From 2167183c34df6ac10a303dd87b9ce994cab8e106 Mon Sep 17 00:00:00 2001 From: Adam Dalloul <47503782+Adam-Dalloul@users.noreply.github.com> Date: Sat, 15 Aug 2026 17:59:01 -0700 Subject: [PATCH 1/3] feat(delegation): let agents spawn sub-agents without an @ mention --- src-tauri/src/acp/delegation/companion.rs | 19 +++++++++++++++++++ src-tauri/src/acp/delegation/tool_schema.json | 4 ++-- 2 files changed, 21 insertions(+), 2 deletions(-) diff --git a/src-tauri/src/acp/delegation/companion.rs b/src-tauri/src/acp/delegation/companion.rs index 8cf8eb0de..3097a7d30 100644 --- a/src-tauri/src/acp/delegation/companion.rs +++ b/src-tauri/src/acp/delegation/companion.rs @@ -1616,6 +1616,25 @@ mod tests { assert!(status["inputSchema"]["properties"]["wait_ms"].is_object()); let required = status["inputSchema"]["required"].as_array().unwrap(); assert!(required.iter().any(|v| v == "task_ids")); + // Self-initiate is allowed: a mention is sufficient, not required. + // The old copy said a mention IS the trigger, so agents waited for `@`. + let desc = delegate["description"].as_str().unwrap(); + assert!( + desc.contains("YOU MAY CALL THIS TOOL WITHOUT A USER @ MENTION"), + "delegate_to_agent must invite self-initiated spawn" + ); + assert!( + desc.contains("Such a mention MUST be honored"), + "an @ mention must still force a delegation" + ); + assert!( + !desc.contains("Such a mention IS an explicit instruction"), + "do not tell the model that only a mention starts a sub-agent" + ); + let agent_desc = delegate["inputSchema"]["properties"]["agent_type"]["description"] + .as_str() + .unwrap(); + assert!(agent_desc.contains("even when the user did not @-mention")); } #[tokio::test] diff --git a/src-tauri/src/acp/delegation/tool_schema.json b/src-tauri/src/acp/delegation/tool_schema.json index 08002aaf4..d213526ce 100644 --- a/src-tauri/src/acp/delegation/tool_schema.json +++ b/src-tauri/src/acp/delegation/tool_schema.json @@ -1,7 +1,7 @@ [ { "name": "delegate_to_agent", - "description": "Hand off a self-contained sub-task to a separate local AI agent that runs in its own session. ASYNCHRONOUS: returns a task_id right away and the sub-agent keeps working in the background — this call never blocks. So you can fan out several delegations at once and keep working, then collect the results with get_delegation_status by passing the task_ids array (one id to poll a single task, or many at once to poll the whole fan-out in one call) — or stop one early with cancel_delegation(task_id). The sub-agent CANNOT see this conversation, your open files, or earlier turns — it starts cold, so `task` must carry everything it needs. Best for independent, parallelizable work you can describe up front; not for steps that need your ongoing back-and-forth. RECOGNIZING AN EXPLICIT DELEGATION REQUEST: the user can name a sub-agent directly in their message — it appears as `@AgentName` or as a Markdown link `[@AgentName](codeg://agent/)`. Such a mention IS an explicit instruction to delegate the associated work to that agent, even when the user never names this tool. If the message names several agents, make one call per agent, each carrying that agent's slice of the work.", + "description": "Hand off a self-contained sub-task to a separate local AI agent that runs in its own session. ASYNCHRONOUS: returns a task_id right away and the sub-agent keeps working in the background — this call never blocks. So you can fan out several delegations at once and keep working, then collect the results with get_delegation_status by passing the task_ids array (one id to poll a single task, or many at once to poll the whole fan-out in one call) — or stop one early with cancel_delegation(task_id). The sub-agent CANNOT see this conversation, your open files, or earlier turns — it starts cold, so `task` must carry everything it needs. Best for independent, parallelizable work you can describe up front; not for steps that need your ongoing back-and-forth. YOU MAY CALL THIS TOOL WITHOUT A USER @ MENTION. When the request has a self-contained sub-task that another listed agent is better suited for, or that can run in parallel, spawn it yourself. Pick agent_type only from this tool's enum (the built-ins listed here plus any custom: slugs shown). Do not invent slugs. Do not copy the whole conversation into the child — only a self-contained slice. Then keep working, or collect results with get_delegation_status. RECOGNIZING AN EXPLICIT DELEGATION REQUEST: the user can name a sub-agent directly in their message — it appears as `@AgentName` or as a Markdown link `[@AgentName](codeg://agent/)`. Such a mention MUST be honored: delegate the associated work to that agent even when the user never names this tool. If the message names several agents, make one call per agent, each carrying that agent's slice of the work.", "inputSchema": { "type": "object", "required": ["agent_type", "task"], @@ -23,7 +23,7 @@ "cursor", "deepseek" ], - "description": "Which local agent runs the sub-task. Pick the one best suited to the work — or, when the user's message names an agent via `@AgentName` / `codeg://agent/`, use that exact `` slug (e.g. `codeg://agent/claude_code` means `claude_code`)." + "description": "Which local agent runs the sub-task. You may pick the one best suited to the work even when the user did not @-mention anyone. When the user's message names an agent via `@AgentName` / `codeg://agent/`, use that exact `` slug (e.g. `codeg://agent/claude_code` means `claude_code`)." }, "task": { "type": "string", From 06f2f0340f26e3cb0d253df5b2f3b13dd82182c2 Mon Sep 17 00:00:00 2001 From: Adam Dalloul <47503782+Adam-Dalloul@users.noreply.github.com> Date: Sat, 15 Aug 2026 18:12:52 -0700 Subject: [PATCH 2/3] feat(delegation): settings toggle for spawn without @ --- src-tauri/src/acp/connection.rs | 15 + src-tauri/src/acp/delegation/broker.rs | 16976 ++++++++-------- src-tauri/src/acp/delegation/companion.rs | 58 + src-tauri/src/commands/delegation.rs | 31 + .../settings/delegation-settings.test.tsx | 4 + .../settings/delegation-settings.tsx | 20 +- src/i18n/messages/ar.json | 9914 ++++----- src/i18n/messages/de.json | 9914 ++++----- src/i18n/messages/en.json | 9914 ++++----- src/i18n/messages/es.json | 9914 ++++----- src/i18n/messages/fr.json | 9914 ++++----- src/i18n/messages/ja.json | 9914 ++++----- src/i18n/messages/ko.json | 9914 ++++----- src/i18n/messages/pt.json | 9914 ++++----- src/i18n/messages/zh-CN.json | 9914 ++++----- src/i18n/messages/zh-TW.json | 9914 ++++----- src/lib/api.ts | 3 + 17 files changed, 58205 insertions(+), 58042 deletions(-) diff --git a/src-tauri/src/acp/connection.rs b/src-tauri/src/acp/connection.rs index dd23cff4b..9f69679a1 100644 --- a/src-tauri/src/acp/connection.rs +++ b/src-tauri/src/acp/connection.rs @@ -3496,6 +3496,9 @@ fn is_executable_file(path: &Path) -> bool { #[derive(Debug, Clone, Copy, Default, PartialEq, Eq)] struct CompanionFeatureFlags { delegation: bool, + /// When true (with delegation), the tool description is @-mention only. + /// Unknown to older companions (ignored). + mention_only: bool, feedback: bool, ask: bool, sessions: bool, @@ -3518,6 +3521,9 @@ fn companion_features_arg(flags: CompanionFeatureFlags) -> Option { let mut features: Vec<&str> = Vec::new(); if flags.delegation { features.push("delegation"); + if flags.mention_only { + features.push("mention_only"); + } } if flags.feedback { features.push("feedback"); @@ -3592,6 +3598,7 @@ async fn inject_codeg_mcp( } let flags = CompanionFeatureFlags { delegation: delegation_enabled, + mention_only: delegation_enabled && !injection.broker.allow_self_initiate(), feedback: feedback_enabled, ask: injection.ask.is_enabled().await, sessions: injection.sessions.is_enabled().await, @@ -15951,6 +15958,7 @@ mod tests { assert_eq!( companion_features_arg(CompanionFeatureFlags { delegation: true, + mention_only: false, feedback: true, ask: true, sessions: true, @@ -15960,6 +15968,13 @@ mod tests { }), Some("delegation,feedback,ask,sessions,tasks,automations,taskboard".to_string()) ); + assert_eq!( + only(|f| { + f.delegation = true; + f.mention_only = true; + }), + Some("delegation,mention_only".to_string()) + ); } // ── Boolean config options (cline 3.0.50 `auto_approve`) ── diff --git a/src-tauri/src/acp/delegation/broker.rs b/src-tauri/src/acp/delegation/broker.rs index 6c428f34b..ca11e5ea2 100644 --- a/src-tauri/src/acp/delegation/broker.rs +++ b/src-tauri/src/acp/delegation/broker.rs @@ -1,8481 +1,8495 @@ -//! `DelegationBroker` — the coordination unit for multi-agent delegation. -//! -//! Delegation is **asynchronous**: `delegate_to_agent` returns a `task_id` -//! ack as soon as setup finishes; the LLM collects the result later with -//! `get_delegation_status` (optionally long-polling) or stops it with -//! `cancel_delegation`. There is no blocking `oneshot` — a running task is just -//! an entry in the `running` map, and a terminal event migrates it into the -//! `completed` cache (atomically, under one lock) and wakes any long-poll via -//! `result_notify`. -//! -//! Lifecycle of a single task: -//! -//! 1. [`DelegationBroker::start_delegation`] is the broker's entry point. The -//! MCP listener feeds it the LLM-issued `delegate_to_agent` payload. -//! 2. Pre-checks: feature enabled? depth limit ok? Both failures return a -//! terminal report immediately, no child session created. -//! 3. Spawn the child via [`ConnectionSpawner::spawn`]. -//! 4. Send the delegation task as the first prompt via -//! [`ConnectionSpawner::send_prompt_linked_for_delegation`]. The trailing -//! [`DelegationLink`] carries the parent's `tool_use_id` and a -//! broker-internal `call_id` (UUID = `task_id`) — persisted onto the new -//! conversation row so the lifecycle resolver can find it. -//! 5. Register a [`RunningTask`] keyed by `call_id` and return a `Running` ack -//! [`DelegationTaskReport`] (or a terminal report when the child finished -//! during setup / a cancel reached it mid-setup / setup itself failed). -//! 6. Later, a terminal event resolves the task — migrating it `running` → -//! `completed` and tearing the child down: -//! - the lifecycle calling [`DelegationBroker::complete_call`] on -//! `TurnComplete` (happy path), or -//! - a cancel — MCP-side (`notifications/cancelled` → -//! [`DelegationBroker::cancel_by_external_handle`]), child-side -//! ([`DelegationBroker::cancel_by_child_connection`]), parent-side -//! ([`DelegationBroker::cancel_by_parent`] / -//! [`DelegationBroker::cancel_by_parent_turn`]), or the LLM's own -//! [`DelegationBroker::cancel_task_by_id`]. -//! -//! v1 is explicitly one-shot — no session reuse. -//! -//! Result durability: child output is NOT stored in codeg's DB, so the broker -//! caches the completed text in `completed` (parent-scoped, FIFO-capped). Once -//! evicted, [`DelegationBroker::get_task_status`] falls back to the DB for the -//! task's terminal STATUS (via [`ChildStatusLookup`]); the full output is always -//! viewable in the child's own session. -//! -//! Cancellation cascade: when a parent session goes away (user-initiated -//! cancel, parent disconnect), the lifecycle subscriber calls -//! [`DelegationBroker::cancel_by_parent`] which fans out cancel + disconnect -//! to every running child of that parent. A normal `end_turn` does NOT cancel -//! children — they keep running in the background (the whole point of async). - -use std::collections::{BTreeMap, HashMap, HashSet, VecDeque}; -use std::sync::Arc; -use std::time::{Duration, Instant}; - -use async_trait::async_trait; -use tokio::sync::{Mutex, Notify}; - -use crate::acp::delegation::event_emitter::{DelegationEventEmitter, NoopEventEmitter}; -use crate::acp::delegation::live_reply::{ChildLiveReplyLookup, NoopChildLiveReplyLookup}; -use crate::acp::delegation::meta_writer::{ - build_delegation_meta, is_synthetic_parent_tool_use_id, DelegationMetaWriter, NoopMetaWriter, -}; -use crate::acp::delegation::spawner::{ConnectionSpawner, DelegationLink}; -use crate::acp::delegation::types::{ - AgentDelegationDefaults, BlockedKind, BlockedOn, DelegationError, DelegationOutcome, - DelegationRequest, DelegationTaskReport, TaskStatus, -}; -use crate::acp::types::DelegationResultSummary; -use crate::models::AgentType; - -/// Default per-parent byte budget for cached completed-task result text. The -/// completed-cache lets `get_delegation_status` / `cancel_delegation` return a -/// finished task's result after the lifecycle resolved it; once a parent's -/// retained result text exceeds this budget the OLDEST results are FIFO-evicted -/// (evicted tasks fall back to the DB status lookup, which carries status only). -/// This is the seed value baked into `DelegationConfig::default()`; the live -/// value is user-configurable from the settings page (in MB) and `0` disables -/// eviction entirely. See `PendingInner::completed_cap_bytes`. -const DEFAULT_COMPLETED_CACHE_CAP_BYTES: usize = 512 * 1024 * 1024; - -/// Per-result cap on cached completed text. The full child output always lives -/// in the child's own session (viewable via the frontend's child-session -/// sheet); this only bounds the broker's in-memory copy of a SINGLE result. -/// Because it is far below the per-parent byte budget -/// (`DEFAULT_COMPLETED_CACHE_CAP_BYTES`), the newest result always fits and is -/// never the eviction victim in `insert_completed`. -const COMPLETED_TEXT_CAP: usize = 256 * 1024; - -/// Cap on the `task_preview` carried by the `DelegationStarted` event and the -/// parent-card meta writes. The full task text lives in the MCP call (and, on -/// most hosts, in the parent tool call's own `raw_input`); the preview only -/// has to label the delegation card, so it shares the status-preview budget -/// rather than the multi-KiB result cap. -const TASK_PREVIEW_CAP: usize = 2 * 1024; - -/// Cap on the inline `text_preview` carried by the `DelegationCompleted` event -/// and the terminal meta, so the parent card can render the result inline -/// without re-fetching the child session. -const STATUS_PREVIEW_CAP: usize = 2 * 1024; - -/// Lookup the `parent_id` for a conversation. Abstracted so the broker can be -/// unit-tested against an in-memory chain without touching SeaORM. -#[async_trait] -pub trait ConversationDepthLookup: Send + Sync { - async fn parent_of(&self, conversation_id: i32) -> Result, DelegationError>; -} - -/// Status-level facts the broker recovers from a child conversation row when a -/// task's in-memory completed-cache entry was evicted. Carries NO result text — -/// child output isn't stored in codeg's DB; the full result lives in the -/// child's own session (viewable via the frontend's child-session sheet). -#[derive(Debug, Clone)] -pub struct ChildStatusRecord { - pub child_conversation_id: i32, - pub status: TaskStatus, - pub agent_type: AgentType, - /// The parent conversation id this child was spawned under. Used to scope - /// the DB fallback to the calling parent so one parent can't read another's - /// task by guessing a UUID. - pub parent_id: Option, -} - -/// DB fallback for `get_delegation_status` / `cancel_delegation` once a task's -/// result has aged out of the broker's in-memory completed-cache. Abstracted -/// so broker unit tests can run without SeaORM; production wires -/// [`DbChildStatusLookup`] via [`DelegationBroker::with_status_lookup`]. -#[async_trait] -pub trait ChildStatusLookup: Send + Sync { - async fn find_by_call_id(&self, call_id: &str) -> Option; -} - -/// Default lookup — always "unknown". Used by `DelegationBroker::new` / -/// `with_writers` (tests that don't exercise the DB-fallback path); production -/// replaces it via `with_status_lookup`. -#[derive(Default, Clone)] -pub struct NoopChildStatusLookup; - -#[async_trait] -impl ChildStatusLookup for NoopChildStatusLookup { - async fn find_by_call_id(&self, _call_id: &str) -> Option { - None - } -} - -#[derive(Debug, Clone)] -pub struct DelegationConfig { - pub enabled: bool, - /// Max chain depth a *new* delegation may exist at. With `depth_limit = 2` - /// the chain root → child → grandchild is allowed; the grandchild trying - /// to spawn a great-grandchild is rejected. See spec §5. - pub depth_limit: u32, - /// Per-agent overrides applied when spawning a delegation child. Keyed by - /// the target `agent_type`; missing entries mean "no override." Forwarded - /// to `ConnectionSpawner::spawn` as `preferred_mode_id` / - /// `preferred_config_values`. - pub agent_defaults: BTreeMap, - /// Per-parent byte budget for cached completed-task result text. `0` - /// disables eviction (unlimited). Surfaced from the settings page in MB and - /// converted to bytes in `into_broker_config`. Pushed into the pending-calls - /// bucket by `set_config` so `insert_completed` reads it lock-free. - pub completed_cache_cap_bytes: usize, -} - -impl Default for DelegationConfig { - fn default() -> Self { - Self { - enabled: false, - depth_limit: 1, - agent_defaults: BTreeMap::new(), - completed_cache_cap_bytes: DEFAULT_COMPLETED_CACHE_CAP_BYTES, - } - } -} - -/// A delegation task running in the background after `start_delegation` -/// returned its `Running` ack. The async redesign drops the parked -/// `oneshot::Sender` the old `PendingCall` carried: the parent's -/// `delegate_to_agent` no longer blocks on a channel, so there is nothing to -/// signal. A terminal event instead migrates the entry into `completed` (same -/// lock) and wakes any `get_delegation_status` long-poll via the broker's -/// `result_notify`. -struct RunningTask { - child_connection_id: String, - child_conversation_id: i32, - parent_connection_id: String, - parent_tool_use_id: String, - /// Target agent — surfaced in status reports. - agent_type: AgentType, - /// Bounded preview of the delegated task text ([`TASK_PREVIEW_CAP`]). - /// Carried so TERMINAL meta writes can keep labeling the parent card — - /// meta is replace-wholesale on the ToolCallState, so a terminal write - /// that dropped the task text would erase what the running write supplied. - task_preview: String, - /// The broker-minted task id — duplicates this entry's key in `running` - /// because the cancel/teardown paths hand around the drained - /// `RunningTask` by value without its map key. - task_id: String, - /// MCP-side opaque handle minted by the companion per `tools/call`. The - /// listener forwards it through `DelegationRequest`; we keep it here so - /// `cancel_by_external_handle` can find the entry. `None` for delegations - /// that didn't come through MCP (tests, future internal callers). - external_handle: Option, - /// When the child started running (after `send_prompt` succeeded). Used to - /// compute a real `duration_ms` at terminal time. - started_at: Instant, - /// The last blocking prompt a status query reported to the parent, and when. - /// Makes "the block I told you about" distinguishable from "a NEW block", - /// which is what stops a `wait_ms: 0` poll from returning instantly forever - /// once a child parks on a permission (#447): the first observation - /// returns, a re-poll on the same prompt goes back to waiting, and a second - /// prompt returns again. - /// - /// The timestamp is the safety valve. Marking a block reported is not proof - /// the parent RECEIVED it — the report still has to cross the listener, the - /// companion's stdout and the agent CLI, and an MCP `notifications/cancelled` - /// or a client-side call abort discards it silently. Without the valve that - /// lost report would be the only one ever offered, re-creating the exact - /// stall this fixes. So the same unanswered prompt becomes reportable again - /// after [`BLOCK_RESURFACE_INTERVAL`]. - last_surfaced_block: Option, -} - -/// See [`RunningTask::last_surfaced_block`]. -struct SurfacedBlock { - request_id: String, - at: Instant, -} - -/// A terminal delegation result retained so `get_delegation_status` / -/// `cancel_delegation` can answer after the lifecycle resolved the task. -/// Parent-scoped, FIFO-evicted once the parent's retained result text exceeds -/// `PendingInner::completed_cap_bytes`, and dropped wholesale when the parent -/// connection tears down. -#[derive(Clone)] -struct CompletedTask { - parent_connection_id: String, - child_conversation_id: i32, - agent_type: AgentType, - status: TaskStatus, - /// Result text for `Completed` (capped at [`COMPLETED_TEXT_CAP`]). `None` - /// for failures/cancels. - text: Option, - error_code: Option, - message: Option, - duration_ms: u64, -} - -#[derive(Default)] -struct PendingCalls { - inner: Mutex, -} - -/// Everything guarded by the single pending-calls mutex. Co-locating the parked -/// calls with the early-terminal bookkeeping under ONE lock is what makes the -/// terminal-vs-registration race safe: a terminal event for a delegation that -/// is still mid-setup (its `handle_request` hasn't parked the [`PendingCall`] -/// yet) and the matching registration are serialized on this lock, so the -/// terminal event either finds the parked entry (resolves via `tx`) or buffers -/// its outcome (and `handle_request` drains it the instant it parks) — never -/// both, never neither. Without this, a terminal that fires in the spawn→park -/// window would no-op the resolver and then strand the parked `rx.await`. -/// -/// Both CHILD-terminal pre-park resolvers are covered, because either can win -/// the race against the parent `write_meta` await between `send_prompt` and the -/// park: -/// * `complete_call` — a fast/empty turn's `TurnComplete` (the prompt is only -/// *enqueued* by `send_prompt`; the child loop emits `TurnComplete` -/// independently). Keyed by `call_id`. -/// * `cancel_by_child_connection` — a freshly-spawned child connection dying -/// before its first prompt is answered. Keyed by `child_connection_id`. -/// -/// Parent-side cancels (`cancel_by_parent` / `cancel_by_parent_turn`) are -/// covered symmetrically by the `inflight` registry: `handle_request` registers -/// each setup at entry, and `mark_inflight_canceled_for_parent` runs in the SAME -/// lock acquisition that drains the parked `calls`. A parent cancel landing -/// while a child is still mid-setup therefore flags the in-flight record, and -/// `handle_request` observes the flag at its next checkpoint (or atomically at -/// park) and tears the child down itself — it is no longer left to the child's -/// own terminal / connection-teardown cascade. -/// -/// The reservation records the `child_connection_id` each resolver gates on; -/// `handle_request` drains both buffers at park. -#[derive(Default)] -struct PendingInner { - /// Tasks running in the background after their `Running` ack, keyed by - /// broker `call_id` (= `task_id`). A terminal event migrates an entry from - /// here into `completed` under THIS lock (atomic `running` → `completed` - /// transition), so a concurrent `get_delegation_status` never observes a - /// task as neither running nor completed. - running: HashMap, - /// Terminal results retained for `get_delegation_status` / `cancel_delegation`, - /// keyed by `task_id`. Bounded by the per-parent byte valve - /// (`completed_cap_bytes` over `completed_bytes`, FIFO-evicted via - /// `completed_order`) and dropped per-parent on connection teardown. - /// Evicted/unknown tasks fall back to the DB status lookup. - completed: HashMap, - /// Per-parent FIFO index over `completed` for byte-valve eviction and - /// per-parent teardown. Keyed by `parent_connection_id`; each deque holds - /// that parent's completed `task_id`s oldest-first. - completed_order: HashMap>, - /// Per-parent running total of retained completed result-text bytes (the - /// `CompletedTask::text` lengths). Drives the `completed_cap_bytes` valve in - /// `insert_completed`; kept in sync on insert/evict and cleared per-parent - /// on teardown. - completed_bytes: HashMap, - /// Per-parent byte budget for retained completed result text. `0` = - /// unlimited (no eviction). Seeded by `set_config` from the live - /// `DelegationConfig` (default until then: `0`, but `set_config` always runs - /// at startup via `apply_persisted_config`). Read lock-free by - /// `insert_completed`, which already holds THIS mutex — so the cap is - /// consulted WITHOUT nesting the `config` lock under the pending lock. - completed_cap_bytes: usize, - /// In-setup delegations (spawned + id minted, not yet parked), mapping - /// `call_id` → `child_connection_id`. Gating the early buffers on membership - /// here distinguishes a genuine pre-registration race (still reserved → - /// buffer) from the normal post-resolution teardown that fires on every - /// completion (no longer reserved → ignore). Removed at park / on the - /// send-failure path. - setups: HashMap, - /// Completion outcomes captured by a `TurnComplete` that beat registration - /// (gated by `setups`), keyed by `call_id`. Each carries the `seq` arrival - /// stamp taken when it buffered, so the park can order it against a racing - /// parent cancel (first-terminal-wins). Drained at park. - early_completes: HashMap, - /// Cancel reasons captured by a child failure that beat registration (gated - /// by `setups`), keyed by `child_connection_id`. The value pairs the `seq` - /// arrival stamp (for the park's first-terminal-wins ordering against a - /// racing parent cancel) with the pre-computed `Canceled { reason }` text - /// (same wording the parked `cancel_by_child_connection` path produces); - /// `handle_request` rebuilds the full outcome at park with the real - /// `child_conversation_id` (which the resolver, finding no entry, lacked). - early_cancels: HashMap, - /// In-flight `handle_request` setups, keyed by a unique per-call id and - /// registered at entry (BEFORE the claim poll, so the whole claim→park - /// window is covered). This is the parent-cancel counterpart to `setups`: - /// `setups` lets a *child* terminal reach a not-yet-parked delegation, - /// while `inflight` lets a *parent* cancel reach one. `cancel_by_parent*` - /// flags every entry it owns (`mark_inflight_canceled_for_parent`); - /// `handle_request` consults the flag after claim, after spawn, and - /// atomically at park, tearing the spawned child down itself when set. - /// Removed at park and on every early-return (no Drop guard — see - /// `register_inflight`). - inflight: HashMap, - /// Monotonic arrival clock (see `tick`). Hands out the unique `inflight` - /// keys AND the arrival stamps on buffered child terminals / parent cancels, - /// so the park can resolve a setup-window race by true first-terminal-wins - /// order. Keys and stamps share this sequence but are never cross-compared - /// (keys match by identity, stamps only by `<` against other stamps). - seq: u64, -} - -/// One in-flight `handle_request` setup tracked for parent-cancel coverage. -struct InflightSetup { - parent_connection_id: String, - /// `Some(stamp)` once a parent cancel lands while this delegation is - /// mid-setup (spawned / sending, not yet parked), where `stamp` is the `seq` - /// arrival-clock value at that moment. First-write-wins and never cleared, - /// so a cancel can't be lost between `handle_request`'s checkpoints, and its - /// stamp lets the park order it against a racing child terminal. - canceled_at: Option, -} - -impl PendingInner { - /// Mark a delegation as setting-up (spawned + id minted, not yet parked) so - /// a terminal event racing the park is buffered rather than dropped. - /// - /// No cap: a reservation lives only for the brief spawn→park window and is - /// always released by `unreserve` on every `handle_request` exit (park, or - /// the send-failure path), so `setups` is bounded by the count of - /// concurrently-in-setup delegations — it never accumulates stale entries. - /// A cap here would be actively unsafe: every reservation is live, so - /// evicting one to make room would drop a real in-flight delegation's race - /// guard and reopen the very hang this machinery exists to prevent. - fn reserve(&mut self, call_id: &str, child_connection_id: &str) { - self.setups - .insert(call_id.to_string(), child_connection_id.to_string()); - } - - /// Release a delegation's reservation and discard any un-drained buffered - /// terminal — called once the entry is parked (the buffers were already - /// drained, so the removals are no-ops then) or when setup errors out - /// (discarding a buffer no `handle_request` will pick up). - fn unreserve(&mut self, call_id: &str, child_connection_id: &str) { - self.setups.remove(call_id); - self.early_completes.remove(call_id); - self.early_cancels.remove(child_connection_id); - } - - /// Whether a child connection belongs to a still-in-setup delegation. O(n) - /// over `setups`, but n is the (tiny) count of concurrently-in-setup - /// delegations. - fn is_child_reserved(&self, child_connection_id: &str) -> bool { - self.setups - .values() - .any(|child| child == child_connection_id) - } - - /// Buffer a completion for a still-reserved delegation, stamped with the - /// current arrival clock so the park can order it against a racing parent - /// cancel. No-op when the `call_id` isn't reserved (already resolved by - /// another terminal path), so the buffer only ever holds genuine - /// pre-registration races. - fn buffer_early_complete(&mut self, call_id: &str, outcome: DelegationOutcome) { - if self.setups.contains_key(call_id) { - let stamp = self.tick(); - self.early_completes - .insert(call_id.to_string(), (stamp, outcome)); - } - } - - /// Buffer a child failure for a still-reserved delegation, stamped with the - /// current arrival clock so the park can order it against a racing parent - /// cancel. No-op when the child isn't reserved (normal post-resolution - /// teardown). Stores the pre-computed cancel reason so the park rebuilds the - /// same wording the parked `cancel_by_child_connection` path produces. - fn buffer_child_failure(&mut self, child_connection_id: &str, detail: Option) { - if self.is_child_reserved(child_connection_id) { - let stamp = self.tick(); - self.early_cancels.insert( - child_connection_id.to_string(), - (stamp, child_canceled_reason(detail.as_deref())), - ); - } - } - - /// Drain a buffered completion with its arrival stamp (by `call_id`) — used - /// by `handle_request` at park. - fn take_early_complete(&mut self, call_id: &str) -> Option<(u64, DelegationOutcome)> { - self.early_completes.remove(call_id) - } - - /// Drain a buffered cancel reason with its arrival stamp (by - /// `child_connection_id`) — used by `handle_request` at park. - fn take_early_cancel(&mut self, child_connection_id: &str) -> Option<(u64, String)> { - self.early_cancels.remove(child_connection_id) - } - - /// Advance the monotonic arrival clock, returning the pre-increment value. - /// Strictly increasing (wraps only after 2^64 calls — unreachable), so two - /// events stamped under this lock always compare in their true arrival - /// order. Backs both `inflight` keys and terminal/cancel arrival stamps; the - /// two uses never cross-compare (keys match by identity, stamps by `<`). - fn tick(&mut self) -> u64 { - let v = self.seq; - self.seq = self.seq.wrapping_add(1); - v - } - - /// Register an in-flight setup at `handle_request` entry, returning its - /// unique id. The caller MUST `deregister_inflight` on every exit path - /// (each early-return, and at park). There is deliberately NO Drop guard: - /// the park hand-off — `calls.insert` followed by `deregister_inflight` — - /// has to be atomic under this lock so a concurrent parent cancel sees the - /// entry in exactly one of `inflight` or `calls`, and a guard firing after - /// the lock releases would reopen that window. - fn register_inflight(&mut self, parent_connection_id: &str) -> u64 { - let id = self.tick(); - self.inflight.insert( - id, - InflightSetup { - parent_connection_id: parent_connection_id.to_string(), - canceled_at: None, - }, - ); - id - } - - /// Drop an in-flight setup record (idempotent). - fn deregister_inflight(&mut self, id: u64) { - self.inflight.remove(&id); - } - - /// Whether a parent cancel flagged this in-flight setup. False once the - /// record is gone (already parked / deregistered). Used by the pre-spawn / - /// post-spawn checkpoints, which only need the boolean. - fn inflight_canceled(&self, id: u64) -> bool { - self.inflight - .get(&id) - .map(|s| s.canceled_at.is_some()) - .unwrap_or(false) - } - - /// Arrival stamp of the parent cancel that flagged this in-flight setup, if - /// any (`None` when not canceled, or the record is already gone). Used at - /// park to order the cancel against a buffered child terminal. - fn inflight_canceled_at(&self, id: u64) -> Option { - self.inflight.get(&id).and_then(|s| s.canceled_at) - } - - /// Flag every in-flight setup owned by `parent_connection_id` as canceled, - /// stamping each with one shared arrival-clock value (this cancel is a - /// single event). First-write-wins per setup, so a later cancel can't push - /// an earlier one's stamp forward. Called from `drain_for_parent_cancel` in - /// the SAME lock acquisition that drains the parked `calls`, so each of the - /// parent's delegations is caught either here (still in-flight → flagged; - /// `handle_request` tears its child down at the next checkpoint) or by the - /// parked-call drain (already parked) — never neither. - fn mark_inflight_canceled_for_parent(&mut self, parent_connection_id: &str) { - let stamp = self.tick(); - for setup in self.inflight.values_mut() { - if setup.parent_connection_id == parent_connection_id && setup.canceled_at.is_none() { - setup.canceled_at = Some(stamp); - } - } - } - - /// Insert a terminal result into the completed-cache, then FIFO-evict this - /// parent's OLDEST results until its retained result-text bytes fit - /// `completed_cap_bytes` (`0` = unlimited). Evicted tasks fall back to the - /// DB status lookup (status only — child text lives in the child session). - /// The just-inserted entry is never the victim: a single result is capped - /// at [`COMPLETED_TEXT_CAP`] (256 KiB), far below any MB-scale budget, so - /// the newest result always survives for the LLM's immediate - /// `get_delegation_status`. The caller does the atomic `running.remove` + - /// this insert under one lock, then notifies long-poll waiters AFTER - /// releasing the lock. - fn insert_completed(&mut self, call_id: &str, task: CompletedTask) { - let parent = task.parent_connection_id.clone(); - let task_bytes = task.text.as_ref().map_or(0, |t| t.len()); - self.completed.insert(call_id.to_string(), task); - *self.completed_bytes.entry(parent.clone()).or_insert(0) += task_bytes; - self.completed_order - .entry(parent.clone()) - .or_default() - .push_back(call_id.to_string()); - self.evict_completed_over_cap(&parent); - } - - /// Evict `parent`'s OLDEST completed results until its retained result-text - /// bytes fit `completed_cap_bytes` (`0` = unlimited). Evicted tasks fall - /// back to the DB status lookup (status only — child text lives in the child - /// session). The newest entry is never evicted: a single result is capped at - /// [`COMPLETED_TEXT_CAP`] (256 KiB), far below any MB-scale budget, so the - /// LLM's immediate `get_delegation_status` always hits. - fn evict_completed_over_cap(&mut self, parent: &str) { - let cap = self.completed_cap_bytes; - if cap == 0 { - return; - } - loop { - if self.completed_bytes.get(parent).copied().unwrap_or(0) <= cap { - break; - } - let evicted = match self.completed_order.get_mut(parent) { - Some(order) if order.len() > 1 => order.pop_front(), - _ => None, - }; - let Some(evicted) = evicted else { - break; - }; - if let Some(removed) = self.completed.remove(&evicted) { - let freed = removed.text.as_ref().map_or(0, |t| t.len()); - if let Some(slot) = self.completed_bytes.get_mut(parent) { - *slot = slot.saturating_sub(freed); - } - } - } - } - - /// Re-apply the current `completed_cap_bytes` to EVERY parent. Called by - /// `set_config` when the cap may have been LOWERED at runtime, so - /// already-retained results are pruned promptly — insert-time eviction alone - /// would otherwise strand them until a parent's next completion (which may - /// never arrive). - fn enforce_completed_cap_all_parents(&mut self) { - if self.completed_cap_bytes == 0 { - return; - } - let parents: Vec = self.completed_bytes.keys().cloned().collect(); - for parent in parents { - self.evict_completed_over_cap(&parent); - } - } - - /// Forget every completed result for a parent. Called on connection - /// teardown (the parent is gone — nothing left to query). A turn cancel - /// deliberately does NOT call this: the connection stays alive and the LLM - /// may still query its just-canceled tasks. - fn drop_completed_for_parent(&mut self, parent_connection_id: &str) { - self.completed_bytes.remove(parent_connection_id); - if let Some(ids) = self.completed_order.remove(parent_connection_id) { - for id in ids { - self.completed.remove(&id); - } - } - } -} - -/// Cap result text retained in the completed-cache. The full output always -/// lives in the child session; this only bounds the broker's copy. -fn cap_completed_text(text: &str) -> String { - truncate_on_char_boundary(text, COMPLETED_TEXT_CAP) -} - -/// Build the bounded inline preview carried by the `DelegationCompleted` event -/// and terminal meta. `None` for empty text. -fn build_text_preview(text: &str) -> Option { - if text.trim().is_empty() { - return None; - } - Some(truncate_on_char_boundary(text, STATUS_PREVIEW_CAP)) -} - -/// Truncate `s` so the RESULT (including the appended ellipsis) is at most `cap` -/// bytes, cut on a UTF-8 char boundary. Reserving the ellipsis bytes keeps the -/// output within the advertised cap rather than `cap + 3`. -fn truncate_on_char_boundary(s: &str, cap: usize) -> String { - if s.len() <= cap { - return s.to_string(); - } - const ELLIPSIS: &str = "…"; - // Leave room for the ellipsis; clamp at 0 for pathologically small caps. - let budget = cap.saturating_sub(ELLIPSIS.len()); - let mut end = budget.min(s.len()); - while end > 0 && !s.is_char_boundary(end) { - end -= 1; - } - format!("{}{ELLIPSIS}", &s[..end]) -} - -/// Derive the completed-cache fields (status / text / error_code / message) -/// from a resolved [`DelegationOutcome`]. `Canceled`-coded errors map to -/// [`TaskStatus::Canceled`]; every other error maps to [`TaskStatus::Failed`]. -fn terminal_fields( - outcome: &DelegationOutcome, -) -> (TaskStatus, Option, Option, Option) { - match outcome { - DelegationOutcome::Ok(ok) => ( - TaskStatus::Completed, - Some(cap_completed_text(&ok.text)), - None, - None, - ), - DelegationOutcome::Err { code, message, .. } => { - let status = if code == "canceled" { - TaskStatus::Canceled - } else { - TaskStatus::Failed - }; - (status, None, Some(code.clone()), Some(message.clone())) - } - } -} - -/// Build a [`CompletedTask`] from a resolved outcome for the completed-cache. -fn build_completed( - parent_connection_id: &str, - child_conversation_id: i32, - agent_type: AgentType, - duration_ms: u64, - outcome: &DelegationOutcome, -) -> CompletedTask { - let (status, text, error_code, message) = terminal_fields(outcome); - CompletedTask { - parent_connection_id: parent_connection_id.to_string(), - child_conversation_id, - agent_type, - status, - text, - error_code, - message, - duration_ms, - } -} - -/// A `canceled`-coded [`DelegationOutcome`] carrying the child conversation id. -fn canceled_outcome(child_conversation_id: i32, reason: &str) -> DelegationOutcome { - DelegationOutcome::from_err( - DelegationError::Canceled { - reason: reason.to_string(), - }, - Some(child_conversation_id), - ) -} - -/// Remove `keys` from `running`, recording each as a `Canceled` completed entry -/// (so a `get_delegation_status` still answers) and returning the drained tasks -/// — each paired with the `duration_ms` captured at this drain point — for I/O -/// teardown. MUST be called with the pending lock held so the running → -/// completed migration is atomic. -/// -/// The duration is captured ONCE here and returned so the slow teardown -/// (parent-card meta, report) reuses the exact value recorded into the -/// completed-cache, rather than recomputing `started_at.elapsed()` later — which -/// would inflate it for the backgrounded `cancel_by_parent_turn` teardown and -/// disagree with the `get_delegation_status` / `cancel_delegation` cards. -fn drain_and_record_canceled( - inner: &mut PendingInner, - keys: Vec, - reason: &str, -) -> Vec<(RunningTask, u64)> { - let mut out = Vec::with_capacity(keys.len()); - for k in keys { - let task = inner.running.remove(&k).expect("key just observed"); - let outcome = canceled_outcome(task.child_conversation_id, reason); - let duration_ms = task.started_at.elapsed().as_millis() as u64; - inner.insert_completed( - &k, - build_completed( - &task.parent_connection_id, - task.child_conversation_id, - task.agent_type, - duration_ms, - &outcome, - ), - ); - out.push((task, duration_ms)); - } - out -} - -/// Project a `DelegationOutcome` + broker-measured `duration_ms` onto the -/// wire-stable `DelegationResultSummary` carried by `DelegationCompleted`. -/// Keeps the mapping (and the bounded `text_preview`) in one place. -fn outcome_to_summary(outcome: &DelegationOutcome, duration_ms: u64) -> DelegationResultSummary { - match outcome { - DelegationOutcome::Ok(ok) => DelegationResultSummary::Ok { - duration_ms, - text_preview: build_text_preview(&ok.text), - }, - DelegationOutcome::Err { code, .. } => DelegationResultSummary::Err { - error_code: code.clone(), - }, - } -} - -/// Project a resolved outcome onto a terminal [`DelegationTaskReport`] (used by -/// the setup-window terminal dispositions and the test shim). -fn report_from_outcome( - task_id: Option, - agent_type: Option, - outcome: &DelegationOutcome, - duration_ms: Option, -) -> DelegationTaskReport { - let (status, text, error_code, message) = terminal_fields(outcome); - let child_conversation_id = match outcome { - DelegationOutcome::Ok(ok) => Some(ok.child_conversation_id), - DelegationOutcome::Err { - child_conversation_id, - .. - } => *child_conversation_id, - }; - DelegationTaskReport { - task_id, - status, - child_conversation_id, - agent_type, - text, - error_code, - message, - duration_ms, - // Terminal by construction — nothing is waiting on the user anymore. - blocked_on: None, - } -} - -/// Build a `Failed`/`Canceled` report for a setup error (no task id — setup -/// failed before/around registration, so the LLM has no task to track). -fn report_err( - agent_type: AgentType, - err: DelegationError, - child_conversation_id: Option, -) -> DelegationTaskReport { - let outcome = DelegationOutcome::from_err(err, child_conversation_id); - report_from_outcome(None, Some(agent_type), &outcome, None) -} - -/// The `Running` ack returned by `start_delegation` for a backgrounded task. -fn running_ack( - call_id: String, - child_conversation_id: i32, - agent_type: AgentType, -) -> DelegationTaskReport { - // Embed the literal task_id in the message so it survives clients that only - // surface the MCP `content` text (not `structuredContent`) — without it the - // LLM couldn't call get_delegation_status / cancel_delegation. - let message = format!( - "Delegation successful. task_id={call_id}. Call get_delegation_status \ - with this id in the task_ids array (optionally wait_ms) to collect the \ - result, or cancel_delegation to stop it." - ); - DelegationTaskReport { - task_id: Some(call_id), - status: TaskStatus::Running, - child_conversation_id: Some(child_conversation_id), - agent_type: Some(agent_type), - text: None, - error_code: None, - message: Some(message), - duration_ms: None, - blocked_on: None, - } -} - -/// How long [`DelegationBroker::get_task_status`] may block before returning the -/// current (possibly still-running) snapshot. Derived by the listener from the -/// MCP tool's `wait_ms`: omitted → [`Immediate`], an explicit `0` → [`Infinite`], -/// any positive value → [`Bounded`] (clamped to the listener's hard ceiling). -/// -/// [`Immediate`]: StatusWait::Immediate -/// [`Bounded`]: StatusWait::Bounded -/// [`Infinite`]: StatusWait::Infinite -#[derive(Debug, Clone, Copy, PartialEq, Eq)] -pub enum StatusWait { - /// Return the current snapshot right away — the default poll. - Immediate, - /// Block up to this many milliseconds, then return whatever snapshot we have - /// (the child keeps running past the deadline; the caller re-issues to wait - /// more). - Bounded(u64), - /// Block until the task reaches a terminal state — never time out. Lets a - /// long-running child be awaited in a single call. A parent disconnect or - /// cancel also drives the task terminal (and fires the completion signal), - /// so this never outlives the task itself. - Infinite, -} - -/// How long an already-reported blocking prompt stays suppressed before a -/// status long-poll will surface it again. Two jobs: it keeps a `wait_ms: 0` -/// caller from spinning on a block it has already been told about, and it -/// bounds the damage when a report is generated but never delivered (see -/// [`RunningTask::last_surfaced_block`]) — a lost report costs a delayed notice -/// instead of a permanent stall. Long relative to a human noticing a prompt, -/// short relative to walking away from the machine. -const BLOCK_RESURFACE_INTERVAL: Duration = Duration::from_secs(300); - -/// Second line of a blocked running report's message. The frontend anchors on -/// this exact prefix to keep recognizing the poll as "running" on hosts that -/// persist only the `CallToolResult` content text — see `textRunningStatus` in -/// `src/lib/delegation-status.ts`. Backend protocol string, never localized. -const BLOCKED_LINE_PREFIX: &str = "Awaiting your decision:"; - -/// Mark a running report as parked on a user decision: set the structured -/// `blocked_on` and replace the bare `"Running."` message with a two-line -/// version naming what needs answering. -/// -/// The note goes on its OWN line, for the same reason the live-reply hint does: -/// content-only hosts recognize a still-running poll by the standalone first -/// line `"Running."`, so a *completed* result whose text happens to start with -/// "Running. …" can never be misread as running. -fn attach_blocked(report: &mut DelegationTaskReport, blocked: BlockedOn) { - let what = match (&blocked.kind, blocked.title.as_deref()) { - (_, Some(title)) => title.to_string(), - (BlockedKind::Permission, None) => "a tool permission".to_string(), - (BlockedKind::Question, None) => "a question".to_string(), - (BlockedKind::PlanApproval, None) => "a plan approval".to_string(), - }; - // The third line is guidance for the orchestrating LLM, in the same spirit - // as `running_ack`'s "call get_delegation_status with this id". Keep it in - // step with the tool description in `tool_schema.json`. - report.message = Some(format!( - "Running.\n{BLOCKED_LINE_PREFIX} {what}\nThe sub-agent is parked until \ - a human answers in Codeg — it is not making progress. Tell the user, \ - then wait again." - )); - report.blocked_on = Some(blocked); -} - -/// Status report for a still-running task. -fn running_report(task_id: &str, task: &RunningTask) -> DelegationTaskReport { - DelegationTaskReport { - task_id: Some(task_id.to_string()), - status: TaskStatus::Running, - child_conversation_id: Some(task.child_conversation_id), - agent_type: Some(task.agent_type), - text: None, - error_code: None, - // Bare baseline; `get_task_status` upgrades this to a two-line - // "Running.\nLatest sub-agent reply: …" when the child has live output. - message: Some("Running.".to_string()), - duration_ms: None, - blocked_on: None, - } -} - -/// Status report from a cached completed result. -fn completed_report(task_id: &str, c: &CompletedTask) -> DelegationTaskReport { - DelegationTaskReport { - task_id: Some(task_id.to_string()), - status: c.status, - child_conversation_id: Some(c.child_conversation_id), - agent_type: Some(c.agent_type), - text: c.text.clone(), - error_code: c.error_code.clone(), - message: c.message.clone(), - duration_ms: Some(c.duration_ms), - blocked_on: None, - } -} - -/// Status report when a task id isn't known to the caller (never existed, -/// owned by a different parent, or evicted with no DB record). -fn unknown_report(task_id: &str) -> DelegationTaskReport { - DelegationTaskReport { - task_id: Some(task_id.to_string()), - status: TaskStatus::Unknown, - child_conversation_id: None, - agent_type: None, - text: None, - error_code: None, - message: Some( - "Unknown task id — it never existed, isn't owned by this session, \ - or its result was evicted with no stored record." - .to_string(), - ), - duration_ms: None, - blocked_on: None, - } -} - -/// Status report recovered from the DB after the in-memory result was evicted. -/// Carries status only — the full output lives in the child session. -fn db_report(task_id: &str, rec: &ChildStatusRecord) -> DelegationTaskReport { - DelegationTaskReport { - task_id: Some(task_id.to_string()), - status: rec.status, - child_conversation_id: Some(rec.child_conversation_id), - agent_type: Some(rec.agent_type), - text: None, - error_code: (rec.status == TaskStatus::Canceled).then(|| "canceled".to_string()), - message: Some(format!( - "Result no longer cached; open child session {} for the full output.", - rec.child_conversation_id - )), - duration_ms: None, - blocked_on: None, - } -} - -/// What [`DelegationBroker::claim_new_blocks`] decided for one status pass. -#[derive(Default)] -struct ClaimedBlocks { - /// At least one blocking prompt is reportable now — the wait should return. - any_claimed: bool, - /// Earliest moment a currently-suppressed prompt becomes reportable again. - /// Bounds how long an otherwise-unbounded park may sleep, so the - /// resurface valve actually fires instead of waiting on a notify that will - /// never come (a blocked child emits nothing further on its own). - retry_at: Option, -} - -/// Per-id classification captured under the pending lock during a (possibly -/// batched) status query. The async resolution that can't run under the lock — -/// `attach_live_reply` (a different lock) for a running task, `status_from_db` -/// (a DB round-trip) for one not in memory — is deferred to `assemble_reports` -/// AFTER the lock is released, so a status query never nests the pending lock -/// inside another await. This is the same lock-ordering the single-task path -/// has always used; batching just captures it per id. -enum StatusClass { - /// Terminal/owned-cached, or a cross-parent `unknown` — the report is final. - Settled(DelegationTaskReport), - /// Running and owned — the bare running snapshot plus its child connection - /// id, so `assemble_reports` can attach the latest live reply out of lock. - Running { - report: DelegationTaskReport, - child_connection_id: String, - }, - /// Neither running nor completed in memory — resolve via the DB fallback in - /// `assemble_reports`. A not-in-memory id is, for wait purposes, already - /// settled: it can never transition back to running, so a batch wait need - /// not park on it (and must not hit the DB on every wake). - NotInMemory, -} - -/// Classify one task id against the in-memory maps while the pending lock is -/// held. Mirrors the single-task resolution order — completed cache (parent -/// scoped) → running set (parent scoped) → not-in-memory — and yields a -/// cross-parent hit as `unknown` so a task owned by another parent never leaks. -fn classify_locked(inner: &PendingInner, parent_connection_id: &str, task_id: &str) -> StatusClass { - if let Some(c) = inner.completed.get(task_id) { - if c.parent_connection_id == parent_connection_id { - return StatusClass::Settled(completed_report(task_id, c)); - } - return StatusClass::Settled(unknown_report(task_id)); - } - match inner.running.get(task_id) { - Some(r) if r.parent_connection_id == parent_connection_id => StatusClass::Running { - report: running_report(task_id, r), - child_connection_id: r.child_connection_id.clone(), - }, - Some(_) => StatusClass::Settled(unknown_report(task_id)), - None => StatusClass::NotInMemory, - } -} - -/// Map a terminal [`DelegationTaskReport`] back to a [`DelegationOutcome`] for -/// the test-only `handle_request` shim (so pre-async tests keep asserting on -/// the old outcome shape). -#[cfg(any(test, feature = "test-utils"))] -fn report_to_outcome(report: &DelegationTaskReport) -> DelegationOutcome { - use crate::acp::delegation::types::DelegationSuccess; - match report.status { - TaskStatus::Completed => DelegationOutcome::Ok(DelegationSuccess { - text: report.text.clone().unwrap_or_default(), - child_conversation_id: report.child_conversation_id.unwrap_or(0), - child_agent_type: report.agent_type.unwrap_or(AgentType::ClaudeCode), - turn_count: 1, - duration_ms: report.duration_ms.unwrap_or(0), - token_usage: None, - }), - // Running never reaches here (the shim loops until terminal); the other - // states all project onto Err. - _ => DelegationOutcome::Err { - code: report - .error_code - .clone() - .unwrap_or_else(|| "canceled".to_string()), - message: report.message.clone().unwrap_or_default(), - child_conversation_id: report.child_conversation_id, - }, - } -} - -/// Build the `Canceled { reason }` string for a child that ended without a -/// clean `TurnComplete`, optionally stitching in the terminal `Error` detail. -/// Shared by `cancel_by_child_connection` and `handle_request`'s early-terminal -/// pickup so both surface the same wording. -fn child_canceled_reason(terminal_error: Option<&str>) -> String { - match terminal_error { - Some(detail) if !detail.trim().is_empty() => { - format!("child session ended without TurnComplete: {detail}") - } - _ => "child session ended without TurnComplete".to_string(), - } -} - -/// Set of MCP-side `external_handle` tokens for which the companion -/// already received `notifications/cancelled` BEFORE the matching -/// `handle_request` reached the pending-registration phase. Without -/// this pre-cancel buffer, a fast cancel that lands during the -/// pre-check / spawn window would find no entry in `pending`, drop -/// silently, and let the broker proceed to spawn a child the caller -/// no longer wants. `handle_request` consults this set both at entry -/// (so we never even spawn) and immediately after parking the pending -/// entry (so a cancel landing mid-spawn still wins). -/// -/// Capped at [`PRE_CANCELED_CAP`] so a misbehaving MCP client (or a -/// pathological cancel-for-unknown-id storm) can't grow the set -/// without bound. Eviction is FIFO via the parallel `order` deque, -/// which is fine because pre-cancels only matter for the short window -/// between the cancel and the late-arriving `handle_request`. -#[derive(Default)] -struct PreCanceledHandles { - inner: Mutex, -} - -#[derive(Default)] -struct PreCanceledState { - set: HashSet, - order: VecDeque, -} - -const PRE_CANCELED_CAP: usize = 256; - -/// Per-parent tracking of `tool_call_id`s that the ACP lifecycle -/// observed firing `delegate_to_agent`. MCP clients (Codex, Claude -/// Code) generally do NOT populate `_meta.tool_use_id` when invoking -/// an MCP tool, so the broker can't read the LLM-issued -/// `tool_use_id` from the wire — we capture it from the parallel ACP -/// `tool_call` event stream instead. -/// -/// Each bucket holds two FIFOs under the SAME mutex: -/// -/// * `pending` — ids the lifecycle has registered but the matching -/// broker round-trip has not yet claimed. UNKEYED entries are subject -/// to [`PENDING_TOOL_CALL_TTL`] eviction so an anonymous ACP id whose -/// MCP round-trip never arrives can't linger and FIFO-mis-bind a later -/// delegation. KEYED entries carry no count cap: they are drained only -/// by their exact-match claim, by terminal tombstoning -/// (`tombstone_pending_tool_call`), or by per-parent teardown — because -/// the host may serialize a delegation's round-trip arbitrarily far -/// behind earlier long-running ones, so a count cap would drop a -/// still-pending keyed id and orphan its card. -/// * `consumed` — ids that were already claimed by a prior -/// round-trip, or terminal-tombstoned (`tombstone_pending_tool_call`). -/// NEITHER subject to TTL eviction NOR to a per-bucket -/// cap: a delegated child agent may run for minutes to hours, and -/// the host can re-emit the same `tool_call` (e.g. as a `completed` -/// status flip) at the end of that run, so the consumed memory -/// must outlast the entire parent-side tool call lifetime. It is -/// scoped to the parent connection's lifetime instead, cleared by -/// `drop_pending_tool_calls_for_parent` on disconnect. The growth -/// is bounded by how many entries ever register for the parent: -/// `delegate_to_agent` calls (typically tens at most) plus, on -/// Cursor connections, one identity-less "MCP: tool" candidate per -/// MCP call the session makes (see `acp::lifecycle`'s -/// `CURSOR_IDENTITYLESS_MCP_TITLE` registration) — with each -/// `(String, Instant)` entry costing well under 100 bytes, an -/// unbounded set stays comfortable for realistic sessions without -/// OOM risk in the typical operating envelope. -/// -/// Co-locating the two halves under one lock makes the -/// claim → mark-consumed pair atomic. A host re-emit racing with the -/// claim cannot observe an empty pending queue AND a consumed memory -/// that does not yet remember the id; consequently it cannot inject -/// a stale duplicate that would mis-bind the next delegation. -#[derive(Default)] -struct ToolCallTracker { - inner: Mutex>, -} - -/// The arguments that uniquely identify a `delegate_to_agent` invocation, -/// used to correlate a parent-side ACP `tool_call` to the matching MCP -/// `tools/call` round-trip. All three fields are values the LLM passed -/// identically to both wire paths, so the triple is the deterministic key -/// when a parent fires several `delegate_to_agent` calls in parallel — -/// matching on `task` alone would swap two calls targeting different agents -/// with the same task, and adding `agent_type` alone would still swap two -/// same-agent/same-task calls aimed at different directories (e.g. "run -/// tests" against `/repo-a` vs `/repo-b`). -/// -/// `working_dir` here is the value the LLM EXPLICITLY passed (`None` when -/// omitted), NOT the listener-defaulted spawn directory: the listener -/// defaults a missing MCP `working_dir` to the parent's launch dir, but the -/// ACP `raw_input` omits it then too, so keying on the explicit value keeps -/// both sides symmetric (`None == None`) for the common omitted case while -/// still distinguishing two calls that name different directories. -#[derive(Clone, Debug, PartialEq, Eq)] -pub struct DelegationMatchKey { - pub agent_type: AgentType, - pub task: String, - pub working_dir: Option, -} - -/// One captured parent-side `delegate_to_agent` tool_call awaiting its -/// matching MCP round-trip. -struct PendingToolCall { - tool_call_id: String, - /// The `(agent_type, task, working_dir)` correlation key parsed from the ACP - /// tool_call's `raw_input`. Matched against the MCP round-trip's own - /// key so parallel `delegate_to_agent` calls each bind to their own - /// `tool_call_id` regardless of arrival order — pure arrival-order FIFO - /// can mis-assign them (or, when one MCP round-trip out-races the - /// matching ACP event, orphan to a synthetic id). `None` when the host - /// shipped no parseable `raw_input` at ToolCall time; such entries are - /// claimable ONLY via the post-budget FIFO fallback - /// (`take_pending_tool_call`), never the in-loop key-match path. - match_key: Option, - /// True when the entry came from an identity-less MCP announcement - /// (Cursor's `"MCP: tool"` + empty input — see - /// `lifecycle::CURSOR_IDENTITYLESS_MCP_TITLE`). Such an id belongs to - /// *some* codeg-mcp call whose identity only the companion round-trip can - /// reveal, so it is additionally claimable by - /// [`DelegationBroker::rewrite_identityless_tool_call`] (the - /// `get_delegation_status` / `cancel_delegation` call-time rename), and a - /// `delegate_to_agent` claim that lands on one triggers the identity - /// write. Plain unkeyed entries (a delegation invocation whose args were - /// unparseable) keep `false` and are never renamed. - identityless: bool, - registered_at: Instant, -} - -#[derive(Default)] -struct ToolCallTrackerBucket { - pending: VecDeque, - consumed: VecDeque<(String, Instant)>, - /// Sticky "this parent has EVER announced an identity-less MCP call" flag. - /// Gates [`DelegationBroker::rewrite_identityless_tool_call`]'s poll: on - /// hosts that ship real identities (Claude/Codex/…) no identity-less - /// entry ever registers, the flag stays `false`, and every status/cancel - /// round-trip skips the rename at zero cost instead of burning the poll - /// budget. Never cleared on claim — only with the bucket on teardown. - identityless_seen: bool, -} - -/// Maximum age before a `pending` entry is discarded as stale — but ONLY for -/// UNKEYED entries (anonymous, arrival-order correlated). KEYED entries are -/// retained regardless of age: each is claimed solely by an exact key match, -/// so it can't mis-bind a later delegation, and its MCP round-trip may be -/// serialized arbitrarily far behind earlier long-running delegations (Claude -/// Code runs parallel `delegate_to_agent` calls one-at-a-time — observed gap -/// 77 s). See the retain block in `take_matching_tool_call_at`. -/// 60 s comfortably covers the ACP→MCP race for the unkeyed case (<5 ms -/// typical) while still GC'ing a forgotten anonymous id before it can -/// FIFO-mis-bind a subsequent unkeyed delegation. -/// -/// The `consumed` side has no TTL — see [`ToolCallTrackerBucket`] — because -/// long-running delegations can re-emit the parent-side `tool_call` well past -/// this window. -const PENDING_TOOL_CALL_TTL: Duration = Duration::from_secs(60); - -/// Poll cadence and budget used by `claim_pending_tool_call_with_brief_wait` -/// to correlate an MCP `delegate_to_agent` round-trip to its parent-side -/// ACP `tool_call_id`. The exact-match path returns instantly; this budget is -/// spent while waiting for THIS delegation's own `tool_call` to register (or to -/// backfill its key onto an already-registered entry) so we bind by exact match -/// instead of stealing a parallel sibling's id, or while no claimable id has -/// arrived yet. Unkeyed entries are never claimed in-loop — arrival-order FIFO -/// is deferred to the post-budget last resort, which runs only after the caller -/// has waited the full budget (the correct clock for "this delegation has no -/// key coming"), so a round-trip can't grab a sibling's not-yet-keyed id -/// mid-race. -/// -/// 200 × 10 ms = 2 s. This budget only matters when the MCP round-trip -/// out-races its own ACP `tool_call` registration — i.e. the `tools/call` -/// reaches the broker before the in-process `session/update(tool_call)` (and -/// any slightly-later `ToolCallUpdate` carrying the `agent_type`/`task` args) -/// has registered the key. That race is sub-5ms locally; the headroom covers -/// busier hosts and split arg streaming. The wait is invisible in the happy -/// path (it returns the instant the key matches) and negligible against the -/// multi-second-to-minutes child run it precedes. -/// -/// NOTE: the budget is NOT what protects a *serialized* second delegation -/// whose round-trip lands many seconds after its tool_call registered (Claude -/// Code runs parallel `delegate_to_agent` calls one-at-a-time, so the 2nd may -/// arrive minutes later). That id is already registered and waiting — the -/// thing that used to orphan it was age-eviction, now fixed by retaining keyed -/// entries indefinitely (see `take_matching_tool_call_at`'s retain -/// block). A host that emits no observable ACP `tool_call` at all still falls -/// through to the synthetic id after the budget, exactly as before. -const CLAIM_POLL_INTERVAL: Duration = Duration::from_millis(10); -const CLAIM_POLL_ATTEMPTS: usize = 200; - -/// Poll budget for the status/cancel call-time rename -/// ([`DelegationBroker::rewrite_identityless_tool_call`]): 30 × 10 ms = 300 ms. -/// Much shorter than the delegate claim budget because the rename is -/// best-effort (a miss falls back to the completion-time result sniff) and the -/// poll delays the status snapshot the LLM is waiting on. It only has to -/// absorb the in-process ordering race between the ACP announcement landing in -/// the lifecycle dispatcher and the companion's UDS round-trip reaching the -/// listener — sub-5 ms in practice; the sticky `identityless_seen` gate keeps -/// hosts that never announce identity-less calls at zero cost. -const IDENTITYLESS_RENAME_POLL_ATTEMPTS: usize = 30; - -/// The broker is intentionally `Clone` (cheap — only `Arc`s inside) so -/// listener/handler code can hand copies to spawned tasks without lifetime -/// gymnastics. -#[derive(Clone)] -pub struct DelegationBroker { - spawner: Arc, - depth_lookup: Arc, - /// Writer for `meta["codeg.delegation"]` on the parent's active - /// `delegate_to_agent` ToolCallState. Defaults to a no-op so tests - /// that aren't exercising the meta lifecycle don't need to wire - /// anything; production constructs the broker with the - /// `ConnectionManagerMetaWriter` via `with_writers`. - meta_writer: Arc, - /// Emitter for `AcpEvent::DelegationCompleted` against the parent - /// connection's event stream. Same Noop/Mock/Production scheme as - /// the meta writer — production wires `ConnectionManagerEventEmitter` - /// via `with_writers`; tests that don't observe the event lifecycle - /// take the default Noop. - event_emitter: Arc, - /// DB fallback for `get_delegation_status` / `cancel_delegation` once a - /// task's result aged out of the in-memory completed-cache. Defaults to a - /// no-op ("unknown"); production wires `DbChildStatusLookup` via - /// `with_status_lookup`. - status_lookup: Arc, - /// Peeks a still-running child's live session for a one-line progress hint, - /// used to enrich `get_delegation_status`'s running report. Defaults to a - /// no-op ("no hint"); production wires `ConnectionManagerLiveReplyLookup` via - /// `with_live_reply_lookup`. - live_reply_lookup: Arc, - pending: Arc, - tool_calls: Arc, - pre_canceled_handles: Arc, - config: Arc>, - /// Woken after every terminal `record_completed` so a `get_delegation_status` - /// long-poll wakes the instant its task finishes instead of busy-polling. - result_notify: Arc, - /// How long an already-reported blocking prompt stays suppressed — - /// [`BLOCK_RESURFACE_INTERVAL`] in production. A field only so tests can - /// shrink it; nothing outside tests ever sets it. - block_resurface: Duration, -} - -impl DelegationBroker { - pub fn new( - spawner: Arc, - depth_lookup: Arc, - ) -> Self { - Self::with_writers( - spawner, - depth_lookup, - Arc::new(NoopMetaWriter) as Arc, - Arc::new(NoopEventEmitter) as Arc, - ) - } - - /// Test-only constructor that injects a meta writer but keeps the - /// default Noop event emitter. Retained so existing meta-focused - /// tests don't have to mention the emitter parameter. New callsites - /// (and production wiring) should prefer `with_writers`. - pub fn with_meta_writer( - spawner: Arc, - depth_lookup: Arc, - meta_writer: Arc, - ) -> Self { - Self::with_writers( - spawner, - depth_lookup, - meta_writer, - Arc::new(NoopEventEmitter) as Arc, - ) - } - - /// Production-grade constructor wiring the broker to both a real - /// meta writer (`ConnectionManagerMetaWriter`) AND an event emitter - /// (`ConnectionManagerEventEmitter`). Tests that observe the full - /// lifecycle (meta writes + DelegationCompleted emits) should use - /// this with `MockMetaWriter` + `MockEventEmitter`. - pub fn with_writers( - spawner: Arc, - depth_lookup: Arc, - meta_writer: Arc, - event_emitter: Arc, - ) -> Self { - Self { - spawner, - depth_lookup, - meta_writer, - event_emitter, - status_lookup: Arc::new(NoopChildStatusLookup), - live_reply_lookup: Arc::new(NoopChildLiveReplyLookup), - pending: Arc::new(PendingCalls::default()), - tool_calls: Arc::new(ToolCallTracker::default()), - pre_canceled_handles: Arc::new(PreCanceledHandles::default()), - config: Arc::new(Mutex::new(DelegationConfig::default())), - result_notify: Arc::new(Notify::new()), - block_resurface: BLOCK_RESURFACE_INTERVAL, - } - } - - /// Replace the DB status fallback used by `get_delegation_status` / - /// `cancel_delegation` for tasks evicted from the in-memory completed-cache. - /// Builder-style so the production wiring can layer it onto `with_writers` - /// without growing that constructor's arity, and tests can opt in. - pub fn with_status_lookup(mut self, status_lookup: Arc) -> Self { - self.status_lookup = status_lookup; - self - } - - /// Replace the live-reply lookup used to enrich `get_delegation_status`'s - /// running report with the child's latest one-line progress. Builder-style, - /// layered onto `with_writers` by the production wiring; tests opt in with a - /// `MockChildLiveReplyLookup`. - pub fn with_live_reply_lookup( - mut self, - live_reply_lookup: Arc, - ) -> Self { - self.live_reply_lookup = live_reply_lookup; - self - } - - /// Shrink [`BLOCK_RESURFACE_INTERVAL`] so a test can observe the - /// delivery-failure valve without waiting minutes. Test-only by - /// construction — production always keeps the constant. - #[cfg(test)] - fn with_block_resurface(mut self, interval: Duration) -> Self { - self.block_resurface = interval; - self - } - - /// Record a parent ACP `tool_call_id` whose title indicates the LLM is - /// invoking `delegate_to_agent`. The next broker round-trip from the - /// same `parent_connection_id` will claim this id as its - /// `parent_tool_use_id`. Bounded FIFO per connection. - /// - /// Two-tier dedupe against host re-emits of `sessionUpdate(tool_call)` - /// (some hosts use the non-update variant to ship status flips and - /// late-arriving `raw_input` chunks): - /// - /// 1. **In-queue**: if the id is still waiting to be claimed, drop - /// the re-emit — the first push will be consumed by the matching - /// MCP round-trip. - /// 2. **Recently consumed**: if the id was already claimed for an - /// earlier delegation on the same parent, drop the re-emit — - /// otherwise it would sit in the queue as a stale id and mis- - /// bind the **next** delegation's MCP round-trip. The consumed - /// memory persists for the parent connection's lifetime (no - /// TTL, no cap) so a host re-emit at terminal status flip is - /// still rejected even if the delegation ran for hours. - pub async fn register_pending_tool_call( - &self, - parent_connection_id: &str, - tool_call_id: String, - ) { - self.register_pending_tool_call_with_key_at( - parent_connection_id, - tool_call_id, - None, - false, - Instant::now(), - ) - .await; - } - - /// Register an id announced with NO identity at all — Cursor's - /// `"MCP: tool"` + empty-input shape, where the wire never reveals which - /// MCP tool the call is. The entry is unkeyed (claimable by the - /// post-budget FIFO fallback, exactly like a keyless delegation - /// invocation) and additionally marked `identityless`, which (a) makes it - /// claimable by the status/cancel call-time rename - /// ([`Self::rewrite_identityless_tool_call`]) and (b) triggers the - /// identity write when a `delegate_to_agent` claim lands on it. - pub async fn register_identityless_tool_call( - &self, - parent_connection_id: &str, - tool_call_id: String, - ) { - self.register_pending_tool_call_with_key_at( - parent_connection_id, - tool_call_id, - None, - true, - Instant::now(), - ) - .await; - } - - /// `register_pending_tool_call` that also records the - /// `(agent_type, task, working_dir)` correlation key parsed from the - /// tool_call's `raw_input`. The key lets - /// the broker bind this id to its matching MCP round-trip deterministically - /// for parallel `delegate_to_agent` calls that pure arrival-order FIFO can - /// mis-assign. Production registration (from the ACP lifecycle dispatcher) - /// goes through here. - pub async fn register_pending_tool_call_with_key( - &self, - parent_connection_id: &str, - tool_call_id: String, - match_key: Option, - ) { - self.register_pending_tool_call_with_key_at( - parent_connection_id, - tool_call_id, - match_key, - false, - Instant::now(), - ) - .await; - } - - /// Core registration. Holds the [`ToolCallTracker`] mutex across both - /// dedupe tiers AND the push so no concurrent `take` can split the - /// "queue empty + not yet recorded as consumed" window where a host - /// re-emit could otherwise inject a stale duplicate. - /// - /// Two-tier dedupe against host re-emits of `sessionUpdate(tool_call)` - /// (some hosts use the non-update variant to ship status flips and - /// late-arriving `raw_input` chunks): - /// - /// 1. **Recently consumed**: if the id was already claimed for an - /// earlier delegation on the same parent, drop the re-emit — - /// otherwise it would sit in the queue as a stale id and mis-bind - /// the **next** delegation's MCP round-trip. The consumed memory - /// persists for the parent connection's lifetime (no TTL, no cap) - /// so a host re-emit at terminal status flip is still rejected - /// even if the delegation ran for hours. - /// 2. **In-queue**: if the id is still waiting to be claimed, drop the - /// re-emit rather than push a duplicate — EXCEPT we backfill the - /// `match_key` onto an entry registered without one. This is the common - /// case for hosts that emit an arg-less initial `ToolCall` and ship the - /// `agent_type`/`task` arguments on a following `ToolCallUpdate`: the - /// lifecycle dispatcher registers BOTH variants (see - /// `register_delegation_tool_call_from_event`), so the first call lands - /// here unkeyed and the later update re-enters and back-fills the key. - /// Keying the entry this way is what lets it survive past the unkeyed - /// GC TTL (see `take_matching_tool_call_at`'s retain block). - async fn register_pending_tool_call_with_key_at( - &self, - parent_connection_id: &str, - tool_call_id: String, - match_key: Option, - identityless: bool, - now: Instant, - ) { - let mut map = self.tool_calls.inner.lock().await; - let bucket = map.entry(parent_connection_id.to_string()).or_default(); - if identityless { - bucket.identityless_seen = true; - } - // Tier 1: recently consumed. No TTL — the consumed memory must - // outlast the entire parent-side tool call lifetime (minutes - // to hours) so a host re-emit at terminal status flip is - // still rejected. See `ToolCallTrackerBucket` docs. - if bucket.consumed.iter().any(|(id, _)| id == &tool_call_id) { - tracing::info!( - "[delegation] dropping ACP tool_call_id={tool_call_id} on conn={parent_connection_id} (already consumed by an earlier delegation)" - ); - return; - } - // Tier 2: in-queue. A re-emit of an already-queued id: adopt the - // LATEST parseable key rather than only back-filling a missing one. - // Hosts stream `raw_input` incrementally and the MCP side keys on the - // FINAL arguments, so a later `ToolCallUpdate` that completes the key - // (e.g. adds an explicit `working_dir` the first parse lacked) must - // REPLACE the earlier `(agent, task, None)` key — otherwise the MCP - // claim keys on `(agent, task, Some(dir))`, fails to match the stale - // `None`, refuses the keyed fallback, and orphans to a synthetic id - // (the very dead-card failure this whole change fixes). An arg-less or - // identical re-emit changes nothing and is dropped as a duplicate. - if let Some(existing) = bucket - .pending - .iter_mut() - .find(|p| p.tool_call_id == tool_call_id) - { - match match_key { - Some(key) if existing.match_key.as_ref() != Some(&key) => { - existing.match_key = Some(key); - } - _ => { - tracing::info!( - "[delegation] dropping duplicate ACP tool_call_id={tool_call_id} on conn={parent_connection_id}" - ); - } - } - return; - } - bucket.pending.push_back(PendingToolCall { - tool_call_id, - match_key, - identityless, - registered_at: now, - }); - } - - /// Pop the oldest pending `tool_call_id` for the given parent, if any. - /// Skips entries older than [`PENDING_TOOL_CALL_TTL`] so an ACP id whose - /// matching MCP round-trip never arrived cannot mis-bind a later - /// delegation. Mutates the queue in-place; the bucket is removed once - /// drained. - pub async fn take_pending_tool_call(&self, parent_connection_id: &str) -> Option { - self.take_pending_tool_call_at(parent_connection_id, Instant::now()) - .await - .map(|(id, _)| id) - } - - /// `take_pending_tool_call` with an injected "as of" instant. The - /// public entry point pins it to `Instant::now()`; tests can supply - /// a future instant to exercise TTL eviction without sleeping past - /// [`PENDING_TOOL_CALL_TTL`]. - /// - /// Anonymous claim: returns the oldest *unkeyed* pending id (plus its - /// `identityless` mark, so the delegate-claim path knows to restore the - /// call's identity), GC'ing stale unkeyed entries along the way. KEYED - /// entries are stepped over and left in place — they're reserved for - /// their exact-key-match round-trip and must never be handed out by this - /// arrival-order path (doing so would steal an in-flight delegation's - /// id). Returns `None` when no unkeyed entry is claimable, even if keyed - /// entries remain. - async fn take_pending_tool_call_at( - &self, - parent_connection_id: &str, - now: Instant, - ) -> Option<(String, bool)> { - self.take_unkeyed_tool_call_at(parent_connection_id, now, false) - .await - } - - /// Claim the oldest pending entry that was registered as IDENTITY-LESS - /// (Cursor's `"MCP: tool"` announcements) — used by the status/cancel - /// call-time rename. Unlike `take_pending_tool_call_at` this NEVER hands - /// out a plain unkeyed entry: that one is a delegation invocation whose - /// args merely didn't parse, and renaming it to a status tool would - /// mislabel a real delegate card. - async fn take_identityless_tool_call(&self, parent_connection_id: &str) -> Option { - self.take_unkeyed_tool_call_at(parent_connection_id, Instant::now(), true) - .await - .map(|(id, _)| id) - } - - /// Shared FIFO claim over unkeyed entries. `identityless_only` restricts - /// eligibility to entries carrying the identity-less mark; keyed entries - /// are always stepped over (reserved for their exact-key-match - /// round-trip), and stale unkeyed entries are GC'd along the way - /// regardless of the filter so the queue stays bounded from either - /// caller. - async fn take_unkeyed_tool_call_at( - &self, - parent_connection_id: &str, - now: Instant, - identityless_only: bool, - ) -> Option<(String, bool)> { - let mut map = self.tool_calls.inner.lock().await; - let bucket = map.get_mut(parent_connection_id)?; - // Anonymous claim (post-budget last resort + legacy single-delegation - // path): only UNKEYED entries are eligible. A keyed entry identifies a - // specific in-flight delegation and is claimable ONLY by its - // exact-key-match round-trip; grabbing it here would steal that - // delegation's id and make IT the dead card. Walk oldest→newest, - // GC'ing stale unkeyed entries and stepping over keyed ones, until we - // find the oldest fresh eligible id. When only keyed siblings remain we - // return `None` — the delegate caller then mints a synthetic id rather - // than mis-binding a sibling. - let mut claimed: Option<(String, bool)> = None; - let mut idx = 0; - while idx < bucket.pending.len() { - if bucket.pending[idx].match_key.is_some() { - idx += 1; // keyed: leave it for its exact-match round-trip - continue; - } - if now.duration_since(bucket.pending[idx].registered_at) > PENDING_TOOL_CALL_TTL { - if let Some(stale) = bucket.pending.remove(idx) { - let age_secs = now.duration_since(stale.registered_at).as_secs(); - tracing::info!( - "[delegation] evicting stale UNKEYED ACP tool_call_id={} (age={age_secs}s) on conn={parent_connection_id}", - stale.tool_call_id - ); - } - // `remove` shifted later entries left into `idx`; re-check it. - continue; - } - if identityless_only && !bucket.pending[idx].identityless { - idx += 1; // plain unkeyed: reserved for the delegate FIFO path - continue; - } - claimed = bucket - .pending - .remove(idx) - .map(|p| (p.tool_call_id, p.identityless)); - break; - } - // Same mutex span: record the claim into the consumed memory so - // a concurrent re-register cannot observe "pending empty AND - // consumed missing" and inject a stale duplicate. Consumed - // entries persist for the whole parent connection lifetime - // (no TTL, no cap — see `ToolCallTrackerBucket`) and are only - // released when the parent disconnects. - if let Some((id, _)) = &claimed { - bucket.consumed.push_back((id.clone(), now)); - } - if bucket.pending.is_empty() && bucket.consumed.is_empty() && !bucket.identityless_seen { - map.remove(parent_connection_id); - } - claimed - } - - /// Whether this parent has EVER registered an identity-less candidate — - /// the zero-cost gate for [`Self::rewrite_identityless_tool_call`]'s poll. - async fn has_seen_identityless_tool_calls(&self, parent_connection_id: &str) -> bool { - self.tool_calls - .inner - .lock() - .await - .get(parent_connection_id) - .is_some_and(|b| b.identityless_seen) - } - - /// Restore the identity of a pending identity-less MCP tool call at - /// companion round-trip time: claim the oldest such candidate for this - /// parent and rewrite its live `title` + `raw_input` to the actual - /// codeg-mcp tool (`get_delegation_status` / `cancel_delegation`) with - /// its real arguments — flipping the card from the generic "MCP: tool" - /// WHILE the call runs, instead of only at the completion-time result - /// sniff (which, for a `wait_ms`-blocked status long-poll, can be minutes - /// away). - /// - /// Best-effort by design: on hosts that ship real identities the sticky - /// `identityless_seen` gate skips everything at zero cost; on an - /// identity-less host whose announcement hasn't registered yet, a short - /// bounded poll (well under the ACP-vs-companion race in practice) - /// absorbs the ordering, and a miss simply leaves the rename to the - /// completion sniff. Mis-pairing under PARALLEL identity-less calls in - /// one burst is the same accepted arrival-order residual as the delegate - /// FIFO fallback — Cursor executes tool calls sequentially, so announce - /// order matches round-trip order in practice. - pub async fn rewrite_identityless_tool_call( - &self, - parent_connection_id: &str, - title: &str, - raw_input: serde_json::Value, - ) -> Option { - if !self - .has_seen_identityless_tool_calls(parent_connection_id) - .await - { - return None; - } - for attempt in 0..IDENTITYLESS_RENAME_POLL_ATTEMPTS { - if attempt > 0 { - tokio::time::sleep(CLAIM_POLL_INTERVAL).await; - } - if let Some(id) = self.take_identityless_tool_call(parent_connection_id).await { - tracing::info!( - "[delegation] renaming identity-less tool_call_id={id} on conn={parent_connection_id} to {title}" - ); - self.meta_writer - .write_tool_call_identity(parent_connection_id, &id, title, raw_input) - .await; - return Some(id); - } - } - None - } - - /// Claim the pending `tool_call_id` for `parent_connection_id` whose - /// recorded key matches `key` (exact `(agent_type, task, working_dir)` - /// match). This is the ONLY claim this method makes — it never hands out an - /// unkeyed entry, because an unkeyed entry may belong to a *different* - /// parallel delegation whose round-trip simply hasn't registered (or keyed) - /// its `tool_call` yet, and claiming it by arrival order would steal that - /// sibling's id. Returns `None` (so the caller keeps polling) whenever no - /// entry's key matches — whether keyed siblings or only unkeyed entries are - /// present. - /// - /// Arrival-order FIFO for genuinely keyless hosts is deferred to the - /// post-budget last resort `take_pending_tool_call`, which runs only after - /// the caller has waited its full budget (see - /// `claim_pending_tool_call_with_brief_wait`) — the correct clock for "no - /// key is coming", since a host can serialize a round-trip arbitrarily far - /// behind its `tool_call` registration, so the entry's own age can never - /// prove a key won't still arrive. Evicts stale *unkeyed* entries along the - /// way; keyed entries are retained regardless of age (their round-trip may - /// be serialized far behind earlier delegations — see the retain block) and - /// an exact key match claims them at any age. - pub async fn take_matching_tool_call( - &self, - parent_connection_id: &str, - key: &DelegationMatchKey, - ) -> Option { - self.take_matching_tool_call_at(parent_connection_id, key, Instant::now()) - .await - } - - /// `take_matching_tool_call` with an injected "as of" - /// instant for TTL tests. - async fn take_matching_tool_call_at( - &self, - parent_connection_id: &str, - key: &DelegationMatchKey, - now: Instant, - ) -> Option { - let mut map = self.tool_calls.inner.lock().await; - let bucket = map.get_mut(parent_connection_id)?; - - // Evict every stale UNKEYED entry up front. The key-match scan below - // ignores unkeyed entries anyway (they carry no key to match), but - // GC'ing here keeps the queue bounded during the poll loop and - // consistent with `take_pending_tool_call_at`'s view, so the - // post-budget last resort never hands out an aged-out id. Mirrors that - // TTL skip but covers entries at any position (not just the front). - bucket.pending.retain(|p| { - // Keyed entries are NEVER aged out. Each identifies one specific - // `delegate_to_agent` invocation and is claimable ONLY by an exact - // key match (never by FIFO — see below), so it cannot mis-bind a - // different delegation no matter how old it gets. And it MUST - // survive until its MCP round-trip arrives, which the host may - // serialize arbitrarily far behind earlier long-running - // delegations: Claude Code runs parallel `delegate_to_agent` calls - // SEQUENTIALLY, so the 2nd call's round-trip only fires after the - // 1st child finishes. Observed in the wild — a 2nd delegation whose - // tool_call registered, then waited 77s (past the old 60s TTL) for - // its round-trip while the 1st ran; age-evicting it here orphaned - // it to a synthetic id and left the parent card stuck on - // "sub-agent running…". Only UNKEYED (anonymous, arrival-order - // correlated) entries keep the age-based GC, since a stale one - // could be mis-claimed via the FIFO path. Keyed memory stays bounded - // by exact-match claim, terminal tombstoning, and - // `drop_pending_tool_calls_for_parent` on connection teardown — not - // by this TTL. - if p.match_key.is_some() { - return true; - } - let fresh = now.duration_since(p.registered_at) <= PENDING_TOOL_CALL_TTL; - if !fresh { - let age_secs = now.duration_since(p.registered_at).as_secs(); - tracing::info!( - "[delegation] evicting stale UNKEYED ACP tool_call_id={} (age={age_secs}s) on conn={parent_connection_id}", - p.tool_call_id - ); - } - fresh - }); - - let claimed = if let Some(pos) = bucket - .pending - .iter() - .position(|p| p.match_key.as_ref() == Some(key)) - { - // Exact (agent_type, task) match: deterministic correlation - // regardless of ACP-vs-MCP arrival order or how many delegations - // are in flight. - bucket.pending.remove(pos).map(|p| p.tool_call_id) - } else { - // No exact key match. We deliberately do NOT claim an unkeyed entry - // here — not even the oldest, not even the only one. An unkeyed - // pending entry may belong to a DIFFERENT parallel delegation whose - // own round-trip hasn't yet registered (or keyed) its `tool_call`, - // and claiming it by arrival order would steal that sibling's id — - // the mis-bind this machinery exists to prevent. - // - // Crucially, the ENTRY's age is the wrong clock for "no key is - // coming": a host can serialize a round-trip arbitrarily far behind - // its `tool_call` registration (see the retain block / the - // `keyed_entry_survives_past_ttl` case), so even an old lone unkeyed - // entry can still be a sibling's. The CALLER's own wait is the right - // clock. So return `None` and let - // `claim_pending_tool_call_with_brief_wait` poll: if this - // delegation's key lands (initial register or a later backfill) we - // bind by the exact match above; only after the caller has spent the - // FULL budget does its post-budget last resort - // (`take_pending_tool_call`) claim the oldest unkeyed id in arrival - // order — the best a genuinely keyless host allows, and the point at - // which waiting longer cannot improve correlation. - None - }; - - if let Some(id) = &claimed { - bucket.consumed.push_back((id.clone(), now)); - } - if bucket.pending.is_empty() && bucket.consumed.is_empty() { - map.remove(parent_connection_id); - } - claimed - } - - /// Consume an explicit `parent_tool_use_id` that the MCP client supplied - /// directly via `_meta.tool_use_id` (the precise-binding path; most clients - /// omit it). In that case `handle_request` does NOT run the claim path, so - /// the matching pending entry the lifecycle dispatcher registered off the - /// parent's ACP stream would otherwise never be consumed — and because - /// keyed entries are now retained indefinitely, it would linger and could - /// be mis-claimed by a *later* delegation sharing the same - /// `(agent_type, task, working_dir)` key, retargeting that delegation's - /// writes/events at the wrong (already-handled) card. - /// - /// Remove the entry from the pending queue AND record the id as consumed. - /// Recording consumed also covers the MCP-before-ACP race: a later ACP - /// registration for the same id is dropped by the Tier-1 consumed check in - /// `register_pending_tool_call_with_key_at`, so the entry can't reappear - /// regardless of arrival order. - async fn consume_explicit_tool_call(&self, parent_connection_id: &str, tool_call_id: &str) { - let mut map = self.tool_calls.inner.lock().await; - let bucket = map.entry(parent_connection_id.to_string()).or_default(); - bucket.pending.retain(|p| p.tool_call_id != tool_call_id); - if !bucket.consumed.iter().any(|(id, _)| id == tool_call_id) { - bucket - .consumed - .push_back((tool_call_id.to_string(), Instant::now())); - } - } - - /// Tombstone a parent `tool_call_id` whose `delegate_to_agent` reached a - /// TERMINAL ACP status (`completed`/`failed`) so a stale keyed pending entry - /// can't mis-bind a later delegation. The lifecycle dispatcher calls this - /// from its terminal-`ToolCallUpdate` branch, keyed on `tool_call_id` - /// (a bare terminal update carries no parseable key). - /// - /// The hazard: keyed pending entries are retained regardless of age (see the - /// retain block in `take_matching_tool_call_at`), so if a `delegate_to_agent` - /// tool call goes terminal without its MCP round-trip ever reaching the - /// broker (the call failed, the turn was interrupted, the companion never - /// dispatched), its entry would linger forever and a LATER delegation sharing - /// the same `(agent_type, task, working_dir)` key would claim this dead id, - /// retargeting its writes/events at the wrong card. Same hazard - /// `consume_explicit_tool_call` guards on the explicit-id path; this is its - /// terminal-status sibling. - /// - /// Safe synchronously, no grace window: a terminal `completed` can only - /// arrive AFTER the round-trip's claim already removed the entry (the ack - /// that claim produces is what lets the parent's tool call return), and a - /// serialized sibling still awaiting its (observed 77s-late) round-trip is - /// NON-terminal while it waits — so this never evicts a live entry. - /// - /// Records `consumed` ONLY when an entry was actually removed: this runs for - /// EVERY terminal tool-call update (the vast majority are non-delegations), - /// and `consumed` has no TTL/cap, so recording unconditionally would grow it - /// with every completed tool call. Recording on a real removal still drops an - /// out-of-order re-registration of the same id via the Tier-1 consumed check - /// in `register_pending_tool_call_with_key_at`. Returns whether an entry was - /// removed (for the dispatcher's gated log). - pub async fn tombstone_pending_tool_call( - &self, - parent_connection_id: &str, - tool_call_id: &str, - ) -> bool { - let mut map = self.tool_calls.inner.lock().await; - // No bucket → nothing registered for this parent; nothing to tombstone - // and nothing to record (unlike `consume_explicit_tool_call`, no - // MCP-before-ACP race can land a terminal status before registration on - // the single ordered ACP stream, so we never pre-create a bucket here). - let Some(bucket) = map.get_mut(parent_connection_id) else { - return false; - }; - let before = bucket.pending.len(); - bucket.pending.retain(|p| p.tool_call_id != tool_call_id); - let removed = bucket.pending.len() != before; - if removed && !bucket.consumed.iter().any(|(id, _)| id == tool_call_id) { - bucket - .consumed - .push_back((tool_call_id.to_string(), Instant::now())); - } - removed - } - - /// Correlate an MCP `delegate_to_agent` round-trip to the parent's - /// real ACP `tool_call_id`, polling briefly to absorb the race between - /// two independent arrival paths for the same invocation: - /// - /// * ACP `session/update(tool_call)` → in-process bus → lifecycle - /// dispatcher → `register_pending_tool_call_with_key` - /// * MCP `tools/call` → stdio round-trip → companion → `handle_request` - /// - /// Correlation is by the `(agent_type, task, working_dir)` key (carried in - /// both the ACP `raw_input` and the MCP call), so several `delegate_to_agent` - /// calls firing in parallel each bind to their own `tool_call_id` - /// regardless of arrival order — pure FIFO mis-assigned them (swapping - /// the child shown under each card) or, when one MCP round-trip out-raced - /// its ACP event, orphaned the loser to a synthetic `delegation-` - /// (the parent UI then never paints "view session" and the card hangs on - /// "sub-agent running…", because the frontend keys its binding map by - /// the agent's real `tool_call_id`). - /// - /// As a last resort after the budget — and the ONLY place arrival-order - /// FIFO is applied — claim the oldest unkeyed id, so a sibling whose - /// registration was unusually delayed, or a genuinely keyless host, still - /// yields a *real* id rather than a synthetic one. Deferring FIFO until the - /// full budget has elapsed is what makes it safe: in-loop we bind ONLY by - /// exact key match, so a round-trip can't FIFO-steal a sibling's - /// not-yet-keyed id while that sibling's own registration is still in - /// flight (the entry's age is no proof a key won't still arrive). A - /// synthetic id only results when no unkeyed id is claimable for the whole - /// budget — only keyed siblings remain, or the queue stays genuinely empty. - /// Returns the claimed id plus its `identityless` mark — `true` only for - /// the post-budget FIFO claim of an identity-less announcement (Cursor), - /// which tells `start_delegation` to restore the call's identity on the - /// live tool call. Exact-key claims are by definition NOT identity-less - /// (the key was parsed from the wire's own `raw_input`). - async fn claim_pending_tool_call_with_brief_wait( - &self, - parent_connection_id: &str, - key: &DelegationMatchKey, - ) -> Option<(String, bool)> { - if let Some(id) = self - .take_matching_tool_call(parent_connection_id, key) - .await - { - return Some((id, false)); - } - for _ in 0..CLAIM_POLL_ATTEMPTS { - tokio::time::sleep(CLAIM_POLL_INTERVAL).await; - if let Some(id) = self - .take_matching_tool_call(parent_connection_id, key) - .await - { - return Some((id, false)); - } - } - // Budget exhausted with no key match. As a last resort claim the - // oldest UNKEYED pending id (a host that shipped no parseable - // `raw_input`, or a mixed-shape race) — a real id beats a synthetic - // placeholder that orphans the parent UI binding. Crucially this - // never claims a KEYED entry: those belong to specific in-flight - // delegations and are reserved for their own exact-key-match - // round-trip, so when only keyed siblings remain the caller falls - // through to a synthetic id rather than stealing a sibling's binding - // (which would just move the dead card from one delegation to another). - self.take_pending_tool_call_at(parent_connection_id, Instant::now()) - .await - } - - /// Remove `handle` from the pre-cancel set, returning whether it was - /// present. Used by `handle_request` at two checkpoints (entry + just - /// after pending registration) so a cancel that lost the race with the - /// MCP round-trip still wins. The set is single-shot per handle — - /// taking it here means a subsequent `cancel_by_external_handle` will - /// have to find the pending entry on its own. - async fn take_pre_canceled_handle(&self, handle: &str) -> bool { - let mut state = self.pre_canceled_handles.inner.lock().await; - if state.set.remove(handle) { - // Best-effort companion-side cleanup of `order` so a later - // FIFO eviction doesn't burn a slot. Linear scan is fine — - // PRE_CANCELED_CAP is small. - if let Some(pos) = state.order.iter().position(|h| h == handle) { - state.order.remove(pos); - } - true - } else { - false - } - } - - /// Insert `handle` into the pre-cancel set with FIFO eviction at - /// [`PRE_CANCELED_CAP`]. Idempotent — re-inserting an existing handle - /// is a no-op. - async fn buffer_pre_canceled_handle(&self, handle: String) { - let mut state = self.pre_canceled_handles.inner.lock().await; - if !state.set.insert(handle.clone()) { - return; - } - state.order.push_back(handle); - while state.order.len() > PRE_CANCELED_CAP { - if let Some(evicted) = state.order.pop_front() { - state.set.remove(&evicted); - } - } - } - - /// Forget every pending and recently-consumed tool_call id for the - /// given parent. Called when the parent connection tears down so - /// stale ids don't bind to a future reuse of the same connection_id - /// (UUIDs make that unlikely but cheap to defend against), and so a - /// fresh connection on the reused id is not blocked by the - /// consumed memory of the previous one. - pub async fn drop_pending_tool_calls_for_parent(&self, parent_connection_id: &str) { - self.drop_tool_calls_for_parent(parent_connection_id, false) - .await; - } - - /// Core of the tool_call-tracker drop, shared by the two cancel scopes. - /// - /// * `keep_consumed == false` — genuine connection teardown: remove the - /// whole bucket (`pending` + `consumed`). The connection is going away, - /// so nothing it remembered can mis-bind a future delegation, and a - /// reused connection_id must start clean. - /// * `keep_consumed == true` — turn/prompt cancel with the parent - /// connection STILL ALIVE: TOMBSTONE the cancelled turn's unclaimed - /// `pending` ids into `consumed` and RETAIN the existing `consumed`. Both - /// the already-claimed ids AND the just-cancelled turn's unclaimed ids - /// must keep rejecting a host re-emit (e.g. a terminal status-flip): the - /// Tier-1 consumed check in `register_pending_tool_call_with_key_at` drops - /// the re-emit, so a stale id can't re-register as fresh `pending` and - /// mis-bind the next same-key delegation on this live connection. Merely - /// CLEARING the unclaimed ids would leave them re-registerable, reopening - /// that hole for the unclaimed half (the claimed half was already safe via - /// `consumed`). Retention is connection-scoped and released on teardown — - /// the same unbounded-but-bounded-by-delegation-count envelope `consumed` - /// already lives in for normal end_turn delegations (see - /// [`ToolCallTrackerBucket`]). - /// - /// Tombstoning ALL of `pending` here is safe (no turn/generation tag - /// needed): `run_conversation_loop` drives at most ONE `session/prompt` - /// future per connection at a time (see `acp/connection.rs`), and a - /// parent-side `tool_call` only streams while its prompt future is in - /// flight, so every `pending` id belongs to the single active turn — the one - /// being cancelled — or is a stale leftover from an earlier turn that should - /// be tombstoned regardless. (The per-connection `prompt_lock` only - /// serializes the prompt-SEND handshake, not the turn, so it is NOT the - /// source of this invariant.) The cancelled turn's serialized MCP round-trip - /// won't arrive after cancel, so nothing legitimate is lost. - async fn drop_tool_calls_for_parent(&self, parent_connection_id: &str, keep_consumed: bool) { - let mut map = self.tool_calls.inner.lock().await; - if !keep_consumed { - map.remove(parent_connection_id); - return; - } - if let Some(bucket) = map.get_mut(parent_connection_id) { - // Tombstone the cancelled turn's unclaimed pending ids into - // `consumed` rather than just dropping them, so a later host re-emit - // of one is rejected by the Tier-1 consumed check instead of - // re-registering as a claimable stale entry. `drain` empties - // `pending` first so the subsequent `consumed` borrow is disjoint. - let now = Instant::now(); - let cleared: Vec = bucket.pending.drain(..).map(|p| p.tool_call_id).collect(); - for id in cleared { - if !bucket.consumed.iter().any(|(c, _)| c == &id) { - bucket.consumed.push_back((id, now)); - } - } - // Drop the now-empty bucket only when nothing consumed remains — - // otherwise keep it so the retained `consumed` ids keep rejecting - // re-emits for the rest of this connection's lifetime. - if bucket.consumed.is_empty() { - map.remove(parent_connection_id); - } - } - } - - pub async fn set_config(&self, cfg: DelegationConfig) { - let cap_bytes = cfg.completed_cache_cap_bytes; - *self.config.lock().await = cfg; - // Seed the byte cap into the pending-calls bucket so `insert_completed` - // reads it lock-free (it already holds the pending lock). Acquired AFTER - // the config guard above is dropped — sequential, never nested — so no - // path locks `config` under `pending` or vice-versa (deadlock-free). - // Then prune existing per-parent caches: a LOWERED cap must free memory - // now, not lazily on each parent's next completion (which may never - // arrive for an idle parent). - let mut inner = self.pending.inner.lock().await; - inner.completed_cap_bytes = cap_bytes; - inner.enforce_completed_cap_all_parents(); - } - - pub async fn config_snapshot(&self) -> DelegationConfig { - self.config.lock().await.clone() - } - - /// If this in-flight setup has been flagged canceled by a parent cancel, - /// deregister it and return true. One lock acquisition; used at the - /// pre-spawn / post-spawn checkpoints in `handle_request`. - async fn take_inflight_cancel(&self, inflight_id: u64) -> bool { - let mut inner = self.pending.inner.lock().await; - if inner.inflight_canceled(inflight_id) { - inner.deregister_inflight(inflight_id); - true - } else { - false - } - } - - /// Drop this setup's in-flight record. Called on each `handle_request` - /// early-return that isn't a park hand-off (the park region deregisters - /// inline, atomically with `calls.insert`). - async fn drop_inflight(&self, inflight_id: u64) { - self.pending - .inner - .lock() - .await - .deregister_inflight(inflight_id); - } - - /// Async entry point for `delegate_to_agent`. Does the bounded setup - /// (claim/depth checks → spawn → send first prompt), registers the task in - /// `running`, and returns a `Running` ack [`DelegationTaskReport`] WITHOUT - /// waiting for the child to finish. The child resolves later via the - /// lifecycle → [`complete_call`] (or a cancel path), which migrates the task - /// into `completed` and wakes any `get_delegation_status` long-poll. - /// - /// Returns a terminal report instead of a `Running` ack in three cases: the - /// child finished during setup (fast/empty turn), a parent cancel reached it - /// mid-setup, or setup itself failed (disabled / depth / spawn / send). - /// - /// All the setup-window race machinery (`setups` / `early_*` / `inflight`) - /// is unchanged — it governs terminals that beat registration, which is - /// orthogonal to whether the caller then blocks. The only change vs. the old - /// `handle_request` is that "park a `oneshot` and await it" becomes "insert a - /// [`RunningTask`] and return the ack." - #[tracing::instrument( - name = "delegation_task", - skip_all, - fields( - parent_connection_id = %req.parent_connection_id, - parent_tool_use_id = %req.parent_tool_use_id, - agent_type = ?req.agent_type, - working_dir = ?req.working_dir, - child_connection_id = tracing::field::Empty, - task_id = tracing::field::Empty, - ) - )] - pub async fn start_delegation(&self, mut req: DelegationRequest) -> DelegationTaskReport { - // Register this setup as the VERY FIRST thing — before the pre-cancel - // check's `.await` and the (possibly multi-second) claim poll — so a - // parent cancel landing ANYWHERE from here to park reaches it, not just - // after park (which is all the `cancel_by_parent*` parked-call drain - // covers on its own). The only residual gap is a cancel firing before - // the broker is even invoked for this request, which no - // in-`handle_request` mechanism can observe. Deregistered on every exit - // path below: each early-return via `drop_inflight` / - // `take_inflight_cancel`, or inline at park (atomically with - // `calls.insert`). - let inflight_id = self - .pending - .inner - .lock() - .await - .register_inflight(&req.parent_connection_id); - // Pre-cancel short-circuit. If the MCP companion already received - // `notifications/cancelled` for this `tools/call` before we even - // started processing (cancel ran ahead of the UDS round-trip), we - // claim the handle from the pre-cancel set and bail without - // spawning anything — the caller will not be receiving our - // response either way (the companion suppresses it per MCP spec). - if let Some(handle) = req.external_handle.as_deref() { - if self.take_pre_canceled_handle(handle).await { - self.drop_inflight(inflight_id).await; - // Bailing here BEFORE the claim path means this delegation never - // consumes the ACP `tool_call_id` the lifecycle keyed for it. As - // keyed entries are retained indefinitely, a leftover would let a - // *later* same-`(agent_type, task, working_dir)` delegation claim - // this canceled call's id and bind its writes/events to the wrong - // card. Drain it now (idempotent; the turn-end tombstone is the - // backstop if the ACP event hasn't registered yet). - if req.parent_tool_use_id.is_empty() { - let key = DelegationMatchKey { - agent_type: req.agent_type, - task: req.task.clone(), - working_dir: req.requested_working_dir.clone(), - }; - let _ = self - .take_matching_tool_call(&req.parent_connection_id, &key) - .await; - } else { - self.consume_explicit_tool_call( - &req.parent_connection_id, - &req.parent_tool_use_id, - ) - .await; - } - return report_err( - req.agent_type, - DelegationError::Canceled { - reason: "canceled before spawn".into(), - }, - None, - ); - } - } - // MCP clients usually don't populate `_meta.tool_use_id`, so the - // listener will pass through an empty string. Claim the matching - // ACP-side `tool_call_id` for this parent by task text — with a brief - // poll loop so an MCP round-trip that out-races the in-process ACP - // `session/update` doesn't fall back to a synthetic id (which breaks - // the parent UI's `parent_tool_use_id` binding). Falls back to a UUID - // placeholder only when no id arrives within the wait budget. - if req.parent_tool_use_id.is_empty() { - let match_key = DelegationMatchKey { - agent_type: req.agent_type, - task: req.task.clone(), - working_dir: req.requested_working_dir.clone(), - }; - let claimed = self - .claim_pending_tool_call_with_brief_wait(&req.parent_connection_id, &match_key) - .await; - let claimed_identityless = matches!(claimed, Some((_, true))); - req.parent_tool_use_id = claimed.map(|(id, _)| id).unwrap_or_else(|| { - tracing::warn!( - "[delegation] synthetic fallback for parent_tool_use_id on conn={} (no ACP tool_call_id arrived within claim budget)", - req.parent_connection_id - ); - format!("delegation-{}", uuid::Uuid::new_v4()) - }); - // The claimed announcement never carried an identity (Cursor's - // "MCP: tool" + "{}" — the wire will not re-send title/arguments): - // restore it NOW, before the multi-second spawn, so the live card - // shows the canonical delegate tool with its real arguments while - // the child is still starting. Hosts whose wire carried the - // identity (keyed or explicit-id claims) are left untouched — a - // reconstructed `raw_input` would clobber host-specific fields. - if claimed_identityless { - let mut raw_input = serde_json::Map::new(); - raw_input.insert("task".into(), serde_json::Value::String(req.task.clone())); - if let Ok(at) = serde_json::to_value(req.agent_type) { - raw_input.insert("agent_type".into(), at); - } - if let Some(dir) = req.requested_working_dir.as_deref() { - raw_input.insert("working_dir".into(), serde_json::Value::String(dir.into())); - } - self.meta_writer - .write_tool_call_identity( - &req.parent_connection_id, - &req.parent_tool_use_id, - crate::acp::delegation::DELEGATE_TOOL_REWRITE_TITLE, - serde_json::Value::Object(raw_input), - ) - .await; - } - } else { - // The client gave us the real ACP tool_call_id directly - // (`_meta.tool_use_id`), so we skip the claim path — but the - // lifecycle dispatcher may already have registered that same id as - // a (now indefinitely-retained) keyed pending entry. Consume it so - // it can't linger and be mis-claimed by a later same-key - // delegation. Idempotent and order-independent (see the method). - self.consume_explicit_tool_call(&req.parent_connection_id, &req.parent_tool_use_id) - .await; - } - let cfg = self.config_snapshot().await; - if !cfg.enabled { - self.drop_inflight(inflight_id).await; - return report_err( - req.agent_type, - DelegationError::Canceled { - reason: "delegation disabled".into(), - }, - None, - ); - } - - // --- Depth pre-check ---------------------------------------------------- - // We walk up to `limit + 1` so we know whether the *new* child would - // sit at >= limit. Cycles/dead chains saturate at the cap. - let lookup = self.depth_lookup.clone(); - let parent_depth = match crate::acp::delegation::depth::compute_depth( - req.parent_conversation_id, - |id| { - let lookup = lookup.clone(); - async move { lookup.parent_of(id).await } - }, - cfg.depth_limit + 1, - ) - .await - { - Ok(d) => d, - Err(e) => { - self.drop_inflight(inflight_id).await; - return report_err(req.agent_type, e, None); - } - }; - // The child the broker is about to create would sit at `parent_depth + 1`. - // Reject only when the *child* depth would strictly exceed the limit; - // a child sitting exactly at `depth_limit` is allowed. - if parent_depth + 1 > cfg.depth_limit { - self.drop_inflight(inflight_id).await; - return report_err( - req.agent_type, - DelegationError::DepthLimitExceeded { - current_depth: parent_depth, - limit: cfg.depth_limit, - }, - None, - ); - } - - // --- Spawn child connection -------------------------------------------- - // Pull per-agent overrides from the broker config (defaults to empty). - // Cloning is cheap — `AgentDelegationDefaults` is at most one Option - // and a small BTreeMap, and the spawner consumes both fields by value. - let (preferred_mode_id, preferred_config_values) = cfg - .agent_defaults - .get(&req.agent_type) - .map(|d: &AgentDelegationDefaults| (d.mode_id.clone(), d.config_values.clone())) - .unwrap_or((None, BTreeMap::new())); - // Checkpoint #1 (opportunistic): if a parent cancel already landed - // during the claim/depth phase, bail before spawning a child the parent - // has abandoned. No child exists yet, so there's nothing to tear down. - if self.take_inflight_cancel(inflight_id).await { - return report_err( - req.agent_type, - DelegationError::Canceled { - reason: "parent canceled".into(), - }, - None, - ); - } - let child_connection_id = match self - .spawner - .spawn( - &req.parent_connection_id, - req.agent_type, - req.working_dir.clone(), - preferred_mode_id, - preferred_config_values, - ) - .await - { - Ok(id) => id, - Err(e) => { - self.drop_inflight(inflight_id).await; - return report_err( - req.agent_type, - DelegationError::SpawnFailed(e.to_string()), - None, - ); - } - }; - - // Checkpoint #2: a parent cancel that landed during spawn() — the child - // now exists but no prompt has been sent, so disconnect it (mirroring - // the send-failure path's disconnect-only teardown) and bail. This is - // the primary guard for the spawn window, which can block while the - // agent process starts up. - if self.take_inflight_cancel(inflight_id).await { - let _ = self.spawner.disconnect(&child_connection_id).await; - return report_err( - req.agent_type, - DelegationError::Canceled { - reason: "parent canceled".into(), - }, - None, - ); - } - - // --- Send linked prompt ------------------------------------------------ - let call_id = uuid::Uuid::new_v4().to_string(); - // Bounded task label used by the started event and every meta write — - // the frontend card's fallback when the parent tool call's `raw_input` - // never carried the arguments (Cursor's identity-less announcements). - let task_preview = truncate_on_char_boundary(&req.task, TASK_PREVIEW_CAP); - // Now that the child connection and task id exist, fill the span's empty - // fields so every subsequent log line in this delegation carries the - // parent→child linkage (see the `delegation_task` span on this fn). - tracing::Span::current().record("child_connection_id", child_connection_id.as_str()); - tracing::Span::current().record("task_id", call_id.as_str()); - let link = DelegationLink { - parent_conversation_id: req.parent_conversation_id, - parent_tool_use_id: req.parent_tool_use_id.clone(), - delegation_call_id: call_id.clone(), - }; - - // Reserve this delegation (both ids) BEFORE sending its first prompt. - // `send_prompt_linked_for_delegation` persists the delegation link onto - // the child row (arming the lifecycle resolver) AND dispatches the - // prompt — after which a fast/empty turn's `TurnComplete` OR an - // immediate child-connection failure can fire before we park the pending - // entry below. The reservation lets those terminal events buffer their - // outcome (see `PendingInner`) for the park to drain, rather than - // no-oping and stranding `rx.await`. There is no `.await` between this - // reservation and `send_prompt` (so nothing the child does can be - // observed before the reservation is in place); it's cleared at park or - // on the send-failure path. Reserving by `call_id` AND - // `child_connection_id` lets each resolver gate on the id it holds — - // `complete_call` the `call_id`, `cancel_by_child_connection` the - // `child_connection_id`. - self.pending - .inner - .lock() - .await - .reserve(&call_id, &child_connection_id); - - let child_conversation_id = match self - .spawner - .send_prompt_linked_for_delegation(&child_connection_id, req.task.clone(), link) - .await - { - Ok(cid) => cid, - Err(e) => { - // Setup failed before parking — release the reservation (and - // discard any terminal that buffered against this delegation in - // the window) so nothing lingers or mis-binds a future id, and - // drop the in-flight record in the same lock acquisition. - { - let mut inner = self.pending.inner.lock().await; - inner.unreserve(&call_id, &child_connection_id); - inner.deregister_inflight(inflight_id); - } - let _ = self.spawner.disconnect(&child_connection_id).await; - return report_err( - req.agent_type, - DelegationError::SpawnFailed(e.to_string()), - None, - ); - } - }; - - // The child is now running. Stamp the start so terminal paths can - // report a real `duration_ms`. - let started_at = Instant::now(); - - // --- Mark the parent's tool call as in-flight ------------------------- - // The frontend's DelegationContext seeds its `parent_tool_use_id`-keyed - // binding map from this meta on snapshot replay, so a page refresh - // mid-delegation can reconstruct the child connection / conversation - // ids without depending on the live `delegation_started` event having - // been received. - self.write_meta_if_real( - &req.parent_connection_id, - &req.parent_tool_use_id, - build_delegation_meta( - "running", - Some(&child_connection_id), - Some(child_conversation_id), - None, - None, - // No meaningful elapsed yet — the child just started. - None, - Some(&task_preview), - Some(&call_id), - ), - ) - .await; - - // Announce the live delegation on the PARENT's event stream so the - // frontend `DelegationContext` binds the child inline and attaches its - // live sub-thread. Symmetric with the terminal `emit_completed_if_real`, - // and — unlike the removed child-stream emit in `send_prompt_linked` — - // delivered on a stream the parent is already attached to in web/server - // mode, carrying the real `parent_connection_id`. - self.emit_started_if_real( - &req.parent_connection_id, - &req.parent_tool_use_id, - &child_connection_id, - child_conversation_id, - req.agent_type, - &task_preview, - &call_id, - ) - .await; - - // --- Register pending, or resolve a terminal that beat us ------------- - // Under a single lock, decide this delegation's fate atomically against - // everything a concurrent resolver may have recorded while we were - // setting up: - // * a child terminal buffered against the reservation — a - // `TurnComplete` via `complete_call` (keyed by `call_id`) OR a child - // failure via `cancel_by_child_connection` (keyed by - // `child_connection_id`); either can race ahead of this park; or - // * a parent cancel that flagged this in-flight setup - // (`mark_inflight_canceled_for_parent`, which runs in the SAME lock - // acquisition that drains the parked `calls`). - // Precedence: strict first-terminal-wins by arrival stamp. Both a child - // terminal and a parent cancel carry the `seq` clock value they were - // recorded at, so whichever landed FIRST wins — a child that completed - // before the cancel keeps its result; a cancel that beat the completion - // discards it (the parent had already abandoned the turn). Ties are - // impossible: every event draws a distinct stamp under this one lock. - // Only when NOTHING beat us do we park for a future resolver, - // deregistering the in-flight record adjacent to `calls.insert` with no - // `.await` between — so a parent cancel serialized AFTER us finds the - // entry in `calls` and drains it, while one serialized BEFORE us is seen - // here via its stamp. When a terminal/cancel DID beat us we deliberately - // DON'T park: resolving inline (never leaving an entry for a second - // resolver to grab) rules out a double-finalize. - enum Disposition { - ChildTerminal(DelegationOutcome), - ParentCanceled, - Running, - } - // Near-zero elapsed for these setup-window races, but measured for - // consistency with the normal terminal paths. - let setup_duration_ms = started_at.elapsed().as_millis() as u64; - let disposition = { - let mut inner = self.pending.inner.lock().await; - // Each buffered child terminal carries (arrival_stamp, outcome). - let child_terminal: Option<(u64, DelegationOutcome)> = - if let Some((stamp, outcome)) = inner.take_early_complete(&call_id) { - Some((stamp, outcome)) - } else { - inner - .take_early_cancel(&child_connection_id) - .map(|(stamp, reason)| { - ( - stamp, - DelegationOutcome::from_err( - DelegationError::Canceled { reason }, - Some(child_conversation_id), - ), - ) - }) - }; - let parent_canceled_at = inner.inflight_canceled_at(inflight_id); - inner.unreserve(&call_id, &child_connection_id); - // For both terminal dispositions we record the completed result - // INSIDE this lock (atomically with unreserve/deregister) so a - // concurrent `get_delegation_status` can never observe the task as - // neither running nor completed. The `Running` arm inserts the live - // task instead of parking a `oneshot` — the caller returns the ack. - let record = |inner: &mut PendingInner, outcome: &DelegationOutcome| { - inner.insert_completed( - &call_id, - build_completed( - &req.parent_connection_id, - child_conversation_id, - req.agent_type, - setup_duration_ms, - outcome, - ), - ); - }; - match (child_terminal, parent_canceled_at) { - // Both raced in the setup window: the earlier arrival stamp wins. - (Some((child_stamp, outcome)), Some(cancel_stamp)) => { - inner.deregister_inflight(inflight_id); - if child_stamp < cancel_stamp { - record(&mut inner, &outcome); - Disposition::ChildTerminal(outcome) - } else { - record( - &mut inner, - &canceled_outcome(child_conversation_id, "parent canceled"), - ); - Disposition::ParentCanceled - } - } - // Only a child terminal fired. - (Some((_, outcome)), None) => { - inner.deregister_inflight(inflight_id); - record(&mut inner, &outcome); - Disposition::ChildTerminal(outcome) - } - // Only a parent cancel fired. - (None, Some(_)) => { - inner.deregister_inflight(inflight_id); - record( - &mut inner, - &canceled_outcome(child_conversation_id, "parent canceled"), - ); - Disposition::ParentCanceled - } - // Nothing beat us — register the running task for a future - // resolver, deregistering the in-flight record adjacent to the - // insert with no `.await` between (so a parent cancel serialized - // AFTER us finds it in `running` and drains it). - (None, None) => { - inner.running.insert( - call_id.clone(), - RunningTask { - child_connection_id: child_connection_id.clone(), - child_conversation_id, - parent_connection_id: req.parent_connection_id.clone(), - parent_tool_use_id: req.parent_tool_use_id.clone(), - agent_type: req.agent_type, - task_preview: task_preview.clone(), - task_id: call_id.clone(), - external_handle: req.external_handle.clone(), - started_at, - last_surfaced_block: None, - }, - ); - inner.deregister_inflight(inflight_id); - Disposition::Running - } - } - }; - - match disposition { - // A child terminal beat registration. Finalize (terminal meta + - // DelegationCompleted event + child teardown) and return the - // terminal report directly. The completed entry was recorded under - // the disposition lock above; wake any long-poll waiter. - Disposition::ChildTerminal(outcome) => { - self.finalize_delegation( - &req.parent_connection_id, - &req.parent_tool_use_id, - &child_connection_id, - child_conversation_id, - req.agent_type, - setup_duration_ms, - &outcome, - &task_preview, - &call_id, - ) - .await; - self.result_notify.notify_waiters(); - return report_from_outcome( - Some(call_id), - Some(req.agent_type), - &outcome, - Some(setup_duration_ms), - ); - } - // A parent cancel reached this delegation mid-setup — after the - // prompt was sent, before we registered. Tear the child down - // ourselves (cancel + disconnect, since a turn is in flight) and - // return a canceled report. The canceled result was recorded above. - Disposition::ParentCanceled => { - self.write_meta_if_real( - &req.parent_connection_id, - &req.parent_tool_use_id, - build_delegation_meta( - "failed", - Some(&child_connection_id), - Some(child_conversation_id), - Some("canceled"), - None, - Some(setup_duration_ms), - Some(&task_preview), - Some(&call_id), - ), - ) - .await; - self.emit_completed_if_real( - &req.parent_connection_id, - &req.parent_tool_use_id, - &child_connection_id, - child_conversation_id, - req.agent_type, - DelegationResultSummary::Err { - error_code: "canceled".to_string(), - }, - ) - .await; - let _ = self.spawner.cancel(&child_connection_id).await; - let _ = self.spawner.disconnect(&child_connection_id).await; - self.result_notify.notify_waiters(); - return report_from_outcome( - Some(call_id), - Some(req.agent_type), - &canceled_outcome(child_conversation_id, "parent canceled"), - Some(setup_duration_ms), - ); - } - // Registered in `running` — fall through to the second pre-cancel - // check, then return the ack. - Disposition::Running => {} - } - - // Second pre-cancel check: a `notifications/cancelled` may have landed - // between the entry-side check and the `running` registration above. If - // so, drain the task ourselves (so a racing `cancel_by_external_handle` - // doesn't double-finalize), record the canceled result, and return a - // canceled report instead of the Running ack. - if let Some(handle) = req.external_handle.as_deref() { - if self.take_pre_canceled_handle(handle).await { - // Capture the elapsed ONCE at terminalization (under the lock, - // when the running task is removed) so the completed-cache, the - // parent-card meta, and the returned report all report the same - // duration. `None` when nothing was drained. - let canceled_duration_ms = { - let mut inner = self.pending.inner.lock().await; - if inner.running.remove(&call_id).is_some() { - let outcome = - canceled_outcome(child_conversation_id, "canceled before await"); - let duration_ms = started_at.elapsed().as_millis() as u64; - inner.insert_completed( - &call_id, - build_completed( - &req.parent_connection_id, - child_conversation_id, - req.agent_type, - duration_ms, - &outcome, - ), - ); - Some(duration_ms) - } else { - None - } - }; - if let Some(duration_ms) = canceled_duration_ms { - self.write_meta_if_real( - &req.parent_connection_id, - &req.parent_tool_use_id, - build_delegation_meta( - "failed", - Some(&child_connection_id), - Some(child_conversation_id), - Some("canceled"), - None, - Some(duration_ms), - Some(&task_preview), - Some(&call_id), - ), - ) - .await; - self.emit_completed_if_real( - &req.parent_connection_id, - &req.parent_tool_use_id, - &child_connection_id, - child_conversation_id, - req.agent_type, - DelegationResultSummary::Err { - error_code: "canceled".to_string(), - }, - ) - .await; - let _ = self.spawner.cancel(&child_connection_id).await; - let _ = self.spawner.disconnect(&child_connection_id).await; - self.result_notify.notify_waiters(); - return report_from_outcome( - Some(call_id), - Some(req.agent_type), - &canceled_outcome(child_conversation_id, "canceled before await"), - Some(duration_ms), - ); - } - } - } - - // Registered and running in the background — return the ack. The child - // resolves later via the lifecycle → `complete_call` (or a cancel path). - running_ack(call_id, child_conversation_id, req.agent_type) - } - - /// Called by the child-session lifecycle subscriber on `TurnComplete` - /// (success path) or by error mappers (failure path). - /// - /// Migrates the task from `running` into `completed` (atomically, under one - /// lock) and then finalizes (terminal meta + `DelegationCompleted` event + - /// child teardown) and wakes any `get_delegation_status` long-poll. - /// - /// If no entry is in `running` under `call_id`, the outcome is buffered for - /// a racing `start_delegation` to drain at registration — but ONLY while the - /// delegation is still reserved (mid-setup). This closes the window where a - /// fast/empty turn's `TurnComplete` propagates through the lifecycle while - /// `start_delegation` is still between `send_prompt` and the `running` - /// insert: the prompt is only *enqueued* by `send_prompt`, and the child - /// loop emits `TurnComplete` independently, so a completion CAN beat it. When - /// the `call_id` is no longer reserved the call was already resolved by - /// another terminal path, so the buffer is skipped (silent no-op). - pub async fn complete_call(&self, call_id: &str, outcome: DelegationOutcome) { - let task = { - let mut inner = self.pending.inner.lock().await; - match inner.running.remove(call_id) { - Some(task) => { - // Atomic running → completed so a concurrent status query - // never sees the task as neither running nor completed. - let duration_ms = task.started_at.elapsed().as_millis() as u64; - inner.insert_completed( - call_id, - build_completed( - &task.parent_connection_id, - task.child_conversation_id, - task.agent_type, - duration_ms, - &outcome, - ), - ); - Some((task, duration_ms)) - } - None => { - // Buffer for the racing `start_delegation` to drain iff still - // reserved (mid-setup); a no-op otherwise, so the clone only - // materializes on the genuine pre-registration race. - inner.buffer_early_complete(call_id, outcome.clone()); - None - } - } - }; - if let Some((task, duration_ms)) = task { - self.finalize_delegation( - &task.parent_connection_id, - &task.parent_tool_use_id, - &task.child_connection_id, - task.child_conversation_id, - task.agent_type, - duration_ms, - &outcome, - &task.task_preview, - &task.task_id, - ) - .await; - self.result_notify.notify_waiters(); - } - } - - /// Write the terminal meta, emit `DelegationCompleted`, and tear down the - /// child for a resolved delegation. Shared by `complete_call` and - /// `start_delegation`'s early-terminal pickup. Mirrors the resolution onto - /// the parent's `delegate_to_agent` ToolCallState meta (including a bounded - /// `text_preview` on the completed path so a post-refresh snapshot renders - /// the result inline) so snapshot recovery shows the final state without the - /// live `delegation_completed` event. Does not touch the pending maps — the - /// caller owns the `running` → `completed` migration. - /// - /// `duration_ms` is the broker-measured elapsed time (from `started_at`), - /// carried onto the event summary so the parent UI shows a real duration. - #[allow(clippy::too_many_arguments)] - async fn finalize_delegation( - &self, - parent_connection_id: &str, - parent_tool_use_id: &str, - child_connection_id: &str, - child_conversation_id: i32, - agent_type: AgentType, - duration_ms: u64, - outcome: &DelegationOutcome, - task_preview: &str, - task_id: &str, - ) { - let meta = match outcome { - DelegationOutcome::Ok(ok) => build_delegation_meta( - "completed", - Some(child_connection_id), - Some(child_conversation_id), - None, - build_text_preview(&ok.text).as_deref(), - Some(duration_ms), - Some(task_preview), - Some(task_id), - ), - DelegationOutcome::Err { code, .. } => build_delegation_meta( - "failed", - Some(child_connection_id), - Some(child_conversation_id), - Some(code), - None, - Some(duration_ms), - Some(task_preview), - Some(task_id), - ), - }; - self.write_meta_if_real(parent_connection_id, parent_tool_use_id, meta) - .await; - self.emit_completed_if_real( - parent_connection_id, - parent_tool_use_id, - child_connection_id, - child_conversation_id, - agent_type, - outcome_to_summary(outcome, duration_ms), - ) - .await; - // v1 one-shot: always tear down the child. - let _ = self.spawner.disconnect(child_connection_id).await; - } - - /// Internal helper — apply the meta write iff the parent's - /// `tool_use_id` refers to a real ACP `tool_call_id`. The - /// broker-synthesized `"delegation-"` placeholder targets no - /// ToolCallState, so emitting a `ToolCallUpdate` against it would be - /// noise that the frontend would route through `apply_tool_call_update` - /// to a non-existent entry. See `meta_writer::is_synthetic_parent_tool_use_id`. - async fn write_meta_if_real( - &self, - parent_connection_id: &str, - parent_tool_use_id: &str, - meta: serde_json::Value, - ) { - if is_synthetic_parent_tool_use_id(parent_tool_use_id) { - return; - } - self.meta_writer - .write_meta(parent_connection_id, parent_tool_use_id, meta) - .await; - } - - /// Internal helper — emit `AcpEvent::DelegationStarted` on the parent's - /// stream iff the `parent_tool_use_id` refers to a real ACP tool_call. - /// Mirror of `emit_completed_if_real`: same synthetic-id skip, and the - /// event rides the parent's stream so the frontend `DelegationContext` - /// receives it via the parent's per-connection attach stream in - /// web/server mode (not only via the desktop firehose). - #[allow(clippy::too_many_arguments)] - async fn emit_started_if_real( - &self, - parent_connection_id: &str, - parent_tool_use_id: &str, - child_connection_id: &str, - child_conversation_id: i32, - agent_type: AgentType, - task_preview: &str, - task_id: &str, - ) { - if is_synthetic_parent_tool_use_id(parent_tool_use_id) { - return; - } - self.event_emitter - .emit_started( - parent_connection_id, - parent_tool_use_id, - child_connection_id, - child_conversation_id, - agent_type, - task_preview, - task_id, - ) - .await; - } - - /// Internal helper — emit `AcpEvent::DelegationCompleted` on the parent's - /// stream iff the `parent_tool_use_id` refers to a real ACP tool_call. - /// Synthetic ids (the `"delegation-"` UUID fallback) map to no - /// live UI binding, so the emit would be wasted noise — same skip - /// criterion as `write_meta_if_real`. - async fn emit_completed_if_real( - &self, - parent_connection_id: &str, - parent_tool_use_id: &str, - child_connection_id: &str, - child_conversation_id: i32, - agent_type: AgentType, - result: DelegationResultSummary, - ) { - if is_synthetic_parent_tool_use_id(parent_tool_use_id) { - return; - } - self.event_emitter - .emit_completed( - parent_connection_id, - parent_tool_use_id, - child_connection_id, - child_conversation_id, - agent_type, - result, - ) - .await; - } - - /// Cancel the pending delegation whose `external_handle` matches. - /// Called by the MCP listener on receipt of `notifications/cancelled` - /// from a companion. When no matching pending entry exists (the - /// cancel arrived before `handle_request` reached the - /// pending-registration phase) the handle is stashed in - /// `pre_canceled_handles` so the in-flight request can drain itself - /// when it tries to register or shortly after. - pub async fn cancel_by_external_handle(&self, external_handle: &str, reason: String) { - let drained = { - let mut inner = self.pending.inner.lock().await; - let keys: Vec = inner - .running - .iter() - .filter(|(_, v)| v.external_handle.as_deref() == Some(external_handle)) - .map(|(k, _)| k.clone()) - .collect(); - drain_and_record_canceled(&mut inner, keys, &reason) - }; - if drained.is_empty() { - // Race: the cancel beat the handle's `running` registration. Buffer - // it (capped, FIFO-evicted) so `start_delegation` can drain itself on - // the next checkpoint instead of proceeding to spawn the child. - self.buffer_pre_canceled_handle(external_handle.to_string()) - .await; - return; - } - for (task, duration_ms) in drained { - // A turn is in flight, so cancel + disconnect. - self.teardown_canceled_child(&task, duration_ms, true).await; - } - self.result_notify.notify_waiters(); - } - - /// Resolve the pending delegation whose child matches - /// `child_connection_id` with a `canceled` outcome. Used when a child - /// session disconnects or errors out without firing a clean - /// TurnComplete — the parent's `tool_use_id` shouldn't dangle. - /// No-op when no matching entry exists. - /// - /// `terminal_error` carries the child connection's last `AcpEvent::Error` - /// detail when the lifecycle worker is dispatching off an `Error` event - /// (vs. a bare `Disconnected`). When present, it gets appended to the - /// `Canceled { reason }` string so the parent agent's tool-call result - /// surfaces the real cause (e.g. "Authentication required", - /// "transport closed") instead of the opaque default. Falls back to - /// the default reason when `None`. - pub async fn cancel_by_child_connection( - &self, - child_connection_id: &str, - terminal_error: Option<&str>, - ) { - let reason = child_canceled_reason(terminal_error); - let drained = { - let mut inner = self.pending.inner.lock().await; - let keys: Vec = inner - .running - .iter() - .filter(|(_, v)| v.child_connection_id == child_connection_id) - .map(|(k, _)| k.clone()) - .collect(); - if keys.is_empty() { - // No running entry. If the child is still reserved, - // `start_delegation` is mid-setup and this failure beat the - // `running` insert — buffer its detail for it to drain at - // registration instead of no-oping. `buffer_child_failure` is a - // no-op when the child isn't reserved, so a normal - // post-resolution child teardown accumulates nothing. - inner.buffer_child_failure( - child_connection_id, - terminal_error.map(|s| s.to_string()), - ); - Vec::new() - } else { - drain_and_record_canceled(&mut inner, keys, &reason) - } - }; - for (task, duration_ms) in drained { - // The child already disconnected/errored — disconnect-only teardown - // (no spawner `cancel`, there's no live turn to interrupt). - self.teardown_canceled_child(&task, duration_ms, false).await; - } - self.result_notify.notify_waiters(); - } - - /// Cascade-cancel every pending delegation owned by `parent_connection_id` - /// when the parent **connection tears down** (disconnect / `run_connection` - /// exit). Drops the parent's entire tool_call tracker bucket (`pending` + - /// `consumed`) since the connection is going away. Runs fully inline — the - /// connection is already exiting, so there is no next prompt to unblock. - pub async fn cancel_by_parent(&self, parent_connection_id: &str) { - let drained = self - .drain_for_parent_cancel(parent_connection_id, false) - .await; - self.finalize_parent_cancel(drained).await; - } - - /// Cascade-cancel every pending delegation owned by `parent_connection_id` - /// for a **turn/prompt cancel** where the parent connection STAYS ALIVE - /// (a non-`end_turn` turn end, or a user Cancel between/within prompts). - /// - /// The fast, turn-scoped part — tombstoning the tool_call tracker and - /// removing this parent's parked calls — runs SYNCHRONOUSLY: the caller - /// awaits it before the connection loop accepts the next prompt, so it can't - /// race a next-turn registration and tombstone/cancel that turn's legitimate - /// entries (the safety the `drop_tool_calls_for_parent` invariant relies - /// on). Only the slow child teardown (meta/emit + spawner `cancel` / - /// `disconnect`, which can block on slow agents) is backgrounded, so the - /// user-visible Cancel path stays responsive. - /// - /// RETAINS the parent's `consumed` tool_call memory (and tombstones the - /// cancelled turn's unclaimed `pending` ids into it): dropping it would let - /// a host re-emit of an already-handled `tool_call_id` re-register and - /// mis-bind the next same-key delegation on this live connection — see - /// `drop_tool_calls_for_parent`. - pub async fn cancel_by_parent_turn(&self, parent_connection_id: &str) { - let drained = self - .drain_for_parent_cancel(parent_connection_id, true) - .await; - // The fast drain above already ran inline (scoped to the just-ended - // turn); background only the slow child teardown. - let broker = self.clone(); - tokio::spawn(async move { - broker.finalize_parent_cancel(drained).await; - }); - } - - /// Fast, lock-guarded part of a parent cancel: drop/tombstone this parent's - /// tool_call tracker (per `keep_consumed`, see `drop_tool_calls_for_parent`) - /// and remove every running task it owns, returning them for the (slow) - /// child teardown. Touches only the two broker mutexes — no spawner I/O — so - /// it is safe to await inline in the connection loop before the next prompt - /// is accepted. - /// - /// `keep_consumed` also governs the completed-cache: a **turn** cancel - /// (`true`) records each drained task as `Canceled` so the still-alive - /// connection's LLM can still query it; a **connection teardown** (`false`) - /// drops the parent's whole completed-cache instead — the parent is gone, so - /// nothing will query it. - async fn drain_for_parent_cancel( - &self, - parent_connection_id: &str, - keep_consumed: bool, - ) -> Vec<(RunningTask, u64)> { - // Also drain any tool_call ids captured ahead of an MCP round-trip that - // never arrived — keeps the map bounded across parent reconnects. - // Teardown drops the whole bucket; a turn cancel keeps `consumed` so a - // later re-emit can't mis-bind the next delegation. - self.drop_tool_calls_for_parent(parent_connection_id, keep_consumed) - .await; - let drained = { - let mut inner = self.pending.inner.lock().await; - // Flag every still-in-flight setup this parent owns in the SAME lock - // acquisition that drains its running tasks: a delegation is then - // caught either here (mid-setup → `start_delegation` tears its child - // down at the next checkpoint) or by the running drain below (already - // registered) — there is no interleaving where both miss it. - inner.mark_inflight_canceled_for_parent(parent_connection_id); - let keys: Vec = inner - .running - .iter() - .filter(|(_, v)| v.parent_connection_id == parent_connection_id) - .map(|(k, _)| k.clone()) - .collect(); - if keep_consumed { - // Turn cancel: connection stays alive → keep each canceled - // result queryable. - drain_and_record_canceled(&mut inner, keys, "parent canceled") - } else { - // Connection teardown: just remove the running tasks and drop the - // whole completed-cache for this parent. No completed entry to - // match, but still capture the elapsed once (at drain time) so - // the teardown meta doesn't recompute it later. - let drained: Vec<(RunningTask, u64)> = keys - .into_iter() - .map(|k| { - let task = inner.running.remove(&k).expect("key just observed"); - let duration_ms = task.started_at.elapsed().as_millis() as u64; - (task, duration_ms) - }) - .collect(); - inner.drop_completed_for_parent(parent_connection_id); - drained - } - }; - self.result_notify.notify_waiters(); - drained - } - - /// Slow part of a parent cancel: for each drained task, patch the parent - /// meta, emit `DelegationCompleted`, and tear the child down. The canceled - /// result was already recorded into `completed` (turn cancel) by - /// `drain_for_parent_cancel` under the lock, so this is pure I/O. Split out - /// so a turn cancel can background it without delaying the fast, turn-scoped - /// drain. - async fn finalize_parent_cancel(&self, drained: Vec<(RunningTask, u64)>) { - for (task, duration_ms) in drained { - // A turn was in flight → cancel + disconnect. - self.teardown_canceled_child(&task, duration_ms, true).await; - } - } - - /// Shared canceled-child teardown: best-effort `failed`/`canceled` meta - /// patch (so a parent-side snapshot post-cancel shows the delegation as - /// canceled rather than stuck on "running"), a `DelegationCompleted` err - /// event, then child teardown. `cancel_turn` is `true` when a turn is in - /// flight (cancel + disconnect) and `false` when the child already - /// disconnected/errored (disconnect only). Does NOT touch the pending maps — - /// the caller already migrated the task into `completed`. - /// - /// `duration_ms` is the elapsed captured by `drain_and_record_canceled` at - /// drain time — reused here (not recomputed) so the parent-card meta matches - /// the completed-cache duration the status/cancel cards report, even when - /// this teardown is backgrounded. - async fn teardown_canceled_child( - &self, - task: &RunningTask, - duration_ms: u64, - cancel_turn: bool, - ) { - self.write_meta_if_real( - &task.parent_connection_id, - &task.parent_tool_use_id, - build_delegation_meta( - "failed", - Some(&task.child_connection_id), - Some(task.child_conversation_id), - Some("canceled"), - None, - Some(duration_ms), - Some(&task.task_preview), - Some(&task.task_id), - ), - ) - .await; - self.emit_completed_if_real( - &task.parent_connection_id, - &task.parent_tool_use_id, - &task.child_connection_id, - task.child_conversation_id, - task.agent_type, - DelegationResultSummary::Err { - error_code: "canceled".to_string(), - }, - ) - .await; - if cancel_turn { - let _ = self.spawner.cancel(&task.child_connection_id).await; - } - let _ = self.spawner.disconnect(&task.child_connection_id).await; - } - - /// Backs the `get_delegation_status` tool for a single task id — a thin - /// wrapper over [`Self::get_tasks_status`] so the single- and batch-poll - /// paths share one snapshot/wait implementation. A one-id batch's - /// "any task settled" wake condition is exactly "this task settled", so the - /// blocking semantics are identical to the historical single-task loop. - pub async fn get_task_status( - &self, - parent_connection_id: &str, - parent_conversation_id: Option, - task_id: &str, - wait: StatusWait, - ) -> DelegationTaskReport { - let ids = [task_id.to_string()]; - self.get_tasks_status(parent_connection_id, parent_conversation_id, &ids, wait) - .await - .pop() - .unwrap_or_else(|| unknown_report(task_id)) - } - - /// Wake every parked status long-poll so it can re-probe its children. - /// - /// Called by the lifecycle dispatcher when ANY connection raises or resolves - /// a blocking prompt — permission, question, or plan approval. Cheap and - /// unconditional: these events are rare, and a wake for a connection that - /// isn't anybody's delegation child just re-snapshots and re-parks, exactly - /// like the spurious wakes `get_tasks_status` already tolerates. - pub fn note_blocking_changed(&self) { - self.result_notify.notify_waiters(); - } - - /// Backs the batch `get_delegation_status` tool. Resolves the status of one - /// or many task ids in a single pass — each from the completed-cache, then - /// the running set, then the DB fallback — scoped to the calling parent (a - /// task owned by another parent reports `Unknown`, never leaking it). Returns - /// one report per requested id, in request order. - /// - /// Blocking obeys [`StatusWait`]: `Immediate` returns the first snapshot. - /// `Bounded`/`Infinite` return as soon as ANY requested task is terminal — - /// INCLUDING one already terminal at entry, so a completed result is never - /// held hostage to a long-running sibling (the caller re-polls the - /// still-running ids to collect the rest) — **or as soon as one becomes - /// blocked on a user decision**. Only an all-running, nothing-newly-blocked - /// batch parks: it wakes when a task settles (the running count drops below - /// the total), when a child raises a blocking prompt, or — for `Bounded` — - /// when the deadline elapses. An all-settled batch returns immediately even - /// under `Infinite`, so it never parks forever. - /// - /// The blocked-return is what closes #447. Without it, a child that hits a - /// permission prompt parks the parent's `wait_ms: 0` call for as long as the - /// user takes to notice — indefinitely, for an unattended run — and the - /// orchestrating LLM cannot even report the stall, because "working" and - /// "waiting on a human" look identical from here. Each blocking prompt is - /// surfaced ONCE (see `RunningTask::last_surfaced_block`), so re-polling an - /// already-reported block goes back to waiting rather than spinning. - pub async fn get_tasks_status( - &self, - parent_connection_id: &str, - parent_conversation_id: Option, - task_ids: &[String], - wait: StatusWait, - ) -> Vec { - if task_ids.is_empty() { - return Vec::new(); - } - // A bounded wait gets a single fixed deadline; Immediate and Infinite - // carry none — Immediate returns on the first pass, Infinite parks on - // `result_notify` until a task is terminal or newly blocked. - let deadline = match wait { - StatusWait::Bounded(ms) => Some(Instant::now() + Duration::from_millis(ms)), - StatusWait::Immediate | StatusWait::Infinite => None, - }; - loop { - // Arm the notify BEFORE the snapshot so a completion landing between - // the snapshot and the await isn't lost (enable() registers now). - let notified = self.result_notify.notified(); - tokio::pin!(notified); - notified.as_mut().enable(); - - // One lock acquisition classifies every requested id. The async - // resolution of running (live reply) / not-in-memory (DB) ids is - // deferred to `assemble_reports`, OUTSIDE this lock. - let classes: Vec = { - let inner = self.pending.inner.lock().await; - task_ids - .iter() - .map(|id| classify_locked(&inner, parent_connection_id, id)) - .collect() - }; - let running_count = classes - .iter() - .filter(|c| matches!(c, StatusClass::Running { .. })) - .count(); - - // Probe each running child for a blocking prompt. Done HERE, after - // the pending lock was dropped at the end of the block above and - // before any early return, because it takes the child's - // `SessionState` lock — the same ordering `attach_live_reply` has - // always used. The result rides along to `assemble_reports` so a - // pass never probes the same child twice. - let blocked = self.probe_blocked(&classes).await; - - // Return now when the poll is Immediate, OR when at least one - // requested task is already (or now) terminal — i.e. not EVERY task - // is still running. This honors the contract "returns as soon as ANY - // requested task reaches a terminal state": a mixed [terminal, - // running] batch surfaces the terminal report immediately instead of - // holding it hostage to a long-running sibling, and the caller - // re-polls (narrowing to the still-running ids) to collect the rest. - // `running_count == 0` (all settled) is the special case that also - // makes Infinite safe. The id set is fixed and a task can only LEAVE - // the running map during a wait (never (re)enter), so once a parked - // all-running batch is woken by a settle the count has dropped below - // the total and this returns; a spurious wake (another parent's task) - // re-snapshots all-running and re-parks. - if matches!(wait, StatusWait::Immediate) || running_count < task_ids.len() { - return self - .assemble_reports(parent_conversation_id, task_ids, classes, blocked) - .await; - } - // Every task is still running, but one of them just parked on the - // user. That is not progress and no completion signal is coming - // until a human acts, so stop waiting and say so. The claim marks - // each prompt as surfaced, so the NEXT poll on the same prompt falls - // through to the park below instead of returning instantly. - let claimed = self.claim_new_blocks(task_ids, &blocked).await; - if claimed.any_claimed { - return self - .assemble_reports(parent_conversation_id, task_ids, classes, blocked) - .await; - } - // A `Bounded` wait gives up at its deadline and returns the running - // snapshot. - let now = Instant::now(); - if deadline.is_some_and(|d| now >= d) { - return self - .assemble_reports(parent_conversation_id, task_ids, classes, blocked) - .await; - } - // Park until the next completion signal — bounded by the deadline - // when there is one, and ALWAYS bounded by `retry_at` when a - // suppressed block is waiting to become reportable again. Without - // that second bound an `Infinite` wait would park on a notify that - // nothing is going to fire: a child parked on a permission emits - // nothing further by itself, so the resurface valve would never get - // a chance to run and a report lost in transit would strand the - // caller for good. - let wake_at = match (deadline, claimed.retry_at) { - (Some(d), Some(r)) => Some(d.min(r)), - (d, r) => d.or(r), - }; - match wake_at { - Some(t) => { - let remaining = t.saturating_duration_since(now); - tokio::select! { - _ = &mut notified => {} - _ = tokio::time::sleep(remaining) => {} - } - } - None => { - notified.await; - } - } - // Loop: re-snapshot (a task likely just completed, the deadline - // passed and the next pass returns the running snapshot, or a - // suppressed block is now reportable again). - } - } - - /// Ask each `Running` entry's child what it is blocked on, position-aligned - /// with `classes` (non-running slots are `None`). One probe per child per - /// pass; must be called with the pending lock RELEASED (it takes the child's - /// `SessionState` lock). - async fn probe_blocked(&self, classes: &[StatusClass]) -> Vec> { - let mut out = Vec::with_capacity(classes.len()); - for class in classes { - let blocked = match class { - StatusClass::Running { - child_connection_id, - .. - } => self.live_reply_lookup.blocked_on(child_connection_id).await, - _ => None, - }; - out.push(blocked); - } - out - } - - /// Claim the blocking prompts in `blocked` that are reportable right now, - /// returning whether any was — and, when none was, the earliest [`Instant`] - /// at which one becomes reportable again. - /// - /// This is the ratchet: a `wait_ms: 0` poll returns the first time a child - /// parks, but a re-poll while the SAME prompt is still unanswered finds - /// nothing new and goes back to waiting — otherwise the caller's wait loop - /// would return instantly forever and burn a round-trip per iteration while - /// the user is simply slow to click. A second, different prompt is new - /// again and returns, and so does the same prompt once - /// [`BLOCK_RESURFACE_INTERVAL`] has passed (the delivery-failure valve — see - /// [`RunningTask::last_surfaced_block`]). - /// - /// Positionally aligned with `task_ids`. Silently skips ids no longer in the - /// running map (settled between the snapshot and here) — those return via - /// the terminal path on the next pass anyway. - async fn claim_new_blocks( - &self, - task_ids: &[String], - blocked: &[Option], - ) -> ClaimedBlocks { - let mut out = ClaimedBlocks::default(); - if blocked.iter().all(|b| b.is_none()) { - return out; - } - let now = Instant::now(); - let mut inner = self.pending.inner.lock().await; - for (id, blocked) in task_ids.iter().zip(blocked) { - let Some(blocked) = blocked else { continue }; - let Some(task) = inner.running.get_mut(id) else { - continue; - }; - if let Some(prev) = task.last_surfaced_block.as_ref() { - if prev.request_id == blocked.request_id { - let due = prev.at + self.block_resurface; - if now < due { - // Not reportable yet. Deliberately does NOT refresh - // `at` — that would push the valve out forever under - // repeated polling. - out.retry_at = Some(out.retry_at.map_or(due, |t: Instant| t.min(due))); - continue; - } - } - } - task.last_surfaced_block = Some(SurfacedBlock { - request_id: blocked.request_id.clone(), - at: now, - }); - out.any_claimed = true; - } - out - } - - /// Finish a batch status pass: resolve each [`StatusClass`] into a final - /// report AFTER the pending lock is released. `Running` ids get their latest - /// live reply (or blocking prompt) attached; `NotInMemory` ids fall back to - /// the DB status lookup. Reports come back in `task_ids` order. - /// - /// `blocked` is the already-probed result from [`Self::probe_blocked`] for - /// this same pass, position-aligned with `classes`. - async fn assemble_reports( - &self, - parent_conversation_id: Option, - task_ids: &[String], - classes: Vec, - blocked: Vec>, - ) -> Vec { - let mut out = Vec::with_capacity(classes.len()); - let mut blocked = blocked.into_iter().chain(std::iter::repeat_with(|| None)); - for (id, class) in task_ids.iter().zip(classes) { - let blocked = blocked.next().flatten(); - let report = match class { - StatusClass::Settled(report) => report, - StatusClass::Running { - mut report, - child_connection_id, - } => { - match blocked { - // A blocked child's last reply is stale by definition — - // it is what it said BEFORE it stopped — so the block - // replaces it rather than competing with it. - Some(blocked) => attach_blocked(&mut report, blocked), - None => { - self.attach_live_reply(&mut report, &child_connection_id) - .await - } - } - report - } - StatusClass::NotInMemory => self.status_from_db(parent_conversation_id, id).await, - }; - out.push(report); - } - out - } - - /// Upgrade a running report's bare `"Running."` message with the child's - /// latest one-line activity, so the parent LLM gets a concrete sign of - /// progress it can report in one shot (instead of polling-and-narrating). - /// Called only on the actual running-return paths, AFTER the pending lock is - /// released. A no-op when the lookup has nothing (default Noop lookup, child - /// gone, or no live output yet) — the report stays `"Running."`. - /// - /// The hint goes on its OWN line (`"Running.\nLatest sub-agent reply: …"`), - /// not appended to the marker line. On hosts that persist only the - /// `CallToolResult` content text (e.g. Claude Code), the frontend recognizes - /// a still-running poll by the standalone first line `"Running."` — keeping - /// the child-controlled reply text on a separate line means a *completed* - /// result that merely starts with "Running. …" can never be misread as - /// running. See `textRunningStatus` in `src/lib/delegation-status.ts`. - async fn attach_live_reply( - &self, - report: &mut DelegationTaskReport, - child_connection_id: &str, - ) { - if let Some(reply) = self - .live_reply_lookup - .latest_reply(child_connection_id) - .await - { - report.message = Some(format!("Running.\nLatest sub-agent reply: {reply}")); - } - } - - /// Backs the `cancel_delegation` tool. Cancels a running task owned by the - /// caller (recording it `Canceled` + tearing the child down) and returns the - /// resulting report. A task that already finished returns its terminal - /// report; one not in memory falls back to the DB status (a finished task - /// can't be canceled). Parent-scoped like `get_task_status`. - pub async fn cancel_task_by_id( - &self, - parent_connection_id: &str, - parent_conversation_id: Option, - task_id: &str, - ) -> DelegationTaskReport { - let drained = { - let mut inner = self.pending.inner.lock().await; - if let Some(c) = inner.completed.get(task_id) { - if c.parent_connection_id == parent_connection_id { - return completed_report(task_id, c); - } - return unknown_report(task_id); - } - match inner.running.get(task_id) { - Some(r) if r.parent_connection_id == parent_connection_id => { - drain_and_record_canceled( - &mut inner, - vec![task_id.to_string()], - "canceled by request", - ) - .pop() - } - Some(_) => return unknown_report(task_id), - None => None, - } - }; - match drained { - Some((task, duration_ms)) => { - // A turn is in flight → cancel + disconnect. Reuse the duration - // captured at drain time for both the teardown meta and the - // report, so all three (completed-cache, meta, report) agree. - self.teardown_canceled_child(&task, duration_ms, true).await; - self.result_notify.notify_waiters(); - report_from_outcome( - Some(task_id.to_string()), - Some(task.agent_type), - &canceled_outcome(task.child_conversation_id, "canceled by request"), - Some(duration_ms), - ) - } - None => self.status_from_db(parent_conversation_id, task_id).await, - } - } - - /// DB status fallback for a task evicted from / never in the in-memory maps. - /// Scopes to the caller's conversation: a child whose `parent_id` doesn't - /// match (or when the caller has no active conversation) reports `Unknown`. - async fn status_from_db( - &self, - parent_conversation_id: Option, - task_id: &str, - ) -> DelegationTaskReport { - match self.status_lookup.find_by_call_id(task_id).await { - Some(rec) - if parent_conversation_id.is_some() && rec.parent_id == parent_conversation_id => - { - db_report(task_id, &rec) - } - _ => unknown_report(task_id), - } - } - - /// Test-only shim preserving the old blocking `handle_request` contract over - /// the async path: start the delegation, then block until it reaches a - /// terminal state (driven by the test's `complete_call` / cancel), mapping - /// the terminal report back to a `DelegationOutcome`. Keeps the broker's - /// extensive setup-window race tests exercising the same lifecycle without - /// each rewriting to the start/poll/collect shape. - #[cfg(any(test, feature = "test-utils"))] - pub async fn handle_request(&self, req: DelegationRequest) -> DelegationOutcome { - let parent_connection_id = req.parent_connection_id.clone(); - let parent_conversation_id = Some(req.parent_conversation_id); - let ack = self.start_delegation(req).await; - let task_id = match ack.task_id.clone() { - Some(id) => id, - // Setup failed before a task existed — the ack itself is terminal. - None => return report_to_outcome(&ack), - }; - if ack.status != TaskStatus::Running { - return report_to_outcome(&ack); - } - // Block until terminal via the long-poll path (re-issued so an - // indefinitely-pending task in a test simply parks here, mirroring the - // old unbounded `rx.await`). - loop { - let report = self - .get_task_status( - &parent_connection_id, - parent_conversation_id, - &task_id, - StatusWait::Bounded(3_600_000), - ) - .await; - if report.status != TaskStatus::Running { - return report_to_outcome(&report); - } - } - } - - #[cfg(any(test, feature = "test-utils"))] - pub async fn peek_first_pending_call_id(&self) -> Option { - self.pending - .inner - .lock() - .await - .running - .keys() - .next() - .cloned() - } - - #[cfg(any(test, feature = "test-utils"))] - pub async fn pending_count(&self) -> usize { - self.pending.inner.lock().await.running.len() - } - - /// Count of cached completed results across all parents. - #[cfg(any(test, feature = "test-utils"))] - pub async fn completed_count(&self) -> usize { - self.pending.inner.lock().await.completed.len() - } - - /// Count of in-flight (registered-at-entry, not-yet-parked / not-yet-exited) - /// `handle_request` setups. Should return to 0 on every exit path. - #[cfg(any(test, feature = "test-utils"))] - pub async fn inflight_count(&self) -> usize { - self.pending.inner.lock().await.inflight.len() - } - - /// Count of in-setup (reserved, not-yet-parked) delegations. Each holds one - /// child and one call_id, so this counts both. - #[cfg(any(test, feature = "test-utils"))] - pub async fn reserved_child_count(&self) -> usize { - self.pending.inner.lock().await.setups.len() - } - - #[cfg(any(test, feature = "test-utils"))] - pub async fn reserved_call_count(&self) -> usize { - self.pending.inner.lock().await.setups.len() - } - - #[cfg(any(test, feature = "test-utils"))] - pub async fn early_cancel_count(&self) -> usize { - self.pending.inner.lock().await.early_cancels.len() - } - - #[cfg(any(test, feature = "test-utils"))] - pub async fn early_complete_count(&self) -> usize { - self.pending.inner.lock().await.early_completes.len() - } - - /// First reserved (mid-setup) `call_id`, if any — lets a test resolve a - /// delegation via `complete_call` while it's pinned in the reserve→park - /// window (its entry isn't parked yet, so `peek_first_pending_call_id` - /// can't see it). - #[cfg(any(test, feature = "test-utils"))] - pub async fn peek_reserved_call_id(&self) -> Option { - self.pending - .inner - .lock() - .await - .setups - .keys() - .next() - .cloned() - } -} - -/// `ConversationDepthLookup` over the live `AppDatabase`. Used by the -/// production wiring; tests use the in-module `MockDepth`. -pub struct DbDepthLookup { - pub db: Arc, -} - -#[async_trait] -impl ConversationDepthLookup for DbDepthLookup { - async fn parent_of(&self, conversation_id: i32) -> Result, DelegationError> { - use sea_orm::EntityTrait; - let row = crate::db::entities::conversation::Entity::find_by_id(conversation_id) - .one(&self.db.conn) - .await - .map_err(|e| DelegationError::SubagentRuntimeError(format!("db: {e}")))?; - Ok(row.and_then(|r| r.parent_id)) - } -} - -/// `ChildStatusLookup` over the live `AppDatabase`. Recovers a delegation -/// task's terminal status (NOT its text — child output isn't in codeg's DB) -/// from the child conversation row once its in-memory result was evicted. -pub struct DbChildStatusLookup { - pub db: Arc, -} - -#[async_trait] -impl ChildStatusLookup for DbChildStatusLookup { - async fn find_by_call_id(&self, call_id: &str) -> Option { - let summary = crate::db::service::conversation_service::get_by_delegation_call_id( - &self.db.conn, - call_id, - ) - .await - .ok() - .flatten()?; - // `summary.status` is the serialized `ConversationStatus` string. - let status = match summary.status.as_str() { - "in_progress" => TaskStatus::Running, - "pending_review" | "completed" => TaskStatus::Completed, - "cancelled" => TaskStatus::Canceled, - _ => TaskStatus::Unknown, - }; - Some(ChildStatusRecord { - child_conversation_id: summary.id, - status, - agent_type: summary.agent_type, - parent_id: summary.parent_id, - }) - } -} - -#[cfg(test)] -mod tests { - use super::*; - use crate::acp::delegation::spawner::{mock::MockSpawner, SpawnerError}; - use crate::acp::delegation::types::DelegationSuccess; - use crate::models::AgentType; - - /// Test-only `ConversationDepthLookup` that resolves against a flat - /// (id, parent_id) table. Unknown ids return `Ok(None)` to keep test - /// setup small. - struct MockDepth(Vec<(i32, Option)>); - - #[async_trait] - impl ConversationDepthLookup for MockDepth { - async fn parent_of(&self, id: i32) -> Result, DelegationError> { - Ok(self.0.iter().find(|(c, _)| *c == id).and_then(|(_, p)| *p)) - } - } - - fn shallow_lookup() -> Arc { - // parent conversation is the root — depth = 0, no rejection. - Arc::new(MockDepth(vec![(1, None)])) as Arc - } - - fn request(parent_conv: i32, tool_use: &str) -> DelegationRequest { - DelegationRequest { - parent_connection_id: "parent-conn".into(), - parent_conversation_id: parent_conv, - parent_tool_use_id: tool_use.into(), - agent_type: AgentType::ClaudeCode, - task: "do x".into(), - working_dir: None, - requested_working_dir: None, - external_handle: None, - } - } - - fn request_with_handle(parent_conv: i32, tool_use: &str, handle: &str) -> DelegationRequest { - let mut r = request(parent_conv, tool_use); - r.external_handle = Some(handle.to_string()); - r - } - - /// Bring the broker's `enabled` switch up before driving any test that - /// hits `handle_request`. Production now defaults to `enabled: false`, - /// so a bare `DelegationBroker::new(...)` would short-circuit before - /// parking a pending entry. Tests that assert disabled behavior set - /// their own config explicitly and skip this helper. - async fn enable_delegation(broker: &DelegationBroker) { - broker - .set_config(DelegationConfig { - enabled: true, - ..DelegationConfig::default() - }) - .await; - } - - // -- Task 4.3 ----------------------------------------------------------- - - #[tokio::test] - async fn config_round_trip() { - let broker = DelegationBroker::new( - Arc::new(MockSpawner::new()) as Arc, - shallow_lookup(), - ); - broker - .set_config(DelegationConfig { - enabled: false, - depth_limit: 5, - ..DelegationConfig::default() - }) - .await; - let got = broker.config_snapshot().await; - assert!(!got.enabled); - assert_eq!(got.depth_limit, 5); - } - - #[tokio::test] - async fn disabled_returns_canceled_without_touching_spawner() { - let mock = Arc::new(MockSpawner::new()); - let broker = - DelegationBroker::new(mock.clone() as Arc, shallow_lookup()); - broker - .set_config(DelegationConfig { - enabled: false, - depth_limit: 2, - ..DelegationConfig::default() - }) - .await; - let outcome = broker.handle_request(request(1, "pt-1")).await; - match outcome { - DelegationOutcome::Err { code, .. } => assert_eq!(code, "canceled"), - _ => panic!("expected Err"), - } - assert!(mock.disconnects.lock().await.is_empty()); - } - - // -- Task 4.4: happy path ---------------------------------------------- - - #[tokio::test] - async fn happy_path_returns_ok_after_complete_call() { - let mock = Arc::new(MockSpawner::new()); - mock.queue_spawn(Ok("child-conn-1".into())).await; - mock.queue_send(Ok(42)).await; - let broker = - DelegationBroker::new(mock.clone() as Arc, shallow_lookup()); - enable_delegation(&broker).await; - - let driver = { - let broker = broker.clone(); - tokio::spawn(async move { broker.handle_request(request(1, "pt-1")).await }) - }; - - // Spin until the broker has registered the pending call so the test - // doesn't race the spawn/send awaits. - let call_id = loop { - if let Some(id) = broker.peek_first_pending_call_id().await { - break id; - } - tokio::time::sleep(Duration::from_millis(5)).await; - }; - - broker - .complete_call( - &call_id, - DelegationOutcome::Ok(DelegationSuccess { - text: "4".into(), - child_conversation_id: 42, - child_agent_type: AgentType::Codex, - turn_count: 1, - duration_ms: 50, - token_usage: None, - }), - ) - .await; - - let outcome = driver.await.unwrap(); - match outcome { - DelegationOutcome::Ok(s) => { - assert_eq!(s.text, "4"); - assert_eq!(s.child_conversation_id, 42); - } - other => panic!("expected Ok, got {other:?}"), - } - assert_eq!(broker.pending_count().await, 0); - // complete_call disconnects the child once. - assert_eq!(mock.disconnects.lock().await.as_slice(), &["child-conn-1"]); - } - - /// `StatusWait::Infinite` (the explicit `wait_ms = 0` escape hatch) must - /// park while the task is still running rather than returning the running - /// snapshot, then resolve to the terminal report once the task completes — - /// no matter how long the child takes. - #[tokio::test] - async fn infinite_wait_parks_until_terminal() { - let mock = Arc::new(MockSpawner::new()); - mock.queue_spawn(Ok("child-conn-1".into())).await; - mock.queue_send(Ok(42)).await; - let broker = - DelegationBroker::new(mock.clone() as Arc, shallow_lookup()); - enable_delegation(&broker).await; - - let ack = broker.start_delegation(request(1, "pt-1")).await; - assert_eq!(ack.status, TaskStatus::Running); - let task_id = ack.task_id.clone().expect("running task carries an id"); - - // Infinite wait: parks on the completion signal instead of returning - // the still-running snapshot. - let waiter = { - let broker = broker.clone(); - let task_id = task_id.clone(); - tokio::spawn(async move { - broker - .get_task_status("parent-conn", Some(1), &task_id, StatusWait::Infinite) - .await - }) - }; - - // Give the waiter a beat — it must still be parked, not finished. - tokio::time::sleep(Duration::from_millis(30)).await; - assert!( - !waiter.is_finished(), - "infinite wait must park while the task is running" - ); - - let call_id = loop { - if let Some(id) = broker.peek_first_pending_call_id().await { - break id; - } - tokio::time::sleep(Duration::from_millis(5)).await; - }; - broker - .complete_call( - &call_id, - DelegationOutcome::Ok(DelegationSuccess { - text: "done".into(), - child_conversation_id: 42, - child_agent_type: AgentType::ClaudeCode, - turn_count: 1, - duration_ms: 5, - token_usage: None, - }), - ) - .await; - - let report = waiter.await.unwrap(); - assert_eq!(report.status, TaskStatus::Completed); - assert_eq!(report.text.as_deref(), Some("done")); - } - - /// A running snapshot upgrades its bare `"Running."` message with the child's - /// latest one-line reply when the live-reply lookup has one. - #[tokio::test] - async fn running_status_appends_live_reply_when_available() { - use crate::acp::delegation::live_reply::mock::MockChildLiveReplyLookup; - - let mock = Arc::new(MockSpawner::new()); - mock.queue_spawn(Ok("child-conn-1".into())).await; - mock.queue_send(Ok(42)).await; - let broker = - DelegationBroker::new(mock.clone() as Arc, shallow_lookup()) - .with_live_reply_lookup(Arc::new(MockChildLiveReplyLookup::new(Some( - "Reading config.rs".into(), - )))); - enable_delegation(&broker).await; - - let ack = broker.start_delegation(request(1, "pt-1")).await; - assert_eq!(ack.status, TaskStatus::Running); - let task_id = ack.task_id.clone().expect("running task carries an id"); - - let report = broker - .get_task_status("parent-conn", Some(1), &task_id, StatusWait::Immediate) - .await; - assert_eq!(report.status, TaskStatus::Running); - // The live hint lands on its own line so a content-only host can anchor - // "still running" to the standalone first line "Running.". - assert_eq!( - report.message.as_deref(), - Some("Running.\nLatest sub-agent reply: Reading config.rs") - ); - } - - /// With no live reply (default Noop lookup / child produced nothing yet) the - /// running snapshot stays the bare `"Running."`. - #[tokio::test] - async fn running_status_stays_bare_without_live_reply() { - let mock = Arc::new(MockSpawner::new()); - mock.queue_spawn(Ok("child-conn-1".into())).await; - mock.queue_send(Ok(42)).await; - let broker = - DelegationBroker::new(mock.clone() as Arc, shallow_lookup()); - enable_delegation(&broker).await; - - let ack = broker.start_delegation(request(1, "pt-1")).await; - let task_id = ack.task_id.clone().expect("running task carries an id"); - - let report = broker - .get_task_status("parent-conn", Some(1), &task_id, StatusWait::Immediate) - .await; - assert_eq!(report.status, TaskStatus::Running); - assert_eq!(report.message.as_deref(), Some("Running.")); - } - - // -- Blocked sub-agents (#447) ----------------------------------------- - - fn permission_block(request_id: &str, title: &str) -> BlockedOn { - BlockedOn { - kind: BlockedKind::Permission, - request_id: request_id.into(), - title: Some(title.into()), - } - } - - /// Spin up a broker whose children all report `blocked` (settable later) and - /// one running task on it. Returns `(broker, lookup, task_id)`. - async fn broker_with_blockable_child() -> ( - DelegationBroker, - Arc, - String, - ) { - // The production interval is minutes; every test but the valve one - // wants "effectively never re-surfaces during this test". - broker_with_blockable_child_resurfacing(Duration::from_secs(3600)).await - } - - async fn broker_with_blockable_child_resurfacing( - resurface: Duration, - ) -> ( - DelegationBroker, - Arc, - String, - ) { - use crate::acp::delegation::live_reply::mock::MockChildLiveReplyLookup; - - let mock = Arc::new(MockSpawner::new()); - mock.queue_spawn(Ok("child-conn-1".into())).await; - mock.queue_send(Ok(42)).await; - let lookup = Arc::new(MockChildLiveReplyLookup::new(Some("Reading x".into()))); - let broker = - DelegationBroker::new(mock.clone() as Arc, shallow_lookup()) - .with_live_reply_lookup(lookup.clone()) - .with_block_resurface(resurface); - enable_delegation(&broker).await; - let task_id = broker - .start_delegation(request(1, "pt-1")) - .await - .task_id - .expect("running task carries an id"); - (broker, lookup, task_id) - } - - /// A child parked on a permission reports `Running` + `blocked_on`, and its - /// message says so INSTEAD of the (now stale) live reply. - #[tokio::test] - async fn blocked_child_reports_blocked_on_over_live_reply() { - let (broker, lookup, task_id) = broker_with_blockable_child().await; - lookup.set_blocked(Some(permission_block("req-1", "rm -rf /tmp/x"))); - - let report = broker - .get_task_status("parent-conn", Some(1), &task_id, StatusWait::Immediate) - .await; - - // Status stays wire-stable `running` — the block rides alongside it, so - // a consumer that predates the field still resolves the poll correctly. - assert_eq!(report.status, TaskStatus::Running); - let blocked = report.blocked_on.expect("blocked_on is set"); - assert_eq!(blocked.kind, BlockedKind::Permission); - assert_eq!(blocked.request_id, "req-1"); - let message = report.message.expect("blocked report carries a message"); - // First line must stay the bare running marker (content-only hosts - // anchor on it), with the note on its own second line. - let mut lines = message.lines(); - assert_eq!(lines.next(), Some("Running.")); - assert_eq!( - lines.next(), - Some("Awaiting your decision: rm -rf /tmp/x"), - "the blocked note replaces the live reply, which is stale by definition" - ); - assert!(!message.contains("Latest sub-agent reply")); - } - - /// The whole point of #447: a `wait_ms: 0` (Infinite) wait must NOT park - /// forever behind a permission prompt. Nothing settles this task — if the - /// block didn't wake it, this test would hang. - #[tokio::test] - async fn infinite_wait_returns_when_the_child_becomes_blocked() { - let (broker, lookup, task_id) = broker_with_blockable_child().await; - lookup.set_blocked(Some(permission_block("req-1", "write to /etc/hosts"))); - - let report = broker - .get_task_status("parent-conn", Some(1), &task_id, StatusWait::Infinite) - .await; - - assert_eq!(report.status, TaskStatus::Running); - assert!(report.blocked_on.is_some()); - } - - /// ...but each prompt is surfaced ONCE. A re-poll while the same prompt is - /// still unanswered goes back to waiting instead of returning instantly, - /// which is what keeps an LLM's wait loop from spinning. A *second*, - /// different prompt is new again and returns. - #[tokio::test] - async fn a_reported_block_does_not_return_twice() { - let (broker, lookup, task_id) = broker_with_blockable_child().await; - lookup.set_blocked(Some(permission_block("req-1", "first"))); - - // First observation returns. - let first = broker - .get_task_status("parent-conn", Some(1), &task_id, StatusWait::Infinite) - .await; - assert_eq!(first.blocked_on.map(|b| b.request_id).as_deref(), Some("req-1")); - - // Same prompt, still unanswered: a bounded wait now runs to its deadline - // rather than returning immediately. - let started = Instant::now(); - let second = broker - .get_task_status("parent-conn", Some(1), &task_id, StatusWait::Bounded(120)) - .await; - assert!( - started.elapsed() >= Duration::from_millis(100), - "an already-reported block must not short-circuit the wait" - ); - // It still REPORTS the block on the way out — only the early return is - // suppressed, never the information. - assert!(second.blocked_on.is_some()); - - // A different prompt is a new event and returns early again. - lookup.set_blocked(Some(permission_block("req-2", "second"))); - let started = Instant::now(); - let third = broker - .get_task_status("parent-conn", Some(1), &task_id, StatusWait::Bounded(5_000)) - .await; - assert!( - started.elapsed() < Duration::from_millis(2_000), - "a NEW blocking prompt must wake the wait" - ); - assert_eq!(third.blocked_on.map(|b| b.request_id).as_deref(), Some("req-2")); - } - - /// The delivery-failure valve: marking a block reported is not proof the - /// parent RECEIVED it (the report still has to cross the listener, the - /// companion's stdout and the agent CLI, and a cancelled or aborted - /// `tools/call` discards it silently). So the SAME unanswered prompt - /// becomes reportable again after the resurface interval — otherwise that - /// one lost report was the only one ever offered and the caller is stranded - /// exactly as before #447. - /// - /// Uses `Infinite`, which has no deadline of its own: if the park weren't - /// bounded by the pending resurface, nothing would ever wake it (a blocked - /// child emits nothing further) and this test would hang. - #[tokio::test] - async fn an_undelivered_block_resurfaces_after_the_interval() { - let (broker, lookup, task_id) = - broker_with_blockable_child_resurfacing(Duration::from_millis(150)).await; - lookup.set_blocked(Some(permission_block("req-1", "first"))); - - // First report — imagine this one never reaches the LLM. - let first = broker - .get_task_status("parent-conn", Some(1), &task_id, StatusWait::Infinite) - .await; - assert!(first.blocked_on.is_some()); - - let started = Instant::now(); - let second = broker - .get_task_status("parent-conn", Some(1), &task_id, StatusWait::Infinite) - .await; - assert_eq!( - second.blocked_on.map(|b| b.request_id).as_deref(), - Some("req-1"), - "the same unanswered prompt must become reportable again" - ); - assert!( - started.elapsed() >= Duration::from_millis(120), - "it must WAIT out the interval, not return instantly (that would be the spin)" - ); - } - - /// An unblocked child is unchanged: no `blocked_on`, live reply intact, and - /// an Infinite wait still parks (proven by a Bounded wait running its full - /// deadline out). - #[tokio::test] - async fn unblocked_child_still_parks_and_keeps_its_live_reply() { - let (broker, _lookup, task_id) = broker_with_blockable_child().await; - - let started = Instant::now(); - let report = broker - .get_task_status("parent-conn", Some(1), &task_id, StatusWait::Bounded(120)) - .await; - assert!(started.elapsed() >= Duration::from_millis(100)); - assert!(report.blocked_on.is_none()); - assert_eq!( - report.message.as_deref(), - Some("Running.\nLatest sub-agent reply: Reading x") - ); - } - - // -- Batch get_tasks_status -------------------------------------------- - - /// Queue one spawn+send pair and start a delegation, returning its task id. - /// Each call consumes one queued `(spawn, send)` from the mock. - async fn start_running( - broker: &DelegationBroker, - mock: &MockSpawner, - child_conn: &str, - child_conv: i32, - tool_use: &str, - ) -> String { - mock.queue_spawn(Ok(child_conn.into())).await; - mock.queue_send(Ok(child_conv)).await; - broker - .start_delegation(request(1, tool_use)) - .await - .task_id - .expect("running task carries an id") - } - - /// The single-id batch agrees with `get_task_status` for a completed task — - /// the refactor that routes the single path through `get_tasks_status` keeps - /// the historical contract. - #[tokio::test] - async fn get_tasks_status_single_matches_get_task_status() { - let mock = Arc::new(MockSpawner::new()); - let broker = - DelegationBroker::new(mock.clone() as Arc, shallow_lookup()); - enable_delegation(&broker).await; - let t1 = start_running(&broker, &mock, "child-1", 42, "pt-1").await; - broker - .complete_call( - &t1, - DelegationOutcome::Ok(DelegationSuccess { - text: "done".into(), - child_conversation_id: 42, - child_agent_type: AgentType::Codex, - turn_count: 1, - duration_ms: 7, - token_usage: None, - }), - ) - .await; - - let single = broker - .get_task_status("parent-conn", Some(1), &t1, StatusWait::Immediate) - .await; - let batch = broker - .get_tasks_status( - "parent-conn", - Some(1), - std::slice::from_ref(&t1), - StatusWait::Immediate, - ) - .await; - assert_eq!(batch.len(), 1); - assert_eq!(batch[0].status, single.status); - assert_eq!(batch[0].text, single.text); - assert_eq!(batch[0].task_id, single.task_id); - } - - /// An immediate batch poll resolves a mix of completed / running / unknown - /// tasks in ONE pass, preserving request order. - #[tokio::test] - async fn batch_status_immediate_mixed_preserves_order() { - let mock = Arc::new(MockSpawner::new()); - let broker = - DelegationBroker::new(mock.clone() as Arc, shallow_lookup()); - enable_delegation(&broker).await; - let t1 = start_running(&broker, &mock, "child-1", 1, "pt-1").await; - let t2 = start_running(&broker, &mock, "child-2", 2, "pt-2").await; - broker - .complete_call( - &t1, - DelegationOutcome::Ok(DelegationSuccess { - text: "first".into(), - child_conversation_id: 1, - child_agent_type: AgentType::Codex, - turn_count: 1, - duration_ms: 3, - token_usage: None, - }), - ) - .await; - - let ids = vec![t1.clone(), t2.clone(), "no-such-id".to_string()]; - let reports = broker - .get_tasks_status("parent-conn", Some(1), &ids, StatusWait::Immediate) - .await; - assert_eq!(reports.len(), 3); - assert_eq!(reports[0].status, TaskStatus::Completed); - assert_eq!(reports[0].text.as_deref(), Some("first")); - assert_eq!(reports[0].task_id.as_deref(), Some(t1.as_str())); - assert_eq!(reports[1].status, TaskStatus::Running); - assert_eq!(reports[1].task_id.as_deref(), Some(t2.as_str())); - assert_eq!(reports[2].status, TaskStatus::Unknown); - } - - /// A batch `Infinite` wait returns as soon as ANY requested task settles, - /// leaving the still-running siblings in the snapshot. - #[tokio::test] - async fn batch_infinite_returns_when_any_settles() { - let mock = Arc::new(MockSpawner::new()); - let broker = - DelegationBroker::new(mock.clone() as Arc, shallow_lookup()); - enable_delegation(&broker).await; - let t1 = start_running(&broker, &mock, "child-1", 1, "pt-1").await; - let t2 = start_running(&broker, &mock, "child-2", 2, "pt-2").await; - - let waiter = { - let broker = broker.clone(); - let ids = vec![t1.clone(), t2.clone()]; - tokio::spawn(async move { - broker - .get_tasks_status("parent-conn", Some(1), &ids, StatusWait::Infinite) - .await - }) - }; - tokio::time::sleep(Duration::from_millis(30)).await; - assert!( - !waiter.is_finished(), - "batch infinite wait must park while both tasks run" - ); - - broker - .complete_call( - &t1, - DelegationOutcome::Ok(DelegationSuccess { - text: "first-done".into(), - child_conversation_id: 1, - child_agent_type: AgentType::Codex, - turn_count: 1, - duration_ms: 4, - token_usage: None, - }), - ) - .await; - - let reports = waiter.await.unwrap(); - assert_eq!(reports.len(), 2); - assert_eq!(reports[0].status, TaskStatus::Completed); - assert_eq!(reports[0].text.as_deref(), Some("first-done")); - assert_eq!(reports[1].status, TaskStatus::Running); - } - - /// A batch `Infinite` wait must NOT hold an already-terminal result hostage - /// to a still-running sibling: when a task is terminal at call ENTRY (it - /// completed before the poll), return immediately with the current snapshot - /// rather than parking for the runner. This is the mixed-at-entry case the - /// transition-only wake used to miss — distinct from - /// [`batch_infinite_returns_when_any_settles`] (both running at entry). - #[tokio::test] - async fn batch_infinite_returns_immediately_when_one_already_terminal() { - let mock = Arc::new(MockSpawner::new()); - let broker = - DelegationBroker::new(mock.clone() as Arc, shallow_lookup()); - enable_delegation(&broker).await; - let t1 = start_running(&broker, &mock, "child-1", 1, "pt-1").await; - let t2 = start_running(&broker, &mock, "child-2", 2, "pt-2").await; - // t1 completes BEFORE the poll; t2 keeps running. - broker - .complete_call( - &t1, - DelegationOutcome::Ok(DelegationSuccess { - text: "first-done".into(), - child_conversation_id: 1, - child_agent_type: AgentType::Codex, - turn_count: 1, - duration_ms: 4, - token_usage: None, - }), - ) - .await; - - // Infinite wait, but one task is already terminal at entry → must return - // at once (a bounded timeout guards against the regression: parking here - // would block until t2 settles, which it never does in this test). - let ids = vec![t1.clone(), t2.clone()]; - let reports = tokio::time::timeout( - Duration::from_secs(2), - broker.get_tasks_status("parent-conn", Some(1), &ids, StatusWait::Infinite), - ) - .await - .expect("a batch with an already-terminal task must not park under Infinite"); - assert_eq!(reports.len(), 2); - assert_eq!(reports[0].status, TaskStatus::Completed); - assert_eq!(reports[0].text.as_deref(), Some("first-done")); - assert_eq!(reports[1].status, TaskStatus::Running); - } - - /// A batch `Infinite` wait where NOTHING is running (all ids unknown) must - /// return immediately rather than parking forever. - #[tokio::test] - async fn batch_infinite_all_settled_returns_immediately() { - let mock = Arc::new(MockSpawner::new()); - let broker = - DelegationBroker::new(mock.clone() as Arc, shallow_lookup()); - enable_delegation(&broker).await; - let ids = vec!["nope-1".to_string(), "nope-2".to_string()]; - let reports = tokio::time::timeout( - Duration::from_secs(2), - broker.get_tasks_status("parent-conn", Some(1), &ids, StatusWait::Infinite), - ) - .await - .expect("all-settled infinite batch must not hang"); - assert_eq!(reports.len(), 2); - assert!(reports.iter().all(|r| r.status == TaskStatus::Unknown)); - } - - /// A bounded batch wait with no completion returns the running snapshot once - /// the deadline elapses (the child keeps running; the caller re-polls). - #[tokio::test] - async fn batch_bounded_deadline_returns_running_snapshot() { - let mock = Arc::new(MockSpawner::new()); - let broker = - DelegationBroker::new(mock.clone() as Arc, shallow_lookup()); - enable_delegation(&broker).await; - let t1 = start_running(&broker, &mock, "child-1", 1, "pt-1").await; - let reports = broker - .get_tasks_status("parent-conn", Some(1), &[t1], StatusWait::Bounded(40)) - .await; - assert_eq!(reports.len(), 1); - assert_eq!(reports[0].status, TaskStatus::Running); - } - - /// A task owned by a different parent reports `Unknown` in a batch — never - /// leaking another parent's task, just like the single-task path. - #[tokio::test] - async fn batch_status_scopes_to_parent() { - let mock = Arc::new(MockSpawner::new()); - let broker = - DelegationBroker::new(mock.clone() as Arc, shallow_lookup()); - enable_delegation(&broker).await; - let t1 = start_running(&broker, &mock, "child-1", 1, "pt-1").await; - let reports = broker - .get_tasks_status("other-parent", Some(2), &[t1], StatusWait::Immediate) - .await; - assert_eq!(reports.len(), 1); - assert_eq!(reports[0].status, TaskStatus::Unknown); - } - - // -- Task 4.5: error paths --------------------------------------------- - - #[tokio::test] - async fn spawn_failure_maps_to_spawn_failed() { - let mock = Arc::new(MockSpawner::new()); - mock.queue_spawn(Err(SpawnerError::Spawn("nope".into()))) - .await; - let broker = DelegationBroker::new(mock as Arc, shallow_lookup()); - enable_delegation(&broker).await; - let outcome = broker.handle_request(request(1, "pt-1")).await; - match outcome { - DelegationOutcome::Err { code, .. } => assert_eq!(code, "spawn_failed"), - other => panic!("expected Err, got {other:?}"), - } - } - - #[tokio::test] - async fn agent_defaults_are_forwarded_to_spawner() { - // Configure broker with per-agent defaults for ClaudeCode and verify - // they reach the spawner. Other agent types should still get the - // empty/None defaults. - let mock = Arc::new(MockSpawner::new()); - mock.queue_spawn(Ok("child-1".into())).await; - mock.queue_send(Err(SpawnerError::Send("stop after spawn".into()))) - .await; - let broker = - DelegationBroker::new(mock.clone() as Arc, shallow_lookup()); - - let mut claude_cfg = BTreeMap::new(); - claude_cfg.insert("model".into(), "claude-sonnet-4-5".into()); - let mut agent_defaults = BTreeMap::new(); - agent_defaults.insert( - AgentType::ClaudeCode, - AgentDelegationDefaults { - mode_id: Some("auto".into()), - config_values: claude_cfg.clone(), - }, - ); - broker - .set_config(DelegationConfig { - enabled: true, - depth_limit: 8, - agent_defaults, - ..DelegationConfig::default() - }) - .await; - - let _ = broker.handle_request(request(1, "pt-1")).await; - - let args = mock.spawn_args.lock().await; - assert_eq!(args.len(), 1); - let call = &args[0]; - assert_eq!(call.agent_type, AgentType::ClaudeCode); - assert_eq!(call.preferred_mode_id.as_deref(), Some("auto")); - assert_eq!(call.preferred_config_values, claude_cfg); - } - - #[tokio::test] - async fn agent_with_no_defaults_gets_empty_preferred_args() { - // ClaudeCode is configured in agent_defaults; a Codex request should - // still receive (None, empty) — no cross-contamination. - let mock = Arc::new(MockSpawner::new()); - mock.queue_spawn(Ok("child-1".into())).await; - mock.queue_send(Err(SpawnerError::Send("stop after spawn".into()))) - .await; - let broker = - DelegationBroker::new(mock.clone() as Arc, shallow_lookup()); - - let mut agent_defaults = BTreeMap::new(); - agent_defaults.insert( - AgentType::ClaudeCode, - AgentDelegationDefaults { - mode_id: Some("auto".into()), - config_values: BTreeMap::new(), - }, - ); - broker - .set_config(DelegationConfig { - enabled: true, - depth_limit: 8, - agent_defaults, - ..DelegationConfig::default() - }) - .await; - - let mut codex_req = request(1, "pt-1"); - codex_req.agent_type = AgentType::Codex; - let _ = broker.handle_request(codex_req).await; - - let args = mock.spawn_args.lock().await; - assert_eq!(args.len(), 1); - assert_eq!(args[0].agent_type, AgentType::Codex); - assert!(args[0].preferred_mode_id.is_none()); - assert!(args[0].preferred_config_values.is_empty()); - } - - #[tokio::test] - async fn send_failure_after_spawn_disconnects_child() { - let mock = Arc::new(MockSpawner::new()); - mock.queue_spawn(Ok("c1".into())).await; - mock.queue_send(Err(SpawnerError::Send("agent rejected prompt".into()))) - .await; - let broker = - DelegationBroker::new(mock.clone() as Arc, shallow_lookup()); - enable_delegation(&broker).await; - let outcome = broker.handle_request(request(1, "pt-1")).await; - match outcome { - DelegationOutcome::Err { code, .. } => assert_eq!(code, "spawn_failed"), - other => panic!("expected Err, got {other:?}"), - } - assert_eq!(mock.disconnects.lock().await.as_slice(), &["c1"]); - } - - #[tokio::test] - async fn handle_request_waits_indefinitely_for_completion() { - // No timeout race anymore: handle_request blocks on `rx.await` until - // complete_call / cancel_* fires. This test asserts the pending entry - // sticks around even after a generous idle window. - let mock = Arc::new(MockSpawner::new()); - mock.queue_spawn(Ok("c1".into())).await; - mock.queue_send(Ok(99)).await; - let broker = - DelegationBroker::new(mock.clone() as Arc, shallow_lookup()); - enable_delegation(&broker).await; - - let driver = { - let broker = broker.clone(); - tokio::spawn(async move { broker.handle_request(request(1, "pt-1")).await }) - }; - - tokio::time::sleep(Duration::from_millis(80)).await; - assert_eq!(broker.pending_count().await, 1); - assert!(mock.cancels.lock().await.is_empty()); - - let call_id = broker.peek_first_pending_call_id().await.unwrap(); - broker - .complete_call( - &call_id, - DelegationOutcome::Ok(DelegationSuccess { - text: "done".into(), - child_conversation_id: 99, - child_agent_type: AgentType::Codex, - turn_count: 1, - duration_ms: 50, - token_usage: None, - }), - ) - .await; - - let outcome = driver.await.unwrap(); - match outcome { - DelegationOutcome::Ok(s) => assert_eq!(s.text, "done"), - other => panic!("expected Ok, got {other:?}"), - } - assert_eq!(mock.disconnects.lock().await.as_slice(), &["c1"]); - } - - // -- Task 4.6: parent-cancel cascade ----------------------------------- - - #[tokio::test] - async fn parent_cancel_cancels_all_pending_children() { - let mock = Arc::new(MockSpawner::new()); - for i in 0..3 { - mock.queue_spawn(Ok(format!("c{i}"))).await; - mock.queue_send(Ok(100 + i)).await; - } - let broker = - DelegationBroker::new(mock.clone() as Arc, shallow_lookup()); - enable_delegation(&broker).await; - - let mut handles = Vec::new(); - for i in 0..3 { - let broker = broker.clone(); - handles.push(tokio::spawn(async move { - broker.handle_request(request(1, &format!("pt-{i}"))).await - })); - } - - // Wait until all three are parked. - while broker.pending_count().await < 3 { - tokio::time::sleep(Duration::from_millis(5)).await; - } - - broker.cancel_by_parent("parent-conn").await; - for h in handles { - let outcome = h.await.unwrap(); - match outcome { - DelegationOutcome::Err { code, .. } => assert_eq!(code, "canceled"), - other => panic!("expected canceled, got {other:?}"), - } - } - assert_eq!(mock.cancels.lock().await.len(), 3); - // Each child disconnects exactly once via cancel_by_parent. - assert_eq!(mock.disconnects.lock().await.len(), 3); - } - - #[tokio::test] - async fn cancel_by_parent_ignores_other_parents() { - let mock = Arc::new(MockSpawner::new()); - mock.queue_spawn(Ok("c1".into())).await; - mock.queue_send(Ok(200)).await; - let broker = - DelegationBroker::new(mock.clone() as Arc, shallow_lookup()); - enable_delegation(&broker).await; - - let driver = { - let broker = broker.clone(); - tokio::spawn(async move { broker.handle_request(request(1, "pt-1")).await }) - }; - while broker.pending_count().await == 0 { - tokio::time::sleep(Duration::from_millis(5)).await; - } - - broker.cancel_by_parent("other-parent").await; - // No effect — pending entry still there. - assert_eq!(broker.pending_count().await, 1); - - let call_id = broker.peek_first_pending_call_id().await.unwrap(); - broker - .complete_call( - &call_id, - DelegationOutcome::Ok(DelegationSuccess { - text: "done".into(), - child_conversation_id: 200, - child_agent_type: AgentType::ClaudeCode, - turn_count: 1, - duration_ms: 10, - token_usage: None, - }), - ) - .await; - let outcome = driver.await.unwrap(); - assert!(matches!(outcome, DelegationOutcome::Ok(_))); - } - - // -- Task 4.7: depth limit --------------------------------------------- - - #[tokio::test] - async fn depth_limit_rejects_before_spawn() { - let mock = Arc::new(MockSpawner::new()); - // No queued spawn results — if the broker tries to spawn, it errors loudly. - // chain: 1 (root, None) <- 2 (child of 1) <- 3 (grandchild of 2). - // Parent = grandchild (id 3): parent_depth = 2. With limit = 2, child - // would sit at depth 3 → reject. - let lookup = Arc::new(MockDepth(vec![(1, None), (2, Some(1)), (3, Some(2))])) - as Arc; - let broker = DelegationBroker::new(mock as Arc, lookup); - broker - .set_config(DelegationConfig { - enabled: true, - depth_limit: 2, - ..DelegationConfig::default() - }) - .await; - let outcome = broker.handle_request(request(3, "pt-1")).await; - match outcome { - DelegationOutcome::Err { code, .. } => assert_eq!(code, "depth_limit"), - other => panic!("expected depth_limit, got {other:?}"), - } - } - - // -- Pending tool_call_id queue (MCP `_meta.tool_use_id` fallback) ---- - - #[tokio::test] - async fn pending_tool_call_register_and_take_is_fifo() { - let broker = DelegationBroker::new( - Arc::new(MockSpawner::new()) as Arc, - shallow_lookup(), - ); - broker.register_pending_tool_call("p1", "tc-a".into()).await; - broker.register_pending_tool_call("p1", "tc-b".into()).await; - assert_eq!( - broker.take_pending_tool_call("p1").await.as_deref(), - Some("tc-a") - ); - assert_eq!( - broker.take_pending_tool_call("p1").await.as_deref(), - Some("tc-b") - ); - assert!(broker.take_pending_tool_call("p1").await.is_none()); - } - - #[tokio::test] - async fn register_dedupes_repeated_tool_call_id() { - // Regression: some hosts re-emit `sessionUpdate(tool_call)` (not - // `tool_call_update`) for the same call as raw_input chunks arrive - // or as the status flips. Without dedupe the second push leaves a - // stale id in the queue that mis-binds the next delegation. - let broker = DelegationBroker::new( - Arc::new(MockSpawner::new()) as Arc, - shallow_lookup(), - ); - broker.register_pending_tool_call("p1", "tc-a".into()).await; - broker.register_pending_tool_call("p1", "tc-a".into()).await; - broker.register_pending_tool_call("p1", "tc-a".into()).await; - assert_eq!( - broker.take_pending_tool_call("p1").await.as_deref(), - Some("tc-a") - ); - assert!( - broker.take_pending_tool_call("p1").await.is_none(), - "duplicate register must not leave a stale id in the queue" - ); - } - - #[tokio::test] - async fn register_after_claim_drops_stale_re_emit() { - // Regression for the post-claim re-emit race: a host re-sends - // `sessionUpdate(tool_call)` for the same id after the matching - // MCP round-trip already consumed it (e.g. shipping the - // `completed` status flip or a settled `raw_input`). The - // in-queue dedupe alone leaves the queue empty at that moment, - // so without the recently-consumed memory the re-emit would - // sneak into the queue and mis-bind the next delegation. - let broker = DelegationBroker::new( - Arc::new(MockSpawner::new()) as Arc, - shallow_lookup(), - ); - broker.register_pending_tool_call("p1", "tc-a".into()).await; - assert_eq!( - broker.take_pending_tool_call("p1").await.as_deref(), - Some("tc-a") - ); - // Re-emit of the same id after it was already claimed. - broker.register_pending_tool_call("p1", "tc-a".into()).await; - assert!( - broker.take_pending_tool_call("p1").await.is_none(), - "post-claim re-emit of the same id must not be re-queued" - ); - // A genuinely new id on the same parent still flows through. - broker.register_pending_tool_call("p1", "tc-b".into()).await; - assert_eq!( - broker.take_pending_tool_call("p1").await.as_deref(), - Some("tc-b") - ); - } - - #[tokio::test] - async fn concurrent_take_and_re_register_never_leaks_stale_duplicate() { - // TOCTOU regression: a host re-emit of the same tool_call_id - // racing against the matching take must never inject a stale - // duplicate. Co-locating `pending` and `consumed` under the - // same mutex guarantees the claim → mark-consumed pair is - // atomic, so the only two legal interleavings are: - // - // * take wins → pending=[], consumed=[id]; re-register sees - // the id in consumed and drops it. - // * register wins → pending=[id] (still the original entry, - // in-queue dedupe drops the re-emit); take then pops it - // and records it in consumed. - // - // In neither case may the queue retain a duplicate id once - // both futures settle. We drive many rounds with `tokio::spawn` - // to stress the interleaving. - let broker = std::sync::Arc::new(DelegationBroker::new( - Arc::new(MockSpawner::new()) as Arc, - shallow_lookup(), - )); - for _ in 0..200 { - broker.register_pending_tool_call("p1", "tc-a".into()).await; - let b_take = broker.clone(); - let b_reg = broker.clone(); - let h_take = tokio::spawn(async move { - b_take.take_pending_tool_call("p1").await; - }); - let h_reg = tokio::spawn(async move { - b_reg.register_pending_tool_call("p1", "tc-a".into()).await; - }); - let _ = tokio::join!(h_take, h_reg); - assert!( - broker.take_pending_tool_call("p1").await.is_none(), - "stale duplicate of tc-a leaked after concurrent take + re-register" - ); - } - } - - #[tokio::test] - async fn consumed_memory_outlives_pending_ttl_for_long_running_delegation() { - // Regression: a delegated child agent can run for - // minutes-to-hours. When it finishes, the host may re-emit - // the parent-side `tool_call` (e.g. as a `completed` status - // flip via the non-update `ToolCall` variant). That re-emit - // arrives well after PENDING_TOOL_CALL_TTL, so the consumed - // memory MUST NOT age out under that TTL — otherwise the - // stale id slips back into pending and mis-binds the next - // delegation. Consumed entries are scoped to the parent - // connection's lifetime instead. - let broker = DelegationBroker::new( - Arc::new(MockSpawner::new()) as Arc, - shallow_lookup(), - ); - broker.register_pending_tool_call("p1", "tc-a".into()).await; - assert_eq!( - broker.take_pending_tool_call("p1").await.as_deref(), - Some("tc-a") - ); - // Simulate the host re-emitting the same tool_call_id 10× - // the pending TTL later (i.e. a long-running delegation that - // finishes after the pending eviction window). - let long_after = Instant::now() + PENDING_TOOL_CALL_TTL * 10; - broker - .register_pending_tool_call_with_key_at("p1", "tc-a".into(), None, false, long_after) - .await; - assert!( - broker - .take_pending_tool_call_at("p1", long_after) - .await - .is_none(), - "consumed memory must outlast the pending TTL so terminal status re-emits cannot leak through" - ); - } - - #[tokio::test] - async fn consumed_memory_unbounded_across_high_fan_out() { - // Regression for the cap removal: a parent session with many - // delegations (well past any prior per-bucket cap) must still - // reject a late re-emit of the very first delegation's id, - // because the consumed half has no cap. A bounded consumed - // set with FIFO eviction would silently re-enable the - // mis-binding bug at high fan-out. - let broker = DelegationBroker::new( - Arc::new(MockSpawner::new()) as Arc, - shallow_lookup(), - ); - let first_id = "tc-first".to_string(); - broker - .register_pending_tool_call("p1", first_id.clone()) - .await; - assert_eq!( - broker.take_pending_tool_call("p1").await.as_deref(), - Some(first_id.as_str()) - ); - // Issue many more delegations than any prior per-bucket cap. With - // no cap on consumed, the first id must remain remembered for the - // lifetime of the parent connection. - for i in 0..128 { - let id = format!("tc-{i}"); - broker.register_pending_tool_call("p1", id.clone()).await; - assert_eq!( - broker.take_pending_tool_call("p1").await.as_deref(), - Some(id.as_str()) - ); - } - // Late re-emit of the very first id (would have been evicted - // by the prior bounded consumed FIFO). - broker - .register_pending_tool_call("p1", first_id.clone()) - .await; - assert!( - broker.take_pending_tool_call("p1").await.is_none(), - "consumed memory must retain the very first id even after high fan-out" - ); - } - - #[tokio::test] - async fn consumed_memory_cleared_on_parent_disconnect() { - // The companion to the long-running invariant above: consumed - // memory is scoped to the parent connection's lifetime, so - // `drop_pending_tool_calls_for_parent` (called when the - // parent disconnects) must clear it. Otherwise a brand-new - // connection reusing the same id (UUID collision is unlikely - // but UUIDs are not the only id scheme in play) would be - // permanently blocked. - let broker = DelegationBroker::new( - Arc::new(MockSpawner::new()) as Arc, - shallow_lookup(), - ); - broker.register_pending_tool_call("p1", "tc-a".into()).await; - assert_eq!( - broker.take_pending_tool_call("p1").await.as_deref(), - Some("tc-a") - ); - broker.drop_pending_tool_calls_for_parent("p1").await; - broker.register_pending_tool_call("p1", "tc-a".into()).await; - assert_eq!( - broker.take_pending_tool_call("p1").await.as_deref(), - Some("tc-a"), - "parent disconnect must clear consumed memory so id reuse is acceptable" - ); - } - - #[tokio::test] - async fn take_skips_entries_older_than_ttl() { - // Regression: an ACP `tool_call` whose matching MCP round-trip - // never arrives (host changed its mind, transport dropped, etc.) - // must not sit in the queue forever and mis-bind a subsequent - // delegation. TTL eviction is exercised by advancing the - // injected `as of` instant past PENDING_TOOL_CALL_TTL. - let broker = DelegationBroker::new( - Arc::new(MockSpawner::new()) as Arc, - shallow_lookup(), - ); - let t0 = Instant::now(); - broker - .register_pending_tool_call("p1", "stale".into()) - .await; - // Fresh id registered "just before" the future `now`. - broker - .register_pending_tool_call("p1", "fresh".into()) - .await; - let future_now = t0 + PENDING_TOOL_CALL_TTL + Duration::from_millis(50); - // Forge "fresh" so it survives the TTL: rewrite its timestamp to - // ~now-relative-to-future-now. Direct field access is OK — we're - // a sibling test in the same module. - { - let mut map = broker.tool_calls.inner.lock().await; - let bucket = map.get_mut("p1").expect("bucket present"); - // Re-stamp the second entry ("fresh") to `future_now`. - if let Some(entry) = bucket - .pending - .iter_mut() - .find(|p| p.tool_call_id == "fresh") - { - entry.registered_at = future_now; - } - } - // First entry ("stale", stamped at ~t0) is past TTL relative to - // future_now; the second ("fresh") was just re-stamped to - // future_now and must survive. - assert_eq!( - broker - .take_pending_tool_call_at("p1", future_now) - .await - .map(|(id, _)| id) - .as_deref(), - Some("fresh") - ); - assert!(broker.take_pending_tool_call("p1").await.is_none()); - } - - #[tokio::test] - async fn pending_tool_call_is_isolated_per_parent() { - let broker = DelegationBroker::new( - Arc::new(MockSpawner::new()) as Arc, - shallow_lookup(), - ); - broker.register_pending_tool_call("p1", "p1-a".into()).await; - broker.register_pending_tool_call("p2", "p2-a".into()).await; - assert_eq!( - broker.take_pending_tool_call("p1").await.as_deref(), - Some("p1-a") - ); - assert_eq!( - broker.take_pending_tool_call("p2").await.as_deref(), - Some("p2-a") - ); - assert!(broker.take_pending_tool_call("p1").await.is_none()); - assert!(broker.take_pending_tool_call("p2").await.is_none()); - } - - // -- (agent_type, task) correlation for parallel delegations ---------- - - /// Build a match key with a fixed agent and no explicit working_dir for - /// the common case where the test only varies the task. Use `key_for` to - /// vary the agent, or `key_with_dir` to vary the directory. - fn task_key(task: &str) -> DelegationMatchKey { - key_for(AgentType::Codex, task) - } - - fn key_for(agent_type: AgentType, task: &str) -> DelegationMatchKey { - DelegationMatchKey { - agent_type, - task: task.to_string(), - working_dir: None, - } - } - - fn key_with_dir(task: &str, working_dir: &str) -> DelegationMatchKey { - DelegationMatchKey { - agent_type: AgentType::Codex, - task: task.to_string(), - working_dir: Some(working_dir.to_string()), - } - } - - #[tokio::test] - async fn parallel_delegations_bind_by_key_regardless_of_order() { - // Two `delegate_to_agent` calls fire in parallel; both ACP tool_call - // events register with their key. The MCP round-trips can claim in - // EITHER order — each must bind to its own id by key match, never - // swap. Pure FIFO would hand the first claimer "tc-A" regardless of - // which call it represented. - let broker = DelegationBroker::new( - Arc::new(MockSpawner::new()) as Arc, - shallow_lookup(), - ); - broker - .register_pending_tool_call_with_key("p1", "tc-A".into(), Some(task_key("task A"))) - .await; - broker - .register_pending_tool_call_with_key("p1", "tc-B".into(), Some(task_key("task B"))) - .await; - // Claim "task B" first (reverse of registration order). - assert_eq!( - broker - .take_matching_tool_call("p1", &task_key("task B")) - .await - .as_deref(), - Some("tc-B") - ); - assert_eq!( - broker - .take_matching_tool_call("p1", &task_key("task A")) - .await - .as_deref(), - Some("tc-A") - ); - // A re-claim of an already-consumed key finds nothing. - assert!(broker - .take_matching_tool_call("p1", &task_key("task A")) - .await - .is_none()); - } - - #[tokio::test] - async fn parallel_same_task_different_agent_do_not_swap() { - // Regression for Codex review: two parallel calls with the SAME task - // text but DIFFERENT agents must bind by the full key, not by task - // alone — otherwise the codex card could show the claude_code child - // and vice versa. - let broker = DelegationBroker::new( - Arc::new(MockSpawner::new()) as Arc, - shallow_lookup(), - ); - broker - .register_pending_tool_call_with_key( - "p1", - "tc-codex".into(), - Some(key_for(AgentType::Codex, "review this")), - ) - .await; - broker - .register_pending_tool_call_with_key( - "p1", - "tc-claude".into(), - Some(key_for(AgentType::ClaudeCode, "review this")), - ) - .await; - // The claude_code round-trip must claim the claude_code id even though - // the codex entry shares the identical task and registered first. - assert_eq!( - broker - .take_matching_tool_call("p1", &key_for(AgentType::ClaudeCode, "review this")) - .await - .as_deref(), - Some("tc-claude") - ); - assert_eq!( - broker - .take_matching_tool_call("p1", &key_for(AgentType::Codex, "review this")) - .await - .as_deref(), - Some("tc-codex") - ); - } - - #[tokio::test] - async fn parallel_same_task_same_agent_different_dir_do_not_swap() { - // Regression for Codex review round 2: two parallel calls with the - // SAME agent and SAME task text but DIFFERENT explicit working_dir - // (e.g. "run tests" against /repo-a vs /repo-b) must bind by the full - // key including working_dir. Claimed in reverse registration order to - // prove it's not arrival-order FIFO. - let broker = DelegationBroker::new( - Arc::new(MockSpawner::new()) as Arc, - shallow_lookup(), - ); - broker - .register_pending_tool_call_with_key( - "p1", - "tc-a".into(), - Some(key_with_dir("run tests", "/repo-a")), - ) - .await; - broker - .register_pending_tool_call_with_key( - "p1", - "tc-b".into(), - Some(key_with_dir("run tests", "/repo-b")), - ) - .await; - assert_eq!( - broker - .take_matching_tool_call("p1", &key_with_dir("run tests", "/repo-b")) - .await - .as_deref(), - Some("tc-b") - ); - assert_eq!( - broker - .take_matching_tool_call("p1", &key_with_dir("run tests", "/repo-a")) - .await - .as_deref(), - Some("tc-a") - ); - } - - #[tokio::test] - async fn claim_does_not_steal_sibling_and_waits_for_own_registration() { - // Regression for the reported bug: with only the SIBLING's keyed id - // registered, a delegation must NOT grab it (which would swap the two - // cards) — it waits for its own id. The brief-wait loop picks it up - // once it registers shortly after. - let broker = std::sync::Arc::new(DelegationBroker::new( - Arc::new(MockSpawner::new()) as Arc, - shallow_lookup(), - )); - broker - .register_pending_tool_call_with_key("p1", "tc-A".into(), Some(task_key("task A"))) - .await; - // Immediate claim for "task B" while only tc-A (task A) is pending - // must refuse to steal tc-A. - assert!( - broker - .take_matching_tool_call("p1", &task_key("task B")) - .await - .is_none(), - "must not steal a sibling's keyed id" - ); - // tc-A is still claimable by its own key. - let broker_bg = broker.clone(); - let register_late = tokio::spawn(async move { - tokio::time::sleep(Duration::from_millis(30)).await; - broker_bg - .register_pending_tool_call_with_key("p1", "tc-B".into(), Some(task_key("task B"))) - .await; - }); - // The brief-wait claim polls until tc-B (task B) registers. - let claimed = broker - .claim_pending_tool_call_with_brief_wait("p1", &task_key("task B")) - .await; - register_late.await.unwrap(); - assert_eq!(claimed.map(|(id, _)| id).as_deref(), Some("tc-B")); - // tc-A remains for its own key. - assert_eq!( - broker - .take_matching_tool_call("p1", &task_key("task A")) - .await - .as_deref(), - Some("tc-A") - ); - } - - #[tokio::test] - async fn lone_unkeyed_entry_is_not_claimed_in_loop_only_post_budget() { - // A host that ships no parseable `raw_input` registers match_key=None. - // The in-loop path NEVER claims it — not even when it's the only entry, - // and regardless of how old it gets (10s here). Entry age is no proof a - // key isn't still coming: a serialized round-trip can register/backfill - // arbitrarily late, and the entry could belong to a parallel sibling - // whose owner hasn't registered yet (the staggered-singleton race — - // Codex review). Arrival-order FIFO is reserved for the post-budget last - // resort, which only runs once the CALLER has waited its full budget. - let broker = DelegationBroker::new( - Arc::new(MockSpawner::new()) as Arc, - shallow_lookup(), - ); - broker.register_pending_tool_call("p1", "tc-A".into()).await; - // Even aged 10s (well past any heuristic grace, still < TTL so not - // evicted), the in-loop claim refuses to hand out the unkeyed id. - let way_aged = Instant::now() + Duration::from_secs(10); - assert!( - broker - .take_matching_tool_call_at("p1", &task_key("whatever"), way_aged) - .await - .is_none(), - "an unkeyed entry must never be claimed in-loop, regardless of age" - ); - // The post-budget last resort is where a genuinely keyless entry binds. - assert_eq!( - broker.take_pending_tool_call("p1").await.as_deref(), - Some("tc-A") - ); - } - - #[tokio::test] - async fn parallel_unkeyed_entries_are_not_claimed_in_loop() { - // THE Finding 1 regression. Two delegations whose initial ToolCalls - // registered UNKEYED (args arrive later on a ToolCallUpdate). Before - // either is keyed, a round-trip arrives. The old `all unkeyed → - // pop_front` handed it the OLDEST entry (tc-A), mis-binding it to the - // wrong delegation. The in-loop claim now withholds (None) because no - // key matches — arrival-order FIFO is left to the post-budget last - // resort. Age never unlocks an in-loop claim. - let broker = DelegationBroker::new( - Arc::new(MockSpawner::new()) as Arc, - shallow_lookup(), - ); - broker.register_pending_tool_call("p1", "tc-A".into()).await; - broker.register_pending_tool_call("p1", "tc-B".into()).await; - // Aged (but < TTL, so not evicted): still withheld in-loop. - let aged = Instant::now() + Duration::from_secs(5); - assert!( - broker - .take_matching_tool_call_at("p1", &task_key("task B"), aged) - .await - .is_none(), - "unkeyed siblings must not be FIFO-claimed in-loop" - ); - // Neither entry was consumed. - let map = broker.tool_calls.inner.lock().await; - assert_eq!(map.get("p1").expect("bucket present").pending.len(), 2); - } - - #[tokio::test] - async fn parallel_unkeyed_resolves_by_backfilled_key_not_fifo() { - // The pay-off: while the claim is withheld, the args arrive and - // backfill a key onto the sibling. The round-trip then binds by EXACT - // MATCH to its own id — never the FIFO-oldest. This is the would-be - // mis-bind turned into a correct correlation. - let broker = DelegationBroker::new( - Arc::new(MockSpawner::new()) as Arc, - shallow_lookup(), - ); - broker.register_pending_tool_call("p1", "tc-A".into()).await; - broker.register_pending_tool_call("p1", "tc-B".into()).await; - // tc-B's args land → backfills its key. - broker - .register_pending_tool_call_with_key("p1", "tc-B".into(), Some(task_key("task B"))) - .await; - // The "task B" round-trip binds to tc-B by key, not to the older tc-A. - assert_eq!( - broker - .take_matching_tool_call("p1", &task_key("task B")) - .await - .as_deref(), - Some("tc-B") - ); - // tc-A is untouched, still pending for its own key/round-trip. - let map = broker.tool_calls.inner.lock().await; - let pending = &map.get("p1").expect("bucket present").pending; - assert_eq!(pending.len(), 1); - assert_eq!(pending[0].tool_call_id, "tc-A"); - } - - #[tokio::test] - async fn post_budget_fallback_still_fifos_parallel_unkeyed() { - // A genuinely keyless host (no key ever lands) must still bind both - // parallel delegations end-to-end. The in-loop claim withholds them, - // but the post-budget last resort `take_pending_tool_call` claims them - // oldest-first — the best a keyless host allows, and unchanged from - // before. Only the premature in-loop FIFO is gone. - let broker = DelegationBroker::new( - Arc::new(MockSpawner::new()) as Arc, - shallow_lookup(), - ); - broker.register_pending_tool_call("p1", "tc-A".into()).await; - broker.register_pending_tool_call("p1", "tc-B".into()).await; - assert_eq!( - broker.take_pending_tool_call("p1").await.as_deref(), - Some("tc-A") - ); - assert_eq!( - broker.take_pending_tool_call("p1").await.as_deref(), - Some("tc-B") - ); - } - - #[tokio::test] - async fn brief_wait_binds_own_late_registration_not_unkeyed_sibling() { - // The staggered-singleton timeline Codex flagged, end-to-end: only an - // UNKEYED sibling (tc-A) is visible when a DIFFERENT delegation's - // round-trip (task B) starts claiming; B's own keyed `tool_call` - // registers a little later, still inside the wait budget. The brief-wait - // loop must bind B to its OWN id (tc-B) by exact match, never FIFO-steal - // the older unkeyed tc-A. The old in-loop FIFO popped tc-A on the very - // first poll (all-unkeyed); a grace gate would still steal it once tc-A - // aged past the grace before tc-B arrived. Deferring all FIFO to the - // post-budget — i.e. binding by exact match in-loop only — is what makes - // this correct. - let broker = std::sync::Arc::new(DelegationBroker::new( - Arc::new(MockSpawner::new()) as Arc, - shallow_lookup(), - )); - broker.register_pending_tool_call("p1", "tc-A".into()).await; - // B's own ACP registration lands ~200ms in — well after any age-based - // heuristic would have fired, but far inside the ~2s claim budget. - let broker_bg = broker.clone(); - let register_late = tokio::spawn(async move { - tokio::time::sleep(Duration::from_millis(200)).await; - broker_bg - .register_pending_tool_call_with_key("p1", "tc-B".into(), Some(task_key("task B"))) - .await; - }); - let claimed = broker - .claim_pending_tool_call_with_brief_wait("p1", &task_key("task B")) - .await; - register_late.await.unwrap(); - assert_eq!( - claimed.map(|(id, _)| id).as_deref(), - Some("tc-B"), - "must wait for its own registration, not FIFO-steal the unkeyed sibling" - ); - // tc-A is untouched, still pending for its own correlation. - let map = broker.tool_calls.inner.lock().await; - let pending = &map.get("p1").expect("bucket present").pending; - assert_eq!(pending.len(), 1); - assert_eq!(pending[0].tool_call_id, "tc-A"); - } - - #[tokio::test] - async fn reemit_backfills_key_onto_unkeyed_entry() { - // A host that re-emits the `session/update(tool_call)` variant: the - // first ToolCall has no parseable args (registers match_key=None), a - // later re-emit carries the full args. The re-emit must backfill the - // key onto the existing entry (not push a duplicate, not be dropped) - // so key matching works. - let broker = DelegationBroker::new( - Arc::new(MockSpawner::new()) as Arc, - shallow_lookup(), - ); - broker.register_pending_tool_call("p1", "tc-A".into()).await; - broker - .register_pending_tool_call_with_key("p1", "tc-A".into(), Some(task_key("task A"))) - .await; - // Now claimable by the backfilled key. - assert_eq!( - broker - .take_matching_tool_call("p1", &task_key("task A")) - .await - .as_deref(), - Some("tc-A") - ); - assert!(broker.take_pending_tool_call("p1").await.is_none()); - } - - #[tokio::test] - async fn fallback_never_steals_a_keyed_sibling() { - // A keyed sibling is pending but the requesting round-trip's key never - // matches (its own tool_call was genuinely lost). The post-budget last - // resort must NOT hand out the keyed sibling — stealing it would just - // move the dead card from this delegation to the sibling. It returns - // None (→ caller mints a synthetic id), and the sibling stays claimable - // by its own round-trip. (Regression: the old behavior FIFO-popped the - // keyed entry here, swapping which delegation broke.) - let broker = DelegationBroker::new( - Arc::new(MockSpawner::new()) as Arc, - shallow_lookup(), - ); - broker - .register_pending_tool_call_with_key("p1", "tc-A".into(), Some(task_key("task A"))) - .await; - // No entry matches "task Z", and a keyed entry is present, so the - // match step refuses to claim. - assert!(broker - .take_matching_tool_call("p1", &task_key("task Z")) - .await - .is_none()); - // The post-budget last resort steps over the keyed entry → None. - assert!( - broker.take_pending_tool_call("p1").await.is_none(), - "must not steal a keyed sibling via the anonymous fallback" - ); - // The keyed sibling is untouched — still claimable by its own key. - assert_eq!( - broker - .take_matching_tool_call("p1", &task_key("task A")) - .await - .as_deref(), - Some("tc-A") - ); - } - - #[tokio::test] - async fn keyed_entry_survives_past_ttl_for_serialized_round_trip() { - // THE headline regression for the reported bug. A 2nd parallel - // delegation's tool_call registers (keyed), then its MCP round-trip is - // serialized far behind the 1st delegation — arriving well past - // PENDING_TOOL_CALL_TTL. The keyed entry must NOT be aged out: an exact - // key match claims it at any age, so the parent card binds instead of - // falling to a synthetic id. (Observed live: round-trip landed 77s - // after registration, past the 60s TTL → evicted → synthetic → dead - // card stuck on "sub-agent running…".) - let broker = DelegationBroker::new( - Arc::new(MockSpawner::new()) as Arc, - shallow_lookup(), - ); - broker - .register_pending_tool_call_with_key( - "p1", - "tc-late".into(), - Some(task_key("slow task")), - ) - .await; - // Claim "as of" long past the TTL — simulates the round-trip arriving - // after a many-times-TTL wait behind a serialized sibling. - let way_past_ttl = Instant::now() + PENDING_TOOL_CALL_TTL * 10; - assert_eq!( - broker - .take_matching_tool_call_at("p1", &task_key("slow task"), way_past_ttl) - .await - .as_deref(), - Some("tc-late"), - "a keyed entry must remain claimable by exact key match regardless of age" - ); - } - - #[tokio::test] - async fn unkeyed_entry_is_still_aged_out() { - // The flip side: UNKEYED entries (host shipped no parseable raw_input) - // remain anonymous and arrival-order-correlated, so a stale one MUST - // still be GC'd by age — otherwise it could mis-bind a much later - // unkeyed delegation via the FIFO path. - let broker = DelegationBroker::new( - Arc::new(MockSpawner::new()) as Arc, - shallow_lookup(), - ); - broker - .register_pending_tool_call("p1", "tc-stale".into()) - .await; - let way_past_ttl = Instant::now() + PENDING_TOOL_CALL_TTL * 10; - // Unkeyed + stale → evicted by the match path's GC → nothing to claim. - assert!(broker - .take_matching_tool_call_at("p1", &task_key("whatever"), way_past_ttl) - .await - .is_none()); - // And the anonymous path agrees it's gone. - assert!(broker - .take_pending_tool_call_at("p1", way_past_ttl) - .await - .is_none()); - } - - #[tokio::test] - async fn explicit_tool_use_id_consumes_pending_entry_acp_first() { - // Codex review fix: client supplies the real id via `_meta.tool_use_id` - // AFTER the dispatcher already registered it (ACP-before-MCP). The - // explicit-id path must consume the keyed pending entry so it can't - // linger (keyed entries are retained indefinitely) and be mis-claimed - // by a later same-key delegation. - let broker = DelegationBroker::new( - Arc::new(MockSpawner::new()) as Arc, - shallow_lookup(), - ); - broker - .register_pending_tool_call_with_key("p1", "tc-x".into(), Some(task_key("task A"))) - .await; - broker.consume_explicit_tool_call("p1", "tc-x").await; - // No longer claimable by its key. - assert!(broker - .take_matching_tool_call("p1", &task_key("task A")) - .await - .is_none()); - // A late ACP re-registration of the same id is dropped (consumed). - broker - .register_pending_tool_call_with_key("p1", "tc-x".into(), Some(task_key("task A"))) - .await; - assert!( - broker - .take_matching_tool_call("p1", &task_key("task A")) - .await - .is_none(), - "a re-registration after explicit consume must stay dropped" - ); - } - - #[tokio::test] - async fn explicit_tool_use_id_consumes_pending_entry_mcp_first() { - // The MCP-before-ACP order: the explicit-id request is handled before - // the ACP tool_call event registers. consume_explicit_tool_call records - // the id as consumed up front, so the later registration is dropped. - let broker = DelegationBroker::new( - Arc::new(MockSpawner::new()) as Arc, - shallow_lookup(), - ); - broker.consume_explicit_tool_call("p1", "tc-y").await; - broker - .register_pending_tool_call_with_key("p1", "tc-y".into(), Some(task_key("task B"))) - .await; - assert!(broker - .take_matching_tool_call("p1", &task_key("task B")) - .await - .is_none()); - } - - #[tokio::test] - async fn tombstone_removes_stale_keyed_entry() { - // A `delegate_to_agent` tool call registered a keyed entry but its MCP - // round-trip never reached the broker (the call failed / the turn was - // interrupted). A terminal `ToolCallUpdate` tombstones the entry so it - // can't linger indefinitely (keyed entries are never aged out). - let broker = DelegationBroker::new( - Arc::new(MockSpawner::new()) as Arc, - shallow_lookup(), - ); - broker - .register_pending_tool_call_with_key("p1", "tc-stale".into(), Some(task_key("task A"))) - .await; - assert!(broker.tombstone_pending_tool_call("p1", "tc-stale").await); - assert!(broker - .take_matching_tool_call("p1", &task_key("task A")) - .await - .is_none()); - } - - #[tokio::test] - async fn tombstone_prevents_same_key_misbind() { - // The High regression: without the tombstone, a stale keyed entry is - // retained forever and a LATER identical-key delegation claims its dead - // id (the exact-key scan returns the oldest match). After tombstoning the - // stale entry, a fresh registration for the same key binds to the FRESH - // id instead. - let broker = DelegationBroker::new( - Arc::new(MockSpawner::new()) as Arc, - shallow_lookup(), - ); - broker - .register_pending_tool_call_with_key("p1", "tc-stale".into(), Some(task_key("task A"))) - .await; - broker.tombstone_pending_tool_call("p1", "tc-stale").await; - broker - .register_pending_tool_call_with_key("p1", "tc-fresh".into(), Some(task_key("task A"))) - .await; - assert_eq!( - broker - .take_matching_tool_call("p1", &task_key("task A")) - .await - .as_deref(), - Some("tc-fresh"), - "a later same-key delegation must claim the fresh id, not the tombstoned one" - ); - } - - #[tokio::test] - async fn tombstone_leaves_other_entries_intact() { - // A terminal update for an unrelated (non-delegation) id no-ops and must - // leave a registered delegation untouched. - let broker = DelegationBroker::new( - Arc::new(MockSpawner::new()) as Arc, - shallow_lookup(), - ); - broker - .register_pending_tool_call_with_key("p1", "tc-keep".into(), Some(task_key("task A"))) - .await; - assert!( - !broker - .tombstone_pending_tool_call("p1", "tc-bash-123") - .await - ); - assert_eq!( - broker - .take_matching_tool_call("p1", &task_key("task A")) - .await - .as_deref(), - Some("tc-keep") - ); - } - - #[tokio::test] - async fn tombstone_then_reregister_same_id_stays_dropped() { - // After tombstoning a real entry, an out-of-order re-registration of the - // same id is dropped by the Tier-1 consumed check — mirrors - // `explicit_tool_use_id_consumes_pending_entry_acp_first`. - let broker = DelegationBroker::new( - Arc::new(MockSpawner::new()) as Arc, - shallow_lookup(), - ); - broker - .register_pending_tool_call_with_key("p1", "tc-stale".into(), Some(task_key("task A"))) - .await; - assert!(broker.tombstone_pending_tool_call("p1", "tc-stale").await); - broker - .register_pending_tool_call_with_key("p1", "tc-stale".into(), Some(task_key("task A"))) - .await; - assert!( - broker - .take_matching_tool_call("p1", &task_key("task A")) - .await - .is_none(), - "a re-registration after tombstone must stay dropped" - ); - } - - #[tokio::test] - async fn tombstone_noop_does_not_record_consumed() { - // The tombstone runs for EVERY terminal tool-call update, most of them - // non-delegations. A no-op tombstone (id not pending) must NOT record - // `consumed` — otherwise `consumed` (no TTL/cap) would grow with every - // completed tool call, and a later legitimate registration of that id - // would be wrongly dropped. - let broker = DelegationBroker::new( - Arc::new(MockSpawner::new()) as Arc, - shallow_lookup(), - ); - assert!(!broker.tombstone_pending_tool_call("p1", "tc-x").await); - broker - .register_pending_tool_call_with_key("p1", "tc-x".into(), Some(task_key("task A"))) - .await; - assert_eq!( - broker - .take_matching_tool_call("p1", &task_key("task A")) - .await - .as_deref(), - Some("tc-x"), - "a no-op tombstone must not record consumed and drop a later registration" - ); - } - - #[tokio::test] - async fn tombstone_removes_only_the_matching_entry_from_a_multi_entry_bucket() { - // Tombstoning a MIDDLE entry removes only that id (retain is by exact - // tool_call_id, position-independent) and leaves the siblings claimable - // by their own keys. - let broker = DelegationBroker::new( - Arc::new(MockSpawner::new()) as Arc, - shallow_lookup(), - ); - broker - .register_pending_tool_call_with_key("p1", "tc-a".into(), Some(task_key("task A"))) - .await; - broker - .register_pending_tool_call_with_key("p1", "tc-b".into(), Some(task_key("task B"))) - .await; - broker - .register_pending_tool_call_with_key("p1", "tc-c".into(), Some(task_key("task C"))) - .await; - assert!(broker.tombstone_pending_tool_call("p1", "tc-b").await); - assert!(broker - .take_matching_tool_call("p1", &task_key("task B")) - .await - .is_none()); - assert_eq!( - broker - .take_matching_tool_call("p1", &task_key("task A")) - .await - .as_deref(), - Some("tc-a") - ); - assert_eq!( - broker - .take_matching_tool_call("p1", &task_key("task C")) - .await - .as_deref(), - Some("tc-c") - ); - } - - #[tokio::test] - async fn keyed_pending_entries_have_no_count_cap() { - // Regression for the PENDING_QUEUE_CAP removal: a high-fan-out parent - // can register hundreds of keyed pending tool_calls — each awaiting its - // own serialized MCP round-trip — and EVERY one is retained. The old - // hard cap evicted the oldest keyed entry past 32, orphaning its card to - // a synthetic id. Keyed entries are now bounded only by claim, terminal - // tombstoning, and per-parent teardown. - let broker = DelegationBroker::new( - Arc::new(MockSpawner::new()) as Arc, - shallow_lookup(), - ); - const N: usize = 256; - for i in 0..N { - broker - .register_pending_tool_call_with_key( - "p1", - format!("tc-{i}"), - Some(task_key(&format!("task {i}"))), - ) - .await; - } - { - let map = broker.tool_calls.inner.lock().await; - let bucket = map.get("p1").expect("bucket present"); - assert_eq!( - bucket.pending.len(), - N, - "all keyed pending entries must be retained — no count cap" - ); - } - // Each entry stays individually claimable by its exact key, in any - // order — proving none were dropped or mis-bound by fan-out. - for i in [0usize, N / 2, N - 1] { - let claimed = broker - .take_matching_tool_call("p1", &task_key(&format!("task {i}"))) - .await; - assert_eq!(claimed.as_deref(), Some(format!("tc-{i}").as_str())); - } - } - - #[tokio::test] - async fn keyed_pending_entry_drains_via_tombstone() { - // The drain path the no-cap design relies on: when the parent-side ACP - // tool_call goes terminal before its MCP round-trip ever claims it, - // `tombstone_pending_tool_call` removes the keyed entry (so it can't - // linger) AND records it consumed (so a late re-emit can't mis-bind a - // later delegation sharing the same key). - let broker = DelegationBroker::new( - Arc::new(MockSpawner::new()) as Arc, - shallow_lookup(), - ); - broker - .register_pending_tool_call_with_key("p1", "tc-x".into(), Some(task_key("task x"))) - .await; - assert!( - broker.tombstone_pending_tool_call("p1", "tc-x").await, - "tombstone must report it removed the pending entry" - ); - assert!( - broker - .take_matching_tool_call("p1", &task_key("task x")) - .await - .is_none(), - "a tombstoned entry must be drained from pending" - ); - // Re-register of the same id after tombstoning is dropped by the - // Tier-1 consumed check, so it can never be claimed. - broker - .register_pending_tool_call_with_key("p1", "tc-x".into(), Some(task_key("task x"))) - .await; - assert!( - broker - .take_matching_tool_call("p1", &task_key("task x")) - .await - .is_none(), - "consumed memory must reject a re-emit of a tombstoned id" - ); - } - - #[tokio::test] - async fn reregistration_refines_key_with_late_working_dir() { - // Codex re-review fix: the same tool_call_id first registers with a key - // LACKING working_dir (an early parseable raw_input), then a later - // ToolCallUpdate completes it with the explicit working_dir. The stored - // key must be REPLACED with the fuller one — otherwise the MCP claim - // keying on Some(dir) can't match the stale None and orphans to a - // synthetic id (dead card for explicit-working-dir delegations). - let broker = DelegationBroker::new( - Arc::new(MockSpawner::new()) as Arc, - shallow_lookup(), - ); - broker - .register_pending_tool_call_with_key( - "p1", - "tc-d".into(), - Some(key_for(AgentType::Codex, "build")), - ) - .await; - // Later update adds the explicit working_dir → key is refined in place. - broker - .register_pending_tool_call_with_key( - "p1", - "tc-d".into(), - Some(key_with_dir("build", "/repo")), - ) - .await; - // The stale `working_dir: None` key no longer matches (it was replaced)… - assert!(broker - .take_matching_tool_call("p1", &key_for(AgentType::Codex, "build")) - .await - .is_none()); - // …and the refined `Some("/repo")` key claims the real id. - assert_eq!( - broker - .take_matching_tool_call("p1", &key_with_dir("build", "/repo")) - .await - .as_deref(), - Some("tc-d"), - "the MCP claim with the explicit working_dir must match the refined key" - ); - } - - #[tokio::test] - async fn empty_parent_tool_use_id_claims_pending_then_completes() { - let mock = Arc::new(MockSpawner::new()); - mock.queue_spawn(Ok("c1".into())).await; - mock.queue_send(Ok(7)).await; - let broker = - DelegationBroker::new(mock.clone() as Arc, shallow_lookup()); - enable_delegation(&broker).await; - broker - .register_pending_tool_call("parent-conn", "tu-from-acp".into()) - .await; - let driver = { - let broker = broker.clone(); - tokio::spawn(async move { broker.handle_request(request(1, "")).await }) - }; - while broker.pending_count().await == 0 { - tokio::time::sleep(Duration::from_millis(5)).await; - } - // The captured ACP id was consumed. - assert!(broker.take_pending_tool_call("parent-conn").await.is_none()); - let call_id = broker.peek_first_pending_call_id().await.unwrap(); - broker - .complete_call( - &call_id, - DelegationOutcome::Ok(DelegationSuccess { - text: "ok".into(), - child_conversation_id: 7, - child_agent_type: AgentType::Codex, - turn_count: 1, - duration_ms: 5, - token_usage: None, - }), - ) - .await; - let outcome = driver.await.unwrap(); - assert!(matches!(outcome, DelegationOutcome::Ok(_))); - } - - #[tokio::test] - async fn empty_parent_tool_use_id_claims_pending_arriving_late() { - // Regression: when the parent's ACP `session/update(tool_call)` - // lands at the lifecycle dispatcher AFTER `broker.handle_request` - // already entered the claim phase, the brief poll loop must still - // pick it up rather than falling back to the synthetic UUID. - let mock = Arc::new(MockSpawner::new()); - mock.queue_spawn(Ok("c-late".into())).await; - mock.queue_send(Ok(13)).await; - let broker = - DelegationBroker::new(mock.clone() as Arc, shallow_lookup()); - enable_delegation(&broker).await; - - let driver = { - let broker = broker.clone(); - tokio::spawn(async move { broker.handle_request(request(1, "")).await }) - }; - - // Give the driver time to enter the claim wait loop on an empty - // queue, then register the ACP id (simulates the dispatcher's - // ToolCall handling landing late). - tokio::time::sleep(Duration::from_millis(30)).await; - broker - .register_pending_tool_call("parent-conn", "tu-late".into()) - .await; - - while broker.pending_count().await == 0 { - tokio::time::sleep(Duration::from_millis(5)).await; - } - // The late-arriving ACP id was consumed by the broker — no leftover - // entry. - assert!(broker.take_pending_tool_call("parent-conn").await.is_none()); - let call_id = broker.peek_first_pending_call_id().await.unwrap(); - broker - .complete_call( - &call_id, - DelegationOutcome::Ok(DelegationSuccess { - text: "late ok".into(), - child_conversation_id: 13, - child_agent_type: AgentType::Codex, - turn_count: 1, - duration_ms: 5, - token_usage: None, - }), - ) - .await; - let outcome = driver.await.unwrap(); - assert!(matches!(outcome, DelegationOutcome::Ok(_))); - } - - #[tokio::test] - async fn empty_parent_tool_use_id_with_no_pending_falls_back_to_uuid() { - let mock = Arc::new(MockSpawner::new()); - mock.queue_spawn(Ok("c1".into())).await; - mock.queue_send(Ok(11)).await; - let broker = - DelegationBroker::new(mock.clone() as Arc, shallow_lookup()); - enable_delegation(&broker).await; - let driver = { - let broker = broker.clone(); - tokio::spawn(async move { broker.handle_request(request(1, "")).await }) - }; - while broker.pending_count().await == 0 { - tokio::time::sleep(Duration::from_millis(5)).await; - } - let call_id = broker.peek_first_pending_call_id().await.unwrap(); - broker - .complete_call( - &call_id, - DelegationOutcome::Ok(DelegationSuccess { - text: "fallback ok".into(), - child_conversation_id: 11, - child_agent_type: AgentType::Codex, - turn_count: 1, - duration_ms: 5, - token_usage: None, - }), - ) - .await; - let outcome = driver.await.unwrap(); - assert!(matches!(outcome, DelegationOutcome::Ok(_))); - } - - #[tokio::test] - async fn cancel_by_parent_also_drops_pending_tool_calls() { - let broker = DelegationBroker::new( - Arc::new(MockSpawner::new()) as Arc, - shallow_lookup(), - ); - broker - .register_pending_tool_call("parent-conn", "tu-1".into()) - .await; - broker.cancel_by_parent("parent-conn").await; - assert!(broker.take_pending_tool_call("parent-conn").await.is_none()); - } - - #[tokio::test] - async fn turn_cancel_keeps_consumed_rejects_reemit() { - // A turn/prompt cancel (parent connection STAYS ALIVE) must NOT drop the - // `consumed` tool_call memory. Otherwise a host re-emit of an - // already-claimed id (e.g. a terminal status-flip) re-registers as fresh - // `pending` and the next same-key delegation mis-binds to it — the - // dead-card/wrong-child class this correlation machinery exists to - // prevent. `cancel_by_parent_turn` retains `consumed`, so the re-emit - // stays rejected by the Tier-1 consumed check. - let broker = DelegationBroker::new( - Arc::new(MockSpawner::new()) as Arc, - shallow_lookup(), - ); - // Register + claim a keyed id (the delegation that just ran). - broker - .register_pending_tool_call_with_key("p1", "tc-A".into(), Some(task_key("task A"))) - .await; - assert_eq!( - broker - .take_matching_tool_call("p1", &task_key("task A")) - .await - .as_deref(), - Some("tc-A"), - ); - // Turn cancel — parent still alive. - broker.cancel_by_parent_turn("p1").await; - // Host re-emits the now-consumed id with the same key. - broker - .register_pending_tool_call_with_key("p1", "tc-A".into(), Some(task_key("task A"))) - .await; - assert!( - broker - .take_matching_tool_call("p1", &task_key("task A")) - .await - .is_none(), - "re-emit of a consumed id must stay rejected across a turn cancel" - ); - } - - #[tokio::test] - async fn turn_cancel_drops_unclaimed_pending() { - // The unclaimed `pending` half is cleared by a turn cancel (tombstoned - // into `consumed`): the cancelled turn's serial round-trip won't arrive, - // so the stale keyed entry must not remain claimable by a later same-key - // delegation. `take_matching` scans only `pending`, so it returns None. - let broker = DelegationBroker::new( - Arc::new(MockSpawner::new()) as Arc, - shallow_lookup(), - ); - broker - .register_pending_tool_call_with_key("p1", "tc-B".into(), Some(task_key("task B"))) - .await; - broker.cancel_by_parent_turn("p1").await; - assert!( - broker - .take_matching_tool_call("p1", &task_key("task B")) - .await - .is_none(), - "unclaimed pending must not stay claimable after a turn cancel" - ); - } - - #[tokio::test] - async fn turn_cancel_tombstones_pending_rejects_late_reemit() { - // Stronger than the clear test: after a turn cancel clears an UNCLAIMED - // keyed pending id, a late host re-emit of that SAME id must not - // resurrect it as a claimable entry — otherwise the next same-key - // delegation would mis-bind to the stale id. The cancel tombstones the - // cleared id into `consumed`, so the re-emit is dropped by the Tier-1 - // consumed check and never re-enters `pending`. - let broker = DelegationBroker::new( - Arc::new(MockSpawner::new()) as Arc, - shallow_lookup(), - ); - broker - .register_pending_tool_call_with_key("p1", "tc-X".into(), Some(task_key("task X"))) - .await; - broker.cancel_by_parent_turn("p1").await; - // Late re-emit of the cancelled turn's unclaimed id (same key). - broker - .register_pending_tool_call_with_key("p1", "tc-X".into(), Some(task_key("task X"))) - .await; - assert!( - broker - .take_matching_tool_call("p1", &task_key("task X")) - .await - .is_none(), - "a re-emit of a tombstoned (cleared-on-cancel) pending id must not be claimable" - ); - } - - #[tokio::test] - async fn teardown_cancel_clears_consumed() { - // The teardown variant (`cancel_by_parent`) DOES drop consumed — the - // connection is going away, so a reused connection_id must start clean. - // Contrast with `turn_cancel_keeps_consumed_rejects_reemit`. - let broker = DelegationBroker::new( - Arc::new(MockSpawner::new()) as Arc, - shallow_lookup(), - ); - broker.register_pending_tool_call("p1", "tc-A".into()).await; - assert_eq!( - broker.take_pending_tool_call("p1").await.as_deref(), - Some("tc-A"), - ); - broker.cancel_by_parent("p1").await; - // consumed cleared → the same id re-registers and is claimable again. - broker.register_pending_tool_call("p1", "tc-A".into()).await; - assert_eq!( - broker.take_pending_tool_call("p1").await.as_deref(), - Some("tc-A"), - "teardown cancel must clear consumed so id reuse is acceptable" - ); - } - - #[tokio::test] - async fn cancel_by_parent_turn_drains_synchronously_then_tears_down_child() { - // The turn cancel must (a) drop the tracker + remove parked calls - // SYNCHRONOUSLY — before the connection loop could accept the next - // prompt — so a delayed cancel can't tombstone/cancel a NEXT turn's - // entries (the invariant `drop_tool_calls_for_parent` relies on); and - // (b) still fully tear the child down (backgrounded), resolving the - // awaiting `handle_request` as canceled exactly once. - let mock = Arc::new(MockSpawner::new()); - mock.queue_spawn(Ok("child-1".into())).await; - mock.queue_send(Ok(7)).await; - let broker = - DelegationBroker::new(mock.clone() as Arc, shallow_lookup()); - enable_delegation(&broker).await; - - // Park a delegation for "parent-conn"... - let driver = { - let broker = broker.clone(); - tokio::spawn(async move { broker.handle_request(request(1, "pt-1")).await }) - }; - while broker.pending_count().await == 0 { - tokio::time::sleep(Duration::from_millis(5)).await; - } - // ...plus a separate unclaimed keyed tracker entry on the same parent. - broker - .register_pending_tool_call_with_key( - "parent-conn", - "tc-Z".into(), - Some(task_key("task Z")), - ) - .await; - - broker.cancel_by_parent_turn("parent-conn").await; - - // (a) Synchronously — no sleep: the parked call is removed and the - // tracker entry is dropped (tombstoned), so neither can leak into a - // next-turn registration that the backgrounded teardown might clobber. - assert_eq!( - broker.pending_count().await, - 0, - "parked call must be drained synchronously by the turn cancel" - ); - assert!( - broker - .take_matching_tool_call("parent-conn", &task_key("task Z")) - .await - .is_none(), - "tracker pending must be dropped synchronously by the turn cancel" - ); - - // (b) The backgrounded child teardown still resolves the driver as - // canceled and tears the child down exactly once. - match driver.await.unwrap() { - DelegationOutcome::Err { code, .. } => assert_eq!(code, "canceled"), - other => panic!("expected canceled, got {other:?}"), - } - assert_eq!(mock.cancels.lock().await.as_slice(), &["child-1"]); - assert_eq!(mock.disconnects.lock().await.as_slice(), &["child-1"]); - } - - #[tokio::test] - async fn depth_limit_allows_root() { - let mock = Arc::new(MockSpawner::new()); - mock.queue_spawn(Ok("c1".into())).await; - mock.queue_send(Ok(7)).await; - let lookup = Arc::new(MockDepth(vec![(1, None)])) as Arc; - let broker = DelegationBroker::new(mock.clone() as Arc, lookup); - broker - .set_config(DelegationConfig { - enabled: true, - depth_limit: 2, - ..DelegationConfig::default() - }) - .await; - - let driver = { - let broker = broker.clone(); - tokio::spawn(async move { broker.handle_request(request(1, "pt-1")).await }) - }; - while broker.pending_count().await == 0 { - tokio::time::sleep(Duration::from_millis(5)).await; - } - let call_id = broker.peek_first_pending_call_id().await.unwrap(); - broker - .complete_call( - &call_id, - DelegationOutcome::Ok(DelegationSuccess { - text: "ok".into(), - child_conversation_id: 7, - child_agent_type: AgentType::ClaudeCode, - turn_count: 1, - duration_ms: 5, - token_usage: None, - }), - ) - .await; - let outcome = driver.await.unwrap(); - assert!(matches!(outcome, DelegationOutcome::Ok(_))); - } - - // -- Meta writer lifecycle -------------------------------------------- - - use crate::acp::delegation::meta_writer::mock::MockMetaWriter; - use crate::acp::delegation::meta_writer::DelegationMetaWriter; - - async fn broker_with_meta( - mock: Arc, - writer: Arc, - ) -> DelegationBroker { - let broker = DelegationBroker::with_meta_writer( - mock as Arc, - shallow_lookup(), - writer as Arc, - ); - enable_delegation(&broker).await; - broker - } - - #[tokio::test] - async fn meta_writes_carry_task_preview_and_task_id_on_every_write() { - // Meta is replace-wholesale on the ToolCallState, so BOTH the running - // and the terminal writes must carry the task label + broker task id — - // they are the persisted card's only label source on hosts whose - // raw_input never carries the arguments (Cursor). - let mock = Arc::new(MockSpawner::new()); - mock.queue_spawn(Ok("child-conn-t".into())).await; - mock.queue_send(Ok(42)).await; - let writer = Arc::new(MockMetaWriter::new()); - let broker = broker_with_meta(mock.clone(), writer.clone()).await; - - let driver = { - let broker = broker.clone(); - tokio::spawn(async move { broker.handle_request(request(1, "pt-task")).await }) - }; - let call_id = loop { - if let Some(id) = broker.peek_first_pending_call_id().await { - break id; - } - tokio::time::sleep(Duration::from_millis(5)).await; - }; - broker - .complete_call( - &call_id, - DelegationOutcome::Ok(DelegationSuccess { - text: "done".into(), - child_conversation_id: 42, - child_agent_type: AgentType::ClaudeCode, - turn_count: 1, - duration_ms: 5, - token_usage: None, - }), - ) - .await; - driver.await.unwrap(); - - let calls = writer.snapshot().await; - assert_eq!(calls.len(), 2); - for call in &calls { - let inner = call - .meta - .get("codeg.delegation") - .unwrap() - .as_object() - .unwrap(); - assert_eq!( - inner.get("task_preview").unwrap().as_str().unwrap(), - "do x", - "every write must keep the task label (status={})", - inner.get("status").unwrap() - ); - assert_eq!( - inner.get("task_id").unwrap().as_str().unwrap(), - &call_id, - "task_id must be the broker call id on every write" - ); - } - } - - #[tokio::test] - async fn identityless_fifo_claim_restores_delegate_identity() { - // Cursor path: the ACP announcement registered an identity-less - // candidate ("MCP: tool" + "{}"), the MCP round-trip arrives with no - // explicit tool_use id. The post-budget FIFO claim must land on the - // candidate AND restore the call's identity (canonical delegate title - // + reconstructed arguments) on the live tool call. - let mock = Arc::new(MockSpawner::new()); - mock.queue_spawn(Ok("child-conn-i".into())).await; - mock.queue_send(Ok(43)).await; - let writer = Arc::new(MockMetaWriter::new()); - let broker = broker_with_meta(mock.clone(), writer.clone()).await; - broker - .register_identityless_tool_call("parent-conn", "call-cursor-7\nfc_x_0".into()) - .await; - - let driver = { - let broker = broker.clone(); - // Empty tool_use id → claim path (2s budget, then FIFO). - tokio::spawn(async move { broker.handle_request(request(1, "")).await }) - }; - let call_id = loop { - if let Some(id) = broker.peek_first_pending_call_id().await { - break id; - } - tokio::time::sleep(Duration::from_millis(5)).await; - }; - broker - .complete_call( - &call_id, - DelegationOutcome::Ok(DelegationSuccess { - text: "done".into(), - child_conversation_id: 43, - child_agent_type: AgentType::ClaudeCode, - turn_count: 1, - duration_ms: 5, - token_usage: None, - }), - ) - .await; - driver.await.unwrap(); - - let identities = writer.identity_snapshot().await; - assert_eq!(identities.len(), 1, "exactly one identity restoration"); - let id_write = &identities[0]; - assert_eq!(id_write.parent_connection_id, "parent-conn"); - assert_eq!(id_write.tool_call_id, "call-cursor-7\nfc_x_0"); - assert_eq!( - id_write.title, - crate::acp::delegation::DELEGATE_TOOL_REWRITE_TITLE - ); - assert_eq!( - id_write.raw_input.get("task").unwrap().as_str().unwrap(), - "do x" - ); - assert_eq!( - id_write - .raw_input - .get("agent_type") - .unwrap() - .as_str() - .unwrap(), - "claude_code" - ); - // The meta writes bound to the REAL claimed id, not a synthetic one. - let metas = writer.snapshot().await; - assert!(metas - .iter() - .all(|m| m.parent_tool_use_id == "call-cursor-7\nfc_x_0")); - } - - #[tokio::test] - async fn keyed_claim_does_not_rewrite_host_identity() { - // A host that shipped real raw_input (keyed registration) keeps its - // own wire identity — reconstructing raw_input would clobber - // host-specific fields. - let mock = Arc::new(MockSpawner::new()); - mock.queue_spawn(Ok("child-conn-k".into())).await; - mock.queue_send(Ok(44)).await; - let writer = Arc::new(MockMetaWriter::new()); - let broker = broker_with_meta(mock.clone(), writer.clone()).await; - broker - .register_pending_tool_call_with_key( - "parent-conn", - "tc-keyed".into(), - Some(DelegationMatchKey { - agent_type: AgentType::ClaudeCode, - task: "do x".into(), - working_dir: None, - }), - ) - .await; - - let driver = { - let broker = broker.clone(); - tokio::spawn(async move { broker.handle_request(request(1, "")).await }) - }; - let call_id = loop { - if let Some(id) = broker.peek_first_pending_call_id().await { - break id; - } - tokio::time::sleep(Duration::from_millis(5)).await; - }; - broker - .complete_call( - &call_id, - DelegationOutcome::Ok(DelegationSuccess { - text: "done".into(), - child_conversation_id: 44, - child_agent_type: AgentType::ClaudeCode, - turn_count: 1, - duration_ms: 5, - token_usage: None, - }), - ) - .await; - driver.await.unwrap(); - - assert!( - writer.identity_snapshot().await.is_empty(), - "keyed (host-identified) claims must not be rewritten" - ); - let metas = writer.snapshot().await; - assert!(metas.iter().all(|m| m.parent_tool_use_id == "tc-keyed")); - } - - #[tokio::test] - async fn rewrite_identityless_tool_call_claims_and_writes_status_identity() { - let writer = Arc::new(MockMetaWriter::new()); - let broker = broker_with_meta(Arc::new(MockSpawner::new()), writer.clone()).await; - broker - .register_identityless_tool_call("parent-conn", "call-status-1".into()) - .await; - - let claimed = broker - .rewrite_identityless_tool_call( - "parent-conn", - crate::acp::delegation::STATUS_TOOL_REWRITE_TITLE, - serde_json::json!({"task_ids": ["t-1"], "wait_ms": 0}), - ) - .await; - assert_eq!(claimed.as_deref(), Some("call-status-1")); - let identities = writer.identity_snapshot().await; - assert_eq!(identities.len(), 1); - assert_eq!( - identities[0].title, - crate::acp::delegation::STATUS_TOOL_REWRITE_TITLE - ); - assert_eq!( - identities[0].raw_input.get("task_ids").unwrap()[0] - .as_str() - .unwrap(), - "t-1" - ); - // Consumed: the candidate can't be claimed again by the delegate FIFO. - assert!(broker.take_pending_tool_call("parent-conn").await.is_none()); - } - - #[tokio::test] - async fn rewrite_skips_connections_that_never_announced_identityless() { - // Plain unkeyed registration (a keyless delegation invocation) must - // NOT be renamed — and the sticky gate must return instantly (no - // 300 ms poll) for such connections. Also: the entry stays claimable - // by the delegate FIFO afterwards. - let writer = Arc::new(MockMetaWriter::new()); - let broker = broker_with_meta(Arc::new(MockSpawner::new()), writer.clone()).await; - broker - .register_pending_tool_call("parent-conn", "tc-plain".into()) - .await; - - let started = std::time::Instant::now(); - let claimed = broker - .rewrite_identityless_tool_call( - "parent-conn", - crate::acp::delegation::STATUS_TOOL_REWRITE_TITLE, - serde_json::json!({"task_ids": ["t-1"]}), - ) - .await; - assert!(claimed.is_none()); - // The poll path sleeps ≥300 ms (30 × 10 ms lower bounds); the gate - // path sleeps zero. 280 ms discriminates the two while leaving slack - // for full-suite parallel-load scheduling jitter. - assert!( - started.elapsed() < Duration::from_millis(280), - "sticky gate must skip the poll for hosts without identity-less announcements" - ); - assert!(writer.identity_snapshot().await.is_empty()); - assert_eq!( - broker - .take_pending_tool_call("parent-conn") - .await - .as_deref(), - Some("tc-plain"), - "the plain unkeyed entry must remain for the delegate FIFO" - ); - } - - #[tokio::test] - async fn meta_writer_records_running_then_completed_on_happy_path() { - let mock = Arc::new(MockSpawner::new()); - mock.queue_spawn(Ok("child-conn-1".into())).await; - mock.queue_send(Ok(42)).await; - let writer = Arc::new(MockMetaWriter::new()); - let broker = broker_with_meta(mock.clone(), writer.clone()).await; - - let driver = { - let broker = broker.clone(); - tokio::spawn(async move { broker.handle_request(request(1, "pt-real")).await }) - }; - let call_id = loop { - if let Some(id) = broker.peek_first_pending_call_id().await { - break id; - } - tokio::time::sleep(Duration::from_millis(5)).await; - }; - broker - .complete_call( - &call_id, - DelegationOutcome::Ok(DelegationSuccess { - text: "done".into(), - child_conversation_id: 42, - child_agent_type: AgentType::ClaudeCode, - turn_count: 1, - duration_ms: 5, - token_usage: None, - }), - ) - .await; - driver.await.unwrap(); - - let calls = writer.snapshot().await; - assert_eq!(calls.len(), 2); - // First write: running, with child connection + conversation ids. - let first = &calls[0]; - assert_eq!(first.parent_tool_use_id, "pt-real"); - let inner_first = first - .meta - .get("codeg.delegation") - .unwrap() - .as_object() - .unwrap(); - assert_eq!( - inner_first.get("status").unwrap().as_str().unwrap(), - "running" - ); - assert_eq!( - inner_first - .get("child_connection_id") - .unwrap() - .as_str() - .unwrap(), - "child-conn-1" - ); - assert_eq!( - inner_first - .get("child_conversation_id") - .unwrap() - .as_i64() - .unwrap(), - 42 - ); - // Second write: completed. - let second = &calls[1]; - let inner_second = second - .meta - .get("codeg.delegation") - .unwrap() - .as_object() - .unwrap(); - assert_eq!( - inner_second.get("status").unwrap().as_str().unwrap(), - "completed" - ); - } - - #[tokio::test] - async fn meta_writer_records_failed_on_err_outcome() { - let mock = Arc::new(MockSpawner::new()); - mock.queue_spawn(Ok("child-conn-2".into())).await; - mock.queue_send(Ok(7)).await; - let writer = Arc::new(MockMetaWriter::new()); - let broker = broker_with_meta(mock.clone(), writer.clone()).await; - - let driver = { - let broker = broker.clone(); - tokio::spawn(async move { broker.handle_request(request(1, "pt-err")).await }) - }; - let call_id = loop { - if let Some(id) = broker.peek_first_pending_call_id().await { - break id; - } - tokio::time::sleep(Duration::from_millis(5)).await; - }; - broker - .complete_call( - &call_id, - DelegationOutcome::from_err( - DelegationError::SubagentRuntimeError("agent died".into()), - Some(7), - ), - ) - .await; - driver.await.unwrap(); - - let calls = writer.snapshot().await; - assert_eq!(calls.len(), 2); - let inner = calls[1] - .meta - .get("codeg.delegation") - .unwrap() - .as_object() - .unwrap(); - assert_eq!(inner.get("status").unwrap().as_str().unwrap(), "failed"); - assert_eq!( - inner.get("error_code").unwrap().as_str().unwrap(), - "subagent_error" - ); - } - - // -- Registration-race: child terminal failure before the entry is parked -- - - /// Headline regression: a child terminal failure (auth error / immediate - /// process death) that fires AFTER the broker reserved the child but BEFORE - /// it parked the pending entry must still resolve the parked request — not - /// no-op and strand it on `rx.await` forever. The `send_gate` pins - /// `handle_request` in exactly that window; we fire the failure, release the - /// gate, and assert the request resolves as canceled (carrying the - /// terminal-error detail) with a single child disconnect and a clean - /// running→failed meta trail. - #[tokio::test] - async fn child_failure_before_park_resolves_instead_of_hanging() { - let mock = Arc::new(MockSpawner::new()); - mock.queue_spawn(Ok("c-fast-fail".into())).await; - mock.queue_send(Ok(55)).await; - let release = mock.install_send_gate().await; - let writer = Arc::new(MockMetaWriter::new()); - let broker = broker_with_meta(mock.clone(), writer.clone()).await; - - let driver = { - let broker = broker.clone(); - tokio::spawn(async move { broker.handle_request(request(1, "pt-fast")).await }) - }; - - // Wait until handle_request has spawned + reserved the child and is - // held inside send_prompt by the gate — entry NOT yet parked. - loop { - if broker.reserved_child_count().await == 1 { - break; - } - tokio::time::sleep(Duration::from_millis(5)).await; - } - assert_eq!(broker.pending_count().await, 0, "entry not parked yet"); - - // Child dies before the entry is parked. With the reservation in place - // this buffers (rather than no-oping on a not-yet-existent entry). - broker - .cancel_by_child_connection("c-fast-fail", Some("Authentication required")) - .await; - assert_eq!(broker.early_cancel_count().await, 1, "failure buffered"); - - // Release send_prompt → handle_request parks, drains the buffered - // failure, and resolves inline instead of hanging. - let _ = release.send(()); - let outcome = driver.await.unwrap(); - match outcome { - DelegationOutcome::Err { - code, - message, - child_conversation_id, - } => { - assert_eq!(code, "canceled"); - assert!( - message.contains("Authentication required"), - "reason should carry the terminal-error detail, got: {message}" - ); - assert_eq!(child_conversation_id, Some(55)); - } - other => panic!("expected canceled Err, got {other:?}"), - } - - // Reservation + buffer drained; child torn down exactly once. - assert_eq!(broker.pending_count().await, 0); - assert_eq!(broker.reserved_child_count().await, 0); - assert_eq!(broker.early_cancel_count().await, 0); - assert_eq!(mock.disconnects.lock().await.as_slice(), &["c-fast-fail"]); - - // Meta trail: running (written pre-park) then failed/canceled (pickup). - let calls = writer.snapshot().await; - assert_eq!(calls.len(), 2); - let running = calls[0] - .meta - .get("codeg.delegation") - .unwrap() - .as_object() - .unwrap(); - assert_eq!(running.get("status").unwrap().as_str().unwrap(), "running"); - let failed = calls[1] - .meta - .get("codeg.delegation") - .unwrap() - .as_object() - .unwrap(); - assert_eq!(failed.get("status").unwrap().as_str().unwrap(), "failed"); - assert_eq!( - failed.get("error_code").unwrap().as_str().unwrap(), - "canceled" - ); - } - - /// The SAME race on the SUCCESS path: a `TurnComplete` whose `complete_call` - /// fires AFTER the delegation reserved but BEFORE `handle_request` parked (a - /// fast/empty turn whose completion propagates while the broker is still - /// awaiting the parent `write_meta`) must still resolve the request. The - /// prompt is only *enqueued* by `send_prompt`, so the child loop can emit - /// `TurnComplete` before the park. The `send_gate` pins `handle_request` in - /// the reserve→park window; we resolve via the reserved `call_id` (the entry - /// isn't parked yet) and assert the request returns Ok instead of hanging. - #[tokio::test] - async fn completion_before_park_resolves_instead_of_hanging() { - let mock = Arc::new(MockSpawner::new()); - mock.queue_spawn(Ok("c-fast-ok".into())).await; - mock.queue_send(Ok(70)).await; - let release = mock.install_send_gate().await; - let writer = Arc::new(MockMetaWriter::new()); - let broker = broker_with_meta(mock.clone(), writer.clone()).await; - - let driver = { - let broker = broker.clone(); - tokio::spawn(async move { broker.handle_request(request(1, "pt-ok")).await }) - }; - - // Wait until reserved (spawned + id minted, held in send_prompt by the - // gate); the entry is NOT parked yet, so grab the call_id from the - // reservation rather than the parked-calls map. - let call_id = loop { - if let Some(id) = broker.peek_reserved_call_id().await { - break id; - } - tokio::time::sleep(Duration::from_millis(5)).await; - }; - assert_eq!(broker.pending_count().await, 0, "entry not parked yet"); - - // TurnComplete beats the park. With the reservation in place this - // buffers (rather than no-oping on a not-yet-existent entry). - broker - .complete_call( - &call_id, - DelegationOutcome::Ok(DelegationSuccess { - text: "fast done".into(), - child_conversation_id: 70, - child_agent_type: AgentType::ClaudeCode, - turn_count: 1, - duration_ms: 5, - token_usage: None, - }), - ) - .await; - assert_eq!( - broker.early_complete_count().await, - 1, - "completion buffered" - ); - - // Release send_prompt → handle_request parks, drains the buffered - // completion, and resolves inline instead of hanging. - let _ = release.send(()); - let outcome = driver.await.unwrap(); - match outcome { - DelegationOutcome::Ok(s) => { - assert_eq!(s.text, "fast done"); - assert_eq!(s.child_conversation_id, 70); - } - other => panic!("expected Ok, got {other:?}"), - } - - assert_eq!(broker.pending_count().await, 0); - assert_eq!(broker.reserved_call_count().await, 0); - assert_eq!(broker.reserved_child_count().await, 0); - assert_eq!(broker.early_complete_count().await, 0); - assert_eq!(mock.disconnects.lock().await.as_slice(), &["c-fast-ok"]); - - // Meta trail: running (written pre-park) then completed (pickup). - let calls = writer.snapshot().await; - assert_eq!(calls.len(), 2); - let running = calls[0] - .meta - .get("codeg.delegation") - .unwrap() - .as_object() - .unwrap(); - assert_eq!(running.get("status").unwrap().as_str().unwrap(), "running"); - let completed = calls[1] - .meta - .get("codeg.delegation") - .unwrap() - .as_object() - .unwrap(); - assert_eq!( - completed.get("status").unwrap().as_str().unwrap(), - "completed" - ); - } - - /// The reservation is released at park, and a SUCCESSFUL completion buffers - /// nothing. The child's post-completion disconnect (normal v1 one-shot - /// teardown) finds the child un-reserved and must NOT buffer a spurious - /// cancel — otherwise every completed delegation would leak a buffer entry. - #[tokio::test] - async fn normal_completion_leaves_no_reservation_or_buffer() { - let mock = Arc::new(MockSpawner::new()); - mock.queue_spawn(Ok("c-clean".into())).await; - mock.queue_send(Ok(60)).await; - let broker = - DelegationBroker::new(mock.clone() as Arc, shallow_lookup()); - enable_delegation(&broker).await; - - let driver = { - let broker = broker.clone(); - tokio::spawn(async move { broker.handle_request(request(1, "pt-clean")).await }) - }; - let call_id = loop { - if let Some(id) = broker.peek_first_pending_call_id().await { - break id; - } - tokio::time::sleep(Duration::from_millis(5)).await; - }; - // Parked → reservation already released. - assert_eq!( - broker.reserved_child_count().await, - 0, - "park releases the reservation" - ); - - broker - .complete_call( - &call_id, - DelegationOutcome::Ok(DelegationSuccess { - text: "ok".into(), - child_conversation_id: 60, - child_agent_type: AgentType::ClaudeCode, - turn_count: 1, - duration_ms: 5, - token_usage: None, - }), - ) - .await; - assert!(matches!(driver.await.unwrap(), DelegationOutcome::Ok(_))); - - // The child's post-completion disconnect arrives. Child is no longer - // reserved → must NOT buffer a spurious cancel. - broker.cancel_by_child_connection("c-clean", None).await; - assert_eq!( - broker.early_cancel_count().await, - 0, - "a post-resolution teardown must not buffer a spurious cancel" - ); - assert_eq!(broker.pending_count().await, 0); - } - - // -- Item 1: parent-cancel coverage of the `handle_request` setup window -- - - /// A parent cancel that lands while `handle_request` is INSIDE `spawn` (the - /// child exists but no prompt has been sent) must disconnect the child and - /// bail — never send it a prompt — instead of no-oping and letting it run - /// orphaned. Pinned with the spawn gate. - #[tokio::test] - async fn parent_cancel_in_spawn_window_disconnects_child_without_sending() { - let mock = Arc::new(MockSpawner::new()); - mock.queue_spawn(Ok("c2".into())).await; - mock.queue_send(Ok(99)).await; // staged but must NOT be consumed - let release = mock.install_spawn_gate().await; - let broker = - DelegationBroker::new(mock.clone() as Arc, shallow_lookup()); - enable_delegation(&broker).await; - - let driver = { - let broker = broker.clone(); - tokio::spawn(async move { broker.handle_request(request(1, "pt-2")).await }) - }; - // Inside spawn (call recorded, held by the gate): registered in-flight, - // not yet reserved. - loop { - if !mock.spawn_args.lock().await.is_empty() { - break; - } - tokio::time::sleep(Duration::from_millis(5)).await; - } - assert_eq!(broker.inflight_count().await, 1); - assert_eq!(broker.reserved_child_count().await, 0, "not reserved yet"); - - broker.cancel_by_parent_turn("parent-conn").await; - let _ = release.send(()); - - match driver.await.unwrap() { - DelegationOutcome::Err { code, .. } => assert_eq!(code, "canceled"), - other => panic!("expected canceled, got {other:?}"), - } - assert_eq!(mock.disconnects.lock().await.as_slice(), &["c2"]); - assert!( - mock.cancels.lock().await.is_empty(), - "no prompt was sent, so no cancel — disconnect only" - ); - assert_eq!( - mock.send_results.lock().await.len(), - 1, - "send must not be consumed — no prompt sent to an abandoned child" - ); - assert_eq!(broker.inflight_count().await, 0); - assert_eq!(broker.reserved_child_count().await, 0); - } - - /// A parent cancel that lands in the reserve→park window (prompt already - /// sent, entry not yet parked) must cancel AND disconnect the child and - /// resolve the request as canceled. Pinned with the send gate; also asserts - /// the running→failed/canceled meta trail. - #[tokio::test] - async fn parent_cancel_in_reserve_park_window_tears_down_child() { - let mock = Arc::new(MockSpawner::new()); - mock.queue_spawn(Ok("c3".into())).await; - mock.queue_send(Ok(33)).await; - let release = mock.install_send_gate().await; - let writer = Arc::new(MockMetaWriter::new()); - let broker = broker_with_meta(mock.clone(), writer.clone()).await; - - let driver = { - let broker = broker.clone(); - tokio::spawn(async move { broker.handle_request(request(1, "pt-3")).await }) - }; - // Spawned + reserved, held inside send_prompt. - loop { - if broker.reserved_child_count().await == 1 { - break; - } - tokio::time::sleep(Duration::from_millis(5)).await; - } - assert_eq!(broker.inflight_count().await, 1); - assert_eq!(broker.pending_count().await, 0, "not parked yet"); - - broker.cancel_by_parent_turn("parent-conn").await; - let _ = release.send(()); - - match driver.await.unwrap() { - DelegationOutcome::Err { - code, - child_conversation_id, - .. - } => { - assert_eq!(code, "canceled"); - assert_eq!(child_conversation_id, Some(33)); - } - other => panic!("expected canceled, got {other:?}"), - } - // Prompt was sent → child cancel()'d AND disconnected. - assert_eq!(mock.cancels.lock().await.as_slice(), &["c3"]); - assert_eq!(mock.disconnects.lock().await.as_slice(), &["c3"]); - assert_eq!(broker.inflight_count().await, 0); - assert_eq!(broker.reserved_child_count().await, 0); - assert_eq!(broker.early_cancel_count().await, 0); - assert_eq!(broker.pending_count().await, 0); - - // Meta trail: running (pre-park) then failed/canceled (ParentCanceled). - let calls = writer.snapshot().await; - assert_eq!(calls.len(), 2); - let running = calls[0] - .meta - .get("codeg.delegation") - .unwrap() - .as_object() - .unwrap(); - assert_eq!(running.get("status").unwrap().as_str().unwrap(), "running"); - let failed = calls[1] - .meta - .get("codeg.delegation") - .unwrap() - .as_object() - .unwrap(); - assert_eq!(failed.get("status").unwrap().as_str().unwrap(), "failed"); - assert_eq!( - failed.get("error_code").unwrap().as_str().unwrap(), - "canceled" - ); - } - - /// Strict first-terminal-wins: when a child completion buffers FIRST and a - /// parent cancel lands afterward, the child's earlier arrival stamp wins and - /// its real result is preserved (the cancel is moot — the child already - /// finished before it). - #[tokio::test] - async fn child_terminal_wins_over_later_parent_cancel() { - let mock = Arc::new(MockSpawner::new()); - mock.queue_spawn(Ok("c4".into())).await; - mock.queue_send(Ok(44)).await; - let release = mock.install_send_gate().await; - let broker = - DelegationBroker::new(mock.clone() as Arc, shallow_lookup()); - enable_delegation(&broker).await; - - let driver = { - let broker = broker.clone(); - tokio::spawn(async move { broker.handle_request(request(1, "pt-4")).await }) - }; - let call_id = loop { - if let Some(id) = broker.peek_reserved_call_id().await { - break id; - } - tokio::time::sleep(Duration::from_millis(5)).await; - }; - assert_eq!(broker.inflight_count().await, 1); - - // Child completes FIRST, then the parent cancels — child result wins. - broker - .complete_call( - &call_id, - DelegationOutcome::Ok(DelegationSuccess { - text: "done".into(), - child_conversation_id: 44, - child_agent_type: AgentType::ClaudeCode, - turn_count: 1, - duration_ms: 5, - token_usage: None, - }), - ) - .await; - broker.cancel_by_parent_turn("parent-conn").await; - let _ = release.send(()); - - assert!(matches!(driver.await.unwrap(), DelegationOutcome::Ok(_))); - assert!( - mock.cancels.lock().await.is_empty(), - "child completed — the moot parent cancel must not cancel it" - ); - assert_eq!(broker.inflight_count().await, 0); - assert_eq!(broker.early_complete_count().await, 0); - } - - /// Strict first-terminal-wins (Item 3): when the parent cancel is recorded - /// BEFORE the child completion buffers, the cancel wins — the late - /// completion is discarded and the child is torn down, because the parent - /// had already abandoned the turn by the time the completion landed. - #[tokio::test] - async fn parent_cancel_wins_when_it_arrives_before_child_terminal() { - let mock = Arc::new(MockSpawner::new()); - mock.queue_spawn(Ok("c5".into())).await; - mock.queue_send(Ok(55)).await; - let release = mock.install_send_gate().await; - let broker = - DelegationBroker::new(mock.clone() as Arc, shallow_lookup()); - enable_delegation(&broker).await; - - let driver = { - let broker = broker.clone(); - tokio::spawn(async move { broker.handle_request(request(1, "pt-5")).await }) - }; - let call_id = loop { - if let Some(id) = broker.peek_reserved_call_id().await { - break id; - } - tokio::time::sleep(Duration::from_millis(5)).await; - }; - - // Parent cancels FIRST (earlier arrival stamp); the child completes - // afterward (later stamp) — first-terminal-wins judges the cancel the - // winner and discards the late completion. - broker.cancel_by_parent_turn("parent-conn").await; - broker - .complete_call( - &call_id, - DelegationOutcome::Ok(DelegationSuccess { - text: "late".into(), - child_conversation_id: 55, - child_agent_type: AgentType::ClaudeCode, - turn_count: 1, - duration_ms: 5, - token_usage: None, - }), - ) - .await; - let _ = release.send(()); - - match driver.await.unwrap() { - DelegationOutcome::Err { - code, - child_conversation_id, - .. - } => { - assert_eq!(code, "canceled"); - assert_eq!(child_conversation_id, Some(55)); - } - other => panic!( - "first-terminal-wins: an earlier parent cancel must beat a later completion, got {other:?}" - ), - } - // The abandoned child is torn down (prompt was sent → cancel + disconnect). - assert_eq!(mock.cancels.lock().await.as_slice(), &["c5"]); - assert_eq!(mock.disconnects.lock().await.as_slice(), &["c5"]); - assert_eq!(broker.inflight_count().await, 0); - // The buffered completion was drained (and discarded), leaving no leak. - assert_eq!(broker.early_complete_count().await, 0); - } - - /// Strict first-terminal-wins through the child-FAILURE buffer: a child - /// failure that buffers BEFORE a parent cancel keeps its (earlier) arrival - /// stamp and wins, so the request resolves with the child's failure detail - /// and the child is torn down once (disconnect only — the child already - /// failed, so there's no in-flight prompt to cancel). Exercises the - /// `early_cancels` stamp path that mirrors the completion case above. - #[tokio::test] - async fn child_failure_wins_over_later_parent_cancel() { - let mock = Arc::new(MockSpawner::new()); - mock.queue_spawn(Ok("cF".into())).await; - mock.queue_send(Ok(66)).await; - let release = mock.install_send_gate().await; - let broker = - DelegationBroker::new(mock.clone() as Arc, shallow_lookup()); - enable_delegation(&broker).await; - - let driver = { - let broker = broker.clone(); - tokio::spawn(async move { broker.handle_request(request(1, "pt-f")).await }) - }; - // Spawned + reserved, held inside send_prompt by the gate. - loop { - if broker.reserved_child_count().await == 1 { - break; - } - tokio::time::sleep(Duration::from_millis(5)).await; - } - - // Child fails FIRST (earlier stamp), then the parent cancels (later - // stamp) — the child terminal wins and carries its failure detail. - broker - .cancel_by_child_connection("cF", Some("boom detail")) - .await; - broker.cancel_by_parent_turn("parent-conn").await; - let _ = release.send(()); - - match driver.await.unwrap() { - DelegationOutcome::Err { - code, - message, - child_conversation_id, - } => { - assert_eq!(code, "canceled"); - assert!( - message.contains("boom detail"), - "child failure detail must survive, got: {message}" - ); - assert_eq!(child_conversation_id, Some(66)); - } - other => panic!("expected child failure Err, got {other:?}"), - } - // Child-terminal path tears down via disconnect only (no cancel). - assert_eq!(mock.disconnects.lock().await.as_slice(), &["cF"]); - assert!( - mock.cancels.lock().await.is_empty(), - "child already failed — the moot parent cancel must not cancel it" - ); - assert_eq!(broker.inflight_count().await, 0); - assert_eq!(broker.early_cancel_count().await, 0); - } - - /// The teardown variant `cancel_by_parent` covers the same reserve→park - /// window as the turn variant — both funnel through `drain_for_parent_cancel` - /// where the in-flight mark is applied. - #[tokio::test] - async fn parent_teardown_in_reserve_park_window_tears_down_child() { - let mock = Arc::new(MockSpawner::new()); - mock.queue_spawn(Ok("c7".into())).await; - mock.queue_send(Ok(77)).await; - let release = mock.install_send_gate().await; - let broker = - DelegationBroker::new(mock.clone() as Arc, shallow_lookup()); - enable_delegation(&broker).await; - - let driver = { - let broker = broker.clone(); - tokio::spawn(async move { broker.handle_request(request(1, "pt-7")).await }) - }; - loop { - if broker.reserved_child_count().await == 1 { - break; - } - tokio::time::sleep(Duration::from_millis(5)).await; - } - broker.cancel_by_parent("parent-conn").await; - let _ = release.send(()); - - match driver.await.unwrap() { - DelegationOutcome::Err { code, .. } => assert_eq!(code, "canceled"), - other => panic!("expected canceled, got {other:?}"), - } - assert_eq!(mock.cancels.lock().await.as_slice(), &["c7"]); - assert_eq!(mock.disconnects.lock().await.as_slice(), &["c7"]); - assert_eq!(broker.inflight_count().await, 0); - } - - /// A cancel targeting a DIFFERENT parent must not flag this setup: it parks - /// normally and resolves via its own child terminal. - #[tokio::test] - async fn parent_cancel_for_other_parent_leaves_setup_intact() { - let mock = Arc::new(MockSpawner::new()); - mock.queue_spawn(Ok("c8".into())).await; - mock.queue_send(Ok(88)).await; - let release = mock.install_send_gate().await; - let broker = - DelegationBroker::new(mock.clone() as Arc, shallow_lookup()); - enable_delegation(&broker).await; - - let driver = { - let broker = broker.clone(); - tokio::spawn(async move { broker.handle_request(request(1, "pt-8")).await }) - }; - loop { - if broker.reserved_child_count().await == 1 { - break; - } - tokio::time::sleep(Duration::from_millis(5)).await; - } - // Wrong-parent cancel — a no-op for this setup. - broker.cancel_by_parent_turn("some-other-parent").await; - let _ = release.send(()); - - // It must park normally; resolve it via its child completion. - let parked = loop { - if let Some(id) = broker.peek_first_pending_call_id().await { - break id; - } - tokio::time::sleep(Duration::from_millis(5)).await; - }; - broker - .complete_call( - &parked, - DelegationOutcome::Ok(DelegationSuccess { - text: "fine".into(), - child_conversation_id: 88, - child_agent_type: AgentType::ClaudeCode, - turn_count: 1, - duration_ms: 5, - token_usage: None, - }), - ) - .await; - assert!(matches!(driver.await.unwrap(), DelegationOutcome::Ok(_))); - assert!( - mock.cancels.lock().await.is_empty(), - "a wrong-parent cancel must not tear this child down" - ); - assert_eq!(broker.inflight_count().await, 0); - } - - /// The in-flight record is deregistered on every exit path: the normal park - /// hand-off, and each early-return (disabled / spawn-fail / send-fail). - #[tokio::test] - async fn inflight_drained_on_normal_park() { - let mock = Arc::new(MockSpawner::new()); - mock.queue_spawn(Ok("c-ok".into())).await; - mock.queue_send(Ok(70)).await; - let broker = - DelegationBroker::new(mock.clone() as Arc, shallow_lookup()); - enable_delegation(&broker).await; - let driver = { - let broker = broker.clone(); - tokio::spawn(async move { broker.handle_request(request(1, "pt-ok")).await }) - }; - let call_id = loop { - if let Some(id) = broker.peek_first_pending_call_id().await { - break id; - } - tokio::time::sleep(Duration::from_millis(5)).await; - }; - // Parked → the in-flight record was handed off (deregistered) at park. - assert_eq!( - broker.inflight_count().await, - 0, - "park deregisters in-flight" - ); - broker - .complete_call( - &call_id, - DelegationOutcome::Ok(DelegationSuccess { - text: "ok".into(), - child_conversation_id: 70, - child_agent_type: AgentType::ClaudeCode, - turn_count: 1, - duration_ms: 5, - token_usage: None, - }), - ) - .await; - assert!(matches!(driver.await.unwrap(), DelegationOutcome::Ok(_))); - assert_eq!(broker.inflight_count().await, 0); - } - - #[tokio::test] - async fn inflight_drained_on_disabled() { - let broker = DelegationBroker::new( - Arc::new(MockSpawner::new()) as Arc, - shallow_lookup(), - ); - // `enabled` defaults to false → short-circuits at the disabled check. - let outcome = broker.handle_request(request(1, "pt-d")).await; - assert!(matches!(outcome, DelegationOutcome::Err { .. })); - assert_eq!(broker.inflight_count().await, 0); - } - - #[tokio::test] - async fn inflight_drained_on_spawn_failure() { - let mock = Arc::new(MockSpawner::new()); - mock.queue_spawn(Err(SpawnerError::Spawn("nope".into()))) - .await; - let broker = - DelegationBroker::new(mock.clone() as Arc, shallow_lookup()); - enable_delegation(&broker).await; - match broker.handle_request(request(1, "pt-sf")).await { - DelegationOutcome::Err { code, .. } => assert_eq!(code, "spawn_failed"), - other => panic!("expected spawn_failed, got {other:?}"), - } - assert_eq!(broker.inflight_count().await, 0); - assert!(mock.disconnects.lock().await.is_empty()); - } - - #[tokio::test] - async fn inflight_drained_on_send_failure() { - let mock = Arc::new(MockSpawner::new()); - mock.queue_spawn(Ok("c6".into())).await; - mock.queue_send(Err(SpawnerError::Send("boom".into()))) - .await; - let broker = - DelegationBroker::new(mock.clone() as Arc, shallow_lookup()); - enable_delegation(&broker).await; - match broker.handle_request(request(1, "pt-sendf")).await { - DelegationOutcome::Err { code, .. } => assert_eq!(code, "spawn_failed"), - other => panic!("expected spawn_failed, got {other:?}"), - } - assert_eq!(broker.inflight_count().await, 0); - assert_eq!(mock.disconnects.lock().await.as_slice(), &["c6"]); - assert!(mock.cancels.lock().await.is_empty()); - } - - /// A terminal failure for a child the broker never reserved (unknown id, or - /// one whose delegation already fully resolved) is a clean no-op — it must - /// not buffer, so the buffer can only ever hold genuine pre-registration - /// races. - #[tokio::test] - async fn cancel_for_unreserved_child_never_buffers() { - let broker = DelegationBroker::new( - Arc::new(MockSpawner::new()) as Arc, - shallow_lookup(), - ); - broker - .cancel_by_child_connection("never-reserved", Some("boom")) - .await; - assert_eq!(broker.early_cancel_count().await, 0); - assert_eq!(broker.pending_count().await, 0); - } - - #[tokio::test] - async fn meta_writer_records_failed_on_parent_cancel() { - let mock = Arc::new(MockSpawner::new()); - mock.queue_spawn(Ok("c-cancel".into())).await; - mock.queue_send(Ok(33)).await; - let writer = Arc::new(MockMetaWriter::new()); - let broker = broker_with_meta(mock.clone(), writer.clone()).await; - - let driver = { - let broker = broker.clone(); - tokio::spawn(async move { broker.handle_request(request(1, "pt-pcancel")).await }) - }; - while broker.pending_count().await == 0 { - tokio::time::sleep(Duration::from_millis(5)).await; - } - broker.cancel_by_parent("parent-conn").await; - let outcome = driver.await.unwrap(); - assert!(matches!(outcome, DelegationOutcome::Err { .. })); - - let calls = writer.snapshot().await; - // running + canceled - assert_eq!(calls.len(), 2); - let inner = calls[1] - .meta - .get("codeg.delegation") - .unwrap() - .as_object() - .unwrap(); - assert_eq!(inner.get("status").unwrap().as_str().unwrap(), "failed"); - assert_eq!( - inner.get("error_code").unwrap().as_str().unwrap(), - "canceled" - ); - } - - #[tokio::test] - async fn meta_writer_skipped_for_synthetic_parent_tool_use_id() { - let mock = Arc::new(MockSpawner::new()); - mock.queue_spawn(Ok("c-synth".into())).await; - mock.queue_send(Ok(8)).await; - let writer = Arc::new(MockMetaWriter::new()); - let broker = broker_with_meta(mock.clone(), writer.clone()).await; - - // Empty `parent_tool_use_id` triggers the broker's UUID fallback — - // `"delegation-"` — which the writer must skip because no - // matching ACP tool_call_id exists. - let driver = { - let broker = broker.clone(); - tokio::spawn(async move { broker.handle_request(request(1, "")).await }) - }; - let call_id = loop { - if let Some(id) = broker.peek_first_pending_call_id().await { - break id; - } - tokio::time::sleep(Duration::from_millis(5)).await; - }; - broker - .complete_call( - &call_id, - DelegationOutcome::Ok(DelegationSuccess { - text: "ok".into(), - child_conversation_id: 8, - child_agent_type: AgentType::Codex, - turn_count: 1, - duration_ms: 5, - token_usage: None, - }), - ) - .await; - driver.await.unwrap(); - - let calls = writer.snapshot().await; - assert!( - calls.is_empty(), - "writer should be skipped for synthetic parent_tool_use_id, got {:?}", - calls - ); - } - - // -- Event emitter lifecycle ------------------------------------------ - // - // Issue: `.docs/issues/2026-05-24-delegation-termination-cascade.md`. - // The broker must emit `AcpEvent::DelegationCompleted` once per drained - // pending entry, regardless of which terminal path drained it (happy - // `complete_call`, MCP `cancel_by_external_handle`, child-disconnect - // cleanup, or parent-cancel cascade). Without these emits the frontend's live - // delegation binding stays at "running" forever — see the issue doc - // for the full path matrix. - - use crate::acp::delegation::event_emitter::mock::MockEventEmitter; - use crate::acp::delegation::event_emitter::DelegationEventEmitter; - use crate::acp::types::DelegationResultSummary; - - async fn broker_with_emitter( - mock: Arc, - writer: Arc, - emitter: Arc, - ) -> DelegationBroker { - let broker = DelegationBroker::with_writers( - mock as Arc, - shallow_lookup(), - writer as Arc, - emitter as Arc, - ); - enable_delegation(&broker).await; - broker - } - - #[tokio::test] - async fn emitter_records_ok_on_complete_call_happy_path() { - let mock = Arc::new(MockSpawner::new()); - mock.queue_spawn(Ok("child-conn-1".into())).await; - mock.queue_send(Ok(42)).await; - let writer = Arc::new(MockMetaWriter::new()); - let emitter = Arc::new(MockEventEmitter::new()); - let broker = broker_with_emitter(mock.clone(), writer.clone(), emitter.clone()).await; - - let driver = { - let broker = broker.clone(); - tokio::spawn(async move { broker.handle_request(request(1, "pt-ok")).await }) - }; - let call_id = loop { - if let Some(id) = broker.peek_first_pending_call_id().await { - break id; - } - tokio::time::sleep(Duration::from_millis(5)).await; - }; - broker - .complete_call( - &call_id, - DelegationOutcome::Ok(DelegationSuccess { - text: "done".into(), - child_conversation_id: 42, - child_agent_type: AgentType::ClaudeCode, - turn_count: 1, - duration_ms: 73, - token_usage: None, - }), - ) - .await; - driver.await.unwrap(); - - let calls = emitter.snapshot().await; - assert_eq!(calls.len(), 1); - let call = &calls[0]; - assert_eq!(call.parent_tool_use_id, "pt-ok"); - assert_eq!(call.child_connection_id, "child-conn-1"); - assert_eq!(call.child_conversation_id, 42); - // The completed event carries the child agent_type (from the running - // task), so a frontend that missed `DelegationStarted` still binds the - // correct agent. `request()` delegates to ClaudeCode. - assert_eq!(call.agent_type, AgentType::ClaudeCode); - // duration_ms is now broker-measured (not the outcome's value); assert - // the Ok variant + the enriched text_preview instead. - assert!( - matches!( - &call.result, - DelegationResultSummary::Ok { text_preview, .. } - if text_preview.as_deref() == Some("done") - ), - "expected Ok with preview, got {:?}", - call.result - ); - } - - #[tokio::test] - async fn emitter_records_started_on_start_delegation_happy_path() { - let mock = Arc::new(MockSpawner::new()); - mock.queue_spawn(Ok("child-conn-start".into())).await; - mock.queue_send(Ok(55)).await; - let writer = Arc::new(MockMetaWriter::new()); - let emitter = Arc::new(MockEventEmitter::new()); - let broker = broker_with_emitter(mock.clone(), writer.clone(), emitter.clone()).await; - - let driver = { - let broker = broker.clone(); - tokio::spawn(async move { broker.handle_request(request(1, "pt-start")).await }) - }; - let call_id = loop { - if let Some(id) = broker.peek_first_pending_call_id().await { - break id; - } - tokio::time::sleep(Duration::from_millis(5)).await; - }; - - // `started` fires during setup, BEFORE the task parks — so it is already - // recorded by the time a pending entry is visible, and it must not be - // conflated with the (not-yet-emitted) terminal. - let started = emitter.started_snapshot().await; - assert_eq!(started.len(), 1, "exactly one DelegationStarted per task"); - let s = &started[0]; - assert_eq!(s.parent_connection_id, "parent-conn"); - assert_eq!(s.parent_tool_use_id, "pt-start"); - assert_eq!(s.child_connection_id, "child-conn-start"); - assert_eq!(s.child_conversation_id, 55); - assert_eq!(s.agent_type, AgentType::ClaudeCode); - assert_eq!( - emitter.count().await, - 0, - "no terminal emit before completion" - ); - - broker - .complete_call( - &call_id, - DelegationOutcome::Ok(DelegationSuccess { - text: "done".into(), - child_conversation_id: 55, - child_agent_type: AgentType::ClaudeCode, - turn_count: 1, - duration_ms: 10, - token_usage: None, - }), - ) - .await; - driver.await.unwrap(); - - // Completion adds exactly one terminal emit; started stays at 1. - assert_eq!(emitter.started_count().await, 1); - assert_eq!(emitter.count().await, 1); - } - - #[tokio::test] - async fn emitter_skips_started_for_synthetic_parent_tool_use_id() { - let mock = Arc::new(MockSpawner::new()); - mock.queue_spawn(Ok("c-synth-start".into())).await; - mock.queue_send(Ok(9)).await; - let writer = Arc::new(MockMetaWriter::new()); - let emitter = Arc::new(MockEventEmitter::new()); - let broker = broker_with_emitter(mock.clone(), writer.clone(), emitter.clone()).await; - - // Empty parent_tool_use_id → broker falls back to a synthetic - // `delegation-` id (no ACP tool_call to claim in a mock harness). - let driver = { - let broker = broker.clone(); - tokio::spawn(async move { broker.handle_request(request(1, "")).await }) - }; - let call_id = loop { - if let Some(id) = broker.peek_first_pending_call_id().await { - break id; - } - tokio::time::sleep(Duration::from_millis(5)).await; - }; - broker - .complete_call( - &call_id, - DelegationOutcome::Ok(DelegationSuccess { - text: "ok".into(), - child_conversation_id: 9, - child_agent_type: AgentType::Codex, - turn_count: 1, - duration_ms: 5, - token_usage: None, - }), - ) - .await; - driver.await.unwrap(); - - assert_eq!( - emitter.started_count().await, - 0, - "started emit must skip synthetic parent_tool_use_id (same rule as the meta writer / completed emit)" - ); - } - - #[tokio::test] - async fn emitter_records_err_on_complete_call_err_outcome() { - let mock = Arc::new(MockSpawner::new()); - mock.queue_spawn(Ok("child-conn-err".into())).await; - mock.queue_send(Ok(11)).await; - let writer = Arc::new(MockMetaWriter::new()); - let emitter = Arc::new(MockEventEmitter::new()); - let broker = broker_with_emitter(mock.clone(), writer.clone(), emitter.clone()).await; - - let driver = { - let broker = broker.clone(); - tokio::spawn(async move { broker.handle_request(request(1, "pt-err")).await }) - }; - let call_id = loop { - if let Some(id) = broker.peek_first_pending_call_id().await { - break id; - } - tokio::time::sleep(Duration::from_millis(5)).await; - }; - broker - .complete_call( - &call_id, - DelegationOutcome::from_err( - DelegationError::SubagentRuntimeError("agent died".into()), - Some(11), - ), - ) - .await; - driver.await.unwrap(); - - let calls = emitter.snapshot().await; - assert_eq!(calls.len(), 1); - match &calls[0].result { - DelegationResultSummary::Err { error_code } => { - assert_eq!(error_code, "subagent_error") - } - other => panic!("expected Err, got {other:?}"), - } - } - - #[tokio::test] - async fn emitter_records_canceled_on_cancel_by_external_handle() { - // MCP-driven cancel path: companion received notifications/cancelled - // and the listener forwarded it to broker.cancel_by_external_handle. - // The broker must drain the pending entry, cancel + disconnect the - // child, and emit DelegationCompleted with error_code = "canceled". - let mock = Arc::new(MockSpawner::new()); - mock.queue_spawn(Ok("child-conn-h".into())).await; - mock.queue_send(Ok(91)).await; - let writer = Arc::new(MockMetaWriter::new()); - let emitter = Arc::new(MockEventEmitter::new()); - let broker = broker_with_emitter(mock.clone(), writer.clone(), emitter.clone()).await; - - let driver = { - let broker = broker.clone(); - tokio::spawn(async move { - broker - .handle_request(request_with_handle(1, "pt-mcp-cancel", "h-1")) - .await - }) - }; - while broker.pending_count().await == 0 { - tokio::time::sleep(Duration::from_millis(5)).await; - } - broker - .cancel_by_external_handle("h-1", "user requested".into()) - .await; - let outcome = driver.await.unwrap(); - assert!(matches!( - outcome, - DelegationOutcome::Err { ref code, .. } if code == "canceled" - )); - - assert_eq!(mock.cancels.lock().await.as_slice(), &["child-conn-h"]); - let calls = emitter.snapshot().await; - assert_eq!(calls.len(), 1, "expected exactly one emit, got {calls:?}"); - let call = &calls[0]; - assert_eq!(call.parent_tool_use_id, "pt-mcp-cancel"); - assert_eq!(call.child_connection_id, "child-conn-h"); - assert_eq!(call.child_conversation_id, 91); - match &call.result { - DelegationResultSummary::Err { error_code } => { - assert_eq!(error_code, "canceled") - } - other => panic!("expected Err{{canceled}}, got {other:?}"), - } - } - - #[tokio::test] - async fn cancel_by_external_handle_no_match_buffers_pre_cancel() { - // Cancel arrives before handle_request reaches pending registration. - // The broker must buffer the handle in pre_canceled_handles so the - // in-flight call drains itself on its post-registration checkpoint. - let mock = Arc::new(MockSpawner::new()); - mock.queue_spawn(Ok("child-conn-pre".into())).await; - mock.queue_send(Ok(13)).await; - let writer = Arc::new(MockMetaWriter::new()); - let emitter = Arc::new(MockEventEmitter::new()); - let broker = broker_with_emitter(mock.clone(), writer.clone(), emitter.clone()).await; - - // Pre-cancel before spawning the driver — handle is unknown to the - // broker right now, but a buffered entry should make the next - // handle_request with the same handle bail out canceled. - broker - .cancel_by_external_handle("h-pre", "early cancel".into()) - .await; - // Pre-cancel set is single-shot: a second call with the same handle - // and no pending entry just buffers it again (idempotent in practice). - let outcome = broker - .handle_request(request_with_handle(1, "pt-pre", "h-pre")) - .await; - match outcome { - DelegationOutcome::Err { code, .. } => assert_eq!(code, "canceled"), - other => panic!("expected canceled, got {other:?}"), - } - // Since the cancel won pre-spawn, no child connection should have - // been opened. - assert!(mock.cancels.lock().await.is_empty()); - assert!(mock.disconnects.lock().await.is_empty()); - // The pre-cancel early-return must also drop the in-flight record - // (registered as handle_request's first statement, before this check). - assert_eq!(broker.inflight_count().await, 0); - } - - /// The real MCP-shaped path carries an `external_handle`. Registration now - /// happens as `handle_request`'s FIRST statement — before the pre-cancel - /// `.await` — so a parent cancel in the setup window reaches these requests - /// too, not just the synthetic-id path. Guards the regression Codex flagged - /// (registration ordered after the pre-cancel await left a miss window). - #[tokio::test] - async fn parent_cancel_covers_external_handle_setup_window() { - let mock = Arc::new(MockSpawner::new()); - mock.queue_spawn(Ok("c-eh".into())).await; - mock.queue_send(Ok(21)).await; - let release = mock.install_send_gate().await; - let broker = - DelegationBroker::new(mock.clone() as Arc, shallow_lookup()); - enable_delegation(&broker).await; - - let driver = { - let broker = broker.clone(); - tokio::spawn(async move { - broker - .handle_request(request_with_handle(1, "pt-eh", "h-eh")) - .await - }) - }; - loop { - if broker.reserved_child_count().await == 1 { - break; - } - tokio::time::sleep(Duration::from_millis(5)).await; - } - assert_eq!(broker.inflight_count().await, 1); - - broker.cancel_by_parent_turn("parent-conn").await; - let _ = release.send(()); - - match driver.await.unwrap() { - DelegationOutcome::Err { code, .. } => assert_eq!(code, "canceled"), - other => panic!("expected canceled, got {other:?}"), - } - assert_eq!(mock.cancels.lock().await.as_slice(), &["c-eh"]); - assert_eq!(mock.disconnects.lock().await.as_slice(), &["c-eh"]); - assert_eq!(broker.inflight_count().await, 0); - } - - #[tokio::test] - async fn emitter_records_canceled_on_cancel_by_child_connection() { - let mock = Arc::new(MockSpawner::new()); - mock.queue_spawn(Ok("c-dropped".into())).await; - mock.queue_send(Ok(55)).await; - let writer = Arc::new(MockMetaWriter::new()); - let emitter = Arc::new(MockEventEmitter::new()); - let broker = broker_with_emitter(mock.clone(), writer.clone(), emitter.clone()).await; - - let driver = { - let broker = broker.clone(); - tokio::spawn(async move { broker.handle_request(request(1, "pt-cbc")).await }) - }; - while broker.pending_count().await == 0 { - tokio::time::sleep(Duration::from_millis(5)).await; - } - broker.cancel_by_child_connection("c-dropped", None).await; - let outcome = driver.await.unwrap(); - match &outcome { - DelegationOutcome::Err { code, message, .. } => { - assert_eq!(code, "canceled"); - // No terminal_error supplied → falls back to default reason. - assert_eq!( - message, - "canceled: child session ended without TurnComplete" - ); - } - other => panic!("expected Err{{canceled}}, got {other:?}"), - } - - let calls = emitter.snapshot().await; - assert_eq!(calls.len(), 1); - match &calls[0].result { - DelegationResultSummary::Err { error_code } => { - assert_eq!(error_code, "canceled") - } - other => panic!("expected Err{{canceled}}, got {other:?}"), - } - } - - #[tokio::test] - async fn cancel_by_child_connection_threads_terminal_error_into_reason() { - // The lifecycle worker forwards the child's last AcpEvent::Error - // detail through `cancel_by_child_connection`. The broker stitches it - // into the `Canceled { reason }` message so the parent's - // `delegate_to_agent` tool-call result surfaces the real failure - // cause (e.g. Gemini OAuth expired) instead of the opaque default. - let mock = Arc::new(MockSpawner::new()); - mock.queue_spawn(Ok("c-auth".into())).await; - mock.queue_send(Ok(77)).await; - let writer = Arc::new(MockMetaWriter::new()); - let emitter = Arc::new(MockEventEmitter::new()); - let broker = broker_with_emitter(mock.clone(), writer.clone(), emitter.clone()).await; - - let driver = { - let broker = broker.clone(); - tokio::spawn(async move { broker.handle_request(request(1, "pt-auth")).await }) - }; - while broker.pending_count().await == 0 { - tokio::time::sleep(Duration::from_millis(5)).await; - } - broker - .cancel_by_child_connection("c-auth", Some("[auth_required] Authentication required")) - .await; - let outcome = driver.await.unwrap(); - match &outcome { - DelegationOutcome::Err { code, message, .. } => { - assert_eq!(code, "canceled"); - assert_eq!( - message, - "canceled: child session ended without TurnComplete: \ - [auth_required] Authentication required" - ); - } - other => panic!("expected Err{{canceled}}, got {other:?}"), - } - } - - #[tokio::test] - async fn cancel_by_child_connection_ignores_empty_terminal_error() { - // Whitespace-only or empty detail strings shouldn't produce a - // dangling "...:" suffix on the reason — fall back to the default. - let mock = Arc::new(MockSpawner::new()); - mock.queue_spawn(Ok("c-empty".into())).await; - mock.queue_send(Ok(78)).await; - let broker = - DelegationBroker::new(mock.clone() as Arc, shallow_lookup()); - enable_delegation(&broker).await; - - let driver = { - let broker = broker.clone(); - tokio::spawn(async move { broker.handle_request(request(1, "pt-empty")).await }) - }; - while broker.pending_count().await == 0 { - tokio::time::sleep(Duration::from_millis(5)).await; - } - broker - .cancel_by_child_connection("c-empty", Some(" ")) - .await; - let outcome = driver.await.unwrap(); - match &outcome { - DelegationOutcome::Err { message, .. } => { - assert_eq!( - message, - "canceled: child session ended without TurnComplete" - ); - } - other => panic!("expected Err, got {other:?}"), - } - } - - #[tokio::test] - async fn emitter_records_one_event_per_drained_entry_on_cancel_by_parent() { - let mock = Arc::new(MockSpawner::new()); - for i in 0..3 { - mock.queue_spawn(Ok(format!("c{i}"))).await; - mock.queue_send(Ok(100 + i)).await; - } - let writer = Arc::new(MockMetaWriter::new()); - let emitter = Arc::new(MockEventEmitter::new()); - let broker = broker_with_emitter(mock.clone(), writer.clone(), emitter.clone()).await; - - let mut handles = Vec::new(); - for i in 0..3 { - let broker = broker.clone(); - handles.push(tokio::spawn(async move { - broker.handle_request(request(1, &format!("pt-{i}"))).await - })); - } - while broker.pending_count().await < 3 { - tokio::time::sleep(Duration::from_millis(5)).await; - } - broker.cancel_by_parent("parent-conn").await; - for h in handles { - let _ = h.await.unwrap(); - } - - let calls = emitter.snapshot().await; - assert_eq!(calls.len(), 3, "expected 3 emits, got {calls:?}"); - let mut parent_tool_use_ids: Vec = - calls.iter().map(|c| c.parent_tool_use_id.clone()).collect(); - parent_tool_use_ids.sort(); - assert_eq!( - parent_tool_use_ids, - vec!["pt-0".to_string(), "pt-1".to_string(), "pt-2".to_string()] - ); - for call in &calls { - match &call.result { - DelegationResultSummary::Err { error_code } => { - assert_eq!(error_code, "canceled") - } - other => panic!("expected Err{{canceled}}, got {other:?}"), - } - } - } - - #[tokio::test] - async fn emitter_does_not_double_emit_on_repeat_cancel_by_parent() { - let mock = Arc::new(MockSpawner::new()); - mock.queue_spawn(Ok("c-once".into())).await; - mock.queue_send(Ok(42)).await; - let writer = Arc::new(MockMetaWriter::new()); - let emitter = Arc::new(MockEventEmitter::new()); - let broker = broker_with_emitter(mock.clone(), writer.clone(), emitter.clone()).await; - - let driver = { - let broker = broker.clone(); - tokio::spawn(async move { broker.handle_request(request(1, "pt-idem")).await }) - }; - while broker.pending_count().await == 0 { - tokio::time::sleep(Duration::from_millis(5)).await; - } - // First call drains the entry + emits one. - broker.cancel_by_parent("parent-conn").await; - // Second call finds the pending map empty — no extra emit. - broker.cancel_by_parent("parent-conn").await; - // Cleanup-guard-style triple call also stays bounded. - broker.cancel_by_parent("parent-conn").await; - let _ = driver.await.unwrap(); - - assert_eq!(emitter.count().await, 1); - } - - #[tokio::test] - async fn emitter_skipped_for_synthetic_parent_tool_use_id() { - let mock = Arc::new(MockSpawner::new()); - mock.queue_spawn(Ok("c-synth".into())).await; - mock.queue_send(Ok(8)).await; - let writer = Arc::new(MockMetaWriter::new()); - let emitter = Arc::new(MockEventEmitter::new()); - let broker = broker_with_emitter(mock.clone(), writer.clone(), emitter.clone()).await; - - let driver = { - let broker = broker.clone(); - tokio::spawn(async move { broker.handle_request(request(1, "")).await }) - }; - let call_id = loop { - if let Some(id) = broker.peek_first_pending_call_id().await { - break id; - } - tokio::time::sleep(Duration::from_millis(5)).await; - }; - broker - .complete_call( - &call_id, - DelegationOutcome::Ok(DelegationSuccess { - text: "ok".into(), - child_conversation_id: 8, - child_agent_type: AgentType::Codex, - turn_count: 1, - duration_ms: 5, - token_usage: None, - }), - ) - .await; - driver.await.unwrap(); - - let calls = emitter.snapshot().await; - assert!( - calls.is_empty(), - "emitter must skip synthetic parent_tool_use_id (same rule as meta writer); got {calls:?}" - ); - } - - #[tokio::test] - async fn emitter_records_after_meta_write_on_complete_call() { - // Frontend's snapshot-recovery path reads `meta["codeg.delegation"]` - // first and the live event second; if the emit lands before the - // meta write, a snapshot taken between them would see "running" - // meta paired with a "completed" event. Enforce meta-before-emit - // by checking the MockMetaWriter has at least one call before the - // emitter records. - let mock = Arc::new(MockSpawner::new()); - mock.queue_spawn(Ok("c-order".into())).await; - mock.queue_send(Ok(7)).await; - let writer = Arc::new(MockMetaWriter::new()); - let emitter = Arc::new(MockEventEmitter::new()); - let broker = broker_with_emitter(mock.clone(), writer.clone(), emitter.clone()).await; - - let driver = { - let broker = broker.clone(); - tokio::spawn(async move { broker.handle_request(request(1, "pt-order")).await }) - }; - let call_id = loop { - if let Some(id) = broker.peek_first_pending_call_id().await { - break id; - } - tokio::time::sleep(Duration::from_millis(5)).await; - }; - broker - .complete_call( - &call_id, - DelegationOutcome::Ok(DelegationSuccess { - text: "ok".into(), - child_conversation_id: 7, - child_agent_type: AgentType::ClaudeCode, - turn_count: 1, - duration_ms: 5, - token_usage: None, - }), - ) - .await; - driver.await.unwrap(); - - let meta_calls = writer.snapshot().await; - let event_calls = emitter.snapshot().await; - // running (from handle_request) + completed (from complete_call) = - // 2 meta writes. The single event must be the "completed" one, - // and it must land AFTER the running meta — guaranteed structurally - // by complete_call's order (write_meta_if_real then emit). - assert_eq!(meta_calls.len(), 2); - assert_eq!(event_calls.len(), 1); - let inner_second = meta_calls[1] - .meta - .get("codeg.delegation") - .unwrap() - .as_object() - .unwrap(); - assert_eq!( - inner_second.get("status").unwrap().as_str().unwrap(), - "completed" - ); - } - - // -- Production-path fanout coverage ---------------------------------- - // - // Every other emitter test in this module uses `MockEventEmitter`. The - // production wiring goes through `ConnectionManagerEventEmitter`, which - // resolves `(state, emitter)` against the live `ConnectionManager` and - // hands the event to `emit_with_state` so it fans out to (1) the parent - // connection's `ConnectionEventStream` (the WS attach path) and (2) the - // `InternalEventBus` (the lifecycle/pet/chat-channel subscriber path). - // These tests exercise that real fanout end-to-end so a regression in - // `get_state_and_emitter` lookup, `emit_with_state` routing, or the - // `EventEmitter::WebOnly { bus, .. }` wiring is caught here even when - // every mock-backed test stays green. - - #[tokio::test] - async fn real_emitter_fans_out_delegation_completed_to_parent_stream_and_bus() { - use crate::acp::delegation::event_emitter::ConnectionManagerEventEmitter; - use crate::acp::manager::ConnectionManager; - use crate::acp::types::AcpEvent; - use crate::web::event_bridge::{EventEmitter, WebEventBroadcaster}; - - // Real ConnectionManager + fake parent wired to a WebOnly emitter so - // the InternalEventBus gets typed envelopes and we can subscribe to - // verify the lifecycle-path delivery alongside the per-connection - // stream delivery. - let manager = ConnectionManager::new(); - let broadcaster = Arc::new(WebEventBroadcaster::new()); - let parent_emitter = EventEmitter::test_web_only(broadcaster); - let bus = parent_emitter - .acp_event_bus() - .expect("WebOnly emitter must expose an InternalEventBus"); - manager - .insert_test_connection("parent-conn", AgentType::ClaudeCode, None, parent_emitter) - .await; - - // Subscribe BEFORE triggering events — broadcast channels drop - // sends that happen with no receivers registered. - let mut bus_rx = bus.subscribe(); - let (parent_state, _) = manager - .get_state_and_emitter("parent-conn") - .await - .expect("parent just inserted"); - let mut stream_rx = parent_state.read().await.event_stream().subscribe(); - - // Build the broker with the PRODUCTION emitter; meta writer can stay - // noop because this test is asserting the event-fanout invariant. - let mock_spawner = Arc::new(MockSpawner::new()); - mock_spawner.queue_spawn(Ok("child-conn-real".into())).await; - mock_spawner.queue_send(Ok(77)).await; - let real_emitter = Arc::new(ConnectionManagerEventEmitter { - manager: Arc::new(manager.clone_ref()), - }); - let broker = DelegationBroker::with_writers( - mock_spawner.clone() as Arc, - shallow_lookup(), - Arc::new(crate::acp::delegation::meta_writer::NoopMetaWriter) - as Arc, - real_emitter as Arc, - ); - enable_delegation(&broker).await; - - // Park a pending entry then trigger cancel_by_parent to drive the - // production emit path. `request()` hard-codes parent_connection_id - // = "parent-conn" which matches the insert above. - let driver = { - let broker = broker.clone(); - tokio::spawn(async move { broker.handle_request(request(1, "pt-fanout")).await }) - }; - while broker.pending_count().await == 0 { - tokio::time::sleep(Duration::from_millis(5)).await; - } - broker.cancel_by_parent("parent-conn").await; - let _ = driver.await.unwrap(); - - // Per-connection stream (WS attach delivery path) must receive the - // envelope tagged with the right connection + payload shape. - // The parent stream now also carries the setup-time DelegationStarted; - // skip past it to the terminal DelegationCompleted. - let envelope = loop { - let env = tokio::time::timeout(Duration::from_millis(500), stream_rx.recv()) - .await - .expect("per-connection stream should receive DelegationCompleted within 500ms") - .expect("envelope recv must not error"); - if matches!(env.payload, AcpEvent::DelegationStarted { .. }) { - continue; - } - break env; - }; - assert_eq!(envelope.connection_id, "parent-conn"); - match &envelope.payload { - AcpEvent::DelegationCompleted { - parent_tool_use_id, - child_connection_id, - child_conversation_id, - result, - .. - } => { - assert_eq!(parent_tool_use_id, "pt-fanout"); - assert_eq!(child_connection_id, "child-conn-real"); - assert_eq!(*child_conversation_id, 77); - match result { - DelegationResultSummary::Err { error_code } => { - assert_eq!(error_code, "canceled"); - } - other => panic!("expected Err{{canceled}}, got {other:?}"), - } - } - other => panic!("expected DelegationCompleted, got {other:?}"), - } - - // InternalEventBus (lifecycle/pet/chat-channel subscriber path) must - // also receive the same envelope — proves the WebOnly emitter's bus - // arm in `emit_with_state` is reached. - let bus_envelope = loop { - let env = tokio::time::timeout(Duration::from_millis(500), bus_rx.recv()) - .await - .expect("InternalEventBus should receive DelegationCompleted within 500ms") - .expect("bus recv must not error"); - if matches!(env.payload, AcpEvent::DelegationStarted { .. }) { - continue; - } - break env; - }; - assert_eq!(bus_envelope.connection_id, "parent-conn"); - assert!(matches!( - bus_envelope.payload, - AcpEvent::DelegationCompleted { .. } - )); - } - - #[tokio::test] - async fn real_emitter_fans_out_delegation_started_to_parent_stream_and_bus() { - use crate::acp::delegation::event_emitter::ConnectionManagerEventEmitter; - use crate::acp::manager::ConnectionManager; - use crate::acp::types::AcpEvent; - use crate::web::event_bridge::{EventEmitter, WebEventBroadcaster}; - - // Web/server delivery shape: a real ConnectionManager + a fake parent on - // a WebOnly emitter. `DelegationStarted` must land on the PARENT's - // per-connection stream (the WS attach path the frontend subscribes to - // in web/server mode) AND the InternalEventBus — mirroring the - // completed-path invariant. This is the regression lock for the - // web-mode live-delegation gap: before moving the emit to the parent - // stream, started rode the (un-attached) child stream and was lost here. - let manager = ConnectionManager::new(); - let broadcaster = Arc::new(WebEventBroadcaster::new()); - let parent_emitter = EventEmitter::test_web_only(broadcaster); - let bus = parent_emitter - .acp_event_bus() - .expect("WebOnly emitter must expose an InternalEventBus"); - manager - .insert_test_connection("parent-conn", AgentType::ClaudeCode, None, parent_emitter) - .await; - - // Subscribe BEFORE triggering events — broadcast channels drop sends - // that happen with no receivers registered. - let mut bus_rx = bus.subscribe(); - let (parent_state, _) = manager - .get_state_and_emitter("parent-conn") - .await - .expect("parent just inserted"); - let mut stream_rx = parent_state.read().await.event_stream().subscribe(); - - let mock_spawner = Arc::new(MockSpawner::new()); - mock_spawner - .queue_spawn(Ok("child-conn-started".into())) - .await; - mock_spawner.queue_send(Ok(88)).await; - let real_emitter = Arc::new(ConnectionManagerEventEmitter { - manager: Arc::new(manager.clone_ref()), - }); - let broker = DelegationBroker::with_writers( - mock_spawner.clone() as Arc, - shallow_lookup(), - Arc::new(crate::acp::delegation::meta_writer::NoopMetaWriter) - as Arc, - real_emitter as Arc, - ); - enable_delegation(&broker).await; - - // `started` fires during setup, before park — drive the request, wait - // for it to park, then assert the envelope already arrived. - let driver = { - let broker = broker.clone(); - tokio::spawn(async move { broker.handle_request(request(1, "pt-started")).await }) - }; - while broker.pending_count().await == 0 { - tokio::time::sleep(Duration::from_millis(5)).await; - } - - let envelope = tokio::time::timeout(Duration::from_millis(500), stream_rx.recv()) - .await - .expect("per-connection stream should receive DelegationStarted within 500ms") - .expect("envelope recv must not error"); - assert_eq!(envelope.connection_id, "parent-conn"); - match &envelope.payload { - AcpEvent::DelegationStarted { - parent_connection_id, - parent_tool_use_id, - child_connection_id, - child_conversation_id, - agent_type, - task_preview, - task_id, - } => { - assert_eq!(parent_connection_id, "parent-conn"); - assert_eq!(parent_tool_use_id, "pt-started"); - assert_eq!(child_connection_id, "child-conn-started"); - assert_eq!(*child_conversation_id, 88); - assert_eq!(*agent_type, AgentType::ClaudeCode); - // The event labels the card even when the parent tool call's - // raw_input never carried the arguments (identity-less hosts). - assert_eq!(task_preview, "do x"); - assert!(!task_id.is_empty(), "broker-minted task id must ride the event"); - } - other => panic!("expected DelegationStarted, got {other:?}"), - } - - let bus_envelope = tokio::time::timeout(Duration::from_millis(500), bus_rx.recv()) - .await - .expect("InternalEventBus should receive DelegationStarted within 500ms") - .expect("bus recv must not error"); - assert_eq!(bus_envelope.connection_id, "parent-conn"); - assert!(matches!( - bus_envelope.payload, - AcpEvent::DelegationStarted { .. } - )); - - // Drain the parked driver so the test doesn't leak the spawned task. - broker.cancel_by_parent("parent-conn").await; - let _ = driver.await.unwrap(); - } - - #[tokio::test] - async fn real_emitter_is_silent_no_op_when_parent_already_detached() { - // Parent torn down mid-delegation: `get_state_and_emitter` returns - // None, the emit silently drops, BUT the broker still drains its - // pending table and surfaces the outcome to the awaiting caller. - // This is the "parent disappeared before terminal" path that the - // mock-backed tests can't observe. - use crate::acp::delegation::event_emitter::ConnectionManagerEventEmitter; - use crate::acp::manager::ConnectionManager; - - let manager = ConnectionManager::new(); - // Intentionally no insert_test_connection — parent is absent. - let real_emitter = Arc::new(ConnectionManagerEventEmitter { - manager: Arc::new(manager.clone_ref()), - }); - let mock_spawner = Arc::new(MockSpawner::new()); - mock_spawner.queue_spawn(Ok("c-orphan".into())).await; - mock_spawner.queue_send(Ok(1)).await; - let broker = DelegationBroker::with_writers( - mock_spawner.clone() as Arc, - shallow_lookup(), - Arc::new(crate::acp::delegation::meta_writer::NoopMetaWriter) - as Arc, - real_emitter as Arc, - ); - enable_delegation(&broker).await; - - let driver = { - let broker = broker.clone(); - tokio::spawn(async move { broker.handle_request(request(1, "pt-orphan")).await }) - }; - while broker.pending_count().await == 0 { - tokio::time::sleep(Duration::from_millis(5)).await; - } - broker.cancel_by_parent("parent-conn").await; - let outcome = driver.await.unwrap(); - - assert!(matches!( - outcome, - DelegationOutcome::Err { ref code, .. } if code == "canceled" - )); - assert_eq!( - broker.pending_count().await, - 0, - "broker must drain pending even when no parent exists to receive the emit" - ); - } - - // -- Async-cutover review regressions ----------------------------------- - - /// A pre-cancel that bails `start_delegation` before the claim path must - /// still drain the keyed ACP tool_call, so a later same-key delegation - /// can't claim the canceled call's id and mis-bind to the wrong card. - #[tokio::test] - async fn pre_cancel_drains_keyed_tool_call_to_avoid_misbinding() { - let broker = DelegationBroker::new( - Arc::new(MockSpawner::new()) as Arc, - shallow_lookup(), - ); - enable_delegation(&broker).await; - let key = DelegationMatchKey { - agent_type: AgentType::ClaudeCode, - task: "do x".into(), - working_dir: None, - }; - // The lifecycle registered the keyed tool_call for this delegation. - broker - .register_pending_tool_call_with_key("parent-conn", "tc-1".into(), Some(key.clone())) - .await; - // notifications/cancelled lands before the round-trip → buffered (no - // running task yet). - broker.cancel_by_external_handle("h-1", "user".into()).await; - // The MCP round-trip arrives (empty parent_tool_use_id, same key) and - // bails at the first pre-cancel check. - let report = broker - .start_delegation(request_with_handle(1, "", "h-1")) - .await; - assert_eq!(report.status, TaskStatus::Canceled); - // The keyed entry must have been drained — not claimable afterward. - assert_eq!( - broker.take_matching_tool_call("parent-conn", &key).await, - None - ); - } - - /// The running ack must carry the literal task_id in its message, so a - /// client that only surfaces MCP `content` text (not `structuredContent`) - /// can still call get_delegation_status / cancel_delegation. - #[test] - fn running_ack_message_embeds_task_id() { - let report = running_ack("task-xyz".into(), 42, AgentType::Codex); - assert_eq!(report.task_id.as_deref(), Some("task-xyz")); - assert!( - report.message.as_deref().unwrap().contains("task-xyz"), - "ack message must embed the literal task_id, got {:?}", - report.message - ); - } - - /// Previews and cached text must stay within their advertised BYTE caps - /// (including the appended ellipsis), and truncate on UTF-8 boundaries. - #[test] - fn previews_and_cached_text_respect_byte_caps() { - let preview = build_text_preview(&"x".repeat(STATUS_PREVIEW_CAP * 2)).unwrap(); - assert!( - preview.len() <= STATUS_PREVIEW_CAP, - "preview {} > cap {STATUS_PREVIEW_CAP}", - preview.len() - ); - let cached = cap_completed_text(&"y".repeat(COMPLETED_TEXT_CAP * 2)); - assert!(cached.len() <= COMPLETED_TEXT_CAP); - // Multibyte safety: 3-byte chars must not be split, and the cap holds. - let multibyte = build_text_preview(&"€".repeat(STATUS_PREVIEW_CAP)).unwrap(); - assert!(multibyte.len() <= STATUS_PREVIEW_CAP); - assert!(std::str::from_utf8(multibyte.as_bytes()).is_ok()); - } - - // -- completed-cache byte valve ---------------------------------------- - - fn completed_with_text(parent: &str, text_len: usize) -> CompletedTask { - CompletedTask { - parent_connection_id: parent.to_string(), - child_conversation_id: 1, - agent_type: AgentType::ClaudeCode, - status: TaskStatus::Completed, - text: Some("x".repeat(text_len)), - error_code: None, - message: None, - duration_ms: 0, - } - } - - #[test] - fn completed_cache_valve_evicts_oldest_over_byte_budget() { - let mut inner = PendingInner { - completed_cap_bytes: 1000, - ..Default::default() - }; - // Three 400-byte results = 1200 bytes > 1000 cap. Oldest must evict. - inner.insert_completed("a", completed_with_text("p1", 400)); - inner.insert_completed("b", completed_with_text("p1", 400)); - inner.insert_completed("c", completed_with_text("p1", 400)); - assert!(!inner.completed.contains_key("a"), "oldest must be evicted"); - assert!(inner.completed.contains_key("b")); - assert!(inner.completed.contains_key("c"), "newest must be retained"); - // Counter + order reflect only the two retained entries. - assert_eq!(inner.completed_bytes.get("p1").copied(), Some(800)); - assert_eq!(inner.completed_order.get("p1").map(|o| o.len()), Some(2)); - // Survivors keep their FULL text — the valve drops whole entries, it - // never truncates a survivor. - assert_eq!( - inner - .completed - .get("c") - .unwrap() - .text - .as_deref() - .map(str::len), - Some(400) - ); - } - - #[test] - fn completed_cache_valve_keeps_newest_even_if_alone_over_budget() { - // A single result larger than the whole budget is still retained — the - // valve never evicts the entry just inserted (the LLM's immediate - // get_delegation_status must hit). Per-result text is independently - // bounded by COMPLETED_TEXT_CAP. - let mut inner = PendingInner { - completed_cap_bytes: 100, - ..Default::default() - }; - inner.insert_completed("solo", completed_with_text("p1", 500)); - assert!(inner.completed.contains_key("solo")); - assert_eq!(inner.completed_bytes.get("p1").copied(), Some(500)); - } - - #[test] - fn completed_cache_unlimited_when_cap_zero() { - let mut inner = PendingInner::default(); // completed_cap_bytes == 0 - for i in 0..50 { - inner.insert_completed(&format!("t{i}"), completed_with_text("p1", 10_000)); - } - assert_eq!(inner.completed.len(), 50, "cap 0 disables eviction"); - assert_eq!(inner.completed_bytes.get("p1").copied(), Some(500_000)); - } - - #[test] - fn completed_cache_valve_is_per_parent() { - let mut inner = PendingInner { - completed_cap_bytes: 1000, - ..Default::default() - }; - // p1 overflows; p2 stays under its own independent budget. - inner.insert_completed("a1", completed_with_text("p1", 600)); - inner.insert_completed("a2", completed_with_text("p1", 600)); // evicts a1 - inner.insert_completed("b1", completed_with_text("p2", 600)); - assert!(!inner.completed.contains_key("a1")); - assert!(inner.completed.contains_key("a2")); - assert!( - inner.completed.contains_key("b1"), - "p2 must be untouched by p1 overflow" - ); - assert_eq!(inner.completed_bytes.get("p1").copied(), Some(600)); - assert_eq!(inner.completed_bytes.get("p2").copied(), Some(600)); - } - - #[test] - fn drop_completed_for_parent_clears_byte_counter() { - let mut inner = PendingInner::default(); // unlimited; teardown still clears - inner.insert_completed("a", completed_with_text("p1", 100)); - inner.insert_completed("b", completed_with_text("p2", 100)); - inner.drop_completed_for_parent("p1"); - assert!(!inner.completed.contains_key("a")); - assert!(inner.completed.contains_key("b")); - assert_eq!( - inner.completed_bytes.get("p1"), - None, - "byte counter must be cleared on teardown" - ); - assert_eq!(inner.completed_bytes.get("p2").copied(), Some(100)); - } - - #[tokio::test] - async fn lowering_cap_prunes_existing_completed_results() { - let broker = DelegationBroker::new( - Arc::new(MockSpawner::new()) as Arc, - shallow_lookup(), - ); - // Start unlimited and retain several results for one parent. - broker - .set_config(DelegationConfig { - completed_cache_cap_bytes: 0, - ..DelegationConfig::default() - }) - .await; - { - let mut inner = broker.pending.inner.lock().await; - for i in 0..5 { - inner.insert_completed(&format!("t{i}"), completed_with_text("p1", 400)); - } - assert_eq!(inner.completed.len(), 5); - assert_eq!(inner.completed_bytes.get("p1").copied(), Some(2000)); - } - // Lower the cap to 1000 bytes — existing results must be pruned NOW, - // not only on the next completion (which may never arrive). - broker - .set_config(DelegationConfig { - completed_cache_cap_bytes: 1000, - ..DelegationConfig::default() - }) - .await; - let inner = broker.pending.inner.lock().await; - assert!( - inner.completed_bytes.get("p1").copied().unwrap_or(0) <= 1000, - "retained bytes must fit the lowered cap" - ); - assert!( - inner.completed.contains_key("t4"), - "newest result must survive pruning" - ); - assert!( - !inner.completed.contains_key("t0"), - "oldest result must be pruned" - ); - } -} +//! `DelegationBroker` — the coordination unit for multi-agent delegation. +//! +//! Delegation is **asynchronous**: `delegate_to_agent` returns a `task_id` +//! ack as soon as setup finishes; the LLM collects the result later with +//! `get_delegation_status` (optionally long-polling) or stops it with +//! `cancel_delegation`. There is no blocking `oneshot` — a running task is just +//! an entry in the `running` map, and a terminal event migrates it into the +//! `completed` cache (atomically, under one lock) and wakes any long-poll via +//! `result_notify`. +//! +//! Lifecycle of a single task: +//! +//! 1. [`DelegationBroker::start_delegation`] is the broker's entry point. The +//! MCP listener feeds it the LLM-issued `delegate_to_agent` payload. +//! 2. Pre-checks: feature enabled? depth limit ok? Both failures return a +//! terminal report immediately, no child session created. +//! 3. Spawn the child via [`ConnectionSpawner::spawn`]. +//! 4. Send the delegation task as the first prompt via +//! [`ConnectionSpawner::send_prompt_linked_for_delegation`]. The trailing +//! [`DelegationLink`] carries the parent's `tool_use_id` and a +//! broker-internal `call_id` (UUID = `task_id`) — persisted onto the new +//! conversation row so the lifecycle resolver can find it. +//! 5. Register a [`RunningTask`] keyed by `call_id` and return a `Running` ack +//! [`DelegationTaskReport`] (or a terminal report when the child finished +//! during setup / a cancel reached it mid-setup / setup itself failed). +//! 6. Later, a terminal event resolves the task — migrating it `running` → +//! `completed` and tearing the child down: +//! - the lifecycle calling [`DelegationBroker::complete_call`] on +//! `TurnComplete` (happy path), or +//! - a cancel — MCP-side (`notifications/cancelled` → +//! [`DelegationBroker::cancel_by_external_handle`]), child-side +//! ([`DelegationBroker::cancel_by_child_connection`]), parent-side +//! ([`DelegationBroker::cancel_by_parent`] / +//! [`DelegationBroker::cancel_by_parent_turn`]), or the LLM's own +//! [`DelegationBroker::cancel_task_by_id`]. +//! +//! v1 is explicitly one-shot — no session reuse. +//! +//! Result durability: child output is NOT stored in codeg's DB, so the broker +//! caches the completed text in `completed` (parent-scoped, FIFO-capped). Once +//! evicted, [`DelegationBroker::get_task_status`] falls back to the DB for the +//! task's terminal STATUS (via [`ChildStatusLookup`]); the full output is always +//! viewable in the child's own session. +//! +//! Cancellation cascade: when a parent session goes away (user-initiated +//! cancel, parent disconnect), the lifecycle subscriber calls +//! [`DelegationBroker::cancel_by_parent`] which fans out cancel + disconnect +//! to every running child of that parent. A normal `end_turn` does NOT cancel +//! children — they keep running in the background (the whole point of async). + +use std::collections::{BTreeMap, HashMap, HashSet, VecDeque}; +use std::sync::atomic::{AtomicBool, Ordering}; +use std::sync::Arc; +use std::time::{Duration, Instant}; + +use async_trait::async_trait; +use tokio::sync::{Mutex, Notify}; + +use crate::acp::delegation::event_emitter::{DelegationEventEmitter, NoopEventEmitter}; +use crate::acp::delegation::live_reply::{ChildLiveReplyLookup, NoopChildLiveReplyLookup}; +use crate::acp::delegation::meta_writer::{ + build_delegation_meta, is_synthetic_parent_tool_use_id, DelegationMetaWriter, NoopMetaWriter, +}; +use crate::acp::delegation::spawner::{ConnectionSpawner, DelegationLink}; +use crate::acp::delegation::types::{ + AgentDelegationDefaults, BlockedKind, BlockedOn, DelegationError, DelegationOutcome, + DelegationRequest, DelegationTaskReport, TaskStatus, +}; +use crate::acp::types::DelegationResultSummary; +use crate::models::AgentType; + +/// Default per-parent byte budget for cached completed-task result text. The +/// completed-cache lets `get_delegation_status` / `cancel_delegation` return a +/// finished task's result after the lifecycle resolved it; once a parent's +/// retained result text exceeds this budget the OLDEST results are FIFO-evicted +/// (evicted tasks fall back to the DB status lookup, which carries status only). +/// This is the seed value baked into `DelegationConfig::default()`; the live +/// value is user-configurable from the settings page (in MB) and `0` disables +/// eviction entirely. See `PendingInner::completed_cap_bytes`. +const DEFAULT_COMPLETED_CACHE_CAP_BYTES: usize = 512 * 1024 * 1024; + +/// Per-result cap on cached completed text. The full child output always lives +/// in the child's own session (viewable via the frontend's child-session +/// sheet); this only bounds the broker's in-memory copy of a SINGLE result. +/// Because it is far below the per-parent byte budget +/// (`DEFAULT_COMPLETED_CACHE_CAP_BYTES`), the newest result always fits and is +/// never the eviction victim in `insert_completed`. +const COMPLETED_TEXT_CAP: usize = 256 * 1024; + +/// Cap on the `task_preview` carried by the `DelegationStarted` event and the +/// parent-card meta writes. The full task text lives in the MCP call (and, on +/// most hosts, in the parent tool call's own `raw_input`); the preview only +/// has to label the delegation card, so it shares the status-preview budget +/// rather than the multi-KiB result cap. +const TASK_PREVIEW_CAP: usize = 2 * 1024; + +/// Cap on the inline `text_preview` carried by the `DelegationCompleted` event +/// and the terminal meta, so the parent card can render the result inline +/// without re-fetching the child session. +const STATUS_PREVIEW_CAP: usize = 2 * 1024; + +/// Lookup the `parent_id` for a conversation. Abstracted so the broker can be +/// unit-tested against an in-memory chain without touching SeaORM. +#[async_trait] +pub trait ConversationDepthLookup: Send + Sync { + async fn parent_of(&self, conversation_id: i32) -> Result, DelegationError>; +} + +/// Status-level facts the broker recovers from a child conversation row when a +/// task's in-memory completed-cache entry was evicted. Carries NO result text — +/// child output isn't stored in codeg's DB; the full result lives in the +/// child's own session (viewable via the frontend's child-session sheet). +#[derive(Debug, Clone)] +pub struct ChildStatusRecord { + pub child_conversation_id: i32, + pub status: TaskStatus, + pub agent_type: AgentType, + /// The parent conversation id this child was spawned under. Used to scope + /// the DB fallback to the calling parent so one parent can't read another's + /// task by guessing a UUID. + pub parent_id: Option, +} + +/// DB fallback for `get_delegation_status` / `cancel_delegation` once a task's +/// result has aged out of the broker's in-memory completed-cache. Abstracted +/// so broker unit tests can run without SeaORM; production wires +/// [`DbChildStatusLookup`] via [`DelegationBroker::with_status_lookup`]. +#[async_trait] +pub trait ChildStatusLookup: Send + Sync { + async fn find_by_call_id(&self, call_id: &str) -> Option; +} + +/// Default lookup — always "unknown". Used by `DelegationBroker::new` / +/// `with_writers` (tests that don't exercise the DB-fallback path); production +/// replaces it via `with_status_lookup`. +#[derive(Default, Clone)] +pub struct NoopChildStatusLookup; + +#[async_trait] +impl ChildStatusLookup for NoopChildStatusLookup { + async fn find_by_call_id(&self, _call_id: &str) -> Option { + None + } +} + +#[derive(Debug, Clone)] +pub struct DelegationConfig { + pub enabled: bool, + /// Max chain depth a *new* delegation may exist at. With `depth_limit = 2` + /// the chain root → child → grandchild is allowed; the grandchild trying + /// to spawn a great-grandchild is rejected. See spec §5. + pub depth_limit: u32, + /// Per-agent overrides applied when spawning a delegation child. Keyed by + /// the target `agent_type`; missing entries mean "no override." Forwarded + /// to `ConnectionSpawner::spawn` as `preferred_mode_id` / + /// `preferred_config_values`. + pub agent_defaults: BTreeMap, + /// Per-parent byte budget for cached completed-task result text. `0` + /// disables eviction (unlimited). Surfaced from the settings page in MB and + /// converted to bytes in `into_broker_config`. Pushed into the pending-calls + /// bucket by `set_config` so `insert_completed` reads it lock-free. + pub completed_cache_cap_bytes: usize, +} + +impl Default for DelegationConfig { + fn default() -> Self { + Self { + enabled: false, + depth_limit: 1, + agent_defaults: BTreeMap::new(), + completed_cache_cap_bytes: DEFAULT_COMPLETED_CACHE_CAP_BYTES, + } + } +} + +/// A delegation task running in the background after `start_delegation` +/// returned its `Running` ack. The async redesign drops the parked +/// `oneshot::Sender` the old `PendingCall` carried: the parent's +/// `delegate_to_agent` no longer blocks on a channel, so there is nothing to +/// signal. A terminal event instead migrates the entry into `completed` (same +/// lock) and wakes any `get_delegation_status` long-poll via the broker's +/// `result_notify`. +struct RunningTask { + child_connection_id: String, + child_conversation_id: i32, + parent_connection_id: String, + parent_tool_use_id: String, + /// Target agent — surfaced in status reports. + agent_type: AgentType, + /// Bounded preview of the delegated task text ([`TASK_PREVIEW_CAP`]). + /// Carried so TERMINAL meta writes can keep labeling the parent card — + /// meta is replace-wholesale on the ToolCallState, so a terminal write + /// that dropped the task text would erase what the running write supplied. + task_preview: String, + /// The broker-minted task id — duplicates this entry's key in `running` + /// because the cancel/teardown paths hand around the drained + /// `RunningTask` by value without its map key. + task_id: String, + /// MCP-side opaque handle minted by the companion per `tools/call`. The + /// listener forwards it through `DelegationRequest`; we keep it here so + /// `cancel_by_external_handle` can find the entry. `None` for delegations + /// that didn't come through MCP (tests, future internal callers). + external_handle: Option, + /// When the child started running (after `send_prompt` succeeded). Used to + /// compute a real `duration_ms` at terminal time. + started_at: Instant, + /// The last blocking prompt a status query reported to the parent, and when. + /// Makes "the block I told you about" distinguishable from "a NEW block", + /// which is what stops a `wait_ms: 0` poll from returning instantly forever + /// once a child parks on a permission (#447): the first observation + /// returns, a re-poll on the same prompt goes back to waiting, and a second + /// prompt returns again. + /// + /// The timestamp is the safety valve. Marking a block reported is not proof + /// the parent RECEIVED it — the report still has to cross the listener, the + /// companion's stdout and the agent CLI, and an MCP `notifications/cancelled` + /// or a client-side call abort discards it silently. Without the valve that + /// lost report would be the only one ever offered, re-creating the exact + /// stall this fixes. So the same unanswered prompt becomes reportable again + /// after [`BLOCK_RESURFACE_INTERVAL`]. + last_surfaced_block: Option, +} + +/// See [`RunningTask::last_surfaced_block`]. +struct SurfacedBlock { + request_id: String, + at: Instant, +} + +/// A terminal delegation result retained so `get_delegation_status` / +/// `cancel_delegation` can answer after the lifecycle resolved the task. +/// Parent-scoped, FIFO-evicted once the parent's retained result text exceeds +/// `PendingInner::completed_cap_bytes`, and dropped wholesale when the parent +/// connection tears down. +#[derive(Clone)] +struct CompletedTask { + parent_connection_id: String, + child_conversation_id: i32, + agent_type: AgentType, + status: TaskStatus, + /// Result text for `Completed` (capped at [`COMPLETED_TEXT_CAP`]). `None` + /// for failures/cancels. + text: Option, + error_code: Option, + message: Option, + duration_ms: u64, +} + +#[derive(Default)] +struct PendingCalls { + inner: Mutex, +} + +/// Everything guarded by the single pending-calls mutex. Co-locating the parked +/// calls with the early-terminal bookkeeping under ONE lock is what makes the +/// terminal-vs-registration race safe: a terminal event for a delegation that +/// is still mid-setup (its `handle_request` hasn't parked the [`PendingCall`] +/// yet) and the matching registration are serialized on this lock, so the +/// terminal event either finds the parked entry (resolves via `tx`) or buffers +/// its outcome (and `handle_request` drains it the instant it parks) — never +/// both, never neither. Without this, a terminal that fires in the spawn→park +/// window would no-op the resolver and then strand the parked `rx.await`. +/// +/// Both CHILD-terminal pre-park resolvers are covered, because either can win +/// the race against the parent `write_meta` await between `send_prompt` and the +/// park: +/// * `complete_call` — a fast/empty turn's `TurnComplete` (the prompt is only +/// *enqueued* by `send_prompt`; the child loop emits `TurnComplete` +/// independently). Keyed by `call_id`. +/// * `cancel_by_child_connection` — a freshly-spawned child connection dying +/// before its first prompt is answered. Keyed by `child_connection_id`. +/// +/// Parent-side cancels (`cancel_by_parent` / `cancel_by_parent_turn`) are +/// covered symmetrically by the `inflight` registry: `handle_request` registers +/// each setup at entry, and `mark_inflight_canceled_for_parent` runs in the SAME +/// lock acquisition that drains the parked `calls`. A parent cancel landing +/// while a child is still mid-setup therefore flags the in-flight record, and +/// `handle_request` observes the flag at its next checkpoint (or atomically at +/// park) and tears the child down itself — it is no longer left to the child's +/// own terminal / connection-teardown cascade. +/// +/// The reservation records the `child_connection_id` each resolver gates on; +/// `handle_request` drains both buffers at park. +#[derive(Default)] +struct PendingInner { + /// Tasks running in the background after their `Running` ack, keyed by + /// broker `call_id` (= `task_id`). A terminal event migrates an entry from + /// here into `completed` under THIS lock (atomic `running` → `completed` + /// transition), so a concurrent `get_delegation_status` never observes a + /// task as neither running nor completed. + running: HashMap, + /// Terminal results retained for `get_delegation_status` / `cancel_delegation`, + /// keyed by `task_id`. Bounded by the per-parent byte valve + /// (`completed_cap_bytes` over `completed_bytes`, FIFO-evicted via + /// `completed_order`) and dropped per-parent on connection teardown. + /// Evicted/unknown tasks fall back to the DB status lookup. + completed: HashMap, + /// Per-parent FIFO index over `completed` for byte-valve eviction and + /// per-parent teardown. Keyed by `parent_connection_id`; each deque holds + /// that parent's completed `task_id`s oldest-first. + completed_order: HashMap>, + /// Per-parent running total of retained completed result-text bytes (the + /// `CompletedTask::text` lengths). Drives the `completed_cap_bytes` valve in + /// `insert_completed`; kept in sync on insert/evict and cleared per-parent + /// on teardown. + completed_bytes: HashMap, + /// Per-parent byte budget for retained completed result text. `0` = + /// unlimited (no eviction). Seeded by `set_config` from the live + /// `DelegationConfig` (default until then: `0`, but `set_config` always runs + /// at startup via `apply_persisted_config`). Read lock-free by + /// `insert_completed`, which already holds THIS mutex — so the cap is + /// consulted WITHOUT nesting the `config` lock under the pending lock. + completed_cap_bytes: usize, + /// In-setup delegations (spawned + id minted, not yet parked), mapping + /// `call_id` → `child_connection_id`. Gating the early buffers on membership + /// here distinguishes a genuine pre-registration race (still reserved → + /// buffer) from the normal post-resolution teardown that fires on every + /// completion (no longer reserved → ignore). Removed at park / on the + /// send-failure path. + setups: HashMap, + /// Completion outcomes captured by a `TurnComplete` that beat registration + /// (gated by `setups`), keyed by `call_id`. Each carries the `seq` arrival + /// stamp taken when it buffered, so the park can order it against a racing + /// parent cancel (first-terminal-wins). Drained at park. + early_completes: HashMap, + /// Cancel reasons captured by a child failure that beat registration (gated + /// by `setups`), keyed by `child_connection_id`. The value pairs the `seq` + /// arrival stamp (for the park's first-terminal-wins ordering against a + /// racing parent cancel) with the pre-computed `Canceled { reason }` text + /// (same wording the parked `cancel_by_child_connection` path produces); + /// `handle_request` rebuilds the full outcome at park with the real + /// `child_conversation_id` (which the resolver, finding no entry, lacked). + early_cancels: HashMap, + /// In-flight `handle_request` setups, keyed by a unique per-call id and + /// registered at entry (BEFORE the claim poll, so the whole claim→park + /// window is covered). This is the parent-cancel counterpart to `setups`: + /// `setups` lets a *child* terminal reach a not-yet-parked delegation, + /// while `inflight` lets a *parent* cancel reach one. `cancel_by_parent*` + /// flags every entry it owns (`mark_inflight_canceled_for_parent`); + /// `handle_request` consults the flag after claim, after spawn, and + /// atomically at park, tearing the spawned child down itself when set. + /// Removed at park and on every early-return (no Drop guard — see + /// `register_inflight`). + inflight: HashMap, + /// Monotonic arrival clock (see `tick`). Hands out the unique `inflight` + /// keys AND the arrival stamps on buffered child terminals / parent cancels, + /// so the park can resolve a setup-window race by true first-terminal-wins + /// order. Keys and stamps share this sequence but are never cross-compared + /// (keys match by identity, stamps only by `<` against other stamps). + seq: u64, +} + +/// One in-flight `handle_request` setup tracked for parent-cancel coverage. +struct InflightSetup { + parent_connection_id: String, + /// `Some(stamp)` once a parent cancel lands while this delegation is + /// mid-setup (spawned / sending, not yet parked), where `stamp` is the `seq` + /// arrival-clock value at that moment. First-write-wins and never cleared, + /// so a cancel can't be lost between `handle_request`'s checkpoints, and its + /// stamp lets the park order it against a racing child terminal. + canceled_at: Option, +} + +impl PendingInner { + /// Mark a delegation as setting-up (spawned + id minted, not yet parked) so + /// a terminal event racing the park is buffered rather than dropped. + /// + /// No cap: a reservation lives only for the brief spawn→park window and is + /// always released by `unreserve` on every `handle_request` exit (park, or + /// the send-failure path), so `setups` is bounded by the count of + /// concurrently-in-setup delegations — it never accumulates stale entries. + /// A cap here would be actively unsafe: every reservation is live, so + /// evicting one to make room would drop a real in-flight delegation's race + /// guard and reopen the very hang this machinery exists to prevent. + fn reserve(&mut self, call_id: &str, child_connection_id: &str) { + self.setups + .insert(call_id.to_string(), child_connection_id.to_string()); + } + + /// Release a delegation's reservation and discard any un-drained buffered + /// terminal — called once the entry is parked (the buffers were already + /// drained, so the removals are no-ops then) or when setup errors out + /// (discarding a buffer no `handle_request` will pick up). + fn unreserve(&mut self, call_id: &str, child_connection_id: &str) { + self.setups.remove(call_id); + self.early_completes.remove(call_id); + self.early_cancels.remove(child_connection_id); + } + + /// Whether a child connection belongs to a still-in-setup delegation. O(n) + /// over `setups`, but n is the (tiny) count of concurrently-in-setup + /// delegations. + fn is_child_reserved(&self, child_connection_id: &str) -> bool { + self.setups + .values() + .any(|child| child == child_connection_id) + } + + /// Buffer a completion for a still-reserved delegation, stamped with the + /// current arrival clock so the park can order it against a racing parent + /// cancel. No-op when the `call_id` isn't reserved (already resolved by + /// another terminal path), so the buffer only ever holds genuine + /// pre-registration races. + fn buffer_early_complete(&mut self, call_id: &str, outcome: DelegationOutcome) { + if self.setups.contains_key(call_id) { + let stamp = self.tick(); + self.early_completes + .insert(call_id.to_string(), (stamp, outcome)); + } + } + + /// Buffer a child failure for a still-reserved delegation, stamped with the + /// current arrival clock so the park can order it against a racing parent + /// cancel. No-op when the child isn't reserved (normal post-resolution + /// teardown). Stores the pre-computed cancel reason so the park rebuilds the + /// same wording the parked `cancel_by_child_connection` path produces. + fn buffer_child_failure(&mut self, child_connection_id: &str, detail: Option) { + if self.is_child_reserved(child_connection_id) { + let stamp = self.tick(); + self.early_cancels.insert( + child_connection_id.to_string(), + (stamp, child_canceled_reason(detail.as_deref())), + ); + } + } + + /// Drain a buffered completion with its arrival stamp (by `call_id`) — used + /// by `handle_request` at park. + fn take_early_complete(&mut self, call_id: &str) -> Option<(u64, DelegationOutcome)> { + self.early_completes.remove(call_id) + } + + /// Drain a buffered cancel reason with its arrival stamp (by + /// `child_connection_id`) — used by `handle_request` at park. + fn take_early_cancel(&mut self, child_connection_id: &str) -> Option<(u64, String)> { + self.early_cancels.remove(child_connection_id) + } + + /// Advance the monotonic arrival clock, returning the pre-increment value. + /// Strictly increasing (wraps only after 2^64 calls — unreachable), so two + /// events stamped under this lock always compare in their true arrival + /// order. Backs both `inflight` keys and terminal/cancel arrival stamps; the + /// two uses never cross-compare (keys match by identity, stamps by `<`). + fn tick(&mut self) -> u64 { + let v = self.seq; + self.seq = self.seq.wrapping_add(1); + v + } + + /// Register an in-flight setup at `handle_request` entry, returning its + /// unique id. The caller MUST `deregister_inflight` on every exit path + /// (each early-return, and at park). There is deliberately NO Drop guard: + /// the park hand-off — `calls.insert` followed by `deregister_inflight` — + /// has to be atomic under this lock so a concurrent parent cancel sees the + /// entry in exactly one of `inflight` or `calls`, and a guard firing after + /// the lock releases would reopen that window. + fn register_inflight(&mut self, parent_connection_id: &str) -> u64 { + let id = self.tick(); + self.inflight.insert( + id, + InflightSetup { + parent_connection_id: parent_connection_id.to_string(), + canceled_at: None, + }, + ); + id + } + + /// Drop an in-flight setup record (idempotent). + fn deregister_inflight(&mut self, id: u64) { + self.inflight.remove(&id); + } + + /// Whether a parent cancel flagged this in-flight setup. False once the + /// record is gone (already parked / deregistered). Used by the pre-spawn / + /// post-spawn checkpoints, which only need the boolean. + fn inflight_canceled(&self, id: u64) -> bool { + self.inflight + .get(&id) + .map(|s| s.canceled_at.is_some()) + .unwrap_or(false) + } + + /// Arrival stamp of the parent cancel that flagged this in-flight setup, if + /// any (`None` when not canceled, or the record is already gone). Used at + /// park to order the cancel against a buffered child terminal. + fn inflight_canceled_at(&self, id: u64) -> Option { + self.inflight.get(&id).and_then(|s| s.canceled_at) + } + + /// Flag every in-flight setup owned by `parent_connection_id` as canceled, + /// stamping each with one shared arrival-clock value (this cancel is a + /// single event). First-write-wins per setup, so a later cancel can't push + /// an earlier one's stamp forward. Called from `drain_for_parent_cancel` in + /// the SAME lock acquisition that drains the parked `calls`, so each of the + /// parent's delegations is caught either here (still in-flight → flagged; + /// `handle_request` tears its child down at the next checkpoint) or by the + /// parked-call drain (already parked) — never neither. + fn mark_inflight_canceled_for_parent(&mut self, parent_connection_id: &str) { + let stamp = self.tick(); + for setup in self.inflight.values_mut() { + if setup.parent_connection_id == parent_connection_id && setup.canceled_at.is_none() { + setup.canceled_at = Some(stamp); + } + } + } + + /// Insert a terminal result into the completed-cache, then FIFO-evict this + /// parent's OLDEST results until its retained result-text bytes fit + /// `completed_cap_bytes` (`0` = unlimited). Evicted tasks fall back to the + /// DB status lookup (status only — child text lives in the child session). + /// The just-inserted entry is never the victim: a single result is capped + /// at [`COMPLETED_TEXT_CAP`] (256 KiB), far below any MB-scale budget, so + /// the newest result always survives for the LLM's immediate + /// `get_delegation_status`. The caller does the atomic `running.remove` + + /// this insert under one lock, then notifies long-poll waiters AFTER + /// releasing the lock. + fn insert_completed(&mut self, call_id: &str, task: CompletedTask) { + let parent = task.parent_connection_id.clone(); + let task_bytes = task.text.as_ref().map_or(0, |t| t.len()); + self.completed.insert(call_id.to_string(), task); + *self.completed_bytes.entry(parent.clone()).or_insert(0) += task_bytes; + self.completed_order + .entry(parent.clone()) + .or_default() + .push_back(call_id.to_string()); + self.evict_completed_over_cap(&parent); + } + + /// Evict `parent`'s OLDEST completed results until its retained result-text + /// bytes fit `completed_cap_bytes` (`0` = unlimited). Evicted tasks fall + /// back to the DB status lookup (status only — child text lives in the child + /// session). The newest entry is never evicted: a single result is capped at + /// [`COMPLETED_TEXT_CAP`] (256 KiB), far below any MB-scale budget, so the + /// LLM's immediate `get_delegation_status` always hits. + fn evict_completed_over_cap(&mut self, parent: &str) { + let cap = self.completed_cap_bytes; + if cap == 0 { + return; + } + loop { + if self.completed_bytes.get(parent).copied().unwrap_or(0) <= cap { + break; + } + let evicted = match self.completed_order.get_mut(parent) { + Some(order) if order.len() > 1 => order.pop_front(), + _ => None, + }; + let Some(evicted) = evicted else { + break; + }; + if let Some(removed) = self.completed.remove(&evicted) { + let freed = removed.text.as_ref().map_or(0, |t| t.len()); + if let Some(slot) = self.completed_bytes.get_mut(parent) { + *slot = slot.saturating_sub(freed); + } + } + } + } + + /// Re-apply the current `completed_cap_bytes` to EVERY parent. Called by + /// `set_config` when the cap may have been LOWERED at runtime, so + /// already-retained results are pruned promptly — insert-time eviction alone + /// would otherwise strand them until a parent's next completion (which may + /// never arrive). + fn enforce_completed_cap_all_parents(&mut self) { + if self.completed_cap_bytes == 0 { + return; + } + let parents: Vec = self.completed_bytes.keys().cloned().collect(); + for parent in parents { + self.evict_completed_over_cap(&parent); + } + } + + /// Forget every completed result for a parent. Called on connection + /// teardown (the parent is gone — nothing left to query). A turn cancel + /// deliberately does NOT call this: the connection stays alive and the LLM + /// may still query its just-canceled tasks. + fn drop_completed_for_parent(&mut self, parent_connection_id: &str) { + self.completed_bytes.remove(parent_connection_id); + if let Some(ids) = self.completed_order.remove(parent_connection_id) { + for id in ids { + self.completed.remove(&id); + } + } + } +} + +/// Cap result text retained in the completed-cache. The full output always +/// lives in the child session; this only bounds the broker's copy. +fn cap_completed_text(text: &str) -> String { + truncate_on_char_boundary(text, COMPLETED_TEXT_CAP) +} + +/// Build the bounded inline preview carried by the `DelegationCompleted` event +/// and terminal meta. `None` for empty text. +fn build_text_preview(text: &str) -> Option { + if text.trim().is_empty() { + return None; + } + Some(truncate_on_char_boundary(text, STATUS_PREVIEW_CAP)) +} + +/// Truncate `s` so the RESULT (including the appended ellipsis) is at most `cap` +/// bytes, cut on a UTF-8 char boundary. Reserving the ellipsis bytes keeps the +/// output within the advertised cap rather than `cap + 3`. +fn truncate_on_char_boundary(s: &str, cap: usize) -> String { + if s.len() <= cap { + return s.to_string(); + } + const ELLIPSIS: &str = "…"; + // Leave room for the ellipsis; clamp at 0 for pathologically small caps. + let budget = cap.saturating_sub(ELLIPSIS.len()); + let mut end = budget.min(s.len()); + while end > 0 && !s.is_char_boundary(end) { + end -= 1; + } + format!("{}{ELLIPSIS}", &s[..end]) +} + +/// Derive the completed-cache fields (status / text / error_code / message) +/// from a resolved [`DelegationOutcome`]. `Canceled`-coded errors map to +/// [`TaskStatus::Canceled`]; every other error maps to [`TaskStatus::Failed`]. +fn terminal_fields( + outcome: &DelegationOutcome, +) -> (TaskStatus, Option, Option, Option) { + match outcome { + DelegationOutcome::Ok(ok) => ( + TaskStatus::Completed, + Some(cap_completed_text(&ok.text)), + None, + None, + ), + DelegationOutcome::Err { code, message, .. } => { + let status = if code == "canceled" { + TaskStatus::Canceled + } else { + TaskStatus::Failed + }; + (status, None, Some(code.clone()), Some(message.clone())) + } + } +} + +/// Build a [`CompletedTask`] from a resolved outcome for the completed-cache. +fn build_completed( + parent_connection_id: &str, + child_conversation_id: i32, + agent_type: AgentType, + duration_ms: u64, + outcome: &DelegationOutcome, +) -> CompletedTask { + let (status, text, error_code, message) = terminal_fields(outcome); + CompletedTask { + parent_connection_id: parent_connection_id.to_string(), + child_conversation_id, + agent_type, + status, + text, + error_code, + message, + duration_ms, + } +} + +/// A `canceled`-coded [`DelegationOutcome`] carrying the child conversation id. +fn canceled_outcome(child_conversation_id: i32, reason: &str) -> DelegationOutcome { + DelegationOutcome::from_err( + DelegationError::Canceled { + reason: reason.to_string(), + }, + Some(child_conversation_id), + ) +} + +/// Remove `keys` from `running`, recording each as a `Canceled` completed entry +/// (so a `get_delegation_status` still answers) and returning the drained tasks +/// — each paired with the `duration_ms` captured at this drain point — for I/O +/// teardown. MUST be called with the pending lock held so the running → +/// completed migration is atomic. +/// +/// The duration is captured ONCE here and returned so the slow teardown +/// (parent-card meta, report) reuses the exact value recorded into the +/// completed-cache, rather than recomputing `started_at.elapsed()` later — which +/// would inflate it for the backgrounded `cancel_by_parent_turn` teardown and +/// disagree with the `get_delegation_status` / `cancel_delegation` cards. +fn drain_and_record_canceled( + inner: &mut PendingInner, + keys: Vec, + reason: &str, +) -> Vec<(RunningTask, u64)> { + let mut out = Vec::with_capacity(keys.len()); + for k in keys { + let task = inner.running.remove(&k).expect("key just observed"); + let outcome = canceled_outcome(task.child_conversation_id, reason); + let duration_ms = task.started_at.elapsed().as_millis() as u64; + inner.insert_completed( + &k, + build_completed( + &task.parent_connection_id, + task.child_conversation_id, + task.agent_type, + duration_ms, + &outcome, + ), + ); + out.push((task, duration_ms)); + } + out +} + +/// Project a `DelegationOutcome` + broker-measured `duration_ms` onto the +/// wire-stable `DelegationResultSummary` carried by `DelegationCompleted`. +/// Keeps the mapping (and the bounded `text_preview`) in one place. +fn outcome_to_summary(outcome: &DelegationOutcome, duration_ms: u64) -> DelegationResultSummary { + match outcome { + DelegationOutcome::Ok(ok) => DelegationResultSummary::Ok { + duration_ms, + text_preview: build_text_preview(&ok.text), + }, + DelegationOutcome::Err { code, .. } => DelegationResultSummary::Err { + error_code: code.clone(), + }, + } +} + +/// Project a resolved outcome onto a terminal [`DelegationTaskReport`] (used by +/// the setup-window terminal dispositions and the test shim). +fn report_from_outcome( + task_id: Option, + agent_type: Option, + outcome: &DelegationOutcome, + duration_ms: Option, +) -> DelegationTaskReport { + let (status, text, error_code, message) = terminal_fields(outcome); + let child_conversation_id = match outcome { + DelegationOutcome::Ok(ok) => Some(ok.child_conversation_id), + DelegationOutcome::Err { + child_conversation_id, + .. + } => *child_conversation_id, + }; + DelegationTaskReport { + task_id, + status, + child_conversation_id, + agent_type, + text, + error_code, + message, + duration_ms, + // Terminal by construction — nothing is waiting on the user anymore. + blocked_on: None, + } +} + +/// Build a `Failed`/`Canceled` report for a setup error (no task id — setup +/// failed before/around registration, so the LLM has no task to track). +fn report_err( + agent_type: AgentType, + err: DelegationError, + child_conversation_id: Option, +) -> DelegationTaskReport { + let outcome = DelegationOutcome::from_err(err, child_conversation_id); + report_from_outcome(None, Some(agent_type), &outcome, None) +} + +/// The `Running` ack returned by `start_delegation` for a backgrounded task. +fn running_ack( + call_id: String, + child_conversation_id: i32, + agent_type: AgentType, +) -> DelegationTaskReport { + // Embed the literal task_id in the message so it survives clients that only + // surface the MCP `content` text (not `structuredContent`) — without it the + // LLM couldn't call get_delegation_status / cancel_delegation. + let message = format!( + "Delegation successful. task_id={call_id}. Call get_delegation_status \ + with this id in the task_ids array (optionally wait_ms) to collect the \ + result, or cancel_delegation to stop it." + ); + DelegationTaskReport { + task_id: Some(call_id), + status: TaskStatus::Running, + child_conversation_id: Some(child_conversation_id), + agent_type: Some(agent_type), + text: None, + error_code: None, + message: Some(message), + duration_ms: None, + blocked_on: None, + } +} + +/// How long [`DelegationBroker::get_task_status`] may block before returning the +/// current (possibly still-running) snapshot. Derived by the listener from the +/// MCP tool's `wait_ms`: omitted → [`Immediate`], an explicit `0` → [`Infinite`], +/// any positive value → [`Bounded`] (clamped to the listener's hard ceiling). +/// +/// [`Immediate`]: StatusWait::Immediate +/// [`Bounded`]: StatusWait::Bounded +/// [`Infinite`]: StatusWait::Infinite +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +pub enum StatusWait { + /// Return the current snapshot right away — the default poll. + Immediate, + /// Block up to this many milliseconds, then return whatever snapshot we have + /// (the child keeps running past the deadline; the caller re-issues to wait + /// more). + Bounded(u64), + /// Block until the task reaches a terminal state — never time out. Lets a + /// long-running child be awaited in a single call. A parent disconnect or + /// cancel also drives the task terminal (and fires the completion signal), + /// so this never outlives the task itself. + Infinite, +} + +/// How long an already-reported blocking prompt stays suppressed before a +/// status long-poll will surface it again. Two jobs: it keeps a `wait_ms: 0` +/// caller from spinning on a block it has already been told about, and it +/// bounds the damage when a report is generated but never delivered (see +/// [`RunningTask::last_surfaced_block`]) — a lost report costs a delayed notice +/// instead of a permanent stall. Long relative to a human noticing a prompt, +/// short relative to walking away from the machine. +const BLOCK_RESURFACE_INTERVAL: Duration = Duration::from_secs(300); + +/// Second line of a blocked running report's message. The frontend anchors on +/// this exact prefix to keep recognizing the poll as "running" on hosts that +/// persist only the `CallToolResult` content text — see `textRunningStatus` in +/// `src/lib/delegation-status.ts`. Backend protocol string, never localized. +const BLOCKED_LINE_PREFIX: &str = "Awaiting your decision:"; + +/// Mark a running report as parked on a user decision: set the structured +/// `blocked_on` and replace the bare `"Running."` message with a two-line +/// version naming what needs answering. +/// +/// The note goes on its OWN line, for the same reason the live-reply hint does: +/// content-only hosts recognize a still-running poll by the standalone first +/// line `"Running."`, so a *completed* result whose text happens to start with +/// "Running. …" can never be misread as running. +fn attach_blocked(report: &mut DelegationTaskReport, blocked: BlockedOn) { + let what = match (&blocked.kind, blocked.title.as_deref()) { + (_, Some(title)) => title.to_string(), + (BlockedKind::Permission, None) => "a tool permission".to_string(), + (BlockedKind::Question, None) => "a question".to_string(), + (BlockedKind::PlanApproval, None) => "a plan approval".to_string(), + }; + // The third line is guidance for the orchestrating LLM, in the same spirit + // as `running_ack`'s "call get_delegation_status with this id". Keep it in + // step with the tool description in `tool_schema.json`. + report.message = Some(format!( + "Running.\n{BLOCKED_LINE_PREFIX} {what}\nThe sub-agent is parked until \ + a human answers in Codeg — it is not making progress. Tell the user, \ + then wait again." + )); + report.blocked_on = Some(blocked); +} + +/// Status report for a still-running task. +fn running_report(task_id: &str, task: &RunningTask) -> DelegationTaskReport { + DelegationTaskReport { + task_id: Some(task_id.to_string()), + status: TaskStatus::Running, + child_conversation_id: Some(task.child_conversation_id), + agent_type: Some(task.agent_type), + text: None, + error_code: None, + // Bare baseline; `get_task_status` upgrades this to a two-line + // "Running.\nLatest sub-agent reply: …" when the child has live output. + message: Some("Running.".to_string()), + duration_ms: None, + blocked_on: None, + } +} + +/// Status report from a cached completed result. +fn completed_report(task_id: &str, c: &CompletedTask) -> DelegationTaskReport { + DelegationTaskReport { + task_id: Some(task_id.to_string()), + status: c.status, + child_conversation_id: Some(c.child_conversation_id), + agent_type: Some(c.agent_type), + text: c.text.clone(), + error_code: c.error_code.clone(), + message: c.message.clone(), + duration_ms: Some(c.duration_ms), + blocked_on: None, + } +} + +/// Status report when a task id isn't known to the caller (never existed, +/// owned by a different parent, or evicted with no DB record). +fn unknown_report(task_id: &str) -> DelegationTaskReport { + DelegationTaskReport { + task_id: Some(task_id.to_string()), + status: TaskStatus::Unknown, + child_conversation_id: None, + agent_type: None, + text: None, + error_code: None, + message: Some( + "Unknown task id — it never existed, isn't owned by this session, \ + or its result was evicted with no stored record." + .to_string(), + ), + duration_ms: None, + blocked_on: None, + } +} + +/// Status report recovered from the DB after the in-memory result was evicted. +/// Carries status only — the full output lives in the child session. +fn db_report(task_id: &str, rec: &ChildStatusRecord) -> DelegationTaskReport { + DelegationTaskReport { + task_id: Some(task_id.to_string()), + status: rec.status, + child_conversation_id: Some(rec.child_conversation_id), + agent_type: Some(rec.agent_type), + text: None, + error_code: (rec.status == TaskStatus::Canceled).then(|| "canceled".to_string()), + message: Some(format!( + "Result no longer cached; open child session {} for the full output.", + rec.child_conversation_id + )), + duration_ms: None, + blocked_on: None, + } +} + +/// What [`DelegationBroker::claim_new_blocks`] decided for one status pass. +#[derive(Default)] +struct ClaimedBlocks { + /// At least one blocking prompt is reportable now — the wait should return. + any_claimed: bool, + /// Earliest moment a currently-suppressed prompt becomes reportable again. + /// Bounds how long an otherwise-unbounded park may sleep, so the + /// resurface valve actually fires instead of waiting on a notify that will + /// never come (a blocked child emits nothing further on its own). + retry_at: Option, +} + +/// Per-id classification captured under the pending lock during a (possibly +/// batched) status query. The async resolution that can't run under the lock — +/// `attach_live_reply` (a different lock) for a running task, `status_from_db` +/// (a DB round-trip) for one not in memory — is deferred to `assemble_reports` +/// AFTER the lock is released, so a status query never nests the pending lock +/// inside another await. This is the same lock-ordering the single-task path +/// has always used; batching just captures it per id. +enum StatusClass { + /// Terminal/owned-cached, or a cross-parent `unknown` — the report is final. + Settled(DelegationTaskReport), + /// Running and owned — the bare running snapshot plus its child connection + /// id, so `assemble_reports` can attach the latest live reply out of lock. + Running { + report: DelegationTaskReport, + child_connection_id: String, + }, + /// Neither running nor completed in memory — resolve via the DB fallback in + /// `assemble_reports`. A not-in-memory id is, for wait purposes, already + /// settled: it can never transition back to running, so a batch wait need + /// not park on it (and must not hit the DB on every wake). + NotInMemory, +} + +/// Classify one task id against the in-memory maps while the pending lock is +/// held. Mirrors the single-task resolution order — completed cache (parent +/// scoped) → running set (parent scoped) → not-in-memory — and yields a +/// cross-parent hit as `unknown` so a task owned by another parent never leaks. +fn classify_locked(inner: &PendingInner, parent_connection_id: &str, task_id: &str) -> StatusClass { + if let Some(c) = inner.completed.get(task_id) { + if c.parent_connection_id == parent_connection_id { + return StatusClass::Settled(completed_report(task_id, c)); + } + return StatusClass::Settled(unknown_report(task_id)); + } + match inner.running.get(task_id) { + Some(r) if r.parent_connection_id == parent_connection_id => StatusClass::Running { + report: running_report(task_id, r), + child_connection_id: r.child_connection_id.clone(), + }, + Some(_) => StatusClass::Settled(unknown_report(task_id)), + None => StatusClass::NotInMemory, + } +} + +/// Map a terminal [`DelegationTaskReport`] back to a [`DelegationOutcome`] for +/// the test-only `handle_request` shim (so pre-async tests keep asserting on +/// the old outcome shape). +#[cfg(any(test, feature = "test-utils"))] +fn report_to_outcome(report: &DelegationTaskReport) -> DelegationOutcome { + use crate::acp::delegation::types::DelegationSuccess; + match report.status { + TaskStatus::Completed => DelegationOutcome::Ok(DelegationSuccess { + text: report.text.clone().unwrap_or_default(), + child_conversation_id: report.child_conversation_id.unwrap_or(0), + child_agent_type: report.agent_type.unwrap_or(AgentType::ClaudeCode), + turn_count: 1, + duration_ms: report.duration_ms.unwrap_or(0), + token_usage: None, + }), + // Running never reaches here (the shim loops until terminal); the other + // states all project onto Err. + _ => DelegationOutcome::Err { + code: report + .error_code + .clone() + .unwrap_or_else(|| "canceled".to_string()), + message: report.message.clone().unwrap_or_default(), + child_conversation_id: report.child_conversation_id, + }, + } +} + +/// Build the `Canceled { reason }` string for a child that ended without a +/// clean `TurnComplete`, optionally stitching in the terminal `Error` detail. +/// Shared by `cancel_by_child_connection` and `handle_request`'s early-terminal +/// pickup so both surface the same wording. +fn child_canceled_reason(terminal_error: Option<&str>) -> String { + match terminal_error { + Some(detail) if !detail.trim().is_empty() => { + format!("child session ended without TurnComplete: {detail}") + } + _ => "child session ended without TurnComplete".to_string(), + } +} + +/// Set of MCP-side `external_handle` tokens for which the companion +/// already received `notifications/cancelled` BEFORE the matching +/// `handle_request` reached the pending-registration phase. Without +/// this pre-cancel buffer, a fast cancel that lands during the +/// pre-check / spawn window would find no entry in `pending`, drop +/// silently, and let the broker proceed to spawn a child the caller +/// no longer wants. `handle_request` consults this set both at entry +/// (so we never even spawn) and immediately after parking the pending +/// entry (so a cancel landing mid-spawn still wins). +/// +/// Capped at [`PRE_CANCELED_CAP`] so a misbehaving MCP client (or a +/// pathological cancel-for-unknown-id storm) can't grow the set +/// without bound. Eviction is FIFO via the parallel `order` deque, +/// which is fine because pre-cancels only matter for the short window +/// between the cancel and the late-arriving `handle_request`. +#[derive(Default)] +struct PreCanceledHandles { + inner: Mutex, +} + +#[derive(Default)] +struct PreCanceledState { + set: HashSet, + order: VecDeque, +} + +const PRE_CANCELED_CAP: usize = 256; + +/// Per-parent tracking of `tool_call_id`s that the ACP lifecycle +/// observed firing `delegate_to_agent`. MCP clients (Codex, Claude +/// Code) generally do NOT populate `_meta.tool_use_id` when invoking +/// an MCP tool, so the broker can't read the LLM-issued +/// `tool_use_id` from the wire — we capture it from the parallel ACP +/// `tool_call` event stream instead. +/// +/// Each bucket holds two FIFOs under the SAME mutex: +/// +/// * `pending` — ids the lifecycle has registered but the matching +/// broker round-trip has not yet claimed. UNKEYED entries are subject +/// to [`PENDING_TOOL_CALL_TTL`] eviction so an anonymous ACP id whose +/// MCP round-trip never arrives can't linger and FIFO-mis-bind a later +/// delegation. KEYED entries carry no count cap: they are drained only +/// by their exact-match claim, by terminal tombstoning +/// (`tombstone_pending_tool_call`), or by per-parent teardown — because +/// the host may serialize a delegation's round-trip arbitrarily far +/// behind earlier long-running ones, so a count cap would drop a +/// still-pending keyed id and orphan its card. +/// * `consumed` — ids that were already claimed by a prior +/// round-trip, or terminal-tombstoned (`tombstone_pending_tool_call`). +/// NEITHER subject to TTL eviction NOR to a per-bucket +/// cap: a delegated child agent may run for minutes to hours, and +/// the host can re-emit the same `tool_call` (e.g. as a `completed` +/// status flip) at the end of that run, so the consumed memory +/// must outlast the entire parent-side tool call lifetime. It is +/// scoped to the parent connection's lifetime instead, cleared by +/// `drop_pending_tool_calls_for_parent` on disconnect. The growth +/// is bounded by how many entries ever register for the parent: +/// `delegate_to_agent` calls (typically tens at most) plus, on +/// Cursor connections, one identity-less "MCP: tool" candidate per +/// MCP call the session makes (see `acp::lifecycle`'s +/// `CURSOR_IDENTITYLESS_MCP_TITLE` registration) — with each +/// `(String, Instant)` entry costing well under 100 bytes, an +/// unbounded set stays comfortable for realistic sessions without +/// OOM risk in the typical operating envelope. +/// +/// Co-locating the two halves under one lock makes the +/// claim → mark-consumed pair atomic. A host re-emit racing with the +/// claim cannot observe an empty pending queue AND a consumed memory +/// that does not yet remember the id; consequently it cannot inject +/// a stale duplicate that would mis-bind the next delegation. +#[derive(Default)] +struct ToolCallTracker { + inner: Mutex>, +} + +/// The arguments that uniquely identify a `delegate_to_agent` invocation, +/// used to correlate a parent-side ACP `tool_call` to the matching MCP +/// `tools/call` round-trip. All three fields are values the LLM passed +/// identically to both wire paths, so the triple is the deterministic key +/// when a parent fires several `delegate_to_agent` calls in parallel — +/// matching on `task` alone would swap two calls targeting different agents +/// with the same task, and adding `agent_type` alone would still swap two +/// same-agent/same-task calls aimed at different directories (e.g. "run +/// tests" against `/repo-a` vs `/repo-b`). +/// +/// `working_dir` here is the value the LLM EXPLICITLY passed (`None` when +/// omitted), NOT the listener-defaulted spawn directory: the listener +/// defaults a missing MCP `working_dir` to the parent's launch dir, but the +/// ACP `raw_input` omits it then too, so keying on the explicit value keeps +/// both sides symmetric (`None == None`) for the common omitted case while +/// still distinguishing two calls that name different directories. +#[derive(Clone, Debug, PartialEq, Eq)] +pub struct DelegationMatchKey { + pub agent_type: AgentType, + pub task: String, + pub working_dir: Option, +} + +/// One captured parent-side `delegate_to_agent` tool_call awaiting its +/// matching MCP round-trip. +struct PendingToolCall { + tool_call_id: String, + /// The `(agent_type, task, working_dir)` correlation key parsed from the ACP + /// tool_call's `raw_input`. Matched against the MCP round-trip's own + /// key so parallel `delegate_to_agent` calls each bind to their own + /// `tool_call_id` regardless of arrival order — pure arrival-order FIFO + /// can mis-assign them (or, when one MCP round-trip out-races the + /// matching ACP event, orphan to a synthetic id). `None` when the host + /// shipped no parseable `raw_input` at ToolCall time; such entries are + /// claimable ONLY via the post-budget FIFO fallback + /// (`take_pending_tool_call`), never the in-loop key-match path. + match_key: Option, + /// True when the entry came from an identity-less MCP announcement + /// (Cursor's `"MCP: tool"` + empty input — see + /// `lifecycle::CURSOR_IDENTITYLESS_MCP_TITLE`). Such an id belongs to + /// *some* codeg-mcp call whose identity only the companion round-trip can + /// reveal, so it is additionally claimable by + /// [`DelegationBroker::rewrite_identityless_tool_call`] (the + /// `get_delegation_status` / `cancel_delegation` call-time rename), and a + /// `delegate_to_agent` claim that lands on one triggers the identity + /// write. Plain unkeyed entries (a delegation invocation whose args were + /// unparseable) keep `false` and are never renamed. + identityless: bool, + registered_at: Instant, +} + +#[derive(Default)] +struct ToolCallTrackerBucket { + pending: VecDeque, + consumed: VecDeque<(String, Instant)>, + /// Sticky "this parent has EVER announced an identity-less MCP call" flag. + /// Gates [`DelegationBroker::rewrite_identityless_tool_call`]'s poll: on + /// hosts that ship real identities (Claude/Codex/…) no identity-less + /// entry ever registers, the flag stays `false`, and every status/cancel + /// round-trip skips the rename at zero cost instead of burning the poll + /// budget. Never cleared on claim — only with the bucket on teardown. + identityless_seen: bool, +} + +/// Maximum age before a `pending` entry is discarded as stale — but ONLY for +/// UNKEYED entries (anonymous, arrival-order correlated). KEYED entries are +/// retained regardless of age: each is claimed solely by an exact key match, +/// so it can't mis-bind a later delegation, and its MCP round-trip may be +/// serialized arbitrarily far behind earlier long-running delegations (Claude +/// Code runs parallel `delegate_to_agent` calls one-at-a-time — observed gap +/// 77 s). See the retain block in `take_matching_tool_call_at`. +/// 60 s comfortably covers the ACP→MCP race for the unkeyed case (<5 ms +/// typical) while still GC'ing a forgotten anonymous id before it can +/// FIFO-mis-bind a subsequent unkeyed delegation. +/// +/// The `consumed` side has no TTL — see [`ToolCallTrackerBucket`] — because +/// long-running delegations can re-emit the parent-side `tool_call` well past +/// this window. +const PENDING_TOOL_CALL_TTL: Duration = Duration::from_secs(60); + +/// Poll cadence and budget used by `claim_pending_tool_call_with_brief_wait` +/// to correlate an MCP `delegate_to_agent` round-trip to its parent-side +/// ACP `tool_call_id`. The exact-match path returns instantly; this budget is +/// spent while waiting for THIS delegation's own `tool_call` to register (or to +/// backfill its key onto an already-registered entry) so we bind by exact match +/// instead of stealing a parallel sibling's id, or while no claimable id has +/// arrived yet. Unkeyed entries are never claimed in-loop — arrival-order FIFO +/// is deferred to the post-budget last resort, which runs only after the caller +/// has waited the full budget (the correct clock for "this delegation has no +/// key coming"), so a round-trip can't grab a sibling's not-yet-keyed id +/// mid-race. +/// +/// 200 × 10 ms = 2 s. This budget only matters when the MCP round-trip +/// out-races its own ACP `tool_call` registration — i.e. the `tools/call` +/// reaches the broker before the in-process `session/update(tool_call)` (and +/// any slightly-later `ToolCallUpdate` carrying the `agent_type`/`task` args) +/// has registered the key. That race is sub-5ms locally; the headroom covers +/// busier hosts and split arg streaming. The wait is invisible in the happy +/// path (it returns the instant the key matches) and negligible against the +/// multi-second-to-minutes child run it precedes. +/// +/// NOTE: the budget is NOT what protects a *serialized* second delegation +/// whose round-trip lands many seconds after its tool_call registered (Claude +/// Code runs parallel `delegate_to_agent` calls one-at-a-time, so the 2nd may +/// arrive minutes later). That id is already registered and waiting — the +/// thing that used to orphan it was age-eviction, now fixed by retaining keyed +/// entries indefinitely (see `take_matching_tool_call_at`'s retain +/// block). A host that emits no observable ACP `tool_call` at all still falls +/// through to the synthetic id after the budget, exactly as before. +const CLAIM_POLL_INTERVAL: Duration = Duration::from_millis(10); +const CLAIM_POLL_ATTEMPTS: usize = 200; + +/// Poll budget for the status/cancel call-time rename +/// ([`DelegationBroker::rewrite_identityless_tool_call`]): 30 × 10 ms = 300 ms. +/// Much shorter than the delegate claim budget because the rename is +/// best-effort (a miss falls back to the completion-time result sniff) and the +/// poll delays the status snapshot the LLM is waiting on. It only has to +/// absorb the in-process ordering race between the ACP announcement landing in +/// the lifecycle dispatcher and the companion's UDS round-trip reaching the +/// listener — sub-5 ms in practice; the sticky `identityless_seen` gate keeps +/// hosts that never announce identity-less calls at zero cost. +const IDENTITYLESS_RENAME_POLL_ATTEMPTS: usize = 30; + +/// The broker is intentionally `Clone` (cheap — only `Arc`s inside) so +/// listener/handler code can hand copies to spawned tasks without lifetime +/// gymnastics. +#[derive(Clone)] +pub struct DelegationBroker { + spawner: Arc, + depth_lookup: Arc, + /// Writer for `meta["codeg.delegation"]` on the parent's active + /// `delegate_to_agent` ToolCallState. Defaults to a no-op so tests + /// that aren't exercising the meta lifecycle don't need to wire + /// anything; production constructs the broker with the + /// `ConnectionManagerMetaWriter` via `with_writers`. + meta_writer: Arc, + /// Emitter for `AcpEvent::DelegationCompleted` against the parent + /// connection's event stream. Same Noop/Mock/Production scheme as + /// the meta writer — production wires `ConnectionManagerEventEmitter` + /// via `with_writers`; tests that don't observe the event lifecycle + /// take the default Noop. + event_emitter: Arc, + /// DB fallback for `get_delegation_status` / `cancel_delegation` once a + /// task's result aged out of the in-memory completed-cache. Defaults to a + /// no-op ("unknown"); production wires `DbChildStatusLookup` via + /// `with_status_lookup`. + status_lookup: Arc, + /// Peeks a still-running child's live session for a one-line progress hint, + /// used to enrich `get_delegation_status`'s running report. Defaults to a + /// no-op ("no hint"); production wires `ConnectionManagerLiveReplyLookup` via + /// `with_live_reply_lookup`. + live_reply_lookup: Arc, + pending: Arc, + tool_calls: Arc, + pre_canceled_handles: Arc, + config: Arc>, + /// Separate from `DelegationConfig` so existing test literals do not + /// have to name it. Default on: agents may spawn without `@`. The + /// settings toggle can turn it off (mention-only description). + allow_self_initiate: Arc, + /// Woken after every terminal `record_completed` so a `get_delegation_status` + /// long-poll wakes the instant its task finishes instead of busy-polling. + result_notify: Arc, + /// How long an already-reported blocking prompt stays suppressed — + /// [`BLOCK_RESURFACE_INTERVAL`] in production. A field only so tests can + /// shrink it; nothing outside tests ever sets it. + block_resurface: Duration, +} + +impl DelegationBroker { + pub fn new( + spawner: Arc, + depth_lookup: Arc, + ) -> Self { + Self::with_writers( + spawner, + depth_lookup, + Arc::new(NoopMetaWriter) as Arc, + Arc::new(NoopEventEmitter) as Arc, + ) + } + + /// Test-only constructor that injects a meta writer but keeps the + /// default Noop event emitter. Retained so existing meta-focused + /// tests don't have to mention the emitter parameter. New callsites + /// (and production wiring) should prefer `with_writers`. + pub fn with_meta_writer( + spawner: Arc, + depth_lookup: Arc, + meta_writer: Arc, + ) -> Self { + Self::with_writers( + spawner, + depth_lookup, + meta_writer, + Arc::new(NoopEventEmitter) as Arc, + ) + } + + /// Production-grade constructor wiring the broker to both a real + /// meta writer (`ConnectionManagerMetaWriter`) AND an event emitter + /// (`ConnectionManagerEventEmitter`). Tests that observe the full + /// lifecycle (meta writes + DelegationCompleted emits) should use + /// this with `MockMetaWriter` + `MockEventEmitter`. + pub fn with_writers( + spawner: Arc, + depth_lookup: Arc, + meta_writer: Arc, + event_emitter: Arc, + ) -> Self { + Self { + spawner, + depth_lookup, + meta_writer, + event_emitter, + status_lookup: Arc::new(NoopChildStatusLookup), + live_reply_lookup: Arc::new(NoopChildLiveReplyLookup), + pending: Arc::new(PendingCalls::default()), + tool_calls: Arc::new(ToolCallTracker::default()), + pre_canceled_handles: Arc::new(PreCanceledHandles::default()), + config: Arc::new(Mutex::new(DelegationConfig::default())), + allow_self_initiate: Arc::new(AtomicBool::new(true)), + result_notify: Arc::new(Notify::new()), + block_resurface: BLOCK_RESURFACE_INTERVAL, + } + } + + /// Replace the DB status fallback used by `get_delegation_status` / + /// `cancel_delegation` for tasks evicted from the in-memory completed-cache. + /// Builder-style so the production wiring can layer it onto `with_writers` + /// without growing that constructor's arity, and tests can opt in. + pub fn with_status_lookup(mut self, status_lookup: Arc) -> Self { + self.status_lookup = status_lookup; + self + } + + /// Replace the live-reply lookup used to enrich `get_delegation_status`'s + /// running report with the child's latest one-line progress. Builder-style, + /// layered onto `with_writers` by the production wiring; tests opt in with a + /// `MockChildLiveReplyLookup`. + pub fn with_live_reply_lookup( + mut self, + live_reply_lookup: Arc, + ) -> Self { + self.live_reply_lookup = live_reply_lookup; + self + } + + /// Shrink [`BLOCK_RESURFACE_INTERVAL`] so a test can observe the + /// delivery-failure valve without waiting minutes. Test-only by + /// construction — production always keeps the constant. + #[cfg(test)] + fn with_block_resurface(mut self, interval: Duration) -> Self { + self.block_resurface = interval; + self + } + + /// Record a parent ACP `tool_call_id` whose title indicates the LLM is + /// invoking `delegate_to_agent`. The next broker round-trip from the + /// same `parent_connection_id` will claim this id as its + /// `parent_tool_use_id`. Bounded FIFO per connection. + /// + /// Two-tier dedupe against host re-emits of `sessionUpdate(tool_call)` + /// (some hosts use the non-update variant to ship status flips and + /// late-arriving `raw_input` chunks): + /// + /// 1. **In-queue**: if the id is still waiting to be claimed, drop + /// the re-emit — the first push will be consumed by the matching + /// MCP round-trip. + /// 2. **Recently consumed**: if the id was already claimed for an + /// earlier delegation on the same parent, drop the re-emit — + /// otherwise it would sit in the queue as a stale id and mis- + /// bind the **next** delegation's MCP round-trip. The consumed + /// memory persists for the parent connection's lifetime (no + /// TTL, no cap) so a host re-emit at terminal status flip is + /// still rejected even if the delegation ran for hours. + pub async fn register_pending_tool_call( + &self, + parent_connection_id: &str, + tool_call_id: String, + ) { + self.register_pending_tool_call_with_key_at( + parent_connection_id, + tool_call_id, + None, + false, + Instant::now(), + ) + .await; + } + + /// Register an id announced with NO identity at all — Cursor's + /// `"MCP: tool"` + empty-input shape, where the wire never reveals which + /// MCP tool the call is. The entry is unkeyed (claimable by the + /// post-budget FIFO fallback, exactly like a keyless delegation + /// invocation) and additionally marked `identityless`, which (a) makes it + /// claimable by the status/cancel call-time rename + /// ([`Self::rewrite_identityless_tool_call`]) and (b) triggers the + /// identity write when a `delegate_to_agent` claim lands on it. + pub async fn register_identityless_tool_call( + &self, + parent_connection_id: &str, + tool_call_id: String, + ) { + self.register_pending_tool_call_with_key_at( + parent_connection_id, + tool_call_id, + None, + true, + Instant::now(), + ) + .await; + } + + /// `register_pending_tool_call` that also records the + /// `(agent_type, task, working_dir)` correlation key parsed from the + /// tool_call's `raw_input`. The key lets + /// the broker bind this id to its matching MCP round-trip deterministically + /// for parallel `delegate_to_agent` calls that pure arrival-order FIFO can + /// mis-assign. Production registration (from the ACP lifecycle dispatcher) + /// goes through here. + pub async fn register_pending_tool_call_with_key( + &self, + parent_connection_id: &str, + tool_call_id: String, + match_key: Option, + ) { + self.register_pending_tool_call_with_key_at( + parent_connection_id, + tool_call_id, + match_key, + false, + Instant::now(), + ) + .await; + } + + /// Core registration. Holds the [`ToolCallTracker`] mutex across both + /// dedupe tiers AND the push so no concurrent `take` can split the + /// "queue empty + not yet recorded as consumed" window where a host + /// re-emit could otherwise inject a stale duplicate. + /// + /// Two-tier dedupe against host re-emits of `sessionUpdate(tool_call)` + /// (some hosts use the non-update variant to ship status flips and + /// late-arriving `raw_input` chunks): + /// + /// 1. **Recently consumed**: if the id was already claimed for an + /// earlier delegation on the same parent, drop the re-emit — + /// otherwise it would sit in the queue as a stale id and mis-bind + /// the **next** delegation's MCP round-trip. The consumed memory + /// persists for the parent connection's lifetime (no TTL, no cap) + /// so a host re-emit at terminal status flip is still rejected + /// even if the delegation ran for hours. + /// 2. **In-queue**: if the id is still waiting to be claimed, drop the + /// re-emit rather than push a duplicate — EXCEPT we backfill the + /// `match_key` onto an entry registered without one. This is the common + /// case for hosts that emit an arg-less initial `ToolCall` and ship the + /// `agent_type`/`task` arguments on a following `ToolCallUpdate`: the + /// lifecycle dispatcher registers BOTH variants (see + /// `register_delegation_tool_call_from_event`), so the first call lands + /// here unkeyed and the later update re-enters and back-fills the key. + /// Keying the entry this way is what lets it survive past the unkeyed + /// GC TTL (see `take_matching_tool_call_at`'s retain block). + async fn register_pending_tool_call_with_key_at( + &self, + parent_connection_id: &str, + tool_call_id: String, + match_key: Option, + identityless: bool, + now: Instant, + ) { + let mut map = self.tool_calls.inner.lock().await; + let bucket = map.entry(parent_connection_id.to_string()).or_default(); + if identityless { + bucket.identityless_seen = true; + } + // Tier 1: recently consumed. No TTL — the consumed memory must + // outlast the entire parent-side tool call lifetime (minutes + // to hours) so a host re-emit at terminal status flip is + // still rejected. See `ToolCallTrackerBucket` docs. + if bucket.consumed.iter().any(|(id, _)| id == &tool_call_id) { + tracing::info!( + "[delegation] dropping ACP tool_call_id={tool_call_id} on conn={parent_connection_id} (already consumed by an earlier delegation)" + ); + return; + } + // Tier 2: in-queue. A re-emit of an already-queued id: adopt the + // LATEST parseable key rather than only back-filling a missing one. + // Hosts stream `raw_input` incrementally and the MCP side keys on the + // FINAL arguments, so a later `ToolCallUpdate` that completes the key + // (e.g. adds an explicit `working_dir` the first parse lacked) must + // REPLACE the earlier `(agent, task, None)` key — otherwise the MCP + // claim keys on `(agent, task, Some(dir))`, fails to match the stale + // `None`, refuses the keyed fallback, and orphans to a synthetic id + // (the very dead-card failure this whole change fixes). An arg-less or + // identical re-emit changes nothing and is dropped as a duplicate. + if let Some(existing) = bucket + .pending + .iter_mut() + .find(|p| p.tool_call_id == tool_call_id) + { + match match_key { + Some(key) if existing.match_key.as_ref() != Some(&key) => { + existing.match_key = Some(key); + } + _ => { + tracing::info!( + "[delegation] dropping duplicate ACP tool_call_id={tool_call_id} on conn={parent_connection_id}" + ); + } + } + return; + } + bucket.pending.push_back(PendingToolCall { + tool_call_id, + match_key, + identityless, + registered_at: now, + }); + } + + /// Pop the oldest pending `tool_call_id` for the given parent, if any. + /// Skips entries older than [`PENDING_TOOL_CALL_TTL`] so an ACP id whose + /// matching MCP round-trip never arrived cannot mis-bind a later + /// delegation. Mutates the queue in-place; the bucket is removed once + /// drained. + pub async fn take_pending_tool_call(&self, parent_connection_id: &str) -> Option { + self.take_pending_tool_call_at(parent_connection_id, Instant::now()) + .await + .map(|(id, _)| id) + } + + /// `take_pending_tool_call` with an injected "as of" instant. The + /// public entry point pins it to `Instant::now()`; tests can supply + /// a future instant to exercise TTL eviction without sleeping past + /// [`PENDING_TOOL_CALL_TTL`]. + /// + /// Anonymous claim: returns the oldest *unkeyed* pending id (plus its + /// `identityless` mark, so the delegate-claim path knows to restore the + /// call's identity), GC'ing stale unkeyed entries along the way. KEYED + /// entries are stepped over and left in place — they're reserved for + /// their exact-key-match round-trip and must never be handed out by this + /// arrival-order path (doing so would steal an in-flight delegation's + /// id). Returns `None` when no unkeyed entry is claimable, even if keyed + /// entries remain. + async fn take_pending_tool_call_at( + &self, + parent_connection_id: &str, + now: Instant, + ) -> Option<(String, bool)> { + self.take_unkeyed_tool_call_at(parent_connection_id, now, false) + .await + } + + /// Claim the oldest pending entry that was registered as IDENTITY-LESS + /// (Cursor's `"MCP: tool"` announcements) — used by the status/cancel + /// call-time rename. Unlike `take_pending_tool_call_at` this NEVER hands + /// out a plain unkeyed entry: that one is a delegation invocation whose + /// args merely didn't parse, and renaming it to a status tool would + /// mislabel a real delegate card. + async fn take_identityless_tool_call(&self, parent_connection_id: &str) -> Option { + self.take_unkeyed_tool_call_at(parent_connection_id, Instant::now(), true) + .await + .map(|(id, _)| id) + } + + /// Shared FIFO claim over unkeyed entries. `identityless_only` restricts + /// eligibility to entries carrying the identity-less mark; keyed entries + /// are always stepped over (reserved for their exact-key-match + /// round-trip), and stale unkeyed entries are GC'd along the way + /// regardless of the filter so the queue stays bounded from either + /// caller. + async fn take_unkeyed_tool_call_at( + &self, + parent_connection_id: &str, + now: Instant, + identityless_only: bool, + ) -> Option<(String, bool)> { + let mut map = self.tool_calls.inner.lock().await; + let bucket = map.get_mut(parent_connection_id)?; + // Anonymous claim (post-budget last resort + legacy single-delegation + // path): only UNKEYED entries are eligible. A keyed entry identifies a + // specific in-flight delegation and is claimable ONLY by its + // exact-key-match round-trip; grabbing it here would steal that + // delegation's id and make IT the dead card. Walk oldest→newest, + // GC'ing stale unkeyed entries and stepping over keyed ones, until we + // find the oldest fresh eligible id. When only keyed siblings remain we + // return `None` — the delegate caller then mints a synthetic id rather + // than mis-binding a sibling. + let mut claimed: Option<(String, bool)> = None; + let mut idx = 0; + while idx < bucket.pending.len() { + if bucket.pending[idx].match_key.is_some() { + idx += 1; // keyed: leave it for its exact-match round-trip + continue; + } + if now.duration_since(bucket.pending[idx].registered_at) > PENDING_TOOL_CALL_TTL { + if let Some(stale) = bucket.pending.remove(idx) { + let age_secs = now.duration_since(stale.registered_at).as_secs(); + tracing::info!( + "[delegation] evicting stale UNKEYED ACP tool_call_id={} (age={age_secs}s) on conn={parent_connection_id}", + stale.tool_call_id + ); + } + // `remove` shifted later entries left into `idx`; re-check it. + continue; + } + if identityless_only && !bucket.pending[idx].identityless { + idx += 1; // plain unkeyed: reserved for the delegate FIFO path + continue; + } + claimed = bucket + .pending + .remove(idx) + .map(|p| (p.tool_call_id, p.identityless)); + break; + } + // Same mutex span: record the claim into the consumed memory so + // a concurrent re-register cannot observe "pending empty AND + // consumed missing" and inject a stale duplicate. Consumed + // entries persist for the whole parent connection lifetime + // (no TTL, no cap — see `ToolCallTrackerBucket`) and are only + // released when the parent disconnects. + if let Some((id, _)) = &claimed { + bucket.consumed.push_back((id.clone(), now)); + } + if bucket.pending.is_empty() && bucket.consumed.is_empty() && !bucket.identityless_seen { + map.remove(parent_connection_id); + } + claimed + } + + /// Whether this parent has EVER registered an identity-less candidate — + /// the zero-cost gate for [`Self::rewrite_identityless_tool_call`]'s poll. + async fn has_seen_identityless_tool_calls(&self, parent_connection_id: &str) -> bool { + self.tool_calls + .inner + .lock() + .await + .get(parent_connection_id) + .is_some_and(|b| b.identityless_seen) + } + + /// Restore the identity of a pending identity-less MCP tool call at + /// companion round-trip time: claim the oldest such candidate for this + /// parent and rewrite its live `title` + `raw_input` to the actual + /// codeg-mcp tool (`get_delegation_status` / `cancel_delegation`) with + /// its real arguments — flipping the card from the generic "MCP: tool" + /// WHILE the call runs, instead of only at the completion-time result + /// sniff (which, for a `wait_ms`-blocked status long-poll, can be minutes + /// away). + /// + /// Best-effort by design: on hosts that ship real identities the sticky + /// `identityless_seen` gate skips everything at zero cost; on an + /// identity-less host whose announcement hasn't registered yet, a short + /// bounded poll (well under the ACP-vs-companion race in practice) + /// absorbs the ordering, and a miss simply leaves the rename to the + /// completion sniff. Mis-pairing under PARALLEL identity-less calls in + /// one burst is the same accepted arrival-order residual as the delegate + /// FIFO fallback — Cursor executes tool calls sequentially, so announce + /// order matches round-trip order in practice. + pub async fn rewrite_identityless_tool_call( + &self, + parent_connection_id: &str, + title: &str, + raw_input: serde_json::Value, + ) -> Option { + if !self + .has_seen_identityless_tool_calls(parent_connection_id) + .await + { + return None; + } + for attempt in 0..IDENTITYLESS_RENAME_POLL_ATTEMPTS { + if attempt > 0 { + tokio::time::sleep(CLAIM_POLL_INTERVAL).await; + } + if let Some(id) = self.take_identityless_tool_call(parent_connection_id).await { + tracing::info!( + "[delegation] renaming identity-less tool_call_id={id} on conn={parent_connection_id} to {title}" + ); + self.meta_writer + .write_tool_call_identity(parent_connection_id, &id, title, raw_input) + .await; + return Some(id); + } + } + None + } + + /// Claim the pending `tool_call_id` for `parent_connection_id` whose + /// recorded key matches `key` (exact `(agent_type, task, working_dir)` + /// match). This is the ONLY claim this method makes — it never hands out an + /// unkeyed entry, because an unkeyed entry may belong to a *different* + /// parallel delegation whose round-trip simply hasn't registered (or keyed) + /// its `tool_call` yet, and claiming it by arrival order would steal that + /// sibling's id. Returns `None` (so the caller keeps polling) whenever no + /// entry's key matches — whether keyed siblings or only unkeyed entries are + /// present. + /// + /// Arrival-order FIFO for genuinely keyless hosts is deferred to the + /// post-budget last resort `take_pending_tool_call`, which runs only after + /// the caller has waited its full budget (see + /// `claim_pending_tool_call_with_brief_wait`) — the correct clock for "no + /// key is coming", since a host can serialize a round-trip arbitrarily far + /// behind its `tool_call` registration, so the entry's own age can never + /// prove a key won't still arrive. Evicts stale *unkeyed* entries along the + /// way; keyed entries are retained regardless of age (their round-trip may + /// be serialized far behind earlier delegations — see the retain block) and + /// an exact key match claims them at any age. + pub async fn take_matching_tool_call( + &self, + parent_connection_id: &str, + key: &DelegationMatchKey, + ) -> Option { + self.take_matching_tool_call_at(parent_connection_id, key, Instant::now()) + .await + } + + /// `take_matching_tool_call` with an injected "as of" + /// instant for TTL tests. + async fn take_matching_tool_call_at( + &self, + parent_connection_id: &str, + key: &DelegationMatchKey, + now: Instant, + ) -> Option { + let mut map = self.tool_calls.inner.lock().await; + let bucket = map.get_mut(parent_connection_id)?; + + // Evict every stale UNKEYED entry up front. The key-match scan below + // ignores unkeyed entries anyway (they carry no key to match), but + // GC'ing here keeps the queue bounded during the poll loop and + // consistent with `take_pending_tool_call_at`'s view, so the + // post-budget last resort never hands out an aged-out id. Mirrors that + // TTL skip but covers entries at any position (not just the front). + bucket.pending.retain(|p| { + // Keyed entries are NEVER aged out. Each identifies one specific + // `delegate_to_agent` invocation and is claimable ONLY by an exact + // key match (never by FIFO — see below), so it cannot mis-bind a + // different delegation no matter how old it gets. And it MUST + // survive until its MCP round-trip arrives, which the host may + // serialize arbitrarily far behind earlier long-running + // delegations: Claude Code runs parallel `delegate_to_agent` calls + // SEQUENTIALLY, so the 2nd call's round-trip only fires after the + // 1st child finishes. Observed in the wild — a 2nd delegation whose + // tool_call registered, then waited 77s (past the old 60s TTL) for + // its round-trip while the 1st ran; age-evicting it here orphaned + // it to a synthetic id and left the parent card stuck on + // "sub-agent running…". Only UNKEYED (anonymous, arrival-order + // correlated) entries keep the age-based GC, since a stale one + // could be mis-claimed via the FIFO path. Keyed memory stays bounded + // by exact-match claim, terminal tombstoning, and + // `drop_pending_tool_calls_for_parent` on connection teardown — not + // by this TTL. + if p.match_key.is_some() { + return true; + } + let fresh = now.duration_since(p.registered_at) <= PENDING_TOOL_CALL_TTL; + if !fresh { + let age_secs = now.duration_since(p.registered_at).as_secs(); + tracing::info!( + "[delegation] evicting stale UNKEYED ACP tool_call_id={} (age={age_secs}s) on conn={parent_connection_id}", + p.tool_call_id + ); + } + fresh + }); + + let claimed = if let Some(pos) = bucket + .pending + .iter() + .position(|p| p.match_key.as_ref() == Some(key)) + { + // Exact (agent_type, task) match: deterministic correlation + // regardless of ACP-vs-MCP arrival order or how many delegations + // are in flight. + bucket.pending.remove(pos).map(|p| p.tool_call_id) + } else { + // No exact key match. We deliberately do NOT claim an unkeyed entry + // here — not even the oldest, not even the only one. An unkeyed + // pending entry may belong to a DIFFERENT parallel delegation whose + // own round-trip hasn't yet registered (or keyed) its `tool_call`, + // and claiming it by arrival order would steal that sibling's id — + // the mis-bind this machinery exists to prevent. + // + // Crucially, the ENTRY's age is the wrong clock for "no key is + // coming": a host can serialize a round-trip arbitrarily far behind + // its `tool_call` registration (see the retain block / the + // `keyed_entry_survives_past_ttl` case), so even an old lone unkeyed + // entry can still be a sibling's. The CALLER's own wait is the right + // clock. So return `None` and let + // `claim_pending_tool_call_with_brief_wait` poll: if this + // delegation's key lands (initial register or a later backfill) we + // bind by the exact match above; only after the caller has spent the + // FULL budget does its post-budget last resort + // (`take_pending_tool_call`) claim the oldest unkeyed id in arrival + // order — the best a genuinely keyless host allows, and the point at + // which waiting longer cannot improve correlation. + None + }; + + if let Some(id) = &claimed { + bucket.consumed.push_back((id.clone(), now)); + } + if bucket.pending.is_empty() && bucket.consumed.is_empty() { + map.remove(parent_connection_id); + } + claimed + } + + /// Consume an explicit `parent_tool_use_id` that the MCP client supplied + /// directly via `_meta.tool_use_id` (the precise-binding path; most clients + /// omit it). In that case `handle_request` does NOT run the claim path, so + /// the matching pending entry the lifecycle dispatcher registered off the + /// parent's ACP stream would otherwise never be consumed — and because + /// keyed entries are now retained indefinitely, it would linger and could + /// be mis-claimed by a *later* delegation sharing the same + /// `(agent_type, task, working_dir)` key, retargeting that delegation's + /// writes/events at the wrong (already-handled) card. + /// + /// Remove the entry from the pending queue AND record the id as consumed. + /// Recording consumed also covers the MCP-before-ACP race: a later ACP + /// registration for the same id is dropped by the Tier-1 consumed check in + /// `register_pending_tool_call_with_key_at`, so the entry can't reappear + /// regardless of arrival order. + async fn consume_explicit_tool_call(&self, parent_connection_id: &str, tool_call_id: &str) { + let mut map = self.tool_calls.inner.lock().await; + let bucket = map.entry(parent_connection_id.to_string()).or_default(); + bucket.pending.retain(|p| p.tool_call_id != tool_call_id); + if !bucket.consumed.iter().any(|(id, _)| id == tool_call_id) { + bucket + .consumed + .push_back((tool_call_id.to_string(), Instant::now())); + } + } + + /// Tombstone a parent `tool_call_id` whose `delegate_to_agent` reached a + /// TERMINAL ACP status (`completed`/`failed`) so a stale keyed pending entry + /// can't mis-bind a later delegation. The lifecycle dispatcher calls this + /// from its terminal-`ToolCallUpdate` branch, keyed on `tool_call_id` + /// (a bare terminal update carries no parseable key). + /// + /// The hazard: keyed pending entries are retained regardless of age (see the + /// retain block in `take_matching_tool_call_at`), so if a `delegate_to_agent` + /// tool call goes terminal without its MCP round-trip ever reaching the + /// broker (the call failed, the turn was interrupted, the companion never + /// dispatched), its entry would linger forever and a LATER delegation sharing + /// the same `(agent_type, task, working_dir)` key would claim this dead id, + /// retargeting its writes/events at the wrong card. Same hazard + /// `consume_explicit_tool_call` guards on the explicit-id path; this is its + /// terminal-status sibling. + /// + /// Safe synchronously, no grace window: a terminal `completed` can only + /// arrive AFTER the round-trip's claim already removed the entry (the ack + /// that claim produces is what lets the parent's tool call return), and a + /// serialized sibling still awaiting its (observed 77s-late) round-trip is + /// NON-terminal while it waits — so this never evicts a live entry. + /// + /// Records `consumed` ONLY when an entry was actually removed: this runs for + /// EVERY terminal tool-call update (the vast majority are non-delegations), + /// and `consumed` has no TTL/cap, so recording unconditionally would grow it + /// with every completed tool call. Recording on a real removal still drops an + /// out-of-order re-registration of the same id via the Tier-1 consumed check + /// in `register_pending_tool_call_with_key_at`. Returns whether an entry was + /// removed (for the dispatcher's gated log). + pub async fn tombstone_pending_tool_call( + &self, + parent_connection_id: &str, + tool_call_id: &str, + ) -> bool { + let mut map = self.tool_calls.inner.lock().await; + // No bucket → nothing registered for this parent; nothing to tombstone + // and nothing to record (unlike `consume_explicit_tool_call`, no + // MCP-before-ACP race can land a terminal status before registration on + // the single ordered ACP stream, so we never pre-create a bucket here). + let Some(bucket) = map.get_mut(parent_connection_id) else { + return false; + }; + let before = bucket.pending.len(); + bucket.pending.retain(|p| p.tool_call_id != tool_call_id); + let removed = bucket.pending.len() != before; + if removed && !bucket.consumed.iter().any(|(id, _)| id == tool_call_id) { + bucket + .consumed + .push_back((tool_call_id.to_string(), Instant::now())); + } + removed + } + + /// Correlate an MCP `delegate_to_agent` round-trip to the parent's + /// real ACP `tool_call_id`, polling briefly to absorb the race between + /// two independent arrival paths for the same invocation: + /// + /// * ACP `session/update(tool_call)` → in-process bus → lifecycle + /// dispatcher → `register_pending_tool_call_with_key` + /// * MCP `tools/call` → stdio round-trip → companion → `handle_request` + /// + /// Correlation is by the `(agent_type, task, working_dir)` key (carried in + /// both the ACP `raw_input` and the MCP call), so several `delegate_to_agent` + /// calls firing in parallel each bind to their own `tool_call_id` + /// regardless of arrival order — pure FIFO mis-assigned them (swapping + /// the child shown under each card) or, when one MCP round-trip out-raced + /// its ACP event, orphaned the loser to a synthetic `delegation-` + /// (the parent UI then never paints "view session" and the card hangs on + /// "sub-agent running…", because the frontend keys its binding map by + /// the agent's real `tool_call_id`). + /// + /// As a last resort after the budget — and the ONLY place arrival-order + /// FIFO is applied — claim the oldest unkeyed id, so a sibling whose + /// registration was unusually delayed, or a genuinely keyless host, still + /// yields a *real* id rather than a synthetic one. Deferring FIFO until the + /// full budget has elapsed is what makes it safe: in-loop we bind ONLY by + /// exact key match, so a round-trip can't FIFO-steal a sibling's + /// not-yet-keyed id while that sibling's own registration is still in + /// flight (the entry's age is no proof a key won't still arrive). A + /// synthetic id only results when no unkeyed id is claimable for the whole + /// budget — only keyed siblings remain, or the queue stays genuinely empty. + /// Returns the claimed id plus its `identityless` mark — `true` only for + /// the post-budget FIFO claim of an identity-less announcement (Cursor), + /// which tells `start_delegation` to restore the call's identity on the + /// live tool call. Exact-key claims are by definition NOT identity-less + /// (the key was parsed from the wire's own `raw_input`). + async fn claim_pending_tool_call_with_brief_wait( + &self, + parent_connection_id: &str, + key: &DelegationMatchKey, + ) -> Option<(String, bool)> { + if let Some(id) = self + .take_matching_tool_call(parent_connection_id, key) + .await + { + return Some((id, false)); + } + for _ in 0..CLAIM_POLL_ATTEMPTS { + tokio::time::sleep(CLAIM_POLL_INTERVAL).await; + if let Some(id) = self + .take_matching_tool_call(parent_connection_id, key) + .await + { + return Some((id, false)); + } + } + // Budget exhausted with no key match. As a last resort claim the + // oldest UNKEYED pending id (a host that shipped no parseable + // `raw_input`, or a mixed-shape race) — a real id beats a synthetic + // placeholder that orphans the parent UI binding. Crucially this + // never claims a KEYED entry: those belong to specific in-flight + // delegations and are reserved for their own exact-key-match + // round-trip, so when only keyed siblings remain the caller falls + // through to a synthetic id rather than stealing a sibling's binding + // (which would just move the dead card from one delegation to another). + self.take_pending_tool_call_at(parent_connection_id, Instant::now()) + .await + } + + /// Remove `handle` from the pre-cancel set, returning whether it was + /// present. Used by `handle_request` at two checkpoints (entry + just + /// after pending registration) so a cancel that lost the race with the + /// MCP round-trip still wins. The set is single-shot per handle — + /// taking it here means a subsequent `cancel_by_external_handle` will + /// have to find the pending entry on its own. + async fn take_pre_canceled_handle(&self, handle: &str) -> bool { + let mut state = self.pre_canceled_handles.inner.lock().await; + if state.set.remove(handle) { + // Best-effort companion-side cleanup of `order` so a later + // FIFO eviction doesn't burn a slot. Linear scan is fine — + // PRE_CANCELED_CAP is small. + if let Some(pos) = state.order.iter().position(|h| h == handle) { + state.order.remove(pos); + } + true + } else { + false + } + } + + /// Insert `handle` into the pre-cancel set with FIFO eviction at + /// [`PRE_CANCELED_CAP`]. Idempotent — re-inserting an existing handle + /// is a no-op. + async fn buffer_pre_canceled_handle(&self, handle: String) { + let mut state = self.pre_canceled_handles.inner.lock().await; + if !state.set.insert(handle.clone()) { + return; + } + state.order.push_back(handle); + while state.order.len() > PRE_CANCELED_CAP { + if let Some(evicted) = state.order.pop_front() { + state.set.remove(&evicted); + } + } + } + + /// Forget every pending and recently-consumed tool_call id for the + /// given parent. Called when the parent connection tears down so + /// stale ids don't bind to a future reuse of the same connection_id + /// (UUIDs make that unlikely but cheap to defend against), and so a + /// fresh connection on the reused id is not blocked by the + /// consumed memory of the previous one. + pub async fn drop_pending_tool_calls_for_parent(&self, parent_connection_id: &str) { + self.drop_tool_calls_for_parent(parent_connection_id, false) + .await; + } + + /// Core of the tool_call-tracker drop, shared by the two cancel scopes. + /// + /// * `keep_consumed == false` — genuine connection teardown: remove the + /// whole bucket (`pending` + `consumed`). The connection is going away, + /// so nothing it remembered can mis-bind a future delegation, and a + /// reused connection_id must start clean. + /// * `keep_consumed == true` — turn/prompt cancel with the parent + /// connection STILL ALIVE: TOMBSTONE the cancelled turn's unclaimed + /// `pending` ids into `consumed` and RETAIN the existing `consumed`. Both + /// the already-claimed ids AND the just-cancelled turn's unclaimed ids + /// must keep rejecting a host re-emit (e.g. a terminal status-flip): the + /// Tier-1 consumed check in `register_pending_tool_call_with_key_at` drops + /// the re-emit, so a stale id can't re-register as fresh `pending` and + /// mis-bind the next same-key delegation on this live connection. Merely + /// CLEARING the unclaimed ids would leave them re-registerable, reopening + /// that hole for the unclaimed half (the claimed half was already safe via + /// `consumed`). Retention is connection-scoped and released on teardown — + /// the same unbounded-but-bounded-by-delegation-count envelope `consumed` + /// already lives in for normal end_turn delegations (see + /// [`ToolCallTrackerBucket`]). + /// + /// Tombstoning ALL of `pending` here is safe (no turn/generation tag + /// needed): `run_conversation_loop` drives at most ONE `session/prompt` + /// future per connection at a time (see `acp/connection.rs`), and a + /// parent-side `tool_call` only streams while its prompt future is in + /// flight, so every `pending` id belongs to the single active turn — the one + /// being cancelled — or is a stale leftover from an earlier turn that should + /// be tombstoned regardless. (The per-connection `prompt_lock` only + /// serializes the prompt-SEND handshake, not the turn, so it is NOT the + /// source of this invariant.) The cancelled turn's serialized MCP round-trip + /// won't arrive after cancel, so nothing legitimate is lost. + async fn drop_tool_calls_for_parent(&self, parent_connection_id: &str, keep_consumed: bool) { + let mut map = self.tool_calls.inner.lock().await; + if !keep_consumed { + map.remove(parent_connection_id); + return; + } + if let Some(bucket) = map.get_mut(parent_connection_id) { + // Tombstone the cancelled turn's unclaimed pending ids into + // `consumed` rather than just dropping them, so a later host re-emit + // of one is rejected by the Tier-1 consumed check instead of + // re-registering as a claimable stale entry. `drain` empties + // `pending` first so the subsequent `consumed` borrow is disjoint. + let now = Instant::now(); + let cleared: Vec = bucket.pending.drain(..).map(|p| p.tool_call_id).collect(); + for id in cleared { + if !bucket.consumed.iter().any(|(c, _)| c == &id) { + bucket.consumed.push_back((id, now)); + } + } + // Drop the now-empty bucket only when nothing consumed remains — + // otherwise keep it so the retained `consumed` ids keep rejecting + // re-emits for the rest of this connection's lifetime. + if bucket.consumed.is_empty() { + map.remove(parent_connection_id); + } + } + } + + pub async fn set_config(&self, cfg: DelegationConfig) { + let cap_bytes = cfg.completed_cache_cap_bytes; + *self.config.lock().await = cfg; + // Seed the byte cap into the pending-calls bucket so `insert_completed` + // reads it lock-free (it already holds the pending lock). Acquired AFTER + // the config guard above is dropped — sequential, never nested — so no + // path locks `config` under `pending` or vice-versa (deadlock-free). + // Then prune existing per-parent caches: a LOWERED cap must free memory + // now, not lazily on each parent's next completion (which may never + // arrive for an idle parent). + let mut inner = self.pending.inner.lock().await; + inner.completed_cap_bytes = cap_bytes; + inner.enforce_completed_cap_all_parents(); + } + + pub async fn config_snapshot(&self) -> DelegationConfig { + self.config.lock().await.clone() + } + + pub fn set_allow_self_initiate(&self, allow: bool) { + self.allow_self_initiate.store(allow, Ordering::Relaxed); + } + + pub fn allow_self_initiate(&self) -> bool { + self.allow_self_initiate.load(Ordering::Relaxed) + } + + /// If this in-flight setup has been flagged canceled by a parent cancel, + /// deregister it and return true. One lock acquisition; used at the + /// pre-spawn / post-spawn checkpoints in `handle_request`. + async fn take_inflight_cancel(&self, inflight_id: u64) -> bool { + let mut inner = self.pending.inner.lock().await; + if inner.inflight_canceled(inflight_id) { + inner.deregister_inflight(inflight_id); + true + } else { + false + } + } + + /// Drop this setup's in-flight record. Called on each `handle_request` + /// early-return that isn't a park hand-off (the park region deregisters + /// inline, atomically with `calls.insert`). + async fn drop_inflight(&self, inflight_id: u64) { + self.pending + .inner + .lock() + .await + .deregister_inflight(inflight_id); + } + + /// Async entry point for `delegate_to_agent`. Does the bounded setup + /// (claim/depth checks → spawn → send first prompt), registers the task in + /// `running`, and returns a `Running` ack [`DelegationTaskReport`] WITHOUT + /// waiting for the child to finish. The child resolves later via the + /// lifecycle → [`complete_call`] (or a cancel path), which migrates the task + /// into `completed` and wakes any `get_delegation_status` long-poll. + /// + /// Returns a terminal report instead of a `Running` ack in three cases: the + /// child finished during setup (fast/empty turn), a parent cancel reached it + /// mid-setup, or setup itself failed (disabled / depth / spawn / send). + /// + /// All the setup-window race machinery (`setups` / `early_*` / `inflight`) + /// is unchanged — it governs terminals that beat registration, which is + /// orthogonal to whether the caller then blocks. The only change vs. the old + /// `handle_request` is that "park a `oneshot` and await it" becomes "insert a + /// [`RunningTask`] and return the ack." + #[tracing::instrument( + name = "delegation_task", + skip_all, + fields( + parent_connection_id = %req.parent_connection_id, + parent_tool_use_id = %req.parent_tool_use_id, + agent_type = ?req.agent_type, + working_dir = ?req.working_dir, + child_connection_id = tracing::field::Empty, + task_id = tracing::field::Empty, + ) + )] + pub async fn start_delegation(&self, mut req: DelegationRequest) -> DelegationTaskReport { + // Register this setup as the VERY FIRST thing — before the pre-cancel + // check's `.await` and the (possibly multi-second) claim poll — so a + // parent cancel landing ANYWHERE from here to park reaches it, not just + // after park (which is all the `cancel_by_parent*` parked-call drain + // covers on its own). The only residual gap is a cancel firing before + // the broker is even invoked for this request, which no + // in-`handle_request` mechanism can observe. Deregistered on every exit + // path below: each early-return via `drop_inflight` / + // `take_inflight_cancel`, or inline at park (atomically with + // `calls.insert`). + let inflight_id = self + .pending + .inner + .lock() + .await + .register_inflight(&req.parent_connection_id); + // Pre-cancel short-circuit. If the MCP companion already received + // `notifications/cancelled` for this `tools/call` before we even + // started processing (cancel ran ahead of the UDS round-trip), we + // claim the handle from the pre-cancel set and bail without + // spawning anything — the caller will not be receiving our + // response either way (the companion suppresses it per MCP spec). + if let Some(handle) = req.external_handle.as_deref() { + if self.take_pre_canceled_handle(handle).await { + self.drop_inflight(inflight_id).await; + // Bailing here BEFORE the claim path means this delegation never + // consumes the ACP `tool_call_id` the lifecycle keyed for it. As + // keyed entries are retained indefinitely, a leftover would let a + // *later* same-`(agent_type, task, working_dir)` delegation claim + // this canceled call's id and bind its writes/events to the wrong + // card. Drain it now (idempotent; the turn-end tombstone is the + // backstop if the ACP event hasn't registered yet). + if req.parent_tool_use_id.is_empty() { + let key = DelegationMatchKey { + agent_type: req.agent_type, + task: req.task.clone(), + working_dir: req.requested_working_dir.clone(), + }; + let _ = self + .take_matching_tool_call(&req.parent_connection_id, &key) + .await; + } else { + self.consume_explicit_tool_call( + &req.parent_connection_id, + &req.parent_tool_use_id, + ) + .await; + } + return report_err( + req.agent_type, + DelegationError::Canceled { + reason: "canceled before spawn".into(), + }, + None, + ); + } + } + // MCP clients usually don't populate `_meta.tool_use_id`, so the + // listener will pass through an empty string. Claim the matching + // ACP-side `tool_call_id` for this parent by task text — with a brief + // poll loop so an MCP round-trip that out-races the in-process ACP + // `session/update` doesn't fall back to a synthetic id (which breaks + // the parent UI's `parent_tool_use_id` binding). Falls back to a UUID + // placeholder only when no id arrives within the wait budget. + if req.parent_tool_use_id.is_empty() { + let match_key = DelegationMatchKey { + agent_type: req.agent_type, + task: req.task.clone(), + working_dir: req.requested_working_dir.clone(), + }; + let claimed = self + .claim_pending_tool_call_with_brief_wait(&req.parent_connection_id, &match_key) + .await; + let claimed_identityless = matches!(claimed, Some((_, true))); + req.parent_tool_use_id = claimed.map(|(id, _)| id).unwrap_or_else(|| { + tracing::warn!( + "[delegation] synthetic fallback for parent_tool_use_id on conn={} (no ACP tool_call_id arrived within claim budget)", + req.parent_connection_id + ); + format!("delegation-{}", uuid::Uuid::new_v4()) + }); + // The claimed announcement never carried an identity (Cursor's + // "MCP: tool" + "{}" — the wire will not re-send title/arguments): + // restore it NOW, before the multi-second spawn, so the live card + // shows the canonical delegate tool with its real arguments while + // the child is still starting. Hosts whose wire carried the + // identity (keyed or explicit-id claims) are left untouched — a + // reconstructed `raw_input` would clobber host-specific fields. + if claimed_identityless { + let mut raw_input = serde_json::Map::new(); + raw_input.insert("task".into(), serde_json::Value::String(req.task.clone())); + if let Ok(at) = serde_json::to_value(req.agent_type) { + raw_input.insert("agent_type".into(), at); + } + if let Some(dir) = req.requested_working_dir.as_deref() { + raw_input.insert("working_dir".into(), serde_json::Value::String(dir.into())); + } + self.meta_writer + .write_tool_call_identity( + &req.parent_connection_id, + &req.parent_tool_use_id, + crate::acp::delegation::DELEGATE_TOOL_REWRITE_TITLE, + serde_json::Value::Object(raw_input), + ) + .await; + } + } else { + // The client gave us the real ACP tool_call_id directly + // (`_meta.tool_use_id`), so we skip the claim path — but the + // lifecycle dispatcher may already have registered that same id as + // a (now indefinitely-retained) keyed pending entry. Consume it so + // it can't linger and be mis-claimed by a later same-key + // delegation. Idempotent and order-independent (see the method). + self.consume_explicit_tool_call(&req.parent_connection_id, &req.parent_tool_use_id) + .await; + } + let cfg = self.config_snapshot().await; + if !cfg.enabled { + self.drop_inflight(inflight_id).await; + return report_err( + req.agent_type, + DelegationError::Canceled { + reason: "delegation disabled".into(), + }, + None, + ); + } + + // --- Depth pre-check ---------------------------------------------------- + // We walk up to `limit + 1` so we know whether the *new* child would + // sit at >= limit. Cycles/dead chains saturate at the cap. + let lookup = self.depth_lookup.clone(); + let parent_depth = match crate::acp::delegation::depth::compute_depth( + req.parent_conversation_id, + |id| { + let lookup = lookup.clone(); + async move { lookup.parent_of(id).await } + }, + cfg.depth_limit + 1, + ) + .await + { + Ok(d) => d, + Err(e) => { + self.drop_inflight(inflight_id).await; + return report_err(req.agent_type, e, None); + } + }; + // The child the broker is about to create would sit at `parent_depth + 1`. + // Reject only when the *child* depth would strictly exceed the limit; + // a child sitting exactly at `depth_limit` is allowed. + if parent_depth + 1 > cfg.depth_limit { + self.drop_inflight(inflight_id).await; + return report_err( + req.agent_type, + DelegationError::DepthLimitExceeded { + current_depth: parent_depth, + limit: cfg.depth_limit, + }, + None, + ); + } + + // --- Spawn child connection -------------------------------------------- + // Pull per-agent overrides from the broker config (defaults to empty). + // Cloning is cheap — `AgentDelegationDefaults` is at most one Option + // and a small BTreeMap, and the spawner consumes both fields by value. + let (preferred_mode_id, preferred_config_values) = cfg + .agent_defaults + .get(&req.agent_type) + .map(|d: &AgentDelegationDefaults| (d.mode_id.clone(), d.config_values.clone())) + .unwrap_or((None, BTreeMap::new())); + // Checkpoint #1 (opportunistic): if a parent cancel already landed + // during the claim/depth phase, bail before spawning a child the parent + // has abandoned. No child exists yet, so there's nothing to tear down. + if self.take_inflight_cancel(inflight_id).await { + return report_err( + req.agent_type, + DelegationError::Canceled { + reason: "parent canceled".into(), + }, + None, + ); + } + let child_connection_id = match self + .spawner + .spawn( + &req.parent_connection_id, + req.agent_type, + req.working_dir.clone(), + preferred_mode_id, + preferred_config_values, + ) + .await + { + Ok(id) => id, + Err(e) => { + self.drop_inflight(inflight_id).await; + return report_err( + req.agent_type, + DelegationError::SpawnFailed(e.to_string()), + None, + ); + } + }; + + // Checkpoint #2: a parent cancel that landed during spawn() — the child + // now exists but no prompt has been sent, so disconnect it (mirroring + // the send-failure path's disconnect-only teardown) and bail. This is + // the primary guard for the spawn window, which can block while the + // agent process starts up. + if self.take_inflight_cancel(inflight_id).await { + let _ = self.spawner.disconnect(&child_connection_id).await; + return report_err( + req.agent_type, + DelegationError::Canceled { + reason: "parent canceled".into(), + }, + None, + ); + } + + // --- Send linked prompt ------------------------------------------------ + let call_id = uuid::Uuid::new_v4().to_string(); + // Bounded task label used by the started event and every meta write — + // the frontend card's fallback when the parent tool call's `raw_input` + // never carried the arguments (Cursor's identity-less announcements). + let task_preview = truncate_on_char_boundary(&req.task, TASK_PREVIEW_CAP); + // Now that the child connection and task id exist, fill the span's empty + // fields so every subsequent log line in this delegation carries the + // parent→child linkage (see the `delegation_task` span on this fn). + tracing::Span::current().record("child_connection_id", child_connection_id.as_str()); + tracing::Span::current().record("task_id", call_id.as_str()); + let link = DelegationLink { + parent_conversation_id: req.parent_conversation_id, + parent_tool_use_id: req.parent_tool_use_id.clone(), + delegation_call_id: call_id.clone(), + }; + + // Reserve this delegation (both ids) BEFORE sending its first prompt. + // `send_prompt_linked_for_delegation` persists the delegation link onto + // the child row (arming the lifecycle resolver) AND dispatches the + // prompt — after which a fast/empty turn's `TurnComplete` OR an + // immediate child-connection failure can fire before we park the pending + // entry below. The reservation lets those terminal events buffer their + // outcome (see `PendingInner`) for the park to drain, rather than + // no-oping and stranding `rx.await`. There is no `.await` between this + // reservation and `send_prompt` (so nothing the child does can be + // observed before the reservation is in place); it's cleared at park or + // on the send-failure path. Reserving by `call_id` AND + // `child_connection_id` lets each resolver gate on the id it holds — + // `complete_call` the `call_id`, `cancel_by_child_connection` the + // `child_connection_id`. + self.pending + .inner + .lock() + .await + .reserve(&call_id, &child_connection_id); + + let child_conversation_id = match self + .spawner + .send_prompt_linked_for_delegation(&child_connection_id, req.task.clone(), link) + .await + { + Ok(cid) => cid, + Err(e) => { + // Setup failed before parking — release the reservation (and + // discard any terminal that buffered against this delegation in + // the window) so nothing lingers or mis-binds a future id, and + // drop the in-flight record in the same lock acquisition. + { + let mut inner = self.pending.inner.lock().await; + inner.unreserve(&call_id, &child_connection_id); + inner.deregister_inflight(inflight_id); + } + let _ = self.spawner.disconnect(&child_connection_id).await; + return report_err( + req.agent_type, + DelegationError::SpawnFailed(e.to_string()), + None, + ); + } + }; + + // The child is now running. Stamp the start so terminal paths can + // report a real `duration_ms`. + let started_at = Instant::now(); + + // --- Mark the parent's tool call as in-flight ------------------------- + // The frontend's DelegationContext seeds its `parent_tool_use_id`-keyed + // binding map from this meta on snapshot replay, so a page refresh + // mid-delegation can reconstruct the child connection / conversation + // ids without depending on the live `delegation_started` event having + // been received. + self.write_meta_if_real( + &req.parent_connection_id, + &req.parent_tool_use_id, + build_delegation_meta( + "running", + Some(&child_connection_id), + Some(child_conversation_id), + None, + None, + // No meaningful elapsed yet — the child just started. + None, + Some(&task_preview), + Some(&call_id), + ), + ) + .await; + + // Announce the live delegation on the PARENT's event stream so the + // frontend `DelegationContext` binds the child inline and attaches its + // live sub-thread. Symmetric with the terminal `emit_completed_if_real`, + // and — unlike the removed child-stream emit in `send_prompt_linked` — + // delivered on a stream the parent is already attached to in web/server + // mode, carrying the real `parent_connection_id`. + self.emit_started_if_real( + &req.parent_connection_id, + &req.parent_tool_use_id, + &child_connection_id, + child_conversation_id, + req.agent_type, + &task_preview, + &call_id, + ) + .await; + + // --- Register pending, or resolve a terminal that beat us ------------- + // Under a single lock, decide this delegation's fate atomically against + // everything a concurrent resolver may have recorded while we were + // setting up: + // * a child terminal buffered against the reservation — a + // `TurnComplete` via `complete_call` (keyed by `call_id`) OR a child + // failure via `cancel_by_child_connection` (keyed by + // `child_connection_id`); either can race ahead of this park; or + // * a parent cancel that flagged this in-flight setup + // (`mark_inflight_canceled_for_parent`, which runs in the SAME lock + // acquisition that drains the parked `calls`). + // Precedence: strict first-terminal-wins by arrival stamp. Both a child + // terminal and a parent cancel carry the `seq` clock value they were + // recorded at, so whichever landed FIRST wins — a child that completed + // before the cancel keeps its result; a cancel that beat the completion + // discards it (the parent had already abandoned the turn). Ties are + // impossible: every event draws a distinct stamp under this one lock. + // Only when NOTHING beat us do we park for a future resolver, + // deregistering the in-flight record adjacent to `calls.insert` with no + // `.await` between — so a parent cancel serialized AFTER us finds the + // entry in `calls` and drains it, while one serialized BEFORE us is seen + // here via its stamp. When a terminal/cancel DID beat us we deliberately + // DON'T park: resolving inline (never leaving an entry for a second + // resolver to grab) rules out a double-finalize. + enum Disposition { + ChildTerminal(DelegationOutcome), + ParentCanceled, + Running, + } + // Near-zero elapsed for these setup-window races, but measured for + // consistency with the normal terminal paths. + let setup_duration_ms = started_at.elapsed().as_millis() as u64; + let disposition = { + let mut inner = self.pending.inner.lock().await; + // Each buffered child terminal carries (arrival_stamp, outcome). + let child_terminal: Option<(u64, DelegationOutcome)> = + if let Some((stamp, outcome)) = inner.take_early_complete(&call_id) { + Some((stamp, outcome)) + } else { + inner + .take_early_cancel(&child_connection_id) + .map(|(stamp, reason)| { + ( + stamp, + DelegationOutcome::from_err( + DelegationError::Canceled { reason }, + Some(child_conversation_id), + ), + ) + }) + }; + let parent_canceled_at = inner.inflight_canceled_at(inflight_id); + inner.unreserve(&call_id, &child_connection_id); + // For both terminal dispositions we record the completed result + // INSIDE this lock (atomically with unreserve/deregister) so a + // concurrent `get_delegation_status` can never observe the task as + // neither running nor completed. The `Running` arm inserts the live + // task instead of parking a `oneshot` — the caller returns the ack. + let record = |inner: &mut PendingInner, outcome: &DelegationOutcome| { + inner.insert_completed( + &call_id, + build_completed( + &req.parent_connection_id, + child_conversation_id, + req.agent_type, + setup_duration_ms, + outcome, + ), + ); + }; + match (child_terminal, parent_canceled_at) { + // Both raced in the setup window: the earlier arrival stamp wins. + (Some((child_stamp, outcome)), Some(cancel_stamp)) => { + inner.deregister_inflight(inflight_id); + if child_stamp < cancel_stamp { + record(&mut inner, &outcome); + Disposition::ChildTerminal(outcome) + } else { + record( + &mut inner, + &canceled_outcome(child_conversation_id, "parent canceled"), + ); + Disposition::ParentCanceled + } + } + // Only a child terminal fired. + (Some((_, outcome)), None) => { + inner.deregister_inflight(inflight_id); + record(&mut inner, &outcome); + Disposition::ChildTerminal(outcome) + } + // Only a parent cancel fired. + (None, Some(_)) => { + inner.deregister_inflight(inflight_id); + record( + &mut inner, + &canceled_outcome(child_conversation_id, "parent canceled"), + ); + Disposition::ParentCanceled + } + // Nothing beat us — register the running task for a future + // resolver, deregistering the in-flight record adjacent to the + // insert with no `.await` between (so a parent cancel serialized + // AFTER us finds it in `running` and drains it). + (None, None) => { + inner.running.insert( + call_id.clone(), + RunningTask { + child_connection_id: child_connection_id.clone(), + child_conversation_id, + parent_connection_id: req.parent_connection_id.clone(), + parent_tool_use_id: req.parent_tool_use_id.clone(), + agent_type: req.agent_type, + task_preview: task_preview.clone(), + task_id: call_id.clone(), + external_handle: req.external_handle.clone(), + started_at, + last_surfaced_block: None, + }, + ); + inner.deregister_inflight(inflight_id); + Disposition::Running + } + } + }; + + match disposition { + // A child terminal beat registration. Finalize (terminal meta + + // DelegationCompleted event + child teardown) and return the + // terminal report directly. The completed entry was recorded under + // the disposition lock above; wake any long-poll waiter. + Disposition::ChildTerminal(outcome) => { + self.finalize_delegation( + &req.parent_connection_id, + &req.parent_tool_use_id, + &child_connection_id, + child_conversation_id, + req.agent_type, + setup_duration_ms, + &outcome, + &task_preview, + &call_id, + ) + .await; + self.result_notify.notify_waiters(); + return report_from_outcome( + Some(call_id), + Some(req.agent_type), + &outcome, + Some(setup_duration_ms), + ); + } + // A parent cancel reached this delegation mid-setup — after the + // prompt was sent, before we registered. Tear the child down + // ourselves (cancel + disconnect, since a turn is in flight) and + // return a canceled report. The canceled result was recorded above. + Disposition::ParentCanceled => { + self.write_meta_if_real( + &req.parent_connection_id, + &req.parent_tool_use_id, + build_delegation_meta( + "failed", + Some(&child_connection_id), + Some(child_conversation_id), + Some("canceled"), + None, + Some(setup_duration_ms), + Some(&task_preview), + Some(&call_id), + ), + ) + .await; + self.emit_completed_if_real( + &req.parent_connection_id, + &req.parent_tool_use_id, + &child_connection_id, + child_conversation_id, + req.agent_type, + DelegationResultSummary::Err { + error_code: "canceled".to_string(), + }, + ) + .await; + let _ = self.spawner.cancel(&child_connection_id).await; + let _ = self.spawner.disconnect(&child_connection_id).await; + self.result_notify.notify_waiters(); + return report_from_outcome( + Some(call_id), + Some(req.agent_type), + &canceled_outcome(child_conversation_id, "parent canceled"), + Some(setup_duration_ms), + ); + } + // Registered in `running` — fall through to the second pre-cancel + // check, then return the ack. + Disposition::Running => {} + } + + // Second pre-cancel check: a `notifications/cancelled` may have landed + // between the entry-side check and the `running` registration above. If + // so, drain the task ourselves (so a racing `cancel_by_external_handle` + // doesn't double-finalize), record the canceled result, and return a + // canceled report instead of the Running ack. + if let Some(handle) = req.external_handle.as_deref() { + if self.take_pre_canceled_handle(handle).await { + // Capture the elapsed ONCE at terminalization (under the lock, + // when the running task is removed) so the completed-cache, the + // parent-card meta, and the returned report all report the same + // duration. `None` when nothing was drained. + let canceled_duration_ms = { + let mut inner = self.pending.inner.lock().await; + if inner.running.remove(&call_id).is_some() { + let outcome = + canceled_outcome(child_conversation_id, "canceled before await"); + let duration_ms = started_at.elapsed().as_millis() as u64; + inner.insert_completed( + &call_id, + build_completed( + &req.parent_connection_id, + child_conversation_id, + req.agent_type, + duration_ms, + &outcome, + ), + ); + Some(duration_ms) + } else { + None + } + }; + if let Some(duration_ms) = canceled_duration_ms { + self.write_meta_if_real( + &req.parent_connection_id, + &req.parent_tool_use_id, + build_delegation_meta( + "failed", + Some(&child_connection_id), + Some(child_conversation_id), + Some("canceled"), + None, + Some(duration_ms), + Some(&task_preview), + Some(&call_id), + ), + ) + .await; + self.emit_completed_if_real( + &req.parent_connection_id, + &req.parent_tool_use_id, + &child_connection_id, + child_conversation_id, + req.agent_type, + DelegationResultSummary::Err { + error_code: "canceled".to_string(), + }, + ) + .await; + let _ = self.spawner.cancel(&child_connection_id).await; + let _ = self.spawner.disconnect(&child_connection_id).await; + self.result_notify.notify_waiters(); + return report_from_outcome( + Some(call_id), + Some(req.agent_type), + &canceled_outcome(child_conversation_id, "canceled before await"), + Some(duration_ms), + ); + } + } + } + + // Registered and running in the background — return the ack. The child + // resolves later via the lifecycle → `complete_call` (or a cancel path). + running_ack(call_id, child_conversation_id, req.agent_type) + } + + /// Called by the child-session lifecycle subscriber on `TurnComplete` + /// (success path) or by error mappers (failure path). + /// + /// Migrates the task from `running` into `completed` (atomically, under one + /// lock) and then finalizes (terminal meta + `DelegationCompleted` event + + /// child teardown) and wakes any `get_delegation_status` long-poll. + /// + /// If no entry is in `running` under `call_id`, the outcome is buffered for + /// a racing `start_delegation` to drain at registration — but ONLY while the + /// delegation is still reserved (mid-setup). This closes the window where a + /// fast/empty turn's `TurnComplete` propagates through the lifecycle while + /// `start_delegation` is still between `send_prompt` and the `running` + /// insert: the prompt is only *enqueued* by `send_prompt`, and the child + /// loop emits `TurnComplete` independently, so a completion CAN beat it. When + /// the `call_id` is no longer reserved the call was already resolved by + /// another terminal path, so the buffer is skipped (silent no-op). + pub async fn complete_call(&self, call_id: &str, outcome: DelegationOutcome) { + let task = { + let mut inner = self.pending.inner.lock().await; + match inner.running.remove(call_id) { + Some(task) => { + // Atomic running → completed so a concurrent status query + // never sees the task as neither running nor completed. + let duration_ms = task.started_at.elapsed().as_millis() as u64; + inner.insert_completed( + call_id, + build_completed( + &task.parent_connection_id, + task.child_conversation_id, + task.agent_type, + duration_ms, + &outcome, + ), + ); + Some((task, duration_ms)) + } + None => { + // Buffer for the racing `start_delegation` to drain iff still + // reserved (mid-setup); a no-op otherwise, so the clone only + // materializes on the genuine pre-registration race. + inner.buffer_early_complete(call_id, outcome.clone()); + None + } + } + }; + if let Some((task, duration_ms)) = task { + self.finalize_delegation( + &task.parent_connection_id, + &task.parent_tool_use_id, + &task.child_connection_id, + task.child_conversation_id, + task.agent_type, + duration_ms, + &outcome, + &task.task_preview, + &task.task_id, + ) + .await; + self.result_notify.notify_waiters(); + } + } + + /// Write the terminal meta, emit `DelegationCompleted`, and tear down the + /// child for a resolved delegation. Shared by `complete_call` and + /// `start_delegation`'s early-terminal pickup. Mirrors the resolution onto + /// the parent's `delegate_to_agent` ToolCallState meta (including a bounded + /// `text_preview` on the completed path so a post-refresh snapshot renders + /// the result inline) so snapshot recovery shows the final state without the + /// live `delegation_completed` event. Does not touch the pending maps — the + /// caller owns the `running` → `completed` migration. + /// + /// `duration_ms` is the broker-measured elapsed time (from `started_at`), + /// carried onto the event summary so the parent UI shows a real duration. + #[allow(clippy::too_many_arguments)] + async fn finalize_delegation( + &self, + parent_connection_id: &str, + parent_tool_use_id: &str, + child_connection_id: &str, + child_conversation_id: i32, + agent_type: AgentType, + duration_ms: u64, + outcome: &DelegationOutcome, + task_preview: &str, + task_id: &str, + ) { + let meta = match outcome { + DelegationOutcome::Ok(ok) => build_delegation_meta( + "completed", + Some(child_connection_id), + Some(child_conversation_id), + None, + build_text_preview(&ok.text).as_deref(), + Some(duration_ms), + Some(task_preview), + Some(task_id), + ), + DelegationOutcome::Err { code, .. } => build_delegation_meta( + "failed", + Some(child_connection_id), + Some(child_conversation_id), + Some(code), + None, + Some(duration_ms), + Some(task_preview), + Some(task_id), + ), + }; + self.write_meta_if_real(parent_connection_id, parent_tool_use_id, meta) + .await; + self.emit_completed_if_real( + parent_connection_id, + parent_tool_use_id, + child_connection_id, + child_conversation_id, + agent_type, + outcome_to_summary(outcome, duration_ms), + ) + .await; + // v1 one-shot: always tear down the child. + let _ = self.spawner.disconnect(child_connection_id).await; + } + + /// Internal helper — apply the meta write iff the parent's + /// `tool_use_id` refers to a real ACP `tool_call_id`. The + /// broker-synthesized `"delegation-"` placeholder targets no + /// ToolCallState, so emitting a `ToolCallUpdate` against it would be + /// noise that the frontend would route through `apply_tool_call_update` + /// to a non-existent entry. See `meta_writer::is_synthetic_parent_tool_use_id`. + async fn write_meta_if_real( + &self, + parent_connection_id: &str, + parent_tool_use_id: &str, + meta: serde_json::Value, + ) { + if is_synthetic_parent_tool_use_id(parent_tool_use_id) { + return; + } + self.meta_writer + .write_meta(parent_connection_id, parent_tool_use_id, meta) + .await; + } + + /// Internal helper — emit `AcpEvent::DelegationStarted` on the parent's + /// stream iff the `parent_tool_use_id` refers to a real ACP tool_call. + /// Mirror of `emit_completed_if_real`: same synthetic-id skip, and the + /// event rides the parent's stream so the frontend `DelegationContext` + /// receives it via the parent's per-connection attach stream in + /// web/server mode (not only via the desktop firehose). + #[allow(clippy::too_many_arguments)] + async fn emit_started_if_real( + &self, + parent_connection_id: &str, + parent_tool_use_id: &str, + child_connection_id: &str, + child_conversation_id: i32, + agent_type: AgentType, + task_preview: &str, + task_id: &str, + ) { + if is_synthetic_parent_tool_use_id(parent_tool_use_id) { + return; + } + self.event_emitter + .emit_started( + parent_connection_id, + parent_tool_use_id, + child_connection_id, + child_conversation_id, + agent_type, + task_preview, + task_id, + ) + .await; + } + + /// Internal helper — emit `AcpEvent::DelegationCompleted` on the parent's + /// stream iff the `parent_tool_use_id` refers to a real ACP tool_call. + /// Synthetic ids (the `"delegation-"` UUID fallback) map to no + /// live UI binding, so the emit would be wasted noise — same skip + /// criterion as `write_meta_if_real`. + async fn emit_completed_if_real( + &self, + parent_connection_id: &str, + parent_tool_use_id: &str, + child_connection_id: &str, + child_conversation_id: i32, + agent_type: AgentType, + result: DelegationResultSummary, + ) { + if is_synthetic_parent_tool_use_id(parent_tool_use_id) { + return; + } + self.event_emitter + .emit_completed( + parent_connection_id, + parent_tool_use_id, + child_connection_id, + child_conversation_id, + agent_type, + result, + ) + .await; + } + + /// Cancel the pending delegation whose `external_handle` matches. + /// Called by the MCP listener on receipt of `notifications/cancelled` + /// from a companion. When no matching pending entry exists (the + /// cancel arrived before `handle_request` reached the + /// pending-registration phase) the handle is stashed in + /// `pre_canceled_handles` so the in-flight request can drain itself + /// when it tries to register or shortly after. + pub async fn cancel_by_external_handle(&self, external_handle: &str, reason: String) { + let drained = { + let mut inner = self.pending.inner.lock().await; + let keys: Vec = inner + .running + .iter() + .filter(|(_, v)| v.external_handle.as_deref() == Some(external_handle)) + .map(|(k, _)| k.clone()) + .collect(); + drain_and_record_canceled(&mut inner, keys, &reason) + }; + if drained.is_empty() { + // Race: the cancel beat the handle's `running` registration. Buffer + // it (capped, FIFO-evicted) so `start_delegation` can drain itself on + // the next checkpoint instead of proceeding to spawn the child. + self.buffer_pre_canceled_handle(external_handle.to_string()) + .await; + return; + } + for (task, duration_ms) in drained { + // A turn is in flight, so cancel + disconnect. + self.teardown_canceled_child(&task, duration_ms, true).await; + } + self.result_notify.notify_waiters(); + } + + /// Resolve the pending delegation whose child matches + /// `child_connection_id` with a `canceled` outcome. Used when a child + /// session disconnects or errors out without firing a clean + /// TurnComplete — the parent's `tool_use_id` shouldn't dangle. + /// No-op when no matching entry exists. + /// + /// `terminal_error` carries the child connection's last `AcpEvent::Error` + /// detail when the lifecycle worker is dispatching off an `Error` event + /// (vs. a bare `Disconnected`). When present, it gets appended to the + /// `Canceled { reason }` string so the parent agent's tool-call result + /// surfaces the real cause (e.g. "Authentication required", + /// "transport closed") instead of the opaque default. Falls back to + /// the default reason when `None`. + pub async fn cancel_by_child_connection( + &self, + child_connection_id: &str, + terminal_error: Option<&str>, + ) { + let reason = child_canceled_reason(terminal_error); + let drained = { + let mut inner = self.pending.inner.lock().await; + let keys: Vec = inner + .running + .iter() + .filter(|(_, v)| v.child_connection_id == child_connection_id) + .map(|(k, _)| k.clone()) + .collect(); + if keys.is_empty() { + // No running entry. If the child is still reserved, + // `start_delegation` is mid-setup and this failure beat the + // `running` insert — buffer its detail for it to drain at + // registration instead of no-oping. `buffer_child_failure` is a + // no-op when the child isn't reserved, so a normal + // post-resolution child teardown accumulates nothing. + inner.buffer_child_failure( + child_connection_id, + terminal_error.map(|s| s.to_string()), + ); + Vec::new() + } else { + drain_and_record_canceled(&mut inner, keys, &reason) + } + }; + for (task, duration_ms) in drained { + // The child already disconnected/errored — disconnect-only teardown + // (no spawner `cancel`, there's no live turn to interrupt). + self.teardown_canceled_child(&task, duration_ms, false).await; + } + self.result_notify.notify_waiters(); + } + + /// Cascade-cancel every pending delegation owned by `parent_connection_id` + /// when the parent **connection tears down** (disconnect / `run_connection` + /// exit). Drops the parent's entire tool_call tracker bucket (`pending` + + /// `consumed`) since the connection is going away. Runs fully inline — the + /// connection is already exiting, so there is no next prompt to unblock. + pub async fn cancel_by_parent(&self, parent_connection_id: &str) { + let drained = self + .drain_for_parent_cancel(parent_connection_id, false) + .await; + self.finalize_parent_cancel(drained).await; + } + + /// Cascade-cancel every pending delegation owned by `parent_connection_id` + /// for a **turn/prompt cancel** where the parent connection STAYS ALIVE + /// (a non-`end_turn` turn end, or a user Cancel between/within prompts). + /// + /// The fast, turn-scoped part — tombstoning the tool_call tracker and + /// removing this parent's parked calls — runs SYNCHRONOUSLY: the caller + /// awaits it before the connection loop accepts the next prompt, so it can't + /// race a next-turn registration and tombstone/cancel that turn's legitimate + /// entries (the safety the `drop_tool_calls_for_parent` invariant relies + /// on). Only the slow child teardown (meta/emit + spawner `cancel` / + /// `disconnect`, which can block on slow agents) is backgrounded, so the + /// user-visible Cancel path stays responsive. + /// + /// RETAINS the parent's `consumed` tool_call memory (and tombstones the + /// cancelled turn's unclaimed `pending` ids into it): dropping it would let + /// a host re-emit of an already-handled `tool_call_id` re-register and + /// mis-bind the next same-key delegation on this live connection — see + /// `drop_tool_calls_for_parent`. + pub async fn cancel_by_parent_turn(&self, parent_connection_id: &str) { + let drained = self + .drain_for_parent_cancel(parent_connection_id, true) + .await; + // The fast drain above already ran inline (scoped to the just-ended + // turn); background only the slow child teardown. + let broker = self.clone(); + tokio::spawn(async move { + broker.finalize_parent_cancel(drained).await; + }); + } + + /// Fast, lock-guarded part of a parent cancel: drop/tombstone this parent's + /// tool_call tracker (per `keep_consumed`, see `drop_tool_calls_for_parent`) + /// and remove every running task it owns, returning them for the (slow) + /// child teardown. Touches only the two broker mutexes — no spawner I/O — so + /// it is safe to await inline in the connection loop before the next prompt + /// is accepted. + /// + /// `keep_consumed` also governs the completed-cache: a **turn** cancel + /// (`true`) records each drained task as `Canceled` so the still-alive + /// connection's LLM can still query it; a **connection teardown** (`false`) + /// drops the parent's whole completed-cache instead — the parent is gone, so + /// nothing will query it. + async fn drain_for_parent_cancel( + &self, + parent_connection_id: &str, + keep_consumed: bool, + ) -> Vec<(RunningTask, u64)> { + // Also drain any tool_call ids captured ahead of an MCP round-trip that + // never arrived — keeps the map bounded across parent reconnects. + // Teardown drops the whole bucket; a turn cancel keeps `consumed` so a + // later re-emit can't mis-bind the next delegation. + self.drop_tool_calls_for_parent(parent_connection_id, keep_consumed) + .await; + let drained = { + let mut inner = self.pending.inner.lock().await; + // Flag every still-in-flight setup this parent owns in the SAME lock + // acquisition that drains its running tasks: a delegation is then + // caught either here (mid-setup → `start_delegation` tears its child + // down at the next checkpoint) or by the running drain below (already + // registered) — there is no interleaving where both miss it. + inner.mark_inflight_canceled_for_parent(parent_connection_id); + let keys: Vec = inner + .running + .iter() + .filter(|(_, v)| v.parent_connection_id == parent_connection_id) + .map(|(k, _)| k.clone()) + .collect(); + if keep_consumed { + // Turn cancel: connection stays alive → keep each canceled + // result queryable. + drain_and_record_canceled(&mut inner, keys, "parent canceled") + } else { + // Connection teardown: just remove the running tasks and drop the + // whole completed-cache for this parent. No completed entry to + // match, but still capture the elapsed once (at drain time) so + // the teardown meta doesn't recompute it later. + let drained: Vec<(RunningTask, u64)> = keys + .into_iter() + .map(|k| { + let task = inner.running.remove(&k).expect("key just observed"); + let duration_ms = task.started_at.elapsed().as_millis() as u64; + (task, duration_ms) + }) + .collect(); + inner.drop_completed_for_parent(parent_connection_id); + drained + } + }; + self.result_notify.notify_waiters(); + drained + } + + /// Slow part of a parent cancel: for each drained task, patch the parent + /// meta, emit `DelegationCompleted`, and tear the child down. The canceled + /// result was already recorded into `completed` (turn cancel) by + /// `drain_for_parent_cancel` under the lock, so this is pure I/O. Split out + /// so a turn cancel can background it without delaying the fast, turn-scoped + /// drain. + async fn finalize_parent_cancel(&self, drained: Vec<(RunningTask, u64)>) { + for (task, duration_ms) in drained { + // A turn was in flight → cancel + disconnect. + self.teardown_canceled_child(&task, duration_ms, true).await; + } + } + + /// Shared canceled-child teardown: best-effort `failed`/`canceled` meta + /// patch (so a parent-side snapshot post-cancel shows the delegation as + /// canceled rather than stuck on "running"), a `DelegationCompleted` err + /// event, then child teardown. `cancel_turn` is `true` when a turn is in + /// flight (cancel + disconnect) and `false` when the child already + /// disconnected/errored (disconnect only). Does NOT touch the pending maps — + /// the caller already migrated the task into `completed`. + /// + /// `duration_ms` is the elapsed captured by `drain_and_record_canceled` at + /// drain time — reused here (not recomputed) so the parent-card meta matches + /// the completed-cache duration the status/cancel cards report, even when + /// this teardown is backgrounded. + async fn teardown_canceled_child( + &self, + task: &RunningTask, + duration_ms: u64, + cancel_turn: bool, + ) { + self.write_meta_if_real( + &task.parent_connection_id, + &task.parent_tool_use_id, + build_delegation_meta( + "failed", + Some(&task.child_connection_id), + Some(task.child_conversation_id), + Some("canceled"), + None, + Some(duration_ms), + Some(&task.task_preview), + Some(&task.task_id), + ), + ) + .await; + self.emit_completed_if_real( + &task.parent_connection_id, + &task.parent_tool_use_id, + &task.child_connection_id, + task.child_conversation_id, + task.agent_type, + DelegationResultSummary::Err { + error_code: "canceled".to_string(), + }, + ) + .await; + if cancel_turn { + let _ = self.spawner.cancel(&task.child_connection_id).await; + } + let _ = self.spawner.disconnect(&task.child_connection_id).await; + } + + /// Backs the `get_delegation_status` tool for a single task id — a thin + /// wrapper over [`Self::get_tasks_status`] so the single- and batch-poll + /// paths share one snapshot/wait implementation. A one-id batch's + /// "any task settled" wake condition is exactly "this task settled", so the + /// blocking semantics are identical to the historical single-task loop. + pub async fn get_task_status( + &self, + parent_connection_id: &str, + parent_conversation_id: Option, + task_id: &str, + wait: StatusWait, + ) -> DelegationTaskReport { + let ids = [task_id.to_string()]; + self.get_tasks_status(parent_connection_id, parent_conversation_id, &ids, wait) + .await + .pop() + .unwrap_or_else(|| unknown_report(task_id)) + } + + /// Wake every parked status long-poll so it can re-probe its children. + /// + /// Called by the lifecycle dispatcher when ANY connection raises or resolves + /// a blocking prompt — permission, question, or plan approval. Cheap and + /// unconditional: these events are rare, and a wake for a connection that + /// isn't anybody's delegation child just re-snapshots and re-parks, exactly + /// like the spurious wakes `get_tasks_status` already tolerates. + pub fn note_blocking_changed(&self) { + self.result_notify.notify_waiters(); + } + + /// Backs the batch `get_delegation_status` tool. Resolves the status of one + /// or many task ids in a single pass — each from the completed-cache, then + /// the running set, then the DB fallback — scoped to the calling parent (a + /// task owned by another parent reports `Unknown`, never leaking it). Returns + /// one report per requested id, in request order. + /// + /// Blocking obeys [`StatusWait`]: `Immediate` returns the first snapshot. + /// `Bounded`/`Infinite` return as soon as ANY requested task is terminal — + /// INCLUDING one already terminal at entry, so a completed result is never + /// held hostage to a long-running sibling (the caller re-polls the + /// still-running ids to collect the rest) — **or as soon as one becomes + /// blocked on a user decision**. Only an all-running, nothing-newly-blocked + /// batch parks: it wakes when a task settles (the running count drops below + /// the total), when a child raises a blocking prompt, or — for `Bounded` — + /// when the deadline elapses. An all-settled batch returns immediately even + /// under `Infinite`, so it never parks forever. + /// + /// The blocked-return is what closes #447. Without it, a child that hits a + /// permission prompt parks the parent's `wait_ms: 0` call for as long as the + /// user takes to notice — indefinitely, for an unattended run — and the + /// orchestrating LLM cannot even report the stall, because "working" and + /// "waiting on a human" look identical from here. Each blocking prompt is + /// surfaced ONCE (see `RunningTask::last_surfaced_block`), so re-polling an + /// already-reported block goes back to waiting rather than spinning. + pub async fn get_tasks_status( + &self, + parent_connection_id: &str, + parent_conversation_id: Option, + task_ids: &[String], + wait: StatusWait, + ) -> Vec { + if task_ids.is_empty() { + return Vec::new(); + } + // A bounded wait gets a single fixed deadline; Immediate and Infinite + // carry none — Immediate returns on the first pass, Infinite parks on + // `result_notify` until a task is terminal or newly blocked. + let deadline = match wait { + StatusWait::Bounded(ms) => Some(Instant::now() + Duration::from_millis(ms)), + StatusWait::Immediate | StatusWait::Infinite => None, + }; + loop { + // Arm the notify BEFORE the snapshot so a completion landing between + // the snapshot and the await isn't lost (enable() registers now). + let notified = self.result_notify.notified(); + tokio::pin!(notified); + notified.as_mut().enable(); + + // One lock acquisition classifies every requested id. The async + // resolution of running (live reply) / not-in-memory (DB) ids is + // deferred to `assemble_reports`, OUTSIDE this lock. + let classes: Vec = { + let inner = self.pending.inner.lock().await; + task_ids + .iter() + .map(|id| classify_locked(&inner, parent_connection_id, id)) + .collect() + }; + let running_count = classes + .iter() + .filter(|c| matches!(c, StatusClass::Running { .. })) + .count(); + + // Probe each running child for a blocking prompt. Done HERE, after + // the pending lock was dropped at the end of the block above and + // before any early return, because it takes the child's + // `SessionState` lock — the same ordering `attach_live_reply` has + // always used. The result rides along to `assemble_reports` so a + // pass never probes the same child twice. + let blocked = self.probe_blocked(&classes).await; + + // Return now when the poll is Immediate, OR when at least one + // requested task is already (or now) terminal — i.e. not EVERY task + // is still running. This honors the contract "returns as soon as ANY + // requested task reaches a terminal state": a mixed [terminal, + // running] batch surfaces the terminal report immediately instead of + // holding it hostage to a long-running sibling, and the caller + // re-polls (narrowing to the still-running ids) to collect the rest. + // `running_count == 0` (all settled) is the special case that also + // makes Infinite safe. The id set is fixed and a task can only LEAVE + // the running map during a wait (never (re)enter), so once a parked + // all-running batch is woken by a settle the count has dropped below + // the total and this returns; a spurious wake (another parent's task) + // re-snapshots all-running and re-parks. + if matches!(wait, StatusWait::Immediate) || running_count < task_ids.len() { + return self + .assemble_reports(parent_conversation_id, task_ids, classes, blocked) + .await; + } + // Every task is still running, but one of them just parked on the + // user. That is not progress and no completion signal is coming + // until a human acts, so stop waiting and say so. The claim marks + // each prompt as surfaced, so the NEXT poll on the same prompt falls + // through to the park below instead of returning instantly. + let claimed = self.claim_new_blocks(task_ids, &blocked).await; + if claimed.any_claimed { + return self + .assemble_reports(parent_conversation_id, task_ids, classes, blocked) + .await; + } + // A `Bounded` wait gives up at its deadline and returns the running + // snapshot. + let now = Instant::now(); + if deadline.is_some_and(|d| now >= d) { + return self + .assemble_reports(parent_conversation_id, task_ids, classes, blocked) + .await; + } + // Park until the next completion signal — bounded by the deadline + // when there is one, and ALWAYS bounded by `retry_at` when a + // suppressed block is waiting to become reportable again. Without + // that second bound an `Infinite` wait would park on a notify that + // nothing is going to fire: a child parked on a permission emits + // nothing further by itself, so the resurface valve would never get + // a chance to run and a report lost in transit would strand the + // caller for good. + let wake_at = match (deadline, claimed.retry_at) { + (Some(d), Some(r)) => Some(d.min(r)), + (d, r) => d.or(r), + }; + match wake_at { + Some(t) => { + let remaining = t.saturating_duration_since(now); + tokio::select! { + _ = &mut notified => {} + _ = tokio::time::sleep(remaining) => {} + } + } + None => { + notified.await; + } + } + // Loop: re-snapshot (a task likely just completed, the deadline + // passed and the next pass returns the running snapshot, or a + // suppressed block is now reportable again). + } + } + + /// Ask each `Running` entry's child what it is blocked on, position-aligned + /// with `classes` (non-running slots are `None`). One probe per child per + /// pass; must be called with the pending lock RELEASED (it takes the child's + /// `SessionState` lock). + async fn probe_blocked(&self, classes: &[StatusClass]) -> Vec> { + let mut out = Vec::with_capacity(classes.len()); + for class in classes { + let blocked = match class { + StatusClass::Running { + child_connection_id, + .. + } => self.live_reply_lookup.blocked_on(child_connection_id).await, + _ => None, + }; + out.push(blocked); + } + out + } + + /// Claim the blocking prompts in `blocked` that are reportable right now, + /// returning whether any was — and, when none was, the earliest [`Instant`] + /// at which one becomes reportable again. + /// + /// This is the ratchet: a `wait_ms: 0` poll returns the first time a child + /// parks, but a re-poll while the SAME prompt is still unanswered finds + /// nothing new and goes back to waiting — otherwise the caller's wait loop + /// would return instantly forever and burn a round-trip per iteration while + /// the user is simply slow to click. A second, different prompt is new + /// again and returns, and so does the same prompt once + /// [`BLOCK_RESURFACE_INTERVAL`] has passed (the delivery-failure valve — see + /// [`RunningTask::last_surfaced_block`]). + /// + /// Positionally aligned with `task_ids`. Silently skips ids no longer in the + /// running map (settled between the snapshot and here) — those return via + /// the terminal path on the next pass anyway. + async fn claim_new_blocks( + &self, + task_ids: &[String], + blocked: &[Option], + ) -> ClaimedBlocks { + let mut out = ClaimedBlocks::default(); + if blocked.iter().all(|b| b.is_none()) { + return out; + } + let now = Instant::now(); + let mut inner = self.pending.inner.lock().await; + for (id, blocked) in task_ids.iter().zip(blocked) { + let Some(blocked) = blocked else { continue }; + let Some(task) = inner.running.get_mut(id) else { + continue; + }; + if let Some(prev) = task.last_surfaced_block.as_ref() { + if prev.request_id == blocked.request_id { + let due = prev.at + self.block_resurface; + if now < due { + // Not reportable yet. Deliberately does NOT refresh + // `at` — that would push the valve out forever under + // repeated polling. + out.retry_at = Some(out.retry_at.map_or(due, |t: Instant| t.min(due))); + continue; + } + } + } + task.last_surfaced_block = Some(SurfacedBlock { + request_id: blocked.request_id.clone(), + at: now, + }); + out.any_claimed = true; + } + out + } + + /// Finish a batch status pass: resolve each [`StatusClass`] into a final + /// report AFTER the pending lock is released. `Running` ids get their latest + /// live reply (or blocking prompt) attached; `NotInMemory` ids fall back to + /// the DB status lookup. Reports come back in `task_ids` order. + /// + /// `blocked` is the already-probed result from [`Self::probe_blocked`] for + /// this same pass, position-aligned with `classes`. + async fn assemble_reports( + &self, + parent_conversation_id: Option, + task_ids: &[String], + classes: Vec, + blocked: Vec>, + ) -> Vec { + let mut out = Vec::with_capacity(classes.len()); + let mut blocked = blocked.into_iter().chain(std::iter::repeat_with(|| None)); + for (id, class) in task_ids.iter().zip(classes) { + let blocked = blocked.next().flatten(); + let report = match class { + StatusClass::Settled(report) => report, + StatusClass::Running { + mut report, + child_connection_id, + } => { + match blocked { + // A blocked child's last reply is stale by definition — + // it is what it said BEFORE it stopped — so the block + // replaces it rather than competing with it. + Some(blocked) => attach_blocked(&mut report, blocked), + None => { + self.attach_live_reply(&mut report, &child_connection_id) + .await + } + } + report + } + StatusClass::NotInMemory => self.status_from_db(parent_conversation_id, id).await, + }; + out.push(report); + } + out + } + + /// Upgrade a running report's bare `"Running."` message with the child's + /// latest one-line activity, so the parent LLM gets a concrete sign of + /// progress it can report in one shot (instead of polling-and-narrating). + /// Called only on the actual running-return paths, AFTER the pending lock is + /// released. A no-op when the lookup has nothing (default Noop lookup, child + /// gone, or no live output yet) — the report stays `"Running."`. + /// + /// The hint goes on its OWN line (`"Running.\nLatest sub-agent reply: …"`), + /// not appended to the marker line. On hosts that persist only the + /// `CallToolResult` content text (e.g. Claude Code), the frontend recognizes + /// a still-running poll by the standalone first line `"Running."` — keeping + /// the child-controlled reply text on a separate line means a *completed* + /// result that merely starts with "Running. …" can never be misread as + /// running. See `textRunningStatus` in `src/lib/delegation-status.ts`. + async fn attach_live_reply( + &self, + report: &mut DelegationTaskReport, + child_connection_id: &str, + ) { + if let Some(reply) = self + .live_reply_lookup + .latest_reply(child_connection_id) + .await + { + report.message = Some(format!("Running.\nLatest sub-agent reply: {reply}")); + } + } + + /// Backs the `cancel_delegation` tool. Cancels a running task owned by the + /// caller (recording it `Canceled` + tearing the child down) and returns the + /// resulting report. A task that already finished returns its terminal + /// report; one not in memory falls back to the DB status (a finished task + /// can't be canceled). Parent-scoped like `get_task_status`. + pub async fn cancel_task_by_id( + &self, + parent_connection_id: &str, + parent_conversation_id: Option, + task_id: &str, + ) -> DelegationTaskReport { + let drained = { + let mut inner = self.pending.inner.lock().await; + if let Some(c) = inner.completed.get(task_id) { + if c.parent_connection_id == parent_connection_id { + return completed_report(task_id, c); + } + return unknown_report(task_id); + } + match inner.running.get(task_id) { + Some(r) if r.parent_connection_id == parent_connection_id => { + drain_and_record_canceled( + &mut inner, + vec![task_id.to_string()], + "canceled by request", + ) + .pop() + } + Some(_) => return unknown_report(task_id), + None => None, + } + }; + match drained { + Some((task, duration_ms)) => { + // A turn is in flight → cancel + disconnect. Reuse the duration + // captured at drain time for both the teardown meta and the + // report, so all three (completed-cache, meta, report) agree. + self.teardown_canceled_child(&task, duration_ms, true).await; + self.result_notify.notify_waiters(); + report_from_outcome( + Some(task_id.to_string()), + Some(task.agent_type), + &canceled_outcome(task.child_conversation_id, "canceled by request"), + Some(duration_ms), + ) + } + None => self.status_from_db(parent_conversation_id, task_id).await, + } + } + + /// DB status fallback for a task evicted from / never in the in-memory maps. + /// Scopes to the caller's conversation: a child whose `parent_id` doesn't + /// match (or when the caller has no active conversation) reports `Unknown`. + async fn status_from_db( + &self, + parent_conversation_id: Option, + task_id: &str, + ) -> DelegationTaskReport { + match self.status_lookup.find_by_call_id(task_id).await { + Some(rec) + if parent_conversation_id.is_some() && rec.parent_id == parent_conversation_id => + { + db_report(task_id, &rec) + } + _ => unknown_report(task_id), + } + } + + /// Test-only shim preserving the old blocking `handle_request` contract over + /// the async path: start the delegation, then block until it reaches a + /// terminal state (driven by the test's `complete_call` / cancel), mapping + /// the terminal report back to a `DelegationOutcome`. Keeps the broker's + /// extensive setup-window race tests exercising the same lifecycle without + /// each rewriting to the start/poll/collect shape. + #[cfg(any(test, feature = "test-utils"))] + pub async fn handle_request(&self, req: DelegationRequest) -> DelegationOutcome { + let parent_connection_id = req.parent_connection_id.clone(); + let parent_conversation_id = Some(req.parent_conversation_id); + let ack = self.start_delegation(req).await; + let task_id = match ack.task_id.clone() { + Some(id) => id, + // Setup failed before a task existed — the ack itself is terminal. + None => return report_to_outcome(&ack), + }; + if ack.status != TaskStatus::Running { + return report_to_outcome(&ack); + } + // Block until terminal via the long-poll path (re-issued so an + // indefinitely-pending task in a test simply parks here, mirroring the + // old unbounded `rx.await`). + loop { + let report = self + .get_task_status( + &parent_connection_id, + parent_conversation_id, + &task_id, + StatusWait::Bounded(3_600_000), + ) + .await; + if report.status != TaskStatus::Running { + return report_to_outcome(&report); + } + } + } + + #[cfg(any(test, feature = "test-utils"))] + pub async fn peek_first_pending_call_id(&self) -> Option { + self.pending + .inner + .lock() + .await + .running + .keys() + .next() + .cloned() + } + + #[cfg(any(test, feature = "test-utils"))] + pub async fn pending_count(&self) -> usize { + self.pending.inner.lock().await.running.len() + } + + /// Count of cached completed results across all parents. + #[cfg(any(test, feature = "test-utils"))] + pub async fn completed_count(&self) -> usize { + self.pending.inner.lock().await.completed.len() + } + + /// Count of in-flight (registered-at-entry, not-yet-parked / not-yet-exited) + /// `handle_request` setups. Should return to 0 on every exit path. + #[cfg(any(test, feature = "test-utils"))] + pub async fn inflight_count(&self) -> usize { + self.pending.inner.lock().await.inflight.len() + } + + /// Count of in-setup (reserved, not-yet-parked) delegations. Each holds one + /// child and one call_id, so this counts both. + #[cfg(any(test, feature = "test-utils"))] + pub async fn reserved_child_count(&self) -> usize { + self.pending.inner.lock().await.setups.len() + } + + #[cfg(any(test, feature = "test-utils"))] + pub async fn reserved_call_count(&self) -> usize { + self.pending.inner.lock().await.setups.len() + } + + #[cfg(any(test, feature = "test-utils"))] + pub async fn early_cancel_count(&self) -> usize { + self.pending.inner.lock().await.early_cancels.len() + } + + #[cfg(any(test, feature = "test-utils"))] + pub async fn early_complete_count(&self) -> usize { + self.pending.inner.lock().await.early_completes.len() + } + + /// First reserved (mid-setup) `call_id`, if any — lets a test resolve a + /// delegation via `complete_call` while it's pinned in the reserve→park + /// window (its entry isn't parked yet, so `peek_first_pending_call_id` + /// can't see it). + #[cfg(any(test, feature = "test-utils"))] + pub async fn peek_reserved_call_id(&self) -> Option { + self.pending + .inner + .lock() + .await + .setups + .keys() + .next() + .cloned() + } +} + +/// `ConversationDepthLookup` over the live `AppDatabase`. Used by the +/// production wiring; tests use the in-module `MockDepth`. +pub struct DbDepthLookup { + pub db: Arc, +} + +#[async_trait] +impl ConversationDepthLookup for DbDepthLookup { + async fn parent_of(&self, conversation_id: i32) -> Result, DelegationError> { + use sea_orm::EntityTrait; + let row = crate::db::entities::conversation::Entity::find_by_id(conversation_id) + .one(&self.db.conn) + .await + .map_err(|e| DelegationError::SubagentRuntimeError(format!("db: {e}")))?; + Ok(row.and_then(|r| r.parent_id)) + } +} + +/// `ChildStatusLookup` over the live `AppDatabase`. Recovers a delegation +/// task's terminal status (NOT its text — child output isn't in codeg's DB) +/// from the child conversation row once its in-memory result was evicted. +pub struct DbChildStatusLookup { + pub db: Arc, +} + +#[async_trait] +impl ChildStatusLookup for DbChildStatusLookup { + async fn find_by_call_id(&self, call_id: &str) -> Option { + let summary = crate::db::service::conversation_service::get_by_delegation_call_id( + &self.db.conn, + call_id, + ) + .await + .ok() + .flatten()?; + // `summary.status` is the serialized `ConversationStatus` string. + let status = match summary.status.as_str() { + "in_progress" => TaskStatus::Running, + "pending_review" | "completed" => TaskStatus::Completed, + "cancelled" => TaskStatus::Canceled, + _ => TaskStatus::Unknown, + }; + Some(ChildStatusRecord { + child_conversation_id: summary.id, + status, + agent_type: summary.agent_type, + parent_id: summary.parent_id, + }) + } +} + +#[cfg(test)] +mod tests { + use super::*; + use crate::acp::delegation::spawner::{mock::MockSpawner, SpawnerError}; + use crate::acp::delegation::types::DelegationSuccess; + use crate::models::AgentType; + + /// Test-only `ConversationDepthLookup` that resolves against a flat + /// (id, parent_id) table. Unknown ids return `Ok(None)` to keep test + /// setup small. + struct MockDepth(Vec<(i32, Option)>); + + #[async_trait] + impl ConversationDepthLookup for MockDepth { + async fn parent_of(&self, id: i32) -> Result, DelegationError> { + Ok(self.0.iter().find(|(c, _)| *c == id).and_then(|(_, p)| *p)) + } + } + + fn shallow_lookup() -> Arc { + // parent conversation is the root — depth = 0, no rejection. + Arc::new(MockDepth(vec![(1, None)])) as Arc + } + + fn request(parent_conv: i32, tool_use: &str) -> DelegationRequest { + DelegationRequest { + parent_connection_id: "parent-conn".into(), + parent_conversation_id: parent_conv, + parent_tool_use_id: tool_use.into(), + agent_type: AgentType::ClaudeCode, + task: "do x".into(), + working_dir: None, + requested_working_dir: None, + external_handle: None, + } + } + + fn request_with_handle(parent_conv: i32, tool_use: &str, handle: &str) -> DelegationRequest { + let mut r = request(parent_conv, tool_use); + r.external_handle = Some(handle.to_string()); + r + } + + /// Bring the broker's `enabled` switch up before driving any test that + /// hits `handle_request`. Production now defaults to `enabled: false`, + /// so a bare `DelegationBroker::new(...)` would short-circuit before + /// parking a pending entry. Tests that assert disabled behavior set + /// their own config explicitly and skip this helper. + async fn enable_delegation(broker: &DelegationBroker) { + broker + .set_config(DelegationConfig { + enabled: true, + ..DelegationConfig::default() + }) + .await; + } + + // -- Task 4.3 ----------------------------------------------------------- + + #[tokio::test] + async fn config_round_trip() { + let broker = DelegationBroker::new( + Arc::new(MockSpawner::new()) as Arc, + shallow_lookup(), + ); + broker + .set_config(DelegationConfig { + enabled: false, + depth_limit: 5, + ..DelegationConfig::default() + }) + .await; + let got = broker.config_snapshot().await; + assert!(!got.enabled); + assert_eq!(got.depth_limit, 5); + } + + #[tokio::test] + async fn disabled_returns_canceled_without_touching_spawner() { + let mock = Arc::new(MockSpawner::new()); + let broker = + DelegationBroker::new(mock.clone() as Arc, shallow_lookup()); + broker + .set_config(DelegationConfig { + enabled: false, + depth_limit: 2, + ..DelegationConfig::default() + }) + .await; + let outcome = broker.handle_request(request(1, "pt-1")).await; + match outcome { + DelegationOutcome::Err { code, .. } => assert_eq!(code, "canceled"), + _ => panic!("expected Err"), + } + assert!(mock.disconnects.lock().await.is_empty()); + } + + // -- Task 4.4: happy path ---------------------------------------------- + + #[tokio::test] + async fn happy_path_returns_ok_after_complete_call() { + let mock = Arc::new(MockSpawner::new()); + mock.queue_spawn(Ok("child-conn-1".into())).await; + mock.queue_send(Ok(42)).await; + let broker = + DelegationBroker::new(mock.clone() as Arc, shallow_lookup()); + enable_delegation(&broker).await; + + let driver = { + let broker = broker.clone(); + tokio::spawn(async move { broker.handle_request(request(1, "pt-1")).await }) + }; + + // Spin until the broker has registered the pending call so the test + // doesn't race the spawn/send awaits. + let call_id = loop { + if let Some(id) = broker.peek_first_pending_call_id().await { + break id; + } + tokio::time::sleep(Duration::from_millis(5)).await; + }; + + broker + .complete_call( + &call_id, + DelegationOutcome::Ok(DelegationSuccess { + text: "4".into(), + child_conversation_id: 42, + child_agent_type: AgentType::Codex, + turn_count: 1, + duration_ms: 50, + token_usage: None, + }), + ) + .await; + + let outcome = driver.await.unwrap(); + match outcome { + DelegationOutcome::Ok(s) => { + assert_eq!(s.text, "4"); + assert_eq!(s.child_conversation_id, 42); + } + other => panic!("expected Ok, got {other:?}"), + } + assert_eq!(broker.pending_count().await, 0); + // complete_call disconnects the child once. + assert_eq!(mock.disconnects.lock().await.as_slice(), &["child-conn-1"]); + } + + /// `StatusWait::Infinite` (the explicit `wait_ms = 0` escape hatch) must + /// park while the task is still running rather than returning the running + /// snapshot, then resolve to the terminal report once the task completes — + /// no matter how long the child takes. + #[tokio::test] + async fn infinite_wait_parks_until_terminal() { + let mock = Arc::new(MockSpawner::new()); + mock.queue_spawn(Ok("child-conn-1".into())).await; + mock.queue_send(Ok(42)).await; + let broker = + DelegationBroker::new(mock.clone() as Arc, shallow_lookup()); + enable_delegation(&broker).await; + + let ack = broker.start_delegation(request(1, "pt-1")).await; + assert_eq!(ack.status, TaskStatus::Running); + let task_id = ack.task_id.clone().expect("running task carries an id"); + + // Infinite wait: parks on the completion signal instead of returning + // the still-running snapshot. + let waiter = { + let broker = broker.clone(); + let task_id = task_id.clone(); + tokio::spawn(async move { + broker + .get_task_status("parent-conn", Some(1), &task_id, StatusWait::Infinite) + .await + }) + }; + + // Give the waiter a beat — it must still be parked, not finished. + tokio::time::sleep(Duration::from_millis(30)).await; + assert!( + !waiter.is_finished(), + "infinite wait must park while the task is running" + ); + + let call_id = loop { + if let Some(id) = broker.peek_first_pending_call_id().await { + break id; + } + tokio::time::sleep(Duration::from_millis(5)).await; + }; + broker + .complete_call( + &call_id, + DelegationOutcome::Ok(DelegationSuccess { + text: "done".into(), + child_conversation_id: 42, + child_agent_type: AgentType::ClaudeCode, + turn_count: 1, + duration_ms: 5, + token_usage: None, + }), + ) + .await; + + let report = waiter.await.unwrap(); + assert_eq!(report.status, TaskStatus::Completed); + assert_eq!(report.text.as_deref(), Some("done")); + } + + /// A running snapshot upgrades its bare `"Running."` message with the child's + /// latest one-line reply when the live-reply lookup has one. + #[tokio::test] + async fn running_status_appends_live_reply_when_available() { + use crate::acp::delegation::live_reply::mock::MockChildLiveReplyLookup; + + let mock = Arc::new(MockSpawner::new()); + mock.queue_spawn(Ok("child-conn-1".into())).await; + mock.queue_send(Ok(42)).await; + let broker = + DelegationBroker::new(mock.clone() as Arc, shallow_lookup()) + .with_live_reply_lookup(Arc::new(MockChildLiveReplyLookup::new(Some( + "Reading config.rs".into(), + )))); + enable_delegation(&broker).await; + + let ack = broker.start_delegation(request(1, "pt-1")).await; + assert_eq!(ack.status, TaskStatus::Running); + let task_id = ack.task_id.clone().expect("running task carries an id"); + + let report = broker + .get_task_status("parent-conn", Some(1), &task_id, StatusWait::Immediate) + .await; + assert_eq!(report.status, TaskStatus::Running); + // The live hint lands on its own line so a content-only host can anchor + // "still running" to the standalone first line "Running.". + assert_eq!( + report.message.as_deref(), + Some("Running.\nLatest sub-agent reply: Reading config.rs") + ); + } + + /// With no live reply (default Noop lookup / child produced nothing yet) the + /// running snapshot stays the bare `"Running."`. + #[tokio::test] + async fn running_status_stays_bare_without_live_reply() { + let mock = Arc::new(MockSpawner::new()); + mock.queue_spawn(Ok("child-conn-1".into())).await; + mock.queue_send(Ok(42)).await; + let broker = + DelegationBroker::new(mock.clone() as Arc, shallow_lookup()); + enable_delegation(&broker).await; + + let ack = broker.start_delegation(request(1, "pt-1")).await; + let task_id = ack.task_id.clone().expect("running task carries an id"); + + let report = broker + .get_task_status("parent-conn", Some(1), &task_id, StatusWait::Immediate) + .await; + assert_eq!(report.status, TaskStatus::Running); + assert_eq!(report.message.as_deref(), Some("Running.")); + } + + // -- Blocked sub-agents (#447) ----------------------------------------- + + fn permission_block(request_id: &str, title: &str) -> BlockedOn { + BlockedOn { + kind: BlockedKind::Permission, + request_id: request_id.into(), + title: Some(title.into()), + } + } + + /// Spin up a broker whose children all report `blocked` (settable later) and + /// one running task on it. Returns `(broker, lookup, task_id)`. + async fn broker_with_blockable_child() -> ( + DelegationBroker, + Arc, + String, + ) { + // The production interval is minutes; every test but the valve one + // wants "effectively never re-surfaces during this test". + broker_with_blockable_child_resurfacing(Duration::from_secs(3600)).await + } + + async fn broker_with_blockable_child_resurfacing( + resurface: Duration, + ) -> ( + DelegationBroker, + Arc, + String, + ) { + use crate::acp::delegation::live_reply::mock::MockChildLiveReplyLookup; + + let mock = Arc::new(MockSpawner::new()); + mock.queue_spawn(Ok("child-conn-1".into())).await; + mock.queue_send(Ok(42)).await; + let lookup = Arc::new(MockChildLiveReplyLookup::new(Some("Reading x".into()))); + let broker = + DelegationBroker::new(mock.clone() as Arc, shallow_lookup()) + .with_live_reply_lookup(lookup.clone()) + .with_block_resurface(resurface); + enable_delegation(&broker).await; + let task_id = broker + .start_delegation(request(1, "pt-1")) + .await + .task_id + .expect("running task carries an id"); + (broker, lookup, task_id) + } + + /// A child parked on a permission reports `Running` + `blocked_on`, and its + /// message says so INSTEAD of the (now stale) live reply. + #[tokio::test] + async fn blocked_child_reports_blocked_on_over_live_reply() { + let (broker, lookup, task_id) = broker_with_blockable_child().await; + lookup.set_blocked(Some(permission_block("req-1", "rm -rf /tmp/x"))); + + let report = broker + .get_task_status("parent-conn", Some(1), &task_id, StatusWait::Immediate) + .await; + + // Status stays wire-stable `running` — the block rides alongside it, so + // a consumer that predates the field still resolves the poll correctly. + assert_eq!(report.status, TaskStatus::Running); + let blocked = report.blocked_on.expect("blocked_on is set"); + assert_eq!(blocked.kind, BlockedKind::Permission); + assert_eq!(blocked.request_id, "req-1"); + let message = report.message.expect("blocked report carries a message"); + // First line must stay the bare running marker (content-only hosts + // anchor on it), with the note on its own second line. + let mut lines = message.lines(); + assert_eq!(lines.next(), Some("Running.")); + assert_eq!( + lines.next(), + Some("Awaiting your decision: rm -rf /tmp/x"), + "the blocked note replaces the live reply, which is stale by definition" + ); + assert!(!message.contains("Latest sub-agent reply")); + } + + /// The whole point of #447: a `wait_ms: 0` (Infinite) wait must NOT park + /// forever behind a permission prompt. Nothing settles this task — if the + /// block didn't wake it, this test would hang. + #[tokio::test] + async fn infinite_wait_returns_when_the_child_becomes_blocked() { + let (broker, lookup, task_id) = broker_with_blockable_child().await; + lookup.set_blocked(Some(permission_block("req-1", "write to /etc/hosts"))); + + let report = broker + .get_task_status("parent-conn", Some(1), &task_id, StatusWait::Infinite) + .await; + + assert_eq!(report.status, TaskStatus::Running); + assert!(report.blocked_on.is_some()); + } + + /// ...but each prompt is surfaced ONCE. A re-poll while the same prompt is + /// still unanswered goes back to waiting instead of returning instantly, + /// which is what keeps an LLM's wait loop from spinning. A *second*, + /// different prompt is new again and returns. + #[tokio::test] + async fn a_reported_block_does_not_return_twice() { + let (broker, lookup, task_id) = broker_with_blockable_child().await; + lookup.set_blocked(Some(permission_block("req-1", "first"))); + + // First observation returns. + let first = broker + .get_task_status("parent-conn", Some(1), &task_id, StatusWait::Infinite) + .await; + assert_eq!(first.blocked_on.map(|b| b.request_id).as_deref(), Some("req-1")); + + // Same prompt, still unanswered: a bounded wait now runs to its deadline + // rather than returning immediately. + let started = Instant::now(); + let second = broker + .get_task_status("parent-conn", Some(1), &task_id, StatusWait::Bounded(120)) + .await; + assert!( + started.elapsed() >= Duration::from_millis(100), + "an already-reported block must not short-circuit the wait" + ); + // It still REPORTS the block on the way out — only the early return is + // suppressed, never the information. + assert!(second.blocked_on.is_some()); + + // A different prompt is a new event and returns early again. + lookup.set_blocked(Some(permission_block("req-2", "second"))); + let started = Instant::now(); + let third = broker + .get_task_status("parent-conn", Some(1), &task_id, StatusWait::Bounded(5_000)) + .await; + assert!( + started.elapsed() < Duration::from_millis(2_000), + "a NEW blocking prompt must wake the wait" + ); + assert_eq!(third.blocked_on.map(|b| b.request_id).as_deref(), Some("req-2")); + } + + /// The delivery-failure valve: marking a block reported is not proof the + /// parent RECEIVED it (the report still has to cross the listener, the + /// companion's stdout and the agent CLI, and a cancelled or aborted + /// `tools/call` discards it silently). So the SAME unanswered prompt + /// becomes reportable again after the resurface interval — otherwise that + /// one lost report was the only one ever offered and the caller is stranded + /// exactly as before #447. + /// + /// Uses `Infinite`, which has no deadline of its own: if the park weren't + /// bounded by the pending resurface, nothing would ever wake it (a blocked + /// child emits nothing further) and this test would hang. + #[tokio::test] + async fn an_undelivered_block_resurfaces_after_the_interval() { + let (broker, lookup, task_id) = + broker_with_blockable_child_resurfacing(Duration::from_millis(150)).await; + lookup.set_blocked(Some(permission_block("req-1", "first"))); + + // First report — imagine this one never reaches the LLM. + let first = broker + .get_task_status("parent-conn", Some(1), &task_id, StatusWait::Infinite) + .await; + assert!(first.blocked_on.is_some()); + + let started = Instant::now(); + let second = broker + .get_task_status("parent-conn", Some(1), &task_id, StatusWait::Infinite) + .await; + assert_eq!( + second.blocked_on.map(|b| b.request_id).as_deref(), + Some("req-1"), + "the same unanswered prompt must become reportable again" + ); + assert!( + started.elapsed() >= Duration::from_millis(120), + "it must WAIT out the interval, not return instantly (that would be the spin)" + ); + } + + /// An unblocked child is unchanged: no `blocked_on`, live reply intact, and + /// an Infinite wait still parks (proven by a Bounded wait running its full + /// deadline out). + #[tokio::test] + async fn unblocked_child_still_parks_and_keeps_its_live_reply() { + let (broker, _lookup, task_id) = broker_with_blockable_child().await; + + let started = Instant::now(); + let report = broker + .get_task_status("parent-conn", Some(1), &task_id, StatusWait::Bounded(120)) + .await; + assert!(started.elapsed() >= Duration::from_millis(100)); + assert!(report.blocked_on.is_none()); + assert_eq!( + report.message.as_deref(), + Some("Running.\nLatest sub-agent reply: Reading x") + ); + } + + // -- Batch get_tasks_status -------------------------------------------- + + /// Queue one spawn+send pair and start a delegation, returning its task id. + /// Each call consumes one queued `(spawn, send)` from the mock. + async fn start_running( + broker: &DelegationBroker, + mock: &MockSpawner, + child_conn: &str, + child_conv: i32, + tool_use: &str, + ) -> String { + mock.queue_spawn(Ok(child_conn.into())).await; + mock.queue_send(Ok(child_conv)).await; + broker + .start_delegation(request(1, tool_use)) + .await + .task_id + .expect("running task carries an id") + } + + /// The single-id batch agrees with `get_task_status` for a completed task — + /// the refactor that routes the single path through `get_tasks_status` keeps + /// the historical contract. + #[tokio::test] + async fn get_tasks_status_single_matches_get_task_status() { + let mock = Arc::new(MockSpawner::new()); + let broker = + DelegationBroker::new(mock.clone() as Arc, shallow_lookup()); + enable_delegation(&broker).await; + let t1 = start_running(&broker, &mock, "child-1", 42, "pt-1").await; + broker + .complete_call( + &t1, + DelegationOutcome::Ok(DelegationSuccess { + text: "done".into(), + child_conversation_id: 42, + child_agent_type: AgentType::Codex, + turn_count: 1, + duration_ms: 7, + token_usage: None, + }), + ) + .await; + + let single = broker + .get_task_status("parent-conn", Some(1), &t1, StatusWait::Immediate) + .await; + let batch = broker + .get_tasks_status( + "parent-conn", + Some(1), + std::slice::from_ref(&t1), + StatusWait::Immediate, + ) + .await; + assert_eq!(batch.len(), 1); + assert_eq!(batch[0].status, single.status); + assert_eq!(batch[0].text, single.text); + assert_eq!(batch[0].task_id, single.task_id); + } + + /// An immediate batch poll resolves a mix of completed / running / unknown + /// tasks in ONE pass, preserving request order. + #[tokio::test] + async fn batch_status_immediate_mixed_preserves_order() { + let mock = Arc::new(MockSpawner::new()); + let broker = + DelegationBroker::new(mock.clone() as Arc, shallow_lookup()); + enable_delegation(&broker).await; + let t1 = start_running(&broker, &mock, "child-1", 1, "pt-1").await; + let t2 = start_running(&broker, &mock, "child-2", 2, "pt-2").await; + broker + .complete_call( + &t1, + DelegationOutcome::Ok(DelegationSuccess { + text: "first".into(), + child_conversation_id: 1, + child_agent_type: AgentType::Codex, + turn_count: 1, + duration_ms: 3, + token_usage: None, + }), + ) + .await; + + let ids = vec![t1.clone(), t2.clone(), "no-such-id".to_string()]; + let reports = broker + .get_tasks_status("parent-conn", Some(1), &ids, StatusWait::Immediate) + .await; + assert_eq!(reports.len(), 3); + assert_eq!(reports[0].status, TaskStatus::Completed); + assert_eq!(reports[0].text.as_deref(), Some("first")); + assert_eq!(reports[0].task_id.as_deref(), Some(t1.as_str())); + assert_eq!(reports[1].status, TaskStatus::Running); + assert_eq!(reports[1].task_id.as_deref(), Some(t2.as_str())); + assert_eq!(reports[2].status, TaskStatus::Unknown); + } + + /// A batch `Infinite` wait returns as soon as ANY requested task settles, + /// leaving the still-running siblings in the snapshot. + #[tokio::test] + async fn batch_infinite_returns_when_any_settles() { + let mock = Arc::new(MockSpawner::new()); + let broker = + DelegationBroker::new(mock.clone() as Arc, shallow_lookup()); + enable_delegation(&broker).await; + let t1 = start_running(&broker, &mock, "child-1", 1, "pt-1").await; + let t2 = start_running(&broker, &mock, "child-2", 2, "pt-2").await; + + let waiter = { + let broker = broker.clone(); + let ids = vec![t1.clone(), t2.clone()]; + tokio::spawn(async move { + broker + .get_tasks_status("parent-conn", Some(1), &ids, StatusWait::Infinite) + .await + }) + }; + tokio::time::sleep(Duration::from_millis(30)).await; + assert!( + !waiter.is_finished(), + "batch infinite wait must park while both tasks run" + ); + + broker + .complete_call( + &t1, + DelegationOutcome::Ok(DelegationSuccess { + text: "first-done".into(), + child_conversation_id: 1, + child_agent_type: AgentType::Codex, + turn_count: 1, + duration_ms: 4, + token_usage: None, + }), + ) + .await; + + let reports = waiter.await.unwrap(); + assert_eq!(reports.len(), 2); + assert_eq!(reports[0].status, TaskStatus::Completed); + assert_eq!(reports[0].text.as_deref(), Some("first-done")); + assert_eq!(reports[1].status, TaskStatus::Running); + } + + /// A batch `Infinite` wait must NOT hold an already-terminal result hostage + /// to a still-running sibling: when a task is terminal at call ENTRY (it + /// completed before the poll), return immediately with the current snapshot + /// rather than parking for the runner. This is the mixed-at-entry case the + /// transition-only wake used to miss — distinct from + /// [`batch_infinite_returns_when_any_settles`] (both running at entry). + #[tokio::test] + async fn batch_infinite_returns_immediately_when_one_already_terminal() { + let mock = Arc::new(MockSpawner::new()); + let broker = + DelegationBroker::new(mock.clone() as Arc, shallow_lookup()); + enable_delegation(&broker).await; + let t1 = start_running(&broker, &mock, "child-1", 1, "pt-1").await; + let t2 = start_running(&broker, &mock, "child-2", 2, "pt-2").await; + // t1 completes BEFORE the poll; t2 keeps running. + broker + .complete_call( + &t1, + DelegationOutcome::Ok(DelegationSuccess { + text: "first-done".into(), + child_conversation_id: 1, + child_agent_type: AgentType::Codex, + turn_count: 1, + duration_ms: 4, + token_usage: None, + }), + ) + .await; + + // Infinite wait, but one task is already terminal at entry → must return + // at once (a bounded timeout guards against the regression: parking here + // would block until t2 settles, which it never does in this test). + let ids = vec![t1.clone(), t2.clone()]; + let reports = tokio::time::timeout( + Duration::from_secs(2), + broker.get_tasks_status("parent-conn", Some(1), &ids, StatusWait::Infinite), + ) + .await + .expect("a batch with an already-terminal task must not park under Infinite"); + assert_eq!(reports.len(), 2); + assert_eq!(reports[0].status, TaskStatus::Completed); + assert_eq!(reports[0].text.as_deref(), Some("first-done")); + assert_eq!(reports[1].status, TaskStatus::Running); + } + + /// A batch `Infinite` wait where NOTHING is running (all ids unknown) must + /// return immediately rather than parking forever. + #[tokio::test] + async fn batch_infinite_all_settled_returns_immediately() { + let mock = Arc::new(MockSpawner::new()); + let broker = + DelegationBroker::new(mock.clone() as Arc, shallow_lookup()); + enable_delegation(&broker).await; + let ids = vec!["nope-1".to_string(), "nope-2".to_string()]; + let reports = tokio::time::timeout( + Duration::from_secs(2), + broker.get_tasks_status("parent-conn", Some(1), &ids, StatusWait::Infinite), + ) + .await + .expect("all-settled infinite batch must not hang"); + assert_eq!(reports.len(), 2); + assert!(reports.iter().all(|r| r.status == TaskStatus::Unknown)); + } + + /// A bounded batch wait with no completion returns the running snapshot once + /// the deadline elapses (the child keeps running; the caller re-polls). + #[tokio::test] + async fn batch_bounded_deadline_returns_running_snapshot() { + let mock = Arc::new(MockSpawner::new()); + let broker = + DelegationBroker::new(mock.clone() as Arc, shallow_lookup()); + enable_delegation(&broker).await; + let t1 = start_running(&broker, &mock, "child-1", 1, "pt-1").await; + let reports = broker + .get_tasks_status("parent-conn", Some(1), &[t1], StatusWait::Bounded(40)) + .await; + assert_eq!(reports.len(), 1); + assert_eq!(reports[0].status, TaskStatus::Running); + } + + /// A task owned by a different parent reports `Unknown` in a batch — never + /// leaking another parent's task, just like the single-task path. + #[tokio::test] + async fn batch_status_scopes_to_parent() { + let mock = Arc::new(MockSpawner::new()); + let broker = + DelegationBroker::new(mock.clone() as Arc, shallow_lookup()); + enable_delegation(&broker).await; + let t1 = start_running(&broker, &mock, "child-1", 1, "pt-1").await; + let reports = broker + .get_tasks_status("other-parent", Some(2), &[t1], StatusWait::Immediate) + .await; + assert_eq!(reports.len(), 1); + assert_eq!(reports[0].status, TaskStatus::Unknown); + } + + // -- Task 4.5: error paths --------------------------------------------- + + #[tokio::test] + async fn spawn_failure_maps_to_spawn_failed() { + let mock = Arc::new(MockSpawner::new()); + mock.queue_spawn(Err(SpawnerError::Spawn("nope".into()))) + .await; + let broker = DelegationBroker::new(mock as Arc, shallow_lookup()); + enable_delegation(&broker).await; + let outcome = broker.handle_request(request(1, "pt-1")).await; + match outcome { + DelegationOutcome::Err { code, .. } => assert_eq!(code, "spawn_failed"), + other => panic!("expected Err, got {other:?}"), + } + } + + #[tokio::test] + async fn agent_defaults_are_forwarded_to_spawner() { + // Configure broker with per-agent defaults for ClaudeCode and verify + // they reach the spawner. Other agent types should still get the + // empty/None defaults. + let mock = Arc::new(MockSpawner::new()); + mock.queue_spawn(Ok("child-1".into())).await; + mock.queue_send(Err(SpawnerError::Send("stop after spawn".into()))) + .await; + let broker = + DelegationBroker::new(mock.clone() as Arc, shallow_lookup()); + + let mut claude_cfg = BTreeMap::new(); + claude_cfg.insert("model".into(), "claude-sonnet-4-5".into()); + let mut agent_defaults = BTreeMap::new(); + agent_defaults.insert( + AgentType::ClaudeCode, + AgentDelegationDefaults { + mode_id: Some("auto".into()), + config_values: claude_cfg.clone(), + }, + ); + broker + .set_config(DelegationConfig { + enabled: true, + depth_limit: 8, + agent_defaults, + ..DelegationConfig::default() + }) + .await; + + let _ = broker.handle_request(request(1, "pt-1")).await; + + let args = mock.spawn_args.lock().await; + assert_eq!(args.len(), 1); + let call = &args[0]; + assert_eq!(call.agent_type, AgentType::ClaudeCode); + assert_eq!(call.preferred_mode_id.as_deref(), Some("auto")); + assert_eq!(call.preferred_config_values, claude_cfg); + } + + #[tokio::test] + async fn agent_with_no_defaults_gets_empty_preferred_args() { + // ClaudeCode is configured in agent_defaults; a Codex request should + // still receive (None, empty) — no cross-contamination. + let mock = Arc::new(MockSpawner::new()); + mock.queue_spawn(Ok("child-1".into())).await; + mock.queue_send(Err(SpawnerError::Send("stop after spawn".into()))) + .await; + let broker = + DelegationBroker::new(mock.clone() as Arc, shallow_lookup()); + + let mut agent_defaults = BTreeMap::new(); + agent_defaults.insert( + AgentType::ClaudeCode, + AgentDelegationDefaults { + mode_id: Some("auto".into()), + config_values: BTreeMap::new(), + }, + ); + broker + .set_config(DelegationConfig { + enabled: true, + depth_limit: 8, + agent_defaults, + ..DelegationConfig::default() + }) + .await; + + let mut codex_req = request(1, "pt-1"); + codex_req.agent_type = AgentType::Codex; + let _ = broker.handle_request(codex_req).await; + + let args = mock.spawn_args.lock().await; + assert_eq!(args.len(), 1); + assert_eq!(args[0].agent_type, AgentType::Codex); + assert!(args[0].preferred_mode_id.is_none()); + assert!(args[0].preferred_config_values.is_empty()); + } + + #[tokio::test] + async fn send_failure_after_spawn_disconnects_child() { + let mock = Arc::new(MockSpawner::new()); + mock.queue_spawn(Ok("c1".into())).await; + mock.queue_send(Err(SpawnerError::Send("agent rejected prompt".into()))) + .await; + let broker = + DelegationBroker::new(mock.clone() as Arc, shallow_lookup()); + enable_delegation(&broker).await; + let outcome = broker.handle_request(request(1, "pt-1")).await; + match outcome { + DelegationOutcome::Err { code, .. } => assert_eq!(code, "spawn_failed"), + other => panic!("expected Err, got {other:?}"), + } + assert_eq!(mock.disconnects.lock().await.as_slice(), &["c1"]); + } + + #[tokio::test] + async fn handle_request_waits_indefinitely_for_completion() { + // No timeout race anymore: handle_request blocks on `rx.await` until + // complete_call / cancel_* fires. This test asserts the pending entry + // sticks around even after a generous idle window. + let mock = Arc::new(MockSpawner::new()); + mock.queue_spawn(Ok("c1".into())).await; + mock.queue_send(Ok(99)).await; + let broker = + DelegationBroker::new(mock.clone() as Arc, shallow_lookup()); + enable_delegation(&broker).await; + + let driver = { + let broker = broker.clone(); + tokio::spawn(async move { broker.handle_request(request(1, "pt-1")).await }) + }; + + tokio::time::sleep(Duration::from_millis(80)).await; + assert_eq!(broker.pending_count().await, 1); + assert!(mock.cancels.lock().await.is_empty()); + + let call_id = broker.peek_first_pending_call_id().await.unwrap(); + broker + .complete_call( + &call_id, + DelegationOutcome::Ok(DelegationSuccess { + text: "done".into(), + child_conversation_id: 99, + child_agent_type: AgentType::Codex, + turn_count: 1, + duration_ms: 50, + token_usage: None, + }), + ) + .await; + + let outcome = driver.await.unwrap(); + match outcome { + DelegationOutcome::Ok(s) => assert_eq!(s.text, "done"), + other => panic!("expected Ok, got {other:?}"), + } + assert_eq!(mock.disconnects.lock().await.as_slice(), &["c1"]); + } + + // -- Task 4.6: parent-cancel cascade ----------------------------------- + + #[tokio::test] + async fn parent_cancel_cancels_all_pending_children() { + let mock = Arc::new(MockSpawner::new()); + for i in 0..3 { + mock.queue_spawn(Ok(format!("c{i}"))).await; + mock.queue_send(Ok(100 + i)).await; + } + let broker = + DelegationBroker::new(mock.clone() as Arc, shallow_lookup()); + enable_delegation(&broker).await; + + let mut handles = Vec::new(); + for i in 0..3 { + let broker = broker.clone(); + handles.push(tokio::spawn(async move { + broker.handle_request(request(1, &format!("pt-{i}"))).await + })); + } + + // Wait until all three are parked. + while broker.pending_count().await < 3 { + tokio::time::sleep(Duration::from_millis(5)).await; + } + + broker.cancel_by_parent("parent-conn").await; + for h in handles { + let outcome = h.await.unwrap(); + match outcome { + DelegationOutcome::Err { code, .. } => assert_eq!(code, "canceled"), + other => panic!("expected canceled, got {other:?}"), + } + } + assert_eq!(mock.cancels.lock().await.len(), 3); + // Each child disconnects exactly once via cancel_by_parent. + assert_eq!(mock.disconnects.lock().await.len(), 3); + } + + #[tokio::test] + async fn cancel_by_parent_ignores_other_parents() { + let mock = Arc::new(MockSpawner::new()); + mock.queue_spawn(Ok("c1".into())).await; + mock.queue_send(Ok(200)).await; + let broker = + DelegationBroker::new(mock.clone() as Arc, shallow_lookup()); + enable_delegation(&broker).await; + + let driver = { + let broker = broker.clone(); + tokio::spawn(async move { broker.handle_request(request(1, "pt-1")).await }) + }; + while broker.pending_count().await == 0 { + tokio::time::sleep(Duration::from_millis(5)).await; + } + + broker.cancel_by_parent("other-parent").await; + // No effect — pending entry still there. + assert_eq!(broker.pending_count().await, 1); + + let call_id = broker.peek_first_pending_call_id().await.unwrap(); + broker + .complete_call( + &call_id, + DelegationOutcome::Ok(DelegationSuccess { + text: "done".into(), + child_conversation_id: 200, + child_agent_type: AgentType::ClaudeCode, + turn_count: 1, + duration_ms: 10, + token_usage: None, + }), + ) + .await; + let outcome = driver.await.unwrap(); + assert!(matches!(outcome, DelegationOutcome::Ok(_))); + } + + // -- Task 4.7: depth limit --------------------------------------------- + + #[tokio::test] + async fn depth_limit_rejects_before_spawn() { + let mock = Arc::new(MockSpawner::new()); + // No queued spawn results — if the broker tries to spawn, it errors loudly. + // chain: 1 (root, None) <- 2 (child of 1) <- 3 (grandchild of 2). + // Parent = grandchild (id 3): parent_depth = 2. With limit = 2, child + // would sit at depth 3 → reject. + let lookup = Arc::new(MockDepth(vec![(1, None), (2, Some(1)), (3, Some(2))])) + as Arc; + let broker = DelegationBroker::new(mock as Arc, lookup); + broker + .set_config(DelegationConfig { + enabled: true, + depth_limit: 2, + ..DelegationConfig::default() + }) + .await; + let outcome = broker.handle_request(request(3, "pt-1")).await; + match outcome { + DelegationOutcome::Err { code, .. } => assert_eq!(code, "depth_limit"), + other => panic!("expected depth_limit, got {other:?}"), + } + } + + // -- Pending tool_call_id queue (MCP `_meta.tool_use_id` fallback) ---- + + #[tokio::test] + async fn pending_tool_call_register_and_take_is_fifo() { + let broker = DelegationBroker::new( + Arc::new(MockSpawner::new()) as Arc, + shallow_lookup(), + ); + broker.register_pending_tool_call("p1", "tc-a".into()).await; + broker.register_pending_tool_call("p1", "tc-b".into()).await; + assert_eq!( + broker.take_pending_tool_call("p1").await.as_deref(), + Some("tc-a") + ); + assert_eq!( + broker.take_pending_tool_call("p1").await.as_deref(), + Some("tc-b") + ); + assert!(broker.take_pending_tool_call("p1").await.is_none()); + } + + #[tokio::test] + async fn register_dedupes_repeated_tool_call_id() { + // Regression: some hosts re-emit `sessionUpdate(tool_call)` (not + // `tool_call_update`) for the same call as raw_input chunks arrive + // or as the status flips. Without dedupe the second push leaves a + // stale id in the queue that mis-binds the next delegation. + let broker = DelegationBroker::new( + Arc::new(MockSpawner::new()) as Arc, + shallow_lookup(), + ); + broker.register_pending_tool_call("p1", "tc-a".into()).await; + broker.register_pending_tool_call("p1", "tc-a".into()).await; + broker.register_pending_tool_call("p1", "tc-a".into()).await; + assert_eq!( + broker.take_pending_tool_call("p1").await.as_deref(), + Some("tc-a") + ); + assert!( + broker.take_pending_tool_call("p1").await.is_none(), + "duplicate register must not leave a stale id in the queue" + ); + } + + #[tokio::test] + async fn register_after_claim_drops_stale_re_emit() { + // Regression for the post-claim re-emit race: a host re-sends + // `sessionUpdate(tool_call)` for the same id after the matching + // MCP round-trip already consumed it (e.g. shipping the + // `completed` status flip or a settled `raw_input`). The + // in-queue dedupe alone leaves the queue empty at that moment, + // so without the recently-consumed memory the re-emit would + // sneak into the queue and mis-bind the next delegation. + let broker = DelegationBroker::new( + Arc::new(MockSpawner::new()) as Arc, + shallow_lookup(), + ); + broker.register_pending_tool_call("p1", "tc-a".into()).await; + assert_eq!( + broker.take_pending_tool_call("p1").await.as_deref(), + Some("tc-a") + ); + // Re-emit of the same id after it was already claimed. + broker.register_pending_tool_call("p1", "tc-a".into()).await; + assert!( + broker.take_pending_tool_call("p1").await.is_none(), + "post-claim re-emit of the same id must not be re-queued" + ); + // A genuinely new id on the same parent still flows through. + broker.register_pending_tool_call("p1", "tc-b".into()).await; + assert_eq!( + broker.take_pending_tool_call("p1").await.as_deref(), + Some("tc-b") + ); + } + + #[tokio::test] + async fn concurrent_take_and_re_register_never_leaks_stale_duplicate() { + // TOCTOU regression: a host re-emit of the same tool_call_id + // racing against the matching take must never inject a stale + // duplicate. Co-locating `pending` and `consumed` under the + // same mutex guarantees the claim → mark-consumed pair is + // atomic, so the only two legal interleavings are: + // + // * take wins → pending=[], consumed=[id]; re-register sees + // the id in consumed and drops it. + // * register wins → pending=[id] (still the original entry, + // in-queue dedupe drops the re-emit); take then pops it + // and records it in consumed. + // + // In neither case may the queue retain a duplicate id once + // both futures settle. We drive many rounds with `tokio::spawn` + // to stress the interleaving. + let broker = std::sync::Arc::new(DelegationBroker::new( + Arc::new(MockSpawner::new()) as Arc, + shallow_lookup(), + )); + for _ in 0..200 { + broker.register_pending_tool_call("p1", "tc-a".into()).await; + let b_take = broker.clone(); + let b_reg = broker.clone(); + let h_take = tokio::spawn(async move { + b_take.take_pending_tool_call("p1").await; + }); + let h_reg = tokio::spawn(async move { + b_reg.register_pending_tool_call("p1", "tc-a".into()).await; + }); + let _ = tokio::join!(h_take, h_reg); + assert!( + broker.take_pending_tool_call("p1").await.is_none(), + "stale duplicate of tc-a leaked after concurrent take + re-register" + ); + } + } + + #[tokio::test] + async fn consumed_memory_outlives_pending_ttl_for_long_running_delegation() { + // Regression: a delegated child agent can run for + // minutes-to-hours. When it finishes, the host may re-emit + // the parent-side `tool_call` (e.g. as a `completed` status + // flip via the non-update `ToolCall` variant). That re-emit + // arrives well after PENDING_TOOL_CALL_TTL, so the consumed + // memory MUST NOT age out under that TTL — otherwise the + // stale id slips back into pending and mis-binds the next + // delegation. Consumed entries are scoped to the parent + // connection's lifetime instead. + let broker = DelegationBroker::new( + Arc::new(MockSpawner::new()) as Arc, + shallow_lookup(), + ); + broker.register_pending_tool_call("p1", "tc-a".into()).await; + assert_eq!( + broker.take_pending_tool_call("p1").await.as_deref(), + Some("tc-a") + ); + // Simulate the host re-emitting the same tool_call_id 10× + // the pending TTL later (i.e. a long-running delegation that + // finishes after the pending eviction window). + let long_after = Instant::now() + PENDING_TOOL_CALL_TTL * 10; + broker + .register_pending_tool_call_with_key_at("p1", "tc-a".into(), None, false, long_after) + .await; + assert!( + broker + .take_pending_tool_call_at("p1", long_after) + .await + .is_none(), + "consumed memory must outlast the pending TTL so terminal status re-emits cannot leak through" + ); + } + + #[tokio::test] + async fn consumed_memory_unbounded_across_high_fan_out() { + // Regression for the cap removal: a parent session with many + // delegations (well past any prior per-bucket cap) must still + // reject a late re-emit of the very first delegation's id, + // because the consumed half has no cap. A bounded consumed + // set with FIFO eviction would silently re-enable the + // mis-binding bug at high fan-out. + let broker = DelegationBroker::new( + Arc::new(MockSpawner::new()) as Arc, + shallow_lookup(), + ); + let first_id = "tc-first".to_string(); + broker + .register_pending_tool_call("p1", first_id.clone()) + .await; + assert_eq!( + broker.take_pending_tool_call("p1").await.as_deref(), + Some(first_id.as_str()) + ); + // Issue many more delegations than any prior per-bucket cap. With + // no cap on consumed, the first id must remain remembered for the + // lifetime of the parent connection. + for i in 0..128 { + let id = format!("tc-{i}"); + broker.register_pending_tool_call("p1", id.clone()).await; + assert_eq!( + broker.take_pending_tool_call("p1").await.as_deref(), + Some(id.as_str()) + ); + } + // Late re-emit of the very first id (would have been evicted + // by the prior bounded consumed FIFO). + broker + .register_pending_tool_call("p1", first_id.clone()) + .await; + assert!( + broker.take_pending_tool_call("p1").await.is_none(), + "consumed memory must retain the very first id even after high fan-out" + ); + } + + #[tokio::test] + async fn consumed_memory_cleared_on_parent_disconnect() { + // The companion to the long-running invariant above: consumed + // memory is scoped to the parent connection's lifetime, so + // `drop_pending_tool_calls_for_parent` (called when the + // parent disconnects) must clear it. Otherwise a brand-new + // connection reusing the same id (UUID collision is unlikely + // but UUIDs are not the only id scheme in play) would be + // permanently blocked. + let broker = DelegationBroker::new( + Arc::new(MockSpawner::new()) as Arc, + shallow_lookup(), + ); + broker.register_pending_tool_call("p1", "tc-a".into()).await; + assert_eq!( + broker.take_pending_tool_call("p1").await.as_deref(), + Some("tc-a") + ); + broker.drop_pending_tool_calls_for_parent("p1").await; + broker.register_pending_tool_call("p1", "tc-a".into()).await; + assert_eq!( + broker.take_pending_tool_call("p1").await.as_deref(), + Some("tc-a"), + "parent disconnect must clear consumed memory so id reuse is acceptable" + ); + } + + #[tokio::test] + async fn take_skips_entries_older_than_ttl() { + // Regression: an ACP `tool_call` whose matching MCP round-trip + // never arrives (host changed its mind, transport dropped, etc.) + // must not sit in the queue forever and mis-bind a subsequent + // delegation. TTL eviction is exercised by advancing the + // injected `as of` instant past PENDING_TOOL_CALL_TTL. + let broker = DelegationBroker::new( + Arc::new(MockSpawner::new()) as Arc, + shallow_lookup(), + ); + let t0 = Instant::now(); + broker + .register_pending_tool_call("p1", "stale".into()) + .await; + // Fresh id registered "just before" the future `now`. + broker + .register_pending_tool_call("p1", "fresh".into()) + .await; + let future_now = t0 + PENDING_TOOL_CALL_TTL + Duration::from_millis(50); + // Forge "fresh" so it survives the TTL: rewrite its timestamp to + // ~now-relative-to-future-now. Direct field access is OK — we're + // a sibling test in the same module. + { + let mut map = broker.tool_calls.inner.lock().await; + let bucket = map.get_mut("p1").expect("bucket present"); + // Re-stamp the second entry ("fresh") to `future_now`. + if let Some(entry) = bucket + .pending + .iter_mut() + .find(|p| p.tool_call_id == "fresh") + { + entry.registered_at = future_now; + } + } + // First entry ("stale", stamped at ~t0) is past TTL relative to + // future_now; the second ("fresh") was just re-stamped to + // future_now and must survive. + assert_eq!( + broker + .take_pending_tool_call_at("p1", future_now) + .await + .map(|(id, _)| id) + .as_deref(), + Some("fresh") + ); + assert!(broker.take_pending_tool_call("p1").await.is_none()); + } + + #[tokio::test] + async fn pending_tool_call_is_isolated_per_parent() { + let broker = DelegationBroker::new( + Arc::new(MockSpawner::new()) as Arc, + shallow_lookup(), + ); + broker.register_pending_tool_call("p1", "p1-a".into()).await; + broker.register_pending_tool_call("p2", "p2-a".into()).await; + assert_eq!( + broker.take_pending_tool_call("p1").await.as_deref(), + Some("p1-a") + ); + assert_eq!( + broker.take_pending_tool_call("p2").await.as_deref(), + Some("p2-a") + ); + assert!(broker.take_pending_tool_call("p1").await.is_none()); + assert!(broker.take_pending_tool_call("p2").await.is_none()); + } + + // -- (agent_type, task) correlation for parallel delegations ---------- + + /// Build a match key with a fixed agent and no explicit working_dir for + /// the common case where the test only varies the task. Use `key_for` to + /// vary the agent, or `key_with_dir` to vary the directory. + fn task_key(task: &str) -> DelegationMatchKey { + key_for(AgentType::Codex, task) + } + + fn key_for(agent_type: AgentType, task: &str) -> DelegationMatchKey { + DelegationMatchKey { + agent_type, + task: task.to_string(), + working_dir: None, + } + } + + fn key_with_dir(task: &str, working_dir: &str) -> DelegationMatchKey { + DelegationMatchKey { + agent_type: AgentType::Codex, + task: task.to_string(), + working_dir: Some(working_dir.to_string()), + } + } + + #[tokio::test] + async fn parallel_delegations_bind_by_key_regardless_of_order() { + // Two `delegate_to_agent` calls fire in parallel; both ACP tool_call + // events register with their key. The MCP round-trips can claim in + // EITHER order — each must bind to its own id by key match, never + // swap. Pure FIFO would hand the first claimer "tc-A" regardless of + // which call it represented. + let broker = DelegationBroker::new( + Arc::new(MockSpawner::new()) as Arc, + shallow_lookup(), + ); + broker + .register_pending_tool_call_with_key("p1", "tc-A".into(), Some(task_key("task A"))) + .await; + broker + .register_pending_tool_call_with_key("p1", "tc-B".into(), Some(task_key("task B"))) + .await; + // Claim "task B" first (reverse of registration order). + assert_eq!( + broker + .take_matching_tool_call("p1", &task_key("task B")) + .await + .as_deref(), + Some("tc-B") + ); + assert_eq!( + broker + .take_matching_tool_call("p1", &task_key("task A")) + .await + .as_deref(), + Some("tc-A") + ); + // A re-claim of an already-consumed key finds nothing. + assert!(broker + .take_matching_tool_call("p1", &task_key("task A")) + .await + .is_none()); + } + + #[tokio::test] + async fn parallel_same_task_different_agent_do_not_swap() { + // Regression for Codex review: two parallel calls with the SAME task + // text but DIFFERENT agents must bind by the full key, not by task + // alone — otherwise the codex card could show the claude_code child + // and vice versa. + let broker = DelegationBroker::new( + Arc::new(MockSpawner::new()) as Arc, + shallow_lookup(), + ); + broker + .register_pending_tool_call_with_key( + "p1", + "tc-codex".into(), + Some(key_for(AgentType::Codex, "review this")), + ) + .await; + broker + .register_pending_tool_call_with_key( + "p1", + "tc-claude".into(), + Some(key_for(AgentType::ClaudeCode, "review this")), + ) + .await; + // The claude_code round-trip must claim the claude_code id even though + // the codex entry shares the identical task and registered first. + assert_eq!( + broker + .take_matching_tool_call("p1", &key_for(AgentType::ClaudeCode, "review this")) + .await + .as_deref(), + Some("tc-claude") + ); + assert_eq!( + broker + .take_matching_tool_call("p1", &key_for(AgentType::Codex, "review this")) + .await + .as_deref(), + Some("tc-codex") + ); + } + + #[tokio::test] + async fn parallel_same_task_same_agent_different_dir_do_not_swap() { + // Regression for Codex review round 2: two parallel calls with the + // SAME agent and SAME task text but DIFFERENT explicit working_dir + // (e.g. "run tests" against /repo-a vs /repo-b) must bind by the full + // key including working_dir. Claimed in reverse registration order to + // prove it's not arrival-order FIFO. + let broker = DelegationBroker::new( + Arc::new(MockSpawner::new()) as Arc, + shallow_lookup(), + ); + broker + .register_pending_tool_call_with_key( + "p1", + "tc-a".into(), + Some(key_with_dir("run tests", "/repo-a")), + ) + .await; + broker + .register_pending_tool_call_with_key( + "p1", + "tc-b".into(), + Some(key_with_dir("run tests", "/repo-b")), + ) + .await; + assert_eq!( + broker + .take_matching_tool_call("p1", &key_with_dir("run tests", "/repo-b")) + .await + .as_deref(), + Some("tc-b") + ); + assert_eq!( + broker + .take_matching_tool_call("p1", &key_with_dir("run tests", "/repo-a")) + .await + .as_deref(), + Some("tc-a") + ); + } + + #[tokio::test] + async fn claim_does_not_steal_sibling_and_waits_for_own_registration() { + // Regression for the reported bug: with only the SIBLING's keyed id + // registered, a delegation must NOT grab it (which would swap the two + // cards) — it waits for its own id. The brief-wait loop picks it up + // once it registers shortly after. + let broker = std::sync::Arc::new(DelegationBroker::new( + Arc::new(MockSpawner::new()) as Arc, + shallow_lookup(), + )); + broker + .register_pending_tool_call_with_key("p1", "tc-A".into(), Some(task_key("task A"))) + .await; + // Immediate claim for "task B" while only tc-A (task A) is pending + // must refuse to steal tc-A. + assert!( + broker + .take_matching_tool_call("p1", &task_key("task B")) + .await + .is_none(), + "must not steal a sibling's keyed id" + ); + // tc-A is still claimable by its own key. + let broker_bg = broker.clone(); + let register_late = tokio::spawn(async move { + tokio::time::sleep(Duration::from_millis(30)).await; + broker_bg + .register_pending_tool_call_with_key("p1", "tc-B".into(), Some(task_key("task B"))) + .await; + }); + // The brief-wait claim polls until tc-B (task B) registers. + let claimed = broker + .claim_pending_tool_call_with_brief_wait("p1", &task_key("task B")) + .await; + register_late.await.unwrap(); + assert_eq!(claimed.map(|(id, _)| id).as_deref(), Some("tc-B")); + // tc-A remains for its own key. + assert_eq!( + broker + .take_matching_tool_call("p1", &task_key("task A")) + .await + .as_deref(), + Some("tc-A") + ); + } + + #[tokio::test] + async fn lone_unkeyed_entry_is_not_claimed_in_loop_only_post_budget() { + // A host that ships no parseable `raw_input` registers match_key=None. + // The in-loop path NEVER claims it — not even when it's the only entry, + // and regardless of how old it gets (10s here). Entry age is no proof a + // key isn't still coming: a serialized round-trip can register/backfill + // arbitrarily late, and the entry could belong to a parallel sibling + // whose owner hasn't registered yet (the staggered-singleton race — + // Codex review). Arrival-order FIFO is reserved for the post-budget last + // resort, which only runs once the CALLER has waited its full budget. + let broker = DelegationBroker::new( + Arc::new(MockSpawner::new()) as Arc, + shallow_lookup(), + ); + broker.register_pending_tool_call("p1", "tc-A".into()).await; + // Even aged 10s (well past any heuristic grace, still < TTL so not + // evicted), the in-loop claim refuses to hand out the unkeyed id. + let way_aged = Instant::now() + Duration::from_secs(10); + assert!( + broker + .take_matching_tool_call_at("p1", &task_key("whatever"), way_aged) + .await + .is_none(), + "an unkeyed entry must never be claimed in-loop, regardless of age" + ); + // The post-budget last resort is where a genuinely keyless entry binds. + assert_eq!( + broker.take_pending_tool_call("p1").await.as_deref(), + Some("tc-A") + ); + } + + #[tokio::test] + async fn parallel_unkeyed_entries_are_not_claimed_in_loop() { + // THE Finding 1 regression. Two delegations whose initial ToolCalls + // registered UNKEYED (args arrive later on a ToolCallUpdate). Before + // either is keyed, a round-trip arrives. The old `all unkeyed → + // pop_front` handed it the OLDEST entry (tc-A), mis-binding it to the + // wrong delegation. The in-loop claim now withholds (None) because no + // key matches — arrival-order FIFO is left to the post-budget last + // resort. Age never unlocks an in-loop claim. + let broker = DelegationBroker::new( + Arc::new(MockSpawner::new()) as Arc, + shallow_lookup(), + ); + broker.register_pending_tool_call("p1", "tc-A".into()).await; + broker.register_pending_tool_call("p1", "tc-B".into()).await; + // Aged (but < TTL, so not evicted): still withheld in-loop. + let aged = Instant::now() + Duration::from_secs(5); + assert!( + broker + .take_matching_tool_call_at("p1", &task_key("task B"), aged) + .await + .is_none(), + "unkeyed siblings must not be FIFO-claimed in-loop" + ); + // Neither entry was consumed. + let map = broker.tool_calls.inner.lock().await; + assert_eq!(map.get("p1").expect("bucket present").pending.len(), 2); + } + + #[tokio::test] + async fn parallel_unkeyed_resolves_by_backfilled_key_not_fifo() { + // The pay-off: while the claim is withheld, the args arrive and + // backfill a key onto the sibling. The round-trip then binds by EXACT + // MATCH to its own id — never the FIFO-oldest. This is the would-be + // mis-bind turned into a correct correlation. + let broker = DelegationBroker::new( + Arc::new(MockSpawner::new()) as Arc, + shallow_lookup(), + ); + broker.register_pending_tool_call("p1", "tc-A".into()).await; + broker.register_pending_tool_call("p1", "tc-B".into()).await; + // tc-B's args land → backfills its key. + broker + .register_pending_tool_call_with_key("p1", "tc-B".into(), Some(task_key("task B"))) + .await; + // The "task B" round-trip binds to tc-B by key, not to the older tc-A. + assert_eq!( + broker + .take_matching_tool_call("p1", &task_key("task B")) + .await + .as_deref(), + Some("tc-B") + ); + // tc-A is untouched, still pending for its own key/round-trip. + let map = broker.tool_calls.inner.lock().await; + let pending = &map.get("p1").expect("bucket present").pending; + assert_eq!(pending.len(), 1); + assert_eq!(pending[0].tool_call_id, "tc-A"); + } + + #[tokio::test] + async fn post_budget_fallback_still_fifos_parallel_unkeyed() { + // A genuinely keyless host (no key ever lands) must still bind both + // parallel delegations end-to-end. The in-loop claim withholds them, + // but the post-budget last resort `take_pending_tool_call` claims them + // oldest-first — the best a keyless host allows, and unchanged from + // before. Only the premature in-loop FIFO is gone. + let broker = DelegationBroker::new( + Arc::new(MockSpawner::new()) as Arc, + shallow_lookup(), + ); + broker.register_pending_tool_call("p1", "tc-A".into()).await; + broker.register_pending_tool_call("p1", "tc-B".into()).await; + assert_eq!( + broker.take_pending_tool_call("p1").await.as_deref(), + Some("tc-A") + ); + assert_eq!( + broker.take_pending_tool_call("p1").await.as_deref(), + Some("tc-B") + ); + } + + #[tokio::test] + async fn brief_wait_binds_own_late_registration_not_unkeyed_sibling() { + // The staggered-singleton timeline Codex flagged, end-to-end: only an + // UNKEYED sibling (tc-A) is visible when a DIFFERENT delegation's + // round-trip (task B) starts claiming; B's own keyed `tool_call` + // registers a little later, still inside the wait budget. The brief-wait + // loop must bind B to its OWN id (tc-B) by exact match, never FIFO-steal + // the older unkeyed tc-A. The old in-loop FIFO popped tc-A on the very + // first poll (all-unkeyed); a grace gate would still steal it once tc-A + // aged past the grace before tc-B arrived. Deferring all FIFO to the + // post-budget — i.e. binding by exact match in-loop only — is what makes + // this correct. + let broker = std::sync::Arc::new(DelegationBroker::new( + Arc::new(MockSpawner::new()) as Arc, + shallow_lookup(), + )); + broker.register_pending_tool_call("p1", "tc-A".into()).await; + // B's own ACP registration lands ~200ms in — well after any age-based + // heuristic would have fired, but far inside the ~2s claim budget. + let broker_bg = broker.clone(); + let register_late = tokio::spawn(async move { + tokio::time::sleep(Duration::from_millis(200)).await; + broker_bg + .register_pending_tool_call_with_key("p1", "tc-B".into(), Some(task_key("task B"))) + .await; + }); + let claimed = broker + .claim_pending_tool_call_with_brief_wait("p1", &task_key("task B")) + .await; + register_late.await.unwrap(); + assert_eq!( + claimed.map(|(id, _)| id).as_deref(), + Some("tc-B"), + "must wait for its own registration, not FIFO-steal the unkeyed sibling" + ); + // tc-A is untouched, still pending for its own correlation. + let map = broker.tool_calls.inner.lock().await; + let pending = &map.get("p1").expect("bucket present").pending; + assert_eq!(pending.len(), 1); + assert_eq!(pending[0].tool_call_id, "tc-A"); + } + + #[tokio::test] + async fn reemit_backfills_key_onto_unkeyed_entry() { + // A host that re-emits the `session/update(tool_call)` variant: the + // first ToolCall has no parseable args (registers match_key=None), a + // later re-emit carries the full args. The re-emit must backfill the + // key onto the existing entry (not push a duplicate, not be dropped) + // so key matching works. + let broker = DelegationBroker::new( + Arc::new(MockSpawner::new()) as Arc, + shallow_lookup(), + ); + broker.register_pending_tool_call("p1", "tc-A".into()).await; + broker + .register_pending_tool_call_with_key("p1", "tc-A".into(), Some(task_key("task A"))) + .await; + // Now claimable by the backfilled key. + assert_eq!( + broker + .take_matching_tool_call("p1", &task_key("task A")) + .await + .as_deref(), + Some("tc-A") + ); + assert!(broker.take_pending_tool_call("p1").await.is_none()); + } + + #[tokio::test] + async fn fallback_never_steals_a_keyed_sibling() { + // A keyed sibling is pending but the requesting round-trip's key never + // matches (its own tool_call was genuinely lost). The post-budget last + // resort must NOT hand out the keyed sibling — stealing it would just + // move the dead card from this delegation to the sibling. It returns + // None (→ caller mints a synthetic id), and the sibling stays claimable + // by its own round-trip. (Regression: the old behavior FIFO-popped the + // keyed entry here, swapping which delegation broke.) + let broker = DelegationBroker::new( + Arc::new(MockSpawner::new()) as Arc, + shallow_lookup(), + ); + broker + .register_pending_tool_call_with_key("p1", "tc-A".into(), Some(task_key("task A"))) + .await; + // No entry matches "task Z", and a keyed entry is present, so the + // match step refuses to claim. + assert!(broker + .take_matching_tool_call("p1", &task_key("task Z")) + .await + .is_none()); + // The post-budget last resort steps over the keyed entry → None. + assert!( + broker.take_pending_tool_call("p1").await.is_none(), + "must not steal a keyed sibling via the anonymous fallback" + ); + // The keyed sibling is untouched — still claimable by its own key. + assert_eq!( + broker + .take_matching_tool_call("p1", &task_key("task A")) + .await + .as_deref(), + Some("tc-A") + ); + } + + #[tokio::test] + async fn keyed_entry_survives_past_ttl_for_serialized_round_trip() { + // THE headline regression for the reported bug. A 2nd parallel + // delegation's tool_call registers (keyed), then its MCP round-trip is + // serialized far behind the 1st delegation — arriving well past + // PENDING_TOOL_CALL_TTL. The keyed entry must NOT be aged out: an exact + // key match claims it at any age, so the parent card binds instead of + // falling to a synthetic id. (Observed live: round-trip landed 77s + // after registration, past the 60s TTL → evicted → synthetic → dead + // card stuck on "sub-agent running…".) + let broker = DelegationBroker::new( + Arc::new(MockSpawner::new()) as Arc, + shallow_lookup(), + ); + broker + .register_pending_tool_call_with_key( + "p1", + "tc-late".into(), + Some(task_key("slow task")), + ) + .await; + // Claim "as of" long past the TTL — simulates the round-trip arriving + // after a many-times-TTL wait behind a serialized sibling. + let way_past_ttl = Instant::now() + PENDING_TOOL_CALL_TTL * 10; + assert_eq!( + broker + .take_matching_tool_call_at("p1", &task_key("slow task"), way_past_ttl) + .await + .as_deref(), + Some("tc-late"), + "a keyed entry must remain claimable by exact key match regardless of age" + ); + } + + #[tokio::test] + async fn unkeyed_entry_is_still_aged_out() { + // The flip side: UNKEYED entries (host shipped no parseable raw_input) + // remain anonymous and arrival-order-correlated, so a stale one MUST + // still be GC'd by age — otherwise it could mis-bind a much later + // unkeyed delegation via the FIFO path. + let broker = DelegationBroker::new( + Arc::new(MockSpawner::new()) as Arc, + shallow_lookup(), + ); + broker + .register_pending_tool_call("p1", "tc-stale".into()) + .await; + let way_past_ttl = Instant::now() + PENDING_TOOL_CALL_TTL * 10; + // Unkeyed + stale → evicted by the match path's GC → nothing to claim. + assert!(broker + .take_matching_tool_call_at("p1", &task_key("whatever"), way_past_ttl) + .await + .is_none()); + // And the anonymous path agrees it's gone. + assert!(broker + .take_pending_tool_call_at("p1", way_past_ttl) + .await + .is_none()); + } + + #[tokio::test] + async fn explicit_tool_use_id_consumes_pending_entry_acp_first() { + // Codex review fix: client supplies the real id via `_meta.tool_use_id` + // AFTER the dispatcher already registered it (ACP-before-MCP). The + // explicit-id path must consume the keyed pending entry so it can't + // linger (keyed entries are retained indefinitely) and be mis-claimed + // by a later same-key delegation. + let broker = DelegationBroker::new( + Arc::new(MockSpawner::new()) as Arc, + shallow_lookup(), + ); + broker + .register_pending_tool_call_with_key("p1", "tc-x".into(), Some(task_key("task A"))) + .await; + broker.consume_explicit_tool_call("p1", "tc-x").await; + // No longer claimable by its key. + assert!(broker + .take_matching_tool_call("p1", &task_key("task A")) + .await + .is_none()); + // A late ACP re-registration of the same id is dropped (consumed). + broker + .register_pending_tool_call_with_key("p1", "tc-x".into(), Some(task_key("task A"))) + .await; + assert!( + broker + .take_matching_tool_call("p1", &task_key("task A")) + .await + .is_none(), + "a re-registration after explicit consume must stay dropped" + ); + } + + #[tokio::test] + async fn explicit_tool_use_id_consumes_pending_entry_mcp_first() { + // The MCP-before-ACP order: the explicit-id request is handled before + // the ACP tool_call event registers. consume_explicit_tool_call records + // the id as consumed up front, so the later registration is dropped. + let broker = DelegationBroker::new( + Arc::new(MockSpawner::new()) as Arc, + shallow_lookup(), + ); + broker.consume_explicit_tool_call("p1", "tc-y").await; + broker + .register_pending_tool_call_with_key("p1", "tc-y".into(), Some(task_key("task B"))) + .await; + assert!(broker + .take_matching_tool_call("p1", &task_key("task B")) + .await + .is_none()); + } + + #[tokio::test] + async fn tombstone_removes_stale_keyed_entry() { + // A `delegate_to_agent` tool call registered a keyed entry but its MCP + // round-trip never reached the broker (the call failed / the turn was + // interrupted). A terminal `ToolCallUpdate` tombstones the entry so it + // can't linger indefinitely (keyed entries are never aged out). + let broker = DelegationBroker::new( + Arc::new(MockSpawner::new()) as Arc, + shallow_lookup(), + ); + broker + .register_pending_tool_call_with_key("p1", "tc-stale".into(), Some(task_key("task A"))) + .await; + assert!(broker.tombstone_pending_tool_call("p1", "tc-stale").await); + assert!(broker + .take_matching_tool_call("p1", &task_key("task A")) + .await + .is_none()); + } + + #[tokio::test] + async fn tombstone_prevents_same_key_misbind() { + // The High regression: without the tombstone, a stale keyed entry is + // retained forever and a LATER identical-key delegation claims its dead + // id (the exact-key scan returns the oldest match). After tombstoning the + // stale entry, a fresh registration for the same key binds to the FRESH + // id instead. + let broker = DelegationBroker::new( + Arc::new(MockSpawner::new()) as Arc, + shallow_lookup(), + ); + broker + .register_pending_tool_call_with_key("p1", "tc-stale".into(), Some(task_key("task A"))) + .await; + broker.tombstone_pending_tool_call("p1", "tc-stale").await; + broker + .register_pending_tool_call_with_key("p1", "tc-fresh".into(), Some(task_key("task A"))) + .await; + assert_eq!( + broker + .take_matching_tool_call("p1", &task_key("task A")) + .await + .as_deref(), + Some("tc-fresh"), + "a later same-key delegation must claim the fresh id, not the tombstoned one" + ); + } + + #[tokio::test] + async fn tombstone_leaves_other_entries_intact() { + // A terminal update for an unrelated (non-delegation) id no-ops and must + // leave a registered delegation untouched. + let broker = DelegationBroker::new( + Arc::new(MockSpawner::new()) as Arc, + shallow_lookup(), + ); + broker + .register_pending_tool_call_with_key("p1", "tc-keep".into(), Some(task_key("task A"))) + .await; + assert!( + !broker + .tombstone_pending_tool_call("p1", "tc-bash-123") + .await + ); + assert_eq!( + broker + .take_matching_tool_call("p1", &task_key("task A")) + .await + .as_deref(), + Some("tc-keep") + ); + } + + #[tokio::test] + async fn tombstone_then_reregister_same_id_stays_dropped() { + // After tombstoning a real entry, an out-of-order re-registration of the + // same id is dropped by the Tier-1 consumed check — mirrors + // `explicit_tool_use_id_consumes_pending_entry_acp_first`. + let broker = DelegationBroker::new( + Arc::new(MockSpawner::new()) as Arc, + shallow_lookup(), + ); + broker + .register_pending_tool_call_with_key("p1", "tc-stale".into(), Some(task_key("task A"))) + .await; + assert!(broker.tombstone_pending_tool_call("p1", "tc-stale").await); + broker + .register_pending_tool_call_with_key("p1", "tc-stale".into(), Some(task_key("task A"))) + .await; + assert!( + broker + .take_matching_tool_call("p1", &task_key("task A")) + .await + .is_none(), + "a re-registration after tombstone must stay dropped" + ); + } + + #[tokio::test] + async fn tombstone_noop_does_not_record_consumed() { + // The tombstone runs for EVERY terminal tool-call update, most of them + // non-delegations. A no-op tombstone (id not pending) must NOT record + // `consumed` — otherwise `consumed` (no TTL/cap) would grow with every + // completed tool call, and a later legitimate registration of that id + // would be wrongly dropped. + let broker = DelegationBroker::new( + Arc::new(MockSpawner::new()) as Arc, + shallow_lookup(), + ); + assert!(!broker.tombstone_pending_tool_call("p1", "tc-x").await); + broker + .register_pending_tool_call_with_key("p1", "tc-x".into(), Some(task_key("task A"))) + .await; + assert_eq!( + broker + .take_matching_tool_call("p1", &task_key("task A")) + .await + .as_deref(), + Some("tc-x"), + "a no-op tombstone must not record consumed and drop a later registration" + ); + } + + #[tokio::test] + async fn tombstone_removes_only_the_matching_entry_from_a_multi_entry_bucket() { + // Tombstoning a MIDDLE entry removes only that id (retain is by exact + // tool_call_id, position-independent) and leaves the siblings claimable + // by their own keys. + let broker = DelegationBroker::new( + Arc::new(MockSpawner::new()) as Arc, + shallow_lookup(), + ); + broker + .register_pending_tool_call_with_key("p1", "tc-a".into(), Some(task_key("task A"))) + .await; + broker + .register_pending_tool_call_with_key("p1", "tc-b".into(), Some(task_key("task B"))) + .await; + broker + .register_pending_tool_call_with_key("p1", "tc-c".into(), Some(task_key("task C"))) + .await; + assert!(broker.tombstone_pending_tool_call("p1", "tc-b").await); + assert!(broker + .take_matching_tool_call("p1", &task_key("task B")) + .await + .is_none()); + assert_eq!( + broker + .take_matching_tool_call("p1", &task_key("task A")) + .await + .as_deref(), + Some("tc-a") + ); + assert_eq!( + broker + .take_matching_tool_call("p1", &task_key("task C")) + .await + .as_deref(), + Some("tc-c") + ); + } + + #[tokio::test] + async fn keyed_pending_entries_have_no_count_cap() { + // Regression for the PENDING_QUEUE_CAP removal: a high-fan-out parent + // can register hundreds of keyed pending tool_calls — each awaiting its + // own serialized MCP round-trip — and EVERY one is retained. The old + // hard cap evicted the oldest keyed entry past 32, orphaning its card to + // a synthetic id. Keyed entries are now bounded only by claim, terminal + // tombstoning, and per-parent teardown. + let broker = DelegationBroker::new( + Arc::new(MockSpawner::new()) as Arc, + shallow_lookup(), + ); + const N: usize = 256; + for i in 0..N { + broker + .register_pending_tool_call_with_key( + "p1", + format!("tc-{i}"), + Some(task_key(&format!("task {i}"))), + ) + .await; + } + { + let map = broker.tool_calls.inner.lock().await; + let bucket = map.get("p1").expect("bucket present"); + assert_eq!( + bucket.pending.len(), + N, + "all keyed pending entries must be retained — no count cap" + ); + } + // Each entry stays individually claimable by its exact key, in any + // order — proving none were dropped or mis-bound by fan-out. + for i in [0usize, N / 2, N - 1] { + let claimed = broker + .take_matching_tool_call("p1", &task_key(&format!("task {i}"))) + .await; + assert_eq!(claimed.as_deref(), Some(format!("tc-{i}").as_str())); + } + } + + #[tokio::test] + async fn keyed_pending_entry_drains_via_tombstone() { + // The drain path the no-cap design relies on: when the parent-side ACP + // tool_call goes terminal before its MCP round-trip ever claims it, + // `tombstone_pending_tool_call` removes the keyed entry (so it can't + // linger) AND records it consumed (so a late re-emit can't mis-bind a + // later delegation sharing the same key). + let broker = DelegationBroker::new( + Arc::new(MockSpawner::new()) as Arc, + shallow_lookup(), + ); + broker + .register_pending_tool_call_with_key("p1", "tc-x".into(), Some(task_key("task x"))) + .await; + assert!( + broker.tombstone_pending_tool_call("p1", "tc-x").await, + "tombstone must report it removed the pending entry" + ); + assert!( + broker + .take_matching_tool_call("p1", &task_key("task x")) + .await + .is_none(), + "a tombstoned entry must be drained from pending" + ); + // Re-register of the same id after tombstoning is dropped by the + // Tier-1 consumed check, so it can never be claimed. + broker + .register_pending_tool_call_with_key("p1", "tc-x".into(), Some(task_key("task x"))) + .await; + assert!( + broker + .take_matching_tool_call("p1", &task_key("task x")) + .await + .is_none(), + "consumed memory must reject a re-emit of a tombstoned id" + ); + } + + #[tokio::test] + async fn reregistration_refines_key_with_late_working_dir() { + // Codex re-review fix: the same tool_call_id first registers with a key + // LACKING working_dir (an early parseable raw_input), then a later + // ToolCallUpdate completes it with the explicit working_dir. The stored + // key must be REPLACED with the fuller one — otherwise the MCP claim + // keying on Some(dir) can't match the stale None and orphans to a + // synthetic id (dead card for explicit-working-dir delegations). + let broker = DelegationBroker::new( + Arc::new(MockSpawner::new()) as Arc, + shallow_lookup(), + ); + broker + .register_pending_tool_call_with_key( + "p1", + "tc-d".into(), + Some(key_for(AgentType::Codex, "build")), + ) + .await; + // Later update adds the explicit working_dir → key is refined in place. + broker + .register_pending_tool_call_with_key( + "p1", + "tc-d".into(), + Some(key_with_dir("build", "/repo")), + ) + .await; + // The stale `working_dir: None` key no longer matches (it was replaced)… + assert!(broker + .take_matching_tool_call("p1", &key_for(AgentType::Codex, "build")) + .await + .is_none()); + // …and the refined `Some("/repo")` key claims the real id. + assert_eq!( + broker + .take_matching_tool_call("p1", &key_with_dir("build", "/repo")) + .await + .as_deref(), + Some("tc-d"), + "the MCP claim with the explicit working_dir must match the refined key" + ); + } + + #[tokio::test] + async fn empty_parent_tool_use_id_claims_pending_then_completes() { + let mock = Arc::new(MockSpawner::new()); + mock.queue_spawn(Ok("c1".into())).await; + mock.queue_send(Ok(7)).await; + let broker = + DelegationBroker::new(mock.clone() as Arc, shallow_lookup()); + enable_delegation(&broker).await; + broker + .register_pending_tool_call("parent-conn", "tu-from-acp".into()) + .await; + let driver = { + let broker = broker.clone(); + tokio::spawn(async move { broker.handle_request(request(1, "")).await }) + }; + while broker.pending_count().await == 0 { + tokio::time::sleep(Duration::from_millis(5)).await; + } + // The captured ACP id was consumed. + assert!(broker.take_pending_tool_call("parent-conn").await.is_none()); + let call_id = broker.peek_first_pending_call_id().await.unwrap(); + broker + .complete_call( + &call_id, + DelegationOutcome::Ok(DelegationSuccess { + text: "ok".into(), + child_conversation_id: 7, + child_agent_type: AgentType::Codex, + turn_count: 1, + duration_ms: 5, + token_usage: None, + }), + ) + .await; + let outcome = driver.await.unwrap(); + assert!(matches!(outcome, DelegationOutcome::Ok(_))); + } + + #[tokio::test] + async fn empty_parent_tool_use_id_claims_pending_arriving_late() { + // Regression: when the parent's ACP `session/update(tool_call)` + // lands at the lifecycle dispatcher AFTER `broker.handle_request` + // already entered the claim phase, the brief poll loop must still + // pick it up rather than falling back to the synthetic UUID. + let mock = Arc::new(MockSpawner::new()); + mock.queue_spawn(Ok("c-late".into())).await; + mock.queue_send(Ok(13)).await; + let broker = + DelegationBroker::new(mock.clone() as Arc, shallow_lookup()); + enable_delegation(&broker).await; + + let driver = { + let broker = broker.clone(); + tokio::spawn(async move { broker.handle_request(request(1, "")).await }) + }; + + // Give the driver time to enter the claim wait loop on an empty + // queue, then register the ACP id (simulates the dispatcher's + // ToolCall handling landing late). + tokio::time::sleep(Duration::from_millis(30)).await; + broker + .register_pending_tool_call("parent-conn", "tu-late".into()) + .await; + + while broker.pending_count().await == 0 { + tokio::time::sleep(Duration::from_millis(5)).await; + } + // The late-arriving ACP id was consumed by the broker — no leftover + // entry. + assert!(broker.take_pending_tool_call("parent-conn").await.is_none()); + let call_id = broker.peek_first_pending_call_id().await.unwrap(); + broker + .complete_call( + &call_id, + DelegationOutcome::Ok(DelegationSuccess { + text: "late ok".into(), + child_conversation_id: 13, + child_agent_type: AgentType::Codex, + turn_count: 1, + duration_ms: 5, + token_usage: None, + }), + ) + .await; + let outcome = driver.await.unwrap(); + assert!(matches!(outcome, DelegationOutcome::Ok(_))); + } + + #[tokio::test] + async fn empty_parent_tool_use_id_with_no_pending_falls_back_to_uuid() { + let mock = Arc::new(MockSpawner::new()); + mock.queue_spawn(Ok("c1".into())).await; + mock.queue_send(Ok(11)).await; + let broker = + DelegationBroker::new(mock.clone() as Arc, shallow_lookup()); + enable_delegation(&broker).await; + let driver = { + let broker = broker.clone(); + tokio::spawn(async move { broker.handle_request(request(1, "")).await }) + }; + while broker.pending_count().await == 0 { + tokio::time::sleep(Duration::from_millis(5)).await; + } + let call_id = broker.peek_first_pending_call_id().await.unwrap(); + broker + .complete_call( + &call_id, + DelegationOutcome::Ok(DelegationSuccess { + text: "fallback ok".into(), + child_conversation_id: 11, + child_agent_type: AgentType::Codex, + turn_count: 1, + duration_ms: 5, + token_usage: None, + }), + ) + .await; + let outcome = driver.await.unwrap(); + assert!(matches!(outcome, DelegationOutcome::Ok(_))); + } + + #[tokio::test] + async fn cancel_by_parent_also_drops_pending_tool_calls() { + let broker = DelegationBroker::new( + Arc::new(MockSpawner::new()) as Arc, + shallow_lookup(), + ); + broker + .register_pending_tool_call("parent-conn", "tu-1".into()) + .await; + broker.cancel_by_parent("parent-conn").await; + assert!(broker.take_pending_tool_call("parent-conn").await.is_none()); + } + + #[tokio::test] + async fn turn_cancel_keeps_consumed_rejects_reemit() { + // A turn/prompt cancel (parent connection STAYS ALIVE) must NOT drop the + // `consumed` tool_call memory. Otherwise a host re-emit of an + // already-claimed id (e.g. a terminal status-flip) re-registers as fresh + // `pending` and the next same-key delegation mis-binds to it — the + // dead-card/wrong-child class this correlation machinery exists to + // prevent. `cancel_by_parent_turn` retains `consumed`, so the re-emit + // stays rejected by the Tier-1 consumed check. + let broker = DelegationBroker::new( + Arc::new(MockSpawner::new()) as Arc, + shallow_lookup(), + ); + // Register + claim a keyed id (the delegation that just ran). + broker + .register_pending_tool_call_with_key("p1", "tc-A".into(), Some(task_key("task A"))) + .await; + assert_eq!( + broker + .take_matching_tool_call("p1", &task_key("task A")) + .await + .as_deref(), + Some("tc-A"), + ); + // Turn cancel — parent still alive. + broker.cancel_by_parent_turn("p1").await; + // Host re-emits the now-consumed id with the same key. + broker + .register_pending_tool_call_with_key("p1", "tc-A".into(), Some(task_key("task A"))) + .await; + assert!( + broker + .take_matching_tool_call("p1", &task_key("task A")) + .await + .is_none(), + "re-emit of a consumed id must stay rejected across a turn cancel" + ); + } + + #[tokio::test] + async fn turn_cancel_drops_unclaimed_pending() { + // The unclaimed `pending` half is cleared by a turn cancel (tombstoned + // into `consumed`): the cancelled turn's serial round-trip won't arrive, + // so the stale keyed entry must not remain claimable by a later same-key + // delegation. `take_matching` scans only `pending`, so it returns None. + let broker = DelegationBroker::new( + Arc::new(MockSpawner::new()) as Arc, + shallow_lookup(), + ); + broker + .register_pending_tool_call_with_key("p1", "tc-B".into(), Some(task_key("task B"))) + .await; + broker.cancel_by_parent_turn("p1").await; + assert!( + broker + .take_matching_tool_call("p1", &task_key("task B")) + .await + .is_none(), + "unclaimed pending must not stay claimable after a turn cancel" + ); + } + + #[tokio::test] + async fn turn_cancel_tombstones_pending_rejects_late_reemit() { + // Stronger than the clear test: after a turn cancel clears an UNCLAIMED + // keyed pending id, a late host re-emit of that SAME id must not + // resurrect it as a claimable entry — otherwise the next same-key + // delegation would mis-bind to the stale id. The cancel tombstones the + // cleared id into `consumed`, so the re-emit is dropped by the Tier-1 + // consumed check and never re-enters `pending`. + let broker = DelegationBroker::new( + Arc::new(MockSpawner::new()) as Arc, + shallow_lookup(), + ); + broker + .register_pending_tool_call_with_key("p1", "tc-X".into(), Some(task_key("task X"))) + .await; + broker.cancel_by_parent_turn("p1").await; + // Late re-emit of the cancelled turn's unclaimed id (same key). + broker + .register_pending_tool_call_with_key("p1", "tc-X".into(), Some(task_key("task X"))) + .await; + assert!( + broker + .take_matching_tool_call("p1", &task_key("task X")) + .await + .is_none(), + "a re-emit of a tombstoned (cleared-on-cancel) pending id must not be claimable" + ); + } + + #[tokio::test] + async fn teardown_cancel_clears_consumed() { + // The teardown variant (`cancel_by_parent`) DOES drop consumed — the + // connection is going away, so a reused connection_id must start clean. + // Contrast with `turn_cancel_keeps_consumed_rejects_reemit`. + let broker = DelegationBroker::new( + Arc::new(MockSpawner::new()) as Arc, + shallow_lookup(), + ); + broker.register_pending_tool_call("p1", "tc-A".into()).await; + assert_eq!( + broker.take_pending_tool_call("p1").await.as_deref(), + Some("tc-A"), + ); + broker.cancel_by_parent("p1").await; + // consumed cleared → the same id re-registers and is claimable again. + broker.register_pending_tool_call("p1", "tc-A".into()).await; + assert_eq!( + broker.take_pending_tool_call("p1").await.as_deref(), + Some("tc-A"), + "teardown cancel must clear consumed so id reuse is acceptable" + ); + } + + #[tokio::test] + async fn cancel_by_parent_turn_drains_synchronously_then_tears_down_child() { + // The turn cancel must (a) drop the tracker + remove parked calls + // SYNCHRONOUSLY — before the connection loop could accept the next + // prompt — so a delayed cancel can't tombstone/cancel a NEXT turn's + // entries (the invariant `drop_tool_calls_for_parent` relies on); and + // (b) still fully tear the child down (backgrounded), resolving the + // awaiting `handle_request` as canceled exactly once. + let mock = Arc::new(MockSpawner::new()); + mock.queue_spawn(Ok("child-1".into())).await; + mock.queue_send(Ok(7)).await; + let broker = + DelegationBroker::new(mock.clone() as Arc, shallow_lookup()); + enable_delegation(&broker).await; + + // Park a delegation for "parent-conn"... + let driver = { + let broker = broker.clone(); + tokio::spawn(async move { broker.handle_request(request(1, "pt-1")).await }) + }; + while broker.pending_count().await == 0 { + tokio::time::sleep(Duration::from_millis(5)).await; + } + // ...plus a separate unclaimed keyed tracker entry on the same parent. + broker + .register_pending_tool_call_with_key( + "parent-conn", + "tc-Z".into(), + Some(task_key("task Z")), + ) + .await; + + broker.cancel_by_parent_turn("parent-conn").await; + + // (a) Synchronously — no sleep: the parked call is removed and the + // tracker entry is dropped (tombstoned), so neither can leak into a + // next-turn registration that the backgrounded teardown might clobber. + assert_eq!( + broker.pending_count().await, + 0, + "parked call must be drained synchronously by the turn cancel" + ); + assert!( + broker + .take_matching_tool_call("parent-conn", &task_key("task Z")) + .await + .is_none(), + "tracker pending must be dropped synchronously by the turn cancel" + ); + + // (b) The backgrounded child teardown still resolves the driver as + // canceled and tears the child down exactly once. + match driver.await.unwrap() { + DelegationOutcome::Err { code, .. } => assert_eq!(code, "canceled"), + other => panic!("expected canceled, got {other:?}"), + } + assert_eq!(mock.cancels.lock().await.as_slice(), &["child-1"]); + assert_eq!(mock.disconnects.lock().await.as_slice(), &["child-1"]); + } + + #[tokio::test] + async fn depth_limit_allows_root() { + let mock = Arc::new(MockSpawner::new()); + mock.queue_spawn(Ok("c1".into())).await; + mock.queue_send(Ok(7)).await; + let lookup = Arc::new(MockDepth(vec![(1, None)])) as Arc; + let broker = DelegationBroker::new(mock.clone() as Arc, lookup); + broker + .set_config(DelegationConfig { + enabled: true, + depth_limit: 2, + ..DelegationConfig::default() + }) + .await; + + let driver = { + let broker = broker.clone(); + tokio::spawn(async move { broker.handle_request(request(1, "pt-1")).await }) + }; + while broker.pending_count().await == 0 { + tokio::time::sleep(Duration::from_millis(5)).await; + } + let call_id = broker.peek_first_pending_call_id().await.unwrap(); + broker + .complete_call( + &call_id, + DelegationOutcome::Ok(DelegationSuccess { + text: "ok".into(), + child_conversation_id: 7, + child_agent_type: AgentType::ClaudeCode, + turn_count: 1, + duration_ms: 5, + token_usage: None, + }), + ) + .await; + let outcome = driver.await.unwrap(); + assert!(matches!(outcome, DelegationOutcome::Ok(_))); + } + + // -- Meta writer lifecycle -------------------------------------------- + + use crate::acp::delegation::meta_writer::mock::MockMetaWriter; + use crate::acp::delegation::meta_writer::DelegationMetaWriter; + + async fn broker_with_meta( + mock: Arc, + writer: Arc, + ) -> DelegationBroker { + let broker = DelegationBroker::with_meta_writer( + mock as Arc, + shallow_lookup(), + writer as Arc, + ); + enable_delegation(&broker).await; + broker + } + + #[tokio::test] + async fn meta_writes_carry_task_preview_and_task_id_on_every_write() { + // Meta is replace-wholesale on the ToolCallState, so BOTH the running + // and the terminal writes must carry the task label + broker task id — + // they are the persisted card's only label source on hosts whose + // raw_input never carries the arguments (Cursor). + let mock = Arc::new(MockSpawner::new()); + mock.queue_spawn(Ok("child-conn-t".into())).await; + mock.queue_send(Ok(42)).await; + let writer = Arc::new(MockMetaWriter::new()); + let broker = broker_with_meta(mock.clone(), writer.clone()).await; + + let driver = { + let broker = broker.clone(); + tokio::spawn(async move { broker.handle_request(request(1, "pt-task")).await }) + }; + let call_id = loop { + if let Some(id) = broker.peek_first_pending_call_id().await { + break id; + } + tokio::time::sleep(Duration::from_millis(5)).await; + }; + broker + .complete_call( + &call_id, + DelegationOutcome::Ok(DelegationSuccess { + text: "done".into(), + child_conversation_id: 42, + child_agent_type: AgentType::ClaudeCode, + turn_count: 1, + duration_ms: 5, + token_usage: None, + }), + ) + .await; + driver.await.unwrap(); + + let calls = writer.snapshot().await; + assert_eq!(calls.len(), 2); + for call in &calls { + let inner = call + .meta + .get("codeg.delegation") + .unwrap() + .as_object() + .unwrap(); + assert_eq!( + inner.get("task_preview").unwrap().as_str().unwrap(), + "do x", + "every write must keep the task label (status={})", + inner.get("status").unwrap() + ); + assert_eq!( + inner.get("task_id").unwrap().as_str().unwrap(), + &call_id, + "task_id must be the broker call id on every write" + ); + } + } + + #[tokio::test] + async fn identityless_fifo_claim_restores_delegate_identity() { + // Cursor path: the ACP announcement registered an identity-less + // candidate ("MCP: tool" + "{}"), the MCP round-trip arrives with no + // explicit tool_use id. The post-budget FIFO claim must land on the + // candidate AND restore the call's identity (canonical delegate title + // + reconstructed arguments) on the live tool call. + let mock = Arc::new(MockSpawner::new()); + mock.queue_spawn(Ok("child-conn-i".into())).await; + mock.queue_send(Ok(43)).await; + let writer = Arc::new(MockMetaWriter::new()); + let broker = broker_with_meta(mock.clone(), writer.clone()).await; + broker + .register_identityless_tool_call("parent-conn", "call-cursor-7\nfc_x_0".into()) + .await; + + let driver = { + let broker = broker.clone(); + // Empty tool_use id → claim path (2s budget, then FIFO). + tokio::spawn(async move { broker.handle_request(request(1, "")).await }) + }; + let call_id = loop { + if let Some(id) = broker.peek_first_pending_call_id().await { + break id; + } + tokio::time::sleep(Duration::from_millis(5)).await; + }; + broker + .complete_call( + &call_id, + DelegationOutcome::Ok(DelegationSuccess { + text: "done".into(), + child_conversation_id: 43, + child_agent_type: AgentType::ClaudeCode, + turn_count: 1, + duration_ms: 5, + token_usage: None, + }), + ) + .await; + driver.await.unwrap(); + + let identities = writer.identity_snapshot().await; + assert_eq!(identities.len(), 1, "exactly one identity restoration"); + let id_write = &identities[0]; + assert_eq!(id_write.parent_connection_id, "parent-conn"); + assert_eq!(id_write.tool_call_id, "call-cursor-7\nfc_x_0"); + assert_eq!( + id_write.title, + crate::acp::delegation::DELEGATE_TOOL_REWRITE_TITLE + ); + assert_eq!( + id_write.raw_input.get("task").unwrap().as_str().unwrap(), + "do x" + ); + assert_eq!( + id_write + .raw_input + .get("agent_type") + .unwrap() + .as_str() + .unwrap(), + "claude_code" + ); + // The meta writes bound to the REAL claimed id, not a synthetic one. + let metas = writer.snapshot().await; + assert!(metas + .iter() + .all(|m| m.parent_tool_use_id == "call-cursor-7\nfc_x_0")); + } + + #[tokio::test] + async fn keyed_claim_does_not_rewrite_host_identity() { + // A host that shipped real raw_input (keyed registration) keeps its + // own wire identity — reconstructing raw_input would clobber + // host-specific fields. + let mock = Arc::new(MockSpawner::new()); + mock.queue_spawn(Ok("child-conn-k".into())).await; + mock.queue_send(Ok(44)).await; + let writer = Arc::new(MockMetaWriter::new()); + let broker = broker_with_meta(mock.clone(), writer.clone()).await; + broker + .register_pending_tool_call_with_key( + "parent-conn", + "tc-keyed".into(), + Some(DelegationMatchKey { + agent_type: AgentType::ClaudeCode, + task: "do x".into(), + working_dir: None, + }), + ) + .await; + + let driver = { + let broker = broker.clone(); + tokio::spawn(async move { broker.handle_request(request(1, "")).await }) + }; + let call_id = loop { + if let Some(id) = broker.peek_first_pending_call_id().await { + break id; + } + tokio::time::sleep(Duration::from_millis(5)).await; + }; + broker + .complete_call( + &call_id, + DelegationOutcome::Ok(DelegationSuccess { + text: "done".into(), + child_conversation_id: 44, + child_agent_type: AgentType::ClaudeCode, + turn_count: 1, + duration_ms: 5, + token_usage: None, + }), + ) + .await; + driver.await.unwrap(); + + assert!( + writer.identity_snapshot().await.is_empty(), + "keyed (host-identified) claims must not be rewritten" + ); + let metas = writer.snapshot().await; + assert!(metas.iter().all(|m| m.parent_tool_use_id == "tc-keyed")); + } + + #[tokio::test] + async fn rewrite_identityless_tool_call_claims_and_writes_status_identity() { + let writer = Arc::new(MockMetaWriter::new()); + let broker = broker_with_meta(Arc::new(MockSpawner::new()), writer.clone()).await; + broker + .register_identityless_tool_call("parent-conn", "call-status-1".into()) + .await; + + let claimed = broker + .rewrite_identityless_tool_call( + "parent-conn", + crate::acp::delegation::STATUS_TOOL_REWRITE_TITLE, + serde_json::json!({"task_ids": ["t-1"], "wait_ms": 0}), + ) + .await; + assert_eq!(claimed.as_deref(), Some("call-status-1")); + let identities = writer.identity_snapshot().await; + assert_eq!(identities.len(), 1); + assert_eq!( + identities[0].title, + crate::acp::delegation::STATUS_TOOL_REWRITE_TITLE + ); + assert_eq!( + identities[0].raw_input.get("task_ids").unwrap()[0] + .as_str() + .unwrap(), + "t-1" + ); + // Consumed: the candidate can't be claimed again by the delegate FIFO. + assert!(broker.take_pending_tool_call("parent-conn").await.is_none()); + } + + #[tokio::test] + async fn rewrite_skips_connections_that_never_announced_identityless() { + // Plain unkeyed registration (a keyless delegation invocation) must + // NOT be renamed — and the sticky gate must return instantly (no + // 300 ms poll) for such connections. Also: the entry stays claimable + // by the delegate FIFO afterwards. + let writer = Arc::new(MockMetaWriter::new()); + let broker = broker_with_meta(Arc::new(MockSpawner::new()), writer.clone()).await; + broker + .register_pending_tool_call("parent-conn", "tc-plain".into()) + .await; + + let started = std::time::Instant::now(); + let claimed = broker + .rewrite_identityless_tool_call( + "parent-conn", + crate::acp::delegation::STATUS_TOOL_REWRITE_TITLE, + serde_json::json!({"task_ids": ["t-1"]}), + ) + .await; + assert!(claimed.is_none()); + // The poll path sleeps ≥300 ms (30 × 10 ms lower bounds); the gate + // path sleeps zero. 280 ms discriminates the two while leaving slack + // for full-suite parallel-load scheduling jitter. + assert!( + started.elapsed() < Duration::from_millis(280), + "sticky gate must skip the poll for hosts without identity-less announcements" + ); + assert!(writer.identity_snapshot().await.is_empty()); + assert_eq!( + broker + .take_pending_tool_call("parent-conn") + .await + .as_deref(), + Some("tc-plain"), + "the plain unkeyed entry must remain for the delegate FIFO" + ); + } + + #[tokio::test] + async fn meta_writer_records_running_then_completed_on_happy_path() { + let mock = Arc::new(MockSpawner::new()); + mock.queue_spawn(Ok("child-conn-1".into())).await; + mock.queue_send(Ok(42)).await; + let writer = Arc::new(MockMetaWriter::new()); + let broker = broker_with_meta(mock.clone(), writer.clone()).await; + + let driver = { + let broker = broker.clone(); + tokio::spawn(async move { broker.handle_request(request(1, "pt-real")).await }) + }; + let call_id = loop { + if let Some(id) = broker.peek_first_pending_call_id().await { + break id; + } + tokio::time::sleep(Duration::from_millis(5)).await; + }; + broker + .complete_call( + &call_id, + DelegationOutcome::Ok(DelegationSuccess { + text: "done".into(), + child_conversation_id: 42, + child_agent_type: AgentType::ClaudeCode, + turn_count: 1, + duration_ms: 5, + token_usage: None, + }), + ) + .await; + driver.await.unwrap(); + + let calls = writer.snapshot().await; + assert_eq!(calls.len(), 2); + // First write: running, with child connection + conversation ids. + let first = &calls[0]; + assert_eq!(first.parent_tool_use_id, "pt-real"); + let inner_first = first + .meta + .get("codeg.delegation") + .unwrap() + .as_object() + .unwrap(); + assert_eq!( + inner_first.get("status").unwrap().as_str().unwrap(), + "running" + ); + assert_eq!( + inner_first + .get("child_connection_id") + .unwrap() + .as_str() + .unwrap(), + "child-conn-1" + ); + assert_eq!( + inner_first + .get("child_conversation_id") + .unwrap() + .as_i64() + .unwrap(), + 42 + ); + // Second write: completed. + let second = &calls[1]; + let inner_second = second + .meta + .get("codeg.delegation") + .unwrap() + .as_object() + .unwrap(); + assert_eq!( + inner_second.get("status").unwrap().as_str().unwrap(), + "completed" + ); + } + + #[tokio::test] + async fn meta_writer_records_failed_on_err_outcome() { + let mock = Arc::new(MockSpawner::new()); + mock.queue_spawn(Ok("child-conn-2".into())).await; + mock.queue_send(Ok(7)).await; + let writer = Arc::new(MockMetaWriter::new()); + let broker = broker_with_meta(mock.clone(), writer.clone()).await; + + let driver = { + let broker = broker.clone(); + tokio::spawn(async move { broker.handle_request(request(1, "pt-err")).await }) + }; + let call_id = loop { + if let Some(id) = broker.peek_first_pending_call_id().await { + break id; + } + tokio::time::sleep(Duration::from_millis(5)).await; + }; + broker + .complete_call( + &call_id, + DelegationOutcome::from_err( + DelegationError::SubagentRuntimeError("agent died".into()), + Some(7), + ), + ) + .await; + driver.await.unwrap(); + + let calls = writer.snapshot().await; + assert_eq!(calls.len(), 2); + let inner = calls[1] + .meta + .get("codeg.delegation") + .unwrap() + .as_object() + .unwrap(); + assert_eq!(inner.get("status").unwrap().as_str().unwrap(), "failed"); + assert_eq!( + inner.get("error_code").unwrap().as_str().unwrap(), + "subagent_error" + ); + } + + // -- Registration-race: child terminal failure before the entry is parked -- + + /// Headline regression: a child terminal failure (auth error / immediate + /// process death) that fires AFTER the broker reserved the child but BEFORE + /// it parked the pending entry must still resolve the parked request — not + /// no-op and strand it on `rx.await` forever. The `send_gate` pins + /// `handle_request` in exactly that window; we fire the failure, release the + /// gate, and assert the request resolves as canceled (carrying the + /// terminal-error detail) with a single child disconnect and a clean + /// running→failed meta trail. + #[tokio::test] + async fn child_failure_before_park_resolves_instead_of_hanging() { + let mock = Arc::new(MockSpawner::new()); + mock.queue_spawn(Ok("c-fast-fail".into())).await; + mock.queue_send(Ok(55)).await; + let release = mock.install_send_gate().await; + let writer = Arc::new(MockMetaWriter::new()); + let broker = broker_with_meta(mock.clone(), writer.clone()).await; + + let driver = { + let broker = broker.clone(); + tokio::spawn(async move { broker.handle_request(request(1, "pt-fast")).await }) + }; + + // Wait until handle_request has spawned + reserved the child and is + // held inside send_prompt by the gate — entry NOT yet parked. + loop { + if broker.reserved_child_count().await == 1 { + break; + } + tokio::time::sleep(Duration::from_millis(5)).await; + } + assert_eq!(broker.pending_count().await, 0, "entry not parked yet"); + + // Child dies before the entry is parked. With the reservation in place + // this buffers (rather than no-oping on a not-yet-existent entry). + broker + .cancel_by_child_connection("c-fast-fail", Some("Authentication required")) + .await; + assert_eq!(broker.early_cancel_count().await, 1, "failure buffered"); + + // Release send_prompt → handle_request parks, drains the buffered + // failure, and resolves inline instead of hanging. + let _ = release.send(()); + let outcome = driver.await.unwrap(); + match outcome { + DelegationOutcome::Err { + code, + message, + child_conversation_id, + } => { + assert_eq!(code, "canceled"); + assert!( + message.contains("Authentication required"), + "reason should carry the terminal-error detail, got: {message}" + ); + assert_eq!(child_conversation_id, Some(55)); + } + other => panic!("expected canceled Err, got {other:?}"), + } + + // Reservation + buffer drained; child torn down exactly once. + assert_eq!(broker.pending_count().await, 0); + assert_eq!(broker.reserved_child_count().await, 0); + assert_eq!(broker.early_cancel_count().await, 0); + assert_eq!(mock.disconnects.lock().await.as_slice(), &["c-fast-fail"]); + + // Meta trail: running (written pre-park) then failed/canceled (pickup). + let calls = writer.snapshot().await; + assert_eq!(calls.len(), 2); + let running = calls[0] + .meta + .get("codeg.delegation") + .unwrap() + .as_object() + .unwrap(); + assert_eq!(running.get("status").unwrap().as_str().unwrap(), "running"); + let failed = calls[1] + .meta + .get("codeg.delegation") + .unwrap() + .as_object() + .unwrap(); + assert_eq!(failed.get("status").unwrap().as_str().unwrap(), "failed"); + assert_eq!( + failed.get("error_code").unwrap().as_str().unwrap(), + "canceled" + ); + } + + /// The SAME race on the SUCCESS path: a `TurnComplete` whose `complete_call` + /// fires AFTER the delegation reserved but BEFORE `handle_request` parked (a + /// fast/empty turn whose completion propagates while the broker is still + /// awaiting the parent `write_meta`) must still resolve the request. The + /// prompt is only *enqueued* by `send_prompt`, so the child loop can emit + /// `TurnComplete` before the park. The `send_gate` pins `handle_request` in + /// the reserve→park window; we resolve via the reserved `call_id` (the entry + /// isn't parked yet) and assert the request returns Ok instead of hanging. + #[tokio::test] + async fn completion_before_park_resolves_instead_of_hanging() { + let mock = Arc::new(MockSpawner::new()); + mock.queue_spawn(Ok("c-fast-ok".into())).await; + mock.queue_send(Ok(70)).await; + let release = mock.install_send_gate().await; + let writer = Arc::new(MockMetaWriter::new()); + let broker = broker_with_meta(mock.clone(), writer.clone()).await; + + let driver = { + let broker = broker.clone(); + tokio::spawn(async move { broker.handle_request(request(1, "pt-ok")).await }) + }; + + // Wait until reserved (spawned + id minted, held in send_prompt by the + // gate); the entry is NOT parked yet, so grab the call_id from the + // reservation rather than the parked-calls map. + let call_id = loop { + if let Some(id) = broker.peek_reserved_call_id().await { + break id; + } + tokio::time::sleep(Duration::from_millis(5)).await; + }; + assert_eq!(broker.pending_count().await, 0, "entry not parked yet"); + + // TurnComplete beats the park. With the reservation in place this + // buffers (rather than no-oping on a not-yet-existent entry). + broker + .complete_call( + &call_id, + DelegationOutcome::Ok(DelegationSuccess { + text: "fast done".into(), + child_conversation_id: 70, + child_agent_type: AgentType::ClaudeCode, + turn_count: 1, + duration_ms: 5, + token_usage: None, + }), + ) + .await; + assert_eq!( + broker.early_complete_count().await, + 1, + "completion buffered" + ); + + // Release send_prompt → handle_request parks, drains the buffered + // completion, and resolves inline instead of hanging. + let _ = release.send(()); + let outcome = driver.await.unwrap(); + match outcome { + DelegationOutcome::Ok(s) => { + assert_eq!(s.text, "fast done"); + assert_eq!(s.child_conversation_id, 70); + } + other => panic!("expected Ok, got {other:?}"), + } + + assert_eq!(broker.pending_count().await, 0); + assert_eq!(broker.reserved_call_count().await, 0); + assert_eq!(broker.reserved_child_count().await, 0); + assert_eq!(broker.early_complete_count().await, 0); + assert_eq!(mock.disconnects.lock().await.as_slice(), &["c-fast-ok"]); + + // Meta trail: running (written pre-park) then completed (pickup). + let calls = writer.snapshot().await; + assert_eq!(calls.len(), 2); + let running = calls[0] + .meta + .get("codeg.delegation") + .unwrap() + .as_object() + .unwrap(); + assert_eq!(running.get("status").unwrap().as_str().unwrap(), "running"); + let completed = calls[1] + .meta + .get("codeg.delegation") + .unwrap() + .as_object() + .unwrap(); + assert_eq!( + completed.get("status").unwrap().as_str().unwrap(), + "completed" + ); + } + + /// The reservation is released at park, and a SUCCESSFUL completion buffers + /// nothing. The child's post-completion disconnect (normal v1 one-shot + /// teardown) finds the child un-reserved and must NOT buffer a spurious + /// cancel — otherwise every completed delegation would leak a buffer entry. + #[tokio::test] + async fn normal_completion_leaves_no_reservation_or_buffer() { + let mock = Arc::new(MockSpawner::new()); + mock.queue_spawn(Ok("c-clean".into())).await; + mock.queue_send(Ok(60)).await; + let broker = + DelegationBroker::new(mock.clone() as Arc, shallow_lookup()); + enable_delegation(&broker).await; + + let driver = { + let broker = broker.clone(); + tokio::spawn(async move { broker.handle_request(request(1, "pt-clean")).await }) + }; + let call_id = loop { + if let Some(id) = broker.peek_first_pending_call_id().await { + break id; + } + tokio::time::sleep(Duration::from_millis(5)).await; + }; + // Parked → reservation already released. + assert_eq!( + broker.reserved_child_count().await, + 0, + "park releases the reservation" + ); + + broker + .complete_call( + &call_id, + DelegationOutcome::Ok(DelegationSuccess { + text: "ok".into(), + child_conversation_id: 60, + child_agent_type: AgentType::ClaudeCode, + turn_count: 1, + duration_ms: 5, + token_usage: None, + }), + ) + .await; + assert!(matches!(driver.await.unwrap(), DelegationOutcome::Ok(_))); + + // The child's post-completion disconnect arrives. Child is no longer + // reserved → must NOT buffer a spurious cancel. + broker.cancel_by_child_connection("c-clean", None).await; + assert_eq!( + broker.early_cancel_count().await, + 0, + "a post-resolution teardown must not buffer a spurious cancel" + ); + assert_eq!(broker.pending_count().await, 0); + } + + // -- Item 1: parent-cancel coverage of the `handle_request` setup window -- + + /// A parent cancel that lands while `handle_request` is INSIDE `spawn` (the + /// child exists but no prompt has been sent) must disconnect the child and + /// bail — never send it a prompt — instead of no-oping and letting it run + /// orphaned. Pinned with the spawn gate. + #[tokio::test] + async fn parent_cancel_in_spawn_window_disconnects_child_without_sending() { + let mock = Arc::new(MockSpawner::new()); + mock.queue_spawn(Ok("c2".into())).await; + mock.queue_send(Ok(99)).await; // staged but must NOT be consumed + let release = mock.install_spawn_gate().await; + let broker = + DelegationBroker::new(mock.clone() as Arc, shallow_lookup()); + enable_delegation(&broker).await; + + let driver = { + let broker = broker.clone(); + tokio::spawn(async move { broker.handle_request(request(1, "pt-2")).await }) + }; + // Inside spawn (call recorded, held by the gate): registered in-flight, + // not yet reserved. + loop { + if !mock.spawn_args.lock().await.is_empty() { + break; + } + tokio::time::sleep(Duration::from_millis(5)).await; + } + assert_eq!(broker.inflight_count().await, 1); + assert_eq!(broker.reserved_child_count().await, 0, "not reserved yet"); + + broker.cancel_by_parent_turn("parent-conn").await; + let _ = release.send(()); + + match driver.await.unwrap() { + DelegationOutcome::Err { code, .. } => assert_eq!(code, "canceled"), + other => panic!("expected canceled, got {other:?}"), + } + assert_eq!(mock.disconnects.lock().await.as_slice(), &["c2"]); + assert!( + mock.cancels.lock().await.is_empty(), + "no prompt was sent, so no cancel — disconnect only" + ); + assert_eq!( + mock.send_results.lock().await.len(), + 1, + "send must not be consumed — no prompt sent to an abandoned child" + ); + assert_eq!(broker.inflight_count().await, 0); + assert_eq!(broker.reserved_child_count().await, 0); + } + + /// A parent cancel that lands in the reserve→park window (prompt already + /// sent, entry not yet parked) must cancel AND disconnect the child and + /// resolve the request as canceled. Pinned with the send gate; also asserts + /// the running→failed/canceled meta trail. + #[tokio::test] + async fn parent_cancel_in_reserve_park_window_tears_down_child() { + let mock = Arc::new(MockSpawner::new()); + mock.queue_spawn(Ok("c3".into())).await; + mock.queue_send(Ok(33)).await; + let release = mock.install_send_gate().await; + let writer = Arc::new(MockMetaWriter::new()); + let broker = broker_with_meta(mock.clone(), writer.clone()).await; + + let driver = { + let broker = broker.clone(); + tokio::spawn(async move { broker.handle_request(request(1, "pt-3")).await }) + }; + // Spawned + reserved, held inside send_prompt. + loop { + if broker.reserved_child_count().await == 1 { + break; + } + tokio::time::sleep(Duration::from_millis(5)).await; + } + assert_eq!(broker.inflight_count().await, 1); + assert_eq!(broker.pending_count().await, 0, "not parked yet"); + + broker.cancel_by_parent_turn("parent-conn").await; + let _ = release.send(()); + + match driver.await.unwrap() { + DelegationOutcome::Err { + code, + child_conversation_id, + .. + } => { + assert_eq!(code, "canceled"); + assert_eq!(child_conversation_id, Some(33)); + } + other => panic!("expected canceled, got {other:?}"), + } + // Prompt was sent → child cancel()'d AND disconnected. + assert_eq!(mock.cancels.lock().await.as_slice(), &["c3"]); + assert_eq!(mock.disconnects.lock().await.as_slice(), &["c3"]); + assert_eq!(broker.inflight_count().await, 0); + assert_eq!(broker.reserved_child_count().await, 0); + assert_eq!(broker.early_cancel_count().await, 0); + assert_eq!(broker.pending_count().await, 0); + + // Meta trail: running (pre-park) then failed/canceled (ParentCanceled). + let calls = writer.snapshot().await; + assert_eq!(calls.len(), 2); + let running = calls[0] + .meta + .get("codeg.delegation") + .unwrap() + .as_object() + .unwrap(); + assert_eq!(running.get("status").unwrap().as_str().unwrap(), "running"); + let failed = calls[1] + .meta + .get("codeg.delegation") + .unwrap() + .as_object() + .unwrap(); + assert_eq!(failed.get("status").unwrap().as_str().unwrap(), "failed"); + assert_eq!( + failed.get("error_code").unwrap().as_str().unwrap(), + "canceled" + ); + } + + /// Strict first-terminal-wins: when a child completion buffers FIRST and a + /// parent cancel lands afterward, the child's earlier arrival stamp wins and + /// its real result is preserved (the cancel is moot — the child already + /// finished before it). + #[tokio::test] + async fn child_terminal_wins_over_later_parent_cancel() { + let mock = Arc::new(MockSpawner::new()); + mock.queue_spawn(Ok("c4".into())).await; + mock.queue_send(Ok(44)).await; + let release = mock.install_send_gate().await; + let broker = + DelegationBroker::new(mock.clone() as Arc, shallow_lookup()); + enable_delegation(&broker).await; + + let driver = { + let broker = broker.clone(); + tokio::spawn(async move { broker.handle_request(request(1, "pt-4")).await }) + }; + let call_id = loop { + if let Some(id) = broker.peek_reserved_call_id().await { + break id; + } + tokio::time::sleep(Duration::from_millis(5)).await; + }; + assert_eq!(broker.inflight_count().await, 1); + + // Child completes FIRST, then the parent cancels — child result wins. + broker + .complete_call( + &call_id, + DelegationOutcome::Ok(DelegationSuccess { + text: "done".into(), + child_conversation_id: 44, + child_agent_type: AgentType::ClaudeCode, + turn_count: 1, + duration_ms: 5, + token_usage: None, + }), + ) + .await; + broker.cancel_by_parent_turn("parent-conn").await; + let _ = release.send(()); + + assert!(matches!(driver.await.unwrap(), DelegationOutcome::Ok(_))); + assert!( + mock.cancels.lock().await.is_empty(), + "child completed — the moot parent cancel must not cancel it" + ); + assert_eq!(broker.inflight_count().await, 0); + assert_eq!(broker.early_complete_count().await, 0); + } + + /// Strict first-terminal-wins (Item 3): when the parent cancel is recorded + /// BEFORE the child completion buffers, the cancel wins — the late + /// completion is discarded and the child is torn down, because the parent + /// had already abandoned the turn by the time the completion landed. + #[tokio::test] + async fn parent_cancel_wins_when_it_arrives_before_child_terminal() { + let mock = Arc::new(MockSpawner::new()); + mock.queue_spawn(Ok("c5".into())).await; + mock.queue_send(Ok(55)).await; + let release = mock.install_send_gate().await; + let broker = + DelegationBroker::new(mock.clone() as Arc, shallow_lookup()); + enable_delegation(&broker).await; + + let driver = { + let broker = broker.clone(); + tokio::spawn(async move { broker.handle_request(request(1, "pt-5")).await }) + }; + let call_id = loop { + if let Some(id) = broker.peek_reserved_call_id().await { + break id; + } + tokio::time::sleep(Duration::from_millis(5)).await; + }; + + // Parent cancels FIRST (earlier arrival stamp); the child completes + // afterward (later stamp) — first-terminal-wins judges the cancel the + // winner and discards the late completion. + broker.cancel_by_parent_turn("parent-conn").await; + broker + .complete_call( + &call_id, + DelegationOutcome::Ok(DelegationSuccess { + text: "late".into(), + child_conversation_id: 55, + child_agent_type: AgentType::ClaudeCode, + turn_count: 1, + duration_ms: 5, + token_usage: None, + }), + ) + .await; + let _ = release.send(()); + + match driver.await.unwrap() { + DelegationOutcome::Err { + code, + child_conversation_id, + .. + } => { + assert_eq!(code, "canceled"); + assert_eq!(child_conversation_id, Some(55)); + } + other => panic!( + "first-terminal-wins: an earlier parent cancel must beat a later completion, got {other:?}" + ), + } + // The abandoned child is torn down (prompt was sent → cancel + disconnect). + assert_eq!(mock.cancels.lock().await.as_slice(), &["c5"]); + assert_eq!(mock.disconnects.lock().await.as_slice(), &["c5"]); + assert_eq!(broker.inflight_count().await, 0); + // The buffered completion was drained (and discarded), leaving no leak. + assert_eq!(broker.early_complete_count().await, 0); + } + + /// Strict first-terminal-wins through the child-FAILURE buffer: a child + /// failure that buffers BEFORE a parent cancel keeps its (earlier) arrival + /// stamp and wins, so the request resolves with the child's failure detail + /// and the child is torn down once (disconnect only — the child already + /// failed, so there's no in-flight prompt to cancel). Exercises the + /// `early_cancels` stamp path that mirrors the completion case above. + #[tokio::test] + async fn child_failure_wins_over_later_parent_cancel() { + let mock = Arc::new(MockSpawner::new()); + mock.queue_spawn(Ok("cF".into())).await; + mock.queue_send(Ok(66)).await; + let release = mock.install_send_gate().await; + let broker = + DelegationBroker::new(mock.clone() as Arc, shallow_lookup()); + enable_delegation(&broker).await; + + let driver = { + let broker = broker.clone(); + tokio::spawn(async move { broker.handle_request(request(1, "pt-f")).await }) + }; + // Spawned + reserved, held inside send_prompt by the gate. + loop { + if broker.reserved_child_count().await == 1 { + break; + } + tokio::time::sleep(Duration::from_millis(5)).await; + } + + // Child fails FIRST (earlier stamp), then the parent cancels (later + // stamp) — the child terminal wins and carries its failure detail. + broker + .cancel_by_child_connection("cF", Some("boom detail")) + .await; + broker.cancel_by_parent_turn("parent-conn").await; + let _ = release.send(()); + + match driver.await.unwrap() { + DelegationOutcome::Err { + code, + message, + child_conversation_id, + } => { + assert_eq!(code, "canceled"); + assert!( + message.contains("boom detail"), + "child failure detail must survive, got: {message}" + ); + assert_eq!(child_conversation_id, Some(66)); + } + other => panic!("expected child failure Err, got {other:?}"), + } + // Child-terminal path tears down via disconnect only (no cancel). + assert_eq!(mock.disconnects.lock().await.as_slice(), &["cF"]); + assert!( + mock.cancels.lock().await.is_empty(), + "child already failed — the moot parent cancel must not cancel it" + ); + assert_eq!(broker.inflight_count().await, 0); + assert_eq!(broker.early_cancel_count().await, 0); + } + + /// The teardown variant `cancel_by_parent` covers the same reserve→park + /// window as the turn variant — both funnel through `drain_for_parent_cancel` + /// where the in-flight mark is applied. + #[tokio::test] + async fn parent_teardown_in_reserve_park_window_tears_down_child() { + let mock = Arc::new(MockSpawner::new()); + mock.queue_spawn(Ok("c7".into())).await; + mock.queue_send(Ok(77)).await; + let release = mock.install_send_gate().await; + let broker = + DelegationBroker::new(mock.clone() as Arc, shallow_lookup()); + enable_delegation(&broker).await; + + let driver = { + let broker = broker.clone(); + tokio::spawn(async move { broker.handle_request(request(1, "pt-7")).await }) + }; + loop { + if broker.reserved_child_count().await == 1 { + break; + } + tokio::time::sleep(Duration::from_millis(5)).await; + } + broker.cancel_by_parent("parent-conn").await; + let _ = release.send(()); + + match driver.await.unwrap() { + DelegationOutcome::Err { code, .. } => assert_eq!(code, "canceled"), + other => panic!("expected canceled, got {other:?}"), + } + assert_eq!(mock.cancels.lock().await.as_slice(), &["c7"]); + assert_eq!(mock.disconnects.lock().await.as_slice(), &["c7"]); + assert_eq!(broker.inflight_count().await, 0); + } + + /// A cancel targeting a DIFFERENT parent must not flag this setup: it parks + /// normally and resolves via its own child terminal. + #[tokio::test] + async fn parent_cancel_for_other_parent_leaves_setup_intact() { + let mock = Arc::new(MockSpawner::new()); + mock.queue_spawn(Ok("c8".into())).await; + mock.queue_send(Ok(88)).await; + let release = mock.install_send_gate().await; + let broker = + DelegationBroker::new(mock.clone() as Arc, shallow_lookup()); + enable_delegation(&broker).await; + + let driver = { + let broker = broker.clone(); + tokio::spawn(async move { broker.handle_request(request(1, "pt-8")).await }) + }; + loop { + if broker.reserved_child_count().await == 1 { + break; + } + tokio::time::sleep(Duration::from_millis(5)).await; + } + // Wrong-parent cancel — a no-op for this setup. + broker.cancel_by_parent_turn("some-other-parent").await; + let _ = release.send(()); + + // It must park normally; resolve it via its child completion. + let parked = loop { + if let Some(id) = broker.peek_first_pending_call_id().await { + break id; + } + tokio::time::sleep(Duration::from_millis(5)).await; + }; + broker + .complete_call( + &parked, + DelegationOutcome::Ok(DelegationSuccess { + text: "fine".into(), + child_conversation_id: 88, + child_agent_type: AgentType::ClaudeCode, + turn_count: 1, + duration_ms: 5, + token_usage: None, + }), + ) + .await; + assert!(matches!(driver.await.unwrap(), DelegationOutcome::Ok(_))); + assert!( + mock.cancels.lock().await.is_empty(), + "a wrong-parent cancel must not tear this child down" + ); + assert_eq!(broker.inflight_count().await, 0); + } + + /// The in-flight record is deregistered on every exit path: the normal park + /// hand-off, and each early-return (disabled / spawn-fail / send-fail). + #[tokio::test] + async fn inflight_drained_on_normal_park() { + let mock = Arc::new(MockSpawner::new()); + mock.queue_spawn(Ok("c-ok".into())).await; + mock.queue_send(Ok(70)).await; + let broker = + DelegationBroker::new(mock.clone() as Arc, shallow_lookup()); + enable_delegation(&broker).await; + let driver = { + let broker = broker.clone(); + tokio::spawn(async move { broker.handle_request(request(1, "pt-ok")).await }) + }; + let call_id = loop { + if let Some(id) = broker.peek_first_pending_call_id().await { + break id; + } + tokio::time::sleep(Duration::from_millis(5)).await; + }; + // Parked → the in-flight record was handed off (deregistered) at park. + assert_eq!( + broker.inflight_count().await, + 0, + "park deregisters in-flight" + ); + broker + .complete_call( + &call_id, + DelegationOutcome::Ok(DelegationSuccess { + text: "ok".into(), + child_conversation_id: 70, + child_agent_type: AgentType::ClaudeCode, + turn_count: 1, + duration_ms: 5, + token_usage: None, + }), + ) + .await; + assert!(matches!(driver.await.unwrap(), DelegationOutcome::Ok(_))); + assert_eq!(broker.inflight_count().await, 0); + } + + #[tokio::test] + async fn inflight_drained_on_disabled() { + let broker = DelegationBroker::new( + Arc::new(MockSpawner::new()) as Arc, + shallow_lookup(), + ); + // `enabled` defaults to false → short-circuits at the disabled check. + let outcome = broker.handle_request(request(1, "pt-d")).await; + assert!(matches!(outcome, DelegationOutcome::Err { .. })); + assert_eq!(broker.inflight_count().await, 0); + } + + #[tokio::test] + async fn inflight_drained_on_spawn_failure() { + let mock = Arc::new(MockSpawner::new()); + mock.queue_spawn(Err(SpawnerError::Spawn("nope".into()))) + .await; + let broker = + DelegationBroker::new(mock.clone() as Arc, shallow_lookup()); + enable_delegation(&broker).await; + match broker.handle_request(request(1, "pt-sf")).await { + DelegationOutcome::Err { code, .. } => assert_eq!(code, "spawn_failed"), + other => panic!("expected spawn_failed, got {other:?}"), + } + assert_eq!(broker.inflight_count().await, 0); + assert!(mock.disconnects.lock().await.is_empty()); + } + + #[tokio::test] + async fn inflight_drained_on_send_failure() { + let mock = Arc::new(MockSpawner::new()); + mock.queue_spawn(Ok("c6".into())).await; + mock.queue_send(Err(SpawnerError::Send("boom".into()))) + .await; + let broker = + DelegationBroker::new(mock.clone() as Arc, shallow_lookup()); + enable_delegation(&broker).await; + match broker.handle_request(request(1, "pt-sendf")).await { + DelegationOutcome::Err { code, .. } => assert_eq!(code, "spawn_failed"), + other => panic!("expected spawn_failed, got {other:?}"), + } + assert_eq!(broker.inflight_count().await, 0); + assert_eq!(mock.disconnects.lock().await.as_slice(), &["c6"]); + assert!(mock.cancels.lock().await.is_empty()); + } + + /// A terminal failure for a child the broker never reserved (unknown id, or + /// one whose delegation already fully resolved) is a clean no-op — it must + /// not buffer, so the buffer can only ever hold genuine pre-registration + /// races. + #[tokio::test] + async fn cancel_for_unreserved_child_never_buffers() { + let broker = DelegationBroker::new( + Arc::new(MockSpawner::new()) as Arc, + shallow_lookup(), + ); + broker + .cancel_by_child_connection("never-reserved", Some("boom")) + .await; + assert_eq!(broker.early_cancel_count().await, 0); + assert_eq!(broker.pending_count().await, 0); + } + + #[tokio::test] + async fn meta_writer_records_failed_on_parent_cancel() { + let mock = Arc::new(MockSpawner::new()); + mock.queue_spawn(Ok("c-cancel".into())).await; + mock.queue_send(Ok(33)).await; + let writer = Arc::new(MockMetaWriter::new()); + let broker = broker_with_meta(mock.clone(), writer.clone()).await; + + let driver = { + let broker = broker.clone(); + tokio::spawn(async move { broker.handle_request(request(1, "pt-pcancel")).await }) + }; + while broker.pending_count().await == 0 { + tokio::time::sleep(Duration::from_millis(5)).await; + } + broker.cancel_by_parent("parent-conn").await; + let outcome = driver.await.unwrap(); + assert!(matches!(outcome, DelegationOutcome::Err { .. })); + + let calls = writer.snapshot().await; + // running + canceled + assert_eq!(calls.len(), 2); + let inner = calls[1] + .meta + .get("codeg.delegation") + .unwrap() + .as_object() + .unwrap(); + assert_eq!(inner.get("status").unwrap().as_str().unwrap(), "failed"); + assert_eq!( + inner.get("error_code").unwrap().as_str().unwrap(), + "canceled" + ); + } + + #[tokio::test] + async fn meta_writer_skipped_for_synthetic_parent_tool_use_id() { + let mock = Arc::new(MockSpawner::new()); + mock.queue_spawn(Ok("c-synth".into())).await; + mock.queue_send(Ok(8)).await; + let writer = Arc::new(MockMetaWriter::new()); + let broker = broker_with_meta(mock.clone(), writer.clone()).await; + + // Empty `parent_tool_use_id` triggers the broker's UUID fallback — + // `"delegation-"` — which the writer must skip because no + // matching ACP tool_call_id exists. + let driver = { + let broker = broker.clone(); + tokio::spawn(async move { broker.handle_request(request(1, "")).await }) + }; + let call_id = loop { + if let Some(id) = broker.peek_first_pending_call_id().await { + break id; + } + tokio::time::sleep(Duration::from_millis(5)).await; + }; + broker + .complete_call( + &call_id, + DelegationOutcome::Ok(DelegationSuccess { + text: "ok".into(), + child_conversation_id: 8, + child_agent_type: AgentType::Codex, + turn_count: 1, + duration_ms: 5, + token_usage: None, + }), + ) + .await; + driver.await.unwrap(); + + let calls = writer.snapshot().await; + assert!( + calls.is_empty(), + "writer should be skipped for synthetic parent_tool_use_id, got {:?}", + calls + ); + } + + // -- Event emitter lifecycle ------------------------------------------ + // + // Issue: `.docs/issues/2026-05-24-delegation-termination-cascade.md`. + // The broker must emit `AcpEvent::DelegationCompleted` once per drained + // pending entry, regardless of which terminal path drained it (happy + // `complete_call`, MCP `cancel_by_external_handle`, child-disconnect + // cleanup, or parent-cancel cascade). Without these emits the frontend's live + // delegation binding stays at "running" forever — see the issue doc + // for the full path matrix. + + use crate::acp::delegation::event_emitter::mock::MockEventEmitter; + use crate::acp::delegation::event_emitter::DelegationEventEmitter; + use crate::acp::types::DelegationResultSummary; + + async fn broker_with_emitter( + mock: Arc, + writer: Arc, + emitter: Arc, + ) -> DelegationBroker { + let broker = DelegationBroker::with_writers( + mock as Arc, + shallow_lookup(), + writer as Arc, + emitter as Arc, + ); + enable_delegation(&broker).await; + broker + } + + #[tokio::test] + async fn emitter_records_ok_on_complete_call_happy_path() { + let mock = Arc::new(MockSpawner::new()); + mock.queue_spawn(Ok("child-conn-1".into())).await; + mock.queue_send(Ok(42)).await; + let writer = Arc::new(MockMetaWriter::new()); + let emitter = Arc::new(MockEventEmitter::new()); + let broker = broker_with_emitter(mock.clone(), writer.clone(), emitter.clone()).await; + + let driver = { + let broker = broker.clone(); + tokio::spawn(async move { broker.handle_request(request(1, "pt-ok")).await }) + }; + let call_id = loop { + if let Some(id) = broker.peek_first_pending_call_id().await { + break id; + } + tokio::time::sleep(Duration::from_millis(5)).await; + }; + broker + .complete_call( + &call_id, + DelegationOutcome::Ok(DelegationSuccess { + text: "done".into(), + child_conversation_id: 42, + child_agent_type: AgentType::ClaudeCode, + turn_count: 1, + duration_ms: 73, + token_usage: None, + }), + ) + .await; + driver.await.unwrap(); + + let calls = emitter.snapshot().await; + assert_eq!(calls.len(), 1); + let call = &calls[0]; + assert_eq!(call.parent_tool_use_id, "pt-ok"); + assert_eq!(call.child_connection_id, "child-conn-1"); + assert_eq!(call.child_conversation_id, 42); + // The completed event carries the child agent_type (from the running + // task), so a frontend that missed `DelegationStarted` still binds the + // correct agent. `request()` delegates to ClaudeCode. + assert_eq!(call.agent_type, AgentType::ClaudeCode); + // duration_ms is now broker-measured (not the outcome's value); assert + // the Ok variant + the enriched text_preview instead. + assert!( + matches!( + &call.result, + DelegationResultSummary::Ok { text_preview, .. } + if text_preview.as_deref() == Some("done") + ), + "expected Ok with preview, got {:?}", + call.result + ); + } + + #[tokio::test] + async fn emitter_records_started_on_start_delegation_happy_path() { + let mock = Arc::new(MockSpawner::new()); + mock.queue_spawn(Ok("child-conn-start".into())).await; + mock.queue_send(Ok(55)).await; + let writer = Arc::new(MockMetaWriter::new()); + let emitter = Arc::new(MockEventEmitter::new()); + let broker = broker_with_emitter(mock.clone(), writer.clone(), emitter.clone()).await; + + let driver = { + let broker = broker.clone(); + tokio::spawn(async move { broker.handle_request(request(1, "pt-start")).await }) + }; + let call_id = loop { + if let Some(id) = broker.peek_first_pending_call_id().await { + break id; + } + tokio::time::sleep(Duration::from_millis(5)).await; + }; + + // `started` fires during setup, BEFORE the task parks — so it is already + // recorded by the time a pending entry is visible, and it must not be + // conflated with the (not-yet-emitted) terminal. + let started = emitter.started_snapshot().await; + assert_eq!(started.len(), 1, "exactly one DelegationStarted per task"); + let s = &started[0]; + assert_eq!(s.parent_connection_id, "parent-conn"); + assert_eq!(s.parent_tool_use_id, "pt-start"); + assert_eq!(s.child_connection_id, "child-conn-start"); + assert_eq!(s.child_conversation_id, 55); + assert_eq!(s.agent_type, AgentType::ClaudeCode); + assert_eq!( + emitter.count().await, + 0, + "no terminal emit before completion" + ); + + broker + .complete_call( + &call_id, + DelegationOutcome::Ok(DelegationSuccess { + text: "done".into(), + child_conversation_id: 55, + child_agent_type: AgentType::ClaudeCode, + turn_count: 1, + duration_ms: 10, + token_usage: None, + }), + ) + .await; + driver.await.unwrap(); + + // Completion adds exactly one terminal emit; started stays at 1. + assert_eq!(emitter.started_count().await, 1); + assert_eq!(emitter.count().await, 1); + } + + #[tokio::test] + async fn emitter_skips_started_for_synthetic_parent_tool_use_id() { + let mock = Arc::new(MockSpawner::new()); + mock.queue_spawn(Ok("c-synth-start".into())).await; + mock.queue_send(Ok(9)).await; + let writer = Arc::new(MockMetaWriter::new()); + let emitter = Arc::new(MockEventEmitter::new()); + let broker = broker_with_emitter(mock.clone(), writer.clone(), emitter.clone()).await; + + // Empty parent_tool_use_id → broker falls back to a synthetic + // `delegation-` id (no ACP tool_call to claim in a mock harness). + let driver = { + let broker = broker.clone(); + tokio::spawn(async move { broker.handle_request(request(1, "")).await }) + }; + let call_id = loop { + if let Some(id) = broker.peek_first_pending_call_id().await { + break id; + } + tokio::time::sleep(Duration::from_millis(5)).await; + }; + broker + .complete_call( + &call_id, + DelegationOutcome::Ok(DelegationSuccess { + text: "ok".into(), + child_conversation_id: 9, + child_agent_type: AgentType::Codex, + turn_count: 1, + duration_ms: 5, + token_usage: None, + }), + ) + .await; + driver.await.unwrap(); + + assert_eq!( + emitter.started_count().await, + 0, + "started emit must skip synthetic parent_tool_use_id (same rule as the meta writer / completed emit)" + ); + } + + #[tokio::test] + async fn emitter_records_err_on_complete_call_err_outcome() { + let mock = Arc::new(MockSpawner::new()); + mock.queue_spawn(Ok("child-conn-err".into())).await; + mock.queue_send(Ok(11)).await; + let writer = Arc::new(MockMetaWriter::new()); + let emitter = Arc::new(MockEventEmitter::new()); + let broker = broker_with_emitter(mock.clone(), writer.clone(), emitter.clone()).await; + + let driver = { + let broker = broker.clone(); + tokio::spawn(async move { broker.handle_request(request(1, "pt-err")).await }) + }; + let call_id = loop { + if let Some(id) = broker.peek_first_pending_call_id().await { + break id; + } + tokio::time::sleep(Duration::from_millis(5)).await; + }; + broker + .complete_call( + &call_id, + DelegationOutcome::from_err( + DelegationError::SubagentRuntimeError("agent died".into()), + Some(11), + ), + ) + .await; + driver.await.unwrap(); + + let calls = emitter.snapshot().await; + assert_eq!(calls.len(), 1); + match &calls[0].result { + DelegationResultSummary::Err { error_code } => { + assert_eq!(error_code, "subagent_error") + } + other => panic!("expected Err, got {other:?}"), + } + } + + #[tokio::test] + async fn emitter_records_canceled_on_cancel_by_external_handle() { + // MCP-driven cancel path: companion received notifications/cancelled + // and the listener forwarded it to broker.cancel_by_external_handle. + // The broker must drain the pending entry, cancel + disconnect the + // child, and emit DelegationCompleted with error_code = "canceled". + let mock = Arc::new(MockSpawner::new()); + mock.queue_spawn(Ok("child-conn-h".into())).await; + mock.queue_send(Ok(91)).await; + let writer = Arc::new(MockMetaWriter::new()); + let emitter = Arc::new(MockEventEmitter::new()); + let broker = broker_with_emitter(mock.clone(), writer.clone(), emitter.clone()).await; + + let driver = { + let broker = broker.clone(); + tokio::spawn(async move { + broker + .handle_request(request_with_handle(1, "pt-mcp-cancel", "h-1")) + .await + }) + }; + while broker.pending_count().await == 0 { + tokio::time::sleep(Duration::from_millis(5)).await; + } + broker + .cancel_by_external_handle("h-1", "user requested".into()) + .await; + let outcome = driver.await.unwrap(); + assert!(matches!( + outcome, + DelegationOutcome::Err { ref code, .. } if code == "canceled" + )); + + assert_eq!(mock.cancels.lock().await.as_slice(), &["child-conn-h"]); + let calls = emitter.snapshot().await; + assert_eq!(calls.len(), 1, "expected exactly one emit, got {calls:?}"); + let call = &calls[0]; + assert_eq!(call.parent_tool_use_id, "pt-mcp-cancel"); + assert_eq!(call.child_connection_id, "child-conn-h"); + assert_eq!(call.child_conversation_id, 91); + match &call.result { + DelegationResultSummary::Err { error_code } => { + assert_eq!(error_code, "canceled") + } + other => panic!("expected Err{{canceled}}, got {other:?}"), + } + } + + #[tokio::test] + async fn cancel_by_external_handle_no_match_buffers_pre_cancel() { + // Cancel arrives before handle_request reaches pending registration. + // The broker must buffer the handle in pre_canceled_handles so the + // in-flight call drains itself on its post-registration checkpoint. + let mock = Arc::new(MockSpawner::new()); + mock.queue_spawn(Ok("child-conn-pre".into())).await; + mock.queue_send(Ok(13)).await; + let writer = Arc::new(MockMetaWriter::new()); + let emitter = Arc::new(MockEventEmitter::new()); + let broker = broker_with_emitter(mock.clone(), writer.clone(), emitter.clone()).await; + + // Pre-cancel before spawning the driver — handle is unknown to the + // broker right now, but a buffered entry should make the next + // handle_request with the same handle bail out canceled. + broker + .cancel_by_external_handle("h-pre", "early cancel".into()) + .await; + // Pre-cancel set is single-shot: a second call with the same handle + // and no pending entry just buffers it again (idempotent in practice). + let outcome = broker + .handle_request(request_with_handle(1, "pt-pre", "h-pre")) + .await; + match outcome { + DelegationOutcome::Err { code, .. } => assert_eq!(code, "canceled"), + other => panic!("expected canceled, got {other:?}"), + } + // Since the cancel won pre-spawn, no child connection should have + // been opened. + assert!(mock.cancels.lock().await.is_empty()); + assert!(mock.disconnects.lock().await.is_empty()); + // The pre-cancel early-return must also drop the in-flight record + // (registered as handle_request's first statement, before this check). + assert_eq!(broker.inflight_count().await, 0); + } + + /// The real MCP-shaped path carries an `external_handle`. Registration now + /// happens as `handle_request`'s FIRST statement — before the pre-cancel + /// `.await` — so a parent cancel in the setup window reaches these requests + /// too, not just the synthetic-id path. Guards the regression Codex flagged + /// (registration ordered after the pre-cancel await left a miss window). + #[tokio::test] + async fn parent_cancel_covers_external_handle_setup_window() { + let mock = Arc::new(MockSpawner::new()); + mock.queue_spawn(Ok("c-eh".into())).await; + mock.queue_send(Ok(21)).await; + let release = mock.install_send_gate().await; + let broker = + DelegationBroker::new(mock.clone() as Arc, shallow_lookup()); + enable_delegation(&broker).await; + + let driver = { + let broker = broker.clone(); + tokio::spawn(async move { + broker + .handle_request(request_with_handle(1, "pt-eh", "h-eh")) + .await + }) + }; + loop { + if broker.reserved_child_count().await == 1 { + break; + } + tokio::time::sleep(Duration::from_millis(5)).await; + } + assert_eq!(broker.inflight_count().await, 1); + + broker.cancel_by_parent_turn("parent-conn").await; + let _ = release.send(()); + + match driver.await.unwrap() { + DelegationOutcome::Err { code, .. } => assert_eq!(code, "canceled"), + other => panic!("expected canceled, got {other:?}"), + } + assert_eq!(mock.cancels.lock().await.as_slice(), &["c-eh"]); + assert_eq!(mock.disconnects.lock().await.as_slice(), &["c-eh"]); + assert_eq!(broker.inflight_count().await, 0); + } + + #[tokio::test] + async fn emitter_records_canceled_on_cancel_by_child_connection() { + let mock = Arc::new(MockSpawner::new()); + mock.queue_spawn(Ok("c-dropped".into())).await; + mock.queue_send(Ok(55)).await; + let writer = Arc::new(MockMetaWriter::new()); + let emitter = Arc::new(MockEventEmitter::new()); + let broker = broker_with_emitter(mock.clone(), writer.clone(), emitter.clone()).await; + + let driver = { + let broker = broker.clone(); + tokio::spawn(async move { broker.handle_request(request(1, "pt-cbc")).await }) + }; + while broker.pending_count().await == 0 { + tokio::time::sleep(Duration::from_millis(5)).await; + } + broker.cancel_by_child_connection("c-dropped", None).await; + let outcome = driver.await.unwrap(); + match &outcome { + DelegationOutcome::Err { code, message, .. } => { + assert_eq!(code, "canceled"); + // No terminal_error supplied → falls back to default reason. + assert_eq!( + message, + "canceled: child session ended without TurnComplete" + ); + } + other => panic!("expected Err{{canceled}}, got {other:?}"), + } + + let calls = emitter.snapshot().await; + assert_eq!(calls.len(), 1); + match &calls[0].result { + DelegationResultSummary::Err { error_code } => { + assert_eq!(error_code, "canceled") + } + other => panic!("expected Err{{canceled}}, got {other:?}"), + } + } + + #[tokio::test] + async fn cancel_by_child_connection_threads_terminal_error_into_reason() { + // The lifecycle worker forwards the child's last AcpEvent::Error + // detail through `cancel_by_child_connection`. The broker stitches it + // into the `Canceled { reason }` message so the parent's + // `delegate_to_agent` tool-call result surfaces the real failure + // cause (e.g. Gemini OAuth expired) instead of the opaque default. + let mock = Arc::new(MockSpawner::new()); + mock.queue_spawn(Ok("c-auth".into())).await; + mock.queue_send(Ok(77)).await; + let writer = Arc::new(MockMetaWriter::new()); + let emitter = Arc::new(MockEventEmitter::new()); + let broker = broker_with_emitter(mock.clone(), writer.clone(), emitter.clone()).await; + + let driver = { + let broker = broker.clone(); + tokio::spawn(async move { broker.handle_request(request(1, "pt-auth")).await }) + }; + while broker.pending_count().await == 0 { + tokio::time::sleep(Duration::from_millis(5)).await; + } + broker + .cancel_by_child_connection("c-auth", Some("[auth_required] Authentication required")) + .await; + let outcome = driver.await.unwrap(); + match &outcome { + DelegationOutcome::Err { code, message, .. } => { + assert_eq!(code, "canceled"); + assert_eq!( + message, + "canceled: child session ended without TurnComplete: \ + [auth_required] Authentication required" + ); + } + other => panic!("expected Err{{canceled}}, got {other:?}"), + } + } + + #[tokio::test] + async fn cancel_by_child_connection_ignores_empty_terminal_error() { + // Whitespace-only or empty detail strings shouldn't produce a + // dangling "...:" suffix on the reason — fall back to the default. + let mock = Arc::new(MockSpawner::new()); + mock.queue_spawn(Ok("c-empty".into())).await; + mock.queue_send(Ok(78)).await; + let broker = + DelegationBroker::new(mock.clone() as Arc, shallow_lookup()); + enable_delegation(&broker).await; + + let driver = { + let broker = broker.clone(); + tokio::spawn(async move { broker.handle_request(request(1, "pt-empty")).await }) + }; + while broker.pending_count().await == 0 { + tokio::time::sleep(Duration::from_millis(5)).await; + } + broker + .cancel_by_child_connection("c-empty", Some(" ")) + .await; + let outcome = driver.await.unwrap(); + match &outcome { + DelegationOutcome::Err { message, .. } => { + assert_eq!( + message, + "canceled: child session ended without TurnComplete" + ); + } + other => panic!("expected Err, got {other:?}"), + } + } + + #[tokio::test] + async fn emitter_records_one_event_per_drained_entry_on_cancel_by_parent() { + let mock = Arc::new(MockSpawner::new()); + for i in 0..3 { + mock.queue_spawn(Ok(format!("c{i}"))).await; + mock.queue_send(Ok(100 + i)).await; + } + let writer = Arc::new(MockMetaWriter::new()); + let emitter = Arc::new(MockEventEmitter::new()); + let broker = broker_with_emitter(mock.clone(), writer.clone(), emitter.clone()).await; + + let mut handles = Vec::new(); + for i in 0..3 { + let broker = broker.clone(); + handles.push(tokio::spawn(async move { + broker.handle_request(request(1, &format!("pt-{i}"))).await + })); + } + while broker.pending_count().await < 3 { + tokio::time::sleep(Duration::from_millis(5)).await; + } + broker.cancel_by_parent("parent-conn").await; + for h in handles { + let _ = h.await.unwrap(); + } + + let calls = emitter.snapshot().await; + assert_eq!(calls.len(), 3, "expected 3 emits, got {calls:?}"); + let mut parent_tool_use_ids: Vec = + calls.iter().map(|c| c.parent_tool_use_id.clone()).collect(); + parent_tool_use_ids.sort(); + assert_eq!( + parent_tool_use_ids, + vec!["pt-0".to_string(), "pt-1".to_string(), "pt-2".to_string()] + ); + for call in &calls { + match &call.result { + DelegationResultSummary::Err { error_code } => { + assert_eq!(error_code, "canceled") + } + other => panic!("expected Err{{canceled}}, got {other:?}"), + } + } + } + + #[tokio::test] + async fn emitter_does_not_double_emit_on_repeat_cancel_by_parent() { + let mock = Arc::new(MockSpawner::new()); + mock.queue_spawn(Ok("c-once".into())).await; + mock.queue_send(Ok(42)).await; + let writer = Arc::new(MockMetaWriter::new()); + let emitter = Arc::new(MockEventEmitter::new()); + let broker = broker_with_emitter(mock.clone(), writer.clone(), emitter.clone()).await; + + let driver = { + let broker = broker.clone(); + tokio::spawn(async move { broker.handle_request(request(1, "pt-idem")).await }) + }; + while broker.pending_count().await == 0 { + tokio::time::sleep(Duration::from_millis(5)).await; + } + // First call drains the entry + emits one. + broker.cancel_by_parent("parent-conn").await; + // Second call finds the pending map empty — no extra emit. + broker.cancel_by_parent("parent-conn").await; + // Cleanup-guard-style triple call also stays bounded. + broker.cancel_by_parent("parent-conn").await; + let _ = driver.await.unwrap(); + + assert_eq!(emitter.count().await, 1); + } + + #[tokio::test] + async fn emitter_skipped_for_synthetic_parent_tool_use_id() { + let mock = Arc::new(MockSpawner::new()); + mock.queue_spawn(Ok("c-synth".into())).await; + mock.queue_send(Ok(8)).await; + let writer = Arc::new(MockMetaWriter::new()); + let emitter = Arc::new(MockEventEmitter::new()); + let broker = broker_with_emitter(mock.clone(), writer.clone(), emitter.clone()).await; + + let driver = { + let broker = broker.clone(); + tokio::spawn(async move { broker.handle_request(request(1, "")).await }) + }; + let call_id = loop { + if let Some(id) = broker.peek_first_pending_call_id().await { + break id; + } + tokio::time::sleep(Duration::from_millis(5)).await; + }; + broker + .complete_call( + &call_id, + DelegationOutcome::Ok(DelegationSuccess { + text: "ok".into(), + child_conversation_id: 8, + child_agent_type: AgentType::Codex, + turn_count: 1, + duration_ms: 5, + token_usage: None, + }), + ) + .await; + driver.await.unwrap(); + + let calls = emitter.snapshot().await; + assert!( + calls.is_empty(), + "emitter must skip synthetic parent_tool_use_id (same rule as meta writer); got {calls:?}" + ); + } + + #[tokio::test] + async fn emitter_records_after_meta_write_on_complete_call() { + // Frontend's snapshot-recovery path reads `meta["codeg.delegation"]` + // first and the live event second; if the emit lands before the + // meta write, a snapshot taken between them would see "running" + // meta paired with a "completed" event. Enforce meta-before-emit + // by checking the MockMetaWriter has at least one call before the + // emitter records. + let mock = Arc::new(MockSpawner::new()); + mock.queue_spawn(Ok("c-order".into())).await; + mock.queue_send(Ok(7)).await; + let writer = Arc::new(MockMetaWriter::new()); + let emitter = Arc::new(MockEventEmitter::new()); + let broker = broker_with_emitter(mock.clone(), writer.clone(), emitter.clone()).await; + + let driver = { + let broker = broker.clone(); + tokio::spawn(async move { broker.handle_request(request(1, "pt-order")).await }) + }; + let call_id = loop { + if let Some(id) = broker.peek_first_pending_call_id().await { + break id; + } + tokio::time::sleep(Duration::from_millis(5)).await; + }; + broker + .complete_call( + &call_id, + DelegationOutcome::Ok(DelegationSuccess { + text: "ok".into(), + child_conversation_id: 7, + child_agent_type: AgentType::ClaudeCode, + turn_count: 1, + duration_ms: 5, + token_usage: None, + }), + ) + .await; + driver.await.unwrap(); + + let meta_calls = writer.snapshot().await; + let event_calls = emitter.snapshot().await; + // running (from handle_request) + completed (from complete_call) = + // 2 meta writes. The single event must be the "completed" one, + // and it must land AFTER the running meta — guaranteed structurally + // by complete_call's order (write_meta_if_real then emit). + assert_eq!(meta_calls.len(), 2); + assert_eq!(event_calls.len(), 1); + let inner_second = meta_calls[1] + .meta + .get("codeg.delegation") + .unwrap() + .as_object() + .unwrap(); + assert_eq!( + inner_second.get("status").unwrap().as_str().unwrap(), + "completed" + ); + } + + // -- Production-path fanout coverage ---------------------------------- + // + // Every other emitter test in this module uses `MockEventEmitter`. The + // production wiring goes through `ConnectionManagerEventEmitter`, which + // resolves `(state, emitter)` against the live `ConnectionManager` and + // hands the event to `emit_with_state` so it fans out to (1) the parent + // connection's `ConnectionEventStream` (the WS attach path) and (2) the + // `InternalEventBus` (the lifecycle/pet/chat-channel subscriber path). + // These tests exercise that real fanout end-to-end so a regression in + // `get_state_and_emitter` lookup, `emit_with_state` routing, or the + // `EventEmitter::WebOnly { bus, .. }` wiring is caught here even when + // every mock-backed test stays green. + + #[tokio::test] + async fn real_emitter_fans_out_delegation_completed_to_parent_stream_and_bus() { + use crate::acp::delegation::event_emitter::ConnectionManagerEventEmitter; + use crate::acp::manager::ConnectionManager; + use crate::acp::types::AcpEvent; + use crate::web::event_bridge::{EventEmitter, WebEventBroadcaster}; + + // Real ConnectionManager + fake parent wired to a WebOnly emitter so + // the InternalEventBus gets typed envelopes and we can subscribe to + // verify the lifecycle-path delivery alongside the per-connection + // stream delivery. + let manager = ConnectionManager::new(); + let broadcaster = Arc::new(WebEventBroadcaster::new()); + let parent_emitter = EventEmitter::test_web_only(broadcaster); + let bus = parent_emitter + .acp_event_bus() + .expect("WebOnly emitter must expose an InternalEventBus"); + manager + .insert_test_connection("parent-conn", AgentType::ClaudeCode, None, parent_emitter) + .await; + + // Subscribe BEFORE triggering events — broadcast channels drop + // sends that happen with no receivers registered. + let mut bus_rx = bus.subscribe(); + let (parent_state, _) = manager + .get_state_and_emitter("parent-conn") + .await + .expect("parent just inserted"); + let mut stream_rx = parent_state.read().await.event_stream().subscribe(); + + // Build the broker with the PRODUCTION emitter; meta writer can stay + // noop because this test is asserting the event-fanout invariant. + let mock_spawner = Arc::new(MockSpawner::new()); + mock_spawner.queue_spawn(Ok("child-conn-real".into())).await; + mock_spawner.queue_send(Ok(77)).await; + let real_emitter = Arc::new(ConnectionManagerEventEmitter { + manager: Arc::new(manager.clone_ref()), + }); + let broker = DelegationBroker::with_writers( + mock_spawner.clone() as Arc, + shallow_lookup(), + Arc::new(crate::acp::delegation::meta_writer::NoopMetaWriter) + as Arc, + real_emitter as Arc, + ); + enable_delegation(&broker).await; + + // Park a pending entry then trigger cancel_by_parent to drive the + // production emit path. `request()` hard-codes parent_connection_id + // = "parent-conn" which matches the insert above. + let driver = { + let broker = broker.clone(); + tokio::spawn(async move { broker.handle_request(request(1, "pt-fanout")).await }) + }; + while broker.pending_count().await == 0 { + tokio::time::sleep(Duration::from_millis(5)).await; + } + broker.cancel_by_parent("parent-conn").await; + let _ = driver.await.unwrap(); + + // Per-connection stream (WS attach delivery path) must receive the + // envelope tagged with the right connection + payload shape. + // The parent stream now also carries the setup-time DelegationStarted; + // skip past it to the terminal DelegationCompleted. + let envelope = loop { + let env = tokio::time::timeout(Duration::from_millis(500), stream_rx.recv()) + .await + .expect("per-connection stream should receive DelegationCompleted within 500ms") + .expect("envelope recv must not error"); + if matches!(env.payload, AcpEvent::DelegationStarted { .. }) { + continue; + } + break env; + }; + assert_eq!(envelope.connection_id, "parent-conn"); + match &envelope.payload { + AcpEvent::DelegationCompleted { + parent_tool_use_id, + child_connection_id, + child_conversation_id, + result, + .. + } => { + assert_eq!(parent_tool_use_id, "pt-fanout"); + assert_eq!(child_connection_id, "child-conn-real"); + assert_eq!(*child_conversation_id, 77); + match result { + DelegationResultSummary::Err { error_code } => { + assert_eq!(error_code, "canceled"); + } + other => panic!("expected Err{{canceled}}, got {other:?}"), + } + } + other => panic!("expected DelegationCompleted, got {other:?}"), + } + + // InternalEventBus (lifecycle/pet/chat-channel subscriber path) must + // also receive the same envelope — proves the WebOnly emitter's bus + // arm in `emit_with_state` is reached. + let bus_envelope = loop { + let env = tokio::time::timeout(Duration::from_millis(500), bus_rx.recv()) + .await + .expect("InternalEventBus should receive DelegationCompleted within 500ms") + .expect("bus recv must not error"); + if matches!(env.payload, AcpEvent::DelegationStarted { .. }) { + continue; + } + break env; + }; + assert_eq!(bus_envelope.connection_id, "parent-conn"); + assert!(matches!( + bus_envelope.payload, + AcpEvent::DelegationCompleted { .. } + )); + } + + #[tokio::test] + async fn real_emitter_fans_out_delegation_started_to_parent_stream_and_bus() { + use crate::acp::delegation::event_emitter::ConnectionManagerEventEmitter; + use crate::acp::manager::ConnectionManager; + use crate::acp::types::AcpEvent; + use crate::web::event_bridge::{EventEmitter, WebEventBroadcaster}; + + // Web/server delivery shape: a real ConnectionManager + a fake parent on + // a WebOnly emitter. `DelegationStarted` must land on the PARENT's + // per-connection stream (the WS attach path the frontend subscribes to + // in web/server mode) AND the InternalEventBus — mirroring the + // completed-path invariant. This is the regression lock for the + // web-mode live-delegation gap: before moving the emit to the parent + // stream, started rode the (un-attached) child stream and was lost here. + let manager = ConnectionManager::new(); + let broadcaster = Arc::new(WebEventBroadcaster::new()); + let parent_emitter = EventEmitter::test_web_only(broadcaster); + let bus = parent_emitter + .acp_event_bus() + .expect("WebOnly emitter must expose an InternalEventBus"); + manager + .insert_test_connection("parent-conn", AgentType::ClaudeCode, None, parent_emitter) + .await; + + // Subscribe BEFORE triggering events — broadcast channels drop sends + // that happen with no receivers registered. + let mut bus_rx = bus.subscribe(); + let (parent_state, _) = manager + .get_state_and_emitter("parent-conn") + .await + .expect("parent just inserted"); + let mut stream_rx = parent_state.read().await.event_stream().subscribe(); + + let mock_spawner = Arc::new(MockSpawner::new()); + mock_spawner + .queue_spawn(Ok("child-conn-started".into())) + .await; + mock_spawner.queue_send(Ok(88)).await; + let real_emitter = Arc::new(ConnectionManagerEventEmitter { + manager: Arc::new(manager.clone_ref()), + }); + let broker = DelegationBroker::with_writers( + mock_spawner.clone() as Arc, + shallow_lookup(), + Arc::new(crate::acp::delegation::meta_writer::NoopMetaWriter) + as Arc, + real_emitter as Arc, + ); + enable_delegation(&broker).await; + + // `started` fires during setup, before park — drive the request, wait + // for it to park, then assert the envelope already arrived. + let driver = { + let broker = broker.clone(); + tokio::spawn(async move { broker.handle_request(request(1, "pt-started")).await }) + }; + while broker.pending_count().await == 0 { + tokio::time::sleep(Duration::from_millis(5)).await; + } + + let envelope = tokio::time::timeout(Duration::from_millis(500), stream_rx.recv()) + .await + .expect("per-connection stream should receive DelegationStarted within 500ms") + .expect("envelope recv must not error"); + assert_eq!(envelope.connection_id, "parent-conn"); + match &envelope.payload { + AcpEvent::DelegationStarted { + parent_connection_id, + parent_tool_use_id, + child_connection_id, + child_conversation_id, + agent_type, + task_preview, + task_id, + } => { + assert_eq!(parent_connection_id, "parent-conn"); + assert_eq!(parent_tool_use_id, "pt-started"); + assert_eq!(child_connection_id, "child-conn-started"); + assert_eq!(*child_conversation_id, 88); + assert_eq!(*agent_type, AgentType::ClaudeCode); + // The event labels the card even when the parent tool call's + // raw_input never carried the arguments (identity-less hosts). + assert_eq!(task_preview, "do x"); + assert!(!task_id.is_empty(), "broker-minted task id must ride the event"); + } + other => panic!("expected DelegationStarted, got {other:?}"), + } + + let bus_envelope = tokio::time::timeout(Duration::from_millis(500), bus_rx.recv()) + .await + .expect("InternalEventBus should receive DelegationStarted within 500ms") + .expect("bus recv must not error"); + assert_eq!(bus_envelope.connection_id, "parent-conn"); + assert!(matches!( + bus_envelope.payload, + AcpEvent::DelegationStarted { .. } + )); + + // Drain the parked driver so the test doesn't leak the spawned task. + broker.cancel_by_parent("parent-conn").await; + let _ = driver.await.unwrap(); + } + + #[tokio::test] + async fn real_emitter_is_silent_no_op_when_parent_already_detached() { + // Parent torn down mid-delegation: `get_state_and_emitter` returns + // None, the emit silently drops, BUT the broker still drains its + // pending table and surfaces the outcome to the awaiting caller. + // This is the "parent disappeared before terminal" path that the + // mock-backed tests can't observe. + use crate::acp::delegation::event_emitter::ConnectionManagerEventEmitter; + use crate::acp::manager::ConnectionManager; + + let manager = ConnectionManager::new(); + // Intentionally no insert_test_connection — parent is absent. + let real_emitter = Arc::new(ConnectionManagerEventEmitter { + manager: Arc::new(manager.clone_ref()), + }); + let mock_spawner = Arc::new(MockSpawner::new()); + mock_spawner.queue_spawn(Ok("c-orphan".into())).await; + mock_spawner.queue_send(Ok(1)).await; + let broker = DelegationBroker::with_writers( + mock_spawner.clone() as Arc, + shallow_lookup(), + Arc::new(crate::acp::delegation::meta_writer::NoopMetaWriter) + as Arc, + real_emitter as Arc, + ); + enable_delegation(&broker).await; + + let driver = { + let broker = broker.clone(); + tokio::spawn(async move { broker.handle_request(request(1, "pt-orphan")).await }) + }; + while broker.pending_count().await == 0 { + tokio::time::sleep(Duration::from_millis(5)).await; + } + broker.cancel_by_parent("parent-conn").await; + let outcome = driver.await.unwrap(); + + assert!(matches!( + outcome, + DelegationOutcome::Err { ref code, .. } if code == "canceled" + )); + assert_eq!( + broker.pending_count().await, + 0, + "broker must drain pending even when no parent exists to receive the emit" + ); + } + + // -- Async-cutover review regressions ----------------------------------- + + /// A pre-cancel that bails `start_delegation` before the claim path must + /// still drain the keyed ACP tool_call, so a later same-key delegation + /// can't claim the canceled call's id and mis-bind to the wrong card. + #[tokio::test] + async fn pre_cancel_drains_keyed_tool_call_to_avoid_misbinding() { + let broker = DelegationBroker::new( + Arc::new(MockSpawner::new()) as Arc, + shallow_lookup(), + ); + enable_delegation(&broker).await; + let key = DelegationMatchKey { + agent_type: AgentType::ClaudeCode, + task: "do x".into(), + working_dir: None, + }; + // The lifecycle registered the keyed tool_call for this delegation. + broker + .register_pending_tool_call_with_key("parent-conn", "tc-1".into(), Some(key.clone())) + .await; + // notifications/cancelled lands before the round-trip → buffered (no + // running task yet). + broker.cancel_by_external_handle("h-1", "user".into()).await; + // The MCP round-trip arrives (empty parent_tool_use_id, same key) and + // bails at the first pre-cancel check. + let report = broker + .start_delegation(request_with_handle(1, "", "h-1")) + .await; + assert_eq!(report.status, TaskStatus::Canceled); + // The keyed entry must have been drained — not claimable afterward. + assert_eq!( + broker.take_matching_tool_call("parent-conn", &key).await, + None + ); + } + + /// The running ack must carry the literal task_id in its message, so a + /// client that only surfaces MCP `content` text (not `structuredContent`) + /// can still call get_delegation_status / cancel_delegation. + #[test] + fn running_ack_message_embeds_task_id() { + let report = running_ack("task-xyz".into(), 42, AgentType::Codex); + assert_eq!(report.task_id.as_deref(), Some("task-xyz")); + assert!( + report.message.as_deref().unwrap().contains("task-xyz"), + "ack message must embed the literal task_id, got {:?}", + report.message + ); + } + + /// Previews and cached text must stay within their advertised BYTE caps + /// (including the appended ellipsis), and truncate on UTF-8 boundaries. + #[test] + fn previews_and_cached_text_respect_byte_caps() { + let preview = build_text_preview(&"x".repeat(STATUS_PREVIEW_CAP * 2)).unwrap(); + assert!( + preview.len() <= STATUS_PREVIEW_CAP, + "preview {} > cap {STATUS_PREVIEW_CAP}", + preview.len() + ); + let cached = cap_completed_text(&"y".repeat(COMPLETED_TEXT_CAP * 2)); + assert!(cached.len() <= COMPLETED_TEXT_CAP); + // Multibyte safety: 3-byte chars must not be split, and the cap holds. + let multibyte = build_text_preview(&"€".repeat(STATUS_PREVIEW_CAP)).unwrap(); + assert!(multibyte.len() <= STATUS_PREVIEW_CAP); + assert!(std::str::from_utf8(multibyte.as_bytes()).is_ok()); + } + + // -- completed-cache byte valve ---------------------------------------- + + fn completed_with_text(parent: &str, text_len: usize) -> CompletedTask { + CompletedTask { + parent_connection_id: parent.to_string(), + child_conversation_id: 1, + agent_type: AgentType::ClaudeCode, + status: TaskStatus::Completed, + text: Some("x".repeat(text_len)), + error_code: None, + message: None, + duration_ms: 0, + } + } + + #[test] + fn completed_cache_valve_evicts_oldest_over_byte_budget() { + let mut inner = PendingInner { + completed_cap_bytes: 1000, + ..Default::default() + }; + // Three 400-byte results = 1200 bytes > 1000 cap. Oldest must evict. + inner.insert_completed("a", completed_with_text("p1", 400)); + inner.insert_completed("b", completed_with_text("p1", 400)); + inner.insert_completed("c", completed_with_text("p1", 400)); + assert!(!inner.completed.contains_key("a"), "oldest must be evicted"); + assert!(inner.completed.contains_key("b")); + assert!(inner.completed.contains_key("c"), "newest must be retained"); + // Counter + order reflect only the two retained entries. + assert_eq!(inner.completed_bytes.get("p1").copied(), Some(800)); + assert_eq!(inner.completed_order.get("p1").map(|o| o.len()), Some(2)); + // Survivors keep their FULL text — the valve drops whole entries, it + // never truncates a survivor. + assert_eq!( + inner + .completed + .get("c") + .unwrap() + .text + .as_deref() + .map(str::len), + Some(400) + ); + } + + #[test] + fn completed_cache_valve_keeps_newest_even_if_alone_over_budget() { + // A single result larger than the whole budget is still retained — the + // valve never evicts the entry just inserted (the LLM's immediate + // get_delegation_status must hit). Per-result text is independently + // bounded by COMPLETED_TEXT_CAP. + let mut inner = PendingInner { + completed_cap_bytes: 100, + ..Default::default() + }; + inner.insert_completed("solo", completed_with_text("p1", 500)); + assert!(inner.completed.contains_key("solo")); + assert_eq!(inner.completed_bytes.get("p1").copied(), Some(500)); + } + + #[test] + fn completed_cache_unlimited_when_cap_zero() { + let mut inner = PendingInner::default(); // completed_cap_bytes == 0 + for i in 0..50 { + inner.insert_completed(&format!("t{i}"), completed_with_text("p1", 10_000)); + } + assert_eq!(inner.completed.len(), 50, "cap 0 disables eviction"); + assert_eq!(inner.completed_bytes.get("p1").copied(), Some(500_000)); + } + + #[test] + fn completed_cache_valve_is_per_parent() { + let mut inner = PendingInner { + completed_cap_bytes: 1000, + ..Default::default() + }; + // p1 overflows; p2 stays under its own independent budget. + inner.insert_completed("a1", completed_with_text("p1", 600)); + inner.insert_completed("a2", completed_with_text("p1", 600)); // evicts a1 + inner.insert_completed("b1", completed_with_text("p2", 600)); + assert!(!inner.completed.contains_key("a1")); + assert!(inner.completed.contains_key("a2")); + assert!( + inner.completed.contains_key("b1"), + "p2 must be untouched by p1 overflow" + ); + assert_eq!(inner.completed_bytes.get("p1").copied(), Some(600)); + assert_eq!(inner.completed_bytes.get("p2").copied(), Some(600)); + } + + #[test] + fn drop_completed_for_parent_clears_byte_counter() { + let mut inner = PendingInner::default(); // unlimited; teardown still clears + inner.insert_completed("a", completed_with_text("p1", 100)); + inner.insert_completed("b", completed_with_text("p2", 100)); + inner.drop_completed_for_parent("p1"); + assert!(!inner.completed.contains_key("a")); + assert!(inner.completed.contains_key("b")); + assert_eq!( + inner.completed_bytes.get("p1"), + None, + "byte counter must be cleared on teardown" + ); + assert_eq!(inner.completed_bytes.get("p2").copied(), Some(100)); + } + + #[tokio::test] + async fn lowering_cap_prunes_existing_completed_results() { + let broker = DelegationBroker::new( + Arc::new(MockSpawner::new()) as Arc, + shallow_lookup(), + ); + // Start unlimited and retain several results for one parent. + broker + .set_config(DelegationConfig { + completed_cache_cap_bytes: 0, + ..DelegationConfig::default() + }) + .await; + { + let mut inner = broker.pending.inner.lock().await; + for i in 0..5 { + inner.insert_completed(&format!("t{i}"), completed_with_text("p1", 400)); + } + assert_eq!(inner.completed.len(), 5); + assert_eq!(inner.completed_bytes.get("p1").copied(), Some(2000)); + } + // Lower the cap to 1000 bytes — existing results must be pruned NOW, + // not only on the next completion (which may never arrive). + broker + .set_config(DelegationConfig { + completed_cache_cap_bytes: 1000, + ..DelegationConfig::default() + }) + .await; + let inner = broker.pending.inner.lock().await; + assert!( + inner.completed_bytes.get("p1").copied().unwrap_or(0) <= 1000, + "retained bytes must fit the lowered cap" + ); + assert!( + inner.completed.contains_key("t4"), + "newest result must survive pruning" + ); + assert!( + !inner.completed.contains_key("t0"), + "oldest result must be pruned" + ); + } +} diff --git a/src-tauri/src/acp/delegation/companion.rs b/src-tauri/src/acp/delegation/companion.rs index 3097a7d30..08c269ea2 100644 --- a/src-tauri/src/acp/delegation/companion.rs +++ b/src-tauri/src/acp/delegation/companion.rs @@ -152,6 +152,9 @@ pub struct CompanionFeatures { pub automations: bool, /// `create_work_task` — queue a card on the work-task board from chat. pub taskboard: bool, + /// When true (with delegation), rewrite `delegate_to_agent` so only an + /// `@` mention starts a child. Unknown token on older parents: ignored. + pub mention_only: bool, } impl CompanionFeatures { @@ -171,6 +174,7 @@ impl CompanionFeatures { tasks: false, automations: false, taskboard: false, + mention_only: false, }; }; let mut f = Self { @@ -181,6 +185,7 @@ impl CompanionFeatures { tasks: false, automations: false, taskboard: false, + mention_only: false, }; for tok in s.split(',').map(str::trim).filter(|t| !t.is_empty()) { match tok { @@ -191,6 +196,7 @@ impl CompanionFeatures { "tasks" => f.tasks = true, "automations" => f.automations = true, "taskboard" => f.taskboard = true, + "mention_only" => f.mention_only = true, _ => {} } } @@ -407,6 +413,9 @@ pub async fn dispatch_line( }; remove_disabled_agents_from_delegate_enum(&mut tools, &ctx.disabled_agents); append_custom_agents_to_delegate_enum(&mut tools, &ctx.custom_agents); + if ctx.features.mention_only { + apply_mention_only_delegate_copy(&mut tools); + } LineAction::Respond(ok(id, json!({ "tools": tools }))) } "tools/call" => build_tools_call_spawn(ctx.clone(), inflight, id, req.params).await, @@ -473,6 +482,28 @@ fn append_custom_agents_to_delegate_enum(tools: &mut Value, custom_agents: &[Str } } +const MENTION_ONLY_DELEGATE_DESCRIPTION: &str = "Hand off a self-contained sub-task to a separate local AI agent that runs in its own session. ASYNCHRONOUS: returns a task_id right away and the sub-agent keeps working in the background — this call never blocks. So you can fan out several delegations at once and keep working, then collect the results with get_delegation_status by passing the task_ids array (one id to poll a single task, or many at once to poll the whole fan-out in one call) — or stop one early with cancel_delegation(task_id). The sub-agent CANNOT see this conversation, your open files, or earlier turns — it starts cold, so `task` must carry everything it needs. Best for independent, parallelizable work you can describe up front; not for steps that need your ongoing back-and-forth. RECOGNIZING AN EXPLICIT DELEGATION REQUEST: the user can name a sub-agent directly in their message — it appears as `@AgentName` or as a Markdown link `[@AgentName](codeg://agent/)`. Such a mention IS an explicit instruction to delegate the associated work to that agent, even when the user never names this tool. If the message names several agents, make one call per agent, each carrying that agent's slice of the work."; + +const MENTION_ONLY_AGENT_TYPE_DESCRIPTION: &str = "Which local agent runs the sub-task. Pick the one best suited to the work — or, when the user's message names an agent via `@AgentName` / `codeg://agent/`, use that exact `` slug (e.g. `codeg://agent/claude_code` means `claude_code`)."; + +/// Settings toggle off: restore the pre-self-initiate copy so models wait +/// for an `@` mention. The enum of launchable agents is unchanged. +fn apply_mention_only_delegate_copy(tools: &mut Value) { + let Some(arr) = tools.as_array_mut() else { + return; + }; + let Some(tool) = arr + .iter_mut() + .find(|t| t.get("name").and_then(|v| v.as_str()) == Some("delegate_to_agent")) + else { + return; + }; + tool["description"] = Value::String(MENTION_ONLY_DELEGATE_DESCRIPTION.to_string()); + if let Some(desc) = tool.pointer_mut("/inputSchema/properties/agent_type/description") { + *desc = Value::String(MENTION_ONLY_AGENT_TYPE_DESCRIPTION.to_string()); + } +} + /// Build the spawned-call descriptor for a `tools/call` (or, when the /// arguments are obviously bogus, a synchronous error response). Registers /// the inflight entry and returns a future the binary should drive. @@ -1539,6 +1570,7 @@ mod tests { tasks: false, automations: false, taskboard: false, + mention_only: false, }) } @@ -1637,6 +1669,26 @@ mod tests { assert!(agent_desc.contains("even when the user did not @-mention")); } + #[tokio::test] + async fn mention_only_feature_restores_at_mention_copy() { + let mut features = CompanionFeatures::parse(Some("delegation,mention_only")); + assert!(features.delegation); + assert!(features.mention_only); + let ctx = ctx_with(features); + let line = r#"{"jsonrpc":"2.0","id":2,"method":"tools/list"}"#; + let resp = unwrap_respond(dispatch_line(&ctx, Arc::new(InflightCalls::new()), line).await); + let delegate = resp.result.unwrap()["tools"] + .as_array() + .unwrap() + .iter() + .find(|t| t["name"] == "delegate_to_agent") + .unwrap() + .clone(); + let desc = delegate["description"].as_str().unwrap(); + assert!(desc.contains("Such a mention IS an explicit instruction")); + assert!(!desc.contains("YOU MAY CALL THIS TOOL WITHOUT A USER @ MENTION")); + } + #[tokio::test] async fn custom_agents_extend_the_delegate_enum_after_the_builtins() { let mut ctx = ctx(); @@ -2134,6 +2186,7 @@ mod tests { tasks: false, automations: false, taskboard: false, + mention_only: false, }; const BOTH: CompanionFeatures = CompanionFeatures { delegation: true, @@ -2143,6 +2196,7 @@ mod tests { tasks: false, automations: false, taskboard: false, + mention_only: false, }; const ASK_ONLY: CompanionFeatures = CompanionFeatures { delegation: false, @@ -2152,6 +2206,7 @@ mod tests { tasks: false, automations: false, taskboard: false, + mention_only: false, }; const SESSIONS_ONLY: CompanionFeatures = CompanionFeatures { delegation: false, @@ -2161,6 +2216,7 @@ mod tests { tasks: false, automations: false, taskboard: false, + mention_only: false, }; fn list_tool_names(action: LineAction) -> Vec { @@ -2451,6 +2507,7 @@ mod tests { tasks: false, automations: true, taskboard: false, + mention_only: false, }; const TASKBOARD_ONLY: CompanionFeatures = CompanionFeatures { delegation: false, @@ -2460,6 +2517,7 @@ mod tests { tasks: false, automations: false, taskboard: true, + mention_only: false, }; /// The two authoring groups gate independently: enabling one must not diff --git a/src-tauri/src/commands/delegation.rs b/src-tauri/src/commands/delegation.rs index 9c2e406e3..70d952f28 100644 --- a/src-tauri/src/commands/delegation.rs +++ b/src-tauri/src/commands/delegation.rs @@ -4,6 +4,7 @@ //! * `delegation.enabled` — feature kill switch (default false) //! * `delegation.depth_limit` — max chain depth a child is allowed to sit at //! * `delegation.agent_defaults` — per-agent spawn overrides (JSON blob) +//! * `delegation.allow_self_initiate` — agents may spawn without `@` //! * `delegation.completed_cache_max_mb` — per-parent byte budget (in MB) for //! the broker's in-memory cache of completed result text (`0` = unlimited) //! @@ -38,6 +39,13 @@ pub const KEY_DELEGATION_DEPTH: &str = "delegation.depth_limit"; pub const KEY_DELEGATION_AGENT_DEFAULTS: &str = "delegation.agent_defaults"; /// Per-parent completed-result cache budget, in MB. `0` = unlimited. pub const KEY_DELEGATION_COMPLETED_CACHE_MB: &str = "delegation.completed_cache_max_mb"; +/// When true (default), `delegate_to_agent` invites self-initiated spawn. +/// When false, the tool description says only an `@` mention starts a child. +pub const KEY_DELEGATION_ALLOW_SELF_INITIATE: &str = "delegation.allow_self_initiate"; + +fn default_allow_self_initiate() -> bool { + true +} pub const DEPTH_MIN: u32 = 1; pub const DEPTH_MAX: u32 = 8; @@ -71,6 +79,11 @@ pub struct DelegationSettings { /// unlimited), so an older client can't silently disable the valve. #[serde(default = "default_completed_cache_max_mb")] pub completed_cache_max_mb: u32, + /// When true, agents may call `delegate_to_agent` without an `@` + /// mention. An `@` mention is still always honored. Missing in a + /// payload → on, matching the post-#478 default. + #[serde(default = "default_allow_self_initiate")] + pub allow_self_initiate: bool, } impl Default for DelegationSettings { @@ -80,6 +93,7 @@ impl Default for DelegationSettings { depth_limit: 1, agent_defaults: BTreeMap::new(), completed_cache_max_mb: DEFAULT_COMPLETED_CACHE_MB, + allow_self_initiate: true, } } } @@ -97,6 +111,7 @@ impl DelegationSettings { // No upper clamp: the cache budget is a user memory choice, not a // safety rail. `0` stays `0` (unlimited). completed_cache_max_mb: self.completed_cache_max_mb, + allow_self_initiate: self.allow_self_initiate, } } @@ -135,6 +150,13 @@ pub async fn load_delegation_settings(conn: &DatabaseConnection) -> DelegationSe settings.completed_cache_max_mb = v; } } + if let Ok(Some(raw)) = + app_metadata_service::get_value(conn, KEY_DELEGATION_ALLOW_SELF_INITIATE).await + { + if let Ok(v) = raw.parse::() { + settings.allow_self_initiate = v; + } + } if let Ok(Some(raw)) = app_metadata_service::get_value(conn, KEY_DELEGATION_AGENT_DEFAULTS).await { @@ -154,6 +176,7 @@ pub async fn load_delegation_settings(conn: &DatabaseConnection) -> DelegationSe /// after any external write to `app_metadata`. pub async fn apply_persisted_config(conn: &DatabaseConnection, broker: &DelegationBroker) { let settings = load_delegation_settings(conn).await; + broker.set_allow_self_initiate(settings.allow_self_initiate); broker.set_config(settings.into_broker_config()).await; } @@ -188,12 +211,20 @@ pub async fn set_delegation_settings_core( let agent_defaults_json = serde_json::to_string(&clamped.agent_defaults).map_err(|e| { AppCommandError::configuration_invalid(format!("serialize agent_defaults: {e}")) })?; + app_metadata_service::upsert_value( + conn, + KEY_DELEGATION_ALLOW_SELF_INITIATE, + &clamped.allow_self_initiate.to_string(), + ) + .await + .map_err(AppCommandError::from)?; app_metadata_service::upsert_value(conn, KEY_DELEGATION_AGENT_DEFAULTS, &agent_defaults_json) .await .map_err(AppCommandError::from)?; broker .set_config(clamped.clone().into_broker_config()) .await; + broker.set_allow_self_initiate(clamped.allow_self_initiate); Ok(clamped) } diff --git a/src/components/settings/delegation-settings.test.tsx b/src/components/settings/delegation-settings.test.tsx index 9d08e4e1a..394a8e8b2 100644 --- a/src/components/settings/delegation-settings.test.tsx +++ b/src/components/settings/delegation-settings.test.tsx @@ -83,6 +83,7 @@ describe("DelegationSettingsSection", () => { await screen.findByLabelText("Maximum delegation depth") ).toBeInTheDocument() expect(screen.getByLabelText("Enable delegation")).toBeInTheDocument() + expect(screen.getByLabelText("Allow spawn without @")).toBeInTheDocument() expect( screen.getByLabelText("Completed-result cache (MB)") ).toBeInTheDocument() @@ -151,6 +152,7 @@ describe("DelegationSettingsSection", () => { await waitFor(() => { expect(mockSetDelegationSettings).toHaveBeenCalledWith({ enabled: true, + allow_self_initiate: true, depth_limit: 1, completed_cache_max_mb: 0, agent_defaults: {}, @@ -175,6 +177,7 @@ describe("DelegationSettingsSection", () => { await waitFor(() => { expect(mockSetDelegationSettings).toHaveBeenCalledWith({ enabled: true, + allow_self_initiate: true, depth_limit: 1, completed_cache_max_mb: 512, agent_defaults: {}, @@ -197,6 +200,7 @@ describe("DelegationSettingsSection", () => { await waitFor(() => { expect(mockSetDelegationSettings).toHaveBeenCalledWith({ enabled: true, + allow_self_initiate: true, depth_limit: 5, completed_cache_max_mb: 512, agent_defaults: {}, diff --git a/src/components/settings/delegation-settings.tsx b/src/components/settings/delegation-settings.tsx index 58e26dd4e..04ac40c00 100644 --- a/src/components/settings/delegation-settings.tsx +++ b/src/components/settings/delegation-settings.tsx @@ -66,6 +66,7 @@ export function DelegationSettingsSection() { const [loading, setLoading] = useState(true) const [saving, setSaving] = useState(false) const [enabled, setEnabled] = useState(false) + const [allowSelfInitiate, setAllowSelfInitiate] = useState(true) const [depth, setDepth] = useState(1) const [cacheMb, setCacheMb] = useState(DEFAULT_CACHE_MB) const [agentDefaults, setAgentDefaults] = useState< @@ -83,6 +84,7 @@ export function DelegationSettingsSection() { .then((s) => { if (cancelled) return setEnabled(s.enabled) + setAllowSelfInitiate(s.allow_self_initiate !== false) setDepth(s.depth_limit) setCacheMb(s.completed_cache_max_mb) setAgentDefaults(s.agent_defaults ?? {}) @@ -136,6 +138,7 @@ export function DelegationSettingsSection() { const save = useCallback(async () => { const payload: DelegationSettings = { enabled, + allow_self_initiate: allowSelfInitiate, depth_limit: clamp(depth, DEPTH_MIN, DEPTH_MAX), completed_cache_max_mb: clampCacheMb(cacheMb), agent_defaults: agentDefaults, @@ -146,6 +149,7 @@ export function DelegationSettingsSection() { // Mirror any server-side clamps / filter passes back into the UI so the // inputs reflect what was actually persisted. setEnabled(applied.enabled) + setAllowSelfInitiate(applied.allow_self_initiate !== false) setDepth(applied.depth_limit) setCacheMb(applied.completed_cache_max_mb) setAgentDefaults(applied.agent_defaults ?? {}) @@ -157,7 +161,7 @@ export function DelegationSettingsSection() { } finally { setSaving(false) } - }, [enabled, depth, cacheMb, agentDefaults, t]) + }, [enabled, allowSelfInitiate, depth, cacheMb, agentDefaults, t]) return (

)} + + } + /> |", - "tooLong": "الاسم طويل جدًا", - "reserved": "هذا الاسم محجوز في ويندوز", - "duplicate": "هذا الاسم مستخدم بالفعل" - }, - "rejection": { - "not_found": "تعذر العثور على هذا المجلد", - "not_a_directory": "هذا المسار ليس مجلدًا", - "same_as_root": "هذا هو مجلد مساحة العمل نفسه", - "ancestor_of_root": "هذا المجلد يحتوي على مساحة العمل", - "inside_root": "موجود بالفعل داخل مساحة العمل", - "already_linked": "مرتبط بالفعل", - "name_unavailable": "لم يتبق اسم متاح لهذا المجلد", - "alreadyLinkedAs": "مرتبط بالفعل باسم {name}" - } - }, - "folderNameDropdown": { - "fallbackFolderName": "مجلد", - "openFolder": "فتح مجلد", - "cloneRepository": "استنساخ المستودع", - "projectBoot": "مُنشئ المشروع", - "opened": "مفتوح", - "recentOpen": "المفتوح مؤخرًا" - }, - "fileWorkspacePanel": { - "addSelectionToChat": "إضافة التحديد إلى المحادثة", - "addToChat": "إضافة إلى المحادثة", - "addSelectionToChatDone": "تمت إضافة {label} إلى المحادثة", - "addFileToChat": "إضافة الملف إلى المحادثة", - "toggleWordWrap": "تبديل التفاف النص", - "addFileToChatDone": "تمت إضافة {label} إلى المحادثة", - "viewDiff": "عرض Diff", - "openFile": "فتح الملف", - "fileCount": "{count, plural, one {# ملف} other {# ملفات}}", - "openFileOrDiff": "افتح ملفًا أو diff من اللوحة اليمنى", - "disk": "القرص", - "head": "HEAD", - "unsaved": "غير محفوظ", - "workingTree": "شجرة العمل", - "loading": "جارٍ التحميل...", - "compareWithBranch": "{path} · مقارنة مع {branch}", - "hunkCount": "{count, plural, one {# مقطع} other {# مقاطع}}", - "prev": "السابق", - "next": "التالي", - "jumpToLine": "الانتقال إلى السطر {line}", - "noParsedDiffSections": "لا توجد أقسام diff محللة", - "loadingEditor": "جارٍ تحميل المحرر...", - "imageZoomIn": "تكبير", - "imageZoomOut": "تصغير", - "imageZoomReset": "إعادة تعيين التكبير", - "htmlPreviewTitle": "معاينة HTML", - "htmlPreviewTrust": "تفعيل البرامج النصية", - "htmlPreviewTrustHint": "تشغيل البرامج النصية لهذا الملف والسماح بالوصول إلى الشبكة. فعّلها فقط للملفات الموثوقة.", - "officePreviewTitle": "معاينة مستند Office", - "officeFullRender": "عرض كامل", - "officeFullRenderHint": "يعرض حركات Morph والأبعاد الثلاثية والمعادلات (يشغّل سكربتات الشريحة نفسها)", - "officeNotInstalled": "OfficeCLI غير مثبّت", - "officeNotInstalledHint": "ثبّت OfficeCLI من الإعدادات → أدوات Office لمعاينة ملفات Word و Excel و PowerPoint.", - "officeOpenSettings": "فتح الإعدادات", - "officeWatchFailed": "تعذّر بدء المعاينة المباشرة", - "officeWatchRetry": "إعادة المحاولة", - "officeServerInstallHint": "يجب تثبيت OfficeCLI على مضيف الخادم. شغّل هذا الأمر هناك ثم أعد المحاولة:", - "officeRemoteDesktopUnsupported": "المعاينة المباشرة غير متاحة في نافذة سطح المكتب البعيد. افتح مساحة العمل هذه في واجهة الويب الخاصة بالخادم لمعاينة ملفات Office." - }, - "branchDropdown": { - "toasts": { - "commitCodeCompleted": "اكتمل التزام الكود", - "pushCodeCompleted": "اكتمل دفع الكود", - "committedFiles": "{count, plural, one {# ملف تم الالتزام به} other {# ملفات تم الالتزام بها}}", - "taskCompleted": "اكتمل {label}", - "taskFailed": "فشل {label}", - "mergeNoNewCommits": "{branchName} لا يحتوي على التزامات جديدة", - "mergedCommits": "{count, plural, one {# التزام تم دمجه} other {# التزامات تم دمجها}}", - "allFilesUpToDate": "كل الملفات محدثة", - "updatedFiles": "{count, plural, one {# ملف تم تحديثه} other {# ملفات تم تحديثها}}", - "openCommitWindowFailed": "فشل فتح نافذة الالتزام", - "openPushWindowFailed": "فشل فتح نافذة الدفع", - "upstreamSet": "تم تعيين فرع upstream", - "upstreamSetAndPushed": "تم تعيين فرع upstream ودفع {count, plural, one {# التزام} other {# التزامات}}", - "noCommitsToPush": "لا توجد التزامات للدفع", - "pushedCommits": "تم دفع {count, plural, one {# التزام} other {# التزامات}}", - "switchedToFolder": "تم التبديل إلى {name}", - "switchFailed": "فشل تبديل الفرع", - "openStashWindowFailed": "فشل فتح نافذة الـ stash" - }, - "tasks": { - "newBranch": "إنشاء الفرع {name}", - "newWorktree": "إنشاء worktree {name}", - "checkoutTo": "Checkout إلى {branchName}", - "mergeBranch": "دمج {branchName}", - "rebaseTo": "Rebase إلى {branchName}", - "deleteRemoteBranch": "حذف الفرع البعيد {branchName}", - "initGitRepo": "تهيئة مستودع Git", - "pullCode": "سحب الكود", - "fetchInfo": "جلب المعلومات", - "pushCode": "دفع الكود", - "stashChanges": "تخزين التغييرات في stash", - "stashPop": "استرجاع stash", - "deleteBranch": "حذف الفرع {branchName}", - "removeWorktree": "حذف worktree الخاص بـ {branchName}", - "removeWorktreeAndBranch": "حذف worktree والفرع {branchName}", - "updateBranch": "تحديث الفرع {branchName}" - }, - "confirm": { - "mergeTitle": "دمج الفرع", - "rebaseTitle": "Rebase للفرع", - "mergeDescription": "دمج {branchName} في الفرع الحالي {currentBranch}؟", - "rebaseDescription": "إجراء rebase للفرع الحالي {currentBranch} على {branchName}؟", - "deleteRemoteTitle": "حذف الفرع البعيد", - "deleteRemoteDescription": "هل تريد حذف الفرع البعيد {branchName}؟ سيؤدي ذلك إلى إزالته من المستودع البعيد ولا يمكن التراجع عن هذا الإجراء.", - "deleteTitle": "حذف الفرع", - "deleteDescription": "حذف الفرع {branchName}؟ لا يمكن التراجع عن هذا الإجراء.", - "forceDeleteTitle": "حذف الفرع بالقوة", - "forceDeleteDescription": "الفرع {branchName} لم يتم دمجه بالكامل. هل أنت متأكد من أنك تريد حذفه بالقوة؟ لا يمكن التراجع عن هذا الإجراء.", - "deleteWorktreeTitle": "حذف worktree", - "deleteWorktreeDescription": "حذف مجلد worktree الذي تم سحب {branchName} فيه؟ سيتم الاحتفاظ بالفرع وإيداعاته.", - "forceDeleteWorktreeTitle": "فرض حذف worktree", - "forceDeleteWorktreeDescription": "يحتوي worktree الخاص بـ {branchName} على ملفات غير مودعة أو غير متتبعة. هل تريد حذفه على أي حال؟ لا يمكن استرجاع تلك التغييرات.", - "deleteWorktreeAndBranchTitle": "حذف worktree والفرع", - "deleteWorktreeAndBranchDescription": "حذف worktree الخاص بـ {branchName} والفرع نفسه ومجلده في مساحة العمل؟ ستنتقل جلساته إلى مجلد المستودع. لا يمكن التراجع عن هذا الإجراء.", - "forceDeleteWorktreeAndBranchTitle": "فرض حذف worktree والفرع", - "forceDeleteWorktreeAndBranchDescription": "يحتوي worktree الخاص بـ {branchName} على ملفات غير مودعة، أو أن الفرع غير مدمج بالكامل. هل تريد حذفهما على أي حال؟ لا يمكن التراجع عن هذا الإجراء." - }, - "current": "الحالي", - "switchToBranch": "التبديل إلى هذا الفرع", - "mergeBranchIntoCurrent": "دمج {branchName} في {currentBranch}", - "rebaseCurrentToBranch": "Rebase لـ {currentBranch} على {branchName}", - "noBranch": "بدون فرع", - "detachedHead": "HEAD منفصل عند {sha}", - "initGitRepo": "تهيئة مستودع Git", - "pullCode": "سحب الكود", - "fetchRemoteBranches": "جلب الفروع البعيدة", - "openCommitWindow": "التزام الكود...", - "pushCode": "دفع...", - "pushBranch": "دفع", - "newBranch": "فرع جديد...", - "newWorktree": "Worktree جديد...", - "stashChanges": "...تخبئة التغييرات", - "stashPop": "استرجاع stash...", - "manageRemotes": "إدارة المستودعات البعيدة...", - "localBranches": "الفروع المحلية ({count, plural, one {#} other {#}})", - "noLocalBranches": "لا توجد فروع محلية", - "remoteBranches": "الفروع البعيدة ({count, plural, one {#} other {#}})", - "noRemoteBranches": "لا توجد فروع بعيدة", - "dialogs": { - "newBranchTitle": "فرع جديد", - "newBranchDescription": "إنشاء فرع جديد من الفرع الحالي {branch}", - "branchNamePlaceholder": "اسم الفرع", - "newWorktreeTitle": "Worktree جديد", - "newWorktreeDescription": "إنشاء worktree جديد من الفرع الحالي {branch}", - "branchNameLabel": "اسم الفرع", - "worktreePathLabel": "مسار worktree", - "worktreePathPlaceholder": "مسار worktree", - "manageRemotesTitle": "إدارة المستودعات البعيدة", - "manageRemotesEmpty": "لم يتم تكوين أي مستودعات بعيدة", - "remoteNamePlaceholder": "اسم المستودع البعيد", - "remoteUrlPlaceholder": "عنوان URL للمستودع البعيد", - "addRemote": "إضافة", - "savingRemotes": "جارٍ الحفظ..." - }, - "conflict": { - "title": "تعارضات الدمج", - "description": "الملفات التالية بها تعارضات تحتاج إلى حل:", - "abort": "إلغاء الدمج", - "openMergeTool": "فتح أداة الدمج", - "completeMerge": "إتمام الدمج", - "abortSuccess": "تم إلغاء الدمج بنجاح", - "completeSuccess": "تم إتمام الدمج بنجاح" - }, - "stashDialog": { - "title": "تخبئة التغييرات", - "description": "حفظ التغييرات الحالية في المخبأ", - "messageLabel": "رسالة", - "messagePlaceholder": "رسالة التخبئة (اختياري)", - "keepIndex": "الاحتفاظ بالفهرس (التغييرات المرحلة تبقى مرحلة)", - "cancel": "إلغاء", - "stash": "تخبئة", - "success": "تم تخبئة التغييرات", - "error": "فشل في تخبئة التغييرات" - }, - "unstashDialog": { - "title": "تطبيق المخبأ", - "noStashes": "لا توجد تخبئات", - "selectFile": "اختر ملفاً لعرض الفرق", - "viewDiff": "عرض الفرق", - "original": "الأصلي", - "modified": "المعدل", - "apply": "تطبيق", - "drop": "حذف", - "applySuccess": "تم تطبيق التخبئة", - "dropSuccess": "تم حذف التخبئة", - "confirmApply": "تطبيق التخبئة {ref} على دليل العمل؟", - "cancel": "إلغاء" - }, - "deleteBranch": "حذف الفرع", - "deleteWorktree": "حذف worktree", - "deleteWorktreeAndBranch": "حذف worktree والفرع", - "searchPlaceholder": "البحث في الفروع والإجراءات", - "searchAriaLabel": "البحث في الفروع والإجراءات", - "branchListLabel": "الفروع والإجراءات", - "noMatches": "لا توجد نتائج" - }, - "commitDialog": { - "toasts": { - "commitCompleted": "اكتمل التزام الكود", - "pushFailed": "فشل الدفع", - "committedFiles": "{count, plural, one {# ملف تم الالتزام به} other {# ملفات تم الالتزام بها}}", - "addedToVcs": "تمت الإضافة إلى VCS", - "addToVcsFailed": "فشلت الإضافة إلى VCS", - "fileDeleted": "تم حذف الملف", - "deleteFailed": "فشل الحذف", - "fileRolledBack": "تم التراجع عن الملف", - "rollbackFailed": "فشل التراجع", - "dirRolledBack": "تم استعادة المجلد", - "dirDeleted": "تم حذف المجلد" - }, - "confirm": { - "deleteTitle": "تأكيد الحذف", - "deleteDescription": "حذف الملف \"{file}\"؟ لا يمكن التراجع عن هذا الإجراء.", - "rollbackTitle": "تأكيد التراجع", - "rollbackDescription": "التراجع عن الملف \"{file}\" إلى HEAD؟ ستفقد التغييرات غير المحفوظة.", - "rollbackDirDescription": "هل تريد استعادة المجلد \"{dir}\" إلى HEAD؟ ستفقد التغييرات غير المحفوظة.", - "deleteDirDescription": "هل تريد حذف المجلد \"{dir}\"؟ لا يمكن التراجع عن هذا الإجراء." - }, - "actions": { - "select": "تحديد", - "unselect": "إلغاء التحديد", - "rollback": "تراجع", - "addToVcs": "إضافة إلى VCS" - }, - "aria": { - "selectFile": "{action}: {path}", - "unselectAllFiles": "إلغاء تحديد كل الملفات", - "selectAllFiles": "تحديد كل الملفات", - "unselectTracked": "إلغاء تحديد التغييرات المتعقبة", - "selectTracked": "تحديد التغييرات المتعقبة", - "unselectUntracked": "إلغاء تحديد الملفات غير المتعقبة", - "selectUntracked": "تحديد الملفات غير المتعقبة" - }, - "loading": "جارٍ التحميل...", - "selectionCount": "{selected} / {total} ملفات", - "emptyFiles": "لا توجد ملفات متغيرة", - "trackedChanges": "التغييرات المتعقبة ({count})", - "untrackedFiles": "الملفات غير المتعقبة ({count})", - "commitMessage": "رسالة الالتزام", - "commitMessagePlaceholder": "أدخل رسالة الالتزام...", - "commitButton": "التزام ({count})", - "commitAndPushButton": "إيداع ودفع ({count})", - "head": "HEAD", - "workingTree": "شجرة العمل", - "clickFileToDiff": "انقر اسم الملف لعرض الفرق", - "loadingDiff": "جارٍ تحميل diff..." - }, - "pushWindow": { - "title": "دفع الكود", - "noUnpushedCommits": "لا توجد التزامات غير مدفوعة", - "noRemoteConfigured": "لم يتم تكوين مستودع Git بعيد\nأضف واحدًا في «إدارة المستودعات البعيدة»", - "newBranchNoPushedCommits": "فرع جديد — ادفع لإنشاء فرع تتبع عن بُعد", - "unpushed": "غير مدفوع", - "selectFileToViewDiff": "اختر ملفًا لعرض الفرق", - "before": "قبل", - "after": "بعد", - "push": "دفع", - "toasts": { - "pushSuccess": "تم الدفع بنجاح", - "pushFailed": "فشل الدفع", - "upstreamSet": "تم تعيين الفرع البعيد", - "upstreamSetAndPushed": "تم تعيين الفرع البعيد ودفع {count} التزام", - "noCommitsToPush": "لا توجد التزامات للدفع", - "pushedCommits": "تم دفع {count} التزام" - } - }, - "gitLogTab": { - "filesTitle": "الملفات", - "expandAllFiles": "توسيع كل الملفات", - "collapseAllFiles": "طي كل الملفات", - "workspace": "مساحة العمل", - "retry": "إعادة المحاولة", - "noCommitsFound": "لم يتم العثور على التزامات", - "notAGitRepoTitle": "ليس مستودع Git", - "notAGitRepoHint": "قم بتهيئة Git من قائمة الفروع أعلاه، أو افتح مستودعًا موجودًا.", - "hash": "بصمة الالتزام", - "copyHash": "نسخ الـ hash", - "copyMessage": "نسخ الرسالة", - "showMore": "عرض المزيد", - "showLess": "طي", - "author": "المؤلف", - "noFileChangeDetails": "لا توجد تفاصيل تغييرات ملفات متاحة.", - "loadingFiles": "جارٍ تحميل الملفات...", - "branchesTitle": "الفروع", - "loadingBranches": "جارٍ تحميل الفروع...", - "noContainingBranches": "لم يتم العثور على فروع تحتوي هذا الالتزام.", - "newBranch": "فرع جديد...", - "resetToHere": "إعادة الضبط إلى هنا", - "resetDisabledReasonNotCurrentBranchView": "متاح فقط عند عرض الفرع الحالي", - "copyFullCommitHashAria": "نسخ hash الكامل للالتزام {hash}", - "pushStatus": { - "pushed": "تم الدفع إلى البعيد", - "notPushed": "لم يتم الدفع إلى البعيد", - "unknown": "حالة الدفع غير معروفة (لم يتم إعداد upstream)" - }, - "time": { - "monthsAgo": "{count, plural, one {منذ # شهر} other {منذ # أشهر}}", - "daysAgo": "{count, plural, one {منذ # يوم} other {منذ # أيام}}", - "hoursAgo": "{count, plural, one {منذ # ساعة} other {منذ # ساعات}}", - "minsAgo": "{count, plural, one {منذ # دقيقة} other {منذ # دقائق}}", - "justNow": "الآن" - }, - "toasts": { - "createdAndSwitchedNewBranch": "تم إنشاء فرع جديد والتبديل إليه", - "newBranchFromCommit": "{name} (من {shortHash})", - "createBranchFailed": "فشل إنشاء الفرع", - "openPushWindowFailed": "فشل فتح نافذة الدفع", - "resetSuccess": "تمت إعادة الضبط بنجاح", - "resetSuccessDescription": "تمت إعادة ضبط {branch} إلى {shortHash} باستخدام {mode}", - "resetFailed": "فشلت إعادة الضبط" - }, - "authorFilter": { - "label": "المؤلف", - "searchPlaceholder": "بحث عن مؤلف", - "noAuthors": "لم يتم العثور على مؤلفين", - "you": "أنت", - "filterByAuthorAria": "تصفية الإيداعات حسب المؤلف", - "filterByQuery": "تصفية حسب \"{query}\"", - "clearAuthorFilterAria": "مسح تصفية المؤلف", - "recent": "الأخيرة", - "matchingAuthors": "المؤلفون المطابقون", - "removeFromRecent": "إزالة {name} من الأخيرة" - }, - "branchSelector": { - "label": "الفرع", - "head": "HEAD", - "headHint": "يتبع الفرع الحالي", - "headHintWithBranch": "يتبع الفرع الحالي ({branch})", - "searchBranch": "بحث عن فرع...", - "noBranches": "لا توجد فروع", - "selectBranchPlaceholder": "اختر فرعًا...", - "localBranches": "الفروع المحلية", - "current": "الحالي", - "remoteBranches": "الفروع البعيدة", - "refreshCommitHistory": "تحديث سجل الالتزامات", - "clearBranchFilterAria": "مسح تصفية الفرع" - }, - "dialogs": { - "newBranchTitle": "فرع جديد", - "newBranchDescription": "إنشاء فرع جديد مع الالتزام {shortHash} كأحدث التزام.", - "branchNamePlaceholder": "اسم الفرع", - "reset": { - "title": "إعادة ضبط الفرع الحالي إلى هذا الالتزام", - "branchLabel": "الفرع", - "targetLabel": "الالتزام الهدف", - "messageLabel": "الرسالة", - "modeLabel": "وضع إعادة الضبط", - "confirmButton": "إعادة الضبط", - "modes": { - "soft": { - "label": "--soft", - "description": "ينقل HEAD ومؤشر الفرع الحالي إلى الالتزام الهدف.\nيبقي Index و Working Tree بدون تغيير.\nتظل تغييرات الالتزامات التي تمت إزالتها في حالة staged." - }, - "mixed": { - "label": "--mixed (الافتراضي)", - "description": "ينقل HEAD إلى الالتزام الهدف.\nيعيد ضبط Index إلى الالتزام الهدف مع الإبقاء على تغييرات Working Tree.\nتتحول التغييرات من staged إلى unstaged." - }, - "hard": { - "label": "--hard", - "description": "ينقل HEAD ويعيد ضبط كل من Index و Working Tree إلى الالتزام الهدف.\nسيتم حذف التغييرات المحلية المتتبعة بعد الالتزام الهدف.\nهذه عملية تدميرية." - }, - "keep": { - "label": "--keep", - "description": "ينقل HEAD إلى الالتزام الهدف مع محاولة الاحتفاظ بالتغييرات المحلية.\nيتم الاحتفاظ فقط بالتغييرات غير المتعارضة.\nعند وجود تعارض، يتم إيقاف العملية لحماية عملك." - } - } - } - }, - "moreActions": "إجراءات Git إضافية" - }, - "gitChangesTab": { - "workspace": "مساحة العمل", - "noChanges": "لا توجد تغييرات محلية", - "notAGitRepoTitle": "ليس مستودع Git", - "notAGitRepoHint": "قم بتهيئة Git من قائمة الفروع أعلاه، أو افتح مستودعًا موجودًا.", - "trackedChanges": "التغييرات المتعقبة ({count})", - "untrackedFiles": "الملفات غير المتعقبة ({count})", - "expandTracked": "توسيع التغييرات المتعقبة", - "collapseTracked": "طي التغييرات المتعقبة", - "expandUntracked": "توسيع الملفات غير المتعقبة", - "collapseUntracked": "طي الملفات غير المتعقبة", - "showRemainingItems": "عرض {count} عنصر إضافي", - "actions": { - "commitCode": "التزام الكود", - "rollback": "تراجع", - "addToVcs": "إضافة إلى VCS", - "delete": "حذف", - "moreActions": "إجراءات Git إضافية", - "addAllToVcs": "إضافة الكل إلى VCS", - "rollbackAll": "تراجع عن الكل", - "refresh": "تحديث" - }, - "toasts": { - "noAddableFilesInDir": "لا توجد ملفات متغيرة في هذا الدليل يمكن إضافتها إلى VCS", - "noRollbackFilesInDir": "لا توجد ملفات متغيرة في هذا الدليل يمكن التراجع عنها", - "addedToVcs": "تمت إضافة {name} إلى VCS", - "addToVcsFailed": "فشلت الإضافة إلى VCS", - "openCommitWindowFailed": "فشل فتح نافذة الالتزام", - "rolledBack": "تم التراجع عن {name}", - "rollbackFailed": "فشل التراجع", - "addedFilesToVcs": "تمت إضافة {count, plural, one {# ملف} other {# ملفات}} إلى VCS", - "rolledBackFiles": "تم التراجع عن {count, plural, one {# ملف} other {# ملفات}}", - "deleted": "تم حذف {name}", - "deleteFailed": "فشل الحذف", - "deletedFiles": "تم حذف {count} ملفات", - "noDeletableFilesInDir": "لا توجد ملفات معدّلة في هذا الدليل يمكن حذفها", - "commitFailed": "فشل الالتزام" - }, - "directoryDialog": { - "descriptionAdd": "اختر ملفات داخل الدليل {path} لإضافتها إلى VCS.", - "descriptionRollback": "اختر ملفات داخل الدليل {path} للتراجع عنها.", - "descriptionDelete": "اختر ملفات داخل الدليل {path} لحذفها. لا يمكن التراجع عن هذا الإجراء.", - "descriptionFallback": "اختر ملفات للمتابعة.", - "selectionCount": "تم تحديد {selected} / {total} ملف", - "selectAll": "تحديد الكل", - "unselectAll": "إلغاء تحديد الكل", - "loadingCandidates": "جارٍ تحميل تغييرات الدليل...", - "noOperableFiles": "لا توجد ملفات قابلة للتشغيل" - }, - "rollbackConfirm": { - "title": "تأكيد التراجع", - "descriptionWithTarget": "التراجع عن التغييرات المحلية لـ {kind} \"{name}\"؟", - "descriptionFallback": "التراجع عن التغييرات المحلية؟", - "kindDirectory": "الدليل", - "kindFile": "الملف" - }, - "deleteConfirm": { - "title": "تأكيد الحذف", - "descriptionWithTarget": "حذف {kind} \"{name}\"؟ لا يمكن التراجع عن هذا الإجراء.", - "descriptionFallback": "لا يمكن التراجع عن هذا الإجراء.", - "kindDirectory": "الدليل", - "kindFile": "الملف" - }, - "quickCommit": { - "placeholder": "رسالة الالتزام (اضغط Enter للالتزام)" - } - }, - "tabContext": { - "loadingConversation": "جارٍ التحميل...", - "untitledConversation": "محادثة بدون عنوان", - "newConversation": "محادثة جديدة" - }, - "fileTreeTab": { - "workspace": "مساحة العمل", - "retry": "إعادة المحاولة", - "git": "Git", - "openInFileManager": "فتح في مدير الملفات", - "openInFinder": "فتح في Finder", - "openInExplorer": "فتح في Explorer", - "attachToCurrentSession": "إضافة إلى الجلسة", - "compareWithBranch": "المقارنة مع الفرع...", - "reloadFromDisk": "إعادة التحميل من القرص", - "new": "جديد", - "newFile": "ملف", - "newDirectory": "مجلد", - "openIn": "فتح في", - "openInTerminal": "فتح في الطرفية", - "linkedFolder": "مجلد مرتبط", - "copyPath": "نسخ المسار", - "upload": "رفع ملفات/مجلد", - "download": "تنزيل ملف", - "downloadAsZip": "تنزيل كملف ZIP", - "actions": { - "select": "تحديد", - "unselect": "إلغاء التحديد", - "commitCode": "تنفيذ الالتزام بالكود", - "rollback": "التراجع", - "addToVcs": "إضافة إلى VCS" - }, - "aria": { - "selectPath": "{action}: {path}" - }, - "toasts": { - "openDirectoryFailed": "فشل فتح المجلد", - "openBuiltinTerminalFailed": "تعذر فتح الطرفية المدمجة", - "openCommitWindowFailed": "فشل فتح نافذة الالتزام", - "noAddableFilesInDir": "لا توجد ملفات متغيرة في هذا المجلد يمكن إضافتها إلى VCS", - "noRollbackFilesInDir": "لا توجد ملفات متغيرة في هذا المجلد يمكن التراجع عنها", - "addedToVcs": "تمت إضافة {name} إلى VCS", - "addToVcsFailed": "فشلت الإضافة إلى VCS", - "loadBranchesFailed": "فشل تحميل الفروع", - "renameFailed": "فشل إعادة التسمية", - "moveFailed": "فشل النقل", - "deleteFailed": "فشل الحذف", - "rolledBack": "تم التراجع عن {name}", - "rollbackFailed": "فشل التراجع", - "addedFilesToVcs": "{count, plural, one {تمت إضافة ملف واحد إلى VCS} other {تمت إضافة # ملفات إلى VCS}}", - "rolledBackFiles": "{count, plural, one {تم التراجع عن ملف واحد} other {تم التراجع عن # ملفات}}", - "savedAsCopy": "تم الحفظ كنسخة", - "saveCopyFailed": "فشل الحفظ كنسخة", - "watchStartFailed": "فشل بدء مراقبة الملفات", - "createFailed": "فشل في الإنشاء", - "downloadFailed": "فشل تنزيل {name}", - "downloadSaved": "تم تنزيل {name}", - "pathCopied": "تم نسخ المسار", - "copyPathFailed": "فشل نسخ المسار" - }, - "createDialog": { - "newFile": "ملف جديد", - "newDirectory": "مجلد جديد", - "description": "أدخل اسمًا لـ{kind} الجديد.", - "placeholderFile": "file-name.ext", - "placeholderDirectory": "folder-name" - }, - "renameDialog": { - "renameDirectory": "إعادة تسمية المجلد", - "renameFile": "إعادة تسمية الملف", - "description": "أدخل اسمًا جديدًا (الاسم فقط، بدون مسار).", - "placeholderDirectory": "اسم-مجلد-جديد", - "placeholderFile": "اسم-ملف-جديد.ext" - }, - "uploadDialog": { - "title": "رفع إلى مساحة العمل", - "description": "اضبط الوجهة عند الحاجة، ثم أضف الملفات أو المجلدات.", - "workspaceRoot": "جذر مساحة العمل", - "targetPathLabel": "رفع إلى", - "targetPathHint": "المسار النهائي: {path}", - "dropHint": "اسحب الملفات أو المجلدات هنا، أو استخدم الأزرار أدناه", - "dropHintActive": "حرّر للإضافة إلى قائمة الانتظار", - "selectFiles": "اختيار ملفات", - "selectFolder": "اختيار مجلد", - "startUpload": "بدء الرفع", - "clearQueue": "مسح المنتهية", - "removeItem": "إزالة من قائمة الانتظار", - "retry": "إعادة المحاولة", - "dropZoneAria": "أفلت الملفات هنا أو نشّط للاستعراض", - "folderEmpty": "لم يتم العثور على ملفات في المجلد المسحوب", - "summary": "الإجمالي: {total} · نجح: {succeeded} · فشل: {failed}", - "status": { - "pending": "قيد الانتظار", - "uploading": "جاري الرفع", - "success": "تم", - "error": "فشل", - "cancelled": "ملغى" - } - }, - "directoryDialog": { - "descriptionAdd": "حدد الملفات ضمن المجلد {path} لإضافتها إلى VCS.", - "descriptionRollback": "حدد الملفات ضمن المجلد {path} للتراجع عنها.", - "descriptionFallback": "حدد الملفات للمتابعة.", - "selectionCount": "تم تحديد {selected} من {total} ملف", - "selectAll": "تحديد الكل", - "unselectAll": "إلغاء تحديد الكل", - "loadingCandidates": "جارٍ تحميل تغييرات المجلد...", - "noOperableFiles": "لا توجد ملفات قابلة للمعالجة" - }, - "compareDialog": { - "title": "المقارنة مع الفرع", - "descriptionWithTarget": "حدد فرعًا وقارن مع {kind} {path}", - "descriptionFallback": "حدد فرعًا للمقارنة.", - "kindDirectory": "مجلد", - "kindFile": "ملف", - "filterPlaceholder": "تصفية الفروع، مثال: main / origin/main", - "singleClickHint": "انقر على فرع للمقارنة مباشرة", - "loadingBranches": "جارٍ تحميل الفروع...", - "recentBranches": "الفروع الحديثة ({count})", - "noCurrentBranch": "لا يوجد فرع حالي", - "localBranches": "الفروع المحلية ({count})", - "remoteBranches": "الفروع البعيدة ({count})", - "noMatchingBranches": "لا توجد فروع مطابقة" - }, - "externalConflictDialog": { - "title": "تم اكتشاف تغييرات خارجية في الملفات", - "descriptionWithPath": "تم تغيير الملف {path} على القرص، والتعديلات الحالية غير محفوظة.", - "descriptionFallback": "تم تغيير الملف الحالي على القرص، والتعديلات الحالية غير محفوظة.", - "compare": "مقارنة", - "savingCopy": "جارٍ حفظ نسخة...", - "saveAsCopy": "حفظ كنسخة", - "reload": "إعادة التحميل" - }, - "deleteConfirm": { - "title": "تأكيد الحذف", - "descriptionWithTarget": "حذف {kind} \"{name}\"؟ لا يمكن التراجع عن هذا الإجراء.", - "descriptionFallback": "لا يمكن التراجع عن هذا الإجراء.", - "kindDirectory": "مجلد", - "kindFile": "ملف" - }, - "rollbackConfirm": { - "title": "تأكيد التراجع", - "descriptionWithTarget": "التراجع عن التغييرات المحلية للملف \"{name}\"؟", - "descriptionFallback": "التراجع عن التغييرات المحلية لهذا الملف؟" - }, - "terminalTitle": "الطرفية · {name}" - }, - "commandDropdown": { - "loading": "جارٍ التحميل...", - "addCommand": "إضافة أمر", - "manageCommands": "إدارة الأوامر...", - "runCommandTitle": "تشغيل: {command}", - "stopCommandTitle": "إيقاف: {command}", - "manageDialog": { - "title": "إدارة الأوامر", - "empty": "لا توجد أوامر بعد", - "noResults": "لا توجد أوامر مطابقة", - "searchPlaceholder": "البحث في الأوامر", - "newCommand": "أمر جديد", - "nameLabel": "الاسم", - "commandLabel": "الأمر", - "dragSort": "اسحب للترتيب", - "dragSortCommand": "اسحب لترتيب {name}", - "orderFailed": "فشل حفظ ترتيب الأوامر", - "loadFailed": "فشل تحميل الأوامر", - "saveFailed": "فشل حفظ الأمر", - "deleteFailed": "فشل حذف الأمر", - "confirmDelete": { - "title": "حذف الأمر؟", - "message": "سيؤدي هذا إلى إزالة \"{name}\". لا يمكن التراجع عن هذا الإجراء." - } - } - }, - "workspaceContext": { - "confirmCloseDirtyTab": "إغلاق \"{title}\" بدون حفظ؟", - "confirmCloseOtherDirtyTabs": "إغلاق التبويبات الأخرى التي تحتوي تغييرات غير محفوظة؟", - "confirmCloseAllDirtyTabs": "إغلاق جميع التبويبات التي تحتوي تغييرات غير محفوظة؟", - "unableLoadContent": "تعذر تحميل المحتوى.\n\n{message}", - "previewRequestTimedOut": "انتهت مهلة طلب المعاينة", - "diffRequestTimedOut": "انتهت مهلة طلب Diff", - "branchCompareRequestTimedOut": "انتهت مهلة طلب مقارنة الفروع", - "commitDiffRequestTimedOut": "انتهت مهلة طلب Diff للالتزام", - "saveRequestTimedOut": "انتهت مهلة طلب الحفظ", - "reloadRequestTimedOut": "انتهت مهلة طلب إعادة التحميل", - "noChanges": "لا توجد تغييرات.", - "noDiffOutput": "لا يوجد مخرجات diff.", - "diffTitleWorkspace": "Diff · مساحة العمل", - "diffDescriptionWorkingTree": "شجرة العمل (HEAD)", - "diffTitleFile": "الفرق · {name}", - "compareTitleFile": "مقارنة · {name}", - "compareTitleBranch": "مقارنة · {branch}", - "compareDescriptionPath": "{path} · مقارنة مع {branch}", - "compareDescriptionBranch": "مقارنة مع {branch}", - "diffTitleCommitFile": "الفرق · {name} @ {hash}", - "diffTitleCommit": "الفرق · {hash}", - "diffDescriptionCommitPath": "{path} · الالتزام {commit}", - "diffDescriptionCommit": "الالتزام {commit}", - "diffTitleConflictFile": "تعارض · {name}", - "diffDescriptionConflict": "{path} · القرص مقابل غير المحفوظ" - }, - "chat": { - "acpConnections": { - "actions": { - "openAgentsSettings": "فتح إعدادات الوكلاء", - "retry": "إعادة المحاولة" - }, - "agentsSetupHint": "افتح الإعدادات > الوكلاء لإدارة التثبيت.", - "withSetupHint": "{message}\n{hint}", - "blocked": { - "missingConfig": "تعذر قراءة إعدادات الوكيل الحالية.", - "disabled": "{agent} معطّل في إعدادات الوكلاء. قم بتمكينه قبل الاتصال.", - "unavailable": "{agent} غير متاح على المنصة الحالية.", - "sdkMissing": "لم يتم تثبيت SDK الخاص بـ {agent}", - "adapterMissing": "محوّل ACP الخاص بـ {agent} غير مثبّت" - }, - "backendErrors": { - "initializeTimeout": "انتهت مهلة مصافحة اتصال {agent} (لا استجابة بعد 60 ثانية). افتح الإعدادات للتحقق من إعدادات الوكيل والشبكة.", - "mcpRejectedByAgent": "رفض {agent} الجلسة أثناء إرفاق رفيق MCP الخاص بـ codeg: {message} إن كان هذا الوكيل لا يدعم MCP، فأوقف «دعم MCP» من الإعدادات ثم أعد الاتصال.", - "processExited": "انتهت عملية {agent} بشكل غير متوقع.", - "spawnFailed": "تعذر بدء تشغيل {agent}: {message}", - "downloadFailed": "فشل تنزيل {agent}: {message}", - "sessionLoadResourceNotFound": "فشل تحميل جلسة {agent}. أعد التحميل لإعادة المحاولة، أو ابدأ محادثة جديدة.", - "sessionLoadUnavailable": "تعذّر على {agent} استعادة هذه الجلسة، فقد تكون انتهت أو توقّف الوكيل. أعد التحميل لإعادة المحاولة، أو ابدأ محادثة جديدة.", - "turnFailedRefusal": "رفض {agent} متابعة هذه الجولة. يدل ذلك غالبًا على خطأ في الخلفية أو البوابة. يرجى مراجعة سجلات الوكيل.", - "turnFailedMaxTokens": "بلغ {agent} الحد الأقصى للرموز المسموح بها في هذه الجولة.", - "turnFailedMaxTurnRequests": "بلغ {agent} الحد الأقصى لعدد الطلبات المسموح بها في هذه الجولة.", - "turnFailedUnknown": "أنهى {agent} الجولة بسبب توقف غير معروف.", - "grokModelSwitchIncompatibleAgent": "لا يمكن لـ {agent} التبديل إلى هذا النموذج في محادثة قائمة. ابدأ جلسة جديدة لاستخدامه.", - "turnFailedEmpty": "أنهى {agent} الجولة دون إنتاج أي رد.", - "turnFailedEmptyProtocol": "أنتج {agent} مخرجات تعذّر على codeg تحليلها — قد لا يتوافق إصدار الوكيل مع البروتوكول.", - "turnFailedEmptyMetadata": "أرسل {agent} تحديثات حالة فقط في هذه الجولة (الخطة / الوضع / الاستخدام) دون أي رد.", - "detailsInAlerts": "افتح التنبيهات في شريط الحالة ووسّع التفاصيل لعرض مخرجات الوكيل." - }, - "unableReadAgentConfig": "تعذر قراءة إعدادات الوكيل: {message}", - "connectFailedTitle": "فشل اتصال {agent}", - "toolFallbackTitle": "أداة", - "eventErrorTitle": "خطأ الوكيل", - "notificationTurnComplete": "{agent} أنهى الاستجابة", - "notificationError": "{agent} خطأ: {message}", - "claudeApiRetry": { - "fallbackError": "authentication_failed", - "retryingWithMax": "إعادة المحاولة {attempt}/{max}", - "retryingAttempt": "إعادة المحاولة رقم {attempt}", - "retrying": "جاري إعادة المحاولة", - "nextRetryIn": "المحاولة التالية خلال {seconds}ث", - "line": "{error}{status} · {retry}", - "lineWithDelay": "{error}{status} · {retry}، {delay}", - "httpStatus": " (HTTP {status})" - }, - "configOptionAdjusted": "ضبط {agent} {option} على {actual} بدلاً من {requested}" - }, - "connectionLifecycle": { - "tasks": { - "connectingTitle": "جارٍ الاتصال بـ {agent}", - "connectingDescription": "جارٍ إنشاء الاتصال", - "loadingSelectorsTitle": "جارٍ تحميل محددات {agent}", - "loadingSelectorsDescription": "جارٍ جلب خيارات الوضع وإعدادات الجلسة", - "initSessionTitle": "جارٍ تهيئة جلسة {agent}", - "initSessionDescription": "جارٍ إنشاء الجلسة وتحميل الإعدادات" - }, - "errors": { - "connectionFailed": "فشل الاتصال", - "sendPromptFailed": "فشل إرسال الرسالة: {error}" - } - }, - "shared": { - "attachedResources": "الموارد المرفقة", - "toolCallFailed": "فشل استدعاء الأداة" - }, - "messageThread": { - "emptyTitle": "لا توجد رسائل بعد", - "emptyDescription": "ابدأ محادثة لرؤية الرسائل هنا" - }, - "chatInput": { - "connecting": "جارٍ الاتصال...", - "agentResponding": "{agent} يرد...", - "sendMessage": "أرسل رسالة..." - }, - "messageInput": { - "askAnything": "اسأل أي شيء...", - "removeAttachmentAria": "إزالة {name}", - "attachFiles": "إرفاق ملفات", - "addActions": "إضافة", - "quickMessages": "الرسائل السريعة", - "quickMessagesEmpty": "لا توجد رسائل سريعة بعد", - "quickMessagesLoading": "جارٍ التحميل...", - "pasteAsPlainText": "لصق كنص عادي", - "cut": "قص", - "copy": "نسخ", - "selectAll": "تحديد الكل", - "pasteUnavailable": "تعذّر قراءة الحافظة. استخدم Ctrl/⌘V للصق.", - "clipboardWriteFailed": "تعذّرت الكتابة إلى الحافظة. استخدم اختصار لوحة المفاتيح.", - "quickMessageUntitled": "بدون عنوان", - "liveFeedback": "ملاحظات مباشرة", - "liveFeedbackDisabledHint": "متاح أثناء عمل الوكيل", - "dropFilesToAttach": "أسقط الملفات لإرفاقها", - "loadingSettings": "جارٍ تحميل الإعدادات...", - "loadingMode": "جارٍ تحميل الوضع...", - "modeLabel": "الوضع", - "toggleOn": "تشغيل", - "toggleOff": "إيقاف", - "agentSettings": "إعدادات الوكيل", - "searchModel": "البحث عن النماذج...", - "searchModelAria": "البحث عن النماذج", - "modelListLabel": "النماذج", - "noModels": "لم يتم العثور على نماذج", - "cancel": "إلغاء", - "send": "إرسال", - "forkAndSend": "تفريع وإرسال", - "queueMessage": "إضافة إلى قائمة الانتظار", - "steerIntoTurn": "إدراج في الدور الحالي", - "steerQueuedInstead": "أُضيفت إلى قائمة الانتظار — ستُرسل مع الدور التالي.", - "steerFailed": "تعذّر الإدراج في الدور الحالي", - "steerAttachmentsUnsupported": "نص فقط — المسودات التي تحتوي على مرفقات تمر عبر قائمة الانتظار.", - "slashCommands": "أوامر الشرطة المائلة", - "slashSearchPlaceholder": "البحث عن الأوامر...", - "slashSearchEmpty": "لا توجد أوامر مطابقة", - "experts": "الخبراء", - "office": "الأعمال المكتبية", - "research": "البحث العلمي", - "attachLocalUpload": "تحميل ملف محلي", - "attachServerFile": "اختيار ملف من الخادم", - "attachUploadTooLarge": "{names} يتجاوز حد التحميل {limit}MB وتم تخطيه.", - "attachUploadFailed": "فشل تحميل {names}.", - "attachUploadNotAFile": "{names} ليس ملفاً عادياً (مجلد أو ملف خاص) وتم تخطيه.", - "attachUploadQuotaExceeded": "نفدت مساحة التحميل على الخادم، تعذر رفع {names}.", - "attachUploadInProgress": "لا تزال الصور قيد الرفع — حاول مرة أخرى بعد قليل.", - "mentionEmpty": "لا توجد نتائج مطابقة", - "mentionLoading": "جارٍ البحث…", - "mentionListLabel": "الإشارات", - "mentionMore": "مزيد من النتائج — تابع الكتابة للتصفية", - "mentionCount": "{count, plural, zero {لا نتائج} one {نتيجة واحدة} two {نتيجتان} few {# نتائج} many {# نتيجة} other {# نتيجة}}", - "mentionGroupFile": "الملفات", - "mentionGroupAgent": "الوكلاء", - "mentionGroupSession": "الجلسات", - "mentionGroupCommit": "عمليات الإيداع", - "mentionGroupSkill": "المهارات" - }, - "messageQueue": { - "addToQueue": "إضافة للقائمة", - "saveEdit": "حفظ", - "cancelEdit": "إلغاء التعديل", - "editItem": "تعديل", - "deleteItem": "حذف" - }, - "welcomeInputPanel": { - "agentsSettingsPath": "الإعدادات > الوكلاء", - "autoConnectFallback": "انقر لفتح {path} وإدارة التثبيت.", - "autoConnectAppend": "{message}. انقر لفتح {path} وإدارة التثبيت.", - "enableAgentFirstPlaceholder": "فعّل وكيلًا واحدًا على الأقل قبل بدء جلسة...", - "prepareSessionFailed": "تعذّر تحضير جلسة الدردشة. يرجى المحاولة مرة أخرى.", - "createConversationFailed": "تعذّر إنشاء المحادثة. يرجى المحاولة مرة أخرى.", - "askAnythingPlaceholder": "اسأل أي شيء...", - "agentNotInstalled": "{agent} غير مثبّت · افتح إعدادات Agents لتثبيته", - "agentAdapterNotInstalled": "محوّل ACP الخاص بـ {agent} غير مثبّت (وهو منفصل عن واجهة الأوامر لديك) · افتح إعدادات Agents لتثبيته" - }, - "welcomePanel": { - "greeting": "ماذا تودّ أن تفعل اليوم؟", - "tips": { - "tileTabs": "انقر بزر الفأرة الأيمن على تبويب محادثة واختر «عرض متجانب» لمقارنة عدة جلسات جنبًا إلى جنب.", - "pinTab": "انقر نقرًا مزدوجًا على تبويب محادثة لتثبيته كي لا تستبدله جلسة جديدة تلقائيًا.", - "shortcutsNewSearch": "{newConversation} يفتح محادثة جديدة، و{searchConversations} يبحث في السجل.", - "slashAtMention": "اكتب / في حقل الإدخال لتشغيل أوامر السلاش، أو @ للإشارة إلى ملف من المشروع.", - "pasteDropFiles": "ألصق لقطة شاشة أو اسحب ملفًا مباشرة إلى حقل الإدخال لإرفاقه.", - "queueMessage": "أثناء رد الوكيل، تابع الكتابة — ستوضع رسالتك التالية في الطابور وتُرسل تلقائيًا عند انتهائه.", - "draftAutoSave": "تُحفظ المسودات غير المُرسلة تلقائيًا لكل محادثة وتُستعاد عند العودة.", - "forkSend": "تتضمن قائمة زر الإرسال المنسدلة «تفرّع وأرسل» لإنشاء فرع من النقطة الحالية في تبويب جديد.", - "exportConversation": "انقر بزر الفأرة الأيمن داخل المحادثة لتصديرها بصيغة Markdown أو HTML أو صورة.", - "chatChannels": "اربط Telegram / Lark / WeChat من «الإعدادات → قنوات الدردشة» للمتابعة من هاتفك.", - "shortcutsAuxPanel": "{toggleAuxPanel} يبدّل اللوحة اليمنى لعرض الملفات المعدّلة وتغييرات Git لهذه الجلسة.", - "shortcutsTerminalSidebar": "{toggleTerminal} يفتح الطرفية المدمجة، و{toggleSidebar} يبدّل الشريط الجانبي.", - "customShortcuts": "يمكن إعادة تعيين جميع الاختصارات من «الإعدادات → الاختصارات».", - "webService": "فعّل «الإعدادات → خدمة الويب» ليتمكن أعضاء الفريق من الوصول إلى نفس codeg عبر المتصفح.", - "fusionMode": "افتح ملفًا أو فرقًا لعرضه تلقائيًا بجوار المحادثة.", - "quickMessages": "افتح زر + بجانب الإدخال واختر «الرسائل السريعة» لإدراج مقتطف محفوظ (تُدار من «الإعدادات → الرسائل السريعة»).", - "experts": "يحتوي زر + على قائمة «مهارات الخبراء» — حمّل أدوارًا مثل التصحيح أو التخطيط بنقرة واحدة.", - "taskBoard": "تنفّذ المهام قيد الانتظار عملاً كاملاً من البداية إلى النهاية: يعمل الوكيل في worktree خاص به، ثم تراجع الفروق وتدمجها.", - "automations": "تشغّل الأتمتة موجّهًا محفوظًا وفق جدول زمني — مراجعة ليلية أو تقريرًا دوريًا — ويمكن أن يحصل كل تشغيل على worktree خاص به.", - "tokenUsage": "انقر على عدد المحادثات في شريط الحالة لفتح استهلاك الرموز، موزّعًا حسب اليوم والوكيل والنموذج والمجلد.", - "mentionTargets": "لا تقتصر @ على الملفات: اذكر وكيلًا آخر لتفويض مهمة فرعية، أو أشِر إلى جلسة سابقة أو التزام أو مهارة.", - "splitGroups": "انقر بزر الفأرة الأيمن على تبويب واختر «تقسيم لليمين» أو «تقسيم للأسفل» لإبقاء محادثتين في لوحين منفصلين.", - "worktrees": "افتح زر الفرع واختر «Worktree جديد» ليعمل عدة وكلاء على المستودع نفسه دون أن يستبدل أحدهم ملفات الآخر.", - "importSessions": "هل شغّلت جلسات في الطرفية من قبل؟ تحتوي قائمة المجلد على «استيراد الجلسات المحلية» لجلب ذلك السجل إلى codeg.", - "subSessions": "عندما يفوّض وكيل مهمة، تظهر الجلسة الفرعية متداخلة تحته في الشريط الجانبي — وسّع الصف لتتابع ما فعلته كل واحدة.", - "liveFeedback": "تُدرج «ملاحظات مباشرة» في قائمة + ملاحظةً داخل الدور الذي ينفّذه الوكيل بالفعل، دون مقاطعته.", - "skillPacks": "تجمع الإعدادات ← حزم المهارات خبراء البرمجة والبحث العلمي ومهارات المكتب — فعّلها لكل وكيل على حدة.", - "modelProviders": "تقبل الإعدادات ← مزودو النماذج مفتاح API أو نقطة نهاية خاصة بك، ثم تختار النموذج مباشرة من حقل الإدخال.", - "workspaceBackground": "تحدّد الإعدادات ← المظهر صورة خلفية لمساحة العمل، وشفافية اللوحات، وخطوط التطبيق." - }, - "quickActions": { - "excel": "مصنّف Excel", - "excelDesc": "جداول بيانات وصيغ ومخططات", - "word": "مستند Word", - "wordDesc": "تقارير ورسائل ومذكرات", - "ppt": "عرض تقديمي", - "pptDesc": "شرائح بتصميم احترافي", - "pitchDeck": "عرض استثماري", - "pitchDeckDesc": "عرض تمويل بمؤشرات رئيسية", - "morph": "حركة Morph", - "morphDesc": "انتقالات شرائح سينمائية", - "morph3d": "Morph ثلاثي الأبعاد", - "morph3dDesc": "نماذج ثلاثية الأبعاد وحركات كاميرا", - "academic": "ورقة أكاديمية", - "academicDesc": "بحث باستشهادات وبنية", - "financial": "نموذج مالي", - "financialDesc": "قوائم وDCF وتوقعات", - "dashboard": "لوحة بيانات", - "dashboardDesc": "مؤشرات وتحليلات من بياناتك", - "prompts": { - "excel": "أنشئ مصنّف Excel وفق المتطلبات التالية:\n\n[صف هنا بياناتك وجداولك وصيغك ومخططاتك]", - "word": "أنشئ مستند Word وفق المتطلبات التالية:\n\n[صف هنا محتوى المستند وبنيته وتنسيقه]", - "ppt": "أنشئ عرض PowerPoint تقديمي وفق المتطلبات التالية:\n\n[صف هنا شرائحك ومحتواك وتصميمك]", - "pitchDeck": "أنشئ عرضًا استثماريًا لجمع التمويل وفق المتطلبات التالية:\n\n[صف هنا شركتك وجولة التمويل والمؤشرات الرئيسية]", - "morph": "أنشئ عرضًا تقديميًا بحركات انتقال Morph:\n\n[صف هنا موضوع العرض والمؤثرات المرئية المطلوبة]", - "morph3d": "أنشئ عرض Morph ثلاثي الأبعاد بنماذج GLB وحركات كاميرا:\n\n[صف هنا موضوعك ومفهومك المرئي ثلاثي الأبعاد]", - "academic": "اكتب ورقة أكاديمية في Word وفق المتطلبات التالية:\n\n[صف هنا موضوع بحثك ومنهجيتك وأبرز نتائجك]", - "financial": "أنشئ نموذجًا ماليًا في Excel وفق المتطلبات التالية:\n\n[صف هنا قوائمك المالية وتوقعاتك وتحليلاتك]", - "dashboard": "أنشئ لوحة بيانات في Excel وفق المتطلبات التالية:\n\n[صف هنا مصدر بياناتك ومؤشراتك ومخططاتك]", - "scientific-brainstorming": "ساعدني في توليد أفكار بحثية: استكشف الروابط متعددة التخصصات، وتحدَّ الافتراضات، واكشف الفجوات الواعدة. المجال الذي أستكشفه: ", - "hypothesis-generation": "ساعدني في تحويل هذه الملاحظات إلى فرضيات قابلة للاختبار، مع تنبؤات واضحة وآليات معقولة وتجارب لاختبارها. ملاحظاتي: ", - "experimental-design": "ساعدني في تصميم تجربة دقيقة قبل جمع البيانات: التصميم والعشوائية والضوابط وكيفية تجنّب الالتباس. ما أريد دراسته: ", - "statistical-power": "ساعدني في تحديد حجم العينة المطلوب: أرشدني خلال تحليل القوة الإحصائية (حجم الأثر، ألفا، القوة) لتصميمي. التفاصيل: ", - "statistical-analysis": "ساعدني في تحليل هذه البيانات بشكل صحيح: اختر الاختبار المناسب، وتحقق من الافتراضات، وأبلغ عن أحجام الأثر، واكتب النتائج. بياناتي وسؤالي: ", - "exploratory-data-analysis": "قم بتحليل استكشافي لملف بياناتي: لخّص بنيته وجودته والأنماط اللافتة، ثم اقترح الخطوات التالية. الملف هو: ", - "scientific-visualization": "ساعدني في إنشاء شكل بجودة النشر: تخطيط واضح، وأشرطة خطأ صادقة، ولوحة ألوان مناسبة لعمى الألوان، وتنسيق المجلة. ما أريد عرضه: ", - "scientific-critical-thinking": "ساعدني في التقييم النقدي لهذه الدراسة أو الادعاء: قيّم جودة الأدلة، وارصد التحيّزات والعوامل المربكة، وزِن الاستنتاجات. إليك المحتوى: ", - "paper-lookup": "ساعدني في العثور على أوراق ذات صلة ونص كامل مفتوح الوصول عبر قواعد البيانات الأكاديمية، مع استشهادات يمكنني إعادة استخدامها. أبحث عن: " - }, - "paper-lookup": "البحث عن الأوراق البحثية", - "paper-lookupDesc": "البحث في 10 واجهات برمجية أكاديمية (PubMed وarXiv وOpenAlex وCrossref…) عن الأوراق والاستشهادات والنص الكامل المفتوح.", - "scientific-critical-thinking": "التفكير النقدي", - "scientific-critical-thinkingDesc": "تقييم الادعاءات العلمية وجودة الأدلة: رصد التحيّزات والعوامل المربكة وتطبيق أطر GRADE ومخاطر التحيّز.", - "scientific-visualization": "التصور العلمي", - "scientific-visualizationDesc": "أشكال جاهزة للنشر: تخطيطات متعددة اللوحات، وتعليقات الدلالة الإحصائية، وتنسيق خاص بكل مجلة.", - "exploratory-data-analysis": "تحليل البيانات الاستكشافي", - "exploratory-data-analysisDesc": "استكشاف آلي لملفات البيانات العلمية بأكثر من 200 صيغة مع مقاييس الجودة والتقارير.", - "statistical-analysis": "التحليل الإحصائي", - "statistical-analysisDesc": "تحليل إحصائي موجَّه: اختيار الاختبار، والتحقق من الافتراضات، وأحجام الأثر، والتقارير بأسلوب APA.", - "statistical-power": "القوة الإحصائية", - "statistical-powerDesc": "تحليل حجم العينة والقوة الإحصائية: عدد المشاركين اللازم، وأصغر تأثير قابل للكشف، ومنحنيات القوة.", - "experimental-design": "تصميم التجارب", - "experimental-designDesc": "تصميم دراسات دقيقة قبل جمع البيانات: العشوائية والتجميع والضوابط وتصاميم العوامل/DOE.", - "hypothesis-generation": "توليد الفرضيات", - "hypothesis-generationDesc": "تحويل الملاحظات إلى فرضيات قابلة للاختبار مع تنبؤات وآليات وتجارب لاختبارها.", - "scientific-brainstorming": "العصف الذهني العلمي", - "scientific-brainstormingDesc": "توليد أفكار بحثية مفتوحة: استكشاف الروابط متعددة التخصصات وتحدّي الافتراضات وكشف الفجوات البحثية.", - "tabs": { - "office": "الأعمال المكتبية", - "coding": "تطوير الكود", - "research": "البحث العلمي" - }, - "coding": { - "brainstormingDesc": "استكشف النية والمتطلبات قبل البناء", - "debuggingDesc": "حدد السبب الجذري قبل اقتراح الإصلاحات", - "writingSkillsDesc": "أنشئ وحرّر وتحقق من مهارات قابلة لإعادة الاستخدام" - }, - "notEnabled": { - "title": "المهارة ”{skill}“ غير مُفعّلة بعد لـ {agent}", - "description": "فعّلها من الإعدادات لاستخدامها هنا.", - "action": "تفعيل", - "hint": "المهارة غير مُفعّلة" - }, - "scrollPrev": "عرض المهارات السابقة", - "scrollNext": "عرض المزيد من المهارات" - } - }, - "agentSelector": { - "noEnabledAgents": "لا يوجد وكلاء مفعّلون", - "openAgentsSettings": "فتح إعدادات الوكلاء", - "notInstalled": "غير مثبّت", - "moreAgents": "وكلاء إضافيون ({count})" - }, - "subAgentOverlay": { - "title": "الوكلاء الفرعيون", - "collapsedSummary": "الوكلاء الفرعيون {count}", - "collapseAria": "طي الوكلاء الفرعيين" - }, - "agentPlanOverlay": { - "title": "خطة الوكيل", - "collapsePlanAria": "طي الخطة", - "collapsedSummary": "الخطة {completed}/{total}", - "status": { - "completed": "مكتمل", - "inProgress": "قيد التنفيذ", - "pending": "قيد الانتظار", - "unknown": "غير معروف" - }, - "priority": { - "high": "مرتفع", - "medium": "متوسط", - "low": "منخفض", - "unknown": "غير معروف" - } - }, - "permissionDialog": { - "subtitle": "يطلب الوكيل إذنًا لمتابعة هذا الدور.", - "queuedCount": "+{count} في الانتظار", - "kindFallbackTool": "أداة", - "command": "أمر", - "cwd": "دليل العمل: {cwd}", - "filesSummary": "الملفات: {count}", - "moreFiles": "+{count} ملف إضافي", - "plan": "الخطة", - "allowedActions": "الإجراءات المسموح بها", - "targetMode": "وضع الهدف: {mode}", - "optionGrants": "ما يمنحه كل خيار", - "changeScopeSession": "هذه الجلسة", - "changeScopeProcess": "هذا التشغيل", - "changeScopeUser": "محفوظ في إعدادات المستخدم", - "changeScopeProject": "محفوظ في إعدادات المشروع", - "changeScopeProjectLocal": "محفوظ في إعدادات المشروع المحلية", - "changeScopePersistent": "محفوظ بشكل دائم" - }, - "questionDialog": { - "title": "الوكيل يطرح سؤالاً", - "placeholder": "اكتب إجابتك...", - "send": "إرسال" - }, - "messageBranch": { - "previousBranchAria": "الفرع السابق", - "nextBranchAria": "الفرع التالي", - "pageOf": "{current} من {total}" - }, - "terminal": { - "title": "الطرفية", - "running": "قيد التشغيل" - }, - "reasoning": { - "thinking": "جارٍ التفكير…", - "thoughtForFewSeconds": "تفكير", - "thoughtForSeconds": "تفكير" - }, - "linkSafety": { - "errorCannotOpen": "تعذر فتح الملف المحلي", - "errorNoWorkspace": "لا يوجد مجلد مساحة عمل نشط حالياً.", - "errorFailedOpen": "فشل فتح الملف المحلي", - "errorFailedLink": "فشل فتح الرابط", - "errorUnsupportedLinkProtocol": "بروتوكول الرابط هذا غير مدعوم." - }, - "fileActions": { - "openInFinder": "فتح في Finder", - "openInExplorer": "فتح في Explorer", - "openInFileManager": "فتح في مدير الملفات", - "copyRelativePath": "نسخ المسار النسبي", - "copyAbsolutePath": "نسخ المسار المطلق", - "pathCopied": "تم نسخ المسار", - "copyPathFailed": "فشل نسخ المسار", - "openFailed": "فشل فتح الملف المحلي" - }, - "messageList": { - "attachedResources": "الموارد المرفقة", - "loading": "جارٍ التحميل...", - "loadEarlier": "تحميل الرسائل السابقة", - "loadingEarlier": "جارٍ تحميل الرسائل السابقة…", - "error": "خطأ: {message}", - "errorTitle": "فشل تحميل الجلسة", - "errorActionReload": "إعادة تحميل", - "errorActionNewSession": "محادثة جديدة", - "emptyConversation": "لا توجد رسائل في هذه المحادثة.", - "systemMessage": "رسالة النظام", - "copyMessage": "نسخ", - "copied": "تم النسخ", - "downloadImage": "تنزيل الصورة", - "downloadFailed": "فشل التنزيل: {message}", - "imageGeneration": "إنشاء الصورة", - "imageGenerationPending": "جارٍ إنشاء الصورة…", - "imageGenerationFailed": "فشل إنشاء الصورة", - "model": "النموذج", - "tokenStats": "استخدام الرموز", - "tokenInput": "الإدخال", - "tokenOutput": "الإخراج", - "tokenCacheRead": "قراءة التخزين المؤقت", - "tokenCacheWrite": "كتابة التخزين المؤقت", - "duration": "المدة", - "completedAt": "وقت الإنجاز", - "jumpToPreviousUserMessage": "الانتقال إلى رسالة المستخدم", - "showMore": "عرض المزيد", - "showLess": "طي" - }, - "liveTurnStats": { - "thinking": "جارٍ التفكير...", - "streaming": "جارٍ البث", - "elapsedHours": "{value}س", - "elapsedMinutes": "{value}د", - "elapsedSeconds": "{value}ث", - "outputSpeedAria": "السرعة التقديرية للإخراج", - "outputSpeedTooltip": "السرعة التقديرية للإخراج (نص + تفكير)" - }, - "jsonTree": { - "viewRaw": "عرض JSON الخام", - "viewTree": "عرض الشجرة", - "fields": "{count, plural, zero {لا حقول} one {حقل واحد} two {حقلان} few {# حقول} many {# حقلًا} other {# حقل}}", - "items": "{count, plural, zero {لا عناصر} one {عنصر واحد} two {عنصران} few {# عناصر} many {# عنصرًا} other {# عنصر}}" - }, - "tool": { - "parameters": "المعلمات", - "error": "خطأ", - "result": "النتيجة", - "status": { - "approvalRequested": "بانتظار الموافقة", - "approvalResponded": "تم الرد", - "inputAvailable": "قيد التشغيل", - "inputStreaming": "قيد الانتظار", - "outputAvailable": "مكتمل", - "outputDenied": "مرفوض", - "outputError": "خطأ" - } - }, - "toolCallBlock": { - "tool": "أداة", - "error": "خطأ", - "result": "النتيجة" - }, - "delegation": { - "subAgentRunning": "العميل الفرعي قيد التشغيل…", - "noDetail": "No detail available yet.", - "unknownAgent": "وكيل فرعي", - "openDetail": "عرض المحادثة", - "detailTitle": "محادثة الوكيل الفرعي", - "detailDescription": "عرض للقراءة فقط لمحادثة الوكيل الفرعي المُفوَّض.", - "waitForResult": "في انتظار نتيجة المهمة {task}", - "waitForResultNoTask": "في انتظار نتيجة المهمة", - "cancelTask": "جارٍ إلغاء المهمة {task}", - "cancelTaskNoTask": "جارٍ إلغاء المهمة", - "resultPageOf": "{current} / {total}", - "prevResult": "النتيجة السابقة", - "nextResult": "النتيجة التالية", - "noResultText": "لا توجد نتيجة في هذا الفحص.", - "status": { - "starting": "قيد البدء", - "running": "قيد التشغيل", - "checked": "تم الفحص", - "waiting": "في انتظار الموافقة", - "ok": "اكتمل", - "err": { - "default": "فشل", - "delegation_disabled": "معطل", - "depth_limit": "حد العمق", - "invalid_agent_type": "وكيل غير صالح", - "spawn_failed": "فشل البدء", - "send_failed": "فشل الإرسال", - "timeout": "انتهت المهلة", - "canceled": "ملغى", - "child_refusal": "رفض الوكيل الفرعي", - "child_max_tokens": "الوكيل الفرعي: حد الرموز", - "child_max_turn_requests": "الوكيل الفرعي: حد الطلبات", - "child_empty": "الوكيل الفرعي بدون استجابة", - "child_unknown": "الوكيل الفرعي: خطأ", - "unknown": "مهمة غير معروفة" - } - } - }, - "contentParts": { - "showingTailOutput": "يتم عرض نهاية المخرجات أثناء البث لتحسين الأداء.", - "result": "النتيجة", - "unknown": "غير معروف", - "inputTruncated": "تم اقتطاع الإدخال — قد يكون الفرق غير مكتمل.", - "replaceAll": "استبدال الكل", - "filesCount": "الملفات: {count}", - "update": "تحديث", - "moreFiles": "+{count} ملف إضافي", - "timeoutMs": "المهلة: {timeout}ms", - "backgroundTrue": "الخلفية: true", - "scriptToolCalls": "{count, plural, zero {صفر استدعاء أداة} one {استدعاء أداة واحد} two {استدعاءا أداة} few {# استدعاءات أداة} many {# استدعاء أداة} other {# استدعاء أداة}}", - "offset": "الإزاحة: {offset}", - "limit": "الحد: {limit}", - "pages": "الصفحات: {pages}", - "mode": "الوضع: {mode}", - "cell": "الخلية: {cell}", - "shellSession": "الجلسة {id}", - "pathLabel": "المسار:", - "globLabel": "نمط glob:", - "typeLabel": "النوع:", - "outputLabel": "المخرجات:", - "caseInsensitive": "غير حساس لحالة الأحرف", - "multiline": "متعدد الأسطر", - "promptLabel": "المطالبة", - "subjectLabel": "الموضوع", - "taskLabel": "المهمة", - "nameLabel": "الاسم:", - "agentPromptLabel": "المطالبة", - "agentModelLabel": "النموذج", - "agentRunning": "قيد التشغيل...", - "agentLiveTranscript": "النشاط المباشر", - "agentProgressTools": "{count} استدعاءات أدوات", - "agentProgressTurns": "{count} جولات", - "agentProgressContext": "السياق {pct}%", - "agentSessionAction": "عرض جلسة الوكيل الفرعي", - "agentSessionTitle": "جلسة الوكيل الفرعي", - "agentSessionLoading": "جارٍ تحميل سجل الوكيل الفرعي…", - "agentSessionEmpty": "لم يكتب الوكيل الفرعي أي شيء بعد.", - "agentFallbackTitle": "جارٍ تشغيل الوكيل الفرعي…", - "agentCodexLaunchOnly": "تم التشغيل. لا يبلّغ Codex عن أي تقدّم إضافي لهذا الوكيل الفرعي — وستصل نتيجته كرسالة في هذه المحادثة.", - "agentStatsBash": "الأوامر", - "agentStatsRead": "الملفات المقروءة", - "agentStatsSearch": "عمليات البحث", - "agentStatsEdit": "التعديلات", - "agentStatsOther": "أخرى", - "goal": { - "title": "الهدف:", - "titleWithStatus": "الهدف {status}", - "objective": "الهدف", - "statusLabel": "الحالة", - "tokensUsed": "tokens المستخدمة", - "budget": "الميزانية", - "remaining": "المتبقي", - "elapsed": "المدة", - "tokens": "tokens", - "pause": "إيقاف مؤقت", - "clear": "مسح", - "status": { - "active": "نشط", - "paused": "متوقف مؤقتًا", - "blocked": "محظور", - "usageLimited": "الاستخدام محدود", - "budgetLimited": "الميزانية محدودة", - "complete": "مكتمل", - "limited": "تم بلوغ الحد" - } - }, - "field": { - "file": "ملف", - "notebook": "دفتر", - "command": "أمر", - "old": "قديم", - "new": "جديد", - "pattern": "النمط", - "path": "المسار", - "query": "الاستعلام", - "url": "URL:", - "description": "الوصف", - "content": "المحتوى", - "source": "المصدر", - "prompt": "المطالبة", - "subject": "الموضوع", - "taskId": "معرف المهمة", - "status": "الحالة", - "skill": "Skill", - "args": "الوسائط", - "offset": "الإزاحة", - "limit": "الحد", - "glob": "نمط glob", - "type": "النوع", - "output": "المخرجات", - "replaceAll": "استبدال الكل", - "language": "اللغة", - "timeout": "المهلة", - "background": "الخلفية", - "agentType": "نوع الوكيل", - "library": "المكتبة", - "libraryId": "معرف المكتبة" - }, - "title": { - "edit": "تحرير", - "command": "أمر", - "script": "سكربت", - "waitCommand": "انتظار {command}", - "waitCell": "انتظار الجلسة {id}", - "terminateCommand": "إنهاء {command}", - "terminateCell": "إنهاء الجلسة {id}", - "stdinChars": "إدخال {chars}", - "todoWrite": "TodoWrite (تحديث المهام)", - "read": "قراءة", - "write": "كتابة", - "notebookEdit": "NotebookEdit (تحرير الدفتر)", - "editFiles": "تحرير ({count} ملفًا)", - "editWithTarget": "تحرير {target}", - "readWithTarget": "قراءة {target}", - "writeWithTarget": "كتابة {target}", - "notebookEditWithTarget": "NotebookEdit ({target})", - "globWithPattern": "نمط glob {pattern}", - "listFilesWithPath": "عرض الملفات {path}", - "grepWithPattern": "نمط grep {pattern}", - "taskCreateWithSubject": "إنشاء مهمة: {subject}", - "taskUpdateWithStatus": "تحديث المهمة #{id} -> {status}", - "taskUpdate": "تحديث المهمة #{id}", - "webFetchWithUrl": "WebFetch ({url})", - "webSearchWithQuery": "بحث الويب: {query}", - "todosProgress": "المهام ({done}/{total})", - "skillWithName": "Skill: {name}", - "genericWithContext": "{tool} ({context})" - }, - "search": { - "noMatches": "لا توجد نتائج مطابقة", - "matchSummary": "{matches, plural, zero {صفر تطابق} one {تطابق واحد} two {تطابقان} few {# تطابقات} many {# تطابقاً} other {# تطابق}} في {files, plural, zero {صفر ملف} one {ملف واحد} two {ملفان} few {# ملفات} many {# ملفاً} other {# ملف}}", - "fileSummary": "{files, plural, zero {صفر ملف} one {ملف واحد} two {ملفان} few {# ملفات} many {# ملفاً} other {# ملف}}", - "moreResults": "{count, plural, zero {لا نتائج إضافية} one {نتيجة إضافية واحدة غير معروضة} two {نتيجتان إضافيتان غير معروضتين} few {# نتائج إضافية غير معروضة} many {# نتيجة إضافية غير معروضة} other {# نتيجة إضافية غير معروضة}}" - }, - "toolGroup": { - "search": "{count, plural, zero {بحث صفر مرة} one {بحث مرة واحدة} two {بحث مرتين} few {بحث # مرات} many {بحث # مرة} other {بحث # مرة}}", - "command": "{count, plural, zero {تنفيذ صفر أمر} one {تنفيذ أمر واحد} two {تنفيذ أمرين} few {تنفيذ # أوامر} many {تنفيذ # أمراً} other {تنفيذ # أمر}}", - "read": "{count, plural, zero {قراءة ملفات صفر مرة} one {قراءة ملفات مرة واحدة} two {قراءة ملفات مرتين} few {قراءة ملفات # مرات} many {قراءة ملفات # مرة} other {قراءة ملفات # مرة}}", - "memory": "{count, plural, zero {استرجاع صفر ذاكرة} one {استرجاع ذاكرة واحدة} two {استرجاع ذاكرتين} few {استرجاع # ذكريات} many {استرجاع # ذكرى} other {استرجاع # ذكرى}}", - "edit": "{count, plural, zero {تعديل ملفات صفر مرة} one {تعديل ملفات مرة واحدة} two {تعديل ملفات مرتين} few {تعديل ملفات # مرات} many {تعديل ملفات # مرة} other {تعديل ملفات # مرة}}", - "fetch": "{count, plural, zero {جلب صفر مورد} one {جلب مورد واحد} two {جلب موردين} few {جلب # موارد} many {جلب # مورداً} other {جلب # مورد}}", - "think": "{count, plural, zero {تفكير صفر مرة} one {تفكير مرة واحدة} two {تفكير مرتين} few {تفكير # مرات} many {تفكير # مرة} other {تفكير # مرة}}", - "todo": "{count, plural, zero {تحديث صفر مهمة} one {تحديث مهمة واحدة} two {تحديث مهمتين} few {تحديث # مهام} many {تحديث # مهمة} other {تحديث # مهمة}}", - "task": "{count, plural, zero {تشغيل صفر مهمة} one {تشغيل مهمة واحدة} two {تشغيل مهمتين} few {تشغيل # مهام} many {تشغيل # مهمة} other {تشغيل # مهمة}}", - "other": "{count, plural, zero {استخدام صفر أداة} one {استخدام أداة واحدة} two {استخدام أداتين} few {استخدام # أدوات} many {استخدام # أداة} other {استخدام # أداة}}", - "errorSuffix": "{count, plural, zero {صفر فشل} one {فشل واحد} two {فشلان} few {# فشلوا} many {# فشلاً} other {# فشل}}", - "joiner": " · " - }, - "planMode": { - "entered": "تم بدء وضع التخطيط", - "planLabel": "الخطة", - "reviewApproved": "تمت الموافقة على الخطة — جارٍ التنفيذ", - "reviewKept": "الاستمرار في وضع الخطة", - "reviewPending": "في انتظار قرار الخطة", - "submitted": "تم إرسال الخطة", - "switched": "تم تبديل الوضع" - }, - "backgroundTask": { - "title": "مهمة في الخلفية", - "titleWithId": "مهمة في الخلفية · {id}", - "running": "قيد التشغيل", - "completed": "اكتملت", - "failed": "فشلت", - "stopped": "متوقفة", - "exitCode": "رمز الخروج {code}", - "polledTimes": "تم الاستعلام {count} مرة", - "runningInBackground": "في الخلفية", - "launchNote": "قيد التشغيل في الخلفية · {id}" - }, - "codexScript": { - "outputMissing": "اقتطع codex مُخرَج النص البرمجي وأزال الفاصل الخاص بهذا الأمر، لذا تعذّر نسب أي مُخرَج إليه.", - "sharedWith": "يحتوي هذا المقطع أيضًا على مُخرَج {commands} — إذ اقتطع codex الفواصل الخاصة بها.", - "truncated": "مقتطع" - } - }, - "messageNav": { - "title": "تنقل الرسائل", - "collapse": "طي تنقل الرسائل", - "collapsedSummary": "الرسائل {count}", - "fileCount": "{count, plural, one {# ملف} other {# ملفات}}", - "remove": "إزالة", - "noDiffDataAvailable": "لا توجد بيانات diff متاحة لـ {filePath}" - }, - "replyArtifacts": { - "title": "الملفات المتغيرة", - "fileCount": "{count, plural, one {# ملف} other {# ملفات}}", - "newFilesTitle": "ملفات جديدة", - "revealInFolder": "عرض في مدير الملفات", - "openFile": "فتح {filePath}", - "openInEditor": "فتح في المحرر", - "remove": "إزالة", - "noDiffDataAvailable": "لا توجد بيانات diff متاحة لـ {filePath}" - }, - "askQuestion": { - "title": "يحتاج الوكيل إلى اختيارك", - "subtitle": "أجب ثم أرسل. يمكنك التخطّي في أي وقت.", - "recommended": "موصى به", - "other": "أخرى", - "otherPlaceholder": "اكتب إجابتك…", - "singleSelect": "اختيار واحد", - "multiSelect": "اختيار متعدد", - "skip": "تخطّي", - "next": "التالي", - "submit": "إرسال", - "submitError": "تعذّر الإرسال. حاول مرة أخرى." - }, - "planApproval": { - "title": "لدى الوكيل خطة — راجعها", - "emptyPlan": "لم يكتب الوكيل خطة. وافق للبدء في التنفيذ أو اطلب تعديلات.", - "approve": "الموافقة والبدء", - "requestChanges": "طلب تعديلات", - "abandon": "تجاهل", - "feedbackPlaceholder": "ما الذي ينبغي تغييره؟", - "sendChanges": "إرسال", - "cancel": "إلغاء", - "submitError": "تعذّر الإرسال. حاول مرة أخرى." - }, - "feedbackCheckResult": { - "count": "{count} ملاحظة", - "expand": "عرض كل الملاحظات", - "collapse": "طي", - "errorTitle": "فشل التحقق من الملاحظات" - }, - "askQuestionResult": { - "title": "سؤال", - "answeredLabel": "سؤال وجواب:", - "awaiting": "في انتظار إجابتك…", - "declined": "لقد تجاهلت هذا — استخدم الوكيل حكمه الخاص.", - "noSelection": "لا يوجد اختيار" - }, - "configStale": { - "agentConfigTitle": "تم تحديث إعدادات الوكيل", - "modelProviderTitle": "تم تحديث مزوّد النموذج", - "description": "لا تزال هذه الجلسة تستخدم الإعدادات السابقة. أعد الاتصال لتطبيقها (سيتم الاحتفاظ بسجل المحادثة).", - "reconnect": "أعد الاتصال للتطبيق", - "reconnecting": "جارٍ إعادة الاتصال…", - "reconnectDisabledDuringTurn": "متاح بعد انتهاء الدور الحالي", - "dismiss": "تجاهل", - "reconnectFailed": "فشل في إعادة الاتصال بالجلسة", - "applied": "تم تطبيق الإعدادات الجديدة" - }, - "piProjectTrust": { - "title": "يتضمّن هذا المشروع موارد pi", - "description": "لا يقوم pi بتحميل ملفات ‎.pi الخاصة بالمستودع. راجعها لتقرّر.", - "descriptionExecutable": "يتضمّن المستودع إضافات pi تُنفّذ التعليمات البرمجية عند بدء التشغيل. لا يقوم pi بتحميلها. راجعها قبل أن تقرّر.", - "review": "مراجعة…", - "dismiss": "تجاهل", - "dialogTitle": "هل تثق بموارد pi في هذا المشروع؟", - "dialogDescription": "لا يحمّل pi ملفات ‎.pi الخاصة بالمستودع إلا إذا وثقت بالمجلد. لا تمنح الثقة إلا إذا كنت تثق بمحتوى هذا المستودع.", - "executionWarning": "الإضافات هي تعليمات برمجية. الوثوق بهذا المجلد يتيح للمستودع تشغيلها عند بدء pi بصلاحياتك، وقبل أن ترسل أي رسالة.", - "scopeNote": "يُحفظ القرار في ملف trust.json الخاص بـ pi لهذا المجلد، ويسري على كل المجلدات داخله، ويُستخدم أيضًا عند تشغيلك pi بنفسك في الطرفية. يمكنك تغييره لاحقًا من الإعدادات ← الوكلاء ← Pi.", - "trust": "الوثوق بالمشروع", - "decline": "إبقاؤها غير محمّلة", - "disabledDuringTurn": "متاح بعد انتهاء الدور الحالي", - "trustedToast": "تم الوثوق بالمشروع — أُعيد الاتصال ليحمّل pi موارده", - "declinedToast": "تبقى موارد المشروع غير محمّلة", - "saveFailed": "تعذّر حفظ قرار الثقة بالمشروع", - "grantTitle": "هذا المشروع موثوق بالفعل", - "grantDescription": "يحمّل pi ملفات ‎.pi الخاصة بهذا المستودع. راجع ما الذي يسمح به ذلك.", - "grantInheritedDescription": "أحد المجلدات الأعلى موثوق، لذا يحمّل pi ملفات ‎.pi الخاصة بهذا المستودع. راجع ما الذي يسمح به ذلك.", - "grantDialogTitle": "موارد pi في هذا المشروع موثوقة", - "grantDialogDescription": "يُسمح لـ pi بتحميل ملفات ‎.pi الخاصة بهذا المستودع. كانت إصدارات codeg السابقة تمنح ذلك تلقائيًا عند فتحك لمجلد، لذا ربما لم يُطلب رأيك مطلقًا.", - "grantExecutionWarning": "الإضافات هي تعليمات برمجية. يشغّلها المستودع عند بدء pi بصلاحياتك، قبل أن ترسل أي رسالة.", - "inheritedFrom": "الثقة موروثة من", - "revoke": "إلغاء الثقة", - "keepTrusted": "الإبقاء على الثقة", - "revokedToast": "أُلغيت الثقة — أُعيد الاتصال ليتوقف pi عن تحميل موارد المشروع", - "trustedNoReconnect": "تم الوثوق بالمشروع — سيسري عند بدء pi في المرة القادمة", - "revokedNoReconnect": "أُلغيت الثقة — ستسري عند بدء pi في المرة القادمة" - }, - "collabAgent": { - "title": "وكيل فرعي", - "errorTitle": "فشلت مهمة الوكيل الفرعي", - "statesLabel": "الوكلاء الفرعيون", - "statusRunning": "قيد التشغيل", - "statusCompleted": "مكتمل", - "statusFailed": "فشل", - "statusPending": "قيد البدء", - "statusInterrupted": "متوقف", - "statusClosed": "مغلق", - "statusNotFound": "غير موجود", - "opSpawn": "بدء تشغيل الوكيل الفرعي", - "opWait": "جلب نتيجة الوكيل الفرعي", - "opClose": "إغلاق الوكيل الفرعي", - "opResume": "استئناف الوكيل الفرعي" - }, - "contextCompaction": { - "compacting": "جارٍ ضغط السياق…", - "compacted": "تم ضغط السياق", - "compactedTokens": "تم ضغط السياق · {before} → {after} رمز", - "failed": "فشل ضغط السياق" - }, - "sessionFailure": { - "category": { - "connection": "مشكلة في الاتصال", - "access": "مشكلة في الوصول", - "limit": "تم بلوغ الحد", - "request": "تم رفض الطلب", - "service": "مشكلة في الخدمة", - "unknown": "مشكلة في الجلسة" - }, - "action": { - "retry": "إعادة المحاولة", - "login": "تسجيل الدخول", - "newSession": "جلسة جديدة" - }, - "recovered": "تم التعافي", - "retryUnavailable": "لا توجد رسالة سابقة لإعادة إرسالها.", - "toggleDetails": "تبديل التفاصيل" - }, - "backgroundTasks": { - "running": "{count, plural, one {مهمة خلفية واحدة قيد التشغيل} two {مهمتا خلفية قيد التشغيل} few {# مهام خلفية قيد التشغيل} other {# مهمة خلفية قيد التشغيل}}", - "settling": "جارٍ مزامنة نتائج الخلفية…", - "settledFallback": "انتهت مهمة الخلفية ({status})", - "cardRunning": "قيد التشغيل في الخلفية", - "cardLaunchedPending": "بدأت مهمة الخلفية", - "cardCompleted": "اكتملت مهمة الخلفية", - "cardFinishedWithStatus": "انتهت مهمة الخلفية ({status})", - "cardResultPending": "لم تصل النتيجة بعد" - }, - "proposedPlan": { - "title": "الخطة المقترحة", - "planning": "جارٍ التخطيط…" - } - }, - "diffPreview": { - "mode": { - "added": "تمت الإضافة", - "deleted": "تم الحذف", - "renamed": "تمت إعادة التسمية", - "modified": "تم التعديل" - }, - "hunkLabel": "مقطع {index}", - "loadingHunk": "جارٍ تحميل hunk...", - "noDiffData": "لا توجد بيانات diff", - "showRemainingLines": "عرض {count} سطر إضافي" - }, - "conversationContextBar": { - "folderTitle": "مجلد العمل", - "branchTitle": "فرع العمل", - "searchFolder": "Search folder...", - "searchBranch": "Search branch...", - "noFolders": "No folders", - "noBranches": "No branches", - "noBranch": "(no branch)", - "chatModeLabel": "وضع الدردشة", - "commit": "Commit", - "push": "Push", - "merge": "Merge", - "toasts": { - "folderChanged": "Switched to {name}", - "openFolderFailed": "Failed to open folder", - "switchedToChatMode": "تم التبديل إلى وضع المحادثة", - "openStashFailed": "Failed to open stash window", - "openMergeFailed": "Failed to open merge window" - } - }, - "cloneDialog": { - "title": "استنساخ مستودع", - "repositoryUrl": "رابط المستودع", - "repositoryUrlPlaceholder": "https://github.com/user/repo.git", - "directory": "المجلد", - "directoryPlaceholder": "اختر مجلد الهدف...", - "browseDirectory": "تصفح المجلد", - "cancel": "إلغاء", - "clone": "استنساخ", - "clonePath": "مسار الاستنساخ: {path}" - }, - "toasts": { - "cloneFailed": "فشل استنساخ المستودع" - } - }, - "ProjectBoot": { - "title": "مُنشئ المشروع", - "tabs": { - "shadcn": "shadcn", - "hyperframes": "HyperFrames" - }, - "hyperframes": { - "title": "مشروع فيديو HyperFrames", - "subtitle": "أنشئ مشروعًا لتحويل HTML إلى فيديو. يمكن لوكيل مساحة العمل بعد ذلك كتابته وعرضه.", - "resolution": "الدقة", - "skillsTitle": "مهارات الوكلاء", - "skillsDesc": "ثبّت مهارات HyperFrames عامًّا (رابط رمزي) للوكلاء المحددين حتى يتمكنوا من إنشاء الفيديو وعرضه.", - "recheck": "إعادة الفحص", - "installedBadge": "مثبّت", - "skillsInstall": "تثبيت / تحديث المهارات", - "skillsInstalling": "جارٍ تثبيت المهارات…", - "skillsInstalled": "تم تثبيت مهارات HyperFrames", - "skillsInstallFailed": "تعذّر تثبيت مهارات HyperFrames" - }, - "config": { - "base": "الأساس", - "style": "النمط", - "baseColor": "اللون الأساسي", - "theme": "السمة", - "chartColor": "لون المخطط", - "iconLibrary": "مكتبة الأيقونات", - "font": "الخط", - "fontHeading": "خط العنوان", - "menuAccent": "تمييز القائمة", - "menuColor": "لون القائمة", - "radius": "نصف القطر", - "template": "القالب", - "createProject": "إنشاء مشروع", - "sectionStyle": "النمط", - "sectionColors": "الألوان", - "sectionTypography": "الخطوط", - "sectionInterface": "الواجهة" - }, - "preview": { - "loading": "جاري تحميل المعاينة..." - }, - "createDialog": { - "title": "إنشاء مشروع", - "projectName": "اسم المشروع", - "projectNamePlaceholder": "my-app", - "frameworkTemplate": "قالب الإطار", - "packageManager": "مدير الحزم", - "saveDirectory": "دليل الحفظ", - "saveDirectoryPlaceholder": "اختر الدليل...", - "browseDirectory": "تصفح", - "projectPath": "سيتم إنشاء المشروع في: {path}", - "advancedOptions": "خيارات متقدمة", - "base": "المكتبة الأساسية", - "enableRtl": "تفعيل دعم RTL", - "enableRtlDescription": "تفعيل دعم التخطيط للغات التي تُكتب من اليمين إلى اليسار (مثل العربية والعبرية)", - "pmChecking": "جارٍ التحقق...", - "pmNotInstalled": "غير مثبت", - "cancel": "إلغاء", - "create": "إنشاء", - "creating": "جاري إنشاء المشروع..." - }, - "toasts": { - "createFailed": "فشل إنشاء المشروع", - "createSuccess": "تم إنشاء المشروع بنجاح", - "openWorkspaceFailed": "تم إنشاء المشروع، ولكن تعذّر فتحه في مساحة العمل" - }, - "errors": { - "directoryExists": "الدليل الهدف موجود بالفعل", - "commandFailed": "فشل أمر إنشاء المشروع." - } - }, - "WebServiceSettings": { - "addressSwitchHint": "التبديل يغيّر فقط العنوان المعروض والمفتوح هنا؛ تستمع الخدمة على جميع الواجهات وتبقى قابلة للوصول من كل عنوان.", - "sectionTitle": "خدمة الويب", - "sectionDescription": "تفعيل للوصول إلى Codeg عن بُعد عبر المتصفح", - "port": "المنفذ", - "status": "الحالة", - "autoStart": "تشغيل تلقائي", - "autoStartHint": "تشغيل خدمة الويب عند بدء Codeg", - "running": "قيد التشغيل", - "stopped": "متوقف", - "processing": "جارٍ المعالجة...", - "start": "تشغيل", - "stop": "إيقاف", - "startFailed": "فشل التشغيل", - "stopFailed": "فشل الإيقاف", - "saveConfigFailed": "فشل حفظ إعدادات خدمة الويب", - "open": "فتح", - "hide": "إخفاء", - "show": "إظهار", - "copy": "نسخ", - "qrcode": "رمز QR", - "qrcodeTitle": "امسح للفتح", - "qrcodeHint": "امسح بهاتفك لفتح Codeg في المتصفح", - "addressLabel": "عنوان الوصول", - "tokenLabel": "رمز الوصول", - "tokenHint": "أدخل هذا الرمز عند الوصول إلى عميل الويب لأول مرة", - "tokenPlaceholder": "اتركه فارغاً للتوليد التلقائي", - "regenerate": "إعادة التوليد", - "stalePortOccupiedTitle": "المنفذ {port} مستخدم من قبل عملية أخرى", - "stalePortUnknownTitle": "حالة المنفذ {port} غير واضحة", - "stalePortHint": "لا يستطيع Codeg الربط قبل تحرير المنفذ. غيّر المنفذ أعلاه، أو أغلق العملية التي تحتفظ به.", - "errors": { - "alreadyRunning": "خدمة الويب قيد التشغيل بالفعل", - "invalidAddress": "تنسيق المضيف أو المنفذ غير صالح", - "portInUse": "المنفذ {port} مستخدم بالفعل. أغلق العملية التي تستخدمه أو اختر منفذاً آخر.", - "permissionDenied": "الصلاحيات غير كافية. استخدم منفذاً أعلى من 1024 أو شغّل التطبيق بصلاحيات أعلى.", - "addressUnavailable": "هذا العنوان غير متاح على هذا الجهاز", - "bindFailed": "فشل ربط العنوان" - } - }, - "DirectoryBrowser": { - "title": "تصفح المجلد", - "pathPlaceholder": "أدخل مسار المجلد...", - "goHome": "الذهاب إلى المجلد الرئيسي", - "navigateUp": "الذهاب إلى المجلد الأعلى", - "select": "اختيار", - "cancel": "إلغاء", - "loading": "جاري التحميل...", - "emptyDirectory": "هذا المجلد فارغ", - "errorLoadingDir": "فشل في تحميل المجلد", - "permissionDenied": "تم رفض الإذن" - }, - "ChatChannelSettings": { - "loading": "جاري التحميل...", - "sectionTitle": "قنوات المحادثة", - "sectionDescription": "تكوين بوتات المراسلة لتلقي إشعارات الأحداث واستعلام نشاط البرمجة.", - "addChannel": "إضافة قناة", - "noChannels": "لم يتم تكوين أي قنوات محادثة بعد.", - "channelName": "الاسم", - "channelNamePlaceholder": "بوت Telegram الخاص بي", - "channelType": "نوع القناة", - "lark": "Lark (Feishu)", - "weixin": "WeChat", - "dailyReport": "التقرير اليومي", - "dailyReportTime": "وقت التقرير", - "nameRequired": "اسم القناة مطلوب.", - "tokenRequired": "الرمز مطلوب.", - "chatIdRequired": "معرف المحادثة مطلوب.", - "topicMode": "وضع مجموعة المواضيع", - "topicModeHint": "يوجه مواضيع منتدى Telegram كجلسات Codeg منفصلة. يجب أن يكون البوت في forum supergroup وأن يملك صلاحية إدارة المواضيع.", - "loadFailed": "فشل في تحميل القنوات.", - "saveFailed": "فشل في حفظ التغييرات.", - "connectSuccess": "تم توصيل القناة.", - "connectFailed": "فشل الاتصال", - "disconnectSuccess": "تم قطع اتصال القناة.", - "disconnectFailed": "فشل قطع الاتصال.", - "testSuccess": "نجح اختبار الاتصال.", - "testFailed": "فشل اختبار الاتصال", - "deleteSuccess": "تم حذف القناة.", - "deleteFailed": "فشل في حذف القناة.", - "deleteConfirmTitle": "حذف القناة", - "deleteConfirmMessage": "سيتم حذف القناة وسجلات رسائلها نهائياً. هل أنت متأكد؟", - "cancel": "إلغاء", - "delete": "حذف", - "create": "إنشاء", - "save": "حفظ", - "channelListTitle": "القنوات المُعدة", - "channelListDescription": "القنوات المفعّلة ستتصل تلقائيًا عند بدء تشغيل الخدمة.", - "editChannel": "تعديل القناة", - "editSuccess": "تم تحديث القناة.", - "tokenPlaceholderKeep": "اتركه فارغاً للاحتفاظ بالقيمة الحالية", - "weixinScanTitle": "مسح رمز QR", - "weixinScanDescription": "افتح WeChat وامسح رمز QR للاتصال.", - "weixinQrcodeExpired": "انتهت صلاحية رمز QR.", - "weixinRefreshQrcode": "تحديث", - "weixinWaitingScan": "في انتظار المسح...", - "weixinPollError": "الاتصال غير مستقر، جاري إعادة المحاولة...", - "weixinReconnectNotice": "بسبب قيود بروتوكول iLink، بعد كل إعادة اتصال يجب عليك إرسال رسالة إلى الروبوت حتى تصبح مشغلات الأحداث فعالة.", - "connect": "اتصال", - "disconnect": "قطع الاتصال", - "test": "اختبار الاتصال", - "tabs": { - "channels": "القنوات", - "commands": "الأوامر", - "events": "الأحداث", - "other": "أخرى" - }, - "commands": { - "title": "الأوامر المدمجة", - "description": "أوامر البوت المتاحة في قنوات المحادثة. في المحادثات الجماعية، يلزم @Bot لمعالجة الرسائل.", - "prefixLabel": "بادئة الأمر", - "prefixDescription": "1-3 أحرف غير أبجدية رقمية لتشغيل أوامر البوت (الافتراضي /).", - "prefixSaved": "تم حفظ بادئة الأمر.", - "prefixSaveFailed": "فشل حفظ بادئة الأمر.", - "prefixInvalid": "يجب أن تكون البادئة 1-3 أحرف غير أبجدية رقمية.", - "save": "حفظ", - "folderDesc": "اختيار مجلد العمل", - "agentDesc": "اختيار وكيل الذكاء الاصطناعي", - "taskDesc": "إنشاء جلسة وتنفيذ المهمة", - "sessionsDesc": "عرض الجلسات النشطة في المجلد", - "resumeDesc": "المحادثات الأخيرة / استئناف جلسة", - "cancelDesc": "إلغاء المهمة الحالية", - "approveDesc": "الموافقة على طلب إذن الوكيل", - "denyDesc": "رفض طلب إذن الوكيل", - "searchDesc": "البحث في المحادثات حسب الكلمة المفتاحية", - "todayDesc": "ملخص نشاط اليوم", - "statusDesc": "حالة اتصال القناة", - "helpDesc": "عرض المساعدة" - }, - "events": { - "title": "إشعارات الأحداث", - "description": "عند تفعيل الأحداث، سيتم إرسالها إلى القناة عند تشغيلها.", - "turnComplete": "اكتمال الدور", - "turnCompleteDesc": "عند انتهاء دور الوكيل", - "error": "خطأ الوكيل", - "errorDesc": "عندما يواجه الوكيل خطأ", - "permissionRequest": "طلب إذن", - "permissionRequestDesc": "عندما يطلب الوكيل إذنًا لتنفيذ إجراء", - "questionRequest": "سؤال من الوكيل", - "questionRequestDesc": "عندما يطرح أحد الوكلاء سؤالاً عليك", - "userPromptSent": "رسالة المستخدم", - "userPromptSentDesc": "عند إرسالك رسالة — يُضمَّن نص الرسالة في الإشعار", - "saved": "تم تحديث فلتر الأحداث.", - "saveFailed": "فشل حفظ فلتر الأحداث.", - "loadFailed": "فشل تحميل الإعدادات.", - "retry": "إعادة المحاولة", - "webhooksTitle": "Webhooks", - "webhooksDescription": "يرسل حمولة JSON عبر POST إلى عنوان واحد أو أكثر عند تشغيل حدث مُفعَّل. ينطبق فلتر الأحداث أعلاه على Webhooks أيضًا.", - "webhookUrlPlaceholder": "https://example.com/webhook", - "addWebhook": "إضافة Webhook", - "removeWebhook": "إزالة Webhook", - "webhookSave": "حفظ", - "webhooksSaved": "تم حفظ Webhooks.", - "webhooksSaveFailed": "فشل حفظ Webhooks.", - "webhookInvalidUrl": "أدخل عناوين http(s) صالحة.", - "docsTitle": "تنسيق الطلب", - "docsMethod": "الطريقة", - "docsContentType": "Content-Type", - "docsNote": "يتم تسليم كل حدث مُفعَّل إلى جميع العناوين. لا يتم تأخير Webhooks؛ ولا يزال فلتر الأحداث أعلاه ساريًا.", - "editWebhook": "تعديل Webhook", - "enableWebhook": "تفعيل Webhook", - "webhookDuplicate": "هذا العنوان مُعد بالفعل.", - "cancel": "إلغاء", - "webhooksEmpty": "لا توجد Webhooks مُعدة بعد.", - "deleteWebhookTitle": "حذف Webhook", - "deleteWebhookMessage": "هل تريد حذف هذا الـ Webhook؟ لن يتم تسليم الأحداث إلى هذا العنوان بعد الآن.", - "delete": "حذف" - }, - "language": { - "title": "لغة الرسائل", - "description": "اللغة المستخدمة لإشعارات الأحداث واستجابات الأوامر والتقارير اليومية المرسلة إلى قنوات الدردشة.", - "saved": "تم حفظ لغة الرسائل.", - "saveFailed": "فشل حفظ لغة الرسائل.", - "en": "الإنجليزية", - "zh-cn": "الصينية المبسطة", - "zh-tw": "الصينية التقليدية", - "ja": "اليابانية", - "ko": "الكورية", - "es": "الإسبانية", - "de": "الألمانية", - "fr": "الفرنسية", - "pt": "البرتغالية", - "ar": "العربية" - } - }, - "ModelProviderSettings": { - "sectionTitle": "مزودو النماذج", - "sectionDescription": "إدارة بيانات اعتماد مزودي API للوكلاء.", - "filterAll": "الكل", - "providerListTitle": "المزودون المُعدّون", - "addProvider": "إضافة مزود", - "editProvider": "تعديل المزود", - "noProviders": "لم يتم تكوين أي مزود نماذج بعد.", - "providerName": "الاسم", - "providerNamePlaceholder": "مثال: OpenAI، Anthropic", - "apiUrl": "عنوان API", - "apiUrlPlaceholder": "https://api.openai.com/v1", - "apiKey": "مفتاح API", - "apiKeyPlaceholder": "sk-...", - "apiKeyKeepCurrent": "اتركه فارغاً للإبقاء على الحالي", - "agentTypes": "أنواع الوكلاء", - "agentTypesRequired": "يجب اختيار نوع وكيل واحد على الأقل.", - "agentType": "نوع الوكيل", - "agentTypeRequired": "نوع الوكيل مطلوب.", - "agentTypeImmutableHint": "لا يمكن تغيير نوع الوكيل بعد الإنشاء.", - "model": "النموذج", - "modelPlaceholderCodex": "gpt-5.6-sol / gpt-5.5", - "modelPlaceholderGemini": "gemini-3-pro-preview", - "claudeMainModel": "النموذج الرئيسي", - "claudeReasoningModel": "نموذج الاستدلال (التفكير)", - "claudeHaikuDefaultModel": "نموذج Haiku الافتراضي", - "claudeSonnetDefaultModel": "نموذج Sonnet الافتراضي", - "claudeOpusDefaultModel": "نموذج Opus الافتراضي", - "claudeCustomModelOption": "معرّف النموذج المخصّص", - "claudeCustomModelOptionName": "اسم النموذج المخصّص", - "claudeCustomModelOptionDescription": "وصف النموذج المخصّص", - "claudeCustomModelOptionHint": "يضيف عنصرًا مخصّصًا واحدًا إلى محدِّد نماذج Claude (مثل نموذج خلف بوابة/وكيل مخصّص). الاسم والوصف اختياريان لأغراض العرض فقط.", - "nameRequired": "اسم المزود مطلوب.", - "apiUrlRequired": "عنوان API مطلوب.", - "apiKeyRequired": "مفتاح API مطلوب.", - "loadFailed": "فشل تحميل المزودين.", - "saveFailed": "فشل حفظ التغييرات.", - "createSuccess": "تم إنشاء المزود.", - "editSuccess": "تم تحديث المزود.", - "deleteSuccess": "تم حذف المزود.", - "deleteConfirmTitle": "حذف المزود", - "deleteConfirmMessage": "سيتم حذف المزود \"{name}\" نهائياً. هل أنت متأكد؟", - "deleteBlockedByAgent": "{agents} يستخدم هذا المزود. يرجى إلغاء الربط قبل الحذف.", - "cancel": "إلغاء", - "delete": "حذف", - "create": "إنشاء", - "save": "حفظ", - "affectedRunningSessions": "{count} جلسة نشطة تحتاج إلى إعادة الاتصال لتطبيق التغيير" - }, - "SkillMatrix": { - "loading": "جارٍ التحميل…", - "searchPlaceholder": "البحث بالاسم أو المعرّف أو الوصف", - "empty": "لا شيء لعرضه.", - "emptySearch": "لا توجد نتائج مطابقة للبحث الحالي.", - "skillColumn": "المهارة", - "selectAll": "تحديد كل المرئي", - "selectSkill": "تحديد {name}", - "everything": { - "label": "إجراء جماعي", - "enable": "تفعيل الكل (المرئي)", - "disable": "تعطيل الكل (المرئي)" - }, - "columnMenu": { - "enableAll": "تفعيل كل المهارات", - "disableAll": "تعطيل كل المهارات" - }, - "rowMenu": { - "label": "إجراءات جماعية لـ {name}", - "enableAll": "تفعيل لكل الوكلاء", - "disableAll": "تعطيل لكل الوكلاء" - }, - "bulk": { - "selected": "{count} محدد", - "targetAll": "كل الوكلاء", - "targetSome": "{count} وكلاء", - "enable": "تفعيل", - "disable": "تعطيل", - "clear": "مسح" - }, - "confirm": { - "disableTitle": "تعطيل هذه الروابط؟", - "disableBody": "سيؤدي هذا إلى إزالة {count} من روابط المهارات التي يديرها codeg. المهارات التي تشغل دليلاً مخصصاً تبقى دون تغيير. يمكنك إعادة تفعيلها في أي وقت.", - "cancel": "إلغاء", - "confirm": "تعطيل" - }, - "toasts": { - "loadFailed": "فشل تحميل حالات المهارات", - "applyFailed": "فشل تطبيق التغييرات", - "enabled": "تم تفعيل {count} رابط", - "disabled": "تم تعطيل {count} رابط", - "enabledPartial": "تم تفعيل {ok}، وفشل {failed}", - "disabledPartial": "تم تعطيل {ok}، وفشل {failed}" - }, - "detail": { - "enableForAgents": "التفعيل للوكلاء", - "preview": "معاينة SKILL.md", - "loadingContent": "جارٍ تحميل المحتوى…" - }, - "copyModeHint": "تم النسخ (غير مرتبط) — أعد التفعيل بعد التحديثات للحصول على أحدث إصدار" - }, - "ExpertsSettings": { - "title": "مهارات الخبراء", - "description": "فعّل سير عمل المهارات المختارة بعناية والمختبرة ميدانيًا لوكلاء البرمجة بالذكاء الاصطناعي. كل خبير هو مهارة مستقلة من مشروع superpowers — يدير codeg النسخة المركزية ويربطها بالوكلاء الذين تختارهم.", - "loading": "جاري تحميل الخبراء…", - "loadingContent": "جاري تحميل المحتوى…", - "emptyExperts": "لا يوجد خبراء متاحون. تحقق من سجلات التطبيق.", - "emptySelection": "اختر خبيرًا لرؤية محتواه وإدارة تفعيله.", - "emptySearch": "لا يوجد خبراء يطابقون البحث الحالي.", - "searchPlaceholder": "ابحث عن الخبراء بالاسم أو المعرّف أو الوصف", - "enableForAgents": "تفعيل للوكلاء", - "noAgents": "لم يتم اكتشاف وكلاء ACP.", - "copyModeWarning": "تم النسخ (غير مرتبط). أعد التفعيل بعد تحديثات codeg للحصول على أحدث إصدار.", - "previewTitle": "معاينة SKILL.md", - "categories": { - "discovery": "الاكتشاف والتصميم", - "planning": "التخطيط", - "execution": "التنفيذ", - "quality": "الجودة والاختبار", - "debugging": "التصحيح", - "review": "المراجعة والدمج", - "meta": "ميتا" - }, - "states": { - "not_linked": "غير مُفعَّل", - "linked_to_codeg": "مُفعَّل", - "linked_elsewhere": "محظور — يوجد رابط آخر", - "blocked_by_real_directory": "محظور — مهارة مخصصة تشغل هذا الاسم", - "broken": "رابط معطوب" - }, - "badges": { - "userModified": "عُدِّل من قبل المستخدم" - }, - "actions": { - "openCentralDir": "فتح المجلد المركزي", - "refresh": "تحديث" - }, - "toasts": { - "loadFailed": "فشل تحميل تفاصيل الخبير", - "enabled": "تم تفعيل الخبير لهذا الوكيل", - "disabled": "تم تعطيل الخبير لهذا الوكيل", - "enableFailed": "فشل تفعيل الخبير", - "disableFailed": "فشل تعطيل الخبير", - "openFolderFailed": "فشل فتح المجلد" - } - }, - "ScienceSettings": { - "title": "مهارات البحث العلمي", - "description": "فعّل مهارات البحث العلمي المنسّقة لوكلاء البرمجة بالذكاء الاصطناعي: توليد الفرضيات، وتصميم التجارب، والإحصاء، والتصور، والتقييم النقدي، والبحث في الأدبيات. يدير codeg نسخة مركزية ويربط كل مهارة بالوكلاء الذين تختارهم.", - "loading": "جارٍ تحميل مهارات البحث العلمي…", - "emptySkills": "لا توجد مهارات بحث علمي متاحة. تحقّق من سجلات التطبيق.", - "searchPlaceholder": "ابحث في مهارات البحث العلمي بالاسم أو المعرّف أو الوصف", - "categories": { - "ideation": "توليد الأفكار", - "design": "تصميم الدراسة", - "analysis": "التحليل", - "visualization": "التصور", - "evaluation": "التقييم", - "literature": "الأدبيات" - }, - "states": { - "not_linked": "غير مُفعَّل", - "linked_to_codeg": "مُفعَّل", - "linked_elsewhere": "محظور — يوجد رابط آخر", - "blocked_by_real_directory": "محظور — مهارة مخصصة تشغل هذا الاسم", - "broken": "رابط معطوب" - }, - "badges": { - "userModified": "عُدِّل من قبل المستخدم", - "needsKey": "يتطلب مفتاحًا", - "needsSetup": "قد يتطلب إعدادًا" - }, - "actions": { - "openCentralDir": "فتح المجلد المركزي", - "refresh": "تحديث" - }, - "toasts": { - "openFolderFailed": "فشل فتح المجلد" - } - }, - "OfficeToolsSettings": { - "title": "أدوات Office", - "description": "إدارة مهارات OfficeCLI لإنشاء ملفات Excel وWord وPowerPoint. قم بتثبيت OfficeCLI ومزامنة المهارات وتفعيلها لكل وكيل.", - "loadingContent": "جارٍ تحميل المحتوى…", - "emptySkills": "لا توجد مهارات متاحة. قم بتثبيت OfficeCLI ومزامنة المهارات.", - "emptySelection": "اختر مهارة لعرض محتواها وإدارة التفعيل.", - "emptySearch": "لا توجد مهارات مطابقة.", - "searchPlaceholder": "البحث بالاسم أو المعرف أو الوصف", - "enableForAgents": "تفعيل للوكلاء", - "noAgents": "لم يتم اكتشاف وكلاء ACP.", - "installFirst": "قم بتثبيت OfficeCLI أولاً لتفعيل المهارات.", - "syncFirst": "قم بمزامنة المهارات أولاً لتحميل المحتوى.", - "noContent": "لا يوجد محتوى متاح.", - "copyModeWarning": "تم النسخ (بدون ربط). أعد المزامنة للحصول على أحدث إصدار.", - "previewTitle": "معاينة SKILL.md", - "detection": { - "installed": "مثبّت", - "notInstalled": "غير مثبّت", - "notRunnable": "مثبّت لكن لا يعمل", - "installHint": "قم بتثبيت OfficeCLI لتفعيل مهارات إنشاء مستندات Office لوكلاء الذكاء الاصطناعي.", - "install": "تثبيت", - "uninstall": "إلغاء التثبيت", - "syncSkills": "مزامنة المهارات" - }, - "categories": { - "general": "عام", - "presentations": "عروض تقديمية", - "documents": "مستندات", - "spreadsheets": "جداول بيانات" - }, - "states": { - "not_linked": "غير مفعّل", - "linked_to_codeg": "مفعّل", - "linked_elsewhere": "محظور — يوجد رابط آخر", - "blocked_by_real_directory": "محظور — مهارة مخصصة تشغل هذا الاسم", - "broken": "رابط معطل" - }, - "badges": { - "notSynced": "غير متزامن" - }, - "actions": { - "refresh": "تحديث" - }, - "toasts": { - "loadFailed": "فشل تحميل تفاصيل المهارة", - "enabled": "تم تفعيل المهارة لهذا الوكيل", - "disabled": "تم تعطيل المهارة لهذا الوكيل", - "enableFailed": "فشل تفعيل المهارة", - "disableFailed": "فشل تعطيل المهارة", - "installSuccess": "تم تثبيت OfficeCLI بنجاح", - "installFailed": "فشل تثبيت OfficeCLI", - "uninstallSuccess": "تم إلغاء تثبيت OfficeCLI", - "uninstallFailed": "فشل إلغاء تثبيت OfficeCLI", - "syncSuccess": "تمت مزامنة {synced} مهارة", - "syncPartial": "تمت مزامنة {synced}، فشلت {errors}", - "syncFailed": "فشل مزامنة المهارات" - }, - "autoPreviewLabel": "فتح المعاينة تلقائيًا", - "autoPreviewHint": "عندما ينشئ وكيل ملف Word أو Excel أو PowerPoint أو يعدّله، افتح معاينته المباشرة تلقائيًا." - }, - "SkillPacksSettings": { - "title": "حزم المهارات", - "description": "حزم مهارات منسّقة يديرها codeg مركزيًا ويربطها بوكلاء الذكاء الاصطناعي لديك — خبراء البرمجة، والبحث العلمي، وأدوات مستندات المكتب. فعّلها لكل وكيل أدناه.", - "tabs": { - "experts": "الخبراء", - "science": "البحث العلمي", - "office": "أدوات المكتب", - "custom": "مخصّصة" - }, - "actions": { - "openCentralDir": "فتح المجلد المركزي", - "refresh": "تحديث" - }, - "toasts": { - "openFolderFailed": "فشل فتح المجلد" - } - }, - "QuickMessagesSettings": { - "title": "رسائل سريعة", - "description": "إدارة مقتطفات الرسائل القابلة لإعادة الاستخدام. اسحب لإعادة الترتيب.", - "loading": "جارٍ تحميل الرسائل السريعة…", - "emptyList": "لا توجد رسائل سريعة بعد. انقر على \"جديد\" لإنشاء واحدة.", - "emptySelection": "اختر رسالة سريعة للتعديل.", - "searchPlaceholder": "ابحث حسب العنوان أو المحتوى", - "untitled": "بدون عنوان", - "actions": { - "new": "جديد", - "save": "حفظ", - "delete": "حذف", - "dragSort": "اسحب لإعادة الترتيب", - "dragSortMessage": "اسحب لإعادة ترتيب الرسالة السريعة: {name}" - }, - "fields": { - "title": "العنوان", - "titlePlaceholder": "أعطِ هذه الرسالة عنوانًا قصيرًا", - "content": "المحتوى", - "contentPlaceholder": "اكتب محتوى الرسالة هنا" - }, - "confirmDelete": { - "title": "حذف الرسالة السريعة؟", - "message": "سيؤدي ذلك إلى حذف \"{name}\" نهائيًا. هل أنت متأكد؟", - "cancel": "إلغاء", - "confirm": "حذف" - }, - "toasts": { - "loadFailed": "فشل تحميل الرسائل السريعة", - "createFailed": "فشل إنشاء الرسالة السريعة", - "saveFailed": "فشل حفظ الرسالة السريعة", - "deleteFailed": "فشل حذف الرسالة السريعة", - "saveOrderFailed": "فشل حفظ الترتيب", - "created": "تم إنشاء الرسالة السريعة", - "saved": "تم حفظ الرسالة السريعة", - "deleted": "تم حذف الرسالة السريعة" - } - }, - "Pet": { - "badge": { - "running": "{count} قيد التشغيل", - "waiting": "{count} في انتظار الموافقة", - "error": "{count} بها خطأ" - }, - "panel": { - "title": "الجلسات النشطة", - "empty": "لا توجد جلسات نشطة", - "emptyHint": "تظهر هنا الوكلاء قيد التشغيل وتلك التي تحتاج إليك.", - "statusRunning": "قيد التشغيل", - "statusWaiting": "في الانتظار", - "statusError": "خطأ", - "subAgentOf": "وكيل فرعي لـ" - }, - "menu": { - "scale": "الحجم", - "openManager": "إدارة الحيوانات الأليفة", - "close": "إغلاق" - }, - "loadError": "فشل تحميل الحيوان الأليف", - "missingPetIdParam": "لم يتم اختيار حيوان أليف", - "summonButton": "حيوان أليف", - "manager": { - "title": "حيوانات سطح المكتب", - "description": "رفقاء عائمون لسطح المكتب باستخدام صفائح سبرايت متوافقة مع Codex.", - "addPet": "إضافة حيوان", - "importFromCodex": "استيراد من Codex", - "noPets": "لا يوجد حيوان أليف. أضف واحدًا أو استورد من Codex.", - "setActive": "تفعيل", - "active": "نشط", - "edit": "تعديل", - "delete": "حذف", - "deleteConfirm": "حذف الحيوان «{name}»؟ سيُحذف من القرص.", - "summon": "استدعاء نافذة الحيوان", - "openCodexHelp": "يجب أن توجد حيوانات Codex داخل ~/.codex/pets/. لم يُعثر على شيء.", - "specRequirement": "يجب أن يكون السبرايت بعرض 1536 بكسل وارتفاع من مضاعفات 208 بكسل (مثل 1872 أو 2288)، بصيغة PNG أو WebP مع شفافية.", - "form": { - "id": "معرف الحيوان", - "idHelp": "حروف صغيرة، أرقام، '-' و '_' فقط. حد أقصى 64 حرفًا.", - "displayName": "اسم العرض", - "description": "الوصف (اختياري)", - "spritesheet": "صفيحة السبرايت", - "chooseFile": "اختر ملفًا", - "replaceFile": "استبدال السبرايت", - "saveCreate": "إضافة الحيوان", - "saveUpdate": "حفظ التغييرات", - "cancel": "إلغاء" - }, - "errors": { - "missingId": "المعرف مطلوب", - "missingName": "الاسم مطلوب", - "missingSpritesheet": "السبرايت مطلوب", - "addFailed": "فشل الإضافة", - "updateFailed": "فشل التحديث", - "deleteFailed": "فشل الحذف", - "loadFailed": "فشل تحميل قائمة الحيوانات", - "setActiveFailed": "فشل تعيين الحيوان النشط", - "summonFailed": "فشل فتح نافذة الحيوان" - } - }, - "import": { - "title": "استيراد من Codex", - "subtitle": "الحيوانات الأليفة المتاحة ضمن ~/.codex/pets/.", - "selectAll": "تحديد الكل", - "alreadyImported": "تم استيراده مسبقًا", - "renameOnConflict": "تسمية المتعارضين بإلحاق -imported", - "import": "استيراد المحدد", - "noneFound": "لا توجد حيوانات Codex قابلة للاستيراد.", - "imported": "تم الاستيراد بنجاح", - "failed": "فشل الاستيراد", - "close": "إغلاق" - }, - "marketplace": { - "openMarketplace": "متجر الحيوانات الأليفة", - "title": "متجر الحيوانات الأليفة", - "search": "ابحث عن حيوان أليف", - "kindFilter": { - "all": "الكل", - "object": "كائن", - "animal": "حيوان", - "person": "شخصية", - "creature": "مخلوق" - }, - "sortFilter": { - "latest": "الأحدث", - "popular": "الأكثر شيوعاً", - "views": "الأكثر مشاهدة" - }, - "refresh": "تحديث", - "install": "تثبيت", - "installing": "جاري التثبيت", - "reinstall": "إعادة التثبيت", - "reinstallConfirm": "هل تريد استبدال الحيوان الأليف المحلي \"{name}\"؟ ستُستبدل البيانات الحالية.", - "cancel": "إلغاء", - "stats": { - "views": "المشاهدات", - "downloads": "التنزيلات", - "likes": "الإعجابات" - }, - "actions": { - "idle": "خامل", - "running_right": "ركض يمين", - "running_left": "ركض يسار", - "waving": "تلويح", - "jumping": "قفز", - "failed": "فشل", - "waiting": "انتظار", - "running": "ركض", - "review": "مراجعة" - }, - "page": "صفحة {page} من {total}", - "prev": "السابق", - "next": "التالي", - "empty": "لا يوجد حيوان أليف مطابق.", - "successInstalled": "تم تثبيت \"{name}\"", - "errors": { - "loadFailed": "تعذّر تحميل المتجر", - "installFailed": "فشل التثبيت", - "alreadyInstalled": "هذا الحيوان موجود بالفعل" - } - } - }, - "RemoteWorkspace": { - "openRemoteWorkspace": "Open remote workspace", - "manage": "Manage remote workspace", - "manageTitle": "Remote Workspace connections", - "empty": "No remote connections", - "searchPlaceholder": "Search remote workspaces", - "orderFailed": "Failed to save remote workspace order", - "dragSort": "Drag to sort", - "dragSortConnection": "Drag to sort {name}", - "newConnection": "New connection", - "loading": "Loading", - "loadingConnection": "Loading remote connection", - "name": "Name", - "baseUrl": "Service URL", - "token": "Access token", - "save": "Save", - "delete": "Delete", - "confirmDelete": { - "title": "Delete remote connection?", - "message": "This will remove \"{name}\" from this device. This action cannot be undone.", - "cancel": "Cancel", - "confirm": "Delete" - }, - "saved": "Remote connection saved.", - "deleted": "Remote connection deleted.", - "loadFailed": "Failed to load remote connections", - "saveFailed": "Failed to save remote connection", - "deleteFailed": "Failed to delete remote connection", - "openFailed": "Failed to open remote workspace", - "connectionLoadFailed": "Failed to load remote connection: {message}", - "connectionExpired": "Remote connection \"{name}\" is expired. Update its token and reload this window." - }, - "ServerFileBrowser": { - "title": "اختر ملفًا من الخادم", - "pathPlaceholder": "أدخل مسار الدليل...", - "goHome": "اذهب إلى المجلد الرئيسي", - "navigateUp": "اذهب إلى المجلد الأعلى", - "select": "اختر", - "cancel": "إلغاء", - "loading": "جارٍ التحميل...", - "emptyDirectory": "هذا المجلد فارغ", - "errorLoadingDir": "فشل تحميل المجلد", - "selectedCount": "{count} محدد" - }, - "BackupSettings": { - "title": "النسخ الاحتياطي والاستعادة", - "description": "صدّر نسخة احتياطية محمولة من بيانات codeg، أو استعد من نسخة.", - "tabs": { - "backup": "نسخ احتياطي", - "restore": "استعادة" - }, - "export": { - "includeExternal": "تضمين محتوى المحادثات", - "includeExternalHint": "يؤرشف أيضًا سجلات محادثات أدوات CLI (Claude وCodex وGemini …). يزيد الحجم.", - "passphrase": "عبارة المرور (اختياري)", - "passphrasePlaceholder": "اتركها فارغة للحصول على أرشيف غير مشفّر", - "passphraseConfirm": "تأكيد عبارة المرور", - "passphraseMismatch": "عبارتا المرور غير متطابقتين.", - "noPassphraseWarning": "ستحتوي هذه النسخة على أسرار (مفاتيح API والرموز) بنص واضح. احفظها في مكان آمن.", - "passphraseLossWarning": "مشفّرة بعبارة المرور هذه. إذا فقدتها، فلن يمكن استعادة النسخة الاحتياطية.", - "button": "تصدير النسخة الاحتياطية", - "inProgress": "جارٍ إنشاء النسخة الاحتياطية…", - "success": "تم إنشاء النسخة الاحتياطية.", - "started": "بدأ تنزيل النسخة الاحتياطية." - }, - "restore": { - "selectFile": "اختر ملف النسخة الاحتياطية", - "passphrasePrompt": "هذه النسخة مشفّرة. أدخل عبارة المرور الخاصة بها.", - "unlock": "فتح القفل", - "preview": { - "title": "تفاصيل النسخة الاحتياطية", - "encrypted": "مشفّرة", - "compatible": "متوافقة", - "incompatible": "غير متوافقة", - "createdAt": "أُنشئت: {value}", - "appVersion": "إصدار التطبيق: {value}", - "incompatibleHint": "أُنشئت هذه النسخة بإصدار أحدث من codeg ولا يمكن استعادتها." - }, - "replaceWarning": "تستبدل الاستعادة جميع بيانات codeg الحالية (قاعدة البيانات والملفات المرفوعة). تُلتقط بياناتك الحالية كلقطة أولًا حتى يمكن استرجاعها.", - "keyringNote": "تُخزَّن رموز GitHub/الدردشة لتطبيق سطح المكتب في سلسلة مفاتيح النظام ولا تُضمَّن؛ أعد إدخالها بعد الاستعادة.", - "button": "استعادة", - "staging": "جارٍ تجهيز الاستعادة…", - "staged": "تم تجهيز الاستعادة. جارٍ إعادة التشغيل…", - "restarting": "تم تجهيز الاستعادة. جارٍ إعادة تشغيل الخادم…", - "restartTimeout": "لم يعد الخادم في الوقت المحدد. أعد تحميل الصفحة بعد تشغيله.", - "externalSideLocation": "تمت استعادة سجلات المحادثات إلى {path}", - "confirmTitle": "استبدال جميع البيانات؟", - "confirmBody": "سيؤدي ذلك إلى استبدال قاعدة بيانات codeg والملفات المرفوعة الحالية بالنسخة الاحتياطية ثم إعادة التشغيل. تُلتقط بياناتك الحالية كلقطة أولًا.", - "cancel": "إلغاء", - "confirmAction": "استبدال وإعادة تشغيل", - "external": { - "title": "محتوى المحادثات", - "hint": "تتضمن هذه النسخة سجلات محادثات أدوات CLI. اختر مكان استعادتها.", - "modeSkip": "عدم الاستعادة", - "modeSide": "الاستعادة إلى مجلد جانبي آمن", - "modeOriginal": "الاستعادة إلى المواقع الأصلية لأدوات CLI", - "forceOverwrite": "الكتابة فوق الملفات الموجودة", - "forceOverwriteHint": "استبدال الملفات الموجودة بالفعل في مجلدات أدوات CLI.", - "scanning": "جارٍ التحقق من التعارضات…", - "noConflicts": "لن تتم الكتابة فوق أي ملف موجود.", - "conflictCount": "سيتأثر {count} من الملفات الموجودة.", - "conflictSkipNote": "تُحفظ الملفات الموجودة (تُتخطى) ما لم تفعّل الكتابة فوقها." - }, - "restartFailed": "تم تجهيز الاستعادة، لكن تعذّر إعادة تشغيل الخادم. أعد تشغيله يدويًا لتطبيقها." - }, - "remoteUnsupported": "يعمل النسخ الاحتياطي والاستعادة على بيانات الجهاز الذي يشغّل codeg. أنت متصل بمساحة عمل بعيدة — أدِر نسخها الاحتياطية من ذلك الخادم مباشرة." - }, - "backup": { - "restore": { - "error": { - "badPassphrase": "عبارة المرور غير صحيحة أو النسخة الاحتياطية تالفة.", - "corrupted": "أرشيف النسخة الاحتياطية تالف.", - "unknownFormat": "هذا الملف ليس نسخة احتياطية معروفة من codeg.", - "newerVersion": "أُنشئت هذه النسخة بواسطة codeg {backupVersion}، وهي أحدث من هذا الإصدار ({appVersion}).", - "alreadyPending": "توجد استعادة مُجهّزة بالفعل. أعد التشغيل لتطبيقها قبل تجهيز أخرى." - } - }, - "error": { - "diskSpace": "لا توجد مساحة قرص كافية لإكمال العملية.", - "cancelled": "تم إلغاء العملية." - } - }, - "WebConnection": { - "disconnectedTitle": "انقطع الاتصال", - "reconnectingDescription": "تتم محاولة إعادة الاتصال بالخادم. عادةً ما يُستعاد الاتصال تلقائيًا خلال ثوانٍ قليلة.", - "reconnectNow": "إعادة الاتصال الآن", - "sessionExpiredTitle": "انتهت الجلسة", - "sessionExpiredDescription": "لم تعد جلستك صالحة. يُرجى تسجيل الدخول مرة أخرى للمتابعة.", - "goToLogin": "الانتقال إلى تسجيل الدخول" - }, - "LiveFeedback": { - "placeholder": "أرسل ملاحظة إلى {agent} أثناء عمله…", - "agentFallback": "الوكيل", - "ariaLabel": "ملاحظة مباشرة", - "dialogTitle": "ملاحظات مباشرة", - "dialogDescription": "أرسل ملاحظة إلى الوكيل أثناء عمله. سيقرأها في فحصه التالي دون مقاطعة الخطوة الحالية.", - "dialogDescriptionInstant": "أرسل ملاحظة إلى الوكيل أثناء عمله. تُدرج الملاحظة فورًا في الدور الحالي — يراها الوكيل على الفور.", - "channelDowngraded": "الإدراج الفوري غير متاح في هذه الجلسة — حُفظت ملاحظتك ليقرأها الوكيل عند فحصه التالي.", - "send": "إرسال", - "cancel": "إلغاء", - "pending": "في الانتظار", - "delivered": "تم الاستلام", - "turnEndedUnread": "أنهى الوكيل الجولة قبل قراءة ملاحظاتك.", - "sendAsMessage": "إرسال كرسالة", - "dismiss": "تجاهل", - "turnEndedResent": "انتهت الجولة — تم الإرسال كرسالة جديدة بدلاً من ذلك.", - "turnEnded": "انتهت الجولة بالفعل.", - "submitFailed": "تعذّر إرسال ملاحظتك" - }, - "AgentToolsSettings": { - "title": "أدوات داخل المحادثة", - "description": "أدوات إضافية يمنحها codeg للوكيل داخل المحادثة. تُحقن عند بدء تشغيل الوكيل، لذا يسري أي تغيير على الوكلاء الذين يبدأون بعده.", - "feedbackLabel": "ملاحظات مباشرة", - "feedbackHint": "أرسل ملاحظات وتصحيحات إلى الوكيل أثناء عمله. إذا كان الوكيل يدعم الإدراج الفوري، تُدرج ملاحظتك فورًا في الدور الجاري؛ وإلا يحصل الوكيل على أداة للاطلاع على ملاحظاتك — وهؤلاء الوكلاء عادةً لا يتحققون منها إلا إذا ذكرت ذلك في الموجّه، مثلًا أضف \"تحقق من ملاحظاتي المباشرة بانتظام\" إلى رسالتك.", - "questionLabel": "سؤال المستخدم", - "questionHint": "يسمح للوكلاء بالتوقّف وطرح سؤال متعدّد الخيارات يظهر فوق مربّع إدخال المحادثة. ينتظر الوكيل حتى تجيب (أو تتخطّى).", - "sessionInfoLabel": "الحصول على معلومات الجلسة", - "sessionInfoHint": "يتيح للوكلاء البحث عن جلسة تشير إليها في رسالتك (شارة جلسة) لقراءة عنوانها والوكيل والحالة ومساحة العمل واستهلاك الرموز وأحدث الرسائل.", - "automationsLabel": "إنشاء الأتمتة", - "automationsHint": "يحفظ المحادثة كأتمتة تعمل وفق جدول زمني. مُعطّل افتراضيًا — إذ تبدأ بعد ذلك تشغيل الوكلاء من تلقاء نفسها.", - "workTasksLabel": "إنشاء مهام قيد الانتظار", - "workTasksHint": "يضيف بطاقة إلى لوحة المهام انطلاقًا من المحادثة. مُعطّل افتراضيًا — لأنه يكتب حالة التطبيق.", - "save": "حفظ", - "saving": "جارٍ الحفظ…", - "saved": "تم حفظ إعدادات الأدوات", - "saveFailed": "تعذّر حفظ إعدادات الأدوات", - "loadFailed": "فشل التحميل: {detail}" - }, - "NotificationSoundSettings": { - "title": "أصوات التنبيه", - "description": "تشغيل صوت قصير عند وقوع حدث للوكيل. هي نفس الأحداث التي تُرسل إلى قنوات المحادثة، وهذا الإعداد يخص هذا الجهاز فقط.", - "enableHint": "معطّل افتراضيًا. تُشغَّل الأصوات في نافذة مساحة العمل بهذا المتصفح أو التطبيق فقط.", - "volume": "مستوى الصوت", - "preview": "استماع", - "previewEvent": "استماع لصوت {event}", - "onlyWhenUnfocused": "فقط عندما تكون النافذة غير نشطة", - "onlyWhenUnfocusedHint": "يبقى صامتًا أثناء استخدامك لـ Codeg.", - "eventsTitle": "الأحداث", - "eventsHint": "اختر نغمة لكل حدث، أو «صامت» لتجاهله. إذا تكرر الحدث نفسه خلال ثوانٍ قليلة فسيُشغَّل مرة واحدة فقط.", - "toneNone": "صامت", - "toneChime": "رنين", - "toneDing": "جرس", - "toneBlip": "نبضة", - "tonePop": "طقّة", - "toneAlert": "تنبيه", - "toneDescend": "نغمة هابطة" - }, - "LogsSettings": { - "loading": "جارٍ التحميل…", - "sectionTitle": "سجلات التشغيل", - "sectionDescription": "عرض وتكوين سجلات تشخيص التطبيق. تُكتب السجلات في ملفات محلية وتُحفظ في الذاكرة للعرض المباشر.", - "captureTitle": "مستوى السجل", - "captureDescription": "يتحكم في مقدار التفاصيل الملتقطة. المستويات الأعلى (Debug، Trace) تسجل المزيد لكنها تنتج سجلات أكبر. «إيقاف» يعطّل التسجيل.", - "captureLabel": "مستوى الالتقاط", - "levels": { - "off": "إيقاف", - "error": "خطأ", - "warn": "تحذير", - "info": "معلومات", - "debug": "تصحيح", - "trace": "تتبع" - }, - "viewerTitle": "السجلات الأخيرة", - "viewerDescription": "عرض مباشر لأحدث السجلات. قم بالتصفية حسب المستوى أو ابحث في النص.", - "searchPlaceholder": "ابحث في الرسالة أو المصدر…", - "viewLevels": { - "all": "كل المستويات", - "error": "خطأ فأعلى", - "warn": "تحذير فأعلى", - "info": "معلومات فأعلى", - "debug": "تصحيح فأعلى", - "trace": "تتبع فأعلى" - }, - "pause": "إيقاف مؤقت", - "resume": "مباشر", - "refresh": "تحديث", - "clear": "مسح", - "openFolder": "فتح المجلد", - "shownCount": "{shown} / {total} معروض", - "empty": "لا توجد سجلات للعرض.", - "levelSaveFailed": "فشل حفظ مستوى السجل", - "openFolderFailed": "فشل فتح مجلد السجلات", - "downloadFailed": "فشل تنزيل ملف السجل", - "filesTitle": "ملفات السجل", - "filesDescription": "نزّل ملفات السجل الكاملة من القرص للاطلاع على السجل خارج المخزن المباشر.", - "filesEmpty": "لا توجد ملفات سجل بعد.", - "download": "تنزيل", - "downloadTruncated": "الملف كبير، تم تنزيل أحدث {size}. الملف الكامل موجود في دليل السجلات.", - "captureEnvLocked": "يتم التحكم في مستوى السجل عبر متغير البيئة RUST_LOG / CODEG_LOG؛ غيّره هناك ليصبح ساريًا.", - "targetsTitle": "تجاوزات حسب الوحدة", - "targetsDescription": "عيّن مستوى مختلفًا لوحدات محددة (مثل codeg_lib::acp) دون تغيير المستوى العام.", - "targetsAdd": "إضافة", - "targetsRemove": "إزالة التجاوز", - "toggleDetails": "تبديل التفاصيل" - }, - "Automations": { - "title": "الأتمتة", - "new": "أتمتة جديدة", - "empty": "لا توجد أتمتة بعد", - "emptyHint": "أنشئ واحدة لتشغيل مهمة الوكيل وفق جدول أو يدويًا.", - "name": "الاسم", - "namePlaceholder": "مثال: مراجعة PR الليلية", - "prompt": "الموجّه", - "promptPlaceholder": "ماذا يجب أن يفعل الوكيل؟", - "agent": "الوكيل", - "folder": "مجلد مساحة العمل", - "folderPlaceholder": "اختر مجلدًا", - "isolation": "العزل", - "isolationWorktree": "worktree جديد لكل تشغيل", - "isolationShared": "التشغيل داخل المجلد", - "isolationSharedCaveat": "تستخدم عمليات التشغيل شجرة عمل هذا المجلد مباشرةً، وقد تتعارض مع تغييراتك غير المُلتزَم بها. فعِّل خيار شجرة العمل لعزل كل عملية تشغيل.", - "trigger": "المُشغِّل", - "triggerSchedule": "وفق جدول", - "triggerManual": "يدوي فقط", - "cron": "الجدولة (cron)", - "cronPlaceholder": "0 9 * * 1-5", - "timezone": "المنطقة الزمنية", - "nextRun": "التشغيل التالي", - "branch": "الفرع", - "branchOptional": "الفرع (اختياري)", - "enabled": "مُفعّل", - "save": "حفظ", - "cancel": "إلغاء", - "edit": "تعديل", - "delete": "حذف", - "runNow": "تشغيل الآن", - "cancelRun": "إلغاء التشغيل", - "runHistory": "سجل التشغيل", - "noRuns": "لا توجد عمليات تشغيل بعد", - "allFolders": "كل المجلدات", - "filterAll": "الكل", - "noMatches": "لا توجد أتمتة مطابقة", - "viewConversation": "عرض المحادثة", - "lastRun": "آخر تشغيل", - "never": "أبدًا", - "running": "قيد التشغيل", - "deleteTitle": "حذف الأتمتة؟", - "deleteDescription": "يؤدي هذا إلى إزالة الأتمتة وجدولها. يُحتفظ بسجل التشغيل.", - "statusRunning": "قيد التشغيل", - "statusSucceeded": "نجحت", - "statusFailed": "فشلت", - "statusCancelled": "أُلغيت", - "statusSkipped": "تم تخطيها", - "errorName": "الاسم مطلوب", - "errorPrompt": "الموجّه مطلوب", - "errorCron": "تتطلب الأتمتة المجدولة تعبير cron", - "errorFolder": "اختر مجلد مساحة العمل", - "presetHourly": "كل ساعة", - "presetDaily": "يوميًا 9 صباحًا", - "presetWeekdays": "أيام العمل 9 صباحًا", - "presetCustom": "مخصص", - "probing": "جارٍ تحميل الخيارات…", - "retry": "إعادة المحاولة", - "configNone": "لا توجد خيارات قابلة للضبط لهذا الوكيل", - "inherit": "افتراضي الوكيل", - "mode": "الوضع", - "config": "الإعدادات", - "branchPlaceholder": "(الفرع الافتراضي)", - "selectHint": "اختر أتمتة لعرض التفاصيل", - "refresh": "تحديث", - "onboardTitle": "أتمتة مهام الوكيل الروتينية", - "onboardHint": "اجدول وكيلًا لمراجعة الشيفرة أو تحديث الاعتماديات أو فرز المشكلات، وفق جدول زمني أو عند الطلب.", - "headerSubtitle": "مهام الوكيل المجدولة وعند الطلب", - "startFromTemplate": "ابدأ من قالب", - "blankTitle": "أتمتة فارغة", - "blankDesc": "اضبط مهمة وكيل من البداية.", - "backToTemplates": "القوالب", - "sectionSchedule": "الجدولة والهدف", - "sectionTarget": "الهدف", - "sectionAction": "الإجراء", - "actionLaunchSession": "تشغيل جلسة", - "actionEnqueueTask": "إضافة مهمة إلى قائمة الانتظار", - "actionEnqueueTaskHint": "عند كل تشغيل تُضاف مهمة قيد الانتظار تحمل اسم هذه الأتمتة إلى المهام قيد الانتظار للمجلد، وينفذها محرك المهام وفق إعدادات اللوحة.", - "sectionPrompt": "الموجّه", - "nextIn": "التالي خلال {rel}", - "manual": "يدوي", - "schedEveryMinutes": "كل {n} دقيقة", - "schedHourly": "كل ساعة", - "schedDaily": "يوميًا في {time}", - "schedWeekdays": "أيام العمل في {time}", - "schedWeekly": "كل {day} في {time}", - "schedMonthly": "شهريًا في اليوم {day} عند {time}", - "dow0": "الأحد", - "dow1": "الاثنين", - "dow2": "الثلاثاء", - "dow3": "الأربعاء", - "dow4": "الخميس", - "dow5": "الجمعة", - "dow6": "السبت", - "tplCodeReviewTitle": "مراجعة الشيفرة", - "tplCodeReviewDesc": "يراجع التغييرات الأخيرة بحثًا عن الأخطاء والانحدارات ومشكلات الجودة.", - "tplDependencyUpdatesTitle": "تحديث الاعتماديات", - "tplDependencyUpdatesDesc": "يعثر على الاعتماديات القديمة ويقترح ترقيات آمنة.", - "tplTestCoverageTitle": "تغطية الاختبارات", - "tplTestCoverageDesc": "يعثر على مسارات الشيفرة غير المختبرة ويضيف الاختبارات الناقصة.", - "tplTodoSweepTitle": "تجميع مهام TODO", - "tplTodoSweepDesc": "يجمع تعليقات TODO وFIXME ويفرزها حسب الأولوية.", - "tplCiTriageTitle": "فرز CI", - "tplCiTriageDesc": "يحقق في الفحوصات الفاشلة الأخيرة ويقترح إصلاحات.", - "tplReleaseNotesTitle": "ملاحظات الإصدار", - "tplReleaseNotesDesc": "يلخّص التغييرات منذ الإصدار الأخير في سجل تغييرات.", - "tplSecurityAuditTitle": "تدقيق الأمان", - "tplSecurityAuditDesc": "يفحص الثغرات والأنماط الخطرة ثم يبلّغ عن النتائج.", - "enable": "تفعيل", - "disable": "تعطيل", - "moreActions": "إجراءات إضافية", - "statusDisabled": "معطّلة", - "cronBuilderTitle": "منشئ الجدولة", - "cronFreqLabel": "التكرار", - "cronFreqMinutes": "كل N دقيقة", - "cronFreqHourly": "كل ساعة", - "cronFreqDaily": "يوميًا", - "cronFreqWeekdays": "أيام الأسبوع", - "cronFreqWeekly": "أسبوعيًا", - "cronFreqMonthly": "شهريًا", - "cronFreqCustom": "مخصص", - "cronEveryLabel": "الفاصل (دقائق)", - "cronTimeLabel": "الوقت", - "cronHourLabel": "الساعة", - "cronMinuteLabel": "الدقيقة", - "cronDowLabel": "يوم الأسبوع", - "cronDomLabel": "يوم الشهر", - "cronApply": "تطبيق", - "cronPreviewLabel": "معاينة", - "cronOpenBuilder": "فتح منشئ الجدولة", - "branchDefault": "الفرع الافتراضي", - "branchUseCustom": "استخدام \"{query}\"", - "branchLocal": "محلي", - "branchRemote": "بعيد", - "branchSearchPlaceholder": "بحث في الفروع…", - "branchNone": "لا توجد فروع" - }, - "Tasks": { - "title": "المهام قيد الانتظار", - "new": "مهمة جديدة", - "empty": "لا توجد مهام بعد", - "emptyHint": "أضف مهمة ثم شغّلها — يعمل الوكيل في worktree معزول، وتراجع النتيجة وتدمجها.", - "emptyColTodo": "لا توجد مهام قيد الانتظار بعد", - "emptyColInProgress": "لا توجد مهام قيد التنفيذ", - "emptyColAttention": "لا توجد مهام بانتظارك", - "emptyColDone": "لا توجد مهام مكتملة بعد", - "allFolders": "كل المجلدات", - "showCanceled": "إظهار الملغاة", - "showArchived": "إظهار المؤرشفة", - "filter": "تصفية", - "viewSwitchToBoard": "التبديل إلى عرض اللوحة", - "viewSwitchToList": "التبديل إلى عرض القائمة", - "statusFilter": "الحالة", - "statusFilterAll": "كل الحالات", - "listEmpty": "لا توجد مهام مطابقة لعوامل التصفية الحالية", - "listColStatus": "الحالة", - "listColTask": "المهمة", - "listColLocation": "الموقع", - "listColChanges": "التغييرات", - "listColUpdated": "آخر تحديث", - "colTodo": "قيد الانتظار", - "colInProgress": "قيد التنفيذ", - "colAttention": "بانتظارك", - "colDone": "مكتملة", - "statusTodo": "قيد الانتظار", - "statusQueued": "في قائمة الانتظار", - "statusPreparing": "قيد التهيئة", - "statusRunning": "قيد التنفيذ", - "statusAwaitingInput": "بانتظار الإدخال", - "statusReview": "بانتظار المراجعة", - "statusMerging": "جارٍ الدمج", - "statusDone": "مكتملة", - "statusFailed": "فشلت", - "statusCanceled": "ملغاة", - "statusInterrupted": "توقّفت", - "badgeCleanupFailed": "فشل التنظيف", - "badgeWorktreeKept": "تم الإبقاء على worktree", - "badgeWorktreeRemoved": "تمت إزالة worktree", - "filesChanged": "{count} ملفات", - "actionStart": "بدء", - "actionSchedule": "جدولة", - "actionCancel": "إلغاء", - "actionRetry": "إعادة المحاولة", - "actionRequeue": "إعادة الإدراج", - "actionViewSession": "عرض المحادثة", - "actionEdit": "تحرير", - "actionDelete": "حذف", - "actionRetryCleanup": "إعادة محاولة التنظيف", - "actionMerge": "دمج", - "actionUnqueueMerge": "مغادرة طابور الدمج", - "actionEditQueuedMerge": "تعديل الدمج المنتظر", - "badgeMergeQueued": "في طابور الدمج", - "badgeMergeQueuedRank": "في طابور الدمج · رقم {rank}", - "badgeMergeQueuedHint": "في انتظار انتهاء الدمج الجاري لهذا المشروع، وسيبدأ هذا تلقائيًا عند دوره.", - "actionComplete": "إنهاء", - "actionAbandon": "تخلٍّ", - "cancelTitle": "إلغاء المهمة؟", - "cancelDescription": "ستصبح المهمة ملغاة. يُحتفظ بـ worktree الخاصة بها ويمكنك إعادة إدراجها لاحقًا.", - "cancelReasonLabel": "السبب (اختياري)", - "cancelReasonPlaceholder": "مثلاً: النهج خاطئ، سأعيد كتابة الوصف", - "cancelKeep": "تراجع", - "cancelSubmit": "إلغاء المهمة", - "restartTitleRetry": "إعادة محاولة المهمة", - "restartTitleRequeue": "إعادة إدراج المهمة", - "restartDescription": "يمكنك إضافة ملاحظة (اختيارية) تصل إلى موجّه التشغيل التالي.", - "scheduleTitle": "جدولة المهمة", - "scheduleDescription": "تبقى المهمة في قائمة الانتظار وتبدأ تلقائيًا في الوقت الذي تحدده. ويظل حد التنفيذ المتزامن للمجلد ساريًا.", - "scheduleDateLabel": "التاريخ", - "schedulePickDate": "اختر التاريخ", - "scheduleTimeLabel": "الوقت", - "schedulePreview": "يبدأ في {time}", - "schedulePastHint": "لقد مضى هذا الوقت — ستبدأ المهمة فور الحفظ.", - "scheduleInAnHour": "بعد ساعة", - "scheduleInThreeHours": "بعد 3 ساعات", - "scheduleTomorrow": "غدًا 9:00", - "scheduleClear": "إلغاء الجدولة", - "scheduleBadge": "بدء مجدول في {time}", - "toastScheduled": "تمت الجدولة في {time}", - "toastScheduleCleared": "تم إلغاء الجدولة", - "actionFollowUp": "متابعة", - "actionAddNote": "إضافة ملاحظة", - "followUpSubmit": "إرسال", - "followUpIntentRevise": "إعادة العمل", - "followUpIntentContinue": "المتابعة", - "followUpIntentQuestion": "طرح سؤال", - "followUpIntentVerify": "مراجعة ذاتية", - "followUpPlaceholderRevise": "ما الذي يجب أن يغيّره الوكيل؟ سيتابع في الجلسة نفسها.", - "followUpPlaceholderContinue": "ما التالي؟ سيبقى العمل المنجز كما هو.", - "followUpPlaceholderQuestion": "ما الذي تريد معرفته؟ سيجيب الوكيل دون تعديل أي ملف.", - "followUpPlaceholderVerify": "اختياري: هل من شيء ينبغي فحصه بعناية؟", - "followUpPlaceholderRetry": "اختياري: ما الذي ينبغي فعله بشكل مختلف؟ مثلاً: شغّل pnpm install أولاً", - "followUpPlaceholderRequeue": "اختياري: لماذا ألغيتها، وما الذي يجب أن يتغيّر هذه المرة؟", - "actionArchive": "أرشفة", - "actionUnarchive": "إلغاء الأرشفة", - "archiveAllDone": "أرشفة الكل", - "dropToStart": "أفلِت للبدء", - "errorView": "عرض", - "notifyReview": "جاهزة للمراجعة: {title}", - "notifyFailed": "فشلت المهمة: {title}", - "createFromMessage": "إنشاء مهمة من الرسالة", - "detailTokens": "إجمالي الرموز", - "editorTitleNew": "مهمة جديدة", - "editorTitleEdit": "تحرير المهمة", - "templates": "القوالب", - "templatesEmpty": "لا توجد قوالب بعد.", - "templateSaveCurrent": "حفظ المحتوى الحالي كقالب", - "templateDelete": "حذف القالب", - "transcriptTitle": "محادثة المهمة", - "transcriptDescription": "عرض مباشر للقراءة فقط لجلسة وكيل المهمة.", - "phaseWork": "تنفيذ المهمة", - "phaseRetry": "إعادة التنفيذ", - "phaseReturn": "متابعة", - "phaseMerge": "الدمج", - "titleLabel": "العنوان", - "titlePlaceholder": "ما الذي يجب إنجازه؟", - "promptLabel": "وصف المهمة", - "promptPlaceholder": "صف المهمة للوكيل — استخدم @ للإشارة إلى الملفات و / للأوامر", - "folderPlaceholder": "اختر مجلدًا", - "agentInheritedHint": "موروث من إعدادات المهام — عدِّله ليصبح خاصًا بهذه المهمة", - "agentOverrideReset": "العودة إلى الوراثة", - "sectionTarget": "الهدف", - "errorTitle": "العنوان مطلوب", - "errorPrompt": "وصف المهمة مطلوب", - "errorFolder": "اختر مجلدًا", - "save": "حفظ", - "cancel": "إلغاء", - "mergeTitle": "دمج المهمة", - "mergeQueuedTitle": "دمج في الطابور", - "mergeQueueHint": "تجري الآن عملية دمج لمهمة أخرى في هذا المشروع. ستنضم هذه المهمة إلى الطابور وتبدأ تلقائيًا فور انتهاء تلك العملية.", - "mergeQueueUpdateHint": "هذه المهمة تنتظر الدمج بالفعل. الإرسال يحدّث خياراتها ويحتفظ بمكانها في الطابور.", - "mergeDescription": "دمج {branch} في {base}. تُرسل التغييرات غير المثبتة في worktree أولًا.", - "mergeMessage": "رسالة الالتزام", - "mergeMessagePlaceholder": "مثال: feat: add login validation", - "mergeAutoMessage": "دع الوكيل يكتب رسالة الإيداع", - "strategySquash": "دمج في التزام واحد", - "strategySquashHint": "تصل جميع تغييرات المهمة إلى الفرع الرئيسي كسجل واحد — تاريخ أكثر ترتيبًا.", - "strategyMerge": "الاحتفاظ بالتاريخ الكامل", - "strategyMergeHint": "يُحتفظ بكل التزام أُنشئ أثناء المهمة، مع إضافة سجل دمج واحد — تبقى كل خطوة قابلة للتتبع.", - "mergeDeleteWorktree": "حذف worktree بعد الدمج", - "mergeSubmit": "دمج", - "mergeSubmitQueue": "إضافة إلى طابور الدمج", - "mergeQueuedToast": "تمت الإضافة إلى طابور الدمج — سيبدأ فور انتهاء الدمج الحالي.", - "completeTitle": "إنهاء المهمة", - "completeDescription": "لم تغيّر هذه المهمة أي ملف، لذا لا يوجد ما يُدمج — سيتم وضع علامة مكتملة عليها مباشرة.", - "completeDescriptionNoWorktree": "تمت إزالة worktree هذه المهمة، فلم يعد الدمج ممكنًا — سيتم وضع علامة مكتملة عليها مباشرة. يُحتفظ بفرع العمل إذا كان لا يزال يحوي إيداعات غير مدمجة.", - "completeDeleteWorktree": "حذف worktree بعد الإنهاء", - "completeSubmit": "إنهاء", - "settingsTitle": "إعدادات المهام", - "settingsDescription": "الإعدادات الافتراضية لمهام {folder}.", - "settingsScope": "النطاق", - "settingsScopeGlobal": "كل المجلدات (الإعدادات العامة)", - "settingsScopeGlobalHint": "المجلدات بلا إعدادات خاصة تستخدم هذه الإعدادات العامة.", - "settingsSource": "مصدر الإعدادات", - "settingsSourceGlobal": "الإعدادات العامة", - "settingsSourceCustom": "إعداد خاص", - "settingsSourceGlobalFollow": "يتبع إعدادات المهام العامة — التغييرات هناك تسري هنا تلقائيًا.", - "settingsSourceCustomHint": "يحفظ إعدادات خاصة بهذا المجلد ويتوقف عن اتباع الإعدادات العامة.", - "settingsAgent": "الوكيل الافتراضي", - "settingsMaxConcurrent": "أقصى عدد للمهام المتزامنة", - "settingsMaxConcurrentHint": "0 = بلا حد", - "settingsAutoProcess": "معالجة تلقائية", - "settingsAutoProcessHint": "تبدأ المهام المعلّقة تلقائيًا ضمن حد التنفيذ المتزامن.", - "settingsMergeStrategy": "استراتيجية الدمج الافتراضية", - "settingsMergeStrategyHint": "كيفية تسجيل تغييرات المهمة في تاريخ الفرع عند الدمج.", - "settingsAutoMerge": "دمج تلقائي", - "settingsAutoMergeHint": "المهمة التي تصل إلى المراجعة وفيها تغييرات قابلة للدمج تُدمج كما لو نقرت «دمج»: يكتب الوكيل رسالة الإيداع، ويتبع الـ worktree الإعداد الافتراضي أدناه. أما المهمة التي فشل فحصها المسبق أو فشل دمجها فتبقى بانتظارك.", - "settingsDeleteWorktree": "حذف الـ worktree بعد الدمج", - "settingsDeleteWorktreeHint": "يُفعّل الخيار مسبقًا في نافذة الدمج، ويمكنك تغييره هناك.", - "settingsWorktreeRoot": "موقع الـ worktree", - "settingsWorktreeRootHint": "المجلد الذي تُنشأ فيه worktrees المهام الجديدة، واحدة لكل مهمة. اتركه فارغًا لإنشائها بجوار مجلد المشروع؛ «~» هو مجلد المنزل، والمسار النسبي يُحسب انطلاقًا من مجلد المشروع.", - "settingsWorktreeRootPlaceholder": "~/codeg-worktrees", - "settingsWorktreeRootBrowse": "اختيار مجلد الـ worktree", - "settingsPreflight": "أمر الفحص المسبق", - "settingsPreflightHint": "يعمل في شجرة العمل عندما تصل المهمة إلى المراجعة.", - "settingsPreflightCustomPlaceholder": "pnpm test", - "settingsInitCommand": "أمر تهيئة worktree", - "settingsInitCommandHint": "يعمل داخل worktree جديد قبل بدء الوكيل.", - "settingsInitCommandPlaceholder": "pnpm install", - "settingsTabGeneral": "عام", - "settingsTabMerge": "الدمج", - "settingsTabWorktree": "Worktree", - "settingsTabPrompts": "التوجيهات", - "settingsPromptsIntro": "لكل مرحلة موجّه مدمج بالفعل — المهمة نفسها، وقواعد شجرة العمل، وخطوات git الدقيقة عند الدمج. وما تضيفه هنا يُلحَق في النهاية كتعليمات إضافية: فهو يُهذّب النص المدمج ولا يستبدله أبدًا.", - "settingsPromptStageAll": "كل المراحل", - "settingsPromptPlaceholderAll": "مثال: التزم باصطلاحات ملف AGENTS.md، واجعل الملخص النهائي في جملتين", - "settingsPromptPlaceholderWork": "مثال: اقرأ الاختبارات المرتبطة أولًا، وأودِع التغييرات على خطوات صغيرة", - "settingsPromptPlaceholderRetry": "مثال: تحقق مما تم إيداعه قبل المتابعة، ولا تُعِد ما أُنجز", - "settingsPromptPlaceholderReturn": "مثلاً: عالج كل نقطة مذكورة؛ ولا تُعِد هيكلة أي شيء غير ذي صلة", - "settingsPromptPlaceholderMerge": "مثال: اكتب رسالة إيداع الدمج بالعربية، ونبّه إلى أي تعارض حللته يدويًا", - "settingsPromptHintAll": "يُلحق بكل توجيه يتلقاه الوكيل، بما في ذلك مرحلة الدمج.", - "settingsPromptHintWork": "يُلحق عند تنفيذ المهمة لأول مرة.", - "settingsPromptHintRetry": "يُلحق عند استئناف مهمة متوقفة أو فاشلة.", - "settingsPromptHintReturn": "يُضاف عند متابعة مهمة قيد المراجعة (إعادة عمل، عمل إضافي، مراجعة ذاتية).", - "settingsPromptHintMerge": "يُلحق عندما يدمج الوكيل المهمة في الفرع الأساسي.", - "preflightPassed": "نجح {name}", - "preflightFailed": "فشل {name}", - "preflightRunning": "{name} قيد التشغيل…", - "detailDescription": "تفاصيل المهمة", - "detailSummary": "النتيجة", - "detailFiles": "الملفات المتغيرة", - "detailDiffAll": "عرض كامل الفروق", - "detailDiffAllTitle": "كامل الفروق", - "detailNoChanges": "لا تغييرات بعد مقارنةً بالأساس", - "detailTimeline": "سجل التقدم", - "detailTimelineEmpty": "لا نشاط بعد", - "showMore": "عرض المزيد", - "showLess": "عرض أقل", - "detailInfo": "التفاصيل", - "detailBranch": "الفرع", - "detailMergeCommit": "إيداع الدمج", - "detailChanges": "التغييرات", - "detailScheduled": "البدء المجدول", - "detailCreated": "تاريخ الإنشاء", - "detailStarted": "تاريخ البدء", - "detailFinished": "تاريخ الانتهاء", - "diffLoading": "جارٍ تحميل الفروق…", - "deleteConfirmTitle": "حذف المهمة؟", - "deleteConfirmBody": "ستُزال “{title}” من اللوحة. يُلغى التشغيل النشط أولًا.", - "deleteWithWorktree": "حذف الـ worktree الخاص بها أيضًا", - "eventCreated": "أُنشئت", - "eventStatusChanged": "تغيّر الحالة", - "eventConfigEffective": "إعداد الإطلاق", - "eventInitCommand": "أمر التهيئة", - "eventAgentProgress": "تقدّم الوكيل", - "eventAgentVerdict": "حكم الوكيل", - "eventMergeAttempt": "بدأ الدمج", - "eventMergeQueued": "أُضيف إلى طابور الدمج", - "eventMergeConflict": "تعارض دمج", - "eventPreflight": "فحص مسبق", - "eventCleanupFailed": "فشل تنظيف worktree", - "eventResumeFallback": "فشل استئناف الجلسة؛ استُخدمت جلسة جديدة", - "eventUserAction": "إجراء المستخدم", - "eventDiffStat": "لقطة التغييرات" - }, - "CustomSkillsSettings": { - "loading": "جارٍ تحميل المهارات المخصّصة…", - "category": "مخصّصة", - "searchPlaceholder": "ابحث عن المهارات المخصّصة بالاسم أو المعرّف أو الوصف", - "states": { - "not_linked": "غير مُفعّلة", - "linked_to_codeg": "مُفعّلة", - "linked_elsewhere": "مرتبطة في مكان آخر", - "blocked_by_real_directory": "محجوبة بمجلد فعلي", - "broken": "رابط معطوب" - }, - "actions": { - "new": "جديدة", - "import": "استيراد", - "importFromAgent": "استيراد من وكيل", - "cancel": "إلغاء", - "save": "حفظ" - }, - "rowMenu": { - "edit": "تعديل", - "duplicate": "تكرار", - "delete": "حذف" - }, - "bulk": { - "delete": "حذف المحدد" - }, - "editor": { - "createTitle": "مهارة مخصّصة جديدة", - "editTitle": "تعديل مهارة مخصّصة", - "description": "تُحفَظ المهارات المخصّصة في المخزن المشترك (~/.codeg/skills) ويمكن تفعيلها لأي وكيل.", - "idLabel": "معرّف المهارة", - "idPlaceholder": "مثال: my-workflow", - "contentLabel": "SKILL.md", - "contentPlaceholder": "اكتب هنا ملف SKILL.md للمهارة…", - "preview": "معاينة", - "edit": "تعديل", - "emptyBody": "لا يوجد محتوى بعد." - }, - "duplicate": { - "title": "تكرار المهارة", - "description": "إنشاء نسخة من «{id}» بمعرّف جديد.", - "newIdPlaceholder": "معرّف المهارة الجديد", - "confirm": "تكرار" - }, - "import": { - "title": "اختر مجلد مهارة للاستيراد" - }, - "importFromAgent": { - "title": "استيراد المهارات من وكيل", - "description": "انسخ مهارات الوكيل الخاصة إلى المخزن المشترك لتفعيلها لأي وكيل.", - "agentLabel": "الوكيل", - "agentPlaceholder": "اختر وكيلاً", - "selectAll": "تحديد الكل ({count})", - "loading": "جارٍ تحميل مهارات الوكيل…", - "unsupported": "لا يوفّر هذا الوكيل دليل مهارات.", - "empty": "لا توجد مهارات قابلة للاستيراد لهذا الوكيل.", - "alreadyInLibrary": "في المكتبة", - "confirm": "استيراد المحدد ({count})" - }, - "delete": { - "title": "حذف المهارات المخصّصة؟", - "body": "سيؤدي هذا إلى إزالة {count} مهارة مخصّصة من المخزن المركزي وفصل روابطها من كل وكيل. لا يمكن التراجع عن ذلك.", - "confirm": "حذف" - }, - "toasts": { - "loadFailed": "فشل تحميل المهارة", - "idRequired": "أدخل معرّف المهارة", - "created": "تم إنشاء المهارة المخصّصة", - "updated": "تم تحديث المهارة المخصّصة", - "saveFailed": "فشل حفظ المهارة", - "imported": "تم استيراد المهارة", - "importFailed": "فشل استيراد المهارة", - "duplicated": "تم تكرار المهارة", - "duplicateFailed": "فشل تكرار المهارة", - "deleted": "تم حذف {count} مهارة", - "deletedPartial": "تم حذف {ok}، وفشل {failed}", - "deleteFailed": "فشل حذف المهارات", - "importedFromAgent": "تم استيراد {count} مهارة", - "importedFromAgentPartial": "تم استيراد {ok}، وفشل {failed}", - "importFromAgentAllSkipped": "لا شيء للاستيراد — {count} موجودة بالفعل في المكتبة", - "importFromAgentFailed": "فشل الاستيراد من الوكيل" - } - }, - "CodexModelEditor": { - "customizedNotice": "لقد خصّصت قائمة النماذج، لذا يدير codeg الآن جدول نماذج codex بالكامل. لن تظهر النماذج الرسمية التي يضيفها codex لاحقًا تلقائيًا — انقر على زر التحديث بالأسفل ثم احفظ مرة أخرى لمزامنتها. امسح كل تخصيصاتك ليعود codex إلى التحديث تلقائيًا.", - "officialsTitle": "النماذج الرسمية", - "officialsHint": "تُضاف تلقائيًا من codex الذي تشغّله؛ احذف ما لا تريده.", - "officialsEmpty": "لا توجد نماذج رسمية متاحة.", - "refresh": "تحديث من codex", - "readdOfficial": "إعادة إضافة رسمي", - "customsTitle": "النماذج المخصّصة", - "customsEmpty": "لا توجد نماذج مخصّصة بعد.", - "addCustom": "إضافة مخصص", - "slugPlaceholder": "معرّف النموذج (slug)", - "displayNamePlaceholder": "الاسم المعروض", - "contextWindow": "السياق", - "makeDefault": "تعيين كافتراضي", - "defaultHint": "النموذج الافتراضي", - "remove": "إزالة", - "advanced": "متقدم", - "baseTemplate": "القالب الأساسي", - "baseTemplateHint": "النموذج الرسمي الذي تُنسخ منه الحقول المطلوبة (موجّه النظام، الأدوات، الحدود).", - "groupBehavior": "السلوك والقدرات", - "fieldReasoningLevel": "الاستدلال الافتراضي", - "fieldReasoningSummary": "ملخص الاستدلال", - "fieldVerbosity": "مستوى التفصيل", - "fieldShellType": "نوع الصدفة", - "fieldApplyPatch": "أداة تطبيق التصحيح", - "fieldReasoningSummaries": "ملخصات الاستدلال", - "fieldSupportVerbosity": "التحكم في التفصيل", - "fieldParallelToolCalls": "استدعاءات الأدوات المتوازية", - "fieldSearchTool": "أداة البحث على الويب", - "optNone": "بلا", - "groupInstructions": "الوصف وموجّه النظام", - "fieldDescription": "الوصف", - "baseInstructions": "موجّه النظام (base_instructions)" - }, - "DiagnosticsSettings": { - "title": "تشخيص البيئة", - "description": "يتحقق من كيفية تحليل هذا التطبيق لواجهة سطر أوامر الوكيل داخل عمليته الخاصة، وقد يختلف ذلك عن الطرفية لديك.", - "loading": "جارٍ تشغيل التشخيص…", - "error": "فشل التشخيص", - "rerun": "إعادة التشغيل", - "copyAll": "نسخ الكل", - "copied": "تم نسخ التشخيص إلى الحافظة", - "button": "تشخيص", - "verdict": { - "ok": "تبدو البيئة سليمة. إذا استمر ظهوره كغير مُثبَّت، فأعد تشغيل التطبيق بالكامل لتحديث ذاكرة التخزين المؤقتة للبادئة.", - "node_missing": "لم يتم العثور على Node.js في مسار PATH الخاص بالتطبيق.", - "npm_missing": "لم يتم العثور على npm في مسار PATH الخاص بالتطبيق.", - "not_installed": "يبدو أن هذا الوكيل غير مُثبَّت.", - "installed_but_unresolved": "مُسجَّل كمُثبَّت، لكن لا يستطيع التطبيق تحديد موقع الملف التنفيذي.", - "user_prefix_not_on_path": "تم التثبيت في بادئة الاحتياط (~/.codeg/npm-global)، وهي ليست في مسار PATH الخاص بالتطبيق. أعد تشغيل التطبيق بالكامل وحاول مرة أخرى.", - "homebrew_bin_not_on_path": "تم التثبيت ضمن مجلد bin الخاص بـ Homebrew، وهو ليس في مسار PATH الخاص بالتطبيق (فصل keg على Apple Silicon).", - "terminal_only_path": "يُحلَّل الأمر في الطرفية لديك لكن ليس في التطبيق — وهي فجوة في مسار PATH لواجهة المستخدم الرسومية. شغّل التطبيق من الطرفية أو أعد التثبيت من إعدادات الوكلاء.", - "npm_prefix_timeout": "كان npm prefix -g بطيئًا جدًا (أكثر من 1.5 ثانية)، لذا تم تخطّي الكشف الاحتياطي. أعد تشغيل التطبيق وحاول مرة أخرى.", - "node_too_old": "إصدار Node.js النشط أقدم مما يتطلبه هذا الوكيل. يرجى ترقية Node.js.", - "adapter_missing_native_present": "واجهة {agent} لديك مثبّتة فعلاً، لكن Codeg يشغّل حزمة محوّل ACP منفصلة، وهي غير مثبّتة بعد. ثبّتها من إعدادات الوكلاء؛ فهي لا تمسّ واجهتك وتتشارك تسجيل الدخول نفسه.", - "adapter_missing": "يشغّل Codeg حزمة محوّل ACP منفصلة من أجل {agent}، وهي غير مثبّتة بعد. ثبّتها من إعدادات الوكلاء — لا يكفي تثبيت واجهة الأوامر الرسمية وحدها." - } - }, - "TokenUsage": { - "title": "استهلاك الرموز", - "rangeLabel": "النطاق الزمني", - "range7d": "٧ أيام", - "range30d": "٣٠ يومًا", - "range90d": "٩٠ يومًا", - "rangeThisMonth": "هذا الشهر", - "rangeThisYear": "هذا العام", - "rangeAll": "الكل", - "rangeCustom": "مخصص", - "moreRanges": "المزيد", - "customRangePick": "اختر نطاقاً زمنياً", - "bucketLabel": "التجميع حسب", - "bucketDay": "يوم", - "bucketWeek": "أسبوع", - "bucketMonth": "شهر", - "bucketUnitDay": "يوم", - "bucketUnitWeek": "أسبوع", - "bucketUnitMonth": "شهر", - "folderFilter": "المجلدات", - "allFolders": "كل المجلدات", - "agentFilter": "الوكلاء", - "allAgents": "كل الوكلاء", - "modelFilter": "النماذج", - "allModels": "كل النماذج", - "searchPlaceholder": "بحث…", - "noMatches": "لا توجد نتائج", - "clearFilter": "مسح التحديد", - "resetFilters": "إعادة ضبط المرشحات", - "refresh": "تحديث", - "rebuild": "إعادة بناء الكل", - "rebuildHint": "يتجاهل البيانات المحسوبة ويعيد قراءة كل سجلات الجلسات. استخدمه إذا نمت جلسة خارج codeg.", - "syncing": "جارٍ حساب الجلسات…", - "syncProgress": "{done} / {total}", - "syncDone": "تم حساب {synced} جلسة", - "syncFailed": "تعذّرت قراءة بعض الجلسات", - "syncBusy": "هناك تحديث قيد التشغيل بالفعل", - "lastSynced": "حُدّث {time}", - "lastSyncedNever": "لم يُحدَّث بعد", - "tileTotal": "إجمالي الرموز", - "tileSessions": "الجلسات", - "tileTurns": "الأدوار", - "tileActiveDays": "الأيام النشطة", - "tileGenTime": "زمن التوليد", - "vsPrevious": "مقارنة بالفترة السابقة", - "deltaNew": "جديد", - "trendTitle": "الاستهلاك عبر الزمن", - "trendEmpty": "لا استهلاك في هذا النطاق", - "trendTurns": "الأدوار", - "trendSessions": "الجلسات", - "compositionTitle": "أين ذهبت الرموز", - "compositionHint": "الإدخال هو ما أرسلته، والإخراج ما كتبه النموذج، وقراءات الذاكرة المؤقتة سياق لم تدفع ثمنه كاملًا.", - "compositionNote": "إعادة إرسال هذه الإصابات المؤقتة بالسعر الكامل كانت ستكلف {value} إضافية.", - "inputTokens": "إدخال", - "outputTokens": "إخراج", - "cacheWrite": "كتابة مؤقتة", - "cacheRead": "قراءة مؤقتة", - "freshTokens": "حساب جديد", - "cacheHitCaption": "إصابة مؤقتة", - "cacheHeroTitleHigh": "معظم السياق لم يُعَد إرساله", - "cacheHeroTitleLow": "معظم السياق ما زال يُحسب بالسعر الكامل", - "cacheHeroDesc": "حملت الذاكرة المؤقتة {cached} من السياق، ولم يُحسب من جديد سوى {fresh} في هذه الفترة.", - "cacheSavedSuffix": "وفّر ذلك ما يعادل {saved} من إعادة الإرسال.", - "avgPerSession": "المتوسط لكل جلسة", - "avgTurnsPerSession": "{count} دورة لكل جلسة في المتوسط", - "avgPerActiveDay": "المتوسط لكل يوم نشط", - "peakBucket": "أعلى {bucket}", - "peakHour": "ساعة الذروة", - "daysValue": "{count} يومًا", - "idleDays": "أيام الخمول", - "byFolderTitle": "حسب المجلد", - "byAgentTitle": "حسب الوكيل", - "byModelTitle": "حسب النموذج", - "distributionTitle": "توزيع الاستخدام", - "distributionHint": "تُجمَّع الجلسات والرموز حسب البعد المحدد — انقر أي صف للتصفية به.", - "otherLabel": "أخرى", - "unknownModel": "نموذج غير مسجَّل", - "emptyBreakdown": "لا توجد سجلات بعد", - "sessionsCount": "{count} جلسة", - "heatmapTitle": "إيقاع عملك", - "heatmapHint": "الرموز حسب اليوم والساعة بالتوقيت المحلي.", - "heatmapPeakHint": "الأكثر كثافة حوالي {hour}:00.", - "less": "أقل", - "more": "أكثر", - "heatmapCell": "{weekday} {hour}:00 — {value} رمز", - "weekMon": "إث", - "weekTue": "ثل", - "weekWed": "أر", - "weekThu": "خم", - "weekFri": "جم", - "weekSat": "سب", - "weekSun": "أح", - "topSessionsTitle": "أكثر الجلسات استهلاكًا", - "untitledSession": "جلسة بلا عنوان", - "topSessionsEmpty": "لا جلسات في هذا النطاق", - "streakLongest": "أطول سلسلة", - "streakLongestDays": "أطول سلسلة: {count} يومًا", - "share": "مشاركة", - "moreActions": "مزيد من الإجراءات", - "shareDialogTitle": "شارك بطاقة استهلاكك", - "shareDialogHint": "لقطة للنطاق والمرشحات التي تعرضها الآن.", - "shareSave": "حفظ الصورة", - "shareCopy": "نسخ الصورة", - "shareCopied": "تم النسخ إلى الحافظة", - "shareSaved": "تم حفظ الصورة", - "shareFailed": "تعذّر إنشاء الصورة", - "shareRendering": "جارٍ الإنشاء…", - "cardHeading": "سجلّي في البرمجة بالذكاء الاصطناعي", - "cardRangeAll": "كل الفترات", - "cardTotalLabel": "الرموز المستهلكة", - "cardFooter": "صُنع بواسطة codeg", - "cardTopModels": "أبرز النماذج", - "cardTopProjects": "أبرز المشاريع", - "archetypeNightOwl": "بومة الليل", - "archetypeNightOwlDesc": "{percent}% من رموزك تُستهلك بعد حلول الظلام.", - "archetypeEarlyBird": "المستيقظ باكرًا", - "archetypeEarlyBirdDesc": "{percent}% من رموزك تُستهلك قبل التاسعة صباحًا.", - "archetypeWeekendWarrior": "محارب عطلة الأسبوع", - "archetypeWeekendWarriorDesc": "{percent}% من رموزك تحدث في عطلة الأسبوع.", - "archetypeCacheMaster": "سيد الذاكرة المؤقتة", - "archetypeCacheMasterDesc": "{percent}% من سياقك جاء من الذاكرة المؤقتة.", - "archetypeMarathoner": "عدّاء المسافات", - "archetypeMarathonerDesc": "{days} يومًا من البناء دون انقطاع.", - "archetypePolyglot": "متعدد المهارات", - "archetypePolyglotDesc": "{count} وكلاء في استخدام جادّ.", - "archetypeLaserFocus": "تركيز مطلق", - "archetypeLaserFocusDesc": "{percent}% من رموزك ذهبت لمشروع واحد.", - "archetypeDeepDiver": "الغوّاص", - "archetypeDeepDiverDesc": "{averageK}K رمز في الجلسة الواحدة وسطيًا.", - "archetypeSteady": "بنّاء ثابت", - "archetypeSteadyDesc": "{days} يومًا من الإنجاز.", - "emptyTitle": "لا توجد بيانات محسوبة بعد", - "emptyHint": "يقرأ codeg أعداد الرموز مباشرة من سجل كل وكيل. حدّث لتُحسب الجلسات الموجودة على هذا الجهاز.", - "emptyAction": "احسب جلساتي", - "loadFailed": "تعذّر تحميل بيانات الاستهلاك", - "truncatedNotice": "هذا النطاق واسع جدًا — الأرقام تغطي أحدث جزء منه فقط." - } -} +{ + "Language": { + "followSystem": "اتباع النظام", + "english": "الإنجليزية", + "simplifiedChinese": "الصينية المبسطة", + "traditionalChinese": "الصينية التقليدية", + "japanese": "اليابانية", + "korean": "الكورية", + "spanish": "الإسبانية", + "german": "الألمانية", + "french": "الفرنسية", + "portuguese": "البرتغالية", + "arabic": "العربية" + }, + "GitCredentialDialog": { + "title": "المصادقة مطلوبة", + "description": "يتطلب الخادم البعيد بيانات اعتماد. أدخل اسم المستخدم وكلمة المرور (أو رمز الوصول الشخصي).", + "username": "اسم المستخدم", + "usernamePlaceholder": "اسم المستخدم أو البريد الإلكتروني", + "password": "كلمة المرور / الرمز", + "passwordPlaceholder": "كلمة المرور أو رمز الوصول الشخصي", + "passwordHint": "أدخل اسم المستخدم وكلمة المرور للخادم.", + "cancel": "إلغاء", + "authenticate": "مصادقة", + "authenticating": "جارٍ المصادقة...", + "invalidCredentials": "بيانات الاعتماد غير صالحة. يرجى المحاولة مرة أخرى.", + "saveCredentials": "حفظ بيانات الاعتماد للعمليات المستقبلية", + "githubTitle": "مصادقة GitHub", + "githubDescription": "أدخل رمز وصول شخصي للاتصال بـ GitHub. سيتم التحقق من الرمز وحفظه تلقائيًا.", + "githubToken": "رمز الوصول الشخصي", + "githubTokenPlaceholder": "ghp_xxxxxxxxxxxx", + "githubTokenHint": "أنشئ رمزًا في GitHub → Settings → Developer settings → Personal access tokens.", + "githubAuthenticate": "التحقق والاتصال", + "generateToken": "إنشاء رمز" + }, + "SettingsShell": { + "title": "الإعدادات", + "preferences": "التفضيلات", + "nav": { + "general": "عام", + "appearance": "المظهر", + "agents": "الوكلاء", + "mcp": "MCP", + "skills": "Skills", + "shortcuts": "الاختصارات", + "version_control": "التحكم بالإصدارات", + "system": "النظام", + "chat_channels": "قنوات المحادثة", + "web_service": "خدمة الويب", + "model_providers": "مزودو النماذج", + "experts": "الخبراء", + "science": "البحث العلمي", + "office_tools": "أدوات المكتب", + "skill_packs": "حزم المهارات", + "quick_messages": "رسائل سريعة", + "logs": "سجلات التشغيل" + } + }, + "AppearanceSettings": { + "sectionTitle": "مظهر السمة", + "sectionDescription": "اختر الفاتح أو الداكن أو اتباع النظام. يتم حفظ الإعدادات تلقائيًا.", + "themeMode": "وضع السمة", + "placeholder": "اختر وضع السمة", + "system": "اتباع النظام", + "light": "فاتح", + "dark": "داكن", + "currentTheme": "السمة الفعالة الحالية: {theme}", + "resolvedTheme": { + "light": "فاتح", + "dark": "داكن", + "unknown": "--" + }, + "themeColor": { + "sectionTitle": "لون السمة", + "sectionDescription": "اختر لوحة ألوان للتمييزات والأزرار والإبرازات.", + "current": "اللون الحالي: {color}", + "options": { + "neutral": "Neutral", + "zinc": "Zinc", + "slate": "Slate", + "stone": "Stone", + "gray": "Gray", + "red": "Red", + "rose": "Rose", + "orange": "Orange", + "green": "Green", + "blue": "Blue", + "yellow": "Yellow", + "violet": "Violet" + } + }, + "customStyle": { + "sectionTitle": "نمط مخصص", + "sectionDescription": "اضبط ألوان السمة الحالية بدقة، أو أدرج CSS خاصًا بك. تُطبَّق التجاوزات فوق الإعداد الأساسي، لذا تبقى عند تبديل الإعداد.", + "summarySuspended": "موقوف مؤقتًا", + "summaryDefault": "الإعداد الأساسي دون تغيير", + "summaryTokens": "{count, plural, one {# تجاوز} other {# تجاوزات}}", + "summaryCss": "CSS مخصص", + "suspendedByShortcut": "النمط المخصص موقوف مؤقتًا. لن يسري أي إعداد هنا حتى تستأنفه.", + "suspendedBySafeParam": "فُتحت هذه النافذة في وضع المظهر الآمن، لذا يُتجاهل النمط المخصص هنا. لا تتأثر النوافذ الأخرى.", + "resume": "استئناف النمط المخصص", + "enableTheme": "تفعيل الألوان المخصصة", + "editingLight": "تحرير قيم الوضع الفاتح. بدّل التطبيق إلى الوضع الداكن لضبطه على حدة.", + "editingDark": "تحرير قيم الوضع الداكن. بدّل التطبيق إلى الوضع الفاتح لضبطه على حدة.", + "resetToken": "إعادة التعيين إلى قيمة الإعداد", + "radius": "استدارة الزوايا", + "radiusHint": "يشتق منها مقياس الاستدارة كاملًا من sm إلى 4xl، لذا يكفي شريط واحد لتغيير استدارة التطبيق بأكمله.", + "advanced": "متقدم ({count} متغيرات إضافية)", + "enableCss": "تفعيل CSS المخصص", + "cssRisk": "ميزة متقدمة. يتجاوز CSS المخصص جميع الأنماط المدمجة وقد يجعل الواجهة غير قابلة للاستخدام.", + "editCss": "تحرير CSS…", + "cssPresent": "تم حفظ {size} كيلوبايت", + "cssEmpty": "لا يوجد محتوى محفوظ بعد", + "escapeHint": "هل تعطلت الواجهة؟ اضغط {shortcut} لإيقاف كل النمط المخصص، أو افتح نافذة بمعامل الاستعلام safeStyle=1.", + "copyTheme": "نسخ JSON السمة", + "importTheme": "استيراد سمة…", + "clearTheme": "مسح التجاوزات", + "interopHint": "تستخدم السمات صيغة registry:theme من shadcn، فيمكنك لصق أي سمة shadcn هنا واستخدام سماتك المصدَّرة في أي مشروع shadcn.", + "importTitle": "استيراد سمة", + "importDescription": "الصق عنصر registry:theme من shadcn، أو كائن light/dark مجردًا، أو خريطة رموز مسطحة.", + "readClipboard": "قراءة الحافظة", + "importConfirm": "استيراد", + "cancel": "إلغاء", + "apply": "تطبيق", + "toasts": { + "copied": "تم نسخ JSON السمة", + "copyFailed": "تعذّر النسخ إلى الحافظة", + "clipboardReadFailed": "تعذّرت قراءة الحافظة، الصق يدويًا", + "importFailed": "لا توجد متغيرات سمة صالحة في هذا الـ JSON", + "imported": "تم استيراد السمة" + }, + "css": { + "dialogTitle": "CSS مخصص", + "dialogDescription": "يسري على جميع نوافذ codeg. تُعاين التغييرات مباشرة؛ اضغط تطبيق للحفظ.", + "size": "{used} كيلوبايت / {max} كيلوبايت", + "ruleCount": "{count} قاعدة", + "errorTooLarge": "الحجم كبير جدًا للحفظ. قلّصه إلى ما دون الحد.", + "errorImportEscaped": "بقيت قاعدة @import بعد الإزالة (صيغة هروب). أزلها للحفظ.", + "warnNoRules": "لم يُحلَّل أي قاعدة، تحقق من الصياغة.", + "noticeImportsRemoved": "قواعد @import المُزالة: {count}. كانت ستجلب أوراق أنماط بعيدة.", + "noticeRemoteUrl": "يحتوي على url() بعيد، وسيُصدر طلب شبكة عند التطبيق.", + "noticePreviewSuspended": "النمط المخصص موقوف، لذا لا تُطبَّق هذه المعاينة.", + "noticeDisabled": "CSS المخصص متوقف. يمكنك المعاينة هنا، لكن لن يسري شيء حتى تفعّله.", + "hintTokens": "تلميح: الألوان التي تجاوزتها متاحة عبر var(--primary) و var(--background) وغيرها." + } + }, + "zoomLevel": { + "sectionTitle": "تكبير النافذة", + "sectionDescription": "تكبير أو تصغير الواجهة بالكامل. يتم تطبيقه فوراً ويُحفظ لكل جهاز على حدة.", + "placeholder": "اختر مستوى التكبير", + "default": "افتراضي", + "current": "التكبير الحالي: {zoom}%" + }, + "fonts": { + "sectionTitle": "الخطوط", + "sectionDescription": "اختر خطوطًا للواجهة ومحرّر الأكواد والطرفية. تُحمّل الخطوط المضمّنة عند الحاجة؛ اختر «مخصّص…» لاستخدام أي خط مثبّت على نظامك.", + "interface": "الواجهة", + "editor": "المحرّر", + "terminal": "الطرفية", + "groupSans": "بلا زوائد", + "groupMono": "ثابت العرض", + "custom": "مخصّص…", + "customPlaceholder": "اسم الخط، مثل Fira Code", + "fontSize": "حجم الخط", + "ligatures": "تفعيل الحروف المتصلة", + "ligaturesUnavailable": "هذا الخط لا يحتوي على حروف متصلة", + "wordWrap": "تفعيل التفاف النص", + "terminalLigaturesHint": "تنطبق الحروف المتصلة في الطرفية على خطوط البرمجة المضمّنة فقط.", + "preview": "معاينة" + }, + "welcomePanel": { + "sectionTitle": "منطقة اختيار الوضع", + "sectionDescription": "بطاقات الاختصار «تطوير الكود / الأعمال المكتبية» التي تظهر أعلى مربع الإدخال في صفحة المحادثة الجديدة.", + "showQuickActions": "العرض في صفحة المحادثة الجديدة" + }, + "workspaceBackground": { + "sectionTitle": "خلفية مساحة العمل", + "sectionDescription": "عرض صورة خلف مساحة العمل بالكامل. يصبح الشريط الجانبي واللوحات شبه شفافة ومصنفرة لتظهر الصورة من خلالها، ويحافظ القناع على وضوح النص.", + "enable": "تفعيل صورة الخلفية", + "image": "الصورة", + "chooseImage": "اختيار صورة", + "replaceImage": "استبدال الصورة", + "removeImage": "إزالة", + "fillMode": "وضع الملء", + "fillModes": { + "cover": "تغطية", + "contain": "احتواء", + "center": "توسيط", + "tile": "تكرار" + }, + "maskOpacity": "عتامة القناع", + "maskOpacityHint": "القيم الأعلى تمزج الصورة نحو لون خلفية السمة، مما يحسّن تباين النص.", + "imageBlur": "تمويه الصورة", + "panelOpacity": "عتامة اللوحات", + "panelOpacityHint": "مدى عتامة الشريط الجانبي واللوحات وأشرطة التبويب. الأقل يُظهر المزيد من الصورة.", + "errorTooLarge": "الصورة كبيرة جدًا (16 ميجابايت كحد أقصى).", + "errorUploadFailed": "فشل تعيين صورة الخلفية." + } + }, + "SystemSettings": { + "loading": "جارٍ التحميل...", + "sectionTitle": "إدارة النظام", + "sectionDescription": "إدارة وكيل الشبكة وتحديثات التطبيق وتفضيلات اللغة.", + "proxyTitle": "وكيل الشبكة", + "proxyDescription": "عند التفعيل، ستُفضَّل إعدادات هذا الوكيل في طلبات الشبكة اللاحقة (بما في ذلك دردشة ACP وتثبيت الوكلاء وعمليات Git البعيدة).", + "loadFailed": "فشل التحميل: {message}", + "enableProxy": "تفعيل وكيل النظام", + "proxyAddress": "عنوان الوكيل", + "proxyHint": "يدعم http(s)/socks5، مثال: {example}. يعمل فقط عند تفعيل وكيل النظام.", + "save": "حفظ", + "saving": "جارٍ الحفظ...", + "proxyRequired": "عنوان URL للوكيل مطلوب عند تفعيل الوكيل", + "saveSuccess": "تم حفظ إعدادات وكيل النظام", + "saveFailed": "فشل الحفظ: {message}", + "languageTitle": "اللغة", + "languageDescription": "حدد لغة التطبيق. عند اتباع لغة النظام، ستعود اللغات غير المدعومة إلى الإنجليزية.", + "appLanguage": "لغة التطبيق", + "languageSaveSuccess": "تم حفظ إعدادات اللغة", + "languageSaveFailed": "فشل حفظ إعدادات اللغة: {message}", + "updateTitle": "تحديث التطبيق", + "versionTitle": "تحديث البرنامج", + "updateDescription": "تحقق من المصدر المهيأ للإصدارات الأحدث وثبّت التحديث مباشرة عند توفره.", + "currentVersion": "الإصدار الحالي", + "upgradableVersion": "أحدث إصدار", + "none": "لا يوجد", + "lastChecked": "آخر فحص: {time}", + "updateError": "خطأ في التحديث: {message}", + "checking": "جارٍ التحقق...", + "checkUpdate": "التحقق من التحديثات", + "updating": "جارٍ التثبيت...", + "downloading": "جارٍ التنزيل...", + "upgradeTo": "الترقية إلى v{version}", + "viewRelease": "عرض إصدار v{version}", + "foundUpdate": "تم العثور على إصدار جديد v{version}", + "alreadyLatest": "أنت على أحدث إصدار", + "checkUpdateFailed": "فشل التحقق من التحديثات: {message}", + "installSuccess": "تم تثبيت التحديث. جارٍ إعادة تشغيل التطبيق.", + "installFailed": "فشل التحديث: {message}", + "upgradeSuccess": "اكتملت الترقية. جارٍ إعادة التحميل...", + "restartTimeout": "لم يعد الخادم في الوقت المناسب. تحقق من سجلات الحاوية أو الخدمة.", + "restartingIn": "إعادة التشغيل خلال {seconds} ثانية...", + "waitingForServer": "في انتظار عودة الخادم...", + "restartToUpdate": "أعد التشغيل للتحديث", + "newVersionBadge": "إصدار جديد v{version}", + "updateAvailableTitle": "يتوفر تحديث", + "releaseNotesTitle": "ما الجديد", + "remindLater": "لاحقًا", + "retry": "إعادة المحاولة", + "stepDownload": "التنزيل", + "stepInstall": "التثبيت", + "stepRestart": "إعادة التشغيل", + "updateReadyHint": "تم تنزيل التحديث — أعد التشغيل لتطبيقه.", + "restarting": "جارٍ إعادة التشغيل...", + "dockerUpgradeHint": "يؤدي هذا إلى ترقية الحاوية قيد التشغيل الآن. وتُفقد عند إعادة إنشاء الحاوية — وللاحتفاظ بها، اسحب أو ابنِ صورة بالإصدار الجديد ثم أعد إنشاء الحاوية.", + "upgradeRolledBack": "فشلت الترقية؛ عاد الخادم إلى الإصدار السابق.", + "serverUnreachable": "تعذّر الوصول إلى الخادم لبدء الترقية. تأكد من أنه قيد التشغيل وحاول مرة أخرى.", + "rollbackButton": "التراجع", + "rollingBack": "جارٍ التراجع...", + "rollbackDescription": "استعادة الإصدار المثبَّت قبل آخر ترقية.", + "rollbackConfirmTitle": "التراجع إلى الإصدار السابق؟", + "rollbackConfirmDescription": "ستعيد الخادم التشغيل على الإصدار المثبَّت قبل آخر ترقية. ويبقى الإصدار الأحدث متاحًا لإعادة التثبيت.", + "rollbackConfirm": "التراجع", + "rollbackCancel": "إلغاء", + "rollbackSuccess": "تم التراجع إلى الإصدار السابق. جارٍ إعادة التحميل...", + "rollbackFailed": "فشل التراجع. تحقّق من سجلات الخادم.", + "updateErrors": { + "sourceUnavailable": "تعذر الوصول إلى مصدر التحديث. تحقق من الشبكة أو الوكيل ثم أعد المحاولة.", + "network": "فشل اتصال الشبكة. تحقق من الشبكة أو الوكيل ثم أعد المحاولة.", + "downloadFailed": "فشل تنزيل حزمة التحديث. يرجى المحاولة مرة أخرى لاحقًا.", + "installFailed": "فشل تثبيت التحديث. يرجى إغلاق التطبيق ثم إعادة المحاولة.", + "unknown": "فشل التحديث. يرجى المحاولة مرة أخرى لاحقًا." + } + }, + "VersionControlSettings": { + "loading": "جارٍ التحميل...", + "sectionTitle": "التحكم بالإصدارات", + "sectionDescription": "تكوين ملف Git التنفيذي وإدارة حسابات GitHub.", + "gitTitle": "إعدادات Git", + "gitDescription": "تكوين ملف Git التنفيذي المستخدم بواسطة التطبيق.", + "gitDetected": "تم اكتشاف Git", + "gitNotFound": "لم يتم العثور على Git في النظام", + "gitVersion": "الإصدار", + "gitPath": "المسار", + "customGitPath": "مسار Git مخصص", + "customGitPathPlaceholder": "/usr/bin/git", + "customGitPathHint": "اتركه فارغًا لاستخدام المسار المكتشف تلقائيًا.", + "test": "اختبار", + "testing": "جارٍ الاختبار...", + "testSuccess": "ملف Git التنفيذي صالح.", + "testFailed": "فشل اختبار Git: {message}", + "save": "حفظ", + "saving": "جارٍ الحفظ...", + "saveSuccess": "تم حفظ إعدادات Git.", + "saveFailed": "فشل الحفظ: {message}", + "githubTitle": "حسابات GitHub", + "githubDescription": "إدارة حسابات GitHub للمصادقة. يتم تخزين الرموز محليًا.", + "noAccounts": "لا توجد حسابات GitHub مكوّنة.", + "addAccount": "إضافة حساب", + "serverUrl": "عنوان الخادم", + "serverUrlPlaceholder": "https://github.com", + "token": "رمز الوصول الشخصي", + "tokenPlaceholder": "ghp_xxxxxxxxxxxx", + "generateToken": "إنشاء رمز", + "tokenHint": "أنشئ رمزًا في GitHub → Settings → Developer settings → Personal access tokens.", + "validateAndAdd": "التحقق والإضافة", + "validating": "جارٍ التحقق...", + "addSuccess": "تمت إضافة الحساب {username} بنجاح.", + "addFailed": "فشل إضافة الحساب: {message}", + "testConnection": "اختبار", + "connectionSuccess": "نجح الاتصال.", + "connectionFailed": "فشل الاتصال: {message}", + "setDefault": "تعيين كافتراضي", + "defaultLabel": "افتراضي", + "defaultSet": "تم تحديث الحساب الافتراضي.", + "removeAccount": "إزالة", + "removeConfirmTitle": "إزالة الحساب", + "removeConfirmMessage": "هل أنت متأكد من إزالة الحساب \"{username}\"؟", + "removeConfirm": "إزالة", + "removeCancel": "إلغاء", + "removeSuccess": "تمت إزالة الحساب.", + "scopes": "النطاقات", + "loadFailed": "فشل تحميل الإعدادات: {message}", + "gitAccount": { + "sectionTitle": "حسابات خادم Git", + "sectionDescription": "إدارة بيانات الاعتماد لخوادم Git غير GitHub (GitLab، Bitbucket، الخوادم الذاتية، إلخ).", + "noAccounts": "لا توجد حسابات خادم Git مكوّنة.", + "addAccount": "إضافة حساب", + "addTitle": "إضافة حساب Git", + "addDescription": "أدخل عنوان الخادم واسم المستخدم وكلمة المرور أو رمز الوصول.", + "serverUrl": "عنوان الخادم", + "serverUrlPlaceholder": "https://gitlab.example.com", + "username": "اسم المستخدم", + "usernamePlaceholder": "اسم المستخدم أو البريد الإلكتروني", + "password": "كلمة المرور / الرمز", + "passwordPlaceholder": "كلمة المرور أو رمز الوصول", + "passwordHint": "أدخل كلمة مرور الخادم أو رمز الوصول.", + "add": "إضافة", + "serverRequired": "عنوان الخادم مطلوب.", + "usernameRequired": "اسم المستخدم مطلوب.", + "passwordRequired": "كلمة المرور مطلوبة." + } + }, + "ShortcutSettings": { + "sectionTitle": "الاختصارات", + "resetDefault": "استعادة الإعدادات الافتراضية", + "recordInstruction": "انقر الزر في الجهة اليمنى ثم اضغط تركيبة مفاتيح. استخدم Ctrl/Cmd وAlt وShift. اضغط Esc لإلغاء التسجيل.", + "recording": "اضغط اختصارًا...", + "toasts": { + "conflict": "الاختصار مستخدم بالفعل بواسطة \"{title}\"", + "updated": "تم تحديث الاختصار", + "invalid": "اختصار غير صالح، يرجى المحاولة مرة أخرى", + "reset": "تمت استعادة الاختصارات الافتراضية" + }, + "actions": { + "toggle_search": { + "title": "فتح البحث", + "description": "إظهار أو إخفاء لوحة البحث في المحادثات" + }, + "toggle_sidebar": { + "title": "تبديل الشريط الجانبي الأيسر", + "description": "إظهار أو إخفاء الشريط الجانبي لقائمة المحادثات" + }, + "toggle_terminal": { + "title": "تبديل الطرفية", + "description": "إظهار أو إخفاء لوحة الطرفية السفلية" + }, + "new_terminal_tab": { + "title": "طرفية جديدة", + "description": "إنشاء تبويب طرفية جديد عندما يكون التركيز على الطرفية" + }, + "close_current_terminal_tab": { + "title": "إغلاق الطرفية الحالية", + "description": "إغلاق تبويب الطرفية الحالي عندما يكون التركيز على الطرفية" + }, + "toggle_aux_panel": { + "title": "تبديل اللوحة اليمنى", + "description": "إظهار أو إخفاء لوحة المعلومات المساعدة" + }, + "new_conversation": { + "title": "محادثة جديدة", + "description": "إنشاء تبويب محادثة جديد في المجلد الحالي" + }, + "open_folder": { + "title": "فتح مجلد", + "description": "فتح منتقي المجلدات وفتح المجلد في نافذة جديدة" + }, + "open_settings": { + "title": "فتح الإعدادات", + "description": "فتح نافذة الإعدادات" + }, + "close_current_tab": { + "title": "إغلاق التبويب الحالي", + "description": "إغلاق المحادثة الحالية أو تبويب الملف الحالي" + }, + "close_all_file_tabs": { + "title": "إغلاق جميع تبويبات الملفات", + "description": "إغلاق جميع تبويبات الملفات المفتوحة عندما تكون لوحة الملفات نشطة" + }, + "next_tab": { + "title": "علامة التبويب التالية", + "description": "التبديل إلى علامة تبويب المحادثة أو الملف التالية" + }, + "prev_tab": { + "title": "علامة التبويب السابقة", + "description": "التبديل إلى علامة تبويب المحادثة أو الملف السابقة" + }, + "send_message": { + "title": "إرسال الرسالة", + "description": "إرسال الرسالة الحالية في مربع الإدخال" + }, + "newline_in_message": { + "title": "سطر جديد في الرسالة", + "description": "إدراج سطر جديد في مربع الإدخال" + }, + "toggle_custom_style": { + "title": "إيقاف/استئناف النمط المخصص", + "description": "مخرج طوارئ: يوقف كل الألوان المخصصة وCSS، ويعيد تفعيلها" + } + } + }, + "SkillsSettings": { + "title": "Skills", + "description": "اختر Skill من الجهة اليسرى. تعرض الجهة اليمنى معاينة Markdown بشكل افتراضي؛ انتقل إلى وضع التحرير للتعديل والحفظ.", + "loadingAgents": "جارٍ تحميل الوكلاء الذين يدعمون Skills...", + "emptyNoManageableAgents": "لا توجد وكلاء متاحة لإدارة Skills.", + "managedTarget": "الهدف المُدار", + "selectAgentPlaceholder": "اختر وكيلًا", + "searchPlaceholder": "ابحث بالاسم / المعرّف / المسار...", + "skillsList": "قائمة Skills", + "loadingSkills": "جارٍ تحميل Skills...", + "agentNotSupported": "الوكيل الحالي لا يدعم إدارة Skills.", + "emptySkills": "لا توجد Skills بعد. انقر \"Skill جديدة\" لإنشاء واحدة.", + "newSkillTitle": "Skill جديدة", + "skillInfo": "معلومات Skill", + "skillIdPlaceholder": "skill-id (حروف/أرقام/-/_/.)", + "skillsDirectoryWithPath": "دليل Skills: {path}", + "skillsDirectoryNeedId": "دليل Skills: أدخل معرّف Skill لإنشاء المسار الكامل", + "markdownContent": "محتوى Markdown", + "editingStatus": "جارٍ التحرير", + "previewStatus": "معاينة", + "contentPlaceholder": "أدخل محتوى Markdown للSkill...", + "metadataTitle": "بيانات Skills الوصفية", + "onlyYamlMetadata": "تحتوي هذه Skill على بيانات YAML الوصفية فقط.", + "emptyContentHint": "لا يوجد محتوى بعد. انقر \"تحرير\" للبدء.", + "loadingSkill": "جارٍ تحميل Skill...", + "emptyNoAgents": "لا يوجد وكيل متاح.", + "noSelectionHint": "اختر Skill من اليسار، أو انقر على \"Skill جديد\" لإنشاء واحد.", + "systemBadge": "نظام", + "systemHint": "Skill مدمج في CLI · للقراءة فقط", + "scope": { + "global": "عام", + "folder": "مجلد", + "selectFolderPlaceholder": "اختر مجلدًا", + "noFolders": "لم يتم العثور على مجلدات", + "pickFolderHint": "اختر مجلدًا لعرض مهاراته." + }, + "actions": { + "preview": "معاينة", + "edit": "تحرير", + "openInWindow": "فتح في نافذة جديدة", + "delete": "حذف", + "deleting": "جارٍ الحذف...", + "refresh": "تحديث", + "newSkill": "Skill جديدة", + "reset": "إعادة تعيين", + "save": "حفظ", + "saving": "جارٍ الحفظ...", + "cancel": "إلغاء" + }, + "deleteDialog": { + "title": "حذف Skill", + "confirm": "هل تريد حذف Skill الحالية؟ لا يمكن التراجع عن هذا الإجراء.", + "confirmWithNamePrefix": "حذف Skill", + "confirmWithNameSuffix": "؟ لا يمكن التراجع عن هذا الإجراء." + }, + "toasts": { + "loadFailed": "فشل تحميل Skill", + "openFolderFailed": "فشل فتح المجلد", + "noSkillDirectory": "لم يتم العثور على دليل Skills متاح للوكيل الحالي", + "nameRequired": "لا يمكن أن يكون اسم Skill فارغًا", + "updated": "تم تحديث Skill", + "created": "تم إنشاء Skill", + "saveFailed": "فشل حفظ Skill", + "deleted": "تم حذف Skill", + "deleteFailed": "فشل حذف Skill" + }, + "templates": { + "gemini": "---\nname: example-skill\ndescription: Describe when this skill should be used.\n---\n\n# Skill Name\n\nInstructions for the agent when this skill is active.\n\n## Workflow\n\n1. Add actionable step one.\n2. Add actionable step two.\n", + "openCode": "---\nname: example-skill\ndescription: Describe when this skill should be used.\n---\n\n# Purpose\n\nDescribe what this skill helps with.\n\n# Steps\n\n1. Add actionable step one.\n2. Add actionable step two.\n", + "openClaw": "---\nname: example-skill\ndescription: Describe when this skill should be used.\nuser-invocable: true\ndisable-model-invocation: false\n---\n\n# Purpose\n\nDescribe what this skill helps with.\n\n# Instructions\n\n1. Add actionable instruction one.\n2. Add actionable instruction two.\n", + "default": "---\nname: example-skill\ndescription: Describe when this skill should be used.\n---\n\n# Skill: example-skill\n\n## When to use\n\n- Describe trigger conditions.\n\n## Instructions\n\n1. Add actionable instruction one.\n2. Add actionable instruction two.\n" + } + }, + "McpSettings": { + "loading": "جارٍ التحميل...", + "summary": { + "missingCommand": "(لا يوجد أمر)", + "missingUrl": "(لا يوجد رابط)" + }, + "protocol": { + "stdio": "Stdio" + }, + "errors": { + "selectInstallProtocol": "يرجى اختيار بروتوكول التثبيت", + "fieldRequired": "{field} مطلوب", + "fieldNeedsBoolean": "{field} يجب أن يكون true أو false", + "fieldNeedsNumber": "{field} يجب أن يكون رقمًا", + "fieldNeedsInteger": "{field} يجب أن يكون عددًا صحيحًا", + "fieldInvalidJson": "{field} يحتوي JSON غير صالح: {message}", + "fieldOutOfRange": "قيمة {field} خارج النطاق المسموح", + "jsonEmpty": "{name} لا يمكن أن يكون فارغًا", + "jsonInvalid": "{name} ليس JSON صالحًا: {message}", + "jsonMustBeObject": "{name} يجب أن يكون كائن JSON", + "specMustBeObject": "يجب أن يكون إعداد MCP كائن JSON.", + "missingType": "حقل type غير موجود في إعداد MCP. حدد أحد القيم: stdio أو http (الأسماء البديلة: streamable-http و streamableHttp) أو sse.", + "unsupportedType": "نوع MCP غير مدعوم {type}. المدعوم: stdio و http (الأسماء البديلة: streamable-http و streamableHttp) و sse.", + "codexEntryUnsupportedType": "إدخال Codex MCP {id} له نوع غير مدعوم {type}. المدعوم: stdio و http (الأسماء البديلة: streamable-http و streamableHttp) و sse.", + "unsupportedTransportType": "نوع transport غير مدعوم {type}. المدعوم: http (الأسماء البديلة: streamable-http و streamableHttp) و sse.", + "stdioCommandRequired": "يتطلب MCP من نوع stdio حقل command غير فارغ.", + "remoteUrlRequired": "تتطلب MCP البعيدة حقل url غير فارغ.", + "appsRequired": "حدد تطبيقاً مستهدفاً واحداً على الأقل." + }, + "jsonNames": { + "localConfig": "إعداد MCP", + "installConfig": "إعداد التثبيت" + }, + "toasts": { + "uninstalled": "تمت إزالة MCP", + "uninstallFailed": "فشل الإزالة: {message}", + "selectAtLeastOneApp": "يرجى اختيار تطبيق هدف واحد على الأقل", + "saveSuccess": "تم الحفظ", + "saveFailed": "فشل الحفظ: {message}", + "installed": "تم تثبيت {name}", + "installFailed": "فشل التثبيت: {message}", + "serverIdRequired": "معرّف الخادم مطلوب", + "serverIdExists": "معرّف الخادم \"{id}\" موجود بالفعل. عدّل العنصر الحالي أو اختر اسماً آخر.", + "created": "تم إنشاء MCP" + }, + "installDialog": { + "title": "تأكيد تثبيت MCP", + "descriptionWithName": "تثبيت {name} في الإعداد المحلي.", + "description": "اختر التطبيقات المستهدفة للتثبيت.", + "protocol": "البروتوكول", + "selectProtocol": "اختر البروتوكول", + "parameters": "معلمات الإعداد", + "booleanPlaceholder": "يرجى اختيار true/false", + "selectOneValue": "اختر قيمة", + "targetApps": "التطبيقات المستهدفة" + }, + "actions": { + "cancel": "إلغاء", + "confirmInstall": "تأكيد التثبيت", + "installing": "جارٍ التثبيت", + "uninstall": "إزالة التثبيت", + "uninstalling": "جارٍ الإزالة", + "viewDetails": "عرض التفاصيل", + "save": "حفظ", + "saving": "جارٍ الحفظ", + "install": "تثبيت", + "refresh": "تحديث", + "newMcp": "MCP جديد", + "create": "إنشاء", + "creating": "جارٍ الإنشاء..." + }, + "tabs": { + "local": "MCP المحلي", + "market": "سوق MCP" + }, + "local": { + "filterPlaceholder": "تصفية MCP المحلي...", + "loadFailed": "فشل التحميل: {message}", + "empty": "لم يتم اكتشاف MCP محلي.", + "description": "يمكن تعديل إعداد MCP المحلي وحفظه مباشرة.", + "enabledApps": "التطبيقات المفعلة", + "configJson": "إعداد MCP (JSON)", + "draftTitle": "MCP جديد", + "draftDescription": "أدخل معرّف الخادم والإعدادات لإنشاء خادم MCP محلي.", + "serverIdLabel": "معرّف الخادم", + "serverIdPlaceholder": "معرّف الخادم (مثل: my-mcp)", + "typeHint": "الأنواع المدعومة: stdio و http (الأسماء البديلة: streamable-http و streamableHttp) و sse. يُستخدم env مع stdio فقط؛ خوادم MCP البعيدة تحمل رموز المصادقة عبر headers.", + "envOnRemoteWarning": "تم اكتشاف env على MCP بعيد. يُستخدم env مع stdio فقط؛ خوادم MCP البعيدة تحمل رموز المصادقة عبر headers، لذا سيتم تجاهل env عند الحفظ." + }, + "market": { + "selectMarketplace": "اختر السوق", + "searchPlaceholder": "ابحث عن MCP...", + "searchFailed": "فشل البحث: {message}", + "loadingList": "جارٍ تحميل قائمة MCP...", + "empty": "لا توجد نتائج MCP.", + "loadingDetail": "جارٍ تحميل تفاصيل السوق...", + "detailLoadFailed": "فشل تحميل التفاصيل: {message}", + "owner": "المالك: {owner}", + "namespace": "المجال: {namespace}", + "defaultInstallProtocol": "بروتوكول التثبيت الافتراضي", + "currentOptionParameterCount": "عدد معلمات الخيار الحالي: {count}", + "installConfigDescription": "إعداد التثبيت (JSON، قابل للتعديل قبل التثبيت؛ ستتجاوز التعديلات نموذج البروتوكول/المعلمات)", + "selectLeftToView": "اختر MCP من السوق في الجهة اليسرى لعرض التفاصيل." + }, + "badges": { + "verified": "موثّق", + "remote": "بعيد", + "hasHomepage": "له صفحة رئيسية", + "uses": "{count} استخدام", + "deployed": "منشور", + "notDeployed": "غير منشور" + }, + "selectLeftMcp": "اختر MCP من الجهة اليسرى." + }, + "AcpAgentSettings": { + "title": "إدارة Agent SDK", + "description": "أدر اتصال Agent SDK وحالة التمكين ومتغيرات البيئة وإدارة الإعدادات ومعلومات فحص الإصدار المسبق في مكان واحد.", + "loadingAgents": "جارٍ تحميل قائمة الوكلاء...", + "agentList": "قائمة الوكلاء", + "emptyNoAgent": "لا يوجد وكيل متاح.", + "configManagement": "إدارة الإعدادات", + "envVars": "متغيرات البيئة", + "hostTools": { + "label": "دع الوكيل يتولى الملفات والأوامر بنفسه", + "description": "يتوقف codeg عن تنفيذ الوصول إلى الملفات وأوامر الطرفية، فينفّذها الوكيل داخل عمليته الخاصة — وعندها فقط تُطبَّق البيئة المعزولة وقواعد الأذونات الخاصة به. كما يُعطَّل التفويض إلى وكلاء آخرين، لأنه سيعيد العمل نفسه عبر codeg. لا يضيف codeg بيئة معزولة من عنده، لذا فعّل هذا الخيار فقط إذا كان الوكيل قد أُعِدّت له واحدة." + }, + "nativeJsonConfig": "إعداد JSON أصلي", + "modelHintDefault": "اتركه فارغًا لاستخدام النموذج الافتراضي للنظام.", + "generalConfigDescriptionClaude": "يدعم الإعداد السريع لـ API URL وAPI Key ونماذج Claude، ويتزامن مع إعداد JSON الأصلي.", + "generalConfigDescriptionDefault": "يدعم إدخال الإعدادات المهمة (API URL وAPI Key وModel) وإدارة إعداد JSON الأصلي.", + "multiAgent": { + "title": "تعاون متعدد الوكلاء", + "description": "اسمح للوكلاء النشطين بتفويض المهام الفرعية إلى وكلاء آخرين.", + "enable": "تفعيل التفويض", + "enableHint": "عند الإيقاف، يتم إخفاء أداة delegate_to_agent من قائمة أدوات MCP الخاصة بالوكيل.", + "withheldByHostTools": "لن تحصل {agents} على أدوات التفويض: مفتاح «دع الوكيل يتولى الملفات والأوامر» الخاص بها مُفعّل.", + "selfInitiate": "Allow spawn without @", + "selfInitiateHint": "When on, an agent may start a listed sub-agent on its own. An @ mention is still always honored. When off, only an @ mention starts a sub-agent.", + "depthLimit": "أقصى عمق للتفويض", + "depthHint": "النطاق المسموح: {min}–{max}. يحدّ من عمق سلسلة التفويض (جذر ← فرعي ← حفيد …).", + "completedCacheLabel": "ذاكرة التخزين المؤقت للنتائج المكتملة (MB)", + "completedCacheHint": "ذاكرة تخزين مؤقتة في الذاكرة لنتائج الوكلاء الفرعيين المكتملة، تُحفظ فقط أثناء تشغيل جلسة التفويض وتُحرَّر تلقائيًا عند انتهاء تلك الجلسة. وعند تجاوز هذه الميزانية، تُسقَط أقدم النتائج من الذاكرة أولًا (تظل قابلة للعرض في جلسة الوكيل الفرعي نفسه)؛ 0 = غير محدود (وتُحرَّر مع ذلك عند انتهاء الجلسة).", + "save": "حفظ", + "saving": "جارٍ الحفظ…", + "saved": "تم حفظ إعدادات التفويض", + "saveFailed": "فشل حفظ إعدادات التفويض", + "loadFailed": "فشل تحميل إعدادات التفويض: {detail}", + "tabGeneral": "عام", + "tabAgentDefaults": "إعدادات الوكيل الفرعي", + "agentDefaultsDescription": "تجاوزات لكل وكيل تُطبَّق عندما يقوم التعاون متعدد الوكلاء بتشغيل وكيل فرعي لاستدعاء تفويض. تأتي الخيارات المعروضة هنا من فحص حي، لذا فإن ما تختاره هو بالضبط ما سيقبله الوكيل.", + "probing": "جارٍ تحميل الخيارات المتاحة من الوكيل…", + "probeFailed": "فشل تحميل الخيارات: {detail}", + "retry": "إعادة المحاولة", + "noConfigAvailable": "لا يحتوي هذا الوكيل على خيارات قابلة للضبط.", + "modeLabel": "الوضع", + "agentDefaultHint": "افتراضي الوكيل: {value}", + "defaultOptionLabel": "افتراضي ({value})" + }, + "actions": { + "dragSort": "اسحب لإعادة الترتيب", + "dragSortAgent": "اسحب لإعادة ترتيب {name}", + "refreshCheck": "تحديث الفحص", + "refreshCheckAgent": "تحديث فحص {name}", + "clickEnable": "انقر لتفعيل {name}", + "clickDisable": "انقر لتعطيل {name}", + "install": "تثبيت", + "upgrade": "ترقية", + "uninstall": "إزالة التثبيت", + "uninstalling": "جارٍ إزالة التثبيت...", + "saveEnvVars": "حفظ متغيرات البيئة", + "saving": "جارٍ الحفظ...", + "saveGrokConfig": "حفظ إعدادات Grok", + "saveCodexConfig": "حفظ إعداد Codex", + "saveGeminiConfig": "حفظ إعداد Gemini", + "saveOpenCodeConfig": "حفظ إعداد OpenCode", + "saveOpenClawConfig": "حفظ إعداد OpenClaw", + "saveConfigManagement": "حفظ إدارة الإعدادات", + "saveCurrentProvider": "حفظ المزود الحالي", + "showApiKey": "إظهار مفتاح API", + "hideApiKey": "إخفاء مفتاح API", + "showKey": "إظهار المفتاح", + "hideKey": "إخفاء المفتاح", + "showToken": "إظهار الرمز", + "hideToken": "إخفاء الرمز", + "cancel": "إلغاء", + "delete": "حذف", + "deleting": "جارٍ الحذف...", + "confirmDelete": "تأكيد الحذف", + "confirmUninstall": "تأكيد إزالة التثبيت", + "saveClineConfig": "حفظ تكوين Cline", + "saveHermesConfig": "حفظ تكوين Hermes", + "saveCodeBuddyConfig": "حفظ إعدادات CodeBuddy", + "saveKimiCodeConfig": "حفظ إعدادات Kimi Code", + "customInstall": "تثبيت مخصص", + "saveKimiCodeRawConfig": "Save config.toml", + "saveDeepSeekConfig": "حفظ إعدادات DeepSeek", + "diagnose": "تشخيص" + }, + "status": { + "enabled": "مفعّل", + "disabled": "معطّل", + "unchecked": "غير مفحوص", + "agentEnabledAria": "{name} مفعّل", + "agentEnabledSwitch": "مفتاح تفعيل {name}" + }, + "preflight": { + "count": "عناصر الفحص المسبق: {count}", + "notRun": "لم يتم تشغيل الفحوصات بعد." + }, + "grok": { + "configDescription": "اضبط Grok هنا. عناصر التحكم أدناه — وضع الأذونات، وجهد الاستدلال، ونموذج مخصّص اختياري (نقطة نهاية خاصة)، والضغط — تُدمج في ~/.grok/config.toml مع الحفاظ على مفاتيحك وتعليقاتك الأخرى. يستخدم تسجيل الدخول XAI_API_KEY أو `grok login`. تبقى المفاتيح الأخرى قابلة للتحرير ضمن «متقدم».", + "permissionModeLabel": "وضع الأذونات", + "permissionDefault": "السؤال في كل مرة", + "permissionAcceptEdits": "الموافقة التلقائية على التعديلات", + "permissionAuto": "موافقة تلقائية ذكية", + "permissionAlwaysApprove": "الموافقة دائمًا", + "reasoningEffortLabel": "جهد الاستدلال", + "effortLow": "منخفض (أسرع)", + "effortMedium": "متوسط (متوازن)", + "effortHigh": "مرتفع", + "effortXhigh": "الأقصى", + "optionDefault": "استخدام الافتراضي", + "authTitle": "المصادقة", + "authMode": "طريقة المصادقة", + "authModeApiKey": "مفتاح XAI API", + "authModeApiKeyHint": "المصادقة باستخدام XAI_API_KEY من وحدة تحكم xAI — للتشغيل غير التفاعلي أو بدون واجهة. يُخزَّن في بيئة هذا الوكيل.", + "authModeCustom": "نقطة نهاية مخصّصة", + "authModeCustomHint": "استخدم نقطة نهاية خاصة بك (BYO): عرّف نموذجًا مخصّصًا في الأسفل مع عنوان URL أساسي ومفتاح API خاصين به. يصبح النموذج الافتراضي لـ Grok.", + "subscriptionHint": "سجّل الدخول باستخدام `grok login` (SuperGrok / X Premium+). لا يُخزَّن أي مفتاح API.", + "loginHint": "نفّذ هذا في الطرفية لتسجيل الدخول، ثم أعد فتح هذه الإعدادات:", + "commandCopied": "تم نسخ الأمر إلى الحافظة", + "copyCommand": "نسخ الأمر", + "authKeyConfigured": "XAI_API_KEY مُهيَّأ.", + "authKeyMissing": "لم يتم تعيين XAI_API_KEY.", + "advancedToggle": "متقدم (config.toml الخام)", + "configTomlNative": "config.toml (أصلي)", + "configTomlHint": "يُحفظ حرفيًا كملف ~/.grok/config.toml بالكامل. يُرفض TOML غير الصالح حتى لا يقتطع خطأ مطبعي ملفك أبدًا.", + "configTomlPlaceholder": "# مفاتيح غير عناصر التحكم أعلاه، مثل\n# [mcp_servers.*] و[cli] وقواعد [permission].", + "customModelTitle": "نموذج مخصّص (نقطة نهاية خاصة)", + "customModelHint": "وجِّه Grok إلى نقطة نهاية مخصّصة أو مستضافة ذاتيًا. يكتب codeg كتلة `[model.*]` لكل نموذج ويجعلها النموذج الافتراضي. اترك معرّف النموذج فارغًا لإزالته.", + "customModelIdLabel": "معرّف النموذج", + "customModelIdPlaceholder": "grok-4.5", + "customModelIdHint": "يُسجَّل ككتلة `[model.*]` ويُرسَل إلى الـ API كاسم للنموذج؛ ويُضبط أيضًا كـ `[models].default`.", + "customBaseUrlLabel": "عنوان URL الأساسي", + "customBaseUrlPlaceholder": "https://api.x.ai/v1 (الافتراضي)", + "customApiBackendLabel": "الواجهة الخلفية لـ API", + "backendResponses": "Responses", + "backendChatCompletions": "Chat Completions", + "backendMessages": "Messages (Anthropic)", + "customApiKeyLabel": "مفتاح API", + "customApiKeyHint": "يُخزَّن ضمن `[model.*].api_key`، مقصورًا على نقطة النهاية هذه.", + "customContextWindowLabel": "نافذة السياق (رموز)", + "customContextWindowHint": "اختياري. يحدّد توقيت الضغط التلقائي؛ اتركه فارغًا لاستخدام القيمة الافتراضية لنقطة النهاية.", + "autoCompactLabel": "عتبة الضغط التلقائي (%)", + "autoCompactHint": "يضغط المحادثة عندما يبلغ استخدام السياق هذه النسبة المئوية (الافتراضي في Grok هو 85). يُكتَب في `[session]`." + }, + "cursor": { + "configDescription": "اضبط Cursor هنا. اختر طريقة مصادقة — اشتراك رسمي (تسجيل دخول عبر المتصفح) أو مفتاح Cursor API للأجهزة بدون واجهة أو الخوادم — ثم اختر نموذجًا وحرّر قواعد أذونات CLI وبيئة الحماية. يكتبها codeg في ~/.cursor/cli-config.json، بالمشاركة مع أداة cursor-agent.", + "authTitle": "المصادقة", + "authChecking": "جارٍ التحقق…", + "authNotInstalled": "cursor-agent غير مثبّت", + "authLoggedIn": "تم تسجيل الدخول", + "authNotLoggedIn": "غير مسجّل الدخول", + "loginHint": "شغّل هذا الأمر في الطرفية لتسجيل الدخول إلى حساب Cursor (سيفتح المتصفح)، ثم اضغط تحديث:", + "apiKeyLabel": "مفتاح Cursor API", + "apiKeyPlaceholder": "المفتاح من cursor.com/dashboard", + "apiKeyHint": "CURSOR_API_KEY — مفتاح حساب من لوحة تحكم Cursor، بديل لتسجيل الدخول عبر المتصفح للأجهزة بدون واجهة أو الخوادم. ليس مفتاحًا خارجيًا أو من OpenAI.", + "modelTitle": "النموذج الافتراضي", + "loadModels": "جلب النماذج", + "modelsUnavailable": "قائمة النماذج غير متاحة", + "modelHint": "يُمرَّر إلى CLI عبر ‎--model عند بدء الجلسة. اتركه افتراضيًا ليختار Cursor بنفسه.", + "permissionsTitle": "الأذونات ووضع الحماية", + "permissionsDescription": "محرّر بصري لقواعد أذونات CLI‏ (cli-config.json). القواعد المسموحة تُنفَّذ دون تأكيد؛ والمرفوضة تُحظر دائمًا.", + "permissionModeLabel": "وضع الأذونات", + "permissionModeDefault": "السؤال قبل التنفيذ (افتراضي)", + "permissionModeForce": "تشغيل كل شيء (--force)", + "permissionModeHint": "يبدأ وضع Run Everything الجلسات بـ --force: يُسمح تلقائيًا بجميع استدعاءات الأدوات باستثناء قواعد الرفض دون طلب تأكيد (قد تقيّده سياسة المؤسسة بقواعد السماح فقط). يسري على الجلسات الجديدة.", + "optionDefault": "افتراضي (غير محدد)", + "sandboxLabel": "وضع الحماية", + "sandboxEnabled": "مفعّل", + "sandboxDisabled": "معطّل", + "allowRulesLabel": "قواعد السماح", + "denyRulesLabel": "قواعد الرفض", + "addRule": "إضافة قاعدة", + "rulesSyntaxHint": "صيغة القواعد: Shell(أمر)، Read(مسار/نمط)، Write(مسار/نمط)، WebFetch(نطاق)، Mcp(خادم:أداة) — قواعد الرفض لها الأولوية دائمًا.", + "saveConfig": "حفظ الإعدادات", + "advancedToggle": "متقدم: cli-config.json الخام", + "advancedHint": "ملف ‎~/.cursor/cli-config.json كاملًا. الحفظ هنا يكتب الملف كما هو؛ أما عناصر التحكم أعلاه فتُدمج فيه.", + "saveRawConfig": "حفظ الملف", + "authMode": "طريقة المصادقة", + "subscriptionHint": "سجّل الدخول بحساب Cursor واستخدم نماذج Cursor.", + "customApiKeyRequired": "مفتاح Cursor API مطلوب.", + "authModeApiKey": "مفتاح Cursor API (بدون واجهة/خادم)", + "authModeApiKeyHint": "المصادقة باستخدام مفتاح API لحساب Cursor من لوحة تحكم Cursor (للأجهزة بدون واجهة أو الخوادم). هذا مفتاح حساب Cursor وليس نقطة نهاية خارجية/OpenAI — إذ يتصل cursor-agent بخادم Cursor الخاص فقط. لاستخدام نقطة نهاية متوافقة مع codex/OpenAI، استخدم وكيل Codex بدلاً من ذلك.", + "modelPickerPlaceholder": "ابحث عن النماذج…", + "modelNoMatch": "لا يوجد نموذج مطابق", + "modelsNeedAuth": "سجّل الدخول لتحميل قائمة النماذج.", + "modelDefaultBadge": "افتراضي" + }, + "deepseek": { + "configManagement": "إعدادات DeepSeek Harness", + "configDescription": "نقطة النهاية والمفتاح متغيّرا بيئة يقرأهما deepseek-acp عند الإقلاع. أما النموذج ومستوى الاستدلال فمحدِّدان على مستوى الجلسة، ويُختاران من حقل الإدخال.", + "baseUrlLabel": "نقطة نهاية API", + "baseUrlHint": "اتركه فارغًا لاستخدام نقطة النهاية الرسمية. يسري على الجلسات التي تبدأ بعد الحفظ؛ أعد الاتصال بالجلسة الجارية كي تأخذ القيمة الجديدة.", + "baseUrlInvalid": "أدخل عنوان http(s) كاملًا وبدون سلسلة استعلام، مثل https://api.deepseek.com", + "apiKeyLabel": "مفتاح API", + "apiKeyHint": "يُمرَّر إلى الوكيل باسم DEEPSEEK_API_KEY. متغيّر البيئة له أسبقية على ملف بيانات الاعتماد، لذا اترك الحقل فارغًا إن كنت تسجّل الدخول من الطرفية." + }, + "codex": { + "configDescription": "يدعم الإعداد السريع لعنوان API ومفتاح API واسم النموذج وجهد الاستدلال، مع المزامنة مع `auth.json` / `config.toml`.", + "authMode": "طريقة المصادقة", + "chatgptSubscription": "اشتراك رسمي", + "chatgptSubscriptionHint": "تسجيل الدخول باشتراك ChatGPT الرسمي، لا حاجة لـ API Key", + "apiKeyHint": "الاتصال باستخدام API Key بخدمات OpenAI أو الخدمات المتوافقة", + "selectProvider": "اختر المزود", + "modelName": "اسم النموذج", + "selectReasoningEffort": "اختر Reasoning Effort", + "enableWebsocket": "تفعيل WebSocket", + "enableWebsocketAria": "تفعيل WebSocket لـ Codex Provider", + "enableSkills": "تفعيل Skills", + "enableSkillsAria": "تفعيل Skills لـ Codex", + "enableFast": "تفعيل Fast", + "enableFastAria": "تفعيل مستوى خدمة Fast لـ Codex", + "sandboxGroupTitle": "بيئة العزل والموافقات", + "sandboxGroupHint": "تُكتب في ~/.codex/config.toml العام، لذا تراها أيضًا جلسات codex CLI وبيئة التطوير. هذه قيم افتراضية للمحادثة: تحكم الأدوار التي يبدأها codex بنفسه (‏/goal و‏/review و‏/compact). أما الرسائل العادية فتستخدم إعداد الموافقة المحدد في صندوق الإدخال. أعد تشغيل الجلسة لتطبيق التغييرات.", + "sandboxShadowedWarning": "يضبط config.toml المفتاح default_permissions، لذا يحسم codex الأذونات عبر ذلك الملف الشخصي ويتجاهل sandbox_mode تمامًا. احذف default_permissions لاستخدام عناصر التحكم أدناه.", + "sandboxPermissionsTableWarning": "يعرّف config.toml ملفات [permissions] دون default_permissions، وهو ما يمنع codex من العمل. اضبطه في المحرر الخام أدناه.", + "approvalPolicyLabel": "سياسة الموافقة", + "approvalPolicyUnset": "غير محددة (افتراضي codex: عند الطلب)", + "approvalPolicy_on-request": "عند الطلب — النموذج يقرر متى يسأل", + "approvalPolicy_untrusted": "غير موثوق — تُنفَّذ تلقائيًا أوامر القراءة الآمنة المعروفة فقط", + "approvalPolicy_never": "أبدًا — بدون أي طلبات موافقة", + "approvalPolicy_granular": "تفصيلي — اختر حسب نوع الطلب", + "approvalPolicyUntrustedAcpWarning": "لا يوجد مكافئ لـ untrusted بين إعدادات الموافقة الثلاثة في محوّل ACP، لذا تعود جلسات codeg إلى «عند الطلب»: يقرّر النموذج حينها متى يسأل، وتتوقف الأوامر التي تسمح بها البيئة المعزولة أصلاً عن طلب التأكيد. قيّد وضع العزل أدناه بدلاً من ذلك.", + "granularHint": "الإيقاف يعني رفض هذا النوع من الطلبات تلقائيًا بدلًا من عرضه عليك.", + "granular_sandbox_approval": "تصعيد صلاحيات أوامر الصدفة", + "granular_rules": "مطالبات قواعد execpolicy", + "granular_skill_approval": "مطالبات تنفيذ نصوص المهارات", + "granular_request_permissions": "مطالبات أداة request_permissions", + "granular_mcp_elicitations": "مطالبات elicitation في MCP", + "sandboxModeLabel": "وضع بيئة العزل", + "sandboxModeUnset": "غير محدد (المجلدات الموثوقة تعود إلى الكتابة في مساحة العمل)", + "sandboxMode_read-only": "قراءة فقط", + "sandboxMode_workspace-write": "الكتابة في مساحة العمل", + "sandboxMode_danger-full-access": "وصول كامل (بدون عزل)", + "sandboxModeHint": "على Windows، تُخفَّض الكتابة في مساحة العمل إلى قراءة فقط ما لم تُفعَّل بيئة العزل التجريبية الخاصة بـ codex.", + "sandboxModeSeedsPresetHint": "يستخدم codeg هذا أيضاً لتحديد إعداد الموافقة الأولي للجلسة، لذا فإنه — بخلاف سياسة الموافقة — يؤثر على الطلبات العادية. ويظل الإعداد المختار في مربع الإدخال هو الأسبق.", + "writableRootsLabel": "مجلدات إضافية قابلة للكتابة", + "writableRootsHint": "مسار مطلق واحد في كل سطر، إضافةً إلى مجلد العمل.", + "sandboxRootsRelativeError": "يجب أن يكون مسارًا مطلقًا — يحسم codex المسارات النسبية داخل ~/.codex: {path}", + "networkAccessLabel": "السماح بالوصول إلى الشبكة", + "excludeTmpdirLabel": "استبعاد TMPDIR من الجذور القابلة للكتابة", + "excludeSlashTmpLabel": "استبعاد /tmp من الجذور القابلة للكتابة", + "authJsonNative": "auth.json (أصلي)", + "configTomlNative": "config.toml (أصلي)", + "loginButton": "تسجيل الدخول باستخدام ChatGPT", + "loginRequesting": "جارٍ طلب رمز تسجيل الدخول...", + "loginStep1": "افتح الرابط التالي في متصفحك:", + "loginStep2": "أدخل الرمز أدناه:", + "loginPolling": "في انتظار التفويض...", + "loginCancel": "إلغاء", + "loginSuccess": "تم تسجيل الدخول بنجاح، تم حفظ الإعدادات!", + "loginFailed": "فشل تسجيل الدخول: {message}", + "loginRetry": "إعادة المحاولة", + "loginCodeCopied": "تم نسخ الرمز", + "loggedIn": "تم تسجيل الدخول", + "loginRelogin": "إعادة تسجيل الدخول / تبديل الحساب", + "loginTimeout": "انتهت مهلة تسجيل الدخول، يرجى المحاولة مرة أخرى", + "loginSaveFailed": "تم تسجيل الدخول بنجاح ولكن فشل حفظ الإعدادات" + }, + "gemini": { + "authConfig": "إعداد مصادقة Gemini", + "authConfigDescription": "متوافق مع وثائق مصادقة Gemini CLI، ويدعم endpoint مخصص وتسجيل دخول Google وGemini API Key وVertex AI ‏(ADC / حساب خدمة / API Key).", + "authMode": "وضع المصادقة", + "selectAuthMode": "اختر وضع المصادقة", + "viewAuthDoc": "عرض وثائق المصادقة", + "mode": { + "custom": "Endpoint مخصص", + "loginGoogle": "تسجيل دخول Google (OAuth)", + "vertexServiceAccount": "Vertex AI (حساب خدمة)" + }, + "hint": { + "custom": "أدخل API URL وAPI Key وModel؛ وسيتم ربطها بـ GOOGLE_GEMINI_BASE_URL / GEMINI_API_KEY / GEMINI_MODEL.", + "loginGoogle": "شغّل gemini في الطرفية وأكمل تسجيل دخول Google أولًا؛ لا حاجة إلى API key.", + "geminiApiKey": "أدخل GEMINI_API_KEY عند استخدام Gemini API.", + "vertexAdc": "استخدم gcloud ADC؛ ويوصى بتعيين GOOGLE_CLOUD_PROJECT وGOOGLE_CLOUD_LOCATION.", + "vertexServiceAccount": "عيّن مسار JSON لحساب الخدمة في GOOGLE_APPLICATION_CREDENTIALS.", + "vertexApiKey": "أدخل GOOGLE_API_KEY عند استخدام مفتاح Vertex AI API." + } + }, + "openCode": { + "configManagement": "إدارة إعداد OpenCode", + "configDescription": "متوافق مع مخطط `provider` في OpenCode، ويدعم إدارة متعددة المزودات ومزامنة ثنائية الاتجاه مع ملفات JSON الأصلية.", + "providerManagement": "إدارة المزودات", + "providerCount": "{count} مزودات", + "addProvider": "إضافة مزود", + "emptyProvider": "لا توجد مزودات مخصصة بعد. انقر على «إضافة مزود مخصص» لإنشاء واحد.", + "providerEnabledState": "حالة تفعيل {providerId}", + "selectProviderNpm": "اختر provider.npm", + "modelManagement": "إدارة النماذج", + "modelCount": "{count} نماذج", + "modelDescription": "متوافق مع `provider.models` في OpenCode. الإدارة السريعة تدعم حاليًا `name` / `id`؛ بينما تُحفظ الحقول المتقدمة الأخرى ويمكن تعديلها في JSON الأصلي أدناه.", + "addModel": "إضافة نموذج", + "emptyModel": "لا يوجد نموذج بعد. أدخل model id ثم انقر \"إضافة نموذج\".", + "modelId": "معرّف النموذج", + "modelName": "اسم النموذج", + "deleteModel": "حذف النموذج {modelId}", + "nativeJsonConfig": "إعداد JSON الأصلي لـ OpenCode", + "mainModel": "النموذج الرئيسي", + "smallModel": "النموذج الصغير", + "noMatchingModels": "لا توجد نماذج مطابقة", + "connectProvider": "ربط مزود", + "connectedProviders": "المزودون المتصلون", + "noConnectedProviders": "لم يتم ربط أي مزود من الكتالوج بعد.", + "advancedProviderConfig": "المزودات المخصصة", + "customProviderConfigHint": "نقاط نهاية متوافقة مع OpenAI تحددها بنفسك — كتلة provider في opencode.json، مع مفتاح API في auth.json.", + "addCustomProvider": "إضافة مزود مخصص", + "disconnect": "قطع الاتصال", + "editConfig": "تحرير", + "customBadge": "مخصص", + "authKindApi": "مفتاح API", + "authKindOauth": "OAuth", + "authKindNone": "لا توجد بيانات اعتماد", + "connect": { + "title": "ربط مزود", + "description": "اختر مزودًا من كتالوج models.dev. تُحفظ بيانات الاعتماد في ملف auth.json الخاص بـ OpenCode.", + "pick": "المزود", + "search": "البحث عن المزودين…", + "loading": "جارٍ تحميل الكتالوج…", + "catalogLabel": "كتالوج models.dev", + "modelsAvailable": "{count} نموذجًا متاحًا", + "getKey": "الحصول على مفتاح API", + "oauthApiKeyNote": "يدعم هذا المزود أيضًا تسجيل الدخول عبر المتصفح باستخدام opencode auth login. سيتوفر تسجيل الدخول عبر المتصفح قريبًا — في الوقت الحالي، الصق مفتاح API.", + "apiKey": "مفتاح API", + "apiKeyHint": "تُحفظ في auth.json وليس في opencode.json أبدًا.", + "baseUrlOptional": "تجاوز عنوان URL الأساسي (اختياري)", + "providerId": "معرّف المزود", + "displayName": "الاسم المعروض", + "modelsList": "النماذج (واحد في كل سطر)", + "modelsHint": "معرّفات النماذج التي تقبلها نقطة النهاية.", + "action": "ربط", + "editTitle": "تعديل المزود", + "editDescription": "حدّث مفتاح API أو عنوان URL الأساسي لهذا المزود.", + "saveAction": "حفظ" + }, + "customProvider": { + "title": "إضافة مزود مخصص", + "description": "حدّد نقطة نهاية متوافقة مع OpenAI. يُحفظ مفتاح API في auth.json، وتُكتب كتلة provider في opencode.json.", + "action": "إضافة المزود", + "idInCatalog": "{providerId} مزود معروف — قم بربطه عبر «ربط مزود» بدلاً من ذلك." + }, + "refreshCatalog": "تحديث الكتالوج", + "reasoningBadge": "استدلال", + "contextWindow": "نافذة السياق", + "permissions": { + "title": "الأذونات", + "description": "حدِّد أي الإجراءات تعمل تلقائيًا، وأيها يطلب موافقتك، وأيها يُحظر. يُكتب في مقطع permission داخل opencode.json ويُطبَّق عند الحفظ أدناه.", + "docsLink": "توثيق الأذونات", + "unparsableConfig": "تعذّر تحليل JSON الأصلي أدناه، لذا أُوقف المحرِّر المرئي مؤقتًا. صحّح JSON للمتابعة.", + "invalidBlock": "بنية مقطع permission غير معروفة لدى codeg. عدِّلها في JSON الأصلي أدناه أو استخدم إعادة الضبط للبدء من جديد.", + "orderingUnsafe": "كُتبت قاعدة عامة بعد أدوات محددة، لذا يطبّقها OpenCode عليها أيضًا — الصفوف أدناه ليست ما هو نافذ فعلًا. «تصحيح الترتيب» يعيد كل قاعدة عامة إلى بداية نطاقها فقط، دون تغيير أي قيمة.", + "orderingUnsafeManual": "قاعدة محجوبة بنمط أعمّ مكتوب بعدها، لذا لا يطبّقها OpenCode أبدًا — الصفوف أدناه ليست ما هو نافذ فعلًا. لا يوجد ترتيب صحيح وحيد لنمطين متداخلين؛ أعد ترتيبهما في JSON الأصلي بحيث يأتي الأعمّ أولًا.", + "fixOrder": "تصحيح الترتيب", + "agentOverrides": "هذه الوكلاء تتجاوز الأذونات وتُطبَّق أخيرًا، لذا تتغلب على كل ما هنا: {agents}. عدّلها في JSON الأصلي أدناه، أو فعّل القبول التلقائي لمسحها.", + "legacyTools": "خريطة tools القديمة في المستوى الأعلى ترفض إحدى الأدوات. يدمجها OpenCode ضمن الأذونات، لذا تُطبَّق فوق كل ما يظهر هنا. عدّلها في JSON الأصلي أدناه، أو فعّل القبول التلقائي لمسحها.", + "autoAcceptTitle": "قبول جميع الأذونات تلقائيًا", + "autoAcceptHint": "تُنفَّذ كل استدعاءات الأدوات — أوامر الصدفة وتعديلات الملفات والمسارات خارج المشروع — دون سؤال. تفعيله يستبدل إعدادات كل أداة أدناه بقاعدة واحدة تسمح بكل شيء، ويمسح تجاوزات كل وكيل ومفاتيح tools القديمة التي كانت ستستمر في الحجب.", + "globalLabel": "الإعداد العام الافتراضي", + "globalHint": "قاعدة *: تنطبق على كل ما لا تتجاوزه الأدوات أدناه.", + "actionUnset": "غير محدد (افتراضيات OpenCode)", + "actionInherit": "اتباع الافتراضي ({action})", + "actionAllow": "سماح", + "actionAsk": "سؤال", + "actionDeny": "رفض", + "perToolTitle": "أذونات كل أداة", + "reset": "إعادة الضبط", + "ruleCount": "القواعد: {count}", + "rulesToggle": "القواعد التفصيلية للأداة {tool}", + "rulesHint": "تُطابَق مع مدخلات الأداة، وتفوز آخر مطابقة، لذا ضع الأنماط الواسعة أولًا. الرمز * يطابق أي عدد من المحارف، و? يطابق محرفًا واحدًا بالضبط، و~ في البداية يتوسّع إلى مجلد المنزل.", + "noRules": "لا توجد قواعد تفصيلية بعد.", + "addRule": "إضافة قاعدة", + "deleteRule": "حذف القاعدة {pattern}", + "duplicateRule": "هذا النمط موجود بالفعل.", + "blankRule": "القاعدة تحتاج إلى نمط — استخدم أيقونة سلة المهملات لحذفها.", + "customKeys": "مفاتيح أذونات أخرى في الملف", + "customKeyHint": "ليست أداة مدمجة في OpenCode — تُحفظ كما هي.", + "keys": { + "bash": "تشغيل أوامر الصدفة، بمطابقة الأمر بعد تحليله", + "edit": "كل تعديلات الملفات: edit وwrite وpatch", + "read": "قراءة الملفات، بمطابقة المسار", + "external_directory": "الوصول إلى مسارات خارج مجلد عمل المشروع", + "task": "تشغيل الوكلاء الفرعيين، بمطابقة نوع الوكيل الفرعي", + "skill": "تحميل المهارات، بمطابقة اسم المهارة", + "glob": "العثور على الملفات، بمطابقة نمط glob", + "grep": "البحث في محتوى الملفات، بمطابقة النمط", + "list": "سرد محتويات المجلد", + "webfetch": "جلب عنوان URL", + "websearch": "البحث في الويب", + "lsp": "تشغيل استعلامات LSP", + "todowrite": "كتابة قائمة المهام", + "question": "طرح سؤال عليك", + "doom_loop": "يُفعَّل عند تكرار الاستدعاء نفسه ثلاث مرات بالمدخلات نفسها" + } + } + }, + "openClaw": { + "gatewayConfig": "إعداد Gateway", + "gatewayDescription": "قم بإعداد اتصال OpenClaw Gateway. يدعم gateway محليًا أو بعيدًا.", + "gatewayUrlHint": "اتركه فارغًا لاستخدام gateway.remote.url من إعداد openclaw المحلي.", + "gatewayTokenPlaceholder": "رمز مصادقة Gateway", + "gatewayTokenHint": "يُفضّل استخدام token-file بدل الرمز النصي متى أمكن؛ قم بالإعداد عبر openclaw CLI.", + "sessionKeyHint": "اختياري. حدّد مفتاح جلسة gateway؛ واتركه فارغًا للتعيين التلقائي لجلسة معزولة." + }, + "hermes": { + "configManagement": "تكوين Hermes", + "configDescription": "يدير Hermes بيانات اعتماده الخاصة في ~/.hermes/.env والإعدادات في ~/.hermes/config.yaml. اختر مزوّدًا، ثم عيّن مفتاح API والنموذج — وسيكتب codeg كلا الملفين نيابةً عنك.", + "providerLabel": "المزوّد", + "providerHint": "يحدّد المزوّد متغيّر مفتاح API و model.provider الذي يستخدمه Hermes. تُهيَّأ مزوّدات OAuth عبر إعداد الطرفية أدناه.", + "groupApiKey": "مزودو مفاتيح API", + "groupOauth": "مزودو OAuth", + "groupAws": "AWS", + "apiKeyHint": "يُحفظ في ~/.hermes/.env. ولا يُحقَن أبدًا في العملية — إذ يقرؤه Hermes من تكوينه الخاص.", + "modelName": "النموذج", + "oauthHint": "يستخدم هذا المزوّد OAuth. شغّل الإعداد أدناه للمصادقة في طرفيتك.", + "awsHint": "يستخدم Bedrock بيانات اعتماد AWS الخاصة بك (البيئة أو الإعداد المشترك). حدّد معرّف النموذج أعلاه واضبط وصول AWS في بيئتك.", + "unsupportedProvider": "لا يمكن تحرير هذا المزود عبر الحقول المنظمة. استخدم محرر config.yaml أدناه أو الإعداد عبر الطرفية.", + "setupTitle": "إعداد ذاتي الإدارة", + "setupHint": "يحتاج إعداد Hermes التفاعلي إلى طرفية. شغّله أدناه، أو انسخ الأمر لتشغيله بنفسك.", + "runSetup": "تشغيل إعداد Hermes", + "configureModel": "تهيئة النموذج", + "openConfigFolder": "فتح ~/.hermes", + "copyCommand": "نسخ الأمر", + "commandCopied": "تم نسخ الأمر إلى الحافظة", + "advancedTitle": "متقدّم: تحرير config.yaml", + "rawConfigHint": "حرّر ~/.hermes/config.yaml مباشرةً. الحفظ هنا يستبدل الملف حرفيًا.", + "saveRawConfig": "حفظ config.yaml" + }, + "codebuddy": { + "configManagement": "تكوين CodeBuddy", + "configDescription": "يصادق CodeBuddy باستخدام مفتاح API. تتطلب إصدارات الصين أيضًا ضبط البيئة على «الصين (internal)»؛ وتستخدم إصدارات iOA «iOA». أما الإصدار الخارجي فيتركها غير مضبوطة.", + "apiKeyLabel": "مفتاح API", + "apiKeyHint": "يُحفظ باسم CODEBUDDY_API_KEY لهذا الوكيل. بدلاً من ذلك، يمكنك تسجيل الدخول عبر واجهة CodeBuddy في الطرفية.", + "apiKeyHintSelfHosted": "يُحفظ باسم CODEBUDDY_API_KEY لهذا الوكيل. استخدم المفتاح الصادر عن نشرك الخاص.", + "environmentLabel": "البيئة", + "environmentHint": "يضبط CODEBUDDY_INTERNET_ENVIRONMENT. يجب أن تستخدم الصين «الصين (internal)»؛ أما الإصدار الخارجي فيتركها غير مضبوطة.", + "envOverseas": "الخارجي (افتراضي)", + "envChina": "الصين (internal)", + "envIoa": "iOA", + "envSelfHosted": "استضافة ذاتية (نشر خاص)", + "baseUrlLabel": "عنوان URL للنشر", + "baseUrlPlaceholder": "https://codebuddy.your-company.com", + "baseUrlHint": "يُحفظ باسم CODEBUDDY_BASE_URL ويوجّه CodeBuddy إلى نقطة النهاية الخاصة بك. في الاستضافة الذاتية يبقى إعداد الشبكة (CODEBUDDY_INTERNET_ENVIRONMENT) غير مضبوط.", + "baseUrlInvalid": "أدخل عنوان URL صالحًا بصيغة http(s).", + "loginHint": "لا تملك مفتاح API؟ شغّل «codebuddy» في الطرفية لتسجيل الدخول بحساب Tencent بدلاً من ذلك." + }, + "kimiCode": { + "configManagement": "إعدادات Kimi Code", + "configDescription": "لا يقبل `kimi acp` سوى رمز تسجيل دخول مخزَّن، لذا يكتب codeg مزوّدًا مُدارًا في ~/.kimi-code/config.toml ويزرع رمز بوابة محليًا — أما الاستدلال فيظل يعمل بمفتاحك أنت.", + "statusUnconfigured": "لم يُضبط بعد", + "statusDirty": "تغييرات غير محفوظة", + "summaryLabel": "المطبَّق حاليًا", + "gateReadyApiKey": "تمت كتابة مفتاح API في config.toml", + "gateReadyLogin": "تم تسجيل الدخول بحساب Kimi", + "revealConfig": "إظهار في المجلد", + "envOverrideWarning": "المتغير {keys} مضبوط وله أولوية على config.toml. الحفظ هنا يزيله.", + "authModeLabel": "طريقة المصادقة", + "authModeApiKey": "مفتاح API", + "authModeLogin": "تسجيل الدخول بحساب Kimi (اشتراك)", + "authModeApiKeyHint": "يكتب مزوّدًا مُدارًا في config.toml ويزرع رمز البوابة كي تتمكن الجلسات من الفتح.", + "loginHint": "شغّل `kimi login` في الطرفية لتسجيل الدخول بحساب اشتراك Kimi. لا يخزّن codeg أي بيانات اعتماد بل يعيد استخدام تسجيل دخول Kimi نفسه. الحفظ هنا يزيل رمز بوابة مفتاح API الخاص بـ codeg.", + "credentialTitle": "بيانات الاعتماد", + "interfaceTypeLabel": "نوع المزوّد", + "interfaceTypeHint": "بروتوكول المزوّد الذي يتحدث به Kimi (الحقل `type` في config.toml). اختر Kimi / Moonshot لمفتاح من Moonshot أو platform.kimi.com.", + "endpointLabel": "نقطة النهاية", + "endpointCustom": "مخصّص (متوافق مع OpenAI)", + "endpointHint": "دولي = api.moonshot.ai؛ الصين (مفاتيح platform.kimi.com) = api.moonshot.cn. أما المخصّص فيشير إلى أي نقطة نهاية متوافقة مع OpenAI.", + "regionInternational": "دولي (api.moonshot.ai)", + "regionChina": "الصين (api.moonshot.cn)", + "baseUrlLabel": "عنوان URL الأساسي", + "baseUrlHint": "اتركه فارغًا لاستخدام القيمة الافتراضية لحزمة SDK الخاصة بالمزوّد.", + "apiKeyLabel": "مفتاح API", + "apiKeyHint": "يُكتب في ~/.kimi-code/config.toml ويُستخدم للاستدلال. من platform.kimi.com أو platform.kimi.ai.", + "vertexProjectLabel": "مشروع GCP‏ (GOOGLE_CLOUD_PROJECT)", + "vertexLocationLabel": "منطقة GCP‏ (GOOGLE_CLOUD_LOCATION)", + "vertexHint": "يستخدم Vertex AI بيانات اعتماد التطبيق الافتراضية من Google — شغّل `gcloud auth application-default login` (بدون مفتاح API).", + "modelTitle": "النموذج", + "modelLabel": "النموذج", + "modelHint": "معرّف النموذج الذي يُكتب في config.toml. استخدم «اختبار وجلب النماذج» لمعرفة ما يمكن لمفتاحك الوصول إليه فعليًا.", + "maxContextLabel": "أقصى حجم للسياق", + "maxContextHint": "مطلوب وفق مخطط Kimi: بدونه يتجاهل Kimi كتلة النموذج بالكامل فلا يعود أي طلب بإجابة. القيمة الافتراضية 262144.", + "fetchModels": "اختبار وجلب النماذج", + "fetchModelsOk": "المفتاح يعمل — {count} نموذجًا متاحًا", + "fetchModelsEmpty": "المفتاح يعمل، لكن لم تُرجَع أي نماذج", + "fetchModelsFailed": "فشل الاختبار", + "fetchModelsNeedsKey": "أدخل أولًا مفتاح API ونقطة النهاية", + "modelNotInList": "هذا النموذج ليس ضمن القائمة التي يستطيع مفتاحك الوصول إليها — سيفشل Kimi برسالة «النموذج غير موجود».", + "reasoningTitle": "الاستدلال", + "reasoningEnableLabel": "تفعيل", + "reasoningDescription": "لا يعرض Kimi محدِّد «Thinking» في صندوق الإدخال إلا إذا أعلن النموذج عن قدرة استدلال، ولذلك يكتبها codeg هنا. يسري على الجلسات الجديدة.", + "effortsLabel": "المستويات المتاحة", + "effortsHint": "تصبح هذه المستويات خيارات محدِّد «Thinking». يمرِّر Kimi المستوى إلى المزوّد كما هو، فاختر ما يقبله نموذجك.", + "effortsEmptyHint": "من دون اختيار أي مستوى، يتراجع صندوق الإدخال إلى مفتاح Off / On فقط.", + "effortsCustomPlaceholder": "أضف مستوى آخر", + "effortsAdd": "إضافة", + "defaultEffortLabel": "المستوى الافتراضي", + "defaultEffortAuto": "اترك الاختيار لـ Kimi", + "alwaysThinkingLabel": "النموذج يستدل دائمًا — أزل خيار Off من المحدِّد", + "fixErrorsFirst": "صحّح الحقول المميّزة أولًا", + "errorModelRequired": "النموذج حقل مطلوب", + "errorMaxContextRequired": "أقصى حجم للسياق حقل مطلوب", + "errorMaxContextInvalid": "يجب أن يكون عددًا صحيحًا موجبًا", + "errorApiKeyRequired": "مفتاح API حقل مطلوب", + "errorApiKeyInvalid": "يجب ألا يحتوي مفتاح API على فواصل أسطر", + "errorBaseUrlRequired": "عنوان URL الأساسي حقل مطلوب", + "errorBaseUrlInvalid": "يجب أن يبدأ بـ http:// أو https://", + "errorVertexProjectRequired": "مشروع GCP حقل مطلوب", + "errorDefaultEffortUnlisted": "اختر أحد المستويات المحددة أعلاه", + "advancedTitle": "خيارات متقدمة", + "authTypeLabel": "موضع كتابة بيانات الاعتماد", + "authTypeApiKey": "‏api_key مضمَّن", + "authTypeEnv": "جدول env الفرعي للمزوّد", + "authTypeHint": "الموضع الذي يُكتب فيه مفتاح API داخل config.toml.", + "rawEditorLabel": "تحرير config.toml مباشرة", + "rawEditorWarning": "الحفظ هنا يستبدل الملف بأكمله حرفيًا، ويحل محل الإعدادات المنظَّمة أعلاه.", + "rawEditorPlaceholder": "[providers.codeg]\ntype = \"kimi\"\nbase_url = \"https://api.moonshot.cn/v1\"\napi_key = \"sk-...\"" + }, + "authModeOfficialSubscription": "الاشتراك الرسمي", + "authModeCustomEndpoint": "نقطة نهاية مخصصة", + "authModeCustomEndpointHint": "تكوين عنوان API ومفتاح API يدوياً لنقطة نهاية مخصصة.", + "authModeModelProvider": "مزود النموذج", + "modelProvider": "مزود النموذج", + "modelProviderHint": "استخدم عنوان API ومفتاح API والنموذج من مزود نموذج مُعدّ.", + "selectModelProvider": "اختر مزود النموذج", + "noModelProviderAvailable": "لا يوجد مزود نموذج مُعدّ لهذا الوكيل. انتقل إلى إعدادات مزود النموذج لإضافة واحد.", + "claude": { + "authMode": "وضع المصادقة", + "officialSubscription": "الاشتراك الرسمي", + "officialSubscriptionHint": "استخدم اشتراك Anthropic الرسمي، لا حاجة لمفتاح API.", + "mainModel": "النموذج الرئيسي", + "reasoningModel": "نموذج الاستدلال (thinking)", + "haikuDefaultModel": "نموذج Haiku الافتراضي", + "sonnetDefaultModel": "نموذج Sonnet الافتراضي", + "opusDefaultModel": "نموذج Opus الافتراضي", + "customModelOption": "معرّف النموذج المخصّص", + "customModelOptionName": "اسم النموذج المخصّص", + "customModelOptionDescription": "وصف النموذج المخصّص", + "customModelOptionHint": "يضيف عنصرًا مخصّصًا واحدًا إلى محدِّد نماذج Claude (مثل نموذج خلف بوابة/وكيل مخصّص). الاسم والوصف اختياريان لأغراض العرض فقط.", + "effortLevel": "مستوى الاستدلال", + "effortLevelDefault": "المستوى الافتراضي", + "effortLevel_low": "منخفض", + "effortLevel_medium": "متوسط", + "effortLevel_high": "مرتفع", + "effortLevel_xhigh": "مرتفع جداً", + "sendAttributionHeader": "إرسال معرّف الإسناد/الفوترة إلى الواجهة", + "sendAttributionHeaderAria": "إرسال معرّف الإسناد/الفوترة الخاص بـ Claude Code إلى الواجهة", + "disableNonessentialTraffic": "تعطيل القياس عن بُعد أو طلبات الشبكة غير الضرورية", + "disableNonessentialTrafficAria": "تعطيل القياس عن بُعد أو طلبات الشبكة غير الضرورية في Claude Code" + }, + "dialogs": { + "confirmDeleteProvider": "حذف المزود {providerId}؟", + "confirmDeleteProviderDescription": "سيتم تحديث إعداد OpenCode وauth JSON معًا. لا يمكن التراجع عن هذا الإجراء.", + "confirmUninstall": "إزالة تثبيت {name}؟", + "confirmUninstallDescription": "سيؤدي هذا إلى إزالة الإصدار المثبت محليًا. يمكنك إعادة التثبيت لاحقًا.", + "customInstallTitle": "تثبيت مخصص لـ {name}", + "customInstallDescription": "أدخل الإصدار المراد تثبيته. سيؤدي ذلك إلى إعادة التثبيت واستبدال الإصدار المثبت حاليًا.", + "customInstallVersionLabel": "رقم الإصدار", + "customInstallInvalid": "أدخل رقم إصدار صالحًا، مثل 1.2.3.", + "customInstallSubmit": "تثبيت" + }, + "errors": { + "windowsFileLocked": "ملفات {name} قيد الاستخدام بواسطة جلسة قيد التشغيل، لذا لا يمكن لـ Windows استبدالها. أغلق جميع جلسات {name} ثم حاول مرة أخرى.", + "nativeJsonMustBeObject": "يجب أن يكون إعداد JSON الأصلي كائنًا", + "nativeJsonInvalid": "خطأ في تنسيق إعداد JSON الأصلي: {message}", + "openCodeAuthMustBeObject": "يجب أن يكون OpenCode auth.json كائن JSON", + "openCodeAuthInvalid": "خطأ في تنسيق OpenCode auth.json: {message}", + "authMustBeObject": "يجب أن يكون auth.json كائن JSON", + "authInvalid": "خطأ في تنسيق auth.json: {message}", + "providerIdPattern": "يدعم معرّف المزود الأحرف والأرقام والشرطة السفلية والنقطة والشرطة فقط", + "providerExists": "المزوّد {providerId} موجود بالفعل", + "modelIdPattern": "يدعم معرّف النموذج الأحرف والأرقام والشرطة السفلية والنقطة والنقطتين والشرطة فقط", + "modelExists": "النموذج {modelId} موجود بالفعل" + }, + "warnings": { + "nativeJsonRecoveredStructured": "إعداد JSON الأصلي غير صالح؛ تمت إعادة التعيين إلى إعداد مُهيكل", + "nativeJsonRecoveredOpenCode": "إعداد JSON الأصلي غير صالح؛ تمت إعادة التعيين إلى إعداد OpenCode المُهيكل", + "openCodeAuthRecovered": "ملف OpenCode auth.json غير صالح؛ تمت إعادة التعيين إلى الإعداد الافتراضي", + "authRecoveredStructured": "ملف auth.json غير صالح؛ تمت إعادة التعيين إلى إعداد مُهيكل" + }, + "toasts": { + "agentActionCompleted": "اكتمل {action} لـ {name}", + "agentActionFailed": "فشل {action} لـ {name}", + "localVersion": "الإصدار المحلي: {version}", + "installCompletedVersionLater": "اكتمل التثبيت، سيتم تحديث الإصدار عند الفحص التالي", + "uninstallCompleted": "اكتملت إزالة تثبيت {name}", + "uninstallFailed": "فشلت إزالة تثبيت {name}", + "localVersionRemoved": "تمت إزالة الإصدار المحلي", + "saveAgentOrderFailed": "فشل حفظ ترتيب Agent", + "saveAgentSwitchFailed": "فشل حفظ مفتاح Agent", + "saveEnvFailed": "فشل حفظ متغيرات البيئة", + "grokSaved": "تم حفظ إعدادات Grok", + "saveGrokNativeFailed": "فشل حفظ إعدادات Grok الأصلية", + "saveGrokApiKeyFailed": "تم حفظ الإعدادات، لكن تعذّر حفظ مفتاح API", + "cursorSaved": "تم حفظ إعدادات Cursor", + "saveCursorConfigFailed": "فشل حفظ إعدادات Cursor", + "codexSaved": "تم حفظ إعداد Codex", + "saveCodexNativeFailed": "فشل حفظ إعداد Codex الأصلي", + "geminiSaved": "تم حفظ إعداد Gemini", + "saveGeminiFailed": "فشل حفظ إعداد Gemini", + "providerDeleted": "تم حذف المزود {providerId}", + "providerDeleteFailed": "فشل حذف المزود {providerId}", + "providerSaved": "تم حفظ المزود {providerId}", + "saveProviderFailed": "فشل حفظ المزود {providerId}", + "openCodeConfigSynced": "تمت مزامنة إعداد OpenCode وauth JSON.", + "openCodeSaved": "تم حفظ إعداد OpenCode", + "saveOpenCodeFailed": "فشل حفظ إعداد OpenCode", + "openClawSaved": "تم حفظ إعداد OpenClaw", + "saveOpenClawFailed": "فشل حفظ إعداد OpenClaw", + "configSaved": "تم حفظ الإعداد", + "configSavedHint": "يجب إعادة فتح الجلسات الحالية لتطبيق التغييرات", + "saveConfigManagementFailed": "فشل حفظ إدارة الإعدادات", + "clineSaved": "تم حفظ تكوين Cline", + "saveClineFailed": "فشل في حفظ تكوين Cline", + "hermesSaved": "تم حفظ تكوين Hermes", + "saveHermesFailed": "فشل في حفظ تكوين Hermes", + "codeBuddySaved": "تم حفظ إعدادات CodeBuddy", + "saveCodeBuddyFailed": "فشل حفظ إعدادات CodeBuddy", + "kimiCodeSaved": "تم حفظ إعدادات Kimi Code", + "saveKimiCodeFailed": "فشل حفظ إعدادات Kimi Code", + "deepseekSaved": "تم حفظ إعدادات DeepSeek", + "saveDeepSeekFailed": "تعذّر حفظ إعدادات DeepSeek", + "modelProviderRequired": "يرجى اختيار مزود نموذج قبل الحفظ.", + "affectedRunningSessions": "{count} جلسة نشطة تحتاج إلى إعادة الاتصال لتطبيق التغيير", + "providerConnected": "تم ربط {providerId}", + "connectFailed": "فشل ربط {providerId}", + "providerDisconnected": "تم قطع اتصال {providerId}", + "disconnectFailed": "فشل قطع اتصال {providerId}", + "catalogRefreshed": "تم تحديث الكتالوج — {count} مزودًا", + "catalogRefreshFailed": "فشل تحديث الكتالوج", + "piSaved": "تم حفظ إعدادات Pi", + "savePiFailed": "فشل حفظ إعدادات Pi", + "piRuntimeSaved": "تم حفظ وقت تشغيل Pi", + "savePiRuntimeFailed": "فشل حفظ وقت تشغيل Pi", + "piBinaryInstalled": "تم تثبيت pi", + "piBinaryInstallFailed": "فشل تثبيت pi", + "piBinaryUninstalled": "تم إلغاء تثبيت pi", + "piBinaryUninstallFailed": "فشل إلغاء تثبيت pi", + "savePiTrustFailed": "فشل حفظ الثقة بمساحة العمل" + }, + "version": { + "statusLabel": "حالة الإصدار", + "notInstalled": "غير مثبت", + "remoteLocal": "البعيد: {remoteVersion} · المحلي: {localVersion}", + "localOnly": "المحلي: {localVersion}", + "localInstalled": "{versionText}. مثبت.", + "platformUnsupported": "{versionText}. المنصة الحالية لا تدعم هذا الوكيل.", + "uvxNotReady": "{versionText}. وقت تشغيل uv غير مثبّت — ثبّته من فحص uv بالأسفل لاستخدام هذا الوكيل.", + "clickInstall": "{versionText}. انقر تثبيت في الجهة اليمنى.", + "localUnrecognized": "{versionText}. الإصدار المحلي غير قابل للمقارنة؛ جرّب الترقية للكتابة فوق التثبيت.", + "upgradeAvailable": "{versionText}. تتوفر ترقية.", + "remoteUnavailable": "{versionText}. الإصدار البعيد غير متاح حاليًا.", + "latest": "{versionText}. أنت على أحدث إصدار." + }, + "adapter": { + "label": "محوّل ACP", + "badge": "محوّل ACP", + "badgeHint": "بالنسبة لهذا الوكيل يثبّت Codeg حزمة محوّل ACP وليس واجهة الأوامر الرسمية. الاثنان مستقلان ويتشاركان الإعدادات نفسها.", + "learnMore": "معرفة المزيد", + "missingWithNative": "تم العثور على {nativeLabel} الخاصة بك في {nativePath}. يتواصل Codeg مع الوكلاء عبر ACP، وهذه الواجهة لا تدعم ACP، لذا يحتاج Codeg إلى حزمة محوّل منفصلة هي {adapterPackage}، يتولى صيانتها مشروع Agent Client Protocol (بدأه فريق Zed). تأتي ببيئة تشغيل خاصة بها، ولا تعدّل أمر {nativeCmd} لديك ولا تستبدله، وتقرأ المسار {configDir} نفسه — فتسجيل الدخول والإعدادات الحالية تبقى كما هي. ثبّتها من الأسفل.", + "missing": "يتواصل Codeg مع الوكلاء عبر ACP، و{nativeLabel} لا تدعم ACP، لذا يحتاج Codeg إلى حزمة محوّل منفصلة هي {adapterPackage}، يتولى صيانتها مشروع Agent Client Protocol (بدأه فريق Zed). تأتي ببيئة تشغيل خاصة بها، فلا حاجة لتثبيت {nativeCmd} أولاً؛ وإن كانت لديك فالاثنان يتعايشان ويتشاركان تسجيل الدخول والإعدادات في {configDir}. ثبّتها من الأسفل.", + "readyWithNative": "المحوّل {adapterCmd} مثبّت — وهو ما يشغّله Codeg، وليس {nativeCmd} الخاص بك في {nativePath}. هما حزمتان مستقلتان تتعايشان، وكلتاهما تقرأ {configDir}، لذا فتسجيل الدخول والإعدادات مشتركة.", + "ready": "المحوّل {adapterCmd} مثبّت — وهو ما يشغّله Codeg. يأتي ببيئة تشغيل خاصة به، لذا لا حاجة إلى {nativeLabel}؛ وإن ثبّتها لاحقاً فالاثنان يتعايشان ويتشاركان {configDir}." + }, + "cline": { + "configDescription": "تكوين مزود واجهة برمجة التطبيقات وبيانات اعتماد Cline. يتم حفظ الإعدادات في ~/.cline/data/." + }, + "opencodePlugins": { + "title": "إضافات OpenCode", + "declared": "الإضافات المعلنة", + "noPlugins": "لا توجد إضافات معلنة في opencode.json", + "status": { + "installed": "مثبّت", + "missing": "غير مثبّت" + }, + "installAll": "تثبيت جميع الإضافات المفقودة", + "pinVersions": "تثبيت إصدارات @latest", + "install": "تثبيت", + "uninstall": "إزالة", + "refresh": "تحديث", + "success": "تم تثبيت جميع الإضافات بنجاح", + "failed": "فشلت عملية الإضافة" + }, + "pi": { + "configManagement": "إعدادات Pi", + "configDescription": "يصادق Pi عبر مفتاح API لمزوّد النموذج. يُكتب المفتاح في ~/.pi/agent/auth.json واختيار النموذج في settings.json.", + "providerLabel": "المزوّد", + "modelLabel": "النموذج", + "thinkingLabel": "التفكير", + "thinking": { + "off": "إيقاف", + "low": "منخفض", + "medium": "متوسط", + "high": "مرتفع", + "minimal": "الحد الأدنى", + "xhigh": "مرتفع جدًا" + }, + "apiKeyLabel": "مفتاح API", + "apiKeyHint": "يُحفظ في ~/.pi/agent/auth.json للمزوّد المحدد.", + "apiKeySetPlaceholder": "•••••• (محفوظ — اتركه فارغًا للإبقاء عليه)", + "saveConfig": "حفظ إعدادات Pi", + "providerModelRequired": "المزوّد والنموذج مطلوبان", + "runtimeTitle": "وقت التشغيل", + "runtimeDescription": "اختر أي ملف pi يعمل. استخدم الافتراضي أو أشِر إلى بناء pi الخاص بك.", + "modeDefault": "pi الافتراضي", + "modeDefaultHint": "يستخدم محوّل pi-acp المدمج مع pi الموجود في PATH. ثبّت pi عبر: npm install -g @earendil-works/pi-coding-agent", + "modeCustom": "pi مخصّص", + "modeCustomHint": "شغّل بناء pi أو تثبيته أو غلافه الخاص بك.", + "commandLabel": "أمر pi أو مساره", + "commandHint": "مسار مطلق، أو اسم أمر في PATH، أو نص غلاف (مثل ./pi-test.sh في monorepo).", + "commandNotFound": "الأمر غير موجود", + "validate": "تحقّق", + "advanced": "متقدّم", + "configDirLabel": "دليل الإعدادات (PI_CODING_AGENT_DIR)", + "sessionDirLabel": "دليل الجلسات (PI_CODING_AGENT_SESSION_DIR)", + "flagsHint": "لا يمرّر pi-acp رايات pi المخصّصة (‎--approve، ‎-e، …) — غلّف pi بنص وأشِر الأمر إليه.", + "customIncomplete": "أدخل أمر pi للحفظ", + "saveRuntime": "حفظ وقت التشغيل", + "providerPlaceholder": "اختر مزوّدًا", + "customProvider": "مزوّد مخصّص…", + "providerIdLabel": "معرّف المزوّد", + "apiProtocolLabel": "بروتوكول API", + "baseUrlLabel": "نقطة نهاية API (عنوان URL الأساسي)", + "customProviderHint": "يعرّف مزوّدًا في ~/.pi/agent/models.json عند نقطة النهاية الخاصة بك. تستخدم معظم الخوادم الذاتية الاستضافة أو الوسيطة openai-completions.", + "baseUrlRequired": "نقطة نهاية API (عنوان URL الأساسي) مطلوبة", + "binaryTitle": "ثنائي pi (pi-coding-agent)", + "binaryDescription": "يشغّل pi-acp ثنائي pi هذا. ثبّته هنا، أو وجّه pi-acp إلى نسختك الخاصة أدناه.", + "binaryInstalled": "مثبَّت", + "binaryMissing": "غير مثبَّت", + "binaryChecking": "جارٍ التحقق…", + "installBinary": "تثبيت pi", + "installing": "جارٍ التثبيت…", + "recheck": "إعادة التحقق", + "configDirSkillsNote": "عند تحديد دليل إعدادات مخصص، لن تنطبق المهارات والخبراء وأدوات المكتب المُدارة في الإعدادات على pi هذا — أدِر مهاراته مباشرةً في ذلك المجلد.", + "projectTrustTitle": "ثقة المشروع", + "projectTrustDescription": "المجلدات التي سمحت لـ pi بتحميل ملفات المشروع منها. المجلد الموثوق يتيح لملفات ‎.pi/extensions في ذلك المستودع تنفيذ التعليمات البرمجية عند بدء pi، ويسري على كل المجلدات داخله، ويُستخدم أيضًا عند تشغيل pi في الطرفية.", + "projectTrustLoading": "جارٍ التحميل…", + "projectTrustEmpty": "لم يتم اتخاذ قرار بشأن أي مجلد بعد.", + "projectTrustTrusted": "موثوق", + "projectTrustDenied": "غير موثوق", + "projectTrustRevoke": "إلغاء", + "reasoningTitle": "الاستدلال", + "reasoningEnableLabel": "تفعيل", + "reasoningDescription": "لا يرسل pi مستوى استدلال إلا لنموذج يعلن عنه — أي نموذج غير معلن تُخفَّض كل مستوياته إلى Off، فيعود المحدِّد في صندوق الإدخال إلى وضعه فور لمسه. يُكتب في مدخل هذا النموذج داخل models.json.", + "levelsLabel": "المستويات المتاحة", + "levelsHint": "تصبح هذه هي خيارات محدِّد الاستدلال في صندوق الإدخال. اختر ما تقبله نقطة النهاية لديك؛ فأي مستوى غير مدرج هنا يرفضه pi.", + "levelsEmptyError": "اختر مستوى واحدًا على الأقل — بدون أي مستوى يعود pi إلى Off.", + "wireValuesTitle": "متقدم: القيم المرسلة إلى المزوّد", + "wireValuesHint": "اتركه فارغًا لإرسال اسم المستوى كما هو. اضبطه عندما تتوقع نقطة النهاية صيغة أخرى — الواجهات على نمط Google تحتاج LOW / HIGH.", + "defaultLevelUnlisted": "هذا المستوى ليس ضمن القائمة أعلاه — سيخفّضه pi." + }, + "addCustomAgent": "إضافة وكيل مخصص", + "addCustomAgentHint": "سجّل أي وكيل متوافق مع ACP. اختر واحدًا من سجل ACP العام، أو الصق معلومات السجل الخاصة به.", + "customAgentFromRegistry": "سجل ACP", + "customAgentManual": "يدوي", + "customAgentSearchPlaceholder": "البحث عن الوكلاء…", + "customAgentLoadingCatalog": "جارٍ تحميل سجل ACP…", + "customAgentRetry": "إعادة المحاولة", + "customAgentNoResults": "لا يوجد وكلاء مطابقون", + "customAgentAdd": "إضافة", + "customAgentAlreadyAdded": "تمت الإضافة", + "customAgentUnsupportedPlatform": "لا يوجد إصدار متاح لهذه المنصة", + "customAgentAdded": "تمت إضافة {name}", + "customAgentIdLabel": "معرّف السجل", + "customAgentNameLabel": "الاسم المعروض", + "customAgentVersionLabel": "الإصدار", + "customAgentSpecLabel": "التوزيع (JSON)", + "customAgentSpecHint": "بنفس شكل كائن distribution في سجل ACP: قنوات npx وuvx وbinary، أو الصق مدخل سجل كاملًا. في npx/uvx يكون cmd هو الأمر التنفيذي الذي تثبته الحزمة — يُشتق من اسم الحزمة عند إغفاله، فحدده عندما يختلفان. يُنظَّم binary حسب مفتاح المنصة (هذا الجهاز: {platform})؛ cmd هو مسار التشغيل داخل الأرشيف، وsha256 اختياري للتحقق من التنزيل.", + "customAgentTemplateLabel": "قوالب", + "customAgentKindLabel": "التشغيل عبر", + "customAgentInvalidJson": "JSON غير صالح", + "customAgentNoDistribution": "لم يتم العثور على توزيع npx أو uvx أو binary", + "customAgentCancel": "إلغاء", + "customAgentSave": "إضافة الوكيل", + "customAgentSaveChanges": "حفظ التغييرات", + "customAgentEdit": "تحرير الوكيل", + "customAgentEditHint": "حدّث الاسم والأيقونة ومعلومات التوزيع وإعلانات المهارات. لا يمكن تغيير معرّف الوكيل.", + "customAgentEditNotFound": "لم يُعثر على الوكيل المخصص {id}", + "customAgentSaved": "تم حفظ {name}", + "customAgentVersionProbeLabel": "أمر الاستعلام عن الإصدار (اختياري)", + "customAgentVersionProbeHint": "أمر يطبع الإصدار المثبت محليًا. عند تركه فارغًا يشغّل codeg أمر الوكيل مع ‎--version.", + "customAgentRemove": "إزالة الوكيل", + "customAgentRemoveHint": "يحذف تعريف الوكيل. تحتفظ المحادثات الحالية بسجلها، ولن يصبح بالإمكان تشغيل الوكيل فحسب.", + "customAgentIconLabel": "الأيقونة (اختياري)", + "customAgentIconUpload": "رفع", + "customAgentIconReplace": "استبدال", + "customAgentIconClear": "إزالة الأيقونة", + "customAgentIconHint": "يُحفظ مع الوكيل، لذا يعمل دون اتصال. وبدونه يُستخدم حرف أول ملوّن.", + "customAgentSkillsLabel": "Skills (‎.agents/skills المشترك)", + "customAgentSkillsHint": "يُعلن أن هذا الوكيل يقرأ مخزن .agents/skills المشترك (المجلدين العام والخاص بالمشروع) ويضيفه إلى جميع مصفوفات المهارات. المهارات المرتبطة هناك تكون مرئية لكل وكيل يقرأ هذا المخزن المشترك.", + "customAgentSkillsDirLabel": "دليل مهارات مخصص", + "customAgentSkillsDirHint": "المسار المطلق للدليل الذي يحمّل منه هذا الوكيل المهارات — مخزنه الخاص، إضافةً إلى المخزن المشترك أو بدلًا منه. يتم توسيع ~ إلى الدليل الرئيسي؛ وتوضع المهارات المرتبطة هنا أولًا.", + "customAgentMcpLabel": "دعم MCP", + "customAgentMcpHint": "يرسل رفيق MCP المدمج في codeg إلى هذا الوكيل عند بدء الجلسة — وهو القناة التي تعتمد عليها الإحالة والتغذية الراجعة الحية وأدوات المهام. أوقفه مع الوكلاء الذين يرفضون خوادم MCP ويفشلون في الاتصال؛ ويسري التغيير من الاتصال التالي.", + "customAgentIconNotAnImage": "اختر ملف صورة.", + "customAgentIconTooLarge": "يجب أن يكون حجم الأيقونة أقل من {limit} كيلوبايت.", + "customAgentIconReadFailed": "تعذّرت قراءة تلك الصورة.", + "customAgentRemoveConfirm": "إزالة {name}؟ ستبقى المحادثات الحالية، لكن لن يمكن تشغيل الوكيل بعد الآن.", + "customAgentRemoveWithData": "حذف سجل المحادثات المسجل أيضًا", + "customAgentRemoved": "تمت إزالة {name}", + "customAgentBadge": "مخصص", + "customAgentNotLaunchable": "لا يمكن تشغيل هذا الوكيل هنا: {reason}" + }, + "SettingsPages": { + "agentsLoading": "جارٍ تحميل إعدادات الوكلاء...", + "skillPacksLoading": "جارٍ تحميل حزم المهارات…" + }, + "GeneralSettings": { + "loading": "جارٍ التحميل...", + "sectionTitle": "عام", + "sectionDescription": "تفضيلات موحّدة للطرفية الافتراضية وتسريع العرض وتفويض الوكلاء المتعدّدين.", + "terminalTitle": "الطرفية الافتراضية", + "terminalDescription": "اختر الصدفة المستخدمة عند فتح علامات تبويب طرفية جديدة من شريط الطرفية أو شجرة الملفات. تستخدمها الوكلاء أيضًا عندما تطلب من codeg تنفيذ سطر أوامر كامل نيابةً عنها.", + "terminalSystemDefault": "افتراضي النظام", + "terminalPowerShell7": "PowerShell 7 (pwsh)", + "terminalWindowsPowerShell": "Windows PowerShell", + "terminalCmd": "موجّه الأوامر (cmd)", + "terminalSaveFailed": "فشل حفظ إعدادات الطرفية: {message}", + "terminalShellCustom": "مسار مخصص", + "terminalShellCustomPath": "مسار الصدفة", + "terminalShellCustomPlaceholder": "/usr/local/bin/fish", + "terminalShellCustomSave": "حفظ", + "terminalShellCustomHint": "أدخل مساراً مطلقاً أو اسماً يمكن حلّه عبر PATH.", + "terminalShellNotInstalled": "غير مثبّت", + "terminalShellNotFoundWarning": "هذا المسار غير موجود على هذا المضيف.", + "terminalCurrentShell": "قيد الاستخدام: {path}", + "renderingDescription": "أوقف تشغيل تسريع الأجهزة إذا ظهرت شاشة سوداء أو أخطاء في العرض (شائع على بعض كروت AMD أو كروت Intel المدمجة). يسري على إصدار سطح المكتب لويندوز فقط.", + "disableHardwareAcceleration": "تعطيل تسريع الأجهزة", + "renderingSaveFailed": "فشل حفظ إعدادات العرض: {message}", + "restartRequired": "تم الحفظ. أعد تشغيل التطبيق ليصبح التغيير نافذًا.", + "restartNow": "إعادة التشغيل الآن", + "restartFailed": "فشل إعادة التشغيل: {message}", + "loadFailed": "فشل التحميل: {message}" + }, + "LoginPage": { + "documentTitle": "تسجيل الدخول - codeg", + "brand": "Codeg", + "subtitle": "أدخل رمز الوصول للاتصال بتطبيق سطح المكتب", + "tokenPlaceholder": "رمز الوصول", + "connect": "اتصال", + "connecting": "جارٍ الاتصال...", + "helpText": "يمكنك الحصول على الرمز من تطبيق سطح المكتب عبر الإعدادات → خدمة الويب", + "invalidToken": "رمز غير صالح. يرجى التحقق والمحاولة مرة أخرى.", + "connectionFailed": "فشل الاتصال (HTTP {status})", + "networkError": "تعذر الاتصال بالخادم" + }, + "CommitPage": { + "title": "التزام", + "invalidFolderId": "معرّف المجلد غير صالح", + "loadingRepo": "جارٍ تحميل المستودع..." + }, + "MergePage": { + "title": "حل التعارضات", + "invalidFolderId": "معرّف المجلد غير صالح", + "loadingRepo": "جارٍ تحميل المستودع...", + "localVersion": "محلي (الخاص بنا)", + "result": "النتيجة", + "remoteVersion": "بعيد (الخاص بهم)", + "acceptLocal": "قبول المحلي", + "acceptRemote": "قبول البعيد", + "markResolved": "تحديد كمحلول", + "abortMerge": "إلغاء", + "completeMerge": "إتمام الدمج", + "unresolvedConflicts": "لا تزال هناك علامات تعارض غير محلولة في هذا الملف", + "fileResolved": "تم حل الملف بنجاح", + "allResolved": "تم حل جميع التعارضات", + "conflictFiles": "ملفات متعارضة", + "loadingFile": "جارٍ تحميل الملف...", + "preparingMerge": "جارٍ تحضير الدمج...", + "selectFile": "اختر ملفًا لحله", + "noConflicts": "لا توجد ملفات متعارضة", + "skipFile": "تخطي", + "abortSuccess": "تم إلغاء العملية", + "applyAllNonConflicting": "تطبيق جميع التغييرات غير المتعارضة", + "applyLeftNonConflicting": "تطبيق المحلي", + "applyRightNonConflicting": "تطبيق البعيد" + }, + "ImportSessions": { + "title": "استيراد الجلسات المحلية", + "scanningTitle": "جارٍ فحص جلسات الوكلاء المحلية…", + "scanningHint": "يجري المرور على مخزن الجلسات المحلي لكل وكيل. قد يستغرق ذلك بعض الوقت مع السجلات الكبيرة. ويجري خلال ذلك تحديث الجلسات المستوردة سابقًا.", + "scanFailed": "فشل الفحص", + "retry": "إعادة المحاولة", + "rescan": "إعادة الفحص", + "empty": "لم يُعثر على جلسات محلية", + "emptyHint": "لم يُعثر على مخازن جلسات للوكلاء على هذا الجهاز.", + "noMatches": "لا توجد جلسات مطابقة للمرشحات الحالية", + "searchPlaceholder": "ابحث في العنوان أو المسار…", + "allAgents": "جميع الوكلاء", + "onlyImportable": "القابلة للاستيراد فقط", + "selectAll": "تحديد الكل", + "clearSelection": "مسح", + "expandAll": "توسيع الكل", + "collapseAll": "طي الكل", + "summaryCounts": "{total} جلسة · {importable} قابلة للاستيراد · {folders} مجلدًا", + "noFolderSkipped": "تم تخطي {count} بدون مجلد مشروع", + "folderNew": "جديد", + "folderCounts": "قابلة للاستيراد {importable}/{total}", + "toggleFolderAria": "تحديد كل الجلسات القابلة للاستيراد في {name}", + "toggleSessionAria": "تحديد الجلسة {title}", + "statusImported": "مستوردة", + "statusDeleted": "محذوفة", + "untitled": "جلسة بلا عنوان", + "messageCount": "{count} رسالة", + "selectedCount": "{count} محددة", + "importSelected": "استيراد المحدد", + "importing": "جارٍ الاستيراد…", + "close": "إغلاق", + "doneTitle": "اكتمل الاستيراد", + "doneImported": "مستوردة", + "doneUpdated": "محدّثة", + "doneSkipped": "متخطاة", + "doneCreatedFolders": "مجلدات منشأة", + "doneNotFound": "غير موجودة", + "doneFailed": "فاشلة", + "continueImport": "متابعة الاستيراد", + "toasts": { + "importFailed": "فشل الاستيراد: {message}" + } + }, + "Folder": { + "workspaceStatus": { + "degradedTitle": "التحديثات الفورية غير متاحة", + "degradedHint": "فشل تشغيل المراقب (مثل رفض الإذن). قم بالتحديث يدويًا لرؤية التغييرات.", + "retry": "إعادة المحاولة", + "retrying": "جارٍ إعادة المحاولة..." + }, + "common": { + "all": "الكل", + "cancel": "إلغاء", + "close": "إغلاق", + "closeOthers": "إغلاق البقية", + "closeAll": "إغلاق الكل", + "confirm": "تأكيد", + "save": "حفظ", + "delete": "حذف", + "rename": "إعادة تسمية", + "loading": "جارٍ التحميل...", + "refresh": "تحديث", + "refreshing": "جارٍ التحديث...", + "create": "إنشاء", + "createAndSwitch": "إنشاء والتبديل", + "openFile": "فتح الملف", + "viewDiff": "عرض Diff", + "push": "دفع..." + }, + "statusLabels": { + "in_progress": "قيد التنفيذ", + "pending_review": "مراجعة", + "completed": "مكتمل", + "cancelled": "ملغى" + }, + "sidebar": { + "title": "المحادثات", + "locateActiveConversation": "تحديد المحادثة النشطة", + "expandAllGroups": "توسيع كل المجموعات", + "collapseAllGroups": "طي كل المجموعات", + "newConversation": "محادثة جديدة", + "newConversationShort": "جديدة", + "newChat": "محادثة جديدة", + "search": "بحث", + "noConversationsFound": "لم يتم العثور على محادثات.", + "importLocalSessions": "استيراد الجلسات المحلية", + "importing": "جارٍ الاستيراد...", + "error": "خطأ: {message}", + "completeAllSessions": "إكمال جميع الجلسات", + "completeAllReviewTitle": "إكمال جميع جلسات المراجعة؟", + "completeAllReviewDescription": "سيؤدي ذلك إلى وضع علامة مكتمل على جميع {count, plural, one {# جلسة} other {# جلسات}} في المراجعة.", + "completing": "جارٍ الإكمال...", + "toasts": { + "importedSessions": "تم استيراد {imported, plural, one {# جلسة} other {# جلسات}}، وتم تخطي {skipped}", + "importedAndUpdated": "تم استيراد {imported, plural, one {# جلسة} other {# جلسات}}، وتم تحديث {updated, plural, one {# عنوان} other {# عناوين}}، وتم تخطي {skipped}", + "updatedTitles": "تم تحديث {updated, plural, one {# عنوان} other {# عناوين}}، وتم تخطي {skipped}", + "noNewSessionsFound": "لم يتم العثور على جلسات جديدة (تم تخطي {skipped})", + "importFailed": "فشل الاستيراد: {message}", + "reviewCompleted": "تم وضع علامة مكتمل على {count, plural, one {# جلسة مراجعة} other {# جلسات مراجعة}}", + "completeReviewFailed": "فشل إكمال جلسات المراجعة: {message}", + "folderOpened": "تم فتح المجلد {name}", + "folderRemoved": "تمت إزالة المجلد {name}", + "openFolderFailed": "فشل فتح المجلد", + "removeFolderFailed": "فشل إزالة المجلد: {message}", + "reorderFoldersFailed": "فشل إعادة ترتيب المجلدات: {message}", + "changeFolderColorFailed": "فشل تغيير اللون: {message}", + "setFolderAliasFailed": "فشل تعيين الاسم المستعار: {message}", + "changeFolderDefaultAgentFailed": "فشل تعيين الوكيل الافتراضي: {message}" + }, + "statsLabel": "{folders} مجلدات · {convos} محادثة", + "reorderHandle": "اسحب لإعادة الترتيب", + "openFolder": "فتح مجلد", + "searchPlaceholder": "بحث عن محادثات...", + "viewOptions": "خيارات العرض", + "showCompleted": "عرض المحادثات المكتملة", + "showWorktrees": "عرض مجلدات worktree", + "showRecent": "عرض مجموعة الأحدث", + "moreOptions": "المزيد من الخيارات", + "sortBy": "الترتيب حسب", + "sortByCreatedAt": "وقت الإنشاء", + "sortByUpdatedAt": "وقت التحديث", + "sectionOrder": "ترتيب الأقسام", + "sectionOrderMoveUp": "تحريك لأعلى", + "sectionOrderMoveDown": "تحريك لأسفل", + "sectionOrderItemLabel": "{name} — الموضع {position} من {total}", + "statusRunningBadge": "قيد التشغيل", + "runningCountBadge": "{count} جلسة قيد التشغيل", + "statusCancelledBadge": "ملغى", + "worktreeRemovedBadge": "تمت إزالة شجرة العمل الأصلية", + "conversationCountUnit": "{count} محادثة", + "emptyFolderHint": "لا توجد محادثات", + "noMatchingConversations": "لا توجد محادثات مطابقة", + "noUnfinishedConversations": "لا توجد محادثات غير مكتملة. يمكنك تفعيل \"عرض المكتملة\" من القائمة في أعلى اليمين.", + "removeFolderConfirmTitle": "إزالة المجلد من مساحة العمل؟", + "removeFolderConfirmDescription": "إزالة \"{name}\" من مساحة العمل؟ سيتم إغلاق علامات التبويب والمحطات المرتبطة.", + "folderHeaderMenu": { + "manageConversations": "إدارة المحادثات…", + "manageLinks": "المجلدات المرتبطة", + "changeColor": "تغيير اللون", + "useThemeColor": "استخدام سمة التطبيق", + "setDefaultAgent": "تعيين الوكيل الافتراضي", + "defaultAgentNone": "بدون افتراضي (استخدام العام)", + "agentUnavailableSuffix": "(غير متاح)", + "loadingAgents": "جارٍ تحميل الوكلاء…", + "setAlias": "تعيين اسم مستعار…", + "setAliasTitle": "تعيين اسم مستعار للمجلد", + "setAliasPlaceholder": "أدخل اسمًا مستعارًا (اتركه فارغًا للمسح)", + "setAliasSave": "حفظ", + "setAliasCancel": "إلغاء", + "removeFromWorkspace": "إزالة من مساحة العمل" + }, + "manageConversations": { + "title": "إدارة المحادثات", + "searchPlaceholder": "البحث بالعنوان…", + "agentFilterAll": "جميع الوكلاء", + "statusFilterAll": "جميع الحالات", + "folderFilterAll": "كل المجلدات", + "branchFilterAll": "كل الفروع", + "branchNone": "بدون فرع", + "branchSearchPlaceholder": "بحث في الفروع…", + "noMatchingBranches": "لا توجد فروع مطابقة", + "selectAllVisible": "تحديد الكل", + "deselectAll": "إلغاء التحديد", + "selectedCount": "{count} محدد", + "matchedCount": "{count} مطابق", + "untitledConversation": "محادثة بدون عنوان", + "setStatus": "تعيين الحالة…", + "deleteSelected": "حذف", + "noConversations": "لا توجد محادثات في هذا المجلد.", + "noConversationsWorkspace": "لا توجد محادثات في مساحة العمل.", + "noMatchingConversations": "لا توجد محادثات مطابقة للفلاتر.", + "confirmDeleteTitle": "حذف {count} محادثة؟", + "confirmDeleteDescription": "لا يمكن التراجع عن هذا الإجراء.", + "toastDeleted": "تم حذف {count} محادثة", + "toastStatusUpdated": "تم تحديث حالة {count} محادثة", + "toastOpFailed": "فشلت العملية: {message}" + }, + "sectionPinned": "مثبّتة", + "sectionFolders": "المجلدات", + "sectionChats": "محادثة", + "sectionRecent": "الأحدث", + "noChats": "لا توجد محادثات", + "noRecent": "لا توجد محادثات حديثة", + "showMoreRecent": "عرض المزيد ({count})", + "noFolders": "لا توجد مجلدات مفتوحة", + "newChatAction": "محادثة جديدة", + "automations": "الأتمتة", + "tasks": "المهام قيد الانتظار", + "loadingSubsessions": "جارٍ تحميل المحادثات الفرعية…" + }, + "conversation": { + "reloadFailed": "فشل إعادة تحميل المحادثة: {message}", + "reloaded": "تمت إعادة تحميل المحادثة", + "reload": "إعادة تحميل", + "activeConversationIndicator": "المحادثة النشطة", + "newConversation": "محادثة جديدة", + "closeConversation": "إغلاق المحادثة", + "copyText": "نسخ النص", + "copyTextSuccess": "تم النسخ", + "copyTextFailed": "فشل النسخ", + "forkSession": "تفريع الجلسة", + "forkSessionSuccess": "تم تفريع الجلسة بنجاح", + "forkSessionFailed": "فشل في تفريع الجلسة: {error}", + "exportConversation": "تصدير المحادثة", + "exportImage": "صورة", + "exportMarkdown": "Markdown", + "exportHtml": "HTML", + "exportSuccess": "تم تصدير المحادثة", + "exportFailed": "فشل التصدير", + "exportImageTooLong": "المحادثة طويلة جداً ولا يمكن تصديرها كصورة", + "exportLabels": { + "untitledConversation": "محادثة بدون عنوان", + "agent": "الوكيل", + "model": "النموذج", + "status": "الحالة", + "started": "البداية", + "updated": "التحديث", + "tokens": "إحصائيات الرموز", + "duration": "المدة", + "inputTokens": "الإدخال", + "outputTokens": "الإخراج", + "cacheRead": "قراءة الذاكرة", + "cacheWrite": "كتابة الذاكرة", + "user": "المستخدم", + "assistant": "المساعد", + "system": "النظام", + "toolResult": "النتيجة", + "toolError": "خطأ" + }, + "moreActions": "إجراءات إضافية" + }, + "sessionDetails": { + "menuLabel": "تفاصيل الجلسة", + "noActiveSession": "لا توجد جلسة نشطة", + "title": "تفاصيل الجلسة", + "subtitle": "بيانات الجلسة الوصفية واستخدام الرموز", + "fieldTitle": "العنوان", + "untitled": "محادثة بدون عنوان", + "sessionId": "معرّف الجلسة", + "externalId": "معرّف الامتداد", + "agent": "الوكيل", + "model": "النموذج", + "status": "الحالة", + "gitBranch": "فرع Git", + "parentId": "الجلسة الأصلية", + "tokensHeading": "استخدام الرموز", + "totalTokens": "الإجمالي", + "inputTokens": "الإدخال", + "outputTokens": "الإخراج", + "cacheWrite": "كتابة الذاكرة", + "cacheRead": "قراءة الذاكرة", + "contextWindow": "نافذة السياق", + "duration": "المدة", + "loadingStats": "جارٍ تحميل استخدام الرموز…", + "loadFailed": "فشل تحميل استخدام الرموز", + "noStats": "لا يوجد استخدام مسجّل", + "timestampsHeading": "الطوابع الزمنية", + "createdAt": "تاريخ الإنشاء", + "updatedAt": "تاريخ التحديث", + "none": "—", + "copyField": "نسخ {field}", + "copiedField": "تم نسخ {field}" + }, + "conversationCard": { + "untitledConversation": "محادثة بدون عنوان", + "newConversation": "محادثة جديدة", + "rename": "إعادة تسمية", + "status": "الحالة", + "delete": "حذف", + "importLocalSessions": "استيراد الجلسات المحلية", + "importing": "جارٍ الاستيراد...", + "renameConversation": "إعادة تسمية المحادثة", + "deleteConversationTitle": "حذف المحادثة؟", + "deleteConversationDescription": "سيؤدي ذلك إلى حذف \"{title}\". لا يمكن التراجع عن هذا الإجراء.", + "cancel": "إلغاء", + "save": "حفظ", + "pin": "تثبيت", + "unpin": "إلغاء التثبيت", + "markCompleted": "وضع علامة كمكتمل", + "reopen": "إعادة فتح", + "expandSubsessions": "توسيع المحادثات الفرعية", + "collapseSubsessions": "طي المحادثات الفرعية" + }, + "search": { + "dialogTitle": "بحث", + "dialogTitleWithFolder": "بحث — {name}", + "tabConversations": "المحادثات", + "tabFiles": "الملفات", + "placeholder": "البحث في المحادثات...", + "filePlaceholder": "البحث في الملفات أو المجلدات...", + "allAgents": "الكل", + "searching": "جارٍ البحث...", + "typeToSearch": "اكتب للبحث في المحادثات", + "typeToSearchFiles": "اكتب للبحث في الملفات أو المجلدات", + "noResults": "لم يتم العثور على نتائج.", + "untitledConversation": "محادثة بدون عنوان" + }, + "folderTitleBar": { + "showSidebar": "إظهار الشريط الجانبي", + "hideSidebar": "إخفاء الشريط الجانبي", + "toggleTerminal": "تبديل الطرفية", + "toggleAuxPanel": "تبديل اللوحة المساعدة", + "search": "بحث", + "openSettings": "فتح الإعدادات", + "backToConversations": "العودة إلى المحادثات", + "withShortcut": "{label} (اختصار: {shortcut})" + }, + "statusBar": { + "connection": { + "connected": "متصل", + "connecting": "جارٍ الاتصال...", + "prompting": "جارٍ الرد...", + "error": "خطأ في الاتصال", + "disconnected": "غير متصل", + "tooltip": "{agent}: {status}", + "tooltipError": "{agent}: {error}", + "title": "اتصال الوكيل", + "triggerAria": "اتصال الوكيل: {status}", + "workingDir": "مجلد العمل", + "sessionId": "معرّف الجلسة", + "viewerNote": "متصل بجلسة يملكها عميل آخر — إعادة الاتصال تعيد ربط هذا العرض فقط.", + "reconnectInterrupts": "إعادة الاتصال تعيد تشغيل الوكيل وتقاطع العمل الجاري.", + "reconnect": "إعادة الاتصال", + "reconnecting": "جارٍ إعادة الاتصال...", + "reconnectUnavailable": "لا توجد جلسة لإعادة الاتصال بها بعد." + }, + "tasks": { + "title": "المهام" + }, + "alerts": { + "title": "التنبيهات", + "empty": "لا توجد تنبيهات", + "details": "التفاصيل" + }, + "stats": { + "conversations": "{count} محادثة", + "openUsage": "عرض إحصاءات الجلسات واستخدام الرموز" + }, + "tokens": { + "contextWindowUsageAria": "استخدام نافذة السياق", + "contextWindow": "نافذة السياق", + "usedMax": "المستخدم / الحد الأقصى", + "tokenUsage": "استخدام الرموز", + "input": "إدخال", + "output": "إخراج", + "cacheRead": "قراءة الكاش", + "cacheWrite": "كتابة الكاش", + "total": "الإجمالي" + } + }, + "auxPanel": { + "tabs": { + "files": "الملفات", + "changes": "التغييرات", + "commits": "الالتزامات" + }, + "noFolderTitle": "لا يوجد مجلد مفتوح", + "noFolderHint": "افتح مجلدا لعرض محتواه هنا" + }, + "windowControls": { + "minimizeWindow": "تصغير النافذة", + "minimize": "تصغير", + "maximizeWindow": "تكبير النافذة", + "maximize": "تكبير", + "restoreWindow": "استعادة النافذة", + "restore": "استعادة", + "closeWindow": "إغلاق النافذة", + "close": "إغلاق" + }, + "tabs": { + "closeConversationTab": "إغلاق تبويب المحادثة", + "close": "إغلاق", + "closeOthers": "إغلاق البقية", + "splitRight": "تقسيم لليمين", + "splitDown": "تقسيم للأسفل", + "splitAndMoveRight": "تقسيم ونقل لليمين", + "splitAndMoveDown": "تقسيم ونقل للأسفل", + "moveToOppositeGroup": "نقل إلى المجموعة المقابلة", + "moveToGroup": "نقل إلى مجموعة", + "groupLabel": "المجموعة {index}", + "changeSplitterOrientation": "تبديل اتجاه الفاصل", + "unsplit": "إلغاء التقسيم", + "unsplitAll": "إلغاء كل التقسيمات", + "closeAll": "إغلاق الكل", + "tileDisplay": "عرض متجانب", + "untileDisplay": "إلغاء التجانب" + }, + "fileWorkspace": { + "files": "الملفات", + "closeFileTab": "إغلاق تبويب الملف", + "close": "إغلاق", + "closeOthers": "إغلاق البقية", + "closeAll": "إغلاق الكل", + "preview": "معاينة", + "editSource": "تحرير المصدر", + "maximize": "تكبير", + "restore": "استعادة", + "emptyDirectory": "مجلد فارغ" + }, + "terminal": { + "rename": "إعادة تسمية", + "close": "إغلاق", + "closeOthers": "إغلاق البقية", + "closeAll": "إغلاق الكل", + "hideTerminal": "إخفاء الطرفية ({shortcut})", + "openFolderFirst": "افتح مجلدا أولا" + }, + "workspaceDialog": { + "title": "فتح مجلد", + "manageTitle": "المجلدات المرتبطة", + "addTargetsTitle": "إضافة مجلدات للربط", + "pickRootDescription": "اختر المجلد الرئيسي لمساحة العمل هذه.", + "linksDescription": "اربط مجلدات أخرى كمجلدات فرعية ليتمكن الوكلاء من العمل عليها جميعًا من مساحة عمل واحدة.", + "addTargetsDescription": "اختر مجلدًا واحدًا أو أكثر. سيصبح كل منها مجلدًا فرعيًا في مساحة العمل.", + "useSystemPicker": "منتقي النظام", + "next": "التالي", + "back": "رجوع", + "done": "تم", + "change": "تغيير", + "addFolders": "إضافة مجلدات", + "addSelected": "إضافة", + "addSelectedCount": "إضافة {count}", + "createCount": "ربط {count} مجلد", + "discardPending": "تجاهل", + "noLinks": "لا توجد مجلدات مرتبطة بعد.", + "gitExclude": "إبقاء الروابط خارج حالة git", + "rename": "إعادة تسمية", + "unlink": "إزالة الرابط", + "repair": "إعادة إنشاء الرابط", + "saveName": "حفظ", + "cancelRename": "إلغاء", + "removePending": "إزالة", + "willAppearAs": "يظهر باسم {name} في مساحة العمل", + "renamedForDuplicate": "تمت إعادة التسمية — {base} مستخدم من رابط آخر", + "renamedForExistingEntry": "تمت إعادة التسمية — {base} موجود بالفعل في هذا المجلد", + "partiallyCreated": "تم ربط {count} مجلد فقط", + "openFailed": "تعذر فتح المجلد", + "previewFailed": "تعذر فحص المجلدات المحددة", + "createFailed": "تعذر ربط المجلدات", + "renameFailed": "تعذرت إعادة تسمية الرابط", + "removeFailed": "تعذرت إزالة الرابط", + "repairFailed": "تعذرت إعادة إنشاء الرابط", + "status": { + "ok": "مرتبط", + "missing": "اختفى الرابط من هذا المجلد", + "conflicted": "يستخدم عنصر آخر هذا الاسم الآن", + "broken": "لم يعد المجلد المرتبط موجودًا" + }, + "nameIssue": { + "empty": "أدخل اسمًا", + "illegalChars": "لا يمكن أن يحتوي على / \\ : * ? \" < > |", + "tooLong": "الاسم طويل جدًا", + "reserved": "هذا الاسم محجوز في ويندوز", + "duplicate": "هذا الاسم مستخدم بالفعل" + }, + "rejection": { + "not_found": "تعذر العثور على هذا المجلد", + "not_a_directory": "هذا المسار ليس مجلدًا", + "same_as_root": "هذا هو مجلد مساحة العمل نفسه", + "ancestor_of_root": "هذا المجلد يحتوي على مساحة العمل", + "inside_root": "موجود بالفعل داخل مساحة العمل", + "already_linked": "مرتبط بالفعل", + "name_unavailable": "لم يتبق اسم متاح لهذا المجلد", + "alreadyLinkedAs": "مرتبط بالفعل باسم {name}" + } + }, + "folderNameDropdown": { + "fallbackFolderName": "مجلد", + "openFolder": "فتح مجلد", + "cloneRepository": "استنساخ المستودع", + "projectBoot": "مُنشئ المشروع", + "opened": "مفتوح", + "recentOpen": "المفتوح مؤخرًا" + }, + "fileWorkspacePanel": { + "addSelectionToChat": "إضافة التحديد إلى المحادثة", + "addToChat": "إضافة إلى المحادثة", + "addSelectionToChatDone": "تمت إضافة {label} إلى المحادثة", + "addFileToChat": "إضافة الملف إلى المحادثة", + "toggleWordWrap": "تبديل التفاف النص", + "addFileToChatDone": "تمت إضافة {label} إلى المحادثة", + "viewDiff": "عرض Diff", + "openFile": "فتح الملف", + "fileCount": "{count, plural, one {# ملف} other {# ملفات}}", + "openFileOrDiff": "افتح ملفًا أو diff من اللوحة اليمنى", + "disk": "القرص", + "head": "HEAD", + "unsaved": "غير محفوظ", + "workingTree": "شجرة العمل", + "loading": "جارٍ التحميل...", + "compareWithBranch": "{path} · مقارنة مع {branch}", + "hunkCount": "{count, plural, one {# مقطع} other {# مقاطع}}", + "prev": "السابق", + "next": "التالي", + "jumpToLine": "الانتقال إلى السطر {line}", + "noParsedDiffSections": "لا توجد أقسام diff محللة", + "loadingEditor": "جارٍ تحميل المحرر...", + "imageZoomIn": "تكبير", + "imageZoomOut": "تصغير", + "imageZoomReset": "إعادة تعيين التكبير", + "htmlPreviewTitle": "معاينة HTML", + "htmlPreviewTrust": "تفعيل البرامج النصية", + "htmlPreviewTrustHint": "تشغيل البرامج النصية لهذا الملف والسماح بالوصول إلى الشبكة. فعّلها فقط للملفات الموثوقة.", + "officePreviewTitle": "معاينة مستند Office", + "officeFullRender": "عرض كامل", + "officeFullRenderHint": "يعرض حركات Morph والأبعاد الثلاثية والمعادلات (يشغّل سكربتات الشريحة نفسها)", + "officeNotInstalled": "OfficeCLI غير مثبّت", + "officeNotInstalledHint": "ثبّت OfficeCLI من الإعدادات → أدوات Office لمعاينة ملفات Word و Excel و PowerPoint.", + "officeOpenSettings": "فتح الإعدادات", + "officeWatchFailed": "تعذّر بدء المعاينة المباشرة", + "officeWatchRetry": "إعادة المحاولة", + "officeServerInstallHint": "يجب تثبيت OfficeCLI على مضيف الخادم. شغّل هذا الأمر هناك ثم أعد المحاولة:", + "officeRemoteDesktopUnsupported": "المعاينة المباشرة غير متاحة في نافذة سطح المكتب البعيد. افتح مساحة العمل هذه في واجهة الويب الخاصة بالخادم لمعاينة ملفات Office." + }, + "branchDropdown": { + "toasts": { + "commitCodeCompleted": "اكتمل التزام الكود", + "pushCodeCompleted": "اكتمل دفع الكود", + "committedFiles": "{count, plural, one {# ملف تم الالتزام به} other {# ملفات تم الالتزام بها}}", + "taskCompleted": "اكتمل {label}", + "taskFailed": "فشل {label}", + "mergeNoNewCommits": "{branchName} لا يحتوي على التزامات جديدة", + "mergedCommits": "{count, plural, one {# التزام تم دمجه} other {# التزامات تم دمجها}}", + "allFilesUpToDate": "كل الملفات محدثة", + "updatedFiles": "{count, plural, one {# ملف تم تحديثه} other {# ملفات تم تحديثها}}", + "openCommitWindowFailed": "فشل فتح نافذة الالتزام", + "openPushWindowFailed": "فشل فتح نافذة الدفع", + "upstreamSet": "تم تعيين فرع upstream", + "upstreamSetAndPushed": "تم تعيين فرع upstream ودفع {count, plural, one {# التزام} other {# التزامات}}", + "noCommitsToPush": "لا توجد التزامات للدفع", + "pushedCommits": "تم دفع {count, plural, one {# التزام} other {# التزامات}}", + "switchedToFolder": "تم التبديل إلى {name}", + "switchFailed": "فشل تبديل الفرع", + "openStashWindowFailed": "فشل فتح نافذة الـ stash" + }, + "tasks": { + "newBranch": "إنشاء الفرع {name}", + "newWorktree": "إنشاء worktree {name}", + "checkoutTo": "Checkout إلى {branchName}", + "mergeBranch": "دمج {branchName}", + "rebaseTo": "Rebase إلى {branchName}", + "deleteRemoteBranch": "حذف الفرع البعيد {branchName}", + "initGitRepo": "تهيئة مستودع Git", + "pullCode": "سحب الكود", + "fetchInfo": "جلب المعلومات", + "pushCode": "دفع الكود", + "stashChanges": "تخزين التغييرات في stash", + "stashPop": "استرجاع stash", + "deleteBranch": "حذف الفرع {branchName}", + "removeWorktree": "حذف worktree الخاص بـ {branchName}", + "removeWorktreeAndBranch": "حذف worktree والفرع {branchName}", + "updateBranch": "تحديث الفرع {branchName}" + }, + "confirm": { + "mergeTitle": "دمج الفرع", + "rebaseTitle": "Rebase للفرع", + "mergeDescription": "دمج {branchName} في الفرع الحالي {currentBranch}؟", + "rebaseDescription": "إجراء rebase للفرع الحالي {currentBranch} على {branchName}؟", + "deleteRemoteTitle": "حذف الفرع البعيد", + "deleteRemoteDescription": "هل تريد حذف الفرع البعيد {branchName}؟ سيؤدي ذلك إلى إزالته من المستودع البعيد ولا يمكن التراجع عن هذا الإجراء.", + "deleteTitle": "حذف الفرع", + "deleteDescription": "حذف الفرع {branchName}؟ لا يمكن التراجع عن هذا الإجراء.", + "forceDeleteTitle": "حذف الفرع بالقوة", + "forceDeleteDescription": "الفرع {branchName} لم يتم دمجه بالكامل. هل أنت متأكد من أنك تريد حذفه بالقوة؟ لا يمكن التراجع عن هذا الإجراء.", + "deleteWorktreeTitle": "حذف worktree", + "deleteWorktreeDescription": "حذف مجلد worktree الذي تم سحب {branchName} فيه؟ سيتم الاحتفاظ بالفرع وإيداعاته.", + "forceDeleteWorktreeTitle": "فرض حذف worktree", + "forceDeleteWorktreeDescription": "يحتوي worktree الخاص بـ {branchName} على ملفات غير مودعة أو غير متتبعة. هل تريد حذفه على أي حال؟ لا يمكن استرجاع تلك التغييرات.", + "deleteWorktreeAndBranchTitle": "حذف worktree والفرع", + "deleteWorktreeAndBranchDescription": "حذف worktree الخاص بـ {branchName} والفرع نفسه ومجلده في مساحة العمل؟ ستنتقل جلساته إلى مجلد المستودع. لا يمكن التراجع عن هذا الإجراء.", + "forceDeleteWorktreeAndBranchTitle": "فرض حذف worktree والفرع", + "forceDeleteWorktreeAndBranchDescription": "يحتوي worktree الخاص بـ {branchName} على ملفات غير مودعة، أو أن الفرع غير مدمج بالكامل. هل تريد حذفهما على أي حال؟ لا يمكن التراجع عن هذا الإجراء." + }, + "current": "الحالي", + "switchToBranch": "التبديل إلى هذا الفرع", + "mergeBranchIntoCurrent": "دمج {branchName} في {currentBranch}", + "rebaseCurrentToBranch": "Rebase لـ {currentBranch} على {branchName}", + "noBranch": "بدون فرع", + "detachedHead": "HEAD منفصل عند {sha}", + "initGitRepo": "تهيئة مستودع Git", + "pullCode": "سحب الكود", + "fetchRemoteBranches": "جلب الفروع البعيدة", + "openCommitWindow": "التزام الكود...", + "pushCode": "دفع...", + "pushBranch": "دفع", + "newBranch": "فرع جديد...", + "newWorktree": "Worktree جديد...", + "stashChanges": "...تخبئة التغييرات", + "stashPop": "استرجاع stash...", + "manageRemotes": "إدارة المستودعات البعيدة...", + "localBranches": "الفروع المحلية ({count, plural, one {#} other {#}})", + "noLocalBranches": "لا توجد فروع محلية", + "remoteBranches": "الفروع البعيدة ({count, plural, one {#} other {#}})", + "noRemoteBranches": "لا توجد فروع بعيدة", + "dialogs": { + "newBranchTitle": "فرع جديد", + "newBranchDescription": "إنشاء فرع جديد من الفرع الحالي {branch}", + "branchNamePlaceholder": "اسم الفرع", + "newWorktreeTitle": "Worktree جديد", + "newWorktreeDescription": "إنشاء worktree جديد من الفرع الحالي {branch}", + "branchNameLabel": "اسم الفرع", + "worktreePathLabel": "مسار worktree", + "worktreePathPlaceholder": "مسار worktree", + "manageRemotesTitle": "إدارة المستودعات البعيدة", + "manageRemotesEmpty": "لم يتم تكوين أي مستودعات بعيدة", + "remoteNamePlaceholder": "اسم المستودع البعيد", + "remoteUrlPlaceholder": "عنوان URL للمستودع البعيد", + "addRemote": "إضافة", + "savingRemotes": "جارٍ الحفظ..." + }, + "conflict": { + "title": "تعارضات الدمج", + "description": "الملفات التالية بها تعارضات تحتاج إلى حل:", + "abort": "إلغاء الدمج", + "openMergeTool": "فتح أداة الدمج", + "completeMerge": "إتمام الدمج", + "abortSuccess": "تم إلغاء الدمج بنجاح", + "completeSuccess": "تم إتمام الدمج بنجاح" + }, + "stashDialog": { + "title": "تخبئة التغييرات", + "description": "حفظ التغييرات الحالية في المخبأ", + "messageLabel": "رسالة", + "messagePlaceholder": "رسالة التخبئة (اختياري)", + "keepIndex": "الاحتفاظ بالفهرس (التغييرات المرحلة تبقى مرحلة)", + "cancel": "إلغاء", + "stash": "تخبئة", + "success": "تم تخبئة التغييرات", + "error": "فشل في تخبئة التغييرات" + }, + "unstashDialog": { + "title": "تطبيق المخبأ", + "noStashes": "لا توجد تخبئات", + "selectFile": "اختر ملفاً لعرض الفرق", + "viewDiff": "عرض الفرق", + "original": "الأصلي", + "modified": "المعدل", + "apply": "تطبيق", + "drop": "حذف", + "applySuccess": "تم تطبيق التخبئة", + "dropSuccess": "تم حذف التخبئة", + "confirmApply": "تطبيق التخبئة {ref} على دليل العمل؟", + "cancel": "إلغاء" + }, + "deleteBranch": "حذف الفرع", + "deleteWorktree": "حذف worktree", + "deleteWorktreeAndBranch": "حذف worktree والفرع", + "searchPlaceholder": "البحث في الفروع والإجراءات", + "searchAriaLabel": "البحث في الفروع والإجراءات", + "branchListLabel": "الفروع والإجراءات", + "noMatches": "لا توجد نتائج" + }, + "commitDialog": { + "toasts": { + "commitCompleted": "اكتمل التزام الكود", + "pushFailed": "فشل الدفع", + "committedFiles": "{count, plural, one {# ملف تم الالتزام به} other {# ملفات تم الالتزام بها}}", + "addedToVcs": "تمت الإضافة إلى VCS", + "addToVcsFailed": "فشلت الإضافة إلى VCS", + "fileDeleted": "تم حذف الملف", + "deleteFailed": "فشل الحذف", + "fileRolledBack": "تم التراجع عن الملف", + "rollbackFailed": "فشل التراجع", + "dirRolledBack": "تم استعادة المجلد", + "dirDeleted": "تم حذف المجلد" + }, + "confirm": { + "deleteTitle": "تأكيد الحذف", + "deleteDescription": "حذف الملف \"{file}\"؟ لا يمكن التراجع عن هذا الإجراء.", + "rollbackTitle": "تأكيد التراجع", + "rollbackDescription": "التراجع عن الملف \"{file}\" إلى HEAD؟ ستفقد التغييرات غير المحفوظة.", + "rollbackDirDescription": "هل تريد استعادة المجلد \"{dir}\" إلى HEAD؟ ستفقد التغييرات غير المحفوظة.", + "deleteDirDescription": "هل تريد حذف المجلد \"{dir}\"؟ لا يمكن التراجع عن هذا الإجراء." + }, + "actions": { + "select": "تحديد", + "unselect": "إلغاء التحديد", + "rollback": "تراجع", + "addToVcs": "إضافة إلى VCS" + }, + "aria": { + "selectFile": "{action}: {path}", + "unselectAllFiles": "إلغاء تحديد كل الملفات", + "selectAllFiles": "تحديد كل الملفات", + "unselectTracked": "إلغاء تحديد التغييرات المتعقبة", + "selectTracked": "تحديد التغييرات المتعقبة", + "unselectUntracked": "إلغاء تحديد الملفات غير المتعقبة", + "selectUntracked": "تحديد الملفات غير المتعقبة" + }, + "loading": "جارٍ التحميل...", + "selectionCount": "{selected} / {total} ملفات", + "emptyFiles": "لا توجد ملفات متغيرة", + "trackedChanges": "التغييرات المتعقبة ({count})", + "untrackedFiles": "الملفات غير المتعقبة ({count})", + "commitMessage": "رسالة الالتزام", + "commitMessagePlaceholder": "أدخل رسالة الالتزام...", + "commitButton": "التزام ({count})", + "commitAndPushButton": "إيداع ودفع ({count})", + "head": "HEAD", + "workingTree": "شجرة العمل", + "clickFileToDiff": "انقر اسم الملف لعرض الفرق", + "loadingDiff": "جارٍ تحميل diff..." + }, + "pushWindow": { + "title": "دفع الكود", + "noUnpushedCommits": "لا توجد التزامات غير مدفوعة", + "noRemoteConfigured": "لم يتم تكوين مستودع Git بعيد\nأضف واحدًا في «إدارة المستودعات البعيدة»", + "newBranchNoPushedCommits": "فرع جديد — ادفع لإنشاء فرع تتبع عن بُعد", + "unpushed": "غير مدفوع", + "selectFileToViewDiff": "اختر ملفًا لعرض الفرق", + "before": "قبل", + "after": "بعد", + "push": "دفع", + "toasts": { + "pushSuccess": "تم الدفع بنجاح", + "pushFailed": "فشل الدفع", + "upstreamSet": "تم تعيين الفرع البعيد", + "upstreamSetAndPushed": "تم تعيين الفرع البعيد ودفع {count} التزام", + "noCommitsToPush": "لا توجد التزامات للدفع", + "pushedCommits": "تم دفع {count} التزام" + } + }, + "gitLogTab": { + "filesTitle": "الملفات", + "expandAllFiles": "توسيع كل الملفات", + "collapseAllFiles": "طي كل الملفات", + "workspace": "مساحة العمل", + "retry": "إعادة المحاولة", + "noCommitsFound": "لم يتم العثور على التزامات", + "notAGitRepoTitle": "ليس مستودع Git", + "notAGitRepoHint": "قم بتهيئة Git من قائمة الفروع أعلاه، أو افتح مستودعًا موجودًا.", + "hash": "بصمة الالتزام", + "copyHash": "نسخ الـ hash", + "copyMessage": "نسخ الرسالة", + "showMore": "عرض المزيد", + "showLess": "طي", + "author": "المؤلف", + "noFileChangeDetails": "لا توجد تفاصيل تغييرات ملفات متاحة.", + "loadingFiles": "جارٍ تحميل الملفات...", + "branchesTitle": "الفروع", + "loadingBranches": "جارٍ تحميل الفروع...", + "noContainingBranches": "لم يتم العثور على فروع تحتوي هذا الالتزام.", + "newBranch": "فرع جديد...", + "resetToHere": "إعادة الضبط إلى هنا", + "resetDisabledReasonNotCurrentBranchView": "متاح فقط عند عرض الفرع الحالي", + "copyFullCommitHashAria": "نسخ hash الكامل للالتزام {hash}", + "pushStatus": { + "pushed": "تم الدفع إلى البعيد", + "notPushed": "لم يتم الدفع إلى البعيد", + "unknown": "حالة الدفع غير معروفة (لم يتم إعداد upstream)" + }, + "time": { + "monthsAgo": "{count, plural, one {منذ # شهر} other {منذ # أشهر}}", + "daysAgo": "{count, plural, one {منذ # يوم} other {منذ # أيام}}", + "hoursAgo": "{count, plural, one {منذ # ساعة} other {منذ # ساعات}}", + "minsAgo": "{count, plural, one {منذ # دقيقة} other {منذ # دقائق}}", + "justNow": "الآن" + }, + "toasts": { + "createdAndSwitchedNewBranch": "تم إنشاء فرع جديد والتبديل إليه", + "newBranchFromCommit": "{name} (من {shortHash})", + "createBranchFailed": "فشل إنشاء الفرع", + "openPushWindowFailed": "فشل فتح نافذة الدفع", + "resetSuccess": "تمت إعادة الضبط بنجاح", + "resetSuccessDescription": "تمت إعادة ضبط {branch} إلى {shortHash} باستخدام {mode}", + "resetFailed": "فشلت إعادة الضبط" + }, + "authorFilter": { + "label": "المؤلف", + "searchPlaceholder": "بحث عن مؤلف", + "noAuthors": "لم يتم العثور على مؤلفين", + "you": "أنت", + "filterByAuthorAria": "تصفية الإيداعات حسب المؤلف", + "filterByQuery": "تصفية حسب \"{query}\"", + "clearAuthorFilterAria": "مسح تصفية المؤلف", + "recent": "الأخيرة", + "matchingAuthors": "المؤلفون المطابقون", + "removeFromRecent": "إزالة {name} من الأخيرة" + }, + "branchSelector": { + "label": "الفرع", + "head": "HEAD", + "headHint": "يتبع الفرع الحالي", + "headHintWithBranch": "يتبع الفرع الحالي ({branch})", + "searchBranch": "بحث عن فرع...", + "noBranches": "لا توجد فروع", + "selectBranchPlaceholder": "اختر فرعًا...", + "localBranches": "الفروع المحلية", + "current": "الحالي", + "remoteBranches": "الفروع البعيدة", + "refreshCommitHistory": "تحديث سجل الالتزامات", + "clearBranchFilterAria": "مسح تصفية الفرع" + }, + "dialogs": { + "newBranchTitle": "فرع جديد", + "newBranchDescription": "إنشاء فرع جديد مع الالتزام {shortHash} كأحدث التزام.", + "branchNamePlaceholder": "اسم الفرع", + "reset": { + "title": "إعادة ضبط الفرع الحالي إلى هذا الالتزام", + "branchLabel": "الفرع", + "targetLabel": "الالتزام الهدف", + "messageLabel": "الرسالة", + "modeLabel": "وضع إعادة الضبط", + "confirmButton": "إعادة الضبط", + "modes": { + "soft": { + "label": "--soft", + "description": "ينقل HEAD ومؤشر الفرع الحالي إلى الالتزام الهدف.\nيبقي Index و Working Tree بدون تغيير.\nتظل تغييرات الالتزامات التي تمت إزالتها في حالة staged." + }, + "mixed": { + "label": "--mixed (الافتراضي)", + "description": "ينقل HEAD إلى الالتزام الهدف.\nيعيد ضبط Index إلى الالتزام الهدف مع الإبقاء على تغييرات Working Tree.\nتتحول التغييرات من staged إلى unstaged." + }, + "hard": { + "label": "--hard", + "description": "ينقل HEAD ويعيد ضبط كل من Index و Working Tree إلى الالتزام الهدف.\nسيتم حذف التغييرات المحلية المتتبعة بعد الالتزام الهدف.\nهذه عملية تدميرية." + }, + "keep": { + "label": "--keep", + "description": "ينقل HEAD إلى الالتزام الهدف مع محاولة الاحتفاظ بالتغييرات المحلية.\nيتم الاحتفاظ فقط بالتغييرات غير المتعارضة.\nعند وجود تعارض، يتم إيقاف العملية لحماية عملك." + } + } + } + }, + "moreActions": "إجراءات Git إضافية" + }, + "gitChangesTab": { + "workspace": "مساحة العمل", + "noChanges": "لا توجد تغييرات محلية", + "notAGitRepoTitle": "ليس مستودع Git", + "notAGitRepoHint": "قم بتهيئة Git من قائمة الفروع أعلاه، أو افتح مستودعًا موجودًا.", + "trackedChanges": "التغييرات المتعقبة ({count})", + "untrackedFiles": "الملفات غير المتعقبة ({count})", + "expandTracked": "توسيع التغييرات المتعقبة", + "collapseTracked": "طي التغييرات المتعقبة", + "expandUntracked": "توسيع الملفات غير المتعقبة", + "collapseUntracked": "طي الملفات غير المتعقبة", + "showRemainingItems": "عرض {count} عنصر إضافي", + "actions": { + "commitCode": "التزام الكود", + "rollback": "تراجع", + "addToVcs": "إضافة إلى VCS", + "delete": "حذف", + "moreActions": "إجراءات Git إضافية", + "addAllToVcs": "إضافة الكل إلى VCS", + "rollbackAll": "تراجع عن الكل", + "refresh": "تحديث" + }, + "toasts": { + "noAddableFilesInDir": "لا توجد ملفات متغيرة في هذا الدليل يمكن إضافتها إلى VCS", + "noRollbackFilesInDir": "لا توجد ملفات متغيرة في هذا الدليل يمكن التراجع عنها", + "addedToVcs": "تمت إضافة {name} إلى VCS", + "addToVcsFailed": "فشلت الإضافة إلى VCS", + "openCommitWindowFailed": "فشل فتح نافذة الالتزام", + "rolledBack": "تم التراجع عن {name}", + "rollbackFailed": "فشل التراجع", + "addedFilesToVcs": "تمت إضافة {count, plural, one {# ملف} other {# ملفات}} إلى VCS", + "rolledBackFiles": "تم التراجع عن {count, plural, one {# ملف} other {# ملفات}}", + "deleted": "تم حذف {name}", + "deleteFailed": "فشل الحذف", + "deletedFiles": "تم حذف {count} ملفات", + "noDeletableFilesInDir": "لا توجد ملفات معدّلة في هذا الدليل يمكن حذفها", + "commitFailed": "فشل الالتزام" + }, + "directoryDialog": { + "descriptionAdd": "اختر ملفات داخل الدليل {path} لإضافتها إلى VCS.", + "descriptionRollback": "اختر ملفات داخل الدليل {path} للتراجع عنها.", + "descriptionDelete": "اختر ملفات داخل الدليل {path} لحذفها. لا يمكن التراجع عن هذا الإجراء.", + "descriptionFallback": "اختر ملفات للمتابعة.", + "selectionCount": "تم تحديد {selected} / {total} ملف", + "selectAll": "تحديد الكل", + "unselectAll": "إلغاء تحديد الكل", + "loadingCandidates": "جارٍ تحميل تغييرات الدليل...", + "noOperableFiles": "لا توجد ملفات قابلة للتشغيل" + }, + "rollbackConfirm": { + "title": "تأكيد التراجع", + "descriptionWithTarget": "التراجع عن التغييرات المحلية لـ {kind} \"{name}\"؟", + "descriptionFallback": "التراجع عن التغييرات المحلية؟", + "kindDirectory": "الدليل", + "kindFile": "الملف" + }, + "deleteConfirm": { + "title": "تأكيد الحذف", + "descriptionWithTarget": "حذف {kind} \"{name}\"؟ لا يمكن التراجع عن هذا الإجراء.", + "descriptionFallback": "لا يمكن التراجع عن هذا الإجراء.", + "kindDirectory": "الدليل", + "kindFile": "الملف" + }, + "quickCommit": { + "placeholder": "رسالة الالتزام (اضغط Enter للالتزام)" + } + }, + "tabContext": { + "loadingConversation": "جارٍ التحميل...", + "untitledConversation": "محادثة بدون عنوان", + "newConversation": "محادثة جديدة" + }, + "fileTreeTab": { + "workspace": "مساحة العمل", + "retry": "إعادة المحاولة", + "git": "Git", + "openInFileManager": "فتح في مدير الملفات", + "openInFinder": "فتح في Finder", + "openInExplorer": "فتح في Explorer", + "attachToCurrentSession": "إضافة إلى الجلسة", + "compareWithBranch": "المقارنة مع الفرع...", + "reloadFromDisk": "إعادة التحميل من القرص", + "new": "جديد", + "newFile": "ملف", + "newDirectory": "مجلد", + "openIn": "فتح في", + "openInTerminal": "فتح في الطرفية", + "linkedFolder": "مجلد مرتبط", + "copyPath": "نسخ المسار", + "upload": "رفع ملفات/مجلد", + "download": "تنزيل ملف", + "downloadAsZip": "تنزيل كملف ZIP", + "actions": { + "select": "تحديد", + "unselect": "إلغاء التحديد", + "commitCode": "تنفيذ الالتزام بالكود", + "rollback": "التراجع", + "addToVcs": "إضافة إلى VCS" + }, + "aria": { + "selectPath": "{action}: {path}" + }, + "toasts": { + "openDirectoryFailed": "فشل فتح المجلد", + "openBuiltinTerminalFailed": "تعذر فتح الطرفية المدمجة", + "openCommitWindowFailed": "فشل فتح نافذة الالتزام", + "noAddableFilesInDir": "لا توجد ملفات متغيرة في هذا المجلد يمكن إضافتها إلى VCS", + "noRollbackFilesInDir": "لا توجد ملفات متغيرة في هذا المجلد يمكن التراجع عنها", + "addedToVcs": "تمت إضافة {name} إلى VCS", + "addToVcsFailed": "فشلت الإضافة إلى VCS", + "loadBranchesFailed": "فشل تحميل الفروع", + "renameFailed": "فشل إعادة التسمية", + "moveFailed": "فشل النقل", + "deleteFailed": "فشل الحذف", + "rolledBack": "تم التراجع عن {name}", + "rollbackFailed": "فشل التراجع", + "addedFilesToVcs": "{count, plural, one {تمت إضافة ملف واحد إلى VCS} other {تمت إضافة # ملفات إلى VCS}}", + "rolledBackFiles": "{count, plural, one {تم التراجع عن ملف واحد} other {تم التراجع عن # ملفات}}", + "savedAsCopy": "تم الحفظ كنسخة", + "saveCopyFailed": "فشل الحفظ كنسخة", + "watchStartFailed": "فشل بدء مراقبة الملفات", + "createFailed": "فشل في الإنشاء", + "downloadFailed": "فشل تنزيل {name}", + "downloadSaved": "تم تنزيل {name}", + "pathCopied": "تم نسخ المسار", + "copyPathFailed": "فشل نسخ المسار" + }, + "createDialog": { + "newFile": "ملف جديد", + "newDirectory": "مجلد جديد", + "description": "أدخل اسمًا لـ{kind} الجديد.", + "placeholderFile": "file-name.ext", + "placeholderDirectory": "folder-name" + }, + "renameDialog": { + "renameDirectory": "إعادة تسمية المجلد", + "renameFile": "إعادة تسمية الملف", + "description": "أدخل اسمًا جديدًا (الاسم فقط، بدون مسار).", + "placeholderDirectory": "اسم-مجلد-جديد", + "placeholderFile": "اسم-ملف-جديد.ext" + }, + "uploadDialog": { + "title": "رفع إلى مساحة العمل", + "description": "اضبط الوجهة عند الحاجة، ثم أضف الملفات أو المجلدات.", + "workspaceRoot": "جذر مساحة العمل", + "targetPathLabel": "رفع إلى", + "targetPathHint": "المسار النهائي: {path}", + "dropHint": "اسحب الملفات أو المجلدات هنا، أو استخدم الأزرار أدناه", + "dropHintActive": "حرّر للإضافة إلى قائمة الانتظار", + "selectFiles": "اختيار ملفات", + "selectFolder": "اختيار مجلد", + "startUpload": "بدء الرفع", + "clearQueue": "مسح المنتهية", + "removeItem": "إزالة من قائمة الانتظار", + "retry": "إعادة المحاولة", + "dropZoneAria": "أفلت الملفات هنا أو نشّط للاستعراض", + "folderEmpty": "لم يتم العثور على ملفات في المجلد المسحوب", + "summary": "الإجمالي: {total} · نجح: {succeeded} · فشل: {failed}", + "status": { + "pending": "قيد الانتظار", + "uploading": "جاري الرفع", + "success": "تم", + "error": "فشل", + "cancelled": "ملغى" + } + }, + "directoryDialog": { + "descriptionAdd": "حدد الملفات ضمن المجلد {path} لإضافتها إلى VCS.", + "descriptionRollback": "حدد الملفات ضمن المجلد {path} للتراجع عنها.", + "descriptionFallback": "حدد الملفات للمتابعة.", + "selectionCount": "تم تحديد {selected} من {total} ملف", + "selectAll": "تحديد الكل", + "unselectAll": "إلغاء تحديد الكل", + "loadingCandidates": "جارٍ تحميل تغييرات المجلد...", + "noOperableFiles": "لا توجد ملفات قابلة للمعالجة" + }, + "compareDialog": { + "title": "المقارنة مع الفرع", + "descriptionWithTarget": "حدد فرعًا وقارن مع {kind} {path}", + "descriptionFallback": "حدد فرعًا للمقارنة.", + "kindDirectory": "مجلد", + "kindFile": "ملف", + "filterPlaceholder": "تصفية الفروع، مثال: main / origin/main", + "singleClickHint": "انقر على فرع للمقارنة مباشرة", + "loadingBranches": "جارٍ تحميل الفروع...", + "recentBranches": "الفروع الحديثة ({count})", + "noCurrentBranch": "لا يوجد فرع حالي", + "localBranches": "الفروع المحلية ({count})", + "remoteBranches": "الفروع البعيدة ({count})", + "noMatchingBranches": "لا توجد فروع مطابقة" + }, + "externalConflictDialog": { + "title": "تم اكتشاف تغييرات خارجية في الملفات", + "descriptionWithPath": "تم تغيير الملف {path} على القرص، والتعديلات الحالية غير محفوظة.", + "descriptionFallback": "تم تغيير الملف الحالي على القرص، والتعديلات الحالية غير محفوظة.", + "compare": "مقارنة", + "savingCopy": "جارٍ حفظ نسخة...", + "saveAsCopy": "حفظ كنسخة", + "reload": "إعادة التحميل" + }, + "deleteConfirm": { + "title": "تأكيد الحذف", + "descriptionWithTarget": "حذف {kind} \"{name}\"؟ لا يمكن التراجع عن هذا الإجراء.", + "descriptionFallback": "لا يمكن التراجع عن هذا الإجراء.", + "kindDirectory": "مجلد", + "kindFile": "ملف" + }, + "rollbackConfirm": { + "title": "تأكيد التراجع", + "descriptionWithTarget": "التراجع عن التغييرات المحلية للملف \"{name}\"؟", + "descriptionFallback": "التراجع عن التغييرات المحلية لهذا الملف؟" + }, + "terminalTitle": "الطرفية · {name}" + }, + "commandDropdown": { + "loading": "جارٍ التحميل...", + "addCommand": "إضافة أمر", + "manageCommands": "إدارة الأوامر...", + "runCommandTitle": "تشغيل: {command}", + "stopCommandTitle": "إيقاف: {command}", + "manageDialog": { + "title": "إدارة الأوامر", + "empty": "لا توجد أوامر بعد", + "noResults": "لا توجد أوامر مطابقة", + "searchPlaceholder": "البحث في الأوامر", + "newCommand": "أمر جديد", + "nameLabel": "الاسم", + "commandLabel": "الأمر", + "dragSort": "اسحب للترتيب", + "dragSortCommand": "اسحب لترتيب {name}", + "orderFailed": "فشل حفظ ترتيب الأوامر", + "loadFailed": "فشل تحميل الأوامر", + "saveFailed": "فشل حفظ الأمر", + "deleteFailed": "فشل حذف الأمر", + "confirmDelete": { + "title": "حذف الأمر؟", + "message": "سيؤدي هذا إلى إزالة \"{name}\". لا يمكن التراجع عن هذا الإجراء." + } + } + }, + "workspaceContext": { + "confirmCloseDirtyTab": "إغلاق \"{title}\" بدون حفظ؟", + "confirmCloseOtherDirtyTabs": "إغلاق التبويبات الأخرى التي تحتوي تغييرات غير محفوظة؟", + "confirmCloseAllDirtyTabs": "إغلاق جميع التبويبات التي تحتوي تغييرات غير محفوظة؟", + "unableLoadContent": "تعذر تحميل المحتوى.\n\n{message}", + "previewRequestTimedOut": "انتهت مهلة طلب المعاينة", + "diffRequestTimedOut": "انتهت مهلة طلب Diff", + "branchCompareRequestTimedOut": "انتهت مهلة طلب مقارنة الفروع", + "commitDiffRequestTimedOut": "انتهت مهلة طلب Diff للالتزام", + "saveRequestTimedOut": "انتهت مهلة طلب الحفظ", + "reloadRequestTimedOut": "انتهت مهلة طلب إعادة التحميل", + "noChanges": "لا توجد تغييرات.", + "noDiffOutput": "لا يوجد مخرجات diff.", + "diffTitleWorkspace": "Diff · مساحة العمل", + "diffDescriptionWorkingTree": "شجرة العمل (HEAD)", + "diffTitleFile": "الفرق · {name}", + "compareTitleFile": "مقارنة · {name}", + "compareTitleBranch": "مقارنة · {branch}", + "compareDescriptionPath": "{path} · مقارنة مع {branch}", + "compareDescriptionBranch": "مقارنة مع {branch}", + "diffTitleCommitFile": "الفرق · {name} @ {hash}", + "diffTitleCommit": "الفرق · {hash}", + "diffDescriptionCommitPath": "{path} · الالتزام {commit}", + "diffDescriptionCommit": "الالتزام {commit}", + "diffTitleConflictFile": "تعارض · {name}", + "diffDescriptionConflict": "{path} · القرص مقابل غير المحفوظ" + }, + "chat": { + "acpConnections": { + "actions": { + "openAgentsSettings": "فتح إعدادات الوكلاء", + "retry": "إعادة المحاولة" + }, + "agentsSetupHint": "افتح الإعدادات > الوكلاء لإدارة التثبيت.", + "withSetupHint": "{message}\n{hint}", + "blocked": { + "missingConfig": "تعذر قراءة إعدادات الوكيل الحالية.", + "disabled": "{agent} معطّل في إعدادات الوكلاء. قم بتمكينه قبل الاتصال.", + "unavailable": "{agent} غير متاح على المنصة الحالية.", + "sdkMissing": "لم يتم تثبيت SDK الخاص بـ {agent}", + "adapterMissing": "محوّل ACP الخاص بـ {agent} غير مثبّت" + }, + "backendErrors": { + "initializeTimeout": "انتهت مهلة مصافحة اتصال {agent} (لا استجابة بعد 60 ثانية). افتح الإعدادات للتحقق من إعدادات الوكيل والشبكة.", + "mcpRejectedByAgent": "رفض {agent} الجلسة أثناء إرفاق رفيق MCP الخاص بـ codeg: {message} إن كان هذا الوكيل لا يدعم MCP، فأوقف «دعم MCP» من الإعدادات ثم أعد الاتصال.", + "processExited": "انتهت عملية {agent} بشكل غير متوقع.", + "spawnFailed": "تعذر بدء تشغيل {agent}: {message}", + "downloadFailed": "فشل تنزيل {agent}: {message}", + "sessionLoadResourceNotFound": "فشل تحميل جلسة {agent}. أعد التحميل لإعادة المحاولة، أو ابدأ محادثة جديدة.", + "sessionLoadUnavailable": "تعذّر على {agent} استعادة هذه الجلسة، فقد تكون انتهت أو توقّف الوكيل. أعد التحميل لإعادة المحاولة، أو ابدأ محادثة جديدة.", + "turnFailedRefusal": "رفض {agent} متابعة هذه الجولة. يدل ذلك غالبًا على خطأ في الخلفية أو البوابة. يرجى مراجعة سجلات الوكيل.", + "turnFailedMaxTokens": "بلغ {agent} الحد الأقصى للرموز المسموح بها في هذه الجولة.", + "turnFailedMaxTurnRequests": "بلغ {agent} الحد الأقصى لعدد الطلبات المسموح بها في هذه الجولة.", + "turnFailedUnknown": "أنهى {agent} الجولة بسبب توقف غير معروف.", + "grokModelSwitchIncompatibleAgent": "لا يمكن لـ {agent} التبديل إلى هذا النموذج في محادثة قائمة. ابدأ جلسة جديدة لاستخدامه.", + "turnFailedEmpty": "أنهى {agent} الجولة دون إنتاج أي رد.", + "turnFailedEmptyProtocol": "أنتج {agent} مخرجات تعذّر على codeg تحليلها — قد لا يتوافق إصدار الوكيل مع البروتوكول.", + "turnFailedEmptyMetadata": "أرسل {agent} تحديثات حالة فقط في هذه الجولة (الخطة / الوضع / الاستخدام) دون أي رد.", + "detailsInAlerts": "افتح التنبيهات في شريط الحالة ووسّع التفاصيل لعرض مخرجات الوكيل." + }, + "unableReadAgentConfig": "تعذر قراءة إعدادات الوكيل: {message}", + "connectFailedTitle": "فشل اتصال {agent}", + "toolFallbackTitle": "أداة", + "eventErrorTitle": "خطأ الوكيل", + "notificationTurnComplete": "{agent} أنهى الاستجابة", + "notificationError": "{agent} خطأ: {message}", + "claudeApiRetry": { + "fallbackError": "authentication_failed", + "retryingWithMax": "إعادة المحاولة {attempt}/{max}", + "retryingAttempt": "إعادة المحاولة رقم {attempt}", + "retrying": "جاري إعادة المحاولة", + "nextRetryIn": "المحاولة التالية خلال {seconds}ث", + "line": "{error}{status} · {retry}", + "lineWithDelay": "{error}{status} · {retry}، {delay}", + "httpStatus": " (HTTP {status})" + }, + "configOptionAdjusted": "ضبط {agent} {option} على {actual} بدلاً من {requested}" + }, + "connectionLifecycle": { + "tasks": { + "connectingTitle": "جارٍ الاتصال بـ {agent}", + "connectingDescription": "جارٍ إنشاء الاتصال", + "loadingSelectorsTitle": "جارٍ تحميل محددات {agent}", + "loadingSelectorsDescription": "جارٍ جلب خيارات الوضع وإعدادات الجلسة", + "initSessionTitle": "جارٍ تهيئة جلسة {agent}", + "initSessionDescription": "جارٍ إنشاء الجلسة وتحميل الإعدادات" + }, + "errors": { + "connectionFailed": "فشل الاتصال", + "sendPromptFailed": "فشل إرسال الرسالة: {error}" + } + }, + "shared": { + "attachedResources": "الموارد المرفقة", + "toolCallFailed": "فشل استدعاء الأداة" + }, + "messageThread": { + "emptyTitle": "لا توجد رسائل بعد", + "emptyDescription": "ابدأ محادثة لرؤية الرسائل هنا" + }, + "chatInput": { + "connecting": "جارٍ الاتصال...", + "agentResponding": "{agent} يرد...", + "sendMessage": "أرسل رسالة..." + }, + "messageInput": { + "askAnything": "اسأل أي شيء...", + "removeAttachmentAria": "إزالة {name}", + "attachFiles": "إرفاق ملفات", + "addActions": "إضافة", + "quickMessages": "الرسائل السريعة", + "quickMessagesEmpty": "لا توجد رسائل سريعة بعد", + "quickMessagesLoading": "جارٍ التحميل...", + "pasteAsPlainText": "لصق كنص عادي", + "cut": "قص", + "copy": "نسخ", + "selectAll": "تحديد الكل", + "pasteUnavailable": "تعذّر قراءة الحافظة. استخدم Ctrl/⌘V للصق.", + "clipboardWriteFailed": "تعذّرت الكتابة إلى الحافظة. استخدم اختصار لوحة المفاتيح.", + "quickMessageUntitled": "بدون عنوان", + "liveFeedback": "ملاحظات مباشرة", + "liveFeedbackDisabledHint": "متاح أثناء عمل الوكيل", + "dropFilesToAttach": "أسقط الملفات لإرفاقها", + "loadingSettings": "جارٍ تحميل الإعدادات...", + "loadingMode": "جارٍ تحميل الوضع...", + "modeLabel": "الوضع", + "toggleOn": "تشغيل", + "toggleOff": "إيقاف", + "agentSettings": "إعدادات الوكيل", + "searchModel": "البحث عن النماذج...", + "searchModelAria": "البحث عن النماذج", + "modelListLabel": "النماذج", + "noModels": "لم يتم العثور على نماذج", + "cancel": "إلغاء", + "send": "إرسال", + "forkAndSend": "تفريع وإرسال", + "queueMessage": "إضافة إلى قائمة الانتظار", + "steerIntoTurn": "إدراج في الدور الحالي", + "steerQueuedInstead": "أُضيفت إلى قائمة الانتظار — ستُرسل مع الدور التالي.", + "steerFailed": "تعذّر الإدراج في الدور الحالي", + "steerAttachmentsUnsupported": "نص فقط — المسودات التي تحتوي على مرفقات تمر عبر قائمة الانتظار.", + "slashCommands": "أوامر الشرطة المائلة", + "slashSearchPlaceholder": "البحث عن الأوامر...", + "slashSearchEmpty": "لا توجد أوامر مطابقة", + "experts": "الخبراء", + "office": "الأعمال المكتبية", + "research": "البحث العلمي", + "attachLocalUpload": "تحميل ملف محلي", + "attachServerFile": "اختيار ملف من الخادم", + "attachUploadTooLarge": "{names} يتجاوز حد التحميل {limit}MB وتم تخطيه.", + "attachUploadFailed": "فشل تحميل {names}.", + "attachUploadNotAFile": "{names} ليس ملفاً عادياً (مجلد أو ملف خاص) وتم تخطيه.", + "attachUploadQuotaExceeded": "نفدت مساحة التحميل على الخادم، تعذر رفع {names}.", + "attachUploadInProgress": "لا تزال الصور قيد الرفع — حاول مرة أخرى بعد قليل.", + "mentionEmpty": "لا توجد نتائج مطابقة", + "mentionLoading": "جارٍ البحث…", + "mentionListLabel": "الإشارات", + "mentionMore": "مزيد من النتائج — تابع الكتابة للتصفية", + "mentionCount": "{count, plural, zero {لا نتائج} one {نتيجة واحدة} two {نتيجتان} few {# نتائج} many {# نتيجة} other {# نتيجة}}", + "mentionGroupFile": "الملفات", + "mentionGroupAgent": "الوكلاء", + "mentionGroupSession": "الجلسات", + "mentionGroupCommit": "عمليات الإيداع", + "mentionGroupSkill": "المهارات" + }, + "messageQueue": { + "addToQueue": "إضافة للقائمة", + "saveEdit": "حفظ", + "cancelEdit": "إلغاء التعديل", + "editItem": "تعديل", + "deleteItem": "حذف" + }, + "welcomeInputPanel": { + "agentsSettingsPath": "الإعدادات > الوكلاء", + "autoConnectFallback": "انقر لفتح {path} وإدارة التثبيت.", + "autoConnectAppend": "{message}. انقر لفتح {path} وإدارة التثبيت.", + "enableAgentFirstPlaceholder": "فعّل وكيلًا واحدًا على الأقل قبل بدء جلسة...", + "prepareSessionFailed": "تعذّر تحضير جلسة الدردشة. يرجى المحاولة مرة أخرى.", + "createConversationFailed": "تعذّر إنشاء المحادثة. يرجى المحاولة مرة أخرى.", + "askAnythingPlaceholder": "اسأل أي شيء...", + "agentNotInstalled": "{agent} غير مثبّت · افتح إعدادات Agents لتثبيته", + "agentAdapterNotInstalled": "محوّل ACP الخاص بـ {agent} غير مثبّت (وهو منفصل عن واجهة الأوامر لديك) · افتح إعدادات Agents لتثبيته" + }, + "welcomePanel": { + "greeting": "ماذا تودّ أن تفعل اليوم؟", + "tips": { + "tileTabs": "انقر بزر الفأرة الأيمن على تبويب محادثة واختر «عرض متجانب» لمقارنة عدة جلسات جنبًا إلى جنب.", + "pinTab": "انقر نقرًا مزدوجًا على تبويب محادثة لتثبيته كي لا تستبدله جلسة جديدة تلقائيًا.", + "shortcutsNewSearch": "{newConversation} يفتح محادثة جديدة، و{searchConversations} يبحث في السجل.", + "slashAtMention": "اكتب / في حقل الإدخال لتشغيل أوامر السلاش، أو @ للإشارة إلى ملف من المشروع.", + "pasteDropFiles": "ألصق لقطة شاشة أو اسحب ملفًا مباشرة إلى حقل الإدخال لإرفاقه.", + "queueMessage": "أثناء رد الوكيل، تابع الكتابة — ستوضع رسالتك التالية في الطابور وتُرسل تلقائيًا عند انتهائه.", + "draftAutoSave": "تُحفظ المسودات غير المُرسلة تلقائيًا لكل محادثة وتُستعاد عند العودة.", + "forkSend": "تتضمن قائمة زر الإرسال المنسدلة «تفرّع وأرسل» لإنشاء فرع من النقطة الحالية في تبويب جديد.", + "exportConversation": "انقر بزر الفأرة الأيمن داخل المحادثة لتصديرها بصيغة Markdown أو HTML أو صورة.", + "chatChannels": "اربط Telegram / Lark / WeChat من «الإعدادات → قنوات الدردشة» للمتابعة من هاتفك.", + "shortcutsAuxPanel": "{toggleAuxPanel} يبدّل اللوحة اليمنى لعرض الملفات المعدّلة وتغييرات Git لهذه الجلسة.", + "shortcutsTerminalSidebar": "{toggleTerminal} يفتح الطرفية المدمجة، و{toggleSidebar} يبدّل الشريط الجانبي.", + "customShortcuts": "يمكن إعادة تعيين جميع الاختصارات من «الإعدادات → الاختصارات».", + "webService": "فعّل «الإعدادات → خدمة الويب» ليتمكن أعضاء الفريق من الوصول إلى نفس codeg عبر المتصفح.", + "fusionMode": "افتح ملفًا أو فرقًا لعرضه تلقائيًا بجوار المحادثة.", + "quickMessages": "افتح زر + بجانب الإدخال واختر «الرسائل السريعة» لإدراج مقتطف محفوظ (تُدار من «الإعدادات → الرسائل السريعة»).", + "experts": "يحتوي زر + على قائمة «مهارات الخبراء» — حمّل أدوارًا مثل التصحيح أو التخطيط بنقرة واحدة.", + "taskBoard": "تنفّذ المهام قيد الانتظار عملاً كاملاً من البداية إلى النهاية: يعمل الوكيل في worktree خاص به، ثم تراجع الفروق وتدمجها.", + "automations": "تشغّل الأتمتة موجّهًا محفوظًا وفق جدول زمني — مراجعة ليلية أو تقريرًا دوريًا — ويمكن أن يحصل كل تشغيل على worktree خاص به.", + "tokenUsage": "انقر على عدد المحادثات في شريط الحالة لفتح استهلاك الرموز، موزّعًا حسب اليوم والوكيل والنموذج والمجلد.", + "mentionTargets": "لا تقتصر @ على الملفات: اذكر وكيلًا آخر لتفويض مهمة فرعية، أو أشِر إلى جلسة سابقة أو التزام أو مهارة.", + "splitGroups": "انقر بزر الفأرة الأيمن على تبويب واختر «تقسيم لليمين» أو «تقسيم للأسفل» لإبقاء محادثتين في لوحين منفصلين.", + "worktrees": "افتح زر الفرع واختر «Worktree جديد» ليعمل عدة وكلاء على المستودع نفسه دون أن يستبدل أحدهم ملفات الآخر.", + "importSessions": "هل شغّلت جلسات في الطرفية من قبل؟ تحتوي قائمة المجلد على «استيراد الجلسات المحلية» لجلب ذلك السجل إلى codeg.", + "subSessions": "عندما يفوّض وكيل مهمة، تظهر الجلسة الفرعية متداخلة تحته في الشريط الجانبي — وسّع الصف لتتابع ما فعلته كل واحدة.", + "liveFeedback": "تُدرج «ملاحظات مباشرة» في قائمة + ملاحظةً داخل الدور الذي ينفّذه الوكيل بالفعل، دون مقاطعته.", + "skillPacks": "تجمع الإعدادات ← حزم المهارات خبراء البرمجة والبحث العلمي ومهارات المكتب — فعّلها لكل وكيل على حدة.", + "modelProviders": "تقبل الإعدادات ← مزودو النماذج مفتاح API أو نقطة نهاية خاصة بك، ثم تختار النموذج مباشرة من حقل الإدخال.", + "workspaceBackground": "تحدّد الإعدادات ← المظهر صورة خلفية لمساحة العمل، وشفافية اللوحات، وخطوط التطبيق." + }, + "quickActions": { + "excel": "مصنّف Excel", + "excelDesc": "جداول بيانات وصيغ ومخططات", + "word": "مستند Word", + "wordDesc": "تقارير ورسائل ومذكرات", + "ppt": "عرض تقديمي", + "pptDesc": "شرائح بتصميم احترافي", + "pitchDeck": "عرض استثماري", + "pitchDeckDesc": "عرض تمويل بمؤشرات رئيسية", + "morph": "حركة Morph", + "morphDesc": "انتقالات شرائح سينمائية", + "morph3d": "Morph ثلاثي الأبعاد", + "morph3dDesc": "نماذج ثلاثية الأبعاد وحركات كاميرا", + "academic": "ورقة أكاديمية", + "academicDesc": "بحث باستشهادات وبنية", + "financial": "نموذج مالي", + "financialDesc": "قوائم وDCF وتوقعات", + "dashboard": "لوحة بيانات", + "dashboardDesc": "مؤشرات وتحليلات من بياناتك", + "prompts": { + "excel": "أنشئ مصنّف Excel وفق المتطلبات التالية:\n\n[صف هنا بياناتك وجداولك وصيغك ومخططاتك]", + "word": "أنشئ مستند Word وفق المتطلبات التالية:\n\n[صف هنا محتوى المستند وبنيته وتنسيقه]", + "ppt": "أنشئ عرض PowerPoint تقديمي وفق المتطلبات التالية:\n\n[صف هنا شرائحك ومحتواك وتصميمك]", + "pitchDeck": "أنشئ عرضًا استثماريًا لجمع التمويل وفق المتطلبات التالية:\n\n[صف هنا شركتك وجولة التمويل والمؤشرات الرئيسية]", + "morph": "أنشئ عرضًا تقديميًا بحركات انتقال Morph:\n\n[صف هنا موضوع العرض والمؤثرات المرئية المطلوبة]", + "morph3d": "أنشئ عرض Morph ثلاثي الأبعاد بنماذج GLB وحركات كاميرا:\n\n[صف هنا موضوعك ومفهومك المرئي ثلاثي الأبعاد]", + "academic": "اكتب ورقة أكاديمية في Word وفق المتطلبات التالية:\n\n[صف هنا موضوع بحثك ومنهجيتك وأبرز نتائجك]", + "financial": "أنشئ نموذجًا ماليًا في Excel وفق المتطلبات التالية:\n\n[صف هنا قوائمك المالية وتوقعاتك وتحليلاتك]", + "dashboard": "أنشئ لوحة بيانات في Excel وفق المتطلبات التالية:\n\n[صف هنا مصدر بياناتك ومؤشراتك ومخططاتك]", + "scientific-brainstorming": "ساعدني في توليد أفكار بحثية: استكشف الروابط متعددة التخصصات، وتحدَّ الافتراضات، واكشف الفجوات الواعدة. المجال الذي أستكشفه: ", + "hypothesis-generation": "ساعدني في تحويل هذه الملاحظات إلى فرضيات قابلة للاختبار، مع تنبؤات واضحة وآليات معقولة وتجارب لاختبارها. ملاحظاتي: ", + "experimental-design": "ساعدني في تصميم تجربة دقيقة قبل جمع البيانات: التصميم والعشوائية والضوابط وكيفية تجنّب الالتباس. ما أريد دراسته: ", + "statistical-power": "ساعدني في تحديد حجم العينة المطلوب: أرشدني خلال تحليل القوة الإحصائية (حجم الأثر، ألفا، القوة) لتصميمي. التفاصيل: ", + "statistical-analysis": "ساعدني في تحليل هذه البيانات بشكل صحيح: اختر الاختبار المناسب، وتحقق من الافتراضات، وأبلغ عن أحجام الأثر، واكتب النتائج. بياناتي وسؤالي: ", + "exploratory-data-analysis": "قم بتحليل استكشافي لملف بياناتي: لخّص بنيته وجودته والأنماط اللافتة، ثم اقترح الخطوات التالية. الملف هو: ", + "scientific-visualization": "ساعدني في إنشاء شكل بجودة النشر: تخطيط واضح، وأشرطة خطأ صادقة، ولوحة ألوان مناسبة لعمى الألوان، وتنسيق المجلة. ما أريد عرضه: ", + "scientific-critical-thinking": "ساعدني في التقييم النقدي لهذه الدراسة أو الادعاء: قيّم جودة الأدلة، وارصد التحيّزات والعوامل المربكة، وزِن الاستنتاجات. إليك المحتوى: ", + "paper-lookup": "ساعدني في العثور على أوراق ذات صلة ونص كامل مفتوح الوصول عبر قواعد البيانات الأكاديمية، مع استشهادات يمكنني إعادة استخدامها. أبحث عن: " + }, + "paper-lookup": "البحث عن الأوراق البحثية", + "paper-lookupDesc": "البحث في 10 واجهات برمجية أكاديمية (PubMed وarXiv وOpenAlex وCrossref…) عن الأوراق والاستشهادات والنص الكامل المفتوح.", + "scientific-critical-thinking": "التفكير النقدي", + "scientific-critical-thinkingDesc": "تقييم الادعاءات العلمية وجودة الأدلة: رصد التحيّزات والعوامل المربكة وتطبيق أطر GRADE ومخاطر التحيّز.", + "scientific-visualization": "التصور العلمي", + "scientific-visualizationDesc": "أشكال جاهزة للنشر: تخطيطات متعددة اللوحات، وتعليقات الدلالة الإحصائية، وتنسيق خاص بكل مجلة.", + "exploratory-data-analysis": "تحليل البيانات الاستكشافي", + "exploratory-data-analysisDesc": "استكشاف آلي لملفات البيانات العلمية بأكثر من 200 صيغة مع مقاييس الجودة والتقارير.", + "statistical-analysis": "التحليل الإحصائي", + "statistical-analysisDesc": "تحليل إحصائي موجَّه: اختيار الاختبار، والتحقق من الافتراضات، وأحجام الأثر، والتقارير بأسلوب APA.", + "statistical-power": "القوة الإحصائية", + "statistical-powerDesc": "تحليل حجم العينة والقوة الإحصائية: عدد المشاركين اللازم، وأصغر تأثير قابل للكشف، ومنحنيات القوة.", + "experimental-design": "تصميم التجارب", + "experimental-designDesc": "تصميم دراسات دقيقة قبل جمع البيانات: العشوائية والتجميع والضوابط وتصاميم العوامل/DOE.", + "hypothesis-generation": "توليد الفرضيات", + "hypothesis-generationDesc": "تحويل الملاحظات إلى فرضيات قابلة للاختبار مع تنبؤات وآليات وتجارب لاختبارها.", + "scientific-brainstorming": "العصف الذهني العلمي", + "scientific-brainstormingDesc": "توليد أفكار بحثية مفتوحة: استكشاف الروابط متعددة التخصصات وتحدّي الافتراضات وكشف الفجوات البحثية.", + "tabs": { + "office": "الأعمال المكتبية", + "coding": "تطوير الكود", + "research": "البحث العلمي" + }, + "coding": { + "brainstormingDesc": "استكشف النية والمتطلبات قبل البناء", + "debuggingDesc": "حدد السبب الجذري قبل اقتراح الإصلاحات", + "writingSkillsDesc": "أنشئ وحرّر وتحقق من مهارات قابلة لإعادة الاستخدام" + }, + "notEnabled": { + "title": "المهارة ”{skill}“ غير مُفعّلة بعد لـ {agent}", + "description": "فعّلها من الإعدادات لاستخدامها هنا.", + "action": "تفعيل", + "hint": "المهارة غير مُفعّلة" + }, + "scrollPrev": "عرض المهارات السابقة", + "scrollNext": "عرض المزيد من المهارات" + } + }, + "agentSelector": { + "noEnabledAgents": "لا يوجد وكلاء مفعّلون", + "openAgentsSettings": "فتح إعدادات الوكلاء", + "notInstalled": "غير مثبّت", + "moreAgents": "وكلاء إضافيون ({count})" + }, + "subAgentOverlay": { + "title": "الوكلاء الفرعيون", + "collapsedSummary": "الوكلاء الفرعيون {count}", + "collapseAria": "طي الوكلاء الفرعيين" + }, + "agentPlanOverlay": { + "title": "خطة الوكيل", + "collapsePlanAria": "طي الخطة", + "collapsedSummary": "الخطة {completed}/{total}", + "status": { + "completed": "مكتمل", + "inProgress": "قيد التنفيذ", + "pending": "قيد الانتظار", + "unknown": "غير معروف" + }, + "priority": { + "high": "مرتفع", + "medium": "متوسط", + "low": "منخفض", + "unknown": "غير معروف" + } + }, + "permissionDialog": { + "subtitle": "يطلب الوكيل إذنًا لمتابعة هذا الدور.", + "queuedCount": "+{count} في الانتظار", + "kindFallbackTool": "أداة", + "command": "أمر", + "cwd": "دليل العمل: {cwd}", + "filesSummary": "الملفات: {count}", + "moreFiles": "+{count} ملف إضافي", + "plan": "الخطة", + "allowedActions": "الإجراءات المسموح بها", + "targetMode": "وضع الهدف: {mode}", + "optionGrants": "ما يمنحه كل خيار", + "changeScopeSession": "هذه الجلسة", + "changeScopeProcess": "هذا التشغيل", + "changeScopeUser": "محفوظ في إعدادات المستخدم", + "changeScopeProject": "محفوظ في إعدادات المشروع", + "changeScopeProjectLocal": "محفوظ في إعدادات المشروع المحلية", + "changeScopePersistent": "محفوظ بشكل دائم" + }, + "questionDialog": { + "title": "الوكيل يطرح سؤالاً", + "placeholder": "اكتب إجابتك...", + "send": "إرسال" + }, + "messageBranch": { + "previousBranchAria": "الفرع السابق", + "nextBranchAria": "الفرع التالي", + "pageOf": "{current} من {total}" + }, + "terminal": { + "title": "الطرفية", + "running": "قيد التشغيل" + }, + "reasoning": { + "thinking": "جارٍ التفكير…", + "thoughtForFewSeconds": "تفكير", + "thoughtForSeconds": "تفكير" + }, + "linkSafety": { + "errorCannotOpen": "تعذر فتح الملف المحلي", + "errorNoWorkspace": "لا يوجد مجلد مساحة عمل نشط حالياً.", + "errorFailedOpen": "فشل فتح الملف المحلي", + "errorFailedLink": "فشل فتح الرابط", + "errorUnsupportedLinkProtocol": "بروتوكول الرابط هذا غير مدعوم." + }, + "fileActions": { + "openInFinder": "فتح في Finder", + "openInExplorer": "فتح في Explorer", + "openInFileManager": "فتح في مدير الملفات", + "copyRelativePath": "نسخ المسار النسبي", + "copyAbsolutePath": "نسخ المسار المطلق", + "pathCopied": "تم نسخ المسار", + "copyPathFailed": "فشل نسخ المسار", + "openFailed": "فشل فتح الملف المحلي" + }, + "messageList": { + "attachedResources": "الموارد المرفقة", + "loading": "جارٍ التحميل...", + "loadEarlier": "تحميل الرسائل السابقة", + "loadingEarlier": "جارٍ تحميل الرسائل السابقة…", + "error": "خطأ: {message}", + "errorTitle": "فشل تحميل الجلسة", + "errorActionReload": "إعادة تحميل", + "errorActionNewSession": "محادثة جديدة", + "emptyConversation": "لا توجد رسائل في هذه المحادثة.", + "systemMessage": "رسالة النظام", + "copyMessage": "نسخ", + "copied": "تم النسخ", + "downloadImage": "تنزيل الصورة", + "downloadFailed": "فشل التنزيل: {message}", + "imageGeneration": "إنشاء الصورة", + "imageGenerationPending": "جارٍ إنشاء الصورة…", + "imageGenerationFailed": "فشل إنشاء الصورة", + "model": "النموذج", + "tokenStats": "استخدام الرموز", + "tokenInput": "الإدخال", + "tokenOutput": "الإخراج", + "tokenCacheRead": "قراءة التخزين المؤقت", + "tokenCacheWrite": "كتابة التخزين المؤقت", + "duration": "المدة", + "completedAt": "وقت الإنجاز", + "jumpToPreviousUserMessage": "الانتقال إلى رسالة المستخدم", + "showMore": "عرض المزيد", + "showLess": "طي" + }, + "liveTurnStats": { + "thinking": "جارٍ التفكير...", + "streaming": "جارٍ البث", + "elapsedHours": "{value}س", + "elapsedMinutes": "{value}د", + "elapsedSeconds": "{value}ث", + "outputSpeedAria": "السرعة التقديرية للإخراج", + "outputSpeedTooltip": "السرعة التقديرية للإخراج (نص + تفكير)" + }, + "jsonTree": { + "viewRaw": "عرض JSON الخام", + "viewTree": "عرض الشجرة", + "fields": "{count, plural, zero {لا حقول} one {حقل واحد} two {حقلان} few {# حقول} many {# حقلًا} other {# حقل}}", + "items": "{count, plural, zero {لا عناصر} one {عنصر واحد} two {عنصران} few {# عناصر} many {# عنصرًا} other {# عنصر}}" + }, + "tool": { + "parameters": "المعلمات", + "error": "خطأ", + "result": "النتيجة", + "status": { + "approvalRequested": "بانتظار الموافقة", + "approvalResponded": "تم الرد", + "inputAvailable": "قيد التشغيل", + "inputStreaming": "قيد الانتظار", + "outputAvailable": "مكتمل", + "outputDenied": "مرفوض", + "outputError": "خطأ" + } + }, + "toolCallBlock": { + "tool": "أداة", + "error": "خطأ", + "result": "النتيجة" + }, + "delegation": { + "subAgentRunning": "العميل الفرعي قيد التشغيل…", + "noDetail": "No detail available yet.", + "unknownAgent": "وكيل فرعي", + "openDetail": "عرض المحادثة", + "detailTitle": "محادثة الوكيل الفرعي", + "detailDescription": "عرض للقراءة فقط لمحادثة الوكيل الفرعي المُفوَّض.", + "waitForResult": "في انتظار نتيجة المهمة {task}", + "waitForResultNoTask": "في انتظار نتيجة المهمة", + "cancelTask": "جارٍ إلغاء المهمة {task}", + "cancelTaskNoTask": "جارٍ إلغاء المهمة", + "resultPageOf": "{current} / {total}", + "prevResult": "النتيجة السابقة", + "nextResult": "النتيجة التالية", + "noResultText": "لا توجد نتيجة في هذا الفحص.", + "status": { + "starting": "قيد البدء", + "running": "قيد التشغيل", + "checked": "تم الفحص", + "waiting": "في انتظار الموافقة", + "ok": "اكتمل", + "err": { + "default": "فشل", + "delegation_disabled": "معطل", + "depth_limit": "حد العمق", + "invalid_agent_type": "وكيل غير صالح", + "spawn_failed": "فشل البدء", + "send_failed": "فشل الإرسال", + "timeout": "انتهت المهلة", + "canceled": "ملغى", + "child_refusal": "رفض الوكيل الفرعي", + "child_max_tokens": "الوكيل الفرعي: حد الرموز", + "child_max_turn_requests": "الوكيل الفرعي: حد الطلبات", + "child_empty": "الوكيل الفرعي بدون استجابة", + "child_unknown": "الوكيل الفرعي: خطأ", + "unknown": "مهمة غير معروفة" + } + } + }, + "contentParts": { + "showingTailOutput": "يتم عرض نهاية المخرجات أثناء البث لتحسين الأداء.", + "result": "النتيجة", + "unknown": "غير معروف", + "inputTruncated": "تم اقتطاع الإدخال — قد يكون الفرق غير مكتمل.", + "replaceAll": "استبدال الكل", + "filesCount": "الملفات: {count}", + "update": "تحديث", + "moreFiles": "+{count} ملف إضافي", + "timeoutMs": "المهلة: {timeout}ms", + "backgroundTrue": "الخلفية: true", + "scriptToolCalls": "{count, plural, zero {صفر استدعاء أداة} one {استدعاء أداة واحد} two {استدعاءا أداة} few {# استدعاءات أداة} many {# استدعاء أداة} other {# استدعاء أداة}}", + "offset": "الإزاحة: {offset}", + "limit": "الحد: {limit}", + "pages": "الصفحات: {pages}", + "mode": "الوضع: {mode}", + "cell": "الخلية: {cell}", + "shellSession": "الجلسة {id}", + "pathLabel": "المسار:", + "globLabel": "نمط glob:", + "typeLabel": "النوع:", + "outputLabel": "المخرجات:", + "caseInsensitive": "غير حساس لحالة الأحرف", + "multiline": "متعدد الأسطر", + "promptLabel": "المطالبة", + "subjectLabel": "الموضوع", + "taskLabel": "المهمة", + "nameLabel": "الاسم:", + "agentPromptLabel": "المطالبة", + "agentModelLabel": "النموذج", + "agentRunning": "قيد التشغيل...", + "agentLiveTranscript": "النشاط المباشر", + "agentProgressTools": "{count} استدعاءات أدوات", + "agentProgressTurns": "{count} جولات", + "agentProgressContext": "السياق {pct}%", + "agentSessionAction": "عرض جلسة الوكيل الفرعي", + "agentSessionTitle": "جلسة الوكيل الفرعي", + "agentSessionLoading": "جارٍ تحميل سجل الوكيل الفرعي…", + "agentSessionEmpty": "لم يكتب الوكيل الفرعي أي شيء بعد.", + "agentFallbackTitle": "جارٍ تشغيل الوكيل الفرعي…", + "agentCodexLaunchOnly": "تم التشغيل. لا يبلّغ Codex عن أي تقدّم إضافي لهذا الوكيل الفرعي — وستصل نتيجته كرسالة في هذه المحادثة.", + "agentStatsBash": "الأوامر", + "agentStatsRead": "الملفات المقروءة", + "agentStatsSearch": "عمليات البحث", + "agentStatsEdit": "التعديلات", + "agentStatsOther": "أخرى", + "goal": { + "title": "الهدف:", + "titleWithStatus": "الهدف {status}", + "objective": "الهدف", + "statusLabel": "الحالة", + "tokensUsed": "tokens المستخدمة", + "budget": "الميزانية", + "remaining": "المتبقي", + "elapsed": "المدة", + "tokens": "tokens", + "pause": "إيقاف مؤقت", + "clear": "مسح", + "status": { + "active": "نشط", + "paused": "متوقف مؤقتًا", + "blocked": "محظور", + "usageLimited": "الاستخدام محدود", + "budgetLimited": "الميزانية محدودة", + "complete": "مكتمل", + "limited": "تم بلوغ الحد" + } + }, + "field": { + "file": "ملف", + "notebook": "دفتر", + "command": "أمر", + "old": "قديم", + "new": "جديد", + "pattern": "النمط", + "path": "المسار", + "query": "الاستعلام", + "url": "URL:", + "description": "الوصف", + "content": "المحتوى", + "source": "المصدر", + "prompt": "المطالبة", + "subject": "الموضوع", + "taskId": "معرف المهمة", + "status": "الحالة", + "skill": "Skill", + "args": "الوسائط", + "offset": "الإزاحة", + "limit": "الحد", + "glob": "نمط glob", + "type": "النوع", + "output": "المخرجات", + "replaceAll": "استبدال الكل", + "language": "اللغة", + "timeout": "المهلة", + "background": "الخلفية", + "agentType": "نوع الوكيل", + "library": "المكتبة", + "libraryId": "معرف المكتبة" + }, + "title": { + "edit": "تحرير", + "command": "أمر", + "script": "سكربت", + "waitCommand": "انتظار {command}", + "waitCell": "انتظار الجلسة {id}", + "terminateCommand": "إنهاء {command}", + "terminateCell": "إنهاء الجلسة {id}", + "stdinChars": "إدخال {chars}", + "todoWrite": "TodoWrite (تحديث المهام)", + "read": "قراءة", + "write": "كتابة", + "notebookEdit": "NotebookEdit (تحرير الدفتر)", + "editFiles": "تحرير ({count} ملفًا)", + "editWithTarget": "تحرير {target}", + "readWithTarget": "قراءة {target}", + "writeWithTarget": "كتابة {target}", + "notebookEditWithTarget": "NotebookEdit ({target})", + "globWithPattern": "نمط glob {pattern}", + "listFilesWithPath": "عرض الملفات {path}", + "grepWithPattern": "نمط grep {pattern}", + "taskCreateWithSubject": "إنشاء مهمة: {subject}", + "taskUpdateWithStatus": "تحديث المهمة #{id} -> {status}", + "taskUpdate": "تحديث المهمة #{id}", + "webFetchWithUrl": "WebFetch ({url})", + "webSearchWithQuery": "بحث الويب: {query}", + "todosProgress": "المهام ({done}/{total})", + "skillWithName": "Skill: {name}", + "genericWithContext": "{tool} ({context})" + }, + "search": { + "noMatches": "لا توجد نتائج مطابقة", + "matchSummary": "{matches, plural, zero {صفر تطابق} one {تطابق واحد} two {تطابقان} few {# تطابقات} many {# تطابقاً} other {# تطابق}} في {files, plural, zero {صفر ملف} one {ملف واحد} two {ملفان} few {# ملفات} many {# ملفاً} other {# ملف}}", + "fileSummary": "{files, plural, zero {صفر ملف} one {ملف واحد} two {ملفان} few {# ملفات} many {# ملفاً} other {# ملف}}", + "moreResults": "{count, plural, zero {لا نتائج إضافية} one {نتيجة إضافية واحدة غير معروضة} two {نتيجتان إضافيتان غير معروضتين} few {# نتائج إضافية غير معروضة} many {# نتيجة إضافية غير معروضة} other {# نتيجة إضافية غير معروضة}}" + }, + "toolGroup": { + "search": "{count, plural, zero {بحث صفر مرة} one {بحث مرة واحدة} two {بحث مرتين} few {بحث # مرات} many {بحث # مرة} other {بحث # مرة}}", + "command": "{count, plural, zero {تنفيذ صفر أمر} one {تنفيذ أمر واحد} two {تنفيذ أمرين} few {تنفيذ # أوامر} many {تنفيذ # أمراً} other {تنفيذ # أمر}}", + "read": "{count, plural, zero {قراءة ملفات صفر مرة} one {قراءة ملفات مرة واحدة} two {قراءة ملفات مرتين} few {قراءة ملفات # مرات} many {قراءة ملفات # مرة} other {قراءة ملفات # مرة}}", + "memory": "{count, plural, zero {استرجاع صفر ذاكرة} one {استرجاع ذاكرة واحدة} two {استرجاع ذاكرتين} few {استرجاع # ذكريات} many {استرجاع # ذكرى} other {استرجاع # ذكرى}}", + "edit": "{count, plural, zero {تعديل ملفات صفر مرة} one {تعديل ملفات مرة واحدة} two {تعديل ملفات مرتين} few {تعديل ملفات # مرات} many {تعديل ملفات # مرة} other {تعديل ملفات # مرة}}", + "fetch": "{count, plural, zero {جلب صفر مورد} one {جلب مورد واحد} two {جلب موردين} few {جلب # موارد} many {جلب # مورداً} other {جلب # مورد}}", + "think": "{count, plural, zero {تفكير صفر مرة} one {تفكير مرة واحدة} two {تفكير مرتين} few {تفكير # مرات} many {تفكير # مرة} other {تفكير # مرة}}", + "todo": "{count, plural, zero {تحديث صفر مهمة} one {تحديث مهمة واحدة} two {تحديث مهمتين} few {تحديث # مهام} many {تحديث # مهمة} other {تحديث # مهمة}}", + "task": "{count, plural, zero {تشغيل صفر مهمة} one {تشغيل مهمة واحدة} two {تشغيل مهمتين} few {تشغيل # مهام} many {تشغيل # مهمة} other {تشغيل # مهمة}}", + "other": "{count, plural, zero {استخدام صفر أداة} one {استخدام أداة واحدة} two {استخدام أداتين} few {استخدام # أدوات} many {استخدام # أداة} other {استخدام # أداة}}", + "errorSuffix": "{count, plural, zero {صفر فشل} one {فشل واحد} two {فشلان} few {# فشلوا} many {# فشلاً} other {# فشل}}", + "joiner": " · " + }, + "planMode": { + "entered": "تم بدء وضع التخطيط", + "planLabel": "الخطة", + "reviewApproved": "تمت الموافقة على الخطة — جارٍ التنفيذ", + "reviewKept": "الاستمرار في وضع الخطة", + "reviewPending": "في انتظار قرار الخطة", + "submitted": "تم إرسال الخطة", + "switched": "تم تبديل الوضع" + }, + "backgroundTask": { + "title": "مهمة في الخلفية", + "titleWithId": "مهمة في الخلفية · {id}", + "running": "قيد التشغيل", + "completed": "اكتملت", + "failed": "فشلت", + "stopped": "متوقفة", + "exitCode": "رمز الخروج {code}", + "polledTimes": "تم الاستعلام {count} مرة", + "runningInBackground": "في الخلفية", + "launchNote": "قيد التشغيل في الخلفية · {id}" + }, + "codexScript": { + "outputMissing": "اقتطع codex مُخرَج النص البرمجي وأزال الفاصل الخاص بهذا الأمر، لذا تعذّر نسب أي مُخرَج إليه.", + "sharedWith": "يحتوي هذا المقطع أيضًا على مُخرَج {commands} — إذ اقتطع codex الفواصل الخاصة بها.", + "truncated": "مقتطع" + } + }, + "messageNav": { + "title": "تنقل الرسائل", + "collapse": "طي تنقل الرسائل", + "collapsedSummary": "الرسائل {count}", + "fileCount": "{count, plural, one {# ملف} other {# ملفات}}", + "remove": "إزالة", + "noDiffDataAvailable": "لا توجد بيانات diff متاحة لـ {filePath}" + }, + "replyArtifacts": { + "title": "الملفات المتغيرة", + "fileCount": "{count, plural, one {# ملف} other {# ملفات}}", + "newFilesTitle": "ملفات جديدة", + "revealInFolder": "عرض في مدير الملفات", + "openFile": "فتح {filePath}", + "openInEditor": "فتح في المحرر", + "remove": "إزالة", + "noDiffDataAvailable": "لا توجد بيانات diff متاحة لـ {filePath}" + }, + "askQuestion": { + "title": "يحتاج الوكيل إلى اختيارك", + "subtitle": "أجب ثم أرسل. يمكنك التخطّي في أي وقت.", + "recommended": "موصى به", + "other": "أخرى", + "otherPlaceholder": "اكتب إجابتك…", + "singleSelect": "اختيار واحد", + "multiSelect": "اختيار متعدد", + "skip": "تخطّي", + "next": "التالي", + "submit": "إرسال", + "submitError": "تعذّر الإرسال. حاول مرة أخرى." + }, + "planApproval": { + "title": "لدى الوكيل خطة — راجعها", + "emptyPlan": "لم يكتب الوكيل خطة. وافق للبدء في التنفيذ أو اطلب تعديلات.", + "approve": "الموافقة والبدء", + "requestChanges": "طلب تعديلات", + "abandon": "تجاهل", + "feedbackPlaceholder": "ما الذي ينبغي تغييره؟", + "sendChanges": "إرسال", + "cancel": "إلغاء", + "submitError": "تعذّر الإرسال. حاول مرة أخرى." + }, + "feedbackCheckResult": { + "count": "{count} ملاحظة", + "expand": "عرض كل الملاحظات", + "collapse": "طي", + "errorTitle": "فشل التحقق من الملاحظات" + }, + "askQuestionResult": { + "title": "سؤال", + "answeredLabel": "سؤال وجواب:", + "awaiting": "في انتظار إجابتك…", + "declined": "لقد تجاهلت هذا — استخدم الوكيل حكمه الخاص.", + "noSelection": "لا يوجد اختيار" + }, + "configStale": { + "agentConfigTitle": "تم تحديث إعدادات الوكيل", + "modelProviderTitle": "تم تحديث مزوّد النموذج", + "description": "لا تزال هذه الجلسة تستخدم الإعدادات السابقة. أعد الاتصال لتطبيقها (سيتم الاحتفاظ بسجل المحادثة).", + "reconnect": "أعد الاتصال للتطبيق", + "reconnecting": "جارٍ إعادة الاتصال…", + "reconnectDisabledDuringTurn": "متاح بعد انتهاء الدور الحالي", + "dismiss": "تجاهل", + "reconnectFailed": "فشل في إعادة الاتصال بالجلسة", + "applied": "تم تطبيق الإعدادات الجديدة" + }, + "piProjectTrust": { + "title": "يتضمّن هذا المشروع موارد pi", + "description": "لا يقوم pi بتحميل ملفات ‎.pi الخاصة بالمستودع. راجعها لتقرّر.", + "descriptionExecutable": "يتضمّن المستودع إضافات pi تُنفّذ التعليمات البرمجية عند بدء التشغيل. لا يقوم pi بتحميلها. راجعها قبل أن تقرّر.", + "review": "مراجعة…", + "dismiss": "تجاهل", + "dialogTitle": "هل تثق بموارد pi في هذا المشروع؟", + "dialogDescription": "لا يحمّل pi ملفات ‎.pi الخاصة بالمستودع إلا إذا وثقت بالمجلد. لا تمنح الثقة إلا إذا كنت تثق بمحتوى هذا المستودع.", + "executionWarning": "الإضافات هي تعليمات برمجية. الوثوق بهذا المجلد يتيح للمستودع تشغيلها عند بدء pi بصلاحياتك، وقبل أن ترسل أي رسالة.", + "scopeNote": "يُحفظ القرار في ملف trust.json الخاص بـ pi لهذا المجلد، ويسري على كل المجلدات داخله، ويُستخدم أيضًا عند تشغيلك pi بنفسك في الطرفية. يمكنك تغييره لاحقًا من الإعدادات ← الوكلاء ← Pi.", + "trust": "الوثوق بالمشروع", + "decline": "إبقاؤها غير محمّلة", + "disabledDuringTurn": "متاح بعد انتهاء الدور الحالي", + "trustedToast": "تم الوثوق بالمشروع — أُعيد الاتصال ليحمّل pi موارده", + "declinedToast": "تبقى موارد المشروع غير محمّلة", + "saveFailed": "تعذّر حفظ قرار الثقة بالمشروع", + "grantTitle": "هذا المشروع موثوق بالفعل", + "grantDescription": "يحمّل pi ملفات ‎.pi الخاصة بهذا المستودع. راجع ما الذي يسمح به ذلك.", + "grantInheritedDescription": "أحد المجلدات الأعلى موثوق، لذا يحمّل pi ملفات ‎.pi الخاصة بهذا المستودع. راجع ما الذي يسمح به ذلك.", + "grantDialogTitle": "موارد pi في هذا المشروع موثوقة", + "grantDialogDescription": "يُسمح لـ pi بتحميل ملفات ‎.pi الخاصة بهذا المستودع. كانت إصدارات codeg السابقة تمنح ذلك تلقائيًا عند فتحك لمجلد، لذا ربما لم يُطلب رأيك مطلقًا.", + "grantExecutionWarning": "الإضافات هي تعليمات برمجية. يشغّلها المستودع عند بدء pi بصلاحياتك، قبل أن ترسل أي رسالة.", + "inheritedFrom": "الثقة موروثة من", + "revoke": "إلغاء الثقة", + "keepTrusted": "الإبقاء على الثقة", + "revokedToast": "أُلغيت الثقة — أُعيد الاتصال ليتوقف pi عن تحميل موارد المشروع", + "trustedNoReconnect": "تم الوثوق بالمشروع — سيسري عند بدء pi في المرة القادمة", + "revokedNoReconnect": "أُلغيت الثقة — ستسري عند بدء pi في المرة القادمة" + }, + "collabAgent": { + "title": "وكيل فرعي", + "errorTitle": "فشلت مهمة الوكيل الفرعي", + "statesLabel": "الوكلاء الفرعيون", + "statusRunning": "قيد التشغيل", + "statusCompleted": "مكتمل", + "statusFailed": "فشل", + "statusPending": "قيد البدء", + "statusInterrupted": "متوقف", + "statusClosed": "مغلق", + "statusNotFound": "غير موجود", + "opSpawn": "بدء تشغيل الوكيل الفرعي", + "opWait": "جلب نتيجة الوكيل الفرعي", + "opClose": "إغلاق الوكيل الفرعي", + "opResume": "استئناف الوكيل الفرعي" + }, + "contextCompaction": { + "compacting": "جارٍ ضغط السياق…", + "compacted": "تم ضغط السياق", + "compactedTokens": "تم ضغط السياق · {before} → {after} رمز", + "failed": "فشل ضغط السياق" + }, + "sessionFailure": { + "category": { + "connection": "مشكلة في الاتصال", + "access": "مشكلة في الوصول", + "limit": "تم بلوغ الحد", + "request": "تم رفض الطلب", + "service": "مشكلة في الخدمة", + "unknown": "مشكلة في الجلسة" + }, + "action": { + "retry": "إعادة المحاولة", + "login": "تسجيل الدخول", + "newSession": "جلسة جديدة" + }, + "recovered": "تم التعافي", + "retryUnavailable": "لا توجد رسالة سابقة لإعادة إرسالها.", + "toggleDetails": "تبديل التفاصيل" + }, + "backgroundTasks": { + "running": "{count, plural, one {مهمة خلفية واحدة قيد التشغيل} two {مهمتا خلفية قيد التشغيل} few {# مهام خلفية قيد التشغيل} other {# مهمة خلفية قيد التشغيل}}", + "settling": "جارٍ مزامنة نتائج الخلفية…", + "settledFallback": "انتهت مهمة الخلفية ({status})", + "cardRunning": "قيد التشغيل في الخلفية", + "cardLaunchedPending": "بدأت مهمة الخلفية", + "cardCompleted": "اكتملت مهمة الخلفية", + "cardFinishedWithStatus": "انتهت مهمة الخلفية ({status})", + "cardResultPending": "لم تصل النتيجة بعد" + }, + "proposedPlan": { + "title": "الخطة المقترحة", + "planning": "جارٍ التخطيط…" + } + }, + "diffPreview": { + "mode": { + "added": "تمت الإضافة", + "deleted": "تم الحذف", + "renamed": "تمت إعادة التسمية", + "modified": "تم التعديل" + }, + "hunkLabel": "مقطع {index}", + "loadingHunk": "جارٍ تحميل hunk...", + "noDiffData": "لا توجد بيانات diff", + "showRemainingLines": "عرض {count} سطر إضافي" + }, + "conversationContextBar": { + "folderTitle": "مجلد العمل", + "branchTitle": "فرع العمل", + "searchFolder": "Search folder...", + "searchBranch": "Search branch...", + "noFolders": "No folders", + "noBranches": "No branches", + "noBranch": "(no branch)", + "chatModeLabel": "وضع الدردشة", + "commit": "Commit", + "push": "Push", + "merge": "Merge", + "toasts": { + "folderChanged": "Switched to {name}", + "openFolderFailed": "Failed to open folder", + "switchedToChatMode": "تم التبديل إلى وضع المحادثة", + "openStashFailed": "Failed to open stash window", + "openMergeFailed": "Failed to open merge window" + } + }, + "cloneDialog": { + "title": "استنساخ مستودع", + "repositoryUrl": "رابط المستودع", + "repositoryUrlPlaceholder": "https://github.com/user/repo.git", + "directory": "المجلد", + "directoryPlaceholder": "اختر مجلد الهدف...", + "browseDirectory": "تصفح المجلد", + "cancel": "إلغاء", + "clone": "استنساخ", + "clonePath": "مسار الاستنساخ: {path}" + }, + "toasts": { + "cloneFailed": "فشل استنساخ المستودع" + } + }, + "ProjectBoot": { + "title": "مُنشئ المشروع", + "tabs": { + "shadcn": "shadcn", + "hyperframes": "HyperFrames" + }, + "hyperframes": { + "title": "مشروع فيديو HyperFrames", + "subtitle": "أنشئ مشروعًا لتحويل HTML إلى فيديو. يمكن لوكيل مساحة العمل بعد ذلك كتابته وعرضه.", + "resolution": "الدقة", + "skillsTitle": "مهارات الوكلاء", + "skillsDesc": "ثبّت مهارات HyperFrames عامًّا (رابط رمزي) للوكلاء المحددين حتى يتمكنوا من إنشاء الفيديو وعرضه.", + "recheck": "إعادة الفحص", + "installedBadge": "مثبّت", + "skillsInstall": "تثبيت / تحديث المهارات", + "skillsInstalling": "جارٍ تثبيت المهارات…", + "skillsInstalled": "تم تثبيت مهارات HyperFrames", + "skillsInstallFailed": "تعذّر تثبيت مهارات HyperFrames" + }, + "config": { + "base": "الأساس", + "style": "النمط", + "baseColor": "اللون الأساسي", + "theme": "السمة", + "chartColor": "لون المخطط", + "iconLibrary": "مكتبة الأيقونات", + "font": "الخط", + "fontHeading": "خط العنوان", + "menuAccent": "تمييز القائمة", + "menuColor": "لون القائمة", + "radius": "نصف القطر", + "template": "القالب", + "createProject": "إنشاء مشروع", + "sectionStyle": "النمط", + "sectionColors": "الألوان", + "sectionTypography": "الخطوط", + "sectionInterface": "الواجهة" + }, + "preview": { + "loading": "جاري تحميل المعاينة..." + }, + "createDialog": { + "title": "إنشاء مشروع", + "projectName": "اسم المشروع", + "projectNamePlaceholder": "my-app", + "frameworkTemplate": "قالب الإطار", + "packageManager": "مدير الحزم", + "saveDirectory": "دليل الحفظ", + "saveDirectoryPlaceholder": "اختر الدليل...", + "browseDirectory": "تصفح", + "projectPath": "سيتم إنشاء المشروع في: {path}", + "advancedOptions": "خيارات متقدمة", + "base": "المكتبة الأساسية", + "enableRtl": "تفعيل دعم RTL", + "enableRtlDescription": "تفعيل دعم التخطيط للغات التي تُكتب من اليمين إلى اليسار (مثل العربية والعبرية)", + "pmChecking": "جارٍ التحقق...", + "pmNotInstalled": "غير مثبت", + "cancel": "إلغاء", + "create": "إنشاء", + "creating": "جاري إنشاء المشروع..." + }, + "toasts": { + "createFailed": "فشل إنشاء المشروع", + "createSuccess": "تم إنشاء المشروع بنجاح", + "openWorkspaceFailed": "تم إنشاء المشروع، ولكن تعذّر فتحه في مساحة العمل" + }, + "errors": { + "directoryExists": "الدليل الهدف موجود بالفعل", + "commandFailed": "فشل أمر إنشاء المشروع." + } + }, + "WebServiceSettings": { + "addressSwitchHint": "التبديل يغيّر فقط العنوان المعروض والمفتوح هنا؛ تستمع الخدمة على جميع الواجهات وتبقى قابلة للوصول من كل عنوان.", + "sectionTitle": "خدمة الويب", + "sectionDescription": "تفعيل للوصول إلى Codeg عن بُعد عبر المتصفح", + "port": "المنفذ", + "status": "الحالة", + "autoStart": "تشغيل تلقائي", + "autoStartHint": "تشغيل خدمة الويب عند بدء Codeg", + "running": "قيد التشغيل", + "stopped": "متوقف", + "processing": "جارٍ المعالجة...", + "start": "تشغيل", + "stop": "إيقاف", + "startFailed": "فشل التشغيل", + "stopFailed": "فشل الإيقاف", + "saveConfigFailed": "فشل حفظ إعدادات خدمة الويب", + "open": "فتح", + "hide": "إخفاء", + "show": "إظهار", + "copy": "نسخ", + "qrcode": "رمز QR", + "qrcodeTitle": "امسح للفتح", + "qrcodeHint": "امسح بهاتفك لفتح Codeg في المتصفح", + "addressLabel": "عنوان الوصول", + "tokenLabel": "رمز الوصول", + "tokenHint": "أدخل هذا الرمز عند الوصول إلى عميل الويب لأول مرة", + "tokenPlaceholder": "اتركه فارغاً للتوليد التلقائي", + "regenerate": "إعادة التوليد", + "stalePortOccupiedTitle": "المنفذ {port} مستخدم من قبل عملية أخرى", + "stalePortUnknownTitle": "حالة المنفذ {port} غير واضحة", + "stalePortHint": "لا يستطيع Codeg الربط قبل تحرير المنفذ. غيّر المنفذ أعلاه، أو أغلق العملية التي تحتفظ به.", + "errors": { + "alreadyRunning": "خدمة الويب قيد التشغيل بالفعل", + "invalidAddress": "تنسيق المضيف أو المنفذ غير صالح", + "portInUse": "المنفذ {port} مستخدم بالفعل. أغلق العملية التي تستخدمه أو اختر منفذاً آخر.", + "permissionDenied": "الصلاحيات غير كافية. استخدم منفذاً أعلى من 1024 أو شغّل التطبيق بصلاحيات أعلى.", + "addressUnavailable": "هذا العنوان غير متاح على هذا الجهاز", + "bindFailed": "فشل ربط العنوان" + } + }, + "DirectoryBrowser": { + "title": "تصفح المجلد", + "pathPlaceholder": "أدخل مسار المجلد...", + "goHome": "الذهاب إلى المجلد الرئيسي", + "navigateUp": "الذهاب إلى المجلد الأعلى", + "select": "اختيار", + "cancel": "إلغاء", + "loading": "جاري التحميل...", + "emptyDirectory": "هذا المجلد فارغ", + "errorLoadingDir": "فشل في تحميل المجلد", + "permissionDenied": "تم رفض الإذن" + }, + "ChatChannelSettings": { + "loading": "جاري التحميل...", + "sectionTitle": "قنوات المحادثة", + "sectionDescription": "تكوين بوتات المراسلة لتلقي إشعارات الأحداث واستعلام نشاط البرمجة.", + "addChannel": "إضافة قناة", + "noChannels": "لم يتم تكوين أي قنوات محادثة بعد.", + "channelName": "الاسم", + "channelNamePlaceholder": "بوت Telegram الخاص بي", + "channelType": "نوع القناة", + "lark": "Lark (Feishu)", + "weixin": "WeChat", + "dailyReport": "التقرير اليومي", + "dailyReportTime": "وقت التقرير", + "nameRequired": "اسم القناة مطلوب.", + "tokenRequired": "الرمز مطلوب.", + "chatIdRequired": "معرف المحادثة مطلوب.", + "topicMode": "وضع مجموعة المواضيع", + "topicModeHint": "يوجه مواضيع منتدى Telegram كجلسات Codeg منفصلة. يجب أن يكون البوت في forum supergroup وأن يملك صلاحية إدارة المواضيع.", + "loadFailed": "فشل في تحميل القنوات.", + "saveFailed": "فشل في حفظ التغييرات.", + "connectSuccess": "تم توصيل القناة.", + "connectFailed": "فشل الاتصال", + "disconnectSuccess": "تم قطع اتصال القناة.", + "disconnectFailed": "فشل قطع الاتصال.", + "testSuccess": "نجح اختبار الاتصال.", + "testFailed": "فشل اختبار الاتصال", + "deleteSuccess": "تم حذف القناة.", + "deleteFailed": "فشل في حذف القناة.", + "deleteConfirmTitle": "حذف القناة", + "deleteConfirmMessage": "سيتم حذف القناة وسجلات رسائلها نهائياً. هل أنت متأكد؟", + "cancel": "إلغاء", + "delete": "حذف", + "create": "إنشاء", + "save": "حفظ", + "channelListTitle": "القنوات المُعدة", + "channelListDescription": "القنوات المفعّلة ستتصل تلقائيًا عند بدء تشغيل الخدمة.", + "editChannel": "تعديل القناة", + "editSuccess": "تم تحديث القناة.", + "tokenPlaceholderKeep": "اتركه فارغاً للاحتفاظ بالقيمة الحالية", + "weixinScanTitle": "مسح رمز QR", + "weixinScanDescription": "افتح WeChat وامسح رمز QR للاتصال.", + "weixinQrcodeExpired": "انتهت صلاحية رمز QR.", + "weixinRefreshQrcode": "تحديث", + "weixinWaitingScan": "في انتظار المسح...", + "weixinPollError": "الاتصال غير مستقر، جاري إعادة المحاولة...", + "weixinReconnectNotice": "بسبب قيود بروتوكول iLink، بعد كل إعادة اتصال يجب عليك إرسال رسالة إلى الروبوت حتى تصبح مشغلات الأحداث فعالة.", + "connect": "اتصال", + "disconnect": "قطع الاتصال", + "test": "اختبار الاتصال", + "tabs": { + "channels": "القنوات", + "commands": "الأوامر", + "events": "الأحداث", + "other": "أخرى" + }, + "commands": { + "title": "الأوامر المدمجة", + "description": "أوامر البوت المتاحة في قنوات المحادثة. في المحادثات الجماعية، يلزم @Bot لمعالجة الرسائل.", + "prefixLabel": "بادئة الأمر", + "prefixDescription": "1-3 أحرف غير أبجدية رقمية لتشغيل أوامر البوت (الافتراضي /).", + "prefixSaved": "تم حفظ بادئة الأمر.", + "prefixSaveFailed": "فشل حفظ بادئة الأمر.", + "prefixInvalid": "يجب أن تكون البادئة 1-3 أحرف غير أبجدية رقمية.", + "save": "حفظ", + "folderDesc": "اختيار مجلد العمل", + "agentDesc": "اختيار وكيل الذكاء الاصطناعي", + "taskDesc": "إنشاء جلسة وتنفيذ المهمة", + "sessionsDesc": "عرض الجلسات النشطة في المجلد", + "resumeDesc": "المحادثات الأخيرة / استئناف جلسة", + "cancelDesc": "إلغاء المهمة الحالية", + "approveDesc": "الموافقة على طلب إذن الوكيل", + "denyDesc": "رفض طلب إذن الوكيل", + "searchDesc": "البحث في المحادثات حسب الكلمة المفتاحية", + "todayDesc": "ملخص نشاط اليوم", + "statusDesc": "حالة اتصال القناة", + "helpDesc": "عرض المساعدة" + }, + "events": { + "title": "إشعارات الأحداث", + "description": "عند تفعيل الأحداث، سيتم إرسالها إلى القناة عند تشغيلها.", + "turnComplete": "اكتمال الدور", + "turnCompleteDesc": "عند انتهاء دور الوكيل", + "error": "خطأ الوكيل", + "errorDesc": "عندما يواجه الوكيل خطأ", + "permissionRequest": "طلب إذن", + "permissionRequestDesc": "عندما يطلب الوكيل إذنًا لتنفيذ إجراء", + "questionRequest": "سؤال من الوكيل", + "questionRequestDesc": "عندما يطرح أحد الوكلاء سؤالاً عليك", + "userPromptSent": "رسالة المستخدم", + "userPromptSentDesc": "عند إرسالك رسالة — يُضمَّن نص الرسالة في الإشعار", + "saved": "تم تحديث فلتر الأحداث.", + "saveFailed": "فشل حفظ فلتر الأحداث.", + "loadFailed": "فشل تحميل الإعدادات.", + "retry": "إعادة المحاولة", + "webhooksTitle": "Webhooks", + "webhooksDescription": "يرسل حمولة JSON عبر POST إلى عنوان واحد أو أكثر عند تشغيل حدث مُفعَّل. ينطبق فلتر الأحداث أعلاه على Webhooks أيضًا.", + "webhookUrlPlaceholder": "https://example.com/webhook", + "addWebhook": "إضافة Webhook", + "removeWebhook": "إزالة Webhook", + "webhookSave": "حفظ", + "webhooksSaved": "تم حفظ Webhooks.", + "webhooksSaveFailed": "فشل حفظ Webhooks.", + "webhookInvalidUrl": "أدخل عناوين http(s) صالحة.", + "docsTitle": "تنسيق الطلب", + "docsMethod": "الطريقة", + "docsContentType": "Content-Type", + "docsNote": "يتم تسليم كل حدث مُفعَّل إلى جميع العناوين. لا يتم تأخير Webhooks؛ ولا يزال فلتر الأحداث أعلاه ساريًا.", + "editWebhook": "تعديل Webhook", + "enableWebhook": "تفعيل Webhook", + "webhookDuplicate": "هذا العنوان مُعد بالفعل.", + "cancel": "إلغاء", + "webhooksEmpty": "لا توجد Webhooks مُعدة بعد.", + "deleteWebhookTitle": "حذف Webhook", + "deleteWebhookMessage": "هل تريد حذف هذا الـ Webhook؟ لن يتم تسليم الأحداث إلى هذا العنوان بعد الآن.", + "delete": "حذف" + }, + "language": { + "title": "لغة الرسائل", + "description": "اللغة المستخدمة لإشعارات الأحداث واستجابات الأوامر والتقارير اليومية المرسلة إلى قنوات الدردشة.", + "saved": "تم حفظ لغة الرسائل.", + "saveFailed": "فشل حفظ لغة الرسائل.", + "en": "الإنجليزية", + "zh-cn": "الصينية المبسطة", + "zh-tw": "الصينية التقليدية", + "ja": "اليابانية", + "ko": "الكورية", + "es": "الإسبانية", + "de": "الألمانية", + "fr": "الفرنسية", + "pt": "البرتغالية", + "ar": "العربية" + } + }, + "ModelProviderSettings": { + "sectionTitle": "مزودو النماذج", + "sectionDescription": "إدارة بيانات اعتماد مزودي API للوكلاء.", + "filterAll": "الكل", + "providerListTitle": "المزودون المُعدّون", + "addProvider": "إضافة مزود", + "editProvider": "تعديل المزود", + "noProviders": "لم يتم تكوين أي مزود نماذج بعد.", + "providerName": "الاسم", + "providerNamePlaceholder": "مثال: OpenAI، Anthropic", + "apiUrl": "عنوان API", + "apiUrlPlaceholder": "https://api.openai.com/v1", + "apiKey": "مفتاح API", + "apiKeyPlaceholder": "sk-...", + "apiKeyKeepCurrent": "اتركه فارغاً للإبقاء على الحالي", + "agentTypes": "أنواع الوكلاء", + "agentTypesRequired": "يجب اختيار نوع وكيل واحد على الأقل.", + "agentType": "نوع الوكيل", + "agentTypeRequired": "نوع الوكيل مطلوب.", + "agentTypeImmutableHint": "لا يمكن تغيير نوع الوكيل بعد الإنشاء.", + "model": "النموذج", + "modelPlaceholderCodex": "gpt-5.6-sol / gpt-5.5", + "modelPlaceholderGemini": "gemini-3-pro-preview", + "claudeMainModel": "النموذج الرئيسي", + "claudeReasoningModel": "نموذج الاستدلال (التفكير)", + "claudeHaikuDefaultModel": "نموذج Haiku الافتراضي", + "claudeSonnetDefaultModel": "نموذج Sonnet الافتراضي", + "claudeOpusDefaultModel": "نموذج Opus الافتراضي", + "claudeCustomModelOption": "معرّف النموذج المخصّص", + "claudeCustomModelOptionName": "اسم النموذج المخصّص", + "claudeCustomModelOptionDescription": "وصف النموذج المخصّص", + "claudeCustomModelOptionHint": "يضيف عنصرًا مخصّصًا واحدًا إلى محدِّد نماذج Claude (مثل نموذج خلف بوابة/وكيل مخصّص). الاسم والوصف اختياريان لأغراض العرض فقط.", + "nameRequired": "اسم المزود مطلوب.", + "apiUrlRequired": "عنوان API مطلوب.", + "apiKeyRequired": "مفتاح API مطلوب.", + "loadFailed": "فشل تحميل المزودين.", + "saveFailed": "فشل حفظ التغييرات.", + "createSuccess": "تم إنشاء المزود.", + "editSuccess": "تم تحديث المزود.", + "deleteSuccess": "تم حذف المزود.", + "deleteConfirmTitle": "حذف المزود", + "deleteConfirmMessage": "سيتم حذف المزود \"{name}\" نهائياً. هل أنت متأكد؟", + "deleteBlockedByAgent": "{agents} يستخدم هذا المزود. يرجى إلغاء الربط قبل الحذف.", + "cancel": "إلغاء", + "delete": "حذف", + "create": "إنشاء", + "save": "حفظ", + "affectedRunningSessions": "{count} جلسة نشطة تحتاج إلى إعادة الاتصال لتطبيق التغيير" + }, + "SkillMatrix": { + "loading": "جارٍ التحميل…", + "searchPlaceholder": "البحث بالاسم أو المعرّف أو الوصف", + "empty": "لا شيء لعرضه.", + "emptySearch": "لا توجد نتائج مطابقة للبحث الحالي.", + "skillColumn": "المهارة", + "selectAll": "تحديد كل المرئي", + "selectSkill": "تحديد {name}", + "everything": { + "label": "إجراء جماعي", + "enable": "تفعيل الكل (المرئي)", + "disable": "تعطيل الكل (المرئي)" + }, + "columnMenu": { + "enableAll": "تفعيل كل المهارات", + "disableAll": "تعطيل كل المهارات" + }, + "rowMenu": { + "label": "إجراءات جماعية لـ {name}", + "enableAll": "تفعيل لكل الوكلاء", + "disableAll": "تعطيل لكل الوكلاء" + }, + "bulk": { + "selected": "{count} محدد", + "targetAll": "كل الوكلاء", + "targetSome": "{count} وكلاء", + "enable": "تفعيل", + "disable": "تعطيل", + "clear": "مسح" + }, + "confirm": { + "disableTitle": "تعطيل هذه الروابط؟", + "disableBody": "سيؤدي هذا إلى إزالة {count} من روابط المهارات التي يديرها codeg. المهارات التي تشغل دليلاً مخصصاً تبقى دون تغيير. يمكنك إعادة تفعيلها في أي وقت.", + "cancel": "إلغاء", + "confirm": "تعطيل" + }, + "toasts": { + "loadFailed": "فشل تحميل حالات المهارات", + "applyFailed": "فشل تطبيق التغييرات", + "enabled": "تم تفعيل {count} رابط", + "disabled": "تم تعطيل {count} رابط", + "enabledPartial": "تم تفعيل {ok}، وفشل {failed}", + "disabledPartial": "تم تعطيل {ok}، وفشل {failed}" + }, + "detail": { + "enableForAgents": "التفعيل للوكلاء", + "preview": "معاينة SKILL.md", + "loadingContent": "جارٍ تحميل المحتوى…" + }, + "copyModeHint": "تم النسخ (غير مرتبط) — أعد التفعيل بعد التحديثات للحصول على أحدث إصدار" + }, + "ExpertsSettings": { + "title": "مهارات الخبراء", + "description": "فعّل سير عمل المهارات المختارة بعناية والمختبرة ميدانيًا لوكلاء البرمجة بالذكاء الاصطناعي. كل خبير هو مهارة مستقلة من مشروع superpowers — يدير codeg النسخة المركزية ويربطها بالوكلاء الذين تختارهم.", + "loading": "جاري تحميل الخبراء…", + "loadingContent": "جاري تحميل المحتوى…", + "emptyExperts": "لا يوجد خبراء متاحون. تحقق من سجلات التطبيق.", + "emptySelection": "اختر خبيرًا لرؤية محتواه وإدارة تفعيله.", + "emptySearch": "لا يوجد خبراء يطابقون البحث الحالي.", + "searchPlaceholder": "ابحث عن الخبراء بالاسم أو المعرّف أو الوصف", + "enableForAgents": "تفعيل للوكلاء", + "noAgents": "لم يتم اكتشاف وكلاء ACP.", + "copyModeWarning": "تم النسخ (غير مرتبط). أعد التفعيل بعد تحديثات codeg للحصول على أحدث إصدار.", + "previewTitle": "معاينة SKILL.md", + "categories": { + "discovery": "الاكتشاف والتصميم", + "planning": "التخطيط", + "execution": "التنفيذ", + "quality": "الجودة والاختبار", + "debugging": "التصحيح", + "review": "المراجعة والدمج", + "meta": "ميتا" + }, + "states": { + "not_linked": "غير مُفعَّل", + "linked_to_codeg": "مُفعَّل", + "linked_elsewhere": "محظور — يوجد رابط آخر", + "blocked_by_real_directory": "محظور — مهارة مخصصة تشغل هذا الاسم", + "broken": "رابط معطوب" + }, + "badges": { + "userModified": "عُدِّل من قبل المستخدم" + }, + "actions": { + "openCentralDir": "فتح المجلد المركزي", + "refresh": "تحديث" + }, + "toasts": { + "loadFailed": "فشل تحميل تفاصيل الخبير", + "enabled": "تم تفعيل الخبير لهذا الوكيل", + "disabled": "تم تعطيل الخبير لهذا الوكيل", + "enableFailed": "فشل تفعيل الخبير", + "disableFailed": "فشل تعطيل الخبير", + "openFolderFailed": "فشل فتح المجلد" + } + }, + "ScienceSettings": { + "title": "مهارات البحث العلمي", + "description": "فعّل مهارات البحث العلمي المنسّقة لوكلاء البرمجة بالذكاء الاصطناعي: توليد الفرضيات، وتصميم التجارب، والإحصاء، والتصور، والتقييم النقدي، والبحث في الأدبيات. يدير codeg نسخة مركزية ويربط كل مهارة بالوكلاء الذين تختارهم.", + "loading": "جارٍ تحميل مهارات البحث العلمي…", + "emptySkills": "لا توجد مهارات بحث علمي متاحة. تحقّق من سجلات التطبيق.", + "searchPlaceholder": "ابحث في مهارات البحث العلمي بالاسم أو المعرّف أو الوصف", + "categories": { + "ideation": "توليد الأفكار", + "design": "تصميم الدراسة", + "analysis": "التحليل", + "visualization": "التصور", + "evaluation": "التقييم", + "literature": "الأدبيات" + }, + "states": { + "not_linked": "غير مُفعَّل", + "linked_to_codeg": "مُفعَّل", + "linked_elsewhere": "محظور — يوجد رابط آخر", + "blocked_by_real_directory": "محظور — مهارة مخصصة تشغل هذا الاسم", + "broken": "رابط معطوب" + }, + "badges": { + "userModified": "عُدِّل من قبل المستخدم", + "needsKey": "يتطلب مفتاحًا", + "needsSetup": "قد يتطلب إعدادًا" + }, + "actions": { + "openCentralDir": "فتح المجلد المركزي", + "refresh": "تحديث" + }, + "toasts": { + "openFolderFailed": "فشل فتح المجلد" + } + }, + "OfficeToolsSettings": { + "title": "أدوات Office", + "description": "إدارة مهارات OfficeCLI لإنشاء ملفات Excel وWord وPowerPoint. قم بتثبيت OfficeCLI ومزامنة المهارات وتفعيلها لكل وكيل.", + "loadingContent": "جارٍ تحميل المحتوى…", + "emptySkills": "لا توجد مهارات متاحة. قم بتثبيت OfficeCLI ومزامنة المهارات.", + "emptySelection": "اختر مهارة لعرض محتواها وإدارة التفعيل.", + "emptySearch": "لا توجد مهارات مطابقة.", + "searchPlaceholder": "البحث بالاسم أو المعرف أو الوصف", + "enableForAgents": "تفعيل للوكلاء", + "noAgents": "لم يتم اكتشاف وكلاء ACP.", + "installFirst": "قم بتثبيت OfficeCLI أولاً لتفعيل المهارات.", + "syncFirst": "قم بمزامنة المهارات أولاً لتحميل المحتوى.", + "noContent": "لا يوجد محتوى متاح.", + "copyModeWarning": "تم النسخ (بدون ربط). أعد المزامنة للحصول على أحدث إصدار.", + "previewTitle": "معاينة SKILL.md", + "detection": { + "installed": "مثبّت", + "notInstalled": "غير مثبّت", + "notRunnable": "مثبّت لكن لا يعمل", + "installHint": "قم بتثبيت OfficeCLI لتفعيل مهارات إنشاء مستندات Office لوكلاء الذكاء الاصطناعي.", + "install": "تثبيت", + "uninstall": "إلغاء التثبيت", + "syncSkills": "مزامنة المهارات" + }, + "categories": { + "general": "عام", + "presentations": "عروض تقديمية", + "documents": "مستندات", + "spreadsheets": "جداول بيانات" + }, + "states": { + "not_linked": "غير مفعّل", + "linked_to_codeg": "مفعّل", + "linked_elsewhere": "محظور — يوجد رابط آخر", + "blocked_by_real_directory": "محظور — مهارة مخصصة تشغل هذا الاسم", + "broken": "رابط معطل" + }, + "badges": { + "notSynced": "غير متزامن" + }, + "actions": { + "refresh": "تحديث" + }, + "toasts": { + "loadFailed": "فشل تحميل تفاصيل المهارة", + "enabled": "تم تفعيل المهارة لهذا الوكيل", + "disabled": "تم تعطيل المهارة لهذا الوكيل", + "enableFailed": "فشل تفعيل المهارة", + "disableFailed": "فشل تعطيل المهارة", + "installSuccess": "تم تثبيت OfficeCLI بنجاح", + "installFailed": "فشل تثبيت OfficeCLI", + "uninstallSuccess": "تم إلغاء تثبيت OfficeCLI", + "uninstallFailed": "فشل إلغاء تثبيت OfficeCLI", + "syncSuccess": "تمت مزامنة {synced} مهارة", + "syncPartial": "تمت مزامنة {synced}، فشلت {errors}", + "syncFailed": "فشل مزامنة المهارات" + }, + "autoPreviewLabel": "فتح المعاينة تلقائيًا", + "autoPreviewHint": "عندما ينشئ وكيل ملف Word أو Excel أو PowerPoint أو يعدّله، افتح معاينته المباشرة تلقائيًا." + }, + "SkillPacksSettings": { + "title": "حزم المهارات", + "description": "حزم مهارات منسّقة يديرها codeg مركزيًا ويربطها بوكلاء الذكاء الاصطناعي لديك — خبراء البرمجة، والبحث العلمي، وأدوات مستندات المكتب. فعّلها لكل وكيل أدناه.", + "tabs": { + "experts": "الخبراء", + "science": "البحث العلمي", + "office": "أدوات المكتب", + "custom": "مخصّصة" + }, + "actions": { + "openCentralDir": "فتح المجلد المركزي", + "refresh": "تحديث" + }, + "toasts": { + "openFolderFailed": "فشل فتح المجلد" + } + }, + "QuickMessagesSettings": { + "title": "رسائل سريعة", + "description": "إدارة مقتطفات الرسائل القابلة لإعادة الاستخدام. اسحب لإعادة الترتيب.", + "loading": "جارٍ تحميل الرسائل السريعة…", + "emptyList": "لا توجد رسائل سريعة بعد. انقر على \"جديد\" لإنشاء واحدة.", + "emptySelection": "اختر رسالة سريعة للتعديل.", + "searchPlaceholder": "ابحث حسب العنوان أو المحتوى", + "untitled": "بدون عنوان", + "actions": { + "new": "جديد", + "save": "حفظ", + "delete": "حذف", + "dragSort": "اسحب لإعادة الترتيب", + "dragSortMessage": "اسحب لإعادة ترتيب الرسالة السريعة: {name}" + }, + "fields": { + "title": "العنوان", + "titlePlaceholder": "أعطِ هذه الرسالة عنوانًا قصيرًا", + "content": "المحتوى", + "contentPlaceholder": "اكتب محتوى الرسالة هنا" + }, + "confirmDelete": { + "title": "حذف الرسالة السريعة؟", + "message": "سيؤدي ذلك إلى حذف \"{name}\" نهائيًا. هل أنت متأكد؟", + "cancel": "إلغاء", + "confirm": "حذف" + }, + "toasts": { + "loadFailed": "فشل تحميل الرسائل السريعة", + "createFailed": "فشل إنشاء الرسالة السريعة", + "saveFailed": "فشل حفظ الرسالة السريعة", + "deleteFailed": "فشل حذف الرسالة السريعة", + "saveOrderFailed": "فشل حفظ الترتيب", + "created": "تم إنشاء الرسالة السريعة", + "saved": "تم حفظ الرسالة السريعة", + "deleted": "تم حذف الرسالة السريعة" + } + }, + "Pet": { + "badge": { + "running": "{count} قيد التشغيل", + "waiting": "{count} في انتظار الموافقة", + "error": "{count} بها خطأ" + }, + "panel": { + "title": "الجلسات النشطة", + "empty": "لا توجد جلسات نشطة", + "emptyHint": "تظهر هنا الوكلاء قيد التشغيل وتلك التي تحتاج إليك.", + "statusRunning": "قيد التشغيل", + "statusWaiting": "في الانتظار", + "statusError": "خطأ", + "subAgentOf": "وكيل فرعي لـ" + }, + "menu": { + "scale": "الحجم", + "openManager": "إدارة الحيوانات الأليفة", + "close": "إغلاق" + }, + "loadError": "فشل تحميل الحيوان الأليف", + "missingPetIdParam": "لم يتم اختيار حيوان أليف", + "summonButton": "حيوان أليف", + "manager": { + "title": "حيوانات سطح المكتب", + "description": "رفقاء عائمون لسطح المكتب باستخدام صفائح سبرايت متوافقة مع Codex.", + "addPet": "إضافة حيوان", + "importFromCodex": "استيراد من Codex", + "noPets": "لا يوجد حيوان أليف. أضف واحدًا أو استورد من Codex.", + "setActive": "تفعيل", + "active": "نشط", + "edit": "تعديل", + "delete": "حذف", + "deleteConfirm": "حذف الحيوان «{name}»؟ سيُحذف من القرص.", + "summon": "استدعاء نافذة الحيوان", + "openCodexHelp": "يجب أن توجد حيوانات Codex داخل ~/.codex/pets/. لم يُعثر على شيء.", + "specRequirement": "يجب أن يكون السبرايت بعرض 1536 بكسل وارتفاع من مضاعفات 208 بكسل (مثل 1872 أو 2288)، بصيغة PNG أو WebP مع شفافية.", + "form": { + "id": "معرف الحيوان", + "idHelp": "حروف صغيرة، أرقام، '-' و '_' فقط. حد أقصى 64 حرفًا.", + "displayName": "اسم العرض", + "description": "الوصف (اختياري)", + "spritesheet": "صفيحة السبرايت", + "chooseFile": "اختر ملفًا", + "replaceFile": "استبدال السبرايت", + "saveCreate": "إضافة الحيوان", + "saveUpdate": "حفظ التغييرات", + "cancel": "إلغاء" + }, + "errors": { + "missingId": "المعرف مطلوب", + "missingName": "الاسم مطلوب", + "missingSpritesheet": "السبرايت مطلوب", + "addFailed": "فشل الإضافة", + "updateFailed": "فشل التحديث", + "deleteFailed": "فشل الحذف", + "loadFailed": "فشل تحميل قائمة الحيوانات", + "setActiveFailed": "فشل تعيين الحيوان النشط", + "summonFailed": "فشل فتح نافذة الحيوان" + } + }, + "import": { + "title": "استيراد من Codex", + "subtitle": "الحيوانات الأليفة المتاحة ضمن ~/.codex/pets/.", + "selectAll": "تحديد الكل", + "alreadyImported": "تم استيراده مسبقًا", + "renameOnConflict": "تسمية المتعارضين بإلحاق -imported", + "import": "استيراد المحدد", + "noneFound": "لا توجد حيوانات Codex قابلة للاستيراد.", + "imported": "تم الاستيراد بنجاح", + "failed": "فشل الاستيراد", + "close": "إغلاق" + }, + "marketplace": { + "openMarketplace": "متجر الحيوانات الأليفة", + "title": "متجر الحيوانات الأليفة", + "search": "ابحث عن حيوان أليف", + "kindFilter": { + "all": "الكل", + "object": "كائن", + "animal": "حيوان", + "person": "شخصية", + "creature": "مخلوق" + }, + "sortFilter": { + "latest": "الأحدث", + "popular": "الأكثر شيوعاً", + "views": "الأكثر مشاهدة" + }, + "refresh": "تحديث", + "install": "تثبيت", + "installing": "جاري التثبيت", + "reinstall": "إعادة التثبيت", + "reinstallConfirm": "هل تريد استبدال الحيوان الأليف المحلي \"{name}\"؟ ستُستبدل البيانات الحالية.", + "cancel": "إلغاء", + "stats": { + "views": "المشاهدات", + "downloads": "التنزيلات", + "likes": "الإعجابات" + }, + "actions": { + "idle": "خامل", + "running_right": "ركض يمين", + "running_left": "ركض يسار", + "waving": "تلويح", + "jumping": "قفز", + "failed": "فشل", + "waiting": "انتظار", + "running": "ركض", + "review": "مراجعة" + }, + "page": "صفحة {page} من {total}", + "prev": "السابق", + "next": "التالي", + "empty": "لا يوجد حيوان أليف مطابق.", + "successInstalled": "تم تثبيت \"{name}\"", + "errors": { + "loadFailed": "تعذّر تحميل المتجر", + "installFailed": "فشل التثبيت", + "alreadyInstalled": "هذا الحيوان موجود بالفعل" + } + } + }, + "RemoteWorkspace": { + "openRemoteWorkspace": "Open remote workspace", + "manage": "Manage remote workspace", + "manageTitle": "Remote Workspace connections", + "empty": "No remote connections", + "searchPlaceholder": "Search remote workspaces", + "orderFailed": "Failed to save remote workspace order", + "dragSort": "Drag to sort", + "dragSortConnection": "Drag to sort {name}", + "newConnection": "New connection", + "loading": "Loading", + "loadingConnection": "Loading remote connection", + "name": "Name", + "baseUrl": "Service URL", + "token": "Access token", + "save": "Save", + "delete": "Delete", + "confirmDelete": { + "title": "Delete remote connection?", + "message": "This will remove \"{name}\" from this device. This action cannot be undone.", + "cancel": "Cancel", + "confirm": "Delete" + }, + "saved": "Remote connection saved.", + "deleted": "Remote connection deleted.", + "loadFailed": "Failed to load remote connections", + "saveFailed": "Failed to save remote connection", + "deleteFailed": "Failed to delete remote connection", + "openFailed": "Failed to open remote workspace", + "connectionLoadFailed": "Failed to load remote connection: {message}", + "connectionExpired": "Remote connection \"{name}\" is expired. Update its token and reload this window." + }, + "ServerFileBrowser": { + "title": "اختر ملفًا من الخادم", + "pathPlaceholder": "أدخل مسار الدليل...", + "goHome": "اذهب إلى المجلد الرئيسي", + "navigateUp": "اذهب إلى المجلد الأعلى", + "select": "اختر", + "cancel": "إلغاء", + "loading": "جارٍ التحميل...", + "emptyDirectory": "هذا المجلد فارغ", + "errorLoadingDir": "فشل تحميل المجلد", + "selectedCount": "{count} محدد" + }, + "BackupSettings": { + "title": "النسخ الاحتياطي والاستعادة", + "description": "صدّر نسخة احتياطية محمولة من بيانات codeg، أو استعد من نسخة.", + "tabs": { + "backup": "نسخ احتياطي", + "restore": "استعادة" + }, + "export": { + "includeExternal": "تضمين محتوى المحادثات", + "includeExternalHint": "يؤرشف أيضًا سجلات محادثات أدوات CLI (Claude وCodex وGemini …). يزيد الحجم.", + "passphrase": "عبارة المرور (اختياري)", + "passphrasePlaceholder": "اتركها فارغة للحصول على أرشيف غير مشفّر", + "passphraseConfirm": "تأكيد عبارة المرور", + "passphraseMismatch": "عبارتا المرور غير متطابقتين.", + "noPassphraseWarning": "ستحتوي هذه النسخة على أسرار (مفاتيح API والرموز) بنص واضح. احفظها في مكان آمن.", + "passphraseLossWarning": "مشفّرة بعبارة المرور هذه. إذا فقدتها، فلن يمكن استعادة النسخة الاحتياطية.", + "button": "تصدير النسخة الاحتياطية", + "inProgress": "جارٍ إنشاء النسخة الاحتياطية…", + "success": "تم إنشاء النسخة الاحتياطية.", + "started": "بدأ تنزيل النسخة الاحتياطية." + }, + "restore": { + "selectFile": "اختر ملف النسخة الاحتياطية", + "passphrasePrompt": "هذه النسخة مشفّرة. أدخل عبارة المرور الخاصة بها.", + "unlock": "فتح القفل", + "preview": { + "title": "تفاصيل النسخة الاحتياطية", + "encrypted": "مشفّرة", + "compatible": "متوافقة", + "incompatible": "غير متوافقة", + "createdAt": "أُنشئت: {value}", + "appVersion": "إصدار التطبيق: {value}", + "incompatibleHint": "أُنشئت هذه النسخة بإصدار أحدث من codeg ولا يمكن استعادتها." + }, + "replaceWarning": "تستبدل الاستعادة جميع بيانات codeg الحالية (قاعدة البيانات والملفات المرفوعة). تُلتقط بياناتك الحالية كلقطة أولًا حتى يمكن استرجاعها.", + "keyringNote": "تُخزَّن رموز GitHub/الدردشة لتطبيق سطح المكتب في سلسلة مفاتيح النظام ولا تُضمَّن؛ أعد إدخالها بعد الاستعادة.", + "button": "استعادة", + "staging": "جارٍ تجهيز الاستعادة…", + "staged": "تم تجهيز الاستعادة. جارٍ إعادة التشغيل…", + "restarting": "تم تجهيز الاستعادة. جارٍ إعادة تشغيل الخادم…", + "restartTimeout": "لم يعد الخادم في الوقت المحدد. أعد تحميل الصفحة بعد تشغيله.", + "externalSideLocation": "تمت استعادة سجلات المحادثات إلى {path}", + "confirmTitle": "استبدال جميع البيانات؟", + "confirmBody": "سيؤدي ذلك إلى استبدال قاعدة بيانات codeg والملفات المرفوعة الحالية بالنسخة الاحتياطية ثم إعادة التشغيل. تُلتقط بياناتك الحالية كلقطة أولًا.", + "cancel": "إلغاء", + "confirmAction": "استبدال وإعادة تشغيل", + "external": { + "title": "محتوى المحادثات", + "hint": "تتضمن هذه النسخة سجلات محادثات أدوات CLI. اختر مكان استعادتها.", + "modeSkip": "عدم الاستعادة", + "modeSide": "الاستعادة إلى مجلد جانبي آمن", + "modeOriginal": "الاستعادة إلى المواقع الأصلية لأدوات CLI", + "forceOverwrite": "الكتابة فوق الملفات الموجودة", + "forceOverwriteHint": "استبدال الملفات الموجودة بالفعل في مجلدات أدوات CLI.", + "scanning": "جارٍ التحقق من التعارضات…", + "noConflicts": "لن تتم الكتابة فوق أي ملف موجود.", + "conflictCount": "سيتأثر {count} من الملفات الموجودة.", + "conflictSkipNote": "تُحفظ الملفات الموجودة (تُتخطى) ما لم تفعّل الكتابة فوقها." + }, + "restartFailed": "تم تجهيز الاستعادة، لكن تعذّر إعادة تشغيل الخادم. أعد تشغيله يدويًا لتطبيقها." + }, + "remoteUnsupported": "يعمل النسخ الاحتياطي والاستعادة على بيانات الجهاز الذي يشغّل codeg. أنت متصل بمساحة عمل بعيدة — أدِر نسخها الاحتياطية من ذلك الخادم مباشرة." + }, + "backup": { + "restore": { + "error": { + "badPassphrase": "عبارة المرور غير صحيحة أو النسخة الاحتياطية تالفة.", + "corrupted": "أرشيف النسخة الاحتياطية تالف.", + "unknownFormat": "هذا الملف ليس نسخة احتياطية معروفة من codeg.", + "newerVersion": "أُنشئت هذه النسخة بواسطة codeg {backupVersion}، وهي أحدث من هذا الإصدار ({appVersion}).", + "alreadyPending": "توجد استعادة مُجهّزة بالفعل. أعد التشغيل لتطبيقها قبل تجهيز أخرى." + } + }, + "error": { + "diskSpace": "لا توجد مساحة قرص كافية لإكمال العملية.", + "cancelled": "تم إلغاء العملية." + } + }, + "WebConnection": { + "disconnectedTitle": "انقطع الاتصال", + "reconnectingDescription": "تتم محاولة إعادة الاتصال بالخادم. عادةً ما يُستعاد الاتصال تلقائيًا خلال ثوانٍ قليلة.", + "reconnectNow": "إعادة الاتصال الآن", + "sessionExpiredTitle": "انتهت الجلسة", + "sessionExpiredDescription": "لم تعد جلستك صالحة. يُرجى تسجيل الدخول مرة أخرى للمتابعة.", + "goToLogin": "الانتقال إلى تسجيل الدخول" + }, + "LiveFeedback": { + "placeholder": "أرسل ملاحظة إلى {agent} أثناء عمله…", + "agentFallback": "الوكيل", + "ariaLabel": "ملاحظة مباشرة", + "dialogTitle": "ملاحظات مباشرة", + "dialogDescription": "أرسل ملاحظة إلى الوكيل أثناء عمله. سيقرأها في فحصه التالي دون مقاطعة الخطوة الحالية.", + "dialogDescriptionInstant": "أرسل ملاحظة إلى الوكيل أثناء عمله. تُدرج الملاحظة فورًا في الدور الحالي — يراها الوكيل على الفور.", + "channelDowngraded": "الإدراج الفوري غير متاح في هذه الجلسة — حُفظت ملاحظتك ليقرأها الوكيل عند فحصه التالي.", + "send": "إرسال", + "cancel": "إلغاء", + "pending": "في الانتظار", + "delivered": "تم الاستلام", + "turnEndedUnread": "أنهى الوكيل الجولة قبل قراءة ملاحظاتك.", + "sendAsMessage": "إرسال كرسالة", + "dismiss": "تجاهل", + "turnEndedResent": "انتهت الجولة — تم الإرسال كرسالة جديدة بدلاً من ذلك.", + "turnEnded": "انتهت الجولة بالفعل.", + "submitFailed": "تعذّر إرسال ملاحظتك" + }, + "AgentToolsSettings": { + "title": "أدوات داخل المحادثة", + "description": "أدوات إضافية يمنحها codeg للوكيل داخل المحادثة. تُحقن عند بدء تشغيل الوكيل، لذا يسري أي تغيير على الوكلاء الذين يبدأون بعده.", + "feedbackLabel": "ملاحظات مباشرة", + "feedbackHint": "أرسل ملاحظات وتصحيحات إلى الوكيل أثناء عمله. إذا كان الوكيل يدعم الإدراج الفوري، تُدرج ملاحظتك فورًا في الدور الجاري؛ وإلا يحصل الوكيل على أداة للاطلاع على ملاحظاتك — وهؤلاء الوكلاء عادةً لا يتحققون منها إلا إذا ذكرت ذلك في الموجّه، مثلًا أضف \"تحقق من ملاحظاتي المباشرة بانتظام\" إلى رسالتك.", + "questionLabel": "سؤال المستخدم", + "questionHint": "يسمح للوكلاء بالتوقّف وطرح سؤال متعدّد الخيارات يظهر فوق مربّع إدخال المحادثة. ينتظر الوكيل حتى تجيب (أو تتخطّى).", + "sessionInfoLabel": "الحصول على معلومات الجلسة", + "sessionInfoHint": "يتيح للوكلاء البحث عن جلسة تشير إليها في رسالتك (شارة جلسة) لقراءة عنوانها والوكيل والحالة ومساحة العمل واستهلاك الرموز وأحدث الرسائل.", + "automationsLabel": "إنشاء الأتمتة", + "automationsHint": "يحفظ المحادثة كأتمتة تعمل وفق جدول زمني. مُعطّل افتراضيًا — إذ تبدأ بعد ذلك تشغيل الوكلاء من تلقاء نفسها.", + "workTasksLabel": "إنشاء مهام قيد الانتظار", + "workTasksHint": "يضيف بطاقة إلى لوحة المهام انطلاقًا من المحادثة. مُعطّل افتراضيًا — لأنه يكتب حالة التطبيق.", + "save": "حفظ", + "saving": "جارٍ الحفظ…", + "saved": "تم حفظ إعدادات الأدوات", + "saveFailed": "تعذّر حفظ إعدادات الأدوات", + "loadFailed": "فشل التحميل: {detail}" + }, + "NotificationSoundSettings": { + "title": "أصوات التنبيه", + "description": "تشغيل صوت قصير عند وقوع حدث للوكيل. هي نفس الأحداث التي تُرسل إلى قنوات المحادثة، وهذا الإعداد يخص هذا الجهاز فقط.", + "enableHint": "معطّل افتراضيًا. تُشغَّل الأصوات في نافذة مساحة العمل بهذا المتصفح أو التطبيق فقط.", + "volume": "مستوى الصوت", + "preview": "استماع", + "previewEvent": "استماع لصوت {event}", + "onlyWhenUnfocused": "فقط عندما تكون النافذة غير نشطة", + "onlyWhenUnfocusedHint": "يبقى صامتًا أثناء استخدامك لـ Codeg.", + "eventsTitle": "الأحداث", + "eventsHint": "اختر نغمة لكل حدث، أو «صامت» لتجاهله. إذا تكرر الحدث نفسه خلال ثوانٍ قليلة فسيُشغَّل مرة واحدة فقط.", + "toneNone": "صامت", + "toneChime": "رنين", + "toneDing": "جرس", + "toneBlip": "نبضة", + "tonePop": "طقّة", + "toneAlert": "تنبيه", + "toneDescend": "نغمة هابطة" + }, + "LogsSettings": { + "loading": "جارٍ التحميل…", + "sectionTitle": "سجلات التشغيل", + "sectionDescription": "عرض وتكوين سجلات تشخيص التطبيق. تُكتب السجلات في ملفات محلية وتُحفظ في الذاكرة للعرض المباشر.", + "captureTitle": "مستوى السجل", + "captureDescription": "يتحكم في مقدار التفاصيل الملتقطة. المستويات الأعلى (Debug، Trace) تسجل المزيد لكنها تنتج سجلات أكبر. «إيقاف» يعطّل التسجيل.", + "captureLabel": "مستوى الالتقاط", + "levels": { + "off": "إيقاف", + "error": "خطأ", + "warn": "تحذير", + "info": "معلومات", + "debug": "تصحيح", + "trace": "تتبع" + }, + "viewerTitle": "السجلات الأخيرة", + "viewerDescription": "عرض مباشر لأحدث السجلات. قم بالتصفية حسب المستوى أو ابحث في النص.", + "searchPlaceholder": "ابحث في الرسالة أو المصدر…", + "viewLevels": { + "all": "كل المستويات", + "error": "خطأ فأعلى", + "warn": "تحذير فأعلى", + "info": "معلومات فأعلى", + "debug": "تصحيح فأعلى", + "trace": "تتبع فأعلى" + }, + "pause": "إيقاف مؤقت", + "resume": "مباشر", + "refresh": "تحديث", + "clear": "مسح", + "openFolder": "فتح المجلد", + "shownCount": "{shown} / {total} معروض", + "empty": "لا توجد سجلات للعرض.", + "levelSaveFailed": "فشل حفظ مستوى السجل", + "openFolderFailed": "فشل فتح مجلد السجلات", + "downloadFailed": "فشل تنزيل ملف السجل", + "filesTitle": "ملفات السجل", + "filesDescription": "نزّل ملفات السجل الكاملة من القرص للاطلاع على السجل خارج المخزن المباشر.", + "filesEmpty": "لا توجد ملفات سجل بعد.", + "download": "تنزيل", + "downloadTruncated": "الملف كبير، تم تنزيل أحدث {size}. الملف الكامل موجود في دليل السجلات.", + "captureEnvLocked": "يتم التحكم في مستوى السجل عبر متغير البيئة RUST_LOG / CODEG_LOG؛ غيّره هناك ليصبح ساريًا.", + "targetsTitle": "تجاوزات حسب الوحدة", + "targetsDescription": "عيّن مستوى مختلفًا لوحدات محددة (مثل codeg_lib::acp) دون تغيير المستوى العام.", + "targetsAdd": "إضافة", + "targetsRemove": "إزالة التجاوز", + "toggleDetails": "تبديل التفاصيل" + }, + "Automations": { + "title": "الأتمتة", + "new": "أتمتة جديدة", + "empty": "لا توجد أتمتة بعد", + "emptyHint": "أنشئ واحدة لتشغيل مهمة الوكيل وفق جدول أو يدويًا.", + "name": "الاسم", + "namePlaceholder": "مثال: مراجعة PR الليلية", + "prompt": "الموجّه", + "promptPlaceholder": "ماذا يجب أن يفعل الوكيل؟", + "agent": "الوكيل", + "folder": "مجلد مساحة العمل", + "folderPlaceholder": "اختر مجلدًا", + "isolation": "العزل", + "isolationWorktree": "worktree جديد لكل تشغيل", + "isolationShared": "التشغيل داخل المجلد", + "isolationSharedCaveat": "تستخدم عمليات التشغيل شجرة عمل هذا المجلد مباشرةً، وقد تتعارض مع تغييراتك غير المُلتزَم بها. فعِّل خيار شجرة العمل لعزل كل عملية تشغيل.", + "trigger": "المُشغِّل", + "triggerSchedule": "وفق جدول", + "triggerManual": "يدوي فقط", + "cron": "الجدولة (cron)", + "cronPlaceholder": "0 9 * * 1-5", + "timezone": "المنطقة الزمنية", + "nextRun": "التشغيل التالي", + "branch": "الفرع", + "branchOptional": "الفرع (اختياري)", + "enabled": "مُفعّل", + "save": "حفظ", + "cancel": "إلغاء", + "edit": "تعديل", + "delete": "حذف", + "runNow": "تشغيل الآن", + "cancelRun": "إلغاء التشغيل", + "runHistory": "سجل التشغيل", + "noRuns": "لا توجد عمليات تشغيل بعد", + "allFolders": "كل المجلدات", + "filterAll": "الكل", + "noMatches": "لا توجد أتمتة مطابقة", + "viewConversation": "عرض المحادثة", + "lastRun": "آخر تشغيل", + "never": "أبدًا", + "running": "قيد التشغيل", + "deleteTitle": "حذف الأتمتة؟", + "deleteDescription": "يؤدي هذا إلى إزالة الأتمتة وجدولها. يُحتفظ بسجل التشغيل.", + "statusRunning": "قيد التشغيل", + "statusSucceeded": "نجحت", + "statusFailed": "فشلت", + "statusCancelled": "أُلغيت", + "statusSkipped": "تم تخطيها", + "errorName": "الاسم مطلوب", + "errorPrompt": "الموجّه مطلوب", + "errorCron": "تتطلب الأتمتة المجدولة تعبير cron", + "errorFolder": "اختر مجلد مساحة العمل", + "presetHourly": "كل ساعة", + "presetDaily": "يوميًا 9 صباحًا", + "presetWeekdays": "أيام العمل 9 صباحًا", + "presetCustom": "مخصص", + "probing": "جارٍ تحميل الخيارات…", + "retry": "إعادة المحاولة", + "configNone": "لا توجد خيارات قابلة للضبط لهذا الوكيل", + "inherit": "افتراضي الوكيل", + "mode": "الوضع", + "config": "الإعدادات", + "branchPlaceholder": "(الفرع الافتراضي)", + "selectHint": "اختر أتمتة لعرض التفاصيل", + "refresh": "تحديث", + "onboardTitle": "أتمتة مهام الوكيل الروتينية", + "onboardHint": "اجدول وكيلًا لمراجعة الشيفرة أو تحديث الاعتماديات أو فرز المشكلات، وفق جدول زمني أو عند الطلب.", + "headerSubtitle": "مهام الوكيل المجدولة وعند الطلب", + "startFromTemplate": "ابدأ من قالب", + "blankTitle": "أتمتة فارغة", + "blankDesc": "اضبط مهمة وكيل من البداية.", + "backToTemplates": "القوالب", + "sectionSchedule": "الجدولة والهدف", + "sectionTarget": "الهدف", + "sectionAction": "الإجراء", + "actionLaunchSession": "تشغيل جلسة", + "actionEnqueueTask": "إضافة مهمة إلى قائمة الانتظار", + "actionEnqueueTaskHint": "عند كل تشغيل تُضاف مهمة قيد الانتظار تحمل اسم هذه الأتمتة إلى المهام قيد الانتظار للمجلد، وينفذها محرك المهام وفق إعدادات اللوحة.", + "sectionPrompt": "الموجّه", + "nextIn": "التالي خلال {rel}", + "manual": "يدوي", + "schedEveryMinutes": "كل {n} دقيقة", + "schedHourly": "كل ساعة", + "schedDaily": "يوميًا في {time}", + "schedWeekdays": "أيام العمل في {time}", + "schedWeekly": "كل {day} في {time}", + "schedMonthly": "شهريًا في اليوم {day} عند {time}", + "dow0": "الأحد", + "dow1": "الاثنين", + "dow2": "الثلاثاء", + "dow3": "الأربعاء", + "dow4": "الخميس", + "dow5": "الجمعة", + "dow6": "السبت", + "tplCodeReviewTitle": "مراجعة الشيفرة", + "tplCodeReviewDesc": "يراجع التغييرات الأخيرة بحثًا عن الأخطاء والانحدارات ومشكلات الجودة.", + "tplDependencyUpdatesTitle": "تحديث الاعتماديات", + "tplDependencyUpdatesDesc": "يعثر على الاعتماديات القديمة ويقترح ترقيات آمنة.", + "tplTestCoverageTitle": "تغطية الاختبارات", + "tplTestCoverageDesc": "يعثر على مسارات الشيفرة غير المختبرة ويضيف الاختبارات الناقصة.", + "tplTodoSweepTitle": "تجميع مهام TODO", + "tplTodoSweepDesc": "يجمع تعليقات TODO وFIXME ويفرزها حسب الأولوية.", + "tplCiTriageTitle": "فرز CI", + "tplCiTriageDesc": "يحقق في الفحوصات الفاشلة الأخيرة ويقترح إصلاحات.", + "tplReleaseNotesTitle": "ملاحظات الإصدار", + "tplReleaseNotesDesc": "يلخّص التغييرات منذ الإصدار الأخير في سجل تغييرات.", + "tplSecurityAuditTitle": "تدقيق الأمان", + "tplSecurityAuditDesc": "يفحص الثغرات والأنماط الخطرة ثم يبلّغ عن النتائج.", + "enable": "تفعيل", + "disable": "تعطيل", + "moreActions": "إجراءات إضافية", + "statusDisabled": "معطّلة", + "cronBuilderTitle": "منشئ الجدولة", + "cronFreqLabel": "التكرار", + "cronFreqMinutes": "كل N دقيقة", + "cronFreqHourly": "كل ساعة", + "cronFreqDaily": "يوميًا", + "cronFreqWeekdays": "أيام الأسبوع", + "cronFreqWeekly": "أسبوعيًا", + "cronFreqMonthly": "شهريًا", + "cronFreqCustom": "مخصص", + "cronEveryLabel": "الفاصل (دقائق)", + "cronTimeLabel": "الوقت", + "cronHourLabel": "الساعة", + "cronMinuteLabel": "الدقيقة", + "cronDowLabel": "يوم الأسبوع", + "cronDomLabel": "يوم الشهر", + "cronApply": "تطبيق", + "cronPreviewLabel": "معاينة", + "cronOpenBuilder": "فتح منشئ الجدولة", + "branchDefault": "الفرع الافتراضي", + "branchUseCustom": "استخدام \"{query}\"", + "branchLocal": "محلي", + "branchRemote": "بعيد", + "branchSearchPlaceholder": "بحث في الفروع…", + "branchNone": "لا توجد فروع" + }, + "Tasks": { + "title": "المهام قيد الانتظار", + "new": "مهمة جديدة", + "empty": "لا توجد مهام بعد", + "emptyHint": "أضف مهمة ثم شغّلها — يعمل الوكيل في worktree معزول، وتراجع النتيجة وتدمجها.", + "emptyColTodo": "لا توجد مهام قيد الانتظار بعد", + "emptyColInProgress": "لا توجد مهام قيد التنفيذ", + "emptyColAttention": "لا توجد مهام بانتظارك", + "emptyColDone": "لا توجد مهام مكتملة بعد", + "allFolders": "كل المجلدات", + "showCanceled": "إظهار الملغاة", + "showArchived": "إظهار المؤرشفة", + "filter": "تصفية", + "viewSwitchToBoard": "التبديل إلى عرض اللوحة", + "viewSwitchToList": "التبديل إلى عرض القائمة", + "statusFilter": "الحالة", + "statusFilterAll": "كل الحالات", + "listEmpty": "لا توجد مهام مطابقة لعوامل التصفية الحالية", + "listColStatus": "الحالة", + "listColTask": "المهمة", + "listColLocation": "الموقع", + "listColChanges": "التغييرات", + "listColUpdated": "آخر تحديث", + "colTodo": "قيد الانتظار", + "colInProgress": "قيد التنفيذ", + "colAttention": "بانتظارك", + "colDone": "مكتملة", + "statusTodo": "قيد الانتظار", + "statusQueued": "في قائمة الانتظار", + "statusPreparing": "قيد التهيئة", + "statusRunning": "قيد التنفيذ", + "statusAwaitingInput": "بانتظار الإدخال", + "statusReview": "بانتظار المراجعة", + "statusMerging": "جارٍ الدمج", + "statusDone": "مكتملة", + "statusFailed": "فشلت", + "statusCanceled": "ملغاة", + "statusInterrupted": "توقّفت", + "badgeCleanupFailed": "فشل التنظيف", + "badgeWorktreeKept": "تم الإبقاء على worktree", + "badgeWorktreeRemoved": "تمت إزالة worktree", + "filesChanged": "{count} ملفات", + "actionStart": "بدء", + "actionSchedule": "جدولة", + "actionCancel": "إلغاء", + "actionRetry": "إعادة المحاولة", + "actionRequeue": "إعادة الإدراج", + "actionViewSession": "عرض المحادثة", + "actionEdit": "تحرير", + "actionDelete": "حذف", + "actionRetryCleanup": "إعادة محاولة التنظيف", + "actionMerge": "دمج", + "actionUnqueueMerge": "مغادرة طابور الدمج", + "actionEditQueuedMerge": "تعديل الدمج المنتظر", + "badgeMergeQueued": "في طابور الدمج", + "badgeMergeQueuedRank": "في طابور الدمج · رقم {rank}", + "badgeMergeQueuedHint": "في انتظار انتهاء الدمج الجاري لهذا المشروع، وسيبدأ هذا تلقائيًا عند دوره.", + "actionComplete": "إنهاء", + "actionAbandon": "تخلٍّ", + "cancelTitle": "إلغاء المهمة؟", + "cancelDescription": "ستصبح المهمة ملغاة. يُحتفظ بـ worktree الخاصة بها ويمكنك إعادة إدراجها لاحقًا.", + "cancelReasonLabel": "السبب (اختياري)", + "cancelReasonPlaceholder": "مثلاً: النهج خاطئ، سأعيد كتابة الوصف", + "cancelKeep": "تراجع", + "cancelSubmit": "إلغاء المهمة", + "restartTitleRetry": "إعادة محاولة المهمة", + "restartTitleRequeue": "إعادة إدراج المهمة", + "restartDescription": "يمكنك إضافة ملاحظة (اختيارية) تصل إلى موجّه التشغيل التالي.", + "scheduleTitle": "جدولة المهمة", + "scheduleDescription": "تبقى المهمة في قائمة الانتظار وتبدأ تلقائيًا في الوقت الذي تحدده. ويظل حد التنفيذ المتزامن للمجلد ساريًا.", + "scheduleDateLabel": "التاريخ", + "schedulePickDate": "اختر التاريخ", + "scheduleTimeLabel": "الوقت", + "schedulePreview": "يبدأ في {time}", + "schedulePastHint": "لقد مضى هذا الوقت — ستبدأ المهمة فور الحفظ.", + "scheduleInAnHour": "بعد ساعة", + "scheduleInThreeHours": "بعد 3 ساعات", + "scheduleTomorrow": "غدًا 9:00", + "scheduleClear": "إلغاء الجدولة", + "scheduleBadge": "بدء مجدول في {time}", + "toastScheduled": "تمت الجدولة في {time}", + "toastScheduleCleared": "تم إلغاء الجدولة", + "actionFollowUp": "متابعة", + "actionAddNote": "إضافة ملاحظة", + "followUpSubmit": "إرسال", + "followUpIntentRevise": "إعادة العمل", + "followUpIntentContinue": "المتابعة", + "followUpIntentQuestion": "طرح سؤال", + "followUpIntentVerify": "مراجعة ذاتية", + "followUpPlaceholderRevise": "ما الذي يجب أن يغيّره الوكيل؟ سيتابع في الجلسة نفسها.", + "followUpPlaceholderContinue": "ما التالي؟ سيبقى العمل المنجز كما هو.", + "followUpPlaceholderQuestion": "ما الذي تريد معرفته؟ سيجيب الوكيل دون تعديل أي ملف.", + "followUpPlaceholderVerify": "اختياري: هل من شيء ينبغي فحصه بعناية؟", + "followUpPlaceholderRetry": "اختياري: ما الذي ينبغي فعله بشكل مختلف؟ مثلاً: شغّل pnpm install أولاً", + "followUpPlaceholderRequeue": "اختياري: لماذا ألغيتها، وما الذي يجب أن يتغيّر هذه المرة؟", + "actionArchive": "أرشفة", + "actionUnarchive": "إلغاء الأرشفة", + "archiveAllDone": "أرشفة الكل", + "dropToStart": "أفلِت للبدء", + "errorView": "عرض", + "notifyReview": "جاهزة للمراجعة: {title}", + "notifyFailed": "فشلت المهمة: {title}", + "createFromMessage": "إنشاء مهمة من الرسالة", + "detailTokens": "إجمالي الرموز", + "editorTitleNew": "مهمة جديدة", + "editorTitleEdit": "تحرير المهمة", + "templates": "القوالب", + "templatesEmpty": "لا توجد قوالب بعد.", + "templateSaveCurrent": "حفظ المحتوى الحالي كقالب", + "templateDelete": "حذف القالب", + "transcriptTitle": "محادثة المهمة", + "transcriptDescription": "عرض مباشر للقراءة فقط لجلسة وكيل المهمة.", + "phaseWork": "تنفيذ المهمة", + "phaseRetry": "إعادة التنفيذ", + "phaseReturn": "متابعة", + "phaseMerge": "الدمج", + "titleLabel": "العنوان", + "titlePlaceholder": "ما الذي يجب إنجازه؟", + "promptLabel": "وصف المهمة", + "promptPlaceholder": "صف المهمة للوكيل — استخدم @ للإشارة إلى الملفات و / للأوامر", + "folderPlaceholder": "اختر مجلدًا", + "agentInheritedHint": "موروث من إعدادات المهام — عدِّله ليصبح خاصًا بهذه المهمة", + "agentOverrideReset": "العودة إلى الوراثة", + "sectionTarget": "الهدف", + "errorTitle": "العنوان مطلوب", + "errorPrompt": "وصف المهمة مطلوب", + "errorFolder": "اختر مجلدًا", + "save": "حفظ", + "cancel": "إلغاء", + "mergeTitle": "دمج المهمة", + "mergeQueuedTitle": "دمج في الطابور", + "mergeQueueHint": "تجري الآن عملية دمج لمهمة أخرى في هذا المشروع. ستنضم هذه المهمة إلى الطابور وتبدأ تلقائيًا فور انتهاء تلك العملية.", + "mergeQueueUpdateHint": "هذه المهمة تنتظر الدمج بالفعل. الإرسال يحدّث خياراتها ويحتفظ بمكانها في الطابور.", + "mergeDescription": "دمج {branch} في {base}. تُرسل التغييرات غير المثبتة في worktree أولًا.", + "mergeMessage": "رسالة الالتزام", + "mergeMessagePlaceholder": "مثال: feat: add login validation", + "mergeAutoMessage": "دع الوكيل يكتب رسالة الإيداع", + "strategySquash": "دمج في التزام واحد", + "strategySquashHint": "تصل جميع تغييرات المهمة إلى الفرع الرئيسي كسجل واحد — تاريخ أكثر ترتيبًا.", + "strategyMerge": "الاحتفاظ بالتاريخ الكامل", + "strategyMergeHint": "يُحتفظ بكل التزام أُنشئ أثناء المهمة، مع إضافة سجل دمج واحد — تبقى كل خطوة قابلة للتتبع.", + "mergeDeleteWorktree": "حذف worktree بعد الدمج", + "mergeSubmit": "دمج", + "mergeSubmitQueue": "إضافة إلى طابور الدمج", + "mergeQueuedToast": "تمت الإضافة إلى طابور الدمج — سيبدأ فور انتهاء الدمج الحالي.", + "completeTitle": "إنهاء المهمة", + "completeDescription": "لم تغيّر هذه المهمة أي ملف، لذا لا يوجد ما يُدمج — سيتم وضع علامة مكتملة عليها مباشرة.", + "completeDescriptionNoWorktree": "تمت إزالة worktree هذه المهمة، فلم يعد الدمج ممكنًا — سيتم وضع علامة مكتملة عليها مباشرة. يُحتفظ بفرع العمل إذا كان لا يزال يحوي إيداعات غير مدمجة.", + "completeDeleteWorktree": "حذف worktree بعد الإنهاء", + "completeSubmit": "إنهاء", + "settingsTitle": "إعدادات المهام", + "settingsDescription": "الإعدادات الافتراضية لمهام {folder}.", + "settingsScope": "النطاق", + "settingsScopeGlobal": "كل المجلدات (الإعدادات العامة)", + "settingsScopeGlobalHint": "المجلدات بلا إعدادات خاصة تستخدم هذه الإعدادات العامة.", + "settingsSource": "مصدر الإعدادات", + "settingsSourceGlobal": "الإعدادات العامة", + "settingsSourceCustom": "إعداد خاص", + "settingsSourceGlobalFollow": "يتبع إعدادات المهام العامة — التغييرات هناك تسري هنا تلقائيًا.", + "settingsSourceCustomHint": "يحفظ إعدادات خاصة بهذا المجلد ويتوقف عن اتباع الإعدادات العامة.", + "settingsAgent": "الوكيل الافتراضي", + "settingsMaxConcurrent": "أقصى عدد للمهام المتزامنة", + "settingsMaxConcurrentHint": "0 = بلا حد", + "settingsAutoProcess": "معالجة تلقائية", + "settingsAutoProcessHint": "تبدأ المهام المعلّقة تلقائيًا ضمن حد التنفيذ المتزامن.", + "settingsMergeStrategy": "استراتيجية الدمج الافتراضية", + "settingsMergeStrategyHint": "كيفية تسجيل تغييرات المهمة في تاريخ الفرع عند الدمج.", + "settingsAutoMerge": "دمج تلقائي", + "settingsAutoMergeHint": "المهمة التي تصل إلى المراجعة وفيها تغييرات قابلة للدمج تُدمج كما لو نقرت «دمج»: يكتب الوكيل رسالة الإيداع، ويتبع الـ worktree الإعداد الافتراضي أدناه. أما المهمة التي فشل فحصها المسبق أو فشل دمجها فتبقى بانتظارك.", + "settingsDeleteWorktree": "حذف الـ worktree بعد الدمج", + "settingsDeleteWorktreeHint": "يُفعّل الخيار مسبقًا في نافذة الدمج، ويمكنك تغييره هناك.", + "settingsWorktreeRoot": "موقع الـ worktree", + "settingsWorktreeRootHint": "المجلد الذي تُنشأ فيه worktrees المهام الجديدة، واحدة لكل مهمة. اتركه فارغًا لإنشائها بجوار مجلد المشروع؛ «~» هو مجلد المنزل، والمسار النسبي يُحسب انطلاقًا من مجلد المشروع.", + "settingsWorktreeRootPlaceholder": "~/codeg-worktrees", + "settingsWorktreeRootBrowse": "اختيار مجلد الـ worktree", + "settingsPreflight": "أمر الفحص المسبق", + "settingsPreflightHint": "يعمل في شجرة العمل عندما تصل المهمة إلى المراجعة.", + "settingsPreflightCustomPlaceholder": "pnpm test", + "settingsInitCommand": "أمر تهيئة worktree", + "settingsInitCommandHint": "يعمل داخل worktree جديد قبل بدء الوكيل.", + "settingsInitCommandPlaceholder": "pnpm install", + "settingsTabGeneral": "عام", + "settingsTabMerge": "الدمج", + "settingsTabWorktree": "Worktree", + "settingsTabPrompts": "التوجيهات", + "settingsPromptsIntro": "لكل مرحلة موجّه مدمج بالفعل — المهمة نفسها، وقواعد شجرة العمل، وخطوات git الدقيقة عند الدمج. وما تضيفه هنا يُلحَق في النهاية كتعليمات إضافية: فهو يُهذّب النص المدمج ولا يستبدله أبدًا.", + "settingsPromptStageAll": "كل المراحل", + "settingsPromptPlaceholderAll": "مثال: التزم باصطلاحات ملف AGENTS.md، واجعل الملخص النهائي في جملتين", + "settingsPromptPlaceholderWork": "مثال: اقرأ الاختبارات المرتبطة أولًا، وأودِع التغييرات على خطوات صغيرة", + "settingsPromptPlaceholderRetry": "مثال: تحقق مما تم إيداعه قبل المتابعة، ولا تُعِد ما أُنجز", + "settingsPromptPlaceholderReturn": "مثلاً: عالج كل نقطة مذكورة؛ ولا تُعِد هيكلة أي شيء غير ذي صلة", + "settingsPromptPlaceholderMerge": "مثال: اكتب رسالة إيداع الدمج بالعربية، ونبّه إلى أي تعارض حللته يدويًا", + "settingsPromptHintAll": "يُلحق بكل توجيه يتلقاه الوكيل، بما في ذلك مرحلة الدمج.", + "settingsPromptHintWork": "يُلحق عند تنفيذ المهمة لأول مرة.", + "settingsPromptHintRetry": "يُلحق عند استئناف مهمة متوقفة أو فاشلة.", + "settingsPromptHintReturn": "يُضاف عند متابعة مهمة قيد المراجعة (إعادة عمل، عمل إضافي، مراجعة ذاتية).", + "settingsPromptHintMerge": "يُلحق عندما يدمج الوكيل المهمة في الفرع الأساسي.", + "preflightPassed": "نجح {name}", + "preflightFailed": "فشل {name}", + "preflightRunning": "{name} قيد التشغيل…", + "detailDescription": "تفاصيل المهمة", + "detailSummary": "النتيجة", + "detailFiles": "الملفات المتغيرة", + "detailDiffAll": "عرض كامل الفروق", + "detailDiffAllTitle": "كامل الفروق", + "detailNoChanges": "لا تغييرات بعد مقارنةً بالأساس", + "detailTimeline": "سجل التقدم", + "detailTimelineEmpty": "لا نشاط بعد", + "showMore": "عرض المزيد", + "showLess": "عرض أقل", + "detailInfo": "التفاصيل", + "detailBranch": "الفرع", + "detailMergeCommit": "إيداع الدمج", + "detailChanges": "التغييرات", + "detailScheduled": "البدء المجدول", + "detailCreated": "تاريخ الإنشاء", + "detailStarted": "تاريخ البدء", + "detailFinished": "تاريخ الانتهاء", + "diffLoading": "جارٍ تحميل الفروق…", + "deleteConfirmTitle": "حذف المهمة؟", + "deleteConfirmBody": "ستُزال “{title}” من اللوحة. يُلغى التشغيل النشط أولًا.", + "deleteWithWorktree": "حذف الـ worktree الخاص بها أيضًا", + "eventCreated": "أُنشئت", + "eventStatusChanged": "تغيّر الحالة", + "eventConfigEffective": "إعداد الإطلاق", + "eventInitCommand": "أمر التهيئة", + "eventAgentProgress": "تقدّم الوكيل", + "eventAgentVerdict": "حكم الوكيل", + "eventMergeAttempt": "بدأ الدمج", + "eventMergeQueued": "أُضيف إلى طابور الدمج", + "eventMergeConflict": "تعارض دمج", + "eventPreflight": "فحص مسبق", + "eventCleanupFailed": "فشل تنظيف worktree", + "eventResumeFallback": "فشل استئناف الجلسة؛ استُخدمت جلسة جديدة", + "eventUserAction": "إجراء المستخدم", + "eventDiffStat": "لقطة التغييرات" + }, + "CustomSkillsSettings": { + "loading": "جارٍ تحميل المهارات المخصّصة…", + "category": "مخصّصة", + "searchPlaceholder": "ابحث عن المهارات المخصّصة بالاسم أو المعرّف أو الوصف", + "states": { + "not_linked": "غير مُفعّلة", + "linked_to_codeg": "مُفعّلة", + "linked_elsewhere": "مرتبطة في مكان آخر", + "blocked_by_real_directory": "محجوبة بمجلد فعلي", + "broken": "رابط معطوب" + }, + "actions": { + "new": "جديدة", + "import": "استيراد", + "importFromAgent": "استيراد من وكيل", + "cancel": "إلغاء", + "save": "حفظ" + }, + "rowMenu": { + "edit": "تعديل", + "duplicate": "تكرار", + "delete": "حذف" + }, + "bulk": { + "delete": "حذف المحدد" + }, + "editor": { + "createTitle": "مهارة مخصّصة جديدة", + "editTitle": "تعديل مهارة مخصّصة", + "description": "تُحفَظ المهارات المخصّصة في المخزن المشترك (~/.codeg/skills) ويمكن تفعيلها لأي وكيل.", + "idLabel": "معرّف المهارة", + "idPlaceholder": "مثال: my-workflow", + "contentLabel": "SKILL.md", + "contentPlaceholder": "اكتب هنا ملف SKILL.md للمهارة…", + "preview": "معاينة", + "edit": "تعديل", + "emptyBody": "لا يوجد محتوى بعد." + }, + "duplicate": { + "title": "تكرار المهارة", + "description": "إنشاء نسخة من «{id}» بمعرّف جديد.", + "newIdPlaceholder": "معرّف المهارة الجديد", + "confirm": "تكرار" + }, + "import": { + "title": "اختر مجلد مهارة للاستيراد" + }, + "importFromAgent": { + "title": "استيراد المهارات من وكيل", + "description": "انسخ مهارات الوكيل الخاصة إلى المخزن المشترك لتفعيلها لأي وكيل.", + "agentLabel": "الوكيل", + "agentPlaceholder": "اختر وكيلاً", + "selectAll": "تحديد الكل ({count})", + "loading": "جارٍ تحميل مهارات الوكيل…", + "unsupported": "لا يوفّر هذا الوكيل دليل مهارات.", + "empty": "لا توجد مهارات قابلة للاستيراد لهذا الوكيل.", + "alreadyInLibrary": "في المكتبة", + "confirm": "استيراد المحدد ({count})" + }, + "delete": { + "title": "حذف المهارات المخصّصة؟", + "body": "سيؤدي هذا إلى إزالة {count} مهارة مخصّصة من المخزن المركزي وفصل روابطها من كل وكيل. لا يمكن التراجع عن ذلك.", + "confirm": "حذف" + }, + "toasts": { + "loadFailed": "فشل تحميل المهارة", + "idRequired": "أدخل معرّف المهارة", + "created": "تم إنشاء المهارة المخصّصة", + "updated": "تم تحديث المهارة المخصّصة", + "saveFailed": "فشل حفظ المهارة", + "imported": "تم استيراد المهارة", + "importFailed": "فشل استيراد المهارة", + "duplicated": "تم تكرار المهارة", + "duplicateFailed": "فشل تكرار المهارة", + "deleted": "تم حذف {count} مهارة", + "deletedPartial": "تم حذف {ok}، وفشل {failed}", + "deleteFailed": "فشل حذف المهارات", + "importedFromAgent": "تم استيراد {count} مهارة", + "importedFromAgentPartial": "تم استيراد {ok}، وفشل {failed}", + "importFromAgentAllSkipped": "لا شيء للاستيراد — {count} موجودة بالفعل في المكتبة", + "importFromAgentFailed": "فشل الاستيراد من الوكيل" + } + }, + "CodexModelEditor": { + "customizedNotice": "لقد خصّصت قائمة النماذج، لذا يدير codeg الآن جدول نماذج codex بالكامل. لن تظهر النماذج الرسمية التي يضيفها codex لاحقًا تلقائيًا — انقر على زر التحديث بالأسفل ثم احفظ مرة أخرى لمزامنتها. امسح كل تخصيصاتك ليعود codex إلى التحديث تلقائيًا.", + "officialsTitle": "النماذج الرسمية", + "officialsHint": "تُضاف تلقائيًا من codex الذي تشغّله؛ احذف ما لا تريده.", + "officialsEmpty": "لا توجد نماذج رسمية متاحة.", + "refresh": "تحديث من codex", + "readdOfficial": "إعادة إضافة رسمي", + "customsTitle": "النماذج المخصّصة", + "customsEmpty": "لا توجد نماذج مخصّصة بعد.", + "addCustom": "إضافة مخصص", + "slugPlaceholder": "معرّف النموذج (slug)", + "displayNamePlaceholder": "الاسم المعروض", + "contextWindow": "السياق", + "makeDefault": "تعيين كافتراضي", + "defaultHint": "النموذج الافتراضي", + "remove": "إزالة", + "advanced": "متقدم", + "baseTemplate": "القالب الأساسي", + "baseTemplateHint": "النموذج الرسمي الذي تُنسخ منه الحقول المطلوبة (موجّه النظام، الأدوات، الحدود).", + "groupBehavior": "السلوك والقدرات", + "fieldReasoningLevel": "الاستدلال الافتراضي", + "fieldReasoningSummary": "ملخص الاستدلال", + "fieldVerbosity": "مستوى التفصيل", + "fieldShellType": "نوع الصدفة", + "fieldApplyPatch": "أداة تطبيق التصحيح", + "fieldReasoningSummaries": "ملخصات الاستدلال", + "fieldSupportVerbosity": "التحكم في التفصيل", + "fieldParallelToolCalls": "استدعاءات الأدوات المتوازية", + "fieldSearchTool": "أداة البحث على الويب", + "optNone": "بلا", + "groupInstructions": "الوصف وموجّه النظام", + "fieldDescription": "الوصف", + "baseInstructions": "موجّه النظام (base_instructions)" + }, + "DiagnosticsSettings": { + "title": "تشخيص البيئة", + "description": "يتحقق من كيفية تحليل هذا التطبيق لواجهة سطر أوامر الوكيل داخل عمليته الخاصة، وقد يختلف ذلك عن الطرفية لديك.", + "loading": "جارٍ تشغيل التشخيص…", + "error": "فشل التشخيص", + "rerun": "إعادة التشغيل", + "copyAll": "نسخ الكل", + "copied": "تم نسخ التشخيص إلى الحافظة", + "button": "تشخيص", + "verdict": { + "ok": "تبدو البيئة سليمة. إذا استمر ظهوره كغير مُثبَّت، فأعد تشغيل التطبيق بالكامل لتحديث ذاكرة التخزين المؤقتة للبادئة.", + "node_missing": "لم يتم العثور على Node.js في مسار PATH الخاص بالتطبيق.", + "npm_missing": "لم يتم العثور على npm في مسار PATH الخاص بالتطبيق.", + "not_installed": "يبدو أن هذا الوكيل غير مُثبَّت.", + "installed_but_unresolved": "مُسجَّل كمُثبَّت، لكن لا يستطيع التطبيق تحديد موقع الملف التنفيذي.", + "user_prefix_not_on_path": "تم التثبيت في بادئة الاحتياط (~/.codeg/npm-global)، وهي ليست في مسار PATH الخاص بالتطبيق. أعد تشغيل التطبيق بالكامل وحاول مرة أخرى.", + "homebrew_bin_not_on_path": "تم التثبيت ضمن مجلد bin الخاص بـ Homebrew، وهو ليس في مسار PATH الخاص بالتطبيق (فصل keg على Apple Silicon).", + "terminal_only_path": "يُحلَّل الأمر في الطرفية لديك لكن ليس في التطبيق — وهي فجوة في مسار PATH لواجهة المستخدم الرسومية. شغّل التطبيق من الطرفية أو أعد التثبيت من إعدادات الوكلاء.", + "npm_prefix_timeout": "كان npm prefix -g بطيئًا جدًا (أكثر من 1.5 ثانية)، لذا تم تخطّي الكشف الاحتياطي. أعد تشغيل التطبيق وحاول مرة أخرى.", + "node_too_old": "إصدار Node.js النشط أقدم مما يتطلبه هذا الوكيل. يرجى ترقية Node.js.", + "adapter_missing_native_present": "واجهة {agent} لديك مثبّتة فعلاً، لكن Codeg يشغّل حزمة محوّل ACP منفصلة، وهي غير مثبّتة بعد. ثبّتها من إعدادات الوكلاء؛ فهي لا تمسّ واجهتك وتتشارك تسجيل الدخول نفسه.", + "adapter_missing": "يشغّل Codeg حزمة محوّل ACP منفصلة من أجل {agent}، وهي غير مثبّتة بعد. ثبّتها من إعدادات الوكلاء — لا يكفي تثبيت واجهة الأوامر الرسمية وحدها." + } + }, + "TokenUsage": { + "title": "استهلاك الرموز", + "rangeLabel": "النطاق الزمني", + "range7d": "٧ أيام", + "range30d": "٣٠ يومًا", + "range90d": "٩٠ يومًا", + "rangeThisMonth": "هذا الشهر", + "rangeThisYear": "هذا العام", + "rangeAll": "الكل", + "rangeCustom": "مخصص", + "moreRanges": "المزيد", + "customRangePick": "اختر نطاقاً زمنياً", + "bucketLabel": "التجميع حسب", + "bucketDay": "يوم", + "bucketWeek": "أسبوع", + "bucketMonth": "شهر", + "bucketUnitDay": "يوم", + "bucketUnitWeek": "أسبوع", + "bucketUnitMonth": "شهر", + "folderFilter": "المجلدات", + "allFolders": "كل المجلدات", + "agentFilter": "الوكلاء", + "allAgents": "كل الوكلاء", + "modelFilter": "النماذج", + "allModels": "كل النماذج", + "searchPlaceholder": "بحث…", + "noMatches": "لا توجد نتائج", + "clearFilter": "مسح التحديد", + "resetFilters": "إعادة ضبط المرشحات", + "refresh": "تحديث", + "rebuild": "إعادة بناء الكل", + "rebuildHint": "يتجاهل البيانات المحسوبة ويعيد قراءة كل سجلات الجلسات. استخدمه إذا نمت جلسة خارج codeg.", + "syncing": "جارٍ حساب الجلسات…", + "syncProgress": "{done} / {total}", + "syncDone": "تم حساب {synced} جلسة", + "syncFailed": "تعذّرت قراءة بعض الجلسات", + "syncBusy": "هناك تحديث قيد التشغيل بالفعل", + "lastSynced": "حُدّث {time}", + "lastSyncedNever": "لم يُحدَّث بعد", + "tileTotal": "إجمالي الرموز", + "tileSessions": "الجلسات", + "tileTurns": "الأدوار", + "tileActiveDays": "الأيام النشطة", + "tileGenTime": "زمن التوليد", + "vsPrevious": "مقارنة بالفترة السابقة", + "deltaNew": "جديد", + "trendTitle": "الاستهلاك عبر الزمن", + "trendEmpty": "لا استهلاك في هذا النطاق", + "trendTurns": "الأدوار", + "trendSessions": "الجلسات", + "compositionTitle": "أين ذهبت الرموز", + "compositionHint": "الإدخال هو ما أرسلته، والإخراج ما كتبه النموذج، وقراءات الذاكرة المؤقتة سياق لم تدفع ثمنه كاملًا.", + "compositionNote": "إعادة إرسال هذه الإصابات المؤقتة بالسعر الكامل كانت ستكلف {value} إضافية.", + "inputTokens": "إدخال", + "outputTokens": "إخراج", + "cacheWrite": "كتابة مؤقتة", + "cacheRead": "قراءة مؤقتة", + "freshTokens": "حساب جديد", + "cacheHitCaption": "إصابة مؤقتة", + "cacheHeroTitleHigh": "معظم السياق لم يُعَد إرساله", + "cacheHeroTitleLow": "معظم السياق ما زال يُحسب بالسعر الكامل", + "cacheHeroDesc": "حملت الذاكرة المؤقتة {cached} من السياق، ولم يُحسب من جديد سوى {fresh} في هذه الفترة.", + "cacheSavedSuffix": "وفّر ذلك ما يعادل {saved} من إعادة الإرسال.", + "avgPerSession": "المتوسط لكل جلسة", + "avgTurnsPerSession": "{count} دورة لكل جلسة في المتوسط", + "avgPerActiveDay": "المتوسط لكل يوم نشط", + "peakBucket": "أعلى {bucket}", + "peakHour": "ساعة الذروة", + "daysValue": "{count} يومًا", + "idleDays": "أيام الخمول", + "byFolderTitle": "حسب المجلد", + "byAgentTitle": "حسب الوكيل", + "byModelTitle": "حسب النموذج", + "distributionTitle": "توزيع الاستخدام", + "distributionHint": "تُجمَّع الجلسات والرموز حسب البعد المحدد — انقر أي صف للتصفية به.", + "otherLabel": "أخرى", + "unknownModel": "نموذج غير مسجَّل", + "emptyBreakdown": "لا توجد سجلات بعد", + "sessionsCount": "{count} جلسة", + "heatmapTitle": "إيقاع عملك", + "heatmapHint": "الرموز حسب اليوم والساعة بالتوقيت المحلي.", + "heatmapPeakHint": "الأكثر كثافة حوالي {hour}:00.", + "less": "أقل", + "more": "أكثر", + "heatmapCell": "{weekday} {hour}:00 — {value} رمز", + "weekMon": "إث", + "weekTue": "ثل", + "weekWed": "أر", + "weekThu": "خم", + "weekFri": "جم", + "weekSat": "سب", + "weekSun": "أح", + "topSessionsTitle": "أكثر الجلسات استهلاكًا", + "untitledSession": "جلسة بلا عنوان", + "topSessionsEmpty": "لا جلسات في هذا النطاق", + "streakLongest": "أطول سلسلة", + "streakLongestDays": "أطول سلسلة: {count} يومًا", + "share": "مشاركة", + "moreActions": "مزيد من الإجراءات", + "shareDialogTitle": "شارك بطاقة استهلاكك", + "shareDialogHint": "لقطة للنطاق والمرشحات التي تعرضها الآن.", + "shareSave": "حفظ الصورة", + "shareCopy": "نسخ الصورة", + "shareCopied": "تم النسخ إلى الحافظة", + "shareSaved": "تم حفظ الصورة", + "shareFailed": "تعذّر إنشاء الصورة", + "shareRendering": "جارٍ الإنشاء…", + "cardHeading": "سجلّي في البرمجة بالذكاء الاصطناعي", + "cardRangeAll": "كل الفترات", + "cardTotalLabel": "الرموز المستهلكة", + "cardFooter": "صُنع بواسطة codeg", + "cardTopModels": "أبرز النماذج", + "cardTopProjects": "أبرز المشاريع", + "archetypeNightOwl": "بومة الليل", + "archetypeNightOwlDesc": "{percent}% من رموزك تُستهلك بعد حلول الظلام.", + "archetypeEarlyBird": "المستيقظ باكرًا", + "archetypeEarlyBirdDesc": "{percent}% من رموزك تُستهلك قبل التاسعة صباحًا.", + "archetypeWeekendWarrior": "محارب عطلة الأسبوع", + "archetypeWeekendWarriorDesc": "{percent}% من رموزك تحدث في عطلة الأسبوع.", + "archetypeCacheMaster": "سيد الذاكرة المؤقتة", + "archetypeCacheMasterDesc": "{percent}% من سياقك جاء من الذاكرة المؤقتة.", + "archetypeMarathoner": "عدّاء المسافات", + "archetypeMarathonerDesc": "{days} يومًا من البناء دون انقطاع.", + "archetypePolyglot": "متعدد المهارات", + "archetypePolyglotDesc": "{count} وكلاء في استخدام جادّ.", + "archetypeLaserFocus": "تركيز مطلق", + "archetypeLaserFocusDesc": "{percent}% من رموزك ذهبت لمشروع واحد.", + "archetypeDeepDiver": "الغوّاص", + "archetypeDeepDiverDesc": "{averageK}K رمز في الجلسة الواحدة وسطيًا.", + "archetypeSteady": "بنّاء ثابت", + "archetypeSteadyDesc": "{days} يومًا من الإنجاز.", + "emptyTitle": "لا توجد بيانات محسوبة بعد", + "emptyHint": "يقرأ codeg أعداد الرموز مباشرة من سجل كل وكيل. حدّث لتُحسب الجلسات الموجودة على هذا الجهاز.", + "emptyAction": "احسب جلساتي", + "loadFailed": "تعذّر تحميل بيانات الاستهلاك", + "truncatedNotice": "هذا النطاق واسع جدًا — الأرقام تغطي أحدث جزء منه فقط." + } +} diff --git a/src/i18n/messages/de.json b/src/i18n/messages/de.json index 0c40db5d3..7e77e7ecf 100644 --- a/src/i18n/messages/de.json +++ b/src/i18n/messages/de.json @@ -1,4956 +1,4958 @@ -{ - "Language": { - "followSystem": "Systemsprache verwenden", - "english": "Englisch", - "simplifiedChinese": "Vereinfachtes Chinesisch", - "traditionalChinese": "Traditionelles Chinesisch", - "japanese": "Japanisch", - "korean": "Koreanisch", - "spanish": "Spanisch", - "german": "Deutsch", - "french": "Französisch", - "portuguese": "Portugiesisch", - "arabic": "Arabisch" - }, - "GitCredentialDialog": { - "title": "Authentifizierung erforderlich", - "description": "Der Remote-Server erfordert Anmeldedaten. Geben Sie Ihren Benutzernamen und Ihr Passwort (oder persönliches Zugriffstoken) ein.", - "username": "Benutzername", - "usernamePlaceholder": "Benutzername oder E-Mail", - "password": "Passwort / Token", - "passwordPlaceholder": "Passwort oder persönliches Zugriffstoken", - "passwordHint": "Geben Sie Benutzername und Passwort des Servers ein.", - "cancel": "Abbrechen", - "authenticate": "Authentifizieren", - "authenticating": "Authentifizierung...", - "invalidCredentials": "Ungültige Anmeldedaten. Bitte versuchen Sie es erneut.", - "saveCredentials": "Anmeldedaten für zukünftige Vorgänge speichern", - "githubTitle": "GitHub-Authentifizierung", - "githubDescription": "Geben Sie ein persönliches Zugriffstoken ein, um sich mit GitHub zu verbinden. Das Token wird validiert und automatisch gespeichert.", - "githubToken": "Persönliches Zugriffstoken", - "githubTokenPlaceholder": "ghp_xxxxxxxxxxxx", - "githubTokenHint": "Erstellen Sie ein Token unter GitHub → Settings → Developer settings → Personal access tokens.", - "githubAuthenticate": "Validieren & verbinden", - "generateToken": "Token erstellen" - }, - "SettingsShell": { - "title": "Einstellungen", - "preferences": "Präferenzen", - "nav": { - "general": "Allgemein", - "appearance": "Darstellung", - "agents": "Agenten", - "mcp": "MCP", - "skills": "Skills", - "shortcuts": "Kurzbefehle", - "version_control": "Versionskontrolle", - "system": "Systemeinstellungen", - "chat_channels": "Chat-Kanäle", - "web_service": "Webdienst", - "model_providers": "Modellanbieter", - "experts": "Experten", - "science": "Wissenschaft", - "office_tools": "Office-Tools", - "skill_packs": "Skill-Pakete", - "quick_messages": "Schnellnachrichten", - "logs": "Laufzeitprotokolle" - } - }, - "AppearanceSettings": { - "sectionTitle": "Design-Erscheinungsbild", - "sectionDescription": "Wähle hell, dunkel oder Systemvorgabe. Einstellungen werden automatisch gespeichert.", - "themeMode": "Designmodus", - "placeholder": "Designmodus auswählen", - "system": "Systemvorgabe", - "light": "Hell", - "dark": "Dunkel", - "currentTheme": "Aktuell wirksames Design: {theme}", - "resolvedTheme": { - "light": "Hell", - "dark": "Dunkel", - "unknown": "--" - }, - "themeColor": { - "sectionTitle": "Themenfarbe", - "sectionDescription": "Wähle eine Farbpalette für Akzente, Schaltflächen und Hervorhebungen.", - "current": "Aktuelle Farbe: {color}", - "options": { - "neutral": "Neutral", - "zinc": "Zinc", - "slate": "Slate", - "stone": "Stone", - "gray": "Gray", - "red": "Red", - "rose": "Rose", - "orange": "Orange", - "green": "Green", - "blue": "Blue", - "yellow": "Yellow", - "violet": "Violet" - } - }, - "customStyle": { - "sectionTitle": "Eigener Stil", - "sectionDescription": "Feinjustiere die Farben des aktuellen Themes oder füge eigenes CSS ein. Überschreibungen liegen über der Basisvorlage und bleiben beim Wechsel der Vorlage erhalten.", - "summarySuspended": "Ausgesetzt", - "summaryDefault": "Vorlage unverändert", - "summaryTokens": "{count, plural, one {# Überschreibung} other {# Überschreibungen}}", - "summaryCss": "Eigenes CSS", - "suspendedByShortcut": "Der eigene Stil ist ausgesetzt. Nichts, was du hier einstellst, wirkt, bis du ihn fortsetzt.", - "suspendedBySafeParam": "Dieses Fenster wurde im sicheren Darstellungsmodus geöffnet, daher wird eigener Stil hier ignoriert. Andere Fenster sind nicht betroffen.", - "resume": "Eigenen Stil fortsetzen", - "enableTheme": "Eigene Farben aktivieren", - "editingLight": "Du bearbeitest die Werte des hellen Modus. Wechsle die App in den dunklen Modus, um diesen separat einzustellen.", - "editingDark": "Du bearbeitest die Werte des dunklen Modus. Wechsle die App in den hellen Modus, um diesen separat einzustellen.", - "resetToken": "Auf Vorlagenwert zurücksetzen", - "radius": "Eckenradius", - "radiusHint": "Daraus leitet sich die gesamte Radiusskala von sm bis 4xl ab – ein Regler rundet die ganze App.", - "advanced": "Erweitert ({count} weitere Variablen)", - "enableCss": "Eigenes CSS aktivieren", - "cssRisk": "Funktion für Fortgeschrittene. Eigenes CSS überschreibt sämtliche eingebauten Stile und kann die Oberfläche unbrauchbar machen.", - "editCss": "CSS bearbeiten…", - "cssPresent": "{size} KB gespeichert", - "cssEmpty": "Noch nichts gespeichert", - "escapeHint": "Oberfläche kaputt? Drücke {shortcut}, um den gesamten eigenen Stil auszusetzen, oder öffne ein Fenster mit dem Query-Parameter safeStyle=1.", - "copyTheme": "Theme-JSON kopieren", - "importTheme": "Theme importieren…", - "clearTheme": "Überschreibungen löschen", - "interopHint": "Themes nutzen das registry:theme-Format von shadcn – du kannst hier jedes shadcn-Theme einfügen und exportierte in jedem shadcn-Projekt verwenden.", - "importTitle": "Theme importieren", - "importDescription": "Füge ein shadcn-registry:theme-Item, ein reines light/dark-Objekt oder eine flache Token-Zuordnung ein.", - "readClipboard": "Zwischenablage lesen", - "importConfirm": "Importieren", - "cancel": "Abbrechen", - "apply": "Anwenden", - "toasts": { - "copied": "Theme-JSON kopiert", - "copyFailed": "Kopieren in die Zwischenablage fehlgeschlagen", - "clipboardReadFailed": "Zwischenablage konnte nicht gelesen werden, bitte manuell einfügen", - "importFailed": "In diesem JSON wurden keine nutzbaren Theme-Variablen gefunden", - "imported": "Theme importiert" - }, - "css": { - "dialogTitle": "Eigenes CSS", - "dialogDescription": "Gilt für alle codeg-Fenster. Änderungen werden live vorschauend angezeigt; zum Speichern auf Anwenden klicken.", - "size": "{used} KB / {max} KB", - "ruleCount": "{count} Regeln", - "errorTooLarge": "Zu groß zum Speichern. Bitte unter das Limit kürzen.", - "errorImportEscaped": "Eine @import-Regel hat das Entfernen überstanden (maskierte Schreibweise). Bitte entfernen, um zu speichern.", - "warnNoRules": "Keine Regeln erkannt – bitte die Syntax prüfen.", - "noticeImportsRemoved": "Entfernte @import-Regeln: {count}. Sie würden entfernte Stylesheets laden.", - "noticeRemoteUrl": "Enthält eine entfernte url(), die beim Anwenden eine Netzwerkanfrage auslöst.", - "noticePreviewSuspended": "Der eigene Stil ist ausgesetzt, daher wird diese Vorschau nicht angewendet.", - "noticeDisabled": "Eigenes CSS ist aus. Du kannst hier eine Vorschau sehen, aber es wirkt erst nach dem Aktivieren.", - "hintTokens": "Tipp: Deine überschriebenen Farben sind als var(--primary), var(--background) usw. verfügbar." - } - }, - "zoomLevel": { - "sectionTitle": "Fensterzoom", - "sectionDescription": "Skaliert die gesamte Oberfläche. Wird sofort übernommen und pro Gerät gespeichert.", - "placeholder": "Zoomstufe wählen", - "default": "Standard", - "current": "Aktueller Zoom: {zoom}%" - }, - "fonts": { - "sectionTitle": "Schriftarten", - "sectionDescription": "Wähle Schriftarten für Oberfläche, Code-Editor und Terminal. Mitgelieferte Schriftarten werden bei Bedarf geladen; wähle „Benutzerdefiniert…“, um eine beliebige auf deinem System installierte Schriftart zu verwenden.", - "interface": "Oberfläche", - "editor": "Editor", - "terminal": "Terminal", - "groupSans": "Serifenlos", - "groupMono": "Monospace", - "custom": "Benutzerdefiniert…", - "customPlaceholder": "Schriftartname, z. B. Fira Code", - "fontSize": "Schriftgröße", - "ligatures": "Ligaturen aktivieren", - "ligaturesUnavailable": "Diese Schriftart hat keine Ligaturen", - "wordWrap": "Zeilenumbruch aktivieren", - "terminalLigaturesHint": "Terminal-Ligaturen gelten nur für mitgelieferte Programmierschriftarten.", - "preview": "Vorschau" - }, - "welcomePanel": { - "sectionTitle": "Modusauswahlbereich", - "sectionDescription": "Die Shortcut-Karten „Code-Entwicklung / Büroarbeit“ über dem Eingabefeld auf der Seite für eine neue Konversation.", - "showQuickActions": "Auf der Seite für neue Konversationen anzeigen" - }, - "workspaceBackground": { - "sectionTitle": "Arbeitsbereich-Hintergrund", - "sectionDescription": "Zeigt ein Bild hinter dem gesamten Arbeitsbereich. Seitenleiste und Panels werden durchscheinend und mattiert, sodass das Bild durchscheint, und eine Maske sorgt für lesbaren Text.", - "enable": "Hintergrundbild aktivieren", - "image": "Bild", - "chooseImage": "Bild auswählen", - "replaceImage": "Bild ersetzen", - "removeImage": "Entfernen", - "fillMode": "Füllmodus", - "fillModes": { - "cover": "Füllen", - "contain": "Einpassen", - "center": "Zentrieren", - "tile": "Kacheln" - }, - "maskOpacity": "Maskendeckkraft", - "maskOpacityHint": "Höhere Werte blenden das Bild zur Hintergrundfarbe des Themes aus und verbessern den Textkontrast.", - "imageBlur": "Bildunschärfe", - "panelOpacity": "Panel-Deckkraft", - "panelOpacityHint": "Wie deckend Seitenleiste, Panels und Tab-Leisten sind. Niedriger lässt mehr vom Bild durchscheinen.", - "errorTooLarge": "Bild ist zu groß (max. 16 MB).", - "errorUploadFailed": "Hintergrundbild konnte nicht festgelegt werden." - } - }, - "SystemSettings": { - "loading": "Wird geladen...", - "sectionTitle": "Systemverwaltung", - "sectionDescription": "Verwalte Netzwerk-Proxy, App-Updates und Spracheinstellungen.", - "proxyTitle": "Netzwerk-Proxy", - "proxyDescription": "Wenn aktiviert, werden nachfolgende Netzwerkanfragen bevorzugt über diesen Proxy ausgeführt (einschließlich ACP-Chat, Agent-Installation und Git-Remote-Operationen).", - "loadFailed": "Laden fehlgeschlagen: {message}", - "enableProxy": "System-Proxy aktivieren", - "proxyAddress": "Proxy-Adresse", - "proxyHint": "Unterstützt http(s)/socks5, Beispiel: {example}. Wirksam nur bei aktiviertem System-Proxy.", - "save": "Speichern", - "saving": "Wird gespeichert...", - "proxyRequired": "Bei aktiviertem Proxy ist eine Proxy-URL erforderlich", - "saveSuccess": "System-Proxy-Einstellungen wurden gespeichert", - "saveFailed": "Speichern fehlgeschlagen: {message}", - "languageTitle": "Sprache", - "languageDescription": "Lege die App-Sprache fest. Bei Systemsprache wird bei nicht unterstützten Sprachen auf Englisch zurückgefallen.", - "appLanguage": "App-Sprache", - "languageSaveSuccess": "Spracheinstellungen wurden gespeichert", - "languageSaveFailed": "Spracheinstellungen konnten nicht gespeichert werden: {message}", - "updateTitle": "App-Update", - "versionTitle": "Softwareupdate", - "updateDescription": "Prüft die konfigurierte Release-Quelle auf neue Versionen und installiert sie bei Verfügbarkeit direkt.", - "currentVersion": "Aktuelle Version", - "upgradableVersion": "Neueste Version", - "none": "Keine", - "lastChecked": "Zuletzt geprüft: {time}", - "updateError": "Update-Fehler: {message}", - "checking": "Wird geprüft...", - "checkUpdate": "Nach Updates suchen", - "updating": "Wird installiert...", - "downloading": "Herunterladen...", - "upgradeTo": "Auf v{version} aktualisieren", - "viewRelease": "Release v{version} anzeigen", - "foundUpdate": "Neue Version v{version} gefunden", - "alreadyLatest": "Du verwendest bereits die neueste Version", - "checkUpdateFailed": "Update-Prüfung fehlgeschlagen: {message}", - "installSuccess": "Update installiert. App wird neu gestartet.", - "installFailed": "Update fehlgeschlagen: {message}", - "upgradeSuccess": "Aktualisierung abgeschlossen. Wird neu geladen...", - "restartTimeout": "Der Server ist nicht rechtzeitig zurückgekehrt. Prüfe die Container- oder Dienstprotokolle.", - "restartingIn": "Neustart in {seconds} s...", - "waitingForServer": "Warten, bis der Server zurückkehrt...", - "restartToUpdate": "Zum Aktualisieren neu starten", - "newVersionBadge": "Neu v{version}", - "updateAvailableTitle": "Update verfügbar", - "releaseNotesTitle": "Neuerungen", - "remindLater": "Später", - "retry": "Erneut versuchen", - "stepDownload": "Download", - "stepInstall": "Installation", - "stepRestart": "Neustart", - "updateReadyHint": "Update heruntergeladen – zum Anwenden neu starten.", - "restarting": "Neustart...", - "dockerUpgradeHint": "Dies aktualisiert jetzt den laufenden Container. Beim Neuerstellen des Containers geht es verloren – zum Beibehalten ein Image mit der neuen Version ziehen oder bauen und den Container neu erstellen.", - "upgradeRolledBack": "Upgrade fehlgeschlagen; der Server wurde auf die vorherige Version zurückgesetzt.", - "serverUnreachable": "Der Server konnte für das Upgrade nicht erreicht werden. Prüfe, ob er läuft, und versuche es erneut.", - "rollbackButton": "Zurücksetzen", - "rollingBack": "Wird zurückgesetzt...", - "rollbackDescription": "Stellt die vor dem letzten Upgrade installierte Version wieder her.", - "rollbackConfirmTitle": "Auf die vorherige Version zurücksetzen?", - "rollbackConfirmDescription": "Der Server startet mit der vor dem letzten Upgrade installierten Version neu. Eine neuere Version kann weiterhin erneut installiert werden.", - "rollbackConfirm": "Zurücksetzen", - "rollbackCancel": "Abbrechen", - "rollbackSuccess": "Auf die vorherige Version zurückgesetzt. Wird neu geladen...", - "rollbackFailed": "Zurücksetzen fehlgeschlagen. Prüfe die Serverprotokolle.", - "updateErrors": { - "sourceUnavailable": "Die Update-Quelle ist nicht erreichbar. Prüfe Netzwerk oder Proxy und versuche es erneut.", - "network": "Netzwerkverbindung fehlgeschlagen. Prüfe Netzwerk oder Proxy und versuche es erneut.", - "downloadFailed": "Das Update-Paket konnte nicht heruntergeladen werden. Bitte später erneut versuchen.", - "installFailed": "Das Update konnte nicht installiert werden. Bitte App schließen und erneut versuchen.", - "unknown": "Update fehlgeschlagen. Bitte später erneut versuchen." - } - }, - "VersionControlSettings": { - "loading": "Laden...", - "sectionTitle": "Versionskontrolle", - "sectionDescription": "Git-Programm konfigurieren und GitHub-Konten verwalten.", - "gitTitle": "Git-Konfiguration", - "gitDescription": "Konfigurieren Sie das von der Anwendung verwendete Git-Programm.", - "gitDetected": "Git erkannt", - "gitNotFound": "Git wurde nicht gefunden", - "gitVersion": "Version", - "gitPath": "Pfad", - "customGitPath": "Benutzerdefinierter Git-Pfad", - "customGitPathPlaceholder": "/usr/bin/git", - "customGitPathHint": "Leer lassen, um den automatisch erkannten Pfad zu verwenden.", - "test": "Testen", - "testing": "Teste...", - "testSuccess": "Git-Programm ist gültig.", - "testFailed": "Git-Test fehlgeschlagen: {message}", - "save": "Speichern", - "saving": "Speichern...", - "saveSuccess": "Git-Einstellungen gespeichert.", - "saveFailed": "Speichern fehlgeschlagen: {message}", - "githubTitle": "GitHub-Konten", - "githubDescription": "GitHub-Konten für die Authentifizierung verwalten. Token werden lokal gespeichert.", - "noAccounts": "Keine GitHub-Konten konfiguriert.", - "addAccount": "Konto hinzufügen", - "serverUrl": "Server-URL", - "serverUrlPlaceholder": "https://github.com", - "token": "Persönlicher Zugriffstoken", - "tokenPlaceholder": "ghp_xxxxxxxxxxxx", - "generateToken": "Token erstellen", - "tokenHint": "Erstellen Sie einen Token unter GitHub → Settings → Developer settings → Personal access tokens.", - "validateAndAdd": "Validieren & hinzufügen", - "validating": "Validiere...", - "addSuccess": "Konto {username} erfolgreich hinzugefügt.", - "addFailed": "Konto konnte nicht hinzugefügt werden: {message}", - "testConnection": "Testen", - "connectionSuccess": "Verbindung erfolgreich.", - "connectionFailed": "Verbindung fehlgeschlagen: {message}", - "setDefault": "Als Standard festlegen", - "defaultLabel": "Standard", - "defaultSet": "Standardkonto aktualisiert.", - "removeAccount": "Entfernen", - "removeConfirmTitle": "Konto entfernen", - "removeConfirmMessage": "Möchten Sie das Konto \"{username}\" wirklich entfernen?", - "removeConfirm": "Entfernen", - "removeCancel": "Abbrechen", - "removeSuccess": "Konto entfernt.", - "scopes": "Berechtigungen", - "loadFailed": "Einstellungen konnten nicht geladen werden: {message}", - "gitAccount": { - "sectionTitle": "Git-Server-Konten", - "sectionDescription": "Verwalten Sie Anmeldedaten für Nicht-GitHub-Git-Server (GitLab, Bitbucket, selbst gehostet usw.).", - "noAccounts": "Keine Git-Server-Konten konfiguriert.", - "addAccount": "Konto hinzufügen", - "addTitle": "Git-Konto hinzufügen", - "addDescription": "Geben Sie Serveradresse, Benutzername und Passwort oder Zugriffstoken ein.", - "serverUrl": "Server-URL", - "serverUrlPlaceholder": "https://gitlab.example.com", - "username": "Benutzername", - "usernamePlaceholder": "Benutzername oder E-Mail", - "password": "Passwort / Token", - "passwordPlaceholder": "Passwort oder Zugriffstoken", - "passwordHint": "Geben Sie das Passwort oder Zugriffstoken des Servers ein.", - "add": "Hinzufügen", - "serverRequired": "Server-URL ist erforderlich.", - "usernameRequired": "Benutzername ist erforderlich.", - "passwordRequired": "Passwort ist erforderlich." - } - }, - "ShortcutSettings": { - "sectionTitle": "Kurzbefehle", - "resetDefault": "Standardwerte zurücksetzen", - "recordInstruction": "Klicke auf die rechte Schaltfläche und drücke dann eine Tastenkombination. Verwende Ctrl/Cmd, Alt und Shift. Drücke Esc, um die Aufzeichnung abzubrechen.", - "recording": "Kurzbefehl drücken...", - "toasts": { - "conflict": "Der Kurzbefehl wird bereits von \"{title}\" verwendet", - "updated": "Kurzbefehl aktualisiert", - "invalid": "Ungültiger Kurzbefehl, bitte erneut versuchen", - "reset": "Standard-Kurzbefehle wurden wiederhergestellt" - }, - "actions": { - "toggle_search": { - "title": "Suche öffnen", - "description": "Zeigt das Konversations-Suchpanel an oder blendet es aus" - }, - "toggle_sidebar": { - "title": "Linke Seitenleiste umschalten", - "description": "Zeigt die Seitenleiste mit der Konversationsliste an oder blendet sie aus" - }, - "toggle_terminal": { - "title": "Terminal umschalten", - "description": "Zeigt das untere Terminal-Panel an oder blendet es aus" - }, - "new_terminal_tab": { - "title": "Neues Terminal", - "description": "Erstellt einen neuen Terminal-Tab, wenn das Terminal fokussiert ist" - }, - "close_current_terminal_tab": { - "title": "Aktuelles Terminal schließen", - "description": "Schließt den aktuellen Terminal-Tab, wenn das Terminal fokussiert ist" - }, - "toggle_aux_panel": { - "title": "Rechtes Panel umschalten", - "description": "Zeigt das Zusatzinformations-Panel an oder blendet es aus" - }, - "new_conversation": { - "title": "Neue Konversation", - "description": "Erstellt einen neuen Konversations-Tab im aktuellen Ordner" - }, - "open_folder": { - "title": "Ordner öffnen", - "description": "Öffnet die Ordnerauswahl und den Ordner in einem neuen Fenster" - }, - "open_settings": { - "title": "Einstellungen öffnen", - "description": "Öffnet das Einstellungsfenster" - }, - "close_current_tab": { - "title": "Aktuellen Tab schließen", - "description": "Schließt den aktuellen Konversations- oder Dateitab" - }, - "close_all_file_tabs": { - "title": "Alle Dateitabs schließen", - "description": "Schließt alle geöffneten Dateitabs, wenn der Dateibereich aktiv ist" - }, - "next_tab": { - "title": "Nächster Tab", - "description": "Zum nächsten Konversations- oder Datei-Tab wechseln" - }, - "prev_tab": { - "title": "Vorheriger Tab", - "description": "Zum vorherigen Konversations- oder Datei-Tab wechseln" - }, - "send_message": { - "title": "Nachricht senden", - "description": "Die aktuelle Nachricht im Eingabefeld senden" - }, - "newline_in_message": { - "title": "Zeilenumbruch einfügen", - "description": "Einen Zeilenumbruch im Eingabefeld einfügen" - }, - "toggle_custom_style": { - "title": "Eigenen Stil aussetzen/fortsetzen", - "description": "Notausstieg: schaltet alle eigenen Farben und CSS aus und wieder ein" - } - } - }, - "SkillsSettings": { - "title": "Skills", - "description": "Wähle links einen Skill aus. Rechts wird standardmäßig eine Markdown-Vorschau angezeigt; wechsle zum Bearbeiten, um zu ändern und zu speichern.", - "loadingAgents": "Agenten mit Skill-Unterstützung werden geladen...", - "emptyNoManageableAgents": "Keine Agenten für Skill-Verwaltung verfügbar.", - "managedTarget": "Verwaltetes Ziel", - "selectAgentPlaceholder": "Agent auswählen", - "searchPlaceholder": "Nach Name / ID / Pfad suchen...", - "skillsList": "Skill-Liste", - "loadingSkills": "Skills werden geladen...", - "agentNotSupported": "Der aktuelle Agent unterstützt keine Skill-Verwaltung.", - "emptySkills": "Noch keine Skills. Klicke auf „Neuer Skill“, um einen zu erstellen.", - "newSkillTitle": "Neuer Skill", - "skillInfo": "Skill-Info", - "skillIdPlaceholder": "skill-id (Buchstaben/Zahlen/-/_/.)", - "skillsDirectoryWithPath": "Skill-Verzeichnis: {path}", - "skillsDirectoryNeedId": "Skill-Verzeichnis: Skill-ID eingeben, um den vollständigen Pfad zu erzeugen", - "markdownContent": "Markdown-Inhalt", - "editingStatus": "Bearbeiten", - "previewStatus": "Vorschau", - "contentPlaceholder": "Markdown-Inhalt des Skills eingeben...", - "metadataTitle": "Skill-Metadaten", - "onlyYamlMetadata": "Dieser Skill enthält nur YAML-Metadaten.", - "emptyContentHint": "Noch kein Inhalt. Klicke auf „Bearbeiten“, um zu starten.", - "loadingSkill": "Skill wird geladen...", - "emptyNoAgents": "Kein verfügbarer Agent.", - "noSelectionHint": "Wählen Sie links einen Skill oder klicken Sie auf „Neuer Skill“, um einen zu erstellen.", - "systemBadge": "System", - "systemHint": "Integrierter CLI-Skill · schreibgeschützt", - "scope": { - "global": "Global", - "folder": "Ordner", - "selectFolderPlaceholder": "Ordner auswählen", - "noFolders": "Keine Ordner gefunden", - "pickFolderHint": "Wählen Sie einen Ordner, um dessen Skills anzuzeigen." - }, - "actions": { - "preview": "Vorschau", - "edit": "Bearbeiten", - "openInWindow": "In neuem Fenster öffnen", - "delete": "Löschen", - "deleting": "Wird gelöscht...", - "refresh": "Aktualisieren", - "newSkill": "Neuer Skill", - "reset": "Zurücksetzen", - "save": "Speichern", - "saving": "Wird gespeichert...", - "cancel": "Abbrechen" - }, - "deleteDialog": { - "title": "Skill löschen", - "confirm": "Aktuellen Skill löschen? Diese Aktion kann nicht rückgängig gemacht werden.", - "confirmWithNamePrefix": "Skill", - "confirmWithNameSuffix": "löschen? Diese Aktion kann nicht rückgängig gemacht werden." - }, - "toasts": { - "loadFailed": "Skill konnte nicht geladen werden", - "openFolderFailed": "Ordner konnte nicht geöffnet werden", - "noSkillDirectory": "Kein verfügbares Skill-Verzeichnis für den aktuellen Agenten gefunden", - "nameRequired": "Skill-Name darf nicht leer sein", - "updated": "Skill aktualisiert", - "created": "Skill erstellt", - "saveFailed": "Skill konnte nicht gespeichert werden", - "deleted": "Skill gelöscht", - "deleteFailed": "Skill konnte nicht gelöscht werden" - }, - "templates": { - "gemini": "---\nname: example-skill\ndescription: Describe when this skill should be used.\n---\n\n# Skill Name\n\nInstructions for the agent when this skill is active.\n\n## Workflow\n\n1. Add actionable step one.\n2. Add actionable step two.\n", - "openCode": "---\nname: example-skill\ndescription: Describe when this skill should be used.\n---\n\n# Purpose\n\nDescribe what this skill helps with.\n\n# Steps\n\n1. Add actionable step one.\n2. Add actionable step two.\n", - "openClaw": "---\nname: example-skill\ndescription: Describe when this skill should be used.\nuser-invocable: true\ndisable-model-invocation: false\n---\n\n# Purpose\n\nDescribe what this skill helps with.\n\n# Instructions\n\n1. Add actionable instruction one.\n2. Add actionable instruction two.\n", - "default": "---\nname: example-skill\ndescription: Describe when this skill should be used.\n---\n\n# Skill: example-skill\n\n## When to use\n\n- Describe trigger conditions.\n\n## Instructions\n\n1. Add actionable instruction one.\n2. Add actionable instruction two.\n" - } - }, - "McpSettings": { - "loading": "Wird geladen...", - "summary": { - "missingCommand": "(fehlender Befehl)", - "missingUrl": "(fehlende URL)" - }, - "protocol": { - "stdio": "Stdio" - }, - "errors": { - "selectInstallProtocol": "Bitte ein Installationsprotokoll auswählen", - "fieldRequired": "{field} ist erforderlich", - "fieldNeedsBoolean": "{field} muss true oder false sein", - "fieldNeedsNumber": "{field} muss eine Zahl sein", - "fieldNeedsInteger": "{field} muss eine Ganzzahl sein", - "fieldInvalidJson": "{field} enthält ungültiges JSON: {message}", - "fieldOutOfRange": "Der Wert von {field} liegt außerhalb des erlaubten Bereichs", - "jsonEmpty": "{name} darf nicht leer sein", - "jsonInvalid": "{name} ist kein gültiges JSON: {message}", - "jsonMustBeObject": "{name} muss ein JSON-Objekt sein", - "specMustBeObject": "Die MCP-Konfiguration muss ein JSON-Objekt sein.", - "missingType": "Der Konfiguration fehlt das Feld type. Bitte stdio, http (Aliase: streamable-http, streamableHttp) oder sse angeben.", - "unsupportedType": "Nicht unterstützter MCP-Typ {type}. Unterstützt: stdio, http (Aliase: streamable-http, streamableHttp), sse.", - "codexEntryUnsupportedType": "Codex-MCP-Eintrag {id} hat den nicht unterstützten Typ {type}. Unterstützt: stdio, http (Aliase: streamable-http, streamableHttp), sse.", - "unsupportedTransportType": "Nicht unterstützter Transport-Typ {type}. Unterstützt: http (Aliase: streamable-http, streamableHttp), sse.", - "stdioCommandRequired": "stdio-MCPs benötigen ein nicht leeres Feld command.", - "remoteUrlRequired": "Remote-MCPs benötigen ein nicht leeres Feld url.", - "appsRequired": "Mindestens eine Ziel-App auswählen." - }, - "jsonNames": { - "localConfig": "MCP-Konfiguration", - "installConfig": "Installationskonfiguration" - }, - "toasts": { - "uninstalled": "MCP deinstalliert", - "uninstallFailed": "Deinstallation fehlgeschlagen: {message}", - "selectAtLeastOneApp": "Bitte mindestens eine Ziel-App auswählen", - "saveSuccess": "Gespeichert", - "saveFailed": "Speichern fehlgeschlagen: {message}", - "installed": "{name} installiert", - "installFailed": "Installation fehlgeschlagen: {message}", - "serverIdRequired": "Server-ID ist erforderlich", - "serverIdExists": "Server-ID \"{id}\" existiert bereits. Bearbeiten Sie den vorhandenen Eintrag oder wählen Sie einen anderen Namen.", - "created": "MCP erstellt" - }, - "installDialog": { - "title": "MCP-Installation bestätigen", - "descriptionWithName": "{name} in lokale Konfiguration installieren.", - "description": "Ziel-Apps für die Installation auswählen.", - "protocol": "Protokoll", - "selectProtocol": "Protokoll auswählen", - "parameters": "Konfigurationsparameter", - "booleanPlaceholder": "Bitte true/false auswählen", - "selectOneValue": "Wert auswählen", - "targetApps": "Ziel-Apps" - }, - "actions": { - "cancel": "Abbrechen", - "confirmInstall": "Installation bestätigen", - "installing": "Installieren", - "uninstall": "Deinstallieren", - "uninstalling": "Deinstallieren", - "viewDetails": "Details anzeigen", - "save": "Speichern", - "saving": "Speichern", - "install": "Installieren", - "refresh": "Aktualisieren", - "newMcp": "Neuer MCP", - "create": "Erstellen", - "creating": "Wird erstellt..." - }, - "tabs": { - "local": "Lokales MCP", - "market": "MCP-Marktplatz" - }, - "local": { - "filterPlaceholder": "Lokales MCP filtern...", - "loadFailed": "Laden fehlgeschlagen: {message}", - "empty": "Kein lokales MCP erkannt.", - "description": "Die lokale MCP-Konfiguration kann direkt bearbeitet und gespeichert werden.", - "enabledApps": "Aktivierte Apps", - "configJson": "MCP-Konfiguration (JSON)", - "draftTitle": "Neuer MCP", - "draftDescription": "Geben Sie eine Server-ID und Konfiguration an, um einen lokalen MCP-Server zu erstellen.", - "serverIdLabel": "Server-ID", - "serverIdPlaceholder": "Server-ID (z. B. my-mcp)", - "typeHint": "Unterstützte Typen: stdio, http (Aliase: streamable-http, streamableHttp), sse. env wird nur von stdio verwendet; für Remote-MCPs Auth-Tokens über headers übermitteln.", - "envOnRemoteWarning": "env wurde in einem Remote-MCP erkannt. Nur stdio verwendet env; Remote-MCPs übermitteln Auth-Tokens über headers, sodass env beim Speichern ignoriert wird." - }, - "market": { - "selectMarketplace": "Marktplatz auswählen", - "searchPlaceholder": "MCP suchen...", - "searchFailed": "Suche fehlgeschlagen: {message}", - "loadingList": "MCP-Liste wird geladen...", - "empty": "Keine MCP-Ergebnisse.", - "loadingDetail": "Marktplatzdetails werden geladen...", - "detailLoadFailed": "Details konnten nicht geladen werden: {message}", - "owner": "Inhaber: {owner}", - "namespace": "Namensraum: {namespace}", - "defaultInstallProtocol": "Standard-Installationsprotokoll", - "currentOptionParameterCount": "Anzahl der Parameter der aktuellen Option: {count}", - "installConfigDescription": "Installationskonfiguration (JSON, vor der Installation bearbeitbar; Änderungen überschreiben das Protokoll-/Parameterformular)", - "selectLeftToView": "Wähle links ein Marktplatz-MCP aus, um Details anzuzeigen." - }, - "badges": { - "verified": "Verifiziert", - "remote": "Remote", - "hasHomepage": "Hat Homepage", - "uses": "{count} Nutzungen", - "deployed": "Bereitgestellt", - "notDeployed": "Nicht bereitgestellt" - }, - "selectLeftMcp": "Wähle links ein MCP aus." - }, - "AcpAgentSettings": { - "title": "Agent SDK-Verwaltung", - "description": "Verwalten Sie Agent-SDK-Verbindung, Aktivierungsstatus, Umgebungsvariablen, Konfigurationsverwaltung und Versions-Preflight-Infos zentral an einem Ort.", - "loadingAgents": "Agentenliste wird geladen...", - "agentList": "Agentenliste", - "emptyNoAgent": "Keine verfügbaren Agenten.", - "configManagement": "Konfigurationsverwaltung", - "envVars": "Umgebungsvariablen", - "hostTools": { - "label": "Dateien und Befehle vom Agenten selbst ausführen lassen", - "description": "codeg übernimmt Dateizugriffe und Terminalbefehle nicht mehr, sodass der Agent sie im eigenen Prozess ausführt – nur dort greifen seine eigene Sandbox und seine Berechtigungsregeln. Auch das Delegieren an andere Agenten wird deaktiviert, da dieselbe Arbeit sonst wieder über codeg liefe. codeg fügt selbst keine Sandbox hinzu; aktivieren Sie dies also nur, wenn im Agenten eine konfiguriert ist." - }, - "nativeJsonConfig": "Natives JSON-Config", - "modelHintDefault": "Leer lassen, um das System-Standardmodell zu verwenden.", - "generalConfigDescriptionClaude": "Unterstützt schnelle Konfiguration von API-URL, API-Key und Claude-Modellen und synchronisiert mit der nativen JSON-Konfiguration.", - "generalConfigDescriptionDefault": "Unterstützt wichtige Konfigurationseingaben (API URL, API Key, Model) und native JSON-Konfigurationsverwaltung.", - "multiAgent": { - "title": "Multi-Agent-Zusammenarbeit", - "description": "Erlaubt aktiven Agenten, Teilaufgaben an andere Agenten zu delegieren.", - "enable": "Delegation aktivieren", - "enableHint": "Wenn deaktiviert, wird das Tool delegate_to_agent im MCP-Toolkatalog des Agenten ausgeblendet.", - "withheldByHostTools": "{agents} erhalten die Delegationswerkzeuge nicht: Ihr agentenspezifischer Schalter „Dateien und Befehle vom Agenten selbst ausführen lassen“ ist aktiv.", - "depthLimit": "Maximale Delegationstiefe", - "depthHint": "Zulässiger Bereich: {min}–{max}. Begrenzt, wie tief eine Delegationskette (Root → Kind → Enkel …) rekursieren kann.", - "completedCacheLabel": "Cache abgeschlossener Ergebnisse (MB)", - "completedCacheHint": "In-Memory-Cache abgeschlossener Subagent-Ergebnisse, der nur gehalten wird, solange die Delegationssitzung läuft, und beim Ende dieser Sitzung automatisch freigegeben wird. Bei Überschreitung dieses Budgets werden die ältesten Ergebnisse zuerst aus dem Speicher verworfen (weiterhin in der eigenen Sitzung des Subagenten einsehbar); 0 = unbegrenzt (wird trotzdem beim Sitzungsende freigegeben).", - "save": "Speichern", - "saving": "Wird gespeichert…", - "saved": "Delegationseinstellungen gespeichert", - "saveFailed": "Delegationseinstellungen konnten nicht gespeichert werden", - "loadFailed": "Delegationseinstellungen konnten nicht geladen werden: {detail}", - "tabGeneral": "Allgemein", - "tabAgentDefaults": "Subagent-Standards", - "agentDefaultsDescription": "Pro-Agent-Überschreibungen, die angewendet werden, wenn die Multi-Agent-Zusammenarbeit einen Subagenten für einen Delegationsaufruf startet. Die hier gezeigten Optionen stammen aus einer Live-Abfrage – Ihre Auswahl ist exakt das, was der Agent akzeptiert.", - "probing": "Verfügbare Optionen vom Agenten werden geladen…", - "probeFailed": "Optionen konnten nicht geladen werden: {detail}", - "retry": "Erneut versuchen", - "noConfigAvailable": "Dieser Agent hat keine konfigurierbaren Optionen.", - "modeLabel": "Modus", - "agentDefaultHint": "Agent-Standard: {value}", - "defaultOptionLabel": "Standard ({value})" - }, - "actions": { - "dragSort": "Zum Neuordnen ziehen", - "dragSortAgent": "{name} zum Neuordnen ziehen", - "refreshCheck": "Prüfung aktualisieren", - "refreshCheckAgent": "Prüfung für {name} aktualisieren", - "clickEnable": "Klicken, um {name} zu aktivieren", - "clickDisable": "Klicken, um {name} zu deaktivieren", - "install": "Installieren", - "upgrade": "Aktualisieren", - "uninstall": "Deinstallieren", - "uninstalling": "Wird deinstalliert...", - "saveEnvVars": "Umgebungsvariablen speichern", - "saving": "Speichern...", - "saveGrokConfig": "Grok-Konfiguration speichern", - "saveCodexConfig": "Codex-Konfiguration speichern", - "saveGeminiConfig": "Gemini-Konfiguration speichern", - "saveOpenCodeConfig": "OpenCode-Konfiguration speichern", - "saveOpenClawConfig": "OpenClaw-Konfiguration speichern", - "saveConfigManagement": "Konfigurationsverwaltung speichern", - "saveCurrentProvider": "Aktuellen Provider speichern", - "showApiKey": "API-Key anzeigen", - "hideApiKey": "API-Key ausblenden", - "showKey": "Schlüssel anzeigen", - "hideKey": "Schlüssel ausblenden", - "showToken": "Token anzeigen", - "hideToken": "Token ausblenden", - "cancel": "Abbrechen", - "delete": "Löschen", - "deleting": "Löschen...", - "confirmDelete": "Löschen bestätigen", - "confirmUninstall": "Deinstallation bestätigen", - "saveClineConfig": "Cline-Konfiguration speichern", - "saveHermesConfig": "Hermes-Konfiguration speichern", - "saveCodeBuddyConfig": "CodeBuddy-Konfiguration speichern", - "saveKimiCodeConfig": "Kimi-Code-Konfiguration speichern", - "customInstall": "Benutzerdefinierte Installation", - "saveKimiCodeRawConfig": "Save config.toml", - "saveDeepSeekConfig": "DeepSeek-Konfiguration speichern", - "diagnose": "Diagnose" - }, - "status": { - "enabled": "Aktiviert", - "disabled": "Deaktiviert", - "unchecked": "Nicht geprüft", - "agentEnabledAria": "{name} aktiviert", - "agentEnabledSwitch": "{name} Aktivierungsschalter" - }, - "preflight": { - "count": "Preflight-Elemente: {count}", - "notRun": "Prüfungen wurden noch nicht ausgeführt." - }, - "grok": { - "configDescription": "Konfiguriere Grok hier. Die folgenden Steuerelemente – Berechtigungsmodus, Reasoning-Aufwand, ein optionales benutzerdefiniertes Modell (eigener Endpunkt) und die Verdichtung – werden in ~/.grok/config.toml zusammengeführt, wobei deine anderen Schlüssel und Kommentare erhalten bleiben. Die Anmeldung nutzt deinen XAI_API_KEY oder `grok login`. Weitere Schlüssel bleiben unter „Erweitert“ bearbeitbar.", - "permissionModeLabel": "Berechtigungsmodus", - "permissionDefault": "Jedes Mal fragen", - "permissionAcceptEdits": "Bearbeitungen automatisch genehmigen", - "permissionAuto": "Intelligente Auto-Genehmigung", - "permissionAlwaysApprove": "Immer zulassen", - "reasoningEffortLabel": "Denkaufwand", - "effortLow": "Niedrig (schneller)", - "effortMedium": "Mittel (ausgewogen)", - "effortHigh": "Hoch", - "effortXhigh": "Maximal", - "optionDefault": "Standard verwenden", - "authTitle": "Authentifizierung", - "authMode": "Authentifizierungsmethode", - "authModeApiKey": "XAI-API-Schlüssel", - "authModeApiKeyHint": "Authentifiziere dich mit einem XAI_API_KEY aus der xAI-Konsole – für nicht-interaktive oder Headless-Läufe. Wird in der Umgebung dieses Agenten gespeichert.", - "authModeCustom": "Benutzerdefinierter Endpunkt", - "authModeCustomHint": "Verwende einen eigenen Endpunkt (BYO): Definiere unten ein benutzerdefiniertes Modell mit eigener Basis-URL und eigenem API-Schlüssel. Es wird zum Standardmodell von Grok.", - "subscriptionHint": "Melde dich mit `grok login` an (SuperGrok / X Premium+). Es wird kein API-Schlüssel gespeichert.", - "loginHint": "Führe dies in einem Terminal aus, um dich anzumelden, und öffne dann diese Einstellungen erneut:", - "commandCopied": "Befehl in die Zwischenablage kopiert", - "copyCommand": "Befehl kopieren", - "authKeyConfigured": "XAI_API_KEY ist konfiguriert.", - "authKeyMissing": "Kein XAI_API_KEY festgelegt.", - "advancedToggle": "Erweitert (rohe config.toml)", - "configTomlNative": "config.toml (nativ)", - "configTomlHint": "Wird wortwörtlich als gesamte ~/.grok/config.toml gespeichert. Ungültiges TOML wird abgelehnt, sodass ein Tippfehler deine Datei nie abschneidet.", - "configTomlPlaceholder": "# Andere Schlüssel als die Steuerelemente oben, z. B.\n# [mcp_servers.*], [cli], [permission]-Regeln.", - "customModelTitle": "Benutzerdefiniertes Modell (eigener Endpunkt)", - "customModelHint": "Richte Grok auf einen benutzerdefinierten oder selbst gehosteten Endpunkt. codeg schreibt einen `[model.*]`-Block pro Modell und legt es als Standard fest. Lasse die Modell-ID leer, um es zu entfernen.", - "customModelIdLabel": "Modell-ID", - "customModelIdPlaceholder": "grok-4.5", - "customModelIdHint": "Wird als `[model.*]`-Block registriert und als Modellname an die API gesendet; außerdem als `[models].default` gesetzt.", - "customBaseUrlLabel": "Basis-URL", - "customBaseUrlPlaceholder": "https://api.x.ai/v1 (Standard)", - "customApiBackendLabel": "API-Backend", - "backendResponses": "Responses", - "backendChatCompletions": "Chat Completions", - "backendMessages": "Messages (Anthropic)", - "customApiKeyLabel": "API-Schlüssel", - "customApiKeyHint": "Inline in `[model.*].api_key` gespeichert, nur für diesen Endpunkt.", - "customContextWindowLabel": "Kontextfenster (Tokens)", - "customContextWindowHint": "Optional. Steuert den Zeitpunkt der automatischen Verdichtung; leer lassen für den Standard des Endpunkts.", - "autoCompactLabel": "Schwellenwert für Auto-Verdichtung (%)", - "autoCompactHint": "Verdichtet die Unterhaltung, wenn die Kontextnutzung diesen Prozentsatz erreicht (Grok-Standard 85). Wird in `[session]` geschrieben." - }, - "cursor": { - "configDescription": "Konfiguriere Cursor hier. Wähle eine Authentifizierungsmethode – offizielles Abo (Browser-Anmeldung) oder einen Cursor-API-Schlüssel für Headless-/Servermaschinen – wähle dann ein Modell und bearbeite die Berechtigungsregeln und die Sandbox des CLI. codeg schreibt sie in ~/.cursor/cli-config.json, gemeinsam mit dem cursor-agent-CLI.", - "authTitle": "Authentifizierung", - "authChecking": "Prüfe…", - "authNotInstalled": "cursor-agent ist nicht installiert", - "authLoggedIn": "Angemeldet", - "authNotLoggedIn": "Nicht angemeldet", - "loginHint": "Führe dies im Terminal aus, um dich mit deinem Cursor-Konto anzumelden (ein Browserfenster öffnet sich), und klicke danach auf Aktualisieren:", - "apiKeyLabel": "Cursor-API-Schlüssel", - "apiKeyPlaceholder": "Schlüssel von cursor.com/dashboard", - "apiKeyHint": "CURSOR_API_KEY – ein Cursor-Dashboard-Kontoschlüssel, Alternative zur Browser-Anmeldung für Headless-/Servermaschinen. Kein Drittanbieter- oder OpenAI-Schlüssel.", - "modelTitle": "Standardmodell", - "loadModels": "Modelle laden", - "modelsUnavailable": "Modellliste nicht verfügbar", - "modelHint": "Wird der CLI beim Sitzungsstart als --model übergeben. Auf Standard lassen, damit Cursor wählt.", - "permissionsTitle": "Berechtigungen & Sandbox", - "permissionsDescription": "Visueller Editor für die Berechtigungsregeln der CLI (cli-config.json). Erlaubte Regeln laufen ohne Rückfrage; verweigerte werden immer blockiert.", - "permissionModeLabel": "Berechtigungsmodus", - "permissionModeDefault": "Vor der Ausführung fragen (Standard)", - "permissionModeForce": "Run Everything (--force)", - "permissionModeHint": "Run Everything startet Sitzungen mit --force: Alle Tool-Aufrufe werden ohne Rückfrage automatisch erlaubt, außer Deny-Regeln (eine Organisationsrichtlinie kann dies auf Allow-Regeln beschränken). Gilt für neue Sitzungen.", - "optionDefault": "Standard (nicht gesetzt)", - "sandboxLabel": "Sandbox", - "sandboxEnabled": "Aktiviert", - "sandboxDisabled": "Deaktiviert", - "allowRulesLabel": "Erlauben-Regeln", - "denyRulesLabel": "Verweigern-Regeln", - "addRule": "Regel hinzufügen", - "rulesSyntaxHint": "Regelsyntax: Shell(Befehl), Read(Pfad/Glob), Write(Pfad/Glob), WebFetch(Domain), Mcp(Server:Tool) — Deny-Regeln haben immer Vorrang.", - "saveConfig": "Konfiguration speichern", - "advancedToggle": "Erweitert: rohe cli-config.json", - "advancedHint": "Die komplette ~/.cursor/cli-config.json. Speichern schreibt die Datei unverändert; die strukturierten Steuerelemente oben werden stattdessen zusammengeführt.", - "saveRawConfig": "Datei speichern", - "authMode": "Authentifizierungsmethode", - "subscriptionHint": "Mit deinem Cursor-Konto anmelden und Cursors Modelle verwenden.", - "customApiKeyRequired": "Ein Cursor-API-Schlüssel ist erforderlich.", - "authModeApiKey": "Cursor-API-Schlüssel (Headless/Server)", - "authModeApiKeyHint": "Mit einem Cursor-Konto-API-Schlüssel aus dem Cursor-Dashboard authentifizieren (für Headless-/Servermaschinen). Das ist ein Cursor-Kontoschlüssel, kein Drittanbieter-/OpenAI-Endpunkt – cursor-agent kommuniziert nur mit dem Cursor-Backend. Um einen codex-/OpenAI-kompatiblen Endpunkt zu nutzen, verwende stattdessen den Codex-Agenten.", - "modelPickerPlaceholder": "Modelle suchen…", - "modelNoMatch": "Kein passendes Modell", - "modelsNeedAuth": "Melde dich an, um die Modellliste zu laden.", - "modelDefaultBadge": "Standard" - }, - "deepseek": { - "configManagement": "DeepSeek-Harness-Konfiguration", - "configDescription": "Endpunkt und Schlüssel sind Umgebungsvariablen, die deepseek-acp beim Start liest. Modell und Denkstufe sind Auswahlfelder pro Sitzung — sie werden im Eingabefeld gewählt.", - "baseUrlLabel": "API-Endpunkt", - "baseUrlHint": "Leer lassen für den offiziellen Endpunkt. Gilt für Sitzungen, die nach dem Speichern starten – eine laufende Sitzung muss neu verbinden.", - "baseUrlInvalid": "Vollständige http(s)-URL ohne Query-String eingeben, zum Beispiel https://api.deepseek.com", - "apiKeyLabel": "API-Schlüssel", - "apiKeyHint": "Wird dem Agenten als DEEPSEEK_API_KEY übergeben. Eine Umgebungsvariable hat Vorrang vor der Zugangsdatendatei – lass das Feld leer, wenn du dich im Terminal anmeldest." - }, - "codex": { - "configDescription": "Unterstützt schnelle Konfiguration von API-URL, API-Key, Modellname und reasoning effort und synchronisiert mit `auth.json` / `config.toml`.", - "authMode": "Authentifizierungsmodus", - "chatgptSubscription": "Offizielles Abonnement", - "chatgptSubscriptionHint": "Mit offiziellem ChatGPT-Abonnement anmelden, kein API Key erforderlich", - "apiKeyHint": "Mit API Key zu OpenAI oder kompatiblen API-Diensten verbinden", - "selectProvider": "Provider auswählen", - "modelName": "Modellname", - "selectReasoningEffort": "Reasoning Effort auswählen", - "enableWebsocket": "WebSocket aktivieren", - "enableWebsocketAria": "WebSocket für Codex Provider aktivieren", - "enableSkills": "Skills aktivieren", - "enableSkillsAria": "Skills für Codex aktivieren", - "enableFast": "Fast aktivieren", - "enableFastAria": "Fast-Servicestufe für Codex aktivieren", - "sandboxGroupTitle": "Sandbox und Freigaben", - "sandboxGroupHint": "Wird in die globale ~/.codex/config.toml geschrieben und gilt daher auch für codex-CLI- und IDE-Sitzungen. Es sind Thread-Standardwerte: Sie gelten für Turns, die codex selbst startet (/goal, /review, /compact). Normale Eingaben nutzen die Freigabe-Voreinstellung des Eingabefelds. Änderungen greifen nach einem Neustart der Sitzung.", - "sandboxShadowedWarning": "config.toml setzt default_permissions, daher löst codex Berechtigungen über dieses Profil auf und ignoriert sandbox_mode vollständig. Entferne default_permissions, um die Optionen unten zu nutzen.", - "sandboxPermissionsTableWarning": "config.toml definiert [permissions]-Profile, aber kein default_permissions — damit verweigert codex den Start. Setze es im Rohtext-Editor unten.", - "approvalPolicyLabel": "Freigaberichtlinie", - "approvalPolicyUnset": "Nicht gesetzt (codex-Standard: auf Anfrage)", - "approvalPolicy_on-request": "Auf Anfrage – das Modell entscheidet, wann es nachfragt", - "approvalPolicy_untrusted": "Nicht vertrauenswürdig – nur bekannt sichere Lesebefehle laufen ohne Nachfrage", - "approvalPolicy_never": "Nie – keinerlei Freigabeabfragen", - "approvalPolicy_granular": "Granular – pro Abfragetyp festlegen", - "approvalPolicyUntrustedAcpWarning": "Für „untrusted“ gibt es unter den drei Freigabe-Voreinstellungen des ACP-Adapters keine Entsprechung, daher fallen codeg-Sitzungen auf „auf Anfrage“ zurück: Das Modell entscheidet dann selbst, wann es fragt, und Befehle, die die Sandbox ohnehin erlaubt, fragen nicht mehr nach. Schränke stattdessen unten den Sandbox-Modus ein.", - "granularHint": "Aus bedeutet, dass Anfragen dieser Art automatisch abgelehnt statt angezeigt werden.", - "granular_sandbox_approval": "Rechteerweiterung für Shell-Befehle", - "granular_rules": "Abfragen aus Execpolicy-Regeln", - "granular_skill_approval": "Abfragen bei Skill-Skripten", - "granular_request_permissions": "Abfragen des request_permissions-Tools", - "granular_mcp_elicitations": "MCP-Elicitation-Abfragen", - "sandboxModeLabel": "Sandbox-Modus", - "sandboxModeUnset": "Nicht gesetzt (vertrauenswürdige Ordner fallen auf Workspace-Schreibzugriff zurück)", - "sandboxMode_read-only": "Nur lesen", - "sandboxMode_workspace-write": "Workspace-Schreibzugriff", - "sandboxMode_danger-full-access": "Vollzugriff (keine Sandbox)", - "sandboxModeHint": "Unter Windows wird Workspace-Schreibzugriff auf Nur-Lesen herabgestuft, sofern die experimentelle Windows-Sandbox von codex nicht aktiviert ist.", - "sandboxModeSeedsPresetHint": "codeg leitet daraus auch die anfängliche Freigabe-Voreinstellung der Sitzung ab — anders als die Freigaberichtlinie wirkt es also auch auf normale Anfragen. Die im Eingabefeld gewählte Voreinstellung hat weiterhin Vorrang.", - "writableRootsLabel": "Zusätzliche beschreibbare Ordner", - "writableRootsHint": "Ein absoluter Pfad pro Zeile, zusätzlich zum Arbeitsverzeichnis.", - "sandboxRootsRelativeError": "Muss ein absoluter Pfad sein – codex löst relative Angaben unter ~/.codex auf: {path}", - "networkAccessLabel": "Netzwerkzugriff erlauben", - "excludeTmpdirLabel": "TMPDIR von den beschreibbaren Wurzeln ausschließen", - "excludeSlashTmpLabel": "/tmp von den beschreibbaren Wurzeln ausschließen", - "authJsonNative": "auth.json (nativ)", - "configTomlNative": "config.toml (nativ)", - "loginButton": "Mit ChatGPT anmelden", - "loginRequesting": "Login-Code wird angefordert...", - "loginStep1": "Öffnen Sie die folgende URL in Ihrem Browser:", - "loginStep2": "Geben Sie den folgenden Code ein:", - "loginPolling": "Warte auf Autorisierung...", - "loginCancel": "Abbrechen", - "loginSuccess": "Erfolgreich angemeldet, Konfiguration gespeichert!", - "loginFailed": "Anmeldung fehlgeschlagen: {message}", - "loginRetry": "Erneut versuchen", - "loginCodeCopied": "Code kopiert", - "loggedIn": "Konto angemeldet", - "loginRelogin": "Erneut anmelden / Konto wechseln", - "loginTimeout": "Anmeldung abgelaufen, bitte erneut versuchen", - "loginSaveFailed": "Anmeldung erfolgreich, aber Konfiguration konnte nicht gespeichert werden" - }, - "gemini": { - "authConfig": "Gemini-Auth-Konfiguration", - "authConfigDescription": "Ausgerichtet an den Gemini CLI-Authentifizierungsdokumenten, mit Unterstützung für benutzerdefinierten Endpoint, Google-Login, Gemini API Key und Vertex AI (ADC / Servicekonto / API Key).", - "authMode": "Auth-Modus", - "selectAuthMode": "Auth-Modus auswählen", - "viewAuthDoc": "Auth-Dokumentation anzeigen", - "mode": { - "custom": "Benutzerdefinierter Endpoint", - "loginGoogle": "Google-Login (OAuth)", - "vertexServiceAccount": "Vertex AI (Servicekonto)" - }, - "hint": { - "custom": "API URL, API Key und Modell ausfüllen; wird auf GOOGLE_GEMINI_BASE_URL / GEMINI_API_KEY / GEMINI_MODEL abgebildet.", - "loginGoogle": "Gemini zuerst im Terminal ausführen und Google-Login abschließen; API key ist nicht erforderlich.", - "geminiApiKey": "Beim Verwenden der Gemini API GEMINI_API_KEY eintragen.", - "vertexAdc": "gcloud ADC verwenden; GOOGLE_CLOUD_PROJECT und GOOGLE_CLOUD_LOCATION werden empfohlen.", - "vertexServiceAccount": "Pfad zur Servicekonto-JSON in GOOGLE_APPLICATION_CREDENTIALS setzen.", - "vertexApiKey": "Beim Verwenden eines Vertex AI API Keys GOOGLE_API_KEY eintragen." - } - }, - "openCode": { - "configManagement": "OpenCode-Konfigurationsverwaltung", - "configDescription": "An OpenCode-`provider`-Schema ausgerichtet, unterstützt Multi-Provider-Verwaltung und bidirektionale Synchronisierung mit nativen JSON-Dateien.", - "providerManagement": "Provider-Verwaltung", - "providerCount": "{count} Provider", - "addProvider": "Provider hinzufügen", - "emptyProvider": "Noch keine benutzerdefinierten Provider. Klicke auf Benutzerdefinierten Provider hinzufügen, um einen zu erstellen.", - "providerEnabledState": "{providerId} Aktivierungsstatus", - "selectProviderNpm": "provider.npm auswählen", - "modelManagement": "Modellverwaltung", - "modelCount": "{count} Modelle", - "modelDescription": "Ausgerichtet an OpenCode `provider.models`. Schnellverwaltung unterstützt derzeit `name` / `id`; andere erweiterte Felder bleiben erhalten und können unten im nativen JSON bearbeitet werden.", - "addModel": "Modell hinzufügen", - "emptyModel": "Noch kein Modell vorhanden. model id eingeben und dann auf „Modell hinzufügen“ klicken.", - "modelId": "Modell-ID", - "modelName": "Modellname", - "deleteModel": "Modell {modelId} löschen", - "nativeJsonConfig": "OpenCode Native JSON-Konfiguration", - "mainModel": "Hauptmodell", - "smallModel": "Kleines Modell", - "noMatchingModels": "Keine passenden Modelle", - "connectProvider": "Provider verbinden", - "connectedProviders": "Verbundene Provider", - "noConnectedProviders": "Noch keine Katalog-Provider verbunden.", - "advancedProviderConfig": "Benutzerdefinierte Provider", - "customProviderConfigHint": "OpenAI-kompatible Endpunkte, die du selbst definierst – ein Provider-Block in opencode.json, mit dem API-Key in auth.json.", - "addCustomProvider": "Benutzerdefinierten Provider hinzufügen", - "disconnect": "Trennen", - "editConfig": "Bearbeiten", - "customBadge": "Benutzerdefiniert", - "authKindApi": "API-Schlüssel", - "authKindOauth": "OAuth", - "authKindNone": "Keine Anmeldedaten", - "connect": { - "title": "Provider verbinden", - "description": "Wähle einen Provider aus dem models.dev-Katalog. Anmeldedaten werden in der auth.json-Datei von OpenCode gespeichert.", - "pick": "Provider", - "search": "Provider suchen…", - "loading": "Katalog wird geladen…", - "catalogLabel": "models.dev-Katalog", - "modelsAvailable": "{count} Modelle verfügbar", - "getKey": "API-Schlüssel holen", - "oauthApiKeyNote": "Dieser Provider unterstützt auch die Browser-Anmeldung über opencode auth login. Die Browser-Anmeldung kommt bald — füge vorerst einen API-Schlüssel ein.", - "apiKey": "API-Schlüssel", - "apiKeyHint": "Wird in auth.json gespeichert, nie in opencode.json.", - "baseUrlOptional": "Basis-URL überschreiben (optional)", - "providerId": "Provider-ID", - "displayName": "Anzeigename", - "modelsList": "Modelle (eins pro Zeile)", - "modelsHint": "Modell-IDs, die der Endpunkt akzeptiert.", - "action": "Verbinden", - "editTitle": "Provider bearbeiten", - "editDescription": "Aktualisiere den API-Schlüssel oder die Basis-URL dieses Providers.", - "saveAction": "Speichern" - }, - "customProvider": { - "title": "Benutzerdefinierten Provider hinzufügen", - "description": "Definiere einen OpenAI-kompatiblen Endpunkt. Der API-Key wird in auth.json gespeichert, der Provider-Block in opencode.json.", - "action": "Provider hinzufügen", - "idInCatalog": "{providerId} ist ein bekannter Provider – verbinde ihn stattdessen über Provider verbinden." - }, - "refreshCatalog": "Katalog aktualisieren", - "reasoningBadge": "Reasoning", - "contextWindow": "Kontextfenster", - "permissions": { - "title": "Berechtigungen", - "description": "Legt fest, welche Aktionen einfach laufen, welche vorher nachfragen und welche blockiert werden. Wird in den permission-Block von opencode.json geschrieben und mit dem Speichern unten übernommen.", - "docsLink": "Dokumentation zu Berechtigungen", - "unparsableConfig": "Das native JSON unten ist ungültig, deshalb pausiert der visuelle Editor. Korrigiere das JSON, um fortzufahren.", - "invalidBlock": "Der permission-Block hat eine Form, die codeg nicht kennt. Bearbeite ihn im nativen JSON unten oder beginne mit Zurücksetzen neu.", - "orderingUnsafe": "Eine Wildcard-Regel steht hinter konkreten Tools, deshalb wendet OpenCode sie auch auf diese an – die Zeilen unten sind nicht das, was tatsächlich gilt. Reihenfolge korrigieren schiebt jede Wildcard nur wieder an den Anfang ihres Bereichs, ohne einen Wert zu ändern.", - "orderingUnsafeManual": "Eine Regel wird von einem späteren, allgemeineren Muster verdeckt, OpenCode wendet sie also nie an – die Zeilen unten sind nicht das, was tatsächlich gilt. Für zwei überlappende Muster gibt es keine eine richtige Reihenfolge; sortiere sie im nativen JSON so, dass das allgemeinere zuerst steht.", - "fixOrder": "Reihenfolge korrigieren", - "agentOverrides": "Diese Agenten überschreiben Berechtigungen und werden zuletzt angewendet, gewinnen also gegen alles hier: {agents}. Bearbeite sie im nativen JSON unten oder schalte die automatische Annahme ein, um sie zu löschen.", - "legacyTools": "Die veraltete tools-Map auf oberster Ebene verweigert ein Tool. OpenCode führt sie mit den Berechtigungen zusammen, sie gilt also über allem hier Gezeigten. Bearbeite sie im nativen JSON unten oder schalte die automatische Annahme ein, um sie zu löschen.", - "autoAcceptTitle": "Alle Berechtigungen automatisch annehmen", - "autoAcceptHint": "Jeder Tool-Aufruf – Shell-Befehle, Dateiänderungen, Pfade außerhalb des Projekts – läuft ohne Rückfrage. Beim Einschalten ersetzt eine einzige Alles-erlauben-Regel die Einstellungen pro Tool unten, und die Overrides einzelner Agenten sowie veraltete tools-Schalter, die sonst weiter blockieren würden, werden gelöscht.", - "globalLabel": "Globaler Standard", - "globalHint": "Die Regel *: gilt für alles, was die Tools unten nicht überschreiben.", - "actionUnset": "Nicht gesetzt (OpenCode-Standard)", - "actionInherit": "Standard übernehmen ({action})", - "actionAllow": "Erlauben", - "actionAsk": "Nachfragen", - "actionDeny": "Verweigern", - "perToolTitle": "Berechtigungen pro Tool", - "reset": "Zurücksetzen", - "ruleCount": "Regeln: {count}", - "rulesToggle": "Feingranulare Regeln für {tool}", - "rulesHint": "Wird gegen die Tool-Eingabe geprüft, die letzte Übereinstimmung gewinnt – schreibe die weiten Muster also zuerst. * passt auf beliebig viele Zeichen, ? auf genau eines, und ein führendes ~ wird zu deinem Home-Verzeichnis.", - "noRules": "Noch keine feingranularen Regeln.", - "addRule": "Regel hinzufügen", - "deleteRule": "Regel {pattern} löschen", - "duplicateRule": "Dieses Muster gibt es bereits.", - "blankRule": "Eine Regel braucht ein Muster – zum Entfernen das Papierkorb-Symbol nutzen.", - "customKeys": "Weitere Berechtigungsschlüssel in der Datei", - "customKeyHint": "Kein eingebautes OpenCode-Tool – bleibt unverändert erhalten.", - "keys": { - "bash": "Shell-Befehle ausführen, geprüft am geparsten Befehl", - "edit": "Alle Dateiänderungen: edit, write und patch", - "read": "Dateien lesen, geprüft am Pfad", - "external_directory": "Pfade außerhalb des Projektarbeitsverzeichnisses erreichen", - "task": "Subagenten starten, geprüft am Subagenten-Typ", - "skill": "Skills laden, geprüft am Skill-Namen", - "glob": "Dateien finden, geprüft am Glob-Muster", - "grep": "Dateiinhalte durchsuchen, geprüft am Muster", - "list": "Verzeichnisinhalte auflisten", - "webfetch": "Eine URL abrufen", - "websearch": "Im Web suchen", - "lsp": "LSP-Abfragen ausführen", - "todowrite": "Die To-do-Liste schreiben", - "question": "Dir eine Frage stellen", - "doom_loop": "Löst aus, wenn sich derselbe Aufruf dreimal mit gleicher Eingabe wiederholt" - } - } - }, - "openClaw": { - "gatewayConfig": "Gateway-Konfiguration", - "gatewayDescription": "OpenClaw-Gateway-Verbindung konfigurieren. Unterstützt lokales oder entferntes Gateway.", - "gatewayUrlHint": "Leer lassen, um gateway.remote.url aus der lokalen openclaw-Konfiguration zu verwenden.", - "gatewayTokenPlaceholder": "Gateway-Auth-Token", - "gatewayTokenHint": "Wenn möglich token-file statt Klartext-Token verwenden; über openclaw CLI konfigurieren.", - "sessionKeyHint": "Optional. Gateway-Session-Key angeben; leer lassen für automatische Zuweisung einer isolierten Session." - }, - "hermes": { - "configManagement": "Hermes-Konfiguration", - "configDescription": "Hermes verwaltet seine eigenen Anmeldedaten in ~/.hermes/.env und die Einstellungen in ~/.hermes/config.yaml. Wähle einen Anbieter und lege dann den API-Schlüssel und das Modell fest – codeg schreibt beide Dateien für dich.", - "providerLabel": "Anbieter", - "providerHint": "Der Anbieter legt fest, welche API-Schlüssel-Variable und welchen model.provider Hermes verwendet. OAuth-Anbieter werden über die Terminal-Einrichtung unten konfiguriert.", - "groupApiKey": "Anbieter mit API-Schlüssel", - "groupOauth": "OAuth-Anbieter", - "groupAws": "AWS", - "apiKeyHint": "Wird in ~/.hermes/.env gespeichert. Er wird niemals in den Prozess eingeschleust – Hermes liest ihn aus seiner eigenen Konfiguration.", - "modelName": "Modell", - "oauthHint": "Dieser Anbieter verwendet OAuth. Führe die Einrichtung unten aus, um dich im Terminal zu authentifizieren.", - "awsHint": "Bedrock verwendet deine AWS-Anmeldedaten (Umgebung oder gemeinsame Konfiguration). Lege oben die Modell-ID fest und konfiguriere den AWS-Zugriff in deiner Umgebung.", - "unsupportedProvider": "Dieser Anbieter lässt sich nicht über strukturierte Felder bearbeiten. Verwende den config.yaml-Editor unten oder die Terminal-Einrichtung.", - "setupTitle": "Selbstverwaltete Einrichtung", - "setupHint": "Die interaktive Einrichtung von Hermes benötigt ein Terminal. Starte sie unten oder kopiere den Befehl, um sie selbst auszuführen.", - "runSetup": "Hermes-Einrichtung ausführen", - "configureModel": "Modell konfigurieren", - "openConfigFolder": "~/.hermes öffnen", - "copyCommand": "Befehl kopieren", - "commandCopied": "Befehl in die Zwischenablage kopiert", - "advancedTitle": "Erweitert: config.yaml bearbeiten", - "rawConfigHint": "Bearbeite ~/.hermes/config.yaml direkt. Das Speichern hier überschreibt die Datei wortwörtlich.", - "saveRawConfig": "config.yaml speichern" - }, - "codebuddy": { - "configManagement": "CodeBuddy-Konfiguration", - "configDescription": "CodeBuddy authentifiziert sich mit einem API-Schlüssel. Builds für Festlandchina erfordern zudem die Umgebung „China (internal)“; iOA-Builds verwenden „iOA“. Der internationale Build lässt sie ungesetzt.", - "apiKeyLabel": "API-Schlüssel", - "apiKeyHint": "Wird als CODEBUDDY_API_KEY für diesen Agenten gespeichert. Alternativ kannst du dich mit der CodeBuddy-CLI im Terminal anmelden.", - "apiKeyHintSelfHosted": "Wird als CODEBUDDY_API_KEY für diesen Agenten gespeichert. Verwende den von deiner privaten Bereitstellung ausgestellten Schlüssel.", - "environmentLabel": "Umgebung", - "environmentHint": "Legt CODEBUDDY_INTERNET_ENVIRONMENT fest. Festlandchina muss „China (internal)“ verwenden; der internationale Build lässt es ungesetzt.", - "envOverseas": "International (Standard)", - "envChina": "China (internal)", - "envIoa": "iOA", - "envSelfHosted": "Selbst gehostet (private Bereitstellung)", - "baseUrlLabel": "Bereitstellungs-URL", - "baseUrlPlaceholder": "https://codebuddy.your-company.com", - "baseUrlHint": "Wird als CODEBUDDY_BASE_URL gespeichert und richtet CodeBuddy auf deinen privaten Endpunkt. Bei Selbsthosting bleibt die Netzwerkumgebung (CODEBUDDY_INTERNET_ENVIRONMENT) ungesetzt.", - "baseUrlInvalid": "Gib eine gültige http(s)-URL ein.", - "loginHint": "Kein API-Schlüssel? Führe „codebuddy“ im Terminal aus, um dich stattdessen mit deinem Tencent-Konto anzumelden." - }, - "kimiCode": { - "configManagement": "Kimi-Code-Konfiguration", - "configDescription": "`kimi acp` akzeptiert nur ein gespeichertes Login-Token, daher schreibt codeg einen verwalteten Provider in ~/.kimi-code/config.toml und legt lokal ein Gate-Token an – die Inferenz läuft weiterhin über deinen eigenen Schlüssel.", - "statusUnconfigured": "Noch nicht konfiguriert", - "statusDirty": "Nicht gespeicherte Änderungen", - "summaryLabel": "Aktiv", - "gateReadyApiKey": "API-Schlüssel in config.toml geschrieben", - "gateReadyLogin": "Mit einem Kimi-Konto angemeldet", - "revealConfig": "Im Ordner anzeigen", - "envOverrideWarning": "{keys} ist gesetzt und hat Vorrang vor config.toml. Beim Speichern hier wird die Variable entfernt.", - "authModeLabel": "Authentifizierungsmethode", - "authModeApiKey": "API-Schlüssel", - "authModeLogin": "Kimi-Konto-Anmeldung (Abo)", - "authModeApiKeyHint": "Schreibt einen verwalteten Provider in config.toml und legt das Gate-Token an, damit Sitzungen geöffnet werden können.", - "loginHint": "Führe `kimi login` im Terminal aus, um dich mit einem Kimi-Abo-Konto anzumelden. codeg speichert nichts und nutzt Kimis eigene Anmeldung. Speichern hier entfernt codegs API-Schlüssel-Gate-Token.", - "credentialTitle": "Zugangsdaten", - "interfaceTypeLabel": "Provider-Typ", - "interfaceTypeHint": "Das Provider-Protokoll, das Kimi spricht (`type` in config.toml). Für einen Moonshot-/platform.kimi.com-Schlüssel Kimi / Moonshot wählen.", - "endpointLabel": "Endpunkt", - "endpointCustom": "Benutzerdefiniert (OpenAI-kompatibel)", - "endpointHint": "International = api.moonshot.ai; China (platform.kimi.com-Schlüssel) = api.moonshot.cn. Benutzerdefiniert zeigt auf einen beliebigen OpenAI-kompatiblen Endpunkt.", - "regionInternational": "International (api.moonshot.ai)", - "regionChina": "China (api.moonshot.cn)", - "baseUrlLabel": "Basis-URL", - "baseUrlHint": "Leer lassen, um den Standardwert des Provider-SDK zu verwenden.", - "apiKeyLabel": "API-Schlüssel", - "apiKeyHint": "Wird in ~/.kimi-code/config.toml geschrieben und für die Inferenz verwendet. Von platform.kimi.com oder platform.kimi.ai.", - "vertexProjectLabel": "GCP-Projekt (GOOGLE_CLOUD_PROJECT)", - "vertexLocationLabel": "GCP-Region (GOOGLE_CLOUD_LOCATION)", - "vertexHint": "Vertex AI nutzt Google Application Default Credentials – führe `gcloud auth application-default login` aus (kein API-Schlüssel nötig).", - "modelTitle": "Modell", - "modelLabel": "Modell", - "modelHint": "Die Modell-ID, die in config.toml geschrieben wird. Über „Testen & Modelle laden“ siehst du, worauf dein Schlüssel tatsächlich zugreifen kann.", - "maxContextLabel": "Maximale Kontextgröße", - "maxContextHint": "Vom Kimi-Schema vorgeschrieben: Fehlt der Wert, verwirft Kimi den gesamten Modellblock und jede Anfrage bleibt ohne Antwort. Standard 262144.", - "fetchModels": "Testen & Modelle laden", - "fetchModelsOk": "Schlüssel funktioniert – {count} Modelle verfügbar", - "fetchModelsEmpty": "Schlüssel funktioniert, es wurden aber keine Modelle zurückgegeben", - "fetchModelsFailed": "Test fehlgeschlagen", - "fetchModelsNeedsKey": "Gib zuerst einen API-Schlüssel und einen Endpunkt ein", - "modelNotInList": "Dieses Modell ist nicht in der Liste, auf die dein Schlüssel zugreifen kann – Kimi scheitert mit „Modell nicht gefunden“.", - "reasoningTitle": "Reasoning", - "reasoningEnableLabel": "Aktivieren", - "reasoningDescription": "Kimi zeigt den „Thinking“-Auswähler im Eingabefeld nur, wenn das Modell eine Reasoning-Fähigkeit deklariert – codeg schreibt sie hier. Gilt ab neuen Sitzungen.", - "effortsLabel": "Angebotene Stufen", - "effortsHint": "Diese Stufen erscheinen im „Thinking“-Auswähler. Kimi reicht die Stufe unverändert an den Provider weiter – wähle also Werte, die dein Modell akzeptiert.", - "effortsEmptyHint": "Ohne ausgewählte Stufe bleibt im Eingabefeld nur ein einfacher Off/On-Schalter.", - "effortsCustomPlaceholder": "Weitere Stufe hinzufügen", - "effortsAdd": "Hinzufügen", - "defaultEffortLabel": "Standardstufe", - "defaultEffortAuto": "Kimi entscheiden lassen", - "alwaysThinkingLabel": "Das Modell denkt immer nach – Off-Eintrag aus dem Auswähler entfernen", - "fixErrorsFirst": "Korrigiere zuerst die markierten Felder", - "errorModelRequired": "Modell ist erforderlich", - "errorMaxContextRequired": "Maximale Kontextgröße ist erforderlich", - "errorMaxContextInvalid": "Muss eine positive ganze Zahl sein", - "errorApiKeyRequired": "API-Schlüssel ist erforderlich", - "errorApiKeyInvalid": "Der API-Schlüssel darf keine Zeilenumbrüche enthalten", - "errorBaseUrlRequired": "Basis-URL ist erforderlich", - "errorBaseUrlInvalid": "Muss mit http:// oder https:// beginnen", - "errorVertexProjectRequired": "GCP-Projekt ist erforderlich", - "errorDefaultEffortUnlisted": "Wähle eine der oben ausgewählten Stufen", - "advancedTitle": "Erweitert", - "authTypeLabel": "Ablageort der Zugangsdaten", - "authTypeApiKey": "Inline api_key", - "authTypeEnv": "env-Untertabelle des Providers", - "authTypeHint": "Wo der API-Schlüssel innerhalb von config.toml abgelegt wird.", - "rawEditorLabel": "config.toml direkt bearbeiten", - "rawEditorWarning": "Speichern hier überschreibt die gesamte Datei wortwörtlich und ersetzt die strukturierten Einstellungen oben.", - "rawEditorPlaceholder": "[providers.codeg]\ntype = \"kimi\"\nbase_url = \"https://api.moonshot.cn/v1\"\napi_key = \"sk-...\"" - }, - "authModeOfficialSubscription": "Offizielles Abonnement", - "authModeCustomEndpoint": "Benutzerdefinierter Endpunkt", - "authModeCustomEndpointHint": "API-URL und API-Key manuell für einen benutzerdefinierten Endpunkt konfigurieren.", - "authModeModelProvider": "Modellanbieter", - "modelProvider": "Modellanbieter", - "modelProviderHint": "API-URL, API-Key und Modell eines konfigurierten Modellanbieters verwenden.", - "selectModelProvider": "Modellanbieter auswählen", - "noModelProviderAvailable": "Kein Modellanbieter für diesen Agent konfiguriert. Gehen Sie zu den Modellanbieter-Einstellungen, um einen hinzuzufügen.", - "claude": { - "authMode": "Authentifizierungsmodus", - "officialSubscription": "Offizielles Abonnement", - "officialSubscriptionHint": "Offizielles Anthropic-Abonnement verwenden, kein API-Key erforderlich.", - "mainModel": "Hauptmodell", - "reasoningModel": "Reasoning-Modell (thinking)", - "haikuDefaultModel": "Standard-Haiku-Modell", - "sonnetDefaultModel": "Standard-Sonnet-Modell", - "opusDefaultModel": "Standard-Opus-Modell", - "customModelOption": "Benutzerdefinierte Modell-ID", - "customModelOptionName": "Name des benutzerdefinierten Modells", - "customModelOptionDescription": "Beschreibung des benutzerdefinierten Modells", - "customModelOptionHint": "Fügt der Modellauswahl von Claude einen einzelnen benutzerdefinierten Eintrag hinzu (z. B. ein Modell hinter einem benutzerdefinierten Gateway/Proxy). Name und Beschreibung sind optionale Anzeigeangaben.", - "effortLevel": "Reasoning-Stufe", - "effortLevelDefault": "Standardstufe", - "effortLevel_low": "Niedrig", - "effortLevel_medium": "Mittel", - "effortLevel_high": "Hoch", - "effortLevel_xhigh": "Sehr Hoch", - "sendAttributionHeader": "Attributions-/Abrechnungskennung an die API senden", - "sendAttributionHeaderAria": "Attributions-/Abrechnungskennung von Claude Code an die API senden", - "disableNonessentialTraffic": "Telemetrie oder überflüssige Netzwerkanfragen deaktivieren", - "disableNonessentialTrafficAria": "Telemetrie oder überflüssige Netzwerkanfragen von Claude Code deaktivieren" - }, - "dialogs": { - "confirmDeleteProvider": "Provider {providerId} löschen?", - "confirmDeleteProviderDescription": "OpenCode-Konfiguration und auth JSON werden zusammen aktualisiert. Diese Aktion kann nicht rückgängig gemacht werden.", - "confirmUninstall": "{name} deinstallieren?", - "confirmUninstallDescription": "Dadurch wird die lokal installierte Version entfernt. Eine Neuinstallation ist später möglich.", - "customInstallTitle": "{name} benutzerdefiniert installieren", - "customInstallDescription": "Geben Sie die zu installierende Version ein. Dies installiert neu und ersetzt die aktuell installierte Version.", - "customInstallVersionLabel": "Versionsnummer", - "customInstallInvalid": "Geben Sie eine gültige Versionsnummer ein, z. B. 1.2.3.", - "customInstallSubmit": "Installieren" - }, - "errors": { - "windowsFileLocked": "Die Dateien von {name} werden von einer laufenden Sitzung verwendet, daher kann Windows sie nicht ersetzen. Schließe alle {name}-Sitzungen und versuche es erneut.", - "nativeJsonMustBeObject": "Native JSON-Konfiguration muss ein Objekt sein", - "nativeJsonInvalid": "Formatfehler in nativer JSON-Konfiguration: {message}", - "openCodeAuthMustBeObject": "OpenCode auth.json muss ein JSON-Objekt sein", - "openCodeAuthInvalid": "Formatfehler in OpenCode auth.json: {message}", - "authMustBeObject": "auth.json muss ein JSON-Objekt sein", - "authInvalid": "Formatfehler in auth.json: {message}", - "providerIdPattern": "Provider-ID unterstützt nur Buchstaben, Zahlen, Unterstrich, Punkt und Bindestrich", - "providerExists": "Provider {providerId} existiert bereits", - "modelIdPattern": "Model-ID unterstützt nur Buchstaben, Zahlen, Unterstrich, Punkt, Doppelpunkt und Bindestrich", - "modelExists": "Model {modelId} existiert bereits" - }, - "warnings": { - "nativeJsonRecoveredStructured": "Native JSON-Konfiguration ist ungültig; auf strukturierte Konfiguration zurückgesetzt", - "nativeJsonRecoveredOpenCode": "Native JSON-Konfiguration ist ungültig; auf OpenCode-strukturierte Konfiguration zurückgesetzt", - "openCodeAuthRecovered": "OpenCode auth.json ist ungültig; auf Standardkonfiguration zurückgesetzt", - "authRecoveredStructured": "auth.json ist ungültig; auf strukturierte Konfiguration zurückgesetzt" - }, - "toasts": { - "agentActionCompleted": "{name} {action} abgeschlossen", - "agentActionFailed": "{name} {action} fehlgeschlagen", - "localVersion": "Lokale Version: {version}", - "installCompletedVersionLater": "Installation abgeschlossen, Version wird bei der nächsten Prüfung aktualisiert", - "uninstallCompleted": "Deinstallation von {name} abgeschlossen", - "uninstallFailed": "Deinstallation von {name} fehlgeschlagen", - "localVersionRemoved": "Lokale Version entfernt", - "saveAgentOrderFailed": "Speichern der Agent-Reihenfolge fehlgeschlagen", - "saveAgentSwitchFailed": "Speichern des Agent-Schalters fehlgeschlagen", - "saveEnvFailed": "Speichern der Umgebungsvariablen fehlgeschlagen", - "grokSaved": "Grok-Konfiguration gespeichert", - "saveGrokNativeFailed": "Grok-Nativkonfiguration konnte nicht gespeichert werden", - "saveGrokApiKeyFailed": "Einstellungen gespeichert, aber der API-Schlüssel konnte nicht gespeichert werden", - "cursorSaved": "Cursor-Konfiguration gespeichert", - "saveCursorConfigFailed": "Cursor-Konfiguration konnte nicht gespeichert werden", - "codexSaved": "Codex-Konfiguration gespeichert", - "saveCodexNativeFailed": "Speichern der nativen Codex-Konfiguration fehlgeschlagen", - "geminiSaved": "Gemini-Konfiguration gespeichert", - "saveGeminiFailed": "Speichern der Gemini-Konfiguration fehlgeschlagen", - "providerDeleted": "Provider {providerId} gelöscht", - "providerDeleteFailed": "Löschen von Provider {providerId} fehlgeschlagen", - "providerSaved": "Provider {providerId} gespeichert", - "saveProviderFailed": "Speichern von Provider {providerId} fehlgeschlagen", - "openCodeConfigSynced": "OpenCode-Konfiguration und auth JSON wurden synchronisiert.", - "openCodeSaved": "OpenCode-Konfiguration gespeichert", - "saveOpenCodeFailed": "Speichern der OpenCode-Konfiguration fehlgeschlagen", - "openClawSaved": "OpenClaw-Konfiguration gespeichert", - "saveOpenClawFailed": "Speichern der OpenClaw-Konfiguration fehlgeschlagen", - "configSaved": "Konfiguration gespeichert", - "configSavedHint": "Bestehende Sitzungen müssen neu geöffnet werden, damit die Änderungen wirksam werden", - "saveConfigManagementFailed": "Speichern der Konfigurationsverwaltung fehlgeschlagen", - "clineSaved": "Cline-Konfiguration gespeichert", - "saveClineFailed": "Cline-Konfiguration konnte nicht gespeichert werden", - "hermesSaved": "Hermes-Konfiguration gespeichert", - "saveHermesFailed": "Hermes-Konfiguration konnte nicht gespeichert werden", - "codeBuddySaved": "CodeBuddy-Konfiguration gespeichert", - "saveCodeBuddyFailed": "CodeBuddy-Konfiguration konnte nicht gespeichert werden", - "kimiCodeSaved": "Kimi-Code-Konfiguration gespeichert", - "saveKimiCodeFailed": "Speichern der Kimi-Code-Konfiguration fehlgeschlagen", - "deepseekSaved": "DeepSeek-Konfiguration gespeichert", - "saveDeepSeekFailed": "DeepSeek-Konfiguration konnte nicht gespeichert werden", - "modelProviderRequired": "Bitte wählen Sie vor dem Speichern einen Modellanbieter aus.", - "affectedRunningSessions": "{count, plural, one {# laufende Sitzung muss zum Anwenden neu verbunden werden} other {# laufende Sitzungen müssen zum Anwenden neu verbunden werden}}", - "providerConnected": "{providerId} verbunden", - "connectFailed": "Verbinden von {providerId} fehlgeschlagen", - "providerDisconnected": "{providerId} getrennt", - "disconnectFailed": "Trennen von {providerId} fehlgeschlagen", - "catalogRefreshed": "Katalog aktualisiert – {count} Provider", - "catalogRefreshFailed": "Aktualisieren des Katalogs fehlgeschlagen", - "piSaved": "Pi-Konfiguration gespeichert", - "savePiFailed": "Pi-Konfiguration konnte nicht gespeichert werden", - "piRuntimeSaved": "Pi-Laufzeit gespeichert", - "savePiRuntimeFailed": "Pi-Laufzeit konnte nicht gespeichert werden", - "piBinaryInstalled": "pi installiert", - "piBinaryInstallFailed": "pi-Installation fehlgeschlagen", - "piBinaryUninstalled": "pi deinstalliert", - "piBinaryUninstallFailed": "pi-Deinstallation fehlgeschlagen", - "savePiTrustFailed": "Speichern des Arbeitsbereich-Vertrauens fehlgeschlagen" - }, - "version": { - "statusLabel": "Versionsstatus", - "notInstalled": "Nicht installiert", - "remoteLocal": "Remote: {remoteVersion} · Lokal: {localVersion}", - "localOnly": "Lokal: {localVersion}", - "localInstalled": "{versionText}. Installiert.", - "platformUnsupported": "{versionText}. Aktuelle Plattform unterstützt diesen Agenten nicht.", - "uvxNotReady": "{versionText}. Die uv-Laufzeit ist nicht installiert – installieren Sie sie über die uv-Prüfung unten, um diesen Agenten zu verwenden.", - "clickInstall": "{versionText}. Rechts auf Installieren klicken.", - "localUnrecognized": "{versionText}. Lokale Version ist nicht vergleichbar; zum Überschreiben bitte Upgrade versuchen.", - "upgradeAvailable": "{versionText}. Upgrade verfügbar.", - "remoteUnavailable": "{versionText}. Remote-Version ist derzeit nicht verfügbar.", - "latest": "{versionText}. Bereits aktuell." - }, - "adapter": { - "label": "ACP-Adapter", - "badge": "ACP-Adapter", - "badgeHint": "Für diesen Agenten installiert Codeg ein ACP-Adapterpaket, nicht die Hersteller-CLI. Beide sind unabhängig und teilen sich dieselbe Konfiguration.", - "learnMore": "Mehr erfahren", - "missingWithNative": "Deine eigene {nativeLabel} wurde unter {nativePath} gefunden. Codeg spricht mit Agenten über ACP, und diese CLI beherrscht kein ACP — deshalb braucht Codeg ein separates Adapterpaket, {adapterPackage}, gepflegt vom Agent-Client-Protocol-Projekt (ursprünglich Zed). Es bringt seine eigene Laufzeit mit, verändert oder ersetzt deinen Befehl {nativeCmd} nie und liest dasselbe {configDir} — Anmeldung und Einstellungen bleiben erhalten. Unten installieren.", - "missing": "Codeg spricht mit Agenten über ACP, und die {nativeLabel} beherrscht kein ACP — deshalb braucht Codeg ein separates Adapterpaket, {adapterPackage}, gepflegt vom Agent-Client-Protocol-Projekt (ursprünglich Zed). Es bringt seine eigene Laufzeit mit, die CLI {nativeCmd} ist also nicht Voraussetzung; hast du sie bereits, koexistieren beide und teilen sich Anmeldung und Einstellungen in {configDir}. Unten installieren.", - "readyWithNative": "Der Adapter {adapterCmd} ist installiert — ihn startet Codeg, nicht dein eigenes {nativeCmd} unter {nativePath}. Es sind getrennte Pakete, die koexistieren, und beide lesen {configDir}, Anmeldung und Einstellungen sind also gemeinsam.", - "ready": "Der Adapter {adapterCmd} ist installiert — ihn startet Codeg. Er bringt seine eigene Laufzeit mit, die {nativeLabel} wird also nicht benötigt; installierst du sie später, koexistieren beide und teilen sich {configDir}." - }, - "cline": { - "configDescription": "Konfigurieren Sie den Cline API-Anbieter und die Anmeldedaten. Einstellungen werden in ~/.cline/data/ gespeichert." - }, - "opencodePlugins": { - "title": "OpenCode-Plugins", - "declared": "Deklarierte Plugins", - "noPlugins": "Keine Plugins in opencode.json deklariert", - "status": { - "installed": "Installiert", - "missing": "Nicht installiert" - }, - "installAll": "Alle fehlenden installieren", - "pinVersions": "@latest-Versionen fixieren", - "install": "Installieren", - "uninstall": "Deinstallieren", - "refresh": "Aktualisieren", - "success": "Alle Plugins wurden erfolgreich installiert", - "failed": "Plugin-Vorgang fehlgeschlagen" - }, - "pi": { - "configManagement": "Pi-Konfiguration", - "configDescription": "Pi authentifiziert sich über den API-Schlüssel deines Modellanbieters. Der Schlüssel wird in ~/.pi/agent/auth.json und die Modellauswahl in settings.json geschrieben.", - "providerLabel": "Anbieter", - "modelLabel": "Modell", - "thinkingLabel": "Denken", - "thinking": { - "off": "Aus", - "low": "Niedrig", - "medium": "Mittel", - "high": "Hoch", - "minimal": "Minimal", - "xhigh": "Sehr hoch" - }, - "apiKeyLabel": "API-Schlüssel", - "apiKeyHint": "Wird in ~/.pi/agent/auth.json für den ausgewählten Anbieter gespeichert.", - "apiKeySetPlaceholder": "•••••• (gespeichert – leer lassen zum Beibehalten)", - "saveConfig": "Pi-Konfiguration speichern", - "providerModelRequired": "Anbieter und Modell sind erforderlich", - "runtimeTitle": "Laufzeit", - "runtimeDescription": "Wähle, welches pi-Binary läuft. Standard verwenden oder auf deinen eigenen pi-Build verweisen.", - "modeDefault": "Standard-pi", - "modeDefaultHint": "Verwendet den integrierten pi-acp-Adapter mit dem pi in deinem PATH. pi installieren: npm install -g @earendil-works/pi-coding-agent", - "modeCustom": "Eigenes pi", - "modeCustomHint": "Führe deinen eigenen pi-Build, deine Installation oder einen Wrapper aus.", - "commandLabel": "pi-Befehl oder -Pfad", - "commandHint": "Ein absoluter Pfad, ein Befehlsname im PATH oder ein Wrapper-Skript (z. B. ./pi-test.sh eines Monorepos).", - "commandNotFound": "Befehl nicht gefunden", - "validate": "Prüfen", - "advanced": "Erweitert", - "configDirLabel": "Konfigurationsverzeichnis (PI_CODING_AGENT_DIR)", - "sessionDirLabel": "Sitzungsverzeichnis (PI_CODING_AGENT_SESSION_DIR)", - "flagsHint": "pi-acp leitet eigene pi-Flags (--approve, -e, …) nicht weiter – umhülle pi mit einem Skript und verweise den Befehl darauf.", - "customIncomplete": "Gib einen pi-Befehl zum Speichern ein", - "saveRuntime": "Laufzeit speichern", - "providerPlaceholder": "Anbieter auswählen", - "customProvider": "Eigener Anbieter…", - "providerIdLabel": "Anbieter-ID", - "apiProtocolLabel": "API-Protokoll", - "baseUrlLabel": "API-Endpunkt (Base URL)", - "customProviderHint": "Definiert einen Anbieter in ~/.pi/agent/models.json an Ihrem Endpunkt. Die meisten selbst gehosteten oder Proxy-Server nutzen openai-completions.", - "baseUrlRequired": "API-Endpunkt (Base URL) ist erforderlich", - "binaryTitle": "pi-Binärdatei (pi-coding-agent)", - "binaryDescription": "pi-acp führt diese pi-Binärdatei aus. Hier installieren oder pi-acp unten auf einen eigenen Build verweisen.", - "binaryInstalled": "Installiert", - "binaryMissing": "Nicht installiert", - "binaryChecking": "Wird geprüft…", - "installBinary": "pi installieren", - "installing": "Wird installiert…", - "recheck": "Erneut prüfen", - "configDirSkillsNote": "Mit einem benutzerdefinierten Konfigurationsverzeichnis gelten die in den Einstellungen verwalteten Skills, Experten und Office-Tools nicht für dieses pi — verwalte seine Skills direkt in diesem Ordner.", - "projectTrustTitle": "Projektvertrauen", - "projectTrustDescription": "Ordner, aus denen pi Projektdateien laden darf. In einem vertrauten Ordner führt das Repository seine .pi/extensions beim Start von pi aus. Die Entscheidung gilt für alle enthaltenen Ordner und auch, wenn du pi im Terminal startest.", - "projectTrustLoading": "Wird geladen…", - "projectTrustEmpty": "Noch keine Ordner entschieden.", - "projectTrustTrusted": "Vertraut", - "projectTrustDenied": "Nicht vertraut", - "projectTrustRevoke": "Widerrufen", - "reasoningTitle": "Reasoning", - "reasoningEnableLabel": "Aktivieren", - "reasoningDescription": "pi sendet einen Reasoning-Aufwand nur für ein Modell, das ihn deklariert — bei einem nicht deklarierten Modell werden alle Stufen auf Off begrenzt, sodass die Auswahl im Eingabefeld sofort zurückspringt. Wird in den Eintrag dieses Modells in models.json geschrieben.", - "levelsLabel": "Verfügbare Stufen", - "levelsHint": "Diese werden zu den Einträgen der Reasoning-Auswahl im Eingabefeld. Wähle die, die dein Endpunkt akzeptiert; jede hier nicht gelistete Stufe lehnt pi ab.", - "levelsEmptyError": "Wähle mindestens eine Stufe — ohne eine fällt pi auf Off zurück.", - "wireValuesTitle": "Erweitert: an den Anbieter gesendete Werte", - "wireValuesHint": "Leer lassen, um den Stufennamen unverändert zu senden. Setze einen Wert, wenn dein Endpunkt etwas anderes erwartet — Google-artige Backends erwarten LOW / HIGH.", - "defaultLevelUnlisted": "Diese Stufe steht nicht in der Liste oben — pi würde sie begrenzen." - }, - "addCustomAgent": "Eigenen Agenten hinzufügen", - "addCustomAgentHint": "Registriere jeden ACP-kompatiblen Agenten. Wähle einen aus der öffentlichen ACP-Registry oder füge seine Registry-Informationen ein.", - "customAgentFromRegistry": "ACP-Registry", - "customAgentManual": "Manuell", - "customAgentSearchPlaceholder": "Agenten suchen…", - "customAgentLoadingCatalog": "ACP-Registry wird geladen…", - "customAgentRetry": "Erneut versuchen", - "customAgentNoResults": "Keine passenden Agenten", - "customAgentAdd": "Hinzufügen", - "customAgentAlreadyAdded": "Hinzugefügt", - "customAgentUnsupportedPlatform": "Kein Build für diese Plattform verfügbar", - "customAgentAdded": "{name} hinzugefügt", - "customAgentIdLabel": "Registry-ID", - "customAgentNameLabel": "Anzeigename", - "customAgentVersionLabel": "Version", - "customAgentSpecLabel": "Distribution (JSON)", - "customAgentSpecHint": "Gleiche Form wie das distribution-Objekt der ACP-Registry: Kanäle npx, uvx und binary, oder ein kompletter Registry-Eintrag zum Einfügen. Bei npx/uvx ist cmd der vom Paket installierte Befehl — bei Weglassen aus dem Paketnamen abgeleitet, bei Abweichung also angeben. binary ist nach Plattformschlüssel gegliedert (diese Maschine: {platform}); cmd ist der Startpfad im Archiv, sha256 prüft optional den Download.", - "customAgentTemplateLabel": "Vorlagen", - "customAgentKindLabel": "Starten über", - "customAgentInvalidJson": "Kein gültiges JSON", - "customAgentNoDistribution": "Keine npx-, uvx- oder binary-Distribution gefunden", - "customAgentCancel": "Abbrechen", - "customAgentSave": "Agent hinzufügen", - "customAgentSaveChanges": "Änderungen speichern", - "customAgentEdit": "Agent bearbeiten", - "customAgentEditHint": "Name, Icon, Distribution und Skills-Deklarationen ändern. Die Agent-ID kann nicht geändert werden.", - "customAgentEditNotFound": "Benutzerdefinierter Agent {id} wurde nicht gefunden", - "customAgentSaved": "{name} gespeichert", - "customAgentVersionProbeLabel": "Versionsabfrage-Befehl (optional)", - "customAgentVersionProbeHint": "Befehl, der die lokal installierte Version ausgibt. Bleibt er leer, führt codeg den Agent-Befehl mit --version aus.", - "customAgentRemove": "Agent entfernen", - "customAgentRemoveHint": "Löscht die Agent-Definition. Bestehende Unterhaltungen behalten ihren Verlauf; der Agent lässt sich nur nicht mehr starten.", - "customAgentIconLabel": "Symbol (optional)", - "customAgentIconUpload": "Hochladen", - "customAgentIconReplace": "Ersetzen", - "customAgentIconClear": "Symbol entfernen", - "customAgentIconHint": "Wird beim Agenten gespeichert und funktioniert daher offline. Ohne Symbol wird ein farbiger Anfangsbuchstabe verwendet.", - "customAgentSkillsLabel": "Skills (gemeinsames .agents/skills)", - "customAgentSkillsHint": "Erklärt, dass dieser Agent den gemeinsamen .agents/skills-Speicher liest (globale und Projekt-Verzeichnisse), und nimmt ihn in alle Skill-Matrizen auf. Dort verknüpfte Skills sind für alle Agenten sichtbar, die diesen Speicher lesen.", - "customAgentSkillsDirLabel": "Dediziertes Skills-Verzeichnis", - "customAgentSkillsDirHint": "Absoluter Pfad des Verzeichnisses, aus dem dieser Agent Skills lädt — sein eigener Speicher, zusätzlich zum geteilten oder an dessen Stelle. ~ wird zum Home-Verzeichnis erweitert; verknüpfte Skills landen zuerst hier.", - "customAgentMcpLabel": "MCP-Unterstützung", - "customAgentMcpHint": "Übergibt den in codeg integrierten MCP-Begleitprozess beim Sitzungsstart an diesen Agenten — der Kanal hinter Delegation, Live-Feedback und Aufgaben-Tools. Für einen Agenten, der MCP-Server ablehnt und deshalb keine Verbindung aufbaut, ausschalten; die Änderung gilt ab der nächsten Verbindung.", - "customAgentIconNotAnImage": "Bitte eine Bilddatei auswählen.", - "customAgentIconTooLarge": "Das Symbol muss kleiner als {limit} KB sein.", - "customAgentIconReadFailed": "Dieses Bild konnte nicht gelesen werden.", - "customAgentRemoveConfirm": "{name} entfernen? Bestehende Unterhaltungen bleiben erhalten, der Agent lässt sich aber nicht mehr starten.", - "customAgentRemoveWithData": "Auch den aufgezeichneten Gesprächsverlauf löschen", - "customAgentRemoved": "{name} entfernt", - "customAgentBadge": "Eigen", - "customAgentNotLaunchable": "Dieser Agent kann hier nicht gestartet werden: {reason}" - }, - "SettingsPages": { - "agentsLoading": "Agent-Einstellungen werden geladen...", - "skillPacksLoading": "Skill-Pakete werden geladen…" - }, - "GeneralSettings": { - "loading": "Wird geladen...", - "sectionTitle": "Allgemein", - "sectionDescription": "Zentrale Einstellungen für das Standardterminal, die Rendering-Beschleunigung und die Multi-Agent-Delegation.", - "terminalTitle": "Standardterminal", - "terminalDescription": "Wählen Sie die Shell, die beim Öffnen neuer Terminal-Tabs über die Terminalleiste oder den Dateibaum verwendet wird. Agenten nutzen sie ebenfalls, wenn sie codeg um die Ausführung einer vollständigen Befehlszeile bitten.", - "terminalSystemDefault": "Systemstandard", - "terminalPowerShell7": "PowerShell 7 (pwsh)", - "terminalWindowsPowerShell": "Windows PowerShell", - "terminalCmd": "Eingabeaufforderung (cmd)", - "terminalSaveFailed": "Speichern der Terminaleinstellungen fehlgeschlagen: {message}", - "terminalShellCustom": "Benutzerdefinierter Pfad", - "terminalShellCustomPath": "Shell-Pfad", - "terminalShellCustomPlaceholder": "/usr/local/bin/fish", - "terminalShellCustomSave": "Speichern", - "terminalShellCustomHint": "Absoluten Pfad oder einen über PATH auflösbaren Namen angeben.", - "terminalShellNotInstalled": "nicht installiert", - "terminalShellNotFoundWarning": "Dieser Pfad existiert auf diesem Host nicht.", - "terminalCurrentShell": "Aktuell verwendet: {path}", - "renderingDescription": "Deaktivieren Sie die Hardwarebeschleunigung, wenn die App einen schwarzen Bildschirm oder Render-Fehler zeigt (häufig bei bestimmten AMD-GPUs oder integrierten Intel-GPUs). Wirkt sich nur auf die Windows-Desktop-Version aus.", - "disableHardwareAcceleration": "Hardwarebeschleunigung deaktivieren", - "renderingSaveFailed": "Render-Einstellungen konnten nicht gespeichert werden: {message}", - "restartRequired": "Gespeichert. Starten Sie die App neu, damit die Änderung wirksam wird.", - "restartNow": "Jetzt neu starten", - "restartFailed": "Neustart fehlgeschlagen: {message}", - "loadFailed": "Laden fehlgeschlagen: {message}" - }, - "LoginPage": { - "documentTitle": "Anmelden - codeg", - "brand": "Codeg", - "subtitle": "Gib dein Zugriffstoken ein, um dich mit der Desktop-App zu verbinden", - "tokenPlaceholder": "Zugriffstoken", - "connect": "Verbinden", - "connecting": "Verbinde...", - "helpText": "Das Token findest du in der Desktop-App unter Einstellungen → Webdienst", - "invalidToken": "Ungültiges Token. Bitte überprüfe es und versuche es erneut.", - "connectionFailed": "Verbindung fehlgeschlagen (HTTP {status})", - "networkError": "Verbindung zum Server nicht möglich" - }, - "CommitPage": { - "title": "Einchecken", - "invalidFolderId": "Ungültige Ordner-ID", - "loadingRepo": "Repository wird geladen..." - }, - "MergePage": { - "title": "Konflikte lösen", - "invalidFolderId": "Ungültige Ordner-ID", - "loadingRepo": "Repository wird geladen...", - "localVersion": "Lokal (Unsere)", - "result": "Ergebnis", - "remoteVersion": "Remote (Deren)", - "acceptLocal": "Lokal übernehmen", - "acceptRemote": "Remote übernehmen", - "markResolved": "Als gelöst markieren", - "abortMerge": "Abbrechen", - "completeMerge": "Merge abschließen", - "unresolvedConflicts": "Es gibt noch ungelöste Konfliktmarkierungen in dieser Datei", - "fileResolved": "Datei erfolgreich gelöst", - "allResolved": "Alle Konflikte gelöst", - "conflictFiles": "Konfliktdateien", - "loadingFile": "Datei wird geladen...", - "preparingMerge": "Merge wird vorbereitet...", - "selectFile": "Datei zum Lösen auswählen", - "noConflicts": "Keine Konfliktdateien", - "skipFile": "Überspringen", - "abortSuccess": "Vorgang abgebrochen", - "applyAllNonConflicting": "Alle konfliktfreien Änderungen anwenden", - "applyLeftNonConflicting": "Lokal anwenden", - "applyRightNonConflicting": "Remote anwenden" - }, - "ImportSessions": { - "title": "Lokale Sitzungen importieren", - "scanningTitle": "Lokale Agentensitzungen werden gescannt…", - "scanningHint": "Die lokalen Sitzungsspeicher der Agenten werden durchsucht. Bei großen Verläufen kann das etwas dauern. Bereits importierte Sitzungen werden dabei aktualisiert.", - "scanFailed": "Scan fehlgeschlagen", - "retry": "Erneut versuchen", - "rescan": "Neu scannen", - "empty": "Keine lokalen Sitzungen gefunden", - "emptyHint": "Auf diesem Rechner wurden keine Sitzungsspeicher von Agenten gefunden.", - "noMatches": "Keine Sitzungen entsprechen den aktuellen Filtern", - "searchPlaceholder": "Titel oder Pfad suchen…", - "allAgents": "Alle Agenten", - "onlyImportable": "Nur importierbare", - "selectAll": "Alle auswählen", - "clearSelection": "Leeren", - "expandAll": "Alle ausklappen", - "collapseAll": "Alle einklappen", - "summaryCounts": "{total} Sitzungen · {importable} importierbar · {folders} Ordner", - "noFolderSkipped": "{count} ohne Projektordner übersprungen", - "folderNew": "Neu", - "folderCounts": "{importable}/{total} importierbar", - "toggleFolderAria": "Alle importierbaren Sitzungen in {name} auswählen", - "toggleSessionAria": "Sitzung {title} auswählen", - "statusImported": "Importiert", - "statusDeleted": "Gelöscht", - "untitled": "Unbenannte Sitzung", - "messageCount": "{count} Nachrichten", - "selectedCount": "{count} ausgewählt", - "importSelected": "Auswahl importieren", - "importing": "Importiere…", - "close": "Schließen", - "doneTitle": "Import abgeschlossen", - "doneImported": "Importiert", - "doneUpdated": "Aktualisiert", - "doneSkipped": "Übersprungen", - "doneCreatedFolders": "Ordner erstellt", - "doneNotFound": "Nicht gefunden", - "doneFailed": "Fehlgeschlagen", - "continueImport": "Weiter importieren", - "toasts": { - "importFailed": "Import fehlgeschlagen: {message}" - } - }, - "Folder": { - "workspaceStatus": { - "degradedTitle": "Live-Aktualisierungen nicht verfügbar", - "degradedHint": "Beobachter konnte nicht gestartet werden (z. B. Berechtigung verweigert). Aktualisiere manuell, um Änderungen zu sehen.", - "retry": "Wiederholen", - "retrying": "Wird wiederholt..." - }, - "common": { - "all": "Alle", - "cancel": "Abbrechen", - "close": "Schließen", - "closeOthers": "Andere schließen", - "closeAll": "Alle schließen", - "confirm": "Bestätigen", - "save": "Speichern", - "delete": "Löschen", - "rename": "Umbenennen", - "loading": "Wird geladen...", - "refresh": "Aktualisieren", - "refreshing": "Aktualisierung...", - "create": "Erstellen", - "createAndSwitch": "Erstellen und wechseln", - "openFile": "Datei öffnen", - "viewDiff": "Diff anzeigen", - "push": "Pushen..." - }, - "statusLabels": { - "in_progress": "In Bearbeitung", - "pending_review": "Prüfung", - "completed": "Abgeschlossen", - "cancelled": "Abgebrochen" - }, - "sidebar": { - "title": "Konversationen", - "locateActiveConversation": "Aktive Konversation finden", - "expandAllGroups": "Alle Gruppen erweitern", - "collapseAllGroups": "Alle Gruppen einklappen", - "newConversation": "Neue Konversation", - "newConversationShort": "Neu", - "newChat": "Neue Konversation", - "search": "Suchen", - "noConversationsFound": "Keine Konversationen gefunden.", - "importLocalSessions": "Lokale Sitzungen importieren", - "importing": "Importiere...", - "error": "Fehler: {message}", - "completeAllSessions": "Alle Sitzungen abschließen", - "completeAllReviewTitle": "Alle Review-Sitzungen abschließen?", - "completeAllReviewDescription": "Dadurch werden alle {count, plural, one {# Sitzung} other {# Sitzungen}} im Review als abgeschlossen markiert.", - "completing": "Abschließen...", - "toasts": { - "importedSessions": "{imported, plural, one {# Sitzung} other {# Sitzungen}} importiert, {skipped} übersprungen", - "importedAndUpdated": "{imported, plural, one {# Sitzung} other {# Sitzungen}} importiert, {updated, plural, one {# Titel} other {# Titel}} aktualisiert, {skipped} übersprungen", - "updatedTitles": "{updated, plural, one {# Titel} other {# Titel}} aktualisiert, {skipped} übersprungen", - "noNewSessionsFound": "Keine neuen Sitzungen gefunden ({skipped} übersprungen)", - "importFailed": "Import fehlgeschlagen: {message}", - "reviewCompleted": "{count, plural, one {# Review-Sitzung} other {# Review-Sitzungen}} als abgeschlossen markiert", - "completeReviewFailed": "Review-Sitzungen konnten nicht abgeschlossen werden: {message}", - "folderOpened": "Ordner {name} geöffnet", - "folderRemoved": "Ordner {name} entfernt", - "openFolderFailed": "Ordner konnte nicht geöffnet werden", - "removeFolderFailed": "Ordner konnte nicht entfernt werden: {message}", - "reorderFoldersFailed": "Ordner konnten nicht neu sortiert werden: {message}", - "changeFolderColorFailed": "Farbe konnte nicht geändert werden: {message}", - "setFolderAliasFailed": "Alias konnte nicht festgelegt werden: {message}", - "changeFolderDefaultAgentFailed": "Standard-Agent konnte nicht gesetzt werden: {message}" - }, - "statsLabel": "{folders} Ordner · {convos} Konversationen", - "reorderHandle": "Zum Neuordnen ziehen", - "openFolder": "Ordner öffnen", - "searchPlaceholder": "Konversationen suchen...", - "viewOptions": "Anzeigeoptionen", - "showCompleted": "Abgeschlossene Konversationen anzeigen", - "showWorktrees": "Worktree-Ordner anzeigen", - "showRecent": "Gruppe „Zuletzt“ anzeigen", - "moreOptions": "Weitere Optionen", - "sortBy": "Sortieren nach", - "sortByCreatedAt": "Erstellungszeit", - "sortByUpdatedAt": "Aktualisierungszeit", - "sectionOrder": "Abschnittsreihenfolge", - "sectionOrderMoveUp": "Nach oben", - "sectionOrderMoveDown": "Nach unten", - "sectionOrderItemLabel": "{name} — Position {position} von {total}", - "statusRunningBadge": "Läuft", - "runningCountBadge": "{count, plural, one {# laufende Sitzung} other {# laufende Sitzungen}}", - "statusCancelledBadge": "Abgebrochen", - "worktreeRemovedBadge": "Quell-Worktree entfernt", - "conversationCountUnit": "{count, plural, one {# Konversation} other {# Konversationen}}", - "emptyFolderHint": "Keine Konversationen", - "noMatchingConversations": "Keine passenden Konversationen", - "noUnfinishedConversations": "Keine offenen Konversationen. Aktiviere \"Abgeschlossene anzeigen\" im Menü oben rechts.", - "removeFolderConfirmTitle": "Ordner aus Arbeitsbereich entfernen?", - "removeFolderConfirmDescription": "\"{name}\" aus dem Arbeitsbereich entfernen? Zugehörige Tabs und Terminals werden geschlossen.", - "folderHeaderMenu": { - "manageConversations": "Konversationen verwalten…", - "manageLinks": "Verknüpfte Ordner", - "changeColor": "Farbe ändern", - "useThemeColor": "App-Design verwenden", - "setDefaultAgent": "Standard-Agent festlegen", - "defaultAgentNone": "Kein Standard (global verwenden)", - "agentUnavailableSuffix": "(nicht verfügbar)", - "loadingAgents": "Agenten werden geladen…", - "setAlias": "Alias festlegen…", - "setAliasTitle": "Ordner-Alias festlegen", - "setAliasPlaceholder": "Alias eingeben (zum Entfernen leer lassen)", - "setAliasSave": "Speichern", - "setAliasCancel": "Abbrechen", - "removeFromWorkspace": "Aus Arbeitsbereich entfernen" - }, - "manageConversations": { - "title": "Konversationen verwalten", - "searchPlaceholder": "Nach Titel suchen…", - "agentFilterAll": "Alle Agenten", - "statusFilterAll": "Alle Status", - "folderFilterAll": "Alle Ordner", - "branchFilterAll": "Alle Branches", - "branchNone": "Kein Branch", - "branchSearchPlaceholder": "Branches suchen…", - "noMatchingBranches": "Keine passenden Branches", - "selectAllVisible": "Alle auswählen", - "deselectAll": "Auswahl aufheben", - "selectedCount": "{count} ausgewählt", - "matchedCount": "{count} Treffer", - "untitledConversation": "Unbenannte Konversation", - "setStatus": "Status setzen…", - "deleteSelected": "Löschen", - "noConversations": "Keine Konversationen in diesem Ordner.", - "noConversationsWorkspace": "Keine Konversationen im Arbeitsbereich.", - "noMatchingConversations": "Keine Konversationen entsprechen den Filtern.", - "confirmDeleteTitle": "{count} Konversation(en) löschen?", - "confirmDeleteDescription": "Diese Aktion kann nicht rückgängig gemacht werden.", - "toastDeleted": "{count} Konversation(en) gelöscht", - "toastStatusUpdated": "Status von {count} Konversation(en) aktualisiert", - "toastOpFailed": "Aktion fehlgeschlagen: {message}" - }, - "sectionPinned": "Angeheftet", - "sectionFolders": "Ordner", - "sectionChats": "Chat", - "sectionRecent": "Zuletzt", - "noChats": "Keine Chats", - "noRecent": "Keine kürzlichen Konversationen", - "showMoreRecent": "Mehr anzeigen ({count})", - "noFolders": "Keine Ordner geöffnet", - "newChatAction": "Neuer Chat", - "automations": "Automatisierungen", - "tasks": "To-dos", - "loadingSubsessions": "Unterkonversationen werden geladen…" - }, - "conversation": { - "reloadFailed": "Konversation konnte nicht neu geladen werden: {message}", - "reloaded": "Konversation neu geladen", - "reload": "Neu laden", - "activeConversationIndicator": "Aktive Konversation", - "newConversation": "Neue Konversation", - "closeConversation": "Konversation schließen", - "copyText": "Text kopieren", - "copyTextSuccess": "Kopiert", - "copyTextFailed": "Kopieren fehlgeschlagen", - "forkSession": "Sitzung forken", - "forkSessionSuccess": "Sitzung erfolgreich geforkt", - "forkSessionFailed": "Sitzung konnte nicht geforkt werden: {error}", - "exportConversation": "Konversation exportieren", - "exportImage": "Bild", - "exportMarkdown": "Markdown", - "exportHtml": "HTML", - "exportSuccess": "Konversation exportiert", - "exportFailed": "Export fehlgeschlagen", - "exportImageTooLong": "Konversation ist zu lang für den Bildexport", - "exportLabels": { - "untitledConversation": "Unbenannte Konversation", - "agent": "Agent", - "model": "Modell", - "status": "Status", - "started": "Gestartet", - "updated": "Aktualisiert", - "tokens": "Token-Statistik", - "duration": "Dauer", - "inputTokens": "Eingabe", - "outputTokens": "Ausgabe", - "cacheRead": "Cache gelesen", - "cacheWrite": "Cache geschrieben", - "user": "Benutzer", - "assistant": "Assistent", - "system": "System", - "toolResult": "Ergebnis", - "toolError": "Fehler" - }, - "moreActions": "Weitere Aktionen" - }, - "sessionDetails": { - "menuLabel": "Sitzungsdetails", - "noActiveSession": "Keine aktive Sitzung", - "title": "Sitzungsdetails", - "subtitle": "Sitzungsmetadaten und Token-Nutzung", - "fieldTitle": "Titel", - "untitled": "Unbenannte Konversation", - "sessionId": "Sitzungs-ID", - "externalId": "Erweiterungs-ID", - "agent": "Agent", - "model": "Modell", - "status": "Status", - "gitBranch": "Git-Branch", - "parentId": "Übergeordnete Sitzung", - "tokensHeading": "Token-Nutzung", - "totalTokens": "Gesamt", - "inputTokens": "Eingabe", - "outputTokens": "Ausgabe", - "cacheWrite": "Cache geschrieben", - "cacheRead": "Cache gelesen", - "contextWindow": "Kontextfenster", - "duration": "Dauer", - "loadingStats": "Token-Nutzung wird geladen…", - "loadFailed": "Token-Nutzung konnte nicht geladen werden", - "noStats": "Keine Nutzung erfasst", - "timestampsHeading": "Zeitstempel", - "createdAt": "Erstellt", - "updatedAt": "Aktualisiert", - "none": "—", - "copyField": "{field} kopieren", - "copiedField": "{field} kopiert" - }, - "conversationCard": { - "untitledConversation": "Unbenannte Konversation", - "newConversation": "Neue Konversation", - "rename": "Umbenennen", - "status": "Zustand", - "delete": "Löschen", - "importLocalSessions": "Lokale Sitzungen importieren", - "importing": "Importiere...", - "renameConversation": "Konversation umbenennen", - "deleteConversationTitle": "Konversation löschen?", - "deleteConversationDescription": "\"{title}\" wird gelöscht. Diese Aktion kann nicht rückgängig gemacht werden.", - "cancel": "Abbrechen", - "save": "Speichern", - "pin": "Anheften", - "unpin": "Loslösen", - "markCompleted": "Als abgeschlossen markieren", - "reopen": "Erneut öffnen", - "expandSubsessions": "Unterkonversationen einblenden", - "collapseSubsessions": "Unterkonversationen ausblenden" - }, - "search": { - "dialogTitle": "Suchen", - "dialogTitleWithFolder": "Suchen — {name}", - "tabConversations": "Konversationen", - "tabFiles": "Dateien", - "placeholder": "Konversationen suchen...", - "filePlaceholder": "Dateien oder Verzeichnisse suchen...", - "allAgents": "Alle", - "searching": "Suche...", - "typeToSearch": "Tippen, um Konversationen zu suchen", - "typeToSearchFiles": "Tippen, um Dateien oder Verzeichnisse zu suchen", - "noResults": "Keine Ergebnisse gefunden.", - "untitledConversation": "Unbenannte Konversation" - }, - "folderTitleBar": { - "showSidebar": "Seitenleiste anzeigen", - "hideSidebar": "Seitenleiste ausblenden", - "toggleTerminal": "Terminal umschalten", - "toggleAuxPanel": "Hilfspaneel umschalten", - "search": "Suchen", - "openSettings": "Einstellungen öffnen", - "backToConversations": "Zurück zu Konversationen", - "withShortcut": "{label} (Tastenkürzel: {shortcut})" - }, - "statusBar": { - "connection": { - "connected": "Verbunden", - "connecting": "Verbinde...", - "prompting": "Antworte...", - "error": "Verbindungsfehler", - "disconnected": "Getrennt", - "tooltip": "{agent}: {status}", - "tooltipError": "{agent}: {error}", - "title": "Agent-Verbindung", - "triggerAria": "Agent-Verbindung: {status}", - "workingDir": "Arbeitsverzeichnis", - "sessionId": "Sitzungs-ID", - "viewerNote": "Mit einer Sitzung verbunden, die einem anderen Client gehört – ein Neuverbinden hängt nur diese Ansicht erneut an.", - "reconnectInterrupts": "Neu verbinden startet den Agenten neu und unterbricht die laufende Arbeit.", - "reconnect": "Neu verbinden", - "reconnecting": "Verbinde neu...", - "reconnectUnavailable": "Noch keine Sitzung zum Neuverbinden." - }, - "tasks": { - "title": "Aufgaben" - }, - "alerts": { - "title": "Warnungen", - "empty": "Keine Warnungen", - "details": "Details" - }, - "stats": { - "conversations": "{count} Konversationen", - "openUsage": "Sitzungsstatistik und Token-Nutzung anzeigen" - }, - "tokens": { - "contextWindowUsageAria": "Kontextfenster-Nutzung", - "contextWindow": "Kontextfenster", - "usedMax": "Verwendet / Max", - "tokenUsage": "Token-Nutzung", - "input": "Eingabe", - "output": "Ausgabe", - "cacheRead": "Cache lesen", - "cacheWrite": "Cache schreiben", - "total": "Gesamt" - } - }, - "auxPanel": { - "tabs": { - "files": "Dateien", - "changes": "Änderungen", - "commits": "Einträge" - }, - "noFolderTitle": "Kein Ordner geöffnet", - "noFolderHint": "Öffnen Sie einen Ordner, um seinen Inhalt hier zu sehen" - }, - "windowControls": { - "minimizeWindow": "Fenster minimieren", - "minimize": "Minimieren", - "maximizeWindow": "Fenster maximieren", - "maximize": "Maximieren", - "restoreWindow": "Fenster wiederherstellen", - "restore": "Wiederherstellen", - "closeWindow": "Fenster schließen", - "close": "Schließen" - }, - "tabs": { - "closeConversationTab": "Konversationstab schließen", - "close": "Schließen", - "closeOthers": "Andere schließen", - "splitRight": "Nach rechts teilen", - "splitDown": "Nach unten teilen", - "splitAndMoveRight": "Teilen und nach rechts verschieben", - "splitAndMoveDown": "Teilen und nach unten verschieben", - "moveToOppositeGroup": "In gegenüberliegende Gruppe verschieben", - "moveToGroup": "In Gruppe verschieben", - "groupLabel": "Gruppe {index}", - "changeSplitterOrientation": "Teiler-Ausrichtung wechseln", - "unsplit": "Teilung aufheben", - "unsplitAll": "Alle Teilungen aufheben", - "closeAll": "Alle schließen", - "tileDisplay": "Kachelansicht", - "untileDisplay": "Kachel beenden" - }, - "fileWorkspace": { - "files": "Dateien", - "closeFileTab": "Dateitab schließen", - "close": "Schließen", - "closeOthers": "Andere schließen", - "closeAll": "Alle schließen", - "preview": "Vorschau", - "editSource": "Quelle bearbeiten", - "maximize": "Maximieren", - "restore": "Wiederherstellen", - "emptyDirectory": "Leerer Ordner" - }, - "terminal": { - "rename": "Umbenennen", - "close": "Schließen", - "closeOthers": "Andere schließen", - "closeAll": "Alle schließen", - "hideTerminal": "Terminal ausblenden ({shortcut})", - "openFolderFirst": "Öffnen Sie zuerst einen Ordner" - }, - "workspaceDialog": { - "title": "Ordner öffnen", - "manageTitle": "Verknüpfte Ordner", - "addTargetsTitle": "Ordner zum Verknüpfen hinzufügen", - "pickRootDescription": "Wähle den Hauptordner für diesen Arbeitsbereich.", - "linksDescription": "Verknüpfe weitere Ordner als Unterverzeichnisse, damit Agenten aus einem Arbeitsbereich heraus über alle hinweg arbeiten können.", - "addTargetsDescription": "Wähle einen oder mehrere Ordner. Jeder wird zu einem Unterverzeichnis des Arbeitsbereichs.", - "useSystemPicker": "Systemauswahl", - "next": "Weiter", - "back": "Zurück", - "done": "Fertig", - "change": "Ändern", - "addFolders": "Ordner hinzufügen", - "addSelected": "Hinzufügen", - "addSelectedCount": "{count} hinzufügen", - "createCount": "{count} Ordner verknüpfen", - "discardPending": "Verwerfen", - "noLinks": "Noch keine verknüpften Ordner.", - "gitExclude": "Verknüpfungen aus dem Git-Status heraushalten", - "rename": "Umbenennen", - "unlink": "Verknüpfung entfernen", - "repair": "Verknüpfung neu anlegen", - "saveName": "Speichern", - "cancelRename": "Abbrechen", - "removePending": "Entfernen", - "willAppearAs": "Erscheint im Arbeitsbereich als {name}", - "renamedForDuplicate": "Umbenannt – {base} wird bereits von einer anderen Verknüpfung genutzt", - "renamedForExistingEntry": "Umbenannt – {base} existiert in diesem Ordner bereits", - "partiallyCreated": "Nur {count} Ordner konnten verknüpft werden", - "openFailed": "Ordner konnte nicht geöffnet werden", - "previewFailed": "Ausgewählte Ordner konnten nicht geprüft werden", - "createFailed": "Ordner konnten nicht verknüpft werden", - "renameFailed": "Verknüpfung konnte nicht umbenannt werden", - "removeFailed": "Verknüpfung konnte nicht entfernt werden", - "repairFailed": "Verknüpfung konnte nicht neu angelegt werden", - "status": { - "ok": "Verknüpft", - "missing": "Die Verknüpfung ist aus diesem Ordner verschwunden", - "conflicted": "Ein anderer Eintrag nutzt jetzt diesen Namen", - "broken": "Der verknüpfte Ordner existiert nicht mehr" - }, - "nameIssue": { - "empty": "Namen eingeben", - "illegalChars": "Darf / \\ : * ? \" < > | nicht enthalten", - "tooLong": "Name ist zu lang", - "reserved": "Dieser Name ist unter Windows reserviert", - "duplicate": "Dieser Name wird bereits verwendet" - }, - "rejection": { - "not_found": "Dieser Ordner wurde nicht gefunden", - "not_a_directory": "Dieser Pfad ist kein Ordner", - "same_as_root": "Das ist der Arbeitsbereichsordner selbst", - "ancestor_of_root": "Dieser Ordner enthält den Arbeitsbereich", - "inside_root": "Liegt bereits im Arbeitsbereich", - "already_linked": "Bereits verknüpft", - "name_unavailable": "Für diesen Ordner ist kein Name mehr frei", - "alreadyLinkedAs": "Bereits als {name} verknüpft" - } - }, - "folderNameDropdown": { - "fallbackFolderName": "Ordner", - "openFolder": "Ordner öffnen", - "cloneRepository": "Repository klonen", - "projectBoot": "Projekt-Boot", - "opened": "Geöffnet", - "recentOpen": "Zuletzt geöffnet" - }, - "fileWorkspacePanel": { - "addSelectionToChat": "Auswahl zum Chat hinzufügen", - "addToChat": "Zum Chat hinzufügen", - "addSelectionToChatDone": "{label} zur Unterhaltung hinzugefügt", - "addFileToChat": "Datei zum Chat hinzufügen", - "toggleWordWrap": "Zeilenumbruch umschalten", - "addFileToChatDone": "{label} zur Unterhaltung hinzugefügt", - "viewDiff": "Diff anzeigen", - "openFile": "Datei öffnen", - "fileCount": "{count, plural, one {# Datei} other {# Dateien}}", - "openFileOrDiff": "Öffne eine Datei oder Diff im rechten Panel", - "disk": "Datenträger", - "head": "HEAD", - "unsaved": "Ungespeichert", - "workingTree": "Arbeitsverzeichnis", - "loading": "Wird geladen...", - "compareWithBranch": "{path} · vergleichen mit {branch}", - "hunkCount": "{count, plural, one {# Hunk} other {# Hunks}}", - "prev": "Zurück", - "next": "Weiter", - "jumpToLine": "Zu Zeile {line} springen", - "noParsedDiffSections": "Keine geparsten Diff-Abschnitte", - "loadingEditor": "Editor wird geladen...", - "imageZoomIn": "Vergrößern", - "imageZoomOut": "Verkleinern", - "imageZoomReset": "Zoom zurücksetzen", - "htmlPreviewTitle": "HTML-Vorschau", - "htmlPreviewTrust": "Skripte aktivieren", - "htmlPreviewTrustHint": "Skripte dieser Datei ausführen und Netzwerkzugriff erlauben. Nur für vertrauenswürdige Dateien aktivieren.", - "officePreviewTitle": "Office-Dokumentvorschau", - "officeFullRender": "Vollständige Darstellung", - "officeFullRenderHint": "Stellt Morph-Animationen, 3D und Formeln dar (führt die Skripte der Folie aus)", - "officeNotInstalled": "OfficeCLI ist nicht installiert", - "officeNotInstalledHint": "Installiere OfficeCLI unter Einstellungen → Office-Tools, um Word-, Excel- und PowerPoint-Dateien vorzuschauen.", - "officeOpenSettings": "Einstellungen öffnen", - "officeWatchFailed": "Live-Vorschau konnte nicht gestartet werden", - "officeWatchRetry": "Erneut versuchen", - "officeServerInstallHint": "OfficeCLI muss auf dem Server-Host installiert sein. Führe diesen Befehl dort aus und versuche es erneut:", - "officeRemoteDesktopUnsupported": "Die Live-Vorschau ist in einem Remote-Desktop-Fenster nicht verfügbar. Öffne diesen Arbeitsbereich in der Web-Oberfläche des Servers, um Office-Dateien anzusehen." - }, - "branchDropdown": { - "toasts": { - "commitCodeCompleted": "Code-Commit abgeschlossen", - "pushCodeCompleted": "Code-Push abgeschlossen", - "committedFiles": "{count, plural, one {# Datei committet} other {# Dateien committet}}", - "taskCompleted": "{label} abgeschlossen", - "taskFailed": "{label} fehlgeschlagen", - "mergeNoNewCommits": "{branchName} hat keine neuen Commits", - "mergedCommits": "{count, plural, one {# Commit zusammengeführt} other {# Commits zusammengeführt}}", - "allFilesUpToDate": "Alle Dateien sind aktuell", - "updatedFiles": "{count, plural, one {# Datei aktualisiert} other {# Dateien aktualisiert}}", - "openCommitWindowFailed": "Commit-Fenster konnte nicht geöffnet werden", - "openPushWindowFailed": "Push-Fenster konnte nicht geöffnet werden", - "upstreamSet": "Upstream-Branch wurde gesetzt", - "upstreamSetAndPushed": "Upstream-Branch gesetzt und {count, plural, one {# Commit} other {# Commits}} gepusht", - "noCommitsToPush": "Keine Commits zum Pushen", - "pushedCommits": "{count, plural, one {# Commit gepusht} other {# Commits gepusht}}", - "switchedToFolder": "Zu {name} gewechselt", - "switchFailed": "Branch konnte nicht gewechselt werden", - "openStashWindowFailed": "Stash-Fenster konnte nicht geöffnet werden" - }, - "tasks": { - "newBranch": "Branch {name} erstellen", - "newWorktree": "Worktree {name} erstellen", - "checkoutTo": "Zu {branchName} wechseln", - "mergeBranch": "{branchName} mergen", - "rebaseTo": "Auf {branchName} rebasen", - "deleteRemoteBranch": "Remote-Branch {branchName} löschen", - "initGitRepo": "Git-Repository initialisieren", - "pullCode": "Code pullen", - "fetchInfo": "Informationen fetchen", - "pushCode": "Code pushen", - "stashChanges": "Änderungen stashen", - "stashPop": "Stash anwenden", - "deleteBranch": "Branch {branchName} löschen", - "removeWorktree": "Worktree von {branchName} löschen", - "removeWorktreeAndBranch": "Worktree und Branch {branchName} löschen", - "updateBranch": "Branch {branchName} aktualisieren" - }, - "confirm": { - "mergeTitle": "Branch mergen", - "rebaseTitle": "Branch rebasen", - "mergeDescription": "{branchName} in den aktuellen Branch {currentBranch} mergen?", - "rebaseDescription": "Aktuellen Branch {currentBranch} auf {branchName} rebasen?", - "deleteRemoteTitle": "Remote-Branch löschen", - "deleteRemoteDescription": "Remote-Branch {branchName} löschen? Dies entfernt ihn aus dem Remote-Repository und kann nicht rückgängig gemacht werden.", - "deleteTitle": "Branch löschen", - "deleteDescription": "Branch {branchName} löschen? Diese Aktion kann nicht rückgängig gemacht werden.", - "forceDeleteTitle": "Branch erzwungen löschen", - "forceDeleteDescription": "Der Branch {branchName} ist nicht vollständig gemergt. Möchten Sie ihn wirklich erzwungen löschen? Diese Aktion kann nicht rückgängig gemacht werden.", - "deleteWorktreeTitle": "Worktree löschen", - "deleteWorktreeDescription": "Das Worktree-Verzeichnis löschen, in dem {branchName} ausgecheckt ist? Der Branch und seine Commits bleiben erhalten.", - "forceDeleteWorktreeTitle": "Worktree erzwungen löschen", - "forceDeleteWorktreeDescription": "Im Worktree von {branchName} gibt es nicht committete oder nicht verfolgte Dateien. Trotzdem löschen? Diese Änderungen lassen sich nicht wiederherstellen.", - "deleteWorktreeAndBranchTitle": "Worktree und Branch löschen", - "deleteWorktreeAndBranchDescription": "Den Worktree von {branchName}, den Branch selbst und seinen Arbeitsbereich-Ordner löschen? Seine Sitzungen wandern in den Repository-Ordner. Diese Aktion kann nicht rückgängig gemacht werden.", - "forceDeleteWorktreeAndBranchTitle": "Worktree und Branch erzwungen löschen", - "forceDeleteWorktreeAndBranchDescription": "Im Worktree von {branchName} gibt es nicht committete Dateien, oder der Branch ist nicht vollständig gemergt. Trotzdem beides löschen? Diese Aktion kann nicht rückgängig gemacht werden." - }, - "current": "Aktuell", - "switchToBranch": "Zu diesem Branch wechseln", - "mergeBranchIntoCurrent": "{branchName} in {currentBranch} mergen", - "rebaseCurrentToBranch": "{currentBranch} auf {branchName} rebasen", - "noBranch": "Kein Branch", - "detachedHead": "Losgelöster HEAD bei {sha}", - "initGitRepo": "Git-Repository initialisieren", - "pullCode": "Code pullen", - "fetchRemoteBranches": "Remote-Branches fetchen", - "openCommitWindow": "Code committen...", - "pushCode": "Hochladen...", - "pushBranch": "Hochladen", - "newBranch": "Neuer Branch...", - "newWorktree": "Neuer Worktree...", - "stashChanges": "Änderungen stashen...", - "stashPop": "Stash anwenden...", - "manageRemotes": "Remotes verwalten...", - "localBranches": "Lokale Branches ({count, plural, one {#} other {#}})", - "noLocalBranches": "Keine lokalen Branches", - "remoteBranches": "Remote-Branches ({count, plural, one {#} other {#}})", - "noRemoteBranches": "Keine Remote-Branches", - "dialogs": { - "newBranchTitle": "Neuer Branch", - "newBranchDescription": "Neuen Branch vom aktuellen Branch {branch} erstellen", - "branchNamePlaceholder": "Branch-Name", - "newWorktreeTitle": "Neuer Worktree", - "newWorktreeDescription": "Neuen Worktree vom aktuellen Branch {branch} erstellen", - "branchNameLabel": "Branch-Name", - "worktreePathLabel": "Worktree-Pfad", - "worktreePathPlaceholder": "Worktree-Pfad", - "manageRemotesTitle": "Remotes verwalten", - "manageRemotesEmpty": "Keine Remotes konfiguriert", - "remoteNamePlaceholder": "Remote-Name", - "remoteUrlPlaceholder": "Remote-URL", - "addRemote": "Hinzufügen", - "savingRemotes": "Speichern..." - }, - "conflict": { - "title": "Merge-Konflikte", - "description": "Die folgenden Dateien haben Konflikte, die gelöst werden müssen:", - "abort": "Merge abbrechen", - "openMergeTool": "Merge-Tool öffnen", - "completeMerge": "Merge abschließen", - "abortSuccess": "Merge erfolgreich abgebrochen", - "completeSuccess": "Merge erfolgreich abgeschlossen" - }, - "stashDialog": { - "title": "Änderungen stashen", - "description": "Aktuelle Änderungen im Stash speichern", - "messageLabel": "Nachricht", - "messagePlaceholder": "Stash-Nachricht (optional)", - "keepIndex": "Index beibehalten (gestagete Änderungen bleiben erhalten)", - "cancel": "Abbrechen", - "stash": "Stashen", - "success": "Änderungen wurden gestasht", - "error": "Stash fehlgeschlagen" - }, - "unstashDialog": { - "title": "Stash anwenden", - "noStashes": "Keine Stashes vorhanden", - "selectFile": "Datei auswählen um Diff anzuzeigen", - "viewDiff": "Diff anzeigen", - "original": "Original", - "modified": "Geändert", - "apply": "Anwenden", - "drop": "Löschen", - "applySuccess": "Stash angewendet", - "dropSuccess": "Stash gelöscht", - "confirmApply": "Stash {ref} auf das Arbeitsverzeichnis anwenden?", - "cancel": "Abbrechen" - }, - "deleteBranch": "Branch löschen", - "deleteWorktree": "Worktree löschen", - "deleteWorktreeAndBranch": "Worktree und Branch löschen", - "searchPlaceholder": "Branches und Aktionen suchen", - "searchAriaLabel": "Branches und Aktionen suchen", - "branchListLabel": "Branches und Aktionen", - "noMatches": "Keine Treffer" - }, - "commitDialog": { - "toasts": { - "commitCompleted": "Code-Commit abgeschlossen", - "pushFailed": "Push fehlgeschlagen", - "committedFiles": "{count, plural, one {# Datei committet} other {# Dateien committet}}", - "addedToVcs": "Zu VCS hinzugefügt", - "addToVcsFailed": "Hinzufügen zu VCS fehlgeschlagen", - "fileDeleted": "Datei gelöscht", - "deleteFailed": "Löschen fehlgeschlagen", - "fileRolledBack": "Datei zurückgesetzt", - "rollbackFailed": "Rollback fehlgeschlagen", - "dirRolledBack": "Verzeichnis zurückgesetzt", - "dirDeleted": "Verzeichnis gelöscht" - }, - "confirm": { - "deleteTitle": "Löschen bestätigen", - "deleteDescription": "Datei \"{file}\" löschen? Diese Aktion kann nicht rückgängig gemacht werden.", - "rollbackTitle": "Rollback bestätigen", - "rollbackDescription": "Datei \"{file}\" auf HEAD zurücksetzen? Ungespeicherte Änderungen gehen verloren.", - "rollbackDirDescription": "Verzeichnis \"{dir}\" auf HEAD zurücksetzen? Nicht gespeicherte Änderungen gehen verloren.", - "deleteDirDescription": "Verzeichnis \"{dir}\" löschen? Diese Aktion kann nicht rückgängig gemacht werden." - }, - "actions": { - "select": "Auswählen", - "unselect": "Auswahl aufheben", - "rollback": "Zurücksetzen", - "addToVcs": "Zu VCS hinzufügen" - }, - "aria": { - "selectFile": "{action}: {path}", - "unselectAllFiles": "Auswahl aller Dateien aufheben", - "selectAllFiles": "Alle Dateien auswählen", - "unselectTracked": "Auswahl verfolgter Änderungen aufheben", - "selectTracked": "Verfolgte Änderungen auswählen", - "unselectUntracked": "Auswahl nicht verfolgter Dateien aufheben", - "selectUntracked": "Nicht verfolgte Dateien auswählen" - }, - "loading": "Wird geladen...", - "selectionCount": "{selected} / {total} Dateien", - "emptyFiles": "Keine geänderten Dateien", - "trackedChanges": "Verfolgte Änderungen ({count})", - "untrackedFiles": "Nicht verfolgte Dateien ({count})", - "commitMessage": "Commit-Nachricht", - "commitMessagePlaceholder": "Commit-Nachricht eingeben...", - "commitButton": "Einchecken ({count})", - "commitAndPushButton": "Committen und pushen ({count})", - "head": "HEAD", - "workingTree": "Arbeitsverzeichnis", - "clickFileToDiff": "Dateinamen anklicken, um Diff zu sehen", - "loadingDiff": "Diff wird geladen..." - }, - "pushWindow": { - "title": "Code pushen", - "noUnpushedCommits": "Keine ungepushten Commits", - "noRemoteConfigured": "Kein Git-Remote konfiguriert\nFüge einen unter Remotes verwalten hinzu", - "newBranchNoPushedCommits": "Neuer Branch — pushen, um Remote-Tracking-Branch zu erstellen", - "unpushed": "Nicht gepusht", - "selectFileToViewDiff": "Datei auswählen, um Unterschiede anzuzeigen", - "before": "Vorher", - "after": "Nachher", - "push": "Pushen", - "toasts": { - "pushSuccess": "Push erfolgreich", - "pushFailed": "Push fehlgeschlagen", - "upstreamSet": "Remote-Tracking-Branch wurde eingerichtet", - "upstreamSetAndPushed": "Remote-Tracking-Branch eingerichtet und {count} Commits gepusht", - "noCommitsToPush": "Keine Commits zum Pushen", - "pushedCommits": "{count} Commits gepusht" - } - }, - "gitLogTab": { - "filesTitle": "Dateien", - "expandAllFiles": "Alle Dateien ausklappen", - "collapseAllFiles": "Alle Dateien einklappen", - "workspace": "Arbeitsbereich", - "retry": "Erneut versuchen", - "noCommitsFound": "Keine Commits gefunden", - "notAGitRepoTitle": "Kein Git-Repository", - "notAGitRepoHint": "Initialisiere Git über das Branch-Menü oben oder öffne ein bestehendes Repository.", - "hash": "Hash-Wert", - "copyHash": "Hash kopieren", - "copyMessage": "Nachricht kopieren", - "showMore": "Mehr anzeigen", - "showLess": "Weniger anzeigen", - "author": "Autor", - "noFileChangeDetails": "Keine Details zu Dateiänderungen verfügbar.", - "loadingFiles": "Dateien werden geladen...", - "branchesTitle": "Zweige", - "loadingBranches": "Branches werden geladen...", - "noContainingBranches": "Keine enthaltenen Branches gefunden.", - "newBranch": "Neuer Branch...", - "resetToHere": "Auf diesen Stand zurücksetzen", - "resetDisabledReasonNotCurrentBranchView": "Nur in der Ansicht des aktuellen Branches verfügbar", - "copyFullCommitHashAria": "Vollständigen Commit-Hash {hash} kopieren", - "pushStatus": { - "pushed": "Zum Remote gepusht", - "notPushed": "Nicht zum Remote gepusht", - "unknown": "Push-Status unbekannt (kein Upstream konfiguriert)" - }, - "time": { - "monthsAgo": "{count, plural, one {vor # Monat} other {vor # Monaten}}", - "daysAgo": "{count, plural, one {vor # Tag} other {vor # Tagen}}", - "hoursAgo": "{count, plural, one {vor # Stunde} other {vor # Stunden}}", - "minsAgo": "{count, plural, one {vor # Min} other {vor # Min}}", - "justNow": "gerade eben" - }, - "toasts": { - "createdAndSwitchedNewBranch": "Neuen Branch erstellt und gewechselt", - "newBranchFromCommit": "{name} (aus {shortHash})", - "createBranchFailed": "Branch konnte nicht erstellt werden", - "openPushWindowFailed": "Push-Fenster konnte nicht geöffnet werden", - "resetSuccess": "Zurücksetzen erfolgreich", - "resetSuccessDescription": "{branch} wurde mit {mode} auf {shortHash} zurückgesetzt", - "resetFailed": "Zurücksetzen fehlgeschlagen" - }, - "authorFilter": { - "label": "Autor", - "searchPlaceholder": "Autor suchen", - "noAuthors": "Keine Autoren gefunden", - "you": "du", - "filterByAuthorAria": "Commits nach Autor filtern", - "filterByQuery": "Nach \"{query}\" filtern", - "clearAuthorFilterAria": "Autorfilter löschen", - "recent": "Zuletzt verwendet", - "matchingAuthors": "Passende Autoren", - "removeFromRecent": "{name} aus „Zuletzt verwendet“ entfernen" - }, - "branchSelector": { - "label": "Branch", - "head": "HEAD", - "headHint": "Folgt dem aktuellen Branch", - "headHintWithBranch": "Folgt dem aktuellen Branch ({branch})", - "searchBranch": "Branch suchen...", - "noBranches": "Keine Branches", - "selectBranchPlaceholder": "Branch auswählen...", - "localBranches": "Lokale Branches", - "current": "Aktuell", - "remoteBranches": "Remote-Branches", - "refreshCommitHistory": "Commit-Verlauf aktualisieren", - "clearBranchFilterAria": "Branch-Filter löschen" - }, - "dialogs": { - "newBranchTitle": "Neuer Branch", - "newBranchDescription": "Erstelle einen neuen Branch mit Commit {shortHash} als letztem Commit.", - "branchNamePlaceholder": "Branch-Name", - "reset": { - "title": "Aktuellen Branch auf diesen Commit zurücksetzen", - "branchLabel": "Branch", - "targetLabel": "Ziel-Commit", - "messageLabel": "Nachricht", - "modeLabel": "Reset-Modus", - "confirmButton": "Zurücksetzen", - "modes": { - "soft": { - "label": "--soft", - "description": "Verschiebt HEAD und den Zeiger des aktuellen Branches auf den Ziel-Commit.\nIndex und Working Tree bleiben unverändert.\nÄnderungen aus den entfernten Commits bleiben staged." - }, - "mixed": { - "label": "--mixed (Standard)", - "description": "Verschiebt HEAD auf den Ziel-Commit.\nSetzt den Index auf den Ziel-Commit zurück und behält Änderungen im Working Tree.\nÄnderungen wechseln von staged zu unstaged." - }, - "hard": { - "label": "--hard", - "description": "Verschiebt HEAD und setzt sowohl Index als auch Working Tree auf den Ziel-Commit zurück.\nLokale verfolgte Änderungen nach dem Ziel-Commit werden verworfen.\nDies ist eine destruktive Operation." - }, - "keep": { - "label": "--keep", - "description": "Verschiebt HEAD auf den Ziel-Commit und versucht lokale Änderungen zu behalten.\nNur nicht-konfliktierende Änderungen bleiben erhalten.\nBei Konflikten wird der Reset zum Schutz der Änderungen abgebrochen." - } - } - } - }, - "moreActions": "Weitere Git-Aktionen" - }, - "gitChangesTab": { - "workspace": "Arbeitsbereich", - "noChanges": "Keine lokalen Änderungen", - "notAGitRepoTitle": "Kein Git-Repository", - "notAGitRepoHint": "Initialisiere Git über das Branch-Menü oben oder öffne ein bestehendes Repository.", - "trackedChanges": "Verfolgte Änderungen ({count})", - "untrackedFiles": "Nicht verfolgte Dateien ({count})", - "expandTracked": "Verfolgte Änderungen ausklappen", - "collapseTracked": "Verfolgte Änderungen einklappen", - "expandUntracked": "Nicht verfolgte Dateien ausklappen", - "collapseUntracked": "Nicht verfolgte Dateien einklappen", - "showRemainingItems": "{count} weitere Einträge anzeigen", - "actions": { - "commitCode": "Code committen", - "rollback": "Zurücksetzen", - "addToVcs": "Zu VCS hinzufügen", - "delete": "Löschen", - "moreActions": "Weitere Git-Aktionen", - "addAllToVcs": "Alle zur VCS hinzufügen", - "rollbackAll": "Alle zurücksetzen", - "refresh": "Aktualisieren" - }, - "toasts": { - "noAddableFilesInDir": "Keine geänderten Dateien in diesem Verzeichnis können zu VCS hinzugefügt werden", - "noRollbackFilesInDir": "Keine geänderten Dateien in diesem Verzeichnis können zurückgesetzt werden", - "addedToVcs": "{name} zu VCS hinzugefügt", - "addToVcsFailed": "Hinzufügen zu VCS fehlgeschlagen", - "openCommitWindowFailed": "Commit-Fenster konnte nicht geöffnet werden", - "rolledBack": "{name} zurückgesetzt", - "rollbackFailed": "Rollback fehlgeschlagen", - "addedFilesToVcs": "{count, plural, one {# Datei} other {# Dateien}} zu VCS hinzugefügt", - "rolledBackFiles": "{count, plural, one {# Datei zurückgesetzt} other {# Dateien zurückgesetzt}}", - "deleted": "{name} gelöscht", - "deleteFailed": "Löschen fehlgeschlagen", - "deletedFiles": "{count} Dateien gelöscht", - "noDeletableFilesInDir": "In diesem Verzeichnis gibt es keine löschbaren geänderten Dateien", - "commitFailed": "Commit fehlgeschlagen" - }, - "directoryDialog": { - "descriptionAdd": "Dateien unter Verzeichnis {path} auswählen, um sie zu VCS hinzuzufügen.", - "descriptionRollback": "Dateien unter Verzeichnis {path} auswählen, um sie zurückzusetzen.", - "descriptionDelete": "Dateien unter Verzeichnis {path} auswählen, um sie zu löschen. Diese Aktion kann nicht rückgängig gemacht werden.", - "descriptionFallback": "Dateien auswählen, um fortzufahren.", - "selectionCount": "{selected} / {total} Dateien ausgewählt", - "selectAll": "Alle auswählen", - "unselectAll": "Auswahl aller aufheben", - "loadingCandidates": "Verzeichnisänderungen werden geladen...", - "noOperableFiles": "Keine bearbeitbaren Dateien" - }, - "rollbackConfirm": { - "title": "Rollback bestätigen", - "descriptionWithTarget": "Lokale Änderungen für {kind} \"{name}\" zurücksetzen?", - "descriptionFallback": "Lokale Änderungen zurücksetzen?", - "kindDirectory": "Verzeichnis", - "kindFile": "Datei" - }, - "deleteConfirm": { - "title": "Löschen bestätigen", - "descriptionWithTarget": "{kind} \"{name}\" löschen? Diese Aktion kann nicht rückgängig gemacht werden.", - "descriptionFallback": "Diese Aktion kann nicht rückgängig gemacht werden.", - "kindDirectory": "Verzeichnis", - "kindFile": "Datei" - }, - "quickCommit": { - "placeholder": "Commit-Nachricht (Enter zum Committen)" - } - }, - "tabContext": { - "loadingConversation": "Wird geladen...", - "untitledConversation": "Unbenannte Konversation", - "newConversation": "Neue Konversation" - }, - "fileTreeTab": { - "workspace": "Arbeitsbereich", - "retry": "Erneut versuchen", - "git": "Git", - "openInFileManager": "Im Dateimanager öffnen", - "openInFinder": "In Finder öffnen", - "openInExplorer": "In Explorer öffnen", - "attachToCurrentSession": "Zur Sitzung hinzufügen", - "compareWithBranch": "Mit Branch vergleichen...", - "reloadFromDisk": "Von Datenträger neu laden", - "new": "Neu", - "newFile": "Datei", - "newDirectory": "Verzeichnis", - "openIn": "Öffnen in", - "openInTerminal": "Im Terminal öffnen", - "linkedFolder": "Verknüpfter Ordner", - "copyPath": "Pfad kopieren", - "upload": "Dateien/Ordner hochladen", - "download": "Datei herunterladen", - "downloadAsZip": "Als ZIP herunterladen", - "actions": { - "select": "Auswählen", - "unselect": "Auswahl aufheben", - "commitCode": "Code committen", - "rollback": "Zurücksetzen", - "addToVcs": "Zu VCS hinzufügen" - }, - "aria": { - "selectPath": "{action}: {path}" - }, - "toasts": { - "openDirectoryFailed": "Verzeichnis konnte nicht geöffnet werden", - "openBuiltinTerminalFailed": "Integriertes Terminal konnte nicht geöffnet werden", - "openCommitWindowFailed": "Commit-Fenster konnte nicht geöffnet werden", - "noAddableFilesInDir": "Keine geänderten Dateien in diesem Verzeichnis können zu VCS hinzugefügt werden", - "noRollbackFilesInDir": "Keine geänderten Dateien in diesem Verzeichnis können zurückgesetzt werden", - "addedToVcs": "{name} zu VCS hinzugefügt", - "addToVcsFailed": "Hinzufügen zu VCS fehlgeschlagen", - "loadBranchesFailed": "Branches konnten nicht geladen werden", - "renameFailed": "Umbenennen fehlgeschlagen", - "moveFailed": "Verschieben fehlgeschlagen", - "deleteFailed": "Löschen fehlgeschlagen", - "rolledBack": "{name} zurückgesetzt", - "rollbackFailed": "Zurücksetzen fehlgeschlagen", - "addedFilesToVcs": "{count, plural, one {# Datei zu VCS hinzugefügt} other {# Dateien zu VCS hinzugefügt}}", - "rolledBackFiles": "{count, plural, one {# Datei zurückgesetzt} other {# Dateien zurückgesetzt}}", - "savedAsCopy": "Als Kopie gespeichert", - "saveCopyFailed": "Speichern als Kopie fehlgeschlagen", - "watchStartFailed": "Dateiwatch konnte nicht gestartet werden", - "createFailed": "Erstellen fehlgeschlagen", - "downloadFailed": "Herunterladen von {name} fehlgeschlagen", - "downloadSaved": "{name} heruntergeladen", - "pathCopied": "Pfad kopiert", - "copyPathFailed": "Pfad konnte nicht kopiert werden" - }, - "createDialog": { - "newFile": "Neue Datei", - "newDirectory": "Neues Verzeichnis", - "description": "Geben Sie einen Namen für das neue {kind} ein.", - "placeholderFile": "file-name.ext", - "placeholderDirectory": "folder-name" - }, - "renameDialog": { - "renameDirectory": "Verzeichnis umbenennen", - "renameFile": "Datei umbenennen", - "description": "Geben Sie einen neuen Namen ein (nur Name, kein Pfad).", - "placeholderDirectory": "neuer-ordnername", - "placeholderFile": "neuer-dateiname.ext" - }, - "uploadDialog": { - "title": "In den Arbeitsbereich hochladen", - "description": "Passe das Ziel bei Bedarf an und füge Dateien oder Ordner hinzu.", - "workspaceRoot": "Arbeitsbereich-Stammverzeichnis", - "targetPathLabel": "Hochladen nach", - "targetPathHint": "Aufgelöster Pfad: {path}", - "dropHint": "Dateien oder Ordner hier ablegen oder die Schaltflächen unten verwenden", - "dropHintActive": "Loslassen, um zur Warteschlange hinzuzufügen", - "selectFiles": "Dateien auswählen", - "selectFolder": "Ordner auswählen", - "startUpload": "Upload starten", - "clearQueue": "Erledigte entfernen", - "removeItem": "Aus der Warteschlange entfernen", - "retry": "Wiederholen", - "dropZoneAria": "Dateien hier ablegen oder aktivieren zum Durchsuchen", - "folderEmpty": "Keine Dateien im abgelegten Ordner gefunden", - "summary": "Gesamt: {total} · Erfolgreich: {succeeded} · Fehlgeschlagen: {failed}", - "status": { - "pending": "Wartet", - "uploading": "Wird hochgeladen", - "success": "Fertig", - "error": "Fehlgeschlagen", - "cancelled": "Abgebrochen" - } - }, - "directoryDialog": { - "descriptionAdd": "Wählen Sie Dateien im Verzeichnis {path} aus, um sie zu VCS hinzuzufügen.", - "descriptionRollback": "Wählen Sie Dateien im Verzeichnis {path} aus, um sie zurückzusetzen.", - "descriptionFallback": "Wählen Sie Dateien aus, um fortzufahren.", - "selectionCount": "{selected} / {total} Dateien ausgewählt", - "selectAll": "Alle auswählen", - "unselectAll": "Auswahl aufheben", - "loadingCandidates": "Verzeichnisänderungen werden geladen...", - "noOperableFiles": "Keine bearbeitbaren Dateien" - }, - "compareDialog": { - "title": "Mit Branch vergleichen", - "descriptionWithTarget": "Wählen Sie einen Branch und vergleichen Sie mit {kind} {path}", - "descriptionFallback": "Wählen Sie einen Branch zum Vergleichen.", - "kindDirectory": "Verzeichnis", - "kindFile": "Datei", - "filterPlaceholder": "Branches filtern, z. B. main / origin/main", - "singleClickHint": "Klicken Sie auf einen Branch, um direkt zu vergleichen", - "loadingBranches": "Branches werden geladen...", - "recentBranches": "Letzte Branches ({count})", - "noCurrentBranch": "Kein aktueller Branch", - "localBranches": "Lokale Branches ({count})", - "remoteBranches": "Remote-Branches ({count})", - "noMatchingBranches": "Keine passenden Branches" - }, - "externalConflictDialog": { - "title": "Externe Dateiänderungen erkannt", - "descriptionWithPath": "Datei {path} wurde auf dem Datenträger geändert, und aktuelle Bearbeitungen sind nicht gespeichert.", - "descriptionFallback": "Aktuelle Datei wurde auf dem Datenträger geändert, und aktuelle Bearbeitungen sind nicht gespeichert.", - "compare": "Vergleichen", - "savingCopy": "Kopie wird gespeichert...", - "saveAsCopy": "Als Kopie speichern", - "reload": "Neu laden" - }, - "deleteConfirm": { - "title": "Löschen bestätigen", - "descriptionWithTarget": "{kind} \"{name}\" löschen? Diese Aktion kann nicht rückgängig gemacht werden.", - "descriptionFallback": "Diese Aktion kann nicht rückgängig gemacht werden.", - "kindDirectory": "Verzeichnis", - "kindFile": "Datei" - }, - "rollbackConfirm": { - "title": "Zurücksetzen bestätigen", - "descriptionWithTarget": "Lokale Änderungen für Datei \"{name}\" zurücksetzen?", - "descriptionFallback": "Lokale Änderungen für diese Datei zurücksetzen?" - }, - "terminalTitle": "Konsole · {name}" - }, - "commandDropdown": { - "loading": "Wird geladen...", - "addCommand": "Befehl hinzufügen", - "manageCommands": "Befehle verwalten...", - "runCommandTitle": "Ausführen: {command}", - "stopCommandTitle": "Stoppen: {command}", - "manageDialog": { - "title": "Befehle verwalten", - "empty": "Noch keine Befehle", - "noResults": "Keine passenden Befehle", - "searchPlaceholder": "Befehle suchen", - "newCommand": "Neuer Befehl", - "nameLabel": "Bezeichnung", - "commandLabel": "Befehl", - "dragSort": "Zum Sortieren ziehen", - "dragSortCommand": "{name} zum Sortieren ziehen", - "orderFailed": "Befehlsreihenfolge konnte nicht gespeichert werden", - "loadFailed": "Befehle konnten nicht geladen werden", - "saveFailed": "Befehl konnte nicht gespeichert werden", - "deleteFailed": "Befehl konnte nicht gelöscht werden", - "confirmDelete": { - "title": "Befehl löschen?", - "message": "Dadurch wird \"{name}\" entfernt. Diese Aktion kann nicht rückgängig gemacht werden." - } - } - }, - "workspaceContext": { - "confirmCloseDirtyTab": "„{title}“ ohne Speichern schließen?", - "confirmCloseOtherDirtyTabs": "Andere Tabs mit ungespeicherten Änderungen schließen?", - "confirmCloseAllDirtyTabs": "Alle Tabs mit ungespeicherten Änderungen schließen?", - "unableLoadContent": "Inhalt konnte nicht geladen werden.\n\n{message}", - "previewRequestTimedOut": "Vorschauanfrage hat das Zeitlimit überschritten", - "diffRequestTimedOut": "Diff-Anfrage hat das Zeitlimit überschritten", - "branchCompareRequestTimedOut": "Branch-Vergleichsanfrage hat das Zeitlimit überschritten", - "commitDiffRequestTimedOut": "Commit-Diff-Anfrage hat das Zeitlimit überschritten", - "saveRequestTimedOut": "Speicheranfrage hat das Zeitlimit überschritten", - "reloadRequestTimedOut": "Neuladeanfrage hat das Zeitlimit überschritten", - "noChanges": "Keine Änderungen.", - "noDiffOutput": "Keine Diff-Ausgabe.", - "diffTitleWorkspace": "Diff · Arbeitsbereich", - "diffDescriptionWorkingTree": "Working Tree (HEAD)", - "diffTitleFile": "Unterschied · {name}", - "compareTitleFile": "Vergleich · {name}", - "compareTitleBranch": "Vergleich · {branch}", - "compareDescriptionPath": "{path} · vergleichen mit {branch}", - "compareDescriptionBranch": "vergleichen mit {branch}", - "diffTitleCommitFile": "Unterschied · {name} @ {hash}", - "diffTitleCommit": "Unterschied · {hash}", - "diffDescriptionCommitPath": "{path} · Commit {commit}", - "diffDescriptionCommit": "Commit {commit}", - "diffTitleConflictFile": "Konflikt · {name}", - "diffDescriptionConflict": "{path} · Disk vs ungespeichert" - }, - "chat": { - "acpConnections": { - "actions": { - "openAgentsSettings": "Agenten-Einstellungen öffnen", - "retry": "Erneut versuchen" - }, - "agentsSetupHint": "Öffnen Sie Einstellungen > Agenten, um die Installation zu verwalten.", - "withSetupHint": "{message}\n{hint}", - "blocked": { - "missingConfig": "Aktuelle Agenten-Konfiguration kann nicht gelesen werden.", - "disabled": "{agent} ist in den Agenten-Einstellungen deaktiviert. Aktivieren Sie ihn vor dem Verbinden.", - "unavailable": "{agent} ist auf der aktuellen Plattform nicht verfügbar.", - "sdkMissing": "{agent} SDK ist nicht installiert", - "adapterMissing": "Der ACP-Adapter von {agent} ist nicht installiert" - }, - "backendErrors": { - "initializeTimeout": "Der Verbindungs-Handshake von {agent} hat nach 60 Sekunden das Zeitlimit überschritten. Öffnen Sie die Einstellungen, um Agenten- und Netzwerkkonfiguration zu prüfen.", - "mcpRejectedByAgent": "{agent} hat die Sitzung abgelehnt, während codegs MCP-Begleitprozess angehängt war: {message} Falls dieser Agent MCP nicht unterstützt, deaktivieren Sie „MCP-Unterstützung“ in den Einstellungen und verbinden Sie erneut.", - "processExited": "{agent}-Prozess wurde unerwartet beendet.", - "spawnFailed": "{agent} konnte nicht gestartet werden: {message}", - "downloadFailed": "{agent}-Download fehlgeschlagen: {message}", - "sessionLoadResourceNotFound": "{agent}-Sitzung konnte nicht geladen werden. Neu laden, um es erneut zu versuchen, oder eine neue Konversation starten.", - "sessionLoadUnavailable": "{agent} konnte diese Sitzung nicht wiederherstellen – sie wurde möglicherweise beendet oder der Agent wurde gestoppt. Neu laden, um es erneut zu versuchen, oder eine neue Konversation starten.", - "turnFailedRefusal": "{agent} hat die Fortsetzung dieser Runde abgelehnt. Häufig deutet das auf einen Backend- oder Gateway-Fehler hin. Bitte prüfen Sie die Agent-Logs.", - "turnFailedMaxTokens": "{agent} hat das Token-Limit für diese Runde erreicht.", - "turnFailedMaxTurnRequests": "{agent} hat die maximale Anzahl zulässiger Anfragen für diese Runde erreicht.", - "turnFailedUnknown": "{agent} hat die Runde mit einem unbekannten Stoppgrund beendet.", - "grokModelSwitchIncompatibleAgent": "{agent} kann in einer bestehenden Unterhaltung nicht zu diesem Modell wechseln. Starte eine neue Sitzung, um es zu verwenden.", - "turnFailedEmpty": "{agent} hat die Runde ohne jegliche Antwort beendet.", - "turnFailedEmptyProtocol": "{agent} hat eine Ausgabe erzeugt, die codeg nicht auswerten konnte — die Agent-Version passt möglicherweise nicht zum Protokoll.", - "turnFailedEmptyMetadata": "{agent} hat in dieser Runde nur Statusaktualisierungen gesendet (Plan / Modus / Verbrauch) und keine Antwort.", - "detailsInAlerts": "Öffnen Sie die Warnungen in der Statusleiste und klappen Sie die Details auf, um die Ausgabe des Agents zu sehen." - }, - "unableReadAgentConfig": "Agenten-Konfiguration kann nicht gelesen werden: {message}", - "connectFailedTitle": "{agent} Verbindung fehlgeschlagen", - "toolFallbackTitle": "Werkzeug", - "eventErrorTitle": "Agentenfehler", - "notificationTurnComplete": "{agent} hat die Antwort abgeschlossen", - "notificationError": "{agent} Fehler: {message}", - "claudeApiRetry": { - "fallbackError": "authentication_failed", - "retryingWithMax": "erneuter Versuch {attempt}/{max}", - "retryingAttempt": "erneuter Versuch {attempt}", - "retrying": "erneuter Versuch", - "nextRetryIn": "nächster in {seconds}s", - "line": "{error}{status} · {retry}", - "lineWithDelay": "{error}{status} · {retry}, {delay}", - "httpStatus": " (HTTP {status})" - }, - "configOptionAdjusted": "{agent} hat {option} auf {actual} statt {requested} gesetzt" - }, - "connectionLifecycle": { - "tasks": { - "connectingTitle": "Verbinde mit {agent}", - "connectingDescription": "Verbindung wird hergestellt", - "loadingSelectorsTitle": "{agent}-Selektoren werden geladen", - "loadingSelectorsDescription": "Modus- und Sitzungsoptionen werden abgerufen", - "initSessionTitle": "Initializing {agent} session", - "initSessionDescription": "Creating session and loading configuration" - }, - "errors": { - "connectionFailed": "Verbindung fehlgeschlagen", - "sendPromptFailed": "Nachricht konnte nicht gesendet werden: {error}" - } - }, - "shared": { - "attachedResources": "Angehängte Ressourcen", - "toolCallFailed": "Tool-Aufruf fehlgeschlagen" - }, - "messageThread": { - "emptyTitle": "Noch keine Nachrichten", - "emptyDescription": "Starten Sie eine Unterhaltung, um hier Nachrichten zu sehen" - }, - "chatInput": { - "connecting": "Verbinden...", - "agentResponding": "{agent} antwortet...", - "sendMessage": "Nachricht senden..." - }, - "messageInput": { - "askAnything": "Fragen Sie alles...", - "removeAttachmentAria": "{name} entfernen", - "attachFiles": "Dateien anhängen", - "addActions": "Hinzufügen", - "quickMessages": "Schnellnachrichten", - "quickMessagesEmpty": "Noch keine Schnellnachrichten", - "quickMessagesLoading": "Wird geladen...", - "pasteAsPlainText": "Als reinen Text einfügen", - "cut": "Ausschneiden", - "copy": "Kopieren", - "selectAll": "Alles auswählen", - "pasteUnavailable": "Zwischenablage konnte nicht gelesen werden. Mit Strg/⌘V einfügen.", - "clipboardWriteFailed": "Schreiben in die Zwischenablage fehlgeschlagen. Bitte das Tastenkürzel verwenden.", - "quickMessageUntitled": "Ohne Titel", - "liveFeedback": "Live-Feedback", - "liveFeedbackDisabledHint": "Verfügbar, während der Agent arbeitet", - "dropFilesToAttach": "Dateien zum Anhängen ablegen", - "loadingSettings": "Einstellungen werden geladen...", - "loadingMode": "Modus wird geladen...", - "modeLabel": "Modus", - "toggleOn": "Ein", - "toggleOff": "Aus", - "agentSettings": "Agent-Einstellungen", - "searchModel": "Modelle suchen...", - "searchModelAria": "Modelle suchen", - "modelListLabel": "Modelle", - "noModels": "Keine Modelle gefunden", - "cancel": "Abbrechen", - "send": "Senden", - "forkAndSend": "Fork & Senden", - "queueMessage": "In Warteschlange stellen", - "steerIntoTurn": "In laufenden Turn einfügen", - "steerQueuedInstead": "Stattdessen in die Warteschlange gestellt – wird mit dem nächsten Turn gesendet.", - "steerFailed": "Konnte nicht in den laufenden Turn eingefügt werden", - "steerAttachmentsUnsupported": "Nur Text – Entwürfe mit Anhängen laufen über die Warteschlange.", - "slashCommands": "Slash-Befehle", - "slashSearchPlaceholder": "Befehle suchen...", - "slashSearchEmpty": "Keine passenden Befehle", - "experts": "Experten", - "office": "Büroarbeit", - "research": "Forschung", - "attachLocalUpload": "Lokale Datei hochladen", - "attachServerFile": "Serverdatei auswählen", - "attachUploadTooLarge": "{names} überschreitet das Upload-Limit von {limit}MB und wurde übersprungen.", - "attachUploadFailed": "Upload fehlgeschlagen: {names}.", - "attachUploadNotAFile": "{names} ist keine reguläre Datei (Verzeichnis oder Spezialdatei) und wurde übersprungen.", - "attachUploadQuotaExceeded": "Auf dem Server ist kein Upload-Speicher mehr verfügbar; {names} konnte nicht hochgeladen werden.", - "attachUploadInProgress": "Bilder werden noch hochgeladen – versuche es gleich noch einmal.", - "mentionEmpty": "Keine Treffer", - "mentionLoading": "Suche läuft…", - "mentionListLabel": "Erwähnungen", - "mentionMore": "Weitere Ergebnisse – tippe weiter, um zu filtern", - "mentionCount": "{count, plural, one {# Ergebnis} other {# Ergebnisse}}", - "mentionGroupFile": "Dateien", - "mentionGroupAgent": "Agenten", - "mentionGroupSession": "Sitzungen", - "mentionGroupCommit": "Commits", - "mentionGroupSkill": "Fähigkeiten" - }, - "messageQueue": { - "addToQueue": "Zur Warteschlange", - "saveEdit": "Speichern", - "cancelEdit": "Bearbeitung abbrechen", - "editItem": "Bearbeiten", - "deleteItem": "Entfernen" - }, - "welcomeInputPanel": { - "agentsSettingsPath": "Einstellungen > Agenten", - "autoConnectFallback": "Klicken Sie, um {path} zu öffnen und die Installation zu verwalten.", - "autoConnectAppend": "{message}. Klicken Sie, um {path} zu öffnen und die Installation zu verwalten.", - "enableAgentFirstPlaceholder": "Aktivieren Sie mindestens einen Agenten, bevor Sie eine Sitzung starten...", - "prepareSessionFailed": "Die Chat-Sitzung konnte nicht vorbereitet werden. Bitte versuche es erneut.", - "createConversationFailed": "Die Konversation konnte nicht erstellt werden. Bitte versuche es erneut.", - "askAnythingPlaceholder": "Fragen Sie alles...", - "agentNotInstalled": "{agent} ist nicht installiert · in den Agents-Einstellungen installieren", - "agentAdapterNotInstalled": "Der ACP-Adapter von {agent} ist nicht installiert (unabhängig von deiner eigenen CLI) · in den Agents-Einstellungen installieren" - }, - "welcomePanel": { - "greeting": "Was möchtest du heute machen?", - "tips": { - "tileTabs": "Klicke mit der rechten Maustaste auf einen Konversations-Tab und wähle Kachelansicht, um mehrere Sitzungen nebeneinander zu sehen.", - "pinTab": "Doppelklicke auf einen Konversations-Tab, um ihn anzuheften – so wird er nicht von einer neuen Sitzung automatisch ersetzt.", - "shortcutsNewSearch": "{newConversation} öffnet eine neue Konversation, {searchConversations} durchsucht den Verlauf.", - "slashAtMention": "Tippe / im Eingabefeld für Slash-Befehle oder @, um eine Datei aus dem Projekt zu referenzieren.", - "pasteDropFiles": "Füge einen Screenshot ein oder ziehe eine Datei direkt ins Eingabefeld, um sie anzuhängen.", - "queueMessage": "Während der Agent antwortet, kannst du weitertippen – deine nächste Nachricht wird in die Warteschlange gestellt und automatisch gesendet.", - "draftAutoSave": "Nicht gesendete Entwürfe werden pro Konversation automatisch gespeichert und beim Zurückkehren wiederhergestellt.", - "forkSend": "Im Dropdown der Senden-Schaltfläche gibt es Verzweigen und senden – verzweige vom aktuellen Punkt in einen neuen Tab.", - "exportConversation": "Klicke mit der rechten Maustaste in die Konversation, um sie als Markdown, HTML oder Bild zu exportieren.", - "chatChannels": "Verbinde Telegram / Lark / WeChat unter Einstellungen → Chat-Kanäle, um vom Handy aus weiterzuarbeiten.", - "shortcutsAuxPanel": "{toggleAuxPanel} blendet das rechte Panel ein – mit den geänderten Dateien und Git-Änderungen dieser Sitzung.", - "shortcutsTerminalSidebar": "{toggleTerminal} öffnet das eingebaute Terminal, {toggleSidebar} schaltet die Seitenleiste um.", - "customShortcuts": "Alle Tastenkürzel lassen sich unter Einstellungen → Tastenkürzel frei belegen.", - "webService": "Aktiviere Einstellungen → Webdienst, damit Teammitglieder dasselbe codeg im Browser nutzen können.", - "fusionMode": "Öffne eine Datei oder ein Diff, um es automatisch neben der Konversation zu sehen.", - "quickMessages": "Klicke auf die +-Schaltfläche neben der Eingabe und wähle Schnellnachrichten, um ein gespeichertes Snippet einzufügen (verwaltbar unter Einstellungen → Schnellnachrichten).", - "experts": "Die +-Schaltfläche hat ein Menü Expertenfähigkeiten – lade Rollen wie Debugging oder Planung mit einem Klick.", - "taskBoard": "To-dos führen eine Aufgabe von Anfang bis Ende aus: Der Agent arbeitet in einem eigenen Worktree, du prüfst das Diff und mergest.", - "automations": "Automatisierungen führen einen gespeicherten Prompt nach Zeitplan aus – etwa ein nächtliches Review – und jeder Lauf kann einen eigenen Worktree bekommen.", - "tokenUsage": "Klicke auf die Konversationszahl in der Statusleiste, um den Token-Verbrauch zu öffnen – aufgeschlüsselt nach Tag, Agent, Modell und Ordner.", - "mentionTargets": "@ holt mehr als Dateien: Erwähne einen anderen Agenten, um eine Teilaufgabe abzugeben, oder verweise auf eine frühere Sitzung, einen Commit oder einen Skill.", - "splitGroups": "Rechtsklick auf einen Tab, dann Nach rechts teilen oder Nach unten teilen – so bleiben zwei Konversationen in eigenen Bereichen offen.", - "worktrees": "Öffne die Branch-Schaltfläche und wähle Neuer Worktree, damit mehrere Agenten dasselbe Repository bearbeiten, ohne sich gegenseitig die Dateien zu überschreiben.", - "importSessions": "Schon Sitzungen im Terminal gelaufen? Im Menü eines Ordners holt Lokale Sitzungen importieren diesen Verlauf nach codeg.", - "subSessions": "Delegiert ein Agent, erscheint die Untersitzung in der Seitenleiste verschachtelt darunter – klapp die Zeile auf, um jeder einzeln zu folgen.", - "liveFeedback": "Live-Feedback im +-Menü schiebt eine Notiz in den Zug, den der Agent gerade ausführt – ohne ihn zu unterbrechen.", - "skillPacks": "Einstellungen → Skill-Pakete bündelt Coding-Experten, wissenschaftliche Recherche und Office-Skills – pro Agent aktivierbar.", - "modelProviders": "Einstellungen → Modellanbieter nimmt deinen eigenen API-Key oder Endpunkt entgegen; das Modell wählst du danach direkt im Eingabefeld.", - "workspaceBackground": "Einstellungen → Darstellung setzt ein Hintergrundbild für den Arbeitsbereich, die Panel-Deckkraft und die Schriftarten der App." - }, - "quickActions": { - "excel": "Excel-Arbeitsmappe", - "excelDesc": "Datentabellen, Formeln & Diagramme", - "word": "Word-Dokument", - "wordDesc": "Berichte, Briefe & Memos", - "ppt": "Präsentation", - "pptDesc": "Folien mit professionellem Design", - "pitchDeck": "Pitch Deck", - "pitchDeckDesc": "Investoren-Deck mit Kennzahlen", - "morph": "Morph-Animation", - "morphDesc": "Filmreife Folienübergänge", - "morph3d": "3D-Morph", - "morph3dDesc": "3D-Modelle mit Kamerafahrten", - "academic": "Wissenschaftliche Arbeit", - "academicDesc": "Forschung mit Zitaten & Struktur", - "financial": "Finanzmodell", - "financialDesc": "Abschlüsse, DCF & Prognosen", - "dashboard": "Daten-Dashboard", - "dashboardDesc": "KPIs & Analysen aus deinen Daten", - "prompts": { - "excel": "Erstelle eine Excel-Arbeitsmappe mit den folgenden Anforderungen:\n\n[beschreibe hier deine Daten, Tabellen, Formeln und Diagramme]", - "word": "Erstelle ein Word-Dokument mit den folgenden Anforderungen:\n\n[beschreibe hier Inhalt, Struktur und Formatierung des Dokuments]", - "ppt": "Erstelle eine PowerPoint-Präsentation mit den folgenden Anforderungen:\n\n[beschreibe hier deine Folien, Inhalte und das Design]", - "pitchDeck": "Erstelle ein Investoren-Pitch-Deck mit den folgenden Anforderungen:\n\n[beschreibe hier dein Unternehmen, die Finanzierungsrunde und die wichtigsten Kennzahlen]", - "morph": "Erstelle eine Präsentation mit Morph-Übergangsanimationen:\n\n[beschreibe hier das Thema der Präsentation und die gewünschten visuellen Effekte]", - "morph3d": "Erstelle eine 3D-Morph-Präsentation mit GLB-Modellen und Kamerafahrten:\n\n[beschreibe hier dein Thema und das visuelle 3D-Konzept]", - "academic": "Schreibe eine wissenschaftliche Arbeit in Word mit den folgenden Anforderungen:\n\n[beschreibe hier dein Forschungsthema, die Methodik und die wichtigsten Ergebnisse]", - "financial": "Erstelle ein Finanzmodell in Excel mit den folgenden Anforderungen:\n\n[beschreibe hier deine Finanzabschlüsse, Prognosen und Analysen]", - "dashboard": "Erstelle ein Daten-Dashboard in Excel mit den folgenden Anforderungen:\n\n[beschreibe hier deine Datenquelle, KPIs und Diagramme]", - "scientific-brainstorming": "Hilf mir beim Brainstorming von Forschungsrichtungen — erkunde interdisziplinäre Verbindungen, hinterfrage Annahmen und finde vielversprechende Lücken. Mein Themenbereich: ", - "hypothesis-generation": "Hilf mir, diese Beobachtungen in prüfbare Hypothesen zu überführen — mit klaren Vorhersagen, plausiblen Mechanismen und Experimenten. Meine Beobachtungen: ", - "experimental-design": "Hilf mir, vor der Datenerhebung ein rigoroses Experiment zu planen — Design, Randomisierung, Kontrollen und wie man Confounding vermeidet. Was ich untersuchen möchte: ", - "statistical-power": "Hilf mir, die benötigte Stichprobengröße zu bestimmen — führe mich durch eine Poweranalyse (Effektstärke, Alpha, Power) für mein Design. Details: ", - "statistical-analysis": "Hilf mir, diese Daten korrekt zu analysieren — den richtigen Test wählen, Annahmen prüfen, Effektstärken berichten und alles aufschreiben. Meine Daten und Frage: ", - "exploratory-data-analysis": "Führe eine explorative Analyse meiner Datendatei durch — fasse Struktur, Qualität und auffällige Muster zusammen und schlage nächste Schritte vor. Die Datei ist: ", - "scientific-visualization": "Hilf mir, eine publikationsreife Abbildung zu erstellen — klares Layout, ehrliche Fehlerbalken, eine farbenblindensichere Palette und Journal-Formatierung. Was ich zeigen möchte: ", - "scientific-critical-thinking": "Hilf mir, diese Studie oder Behauptung kritisch zu bewerten — beurteile die Evidenzqualität, erkenne Verzerrungen und Confounder und wäge die Schlussfolgerungen ab. Hier ist sie: ", - "paper-lookup": "Hilf mir, relevante Artikel und Open-Access-Volltexte in wissenschaftlichen Datenbanken zu finden, mit wiederverwendbaren Zitaten. Ich suche: " - }, - "paper-lookup": "Publikationssuche", - "paper-lookupDesc": "10 wissenschaftliche APIs (PubMed, arXiv, OpenAlex, Crossref…) nach Artikeln, Zitationen und Open-Access-Volltext durchsuchen.", - "scientific-critical-thinking": "Kritisches Denken", - "scientific-critical-thinkingDesc": "Wissenschaftliche Aussagen und Evidenzqualität beurteilen — Verzerrungen und Confounder erkennen, GRADE anwenden.", - "scientific-visualization": "Wissenschaftliche Visualisierung", - "scientific-visualizationDesc": "Publikationsreife Abbildungen — Mehrfeld-Layouts, Signifikanz-Annotationen und journalspezifische Formate.", - "exploratory-data-analysis": "Explorative Datenanalyse", - "exploratory-data-analysisDesc": "Automatisierte Exploration wissenschaftlicher Datendateien in über 200 Formaten mit Qualitätsmetriken und Berichten.", - "statistical-analysis": "Statistische Analyse", - "statistical-analysisDesc": "Geführte statistische Analyse — Testauswahl, Annahmenprüfung, Effektstärken und Bericht im APA-Stil.", - "statistical-power": "Teststärke", - "statistical-powerDesc": "Stichprobengröße und Teststärke — benötigte Fallzahl, minimal nachweisbare Effekte und Powerkurven.", - "experimental-design": "Versuchsplanung", - "experimental-designDesc": "Rigorose Studien vor der Datenerhebung planen — Randomisierung, Blockbildung, Kontrollen und faktorielle/DOE-Designs.", - "hypothesis-generation": "Hypothesengenerierung", - "hypothesis-generationDesc": "Beobachtungen in prüfbare Hypothesen mit Vorhersagen, Mechanismen und Experimenten überführen.", - "scientific-brainstorming": "Wissenschaftliches Brainstorming", - "scientific-brainstormingDesc": "Offene Forschungsideen — interdisziplinäre Verbindungen erkunden, Annahmen hinterfragen, Forschungslücken finden.", - "tabs": { - "office": "Büroarbeit", - "coding": "Code-Entwicklung", - "research": "Forschung" - }, - "coding": { - "brainstormingDesc": "Absicht & Anforderungen vor dem Bauen klären", - "debuggingDesc": "Erst die Ursache finden, dann Fixes vorschlagen", - "writingSkillsDesc": "Wiederverwendbare Skills erstellen, bearbeiten & prüfen" - }, - "notEnabled": { - "title": "Skill „{skill}“ ist für {agent} noch nicht aktiviert", - "description": "Aktiviere ihn in den Einstellungen, um ihn hier zu nutzen.", - "action": "Aktivieren", - "hint": "Skill nicht aktiviert" - }, - "scrollPrev": "Vorherige Skills anzeigen", - "scrollNext": "Weitere Skills anzeigen" - } - }, - "agentSelector": { - "noEnabledAgents": "Keine aktivierten Agenten", - "openAgentsSettings": "Agenten-Einstellungen öffnen", - "notInstalled": "Nicht installiert", - "moreAgents": "Weitere Agenten ({count})" - }, - "subAgentOverlay": { - "title": "Subagenten", - "collapsedSummary": "Subagenten {count}", - "collapseAria": "Subagenten einklappen" - }, - "agentPlanOverlay": { - "title": "Agentenplan", - "collapsePlanAria": "Plan einklappen", - "collapsedSummary": "Arbeitsplan {completed}/{total}", - "status": { - "completed": "Abgeschlossen", - "inProgress": "In Bearbeitung", - "pending": "Ausstehend", - "unknown": "Unbekannt" - }, - "priority": { - "high": "Hoch", - "medium": "Mittel", - "low": "Niedrig", - "unknown": "Unbekannt" - } - }, - "permissionDialog": { - "subtitle": "Agent fordert Berechtigung an, um diesen Zug fortzusetzen.", - "queuedCount": "+{count} wartend", - "kindFallbackTool": "Tool", - "command": "Befehl", - "cwd": "Arbeitsverzeichnis: {cwd}", - "filesSummary": "Dateien: {count}", - "moreFiles": "+{count} weitere Dateien", - "plan": "Arbeitsplan", - "allowedActions": "Erlaubte Aktionen", - "targetMode": "Zielmodus: {mode}", - "optionGrants": "Was jede Option gewährt", - "changeScopeSession": "Diese Sitzung", - "changeScopeProcess": "Dieser Lauf", - "changeScopeUser": "In Benutzereinstellungen gespeichert", - "changeScopeProject": "In Projekteinstellungen gespeichert", - "changeScopeProjectLocal": "In lokalen Projekteinstellungen gespeichert", - "changeScopePersistent": "Dauerhaft gespeichert" - }, - "questionDialog": { - "title": "Agent stellt eine Frage", - "placeholder": "Antwort eingeben...", - "send": "Senden" - }, - "messageBranch": { - "previousBranchAria": "Vorheriger Branch", - "nextBranchAria": "Nächster Branch", - "pageOf": "{current} von {total}" - }, - "terminal": { - "title": "Konsole", - "running": "Läuft" - }, - "reasoning": { - "thinking": "Denkt nach…", - "thoughtForFewSeconds": "Nachgedacht", - "thoughtForSeconds": "Nachgedacht" - }, - "linkSafety": { - "errorCannotOpen": "Lokale Datei kann nicht geöffnet werden", - "errorNoWorkspace": "Es ist kein Arbeitsbereichsordner aktiv.", - "errorFailedOpen": "Lokale Datei konnte nicht geöffnet werden", - "errorFailedLink": "Link konnte nicht geöffnet werden", - "errorUnsupportedLinkProtocol": "Dieses Linkprotokoll wird nicht unterstützt." - }, - "fileActions": { - "openInFinder": "In Finder öffnen", - "openInExplorer": "In Explorer öffnen", - "openInFileManager": "Im Dateimanager öffnen", - "copyRelativePath": "Relativen Pfad kopieren", - "copyAbsolutePath": "Absoluten Pfad kopieren", - "pathCopied": "Pfad kopiert", - "copyPathFailed": "Pfad konnte nicht kopiert werden", - "openFailed": "Lokale Datei konnte nicht geöffnet werden" - }, - "messageList": { - "attachedResources": "Angehängte Ressourcen", - "loading": "Lädt...", - "loadEarlier": "Frühere Nachrichten laden", - "loadingEarlier": "Frühere Nachrichten werden geladen…", - "error": "Fehler: {message}", - "errorTitle": "Sitzung konnte nicht geladen werden", - "errorActionReload": "Neu laden", - "errorActionNewSession": "Neue Konversation", - "emptyConversation": "Keine Nachrichten in dieser Unterhaltung.", - "systemMessage": "Systemnachricht", - "copyMessage": "Kopieren", - "copied": "Kopiert", - "downloadImage": "Bild herunterladen", - "downloadFailed": "Download fehlgeschlagen: {message}", - "imageGeneration": "Bildgenerierung", - "imageGenerationPending": "Bild wird generiert…", - "imageGenerationFailed": "Bildgenerierung fehlgeschlagen", - "model": "Modell", - "tokenStats": "Token-Nutzung", - "tokenInput": "Eingabe", - "tokenOutput": "Ausgabe", - "tokenCacheRead": "Cache-Lesen", - "tokenCacheWrite": "Cache-Schreiben", - "duration": "Dauer", - "completedAt": "Abgeschlossen um", - "jumpToPreviousUserMessage": "Zur Benutzernachricht springen", - "showMore": "Mehr anzeigen", - "showLess": "Weniger anzeigen" - }, - "liveTurnStats": { - "thinking": "Denkt nach...", - "streaming": "Übertragung", - "elapsedHours": "{value} Std", - "elapsedMinutes": "{value} Min", - "elapsedSeconds": "{value} Sek", - "outputSpeedAria": "Geschätzte Ausgabegeschwindigkeit", - "outputSpeedTooltip": "Geschätzte Ausgabegeschwindigkeit (Text + Denken)" - }, - "jsonTree": { - "viewRaw": "Rohes JSON anzeigen", - "viewTree": "Baum anzeigen", - "fields": "{count, plural, one {# Feld} other {# Felder}}", - "items": "{count, plural, one {# Eintrag} other {# Einträge}}" - }, - "tool": { - "parameters": "Parameter", - "error": "Fehler", - "result": "Ergebnis", - "status": { - "approvalRequested": "Warten auf Genehmigung", - "approvalResponded": "Beantwortet", - "inputAvailable": "Läuft", - "inputStreaming": "Ausstehend", - "outputAvailable": "Abgeschlossen", - "outputDenied": "Abgelehnt", - "outputError": "Fehler" - } - }, - "toolCallBlock": { - "tool": "Werkzeug", - "error": "Fehler", - "result": "Ergebnis" - }, - "delegation": { - "subAgentRunning": "Unteragent läuft…", - "noDetail": "No detail available yet.", - "unknownAgent": "Sub-Agent", - "openDetail": "Konversation anzeigen", - "detailTitle": "Unteragent-Konversation", - "detailDescription": "Schreibgeschützte Ansicht der delegierten Unteragent-Konversation.", - "waitForResult": "Warte auf das Ergebnis von Aufgabe {task}", - "waitForResultNoTask": "Warte auf das Aufgabenergebnis", - "cancelTask": "Aufgabe {task} wird abgebrochen", - "cancelTaskNoTask": "Aufgabe wird abgebrochen", - "resultPageOf": "{current} / {total}", - "prevResult": "Vorheriges Ergebnis", - "nextResult": "Nächstes Ergebnis", - "noResultText": "Kein Ergebnis bei dieser Prüfung.", - "status": { - "starting": "startet", - "running": "läuft", - "checked": "geprüft", - "waiting": "Genehmigung ausstehend", - "ok": "fertig", - "err": { - "default": "fehlgeschlagen", - "delegation_disabled": "deaktiviert", - "depth_limit": "Tiefenlimit", - "invalid_agent_type": "ungültiger Agent", - "spawn_failed": "Start fehlgeschlagen", - "send_failed": "Senden fehlgeschlagen", - "timeout": "Zeitüberschreitung", - "canceled": "abgebrochen", - "child_refusal": "Subagent verweigerte", - "child_max_tokens": "Subagent: Token-Limit", - "child_max_turn_requests": "Subagent: Anfragelimit", - "child_empty": "Subagent ohne Ausgabe", - "child_unknown": "Subagent: Fehler", - "unknown": "unbekannte Aufgabe" - } - } - }, - "contentParts": { - "showingTailOutput": "Zur besseren Performance wird während des Streamings nur die Endausgabe angezeigt.", - "result": "Ergebnis", - "unknown": "unbekannt", - "inputTruncated": "Eingabe wurde gekürzt — Diff ist möglicherweise unvollständig.", - "replaceAll": "ALLES ERSETZEN", - "filesCount": "Dateien: {count}", - "update": "aktualisieren", - "moreFiles": "+{count} weitere Dateien", - "timeoutMs": "Zeitlimit: {timeout}ms", - "backgroundTrue": "Hintergrund: true", - "scriptToolCalls": "{count, plural, one {# Tool-Aufruf} other {# Tool-Aufrufe}}", - "offset": "Versatz: {offset}", - "limit": "Grenze: {limit}", - "pages": "Seiten: {pages}", - "mode": "Modus: {mode}", - "cell": "Zelle: {cell}", - "shellSession": "Sitzung {id}", - "pathLabel": "Pfad:", - "globLabel": "Glob-Muster:", - "typeLabel": "Typ:", - "outputLabel": "Ausgabe:", - "caseInsensitive": "Groß-/Kleinschreibung ignorieren", - "multiline": "Mehrzeilig", - "promptLabel": "Eingabe", - "subjectLabel": "Betreff", - "taskLabel": "Aufgabe", - "nameLabel": "Bezeichnung:", - "agentPromptLabel": "Eingabe", - "agentModelLabel": "Modell", - "agentRunning": "Läuft...", - "agentLiveTranscript": "Live-Aktivität", - "agentProgressTools": "{count} Tool-Aufrufe", - "agentProgressTurns": "{count} Runden", - "agentProgressContext": "Kontext {pct}%", - "agentSessionAction": "Subagent-Sitzung ansehen", - "agentSessionTitle": "Subagent-Sitzung", - "agentSessionLoading": "Protokoll des Subagenten wird geladen…", - "agentSessionEmpty": "Der Subagent hat noch nichts geschrieben.", - "agentFallbackTitle": "Sub-Agent wird gestartet…", - "agentCodexLaunchOnly": "Gestartet. Codex meldet keinen weiteren Fortschritt dieses Sub-Agenten – sein Ergebnis trifft als Nachricht in dieser Unterhaltung ein.", - "agentStatsBash": "Befehle", - "agentStatsRead": "Dateien gelesen", - "agentStatsSearch": "Suchen", - "agentStatsEdit": "Bearbeitungen", - "agentStatsOther": "Sonstige", - "goal": { - "title": "Ziel:", - "titleWithStatus": "Ziel {status}", - "objective": "Ziel", - "statusLabel": "Status", - "tokensUsed": "Verwendete tokens", - "budget": "Budget", - "remaining": "Verbleibend", - "elapsed": "Verstrichen", - "tokens": "tokens", - "pause": "Pausieren", - "clear": "Löschen", - "status": { - "active": "aktiv", - "paused": "pausiert", - "blocked": "blockiert", - "usageLimited": "Nutzung begrenzt", - "budgetLimited": "Budget begrenzt", - "complete": "abgeschlossen", - "limited": "Limit erreicht" - } - }, - "field": { - "file": "Datei", - "notebook": "Notizbuch", - "command": "Befehl", - "old": "Alt", - "new": "Neu", - "pattern": "Muster", - "path": "Pfad", - "query": "Abfrage", - "url": "URL:", - "description": "Beschreibung", - "content": "Inhalt", - "source": "Quelle", - "prompt": "Eingabe", - "subject": "Betreff", - "taskId": "Aufgaben-ID", - "status": "Zustand", - "skill": "Skill", - "args": "Argumente", - "offset": "Versatz", - "limit": "Grenze", - "glob": "Glob-Muster", - "type": "Typ", - "output": "Ausgabe", - "replaceAll": "Alles ersetzen", - "language": "Sprache", - "timeout": "Zeitlimit", - "background": "Hintergrund", - "agentType": "Agent-Typ", - "library": "Bibliothek", - "libraryId": "Bibliotheks-ID" - }, - "title": { - "edit": "Bearbeiten", - "command": "Befehl", - "script": "Skript", - "waitCommand": "Warten {command}", - "waitCell": "Sitzung {id} abwarten", - "terminateCommand": "Beenden {command}", - "terminateCell": "Sitzung {id} beenden", - "stdinChars": "Eingabe {chars}", - "todoWrite": "TodoWrite (Aufgaben aktualisieren)", - "read": "Lesen", - "write": "Schreiben", - "notebookEdit": "NotebookEdit (Notizbuch bearbeiten)", - "editFiles": "Bearbeiten ({count} Dateien)", - "editWithTarget": "{target} bearbeiten", - "readWithTarget": "{target} lesen", - "writeWithTarget": "{target} schreiben", - "notebookEditWithTarget": "NotebookEdit ({target})", - "globWithPattern": "Glob-Muster {pattern}", - "listFilesWithPath": "Dateien auflisten {path}", - "grepWithPattern": "Grep-Muster {pattern}", - "taskCreateWithSubject": "Aufgabe erstellen: {subject}", - "taskUpdateWithStatus": "Aufgabe aktualisieren #{id} -> {status}", - "taskUpdate": "Aufgabe aktualisieren #{id}", - "webFetchWithUrl": "WebFetch ({url})", - "webSearchWithQuery": "Websuche: {query}", - "todosProgress": "Aufgaben ({done}/{total})", - "skillWithName": "Skill: {name}", - "genericWithContext": "{tool} ({context})" - }, - "search": { - "noMatches": "Keine Treffer", - "matchSummary": "{matches, plural, one {# Treffer} other {# Treffer}} in {files, plural, one {# Datei} other {# Dateien}}", - "fileSummary": "{files, plural, one {# Datei} other {# Dateien}}", - "moreResults": "{count, plural, one {# weiteres Ergebnis nicht angezeigt} other {# weitere Ergebnisse nicht angezeigt}}" - }, - "toolGroup": { - "search": "{count, plural, one {# Suche durchgeführt} other {# Suchen durchgeführt}}", - "command": "{count, plural, one {# Befehl ausgeführt} other {# Befehle ausgeführt}}", - "read": "{count, plural, one {Dateien # Mal gelesen} other {Dateien # Mal gelesen}}", - "memory": "{count, plural, one {# Erinnerung abgerufen} other {# Erinnerungen abgerufen}}", - "edit": "{count, plural, one {Dateien # Mal bearbeitet} other {Dateien # Mal bearbeitet}}", - "fetch": "{count, plural, one {# Ressource abgerufen} other {# Ressourcen abgerufen}}", - "think": "{count, plural, one {# Mal nachgedacht} other {# Mal nachgedacht}}", - "todo": "{count, plural, one {# Aufgabe aktualisiert} other {# Aufgaben aktualisiert}}", - "task": "{count, plural, one {# Aufgabe ausgeführt} other {# Aufgaben ausgeführt}}", - "other": "{count, plural, one {# Werkzeug verwendet} other {# Werkzeuge verwendet}}", - "errorSuffix": "{count, plural, one {# fehlgeschlagen} other {# fehlgeschlagen}}", - "joiner": " · " - }, - "planMode": { - "entered": "Planungsmodus gestartet", - "planLabel": "Plan", - "reviewApproved": "Plan genehmigt – wird umgesetzt", - "reviewKept": "Im Planmodus geblieben", - "reviewPending": "Warte auf Planentscheidung", - "submitted": "Plan eingereicht", - "switched": "Modus gewechselt" - }, - "backgroundTask": { - "title": "Hintergrundaufgabe", - "titleWithId": "Hintergrundaufgabe · {id}", - "running": "Läuft", - "completed": "Abgeschlossen", - "failed": "Fehlgeschlagen", - "stopped": "Gestoppt", - "exitCode": "Exit {code}", - "polledTimes": "{count}-mal abgefragt", - "runningInBackground": "Hintergrund", - "launchNote": "Läuft im Hintergrund · {id}" - }, - "codexScript": { - "outputMissing": "Codex hat die Skriptausgabe gekürzt und dabei das Trennzeichen dieses Befehls entfernt, sodass ihm keine Ausgabe zugeordnet werden konnte.", - "sharedWith": "Enthält auch die Ausgabe von {commands} – codex hat deren Trennzeichen abgeschnitten.", - "truncated": "gekürzt" - } - }, - "messageNav": { - "title": "Nachrichtennavigation", - "collapse": "Nachrichtennavigation ausblenden", - "collapsedSummary": "Nachrichten {count}", - "fileCount": "{count, plural, one {# Datei} other {# Dateien}}", - "remove": "Entfernen", - "noDiffDataAvailable": "Keine Diff-Daten verfügbar für {filePath}" - }, - "replyArtifacts": { - "title": "Geänderte Dateien", - "fileCount": "{count, plural, one {# Datei} other {# Dateien}}", - "newFilesTitle": "Neue Dateien", - "revealInFolder": "Im Dateimanager anzeigen", - "openFile": "{filePath} öffnen", - "openInEditor": "Im Editor öffnen", - "remove": "Entfernen", - "noDiffDataAvailable": "Keine Diff-Daten verfügbar für {filePath}" - }, - "askQuestion": { - "title": "Der Agent benötigt deine Auswahl", - "subtitle": "Antworten und absenden. Du kannst jederzeit überspringen.", - "recommended": "Empfohlen", - "other": "Andere", - "otherPlaceholder": "Antwort eingeben…", - "singleSelect": "Einfach", - "multiSelect": "Mehrfach", - "skip": "Überspringen", - "next": "Weiter", - "submit": "Senden", - "submitError": "Senden fehlgeschlagen. Bitte versuche es erneut." - }, - "planApproval": { - "title": "Der Agent hat einen Plan – bitte prüfen", - "emptyPlan": "Der Agent hat keinen Plan geschrieben. Genehmige, um zu starten, oder fordere Änderungen an.", - "approve": "Genehmigen & starten", - "requestChanges": "Änderungen anfordern", - "abandon": "Verwerfen", - "feedbackPlaceholder": "Was soll geändert werden?", - "sendChanges": "Senden", - "cancel": "Abbrechen", - "submitError": "Senden fehlgeschlagen. Bitte erneut versuchen." - }, - "feedbackCheckResult": { - "count": "{count, plural, =1 {1 Rückmeldung} other {# Rückmeldungen}}", - "expand": "Alle Rückmeldungen anzeigen", - "collapse": "Einklappen", - "errorTitle": "Feedback-Prüfung fehlgeschlagen" - }, - "askQuestionResult": { - "title": "Frage", - "answeredLabel": "Frage & Antwort:", - "awaiting": "Warten auf deine Antwort…", - "declined": "Du hast dies verworfen – der Agent hat nach eigenem Ermessen entschieden.", - "noSelection": "Keine Auswahl" - }, - "configStale": { - "agentConfigTitle": "Agent-Einstellungen aktualisiert", - "modelProviderTitle": "Modellanbieter aktualisiert", - "description": "Diese Sitzung verwendet weiterhin die bisherige Konfiguration. Zum Anwenden neu verbinden (der Gesprächsverlauf bleibt erhalten).", - "reconnect": "Zum Anwenden neu verbinden", - "reconnecting": "Wird neu verbunden…", - "reconnectDisabledDuringTurn": "Verfügbar, sobald die aktuelle Runde abgeschlossen ist", - "dismiss": "Schließen", - "reconnectFailed": "Sitzung konnte nicht neu verbunden werden", - "applied": "Neue Konfiguration angewendet" - }, - "piProjectTrust": { - "title": "Dieses Projekt enthält pi-Ressourcen", - "description": "pi lädt die .pi-Dateien des Repositorys nicht. Prüfe sie, um zu entscheiden.", - "descriptionExecutable": "Das Repository enthält pi-Erweiterungen, die beim Start Code ausführen. pi lädt sie nicht. Prüfe sie, bevor du entscheidest.", - "review": "Prüfen…", - "dismiss": "Ausblenden", - "dialogTitle": "Den pi-Ressourcen dieses Projekts vertrauen?", - "dialogDescription": "pi lädt die .pi-Dateien eines Repositorys nur, wenn du dem Ordner vertraust. Vertraue nur, wenn du dem Inhalt dieses Repositorys vertraust.", - "executionWarning": "Erweiterungen sind Code. Wenn du diesem Ordner vertraust, führt das Repository sie beim Start von pi mit deinen Rechten aus – noch bevor du eine Nachricht sendest.", - "scopeNote": "Die Entscheidung wird in der trust.json von pi für diesen Ordner gespeichert, gilt für alle darin enthaltenen Ordner und wird auch verwendet, wenn du pi selbst im Terminal startest. Du kannst sie später unter Einstellungen → Agenten → Pi ändern.", - "trust": "Projekt vertrauen", - "decline": "Nicht laden", - "disabledDuringTurn": "Verfügbar, sobald der aktuelle Zug beendet ist", - "trustedToast": "Projekt vertraut – neu verbunden, damit pi seine Ressourcen lädt", - "declinedToast": "Projektressourcen bleiben ungeladen", - "saveFailed": "Die Vertrauensentscheidung für das Projekt konnte nicht gespeichert werden", - "grantTitle": "Diesem Projekt wird bereits vertraut", - "grantDescription": "pi lädt die .pi-Dateien dieses Repositorys. Sieh dir an, was das erlaubt.", - "grantInheritedDescription": "Einem übergeordneten Ordner wird vertraut, daher lädt pi die .pi-Dateien dieses Repositorys. Sieh dir an, was das erlaubt.", - "grantDialogTitle": "Den pi-Ressourcen dieses Projekts wird vertraut", - "grantDialogDescription": "pi darf die .pi-Dateien dieses Repositorys laden. Frühere codeg-Versionen haben das beim Öffnen eines Ordners automatisch erteilt, du wurdest also womöglich nie gefragt.", - "grantExecutionWarning": "Erweiterungen sind Code. Das Repository führt sie beim Start von pi mit deinen Rechten aus, bevor du eine Nachricht sendest.", - "inheritedFrom": "Vertraut über", - "revoke": "Vertrauen widerrufen", - "keepTrusted": "Vertrauen behalten", - "revokedToast": "Vertrauen widerrufen – neu verbunden, damit pi die Projektressourcen nicht mehr lädt", - "trustedNoReconnect": "Projekt vertraut – gilt ab dem nächsten Start von pi", - "revokedNoReconnect": "Vertrauen widerrufen – gilt ab dem nächsten Start von pi" - }, - "collabAgent": { - "title": "Subagent", - "errorTitle": "Subagent-Aufgabe fehlgeschlagen", - "statesLabel": "Subagenten", - "statusRunning": "Läuft", - "statusCompleted": "Abgeschlossen", - "statusFailed": "Fehlgeschlagen", - "statusPending": "Wird gestartet", - "statusInterrupted": "Unterbrochen", - "statusClosed": "Geschlossen", - "statusNotFound": "Nicht gefunden", - "opSpawn": "Sub-Agent wird gestartet", - "opWait": "Sub-Agent-Ergebnis wird abgerufen", - "opClose": "Sub-Agent wird geschlossen", - "opResume": "Sub-Agent wird fortgesetzt" - }, - "contextCompaction": { - "compacting": "Kontext wird komprimiert…", - "compacted": "Kontext komprimiert", - "compactedTokens": "Kontext komprimiert · {before} → {after} Tokens", - "failed": "Kontextkomprimierung fehlgeschlagen" - }, - "sessionFailure": { - "category": { - "connection": "Verbindungsproblem", - "access": "Zugriffsproblem", - "limit": "Limit erreicht", - "request": "Anfrage abgelehnt", - "service": "Dienstproblem", - "unknown": "Sitzungsproblem" - }, - "action": { - "retry": "Erneut versuchen", - "login": "Anmelden", - "newSession": "Neue Sitzung" - }, - "recovered": "Wiederhergestellt", - "retryUnavailable": "Keine vorherige Nachricht zum erneuten Senden.", - "toggleDetails": "Details umschalten" - }, - "backgroundTasks": { - "running": "{count, plural, one {# Hintergrundaufgabe läuft} other {# Hintergrundaufgaben laufen}}", - "settling": "Hintergrundergebnisse werden synchronisiert…", - "settledFallback": "Hintergrundaufgabe beendet ({status})", - "cardRunning": "Läuft im Hintergrund", - "cardLaunchedPending": "Hintergrundaufgabe gestartet", - "cardCompleted": "Hintergrundaufgabe abgeschlossen", - "cardFinishedWithStatus": "Hintergrundaufgabe beendet ({status})", - "cardResultPending": "Ergebnis steht noch aus" - }, - "proposedPlan": { - "title": "Vorgeschlagener Plan", - "planning": "Wird geplant…" - } - }, - "diffPreview": { - "mode": { - "added": "Hinzugefügt", - "deleted": "Gelöscht", - "renamed": "Umbenannt", - "modified": "Geändert" - }, - "hunkLabel": "Block {index}", - "loadingHunk": "Hunk wird geladen...", - "noDiffData": "Keine Diff-Daten", - "showRemainingLines": "{count} weitere Zeilen anzeigen" - }, - "conversationContextBar": { - "folderTitle": "Arbeitsordner", - "branchTitle": "Arbeits-Branch", - "searchFolder": "Search folder...", - "searchBranch": "Search branch...", - "noFolders": "No folders", - "noBranches": "No branches", - "noBranch": "(no branch)", - "chatModeLabel": "Chat-Modus", - "commit": "Commit", - "push": "Push", - "merge": "Merge", - "toasts": { - "folderChanged": "Switched to {name}", - "openFolderFailed": "Failed to open folder", - "switchedToChatMode": "In den Chat-Modus gewechselt", - "openStashFailed": "Failed to open stash window", - "openMergeFailed": "Failed to open merge window" - } - }, - "cloneDialog": { - "title": "Repository klonen", - "repositoryUrl": "Repository-URL", - "repositoryUrlPlaceholder": "https://github.com/user/repo.git", - "directory": "Verzeichnis", - "directoryPlaceholder": "Zielverzeichnis auswählen...", - "browseDirectory": "Verzeichnis durchsuchen", - "cancel": "Abbrechen", - "clone": "Klonen", - "clonePath": "Klonpfad: {path}" - }, - "toasts": { - "cloneFailed": "Repository konnte nicht geklont werden" - } - }, - "ProjectBoot": { - "title": "Projekt-Starter", - "tabs": { - "shadcn": "shadcn", - "hyperframes": "HyperFrames" - }, - "hyperframes": { - "title": "HyperFrames-Videoprojekt", - "subtitle": "Erstelle ein HTML-zu-Video-Projekt. Der Agent im Arbeitsbereich kann es dann schreiben und rendern.", - "resolution": "Auflösung", - "skillsTitle": "Agenten-Skills", - "skillsDesc": "Installiert die HyperFrames-Skills global (Symlink) für die ausgewählten Agenten, damit sie Videos erstellen und rendern können.", - "recheck": "Erneut prüfen", - "installedBadge": "Installiert", - "skillsInstall": "Skills installieren / aktualisieren", - "skillsInstalling": "Skills werden installiert…", - "skillsInstalled": "HyperFrames-Skills installiert", - "skillsInstallFailed": "HyperFrames-Skills konnten nicht installiert werden" - }, - "config": { - "base": "Basis", - "style": "Stil", - "baseColor": "Basisfarbe", - "theme": "Thema", - "chartColor": "Diagrammfarbe", - "iconLibrary": "Icon-Bibliothek", - "font": "Schriftart", - "fontHeading": "Überschrift-Schriftart", - "menuAccent": "Menü-Akzent", - "menuColor": "Menü-Farbe", - "radius": "Radius", - "template": "Vorlage", - "createProject": "Projekt erstellen", - "sectionStyle": "Stil", - "sectionColors": "Farben", - "sectionTypography": "Typografie", - "sectionInterface": "Oberfläche" - }, - "preview": { - "loading": "Vorschau wird geladen..." - }, - "createDialog": { - "title": "Projekt erstellen", - "projectName": "Projektname", - "projectNamePlaceholder": "my-app", - "frameworkTemplate": "Framework-Vorlage", - "packageManager": "Paketmanager", - "saveDirectory": "Speicherverzeichnis", - "saveDirectoryPlaceholder": "Verzeichnis auswählen...", - "browseDirectory": "Durchsuchen", - "projectPath": "Projekt wird erstellt in: {path}", - "advancedOptions": "Erweiterte Optionen", - "base": "Basisbibliothek", - "enableRtl": "RTL-Unterstützung aktivieren", - "enableRtlDescription": "Layout-Unterstützung für Rechts-nach-links-Sprachen (z.B. Arabisch, Hebräisch) aktivieren", - "pmChecking": "Wird überprüft...", - "pmNotInstalled": "Nicht installiert", - "cancel": "Abbrechen", - "create": "Erstellen", - "creating": "Projekt wird erstellt..." - }, - "toasts": { - "createFailed": "Projekt konnte nicht erstellt werden", - "createSuccess": "Projekt erfolgreich erstellt", - "openWorkspaceFailed": "Projekt erstellt, konnte aber nicht im Arbeitsbereich geöffnet werden" - }, - "errors": { - "directoryExists": "Zielverzeichnis existiert bereits", - "commandFailed": "Projekterstellungsbefehl fehlgeschlagen." - } - }, - "WebServiceSettings": { - "addressSwitchHint": "Das Umschalten ändert nur die hier angezeigte und geöffnete Adresse – der Dienst lauscht auf allen Schnittstellen und bleibt unter jeder Adresse erreichbar.", - "sectionTitle": "Webdienst", - "sectionDescription": "Aktivieren Sie den Fernzugriff auf Codeg über den Browser", - "port": "Port", - "status": "Status", - "autoStart": "Automatisch starten", - "autoStartHint": "Webdienst beim Start von Codeg starten", - "running": "Läuft", - "stopped": "Gestoppt", - "processing": "Verarbeitung...", - "start": "Starten", - "stop": "Stoppen", - "startFailed": "Start fehlgeschlagen", - "stopFailed": "Stopp fehlgeschlagen", - "saveConfigFailed": "Webdienst-Einstellungen konnten nicht gespeichert werden", - "open": "Öffnen", - "hide": "Ausblenden", - "show": "Einblenden", - "copy": "Kopieren", - "qrcode": "QR-Code", - "qrcodeTitle": "Zum Öffnen scannen", - "qrcodeHint": "Scanne mit deinem Handy, um Codeg im Browser zu öffnen", - "addressLabel": "Zugriffsadresse", - "tokenLabel": "Zugriffstoken", - "tokenHint": "Geben Sie dieses Token beim ersten Zugriff auf den Web-Client ein", - "tokenPlaceholder": "Leer lassen für automatische Generierung", - "regenerate": "Neu generieren", - "stalePortOccupiedTitle": "Port {port} wird von einem anderen Prozess belegt", - "stalePortUnknownTitle": "Status von Port {port} unklar", - "stalePortHint": "Codeg kann sich nicht binden, bis der Port freigegeben ist. Ändere den Port oben oder beende den Prozess, der ihn hält.", - "errors": { - "alreadyRunning": "Der Web-Dienst läuft bereits", - "invalidAddress": "Host- oder Portformat ungültig", - "portInUse": "Port {port} wird bereits verwendet. Beenden Sie den Prozess oder wählen Sie einen anderen Port.", - "permissionDenied": "Zugriff verweigert. Verwenden Sie einen Port über 1024 oder starten Sie mit höheren Rechten.", - "addressUnavailable": "Die Adresse ist auf diesem Computer nicht verfügbar", - "bindFailed": "Adresse konnte nicht gebunden werden" - } - }, - "DirectoryBrowser": { - "title": "Verzeichnis durchsuchen", - "pathPlaceholder": "Verzeichnispfad eingeben...", - "goHome": "Zum Heimverzeichnis", - "navigateUp": "Zum übergeordneten Verzeichnis", - "select": "Auswählen", - "cancel": "Abbrechen", - "loading": "Wird geladen...", - "emptyDirectory": "Dieses Verzeichnis ist leer", - "errorLoadingDir": "Verzeichnis konnte nicht geladen werden", - "permissionDenied": "Zugriff verweigert" - }, - "ChatChannelSettings": { - "loading": "Wird geladen...", - "sectionTitle": "Chat-Kanäle", - "sectionDescription": "Konfigurieren Sie IM-Bots, um Ereignisbenachrichtigungen zu empfangen und Codieraktivitäten abzufragen.", - "addChannel": "Kanal hinzufügen", - "noChannels": "Noch keine Chat-Kanäle konfiguriert.", - "channelName": "Name", - "channelNamePlaceholder": "Mein Telegram Bot", - "channelType": "Kanaltyp", - "lark": "Lark (Feishu)", - "weixin": "WeChat", - "dailyReport": "Tagesbericht", - "dailyReportTime": "Berichtszeit", - "nameRequired": "Kanalname ist erforderlich.", - "tokenRequired": "Token ist erforderlich.", - "chatIdRequired": "Chat-ID ist erforderlich.", - "topicMode": "Themengruppenmodus", - "topicModeHint": "Leitet Telegram-Forum-Themen als separate Codeg-Sitzungen weiter. Der Bot muss in einer Forum-Supergruppe sein und Themen verwalten dürfen.", - "loadFailed": "Kanäle konnten nicht geladen werden.", - "saveFailed": "Änderungen konnten nicht gespeichert werden.", - "connectSuccess": "Kanal verbunden.", - "connectFailed": "Verbindung fehlgeschlagen", - "disconnectSuccess": "Kanal getrennt.", - "disconnectFailed": "Trennung fehlgeschlagen.", - "testSuccess": "Verbindungstest bestanden.", - "testFailed": "Verbindungstest fehlgeschlagen", - "deleteSuccess": "Kanal gelöscht.", - "deleteFailed": "Kanal konnte nicht gelöscht werden.", - "deleteConfirmTitle": "Kanal löschen", - "deleteConfirmMessage": "Der Kanal und seine Nachrichtenprotokolle werden dauerhaft gelöscht. Sind Sie sicher?", - "cancel": "Abbrechen", - "delete": "Löschen", - "create": "Erstellen", - "save": "Speichern", - "channelListTitle": "Konfigurierte Kanäle", - "channelListDescription": "Aktivierte Kanäle werden beim Dienststart automatisch verbunden.", - "editChannel": "Kanal bearbeiten", - "editSuccess": "Kanal aktualisiert.", - "tokenPlaceholderKeep": "Leer lassen, um aktuellen Wert beizubehalten", - "weixinScanTitle": "QR-Code scannen", - "weixinScanDescription": "Öffnen Sie WeChat und scannen Sie den QR-Code, um eine Verbindung herzustellen.", - "weixinQrcodeExpired": "QR-Code abgelaufen.", - "weixinRefreshQrcode": "Aktualisieren", - "weixinWaitingScan": "Warten auf Scan...", - "weixinPollError": "Verbindung instabil, erneuter Versuch...", - "weixinReconnectNotice": "Aufgrund von Einschränkungen des iLink-Protokolls müssen Sie nach jeder erneuten Verbindung dem Bot eine Nachricht senden, damit Ereignisauslöser wirksam werden.", - "connect": "Verbinden", - "disconnect": "Trennen", - "test": "Verbindung testen", - "tabs": { - "channels": "Kanäle", - "commands": "Befehle", - "events": "Ereignisse", - "other": "Sonstiges" - }, - "commands": { - "title": "Integrierte Befehle", - "description": "Im Chat-Kanal verfügbare Bot-Befehle. In Gruppenchats ist @Bot erforderlich, um Nachrichten zu verarbeiten.", - "prefixLabel": "Befehlspräfix", - "prefixDescription": "1-3 nicht-alphanumerische Zeichen zum Auslösen von Bot-Befehlen (Standard /).", - "prefixSaved": "Befehlspräfix gespeichert.", - "prefixSaveFailed": "Fehler beim Speichern des Präfixes.", - "prefixInvalid": "Das Präfix muss 1-3 nicht-alphanumerische Zeichen sein.", - "save": "Speichern", - "folderDesc": "Arbeitsordner auswählen", - "agentDesc": "KI-Agent auswählen", - "taskDesc": "Sitzung erstellen und Aufgabe ausführen", - "sessionsDesc": "Aktive Sitzungen im Ordner anzeigen", - "resumeDesc": "Neueste Konversationen / Sitzung fortsetzen", - "cancelDesc": "Aktuelle Aufgabe abbrechen", - "approveDesc": "Berechtigungsanfrage des Agenten genehmigen", - "denyDesc": "Berechtigungsanfrage des Agenten ablehnen", - "searchDesc": "Konversationen nach Stichwort suchen", - "todayDesc": "Heutige Aktivitätsübersicht", - "statusDesc": "Kanal-Verbindungsstatus", - "helpDesc": "Hilfe anzeigen" - }, - "events": { - "title": "Ereignisbenachrichtigungen", - "description": "Nach Aktivierung werden ausgelöste Ereignisse an den Kanal gesendet.", - "turnComplete": "Runde abgeschlossen", - "turnCompleteDesc": "Wenn eine Agentenrunde endet", - "error": "Agentenfehler", - "errorDesc": "Wenn ein Agent einen Fehler feststellt", - "permissionRequest": "Berechtigungsanfrage", - "permissionRequestDesc": "Wenn ein Agent eine Berechtigung anfordert", - "questionRequest": "Frage des Agenten", - "questionRequestDesc": "Wenn ein Agent dir eine Frage stellt", - "userPromptSent": "Benutzernachricht", - "userPromptSentDesc": "Wenn du eine Nachricht sendest – der Nachrichtentext ist in der Benachrichtigung enthalten", - "saved": "Ereignisfilter aktualisiert.", - "saveFailed": "Fehler beim Speichern des Ereignisfilters.", - "loadFailed": "Einstellungen konnten nicht geladen werden.", - "retry": "Erneut versuchen", - "webhooksTitle": "Webhooks", - "webhooksDescription": "Sendet bei einem aktivierten Ereignis eine JSON-Nutzlast per POST an eine oder mehrere URLs. Der Ereignisfilter oben gilt auch für Webhooks.", - "webhookUrlPlaceholder": "https://example.com/webhook", - "addWebhook": "Webhook hinzufügen", - "removeWebhook": "Webhook entfernen", - "webhookSave": "Speichern", - "webhooksSaved": "Webhooks gespeichert.", - "webhooksSaveFailed": "Fehler beim Speichern der Webhooks.", - "webhookInvalidUrl": "Gültige http(s)-URLs eingeben.", - "docsTitle": "Anfrageformat", - "docsMethod": "Methode", - "docsContentType": "Content-Type", - "docsNote": "Jedes aktivierte Ereignis wird an alle URLs gesendet. Webhooks werden nicht entprellt; der Ereignisfilter oben gilt weiterhin.", - "editWebhook": "Webhook bearbeiten", - "enableWebhook": "Webhook aktivieren", - "webhookDuplicate": "Diese URL ist bereits konfiguriert.", - "cancel": "Abbrechen", - "webhooksEmpty": "Noch keine Webhooks konfiguriert.", - "deleteWebhookTitle": "Webhook löschen", - "deleteWebhookMessage": "Diesen Webhook entfernen? Ereignisse werden nicht mehr an diese URL gesendet.", - "delete": "Löschen" - }, - "language": { - "title": "Nachrichtensprache", - "description": "Sprache für Ereignisbenachrichtigungen, Befehlsantworten und tägliche Berichte, die an Chat-Kanäle gesendet werden.", - "saved": "Nachrichtensprache gespeichert.", - "saveFailed": "Fehler beim Speichern der Nachrichtensprache.", - "en": "Englisch", - "zh-cn": "Vereinfachtes Chinesisch", - "zh-tw": "Traditionelles Chinesisch", - "ja": "Japanisch", - "ko": "Koreanisch", - "es": "Spanisch", - "de": "Deutsch", - "fr": "Französisch", - "pt": "Portugiesisch", - "ar": "Arabisch" - } - }, - "ModelProviderSettings": { - "sectionTitle": "Modellanbieter", - "sectionDescription": "API-Anbieter-Zugangsdaten für Agenten verwalten.", - "filterAll": "Alle", - "providerListTitle": "Konfigurierte Anbieter", - "addProvider": "Anbieter hinzufügen", - "editProvider": "Anbieter bearbeiten", - "noProviders": "Noch keine Modellanbieter konfiguriert.", - "providerName": "Name", - "providerNamePlaceholder": "z.B. OpenAI, Anthropic", - "apiUrl": "API-URL", - "apiUrlPlaceholder": "https://api.openai.com/v1", - "apiKey": "API-Schlüssel", - "apiKeyPlaceholder": "sk-...", - "apiKeyKeepCurrent": "Leer lassen, um aktuellen Wert beizubehalten", - "agentTypes": "Agententypen", - "agentTypesRequired": "Mindestens ein Agententyp ist erforderlich.", - "agentType": "Agententyp", - "agentTypeRequired": "Agententyp ist erforderlich.", - "agentTypeImmutableHint": "Der Agententyp kann nach der Erstellung nicht mehr geändert werden.", - "model": "Modell", - "modelPlaceholderCodex": "gpt-5.6-sol / gpt-5.5", - "modelPlaceholderGemini": "gemini-3-pro-preview", - "claudeMainModel": "Hauptmodell", - "claudeReasoningModel": "Reasoning-Modell (Thinking)", - "claudeHaikuDefaultModel": "Standard Haiku-Modell", - "claudeSonnetDefaultModel": "Standard Sonnet-Modell", - "claudeOpusDefaultModel": "Standard Opus-Modell", - "claudeCustomModelOption": "Benutzerdefinierte Modell-ID", - "claudeCustomModelOptionName": "Name des benutzerdefinierten Modells", - "claudeCustomModelOptionDescription": "Beschreibung des benutzerdefinierten Modells", - "claudeCustomModelOptionHint": "Fügt der Modellauswahl von Claude einen einzelnen benutzerdefinierten Eintrag hinzu (z. B. ein Modell hinter einem benutzerdefinierten Gateway/Proxy). Name und Beschreibung sind optionale Anzeigeangaben.", - "nameRequired": "Anbietername ist erforderlich.", - "apiUrlRequired": "API-URL ist erforderlich.", - "apiKeyRequired": "API-Schlüssel ist erforderlich.", - "loadFailed": "Anbieter konnten nicht geladen werden.", - "saveFailed": "Änderungen konnten nicht gespeichert werden.", - "createSuccess": "Anbieter erstellt.", - "editSuccess": "Anbieter aktualisiert.", - "deleteSuccess": "Anbieter gelöscht.", - "deleteConfirmTitle": "Anbieter löschen", - "deleteConfirmMessage": "Der Anbieter \"{name}\" wird dauerhaft gelöscht. Sind Sie sicher?", - "deleteBlockedByAgent": "{agents} verwendet diesen Anbieter. Bitte trennen Sie die Verbindung vor dem Löschen.", - "cancel": "Abbrechen", - "delete": "Löschen", - "create": "Erstellen", - "save": "Speichern", - "affectedRunningSessions": "{count, plural, one {# laufende Sitzung muss zum Anwenden neu verbunden werden} other {# laufende Sitzungen müssen zum Anwenden neu verbunden werden}}" - }, - "SkillMatrix": { - "loading": "Wird geladen…", - "searchPlaceholder": "Nach Name, ID oder Beschreibung suchen", - "empty": "Nichts anzuzeigen.", - "emptySearch": "Keine Treffer für die aktuelle Suche.", - "skillColumn": "Skill", - "selectAll": "Alle sichtbaren auswählen", - "selectSkill": "{name} auswählen", - "everything": { - "label": "Sammelaktion", - "enable": "Alle aktivieren (sichtbar)", - "disable": "Alle deaktivieren (sichtbar)" - }, - "columnMenu": { - "enableAll": "Alle Skills aktivieren", - "disableAll": "Alle Skills deaktivieren" - }, - "rowMenu": { - "label": "Sammelaktionen für {name}", - "enableAll": "Für alle Agenten aktivieren", - "disableAll": "Für alle Agenten deaktivieren" - }, - "bulk": { - "selected": "{count} ausgewählt", - "targetAll": "Alle Agenten", - "targetSome": "{count} Agenten", - "enable": "Aktivieren", - "disable": "Deaktivieren", - "clear": "Leeren" - }, - "confirm": { - "disableTitle": "Diese Verknüpfungen deaktivieren?", - "disableBody": "Dadurch werden {count} von codeg verwaltete Skill-Verknüpfungen entfernt. Skills, die ein eigenes Verzeichnis belegen, bleiben unberührt. Du kannst sie jederzeit wieder aktivieren.", - "cancel": "Abbrechen", - "confirm": "Deaktivieren" - }, - "toasts": { - "loadFailed": "Skill-Status konnte nicht geladen werden", - "applyFailed": "Änderungen konnten nicht angewendet werden", - "enabled": "{count} Verknüpfungen aktiviert", - "disabled": "{count} Verknüpfungen deaktiviert", - "enabledPartial": "{ok} aktiviert, {failed} fehlgeschlagen", - "disabledPartial": "{ok} deaktiviert, {failed} fehlgeschlagen" - }, - "detail": { - "enableForAgents": "Für Agenten aktivieren", - "preview": "SKILL.md-Vorschau", - "loadingContent": "Inhalt wird geladen…" - }, - "copyModeHint": "Kopiert (nicht verknüpft) – nach Updates erneut aktivieren, um die neueste Version zu erhalten" - }, - "ExpertsSettings": { - "title": "Experten-Skills", - "description": "Aktivieren Sie kuratierte, praxiserprobte Skill-Workflows für Ihre KI-Coding-Agents. Jeder Experte ist ein eigenständiger Skill aus dem superpowers-Projekt — codeg verwaltet die zentrale Kopie und verknüpft sie mit den von Ihnen ausgewählten Agents.", - "loading": "Experten werden geladen…", - "loadingContent": "Inhalt wird geladen…", - "emptyExperts": "Keine Experten verfügbar. Prüfen Sie die Anwendungsprotokolle.", - "emptySelection": "Wählen Sie einen Experten aus, um seinen Inhalt anzuzeigen und die Aktivierung zu verwalten.", - "emptySearch": "Keine Experten entsprechen der aktuellen Suche.", - "searchPlaceholder": "Experten nach Name, ID oder Beschreibung suchen", - "enableForAgents": "Für Agents aktivieren", - "noAgents": "Keine ACP-Agents erkannt.", - "copyModeWarning": "Kopiert (nicht verknüpft). Nach codeg-Updates erneut aktivieren, um die neueste Version zu erhalten.", - "previewTitle": "SKILL.md-Vorschau", - "categories": { - "discovery": "Entdeckung & Design", - "planning": "Planung", - "execution": "Ausführung", - "quality": "Qualität & Tests", - "debugging": "Debugging", - "review": "Review & Integration", - "meta": "Meta" - }, - "states": { - "not_linked": "Nicht aktiviert", - "linked_to_codeg": "Aktiviert", - "linked_elsewhere": "Blockiert — ein anderer Link existiert", - "blocked_by_real_directory": "Blockiert — ein benutzerdefinierter Skill belegt diesen Namen", - "broken": "Defekter Link" - }, - "badges": { - "userModified": "Vom Benutzer geändert" - }, - "actions": { - "openCentralDir": "Zentralen Ordner öffnen", - "refresh": "Aktualisieren" - }, - "toasts": { - "loadFailed": "Laden der Expertendetails fehlgeschlagen", - "enabled": "Experte für diesen Agent aktiviert", - "disabled": "Experte für diesen Agent deaktiviert", - "enableFailed": "Aktivieren des Experten fehlgeschlagen", - "disableFailed": "Deaktivieren des Experten fehlgeschlagen", - "openFolderFailed": "Ordner konnte nicht geöffnet werden" - } - }, - "ScienceSettings": { - "title": "Wissenschaftliche Skills", - "description": "Aktiviere kuratierte wissenschaftliche Skills für deine KI-Coding-Agents — Hypothesengenerierung, Versuchsplanung, Statistik, Visualisierung, kritische Bewertung und Literatursuche. codeg verwaltet eine zentrale Kopie und verlinkt jeden Skill in die von dir gewählten Agents.", - "loading": "Wissenschaftliche Skills werden geladen…", - "emptySkills": "Keine wissenschaftlichen Skills verfügbar. Prüfe die Anwendungsprotokolle.", - "searchPlaceholder": "Wissenschaftliche Skills nach Name, ID oder Beschreibung suchen", - "categories": { - "ideation": "Ideenfindung", - "design": "Studiendesign", - "analysis": "Analyse", - "visualization": "Visualisierung", - "evaluation": "Bewertung", - "literature": "Literatur" - }, - "states": { - "not_linked": "Nicht aktiviert", - "linked_to_codeg": "Aktiviert", - "linked_elsewhere": "Blockiert — ein anderer Link existiert", - "blocked_by_real_directory": "Blockiert — ein benutzerdefinierter Skill belegt diesen Namen", - "broken": "Defekter Link" - }, - "badges": { - "userModified": "Vom Benutzer geändert", - "needsKey": "API-Schlüssel nötig", - "needsSetup": "Ggf. Einrichtung nötig" - }, - "actions": { - "openCentralDir": "Zentralen Ordner öffnen", - "refresh": "Aktualisieren" - }, - "toasts": { - "openFolderFailed": "Ordner konnte nicht geöffnet werden" - } - }, - "OfficeToolsSettings": { - "title": "Office-Tools", - "description": "Verwalten Sie OfficeCLI-Skills zum Erstellen von Excel-, Word- und PowerPoint-Dateien. Installieren Sie OfficeCLI, synchronisieren Sie Skills und aktivieren Sie sie pro Agent.", - "loadingContent": "Inhalt wird geladen…", - "emptySkills": "Keine Skills verfügbar. Installieren Sie OfficeCLI und synchronisieren Sie die Skills.", - "emptySelection": "Wählen Sie einen Skill aus, um den Inhalt anzuzeigen und die Aktivierung zu verwalten.", - "emptySearch": "Keine übereinstimmenden Skills gefunden.", - "searchPlaceholder": "Skills nach Name, ID oder Beschreibung suchen", - "enableForAgents": "Für Agenten aktivieren", - "noAgents": "Keine ACP-Agenten erkannt.", - "installFirst": "Installieren Sie zuerst OfficeCLI, um Skills zu aktivieren.", - "syncFirst": "Synchronisieren Sie zuerst die Skills, um den Inhalt zu laden.", - "noContent": "Kein Inhalt verfügbar.", - "copyModeWarning": "Kopiert (nicht verknüpft). Erneut synchronisieren, um die neueste Version zu erhalten.", - "previewTitle": "SKILL.md-Vorschau", - "detection": { - "installed": "Installiert", - "notInstalled": "Nicht installiert", - "notRunnable": "Installiert, aber nicht lauffähig", - "installHint": "Installieren Sie OfficeCLI, um Office-Dokumentenerstellungs-Skills für Ihre KI-Agenten zu aktivieren.", - "install": "Installieren", - "uninstall": "Deinstallieren", - "syncSkills": "Skills synchronisieren" - }, - "categories": { - "general": "Allgemein", - "presentations": "Präsentationen", - "documents": "Dokumente", - "spreadsheets": "Tabellenkalkulationen" - }, - "states": { - "not_linked": "Nicht aktiviert", - "linked_to_codeg": "Aktiviert", - "linked_elsewhere": "Blockiert — ein anderer Link existiert", - "blocked_by_real_directory": "Blockiert — ein benutzerdefinierter Skill belegt diesen Namen", - "broken": "Defekter Link" - }, - "badges": { - "notSynced": "Nicht synchronisiert" - }, - "actions": { - "refresh": "Aktualisieren" - }, - "toasts": { - "loadFailed": "Skill-Details konnten nicht geladen werden", - "enabled": "Skill für diesen Agenten aktiviert", - "disabled": "Skill für diesen Agenten deaktiviert", - "enableFailed": "Skill konnte nicht aktiviert werden", - "disableFailed": "Skill konnte nicht deaktiviert werden", - "installSuccess": "OfficeCLI erfolgreich installiert", - "installFailed": "OfficeCLI konnte nicht installiert werden", - "uninstallSuccess": "OfficeCLI deinstalliert", - "uninstallFailed": "OfficeCLI konnte nicht deinstalliert werden", - "syncSuccess": "{synced} Skills erfolgreich synchronisiert", - "syncPartial": "{synced} synchronisiert, {errors} fehlgeschlagen", - "syncFailed": "Skills konnten nicht synchronisiert werden" - }, - "autoPreviewLabel": "Vorschau automatisch öffnen", - "autoPreviewHint": "Wenn ein Agent eine Word-, Excel- oder PowerPoint-Datei erstellt oder bearbeitet, wird die Live-Vorschau automatisch geöffnet." - }, - "SkillPacksSettings": { - "title": "Skill-Pakete", - "description": "Kuratierte Skill-Pakete, die codeg zentral verwaltet und mit deinen KI-Agenten verknüpft – Programmierexperten, wissenschaftliche Forschung und Office-Dokumenttools. Unten pro Agent aktivierbar.", - "tabs": { - "experts": "Experten", - "science": "Wissenschaft", - "office": "Office-Tools", - "custom": "Benutzerdefiniert" - }, - "actions": { - "openCentralDir": "Zentralen Ordner öffnen", - "refresh": "Aktualisieren" - }, - "toasts": { - "openFolderFailed": "Ordner konnte nicht geöffnet werden" - } - }, - "QuickMessagesSettings": { - "title": "Schnellnachrichten", - "description": "Verwalte wiederverwendbare Nachrichtenbausteine. Ziehe zum Neuordnen.", - "loading": "Schnellnachrichten werden geladen…", - "emptyList": "Noch keine Schnellnachrichten. Klicke auf \"Neu\", um eine zu erstellen.", - "emptySelection": "Wähle eine Schnellnachricht zum Bearbeiten aus.", - "searchPlaceholder": "Nach Titel oder Inhalt suchen", - "untitled": "Ohne Titel", - "actions": { - "new": "Neu", - "save": "Speichern", - "delete": "Löschen", - "dragSort": "Zum Neuordnen ziehen", - "dragSortMessage": "Schnellnachricht neu ordnen: {name}" - }, - "fields": { - "title": "Titel", - "titlePlaceholder": "Gib dieser Nachricht einen kurzen Titel", - "content": "Inhalt", - "contentPlaceholder": "Gib hier den Nachrichteninhalt ein" - }, - "confirmDelete": { - "title": "Schnellnachricht löschen?", - "message": "Dadurch wird \"{name}\" dauerhaft gelöscht. Bist du sicher?", - "cancel": "Abbrechen", - "confirm": "Löschen" - }, - "toasts": { - "loadFailed": "Laden der Schnellnachrichten fehlgeschlagen", - "createFailed": "Erstellen der Schnellnachricht fehlgeschlagen", - "saveFailed": "Speichern der Schnellnachricht fehlgeschlagen", - "deleteFailed": "Löschen der Schnellnachricht fehlgeschlagen", - "saveOrderFailed": "Reihenfolge konnte nicht gespeichert werden", - "created": "Schnellnachricht erstellt", - "saved": "Schnellnachricht gespeichert", - "deleted": "Schnellnachricht gelöscht" - } - }, - "Pet": { - "badge": { - "running": "{count} laufend", - "waiting": "{count} warten auf Freigabe", - "error": "{count} fehlgeschlagen" - }, - "panel": { - "title": "Aktive Sitzungen", - "empty": "Keine aktiven Sitzungen", - "emptyHint": "Laufende Agenten und solche, die dich brauchen, erscheinen hier.", - "statusRunning": "Läuft", - "statusWaiting": "Wartet", - "statusError": "Fehler", - "subAgentOf": "Sub-Agent von" - }, - "menu": { - "scale": "Skalierung", - "openManager": "Pets verwalten", - "close": "Schließen" - }, - "loadError": "Pet konnte nicht geladen werden", - "missingPetIdParam": "Kein Pet ausgewählt", - "summonButton": "Pet", - "manager": { - "title": "Desktop-Pets", - "description": "Schwebende Begleiter mit Codex-kompatiblen Sprite-Sheets.", - "addPet": "Pet hinzufügen", - "importFromCodex": "Aus Codex importieren", - "noPets": "Keine Pets. Lege eines an oder importiere aus Codex.", - "setActive": "Aktivieren", - "active": "Aktiv", - "edit": "Bearbeiten", - "delete": "Löschen", - "deleteConfirm": "Pet „{name}\" löschen? Auch von der Festplatte entfernt.", - "summon": "Pet-Fenster aufrufen", - "openCodexHelp": "Codex-Pets müssen in ~/.codex/pets/ liegen. Nichts gefunden.", - "specRequirement": "Sprite-Sheet muss 1536px breit sein, mit einer Höhe als Vielfaches von 208px (z. B. 1872 oder 2288), als PNG oder WebP mit Transparenz.", - "form": { - "id": "Pet-ID", - "idHelp": "Kleinbuchstaben, Ziffern, '-' und '_'. Max 64 Zeichen.", - "displayName": "Anzeigename", - "description": "Beschreibung (optional)", - "spritesheet": "Sprite-Sheet", - "chooseFile": "Datei wählen", - "replaceFile": "Sprite ersetzen", - "saveCreate": "Pet hinzufügen", - "saveUpdate": "Änderungen speichern", - "cancel": "Abbrechen" - }, - "errors": { - "missingId": "Pet-ID erforderlich", - "missingName": "Anzeigename erforderlich", - "missingSpritesheet": "Sprite erforderlich", - "addFailed": "Hinzufügen fehlgeschlagen", - "updateFailed": "Aktualisieren fehlgeschlagen", - "deleteFailed": "Löschen fehlgeschlagen", - "loadFailed": "Pet-Liste konnte nicht geladen werden", - "setActiveFailed": "Aktivieren fehlgeschlagen", - "summonFailed": "Pet-Fenster konnte nicht geöffnet werden" - } - }, - "import": { - "title": "Aus Codex importieren", - "subtitle": "Pets unter ~/.codex/pets/.", - "selectAll": "Alle auswählen", - "alreadyImported": "Bereits importiert", - "renameOnConflict": "Konflikte mit Suffix -imported umbenennen", - "import": "Auswahl importieren", - "noneFound": "Keine importierbaren Codex-Pets gefunden.", - "imported": "Erfolgreich importiert", - "failed": "Import fehlgeschlagen", - "close": "Schließen" - }, - "marketplace": { - "openMarketplace": "Pet-Marketplace", - "title": "Pet-Marketplace", - "search": "Pets suchen", - "kindFilter": { - "all": "Alle", - "object": "Objekt", - "animal": "Tier", - "person": "Person", - "creature": "Kreatur" - }, - "sortFilter": { - "latest": "Neueste", - "popular": "Beliebt", - "views": "Aufrufe" - }, - "refresh": "Aktualisieren", - "install": "Installieren", - "installing": "Wird installiert", - "reinstall": "Neu installieren", - "reinstallConfirm": "Lokales Pet \"{name}\" überschreiben? Vorhandene Daten werden ersetzt.", - "cancel": "Abbrechen", - "stats": { - "views": "Aufrufe", - "downloads": "Downloads", - "likes": "Likes" - }, - "actions": { - "idle": "Idle", - "running_right": "Rechtslauf", - "running_left": "Linkslauf", - "waving": "Winken", - "jumping": "Springen", - "failed": "Fehler", - "waiting": "Warten", - "running": "Laufen", - "review": "Review" - }, - "page": "Seite {page} von {total}", - "prev": "Zurück", - "next": "Weiter", - "empty": "Keine Pets entsprechen dem Filter.", - "successInstalled": "\"{name}\" installiert", - "errors": { - "loadFailed": "Marketplace konnte nicht geladen werden", - "installFailed": "Installation fehlgeschlagen", - "alreadyInstalled": "Pet existiert bereits lokal" - } - } - }, - "RemoteWorkspace": { - "openRemoteWorkspace": "Open remote workspace", - "manage": "Manage remote workspace", - "manageTitle": "Remote Workspace connections", - "empty": "No remote connections", - "searchPlaceholder": "Search remote workspaces", - "orderFailed": "Failed to save remote workspace order", - "dragSort": "Drag to sort", - "dragSortConnection": "Drag to sort {name}", - "newConnection": "New connection", - "loading": "Loading", - "loadingConnection": "Loading remote connection", - "name": "Name", - "baseUrl": "Service URL", - "token": "Access token", - "save": "Save", - "delete": "Delete", - "confirmDelete": { - "title": "Delete remote connection?", - "message": "This will remove \"{name}\" from this device. This action cannot be undone.", - "cancel": "Cancel", - "confirm": "Delete" - }, - "saved": "Remote connection saved.", - "deleted": "Remote connection deleted.", - "loadFailed": "Failed to load remote connections", - "saveFailed": "Failed to save remote connection", - "deleteFailed": "Failed to delete remote connection", - "openFailed": "Failed to open remote workspace", - "connectionLoadFailed": "Failed to load remote connection: {message}", - "connectionExpired": "Remote connection \"{name}\" is expired. Update its token and reload this window." - }, - "ServerFileBrowser": { - "title": "Serverdatei auswählen", - "pathPlaceholder": "Verzeichnispfad eingeben...", - "goHome": "Zum Home-Verzeichnis", - "navigateUp": "Zum übergeordneten Verzeichnis", - "select": "Auswählen", - "cancel": "Abbrechen", - "loading": "Laden...", - "emptyDirectory": "Dieses Verzeichnis ist leer", - "errorLoadingDir": "Verzeichnis konnte nicht geladen werden", - "selectedCount": "{count} ausgewählt" - }, - "BackupSettings": { - "title": "Sicherung & Wiederherstellung", - "description": "Exportiere eine portable Sicherung deiner codeg-Daten oder stelle aus einer Sicherung wieder her.", - "tabs": { - "backup": "Sicherung", - "restore": "Wiederherstellung" - }, - "export": { - "includeExternal": "Gesprächsinhalte einschließen", - "includeExternalHint": "Archiviert auch die CLI-Transkripte (Claude, Codex, Gemini, …). Erhöht die Größe.", - "passphrase": "Passphrase (optional)", - "passphrasePlaceholder": "Leer lassen für ein unverschlüsseltes Archiv", - "passphraseConfirm": "Passphrase bestätigen", - "passphraseMismatch": "Die Passphrasen stimmen nicht überein.", - "noPassphraseWarning": "Diese Sicherung enthält Geheimnisse (API-Schlüssel, Tokens) im Klartext. Bewahre sie sicher auf.", - "passphraseLossWarning": "Mit dieser Passphrase verschlüsselt. Wenn du sie verlierst, kann die Sicherung nicht wiederhergestellt werden.", - "button": "Sicherung exportieren", - "inProgress": "Sicherung wird erstellt…", - "success": "Sicherung erstellt.", - "started": "Download der Sicherung gestartet." - }, - "restore": { - "selectFile": "Sicherungsdatei auswählen", - "passphrasePrompt": "Diese Sicherung ist verschlüsselt. Gib ihre Passphrase ein.", - "unlock": "Entsperren", - "preview": { - "title": "Sicherungsdetails", - "encrypted": "Verschlüsselt", - "compatible": "Kompatibel", - "incompatible": "Inkompatibel", - "createdAt": "Erstellt: {value}", - "appVersion": "App-Version: {value}", - "incompatibleHint": "Diese Sicherung wurde mit einer neueren Version von codeg erstellt und kann nicht wiederhergestellt werden." - }, - "replaceWarning": "Beim Wiederherstellen werden alle aktuellen codeg-Daten (Datenbank und Uploads) ersetzt. Deine aktuellen Daten werden zuvor als Snapshot gesichert.", - "keyringNote": "GitHub-/Chat-Tokens der Desktop-App liegen im Schlüsselbund des Betriebssystems und sind nicht enthalten; gib sie nach dem Wiederherstellen erneut ein.", - "button": "Wiederherstellen", - "staging": "Wiederherstellung wird vorbereitet…", - "staged": "Wiederherstellung vorbereitet. Neustart…", - "restarting": "Wiederherstellung vorbereitet. Server wird neu gestartet…", - "restartTimeout": "Der Server kam nicht rechtzeitig zurück. Lade die Seite neu, sobald er läuft.", - "externalSideLocation": "Gesprächstranskripte wurden nach {path} wiederhergestellt", - "confirmTitle": "Alle Daten ersetzen?", - "confirmBody": "Dadurch werden deine aktuelle codeg-Datenbank und Uploads durch die Sicherung ersetzt und anschließend neu gestartet. Deine aktuellen Daten werden zuvor als Snapshot gesichert.", - "cancel": "Abbrechen", - "confirmAction": "Ersetzen & neu starten", - "external": { - "title": "Gesprächsinhalte", - "hint": "Diese Sicherung enthält CLI-Transkripte. Wähle, wohin sie wiederhergestellt werden.", - "modeSkip": "Nicht wiederherstellen", - "modeSide": "In einen sicheren Nebenordner wiederherstellen", - "modeOriginal": "An den ursprünglichen CLI-Speicherorten wiederherstellen", - "forceOverwrite": "Vorhandene Dateien überschreiben", - "forceOverwriteHint": "Ersetzt Dateien, die bereits in den CLI-Ordnern vorhanden sind.", - "scanning": "Konflikte werden geprüft…", - "noConflicts": "Es werden keine vorhandenen Dateien überschrieben.", - "conflictCount": "{count} vorhandene Datei(en) wären betroffen.", - "conflictSkipNote": "Vorhandene Dateien bleiben erhalten (übersprungen), sofern du das Überschreiben nicht aktivierst." - }, - "restartFailed": "Wiederherstellung vorbereitet, aber der Server konnte nicht neu starten. Starte ihn manuell neu, um sie anzuwenden." - }, - "remoteUnsupported": "Sicherung & Wiederherstellung wirken auf die Daten des Rechners, auf dem codeg läuft. Du bist mit einem entfernten Arbeitsbereich verbunden – verwalte dessen Sicherungen direkt auf jenem Server." - }, - "backup": { - "restore": { - "error": { - "badPassphrase": "Falsche Passphrase oder beschädigte Sicherung.", - "corrupted": "Das Sicherungsarchiv ist beschädigt.", - "unknownFormat": "Diese Datei ist keine erkannte codeg-Sicherung.", - "newerVersion": "Diese Sicherung wurde mit codeg {backupVersion} erstellt, neuer als diese Version ({appVersion}).", - "alreadyPending": "Es ist bereits eine Wiederherstellung vorbereitet. Starte neu, um sie anzuwenden, bevor du eine weitere vorbereitest." - } - }, - "error": { - "diskSpace": "Nicht genügend Speicherplatz, um den Vorgang abzuschließen.", - "cancelled": "Der Vorgang wurde abgebrochen." - } - }, - "WebConnection": { - "disconnectedTitle": "Verbindung getrennt", - "reconnectingDescription": "Verbindung zum Server wird wiederhergestellt. Das geschieht normalerweise innerhalb weniger Sekunden automatisch.", - "reconnectNow": "Jetzt neu verbinden", - "sessionExpiredTitle": "Sitzung abgelaufen", - "sessionExpiredDescription": "Deine Sitzung ist nicht mehr gültig. Bitte melde dich erneut an, um fortzufahren.", - "goToLogin": "Zur Anmeldung" - }, - "LiveFeedback": { - "placeholder": "Sende {agent} eine Notiz, während er arbeitet…", - "agentFallback": "der Agent", - "ariaLabel": "Live-Feedback-Notiz", - "dialogTitle": "Live-Feedback", - "dialogDescription": "Sende dem Agenten eine Notiz, während er arbeitet. Er liest sie bei der nächsten Prüfung – ohne den aktuellen Schritt zu unterbrechen.", - "dialogDescriptionInstant": "Sende dem Agenten eine Notiz, während er arbeitet. Sie wird sofort in den laufenden Turn eingefügt – der Agent sieht sie umgehend.", - "channelDowngraded": "Sofortiges Einfügen ist in dieser Sitzung nicht verfügbar – deine Notiz wurde gespeichert; der Agent holt sie bei seinem nächsten Check ab.", - "send": "Senden", - "cancel": "Abbrechen", - "pending": "wartet", - "delivered": "erhalten", - "turnEndedUnread": "Der Agent hat die Runde beendet, bevor er dein Feedback gelesen hat.", - "sendAsMessage": "Als Nachricht senden", - "dismiss": "Verwerfen", - "turnEndedResent": "Die Runde endete – stattdessen als neue Nachricht gesendet.", - "turnEnded": "Die Runde ist bereits beendet.", - "submitFailed": "Deine Notiz konnte nicht gesendet werden" - }, - "AgentToolsSettings": { - "title": "Tools in der Unterhaltung", - "description": "Zusätzliche Tools, die codeg einem Agenten innerhalb einer Unterhaltung gibt. Sie werden beim Start des Agenten injiziert – eine Änderung gilt daher für danach gestartete Agenten.", - "feedbackLabel": "Live-Feedback", - "feedbackHint": "Sende einem Agenten Notizen und Korrekturen, während er arbeitet. Unterstützt der Agent sofortiges Einfügen, landet deine Notiz umgehend im laufenden Turn; andernfalls erhält der Agent ein Tool zum Abrufen deines Feedbacks – solche Agenten prüfen es meist nur, wenn du es im Prompt erwähnst, z. B. mit \"prüfe regelmäßig mein Live-Feedback\".", - "questionLabel": "Benutzer fragen", - "questionHint": "Erlaubt Agenten, anzuhalten und dir eine Multiple-Choice-Frage zu stellen, die über dem Eingabefeld der Unterhaltung erscheint. Der Agent wartet, bis du antwortest (oder überspringst).", - "sessionInfoLabel": "Sitzungsinformationen abrufen", - "sessionInfoHint": "Erlaubt Agenten, eine in deiner Nachricht referenzierte Sitzung (ein Sitzungs-Badge) nachzuschlagen, um Titel, Agent, Status, Arbeitsbereich, Token-Verbrauch und letzte Nachrichten zu lesen.", - "automationsLabel": "Automatisierungen erstellen", - "automationsHint": "Speichert die Unterhaltung als Automatisierung, die nach Zeitplan läuft. Standardmäßig aus – sie startet danach selbst Agenten.", - "workTasksLabel": "To-do-Aufgaben erstellen", - "workTasksHint": "Stellt aus der Unterhaltung heraus eine Karte auf das To-do-Board. Standardmäßig aus – schreibt App-Zustand.", - "save": "Speichern", - "saving": "Wird gespeichert…", - "saved": "Tool-Einstellungen gespeichert", - "saveFailed": "Tool-Einstellungen konnten nicht gespeichert werden", - "loadFailed": "Laden fehlgeschlagen: {detail}" - }, - "NotificationSoundSettings": { - "title": "Benachrichtigungstöne", - "description": "Spielt einen kurzen Ton ab, wenn ein Agent-Ereignis eintritt. Es sind dieselben Ereignisse, die an die Chat-Kanäle gesendet werden; diese Einstellung gilt nur für dieses Gerät.", - "enableHint": "Standardmäßig aus. Töne werden nur im Arbeitsbereich-Fenster dieses Browsers oder dieser App abgespielt.", - "volume": "Lautstärke", - "preview": "Anhören", - "previewEvent": "Ton für {event} anhören", - "onlyWhenUnfocused": "Nur wenn das Fenster nicht im Fokus ist", - "onlyWhenUnfocusedHint": "Bleibt stumm, solange du Codeg ansiehst.", - "eventsTitle": "Ereignisse", - "eventsHint": "Wähle pro Ereignis einen Ton oder „Stumm“, um es zu überspringen. Wiederholt sich dasselbe Ereignis innerhalb weniger Sekunden, erklingt es nur einmal.", - "toneNone": "Stumm", - "toneChime": "Glockenspiel", - "toneDing": "Klingel", - "toneBlip": "Blip", - "tonePop": "Pop", - "toneAlert": "Alarm", - "toneDescend": "Absteigend" - }, - "LogsSettings": { - "loading": "Wird geladen…", - "sectionTitle": "Laufzeitprotokolle", - "sectionDescription": "Diagnoseprotokolle der Anwendung anzeigen und konfigurieren. Protokolle werden in lokale Dateien geschrieben und für die Live-Ansicht im Speicher gehalten.", - "captureTitle": "Protokollebene", - "captureDescription": "Steuert, wie viele Details erfasst werden. Höhere Stufen (Debug, Trace) zeichnen mehr auf, erzeugen aber größere Protokolle. „Aus“ deaktiviert die Protokollierung.", - "captureLabel": "Erfassungsebene", - "levels": { - "off": "Aus", - "error": "Fehler", - "warn": "Warnung", - "info": "Info", - "debug": "Debug", - "trace": "Trace" - }, - "viewerTitle": "Aktuelle Protokolle", - "viewerDescription": "Live-Ansicht der letzten Protokolleinträge. Nach Ebene filtern oder Text suchen.", - "searchPlaceholder": "Nachricht oder Ziel suchen…", - "viewLevels": { - "all": "Alle Ebenen", - "error": "Fehler und höher", - "warn": "Warnung und höher", - "info": "Info und höher", - "debug": "Debug und höher", - "trace": "Trace und höher" - }, - "pause": "Pause", - "resume": "Live", - "refresh": "Aktualisieren", - "clear": "Leeren", - "openFolder": "Ordner öffnen", - "shownCount": "{shown} / {total} angezeigt", - "empty": "Keine Protokolle vorhanden.", - "levelSaveFailed": "Protokollebene konnte nicht gespeichert werden", - "openFolderFailed": "Protokollordner konnte nicht geöffnet werden", - "downloadFailed": "Protokolldatei konnte nicht heruntergeladen werden", - "filesTitle": "Protokolldateien", - "filesDescription": "Vollständige Protokolldateien von der Festplatte herunterladen, um den Verlauf über den Live-Puffer hinaus anzuzeigen.", - "filesEmpty": "Noch keine Protokolldateien.", - "download": "Herunterladen", - "downloadTruncated": "Die Datei ist groß; die neuesten {size} wurden heruntergeladen. Die vollständige Datei befindet sich im Log-Verzeichnis.", - "captureEnvLocked": "Die Protokollebene wird durch die Umgebungsvariable RUST_LOG / CODEG_LOG gesteuert; ändere sie dort, damit es wirksam wird.", - "targetsTitle": "Modulspezifische Überschreibungen", - "targetsDescription": "Lege für bestimmte Module (z. B. codeg_lib::acp) eine andere Stufe fest, ohne die globale Stufe zu ändern.", - "targetsAdd": "Hinzufügen", - "targetsRemove": "Überschreibung entfernen", - "toggleDetails": "Details umschalten" - }, - "Automations": { - "title": "Automatisierungen", - "new": "Neue Automatisierung", - "empty": "Noch keine Automatisierungen", - "emptyHint": "Erstelle eine, um eine Agentenaufgabe geplant oder manuell auszuführen.", - "name": "Name", - "namePlaceholder": "z. B. Nächtliche PR-Prüfung", - "prompt": "Eingabe", - "promptPlaceholder": "Was soll der Agent tun?", - "agent": "Agent", - "folder": "Arbeitsbereich-Ordner", - "folderPlaceholder": "Ordner auswählen", - "isolation": "Isolierung", - "isolationWorktree": "Neues Worktree pro Lauf", - "isolationShared": "Im Ordner ausführen", - "isolationSharedCaveat": "Ausführungen verwenden den Arbeitsbaum dieses Ordners direkt und können mit deinen nicht committeten Änderungen kollidieren. Aktiviere die Worktree-Option, um jede Ausführung zu isolieren.", - "trigger": "Auslöser", - "triggerSchedule": "Nach Zeitplan", - "triggerManual": "Nur manuell", - "cron": "Zeitplan (Cron)", - "cronPlaceholder": "0 9 * * 1-5", - "timezone": "Zeitzone", - "nextRun": "Nächster Lauf", - "branch": "Branch", - "branchOptional": "Branch (optional)", - "enabled": "Aktiviert", - "save": "Speichern", - "cancel": "Abbrechen", - "edit": "Bearbeiten", - "delete": "Löschen", - "runNow": "Jetzt ausführen", - "cancelRun": "Lauf abbrechen", - "runHistory": "Laufverlauf", - "noRuns": "Noch keine Läufe", - "allFolders": "Alle Ordner", - "filterAll": "Alle", - "noMatches": "Keine passenden Automatisierungen", - "viewConversation": "Konversation ansehen", - "lastRun": "Letzter Lauf", - "never": "Nie", - "running": "Läuft", - "deleteTitle": "Automatisierung löschen?", - "deleteDescription": "Dies entfernt die Automatisierung und ihren Zeitplan. Der Laufverlauf bleibt erhalten.", - "statusRunning": "Läuft", - "statusSucceeded": "Erfolgreich", - "statusFailed": "Fehlgeschlagen", - "statusCancelled": "Abgebrochen", - "statusSkipped": "Übersprungen", - "errorName": "Name ist erforderlich", - "errorPrompt": "Eingabe ist erforderlich", - "errorCron": "Geplante Automatisierungen benötigen einen Cron-Ausdruck", - "errorFolder": "Wähle einen Arbeitsbereich-Ordner", - "presetHourly": "Stündlich", - "presetDaily": "Täglich 9 Uhr", - "presetWeekdays": "Werktags 9 Uhr", - "presetCustom": "Benutzerdefiniert", - "probing": "Optionen werden geladen…", - "retry": "Erneut versuchen", - "configNone": "Dieser Agent hat keine konfigurierbaren Optionen", - "inherit": "Agent-Standard", - "mode": "Modus", - "config": "Konfiguration", - "branchPlaceholder": "(Standard-Branch)", - "selectHint": "Wähle eine Automatisierung, um Details zu sehen", - "refresh": "Aktualisieren", - "onboardTitle": "Routineaufgaben des Agenten automatisieren", - "onboardHint": "Plane einen Agenten, der Code überprüft, Abhängigkeiten aktualisiert oder Probleme sichtet – nach Zeitplan oder bei Bedarf.", - "headerSubtitle": "Geplante und bedarfsgesteuerte Agentenaufgaben", - "startFromTemplate": "Mit einer Vorlage beginnen", - "blankTitle": "Leere Automatisierung", - "blankDesc": "Eine Agentenaufgabe von Grund auf konfigurieren.", - "backToTemplates": "Vorlagen", - "sectionSchedule": "Zeitplan & Ziel", - "sectionTarget": "Ziel", - "sectionAction": "Aktion", - "actionLaunchSession": "Sitzung starten", - "actionEnqueueTask": "Aufgabe einreihen", - "actionEnqueueTaskHint": "Jede Auslösung fügt den To-dos des Ordners eine To-do-Aufgabe mit dem Namen dieser Automatisierung hinzu; die Task-Engine führt sie gemäß den Board-Einstellungen aus.", - "sectionPrompt": "Prompt", - "nextIn": "Nächste in {rel}", - "manual": "Manuell", - "schedEveryMinutes": "Alle {n} Minuten", - "schedHourly": "Stündlich", - "schedDaily": "Täglich um {time}", - "schedWeekdays": "Wochentags um {time}", - "schedWeekly": "Jeden {day} um {time}", - "schedMonthly": "Monatlich am {day}. um {time}", - "dow0": "Sonntag", - "dow1": "Montag", - "dow2": "Dienstag", - "dow3": "Mittwoch", - "dow4": "Donnerstag", - "dow5": "Freitag", - "dow6": "Samstag", - "tplCodeReviewTitle": "Code-Review", - "tplCodeReviewDesc": "Überprüft aktuelle Änderungen auf Fehler, Regressionen und Qualitätsprobleme.", - "tplDependencyUpdatesTitle": "Abhängigkeits-Updates", - "tplDependencyUpdatesDesc": "Findet veraltete Abhängigkeiten und schlägt sichere Upgrades vor.", - "tplTestCoverageTitle": "Testabdeckung", - "tplTestCoverageDesc": "Findet ungetestete Codepfade und ergänzt die fehlenden Tests.", - "tplTodoSweepTitle": "TODO-Durchsicht", - "tplTodoSweepDesc": "Sammelt TODO- und FIXME-Kommentare und sortiert sie nach Priorität.", - "tplCiTriageTitle": "CI-Sichtung", - "tplCiTriageDesc": "Untersucht kürzlich fehlgeschlagene Prüfungen und schlägt Korrekturen vor.", - "tplReleaseNotesTitle": "Release Notes", - "tplReleaseNotesDesc": "Fasst Änderungen seit dem letzten Release in einem Changelog zusammen.", - "tplSecurityAuditTitle": "Sicherheitsaudit", - "tplSecurityAuditDesc": "Sucht nach Schwachstellen und riskanten Mustern und meldet die Ergebnisse.", - "enable": "Aktivieren", - "disable": "Deaktivieren", - "moreActions": "Weitere Aktionen", - "statusDisabled": "Deaktiviert", - "cronBuilderTitle": "Zeitplan-Generator", - "cronFreqLabel": "Häufigkeit", - "cronFreqMinutes": "Alle N Minuten", - "cronFreqHourly": "Stündlich", - "cronFreqDaily": "Täglich", - "cronFreqWeekdays": "Wochentags", - "cronFreqWeekly": "Wöchentlich", - "cronFreqMonthly": "Monatlich", - "cronFreqCustom": "Benutzerdefiniert", - "cronEveryLabel": "Intervall (Minuten)", - "cronTimeLabel": "Uhrzeit", - "cronHourLabel": "Stunde", - "cronMinuteLabel": "Minute", - "cronDowLabel": "Wochentag", - "cronDomLabel": "Tag des Monats", - "cronApply": "Anwenden", - "cronPreviewLabel": "Vorschau", - "cronOpenBuilder": "Zeitplan-Generator öffnen", - "branchDefault": "Standard-Branch", - "branchUseCustom": "„{query}“ verwenden", - "branchLocal": "Lokal", - "branchRemote": "Remote", - "branchSearchPlaceholder": "Branches suchen…", - "branchNone": "Keine Branches" - }, - "Tasks": { - "title": "To-dos", - "new": "Neue Aufgabe", - "empty": "Noch keine Aufgaben", - "emptyHint": "Füge ein To-do hinzu und starte es — der Agent arbeitet in einem isolierten Worktree, du prüfst und mergst das Ergebnis.", - "emptyColTodo": "Noch keine To-dos", - "emptyColInProgress": "Nichts in Arbeit", - "emptyColAttention": "Nichts wartet auf dich", - "emptyColDone": "Noch nichts fertig", - "allFolders": "Alle Ordner", - "showCanceled": "Abgebrochene anzeigen", - "showArchived": "Archivierte anzeigen", - "filter": "Filter", - "viewSwitchToBoard": "Zur Board-Ansicht wechseln", - "viewSwitchToList": "Zur Listenansicht wechseln", - "statusFilter": "Status", - "statusFilterAll": "Alle Status", - "listEmpty": "Keine Aufgabe entspricht den aktuellen Filtern", - "listColStatus": "Status", - "listColTask": "Aufgabe", - "listColLocation": "Ort", - "listColChanges": "Änderungen", - "listColUpdated": "Aktualisiert", - "colTodo": "To-do", - "colInProgress": "In Arbeit", - "colAttention": "Wartet auf dich", - "colDone": "Fertig", - "statusTodo": "To-do", - "statusQueued": "In Warteschlange", - "statusPreparing": "Wird vorbereitet", - "statusRunning": "Läuft", - "statusAwaitingInput": "Wartet auf Eingabe", - "statusReview": "Zur Prüfung", - "statusMerging": "Wird gemergt", - "statusDone": "Fertig", - "statusFailed": "Fehlgeschlagen", - "statusCanceled": "Abgebrochen", - "statusInterrupted": "Unterbrochen", - "badgeCleanupFailed": "Aufräumen fehlgeschlagen", - "badgeWorktreeKept": "Worktree behalten", - "badgeWorktreeRemoved": "Worktree entfernt", - "filesChanged": "{count} Dateien", - "actionStart": "Starten", - "actionSchedule": "Planen", - "actionCancel": "Abbrechen", - "actionRetry": "Erneut versuchen", - "actionRequeue": "Erneut einreihen", - "actionViewSession": "Konversation anzeigen", - "actionEdit": "Bearbeiten", - "actionDelete": "Löschen", - "actionRetryCleanup": "Aufräumen wiederholen", - "actionMerge": "Mergen", - "actionUnqueueMerge": "Merge-Warteschlange verlassen", - "actionEditQueuedMerge": "Wartenden Merge bearbeiten", - "badgeMergeQueued": "Wartet auf Merge", - "badgeMergeQueuedRank": "Wartet auf Merge · Nr. {rank}", - "badgeMergeQueuedHint": "Wartet, bis der laufende Merge des Projekts fertig ist; dieser startet dann von selbst.", - "actionComplete": "Abschließen", - "actionAbandon": "Verwerfen", - "cancelTitle": "Aufgabe abbrechen?", - "cancelDescription": "Die Aufgabe wird auf Abgebrochen gesetzt. Ihr Worktree bleibt erhalten und du kannst sie später erneut einreihen.", - "cancelReasonLabel": "Grund (optional)", - "cancelReasonPlaceholder": "Z. B. falscher Ansatz – ich schreibe die Beschreibung neu", - "cancelKeep": "Doch nicht", - "cancelSubmit": "Aufgabe abbrechen", - "restartTitleRetry": "Aufgabe erneut versuchen", - "restartTitleRequeue": "Aufgabe erneut einreihen", - "restartDescription": "Du kannst eine Notiz ergänzen (optional) – sie landet im Prompt des nächsten Laufs.", - "scheduleTitle": "Aufgabe planen", - "scheduleDescription": "Die Aufgabe bleibt im To-do und startet zur gewählten Zeit von selbst. Das Parallelitätslimit des Ordners gilt weiterhin.", - "scheduleDateLabel": "Datum", - "schedulePickDate": "Datum wählen", - "scheduleTimeLabel": "Uhrzeit", - "schedulePreview": "Läuft am {time}", - "schedulePastHint": "Dieser Zeitpunkt liegt in der Vergangenheit – die Aufgabe startet direkt nach dem Speichern.", - "scheduleInAnHour": "In 1 Stunde", - "scheduleInThreeHours": "In 3 Stunden", - "scheduleTomorrow": "Morgen 9:00", - "scheduleClear": "Planung entfernen", - "scheduleBadge": "Geplanter Start: {time}", - "toastScheduled": "Geplant für {time}", - "toastScheduleCleared": "Planung entfernt", - "actionFollowUp": "Nachfassen", - "actionAddNote": "Hinweis ergänzen", - "followUpSubmit": "Senden", - "followUpIntentRevise": "Überarbeiten", - "followUpIntentContinue": "Weitermachen", - "followUpIntentQuestion": "Nachfragen", - "followUpIntentVerify": "Selbstprüfung", - "followUpPlaceholderRevise": "Was soll der Agent ändern? Er macht in derselben Sitzung weiter.", - "followUpPlaceholderContinue": "Was kommt als Nächstes? Das Bisherige bleibt bestehen.", - "followUpPlaceholderQuestion": "Was möchtest du wissen? Der Agent antwortet, ohne Dateien anzufassen.", - "followUpPlaceholderVerify": "Optional: Worauf soll es besonders achten?", - "followUpPlaceholderRetry": "Optional: Was soll diesmal anders laufen? Z. B. zuerst pnpm install ausführen", - "followUpPlaceholderRequeue": "Optional: Warum hast du abgebrochen, und was soll diesmal anders sein?", - "actionArchive": "Archivieren", - "actionUnarchive": "Dearchivieren", - "archiveAllDone": "Alle archivieren", - "dropToStart": "Loslassen zum Starten", - "errorView": "Ansehen", - "notifyReview": "Bereit zur Abnahme: {title}", - "notifyFailed": "Aufgabe fehlgeschlagen: {title}", - "createFromMessage": "Aufgabe aus Nachricht erstellen", - "detailTokens": "Token insgesamt", - "editorTitleNew": "Neue Aufgabe", - "editorTitleEdit": "Aufgabe bearbeiten", - "templates": "Vorlagen", - "templatesEmpty": "Noch keine Vorlagen.", - "templateSaveCurrent": "Aktuelles als Vorlage speichern", - "templateDelete": "Vorlage löschen", - "transcriptTitle": "Aufgaben-Konversation", - "transcriptDescription": "Schreibgeschützte Live-Ansicht der Agentensitzung dieser Aufgabe.", - "phaseWork": "Ausführung", - "phaseRetry": "Neuversuch", - "phaseReturn": "Nachfassen", - "phaseMerge": "Merge", - "titleLabel": "Titel", - "titlePlaceholder": "Was ist zu tun?", - "promptLabel": "Aufgabenbeschreibung", - "promptPlaceholder": "Beschreibe die Aufgabe für den Agenten — @ für Dateiverweise, / für Befehle", - "folderPlaceholder": "Ordner wählen", - "agentInheritedHint": "Aus den Aufgaben-Einstellungen geerbt — Änderungen gelten nur für diese Aufgabe", - "agentOverrideReset": "Wieder erben", - "sectionTarget": "Ziel", - "errorTitle": "Titel ist erforderlich", - "errorPrompt": "Beschreibung ist erforderlich", - "errorFolder": "Ordner wählen", - "save": "Speichern", - "cancel": "Abbrechen", - "mergeTitle": "Aufgabe mergen", - "mergeQueuedTitle": "Wartender Merge", - "mergeQueueHint": "Eine andere Aufgabe dieses Projekts wird gerade gemergt. Diese reiht sich ein und startet von selbst, sobald die andere fertig ist.", - "mergeQueueUpdateHint": "Diese Aufgabe wartet bereits auf den Merge. Beim Absenden wird sie aktualisiert und behält ihren Platz in der Warteschlange.", - "mergeDescription": "{branch} in {base} mergen. Nicht committete Änderungen im Worktree werden zuerst committet.", - "mergeMessage": "Commit-Nachricht", - "mergeMessagePlaceholder": "z. B. feat: add login validation", - "mergeAutoMessage": "Commit-Nachricht vom Agenten schreiben lassen", - "strategySquash": "Zu einem Commit zusammenfassen", - "strategySquashHint": "Alle Änderungen der Aufgabe landen als ein einzelner Eintrag im Verlauf des Hauptbranchs — der Verlauf bleibt übersichtlich.", - "strategyMerge": "Gesamten Verlauf behalten", - "strategyMergeHint": "Jeder während der Aufgabe erstellte Commit bleibt erhalten, plus ein Merge-Eintrag — jeder Schritt bleibt nachvollziehbar.", - "mergeDeleteWorktree": "Worktree nach dem Merge löschen", - "mergeSubmit": "Mergen", - "mergeSubmitQueue": "In die Warteschlange", - "mergeQueuedToast": "Zur Merge-Warteschlange hinzugefügt – startet, sobald der laufende Merge fertig ist.", - "completeTitle": "Aufgabe abschließen", - "completeDescription": "Diese Aufgabe hat keine Dateien geändert – es gibt nichts zu mergen, sie wird direkt als fertig markiert.", - "completeDescriptionNoWorktree": "Der Worktree dieser Aufgabe wurde entfernt – es kann nichts mehr gemergt werden, sie wird direkt als fertig markiert. Ein Arbeitsbranch mit noch nicht gemergten Commits bleibt erhalten.", - "completeDeleteWorktree": "Worktree nach dem Abschließen löschen", - "completeSubmit": "Abschließen", - "settingsTitle": "Aufgaben-Einstellungen", - "settingsDescription": "Standardwerte für Aufgaben in {folder}.", - "settingsScope": "Geltungsbereich", - "settingsScopeGlobal": "Alle Ordner (globale Standardwerte)", - "settingsScopeGlobalHint": "Ordner ohne eigene Einstellungen verwenden diese globalen Standardwerte.", - "settingsSource": "Konfigurationsquelle", - "settingsSourceGlobal": "Globale Standards", - "settingsSourceCustom": "Eigene", - "settingsSourceGlobalFollow": "Folgt den globalen Aufgaben-Einstellungen — Änderungen dort gelten hier automatisch.", - "settingsSourceCustomHint": "Speichert eigene Einstellungen für diesen Ordner; die globalen Standards gelten dann nicht mehr.", - "settingsAgent": "Standard-Agent", - "settingsMaxConcurrent": "Max. gleichzeitige Aufgaben", - "settingsMaxConcurrentHint": "0 = unbegrenzt", - "settingsAutoProcess": "Automatisch verarbeiten", - "settingsAutoProcessHint": "Offene Aufgaben starten von selbst, bis zum Parallelitätslimit.", - "settingsMergeStrategy": "Standard-Merge-Strategie", - "settingsMergeStrategyHint": "Wie die Änderungen der Aufgabe beim Mergen im Branch-Verlauf festgehalten werden.", - "settingsAutoMerge": "Automatisch mergen", - "settingsAutoMergeHint": "Eine Aufgabe, die mit landbaren Änderungen das Review erreicht, wird gemergt, als hättest du auf Mergen geklickt: Der Agent schreibt die Commit-Nachricht, der Worktree folgt der Voreinstellung unten. Bei rotem Preflight oder einem fehlgeschlagenen Merge wartet die Aufgabe auf dich.", - "settingsDeleteWorktree": "Worktree nach dem Mergen löschen", - "settingsDeleteWorktreeHint": "Aktiviert die Option im Merge-Dialog vor; dort lässt sie sich weiterhin ändern.", - "settingsWorktreeRoot": "Worktree-Verzeichnis", - "settingsWorktreeRootHint": "Verzeichnis, in dem neue Aufgaben-Worktrees angelegt werden – eines pro Aufgabe. Leer lassen, um sie neben dem Projektordner anzulegen; „~“ ist dein Home-Verzeichnis, ein relativer Pfad gilt relativ zum Projektordner.", - "settingsWorktreeRootPlaceholder": "~/codeg-worktrees", - "settingsWorktreeRootBrowse": "Worktree-Verzeichnis auswählen", - "settingsPreflight": "Preflight-Befehl", - "settingsPreflightHint": "Läuft im Worktree, sobald eine Aufgabe das Review erreicht.", - "settingsPreflightCustomPlaceholder": "pnpm test", - "settingsInitCommand": "Worktree-Init-Befehl", - "settingsInitCommandHint": "Läuft in einem frisch erstellten Worktree, bevor der Agent startet.", - "settingsInitCommandPlaceholder": "pnpm install", - "settingsTabGeneral": "Allgemein", - "settingsTabMerge": "Merge", - "settingsTabWorktree": "Worktree", - "settingsTabPrompts": "Prompts", - "settingsPromptsIntro": "Jede Phase sendet bereits einen eingebauten Prompt — die Aufgabe selbst, die Worktree-Regeln und beim Mergen die genauen Git-Schritte. Was du hier ergänzt, wird als zusätzliche Anweisung ans Ende gehängt: Es verfeinert den eingebauten Text, ersetzt ihn aber nie.", - "settingsPromptStageAll": "Alle Phasen", - "settingsPromptPlaceholderAll": "z. B. Halte dich an die Konventionen in AGENTS.md; fasse am Ende in zwei Sätzen zusammen", - "settingsPromptPlaceholderWork": "z. B. Lies zuerst die zugehörigen Tests; committe in kleinen Schritten", - "settingsPromptPlaceholderRetry": "z. B. Prüfe vor dem Weitermachen, was bereits committet ist; wiederhole nichts Fertiges", - "settingsPromptPlaceholderReturn": "Z. B. Arbeite jeden genannten Punkt ab; refaktoriere nichts Fremdes", - "settingsPromptPlaceholderMerge": "z. B. Schreibe die Merge-Commit-Nachricht auf Deutsch; nenne jeden manuell gelösten Konflikt", - "settingsPromptHintAll": "Wird an jeden Prompt des Agents angehängt, auch beim Merge-Lauf.", - "settingsPromptHintWork": "Wird angehängt, wenn eine Aufgabe zum ersten Mal läuft.", - "settingsPromptHintRetry": "Wird angehängt, wenn eine unterbrochene oder fehlgeschlagene Aufgabe fortgesetzt wird.", - "settingsPromptHintReturn": "Wird ergänzt, wenn du bei einer Aufgabe in Prüfung nachfasst (überarbeiten, erweitern, prüfen).", - "settingsPromptHintMerge": "Wird angehängt, wenn der Agent die Aufgabe in den Basis-Branch übernimmt.", - "preflightPassed": "{name} bestanden", - "preflightFailed": "{name} fehlgeschlagen", - "preflightRunning": "{name} läuft…", - "detailDescription": "Aufgabendetails", - "detailSummary": "Ergebnis", - "detailFiles": "Geänderte Dateien", - "detailDiffAll": "Gesamtes Diff anzeigen", - "detailDiffAllTitle": "Gesamtes Diff", - "detailNoChanges": "Noch keine Änderungen gegenüber der Basis", - "detailTimeline": "Verlauf", - "detailTimelineEmpty": "Noch keine Aktivität", - "showMore": "Mehr anzeigen", - "showLess": "Weniger anzeigen", - "detailInfo": "Details", - "detailBranch": "Branch", - "detailMergeCommit": "Merge-Commit", - "detailChanges": "Änderungen", - "detailScheduled": "Geplanter Start", - "detailCreated": "Erstellt", - "detailStarted": "Gestartet", - "detailFinished": "Abgeschlossen", - "diffLoading": "Diff wird geladen…", - "deleteConfirmTitle": "Aufgabe löschen?", - "deleteConfirmBody": "„{title}“ wird vom Board entfernt. Ein aktiver Lauf wird zuerst abgebrochen.", - "deleteWithWorktree": "Auch den Worktree löschen", - "eventCreated": "Erstellt", - "eventStatusChanged": "Statusänderung", - "eventConfigEffective": "Startkonfiguration", - "eventInitCommand": "Init-Befehl", - "eventAgentProgress": "Agent-Fortschritt", - "eventAgentVerdict": "Agent-Urteil", - "eventMergeAttempt": "Merge gestartet", - "eventMergeQueued": "In Merge-Warteschlange", - "eventMergeConflict": "Merge-Konflikt", - "eventPreflight": "Preflight", - "eventCleanupFailed": "Worktree-Aufräumen fehlgeschlagen", - "eventResumeFallback": "Sitzungsfortsetzung fehlgeschlagen, neue Sitzung", - "eventUserAction": "Benutzeraktion", - "eventDiffStat": "Änderungs-Snapshot" - }, - "CustomSkillsSettings": { - "loading": "Benutzerdefinierte Skills werden geladen…", - "category": "Benutzerdefiniert", - "searchPlaceholder": "Benutzerdefinierte Skills nach Name, ID oder Beschreibung suchen", - "states": { - "not_linked": "Nicht aktiviert", - "linked_to_codeg": "Aktiviert", - "linked_elsewhere": "Anderweitig verknüpft", - "blocked_by_real_directory": "Durch echten Ordner blockiert", - "broken": "Defekter Link" - }, - "actions": { - "new": "Neu", - "import": "Importieren", - "importFromAgent": "Von Agent importieren", - "cancel": "Abbrechen", - "save": "Speichern" - }, - "rowMenu": { - "edit": "Bearbeiten", - "duplicate": "Duplizieren", - "delete": "Löschen" - }, - "bulk": { - "delete": "Auswahl löschen" - }, - "editor": { - "createTitle": "Neuer benutzerdefinierter Skill", - "editTitle": "Benutzerdefinierten Skill bearbeiten", - "description": "Benutzerdefinierte Skills liegen im gemeinsamen Speicher (~/.codeg/skills) und können für jeden Agenten aktiviert werden.", - "idLabel": "Skill-ID", - "idPlaceholder": "z. B. my-workflow", - "contentLabel": "SKILL.md", - "contentPlaceholder": "Hier die SKILL.md des Skills schreiben…", - "preview": "Vorschau", - "edit": "Bearbeiten", - "emptyBody": "Noch kein Inhalt." - }, - "duplicate": { - "title": "Skill duplizieren", - "description": "Eine Kopie von „{id}“ mit einer neuen ID erstellen.", - "newIdPlaceholder": "Neue Skill-ID", - "confirm": "Duplizieren" - }, - "import": { - "title": "Skill-Ordner zum Importieren wählen" - }, - "importFromAgent": { - "title": "Skills von einem Agenten importieren", - "description": "Kopiere die eigenen Skills eines Agenten in den gemeinsamen Speicher, um sie für jeden Agenten zu aktivieren.", - "agentLabel": "Agent", - "agentPlaceholder": "Agent auswählen", - "selectAll": "Alle auswählen ({count})", - "loading": "Skills des Agenten werden geladen…", - "unsupported": "Dieser Agent stellt kein Skill-Verzeichnis bereit.", - "empty": "Dieser Agent hat keine importierbaren Skills.", - "alreadyInLibrary": "In Bibliothek", - "confirm": "Auswahl importieren ({count})" - }, - "delete": { - "title": "Benutzerdefinierte Skills löschen?", - "body": "Dadurch werden {count} benutzerdefinierte Skill(s) aus dem zentralen Speicher entfernt und von allen Agenten getrennt. Dies kann nicht rückgängig gemacht werden.", - "confirm": "Löschen" - }, - "toasts": { - "loadFailed": "Skill konnte nicht geladen werden", - "idRequired": "Bitte eine Skill-ID eingeben", - "created": "Benutzerdefinierter Skill erstellt", - "updated": "Benutzerdefinierter Skill aktualisiert", - "saveFailed": "Skill konnte nicht gespeichert werden", - "imported": "Skill importiert", - "importFailed": "Skill konnte nicht importiert werden", - "duplicated": "Skill dupliziert", - "duplicateFailed": "Skill konnte nicht dupliziert werden", - "deleted": "{count} Skill(s) gelöscht", - "deletedPartial": "{ok} gelöscht, {failed} fehlgeschlagen", - "deleteFailed": "Skills konnten nicht gelöscht werden", - "importedFromAgent": "{count} Skill(s) importiert", - "importedFromAgentPartial": "{ok} importiert, {failed} fehlgeschlagen", - "importFromAgentAllSkipped": "Nichts zu importieren – {count} bereits in der Bibliothek", - "importFromAgentFailed": "Import vom Agenten fehlgeschlagen" - } - }, - "CodexModelEditor": { - "customizedNotice": "Du hast die Modellliste angepasst, daher verwaltet codeg jetzt die gesamte Modelltabelle von codex. Offizielle Modelle, die codex später hinzufügt, erscheinen nicht automatisch – klicke unten auf Aktualisieren und speichere erneut, um sie zu übernehmen. Entferne alle Anpassungen, damit codex sich wieder automatisch aktualisiert.", - "officialsTitle": "Offizielle Modelle", - "officialsHint": "Automatisch aus dem gestarteten codex übernommen; nicht benötigte entfernen.", - "officialsEmpty": "Keine offiziellen Modelle verfügbar.", - "refresh": "Aus codex aktualisieren", - "readdOfficial": "Offizielles erneut hinzufügen", - "customsTitle": "Benutzerdefinierte Modelle", - "customsEmpty": "Noch keine benutzerdefinierten Modelle.", - "addCustom": "Benutzerdefiniert hinzufügen", - "slugPlaceholder": "Modell-ID (Slug)", - "displayNamePlaceholder": "Anzeigename", - "contextWindow": "Kontext", - "makeDefault": "Als Standard festlegen", - "defaultHint": "Standardmodell", - "remove": "Entfernen", - "advanced": "Erweitert", - "baseTemplate": "Basisvorlage", - "baseTemplateHint": "Offizielles Modell, von dem Pflichtfelder (System-Prompt, Tools, Limits) geklont werden.", - "groupBehavior": "Verhalten & Funktionen", - "fieldReasoningLevel": "Standard-Reasoning", - "fieldReasoningSummary": "Reasoning-Zusammenfassung", - "fieldVerbosity": "Ausführlichkeit", - "fieldShellType": "Shell-Typ", - "fieldApplyPatch": "Apply-Patch-Tool", - "fieldReasoningSummaries": "Reasoning-Zusammenfassungen", - "fieldSupportVerbosity": "Ausführlichkeitssteuerung", - "fieldParallelToolCalls": "Parallele Tool-Aufrufe", - "fieldSearchTool": "Websuche-Tool", - "optNone": "Keine", - "groupInstructions": "Beschreibung & System-Prompt", - "fieldDescription": "Beschreibung", - "baseInstructions": "System-Prompt (base_instructions)" - }, - "DiagnosticsSettings": { - "title": "Umgebungsdiagnose", - "description": "Prüft, wie diese App die Agent-CLI im eigenen Prozess auflöst – das kann sich von deinem Terminal unterscheiden.", - "loading": "Diagnose wird ausgeführt…", - "error": "Diagnose fehlgeschlagen", - "rerun": "Erneut ausführen", - "copyAll": "Alles kopieren", - "copied": "Diagnose in die Zwischenablage kopiert", - "button": "Diagnose", - "verdict": { - "ok": "Die Umgebung sieht in Ordnung aus. Wird trotzdem „nicht installiert“ angezeigt, starte die App komplett neu, um den Prefix-Cache zu aktualisieren.", - "node_missing": "Node.js wurde im PATH der App nicht gefunden.", - "npm_missing": "npm wurde im PATH der App nicht gefunden.", - "not_installed": "Dieser Agent scheint nicht installiert zu sein.", - "installed_but_unresolved": "Als installiert vermerkt, aber die App findet die ausführbare Datei nicht.", - "user_prefix_not_on_path": "In das Ausweich-Prefix (~/.codeg/npm-global) installiert, das nicht im PATH der App liegt. Starte die App komplett neu und versuche es erneut.", - "homebrew_bin_not_on_path": "Unter dem Homebrew-bin installiert, das nicht im PATH der App liegt (Apple-Silicon-Keg-Trennung).", - "terminal_only_path": "Der Befehl wird in deinem Terminal aufgelöst, aber nicht in der App – eine GUI-PATH-Lücke. Starte die App aus einem Terminal oder installiere sie in den Agent-Einstellungen neu.", - "npm_prefix_timeout": "npm prefix -g war zu langsam (über 1,5 s), daher wurde die Ausweicherkennung übersprungen. Starte die App neu und versuche es erneut.", - "node_too_old": "Dein aktives Node.js ist älter als von diesem Agenten benötigt. Aktualisiere Node.js.", - "adapter_missing_native_present": "Deine eigene {agent}-CLI ist installiert, aber Codeg startet ein separates ACP-Adapterpaket — und das fehlt noch. Installiere es in den Agenten-Einstellungen; es rührt deine CLI nicht an und teilt sich dieselbe Anmeldung.", - "adapter_missing": "Codeg startet für {agent} ein separates ACP-Adapterpaket, das noch nicht installiert ist. Installiere es in den Agenten-Einstellungen — die Hersteller-CLI allein genügt nicht." - } - }, - "TokenUsage": { - "title": "Token-Verbrauch", - "rangeLabel": "Zeitraum", - "range7d": "7 Tage", - "range30d": "30 Tage", - "range90d": "90 Tage", - "rangeThisMonth": "Dieser Monat", - "rangeThisYear": "Dieses Jahr", - "rangeAll": "Gesamt", - "rangeCustom": "Benutzerdefiniert", - "moreRanges": "Mehr", - "customRangePick": "Zeitraum wählen", - "bucketLabel": "Gruppieren nach", - "bucketDay": "Tag", - "bucketWeek": "Woche", - "bucketMonth": "Monat", - "bucketUnitDay": "Tag", - "bucketUnitWeek": "Woche", - "bucketUnitMonth": "Monat", - "folderFilter": "Ordner", - "allFolders": "Alle Ordner", - "agentFilter": "Agenten", - "allAgents": "Alle Agenten", - "modelFilter": "Modelle", - "allModels": "Alle Modelle", - "searchPlaceholder": "Suchen…", - "noMatches": "Keine Treffer", - "clearFilter": "Auswahl löschen", - "resetFilters": "Filter zurücksetzen", - "refresh": "Aktualisieren", - "rebuild": "Alles neu aufbauen", - "rebuildHint": "Verwirft die gezählten Daten und liest alle Sitzungsprotokolle neu ein. Nützlich, wenn eine Sitzung außerhalb von codeg gewachsen ist.", - "syncing": "Sitzungen werden gezählt…", - "syncProgress": "{done} / {total}", - "syncDone": "{synced} Sitzungen gezählt", - "syncFailed": "Einige Sitzungen konnten nicht gelesen werden", - "syncBusy": "Eine Aktualisierung läuft bereits", - "lastSynced": "Aktualisiert {time}", - "lastSyncedNever": "Noch nie aktualisiert", - "tileTotal": "Tokens gesamt", - "tileSessions": "Sitzungen", - "tileTurns": "Turns", - "tileActiveDays": "Aktive Tage", - "tileGenTime": "Generierungszeit", - "vsPrevious": "ggü. Vorperiode", - "deltaNew": "neu", - "trendTitle": "Verbrauch im Zeitverlauf", - "trendEmpty": "Kein Verbrauch in diesem Zeitraum", - "trendTurns": "Turns", - "trendSessions": "Sitzungen", - "compositionTitle": "Wofür die Tokens draufgingen", - "compositionHint": "Eingabe ist, was du gesendet hast, Ausgabe, was das Modell geschrieben hat, und Cache-Lesevorgänge sind Kontext, den du nicht voll bezahlt hast.", - "compositionNote": "Diese Cache-Treffer zum vollen Preis erneut zu senden hätte weitere {value} gekostet.", - "inputTokens": "Eingabe", - "outputTokens": "Ausgabe", - "cacheWrite": "Cache-Schreiben", - "cacheRead": "Cache-Lesen", - "freshTokens": "Frisch berechnet", - "cacheHitCaption": "Cache-Treffer", - "cacheHeroTitleHigh": "Der Großteil des Kontexts musste nie erneut gesendet werden", - "cacheHeroTitleLow": "Der Großteil des Kontexts wird noch voll berechnet", - "cacheHeroDesc": "{cached} des Kontexts trug der Cache — nur {fresh} wurde in diesem Zeitraum wirklich neu berechnet.", - "cacheSavedSuffix": "Das sparte erneutes Senden im Umfang von {saved}.", - "avgPerSession": "Ø pro Sitzung", - "avgTurnsPerSession": "Ø {count} Turns pro Sitzung", - "avgPerActiveDay": "Ø pro aktivem Tag", - "peakBucket": "Stärkste(r) {bucket}", - "peakHour": "Spitzenstunde", - "daysValue": "{count} Tage", - "idleDays": "Leerlauftage", - "byFolderTitle": "Nach Ordner", - "byAgentTitle": "Nach Agent", - "byModelTitle": "Nach Modell", - "distributionTitle": "Verteilung der Nutzung", - "distributionHint": "Sitzungen und Tokens nach gewählter Dimension gebündelt — Klick auf eine Zeile filtert danach.", - "otherLabel": "Sonstige", - "unknownModel": "Modell nicht erfasst", - "emptyBreakdown": "Noch nichts erfasst", - "sessionsCount": "{count} Sitzungen", - "heatmapTitle": "Wann du baust", - "heatmapHint": "Tokens nach lokalem Wochentag und Stunde.", - "heatmapPeakHint": "Am dichtesten gegen {hour}:00 Uhr.", - "less": "Weniger", - "more": "Mehr", - "heatmapCell": "{weekday} {hour}:00 — {value} Tokens", - "weekMon": "Mo", - "weekTue": "Di", - "weekWed": "Mi", - "weekThu": "Do", - "weekFri": "Fr", - "weekSat": "Sa", - "weekSun": "So", - "topSessionsTitle": "Teuerste Sitzungen", - "untitledSession": "Unbenannte Sitzung", - "topSessionsEmpty": "Keine Sitzungen in diesem Zeitraum", - "streakLongest": "Längste Serie", - "streakLongestDays": "Längste Serie: {count} Tage", - "share": "Teilen", - "moreActions": "Weitere Aktionen", - "shareDialogTitle": "Teile deine Verbrauchskarte", - "shareDialogHint": "Eine Momentaufnahme des gewählten Zeitraums und der Filter.", - "shareSave": "Bild speichern", - "shareCopy": "Bild kopieren", - "shareCopied": "In die Zwischenablage kopiert", - "shareSaved": "Bild gespeichert", - "shareFailed": "Bild konnte nicht erstellt werden", - "shareRendering": "Wird erstellt…", - "cardHeading": "Meine KI-Coding-Bilanz", - "cardRangeAll": "Gesamter Zeitraum", - "cardTotalLabel": "Verbrauchte Tokens", - "cardFooter": "Erstellt mit codeg", - "cardTopModels": "Top-Modelle", - "cardTopProjects": "Top-Projekte", - "archetypeNightOwl": "Nachteule", - "archetypeNightOwlDesc": "{percent}% deiner Tokens gehen nach Einbruch der Dunkelheit drauf.", - "archetypeEarlyBird": "Frühaufsteher", - "archetypeEarlyBirdDesc": "{percent}% deiner Tokens fallen vor 9 Uhr an.", - "archetypeWeekendWarrior": "Wochenendkrieger", - "archetypeWeekendWarriorDesc": "{percent}% deiner Tokens entstehen am Wochenende.", - "archetypeCacheMaster": "Cache-Meister", - "archetypeCacheMasterDesc": "{percent}% deines Kontexts kamen aus dem Cache.", - "archetypeMarathoner": "Marathonläufer", - "archetypeMarathonerDesc": "{days} Tage am Stück gebaut.", - "archetypePolyglot": "Allrounder", - "archetypePolyglotDesc": "{count} Agenten im ernsthaften Einsatz.", - "archetypeLaserFocus": "Laserfokus", - "archetypeLaserFocusDesc": "{percent}% deiner Tokens gingen in ein einziges Projekt.", - "archetypeDeepDiver": "Tieftaucher", - "archetypeDeepDiverDesc": "{averageK}K Tokens in einer durchschnittlichen Sitzung.", - "archetypeSteady": "Stetiger Bauer", - "archetypeSteadyDesc": "{days} Tage geliefert.", - "emptyTitle": "Noch nichts gezählt", - "emptyHint": "Codeg liest die Token-Zahlen direkt aus dem Protokoll jedes Agenten. Aktualisiere, um zu zählen, was schon auf diesem Rechner liegt.", - "emptyAction": "Meine Sitzungen zählen", - "loadFailed": "Verbrauch konnte nicht geladen werden", - "truncatedNotice": "Dieser Zeitraum ist sehr groß — die Zahlen decken nur seinen jüngsten Abschnitt ab." - } -} +{ + "Language": { + "followSystem": "Systemsprache verwenden", + "english": "Englisch", + "simplifiedChinese": "Vereinfachtes Chinesisch", + "traditionalChinese": "Traditionelles Chinesisch", + "japanese": "Japanisch", + "korean": "Koreanisch", + "spanish": "Spanisch", + "german": "Deutsch", + "french": "Französisch", + "portuguese": "Portugiesisch", + "arabic": "Arabisch" + }, + "GitCredentialDialog": { + "title": "Authentifizierung erforderlich", + "description": "Der Remote-Server erfordert Anmeldedaten. Geben Sie Ihren Benutzernamen und Ihr Passwort (oder persönliches Zugriffstoken) ein.", + "username": "Benutzername", + "usernamePlaceholder": "Benutzername oder E-Mail", + "password": "Passwort / Token", + "passwordPlaceholder": "Passwort oder persönliches Zugriffstoken", + "passwordHint": "Geben Sie Benutzername und Passwort des Servers ein.", + "cancel": "Abbrechen", + "authenticate": "Authentifizieren", + "authenticating": "Authentifizierung...", + "invalidCredentials": "Ungültige Anmeldedaten. Bitte versuchen Sie es erneut.", + "saveCredentials": "Anmeldedaten für zukünftige Vorgänge speichern", + "githubTitle": "GitHub-Authentifizierung", + "githubDescription": "Geben Sie ein persönliches Zugriffstoken ein, um sich mit GitHub zu verbinden. Das Token wird validiert und automatisch gespeichert.", + "githubToken": "Persönliches Zugriffstoken", + "githubTokenPlaceholder": "ghp_xxxxxxxxxxxx", + "githubTokenHint": "Erstellen Sie ein Token unter GitHub → Settings → Developer settings → Personal access tokens.", + "githubAuthenticate": "Validieren & verbinden", + "generateToken": "Token erstellen" + }, + "SettingsShell": { + "title": "Einstellungen", + "preferences": "Präferenzen", + "nav": { + "general": "Allgemein", + "appearance": "Darstellung", + "agents": "Agenten", + "mcp": "MCP", + "skills": "Skills", + "shortcuts": "Kurzbefehle", + "version_control": "Versionskontrolle", + "system": "Systemeinstellungen", + "chat_channels": "Chat-Kanäle", + "web_service": "Webdienst", + "model_providers": "Modellanbieter", + "experts": "Experten", + "science": "Wissenschaft", + "office_tools": "Office-Tools", + "skill_packs": "Skill-Pakete", + "quick_messages": "Schnellnachrichten", + "logs": "Laufzeitprotokolle" + } + }, + "AppearanceSettings": { + "sectionTitle": "Design-Erscheinungsbild", + "sectionDescription": "Wähle hell, dunkel oder Systemvorgabe. Einstellungen werden automatisch gespeichert.", + "themeMode": "Designmodus", + "placeholder": "Designmodus auswählen", + "system": "Systemvorgabe", + "light": "Hell", + "dark": "Dunkel", + "currentTheme": "Aktuell wirksames Design: {theme}", + "resolvedTheme": { + "light": "Hell", + "dark": "Dunkel", + "unknown": "--" + }, + "themeColor": { + "sectionTitle": "Themenfarbe", + "sectionDescription": "Wähle eine Farbpalette für Akzente, Schaltflächen und Hervorhebungen.", + "current": "Aktuelle Farbe: {color}", + "options": { + "neutral": "Neutral", + "zinc": "Zinc", + "slate": "Slate", + "stone": "Stone", + "gray": "Gray", + "red": "Red", + "rose": "Rose", + "orange": "Orange", + "green": "Green", + "blue": "Blue", + "yellow": "Yellow", + "violet": "Violet" + } + }, + "customStyle": { + "sectionTitle": "Eigener Stil", + "sectionDescription": "Feinjustiere die Farben des aktuellen Themes oder füge eigenes CSS ein. Überschreibungen liegen über der Basisvorlage und bleiben beim Wechsel der Vorlage erhalten.", + "summarySuspended": "Ausgesetzt", + "summaryDefault": "Vorlage unverändert", + "summaryTokens": "{count, plural, one {# Überschreibung} other {# Überschreibungen}}", + "summaryCss": "Eigenes CSS", + "suspendedByShortcut": "Der eigene Stil ist ausgesetzt. Nichts, was du hier einstellst, wirkt, bis du ihn fortsetzt.", + "suspendedBySafeParam": "Dieses Fenster wurde im sicheren Darstellungsmodus geöffnet, daher wird eigener Stil hier ignoriert. Andere Fenster sind nicht betroffen.", + "resume": "Eigenen Stil fortsetzen", + "enableTheme": "Eigene Farben aktivieren", + "editingLight": "Du bearbeitest die Werte des hellen Modus. Wechsle die App in den dunklen Modus, um diesen separat einzustellen.", + "editingDark": "Du bearbeitest die Werte des dunklen Modus. Wechsle die App in den hellen Modus, um diesen separat einzustellen.", + "resetToken": "Auf Vorlagenwert zurücksetzen", + "radius": "Eckenradius", + "radiusHint": "Daraus leitet sich die gesamte Radiusskala von sm bis 4xl ab – ein Regler rundet die ganze App.", + "advanced": "Erweitert ({count} weitere Variablen)", + "enableCss": "Eigenes CSS aktivieren", + "cssRisk": "Funktion für Fortgeschrittene. Eigenes CSS überschreibt sämtliche eingebauten Stile und kann die Oberfläche unbrauchbar machen.", + "editCss": "CSS bearbeiten…", + "cssPresent": "{size} KB gespeichert", + "cssEmpty": "Noch nichts gespeichert", + "escapeHint": "Oberfläche kaputt? Drücke {shortcut}, um den gesamten eigenen Stil auszusetzen, oder öffne ein Fenster mit dem Query-Parameter safeStyle=1.", + "copyTheme": "Theme-JSON kopieren", + "importTheme": "Theme importieren…", + "clearTheme": "Überschreibungen löschen", + "interopHint": "Themes nutzen das registry:theme-Format von shadcn – du kannst hier jedes shadcn-Theme einfügen und exportierte in jedem shadcn-Projekt verwenden.", + "importTitle": "Theme importieren", + "importDescription": "Füge ein shadcn-registry:theme-Item, ein reines light/dark-Objekt oder eine flache Token-Zuordnung ein.", + "readClipboard": "Zwischenablage lesen", + "importConfirm": "Importieren", + "cancel": "Abbrechen", + "apply": "Anwenden", + "toasts": { + "copied": "Theme-JSON kopiert", + "copyFailed": "Kopieren in die Zwischenablage fehlgeschlagen", + "clipboardReadFailed": "Zwischenablage konnte nicht gelesen werden, bitte manuell einfügen", + "importFailed": "In diesem JSON wurden keine nutzbaren Theme-Variablen gefunden", + "imported": "Theme importiert" + }, + "css": { + "dialogTitle": "Eigenes CSS", + "dialogDescription": "Gilt für alle codeg-Fenster. Änderungen werden live vorschauend angezeigt; zum Speichern auf Anwenden klicken.", + "size": "{used} KB / {max} KB", + "ruleCount": "{count} Regeln", + "errorTooLarge": "Zu groß zum Speichern. Bitte unter das Limit kürzen.", + "errorImportEscaped": "Eine @import-Regel hat das Entfernen überstanden (maskierte Schreibweise). Bitte entfernen, um zu speichern.", + "warnNoRules": "Keine Regeln erkannt – bitte die Syntax prüfen.", + "noticeImportsRemoved": "Entfernte @import-Regeln: {count}. Sie würden entfernte Stylesheets laden.", + "noticeRemoteUrl": "Enthält eine entfernte url(), die beim Anwenden eine Netzwerkanfrage auslöst.", + "noticePreviewSuspended": "Der eigene Stil ist ausgesetzt, daher wird diese Vorschau nicht angewendet.", + "noticeDisabled": "Eigenes CSS ist aus. Du kannst hier eine Vorschau sehen, aber es wirkt erst nach dem Aktivieren.", + "hintTokens": "Tipp: Deine überschriebenen Farben sind als var(--primary), var(--background) usw. verfügbar." + } + }, + "zoomLevel": { + "sectionTitle": "Fensterzoom", + "sectionDescription": "Skaliert die gesamte Oberfläche. Wird sofort übernommen und pro Gerät gespeichert.", + "placeholder": "Zoomstufe wählen", + "default": "Standard", + "current": "Aktueller Zoom: {zoom}%" + }, + "fonts": { + "sectionTitle": "Schriftarten", + "sectionDescription": "Wähle Schriftarten für Oberfläche, Code-Editor und Terminal. Mitgelieferte Schriftarten werden bei Bedarf geladen; wähle „Benutzerdefiniert…“, um eine beliebige auf deinem System installierte Schriftart zu verwenden.", + "interface": "Oberfläche", + "editor": "Editor", + "terminal": "Terminal", + "groupSans": "Serifenlos", + "groupMono": "Monospace", + "custom": "Benutzerdefiniert…", + "customPlaceholder": "Schriftartname, z. B. Fira Code", + "fontSize": "Schriftgröße", + "ligatures": "Ligaturen aktivieren", + "ligaturesUnavailable": "Diese Schriftart hat keine Ligaturen", + "wordWrap": "Zeilenumbruch aktivieren", + "terminalLigaturesHint": "Terminal-Ligaturen gelten nur für mitgelieferte Programmierschriftarten.", + "preview": "Vorschau" + }, + "welcomePanel": { + "sectionTitle": "Modusauswahlbereich", + "sectionDescription": "Die Shortcut-Karten „Code-Entwicklung / Büroarbeit“ über dem Eingabefeld auf der Seite für eine neue Konversation.", + "showQuickActions": "Auf der Seite für neue Konversationen anzeigen" + }, + "workspaceBackground": { + "sectionTitle": "Arbeitsbereich-Hintergrund", + "sectionDescription": "Zeigt ein Bild hinter dem gesamten Arbeitsbereich. Seitenleiste und Panels werden durchscheinend und mattiert, sodass das Bild durchscheint, und eine Maske sorgt für lesbaren Text.", + "enable": "Hintergrundbild aktivieren", + "image": "Bild", + "chooseImage": "Bild auswählen", + "replaceImage": "Bild ersetzen", + "removeImage": "Entfernen", + "fillMode": "Füllmodus", + "fillModes": { + "cover": "Füllen", + "contain": "Einpassen", + "center": "Zentrieren", + "tile": "Kacheln" + }, + "maskOpacity": "Maskendeckkraft", + "maskOpacityHint": "Höhere Werte blenden das Bild zur Hintergrundfarbe des Themes aus und verbessern den Textkontrast.", + "imageBlur": "Bildunschärfe", + "panelOpacity": "Panel-Deckkraft", + "panelOpacityHint": "Wie deckend Seitenleiste, Panels und Tab-Leisten sind. Niedriger lässt mehr vom Bild durchscheinen.", + "errorTooLarge": "Bild ist zu groß (max. 16 MB).", + "errorUploadFailed": "Hintergrundbild konnte nicht festgelegt werden." + } + }, + "SystemSettings": { + "loading": "Wird geladen...", + "sectionTitle": "Systemverwaltung", + "sectionDescription": "Verwalte Netzwerk-Proxy, App-Updates und Spracheinstellungen.", + "proxyTitle": "Netzwerk-Proxy", + "proxyDescription": "Wenn aktiviert, werden nachfolgende Netzwerkanfragen bevorzugt über diesen Proxy ausgeführt (einschließlich ACP-Chat, Agent-Installation und Git-Remote-Operationen).", + "loadFailed": "Laden fehlgeschlagen: {message}", + "enableProxy": "System-Proxy aktivieren", + "proxyAddress": "Proxy-Adresse", + "proxyHint": "Unterstützt http(s)/socks5, Beispiel: {example}. Wirksam nur bei aktiviertem System-Proxy.", + "save": "Speichern", + "saving": "Wird gespeichert...", + "proxyRequired": "Bei aktiviertem Proxy ist eine Proxy-URL erforderlich", + "saveSuccess": "System-Proxy-Einstellungen wurden gespeichert", + "saveFailed": "Speichern fehlgeschlagen: {message}", + "languageTitle": "Sprache", + "languageDescription": "Lege die App-Sprache fest. Bei Systemsprache wird bei nicht unterstützten Sprachen auf Englisch zurückgefallen.", + "appLanguage": "App-Sprache", + "languageSaveSuccess": "Spracheinstellungen wurden gespeichert", + "languageSaveFailed": "Spracheinstellungen konnten nicht gespeichert werden: {message}", + "updateTitle": "App-Update", + "versionTitle": "Softwareupdate", + "updateDescription": "Prüft die konfigurierte Release-Quelle auf neue Versionen und installiert sie bei Verfügbarkeit direkt.", + "currentVersion": "Aktuelle Version", + "upgradableVersion": "Neueste Version", + "none": "Keine", + "lastChecked": "Zuletzt geprüft: {time}", + "updateError": "Update-Fehler: {message}", + "checking": "Wird geprüft...", + "checkUpdate": "Nach Updates suchen", + "updating": "Wird installiert...", + "downloading": "Herunterladen...", + "upgradeTo": "Auf v{version} aktualisieren", + "viewRelease": "Release v{version} anzeigen", + "foundUpdate": "Neue Version v{version} gefunden", + "alreadyLatest": "Du verwendest bereits die neueste Version", + "checkUpdateFailed": "Update-Prüfung fehlgeschlagen: {message}", + "installSuccess": "Update installiert. App wird neu gestartet.", + "installFailed": "Update fehlgeschlagen: {message}", + "upgradeSuccess": "Aktualisierung abgeschlossen. Wird neu geladen...", + "restartTimeout": "Der Server ist nicht rechtzeitig zurückgekehrt. Prüfe die Container- oder Dienstprotokolle.", + "restartingIn": "Neustart in {seconds} s...", + "waitingForServer": "Warten, bis der Server zurückkehrt...", + "restartToUpdate": "Zum Aktualisieren neu starten", + "newVersionBadge": "Neu v{version}", + "updateAvailableTitle": "Update verfügbar", + "releaseNotesTitle": "Neuerungen", + "remindLater": "Später", + "retry": "Erneut versuchen", + "stepDownload": "Download", + "stepInstall": "Installation", + "stepRestart": "Neustart", + "updateReadyHint": "Update heruntergeladen – zum Anwenden neu starten.", + "restarting": "Neustart...", + "dockerUpgradeHint": "Dies aktualisiert jetzt den laufenden Container. Beim Neuerstellen des Containers geht es verloren – zum Beibehalten ein Image mit der neuen Version ziehen oder bauen und den Container neu erstellen.", + "upgradeRolledBack": "Upgrade fehlgeschlagen; der Server wurde auf die vorherige Version zurückgesetzt.", + "serverUnreachable": "Der Server konnte für das Upgrade nicht erreicht werden. Prüfe, ob er läuft, und versuche es erneut.", + "rollbackButton": "Zurücksetzen", + "rollingBack": "Wird zurückgesetzt...", + "rollbackDescription": "Stellt die vor dem letzten Upgrade installierte Version wieder her.", + "rollbackConfirmTitle": "Auf die vorherige Version zurücksetzen?", + "rollbackConfirmDescription": "Der Server startet mit der vor dem letzten Upgrade installierten Version neu. Eine neuere Version kann weiterhin erneut installiert werden.", + "rollbackConfirm": "Zurücksetzen", + "rollbackCancel": "Abbrechen", + "rollbackSuccess": "Auf die vorherige Version zurückgesetzt. Wird neu geladen...", + "rollbackFailed": "Zurücksetzen fehlgeschlagen. Prüfe die Serverprotokolle.", + "updateErrors": { + "sourceUnavailable": "Die Update-Quelle ist nicht erreichbar. Prüfe Netzwerk oder Proxy und versuche es erneut.", + "network": "Netzwerkverbindung fehlgeschlagen. Prüfe Netzwerk oder Proxy und versuche es erneut.", + "downloadFailed": "Das Update-Paket konnte nicht heruntergeladen werden. Bitte später erneut versuchen.", + "installFailed": "Das Update konnte nicht installiert werden. Bitte App schließen und erneut versuchen.", + "unknown": "Update fehlgeschlagen. Bitte später erneut versuchen." + } + }, + "VersionControlSettings": { + "loading": "Laden...", + "sectionTitle": "Versionskontrolle", + "sectionDescription": "Git-Programm konfigurieren und GitHub-Konten verwalten.", + "gitTitle": "Git-Konfiguration", + "gitDescription": "Konfigurieren Sie das von der Anwendung verwendete Git-Programm.", + "gitDetected": "Git erkannt", + "gitNotFound": "Git wurde nicht gefunden", + "gitVersion": "Version", + "gitPath": "Pfad", + "customGitPath": "Benutzerdefinierter Git-Pfad", + "customGitPathPlaceholder": "/usr/bin/git", + "customGitPathHint": "Leer lassen, um den automatisch erkannten Pfad zu verwenden.", + "test": "Testen", + "testing": "Teste...", + "testSuccess": "Git-Programm ist gültig.", + "testFailed": "Git-Test fehlgeschlagen: {message}", + "save": "Speichern", + "saving": "Speichern...", + "saveSuccess": "Git-Einstellungen gespeichert.", + "saveFailed": "Speichern fehlgeschlagen: {message}", + "githubTitle": "GitHub-Konten", + "githubDescription": "GitHub-Konten für die Authentifizierung verwalten. Token werden lokal gespeichert.", + "noAccounts": "Keine GitHub-Konten konfiguriert.", + "addAccount": "Konto hinzufügen", + "serverUrl": "Server-URL", + "serverUrlPlaceholder": "https://github.com", + "token": "Persönlicher Zugriffstoken", + "tokenPlaceholder": "ghp_xxxxxxxxxxxx", + "generateToken": "Token erstellen", + "tokenHint": "Erstellen Sie einen Token unter GitHub → Settings → Developer settings → Personal access tokens.", + "validateAndAdd": "Validieren & hinzufügen", + "validating": "Validiere...", + "addSuccess": "Konto {username} erfolgreich hinzugefügt.", + "addFailed": "Konto konnte nicht hinzugefügt werden: {message}", + "testConnection": "Testen", + "connectionSuccess": "Verbindung erfolgreich.", + "connectionFailed": "Verbindung fehlgeschlagen: {message}", + "setDefault": "Als Standard festlegen", + "defaultLabel": "Standard", + "defaultSet": "Standardkonto aktualisiert.", + "removeAccount": "Entfernen", + "removeConfirmTitle": "Konto entfernen", + "removeConfirmMessage": "Möchten Sie das Konto \"{username}\" wirklich entfernen?", + "removeConfirm": "Entfernen", + "removeCancel": "Abbrechen", + "removeSuccess": "Konto entfernt.", + "scopes": "Berechtigungen", + "loadFailed": "Einstellungen konnten nicht geladen werden: {message}", + "gitAccount": { + "sectionTitle": "Git-Server-Konten", + "sectionDescription": "Verwalten Sie Anmeldedaten für Nicht-GitHub-Git-Server (GitLab, Bitbucket, selbst gehostet usw.).", + "noAccounts": "Keine Git-Server-Konten konfiguriert.", + "addAccount": "Konto hinzufügen", + "addTitle": "Git-Konto hinzufügen", + "addDescription": "Geben Sie Serveradresse, Benutzername und Passwort oder Zugriffstoken ein.", + "serverUrl": "Server-URL", + "serverUrlPlaceholder": "https://gitlab.example.com", + "username": "Benutzername", + "usernamePlaceholder": "Benutzername oder E-Mail", + "password": "Passwort / Token", + "passwordPlaceholder": "Passwort oder Zugriffstoken", + "passwordHint": "Geben Sie das Passwort oder Zugriffstoken des Servers ein.", + "add": "Hinzufügen", + "serverRequired": "Server-URL ist erforderlich.", + "usernameRequired": "Benutzername ist erforderlich.", + "passwordRequired": "Passwort ist erforderlich." + } + }, + "ShortcutSettings": { + "sectionTitle": "Kurzbefehle", + "resetDefault": "Standardwerte zurücksetzen", + "recordInstruction": "Klicke auf die rechte Schaltfläche und drücke dann eine Tastenkombination. Verwende Ctrl/Cmd, Alt und Shift. Drücke Esc, um die Aufzeichnung abzubrechen.", + "recording": "Kurzbefehl drücken...", + "toasts": { + "conflict": "Der Kurzbefehl wird bereits von \"{title}\" verwendet", + "updated": "Kurzbefehl aktualisiert", + "invalid": "Ungültiger Kurzbefehl, bitte erneut versuchen", + "reset": "Standard-Kurzbefehle wurden wiederhergestellt" + }, + "actions": { + "toggle_search": { + "title": "Suche öffnen", + "description": "Zeigt das Konversations-Suchpanel an oder blendet es aus" + }, + "toggle_sidebar": { + "title": "Linke Seitenleiste umschalten", + "description": "Zeigt die Seitenleiste mit der Konversationsliste an oder blendet sie aus" + }, + "toggle_terminal": { + "title": "Terminal umschalten", + "description": "Zeigt das untere Terminal-Panel an oder blendet es aus" + }, + "new_terminal_tab": { + "title": "Neues Terminal", + "description": "Erstellt einen neuen Terminal-Tab, wenn das Terminal fokussiert ist" + }, + "close_current_terminal_tab": { + "title": "Aktuelles Terminal schließen", + "description": "Schließt den aktuellen Terminal-Tab, wenn das Terminal fokussiert ist" + }, + "toggle_aux_panel": { + "title": "Rechtes Panel umschalten", + "description": "Zeigt das Zusatzinformations-Panel an oder blendet es aus" + }, + "new_conversation": { + "title": "Neue Konversation", + "description": "Erstellt einen neuen Konversations-Tab im aktuellen Ordner" + }, + "open_folder": { + "title": "Ordner öffnen", + "description": "Öffnet die Ordnerauswahl und den Ordner in einem neuen Fenster" + }, + "open_settings": { + "title": "Einstellungen öffnen", + "description": "Öffnet das Einstellungsfenster" + }, + "close_current_tab": { + "title": "Aktuellen Tab schließen", + "description": "Schließt den aktuellen Konversations- oder Dateitab" + }, + "close_all_file_tabs": { + "title": "Alle Dateitabs schließen", + "description": "Schließt alle geöffneten Dateitabs, wenn der Dateibereich aktiv ist" + }, + "next_tab": { + "title": "Nächster Tab", + "description": "Zum nächsten Konversations- oder Datei-Tab wechseln" + }, + "prev_tab": { + "title": "Vorheriger Tab", + "description": "Zum vorherigen Konversations- oder Datei-Tab wechseln" + }, + "send_message": { + "title": "Nachricht senden", + "description": "Die aktuelle Nachricht im Eingabefeld senden" + }, + "newline_in_message": { + "title": "Zeilenumbruch einfügen", + "description": "Einen Zeilenumbruch im Eingabefeld einfügen" + }, + "toggle_custom_style": { + "title": "Eigenen Stil aussetzen/fortsetzen", + "description": "Notausstieg: schaltet alle eigenen Farben und CSS aus und wieder ein" + } + } + }, + "SkillsSettings": { + "title": "Skills", + "description": "Wähle links einen Skill aus. Rechts wird standardmäßig eine Markdown-Vorschau angezeigt; wechsle zum Bearbeiten, um zu ändern und zu speichern.", + "loadingAgents": "Agenten mit Skill-Unterstützung werden geladen...", + "emptyNoManageableAgents": "Keine Agenten für Skill-Verwaltung verfügbar.", + "managedTarget": "Verwaltetes Ziel", + "selectAgentPlaceholder": "Agent auswählen", + "searchPlaceholder": "Nach Name / ID / Pfad suchen...", + "skillsList": "Skill-Liste", + "loadingSkills": "Skills werden geladen...", + "agentNotSupported": "Der aktuelle Agent unterstützt keine Skill-Verwaltung.", + "emptySkills": "Noch keine Skills. Klicke auf „Neuer Skill“, um einen zu erstellen.", + "newSkillTitle": "Neuer Skill", + "skillInfo": "Skill-Info", + "skillIdPlaceholder": "skill-id (Buchstaben/Zahlen/-/_/.)", + "skillsDirectoryWithPath": "Skill-Verzeichnis: {path}", + "skillsDirectoryNeedId": "Skill-Verzeichnis: Skill-ID eingeben, um den vollständigen Pfad zu erzeugen", + "markdownContent": "Markdown-Inhalt", + "editingStatus": "Bearbeiten", + "previewStatus": "Vorschau", + "contentPlaceholder": "Markdown-Inhalt des Skills eingeben...", + "metadataTitle": "Skill-Metadaten", + "onlyYamlMetadata": "Dieser Skill enthält nur YAML-Metadaten.", + "emptyContentHint": "Noch kein Inhalt. Klicke auf „Bearbeiten“, um zu starten.", + "loadingSkill": "Skill wird geladen...", + "emptyNoAgents": "Kein verfügbarer Agent.", + "noSelectionHint": "Wählen Sie links einen Skill oder klicken Sie auf „Neuer Skill“, um einen zu erstellen.", + "systemBadge": "System", + "systemHint": "Integrierter CLI-Skill · schreibgeschützt", + "scope": { + "global": "Global", + "folder": "Ordner", + "selectFolderPlaceholder": "Ordner auswählen", + "noFolders": "Keine Ordner gefunden", + "pickFolderHint": "Wählen Sie einen Ordner, um dessen Skills anzuzeigen." + }, + "actions": { + "preview": "Vorschau", + "edit": "Bearbeiten", + "openInWindow": "In neuem Fenster öffnen", + "delete": "Löschen", + "deleting": "Wird gelöscht...", + "refresh": "Aktualisieren", + "newSkill": "Neuer Skill", + "reset": "Zurücksetzen", + "save": "Speichern", + "saving": "Wird gespeichert...", + "cancel": "Abbrechen" + }, + "deleteDialog": { + "title": "Skill löschen", + "confirm": "Aktuellen Skill löschen? Diese Aktion kann nicht rückgängig gemacht werden.", + "confirmWithNamePrefix": "Skill", + "confirmWithNameSuffix": "löschen? Diese Aktion kann nicht rückgängig gemacht werden." + }, + "toasts": { + "loadFailed": "Skill konnte nicht geladen werden", + "openFolderFailed": "Ordner konnte nicht geöffnet werden", + "noSkillDirectory": "Kein verfügbares Skill-Verzeichnis für den aktuellen Agenten gefunden", + "nameRequired": "Skill-Name darf nicht leer sein", + "updated": "Skill aktualisiert", + "created": "Skill erstellt", + "saveFailed": "Skill konnte nicht gespeichert werden", + "deleted": "Skill gelöscht", + "deleteFailed": "Skill konnte nicht gelöscht werden" + }, + "templates": { + "gemini": "---\nname: example-skill\ndescription: Describe when this skill should be used.\n---\n\n# Skill Name\n\nInstructions for the agent when this skill is active.\n\n## Workflow\n\n1. Add actionable step one.\n2. Add actionable step two.\n", + "openCode": "---\nname: example-skill\ndescription: Describe when this skill should be used.\n---\n\n# Purpose\n\nDescribe what this skill helps with.\n\n# Steps\n\n1. Add actionable step one.\n2. Add actionable step two.\n", + "openClaw": "---\nname: example-skill\ndescription: Describe when this skill should be used.\nuser-invocable: true\ndisable-model-invocation: false\n---\n\n# Purpose\n\nDescribe what this skill helps with.\n\n# Instructions\n\n1. Add actionable instruction one.\n2. Add actionable instruction two.\n", + "default": "---\nname: example-skill\ndescription: Describe when this skill should be used.\n---\n\n# Skill: example-skill\n\n## When to use\n\n- Describe trigger conditions.\n\n## Instructions\n\n1. Add actionable instruction one.\n2. Add actionable instruction two.\n" + } + }, + "McpSettings": { + "loading": "Wird geladen...", + "summary": { + "missingCommand": "(fehlender Befehl)", + "missingUrl": "(fehlende URL)" + }, + "protocol": { + "stdio": "Stdio" + }, + "errors": { + "selectInstallProtocol": "Bitte ein Installationsprotokoll auswählen", + "fieldRequired": "{field} ist erforderlich", + "fieldNeedsBoolean": "{field} muss true oder false sein", + "fieldNeedsNumber": "{field} muss eine Zahl sein", + "fieldNeedsInteger": "{field} muss eine Ganzzahl sein", + "fieldInvalidJson": "{field} enthält ungültiges JSON: {message}", + "fieldOutOfRange": "Der Wert von {field} liegt außerhalb des erlaubten Bereichs", + "jsonEmpty": "{name} darf nicht leer sein", + "jsonInvalid": "{name} ist kein gültiges JSON: {message}", + "jsonMustBeObject": "{name} muss ein JSON-Objekt sein", + "specMustBeObject": "Die MCP-Konfiguration muss ein JSON-Objekt sein.", + "missingType": "Der Konfiguration fehlt das Feld type. Bitte stdio, http (Aliase: streamable-http, streamableHttp) oder sse angeben.", + "unsupportedType": "Nicht unterstützter MCP-Typ {type}. Unterstützt: stdio, http (Aliase: streamable-http, streamableHttp), sse.", + "codexEntryUnsupportedType": "Codex-MCP-Eintrag {id} hat den nicht unterstützten Typ {type}. Unterstützt: stdio, http (Aliase: streamable-http, streamableHttp), sse.", + "unsupportedTransportType": "Nicht unterstützter Transport-Typ {type}. Unterstützt: http (Aliase: streamable-http, streamableHttp), sse.", + "stdioCommandRequired": "stdio-MCPs benötigen ein nicht leeres Feld command.", + "remoteUrlRequired": "Remote-MCPs benötigen ein nicht leeres Feld url.", + "appsRequired": "Mindestens eine Ziel-App auswählen." + }, + "jsonNames": { + "localConfig": "MCP-Konfiguration", + "installConfig": "Installationskonfiguration" + }, + "toasts": { + "uninstalled": "MCP deinstalliert", + "uninstallFailed": "Deinstallation fehlgeschlagen: {message}", + "selectAtLeastOneApp": "Bitte mindestens eine Ziel-App auswählen", + "saveSuccess": "Gespeichert", + "saveFailed": "Speichern fehlgeschlagen: {message}", + "installed": "{name} installiert", + "installFailed": "Installation fehlgeschlagen: {message}", + "serverIdRequired": "Server-ID ist erforderlich", + "serverIdExists": "Server-ID \"{id}\" existiert bereits. Bearbeiten Sie den vorhandenen Eintrag oder wählen Sie einen anderen Namen.", + "created": "MCP erstellt" + }, + "installDialog": { + "title": "MCP-Installation bestätigen", + "descriptionWithName": "{name} in lokale Konfiguration installieren.", + "description": "Ziel-Apps für die Installation auswählen.", + "protocol": "Protokoll", + "selectProtocol": "Protokoll auswählen", + "parameters": "Konfigurationsparameter", + "booleanPlaceholder": "Bitte true/false auswählen", + "selectOneValue": "Wert auswählen", + "targetApps": "Ziel-Apps" + }, + "actions": { + "cancel": "Abbrechen", + "confirmInstall": "Installation bestätigen", + "installing": "Installieren", + "uninstall": "Deinstallieren", + "uninstalling": "Deinstallieren", + "viewDetails": "Details anzeigen", + "save": "Speichern", + "saving": "Speichern", + "install": "Installieren", + "refresh": "Aktualisieren", + "newMcp": "Neuer MCP", + "create": "Erstellen", + "creating": "Wird erstellt..." + }, + "tabs": { + "local": "Lokales MCP", + "market": "MCP-Marktplatz" + }, + "local": { + "filterPlaceholder": "Lokales MCP filtern...", + "loadFailed": "Laden fehlgeschlagen: {message}", + "empty": "Kein lokales MCP erkannt.", + "description": "Die lokale MCP-Konfiguration kann direkt bearbeitet und gespeichert werden.", + "enabledApps": "Aktivierte Apps", + "configJson": "MCP-Konfiguration (JSON)", + "draftTitle": "Neuer MCP", + "draftDescription": "Geben Sie eine Server-ID und Konfiguration an, um einen lokalen MCP-Server zu erstellen.", + "serverIdLabel": "Server-ID", + "serverIdPlaceholder": "Server-ID (z. B. my-mcp)", + "typeHint": "Unterstützte Typen: stdio, http (Aliase: streamable-http, streamableHttp), sse. env wird nur von stdio verwendet; für Remote-MCPs Auth-Tokens über headers übermitteln.", + "envOnRemoteWarning": "env wurde in einem Remote-MCP erkannt. Nur stdio verwendet env; Remote-MCPs übermitteln Auth-Tokens über headers, sodass env beim Speichern ignoriert wird." + }, + "market": { + "selectMarketplace": "Marktplatz auswählen", + "searchPlaceholder": "MCP suchen...", + "searchFailed": "Suche fehlgeschlagen: {message}", + "loadingList": "MCP-Liste wird geladen...", + "empty": "Keine MCP-Ergebnisse.", + "loadingDetail": "Marktplatzdetails werden geladen...", + "detailLoadFailed": "Details konnten nicht geladen werden: {message}", + "owner": "Inhaber: {owner}", + "namespace": "Namensraum: {namespace}", + "defaultInstallProtocol": "Standard-Installationsprotokoll", + "currentOptionParameterCount": "Anzahl der Parameter der aktuellen Option: {count}", + "installConfigDescription": "Installationskonfiguration (JSON, vor der Installation bearbeitbar; Änderungen überschreiben das Protokoll-/Parameterformular)", + "selectLeftToView": "Wähle links ein Marktplatz-MCP aus, um Details anzuzeigen." + }, + "badges": { + "verified": "Verifiziert", + "remote": "Remote", + "hasHomepage": "Hat Homepage", + "uses": "{count} Nutzungen", + "deployed": "Bereitgestellt", + "notDeployed": "Nicht bereitgestellt" + }, + "selectLeftMcp": "Wähle links ein MCP aus." + }, + "AcpAgentSettings": { + "title": "Agent SDK-Verwaltung", + "description": "Verwalten Sie Agent-SDK-Verbindung, Aktivierungsstatus, Umgebungsvariablen, Konfigurationsverwaltung und Versions-Preflight-Infos zentral an einem Ort.", + "loadingAgents": "Agentenliste wird geladen...", + "agentList": "Agentenliste", + "emptyNoAgent": "Keine verfügbaren Agenten.", + "configManagement": "Konfigurationsverwaltung", + "envVars": "Umgebungsvariablen", + "hostTools": { + "label": "Dateien und Befehle vom Agenten selbst ausführen lassen", + "description": "codeg übernimmt Dateizugriffe und Terminalbefehle nicht mehr, sodass der Agent sie im eigenen Prozess ausführt – nur dort greifen seine eigene Sandbox und seine Berechtigungsregeln. Auch das Delegieren an andere Agenten wird deaktiviert, da dieselbe Arbeit sonst wieder über codeg liefe. codeg fügt selbst keine Sandbox hinzu; aktivieren Sie dies also nur, wenn im Agenten eine konfiguriert ist." + }, + "nativeJsonConfig": "Natives JSON-Config", + "modelHintDefault": "Leer lassen, um das System-Standardmodell zu verwenden.", + "generalConfigDescriptionClaude": "Unterstützt schnelle Konfiguration von API-URL, API-Key und Claude-Modellen und synchronisiert mit der nativen JSON-Konfiguration.", + "generalConfigDescriptionDefault": "Unterstützt wichtige Konfigurationseingaben (API URL, API Key, Model) und native JSON-Konfigurationsverwaltung.", + "multiAgent": { + "title": "Multi-Agent-Zusammenarbeit", + "description": "Erlaubt aktiven Agenten, Teilaufgaben an andere Agenten zu delegieren.", + "enable": "Delegation aktivieren", + "enableHint": "Wenn deaktiviert, wird das Tool delegate_to_agent im MCP-Toolkatalog des Agenten ausgeblendet.", + "withheldByHostTools": "{agents} erhalten die Delegationswerkzeuge nicht: Ihr agentenspezifischer Schalter „Dateien und Befehle vom Agenten selbst ausführen lassen“ ist aktiv.", + "selfInitiate": "Allow spawn without @", + "selfInitiateHint": "When on, an agent may start a listed sub-agent on its own. An @ mention is still always honored. When off, only an @ mention starts a sub-agent.", + "depthLimit": "Maximale Delegationstiefe", + "depthHint": "Zulässiger Bereich: {min}–{max}. Begrenzt, wie tief eine Delegationskette (Root → Kind → Enkel …) rekursieren kann.", + "completedCacheLabel": "Cache abgeschlossener Ergebnisse (MB)", + "completedCacheHint": "In-Memory-Cache abgeschlossener Subagent-Ergebnisse, der nur gehalten wird, solange die Delegationssitzung läuft, und beim Ende dieser Sitzung automatisch freigegeben wird. Bei Überschreitung dieses Budgets werden die ältesten Ergebnisse zuerst aus dem Speicher verworfen (weiterhin in der eigenen Sitzung des Subagenten einsehbar); 0 = unbegrenzt (wird trotzdem beim Sitzungsende freigegeben).", + "save": "Speichern", + "saving": "Wird gespeichert…", + "saved": "Delegationseinstellungen gespeichert", + "saveFailed": "Delegationseinstellungen konnten nicht gespeichert werden", + "loadFailed": "Delegationseinstellungen konnten nicht geladen werden: {detail}", + "tabGeneral": "Allgemein", + "tabAgentDefaults": "Subagent-Standards", + "agentDefaultsDescription": "Pro-Agent-Überschreibungen, die angewendet werden, wenn die Multi-Agent-Zusammenarbeit einen Subagenten für einen Delegationsaufruf startet. Die hier gezeigten Optionen stammen aus einer Live-Abfrage – Ihre Auswahl ist exakt das, was der Agent akzeptiert.", + "probing": "Verfügbare Optionen vom Agenten werden geladen…", + "probeFailed": "Optionen konnten nicht geladen werden: {detail}", + "retry": "Erneut versuchen", + "noConfigAvailable": "Dieser Agent hat keine konfigurierbaren Optionen.", + "modeLabel": "Modus", + "agentDefaultHint": "Agent-Standard: {value}", + "defaultOptionLabel": "Standard ({value})" + }, + "actions": { + "dragSort": "Zum Neuordnen ziehen", + "dragSortAgent": "{name} zum Neuordnen ziehen", + "refreshCheck": "Prüfung aktualisieren", + "refreshCheckAgent": "Prüfung für {name} aktualisieren", + "clickEnable": "Klicken, um {name} zu aktivieren", + "clickDisable": "Klicken, um {name} zu deaktivieren", + "install": "Installieren", + "upgrade": "Aktualisieren", + "uninstall": "Deinstallieren", + "uninstalling": "Wird deinstalliert...", + "saveEnvVars": "Umgebungsvariablen speichern", + "saving": "Speichern...", + "saveGrokConfig": "Grok-Konfiguration speichern", + "saveCodexConfig": "Codex-Konfiguration speichern", + "saveGeminiConfig": "Gemini-Konfiguration speichern", + "saveOpenCodeConfig": "OpenCode-Konfiguration speichern", + "saveOpenClawConfig": "OpenClaw-Konfiguration speichern", + "saveConfigManagement": "Konfigurationsverwaltung speichern", + "saveCurrentProvider": "Aktuellen Provider speichern", + "showApiKey": "API-Key anzeigen", + "hideApiKey": "API-Key ausblenden", + "showKey": "Schlüssel anzeigen", + "hideKey": "Schlüssel ausblenden", + "showToken": "Token anzeigen", + "hideToken": "Token ausblenden", + "cancel": "Abbrechen", + "delete": "Löschen", + "deleting": "Löschen...", + "confirmDelete": "Löschen bestätigen", + "confirmUninstall": "Deinstallation bestätigen", + "saveClineConfig": "Cline-Konfiguration speichern", + "saveHermesConfig": "Hermes-Konfiguration speichern", + "saveCodeBuddyConfig": "CodeBuddy-Konfiguration speichern", + "saveKimiCodeConfig": "Kimi-Code-Konfiguration speichern", + "customInstall": "Benutzerdefinierte Installation", + "saveKimiCodeRawConfig": "Save config.toml", + "saveDeepSeekConfig": "DeepSeek-Konfiguration speichern", + "diagnose": "Diagnose" + }, + "status": { + "enabled": "Aktiviert", + "disabled": "Deaktiviert", + "unchecked": "Nicht geprüft", + "agentEnabledAria": "{name} aktiviert", + "agentEnabledSwitch": "{name} Aktivierungsschalter" + }, + "preflight": { + "count": "Preflight-Elemente: {count}", + "notRun": "Prüfungen wurden noch nicht ausgeführt." + }, + "grok": { + "configDescription": "Konfiguriere Grok hier. Die folgenden Steuerelemente – Berechtigungsmodus, Reasoning-Aufwand, ein optionales benutzerdefiniertes Modell (eigener Endpunkt) und die Verdichtung – werden in ~/.grok/config.toml zusammengeführt, wobei deine anderen Schlüssel und Kommentare erhalten bleiben. Die Anmeldung nutzt deinen XAI_API_KEY oder `grok login`. Weitere Schlüssel bleiben unter „Erweitert“ bearbeitbar.", + "permissionModeLabel": "Berechtigungsmodus", + "permissionDefault": "Jedes Mal fragen", + "permissionAcceptEdits": "Bearbeitungen automatisch genehmigen", + "permissionAuto": "Intelligente Auto-Genehmigung", + "permissionAlwaysApprove": "Immer zulassen", + "reasoningEffortLabel": "Denkaufwand", + "effortLow": "Niedrig (schneller)", + "effortMedium": "Mittel (ausgewogen)", + "effortHigh": "Hoch", + "effortXhigh": "Maximal", + "optionDefault": "Standard verwenden", + "authTitle": "Authentifizierung", + "authMode": "Authentifizierungsmethode", + "authModeApiKey": "XAI-API-Schlüssel", + "authModeApiKeyHint": "Authentifiziere dich mit einem XAI_API_KEY aus der xAI-Konsole – für nicht-interaktive oder Headless-Läufe. Wird in der Umgebung dieses Agenten gespeichert.", + "authModeCustom": "Benutzerdefinierter Endpunkt", + "authModeCustomHint": "Verwende einen eigenen Endpunkt (BYO): Definiere unten ein benutzerdefiniertes Modell mit eigener Basis-URL und eigenem API-Schlüssel. Es wird zum Standardmodell von Grok.", + "subscriptionHint": "Melde dich mit `grok login` an (SuperGrok / X Premium+). Es wird kein API-Schlüssel gespeichert.", + "loginHint": "Führe dies in einem Terminal aus, um dich anzumelden, und öffne dann diese Einstellungen erneut:", + "commandCopied": "Befehl in die Zwischenablage kopiert", + "copyCommand": "Befehl kopieren", + "authKeyConfigured": "XAI_API_KEY ist konfiguriert.", + "authKeyMissing": "Kein XAI_API_KEY festgelegt.", + "advancedToggle": "Erweitert (rohe config.toml)", + "configTomlNative": "config.toml (nativ)", + "configTomlHint": "Wird wortwörtlich als gesamte ~/.grok/config.toml gespeichert. Ungültiges TOML wird abgelehnt, sodass ein Tippfehler deine Datei nie abschneidet.", + "configTomlPlaceholder": "# Andere Schlüssel als die Steuerelemente oben, z. B.\n# [mcp_servers.*], [cli], [permission]-Regeln.", + "customModelTitle": "Benutzerdefiniertes Modell (eigener Endpunkt)", + "customModelHint": "Richte Grok auf einen benutzerdefinierten oder selbst gehosteten Endpunkt. codeg schreibt einen `[model.*]`-Block pro Modell und legt es als Standard fest. Lasse die Modell-ID leer, um es zu entfernen.", + "customModelIdLabel": "Modell-ID", + "customModelIdPlaceholder": "grok-4.5", + "customModelIdHint": "Wird als `[model.*]`-Block registriert und als Modellname an die API gesendet; außerdem als `[models].default` gesetzt.", + "customBaseUrlLabel": "Basis-URL", + "customBaseUrlPlaceholder": "https://api.x.ai/v1 (Standard)", + "customApiBackendLabel": "API-Backend", + "backendResponses": "Responses", + "backendChatCompletions": "Chat Completions", + "backendMessages": "Messages (Anthropic)", + "customApiKeyLabel": "API-Schlüssel", + "customApiKeyHint": "Inline in `[model.*].api_key` gespeichert, nur für diesen Endpunkt.", + "customContextWindowLabel": "Kontextfenster (Tokens)", + "customContextWindowHint": "Optional. Steuert den Zeitpunkt der automatischen Verdichtung; leer lassen für den Standard des Endpunkts.", + "autoCompactLabel": "Schwellenwert für Auto-Verdichtung (%)", + "autoCompactHint": "Verdichtet die Unterhaltung, wenn die Kontextnutzung diesen Prozentsatz erreicht (Grok-Standard 85). Wird in `[session]` geschrieben." + }, + "cursor": { + "configDescription": "Konfiguriere Cursor hier. Wähle eine Authentifizierungsmethode – offizielles Abo (Browser-Anmeldung) oder einen Cursor-API-Schlüssel für Headless-/Servermaschinen – wähle dann ein Modell und bearbeite die Berechtigungsregeln und die Sandbox des CLI. codeg schreibt sie in ~/.cursor/cli-config.json, gemeinsam mit dem cursor-agent-CLI.", + "authTitle": "Authentifizierung", + "authChecking": "Prüfe…", + "authNotInstalled": "cursor-agent ist nicht installiert", + "authLoggedIn": "Angemeldet", + "authNotLoggedIn": "Nicht angemeldet", + "loginHint": "Führe dies im Terminal aus, um dich mit deinem Cursor-Konto anzumelden (ein Browserfenster öffnet sich), und klicke danach auf Aktualisieren:", + "apiKeyLabel": "Cursor-API-Schlüssel", + "apiKeyPlaceholder": "Schlüssel von cursor.com/dashboard", + "apiKeyHint": "CURSOR_API_KEY – ein Cursor-Dashboard-Kontoschlüssel, Alternative zur Browser-Anmeldung für Headless-/Servermaschinen. Kein Drittanbieter- oder OpenAI-Schlüssel.", + "modelTitle": "Standardmodell", + "loadModels": "Modelle laden", + "modelsUnavailable": "Modellliste nicht verfügbar", + "modelHint": "Wird der CLI beim Sitzungsstart als --model übergeben. Auf Standard lassen, damit Cursor wählt.", + "permissionsTitle": "Berechtigungen & Sandbox", + "permissionsDescription": "Visueller Editor für die Berechtigungsregeln der CLI (cli-config.json). Erlaubte Regeln laufen ohne Rückfrage; verweigerte werden immer blockiert.", + "permissionModeLabel": "Berechtigungsmodus", + "permissionModeDefault": "Vor der Ausführung fragen (Standard)", + "permissionModeForce": "Run Everything (--force)", + "permissionModeHint": "Run Everything startet Sitzungen mit --force: Alle Tool-Aufrufe werden ohne Rückfrage automatisch erlaubt, außer Deny-Regeln (eine Organisationsrichtlinie kann dies auf Allow-Regeln beschränken). Gilt für neue Sitzungen.", + "optionDefault": "Standard (nicht gesetzt)", + "sandboxLabel": "Sandbox", + "sandboxEnabled": "Aktiviert", + "sandboxDisabled": "Deaktiviert", + "allowRulesLabel": "Erlauben-Regeln", + "denyRulesLabel": "Verweigern-Regeln", + "addRule": "Regel hinzufügen", + "rulesSyntaxHint": "Regelsyntax: Shell(Befehl), Read(Pfad/Glob), Write(Pfad/Glob), WebFetch(Domain), Mcp(Server:Tool) — Deny-Regeln haben immer Vorrang.", + "saveConfig": "Konfiguration speichern", + "advancedToggle": "Erweitert: rohe cli-config.json", + "advancedHint": "Die komplette ~/.cursor/cli-config.json. Speichern schreibt die Datei unverändert; die strukturierten Steuerelemente oben werden stattdessen zusammengeführt.", + "saveRawConfig": "Datei speichern", + "authMode": "Authentifizierungsmethode", + "subscriptionHint": "Mit deinem Cursor-Konto anmelden und Cursors Modelle verwenden.", + "customApiKeyRequired": "Ein Cursor-API-Schlüssel ist erforderlich.", + "authModeApiKey": "Cursor-API-Schlüssel (Headless/Server)", + "authModeApiKeyHint": "Mit einem Cursor-Konto-API-Schlüssel aus dem Cursor-Dashboard authentifizieren (für Headless-/Servermaschinen). Das ist ein Cursor-Kontoschlüssel, kein Drittanbieter-/OpenAI-Endpunkt – cursor-agent kommuniziert nur mit dem Cursor-Backend. Um einen codex-/OpenAI-kompatiblen Endpunkt zu nutzen, verwende stattdessen den Codex-Agenten.", + "modelPickerPlaceholder": "Modelle suchen…", + "modelNoMatch": "Kein passendes Modell", + "modelsNeedAuth": "Melde dich an, um die Modellliste zu laden.", + "modelDefaultBadge": "Standard" + }, + "deepseek": { + "configManagement": "DeepSeek-Harness-Konfiguration", + "configDescription": "Endpunkt und Schlüssel sind Umgebungsvariablen, die deepseek-acp beim Start liest. Modell und Denkstufe sind Auswahlfelder pro Sitzung — sie werden im Eingabefeld gewählt.", + "baseUrlLabel": "API-Endpunkt", + "baseUrlHint": "Leer lassen für den offiziellen Endpunkt. Gilt für Sitzungen, die nach dem Speichern starten – eine laufende Sitzung muss neu verbinden.", + "baseUrlInvalid": "Vollständige http(s)-URL ohne Query-String eingeben, zum Beispiel https://api.deepseek.com", + "apiKeyLabel": "API-Schlüssel", + "apiKeyHint": "Wird dem Agenten als DEEPSEEK_API_KEY übergeben. Eine Umgebungsvariable hat Vorrang vor der Zugangsdatendatei – lass das Feld leer, wenn du dich im Terminal anmeldest." + }, + "codex": { + "configDescription": "Unterstützt schnelle Konfiguration von API-URL, API-Key, Modellname und reasoning effort und synchronisiert mit `auth.json` / `config.toml`.", + "authMode": "Authentifizierungsmodus", + "chatgptSubscription": "Offizielles Abonnement", + "chatgptSubscriptionHint": "Mit offiziellem ChatGPT-Abonnement anmelden, kein API Key erforderlich", + "apiKeyHint": "Mit API Key zu OpenAI oder kompatiblen API-Diensten verbinden", + "selectProvider": "Provider auswählen", + "modelName": "Modellname", + "selectReasoningEffort": "Reasoning Effort auswählen", + "enableWebsocket": "WebSocket aktivieren", + "enableWebsocketAria": "WebSocket für Codex Provider aktivieren", + "enableSkills": "Skills aktivieren", + "enableSkillsAria": "Skills für Codex aktivieren", + "enableFast": "Fast aktivieren", + "enableFastAria": "Fast-Servicestufe für Codex aktivieren", + "sandboxGroupTitle": "Sandbox und Freigaben", + "sandboxGroupHint": "Wird in die globale ~/.codex/config.toml geschrieben und gilt daher auch für codex-CLI- und IDE-Sitzungen. Es sind Thread-Standardwerte: Sie gelten für Turns, die codex selbst startet (/goal, /review, /compact). Normale Eingaben nutzen die Freigabe-Voreinstellung des Eingabefelds. Änderungen greifen nach einem Neustart der Sitzung.", + "sandboxShadowedWarning": "config.toml setzt default_permissions, daher löst codex Berechtigungen über dieses Profil auf und ignoriert sandbox_mode vollständig. Entferne default_permissions, um die Optionen unten zu nutzen.", + "sandboxPermissionsTableWarning": "config.toml definiert [permissions]-Profile, aber kein default_permissions — damit verweigert codex den Start. Setze es im Rohtext-Editor unten.", + "approvalPolicyLabel": "Freigaberichtlinie", + "approvalPolicyUnset": "Nicht gesetzt (codex-Standard: auf Anfrage)", + "approvalPolicy_on-request": "Auf Anfrage – das Modell entscheidet, wann es nachfragt", + "approvalPolicy_untrusted": "Nicht vertrauenswürdig – nur bekannt sichere Lesebefehle laufen ohne Nachfrage", + "approvalPolicy_never": "Nie – keinerlei Freigabeabfragen", + "approvalPolicy_granular": "Granular – pro Abfragetyp festlegen", + "approvalPolicyUntrustedAcpWarning": "Für „untrusted“ gibt es unter den drei Freigabe-Voreinstellungen des ACP-Adapters keine Entsprechung, daher fallen codeg-Sitzungen auf „auf Anfrage“ zurück: Das Modell entscheidet dann selbst, wann es fragt, und Befehle, die die Sandbox ohnehin erlaubt, fragen nicht mehr nach. Schränke stattdessen unten den Sandbox-Modus ein.", + "granularHint": "Aus bedeutet, dass Anfragen dieser Art automatisch abgelehnt statt angezeigt werden.", + "granular_sandbox_approval": "Rechteerweiterung für Shell-Befehle", + "granular_rules": "Abfragen aus Execpolicy-Regeln", + "granular_skill_approval": "Abfragen bei Skill-Skripten", + "granular_request_permissions": "Abfragen des request_permissions-Tools", + "granular_mcp_elicitations": "MCP-Elicitation-Abfragen", + "sandboxModeLabel": "Sandbox-Modus", + "sandboxModeUnset": "Nicht gesetzt (vertrauenswürdige Ordner fallen auf Workspace-Schreibzugriff zurück)", + "sandboxMode_read-only": "Nur lesen", + "sandboxMode_workspace-write": "Workspace-Schreibzugriff", + "sandboxMode_danger-full-access": "Vollzugriff (keine Sandbox)", + "sandboxModeHint": "Unter Windows wird Workspace-Schreibzugriff auf Nur-Lesen herabgestuft, sofern die experimentelle Windows-Sandbox von codex nicht aktiviert ist.", + "sandboxModeSeedsPresetHint": "codeg leitet daraus auch die anfängliche Freigabe-Voreinstellung der Sitzung ab — anders als die Freigaberichtlinie wirkt es also auch auf normale Anfragen. Die im Eingabefeld gewählte Voreinstellung hat weiterhin Vorrang.", + "writableRootsLabel": "Zusätzliche beschreibbare Ordner", + "writableRootsHint": "Ein absoluter Pfad pro Zeile, zusätzlich zum Arbeitsverzeichnis.", + "sandboxRootsRelativeError": "Muss ein absoluter Pfad sein – codex löst relative Angaben unter ~/.codex auf: {path}", + "networkAccessLabel": "Netzwerkzugriff erlauben", + "excludeTmpdirLabel": "TMPDIR von den beschreibbaren Wurzeln ausschließen", + "excludeSlashTmpLabel": "/tmp von den beschreibbaren Wurzeln ausschließen", + "authJsonNative": "auth.json (nativ)", + "configTomlNative": "config.toml (nativ)", + "loginButton": "Mit ChatGPT anmelden", + "loginRequesting": "Login-Code wird angefordert...", + "loginStep1": "Öffnen Sie die folgende URL in Ihrem Browser:", + "loginStep2": "Geben Sie den folgenden Code ein:", + "loginPolling": "Warte auf Autorisierung...", + "loginCancel": "Abbrechen", + "loginSuccess": "Erfolgreich angemeldet, Konfiguration gespeichert!", + "loginFailed": "Anmeldung fehlgeschlagen: {message}", + "loginRetry": "Erneut versuchen", + "loginCodeCopied": "Code kopiert", + "loggedIn": "Konto angemeldet", + "loginRelogin": "Erneut anmelden / Konto wechseln", + "loginTimeout": "Anmeldung abgelaufen, bitte erneut versuchen", + "loginSaveFailed": "Anmeldung erfolgreich, aber Konfiguration konnte nicht gespeichert werden" + }, + "gemini": { + "authConfig": "Gemini-Auth-Konfiguration", + "authConfigDescription": "Ausgerichtet an den Gemini CLI-Authentifizierungsdokumenten, mit Unterstützung für benutzerdefinierten Endpoint, Google-Login, Gemini API Key und Vertex AI (ADC / Servicekonto / API Key).", + "authMode": "Auth-Modus", + "selectAuthMode": "Auth-Modus auswählen", + "viewAuthDoc": "Auth-Dokumentation anzeigen", + "mode": { + "custom": "Benutzerdefinierter Endpoint", + "loginGoogle": "Google-Login (OAuth)", + "vertexServiceAccount": "Vertex AI (Servicekonto)" + }, + "hint": { + "custom": "API URL, API Key und Modell ausfüllen; wird auf GOOGLE_GEMINI_BASE_URL / GEMINI_API_KEY / GEMINI_MODEL abgebildet.", + "loginGoogle": "Gemini zuerst im Terminal ausführen und Google-Login abschließen; API key ist nicht erforderlich.", + "geminiApiKey": "Beim Verwenden der Gemini API GEMINI_API_KEY eintragen.", + "vertexAdc": "gcloud ADC verwenden; GOOGLE_CLOUD_PROJECT und GOOGLE_CLOUD_LOCATION werden empfohlen.", + "vertexServiceAccount": "Pfad zur Servicekonto-JSON in GOOGLE_APPLICATION_CREDENTIALS setzen.", + "vertexApiKey": "Beim Verwenden eines Vertex AI API Keys GOOGLE_API_KEY eintragen." + } + }, + "openCode": { + "configManagement": "OpenCode-Konfigurationsverwaltung", + "configDescription": "An OpenCode-`provider`-Schema ausgerichtet, unterstützt Multi-Provider-Verwaltung und bidirektionale Synchronisierung mit nativen JSON-Dateien.", + "providerManagement": "Provider-Verwaltung", + "providerCount": "{count} Provider", + "addProvider": "Provider hinzufügen", + "emptyProvider": "Noch keine benutzerdefinierten Provider. Klicke auf Benutzerdefinierten Provider hinzufügen, um einen zu erstellen.", + "providerEnabledState": "{providerId} Aktivierungsstatus", + "selectProviderNpm": "provider.npm auswählen", + "modelManagement": "Modellverwaltung", + "modelCount": "{count} Modelle", + "modelDescription": "Ausgerichtet an OpenCode `provider.models`. Schnellverwaltung unterstützt derzeit `name` / `id`; andere erweiterte Felder bleiben erhalten und können unten im nativen JSON bearbeitet werden.", + "addModel": "Modell hinzufügen", + "emptyModel": "Noch kein Modell vorhanden. model id eingeben und dann auf „Modell hinzufügen“ klicken.", + "modelId": "Modell-ID", + "modelName": "Modellname", + "deleteModel": "Modell {modelId} löschen", + "nativeJsonConfig": "OpenCode Native JSON-Konfiguration", + "mainModel": "Hauptmodell", + "smallModel": "Kleines Modell", + "noMatchingModels": "Keine passenden Modelle", + "connectProvider": "Provider verbinden", + "connectedProviders": "Verbundene Provider", + "noConnectedProviders": "Noch keine Katalog-Provider verbunden.", + "advancedProviderConfig": "Benutzerdefinierte Provider", + "customProviderConfigHint": "OpenAI-kompatible Endpunkte, die du selbst definierst – ein Provider-Block in opencode.json, mit dem API-Key in auth.json.", + "addCustomProvider": "Benutzerdefinierten Provider hinzufügen", + "disconnect": "Trennen", + "editConfig": "Bearbeiten", + "customBadge": "Benutzerdefiniert", + "authKindApi": "API-Schlüssel", + "authKindOauth": "OAuth", + "authKindNone": "Keine Anmeldedaten", + "connect": { + "title": "Provider verbinden", + "description": "Wähle einen Provider aus dem models.dev-Katalog. Anmeldedaten werden in der auth.json-Datei von OpenCode gespeichert.", + "pick": "Provider", + "search": "Provider suchen…", + "loading": "Katalog wird geladen…", + "catalogLabel": "models.dev-Katalog", + "modelsAvailable": "{count} Modelle verfügbar", + "getKey": "API-Schlüssel holen", + "oauthApiKeyNote": "Dieser Provider unterstützt auch die Browser-Anmeldung über opencode auth login. Die Browser-Anmeldung kommt bald — füge vorerst einen API-Schlüssel ein.", + "apiKey": "API-Schlüssel", + "apiKeyHint": "Wird in auth.json gespeichert, nie in opencode.json.", + "baseUrlOptional": "Basis-URL überschreiben (optional)", + "providerId": "Provider-ID", + "displayName": "Anzeigename", + "modelsList": "Modelle (eins pro Zeile)", + "modelsHint": "Modell-IDs, die der Endpunkt akzeptiert.", + "action": "Verbinden", + "editTitle": "Provider bearbeiten", + "editDescription": "Aktualisiere den API-Schlüssel oder die Basis-URL dieses Providers.", + "saveAction": "Speichern" + }, + "customProvider": { + "title": "Benutzerdefinierten Provider hinzufügen", + "description": "Definiere einen OpenAI-kompatiblen Endpunkt. Der API-Key wird in auth.json gespeichert, der Provider-Block in opencode.json.", + "action": "Provider hinzufügen", + "idInCatalog": "{providerId} ist ein bekannter Provider – verbinde ihn stattdessen über Provider verbinden." + }, + "refreshCatalog": "Katalog aktualisieren", + "reasoningBadge": "Reasoning", + "contextWindow": "Kontextfenster", + "permissions": { + "title": "Berechtigungen", + "description": "Legt fest, welche Aktionen einfach laufen, welche vorher nachfragen und welche blockiert werden. Wird in den permission-Block von opencode.json geschrieben und mit dem Speichern unten übernommen.", + "docsLink": "Dokumentation zu Berechtigungen", + "unparsableConfig": "Das native JSON unten ist ungültig, deshalb pausiert der visuelle Editor. Korrigiere das JSON, um fortzufahren.", + "invalidBlock": "Der permission-Block hat eine Form, die codeg nicht kennt. Bearbeite ihn im nativen JSON unten oder beginne mit Zurücksetzen neu.", + "orderingUnsafe": "Eine Wildcard-Regel steht hinter konkreten Tools, deshalb wendet OpenCode sie auch auf diese an – die Zeilen unten sind nicht das, was tatsächlich gilt. Reihenfolge korrigieren schiebt jede Wildcard nur wieder an den Anfang ihres Bereichs, ohne einen Wert zu ändern.", + "orderingUnsafeManual": "Eine Regel wird von einem späteren, allgemeineren Muster verdeckt, OpenCode wendet sie also nie an – die Zeilen unten sind nicht das, was tatsächlich gilt. Für zwei überlappende Muster gibt es keine eine richtige Reihenfolge; sortiere sie im nativen JSON so, dass das allgemeinere zuerst steht.", + "fixOrder": "Reihenfolge korrigieren", + "agentOverrides": "Diese Agenten überschreiben Berechtigungen und werden zuletzt angewendet, gewinnen also gegen alles hier: {agents}. Bearbeite sie im nativen JSON unten oder schalte die automatische Annahme ein, um sie zu löschen.", + "legacyTools": "Die veraltete tools-Map auf oberster Ebene verweigert ein Tool. OpenCode führt sie mit den Berechtigungen zusammen, sie gilt also über allem hier Gezeigten. Bearbeite sie im nativen JSON unten oder schalte die automatische Annahme ein, um sie zu löschen.", + "autoAcceptTitle": "Alle Berechtigungen automatisch annehmen", + "autoAcceptHint": "Jeder Tool-Aufruf – Shell-Befehle, Dateiänderungen, Pfade außerhalb des Projekts – läuft ohne Rückfrage. Beim Einschalten ersetzt eine einzige Alles-erlauben-Regel die Einstellungen pro Tool unten, und die Overrides einzelner Agenten sowie veraltete tools-Schalter, die sonst weiter blockieren würden, werden gelöscht.", + "globalLabel": "Globaler Standard", + "globalHint": "Die Regel *: gilt für alles, was die Tools unten nicht überschreiben.", + "actionUnset": "Nicht gesetzt (OpenCode-Standard)", + "actionInherit": "Standard übernehmen ({action})", + "actionAllow": "Erlauben", + "actionAsk": "Nachfragen", + "actionDeny": "Verweigern", + "perToolTitle": "Berechtigungen pro Tool", + "reset": "Zurücksetzen", + "ruleCount": "Regeln: {count}", + "rulesToggle": "Feingranulare Regeln für {tool}", + "rulesHint": "Wird gegen die Tool-Eingabe geprüft, die letzte Übereinstimmung gewinnt – schreibe die weiten Muster also zuerst. * passt auf beliebig viele Zeichen, ? auf genau eines, und ein führendes ~ wird zu deinem Home-Verzeichnis.", + "noRules": "Noch keine feingranularen Regeln.", + "addRule": "Regel hinzufügen", + "deleteRule": "Regel {pattern} löschen", + "duplicateRule": "Dieses Muster gibt es bereits.", + "blankRule": "Eine Regel braucht ein Muster – zum Entfernen das Papierkorb-Symbol nutzen.", + "customKeys": "Weitere Berechtigungsschlüssel in der Datei", + "customKeyHint": "Kein eingebautes OpenCode-Tool – bleibt unverändert erhalten.", + "keys": { + "bash": "Shell-Befehle ausführen, geprüft am geparsten Befehl", + "edit": "Alle Dateiänderungen: edit, write und patch", + "read": "Dateien lesen, geprüft am Pfad", + "external_directory": "Pfade außerhalb des Projektarbeitsverzeichnisses erreichen", + "task": "Subagenten starten, geprüft am Subagenten-Typ", + "skill": "Skills laden, geprüft am Skill-Namen", + "glob": "Dateien finden, geprüft am Glob-Muster", + "grep": "Dateiinhalte durchsuchen, geprüft am Muster", + "list": "Verzeichnisinhalte auflisten", + "webfetch": "Eine URL abrufen", + "websearch": "Im Web suchen", + "lsp": "LSP-Abfragen ausführen", + "todowrite": "Die To-do-Liste schreiben", + "question": "Dir eine Frage stellen", + "doom_loop": "Löst aus, wenn sich derselbe Aufruf dreimal mit gleicher Eingabe wiederholt" + } + } + }, + "openClaw": { + "gatewayConfig": "Gateway-Konfiguration", + "gatewayDescription": "OpenClaw-Gateway-Verbindung konfigurieren. Unterstützt lokales oder entferntes Gateway.", + "gatewayUrlHint": "Leer lassen, um gateway.remote.url aus der lokalen openclaw-Konfiguration zu verwenden.", + "gatewayTokenPlaceholder": "Gateway-Auth-Token", + "gatewayTokenHint": "Wenn möglich token-file statt Klartext-Token verwenden; über openclaw CLI konfigurieren.", + "sessionKeyHint": "Optional. Gateway-Session-Key angeben; leer lassen für automatische Zuweisung einer isolierten Session." + }, + "hermes": { + "configManagement": "Hermes-Konfiguration", + "configDescription": "Hermes verwaltet seine eigenen Anmeldedaten in ~/.hermes/.env und die Einstellungen in ~/.hermes/config.yaml. Wähle einen Anbieter und lege dann den API-Schlüssel und das Modell fest – codeg schreibt beide Dateien für dich.", + "providerLabel": "Anbieter", + "providerHint": "Der Anbieter legt fest, welche API-Schlüssel-Variable und welchen model.provider Hermes verwendet. OAuth-Anbieter werden über die Terminal-Einrichtung unten konfiguriert.", + "groupApiKey": "Anbieter mit API-Schlüssel", + "groupOauth": "OAuth-Anbieter", + "groupAws": "AWS", + "apiKeyHint": "Wird in ~/.hermes/.env gespeichert. Er wird niemals in den Prozess eingeschleust – Hermes liest ihn aus seiner eigenen Konfiguration.", + "modelName": "Modell", + "oauthHint": "Dieser Anbieter verwendet OAuth. Führe die Einrichtung unten aus, um dich im Terminal zu authentifizieren.", + "awsHint": "Bedrock verwendet deine AWS-Anmeldedaten (Umgebung oder gemeinsame Konfiguration). Lege oben die Modell-ID fest und konfiguriere den AWS-Zugriff in deiner Umgebung.", + "unsupportedProvider": "Dieser Anbieter lässt sich nicht über strukturierte Felder bearbeiten. Verwende den config.yaml-Editor unten oder die Terminal-Einrichtung.", + "setupTitle": "Selbstverwaltete Einrichtung", + "setupHint": "Die interaktive Einrichtung von Hermes benötigt ein Terminal. Starte sie unten oder kopiere den Befehl, um sie selbst auszuführen.", + "runSetup": "Hermes-Einrichtung ausführen", + "configureModel": "Modell konfigurieren", + "openConfigFolder": "~/.hermes öffnen", + "copyCommand": "Befehl kopieren", + "commandCopied": "Befehl in die Zwischenablage kopiert", + "advancedTitle": "Erweitert: config.yaml bearbeiten", + "rawConfigHint": "Bearbeite ~/.hermes/config.yaml direkt. Das Speichern hier überschreibt die Datei wortwörtlich.", + "saveRawConfig": "config.yaml speichern" + }, + "codebuddy": { + "configManagement": "CodeBuddy-Konfiguration", + "configDescription": "CodeBuddy authentifiziert sich mit einem API-Schlüssel. Builds für Festlandchina erfordern zudem die Umgebung „China (internal)“; iOA-Builds verwenden „iOA“. Der internationale Build lässt sie ungesetzt.", + "apiKeyLabel": "API-Schlüssel", + "apiKeyHint": "Wird als CODEBUDDY_API_KEY für diesen Agenten gespeichert. Alternativ kannst du dich mit der CodeBuddy-CLI im Terminal anmelden.", + "apiKeyHintSelfHosted": "Wird als CODEBUDDY_API_KEY für diesen Agenten gespeichert. Verwende den von deiner privaten Bereitstellung ausgestellten Schlüssel.", + "environmentLabel": "Umgebung", + "environmentHint": "Legt CODEBUDDY_INTERNET_ENVIRONMENT fest. Festlandchina muss „China (internal)“ verwenden; der internationale Build lässt es ungesetzt.", + "envOverseas": "International (Standard)", + "envChina": "China (internal)", + "envIoa": "iOA", + "envSelfHosted": "Selbst gehostet (private Bereitstellung)", + "baseUrlLabel": "Bereitstellungs-URL", + "baseUrlPlaceholder": "https://codebuddy.your-company.com", + "baseUrlHint": "Wird als CODEBUDDY_BASE_URL gespeichert und richtet CodeBuddy auf deinen privaten Endpunkt. Bei Selbsthosting bleibt die Netzwerkumgebung (CODEBUDDY_INTERNET_ENVIRONMENT) ungesetzt.", + "baseUrlInvalid": "Gib eine gültige http(s)-URL ein.", + "loginHint": "Kein API-Schlüssel? Führe „codebuddy“ im Terminal aus, um dich stattdessen mit deinem Tencent-Konto anzumelden." + }, + "kimiCode": { + "configManagement": "Kimi-Code-Konfiguration", + "configDescription": "`kimi acp` akzeptiert nur ein gespeichertes Login-Token, daher schreibt codeg einen verwalteten Provider in ~/.kimi-code/config.toml und legt lokal ein Gate-Token an – die Inferenz läuft weiterhin über deinen eigenen Schlüssel.", + "statusUnconfigured": "Noch nicht konfiguriert", + "statusDirty": "Nicht gespeicherte Änderungen", + "summaryLabel": "Aktiv", + "gateReadyApiKey": "API-Schlüssel in config.toml geschrieben", + "gateReadyLogin": "Mit einem Kimi-Konto angemeldet", + "revealConfig": "Im Ordner anzeigen", + "envOverrideWarning": "{keys} ist gesetzt und hat Vorrang vor config.toml. Beim Speichern hier wird die Variable entfernt.", + "authModeLabel": "Authentifizierungsmethode", + "authModeApiKey": "API-Schlüssel", + "authModeLogin": "Kimi-Konto-Anmeldung (Abo)", + "authModeApiKeyHint": "Schreibt einen verwalteten Provider in config.toml und legt das Gate-Token an, damit Sitzungen geöffnet werden können.", + "loginHint": "Führe `kimi login` im Terminal aus, um dich mit einem Kimi-Abo-Konto anzumelden. codeg speichert nichts und nutzt Kimis eigene Anmeldung. Speichern hier entfernt codegs API-Schlüssel-Gate-Token.", + "credentialTitle": "Zugangsdaten", + "interfaceTypeLabel": "Provider-Typ", + "interfaceTypeHint": "Das Provider-Protokoll, das Kimi spricht (`type` in config.toml). Für einen Moonshot-/platform.kimi.com-Schlüssel Kimi / Moonshot wählen.", + "endpointLabel": "Endpunkt", + "endpointCustom": "Benutzerdefiniert (OpenAI-kompatibel)", + "endpointHint": "International = api.moonshot.ai; China (platform.kimi.com-Schlüssel) = api.moonshot.cn. Benutzerdefiniert zeigt auf einen beliebigen OpenAI-kompatiblen Endpunkt.", + "regionInternational": "International (api.moonshot.ai)", + "regionChina": "China (api.moonshot.cn)", + "baseUrlLabel": "Basis-URL", + "baseUrlHint": "Leer lassen, um den Standardwert des Provider-SDK zu verwenden.", + "apiKeyLabel": "API-Schlüssel", + "apiKeyHint": "Wird in ~/.kimi-code/config.toml geschrieben und für die Inferenz verwendet. Von platform.kimi.com oder platform.kimi.ai.", + "vertexProjectLabel": "GCP-Projekt (GOOGLE_CLOUD_PROJECT)", + "vertexLocationLabel": "GCP-Region (GOOGLE_CLOUD_LOCATION)", + "vertexHint": "Vertex AI nutzt Google Application Default Credentials – führe `gcloud auth application-default login` aus (kein API-Schlüssel nötig).", + "modelTitle": "Modell", + "modelLabel": "Modell", + "modelHint": "Die Modell-ID, die in config.toml geschrieben wird. Über „Testen & Modelle laden“ siehst du, worauf dein Schlüssel tatsächlich zugreifen kann.", + "maxContextLabel": "Maximale Kontextgröße", + "maxContextHint": "Vom Kimi-Schema vorgeschrieben: Fehlt der Wert, verwirft Kimi den gesamten Modellblock und jede Anfrage bleibt ohne Antwort. Standard 262144.", + "fetchModels": "Testen & Modelle laden", + "fetchModelsOk": "Schlüssel funktioniert – {count} Modelle verfügbar", + "fetchModelsEmpty": "Schlüssel funktioniert, es wurden aber keine Modelle zurückgegeben", + "fetchModelsFailed": "Test fehlgeschlagen", + "fetchModelsNeedsKey": "Gib zuerst einen API-Schlüssel und einen Endpunkt ein", + "modelNotInList": "Dieses Modell ist nicht in der Liste, auf die dein Schlüssel zugreifen kann – Kimi scheitert mit „Modell nicht gefunden“.", + "reasoningTitle": "Reasoning", + "reasoningEnableLabel": "Aktivieren", + "reasoningDescription": "Kimi zeigt den „Thinking“-Auswähler im Eingabefeld nur, wenn das Modell eine Reasoning-Fähigkeit deklariert – codeg schreibt sie hier. Gilt ab neuen Sitzungen.", + "effortsLabel": "Angebotene Stufen", + "effortsHint": "Diese Stufen erscheinen im „Thinking“-Auswähler. Kimi reicht die Stufe unverändert an den Provider weiter – wähle also Werte, die dein Modell akzeptiert.", + "effortsEmptyHint": "Ohne ausgewählte Stufe bleibt im Eingabefeld nur ein einfacher Off/On-Schalter.", + "effortsCustomPlaceholder": "Weitere Stufe hinzufügen", + "effortsAdd": "Hinzufügen", + "defaultEffortLabel": "Standardstufe", + "defaultEffortAuto": "Kimi entscheiden lassen", + "alwaysThinkingLabel": "Das Modell denkt immer nach – Off-Eintrag aus dem Auswähler entfernen", + "fixErrorsFirst": "Korrigiere zuerst die markierten Felder", + "errorModelRequired": "Modell ist erforderlich", + "errorMaxContextRequired": "Maximale Kontextgröße ist erforderlich", + "errorMaxContextInvalid": "Muss eine positive ganze Zahl sein", + "errorApiKeyRequired": "API-Schlüssel ist erforderlich", + "errorApiKeyInvalid": "Der API-Schlüssel darf keine Zeilenumbrüche enthalten", + "errorBaseUrlRequired": "Basis-URL ist erforderlich", + "errorBaseUrlInvalid": "Muss mit http:// oder https:// beginnen", + "errorVertexProjectRequired": "GCP-Projekt ist erforderlich", + "errorDefaultEffortUnlisted": "Wähle eine der oben ausgewählten Stufen", + "advancedTitle": "Erweitert", + "authTypeLabel": "Ablageort der Zugangsdaten", + "authTypeApiKey": "Inline api_key", + "authTypeEnv": "env-Untertabelle des Providers", + "authTypeHint": "Wo der API-Schlüssel innerhalb von config.toml abgelegt wird.", + "rawEditorLabel": "config.toml direkt bearbeiten", + "rawEditorWarning": "Speichern hier überschreibt die gesamte Datei wortwörtlich und ersetzt die strukturierten Einstellungen oben.", + "rawEditorPlaceholder": "[providers.codeg]\ntype = \"kimi\"\nbase_url = \"https://api.moonshot.cn/v1\"\napi_key = \"sk-...\"" + }, + "authModeOfficialSubscription": "Offizielles Abonnement", + "authModeCustomEndpoint": "Benutzerdefinierter Endpunkt", + "authModeCustomEndpointHint": "API-URL und API-Key manuell für einen benutzerdefinierten Endpunkt konfigurieren.", + "authModeModelProvider": "Modellanbieter", + "modelProvider": "Modellanbieter", + "modelProviderHint": "API-URL, API-Key und Modell eines konfigurierten Modellanbieters verwenden.", + "selectModelProvider": "Modellanbieter auswählen", + "noModelProviderAvailable": "Kein Modellanbieter für diesen Agent konfiguriert. Gehen Sie zu den Modellanbieter-Einstellungen, um einen hinzuzufügen.", + "claude": { + "authMode": "Authentifizierungsmodus", + "officialSubscription": "Offizielles Abonnement", + "officialSubscriptionHint": "Offizielles Anthropic-Abonnement verwenden, kein API-Key erforderlich.", + "mainModel": "Hauptmodell", + "reasoningModel": "Reasoning-Modell (thinking)", + "haikuDefaultModel": "Standard-Haiku-Modell", + "sonnetDefaultModel": "Standard-Sonnet-Modell", + "opusDefaultModel": "Standard-Opus-Modell", + "customModelOption": "Benutzerdefinierte Modell-ID", + "customModelOptionName": "Name des benutzerdefinierten Modells", + "customModelOptionDescription": "Beschreibung des benutzerdefinierten Modells", + "customModelOptionHint": "Fügt der Modellauswahl von Claude einen einzelnen benutzerdefinierten Eintrag hinzu (z. B. ein Modell hinter einem benutzerdefinierten Gateway/Proxy). Name und Beschreibung sind optionale Anzeigeangaben.", + "effortLevel": "Reasoning-Stufe", + "effortLevelDefault": "Standardstufe", + "effortLevel_low": "Niedrig", + "effortLevel_medium": "Mittel", + "effortLevel_high": "Hoch", + "effortLevel_xhigh": "Sehr Hoch", + "sendAttributionHeader": "Attributions-/Abrechnungskennung an die API senden", + "sendAttributionHeaderAria": "Attributions-/Abrechnungskennung von Claude Code an die API senden", + "disableNonessentialTraffic": "Telemetrie oder überflüssige Netzwerkanfragen deaktivieren", + "disableNonessentialTrafficAria": "Telemetrie oder überflüssige Netzwerkanfragen von Claude Code deaktivieren" + }, + "dialogs": { + "confirmDeleteProvider": "Provider {providerId} löschen?", + "confirmDeleteProviderDescription": "OpenCode-Konfiguration und auth JSON werden zusammen aktualisiert. Diese Aktion kann nicht rückgängig gemacht werden.", + "confirmUninstall": "{name} deinstallieren?", + "confirmUninstallDescription": "Dadurch wird die lokal installierte Version entfernt. Eine Neuinstallation ist später möglich.", + "customInstallTitle": "{name} benutzerdefiniert installieren", + "customInstallDescription": "Geben Sie die zu installierende Version ein. Dies installiert neu und ersetzt die aktuell installierte Version.", + "customInstallVersionLabel": "Versionsnummer", + "customInstallInvalid": "Geben Sie eine gültige Versionsnummer ein, z. B. 1.2.3.", + "customInstallSubmit": "Installieren" + }, + "errors": { + "windowsFileLocked": "Die Dateien von {name} werden von einer laufenden Sitzung verwendet, daher kann Windows sie nicht ersetzen. Schließe alle {name}-Sitzungen und versuche es erneut.", + "nativeJsonMustBeObject": "Native JSON-Konfiguration muss ein Objekt sein", + "nativeJsonInvalid": "Formatfehler in nativer JSON-Konfiguration: {message}", + "openCodeAuthMustBeObject": "OpenCode auth.json muss ein JSON-Objekt sein", + "openCodeAuthInvalid": "Formatfehler in OpenCode auth.json: {message}", + "authMustBeObject": "auth.json muss ein JSON-Objekt sein", + "authInvalid": "Formatfehler in auth.json: {message}", + "providerIdPattern": "Provider-ID unterstützt nur Buchstaben, Zahlen, Unterstrich, Punkt und Bindestrich", + "providerExists": "Provider {providerId} existiert bereits", + "modelIdPattern": "Model-ID unterstützt nur Buchstaben, Zahlen, Unterstrich, Punkt, Doppelpunkt und Bindestrich", + "modelExists": "Model {modelId} existiert bereits" + }, + "warnings": { + "nativeJsonRecoveredStructured": "Native JSON-Konfiguration ist ungültig; auf strukturierte Konfiguration zurückgesetzt", + "nativeJsonRecoveredOpenCode": "Native JSON-Konfiguration ist ungültig; auf OpenCode-strukturierte Konfiguration zurückgesetzt", + "openCodeAuthRecovered": "OpenCode auth.json ist ungültig; auf Standardkonfiguration zurückgesetzt", + "authRecoveredStructured": "auth.json ist ungültig; auf strukturierte Konfiguration zurückgesetzt" + }, + "toasts": { + "agentActionCompleted": "{name} {action} abgeschlossen", + "agentActionFailed": "{name} {action} fehlgeschlagen", + "localVersion": "Lokale Version: {version}", + "installCompletedVersionLater": "Installation abgeschlossen, Version wird bei der nächsten Prüfung aktualisiert", + "uninstallCompleted": "Deinstallation von {name} abgeschlossen", + "uninstallFailed": "Deinstallation von {name} fehlgeschlagen", + "localVersionRemoved": "Lokale Version entfernt", + "saveAgentOrderFailed": "Speichern der Agent-Reihenfolge fehlgeschlagen", + "saveAgentSwitchFailed": "Speichern des Agent-Schalters fehlgeschlagen", + "saveEnvFailed": "Speichern der Umgebungsvariablen fehlgeschlagen", + "grokSaved": "Grok-Konfiguration gespeichert", + "saveGrokNativeFailed": "Grok-Nativkonfiguration konnte nicht gespeichert werden", + "saveGrokApiKeyFailed": "Einstellungen gespeichert, aber der API-Schlüssel konnte nicht gespeichert werden", + "cursorSaved": "Cursor-Konfiguration gespeichert", + "saveCursorConfigFailed": "Cursor-Konfiguration konnte nicht gespeichert werden", + "codexSaved": "Codex-Konfiguration gespeichert", + "saveCodexNativeFailed": "Speichern der nativen Codex-Konfiguration fehlgeschlagen", + "geminiSaved": "Gemini-Konfiguration gespeichert", + "saveGeminiFailed": "Speichern der Gemini-Konfiguration fehlgeschlagen", + "providerDeleted": "Provider {providerId} gelöscht", + "providerDeleteFailed": "Löschen von Provider {providerId} fehlgeschlagen", + "providerSaved": "Provider {providerId} gespeichert", + "saveProviderFailed": "Speichern von Provider {providerId} fehlgeschlagen", + "openCodeConfigSynced": "OpenCode-Konfiguration und auth JSON wurden synchronisiert.", + "openCodeSaved": "OpenCode-Konfiguration gespeichert", + "saveOpenCodeFailed": "Speichern der OpenCode-Konfiguration fehlgeschlagen", + "openClawSaved": "OpenClaw-Konfiguration gespeichert", + "saveOpenClawFailed": "Speichern der OpenClaw-Konfiguration fehlgeschlagen", + "configSaved": "Konfiguration gespeichert", + "configSavedHint": "Bestehende Sitzungen müssen neu geöffnet werden, damit die Änderungen wirksam werden", + "saveConfigManagementFailed": "Speichern der Konfigurationsverwaltung fehlgeschlagen", + "clineSaved": "Cline-Konfiguration gespeichert", + "saveClineFailed": "Cline-Konfiguration konnte nicht gespeichert werden", + "hermesSaved": "Hermes-Konfiguration gespeichert", + "saveHermesFailed": "Hermes-Konfiguration konnte nicht gespeichert werden", + "codeBuddySaved": "CodeBuddy-Konfiguration gespeichert", + "saveCodeBuddyFailed": "CodeBuddy-Konfiguration konnte nicht gespeichert werden", + "kimiCodeSaved": "Kimi-Code-Konfiguration gespeichert", + "saveKimiCodeFailed": "Speichern der Kimi-Code-Konfiguration fehlgeschlagen", + "deepseekSaved": "DeepSeek-Konfiguration gespeichert", + "saveDeepSeekFailed": "DeepSeek-Konfiguration konnte nicht gespeichert werden", + "modelProviderRequired": "Bitte wählen Sie vor dem Speichern einen Modellanbieter aus.", + "affectedRunningSessions": "{count, plural, one {# laufende Sitzung muss zum Anwenden neu verbunden werden} other {# laufende Sitzungen müssen zum Anwenden neu verbunden werden}}", + "providerConnected": "{providerId} verbunden", + "connectFailed": "Verbinden von {providerId} fehlgeschlagen", + "providerDisconnected": "{providerId} getrennt", + "disconnectFailed": "Trennen von {providerId} fehlgeschlagen", + "catalogRefreshed": "Katalog aktualisiert – {count} Provider", + "catalogRefreshFailed": "Aktualisieren des Katalogs fehlgeschlagen", + "piSaved": "Pi-Konfiguration gespeichert", + "savePiFailed": "Pi-Konfiguration konnte nicht gespeichert werden", + "piRuntimeSaved": "Pi-Laufzeit gespeichert", + "savePiRuntimeFailed": "Pi-Laufzeit konnte nicht gespeichert werden", + "piBinaryInstalled": "pi installiert", + "piBinaryInstallFailed": "pi-Installation fehlgeschlagen", + "piBinaryUninstalled": "pi deinstalliert", + "piBinaryUninstallFailed": "pi-Deinstallation fehlgeschlagen", + "savePiTrustFailed": "Speichern des Arbeitsbereich-Vertrauens fehlgeschlagen" + }, + "version": { + "statusLabel": "Versionsstatus", + "notInstalled": "Nicht installiert", + "remoteLocal": "Remote: {remoteVersion} · Lokal: {localVersion}", + "localOnly": "Lokal: {localVersion}", + "localInstalled": "{versionText}. Installiert.", + "platformUnsupported": "{versionText}. Aktuelle Plattform unterstützt diesen Agenten nicht.", + "uvxNotReady": "{versionText}. Die uv-Laufzeit ist nicht installiert – installieren Sie sie über die uv-Prüfung unten, um diesen Agenten zu verwenden.", + "clickInstall": "{versionText}. Rechts auf Installieren klicken.", + "localUnrecognized": "{versionText}. Lokale Version ist nicht vergleichbar; zum Überschreiben bitte Upgrade versuchen.", + "upgradeAvailable": "{versionText}. Upgrade verfügbar.", + "remoteUnavailable": "{versionText}. Remote-Version ist derzeit nicht verfügbar.", + "latest": "{versionText}. Bereits aktuell." + }, + "adapter": { + "label": "ACP-Adapter", + "badge": "ACP-Adapter", + "badgeHint": "Für diesen Agenten installiert Codeg ein ACP-Adapterpaket, nicht die Hersteller-CLI. Beide sind unabhängig und teilen sich dieselbe Konfiguration.", + "learnMore": "Mehr erfahren", + "missingWithNative": "Deine eigene {nativeLabel} wurde unter {nativePath} gefunden. Codeg spricht mit Agenten über ACP, und diese CLI beherrscht kein ACP — deshalb braucht Codeg ein separates Adapterpaket, {adapterPackage}, gepflegt vom Agent-Client-Protocol-Projekt (ursprünglich Zed). Es bringt seine eigene Laufzeit mit, verändert oder ersetzt deinen Befehl {nativeCmd} nie und liest dasselbe {configDir} — Anmeldung und Einstellungen bleiben erhalten. Unten installieren.", + "missing": "Codeg spricht mit Agenten über ACP, und die {nativeLabel} beherrscht kein ACP — deshalb braucht Codeg ein separates Adapterpaket, {adapterPackage}, gepflegt vom Agent-Client-Protocol-Projekt (ursprünglich Zed). Es bringt seine eigene Laufzeit mit, die CLI {nativeCmd} ist also nicht Voraussetzung; hast du sie bereits, koexistieren beide und teilen sich Anmeldung und Einstellungen in {configDir}. Unten installieren.", + "readyWithNative": "Der Adapter {adapterCmd} ist installiert — ihn startet Codeg, nicht dein eigenes {nativeCmd} unter {nativePath}. Es sind getrennte Pakete, die koexistieren, und beide lesen {configDir}, Anmeldung und Einstellungen sind also gemeinsam.", + "ready": "Der Adapter {adapterCmd} ist installiert — ihn startet Codeg. Er bringt seine eigene Laufzeit mit, die {nativeLabel} wird also nicht benötigt; installierst du sie später, koexistieren beide und teilen sich {configDir}." + }, + "cline": { + "configDescription": "Konfigurieren Sie den Cline API-Anbieter und die Anmeldedaten. Einstellungen werden in ~/.cline/data/ gespeichert." + }, + "opencodePlugins": { + "title": "OpenCode-Plugins", + "declared": "Deklarierte Plugins", + "noPlugins": "Keine Plugins in opencode.json deklariert", + "status": { + "installed": "Installiert", + "missing": "Nicht installiert" + }, + "installAll": "Alle fehlenden installieren", + "pinVersions": "@latest-Versionen fixieren", + "install": "Installieren", + "uninstall": "Deinstallieren", + "refresh": "Aktualisieren", + "success": "Alle Plugins wurden erfolgreich installiert", + "failed": "Plugin-Vorgang fehlgeschlagen" + }, + "pi": { + "configManagement": "Pi-Konfiguration", + "configDescription": "Pi authentifiziert sich über den API-Schlüssel deines Modellanbieters. Der Schlüssel wird in ~/.pi/agent/auth.json und die Modellauswahl in settings.json geschrieben.", + "providerLabel": "Anbieter", + "modelLabel": "Modell", + "thinkingLabel": "Denken", + "thinking": { + "off": "Aus", + "low": "Niedrig", + "medium": "Mittel", + "high": "Hoch", + "minimal": "Minimal", + "xhigh": "Sehr hoch" + }, + "apiKeyLabel": "API-Schlüssel", + "apiKeyHint": "Wird in ~/.pi/agent/auth.json für den ausgewählten Anbieter gespeichert.", + "apiKeySetPlaceholder": "•••••• (gespeichert – leer lassen zum Beibehalten)", + "saveConfig": "Pi-Konfiguration speichern", + "providerModelRequired": "Anbieter und Modell sind erforderlich", + "runtimeTitle": "Laufzeit", + "runtimeDescription": "Wähle, welches pi-Binary läuft. Standard verwenden oder auf deinen eigenen pi-Build verweisen.", + "modeDefault": "Standard-pi", + "modeDefaultHint": "Verwendet den integrierten pi-acp-Adapter mit dem pi in deinem PATH. pi installieren: npm install -g @earendil-works/pi-coding-agent", + "modeCustom": "Eigenes pi", + "modeCustomHint": "Führe deinen eigenen pi-Build, deine Installation oder einen Wrapper aus.", + "commandLabel": "pi-Befehl oder -Pfad", + "commandHint": "Ein absoluter Pfad, ein Befehlsname im PATH oder ein Wrapper-Skript (z. B. ./pi-test.sh eines Monorepos).", + "commandNotFound": "Befehl nicht gefunden", + "validate": "Prüfen", + "advanced": "Erweitert", + "configDirLabel": "Konfigurationsverzeichnis (PI_CODING_AGENT_DIR)", + "sessionDirLabel": "Sitzungsverzeichnis (PI_CODING_AGENT_SESSION_DIR)", + "flagsHint": "pi-acp leitet eigene pi-Flags (--approve, -e, …) nicht weiter – umhülle pi mit einem Skript und verweise den Befehl darauf.", + "customIncomplete": "Gib einen pi-Befehl zum Speichern ein", + "saveRuntime": "Laufzeit speichern", + "providerPlaceholder": "Anbieter auswählen", + "customProvider": "Eigener Anbieter…", + "providerIdLabel": "Anbieter-ID", + "apiProtocolLabel": "API-Protokoll", + "baseUrlLabel": "API-Endpunkt (Base URL)", + "customProviderHint": "Definiert einen Anbieter in ~/.pi/agent/models.json an Ihrem Endpunkt. Die meisten selbst gehosteten oder Proxy-Server nutzen openai-completions.", + "baseUrlRequired": "API-Endpunkt (Base URL) ist erforderlich", + "binaryTitle": "pi-Binärdatei (pi-coding-agent)", + "binaryDescription": "pi-acp führt diese pi-Binärdatei aus. Hier installieren oder pi-acp unten auf einen eigenen Build verweisen.", + "binaryInstalled": "Installiert", + "binaryMissing": "Nicht installiert", + "binaryChecking": "Wird geprüft…", + "installBinary": "pi installieren", + "installing": "Wird installiert…", + "recheck": "Erneut prüfen", + "configDirSkillsNote": "Mit einem benutzerdefinierten Konfigurationsverzeichnis gelten die in den Einstellungen verwalteten Skills, Experten und Office-Tools nicht für dieses pi — verwalte seine Skills direkt in diesem Ordner.", + "projectTrustTitle": "Projektvertrauen", + "projectTrustDescription": "Ordner, aus denen pi Projektdateien laden darf. In einem vertrauten Ordner führt das Repository seine .pi/extensions beim Start von pi aus. Die Entscheidung gilt für alle enthaltenen Ordner und auch, wenn du pi im Terminal startest.", + "projectTrustLoading": "Wird geladen…", + "projectTrustEmpty": "Noch keine Ordner entschieden.", + "projectTrustTrusted": "Vertraut", + "projectTrustDenied": "Nicht vertraut", + "projectTrustRevoke": "Widerrufen", + "reasoningTitle": "Reasoning", + "reasoningEnableLabel": "Aktivieren", + "reasoningDescription": "pi sendet einen Reasoning-Aufwand nur für ein Modell, das ihn deklariert — bei einem nicht deklarierten Modell werden alle Stufen auf Off begrenzt, sodass die Auswahl im Eingabefeld sofort zurückspringt. Wird in den Eintrag dieses Modells in models.json geschrieben.", + "levelsLabel": "Verfügbare Stufen", + "levelsHint": "Diese werden zu den Einträgen der Reasoning-Auswahl im Eingabefeld. Wähle die, die dein Endpunkt akzeptiert; jede hier nicht gelistete Stufe lehnt pi ab.", + "levelsEmptyError": "Wähle mindestens eine Stufe — ohne eine fällt pi auf Off zurück.", + "wireValuesTitle": "Erweitert: an den Anbieter gesendete Werte", + "wireValuesHint": "Leer lassen, um den Stufennamen unverändert zu senden. Setze einen Wert, wenn dein Endpunkt etwas anderes erwartet — Google-artige Backends erwarten LOW / HIGH.", + "defaultLevelUnlisted": "Diese Stufe steht nicht in der Liste oben — pi würde sie begrenzen." + }, + "addCustomAgent": "Eigenen Agenten hinzufügen", + "addCustomAgentHint": "Registriere jeden ACP-kompatiblen Agenten. Wähle einen aus der öffentlichen ACP-Registry oder füge seine Registry-Informationen ein.", + "customAgentFromRegistry": "ACP-Registry", + "customAgentManual": "Manuell", + "customAgentSearchPlaceholder": "Agenten suchen…", + "customAgentLoadingCatalog": "ACP-Registry wird geladen…", + "customAgentRetry": "Erneut versuchen", + "customAgentNoResults": "Keine passenden Agenten", + "customAgentAdd": "Hinzufügen", + "customAgentAlreadyAdded": "Hinzugefügt", + "customAgentUnsupportedPlatform": "Kein Build für diese Plattform verfügbar", + "customAgentAdded": "{name} hinzugefügt", + "customAgentIdLabel": "Registry-ID", + "customAgentNameLabel": "Anzeigename", + "customAgentVersionLabel": "Version", + "customAgentSpecLabel": "Distribution (JSON)", + "customAgentSpecHint": "Gleiche Form wie das distribution-Objekt der ACP-Registry: Kanäle npx, uvx und binary, oder ein kompletter Registry-Eintrag zum Einfügen. Bei npx/uvx ist cmd der vom Paket installierte Befehl — bei Weglassen aus dem Paketnamen abgeleitet, bei Abweichung also angeben. binary ist nach Plattformschlüssel gegliedert (diese Maschine: {platform}); cmd ist der Startpfad im Archiv, sha256 prüft optional den Download.", + "customAgentTemplateLabel": "Vorlagen", + "customAgentKindLabel": "Starten über", + "customAgentInvalidJson": "Kein gültiges JSON", + "customAgentNoDistribution": "Keine npx-, uvx- oder binary-Distribution gefunden", + "customAgentCancel": "Abbrechen", + "customAgentSave": "Agent hinzufügen", + "customAgentSaveChanges": "Änderungen speichern", + "customAgentEdit": "Agent bearbeiten", + "customAgentEditHint": "Name, Icon, Distribution und Skills-Deklarationen ändern. Die Agent-ID kann nicht geändert werden.", + "customAgentEditNotFound": "Benutzerdefinierter Agent {id} wurde nicht gefunden", + "customAgentSaved": "{name} gespeichert", + "customAgentVersionProbeLabel": "Versionsabfrage-Befehl (optional)", + "customAgentVersionProbeHint": "Befehl, der die lokal installierte Version ausgibt. Bleibt er leer, führt codeg den Agent-Befehl mit --version aus.", + "customAgentRemove": "Agent entfernen", + "customAgentRemoveHint": "Löscht die Agent-Definition. Bestehende Unterhaltungen behalten ihren Verlauf; der Agent lässt sich nur nicht mehr starten.", + "customAgentIconLabel": "Symbol (optional)", + "customAgentIconUpload": "Hochladen", + "customAgentIconReplace": "Ersetzen", + "customAgentIconClear": "Symbol entfernen", + "customAgentIconHint": "Wird beim Agenten gespeichert und funktioniert daher offline. Ohne Symbol wird ein farbiger Anfangsbuchstabe verwendet.", + "customAgentSkillsLabel": "Skills (gemeinsames .agents/skills)", + "customAgentSkillsHint": "Erklärt, dass dieser Agent den gemeinsamen .agents/skills-Speicher liest (globale und Projekt-Verzeichnisse), und nimmt ihn in alle Skill-Matrizen auf. Dort verknüpfte Skills sind für alle Agenten sichtbar, die diesen Speicher lesen.", + "customAgentSkillsDirLabel": "Dediziertes Skills-Verzeichnis", + "customAgentSkillsDirHint": "Absoluter Pfad des Verzeichnisses, aus dem dieser Agent Skills lädt — sein eigener Speicher, zusätzlich zum geteilten oder an dessen Stelle. ~ wird zum Home-Verzeichnis erweitert; verknüpfte Skills landen zuerst hier.", + "customAgentMcpLabel": "MCP-Unterstützung", + "customAgentMcpHint": "Übergibt den in codeg integrierten MCP-Begleitprozess beim Sitzungsstart an diesen Agenten — der Kanal hinter Delegation, Live-Feedback und Aufgaben-Tools. Für einen Agenten, der MCP-Server ablehnt und deshalb keine Verbindung aufbaut, ausschalten; die Änderung gilt ab der nächsten Verbindung.", + "customAgentIconNotAnImage": "Bitte eine Bilddatei auswählen.", + "customAgentIconTooLarge": "Das Symbol muss kleiner als {limit} KB sein.", + "customAgentIconReadFailed": "Dieses Bild konnte nicht gelesen werden.", + "customAgentRemoveConfirm": "{name} entfernen? Bestehende Unterhaltungen bleiben erhalten, der Agent lässt sich aber nicht mehr starten.", + "customAgentRemoveWithData": "Auch den aufgezeichneten Gesprächsverlauf löschen", + "customAgentRemoved": "{name} entfernt", + "customAgentBadge": "Eigen", + "customAgentNotLaunchable": "Dieser Agent kann hier nicht gestartet werden: {reason}" + }, + "SettingsPages": { + "agentsLoading": "Agent-Einstellungen werden geladen...", + "skillPacksLoading": "Skill-Pakete werden geladen…" + }, + "GeneralSettings": { + "loading": "Wird geladen...", + "sectionTitle": "Allgemein", + "sectionDescription": "Zentrale Einstellungen für das Standardterminal, die Rendering-Beschleunigung und die Multi-Agent-Delegation.", + "terminalTitle": "Standardterminal", + "terminalDescription": "Wählen Sie die Shell, die beim Öffnen neuer Terminal-Tabs über die Terminalleiste oder den Dateibaum verwendet wird. Agenten nutzen sie ebenfalls, wenn sie codeg um die Ausführung einer vollständigen Befehlszeile bitten.", + "terminalSystemDefault": "Systemstandard", + "terminalPowerShell7": "PowerShell 7 (pwsh)", + "terminalWindowsPowerShell": "Windows PowerShell", + "terminalCmd": "Eingabeaufforderung (cmd)", + "terminalSaveFailed": "Speichern der Terminaleinstellungen fehlgeschlagen: {message}", + "terminalShellCustom": "Benutzerdefinierter Pfad", + "terminalShellCustomPath": "Shell-Pfad", + "terminalShellCustomPlaceholder": "/usr/local/bin/fish", + "terminalShellCustomSave": "Speichern", + "terminalShellCustomHint": "Absoluten Pfad oder einen über PATH auflösbaren Namen angeben.", + "terminalShellNotInstalled": "nicht installiert", + "terminalShellNotFoundWarning": "Dieser Pfad existiert auf diesem Host nicht.", + "terminalCurrentShell": "Aktuell verwendet: {path}", + "renderingDescription": "Deaktivieren Sie die Hardwarebeschleunigung, wenn die App einen schwarzen Bildschirm oder Render-Fehler zeigt (häufig bei bestimmten AMD-GPUs oder integrierten Intel-GPUs). Wirkt sich nur auf die Windows-Desktop-Version aus.", + "disableHardwareAcceleration": "Hardwarebeschleunigung deaktivieren", + "renderingSaveFailed": "Render-Einstellungen konnten nicht gespeichert werden: {message}", + "restartRequired": "Gespeichert. Starten Sie die App neu, damit die Änderung wirksam wird.", + "restartNow": "Jetzt neu starten", + "restartFailed": "Neustart fehlgeschlagen: {message}", + "loadFailed": "Laden fehlgeschlagen: {message}" + }, + "LoginPage": { + "documentTitle": "Anmelden - codeg", + "brand": "Codeg", + "subtitle": "Gib dein Zugriffstoken ein, um dich mit der Desktop-App zu verbinden", + "tokenPlaceholder": "Zugriffstoken", + "connect": "Verbinden", + "connecting": "Verbinde...", + "helpText": "Das Token findest du in der Desktop-App unter Einstellungen → Webdienst", + "invalidToken": "Ungültiges Token. Bitte überprüfe es und versuche es erneut.", + "connectionFailed": "Verbindung fehlgeschlagen (HTTP {status})", + "networkError": "Verbindung zum Server nicht möglich" + }, + "CommitPage": { + "title": "Einchecken", + "invalidFolderId": "Ungültige Ordner-ID", + "loadingRepo": "Repository wird geladen..." + }, + "MergePage": { + "title": "Konflikte lösen", + "invalidFolderId": "Ungültige Ordner-ID", + "loadingRepo": "Repository wird geladen...", + "localVersion": "Lokal (Unsere)", + "result": "Ergebnis", + "remoteVersion": "Remote (Deren)", + "acceptLocal": "Lokal übernehmen", + "acceptRemote": "Remote übernehmen", + "markResolved": "Als gelöst markieren", + "abortMerge": "Abbrechen", + "completeMerge": "Merge abschließen", + "unresolvedConflicts": "Es gibt noch ungelöste Konfliktmarkierungen in dieser Datei", + "fileResolved": "Datei erfolgreich gelöst", + "allResolved": "Alle Konflikte gelöst", + "conflictFiles": "Konfliktdateien", + "loadingFile": "Datei wird geladen...", + "preparingMerge": "Merge wird vorbereitet...", + "selectFile": "Datei zum Lösen auswählen", + "noConflicts": "Keine Konfliktdateien", + "skipFile": "Überspringen", + "abortSuccess": "Vorgang abgebrochen", + "applyAllNonConflicting": "Alle konfliktfreien Änderungen anwenden", + "applyLeftNonConflicting": "Lokal anwenden", + "applyRightNonConflicting": "Remote anwenden" + }, + "ImportSessions": { + "title": "Lokale Sitzungen importieren", + "scanningTitle": "Lokale Agentensitzungen werden gescannt…", + "scanningHint": "Die lokalen Sitzungsspeicher der Agenten werden durchsucht. Bei großen Verläufen kann das etwas dauern. Bereits importierte Sitzungen werden dabei aktualisiert.", + "scanFailed": "Scan fehlgeschlagen", + "retry": "Erneut versuchen", + "rescan": "Neu scannen", + "empty": "Keine lokalen Sitzungen gefunden", + "emptyHint": "Auf diesem Rechner wurden keine Sitzungsspeicher von Agenten gefunden.", + "noMatches": "Keine Sitzungen entsprechen den aktuellen Filtern", + "searchPlaceholder": "Titel oder Pfad suchen…", + "allAgents": "Alle Agenten", + "onlyImportable": "Nur importierbare", + "selectAll": "Alle auswählen", + "clearSelection": "Leeren", + "expandAll": "Alle ausklappen", + "collapseAll": "Alle einklappen", + "summaryCounts": "{total} Sitzungen · {importable} importierbar · {folders} Ordner", + "noFolderSkipped": "{count} ohne Projektordner übersprungen", + "folderNew": "Neu", + "folderCounts": "{importable}/{total} importierbar", + "toggleFolderAria": "Alle importierbaren Sitzungen in {name} auswählen", + "toggleSessionAria": "Sitzung {title} auswählen", + "statusImported": "Importiert", + "statusDeleted": "Gelöscht", + "untitled": "Unbenannte Sitzung", + "messageCount": "{count} Nachrichten", + "selectedCount": "{count} ausgewählt", + "importSelected": "Auswahl importieren", + "importing": "Importiere…", + "close": "Schließen", + "doneTitle": "Import abgeschlossen", + "doneImported": "Importiert", + "doneUpdated": "Aktualisiert", + "doneSkipped": "Übersprungen", + "doneCreatedFolders": "Ordner erstellt", + "doneNotFound": "Nicht gefunden", + "doneFailed": "Fehlgeschlagen", + "continueImport": "Weiter importieren", + "toasts": { + "importFailed": "Import fehlgeschlagen: {message}" + } + }, + "Folder": { + "workspaceStatus": { + "degradedTitle": "Live-Aktualisierungen nicht verfügbar", + "degradedHint": "Beobachter konnte nicht gestartet werden (z. B. Berechtigung verweigert). Aktualisiere manuell, um Änderungen zu sehen.", + "retry": "Wiederholen", + "retrying": "Wird wiederholt..." + }, + "common": { + "all": "Alle", + "cancel": "Abbrechen", + "close": "Schließen", + "closeOthers": "Andere schließen", + "closeAll": "Alle schließen", + "confirm": "Bestätigen", + "save": "Speichern", + "delete": "Löschen", + "rename": "Umbenennen", + "loading": "Wird geladen...", + "refresh": "Aktualisieren", + "refreshing": "Aktualisierung...", + "create": "Erstellen", + "createAndSwitch": "Erstellen und wechseln", + "openFile": "Datei öffnen", + "viewDiff": "Diff anzeigen", + "push": "Pushen..." + }, + "statusLabels": { + "in_progress": "In Bearbeitung", + "pending_review": "Prüfung", + "completed": "Abgeschlossen", + "cancelled": "Abgebrochen" + }, + "sidebar": { + "title": "Konversationen", + "locateActiveConversation": "Aktive Konversation finden", + "expandAllGroups": "Alle Gruppen erweitern", + "collapseAllGroups": "Alle Gruppen einklappen", + "newConversation": "Neue Konversation", + "newConversationShort": "Neu", + "newChat": "Neue Konversation", + "search": "Suchen", + "noConversationsFound": "Keine Konversationen gefunden.", + "importLocalSessions": "Lokale Sitzungen importieren", + "importing": "Importiere...", + "error": "Fehler: {message}", + "completeAllSessions": "Alle Sitzungen abschließen", + "completeAllReviewTitle": "Alle Review-Sitzungen abschließen?", + "completeAllReviewDescription": "Dadurch werden alle {count, plural, one {# Sitzung} other {# Sitzungen}} im Review als abgeschlossen markiert.", + "completing": "Abschließen...", + "toasts": { + "importedSessions": "{imported, plural, one {# Sitzung} other {# Sitzungen}} importiert, {skipped} übersprungen", + "importedAndUpdated": "{imported, plural, one {# Sitzung} other {# Sitzungen}} importiert, {updated, plural, one {# Titel} other {# Titel}} aktualisiert, {skipped} übersprungen", + "updatedTitles": "{updated, plural, one {# Titel} other {# Titel}} aktualisiert, {skipped} übersprungen", + "noNewSessionsFound": "Keine neuen Sitzungen gefunden ({skipped} übersprungen)", + "importFailed": "Import fehlgeschlagen: {message}", + "reviewCompleted": "{count, plural, one {# Review-Sitzung} other {# Review-Sitzungen}} als abgeschlossen markiert", + "completeReviewFailed": "Review-Sitzungen konnten nicht abgeschlossen werden: {message}", + "folderOpened": "Ordner {name} geöffnet", + "folderRemoved": "Ordner {name} entfernt", + "openFolderFailed": "Ordner konnte nicht geöffnet werden", + "removeFolderFailed": "Ordner konnte nicht entfernt werden: {message}", + "reorderFoldersFailed": "Ordner konnten nicht neu sortiert werden: {message}", + "changeFolderColorFailed": "Farbe konnte nicht geändert werden: {message}", + "setFolderAliasFailed": "Alias konnte nicht festgelegt werden: {message}", + "changeFolderDefaultAgentFailed": "Standard-Agent konnte nicht gesetzt werden: {message}" + }, + "statsLabel": "{folders} Ordner · {convos} Konversationen", + "reorderHandle": "Zum Neuordnen ziehen", + "openFolder": "Ordner öffnen", + "searchPlaceholder": "Konversationen suchen...", + "viewOptions": "Anzeigeoptionen", + "showCompleted": "Abgeschlossene Konversationen anzeigen", + "showWorktrees": "Worktree-Ordner anzeigen", + "showRecent": "Gruppe „Zuletzt“ anzeigen", + "moreOptions": "Weitere Optionen", + "sortBy": "Sortieren nach", + "sortByCreatedAt": "Erstellungszeit", + "sortByUpdatedAt": "Aktualisierungszeit", + "sectionOrder": "Abschnittsreihenfolge", + "sectionOrderMoveUp": "Nach oben", + "sectionOrderMoveDown": "Nach unten", + "sectionOrderItemLabel": "{name} — Position {position} von {total}", + "statusRunningBadge": "Läuft", + "runningCountBadge": "{count, plural, one {# laufende Sitzung} other {# laufende Sitzungen}}", + "statusCancelledBadge": "Abgebrochen", + "worktreeRemovedBadge": "Quell-Worktree entfernt", + "conversationCountUnit": "{count, plural, one {# Konversation} other {# Konversationen}}", + "emptyFolderHint": "Keine Konversationen", + "noMatchingConversations": "Keine passenden Konversationen", + "noUnfinishedConversations": "Keine offenen Konversationen. Aktiviere \"Abgeschlossene anzeigen\" im Menü oben rechts.", + "removeFolderConfirmTitle": "Ordner aus Arbeitsbereich entfernen?", + "removeFolderConfirmDescription": "\"{name}\" aus dem Arbeitsbereich entfernen? Zugehörige Tabs und Terminals werden geschlossen.", + "folderHeaderMenu": { + "manageConversations": "Konversationen verwalten…", + "manageLinks": "Verknüpfte Ordner", + "changeColor": "Farbe ändern", + "useThemeColor": "App-Design verwenden", + "setDefaultAgent": "Standard-Agent festlegen", + "defaultAgentNone": "Kein Standard (global verwenden)", + "agentUnavailableSuffix": "(nicht verfügbar)", + "loadingAgents": "Agenten werden geladen…", + "setAlias": "Alias festlegen…", + "setAliasTitle": "Ordner-Alias festlegen", + "setAliasPlaceholder": "Alias eingeben (zum Entfernen leer lassen)", + "setAliasSave": "Speichern", + "setAliasCancel": "Abbrechen", + "removeFromWorkspace": "Aus Arbeitsbereich entfernen" + }, + "manageConversations": { + "title": "Konversationen verwalten", + "searchPlaceholder": "Nach Titel suchen…", + "agentFilterAll": "Alle Agenten", + "statusFilterAll": "Alle Status", + "folderFilterAll": "Alle Ordner", + "branchFilterAll": "Alle Branches", + "branchNone": "Kein Branch", + "branchSearchPlaceholder": "Branches suchen…", + "noMatchingBranches": "Keine passenden Branches", + "selectAllVisible": "Alle auswählen", + "deselectAll": "Auswahl aufheben", + "selectedCount": "{count} ausgewählt", + "matchedCount": "{count} Treffer", + "untitledConversation": "Unbenannte Konversation", + "setStatus": "Status setzen…", + "deleteSelected": "Löschen", + "noConversations": "Keine Konversationen in diesem Ordner.", + "noConversationsWorkspace": "Keine Konversationen im Arbeitsbereich.", + "noMatchingConversations": "Keine Konversationen entsprechen den Filtern.", + "confirmDeleteTitle": "{count} Konversation(en) löschen?", + "confirmDeleteDescription": "Diese Aktion kann nicht rückgängig gemacht werden.", + "toastDeleted": "{count} Konversation(en) gelöscht", + "toastStatusUpdated": "Status von {count} Konversation(en) aktualisiert", + "toastOpFailed": "Aktion fehlgeschlagen: {message}" + }, + "sectionPinned": "Angeheftet", + "sectionFolders": "Ordner", + "sectionChats": "Chat", + "sectionRecent": "Zuletzt", + "noChats": "Keine Chats", + "noRecent": "Keine kürzlichen Konversationen", + "showMoreRecent": "Mehr anzeigen ({count})", + "noFolders": "Keine Ordner geöffnet", + "newChatAction": "Neuer Chat", + "automations": "Automatisierungen", + "tasks": "To-dos", + "loadingSubsessions": "Unterkonversationen werden geladen…" + }, + "conversation": { + "reloadFailed": "Konversation konnte nicht neu geladen werden: {message}", + "reloaded": "Konversation neu geladen", + "reload": "Neu laden", + "activeConversationIndicator": "Aktive Konversation", + "newConversation": "Neue Konversation", + "closeConversation": "Konversation schließen", + "copyText": "Text kopieren", + "copyTextSuccess": "Kopiert", + "copyTextFailed": "Kopieren fehlgeschlagen", + "forkSession": "Sitzung forken", + "forkSessionSuccess": "Sitzung erfolgreich geforkt", + "forkSessionFailed": "Sitzung konnte nicht geforkt werden: {error}", + "exportConversation": "Konversation exportieren", + "exportImage": "Bild", + "exportMarkdown": "Markdown", + "exportHtml": "HTML", + "exportSuccess": "Konversation exportiert", + "exportFailed": "Export fehlgeschlagen", + "exportImageTooLong": "Konversation ist zu lang für den Bildexport", + "exportLabels": { + "untitledConversation": "Unbenannte Konversation", + "agent": "Agent", + "model": "Modell", + "status": "Status", + "started": "Gestartet", + "updated": "Aktualisiert", + "tokens": "Token-Statistik", + "duration": "Dauer", + "inputTokens": "Eingabe", + "outputTokens": "Ausgabe", + "cacheRead": "Cache gelesen", + "cacheWrite": "Cache geschrieben", + "user": "Benutzer", + "assistant": "Assistent", + "system": "System", + "toolResult": "Ergebnis", + "toolError": "Fehler" + }, + "moreActions": "Weitere Aktionen" + }, + "sessionDetails": { + "menuLabel": "Sitzungsdetails", + "noActiveSession": "Keine aktive Sitzung", + "title": "Sitzungsdetails", + "subtitle": "Sitzungsmetadaten und Token-Nutzung", + "fieldTitle": "Titel", + "untitled": "Unbenannte Konversation", + "sessionId": "Sitzungs-ID", + "externalId": "Erweiterungs-ID", + "agent": "Agent", + "model": "Modell", + "status": "Status", + "gitBranch": "Git-Branch", + "parentId": "Übergeordnete Sitzung", + "tokensHeading": "Token-Nutzung", + "totalTokens": "Gesamt", + "inputTokens": "Eingabe", + "outputTokens": "Ausgabe", + "cacheWrite": "Cache geschrieben", + "cacheRead": "Cache gelesen", + "contextWindow": "Kontextfenster", + "duration": "Dauer", + "loadingStats": "Token-Nutzung wird geladen…", + "loadFailed": "Token-Nutzung konnte nicht geladen werden", + "noStats": "Keine Nutzung erfasst", + "timestampsHeading": "Zeitstempel", + "createdAt": "Erstellt", + "updatedAt": "Aktualisiert", + "none": "—", + "copyField": "{field} kopieren", + "copiedField": "{field} kopiert" + }, + "conversationCard": { + "untitledConversation": "Unbenannte Konversation", + "newConversation": "Neue Konversation", + "rename": "Umbenennen", + "status": "Zustand", + "delete": "Löschen", + "importLocalSessions": "Lokale Sitzungen importieren", + "importing": "Importiere...", + "renameConversation": "Konversation umbenennen", + "deleteConversationTitle": "Konversation löschen?", + "deleteConversationDescription": "\"{title}\" wird gelöscht. Diese Aktion kann nicht rückgängig gemacht werden.", + "cancel": "Abbrechen", + "save": "Speichern", + "pin": "Anheften", + "unpin": "Loslösen", + "markCompleted": "Als abgeschlossen markieren", + "reopen": "Erneut öffnen", + "expandSubsessions": "Unterkonversationen einblenden", + "collapseSubsessions": "Unterkonversationen ausblenden" + }, + "search": { + "dialogTitle": "Suchen", + "dialogTitleWithFolder": "Suchen — {name}", + "tabConversations": "Konversationen", + "tabFiles": "Dateien", + "placeholder": "Konversationen suchen...", + "filePlaceholder": "Dateien oder Verzeichnisse suchen...", + "allAgents": "Alle", + "searching": "Suche...", + "typeToSearch": "Tippen, um Konversationen zu suchen", + "typeToSearchFiles": "Tippen, um Dateien oder Verzeichnisse zu suchen", + "noResults": "Keine Ergebnisse gefunden.", + "untitledConversation": "Unbenannte Konversation" + }, + "folderTitleBar": { + "showSidebar": "Seitenleiste anzeigen", + "hideSidebar": "Seitenleiste ausblenden", + "toggleTerminal": "Terminal umschalten", + "toggleAuxPanel": "Hilfspaneel umschalten", + "search": "Suchen", + "openSettings": "Einstellungen öffnen", + "backToConversations": "Zurück zu Konversationen", + "withShortcut": "{label} (Tastenkürzel: {shortcut})" + }, + "statusBar": { + "connection": { + "connected": "Verbunden", + "connecting": "Verbinde...", + "prompting": "Antworte...", + "error": "Verbindungsfehler", + "disconnected": "Getrennt", + "tooltip": "{agent}: {status}", + "tooltipError": "{agent}: {error}", + "title": "Agent-Verbindung", + "triggerAria": "Agent-Verbindung: {status}", + "workingDir": "Arbeitsverzeichnis", + "sessionId": "Sitzungs-ID", + "viewerNote": "Mit einer Sitzung verbunden, die einem anderen Client gehört – ein Neuverbinden hängt nur diese Ansicht erneut an.", + "reconnectInterrupts": "Neu verbinden startet den Agenten neu und unterbricht die laufende Arbeit.", + "reconnect": "Neu verbinden", + "reconnecting": "Verbinde neu...", + "reconnectUnavailable": "Noch keine Sitzung zum Neuverbinden." + }, + "tasks": { + "title": "Aufgaben" + }, + "alerts": { + "title": "Warnungen", + "empty": "Keine Warnungen", + "details": "Details" + }, + "stats": { + "conversations": "{count} Konversationen", + "openUsage": "Sitzungsstatistik und Token-Nutzung anzeigen" + }, + "tokens": { + "contextWindowUsageAria": "Kontextfenster-Nutzung", + "contextWindow": "Kontextfenster", + "usedMax": "Verwendet / Max", + "tokenUsage": "Token-Nutzung", + "input": "Eingabe", + "output": "Ausgabe", + "cacheRead": "Cache lesen", + "cacheWrite": "Cache schreiben", + "total": "Gesamt" + } + }, + "auxPanel": { + "tabs": { + "files": "Dateien", + "changes": "Änderungen", + "commits": "Einträge" + }, + "noFolderTitle": "Kein Ordner geöffnet", + "noFolderHint": "Öffnen Sie einen Ordner, um seinen Inhalt hier zu sehen" + }, + "windowControls": { + "minimizeWindow": "Fenster minimieren", + "minimize": "Minimieren", + "maximizeWindow": "Fenster maximieren", + "maximize": "Maximieren", + "restoreWindow": "Fenster wiederherstellen", + "restore": "Wiederherstellen", + "closeWindow": "Fenster schließen", + "close": "Schließen" + }, + "tabs": { + "closeConversationTab": "Konversationstab schließen", + "close": "Schließen", + "closeOthers": "Andere schließen", + "splitRight": "Nach rechts teilen", + "splitDown": "Nach unten teilen", + "splitAndMoveRight": "Teilen und nach rechts verschieben", + "splitAndMoveDown": "Teilen und nach unten verschieben", + "moveToOppositeGroup": "In gegenüberliegende Gruppe verschieben", + "moveToGroup": "In Gruppe verschieben", + "groupLabel": "Gruppe {index}", + "changeSplitterOrientation": "Teiler-Ausrichtung wechseln", + "unsplit": "Teilung aufheben", + "unsplitAll": "Alle Teilungen aufheben", + "closeAll": "Alle schließen", + "tileDisplay": "Kachelansicht", + "untileDisplay": "Kachel beenden" + }, + "fileWorkspace": { + "files": "Dateien", + "closeFileTab": "Dateitab schließen", + "close": "Schließen", + "closeOthers": "Andere schließen", + "closeAll": "Alle schließen", + "preview": "Vorschau", + "editSource": "Quelle bearbeiten", + "maximize": "Maximieren", + "restore": "Wiederherstellen", + "emptyDirectory": "Leerer Ordner" + }, + "terminal": { + "rename": "Umbenennen", + "close": "Schließen", + "closeOthers": "Andere schließen", + "closeAll": "Alle schließen", + "hideTerminal": "Terminal ausblenden ({shortcut})", + "openFolderFirst": "Öffnen Sie zuerst einen Ordner" + }, + "workspaceDialog": { + "title": "Ordner öffnen", + "manageTitle": "Verknüpfte Ordner", + "addTargetsTitle": "Ordner zum Verknüpfen hinzufügen", + "pickRootDescription": "Wähle den Hauptordner für diesen Arbeitsbereich.", + "linksDescription": "Verknüpfe weitere Ordner als Unterverzeichnisse, damit Agenten aus einem Arbeitsbereich heraus über alle hinweg arbeiten können.", + "addTargetsDescription": "Wähle einen oder mehrere Ordner. Jeder wird zu einem Unterverzeichnis des Arbeitsbereichs.", + "useSystemPicker": "Systemauswahl", + "next": "Weiter", + "back": "Zurück", + "done": "Fertig", + "change": "Ändern", + "addFolders": "Ordner hinzufügen", + "addSelected": "Hinzufügen", + "addSelectedCount": "{count} hinzufügen", + "createCount": "{count} Ordner verknüpfen", + "discardPending": "Verwerfen", + "noLinks": "Noch keine verknüpften Ordner.", + "gitExclude": "Verknüpfungen aus dem Git-Status heraushalten", + "rename": "Umbenennen", + "unlink": "Verknüpfung entfernen", + "repair": "Verknüpfung neu anlegen", + "saveName": "Speichern", + "cancelRename": "Abbrechen", + "removePending": "Entfernen", + "willAppearAs": "Erscheint im Arbeitsbereich als {name}", + "renamedForDuplicate": "Umbenannt – {base} wird bereits von einer anderen Verknüpfung genutzt", + "renamedForExistingEntry": "Umbenannt – {base} existiert in diesem Ordner bereits", + "partiallyCreated": "Nur {count} Ordner konnten verknüpft werden", + "openFailed": "Ordner konnte nicht geöffnet werden", + "previewFailed": "Ausgewählte Ordner konnten nicht geprüft werden", + "createFailed": "Ordner konnten nicht verknüpft werden", + "renameFailed": "Verknüpfung konnte nicht umbenannt werden", + "removeFailed": "Verknüpfung konnte nicht entfernt werden", + "repairFailed": "Verknüpfung konnte nicht neu angelegt werden", + "status": { + "ok": "Verknüpft", + "missing": "Die Verknüpfung ist aus diesem Ordner verschwunden", + "conflicted": "Ein anderer Eintrag nutzt jetzt diesen Namen", + "broken": "Der verknüpfte Ordner existiert nicht mehr" + }, + "nameIssue": { + "empty": "Namen eingeben", + "illegalChars": "Darf / \\ : * ? \" < > | nicht enthalten", + "tooLong": "Name ist zu lang", + "reserved": "Dieser Name ist unter Windows reserviert", + "duplicate": "Dieser Name wird bereits verwendet" + }, + "rejection": { + "not_found": "Dieser Ordner wurde nicht gefunden", + "not_a_directory": "Dieser Pfad ist kein Ordner", + "same_as_root": "Das ist der Arbeitsbereichsordner selbst", + "ancestor_of_root": "Dieser Ordner enthält den Arbeitsbereich", + "inside_root": "Liegt bereits im Arbeitsbereich", + "already_linked": "Bereits verknüpft", + "name_unavailable": "Für diesen Ordner ist kein Name mehr frei", + "alreadyLinkedAs": "Bereits als {name} verknüpft" + } + }, + "folderNameDropdown": { + "fallbackFolderName": "Ordner", + "openFolder": "Ordner öffnen", + "cloneRepository": "Repository klonen", + "projectBoot": "Projekt-Boot", + "opened": "Geöffnet", + "recentOpen": "Zuletzt geöffnet" + }, + "fileWorkspacePanel": { + "addSelectionToChat": "Auswahl zum Chat hinzufügen", + "addToChat": "Zum Chat hinzufügen", + "addSelectionToChatDone": "{label} zur Unterhaltung hinzugefügt", + "addFileToChat": "Datei zum Chat hinzufügen", + "toggleWordWrap": "Zeilenumbruch umschalten", + "addFileToChatDone": "{label} zur Unterhaltung hinzugefügt", + "viewDiff": "Diff anzeigen", + "openFile": "Datei öffnen", + "fileCount": "{count, plural, one {# Datei} other {# Dateien}}", + "openFileOrDiff": "Öffne eine Datei oder Diff im rechten Panel", + "disk": "Datenträger", + "head": "HEAD", + "unsaved": "Ungespeichert", + "workingTree": "Arbeitsverzeichnis", + "loading": "Wird geladen...", + "compareWithBranch": "{path} · vergleichen mit {branch}", + "hunkCount": "{count, plural, one {# Hunk} other {# Hunks}}", + "prev": "Zurück", + "next": "Weiter", + "jumpToLine": "Zu Zeile {line} springen", + "noParsedDiffSections": "Keine geparsten Diff-Abschnitte", + "loadingEditor": "Editor wird geladen...", + "imageZoomIn": "Vergrößern", + "imageZoomOut": "Verkleinern", + "imageZoomReset": "Zoom zurücksetzen", + "htmlPreviewTitle": "HTML-Vorschau", + "htmlPreviewTrust": "Skripte aktivieren", + "htmlPreviewTrustHint": "Skripte dieser Datei ausführen und Netzwerkzugriff erlauben. Nur für vertrauenswürdige Dateien aktivieren.", + "officePreviewTitle": "Office-Dokumentvorschau", + "officeFullRender": "Vollständige Darstellung", + "officeFullRenderHint": "Stellt Morph-Animationen, 3D und Formeln dar (führt die Skripte der Folie aus)", + "officeNotInstalled": "OfficeCLI ist nicht installiert", + "officeNotInstalledHint": "Installiere OfficeCLI unter Einstellungen → Office-Tools, um Word-, Excel- und PowerPoint-Dateien vorzuschauen.", + "officeOpenSettings": "Einstellungen öffnen", + "officeWatchFailed": "Live-Vorschau konnte nicht gestartet werden", + "officeWatchRetry": "Erneut versuchen", + "officeServerInstallHint": "OfficeCLI muss auf dem Server-Host installiert sein. Führe diesen Befehl dort aus und versuche es erneut:", + "officeRemoteDesktopUnsupported": "Die Live-Vorschau ist in einem Remote-Desktop-Fenster nicht verfügbar. Öffne diesen Arbeitsbereich in der Web-Oberfläche des Servers, um Office-Dateien anzusehen." + }, + "branchDropdown": { + "toasts": { + "commitCodeCompleted": "Code-Commit abgeschlossen", + "pushCodeCompleted": "Code-Push abgeschlossen", + "committedFiles": "{count, plural, one {# Datei committet} other {# Dateien committet}}", + "taskCompleted": "{label} abgeschlossen", + "taskFailed": "{label} fehlgeschlagen", + "mergeNoNewCommits": "{branchName} hat keine neuen Commits", + "mergedCommits": "{count, plural, one {# Commit zusammengeführt} other {# Commits zusammengeführt}}", + "allFilesUpToDate": "Alle Dateien sind aktuell", + "updatedFiles": "{count, plural, one {# Datei aktualisiert} other {# Dateien aktualisiert}}", + "openCommitWindowFailed": "Commit-Fenster konnte nicht geöffnet werden", + "openPushWindowFailed": "Push-Fenster konnte nicht geöffnet werden", + "upstreamSet": "Upstream-Branch wurde gesetzt", + "upstreamSetAndPushed": "Upstream-Branch gesetzt und {count, plural, one {# Commit} other {# Commits}} gepusht", + "noCommitsToPush": "Keine Commits zum Pushen", + "pushedCommits": "{count, plural, one {# Commit gepusht} other {# Commits gepusht}}", + "switchedToFolder": "Zu {name} gewechselt", + "switchFailed": "Branch konnte nicht gewechselt werden", + "openStashWindowFailed": "Stash-Fenster konnte nicht geöffnet werden" + }, + "tasks": { + "newBranch": "Branch {name} erstellen", + "newWorktree": "Worktree {name} erstellen", + "checkoutTo": "Zu {branchName} wechseln", + "mergeBranch": "{branchName} mergen", + "rebaseTo": "Auf {branchName} rebasen", + "deleteRemoteBranch": "Remote-Branch {branchName} löschen", + "initGitRepo": "Git-Repository initialisieren", + "pullCode": "Code pullen", + "fetchInfo": "Informationen fetchen", + "pushCode": "Code pushen", + "stashChanges": "Änderungen stashen", + "stashPop": "Stash anwenden", + "deleteBranch": "Branch {branchName} löschen", + "removeWorktree": "Worktree von {branchName} löschen", + "removeWorktreeAndBranch": "Worktree und Branch {branchName} löschen", + "updateBranch": "Branch {branchName} aktualisieren" + }, + "confirm": { + "mergeTitle": "Branch mergen", + "rebaseTitle": "Branch rebasen", + "mergeDescription": "{branchName} in den aktuellen Branch {currentBranch} mergen?", + "rebaseDescription": "Aktuellen Branch {currentBranch} auf {branchName} rebasen?", + "deleteRemoteTitle": "Remote-Branch löschen", + "deleteRemoteDescription": "Remote-Branch {branchName} löschen? Dies entfernt ihn aus dem Remote-Repository und kann nicht rückgängig gemacht werden.", + "deleteTitle": "Branch löschen", + "deleteDescription": "Branch {branchName} löschen? Diese Aktion kann nicht rückgängig gemacht werden.", + "forceDeleteTitle": "Branch erzwungen löschen", + "forceDeleteDescription": "Der Branch {branchName} ist nicht vollständig gemergt. Möchten Sie ihn wirklich erzwungen löschen? Diese Aktion kann nicht rückgängig gemacht werden.", + "deleteWorktreeTitle": "Worktree löschen", + "deleteWorktreeDescription": "Das Worktree-Verzeichnis löschen, in dem {branchName} ausgecheckt ist? Der Branch und seine Commits bleiben erhalten.", + "forceDeleteWorktreeTitle": "Worktree erzwungen löschen", + "forceDeleteWorktreeDescription": "Im Worktree von {branchName} gibt es nicht committete oder nicht verfolgte Dateien. Trotzdem löschen? Diese Änderungen lassen sich nicht wiederherstellen.", + "deleteWorktreeAndBranchTitle": "Worktree und Branch löschen", + "deleteWorktreeAndBranchDescription": "Den Worktree von {branchName}, den Branch selbst und seinen Arbeitsbereich-Ordner löschen? Seine Sitzungen wandern in den Repository-Ordner. Diese Aktion kann nicht rückgängig gemacht werden.", + "forceDeleteWorktreeAndBranchTitle": "Worktree und Branch erzwungen löschen", + "forceDeleteWorktreeAndBranchDescription": "Im Worktree von {branchName} gibt es nicht committete Dateien, oder der Branch ist nicht vollständig gemergt. Trotzdem beides löschen? Diese Aktion kann nicht rückgängig gemacht werden." + }, + "current": "Aktuell", + "switchToBranch": "Zu diesem Branch wechseln", + "mergeBranchIntoCurrent": "{branchName} in {currentBranch} mergen", + "rebaseCurrentToBranch": "{currentBranch} auf {branchName} rebasen", + "noBranch": "Kein Branch", + "detachedHead": "Losgelöster HEAD bei {sha}", + "initGitRepo": "Git-Repository initialisieren", + "pullCode": "Code pullen", + "fetchRemoteBranches": "Remote-Branches fetchen", + "openCommitWindow": "Code committen...", + "pushCode": "Hochladen...", + "pushBranch": "Hochladen", + "newBranch": "Neuer Branch...", + "newWorktree": "Neuer Worktree...", + "stashChanges": "Änderungen stashen...", + "stashPop": "Stash anwenden...", + "manageRemotes": "Remotes verwalten...", + "localBranches": "Lokale Branches ({count, plural, one {#} other {#}})", + "noLocalBranches": "Keine lokalen Branches", + "remoteBranches": "Remote-Branches ({count, plural, one {#} other {#}})", + "noRemoteBranches": "Keine Remote-Branches", + "dialogs": { + "newBranchTitle": "Neuer Branch", + "newBranchDescription": "Neuen Branch vom aktuellen Branch {branch} erstellen", + "branchNamePlaceholder": "Branch-Name", + "newWorktreeTitle": "Neuer Worktree", + "newWorktreeDescription": "Neuen Worktree vom aktuellen Branch {branch} erstellen", + "branchNameLabel": "Branch-Name", + "worktreePathLabel": "Worktree-Pfad", + "worktreePathPlaceholder": "Worktree-Pfad", + "manageRemotesTitle": "Remotes verwalten", + "manageRemotesEmpty": "Keine Remotes konfiguriert", + "remoteNamePlaceholder": "Remote-Name", + "remoteUrlPlaceholder": "Remote-URL", + "addRemote": "Hinzufügen", + "savingRemotes": "Speichern..." + }, + "conflict": { + "title": "Merge-Konflikte", + "description": "Die folgenden Dateien haben Konflikte, die gelöst werden müssen:", + "abort": "Merge abbrechen", + "openMergeTool": "Merge-Tool öffnen", + "completeMerge": "Merge abschließen", + "abortSuccess": "Merge erfolgreich abgebrochen", + "completeSuccess": "Merge erfolgreich abgeschlossen" + }, + "stashDialog": { + "title": "Änderungen stashen", + "description": "Aktuelle Änderungen im Stash speichern", + "messageLabel": "Nachricht", + "messagePlaceholder": "Stash-Nachricht (optional)", + "keepIndex": "Index beibehalten (gestagete Änderungen bleiben erhalten)", + "cancel": "Abbrechen", + "stash": "Stashen", + "success": "Änderungen wurden gestasht", + "error": "Stash fehlgeschlagen" + }, + "unstashDialog": { + "title": "Stash anwenden", + "noStashes": "Keine Stashes vorhanden", + "selectFile": "Datei auswählen um Diff anzuzeigen", + "viewDiff": "Diff anzeigen", + "original": "Original", + "modified": "Geändert", + "apply": "Anwenden", + "drop": "Löschen", + "applySuccess": "Stash angewendet", + "dropSuccess": "Stash gelöscht", + "confirmApply": "Stash {ref} auf das Arbeitsverzeichnis anwenden?", + "cancel": "Abbrechen" + }, + "deleteBranch": "Branch löschen", + "deleteWorktree": "Worktree löschen", + "deleteWorktreeAndBranch": "Worktree und Branch löschen", + "searchPlaceholder": "Branches und Aktionen suchen", + "searchAriaLabel": "Branches und Aktionen suchen", + "branchListLabel": "Branches und Aktionen", + "noMatches": "Keine Treffer" + }, + "commitDialog": { + "toasts": { + "commitCompleted": "Code-Commit abgeschlossen", + "pushFailed": "Push fehlgeschlagen", + "committedFiles": "{count, plural, one {# Datei committet} other {# Dateien committet}}", + "addedToVcs": "Zu VCS hinzugefügt", + "addToVcsFailed": "Hinzufügen zu VCS fehlgeschlagen", + "fileDeleted": "Datei gelöscht", + "deleteFailed": "Löschen fehlgeschlagen", + "fileRolledBack": "Datei zurückgesetzt", + "rollbackFailed": "Rollback fehlgeschlagen", + "dirRolledBack": "Verzeichnis zurückgesetzt", + "dirDeleted": "Verzeichnis gelöscht" + }, + "confirm": { + "deleteTitle": "Löschen bestätigen", + "deleteDescription": "Datei \"{file}\" löschen? Diese Aktion kann nicht rückgängig gemacht werden.", + "rollbackTitle": "Rollback bestätigen", + "rollbackDescription": "Datei \"{file}\" auf HEAD zurücksetzen? Ungespeicherte Änderungen gehen verloren.", + "rollbackDirDescription": "Verzeichnis \"{dir}\" auf HEAD zurücksetzen? Nicht gespeicherte Änderungen gehen verloren.", + "deleteDirDescription": "Verzeichnis \"{dir}\" löschen? Diese Aktion kann nicht rückgängig gemacht werden." + }, + "actions": { + "select": "Auswählen", + "unselect": "Auswahl aufheben", + "rollback": "Zurücksetzen", + "addToVcs": "Zu VCS hinzufügen" + }, + "aria": { + "selectFile": "{action}: {path}", + "unselectAllFiles": "Auswahl aller Dateien aufheben", + "selectAllFiles": "Alle Dateien auswählen", + "unselectTracked": "Auswahl verfolgter Änderungen aufheben", + "selectTracked": "Verfolgte Änderungen auswählen", + "unselectUntracked": "Auswahl nicht verfolgter Dateien aufheben", + "selectUntracked": "Nicht verfolgte Dateien auswählen" + }, + "loading": "Wird geladen...", + "selectionCount": "{selected} / {total} Dateien", + "emptyFiles": "Keine geänderten Dateien", + "trackedChanges": "Verfolgte Änderungen ({count})", + "untrackedFiles": "Nicht verfolgte Dateien ({count})", + "commitMessage": "Commit-Nachricht", + "commitMessagePlaceholder": "Commit-Nachricht eingeben...", + "commitButton": "Einchecken ({count})", + "commitAndPushButton": "Committen und pushen ({count})", + "head": "HEAD", + "workingTree": "Arbeitsverzeichnis", + "clickFileToDiff": "Dateinamen anklicken, um Diff zu sehen", + "loadingDiff": "Diff wird geladen..." + }, + "pushWindow": { + "title": "Code pushen", + "noUnpushedCommits": "Keine ungepushten Commits", + "noRemoteConfigured": "Kein Git-Remote konfiguriert\nFüge einen unter Remotes verwalten hinzu", + "newBranchNoPushedCommits": "Neuer Branch — pushen, um Remote-Tracking-Branch zu erstellen", + "unpushed": "Nicht gepusht", + "selectFileToViewDiff": "Datei auswählen, um Unterschiede anzuzeigen", + "before": "Vorher", + "after": "Nachher", + "push": "Pushen", + "toasts": { + "pushSuccess": "Push erfolgreich", + "pushFailed": "Push fehlgeschlagen", + "upstreamSet": "Remote-Tracking-Branch wurde eingerichtet", + "upstreamSetAndPushed": "Remote-Tracking-Branch eingerichtet und {count} Commits gepusht", + "noCommitsToPush": "Keine Commits zum Pushen", + "pushedCommits": "{count} Commits gepusht" + } + }, + "gitLogTab": { + "filesTitle": "Dateien", + "expandAllFiles": "Alle Dateien ausklappen", + "collapseAllFiles": "Alle Dateien einklappen", + "workspace": "Arbeitsbereich", + "retry": "Erneut versuchen", + "noCommitsFound": "Keine Commits gefunden", + "notAGitRepoTitle": "Kein Git-Repository", + "notAGitRepoHint": "Initialisiere Git über das Branch-Menü oben oder öffne ein bestehendes Repository.", + "hash": "Hash-Wert", + "copyHash": "Hash kopieren", + "copyMessage": "Nachricht kopieren", + "showMore": "Mehr anzeigen", + "showLess": "Weniger anzeigen", + "author": "Autor", + "noFileChangeDetails": "Keine Details zu Dateiänderungen verfügbar.", + "loadingFiles": "Dateien werden geladen...", + "branchesTitle": "Zweige", + "loadingBranches": "Branches werden geladen...", + "noContainingBranches": "Keine enthaltenen Branches gefunden.", + "newBranch": "Neuer Branch...", + "resetToHere": "Auf diesen Stand zurücksetzen", + "resetDisabledReasonNotCurrentBranchView": "Nur in der Ansicht des aktuellen Branches verfügbar", + "copyFullCommitHashAria": "Vollständigen Commit-Hash {hash} kopieren", + "pushStatus": { + "pushed": "Zum Remote gepusht", + "notPushed": "Nicht zum Remote gepusht", + "unknown": "Push-Status unbekannt (kein Upstream konfiguriert)" + }, + "time": { + "monthsAgo": "{count, plural, one {vor # Monat} other {vor # Monaten}}", + "daysAgo": "{count, plural, one {vor # Tag} other {vor # Tagen}}", + "hoursAgo": "{count, plural, one {vor # Stunde} other {vor # Stunden}}", + "minsAgo": "{count, plural, one {vor # Min} other {vor # Min}}", + "justNow": "gerade eben" + }, + "toasts": { + "createdAndSwitchedNewBranch": "Neuen Branch erstellt und gewechselt", + "newBranchFromCommit": "{name} (aus {shortHash})", + "createBranchFailed": "Branch konnte nicht erstellt werden", + "openPushWindowFailed": "Push-Fenster konnte nicht geöffnet werden", + "resetSuccess": "Zurücksetzen erfolgreich", + "resetSuccessDescription": "{branch} wurde mit {mode} auf {shortHash} zurückgesetzt", + "resetFailed": "Zurücksetzen fehlgeschlagen" + }, + "authorFilter": { + "label": "Autor", + "searchPlaceholder": "Autor suchen", + "noAuthors": "Keine Autoren gefunden", + "you": "du", + "filterByAuthorAria": "Commits nach Autor filtern", + "filterByQuery": "Nach \"{query}\" filtern", + "clearAuthorFilterAria": "Autorfilter löschen", + "recent": "Zuletzt verwendet", + "matchingAuthors": "Passende Autoren", + "removeFromRecent": "{name} aus „Zuletzt verwendet“ entfernen" + }, + "branchSelector": { + "label": "Branch", + "head": "HEAD", + "headHint": "Folgt dem aktuellen Branch", + "headHintWithBranch": "Folgt dem aktuellen Branch ({branch})", + "searchBranch": "Branch suchen...", + "noBranches": "Keine Branches", + "selectBranchPlaceholder": "Branch auswählen...", + "localBranches": "Lokale Branches", + "current": "Aktuell", + "remoteBranches": "Remote-Branches", + "refreshCommitHistory": "Commit-Verlauf aktualisieren", + "clearBranchFilterAria": "Branch-Filter löschen" + }, + "dialogs": { + "newBranchTitle": "Neuer Branch", + "newBranchDescription": "Erstelle einen neuen Branch mit Commit {shortHash} als letztem Commit.", + "branchNamePlaceholder": "Branch-Name", + "reset": { + "title": "Aktuellen Branch auf diesen Commit zurücksetzen", + "branchLabel": "Branch", + "targetLabel": "Ziel-Commit", + "messageLabel": "Nachricht", + "modeLabel": "Reset-Modus", + "confirmButton": "Zurücksetzen", + "modes": { + "soft": { + "label": "--soft", + "description": "Verschiebt HEAD und den Zeiger des aktuellen Branches auf den Ziel-Commit.\nIndex und Working Tree bleiben unverändert.\nÄnderungen aus den entfernten Commits bleiben staged." + }, + "mixed": { + "label": "--mixed (Standard)", + "description": "Verschiebt HEAD auf den Ziel-Commit.\nSetzt den Index auf den Ziel-Commit zurück und behält Änderungen im Working Tree.\nÄnderungen wechseln von staged zu unstaged." + }, + "hard": { + "label": "--hard", + "description": "Verschiebt HEAD und setzt sowohl Index als auch Working Tree auf den Ziel-Commit zurück.\nLokale verfolgte Änderungen nach dem Ziel-Commit werden verworfen.\nDies ist eine destruktive Operation." + }, + "keep": { + "label": "--keep", + "description": "Verschiebt HEAD auf den Ziel-Commit und versucht lokale Änderungen zu behalten.\nNur nicht-konfliktierende Änderungen bleiben erhalten.\nBei Konflikten wird der Reset zum Schutz der Änderungen abgebrochen." + } + } + } + }, + "moreActions": "Weitere Git-Aktionen" + }, + "gitChangesTab": { + "workspace": "Arbeitsbereich", + "noChanges": "Keine lokalen Änderungen", + "notAGitRepoTitle": "Kein Git-Repository", + "notAGitRepoHint": "Initialisiere Git über das Branch-Menü oben oder öffne ein bestehendes Repository.", + "trackedChanges": "Verfolgte Änderungen ({count})", + "untrackedFiles": "Nicht verfolgte Dateien ({count})", + "expandTracked": "Verfolgte Änderungen ausklappen", + "collapseTracked": "Verfolgte Änderungen einklappen", + "expandUntracked": "Nicht verfolgte Dateien ausklappen", + "collapseUntracked": "Nicht verfolgte Dateien einklappen", + "showRemainingItems": "{count} weitere Einträge anzeigen", + "actions": { + "commitCode": "Code committen", + "rollback": "Zurücksetzen", + "addToVcs": "Zu VCS hinzufügen", + "delete": "Löschen", + "moreActions": "Weitere Git-Aktionen", + "addAllToVcs": "Alle zur VCS hinzufügen", + "rollbackAll": "Alle zurücksetzen", + "refresh": "Aktualisieren" + }, + "toasts": { + "noAddableFilesInDir": "Keine geänderten Dateien in diesem Verzeichnis können zu VCS hinzugefügt werden", + "noRollbackFilesInDir": "Keine geänderten Dateien in diesem Verzeichnis können zurückgesetzt werden", + "addedToVcs": "{name} zu VCS hinzugefügt", + "addToVcsFailed": "Hinzufügen zu VCS fehlgeschlagen", + "openCommitWindowFailed": "Commit-Fenster konnte nicht geöffnet werden", + "rolledBack": "{name} zurückgesetzt", + "rollbackFailed": "Rollback fehlgeschlagen", + "addedFilesToVcs": "{count, plural, one {# Datei} other {# Dateien}} zu VCS hinzugefügt", + "rolledBackFiles": "{count, plural, one {# Datei zurückgesetzt} other {# Dateien zurückgesetzt}}", + "deleted": "{name} gelöscht", + "deleteFailed": "Löschen fehlgeschlagen", + "deletedFiles": "{count} Dateien gelöscht", + "noDeletableFilesInDir": "In diesem Verzeichnis gibt es keine löschbaren geänderten Dateien", + "commitFailed": "Commit fehlgeschlagen" + }, + "directoryDialog": { + "descriptionAdd": "Dateien unter Verzeichnis {path} auswählen, um sie zu VCS hinzuzufügen.", + "descriptionRollback": "Dateien unter Verzeichnis {path} auswählen, um sie zurückzusetzen.", + "descriptionDelete": "Dateien unter Verzeichnis {path} auswählen, um sie zu löschen. Diese Aktion kann nicht rückgängig gemacht werden.", + "descriptionFallback": "Dateien auswählen, um fortzufahren.", + "selectionCount": "{selected} / {total} Dateien ausgewählt", + "selectAll": "Alle auswählen", + "unselectAll": "Auswahl aller aufheben", + "loadingCandidates": "Verzeichnisänderungen werden geladen...", + "noOperableFiles": "Keine bearbeitbaren Dateien" + }, + "rollbackConfirm": { + "title": "Rollback bestätigen", + "descriptionWithTarget": "Lokale Änderungen für {kind} \"{name}\" zurücksetzen?", + "descriptionFallback": "Lokale Änderungen zurücksetzen?", + "kindDirectory": "Verzeichnis", + "kindFile": "Datei" + }, + "deleteConfirm": { + "title": "Löschen bestätigen", + "descriptionWithTarget": "{kind} \"{name}\" löschen? Diese Aktion kann nicht rückgängig gemacht werden.", + "descriptionFallback": "Diese Aktion kann nicht rückgängig gemacht werden.", + "kindDirectory": "Verzeichnis", + "kindFile": "Datei" + }, + "quickCommit": { + "placeholder": "Commit-Nachricht (Enter zum Committen)" + } + }, + "tabContext": { + "loadingConversation": "Wird geladen...", + "untitledConversation": "Unbenannte Konversation", + "newConversation": "Neue Konversation" + }, + "fileTreeTab": { + "workspace": "Arbeitsbereich", + "retry": "Erneut versuchen", + "git": "Git", + "openInFileManager": "Im Dateimanager öffnen", + "openInFinder": "In Finder öffnen", + "openInExplorer": "In Explorer öffnen", + "attachToCurrentSession": "Zur Sitzung hinzufügen", + "compareWithBranch": "Mit Branch vergleichen...", + "reloadFromDisk": "Von Datenträger neu laden", + "new": "Neu", + "newFile": "Datei", + "newDirectory": "Verzeichnis", + "openIn": "Öffnen in", + "openInTerminal": "Im Terminal öffnen", + "linkedFolder": "Verknüpfter Ordner", + "copyPath": "Pfad kopieren", + "upload": "Dateien/Ordner hochladen", + "download": "Datei herunterladen", + "downloadAsZip": "Als ZIP herunterladen", + "actions": { + "select": "Auswählen", + "unselect": "Auswahl aufheben", + "commitCode": "Code committen", + "rollback": "Zurücksetzen", + "addToVcs": "Zu VCS hinzufügen" + }, + "aria": { + "selectPath": "{action}: {path}" + }, + "toasts": { + "openDirectoryFailed": "Verzeichnis konnte nicht geöffnet werden", + "openBuiltinTerminalFailed": "Integriertes Terminal konnte nicht geöffnet werden", + "openCommitWindowFailed": "Commit-Fenster konnte nicht geöffnet werden", + "noAddableFilesInDir": "Keine geänderten Dateien in diesem Verzeichnis können zu VCS hinzugefügt werden", + "noRollbackFilesInDir": "Keine geänderten Dateien in diesem Verzeichnis können zurückgesetzt werden", + "addedToVcs": "{name} zu VCS hinzugefügt", + "addToVcsFailed": "Hinzufügen zu VCS fehlgeschlagen", + "loadBranchesFailed": "Branches konnten nicht geladen werden", + "renameFailed": "Umbenennen fehlgeschlagen", + "moveFailed": "Verschieben fehlgeschlagen", + "deleteFailed": "Löschen fehlgeschlagen", + "rolledBack": "{name} zurückgesetzt", + "rollbackFailed": "Zurücksetzen fehlgeschlagen", + "addedFilesToVcs": "{count, plural, one {# Datei zu VCS hinzugefügt} other {# Dateien zu VCS hinzugefügt}}", + "rolledBackFiles": "{count, plural, one {# Datei zurückgesetzt} other {# Dateien zurückgesetzt}}", + "savedAsCopy": "Als Kopie gespeichert", + "saveCopyFailed": "Speichern als Kopie fehlgeschlagen", + "watchStartFailed": "Dateiwatch konnte nicht gestartet werden", + "createFailed": "Erstellen fehlgeschlagen", + "downloadFailed": "Herunterladen von {name} fehlgeschlagen", + "downloadSaved": "{name} heruntergeladen", + "pathCopied": "Pfad kopiert", + "copyPathFailed": "Pfad konnte nicht kopiert werden" + }, + "createDialog": { + "newFile": "Neue Datei", + "newDirectory": "Neues Verzeichnis", + "description": "Geben Sie einen Namen für das neue {kind} ein.", + "placeholderFile": "file-name.ext", + "placeholderDirectory": "folder-name" + }, + "renameDialog": { + "renameDirectory": "Verzeichnis umbenennen", + "renameFile": "Datei umbenennen", + "description": "Geben Sie einen neuen Namen ein (nur Name, kein Pfad).", + "placeholderDirectory": "neuer-ordnername", + "placeholderFile": "neuer-dateiname.ext" + }, + "uploadDialog": { + "title": "In den Arbeitsbereich hochladen", + "description": "Passe das Ziel bei Bedarf an und füge Dateien oder Ordner hinzu.", + "workspaceRoot": "Arbeitsbereich-Stammverzeichnis", + "targetPathLabel": "Hochladen nach", + "targetPathHint": "Aufgelöster Pfad: {path}", + "dropHint": "Dateien oder Ordner hier ablegen oder die Schaltflächen unten verwenden", + "dropHintActive": "Loslassen, um zur Warteschlange hinzuzufügen", + "selectFiles": "Dateien auswählen", + "selectFolder": "Ordner auswählen", + "startUpload": "Upload starten", + "clearQueue": "Erledigte entfernen", + "removeItem": "Aus der Warteschlange entfernen", + "retry": "Wiederholen", + "dropZoneAria": "Dateien hier ablegen oder aktivieren zum Durchsuchen", + "folderEmpty": "Keine Dateien im abgelegten Ordner gefunden", + "summary": "Gesamt: {total} · Erfolgreich: {succeeded} · Fehlgeschlagen: {failed}", + "status": { + "pending": "Wartet", + "uploading": "Wird hochgeladen", + "success": "Fertig", + "error": "Fehlgeschlagen", + "cancelled": "Abgebrochen" + } + }, + "directoryDialog": { + "descriptionAdd": "Wählen Sie Dateien im Verzeichnis {path} aus, um sie zu VCS hinzuzufügen.", + "descriptionRollback": "Wählen Sie Dateien im Verzeichnis {path} aus, um sie zurückzusetzen.", + "descriptionFallback": "Wählen Sie Dateien aus, um fortzufahren.", + "selectionCount": "{selected} / {total} Dateien ausgewählt", + "selectAll": "Alle auswählen", + "unselectAll": "Auswahl aufheben", + "loadingCandidates": "Verzeichnisänderungen werden geladen...", + "noOperableFiles": "Keine bearbeitbaren Dateien" + }, + "compareDialog": { + "title": "Mit Branch vergleichen", + "descriptionWithTarget": "Wählen Sie einen Branch und vergleichen Sie mit {kind} {path}", + "descriptionFallback": "Wählen Sie einen Branch zum Vergleichen.", + "kindDirectory": "Verzeichnis", + "kindFile": "Datei", + "filterPlaceholder": "Branches filtern, z. B. main / origin/main", + "singleClickHint": "Klicken Sie auf einen Branch, um direkt zu vergleichen", + "loadingBranches": "Branches werden geladen...", + "recentBranches": "Letzte Branches ({count})", + "noCurrentBranch": "Kein aktueller Branch", + "localBranches": "Lokale Branches ({count})", + "remoteBranches": "Remote-Branches ({count})", + "noMatchingBranches": "Keine passenden Branches" + }, + "externalConflictDialog": { + "title": "Externe Dateiänderungen erkannt", + "descriptionWithPath": "Datei {path} wurde auf dem Datenträger geändert, und aktuelle Bearbeitungen sind nicht gespeichert.", + "descriptionFallback": "Aktuelle Datei wurde auf dem Datenträger geändert, und aktuelle Bearbeitungen sind nicht gespeichert.", + "compare": "Vergleichen", + "savingCopy": "Kopie wird gespeichert...", + "saveAsCopy": "Als Kopie speichern", + "reload": "Neu laden" + }, + "deleteConfirm": { + "title": "Löschen bestätigen", + "descriptionWithTarget": "{kind} \"{name}\" löschen? Diese Aktion kann nicht rückgängig gemacht werden.", + "descriptionFallback": "Diese Aktion kann nicht rückgängig gemacht werden.", + "kindDirectory": "Verzeichnis", + "kindFile": "Datei" + }, + "rollbackConfirm": { + "title": "Zurücksetzen bestätigen", + "descriptionWithTarget": "Lokale Änderungen für Datei \"{name}\" zurücksetzen?", + "descriptionFallback": "Lokale Änderungen für diese Datei zurücksetzen?" + }, + "terminalTitle": "Konsole · {name}" + }, + "commandDropdown": { + "loading": "Wird geladen...", + "addCommand": "Befehl hinzufügen", + "manageCommands": "Befehle verwalten...", + "runCommandTitle": "Ausführen: {command}", + "stopCommandTitle": "Stoppen: {command}", + "manageDialog": { + "title": "Befehle verwalten", + "empty": "Noch keine Befehle", + "noResults": "Keine passenden Befehle", + "searchPlaceholder": "Befehle suchen", + "newCommand": "Neuer Befehl", + "nameLabel": "Bezeichnung", + "commandLabel": "Befehl", + "dragSort": "Zum Sortieren ziehen", + "dragSortCommand": "{name} zum Sortieren ziehen", + "orderFailed": "Befehlsreihenfolge konnte nicht gespeichert werden", + "loadFailed": "Befehle konnten nicht geladen werden", + "saveFailed": "Befehl konnte nicht gespeichert werden", + "deleteFailed": "Befehl konnte nicht gelöscht werden", + "confirmDelete": { + "title": "Befehl löschen?", + "message": "Dadurch wird \"{name}\" entfernt. Diese Aktion kann nicht rückgängig gemacht werden." + } + } + }, + "workspaceContext": { + "confirmCloseDirtyTab": "„{title}“ ohne Speichern schließen?", + "confirmCloseOtherDirtyTabs": "Andere Tabs mit ungespeicherten Änderungen schließen?", + "confirmCloseAllDirtyTabs": "Alle Tabs mit ungespeicherten Änderungen schließen?", + "unableLoadContent": "Inhalt konnte nicht geladen werden.\n\n{message}", + "previewRequestTimedOut": "Vorschauanfrage hat das Zeitlimit überschritten", + "diffRequestTimedOut": "Diff-Anfrage hat das Zeitlimit überschritten", + "branchCompareRequestTimedOut": "Branch-Vergleichsanfrage hat das Zeitlimit überschritten", + "commitDiffRequestTimedOut": "Commit-Diff-Anfrage hat das Zeitlimit überschritten", + "saveRequestTimedOut": "Speicheranfrage hat das Zeitlimit überschritten", + "reloadRequestTimedOut": "Neuladeanfrage hat das Zeitlimit überschritten", + "noChanges": "Keine Änderungen.", + "noDiffOutput": "Keine Diff-Ausgabe.", + "diffTitleWorkspace": "Diff · Arbeitsbereich", + "diffDescriptionWorkingTree": "Working Tree (HEAD)", + "diffTitleFile": "Unterschied · {name}", + "compareTitleFile": "Vergleich · {name}", + "compareTitleBranch": "Vergleich · {branch}", + "compareDescriptionPath": "{path} · vergleichen mit {branch}", + "compareDescriptionBranch": "vergleichen mit {branch}", + "diffTitleCommitFile": "Unterschied · {name} @ {hash}", + "diffTitleCommit": "Unterschied · {hash}", + "diffDescriptionCommitPath": "{path} · Commit {commit}", + "diffDescriptionCommit": "Commit {commit}", + "diffTitleConflictFile": "Konflikt · {name}", + "diffDescriptionConflict": "{path} · Disk vs ungespeichert" + }, + "chat": { + "acpConnections": { + "actions": { + "openAgentsSettings": "Agenten-Einstellungen öffnen", + "retry": "Erneut versuchen" + }, + "agentsSetupHint": "Öffnen Sie Einstellungen > Agenten, um die Installation zu verwalten.", + "withSetupHint": "{message}\n{hint}", + "blocked": { + "missingConfig": "Aktuelle Agenten-Konfiguration kann nicht gelesen werden.", + "disabled": "{agent} ist in den Agenten-Einstellungen deaktiviert. Aktivieren Sie ihn vor dem Verbinden.", + "unavailable": "{agent} ist auf der aktuellen Plattform nicht verfügbar.", + "sdkMissing": "{agent} SDK ist nicht installiert", + "adapterMissing": "Der ACP-Adapter von {agent} ist nicht installiert" + }, + "backendErrors": { + "initializeTimeout": "Der Verbindungs-Handshake von {agent} hat nach 60 Sekunden das Zeitlimit überschritten. Öffnen Sie die Einstellungen, um Agenten- und Netzwerkkonfiguration zu prüfen.", + "mcpRejectedByAgent": "{agent} hat die Sitzung abgelehnt, während codegs MCP-Begleitprozess angehängt war: {message} Falls dieser Agent MCP nicht unterstützt, deaktivieren Sie „MCP-Unterstützung“ in den Einstellungen und verbinden Sie erneut.", + "processExited": "{agent}-Prozess wurde unerwartet beendet.", + "spawnFailed": "{agent} konnte nicht gestartet werden: {message}", + "downloadFailed": "{agent}-Download fehlgeschlagen: {message}", + "sessionLoadResourceNotFound": "{agent}-Sitzung konnte nicht geladen werden. Neu laden, um es erneut zu versuchen, oder eine neue Konversation starten.", + "sessionLoadUnavailable": "{agent} konnte diese Sitzung nicht wiederherstellen – sie wurde möglicherweise beendet oder der Agent wurde gestoppt. Neu laden, um es erneut zu versuchen, oder eine neue Konversation starten.", + "turnFailedRefusal": "{agent} hat die Fortsetzung dieser Runde abgelehnt. Häufig deutet das auf einen Backend- oder Gateway-Fehler hin. Bitte prüfen Sie die Agent-Logs.", + "turnFailedMaxTokens": "{agent} hat das Token-Limit für diese Runde erreicht.", + "turnFailedMaxTurnRequests": "{agent} hat die maximale Anzahl zulässiger Anfragen für diese Runde erreicht.", + "turnFailedUnknown": "{agent} hat die Runde mit einem unbekannten Stoppgrund beendet.", + "grokModelSwitchIncompatibleAgent": "{agent} kann in einer bestehenden Unterhaltung nicht zu diesem Modell wechseln. Starte eine neue Sitzung, um es zu verwenden.", + "turnFailedEmpty": "{agent} hat die Runde ohne jegliche Antwort beendet.", + "turnFailedEmptyProtocol": "{agent} hat eine Ausgabe erzeugt, die codeg nicht auswerten konnte — die Agent-Version passt möglicherweise nicht zum Protokoll.", + "turnFailedEmptyMetadata": "{agent} hat in dieser Runde nur Statusaktualisierungen gesendet (Plan / Modus / Verbrauch) und keine Antwort.", + "detailsInAlerts": "Öffnen Sie die Warnungen in der Statusleiste und klappen Sie die Details auf, um die Ausgabe des Agents zu sehen." + }, + "unableReadAgentConfig": "Agenten-Konfiguration kann nicht gelesen werden: {message}", + "connectFailedTitle": "{agent} Verbindung fehlgeschlagen", + "toolFallbackTitle": "Werkzeug", + "eventErrorTitle": "Agentenfehler", + "notificationTurnComplete": "{agent} hat die Antwort abgeschlossen", + "notificationError": "{agent} Fehler: {message}", + "claudeApiRetry": { + "fallbackError": "authentication_failed", + "retryingWithMax": "erneuter Versuch {attempt}/{max}", + "retryingAttempt": "erneuter Versuch {attempt}", + "retrying": "erneuter Versuch", + "nextRetryIn": "nächster in {seconds}s", + "line": "{error}{status} · {retry}", + "lineWithDelay": "{error}{status} · {retry}, {delay}", + "httpStatus": " (HTTP {status})" + }, + "configOptionAdjusted": "{agent} hat {option} auf {actual} statt {requested} gesetzt" + }, + "connectionLifecycle": { + "tasks": { + "connectingTitle": "Verbinde mit {agent}", + "connectingDescription": "Verbindung wird hergestellt", + "loadingSelectorsTitle": "{agent}-Selektoren werden geladen", + "loadingSelectorsDescription": "Modus- und Sitzungsoptionen werden abgerufen", + "initSessionTitle": "Initializing {agent} session", + "initSessionDescription": "Creating session and loading configuration" + }, + "errors": { + "connectionFailed": "Verbindung fehlgeschlagen", + "sendPromptFailed": "Nachricht konnte nicht gesendet werden: {error}" + } + }, + "shared": { + "attachedResources": "Angehängte Ressourcen", + "toolCallFailed": "Tool-Aufruf fehlgeschlagen" + }, + "messageThread": { + "emptyTitle": "Noch keine Nachrichten", + "emptyDescription": "Starten Sie eine Unterhaltung, um hier Nachrichten zu sehen" + }, + "chatInput": { + "connecting": "Verbinden...", + "agentResponding": "{agent} antwortet...", + "sendMessage": "Nachricht senden..." + }, + "messageInput": { + "askAnything": "Fragen Sie alles...", + "removeAttachmentAria": "{name} entfernen", + "attachFiles": "Dateien anhängen", + "addActions": "Hinzufügen", + "quickMessages": "Schnellnachrichten", + "quickMessagesEmpty": "Noch keine Schnellnachrichten", + "quickMessagesLoading": "Wird geladen...", + "pasteAsPlainText": "Als reinen Text einfügen", + "cut": "Ausschneiden", + "copy": "Kopieren", + "selectAll": "Alles auswählen", + "pasteUnavailable": "Zwischenablage konnte nicht gelesen werden. Mit Strg/⌘V einfügen.", + "clipboardWriteFailed": "Schreiben in die Zwischenablage fehlgeschlagen. Bitte das Tastenkürzel verwenden.", + "quickMessageUntitled": "Ohne Titel", + "liveFeedback": "Live-Feedback", + "liveFeedbackDisabledHint": "Verfügbar, während der Agent arbeitet", + "dropFilesToAttach": "Dateien zum Anhängen ablegen", + "loadingSettings": "Einstellungen werden geladen...", + "loadingMode": "Modus wird geladen...", + "modeLabel": "Modus", + "toggleOn": "Ein", + "toggleOff": "Aus", + "agentSettings": "Agent-Einstellungen", + "searchModel": "Modelle suchen...", + "searchModelAria": "Modelle suchen", + "modelListLabel": "Modelle", + "noModels": "Keine Modelle gefunden", + "cancel": "Abbrechen", + "send": "Senden", + "forkAndSend": "Fork & Senden", + "queueMessage": "In Warteschlange stellen", + "steerIntoTurn": "In laufenden Turn einfügen", + "steerQueuedInstead": "Stattdessen in die Warteschlange gestellt – wird mit dem nächsten Turn gesendet.", + "steerFailed": "Konnte nicht in den laufenden Turn eingefügt werden", + "steerAttachmentsUnsupported": "Nur Text – Entwürfe mit Anhängen laufen über die Warteschlange.", + "slashCommands": "Slash-Befehle", + "slashSearchPlaceholder": "Befehle suchen...", + "slashSearchEmpty": "Keine passenden Befehle", + "experts": "Experten", + "office": "Büroarbeit", + "research": "Forschung", + "attachLocalUpload": "Lokale Datei hochladen", + "attachServerFile": "Serverdatei auswählen", + "attachUploadTooLarge": "{names} überschreitet das Upload-Limit von {limit}MB und wurde übersprungen.", + "attachUploadFailed": "Upload fehlgeschlagen: {names}.", + "attachUploadNotAFile": "{names} ist keine reguläre Datei (Verzeichnis oder Spezialdatei) und wurde übersprungen.", + "attachUploadQuotaExceeded": "Auf dem Server ist kein Upload-Speicher mehr verfügbar; {names} konnte nicht hochgeladen werden.", + "attachUploadInProgress": "Bilder werden noch hochgeladen – versuche es gleich noch einmal.", + "mentionEmpty": "Keine Treffer", + "mentionLoading": "Suche läuft…", + "mentionListLabel": "Erwähnungen", + "mentionMore": "Weitere Ergebnisse – tippe weiter, um zu filtern", + "mentionCount": "{count, plural, one {# Ergebnis} other {# Ergebnisse}}", + "mentionGroupFile": "Dateien", + "mentionGroupAgent": "Agenten", + "mentionGroupSession": "Sitzungen", + "mentionGroupCommit": "Commits", + "mentionGroupSkill": "Fähigkeiten" + }, + "messageQueue": { + "addToQueue": "Zur Warteschlange", + "saveEdit": "Speichern", + "cancelEdit": "Bearbeitung abbrechen", + "editItem": "Bearbeiten", + "deleteItem": "Entfernen" + }, + "welcomeInputPanel": { + "agentsSettingsPath": "Einstellungen > Agenten", + "autoConnectFallback": "Klicken Sie, um {path} zu öffnen und die Installation zu verwalten.", + "autoConnectAppend": "{message}. Klicken Sie, um {path} zu öffnen und die Installation zu verwalten.", + "enableAgentFirstPlaceholder": "Aktivieren Sie mindestens einen Agenten, bevor Sie eine Sitzung starten...", + "prepareSessionFailed": "Die Chat-Sitzung konnte nicht vorbereitet werden. Bitte versuche es erneut.", + "createConversationFailed": "Die Konversation konnte nicht erstellt werden. Bitte versuche es erneut.", + "askAnythingPlaceholder": "Fragen Sie alles...", + "agentNotInstalled": "{agent} ist nicht installiert · in den Agents-Einstellungen installieren", + "agentAdapterNotInstalled": "Der ACP-Adapter von {agent} ist nicht installiert (unabhängig von deiner eigenen CLI) · in den Agents-Einstellungen installieren" + }, + "welcomePanel": { + "greeting": "Was möchtest du heute machen?", + "tips": { + "tileTabs": "Klicke mit der rechten Maustaste auf einen Konversations-Tab und wähle Kachelansicht, um mehrere Sitzungen nebeneinander zu sehen.", + "pinTab": "Doppelklicke auf einen Konversations-Tab, um ihn anzuheften – so wird er nicht von einer neuen Sitzung automatisch ersetzt.", + "shortcutsNewSearch": "{newConversation} öffnet eine neue Konversation, {searchConversations} durchsucht den Verlauf.", + "slashAtMention": "Tippe / im Eingabefeld für Slash-Befehle oder @, um eine Datei aus dem Projekt zu referenzieren.", + "pasteDropFiles": "Füge einen Screenshot ein oder ziehe eine Datei direkt ins Eingabefeld, um sie anzuhängen.", + "queueMessage": "Während der Agent antwortet, kannst du weitertippen – deine nächste Nachricht wird in die Warteschlange gestellt und automatisch gesendet.", + "draftAutoSave": "Nicht gesendete Entwürfe werden pro Konversation automatisch gespeichert und beim Zurückkehren wiederhergestellt.", + "forkSend": "Im Dropdown der Senden-Schaltfläche gibt es Verzweigen und senden – verzweige vom aktuellen Punkt in einen neuen Tab.", + "exportConversation": "Klicke mit der rechten Maustaste in die Konversation, um sie als Markdown, HTML oder Bild zu exportieren.", + "chatChannels": "Verbinde Telegram / Lark / WeChat unter Einstellungen → Chat-Kanäle, um vom Handy aus weiterzuarbeiten.", + "shortcutsAuxPanel": "{toggleAuxPanel} blendet das rechte Panel ein – mit den geänderten Dateien und Git-Änderungen dieser Sitzung.", + "shortcutsTerminalSidebar": "{toggleTerminal} öffnet das eingebaute Terminal, {toggleSidebar} schaltet die Seitenleiste um.", + "customShortcuts": "Alle Tastenkürzel lassen sich unter Einstellungen → Tastenkürzel frei belegen.", + "webService": "Aktiviere Einstellungen → Webdienst, damit Teammitglieder dasselbe codeg im Browser nutzen können.", + "fusionMode": "Öffne eine Datei oder ein Diff, um es automatisch neben der Konversation zu sehen.", + "quickMessages": "Klicke auf die +-Schaltfläche neben der Eingabe und wähle Schnellnachrichten, um ein gespeichertes Snippet einzufügen (verwaltbar unter Einstellungen → Schnellnachrichten).", + "experts": "Die +-Schaltfläche hat ein Menü Expertenfähigkeiten – lade Rollen wie Debugging oder Planung mit einem Klick.", + "taskBoard": "To-dos führen eine Aufgabe von Anfang bis Ende aus: Der Agent arbeitet in einem eigenen Worktree, du prüfst das Diff und mergest.", + "automations": "Automatisierungen führen einen gespeicherten Prompt nach Zeitplan aus – etwa ein nächtliches Review – und jeder Lauf kann einen eigenen Worktree bekommen.", + "tokenUsage": "Klicke auf die Konversationszahl in der Statusleiste, um den Token-Verbrauch zu öffnen – aufgeschlüsselt nach Tag, Agent, Modell und Ordner.", + "mentionTargets": "@ holt mehr als Dateien: Erwähne einen anderen Agenten, um eine Teilaufgabe abzugeben, oder verweise auf eine frühere Sitzung, einen Commit oder einen Skill.", + "splitGroups": "Rechtsklick auf einen Tab, dann Nach rechts teilen oder Nach unten teilen – so bleiben zwei Konversationen in eigenen Bereichen offen.", + "worktrees": "Öffne die Branch-Schaltfläche und wähle Neuer Worktree, damit mehrere Agenten dasselbe Repository bearbeiten, ohne sich gegenseitig die Dateien zu überschreiben.", + "importSessions": "Schon Sitzungen im Terminal gelaufen? Im Menü eines Ordners holt Lokale Sitzungen importieren diesen Verlauf nach codeg.", + "subSessions": "Delegiert ein Agent, erscheint die Untersitzung in der Seitenleiste verschachtelt darunter – klapp die Zeile auf, um jeder einzeln zu folgen.", + "liveFeedback": "Live-Feedback im +-Menü schiebt eine Notiz in den Zug, den der Agent gerade ausführt – ohne ihn zu unterbrechen.", + "skillPacks": "Einstellungen → Skill-Pakete bündelt Coding-Experten, wissenschaftliche Recherche und Office-Skills – pro Agent aktivierbar.", + "modelProviders": "Einstellungen → Modellanbieter nimmt deinen eigenen API-Key oder Endpunkt entgegen; das Modell wählst du danach direkt im Eingabefeld.", + "workspaceBackground": "Einstellungen → Darstellung setzt ein Hintergrundbild für den Arbeitsbereich, die Panel-Deckkraft und die Schriftarten der App." + }, + "quickActions": { + "excel": "Excel-Arbeitsmappe", + "excelDesc": "Datentabellen, Formeln & Diagramme", + "word": "Word-Dokument", + "wordDesc": "Berichte, Briefe & Memos", + "ppt": "Präsentation", + "pptDesc": "Folien mit professionellem Design", + "pitchDeck": "Pitch Deck", + "pitchDeckDesc": "Investoren-Deck mit Kennzahlen", + "morph": "Morph-Animation", + "morphDesc": "Filmreife Folienübergänge", + "morph3d": "3D-Morph", + "morph3dDesc": "3D-Modelle mit Kamerafahrten", + "academic": "Wissenschaftliche Arbeit", + "academicDesc": "Forschung mit Zitaten & Struktur", + "financial": "Finanzmodell", + "financialDesc": "Abschlüsse, DCF & Prognosen", + "dashboard": "Daten-Dashboard", + "dashboardDesc": "KPIs & Analysen aus deinen Daten", + "prompts": { + "excel": "Erstelle eine Excel-Arbeitsmappe mit den folgenden Anforderungen:\n\n[beschreibe hier deine Daten, Tabellen, Formeln und Diagramme]", + "word": "Erstelle ein Word-Dokument mit den folgenden Anforderungen:\n\n[beschreibe hier Inhalt, Struktur und Formatierung des Dokuments]", + "ppt": "Erstelle eine PowerPoint-Präsentation mit den folgenden Anforderungen:\n\n[beschreibe hier deine Folien, Inhalte und das Design]", + "pitchDeck": "Erstelle ein Investoren-Pitch-Deck mit den folgenden Anforderungen:\n\n[beschreibe hier dein Unternehmen, die Finanzierungsrunde und die wichtigsten Kennzahlen]", + "morph": "Erstelle eine Präsentation mit Morph-Übergangsanimationen:\n\n[beschreibe hier das Thema der Präsentation und die gewünschten visuellen Effekte]", + "morph3d": "Erstelle eine 3D-Morph-Präsentation mit GLB-Modellen und Kamerafahrten:\n\n[beschreibe hier dein Thema und das visuelle 3D-Konzept]", + "academic": "Schreibe eine wissenschaftliche Arbeit in Word mit den folgenden Anforderungen:\n\n[beschreibe hier dein Forschungsthema, die Methodik und die wichtigsten Ergebnisse]", + "financial": "Erstelle ein Finanzmodell in Excel mit den folgenden Anforderungen:\n\n[beschreibe hier deine Finanzabschlüsse, Prognosen und Analysen]", + "dashboard": "Erstelle ein Daten-Dashboard in Excel mit den folgenden Anforderungen:\n\n[beschreibe hier deine Datenquelle, KPIs und Diagramme]", + "scientific-brainstorming": "Hilf mir beim Brainstorming von Forschungsrichtungen — erkunde interdisziplinäre Verbindungen, hinterfrage Annahmen und finde vielversprechende Lücken. Mein Themenbereich: ", + "hypothesis-generation": "Hilf mir, diese Beobachtungen in prüfbare Hypothesen zu überführen — mit klaren Vorhersagen, plausiblen Mechanismen und Experimenten. Meine Beobachtungen: ", + "experimental-design": "Hilf mir, vor der Datenerhebung ein rigoroses Experiment zu planen — Design, Randomisierung, Kontrollen und wie man Confounding vermeidet. Was ich untersuchen möchte: ", + "statistical-power": "Hilf mir, die benötigte Stichprobengröße zu bestimmen — führe mich durch eine Poweranalyse (Effektstärke, Alpha, Power) für mein Design. Details: ", + "statistical-analysis": "Hilf mir, diese Daten korrekt zu analysieren — den richtigen Test wählen, Annahmen prüfen, Effektstärken berichten und alles aufschreiben. Meine Daten und Frage: ", + "exploratory-data-analysis": "Führe eine explorative Analyse meiner Datendatei durch — fasse Struktur, Qualität und auffällige Muster zusammen und schlage nächste Schritte vor. Die Datei ist: ", + "scientific-visualization": "Hilf mir, eine publikationsreife Abbildung zu erstellen — klares Layout, ehrliche Fehlerbalken, eine farbenblindensichere Palette und Journal-Formatierung. Was ich zeigen möchte: ", + "scientific-critical-thinking": "Hilf mir, diese Studie oder Behauptung kritisch zu bewerten — beurteile die Evidenzqualität, erkenne Verzerrungen und Confounder und wäge die Schlussfolgerungen ab. Hier ist sie: ", + "paper-lookup": "Hilf mir, relevante Artikel und Open-Access-Volltexte in wissenschaftlichen Datenbanken zu finden, mit wiederverwendbaren Zitaten. Ich suche: " + }, + "paper-lookup": "Publikationssuche", + "paper-lookupDesc": "10 wissenschaftliche APIs (PubMed, arXiv, OpenAlex, Crossref…) nach Artikeln, Zitationen und Open-Access-Volltext durchsuchen.", + "scientific-critical-thinking": "Kritisches Denken", + "scientific-critical-thinkingDesc": "Wissenschaftliche Aussagen und Evidenzqualität beurteilen — Verzerrungen und Confounder erkennen, GRADE anwenden.", + "scientific-visualization": "Wissenschaftliche Visualisierung", + "scientific-visualizationDesc": "Publikationsreife Abbildungen — Mehrfeld-Layouts, Signifikanz-Annotationen und journalspezifische Formate.", + "exploratory-data-analysis": "Explorative Datenanalyse", + "exploratory-data-analysisDesc": "Automatisierte Exploration wissenschaftlicher Datendateien in über 200 Formaten mit Qualitätsmetriken und Berichten.", + "statistical-analysis": "Statistische Analyse", + "statistical-analysisDesc": "Geführte statistische Analyse — Testauswahl, Annahmenprüfung, Effektstärken und Bericht im APA-Stil.", + "statistical-power": "Teststärke", + "statistical-powerDesc": "Stichprobengröße und Teststärke — benötigte Fallzahl, minimal nachweisbare Effekte und Powerkurven.", + "experimental-design": "Versuchsplanung", + "experimental-designDesc": "Rigorose Studien vor der Datenerhebung planen — Randomisierung, Blockbildung, Kontrollen und faktorielle/DOE-Designs.", + "hypothesis-generation": "Hypothesengenerierung", + "hypothesis-generationDesc": "Beobachtungen in prüfbare Hypothesen mit Vorhersagen, Mechanismen und Experimenten überführen.", + "scientific-brainstorming": "Wissenschaftliches Brainstorming", + "scientific-brainstormingDesc": "Offene Forschungsideen — interdisziplinäre Verbindungen erkunden, Annahmen hinterfragen, Forschungslücken finden.", + "tabs": { + "office": "Büroarbeit", + "coding": "Code-Entwicklung", + "research": "Forschung" + }, + "coding": { + "brainstormingDesc": "Absicht & Anforderungen vor dem Bauen klären", + "debuggingDesc": "Erst die Ursache finden, dann Fixes vorschlagen", + "writingSkillsDesc": "Wiederverwendbare Skills erstellen, bearbeiten & prüfen" + }, + "notEnabled": { + "title": "Skill „{skill}“ ist für {agent} noch nicht aktiviert", + "description": "Aktiviere ihn in den Einstellungen, um ihn hier zu nutzen.", + "action": "Aktivieren", + "hint": "Skill nicht aktiviert" + }, + "scrollPrev": "Vorherige Skills anzeigen", + "scrollNext": "Weitere Skills anzeigen" + } + }, + "agentSelector": { + "noEnabledAgents": "Keine aktivierten Agenten", + "openAgentsSettings": "Agenten-Einstellungen öffnen", + "notInstalled": "Nicht installiert", + "moreAgents": "Weitere Agenten ({count})" + }, + "subAgentOverlay": { + "title": "Subagenten", + "collapsedSummary": "Subagenten {count}", + "collapseAria": "Subagenten einklappen" + }, + "agentPlanOverlay": { + "title": "Agentenplan", + "collapsePlanAria": "Plan einklappen", + "collapsedSummary": "Arbeitsplan {completed}/{total}", + "status": { + "completed": "Abgeschlossen", + "inProgress": "In Bearbeitung", + "pending": "Ausstehend", + "unknown": "Unbekannt" + }, + "priority": { + "high": "Hoch", + "medium": "Mittel", + "low": "Niedrig", + "unknown": "Unbekannt" + } + }, + "permissionDialog": { + "subtitle": "Agent fordert Berechtigung an, um diesen Zug fortzusetzen.", + "queuedCount": "+{count} wartend", + "kindFallbackTool": "Tool", + "command": "Befehl", + "cwd": "Arbeitsverzeichnis: {cwd}", + "filesSummary": "Dateien: {count}", + "moreFiles": "+{count} weitere Dateien", + "plan": "Arbeitsplan", + "allowedActions": "Erlaubte Aktionen", + "targetMode": "Zielmodus: {mode}", + "optionGrants": "Was jede Option gewährt", + "changeScopeSession": "Diese Sitzung", + "changeScopeProcess": "Dieser Lauf", + "changeScopeUser": "In Benutzereinstellungen gespeichert", + "changeScopeProject": "In Projekteinstellungen gespeichert", + "changeScopeProjectLocal": "In lokalen Projekteinstellungen gespeichert", + "changeScopePersistent": "Dauerhaft gespeichert" + }, + "questionDialog": { + "title": "Agent stellt eine Frage", + "placeholder": "Antwort eingeben...", + "send": "Senden" + }, + "messageBranch": { + "previousBranchAria": "Vorheriger Branch", + "nextBranchAria": "Nächster Branch", + "pageOf": "{current} von {total}" + }, + "terminal": { + "title": "Konsole", + "running": "Läuft" + }, + "reasoning": { + "thinking": "Denkt nach…", + "thoughtForFewSeconds": "Nachgedacht", + "thoughtForSeconds": "Nachgedacht" + }, + "linkSafety": { + "errorCannotOpen": "Lokale Datei kann nicht geöffnet werden", + "errorNoWorkspace": "Es ist kein Arbeitsbereichsordner aktiv.", + "errorFailedOpen": "Lokale Datei konnte nicht geöffnet werden", + "errorFailedLink": "Link konnte nicht geöffnet werden", + "errorUnsupportedLinkProtocol": "Dieses Linkprotokoll wird nicht unterstützt." + }, + "fileActions": { + "openInFinder": "In Finder öffnen", + "openInExplorer": "In Explorer öffnen", + "openInFileManager": "Im Dateimanager öffnen", + "copyRelativePath": "Relativen Pfad kopieren", + "copyAbsolutePath": "Absoluten Pfad kopieren", + "pathCopied": "Pfad kopiert", + "copyPathFailed": "Pfad konnte nicht kopiert werden", + "openFailed": "Lokale Datei konnte nicht geöffnet werden" + }, + "messageList": { + "attachedResources": "Angehängte Ressourcen", + "loading": "Lädt...", + "loadEarlier": "Frühere Nachrichten laden", + "loadingEarlier": "Frühere Nachrichten werden geladen…", + "error": "Fehler: {message}", + "errorTitle": "Sitzung konnte nicht geladen werden", + "errorActionReload": "Neu laden", + "errorActionNewSession": "Neue Konversation", + "emptyConversation": "Keine Nachrichten in dieser Unterhaltung.", + "systemMessage": "Systemnachricht", + "copyMessage": "Kopieren", + "copied": "Kopiert", + "downloadImage": "Bild herunterladen", + "downloadFailed": "Download fehlgeschlagen: {message}", + "imageGeneration": "Bildgenerierung", + "imageGenerationPending": "Bild wird generiert…", + "imageGenerationFailed": "Bildgenerierung fehlgeschlagen", + "model": "Modell", + "tokenStats": "Token-Nutzung", + "tokenInput": "Eingabe", + "tokenOutput": "Ausgabe", + "tokenCacheRead": "Cache-Lesen", + "tokenCacheWrite": "Cache-Schreiben", + "duration": "Dauer", + "completedAt": "Abgeschlossen um", + "jumpToPreviousUserMessage": "Zur Benutzernachricht springen", + "showMore": "Mehr anzeigen", + "showLess": "Weniger anzeigen" + }, + "liveTurnStats": { + "thinking": "Denkt nach...", + "streaming": "Übertragung", + "elapsedHours": "{value} Std", + "elapsedMinutes": "{value} Min", + "elapsedSeconds": "{value} Sek", + "outputSpeedAria": "Geschätzte Ausgabegeschwindigkeit", + "outputSpeedTooltip": "Geschätzte Ausgabegeschwindigkeit (Text + Denken)" + }, + "jsonTree": { + "viewRaw": "Rohes JSON anzeigen", + "viewTree": "Baum anzeigen", + "fields": "{count, plural, one {# Feld} other {# Felder}}", + "items": "{count, plural, one {# Eintrag} other {# Einträge}}" + }, + "tool": { + "parameters": "Parameter", + "error": "Fehler", + "result": "Ergebnis", + "status": { + "approvalRequested": "Warten auf Genehmigung", + "approvalResponded": "Beantwortet", + "inputAvailable": "Läuft", + "inputStreaming": "Ausstehend", + "outputAvailable": "Abgeschlossen", + "outputDenied": "Abgelehnt", + "outputError": "Fehler" + } + }, + "toolCallBlock": { + "tool": "Werkzeug", + "error": "Fehler", + "result": "Ergebnis" + }, + "delegation": { + "subAgentRunning": "Unteragent läuft…", + "noDetail": "No detail available yet.", + "unknownAgent": "Sub-Agent", + "openDetail": "Konversation anzeigen", + "detailTitle": "Unteragent-Konversation", + "detailDescription": "Schreibgeschützte Ansicht der delegierten Unteragent-Konversation.", + "waitForResult": "Warte auf das Ergebnis von Aufgabe {task}", + "waitForResultNoTask": "Warte auf das Aufgabenergebnis", + "cancelTask": "Aufgabe {task} wird abgebrochen", + "cancelTaskNoTask": "Aufgabe wird abgebrochen", + "resultPageOf": "{current} / {total}", + "prevResult": "Vorheriges Ergebnis", + "nextResult": "Nächstes Ergebnis", + "noResultText": "Kein Ergebnis bei dieser Prüfung.", + "status": { + "starting": "startet", + "running": "läuft", + "checked": "geprüft", + "waiting": "Genehmigung ausstehend", + "ok": "fertig", + "err": { + "default": "fehlgeschlagen", + "delegation_disabled": "deaktiviert", + "depth_limit": "Tiefenlimit", + "invalid_agent_type": "ungültiger Agent", + "spawn_failed": "Start fehlgeschlagen", + "send_failed": "Senden fehlgeschlagen", + "timeout": "Zeitüberschreitung", + "canceled": "abgebrochen", + "child_refusal": "Subagent verweigerte", + "child_max_tokens": "Subagent: Token-Limit", + "child_max_turn_requests": "Subagent: Anfragelimit", + "child_empty": "Subagent ohne Ausgabe", + "child_unknown": "Subagent: Fehler", + "unknown": "unbekannte Aufgabe" + } + } + }, + "contentParts": { + "showingTailOutput": "Zur besseren Performance wird während des Streamings nur die Endausgabe angezeigt.", + "result": "Ergebnis", + "unknown": "unbekannt", + "inputTruncated": "Eingabe wurde gekürzt — Diff ist möglicherweise unvollständig.", + "replaceAll": "ALLES ERSETZEN", + "filesCount": "Dateien: {count}", + "update": "aktualisieren", + "moreFiles": "+{count} weitere Dateien", + "timeoutMs": "Zeitlimit: {timeout}ms", + "backgroundTrue": "Hintergrund: true", + "scriptToolCalls": "{count, plural, one {# Tool-Aufruf} other {# Tool-Aufrufe}}", + "offset": "Versatz: {offset}", + "limit": "Grenze: {limit}", + "pages": "Seiten: {pages}", + "mode": "Modus: {mode}", + "cell": "Zelle: {cell}", + "shellSession": "Sitzung {id}", + "pathLabel": "Pfad:", + "globLabel": "Glob-Muster:", + "typeLabel": "Typ:", + "outputLabel": "Ausgabe:", + "caseInsensitive": "Groß-/Kleinschreibung ignorieren", + "multiline": "Mehrzeilig", + "promptLabel": "Eingabe", + "subjectLabel": "Betreff", + "taskLabel": "Aufgabe", + "nameLabel": "Bezeichnung:", + "agentPromptLabel": "Eingabe", + "agentModelLabel": "Modell", + "agentRunning": "Läuft...", + "agentLiveTranscript": "Live-Aktivität", + "agentProgressTools": "{count} Tool-Aufrufe", + "agentProgressTurns": "{count} Runden", + "agentProgressContext": "Kontext {pct}%", + "agentSessionAction": "Subagent-Sitzung ansehen", + "agentSessionTitle": "Subagent-Sitzung", + "agentSessionLoading": "Protokoll des Subagenten wird geladen…", + "agentSessionEmpty": "Der Subagent hat noch nichts geschrieben.", + "agentFallbackTitle": "Sub-Agent wird gestartet…", + "agentCodexLaunchOnly": "Gestartet. Codex meldet keinen weiteren Fortschritt dieses Sub-Agenten – sein Ergebnis trifft als Nachricht in dieser Unterhaltung ein.", + "agentStatsBash": "Befehle", + "agentStatsRead": "Dateien gelesen", + "agentStatsSearch": "Suchen", + "agentStatsEdit": "Bearbeitungen", + "agentStatsOther": "Sonstige", + "goal": { + "title": "Ziel:", + "titleWithStatus": "Ziel {status}", + "objective": "Ziel", + "statusLabel": "Status", + "tokensUsed": "Verwendete tokens", + "budget": "Budget", + "remaining": "Verbleibend", + "elapsed": "Verstrichen", + "tokens": "tokens", + "pause": "Pausieren", + "clear": "Löschen", + "status": { + "active": "aktiv", + "paused": "pausiert", + "blocked": "blockiert", + "usageLimited": "Nutzung begrenzt", + "budgetLimited": "Budget begrenzt", + "complete": "abgeschlossen", + "limited": "Limit erreicht" + } + }, + "field": { + "file": "Datei", + "notebook": "Notizbuch", + "command": "Befehl", + "old": "Alt", + "new": "Neu", + "pattern": "Muster", + "path": "Pfad", + "query": "Abfrage", + "url": "URL:", + "description": "Beschreibung", + "content": "Inhalt", + "source": "Quelle", + "prompt": "Eingabe", + "subject": "Betreff", + "taskId": "Aufgaben-ID", + "status": "Zustand", + "skill": "Skill", + "args": "Argumente", + "offset": "Versatz", + "limit": "Grenze", + "glob": "Glob-Muster", + "type": "Typ", + "output": "Ausgabe", + "replaceAll": "Alles ersetzen", + "language": "Sprache", + "timeout": "Zeitlimit", + "background": "Hintergrund", + "agentType": "Agent-Typ", + "library": "Bibliothek", + "libraryId": "Bibliotheks-ID" + }, + "title": { + "edit": "Bearbeiten", + "command": "Befehl", + "script": "Skript", + "waitCommand": "Warten {command}", + "waitCell": "Sitzung {id} abwarten", + "terminateCommand": "Beenden {command}", + "terminateCell": "Sitzung {id} beenden", + "stdinChars": "Eingabe {chars}", + "todoWrite": "TodoWrite (Aufgaben aktualisieren)", + "read": "Lesen", + "write": "Schreiben", + "notebookEdit": "NotebookEdit (Notizbuch bearbeiten)", + "editFiles": "Bearbeiten ({count} Dateien)", + "editWithTarget": "{target} bearbeiten", + "readWithTarget": "{target} lesen", + "writeWithTarget": "{target} schreiben", + "notebookEditWithTarget": "NotebookEdit ({target})", + "globWithPattern": "Glob-Muster {pattern}", + "listFilesWithPath": "Dateien auflisten {path}", + "grepWithPattern": "Grep-Muster {pattern}", + "taskCreateWithSubject": "Aufgabe erstellen: {subject}", + "taskUpdateWithStatus": "Aufgabe aktualisieren #{id} -> {status}", + "taskUpdate": "Aufgabe aktualisieren #{id}", + "webFetchWithUrl": "WebFetch ({url})", + "webSearchWithQuery": "Websuche: {query}", + "todosProgress": "Aufgaben ({done}/{total})", + "skillWithName": "Skill: {name}", + "genericWithContext": "{tool} ({context})" + }, + "search": { + "noMatches": "Keine Treffer", + "matchSummary": "{matches, plural, one {# Treffer} other {# Treffer}} in {files, plural, one {# Datei} other {# Dateien}}", + "fileSummary": "{files, plural, one {# Datei} other {# Dateien}}", + "moreResults": "{count, plural, one {# weiteres Ergebnis nicht angezeigt} other {# weitere Ergebnisse nicht angezeigt}}" + }, + "toolGroup": { + "search": "{count, plural, one {# Suche durchgeführt} other {# Suchen durchgeführt}}", + "command": "{count, plural, one {# Befehl ausgeführt} other {# Befehle ausgeführt}}", + "read": "{count, plural, one {Dateien # Mal gelesen} other {Dateien # Mal gelesen}}", + "memory": "{count, plural, one {# Erinnerung abgerufen} other {# Erinnerungen abgerufen}}", + "edit": "{count, plural, one {Dateien # Mal bearbeitet} other {Dateien # Mal bearbeitet}}", + "fetch": "{count, plural, one {# Ressource abgerufen} other {# Ressourcen abgerufen}}", + "think": "{count, plural, one {# Mal nachgedacht} other {# Mal nachgedacht}}", + "todo": "{count, plural, one {# Aufgabe aktualisiert} other {# Aufgaben aktualisiert}}", + "task": "{count, plural, one {# Aufgabe ausgeführt} other {# Aufgaben ausgeführt}}", + "other": "{count, plural, one {# Werkzeug verwendet} other {# Werkzeuge verwendet}}", + "errorSuffix": "{count, plural, one {# fehlgeschlagen} other {# fehlgeschlagen}}", + "joiner": " · " + }, + "planMode": { + "entered": "Planungsmodus gestartet", + "planLabel": "Plan", + "reviewApproved": "Plan genehmigt – wird umgesetzt", + "reviewKept": "Im Planmodus geblieben", + "reviewPending": "Warte auf Planentscheidung", + "submitted": "Plan eingereicht", + "switched": "Modus gewechselt" + }, + "backgroundTask": { + "title": "Hintergrundaufgabe", + "titleWithId": "Hintergrundaufgabe · {id}", + "running": "Läuft", + "completed": "Abgeschlossen", + "failed": "Fehlgeschlagen", + "stopped": "Gestoppt", + "exitCode": "Exit {code}", + "polledTimes": "{count}-mal abgefragt", + "runningInBackground": "Hintergrund", + "launchNote": "Läuft im Hintergrund · {id}" + }, + "codexScript": { + "outputMissing": "Codex hat die Skriptausgabe gekürzt und dabei das Trennzeichen dieses Befehls entfernt, sodass ihm keine Ausgabe zugeordnet werden konnte.", + "sharedWith": "Enthält auch die Ausgabe von {commands} – codex hat deren Trennzeichen abgeschnitten.", + "truncated": "gekürzt" + } + }, + "messageNav": { + "title": "Nachrichtennavigation", + "collapse": "Nachrichtennavigation ausblenden", + "collapsedSummary": "Nachrichten {count}", + "fileCount": "{count, plural, one {# Datei} other {# Dateien}}", + "remove": "Entfernen", + "noDiffDataAvailable": "Keine Diff-Daten verfügbar für {filePath}" + }, + "replyArtifacts": { + "title": "Geänderte Dateien", + "fileCount": "{count, plural, one {# Datei} other {# Dateien}}", + "newFilesTitle": "Neue Dateien", + "revealInFolder": "Im Dateimanager anzeigen", + "openFile": "{filePath} öffnen", + "openInEditor": "Im Editor öffnen", + "remove": "Entfernen", + "noDiffDataAvailable": "Keine Diff-Daten verfügbar für {filePath}" + }, + "askQuestion": { + "title": "Der Agent benötigt deine Auswahl", + "subtitle": "Antworten und absenden. Du kannst jederzeit überspringen.", + "recommended": "Empfohlen", + "other": "Andere", + "otherPlaceholder": "Antwort eingeben…", + "singleSelect": "Einfach", + "multiSelect": "Mehrfach", + "skip": "Überspringen", + "next": "Weiter", + "submit": "Senden", + "submitError": "Senden fehlgeschlagen. Bitte versuche es erneut." + }, + "planApproval": { + "title": "Der Agent hat einen Plan – bitte prüfen", + "emptyPlan": "Der Agent hat keinen Plan geschrieben. Genehmige, um zu starten, oder fordere Änderungen an.", + "approve": "Genehmigen & starten", + "requestChanges": "Änderungen anfordern", + "abandon": "Verwerfen", + "feedbackPlaceholder": "Was soll geändert werden?", + "sendChanges": "Senden", + "cancel": "Abbrechen", + "submitError": "Senden fehlgeschlagen. Bitte erneut versuchen." + }, + "feedbackCheckResult": { + "count": "{count, plural, =1 {1 Rückmeldung} other {# Rückmeldungen}}", + "expand": "Alle Rückmeldungen anzeigen", + "collapse": "Einklappen", + "errorTitle": "Feedback-Prüfung fehlgeschlagen" + }, + "askQuestionResult": { + "title": "Frage", + "answeredLabel": "Frage & Antwort:", + "awaiting": "Warten auf deine Antwort…", + "declined": "Du hast dies verworfen – der Agent hat nach eigenem Ermessen entschieden.", + "noSelection": "Keine Auswahl" + }, + "configStale": { + "agentConfigTitle": "Agent-Einstellungen aktualisiert", + "modelProviderTitle": "Modellanbieter aktualisiert", + "description": "Diese Sitzung verwendet weiterhin die bisherige Konfiguration. Zum Anwenden neu verbinden (der Gesprächsverlauf bleibt erhalten).", + "reconnect": "Zum Anwenden neu verbinden", + "reconnecting": "Wird neu verbunden…", + "reconnectDisabledDuringTurn": "Verfügbar, sobald die aktuelle Runde abgeschlossen ist", + "dismiss": "Schließen", + "reconnectFailed": "Sitzung konnte nicht neu verbunden werden", + "applied": "Neue Konfiguration angewendet" + }, + "piProjectTrust": { + "title": "Dieses Projekt enthält pi-Ressourcen", + "description": "pi lädt die .pi-Dateien des Repositorys nicht. Prüfe sie, um zu entscheiden.", + "descriptionExecutable": "Das Repository enthält pi-Erweiterungen, die beim Start Code ausführen. pi lädt sie nicht. Prüfe sie, bevor du entscheidest.", + "review": "Prüfen…", + "dismiss": "Ausblenden", + "dialogTitle": "Den pi-Ressourcen dieses Projekts vertrauen?", + "dialogDescription": "pi lädt die .pi-Dateien eines Repositorys nur, wenn du dem Ordner vertraust. Vertraue nur, wenn du dem Inhalt dieses Repositorys vertraust.", + "executionWarning": "Erweiterungen sind Code. Wenn du diesem Ordner vertraust, führt das Repository sie beim Start von pi mit deinen Rechten aus – noch bevor du eine Nachricht sendest.", + "scopeNote": "Die Entscheidung wird in der trust.json von pi für diesen Ordner gespeichert, gilt für alle darin enthaltenen Ordner und wird auch verwendet, wenn du pi selbst im Terminal startest. Du kannst sie später unter Einstellungen → Agenten → Pi ändern.", + "trust": "Projekt vertrauen", + "decline": "Nicht laden", + "disabledDuringTurn": "Verfügbar, sobald der aktuelle Zug beendet ist", + "trustedToast": "Projekt vertraut – neu verbunden, damit pi seine Ressourcen lädt", + "declinedToast": "Projektressourcen bleiben ungeladen", + "saveFailed": "Die Vertrauensentscheidung für das Projekt konnte nicht gespeichert werden", + "grantTitle": "Diesem Projekt wird bereits vertraut", + "grantDescription": "pi lädt die .pi-Dateien dieses Repositorys. Sieh dir an, was das erlaubt.", + "grantInheritedDescription": "Einem übergeordneten Ordner wird vertraut, daher lädt pi die .pi-Dateien dieses Repositorys. Sieh dir an, was das erlaubt.", + "grantDialogTitle": "Den pi-Ressourcen dieses Projekts wird vertraut", + "grantDialogDescription": "pi darf die .pi-Dateien dieses Repositorys laden. Frühere codeg-Versionen haben das beim Öffnen eines Ordners automatisch erteilt, du wurdest also womöglich nie gefragt.", + "grantExecutionWarning": "Erweiterungen sind Code. Das Repository führt sie beim Start von pi mit deinen Rechten aus, bevor du eine Nachricht sendest.", + "inheritedFrom": "Vertraut über", + "revoke": "Vertrauen widerrufen", + "keepTrusted": "Vertrauen behalten", + "revokedToast": "Vertrauen widerrufen – neu verbunden, damit pi die Projektressourcen nicht mehr lädt", + "trustedNoReconnect": "Projekt vertraut – gilt ab dem nächsten Start von pi", + "revokedNoReconnect": "Vertrauen widerrufen – gilt ab dem nächsten Start von pi" + }, + "collabAgent": { + "title": "Subagent", + "errorTitle": "Subagent-Aufgabe fehlgeschlagen", + "statesLabel": "Subagenten", + "statusRunning": "Läuft", + "statusCompleted": "Abgeschlossen", + "statusFailed": "Fehlgeschlagen", + "statusPending": "Wird gestartet", + "statusInterrupted": "Unterbrochen", + "statusClosed": "Geschlossen", + "statusNotFound": "Nicht gefunden", + "opSpawn": "Sub-Agent wird gestartet", + "opWait": "Sub-Agent-Ergebnis wird abgerufen", + "opClose": "Sub-Agent wird geschlossen", + "opResume": "Sub-Agent wird fortgesetzt" + }, + "contextCompaction": { + "compacting": "Kontext wird komprimiert…", + "compacted": "Kontext komprimiert", + "compactedTokens": "Kontext komprimiert · {before} → {after} Tokens", + "failed": "Kontextkomprimierung fehlgeschlagen" + }, + "sessionFailure": { + "category": { + "connection": "Verbindungsproblem", + "access": "Zugriffsproblem", + "limit": "Limit erreicht", + "request": "Anfrage abgelehnt", + "service": "Dienstproblem", + "unknown": "Sitzungsproblem" + }, + "action": { + "retry": "Erneut versuchen", + "login": "Anmelden", + "newSession": "Neue Sitzung" + }, + "recovered": "Wiederhergestellt", + "retryUnavailable": "Keine vorherige Nachricht zum erneuten Senden.", + "toggleDetails": "Details umschalten" + }, + "backgroundTasks": { + "running": "{count, plural, one {# Hintergrundaufgabe läuft} other {# Hintergrundaufgaben laufen}}", + "settling": "Hintergrundergebnisse werden synchronisiert…", + "settledFallback": "Hintergrundaufgabe beendet ({status})", + "cardRunning": "Läuft im Hintergrund", + "cardLaunchedPending": "Hintergrundaufgabe gestartet", + "cardCompleted": "Hintergrundaufgabe abgeschlossen", + "cardFinishedWithStatus": "Hintergrundaufgabe beendet ({status})", + "cardResultPending": "Ergebnis steht noch aus" + }, + "proposedPlan": { + "title": "Vorgeschlagener Plan", + "planning": "Wird geplant…" + } + }, + "diffPreview": { + "mode": { + "added": "Hinzugefügt", + "deleted": "Gelöscht", + "renamed": "Umbenannt", + "modified": "Geändert" + }, + "hunkLabel": "Block {index}", + "loadingHunk": "Hunk wird geladen...", + "noDiffData": "Keine Diff-Daten", + "showRemainingLines": "{count} weitere Zeilen anzeigen" + }, + "conversationContextBar": { + "folderTitle": "Arbeitsordner", + "branchTitle": "Arbeits-Branch", + "searchFolder": "Search folder...", + "searchBranch": "Search branch...", + "noFolders": "No folders", + "noBranches": "No branches", + "noBranch": "(no branch)", + "chatModeLabel": "Chat-Modus", + "commit": "Commit", + "push": "Push", + "merge": "Merge", + "toasts": { + "folderChanged": "Switched to {name}", + "openFolderFailed": "Failed to open folder", + "switchedToChatMode": "In den Chat-Modus gewechselt", + "openStashFailed": "Failed to open stash window", + "openMergeFailed": "Failed to open merge window" + } + }, + "cloneDialog": { + "title": "Repository klonen", + "repositoryUrl": "Repository-URL", + "repositoryUrlPlaceholder": "https://github.com/user/repo.git", + "directory": "Verzeichnis", + "directoryPlaceholder": "Zielverzeichnis auswählen...", + "browseDirectory": "Verzeichnis durchsuchen", + "cancel": "Abbrechen", + "clone": "Klonen", + "clonePath": "Klonpfad: {path}" + }, + "toasts": { + "cloneFailed": "Repository konnte nicht geklont werden" + } + }, + "ProjectBoot": { + "title": "Projekt-Starter", + "tabs": { + "shadcn": "shadcn", + "hyperframes": "HyperFrames" + }, + "hyperframes": { + "title": "HyperFrames-Videoprojekt", + "subtitle": "Erstelle ein HTML-zu-Video-Projekt. Der Agent im Arbeitsbereich kann es dann schreiben und rendern.", + "resolution": "Auflösung", + "skillsTitle": "Agenten-Skills", + "skillsDesc": "Installiert die HyperFrames-Skills global (Symlink) für die ausgewählten Agenten, damit sie Videos erstellen und rendern können.", + "recheck": "Erneut prüfen", + "installedBadge": "Installiert", + "skillsInstall": "Skills installieren / aktualisieren", + "skillsInstalling": "Skills werden installiert…", + "skillsInstalled": "HyperFrames-Skills installiert", + "skillsInstallFailed": "HyperFrames-Skills konnten nicht installiert werden" + }, + "config": { + "base": "Basis", + "style": "Stil", + "baseColor": "Basisfarbe", + "theme": "Thema", + "chartColor": "Diagrammfarbe", + "iconLibrary": "Icon-Bibliothek", + "font": "Schriftart", + "fontHeading": "Überschrift-Schriftart", + "menuAccent": "Menü-Akzent", + "menuColor": "Menü-Farbe", + "radius": "Radius", + "template": "Vorlage", + "createProject": "Projekt erstellen", + "sectionStyle": "Stil", + "sectionColors": "Farben", + "sectionTypography": "Typografie", + "sectionInterface": "Oberfläche" + }, + "preview": { + "loading": "Vorschau wird geladen..." + }, + "createDialog": { + "title": "Projekt erstellen", + "projectName": "Projektname", + "projectNamePlaceholder": "my-app", + "frameworkTemplate": "Framework-Vorlage", + "packageManager": "Paketmanager", + "saveDirectory": "Speicherverzeichnis", + "saveDirectoryPlaceholder": "Verzeichnis auswählen...", + "browseDirectory": "Durchsuchen", + "projectPath": "Projekt wird erstellt in: {path}", + "advancedOptions": "Erweiterte Optionen", + "base": "Basisbibliothek", + "enableRtl": "RTL-Unterstützung aktivieren", + "enableRtlDescription": "Layout-Unterstützung für Rechts-nach-links-Sprachen (z.B. Arabisch, Hebräisch) aktivieren", + "pmChecking": "Wird überprüft...", + "pmNotInstalled": "Nicht installiert", + "cancel": "Abbrechen", + "create": "Erstellen", + "creating": "Projekt wird erstellt..." + }, + "toasts": { + "createFailed": "Projekt konnte nicht erstellt werden", + "createSuccess": "Projekt erfolgreich erstellt", + "openWorkspaceFailed": "Projekt erstellt, konnte aber nicht im Arbeitsbereich geöffnet werden" + }, + "errors": { + "directoryExists": "Zielverzeichnis existiert bereits", + "commandFailed": "Projekterstellungsbefehl fehlgeschlagen." + } + }, + "WebServiceSettings": { + "addressSwitchHint": "Das Umschalten ändert nur die hier angezeigte und geöffnete Adresse – der Dienst lauscht auf allen Schnittstellen und bleibt unter jeder Adresse erreichbar.", + "sectionTitle": "Webdienst", + "sectionDescription": "Aktivieren Sie den Fernzugriff auf Codeg über den Browser", + "port": "Port", + "status": "Status", + "autoStart": "Automatisch starten", + "autoStartHint": "Webdienst beim Start von Codeg starten", + "running": "Läuft", + "stopped": "Gestoppt", + "processing": "Verarbeitung...", + "start": "Starten", + "stop": "Stoppen", + "startFailed": "Start fehlgeschlagen", + "stopFailed": "Stopp fehlgeschlagen", + "saveConfigFailed": "Webdienst-Einstellungen konnten nicht gespeichert werden", + "open": "Öffnen", + "hide": "Ausblenden", + "show": "Einblenden", + "copy": "Kopieren", + "qrcode": "QR-Code", + "qrcodeTitle": "Zum Öffnen scannen", + "qrcodeHint": "Scanne mit deinem Handy, um Codeg im Browser zu öffnen", + "addressLabel": "Zugriffsadresse", + "tokenLabel": "Zugriffstoken", + "tokenHint": "Geben Sie dieses Token beim ersten Zugriff auf den Web-Client ein", + "tokenPlaceholder": "Leer lassen für automatische Generierung", + "regenerate": "Neu generieren", + "stalePortOccupiedTitle": "Port {port} wird von einem anderen Prozess belegt", + "stalePortUnknownTitle": "Status von Port {port} unklar", + "stalePortHint": "Codeg kann sich nicht binden, bis der Port freigegeben ist. Ändere den Port oben oder beende den Prozess, der ihn hält.", + "errors": { + "alreadyRunning": "Der Web-Dienst läuft bereits", + "invalidAddress": "Host- oder Portformat ungültig", + "portInUse": "Port {port} wird bereits verwendet. Beenden Sie den Prozess oder wählen Sie einen anderen Port.", + "permissionDenied": "Zugriff verweigert. Verwenden Sie einen Port über 1024 oder starten Sie mit höheren Rechten.", + "addressUnavailable": "Die Adresse ist auf diesem Computer nicht verfügbar", + "bindFailed": "Adresse konnte nicht gebunden werden" + } + }, + "DirectoryBrowser": { + "title": "Verzeichnis durchsuchen", + "pathPlaceholder": "Verzeichnispfad eingeben...", + "goHome": "Zum Heimverzeichnis", + "navigateUp": "Zum übergeordneten Verzeichnis", + "select": "Auswählen", + "cancel": "Abbrechen", + "loading": "Wird geladen...", + "emptyDirectory": "Dieses Verzeichnis ist leer", + "errorLoadingDir": "Verzeichnis konnte nicht geladen werden", + "permissionDenied": "Zugriff verweigert" + }, + "ChatChannelSettings": { + "loading": "Wird geladen...", + "sectionTitle": "Chat-Kanäle", + "sectionDescription": "Konfigurieren Sie IM-Bots, um Ereignisbenachrichtigungen zu empfangen und Codieraktivitäten abzufragen.", + "addChannel": "Kanal hinzufügen", + "noChannels": "Noch keine Chat-Kanäle konfiguriert.", + "channelName": "Name", + "channelNamePlaceholder": "Mein Telegram Bot", + "channelType": "Kanaltyp", + "lark": "Lark (Feishu)", + "weixin": "WeChat", + "dailyReport": "Tagesbericht", + "dailyReportTime": "Berichtszeit", + "nameRequired": "Kanalname ist erforderlich.", + "tokenRequired": "Token ist erforderlich.", + "chatIdRequired": "Chat-ID ist erforderlich.", + "topicMode": "Themengruppenmodus", + "topicModeHint": "Leitet Telegram-Forum-Themen als separate Codeg-Sitzungen weiter. Der Bot muss in einer Forum-Supergruppe sein und Themen verwalten dürfen.", + "loadFailed": "Kanäle konnten nicht geladen werden.", + "saveFailed": "Änderungen konnten nicht gespeichert werden.", + "connectSuccess": "Kanal verbunden.", + "connectFailed": "Verbindung fehlgeschlagen", + "disconnectSuccess": "Kanal getrennt.", + "disconnectFailed": "Trennung fehlgeschlagen.", + "testSuccess": "Verbindungstest bestanden.", + "testFailed": "Verbindungstest fehlgeschlagen", + "deleteSuccess": "Kanal gelöscht.", + "deleteFailed": "Kanal konnte nicht gelöscht werden.", + "deleteConfirmTitle": "Kanal löschen", + "deleteConfirmMessage": "Der Kanal und seine Nachrichtenprotokolle werden dauerhaft gelöscht. Sind Sie sicher?", + "cancel": "Abbrechen", + "delete": "Löschen", + "create": "Erstellen", + "save": "Speichern", + "channelListTitle": "Konfigurierte Kanäle", + "channelListDescription": "Aktivierte Kanäle werden beim Dienststart automatisch verbunden.", + "editChannel": "Kanal bearbeiten", + "editSuccess": "Kanal aktualisiert.", + "tokenPlaceholderKeep": "Leer lassen, um aktuellen Wert beizubehalten", + "weixinScanTitle": "QR-Code scannen", + "weixinScanDescription": "Öffnen Sie WeChat und scannen Sie den QR-Code, um eine Verbindung herzustellen.", + "weixinQrcodeExpired": "QR-Code abgelaufen.", + "weixinRefreshQrcode": "Aktualisieren", + "weixinWaitingScan": "Warten auf Scan...", + "weixinPollError": "Verbindung instabil, erneuter Versuch...", + "weixinReconnectNotice": "Aufgrund von Einschränkungen des iLink-Protokolls müssen Sie nach jeder erneuten Verbindung dem Bot eine Nachricht senden, damit Ereignisauslöser wirksam werden.", + "connect": "Verbinden", + "disconnect": "Trennen", + "test": "Verbindung testen", + "tabs": { + "channels": "Kanäle", + "commands": "Befehle", + "events": "Ereignisse", + "other": "Sonstiges" + }, + "commands": { + "title": "Integrierte Befehle", + "description": "Im Chat-Kanal verfügbare Bot-Befehle. In Gruppenchats ist @Bot erforderlich, um Nachrichten zu verarbeiten.", + "prefixLabel": "Befehlspräfix", + "prefixDescription": "1-3 nicht-alphanumerische Zeichen zum Auslösen von Bot-Befehlen (Standard /).", + "prefixSaved": "Befehlspräfix gespeichert.", + "prefixSaveFailed": "Fehler beim Speichern des Präfixes.", + "prefixInvalid": "Das Präfix muss 1-3 nicht-alphanumerische Zeichen sein.", + "save": "Speichern", + "folderDesc": "Arbeitsordner auswählen", + "agentDesc": "KI-Agent auswählen", + "taskDesc": "Sitzung erstellen und Aufgabe ausführen", + "sessionsDesc": "Aktive Sitzungen im Ordner anzeigen", + "resumeDesc": "Neueste Konversationen / Sitzung fortsetzen", + "cancelDesc": "Aktuelle Aufgabe abbrechen", + "approveDesc": "Berechtigungsanfrage des Agenten genehmigen", + "denyDesc": "Berechtigungsanfrage des Agenten ablehnen", + "searchDesc": "Konversationen nach Stichwort suchen", + "todayDesc": "Heutige Aktivitätsübersicht", + "statusDesc": "Kanal-Verbindungsstatus", + "helpDesc": "Hilfe anzeigen" + }, + "events": { + "title": "Ereignisbenachrichtigungen", + "description": "Nach Aktivierung werden ausgelöste Ereignisse an den Kanal gesendet.", + "turnComplete": "Runde abgeschlossen", + "turnCompleteDesc": "Wenn eine Agentenrunde endet", + "error": "Agentenfehler", + "errorDesc": "Wenn ein Agent einen Fehler feststellt", + "permissionRequest": "Berechtigungsanfrage", + "permissionRequestDesc": "Wenn ein Agent eine Berechtigung anfordert", + "questionRequest": "Frage des Agenten", + "questionRequestDesc": "Wenn ein Agent dir eine Frage stellt", + "userPromptSent": "Benutzernachricht", + "userPromptSentDesc": "Wenn du eine Nachricht sendest – der Nachrichtentext ist in der Benachrichtigung enthalten", + "saved": "Ereignisfilter aktualisiert.", + "saveFailed": "Fehler beim Speichern des Ereignisfilters.", + "loadFailed": "Einstellungen konnten nicht geladen werden.", + "retry": "Erneut versuchen", + "webhooksTitle": "Webhooks", + "webhooksDescription": "Sendet bei einem aktivierten Ereignis eine JSON-Nutzlast per POST an eine oder mehrere URLs. Der Ereignisfilter oben gilt auch für Webhooks.", + "webhookUrlPlaceholder": "https://example.com/webhook", + "addWebhook": "Webhook hinzufügen", + "removeWebhook": "Webhook entfernen", + "webhookSave": "Speichern", + "webhooksSaved": "Webhooks gespeichert.", + "webhooksSaveFailed": "Fehler beim Speichern der Webhooks.", + "webhookInvalidUrl": "Gültige http(s)-URLs eingeben.", + "docsTitle": "Anfrageformat", + "docsMethod": "Methode", + "docsContentType": "Content-Type", + "docsNote": "Jedes aktivierte Ereignis wird an alle URLs gesendet. Webhooks werden nicht entprellt; der Ereignisfilter oben gilt weiterhin.", + "editWebhook": "Webhook bearbeiten", + "enableWebhook": "Webhook aktivieren", + "webhookDuplicate": "Diese URL ist bereits konfiguriert.", + "cancel": "Abbrechen", + "webhooksEmpty": "Noch keine Webhooks konfiguriert.", + "deleteWebhookTitle": "Webhook löschen", + "deleteWebhookMessage": "Diesen Webhook entfernen? Ereignisse werden nicht mehr an diese URL gesendet.", + "delete": "Löschen" + }, + "language": { + "title": "Nachrichtensprache", + "description": "Sprache für Ereignisbenachrichtigungen, Befehlsantworten und tägliche Berichte, die an Chat-Kanäle gesendet werden.", + "saved": "Nachrichtensprache gespeichert.", + "saveFailed": "Fehler beim Speichern der Nachrichtensprache.", + "en": "Englisch", + "zh-cn": "Vereinfachtes Chinesisch", + "zh-tw": "Traditionelles Chinesisch", + "ja": "Japanisch", + "ko": "Koreanisch", + "es": "Spanisch", + "de": "Deutsch", + "fr": "Französisch", + "pt": "Portugiesisch", + "ar": "Arabisch" + } + }, + "ModelProviderSettings": { + "sectionTitle": "Modellanbieter", + "sectionDescription": "API-Anbieter-Zugangsdaten für Agenten verwalten.", + "filterAll": "Alle", + "providerListTitle": "Konfigurierte Anbieter", + "addProvider": "Anbieter hinzufügen", + "editProvider": "Anbieter bearbeiten", + "noProviders": "Noch keine Modellanbieter konfiguriert.", + "providerName": "Name", + "providerNamePlaceholder": "z.B. OpenAI, Anthropic", + "apiUrl": "API-URL", + "apiUrlPlaceholder": "https://api.openai.com/v1", + "apiKey": "API-Schlüssel", + "apiKeyPlaceholder": "sk-...", + "apiKeyKeepCurrent": "Leer lassen, um aktuellen Wert beizubehalten", + "agentTypes": "Agententypen", + "agentTypesRequired": "Mindestens ein Agententyp ist erforderlich.", + "agentType": "Agententyp", + "agentTypeRequired": "Agententyp ist erforderlich.", + "agentTypeImmutableHint": "Der Agententyp kann nach der Erstellung nicht mehr geändert werden.", + "model": "Modell", + "modelPlaceholderCodex": "gpt-5.6-sol / gpt-5.5", + "modelPlaceholderGemini": "gemini-3-pro-preview", + "claudeMainModel": "Hauptmodell", + "claudeReasoningModel": "Reasoning-Modell (Thinking)", + "claudeHaikuDefaultModel": "Standard Haiku-Modell", + "claudeSonnetDefaultModel": "Standard Sonnet-Modell", + "claudeOpusDefaultModel": "Standard Opus-Modell", + "claudeCustomModelOption": "Benutzerdefinierte Modell-ID", + "claudeCustomModelOptionName": "Name des benutzerdefinierten Modells", + "claudeCustomModelOptionDescription": "Beschreibung des benutzerdefinierten Modells", + "claudeCustomModelOptionHint": "Fügt der Modellauswahl von Claude einen einzelnen benutzerdefinierten Eintrag hinzu (z. B. ein Modell hinter einem benutzerdefinierten Gateway/Proxy). Name und Beschreibung sind optionale Anzeigeangaben.", + "nameRequired": "Anbietername ist erforderlich.", + "apiUrlRequired": "API-URL ist erforderlich.", + "apiKeyRequired": "API-Schlüssel ist erforderlich.", + "loadFailed": "Anbieter konnten nicht geladen werden.", + "saveFailed": "Änderungen konnten nicht gespeichert werden.", + "createSuccess": "Anbieter erstellt.", + "editSuccess": "Anbieter aktualisiert.", + "deleteSuccess": "Anbieter gelöscht.", + "deleteConfirmTitle": "Anbieter löschen", + "deleteConfirmMessage": "Der Anbieter \"{name}\" wird dauerhaft gelöscht. Sind Sie sicher?", + "deleteBlockedByAgent": "{agents} verwendet diesen Anbieter. Bitte trennen Sie die Verbindung vor dem Löschen.", + "cancel": "Abbrechen", + "delete": "Löschen", + "create": "Erstellen", + "save": "Speichern", + "affectedRunningSessions": "{count, plural, one {# laufende Sitzung muss zum Anwenden neu verbunden werden} other {# laufende Sitzungen müssen zum Anwenden neu verbunden werden}}" + }, + "SkillMatrix": { + "loading": "Wird geladen…", + "searchPlaceholder": "Nach Name, ID oder Beschreibung suchen", + "empty": "Nichts anzuzeigen.", + "emptySearch": "Keine Treffer für die aktuelle Suche.", + "skillColumn": "Skill", + "selectAll": "Alle sichtbaren auswählen", + "selectSkill": "{name} auswählen", + "everything": { + "label": "Sammelaktion", + "enable": "Alle aktivieren (sichtbar)", + "disable": "Alle deaktivieren (sichtbar)" + }, + "columnMenu": { + "enableAll": "Alle Skills aktivieren", + "disableAll": "Alle Skills deaktivieren" + }, + "rowMenu": { + "label": "Sammelaktionen für {name}", + "enableAll": "Für alle Agenten aktivieren", + "disableAll": "Für alle Agenten deaktivieren" + }, + "bulk": { + "selected": "{count} ausgewählt", + "targetAll": "Alle Agenten", + "targetSome": "{count} Agenten", + "enable": "Aktivieren", + "disable": "Deaktivieren", + "clear": "Leeren" + }, + "confirm": { + "disableTitle": "Diese Verknüpfungen deaktivieren?", + "disableBody": "Dadurch werden {count} von codeg verwaltete Skill-Verknüpfungen entfernt. Skills, die ein eigenes Verzeichnis belegen, bleiben unberührt. Du kannst sie jederzeit wieder aktivieren.", + "cancel": "Abbrechen", + "confirm": "Deaktivieren" + }, + "toasts": { + "loadFailed": "Skill-Status konnte nicht geladen werden", + "applyFailed": "Änderungen konnten nicht angewendet werden", + "enabled": "{count} Verknüpfungen aktiviert", + "disabled": "{count} Verknüpfungen deaktiviert", + "enabledPartial": "{ok} aktiviert, {failed} fehlgeschlagen", + "disabledPartial": "{ok} deaktiviert, {failed} fehlgeschlagen" + }, + "detail": { + "enableForAgents": "Für Agenten aktivieren", + "preview": "SKILL.md-Vorschau", + "loadingContent": "Inhalt wird geladen…" + }, + "copyModeHint": "Kopiert (nicht verknüpft) – nach Updates erneut aktivieren, um die neueste Version zu erhalten" + }, + "ExpertsSettings": { + "title": "Experten-Skills", + "description": "Aktivieren Sie kuratierte, praxiserprobte Skill-Workflows für Ihre KI-Coding-Agents. Jeder Experte ist ein eigenständiger Skill aus dem superpowers-Projekt — codeg verwaltet die zentrale Kopie und verknüpft sie mit den von Ihnen ausgewählten Agents.", + "loading": "Experten werden geladen…", + "loadingContent": "Inhalt wird geladen…", + "emptyExperts": "Keine Experten verfügbar. Prüfen Sie die Anwendungsprotokolle.", + "emptySelection": "Wählen Sie einen Experten aus, um seinen Inhalt anzuzeigen und die Aktivierung zu verwalten.", + "emptySearch": "Keine Experten entsprechen der aktuellen Suche.", + "searchPlaceholder": "Experten nach Name, ID oder Beschreibung suchen", + "enableForAgents": "Für Agents aktivieren", + "noAgents": "Keine ACP-Agents erkannt.", + "copyModeWarning": "Kopiert (nicht verknüpft). Nach codeg-Updates erneut aktivieren, um die neueste Version zu erhalten.", + "previewTitle": "SKILL.md-Vorschau", + "categories": { + "discovery": "Entdeckung & Design", + "planning": "Planung", + "execution": "Ausführung", + "quality": "Qualität & Tests", + "debugging": "Debugging", + "review": "Review & Integration", + "meta": "Meta" + }, + "states": { + "not_linked": "Nicht aktiviert", + "linked_to_codeg": "Aktiviert", + "linked_elsewhere": "Blockiert — ein anderer Link existiert", + "blocked_by_real_directory": "Blockiert — ein benutzerdefinierter Skill belegt diesen Namen", + "broken": "Defekter Link" + }, + "badges": { + "userModified": "Vom Benutzer geändert" + }, + "actions": { + "openCentralDir": "Zentralen Ordner öffnen", + "refresh": "Aktualisieren" + }, + "toasts": { + "loadFailed": "Laden der Expertendetails fehlgeschlagen", + "enabled": "Experte für diesen Agent aktiviert", + "disabled": "Experte für diesen Agent deaktiviert", + "enableFailed": "Aktivieren des Experten fehlgeschlagen", + "disableFailed": "Deaktivieren des Experten fehlgeschlagen", + "openFolderFailed": "Ordner konnte nicht geöffnet werden" + } + }, + "ScienceSettings": { + "title": "Wissenschaftliche Skills", + "description": "Aktiviere kuratierte wissenschaftliche Skills für deine KI-Coding-Agents — Hypothesengenerierung, Versuchsplanung, Statistik, Visualisierung, kritische Bewertung und Literatursuche. codeg verwaltet eine zentrale Kopie und verlinkt jeden Skill in die von dir gewählten Agents.", + "loading": "Wissenschaftliche Skills werden geladen…", + "emptySkills": "Keine wissenschaftlichen Skills verfügbar. Prüfe die Anwendungsprotokolle.", + "searchPlaceholder": "Wissenschaftliche Skills nach Name, ID oder Beschreibung suchen", + "categories": { + "ideation": "Ideenfindung", + "design": "Studiendesign", + "analysis": "Analyse", + "visualization": "Visualisierung", + "evaluation": "Bewertung", + "literature": "Literatur" + }, + "states": { + "not_linked": "Nicht aktiviert", + "linked_to_codeg": "Aktiviert", + "linked_elsewhere": "Blockiert — ein anderer Link existiert", + "blocked_by_real_directory": "Blockiert — ein benutzerdefinierter Skill belegt diesen Namen", + "broken": "Defekter Link" + }, + "badges": { + "userModified": "Vom Benutzer geändert", + "needsKey": "API-Schlüssel nötig", + "needsSetup": "Ggf. Einrichtung nötig" + }, + "actions": { + "openCentralDir": "Zentralen Ordner öffnen", + "refresh": "Aktualisieren" + }, + "toasts": { + "openFolderFailed": "Ordner konnte nicht geöffnet werden" + } + }, + "OfficeToolsSettings": { + "title": "Office-Tools", + "description": "Verwalten Sie OfficeCLI-Skills zum Erstellen von Excel-, Word- und PowerPoint-Dateien. Installieren Sie OfficeCLI, synchronisieren Sie Skills und aktivieren Sie sie pro Agent.", + "loadingContent": "Inhalt wird geladen…", + "emptySkills": "Keine Skills verfügbar. Installieren Sie OfficeCLI und synchronisieren Sie die Skills.", + "emptySelection": "Wählen Sie einen Skill aus, um den Inhalt anzuzeigen und die Aktivierung zu verwalten.", + "emptySearch": "Keine übereinstimmenden Skills gefunden.", + "searchPlaceholder": "Skills nach Name, ID oder Beschreibung suchen", + "enableForAgents": "Für Agenten aktivieren", + "noAgents": "Keine ACP-Agenten erkannt.", + "installFirst": "Installieren Sie zuerst OfficeCLI, um Skills zu aktivieren.", + "syncFirst": "Synchronisieren Sie zuerst die Skills, um den Inhalt zu laden.", + "noContent": "Kein Inhalt verfügbar.", + "copyModeWarning": "Kopiert (nicht verknüpft). Erneut synchronisieren, um die neueste Version zu erhalten.", + "previewTitle": "SKILL.md-Vorschau", + "detection": { + "installed": "Installiert", + "notInstalled": "Nicht installiert", + "notRunnable": "Installiert, aber nicht lauffähig", + "installHint": "Installieren Sie OfficeCLI, um Office-Dokumentenerstellungs-Skills für Ihre KI-Agenten zu aktivieren.", + "install": "Installieren", + "uninstall": "Deinstallieren", + "syncSkills": "Skills synchronisieren" + }, + "categories": { + "general": "Allgemein", + "presentations": "Präsentationen", + "documents": "Dokumente", + "spreadsheets": "Tabellenkalkulationen" + }, + "states": { + "not_linked": "Nicht aktiviert", + "linked_to_codeg": "Aktiviert", + "linked_elsewhere": "Blockiert — ein anderer Link existiert", + "blocked_by_real_directory": "Blockiert — ein benutzerdefinierter Skill belegt diesen Namen", + "broken": "Defekter Link" + }, + "badges": { + "notSynced": "Nicht synchronisiert" + }, + "actions": { + "refresh": "Aktualisieren" + }, + "toasts": { + "loadFailed": "Skill-Details konnten nicht geladen werden", + "enabled": "Skill für diesen Agenten aktiviert", + "disabled": "Skill für diesen Agenten deaktiviert", + "enableFailed": "Skill konnte nicht aktiviert werden", + "disableFailed": "Skill konnte nicht deaktiviert werden", + "installSuccess": "OfficeCLI erfolgreich installiert", + "installFailed": "OfficeCLI konnte nicht installiert werden", + "uninstallSuccess": "OfficeCLI deinstalliert", + "uninstallFailed": "OfficeCLI konnte nicht deinstalliert werden", + "syncSuccess": "{synced} Skills erfolgreich synchronisiert", + "syncPartial": "{synced} synchronisiert, {errors} fehlgeschlagen", + "syncFailed": "Skills konnten nicht synchronisiert werden" + }, + "autoPreviewLabel": "Vorschau automatisch öffnen", + "autoPreviewHint": "Wenn ein Agent eine Word-, Excel- oder PowerPoint-Datei erstellt oder bearbeitet, wird die Live-Vorschau automatisch geöffnet." + }, + "SkillPacksSettings": { + "title": "Skill-Pakete", + "description": "Kuratierte Skill-Pakete, die codeg zentral verwaltet und mit deinen KI-Agenten verknüpft – Programmierexperten, wissenschaftliche Forschung und Office-Dokumenttools. Unten pro Agent aktivierbar.", + "tabs": { + "experts": "Experten", + "science": "Wissenschaft", + "office": "Office-Tools", + "custom": "Benutzerdefiniert" + }, + "actions": { + "openCentralDir": "Zentralen Ordner öffnen", + "refresh": "Aktualisieren" + }, + "toasts": { + "openFolderFailed": "Ordner konnte nicht geöffnet werden" + } + }, + "QuickMessagesSettings": { + "title": "Schnellnachrichten", + "description": "Verwalte wiederverwendbare Nachrichtenbausteine. Ziehe zum Neuordnen.", + "loading": "Schnellnachrichten werden geladen…", + "emptyList": "Noch keine Schnellnachrichten. Klicke auf \"Neu\", um eine zu erstellen.", + "emptySelection": "Wähle eine Schnellnachricht zum Bearbeiten aus.", + "searchPlaceholder": "Nach Titel oder Inhalt suchen", + "untitled": "Ohne Titel", + "actions": { + "new": "Neu", + "save": "Speichern", + "delete": "Löschen", + "dragSort": "Zum Neuordnen ziehen", + "dragSortMessage": "Schnellnachricht neu ordnen: {name}" + }, + "fields": { + "title": "Titel", + "titlePlaceholder": "Gib dieser Nachricht einen kurzen Titel", + "content": "Inhalt", + "contentPlaceholder": "Gib hier den Nachrichteninhalt ein" + }, + "confirmDelete": { + "title": "Schnellnachricht löschen?", + "message": "Dadurch wird \"{name}\" dauerhaft gelöscht. Bist du sicher?", + "cancel": "Abbrechen", + "confirm": "Löschen" + }, + "toasts": { + "loadFailed": "Laden der Schnellnachrichten fehlgeschlagen", + "createFailed": "Erstellen der Schnellnachricht fehlgeschlagen", + "saveFailed": "Speichern der Schnellnachricht fehlgeschlagen", + "deleteFailed": "Löschen der Schnellnachricht fehlgeschlagen", + "saveOrderFailed": "Reihenfolge konnte nicht gespeichert werden", + "created": "Schnellnachricht erstellt", + "saved": "Schnellnachricht gespeichert", + "deleted": "Schnellnachricht gelöscht" + } + }, + "Pet": { + "badge": { + "running": "{count} laufend", + "waiting": "{count} warten auf Freigabe", + "error": "{count} fehlgeschlagen" + }, + "panel": { + "title": "Aktive Sitzungen", + "empty": "Keine aktiven Sitzungen", + "emptyHint": "Laufende Agenten und solche, die dich brauchen, erscheinen hier.", + "statusRunning": "Läuft", + "statusWaiting": "Wartet", + "statusError": "Fehler", + "subAgentOf": "Sub-Agent von" + }, + "menu": { + "scale": "Skalierung", + "openManager": "Pets verwalten", + "close": "Schließen" + }, + "loadError": "Pet konnte nicht geladen werden", + "missingPetIdParam": "Kein Pet ausgewählt", + "summonButton": "Pet", + "manager": { + "title": "Desktop-Pets", + "description": "Schwebende Begleiter mit Codex-kompatiblen Sprite-Sheets.", + "addPet": "Pet hinzufügen", + "importFromCodex": "Aus Codex importieren", + "noPets": "Keine Pets. Lege eines an oder importiere aus Codex.", + "setActive": "Aktivieren", + "active": "Aktiv", + "edit": "Bearbeiten", + "delete": "Löschen", + "deleteConfirm": "Pet „{name}\" löschen? Auch von der Festplatte entfernt.", + "summon": "Pet-Fenster aufrufen", + "openCodexHelp": "Codex-Pets müssen in ~/.codex/pets/ liegen. Nichts gefunden.", + "specRequirement": "Sprite-Sheet muss 1536px breit sein, mit einer Höhe als Vielfaches von 208px (z. B. 1872 oder 2288), als PNG oder WebP mit Transparenz.", + "form": { + "id": "Pet-ID", + "idHelp": "Kleinbuchstaben, Ziffern, '-' und '_'. Max 64 Zeichen.", + "displayName": "Anzeigename", + "description": "Beschreibung (optional)", + "spritesheet": "Sprite-Sheet", + "chooseFile": "Datei wählen", + "replaceFile": "Sprite ersetzen", + "saveCreate": "Pet hinzufügen", + "saveUpdate": "Änderungen speichern", + "cancel": "Abbrechen" + }, + "errors": { + "missingId": "Pet-ID erforderlich", + "missingName": "Anzeigename erforderlich", + "missingSpritesheet": "Sprite erforderlich", + "addFailed": "Hinzufügen fehlgeschlagen", + "updateFailed": "Aktualisieren fehlgeschlagen", + "deleteFailed": "Löschen fehlgeschlagen", + "loadFailed": "Pet-Liste konnte nicht geladen werden", + "setActiveFailed": "Aktivieren fehlgeschlagen", + "summonFailed": "Pet-Fenster konnte nicht geöffnet werden" + } + }, + "import": { + "title": "Aus Codex importieren", + "subtitle": "Pets unter ~/.codex/pets/.", + "selectAll": "Alle auswählen", + "alreadyImported": "Bereits importiert", + "renameOnConflict": "Konflikte mit Suffix -imported umbenennen", + "import": "Auswahl importieren", + "noneFound": "Keine importierbaren Codex-Pets gefunden.", + "imported": "Erfolgreich importiert", + "failed": "Import fehlgeschlagen", + "close": "Schließen" + }, + "marketplace": { + "openMarketplace": "Pet-Marketplace", + "title": "Pet-Marketplace", + "search": "Pets suchen", + "kindFilter": { + "all": "Alle", + "object": "Objekt", + "animal": "Tier", + "person": "Person", + "creature": "Kreatur" + }, + "sortFilter": { + "latest": "Neueste", + "popular": "Beliebt", + "views": "Aufrufe" + }, + "refresh": "Aktualisieren", + "install": "Installieren", + "installing": "Wird installiert", + "reinstall": "Neu installieren", + "reinstallConfirm": "Lokales Pet \"{name}\" überschreiben? Vorhandene Daten werden ersetzt.", + "cancel": "Abbrechen", + "stats": { + "views": "Aufrufe", + "downloads": "Downloads", + "likes": "Likes" + }, + "actions": { + "idle": "Idle", + "running_right": "Rechtslauf", + "running_left": "Linkslauf", + "waving": "Winken", + "jumping": "Springen", + "failed": "Fehler", + "waiting": "Warten", + "running": "Laufen", + "review": "Review" + }, + "page": "Seite {page} von {total}", + "prev": "Zurück", + "next": "Weiter", + "empty": "Keine Pets entsprechen dem Filter.", + "successInstalled": "\"{name}\" installiert", + "errors": { + "loadFailed": "Marketplace konnte nicht geladen werden", + "installFailed": "Installation fehlgeschlagen", + "alreadyInstalled": "Pet existiert bereits lokal" + } + } + }, + "RemoteWorkspace": { + "openRemoteWorkspace": "Open remote workspace", + "manage": "Manage remote workspace", + "manageTitle": "Remote Workspace connections", + "empty": "No remote connections", + "searchPlaceholder": "Search remote workspaces", + "orderFailed": "Failed to save remote workspace order", + "dragSort": "Drag to sort", + "dragSortConnection": "Drag to sort {name}", + "newConnection": "New connection", + "loading": "Loading", + "loadingConnection": "Loading remote connection", + "name": "Name", + "baseUrl": "Service URL", + "token": "Access token", + "save": "Save", + "delete": "Delete", + "confirmDelete": { + "title": "Delete remote connection?", + "message": "This will remove \"{name}\" from this device. This action cannot be undone.", + "cancel": "Cancel", + "confirm": "Delete" + }, + "saved": "Remote connection saved.", + "deleted": "Remote connection deleted.", + "loadFailed": "Failed to load remote connections", + "saveFailed": "Failed to save remote connection", + "deleteFailed": "Failed to delete remote connection", + "openFailed": "Failed to open remote workspace", + "connectionLoadFailed": "Failed to load remote connection: {message}", + "connectionExpired": "Remote connection \"{name}\" is expired. Update its token and reload this window." + }, + "ServerFileBrowser": { + "title": "Serverdatei auswählen", + "pathPlaceholder": "Verzeichnispfad eingeben...", + "goHome": "Zum Home-Verzeichnis", + "navigateUp": "Zum übergeordneten Verzeichnis", + "select": "Auswählen", + "cancel": "Abbrechen", + "loading": "Laden...", + "emptyDirectory": "Dieses Verzeichnis ist leer", + "errorLoadingDir": "Verzeichnis konnte nicht geladen werden", + "selectedCount": "{count} ausgewählt" + }, + "BackupSettings": { + "title": "Sicherung & Wiederherstellung", + "description": "Exportiere eine portable Sicherung deiner codeg-Daten oder stelle aus einer Sicherung wieder her.", + "tabs": { + "backup": "Sicherung", + "restore": "Wiederherstellung" + }, + "export": { + "includeExternal": "Gesprächsinhalte einschließen", + "includeExternalHint": "Archiviert auch die CLI-Transkripte (Claude, Codex, Gemini, …). Erhöht die Größe.", + "passphrase": "Passphrase (optional)", + "passphrasePlaceholder": "Leer lassen für ein unverschlüsseltes Archiv", + "passphraseConfirm": "Passphrase bestätigen", + "passphraseMismatch": "Die Passphrasen stimmen nicht überein.", + "noPassphraseWarning": "Diese Sicherung enthält Geheimnisse (API-Schlüssel, Tokens) im Klartext. Bewahre sie sicher auf.", + "passphraseLossWarning": "Mit dieser Passphrase verschlüsselt. Wenn du sie verlierst, kann die Sicherung nicht wiederhergestellt werden.", + "button": "Sicherung exportieren", + "inProgress": "Sicherung wird erstellt…", + "success": "Sicherung erstellt.", + "started": "Download der Sicherung gestartet." + }, + "restore": { + "selectFile": "Sicherungsdatei auswählen", + "passphrasePrompt": "Diese Sicherung ist verschlüsselt. Gib ihre Passphrase ein.", + "unlock": "Entsperren", + "preview": { + "title": "Sicherungsdetails", + "encrypted": "Verschlüsselt", + "compatible": "Kompatibel", + "incompatible": "Inkompatibel", + "createdAt": "Erstellt: {value}", + "appVersion": "App-Version: {value}", + "incompatibleHint": "Diese Sicherung wurde mit einer neueren Version von codeg erstellt und kann nicht wiederhergestellt werden." + }, + "replaceWarning": "Beim Wiederherstellen werden alle aktuellen codeg-Daten (Datenbank und Uploads) ersetzt. Deine aktuellen Daten werden zuvor als Snapshot gesichert.", + "keyringNote": "GitHub-/Chat-Tokens der Desktop-App liegen im Schlüsselbund des Betriebssystems und sind nicht enthalten; gib sie nach dem Wiederherstellen erneut ein.", + "button": "Wiederherstellen", + "staging": "Wiederherstellung wird vorbereitet…", + "staged": "Wiederherstellung vorbereitet. Neustart…", + "restarting": "Wiederherstellung vorbereitet. Server wird neu gestartet…", + "restartTimeout": "Der Server kam nicht rechtzeitig zurück. Lade die Seite neu, sobald er läuft.", + "externalSideLocation": "Gesprächstranskripte wurden nach {path} wiederhergestellt", + "confirmTitle": "Alle Daten ersetzen?", + "confirmBody": "Dadurch werden deine aktuelle codeg-Datenbank und Uploads durch die Sicherung ersetzt und anschließend neu gestartet. Deine aktuellen Daten werden zuvor als Snapshot gesichert.", + "cancel": "Abbrechen", + "confirmAction": "Ersetzen & neu starten", + "external": { + "title": "Gesprächsinhalte", + "hint": "Diese Sicherung enthält CLI-Transkripte. Wähle, wohin sie wiederhergestellt werden.", + "modeSkip": "Nicht wiederherstellen", + "modeSide": "In einen sicheren Nebenordner wiederherstellen", + "modeOriginal": "An den ursprünglichen CLI-Speicherorten wiederherstellen", + "forceOverwrite": "Vorhandene Dateien überschreiben", + "forceOverwriteHint": "Ersetzt Dateien, die bereits in den CLI-Ordnern vorhanden sind.", + "scanning": "Konflikte werden geprüft…", + "noConflicts": "Es werden keine vorhandenen Dateien überschrieben.", + "conflictCount": "{count} vorhandene Datei(en) wären betroffen.", + "conflictSkipNote": "Vorhandene Dateien bleiben erhalten (übersprungen), sofern du das Überschreiben nicht aktivierst." + }, + "restartFailed": "Wiederherstellung vorbereitet, aber der Server konnte nicht neu starten. Starte ihn manuell neu, um sie anzuwenden." + }, + "remoteUnsupported": "Sicherung & Wiederherstellung wirken auf die Daten des Rechners, auf dem codeg läuft. Du bist mit einem entfernten Arbeitsbereich verbunden – verwalte dessen Sicherungen direkt auf jenem Server." + }, + "backup": { + "restore": { + "error": { + "badPassphrase": "Falsche Passphrase oder beschädigte Sicherung.", + "corrupted": "Das Sicherungsarchiv ist beschädigt.", + "unknownFormat": "Diese Datei ist keine erkannte codeg-Sicherung.", + "newerVersion": "Diese Sicherung wurde mit codeg {backupVersion} erstellt, neuer als diese Version ({appVersion}).", + "alreadyPending": "Es ist bereits eine Wiederherstellung vorbereitet. Starte neu, um sie anzuwenden, bevor du eine weitere vorbereitest." + } + }, + "error": { + "diskSpace": "Nicht genügend Speicherplatz, um den Vorgang abzuschließen.", + "cancelled": "Der Vorgang wurde abgebrochen." + } + }, + "WebConnection": { + "disconnectedTitle": "Verbindung getrennt", + "reconnectingDescription": "Verbindung zum Server wird wiederhergestellt. Das geschieht normalerweise innerhalb weniger Sekunden automatisch.", + "reconnectNow": "Jetzt neu verbinden", + "sessionExpiredTitle": "Sitzung abgelaufen", + "sessionExpiredDescription": "Deine Sitzung ist nicht mehr gültig. Bitte melde dich erneut an, um fortzufahren.", + "goToLogin": "Zur Anmeldung" + }, + "LiveFeedback": { + "placeholder": "Sende {agent} eine Notiz, während er arbeitet…", + "agentFallback": "der Agent", + "ariaLabel": "Live-Feedback-Notiz", + "dialogTitle": "Live-Feedback", + "dialogDescription": "Sende dem Agenten eine Notiz, während er arbeitet. Er liest sie bei der nächsten Prüfung – ohne den aktuellen Schritt zu unterbrechen.", + "dialogDescriptionInstant": "Sende dem Agenten eine Notiz, während er arbeitet. Sie wird sofort in den laufenden Turn eingefügt – der Agent sieht sie umgehend.", + "channelDowngraded": "Sofortiges Einfügen ist in dieser Sitzung nicht verfügbar – deine Notiz wurde gespeichert; der Agent holt sie bei seinem nächsten Check ab.", + "send": "Senden", + "cancel": "Abbrechen", + "pending": "wartet", + "delivered": "erhalten", + "turnEndedUnread": "Der Agent hat die Runde beendet, bevor er dein Feedback gelesen hat.", + "sendAsMessage": "Als Nachricht senden", + "dismiss": "Verwerfen", + "turnEndedResent": "Die Runde endete – stattdessen als neue Nachricht gesendet.", + "turnEnded": "Die Runde ist bereits beendet.", + "submitFailed": "Deine Notiz konnte nicht gesendet werden" + }, + "AgentToolsSettings": { + "title": "Tools in der Unterhaltung", + "description": "Zusätzliche Tools, die codeg einem Agenten innerhalb einer Unterhaltung gibt. Sie werden beim Start des Agenten injiziert – eine Änderung gilt daher für danach gestartete Agenten.", + "feedbackLabel": "Live-Feedback", + "feedbackHint": "Sende einem Agenten Notizen und Korrekturen, während er arbeitet. Unterstützt der Agent sofortiges Einfügen, landet deine Notiz umgehend im laufenden Turn; andernfalls erhält der Agent ein Tool zum Abrufen deines Feedbacks – solche Agenten prüfen es meist nur, wenn du es im Prompt erwähnst, z. B. mit \"prüfe regelmäßig mein Live-Feedback\".", + "questionLabel": "Benutzer fragen", + "questionHint": "Erlaubt Agenten, anzuhalten und dir eine Multiple-Choice-Frage zu stellen, die über dem Eingabefeld der Unterhaltung erscheint. Der Agent wartet, bis du antwortest (oder überspringst).", + "sessionInfoLabel": "Sitzungsinformationen abrufen", + "sessionInfoHint": "Erlaubt Agenten, eine in deiner Nachricht referenzierte Sitzung (ein Sitzungs-Badge) nachzuschlagen, um Titel, Agent, Status, Arbeitsbereich, Token-Verbrauch und letzte Nachrichten zu lesen.", + "automationsLabel": "Automatisierungen erstellen", + "automationsHint": "Speichert die Unterhaltung als Automatisierung, die nach Zeitplan läuft. Standardmäßig aus – sie startet danach selbst Agenten.", + "workTasksLabel": "To-do-Aufgaben erstellen", + "workTasksHint": "Stellt aus der Unterhaltung heraus eine Karte auf das To-do-Board. Standardmäßig aus – schreibt App-Zustand.", + "save": "Speichern", + "saving": "Wird gespeichert…", + "saved": "Tool-Einstellungen gespeichert", + "saveFailed": "Tool-Einstellungen konnten nicht gespeichert werden", + "loadFailed": "Laden fehlgeschlagen: {detail}" + }, + "NotificationSoundSettings": { + "title": "Benachrichtigungstöne", + "description": "Spielt einen kurzen Ton ab, wenn ein Agent-Ereignis eintritt. Es sind dieselben Ereignisse, die an die Chat-Kanäle gesendet werden; diese Einstellung gilt nur für dieses Gerät.", + "enableHint": "Standardmäßig aus. Töne werden nur im Arbeitsbereich-Fenster dieses Browsers oder dieser App abgespielt.", + "volume": "Lautstärke", + "preview": "Anhören", + "previewEvent": "Ton für {event} anhören", + "onlyWhenUnfocused": "Nur wenn das Fenster nicht im Fokus ist", + "onlyWhenUnfocusedHint": "Bleibt stumm, solange du Codeg ansiehst.", + "eventsTitle": "Ereignisse", + "eventsHint": "Wähle pro Ereignis einen Ton oder „Stumm“, um es zu überspringen. Wiederholt sich dasselbe Ereignis innerhalb weniger Sekunden, erklingt es nur einmal.", + "toneNone": "Stumm", + "toneChime": "Glockenspiel", + "toneDing": "Klingel", + "toneBlip": "Blip", + "tonePop": "Pop", + "toneAlert": "Alarm", + "toneDescend": "Absteigend" + }, + "LogsSettings": { + "loading": "Wird geladen…", + "sectionTitle": "Laufzeitprotokolle", + "sectionDescription": "Diagnoseprotokolle der Anwendung anzeigen und konfigurieren. Protokolle werden in lokale Dateien geschrieben und für die Live-Ansicht im Speicher gehalten.", + "captureTitle": "Protokollebene", + "captureDescription": "Steuert, wie viele Details erfasst werden. Höhere Stufen (Debug, Trace) zeichnen mehr auf, erzeugen aber größere Protokolle. „Aus“ deaktiviert die Protokollierung.", + "captureLabel": "Erfassungsebene", + "levels": { + "off": "Aus", + "error": "Fehler", + "warn": "Warnung", + "info": "Info", + "debug": "Debug", + "trace": "Trace" + }, + "viewerTitle": "Aktuelle Protokolle", + "viewerDescription": "Live-Ansicht der letzten Protokolleinträge. Nach Ebene filtern oder Text suchen.", + "searchPlaceholder": "Nachricht oder Ziel suchen…", + "viewLevels": { + "all": "Alle Ebenen", + "error": "Fehler und höher", + "warn": "Warnung und höher", + "info": "Info und höher", + "debug": "Debug und höher", + "trace": "Trace und höher" + }, + "pause": "Pause", + "resume": "Live", + "refresh": "Aktualisieren", + "clear": "Leeren", + "openFolder": "Ordner öffnen", + "shownCount": "{shown} / {total} angezeigt", + "empty": "Keine Protokolle vorhanden.", + "levelSaveFailed": "Protokollebene konnte nicht gespeichert werden", + "openFolderFailed": "Protokollordner konnte nicht geöffnet werden", + "downloadFailed": "Protokolldatei konnte nicht heruntergeladen werden", + "filesTitle": "Protokolldateien", + "filesDescription": "Vollständige Protokolldateien von der Festplatte herunterladen, um den Verlauf über den Live-Puffer hinaus anzuzeigen.", + "filesEmpty": "Noch keine Protokolldateien.", + "download": "Herunterladen", + "downloadTruncated": "Die Datei ist groß; die neuesten {size} wurden heruntergeladen. Die vollständige Datei befindet sich im Log-Verzeichnis.", + "captureEnvLocked": "Die Protokollebene wird durch die Umgebungsvariable RUST_LOG / CODEG_LOG gesteuert; ändere sie dort, damit es wirksam wird.", + "targetsTitle": "Modulspezifische Überschreibungen", + "targetsDescription": "Lege für bestimmte Module (z. B. codeg_lib::acp) eine andere Stufe fest, ohne die globale Stufe zu ändern.", + "targetsAdd": "Hinzufügen", + "targetsRemove": "Überschreibung entfernen", + "toggleDetails": "Details umschalten" + }, + "Automations": { + "title": "Automatisierungen", + "new": "Neue Automatisierung", + "empty": "Noch keine Automatisierungen", + "emptyHint": "Erstelle eine, um eine Agentenaufgabe geplant oder manuell auszuführen.", + "name": "Name", + "namePlaceholder": "z. B. Nächtliche PR-Prüfung", + "prompt": "Eingabe", + "promptPlaceholder": "Was soll der Agent tun?", + "agent": "Agent", + "folder": "Arbeitsbereich-Ordner", + "folderPlaceholder": "Ordner auswählen", + "isolation": "Isolierung", + "isolationWorktree": "Neues Worktree pro Lauf", + "isolationShared": "Im Ordner ausführen", + "isolationSharedCaveat": "Ausführungen verwenden den Arbeitsbaum dieses Ordners direkt und können mit deinen nicht committeten Änderungen kollidieren. Aktiviere die Worktree-Option, um jede Ausführung zu isolieren.", + "trigger": "Auslöser", + "triggerSchedule": "Nach Zeitplan", + "triggerManual": "Nur manuell", + "cron": "Zeitplan (Cron)", + "cronPlaceholder": "0 9 * * 1-5", + "timezone": "Zeitzone", + "nextRun": "Nächster Lauf", + "branch": "Branch", + "branchOptional": "Branch (optional)", + "enabled": "Aktiviert", + "save": "Speichern", + "cancel": "Abbrechen", + "edit": "Bearbeiten", + "delete": "Löschen", + "runNow": "Jetzt ausführen", + "cancelRun": "Lauf abbrechen", + "runHistory": "Laufverlauf", + "noRuns": "Noch keine Läufe", + "allFolders": "Alle Ordner", + "filterAll": "Alle", + "noMatches": "Keine passenden Automatisierungen", + "viewConversation": "Konversation ansehen", + "lastRun": "Letzter Lauf", + "never": "Nie", + "running": "Läuft", + "deleteTitle": "Automatisierung löschen?", + "deleteDescription": "Dies entfernt die Automatisierung und ihren Zeitplan. Der Laufverlauf bleibt erhalten.", + "statusRunning": "Läuft", + "statusSucceeded": "Erfolgreich", + "statusFailed": "Fehlgeschlagen", + "statusCancelled": "Abgebrochen", + "statusSkipped": "Übersprungen", + "errorName": "Name ist erforderlich", + "errorPrompt": "Eingabe ist erforderlich", + "errorCron": "Geplante Automatisierungen benötigen einen Cron-Ausdruck", + "errorFolder": "Wähle einen Arbeitsbereich-Ordner", + "presetHourly": "Stündlich", + "presetDaily": "Täglich 9 Uhr", + "presetWeekdays": "Werktags 9 Uhr", + "presetCustom": "Benutzerdefiniert", + "probing": "Optionen werden geladen…", + "retry": "Erneut versuchen", + "configNone": "Dieser Agent hat keine konfigurierbaren Optionen", + "inherit": "Agent-Standard", + "mode": "Modus", + "config": "Konfiguration", + "branchPlaceholder": "(Standard-Branch)", + "selectHint": "Wähle eine Automatisierung, um Details zu sehen", + "refresh": "Aktualisieren", + "onboardTitle": "Routineaufgaben des Agenten automatisieren", + "onboardHint": "Plane einen Agenten, der Code überprüft, Abhängigkeiten aktualisiert oder Probleme sichtet – nach Zeitplan oder bei Bedarf.", + "headerSubtitle": "Geplante und bedarfsgesteuerte Agentenaufgaben", + "startFromTemplate": "Mit einer Vorlage beginnen", + "blankTitle": "Leere Automatisierung", + "blankDesc": "Eine Agentenaufgabe von Grund auf konfigurieren.", + "backToTemplates": "Vorlagen", + "sectionSchedule": "Zeitplan & Ziel", + "sectionTarget": "Ziel", + "sectionAction": "Aktion", + "actionLaunchSession": "Sitzung starten", + "actionEnqueueTask": "Aufgabe einreihen", + "actionEnqueueTaskHint": "Jede Auslösung fügt den To-dos des Ordners eine To-do-Aufgabe mit dem Namen dieser Automatisierung hinzu; die Task-Engine führt sie gemäß den Board-Einstellungen aus.", + "sectionPrompt": "Prompt", + "nextIn": "Nächste in {rel}", + "manual": "Manuell", + "schedEveryMinutes": "Alle {n} Minuten", + "schedHourly": "Stündlich", + "schedDaily": "Täglich um {time}", + "schedWeekdays": "Wochentags um {time}", + "schedWeekly": "Jeden {day} um {time}", + "schedMonthly": "Monatlich am {day}. um {time}", + "dow0": "Sonntag", + "dow1": "Montag", + "dow2": "Dienstag", + "dow3": "Mittwoch", + "dow4": "Donnerstag", + "dow5": "Freitag", + "dow6": "Samstag", + "tplCodeReviewTitle": "Code-Review", + "tplCodeReviewDesc": "Überprüft aktuelle Änderungen auf Fehler, Regressionen und Qualitätsprobleme.", + "tplDependencyUpdatesTitle": "Abhängigkeits-Updates", + "tplDependencyUpdatesDesc": "Findet veraltete Abhängigkeiten und schlägt sichere Upgrades vor.", + "tplTestCoverageTitle": "Testabdeckung", + "tplTestCoverageDesc": "Findet ungetestete Codepfade und ergänzt die fehlenden Tests.", + "tplTodoSweepTitle": "TODO-Durchsicht", + "tplTodoSweepDesc": "Sammelt TODO- und FIXME-Kommentare und sortiert sie nach Priorität.", + "tplCiTriageTitle": "CI-Sichtung", + "tplCiTriageDesc": "Untersucht kürzlich fehlgeschlagene Prüfungen und schlägt Korrekturen vor.", + "tplReleaseNotesTitle": "Release Notes", + "tplReleaseNotesDesc": "Fasst Änderungen seit dem letzten Release in einem Changelog zusammen.", + "tplSecurityAuditTitle": "Sicherheitsaudit", + "tplSecurityAuditDesc": "Sucht nach Schwachstellen und riskanten Mustern und meldet die Ergebnisse.", + "enable": "Aktivieren", + "disable": "Deaktivieren", + "moreActions": "Weitere Aktionen", + "statusDisabled": "Deaktiviert", + "cronBuilderTitle": "Zeitplan-Generator", + "cronFreqLabel": "Häufigkeit", + "cronFreqMinutes": "Alle N Minuten", + "cronFreqHourly": "Stündlich", + "cronFreqDaily": "Täglich", + "cronFreqWeekdays": "Wochentags", + "cronFreqWeekly": "Wöchentlich", + "cronFreqMonthly": "Monatlich", + "cronFreqCustom": "Benutzerdefiniert", + "cronEveryLabel": "Intervall (Minuten)", + "cronTimeLabel": "Uhrzeit", + "cronHourLabel": "Stunde", + "cronMinuteLabel": "Minute", + "cronDowLabel": "Wochentag", + "cronDomLabel": "Tag des Monats", + "cronApply": "Anwenden", + "cronPreviewLabel": "Vorschau", + "cronOpenBuilder": "Zeitplan-Generator öffnen", + "branchDefault": "Standard-Branch", + "branchUseCustom": "„{query}“ verwenden", + "branchLocal": "Lokal", + "branchRemote": "Remote", + "branchSearchPlaceholder": "Branches suchen…", + "branchNone": "Keine Branches" + }, + "Tasks": { + "title": "To-dos", + "new": "Neue Aufgabe", + "empty": "Noch keine Aufgaben", + "emptyHint": "Füge ein To-do hinzu und starte es — der Agent arbeitet in einem isolierten Worktree, du prüfst und mergst das Ergebnis.", + "emptyColTodo": "Noch keine To-dos", + "emptyColInProgress": "Nichts in Arbeit", + "emptyColAttention": "Nichts wartet auf dich", + "emptyColDone": "Noch nichts fertig", + "allFolders": "Alle Ordner", + "showCanceled": "Abgebrochene anzeigen", + "showArchived": "Archivierte anzeigen", + "filter": "Filter", + "viewSwitchToBoard": "Zur Board-Ansicht wechseln", + "viewSwitchToList": "Zur Listenansicht wechseln", + "statusFilter": "Status", + "statusFilterAll": "Alle Status", + "listEmpty": "Keine Aufgabe entspricht den aktuellen Filtern", + "listColStatus": "Status", + "listColTask": "Aufgabe", + "listColLocation": "Ort", + "listColChanges": "Änderungen", + "listColUpdated": "Aktualisiert", + "colTodo": "To-do", + "colInProgress": "In Arbeit", + "colAttention": "Wartet auf dich", + "colDone": "Fertig", + "statusTodo": "To-do", + "statusQueued": "In Warteschlange", + "statusPreparing": "Wird vorbereitet", + "statusRunning": "Läuft", + "statusAwaitingInput": "Wartet auf Eingabe", + "statusReview": "Zur Prüfung", + "statusMerging": "Wird gemergt", + "statusDone": "Fertig", + "statusFailed": "Fehlgeschlagen", + "statusCanceled": "Abgebrochen", + "statusInterrupted": "Unterbrochen", + "badgeCleanupFailed": "Aufräumen fehlgeschlagen", + "badgeWorktreeKept": "Worktree behalten", + "badgeWorktreeRemoved": "Worktree entfernt", + "filesChanged": "{count} Dateien", + "actionStart": "Starten", + "actionSchedule": "Planen", + "actionCancel": "Abbrechen", + "actionRetry": "Erneut versuchen", + "actionRequeue": "Erneut einreihen", + "actionViewSession": "Konversation anzeigen", + "actionEdit": "Bearbeiten", + "actionDelete": "Löschen", + "actionRetryCleanup": "Aufräumen wiederholen", + "actionMerge": "Mergen", + "actionUnqueueMerge": "Merge-Warteschlange verlassen", + "actionEditQueuedMerge": "Wartenden Merge bearbeiten", + "badgeMergeQueued": "Wartet auf Merge", + "badgeMergeQueuedRank": "Wartet auf Merge · Nr. {rank}", + "badgeMergeQueuedHint": "Wartet, bis der laufende Merge des Projekts fertig ist; dieser startet dann von selbst.", + "actionComplete": "Abschließen", + "actionAbandon": "Verwerfen", + "cancelTitle": "Aufgabe abbrechen?", + "cancelDescription": "Die Aufgabe wird auf Abgebrochen gesetzt. Ihr Worktree bleibt erhalten und du kannst sie später erneut einreihen.", + "cancelReasonLabel": "Grund (optional)", + "cancelReasonPlaceholder": "Z. B. falscher Ansatz – ich schreibe die Beschreibung neu", + "cancelKeep": "Doch nicht", + "cancelSubmit": "Aufgabe abbrechen", + "restartTitleRetry": "Aufgabe erneut versuchen", + "restartTitleRequeue": "Aufgabe erneut einreihen", + "restartDescription": "Du kannst eine Notiz ergänzen (optional) – sie landet im Prompt des nächsten Laufs.", + "scheduleTitle": "Aufgabe planen", + "scheduleDescription": "Die Aufgabe bleibt im To-do und startet zur gewählten Zeit von selbst. Das Parallelitätslimit des Ordners gilt weiterhin.", + "scheduleDateLabel": "Datum", + "schedulePickDate": "Datum wählen", + "scheduleTimeLabel": "Uhrzeit", + "schedulePreview": "Läuft am {time}", + "schedulePastHint": "Dieser Zeitpunkt liegt in der Vergangenheit – die Aufgabe startet direkt nach dem Speichern.", + "scheduleInAnHour": "In 1 Stunde", + "scheduleInThreeHours": "In 3 Stunden", + "scheduleTomorrow": "Morgen 9:00", + "scheduleClear": "Planung entfernen", + "scheduleBadge": "Geplanter Start: {time}", + "toastScheduled": "Geplant für {time}", + "toastScheduleCleared": "Planung entfernt", + "actionFollowUp": "Nachfassen", + "actionAddNote": "Hinweis ergänzen", + "followUpSubmit": "Senden", + "followUpIntentRevise": "Überarbeiten", + "followUpIntentContinue": "Weitermachen", + "followUpIntentQuestion": "Nachfragen", + "followUpIntentVerify": "Selbstprüfung", + "followUpPlaceholderRevise": "Was soll der Agent ändern? Er macht in derselben Sitzung weiter.", + "followUpPlaceholderContinue": "Was kommt als Nächstes? Das Bisherige bleibt bestehen.", + "followUpPlaceholderQuestion": "Was möchtest du wissen? Der Agent antwortet, ohne Dateien anzufassen.", + "followUpPlaceholderVerify": "Optional: Worauf soll es besonders achten?", + "followUpPlaceholderRetry": "Optional: Was soll diesmal anders laufen? Z. B. zuerst pnpm install ausführen", + "followUpPlaceholderRequeue": "Optional: Warum hast du abgebrochen, und was soll diesmal anders sein?", + "actionArchive": "Archivieren", + "actionUnarchive": "Dearchivieren", + "archiveAllDone": "Alle archivieren", + "dropToStart": "Loslassen zum Starten", + "errorView": "Ansehen", + "notifyReview": "Bereit zur Abnahme: {title}", + "notifyFailed": "Aufgabe fehlgeschlagen: {title}", + "createFromMessage": "Aufgabe aus Nachricht erstellen", + "detailTokens": "Token insgesamt", + "editorTitleNew": "Neue Aufgabe", + "editorTitleEdit": "Aufgabe bearbeiten", + "templates": "Vorlagen", + "templatesEmpty": "Noch keine Vorlagen.", + "templateSaveCurrent": "Aktuelles als Vorlage speichern", + "templateDelete": "Vorlage löschen", + "transcriptTitle": "Aufgaben-Konversation", + "transcriptDescription": "Schreibgeschützte Live-Ansicht der Agentensitzung dieser Aufgabe.", + "phaseWork": "Ausführung", + "phaseRetry": "Neuversuch", + "phaseReturn": "Nachfassen", + "phaseMerge": "Merge", + "titleLabel": "Titel", + "titlePlaceholder": "Was ist zu tun?", + "promptLabel": "Aufgabenbeschreibung", + "promptPlaceholder": "Beschreibe die Aufgabe für den Agenten — @ für Dateiverweise, / für Befehle", + "folderPlaceholder": "Ordner wählen", + "agentInheritedHint": "Aus den Aufgaben-Einstellungen geerbt — Änderungen gelten nur für diese Aufgabe", + "agentOverrideReset": "Wieder erben", + "sectionTarget": "Ziel", + "errorTitle": "Titel ist erforderlich", + "errorPrompt": "Beschreibung ist erforderlich", + "errorFolder": "Ordner wählen", + "save": "Speichern", + "cancel": "Abbrechen", + "mergeTitle": "Aufgabe mergen", + "mergeQueuedTitle": "Wartender Merge", + "mergeQueueHint": "Eine andere Aufgabe dieses Projekts wird gerade gemergt. Diese reiht sich ein und startet von selbst, sobald die andere fertig ist.", + "mergeQueueUpdateHint": "Diese Aufgabe wartet bereits auf den Merge. Beim Absenden wird sie aktualisiert und behält ihren Platz in der Warteschlange.", + "mergeDescription": "{branch} in {base} mergen. Nicht committete Änderungen im Worktree werden zuerst committet.", + "mergeMessage": "Commit-Nachricht", + "mergeMessagePlaceholder": "z. B. feat: add login validation", + "mergeAutoMessage": "Commit-Nachricht vom Agenten schreiben lassen", + "strategySquash": "Zu einem Commit zusammenfassen", + "strategySquashHint": "Alle Änderungen der Aufgabe landen als ein einzelner Eintrag im Verlauf des Hauptbranchs — der Verlauf bleibt übersichtlich.", + "strategyMerge": "Gesamten Verlauf behalten", + "strategyMergeHint": "Jeder während der Aufgabe erstellte Commit bleibt erhalten, plus ein Merge-Eintrag — jeder Schritt bleibt nachvollziehbar.", + "mergeDeleteWorktree": "Worktree nach dem Merge löschen", + "mergeSubmit": "Mergen", + "mergeSubmitQueue": "In die Warteschlange", + "mergeQueuedToast": "Zur Merge-Warteschlange hinzugefügt – startet, sobald der laufende Merge fertig ist.", + "completeTitle": "Aufgabe abschließen", + "completeDescription": "Diese Aufgabe hat keine Dateien geändert – es gibt nichts zu mergen, sie wird direkt als fertig markiert.", + "completeDescriptionNoWorktree": "Der Worktree dieser Aufgabe wurde entfernt – es kann nichts mehr gemergt werden, sie wird direkt als fertig markiert. Ein Arbeitsbranch mit noch nicht gemergten Commits bleibt erhalten.", + "completeDeleteWorktree": "Worktree nach dem Abschließen löschen", + "completeSubmit": "Abschließen", + "settingsTitle": "Aufgaben-Einstellungen", + "settingsDescription": "Standardwerte für Aufgaben in {folder}.", + "settingsScope": "Geltungsbereich", + "settingsScopeGlobal": "Alle Ordner (globale Standardwerte)", + "settingsScopeGlobalHint": "Ordner ohne eigene Einstellungen verwenden diese globalen Standardwerte.", + "settingsSource": "Konfigurationsquelle", + "settingsSourceGlobal": "Globale Standards", + "settingsSourceCustom": "Eigene", + "settingsSourceGlobalFollow": "Folgt den globalen Aufgaben-Einstellungen — Änderungen dort gelten hier automatisch.", + "settingsSourceCustomHint": "Speichert eigene Einstellungen für diesen Ordner; die globalen Standards gelten dann nicht mehr.", + "settingsAgent": "Standard-Agent", + "settingsMaxConcurrent": "Max. gleichzeitige Aufgaben", + "settingsMaxConcurrentHint": "0 = unbegrenzt", + "settingsAutoProcess": "Automatisch verarbeiten", + "settingsAutoProcessHint": "Offene Aufgaben starten von selbst, bis zum Parallelitätslimit.", + "settingsMergeStrategy": "Standard-Merge-Strategie", + "settingsMergeStrategyHint": "Wie die Änderungen der Aufgabe beim Mergen im Branch-Verlauf festgehalten werden.", + "settingsAutoMerge": "Automatisch mergen", + "settingsAutoMergeHint": "Eine Aufgabe, die mit landbaren Änderungen das Review erreicht, wird gemergt, als hättest du auf Mergen geklickt: Der Agent schreibt die Commit-Nachricht, der Worktree folgt der Voreinstellung unten. Bei rotem Preflight oder einem fehlgeschlagenen Merge wartet die Aufgabe auf dich.", + "settingsDeleteWorktree": "Worktree nach dem Mergen löschen", + "settingsDeleteWorktreeHint": "Aktiviert die Option im Merge-Dialog vor; dort lässt sie sich weiterhin ändern.", + "settingsWorktreeRoot": "Worktree-Verzeichnis", + "settingsWorktreeRootHint": "Verzeichnis, in dem neue Aufgaben-Worktrees angelegt werden – eines pro Aufgabe. Leer lassen, um sie neben dem Projektordner anzulegen; „~“ ist dein Home-Verzeichnis, ein relativer Pfad gilt relativ zum Projektordner.", + "settingsWorktreeRootPlaceholder": "~/codeg-worktrees", + "settingsWorktreeRootBrowse": "Worktree-Verzeichnis auswählen", + "settingsPreflight": "Preflight-Befehl", + "settingsPreflightHint": "Läuft im Worktree, sobald eine Aufgabe das Review erreicht.", + "settingsPreflightCustomPlaceholder": "pnpm test", + "settingsInitCommand": "Worktree-Init-Befehl", + "settingsInitCommandHint": "Läuft in einem frisch erstellten Worktree, bevor der Agent startet.", + "settingsInitCommandPlaceholder": "pnpm install", + "settingsTabGeneral": "Allgemein", + "settingsTabMerge": "Merge", + "settingsTabWorktree": "Worktree", + "settingsTabPrompts": "Prompts", + "settingsPromptsIntro": "Jede Phase sendet bereits einen eingebauten Prompt — die Aufgabe selbst, die Worktree-Regeln und beim Mergen die genauen Git-Schritte. Was du hier ergänzt, wird als zusätzliche Anweisung ans Ende gehängt: Es verfeinert den eingebauten Text, ersetzt ihn aber nie.", + "settingsPromptStageAll": "Alle Phasen", + "settingsPromptPlaceholderAll": "z. B. Halte dich an die Konventionen in AGENTS.md; fasse am Ende in zwei Sätzen zusammen", + "settingsPromptPlaceholderWork": "z. B. Lies zuerst die zugehörigen Tests; committe in kleinen Schritten", + "settingsPromptPlaceholderRetry": "z. B. Prüfe vor dem Weitermachen, was bereits committet ist; wiederhole nichts Fertiges", + "settingsPromptPlaceholderReturn": "Z. B. Arbeite jeden genannten Punkt ab; refaktoriere nichts Fremdes", + "settingsPromptPlaceholderMerge": "z. B. Schreibe die Merge-Commit-Nachricht auf Deutsch; nenne jeden manuell gelösten Konflikt", + "settingsPromptHintAll": "Wird an jeden Prompt des Agents angehängt, auch beim Merge-Lauf.", + "settingsPromptHintWork": "Wird angehängt, wenn eine Aufgabe zum ersten Mal läuft.", + "settingsPromptHintRetry": "Wird angehängt, wenn eine unterbrochene oder fehlgeschlagene Aufgabe fortgesetzt wird.", + "settingsPromptHintReturn": "Wird ergänzt, wenn du bei einer Aufgabe in Prüfung nachfasst (überarbeiten, erweitern, prüfen).", + "settingsPromptHintMerge": "Wird angehängt, wenn der Agent die Aufgabe in den Basis-Branch übernimmt.", + "preflightPassed": "{name} bestanden", + "preflightFailed": "{name} fehlgeschlagen", + "preflightRunning": "{name} läuft…", + "detailDescription": "Aufgabendetails", + "detailSummary": "Ergebnis", + "detailFiles": "Geänderte Dateien", + "detailDiffAll": "Gesamtes Diff anzeigen", + "detailDiffAllTitle": "Gesamtes Diff", + "detailNoChanges": "Noch keine Änderungen gegenüber der Basis", + "detailTimeline": "Verlauf", + "detailTimelineEmpty": "Noch keine Aktivität", + "showMore": "Mehr anzeigen", + "showLess": "Weniger anzeigen", + "detailInfo": "Details", + "detailBranch": "Branch", + "detailMergeCommit": "Merge-Commit", + "detailChanges": "Änderungen", + "detailScheduled": "Geplanter Start", + "detailCreated": "Erstellt", + "detailStarted": "Gestartet", + "detailFinished": "Abgeschlossen", + "diffLoading": "Diff wird geladen…", + "deleteConfirmTitle": "Aufgabe löschen?", + "deleteConfirmBody": "„{title}“ wird vom Board entfernt. Ein aktiver Lauf wird zuerst abgebrochen.", + "deleteWithWorktree": "Auch den Worktree löschen", + "eventCreated": "Erstellt", + "eventStatusChanged": "Statusänderung", + "eventConfigEffective": "Startkonfiguration", + "eventInitCommand": "Init-Befehl", + "eventAgentProgress": "Agent-Fortschritt", + "eventAgentVerdict": "Agent-Urteil", + "eventMergeAttempt": "Merge gestartet", + "eventMergeQueued": "In Merge-Warteschlange", + "eventMergeConflict": "Merge-Konflikt", + "eventPreflight": "Preflight", + "eventCleanupFailed": "Worktree-Aufräumen fehlgeschlagen", + "eventResumeFallback": "Sitzungsfortsetzung fehlgeschlagen, neue Sitzung", + "eventUserAction": "Benutzeraktion", + "eventDiffStat": "Änderungs-Snapshot" + }, + "CustomSkillsSettings": { + "loading": "Benutzerdefinierte Skills werden geladen…", + "category": "Benutzerdefiniert", + "searchPlaceholder": "Benutzerdefinierte Skills nach Name, ID oder Beschreibung suchen", + "states": { + "not_linked": "Nicht aktiviert", + "linked_to_codeg": "Aktiviert", + "linked_elsewhere": "Anderweitig verknüpft", + "blocked_by_real_directory": "Durch echten Ordner blockiert", + "broken": "Defekter Link" + }, + "actions": { + "new": "Neu", + "import": "Importieren", + "importFromAgent": "Von Agent importieren", + "cancel": "Abbrechen", + "save": "Speichern" + }, + "rowMenu": { + "edit": "Bearbeiten", + "duplicate": "Duplizieren", + "delete": "Löschen" + }, + "bulk": { + "delete": "Auswahl löschen" + }, + "editor": { + "createTitle": "Neuer benutzerdefinierter Skill", + "editTitle": "Benutzerdefinierten Skill bearbeiten", + "description": "Benutzerdefinierte Skills liegen im gemeinsamen Speicher (~/.codeg/skills) und können für jeden Agenten aktiviert werden.", + "idLabel": "Skill-ID", + "idPlaceholder": "z. B. my-workflow", + "contentLabel": "SKILL.md", + "contentPlaceholder": "Hier die SKILL.md des Skills schreiben…", + "preview": "Vorschau", + "edit": "Bearbeiten", + "emptyBody": "Noch kein Inhalt." + }, + "duplicate": { + "title": "Skill duplizieren", + "description": "Eine Kopie von „{id}“ mit einer neuen ID erstellen.", + "newIdPlaceholder": "Neue Skill-ID", + "confirm": "Duplizieren" + }, + "import": { + "title": "Skill-Ordner zum Importieren wählen" + }, + "importFromAgent": { + "title": "Skills von einem Agenten importieren", + "description": "Kopiere die eigenen Skills eines Agenten in den gemeinsamen Speicher, um sie für jeden Agenten zu aktivieren.", + "agentLabel": "Agent", + "agentPlaceholder": "Agent auswählen", + "selectAll": "Alle auswählen ({count})", + "loading": "Skills des Agenten werden geladen…", + "unsupported": "Dieser Agent stellt kein Skill-Verzeichnis bereit.", + "empty": "Dieser Agent hat keine importierbaren Skills.", + "alreadyInLibrary": "In Bibliothek", + "confirm": "Auswahl importieren ({count})" + }, + "delete": { + "title": "Benutzerdefinierte Skills löschen?", + "body": "Dadurch werden {count} benutzerdefinierte Skill(s) aus dem zentralen Speicher entfernt und von allen Agenten getrennt. Dies kann nicht rückgängig gemacht werden.", + "confirm": "Löschen" + }, + "toasts": { + "loadFailed": "Skill konnte nicht geladen werden", + "idRequired": "Bitte eine Skill-ID eingeben", + "created": "Benutzerdefinierter Skill erstellt", + "updated": "Benutzerdefinierter Skill aktualisiert", + "saveFailed": "Skill konnte nicht gespeichert werden", + "imported": "Skill importiert", + "importFailed": "Skill konnte nicht importiert werden", + "duplicated": "Skill dupliziert", + "duplicateFailed": "Skill konnte nicht dupliziert werden", + "deleted": "{count} Skill(s) gelöscht", + "deletedPartial": "{ok} gelöscht, {failed} fehlgeschlagen", + "deleteFailed": "Skills konnten nicht gelöscht werden", + "importedFromAgent": "{count} Skill(s) importiert", + "importedFromAgentPartial": "{ok} importiert, {failed} fehlgeschlagen", + "importFromAgentAllSkipped": "Nichts zu importieren – {count} bereits in der Bibliothek", + "importFromAgentFailed": "Import vom Agenten fehlgeschlagen" + } + }, + "CodexModelEditor": { + "customizedNotice": "Du hast die Modellliste angepasst, daher verwaltet codeg jetzt die gesamte Modelltabelle von codex. Offizielle Modelle, die codex später hinzufügt, erscheinen nicht automatisch – klicke unten auf Aktualisieren und speichere erneut, um sie zu übernehmen. Entferne alle Anpassungen, damit codex sich wieder automatisch aktualisiert.", + "officialsTitle": "Offizielle Modelle", + "officialsHint": "Automatisch aus dem gestarteten codex übernommen; nicht benötigte entfernen.", + "officialsEmpty": "Keine offiziellen Modelle verfügbar.", + "refresh": "Aus codex aktualisieren", + "readdOfficial": "Offizielles erneut hinzufügen", + "customsTitle": "Benutzerdefinierte Modelle", + "customsEmpty": "Noch keine benutzerdefinierten Modelle.", + "addCustom": "Benutzerdefiniert hinzufügen", + "slugPlaceholder": "Modell-ID (Slug)", + "displayNamePlaceholder": "Anzeigename", + "contextWindow": "Kontext", + "makeDefault": "Als Standard festlegen", + "defaultHint": "Standardmodell", + "remove": "Entfernen", + "advanced": "Erweitert", + "baseTemplate": "Basisvorlage", + "baseTemplateHint": "Offizielles Modell, von dem Pflichtfelder (System-Prompt, Tools, Limits) geklont werden.", + "groupBehavior": "Verhalten & Funktionen", + "fieldReasoningLevel": "Standard-Reasoning", + "fieldReasoningSummary": "Reasoning-Zusammenfassung", + "fieldVerbosity": "Ausführlichkeit", + "fieldShellType": "Shell-Typ", + "fieldApplyPatch": "Apply-Patch-Tool", + "fieldReasoningSummaries": "Reasoning-Zusammenfassungen", + "fieldSupportVerbosity": "Ausführlichkeitssteuerung", + "fieldParallelToolCalls": "Parallele Tool-Aufrufe", + "fieldSearchTool": "Websuche-Tool", + "optNone": "Keine", + "groupInstructions": "Beschreibung & System-Prompt", + "fieldDescription": "Beschreibung", + "baseInstructions": "System-Prompt (base_instructions)" + }, + "DiagnosticsSettings": { + "title": "Umgebungsdiagnose", + "description": "Prüft, wie diese App die Agent-CLI im eigenen Prozess auflöst – das kann sich von deinem Terminal unterscheiden.", + "loading": "Diagnose wird ausgeführt…", + "error": "Diagnose fehlgeschlagen", + "rerun": "Erneut ausführen", + "copyAll": "Alles kopieren", + "copied": "Diagnose in die Zwischenablage kopiert", + "button": "Diagnose", + "verdict": { + "ok": "Die Umgebung sieht in Ordnung aus. Wird trotzdem „nicht installiert“ angezeigt, starte die App komplett neu, um den Prefix-Cache zu aktualisieren.", + "node_missing": "Node.js wurde im PATH der App nicht gefunden.", + "npm_missing": "npm wurde im PATH der App nicht gefunden.", + "not_installed": "Dieser Agent scheint nicht installiert zu sein.", + "installed_but_unresolved": "Als installiert vermerkt, aber die App findet die ausführbare Datei nicht.", + "user_prefix_not_on_path": "In das Ausweich-Prefix (~/.codeg/npm-global) installiert, das nicht im PATH der App liegt. Starte die App komplett neu und versuche es erneut.", + "homebrew_bin_not_on_path": "Unter dem Homebrew-bin installiert, das nicht im PATH der App liegt (Apple-Silicon-Keg-Trennung).", + "terminal_only_path": "Der Befehl wird in deinem Terminal aufgelöst, aber nicht in der App – eine GUI-PATH-Lücke. Starte die App aus einem Terminal oder installiere sie in den Agent-Einstellungen neu.", + "npm_prefix_timeout": "npm prefix -g war zu langsam (über 1,5 s), daher wurde die Ausweicherkennung übersprungen. Starte die App neu und versuche es erneut.", + "node_too_old": "Dein aktives Node.js ist älter als von diesem Agenten benötigt. Aktualisiere Node.js.", + "adapter_missing_native_present": "Deine eigene {agent}-CLI ist installiert, aber Codeg startet ein separates ACP-Adapterpaket — und das fehlt noch. Installiere es in den Agenten-Einstellungen; es rührt deine CLI nicht an und teilt sich dieselbe Anmeldung.", + "adapter_missing": "Codeg startet für {agent} ein separates ACP-Adapterpaket, das noch nicht installiert ist. Installiere es in den Agenten-Einstellungen — die Hersteller-CLI allein genügt nicht." + } + }, + "TokenUsage": { + "title": "Token-Verbrauch", + "rangeLabel": "Zeitraum", + "range7d": "7 Tage", + "range30d": "30 Tage", + "range90d": "90 Tage", + "rangeThisMonth": "Dieser Monat", + "rangeThisYear": "Dieses Jahr", + "rangeAll": "Gesamt", + "rangeCustom": "Benutzerdefiniert", + "moreRanges": "Mehr", + "customRangePick": "Zeitraum wählen", + "bucketLabel": "Gruppieren nach", + "bucketDay": "Tag", + "bucketWeek": "Woche", + "bucketMonth": "Monat", + "bucketUnitDay": "Tag", + "bucketUnitWeek": "Woche", + "bucketUnitMonth": "Monat", + "folderFilter": "Ordner", + "allFolders": "Alle Ordner", + "agentFilter": "Agenten", + "allAgents": "Alle Agenten", + "modelFilter": "Modelle", + "allModels": "Alle Modelle", + "searchPlaceholder": "Suchen…", + "noMatches": "Keine Treffer", + "clearFilter": "Auswahl löschen", + "resetFilters": "Filter zurücksetzen", + "refresh": "Aktualisieren", + "rebuild": "Alles neu aufbauen", + "rebuildHint": "Verwirft die gezählten Daten und liest alle Sitzungsprotokolle neu ein. Nützlich, wenn eine Sitzung außerhalb von codeg gewachsen ist.", + "syncing": "Sitzungen werden gezählt…", + "syncProgress": "{done} / {total}", + "syncDone": "{synced} Sitzungen gezählt", + "syncFailed": "Einige Sitzungen konnten nicht gelesen werden", + "syncBusy": "Eine Aktualisierung läuft bereits", + "lastSynced": "Aktualisiert {time}", + "lastSyncedNever": "Noch nie aktualisiert", + "tileTotal": "Tokens gesamt", + "tileSessions": "Sitzungen", + "tileTurns": "Turns", + "tileActiveDays": "Aktive Tage", + "tileGenTime": "Generierungszeit", + "vsPrevious": "ggü. Vorperiode", + "deltaNew": "neu", + "trendTitle": "Verbrauch im Zeitverlauf", + "trendEmpty": "Kein Verbrauch in diesem Zeitraum", + "trendTurns": "Turns", + "trendSessions": "Sitzungen", + "compositionTitle": "Wofür die Tokens draufgingen", + "compositionHint": "Eingabe ist, was du gesendet hast, Ausgabe, was das Modell geschrieben hat, und Cache-Lesevorgänge sind Kontext, den du nicht voll bezahlt hast.", + "compositionNote": "Diese Cache-Treffer zum vollen Preis erneut zu senden hätte weitere {value} gekostet.", + "inputTokens": "Eingabe", + "outputTokens": "Ausgabe", + "cacheWrite": "Cache-Schreiben", + "cacheRead": "Cache-Lesen", + "freshTokens": "Frisch berechnet", + "cacheHitCaption": "Cache-Treffer", + "cacheHeroTitleHigh": "Der Großteil des Kontexts musste nie erneut gesendet werden", + "cacheHeroTitleLow": "Der Großteil des Kontexts wird noch voll berechnet", + "cacheHeroDesc": "{cached} des Kontexts trug der Cache — nur {fresh} wurde in diesem Zeitraum wirklich neu berechnet.", + "cacheSavedSuffix": "Das sparte erneutes Senden im Umfang von {saved}.", + "avgPerSession": "Ø pro Sitzung", + "avgTurnsPerSession": "Ø {count} Turns pro Sitzung", + "avgPerActiveDay": "Ø pro aktivem Tag", + "peakBucket": "Stärkste(r) {bucket}", + "peakHour": "Spitzenstunde", + "daysValue": "{count} Tage", + "idleDays": "Leerlauftage", + "byFolderTitle": "Nach Ordner", + "byAgentTitle": "Nach Agent", + "byModelTitle": "Nach Modell", + "distributionTitle": "Verteilung der Nutzung", + "distributionHint": "Sitzungen und Tokens nach gewählter Dimension gebündelt — Klick auf eine Zeile filtert danach.", + "otherLabel": "Sonstige", + "unknownModel": "Modell nicht erfasst", + "emptyBreakdown": "Noch nichts erfasst", + "sessionsCount": "{count} Sitzungen", + "heatmapTitle": "Wann du baust", + "heatmapHint": "Tokens nach lokalem Wochentag und Stunde.", + "heatmapPeakHint": "Am dichtesten gegen {hour}:00 Uhr.", + "less": "Weniger", + "more": "Mehr", + "heatmapCell": "{weekday} {hour}:00 — {value} Tokens", + "weekMon": "Mo", + "weekTue": "Di", + "weekWed": "Mi", + "weekThu": "Do", + "weekFri": "Fr", + "weekSat": "Sa", + "weekSun": "So", + "topSessionsTitle": "Teuerste Sitzungen", + "untitledSession": "Unbenannte Sitzung", + "topSessionsEmpty": "Keine Sitzungen in diesem Zeitraum", + "streakLongest": "Längste Serie", + "streakLongestDays": "Längste Serie: {count} Tage", + "share": "Teilen", + "moreActions": "Weitere Aktionen", + "shareDialogTitle": "Teile deine Verbrauchskarte", + "shareDialogHint": "Eine Momentaufnahme des gewählten Zeitraums und der Filter.", + "shareSave": "Bild speichern", + "shareCopy": "Bild kopieren", + "shareCopied": "In die Zwischenablage kopiert", + "shareSaved": "Bild gespeichert", + "shareFailed": "Bild konnte nicht erstellt werden", + "shareRendering": "Wird erstellt…", + "cardHeading": "Meine KI-Coding-Bilanz", + "cardRangeAll": "Gesamter Zeitraum", + "cardTotalLabel": "Verbrauchte Tokens", + "cardFooter": "Erstellt mit codeg", + "cardTopModels": "Top-Modelle", + "cardTopProjects": "Top-Projekte", + "archetypeNightOwl": "Nachteule", + "archetypeNightOwlDesc": "{percent}% deiner Tokens gehen nach Einbruch der Dunkelheit drauf.", + "archetypeEarlyBird": "Frühaufsteher", + "archetypeEarlyBirdDesc": "{percent}% deiner Tokens fallen vor 9 Uhr an.", + "archetypeWeekendWarrior": "Wochenendkrieger", + "archetypeWeekendWarriorDesc": "{percent}% deiner Tokens entstehen am Wochenende.", + "archetypeCacheMaster": "Cache-Meister", + "archetypeCacheMasterDesc": "{percent}% deines Kontexts kamen aus dem Cache.", + "archetypeMarathoner": "Marathonläufer", + "archetypeMarathonerDesc": "{days} Tage am Stück gebaut.", + "archetypePolyglot": "Allrounder", + "archetypePolyglotDesc": "{count} Agenten im ernsthaften Einsatz.", + "archetypeLaserFocus": "Laserfokus", + "archetypeLaserFocusDesc": "{percent}% deiner Tokens gingen in ein einziges Projekt.", + "archetypeDeepDiver": "Tieftaucher", + "archetypeDeepDiverDesc": "{averageK}K Tokens in einer durchschnittlichen Sitzung.", + "archetypeSteady": "Stetiger Bauer", + "archetypeSteadyDesc": "{days} Tage geliefert.", + "emptyTitle": "Noch nichts gezählt", + "emptyHint": "Codeg liest die Token-Zahlen direkt aus dem Protokoll jedes Agenten. Aktualisiere, um zu zählen, was schon auf diesem Rechner liegt.", + "emptyAction": "Meine Sitzungen zählen", + "loadFailed": "Verbrauch konnte nicht geladen werden", + "truncatedNotice": "Dieser Zeitraum ist sehr groß — die Zahlen decken nur seinen jüngsten Abschnitt ab." + } +} diff --git a/src/i18n/messages/en.json b/src/i18n/messages/en.json index 273af3aa0..7c9c876d7 100644 --- a/src/i18n/messages/en.json +++ b/src/i18n/messages/en.json @@ -1,4956 +1,4958 @@ -{ - "Language": { - "followSystem": "Follow System", - "english": "English", - "simplifiedChinese": "Simplified Chinese", - "traditionalChinese": "Traditional Chinese", - "japanese": "Japanese", - "korean": "Korean", - "spanish": "Spanish", - "german": "German", - "french": "French", - "portuguese": "Portuguese", - "arabic": "Arabic" - }, - "GitCredentialDialog": { - "title": "Authentication Required", - "description": "The remote server requires credentials. Enter your username and password (or personal access token).", - "username": "Username", - "usernamePlaceholder": "Username or email", - "password": "Password / Token", - "passwordPlaceholder": "Password or personal access token", - "passwordHint": "For non-GitHub servers, enter your username and password.", - "cancel": "Cancel", - "authenticate": "Authenticate", - "authenticating": "Authenticating...", - "invalidCredentials": "Invalid credentials. Please try again.", - "saveCredentials": "Save credentials for future operations", - "githubTitle": "GitHub Authentication", - "githubDescription": "Enter a personal access token to authenticate with GitHub. The token will be validated and saved to your accounts.", - "githubToken": "Personal Access Token", - "githubTokenPlaceholder": "ghp_xxxxxxxxxxxx", - "githubTokenHint": "Generate a token at GitHub → Settings → Developer settings → Personal access tokens.", - "githubAuthenticate": "Validate & Connect", - "generateToken": "Generate token" - }, - "SettingsShell": { - "title": "Settings", - "preferences": "Preferences", - "nav": { - "general": "General", - "appearance": "Appearance", - "agents": "Agents", - "mcp": "MCP", - "skills": "Skills", - "shortcuts": "Shortcuts", - "version_control": "Version Control", - "system": "System", - "chat_channels": "Chat Channels", - "web_service": "Web Service", - "model_providers": "Model Providers", - "experts": "Experts", - "science": "Science", - "office_tools": "Office Tools", - "skill_packs": "Skill Packs", - "quick_messages": "Quick Messages", - "logs": "Runtime Logs" - } - }, - "AppearanceSettings": { - "sectionTitle": "Theme Appearance", - "sectionDescription": "Choose light, dark, or follow system. Settings are saved automatically.", - "themeMode": "Theme mode", - "placeholder": "Select theme mode", - "system": "Follow system", - "light": "Light", - "dark": "Dark", - "currentTheme": "Current effective theme: {theme}", - "resolvedTheme": { - "light": "Light", - "dark": "Dark", - "unknown": "--" - }, - "themeColor": { - "sectionTitle": "Theme color", - "sectionDescription": "Pick a color palette for accents, buttons, and highlights.", - "current": "Current color: {color}", - "options": { - "neutral": "Neutral", - "zinc": "Zinc", - "slate": "Slate", - "stone": "Stone", - "gray": "Gray", - "red": "Red", - "rose": "Rose", - "orange": "Orange", - "green": "Green", - "blue": "Blue", - "yellow": "Yellow", - "violet": "Violet" - } - }, - "customStyle": { - "sectionTitle": "Custom Style", - "sectionDescription": "Fine-tune the current theme's colors, or inject your own CSS. Overrides sit on top of the base preset, so switching presets keeps them.", - "summarySuspended": "Suspended", - "summaryDefault": "Preset defaults", - "summaryTokens": "{count, plural, one {# override} other {# overrides}}", - "summaryCss": "Custom CSS", - "suspendedByShortcut": "Custom style is suspended. Nothing set here takes effect until you resume it.", - "suspendedBySafeParam": "This window was opened in safe appearance mode, so custom style is ignored here. Other windows are unaffected.", - "resume": "Resume custom style", - "enableTheme": "Enable custom colors", - "editingLight": "Editing light mode values. Switch the app to dark mode to set its own.", - "editingDark": "Editing dark mode values. Switch the app to light mode to set its own.", - "resetToken": "Reset to preset value", - "radius": "Corner radius", - "radiusHint": "Drives the whole radius scale from sm to 4xl, so one slider rounds the entire app.", - "advanced": "Advanced ({count} more variables)", - "enableCss": "Enable custom CSS", - "cssRisk": "Advanced feature. Custom CSS overrides every built-in style and can make the interface unusable.", - "editCss": "Edit CSS…", - "cssPresent": "{size} KB saved", - "cssEmpty": "Nothing saved yet", - "escapeHint": "Stuck with a broken interface? Press {shortcut} to suspend all custom style, or open a window with the safeStyle=1 query parameter.", - "copyTheme": "Copy theme JSON", - "importTheme": "Import theme…", - "clearTheme": "Clear overrides", - "interopHint": "Themes use shadcn's registry:theme format, so you can paste any shadcn theme here and use exported ones in any shadcn project.", - "importTitle": "Import theme", - "importDescription": "Paste a shadcn registry:theme item, a bare light/dark object, or a flat token map.", - "readClipboard": "Read clipboard", - "importConfirm": "Import", - "cancel": "Cancel", - "apply": "Apply", - "toasts": { - "copied": "Theme JSON copied", - "copyFailed": "Could not copy to the clipboard", - "clipboardReadFailed": "Could not read the clipboard, paste manually", - "importFailed": "No usable theme tokens found in that JSON", - "imported": "Theme imported" - }, - "css": { - "dialogTitle": "Custom CSS", - "dialogDescription": "Applies to every codeg window. Changes preview live; press Apply to save.", - "size": "{used} KB / {max} KB", - "ruleCount": "{count} rules", - "errorTooLarge": "Too large to save. Trim it below the limit.", - "errorImportEscaped": "An @import rule survived removal (escaped syntax). Remove it to save.", - "warnNoRules": "No rules parsed, check the syntax.", - "noticeImportsRemoved": "@import rules removed: {count}. They would fetch remote stylesheets.", - "noticeRemoteUrl": "Contains a remote url(), which makes a network request when applied.", - "noticePreviewSuspended": "Custom style is suspended, so this preview is not applied.", - "noticeDisabled": "Custom CSS is off. You can preview here, but nothing applies until you enable it.", - "hintTokens": "Tip: your color overrides are available as var(--primary), var(--background) and so on." - } - }, - "zoomLevel": { - "sectionTitle": "Window zoom", - "sectionDescription": "Scale the entire interface. Applies immediately and persists per device.", - "placeholder": "Select zoom level", - "default": "Default", - "current": "Current zoom: {zoom}%" - }, - "fonts": { - "sectionTitle": "Fonts", - "sectionDescription": "Choose fonts for the interface, code editor, and terminal. Bundled fonts load on demand; pick “Custom…” to use any font installed on your system.", - "interface": "Interface", - "editor": "Editor", - "terminal": "Terminal", - "groupSans": "Sans-serif", - "groupMono": "Monospace", - "custom": "Custom…", - "customPlaceholder": "Font family, e.g. Fira Code", - "fontSize": "Font size", - "ligatures": "Enable font ligatures", - "ligaturesUnavailable": "This font has no ligatures", - "wordWrap": "Enable word wrap", - "terminalLigaturesHint": "Terminal ligatures apply only to bundled coding fonts.", - "preview": "Preview" - }, - "welcomePanel": { - "sectionTitle": "Mode selection area", - "sectionDescription": "The Code Development / Office Work shortcut cards shown above the composer on the new conversation page.", - "showQuickActions": "Show on the new conversation page" - }, - "workspaceBackground": { - "sectionTitle": "Workspace background", - "sectionDescription": "Show a picture behind the whole workspace. Sidebar and panels turn translucent and frosted so the image shows through, and a mask keeps text readable.", - "enable": "Enable background image", - "image": "Image", - "chooseImage": "Choose image", - "replaceImage": "Replace image", - "removeImage": "Remove", - "fillMode": "Fill mode", - "fillModes": { - "cover": "Cover", - "contain": "Contain", - "center": "Center", - "tile": "Tile" - }, - "maskOpacity": "Mask opacity", - "maskOpacityHint": "Higher values fade the image toward the theme background, improving text contrast.", - "imageBlur": "Image blur", - "panelOpacity": "Panel opacity", - "panelOpacityHint": "How opaque the sidebar, panels and tab bars are. Lower lets more of the image show through.", - "errorTooLarge": "Image is too large (max 16 MB).", - "errorUploadFailed": "Failed to set the background image." - } - }, - "SystemSettings": { - "loading": "Loading...", - "sectionTitle": "System Management", - "sectionDescription": "Manage network proxy, app updates and language preferences.", - "proxyTitle": "Network Proxy", - "proxyDescription": "When enabled, subsequent network requests prefer this proxy (including ACP chat, agent installation and Git remote operations).", - "loadFailed": "Load failed: {message}", - "enableProxy": "Enable system proxy", - "proxyAddress": "Proxy address", - "proxyHint": "Supports http(s)/socks5, example: {example}. Only effective when system proxy is enabled.", - "save": "Save", - "saving": "Saving...", - "proxyRequired": "Proxy URL is required when proxy is enabled", - "saveSuccess": "System proxy settings saved", - "saveFailed": "Save failed: {message}", - "languageTitle": "Language", - "languageDescription": "Set app language. When following system locale, unsupported languages fall back to English.", - "appLanguage": "App language", - "languageSaveSuccess": "Language settings saved", - "languageSaveFailed": "Failed to save language settings: {message}", - "updateTitle": "App Update", - "versionTitle": "Software Update", - "updateDescription": "Check the configured release source for newer versions and install directly when available.", - "currentVersion": "Current version", - "upgradableVersion": "Latest version", - "none": "None", - "lastChecked": "Last checked: {time}", - "updateError": "Update error: {message}", - "checking": "Checking...", - "checkUpdate": "Check for updates", - "updating": "Installing...", - "downloading": "Downloading...", - "upgradeTo": "Upgrade to v{version}", - "viewRelease": "View v{version} release", - "foundUpdate": "New version v{version} found", - "alreadyLatest": "You're on the latest version", - "checkUpdateFailed": "Failed to check for updates: {message}", - "installSuccess": "Update installed. Relaunching app.", - "installFailed": "Update failed: {message}", - "upgradeSuccess": "Upgrade complete. Reloading...", - "restartTimeout": "The server didn't come back in time. Check the container or service logs.", - "restartingIn": "Restarting in {seconds}s...", - "waitingForServer": "Waiting for the server to come back...", - "restartToUpdate": "Restart to update", - "newVersionBadge": "New v{version}", - "updateAvailableTitle": "Update available", - "releaseNotesTitle": "What's new", - "remindLater": "Later", - "retry": "Retry", - "stepDownload": "Download", - "stepInstall": "Install", - "stepRestart": "Restart", - "updateReadyHint": "Update downloaded — restart to apply.", - "restarting": "Restarting...", - "dockerUpgradeHint": "This upgrades the running container now. It's lost if the container is recreated — to keep it, pull or build an image at the new version and recreate.", - "upgradeRolledBack": "Upgrade failed; the server rolled back to the previous version.", - "serverUnreachable": "Couldn't reach the server to start the upgrade. Check that it's running and try again.", - "rollbackButton": "Roll back", - "rollingBack": "Rolling back...", - "rollbackDescription": "Restore the version installed before the last upgrade.", - "rollbackConfirmTitle": "Roll back to the previous version?", - "rollbackConfirmDescription": "The server will restart on the version installed before the last upgrade. A newer release stays available to install again.", - "rollbackConfirm": "Roll back", - "rollbackCancel": "Cancel", - "rollbackSuccess": "Rolled back to the previous version. Reloading...", - "rollbackFailed": "Rollback failed. Check the server logs.", - "updateErrors": { - "sourceUnavailable": "Cannot reach the update source. Check your network or proxy and try again.", - "network": "Network connection failed. Check your network or proxy and try again.", - "downloadFailed": "Failed to download update package. Please try again later.", - "installFailed": "Failed to install update. Please close the app and try again.", - "unknown": "Update failed. Please try again later." - } - }, - "VersionControlSettings": { - "loading": "Loading...", - "sectionTitle": "Version Control", - "sectionDescription": "Configure Git executable and manage GitHub accounts.", - "gitTitle": "Git Configuration", - "gitDescription": "Configure the Git executable used by the application.", - "gitDetected": "Git detected", - "gitNotFound": "Git not found on this system", - "gitVersion": "Version", - "gitPath": "Path", - "customGitPath": "Custom Git Path", - "customGitPathPlaceholder": "/usr/bin/git", - "customGitPathHint": "Leave empty to use the auto-detected path.", - "test": "Test", - "testing": "Testing...", - "testSuccess": "Git executable is valid.", - "testFailed": "Git test failed: {message}", - "save": "Save", - "saving": "Saving...", - "saveSuccess": "Git settings saved.", - "saveFailed": "Failed to save: {message}", - "githubTitle": "GitHub Accounts", - "githubDescription": "Manage GitHub accounts for authentication. Tokens are stored locally.", - "noAccounts": "No GitHub accounts configured.", - "addAccount": "Add Account", - "serverUrl": "Server URL", - "serverUrlPlaceholder": "https://github.com", - "token": "Personal Access Token", - "tokenPlaceholder": "ghp_xxxxxxxxxxxx", - "generateToken": "Generate token", - "tokenHint": "Generate a token at GitHub → Settings → Developer settings → Personal access tokens.", - "validateAndAdd": "Validate & Add", - "validating": "Validating...", - "addSuccess": "Account {username} added successfully.", - "addFailed": "Failed to add account: {message}", - "testConnection": "Test", - "connectionSuccess": "Connection successful.", - "connectionFailed": "Connection failed: {message}", - "setDefault": "Set Default", - "defaultLabel": "Default", - "defaultSet": "Default account updated.", - "removeAccount": "Remove", - "removeConfirmTitle": "Remove Account", - "removeConfirmMessage": "Are you sure you want to remove the account \"{username}\"?", - "removeConfirm": "Remove", - "removeCancel": "Cancel", - "removeSuccess": "Account removed.", - "scopes": "Scopes", - "loadFailed": "Failed to load settings: {message}", - "gitAccount": { - "sectionTitle": "Git Accounts", - "sectionDescription": "Manage credentials for non-GitHub Git servers (GitLab, Bitbucket, self-hosted, etc.).", - "noAccounts": "No Git server accounts configured.", - "addAccount": "Add Account", - "addTitle": "Add Git Account", - "addDescription": "Enter the server address, username, and password or access token.", - "serverUrl": "Server URL", - "serverUrlPlaceholder": "https://gitlab.example.com", - "username": "Username", - "usernamePlaceholder": "Username or email", - "password": "Password / Token", - "passwordPlaceholder": "Password or access token", - "passwordHint": "Enter your password or a personal access token for the server.", - "add": "Add", - "serverRequired": "Server URL is required.", - "usernameRequired": "Username is required.", - "passwordRequired": "Password is required." - } - }, - "ShortcutSettings": { - "sectionTitle": "Shortcuts", - "resetDefault": "Reset defaults", - "recordInstruction": "Click the right-side button, then press a key combination. Use Ctrl/Cmd, Alt, and Shift. Press Esc to cancel recording.", - "recording": "Press shortcut...", - "toasts": { - "conflict": "Shortcut is already used by \"{title}\"", - "updated": "Shortcut updated", - "invalid": "Invalid shortcut, please try again", - "reset": "Default shortcuts restored" - }, - "actions": { - "toggle_search": { - "title": "Open Search", - "description": "Show or hide the conversation search panel" - }, - "toggle_sidebar": { - "title": "Toggle Left Sidebar", - "description": "Show or hide the conversation list sidebar" - }, - "toggle_terminal": { - "title": "Toggle Terminal", - "description": "Show or hide the bottom terminal panel" - }, - "new_terminal_tab": { - "title": "New Terminal", - "description": "Create a new terminal tab when focus is on terminal" - }, - "close_current_terminal_tab": { - "title": "Close Current Terminal", - "description": "Close the current terminal tab when focus is on terminal" - }, - "toggle_aux_panel": { - "title": "Toggle Right Panel", - "description": "Show or hide the auxiliary info panel" - }, - "new_conversation": { - "title": "New Conversation", - "description": "Create a new conversation tab in current folder" - }, - "open_folder": { - "title": "Open Folder", - "description": "Open folder picker and open in a new window" - }, - "open_settings": { - "title": "Open Settings", - "description": "Open settings window" - }, - "close_current_tab": { - "title": "Close Current Tab", - "description": "Close current conversation or file tab" - }, - "close_all_file_tabs": { - "title": "Close All File Tabs", - "description": "Close all open file tabs when the file pane is active" - }, - "next_tab": { - "title": "Next Tab", - "description": "Switch to the next conversation or file tab" - }, - "prev_tab": { - "title": "Previous Tab", - "description": "Switch to the previous conversation or file tab" - }, - "send_message": { - "title": "Send Message", - "description": "Send the current message in the input box" - }, - "newline_in_message": { - "title": "Newline in Message", - "description": "Insert a newline in the message input box" - }, - "toggle_custom_style": { - "title": "Suspend/resume custom style", - "description": "Escape hatch: turns all custom colors and CSS off, and back on" - } - } - }, - "SkillsSettings": { - "title": "Skills", - "description": "Select a skill on the left. The right side previews Markdown by default; switch to edit to modify and save.", - "loadingAgents": "Loading agents that support Skills...", - "emptyNoManageableAgents": "No agents available for Skills management.", - "managedTarget": "Managed target", - "selectAgentPlaceholder": "Select an agent", - "searchPlaceholder": "Search by name / ID / path...", - "skillsList": "Skills list", - "loadingSkills": "Loading skills...", - "agentNotSupported": "Current agent does not support Skills management.", - "emptySkills": "No skills yet. Click \"New Skill\" to create one.", - "newSkillTitle": "New Skill", - "skillInfo": "Skill Info", - "skillIdPlaceholder": "skill-id (letters/numbers/-/_/.)", - "skillsDirectoryWithPath": "Skills directory: {path}", - "skillsDirectoryNeedId": "Skills directory: enter Skill ID to generate full path", - "markdownContent": "Markdown Content", - "editingStatus": "Editing", - "previewStatus": "Previewing", - "contentPlaceholder": "Enter Skill markdown content...", - "metadataTitle": "Skills Metadata", - "onlyYamlMetadata": "This skill only contains YAML metadata.", - "emptyContentHint": "No content yet. Click \"Edit\" to start.", - "loadingSkill": "Loading skill...", - "emptyNoAgents": "No available agent.", - "noSelectionHint": "Select a skill on the left, or click \"New Skill\" to create one.", - "systemBadge": "System", - "systemHint": "Built-in CLI skill · read-only", - "scope": { - "global": "Global", - "folder": "Folder", - "selectFolderPlaceholder": "Select a folder", - "noFolders": "No folders found", - "pickFolderHint": "Select a folder to view its skills." - }, - "actions": { - "preview": "Preview", - "edit": "Edit", - "openInWindow": "Open in new window", - "delete": "Delete", - "deleting": "Deleting...", - "refresh": "Refresh", - "newSkill": "New Skill", - "reset": "Reset", - "save": "Save", - "saving": "Saving...", - "cancel": "Cancel" - }, - "deleteDialog": { - "title": "Delete Skill", - "confirm": "Delete current skill? This action cannot be undone.", - "confirmWithNamePrefix": "Delete skill", - "confirmWithNameSuffix": "? This action cannot be undone." - }, - "toasts": { - "loadFailed": "Failed to load skill", - "openFolderFailed": "Failed to open folder", - "noSkillDirectory": "No available Skills directory found for current agent", - "nameRequired": "Skill name cannot be empty", - "updated": "Skill updated", - "created": "Skill created", - "saveFailed": "Failed to save skill", - "deleted": "Skill deleted", - "deleteFailed": "Failed to delete skill" - }, - "templates": { - "gemini": "---\nname: example-skill\ndescription: Describe when this skill should be used.\n---\n\n# Skill Name\n\nInstructions for the agent when this skill is active.\n\n## Workflow\n\n1. Add actionable step one.\n2. Add actionable step two.\n", - "openCode": "---\nname: example-skill\ndescription: Describe when this skill should be used.\n---\n\n# Purpose\n\nDescribe what this skill helps with.\n\n# Steps\n\n1. Add actionable step one.\n2. Add actionable step two.\n", - "openClaw": "---\nname: example-skill\ndescription: Describe when this skill should be used.\nuser-invocable: true\ndisable-model-invocation: false\n---\n\n# Purpose\n\nDescribe what this skill helps with.\n\n# Instructions\n\n1. Add actionable instruction one.\n2. Add actionable instruction two.\n", - "default": "---\nname: example-skill\ndescription: Describe when this skill should be used.\n---\n\n# Skill: example-skill\n\n## When to use\n\n- Describe trigger conditions.\n\n## Instructions\n\n1. Add actionable instruction one.\n2. Add actionable instruction two.\n" - } - }, - "McpSettings": { - "loading": "Loading...", - "summary": { - "missingCommand": "(missing command)", - "missingUrl": "(missing url)" - }, - "protocol": { - "stdio": "Stdio" - }, - "errors": { - "selectInstallProtocol": "Please select an install protocol", - "fieldRequired": "{field} is required", - "fieldNeedsBoolean": "{field} must be true or false", - "fieldNeedsNumber": "{field} must be a number", - "fieldNeedsInteger": "{field} must be an integer", - "fieldInvalidJson": "{field} has invalid JSON: {message}", - "fieldOutOfRange": "{field} value is out of allowed range", - "jsonEmpty": "{name} cannot be empty", - "jsonInvalid": "{name} is not valid JSON: {message}", - "jsonMustBeObject": "{name} must be a JSON object", - "specMustBeObject": "MCP config must be a JSON object.", - "missingType": "MCP config is missing the type field. Use one of stdio, http (aliases: streamable-http, streamableHttp), sse.", - "unsupportedType": "Unsupported MCP type {type}. Supported: stdio, http (aliases: streamable-http, streamableHttp), sse.", - "codexEntryUnsupportedType": "Codex MCP entry {id} has unsupported type {type}. Supported: stdio, http (aliases: streamable-http, streamableHttp), sse.", - "unsupportedTransportType": "Unsupported transport type {type}. Supported: http (aliases: streamable-http, streamableHttp), sse.", - "stdioCommandRequired": "stdio MCP requires a non-empty command field.", - "remoteUrlRequired": "Remote MCP requires a non-empty url field.", - "appsRequired": "Select at least one target app." - }, - "jsonNames": { - "localConfig": "MCP Config", - "installConfig": "Install Config" - }, - "toasts": { - "uninstalled": "MCP uninstalled", - "uninstallFailed": "Uninstall failed: {message}", - "selectAtLeastOneApp": "Please select at least one target app", - "saveSuccess": "Saved", - "saveFailed": "Save failed: {message}", - "installed": "{name} installed", - "installFailed": "Install failed: {message}", - "serverIdRequired": "Server ID is required", - "serverIdExists": "Server ID \"{id}\" already exists. Edit the existing entry or pick a different name.", - "created": "MCP created" - }, - "installDialog": { - "title": "Confirm MCP Installation", - "descriptionWithName": "Install {name} to local configuration.", - "description": "Select target apps for installation.", - "protocol": "Protocol", - "selectProtocol": "Select protocol", - "parameters": "Configuration Parameters", - "booleanPlaceholder": "Please select true/false", - "selectOneValue": "Select a value", - "targetApps": "Target Apps" - }, - "actions": { - "cancel": "Cancel", - "confirmInstall": "Confirm Install", - "installing": "Installing", - "uninstall": "Uninstall", - "uninstalling": "Uninstalling", - "viewDetails": "View Details", - "save": "Save", - "saving": "Saving", - "install": "Install", - "refresh": "Refresh", - "newMcp": "New MCP", - "create": "Create", - "creating": "Creating..." - }, - "tabs": { - "local": "Local MCP", - "market": "MCP Marketplace" - }, - "local": { - "filterPlaceholder": "Filter local MCP...", - "loadFailed": "Load failed: {message}", - "empty": "No local MCP detected.", - "description": "Local MCP configuration can be edited and saved directly.", - "enabledApps": "Enabled Apps", - "configJson": "MCP Config (JSON)", - "draftTitle": "New MCP", - "draftDescription": "Provide a Server ID and configuration to create a local MCP server.", - "serverIdLabel": "Server ID", - "serverIdPlaceholder": "Server ID (e.g. my-mcp)", - "typeHint": "Supported types: stdio, http (aliases: streamable-http, streamableHttp), sse. env is only used by stdio; for remote MCPs use headers to carry auth tokens.", - "envOnRemoteWarning": "env detected on a remote MCP. Only stdio uses env; remote MCPs carry auth tokens via headers, so env will be ignored on save." - }, - "market": { - "selectMarketplace": "Select marketplace", - "searchPlaceholder": "Search MCP...", - "searchFailed": "Search failed: {message}", - "loadingList": "Loading MCP list...", - "empty": "No MCP results.", - "loadingDetail": "Loading marketplace details...", - "detailLoadFailed": "Failed to load details: {message}", - "owner": "Owner: {owner}", - "namespace": "Namespace: {namespace}", - "defaultInstallProtocol": "Default Install Protocol", - "currentOptionParameterCount": "Current option parameter count: {count}", - "installConfigDescription": "Install Config (JSON, editable before install; edits will override protocol/parameter form)", - "selectLeftToView": "Select a marketplace MCP on the left to view details." - }, - "badges": { - "verified": "Verified", - "remote": "Remote", - "hasHomepage": "Has Homepage", - "uses": "{count} uses", - "deployed": "Deployed", - "notDeployed": "Not Deployed" - }, - "selectLeftMcp": "Select an MCP on the left." - }, - "AcpAgentSettings": { - "title": "Agent SDK Management", - "description": "Manage Agent SDK connection, enabled state, environment variables, config management and version preflight info in one place.", - "loadingAgents": "Loading agent list...", - "agentList": "Agent List", - "emptyNoAgent": "No available agent.", - "configManagement": "Config Management", - "envVars": "Environment Variables", - "hostTools": { - "label": "Let the agent handle files and commands", - "description": "codeg stops serving file access and terminal commands, so the agent runs them in its own process — where its own sandbox and permission rules apply. Delegating to other agents is also turned off, since that would route the same work back through codeg. codeg adds no sandbox itself, so turn this on only if the agent has one configured." - }, - "nativeJsonConfig": "Native JSON Config", - "modelHintDefault": "Leave empty to use system default model.", - "generalConfigDescriptionClaude": "Supports quick configuration for API URL, API Key and Claude models, and syncs with native JSON config.", - "generalConfigDescriptionDefault": "Supports important config input (API URL, API Key, Model) and native JSON config management.", - "multiAgent": { - "title": "Multi-Agent Collaboration", - "description": "Allow active agents to delegate sub-tasks to other agents.", - "enable": "Enable delegation", - "enableHint": "When off, the delegate_to_agent tool is hidden from the agent's MCP catalog.", - "withheldByHostTools": "{agents} will not get the delegation tools: their per-agent “Let the agent handle files and commands” switch is on.", - "depthLimit": "Maximum delegation depth", - "depthHint": "Allowed range: {min}–{max}. Caps how deep a chain (root → child → grandchild …) can recurse.", - "completedCacheLabel": "Completed-result cache (MB)", - "completedCacheHint": "In-memory cache of finished sub-agent results, held only while the delegating session is running and cleared automatically when it ends. Over this budget the oldest results are dropped from memory first (still viewable in the sub-agent's own session); 0 = unlimited (still cleared when the session ends).", - "save": "Save", - "saving": "Saving…", - "saved": "Delegation settings saved", - "saveFailed": "Failed to save delegation settings", - "loadFailed": "Failed to load delegation settings: {detail}", - "tabGeneral": "General", - "tabAgentDefaults": "Agent defaults", - "agentDefaultsDescription": "Per-agent overrides applied when Multi-Agent Collaboration spawns a subagent for a delegation call. Options shown here come from a live probe — what you pick is exactly what the agent will accept.", - "probing": "Loading available options from the agent…", - "probeFailed": "Failed to load options: {detail}", - "retry": "Retry", - "noConfigAvailable": "This agent has no configurable options.", - "modeLabel": "Mode", - "agentDefaultHint": "Agent default: {value}", - "defaultOptionLabel": "Default ({value})" - }, - "actions": { - "dragSort": "Drag to reorder", - "dragSortAgent": "Drag to reorder {name}", - "refreshCheck": "Refresh check", - "refreshCheckAgent": "Refresh check {name}", - "clickEnable": "Click to enable {name}", - "clickDisable": "Click to disable {name}", - "install": "Install", - "upgrade": "Upgrade", - "uninstall": "Uninstall", - "uninstalling": "Uninstalling...", - "saveEnvVars": "Save environment variables", - "saving": "Saving...", - "saveGrokConfig": "Save Grok Config", - "saveCodexConfig": "Save Codex Config", - "saveGeminiConfig": "Save Gemini Config", - "saveOpenCodeConfig": "Save OpenCode Config", - "saveOpenClawConfig": "Save OpenClaw Config", - "saveConfigManagement": "Save Config Management", - "saveCurrentProvider": "Save Current Provider", - "showApiKey": "Show API Key", - "hideApiKey": "Hide API Key", - "showKey": "Show Key", - "hideKey": "Hide Key", - "showToken": "Show Token", - "hideToken": "Hide Token", - "cancel": "Cancel", - "delete": "Delete", - "deleting": "Deleting...", - "confirmDelete": "Confirm Delete", - "confirmUninstall": "Confirm Uninstall", - "saveClineConfig": "Save Cline Config", - "saveHermesConfig": "Save Hermes Config", - "saveCodeBuddyConfig": "Save CodeBuddy Config", - "saveKimiCodeConfig": "Save Kimi Code Config", - "customInstall": "Custom install", - "saveKimiCodeRawConfig": "Save config.toml", - "saveDeepSeekConfig": "Save DeepSeek Config", - "diagnose": "Diagnose" - }, - "status": { - "enabled": "Enabled", - "disabled": "Disabled", - "unchecked": "Unchecked", - "agentEnabledAria": "{name} enabled", - "agentEnabledSwitch": "{name} enable switch" - }, - "preflight": { - "count": "Preflight items: {count}", - "notRun": "Checks have not run yet." - }, - "grok": { - "configDescription": "Configure Grok here. The controls below — permission mode, reasoning effort, an optional custom (BYO endpoint) model, and compaction — merge into ~/.grok/config.toml, preserving your other keys and comments. Sign-in uses your XAI_API_KEY or `grok login`. Other keys stay editable under Advanced.", - "permissionModeLabel": "Permission mode", - "permissionDefault": "Ask every time", - "permissionAcceptEdits": "Auto-approve edits", - "permissionAuto": "Smart auto-approve", - "permissionAlwaysApprove": "Always approve", - "reasoningEffortLabel": "Reasoning effort", - "effortLow": "Low (faster)", - "effortMedium": "Medium (balanced)", - "effortHigh": "High", - "effortXhigh": "Max", - "optionDefault": "Use default", - "authTitle": "Authentication", - "authMode": "Authentication method", - "authModeApiKey": "XAI API key", - "authModeApiKeyHint": "Authenticate with an XAI_API_KEY from the xAI console — for non-interactive or headless runs. Stored in this agent's environment.", - "authModeCustom": "Custom endpoint", - "authModeCustomHint": "Use a bring-your-own endpoint: define a custom model below with its own base URL and API key. It becomes Grok's default model.", - "subscriptionHint": "Sign in with `grok login` (SuperGrok / X Premium+). No API key is stored.", - "loginHint": "Run this in a terminal to sign in, then reopen these settings:", - "commandCopied": "Command copied to clipboard", - "copyCommand": "Copy command", - "authKeyConfigured": "XAI_API_KEY is configured.", - "authKeyMissing": "No XAI_API_KEY set.", - "advancedToggle": "Advanced (raw config.toml)", - "configTomlNative": "config.toml (native)", - "configTomlHint": "Saved verbatim as the whole ~/.grok/config.toml. Invalid TOML is rejected so a typo never truncates your file.", - "configTomlPlaceholder": "# Keys other than the controls above, e.g.\n# [mcp_servers.*], [cli], [permission] rules.", - "customModelTitle": "Custom model (BYO endpoint)", - "customModelHint": "Point Grok at a custom or self-hosted endpoint. codeg writes a per-model `[model.*]` block and makes it the default. Leave the Model ID empty to remove it.", - "customModelIdLabel": "Model ID", - "customModelIdPlaceholder": "grok-4.5", - "customModelIdHint": "Registered as a `[model.*]` block and sent to the API as the model name; also set as `[models].default`.", - "customBaseUrlLabel": "Base URL", - "customBaseUrlPlaceholder": "https://api.x.ai/v1 (default)", - "customApiBackendLabel": "API backend", - "backendResponses": "Responses", - "backendChatCompletions": "Chat Completions", - "backendMessages": "Messages (Anthropic)", - "customApiKeyLabel": "API Key", - "customApiKeyHint": "Stored inline in `[model.*].api_key`, scoped to this endpoint.", - "customContextWindowLabel": "Context window (tokens)", - "customContextWindowHint": "Optional. Drives auto-compact timing; leave empty for the endpoint default.", - "autoCompactLabel": "Auto-compact threshold (%)", - "autoCompactHint": "Compact the conversation when context usage reaches this percent (Grok default 85). Written to `[session]`." - }, - "cursor": { - "configDescription": "Configure Cursor here. Choose an authentication method — official subscription (browser sign-in) or a Cursor API key for headless/server machines — then pick a model and edit the CLI's permission rules and sandbox. codeg writes them into ~/.cursor/cli-config.json, shared with the cursor-agent CLI.", - "authTitle": "Authentication", - "authChecking": "Checking…", - "authNotInstalled": "cursor-agent is not installed", - "authLoggedIn": "Logged in", - "authNotLoggedIn": "Not logged in", - "loginHint": "Run this in a terminal to sign in with your Cursor account (a browser window opens), then hit refresh:", - "apiKeyLabel": "Cursor API key", - "apiKeyPlaceholder": "key from cursor.com/dashboard", - "apiKeyHint": "CURSOR_API_KEY — a Cursor Dashboard account key, an alternative to browser login for headless/server machines. Not a third-party or OpenAI key.", - "modelTitle": "Default model", - "loadModels": "Load models", - "modelsUnavailable": "Model list unavailable", - "modelHint": "Passed to the CLI as --model at session start. Leave on default to let Cursor choose.", - "permissionsTitle": "Permissions & sandbox", - "permissionsDescription": "Visual editor for the CLI's permission rules (cli-config.json). Allow rules run without prompting; deny rules are always blocked.", - "permissionModeLabel": "Permission mode", - "permissionModeDefault": "Ask before running (default)", - "permissionModeForce": "Run Everything (--force)", - "permissionModeHint": "Run Everything launches sessions with --force: every tool call is auto-allowed except deny rules, with no confirmation prompts (an organization policy may downgrade it to allow-rule matching). Takes effect for new sessions.", - "optionDefault": "Default (unset)", - "sandboxLabel": "Sandbox", - "sandboxEnabled": "Enabled", - "sandboxDisabled": "Disabled", - "allowRulesLabel": "Allow rules", - "denyRulesLabel": "Deny rules", - "addRule": "Add rule", - "rulesSyntaxHint": "Rule syntax: Shell(cmd), Read(path/glob), Write(path/glob), WebFetch(domain), Mcp(server:tool) — deny rules always win.", - "saveConfig": "Save configuration", - "advancedToggle": "Advanced: raw cli-config.json", - "advancedHint": "The whole ~/.cursor/cli-config.json. Saving writes the file verbatim — the structured controls above merge into it instead.", - "saveRawConfig": "Save file", - "authMode": "Authentication method", - "subscriptionHint": "Sign in with your Cursor account and use Cursor's models.", - "customApiKeyRequired": "A Cursor API key is required.", - "authModeApiKey": "Cursor API key (headless)", - "authModeApiKeyHint": "Authenticate with a Cursor account API key from the Cursor dashboard — for headless or server machines. This is a Cursor account key, not a third-party/OpenAI endpoint: cursor-agent only talks to Cursor's own backend. To use a codex/OpenAI-compatible endpoint, use the Codex agent instead.", - "modelPickerPlaceholder": "Search models…", - "modelNoMatch": "No matching model", - "modelsNeedAuth": "Sign in to load the model list.", - "modelDefaultBadge": "default" - }, - "deepseek": { - "configManagement": "DeepSeek Harness Configuration", - "configDescription": "The endpoint and key are environment variables deepseek-acp reads at launch. Model and reasoning effort are per-session selectors — pick them in the composer.", - "baseUrlLabel": "API endpoint", - "baseUrlHint": "Leave empty for the official endpoint. Applies to sessions started after the save — reconnect a running session to pick it up.", - "baseUrlInvalid": "Enter a full http(s) URL with no query string, for example https://api.deepseek.com", - "apiKeyLabel": "API key", - "apiKeyHint": "Passed to the agent as DEEPSEEK_API_KEY. An environment variable outranks the credentials file, so leave this empty if you sign in through the terminal." - }, - "codex": { - "configDescription": "Supports quick configuration for API URL, API Key, model name and reasoning effort, and syncs with `auth.json` / `config.toml`.", - "authMode": "Auth Mode", - "chatgptSubscription": "Official Subscription", - "chatgptSubscriptionHint": "Log in with ChatGPT official subscription, no API Key required", - "apiKeyHint": "Connect using API Key to OpenAI or compatible API services", - "selectProvider": "Select Provider", - "modelName": "Model Name", - "selectReasoningEffort": "Select Reasoning Effort", - "enableWebsocket": "Enable WebSocket", - "enableWebsocketAria": "Enable WebSocket for Codex Provider", - "enableSkills": "Enable Skills", - "enableSkillsAria": "Enable Skills for Codex", - "enableFast": "Enable Fast", - "enableFastAria": "Enable Fast service tier for Codex", - "sandboxGroupTitle": "Sandbox & approvals", - "sandboxGroupHint": "Written to the global ~/.codex/config.toml, so codex CLI and IDE sessions see it too. These are thread defaults: they govern the turns codex starts on its own (/goal, /review, /compact). Ordinary prompts use the composer's approval preset instead. Restart a session to pick up changes.", - "sandboxShadowedWarning": "config.toml sets default_permissions, so codex resolves permissions through that profile and ignores sandbox_mode entirely. Remove default_permissions to use the controls below.", - "sandboxPermissionsTableWarning": "config.toml defines [permissions] profiles but no default_permissions, which makes codex refuse to start. Set one in the raw editor below.", - "approvalPolicyLabel": "Approval policy", - "approvalPolicyUnset": "Not set (codex default: on request)", - "approvalPolicy_on-request": "On request — the model decides when to ask", - "approvalPolicy_untrusted": "Untrusted — only known-safe read-only commands run unattended", - "approvalPolicy_never": "Never — no approval prompts at all", - "approvalPolicy_granular": "Granular — choose per prompt type", - "approvalPolicyUntrustedAcpWarning": "Untrusted has no equivalent in the ACP adapter's three approval presets, so codeg sessions fall back to \"on request\" — the model then decides when to ask, and commands the sandbox already allows stop prompting. Tighten the sandbox mode below instead.", - "granularHint": "Off means requests of that kind are auto-rejected instead of shown to you.", - "granular_sandbox_approval": "Shell command escalations", - "granular_rules": "Execpolicy rule prompts", - "granular_skill_approval": "Skill script prompts", - "granular_request_permissions": "request_permissions tool prompts", - "granular_mcp_elicitations": "MCP elicitation prompts", - "sandboxModeLabel": "Sandbox mode", - "sandboxModeUnset": "Not set (trusted folders fall back to workspace write)", - "sandboxMode_read-only": "Read-only", - "sandboxMode_workspace-write": "Workspace write", - "sandboxMode_danger-full-access": "Full access (no sandbox)", - "sandboxModeHint": "On Windows, workspace write is downgraded to read-only unless codex's experimental Windows sandbox is enabled.", - "sandboxModeSeedsPresetHint": "codeg also maps this onto the session's starting approval preset, so unlike approval policy it does reach ordinary prompts. The composer's preset still overrides it.", - "writableRootsLabel": "Extra writable folders", - "writableRootsHint": "One absolute path per line, in addition to the working directory.", - "sandboxRootsRelativeError": "Must be an absolute path — codex resolves relative entries against ~/.codex: {path}", - "networkAccessLabel": "Allow network access", - "excludeTmpdirLabel": "Exclude TMPDIR from writable roots", - "excludeSlashTmpLabel": "Exclude /tmp from writable roots", - "authJsonNative": "auth.json (native)", - "configTomlNative": "config.toml (native)", - "loginButton": "Log in with ChatGPT", - "loginRequesting": "Requesting login code...", - "loginStep1": "Open the following URL in your browser:", - "loginStep2": "Enter the code below:", - "loginPolling": "Waiting for authorization...", - "loginCancel": "Cancel", - "loginSuccess": "Logged in successfully, config saved!", - "loginFailed": "Login failed: {message}", - "loginRetry": "Retry", - "loginCodeCopied": "Code copied", - "loggedIn": "Account logged in", - "loginRelogin": "Re-login / Switch account", - "loginTimeout": "Login timed out, please try again", - "loginSaveFailed": "Login succeeded but failed to save config" - }, - "gemini": { - "authConfig": "Gemini Auth Config", - "authConfigDescription": "Aligned with Gemini CLI authentication docs, supporting custom endpoint, Google login, Gemini API Key and Vertex AI (ADC / service account / API Key).", - "authMode": "Auth Mode", - "selectAuthMode": "Select auth mode", - "viewAuthDoc": "View auth docs", - "mode": { - "custom": "Custom Endpoint", - "loginGoogle": "Google Login (OAuth)", - "vertexServiceAccount": "Vertex AI (Service Account)" - }, - "hint": { - "custom": "Fill API URL, API Key and Model, mapped to GOOGLE_GEMINI_BASE_URL / GEMINI_API_KEY / GEMINI_MODEL.", - "loginGoogle": "Run gemini in terminal and complete Google login first; API key is not required.", - "geminiApiKey": "Fill GEMINI_API_KEY when using Gemini API.", - "vertexAdc": "Use gcloud ADC; GOOGLE_CLOUD_PROJECT and GOOGLE_CLOUD_LOCATION are recommended.", - "vertexServiceAccount": "Set service account JSON path to GOOGLE_APPLICATION_CREDENTIALS.", - "vertexApiKey": "Fill GOOGLE_API_KEY when using Vertex AI API key." - } - }, - "openCode": { - "configManagement": "OpenCode Config Management", - "configDescription": "Aligned with OpenCode `provider` schema, supports multi-provider management and two-way sync with native JSON files.", - "providerManagement": "Provider Management", - "providerCount": "{count} providers", - "addProvider": "Add Provider", - "emptyProvider": "No custom providers yet. Click Add custom provider to create one.", - "providerEnabledState": "{providerId} enabled state", - "selectProviderNpm": "Select provider.npm", - "modelManagement": "Model Management", - "modelCount": "{count} models", - "modelDescription": "Aligned with OpenCode `provider.models`. Fast management currently supports `name` / `id`; other advanced fields are preserved and can be edited in native JSON below.", - "addModel": "Add model", - "emptyModel": "No model yet. Enter model id then click \"Add model\".", - "modelId": "Model ID", - "modelName": "Model Name", - "deleteModel": "Delete model {modelId}", - "nativeJsonConfig": "OpenCode Native JSON Config", - "mainModel": "Main Model", - "smallModel": "Small Model", - "noMatchingModels": "No matching models", - "connectProvider": "Connect Provider", - "connectedProviders": "Connected providers", - "noConnectedProviders": "No catalog providers connected yet.", - "advancedProviderConfig": "Custom providers", - "customProviderConfigHint": "OpenAI-compatible endpoints you define yourself — a provider block in opencode.json, with the API key in auth.json.", - "addCustomProvider": "Add custom provider", - "disconnect": "Disconnect", - "editConfig": "Edit", - "customBadge": "Custom", - "authKindApi": "API Key", - "authKindOauth": "OAuth", - "authKindNone": "No credential", - "connect": { - "title": "Connect a provider", - "description": "Choose a provider from the models.dev catalog. Credentials are saved to the OpenCode auth.json file.", - "pick": "Provider", - "search": "Search providers…", - "loading": "Loading catalog…", - "catalogLabel": "models.dev catalog", - "modelsAvailable": "{count} models available", - "getKey": "Get API key", - "oauthApiKeyNote": "This provider also supports browser sign-in via opencode auth login. Browser sign-in is coming soon — for now, paste an API key.", - "apiKey": "API Key", - "apiKeyHint": "Stored in auth.json, never in opencode.json.", - "baseUrlOptional": "Base URL override (optional)", - "providerId": "Provider ID", - "displayName": "Display name", - "modelsList": "Models (one per line)", - "modelsHint": "Model ids the endpoint accepts.", - "action": "Connect", - "editTitle": "Edit provider", - "editDescription": "Update this provider's API key or base URL.", - "saveAction": "Save" - }, - "customProvider": { - "title": "Add a custom provider", - "description": "Define an OpenAI-compatible endpoint. The API key is saved to auth.json; the provider block goes to opencode.json.", - "action": "Add provider", - "idInCatalog": "{providerId} is a known provider — connect it via Connect Provider instead." - }, - "refreshCatalog": "Refresh catalog", - "reasoningBadge": "reasoning", - "contextWindow": "Context window", - "permissions": { - "title": "Permissions", - "description": "Decide which actions run on their own, prompt you first, or are blocked. Written to the permission block of opencode.json and applied once you save below.", - "docsLink": "Permissions docs", - "unparsableConfig": "The native JSON below is not valid, so the visual editor is paused. Fix the JSON to resume.", - "invalidBlock": "The permission block has a shape codeg does not recognize. Edit it in the native JSON below, or use Reset to start over.", - "orderingUnsafe": "A wildcard rule is written after specific tools, so OpenCode applies it to them as well — the rows below are not what is in force. Fix order moves every wildcard back to the front of its scope without changing a single value.", - "orderingUnsafeManual": "One rule is shadowed by a later, more general pattern, so OpenCode never applies it — the rows below are not what is in force. Two overlapping patterns have no single right order; reorder them in the native JSON so the general one comes first.", - "fixOrder": "Fix order", - "agentOverrides": "These agents override permissions and are applied last, so they win over everything here: {agents}. Edit them in the native JSON below, or turn on auto-accept to clear them.", - "legacyTools": "The legacy top-level tools map denies a tool. OpenCode folds it into the permissions, so it applies on top of everything shown here. Edit it in the native JSON below, or turn on auto-accept to clear it.", - "autoAcceptTitle": "Auto-accept every permission", - "autoAcceptHint": "Every tool call — shell commands, file edits, paths outside the project — runs without asking. Turning this on replaces the per-tool settings below with a single allow-all rule, and clears the per-agent permission overrides and legacy tool toggles that would otherwise still block.", - "globalLabel": "Global default", - "globalHint": "The * rule: what applies to anything the tools below do not override.", - "actionUnset": "Unset (OpenCode defaults)", - "actionInherit": "Inherit ({action})", - "actionAllow": "Allow", - "actionAsk": "Ask", - "actionDeny": "Deny", - "perToolTitle": "Per-tool permissions", - "reset": "Reset", - "ruleCount": "rules: {count}", - "rulesToggle": "Fine-grained rules for {tool}", - "rulesHint": "Matched against the tool input, last match wins — so put the broad patterns first. * matches any characters, ? matches exactly one, and a leading ~ expands to your home directory.", - "noRules": "No fine-grained rules yet.", - "addRule": "Add rule", - "deleteRule": "Delete rule {pattern}", - "duplicateRule": "That pattern already exists.", - "blankRule": "A rule needs a pattern — use the trash icon to remove it.", - "customKeys": "Other permission keys in the file", - "customKeyHint": "Not a built-in OpenCode tool — kept as written.", - "keys": { - "bash": "Run shell commands, matched by the parsed command", - "edit": "All file modifications: edit, write and patch", - "read": "Read files, matched by path", - "external_directory": "Reach paths outside the project working directory", - "task": "Launch subagents, matched by subagent type", - "skill": "Load skills, matched by skill name", - "glob": "Find files, matched by glob pattern", - "grep": "Search file contents, matched by pattern", - "list": "List directory contents", - "webfetch": "Fetch a URL", - "websearch": "Search the web", - "lsp": "Run LSP queries", - "todowrite": "Write the todo list", - "question": "Ask you a question", - "doom_loop": "Trips when the same call repeats three times with identical input" - } - } - }, - "openClaw": { - "gatewayConfig": "Gateway Config", - "gatewayDescription": "Configure OpenClaw Gateway connection. Supports local or remote gateway.", - "gatewayUrlHint": "Leave empty to use gateway.remote.url from local openclaw config.", - "gatewayTokenPlaceholder": "Gateway auth token", - "gatewayTokenHint": "Use token-file instead of plain token when possible; configure via openclaw CLI.", - "sessionKeyHint": "Optional. Specify gateway session key; leave empty to auto-assign isolated session." - }, - "hermes": { - "configManagement": "Hermes Configuration", - "configDescription": "Hermes manages its own credentials in ~/.hermes/.env and settings in ~/.hermes/config.yaml. Pick a provider, then set the API key and model — codeg writes both files for you.", - "providerLabel": "Provider", - "providerHint": "The provider selects which API key variable and model.provider Hermes uses. OAuth providers are configured through the terminal setup below.", - "groupApiKey": "API key providers", - "groupOauth": "OAuth providers", - "groupAws": "AWS", - "apiKeyHint": "Saved to ~/.hermes/.env. It is never injected into the process — Hermes reads it from its own config.", - "modelName": "Model", - "oauthHint": "This provider uses OAuth. Run the setup below to authenticate in your terminal.", - "awsHint": "Bedrock uses your AWS credentials (environment or shared config). Set the model id above and configure AWS access in your environment.", - "unsupportedProvider": "This provider isn't editable with structured fields. Use the raw config.yaml editor below or the terminal setup.", - "setupTitle": "Self-managed setup", - "setupHint": "Hermes's interactive setup needs a terminal. Launch it below, or copy the command to run it yourself.", - "runSetup": "Run Hermes setup", - "configureModel": "Configure model", - "openConfigFolder": "Open ~/.hermes", - "copyCommand": "Copy command", - "commandCopied": "Command copied to clipboard", - "advancedTitle": "Advanced: edit config.yaml", - "rawConfigHint": "Edit ~/.hermes/config.yaml directly. Saving here overwrites the file verbatim.", - "saveRawConfig": "Save config.yaml" - }, - "codebuddy": { - "configManagement": "CodeBuddy Configuration", - "configDescription": "CodeBuddy authenticates with an API key. Mainland China builds also require the environment set to “China (internal)”; iOA builds use “iOA”. The overseas build leaves it unset.", - "apiKeyLabel": "API Key", - "apiKeyHint": "Saved as CODEBUDDY_API_KEY for this agent. Alternatively, sign in with the CodeBuddy CLI in a terminal.", - "apiKeyHintSelfHosted": "Saved as CODEBUDDY_API_KEY for this agent. Use the key issued by your private deployment.", - "environmentLabel": "Environment", - "environmentHint": "Sets CODEBUDDY_INTERNET_ENVIRONMENT. Mainland China must use “China (internal)”; the overseas build leaves it unset.", - "envOverseas": "Overseas (default)", - "envChina": "China (internal)", - "envIoa": "iOA", - "envSelfHosted": "Self-hosted (private deployment)", - "baseUrlLabel": "Deployment URL", - "baseUrlPlaceholder": "https://codebuddy.your-company.com", - "baseUrlHint": "Saved as CODEBUDDY_BASE_URL and points CodeBuddy at your private endpoint. The region setting is left unset for self-hosted deployments.", - "baseUrlInvalid": "Enter a valid http(s) URL.", - "loginHint": "No API key? Run “codebuddy” in a terminal to sign in with your Tencent account instead." - }, - "kimiCode": { - "configManagement": "Kimi Code Configuration", - "configDescription": "`kimi acp` only accepts a stored login token, so codeg writes a managed provider into ~/.kimi-code/config.toml and seeds a local gate token — inference still runs on your own key.", - "statusUnconfigured": "Not configured yet", - "statusDirty": "Unsaved changes", - "summaryLabel": "In effect", - "gateReadyApiKey": "API key written to config.toml", - "gateReadyLogin": "Signed in with a Kimi account", - "revealConfig": "Show in folder", - "envOverrideWarning": "{keys} is set and takes priority over config.toml. Saving here clears it.", - "authModeLabel": "Authentication method", - "authModeApiKey": "API key", - "authModeLogin": "Kimi account login (subscription)", - "authModeApiKeyHint": "Writes a codeg-managed provider into config.toml and seeds the gate token so sessions can open.", - "loginHint": "Run `kimi login` in a terminal to sign in with a Kimi subscription account. codeg stores nothing and reuses Kimi's own login. Saving here removes codeg's API-key gate token.", - "credentialTitle": "Credential", - "interfaceTypeLabel": "Provider type", - "interfaceTypeHint": "The provider protocol Kimi speaks (config.toml `type`). Use Kimi / Moonshot for a Moonshot / platform.kimi.com key.", - "endpointLabel": "Endpoint", - "endpointCustom": "Custom (OpenAI-compatible)", - "endpointHint": "International = api.moonshot.ai; China (platform.kimi.com keys) = api.moonshot.cn. Custom points at any OpenAI-compatible endpoint.", - "regionInternational": "International (api.moonshot.ai)", - "regionChina": "China (api.moonshot.cn)", - "baseUrlLabel": "Base URL", - "baseUrlHint": "Leave blank to use the provider SDK default.", - "apiKeyLabel": "API Key", - "apiKeyHint": "Written to ~/.kimi-code/config.toml and used for inference. From platform.kimi.com or platform.kimi.ai.", - "vertexProjectLabel": "GCP project (GOOGLE_CLOUD_PROJECT)", - "vertexLocationLabel": "GCP location (GOOGLE_CLOUD_LOCATION)", - "vertexHint": "Vertex AI uses Google Application Default Credentials — run `gcloud auth application-default login` (no API key).", - "modelTitle": "Model", - "modelLabel": "Model", - "modelHint": "The model id written to config.toml. Use “Test & list models” to see what your key can actually access.", - "maxContextLabel": "Max context size", - "maxContextHint": "Required by Kimi's schema: without it Kimi discards the whole model block and every prompt comes back empty. Defaults to 262144.", - "fetchModels": "Test & list models", - "fetchModelsOk": "Key works — {count} models available", - "fetchModelsEmpty": "Key works, but no models were returned", - "fetchModelsFailed": "Test failed", - "fetchModelsNeedsKey": "Enter an API key and endpoint first", - "modelNotInList": "This model is not in the list your key can access — Kimi will fail with “model not found”.", - "reasoningTitle": "Reasoning", - "reasoningEnableLabel": "Enable", - "reasoningDescription": "Kimi only shows a Thinking picker in the composer when the model declares a reasoning capability, so codeg writes one here. Takes effect on new sessions.", - "effortsLabel": "Levels offered", - "effortsHint": "These become the rows of the composer's Thinking picker. Kimi forwards the level to the provider verbatim, so pick ones your model accepts.", - "effortsEmptyHint": "With no levels chosen the composer falls back to a plain Off / On toggle.", - "effortsCustomPlaceholder": "Add another level", - "effortsAdd": "Add", - "defaultEffortLabel": "Default level", - "defaultEffortAuto": "Let Kimi choose", - "alwaysThinkingLabel": "The model always reasons — remove the Off row from the picker", - "fixErrorsFirst": "Fix the highlighted fields first", - "errorModelRequired": "Model is required", - "errorMaxContextRequired": "Max context size is required", - "errorMaxContextInvalid": "Must be a positive integer", - "errorApiKeyRequired": "API key is required", - "errorApiKeyInvalid": "The API key must not contain line breaks", - "errorBaseUrlRequired": "Base URL is required", - "errorBaseUrlInvalid": "Must start with http:// or https://", - "errorVertexProjectRequired": "GCP project is required", - "errorDefaultEffortUnlisted": "Pick one of the levels selected above", - "advancedTitle": "Advanced", - "authTypeLabel": "Credential placement", - "authTypeApiKey": "Inline api_key", - "authTypeEnv": "Provider env sub-table", - "authTypeHint": "Where the API key is written inside config.toml.", - "rawEditorLabel": "Edit config.toml directly", - "rawEditorWarning": "Saving here overwrites the entire file verbatim, replacing the structured settings above.", - "rawEditorPlaceholder": "[providers.codeg]\ntype = \"kimi\"\nbase_url = \"https://api.moonshot.cn/v1\"\napi_key = \"sk-...\"" - }, - "authModeOfficialSubscription": "Official Subscription", - "authModeCustomEndpoint": "Custom Endpoint", - "authModeCustomEndpointHint": "Manually configure API URL and API Key for a custom endpoint.", - "authModeModelProvider": "Model Provider", - "modelProvider": "Model Provider", - "modelProviderHint": "Use API URL, API Key, and model from a configured model provider.", - "selectModelProvider": "Select Model Provider", - "noModelProviderAvailable": "No model provider configured for this agent. Go to Model Provider Settings to add one.", - "claude": { - "authMode": "Auth Mode", - "officialSubscription": "Official Subscription", - "officialSubscriptionHint": "Use official Anthropic subscription, no API Key required.", - "mainModel": "Main Model", - "reasoningModel": "Reasoning Model (thinking)", - "haikuDefaultModel": "Default Haiku Model", - "sonnetDefaultModel": "Default Sonnet Model", - "opusDefaultModel": "Default Opus Model", - "customModelOption": "Custom Model ID", - "customModelOptionName": "Custom Model Name", - "customModelOptionDescription": "Custom Model Description", - "customModelOptionHint": "Adds a single custom entry to Claude's model picker (e.g. a model behind a custom gateway/proxy). Name and description are optional display overrides.", - "effortLevel": "Reasoning Effort Level", - "effortLevelDefault": "Default Level", - "effortLevel_low": "Low", - "effortLevel_medium": "Medium", - "effortLevel_high": "High", - "effortLevel_xhigh": "Extra High", - "sendAttributionHeader": "Send attribution/billing identifier to the API", - "sendAttributionHeaderAria": "Send Claude Code attribution/billing identifier to the API", - "disableNonessentialTraffic": "Disable telemetry or redundant network requests", - "disableNonessentialTrafficAria": "Disable Claude Code telemetry or redundant network requests" - }, - "dialogs": { - "confirmDeleteProvider": "Delete Provider {providerId}?", - "confirmDeleteProviderDescription": "OpenCode config and auth JSON will be updated together. This action cannot be undone.", - "confirmUninstall": "Uninstall {name}?", - "confirmUninstallDescription": "This removes local installed version. You can reinstall later.", - "customInstallTitle": "Custom install {name}", - "customInstallDescription": "Enter the version to install. This reinstalls and replaces the currently installed version.", - "customInstallVersionLabel": "Version number", - "customInstallInvalid": "Enter a valid version number, e.g. 1.2.3.", - "customInstallSubmit": "Install" - }, - "errors": { - "windowsFileLocked": "{name}'s files are in use by a running session, so Windows can't replace them. Close all {name} sessions and try again.", - "nativeJsonMustBeObject": "Native JSON config must be an object", - "nativeJsonInvalid": "Native JSON config format error: {message}", - "openCodeAuthMustBeObject": "OpenCode auth.json must be a JSON object", - "openCodeAuthInvalid": "OpenCode auth.json format error: {message}", - "authMustBeObject": "auth.json must be a JSON object", - "authInvalid": "auth.json format error: {message}", - "providerIdPattern": "Provider ID only supports letters, numbers, underscore, dot and hyphen", - "providerExists": "Provider {providerId} already exists", - "modelIdPattern": "Model ID only supports letters, numbers, underscore, dot, colon and hyphen", - "modelExists": "Model {modelId} already exists" - }, - "warnings": { - "nativeJsonRecoveredStructured": "Native JSON config is invalid; reset to structured config", - "nativeJsonRecoveredOpenCode": "Native JSON config is invalid; reset to OpenCode structured config", - "openCodeAuthRecovered": "OpenCode auth.json is invalid; reset to default config", - "authRecoveredStructured": "auth.json is invalid; reset to structured config" - }, - "toasts": { - "agentActionCompleted": "{name} {action} completed", - "agentActionFailed": "{name} {action} failed", - "localVersion": "Local version: {version}", - "installCompletedVersionLater": "Install completed, version will update on next check", - "uninstallCompleted": "{name} uninstall completed", - "uninstallFailed": "{name} uninstall failed", - "localVersionRemoved": "Local version removed", - "saveAgentOrderFailed": "Failed to save Agent order", - "saveAgentSwitchFailed": "Failed to save Agent switch", - "saveEnvFailed": "Failed to save environment variables", - "grokSaved": "Grok config saved", - "saveGrokNativeFailed": "Failed to save Grok native config", - "saveGrokApiKeyFailed": "Settings saved, but the API key couldn't be saved", - "cursorSaved": "Cursor config saved", - "saveCursorConfigFailed": "Failed to save Cursor config", - "codexSaved": "Codex config saved", - "saveCodexNativeFailed": "Failed to save Codex native config", - "geminiSaved": "Gemini config saved", - "saveGeminiFailed": "Failed to save Gemini config", - "providerDeleted": "Provider {providerId} deleted", - "providerDeleteFailed": "Failed to delete Provider {providerId}", - "providerSaved": "Provider {providerId} saved", - "saveProviderFailed": "Failed to save Provider {providerId}", - "openCodeConfigSynced": "OpenCode config and auth JSON have been synced.", - "openCodeSaved": "OpenCode config saved", - "saveOpenCodeFailed": "Failed to save OpenCode config", - "openClawSaved": "OpenClaw config saved", - "saveOpenClawFailed": "Failed to save OpenClaw config", - "configSaved": "Config saved", - "configSavedHint": "Existing sessions need to be reopened to take effect", - "saveConfigManagementFailed": "Failed to save config management", - "clineSaved": "Cline config saved", - "saveClineFailed": "Failed to save Cline config", - "hermesSaved": "Hermes config saved", - "saveHermesFailed": "Failed to save Hermes config", - "codeBuddySaved": "CodeBuddy config saved", - "saveCodeBuddyFailed": "Failed to save CodeBuddy config", - "kimiCodeSaved": "Kimi Code config saved", - "saveKimiCodeFailed": "Failed to save Kimi Code config", - "deepseekSaved": "DeepSeek config saved", - "saveDeepSeekFailed": "Failed to save DeepSeek config", - "modelProviderRequired": "Please select a model provider before saving.", - "affectedRunningSessions": "{count, plural, one {# running session needs to reconnect to apply the change} other {# running sessions need to reconnect to apply the change}}", - "providerConnected": "Connected {providerId}", - "connectFailed": "Failed to connect {providerId}", - "providerDisconnected": "Disconnected {providerId}", - "disconnectFailed": "Failed to disconnect {providerId}", - "catalogRefreshed": "Catalog refreshed — {count} providers", - "catalogRefreshFailed": "Failed to refresh catalog", - "piSaved": "Pi config saved", - "savePiFailed": "Failed to save Pi config", - "piRuntimeSaved": "Pi runtime saved", - "savePiRuntimeFailed": "Failed to save Pi runtime", - "piBinaryInstalled": "pi installed", - "piBinaryInstallFailed": "Failed to install pi", - "piBinaryUninstalled": "pi uninstalled", - "piBinaryUninstallFailed": "Failed to uninstall pi", - "savePiTrustFailed": "Failed to save workspace trust" - }, - "version": { - "statusLabel": "Version Status", - "notInstalled": "Not installed", - "remoteLocal": "Remote: {remoteVersion} · Local: {localVersion}", - "localOnly": "Local: {localVersion}", - "localInstalled": "{versionText}. Installed.", - "platformUnsupported": "{versionText}. Current platform does not support this agent.", - "uvxNotReady": "{versionText}. The uv runtime isn't installed — install it from the uv check below to use this agent.", - "clickInstall": "{versionText}. Click Install on the right.", - "localUnrecognized": "{versionText}. Local version is not comparable; try upgrade to overwrite install.", - "upgradeAvailable": "{versionText}. Upgrade available.", - "remoteUnavailable": "{versionText}. Remote version is currently unavailable.", - "latest": "{versionText}. Already latest." - }, - "adapter": { - "label": "ACP adapter", - "badge": "ACP adapter", - "badgeHint": "For this agent Codeg installs an ACP adapter package, not the vendor CLI. The two are independent and share the same config.", - "learnMore": "Learn more", - "missingWithNative": "Found your own {nativeLabel} at {nativePath}. Codeg drives agents over ACP and that CLI does not speak ACP, so Codeg needs a separate adapter package, {adapterPackage}, maintained by the Agent Client Protocol project (originally Zed). It ships its own runtime, never modifies or replaces your {nativeCmd} command, and reads the same {configDir} — your existing sign-in and settings carry over. Install it below.", - "missing": "Codeg drives agents over ACP and the {nativeLabel} does not speak ACP, so Codeg needs a separate adapter package, {adapterPackage}, maintained by the Agent Client Protocol project (originally Zed). It ships its own runtime, so the {nativeCmd} CLI is not required first; if you do have it, the two coexist and share the same {configDir} sign-in and settings. Install it below.", - "readyWithNative": "Adapter {adapterCmd} is installed — that is what Codeg launches, not your own {nativeCmd} at {nativePath}. They are separate packages that coexist, and both read {configDir}, so sign-in and settings are shared.", - "ready": "Adapter {adapterCmd} is installed — that is what Codeg launches. It ships its own runtime, so the {nativeLabel} is not required; install it later and the two coexist, sharing {configDir}." - }, - "cline": { - "configDescription": "Configure Cline API provider and credentials. Settings are saved to ~/.cline/data/." - }, - "opencodePlugins": { - "title": "OpenCode Plugins", - "declared": "Declared Plugins", - "noPlugins": "No plugins declared.", - "status": { - "installed": "Installed", - "missing": "Missing" - }, - "installAll": "Install All Missing", - "pinVersions": "Pin @latest Versions", - "install": "Install", - "uninstall": "Uninstall", - "refresh": "Refresh", - "success": "All plugins installed successfully.", - "failed": "Installation failed" - }, - "pi": { - "configManagement": "Pi Configuration", - "configDescription": "Pi authenticates with your model provider's API key. The key is written to ~/.pi/agent/auth.json and the model selection to settings.json.", - "providerLabel": "Provider", - "modelLabel": "Model", - "thinkingLabel": "Thinking", - "thinking": { - "off": "Off", - "low": "Low", - "medium": "Medium", - "high": "High", - "minimal": "Minimal", - "xhigh": "Extra high" - }, - "apiKeyLabel": "API Key", - "apiKeyHint": "Stored in ~/.pi/agent/auth.json for the selected provider.", - "apiKeySetPlaceholder": "•••••• (saved — leave blank to keep)", - "saveConfig": "Save Pi Config", - "providerModelRequired": "Provider and model are required", - "runtimeTitle": "Runtime", - "runtimeDescription": "Choose which pi binary runs. Use the default, or point at your own pi build.", - "modeDefault": "Default pi", - "modeDefaultHint": "Use the bundled pi-acp adapter with the pi on your PATH. Install pi with: npm install -g @earendil-works/pi-coding-agent", - "modeCustom": "Custom pi", - "modeCustomHint": "Run your own pi build, install, or wrapper.", - "commandLabel": "pi command or path", - "commandHint": "An absolute path, a command name on PATH, or a wrapper script (e.g. a monorepo ./pi-test.sh).", - "commandNotFound": "Command not found", - "validate": "Validate", - "advanced": "Advanced", - "configDirLabel": "Config directory (PI_CODING_AGENT_DIR)", - "sessionDirLabel": "Sessions directory (PI_CODING_AGENT_SESSION_DIR)", - "flagsHint": "Custom pi flags (--approve, -e, …) aren't forwarded by pi-acp — wrap pi in a script and point the command at it.", - "customIncomplete": "Enter a pi command to save", - "saveRuntime": "Save Runtime", - "providerPlaceholder": "Select a provider", - "customProvider": "Custom provider…", - "providerIdLabel": "Provider ID", - "apiProtocolLabel": "API protocol", - "baseUrlLabel": "API endpoint (Base URL)", - "customProviderHint": "Defines a provider in ~/.pi/agent/models.json at your endpoint. Most self-hosted or proxy servers use openai-completions.", - "baseUrlRequired": "API endpoint (Base URL) is required", - "binaryTitle": "pi binary (pi-coding-agent)", - "binaryDescription": "pi-acp runs this pi binary. Install it here, or point pi-acp at your own build below.", - "binaryInstalled": "Installed", - "binaryMissing": "Not installed", - "binaryChecking": "Checking…", - "installBinary": "Install pi", - "installing": "Installing…", - "recheck": "Recheck", - "configDirSkillsNote": "With a custom config directory, the Skills, Experts, and Office tools managed in Settings won't apply to this pi — manage its skills in that folder directly.", - "projectTrustTitle": "Project trust", - "projectTrustDescription": "Folders you allowed pi to load project files from. A trusted folder lets that repository's .pi/extensions run code when pi starts, applies to every folder inside it, and is also used when you run pi in a terminal.", - "projectTrustLoading": "Loading…", - "projectTrustEmpty": "No folders decided yet.", - "projectTrustTrusted": "Trusted", - "projectTrustDenied": "Not trusted", - "projectTrustRevoke": "Revoke", - "reasoningTitle": "Reasoning", - "reasoningEnableLabel": "Enable", - "reasoningDescription": "pi only sends a reasoning effort for a model that declares it — an undeclared model has every level clamped to Off, so the composer's picker springs back the moment you touch it. Written to this model's entry in models.json.", - "levelsLabel": "Available levels", - "levelsHint": "These become the rows in the composer's reasoning picker. Pick the ones your endpoint accepts; pi rejects any level that isn't listed here.", - "levelsEmptyError": "Pick at least one level — with none, pi falls back to Off.", - "wireValuesTitle": "Advanced: values sent to the provider", - "wireValuesHint": "Leave blank to send the level name as-is. Set one when your endpoint expects something else — Google-style backends want LOW / HIGH.", - "defaultLevelUnlisted": "This level isn't in the available list above — pi would clamp it." - }, - "addCustomAgent": "Add custom agent", - "addCustomAgentHint": "Register any ACP-compatible agent. Pick one from the public ACP registry, or paste its registry information.", - "customAgentFromRegistry": "ACP registry", - "customAgentManual": "Manual", - "customAgentSearchPlaceholder": "Search agents…", - "customAgentLoadingCatalog": "Loading the ACP registry…", - "customAgentRetry": "Retry", - "customAgentNoResults": "No matching agents", - "customAgentAdd": "Add", - "customAgentAlreadyAdded": "Added", - "customAgentUnsupportedPlatform": "No build available for this platform", - "customAgentAdded": "Added {name}", - "customAgentIdLabel": "Registry ID", - "customAgentNameLabel": "Display name", - "customAgentVersionLabel": "Version", - "customAgentSpecLabel": "Distribution (JSON)", - "customAgentSpecHint": "Same shape as a registry entry's distribution object: npx, uvx and binary channels, or paste a whole registry entry. For npx/uvx, cmd is the executable the package installs — derived from the package name when omitted, so set it when the two differ. binary is keyed by platform (this machine: {platform}); its cmd is the launch path inside the archive, and sha256 optionally verifies the download.", - "customAgentTemplateLabel": "Templates", - "customAgentKindLabel": "Launch via", - "customAgentInvalidJson": "Not valid JSON", - "customAgentNoDistribution": "No npx, uvx, or binary distribution found", - "customAgentCancel": "Cancel", - "customAgentSave": "Add agent", - "customAgentSaveChanges": "Save changes", - "customAgentEdit": "Edit agent", - "customAgentEditHint": "Update the name, icon, distribution and skills declarations. The agent ID cannot be changed.", - "customAgentEditNotFound": "Custom agent {id} was not found", - "customAgentSaved": "Saved {name}", - "customAgentVersionProbeLabel": "Version probe command (optional)", - "customAgentVersionProbeHint": "Command that prints the locally installed version. Left empty, codeg runs the agent command with --version.", - "customAgentRemove": "Remove agent", - "customAgentRemoveHint": "Deletes the agent definition. Existing conversations keep their history; the agent just can no longer be launched.", - "customAgentIconLabel": "Icon (optional)", - "customAgentIconUpload": "Upload", - "customAgentIconReplace": "Replace", - "customAgentIconClear": "Remove icon", - "customAgentIconHint": "Stored with the agent, so it works offline. Without one, a colored initial is used.", - "customAgentSkillsLabel": "Skills (shared .agents/skills)", - "customAgentSkillsHint": "Declares that this agent reads the shared .agents/skills store — its global and project directories — and adds it to every skills matrix. Skills linked there are visible to every agent that reads the shared store.", - "customAgentSkillsDirLabel": "Dedicated skills directory", - "customAgentSkillsDirHint": "Absolute path of a directory this agent loads skills from — its own store, in addition to (or instead of) the shared one. ~ expands to your home directory; linked skills are placed here first.", - "customAgentMcpLabel": "MCP support", - "customAgentMcpHint": "Sends codeg's built-in MCP companion to this agent when a session starts — the channel behind delegation, live feedback and task tools. Turn it off for an agent that rejects MCP servers and fails to connect; the change applies to the next connection.", - "customAgentIconNotAnImage": "Pick an image file.", - "customAgentIconTooLarge": "The icon must be smaller than {limit} KB.", - "customAgentIconReadFailed": "Could not read that image.", - "customAgentRemoveConfirm": "Remove {name}? Existing conversations stay, but the agent can no longer be launched.", - "customAgentRemoveWithData": "Also delete its recorded conversation history", - "customAgentRemoved": "Removed {name}", - "customAgentBadge": "Custom", - "customAgentNotLaunchable": "This agent cannot launch here: {reason}" - }, - "SettingsPages": { - "agentsLoading": "Loading agent settings...", - "skillPacksLoading": "Loading skill packs…" - }, - "GeneralSettings": { - "loading": "Loading...", - "sectionTitle": "General", - "sectionDescription": "Centralized preferences for the default terminal, rendering acceleration, and multi-agent delegation.", - "terminalTitle": "Default Terminal", - "terminalDescription": "Choose the shell used when opening new terminal tabs from the terminal bar or file tree. Agents also use it when they ask codeg to run a whole command line for them.", - "terminalSystemDefault": "System default", - "terminalPowerShell7": "PowerShell 7 (pwsh)", - "terminalWindowsPowerShell": "Windows PowerShell", - "terminalCmd": "Command Prompt (cmd)", - "terminalSaveFailed": "Failed to save terminal settings: {message}", - "terminalShellCustom": "Custom path", - "terminalShellCustomPath": "Shell path", - "terminalShellCustomPlaceholder": "/usr/local/bin/fish", - "terminalShellCustomSave": "Save", - "terminalShellCustomHint": "Provide an absolute path or a name resolvable on PATH.", - "terminalShellNotInstalled": "not installed", - "terminalShellNotFoundWarning": "This path doesn't exist on this host.", - "terminalCurrentShell": "Currently using: {path}", - "renderingDescription": "Disable hardware acceleration if the app shows a black screen or rendering glitches (common on certain AMD GPUs or Intel integrated GPUs). Only takes effect on the Windows desktop build.", - "disableHardwareAcceleration": "Disable hardware acceleration", - "renderingSaveFailed": "Failed to save rendering settings: {message}", - "restartRequired": "Saved. Restart the app for the change to take effect.", - "restartNow": "Restart now", - "restartFailed": "Failed to restart: {message}", - "loadFailed": "Load failed: {message}" - }, - "LoginPage": { - "documentTitle": "Login - codeg", - "brand": "Codeg", - "subtitle": "Enter your access token to connect to the desktop app", - "tokenPlaceholder": "Access Token", - "connect": "Connect", - "connecting": "Connecting...", - "helpText": "Find your token in the desktop app under Settings → Web Service", - "invalidToken": "Invalid token. Please check and try again.", - "connectionFailed": "Connection failed (HTTP {status})", - "networkError": "Unable to connect to the server" - }, - "CommitPage": { - "title": "Commit", - "invalidFolderId": "Invalid folder ID", - "loadingRepo": "Loading repository..." - }, - "MergePage": { - "title": "Resolve Conflicts", - "invalidFolderId": "Invalid folder ID", - "loadingRepo": "Loading repository...", - "localVersion": "Local (Ours)", - "result": "Result", - "remoteVersion": "Remote (Theirs)", - "acceptLocal": "Accept Local", - "acceptRemote": "Accept Remote", - "markResolved": "Mark Resolved", - "abortMerge": "Abort", - "completeMerge": "Complete Merge", - "unresolvedConflicts": "There are still unresolved conflict markers in this file", - "fileResolved": "File resolved successfully", - "allResolved": "All conflicts resolved", - "conflictFiles": "Conflict Files", - "loadingFile": "Loading file...", - "preparingMerge": "Preparing merge...", - "selectFile": "Select a file to resolve", - "noConflicts": "No conflict files", - "skipFile": "Skip", - "abortSuccess": "Operation aborted", - "applyAllNonConflicting": "Apply All Non-Conflicting", - "applyLeftNonConflicting": "Apply Local", - "applyRightNonConflicting": "Apply Remote" - }, - "ImportSessions": { - "title": "Import Local Sessions", - "scanningTitle": "Scanning local agent sessions…", - "scanningHint": "Walking each agent's local session store. Large histories can take a moment. Sessions you already imported are refreshed along the way.", - "scanFailed": "Scan failed", - "retry": "Retry", - "rescan": "Rescan", - "empty": "No local sessions found", - "emptyHint": "No agent session stores were found on this machine.", - "noMatches": "No sessions match the current filters", - "searchPlaceholder": "Search title or path…", - "allAgents": "All agents", - "onlyImportable": "Importable only", - "selectAll": "Select all", - "clearSelection": "Clear", - "expandAll": "Expand all", - "collapseAll": "Collapse all", - "summaryCounts": "{total} sessions · {importable} importable · {folders} folders", - "noFolderSkipped": "{count} without a project folder skipped", - "folderNew": "New", - "folderCounts": "{importable}/{total} importable", - "toggleFolderAria": "Select all importable sessions in {name}", - "toggleSessionAria": "Select session {title}", - "statusImported": "Imported", - "statusDeleted": "Deleted", - "untitled": "Untitled session", - "messageCount": "{count} msgs", - "selectedCount": "{count} selected", - "importSelected": "Import selected", - "importing": "Importing…", - "close": "Close", - "doneTitle": "Import finished", - "doneImported": "Imported", - "doneUpdated": "Refreshed", - "doneSkipped": "Skipped", - "doneCreatedFolders": "Folders created", - "doneNotFound": "Not found", - "doneFailed": "Failed", - "continueImport": "Continue importing", - "toasts": { - "importFailed": "Import failed: {message}" - } - }, - "Folder": { - "workspaceStatus": { - "degradedTitle": "Live updates unavailable", - "degradedHint": "Watcher failed to start (e.g. permission denied). Refresh manually to see changes.", - "retry": "Retry", - "retrying": "Retrying..." - }, - "common": { - "all": "All", - "cancel": "Cancel", - "close": "Close", - "closeOthers": "Close Others", - "closeAll": "Close All", - "confirm": "Confirm", - "save": "Save", - "delete": "Delete", - "rename": "Rename", - "loading": "Loading...", - "refresh": "Refresh", - "refreshing": "Refreshing...", - "create": "Create", - "createAndSwitch": "Create and Switch", - "openFile": "Open File", - "viewDiff": "View Diff", - "push": "Push..." - }, - "statusLabels": { - "in_progress": "In Progress", - "pending_review": "Review", - "completed": "Completed", - "cancelled": "Cancelled" - }, - "sidebar": { - "title": "Conversations", - "locateActiveConversation": "Locate Active Conversation", - "expandAllGroups": "Expand All Groups", - "collapseAllGroups": "Collapse All Groups", - "newConversation": "New Conversation", - "newConversationShort": "New", - "newChat": "New chat", - "search": "Search", - "noConversationsFound": "No conversations found.", - "importLocalSessions": "Import local sessions", - "importing": "Importing...", - "error": "Error: {message}", - "completeAllSessions": "Complete all sessions", - "completeAllReviewTitle": "Complete all review sessions?", - "completeAllReviewDescription": "This will mark all {count, plural, one {# session} other {# sessions}} in Review as completed.", - "completing": "Completing...", - "toasts": { - "importedSessions": "Imported {imported, plural, one {# session} other {# sessions}}, skipped {skipped}", - "importedAndUpdated": "Imported {imported, plural, one {# session} other {# sessions}}, updated {updated, plural, one {# title} other {# titles}}, skipped {skipped}", - "updatedTitles": "Updated {updated, plural, one {# title} other {# titles}}, skipped {skipped}", - "noNewSessionsFound": "No new sessions found (skipped {skipped})", - "importFailed": "Import failed: {message}", - "reviewCompleted": "Marked {count, plural, one {# review session} other {# review sessions}} as completed", - "completeReviewFailed": "Failed to complete review sessions: {message}", - "folderOpened": "Opened folder {name}", - "folderRemoved": "Removed folder {name}", - "openFolderFailed": "Failed to open folder", - "removeFolderFailed": "Failed to remove folder: {message}", - "reorderFoldersFailed": "Failed to reorder folders: {message}", - "changeFolderColorFailed": "Failed to change folder color: {message}", - "setFolderAliasFailed": "Failed to set alias: {message}", - "changeFolderDefaultAgentFailed": "Failed to set default agent: {message}" - }, - "statsLabel": "{folders} folders · {convos} conversations", - "reorderHandle": "Drag to reorder", - "openFolder": "Open Folder", - "searchPlaceholder": "Search conversations...", - "viewOptions": "View options", - "showCompleted": "Show completed conversations", - "showWorktrees": "Show worktree folders", - "showRecent": "Show Recent group", - "moreOptions": "More options", - "sortBy": "Sort by", - "sortByCreatedAt": "Created time", - "sortByUpdatedAt": "Updated time", - "sectionOrder": "Section order", - "sectionOrderMoveUp": "Move up", - "sectionOrderMoveDown": "Move down", - "sectionOrderItemLabel": "{name} — position {position} of {total}", - "statusRunningBadge": "Running", - "runningCountBadge": "{count, plural, one {# session running} other {# sessions running}}", - "statusCancelledBadge": "Cancelled", - "worktreeRemovedBadge": "Source worktree removed", - "conversationCountUnit": "{count, plural, one {# conversation} other {# conversations}}", - "emptyFolderHint": "No conversations", - "noMatchingConversations": "No matching conversations", - "noUnfinishedConversations": "No unfinished conversations. Enable \"Show completed\" from the top-right menu.", - "removeFolderConfirmTitle": "Remove folder from workspace?", - "removeFolderConfirmDescription": "Remove \"{name}\" from the workspace? Its tabs and terminals will close.", - "folderHeaderMenu": { - "manageConversations": "Manage conversations…", - "manageLinks": "Linked folders", - "changeColor": "Change color", - "useThemeColor": "Use app theme", - "setDefaultAgent": "Set default agent", - "defaultAgentNone": "No default (use global)", - "agentUnavailableSuffix": "(unavailable)", - "loadingAgents": "Loading agents…", - "setAlias": "Set alias…", - "setAliasTitle": "Set folder alias", - "setAliasPlaceholder": "Enter an alias (leave empty to clear)", - "setAliasSave": "Save", - "setAliasCancel": "Cancel", - "removeFromWorkspace": "Remove from workspace" - }, - "manageConversations": { - "title": "Manage conversations", - "searchPlaceholder": "Search by title…", - "agentFilterAll": "All agents", - "statusFilterAll": "All statuses", - "folderFilterAll": "All folders", - "branchFilterAll": "All branches", - "branchNone": "No branch", - "branchSearchPlaceholder": "Search branches…", - "noMatchingBranches": "No matching branches", - "selectAllVisible": "Select all", - "deselectAll": "Deselect all", - "selectedCount": "{count} selected", - "matchedCount": "{count} matched", - "untitledConversation": "Untitled conversation", - "setStatus": "Set status…", - "deleteSelected": "Delete", - "noConversations": "No conversations in this folder.", - "noConversationsWorkspace": "No conversations in the workspace.", - "noMatchingConversations": "No conversations match the filters.", - "confirmDeleteTitle": "Delete {count} conversation(s)?", - "confirmDeleteDescription": "This action cannot be undone.", - "toastDeleted": "Deleted {count} conversation(s)", - "toastStatusUpdated": "Updated status for {count} conversation(s)", - "toastOpFailed": "Operation failed: {message}" - }, - "sectionPinned": "Pinned", - "sectionFolders": "Folders", - "sectionChats": "Chat", - "sectionRecent": "Recent", - "noChats": "No chats", - "noRecent": "No recent conversations", - "showMoreRecent": "Show more ({count})", - "noFolders": "No folders open", - "newChatAction": "New chat", - "automations": "Automations", - "tasks": "To-dos", - "loadingSubsessions": "Loading sub-conversations…" - }, - "conversation": { - "reloadFailed": "Failed to reload conversation: {message}", - "reloaded": "Conversation reloaded", - "reload": "Reload", - "activeConversationIndicator": "Active conversation", - "newConversation": "New Conversation", - "closeConversation": "Close Conversation", - "copyText": "Copy Text", - "copyTextSuccess": "Copied", - "copyTextFailed": "Copy failed", - "forkSession": "Fork Session", - "forkSessionSuccess": "Session forked successfully", - "forkSessionFailed": "Failed to fork session: {error}", - "exportConversation": "Export Conversation", - "exportImage": "Image", - "exportMarkdown": "Markdown", - "exportHtml": "HTML", - "exportSuccess": "Conversation exported", - "exportFailed": "Export failed", - "exportImageTooLong": "Conversation is too long to export as image", - "exportLabels": { - "untitledConversation": "Untitled Conversation", - "agent": "Agent", - "model": "Model", - "status": "Status", - "started": "Started", - "updated": "Updated", - "tokens": "Token Stats", - "duration": "Duration", - "inputTokens": "Input", - "outputTokens": "Output", - "cacheRead": "Cache Read", - "cacheWrite": "Cache Write", - "user": "User", - "assistant": "Assistant", - "system": "System", - "toolResult": "Result", - "toolError": "Error" - }, - "moreActions": "More actions" - }, - "sessionDetails": { - "menuLabel": "Session Details", - "noActiveSession": "No active session", - "title": "Session Details", - "subtitle": "Session metadata and token usage", - "fieldTitle": "Title", - "untitled": "Untitled conversation", - "sessionId": "Session ID", - "externalId": "Extension ID", - "agent": "Agent", - "model": "Model", - "status": "Status", - "gitBranch": "Git Branch", - "parentId": "Parent Session", - "tokensHeading": "Token Usage", - "totalTokens": "Total", - "inputTokens": "Input", - "outputTokens": "Output", - "cacheWrite": "Cache Write", - "cacheRead": "Cache Read", - "contextWindow": "Context Window", - "duration": "Duration", - "loadingStats": "Loading token usage…", - "loadFailed": "Failed to load token usage", - "noStats": "No usage recorded", - "timestampsHeading": "Timestamps", - "createdAt": "Created", - "updatedAt": "Updated", - "none": "—", - "copyField": "Copy {field}", - "copiedField": "Copied {field}" - }, - "conversationCard": { - "untitledConversation": "Untitled conversation", - "newConversation": "New Conversation", - "rename": "Rename", - "status": "Status", - "delete": "Delete", - "importLocalSessions": "Import local sessions", - "importing": "Importing...", - "renameConversation": "Rename conversation", - "deleteConversationTitle": "Delete conversation?", - "deleteConversationDescription": "This will delete \"{title}\". This action cannot be undone.", - "cancel": "Cancel", - "save": "Save", - "pin": "Pin", - "unpin": "Unpin", - "markCompleted": "Mark as completed", - "reopen": "Reopen", - "expandSubsessions": "Expand sub-conversations", - "collapseSubsessions": "Collapse sub-conversations" - }, - "search": { - "dialogTitle": "Search", - "dialogTitleWithFolder": "Search — {name}", - "tabConversations": "Conversations", - "tabFiles": "Files", - "placeholder": "Search conversations...", - "filePlaceholder": "Search files or directories...", - "allAgents": "All", - "searching": "Searching...", - "typeToSearch": "Type to search conversations", - "typeToSearchFiles": "Type to search files or directories", - "noResults": "No results found.", - "untitledConversation": "Untitled conversation" - }, - "folderTitleBar": { - "showSidebar": "Show Sidebar", - "hideSidebar": "Hide Sidebar", - "toggleTerminal": "Toggle Terminal", - "toggleAuxPanel": "Toggle Auxiliary Panel", - "search": "Search", - "openSettings": "Open Settings", - "backToConversations": "Back to Conversations", - "withShortcut": "{label} ({shortcut})" - }, - "statusBar": { - "connection": { - "connected": "Connected", - "connecting": "Connecting...", - "prompting": "Responding...", - "error": "Connection error", - "disconnected": "Disconnected", - "tooltip": "{agent} - {status}", - "tooltipError": "{agent} - {error}", - "title": "Agent connection", - "triggerAria": "Agent connection: {status}", - "workingDir": "Working directory", - "sessionId": "Session ID", - "viewerNote": "Attached to a session another client owns — reconnecting only re-attaches this view.", - "reconnectInterrupts": "Reconnecting restarts the agent and interrupts the work in progress.", - "reconnect": "Reconnect", - "reconnecting": "Reconnecting...", - "reconnectUnavailable": "Nothing to reconnect to yet." - }, - "tasks": { - "title": "Tasks" - }, - "alerts": { - "title": "Alerts", - "empty": "No alerts", - "details": "Details" - }, - "stats": { - "conversations": "{count} conversations", - "openUsage": "View session stats & token usage" - }, - "tokens": { - "contextWindowUsageAria": "Context window usage", - "contextWindow": "Context Window", - "usedMax": "Used / Max", - "tokenUsage": "Token Usage", - "input": "Input", - "output": "Output", - "cacheRead": "Cache Read", - "cacheWrite": "Cache Write", - "total": "Total" - } - }, - "auxPanel": { - "tabs": { - "files": "Files", - "changes": "Changes", - "commits": "Commits" - }, - "noFolderTitle": "No folder open", - "noFolderHint": "Open a folder to see its contents here" - }, - "windowControls": { - "minimizeWindow": "Minimize window", - "minimize": "Minimize", - "maximizeWindow": "Maximize window", - "maximize": "Maximize", - "restoreWindow": "Restore window", - "restore": "Restore", - "closeWindow": "Close window", - "close": "Close" - }, - "tabs": { - "closeConversationTab": "Close conversation tab", - "close": "Close", - "closeOthers": "Close Others", - "splitRight": "Split Right", - "splitDown": "Split Down", - "splitAndMoveRight": "Split and Move Right", - "splitAndMoveDown": "Split and Move Down", - "moveToOppositeGroup": "Move to Opposite Group", - "moveToGroup": "Move to Group", - "groupLabel": "Group {index}", - "changeSplitterOrientation": "Change Splitter Orientation", - "unsplit": "Unsplit", - "unsplitAll": "Unsplit All", - "closeAll": "Close All", - "tileDisplay": "Tile Display", - "untileDisplay": "Exit Tile" - }, - "fileWorkspace": { - "files": "Files", - "closeFileTab": "Close file tab", - "close": "Close", - "closeOthers": "Close Others", - "closeAll": "Close All", - "preview": "Preview", - "editSource": "Edit Source", - "maximize": "Maximize", - "restore": "Restore", - "emptyDirectory": "Empty folder" - }, - "terminal": { - "rename": "Rename", - "close": "Close", - "closeOthers": "Close Others", - "closeAll": "Close All", - "hideTerminal": "Hide Terminal ({shortcut})", - "openFolderFirst": "Open a folder first" - }, - "workspaceDialog": { - "title": "Open Folder", - "manageTitle": "Linked Folders", - "addTargetsTitle": "Add Folders to Link", - "pickRootDescription": "Pick the main folder for this workspace.", - "linksDescription": "Link other folders in as subdirectories so agents can work across all of them from this one workspace.", - "addTargetsDescription": "Select one or more folders. Each becomes a subdirectory of the workspace.", - "useSystemPicker": "System picker", - "next": "Next", - "back": "Back", - "done": "Done", - "change": "Change", - "addFolders": "Add folders", - "addSelected": "Add", - "addSelectedCount": "Add {count}", - "createCount": "Link {count} folder(s)", - "discardPending": "Discard", - "noLinks": "No linked folders yet.", - "gitExclude": "Keep links out of git status", - "rename": "Rename", - "unlink": "Remove link", - "repair": "Recreate link", - "saveName": "Save", - "cancelRename": "Cancel", - "removePending": "Remove", - "willAppearAs": "Appears as {name} in the workspace", - "renamedForDuplicate": "Renamed — {base} is already used by another link", - "renamedForExistingEntry": "Renamed — {base} already exists in this folder", - "partiallyCreated": "Only {count} folder(s) could be linked", - "openFailed": "Failed to open the folder", - "previewFailed": "Failed to check the selected folders", - "createFailed": "Failed to link the folders", - "renameFailed": "Failed to rename the link", - "removeFailed": "Failed to remove the link", - "repairFailed": "Failed to recreate the link", - "status": { - "ok": "Linked", - "missing": "The link is gone from this folder", - "conflicted": "Another entry now uses this name", - "broken": "The linked folder no longer exists" - }, - "nameIssue": { - "empty": "Enter a name", - "illegalChars": "Cannot contain / \\ : * ? \" < > |", - "tooLong": "Name is too long", - "reserved": "This name is reserved by Windows", - "duplicate": "This name is already used" - }, - "rejection": { - "not_found": "This folder could not be found", - "not_a_directory": "This path is not a folder", - "same_as_root": "This is the workspace folder itself", - "ancestor_of_root": "This folder contains the workspace", - "inside_root": "Already inside the workspace", - "already_linked": "Already linked", - "name_unavailable": "No free name is left for this folder", - "alreadyLinkedAs": "Already linked as {name}" - } - }, - "folderNameDropdown": { - "fallbackFolderName": "Folder", - "openFolder": "Open Folder", - "cloneRepository": "Clone Repository", - "projectBoot": "Project Boot", - "opened": "Opened", - "recentOpen": "Recently Opened" - }, - "fileWorkspacePanel": { - "addSelectionToChat": "Add Selection to Chat", - "addToChat": "Add to Chat", - "addSelectionToChatDone": "Added {label} to the conversation", - "addFileToChat": "Add File to Chat", - "toggleWordWrap": "Toggle Word Wrap", - "addFileToChatDone": "Added {label} to the conversation", - "viewDiff": "View Diff", - "openFile": "Open File", - "fileCount": "{count, plural, one {# file} other {# files}}", - "openFileOrDiff": "Open a file or diff from the right panel", - "disk": "Disk", - "head": "HEAD", - "unsaved": "Unsaved", - "workingTree": "Working Tree", - "loading": "Loading...", - "compareWithBranch": "{path} · compare with {branch}", - "hunkCount": "{count, plural, one {# hunk} other {# hunks}}", - "prev": "Prev", - "next": "Next", - "jumpToLine": "Jump to line {line}", - "noParsedDiffSections": "No parsed diff sections", - "loadingEditor": "Loading editor...", - "imageZoomIn": "Zoom in", - "imageZoomOut": "Zoom out", - "imageZoomReset": "Reset zoom", - "htmlPreviewTitle": "HTML preview", - "htmlPreviewTrust": "Enable scripts", - "htmlPreviewTrustHint": "Run this file's scripts and allow network access. Enable only for files you trust.", - "officePreviewTitle": "Office document preview", - "officeFullRender": "Full render", - "officeFullRenderHint": "Render Morph animations, 3D and math (runs the slide's own scripts)", - "officeNotInstalled": "OfficeCLI is not installed", - "officeNotInstalledHint": "Install OfficeCLI under Settings → Office Tools to preview Word, Excel, and PowerPoint files.", - "officeOpenSettings": "Open Settings", - "officeWatchFailed": "Couldn't start the live preview", - "officeWatchRetry": "Retry", - "officeServerInstallHint": "OfficeCLI must be installed on the server host. Run this command there, then retry:", - "officeRemoteDesktopUnsupported": "Live preview isn't available in a remote-desktop window. Open this workspace in the server's web UI to preview Office files." - }, - "branchDropdown": { - "toasts": { - "commitCodeCompleted": "Code commit completed", - "pushCodeCompleted": "Code push completed", - "committedFiles": "Committed {count, plural, one {# file} other {# files}}", - "taskCompleted": "{label} completed", - "taskFailed": "{label} failed", - "mergeNoNewCommits": "{branchName} has no new commits", - "mergedCommits": "Merged {count, plural, one {# commit} other {# commits}}", - "allFilesUpToDate": "All files are up to date", - "updatedFiles": "Updated {count, plural, one {# file} other {# files}}", - "openCommitWindowFailed": "Failed to open commit window", - "openPushWindowFailed": "Failed to open push window", - "upstreamSet": "Upstream branch has been set", - "upstreamSetAndPushed": "Upstream branch set and pushed {count, plural, one {# commit} other {# commits}}", - "noCommitsToPush": "No commits to push", - "pushedCommits": "Pushed {count, plural, one {# commit} other {# commits}}", - "switchedToFolder": "Switched to {name}", - "switchFailed": "Failed to switch branch", - "openStashWindowFailed": "Failed to open stash window" - }, - "tasks": { - "newBranch": "Create branch {name}", - "newWorktree": "Create worktree {name}", - "checkoutTo": "Checkout to {branchName}", - "mergeBranch": "Merge {branchName}", - "rebaseTo": "Rebase to {branchName}", - "deleteRemoteBranch": "Delete remote branch {branchName}", - "initGitRepo": "Initialize Git repository", - "pullCode": "Pull code", - "fetchInfo": "Fetch info", - "pushCode": "Push code", - "stashChanges": "Stash changes", - "stashPop": "Pop stash", - "deleteBranch": "Delete branch {branchName}", - "removeWorktree": "Delete worktree for {branchName}", - "removeWorktreeAndBranch": "Delete worktree and branch {branchName}", - "updateBranch": "Update branch {branchName}" - }, - "confirm": { - "mergeTitle": "Merge branch", - "rebaseTitle": "Rebase branch", - "mergeDescription": "Merge {branchName} into current branch {currentBranch}?", - "rebaseDescription": "Rebase current branch {currentBranch} onto {branchName}?", - "deleteRemoteTitle": "Delete Remote Branch", - "deleteRemoteDescription": "Delete remote branch {branchName}? This will remove it from the remote repository and cannot be undone.", - "deleteTitle": "Delete branch", - "deleteDescription": "Delete branch {branchName}? This action cannot be undone.", - "forceDeleteTitle": "Force Delete Branch", - "forceDeleteDescription": "Branch {branchName} is not fully merged. Are you sure you want to force delete it? This action cannot be undone.", - "deleteWorktreeTitle": "Delete worktree", - "deleteWorktreeDescription": "Delete the worktree directory that has {branchName} checked out? The branch and its commits are kept.", - "forceDeleteWorktreeTitle": "Force delete worktree", - "forceDeleteWorktreeDescription": "The worktree for {branchName} has uncommitted or untracked files. Delete it anyway? Those changes cannot be recovered.", - "deleteWorktreeAndBranchTitle": "Delete worktree and branch", - "deleteWorktreeAndBranchDescription": "Delete the worktree for {branchName}, the branch itself, and its workspace folder? Its sessions move to the repository folder. This action cannot be undone.", - "forceDeleteWorktreeAndBranchTitle": "Force delete worktree and branch", - "forceDeleteWorktreeAndBranchDescription": "The worktree for {branchName} has uncommitted files, or the branch is not fully merged. Delete both anyway? This action cannot be undone." - }, - "current": "Current", - "switchToBranch": "Switch to this branch", - "mergeBranchIntoCurrent": "Merge {branchName} into {currentBranch}", - "rebaseCurrentToBranch": "Rebase {currentBranch} onto {branchName}", - "noBranch": "No branch", - "detachedHead": "Detached HEAD at {sha}", - "initGitRepo": "Initialize Git repository", - "pullCode": "Pull code", - "fetchRemoteBranches": "Fetch remote branches", - "openCommitWindow": "Commit code...", - "pushCode": "Push...", - "pushBranch": "Push", - "newBranch": "New branch...", - "newWorktree": "New worktree...", - "stashChanges": "Stash changes...", - "stashPop": "Unstash...", - "manageRemotes": "Manage Remotes...", - "localBranches": "Local branches ({count, plural, one {#} other {#}})", - "noLocalBranches": "No local branches", - "remoteBranches": "Remote branches ({count, plural, one {#} other {#}})", - "noRemoteBranches": "No remote branches", - "dialogs": { - "newBranchTitle": "New branch", - "newBranchDescription": "Create a new branch from current branch {branch}", - "branchNamePlaceholder": "Branch name", - "newWorktreeTitle": "New worktree", - "newWorktreeDescription": "Create a new worktree from current branch {branch}", - "branchNameLabel": "Branch name", - "worktreePathLabel": "Worktree path", - "worktreePathPlaceholder": "Worktree path", - "manageRemotesTitle": "Manage Remotes", - "manageRemotesEmpty": "No remotes configured", - "remoteNamePlaceholder": "Remote name", - "remoteUrlPlaceholder": "Remote URL", - "addRemote": "Add", - "savingRemotes": "Saving..." - }, - "conflict": { - "title": "Merge Conflicts", - "description": "The following files have conflicts that need to be resolved:", - "abort": "Abort Merge", - "openMergeTool": "Open Merge Tool", - "completeMerge": "Complete Merge", - "abortSuccess": "Merge aborted successfully", - "completeSuccess": "Merge completed successfully" - }, - "stashDialog": { - "title": "Stash Changes", - "description": "Save your current changes to a stash", - "messageLabel": "Message", - "messagePlaceholder": "Stash message (optional)", - "keepIndex": "Keep index (staged changes remain staged)", - "cancel": "Cancel", - "stash": "Stash", - "success": "Changes stashed successfully", - "error": "Failed to stash changes" - }, - "unstashDialog": { - "title": "Unstash Changes", - "noStashes": "No stashes found", - "selectFile": "Select a file to view diff", - "viewDiff": "View Diff", - "original": "Original", - "modified": "Modified", - "apply": "Apply", - "drop": "Drop", - "applySuccess": "Stash applied successfully", - "dropSuccess": "Stash dropped", - "confirmApply": "Apply stash {ref} to working directory?", - "cancel": "Cancel" - }, - "deleteBranch": "Delete branch", - "deleteWorktree": "Delete worktree", - "deleteWorktreeAndBranch": "Delete worktree and branch", - "searchPlaceholder": "Search branches and actions", - "searchAriaLabel": "Search branches and actions", - "branchListLabel": "Branches and actions", - "noMatches": "No matches" - }, - "commitDialog": { - "toasts": { - "commitCompleted": "Code commit completed", - "pushFailed": "Push failed", - "committedFiles": "Committed {count, plural, one {# file} other {# files}}", - "addedToVcs": "Added to VCS", - "addToVcsFailed": "Failed to add to VCS", - "fileDeleted": "File deleted", - "deleteFailed": "Delete failed", - "fileRolledBack": "File rolled back", - "rollbackFailed": "Rollback failed", - "dirRolledBack": "Directory rolled back", - "dirDeleted": "Directory deleted" - }, - "confirm": { - "deleteTitle": "Confirm deletion", - "deleteDescription": "Delete file \"{file}\"? This action cannot be undone.", - "rollbackTitle": "Confirm rollback", - "rollbackDescription": "Rollback file \"{file}\" to HEAD? Unsaved changes will be lost.", - "rollbackDirDescription": "Rollback directory \"{dir}\" to HEAD? Unsaved changes will be lost.", - "deleteDirDescription": "Delete directory \"{dir}\"? This action cannot be undone." - }, - "actions": { - "select": "Select", - "unselect": "Unselect", - "rollback": "Rollback", - "addToVcs": "Add to VCS" - }, - "aria": { - "selectFile": "{action} {path}", - "unselectAllFiles": "Unselect all files", - "selectAllFiles": "Select all files", - "unselectTracked": "Unselect tracked changes", - "selectTracked": "Select tracked changes", - "unselectUntracked": "Unselect untracked files", - "selectUntracked": "Select untracked files" - }, - "loading": "Loading...", - "selectionCount": "{selected} / {total} files", - "emptyFiles": "No changed files", - "trackedChanges": "Tracked changes ({count})", - "untrackedFiles": "Untracked files ({count})", - "commitMessage": "Commit message", - "commitMessagePlaceholder": "Enter commit message...", - "commitButton": "Commit ({count})", - "commitAndPushButton": "Commit and Push ({count})", - "head": "HEAD", - "workingTree": "Working Tree", - "clickFileToDiff": "Click a file name to view diff", - "loadingDiff": "Loading diff..." - }, - "pushWindow": { - "title": "Push Code", - "noUnpushedCommits": "No unpushed commits", - "noRemoteConfigured": "No Git remote configured\nAdd a remote in Manage Remotes", - "newBranchNoPushedCommits": "New branch — push to create remote tracking branch", - "unpushed": "Unpushed", - "selectFileToViewDiff": "Select a file to view diff", - "before": "Before", - "after": "After", - "push": "Push", - "toasts": { - "pushSuccess": "Push successful", - "pushFailed": "Push failed", - "upstreamSet": "Upstream branch has been set", - "upstreamSetAndPushed": "Upstream branch set and pushed {count, plural, one {# commit} other {# commits}}", - "noCommitsToPush": "No commits to push", - "pushedCommits": "Pushed {count, plural, one {# commit} other {# commits}}" - } - }, - "gitLogTab": { - "filesTitle": "Files", - "expandAllFiles": "Expand all files", - "collapseAllFiles": "Collapse all files", - "workspace": "workspace", - "retry": "Retry", - "noCommitsFound": "No commits found", - "notAGitRepoTitle": "Not a Git repository", - "notAGitRepoHint": "Initialize Git from the branch menu above, or open a folder that is already tracked.", - "hash": "Hash", - "copyHash": "Copy hash", - "copyMessage": "Copy message", - "showMore": "Show more", - "showLess": "Show less", - "author": "Author", - "noFileChangeDetails": "No file change details available.", - "loadingFiles": "Loading files...", - "branchesTitle": "Branches", - "loadingBranches": "Loading branches...", - "noContainingBranches": "No containing branches found.", - "newBranch": "New branch...", - "resetToHere": "Reset to Here", - "resetDisabledReasonNotCurrentBranchView": "Available only when viewing current branch", - "copyFullCommitHashAria": "Copy full commit hash {hash}", - "pushStatus": { - "pushed": "Pushed to remote", - "notPushed": "Not pushed to remote", - "unknown": "Push status unknown (no upstream configured)" - }, - "time": { - "monthsAgo": "{count, plural, one {# month ago} other {# months ago}}", - "daysAgo": "{count, plural, one {# day ago} other {# days ago}}", - "hoursAgo": "{count, plural, one {# hour ago} other {# hours ago}}", - "minsAgo": "{count, plural, one {# min ago} other {# mins ago}}", - "justNow": "just now" - }, - "toasts": { - "createdAndSwitchedNewBranch": "Created and switched to new branch", - "newBranchFromCommit": "{name} (from {shortHash})", - "createBranchFailed": "Failed to create branch", - "openPushWindowFailed": "Failed to open push window", - "resetSuccess": "Reset successful", - "resetSuccessDescription": "{branch} reset to {shortHash} with {mode}", - "resetFailed": "Reset failed" - }, - "authorFilter": { - "label": "Author", - "searchPlaceholder": "Search author", - "noAuthors": "No authors found", - "you": "you", - "filterByAuthorAria": "Filter commits by author", - "filterByQuery": "Filter by \"{query}\"", - "clearAuthorFilterAria": "Clear author filter", - "recent": "Recent", - "matchingAuthors": "Matching authors", - "removeFromRecent": "Remove {name} from recent" - }, - "branchSelector": { - "label": "Branch", - "head": "HEAD", - "headHint": "Follows the current branch", - "headHintWithBranch": "Follows the current branch ({branch})", - "searchBranch": "Search branch...", - "noBranches": "No branches", - "selectBranchPlaceholder": "Select branch...", - "localBranches": "Local branches", - "current": "Current", - "remoteBranches": "Remote branches", - "refreshCommitHistory": "Refresh commit history", - "clearBranchFilterAria": "Clear branch filter" - }, - "dialogs": { - "newBranchTitle": "New branch", - "newBranchDescription": "Create a new branch with commit {shortHash} as the latest commit.", - "branchNamePlaceholder": "Branch name", - "reset": { - "title": "Reset Current Branch to Here", - "branchLabel": "Branch", - "targetLabel": "Target", - "messageLabel": "Message", - "modeLabel": "Reset mode", - "confirmButton": "Reset", - "modes": { - "soft": { - "label": "--soft", - "description": "Move HEAD and the current branch pointer to the target commit.\nKeep Index and Working Tree unchanged.\nChanges from the removed commits stay staged." - }, - "mixed": { - "label": "--mixed (default)", - "description": "Move HEAD to the target commit.\nReset Index to the target commit while keeping Working Tree changes.\nThose changes become unstaged." - }, - "hard": { - "label": "--hard", - "description": "Move HEAD and reset both Index and Working Tree to the target commit.\nLocal tracked changes after the target commit are discarded.\nThis is a destructive operation." - }, - "keep": { - "label": "--keep", - "description": "Move HEAD to the target commit and keep local changes when possible.\nOnly non-conflicting local changes are preserved.\nIf conflicts are detected, reset aborts to protect your work." - } - } - } - }, - "moreActions": "More Git actions" - }, - "gitChangesTab": { - "workspace": "workspace", - "noChanges": "No local changes", - "notAGitRepoTitle": "Not a Git repository", - "notAGitRepoHint": "Initialize Git from the branch menu above, or open a folder that is already tracked.", - "trackedChanges": "Tracked changes ({count})", - "untrackedFiles": "Untracked files ({count})", - "expandTracked": "Expand tracked changes", - "collapseTracked": "Collapse tracked changes", - "expandUntracked": "Expand untracked files", - "collapseUntracked": "Collapse untracked files", - "showRemainingItems": "Show {count} more items", - "actions": { - "commitCode": "Commit code", - "rollback": "Rollback", - "addToVcs": "Add to VCS", - "delete": "Delete", - "moreActions": "More Git actions", - "addAllToVcs": "Add all to VCS", - "rollbackAll": "Rollback all", - "refresh": "Refresh" - }, - "toasts": { - "noAddableFilesInDir": "No changed files in this directory can be added to VCS", - "noRollbackFilesInDir": "No changed files in this directory can be rolled back", - "addedToVcs": "Added {name} to VCS", - "addToVcsFailed": "Failed to add to VCS", - "openCommitWindowFailed": "Failed to open commit window", - "rolledBack": "Rolled back {name}", - "rollbackFailed": "Rollback failed", - "addedFilesToVcs": "Added {count, plural, one {# file} other {# files}} to VCS", - "rolledBackFiles": "Rolled back {count, plural, one {# file} other {# files}}", - "deleted": "Deleted {name}", - "deleteFailed": "Delete failed", - "deletedFiles": "Deleted {count, plural, one {# file} other {# files}}", - "noDeletableFilesInDir": "No changed files in this directory can be deleted", - "commitFailed": "Commit failed" - }, - "directoryDialog": { - "descriptionAdd": "Select files under directory {path} to add to VCS.", - "descriptionRollback": "Select files under directory {path} to roll back.", - "descriptionDelete": "Select files under directory {path} to delete. This action cannot be undone.", - "descriptionFallback": "Select files to proceed.", - "selectionCount": "Selected {selected} / {total} files", - "selectAll": "Select all", - "unselectAll": "Unselect all", - "loadingCandidates": "Loading directory changes...", - "noOperableFiles": "No operable files" - }, - "rollbackConfirm": { - "title": "Confirm rollback", - "descriptionWithTarget": "Roll back local changes for {kind} \"{name}\"?", - "descriptionFallback": "Roll back local changes?", - "kindDirectory": "directory", - "kindFile": "file" - }, - "deleteConfirm": { - "title": "Confirm deletion", - "descriptionWithTarget": "Delete {kind} \"{name}\"? This action cannot be undone.", - "descriptionFallback": "This action cannot be undone.", - "kindDirectory": "directory", - "kindFile": "file" - }, - "quickCommit": { - "placeholder": "Commit message (Enter to commit)" - } - }, - "tabContext": { - "loadingConversation": "Loading...", - "untitledConversation": "Untitled conversation", - "newConversation": "New Conversation" - }, - "fileTreeTab": { - "workspace": "Workspace", - "retry": "Retry", - "git": "Git", - "openInFileManager": "Open in file manager", - "openInFinder": "Open in Finder", - "openInExplorer": "Open in Explorer", - "attachToCurrentSession": "Add to session", - "compareWithBranch": "Compare with branch...", - "reloadFromDisk": "Reload from disk", - "new": "New", - "newFile": "File", - "newDirectory": "Directory", - "openIn": "Open in", - "openInTerminal": "Open in terminal", - "linkedFolder": "Linked folder", - "copyPath": "Copy path", - "upload": "Upload files/folder", - "download": "Download file", - "downloadAsZip": "Download as ZIP", - "actions": { - "select": "Select", - "unselect": "Unselect", - "commitCode": "Commit code", - "rollback": "Rollback", - "addToVcs": "Add to VCS" - }, - "aria": { - "selectPath": "{action} {path}" - }, - "toasts": { - "openDirectoryFailed": "Failed to open directory", - "openBuiltinTerminalFailed": "Unable to open built-in terminal", - "openCommitWindowFailed": "Failed to open commit window", - "noAddableFilesInDir": "No changed files in this directory can be added to VCS", - "noRollbackFilesInDir": "No changed files in this directory can be rolled back", - "addedToVcs": "Added {name} to VCS", - "addToVcsFailed": "Failed to add to VCS", - "loadBranchesFailed": "Failed to load branches", - "renameFailed": "Rename failed", - "moveFailed": "Move failed", - "deleteFailed": "Delete failed", - "rolledBack": "Rolled back {name}", - "rollbackFailed": "Rollback failed", - "addedFilesToVcs": "Added {count, plural, one {# file} other {# files}} to VCS", - "rolledBackFiles": "Rolled back {count, plural, one {# file} other {# files}}", - "savedAsCopy": "Saved as a copy", - "saveCopyFailed": "Failed to save as copy", - "watchStartFailed": "Failed to start file watch", - "createFailed": "Failed to create", - "downloadFailed": "Failed to download {name}", - "downloadSaved": "Downloaded {name}", - "pathCopied": "Path copied", - "copyPathFailed": "Failed to copy path" - }, - "createDialog": { - "newFile": "New file", - "newDirectory": "New directory", - "description": "Enter a name for the new {kind}.", - "placeholderFile": "file-name.ext", - "placeholderDirectory": "folder-name" - }, - "renameDialog": { - "renameDirectory": "Rename directory", - "renameFile": "Rename file", - "description": "Enter a new name (name only, no path).", - "placeholderDirectory": "new-folder-name", - "placeholderFile": "new-file-name.ext" - }, - "uploadDialog": { - "title": "Upload to workspace", - "description": "Adjust the destination if needed, then add files or folders.", - "workspaceRoot": "workspace root", - "targetPathLabel": "Upload to", - "targetPathHint": "Resolved path: {path}", - "dropHint": "Drag files or folders here, or use the buttons below", - "dropHintActive": "Release to add to the queue", - "selectFiles": "Select files", - "selectFolder": "Select folder", - "startUpload": "Start upload", - "clearQueue": "Clear finished", - "removeItem": "Remove from queue", - "retry": "Retry", - "dropZoneAria": "Drop files here or activate to browse", - "folderEmpty": "No files found in the dropped folder", - "summary": "Total: {total} · Succeeded: {succeeded} · Failed: {failed}", - "status": { - "pending": "Waiting", - "uploading": "Uploading", - "success": "Done", - "error": "Failed", - "cancelled": "Cancelled" - } - }, - "directoryDialog": { - "descriptionAdd": "Select files under directory {path} to add to VCS.", - "descriptionRollback": "Select files under directory {path} to roll back.", - "descriptionFallback": "Select files to proceed.", - "selectionCount": "Selected {selected} / {total} files", - "selectAll": "Select all", - "unselectAll": "Unselect all", - "loadingCandidates": "Loading directory changes...", - "noOperableFiles": "No operable files" - }, - "compareDialog": { - "title": "Compare with branch", - "descriptionWithTarget": "Select a branch and compare with {kind} {path}", - "descriptionFallback": "Select a branch to compare.", - "kindDirectory": "directory", - "kindFile": "file", - "filterPlaceholder": "Filter branches, e.g. main / origin/main", - "singleClickHint": "Click a branch to compare directly", - "loadingBranches": "Loading branches...", - "recentBranches": "Recent branches ({count})", - "noCurrentBranch": "No current branch", - "localBranches": "Local branches ({count})", - "remoteBranches": "Remote branches ({count})", - "noMatchingBranches": "No matching branches" - }, - "externalConflictDialog": { - "title": "External file changes detected", - "descriptionWithPath": "File {path} has changed on disk, and current edits are unsaved.", - "descriptionFallback": "Current file has changed on disk, and current edits are unsaved.", - "compare": "Compare", - "savingCopy": "Saving copy...", - "saveAsCopy": "Save as copy", - "reload": "Reload" - }, - "deleteConfirm": { - "title": "Confirm deletion", - "descriptionWithTarget": "Delete {kind} \"{name}\"? This action cannot be undone.", - "descriptionFallback": "This action cannot be undone.", - "kindDirectory": "directory", - "kindFile": "file" - }, - "rollbackConfirm": { - "title": "Confirm rollback", - "descriptionWithTarget": "Rollback local changes for file \"{name}\"?", - "descriptionFallback": "Rollback local changes for this file?" - }, - "terminalTitle": "Terminal · {name}" - }, - "commandDropdown": { - "loading": "Loading...", - "addCommand": "Add Command", - "manageCommands": "Manage Commands...", - "runCommandTitle": "Run: {command}", - "stopCommandTitle": "Stop: {command}", - "manageDialog": { - "title": "Manage Commands", - "empty": "No commands yet", - "noResults": "No matching commands", - "searchPlaceholder": "Search commands", - "newCommand": "New command", - "nameLabel": "Name", - "commandLabel": "Command", - "dragSort": "Drag to sort", - "dragSortCommand": "Drag to sort {name}", - "orderFailed": "Failed to save command order", - "loadFailed": "Failed to load commands", - "saveFailed": "Failed to save command", - "deleteFailed": "Failed to delete command", - "confirmDelete": { - "title": "Delete command?", - "message": "This will remove \"{name}\". This action cannot be undone." - } - } - }, - "workspaceContext": { - "confirmCloseDirtyTab": "Close \"{title}\" without saving?", - "confirmCloseOtherDirtyTabs": "Close other tabs with unsaved changes?", - "confirmCloseAllDirtyTabs": "Close all tabs with unsaved changes?", - "unableLoadContent": "Unable to load content.\n\n{message}", - "previewRequestTimedOut": "Preview request timed out", - "diffRequestTimedOut": "Diff request timed out", - "branchCompareRequestTimedOut": "Branch compare request timed out", - "commitDiffRequestTimedOut": "Commit diff request timed out", - "saveRequestTimedOut": "Save request timed out", - "reloadRequestTimedOut": "Reload request timed out", - "noChanges": "No changes.", - "noDiffOutput": "No diff output.", - "diffTitleWorkspace": "Diff · Workspace", - "diffDescriptionWorkingTree": "Working tree (HEAD)", - "diffTitleFile": "Diff · {name}", - "compareTitleFile": "Compare · {name}", - "compareTitleBranch": "Compare · {branch}", - "compareDescriptionPath": "{path} · compare with {branch}", - "compareDescriptionBranch": "compare with {branch}", - "diffTitleCommitFile": "Diff · {name} @ {hash}", - "diffTitleCommit": "Diff · {hash}", - "diffDescriptionCommitPath": "{path} · commit {commit}", - "diffDescriptionCommit": "commit {commit}", - "diffTitleConflictFile": "Conflict · {name}", - "diffDescriptionConflict": "{path} · disk vs unsaved" - }, - "chat": { - "acpConnections": { - "actions": { - "openAgentsSettings": "Open Agents settings", - "retry": "Retry" - }, - "agentsSetupHint": "Open Settings > Agents to manage installation.", - "withSetupHint": "{message}\n{hint}", - "blocked": { - "missingConfig": "Unable to read current Agent configuration.", - "disabled": "{agent} is disabled in Agents settings. Enable it before connecting.", - "unavailable": "{agent} is unavailable on the current platform.", - "sdkMissing": "{agent} SDK is not installed", - "adapterMissing": "{agent}'s ACP adapter is not installed" - }, - "backendErrors": { - "initializeTimeout": "{agent} connection handshake timed out after 60 seconds. Please open Settings to check Agent configuration and network settings.", - "mcpRejectedByAgent": "{agent} refused the session while codeg’s MCP companion was attached: {message} If this agent does not support MCP, turn off “MCP support” for it in Settings and connect again.", - "processExited": "{agent} process exited unexpectedly.", - "spawnFailed": "Failed to start {agent}: {message}", - "downloadFailed": "{agent} download failed: {message}", - "sessionLoadResourceNotFound": "{agent} session failed to load. Reload to retry, or start a new conversation.", - "sessionLoadUnavailable": "{agent} couldn't restore this session — it may have ended or the agent stopped. Reload to retry, or start a new conversation.", - "turnFailedRefusal": "{agent} refused to continue this turn. This often indicates a backend or gateway error — check the agent's logs.", - "turnFailedMaxTokens": "{agent} reached the maximum token limit for this turn.", - "turnFailedMaxTurnRequests": "{agent} reached the maximum number of allowed requests for this turn.", - "turnFailedUnknown": "{agent} ended the turn with an unrecognized stop reason.", - "grokModelSwitchIncompatibleAgent": "{agent} can't switch to that model in an existing conversation. Start a new session to use it.", - "turnFailedEmpty": "{agent} ended the turn without producing any response.", - "turnFailedEmptyProtocol": "{agent} produced output that codeg could not parse — the agent version may not match the protocol.", - "turnFailedEmptyMetadata": "{agent} sent only status updates this turn (plan / mode / usage) and no reply.", - "detailsInAlerts": "Open Alerts in the status bar and expand the details to see the agent's output." - }, - "unableReadAgentConfig": "Unable to read Agent config: {message}", - "connectFailedTitle": "{agent} connection failed", - "toolFallbackTitle": "Tool", - "eventErrorTitle": "Agent Error", - "notificationTurnComplete": "{agent} has finished responding", - "notificationError": "{agent} error: {message}", - "claudeApiRetry": { - "fallbackError": "authentication_failed", - "retryingWithMax": "retrying {attempt}/{max}", - "retryingAttempt": "retrying attempt {attempt}", - "retrying": "retrying", - "nextRetryIn": "next in {seconds}s", - "line": "{error}{status} · {retry}", - "lineWithDelay": "{error}{status} · {retry}, {delay}", - "httpStatus": " (HTTP {status})" - }, - "configOptionAdjusted": "{agent} set {option} to {actual} instead of {requested}" - }, - "connectionLifecycle": { - "tasks": { - "connectingTitle": "Connecting to {agent}", - "connectingDescription": "Establishing connection", - "loadingSelectorsTitle": "Loading {agent} selectors", - "loadingSelectorsDescription": "Fetching mode and session config options", - "initSessionTitle": "Initializing {agent} session", - "initSessionDescription": "Creating session and loading configuration" - }, - "errors": { - "connectionFailed": "Connection failed", - "sendPromptFailed": "Failed to send the message: {error}" - } - }, - "shared": { - "attachedResources": "Attached resources", - "toolCallFailed": "Tool call failed" - }, - "messageThread": { - "emptyTitle": "No messages yet", - "emptyDescription": "Start a conversation to see messages here" - }, - "chatInput": { - "connecting": "Connecting...", - "agentResponding": "{agent} is responding...", - "sendMessage": "Send a message..." - }, - "messageInput": { - "askAnything": "Ask anything...", - "removeAttachmentAria": "Remove {name}", - "attachFiles": "Attach files", - "attachLocalUpload": "Upload local file", - "attachServerFile": "Pick server file", - "addActions": "Add", - "quickMessages": "Quick messages", - "quickMessagesEmpty": "No quick messages yet", - "quickMessagesLoading": "Loading...", - "pasteAsPlainText": "Paste as plain text", - "cut": "Cut", - "copy": "Copy", - "selectAll": "Select all", - "pasteUnavailable": "Couldn't read the clipboard. Press Ctrl/⌘V to paste instead.", - "clipboardWriteFailed": "Couldn't write to the clipboard. Use the keyboard shortcut instead.", - "quickMessageUntitled": "Untitled", - "liveFeedback": "Live feedback", - "liveFeedbackDisabledHint": "Available while the agent is working", - "dropFilesToAttach": "Drop files to attach", - "loadingSettings": "Loading settings...", - "loadingMode": "Loading mode...", - "modeLabel": "Mode", - "toggleOn": "On", - "toggleOff": "Off", - "agentSettings": "Agent settings", - "searchModel": "Search models...", - "searchModelAria": "Search models", - "modelListLabel": "Models", - "noModels": "No models found", - "cancel": "Cancel", - "send": "Send", - "forkAndSend": "Fork & Send", - "queueMessage": "Queue message", - "steerIntoTurn": "Insert into current turn", - "steerQueuedInstead": "Queued instead — it will be sent with the next turn.", - "steerFailed": "Couldn't insert into the current turn", - "steerAttachmentsUnsupported": "Text only — drafts with attachments go through the queue.", - "slashCommands": "Slash commands", - "slashSearchPlaceholder": "Search commands...", - "slashSearchEmpty": "No matching commands", - "experts": "Experts", - "office": "Office Work", - "research": "Scientific Research", - "attachUploadTooLarge": "{names} exceeds the {limit}MB upload limit and was skipped.", - "attachUploadFailed": "Failed to upload {names}.", - "attachUploadNotAFile": "{names} isn't a regular file (directory or special file) and was skipped.", - "attachUploadQuotaExceeded": "The server is out of upload storage; {names} couldn't be uploaded.", - "attachUploadInProgress": "Images are still uploading — try again in a moment.", - "mentionEmpty": "No matches", - "mentionLoading": "Searching…", - "mentionListLabel": "Mentions", - "mentionMore": "More results — keep typing to filter", - "mentionCount": "{count, plural, one {# result} other {# results}}", - "mentionGroupFile": "Files", - "mentionGroupAgent": "Agents", - "mentionGroupSession": "Sessions", - "mentionGroupCommit": "Commits", - "mentionGroupSkill": "Skills" - }, - "messageQueue": { - "addToQueue": "Queue message", - "saveEdit": "Save", - "cancelEdit": "Cancel edit", - "editItem": "Edit", - "deleteItem": "Remove" - }, - "welcomeInputPanel": { - "agentsSettingsPath": "Settings > Agents", - "autoConnectFallback": "Click to open {path} and manage installation.", - "autoConnectAppend": "{message}. Click to open {path} and manage installation.", - "enableAgentFirstPlaceholder": "Enable at least one agent before starting a session...", - "prepareSessionFailed": "Couldn't prepare the chat session. Please try again.", - "createConversationFailed": "Couldn't create the conversation. Please try again.", - "askAnythingPlaceholder": "Ask anything...", - "agentNotInstalled": "{agent} is not installed — open Agents settings to install it", - "agentAdapterNotInstalled": "{agent}'s ACP adapter is not installed (separate from your own CLI) · open Agents settings to install it" - }, - "welcomePanel": { - "greeting": "What would you like to do today?", - "tips": { - "tileTabs": "Right-click any conversation tab and choose Tile Display to see multiple sessions side by side.", - "pinTab": "Double-click a conversation tab to pin it, so a newly opened session won't auto-replace it.", - "shortcutsNewSearch": "{newConversation} opens a new conversation, {searchConversations} searches your history.", - "slashAtMention": "Type / in the input to trigger slash commands, or @ to reference a file from the project.", - "pasteDropFiles": "Paste a screenshot or drop a file directly onto the input to attach it.", - "queueMessage": "While the agent is replying, keep typing — your next message gets queued and auto-sent when it finishes.", - "draftAutoSave": "Unsent drafts are auto-saved per conversation and restored when you come back.", - "forkSend": "The send button's dropdown has Fork and Send — branch from the current turn into a new tab.", - "exportConversation": "Right-click inside the conversation to export it as Markdown, HTML, or an image.", - "chatChannels": "Connect Telegram / Lark / WeChat under Settings → Chat Channels to continue from your phone.", - "shortcutsAuxPanel": "{toggleAuxPanel} toggles the right panel to view this session's touched files and Git changes.", - "shortcutsTerminalSidebar": "{toggleTerminal} opens the built-in terminal, {toggleSidebar} toggles the sidebar.", - "customShortcuts": "Every shortcut is fully remappable under Settings → Shortcuts.", - "webService": "Enable Settings → Web Service so teammates can reach the same codeg from a browser.", - "fusionMode": "Open a file or diff to automatically show it alongside the conversation.", - "quickMessages": "Open the + button next to the input and pick Quick Messages to insert a saved snippet (manage them under Settings → Quick Messages).", - "experts": "The + button has an Expert Skills menu — preload roles like Debug or Planning with one click.", - "taskBoard": "To-dos run a task end to end — the agent works in its own worktree, then you review the diff and merge.", - "automations": "Automations run a saved prompt on a schedule — a nightly review, a recurring report — and each run can get its own worktree.", - "tokenUsage": "Click the conversation count in the status bar to open Token Usage — spend broken down by day, agent, model, and folder.", - "mentionTargets": "@ pulls in more than files — mention another agent to hand off a subtask, or reference a past session, a commit, or a skill.", - "splitGroups": "Right-click a tab and pick Split Right or Split Down to keep two conversations open in their own panes.", - "worktrees": "Open the branch button and pick New worktree so several agents can work the same repo without overwriting each other's files.", - "importSessions": "Already ran sessions in the terminal? A folder's menu has Import local sessions — bring that history into codeg.", - "subSessions": "When an agent delegates, the sub-session appears nested under it in the sidebar — expand the row to follow what each one did.", - "liveFeedback": "Live feedback in the + menu drops a note into the turn the agent is already running, without interrupting it.", - "skillPacks": "Settings → Skill Packs bundles coding experts, scientific research, and office skills — switch them on per agent.", - "modelProviders": "Settings → Model Providers takes your own API key or endpoint, and you pick the model right in the composer.", - "workspaceBackground": "Settings → Appearance sets a workspace background image, panel opacity, and the app's fonts." - }, - "quickActions": { - "excel": "Excel Workbook", - "excelDesc": "Data tables, formulas & charts", - "word": "Word Document", - "wordDesc": "Reports, letters & memos", - "ppt": "Presentation", - "pptDesc": "Slides with professional design", - "pitchDeck": "Pitch Deck", - "pitchDeckDesc": "Fundraising deck with key metrics", - "morph": "Morph Animation", - "morphDesc": "Cinematic slide transitions", - "morph3d": "3D Morph", - "morph3dDesc": "3D models with camera moves", - "academic": "Academic Paper", - "academicDesc": "Research with citations & structure", - "financial": "Financial Model", - "financialDesc": "Statements, DCF & projections", - "dashboard": "Data Dashboard", - "dashboardDesc": "KPIs & analytics from your data", - "prompts": { - "excel": "Create an Excel workbook with the following requirements:\n\n[describe your data, tables, formulas, and charts here]", - "word": "Create a Word document with the following requirements:\n\n[describe your document content, structure, and formatting here]", - "ppt": "Create a PowerPoint presentation with the following requirements:\n\n[describe your slides, content, and design here]", - "pitchDeck": "Create a fundraising pitch deck with the following requirements:\n\n[describe your company, funding round, and key metrics here]", - "morph": "Create a presentation with Morph transition animations:\n\n[describe your presentation topic and desired visual effects here]", - "morph3d": "Create a 3D Morph presentation with GLB models and camera moves:\n\n[describe your topic and 3D visual concept here]", - "academic": "Write an academic paper in Word with the following requirements:\n\n[describe your research topic, methodology, and key findings here]", - "financial": "Create a financial model in Excel with the following requirements:\n\n[describe your financial statements, projections, and analysis here]", - "dashboard": "Create a data dashboard in Excel with the following requirements:\n\n[describe your data source, KPIs, and charts here]", - "scientific-brainstorming": "Help me brainstorm research directions — explore interdisciplinary connections, challenge assumptions, and surface promising gaps. The area I'm exploring: ", - "hypothesis-generation": "Help me turn these observations into testable hypotheses — with clear predictions, plausible mechanisms, and experiments to test them. My observations: ", - "experimental-design": "Help me design a rigorous experiment before I collect data — the design, randomization, controls, and how to avoid confounding. What I want to study: ", - "statistical-power": "Help me determine the sample size I need — walk me through a power analysis (effect size, alpha, power) for my design. Details: ", - "statistical-analysis": "Help me analyze this data properly — choose the right test, check assumptions, report effect sizes, and write it up. My data and question: ", - "exploratory-data-analysis": "Do an exploratory analysis of my data file — summarize its structure, quality, and notable patterns, then suggest next steps. The file is: ", - "scientific-visualization": "Help me make a publication-quality figure — clear layout, honest error bars, a colorblind-safe palette, and journal formatting. What I want to show: ", - "scientific-critical-thinking": "Help me critically appraise this study or claim — assess the evidence quality, spot biases and confounders, and weigh the conclusions. Here it is: ", - "paper-lookup": "Help me find relevant papers and open-access full text across scholarly databases, with citations I can reuse. I'm looking for: " - }, - "paper-lookup": "Paper Lookup", - "paper-lookupDesc": "Search 10 scholarly APIs (PubMed, arXiv, OpenAlex, Crossref…) for papers, citations, and open-access full text.", - "scientific-critical-thinking": "Critical Thinking", - "scientific-critical-thinkingDesc": "Appraise scientific claims and evidence quality — spot biases and confounders, apply GRADE and risk-of-bias frameworks.", - "scientific-visualization": "Scientific Visualization", - "scientific-visualizationDesc": "Publication-ready figures — multi-panel layouts, significance annotations, and journal-specific formatting.", - "exploratory-data-analysis": "Exploratory Data Analysis", - "exploratory-data-analysisDesc": "Automated exploration of scientific data files across 200+ formats with quality metrics and reports.", - "statistical-analysis": "Statistical Analysis", - "statistical-analysisDesc": "Guided statistical analysis — test selection, assumption checks, effect sizes, and APA-style reporting.", - "statistical-power": "Statistical Power", - "statistical-powerDesc": "Sample-size and power analysis — how many subjects you need, minimum detectable effects, and power curves.", - "experimental-design": "Experimental Design", - "experimental-designDesc": "Design rigorous studies before collecting data — randomization, blocking, controls, and factorial/DOE layouts.", - "hypothesis-generation": "Hypothesis Generation", - "hypothesis-generationDesc": "Turn observations into testable hypotheses with predictions, mechanisms, and experiments to test them.", - "scientific-brainstorming": "Scientific Brainstorming", - "scientific-brainstormingDesc": "Open-ended research ideation — explore interdisciplinary links, challenge assumptions, and surface research gaps.", - "tabs": { - "office": "Office Work", - "coding": "Code Development", - "research": "Scientific Research" - }, - "coding": { - "brainstormingDesc": "Explore intent & requirements before building", - "debuggingDesc": "Find the root cause before proposing fixes", - "writingSkillsDesc": "Create, edit & verify reusable skills" - }, - "notEnabled": { - "title": "“{skill}” isn’t enabled for {agent} yet", - "description": "Enable it in Settings to use it here.", - "action": "Enable", - "hint": "Skill not enabled" - }, - "scrollPrev": "Show previous skills", - "scrollNext": "Show more skills" - } - }, - "agentSelector": { - "noEnabledAgents": "No enabled agents", - "openAgentsSettings": "Open Agents settings", - "notInstalled": "Not installed", - "moreAgents": "More agents ({count})" - }, - "subAgentOverlay": { - "title": "Sub-agents", - "collapsedSummary": "Sub-agents {count}", - "collapseAria": "Collapse sub-agents" - }, - "agentPlanOverlay": { - "title": "Agent Plan", - "collapsePlanAria": "Collapse plan", - "collapsedSummary": "Plan {completed}/{total}", - "status": { - "completed": "Completed", - "inProgress": "In Progress", - "pending": "Pending", - "unknown": "Unknown" - }, - "priority": { - "high": "High", - "medium": "Medium", - "low": "Low", - "unknown": "Unknown" - } - }, - "permissionDialog": { - "subtitle": "Agent requests permission to continue this turn.", - "queuedCount": "+{count} waiting", - "kindFallbackTool": "tool", - "command": "Command", - "cwd": "CWD: {cwd}", - "filesSummary": "Files: {count}", - "moreFiles": "+{count} more files", - "plan": "Plan", - "allowedActions": "Allowed actions", - "targetMode": "Target mode: {mode}", - "optionGrants": "What each option grants", - "changeScopeSession": "This session", - "changeScopeProcess": "This run", - "changeScopeUser": "Saved to user settings", - "changeScopeProject": "Saved to project settings", - "changeScopeProjectLocal": "Saved to local project settings", - "changeScopePersistent": "Saved permanently" - }, - "questionDialog": { - "title": "Agent is asking a question", - "placeholder": "Type your answer...", - "send": "Send" - }, - "messageBranch": { - "previousBranchAria": "Previous branch", - "nextBranchAria": "Next branch", - "pageOf": "{current} of {total}" - }, - "terminal": { - "title": "Terminal", - "running": "Running" - }, - "reasoning": { - "thinking": "Thinking…", - "thoughtForFewSeconds": "Thought", - "thoughtForSeconds": "Thought" - }, - "linkSafety": { - "errorCannotOpen": "Cannot open local file", - "errorNoWorkspace": "No workspace folder is currently active.", - "errorFailedOpen": "Failed to open local file", - "errorFailedLink": "Failed to open link", - "errorUnsupportedLinkProtocol": "This link protocol is not supported." - }, - "fileActions": { - "openInFinder": "Open in Finder", - "openInExplorer": "Open in Explorer", - "openInFileManager": "Open in file manager", - "copyRelativePath": "Copy relative path", - "copyAbsolutePath": "Copy absolute path", - "pathCopied": "Path copied", - "copyPathFailed": "Failed to copy path", - "openFailed": "Failed to open local file" - }, - "messageList": { - "attachedResources": "Attached resources", - "loading": "Loading...", - "loadEarlier": "Load earlier messages", - "loadingEarlier": "Loading earlier messages…", - "error": "Error: {message}", - "errorTitle": "Session load failed", - "errorActionReload": "Reload", - "errorActionNewSession": "New conversation", - "emptyConversation": "No messages in this conversation.", - "systemMessage": "System message", - "copyMessage": "Copy", - "copied": "Copied", - "downloadImage": "Download image", - "downloadFailed": "Download failed: {message}", - "imageGeneration": "Image generation", - "imageGenerationPending": "Generating image…", - "imageGenerationFailed": "Image generation failed", - "model": "Model", - "tokenStats": "Token usage", - "tokenInput": "Input", - "tokenOutput": "Output", - "tokenCacheRead": "Cache read", - "tokenCacheWrite": "Cache write", - "duration": "Duration", - "completedAt": "Completed at", - "jumpToPreviousUserMessage": "Jump to user message", - "showMore": "Show more", - "showLess": "Show less" - }, - "liveTurnStats": { - "thinking": "Thinking...", - "streaming": "Streaming", - "elapsedHours": "{value}h", - "elapsedMinutes": "{value}m", - "elapsedSeconds": "{value}s", - "outputSpeedAria": "Estimated output speed", - "outputSpeedTooltip": "Estimated output speed (text + thinking)" - }, - "jsonTree": { - "viewRaw": "Show raw JSON", - "viewTree": "Show tree", - "fields": "{count, plural, one {# field} other {# fields}}", - "items": "{count, plural, one {# item} other {# items}}" - }, - "tool": { - "parameters": "Parameters", - "error": "Error", - "result": "Result", - "status": { - "approvalRequested": "Awaiting Approval", - "approvalResponded": "Responded", - "inputAvailable": "Running", - "inputStreaming": "Pending", - "outputAvailable": "Completed", - "outputDenied": "Denied", - "outputError": "Error" - } - }, - "toolCallBlock": { - "tool": "Tool", - "error": "Error", - "result": "Result" - }, - "delegation": { - "subAgentRunning": "Sub-agent running…", - "noDetail": "No detail available yet.", - "unknownAgent": "Sub-agent", - "openDetail": "Open conversation", - "detailTitle": "Sub-agent conversation", - "detailDescription": "Read-only view of the delegated sub-agent's conversation.", - "waitForResult": "Waiting for task {task} result", - "waitForResultNoTask": "Waiting for task result", - "cancelTask": "Canceling task {task}", - "cancelTaskNoTask": "Canceling task", - "resultPageOf": "{current} / {total}", - "prevResult": "Previous result", - "nextResult": "Next result", - "noResultText": "No result captured for this check.", - "status": { - "starting": "starting", - "running": "running", - "checked": "checked", - "waiting": "awaiting approval", - "ok": "done", - "err": { - "default": "failed", - "delegation_disabled": "disabled", - "depth_limit": "depth limit", - "invalid_agent_type": "bad agent", - "spawn_failed": "spawn failed", - "send_failed": "send failed", - "timeout": "timeout", - "canceled": "canceled", - "child_refusal": "subagent refused", - "child_max_tokens": "subagent token limit", - "child_max_turn_requests": "subagent request limit", - "child_empty": "subagent no output", - "child_unknown": "subagent unknown error", - "unknown": "unknown task" - } - } - }, - "contentParts": { - "showingTailOutput": "Showing tail output while streaming for performance.", - "result": "Result", - "unknown": "unknown", - "inputTruncated": "Input was truncated — diff may be incomplete.", - "replaceAll": "REPLACE ALL", - "filesCount": "Files: {count}", - "update": "update", - "moreFiles": "+{count} more files", - "timeoutMs": "Timeout: {timeout}ms", - "backgroundTrue": "Background: true", - "scriptToolCalls": "{count, plural, one {# tool call} other {# tool calls}}", - "offset": "Offset: {offset}", - "limit": "Limit: {limit}", - "pages": "Pages: {pages}", - "mode": "Mode: {mode}", - "cell": "Cell: {cell}", - "shellSession": "Session {id}", - "pathLabel": "Path:", - "globLabel": "Glob:", - "typeLabel": "Type:", - "outputLabel": "Output:", - "caseInsensitive": "Case insensitive", - "multiline": "Multiline", - "promptLabel": "Prompt", - "subjectLabel": "Subject", - "taskLabel": "Task", - "nameLabel": "Name:", - "agentPromptLabel": "Prompt", - "agentModelLabel": "Model", - "agentRunning": "Running...", - "agentLiveTranscript": "Live activity", - "agentProgressTools": "{count} tool calls", - "agentProgressTurns": "{count} turns", - "agentProgressContext": "context {pct}%", - "agentSessionAction": "View sub-agent session", - "agentSessionTitle": "Sub-agent session", - "agentSessionLoading": "Loading the sub-agent's transcript…", - "agentSessionEmpty": "The sub-agent hasn't written anything yet.", - "agentFallbackTitle": "Sub-agent starting…", - "agentCodexLaunchOnly": "Launched. Codex reports no further progress for this sub-agent — its result arrives as a message in this conversation.", - "agentStatsBash": "Commands", - "agentStatsRead": "Files read", - "agentStatsSearch": "Searches", - "agentStatsEdit": "Edits", - "agentStatsOther": "Other", - "goal": { - "title": "Goal:", - "titleWithStatus": "Goal {status}", - "objective": "Objective", - "statusLabel": "Status", - "tokensUsed": "Tokens used", - "budget": "Budget", - "remaining": "Remaining", - "elapsed": "Elapsed", - "tokens": "tokens", - "pause": "Pause", - "clear": "Clear", - "status": { - "active": "active", - "paused": "paused", - "blocked": "blocked", - "usageLimited": "usage limited", - "budgetLimited": "budget limited", - "complete": "complete", - "limited": "limit reached" - } - }, - "field": { - "file": "File", - "notebook": "Notebook", - "command": "Command", - "old": "Old", - "new": "New", - "pattern": "Pattern", - "path": "Path", - "query": "Query", - "url": "URL", - "description": "Description", - "content": "Content", - "source": "Source", - "prompt": "Prompt", - "subject": "Subject", - "taskId": "Task ID", - "status": "Status", - "skill": "Skill", - "args": "Args", - "offset": "Offset", - "limit": "Limit", - "glob": "Glob", - "type": "Type", - "output": "Output", - "replaceAll": "Replace All", - "language": "Language", - "timeout": "Timeout", - "background": "Background", - "agentType": "Agent Type", - "library": "Library", - "libraryId": "Library ID" - }, - "title": { - "edit": "Edit", - "command": "Command", - "script": "Script", - "waitCommand": "Wait {command}", - "waitCell": "Wait cell {id}", - "terminateCommand": "Terminate {command}", - "terminateCell": "Terminate cell {id}", - "stdinChars": "Stdin {chars}", - "todoWrite": "TodoWrite", - "read": "Read", - "write": "Write", - "notebookEdit": "NotebookEdit", - "editFiles": "Edit ({count} files)", - "editWithTarget": "Edit {target}", - "readWithTarget": "Read {target}", - "writeWithTarget": "Write {target}", - "notebookEditWithTarget": "NotebookEdit {target}", - "globWithPattern": "Glob {pattern}", - "listFilesWithPath": "List files {path}", - "grepWithPattern": "Grep {pattern}", - "taskCreateWithSubject": "TaskCreate: {subject}", - "taskUpdateWithStatus": "TaskUpdate #{id} -> {status}", - "taskUpdate": "TaskUpdate #{id}", - "webFetchWithUrl": "WebFetch {url}", - "webSearchWithQuery": "WebSearch: {query}", - "todosProgress": "Todos ({done}/{total})", - "skillWithName": "Skill: {name}", - "genericWithContext": "{tool}: {context}" - }, - "search": { - "noMatches": "No matches", - "matchSummary": "{matches, plural, one {# match} other {# matches}} in {files, plural, one {# file} other {# files}}", - "fileSummary": "{files, plural, one {# file} other {# files}}", - "moreResults": "{count, plural, one {# more result not shown} other {# more results not shown}}" - }, - "toolGroup": { - "search": "{count, plural, one {Explored # search} other {Explored # searches}}", - "command": "{count, plural, one {Ran # command} other {Ran # commands}}", - "read": "{count, plural, one {Read files # time} other {Read files # times}}", - "memory": "{count, plural, one {Recalled # memory} other {Recalled # memories}}", - "edit": "{count, plural, one {Edited files # time} other {Edited files # times}}", - "fetch": "{count, plural, one {Fetched # resource} other {Fetched # resources}}", - "think": "{count, plural, one {Thought # time} other {Thought # times}}", - "todo": "{count, plural, one {Updated # todo} other {Updated # todos}}", - "task": "{count, plural, one {Ran # task} other {Ran # tasks}}", - "other": "{count, plural, one {Used # tool} other {Used # tools}}", - "errorSuffix": "{count, plural, one {# failed} other {# failed}}", - "joiner": " · " - }, - "planMode": { - "entered": "Entered plan mode", - "planLabel": "Plan", - "reviewApproved": "Plan approved — implementing", - "reviewKept": "Kept in plan mode", - "reviewPending": "Awaiting plan decision", - "submitted": "Plan submitted", - "switched": "Switched mode" - }, - "backgroundTask": { - "title": "Background task", - "titleWithId": "Background task · {id}", - "running": "Running", - "completed": "Completed", - "failed": "Failed", - "stopped": "Stopped", - "exitCode": "exit {code}", - "polledTimes": "Polled {count} times", - "runningInBackground": "Background", - "launchNote": "Running in background · {id}" - }, - "codexScript": { - "outputMissing": "Codex truncated the script output and dropped this command's separator, so none of the output could be attributed to it.", - "sharedWith": "Also contains the output of {commands} — codex truncated their separators away.", - "truncated": "truncated" - } - }, - "messageNav": { - "title": "Message navigation", - "collapse": "Collapse message navigation", - "collapsedSummary": "Messages {count}", - "fileCount": "{count, plural, one {# file} other {# files}}", - "remove": "Remove", - "noDiffDataAvailable": "No diff data available for {filePath}" - }, - "replyArtifacts": { - "title": "Files changed", - "fileCount": "{count, plural, one {# file} other {# files}}", - "newFilesTitle": "New files", - "revealInFolder": "Show in file manager", - "openFile": "Open {filePath}", - "openInEditor": "Open in editor", - "remove": "Remove", - "noDiffDataAvailable": "No diff data available for {filePath}" - }, - "askQuestion": { - "title": "The agent needs your input", - "subtitle": "Answer below, then submit. You can skip anytime.", - "recommended": "Recommended", - "other": "Other", - "otherPlaceholder": "Type your answer…", - "singleSelect": "Single", - "multiSelect": "Multiple", - "skip": "Skip", - "next": "Next", - "submit": "Submit", - "submitError": "Couldn't submit. Please try again." - }, - "planApproval": { - "title": "The agent has a plan — review it", - "emptyPlan": "The agent didn't write a plan. Approve to start building, or request changes.", - "approve": "Approve & build", - "requestChanges": "Request changes", - "abandon": "Abandon", - "feedbackPlaceholder": "What should change?", - "sendChanges": "Send", - "cancel": "Cancel", - "submitError": "Couldn't submit. Please try again." - }, - "feedbackCheckResult": { - "count": "{count, plural, =1 {1 feedback note} other {# feedback notes}}", - "expand": "Show all feedback", - "collapse": "Collapse", - "errorTitle": "Feedback check failed" - }, - "askQuestionResult": { - "title": "Question", - "answeredLabel": "Q&A:", - "awaiting": "Waiting for your answer…", - "declined": "You dismissed this — the agent used its own judgment.", - "noSelection": "No selection" - }, - "configStale": { - "agentConfigTitle": "Agent settings updated", - "modelProviderTitle": "Model provider updated", - "description": "This session is still using its previous configuration. Reconnect to apply — your conversation history is kept.", - "reconnect": "Reconnect to apply", - "reconnecting": "Reconnecting…", - "reconnectDisabledDuringTurn": "Available once the current turn finishes", - "dismiss": "Dismiss", - "reconnectFailed": "Failed to reconnect session", - "applied": "New configuration applied" - }, - "piProjectTrust": { - "title": "This project ships pi resources", - "description": "pi is not loading the repository's own .pi files. Review them to decide.", - "descriptionExecutable": "The repository ships pi extensions, which run code at startup. pi is not loading them. Review before you decide.", - "review": "Review…", - "dismiss": "Dismiss", - "dialogTitle": "Trust this project's pi resources?", - "dialogDescription": "pi only loads a repository's own .pi files once you trust the folder. Trust it only if you trust this repository's contents.", - "executionWarning": "Extensions are code. Trusting this folder lets the repository run them at pi startup with your permissions, before you send any message.", - "scopeNote": "The decision is saved in pi's trust.json for this folder, applies to every folder inside it, and is also used when you run pi yourself in a terminal. You can change it later in Settings → Agents → Pi.", - "trust": "Trust project", - "decline": "Keep unloaded", - "disabledDuringTurn": "Available once the current turn finishes", - "trustedToast": "Project trusted — reconnected so pi loads its resources", - "declinedToast": "Project resources stay unloaded", - "saveFailed": "Failed to save the project trust decision", - "grantTitle": "This project is already trusted", - "grantDescription": "pi loads this repository's own .pi files. Review what that allows.", - "grantInheritedDescription": "A parent folder is trusted, so pi loads this repository's own .pi files. Review what that allows.", - "grantDialogTitle": "This project's pi resources are trusted", - "grantDialogDescription": "pi is allowed to load this repository's own .pi files. Earlier codeg versions granted this automatically when you opened a folder, so you may not have been asked.", - "grantExecutionWarning": "Extensions are code. The repository runs them at pi startup with your permissions, before you send any message.", - "inheritedFrom": "Trusted via", - "revoke": "Revoke trust", - "keepTrusted": "Keep trusted", - "revokedToast": "Trust revoked — reconnected so pi stops loading the project's resources", - "trustedNoReconnect": "Project trusted — it applies the next time pi starts", - "revokedNoReconnect": "Trust revoked — it applies the next time pi starts" - }, - "collabAgent": { - "title": "Sub-agent", - "errorTitle": "Sub-agent task failed", - "statesLabel": "Sub-agents", - "statusRunning": "Running", - "statusCompleted": "Completed", - "statusFailed": "Failed", - "statusPending": "Starting", - "statusInterrupted": "Interrupted", - "statusClosed": "Closed", - "statusNotFound": "Not found", - "opSpawn": "Starting sub-agent", - "opWait": "Fetching sub-agent result", - "opClose": "Closing sub-agent", - "opResume": "Resuming sub-agent" - }, - "contextCompaction": { - "compacting": "Compacting context…", - "compacted": "Context compacted", - "compactedTokens": "Context compacted · {before} → {after} tokens", - "failed": "Context compaction failed" - }, - "sessionFailure": { - "category": { - "connection": "Connection issue", - "access": "Access issue", - "limit": "Limit reached", - "request": "Request rejected", - "service": "Service issue", - "unknown": "Session issue" - }, - "action": { - "retry": "Retry", - "login": "Sign in", - "newSession": "New session" - }, - "recovered": "Recovered", - "retryUnavailable": "No previous message to resend.", - "toggleDetails": "Toggle details" - }, - "backgroundTasks": { - "running": "{count, plural, one {# background task running} other {# background tasks running}}", - "settling": "Syncing background results…", - "settledFallback": "Background task finished ({status})", - "cardRunning": "Running in background", - "cardLaunchedPending": "Launched in background", - "cardCompleted": "Background task completed", - "cardFinishedWithStatus": "Background task finished ({status})", - "cardResultPending": "Result not returned yet" - }, - "proposedPlan": { - "title": "Proposed plan", - "planning": "Planning…" - } - }, - "diffPreview": { - "mode": { - "added": "Added", - "deleted": "Deleted", - "renamed": "Renamed", - "modified": "Modified" - }, - "hunkLabel": "Hunk {index}", - "loadingHunk": "Loading hunk...", - "noDiffData": "No diff data", - "showRemainingLines": "Show {count} more lines" - }, - "conversationContextBar": { - "folderTitle": "Working folder", - "branchTitle": "Working branch", - "searchFolder": "Search folder...", - "searchBranch": "Search branch...", - "noFolders": "No folders", - "noBranches": "No branches", - "noBranch": "(no branch)", - "chatModeLabel": "Chat mode", - "commit": "Commit", - "push": "Push", - "merge": "Merge", - "toasts": { - "folderChanged": "Switched to {name}", - "openFolderFailed": "Failed to open folder", - "switchedToChatMode": "Switched to chat mode", - "openStashFailed": "Failed to open stash window", - "openMergeFailed": "Failed to open merge window" - } - }, - "cloneDialog": { - "title": "Clone Repository", - "repositoryUrl": "Repository URL", - "repositoryUrlPlaceholder": "https://github.com/user/repo.git", - "directory": "Directory", - "directoryPlaceholder": "Select target directory...", - "browseDirectory": "Browse directory", - "cancel": "Cancel", - "clone": "Clone", - "clonePath": "Clone path: {path}" - }, - "toasts": { - "cloneFailed": "Failed to clone repository" - } - }, - "ProjectBoot": { - "title": "Project Boot", - "tabs": { - "shadcn": "shadcn", - "hyperframes": "HyperFrames" - }, - "hyperframes": { - "title": "HyperFrames Video Project", - "subtitle": "Scaffold an HTML-to-video project. Your workspace agent can then write and render it.", - "resolution": "Resolution", - "skillsTitle": "Agent Skills", - "skillsDesc": "Globally install the HyperFrames skills (symlinked) for the selected agents so they can author and render video.", - "recheck": "Re-check", - "installedBadge": "Installed", - "skillsInstall": "Install / update skills", - "skillsInstalling": "Installing skills…", - "skillsInstalled": "HyperFrames skills installed", - "skillsInstallFailed": "Couldn't install HyperFrames skills" - }, - "config": { - "base": "Base", - "style": "Style", - "baseColor": "Base Color", - "theme": "Theme", - "chartColor": "Chart Color", - "iconLibrary": "Icon Library", - "font": "Font", - "fontHeading": "Heading Font", - "menuAccent": "Menu Accent", - "menuColor": "Menu Color", - "radius": "Radius", - "template": "Template", - "createProject": "Create Project", - "sectionStyle": "Style", - "sectionColors": "Colors", - "sectionTypography": "Typography", - "sectionInterface": "Interface" - }, - "preview": { - "loading": "Loading preview..." - }, - "createDialog": { - "title": "Create Project", - "projectName": "Project Name", - "projectNamePlaceholder": "my-app", - "frameworkTemplate": "Framework Template", - "packageManager": "Package Manager", - "saveDirectory": "Save Directory", - "saveDirectoryPlaceholder": "Select directory...", - "browseDirectory": "Browse", - "projectPath": "Project will be created at: {path}", - "advancedOptions": "Advanced Options", - "base": "Base Library", - "enableRtl": "Enable RTL Support", - "enableRtlDescription": "Enable layout support for right-to-left languages (e.g. Arabic, Hebrew)", - "pmChecking": "Checking...", - "pmNotInstalled": "Not installed", - "cancel": "Cancel", - "create": "Create", - "creating": "Creating project..." - }, - "toasts": { - "createFailed": "Failed to create project", - "createSuccess": "Project created successfully", - "openWorkspaceFailed": "Project created, but couldn't open it in the workspace" - }, - "errors": { - "directoryExists": "Target directory already exists", - "commandFailed": "Project creation command failed." - } - }, - "WebServiceSettings": { - "addressSwitchHint": "Switching only changes the address shown and opened here — the service listens on all interfaces and stays reachable at every address.", - "sectionTitle": "Web Service", - "sectionDescription": "Enable to access Codeg remotely via browser", - "port": "Port", - "status": "Status", - "autoStart": "Auto-start", - "autoStartHint": "Start the Web service when Codeg launches", - "running": "Running", - "stopped": "Stopped", - "processing": "Processing...", - "start": "Start", - "stop": "Stop", - "startFailed": "Failed to start", - "stopFailed": "Failed to stop", - "saveConfigFailed": "Failed to save Web service settings", - "open": "Open", - "hide": "Hide", - "show": "Show", - "copy": "Copy", - "qrcode": "QR Code", - "qrcodeTitle": "Scan to Open", - "qrcodeHint": "Scan with your phone to open Codeg in a browser", - "addressLabel": "Access Address", - "tokenLabel": "Access Token", - "tokenHint": "Enter this token when accessing the Web client for the first time", - "tokenPlaceholder": "Leave empty to auto-generate", - "regenerate": "Regenerate", - "stalePortOccupiedTitle": "Port {port} is held by another process", - "stalePortUnknownTitle": "Port {port} status is unclear", - "stalePortHint": "Codeg can't bind here until the port is released. Change the port above, or close the process holding it.", - "errors": { - "alreadyRunning": "Web service is already running", - "invalidAddress": "Invalid host or port format", - "portInUse": "Port {port} is already in use. Close the process using it or choose another port.", - "permissionDenied": "Permission denied. Try a port above 1024 or run with higher privileges.", - "addressUnavailable": "The address is not available on this machine", - "bindFailed": "Failed to bind address" - } - }, - "DirectoryBrowser": { - "title": "Browse Directory", - "pathPlaceholder": "Enter directory path...", - "goHome": "Go to home directory", - "navigateUp": "Go to parent directory", - "select": "Select", - "cancel": "Cancel", - "loading": "Loading...", - "emptyDirectory": "This directory is empty", - "errorLoadingDir": "Failed to load directory", - "permissionDenied": "Permission denied" - }, - "ServerFileBrowser": { - "title": "Pick server file", - "pathPlaceholder": "Enter directory path...", - "goHome": "Go to home directory", - "navigateUp": "Go to parent directory", - "select": "Select", - "cancel": "Cancel", - "loading": "Loading...", - "emptyDirectory": "This directory is empty", - "errorLoadingDir": "Failed to load directory", - "selectedCount": "{count} selected" - }, - "ChatChannelSettings": { - "loading": "Loading...", - "sectionTitle": "Chat Channels", - "sectionDescription": "Configure IM bots to receive event notifications and query coding activity.", - "addChannel": "Add Channel", - "noChannels": "No chat channels configured yet.", - "channelName": "Name", - "channelNamePlaceholder": "My Telegram Bot", - "channelType": "Channel Type", - "lark": "Lark (Feishu)", - "weixin": "WeChat", - "dailyReport": "Daily Report", - "dailyReportTime": "Report Time", - "nameRequired": "Channel name is required.", - "tokenRequired": "Token is required.", - "chatIdRequired": "Chat ID is required.", - "topicMode": "Topic group mode", - "topicModeHint": "Route Telegram forum topics as separate Codeg sessions. The bot must be in a forum supergroup and be allowed to manage topics.", - "loadFailed": "Failed to load channels.", - "saveFailed": "Failed to save changes.", - "connectSuccess": "Channel connected.", - "connectFailed": "Failed to connect", - "disconnectSuccess": "Channel disconnected.", - "disconnectFailed": "Failed to disconnect.", - "testSuccess": "Connection test passed.", - "testFailed": "Connection test failed", - "deleteSuccess": "Channel deleted.", - "deleteFailed": "Failed to delete channel.", - "deleteConfirmTitle": "Delete Channel", - "deleteConfirmMessage": "This will permanently delete the channel and its message logs. Are you sure?", - "cancel": "Cancel", - "delete": "Delete", - "create": "Create", - "save": "Save", - "channelListTitle": "Configured Channels", - "channelListDescription": "Enabled channels will auto-connect when the service starts.", - "editChannel": "Edit Channel", - "editSuccess": "Channel updated.", - "tokenPlaceholderKeep": "Leave blank to keep current", - "weixinScanTitle": "Scan QR Code", - "weixinScanDescription": "Open WeChat and scan the QR code to connect.", - "weixinQrcodeExpired": "QR code expired.", - "weixinRefreshQrcode": "Refresh", - "weixinWaitingScan": "Waiting for scan...", - "weixinPollError": "Connection unstable, retrying...", - "weixinReconnectNotice": "Due to iLink protocol limitations, after each reconnection you must send a message to the bot before event triggers take effect.", - "connect": "Connect", - "disconnect": "Disconnect", - "test": "Test Connection", - "tabs": { - "channels": "Channels", - "commands": "Commands", - "events": "Events", - "other": "Other" - }, - "commands": { - "title": "Built-in Commands", - "description": "Bot commands available in chat channels. In group chats, @Bot is required to process messages.", - "prefixLabel": "Command Prefix", - "prefixDescription": "1-3 non-alphanumeric characters used to trigger bot commands (default /).", - "prefixSaved": "Command prefix saved.", - "prefixSaveFailed": "Failed to save command prefix.", - "prefixInvalid": "Prefix must be 1-3 non-alphanumeric characters.", - "save": "Save", - "folderDesc": "Select working folder", - "agentDesc": "Select AI agent", - "taskDesc": "Create session and run task", - "sessionsDesc": "List active sessions in folder", - "resumeDesc": "Recent conversations / resume a session", - "cancelDesc": "Cancel current task", - "approveDesc": "Approve agent permission request", - "denyDesc": "Deny agent permission request", - "searchDesc": "Search conversations by keyword", - "todayDesc": "Today's activity summary", - "statusDesc": "Channel connection status", - "helpDesc": "Show help message" - }, - "events": { - "title": "Event Notifications", - "description": "When enabled, triggered events will be pushed to the channel.", - "turnComplete": "Turn Complete", - "turnCompleteDesc": "When an agent turn ends", - "error": "Agent Error", - "errorDesc": "When an agent encounters an error", - "permissionRequest": "Permission Request", - "permissionRequestDesc": "When an agent requests permission to act", - "questionRequest": "Agent Question", - "questionRequestDesc": "When an agent asks you a question", - "userPromptSent": "User Message", - "userPromptSentDesc": "When you send a message — the message text is included in the notification", - "saved": "Event filter updated.", - "saveFailed": "Failed to save event filter.", - "loadFailed": "Failed to load settings.", - "retry": "Retry", - "webhooksTitle": "Webhooks", - "webhooksDescription": "POST a JSON payload to one or more URLs when an enabled event fires. The event filter above also applies to webhooks.", - "webhookUrlPlaceholder": "https://example.com/webhook", - "addWebhook": "Add Webhook", - "removeWebhook": "Remove webhook", - "webhookSave": "Save", - "webhooksSaved": "Webhooks saved.", - "webhooksSaveFailed": "Failed to save webhooks.", - "webhookInvalidUrl": "Enter valid http(s) URLs.", - "docsTitle": "Request Format", - "docsMethod": "Method", - "docsContentType": "Content-Type", - "docsNote": "Each enabled event is delivered to every URL. Webhooks are not debounced; the event filter above still applies.", - "editWebhook": "Edit Webhook", - "enableWebhook": "Enable webhook", - "webhookDuplicate": "This URL is already configured.", - "cancel": "Cancel", - "webhooksEmpty": "No webhooks configured yet.", - "deleteWebhookTitle": "Delete Webhook", - "deleteWebhookMessage": "Remove this webhook? Events will no longer be delivered to this URL.", - "delete": "Delete" - }, - "language": { - "title": "Message Language", - "description": "Language used for event notifications, command responses, and daily reports sent to chat channels.", - "saved": "Message language saved.", - "saveFailed": "Failed to save message language.", - "en": "English", - "zh-cn": "Simplified Chinese", - "zh-tw": "Traditional Chinese", - "ja": "Japanese", - "ko": "Korean", - "es": "Spanish", - "de": "German", - "fr": "French", - "pt": "Portuguese", - "ar": "Arabic" - } - }, - "ModelProviderSettings": { - "sectionTitle": "Model Providers", - "sectionDescription": "Manage API provider credentials for agents.", - "filterAll": "All", - "providerListTitle": "Configured Providers", - "addProvider": "Add Provider", - "editProvider": "Edit Provider", - "noProviders": "No model providers configured yet.", - "providerName": "Name", - "providerNamePlaceholder": "e.g. OpenAI, Anthropic", - "apiUrl": "API URL", - "apiUrlPlaceholder": "https://api.openai.com/v1", - "apiKey": "API Key", - "apiKeyPlaceholder": "sk-...", - "apiKeyKeepCurrent": "Leave blank to keep current", - "agentTypes": "Agent Types", - "agentTypesRequired": "At least one agent type is required.", - "agentType": "Agent Type", - "agentTypeRequired": "Agent type is required.", - "agentTypeImmutableHint": "Agent type cannot be changed after creation.", - "model": "Model", - "modelPlaceholderCodex": "gpt-5.6-sol / gpt-5.5", - "modelPlaceholderGemini": "gemini-3-pro-preview", - "claudeMainModel": "Main Model", - "claudeReasoningModel": "Reasoning Model (thinking)", - "claudeHaikuDefaultModel": "Default Haiku Model", - "claudeSonnetDefaultModel": "Default Sonnet Model", - "claudeOpusDefaultModel": "Default Opus Model", - "claudeCustomModelOption": "Custom Model ID", - "claudeCustomModelOptionName": "Custom Model Name", - "claudeCustomModelOptionDescription": "Custom Model Description", - "claudeCustomModelOptionHint": "Adds a single custom entry to Claude's model picker (e.g. a model behind a custom gateway/proxy). Name and description are optional display overrides.", - "nameRequired": "Provider name is required.", - "apiUrlRequired": "API URL is required.", - "apiKeyRequired": "API Key is required.", - "loadFailed": "Failed to load providers.", - "saveFailed": "Failed to save changes.", - "createSuccess": "Provider created.", - "editSuccess": "Provider updated.", - "deleteSuccess": "Provider deleted.", - "deleteConfirmTitle": "Delete Provider", - "deleteConfirmMessage": "This will permanently delete the provider \"{name}\". Are you sure?", - "deleteBlockedByAgent": "{agents} is currently using this provider. Please unlink before deleting.", - "cancel": "Cancel", - "delete": "Delete", - "create": "Create", - "save": "Save", - "affectedRunningSessions": "{count, plural, one {# running session needs to reconnect to apply the change} other {# running sessions need to reconnect to apply the change}}" - }, - "SkillMatrix": { - "loading": "Loading…", - "searchPlaceholder": "Search by name, id, or description", - "empty": "Nothing to show.", - "emptySearch": "No matches for the current search.", - "skillColumn": "Skill", - "selectAll": "Select all visible", - "selectSkill": "Select {name}", - "everything": { - "label": "Bulk", - "enable": "Enable everything (visible)", - "disable": "Disable everything (visible)" - }, - "columnMenu": { - "enableAll": "Enable all skills", - "disableAll": "Disable all skills" - }, - "rowMenu": { - "label": "Batch actions for {name}", - "enableAll": "Enable for all agents", - "disableAll": "Disable for all agents" - }, - "bulk": { - "selected": "{count} selected", - "targetAll": "All agents", - "targetSome": "{count} agents", - "enable": "Enable", - "disable": "Disable", - "clear": "Clear" - }, - "confirm": { - "disableTitle": "Disable these links?", - "disableBody": "This removes {count} codeg-managed skill link(s). Skills occupying a custom directory are left untouched. You can re-enable them anytime.", - "cancel": "Cancel", - "confirm": "Disable" - }, - "toasts": { - "loadFailed": "Failed to load skill statuses", - "applyFailed": "Failed to apply changes", - "enabled": "Enabled {count} link(s)", - "disabled": "Disabled {count} link(s)", - "enabledPartial": "Enabled {ok}, {failed} failed", - "disabledPartial": "Disabled {ok}, {failed} failed" - }, - "detail": { - "enableForAgents": "Enable for agents", - "preview": "SKILL.md preview", - "loadingContent": "Loading content…" - }, - "copyModeHint": "Copied (not linked) — re-enable after updates for the latest version" - }, - "ExpertsSettings": { - "title": "Expert Skills", - "description": "Enable curated, battle-tested skill workflows for your AI coding agents. Each expert is a standalone skill from the superpowers project — codeg manages the central copy and links it into the agents you choose.", - "loading": "Loading experts…", - "loadingContent": "Loading content…", - "emptyExperts": "No experts available. Check the application logs.", - "emptySelection": "Select an expert to see its content and manage activation.", - "emptySearch": "No experts match the current search.", - "searchPlaceholder": "Search experts by name, id, or description", - "enableForAgents": "Enable for agents", - "noAgents": "No ACP agents detected.", - "copyModeWarning": "Copied (not linked). Re-enable after codeg updates to get the latest version.", - "previewTitle": "SKILL.md preview", - "categories": { - "discovery": "Discovery & Design", - "planning": "Planning", - "execution": "Execution", - "quality": "Quality & Testing", - "debugging": "Debugging", - "review": "Review & Integration", - "meta": "Meta" - }, - "states": { - "not_linked": "Not enabled", - "linked_to_codeg": "Enabled", - "linked_elsewhere": "Blocked — another link exists", - "blocked_by_real_directory": "Blocked — a custom skill occupies this name", - "broken": "Broken link" - }, - "badges": { - "userModified": "User modified" - }, - "actions": { - "openCentralDir": "Open central folder", - "refresh": "Refresh" - }, - "toasts": { - "loadFailed": "Failed to load expert details", - "enabled": "Expert enabled for this agent", - "disabled": "Expert disabled for this agent", - "enableFailed": "Failed to enable expert", - "disableFailed": "Failed to disable expert", - "openFolderFailed": "Failed to open folder" - } - }, - "ScienceSettings": { - "title": "Scientific Research Skills", - "description": "Enable curated scientific-research skills for your AI coding agents — hypothesis generation, experimental design, statistics, visualization, critical appraisal, and literature search. codeg manages a central copy and links each skill into the agents you choose.", - "loading": "Loading science skills…", - "emptySkills": "No science skills available. Check the application logs.", - "searchPlaceholder": "Search science skills by name, id, or description", - "categories": { - "ideation": "Ideation", - "design": "Study Design", - "analysis": "Analysis", - "visualization": "Visualization", - "evaluation": "Evaluation", - "literature": "Literature" - }, - "states": { - "not_linked": "Not enabled", - "linked_to_codeg": "Enabled", - "linked_elsewhere": "Blocked — another link exists", - "blocked_by_real_directory": "Blocked — a custom skill occupies this name", - "broken": "Broken link" - }, - "badges": { - "userModified": "User modified", - "needsKey": "Needs API key", - "needsSetup": "May need setup" - }, - "actions": { - "openCentralDir": "Open central folder", - "refresh": "Refresh" - }, - "toasts": { - "openFolderFailed": "Failed to open folder" - } - }, - "OfficeToolsSettings": { - "title": "Office Tools", - "description": "Manage OfficeCLI skills for creating Excel, Word, and PowerPoint files. Install OfficeCLI, sync skills, and enable them per agent.", - "loadingContent": "Loading content…", - "emptySkills": "No skills available. Install OfficeCLI and sync skills to get started.", - "emptySelection": "Select a skill to see its content and manage activation.", - "emptySearch": "No skills match the current search.", - "searchPlaceholder": "Search skills by name, id, or description", - "enableForAgents": "Enable for agents", - "noAgents": "No ACP agents detected.", - "installFirst": "Install OfficeCLI first to enable skills for agents.", - "syncFirst": "Sync skills first to load this skill's content.", - "noContent": "No content available.", - "copyModeWarning": "Copied (not linked). Re-sync to get the latest version.", - "previewTitle": "SKILL.md preview", - "detection": { - "installed": "Installed", - "notInstalled": "Not installed", - "notRunnable": "Installed but not runnable", - "installHint": "Install OfficeCLI to enable office document generation skills for your AI agents.", - "install": "Install", - "uninstall": "Uninstall", - "syncSkills": "Sync Skills" - }, - "categories": { - "general": "General", - "presentations": "Presentations", - "documents": "Documents", - "spreadsheets": "Spreadsheets" - }, - "states": { - "not_linked": "Not enabled", - "linked_to_codeg": "Enabled", - "linked_elsewhere": "Blocked — another link exists", - "blocked_by_real_directory": "Blocked — a custom skill occupies this name", - "broken": "Broken link" - }, - "badges": { - "notSynced": "Not synced" - }, - "actions": { - "refresh": "Refresh" - }, - "toasts": { - "loadFailed": "Failed to load skill details", - "enabled": "Skill enabled for this agent", - "disabled": "Skill disabled for this agent", - "enableFailed": "Failed to enable skill", - "disableFailed": "Failed to disable skill", - "installSuccess": "OfficeCLI installed successfully", - "installFailed": "Failed to install OfficeCLI", - "uninstallSuccess": "OfficeCLI uninstalled", - "uninstallFailed": "Failed to uninstall OfficeCLI", - "syncSuccess": "{synced} skills synced successfully", - "syncPartial": "{synced} skills synced, {errors} failed", - "syncFailed": "Failed to sync skills" - }, - "autoPreviewLabel": "Auto-open preview", - "autoPreviewHint": "When an agent creates or edits a Word, Excel, or PowerPoint file, open its live preview automatically." - }, - "SkillPacksSettings": { - "title": "Skill Packs", - "description": "Curated skill bundles that codeg manages centrally and links into your AI agents — coding experts, scientific research, and office document tools. Enable them per agent below.", - "tabs": { - "experts": "Experts", - "science": "Science", - "office": "Office Tools", - "custom": "Custom" - }, - "actions": { - "openCentralDir": "Open central folder", - "refresh": "Refresh" - }, - "toasts": { - "openFolderFailed": "Failed to open folder" - } - }, - "QuickMessagesSettings": { - "title": "Quick Messages", - "description": "Manage reusable message snippets. Drag to reorder.", - "loading": "Loading quick messages…", - "emptyList": "No quick messages yet. Click \"New\" to create one.", - "emptySelection": "Select a quick message to edit.", - "searchPlaceholder": "Search by title or content", - "untitled": "Untitled", - "actions": { - "new": "New", - "save": "Save", - "delete": "Delete", - "dragSort": "Drag to reorder", - "dragSortMessage": "Drag to reorder quick message: {name}" - }, - "fields": { - "title": "Title", - "titlePlaceholder": "Give this message a short title", - "content": "Content", - "contentPlaceholder": "Write the message content here" - }, - "confirmDelete": { - "title": "Delete quick message?", - "message": "This will permanently delete \"{name}\". Are you sure?", - "cancel": "Cancel", - "confirm": "Delete" - }, - "toasts": { - "loadFailed": "Failed to load quick messages", - "createFailed": "Failed to create quick message", - "saveFailed": "Failed to save quick message", - "deleteFailed": "Failed to delete quick message", - "saveOrderFailed": "Failed to save order", - "created": "Quick message created", - "saved": "Quick message saved", - "deleted": "Quick message deleted" - } - }, - "Pet": { - "badge": { - "running": "{count} running", - "waiting": "{count} awaiting approval", - "error": "{count} errored" - }, - "panel": { - "title": "Active sessions", - "empty": "No active sessions", - "emptyHint": "Running agents and ones that need you appear here.", - "statusRunning": "Running", - "statusWaiting": "Waiting", - "statusError": "Error", - "subAgentOf": "Sub-agent of" - }, - "menu": { - "scale": "Scale", - "openManager": "Manage pets", - "close": "Close" - }, - "loadError": "Failed to load pet", - "missingPetIdParam": "No pet selected", - "summonButton": "Pet", - "manager": { - "title": "Pets", - "description": "Floating desktop companions powered by Codex-compatible sprite sheets.", - "addPet": "Add pet", - "importFromCodex": "Import from Codex", - "noPets": "No pets yet. Add one or import from Codex.", - "setActive": "Set active", - "active": "Active", - "edit": "Edit", - "delete": "Delete", - "deleteConfirm": "Delete pet \"{name}\"? It will be removed from disk.", - "summon": "Summon pet window", - "openCodexHelp": "Codex pets must be installed under ~/.codex/pets/. None found.", - "specRequirement": "Spritesheet must be 1536px wide with a height in 208px rows (e.g. 1872 or 2288), PNG or WebP with transparency.", - "form": { - "id": "Pet ID", - "idHelp": "Lowercase letters, digits, '-' and '_'. Max 64 chars.", - "displayName": "Display name", - "description": "Description (optional)", - "spritesheet": "Spritesheet", - "chooseFile": "Choose file", - "replaceFile": "Replace spritesheet", - "saveCreate": "Add pet", - "saveUpdate": "Save changes", - "cancel": "Cancel" - }, - "errors": { - "missingId": "Pet id is required", - "missingName": "Display name is required", - "missingSpritesheet": "Spritesheet is required", - "addFailed": "Failed to add pet", - "updateFailed": "Failed to update pet", - "deleteFailed": "Failed to delete pet", - "loadFailed": "Failed to load pets", - "setActiveFailed": "Failed to set active pet", - "summonFailed": "Failed to summon pet window" - } - }, - "import": { - "title": "Import from Codex", - "subtitle": "These pets are available under ~/.codex/pets/.", - "selectAll": "Select all", - "alreadyImported": "Already imported", - "renameOnConflict": "Rename conflicts with -imported suffix", - "import": "Import selected", - "noneFound": "No importable Codex pets found.", - "imported": "Imported successfully", - "failed": "Import failed", - "close": "Close" - }, - "marketplace": { - "openMarketplace": "Pet marketplace", - "title": "Pet marketplace", - "search": "Search pets", - "kindFilter": { - "all": "All", - "object": "Object", - "animal": "Animal", - "person": "Person", - "creature": "Creature" - }, - "sortFilter": { - "latest": "Latest", - "popular": "Popular", - "views": "Most viewed" - }, - "refresh": "Refresh", - "install": "Install", - "installing": "Installing", - "reinstall": "Reinstall", - "reinstallConfirm": "Replace local pet \"{name}\"? Existing data will be overwritten.", - "cancel": "Cancel", - "stats": { - "views": "Views", - "downloads": "Downloads", - "likes": "Likes" - }, - "actions": { - "idle": "Idle", - "running_right": "Run right", - "running_left": "Run left", - "waving": "Wave", - "jumping": "Jump", - "failed": "Fail", - "waiting": "Wait", - "running": "Run", - "review": "Review" - }, - "page": "Page {page} of {total}", - "prev": "Previous", - "next": "Next", - "empty": "No pets match this filter.", - "successInstalled": "Installed \"{name}\"", - "errors": { - "loadFailed": "Failed to load marketplace", - "installFailed": "Failed to install pet", - "alreadyInstalled": "Pet already exists locally" - } - } - }, - "RemoteWorkspace": { - "openRemoteWorkspace": "Open remote workspace", - "manage": "Manage remote workspace", - "manageTitle": "Remote Workspace connections", - "empty": "No remote connections", - "searchPlaceholder": "Search remote workspaces", - "orderFailed": "Failed to save remote workspace order", - "dragSort": "Drag to sort", - "dragSortConnection": "Drag to sort {name}", - "newConnection": "New connection", - "loading": "Loading", - "loadingConnection": "Loading remote connection", - "name": "Name", - "baseUrl": "Service URL", - "token": "Access token", - "save": "Save", - "delete": "Delete", - "confirmDelete": { - "title": "Delete remote connection?", - "message": "This will remove \"{name}\" from this device. This action cannot be undone.", - "cancel": "Cancel", - "confirm": "Delete" - }, - "saved": "Remote connection saved.", - "deleted": "Remote connection deleted.", - "loadFailed": "Failed to load remote connections", - "saveFailed": "Failed to save remote connection", - "deleteFailed": "Failed to delete remote connection", - "openFailed": "Failed to open remote workspace", - "connectionLoadFailed": "Failed to load remote connection: {message}", - "connectionExpired": "Remote connection \"{name}\" is expired. Update its token and reload this window." - }, - "BackupSettings": { - "title": "Backup & Restore", - "description": "Export a portable backup of your codeg data, or restore from one.", - "tabs": { - "backup": "Backup", - "restore": "Restore" - }, - "export": { - "includeExternal": "Include conversation content", - "includeExternalHint": "Also archive agent CLI transcripts (Claude, Codex, Gemini, …). Increases size.", - "passphrase": "Passphrase (optional)", - "passphrasePlaceholder": "Leave empty for an unencrypted archive", - "passphraseConfirm": "Confirm passphrase", - "passphraseMismatch": "Passphrases do not match.", - "noPassphraseWarning": "This backup will contain secrets (API keys, tokens) in plaintext. Store it somewhere safe.", - "passphraseLossWarning": "Encrypted with this passphrase. If you lose it, the backup cannot be recovered.", - "button": "Export backup", - "inProgress": "Creating backup…", - "success": "Backup created.", - "started": "Backup download started." - }, - "restore": { - "selectFile": "Select backup file", - "passphrasePrompt": "This backup is encrypted. Enter its passphrase.", - "unlock": "Unlock", - "preview": { - "title": "Backup details", - "encrypted": "Encrypted", - "compatible": "Compatible", - "incompatible": "Incompatible", - "createdAt": "Created: {value}", - "appVersion": "App version: {value}", - "incompatibleHint": "This backup was created by a newer version of codeg and cannot be restored." - }, - "replaceWarning": "Restoring replaces all current codeg data (database and uploads). Your current data is snapshotted first so it can be recovered.", - "keyringNote": "Desktop GitHub/chat tokens live in your OS keychain and are not included; re-enter them after restoring.", - "button": "Restore", - "staging": "Preparing restore…", - "staged": "Restore staged. Restarting…", - "restarting": "Restore staged. Restarting the server…", - "restartTimeout": "The server did not come back in time. Reload the page once it is up.", - "externalSideLocation": "Conversation transcripts were restored to {path}", - "confirmTitle": "Replace all data?", - "confirmBody": "This will replace your current codeg database and uploads with the backup, then restart. Your current data is snapshotted first.", - "cancel": "Cancel", - "confirmAction": "Replace & restart", - "external": { - "title": "Conversation content", - "hint": "This backup includes agent CLI transcripts. Choose where to restore them.", - "modeSkip": "Don't restore", - "modeSide": "Restore to a safe side folder", - "modeOriginal": "Restore to original CLI locations", - "forceOverwrite": "Overwrite existing files", - "forceOverwriteHint": "Replace files that already exist in the agent CLI folders.", - "scanning": "Checking for conflicts…", - "noConflicts": "No existing files would be overwritten.", - "conflictCount": "{count} existing file(s) would be affected.", - "conflictSkipNote": "Existing files are kept (skipped) unless you enable overwrite." - }, - "restartFailed": "Restore staged, but the server couldn't restart. Restart it manually to apply the restore." - }, - "remoteUnsupported": "Backup & restore acts on the data of the machine running codeg. You're connected to a remote workspace — manage its backups from that server directly." - }, - "backup": { - "restore": { - "error": { - "badPassphrase": "Incorrect passphrase or corrupted backup.", - "corrupted": "The backup archive is corrupted.", - "unknownFormat": "This file is not a recognized codeg backup.", - "newerVersion": "This backup was created by codeg {backupVersion}, newer than this version ({appVersion}).", - "alreadyPending": "A restore is already staged. Restart to apply it before staging another." - } - }, - "error": { - "diskSpace": "Not enough disk space to complete the operation.", - "cancelled": "The operation was cancelled." - } - }, - "WebConnection": { - "disconnectedTitle": "Connection lost", - "reconnectingDescription": "Trying to reconnect to the server. This usually recovers on its own within a few seconds.", - "reconnectNow": "Reconnect now", - "sessionExpiredTitle": "Session expired", - "sessionExpiredDescription": "Your session is no longer valid. Please sign in again to continue.", - "goToLogin": "Go to login" - }, - "LiveFeedback": { - "placeholder": "Send a note to {agent} while it works…", - "agentFallback": "the agent", - "ariaLabel": "Live feedback note", - "dialogTitle": "Live feedback", - "dialogDescription": "Send a note to the agent while it works. It reads your note the next time it checks — without interrupting the current step.", - "dialogDescriptionInstant": "Send a note to the agent while it works. It lands in the current turn immediately — the agent sees it right away.", - "channelDowngraded": "Instant insert isn't available in this session — your note was saved for the agent to pick up on its next check.", - "send": "Send", - "cancel": "Cancel", - "pending": "waiting", - "delivered": "received", - "turnEndedUnread": "The agent finished before reading your feedback.", - "sendAsMessage": "Send as message", - "dismiss": "Dismiss", - "turnEndedResent": "The turn ended — sent as a new message instead.", - "turnEnded": "The turn already ended.", - "submitFailed": "Couldn't send your note" - }, - "AgentToolsSettings": { - "title": "In-conversation tools", - "description": "Extra tools codeg gives an agent inside a conversation. Each is injected when the agent starts, so a change applies to agents started afterwards.", - "feedbackLabel": "Live Feedback", - "feedbackHint": "Send notes and corrections to an agent while it's working. When the agent supports instant steering, your note is inserted into the running turn immediately; otherwise the agent gets a tool to check for your feedback — those agents typically only check when you mention it in your prompt, for example add \"check my live feedback regularly\" to your message.", - "questionLabel": "Ask user question", - "questionHint": "Let agents pause and ask you a multiple-choice question that appears above the conversation input box. The agent waits until you answer (or skip).", - "sessionInfoLabel": "Get session info", - "sessionInfoHint": "Let agents look up a session you reference in your message (a session badge) to read its title, agent, status, workspace, token usage, and recent messages.", - "automationsLabel": "Create automations", - "automationsHint": "Save the conversation as an automation that runs on a schedule. Off by default — it goes on to start agents on its own.", - "workTasksLabel": "Create to-do tasks", - "workTasksHint": "Queue a card on the to-do board from the conversation. Off by default — it writes app state.", - "save": "Save", - "saving": "Saving…", - "saved": "Tool settings saved", - "saveFailed": "Failed to save tool settings", - "loadFailed": "Failed to load: {detail}" - }, - "NotificationSoundSettings": { - "title": "Notification sounds", - "description": "Play a short sound when an agent event fires. These are the same events the chat channels push — configured here for this device only.", - "enableHint": "Off by default. Sounds play in the workspace window of this browser or app only.", - "volume": "Volume", - "preview": "Preview", - "previewEvent": "Preview the {event} sound", - "onlyWhenUnfocused": "Only when the window is not focused", - "onlyWhenUnfocusedHint": "Stay silent while you are looking at Codeg.", - "eventsTitle": "Events", - "eventsHint": "Pick a tone per event, or “Silent” to skip it. Repeats of the same event within a couple of seconds play once.", - "toneNone": "Silent", - "toneChime": "Chime", - "toneDing": "Ding", - "toneBlip": "Blip", - "tonePop": "Pop", - "toneAlert": "Alert", - "toneDescend": "Descending" - }, - "LogsSettings": { - "loading": "Loading…", - "sectionTitle": "Runtime Logs", - "sectionDescription": "View and configure application diagnostic logs. Logs are written to local files and kept in memory for live viewing.", - "captureTitle": "Log level", - "captureDescription": "Controls how much detail is captured. Higher levels (Debug, Trace) record more but produce larger logs. Off disables logging.", - "captureLabel": "Capture level", - "levels": { - "off": "Off", - "error": "Error", - "warn": "Warning", - "info": "Info", - "debug": "Debug", - "trace": "Trace" - }, - "viewerTitle": "Recent logs", - "viewerDescription": "Live view of recent log records. Filter by level or search text.", - "searchPlaceholder": "Search message or target…", - "viewLevels": { - "all": "All levels", - "error": "Error+", - "warn": "Warning+", - "info": "Info+", - "debug": "Debug+", - "trace": "Trace+" - }, - "pause": "Pause", - "resume": "Live", - "refresh": "Refresh", - "clear": "Clear", - "openFolder": "Open folder", - "shownCount": "{shown} / {total} shown", - "empty": "No logs to display.", - "levelSaveFailed": "Failed to save log level", - "openFolderFailed": "Failed to open log folder", - "downloadFailed": "Failed to download log file", - "filesTitle": "Log files", - "filesDescription": "Download full log files from disk for history beyond the live buffer.", - "filesEmpty": "No log files yet.", - "download": "Download", - "downloadTruncated": "File is large; downloaded the latest {size}. The full file is in the logs directory.", - "captureEnvLocked": "Log level is controlled by the RUST_LOG / CODEG_LOG environment variable; change it there to take effect.", - "targetsTitle": "Per-module overrides", - "targetsDescription": "Set a different level for specific modules (e.g. codeg_lib::acp) without changing the global level.", - "targetsAdd": "Add", - "targetsRemove": "Remove override", - "toggleDetails": "Toggle details" - }, - "Automations": { - "title": "Automations", - "new": "New automation", - "empty": "No automations yet", - "emptyHint": "Create one to run an agent task on a schedule or on demand.", - "name": "Name", - "namePlaceholder": "e.g. Nightly PR review", - "prompt": "Prompt", - "promptPlaceholder": "What should the agent do?", - "agent": "Agent", - "folder": "Workspace folder", - "folderPlaceholder": "Select a folder", - "isolation": "Isolation", - "isolationWorktree": "New worktree per run", - "isolationShared": "Run in the folder", - "isolationSharedCaveat": "Runs use this folder's working tree directly — they can collide with your uncommitted changes. Enable the worktree option to isolate each run.", - "trigger": "Trigger", - "triggerSchedule": "On a schedule", - "triggerManual": "Manual only", - "cron": "Schedule (cron)", - "cronPlaceholder": "0 9 * * 1-5", - "timezone": "Timezone", - "nextRun": "Next run", - "branch": "Branch", - "branchOptional": "Branch (optional)", - "enabled": "Enabled", - "save": "Save", - "cancel": "Cancel", - "edit": "Edit", - "delete": "Delete", - "runNow": "Run now", - "cancelRun": "Cancel run", - "runHistory": "Run history", - "noRuns": "No runs yet", - "allFolders": "All folders", - "filterAll": "All", - "noMatches": "No matching automations", - "viewConversation": "View conversation", - "lastRun": "Last run", - "never": "Never", - "running": "Running", - "deleteTitle": "Delete automation?", - "deleteDescription": "This removes the automation and its schedule. Run history is kept.", - "statusRunning": "Running", - "statusSucceeded": "Succeeded", - "statusFailed": "Failed", - "statusCancelled": "Cancelled", - "statusSkipped": "Skipped", - "errorName": "Name is required", - "errorPrompt": "Prompt is required", - "errorCron": "A cron expression is required for scheduled automations", - "errorFolder": "Select a workspace folder", - "presetHourly": "Hourly", - "presetDaily": "Daily 9am", - "presetWeekdays": "Weekdays 9am", - "presetCustom": "Custom", - "probing": "Loading options…", - "retry": "Retry", - "configNone": "This agent has no configurable options", - "inherit": "Agent default", - "mode": "Mode", - "config": "Configuration", - "branchPlaceholder": "(default branch)", - "selectHint": "Select an automation to see details", - "refresh": "Refresh", - "onboardTitle": "Automate routine agent tasks", - "onboardHint": "Schedule an agent to review code, update dependencies, or triage issues — on a cadence or on demand.", - "headerSubtitle": "Scheduled and on-demand agent tasks", - "startFromTemplate": "Start from a template", - "blankTitle": "Blank automation", - "blankDesc": "Configure an agent task from scratch.", - "backToTemplates": "Templates", - "sectionSchedule": "Schedule & target", - "sectionTarget": "Target", - "sectionAction": "Action", - "actionLaunchSession": "Launch session", - "actionEnqueueTask": "Enqueue task", - "actionEnqueueTaskHint": "Each fire adds a to-do task titled after this automation to the folder's to-dos; the task engine runs it per the board's settings.", - "sectionPrompt": "Prompt", - "nextIn": "Next in {rel}", - "manual": "Manual", - "schedEveryMinutes": "Every {n} minutes", - "schedHourly": "Hourly", - "schedDaily": "Daily at {time}", - "schedWeekdays": "Weekdays at {time}", - "schedWeekly": "Every {day} at {time}", - "schedMonthly": "Monthly on day {day} at {time}", - "dow0": "Sunday", - "dow1": "Monday", - "dow2": "Tuesday", - "dow3": "Wednesday", - "dow4": "Thursday", - "dow5": "Friday", - "dow6": "Saturday", - "tplCodeReviewTitle": "Code review", - "tplCodeReviewDesc": "Review recent changes for bugs, regressions, and quality issues.", - "tplDependencyUpdatesTitle": "Dependency updates", - "tplDependencyUpdatesDesc": "Find outdated dependencies and propose safe upgrades.", - "tplTestCoverageTitle": "Test coverage", - "tplTestCoverageDesc": "Find untested code paths and add the missing tests.", - "tplTodoSweepTitle": "TODO sweep", - "tplTodoSweepDesc": "Collect TODO and FIXME comments and triage them by priority.", - "tplCiTriageTitle": "CI triage", - "tplCiTriageDesc": "Investigate recent failing checks and propose fixes.", - "tplReleaseNotesTitle": "Release notes", - "tplReleaseNotesDesc": "Summarize changes since the last release into a changelog.", - "tplSecurityAuditTitle": "Security audit", - "tplSecurityAuditDesc": "Scan for vulnerabilities and risky patterns, then report findings.", - "enable": "Enable", - "disable": "Disable", - "moreActions": "More actions", - "statusDisabled": "Disabled", - "cronBuilderTitle": "Schedule builder", - "cronFreqLabel": "Frequency", - "cronFreqMinutes": "Every N minutes", - "cronFreqHourly": "Hourly", - "cronFreqDaily": "Daily", - "cronFreqWeekdays": "Weekdays", - "cronFreqWeekly": "Weekly", - "cronFreqMonthly": "Monthly", - "cronFreqCustom": "Custom", - "cronEveryLabel": "Interval (minutes)", - "cronTimeLabel": "Time", - "cronHourLabel": "Hour", - "cronMinuteLabel": "Minute", - "cronDowLabel": "Day of week", - "cronDomLabel": "Day of month", - "cronApply": "Apply", - "cronPreviewLabel": "Preview", - "cronOpenBuilder": "Open schedule builder", - "branchDefault": "Default branch", - "branchUseCustom": "Use \"{query}\"", - "branchLocal": "Local", - "branchRemote": "Remote", - "branchSearchPlaceholder": "Search branches…", - "branchNone": "No branches" - }, - "Tasks": { - "title": "To-dos", - "new": "New task", - "empty": "No tasks yet", - "emptyHint": "Add a to-do, then run it — the agent works in an isolated worktree and you review and merge the result.", - "emptyColTodo": "No to-dos yet", - "emptyColInProgress": "Nothing in progress", - "emptyColAttention": "Nothing needs you right now", - "emptyColDone": "Nothing done yet", - "allFolders": "All folders", - "showCanceled": "Show canceled", - "showArchived": "Show archived", - "filter": "Filter", - "viewSwitchToBoard": "Switch to board view", - "viewSwitchToList": "Switch to list view", - "statusFilter": "Status", - "statusFilterAll": "All statuses", - "listEmpty": "No tasks match the current filters", - "listColStatus": "Status", - "listColTask": "Task", - "listColLocation": "Location", - "listColChanges": "Changes", - "listColUpdated": "Updated", - "colTodo": "To do", - "colInProgress": "In progress", - "colAttention": "Needs you", - "colDone": "Done", - "statusTodo": "To do", - "statusQueued": "Queued", - "statusPreparing": "Setting up", - "statusRunning": "Running", - "statusAwaitingInput": "Awaiting input", - "statusReview": "To review", - "statusMerging": "Merging", - "statusDone": "Done", - "statusFailed": "Failed", - "statusCanceled": "Canceled", - "statusInterrupted": "Interrupted", - "badgeCleanupFailed": "Cleanup failed", - "badgeWorktreeKept": "Worktree kept", - "badgeWorktreeRemoved": "Worktree removed", - "filesChanged": "{count} files", - "actionStart": "Start", - "actionSchedule": "Schedule", - "actionCancel": "Cancel", - "actionRetry": "Retry", - "actionRequeue": "Requeue", - "actionViewSession": "View session", - "actionEdit": "Edit", - "actionDelete": "Delete", - "actionRetryCleanup": "Retry cleanup", - "actionMerge": "Merge", - "actionUnqueueMerge": "Leave merge queue", - "actionEditQueuedMerge": "Edit queued merge", - "badgeMergeQueued": "Queued to merge", - "badgeMergeQueuedRank": "Queued to merge · #{rank}", - "badgeMergeQueuedHint": "Waiting for the project's current merge to finish; this one starts on its own.", - "actionComplete": "Complete", - "actionAbandon": "Abandon", - "cancelTitle": "Cancel task?", - "cancelDescription": "The task moves to Canceled. Its worktree is kept, and you can requeue it later.", - "cancelReasonLabel": "Reason (optional)", - "cancelReasonPlaceholder": "e.g. wrong approach — I'll rewrite the description", - "cancelKeep": "Never mind", - "cancelSubmit": "Cancel task", - "restartTitleRetry": "Retry task", - "restartTitleRequeue": "Requeue task", - "restartDescription": "Add a note for the agent (optional) — it reaches the prompt of the next run.", - "scheduleTitle": "Schedule task", - "scheduleDescription": "The task stays in To do and starts on its own at the time you pick. The folder's concurrency limit still applies.", - "scheduleDateLabel": "Date", - "schedulePickDate": "Select date", - "scheduleTimeLabel": "Time", - "schedulePreview": "Runs at {time}", - "schedulePastHint": "That time has passed — the task starts as soon as you save.", - "scheduleInAnHour": "In 1 hour", - "scheduleInThreeHours": "In 3 hours", - "scheduleTomorrow": "Tomorrow 9:00", - "scheduleClear": "Clear schedule", - "scheduleBadge": "Scheduled to start at {time}", - "toastScheduled": "Scheduled for {time}", - "toastScheduleCleared": "Schedule cleared", - "actionFollowUp": "Follow up", - "actionAddNote": "Add a note", - "followUpSubmit": "Send", - "followUpIntentRevise": "Rework", - "followUpIntentContinue": "Keep going", - "followUpIntentQuestion": "Ask", - "followUpIntentVerify": "Double-check", - "followUpPlaceholderRevise": "What should the agent change? It continues in the same session.", - "followUpPlaceholderContinue": "What's next? The work so far stays as it is.", - "followUpPlaceholderQuestion": "What do you want to know? The agent answers without touching any file.", - "followUpPlaceholderVerify": "Optional: anything it should look at closely?", - "followUpPlaceholderRetry": "Optional: what should it do differently? e.g. run pnpm install first", - "followUpPlaceholderRequeue": "Optional: why did you cancel it, and what should change this time?", - "actionArchive": "Archive", - "actionUnarchive": "Unarchive", - "archiveAllDone": "Archive all", - "dropToStart": "Release to start", - "errorView": "View", - "notifyReview": "Ready for review: {title}", - "notifyFailed": "Task failed: {title}", - "createFromMessage": "Create task from message", - "detailTokens": "Total tokens", - "editorTitleNew": "New task", - "editorTitleEdit": "Edit task", - "templates": "Templates", - "templatesEmpty": "No templates yet.", - "templateSaveCurrent": "Save current as template", - "templateDelete": "Delete template", - "transcriptTitle": "Task session", - "transcriptDescription": "Read-only live view of the task's agent session.", - "phaseWork": "Task run", - "phaseRetry": "Retry run", - "phaseReturn": "Follow-up", - "phaseMerge": "Merge", - "titleLabel": "Title", - "titlePlaceholder": "What needs to be done?", - "promptLabel": "Task description", - "promptPlaceholder": "Describe the task for the agent — @ to reference files, / for commands", - "folderPlaceholder": "Select a folder", - "agentInheritedHint": "Inherited from task settings — change it to override for this task", - "agentOverrideReset": "Reset to inherited", - "sectionTarget": "Target", - "errorTitle": "Title is required", - "errorPrompt": "Task description is required", - "errorFolder": "Select a folder", - "save": "Save", - "cancel": "Cancel", - "mergeTitle": "Merge task", - "mergeQueuedTitle": "Queued merge", - "mergeQueueHint": "Another task of this project is merging right now. This one joins the queue and starts on its own as soon as that one finishes.", - "mergeQueueUpdateHint": "This task is already waiting to merge. Submitting updates it and keeps its place in the queue.", - "mergeDescription": "Merge {branch} into {base}. Uncommitted changes in the worktree are committed first.", - "mergeMessage": "Commit message", - "mergeMessagePlaceholder": "e.g. feat: add login validation", - "mergeAutoMessage": "Let the agent write the commit message", - "strategySquash": "Combine into one commit", - "strategySquashHint": "All the task's changes land in the main branch as a single history entry — a tidier history.", - "strategyMerge": "Keep full history", - "strategyMergeHint": "Every commit made during the task is kept, plus one merge entry — each step stays traceable.", - "mergeDeleteWorktree": "Delete worktree after merge", - "mergeSubmit": "Merge", - "mergeSubmitQueue": "Add to merge queue", - "mergeQueuedToast": "Added to the merge queue — it starts as soon as the current merge finishes.", - "completeTitle": "Complete task", - "completeDescription": "This task changed no files, so there is nothing to merge — it is marked as done directly.", - "completeDescriptionNoWorktree": "This task's worktree has been removed, so there is no merge to run — it is marked as done directly. A work branch that still holds unmerged commits is kept.", - "completeDeleteWorktree": "Delete the worktree after completing", - "completeSubmit": "Complete", - "settingsTitle": "Task settings", - "settingsDescription": "Defaults for tasks in {folder}.", - "settingsScope": "Scope", - "settingsScopeGlobal": "All folders (global defaults)", - "settingsScopeGlobalHint": "Folders without their own settings use these global defaults.", - "settingsSource": "Configuration", - "settingsSourceGlobal": "Global defaults", - "settingsSourceCustom": "Custom", - "settingsSourceGlobalFollow": "Follows the global task settings — changes there apply here automatically.", - "settingsSourceCustomHint": "Saves this folder's own settings; it stops following the global defaults.", - "settingsAgent": "Default agent", - "settingsMaxConcurrent": "Max concurrent tasks", - "settingsMaxConcurrentHint": "0 = unlimited", - "settingsAutoProcess": "Process automatically", - "settingsAutoProcessHint": "To-dos start on their own, up to the concurrency limit.", - "settingsMergeStrategy": "Default merge strategy", - "settingsMergeStrategyHint": "How the task's changes are recorded in the branch history when merged.", - "settingsAutoMerge": "Merge automatically", - "settingsAutoMergeHint": "A task that reaches review with something to land merges as if you clicked Merge: the agent writes the commit message, and the worktree follows the default below. A red preflight or a failed merge leaves the task waiting for you.", - "settingsDeleteWorktree": "Delete the worktree after merging", - "settingsDeleteWorktreeHint": "Pre-selects the option in the merge dialog; you can still change it there.", - "settingsWorktreeRoot": "Worktree location", - "settingsWorktreeRootHint": "Directory new task worktrees are created in — one per task. Leave it empty to keep them next to the project folder; \"~\" is your home directory, and a relative path resolves against the project folder.", - "settingsWorktreeRootPlaceholder": "~/codeg-worktrees", - "settingsWorktreeRootBrowse": "Choose the worktree directory", - "settingsPreflight": "Preflight command", - "settingsPreflightHint": "Runs in the worktree when a task reaches review.", - "settingsPreflightCustomPlaceholder": "pnpm test", - "settingsInitCommand": "Worktree init command", - "settingsInitCommandHint": "Runs inside a freshly created worktree before the agent starts.", - "settingsInitCommandPlaceholder": "pnpm install", - "settingsTabGeneral": "General", - "settingsTabMerge": "Merge", - "settingsTabWorktree": "Worktree", - "settingsTabPrompts": "Prompts", - "settingsPromptsIntro": "Each stage already sends a built-in prompt — the task itself, the worktree rules, and for merging the exact git steps. Text you add here is appended at the end as extra instructions: it refines those built-ins, it never replaces them.", - "settingsPromptStageAll": "All stages", - "settingsPromptPlaceholderAll": "e.g. Follow the conventions in AGENTS.md; keep the final summary to two sentences", - "settingsPromptPlaceholderWork": "e.g. Read the related tests first; commit in small steps as you go", - "settingsPromptPlaceholderRetry": "e.g. Check what is already committed before continuing; don't redo finished work", - "settingsPromptPlaceholderReturn": "e.g. Address every point raised; don't refactor anything unrelated", - "settingsPromptPlaceholderMerge": "e.g. Write the landing commit message in English; call out any conflict you resolved by hand", - "settingsPromptHintAll": "Appended to every prompt the agent receives, the merge run included.", - "settingsPromptHintWork": "Appended when a task runs for the first time.", - "settingsPromptHintRetry": "Appended when an interrupted or failed task is picked up again.", - "settingsPromptHintReturn": "Appended when you follow up on a reviewed task (rework, extra work, self-check).", - "settingsPromptHintMerge": "Appended when the agent lands the task onto the base branch.", - "preflightPassed": "{name} passed", - "preflightFailed": "{name} failed", - "preflightRunning": "{name} running…", - "detailDescription": "Task detail", - "detailSummary": "Result", - "detailFiles": "Changed files", - "detailDiffAll": "View full diff", - "detailDiffAllTitle": "Full diff", - "detailNoChanges": "No changes vs the base yet", - "detailTimeline": "Progress", - "detailTimelineEmpty": "No activity yet", - "showMore": "Show more", - "showLess": "Show less", - "detailInfo": "Details", - "detailBranch": "Branch", - "detailMergeCommit": "Merge commit", - "detailChanges": "Changes", - "detailScheduled": "Scheduled start", - "detailCreated": "Created", - "detailStarted": "Started", - "detailFinished": "Finished", - "diffLoading": "Loading diff…", - "deleteConfirmTitle": "Delete task?", - "deleteConfirmBody": "“{title}” will be removed from the board. An active run is canceled first.", - "deleteWithWorktree": "Also delete its worktree", - "eventCreated": "Created", - "eventStatusChanged": "Status changed", - "eventConfigEffective": "Launch config", - "eventInitCommand": "Init command", - "eventAgentProgress": "Agent progress", - "eventAgentVerdict": "Agent verdict", - "eventMergeAttempt": "Merge started", - "eventMergeQueued": "Queued to merge", - "eventMergeConflict": "Merge conflict", - "eventPreflight": "Preflight", - "eventCleanupFailed": "Worktree cleanup failed", - "eventResumeFallback": "Session resume fell back to a new session", - "eventUserAction": "User action", - "eventDiffStat": "Change snapshot" - }, - "CustomSkillsSettings": { - "loading": "Loading custom skills…", - "category": "Custom", - "searchPlaceholder": "Search custom skills by name, id, or description", - "states": { - "not_linked": "Not enabled", - "linked_to_codeg": "Enabled", - "linked_elsewhere": "Linked elsewhere", - "blocked_by_real_directory": "Blocked by a real folder", - "broken": "Broken link" - }, - "actions": { - "new": "New", - "import": "Import", - "importFromAgent": "Import from agent", - "cancel": "Cancel", - "save": "Save" - }, - "rowMenu": { - "edit": "Edit", - "duplicate": "Duplicate", - "delete": "Delete" - }, - "bulk": { - "delete": "Delete selected" - }, - "editor": { - "createTitle": "New custom skill", - "editTitle": "Edit custom skill", - "description": "Custom skills live in the shared store (~/.codeg/skills) and can be enabled for any agent.", - "idLabel": "Skill id", - "idPlaceholder": "e.g. my-workflow", - "contentLabel": "SKILL.md", - "contentPlaceholder": "Write the skill's SKILL.md here…", - "preview": "Preview", - "edit": "Edit", - "emptyBody": "No content yet." - }, - "duplicate": { - "title": "Duplicate skill", - "description": "Create a copy of \"{id}\" with a new id.", - "newIdPlaceholder": "New skill id", - "confirm": "Duplicate" - }, - "import": { - "title": "Choose a skill folder to import" - }, - "importFromAgent": { - "title": "Import skills from an agent", - "description": "Copy an agent's own skills into the shared store so you can enable them for any agent.", - "agentLabel": "Agent", - "agentPlaceholder": "Select an agent", - "selectAll": "Select all ({count})", - "loading": "Loading the agent's skills…", - "unsupported": "This agent doesn't expose a skills directory.", - "empty": "This agent has no importable skills.", - "alreadyInLibrary": "In library", - "confirm": "Import selected ({count})" - }, - "delete": { - "title": "Delete custom skills?", - "body": "This removes {count} custom skill(s) from the central store and unlinks them from every agent. This can't be undone.", - "confirm": "Delete" - }, - "toasts": { - "loadFailed": "Failed to load skill", - "idRequired": "Please enter a skill id", - "created": "Custom skill created", - "updated": "Custom skill updated", - "saveFailed": "Failed to save skill", - "imported": "Skill imported", - "importFailed": "Failed to import skill", - "duplicated": "Skill duplicated", - "duplicateFailed": "Failed to duplicate skill", - "deleted": "Deleted {count} skill(s)", - "deletedPartial": "Deleted {ok}, {failed} failed", - "deleteFailed": "Failed to delete skills", - "importedFromAgent": "Imported {count} skill(s)", - "importedFromAgentPartial": "Imported {ok}, {failed} failed", - "importFromAgentAllSkipped": "Nothing to import — {count} already in the library", - "importFromAgentFailed": "Failed to import from agent" - } - }, - "CodexModelEditor": { - "customizedNotice": "You've customized the model list, so codeg now manages codex's full model table. Official models codex ships later won't appear automatically — click the refresh button below and save again to sync them. Clear your customizations to let codex update automatically.", - "officialsTitle": "Official models", - "officialsHint": "Auto-included from the codex you launch; remove any you don't want.", - "officialsEmpty": "No official models available.", - "refresh": "Refresh from codex", - "readdOfficial": "Re-add official", - "customsTitle": "Custom models", - "customsEmpty": "No custom models yet.", - "addCustom": "Add custom", - "slugPlaceholder": "Model id (slug)", - "displayNamePlaceholder": "Display name", - "contextWindow": "Context", - "makeDefault": "Set as default", - "defaultHint": "Default model", - "remove": "Remove", - "advanced": "Advanced", - "baseTemplate": "Base template", - "baseTemplateHint": "Official model to clone required fields (system prompt, tools, limits) from.", - "groupBehavior": "Behavior & capabilities", - "fieldReasoningLevel": "Default reasoning", - "fieldReasoningSummary": "Reasoning summary", - "fieldVerbosity": "Verbosity", - "fieldShellType": "Shell type", - "fieldApplyPatch": "Apply-patch tool", - "fieldReasoningSummaries": "Reasoning summaries", - "fieldSupportVerbosity": "Verbosity control", - "fieldParallelToolCalls": "Parallel tool calls", - "fieldSearchTool": "Web search tool", - "optNone": "None", - "groupInstructions": "Description & system prompt", - "fieldDescription": "Description", - "baseInstructions": "System prompt (base_instructions)" - }, - "DiagnosticsSettings": { - "title": "Environment diagnostics", - "description": "Checks how this app resolves the agent CLI inside its own process, which can differ from your terminal.", - "loading": "Running diagnostics…", - "error": "Diagnostics failed", - "rerun": "Re-run", - "copyAll": "Copy all", - "copied": "Diagnostics copied to clipboard", - "button": "Diagnose", - "verdict": { - "ok": "Environment looks healthy. If it still shows as not installed, fully restart the app so the prefix cache refreshes.", - "node_missing": "Node.js was not found on the app PATH.", - "npm_missing": "npm was not found on the app PATH.", - "not_installed": "This agent does not appear to be installed.", - "installed_but_unresolved": "The agent is recorded as installed, but the app cannot locate its executable.", - "user_prefix_not_on_path": "Installed into the fallback prefix (~/.codeg/npm-global), which is not on the app PATH. Fully restart the app and try again.", - "homebrew_bin_not_on_path": "Installed under the Homebrew bin, which is not on the app PATH (Apple Silicon keg split).", - "terminal_only_path": "The command resolves in your terminal but not in the app — a GUI PATH gap. Launch the app from a terminal, or reinstall from Agent Settings.", - "npm_prefix_timeout": "npm prefix -g was too slow (over 1.5s), so fallback detection was skipped. Restart the app and try again.", - "node_too_old": "Your active Node.js is older than this agent requires. Upgrade Node.js.", - "adapter_missing_native_present": "Your own {agent} CLI is installed, but Codeg launches a separate ACP adapter package — and that one isn't installed yet. Install it from Agent Settings; it won't touch your CLI and shares the same sign-in.", - "adapter_missing": "Codeg launches a separate ACP adapter package for {agent}, and it isn't installed yet. Install it from Agent Settings — installing the vendor CLI alone is not enough." - } - }, - "TokenUsage": { - "title": "Token Usage", - "rangeLabel": "Time range", - "range7d": "7 days", - "range30d": "30 days", - "range90d": "90 days", - "rangeThisMonth": "This month", - "rangeThisYear": "This year", - "rangeAll": "All time", - "rangeCustom": "Custom", - "moreRanges": "More", - "customRangePick": "Pick a date range", - "bucketLabel": "Group by", - "bucketDay": "Day", - "bucketWeek": "Week", - "bucketMonth": "Month", - "bucketUnitDay": "day", - "bucketUnitWeek": "week", - "bucketUnitMonth": "month", - "folderFilter": "Folders", - "allFolders": "All folders", - "agentFilter": "Agents", - "allAgents": "All agents", - "modelFilter": "Models", - "allModels": "All models", - "searchPlaceholder": "Search…", - "noMatches": "No matches", - "clearFilter": "Clear selection", - "resetFilters": "Reset filters", - "refresh": "Refresh", - "rebuild": "Rebuild all", - "rebuildHint": "Re-reads every transcript from scratch. Use this if a session grew outside codeg.", - "syncing": "Counting sessions…", - "syncProgress": "{done} / {total}", - "syncDone": "Counted {synced} sessions", - "syncFailed": "Could not read some sessions", - "syncBusy": "A refresh is already running", - "lastSynced": "Updated {time}", - "lastSyncedNever": "Never updated", - "tileTotal": "Total tokens", - "tileSessions": "Sessions", - "tileTurns": "Turns", - "tileActiveDays": "Active days", - "tileGenTime": "Generation time", - "vsPrevious": "vs. previous period", - "deltaNew": "new", - "trendTitle": "Usage over time", - "trendEmpty": "No usage in this range", - "trendTurns": "Turns", - "trendSessions": "Sessions", - "compositionTitle": "What the tokens were", - "compositionHint": "Input is what you sent, output is what the model wrote, and cache reads are context you didn't pay full price for.", - "compositionNote": "Re-sending those cache hits at full price would have cost another {value}.", - "inputTokens": "Input", - "outputTokens": "Output", - "cacheWrite": "Cache write", - "cacheRead": "Cache read", - "freshTokens": "Fresh compute", - "cacheHitCaption": "Cache hit", - "cacheHeroTitleHigh": "Most context never got re-sent", - "cacheHeroTitleLow": "Most context still bills at full price", - "cacheHeroDesc": "The cache carried {cached} of context — only {fresh} was freshly computed in this period.", - "cacheSavedSuffix": "That saved re-sending the equivalent of {saved}.", - "avgPerSession": "Avg. per session", - "avgTurnsPerSession": "{count} turns per session", - "avgPerActiveDay": "Avg. per active day", - "peakBucket": "Busiest {bucket}", - "peakHour": "Peak hour", - "daysValue": "{count} days", - "idleDays": "Idle days", - "byFolderTitle": "By folder", - "byAgentTitle": "By agent", - "byModelTitle": "By model", - "distributionTitle": "Usage distribution", - "distributionHint": "Sessions and tokens grouped by the selected dimension — click a row to filter by it.", - "otherLabel": "Other", - "unknownModel": "Unspecified model", - "emptyBreakdown": "Nothing recorded yet", - "sessionsCount": "{count} sessions", - "heatmapTitle": "When you build", - "heatmapHint": "Tokens by local weekday and hour.", - "heatmapPeakHint": "Densest around {hour}:00.", - "less": "Less", - "more": "More", - "heatmapCell": "{weekday} {hour}:00 — {value} tokens", - "weekMon": "Mon", - "weekTue": "Tue", - "weekWed": "Wed", - "weekThu": "Thu", - "weekFri": "Fri", - "weekSat": "Sat", - "weekSun": "Sun", - "topSessionsTitle": "Heaviest sessions", - "untitledSession": "Untitled session", - "topSessionsEmpty": "No sessions in this range", - "streakLongest": "Longest streak", - "streakLongestDays": "Longest streak {count} days", - "share": "Share", - "moreActions": "More actions", - "shareDialogTitle": "Share your usage card", - "shareDialogHint": "A snapshot of the range and filters you're looking at.", - "shareSave": "Save image", - "shareCopy": "Copy image", - "shareCopied": "Copied to clipboard", - "shareSaved": "Image saved", - "shareFailed": "Could not create the image", - "shareRendering": "Rendering…", - "cardHeading": "My AI coding stats", - "cardRangeAll": "All time", - "cardTotalLabel": "Tokens used", - "cardFooter": "Made with codeg", - "cardTopModels": "Top models", - "cardTopProjects": "Top projects", - "archetypeNightOwl": "Night Owl", - "archetypeNightOwlDesc": "{percent}% of your tokens burn after dark.", - "archetypeEarlyBird": "Early Bird", - "archetypeEarlyBirdDesc": "{percent}% of your tokens land before 9am.", - "archetypeWeekendWarrior": "Weekend Warrior", - "archetypeWeekendWarriorDesc": "{percent}% of your tokens happen on the weekend.", - "archetypeCacheMaster": "Cache Master", - "archetypeCacheMasterDesc": "{percent}% of your context came from cache.", - "archetypeMarathoner": "Marathoner", - "archetypeMarathonerDesc": "{days} days building without a break.", - "archetypePolyglot": "Polyglot", - "archetypePolyglotDesc": "{count} agents in serious rotation.", - "archetypeLaserFocus": "Laser Focus", - "archetypeLaserFocusDesc": "{percent}% of your tokens went to one project.", - "archetypeDeepDiver": "Deep Diver", - "archetypeDeepDiverDesc": "{averageK}K tokens in an average session.", - "archetypeSteady": "Steady Builder", - "archetypeSteadyDesc": "{days} days of shipping.", - "emptyTitle": "Nothing counted yet", - "emptyHint": "Codeg reads token counts straight from each agent's own transcript. Run a refresh to count what's already on this machine.", - "emptyAction": "Count my sessions", - "loadFailed": "Could not load usage", - "truncatedNotice": "This range is very large — the numbers cover only the most recent slice of it." - } -} +{ + "Language": { + "followSystem": "Follow System", + "english": "English", + "simplifiedChinese": "Simplified Chinese", + "traditionalChinese": "Traditional Chinese", + "japanese": "Japanese", + "korean": "Korean", + "spanish": "Spanish", + "german": "German", + "french": "French", + "portuguese": "Portuguese", + "arabic": "Arabic" + }, + "GitCredentialDialog": { + "title": "Authentication Required", + "description": "The remote server requires credentials. Enter your username and password (or personal access token).", + "username": "Username", + "usernamePlaceholder": "Username or email", + "password": "Password / Token", + "passwordPlaceholder": "Password or personal access token", + "passwordHint": "For non-GitHub servers, enter your username and password.", + "cancel": "Cancel", + "authenticate": "Authenticate", + "authenticating": "Authenticating...", + "invalidCredentials": "Invalid credentials. Please try again.", + "saveCredentials": "Save credentials for future operations", + "githubTitle": "GitHub Authentication", + "githubDescription": "Enter a personal access token to authenticate with GitHub. The token will be validated and saved to your accounts.", + "githubToken": "Personal Access Token", + "githubTokenPlaceholder": "ghp_xxxxxxxxxxxx", + "githubTokenHint": "Generate a token at GitHub → Settings → Developer settings → Personal access tokens.", + "githubAuthenticate": "Validate & Connect", + "generateToken": "Generate token" + }, + "SettingsShell": { + "title": "Settings", + "preferences": "Preferences", + "nav": { + "general": "General", + "appearance": "Appearance", + "agents": "Agents", + "mcp": "MCP", + "skills": "Skills", + "shortcuts": "Shortcuts", + "version_control": "Version Control", + "system": "System", + "chat_channels": "Chat Channels", + "web_service": "Web Service", + "model_providers": "Model Providers", + "experts": "Experts", + "science": "Science", + "office_tools": "Office Tools", + "skill_packs": "Skill Packs", + "quick_messages": "Quick Messages", + "logs": "Runtime Logs" + } + }, + "AppearanceSettings": { + "sectionTitle": "Theme Appearance", + "sectionDescription": "Choose light, dark, or follow system. Settings are saved automatically.", + "themeMode": "Theme mode", + "placeholder": "Select theme mode", + "system": "Follow system", + "light": "Light", + "dark": "Dark", + "currentTheme": "Current effective theme: {theme}", + "resolvedTheme": { + "light": "Light", + "dark": "Dark", + "unknown": "--" + }, + "themeColor": { + "sectionTitle": "Theme color", + "sectionDescription": "Pick a color palette for accents, buttons, and highlights.", + "current": "Current color: {color}", + "options": { + "neutral": "Neutral", + "zinc": "Zinc", + "slate": "Slate", + "stone": "Stone", + "gray": "Gray", + "red": "Red", + "rose": "Rose", + "orange": "Orange", + "green": "Green", + "blue": "Blue", + "yellow": "Yellow", + "violet": "Violet" + } + }, + "customStyle": { + "sectionTitle": "Custom Style", + "sectionDescription": "Fine-tune the current theme's colors, or inject your own CSS. Overrides sit on top of the base preset, so switching presets keeps them.", + "summarySuspended": "Suspended", + "summaryDefault": "Preset defaults", + "summaryTokens": "{count, plural, one {# override} other {# overrides}}", + "summaryCss": "Custom CSS", + "suspendedByShortcut": "Custom style is suspended. Nothing set here takes effect until you resume it.", + "suspendedBySafeParam": "This window was opened in safe appearance mode, so custom style is ignored here. Other windows are unaffected.", + "resume": "Resume custom style", + "enableTheme": "Enable custom colors", + "editingLight": "Editing light mode values. Switch the app to dark mode to set its own.", + "editingDark": "Editing dark mode values. Switch the app to light mode to set its own.", + "resetToken": "Reset to preset value", + "radius": "Corner radius", + "radiusHint": "Drives the whole radius scale from sm to 4xl, so one slider rounds the entire app.", + "advanced": "Advanced ({count} more variables)", + "enableCss": "Enable custom CSS", + "cssRisk": "Advanced feature. Custom CSS overrides every built-in style and can make the interface unusable.", + "editCss": "Edit CSS…", + "cssPresent": "{size} KB saved", + "cssEmpty": "Nothing saved yet", + "escapeHint": "Stuck with a broken interface? Press {shortcut} to suspend all custom style, or open a window with the safeStyle=1 query parameter.", + "copyTheme": "Copy theme JSON", + "importTheme": "Import theme…", + "clearTheme": "Clear overrides", + "interopHint": "Themes use shadcn's registry:theme format, so you can paste any shadcn theme here and use exported ones in any shadcn project.", + "importTitle": "Import theme", + "importDescription": "Paste a shadcn registry:theme item, a bare light/dark object, or a flat token map.", + "readClipboard": "Read clipboard", + "importConfirm": "Import", + "cancel": "Cancel", + "apply": "Apply", + "toasts": { + "copied": "Theme JSON copied", + "copyFailed": "Could not copy to the clipboard", + "clipboardReadFailed": "Could not read the clipboard, paste manually", + "importFailed": "No usable theme tokens found in that JSON", + "imported": "Theme imported" + }, + "css": { + "dialogTitle": "Custom CSS", + "dialogDescription": "Applies to every codeg window. Changes preview live; press Apply to save.", + "size": "{used} KB / {max} KB", + "ruleCount": "{count} rules", + "errorTooLarge": "Too large to save. Trim it below the limit.", + "errorImportEscaped": "An @import rule survived removal (escaped syntax). Remove it to save.", + "warnNoRules": "No rules parsed, check the syntax.", + "noticeImportsRemoved": "@import rules removed: {count}. They would fetch remote stylesheets.", + "noticeRemoteUrl": "Contains a remote url(), which makes a network request when applied.", + "noticePreviewSuspended": "Custom style is suspended, so this preview is not applied.", + "noticeDisabled": "Custom CSS is off. You can preview here, but nothing applies until you enable it.", + "hintTokens": "Tip: your color overrides are available as var(--primary), var(--background) and so on." + } + }, + "zoomLevel": { + "sectionTitle": "Window zoom", + "sectionDescription": "Scale the entire interface. Applies immediately and persists per device.", + "placeholder": "Select zoom level", + "default": "Default", + "current": "Current zoom: {zoom}%" + }, + "fonts": { + "sectionTitle": "Fonts", + "sectionDescription": "Choose fonts for the interface, code editor, and terminal. Bundled fonts load on demand; pick “Custom…” to use any font installed on your system.", + "interface": "Interface", + "editor": "Editor", + "terminal": "Terminal", + "groupSans": "Sans-serif", + "groupMono": "Monospace", + "custom": "Custom…", + "customPlaceholder": "Font family, e.g. Fira Code", + "fontSize": "Font size", + "ligatures": "Enable font ligatures", + "ligaturesUnavailable": "This font has no ligatures", + "wordWrap": "Enable word wrap", + "terminalLigaturesHint": "Terminal ligatures apply only to bundled coding fonts.", + "preview": "Preview" + }, + "welcomePanel": { + "sectionTitle": "Mode selection area", + "sectionDescription": "The Code Development / Office Work shortcut cards shown above the composer on the new conversation page.", + "showQuickActions": "Show on the new conversation page" + }, + "workspaceBackground": { + "sectionTitle": "Workspace background", + "sectionDescription": "Show a picture behind the whole workspace. Sidebar and panels turn translucent and frosted so the image shows through, and a mask keeps text readable.", + "enable": "Enable background image", + "image": "Image", + "chooseImage": "Choose image", + "replaceImage": "Replace image", + "removeImage": "Remove", + "fillMode": "Fill mode", + "fillModes": { + "cover": "Cover", + "contain": "Contain", + "center": "Center", + "tile": "Tile" + }, + "maskOpacity": "Mask opacity", + "maskOpacityHint": "Higher values fade the image toward the theme background, improving text contrast.", + "imageBlur": "Image blur", + "panelOpacity": "Panel opacity", + "panelOpacityHint": "How opaque the sidebar, panels and tab bars are. Lower lets more of the image show through.", + "errorTooLarge": "Image is too large (max 16 MB).", + "errorUploadFailed": "Failed to set the background image." + } + }, + "SystemSettings": { + "loading": "Loading...", + "sectionTitle": "System Management", + "sectionDescription": "Manage network proxy, app updates and language preferences.", + "proxyTitle": "Network Proxy", + "proxyDescription": "When enabled, subsequent network requests prefer this proxy (including ACP chat, agent installation and Git remote operations).", + "loadFailed": "Load failed: {message}", + "enableProxy": "Enable system proxy", + "proxyAddress": "Proxy address", + "proxyHint": "Supports http(s)/socks5, example: {example}. Only effective when system proxy is enabled.", + "save": "Save", + "saving": "Saving...", + "proxyRequired": "Proxy URL is required when proxy is enabled", + "saveSuccess": "System proxy settings saved", + "saveFailed": "Save failed: {message}", + "languageTitle": "Language", + "languageDescription": "Set app language. When following system locale, unsupported languages fall back to English.", + "appLanguage": "App language", + "languageSaveSuccess": "Language settings saved", + "languageSaveFailed": "Failed to save language settings: {message}", + "updateTitle": "App Update", + "versionTitle": "Software Update", + "updateDescription": "Check the configured release source for newer versions and install directly when available.", + "currentVersion": "Current version", + "upgradableVersion": "Latest version", + "none": "None", + "lastChecked": "Last checked: {time}", + "updateError": "Update error: {message}", + "checking": "Checking...", + "checkUpdate": "Check for updates", + "updating": "Installing...", + "downloading": "Downloading...", + "upgradeTo": "Upgrade to v{version}", + "viewRelease": "View v{version} release", + "foundUpdate": "New version v{version} found", + "alreadyLatest": "You're on the latest version", + "checkUpdateFailed": "Failed to check for updates: {message}", + "installSuccess": "Update installed. Relaunching app.", + "installFailed": "Update failed: {message}", + "upgradeSuccess": "Upgrade complete. Reloading...", + "restartTimeout": "The server didn't come back in time. Check the container or service logs.", + "restartingIn": "Restarting in {seconds}s...", + "waitingForServer": "Waiting for the server to come back...", + "restartToUpdate": "Restart to update", + "newVersionBadge": "New v{version}", + "updateAvailableTitle": "Update available", + "releaseNotesTitle": "What's new", + "remindLater": "Later", + "retry": "Retry", + "stepDownload": "Download", + "stepInstall": "Install", + "stepRestart": "Restart", + "updateReadyHint": "Update downloaded — restart to apply.", + "restarting": "Restarting...", + "dockerUpgradeHint": "This upgrades the running container now. It's lost if the container is recreated — to keep it, pull or build an image at the new version and recreate.", + "upgradeRolledBack": "Upgrade failed; the server rolled back to the previous version.", + "serverUnreachable": "Couldn't reach the server to start the upgrade. Check that it's running and try again.", + "rollbackButton": "Roll back", + "rollingBack": "Rolling back...", + "rollbackDescription": "Restore the version installed before the last upgrade.", + "rollbackConfirmTitle": "Roll back to the previous version?", + "rollbackConfirmDescription": "The server will restart on the version installed before the last upgrade. A newer release stays available to install again.", + "rollbackConfirm": "Roll back", + "rollbackCancel": "Cancel", + "rollbackSuccess": "Rolled back to the previous version. Reloading...", + "rollbackFailed": "Rollback failed. Check the server logs.", + "updateErrors": { + "sourceUnavailable": "Cannot reach the update source. Check your network or proxy and try again.", + "network": "Network connection failed. Check your network or proxy and try again.", + "downloadFailed": "Failed to download update package. Please try again later.", + "installFailed": "Failed to install update. Please close the app and try again.", + "unknown": "Update failed. Please try again later." + } + }, + "VersionControlSettings": { + "loading": "Loading...", + "sectionTitle": "Version Control", + "sectionDescription": "Configure Git executable and manage GitHub accounts.", + "gitTitle": "Git Configuration", + "gitDescription": "Configure the Git executable used by the application.", + "gitDetected": "Git detected", + "gitNotFound": "Git not found on this system", + "gitVersion": "Version", + "gitPath": "Path", + "customGitPath": "Custom Git Path", + "customGitPathPlaceholder": "/usr/bin/git", + "customGitPathHint": "Leave empty to use the auto-detected path.", + "test": "Test", + "testing": "Testing...", + "testSuccess": "Git executable is valid.", + "testFailed": "Git test failed: {message}", + "save": "Save", + "saving": "Saving...", + "saveSuccess": "Git settings saved.", + "saveFailed": "Failed to save: {message}", + "githubTitle": "GitHub Accounts", + "githubDescription": "Manage GitHub accounts for authentication. Tokens are stored locally.", + "noAccounts": "No GitHub accounts configured.", + "addAccount": "Add Account", + "serverUrl": "Server URL", + "serverUrlPlaceholder": "https://github.com", + "token": "Personal Access Token", + "tokenPlaceholder": "ghp_xxxxxxxxxxxx", + "generateToken": "Generate token", + "tokenHint": "Generate a token at GitHub → Settings → Developer settings → Personal access tokens.", + "validateAndAdd": "Validate & Add", + "validating": "Validating...", + "addSuccess": "Account {username} added successfully.", + "addFailed": "Failed to add account: {message}", + "testConnection": "Test", + "connectionSuccess": "Connection successful.", + "connectionFailed": "Connection failed: {message}", + "setDefault": "Set Default", + "defaultLabel": "Default", + "defaultSet": "Default account updated.", + "removeAccount": "Remove", + "removeConfirmTitle": "Remove Account", + "removeConfirmMessage": "Are you sure you want to remove the account \"{username}\"?", + "removeConfirm": "Remove", + "removeCancel": "Cancel", + "removeSuccess": "Account removed.", + "scopes": "Scopes", + "loadFailed": "Failed to load settings: {message}", + "gitAccount": { + "sectionTitle": "Git Accounts", + "sectionDescription": "Manage credentials for non-GitHub Git servers (GitLab, Bitbucket, self-hosted, etc.).", + "noAccounts": "No Git server accounts configured.", + "addAccount": "Add Account", + "addTitle": "Add Git Account", + "addDescription": "Enter the server address, username, and password or access token.", + "serverUrl": "Server URL", + "serverUrlPlaceholder": "https://gitlab.example.com", + "username": "Username", + "usernamePlaceholder": "Username or email", + "password": "Password / Token", + "passwordPlaceholder": "Password or access token", + "passwordHint": "Enter your password or a personal access token for the server.", + "add": "Add", + "serverRequired": "Server URL is required.", + "usernameRequired": "Username is required.", + "passwordRequired": "Password is required." + } + }, + "ShortcutSettings": { + "sectionTitle": "Shortcuts", + "resetDefault": "Reset defaults", + "recordInstruction": "Click the right-side button, then press a key combination. Use Ctrl/Cmd, Alt, and Shift. Press Esc to cancel recording.", + "recording": "Press shortcut...", + "toasts": { + "conflict": "Shortcut is already used by \"{title}\"", + "updated": "Shortcut updated", + "invalid": "Invalid shortcut, please try again", + "reset": "Default shortcuts restored" + }, + "actions": { + "toggle_search": { + "title": "Open Search", + "description": "Show or hide the conversation search panel" + }, + "toggle_sidebar": { + "title": "Toggle Left Sidebar", + "description": "Show or hide the conversation list sidebar" + }, + "toggle_terminal": { + "title": "Toggle Terminal", + "description": "Show or hide the bottom terminal panel" + }, + "new_terminal_tab": { + "title": "New Terminal", + "description": "Create a new terminal tab when focus is on terminal" + }, + "close_current_terminal_tab": { + "title": "Close Current Terminal", + "description": "Close the current terminal tab when focus is on terminal" + }, + "toggle_aux_panel": { + "title": "Toggle Right Panel", + "description": "Show or hide the auxiliary info panel" + }, + "new_conversation": { + "title": "New Conversation", + "description": "Create a new conversation tab in current folder" + }, + "open_folder": { + "title": "Open Folder", + "description": "Open folder picker and open in a new window" + }, + "open_settings": { + "title": "Open Settings", + "description": "Open settings window" + }, + "close_current_tab": { + "title": "Close Current Tab", + "description": "Close current conversation or file tab" + }, + "close_all_file_tabs": { + "title": "Close All File Tabs", + "description": "Close all open file tabs when the file pane is active" + }, + "next_tab": { + "title": "Next Tab", + "description": "Switch to the next conversation or file tab" + }, + "prev_tab": { + "title": "Previous Tab", + "description": "Switch to the previous conversation or file tab" + }, + "send_message": { + "title": "Send Message", + "description": "Send the current message in the input box" + }, + "newline_in_message": { + "title": "Newline in Message", + "description": "Insert a newline in the message input box" + }, + "toggle_custom_style": { + "title": "Suspend/resume custom style", + "description": "Escape hatch: turns all custom colors and CSS off, and back on" + } + } + }, + "SkillsSettings": { + "title": "Skills", + "description": "Select a skill on the left. The right side previews Markdown by default; switch to edit to modify and save.", + "loadingAgents": "Loading agents that support Skills...", + "emptyNoManageableAgents": "No agents available for Skills management.", + "managedTarget": "Managed target", + "selectAgentPlaceholder": "Select an agent", + "searchPlaceholder": "Search by name / ID / path...", + "skillsList": "Skills list", + "loadingSkills": "Loading skills...", + "agentNotSupported": "Current agent does not support Skills management.", + "emptySkills": "No skills yet. Click \"New Skill\" to create one.", + "newSkillTitle": "New Skill", + "skillInfo": "Skill Info", + "skillIdPlaceholder": "skill-id (letters/numbers/-/_/.)", + "skillsDirectoryWithPath": "Skills directory: {path}", + "skillsDirectoryNeedId": "Skills directory: enter Skill ID to generate full path", + "markdownContent": "Markdown Content", + "editingStatus": "Editing", + "previewStatus": "Previewing", + "contentPlaceholder": "Enter Skill markdown content...", + "metadataTitle": "Skills Metadata", + "onlyYamlMetadata": "This skill only contains YAML metadata.", + "emptyContentHint": "No content yet. Click \"Edit\" to start.", + "loadingSkill": "Loading skill...", + "emptyNoAgents": "No available agent.", + "noSelectionHint": "Select a skill on the left, or click \"New Skill\" to create one.", + "systemBadge": "System", + "systemHint": "Built-in CLI skill · read-only", + "scope": { + "global": "Global", + "folder": "Folder", + "selectFolderPlaceholder": "Select a folder", + "noFolders": "No folders found", + "pickFolderHint": "Select a folder to view its skills." + }, + "actions": { + "preview": "Preview", + "edit": "Edit", + "openInWindow": "Open in new window", + "delete": "Delete", + "deleting": "Deleting...", + "refresh": "Refresh", + "newSkill": "New Skill", + "reset": "Reset", + "save": "Save", + "saving": "Saving...", + "cancel": "Cancel" + }, + "deleteDialog": { + "title": "Delete Skill", + "confirm": "Delete current skill? This action cannot be undone.", + "confirmWithNamePrefix": "Delete skill", + "confirmWithNameSuffix": "? This action cannot be undone." + }, + "toasts": { + "loadFailed": "Failed to load skill", + "openFolderFailed": "Failed to open folder", + "noSkillDirectory": "No available Skills directory found for current agent", + "nameRequired": "Skill name cannot be empty", + "updated": "Skill updated", + "created": "Skill created", + "saveFailed": "Failed to save skill", + "deleted": "Skill deleted", + "deleteFailed": "Failed to delete skill" + }, + "templates": { + "gemini": "---\nname: example-skill\ndescription: Describe when this skill should be used.\n---\n\n# Skill Name\n\nInstructions for the agent when this skill is active.\n\n## Workflow\n\n1. Add actionable step one.\n2. Add actionable step two.\n", + "openCode": "---\nname: example-skill\ndescription: Describe when this skill should be used.\n---\n\n# Purpose\n\nDescribe what this skill helps with.\n\n# Steps\n\n1. Add actionable step one.\n2. Add actionable step two.\n", + "openClaw": "---\nname: example-skill\ndescription: Describe when this skill should be used.\nuser-invocable: true\ndisable-model-invocation: false\n---\n\n# Purpose\n\nDescribe what this skill helps with.\n\n# Instructions\n\n1. Add actionable instruction one.\n2. Add actionable instruction two.\n", + "default": "---\nname: example-skill\ndescription: Describe when this skill should be used.\n---\n\n# Skill: example-skill\n\n## When to use\n\n- Describe trigger conditions.\n\n## Instructions\n\n1. Add actionable instruction one.\n2. Add actionable instruction two.\n" + } + }, + "McpSettings": { + "loading": "Loading...", + "summary": { + "missingCommand": "(missing command)", + "missingUrl": "(missing url)" + }, + "protocol": { + "stdio": "Stdio" + }, + "errors": { + "selectInstallProtocol": "Please select an install protocol", + "fieldRequired": "{field} is required", + "fieldNeedsBoolean": "{field} must be true or false", + "fieldNeedsNumber": "{field} must be a number", + "fieldNeedsInteger": "{field} must be an integer", + "fieldInvalidJson": "{field} has invalid JSON: {message}", + "fieldOutOfRange": "{field} value is out of allowed range", + "jsonEmpty": "{name} cannot be empty", + "jsonInvalid": "{name} is not valid JSON: {message}", + "jsonMustBeObject": "{name} must be a JSON object", + "specMustBeObject": "MCP config must be a JSON object.", + "missingType": "MCP config is missing the type field. Use one of stdio, http (aliases: streamable-http, streamableHttp), sse.", + "unsupportedType": "Unsupported MCP type {type}. Supported: stdio, http (aliases: streamable-http, streamableHttp), sse.", + "codexEntryUnsupportedType": "Codex MCP entry {id} has unsupported type {type}. Supported: stdio, http (aliases: streamable-http, streamableHttp), sse.", + "unsupportedTransportType": "Unsupported transport type {type}. Supported: http (aliases: streamable-http, streamableHttp), sse.", + "stdioCommandRequired": "stdio MCP requires a non-empty command field.", + "remoteUrlRequired": "Remote MCP requires a non-empty url field.", + "appsRequired": "Select at least one target app." + }, + "jsonNames": { + "localConfig": "MCP Config", + "installConfig": "Install Config" + }, + "toasts": { + "uninstalled": "MCP uninstalled", + "uninstallFailed": "Uninstall failed: {message}", + "selectAtLeastOneApp": "Please select at least one target app", + "saveSuccess": "Saved", + "saveFailed": "Save failed: {message}", + "installed": "{name} installed", + "installFailed": "Install failed: {message}", + "serverIdRequired": "Server ID is required", + "serverIdExists": "Server ID \"{id}\" already exists. Edit the existing entry or pick a different name.", + "created": "MCP created" + }, + "installDialog": { + "title": "Confirm MCP Installation", + "descriptionWithName": "Install {name} to local configuration.", + "description": "Select target apps for installation.", + "protocol": "Protocol", + "selectProtocol": "Select protocol", + "parameters": "Configuration Parameters", + "booleanPlaceholder": "Please select true/false", + "selectOneValue": "Select a value", + "targetApps": "Target Apps" + }, + "actions": { + "cancel": "Cancel", + "confirmInstall": "Confirm Install", + "installing": "Installing", + "uninstall": "Uninstall", + "uninstalling": "Uninstalling", + "viewDetails": "View Details", + "save": "Save", + "saving": "Saving", + "install": "Install", + "refresh": "Refresh", + "newMcp": "New MCP", + "create": "Create", + "creating": "Creating..." + }, + "tabs": { + "local": "Local MCP", + "market": "MCP Marketplace" + }, + "local": { + "filterPlaceholder": "Filter local MCP...", + "loadFailed": "Load failed: {message}", + "empty": "No local MCP detected.", + "description": "Local MCP configuration can be edited and saved directly.", + "enabledApps": "Enabled Apps", + "configJson": "MCP Config (JSON)", + "draftTitle": "New MCP", + "draftDescription": "Provide a Server ID and configuration to create a local MCP server.", + "serverIdLabel": "Server ID", + "serverIdPlaceholder": "Server ID (e.g. my-mcp)", + "typeHint": "Supported types: stdio, http (aliases: streamable-http, streamableHttp), sse. env is only used by stdio; for remote MCPs use headers to carry auth tokens.", + "envOnRemoteWarning": "env detected on a remote MCP. Only stdio uses env; remote MCPs carry auth tokens via headers, so env will be ignored on save." + }, + "market": { + "selectMarketplace": "Select marketplace", + "searchPlaceholder": "Search MCP...", + "searchFailed": "Search failed: {message}", + "loadingList": "Loading MCP list...", + "empty": "No MCP results.", + "loadingDetail": "Loading marketplace details...", + "detailLoadFailed": "Failed to load details: {message}", + "owner": "Owner: {owner}", + "namespace": "Namespace: {namespace}", + "defaultInstallProtocol": "Default Install Protocol", + "currentOptionParameterCount": "Current option parameter count: {count}", + "installConfigDescription": "Install Config (JSON, editable before install; edits will override protocol/parameter form)", + "selectLeftToView": "Select a marketplace MCP on the left to view details." + }, + "badges": { + "verified": "Verified", + "remote": "Remote", + "hasHomepage": "Has Homepage", + "uses": "{count} uses", + "deployed": "Deployed", + "notDeployed": "Not Deployed" + }, + "selectLeftMcp": "Select an MCP on the left." + }, + "AcpAgentSettings": { + "title": "Agent SDK Management", + "description": "Manage Agent SDK connection, enabled state, environment variables, config management and version preflight info in one place.", + "loadingAgents": "Loading agent list...", + "agentList": "Agent List", + "emptyNoAgent": "No available agent.", + "configManagement": "Config Management", + "envVars": "Environment Variables", + "hostTools": { + "label": "Let the agent handle files and commands", + "description": "codeg stops serving file access and terminal commands, so the agent runs them in its own process — where its own sandbox and permission rules apply. Delegating to other agents is also turned off, since that would route the same work back through codeg. codeg adds no sandbox itself, so turn this on only if the agent has one configured." + }, + "nativeJsonConfig": "Native JSON Config", + "modelHintDefault": "Leave empty to use system default model.", + "generalConfigDescriptionClaude": "Supports quick configuration for API URL, API Key and Claude models, and syncs with native JSON config.", + "generalConfigDescriptionDefault": "Supports important config input (API URL, API Key, Model) and native JSON config management.", + "multiAgent": { + "title": "Multi-Agent Collaboration", + "description": "Allow active agents to delegate sub-tasks to other agents.", + "enable": "Enable delegation", + "enableHint": "When off, the delegate_to_agent tool is hidden from the agent's MCP catalog.", + "withheldByHostTools": "{agents} will not get the delegation tools: their per-agent “Let the agent handle files and commands” switch is on.", + "selfInitiate": "Allow spawn without @", + "selfInitiateHint": "When on, an agent may start a listed sub-agent on its own. An @ mention is still always honored. When off, only an @ mention starts a sub-agent.", + "depthLimit": "Maximum delegation depth", + "depthHint": "Allowed range: {min}–{max}. Caps how deep a chain (root → child → grandchild …) can recurse.", + "completedCacheLabel": "Completed-result cache (MB)", + "completedCacheHint": "In-memory cache of finished sub-agent results, held only while the delegating session is running and cleared automatically when it ends. Over this budget the oldest results are dropped from memory first (still viewable in the sub-agent's own session); 0 = unlimited (still cleared when the session ends).", + "save": "Save", + "saving": "Saving…", + "saved": "Delegation settings saved", + "saveFailed": "Failed to save delegation settings", + "loadFailed": "Failed to load delegation settings: {detail}", + "tabGeneral": "General", + "tabAgentDefaults": "Agent defaults", + "agentDefaultsDescription": "Per-agent overrides applied when Multi-Agent Collaboration spawns a subagent for a delegation call. Options shown here come from a live probe — what you pick is exactly what the agent will accept.", + "probing": "Loading available options from the agent…", + "probeFailed": "Failed to load options: {detail}", + "retry": "Retry", + "noConfigAvailable": "This agent has no configurable options.", + "modeLabel": "Mode", + "agentDefaultHint": "Agent default: {value}", + "defaultOptionLabel": "Default ({value})" + }, + "actions": { + "dragSort": "Drag to reorder", + "dragSortAgent": "Drag to reorder {name}", + "refreshCheck": "Refresh check", + "refreshCheckAgent": "Refresh check {name}", + "clickEnable": "Click to enable {name}", + "clickDisable": "Click to disable {name}", + "install": "Install", + "upgrade": "Upgrade", + "uninstall": "Uninstall", + "uninstalling": "Uninstalling...", + "saveEnvVars": "Save environment variables", + "saving": "Saving...", + "saveGrokConfig": "Save Grok Config", + "saveCodexConfig": "Save Codex Config", + "saveGeminiConfig": "Save Gemini Config", + "saveOpenCodeConfig": "Save OpenCode Config", + "saveOpenClawConfig": "Save OpenClaw Config", + "saveConfigManagement": "Save Config Management", + "saveCurrentProvider": "Save Current Provider", + "showApiKey": "Show API Key", + "hideApiKey": "Hide API Key", + "showKey": "Show Key", + "hideKey": "Hide Key", + "showToken": "Show Token", + "hideToken": "Hide Token", + "cancel": "Cancel", + "delete": "Delete", + "deleting": "Deleting...", + "confirmDelete": "Confirm Delete", + "confirmUninstall": "Confirm Uninstall", + "saveClineConfig": "Save Cline Config", + "saveHermesConfig": "Save Hermes Config", + "saveCodeBuddyConfig": "Save CodeBuddy Config", + "saveKimiCodeConfig": "Save Kimi Code Config", + "customInstall": "Custom install", + "saveKimiCodeRawConfig": "Save config.toml", + "saveDeepSeekConfig": "Save DeepSeek Config", + "diagnose": "Diagnose" + }, + "status": { + "enabled": "Enabled", + "disabled": "Disabled", + "unchecked": "Unchecked", + "agentEnabledAria": "{name} enabled", + "agentEnabledSwitch": "{name} enable switch" + }, + "preflight": { + "count": "Preflight items: {count}", + "notRun": "Checks have not run yet." + }, + "grok": { + "configDescription": "Configure Grok here. The controls below — permission mode, reasoning effort, an optional custom (BYO endpoint) model, and compaction — merge into ~/.grok/config.toml, preserving your other keys and comments. Sign-in uses your XAI_API_KEY or `grok login`. Other keys stay editable under Advanced.", + "permissionModeLabel": "Permission mode", + "permissionDefault": "Ask every time", + "permissionAcceptEdits": "Auto-approve edits", + "permissionAuto": "Smart auto-approve", + "permissionAlwaysApprove": "Always approve", + "reasoningEffortLabel": "Reasoning effort", + "effortLow": "Low (faster)", + "effortMedium": "Medium (balanced)", + "effortHigh": "High", + "effortXhigh": "Max", + "optionDefault": "Use default", + "authTitle": "Authentication", + "authMode": "Authentication method", + "authModeApiKey": "XAI API key", + "authModeApiKeyHint": "Authenticate with an XAI_API_KEY from the xAI console — for non-interactive or headless runs. Stored in this agent's environment.", + "authModeCustom": "Custom endpoint", + "authModeCustomHint": "Use a bring-your-own endpoint: define a custom model below with its own base URL and API key. It becomes Grok's default model.", + "subscriptionHint": "Sign in with `grok login` (SuperGrok / X Premium+). No API key is stored.", + "loginHint": "Run this in a terminal to sign in, then reopen these settings:", + "commandCopied": "Command copied to clipboard", + "copyCommand": "Copy command", + "authKeyConfigured": "XAI_API_KEY is configured.", + "authKeyMissing": "No XAI_API_KEY set.", + "advancedToggle": "Advanced (raw config.toml)", + "configTomlNative": "config.toml (native)", + "configTomlHint": "Saved verbatim as the whole ~/.grok/config.toml. Invalid TOML is rejected so a typo never truncates your file.", + "configTomlPlaceholder": "# Keys other than the controls above, e.g.\n# [mcp_servers.*], [cli], [permission] rules.", + "customModelTitle": "Custom model (BYO endpoint)", + "customModelHint": "Point Grok at a custom or self-hosted endpoint. codeg writes a per-model `[model.*]` block and makes it the default. Leave the Model ID empty to remove it.", + "customModelIdLabel": "Model ID", + "customModelIdPlaceholder": "grok-4.5", + "customModelIdHint": "Registered as a `[model.*]` block and sent to the API as the model name; also set as `[models].default`.", + "customBaseUrlLabel": "Base URL", + "customBaseUrlPlaceholder": "https://api.x.ai/v1 (default)", + "customApiBackendLabel": "API backend", + "backendResponses": "Responses", + "backendChatCompletions": "Chat Completions", + "backendMessages": "Messages (Anthropic)", + "customApiKeyLabel": "API Key", + "customApiKeyHint": "Stored inline in `[model.*].api_key`, scoped to this endpoint.", + "customContextWindowLabel": "Context window (tokens)", + "customContextWindowHint": "Optional. Drives auto-compact timing; leave empty for the endpoint default.", + "autoCompactLabel": "Auto-compact threshold (%)", + "autoCompactHint": "Compact the conversation when context usage reaches this percent (Grok default 85). Written to `[session]`." + }, + "cursor": { + "configDescription": "Configure Cursor here. Choose an authentication method — official subscription (browser sign-in) or a Cursor API key for headless/server machines — then pick a model and edit the CLI's permission rules and sandbox. codeg writes them into ~/.cursor/cli-config.json, shared with the cursor-agent CLI.", + "authTitle": "Authentication", + "authChecking": "Checking…", + "authNotInstalled": "cursor-agent is not installed", + "authLoggedIn": "Logged in", + "authNotLoggedIn": "Not logged in", + "loginHint": "Run this in a terminal to sign in with your Cursor account (a browser window opens), then hit refresh:", + "apiKeyLabel": "Cursor API key", + "apiKeyPlaceholder": "key from cursor.com/dashboard", + "apiKeyHint": "CURSOR_API_KEY — a Cursor Dashboard account key, an alternative to browser login for headless/server machines. Not a third-party or OpenAI key.", + "modelTitle": "Default model", + "loadModels": "Load models", + "modelsUnavailable": "Model list unavailable", + "modelHint": "Passed to the CLI as --model at session start. Leave on default to let Cursor choose.", + "permissionsTitle": "Permissions & sandbox", + "permissionsDescription": "Visual editor for the CLI's permission rules (cli-config.json). Allow rules run without prompting; deny rules are always blocked.", + "permissionModeLabel": "Permission mode", + "permissionModeDefault": "Ask before running (default)", + "permissionModeForce": "Run Everything (--force)", + "permissionModeHint": "Run Everything launches sessions with --force: every tool call is auto-allowed except deny rules, with no confirmation prompts (an organization policy may downgrade it to allow-rule matching). Takes effect for new sessions.", + "optionDefault": "Default (unset)", + "sandboxLabel": "Sandbox", + "sandboxEnabled": "Enabled", + "sandboxDisabled": "Disabled", + "allowRulesLabel": "Allow rules", + "denyRulesLabel": "Deny rules", + "addRule": "Add rule", + "rulesSyntaxHint": "Rule syntax: Shell(cmd), Read(path/glob), Write(path/glob), WebFetch(domain), Mcp(server:tool) — deny rules always win.", + "saveConfig": "Save configuration", + "advancedToggle": "Advanced: raw cli-config.json", + "advancedHint": "The whole ~/.cursor/cli-config.json. Saving writes the file verbatim — the structured controls above merge into it instead.", + "saveRawConfig": "Save file", + "authMode": "Authentication method", + "subscriptionHint": "Sign in with your Cursor account and use Cursor's models.", + "customApiKeyRequired": "A Cursor API key is required.", + "authModeApiKey": "Cursor API key (headless)", + "authModeApiKeyHint": "Authenticate with a Cursor account API key from the Cursor dashboard — for headless or server machines. This is a Cursor account key, not a third-party/OpenAI endpoint: cursor-agent only talks to Cursor's own backend. To use a codex/OpenAI-compatible endpoint, use the Codex agent instead.", + "modelPickerPlaceholder": "Search models…", + "modelNoMatch": "No matching model", + "modelsNeedAuth": "Sign in to load the model list.", + "modelDefaultBadge": "default" + }, + "deepseek": { + "configManagement": "DeepSeek Harness Configuration", + "configDescription": "The endpoint and key are environment variables deepseek-acp reads at launch. Model and reasoning effort are per-session selectors — pick them in the composer.", + "baseUrlLabel": "API endpoint", + "baseUrlHint": "Leave empty for the official endpoint. Applies to sessions started after the save — reconnect a running session to pick it up.", + "baseUrlInvalid": "Enter a full http(s) URL with no query string, for example https://api.deepseek.com", + "apiKeyLabel": "API key", + "apiKeyHint": "Passed to the agent as DEEPSEEK_API_KEY. An environment variable outranks the credentials file, so leave this empty if you sign in through the terminal." + }, + "codex": { + "configDescription": "Supports quick configuration for API URL, API Key, model name and reasoning effort, and syncs with `auth.json` / `config.toml`.", + "authMode": "Auth Mode", + "chatgptSubscription": "Official Subscription", + "chatgptSubscriptionHint": "Log in with ChatGPT official subscription, no API Key required", + "apiKeyHint": "Connect using API Key to OpenAI or compatible API services", + "selectProvider": "Select Provider", + "modelName": "Model Name", + "selectReasoningEffort": "Select Reasoning Effort", + "enableWebsocket": "Enable WebSocket", + "enableWebsocketAria": "Enable WebSocket for Codex Provider", + "enableSkills": "Enable Skills", + "enableSkillsAria": "Enable Skills for Codex", + "enableFast": "Enable Fast", + "enableFastAria": "Enable Fast service tier for Codex", + "sandboxGroupTitle": "Sandbox & approvals", + "sandboxGroupHint": "Written to the global ~/.codex/config.toml, so codex CLI and IDE sessions see it too. These are thread defaults: they govern the turns codex starts on its own (/goal, /review, /compact). Ordinary prompts use the composer's approval preset instead. Restart a session to pick up changes.", + "sandboxShadowedWarning": "config.toml sets default_permissions, so codex resolves permissions through that profile and ignores sandbox_mode entirely. Remove default_permissions to use the controls below.", + "sandboxPermissionsTableWarning": "config.toml defines [permissions] profiles but no default_permissions, which makes codex refuse to start. Set one in the raw editor below.", + "approvalPolicyLabel": "Approval policy", + "approvalPolicyUnset": "Not set (codex default: on request)", + "approvalPolicy_on-request": "On request — the model decides when to ask", + "approvalPolicy_untrusted": "Untrusted — only known-safe read-only commands run unattended", + "approvalPolicy_never": "Never — no approval prompts at all", + "approvalPolicy_granular": "Granular — choose per prompt type", + "approvalPolicyUntrustedAcpWarning": "Untrusted has no equivalent in the ACP adapter's three approval presets, so codeg sessions fall back to \"on request\" — the model then decides when to ask, and commands the sandbox already allows stop prompting. Tighten the sandbox mode below instead.", + "granularHint": "Off means requests of that kind are auto-rejected instead of shown to you.", + "granular_sandbox_approval": "Shell command escalations", + "granular_rules": "Execpolicy rule prompts", + "granular_skill_approval": "Skill script prompts", + "granular_request_permissions": "request_permissions tool prompts", + "granular_mcp_elicitations": "MCP elicitation prompts", + "sandboxModeLabel": "Sandbox mode", + "sandboxModeUnset": "Not set (trusted folders fall back to workspace write)", + "sandboxMode_read-only": "Read-only", + "sandboxMode_workspace-write": "Workspace write", + "sandboxMode_danger-full-access": "Full access (no sandbox)", + "sandboxModeHint": "On Windows, workspace write is downgraded to read-only unless codex's experimental Windows sandbox is enabled.", + "sandboxModeSeedsPresetHint": "codeg also maps this onto the session's starting approval preset, so unlike approval policy it does reach ordinary prompts. The composer's preset still overrides it.", + "writableRootsLabel": "Extra writable folders", + "writableRootsHint": "One absolute path per line, in addition to the working directory.", + "sandboxRootsRelativeError": "Must be an absolute path — codex resolves relative entries against ~/.codex: {path}", + "networkAccessLabel": "Allow network access", + "excludeTmpdirLabel": "Exclude TMPDIR from writable roots", + "excludeSlashTmpLabel": "Exclude /tmp from writable roots", + "authJsonNative": "auth.json (native)", + "configTomlNative": "config.toml (native)", + "loginButton": "Log in with ChatGPT", + "loginRequesting": "Requesting login code...", + "loginStep1": "Open the following URL in your browser:", + "loginStep2": "Enter the code below:", + "loginPolling": "Waiting for authorization...", + "loginCancel": "Cancel", + "loginSuccess": "Logged in successfully, config saved!", + "loginFailed": "Login failed: {message}", + "loginRetry": "Retry", + "loginCodeCopied": "Code copied", + "loggedIn": "Account logged in", + "loginRelogin": "Re-login / Switch account", + "loginTimeout": "Login timed out, please try again", + "loginSaveFailed": "Login succeeded but failed to save config" + }, + "gemini": { + "authConfig": "Gemini Auth Config", + "authConfigDescription": "Aligned with Gemini CLI authentication docs, supporting custom endpoint, Google login, Gemini API Key and Vertex AI (ADC / service account / API Key).", + "authMode": "Auth Mode", + "selectAuthMode": "Select auth mode", + "viewAuthDoc": "View auth docs", + "mode": { + "custom": "Custom Endpoint", + "loginGoogle": "Google Login (OAuth)", + "vertexServiceAccount": "Vertex AI (Service Account)" + }, + "hint": { + "custom": "Fill API URL, API Key and Model, mapped to GOOGLE_GEMINI_BASE_URL / GEMINI_API_KEY / GEMINI_MODEL.", + "loginGoogle": "Run gemini in terminal and complete Google login first; API key is not required.", + "geminiApiKey": "Fill GEMINI_API_KEY when using Gemini API.", + "vertexAdc": "Use gcloud ADC; GOOGLE_CLOUD_PROJECT and GOOGLE_CLOUD_LOCATION are recommended.", + "vertexServiceAccount": "Set service account JSON path to GOOGLE_APPLICATION_CREDENTIALS.", + "vertexApiKey": "Fill GOOGLE_API_KEY when using Vertex AI API key." + } + }, + "openCode": { + "configManagement": "OpenCode Config Management", + "configDescription": "Aligned with OpenCode `provider` schema, supports multi-provider management and two-way sync with native JSON files.", + "providerManagement": "Provider Management", + "providerCount": "{count} providers", + "addProvider": "Add Provider", + "emptyProvider": "No custom providers yet. Click Add custom provider to create one.", + "providerEnabledState": "{providerId} enabled state", + "selectProviderNpm": "Select provider.npm", + "modelManagement": "Model Management", + "modelCount": "{count} models", + "modelDescription": "Aligned with OpenCode `provider.models`. Fast management currently supports `name` / `id`; other advanced fields are preserved and can be edited in native JSON below.", + "addModel": "Add model", + "emptyModel": "No model yet. Enter model id then click \"Add model\".", + "modelId": "Model ID", + "modelName": "Model Name", + "deleteModel": "Delete model {modelId}", + "nativeJsonConfig": "OpenCode Native JSON Config", + "mainModel": "Main Model", + "smallModel": "Small Model", + "noMatchingModels": "No matching models", + "connectProvider": "Connect Provider", + "connectedProviders": "Connected providers", + "noConnectedProviders": "No catalog providers connected yet.", + "advancedProviderConfig": "Custom providers", + "customProviderConfigHint": "OpenAI-compatible endpoints you define yourself — a provider block in opencode.json, with the API key in auth.json.", + "addCustomProvider": "Add custom provider", + "disconnect": "Disconnect", + "editConfig": "Edit", + "customBadge": "Custom", + "authKindApi": "API Key", + "authKindOauth": "OAuth", + "authKindNone": "No credential", + "connect": { + "title": "Connect a provider", + "description": "Choose a provider from the models.dev catalog. Credentials are saved to the OpenCode auth.json file.", + "pick": "Provider", + "search": "Search providers…", + "loading": "Loading catalog…", + "catalogLabel": "models.dev catalog", + "modelsAvailable": "{count} models available", + "getKey": "Get API key", + "oauthApiKeyNote": "This provider also supports browser sign-in via opencode auth login. Browser sign-in is coming soon — for now, paste an API key.", + "apiKey": "API Key", + "apiKeyHint": "Stored in auth.json, never in opencode.json.", + "baseUrlOptional": "Base URL override (optional)", + "providerId": "Provider ID", + "displayName": "Display name", + "modelsList": "Models (one per line)", + "modelsHint": "Model ids the endpoint accepts.", + "action": "Connect", + "editTitle": "Edit provider", + "editDescription": "Update this provider's API key or base URL.", + "saveAction": "Save" + }, + "customProvider": { + "title": "Add a custom provider", + "description": "Define an OpenAI-compatible endpoint. The API key is saved to auth.json; the provider block goes to opencode.json.", + "action": "Add provider", + "idInCatalog": "{providerId} is a known provider — connect it via Connect Provider instead." + }, + "refreshCatalog": "Refresh catalog", + "reasoningBadge": "reasoning", + "contextWindow": "Context window", + "permissions": { + "title": "Permissions", + "description": "Decide which actions run on their own, prompt you first, or are blocked. Written to the permission block of opencode.json and applied once you save below.", + "docsLink": "Permissions docs", + "unparsableConfig": "The native JSON below is not valid, so the visual editor is paused. Fix the JSON to resume.", + "invalidBlock": "The permission block has a shape codeg does not recognize. Edit it in the native JSON below, or use Reset to start over.", + "orderingUnsafe": "A wildcard rule is written after specific tools, so OpenCode applies it to them as well — the rows below are not what is in force. Fix order moves every wildcard back to the front of its scope without changing a single value.", + "orderingUnsafeManual": "One rule is shadowed by a later, more general pattern, so OpenCode never applies it — the rows below are not what is in force. Two overlapping patterns have no single right order; reorder them in the native JSON so the general one comes first.", + "fixOrder": "Fix order", + "agentOverrides": "These agents override permissions and are applied last, so they win over everything here: {agents}. Edit them in the native JSON below, or turn on auto-accept to clear them.", + "legacyTools": "The legacy top-level tools map denies a tool. OpenCode folds it into the permissions, so it applies on top of everything shown here. Edit it in the native JSON below, or turn on auto-accept to clear it.", + "autoAcceptTitle": "Auto-accept every permission", + "autoAcceptHint": "Every tool call — shell commands, file edits, paths outside the project — runs without asking. Turning this on replaces the per-tool settings below with a single allow-all rule, and clears the per-agent permission overrides and legacy tool toggles that would otherwise still block.", + "globalLabel": "Global default", + "globalHint": "The * rule: what applies to anything the tools below do not override.", + "actionUnset": "Unset (OpenCode defaults)", + "actionInherit": "Inherit ({action})", + "actionAllow": "Allow", + "actionAsk": "Ask", + "actionDeny": "Deny", + "perToolTitle": "Per-tool permissions", + "reset": "Reset", + "ruleCount": "rules: {count}", + "rulesToggle": "Fine-grained rules for {tool}", + "rulesHint": "Matched against the tool input, last match wins — so put the broad patterns first. * matches any characters, ? matches exactly one, and a leading ~ expands to your home directory.", + "noRules": "No fine-grained rules yet.", + "addRule": "Add rule", + "deleteRule": "Delete rule {pattern}", + "duplicateRule": "That pattern already exists.", + "blankRule": "A rule needs a pattern — use the trash icon to remove it.", + "customKeys": "Other permission keys in the file", + "customKeyHint": "Not a built-in OpenCode tool — kept as written.", + "keys": { + "bash": "Run shell commands, matched by the parsed command", + "edit": "All file modifications: edit, write and patch", + "read": "Read files, matched by path", + "external_directory": "Reach paths outside the project working directory", + "task": "Launch subagents, matched by subagent type", + "skill": "Load skills, matched by skill name", + "glob": "Find files, matched by glob pattern", + "grep": "Search file contents, matched by pattern", + "list": "List directory contents", + "webfetch": "Fetch a URL", + "websearch": "Search the web", + "lsp": "Run LSP queries", + "todowrite": "Write the todo list", + "question": "Ask you a question", + "doom_loop": "Trips when the same call repeats three times with identical input" + } + } + }, + "openClaw": { + "gatewayConfig": "Gateway Config", + "gatewayDescription": "Configure OpenClaw Gateway connection. Supports local or remote gateway.", + "gatewayUrlHint": "Leave empty to use gateway.remote.url from local openclaw config.", + "gatewayTokenPlaceholder": "Gateway auth token", + "gatewayTokenHint": "Use token-file instead of plain token when possible; configure via openclaw CLI.", + "sessionKeyHint": "Optional. Specify gateway session key; leave empty to auto-assign isolated session." + }, + "hermes": { + "configManagement": "Hermes Configuration", + "configDescription": "Hermes manages its own credentials in ~/.hermes/.env and settings in ~/.hermes/config.yaml. Pick a provider, then set the API key and model — codeg writes both files for you.", + "providerLabel": "Provider", + "providerHint": "The provider selects which API key variable and model.provider Hermes uses. OAuth providers are configured through the terminal setup below.", + "groupApiKey": "API key providers", + "groupOauth": "OAuth providers", + "groupAws": "AWS", + "apiKeyHint": "Saved to ~/.hermes/.env. It is never injected into the process — Hermes reads it from its own config.", + "modelName": "Model", + "oauthHint": "This provider uses OAuth. Run the setup below to authenticate in your terminal.", + "awsHint": "Bedrock uses your AWS credentials (environment or shared config). Set the model id above and configure AWS access in your environment.", + "unsupportedProvider": "This provider isn't editable with structured fields. Use the raw config.yaml editor below or the terminal setup.", + "setupTitle": "Self-managed setup", + "setupHint": "Hermes's interactive setup needs a terminal. Launch it below, or copy the command to run it yourself.", + "runSetup": "Run Hermes setup", + "configureModel": "Configure model", + "openConfigFolder": "Open ~/.hermes", + "copyCommand": "Copy command", + "commandCopied": "Command copied to clipboard", + "advancedTitle": "Advanced: edit config.yaml", + "rawConfigHint": "Edit ~/.hermes/config.yaml directly. Saving here overwrites the file verbatim.", + "saveRawConfig": "Save config.yaml" + }, + "codebuddy": { + "configManagement": "CodeBuddy Configuration", + "configDescription": "CodeBuddy authenticates with an API key. Mainland China builds also require the environment set to “China (internal)”; iOA builds use “iOA”. The overseas build leaves it unset.", + "apiKeyLabel": "API Key", + "apiKeyHint": "Saved as CODEBUDDY_API_KEY for this agent. Alternatively, sign in with the CodeBuddy CLI in a terminal.", + "apiKeyHintSelfHosted": "Saved as CODEBUDDY_API_KEY for this agent. Use the key issued by your private deployment.", + "environmentLabel": "Environment", + "environmentHint": "Sets CODEBUDDY_INTERNET_ENVIRONMENT. Mainland China must use “China (internal)”; the overseas build leaves it unset.", + "envOverseas": "Overseas (default)", + "envChina": "China (internal)", + "envIoa": "iOA", + "envSelfHosted": "Self-hosted (private deployment)", + "baseUrlLabel": "Deployment URL", + "baseUrlPlaceholder": "https://codebuddy.your-company.com", + "baseUrlHint": "Saved as CODEBUDDY_BASE_URL and points CodeBuddy at your private endpoint. The region setting is left unset for self-hosted deployments.", + "baseUrlInvalid": "Enter a valid http(s) URL.", + "loginHint": "No API key? Run “codebuddy” in a terminal to sign in with your Tencent account instead." + }, + "kimiCode": { + "configManagement": "Kimi Code Configuration", + "configDescription": "`kimi acp` only accepts a stored login token, so codeg writes a managed provider into ~/.kimi-code/config.toml and seeds a local gate token — inference still runs on your own key.", + "statusUnconfigured": "Not configured yet", + "statusDirty": "Unsaved changes", + "summaryLabel": "In effect", + "gateReadyApiKey": "API key written to config.toml", + "gateReadyLogin": "Signed in with a Kimi account", + "revealConfig": "Show in folder", + "envOverrideWarning": "{keys} is set and takes priority over config.toml. Saving here clears it.", + "authModeLabel": "Authentication method", + "authModeApiKey": "API key", + "authModeLogin": "Kimi account login (subscription)", + "authModeApiKeyHint": "Writes a codeg-managed provider into config.toml and seeds the gate token so sessions can open.", + "loginHint": "Run `kimi login` in a terminal to sign in with a Kimi subscription account. codeg stores nothing and reuses Kimi's own login. Saving here removes codeg's API-key gate token.", + "credentialTitle": "Credential", + "interfaceTypeLabel": "Provider type", + "interfaceTypeHint": "The provider protocol Kimi speaks (config.toml `type`). Use Kimi / Moonshot for a Moonshot / platform.kimi.com key.", + "endpointLabel": "Endpoint", + "endpointCustom": "Custom (OpenAI-compatible)", + "endpointHint": "International = api.moonshot.ai; China (platform.kimi.com keys) = api.moonshot.cn. Custom points at any OpenAI-compatible endpoint.", + "regionInternational": "International (api.moonshot.ai)", + "regionChina": "China (api.moonshot.cn)", + "baseUrlLabel": "Base URL", + "baseUrlHint": "Leave blank to use the provider SDK default.", + "apiKeyLabel": "API Key", + "apiKeyHint": "Written to ~/.kimi-code/config.toml and used for inference. From platform.kimi.com or platform.kimi.ai.", + "vertexProjectLabel": "GCP project (GOOGLE_CLOUD_PROJECT)", + "vertexLocationLabel": "GCP location (GOOGLE_CLOUD_LOCATION)", + "vertexHint": "Vertex AI uses Google Application Default Credentials — run `gcloud auth application-default login` (no API key).", + "modelTitle": "Model", + "modelLabel": "Model", + "modelHint": "The model id written to config.toml. Use “Test & list models” to see what your key can actually access.", + "maxContextLabel": "Max context size", + "maxContextHint": "Required by Kimi's schema: without it Kimi discards the whole model block and every prompt comes back empty. Defaults to 262144.", + "fetchModels": "Test & list models", + "fetchModelsOk": "Key works — {count} models available", + "fetchModelsEmpty": "Key works, but no models were returned", + "fetchModelsFailed": "Test failed", + "fetchModelsNeedsKey": "Enter an API key and endpoint first", + "modelNotInList": "This model is not in the list your key can access — Kimi will fail with “model not found”.", + "reasoningTitle": "Reasoning", + "reasoningEnableLabel": "Enable", + "reasoningDescription": "Kimi only shows a Thinking picker in the composer when the model declares a reasoning capability, so codeg writes one here. Takes effect on new sessions.", + "effortsLabel": "Levels offered", + "effortsHint": "These become the rows of the composer's Thinking picker. Kimi forwards the level to the provider verbatim, so pick ones your model accepts.", + "effortsEmptyHint": "With no levels chosen the composer falls back to a plain Off / On toggle.", + "effortsCustomPlaceholder": "Add another level", + "effortsAdd": "Add", + "defaultEffortLabel": "Default level", + "defaultEffortAuto": "Let Kimi choose", + "alwaysThinkingLabel": "The model always reasons — remove the Off row from the picker", + "fixErrorsFirst": "Fix the highlighted fields first", + "errorModelRequired": "Model is required", + "errorMaxContextRequired": "Max context size is required", + "errorMaxContextInvalid": "Must be a positive integer", + "errorApiKeyRequired": "API key is required", + "errorApiKeyInvalid": "The API key must not contain line breaks", + "errorBaseUrlRequired": "Base URL is required", + "errorBaseUrlInvalid": "Must start with http:// or https://", + "errorVertexProjectRequired": "GCP project is required", + "errorDefaultEffortUnlisted": "Pick one of the levels selected above", + "advancedTitle": "Advanced", + "authTypeLabel": "Credential placement", + "authTypeApiKey": "Inline api_key", + "authTypeEnv": "Provider env sub-table", + "authTypeHint": "Where the API key is written inside config.toml.", + "rawEditorLabel": "Edit config.toml directly", + "rawEditorWarning": "Saving here overwrites the entire file verbatim, replacing the structured settings above.", + "rawEditorPlaceholder": "[providers.codeg]\ntype = \"kimi\"\nbase_url = \"https://api.moonshot.cn/v1\"\napi_key = \"sk-...\"" + }, + "authModeOfficialSubscription": "Official Subscription", + "authModeCustomEndpoint": "Custom Endpoint", + "authModeCustomEndpointHint": "Manually configure API URL and API Key for a custom endpoint.", + "authModeModelProvider": "Model Provider", + "modelProvider": "Model Provider", + "modelProviderHint": "Use API URL, API Key, and model from a configured model provider.", + "selectModelProvider": "Select Model Provider", + "noModelProviderAvailable": "No model provider configured for this agent. Go to Model Provider Settings to add one.", + "claude": { + "authMode": "Auth Mode", + "officialSubscription": "Official Subscription", + "officialSubscriptionHint": "Use official Anthropic subscription, no API Key required.", + "mainModel": "Main Model", + "reasoningModel": "Reasoning Model (thinking)", + "haikuDefaultModel": "Default Haiku Model", + "sonnetDefaultModel": "Default Sonnet Model", + "opusDefaultModel": "Default Opus Model", + "customModelOption": "Custom Model ID", + "customModelOptionName": "Custom Model Name", + "customModelOptionDescription": "Custom Model Description", + "customModelOptionHint": "Adds a single custom entry to Claude's model picker (e.g. a model behind a custom gateway/proxy). Name and description are optional display overrides.", + "effortLevel": "Reasoning Effort Level", + "effortLevelDefault": "Default Level", + "effortLevel_low": "Low", + "effortLevel_medium": "Medium", + "effortLevel_high": "High", + "effortLevel_xhigh": "Extra High", + "sendAttributionHeader": "Send attribution/billing identifier to the API", + "sendAttributionHeaderAria": "Send Claude Code attribution/billing identifier to the API", + "disableNonessentialTraffic": "Disable telemetry or redundant network requests", + "disableNonessentialTrafficAria": "Disable Claude Code telemetry or redundant network requests" + }, + "dialogs": { + "confirmDeleteProvider": "Delete Provider {providerId}?", + "confirmDeleteProviderDescription": "OpenCode config and auth JSON will be updated together. This action cannot be undone.", + "confirmUninstall": "Uninstall {name}?", + "confirmUninstallDescription": "This removes local installed version. You can reinstall later.", + "customInstallTitle": "Custom install {name}", + "customInstallDescription": "Enter the version to install. This reinstalls and replaces the currently installed version.", + "customInstallVersionLabel": "Version number", + "customInstallInvalid": "Enter a valid version number, e.g. 1.2.3.", + "customInstallSubmit": "Install" + }, + "errors": { + "windowsFileLocked": "{name}'s files are in use by a running session, so Windows can't replace them. Close all {name} sessions and try again.", + "nativeJsonMustBeObject": "Native JSON config must be an object", + "nativeJsonInvalid": "Native JSON config format error: {message}", + "openCodeAuthMustBeObject": "OpenCode auth.json must be a JSON object", + "openCodeAuthInvalid": "OpenCode auth.json format error: {message}", + "authMustBeObject": "auth.json must be a JSON object", + "authInvalid": "auth.json format error: {message}", + "providerIdPattern": "Provider ID only supports letters, numbers, underscore, dot and hyphen", + "providerExists": "Provider {providerId} already exists", + "modelIdPattern": "Model ID only supports letters, numbers, underscore, dot, colon and hyphen", + "modelExists": "Model {modelId} already exists" + }, + "warnings": { + "nativeJsonRecoveredStructured": "Native JSON config is invalid; reset to structured config", + "nativeJsonRecoveredOpenCode": "Native JSON config is invalid; reset to OpenCode structured config", + "openCodeAuthRecovered": "OpenCode auth.json is invalid; reset to default config", + "authRecoveredStructured": "auth.json is invalid; reset to structured config" + }, + "toasts": { + "agentActionCompleted": "{name} {action} completed", + "agentActionFailed": "{name} {action} failed", + "localVersion": "Local version: {version}", + "installCompletedVersionLater": "Install completed, version will update on next check", + "uninstallCompleted": "{name} uninstall completed", + "uninstallFailed": "{name} uninstall failed", + "localVersionRemoved": "Local version removed", + "saveAgentOrderFailed": "Failed to save Agent order", + "saveAgentSwitchFailed": "Failed to save Agent switch", + "saveEnvFailed": "Failed to save environment variables", + "grokSaved": "Grok config saved", + "saveGrokNativeFailed": "Failed to save Grok native config", + "saveGrokApiKeyFailed": "Settings saved, but the API key couldn't be saved", + "cursorSaved": "Cursor config saved", + "saveCursorConfigFailed": "Failed to save Cursor config", + "codexSaved": "Codex config saved", + "saveCodexNativeFailed": "Failed to save Codex native config", + "geminiSaved": "Gemini config saved", + "saveGeminiFailed": "Failed to save Gemini config", + "providerDeleted": "Provider {providerId} deleted", + "providerDeleteFailed": "Failed to delete Provider {providerId}", + "providerSaved": "Provider {providerId} saved", + "saveProviderFailed": "Failed to save Provider {providerId}", + "openCodeConfigSynced": "OpenCode config and auth JSON have been synced.", + "openCodeSaved": "OpenCode config saved", + "saveOpenCodeFailed": "Failed to save OpenCode config", + "openClawSaved": "OpenClaw config saved", + "saveOpenClawFailed": "Failed to save OpenClaw config", + "configSaved": "Config saved", + "configSavedHint": "Existing sessions need to be reopened to take effect", + "saveConfigManagementFailed": "Failed to save config management", + "clineSaved": "Cline config saved", + "saveClineFailed": "Failed to save Cline config", + "hermesSaved": "Hermes config saved", + "saveHermesFailed": "Failed to save Hermes config", + "codeBuddySaved": "CodeBuddy config saved", + "saveCodeBuddyFailed": "Failed to save CodeBuddy config", + "kimiCodeSaved": "Kimi Code config saved", + "saveKimiCodeFailed": "Failed to save Kimi Code config", + "deepseekSaved": "DeepSeek config saved", + "saveDeepSeekFailed": "Failed to save DeepSeek config", + "modelProviderRequired": "Please select a model provider before saving.", + "affectedRunningSessions": "{count, plural, one {# running session needs to reconnect to apply the change} other {# running sessions need to reconnect to apply the change}}", + "providerConnected": "Connected {providerId}", + "connectFailed": "Failed to connect {providerId}", + "providerDisconnected": "Disconnected {providerId}", + "disconnectFailed": "Failed to disconnect {providerId}", + "catalogRefreshed": "Catalog refreshed — {count} providers", + "catalogRefreshFailed": "Failed to refresh catalog", + "piSaved": "Pi config saved", + "savePiFailed": "Failed to save Pi config", + "piRuntimeSaved": "Pi runtime saved", + "savePiRuntimeFailed": "Failed to save Pi runtime", + "piBinaryInstalled": "pi installed", + "piBinaryInstallFailed": "Failed to install pi", + "piBinaryUninstalled": "pi uninstalled", + "piBinaryUninstallFailed": "Failed to uninstall pi", + "savePiTrustFailed": "Failed to save workspace trust" + }, + "version": { + "statusLabel": "Version Status", + "notInstalled": "Not installed", + "remoteLocal": "Remote: {remoteVersion} · Local: {localVersion}", + "localOnly": "Local: {localVersion}", + "localInstalled": "{versionText}. Installed.", + "platformUnsupported": "{versionText}. Current platform does not support this agent.", + "uvxNotReady": "{versionText}. The uv runtime isn't installed — install it from the uv check below to use this agent.", + "clickInstall": "{versionText}. Click Install on the right.", + "localUnrecognized": "{versionText}. Local version is not comparable; try upgrade to overwrite install.", + "upgradeAvailable": "{versionText}. Upgrade available.", + "remoteUnavailable": "{versionText}. Remote version is currently unavailable.", + "latest": "{versionText}. Already latest." + }, + "adapter": { + "label": "ACP adapter", + "badge": "ACP adapter", + "badgeHint": "For this agent Codeg installs an ACP adapter package, not the vendor CLI. The two are independent and share the same config.", + "learnMore": "Learn more", + "missingWithNative": "Found your own {nativeLabel} at {nativePath}. Codeg drives agents over ACP and that CLI does not speak ACP, so Codeg needs a separate adapter package, {adapterPackage}, maintained by the Agent Client Protocol project (originally Zed). It ships its own runtime, never modifies or replaces your {nativeCmd} command, and reads the same {configDir} — your existing sign-in and settings carry over. Install it below.", + "missing": "Codeg drives agents over ACP and the {nativeLabel} does not speak ACP, so Codeg needs a separate adapter package, {adapterPackage}, maintained by the Agent Client Protocol project (originally Zed). It ships its own runtime, so the {nativeCmd} CLI is not required first; if you do have it, the two coexist and share the same {configDir} sign-in and settings. Install it below.", + "readyWithNative": "Adapter {adapterCmd} is installed — that is what Codeg launches, not your own {nativeCmd} at {nativePath}. They are separate packages that coexist, and both read {configDir}, so sign-in and settings are shared.", + "ready": "Adapter {adapterCmd} is installed — that is what Codeg launches. It ships its own runtime, so the {nativeLabel} is not required; install it later and the two coexist, sharing {configDir}." + }, + "cline": { + "configDescription": "Configure Cline API provider and credentials. Settings are saved to ~/.cline/data/." + }, + "opencodePlugins": { + "title": "OpenCode Plugins", + "declared": "Declared Plugins", + "noPlugins": "No plugins declared.", + "status": { + "installed": "Installed", + "missing": "Missing" + }, + "installAll": "Install All Missing", + "pinVersions": "Pin @latest Versions", + "install": "Install", + "uninstall": "Uninstall", + "refresh": "Refresh", + "success": "All plugins installed successfully.", + "failed": "Installation failed" + }, + "pi": { + "configManagement": "Pi Configuration", + "configDescription": "Pi authenticates with your model provider's API key. The key is written to ~/.pi/agent/auth.json and the model selection to settings.json.", + "providerLabel": "Provider", + "modelLabel": "Model", + "thinkingLabel": "Thinking", + "thinking": { + "off": "Off", + "low": "Low", + "medium": "Medium", + "high": "High", + "minimal": "Minimal", + "xhigh": "Extra high" + }, + "apiKeyLabel": "API Key", + "apiKeyHint": "Stored in ~/.pi/agent/auth.json for the selected provider.", + "apiKeySetPlaceholder": "•••••• (saved — leave blank to keep)", + "saveConfig": "Save Pi Config", + "providerModelRequired": "Provider and model are required", + "runtimeTitle": "Runtime", + "runtimeDescription": "Choose which pi binary runs. Use the default, or point at your own pi build.", + "modeDefault": "Default pi", + "modeDefaultHint": "Use the bundled pi-acp adapter with the pi on your PATH. Install pi with: npm install -g @earendil-works/pi-coding-agent", + "modeCustom": "Custom pi", + "modeCustomHint": "Run your own pi build, install, or wrapper.", + "commandLabel": "pi command or path", + "commandHint": "An absolute path, a command name on PATH, or a wrapper script (e.g. a monorepo ./pi-test.sh).", + "commandNotFound": "Command not found", + "validate": "Validate", + "advanced": "Advanced", + "configDirLabel": "Config directory (PI_CODING_AGENT_DIR)", + "sessionDirLabel": "Sessions directory (PI_CODING_AGENT_SESSION_DIR)", + "flagsHint": "Custom pi flags (--approve, -e, …) aren't forwarded by pi-acp — wrap pi in a script and point the command at it.", + "customIncomplete": "Enter a pi command to save", + "saveRuntime": "Save Runtime", + "providerPlaceholder": "Select a provider", + "customProvider": "Custom provider…", + "providerIdLabel": "Provider ID", + "apiProtocolLabel": "API protocol", + "baseUrlLabel": "API endpoint (Base URL)", + "customProviderHint": "Defines a provider in ~/.pi/agent/models.json at your endpoint. Most self-hosted or proxy servers use openai-completions.", + "baseUrlRequired": "API endpoint (Base URL) is required", + "binaryTitle": "pi binary (pi-coding-agent)", + "binaryDescription": "pi-acp runs this pi binary. Install it here, or point pi-acp at your own build below.", + "binaryInstalled": "Installed", + "binaryMissing": "Not installed", + "binaryChecking": "Checking…", + "installBinary": "Install pi", + "installing": "Installing…", + "recheck": "Recheck", + "configDirSkillsNote": "With a custom config directory, the Skills, Experts, and Office tools managed in Settings won't apply to this pi — manage its skills in that folder directly.", + "projectTrustTitle": "Project trust", + "projectTrustDescription": "Folders you allowed pi to load project files from. A trusted folder lets that repository's .pi/extensions run code when pi starts, applies to every folder inside it, and is also used when you run pi in a terminal.", + "projectTrustLoading": "Loading…", + "projectTrustEmpty": "No folders decided yet.", + "projectTrustTrusted": "Trusted", + "projectTrustDenied": "Not trusted", + "projectTrustRevoke": "Revoke", + "reasoningTitle": "Reasoning", + "reasoningEnableLabel": "Enable", + "reasoningDescription": "pi only sends a reasoning effort for a model that declares it — an undeclared model has every level clamped to Off, so the composer's picker springs back the moment you touch it. Written to this model's entry in models.json.", + "levelsLabel": "Available levels", + "levelsHint": "These become the rows in the composer's reasoning picker. Pick the ones your endpoint accepts; pi rejects any level that isn't listed here.", + "levelsEmptyError": "Pick at least one level — with none, pi falls back to Off.", + "wireValuesTitle": "Advanced: values sent to the provider", + "wireValuesHint": "Leave blank to send the level name as-is. Set one when your endpoint expects something else — Google-style backends want LOW / HIGH.", + "defaultLevelUnlisted": "This level isn't in the available list above — pi would clamp it." + }, + "addCustomAgent": "Add custom agent", + "addCustomAgentHint": "Register any ACP-compatible agent. Pick one from the public ACP registry, or paste its registry information.", + "customAgentFromRegistry": "ACP registry", + "customAgentManual": "Manual", + "customAgentSearchPlaceholder": "Search agents…", + "customAgentLoadingCatalog": "Loading the ACP registry…", + "customAgentRetry": "Retry", + "customAgentNoResults": "No matching agents", + "customAgentAdd": "Add", + "customAgentAlreadyAdded": "Added", + "customAgentUnsupportedPlatform": "No build available for this platform", + "customAgentAdded": "Added {name}", + "customAgentIdLabel": "Registry ID", + "customAgentNameLabel": "Display name", + "customAgentVersionLabel": "Version", + "customAgentSpecLabel": "Distribution (JSON)", + "customAgentSpecHint": "Same shape as a registry entry's distribution object: npx, uvx and binary channels, or paste a whole registry entry. For npx/uvx, cmd is the executable the package installs — derived from the package name when omitted, so set it when the two differ. binary is keyed by platform (this machine: {platform}); its cmd is the launch path inside the archive, and sha256 optionally verifies the download.", + "customAgentTemplateLabel": "Templates", + "customAgentKindLabel": "Launch via", + "customAgentInvalidJson": "Not valid JSON", + "customAgentNoDistribution": "No npx, uvx, or binary distribution found", + "customAgentCancel": "Cancel", + "customAgentSave": "Add agent", + "customAgentSaveChanges": "Save changes", + "customAgentEdit": "Edit agent", + "customAgentEditHint": "Update the name, icon, distribution and skills declarations. The agent ID cannot be changed.", + "customAgentEditNotFound": "Custom agent {id} was not found", + "customAgentSaved": "Saved {name}", + "customAgentVersionProbeLabel": "Version probe command (optional)", + "customAgentVersionProbeHint": "Command that prints the locally installed version. Left empty, codeg runs the agent command with --version.", + "customAgentRemove": "Remove agent", + "customAgentRemoveHint": "Deletes the agent definition. Existing conversations keep their history; the agent just can no longer be launched.", + "customAgentIconLabel": "Icon (optional)", + "customAgentIconUpload": "Upload", + "customAgentIconReplace": "Replace", + "customAgentIconClear": "Remove icon", + "customAgentIconHint": "Stored with the agent, so it works offline. Without one, a colored initial is used.", + "customAgentSkillsLabel": "Skills (shared .agents/skills)", + "customAgentSkillsHint": "Declares that this agent reads the shared .agents/skills store — its global and project directories — and adds it to every skills matrix. Skills linked there are visible to every agent that reads the shared store.", + "customAgentSkillsDirLabel": "Dedicated skills directory", + "customAgentSkillsDirHint": "Absolute path of a directory this agent loads skills from — its own store, in addition to (or instead of) the shared one. ~ expands to your home directory; linked skills are placed here first.", + "customAgentMcpLabel": "MCP support", + "customAgentMcpHint": "Sends codeg's built-in MCP companion to this agent when a session starts — the channel behind delegation, live feedback and task tools. Turn it off for an agent that rejects MCP servers and fails to connect; the change applies to the next connection.", + "customAgentIconNotAnImage": "Pick an image file.", + "customAgentIconTooLarge": "The icon must be smaller than {limit} KB.", + "customAgentIconReadFailed": "Could not read that image.", + "customAgentRemoveConfirm": "Remove {name}? Existing conversations stay, but the agent can no longer be launched.", + "customAgentRemoveWithData": "Also delete its recorded conversation history", + "customAgentRemoved": "Removed {name}", + "customAgentBadge": "Custom", + "customAgentNotLaunchable": "This agent cannot launch here: {reason}" + }, + "SettingsPages": { + "agentsLoading": "Loading agent settings...", + "skillPacksLoading": "Loading skill packs…" + }, + "GeneralSettings": { + "loading": "Loading...", + "sectionTitle": "General", + "sectionDescription": "Centralized preferences for the default terminal, rendering acceleration, and multi-agent delegation.", + "terminalTitle": "Default Terminal", + "terminalDescription": "Choose the shell used when opening new terminal tabs from the terminal bar or file tree. Agents also use it when they ask codeg to run a whole command line for them.", + "terminalSystemDefault": "System default", + "terminalPowerShell7": "PowerShell 7 (pwsh)", + "terminalWindowsPowerShell": "Windows PowerShell", + "terminalCmd": "Command Prompt (cmd)", + "terminalSaveFailed": "Failed to save terminal settings: {message}", + "terminalShellCustom": "Custom path", + "terminalShellCustomPath": "Shell path", + "terminalShellCustomPlaceholder": "/usr/local/bin/fish", + "terminalShellCustomSave": "Save", + "terminalShellCustomHint": "Provide an absolute path or a name resolvable on PATH.", + "terminalShellNotInstalled": "not installed", + "terminalShellNotFoundWarning": "This path doesn't exist on this host.", + "terminalCurrentShell": "Currently using: {path}", + "renderingDescription": "Disable hardware acceleration if the app shows a black screen or rendering glitches (common on certain AMD GPUs or Intel integrated GPUs). Only takes effect on the Windows desktop build.", + "disableHardwareAcceleration": "Disable hardware acceleration", + "renderingSaveFailed": "Failed to save rendering settings: {message}", + "restartRequired": "Saved. Restart the app for the change to take effect.", + "restartNow": "Restart now", + "restartFailed": "Failed to restart: {message}", + "loadFailed": "Load failed: {message}" + }, + "LoginPage": { + "documentTitle": "Login - codeg", + "brand": "Codeg", + "subtitle": "Enter your access token to connect to the desktop app", + "tokenPlaceholder": "Access Token", + "connect": "Connect", + "connecting": "Connecting...", + "helpText": "Find your token in the desktop app under Settings → Web Service", + "invalidToken": "Invalid token. Please check and try again.", + "connectionFailed": "Connection failed (HTTP {status})", + "networkError": "Unable to connect to the server" + }, + "CommitPage": { + "title": "Commit", + "invalidFolderId": "Invalid folder ID", + "loadingRepo": "Loading repository..." + }, + "MergePage": { + "title": "Resolve Conflicts", + "invalidFolderId": "Invalid folder ID", + "loadingRepo": "Loading repository...", + "localVersion": "Local (Ours)", + "result": "Result", + "remoteVersion": "Remote (Theirs)", + "acceptLocal": "Accept Local", + "acceptRemote": "Accept Remote", + "markResolved": "Mark Resolved", + "abortMerge": "Abort", + "completeMerge": "Complete Merge", + "unresolvedConflicts": "There are still unresolved conflict markers in this file", + "fileResolved": "File resolved successfully", + "allResolved": "All conflicts resolved", + "conflictFiles": "Conflict Files", + "loadingFile": "Loading file...", + "preparingMerge": "Preparing merge...", + "selectFile": "Select a file to resolve", + "noConflicts": "No conflict files", + "skipFile": "Skip", + "abortSuccess": "Operation aborted", + "applyAllNonConflicting": "Apply All Non-Conflicting", + "applyLeftNonConflicting": "Apply Local", + "applyRightNonConflicting": "Apply Remote" + }, + "ImportSessions": { + "title": "Import Local Sessions", + "scanningTitle": "Scanning local agent sessions…", + "scanningHint": "Walking each agent's local session store. Large histories can take a moment. Sessions you already imported are refreshed along the way.", + "scanFailed": "Scan failed", + "retry": "Retry", + "rescan": "Rescan", + "empty": "No local sessions found", + "emptyHint": "No agent session stores were found on this machine.", + "noMatches": "No sessions match the current filters", + "searchPlaceholder": "Search title or path…", + "allAgents": "All agents", + "onlyImportable": "Importable only", + "selectAll": "Select all", + "clearSelection": "Clear", + "expandAll": "Expand all", + "collapseAll": "Collapse all", + "summaryCounts": "{total} sessions · {importable} importable · {folders} folders", + "noFolderSkipped": "{count} without a project folder skipped", + "folderNew": "New", + "folderCounts": "{importable}/{total} importable", + "toggleFolderAria": "Select all importable sessions in {name}", + "toggleSessionAria": "Select session {title}", + "statusImported": "Imported", + "statusDeleted": "Deleted", + "untitled": "Untitled session", + "messageCount": "{count} msgs", + "selectedCount": "{count} selected", + "importSelected": "Import selected", + "importing": "Importing…", + "close": "Close", + "doneTitle": "Import finished", + "doneImported": "Imported", + "doneUpdated": "Refreshed", + "doneSkipped": "Skipped", + "doneCreatedFolders": "Folders created", + "doneNotFound": "Not found", + "doneFailed": "Failed", + "continueImport": "Continue importing", + "toasts": { + "importFailed": "Import failed: {message}" + } + }, + "Folder": { + "workspaceStatus": { + "degradedTitle": "Live updates unavailable", + "degradedHint": "Watcher failed to start (e.g. permission denied). Refresh manually to see changes.", + "retry": "Retry", + "retrying": "Retrying..." + }, + "common": { + "all": "All", + "cancel": "Cancel", + "close": "Close", + "closeOthers": "Close Others", + "closeAll": "Close All", + "confirm": "Confirm", + "save": "Save", + "delete": "Delete", + "rename": "Rename", + "loading": "Loading...", + "refresh": "Refresh", + "refreshing": "Refreshing...", + "create": "Create", + "createAndSwitch": "Create and Switch", + "openFile": "Open File", + "viewDiff": "View Diff", + "push": "Push..." + }, + "statusLabels": { + "in_progress": "In Progress", + "pending_review": "Review", + "completed": "Completed", + "cancelled": "Cancelled" + }, + "sidebar": { + "title": "Conversations", + "locateActiveConversation": "Locate Active Conversation", + "expandAllGroups": "Expand All Groups", + "collapseAllGroups": "Collapse All Groups", + "newConversation": "New Conversation", + "newConversationShort": "New", + "newChat": "New chat", + "search": "Search", + "noConversationsFound": "No conversations found.", + "importLocalSessions": "Import local sessions", + "importing": "Importing...", + "error": "Error: {message}", + "completeAllSessions": "Complete all sessions", + "completeAllReviewTitle": "Complete all review sessions?", + "completeAllReviewDescription": "This will mark all {count, plural, one {# session} other {# sessions}} in Review as completed.", + "completing": "Completing...", + "toasts": { + "importedSessions": "Imported {imported, plural, one {# session} other {# sessions}}, skipped {skipped}", + "importedAndUpdated": "Imported {imported, plural, one {# session} other {# sessions}}, updated {updated, plural, one {# title} other {# titles}}, skipped {skipped}", + "updatedTitles": "Updated {updated, plural, one {# title} other {# titles}}, skipped {skipped}", + "noNewSessionsFound": "No new sessions found (skipped {skipped})", + "importFailed": "Import failed: {message}", + "reviewCompleted": "Marked {count, plural, one {# review session} other {# review sessions}} as completed", + "completeReviewFailed": "Failed to complete review sessions: {message}", + "folderOpened": "Opened folder {name}", + "folderRemoved": "Removed folder {name}", + "openFolderFailed": "Failed to open folder", + "removeFolderFailed": "Failed to remove folder: {message}", + "reorderFoldersFailed": "Failed to reorder folders: {message}", + "changeFolderColorFailed": "Failed to change folder color: {message}", + "setFolderAliasFailed": "Failed to set alias: {message}", + "changeFolderDefaultAgentFailed": "Failed to set default agent: {message}" + }, + "statsLabel": "{folders} folders · {convos} conversations", + "reorderHandle": "Drag to reorder", + "openFolder": "Open Folder", + "searchPlaceholder": "Search conversations...", + "viewOptions": "View options", + "showCompleted": "Show completed conversations", + "showWorktrees": "Show worktree folders", + "showRecent": "Show Recent group", + "moreOptions": "More options", + "sortBy": "Sort by", + "sortByCreatedAt": "Created time", + "sortByUpdatedAt": "Updated time", + "sectionOrder": "Section order", + "sectionOrderMoveUp": "Move up", + "sectionOrderMoveDown": "Move down", + "sectionOrderItemLabel": "{name} — position {position} of {total}", + "statusRunningBadge": "Running", + "runningCountBadge": "{count, plural, one {# session running} other {# sessions running}}", + "statusCancelledBadge": "Cancelled", + "worktreeRemovedBadge": "Source worktree removed", + "conversationCountUnit": "{count, plural, one {# conversation} other {# conversations}}", + "emptyFolderHint": "No conversations", + "noMatchingConversations": "No matching conversations", + "noUnfinishedConversations": "No unfinished conversations. Enable \"Show completed\" from the top-right menu.", + "removeFolderConfirmTitle": "Remove folder from workspace?", + "removeFolderConfirmDescription": "Remove \"{name}\" from the workspace? Its tabs and terminals will close.", + "folderHeaderMenu": { + "manageConversations": "Manage conversations…", + "manageLinks": "Linked folders", + "changeColor": "Change color", + "useThemeColor": "Use app theme", + "setDefaultAgent": "Set default agent", + "defaultAgentNone": "No default (use global)", + "agentUnavailableSuffix": "(unavailable)", + "loadingAgents": "Loading agents…", + "setAlias": "Set alias…", + "setAliasTitle": "Set folder alias", + "setAliasPlaceholder": "Enter an alias (leave empty to clear)", + "setAliasSave": "Save", + "setAliasCancel": "Cancel", + "removeFromWorkspace": "Remove from workspace" + }, + "manageConversations": { + "title": "Manage conversations", + "searchPlaceholder": "Search by title…", + "agentFilterAll": "All agents", + "statusFilterAll": "All statuses", + "folderFilterAll": "All folders", + "branchFilterAll": "All branches", + "branchNone": "No branch", + "branchSearchPlaceholder": "Search branches…", + "noMatchingBranches": "No matching branches", + "selectAllVisible": "Select all", + "deselectAll": "Deselect all", + "selectedCount": "{count} selected", + "matchedCount": "{count} matched", + "untitledConversation": "Untitled conversation", + "setStatus": "Set status…", + "deleteSelected": "Delete", + "noConversations": "No conversations in this folder.", + "noConversationsWorkspace": "No conversations in the workspace.", + "noMatchingConversations": "No conversations match the filters.", + "confirmDeleteTitle": "Delete {count} conversation(s)?", + "confirmDeleteDescription": "This action cannot be undone.", + "toastDeleted": "Deleted {count} conversation(s)", + "toastStatusUpdated": "Updated status for {count} conversation(s)", + "toastOpFailed": "Operation failed: {message}" + }, + "sectionPinned": "Pinned", + "sectionFolders": "Folders", + "sectionChats": "Chat", + "sectionRecent": "Recent", + "noChats": "No chats", + "noRecent": "No recent conversations", + "showMoreRecent": "Show more ({count})", + "noFolders": "No folders open", + "newChatAction": "New chat", + "automations": "Automations", + "tasks": "To-dos", + "loadingSubsessions": "Loading sub-conversations…" + }, + "conversation": { + "reloadFailed": "Failed to reload conversation: {message}", + "reloaded": "Conversation reloaded", + "reload": "Reload", + "activeConversationIndicator": "Active conversation", + "newConversation": "New Conversation", + "closeConversation": "Close Conversation", + "copyText": "Copy Text", + "copyTextSuccess": "Copied", + "copyTextFailed": "Copy failed", + "forkSession": "Fork Session", + "forkSessionSuccess": "Session forked successfully", + "forkSessionFailed": "Failed to fork session: {error}", + "exportConversation": "Export Conversation", + "exportImage": "Image", + "exportMarkdown": "Markdown", + "exportHtml": "HTML", + "exportSuccess": "Conversation exported", + "exportFailed": "Export failed", + "exportImageTooLong": "Conversation is too long to export as image", + "exportLabels": { + "untitledConversation": "Untitled Conversation", + "agent": "Agent", + "model": "Model", + "status": "Status", + "started": "Started", + "updated": "Updated", + "tokens": "Token Stats", + "duration": "Duration", + "inputTokens": "Input", + "outputTokens": "Output", + "cacheRead": "Cache Read", + "cacheWrite": "Cache Write", + "user": "User", + "assistant": "Assistant", + "system": "System", + "toolResult": "Result", + "toolError": "Error" + }, + "moreActions": "More actions" + }, + "sessionDetails": { + "menuLabel": "Session Details", + "noActiveSession": "No active session", + "title": "Session Details", + "subtitle": "Session metadata and token usage", + "fieldTitle": "Title", + "untitled": "Untitled conversation", + "sessionId": "Session ID", + "externalId": "Extension ID", + "agent": "Agent", + "model": "Model", + "status": "Status", + "gitBranch": "Git Branch", + "parentId": "Parent Session", + "tokensHeading": "Token Usage", + "totalTokens": "Total", + "inputTokens": "Input", + "outputTokens": "Output", + "cacheWrite": "Cache Write", + "cacheRead": "Cache Read", + "contextWindow": "Context Window", + "duration": "Duration", + "loadingStats": "Loading token usage…", + "loadFailed": "Failed to load token usage", + "noStats": "No usage recorded", + "timestampsHeading": "Timestamps", + "createdAt": "Created", + "updatedAt": "Updated", + "none": "—", + "copyField": "Copy {field}", + "copiedField": "Copied {field}" + }, + "conversationCard": { + "untitledConversation": "Untitled conversation", + "newConversation": "New Conversation", + "rename": "Rename", + "status": "Status", + "delete": "Delete", + "importLocalSessions": "Import local sessions", + "importing": "Importing...", + "renameConversation": "Rename conversation", + "deleteConversationTitle": "Delete conversation?", + "deleteConversationDescription": "This will delete \"{title}\". This action cannot be undone.", + "cancel": "Cancel", + "save": "Save", + "pin": "Pin", + "unpin": "Unpin", + "markCompleted": "Mark as completed", + "reopen": "Reopen", + "expandSubsessions": "Expand sub-conversations", + "collapseSubsessions": "Collapse sub-conversations" + }, + "search": { + "dialogTitle": "Search", + "dialogTitleWithFolder": "Search — {name}", + "tabConversations": "Conversations", + "tabFiles": "Files", + "placeholder": "Search conversations...", + "filePlaceholder": "Search files or directories...", + "allAgents": "All", + "searching": "Searching...", + "typeToSearch": "Type to search conversations", + "typeToSearchFiles": "Type to search files or directories", + "noResults": "No results found.", + "untitledConversation": "Untitled conversation" + }, + "folderTitleBar": { + "showSidebar": "Show Sidebar", + "hideSidebar": "Hide Sidebar", + "toggleTerminal": "Toggle Terminal", + "toggleAuxPanel": "Toggle Auxiliary Panel", + "search": "Search", + "openSettings": "Open Settings", + "backToConversations": "Back to Conversations", + "withShortcut": "{label} ({shortcut})" + }, + "statusBar": { + "connection": { + "connected": "Connected", + "connecting": "Connecting...", + "prompting": "Responding...", + "error": "Connection error", + "disconnected": "Disconnected", + "tooltip": "{agent} - {status}", + "tooltipError": "{agent} - {error}", + "title": "Agent connection", + "triggerAria": "Agent connection: {status}", + "workingDir": "Working directory", + "sessionId": "Session ID", + "viewerNote": "Attached to a session another client owns — reconnecting only re-attaches this view.", + "reconnectInterrupts": "Reconnecting restarts the agent and interrupts the work in progress.", + "reconnect": "Reconnect", + "reconnecting": "Reconnecting...", + "reconnectUnavailable": "Nothing to reconnect to yet." + }, + "tasks": { + "title": "Tasks" + }, + "alerts": { + "title": "Alerts", + "empty": "No alerts", + "details": "Details" + }, + "stats": { + "conversations": "{count} conversations", + "openUsage": "View session stats & token usage" + }, + "tokens": { + "contextWindowUsageAria": "Context window usage", + "contextWindow": "Context Window", + "usedMax": "Used / Max", + "tokenUsage": "Token Usage", + "input": "Input", + "output": "Output", + "cacheRead": "Cache Read", + "cacheWrite": "Cache Write", + "total": "Total" + } + }, + "auxPanel": { + "tabs": { + "files": "Files", + "changes": "Changes", + "commits": "Commits" + }, + "noFolderTitle": "No folder open", + "noFolderHint": "Open a folder to see its contents here" + }, + "windowControls": { + "minimizeWindow": "Minimize window", + "minimize": "Minimize", + "maximizeWindow": "Maximize window", + "maximize": "Maximize", + "restoreWindow": "Restore window", + "restore": "Restore", + "closeWindow": "Close window", + "close": "Close" + }, + "tabs": { + "closeConversationTab": "Close conversation tab", + "close": "Close", + "closeOthers": "Close Others", + "splitRight": "Split Right", + "splitDown": "Split Down", + "splitAndMoveRight": "Split and Move Right", + "splitAndMoveDown": "Split and Move Down", + "moveToOppositeGroup": "Move to Opposite Group", + "moveToGroup": "Move to Group", + "groupLabel": "Group {index}", + "changeSplitterOrientation": "Change Splitter Orientation", + "unsplit": "Unsplit", + "unsplitAll": "Unsplit All", + "closeAll": "Close All", + "tileDisplay": "Tile Display", + "untileDisplay": "Exit Tile" + }, + "fileWorkspace": { + "files": "Files", + "closeFileTab": "Close file tab", + "close": "Close", + "closeOthers": "Close Others", + "closeAll": "Close All", + "preview": "Preview", + "editSource": "Edit Source", + "maximize": "Maximize", + "restore": "Restore", + "emptyDirectory": "Empty folder" + }, + "terminal": { + "rename": "Rename", + "close": "Close", + "closeOthers": "Close Others", + "closeAll": "Close All", + "hideTerminal": "Hide Terminal ({shortcut})", + "openFolderFirst": "Open a folder first" + }, + "workspaceDialog": { + "title": "Open Folder", + "manageTitle": "Linked Folders", + "addTargetsTitle": "Add Folders to Link", + "pickRootDescription": "Pick the main folder for this workspace.", + "linksDescription": "Link other folders in as subdirectories so agents can work across all of them from this one workspace.", + "addTargetsDescription": "Select one or more folders. Each becomes a subdirectory of the workspace.", + "useSystemPicker": "System picker", + "next": "Next", + "back": "Back", + "done": "Done", + "change": "Change", + "addFolders": "Add folders", + "addSelected": "Add", + "addSelectedCount": "Add {count}", + "createCount": "Link {count} folder(s)", + "discardPending": "Discard", + "noLinks": "No linked folders yet.", + "gitExclude": "Keep links out of git status", + "rename": "Rename", + "unlink": "Remove link", + "repair": "Recreate link", + "saveName": "Save", + "cancelRename": "Cancel", + "removePending": "Remove", + "willAppearAs": "Appears as {name} in the workspace", + "renamedForDuplicate": "Renamed — {base} is already used by another link", + "renamedForExistingEntry": "Renamed — {base} already exists in this folder", + "partiallyCreated": "Only {count} folder(s) could be linked", + "openFailed": "Failed to open the folder", + "previewFailed": "Failed to check the selected folders", + "createFailed": "Failed to link the folders", + "renameFailed": "Failed to rename the link", + "removeFailed": "Failed to remove the link", + "repairFailed": "Failed to recreate the link", + "status": { + "ok": "Linked", + "missing": "The link is gone from this folder", + "conflicted": "Another entry now uses this name", + "broken": "The linked folder no longer exists" + }, + "nameIssue": { + "empty": "Enter a name", + "illegalChars": "Cannot contain / \\ : * ? \" < > |", + "tooLong": "Name is too long", + "reserved": "This name is reserved by Windows", + "duplicate": "This name is already used" + }, + "rejection": { + "not_found": "This folder could not be found", + "not_a_directory": "This path is not a folder", + "same_as_root": "This is the workspace folder itself", + "ancestor_of_root": "This folder contains the workspace", + "inside_root": "Already inside the workspace", + "already_linked": "Already linked", + "name_unavailable": "No free name is left for this folder", + "alreadyLinkedAs": "Already linked as {name}" + } + }, + "folderNameDropdown": { + "fallbackFolderName": "Folder", + "openFolder": "Open Folder", + "cloneRepository": "Clone Repository", + "projectBoot": "Project Boot", + "opened": "Opened", + "recentOpen": "Recently Opened" + }, + "fileWorkspacePanel": { + "addSelectionToChat": "Add Selection to Chat", + "addToChat": "Add to Chat", + "addSelectionToChatDone": "Added {label} to the conversation", + "addFileToChat": "Add File to Chat", + "toggleWordWrap": "Toggle Word Wrap", + "addFileToChatDone": "Added {label} to the conversation", + "viewDiff": "View Diff", + "openFile": "Open File", + "fileCount": "{count, plural, one {# file} other {# files}}", + "openFileOrDiff": "Open a file or diff from the right panel", + "disk": "Disk", + "head": "HEAD", + "unsaved": "Unsaved", + "workingTree": "Working Tree", + "loading": "Loading...", + "compareWithBranch": "{path} · compare with {branch}", + "hunkCount": "{count, plural, one {# hunk} other {# hunks}}", + "prev": "Prev", + "next": "Next", + "jumpToLine": "Jump to line {line}", + "noParsedDiffSections": "No parsed diff sections", + "loadingEditor": "Loading editor...", + "imageZoomIn": "Zoom in", + "imageZoomOut": "Zoom out", + "imageZoomReset": "Reset zoom", + "htmlPreviewTitle": "HTML preview", + "htmlPreviewTrust": "Enable scripts", + "htmlPreviewTrustHint": "Run this file's scripts and allow network access. Enable only for files you trust.", + "officePreviewTitle": "Office document preview", + "officeFullRender": "Full render", + "officeFullRenderHint": "Render Morph animations, 3D and math (runs the slide's own scripts)", + "officeNotInstalled": "OfficeCLI is not installed", + "officeNotInstalledHint": "Install OfficeCLI under Settings → Office Tools to preview Word, Excel, and PowerPoint files.", + "officeOpenSettings": "Open Settings", + "officeWatchFailed": "Couldn't start the live preview", + "officeWatchRetry": "Retry", + "officeServerInstallHint": "OfficeCLI must be installed on the server host. Run this command there, then retry:", + "officeRemoteDesktopUnsupported": "Live preview isn't available in a remote-desktop window. Open this workspace in the server's web UI to preview Office files." + }, + "branchDropdown": { + "toasts": { + "commitCodeCompleted": "Code commit completed", + "pushCodeCompleted": "Code push completed", + "committedFiles": "Committed {count, plural, one {# file} other {# files}}", + "taskCompleted": "{label} completed", + "taskFailed": "{label} failed", + "mergeNoNewCommits": "{branchName} has no new commits", + "mergedCommits": "Merged {count, plural, one {# commit} other {# commits}}", + "allFilesUpToDate": "All files are up to date", + "updatedFiles": "Updated {count, plural, one {# file} other {# files}}", + "openCommitWindowFailed": "Failed to open commit window", + "openPushWindowFailed": "Failed to open push window", + "upstreamSet": "Upstream branch has been set", + "upstreamSetAndPushed": "Upstream branch set and pushed {count, plural, one {# commit} other {# commits}}", + "noCommitsToPush": "No commits to push", + "pushedCommits": "Pushed {count, plural, one {# commit} other {# commits}}", + "switchedToFolder": "Switched to {name}", + "switchFailed": "Failed to switch branch", + "openStashWindowFailed": "Failed to open stash window" + }, + "tasks": { + "newBranch": "Create branch {name}", + "newWorktree": "Create worktree {name}", + "checkoutTo": "Checkout to {branchName}", + "mergeBranch": "Merge {branchName}", + "rebaseTo": "Rebase to {branchName}", + "deleteRemoteBranch": "Delete remote branch {branchName}", + "initGitRepo": "Initialize Git repository", + "pullCode": "Pull code", + "fetchInfo": "Fetch info", + "pushCode": "Push code", + "stashChanges": "Stash changes", + "stashPop": "Pop stash", + "deleteBranch": "Delete branch {branchName}", + "removeWorktree": "Delete worktree for {branchName}", + "removeWorktreeAndBranch": "Delete worktree and branch {branchName}", + "updateBranch": "Update branch {branchName}" + }, + "confirm": { + "mergeTitle": "Merge branch", + "rebaseTitle": "Rebase branch", + "mergeDescription": "Merge {branchName} into current branch {currentBranch}?", + "rebaseDescription": "Rebase current branch {currentBranch} onto {branchName}?", + "deleteRemoteTitle": "Delete Remote Branch", + "deleteRemoteDescription": "Delete remote branch {branchName}? This will remove it from the remote repository and cannot be undone.", + "deleteTitle": "Delete branch", + "deleteDescription": "Delete branch {branchName}? This action cannot be undone.", + "forceDeleteTitle": "Force Delete Branch", + "forceDeleteDescription": "Branch {branchName} is not fully merged. Are you sure you want to force delete it? This action cannot be undone.", + "deleteWorktreeTitle": "Delete worktree", + "deleteWorktreeDescription": "Delete the worktree directory that has {branchName} checked out? The branch and its commits are kept.", + "forceDeleteWorktreeTitle": "Force delete worktree", + "forceDeleteWorktreeDescription": "The worktree for {branchName} has uncommitted or untracked files. Delete it anyway? Those changes cannot be recovered.", + "deleteWorktreeAndBranchTitle": "Delete worktree and branch", + "deleteWorktreeAndBranchDescription": "Delete the worktree for {branchName}, the branch itself, and its workspace folder? Its sessions move to the repository folder. This action cannot be undone.", + "forceDeleteWorktreeAndBranchTitle": "Force delete worktree and branch", + "forceDeleteWorktreeAndBranchDescription": "The worktree for {branchName} has uncommitted files, or the branch is not fully merged. Delete both anyway? This action cannot be undone." + }, + "current": "Current", + "switchToBranch": "Switch to this branch", + "mergeBranchIntoCurrent": "Merge {branchName} into {currentBranch}", + "rebaseCurrentToBranch": "Rebase {currentBranch} onto {branchName}", + "noBranch": "No branch", + "detachedHead": "Detached HEAD at {sha}", + "initGitRepo": "Initialize Git repository", + "pullCode": "Pull code", + "fetchRemoteBranches": "Fetch remote branches", + "openCommitWindow": "Commit code...", + "pushCode": "Push...", + "pushBranch": "Push", + "newBranch": "New branch...", + "newWorktree": "New worktree...", + "stashChanges": "Stash changes...", + "stashPop": "Unstash...", + "manageRemotes": "Manage Remotes...", + "localBranches": "Local branches ({count, plural, one {#} other {#}})", + "noLocalBranches": "No local branches", + "remoteBranches": "Remote branches ({count, plural, one {#} other {#}})", + "noRemoteBranches": "No remote branches", + "dialogs": { + "newBranchTitle": "New branch", + "newBranchDescription": "Create a new branch from current branch {branch}", + "branchNamePlaceholder": "Branch name", + "newWorktreeTitle": "New worktree", + "newWorktreeDescription": "Create a new worktree from current branch {branch}", + "branchNameLabel": "Branch name", + "worktreePathLabel": "Worktree path", + "worktreePathPlaceholder": "Worktree path", + "manageRemotesTitle": "Manage Remotes", + "manageRemotesEmpty": "No remotes configured", + "remoteNamePlaceholder": "Remote name", + "remoteUrlPlaceholder": "Remote URL", + "addRemote": "Add", + "savingRemotes": "Saving..." + }, + "conflict": { + "title": "Merge Conflicts", + "description": "The following files have conflicts that need to be resolved:", + "abort": "Abort Merge", + "openMergeTool": "Open Merge Tool", + "completeMerge": "Complete Merge", + "abortSuccess": "Merge aborted successfully", + "completeSuccess": "Merge completed successfully" + }, + "stashDialog": { + "title": "Stash Changes", + "description": "Save your current changes to a stash", + "messageLabel": "Message", + "messagePlaceholder": "Stash message (optional)", + "keepIndex": "Keep index (staged changes remain staged)", + "cancel": "Cancel", + "stash": "Stash", + "success": "Changes stashed successfully", + "error": "Failed to stash changes" + }, + "unstashDialog": { + "title": "Unstash Changes", + "noStashes": "No stashes found", + "selectFile": "Select a file to view diff", + "viewDiff": "View Diff", + "original": "Original", + "modified": "Modified", + "apply": "Apply", + "drop": "Drop", + "applySuccess": "Stash applied successfully", + "dropSuccess": "Stash dropped", + "confirmApply": "Apply stash {ref} to working directory?", + "cancel": "Cancel" + }, + "deleteBranch": "Delete branch", + "deleteWorktree": "Delete worktree", + "deleteWorktreeAndBranch": "Delete worktree and branch", + "searchPlaceholder": "Search branches and actions", + "searchAriaLabel": "Search branches and actions", + "branchListLabel": "Branches and actions", + "noMatches": "No matches" + }, + "commitDialog": { + "toasts": { + "commitCompleted": "Code commit completed", + "pushFailed": "Push failed", + "committedFiles": "Committed {count, plural, one {# file} other {# files}}", + "addedToVcs": "Added to VCS", + "addToVcsFailed": "Failed to add to VCS", + "fileDeleted": "File deleted", + "deleteFailed": "Delete failed", + "fileRolledBack": "File rolled back", + "rollbackFailed": "Rollback failed", + "dirRolledBack": "Directory rolled back", + "dirDeleted": "Directory deleted" + }, + "confirm": { + "deleteTitle": "Confirm deletion", + "deleteDescription": "Delete file \"{file}\"? This action cannot be undone.", + "rollbackTitle": "Confirm rollback", + "rollbackDescription": "Rollback file \"{file}\" to HEAD? Unsaved changes will be lost.", + "rollbackDirDescription": "Rollback directory \"{dir}\" to HEAD? Unsaved changes will be lost.", + "deleteDirDescription": "Delete directory \"{dir}\"? This action cannot be undone." + }, + "actions": { + "select": "Select", + "unselect": "Unselect", + "rollback": "Rollback", + "addToVcs": "Add to VCS" + }, + "aria": { + "selectFile": "{action} {path}", + "unselectAllFiles": "Unselect all files", + "selectAllFiles": "Select all files", + "unselectTracked": "Unselect tracked changes", + "selectTracked": "Select tracked changes", + "unselectUntracked": "Unselect untracked files", + "selectUntracked": "Select untracked files" + }, + "loading": "Loading...", + "selectionCount": "{selected} / {total} files", + "emptyFiles": "No changed files", + "trackedChanges": "Tracked changes ({count})", + "untrackedFiles": "Untracked files ({count})", + "commitMessage": "Commit message", + "commitMessagePlaceholder": "Enter commit message...", + "commitButton": "Commit ({count})", + "commitAndPushButton": "Commit and Push ({count})", + "head": "HEAD", + "workingTree": "Working Tree", + "clickFileToDiff": "Click a file name to view diff", + "loadingDiff": "Loading diff..." + }, + "pushWindow": { + "title": "Push Code", + "noUnpushedCommits": "No unpushed commits", + "noRemoteConfigured": "No Git remote configured\nAdd a remote in Manage Remotes", + "newBranchNoPushedCommits": "New branch — push to create remote tracking branch", + "unpushed": "Unpushed", + "selectFileToViewDiff": "Select a file to view diff", + "before": "Before", + "after": "After", + "push": "Push", + "toasts": { + "pushSuccess": "Push successful", + "pushFailed": "Push failed", + "upstreamSet": "Upstream branch has been set", + "upstreamSetAndPushed": "Upstream branch set and pushed {count, plural, one {# commit} other {# commits}}", + "noCommitsToPush": "No commits to push", + "pushedCommits": "Pushed {count, plural, one {# commit} other {# commits}}" + } + }, + "gitLogTab": { + "filesTitle": "Files", + "expandAllFiles": "Expand all files", + "collapseAllFiles": "Collapse all files", + "workspace": "workspace", + "retry": "Retry", + "noCommitsFound": "No commits found", + "notAGitRepoTitle": "Not a Git repository", + "notAGitRepoHint": "Initialize Git from the branch menu above, or open a folder that is already tracked.", + "hash": "Hash", + "copyHash": "Copy hash", + "copyMessage": "Copy message", + "showMore": "Show more", + "showLess": "Show less", + "author": "Author", + "noFileChangeDetails": "No file change details available.", + "loadingFiles": "Loading files...", + "branchesTitle": "Branches", + "loadingBranches": "Loading branches...", + "noContainingBranches": "No containing branches found.", + "newBranch": "New branch...", + "resetToHere": "Reset to Here", + "resetDisabledReasonNotCurrentBranchView": "Available only when viewing current branch", + "copyFullCommitHashAria": "Copy full commit hash {hash}", + "pushStatus": { + "pushed": "Pushed to remote", + "notPushed": "Not pushed to remote", + "unknown": "Push status unknown (no upstream configured)" + }, + "time": { + "monthsAgo": "{count, plural, one {# month ago} other {# months ago}}", + "daysAgo": "{count, plural, one {# day ago} other {# days ago}}", + "hoursAgo": "{count, plural, one {# hour ago} other {# hours ago}}", + "minsAgo": "{count, plural, one {# min ago} other {# mins ago}}", + "justNow": "just now" + }, + "toasts": { + "createdAndSwitchedNewBranch": "Created and switched to new branch", + "newBranchFromCommit": "{name} (from {shortHash})", + "createBranchFailed": "Failed to create branch", + "openPushWindowFailed": "Failed to open push window", + "resetSuccess": "Reset successful", + "resetSuccessDescription": "{branch} reset to {shortHash} with {mode}", + "resetFailed": "Reset failed" + }, + "authorFilter": { + "label": "Author", + "searchPlaceholder": "Search author", + "noAuthors": "No authors found", + "you": "you", + "filterByAuthorAria": "Filter commits by author", + "filterByQuery": "Filter by \"{query}\"", + "clearAuthorFilterAria": "Clear author filter", + "recent": "Recent", + "matchingAuthors": "Matching authors", + "removeFromRecent": "Remove {name} from recent" + }, + "branchSelector": { + "label": "Branch", + "head": "HEAD", + "headHint": "Follows the current branch", + "headHintWithBranch": "Follows the current branch ({branch})", + "searchBranch": "Search branch...", + "noBranches": "No branches", + "selectBranchPlaceholder": "Select branch...", + "localBranches": "Local branches", + "current": "Current", + "remoteBranches": "Remote branches", + "refreshCommitHistory": "Refresh commit history", + "clearBranchFilterAria": "Clear branch filter" + }, + "dialogs": { + "newBranchTitle": "New branch", + "newBranchDescription": "Create a new branch with commit {shortHash} as the latest commit.", + "branchNamePlaceholder": "Branch name", + "reset": { + "title": "Reset Current Branch to Here", + "branchLabel": "Branch", + "targetLabel": "Target", + "messageLabel": "Message", + "modeLabel": "Reset mode", + "confirmButton": "Reset", + "modes": { + "soft": { + "label": "--soft", + "description": "Move HEAD and the current branch pointer to the target commit.\nKeep Index and Working Tree unchanged.\nChanges from the removed commits stay staged." + }, + "mixed": { + "label": "--mixed (default)", + "description": "Move HEAD to the target commit.\nReset Index to the target commit while keeping Working Tree changes.\nThose changes become unstaged." + }, + "hard": { + "label": "--hard", + "description": "Move HEAD and reset both Index and Working Tree to the target commit.\nLocal tracked changes after the target commit are discarded.\nThis is a destructive operation." + }, + "keep": { + "label": "--keep", + "description": "Move HEAD to the target commit and keep local changes when possible.\nOnly non-conflicting local changes are preserved.\nIf conflicts are detected, reset aborts to protect your work." + } + } + } + }, + "moreActions": "More Git actions" + }, + "gitChangesTab": { + "workspace": "workspace", + "noChanges": "No local changes", + "notAGitRepoTitle": "Not a Git repository", + "notAGitRepoHint": "Initialize Git from the branch menu above, or open a folder that is already tracked.", + "trackedChanges": "Tracked changes ({count})", + "untrackedFiles": "Untracked files ({count})", + "expandTracked": "Expand tracked changes", + "collapseTracked": "Collapse tracked changes", + "expandUntracked": "Expand untracked files", + "collapseUntracked": "Collapse untracked files", + "showRemainingItems": "Show {count} more items", + "actions": { + "commitCode": "Commit code", + "rollback": "Rollback", + "addToVcs": "Add to VCS", + "delete": "Delete", + "moreActions": "More Git actions", + "addAllToVcs": "Add all to VCS", + "rollbackAll": "Rollback all", + "refresh": "Refresh" + }, + "toasts": { + "noAddableFilesInDir": "No changed files in this directory can be added to VCS", + "noRollbackFilesInDir": "No changed files in this directory can be rolled back", + "addedToVcs": "Added {name} to VCS", + "addToVcsFailed": "Failed to add to VCS", + "openCommitWindowFailed": "Failed to open commit window", + "rolledBack": "Rolled back {name}", + "rollbackFailed": "Rollback failed", + "addedFilesToVcs": "Added {count, plural, one {# file} other {# files}} to VCS", + "rolledBackFiles": "Rolled back {count, plural, one {# file} other {# files}}", + "deleted": "Deleted {name}", + "deleteFailed": "Delete failed", + "deletedFiles": "Deleted {count, plural, one {# file} other {# files}}", + "noDeletableFilesInDir": "No changed files in this directory can be deleted", + "commitFailed": "Commit failed" + }, + "directoryDialog": { + "descriptionAdd": "Select files under directory {path} to add to VCS.", + "descriptionRollback": "Select files under directory {path} to roll back.", + "descriptionDelete": "Select files under directory {path} to delete. This action cannot be undone.", + "descriptionFallback": "Select files to proceed.", + "selectionCount": "Selected {selected} / {total} files", + "selectAll": "Select all", + "unselectAll": "Unselect all", + "loadingCandidates": "Loading directory changes...", + "noOperableFiles": "No operable files" + }, + "rollbackConfirm": { + "title": "Confirm rollback", + "descriptionWithTarget": "Roll back local changes for {kind} \"{name}\"?", + "descriptionFallback": "Roll back local changes?", + "kindDirectory": "directory", + "kindFile": "file" + }, + "deleteConfirm": { + "title": "Confirm deletion", + "descriptionWithTarget": "Delete {kind} \"{name}\"? This action cannot be undone.", + "descriptionFallback": "This action cannot be undone.", + "kindDirectory": "directory", + "kindFile": "file" + }, + "quickCommit": { + "placeholder": "Commit message (Enter to commit)" + } + }, + "tabContext": { + "loadingConversation": "Loading...", + "untitledConversation": "Untitled conversation", + "newConversation": "New Conversation" + }, + "fileTreeTab": { + "workspace": "Workspace", + "retry": "Retry", + "git": "Git", + "openInFileManager": "Open in file manager", + "openInFinder": "Open in Finder", + "openInExplorer": "Open in Explorer", + "attachToCurrentSession": "Add to session", + "compareWithBranch": "Compare with branch...", + "reloadFromDisk": "Reload from disk", + "new": "New", + "newFile": "File", + "newDirectory": "Directory", + "openIn": "Open in", + "openInTerminal": "Open in terminal", + "linkedFolder": "Linked folder", + "copyPath": "Copy path", + "upload": "Upload files/folder", + "download": "Download file", + "downloadAsZip": "Download as ZIP", + "actions": { + "select": "Select", + "unselect": "Unselect", + "commitCode": "Commit code", + "rollback": "Rollback", + "addToVcs": "Add to VCS" + }, + "aria": { + "selectPath": "{action} {path}" + }, + "toasts": { + "openDirectoryFailed": "Failed to open directory", + "openBuiltinTerminalFailed": "Unable to open built-in terminal", + "openCommitWindowFailed": "Failed to open commit window", + "noAddableFilesInDir": "No changed files in this directory can be added to VCS", + "noRollbackFilesInDir": "No changed files in this directory can be rolled back", + "addedToVcs": "Added {name} to VCS", + "addToVcsFailed": "Failed to add to VCS", + "loadBranchesFailed": "Failed to load branches", + "renameFailed": "Rename failed", + "moveFailed": "Move failed", + "deleteFailed": "Delete failed", + "rolledBack": "Rolled back {name}", + "rollbackFailed": "Rollback failed", + "addedFilesToVcs": "Added {count, plural, one {# file} other {# files}} to VCS", + "rolledBackFiles": "Rolled back {count, plural, one {# file} other {# files}}", + "savedAsCopy": "Saved as a copy", + "saveCopyFailed": "Failed to save as copy", + "watchStartFailed": "Failed to start file watch", + "createFailed": "Failed to create", + "downloadFailed": "Failed to download {name}", + "downloadSaved": "Downloaded {name}", + "pathCopied": "Path copied", + "copyPathFailed": "Failed to copy path" + }, + "createDialog": { + "newFile": "New file", + "newDirectory": "New directory", + "description": "Enter a name for the new {kind}.", + "placeholderFile": "file-name.ext", + "placeholderDirectory": "folder-name" + }, + "renameDialog": { + "renameDirectory": "Rename directory", + "renameFile": "Rename file", + "description": "Enter a new name (name only, no path).", + "placeholderDirectory": "new-folder-name", + "placeholderFile": "new-file-name.ext" + }, + "uploadDialog": { + "title": "Upload to workspace", + "description": "Adjust the destination if needed, then add files or folders.", + "workspaceRoot": "workspace root", + "targetPathLabel": "Upload to", + "targetPathHint": "Resolved path: {path}", + "dropHint": "Drag files or folders here, or use the buttons below", + "dropHintActive": "Release to add to the queue", + "selectFiles": "Select files", + "selectFolder": "Select folder", + "startUpload": "Start upload", + "clearQueue": "Clear finished", + "removeItem": "Remove from queue", + "retry": "Retry", + "dropZoneAria": "Drop files here or activate to browse", + "folderEmpty": "No files found in the dropped folder", + "summary": "Total: {total} · Succeeded: {succeeded} · Failed: {failed}", + "status": { + "pending": "Waiting", + "uploading": "Uploading", + "success": "Done", + "error": "Failed", + "cancelled": "Cancelled" + } + }, + "directoryDialog": { + "descriptionAdd": "Select files under directory {path} to add to VCS.", + "descriptionRollback": "Select files under directory {path} to roll back.", + "descriptionFallback": "Select files to proceed.", + "selectionCount": "Selected {selected} / {total} files", + "selectAll": "Select all", + "unselectAll": "Unselect all", + "loadingCandidates": "Loading directory changes...", + "noOperableFiles": "No operable files" + }, + "compareDialog": { + "title": "Compare with branch", + "descriptionWithTarget": "Select a branch and compare with {kind} {path}", + "descriptionFallback": "Select a branch to compare.", + "kindDirectory": "directory", + "kindFile": "file", + "filterPlaceholder": "Filter branches, e.g. main / origin/main", + "singleClickHint": "Click a branch to compare directly", + "loadingBranches": "Loading branches...", + "recentBranches": "Recent branches ({count})", + "noCurrentBranch": "No current branch", + "localBranches": "Local branches ({count})", + "remoteBranches": "Remote branches ({count})", + "noMatchingBranches": "No matching branches" + }, + "externalConflictDialog": { + "title": "External file changes detected", + "descriptionWithPath": "File {path} has changed on disk, and current edits are unsaved.", + "descriptionFallback": "Current file has changed on disk, and current edits are unsaved.", + "compare": "Compare", + "savingCopy": "Saving copy...", + "saveAsCopy": "Save as copy", + "reload": "Reload" + }, + "deleteConfirm": { + "title": "Confirm deletion", + "descriptionWithTarget": "Delete {kind} \"{name}\"? This action cannot be undone.", + "descriptionFallback": "This action cannot be undone.", + "kindDirectory": "directory", + "kindFile": "file" + }, + "rollbackConfirm": { + "title": "Confirm rollback", + "descriptionWithTarget": "Rollback local changes for file \"{name}\"?", + "descriptionFallback": "Rollback local changes for this file?" + }, + "terminalTitle": "Terminal · {name}" + }, + "commandDropdown": { + "loading": "Loading...", + "addCommand": "Add Command", + "manageCommands": "Manage Commands...", + "runCommandTitle": "Run: {command}", + "stopCommandTitle": "Stop: {command}", + "manageDialog": { + "title": "Manage Commands", + "empty": "No commands yet", + "noResults": "No matching commands", + "searchPlaceholder": "Search commands", + "newCommand": "New command", + "nameLabel": "Name", + "commandLabel": "Command", + "dragSort": "Drag to sort", + "dragSortCommand": "Drag to sort {name}", + "orderFailed": "Failed to save command order", + "loadFailed": "Failed to load commands", + "saveFailed": "Failed to save command", + "deleteFailed": "Failed to delete command", + "confirmDelete": { + "title": "Delete command?", + "message": "This will remove \"{name}\". This action cannot be undone." + } + } + }, + "workspaceContext": { + "confirmCloseDirtyTab": "Close \"{title}\" without saving?", + "confirmCloseOtherDirtyTabs": "Close other tabs with unsaved changes?", + "confirmCloseAllDirtyTabs": "Close all tabs with unsaved changes?", + "unableLoadContent": "Unable to load content.\n\n{message}", + "previewRequestTimedOut": "Preview request timed out", + "diffRequestTimedOut": "Diff request timed out", + "branchCompareRequestTimedOut": "Branch compare request timed out", + "commitDiffRequestTimedOut": "Commit diff request timed out", + "saveRequestTimedOut": "Save request timed out", + "reloadRequestTimedOut": "Reload request timed out", + "noChanges": "No changes.", + "noDiffOutput": "No diff output.", + "diffTitleWorkspace": "Diff · Workspace", + "diffDescriptionWorkingTree": "Working tree (HEAD)", + "diffTitleFile": "Diff · {name}", + "compareTitleFile": "Compare · {name}", + "compareTitleBranch": "Compare · {branch}", + "compareDescriptionPath": "{path} · compare with {branch}", + "compareDescriptionBranch": "compare with {branch}", + "diffTitleCommitFile": "Diff · {name} @ {hash}", + "diffTitleCommit": "Diff · {hash}", + "diffDescriptionCommitPath": "{path} · commit {commit}", + "diffDescriptionCommit": "commit {commit}", + "diffTitleConflictFile": "Conflict · {name}", + "diffDescriptionConflict": "{path} · disk vs unsaved" + }, + "chat": { + "acpConnections": { + "actions": { + "openAgentsSettings": "Open Agents settings", + "retry": "Retry" + }, + "agentsSetupHint": "Open Settings > Agents to manage installation.", + "withSetupHint": "{message}\n{hint}", + "blocked": { + "missingConfig": "Unable to read current Agent configuration.", + "disabled": "{agent} is disabled in Agents settings. Enable it before connecting.", + "unavailable": "{agent} is unavailable on the current platform.", + "sdkMissing": "{agent} SDK is not installed", + "adapterMissing": "{agent}'s ACP adapter is not installed" + }, + "backendErrors": { + "initializeTimeout": "{agent} connection handshake timed out after 60 seconds. Please open Settings to check Agent configuration and network settings.", + "mcpRejectedByAgent": "{agent} refused the session while codeg’s MCP companion was attached: {message} If this agent does not support MCP, turn off “MCP support” for it in Settings and connect again.", + "processExited": "{agent} process exited unexpectedly.", + "spawnFailed": "Failed to start {agent}: {message}", + "downloadFailed": "{agent} download failed: {message}", + "sessionLoadResourceNotFound": "{agent} session failed to load. Reload to retry, or start a new conversation.", + "sessionLoadUnavailable": "{agent} couldn't restore this session — it may have ended or the agent stopped. Reload to retry, or start a new conversation.", + "turnFailedRefusal": "{agent} refused to continue this turn. This often indicates a backend or gateway error — check the agent's logs.", + "turnFailedMaxTokens": "{agent} reached the maximum token limit for this turn.", + "turnFailedMaxTurnRequests": "{agent} reached the maximum number of allowed requests for this turn.", + "turnFailedUnknown": "{agent} ended the turn with an unrecognized stop reason.", + "grokModelSwitchIncompatibleAgent": "{agent} can't switch to that model in an existing conversation. Start a new session to use it.", + "turnFailedEmpty": "{agent} ended the turn without producing any response.", + "turnFailedEmptyProtocol": "{agent} produced output that codeg could not parse — the agent version may not match the protocol.", + "turnFailedEmptyMetadata": "{agent} sent only status updates this turn (plan / mode / usage) and no reply.", + "detailsInAlerts": "Open Alerts in the status bar and expand the details to see the agent's output." + }, + "unableReadAgentConfig": "Unable to read Agent config: {message}", + "connectFailedTitle": "{agent} connection failed", + "toolFallbackTitle": "Tool", + "eventErrorTitle": "Agent Error", + "notificationTurnComplete": "{agent} has finished responding", + "notificationError": "{agent} error: {message}", + "claudeApiRetry": { + "fallbackError": "authentication_failed", + "retryingWithMax": "retrying {attempt}/{max}", + "retryingAttempt": "retrying attempt {attempt}", + "retrying": "retrying", + "nextRetryIn": "next in {seconds}s", + "line": "{error}{status} · {retry}", + "lineWithDelay": "{error}{status} · {retry}, {delay}", + "httpStatus": " (HTTP {status})" + }, + "configOptionAdjusted": "{agent} set {option} to {actual} instead of {requested}" + }, + "connectionLifecycle": { + "tasks": { + "connectingTitle": "Connecting to {agent}", + "connectingDescription": "Establishing connection", + "loadingSelectorsTitle": "Loading {agent} selectors", + "loadingSelectorsDescription": "Fetching mode and session config options", + "initSessionTitle": "Initializing {agent} session", + "initSessionDescription": "Creating session and loading configuration" + }, + "errors": { + "connectionFailed": "Connection failed", + "sendPromptFailed": "Failed to send the message: {error}" + } + }, + "shared": { + "attachedResources": "Attached resources", + "toolCallFailed": "Tool call failed" + }, + "messageThread": { + "emptyTitle": "No messages yet", + "emptyDescription": "Start a conversation to see messages here" + }, + "chatInput": { + "connecting": "Connecting...", + "agentResponding": "{agent} is responding...", + "sendMessage": "Send a message..." + }, + "messageInput": { + "askAnything": "Ask anything...", + "removeAttachmentAria": "Remove {name}", + "attachFiles": "Attach files", + "attachLocalUpload": "Upload local file", + "attachServerFile": "Pick server file", + "addActions": "Add", + "quickMessages": "Quick messages", + "quickMessagesEmpty": "No quick messages yet", + "quickMessagesLoading": "Loading...", + "pasteAsPlainText": "Paste as plain text", + "cut": "Cut", + "copy": "Copy", + "selectAll": "Select all", + "pasteUnavailable": "Couldn't read the clipboard. Press Ctrl/⌘V to paste instead.", + "clipboardWriteFailed": "Couldn't write to the clipboard. Use the keyboard shortcut instead.", + "quickMessageUntitled": "Untitled", + "liveFeedback": "Live feedback", + "liveFeedbackDisabledHint": "Available while the agent is working", + "dropFilesToAttach": "Drop files to attach", + "loadingSettings": "Loading settings...", + "loadingMode": "Loading mode...", + "modeLabel": "Mode", + "toggleOn": "On", + "toggleOff": "Off", + "agentSettings": "Agent settings", + "searchModel": "Search models...", + "searchModelAria": "Search models", + "modelListLabel": "Models", + "noModels": "No models found", + "cancel": "Cancel", + "send": "Send", + "forkAndSend": "Fork & Send", + "queueMessage": "Queue message", + "steerIntoTurn": "Insert into current turn", + "steerQueuedInstead": "Queued instead — it will be sent with the next turn.", + "steerFailed": "Couldn't insert into the current turn", + "steerAttachmentsUnsupported": "Text only — drafts with attachments go through the queue.", + "slashCommands": "Slash commands", + "slashSearchPlaceholder": "Search commands...", + "slashSearchEmpty": "No matching commands", + "experts": "Experts", + "office": "Office Work", + "research": "Scientific Research", + "attachUploadTooLarge": "{names} exceeds the {limit}MB upload limit and was skipped.", + "attachUploadFailed": "Failed to upload {names}.", + "attachUploadNotAFile": "{names} isn't a regular file (directory or special file) and was skipped.", + "attachUploadQuotaExceeded": "The server is out of upload storage; {names} couldn't be uploaded.", + "attachUploadInProgress": "Images are still uploading — try again in a moment.", + "mentionEmpty": "No matches", + "mentionLoading": "Searching…", + "mentionListLabel": "Mentions", + "mentionMore": "More results — keep typing to filter", + "mentionCount": "{count, plural, one {# result} other {# results}}", + "mentionGroupFile": "Files", + "mentionGroupAgent": "Agents", + "mentionGroupSession": "Sessions", + "mentionGroupCommit": "Commits", + "mentionGroupSkill": "Skills" + }, + "messageQueue": { + "addToQueue": "Queue message", + "saveEdit": "Save", + "cancelEdit": "Cancel edit", + "editItem": "Edit", + "deleteItem": "Remove" + }, + "welcomeInputPanel": { + "agentsSettingsPath": "Settings > Agents", + "autoConnectFallback": "Click to open {path} and manage installation.", + "autoConnectAppend": "{message}. Click to open {path} and manage installation.", + "enableAgentFirstPlaceholder": "Enable at least one agent before starting a session...", + "prepareSessionFailed": "Couldn't prepare the chat session. Please try again.", + "createConversationFailed": "Couldn't create the conversation. Please try again.", + "askAnythingPlaceholder": "Ask anything...", + "agentNotInstalled": "{agent} is not installed — open Agents settings to install it", + "agentAdapterNotInstalled": "{agent}'s ACP adapter is not installed (separate from your own CLI) · open Agents settings to install it" + }, + "welcomePanel": { + "greeting": "What would you like to do today?", + "tips": { + "tileTabs": "Right-click any conversation tab and choose Tile Display to see multiple sessions side by side.", + "pinTab": "Double-click a conversation tab to pin it, so a newly opened session won't auto-replace it.", + "shortcutsNewSearch": "{newConversation} opens a new conversation, {searchConversations} searches your history.", + "slashAtMention": "Type / in the input to trigger slash commands, or @ to reference a file from the project.", + "pasteDropFiles": "Paste a screenshot or drop a file directly onto the input to attach it.", + "queueMessage": "While the agent is replying, keep typing — your next message gets queued and auto-sent when it finishes.", + "draftAutoSave": "Unsent drafts are auto-saved per conversation and restored when you come back.", + "forkSend": "The send button's dropdown has Fork and Send — branch from the current turn into a new tab.", + "exportConversation": "Right-click inside the conversation to export it as Markdown, HTML, or an image.", + "chatChannels": "Connect Telegram / Lark / WeChat under Settings → Chat Channels to continue from your phone.", + "shortcutsAuxPanel": "{toggleAuxPanel} toggles the right panel to view this session's touched files and Git changes.", + "shortcutsTerminalSidebar": "{toggleTerminal} opens the built-in terminal, {toggleSidebar} toggles the sidebar.", + "customShortcuts": "Every shortcut is fully remappable under Settings → Shortcuts.", + "webService": "Enable Settings → Web Service so teammates can reach the same codeg from a browser.", + "fusionMode": "Open a file or diff to automatically show it alongside the conversation.", + "quickMessages": "Open the + button next to the input and pick Quick Messages to insert a saved snippet (manage them under Settings → Quick Messages).", + "experts": "The + button has an Expert Skills menu — preload roles like Debug or Planning with one click.", + "taskBoard": "To-dos run a task end to end — the agent works in its own worktree, then you review the diff and merge.", + "automations": "Automations run a saved prompt on a schedule — a nightly review, a recurring report — and each run can get its own worktree.", + "tokenUsage": "Click the conversation count in the status bar to open Token Usage — spend broken down by day, agent, model, and folder.", + "mentionTargets": "@ pulls in more than files — mention another agent to hand off a subtask, or reference a past session, a commit, or a skill.", + "splitGroups": "Right-click a tab and pick Split Right or Split Down to keep two conversations open in their own panes.", + "worktrees": "Open the branch button and pick New worktree so several agents can work the same repo without overwriting each other's files.", + "importSessions": "Already ran sessions in the terminal? A folder's menu has Import local sessions — bring that history into codeg.", + "subSessions": "When an agent delegates, the sub-session appears nested under it in the sidebar — expand the row to follow what each one did.", + "liveFeedback": "Live feedback in the + menu drops a note into the turn the agent is already running, without interrupting it.", + "skillPacks": "Settings → Skill Packs bundles coding experts, scientific research, and office skills — switch them on per agent.", + "modelProviders": "Settings → Model Providers takes your own API key or endpoint, and you pick the model right in the composer.", + "workspaceBackground": "Settings → Appearance sets a workspace background image, panel opacity, and the app's fonts." + }, + "quickActions": { + "excel": "Excel Workbook", + "excelDesc": "Data tables, formulas & charts", + "word": "Word Document", + "wordDesc": "Reports, letters & memos", + "ppt": "Presentation", + "pptDesc": "Slides with professional design", + "pitchDeck": "Pitch Deck", + "pitchDeckDesc": "Fundraising deck with key metrics", + "morph": "Morph Animation", + "morphDesc": "Cinematic slide transitions", + "morph3d": "3D Morph", + "morph3dDesc": "3D models with camera moves", + "academic": "Academic Paper", + "academicDesc": "Research with citations & structure", + "financial": "Financial Model", + "financialDesc": "Statements, DCF & projections", + "dashboard": "Data Dashboard", + "dashboardDesc": "KPIs & analytics from your data", + "prompts": { + "excel": "Create an Excel workbook with the following requirements:\n\n[describe your data, tables, formulas, and charts here]", + "word": "Create a Word document with the following requirements:\n\n[describe your document content, structure, and formatting here]", + "ppt": "Create a PowerPoint presentation with the following requirements:\n\n[describe your slides, content, and design here]", + "pitchDeck": "Create a fundraising pitch deck with the following requirements:\n\n[describe your company, funding round, and key metrics here]", + "morph": "Create a presentation with Morph transition animations:\n\n[describe your presentation topic and desired visual effects here]", + "morph3d": "Create a 3D Morph presentation with GLB models and camera moves:\n\n[describe your topic and 3D visual concept here]", + "academic": "Write an academic paper in Word with the following requirements:\n\n[describe your research topic, methodology, and key findings here]", + "financial": "Create a financial model in Excel with the following requirements:\n\n[describe your financial statements, projections, and analysis here]", + "dashboard": "Create a data dashboard in Excel with the following requirements:\n\n[describe your data source, KPIs, and charts here]", + "scientific-brainstorming": "Help me brainstorm research directions — explore interdisciplinary connections, challenge assumptions, and surface promising gaps. The area I'm exploring: ", + "hypothesis-generation": "Help me turn these observations into testable hypotheses — with clear predictions, plausible mechanisms, and experiments to test them. My observations: ", + "experimental-design": "Help me design a rigorous experiment before I collect data — the design, randomization, controls, and how to avoid confounding. What I want to study: ", + "statistical-power": "Help me determine the sample size I need — walk me through a power analysis (effect size, alpha, power) for my design. Details: ", + "statistical-analysis": "Help me analyze this data properly — choose the right test, check assumptions, report effect sizes, and write it up. My data and question: ", + "exploratory-data-analysis": "Do an exploratory analysis of my data file — summarize its structure, quality, and notable patterns, then suggest next steps. The file is: ", + "scientific-visualization": "Help me make a publication-quality figure — clear layout, honest error bars, a colorblind-safe palette, and journal formatting. What I want to show: ", + "scientific-critical-thinking": "Help me critically appraise this study or claim — assess the evidence quality, spot biases and confounders, and weigh the conclusions. Here it is: ", + "paper-lookup": "Help me find relevant papers and open-access full text across scholarly databases, with citations I can reuse. I'm looking for: " + }, + "paper-lookup": "Paper Lookup", + "paper-lookupDesc": "Search 10 scholarly APIs (PubMed, arXiv, OpenAlex, Crossref…) for papers, citations, and open-access full text.", + "scientific-critical-thinking": "Critical Thinking", + "scientific-critical-thinkingDesc": "Appraise scientific claims and evidence quality — spot biases and confounders, apply GRADE and risk-of-bias frameworks.", + "scientific-visualization": "Scientific Visualization", + "scientific-visualizationDesc": "Publication-ready figures — multi-panel layouts, significance annotations, and journal-specific formatting.", + "exploratory-data-analysis": "Exploratory Data Analysis", + "exploratory-data-analysisDesc": "Automated exploration of scientific data files across 200+ formats with quality metrics and reports.", + "statistical-analysis": "Statistical Analysis", + "statistical-analysisDesc": "Guided statistical analysis — test selection, assumption checks, effect sizes, and APA-style reporting.", + "statistical-power": "Statistical Power", + "statistical-powerDesc": "Sample-size and power analysis — how many subjects you need, minimum detectable effects, and power curves.", + "experimental-design": "Experimental Design", + "experimental-designDesc": "Design rigorous studies before collecting data — randomization, blocking, controls, and factorial/DOE layouts.", + "hypothesis-generation": "Hypothesis Generation", + "hypothesis-generationDesc": "Turn observations into testable hypotheses with predictions, mechanisms, and experiments to test them.", + "scientific-brainstorming": "Scientific Brainstorming", + "scientific-brainstormingDesc": "Open-ended research ideation — explore interdisciplinary links, challenge assumptions, and surface research gaps.", + "tabs": { + "office": "Office Work", + "coding": "Code Development", + "research": "Scientific Research" + }, + "coding": { + "brainstormingDesc": "Explore intent & requirements before building", + "debuggingDesc": "Find the root cause before proposing fixes", + "writingSkillsDesc": "Create, edit & verify reusable skills" + }, + "notEnabled": { + "title": "“{skill}” isn’t enabled for {agent} yet", + "description": "Enable it in Settings to use it here.", + "action": "Enable", + "hint": "Skill not enabled" + }, + "scrollPrev": "Show previous skills", + "scrollNext": "Show more skills" + } + }, + "agentSelector": { + "noEnabledAgents": "No enabled agents", + "openAgentsSettings": "Open Agents settings", + "notInstalled": "Not installed", + "moreAgents": "More agents ({count})" + }, + "subAgentOverlay": { + "title": "Sub-agents", + "collapsedSummary": "Sub-agents {count}", + "collapseAria": "Collapse sub-agents" + }, + "agentPlanOverlay": { + "title": "Agent Plan", + "collapsePlanAria": "Collapse plan", + "collapsedSummary": "Plan {completed}/{total}", + "status": { + "completed": "Completed", + "inProgress": "In Progress", + "pending": "Pending", + "unknown": "Unknown" + }, + "priority": { + "high": "High", + "medium": "Medium", + "low": "Low", + "unknown": "Unknown" + } + }, + "permissionDialog": { + "subtitle": "Agent requests permission to continue this turn.", + "queuedCount": "+{count} waiting", + "kindFallbackTool": "tool", + "command": "Command", + "cwd": "CWD: {cwd}", + "filesSummary": "Files: {count}", + "moreFiles": "+{count} more files", + "plan": "Plan", + "allowedActions": "Allowed actions", + "targetMode": "Target mode: {mode}", + "optionGrants": "What each option grants", + "changeScopeSession": "This session", + "changeScopeProcess": "This run", + "changeScopeUser": "Saved to user settings", + "changeScopeProject": "Saved to project settings", + "changeScopeProjectLocal": "Saved to local project settings", + "changeScopePersistent": "Saved permanently" + }, + "questionDialog": { + "title": "Agent is asking a question", + "placeholder": "Type your answer...", + "send": "Send" + }, + "messageBranch": { + "previousBranchAria": "Previous branch", + "nextBranchAria": "Next branch", + "pageOf": "{current} of {total}" + }, + "terminal": { + "title": "Terminal", + "running": "Running" + }, + "reasoning": { + "thinking": "Thinking…", + "thoughtForFewSeconds": "Thought", + "thoughtForSeconds": "Thought" + }, + "linkSafety": { + "errorCannotOpen": "Cannot open local file", + "errorNoWorkspace": "No workspace folder is currently active.", + "errorFailedOpen": "Failed to open local file", + "errorFailedLink": "Failed to open link", + "errorUnsupportedLinkProtocol": "This link protocol is not supported." + }, + "fileActions": { + "openInFinder": "Open in Finder", + "openInExplorer": "Open in Explorer", + "openInFileManager": "Open in file manager", + "copyRelativePath": "Copy relative path", + "copyAbsolutePath": "Copy absolute path", + "pathCopied": "Path copied", + "copyPathFailed": "Failed to copy path", + "openFailed": "Failed to open local file" + }, + "messageList": { + "attachedResources": "Attached resources", + "loading": "Loading...", + "loadEarlier": "Load earlier messages", + "loadingEarlier": "Loading earlier messages…", + "error": "Error: {message}", + "errorTitle": "Session load failed", + "errorActionReload": "Reload", + "errorActionNewSession": "New conversation", + "emptyConversation": "No messages in this conversation.", + "systemMessage": "System message", + "copyMessage": "Copy", + "copied": "Copied", + "downloadImage": "Download image", + "downloadFailed": "Download failed: {message}", + "imageGeneration": "Image generation", + "imageGenerationPending": "Generating image…", + "imageGenerationFailed": "Image generation failed", + "model": "Model", + "tokenStats": "Token usage", + "tokenInput": "Input", + "tokenOutput": "Output", + "tokenCacheRead": "Cache read", + "tokenCacheWrite": "Cache write", + "duration": "Duration", + "completedAt": "Completed at", + "jumpToPreviousUserMessage": "Jump to user message", + "showMore": "Show more", + "showLess": "Show less" + }, + "liveTurnStats": { + "thinking": "Thinking...", + "streaming": "Streaming", + "elapsedHours": "{value}h", + "elapsedMinutes": "{value}m", + "elapsedSeconds": "{value}s", + "outputSpeedAria": "Estimated output speed", + "outputSpeedTooltip": "Estimated output speed (text + thinking)" + }, + "jsonTree": { + "viewRaw": "Show raw JSON", + "viewTree": "Show tree", + "fields": "{count, plural, one {# field} other {# fields}}", + "items": "{count, plural, one {# item} other {# items}}" + }, + "tool": { + "parameters": "Parameters", + "error": "Error", + "result": "Result", + "status": { + "approvalRequested": "Awaiting Approval", + "approvalResponded": "Responded", + "inputAvailable": "Running", + "inputStreaming": "Pending", + "outputAvailable": "Completed", + "outputDenied": "Denied", + "outputError": "Error" + } + }, + "toolCallBlock": { + "tool": "Tool", + "error": "Error", + "result": "Result" + }, + "delegation": { + "subAgentRunning": "Sub-agent running…", + "noDetail": "No detail available yet.", + "unknownAgent": "Sub-agent", + "openDetail": "Open conversation", + "detailTitle": "Sub-agent conversation", + "detailDescription": "Read-only view of the delegated sub-agent's conversation.", + "waitForResult": "Waiting for task {task} result", + "waitForResultNoTask": "Waiting for task result", + "cancelTask": "Canceling task {task}", + "cancelTaskNoTask": "Canceling task", + "resultPageOf": "{current} / {total}", + "prevResult": "Previous result", + "nextResult": "Next result", + "noResultText": "No result captured for this check.", + "status": { + "starting": "starting", + "running": "running", + "checked": "checked", + "waiting": "awaiting approval", + "ok": "done", + "err": { + "default": "failed", + "delegation_disabled": "disabled", + "depth_limit": "depth limit", + "invalid_agent_type": "bad agent", + "spawn_failed": "spawn failed", + "send_failed": "send failed", + "timeout": "timeout", + "canceled": "canceled", + "child_refusal": "subagent refused", + "child_max_tokens": "subagent token limit", + "child_max_turn_requests": "subagent request limit", + "child_empty": "subagent no output", + "child_unknown": "subagent unknown error", + "unknown": "unknown task" + } + } + }, + "contentParts": { + "showingTailOutput": "Showing tail output while streaming for performance.", + "result": "Result", + "unknown": "unknown", + "inputTruncated": "Input was truncated — diff may be incomplete.", + "replaceAll": "REPLACE ALL", + "filesCount": "Files: {count}", + "update": "update", + "moreFiles": "+{count} more files", + "timeoutMs": "Timeout: {timeout}ms", + "backgroundTrue": "Background: true", + "scriptToolCalls": "{count, plural, one {# tool call} other {# tool calls}}", + "offset": "Offset: {offset}", + "limit": "Limit: {limit}", + "pages": "Pages: {pages}", + "mode": "Mode: {mode}", + "cell": "Cell: {cell}", + "shellSession": "Session {id}", + "pathLabel": "Path:", + "globLabel": "Glob:", + "typeLabel": "Type:", + "outputLabel": "Output:", + "caseInsensitive": "Case insensitive", + "multiline": "Multiline", + "promptLabel": "Prompt", + "subjectLabel": "Subject", + "taskLabel": "Task", + "nameLabel": "Name:", + "agentPromptLabel": "Prompt", + "agentModelLabel": "Model", + "agentRunning": "Running...", + "agentLiveTranscript": "Live activity", + "agentProgressTools": "{count} tool calls", + "agentProgressTurns": "{count} turns", + "agentProgressContext": "context {pct}%", + "agentSessionAction": "View sub-agent session", + "agentSessionTitle": "Sub-agent session", + "agentSessionLoading": "Loading the sub-agent's transcript…", + "agentSessionEmpty": "The sub-agent hasn't written anything yet.", + "agentFallbackTitle": "Sub-agent starting…", + "agentCodexLaunchOnly": "Launched. Codex reports no further progress for this sub-agent — its result arrives as a message in this conversation.", + "agentStatsBash": "Commands", + "agentStatsRead": "Files read", + "agentStatsSearch": "Searches", + "agentStatsEdit": "Edits", + "agentStatsOther": "Other", + "goal": { + "title": "Goal:", + "titleWithStatus": "Goal {status}", + "objective": "Objective", + "statusLabel": "Status", + "tokensUsed": "Tokens used", + "budget": "Budget", + "remaining": "Remaining", + "elapsed": "Elapsed", + "tokens": "tokens", + "pause": "Pause", + "clear": "Clear", + "status": { + "active": "active", + "paused": "paused", + "blocked": "blocked", + "usageLimited": "usage limited", + "budgetLimited": "budget limited", + "complete": "complete", + "limited": "limit reached" + } + }, + "field": { + "file": "File", + "notebook": "Notebook", + "command": "Command", + "old": "Old", + "new": "New", + "pattern": "Pattern", + "path": "Path", + "query": "Query", + "url": "URL", + "description": "Description", + "content": "Content", + "source": "Source", + "prompt": "Prompt", + "subject": "Subject", + "taskId": "Task ID", + "status": "Status", + "skill": "Skill", + "args": "Args", + "offset": "Offset", + "limit": "Limit", + "glob": "Glob", + "type": "Type", + "output": "Output", + "replaceAll": "Replace All", + "language": "Language", + "timeout": "Timeout", + "background": "Background", + "agentType": "Agent Type", + "library": "Library", + "libraryId": "Library ID" + }, + "title": { + "edit": "Edit", + "command": "Command", + "script": "Script", + "waitCommand": "Wait {command}", + "waitCell": "Wait cell {id}", + "terminateCommand": "Terminate {command}", + "terminateCell": "Terminate cell {id}", + "stdinChars": "Stdin {chars}", + "todoWrite": "TodoWrite", + "read": "Read", + "write": "Write", + "notebookEdit": "NotebookEdit", + "editFiles": "Edit ({count} files)", + "editWithTarget": "Edit {target}", + "readWithTarget": "Read {target}", + "writeWithTarget": "Write {target}", + "notebookEditWithTarget": "NotebookEdit {target}", + "globWithPattern": "Glob {pattern}", + "listFilesWithPath": "List files {path}", + "grepWithPattern": "Grep {pattern}", + "taskCreateWithSubject": "TaskCreate: {subject}", + "taskUpdateWithStatus": "TaskUpdate #{id} -> {status}", + "taskUpdate": "TaskUpdate #{id}", + "webFetchWithUrl": "WebFetch {url}", + "webSearchWithQuery": "WebSearch: {query}", + "todosProgress": "Todos ({done}/{total})", + "skillWithName": "Skill: {name}", + "genericWithContext": "{tool}: {context}" + }, + "search": { + "noMatches": "No matches", + "matchSummary": "{matches, plural, one {# match} other {# matches}} in {files, plural, one {# file} other {# files}}", + "fileSummary": "{files, plural, one {# file} other {# files}}", + "moreResults": "{count, plural, one {# more result not shown} other {# more results not shown}}" + }, + "toolGroup": { + "search": "{count, plural, one {Explored # search} other {Explored # searches}}", + "command": "{count, plural, one {Ran # command} other {Ran # commands}}", + "read": "{count, plural, one {Read files # time} other {Read files # times}}", + "memory": "{count, plural, one {Recalled # memory} other {Recalled # memories}}", + "edit": "{count, plural, one {Edited files # time} other {Edited files # times}}", + "fetch": "{count, plural, one {Fetched # resource} other {Fetched # resources}}", + "think": "{count, plural, one {Thought # time} other {Thought # times}}", + "todo": "{count, plural, one {Updated # todo} other {Updated # todos}}", + "task": "{count, plural, one {Ran # task} other {Ran # tasks}}", + "other": "{count, plural, one {Used # tool} other {Used # tools}}", + "errorSuffix": "{count, plural, one {# failed} other {# failed}}", + "joiner": " · " + }, + "planMode": { + "entered": "Entered plan mode", + "planLabel": "Plan", + "reviewApproved": "Plan approved — implementing", + "reviewKept": "Kept in plan mode", + "reviewPending": "Awaiting plan decision", + "submitted": "Plan submitted", + "switched": "Switched mode" + }, + "backgroundTask": { + "title": "Background task", + "titleWithId": "Background task · {id}", + "running": "Running", + "completed": "Completed", + "failed": "Failed", + "stopped": "Stopped", + "exitCode": "exit {code}", + "polledTimes": "Polled {count} times", + "runningInBackground": "Background", + "launchNote": "Running in background · {id}" + }, + "codexScript": { + "outputMissing": "Codex truncated the script output and dropped this command's separator, so none of the output could be attributed to it.", + "sharedWith": "Also contains the output of {commands} — codex truncated their separators away.", + "truncated": "truncated" + } + }, + "messageNav": { + "title": "Message navigation", + "collapse": "Collapse message navigation", + "collapsedSummary": "Messages {count}", + "fileCount": "{count, plural, one {# file} other {# files}}", + "remove": "Remove", + "noDiffDataAvailable": "No diff data available for {filePath}" + }, + "replyArtifacts": { + "title": "Files changed", + "fileCount": "{count, plural, one {# file} other {# files}}", + "newFilesTitle": "New files", + "revealInFolder": "Show in file manager", + "openFile": "Open {filePath}", + "openInEditor": "Open in editor", + "remove": "Remove", + "noDiffDataAvailable": "No diff data available for {filePath}" + }, + "askQuestion": { + "title": "The agent needs your input", + "subtitle": "Answer below, then submit. You can skip anytime.", + "recommended": "Recommended", + "other": "Other", + "otherPlaceholder": "Type your answer…", + "singleSelect": "Single", + "multiSelect": "Multiple", + "skip": "Skip", + "next": "Next", + "submit": "Submit", + "submitError": "Couldn't submit. Please try again." + }, + "planApproval": { + "title": "The agent has a plan — review it", + "emptyPlan": "The agent didn't write a plan. Approve to start building, or request changes.", + "approve": "Approve & build", + "requestChanges": "Request changes", + "abandon": "Abandon", + "feedbackPlaceholder": "What should change?", + "sendChanges": "Send", + "cancel": "Cancel", + "submitError": "Couldn't submit. Please try again." + }, + "feedbackCheckResult": { + "count": "{count, plural, =1 {1 feedback note} other {# feedback notes}}", + "expand": "Show all feedback", + "collapse": "Collapse", + "errorTitle": "Feedback check failed" + }, + "askQuestionResult": { + "title": "Question", + "answeredLabel": "Q&A:", + "awaiting": "Waiting for your answer…", + "declined": "You dismissed this — the agent used its own judgment.", + "noSelection": "No selection" + }, + "configStale": { + "agentConfigTitle": "Agent settings updated", + "modelProviderTitle": "Model provider updated", + "description": "This session is still using its previous configuration. Reconnect to apply — your conversation history is kept.", + "reconnect": "Reconnect to apply", + "reconnecting": "Reconnecting…", + "reconnectDisabledDuringTurn": "Available once the current turn finishes", + "dismiss": "Dismiss", + "reconnectFailed": "Failed to reconnect session", + "applied": "New configuration applied" + }, + "piProjectTrust": { + "title": "This project ships pi resources", + "description": "pi is not loading the repository's own .pi files. Review them to decide.", + "descriptionExecutable": "The repository ships pi extensions, which run code at startup. pi is not loading them. Review before you decide.", + "review": "Review…", + "dismiss": "Dismiss", + "dialogTitle": "Trust this project's pi resources?", + "dialogDescription": "pi only loads a repository's own .pi files once you trust the folder. Trust it only if you trust this repository's contents.", + "executionWarning": "Extensions are code. Trusting this folder lets the repository run them at pi startup with your permissions, before you send any message.", + "scopeNote": "The decision is saved in pi's trust.json for this folder, applies to every folder inside it, and is also used when you run pi yourself in a terminal. You can change it later in Settings → Agents → Pi.", + "trust": "Trust project", + "decline": "Keep unloaded", + "disabledDuringTurn": "Available once the current turn finishes", + "trustedToast": "Project trusted — reconnected so pi loads its resources", + "declinedToast": "Project resources stay unloaded", + "saveFailed": "Failed to save the project trust decision", + "grantTitle": "This project is already trusted", + "grantDescription": "pi loads this repository's own .pi files. Review what that allows.", + "grantInheritedDescription": "A parent folder is trusted, so pi loads this repository's own .pi files. Review what that allows.", + "grantDialogTitle": "This project's pi resources are trusted", + "grantDialogDescription": "pi is allowed to load this repository's own .pi files. Earlier codeg versions granted this automatically when you opened a folder, so you may not have been asked.", + "grantExecutionWarning": "Extensions are code. The repository runs them at pi startup with your permissions, before you send any message.", + "inheritedFrom": "Trusted via", + "revoke": "Revoke trust", + "keepTrusted": "Keep trusted", + "revokedToast": "Trust revoked — reconnected so pi stops loading the project's resources", + "trustedNoReconnect": "Project trusted — it applies the next time pi starts", + "revokedNoReconnect": "Trust revoked — it applies the next time pi starts" + }, + "collabAgent": { + "title": "Sub-agent", + "errorTitle": "Sub-agent task failed", + "statesLabel": "Sub-agents", + "statusRunning": "Running", + "statusCompleted": "Completed", + "statusFailed": "Failed", + "statusPending": "Starting", + "statusInterrupted": "Interrupted", + "statusClosed": "Closed", + "statusNotFound": "Not found", + "opSpawn": "Starting sub-agent", + "opWait": "Fetching sub-agent result", + "opClose": "Closing sub-agent", + "opResume": "Resuming sub-agent" + }, + "contextCompaction": { + "compacting": "Compacting context…", + "compacted": "Context compacted", + "compactedTokens": "Context compacted · {before} → {after} tokens", + "failed": "Context compaction failed" + }, + "sessionFailure": { + "category": { + "connection": "Connection issue", + "access": "Access issue", + "limit": "Limit reached", + "request": "Request rejected", + "service": "Service issue", + "unknown": "Session issue" + }, + "action": { + "retry": "Retry", + "login": "Sign in", + "newSession": "New session" + }, + "recovered": "Recovered", + "retryUnavailable": "No previous message to resend.", + "toggleDetails": "Toggle details" + }, + "backgroundTasks": { + "running": "{count, plural, one {# background task running} other {# background tasks running}}", + "settling": "Syncing background results…", + "settledFallback": "Background task finished ({status})", + "cardRunning": "Running in background", + "cardLaunchedPending": "Launched in background", + "cardCompleted": "Background task completed", + "cardFinishedWithStatus": "Background task finished ({status})", + "cardResultPending": "Result not returned yet" + }, + "proposedPlan": { + "title": "Proposed plan", + "planning": "Planning…" + } + }, + "diffPreview": { + "mode": { + "added": "Added", + "deleted": "Deleted", + "renamed": "Renamed", + "modified": "Modified" + }, + "hunkLabel": "Hunk {index}", + "loadingHunk": "Loading hunk...", + "noDiffData": "No diff data", + "showRemainingLines": "Show {count} more lines" + }, + "conversationContextBar": { + "folderTitle": "Working folder", + "branchTitle": "Working branch", + "searchFolder": "Search folder...", + "searchBranch": "Search branch...", + "noFolders": "No folders", + "noBranches": "No branches", + "noBranch": "(no branch)", + "chatModeLabel": "Chat mode", + "commit": "Commit", + "push": "Push", + "merge": "Merge", + "toasts": { + "folderChanged": "Switched to {name}", + "openFolderFailed": "Failed to open folder", + "switchedToChatMode": "Switched to chat mode", + "openStashFailed": "Failed to open stash window", + "openMergeFailed": "Failed to open merge window" + } + }, + "cloneDialog": { + "title": "Clone Repository", + "repositoryUrl": "Repository URL", + "repositoryUrlPlaceholder": "https://github.com/user/repo.git", + "directory": "Directory", + "directoryPlaceholder": "Select target directory...", + "browseDirectory": "Browse directory", + "cancel": "Cancel", + "clone": "Clone", + "clonePath": "Clone path: {path}" + }, + "toasts": { + "cloneFailed": "Failed to clone repository" + } + }, + "ProjectBoot": { + "title": "Project Boot", + "tabs": { + "shadcn": "shadcn", + "hyperframes": "HyperFrames" + }, + "hyperframes": { + "title": "HyperFrames Video Project", + "subtitle": "Scaffold an HTML-to-video project. Your workspace agent can then write and render it.", + "resolution": "Resolution", + "skillsTitle": "Agent Skills", + "skillsDesc": "Globally install the HyperFrames skills (symlinked) for the selected agents so they can author and render video.", + "recheck": "Re-check", + "installedBadge": "Installed", + "skillsInstall": "Install / update skills", + "skillsInstalling": "Installing skills…", + "skillsInstalled": "HyperFrames skills installed", + "skillsInstallFailed": "Couldn't install HyperFrames skills" + }, + "config": { + "base": "Base", + "style": "Style", + "baseColor": "Base Color", + "theme": "Theme", + "chartColor": "Chart Color", + "iconLibrary": "Icon Library", + "font": "Font", + "fontHeading": "Heading Font", + "menuAccent": "Menu Accent", + "menuColor": "Menu Color", + "radius": "Radius", + "template": "Template", + "createProject": "Create Project", + "sectionStyle": "Style", + "sectionColors": "Colors", + "sectionTypography": "Typography", + "sectionInterface": "Interface" + }, + "preview": { + "loading": "Loading preview..." + }, + "createDialog": { + "title": "Create Project", + "projectName": "Project Name", + "projectNamePlaceholder": "my-app", + "frameworkTemplate": "Framework Template", + "packageManager": "Package Manager", + "saveDirectory": "Save Directory", + "saveDirectoryPlaceholder": "Select directory...", + "browseDirectory": "Browse", + "projectPath": "Project will be created at: {path}", + "advancedOptions": "Advanced Options", + "base": "Base Library", + "enableRtl": "Enable RTL Support", + "enableRtlDescription": "Enable layout support for right-to-left languages (e.g. Arabic, Hebrew)", + "pmChecking": "Checking...", + "pmNotInstalled": "Not installed", + "cancel": "Cancel", + "create": "Create", + "creating": "Creating project..." + }, + "toasts": { + "createFailed": "Failed to create project", + "createSuccess": "Project created successfully", + "openWorkspaceFailed": "Project created, but couldn't open it in the workspace" + }, + "errors": { + "directoryExists": "Target directory already exists", + "commandFailed": "Project creation command failed." + } + }, + "WebServiceSettings": { + "addressSwitchHint": "Switching only changes the address shown and opened here — the service listens on all interfaces and stays reachable at every address.", + "sectionTitle": "Web Service", + "sectionDescription": "Enable to access Codeg remotely via browser", + "port": "Port", + "status": "Status", + "autoStart": "Auto-start", + "autoStartHint": "Start the Web service when Codeg launches", + "running": "Running", + "stopped": "Stopped", + "processing": "Processing...", + "start": "Start", + "stop": "Stop", + "startFailed": "Failed to start", + "stopFailed": "Failed to stop", + "saveConfigFailed": "Failed to save Web service settings", + "open": "Open", + "hide": "Hide", + "show": "Show", + "copy": "Copy", + "qrcode": "QR Code", + "qrcodeTitle": "Scan to Open", + "qrcodeHint": "Scan with your phone to open Codeg in a browser", + "addressLabel": "Access Address", + "tokenLabel": "Access Token", + "tokenHint": "Enter this token when accessing the Web client for the first time", + "tokenPlaceholder": "Leave empty to auto-generate", + "regenerate": "Regenerate", + "stalePortOccupiedTitle": "Port {port} is held by another process", + "stalePortUnknownTitle": "Port {port} status is unclear", + "stalePortHint": "Codeg can't bind here until the port is released. Change the port above, or close the process holding it.", + "errors": { + "alreadyRunning": "Web service is already running", + "invalidAddress": "Invalid host or port format", + "portInUse": "Port {port} is already in use. Close the process using it or choose another port.", + "permissionDenied": "Permission denied. Try a port above 1024 or run with higher privileges.", + "addressUnavailable": "The address is not available on this machine", + "bindFailed": "Failed to bind address" + } + }, + "DirectoryBrowser": { + "title": "Browse Directory", + "pathPlaceholder": "Enter directory path...", + "goHome": "Go to home directory", + "navigateUp": "Go to parent directory", + "select": "Select", + "cancel": "Cancel", + "loading": "Loading...", + "emptyDirectory": "This directory is empty", + "errorLoadingDir": "Failed to load directory", + "permissionDenied": "Permission denied" + }, + "ServerFileBrowser": { + "title": "Pick server file", + "pathPlaceholder": "Enter directory path...", + "goHome": "Go to home directory", + "navigateUp": "Go to parent directory", + "select": "Select", + "cancel": "Cancel", + "loading": "Loading...", + "emptyDirectory": "This directory is empty", + "errorLoadingDir": "Failed to load directory", + "selectedCount": "{count} selected" + }, + "ChatChannelSettings": { + "loading": "Loading...", + "sectionTitle": "Chat Channels", + "sectionDescription": "Configure IM bots to receive event notifications and query coding activity.", + "addChannel": "Add Channel", + "noChannels": "No chat channels configured yet.", + "channelName": "Name", + "channelNamePlaceholder": "My Telegram Bot", + "channelType": "Channel Type", + "lark": "Lark (Feishu)", + "weixin": "WeChat", + "dailyReport": "Daily Report", + "dailyReportTime": "Report Time", + "nameRequired": "Channel name is required.", + "tokenRequired": "Token is required.", + "chatIdRequired": "Chat ID is required.", + "topicMode": "Topic group mode", + "topicModeHint": "Route Telegram forum topics as separate Codeg sessions. The bot must be in a forum supergroup and be allowed to manage topics.", + "loadFailed": "Failed to load channels.", + "saveFailed": "Failed to save changes.", + "connectSuccess": "Channel connected.", + "connectFailed": "Failed to connect", + "disconnectSuccess": "Channel disconnected.", + "disconnectFailed": "Failed to disconnect.", + "testSuccess": "Connection test passed.", + "testFailed": "Connection test failed", + "deleteSuccess": "Channel deleted.", + "deleteFailed": "Failed to delete channel.", + "deleteConfirmTitle": "Delete Channel", + "deleteConfirmMessage": "This will permanently delete the channel and its message logs. Are you sure?", + "cancel": "Cancel", + "delete": "Delete", + "create": "Create", + "save": "Save", + "channelListTitle": "Configured Channels", + "channelListDescription": "Enabled channels will auto-connect when the service starts.", + "editChannel": "Edit Channel", + "editSuccess": "Channel updated.", + "tokenPlaceholderKeep": "Leave blank to keep current", + "weixinScanTitle": "Scan QR Code", + "weixinScanDescription": "Open WeChat and scan the QR code to connect.", + "weixinQrcodeExpired": "QR code expired.", + "weixinRefreshQrcode": "Refresh", + "weixinWaitingScan": "Waiting for scan...", + "weixinPollError": "Connection unstable, retrying...", + "weixinReconnectNotice": "Due to iLink protocol limitations, after each reconnection you must send a message to the bot before event triggers take effect.", + "connect": "Connect", + "disconnect": "Disconnect", + "test": "Test Connection", + "tabs": { + "channels": "Channels", + "commands": "Commands", + "events": "Events", + "other": "Other" + }, + "commands": { + "title": "Built-in Commands", + "description": "Bot commands available in chat channels. In group chats, @Bot is required to process messages.", + "prefixLabel": "Command Prefix", + "prefixDescription": "1-3 non-alphanumeric characters used to trigger bot commands (default /).", + "prefixSaved": "Command prefix saved.", + "prefixSaveFailed": "Failed to save command prefix.", + "prefixInvalid": "Prefix must be 1-3 non-alphanumeric characters.", + "save": "Save", + "folderDesc": "Select working folder", + "agentDesc": "Select AI agent", + "taskDesc": "Create session and run task", + "sessionsDesc": "List active sessions in folder", + "resumeDesc": "Recent conversations / resume a session", + "cancelDesc": "Cancel current task", + "approveDesc": "Approve agent permission request", + "denyDesc": "Deny agent permission request", + "searchDesc": "Search conversations by keyword", + "todayDesc": "Today's activity summary", + "statusDesc": "Channel connection status", + "helpDesc": "Show help message" + }, + "events": { + "title": "Event Notifications", + "description": "When enabled, triggered events will be pushed to the channel.", + "turnComplete": "Turn Complete", + "turnCompleteDesc": "When an agent turn ends", + "error": "Agent Error", + "errorDesc": "When an agent encounters an error", + "permissionRequest": "Permission Request", + "permissionRequestDesc": "When an agent requests permission to act", + "questionRequest": "Agent Question", + "questionRequestDesc": "When an agent asks you a question", + "userPromptSent": "User Message", + "userPromptSentDesc": "When you send a message — the message text is included in the notification", + "saved": "Event filter updated.", + "saveFailed": "Failed to save event filter.", + "loadFailed": "Failed to load settings.", + "retry": "Retry", + "webhooksTitle": "Webhooks", + "webhooksDescription": "POST a JSON payload to one or more URLs when an enabled event fires. The event filter above also applies to webhooks.", + "webhookUrlPlaceholder": "https://example.com/webhook", + "addWebhook": "Add Webhook", + "removeWebhook": "Remove webhook", + "webhookSave": "Save", + "webhooksSaved": "Webhooks saved.", + "webhooksSaveFailed": "Failed to save webhooks.", + "webhookInvalidUrl": "Enter valid http(s) URLs.", + "docsTitle": "Request Format", + "docsMethod": "Method", + "docsContentType": "Content-Type", + "docsNote": "Each enabled event is delivered to every URL. Webhooks are not debounced; the event filter above still applies.", + "editWebhook": "Edit Webhook", + "enableWebhook": "Enable webhook", + "webhookDuplicate": "This URL is already configured.", + "cancel": "Cancel", + "webhooksEmpty": "No webhooks configured yet.", + "deleteWebhookTitle": "Delete Webhook", + "deleteWebhookMessage": "Remove this webhook? Events will no longer be delivered to this URL.", + "delete": "Delete" + }, + "language": { + "title": "Message Language", + "description": "Language used for event notifications, command responses, and daily reports sent to chat channels.", + "saved": "Message language saved.", + "saveFailed": "Failed to save message language.", + "en": "English", + "zh-cn": "Simplified Chinese", + "zh-tw": "Traditional Chinese", + "ja": "Japanese", + "ko": "Korean", + "es": "Spanish", + "de": "German", + "fr": "French", + "pt": "Portuguese", + "ar": "Arabic" + } + }, + "ModelProviderSettings": { + "sectionTitle": "Model Providers", + "sectionDescription": "Manage API provider credentials for agents.", + "filterAll": "All", + "providerListTitle": "Configured Providers", + "addProvider": "Add Provider", + "editProvider": "Edit Provider", + "noProviders": "No model providers configured yet.", + "providerName": "Name", + "providerNamePlaceholder": "e.g. OpenAI, Anthropic", + "apiUrl": "API URL", + "apiUrlPlaceholder": "https://api.openai.com/v1", + "apiKey": "API Key", + "apiKeyPlaceholder": "sk-...", + "apiKeyKeepCurrent": "Leave blank to keep current", + "agentTypes": "Agent Types", + "agentTypesRequired": "At least one agent type is required.", + "agentType": "Agent Type", + "agentTypeRequired": "Agent type is required.", + "agentTypeImmutableHint": "Agent type cannot be changed after creation.", + "model": "Model", + "modelPlaceholderCodex": "gpt-5.6-sol / gpt-5.5", + "modelPlaceholderGemini": "gemini-3-pro-preview", + "claudeMainModel": "Main Model", + "claudeReasoningModel": "Reasoning Model (thinking)", + "claudeHaikuDefaultModel": "Default Haiku Model", + "claudeSonnetDefaultModel": "Default Sonnet Model", + "claudeOpusDefaultModel": "Default Opus Model", + "claudeCustomModelOption": "Custom Model ID", + "claudeCustomModelOptionName": "Custom Model Name", + "claudeCustomModelOptionDescription": "Custom Model Description", + "claudeCustomModelOptionHint": "Adds a single custom entry to Claude's model picker (e.g. a model behind a custom gateway/proxy). Name and description are optional display overrides.", + "nameRequired": "Provider name is required.", + "apiUrlRequired": "API URL is required.", + "apiKeyRequired": "API Key is required.", + "loadFailed": "Failed to load providers.", + "saveFailed": "Failed to save changes.", + "createSuccess": "Provider created.", + "editSuccess": "Provider updated.", + "deleteSuccess": "Provider deleted.", + "deleteConfirmTitle": "Delete Provider", + "deleteConfirmMessage": "This will permanently delete the provider \"{name}\". Are you sure?", + "deleteBlockedByAgent": "{agents} is currently using this provider. Please unlink before deleting.", + "cancel": "Cancel", + "delete": "Delete", + "create": "Create", + "save": "Save", + "affectedRunningSessions": "{count, plural, one {# running session needs to reconnect to apply the change} other {# running sessions need to reconnect to apply the change}}" + }, + "SkillMatrix": { + "loading": "Loading…", + "searchPlaceholder": "Search by name, id, or description", + "empty": "Nothing to show.", + "emptySearch": "No matches for the current search.", + "skillColumn": "Skill", + "selectAll": "Select all visible", + "selectSkill": "Select {name}", + "everything": { + "label": "Bulk", + "enable": "Enable everything (visible)", + "disable": "Disable everything (visible)" + }, + "columnMenu": { + "enableAll": "Enable all skills", + "disableAll": "Disable all skills" + }, + "rowMenu": { + "label": "Batch actions for {name}", + "enableAll": "Enable for all agents", + "disableAll": "Disable for all agents" + }, + "bulk": { + "selected": "{count} selected", + "targetAll": "All agents", + "targetSome": "{count} agents", + "enable": "Enable", + "disable": "Disable", + "clear": "Clear" + }, + "confirm": { + "disableTitle": "Disable these links?", + "disableBody": "This removes {count} codeg-managed skill link(s). Skills occupying a custom directory are left untouched. You can re-enable them anytime.", + "cancel": "Cancel", + "confirm": "Disable" + }, + "toasts": { + "loadFailed": "Failed to load skill statuses", + "applyFailed": "Failed to apply changes", + "enabled": "Enabled {count} link(s)", + "disabled": "Disabled {count} link(s)", + "enabledPartial": "Enabled {ok}, {failed} failed", + "disabledPartial": "Disabled {ok}, {failed} failed" + }, + "detail": { + "enableForAgents": "Enable for agents", + "preview": "SKILL.md preview", + "loadingContent": "Loading content…" + }, + "copyModeHint": "Copied (not linked) — re-enable after updates for the latest version" + }, + "ExpertsSettings": { + "title": "Expert Skills", + "description": "Enable curated, battle-tested skill workflows for your AI coding agents. Each expert is a standalone skill from the superpowers project — codeg manages the central copy and links it into the agents you choose.", + "loading": "Loading experts…", + "loadingContent": "Loading content…", + "emptyExperts": "No experts available. Check the application logs.", + "emptySelection": "Select an expert to see its content and manage activation.", + "emptySearch": "No experts match the current search.", + "searchPlaceholder": "Search experts by name, id, or description", + "enableForAgents": "Enable for agents", + "noAgents": "No ACP agents detected.", + "copyModeWarning": "Copied (not linked). Re-enable after codeg updates to get the latest version.", + "previewTitle": "SKILL.md preview", + "categories": { + "discovery": "Discovery & Design", + "planning": "Planning", + "execution": "Execution", + "quality": "Quality & Testing", + "debugging": "Debugging", + "review": "Review & Integration", + "meta": "Meta" + }, + "states": { + "not_linked": "Not enabled", + "linked_to_codeg": "Enabled", + "linked_elsewhere": "Blocked — another link exists", + "blocked_by_real_directory": "Blocked — a custom skill occupies this name", + "broken": "Broken link" + }, + "badges": { + "userModified": "User modified" + }, + "actions": { + "openCentralDir": "Open central folder", + "refresh": "Refresh" + }, + "toasts": { + "loadFailed": "Failed to load expert details", + "enabled": "Expert enabled for this agent", + "disabled": "Expert disabled for this agent", + "enableFailed": "Failed to enable expert", + "disableFailed": "Failed to disable expert", + "openFolderFailed": "Failed to open folder" + } + }, + "ScienceSettings": { + "title": "Scientific Research Skills", + "description": "Enable curated scientific-research skills for your AI coding agents — hypothesis generation, experimental design, statistics, visualization, critical appraisal, and literature search. codeg manages a central copy and links each skill into the agents you choose.", + "loading": "Loading science skills…", + "emptySkills": "No science skills available. Check the application logs.", + "searchPlaceholder": "Search science skills by name, id, or description", + "categories": { + "ideation": "Ideation", + "design": "Study Design", + "analysis": "Analysis", + "visualization": "Visualization", + "evaluation": "Evaluation", + "literature": "Literature" + }, + "states": { + "not_linked": "Not enabled", + "linked_to_codeg": "Enabled", + "linked_elsewhere": "Blocked — another link exists", + "blocked_by_real_directory": "Blocked — a custom skill occupies this name", + "broken": "Broken link" + }, + "badges": { + "userModified": "User modified", + "needsKey": "Needs API key", + "needsSetup": "May need setup" + }, + "actions": { + "openCentralDir": "Open central folder", + "refresh": "Refresh" + }, + "toasts": { + "openFolderFailed": "Failed to open folder" + } + }, + "OfficeToolsSettings": { + "title": "Office Tools", + "description": "Manage OfficeCLI skills for creating Excel, Word, and PowerPoint files. Install OfficeCLI, sync skills, and enable them per agent.", + "loadingContent": "Loading content…", + "emptySkills": "No skills available. Install OfficeCLI and sync skills to get started.", + "emptySelection": "Select a skill to see its content and manage activation.", + "emptySearch": "No skills match the current search.", + "searchPlaceholder": "Search skills by name, id, or description", + "enableForAgents": "Enable for agents", + "noAgents": "No ACP agents detected.", + "installFirst": "Install OfficeCLI first to enable skills for agents.", + "syncFirst": "Sync skills first to load this skill's content.", + "noContent": "No content available.", + "copyModeWarning": "Copied (not linked). Re-sync to get the latest version.", + "previewTitle": "SKILL.md preview", + "detection": { + "installed": "Installed", + "notInstalled": "Not installed", + "notRunnable": "Installed but not runnable", + "installHint": "Install OfficeCLI to enable office document generation skills for your AI agents.", + "install": "Install", + "uninstall": "Uninstall", + "syncSkills": "Sync Skills" + }, + "categories": { + "general": "General", + "presentations": "Presentations", + "documents": "Documents", + "spreadsheets": "Spreadsheets" + }, + "states": { + "not_linked": "Not enabled", + "linked_to_codeg": "Enabled", + "linked_elsewhere": "Blocked — another link exists", + "blocked_by_real_directory": "Blocked — a custom skill occupies this name", + "broken": "Broken link" + }, + "badges": { + "notSynced": "Not synced" + }, + "actions": { + "refresh": "Refresh" + }, + "toasts": { + "loadFailed": "Failed to load skill details", + "enabled": "Skill enabled for this agent", + "disabled": "Skill disabled for this agent", + "enableFailed": "Failed to enable skill", + "disableFailed": "Failed to disable skill", + "installSuccess": "OfficeCLI installed successfully", + "installFailed": "Failed to install OfficeCLI", + "uninstallSuccess": "OfficeCLI uninstalled", + "uninstallFailed": "Failed to uninstall OfficeCLI", + "syncSuccess": "{synced} skills synced successfully", + "syncPartial": "{synced} skills synced, {errors} failed", + "syncFailed": "Failed to sync skills" + }, + "autoPreviewLabel": "Auto-open preview", + "autoPreviewHint": "When an agent creates or edits a Word, Excel, or PowerPoint file, open its live preview automatically." + }, + "SkillPacksSettings": { + "title": "Skill Packs", + "description": "Curated skill bundles that codeg manages centrally and links into your AI agents — coding experts, scientific research, and office document tools. Enable them per agent below.", + "tabs": { + "experts": "Experts", + "science": "Science", + "office": "Office Tools", + "custom": "Custom" + }, + "actions": { + "openCentralDir": "Open central folder", + "refresh": "Refresh" + }, + "toasts": { + "openFolderFailed": "Failed to open folder" + } + }, + "QuickMessagesSettings": { + "title": "Quick Messages", + "description": "Manage reusable message snippets. Drag to reorder.", + "loading": "Loading quick messages…", + "emptyList": "No quick messages yet. Click \"New\" to create one.", + "emptySelection": "Select a quick message to edit.", + "searchPlaceholder": "Search by title or content", + "untitled": "Untitled", + "actions": { + "new": "New", + "save": "Save", + "delete": "Delete", + "dragSort": "Drag to reorder", + "dragSortMessage": "Drag to reorder quick message: {name}" + }, + "fields": { + "title": "Title", + "titlePlaceholder": "Give this message a short title", + "content": "Content", + "contentPlaceholder": "Write the message content here" + }, + "confirmDelete": { + "title": "Delete quick message?", + "message": "This will permanently delete \"{name}\". Are you sure?", + "cancel": "Cancel", + "confirm": "Delete" + }, + "toasts": { + "loadFailed": "Failed to load quick messages", + "createFailed": "Failed to create quick message", + "saveFailed": "Failed to save quick message", + "deleteFailed": "Failed to delete quick message", + "saveOrderFailed": "Failed to save order", + "created": "Quick message created", + "saved": "Quick message saved", + "deleted": "Quick message deleted" + } + }, + "Pet": { + "badge": { + "running": "{count} running", + "waiting": "{count} awaiting approval", + "error": "{count} errored" + }, + "panel": { + "title": "Active sessions", + "empty": "No active sessions", + "emptyHint": "Running agents and ones that need you appear here.", + "statusRunning": "Running", + "statusWaiting": "Waiting", + "statusError": "Error", + "subAgentOf": "Sub-agent of" + }, + "menu": { + "scale": "Scale", + "openManager": "Manage pets", + "close": "Close" + }, + "loadError": "Failed to load pet", + "missingPetIdParam": "No pet selected", + "summonButton": "Pet", + "manager": { + "title": "Pets", + "description": "Floating desktop companions powered by Codex-compatible sprite sheets.", + "addPet": "Add pet", + "importFromCodex": "Import from Codex", + "noPets": "No pets yet. Add one or import from Codex.", + "setActive": "Set active", + "active": "Active", + "edit": "Edit", + "delete": "Delete", + "deleteConfirm": "Delete pet \"{name}\"? It will be removed from disk.", + "summon": "Summon pet window", + "openCodexHelp": "Codex pets must be installed under ~/.codex/pets/. None found.", + "specRequirement": "Spritesheet must be 1536px wide with a height in 208px rows (e.g. 1872 or 2288), PNG or WebP with transparency.", + "form": { + "id": "Pet ID", + "idHelp": "Lowercase letters, digits, '-' and '_'. Max 64 chars.", + "displayName": "Display name", + "description": "Description (optional)", + "spritesheet": "Spritesheet", + "chooseFile": "Choose file", + "replaceFile": "Replace spritesheet", + "saveCreate": "Add pet", + "saveUpdate": "Save changes", + "cancel": "Cancel" + }, + "errors": { + "missingId": "Pet id is required", + "missingName": "Display name is required", + "missingSpritesheet": "Spritesheet is required", + "addFailed": "Failed to add pet", + "updateFailed": "Failed to update pet", + "deleteFailed": "Failed to delete pet", + "loadFailed": "Failed to load pets", + "setActiveFailed": "Failed to set active pet", + "summonFailed": "Failed to summon pet window" + } + }, + "import": { + "title": "Import from Codex", + "subtitle": "These pets are available under ~/.codex/pets/.", + "selectAll": "Select all", + "alreadyImported": "Already imported", + "renameOnConflict": "Rename conflicts with -imported suffix", + "import": "Import selected", + "noneFound": "No importable Codex pets found.", + "imported": "Imported successfully", + "failed": "Import failed", + "close": "Close" + }, + "marketplace": { + "openMarketplace": "Pet marketplace", + "title": "Pet marketplace", + "search": "Search pets", + "kindFilter": { + "all": "All", + "object": "Object", + "animal": "Animal", + "person": "Person", + "creature": "Creature" + }, + "sortFilter": { + "latest": "Latest", + "popular": "Popular", + "views": "Most viewed" + }, + "refresh": "Refresh", + "install": "Install", + "installing": "Installing", + "reinstall": "Reinstall", + "reinstallConfirm": "Replace local pet \"{name}\"? Existing data will be overwritten.", + "cancel": "Cancel", + "stats": { + "views": "Views", + "downloads": "Downloads", + "likes": "Likes" + }, + "actions": { + "idle": "Idle", + "running_right": "Run right", + "running_left": "Run left", + "waving": "Wave", + "jumping": "Jump", + "failed": "Fail", + "waiting": "Wait", + "running": "Run", + "review": "Review" + }, + "page": "Page {page} of {total}", + "prev": "Previous", + "next": "Next", + "empty": "No pets match this filter.", + "successInstalled": "Installed \"{name}\"", + "errors": { + "loadFailed": "Failed to load marketplace", + "installFailed": "Failed to install pet", + "alreadyInstalled": "Pet already exists locally" + } + } + }, + "RemoteWorkspace": { + "openRemoteWorkspace": "Open remote workspace", + "manage": "Manage remote workspace", + "manageTitle": "Remote Workspace connections", + "empty": "No remote connections", + "searchPlaceholder": "Search remote workspaces", + "orderFailed": "Failed to save remote workspace order", + "dragSort": "Drag to sort", + "dragSortConnection": "Drag to sort {name}", + "newConnection": "New connection", + "loading": "Loading", + "loadingConnection": "Loading remote connection", + "name": "Name", + "baseUrl": "Service URL", + "token": "Access token", + "save": "Save", + "delete": "Delete", + "confirmDelete": { + "title": "Delete remote connection?", + "message": "This will remove \"{name}\" from this device. This action cannot be undone.", + "cancel": "Cancel", + "confirm": "Delete" + }, + "saved": "Remote connection saved.", + "deleted": "Remote connection deleted.", + "loadFailed": "Failed to load remote connections", + "saveFailed": "Failed to save remote connection", + "deleteFailed": "Failed to delete remote connection", + "openFailed": "Failed to open remote workspace", + "connectionLoadFailed": "Failed to load remote connection: {message}", + "connectionExpired": "Remote connection \"{name}\" is expired. Update its token and reload this window." + }, + "BackupSettings": { + "title": "Backup & Restore", + "description": "Export a portable backup of your codeg data, or restore from one.", + "tabs": { + "backup": "Backup", + "restore": "Restore" + }, + "export": { + "includeExternal": "Include conversation content", + "includeExternalHint": "Also archive agent CLI transcripts (Claude, Codex, Gemini, …). Increases size.", + "passphrase": "Passphrase (optional)", + "passphrasePlaceholder": "Leave empty for an unencrypted archive", + "passphraseConfirm": "Confirm passphrase", + "passphraseMismatch": "Passphrases do not match.", + "noPassphraseWarning": "This backup will contain secrets (API keys, tokens) in plaintext. Store it somewhere safe.", + "passphraseLossWarning": "Encrypted with this passphrase. If you lose it, the backup cannot be recovered.", + "button": "Export backup", + "inProgress": "Creating backup…", + "success": "Backup created.", + "started": "Backup download started." + }, + "restore": { + "selectFile": "Select backup file", + "passphrasePrompt": "This backup is encrypted. Enter its passphrase.", + "unlock": "Unlock", + "preview": { + "title": "Backup details", + "encrypted": "Encrypted", + "compatible": "Compatible", + "incompatible": "Incompatible", + "createdAt": "Created: {value}", + "appVersion": "App version: {value}", + "incompatibleHint": "This backup was created by a newer version of codeg and cannot be restored." + }, + "replaceWarning": "Restoring replaces all current codeg data (database and uploads). Your current data is snapshotted first so it can be recovered.", + "keyringNote": "Desktop GitHub/chat tokens live in your OS keychain and are not included; re-enter them after restoring.", + "button": "Restore", + "staging": "Preparing restore…", + "staged": "Restore staged. Restarting…", + "restarting": "Restore staged. Restarting the server…", + "restartTimeout": "The server did not come back in time. Reload the page once it is up.", + "externalSideLocation": "Conversation transcripts were restored to {path}", + "confirmTitle": "Replace all data?", + "confirmBody": "This will replace your current codeg database and uploads with the backup, then restart. Your current data is snapshotted first.", + "cancel": "Cancel", + "confirmAction": "Replace & restart", + "external": { + "title": "Conversation content", + "hint": "This backup includes agent CLI transcripts. Choose where to restore them.", + "modeSkip": "Don't restore", + "modeSide": "Restore to a safe side folder", + "modeOriginal": "Restore to original CLI locations", + "forceOverwrite": "Overwrite existing files", + "forceOverwriteHint": "Replace files that already exist in the agent CLI folders.", + "scanning": "Checking for conflicts…", + "noConflicts": "No existing files would be overwritten.", + "conflictCount": "{count} existing file(s) would be affected.", + "conflictSkipNote": "Existing files are kept (skipped) unless you enable overwrite." + }, + "restartFailed": "Restore staged, but the server couldn't restart. Restart it manually to apply the restore." + }, + "remoteUnsupported": "Backup & restore acts on the data of the machine running codeg. You're connected to a remote workspace — manage its backups from that server directly." + }, + "backup": { + "restore": { + "error": { + "badPassphrase": "Incorrect passphrase or corrupted backup.", + "corrupted": "The backup archive is corrupted.", + "unknownFormat": "This file is not a recognized codeg backup.", + "newerVersion": "This backup was created by codeg {backupVersion}, newer than this version ({appVersion}).", + "alreadyPending": "A restore is already staged. Restart to apply it before staging another." + } + }, + "error": { + "diskSpace": "Not enough disk space to complete the operation.", + "cancelled": "The operation was cancelled." + } + }, + "WebConnection": { + "disconnectedTitle": "Connection lost", + "reconnectingDescription": "Trying to reconnect to the server. This usually recovers on its own within a few seconds.", + "reconnectNow": "Reconnect now", + "sessionExpiredTitle": "Session expired", + "sessionExpiredDescription": "Your session is no longer valid. Please sign in again to continue.", + "goToLogin": "Go to login" + }, + "LiveFeedback": { + "placeholder": "Send a note to {agent} while it works…", + "agentFallback": "the agent", + "ariaLabel": "Live feedback note", + "dialogTitle": "Live feedback", + "dialogDescription": "Send a note to the agent while it works. It reads your note the next time it checks — without interrupting the current step.", + "dialogDescriptionInstant": "Send a note to the agent while it works. It lands in the current turn immediately — the agent sees it right away.", + "channelDowngraded": "Instant insert isn't available in this session — your note was saved for the agent to pick up on its next check.", + "send": "Send", + "cancel": "Cancel", + "pending": "waiting", + "delivered": "received", + "turnEndedUnread": "The agent finished before reading your feedback.", + "sendAsMessage": "Send as message", + "dismiss": "Dismiss", + "turnEndedResent": "The turn ended — sent as a new message instead.", + "turnEnded": "The turn already ended.", + "submitFailed": "Couldn't send your note" + }, + "AgentToolsSettings": { + "title": "In-conversation tools", + "description": "Extra tools codeg gives an agent inside a conversation. Each is injected when the agent starts, so a change applies to agents started afterwards.", + "feedbackLabel": "Live Feedback", + "feedbackHint": "Send notes and corrections to an agent while it's working. When the agent supports instant steering, your note is inserted into the running turn immediately; otherwise the agent gets a tool to check for your feedback — those agents typically only check when you mention it in your prompt, for example add \"check my live feedback regularly\" to your message.", + "questionLabel": "Ask user question", + "questionHint": "Let agents pause and ask you a multiple-choice question that appears above the conversation input box. The agent waits until you answer (or skip).", + "sessionInfoLabel": "Get session info", + "sessionInfoHint": "Let agents look up a session you reference in your message (a session badge) to read its title, agent, status, workspace, token usage, and recent messages.", + "automationsLabel": "Create automations", + "automationsHint": "Save the conversation as an automation that runs on a schedule. Off by default — it goes on to start agents on its own.", + "workTasksLabel": "Create to-do tasks", + "workTasksHint": "Queue a card on the to-do board from the conversation. Off by default — it writes app state.", + "save": "Save", + "saving": "Saving…", + "saved": "Tool settings saved", + "saveFailed": "Failed to save tool settings", + "loadFailed": "Failed to load: {detail}" + }, + "NotificationSoundSettings": { + "title": "Notification sounds", + "description": "Play a short sound when an agent event fires. These are the same events the chat channels push — configured here for this device only.", + "enableHint": "Off by default. Sounds play in the workspace window of this browser or app only.", + "volume": "Volume", + "preview": "Preview", + "previewEvent": "Preview the {event} sound", + "onlyWhenUnfocused": "Only when the window is not focused", + "onlyWhenUnfocusedHint": "Stay silent while you are looking at Codeg.", + "eventsTitle": "Events", + "eventsHint": "Pick a tone per event, or “Silent” to skip it. Repeats of the same event within a couple of seconds play once.", + "toneNone": "Silent", + "toneChime": "Chime", + "toneDing": "Ding", + "toneBlip": "Blip", + "tonePop": "Pop", + "toneAlert": "Alert", + "toneDescend": "Descending" + }, + "LogsSettings": { + "loading": "Loading…", + "sectionTitle": "Runtime Logs", + "sectionDescription": "View and configure application diagnostic logs. Logs are written to local files and kept in memory for live viewing.", + "captureTitle": "Log level", + "captureDescription": "Controls how much detail is captured. Higher levels (Debug, Trace) record more but produce larger logs. Off disables logging.", + "captureLabel": "Capture level", + "levels": { + "off": "Off", + "error": "Error", + "warn": "Warning", + "info": "Info", + "debug": "Debug", + "trace": "Trace" + }, + "viewerTitle": "Recent logs", + "viewerDescription": "Live view of recent log records. Filter by level or search text.", + "searchPlaceholder": "Search message or target…", + "viewLevels": { + "all": "All levels", + "error": "Error+", + "warn": "Warning+", + "info": "Info+", + "debug": "Debug+", + "trace": "Trace+" + }, + "pause": "Pause", + "resume": "Live", + "refresh": "Refresh", + "clear": "Clear", + "openFolder": "Open folder", + "shownCount": "{shown} / {total} shown", + "empty": "No logs to display.", + "levelSaveFailed": "Failed to save log level", + "openFolderFailed": "Failed to open log folder", + "downloadFailed": "Failed to download log file", + "filesTitle": "Log files", + "filesDescription": "Download full log files from disk for history beyond the live buffer.", + "filesEmpty": "No log files yet.", + "download": "Download", + "downloadTruncated": "File is large; downloaded the latest {size}. The full file is in the logs directory.", + "captureEnvLocked": "Log level is controlled by the RUST_LOG / CODEG_LOG environment variable; change it there to take effect.", + "targetsTitle": "Per-module overrides", + "targetsDescription": "Set a different level for specific modules (e.g. codeg_lib::acp) without changing the global level.", + "targetsAdd": "Add", + "targetsRemove": "Remove override", + "toggleDetails": "Toggle details" + }, + "Automations": { + "title": "Automations", + "new": "New automation", + "empty": "No automations yet", + "emptyHint": "Create one to run an agent task on a schedule or on demand.", + "name": "Name", + "namePlaceholder": "e.g. Nightly PR review", + "prompt": "Prompt", + "promptPlaceholder": "What should the agent do?", + "agent": "Agent", + "folder": "Workspace folder", + "folderPlaceholder": "Select a folder", + "isolation": "Isolation", + "isolationWorktree": "New worktree per run", + "isolationShared": "Run in the folder", + "isolationSharedCaveat": "Runs use this folder's working tree directly — they can collide with your uncommitted changes. Enable the worktree option to isolate each run.", + "trigger": "Trigger", + "triggerSchedule": "On a schedule", + "triggerManual": "Manual only", + "cron": "Schedule (cron)", + "cronPlaceholder": "0 9 * * 1-5", + "timezone": "Timezone", + "nextRun": "Next run", + "branch": "Branch", + "branchOptional": "Branch (optional)", + "enabled": "Enabled", + "save": "Save", + "cancel": "Cancel", + "edit": "Edit", + "delete": "Delete", + "runNow": "Run now", + "cancelRun": "Cancel run", + "runHistory": "Run history", + "noRuns": "No runs yet", + "allFolders": "All folders", + "filterAll": "All", + "noMatches": "No matching automations", + "viewConversation": "View conversation", + "lastRun": "Last run", + "never": "Never", + "running": "Running", + "deleteTitle": "Delete automation?", + "deleteDescription": "This removes the automation and its schedule. Run history is kept.", + "statusRunning": "Running", + "statusSucceeded": "Succeeded", + "statusFailed": "Failed", + "statusCancelled": "Cancelled", + "statusSkipped": "Skipped", + "errorName": "Name is required", + "errorPrompt": "Prompt is required", + "errorCron": "A cron expression is required for scheduled automations", + "errorFolder": "Select a workspace folder", + "presetHourly": "Hourly", + "presetDaily": "Daily 9am", + "presetWeekdays": "Weekdays 9am", + "presetCustom": "Custom", + "probing": "Loading options…", + "retry": "Retry", + "configNone": "This agent has no configurable options", + "inherit": "Agent default", + "mode": "Mode", + "config": "Configuration", + "branchPlaceholder": "(default branch)", + "selectHint": "Select an automation to see details", + "refresh": "Refresh", + "onboardTitle": "Automate routine agent tasks", + "onboardHint": "Schedule an agent to review code, update dependencies, or triage issues — on a cadence or on demand.", + "headerSubtitle": "Scheduled and on-demand agent tasks", + "startFromTemplate": "Start from a template", + "blankTitle": "Blank automation", + "blankDesc": "Configure an agent task from scratch.", + "backToTemplates": "Templates", + "sectionSchedule": "Schedule & target", + "sectionTarget": "Target", + "sectionAction": "Action", + "actionLaunchSession": "Launch session", + "actionEnqueueTask": "Enqueue task", + "actionEnqueueTaskHint": "Each fire adds a to-do task titled after this automation to the folder's to-dos; the task engine runs it per the board's settings.", + "sectionPrompt": "Prompt", + "nextIn": "Next in {rel}", + "manual": "Manual", + "schedEveryMinutes": "Every {n} minutes", + "schedHourly": "Hourly", + "schedDaily": "Daily at {time}", + "schedWeekdays": "Weekdays at {time}", + "schedWeekly": "Every {day} at {time}", + "schedMonthly": "Monthly on day {day} at {time}", + "dow0": "Sunday", + "dow1": "Monday", + "dow2": "Tuesday", + "dow3": "Wednesday", + "dow4": "Thursday", + "dow5": "Friday", + "dow6": "Saturday", + "tplCodeReviewTitle": "Code review", + "tplCodeReviewDesc": "Review recent changes for bugs, regressions, and quality issues.", + "tplDependencyUpdatesTitle": "Dependency updates", + "tplDependencyUpdatesDesc": "Find outdated dependencies and propose safe upgrades.", + "tplTestCoverageTitle": "Test coverage", + "tplTestCoverageDesc": "Find untested code paths and add the missing tests.", + "tplTodoSweepTitle": "TODO sweep", + "tplTodoSweepDesc": "Collect TODO and FIXME comments and triage them by priority.", + "tplCiTriageTitle": "CI triage", + "tplCiTriageDesc": "Investigate recent failing checks and propose fixes.", + "tplReleaseNotesTitle": "Release notes", + "tplReleaseNotesDesc": "Summarize changes since the last release into a changelog.", + "tplSecurityAuditTitle": "Security audit", + "tplSecurityAuditDesc": "Scan for vulnerabilities and risky patterns, then report findings.", + "enable": "Enable", + "disable": "Disable", + "moreActions": "More actions", + "statusDisabled": "Disabled", + "cronBuilderTitle": "Schedule builder", + "cronFreqLabel": "Frequency", + "cronFreqMinutes": "Every N minutes", + "cronFreqHourly": "Hourly", + "cronFreqDaily": "Daily", + "cronFreqWeekdays": "Weekdays", + "cronFreqWeekly": "Weekly", + "cronFreqMonthly": "Monthly", + "cronFreqCustom": "Custom", + "cronEveryLabel": "Interval (minutes)", + "cronTimeLabel": "Time", + "cronHourLabel": "Hour", + "cronMinuteLabel": "Minute", + "cronDowLabel": "Day of week", + "cronDomLabel": "Day of month", + "cronApply": "Apply", + "cronPreviewLabel": "Preview", + "cronOpenBuilder": "Open schedule builder", + "branchDefault": "Default branch", + "branchUseCustom": "Use \"{query}\"", + "branchLocal": "Local", + "branchRemote": "Remote", + "branchSearchPlaceholder": "Search branches…", + "branchNone": "No branches" + }, + "Tasks": { + "title": "To-dos", + "new": "New task", + "empty": "No tasks yet", + "emptyHint": "Add a to-do, then run it — the agent works in an isolated worktree and you review and merge the result.", + "emptyColTodo": "No to-dos yet", + "emptyColInProgress": "Nothing in progress", + "emptyColAttention": "Nothing needs you right now", + "emptyColDone": "Nothing done yet", + "allFolders": "All folders", + "showCanceled": "Show canceled", + "showArchived": "Show archived", + "filter": "Filter", + "viewSwitchToBoard": "Switch to board view", + "viewSwitchToList": "Switch to list view", + "statusFilter": "Status", + "statusFilterAll": "All statuses", + "listEmpty": "No tasks match the current filters", + "listColStatus": "Status", + "listColTask": "Task", + "listColLocation": "Location", + "listColChanges": "Changes", + "listColUpdated": "Updated", + "colTodo": "To do", + "colInProgress": "In progress", + "colAttention": "Needs you", + "colDone": "Done", + "statusTodo": "To do", + "statusQueued": "Queued", + "statusPreparing": "Setting up", + "statusRunning": "Running", + "statusAwaitingInput": "Awaiting input", + "statusReview": "To review", + "statusMerging": "Merging", + "statusDone": "Done", + "statusFailed": "Failed", + "statusCanceled": "Canceled", + "statusInterrupted": "Interrupted", + "badgeCleanupFailed": "Cleanup failed", + "badgeWorktreeKept": "Worktree kept", + "badgeWorktreeRemoved": "Worktree removed", + "filesChanged": "{count} files", + "actionStart": "Start", + "actionSchedule": "Schedule", + "actionCancel": "Cancel", + "actionRetry": "Retry", + "actionRequeue": "Requeue", + "actionViewSession": "View session", + "actionEdit": "Edit", + "actionDelete": "Delete", + "actionRetryCleanup": "Retry cleanup", + "actionMerge": "Merge", + "actionUnqueueMerge": "Leave merge queue", + "actionEditQueuedMerge": "Edit queued merge", + "badgeMergeQueued": "Queued to merge", + "badgeMergeQueuedRank": "Queued to merge · #{rank}", + "badgeMergeQueuedHint": "Waiting for the project's current merge to finish; this one starts on its own.", + "actionComplete": "Complete", + "actionAbandon": "Abandon", + "cancelTitle": "Cancel task?", + "cancelDescription": "The task moves to Canceled. Its worktree is kept, and you can requeue it later.", + "cancelReasonLabel": "Reason (optional)", + "cancelReasonPlaceholder": "e.g. wrong approach — I'll rewrite the description", + "cancelKeep": "Never mind", + "cancelSubmit": "Cancel task", + "restartTitleRetry": "Retry task", + "restartTitleRequeue": "Requeue task", + "restartDescription": "Add a note for the agent (optional) — it reaches the prompt of the next run.", + "scheduleTitle": "Schedule task", + "scheduleDescription": "The task stays in To do and starts on its own at the time you pick. The folder's concurrency limit still applies.", + "scheduleDateLabel": "Date", + "schedulePickDate": "Select date", + "scheduleTimeLabel": "Time", + "schedulePreview": "Runs at {time}", + "schedulePastHint": "That time has passed — the task starts as soon as you save.", + "scheduleInAnHour": "In 1 hour", + "scheduleInThreeHours": "In 3 hours", + "scheduleTomorrow": "Tomorrow 9:00", + "scheduleClear": "Clear schedule", + "scheduleBadge": "Scheduled to start at {time}", + "toastScheduled": "Scheduled for {time}", + "toastScheduleCleared": "Schedule cleared", + "actionFollowUp": "Follow up", + "actionAddNote": "Add a note", + "followUpSubmit": "Send", + "followUpIntentRevise": "Rework", + "followUpIntentContinue": "Keep going", + "followUpIntentQuestion": "Ask", + "followUpIntentVerify": "Double-check", + "followUpPlaceholderRevise": "What should the agent change? It continues in the same session.", + "followUpPlaceholderContinue": "What's next? The work so far stays as it is.", + "followUpPlaceholderQuestion": "What do you want to know? The agent answers without touching any file.", + "followUpPlaceholderVerify": "Optional: anything it should look at closely?", + "followUpPlaceholderRetry": "Optional: what should it do differently? e.g. run pnpm install first", + "followUpPlaceholderRequeue": "Optional: why did you cancel it, and what should change this time?", + "actionArchive": "Archive", + "actionUnarchive": "Unarchive", + "archiveAllDone": "Archive all", + "dropToStart": "Release to start", + "errorView": "View", + "notifyReview": "Ready for review: {title}", + "notifyFailed": "Task failed: {title}", + "createFromMessage": "Create task from message", + "detailTokens": "Total tokens", + "editorTitleNew": "New task", + "editorTitleEdit": "Edit task", + "templates": "Templates", + "templatesEmpty": "No templates yet.", + "templateSaveCurrent": "Save current as template", + "templateDelete": "Delete template", + "transcriptTitle": "Task session", + "transcriptDescription": "Read-only live view of the task's agent session.", + "phaseWork": "Task run", + "phaseRetry": "Retry run", + "phaseReturn": "Follow-up", + "phaseMerge": "Merge", + "titleLabel": "Title", + "titlePlaceholder": "What needs to be done?", + "promptLabel": "Task description", + "promptPlaceholder": "Describe the task for the agent — @ to reference files, / for commands", + "folderPlaceholder": "Select a folder", + "agentInheritedHint": "Inherited from task settings — change it to override for this task", + "agentOverrideReset": "Reset to inherited", + "sectionTarget": "Target", + "errorTitle": "Title is required", + "errorPrompt": "Task description is required", + "errorFolder": "Select a folder", + "save": "Save", + "cancel": "Cancel", + "mergeTitle": "Merge task", + "mergeQueuedTitle": "Queued merge", + "mergeQueueHint": "Another task of this project is merging right now. This one joins the queue and starts on its own as soon as that one finishes.", + "mergeQueueUpdateHint": "This task is already waiting to merge. Submitting updates it and keeps its place in the queue.", + "mergeDescription": "Merge {branch} into {base}. Uncommitted changes in the worktree are committed first.", + "mergeMessage": "Commit message", + "mergeMessagePlaceholder": "e.g. feat: add login validation", + "mergeAutoMessage": "Let the agent write the commit message", + "strategySquash": "Combine into one commit", + "strategySquashHint": "All the task's changes land in the main branch as a single history entry — a tidier history.", + "strategyMerge": "Keep full history", + "strategyMergeHint": "Every commit made during the task is kept, plus one merge entry — each step stays traceable.", + "mergeDeleteWorktree": "Delete worktree after merge", + "mergeSubmit": "Merge", + "mergeSubmitQueue": "Add to merge queue", + "mergeQueuedToast": "Added to the merge queue — it starts as soon as the current merge finishes.", + "completeTitle": "Complete task", + "completeDescription": "This task changed no files, so there is nothing to merge — it is marked as done directly.", + "completeDescriptionNoWorktree": "This task's worktree has been removed, so there is no merge to run — it is marked as done directly. A work branch that still holds unmerged commits is kept.", + "completeDeleteWorktree": "Delete the worktree after completing", + "completeSubmit": "Complete", + "settingsTitle": "Task settings", + "settingsDescription": "Defaults for tasks in {folder}.", + "settingsScope": "Scope", + "settingsScopeGlobal": "All folders (global defaults)", + "settingsScopeGlobalHint": "Folders without their own settings use these global defaults.", + "settingsSource": "Configuration", + "settingsSourceGlobal": "Global defaults", + "settingsSourceCustom": "Custom", + "settingsSourceGlobalFollow": "Follows the global task settings — changes there apply here automatically.", + "settingsSourceCustomHint": "Saves this folder's own settings; it stops following the global defaults.", + "settingsAgent": "Default agent", + "settingsMaxConcurrent": "Max concurrent tasks", + "settingsMaxConcurrentHint": "0 = unlimited", + "settingsAutoProcess": "Process automatically", + "settingsAutoProcessHint": "To-dos start on their own, up to the concurrency limit.", + "settingsMergeStrategy": "Default merge strategy", + "settingsMergeStrategyHint": "How the task's changes are recorded in the branch history when merged.", + "settingsAutoMerge": "Merge automatically", + "settingsAutoMergeHint": "A task that reaches review with something to land merges as if you clicked Merge: the agent writes the commit message, and the worktree follows the default below. A red preflight or a failed merge leaves the task waiting for you.", + "settingsDeleteWorktree": "Delete the worktree after merging", + "settingsDeleteWorktreeHint": "Pre-selects the option in the merge dialog; you can still change it there.", + "settingsWorktreeRoot": "Worktree location", + "settingsWorktreeRootHint": "Directory new task worktrees are created in — one per task. Leave it empty to keep them next to the project folder; \"~\" is your home directory, and a relative path resolves against the project folder.", + "settingsWorktreeRootPlaceholder": "~/codeg-worktrees", + "settingsWorktreeRootBrowse": "Choose the worktree directory", + "settingsPreflight": "Preflight command", + "settingsPreflightHint": "Runs in the worktree when a task reaches review.", + "settingsPreflightCustomPlaceholder": "pnpm test", + "settingsInitCommand": "Worktree init command", + "settingsInitCommandHint": "Runs inside a freshly created worktree before the agent starts.", + "settingsInitCommandPlaceholder": "pnpm install", + "settingsTabGeneral": "General", + "settingsTabMerge": "Merge", + "settingsTabWorktree": "Worktree", + "settingsTabPrompts": "Prompts", + "settingsPromptsIntro": "Each stage already sends a built-in prompt — the task itself, the worktree rules, and for merging the exact git steps. Text you add here is appended at the end as extra instructions: it refines those built-ins, it never replaces them.", + "settingsPromptStageAll": "All stages", + "settingsPromptPlaceholderAll": "e.g. Follow the conventions in AGENTS.md; keep the final summary to two sentences", + "settingsPromptPlaceholderWork": "e.g. Read the related tests first; commit in small steps as you go", + "settingsPromptPlaceholderRetry": "e.g. Check what is already committed before continuing; don't redo finished work", + "settingsPromptPlaceholderReturn": "e.g. Address every point raised; don't refactor anything unrelated", + "settingsPromptPlaceholderMerge": "e.g. Write the landing commit message in English; call out any conflict you resolved by hand", + "settingsPromptHintAll": "Appended to every prompt the agent receives, the merge run included.", + "settingsPromptHintWork": "Appended when a task runs for the first time.", + "settingsPromptHintRetry": "Appended when an interrupted or failed task is picked up again.", + "settingsPromptHintReturn": "Appended when you follow up on a reviewed task (rework, extra work, self-check).", + "settingsPromptHintMerge": "Appended when the agent lands the task onto the base branch.", + "preflightPassed": "{name} passed", + "preflightFailed": "{name} failed", + "preflightRunning": "{name} running…", + "detailDescription": "Task detail", + "detailSummary": "Result", + "detailFiles": "Changed files", + "detailDiffAll": "View full diff", + "detailDiffAllTitle": "Full diff", + "detailNoChanges": "No changes vs the base yet", + "detailTimeline": "Progress", + "detailTimelineEmpty": "No activity yet", + "showMore": "Show more", + "showLess": "Show less", + "detailInfo": "Details", + "detailBranch": "Branch", + "detailMergeCommit": "Merge commit", + "detailChanges": "Changes", + "detailScheduled": "Scheduled start", + "detailCreated": "Created", + "detailStarted": "Started", + "detailFinished": "Finished", + "diffLoading": "Loading diff…", + "deleteConfirmTitle": "Delete task?", + "deleteConfirmBody": "“{title}” will be removed from the board. An active run is canceled first.", + "deleteWithWorktree": "Also delete its worktree", + "eventCreated": "Created", + "eventStatusChanged": "Status changed", + "eventConfigEffective": "Launch config", + "eventInitCommand": "Init command", + "eventAgentProgress": "Agent progress", + "eventAgentVerdict": "Agent verdict", + "eventMergeAttempt": "Merge started", + "eventMergeQueued": "Queued to merge", + "eventMergeConflict": "Merge conflict", + "eventPreflight": "Preflight", + "eventCleanupFailed": "Worktree cleanup failed", + "eventResumeFallback": "Session resume fell back to a new session", + "eventUserAction": "User action", + "eventDiffStat": "Change snapshot" + }, + "CustomSkillsSettings": { + "loading": "Loading custom skills…", + "category": "Custom", + "searchPlaceholder": "Search custom skills by name, id, or description", + "states": { + "not_linked": "Not enabled", + "linked_to_codeg": "Enabled", + "linked_elsewhere": "Linked elsewhere", + "blocked_by_real_directory": "Blocked by a real folder", + "broken": "Broken link" + }, + "actions": { + "new": "New", + "import": "Import", + "importFromAgent": "Import from agent", + "cancel": "Cancel", + "save": "Save" + }, + "rowMenu": { + "edit": "Edit", + "duplicate": "Duplicate", + "delete": "Delete" + }, + "bulk": { + "delete": "Delete selected" + }, + "editor": { + "createTitle": "New custom skill", + "editTitle": "Edit custom skill", + "description": "Custom skills live in the shared store (~/.codeg/skills) and can be enabled for any agent.", + "idLabel": "Skill id", + "idPlaceholder": "e.g. my-workflow", + "contentLabel": "SKILL.md", + "contentPlaceholder": "Write the skill's SKILL.md here…", + "preview": "Preview", + "edit": "Edit", + "emptyBody": "No content yet." + }, + "duplicate": { + "title": "Duplicate skill", + "description": "Create a copy of \"{id}\" with a new id.", + "newIdPlaceholder": "New skill id", + "confirm": "Duplicate" + }, + "import": { + "title": "Choose a skill folder to import" + }, + "importFromAgent": { + "title": "Import skills from an agent", + "description": "Copy an agent's own skills into the shared store so you can enable them for any agent.", + "agentLabel": "Agent", + "agentPlaceholder": "Select an agent", + "selectAll": "Select all ({count})", + "loading": "Loading the agent's skills…", + "unsupported": "This agent doesn't expose a skills directory.", + "empty": "This agent has no importable skills.", + "alreadyInLibrary": "In library", + "confirm": "Import selected ({count})" + }, + "delete": { + "title": "Delete custom skills?", + "body": "This removes {count} custom skill(s) from the central store and unlinks them from every agent. This can't be undone.", + "confirm": "Delete" + }, + "toasts": { + "loadFailed": "Failed to load skill", + "idRequired": "Please enter a skill id", + "created": "Custom skill created", + "updated": "Custom skill updated", + "saveFailed": "Failed to save skill", + "imported": "Skill imported", + "importFailed": "Failed to import skill", + "duplicated": "Skill duplicated", + "duplicateFailed": "Failed to duplicate skill", + "deleted": "Deleted {count} skill(s)", + "deletedPartial": "Deleted {ok}, {failed} failed", + "deleteFailed": "Failed to delete skills", + "importedFromAgent": "Imported {count} skill(s)", + "importedFromAgentPartial": "Imported {ok}, {failed} failed", + "importFromAgentAllSkipped": "Nothing to import — {count} already in the library", + "importFromAgentFailed": "Failed to import from agent" + } + }, + "CodexModelEditor": { + "customizedNotice": "You've customized the model list, so codeg now manages codex's full model table. Official models codex ships later won't appear automatically — click the refresh button below and save again to sync them. Clear your customizations to let codex update automatically.", + "officialsTitle": "Official models", + "officialsHint": "Auto-included from the codex you launch; remove any you don't want.", + "officialsEmpty": "No official models available.", + "refresh": "Refresh from codex", + "readdOfficial": "Re-add official", + "customsTitle": "Custom models", + "customsEmpty": "No custom models yet.", + "addCustom": "Add custom", + "slugPlaceholder": "Model id (slug)", + "displayNamePlaceholder": "Display name", + "contextWindow": "Context", + "makeDefault": "Set as default", + "defaultHint": "Default model", + "remove": "Remove", + "advanced": "Advanced", + "baseTemplate": "Base template", + "baseTemplateHint": "Official model to clone required fields (system prompt, tools, limits) from.", + "groupBehavior": "Behavior & capabilities", + "fieldReasoningLevel": "Default reasoning", + "fieldReasoningSummary": "Reasoning summary", + "fieldVerbosity": "Verbosity", + "fieldShellType": "Shell type", + "fieldApplyPatch": "Apply-patch tool", + "fieldReasoningSummaries": "Reasoning summaries", + "fieldSupportVerbosity": "Verbosity control", + "fieldParallelToolCalls": "Parallel tool calls", + "fieldSearchTool": "Web search tool", + "optNone": "None", + "groupInstructions": "Description & system prompt", + "fieldDescription": "Description", + "baseInstructions": "System prompt (base_instructions)" + }, + "DiagnosticsSettings": { + "title": "Environment diagnostics", + "description": "Checks how this app resolves the agent CLI inside its own process, which can differ from your terminal.", + "loading": "Running diagnostics…", + "error": "Diagnostics failed", + "rerun": "Re-run", + "copyAll": "Copy all", + "copied": "Diagnostics copied to clipboard", + "button": "Diagnose", + "verdict": { + "ok": "Environment looks healthy. If it still shows as not installed, fully restart the app so the prefix cache refreshes.", + "node_missing": "Node.js was not found on the app PATH.", + "npm_missing": "npm was not found on the app PATH.", + "not_installed": "This agent does not appear to be installed.", + "installed_but_unresolved": "The agent is recorded as installed, but the app cannot locate its executable.", + "user_prefix_not_on_path": "Installed into the fallback prefix (~/.codeg/npm-global), which is not on the app PATH. Fully restart the app and try again.", + "homebrew_bin_not_on_path": "Installed under the Homebrew bin, which is not on the app PATH (Apple Silicon keg split).", + "terminal_only_path": "The command resolves in your terminal but not in the app — a GUI PATH gap. Launch the app from a terminal, or reinstall from Agent Settings.", + "npm_prefix_timeout": "npm prefix -g was too slow (over 1.5s), so fallback detection was skipped. Restart the app and try again.", + "node_too_old": "Your active Node.js is older than this agent requires. Upgrade Node.js.", + "adapter_missing_native_present": "Your own {agent} CLI is installed, but Codeg launches a separate ACP adapter package — and that one isn't installed yet. Install it from Agent Settings; it won't touch your CLI and shares the same sign-in.", + "adapter_missing": "Codeg launches a separate ACP adapter package for {agent}, and it isn't installed yet. Install it from Agent Settings — installing the vendor CLI alone is not enough." + } + }, + "TokenUsage": { + "title": "Token Usage", + "rangeLabel": "Time range", + "range7d": "7 days", + "range30d": "30 days", + "range90d": "90 days", + "rangeThisMonth": "This month", + "rangeThisYear": "This year", + "rangeAll": "All time", + "rangeCustom": "Custom", + "moreRanges": "More", + "customRangePick": "Pick a date range", + "bucketLabel": "Group by", + "bucketDay": "Day", + "bucketWeek": "Week", + "bucketMonth": "Month", + "bucketUnitDay": "day", + "bucketUnitWeek": "week", + "bucketUnitMonth": "month", + "folderFilter": "Folders", + "allFolders": "All folders", + "agentFilter": "Agents", + "allAgents": "All agents", + "modelFilter": "Models", + "allModels": "All models", + "searchPlaceholder": "Search…", + "noMatches": "No matches", + "clearFilter": "Clear selection", + "resetFilters": "Reset filters", + "refresh": "Refresh", + "rebuild": "Rebuild all", + "rebuildHint": "Re-reads every transcript from scratch. Use this if a session grew outside codeg.", + "syncing": "Counting sessions…", + "syncProgress": "{done} / {total}", + "syncDone": "Counted {synced} sessions", + "syncFailed": "Could not read some sessions", + "syncBusy": "A refresh is already running", + "lastSynced": "Updated {time}", + "lastSyncedNever": "Never updated", + "tileTotal": "Total tokens", + "tileSessions": "Sessions", + "tileTurns": "Turns", + "tileActiveDays": "Active days", + "tileGenTime": "Generation time", + "vsPrevious": "vs. previous period", + "deltaNew": "new", + "trendTitle": "Usage over time", + "trendEmpty": "No usage in this range", + "trendTurns": "Turns", + "trendSessions": "Sessions", + "compositionTitle": "What the tokens were", + "compositionHint": "Input is what you sent, output is what the model wrote, and cache reads are context you didn't pay full price for.", + "compositionNote": "Re-sending those cache hits at full price would have cost another {value}.", + "inputTokens": "Input", + "outputTokens": "Output", + "cacheWrite": "Cache write", + "cacheRead": "Cache read", + "freshTokens": "Fresh compute", + "cacheHitCaption": "Cache hit", + "cacheHeroTitleHigh": "Most context never got re-sent", + "cacheHeroTitleLow": "Most context still bills at full price", + "cacheHeroDesc": "The cache carried {cached} of context — only {fresh} was freshly computed in this period.", + "cacheSavedSuffix": "That saved re-sending the equivalent of {saved}.", + "avgPerSession": "Avg. per session", + "avgTurnsPerSession": "{count} turns per session", + "avgPerActiveDay": "Avg. per active day", + "peakBucket": "Busiest {bucket}", + "peakHour": "Peak hour", + "daysValue": "{count} days", + "idleDays": "Idle days", + "byFolderTitle": "By folder", + "byAgentTitle": "By agent", + "byModelTitle": "By model", + "distributionTitle": "Usage distribution", + "distributionHint": "Sessions and tokens grouped by the selected dimension — click a row to filter by it.", + "otherLabel": "Other", + "unknownModel": "Unspecified model", + "emptyBreakdown": "Nothing recorded yet", + "sessionsCount": "{count} sessions", + "heatmapTitle": "When you build", + "heatmapHint": "Tokens by local weekday and hour.", + "heatmapPeakHint": "Densest around {hour}:00.", + "less": "Less", + "more": "More", + "heatmapCell": "{weekday} {hour}:00 — {value} tokens", + "weekMon": "Mon", + "weekTue": "Tue", + "weekWed": "Wed", + "weekThu": "Thu", + "weekFri": "Fri", + "weekSat": "Sat", + "weekSun": "Sun", + "topSessionsTitle": "Heaviest sessions", + "untitledSession": "Untitled session", + "topSessionsEmpty": "No sessions in this range", + "streakLongest": "Longest streak", + "streakLongestDays": "Longest streak {count} days", + "share": "Share", + "moreActions": "More actions", + "shareDialogTitle": "Share your usage card", + "shareDialogHint": "A snapshot of the range and filters you're looking at.", + "shareSave": "Save image", + "shareCopy": "Copy image", + "shareCopied": "Copied to clipboard", + "shareSaved": "Image saved", + "shareFailed": "Could not create the image", + "shareRendering": "Rendering…", + "cardHeading": "My AI coding stats", + "cardRangeAll": "All time", + "cardTotalLabel": "Tokens used", + "cardFooter": "Made with codeg", + "cardTopModels": "Top models", + "cardTopProjects": "Top projects", + "archetypeNightOwl": "Night Owl", + "archetypeNightOwlDesc": "{percent}% of your tokens burn after dark.", + "archetypeEarlyBird": "Early Bird", + "archetypeEarlyBirdDesc": "{percent}% of your tokens land before 9am.", + "archetypeWeekendWarrior": "Weekend Warrior", + "archetypeWeekendWarriorDesc": "{percent}% of your tokens happen on the weekend.", + "archetypeCacheMaster": "Cache Master", + "archetypeCacheMasterDesc": "{percent}% of your context came from cache.", + "archetypeMarathoner": "Marathoner", + "archetypeMarathonerDesc": "{days} days building without a break.", + "archetypePolyglot": "Polyglot", + "archetypePolyglotDesc": "{count} agents in serious rotation.", + "archetypeLaserFocus": "Laser Focus", + "archetypeLaserFocusDesc": "{percent}% of your tokens went to one project.", + "archetypeDeepDiver": "Deep Diver", + "archetypeDeepDiverDesc": "{averageK}K tokens in an average session.", + "archetypeSteady": "Steady Builder", + "archetypeSteadyDesc": "{days} days of shipping.", + "emptyTitle": "Nothing counted yet", + "emptyHint": "Codeg reads token counts straight from each agent's own transcript. Run a refresh to count what's already on this machine.", + "emptyAction": "Count my sessions", + "loadFailed": "Could not load usage", + "truncatedNotice": "This range is very large — the numbers cover only the most recent slice of it." + } +} diff --git a/src/i18n/messages/es.json b/src/i18n/messages/es.json index 9948070a4..663f1b60b 100644 --- a/src/i18n/messages/es.json +++ b/src/i18n/messages/es.json @@ -1,4956 +1,4958 @@ -{ - "Language": { - "followSystem": "Seguir el sistema", - "english": "Inglés", - "simplifiedChinese": "Chino simplificado", - "traditionalChinese": "Chino tradicional", - "japanese": "Japonés", - "korean": "Coreano", - "spanish": "Español", - "german": "Alemán", - "french": "Francés", - "portuguese": "Portugués", - "arabic": "Árabe" - }, - "GitCredentialDialog": { - "title": "Autenticación requerida", - "description": "El servidor remoto requiere credenciales. Introduce tu nombre de usuario y contraseña (o token de acceso personal).", - "username": "Nombre de usuario", - "usernamePlaceholder": "Usuario o correo electrónico", - "password": "Contraseña / Token", - "passwordPlaceholder": "Contraseña o token de acceso personal", - "passwordHint": "Introduce el nombre de usuario y contraseña del servidor.", - "cancel": "Cancelar", - "authenticate": "Autenticar", - "authenticating": "Autenticando...", - "invalidCredentials": "Credenciales inválidas. Inténtalo de nuevo.", - "saveCredentials": "Guardar credenciales para futuras operaciones", - "githubTitle": "Autenticación de GitHub", - "githubDescription": "Introduce un token de acceso personal para conectarte a GitHub. El token se validará y guardará automáticamente.", - "githubToken": "Token de acceso personal", - "githubTokenPlaceholder": "ghp_xxxxxxxxxxxx", - "githubTokenHint": "Genera un token en GitHub → Settings → Developer settings → Personal access tokens.", - "githubAuthenticate": "Validar y conectar", - "generateToken": "Generar token" - }, - "SettingsShell": { - "title": "Configuración", - "preferences": "Preferencias", - "nav": { - "general": "General", - "appearance": "Apariencia", - "agents": "Agentes", - "mcp": "MCP", - "skills": "Skills", - "shortcuts": "Atajos", - "version_control": "Control de versiones", - "system": "Sistema", - "chat_channels": "Canales de chat", - "web_service": "Servicio Web", - "model_providers": "Proveedores de Modelos", - "experts": "Expertos", - "science": "Ciencia", - "office_tools": "Herramientas de oficina", - "skill_packs": "Paquetes de habilidades", - "quick_messages": "Mensajes rápidos", - "logs": "Registros de ejecución" - } - }, - "AppearanceSettings": { - "sectionTitle": "Apariencia del tema", - "sectionDescription": "Elige claro, oscuro o seguir el sistema. La configuración se guarda automáticamente.", - "themeMode": "Modo de tema", - "placeholder": "Selecciona el modo de tema", - "system": "Seguir el sistema", - "light": "Claro", - "dark": "Oscuro", - "currentTheme": "Tema efectivo actual: {theme}", - "resolvedTheme": { - "light": "Claro", - "dark": "Oscuro", - "unknown": "--" - }, - "themeColor": { - "sectionTitle": "Color del tema", - "sectionDescription": "Elige una paleta de colores para acentos, botones y resaltados.", - "current": "Color actual: {color}", - "options": { - "neutral": "Neutral", - "zinc": "Zinc", - "slate": "Slate", - "stone": "Stone", - "gray": "Gray", - "red": "Red", - "rose": "Rose", - "orange": "Orange", - "green": "Green", - "blue": "Blue", - "yellow": "Yellow", - "violet": "Violet" - } - }, - "customStyle": { - "sectionTitle": "Estilo personalizado", - "sectionDescription": "Ajusta los colores del tema actual o inyecta tu propio CSS. Las anulaciones se aplican sobre el preajuste base, así que se conservan al cambiar de preajuste.", - "summarySuspended": "Suspendido", - "summaryDefault": "Preajuste sin cambios", - "summaryTokens": "{count, plural, one {# anulación} other {# anulaciones}}", - "summaryCss": "CSS personalizado", - "suspendedByShortcut": "El estilo personalizado está suspendido. Nada de lo que configures aquí surtirá efecto hasta que lo reanudes.", - "suspendedBySafeParam": "Esta ventana se abrió en modo de apariencia segura, por lo que el estilo personalizado se ignora aquí. Las demás ventanas no se ven afectadas.", - "resume": "Reanudar estilo personalizado", - "enableTheme": "Activar colores personalizados", - "editingLight": "Editando los valores del modo claro. Cambia la aplicación al modo oscuro para configurarlo por separado.", - "editingDark": "Editando los valores del modo oscuro. Cambia la aplicación al modo claro para configurarlo por separado.", - "resetToken": "Restablecer al valor del preajuste", - "radius": "Radio de esquina", - "radiusHint": "De él deriva toda la escala de radios, de sm a 4xl, así que un único control redondea toda la aplicación.", - "advanced": "Avanzado ({count} variables más)", - "enableCss": "Activar CSS personalizado", - "cssRisk": "Función avanzada. El CSS personalizado anula todos los estilos integrados y puede dejar la interfaz inutilizable.", - "editCss": "Editar CSS…", - "cssPresent": "{size} KB guardados", - "cssEmpty": "Todavía no hay nada guardado", - "escapeHint": "¿Interfaz rota? Pulsa {shortcut} para suspender todo el estilo personalizado, o abre una ventana con el parámetro de consulta safeStyle=1.", - "copyTheme": "Copiar JSON del tema", - "importTheme": "Importar tema…", - "clearTheme": "Borrar anulaciones", - "interopHint": "Los temas usan el formato registry:theme de shadcn, así que puedes pegar aquí cualquier tema de shadcn y usar los exportados en cualquier proyecto shadcn.", - "importTitle": "Importar tema", - "importDescription": "Pega un elemento registry:theme de shadcn, un objeto light/dark simple o un mapa plano de tokens.", - "readClipboard": "Leer portapapeles", - "importConfirm": "Importar", - "cancel": "Cancelar", - "apply": "Aplicar", - "toasts": { - "copied": "JSON del tema copiado", - "copyFailed": "No se pudo copiar al portapapeles", - "clipboardReadFailed": "No se pudo leer el portapapeles, pégalo manualmente", - "importFailed": "Ese JSON no contiene variables de tema utilizables", - "imported": "Tema importado" - }, - "css": { - "dialogTitle": "CSS personalizado", - "dialogDescription": "Se aplica a todas las ventanas de codeg. Los cambios se previsualizan en vivo; pulsa Aplicar para guardar.", - "size": "{used} KB / {max} KB", - "ruleCount": "{count} reglas", - "errorTooLarge": "Demasiado grande para guardar. Redúcelo por debajo del límite.", - "errorImportEscaped": "Una regla @import sobrevivió a la eliminación (sintaxis con escapes). Quítala para guardar.", - "warnNoRules": "No se analizó ninguna regla; revisa la sintaxis.", - "noticeImportsRemoved": "Reglas @import eliminadas: {count}. Descargarían hojas de estilo remotas.", - "noticeRemoteUrl": "Contiene una url() remota, que hará una petición de red al aplicarse.", - "noticePreviewSuspended": "El estilo personalizado está suspendido, así que esta vista previa no se aplica.", - "noticeDisabled": "El CSS personalizado está desactivado. Puedes previsualizar aquí, pero no se aplicará hasta que lo actives.", - "hintTokens": "Consejo: tus colores anulados están disponibles como var(--primary), var(--background), etc." - } - }, - "zoomLevel": { - "sectionTitle": "Zoom de ventana", - "sectionDescription": "Escala toda la interfaz. Se aplica al instante y se guarda por dispositivo.", - "placeholder": "Selecciona el nivel de zoom", - "default": "Predeterminado", - "current": "Zoom actual: {zoom}%" - }, - "fonts": { - "sectionTitle": "Fuentes", - "sectionDescription": "Elige las fuentes para la interfaz, el editor de código y el terminal. Las fuentes incluidas se cargan cuando se necesitan; selecciona «Personalizada…» para usar cualquier fuente instalada en tu sistema.", - "interface": "Interfaz", - "editor": "Editor", - "terminal": "Terminal", - "groupSans": "Sans-serif", - "groupMono": "Monoespaciada", - "custom": "Personalizada…", - "customPlaceholder": "Nombre de la fuente, p. ej. Fira Code", - "fontSize": "Tamaño de fuente", - "ligatures": "Activar ligaduras", - "ligaturesUnavailable": "Esta fuente no tiene ligaduras", - "wordWrap": "Activar ajuste de línea", - "terminalLigaturesHint": "Las ligaduras del terminal solo se aplican a las fuentes de programación incluidas.", - "preview": "Vista previa" - }, - "welcomePanel": { - "sectionTitle": "Área de selección de modo", - "sectionDescription": "Las tarjetas de acceso rápido «Desarrollo de código / Ofimática» que se muestran sobre el editor en la página de nueva conversación.", - "showQuickActions": "Mostrar en la página de nueva conversación" - }, - "workspaceBackground": { - "sectionTitle": "Fondo del espacio de trabajo", - "sectionDescription": "Muestra una imagen detrás de todo el espacio de trabajo. La barra lateral y los paneles se vuelven translúcidos y esmerilados para dejar ver la imagen, y una máscara mantiene el texto legible.", - "enable": "Activar imagen de fondo", - "image": "Imagen", - "chooseImage": "Elegir imagen", - "replaceImage": "Reemplazar imagen", - "removeImage": "Quitar", - "fillMode": "Modo de relleno", - "fillModes": { - "cover": "Cubrir", - "contain": "Ajustar", - "center": "Centrar", - "tile": "Mosaico" - }, - "maskOpacity": "Opacidad de la máscara", - "maskOpacityHint": "Los valores más altos difuminan la imagen hacia el color de fondo del tema, mejorando el contraste del texto.", - "imageBlur": "Desenfoque de la imagen", - "panelOpacity": "Opacidad de los paneles", - "panelOpacityHint": "Cuán opacos son la barra lateral, los paneles y las barras de pestañas. Más bajo deja ver más la imagen.", - "errorTooLarge": "La imagen es demasiado grande (máx. 16 MB).", - "errorUploadFailed": "No se pudo establecer la imagen de fondo." - } - }, - "SystemSettings": { - "loading": "Cargando...", - "sectionTitle": "Administración del sistema", - "sectionDescription": "Administra el proxy de red, las actualizaciones de la app y las preferencias de idioma.", - "proxyTitle": "Proxy de red", - "proxyDescription": "Cuando está activado, las solicitudes de red posteriores usarán este proxy preferentemente (incluyendo chat ACP, instalación de agentes y operaciones remotas de Git).", - "loadFailed": "Error al cargar: {message}", - "enableProxy": "Activar proxy del sistema", - "proxyAddress": "Dirección del proxy", - "proxyHint": "Compatible con http(s)/socks5, ejemplo: {example}. Solo funciona cuando el proxy del sistema está activado.", - "save": "Guardar", - "saving": "Guardando...", - "proxyRequired": "Se requiere URL del proxy cuando el proxy está activado", - "saveSuccess": "La configuración del proxy del sistema se guardó", - "saveFailed": "Error al guardar: {message}", - "languageTitle": "Idioma", - "languageDescription": "Configura el idioma de la app. Al seguir el idioma del sistema, los no compatibles vuelven a inglés.", - "appLanguage": "Idioma de la app", - "languageSaveSuccess": "La configuración de idioma se guardó", - "languageSaveFailed": "No se pudo guardar la configuración de idioma: {message}", - "updateTitle": "Actualización de la app", - "versionTitle": "Actualización de software", - "updateDescription": "Comprueba versiones más nuevas en la fuente de versiones configurada e instálalas directamente cuando estén disponibles.", - "currentVersion": "Versión actual", - "upgradableVersion": "Última versión", - "none": "Ninguna", - "lastChecked": "Última comprobación: {time}", - "updateError": "Error de actualización: {message}", - "checking": "Comprobando...", - "checkUpdate": "Buscar actualizaciones", - "updating": "Instalando...", - "downloading": "Descargando...", - "upgradeTo": "Actualizar a v{version}", - "viewRelease": "Ver lanzamiento v{version}", - "foundUpdate": "Nueva versión v{version} encontrada", - "alreadyLatest": "Ya tienes la versión más reciente", - "checkUpdateFailed": "No se pudo buscar actualizaciones: {message}", - "installSuccess": "Actualización instalada. Reiniciando la app.", - "installFailed": "La actualización falló: {message}", - "upgradeSuccess": "Actualización completada. Recargando...", - "restartTimeout": "El servidor no volvió a tiempo. Revisa los registros del contenedor o del servicio.", - "restartingIn": "Reiniciando en {seconds} s...", - "waitingForServer": "Esperando a que el servidor vuelva...", - "restartToUpdate": "Reiniciar para actualizar", - "newVersionBadge": "Nueva v{version}", - "updateAvailableTitle": "Actualización disponible", - "releaseNotesTitle": "Novedades", - "remindLater": "Más tarde", - "retry": "Reintentar", - "stepDownload": "Descarga", - "stepInstall": "Instalación", - "stepRestart": "Reinicio", - "updateReadyHint": "Actualización descargada: reinicia para aplicarla.", - "restarting": "Reiniciando...", - "dockerUpgradeHint": "Esto actualiza el contenedor en ejecución ahora. Se pierde si se recrea el contenedor: para conservarlo, descarga o crea una imagen con la nueva versión y recrea el contenedor.", - "upgradeRolledBack": "La actualización falló; el servidor volvió a la versión anterior.", - "serverUnreachable": "No se pudo conectar con el servidor para iniciar la actualización. Comprueba que esté en ejecución e inténtalo de nuevo.", - "rollbackButton": "Revertir", - "rollingBack": "Revirtiendo...", - "rollbackDescription": "Restaura la versión instalada antes de la última actualización.", - "rollbackConfirmTitle": "¿Revertir a la versión anterior?", - "rollbackConfirmDescription": "El servidor se reiniciará con la versión instalada antes de la última actualización. Una versión más reciente seguirá disponible para instalar de nuevo.", - "rollbackConfirm": "Revertir", - "rollbackCancel": "Cancelar", - "rollbackSuccess": "Se revirtió a la versión anterior. Recargando...", - "rollbackFailed": "Error al revertir. Revisa los registros del servidor.", - "updateErrors": { - "sourceUnavailable": "No se puede acceder al origen de actualización. Revisa tu red o proxy e inténtalo de nuevo.", - "network": "Falló la conexión de red. Revisa tu red o proxy e inténtalo de nuevo.", - "downloadFailed": "No se pudo descargar el paquete de actualización. Inténtalo más tarde.", - "installFailed": "No se pudo instalar la actualización. Cierra la app e inténtalo de nuevo.", - "unknown": "La actualización falló. Inténtalo más tarde." - } - }, - "VersionControlSettings": { - "loading": "Cargando...", - "sectionTitle": "Control de versiones", - "sectionDescription": "Configura el ejecutable de Git y gestiona las cuentas de GitHub.", - "gitTitle": "Configuración de Git", - "gitDescription": "Configura el ejecutable de Git utilizado por la aplicación.", - "gitDetected": "Git detectado", - "gitNotFound": "Git no encontrado en el sistema", - "gitVersion": "Versión", - "gitPath": "Ruta", - "customGitPath": "Ruta personalizada de Git", - "customGitPathPlaceholder": "/usr/bin/git", - "customGitPathHint": "Dejar vacío para usar la ruta detectada automáticamente.", - "test": "Probar", - "testing": "Probando...", - "testSuccess": "El ejecutable de Git es válido.", - "testFailed": "Prueba de Git fallida: {message}", - "save": "Guardar", - "saving": "Guardando...", - "saveSuccess": "Configuración de Git guardada.", - "saveFailed": "Error al guardar: {message}", - "githubTitle": "Cuentas de GitHub", - "githubDescription": "Gestiona las cuentas de GitHub para autenticación. Los tokens se almacenan localmente.", - "noAccounts": "No hay cuentas de GitHub configuradas.", - "addAccount": "Añadir cuenta", - "serverUrl": "URL del servidor", - "serverUrlPlaceholder": "https://github.com", - "token": "Token de acceso personal", - "tokenPlaceholder": "ghp_xxxxxxxxxxxx", - "generateToken": "Generar token", - "tokenHint": "Genera un token en GitHub → Settings → Developer settings → Personal access tokens.", - "validateAndAdd": "Validar y añadir", - "validating": "Validando...", - "addSuccess": "Cuenta {username} añadida correctamente.", - "addFailed": "Error al añadir cuenta: {message}", - "testConnection": "Probar", - "connectionSuccess": "Conexión exitosa.", - "connectionFailed": "Conexión fallida: {message}", - "setDefault": "Establecer como predeterminada", - "defaultLabel": "Predeterminada", - "defaultSet": "Cuenta predeterminada actualizada.", - "removeAccount": "Eliminar", - "removeConfirmTitle": "Eliminar cuenta", - "removeConfirmMessage": "¿Estás seguro de que deseas eliminar la cuenta \"{username}\"?", - "removeConfirm": "Eliminar", - "removeCancel": "Cancelar", - "removeSuccess": "Cuenta eliminada.", - "scopes": "Alcances", - "loadFailed": "Error al cargar configuración: {message}", - "gitAccount": { - "sectionTitle": "Cuentas de servidor Git", - "sectionDescription": "Gestiona credenciales para servidores Git que no son GitHub (GitLab, Bitbucket, autoalojados, etc.).", - "noAccounts": "No hay cuentas de servidor Git configuradas.", - "addAccount": "Añadir cuenta", - "addTitle": "Añadir cuenta Git", - "addDescription": "Introduce la dirección del servidor, nombre de usuario y contraseña o token de acceso.", - "serverUrl": "URL del servidor", - "serverUrlPlaceholder": "https://gitlab.example.com", - "username": "Nombre de usuario", - "usernamePlaceholder": "Usuario o correo electrónico", - "password": "Contraseña / Token", - "passwordPlaceholder": "Contraseña o token de acceso", - "passwordHint": "Introduce tu contraseña o token de acceso del servidor.", - "add": "Añadir", - "serverRequired": "La URL del servidor es obligatoria.", - "usernameRequired": "El nombre de usuario es obligatorio.", - "passwordRequired": "La contraseña es obligatoria." - } - }, - "ShortcutSettings": { - "sectionTitle": "Atajos", - "resetDefault": "Restablecer valores predeterminados", - "recordInstruction": "Haz clic en el botón derecho y luego pulsa una combinación de teclas. Usa Ctrl/Cmd, Alt y Shift. Pulsa Esc para cancelar la grabación.", - "recording": "Pulsa un atajo...", - "toasts": { - "conflict": "El atajo ya está en uso por \"{title}\"", - "updated": "Atajo actualizado", - "invalid": "Atajo no válido, inténtalo de nuevo", - "reset": "Se restauraron los atajos predeterminados" - }, - "actions": { - "toggle_search": { - "title": "Abrir búsqueda", - "description": "Muestra u oculta el panel de búsqueda de conversaciones" - }, - "toggle_sidebar": { - "title": "Alternar barra lateral izquierda", - "description": "Muestra u oculta la barra lateral de lista de conversaciones" - }, - "toggle_terminal": { - "title": "Alternar terminal", - "description": "Muestra u oculta el panel de terminal inferior" - }, - "new_terminal_tab": { - "title": "Nueva terminal", - "description": "Crea una nueva pestaña de terminal cuando el foco está en la terminal" - }, - "close_current_terminal_tab": { - "title": "Cerrar terminal actual", - "description": "Cierra la pestaña de terminal actual cuando el foco está en la terminal" - }, - "toggle_aux_panel": { - "title": "Alternar panel derecho", - "description": "Muestra u oculta el panel de información auxiliar" - }, - "new_conversation": { - "title": "Nueva conversación", - "description": "Crea una nueva pestaña de conversación en la carpeta actual" - }, - "open_folder": { - "title": "Abrir carpeta", - "description": "Abre el selector de carpetas y la carpeta en una nueva ventana" - }, - "open_settings": { - "title": "Abrir configuración", - "description": "Abre la ventana de configuración" - }, - "close_current_tab": { - "title": "Cerrar pestaña actual", - "description": "Cierra la conversación o pestaña de archivo actual" - }, - "close_all_file_tabs": { - "title": "Cerrar todas las pestañas de archivos", - "description": "Cierra todas las pestañas de archivos abiertas cuando el panel de archivos está activo" - }, - "next_tab": { - "title": "Pestaña siguiente", - "description": "Cambiar a la siguiente pestaña de conversación o archivo" - }, - "prev_tab": { - "title": "Pestaña anterior", - "description": "Cambiar a la pestaña anterior de conversación o archivo" - }, - "send_message": { - "title": "Enviar mensaje", - "description": "Enviar el mensaje actual en el cuadro de entrada" - }, - "newline_in_message": { - "title": "Nueva línea en mensaje", - "description": "Insertar una nueva línea en el cuadro de entrada" - }, - "toggle_custom_style": { - "title": "Suspender/reanudar estilo personalizado", - "description": "Vía de escape: desactiva todos los colores y el CSS personalizados, y los vuelve a activar" - } - } - }, - "SkillsSettings": { - "title": "Skills", - "description": "Selecciona una Skill a la izquierda. A la derecha se muestra una vista previa de Markdown por defecto; cambia a edición para modificar y guardar.", - "loadingAgents": "Cargando agentes compatibles con Skills...", - "emptyNoManageableAgents": "No hay agentes disponibles para gestionar Skills.", - "managedTarget": "Objetivo gestionado", - "selectAgentPlaceholder": "Selecciona un agente", - "searchPlaceholder": "Buscar por nombre / ID / ruta...", - "skillsList": "Lista de Skills", - "loadingSkills": "Cargando Skills...", - "agentNotSupported": "El agente actual no admite gestión de Skills.", - "emptySkills": "Aún no hay Skills. Haz clic en \"Nueva Skill\" para crear una.", - "newSkillTitle": "Nueva Skill", - "skillInfo": "Información de la Skill", - "skillIdPlaceholder": "skill-id (letras/números/-/_/.)", - "skillsDirectoryWithPath": "Directorio de Skills: {path}", - "skillsDirectoryNeedId": "Directorio de Skills: introduce el ID de Skill para generar la ruta completa", - "markdownContent": "Contenido Markdown", - "editingStatus": "Editando", - "previewStatus": "Vista previa", - "contentPlaceholder": "Introduce el contenido Markdown de la Skill...", - "metadataTitle": "Metadatos de Skills", - "onlyYamlMetadata": "Esta Skill solo contiene metadatos YAML.", - "emptyContentHint": "Aún no hay contenido. Haz clic en \"Editar\" para empezar.", - "loadingSkill": "Cargando Skill...", - "emptyNoAgents": "No hay agentes disponibles.", - "noSelectionHint": "Selecciona un Skill a la izquierda o haz clic en \"Nuevo Skill\" para crear uno.", - "systemBadge": "Sistema", - "systemHint": "Skill integrado del CLI · solo lectura", - "scope": { - "global": "Global", - "folder": "Carpeta", - "selectFolderPlaceholder": "Seleccionar una carpeta", - "noFolders": "No se encontraron carpetas", - "pickFolderHint": "Selecciona una carpeta para ver sus Skills." - }, - "actions": { - "preview": "Vista previa", - "edit": "Editar", - "openInWindow": "Abrir en nueva ventana", - "delete": "Eliminar", - "deleting": "Eliminando...", - "refresh": "Actualizar", - "newSkill": "Nueva Skill", - "reset": "Restablecer", - "save": "Guardar", - "saving": "Guardando...", - "cancel": "Cancelar" - }, - "deleteDialog": { - "title": "Eliminar Skill", - "confirm": "¿Eliminar la Skill actual? Esta acción no se puede deshacer.", - "confirmWithNamePrefix": "¿Eliminar la Skill", - "confirmWithNameSuffix": "? Esta acción no se puede deshacer." - }, - "toasts": { - "loadFailed": "No se pudo cargar la Skill", - "openFolderFailed": "No se pudo abrir la carpeta", - "noSkillDirectory": "No se encontró un directorio de Skills disponible para el agente actual", - "nameRequired": "El nombre de la Skill no puede estar vacío", - "updated": "Skill actualizada", - "created": "Skill creada", - "saveFailed": "No se pudo guardar la Skill", - "deleted": "Skill eliminada", - "deleteFailed": "No se pudo eliminar la Skill" - }, - "templates": { - "gemini": "---\nname: example-skill\ndescription: Describe when this skill should be used.\n---\n\n# Skill Name\n\nInstructions for the agent when this skill is active.\n\n## Workflow\n\n1. Add actionable step one.\n2. Add actionable step two.\n", - "openCode": "---\nname: example-skill\ndescription: Describe when this skill should be used.\n---\n\n# Purpose\n\nDescribe what this skill helps with.\n\n# Steps\n\n1. Add actionable step one.\n2. Add actionable step two.\n", - "openClaw": "---\nname: example-skill\ndescription: Describe when this skill should be used.\nuser-invocable: true\ndisable-model-invocation: false\n---\n\n# Purpose\n\nDescribe what this skill helps with.\n\n# Instructions\n\n1. Add actionable instruction one.\n2. Add actionable instruction two.\n", - "default": "---\nname: example-skill\ndescription: Describe when this skill should be used.\n---\n\n# Skill: example-skill\n\n## When to use\n\n- Describe trigger conditions.\n\n## Instructions\n\n1. Add actionable instruction one.\n2. Add actionable instruction two.\n" - } - }, - "McpSettings": { - "loading": "Cargando...", - "summary": { - "missingCommand": "(comando faltante)", - "missingUrl": "(URL faltante)" - }, - "protocol": { - "stdio": "Stdio" - }, - "errors": { - "selectInstallProtocol": "Selecciona un protocolo de instalación", - "fieldRequired": "{field} es obligatorio", - "fieldNeedsBoolean": "{field} debe ser true o false", - "fieldNeedsNumber": "{field} debe ser un número", - "fieldNeedsInteger": "{field} debe ser un entero", - "fieldInvalidJson": "{field} tiene JSON inválido: {message}", - "fieldOutOfRange": "El valor de {field} está fuera del rango permitido", - "jsonEmpty": "{name} no puede estar vacío", - "jsonInvalid": "{name} no es un JSON válido: {message}", - "jsonMustBeObject": "{name} debe ser un objeto JSON", - "specMustBeObject": "La configuración de MCP debe ser un objeto JSON.", - "missingType": "Falta el campo type en la configuración de MCP. Indica uno de stdio, http (alias: streamable-http, streamableHttp), sse.", - "unsupportedType": "Tipo de MCP no admitido {type}. Compatibles: stdio, http (alias: streamable-http, streamableHttp), sse.", - "codexEntryUnsupportedType": "La entrada Codex MCP {id} tiene un tipo no admitido {type}. Compatibles: stdio, http (alias: streamable-http, streamableHttp), sse.", - "unsupportedTransportType": "Tipo de transport no admitido {type}. Compatibles: http (alias: streamable-http, streamableHttp), sse.", - "stdioCommandRequired": "Los MCP stdio requieren un campo command no vacío.", - "remoteUrlRequired": "Los MCP remotos requieren un campo url no vacío.", - "appsRequired": "Selecciona al menos una aplicación de destino." - }, - "jsonNames": { - "localConfig": "Configuración MCP", - "installConfig": "Configuración de instalación" - }, - "toasts": { - "uninstalled": "MCP desinstalado", - "uninstallFailed": "Error al desinstalar: {message}", - "selectAtLeastOneApp": "Selecciona al menos una app de destino", - "saveSuccess": "Guardado", - "saveFailed": "Error al guardar: {message}", - "installed": "{name} instalado", - "installFailed": "Error al instalar: {message}", - "serverIdRequired": "Server ID es obligatorio", - "serverIdExists": "El Server ID \"{id}\" ya existe. Edita la entrada existente o usa un nombre diferente.", - "created": "MCP creado" - }, - "installDialog": { - "title": "Confirmar instalación de MCP", - "descriptionWithName": "Instalar {name} en la configuración local.", - "description": "Selecciona las apps de destino para la instalación.", - "protocol": "Protocolo", - "selectProtocol": "Seleccionar protocolo", - "parameters": "Parámetros de configuración", - "booleanPlaceholder": "Selecciona true/false", - "selectOneValue": "Selecciona un valor", - "targetApps": "Apps de destino" - }, - "actions": { - "cancel": "Cancelar", - "confirmInstall": "Confirmar instalación", - "installing": "Instalando", - "uninstall": "Desinstalar", - "uninstalling": "Desinstalando", - "viewDetails": "Ver detalles", - "save": "Guardar", - "saving": "Guardando", - "install": "Instalar", - "refresh": "Actualizar", - "newMcp": "Nuevo MCP", - "create": "Crear", - "creating": "Creando..." - }, - "tabs": { - "local": "MCP local", - "market": "Marketplace MCP" - }, - "local": { - "filterPlaceholder": "Filtrar MCP local...", - "loadFailed": "Error de carga: {message}", - "empty": "No se detectó MCP local.", - "description": "La configuración de MCP local se puede editar y guardar directamente.", - "enabledApps": "Apps habilitadas", - "configJson": "Configuración MCP (JSON)", - "draftTitle": "Nuevo MCP", - "draftDescription": "Indica un Server ID y la configuración para crear un servidor MCP local.", - "serverIdLabel": "Server ID", - "serverIdPlaceholder": "Server ID (p. ej. my-mcp)", - "typeHint": "Tipos admitidos: stdio, http (alias: streamable-http, streamableHttp), sse. env solo se usa con stdio; para MCP remotos usa headers para llevar tokens de autenticación.", - "envOnRemoteWarning": "Se detectó env en un MCP remoto. Solo stdio usa env; los MCP remotos llevan los tokens de autenticación en headers, así que env se ignorará al guardar." - }, - "market": { - "selectMarketplace": "Seleccionar marketplace", - "searchPlaceholder": "Buscar MCP...", - "searchFailed": "Error de búsqueda: {message}", - "loadingList": "Cargando lista de MCP...", - "empty": "Sin resultados de MCP.", - "loadingDetail": "Cargando detalles del marketplace...", - "detailLoadFailed": "No se pudieron cargar los detalles: {message}", - "owner": "Propietario: {owner}", - "namespace": "Espacio de nombres: {namespace}", - "defaultInstallProtocol": "Protocolo de instalación predeterminado", - "currentOptionParameterCount": "Cantidad de parámetros de la opción actual: {count}", - "installConfigDescription": "Configuración de instalación (JSON, editable antes de instalar; las ediciones sobrescribirán el formulario de protocolo/parámetros)", - "selectLeftToView": "Selecciona un MCP del marketplace a la izquierda para ver detalles." - }, - "badges": { - "verified": "Verificado", - "remote": "Remoto", - "hasHomepage": "Tiene página web", - "uses": "{count} usos", - "deployed": "Desplegado", - "notDeployed": "No desplegado" - }, - "selectLeftMcp": "Selecciona un MCP a la izquierda." - }, - "AcpAgentSettings": { - "title": "Gestión del SDK de agentes", - "description": "Gestiona en un solo lugar la conexión del SDK de agentes, estado habilitado, variables de entorno, gestión de configuración e información de preflight de versión.", - "loadingAgents": "Cargando lista de agentes...", - "agentList": "Lista de agentes", - "emptyNoAgent": "No hay agentes disponibles.", - "configManagement": "Gestión de configuración", - "envVars": "Variables de entorno", - "hostTools": { - "label": "Dejar que el agente gestione archivos y comandos", - "description": "codeg deja de atender el acceso a archivos y los comandos de terminal, de modo que el agente los ejecuta en su propio proceso, donde sí se aplican su sandbox y sus reglas de permisos. También se desactiva la delegación a otros agentes, ya que devolvería ese mismo trabajo a codeg. codeg no añade ningún sandbox propio, así que actívalo solo si el agente tiene uno configurado." - }, - "nativeJsonConfig": "Configuración JSON nativa", - "modelHintDefault": "Déjalo vacío para usar el modelo predeterminado del sistema.", - "generalConfigDescriptionClaude": "Admite configuración rápida de API URL, API Key y modelos de Claude, y sincroniza con la configuración JSON nativa.", - "generalConfigDescriptionDefault": "Admite entrada de configuración importante (API URL, API Key, Model) y gestión de configuración JSON nativa.", - "multiAgent": { - "title": "Colaboración multiagente", - "description": "Permite que los agentes activos deleguen subtareas a otros agentes.", - "enable": "Activar delegación", - "enableHint": "Cuando está desactivado, la herramienta delegate_to_agent se oculta del catálogo de herramientas MCP del agente.", - "withheldByHostTools": "{agents} no recibirán las herramientas de delegación: su interruptor por agente «Deja que el agente gestione archivos y comandos» está activado.", - "depthLimit": "Profundidad máxima de delegación", - "depthHint": "Rango permitido: {min}–{max}. Limita la profundidad de recursión de una cadena de delegación (raíz → hijo → nieto …).", - "completedCacheLabel": "Caché de resultados completados (MB)", - "completedCacheHint": "Caché en memoria de los resultados completados de subagentes, que se conserva solo mientras la sesión de delegación está en ejecución y se libera automáticamente cuando esa sesión termina. Al superar este presupuesto, los resultados más antiguos se descartan primero de la memoria (aún visibles en la sesión propia del subagente); 0 = sin límite (igualmente se libera al terminar la sesión).", - "save": "Guardar", - "saving": "Guardando…", - "saved": "Configuración de delegación guardada", - "saveFailed": "Error al guardar la configuración de delegación", - "loadFailed": "Error al cargar la configuración de delegación: {detail}", - "tabGeneral": "General", - "tabAgentDefaults": "Valores por defecto del agente", - "agentDefaultsDescription": "Anulaciones por agente que se aplican cuando Colaboración multiagente inicia un subagente para una llamada de delegación. Las opciones mostradas provienen de un sondeo en vivo: lo que selecciones es exactamente lo que el agente aceptará.", - "probing": "Cargando las opciones disponibles del agente…", - "probeFailed": "Error al cargar las opciones: {detail}", - "retry": "Reintentar", - "noConfigAvailable": "Este agente no tiene opciones configurables.", - "modeLabel": "Modo", - "agentDefaultHint": "Predeterminado del agente: {value}", - "defaultOptionLabel": "Predeterminado ({value})" - }, - "actions": { - "dragSort": "Arrastrar para reordenar", - "dragSortAgent": "Arrastrar para reordenar {name}", - "refreshCheck": "Actualizar comprobación", - "refreshCheckAgent": "Actualizar comprobación de {name}", - "clickEnable": "Haz clic para habilitar {name}", - "clickDisable": "Haz clic para deshabilitar {name}", - "install": "Instalar", - "upgrade": "Actualizar", - "uninstall": "Desinstalar", - "uninstalling": "Desinstalando...", - "saveEnvVars": "Guardar variables de entorno", - "saving": "Guardando...", - "saveGrokConfig": "Guardar configuración de Grok", - "saveCodexConfig": "Guardar configuración de Codex", - "saveGeminiConfig": "Guardar configuración de Gemini", - "saveOpenCodeConfig": "Guardar configuración de OpenCode", - "saveOpenClawConfig": "Guardar configuración de OpenClaw", - "saveConfigManagement": "Guardar gestión de configuración", - "saveCurrentProvider": "Guardar proveedor actual", - "showApiKey": "Mostrar API Key", - "hideApiKey": "Ocultar API Key", - "showKey": "Mostrar clave", - "hideKey": "Ocultar clave", - "showToken": "Mostrar token", - "hideToken": "Ocultar token", - "cancel": "Cancelar", - "delete": "Eliminar", - "deleting": "Eliminando...", - "confirmDelete": "Confirmar eliminación", - "confirmUninstall": "Confirmar desinstalación", - "saveClineConfig": "Guardar configuración de Cline", - "saveHermesConfig": "Guardar configuración de Hermes", - "saveCodeBuddyConfig": "Guardar configuración de CodeBuddy", - "saveKimiCodeConfig": "Guardar configuración de Kimi Code", - "customInstall": "Instalación personalizada", - "saveKimiCodeRawConfig": "Save config.toml", - "saveDeepSeekConfig": "Guardar configuración de DeepSeek", - "diagnose": "Diagnosticar" - }, - "status": { - "enabled": "Habilitado", - "disabled": "Deshabilitado", - "unchecked": "Sin comprobar", - "agentEnabledAria": "{name} habilitado", - "agentEnabledSwitch": "Interruptor de habilitación de {name}" - }, - "preflight": { - "count": "Elementos de preflight: {count}", - "notRun": "Las comprobaciones aún no se han ejecutado." - }, - "grok": { - "configDescription": "Configura Grok aquí. Los controles siguientes —modo de permisos, esfuerzo de razonamiento, un modelo personalizado opcional (endpoint propio) y la compactación— se combinan en ~/.grok/config.toml, conservando tus otras claves y comentarios. El inicio de sesión usa tu XAI_API_KEY o `grok login`. Las demás claves siguen siendo editables en Avanzado.", - "permissionModeLabel": "Modo de permisos", - "permissionDefault": "Preguntar siempre", - "permissionAcceptEdits": "Aprobar ediciones automáticamente", - "permissionAuto": "Aprobación automática inteligente", - "permissionAlwaysApprove": "Aprobar siempre", - "reasoningEffortLabel": "Esfuerzo de razonamiento", - "effortLow": "Bajo (más rápido)", - "effortMedium": "Medio (equilibrado)", - "effortHigh": "Alto", - "effortXhigh": "Máximo", - "optionDefault": "Usar predeterminado", - "authTitle": "Autenticación", - "authMode": "Método de autenticación", - "authModeApiKey": "Clave de API de XAI", - "authModeApiKeyHint": "Autentícate con una XAI_API_KEY de la consola de xAI, para ejecuciones no interactivas o headless. Se guarda en el entorno de este agente.", - "authModeCustom": "Endpoint personalizado", - "authModeCustomHint": "Usa un endpoint propio (BYO): define abajo un modelo personalizado con su propia base URL y clave de API. Se convierte en el modelo predeterminado de Grok.", - "subscriptionHint": "Inicia sesión con `grok login` (SuperGrok / X Premium+). No se guarda ninguna clave de API.", - "loginHint": "Ejecuta esto en una terminal para iniciar sesión y luego vuelve a abrir esta configuración:", - "commandCopied": "Comando copiado al portapapeles", - "copyCommand": "Copiar comando", - "authKeyConfigured": "XAI_API_KEY está configurada.", - "authKeyMissing": "No hay XAI_API_KEY configurada.", - "advancedToggle": "Avanzado (config.toml sin procesar)", - "configTomlNative": "config.toml (nativo)", - "configTomlHint": "Se guarda literalmente como todo el ~/.grok/config.toml. El TOML no válido se rechaza para que una errata no trunque tu archivo.", - "configTomlPlaceholder": "# Claves distintas de los controles de arriba, p. ej.\n# [mcp_servers.*], [cli], reglas [permission].", - "customModelTitle": "Modelo personalizado (endpoint propio)", - "customModelHint": "Apunta Grok a un endpoint personalizado o autoalojado. codeg escribe un bloque `[model.*]` por modelo y lo establece como predeterminado. Deja el ID de modelo vacío para eliminarlo.", - "customModelIdLabel": "ID del modelo", - "customModelIdPlaceholder": "grok-4.5", - "customModelIdHint": "Se registra como un bloque `[model.*]` y se envía a la API como nombre del modelo; también se establece como `[models].default`.", - "customBaseUrlLabel": "URL base", - "customBaseUrlPlaceholder": "https://api.x.ai/v1 (predeterminado)", - "customApiBackendLabel": "Backend de la API", - "backendResponses": "Responses", - "backendChatCompletions": "Chat Completions", - "backendMessages": "Messages (Anthropic)", - "customApiKeyLabel": "Clave de API", - "customApiKeyHint": "Se guarda en línea en `[model.*].api_key`, limitada a este endpoint.", - "customContextWindowLabel": "Ventana de contexto (tokens)", - "customContextWindowHint": "Opcional. Determina el momento de la autocompactación; déjalo vacío para el valor predeterminado del endpoint.", - "autoCompactLabel": "Umbral de autocompactación (%)", - "autoCompactHint": "Compacta la conversación cuando el uso del contexto alcanza este porcentaje (predeterminado de Grok: 85). Se escribe en `[session]`." - }, - "cursor": { - "configDescription": "Configura Cursor aquí. Elige un método de autenticación —suscripción oficial (inicio de sesión en el navegador) o una clave API de Cursor para equipos sin interfaz o servidores— y luego elige un modelo y edita las reglas de permisos y el sandbox del CLI. codeg los escribe en ~/.cursor/cli-config.json, compartido con el CLI cursor-agent.", - "authTitle": "Autenticación", - "authChecking": "Comprobando…", - "authNotInstalled": "cursor-agent no está instalado", - "authLoggedIn": "Sesión iniciada", - "authNotLoggedIn": "Sin sesión", - "loginHint": "Ejecuta esto en una terminal para iniciar sesión con tu cuenta de Cursor (se abre el navegador) y luego pulsa actualizar:", - "apiKeyLabel": "Clave API de Cursor", - "apiKeyPlaceholder": "clave de cursor.com/dashboard", - "apiKeyHint": "CURSOR_API_KEY: una clave de cuenta del panel de Cursor, alternativa al inicio de sesión en el navegador para equipos sin interfaz o servidores. No es una clave de terceros ni de OpenAI.", - "modelTitle": "Modelo predeterminado", - "loadModels": "Cargar modelos", - "modelsUnavailable": "Lista de modelos no disponible", - "modelHint": "Se pasa a la CLI como --model al iniciar la sesión. Déjalo en predeterminado para que Cursor elija.", - "permissionsTitle": "Permisos y sandbox", - "permissionsDescription": "Editor visual de las reglas de permisos de la CLI (cli-config.json). Las reglas permitidas se ejecutan sin confirmación; las denegadas se bloquean siempre.", - "permissionModeLabel": "Modo de permisos", - "permissionModeDefault": "Preguntar antes de ejecutar (predeterminado)", - "permissionModeForce": "Run Everything (--force)", - "permissionModeHint": "Run Everything inicia las sesiones con --force: todas las llamadas de herramientas se permiten automáticamente salvo las reglas de denegación, sin confirmaciones (una política de la organización puede limitarlo a las reglas de permiso). Se aplica a las sesiones nuevas.", - "optionDefault": "Predeterminado (sin definir)", - "sandboxLabel": "Sandbox", - "sandboxEnabled": "Activado", - "sandboxDisabled": "Desactivado", - "allowRulesLabel": "Reglas permitidas", - "denyRulesLabel": "Reglas denegadas", - "addRule": "Añadir regla", - "rulesSyntaxHint": "Sintaxis de reglas: Shell(cmd), Read(ruta/glob), Write(ruta/glob), WebFetch(dominio), Mcp(servidor:herramienta) — las reglas de denegación siempre prevalecen.", - "saveConfig": "Guardar configuración", - "advancedToggle": "Avanzado: cli-config.json sin procesar", - "advancedHint": "El ~/.cursor/cli-config.json completo. Guardar escribe el archivo tal cual; los controles estructurados de arriba se fusionan en él.", - "saveRawConfig": "Guardar archivo", - "authMode": "Método de autenticación", - "subscriptionHint": "Inicia sesión con tu cuenta de Cursor y usa los modelos de Cursor.", - "customApiKeyRequired": "Se requiere una clave API de Cursor.", - "authModeApiKey": "Clave API de Cursor (sin interfaz)", - "authModeApiKeyHint": "Autentícate con una clave API de cuenta de Cursor generada en el panel de Cursor (para equipos sin interfaz o servidores). Es una clave de cuenta de Cursor, no un endpoint de terceros/OpenAI: cursor-agent solo se comunica con el backend de Cursor. Para usar un endpoint compatible con codex/OpenAI, usa el agente Codex en su lugar.", - "modelPickerPlaceholder": "Buscar modelos…", - "modelNoMatch": "Ningún modelo coincide", - "modelsNeedAuth": "Inicia sesión para cargar la lista de modelos.", - "modelDefaultBadge": "predeterminado" - }, - "deepseek": { - "configManagement": "Configuración de DeepSeek Harness", - "configDescription": "El endpoint y la clave son variables de entorno que deepseek-acp lee al arrancar. El modelo y el esfuerzo de razonamiento son selectores por sesión: se eligen en el campo de mensaje.", - "baseUrlLabel": "Endpoint de la API", - "baseUrlHint": "Déjalo vacío para el endpoint oficial. Se aplica a las sesiones iniciadas tras guardar; vuelve a conectar una sesión en curso para que lo tome.", - "baseUrlInvalid": "Introduce una URL http(s) completa y sin cadena de consulta, por ejemplo https://api.deepseek.com", - "apiKeyLabel": "Clave de API", - "apiKeyHint": "Se pasa al agente como DEEPSEEK_API_KEY. Una variable de entorno tiene prioridad sobre el archivo de credenciales, así que déjala vacía si inicias sesión desde la terminal." - }, - "codex": { - "configDescription": "Admite configuración rápida de URL de API, API Key, nombre del modelo y reasoning effort, y sincroniza con `auth.json` / `config.toml`.", - "authMode": "Modo de Autenticación", - "chatgptSubscription": "Suscripción oficial", - "chatgptSubscriptionHint": "Iniciar sesión con suscripción oficial de ChatGPT, sin necesidad de API Key", - "apiKeyHint": "Conectar usando API Key a OpenAI o servicios API compatibles", - "selectProvider": "Seleccionar proveedor", - "modelName": "Nombre del modelo", - "selectReasoningEffort": "Seleccionar Reasoning Effort", - "enableWebsocket": "Habilitar WebSocket", - "enableWebsocketAria": "Habilitar WebSocket para Codex Provider", - "enableSkills": "Habilitar Skills", - "enableSkillsAria": "Habilitar Skills para Codex", - "enableFast": "Habilitar Fast", - "enableFastAria": "Habilitar nivel de servicio Fast para Codex", - "sandboxGroupTitle": "Sandbox y aprobaciones", - "sandboxGroupHint": "Se escribe en el ~/.codex/config.toml global, por lo que también lo ven las sesiones de codex CLI e IDE. Son valores predeterminados del hilo: rigen los turnos que codex inicia por su cuenta (/goal, /review, /compact). Los mensajes normales usan el preajuste de aprobación del compositor. Reinicia una sesión para aplicar los cambios.", - "sandboxShadowedWarning": "config.toml define default_permissions, así que codex resuelve los permisos con ese perfil e ignora sandbox_mode por completo. Elimina default_permissions para usar los controles de abajo.", - "sandboxPermissionsTableWarning": "config.toml define perfiles [permissions] pero no default_permissions, lo que impide que codex arranque. Configúralo en el editor sin formato de abajo.", - "approvalPolicyLabel": "Política de aprobación", - "approvalPolicyUnset": "Sin definir (predeterminado de codex: a petición)", - "approvalPolicy_on-request": "A petición: el modelo decide cuándo preguntar", - "approvalPolicy_untrusted": "No confiable: solo se ejecutan sin supervisión los comandos de solo lectura seguros", - "approvalPolicy_never": "Nunca: sin ninguna solicitud de aprobación", - "approvalPolicy_granular": "Granular: elige por tipo de solicitud", - "approvalPolicyUntrustedAcpWarning": "Untrusted no tiene equivalente entre los tres ajustes de aprobación del adaptador ACP, así que las sesiones de codeg recurren a «a petición»: el modelo decide entonces cuándo preguntar y los comandos que la zona aislada ya permite dejan de pedir confirmación. Restringe mejor el modo de aislamiento de abajo.", - "granularHint": "Desactivado significa que ese tipo de solicitud se rechaza automáticamente en vez de mostrártela.", - "granular_sandbox_approval": "Escalados de comandos de shell", - "granular_rules": "Avisos de reglas de execpolicy", - "granular_skill_approval": "Avisos de scripts de habilidades", - "granular_request_permissions": "Avisos de la herramienta request_permissions", - "granular_mcp_elicitations": "Avisos de elicitación MCP", - "sandboxModeLabel": "Modo de sandbox", - "sandboxModeUnset": "Sin definir (las carpetas de confianza usan escritura en el espacio de trabajo)", - "sandboxMode_read-only": "Solo lectura", - "sandboxMode_workspace-write": "Escritura en el espacio de trabajo", - "sandboxMode_danger-full-access": "Acceso total (sin sandbox)", - "sandboxModeHint": "En Windows, la escritura en el espacio de trabajo baja a solo lectura salvo que actives el sandbox experimental de Windows de codex.", - "sandboxModeSeedsPresetHint": "codeg también lo traduce al ajuste de aprobación inicial de la sesión, así que —a diferencia de la política de aprobación— sí afecta a las peticiones normales. El ajuste elegido en el editor sigue teniendo prioridad.", - "writableRootsLabel": "Carpetas adicionales con escritura", - "writableRootsHint": "Una ruta absoluta por línea, además del directorio de trabajo.", - "sandboxRootsRelativeError": "Debe ser una ruta absoluta: codex resuelve las rutas relativas dentro de ~/.codex: {path}", - "networkAccessLabel": "Permitir acceso a la red", - "excludeTmpdirLabel": "Excluir TMPDIR de las raíces con escritura", - "excludeSlashTmpLabel": "Excluir /tmp de las raíces con escritura", - "authJsonNative": "auth.json (nativo)", - "configTomlNative": "config.toml (nativo)", - "loginButton": "Iniciar sesión con ChatGPT", - "loginRequesting": "Solicitando código de inicio de sesión...", - "loginStep1": "Abre la siguiente URL en tu navegador:", - "loginStep2": "Introduce el siguiente código:", - "loginPolling": "Esperando autorización...", - "loginCancel": "Cancelar", - "loginSuccess": "¡Inicio de sesión exitoso, configuración guardada!", - "loginFailed": "Error de inicio de sesión: {message}", - "loginRetry": "Reintentar", - "loginCodeCopied": "Código copiado", - "loggedIn": "Cuenta conectada", - "loginRelogin": "Reconectar / Cambiar cuenta", - "loginTimeout": "Tiempo de inicio de sesión agotado, inténtalo de nuevo", - "loginSaveFailed": "Inicio de sesión exitoso pero falló al guardar la configuración" - }, - "gemini": { - "authConfig": "Configuración de autenticación de Gemini", - "authConfigDescription": "Alineado con la documentación de autenticación de Gemini CLI, con soporte para endpoint personalizado, inicio de sesión de Google, Gemini API Key y Vertex AI (ADC / cuenta de servicio / API Key).", - "authMode": "Modo de autenticación", - "selectAuthMode": "Seleccionar modo de autenticación", - "viewAuthDoc": "Ver documentación de autenticación", - "mode": { - "custom": "Endpoint personalizado", - "loginGoogle": "Inicio de sesión de Google (OAuth)", - "vertexServiceAccount": "Vertex AI (Cuenta de servicio)" - }, - "hint": { - "custom": "Completa API URL, API Key y Modelo; se mapean a GOOGLE_GEMINI_BASE_URL / GEMINI_API_KEY / GEMINI_MODEL.", - "loginGoogle": "Ejecuta gemini en terminal y completa primero el inicio de sesión de Google; no se requiere API key.", - "geminiApiKey": "Completa GEMINI_API_KEY cuando uses la API de Gemini.", - "vertexAdc": "Usa gcloud ADC; se recomienda configurar GOOGLE_CLOUD_PROJECT y GOOGLE_CLOUD_LOCATION.", - "vertexServiceAccount": "Establece la ruta del JSON de la cuenta de servicio en GOOGLE_APPLICATION_CREDENTIALS.", - "vertexApiKey": "Completa GOOGLE_API_KEY cuando uses API key de Vertex AI." - } - }, - "openCode": { - "configManagement": "Gestión de configuración de OpenCode", - "configDescription": "Alineado con el esquema `provider` de OpenCode, admite gestión de múltiples proveedores y sincronización bidireccional con archivos JSON nativos.", - "providerManagement": "Gestión de proveedores", - "providerCount": "{count} proveedores", - "addProvider": "Agregar proveedor", - "emptyProvider": "Aún no hay proveedores personalizados. Haz clic en Agregar proveedor personalizado para crear uno.", - "providerEnabledState": "Estado habilitado de {providerId}", - "selectProviderNpm": "Seleccionar provider.npm", - "modelManagement": "Gestión de modelos", - "modelCount": "{count} modelos", - "modelDescription": "Alineado con `provider.models` de OpenCode. La gestión rápida actualmente soporta `name` / `id`; otros campos avanzados se conservan y se pueden editar en el JSON nativo de abajo.", - "addModel": "Agregar modelo", - "emptyModel": "Aún no hay modelo. Introduce model id y haz clic en \"Agregar modelo\".", - "modelId": "ID de modelo", - "modelName": "Nombre del modelo", - "deleteModel": "Eliminar modelo {modelId}", - "nativeJsonConfig": "Configuración JSON nativa de OpenCode", - "mainModel": "Modelo principal", - "smallModel": "Modelo pequeño", - "noMatchingModels": "No hay modelos coincidentes", - "connectProvider": "Conectar proveedor", - "connectedProviders": "Proveedores conectados", - "noConnectedProviders": "Aún no hay proveedores del catálogo conectados.", - "advancedProviderConfig": "Proveedores personalizados", - "customProviderConfigHint": "Endpoints compatibles con OpenAI que defines tú mismo: un bloque de provider en opencode.json, con la API key en auth.json.", - "addCustomProvider": "Agregar proveedor personalizado", - "disconnect": "Desconectar", - "editConfig": "Editar", - "customBadge": "Personalizado", - "authKindApi": "Clave API", - "authKindOauth": "OAuth", - "authKindNone": "Sin credencial", - "connect": { - "title": "Conectar un proveedor", - "description": "Elige un proveedor del catálogo de models.dev. Las credenciales se guardan en el archivo auth.json de OpenCode.", - "pick": "Proveedor", - "search": "Buscar proveedores…", - "loading": "Cargando catálogo…", - "catalogLabel": "Catálogo de models.dev", - "modelsAvailable": "{count} modelos disponibles", - "getKey": "Obtener clave API", - "oauthApiKeyNote": "Este proveedor también admite el inicio de sesión por navegador con opencode auth login. El inicio por navegador llegará pronto; por ahora, pega una clave API.", - "apiKey": "Clave API", - "apiKeyHint": "Se guarda en auth.json, nunca en opencode.json.", - "baseUrlOptional": "Anular Base URL (opcional)", - "providerId": "ID del proveedor", - "displayName": "Nombre visible", - "modelsList": "Modelos (uno por línea)", - "modelsHint": "IDs de modelo que acepta el endpoint.", - "action": "Conectar", - "editTitle": "Editar proveedor", - "editDescription": "Actualiza la clave API o la Base URL de este proveedor.", - "saveAction": "Guardar" - }, - "customProvider": { - "title": "Agregar un proveedor personalizado", - "description": "Define un endpoint compatible con OpenAI. La API key se guarda en auth.json; el bloque de provider va a opencode.json.", - "action": "Agregar proveedor", - "idInCatalog": "{providerId} es un proveedor conocido: conéctalo mediante Conectar proveedor." - }, - "refreshCatalog": "Actualizar catálogo", - "reasoningBadge": "razonamiento", - "contextWindow": "Ventana de contexto", - "permissions": { - "title": "Permisos", - "description": "Decide qué acciones se ejecutan solas, cuáles te preguntan primero y cuáles se bloquean. Se escribe en el bloque permission de opencode.json y se aplica al guardar abajo.", - "docsLink": "Documentación de permisos", - "unparsableConfig": "El JSON nativo de abajo no es válido, así que el editor visual está pausado. Corrige el JSON para continuar.", - "invalidBlock": "El bloque permission tiene una forma que codeg no reconoce. Edítalo en el JSON nativo de abajo o usa Restablecer para empezar de nuevo.", - "orderingUnsafe": "Hay una regla comodín escrita después de herramientas concretas, así que OpenCode también se la aplica a ellas: las filas de abajo no son lo que está en vigor. Corregir orden solo devuelve cada comodín al principio de su ámbito, sin cambiar ningún valor.", - "orderingUnsafeManual": "Una regla queda tapada por un patrón posterior más general, así que OpenCode nunca la aplica: las filas de abajo no son lo que está en vigor. Dos patrones que se solapan no tienen un único orden correcto; reordénalos en el JSON nativo para que el más general vaya primero.", - "fixOrder": "Corregir orden", - "agentOverrides": "Estos agentes anulan los permisos y se aplican al final, así que ganan sobre todo lo de aquí: {agents}. Edítalos en el JSON nativo de abajo o activa el aceptar automático para borrarlos.", - "legacyTools": "El mapa tools heredado del nivel superior deniega una herramienta. OpenCode lo fusiona con los permisos, así que se aplica por encima de todo lo que se ve aquí. Edítalo en el JSON nativo de abajo o activa el aceptar automático para borrarlo.", - "autoAcceptTitle": "Aceptar todos los permisos automáticamente", - "autoAcceptHint": "Toda llamada a herramientas —comandos de shell, ediciones de archivos, rutas fuera del proyecto— se ejecuta sin preguntar. Al activarlo, los ajustes por herramienta de abajo se sustituyen por una única regla que lo permite todo, y se borran las anulaciones por agente y los conmutadores tools heredados que si no seguirían bloqueando.", - "globalLabel": "Valor global por defecto", - "globalHint": "La regla *: se aplica a todo lo que las herramientas de abajo no anulen.", - "actionUnset": "Sin definir (valores de OpenCode)", - "actionInherit": "Heredar ({action})", - "actionAllow": "Permitir", - "actionAsk": "Preguntar", - "actionDeny": "Denegar", - "perToolTitle": "Permisos por herramienta", - "reset": "Restablecer", - "ruleCount": "reglas: {count}", - "rulesToggle": "Reglas detalladas de {tool}", - "rulesHint": "Se comparan con la entrada de la herramienta y gana la última coincidencia, así que pon primero los patrones amplios. * coincide con cualquier cantidad de caracteres, ? con exactamente uno, y un ~ inicial se expande a tu carpeta personal.", - "noRules": "Todavía no hay reglas detalladas.", - "addRule": "Añadir regla", - "deleteRule": "Eliminar la regla {pattern}", - "duplicateRule": "Ese patrón ya existe.", - "blankRule": "Una regla necesita un patrón; usa el icono de papelera para eliminarla.", - "customKeys": "Otras claves de permiso del archivo", - "customKeyHint": "No es una herramienta integrada de OpenCode; se conserva tal cual.", - "keys": { - "bash": "Ejecutar comandos de shell, según el comando analizado", - "edit": "Todas las modificaciones de archivos: edit, write y patch", - "read": "Leer archivos, según la ruta", - "external_directory": "Acceder a rutas fuera del directorio de trabajo del proyecto", - "task": "Lanzar subagentes, según el tipo de subagente", - "skill": "Cargar habilidades, según su nombre", - "glob": "Buscar archivos, según el patrón glob", - "grep": "Buscar en el contenido de los archivos, según el patrón", - "list": "Listar el contenido de un directorio", - "webfetch": "Descargar una URL", - "websearch": "Buscar en la web", - "lsp": "Ejecutar consultas LSP", - "todowrite": "Escribir la lista de tareas", - "question": "Hacerte una pregunta", - "doom_loop": "Se activa cuando la misma llamada se repite tres veces con la misma entrada" - } - } - }, - "openClaw": { - "gatewayConfig": "Configuración de Gateway", - "gatewayDescription": "Configura la conexión de OpenClaw Gateway. Admite gateway local o remoto.", - "gatewayUrlHint": "Déjalo vacío para usar gateway.remote.url desde la configuración local de openclaw.", - "gatewayTokenPlaceholder": "Token de autenticación de Gateway", - "gatewayTokenHint": "Usa token-file en lugar de token en texto plano cuando sea posible; configúralo con el CLI de openclaw.", - "sessionKeyHint": "Opcional. Especifica la session key del gateway; si se deja vacío se asigna automáticamente una sesión aislada." - }, - "hermes": { - "configManagement": "Configuración de Hermes", - "configDescription": "Hermes gestiona sus propias credenciales en ~/.hermes/.env y los ajustes en ~/.hermes/config.yaml. Elige un proveedor y luego establece la clave de API y el modelo: codeg escribe ambos archivos por ti.", - "providerLabel": "Proveedor", - "providerHint": "El proveedor determina qué variable de clave de API y qué model.provider usa Hermes. Los proveedores de OAuth se configuran mediante la configuración del terminal que aparece a continuación.", - "groupApiKey": "Proveedores con clave API", - "groupOauth": "Proveedores OAuth", - "groupAws": "AWS", - "apiKeyHint": "Se guarda en ~/.hermes/.env. Nunca se inyecta en el proceso: Hermes la lee de su propia configuración.", - "modelName": "Modelo", - "oauthHint": "Este proveedor usa OAuth. Ejecuta la configuración de abajo para autenticarte en tu terminal.", - "awsHint": "Bedrock usa tus credenciales de AWS (entorno o configuración compartida). Define el ID del modelo arriba y configura el acceso a AWS en tu entorno.", - "unsupportedProvider": "Este proveedor no se puede editar con campos estructurados. Usa el editor de config.yaml de abajo o la configuración por terminal.", - "setupTitle": "Configuración autogestionada", - "setupHint": "La configuración interactiva de Hermes necesita un terminal. Iníciala abajo o copia el comando para ejecutarlo tú mismo.", - "runSetup": "Ejecutar configuración de Hermes", - "configureModel": "Configurar modelo", - "openConfigFolder": "Abrir ~/.hermes", - "copyCommand": "Copiar comando", - "commandCopied": "Comando copiado al portapapeles", - "advancedTitle": "Avanzado: editar config.yaml", - "rawConfigHint": "Edita ~/.hermes/config.yaml directamente. Guardar aquí sobrescribe el archivo tal cual.", - "saveRawConfig": "Guardar config.yaml" - }, - "codebuddy": { - "configManagement": "Configuración de CodeBuddy", - "configDescription": "CodeBuddy se autentica con una clave de API. Las versiones para China continental también requieren establecer el entorno en «China (internal)»; las versiones iOA usan «iOA». La versión internacional lo deja sin definir.", - "apiKeyLabel": "Clave de API", - "apiKeyHint": "Se guarda como CODEBUDDY_API_KEY para este agente. También puedes iniciar sesión con la CLI de CodeBuddy en una terminal.", - "apiKeyHintSelfHosted": "Se guarda como CODEBUDDY_API_KEY para este agente. Usa la clave emitida por tu implementación privada.", - "environmentLabel": "Entorno", - "environmentHint": "Establece CODEBUDDY_INTERNET_ENVIRONMENT. China continental debe usar «China (internal)»; la versión internacional lo deja sin definir.", - "envOverseas": "Internacional (predeterminado)", - "envChina": "China (internal)", - "envIoa": "iOA", - "envSelfHosted": "Autoalojado (implementación privada)", - "baseUrlLabel": "URL de implementación", - "baseUrlPlaceholder": "https://codebuddy.your-company.com", - "baseUrlHint": "Se guarda como CODEBUDDY_BASE_URL y dirige CodeBuddy a tu endpoint privado. En autoalojado, el entorno de red (CODEBUDDY_INTERNET_ENVIRONMENT) queda sin configurar.", - "baseUrlInvalid": "Introduce una URL http(s) válida.", - "loginHint": "¿No tienes clave de API? Ejecuta «codebuddy» en una terminal para iniciar sesión con tu cuenta de Tencent." - }, - "kimiCode": { - "configManagement": "Configuración de Kimi Code", - "configDescription": "`kimi acp` solo acepta un token de sesión almacenado, así que codeg escribe un proveedor gestionado en ~/.kimi-code/config.toml y siembra un token de acceso local: la inferencia sigue usando tu propia clave.", - "statusUnconfigured": "Sin configurar", - "statusDirty": "Cambios sin guardar", - "summaryLabel": "En vigor", - "gateReadyApiKey": "Clave de API escrita en config.toml", - "gateReadyLogin": "Sesión iniciada con una cuenta de Kimi", - "revealConfig": "Mostrar en la carpeta", - "envOverrideWarning": "{keys} está definido y tiene prioridad sobre config.toml. Al guardar aquí se elimina.", - "authModeLabel": "Método de autenticación", - "authModeApiKey": "Clave de API", - "authModeLogin": "Inicio de sesión de Kimi (suscripción)", - "authModeApiKeyHint": "Escribe un proveedor gestionado en config.toml y siembra el token de acceso para que las sesiones puedan abrirse.", - "loginHint": "Ejecuta `kimi login` en una terminal para iniciar sesión con una cuenta de suscripción de Kimi. codeg no guarda nada y reutiliza el inicio de sesión de Kimi. Guardar aquí elimina el token de acceso por clave de API de codeg.", - "credentialTitle": "Credencial", - "interfaceTypeLabel": "Tipo de proveedor", - "interfaceTypeHint": "El protocolo de proveedor que habla Kimi (el `type` de config.toml). Usa Kimi / Moonshot para una clave de Moonshot / platform.kimi.com.", - "endpointLabel": "Endpoint", - "endpointCustom": "Personalizado (compatible con OpenAI)", - "endpointHint": "Internacional = api.moonshot.ai; China (claves de platform.kimi.com) = api.moonshot.cn. Personalizado apunta a cualquier endpoint compatible con OpenAI.", - "regionInternational": "Internacional (api.moonshot.ai)", - "regionChina": "China (api.moonshot.cn)", - "baseUrlLabel": "URL base", - "baseUrlHint": "Déjalo en blanco para usar el valor por defecto del SDK del proveedor.", - "apiKeyLabel": "Clave de API", - "apiKeyHint": "Se escribe en ~/.kimi-code/config.toml y se usa para la inferencia. De platform.kimi.com o platform.kimi.ai.", - "vertexProjectLabel": "Proyecto de GCP (GOOGLE_CLOUD_PROJECT)", - "vertexLocationLabel": "Región de GCP (GOOGLE_CLOUD_LOCATION)", - "vertexHint": "Vertex AI usa las credenciales predeterminadas de aplicación de Google: ejecuta `gcloud auth application-default login` (sin clave de API).", - "modelTitle": "Modelo", - "modelLabel": "Modelo", - "modelHint": "El id de modelo que se escribe en config.toml. Usa «Probar y listar modelos» para ver a cuáles puede acceder tu clave.", - "maxContextLabel": "Tamaño máximo de contexto", - "maxContextHint": "Obligatorio según el esquema de Kimi: sin él, Kimi descarta todo el bloque del modelo y ninguna consulta devuelve respuesta. Por defecto 262144.", - "fetchModels": "Probar y listar modelos", - "fetchModelsOk": "La clave funciona: {count} modelos disponibles", - "fetchModelsEmpty": "La clave funciona, pero no se devolvió ningún modelo", - "fetchModelsFailed": "La prueba falló", - "fetchModelsNeedsKey": "Introduce primero una clave de API y un endpoint", - "modelNotInList": "Este modelo no está en la lista a la que tu clave puede acceder: Kimi fallará con «modelo no encontrado».", - "reasoningTitle": "Razonamiento", - "reasoningEnableLabel": "Activar", - "reasoningDescription": "Kimi solo muestra el selector «Thinking» en el cuadro de mensaje cuando el modelo declara una capacidad de razonamiento, así que codeg la escribe aquí. Se aplica a las sesiones nuevas.", - "effortsLabel": "Niveles ofrecidos", - "effortsHint": "Estos son los niveles que aparecerán en el selector «Thinking». Kimi los reenvía al proveedor tal cual, así que elige los que acepte tu modelo.", - "effortsEmptyHint": "Sin ningún nivel elegido, el cuadro de mensaje se reduce a un simple interruptor Off / On.", - "effortsCustomPlaceholder": "Añadir otro nivel", - "effortsAdd": "Añadir", - "defaultEffortLabel": "Nivel por defecto", - "defaultEffortAuto": "Que elija Kimi", - "alwaysThinkingLabel": "El modelo siempre razona: quitar la opción Off del selector", - "fixErrorsFirst": "Corrige primero los campos marcados", - "errorModelRequired": "El modelo es obligatorio", - "errorMaxContextRequired": "El tamaño máximo de contexto es obligatorio", - "errorMaxContextInvalid": "Debe ser un entero positivo", - "errorApiKeyRequired": "La clave de API es obligatoria", - "errorApiKeyInvalid": "La clave de API no puede contener saltos de línea", - "errorBaseUrlRequired": "La URL base es obligatoria", - "errorBaseUrlInvalid": "Debe empezar por http:// o https://", - "errorVertexProjectRequired": "El proyecto de GCP es obligatorio", - "errorDefaultEffortUnlisted": "Elige uno de los niveles seleccionados arriba", - "advancedTitle": "Avanzado", - "authTypeLabel": "Ubicación de la credencial", - "authTypeApiKey": "api_key en línea", - "authTypeEnv": "Subtabla env del proveedor", - "authTypeHint": "Dónde se escribe la clave de API dentro de config.toml.", - "rawEditorLabel": "Editar config.toml directamente", - "rawEditorWarning": "Guardar aquí sobrescribe el archivo completo tal cual y reemplaza la configuración estructurada de arriba.", - "rawEditorPlaceholder": "[providers.codeg]\ntype = \"kimi\"\nbase_url = \"https://api.moonshot.cn/v1\"\napi_key = \"sk-...\"" - }, - "authModeOfficialSubscription": "Suscripción oficial", - "authModeCustomEndpoint": "Endpoint personalizado", - "authModeCustomEndpointHint": "Configurar manualmente la URL de API y la clave API para un endpoint personalizado.", - "authModeModelProvider": "Proveedor de modelo", - "modelProvider": "Proveedor de modelo", - "modelProviderHint": "Usar la URL de API, la clave API y el modelo de un proveedor de modelo configurado.", - "selectModelProvider": "Seleccionar proveedor de modelo", - "noModelProviderAvailable": "No hay proveedor de modelo configurado para este agente. Vaya a la configuración de proveedores de modelo para agregar uno.", - "claude": { - "authMode": "Modo de autenticación", - "officialSubscription": "Suscripción oficial", - "officialSubscriptionHint": "Usar la suscripción oficial de Anthropic, no se requiere API Key.", - "mainModel": "Modelo principal", - "reasoningModel": "Modelo de razonamiento (thinking)", - "haikuDefaultModel": "Modelo Haiku predeterminado", - "sonnetDefaultModel": "Modelo Sonnet predeterminado", - "opusDefaultModel": "Modelo Opus predeterminado", - "customModelOption": "ID de modelo personalizado", - "customModelOptionName": "Nombre del modelo personalizado", - "customModelOptionDescription": "Descripción del modelo personalizado", - "customModelOptionHint": "Añade una única entrada personalizada al selector de modelos de Claude (por ejemplo, un modelo detrás de una pasarela/proxy personalizado). El nombre y la descripción son opcionales y solo afectan a la visualización.", - "effortLevel": "Nivel de razonamiento", - "effortLevelDefault": "Nivel predeterminado", - "effortLevel_low": "Bajo", - "effortLevel_medium": "Medio", - "effortLevel_high": "Alto", - "effortLevel_xhigh": "Extra Alto", - "sendAttributionHeader": "Enviar identificador de atribución/facturación a la API", - "sendAttributionHeaderAria": "Enviar el identificador de atribución/facturación de Claude Code a la API", - "disableNonessentialTraffic": "Desactivar la telemetría o las solicitudes de red innecesarias", - "disableNonessentialTrafficAria": "Desactivar la telemetría o las solicitudes de red innecesarias de Claude Code" - }, - "dialogs": { - "confirmDeleteProvider": "¿Eliminar proveedor {providerId}?", - "confirmDeleteProviderDescription": "La configuración de OpenCode y auth JSON se actualizarán juntos. Esta acción no se puede deshacer.", - "confirmUninstall": "¿Desinstalar {name}?", - "confirmUninstallDescription": "Esto elimina la versión instalada localmente. Puedes reinstalar más tarde.", - "customInstallTitle": "Instalación personalizada de {name}", - "customInstallDescription": "Introduce la versión que quieres instalar. Se reinstalará y reemplazará la versión instalada actualmente.", - "customInstallVersionLabel": "Número de versión", - "customInstallInvalid": "Introduce un número de versión válido, p. ej. 1.2.3.", - "customInstallSubmit": "Instalar" - }, - "errors": { - "windowsFileLocked": "Los archivos de {name} están en uso por una sesión activa, por lo que Windows no puede reemplazarlos. Cierra todas las sesiones de {name} e inténtalo de nuevo.", - "nativeJsonMustBeObject": "La configuración JSON nativa debe ser un objeto", - "nativeJsonInvalid": "Error de formato en JSON nativo: {message}", - "openCodeAuthMustBeObject": "OpenCode auth.json debe ser un objeto JSON", - "openCodeAuthInvalid": "Error de formato en OpenCode auth.json: {message}", - "authMustBeObject": "auth.json debe ser un objeto JSON", - "authInvalid": "Error de formato en auth.json: {message}", - "providerIdPattern": "El ID de proveedor solo admite letras, números, guion bajo, punto y guion", - "providerExists": "El proveedor {providerId} ya existe", - "modelIdPattern": "El ID de modelo solo admite letras, números, guion bajo, punto, dos puntos y guion", - "modelExists": "El modelo {modelId} ya existe" - }, - "warnings": { - "nativeJsonRecoveredStructured": "La configuración JSON nativa es inválida; se restableció a configuración estructurada", - "nativeJsonRecoveredOpenCode": "La configuración JSON nativa es inválida; se restableció a configuración estructurada de OpenCode", - "openCodeAuthRecovered": "OpenCode auth.json es inválido; se restableció a configuración predeterminada", - "authRecoveredStructured": "auth.json es inválido; se restableció a configuración estructurada" - }, - "toasts": { - "agentActionCompleted": "{name} {action} completado", - "agentActionFailed": "{name} {action} falló", - "localVersion": "Versión local: {version}", - "installCompletedVersionLater": "Instalación completada, la versión se actualizará en la próxima comprobación", - "uninstallCompleted": "Desinstalación de {name} completada", - "uninstallFailed": "Desinstalación de {name} fallida", - "localVersionRemoved": "Versión local eliminada", - "saveAgentOrderFailed": "No se pudo guardar el orden de Agent", - "saveAgentSwitchFailed": "No se pudo guardar el switch de Agent", - "saveEnvFailed": "No se pudieron guardar las variables de entorno", - "grokSaved": "Configuración de Grok guardada", - "saveGrokNativeFailed": "No se pudo guardar la configuración nativa de Grok", - "saveGrokApiKeyFailed": "Ajustes guardados, pero no se pudo guardar la clave API", - "cursorSaved": "Configuración de Cursor guardada", - "saveCursorConfigFailed": "Error al guardar la configuración de Cursor", - "codexSaved": "Configuración de Codex guardada", - "saveCodexNativeFailed": "No se pudo guardar la configuración nativa de Codex", - "geminiSaved": "Configuración de Gemini guardada", - "saveGeminiFailed": "No se pudo guardar la configuración de Gemini", - "providerDeleted": "Proveedor {providerId} eliminado", - "providerDeleteFailed": "No se pudo eliminar el proveedor {providerId}", - "providerSaved": "Proveedor {providerId} guardado", - "saveProviderFailed": "No se pudo guardar el proveedor {providerId}", - "openCodeConfigSynced": "La configuración de OpenCode y auth JSON se sincronizaron.", - "openCodeSaved": "Configuración de OpenCode guardada", - "saveOpenCodeFailed": "No se pudo guardar la configuración de OpenCode", - "openClawSaved": "Configuración de OpenClaw guardada", - "saveOpenClawFailed": "No se pudo guardar la configuración de OpenClaw", - "configSaved": "Configuración guardada", - "configSavedHint": "Las sesiones existentes deben reabrirse para que surta efecto", - "saveConfigManagementFailed": "No se pudo guardar la gestión de configuración", - "clineSaved": "Configuración de Cline guardada", - "saveClineFailed": "Error al guardar la configuración de Cline", - "hermesSaved": "Configuración de Hermes guardada", - "saveHermesFailed": "Error al guardar la configuración de Hermes", - "codeBuddySaved": "Configuración de CodeBuddy guardada", - "saveCodeBuddyFailed": "No se pudo guardar la configuración de CodeBuddy", - "kimiCodeSaved": "Configuración de Kimi Code guardada", - "saveKimiCodeFailed": "Error al guardar la configuración de Kimi Code", - "deepseekSaved": "Configuración de DeepSeek guardada", - "saveDeepSeekFailed": "No se pudo guardar la configuración de DeepSeek", - "modelProviderRequired": "Seleccione un proveedor de modelo antes de guardar.", - "affectedRunningSessions": "{count, plural, one {# sesión activa necesita reconectarse para aplicar el cambio} other {# sesiones activas necesitan reconectarse para aplicar el cambio}}", - "providerConnected": "Conectado {providerId}", - "connectFailed": "Error al conectar {providerId}", - "providerDisconnected": "Desconectado {providerId}", - "disconnectFailed": "Error al desconectar {providerId}", - "catalogRefreshed": "Catálogo actualizado: {count} proveedores", - "catalogRefreshFailed": "Error al actualizar el catálogo", - "piSaved": "Configuración de Pi guardada", - "savePiFailed": "No se pudo guardar la configuración de Pi", - "piRuntimeSaved": "Entorno de Pi guardado", - "savePiRuntimeFailed": "No se pudo guardar el entorno de Pi", - "piBinaryInstalled": "pi instalado", - "piBinaryInstallFailed": "Error al instalar pi", - "piBinaryUninstalled": "pi desinstalado", - "piBinaryUninstallFailed": "Error al desinstalar pi", - "savePiTrustFailed": "Error al guardar la confianza del espacio de trabajo" - }, - "version": { - "statusLabel": "Estado de versión", - "notInstalled": "No instalado", - "remoteLocal": "Remota: {remoteVersion} · Local: {localVersion}", - "localOnly": "Local: {localVersion}", - "localInstalled": "{versionText}. Instalado.", - "platformUnsupported": "{versionText}. La plataforma actual no soporta este agente.", - "uvxNotReady": "{versionText}. El runtime de uv no está instalado: instálalo desde la comprobación de uv de abajo para usar este agente.", - "clickInstall": "{versionText}. Haz clic en Instalar a la derecha.", - "localUnrecognized": "{versionText}. La versión local no es comparable; intenta actualizar para sobrescribir la instalación.", - "upgradeAvailable": "{versionText}. Hay actualización disponible.", - "remoteUnavailable": "{versionText}. La versión remota no está disponible por ahora.", - "latest": "{versionText}. Ya está en la última versión." - }, - "adapter": { - "label": "Adaptador ACP", - "badge": "Adaptador ACP", - "badgeHint": "Para este agente Codeg instala un paquete adaptador ACP, no la CLI del proveedor. Son independientes y comparten la misma configuración.", - "learnMore": "Más información", - "missingWithNative": "Se encontró tu {nativeLabel} en {nativePath}. Codeg habla con los agentes mediante ACP y esa CLI no habla ACP, así que Codeg necesita un paquete adaptador aparte, {adapterPackage}, mantenido por el proyecto Agent Client Protocol (originalmente Zed). Incluye su propio runtime, nunca modifica ni reemplaza tu comando {nativeCmd} y lee el mismo {configDir}: tu sesión y tus ajustes actuales se conservan. Instálalo abajo.", - "missing": "Codeg habla con los agentes mediante ACP y la {nativeLabel} no habla ACP, así que Codeg necesita un paquete adaptador aparte, {adapterPackage}, mantenido por el proyecto Agent Client Protocol (originalmente Zed). Incluye su propio runtime, por lo que no hace falta instalar antes la CLI {nativeCmd}; si ya la tienes, ambas conviven y comparten la sesión y los ajustes de {configDir}. Instálalo abajo.", - "readyWithNative": "El adaptador {adapterCmd} está instalado: es lo que Codeg ejecuta, no tu propio {nativeCmd} en {nativePath}. Son paquetes distintos que conviven y ambos leen {configDir}, así que la sesión y los ajustes son compartidos.", - "ready": "El adaptador {adapterCmd} está instalado: es lo que Codeg ejecuta. Incluye su propio runtime, así que la {nativeLabel} no es necesaria; si la instalas después, ambas conviven y comparten {configDir}." - }, - "cline": { - "configDescription": "Configure el proveedor de API y las credenciales de Cline. La configuración se guarda en ~/.cline/data/." - }, - "opencodePlugins": { - "title": "Plugins de OpenCode", - "declared": "Plugins declarados", - "noPlugins": "No hay plugins declarados en opencode.json", - "status": { - "installed": "Instalado", - "missing": "No instalado" - }, - "installAll": "Instalar todos los faltantes", - "pinVersions": "Fijar versiones @latest", - "install": "Instalar", - "uninstall": "Desinstalar", - "refresh": "Actualizar", - "success": "Todos los plugins se instalaron correctamente", - "failed": "La operación del plugin falló" - }, - "pi": { - "configManagement": "Configuración de Pi", - "configDescription": "Pi se autentica con la clave API de tu proveedor de modelos. La clave se escribe en ~/.pi/agent/auth.json y la selección de modelo en settings.json.", - "providerLabel": "Proveedor", - "modelLabel": "Modelo", - "thinkingLabel": "Razonamiento", - "thinking": { - "off": "Desactivado", - "low": "Bajo", - "medium": "Medio", - "high": "Alto", - "minimal": "Mínimo", - "xhigh": "Muy alto" - }, - "apiKeyLabel": "Clave API", - "apiKeyHint": "Se guarda en ~/.pi/agent/auth.json para el proveedor seleccionado.", - "apiKeySetPlaceholder": "•••••• (guardada — déjalo vacío para mantener)", - "saveConfig": "Guardar configuración de Pi", - "providerModelRequired": "El proveedor y el modelo son obligatorios", - "runtimeTitle": "Entorno de ejecución", - "runtimeDescription": "Elige qué binario de pi se ejecuta. Usa el predeterminado o apunta a tu propia compilación de pi.", - "modeDefault": "pi predeterminado", - "modeDefaultHint": "Usa el adaptador pi-acp integrado con el pi de tu PATH. Instala pi con: npm install -g @earendil-works/pi-coding-agent", - "modeCustom": "pi personalizado", - "modeCustomHint": "Ejecuta tu propia compilación, instalación o envoltorio de pi.", - "commandLabel": "Comando o ruta de pi", - "commandHint": "Una ruta absoluta, un nombre de comando en el PATH o un script envoltorio (p. ej. ./pi-test.sh de un monorepo).", - "commandNotFound": "Comando no encontrado", - "validate": "Validar", - "advanced": "Avanzado", - "configDirLabel": "Directorio de configuración (PI_CODING_AGENT_DIR)", - "sessionDirLabel": "Directorio de sesiones (PI_CODING_AGENT_SESSION_DIR)", - "flagsHint": "pi-acp no reenvía flags personalizados de pi (--approve, -e, …); envuelve pi en un script y apunta el comando a él.", - "customIncomplete": "Introduce un comando de pi para guardar", - "saveRuntime": "Guardar entorno", - "providerPlaceholder": "Seleccionar un proveedor", - "customProvider": "Proveedor personalizado…", - "providerIdLabel": "ID del proveedor", - "apiProtocolLabel": "Protocolo de API", - "baseUrlLabel": "Endpoint de API (Base URL)", - "customProviderHint": "Define un proveedor en ~/.pi/agent/models.json hacia tu endpoint. La mayoría de los servidores autoalojados o proxy usan openai-completions.", - "baseUrlRequired": "El endpoint de API (Base URL) es obligatorio", - "binaryTitle": "binario pi (pi-coding-agent)", - "binaryDescription": "pi-acp ejecuta este binario pi. Instálalo aquí o apunta pi-acp a tu propia compilación más abajo.", - "binaryInstalled": "Instalado", - "binaryMissing": "No instalado", - "binaryChecking": "Comprobando…", - "installBinary": "Instalar pi", - "installing": "Instalando…", - "recheck": "Volver a comprobar", - "configDirSkillsNote": "Con un directorio de configuración personalizado, las habilidades, los expertos y las herramientas de oficina gestionados en Ajustes no se aplican a este pi; gestiona sus habilidades directamente en esa carpeta.", - "projectTrustTitle": "Confianza del proyecto", - "projectTrustDescription": "Carpetas desde las que permitiste que pi cargue archivos del proyecto. Una carpeta de confianza permite que las .pi/extensions de ese repositorio ejecuten código al iniciar pi, se aplica a todas las carpetas que contiene y también se usa cuando ejecutas pi en una terminal.", - "projectTrustLoading": "Cargando…", - "projectTrustEmpty": "Aún no hay carpetas decididas.", - "projectTrustTrusted": "De confianza", - "projectTrustDenied": "Sin confianza", - "projectTrustRevoke": "Revocar", - "reasoningTitle": "Razonamiento", - "reasoningEnableLabel": "Activar", - "reasoningDescription": "pi solo envía un esfuerzo de razonamiento para un modelo que lo declara: en un modelo sin declarar, todos los niveles se reducen a Off, así que el selector del compositor vuelve atrás en cuanto lo tocas. Se escribe en la entrada de este modelo en models.json.", - "levelsLabel": "Niveles disponibles", - "levelsHint": "Serán las filas del selector de razonamiento del compositor. Elige los que acepte tu endpoint; pi rechaza cualquier nivel que no esté aquí.", - "levelsEmptyError": "Elige al menos un nivel: sin ninguno, pi vuelve a Off.", - "wireValuesTitle": "Avanzado: valores enviados al proveedor", - "wireValuesHint": "Déjalo vacío para enviar el nombre del nivel tal cual. Defínelo cuando tu endpoint espere otra cosa: los backends al estilo de Google quieren LOW / HIGH.", - "defaultLevelUnlisted": "Este nivel no está en la lista de arriba: pi lo reduciría." - }, - "addCustomAgent": "Añadir agente personalizado", - "addCustomAgentHint": "Registra cualquier agente compatible con ACP. Elige uno del registro público de ACP o pega su información de registro.", - "customAgentFromRegistry": "Registro ACP", - "customAgentManual": "Manual", - "customAgentSearchPlaceholder": "Buscar agentes…", - "customAgentLoadingCatalog": "Cargando el registro ACP…", - "customAgentRetry": "Reintentar", - "customAgentNoResults": "No hay agentes coincidentes", - "customAgentAdd": "Añadir", - "customAgentAlreadyAdded": "Añadido", - "customAgentUnsupportedPlatform": "No hay compilación disponible para esta plataforma", - "customAgentAdded": "{name} añadido", - "customAgentIdLabel": "ID del registro", - "customAgentNameLabel": "Nombre visible", - "customAgentVersionLabel": "Versión", - "customAgentSpecLabel": "Distribución (JSON)", - "customAgentSpecHint": "Misma forma que el objeto distribution del registro ACP: canales npx, uvx y binary, o pega una entrada completa del registro. En npx/uvx, cmd es el ejecutable que instala el paquete; se deriva del nombre del paquete si se omite, así que indícalo cuando difieran. binary se organiza por clave de plataforma (esta máquina: {platform}); su cmd es la ruta de arranque dentro del archivo y sha256 verifica opcionalmente la descarga.", - "customAgentTemplateLabel": "Plantillas", - "customAgentKindLabel": "Iniciar mediante", - "customAgentInvalidJson": "JSON no válido", - "customAgentNoDistribution": "No se encontró distribución npx, uvx ni binary", - "customAgentCancel": "Cancelar", - "customAgentSave": "Añadir agente", - "customAgentSaveChanges": "Guardar cambios", - "customAgentEdit": "Editar agente", - "customAgentEditHint": "Actualiza el nombre, el icono, la distribución y las declaraciones de skills. El ID del agente no puede cambiarse.", - "customAgentEditNotFound": "No se encontró el agente personalizado {id}", - "customAgentSaved": "{name} guardado", - "customAgentVersionProbeLabel": "Comando de consulta de versión (opcional)", - "customAgentVersionProbeHint": "Comando que imprime la versión instalada localmente. Si se deja vacío, codeg ejecuta el comando del agente con --version.", - "customAgentRemove": "Eliminar agente", - "customAgentRemoveHint": "Elimina la definición del agente. Las conversaciones existentes conservan su historial; el agente simplemente ya no se puede iniciar.", - "customAgentIconLabel": "Icono (opcional)", - "customAgentIconUpload": "Subir", - "customAgentIconReplace": "Reemplazar", - "customAgentIconClear": "Quitar icono", - "customAgentIconHint": "Se guarda junto al agente, así funciona sin conexión. Si no indicas ninguno, se usa una inicial de color.", - "customAgentSkillsLabel": "Skills (.agents/skills compartido)", - "customAgentSkillsHint": "Declara que este agente lee el almacén compartido .agents/skills (directorios global y de proyecto) y lo añade a todas las matrices de habilidades. Las habilidades vinculadas allí son visibles para todos los agentes que leen ese almacén compartido.", - "customAgentSkillsDirLabel": "Directorio de skills dedicado", - "customAgentSkillsDirHint": "Ruta absoluta del directorio desde el que este agente carga skills: su propio almacén, además del compartido o en su lugar. ~ se expande al directorio personal; las skills vinculadas se colocan aquí primero.", - "customAgentMcpLabel": "Compatibilidad con MCP", - "customAgentMcpHint": "Envía el complemento MCP integrado de codeg a este agente al iniciar la sesión: es el canal de la delegación, los comentarios en vivo y las herramientas de tareas. Desactívalo para un agente que rechaza servidores MCP y no llega a conectarse; el cambio se aplica en la próxima conexión.", - "customAgentIconNotAnImage": "Selecciona un archivo de imagen.", - "customAgentIconTooLarge": "El icono debe pesar menos de {limit} KB.", - "customAgentIconReadFailed": "No se pudo leer esa imagen.", - "customAgentRemoveConfirm": "¿Eliminar {name}? Las conversaciones existentes se conservan, pero el agente ya no podrá iniciarse.", - "customAgentRemoveWithData": "Eliminar también su historial de conversaciones registrado", - "customAgentRemoved": "{name} eliminado", - "customAgentBadge": "Personalizado", - "customAgentNotLaunchable": "Este agente no puede iniciarse aquí: {reason}" - }, - "SettingsPages": { - "agentsLoading": "Cargando configuración de agentes...", - "skillPacksLoading": "Cargando paquetes de habilidades…" - }, - "GeneralSettings": { - "loading": "Cargando...", - "sectionTitle": "General", - "sectionDescription": "Preferencias centralizadas para el terminal predeterminado, la aceleración de renderizado y la delegación entre agentes.", - "terminalTitle": "Terminal predeterminada", - "terminalDescription": "Elige el shell que se usa al abrir nuevas pestañas de terminal desde la barra de terminal o el árbol de archivos. Los agentes también lo usan cuando piden a codeg que ejecute una línea de comandos completa.", - "terminalSystemDefault": "Predeterminado del sistema", - "terminalPowerShell7": "PowerShell 7 (pwsh)", - "terminalWindowsPowerShell": "Windows PowerShell", - "terminalCmd": "Símbolo del sistema (cmd)", - "terminalSaveFailed": "Error al guardar la configuración del terminal: {message}", - "terminalShellCustom": "Ruta personalizada", - "terminalShellCustomPath": "Ruta del shell", - "terminalShellCustomPlaceholder": "/usr/local/bin/fish", - "terminalShellCustomSave": "Guardar", - "terminalShellCustomHint": "Indica una ruta absoluta o un nombre resoluble en PATH.", - "terminalShellNotInstalled": "no instalado", - "terminalShellNotFoundWarning": "Esta ruta no existe en este host.", - "terminalCurrentShell": "En uso actualmente: {path}", - "renderingDescription": "Desactiva la aceleración por hardware si la aplicación muestra pantalla negra o fallos de renderizado (común en algunas GPU AMD o Intel integradas). Solo afecta a la versión de escritorio en Windows.", - "disableHardwareAcceleration": "Desactivar aceleración por hardware", - "renderingSaveFailed": "No se pudo guardar la configuración de renderizado: {message}", - "restartRequired": "Guardado. Reinicia la aplicación para aplicar el cambio.", - "restartNow": "Reiniciar ahora", - "restartFailed": "No se pudo reiniciar: {message}", - "loadFailed": "Error al cargar: {message}" - }, - "LoginPage": { - "documentTitle": "Iniciar sesión - codeg", - "brand": "Codeg", - "subtitle": "Introduce tu token de acceso para conectarte a la aplicación de escritorio", - "tokenPlaceholder": "Token de acceso", - "connect": "Conectar", - "connecting": "Conectando...", - "helpText": "Encuentra tu token en la aplicación de escritorio en Configuración → Servicio web", - "invalidToken": "Token no válido. Por favor, comprueba e inténtalo de nuevo.", - "connectionFailed": "Error de conexión (HTTP {status})", - "networkError": "No se puede conectar al servidor" - }, - "CommitPage": { - "title": "Confirmación", - "invalidFolderId": "ID de carpeta no válido", - "loadingRepo": "Cargando repositorio..." - }, - "MergePage": { - "title": "Resolver conflictos", - "invalidFolderId": "ID de carpeta no válido", - "loadingRepo": "Cargando repositorio...", - "localVersion": "Local (Nuestro)", - "result": "Resultado", - "remoteVersion": "Remoto (Suyo)", - "acceptLocal": "Aceptar local", - "acceptRemote": "Aceptar remoto", - "markResolved": "Marcar como resuelto", - "abortMerge": "Abortar", - "completeMerge": "Completar fusión", - "unresolvedConflicts": "Todavía hay marcadores de conflicto sin resolver en este archivo", - "fileResolved": "Archivo resuelto correctamente", - "allResolved": "Todos los conflictos resueltos", - "conflictFiles": "Archivos en conflicto", - "loadingFile": "Cargando archivo...", - "preparingMerge": "Preparando fusión...", - "selectFile": "Seleccionar un archivo para resolver", - "noConflicts": "No hay archivos en conflicto", - "skipFile": "Omitir", - "abortSuccess": "Operación abortada", - "applyAllNonConflicting": "Aplicar todos los cambios sin conflicto", - "applyLeftNonConflicting": "Aplicar local", - "applyRightNonConflicting": "Aplicar remoto" - }, - "ImportSessions": { - "title": "Importar sesiones locales", - "scanningTitle": "Escaneando sesiones locales de los agentes…", - "scanningHint": "Recorriendo el almacén local de sesiones de cada agente. Con historiales grandes puede tardar un momento. Las sesiones ya importadas se actualizan por el camino.", - "scanFailed": "Error al escanear", - "retry": "Reintentar", - "rescan": "Reescanear", - "empty": "No se encontraron sesiones locales", - "emptyHint": "No se encontraron almacenes de sesiones de agentes en este equipo.", - "noMatches": "Ninguna sesión coincide con los filtros actuales", - "searchPlaceholder": "Buscar título o ruta…", - "allAgents": "Todos los agentes", - "onlyImportable": "Solo importables", - "selectAll": "Seleccionar todo", - "clearSelection": "Limpiar", - "expandAll": "Expandir todo", - "collapseAll": "Contraer todo", - "summaryCounts": "{total} sesiones · {importable} importables · {folders} carpetas", - "noFolderSkipped": "{count} sin carpeta de proyecto omitidas", - "folderNew": "Nueva", - "folderCounts": "{importable}/{total} importables", - "toggleFolderAria": "Seleccionar todas las sesiones importables de {name}", - "toggleSessionAria": "Seleccionar la sesión {title}", - "statusImported": "Importada", - "statusDeleted": "Eliminada", - "untitled": "Sesión sin título", - "messageCount": "{count} mensajes", - "selectedCount": "{count} seleccionadas", - "importSelected": "Importar selección", - "importing": "Importando…", - "close": "Cerrar", - "doneTitle": "Importación finalizada", - "doneImported": "Importadas", - "doneUpdated": "Actualizadas", - "doneSkipped": "Omitidas", - "doneCreatedFolders": "Carpetas creadas", - "doneNotFound": "No encontradas", - "doneFailed": "Fallidas", - "continueImport": "Seguir importando", - "toasts": { - "importFailed": "Error al importar: {message}" - } - }, - "Folder": { - "workspaceStatus": { - "degradedTitle": "Actualizaciones en vivo no disponibles", - "degradedHint": "El observador no pudo iniciarse (por ejemplo, permiso denegado). Actualiza manualmente para ver los cambios.", - "retry": "Reintentar", - "retrying": "Reintentando..." - }, - "common": { - "all": "Todo", - "cancel": "Cancelar", - "close": "Cerrar", - "closeOthers": "Cerrar otros", - "closeAll": "Cerrar todo", - "confirm": "Confirmar", - "save": "Guardar", - "delete": "Eliminar", - "rename": "Renombrar", - "loading": "Cargando...", - "refresh": "Actualizar", - "refreshing": "Actualizando...", - "create": "Crear", - "createAndSwitch": "Crear y cambiar", - "openFile": "Abrir archivo", - "viewDiff": "Ver Diff", - "push": "Enviar..." - }, - "statusLabels": { - "in_progress": "En progreso", - "pending_review": "Revisión", - "completed": "Completado", - "cancelled": "Cancelado" - }, - "sidebar": { - "title": "Conversaciones", - "locateActiveConversation": "Ubicar conversación activa", - "expandAllGroups": "Expandir todos los grupos", - "collapseAllGroups": "Colapsar todos los grupos", - "newConversation": "Nueva conversación", - "newConversationShort": "Nueva", - "newChat": "Nueva conversación", - "search": "Buscar", - "noConversationsFound": "No se encontraron conversaciones.", - "importLocalSessions": "Importar sesiones locales", - "importing": "Importando...", - "error": "Error del sistema: {message}", - "completeAllSessions": "Completar todas las sesiones", - "completeAllReviewTitle": "¿Completar todas las sesiones en revisión?", - "completeAllReviewDescription": "Esto marcará como completadas todas las {count, plural, one {# sesión} other {# sesiones}} en Revisión.", - "completing": "Completando...", - "toasts": { - "importedSessions": "Se importaron {imported, plural, one {# sesión} other {# sesiones}}, se omitieron {skipped}", - "importedAndUpdated": "Se importaron {imported, plural, one {# sesión} other {# sesiones}}, se actualizaron {updated, plural, one {# título} other {# títulos}}, se omitieron {skipped}", - "updatedTitles": "Se actualizaron {updated, plural, one {# título} other {# títulos}}, se omitieron {skipped}", - "noNewSessionsFound": "No se encontraron sesiones nuevas (omitidas {skipped})", - "importFailed": "Error al importar: {message}", - "reviewCompleted": "Se marcaron como completadas {count, plural, one {# sesión en revisión} other {# sesiones en revisión}}", - "completeReviewFailed": "Error al completar sesiones en revisión: {message}", - "folderOpened": "Carpeta {name} abierta", - "folderRemoved": "Carpeta {name} eliminada", - "openFolderFailed": "Error al abrir carpeta", - "removeFolderFailed": "Error al eliminar carpeta: {message}", - "reorderFoldersFailed": "Error al reordenar carpetas: {message}", - "changeFolderColorFailed": "Error al cambiar el color: {message}", - "setFolderAliasFailed": "Error al establecer el alias: {message}", - "changeFolderDefaultAgentFailed": "Error al establecer agente predeterminado: {message}" - }, - "statsLabel": "{folders} carpetas · {convos} conversaciones", - "reorderHandle": "Arrastrar para reordenar", - "openFolder": "Abrir carpeta", - "searchPlaceholder": "Buscar conversaciones...", - "viewOptions": "Opciones de visualización", - "showCompleted": "Mostrar conversaciones completadas", - "showWorktrees": "Mostrar carpetas de worktree", - "showRecent": "Mostrar grupo Recientes", - "moreOptions": "Más opciones", - "sortBy": "Ordenar por", - "sortByCreatedAt": "Fecha de creación", - "sortByUpdatedAt": "Fecha de actualización", - "sectionOrder": "Orden de secciones", - "sectionOrderMoveUp": "Subir", - "sectionOrderMoveDown": "Bajar", - "sectionOrderItemLabel": "{name} — posición {position} de {total}", - "statusRunningBadge": "Ejecutando", - "runningCountBadge": "{count, plural, one {# sesión en ejecución} other {# sesiones en ejecución}}", - "statusCancelledBadge": "Cancelado", - "worktreeRemovedBadge": "Worktree de origen eliminado", - "conversationCountUnit": "{count, plural, one {# conversación} other {# conversaciones}}", - "emptyFolderHint": "Sin conversaciones", - "noMatchingConversations": "No hay conversaciones coincidentes", - "noUnfinishedConversations": "No hay conversaciones pendientes. Activa \"Mostrar completadas\" desde el menú superior derecho.", - "removeFolderConfirmTitle": "¿Eliminar carpeta del espacio de trabajo?", - "removeFolderConfirmDescription": "¿Eliminar \"{name}\" del espacio de trabajo? Sus pestañas y terminales se cerrarán.", - "folderHeaderMenu": { - "manageConversations": "Gestionar conversaciones…", - "manageLinks": "Carpetas vinculadas", - "changeColor": "Cambiar color", - "useThemeColor": "Usar tema de la app", - "setDefaultAgent": "Establecer agente predeterminado", - "defaultAgentNone": "Sin valor (usar predeterminado global)", - "agentUnavailableSuffix": "(no disponible)", - "loadingAgents": "Cargando agentes…", - "setAlias": "Establecer alias…", - "setAliasTitle": "Establecer alias de la carpeta", - "setAliasPlaceholder": "Introduce un alias (déjalo vacío para borrarlo)", - "setAliasSave": "Guardar", - "setAliasCancel": "Cancelar", - "removeFromWorkspace": "Quitar del espacio de trabajo" - }, - "manageConversations": { - "title": "Gestionar conversaciones", - "searchPlaceholder": "Buscar por título…", - "agentFilterAll": "Todos los agentes", - "statusFilterAll": "Todos los estados", - "folderFilterAll": "Todas las carpetas", - "branchFilterAll": "Todas las ramas", - "branchNone": "Sin rama", - "branchSearchPlaceholder": "Buscar ramas…", - "noMatchingBranches": "No hay ramas coincidentes", - "selectAllVisible": "Seleccionar todo", - "deselectAll": "Deseleccionar todo", - "selectedCount": "{count} seleccionada(s)", - "matchedCount": "{count} coincidencia(s)", - "untitledConversation": "Conversación sin título", - "setStatus": "Cambiar estado…", - "deleteSelected": "Eliminar", - "noConversations": "No hay conversaciones en esta carpeta.", - "noConversationsWorkspace": "No hay conversaciones en el espacio de trabajo.", - "noMatchingConversations": "Ninguna conversación coincide con los filtros.", - "confirmDeleteTitle": "¿Eliminar {count} conversación(es)?", - "confirmDeleteDescription": "Esta acción no se puede deshacer.", - "toastDeleted": "Se eliminaron {count} conversación(es)", - "toastStatusUpdated": "Estado actualizado para {count} conversación(es)", - "toastOpFailed": "Error en la operación: {message}" - }, - "sectionPinned": "Fijadas", - "sectionFolders": "Carpetas", - "sectionChats": "Chat", - "sectionRecent": "Recientes", - "noChats": "Sin chats", - "noRecent": "Sin conversaciones recientes", - "showMoreRecent": "Mostrar más ({count})", - "noFolders": "No hay carpetas abiertas", - "newChatAction": "Nuevo chat", - "automations": "Automatizaciones", - "tasks": "Tareas pendientes", - "loadingSubsessions": "Cargando subconversaciones…" - }, - "conversation": { - "reloadFailed": "No se pudo recargar la conversación: {message}", - "reloaded": "Conversación recargada", - "reload": "Recargar", - "activeConversationIndicator": "Conversación activa", - "newConversation": "Nueva conversación", - "closeConversation": "Cerrar conversación", - "copyText": "Copiar texto", - "copyTextSuccess": "Copiado", - "copyTextFailed": "Error al copiar", - "forkSession": "Bifurcar sesión", - "forkSessionSuccess": "Sesión bifurcada exitosamente", - "forkSessionFailed": "Error al bifurcar la sesión: {error}", - "exportConversation": "Exportar conversación", - "exportImage": "Imagen", - "exportMarkdown": "Markdown", - "exportHtml": "HTML", - "exportSuccess": "Conversación exportada", - "exportFailed": "Error al exportar", - "exportImageTooLong": "La conversación es demasiado larga para exportar como imagen", - "exportLabels": { - "untitledConversation": "Conversación sin título", - "agent": "Agente", - "model": "Modelo", - "status": "Estado", - "started": "Inicio", - "updated": "Actualizado", - "tokens": "Estadísticas de tokens", - "duration": "Duración", - "inputTokens": "Entrada", - "outputTokens": "Salida", - "cacheRead": "Caché leída", - "cacheWrite": "Caché escrita", - "user": "Usuario", - "assistant": "Asistente", - "system": "Sistema", - "toolResult": "Resultado", - "toolError": "Error" - }, - "moreActions": "Más acciones" - }, - "sessionDetails": { - "menuLabel": "Detalles de la sesión", - "noActiveSession": "No hay ninguna sesión activa", - "title": "Detalles de la sesión", - "subtitle": "Metadatos de la sesión y uso de tokens", - "fieldTitle": "Título", - "untitled": "Conversación sin título", - "sessionId": "ID de sesión", - "externalId": "ID de extensión", - "agent": "Agente", - "model": "Modelo", - "status": "Estado", - "gitBranch": "Rama de Git", - "parentId": "Sesión principal", - "tokensHeading": "Uso de tokens", - "totalTokens": "Total", - "inputTokens": "Entrada", - "outputTokens": "Salida", - "cacheWrite": "Caché escrita", - "cacheRead": "Caché leída", - "contextWindow": "Ventana de contexto", - "duration": "Duración", - "loadingStats": "Cargando uso de tokens…", - "loadFailed": "Error al cargar el uso de tokens", - "noStats": "Sin uso registrado", - "timestampsHeading": "Marcas de tiempo", - "createdAt": "Creado", - "updatedAt": "Actualizado", - "none": "—", - "copyField": "Copiar {field}", - "copiedField": "{field} copiado" - }, - "conversationCard": { - "untitledConversation": "Conversación sin título", - "newConversation": "Nueva conversación", - "rename": "Renombrar", - "status": "Estado", - "delete": "Eliminar", - "importLocalSessions": "Importar sesiones locales", - "importing": "Importando...", - "renameConversation": "Renombrar conversación", - "deleteConversationTitle": "¿Eliminar conversación?", - "deleteConversationDescription": "Esto eliminará \"{title}\". Esta acción no se puede deshacer.", - "cancel": "Cancelar", - "save": "Guardar", - "pin": "Fijar", - "unpin": "Dejar de fijar", - "markCompleted": "Marcar como completada", - "reopen": "Reabrir", - "expandSubsessions": "Expandir subconversaciones", - "collapseSubsessions": "Contraer subconversaciones" - }, - "search": { - "dialogTitle": "Buscar", - "dialogTitleWithFolder": "Buscar — {name}", - "tabConversations": "Conversaciones", - "tabFiles": "Archivos", - "placeholder": "Buscar conversaciones...", - "filePlaceholder": "Buscar archivos o directorios...", - "allAgents": "Todo", - "searching": "Buscando...", - "typeToSearch": "Escribe para buscar conversaciones", - "typeToSearchFiles": "Escribe para buscar archivos o directorios", - "noResults": "No se encontraron resultados.", - "untitledConversation": "Conversación sin título" - }, - "folderTitleBar": { - "showSidebar": "Mostrar barra lateral", - "hideSidebar": "Ocultar barra lateral", - "toggleTerminal": "Alternar terminal", - "toggleAuxPanel": "Alternar panel auxiliar", - "search": "Buscar", - "openSettings": "Abrir configuración", - "backToConversations": "Volver a conversaciones", - "withShortcut": "{label} (atajo: {shortcut})" - }, - "statusBar": { - "connection": { - "connected": "Conectado", - "connecting": "Conectando...", - "prompting": "Respondiendo...", - "error": "Error de conexión", - "disconnected": "Desconectado", - "tooltip": "{agent}: {status}", - "tooltipError": "{agent}: {error}", - "title": "Conexión del agente", - "triggerAria": "Conexión del agente: {status}", - "workingDir": "Directorio de trabajo", - "sessionId": "ID de sesión", - "viewerNote": "Conectado a una sesión que pertenece a otro cliente: reconectar solo vuelve a adjuntar esta vista.", - "reconnectInterrupts": "Reconectar reinicia el agente e interrumpe el trabajo en curso.", - "reconnect": "Reconectar", - "reconnecting": "Reconectando...", - "reconnectUnavailable": "Aún no hay ninguna sesión a la que reconectar." - }, - "tasks": { - "title": "Tareas" - }, - "alerts": { - "title": "Alertas", - "empty": "Sin alertas", - "details": "Detalles" - }, - "stats": { - "conversations": "{count} conversaciones", - "openUsage": "Ver estadísticas de sesiones y uso de tokens" - }, - "tokens": { - "contextWindowUsageAria": "Uso de la ventana de contexto", - "contextWindow": "Ventana de contexto", - "usedMax": "Usado / Máx", - "tokenUsage": "Uso de tokens", - "input": "Entrada", - "output": "Salida", - "cacheRead": "Lectura de caché", - "cacheWrite": "Escritura de caché", - "total": "Total de tokens" - } - }, - "auxPanel": { - "tabs": { - "files": "Archivos", - "changes": "Cambios", - "commits": "Confirmaciones" - }, - "noFolderTitle": "No hay carpeta abierta", - "noFolderHint": "Abre una carpeta para ver su contenido aquí" - }, - "windowControls": { - "minimizeWindow": "Minimizar ventana", - "minimize": "Minimizar", - "maximizeWindow": "Maximizar ventana", - "maximize": "Maximizar", - "restoreWindow": "Restaurar ventana", - "restore": "Restaurar", - "closeWindow": "Cerrar ventana", - "close": "Cerrar" - }, - "tabs": { - "closeConversationTab": "Cerrar pestaña de conversación", - "close": "Cerrar", - "closeOthers": "Cerrar otros", - "splitRight": "Dividir a la derecha", - "splitDown": "Dividir abajo", - "splitAndMoveRight": "Dividir y mover a la derecha", - "splitAndMoveDown": "Dividir y mover abajo", - "moveToOppositeGroup": "Mover al grupo opuesto", - "moveToGroup": "Mover al grupo", - "groupLabel": "Grupo {index}", - "changeSplitterOrientation": "Cambiar orientación del divisor", - "unsplit": "Deshacer división", - "unsplitAll": "Deshacer todas las divisiones", - "closeAll": "Cerrar todo", - "tileDisplay": "Vista en mosaico", - "untileDisplay": "Salir de mosaico" - }, - "fileWorkspace": { - "files": "Archivos", - "closeFileTab": "Cerrar pestaña de archivo", - "close": "Cerrar", - "closeOthers": "Cerrar otros", - "closeAll": "Cerrar todo", - "preview": "Vista previa", - "editSource": "Editar fuente", - "maximize": "Maximizar", - "restore": "Restaurar", - "emptyDirectory": "Carpeta vacía" - }, - "terminal": { - "rename": "Renombrar", - "close": "Cerrar", - "closeOthers": "Cerrar otros", - "closeAll": "Cerrar todo", - "hideTerminal": "Ocultar terminal ({shortcut})", - "openFolderFirst": "Abre primero una carpeta" - }, - "workspaceDialog": { - "title": "Abrir carpeta", - "manageTitle": "Carpetas vinculadas", - "addTargetsTitle": "Añadir carpetas para vincular", - "pickRootDescription": "Elige la carpeta principal de este espacio de trabajo.", - "linksDescription": "Vincula otras carpetas como subdirectorios para que los agentes trabajen en todas ellas desde un solo espacio de trabajo.", - "addTargetsDescription": "Selecciona una o más carpetas. Cada una será un subdirectorio del espacio de trabajo.", - "useSystemPicker": "Selector del sistema", - "next": "Siguiente", - "back": "Atrás", - "done": "Listo", - "change": "Cambiar", - "addFolders": "Añadir carpetas", - "addSelected": "Añadir", - "addSelectedCount": "Añadir {count}", - "createCount": "Vincular {count} carpeta(s)", - "discardPending": "Descartar", - "noLinks": "Todavía no hay carpetas vinculadas.", - "gitExclude": "Mantener los enlaces fuera del estado de git", - "rename": "Renombrar", - "unlink": "Quitar enlace", - "repair": "Recrear enlace", - "saveName": "Guardar", - "cancelRename": "Cancelar", - "removePending": "Quitar", - "willAppearAs": "Aparece como {name} en el espacio de trabajo", - "renamedForDuplicate": "Renombrada: {base} ya lo usa otro enlace", - "renamedForExistingEntry": "Renombrada: {base} ya existe en esta carpeta", - "partiallyCreated": "Solo se pudieron vincular {count} carpeta(s)", - "openFailed": "No se pudo abrir la carpeta", - "previewFailed": "No se pudieron comprobar las carpetas seleccionadas", - "createFailed": "No se pudieron vincular las carpetas", - "renameFailed": "No se pudo renombrar el enlace", - "removeFailed": "No se pudo quitar el enlace", - "repairFailed": "No se pudo recrear el enlace", - "status": { - "ok": "Vinculada", - "missing": "El enlace ya no está en esta carpeta", - "conflicted": "Otra entrada usa ahora este nombre", - "broken": "La carpeta vinculada ya no existe" - }, - "nameIssue": { - "empty": "Escribe un nombre", - "illegalChars": "No puede contener / \\ : * ? \" < > |", - "tooLong": "El nombre es demasiado largo", - "reserved": "Windows reserva este nombre", - "duplicate": "Este nombre ya está en uso" - }, - "rejection": { - "not_found": "No se encontró esta carpeta", - "not_a_directory": "Esta ruta no es una carpeta", - "same_as_root": "Es la propia carpeta del espacio de trabajo", - "ancestor_of_root": "Esta carpeta contiene el espacio de trabajo", - "inside_root": "Ya está dentro del espacio de trabajo", - "already_linked": "Ya está vinculada", - "name_unavailable": "No queda ningún nombre libre para esta carpeta", - "alreadyLinkedAs": "Ya vinculada como {name}" - } - }, - "folderNameDropdown": { - "fallbackFolderName": "Carpeta", - "openFolder": "Abrir carpeta", - "cloneRepository": "Clonar repositorio", - "projectBoot": "Inicializador de proyecto", - "opened": "Abierto", - "recentOpen": "Abiertos recientemente" - }, - "fileWorkspacePanel": { - "addSelectionToChat": "Añadir selección al chat", - "addToChat": "Añadir al chat", - "addSelectionToChatDone": "Se añadió {label} a la conversación", - "addFileToChat": "Añadir archivo al chat", - "toggleWordWrap": "Alternar ajuste de línea", - "addFileToChatDone": "Se añadió {label} a la conversación", - "viewDiff": "Ver Diff", - "openFile": "Abrir archivo", - "fileCount": "{count, plural, one {# archivo} other {# archivos}}", - "openFileOrDiff": "Abre un archivo o diff desde el panel derecho", - "disk": "Disco", - "head": "HEAD (referencia)", - "unsaved": "Sin guardar", - "workingTree": "Árbol de trabajo", - "loading": "Cargando...", - "compareWithBranch": "{path} · comparar con {branch}", - "hunkCount": "{count, plural, one {# bloque} other {# bloques}}", - "prev": "Anterior", - "next": "Siguiente", - "jumpToLine": "Ir a la línea {line}", - "noParsedDiffSections": "No hay secciones de diff analizadas", - "loadingEditor": "Cargando editor...", - "imageZoomIn": "Ampliar", - "imageZoomOut": "Reducir", - "imageZoomReset": "Restablecer zoom", - "htmlPreviewTitle": "Vista previa HTML", - "htmlPreviewTrust": "Habilitar scripts", - "htmlPreviewTrustHint": "Ejecuta los scripts de este archivo y permite el acceso a la red. Actívalo solo para archivos de confianza.", - "officePreviewTitle": "Vista previa de documento de Office", - "officeFullRender": "Renderizado completo", - "officeFullRenderHint": "Renderiza animaciones Morph, 3D y fórmulas (ejecuta los scripts de la diapositiva)", - "officeNotInstalled": "OfficeCLI no está instalado", - "officeNotInstalledHint": "Instala OfficeCLI en Ajustes → Herramientas de Office para previsualizar archivos de Word, Excel y PowerPoint.", - "officeOpenSettings": "Abrir ajustes", - "officeWatchFailed": "No se pudo iniciar la vista previa en vivo", - "officeWatchRetry": "Reintentar", - "officeServerInstallHint": "OfficeCLI debe instalarse en el host del servidor. Ejecuta este comando allí y vuelve a intentarlo:", - "officeRemoteDesktopUnsupported": "La vista previa en vivo no está disponible en una ventana de escritorio remoto. Abre este espacio de trabajo en la interfaz web del servidor para previsualizar archivos de Office." - }, - "branchDropdown": { - "toasts": { - "commitCodeCompleted": "Commit de código completado", - "pushCodeCompleted": "Push de código completado", - "committedFiles": "{count, plural, one {# archivo confirmado} other {# archivos confirmados}}", - "taskCompleted": "{label} completado", - "taskFailed": "{label} falló", - "mergeNoNewCommits": "{branchName} no tiene commits nuevos", - "mergedCommits": "{count, plural, one {# commit fusionado} other {# commits fusionados}}", - "allFilesUpToDate": "Todos los archivos están actualizados", - "updatedFiles": "{count, plural, one {# archivo actualizado} other {# archivos actualizados}}", - "openCommitWindowFailed": "No se pudo abrir la ventana de commit", - "openPushWindowFailed": "Error al abrir la ventana de envío", - "upstreamSet": "La rama upstream se ha configurado", - "upstreamSetAndPushed": "Rama upstream configurada y se enviaron {count, plural, one {# commit} other {# commits}}", - "noCommitsToPush": "No hay commits para enviar", - "pushedCommits": "Se enviaron {count, plural, one {# commit} other {# commits}}", - "switchedToFolder": "Cambiado a {name}", - "switchFailed": "No se pudo cambiar de rama", - "openStashWindowFailed": "No se pudo abrir la ventana de stash" - }, - "tasks": { - "newBranch": "Crear rama {name}", - "newWorktree": "Crear worktree {name}", - "checkoutTo": "Cambiar a {branchName}", - "mergeBranch": "Fusionar {branchName}", - "rebaseTo": "Rebase a {branchName}", - "deleteRemoteBranch": "Eliminar rama remota {branchName}", - "initGitRepo": "Inicializar repositorio Git", - "pullCode": "Hacer pull del código", - "fetchInfo": "Obtener información", - "pushCode": "Enviar código", - "stashChanges": "Guardar cambios en stash", - "stashPop": "Aplicar stash", - "deleteBranch": "Eliminar rama {branchName}", - "removeWorktree": "Eliminar el worktree de {branchName}", - "removeWorktreeAndBranch": "Eliminar el worktree y la rama {branchName}", - "updateBranch": "Actualizar la rama {branchName}" - }, - "confirm": { - "mergeTitle": "Fusionar rama", - "rebaseTitle": "Rebase de rama", - "mergeDescription": "¿Fusionar {branchName} en la rama actual {currentBranch}?", - "rebaseDescription": "¿Hacer rebase de la rama actual {currentBranch} sobre {branchName}?", - "deleteRemoteTitle": "Eliminar rama remota", - "deleteRemoteDescription": "¿Eliminar la rama remota {branchName}? Esto la eliminará del repositorio remoto y no se puede deshacer.", - "deleteTitle": "Eliminar rama", - "deleteDescription": "¿Eliminar la rama {branchName}? Esta acción no se puede deshacer.", - "forceDeleteTitle": "Forzar eliminación de rama", - "forceDeleteDescription": "La rama {branchName} no está completamente fusionada. ¿Estás seguro de que quieres forzar su eliminación? Esta acción no se puede deshacer.", - "deleteWorktreeTitle": "Eliminar worktree", - "deleteWorktreeDescription": "¿Eliminar el directorio del worktree que tiene {branchName} activa? La rama y sus commits se conservan.", - "forceDeleteWorktreeTitle": "Forzar la eliminación del worktree", - "forceDeleteWorktreeDescription": "El worktree de {branchName} tiene archivos sin confirmar o sin seguimiento. ¿Eliminarlo de todos modos? Esos cambios no se podrán recuperar.", - "deleteWorktreeAndBranchTitle": "Eliminar worktree y rama", - "deleteWorktreeAndBranchDescription": "¿Eliminar el worktree de {branchName}, la rama y su carpeta del espacio de trabajo? Sus sesiones pasan a la carpeta del repositorio. Esta acción no se puede deshacer.", - "forceDeleteWorktreeAndBranchTitle": "Forzar la eliminación del worktree y la rama", - "forceDeleteWorktreeAndBranchDescription": "El worktree de {branchName} tiene archivos sin confirmar, o la rama no está totalmente fusionada. ¿Eliminar ambos de todos modos? Esta acción no se puede deshacer." - }, - "current": "Actual", - "switchToBranch": "Cambiar a esta rama", - "mergeBranchIntoCurrent": "Fusionar {branchName} en {currentBranch}", - "rebaseCurrentToBranch": "Rebase de {currentBranch} sobre {branchName}", - "noBranch": "Sin rama", - "detachedHead": "HEAD desacoplado en {sha}", - "initGitRepo": "Inicializar repositorio Git", - "pullCode": "Hacer pull del código", - "fetchRemoteBranches": "Obtener ramas remotas", - "openCommitWindow": "Commit de código...", - "pushCode": "Enviar...", - "pushBranch": "Enviar", - "newBranch": "Nueva rama...", - "newWorktree": "Nuevo worktree...", - "stashChanges": "Guardar cambios...", - "stashPop": "Aplicar stash...", - "manageRemotes": "Gestionar remotos...", - "localBranches": "Ramas locales ({count, plural, one {#} other {#}})", - "noLocalBranches": "Sin ramas locales", - "remoteBranches": "Ramas remotas ({count, plural, one {#} other {#}})", - "noRemoteBranches": "Sin ramas remotas", - "dialogs": { - "newBranchTitle": "Nueva rama", - "newBranchDescription": "Crear una nueva rama desde la rama actual {branch}", - "branchNamePlaceholder": "Nombre de la rama", - "newWorktreeTitle": "Nuevo worktree", - "newWorktreeDescription": "Crear un nuevo worktree desde la rama actual {branch}", - "branchNameLabel": "Nombre de la rama", - "worktreePathLabel": "Ruta del worktree", - "worktreePathPlaceholder": "Ruta del worktree", - "manageRemotesTitle": "Gestionar remotos", - "manageRemotesEmpty": "No hay remotos configurados", - "remoteNamePlaceholder": "Nombre del remoto", - "remoteUrlPlaceholder": "URL del remoto", - "addRemote": "Añadir", - "savingRemotes": "Guardando..." - }, - "conflict": { - "title": "Conflictos de fusión", - "description": "Los siguientes archivos tienen conflictos que necesitan ser resueltos:", - "abort": "Abortar fusión", - "openMergeTool": "Abrir herramienta de fusión", - "completeMerge": "Completar fusión", - "abortSuccess": "Fusión abortada correctamente", - "completeSuccess": "Fusión completada correctamente" - }, - "stashDialog": { - "title": "Guardar cambios en stash", - "description": "Guardar los cambios actuales en el stash", - "messageLabel": "Mensaje", - "messagePlaceholder": "Mensaje del stash (opcional)", - "keepIndex": "Mantener índice (los cambios preparados permanecen preparados)", - "cancel": "Cancelar", - "stash": "Guardar", - "success": "Cambios guardados en stash", - "error": "Error al guardar en stash" - }, - "unstashDialog": { - "title": "Aplicar stash", - "noStashes": "No hay stashes", - "selectFile": "Selecciona un archivo para ver diferencias", - "viewDiff": "Ver diferencias", - "original": "Original", - "modified": "Modificado", - "apply": "Aplicar", - "drop": "Eliminar", - "applySuccess": "Stash aplicado", - "dropSuccess": "Stash eliminado", - "confirmApply": "¿Aplicar stash {ref} al directorio de trabajo?", - "cancel": "Cancelar" - }, - "deleteBranch": "Eliminar rama", - "deleteWorktree": "Eliminar worktree", - "deleteWorktreeAndBranch": "Eliminar worktree y rama", - "searchPlaceholder": "Buscar ramas y acciones", - "searchAriaLabel": "Buscar ramas y acciones", - "branchListLabel": "Ramas y acciones", - "noMatches": "Sin coincidencias" - }, - "commitDialog": { - "toasts": { - "commitCompleted": "Commit de código completado", - "pushFailed": "Error al enviar", - "committedFiles": "{count, plural, one {# archivo confirmado} other {# archivos confirmados}}", - "addedToVcs": "Añadido a VCS", - "addToVcsFailed": "No se pudo añadir a VCS", - "fileDeleted": "Archivo eliminado", - "deleteFailed": "Error al eliminar", - "fileRolledBack": "Archivo revertido", - "rollbackFailed": "Error al revertir", - "dirRolledBack": "Directorio revertido", - "dirDeleted": "Directorio eliminado" - }, - "confirm": { - "deleteTitle": "Confirmar eliminación", - "deleteDescription": "¿Eliminar el archivo \"{file}\"? Esta acción no se puede deshacer.", - "rollbackTitle": "Confirmar reversión", - "rollbackDescription": "¿Revertir el archivo \"{file}\" a HEAD? Se perderán los cambios sin guardar.", - "rollbackDirDescription": "¿Revertir el directorio \"{dir}\" a HEAD? Los cambios no guardados se perderán.", - "deleteDirDescription": "¿Eliminar el directorio \"{dir}\"? Esta acción no se puede deshacer." - }, - "actions": { - "select": "Seleccionar", - "unselect": "Deseleccionar", - "rollback": "Revertir", - "addToVcs": "Añadir a VCS" - }, - "aria": { - "selectFile": "{action}: {path}", - "unselectAllFiles": "Deseleccionar todos los archivos", - "selectAllFiles": "Seleccionar todos los archivos", - "unselectTracked": "Deseleccionar cambios rastreados", - "selectTracked": "Seleccionar cambios rastreados", - "unselectUntracked": "Deseleccionar archivos no rastreados", - "selectUntracked": "Seleccionar archivos no rastreados" - }, - "loading": "Cargando...", - "selectionCount": "{selected} / {total} archivos", - "emptyFiles": "No hay archivos cambiados", - "trackedChanges": "Cambios rastreados ({count})", - "untrackedFiles": "Archivos no rastreados ({count})", - "commitMessage": "Mensaje de commit", - "commitMessagePlaceholder": "Introduce el mensaje de commit...", - "commitButton": "Confirmar ({count})", - "commitAndPushButton": "Confirmar y enviar ({count})", - "head": "HEAD", - "workingTree": "Árbol de trabajo", - "clickFileToDiff": "Haz clic en un nombre de archivo para ver diff", - "loadingDiff": "Cargando diff..." - }, - "pushWindow": { - "title": "Enviar código", - "noUnpushedCommits": "No hay commits sin enviar", - "noRemoteConfigured": "No hay remoto Git configurado\nAñade uno en «Gestionar remotos»", - "newBranchNoPushedCommits": "Nueva rama — enviar para crear rama de seguimiento remota", - "unpushed": "Sin enviar", - "selectFileToViewDiff": "Selecciona un archivo para ver las diferencias", - "before": "Antes", - "after": "Después", - "push": "Enviar", - "toasts": { - "pushSuccess": "Envío exitoso", - "pushFailed": "Error al enviar", - "upstreamSet": "Se ha configurado la rama remota", - "upstreamSetAndPushed": "Rama remota configurada y enviados {count} commits", - "noCommitsToPush": "No hay commits para enviar", - "pushedCommits": "Enviados {count} commits" - } - }, - "gitLogTab": { - "filesTitle": "Archivos", - "expandAllFiles": "Expandir todos los archivos", - "collapseAllFiles": "Colapsar todos los archivos", - "workspace": "espacio de trabajo", - "retry": "Reintentar", - "noCommitsFound": "No se encontraron commits", - "notAGitRepoTitle": "No es un repositorio Git", - "notAGitRepoHint": "Inicializa Git desde el menú de ramas superior, o abre un repositorio existente.", - "hash": "Hash del commit", - "copyHash": "Copiar hash", - "copyMessage": "Copiar mensaje", - "showMore": "Mostrar más", - "showLess": "Mostrar menos", - "author": "Autor", - "noFileChangeDetails": "No hay detalles de cambios de archivo disponibles.", - "loadingFiles": "Cargando archivos...", - "branchesTitle": "Ramas", - "loadingBranches": "Cargando ramas...", - "noContainingBranches": "No se encontraron ramas contenedoras.", - "newBranch": "Nueva rama...", - "resetToHere": "Resetear aquí", - "resetDisabledReasonNotCurrentBranchView": "Disponible solo al ver la rama actual", - "copyFullCommitHashAria": "Copiar hash completo del commit {hash}", - "pushStatus": { - "pushed": "Enviado al remoto", - "notPushed": "No enviado al remoto", - "unknown": "Estado de push desconocido (sin upstream configurado)" - }, - "time": { - "monthsAgo": "{count, plural, one {hace # mes} other {hace # meses}}", - "daysAgo": "{count, plural, one {hace # día} other {hace # días}}", - "hoursAgo": "{count, plural, one {hace # hora} other {hace # horas}}", - "minsAgo": "{count, plural, one {hace # min} other {hace # mins}}", - "justNow": "justo ahora" - }, - "toasts": { - "createdAndSwitchedNewBranch": "Nueva rama creada y activada", - "newBranchFromCommit": "{name} (desde {shortHash})", - "createBranchFailed": "No se pudo crear la rama", - "openPushWindowFailed": "No se pudo abrir la ventana de envío", - "resetSuccess": "Reset completado", - "resetSuccessDescription": "{branch} se reseteó a {shortHash} con {mode}", - "resetFailed": "Falló el reset" - }, - "authorFilter": { - "label": "Autor", - "searchPlaceholder": "Buscar autor", - "noAuthors": "No se encontraron autores", - "you": "tú", - "filterByAuthorAria": "Filtrar commits por autor", - "filterByQuery": "Filtrar por \"{query}\"", - "clearAuthorFilterAria": "Borrar filtro de autor", - "recent": "Recientes", - "matchingAuthors": "Autores coincidentes", - "removeFromRecent": "Quitar {name} de recientes" - }, - "branchSelector": { - "label": "Rama", - "head": "HEAD", - "headHint": "Sigue la rama actual", - "headHintWithBranch": "Sigue la rama actual ({branch})", - "searchBranch": "Buscar rama...", - "noBranches": "Sin ramas", - "selectBranchPlaceholder": "Seleccionar rama...", - "localBranches": "Ramas locales", - "current": "Actual", - "remoteBranches": "Ramas remotas", - "refreshCommitHistory": "Actualizar historial de commits", - "clearBranchFilterAria": "Borrar filtro de rama" - }, - "dialogs": { - "newBranchTitle": "Nueva rama", - "newBranchDescription": "Crea una nueva rama con el commit {shortHash} como último commit.", - "branchNamePlaceholder": "Nombre de la rama", - "reset": { - "title": "Resetear la rama actual hasta aquí", - "branchLabel": "Rama", - "targetLabel": "Commit objetivo", - "messageLabel": "Mensaje", - "modeLabel": "Modo de reset", - "confirmButton": "Resetear", - "modes": { - "soft": { - "label": "--soft", - "description": "Mueve HEAD y el puntero de la rama actual al commit objetivo.\nMantiene Index y Working Tree sin cambios.\nLos cambios de los commits retirados permanecen en estado staged." - }, - "mixed": { - "label": "--mixed (predeterminado)", - "description": "Mueve HEAD al commit objetivo.\nResetea Index al commit objetivo y mantiene los cambios en Working Tree.\nLos cambios pasan de staged a unstaged." - }, - "hard": { - "label": "--hard", - "description": "Mueve HEAD y resetea tanto Index como Working Tree al commit objetivo.\nSe descartan los cambios locales rastreados posteriores al commit objetivo.\nEs una operación destructiva." - }, - "keep": { - "label": "--keep", - "description": "Mueve HEAD al commit objetivo e intenta conservar los cambios locales.\nSolo se conservan cambios que no entren en conflicto.\nSi hay conflictos, el reset se aborta para proteger tu trabajo." - } - } - } - }, - "moreActions": "Más acciones de Git" - }, - "gitChangesTab": { - "workspace": "espacio de trabajo", - "noChanges": "No hay cambios locales", - "notAGitRepoTitle": "No es un repositorio Git", - "notAGitRepoHint": "Inicializa Git desde el menú de ramas superior, o abre un repositorio existente.", - "trackedChanges": "Cambios rastreados ({count})", - "untrackedFiles": "Archivos no rastreados ({count})", - "expandTracked": "Expandir cambios rastreados", - "collapseTracked": "Colapsar cambios rastreados", - "expandUntracked": "Expandir archivos no rastreados", - "collapseUntracked": "Colapsar archivos no rastreados", - "showRemainingItems": "Mostrar {count} elementos más", - "actions": { - "commitCode": "Hacer commit del código", - "rollback": "Revertir", - "addToVcs": "Añadir a VCS", - "delete": "Eliminar", - "moreActions": "Más acciones de Git", - "addAllToVcs": "Añadir todo al VCS", - "rollbackAll": "Revertir todo", - "refresh": "Actualizar" - }, - "toasts": { - "noAddableFilesInDir": "No hay archivos cambiados en este directorio para añadir a VCS", - "noRollbackFilesInDir": "No hay archivos cambiados en este directorio para revertir", - "addedToVcs": "Se añadió {name} a VCS", - "addToVcsFailed": "No se pudo añadir a VCS", - "openCommitWindowFailed": "No se pudo abrir la ventana de commit", - "rolledBack": "Se revirtió {name}", - "rollbackFailed": "Error al revertir", - "addedFilesToVcs": "Se añadieron {count, plural, one {# archivo} other {# archivos}} a VCS", - "rolledBackFiles": "Se revirtieron {count, plural, one {# archivo} other {# archivos}}", - "deleted": "Se eliminó {name}", - "deleteFailed": "Error al eliminar", - "deletedFiles": "Se eliminaron {count} archivos", - "noDeletableFilesInDir": "No hay archivos modificados en este directorio que se puedan eliminar", - "commitFailed": "Error al confirmar" - }, - "directoryDialog": { - "descriptionAdd": "Selecciona archivos bajo el directorio {path} para añadir a VCS.", - "descriptionRollback": "Selecciona archivos bajo el directorio {path} para revertir.", - "descriptionDelete": "Selecciona archivos bajo el directorio {path} para eliminar. Esta acción no se puede deshacer.", - "descriptionFallback": "Selecciona archivos para continuar.", - "selectionCount": "Seleccionados {selected} / {total} archivos", - "selectAll": "Seleccionar todo", - "unselectAll": "Deseleccionar todo", - "loadingCandidates": "Cargando cambios del directorio...", - "noOperableFiles": "No hay archivos operables" - }, - "rollbackConfirm": { - "title": "Confirmar reversión", - "descriptionWithTarget": "¿Revertir cambios locales de {kind} \"{name}\"?", - "descriptionFallback": "¿Revertir cambios locales?", - "kindDirectory": "directorio", - "kindFile": "archivo" - }, - "deleteConfirm": { - "title": "Confirmar eliminación", - "descriptionWithTarget": "¿Eliminar {kind} \"{name}\"? Esta acción no se puede deshacer.", - "descriptionFallback": "Esta acción no se puede deshacer.", - "kindDirectory": "directorio", - "kindFile": "archivo" - }, - "quickCommit": { - "placeholder": "Mensaje del commit (Intro para confirmar)" - } - }, - "tabContext": { - "loadingConversation": "Cargando...", - "untitledConversation": "Conversación sin título", - "newConversation": "Nueva conversación" - }, - "fileTreeTab": { - "workspace": "Espacio de trabajo", - "retry": "Reintentar", - "git": "Git", - "openInFileManager": "Abrir en el gestor de archivos", - "openInFinder": "Abrir en Finder", - "openInExplorer": "Abrir en Explorer", - "attachToCurrentSession": "Agregar a la sesión", - "compareWithBranch": "Comparar con rama...", - "reloadFromDisk": "Recargar desde disco", - "new": "Nuevo", - "newFile": "Archivo", - "newDirectory": "Directorio", - "openIn": "Abrir en", - "openInTerminal": "Abrir en terminal", - "linkedFolder": "Carpeta vinculada", - "copyPath": "Copiar ruta", - "upload": "Subir archivos/carpeta", - "download": "Descargar archivo", - "downloadAsZip": "Descargar como ZIP", - "actions": { - "select": "Seleccionar", - "unselect": "Deseleccionar", - "commitCode": "Confirmar código", - "rollback": "Revertir", - "addToVcs": "Añadir a VCS" - }, - "aria": { - "selectPath": "{action}: {path}" - }, - "toasts": { - "openDirectoryFailed": "No se pudo abrir el directorio", - "openBuiltinTerminalFailed": "No se pudo abrir la terminal integrada", - "openCommitWindowFailed": "No se pudo abrir la ventana de commit", - "noAddableFilesInDir": "No hay archivos modificados en este directorio que se puedan añadir a VCS", - "noRollbackFilesInDir": "No hay archivos modificados en este directorio que se puedan revertir", - "addedToVcs": "Se añadió {name} a VCS", - "addToVcsFailed": "No se pudo añadir a VCS", - "loadBranchesFailed": "No se pudieron cargar las ramas", - "renameFailed": "Error al renombrar", - "moveFailed": "Error al mover", - "deleteFailed": "Error al eliminar", - "rolledBack": "Se revirtió {name}", - "rollbackFailed": "Error al revertir", - "addedFilesToVcs": "{count, plural, one {Se añadió # archivo a VCS} other {Se añadieron # archivos a VCS}}", - "rolledBackFiles": "{count, plural, one {Se revirtió # archivo} other {Se revirtieron # archivos}}", - "savedAsCopy": "Guardado como copia", - "saveCopyFailed": "No se pudo guardar como copia", - "watchStartFailed": "No se pudo iniciar la vigilancia de archivos", - "createFailed": "Error al crear", - "downloadFailed": "No se pudo descargar {name}", - "downloadSaved": "{name} descargado", - "pathCopied": "Ruta copiada", - "copyPathFailed": "No se pudo copiar la ruta" - }, - "createDialog": { - "newFile": "Nuevo archivo", - "newDirectory": "Nuevo directorio", - "description": "Ingrese un nombre para el nuevo {kind}.", - "placeholderFile": "file-name.ext", - "placeholderDirectory": "folder-name" - }, - "renameDialog": { - "renameDirectory": "Renombrar directorio", - "renameFile": "Renombrar archivo", - "description": "Introduce un nuevo nombre (solo nombre, sin ruta).", - "placeholderDirectory": "nuevo-nombre-carpeta", - "placeholderFile": "nuevo-nombre-archivo.ext" - }, - "uploadDialog": { - "title": "Subir al área de trabajo", - "description": "Ajusta el destino si es necesario y añade archivos o carpetas.", - "workspaceRoot": "raíz del área de trabajo", - "targetPathLabel": "Subir a", - "targetPathHint": "Ruta resuelta: {path}", - "dropHint": "Arrastra archivos o carpetas aquí, o usa los botones de abajo", - "dropHintActive": "Suelta para añadir a la cola", - "selectFiles": "Seleccionar archivos", - "selectFolder": "Seleccionar carpeta", - "startUpload": "Iniciar subida", - "clearQueue": "Limpiar finalizados", - "removeItem": "Quitar de la cola", - "retry": "Reintentar", - "dropZoneAria": "Suelta archivos aquí o activa para examinar", - "folderEmpty": "No se encontraron archivos en la carpeta soltada", - "summary": "Total: {total} · Con éxito: {succeeded} · Con error: {failed}", - "status": { - "pending": "En espera", - "uploading": "Subiendo", - "success": "Completado", - "error": "Falló", - "cancelled": "Cancelado" - } - }, - "directoryDialog": { - "descriptionAdd": "Selecciona archivos del directorio {path} para añadir a VCS.", - "descriptionRollback": "Selecciona archivos del directorio {path} para revertir.", - "descriptionFallback": "Selecciona archivos para continuar.", - "selectionCount": "Seleccionados {selected} / {total} archivos", - "selectAll": "Seleccionar todo", - "unselectAll": "Deseleccionar todo", - "loadingCandidates": "Cargando cambios del directorio...", - "noOperableFiles": "No hay archivos operables" - }, - "compareDialog": { - "title": "Comparar con rama", - "descriptionWithTarget": "Selecciona una rama y compara con {kind} {path}", - "descriptionFallback": "Selecciona una rama para comparar.", - "kindDirectory": "directorio", - "kindFile": "archivo", - "filterPlaceholder": "Filtra ramas, p. ej. main / origin/main", - "singleClickHint": "Haz clic en una rama para comparar directamente", - "loadingBranches": "Cargando ramas...", - "recentBranches": "Ramas recientes ({count})", - "noCurrentBranch": "Sin rama actual", - "localBranches": "Ramas locales ({count})", - "remoteBranches": "Ramas remotas ({count})", - "noMatchingBranches": "No hay ramas coincidentes" - }, - "externalConflictDialog": { - "title": "Se detectaron cambios externos en archivos", - "descriptionWithPath": "El archivo {path} cambió en disco y las ediciones actuales no están guardadas.", - "descriptionFallback": "El archivo actual cambió en disco y las ediciones actuales no están guardadas.", - "compare": "Comparar", - "savingCopy": "Guardando copia...", - "saveAsCopy": "Guardar como copia", - "reload": "Recargar" - }, - "deleteConfirm": { - "title": "Confirmar eliminación", - "descriptionWithTarget": "¿Eliminar {kind} \"{name}\"? Esta acción no se puede deshacer.", - "descriptionFallback": "Esta acción no se puede deshacer.", - "kindDirectory": "directorio", - "kindFile": "archivo" - }, - "rollbackConfirm": { - "title": "Confirmar reversión", - "descriptionWithTarget": "¿Revertir cambios locales del archivo \"{name}\"?", - "descriptionFallback": "¿Revertir cambios locales de este archivo?" - }, - "terminalTitle": "Consola · {name}" - }, - "commandDropdown": { - "loading": "Cargando...", - "addCommand": "Agregar comando", - "manageCommands": "Gestionar comandos...", - "runCommandTitle": "Ejecutar: {command}", - "stopCommandTitle": "Detener: {command}", - "manageDialog": { - "title": "Gestionar comandos", - "empty": "Aún no hay comandos", - "noResults": "No hay comandos coincidentes", - "searchPlaceholder": "Buscar comandos", - "newCommand": "Nuevo comando", - "nameLabel": "Nombre", - "commandLabel": "Comando", - "dragSort": "Arrastra para ordenar", - "dragSortCommand": "Arrastra para ordenar {name}", - "orderFailed": "No se pudo guardar el orden de los comandos", - "loadFailed": "No se pudieron cargar los comandos", - "saveFailed": "No se pudo guardar el comando", - "deleteFailed": "No se pudo eliminar el comando", - "confirmDelete": { - "title": "¿Eliminar comando?", - "message": "Esto eliminará \"{name}\". Esta acción no se puede deshacer." - } - } - }, - "workspaceContext": { - "confirmCloseDirtyTab": "¿Cerrar \"{title}\" sin guardar?", - "confirmCloseOtherDirtyTabs": "¿Cerrar otras pestañas con cambios sin guardar?", - "confirmCloseAllDirtyTabs": "¿Cerrar todas las pestañas con cambios sin guardar?", - "unableLoadContent": "No se puede cargar el contenido.\n\n{message}", - "previewRequestTimedOut": "La solicitud de vista previa agotó el tiempo", - "diffRequestTimedOut": "La solicitud de Diff agotó el tiempo", - "branchCompareRequestTimedOut": "La solicitud de comparación de ramas agotó el tiempo", - "commitDiffRequestTimedOut": "La solicitud de Diff de commit agotó el tiempo", - "saveRequestTimedOut": "La solicitud de guardado agotó el tiempo", - "reloadRequestTimedOut": "La solicitud de recarga agotó el tiempo", - "noChanges": "Sin cambios.", - "noDiffOutput": "Sin salida de diff.", - "diffTitleWorkspace": "Diferencias · Espacio de trabajo", - "diffDescriptionWorkingTree": "Árbol de trabajo (HEAD)", - "diffTitleFile": "Diferencias · {name}", - "compareTitleFile": "Comparar · {name}", - "compareTitleBranch": "Comparar · {branch}", - "compareDescriptionPath": "{path} · comparar con {branch}", - "compareDescriptionBranch": "comparar con {branch}", - "diffTitleCommitFile": "Diferencias · {name} @ {hash}", - "diffTitleCommit": "Diferencias · {hash}", - "diffDescriptionCommitPath": "{path} · confirmación {commit}", - "diffDescriptionCommit": "confirmación {commit}", - "diffTitleConflictFile": "Conflicto · {name}", - "diffDescriptionConflict": "{path} · disco vs sin guardar" - }, - "chat": { - "acpConnections": { - "actions": { - "openAgentsSettings": "Abrir ajustes de agentes", - "retry": "Reintentar" - }, - "agentsSetupHint": "Abre Ajustes > Agentes para gestionar la instalación.", - "withSetupHint": "{message}\n{hint}", - "blocked": { - "missingConfig": "No se puede leer la configuración actual del agente.", - "disabled": "{agent} está deshabilitado en Ajustes de agentes. Actívalo antes de conectar.", - "unavailable": "{agent} no está disponible en la plataforma actual.", - "sdkMissing": "El SDK de {agent} no está instalado", - "adapterMissing": "El adaptador ACP de {agent} no está instalado" - }, - "backendErrors": { - "initializeTimeout": "Se agotó el tiempo del handshake de conexión de {agent} (sin respuesta tras 60 segundos). Abre Ajustes para revisar la configuración del agente y de la red.", - "mcpRejectedByAgent": "{agent} rechazó la sesión con el complemento MCP de codeg adjunto: {message} Si este agente no admite MCP, desactiva «Compatibilidad con MCP» en Ajustes y vuelve a conectar.", - "processExited": "El proceso de {agent} terminó inesperadamente.", - "spawnFailed": "No se pudo iniciar {agent}: {message}", - "downloadFailed": "La descarga de {agent} falló: {message}", - "sessionLoadResourceNotFound": "Error al cargar la sesión de {agent}. Recarga para reintentar o inicia una nueva conversación.", - "sessionLoadUnavailable": "{agent} no pudo restaurar esta sesión; es posible que haya finalizado o que el agente se haya detenido. Recarga para reintentar o inicia una nueva conversación.", - "turnFailedRefusal": "{agent} rechazó continuar este turno. Suele indicar un error de backend o pasarela. Revisa los registros del agente.", - "turnFailedMaxTokens": "{agent} alcanzó el límite máximo de tokens para este turno.", - "turnFailedMaxTurnRequests": "{agent} alcanzó el número máximo de solicitudes permitidas para este turno.", - "turnFailedUnknown": "{agent} finalizó el turno con un motivo de parada no reconocido.", - "grokModelSwitchIncompatibleAgent": "{agent} no puede cambiar a ese modelo en una conversación existente. Inicia una nueva sesión para usarlo.", - "turnFailedEmpty": "{agent} finalizó el turno sin producir ninguna respuesta.", - "turnFailedEmptyProtocol": "{agent} produjo una salida que codeg no pudo analizar; la versión del agente podría no coincidir con el protocolo.", - "turnFailedEmptyMetadata": "{agent} solo envió actualizaciones de estado en este turno (plan / modo / uso) y ninguna respuesta.", - "detailsInAlerts": "Abre Alertas en la barra de estado y despliega los detalles para ver la salida del agente." - }, - "unableReadAgentConfig": "No se puede leer la configuración del agente: {message}", - "connectFailedTitle": "Falló la conexión de {agent}", - "toolFallbackTitle": "Herramienta", - "eventErrorTitle": "Error del agente", - "notificationTurnComplete": "{agent} ha terminado de responder", - "notificationError": "{agent} error: {message}", - "claudeApiRetry": { - "fallbackError": "authentication_failed", - "retryingWithMax": "reintentando {attempt}/{max}", - "retryingAttempt": "reintentando intento {attempt}", - "retrying": "reintentando", - "nextRetryIn": "siguiente en {seconds}s", - "line": "{error}{status} · {retry}", - "lineWithDelay": "{error}{status} · {retry}, {delay}", - "httpStatus": " (HTTP {status})" - }, - "configOptionAdjusted": "{agent} estableció {option} en {actual} en lugar de {requested}" - }, - "connectionLifecycle": { - "tasks": { - "connectingTitle": "Conectando con {agent}", - "connectingDescription": "Estableciendo conexión", - "loadingSelectorsTitle": "Cargando selectores de {agent}", - "loadingSelectorsDescription": "Obteniendo opciones de modo y configuración de sesión", - "initSessionTitle": "Initializing {agent} session", - "initSessionDescription": "Creating session and loading configuration" - }, - "errors": { - "connectionFailed": "Conexión fallida", - "sendPromptFailed": "No se pudo enviar el mensaje: {error}" - } - }, - "shared": { - "attachedResources": "Recursos adjuntos", - "toolCallFailed": "Falló la llamada de herramienta" - }, - "messageThread": { - "emptyTitle": "Aún no hay mensajes", - "emptyDescription": "Inicia una conversación para ver mensajes aquí" - }, - "chatInput": { - "connecting": "Conectando...", - "agentResponding": "{agent} está respondiendo...", - "sendMessage": "Enviar un mensaje..." - }, - "messageInput": { - "askAnything": "Pregunta lo que sea...", - "removeAttachmentAria": "Quitar {name}", - "attachFiles": "Adjuntar archivos", - "addActions": "Añadir", - "quickMessages": "Mensajes rápidos", - "quickMessagesEmpty": "Aún no hay mensajes rápidos", - "quickMessagesLoading": "Cargando...", - "pasteAsPlainText": "Pegar como texto sin formato", - "cut": "Cortar", - "copy": "Copiar", - "selectAll": "Seleccionar todo", - "pasteUnavailable": "No se pudo leer el portapapeles. Pulsa Ctrl/⌘V para pegar.", - "clipboardWriteFailed": "No se pudo escribir en el portapapeles. Usa el atajo de teclado.", - "quickMessageUntitled": "Sin título", - "liveFeedback": "Comentarios en vivo", - "liveFeedbackDisabledHint": "Disponible mientras el agente trabaja", - "dropFilesToAttach": "Suelta archivos para adjuntar", - "loadingSettings": "Cargando ajustes...", - "loadingMode": "Cargando modo...", - "modeLabel": "Modo", - "toggleOn": "Activado", - "toggleOff": "Desactivado", - "agentSettings": "Ajustes del agente", - "searchModel": "Buscar modelos...", - "searchModelAria": "Buscar modelos", - "modelListLabel": "Modelos", - "noModels": "No se encontraron modelos", - "cancel": "Cancelar", - "send": "Enviar", - "forkAndSend": "Fork y Enviar", - "queueMessage": "Poner en cola", - "steerIntoTurn": "Insertar en el turno actual", - "steerQueuedInstead": "Se puso en cola: se enviará con el siguiente turno.", - "steerFailed": "No se pudo insertar en el turno actual", - "steerAttachmentsUnsupported": "Solo texto: los borradores con adjuntos pasan por la cola.", - "slashCommands": "Comandos de barra", - "slashSearchPlaceholder": "Buscar comandos...", - "slashSearchEmpty": "Sin comandos coincidentes", - "experts": "Expertos", - "office": "Ofimática", - "research": "Investigación", - "attachLocalUpload": "Subir archivo local", - "attachServerFile": "Seleccionar archivo del servidor", - "attachUploadTooLarge": "{names} supera el límite de carga de {limit}MB y se omitió.", - "attachUploadFailed": "Error al subir {names}.", - "attachUploadNotAFile": "{names} no es un archivo regular (directorio o archivo especial) y se omitió.", - "attachUploadQuotaExceeded": "El servidor se quedó sin espacio para subidas; no se pudo cargar {names}.", - "attachUploadInProgress": "Las imágenes aún se están subiendo; inténtalo de nuevo en un momento.", - "mentionEmpty": "Sin coincidencias", - "mentionLoading": "Buscando…", - "mentionListLabel": "Menciones", - "mentionMore": "Más resultados: sigue escribiendo para filtrar", - "mentionCount": "{count, plural, one {# resultado} other {# resultados}}", - "mentionGroupFile": "Archivos", - "mentionGroupAgent": "Agentes", - "mentionGroupSession": "Sesiones", - "mentionGroupCommit": "Commits", - "mentionGroupSkill": "Habilidades" - }, - "messageQueue": { - "addToQueue": "Agregar a la cola", - "saveEdit": "Guardar", - "cancelEdit": "Cancelar edición", - "editItem": "Editar", - "deleteItem": "Eliminar" - }, - "welcomeInputPanel": { - "agentsSettingsPath": "Ajustes > Agentes", - "autoConnectFallback": "Haz clic para abrir {path} y gestionar la instalación.", - "autoConnectAppend": "{message}. Haz clic para abrir {path} y gestionar la instalación.", - "enableAgentFirstPlaceholder": "Habilita al menos un agente antes de iniciar una sesión...", - "prepareSessionFailed": "No se pudo preparar la sesión de chat. Inténtalo de nuevo.", - "createConversationFailed": "No se pudo crear la conversación. Inténtalo de nuevo.", - "askAnythingPlaceholder": "Pregunta lo que sea...", - "agentNotInstalled": "{agent} no está instalado · abre la configuración de Agents para instalarlo", - "agentAdapterNotInstalled": "El adaptador ACP de {agent} no está instalado (es aparte de tu propia CLI) · abre la configuración de Agents para instalarlo" - }, - "welcomePanel": { - "greeting": "¿Qué te gustaría hacer hoy?", - "tips": { - "tileTabs": "Haz clic derecho en una pestaña de conversación y elige Vista en mosaico para comparar varias sesiones lado a lado.", - "pinTab": "Haz doble clic en una pestaña de conversación para fijarla y que una sesión nueva no la reemplace automáticamente.", - "shortcutsNewSearch": "{newConversation} abre una conversación nueva, {searchConversations} busca en el historial.", - "slashAtMention": "Escribe / en la entrada para activar comandos slash, o @ para referenciar un archivo del proyecto.", - "pasteDropFiles": "Pega una captura de pantalla o arrastra un archivo a la entrada para adjuntarlo.", - "queueMessage": "Mientras el agente responde, sigue escribiendo: tu próximo mensaje se pone en cola y se envía al terminar.", - "draftAutoSave": "Los borradores sin enviar se guardan automáticamente por conversación y se restauran al volver.", - "forkSend": "El desplegable del botón de enviar incluye Bifurcar y enviar, que ramifica desde el punto actual a una pestaña nueva.", - "exportConversation": "Haz clic derecho dentro de la conversación para exportarla como Markdown, HTML o imagen.", - "chatChannels": "Conecta Telegram / Lark / WeChat en Ajustes → Canales de chat para continuar desde el móvil.", - "shortcutsAuxPanel": "{toggleAuxPanel} alterna el panel derecho para ver los archivos tocados y los cambios de Git de esta sesión.", - "shortcutsTerminalSidebar": "{toggleTerminal} abre la terminal integrada, {toggleSidebar} alterna la barra lateral.", - "customShortcuts": "Todos los atajos se pueden reasignar en Ajustes → Atajos.", - "webService": "Activa Ajustes → Servicio web para que tu equipo acceda al mismo codeg desde un navegador.", - "fusionMode": "Abre un archivo o diff para mostrarlo automáticamente junto a la conversación.", - "quickMessages": "Abre el botón + junto a la entrada y elige Mensajes rápidos para insertar un fragmento guardado (gestiónalos en Ajustes → Mensajes rápidos).", - "experts": "El botón + tiene un menú Habilidades expertas: carga roles como Depuración o Planificación con un clic.", - "taskBoard": "Las tareas pendientes ejecutan un trabajo de principio a fin: el agente trabaja en su propio worktree y tú revisas el diff antes de fusionar.", - "automations": "Las Automatizaciones ejecutan un prompt guardado según un horario —una revisión nocturna, un informe recurrente— y cada ejecución puede tener su propio worktree.", - "tokenUsage": "Haz clic en el número de conversaciones de la barra de estado para abrir Uso de tokens, desglosado por día, agente, modelo y carpeta.", - "mentionTargets": "@ no solo trae archivos: menciona a otro agente para delegarle una subtarea, o referencia una sesión anterior, un commit o una habilidad.", - "splitGroups": "Haz clic derecho en una pestaña y elige Dividir a la derecha o Dividir abajo para mantener dos conversaciones en paneles propios.", - "worktrees": "Abre el botón de rama y elige Nuevo worktree para que varios agentes trabajen en el mismo repositorio sin pisarse los archivos.", - "importSessions": "¿Ya ejecutaste sesiones en la terminal? El menú de una carpeta tiene Importar sesiones locales para traer ese historial a codeg.", - "subSessions": "Cuando un agente delega, la subsesión aparece anidada bajo él en la barra lateral: despliega la fila para seguir lo que hizo cada una.", - "liveFeedback": "Comentarios en vivo, en el menú +, inserta una nota en el turno que el agente ya está ejecutando, sin interrumpirlo.", - "skillPacks": "Configuración → Paquetes de habilidades reúne expertos de programación, investigación científica y ofimática; actívalos por agente.", - "modelProviders": "Configuración → Proveedores de Modelos acepta tu propia clave de API o endpoint, y el modelo lo eliges desde el cuadro de entrada.", - "workspaceBackground": "Configuración → Apariencia define una imagen de fondo del espacio de trabajo, la opacidad de los paneles y las fuentes de la app." - }, - "quickActions": { - "excel": "Libro de Excel", - "excelDesc": "Tablas, fórmulas y gráficos", - "word": "Documento de Word", - "wordDesc": "Informes, cartas y notas", - "ppt": "Presentación", - "pptDesc": "Diapositivas con diseño profesional", - "pitchDeck": "Pitch Deck", - "pitchDeckDesc": "Presentación de inversión con métricas", - "morph": "Animación Morph", - "morphDesc": "Transiciones de diapositiva cinematográficas", - "morph3d": "Morph 3D", - "morph3dDesc": "Modelos 3D con movimientos de cámara", - "academic": "Artículo académico", - "academicDesc": "Investigación con citas y estructura", - "financial": "Modelo financiero", - "financialDesc": "Estados, DCF y proyecciones", - "dashboard": "Panel de datos", - "dashboardDesc": "KPIs y análisis a partir de tus datos", - "prompts": { - "excel": "Crea un libro de Excel con los siguientes requisitos:\n\n[describe aquí tus datos, tablas, fórmulas y gráficos]", - "word": "Crea un documento de Word con los siguientes requisitos:\n\n[describe aquí el contenido, la estructura y el formato del documento]", - "ppt": "Crea una presentación de PowerPoint con los siguientes requisitos:\n\n[describe aquí tus diapositivas, contenido y diseño]", - "pitchDeck": "Crea un pitch deck de inversión con los siguientes requisitos:\n\n[describe aquí tu empresa, ronda de financiación y métricas clave]", - "morph": "Crea una presentación con animaciones de transición Morph:\n\n[describe aquí el tema de la presentación y los efectos visuales deseados]", - "morph3d": "Crea una presentación Morph 3D con modelos GLB y movimientos de cámara:\n\n[describe aquí tu tema y concepto visual en 3D]", - "academic": "Escribe un artículo académico en Word con los siguientes requisitos:\n\n[describe aquí tu tema de investigación, metodología y hallazgos clave]", - "financial": "Crea un modelo financiero en Excel con los siguientes requisitos:\n\n[describe aquí tus estados financieros, proyecciones y análisis]", - "dashboard": "Crea un panel de datos en Excel con los siguientes requisitos:\n\n[describe aquí tu fuente de datos, KPIs y gráficos]", - "scientific-brainstorming": "Ayúdame a generar ideas de investigación: explora conexiones interdisciplinares, cuestiona supuestos y detecta vacíos prometedores. El área que exploro: ", - "hypothesis-generation": "Ayúdame a convertir estas observaciones en hipótesis comprobables, con predicciones claras, mecanismos plausibles y experimentos para probarlas. Mis observaciones: ", - "experimental-design": "Ayúdame a diseñar un experimento riguroso antes de recolectar datos: el diseño, la aleatorización, los controles y cómo evitar la confusión. Lo que quiero estudiar: ", - "statistical-power": "Ayúdame a determinar el tamaño muestral que necesito: guíame en un análisis de potencia (tamaño del efecto, alfa, potencia) para mi diseño. Detalles: ", - "statistical-analysis": "Ayúdame a analizar estos datos correctamente: elige la prueba adecuada, verifica los supuestos, informa los tamaños de efecto y redáctalo. Mis datos y pregunta: ", - "exploratory-data-analysis": "Haz un análisis exploratorio de mi archivo de datos: resume su estructura, calidad y patrones destacados, y sugiere próximos pasos. El archivo es: ", - "scientific-visualization": "Ayúdame a crear una figura de calidad de publicación: diseño claro, barras de error honestas, una paleta apta para daltónicos y formato de revista. Lo que quiero mostrar: ", - "scientific-critical-thinking": "Ayúdame a evaluar críticamente este estudio o afirmación: valora la calidad de la evidencia, detecta sesgos y confusores, y pondera las conclusiones. Aquí está: ", - "paper-lookup": "Ayúdame a encontrar artículos relevantes y texto completo de acceso abierto en bases de datos académicas, con citas que pueda reutilizar. Busco: " - }, - "paper-lookup": "Búsqueda de artículos", - "paper-lookupDesc": "Busca en 10 API académicas (PubMed, arXiv, OpenAlex, Crossref…) artículos, citas y texto completo de acceso abierto.", - "scientific-critical-thinking": "Pensamiento crítico", - "scientific-critical-thinkingDesc": "Evalúa afirmaciones científicas y calidad de la evidencia: detecta sesgos y confusores, aplica GRADE y riesgo de sesgo.", - "scientific-visualization": "Visualización científica", - "scientific-visualizationDesc": "Figuras listas para publicar: diseños multipanel, anotaciones de significancia y formato específico de revista.", - "exploratory-data-analysis": "Análisis exploratorio de datos", - "exploratory-data-analysisDesc": "Exploración automatizada de archivos de datos científicos en más de 200 formatos con métricas de calidad e informes.", - "statistical-analysis": "Análisis estadístico", - "statistical-analysisDesc": "Análisis estadístico guiado: selección de pruebas, verificación de supuestos, tamaños de efecto e informe estilo APA.", - "statistical-power": "Potencia estadística", - "statistical-powerDesc": "Análisis de tamaño muestral y potencia: cuántos sujetos necesitas, efectos mínimos detectables y curvas de potencia.", - "experimental-design": "Diseño experimental", - "experimental-designDesc": "Diseña estudios rigurosos antes de recolectar datos: aleatorización, bloqueo, controles y diseños factoriales/DOE.", - "hypothesis-generation": "Generación de hipótesis", - "hypothesis-generationDesc": "Convierte observaciones en hipótesis comprobables con predicciones, mecanismos y experimentos para probarlas.", - "scientific-brainstorming": "Lluvia de ideas científica", - "scientific-brainstormingDesc": "Ideación abierta de investigación: explora conexiones interdisciplinares, cuestiona supuestos y detecta vacíos.", - "tabs": { - "office": "Ofimática", - "coding": "Desarrollo de código", - "research": "Investigación" - }, - "coding": { - "brainstormingDesc": "Explora intención y requisitos antes de construir", - "debuggingDesc": "Encuentra la causa raíz antes de proponer arreglos", - "writingSkillsDesc": "Crea, edita y verifica habilidades reutilizables" - }, - "notEnabled": { - "title": "La habilidad «{skill}» aún no está activada para {agent}", - "description": "Actívala en Ajustes para usarla aquí.", - "action": "Activar", - "hint": "Habilidad no activada" - }, - "scrollPrev": "Mostrar habilidades anteriores", - "scrollNext": "Mostrar más habilidades" - } - }, - "agentSelector": { - "noEnabledAgents": "No hay agentes habilitados", - "openAgentsSettings": "Abrir ajustes de agentes", - "notInstalled": "No instalado", - "moreAgents": "Más agentes ({count})" - }, - "subAgentOverlay": { - "title": "Subagentes", - "collapsedSummary": "Subagentes {count}", - "collapseAria": "Contraer subagentes" - }, - "agentPlanOverlay": { - "title": "Plan del agente", - "collapsePlanAria": "Contraer plan", - "collapsedSummary": "Plan de trabajo {completed}/{total}", - "status": { - "completed": "Completado", - "inProgress": "En progreso", - "pending": "Pendiente", - "unknown": "Desconocido" - }, - "priority": { - "high": "Alta", - "medium": "Media", - "low": "Baja", - "unknown": "Desconocida" - } - }, - "permissionDialog": { - "subtitle": "El agente solicita permiso para continuar este turno.", - "queuedCount": "+{count} en espera", - "kindFallbackTool": "herramienta", - "command": "Comando", - "cwd": "Directorio de trabajo: {cwd}", - "filesSummary": "Archivos: {count}", - "moreFiles": "+{count} archivos más", - "plan": "Plan de trabajo", - "allowedActions": "Acciones permitidas", - "targetMode": "Modo objetivo: {mode}", - "optionGrants": "Lo que concede cada opción", - "changeScopeSession": "Esta sesión", - "changeScopeProcess": "Esta ejecución", - "changeScopeUser": "Guardado en la configuración del usuario", - "changeScopeProject": "Guardado en la configuración del proyecto", - "changeScopeProjectLocal": "Guardado en la configuración local del proyecto", - "changeScopePersistent": "Guardado permanentemente" - }, - "questionDialog": { - "title": "El agente está haciendo una pregunta", - "placeholder": "Escribe tu respuesta...", - "send": "Enviar" - }, - "messageBranch": { - "previousBranchAria": "Rama anterior", - "nextBranchAria": "Rama siguiente", - "pageOf": "{current} de {total}" - }, - "terminal": { - "title": "Consola", - "running": "En ejecución" - }, - "reasoning": { - "thinking": "Pensando…", - "thoughtForFewSeconds": "Pensamiento", - "thoughtForSeconds": "Pensamiento" - }, - "linkSafety": { - "errorCannotOpen": "No se puede abrir el archivo local", - "errorNoWorkspace": "No hay ninguna carpeta de espacio de trabajo activa.", - "errorFailedOpen": "Error al abrir el archivo local", - "errorFailedLink": "Error al abrir el enlace", - "errorUnsupportedLinkProtocol": "Este protocolo de enlace no es compatible." - }, - "fileActions": { - "openInFinder": "Abrir en Finder", - "openInExplorer": "Abrir en Explorer", - "openInFileManager": "Abrir en el gestor de archivos", - "copyRelativePath": "Copiar ruta relativa", - "copyAbsolutePath": "Copiar ruta absoluta", - "pathCopied": "Ruta copiada", - "copyPathFailed": "No se pudo copiar la ruta", - "openFailed": "Error al abrir el archivo local" - }, - "messageList": { - "attachedResources": "Recursos adjuntos", - "loading": "Cargando...", - "loadEarlier": "Cargar mensajes anteriores", - "loadingEarlier": "Cargando mensajes anteriores…", - "error": "Error del chat: {message}", - "errorTitle": "Error al cargar la sesión", - "errorActionReload": "Recargar", - "errorActionNewSession": "Nueva conversación", - "emptyConversation": "No hay mensajes en esta conversación.", - "systemMessage": "Mensaje del sistema", - "copyMessage": "Copiar", - "copied": "Copiado", - "downloadImage": "Descargar imagen", - "downloadFailed": "Descarga fallida: {message}", - "imageGeneration": "Generación de imágenes", - "imageGenerationPending": "Generando imagen…", - "imageGenerationFailed": "Error al generar la imagen", - "model": "Modelo", - "tokenStats": "Uso de tokens", - "tokenInput": "Entrada", - "tokenOutput": "Salida", - "tokenCacheRead": "Lectura de caché", - "tokenCacheWrite": "Escritura de caché", - "duration": "Duración", - "completedAt": "Completado a las", - "jumpToPreviousUserMessage": "Ir al mensaje del usuario", - "showMore": "Mostrar más", - "showLess": "Mostrar menos" - }, - "liveTurnStats": { - "thinking": "Pensando...", - "streaming": "Transmitiendo", - "elapsedHours": "{value} h", - "elapsedMinutes": "{value} min", - "elapsedSeconds": "{value} s", - "outputSpeedAria": "Velocidad de salida estimada", - "outputSpeedTooltip": "Velocidad de salida estimada (texto + razonamiento)" - }, - "jsonTree": { - "viewRaw": "Ver JSON sin formato", - "viewTree": "Ver árbol", - "fields": "{count, plural, one {# campo} other {# campos}}", - "items": "{count, plural, one {# elemento} other {# elementos}}" - }, - "tool": { - "parameters": "Parámetros", - "error": "Error de herramienta", - "result": "Resultado", - "status": { - "approvalRequested": "Esperando aprobación", - "approvalResponded": "Respondido", - "inputAvailable": "En ejecución", - "inputStreaming": "Pendiente", - "outputAvailable": "Completado", - "outputDenied": "Denegado", - "outputError": "Error de salida" - } - }, - "toolCallBlock": { - "tool": "Herramienta", - "error": "Error de ejecución", - "result": "Resultado" - }, - "delegation": { - "subAgentRunning": "Subagente en ejecución…", - "noDetail": "No detail available yet.", - "unknownAgent": "Sub-agente", - "openDetail": "Ver conversación", - "detailTitle": "Conversación del subagente", - "detailDescription": "Vista de solo lectura de la conversación del subagente delegado.", - "waitForResult": "Esperando el resultado de la tarea {task}", - "waitForResultNoTask": "Esperando el resultado de la tarea", - "cancelTask": "Cancelando la tarea {task}", - "cancelTaskNoTask": "Cancelando la tarea", - "resultPageOf": "{current} / {total}", - "prevResult": "Resultado anterior", - "nextResult": "Resultado siguiente", - "noResultText": "Sin resultado en esta comprobación.", - "status": { - "starting": "iniciando", - "running": "en curso", - "checked": "consultado", - "waiting": "esperando aprobación", - "ok": "completado", - "err": { - "default": "fallido", - "delegation_disabled": "deshabilitado", - "depth_limit": "límite de profundidad", - "invalid_agent_type": "agente inválido", - "spawn_failed": "fallo al iniciar", - "send_failed": "fallo al enviar", - "timeout": "tiempo agotado", - "canceled": "cancelado", - "child_refusal": "subagente rechazó", - "child_max_tokens": "subagente: límite de tokens", - "child_max_turn_requests": "subagente: límite de solicitudes", - "child_empty": "subagente sin salida", - "child_unknown": "subagente: error", - "unknown": "tarea desconocida" - } - } - }, - "contentParts": { - "showingTailOutput": "Mostrando la salida final durante el streaming para mejorar el rendimiento.", - "result": "Resultado", - "unknown": "desconocido", - "inputTruncated": "La entrada fue truncada — el diff puede estar incompleto.", - "replaceAll": "REEMPLAZAR TODO", - "filesCount": "Archivos: {count}", - "update": "actualizar", - "moreFiles": "+{count} archivos más", - "timeoutMs": "Tiempo de espera: {timeout}ms", - "backgroundTrue": "Segundo plano: true", - "scriptToolCalls": "{count, plural, one {# llamada a herramienta} other {# llamadas a herramientas}}", - "offset": "Desplazamiento: {offset}", - "limit": "Límite: {limit}", - "pages": "Páginas: {pages}", - "mode": "Modo: {mode}", - "cell": "Celda: {cell}", - "shellSession": "Sesión {id}", - "pathLabel": "Ruta:", - "globLabel": "Patrón glob:", - "typeLabel": "Tipo:", - "outputLabel": "Salida:", - "caseInsensitive": "Sin distinguir mayúsculas/minúsculas", - "multiline": "Multilínea", - "promptLabel": "Instrucción", - "subjectLabel": "Asunto", - "taskLabel": "Tarea", - "nameLabel": "Nombre:", - "agentPromptLabel": "Instrucción", - "agentModelLabel": "Modelo", - "agentRunning": "Ejecutando...", - "agentLiveTranscript": "Actividad en vivo", - "agentProgressTools": "{count} llamadas a herramientas", - "agentProgressTurns": "{count} turnos", - "agentProgressContext": "contexto {pct}%", - "agentSessionAction": "Ver la sesión del subagente", - "agentSessionTitle": "Sesión del subagente", - "agentSessionLoading": "Cargando la transcripción del subagente…", - "agentSessionEmpty": "El subagente aún no ha escrito nada.", - "agentFallbackTitle": "Iniciando subagente…", - "agentCodexLaunchOnly": "Lanzado. Codex no informa de más progreso sobre este subagente: su resultado llega como un mensaje en esta conversación.", - "agentStatsBash": "Comandos", - "agentStatsRead": "Archivos leídos", - "agentStatsSearch": "Búsquedas", - "agentStatsEdit": "Ediciones", - "agentStatsOther": "Otros", - "goal": { - "title": "Objetivo:", - "titleWithStatus": "Objetivo {status}", - "objective": "Objetivo", - "statusLabel": "Estado", - "tokensUsed": "Tokens usados", - "budget": "Presupuesto", - "remaining": "Restante", - "elapsed": "Transcurrido", - "tokens": "tokens", - "pause": "Pausar", - "clear": "Borrar", - "status": { - "active": "activo", - "paused": "pausado", - "blocked": "bloqueado", - "usageLimited": "uso limitado", - "budgetLimited": "presupuesto limitado", - "complete": "completo", - "limited": "límite alcanzado" - } - }, - "field": { - "file": "Archivo", - "notebook": "Cuaderno", - "command": "Comando", - "old": "Anterior", - "new": "Nuevo", - "pattern": "Patrón", - "path": "Ruta", - "query": "Consulta", - "url": "URL:", - "description": "Descripción", - "content": "Contenido", - "source": "Fuente", - "prompt": "Instrucción", - "subject": "Asunto", - "taskId": "ID de tarea", - "status": "Estado", - "skill": "Skill", - "args": "Argumentos", - "offset": "Desplazamiento", - "limit": "Límite", - "glob": "Patrón glob", - "type": "Tipo", - "output": "Salida", - "replaceAll": "Reemplazar todo", - "language": "Idioma", - "timeout": "Tiempo de espera", - "background": "Segundo plano", - "agentType": "Tipo de agente", - "library": "Biblioteca", - "libraryId": "ID de biblioteca" - }, - "title": { - "edit": "Editar", - "command": "Comando", - "script": "Script", - "waitCommand": "Esperar {command}", - "waitCell": "Esperar sesión {id}", - "terminateCommand": "Terminar {command}", - "terminateCell": "Terminar sesión {id}", - "stdinChars": "Entrada {chars}", - "todoWrite": "TodoWrite (actualización de tareas)", - "read": "Leer", - "write": "Escribir", - "notebookEdit": "NotebookEdit (edición de cuaderno)", - "editFiles": "Editar ({count} archivos)", - "editWithTarget": "Editar {target}", - "readWithTarget": "Leer {target}", - "writeWithTarget": "Escribir {target}", - "notebookEditWithTarget": "NotebookEdit ({target})", - "globWithPattern": "Patrón glob {pattern}", - "listFilesWithPath": "Listar archivos {path}", - "grepWithPattern": "Patrón grep {pattern}", - "taskCreateWithSubject": "Crear tarea: {subject}", - "taskUpdateWithStatus": "Actualizar tarea #{id} -> {status}", - "taskUpdate": "Actualizar tarea #{id}", - "webFetchWithUrl": "WebFetch ({url})", - "webSearchWithQuery": "Búsqueda web: {query}", - "todosProgress": "Tareas ({done}/{total})", - "skillWithName": "Skill: {name}", - "genericWithContext": "{tool} ({context})" - }, - "search": { - "noMatches": "Sin coincidencias", - "matchSummary": "{matches, plural, one {# coincidencia} other {# coincidencias}} en {files, plural, one {# archivo} other {# archivos}}", - "fileSummary": "{files, plural, one {# archivo} other {# archivos}}", - "moreResults": "{count, plural, one {# resultado más no mostrado} other {# resultados más no mostrados}}" - }, - "toolGroup": { - "search": "{count, plural, one {Exploró # búsqueda} other {Exploró # búsquedas}}", - "command": "{count, plural, one {Ejecutó # comando} other {Ejecutó # comandos}}", - "read": "{count, plural, one {Leyó archivos # vez} other {Leyó archivos # veces}}", - "memory": "{count, plural, one {Recordó # memoria} other {Recordó # memorias}}", - "edit": "{count, plural, one {Editó archivos # vez} other {Editó archivos # veces}}", - "fetch": "{count, plural, one {Recuperó # recurso} other {Recuperó # recursos}}", - "think": "{count, plural, one {Pensó # vez} other {Pensó # veces}}", - "todo": "{count, plural, one {Actualizó # tarea} other {Actualizó # tareas}}", - "task": "{count, plural, one {Ejecutó # tarea} other {Ejecutó # tareas}}", - "other": "{count, plural, one {Usó # herramienta} other {Usó # herramientas}}", - "errorSuffix": "{count, plural, one {# falló} other {# fallaron}}", - "joiner": " · " - }, - "planMode": { - "entered": "Modo de planificación iniciado", - "planLabel": "Plan", - "reviewApproved": "Plan aprobado: implementando", - "reviewKept": "Se mantuvo en modo plan", - "reviewPending": "Esperando la decisión sobre el plan", - "submitted": "Plan enviado", - "switched": "Modo cambiado" - }, - "backgroundTask": { - "title": "Tarea en segundo plano", - "titleWithId": "Tarea en segundo plano · {id}", - "running": "En ejecución", - "completed": "Completada", - "failed": "Fallida", - "stopped": "Detenida", - "exitCode": "salida {code}", - "polledTimes": "Consultada {count} veces", - "runningInBackground": "Segundo plano", - "launchNote": "Ejecutándose en segundo plano · {id}" - }, - "codexScript": { - "outputMissing": "Codex truncó la salida del script y eliminó el separador de este comando, por lo que no se le pudo atribuir ninguna salida.", - "sharedWith": "También contiene la salida de {commands}: codex truncó sus separadores.", - "truncated": "truncado" - } - }, - "messageNav": { - "title": "Navegación de mensajes", - "collapse": "Contraer navegación de mensajes", - "collapsedSummary": "Mensajes {count}", - "fileCount": "{count, plural, one {# archivo} other {# archivos}}", - "remove": "Quitar", - "noDiffDataAvailable": "No hay datos de diff disponibles para {filePath}" - }, - "replyArtifacts": { - "title": "Archivos modificados", - "fileCount": "{count, plural, one {# archivo} other {# archivos}}", - "newFilesTitle": "Archivos nuevos", - "revealInFolder": "Mostrar en el gestor de archivos", - "openFile": "Abrir {filePath}", - "openInEditor": "Abrir en el editor", - "remove": "Quitar", - "noDiffDataAvailable": "No hay datos de diff disponibles para {filePath}" - }, - "askQuestion": { - "title": "El agente necesita tu elección", - "subtitle": "Responde y luego envía. Puedes omitir en cualquier momento.", - "recommended": "Recomendado", - "other": "Otro", - "otherPlaceholder": "Escribe tu respuesta…", - "singleSelect": "Única", - "multiSelect": "Múltiple", - "skip": "Omitir", - "next": "Siguiente", - "submit": "Enviar", - "submitError": "No se pudo enviar. Inténtalo de nuevo." - }, - "planApproval": { - "title": "El agente tiene un plan: revísalo", - "emptyPlan": "El agente no escribió un plan. Aprueba para empezar a construir o solicita cambios.", - "approve": "Aprobar y construir", - "requestChanges": "Solicitar cambios", - "abandon": "Descartar", - "feedbackPlaceholder": "¿Qué debería cambiar?", - "sendChanges": "Enviar", - "cancel": "Cancelar", - "submitError": "No se pudo enviar. Inténtalo de nuevo." - }, - "feedbackCheckResult": { - "count": "{count, plural, =1 {1 comentario} other {# comentarios}}", - "expand": "Mostrar todos los comentarios", - "collapse": "Contraer", - "errorTitle": "Error al comprobar los comentarios" - }, - "askQuestionResult": { - "title": "Pregunta", - "answeredLabel": "Pregunta y respuesta:", - "awaiting": "Esperando tu respuesta…", - "declined": "Descartaste esto: el agente usó su propio criterio.", - "noSelection": "Sin selección" - }, - "configStale": { - "agentConfigTitle": "Configuración del agente actualizada", - "modelProviderTitle": "Proveedor de modelo actualizado", - "description": "Esta sesión sigue usando su configuración anterior. Vuelve a conectarte para aplicarla (se conserva el historial de la conversación).", - "reconnect": "Reconectar para aplicar", - "reconnecting": "Reconectando…", - "reconnectDisabledDuringTurn": "Disponible cuando termine el turno actual", - "dismiss": "Descartar", - "reconnectFailed": "No se pudo reconectar la sesión", - "applied": "Nueva configuración aplicada" - }, - "piProjectTrust": { - "title": "Este proyecto incluye recursos de pi", - "description": "pi no está cargando los archivos .pi del propio repositorio. Revísalos para decidir.", - "descriptionExecutable": "El repositorio incluye extensiones de pi, que ejecutan código al iniciar. pi no las está cargando. Revísalas antes de decidir.", - "review": "Revisar…", - "dismiss": "Descartar", - "dialogTitle": "¿Confiar en los recursos de pi de este proyecto?", - "dialogDescription": "pi solo carga los archivos .pi del propio repositorio si confías en la carpeta. Confía solo si confías en el contenido de este repositorio.", - "executionWarning": "Las extensiones son código. Al confiar en esta carpeta, el repositorio podrá ejecutarlas al iniciar pi con tus permisos, antes de que envíes ningún mensaje.", - "scopeNote": "La decisión se guarda en el trust.json de pi para esta carpeta, se aplica a todas las carpetas que contiene y también se usa cuando ejecutas pi por tu cuenta en una terminal. Puedes cambiarla en Ajustes → Agentes → Pi.", - "trust": "Confiar en el proyecto", - "decline": "Mantener sin cargar", - "disabledDuringTurn": "Disponible cuando termine el turno actual", - "trustedToast": "Proyecto de confianza: se reconectó para que pi cargue sus recursos", - "declinedToast": "Los recursos del proyecto siguen sin cargarse", - "saveFailed": "No se pudo guardar la decisión de confianza del proyecto", - "grantTitle": "Este proyecto ya es de confianza", - "grantDescription": "pi carga los archivos .pi del propio repositorio. Revisa lo que eso permite.", - "grantInheritedDescription": "Una carpeta superior es de confianza, así que pi carga los archivos .pi del propio repositorio. Revisa lo que eso permite.", - "grantDialogTitle": "Los recursos de pi de este proyecto son de confianza", - "grantDialogDescription": "pi tiene permiso para cargar los archivos .pi del propio repositorio. Versiones anteriores de codeg lo concedían automáticamente al abrir una carpeta, así que puede que nunca te lo preguntaran.", - "grantExecutionWarning": "Las extensiones son código. El repositorio las ejecuta al iniciar pi con tus permisos, antes de que envíes ningún mensaje.", - "inheritedFrom": "Confianza heredada de", - "revoke": "Revocar confianza", - "keepTrusted": "Mantener la confianza", - "revokedToast": "Confianza revocada: se reconectó para que pi deje de cargar los recursos del proyecto", - "trustedNoReconnect": "Proyecto de confianza: se aplicará la próxima vez que se inicie pi", - "revokedNoReconnect": "Confianza revocada: se aplicará la próxima vez que se inicie pi" - }, - "collabAgent": { - "title": "Subagente", - "errorTitle": "La tarea del subagente falló", - "statesLabel": "Subagentes", - "statusRunning": "En ejecución", - "statusCompleted": "Completado", - "statusFailed": "Fallido", - "statusPending": "Iniciando", - "statusInterrupted": "Interrumpido", - "statusClosed": "Cerrado", - "statusNotFound": "No encontrado", - "opSpawn": "Iniciando subagente", - "opWait": "Obteniendo resultado del subagente", - "opClose": "Cerrando subagente", - "opResume": "Reanudando subagente" - }, - "contextCompaction": { - "compacting": "Compactando el contexto…", - "compacted": "Contexto compactado", - "compactedTokens": "Contexto compactado · {before} → {after} tokens", - "failed": "Error al compactar el contexto" - }, - "sessionFailure": { - "category": { - "connection": "Problema de conexión", - "access": "Problema de acceso", - "limit": "Límite alcanzado", - "request": "Solicitud rechazada", - "service": "Problema del servicio", - "unknown": "Problema de sesión" - }, - "action": { - "retry": "Reintentar", - "login": "Iniciar sesión", - "newSession": "Nueva sesión" - }, - "recovered": "Recuperado", - "retryUnavailable": "No hay ningún mensaje anterior para reenviar.", - "toggleDetails": "Mostrar u ocultar detalles" - }, - "backgroundTasks": { - "running": "{count, plural, one {# tarea en segundo plano en ejecución} other {# tareas en segundo plano en ejecución}}", - "settling": "Sincronizando resultados en segundo plano…", - "settledFallback": "Tarea en segundo plano finalizada ({status})", - "cardRunning": "Ejecutándose en segundo plano", - "cardLaunchedPending": "Tarea lanzada en segundo plano", - "cardCompleted": "Tarea en segundo plano completada", - "cardFinishedWithStatus": "Tarea en segundo plano finalizada ({status})", - "cardResultPending": "El resultado aún no ha llegado" - }, - "proposedPlan": { - "title": "Plan propuesto", - "planning": "Planificando…" - } - }, - "diffPreview": { - "mode": { - "added": "Añadido", - "deleted": "Eliminado", - "renamed": "Renombrado", - "modified": "Modificado" - }, - "hunkLabel": "Bloque {index}", - "loadingHunk": "Cargando hunk...", - "noDiffData": "Sin datos de diff", - "showRemainingLines": "Mostrar {count} líneas más" - }, - "conversationContextBar": { - "folderTitle": "Carpeta de trabajo", - "branchTitle": "Rama de trabajo", - "searchFolder": "Search folder...", - "searchBranch": "Search branch...", - "noFolders": "No folders", - "noBranches": "No branches", - "noBranch": "(no branch)", - "chatModeLabel": "Modo de chat", - "commit": "Commit", - "push": "Push", - "merge": "Merge", - "toasts": { - "folderChanged": "Switched to {name}", - "openFolderFailed": "Failed to open folder", - "switchedToChatMode": "Cambiado al modo de chat", - "openStashFailed": "Failed to open stash window", - "openMergeFailed": "Failed to open merge window" - } - }, - "cloneDialog": { - "title": "Clonar repositorio", - "repositoryUrl": "URL del repositorio", - "repositoryUrlPlaceholder": "https://github.com/user/repo.git", - "directory": "Directorio", - "directoryPlaceholder": "Selecciona el directorio de destino...", - "browseDirectory": "Explorar directorio", - "cancel": "Cancelar", - "clone": "Clonar", - "clonePath": "Ruta de clonación: {path}" - }, - "toasts": { - "cloneFailed": "No se pudo clonar el repositorio" - } - }, - "ProjectBoot": { - "title": "Inicio de Proyecto", - "tabs": { - "shadcn": "shadcn", - "hyperframes": "HyperFrames" - }, - "hyperframes": { - "title": "Proyecto de vídeo HyperFrames", - "subtitle": "Genera un proyecto de HTML a vídeo. Luego, el agente del espacio de trabajo puede escribirlo y renderizarlo.", - "resolution": "Resolución", - "skillsTitle": "Skills de agentes", - "skillsDesc": "Instala globalmente las skills de HyperFrames (enlace simbólico) para los agentes seleccionados, para que puedan crear y renderizar vídeo.", - "recheck": "Volver a comprobar", - "installedBadge": "Instalado", - "skillsInstall": "Instalar / actualizar skills", - "skillsInstalling": "Instalando skills…", - "skillsInstalled": "Skills de HyperFrames instaladas", - "skillsInstallFailed": "No se pudieron instalar las skills de HyperFrames" - }, - "config": { - "base": "Base", - "style": "Estilo", - "baseColor": "Color base", - "theme": "Tema", - "chartColor": "Color del gráfico", - "iconLibrary": "Biblioteca de iconos", - "font": "Fuente", - "fontHeading": "Fuente de título", - "menuAccent": "Acento del menú", - "menuColor": "Color del menú", - "radius": "Radio", - "template": "Plantilla", - "createProject": "Crear proyecto", - "sectionStyle": "Estilo", - "sectionColors": "Colores", - "sectionTypography": "Tipografía", - "sectionInterface": "Interfaz" - }, - "preview": { - "loading": "Cargando vista previa..." - }, - "createDialog": { - "title": "Crear proyecto", - "projectName": "Nombre del proyecto", - "projectNamePlaceholder": "my-app", - "frameworkTemplate": "Plantilla del framework", - "packageManager": "Gestor de paquetes", - "saveDirectory": "Directorio de guardado", - "saveDirectoryPlaceholder": "Seleccionar directorio...", - "browseDirectory": "Explorar", - "projectPath": "El proyecto se creará en: {path}", - "advancedOptions": "Opciones Avanzadas", - "base": "Biblioteca Base", - "enableRtl": "Habilitar Soporte RTL", - "enableRtlDescription": "Habilitar soporte de diseño para idiomas de derecha a izquierda (ej. árabe, hebreo)", - "pmChecking": "Verificando...", - "pmNotInstalled": "No instalado", - "cancel": "Cancelar", - "create": "Crear", - "creating": "Creando proyecto..." - }, - "toasts": { - "createFailed": "Error al crear el proyecto", - "createSuccess": "Proyecto creado exitosamente", - "openWorkspaceFailed": "Proyecto creado, pero no se pudo abrir en el espacio de trabajo" - }, - "errors": { - "directoryExists": "El directorio de destino ya existe", - "commandFailed": "El comando de creación del proyecto falló." - } - }, - "WebServiceSettings": { - "addressSwitchHint": "Cambiar solo modifica la dirección que se muestra y se abre aquí; el servicio escucha en todas las interfaces y sigue accesible en cada dirección.", - "sectionTitle": "Servicio Web", - "sectionDescription": "Habilitar para acceder a Codeg de forma remota a través del navegador", - "port": "Puerto", - "status": "Estado", - "autoStart": "Inicio automático", - "autoStartHint": "Iniciar el servicio web al abrir Codeg", - "running": "En ejecución", - "stopped": "Detenido", - "processing": "Procesando...", - "start": "Iniciar", - "stop": "Detener", - "startFailed": "Error al iniciar", - "stopFailed": "Error al detener", - "saveConfigFailed": "No se pudo guardar la configuración del servicio web", - "open": "Abrir", - "hide": "Ocultar", - "show": "Mostrar", - "copy": "Copiar", - "qrcode": "Código QR", - "qrcodeTitle": "Escanear para abrir", - "qrcodeHint": "Escanea con tu teléfono para abrir Codeg en el navegador", - "addressLabel": "Dirección de acceso", - "tokenLabel": "Token de acceso", - "tokenHint": "Ingrese este token al acceder al cliente Web por primera vez", - "tokenPlaceholder": "Dejar vacío para generar automáticamente", - "regenerate": "Regenerar", - "stalePortOccupiedTitle": "El puerto {port} está en uso por otro proceso", - "stalePortUnknownTitle": "Estado del puerto {port} indeterminado", - "stalePortHint": "Codeg no puede vincularse hasta que se libere el puerto. Cambia el puerto arriba o cierra el proceso que lo retiene.", - "errors": { - "alreadyRunning": "El servicio Web ya está en ejecución", - "invalidAddress": "Formato de host o puerto no válido", - "portInUse": "El puerto {port} ya está en uso. Cierre el proceso que lo usa o elija otro puerto.", - "permissionDenied": "Permiso denegado. Utilice un puerto superior a 1024 o ejecute con mayores privilegios.", - "addressUnavailable": "La dirección no está disponible en este equipo", - "bindFailed": "No se pudo enlazar la dirección" - } - }, - "DirectoryBrowser": { - "title": "Explorar directorio", - "pathPlaceholder": "Ingrese la ruta del directorio...", - "goHome": "Ir al directorio principal", - "navigateUp": "Ir al directorio superior", - "select": "Seleccionar", - "cancel": "Cancelar", - "loading": "Cargando...", - "emptyDirectory": "Este directorio está vacío", - "errorLoadingDir": "Error al cargar el directorio", - "permissionDenied": "Permiso denegado" - }, - "ChatChannelSettings": { - "loading": "Cargando...", - "sectionTitle": "Canales de chat", - "sectionDescription": "Configure bots de IM para recibir notificaciones de eventos y consultar actividad de codificación.", - "addChannel": "Agregar canal", - "noChannels": "Aún no se han configurado canales de chat.", - "channelName": "Nombre", - "channelNamePlaceholder": "Mi bot de Telegram", - "channelType": "Tipo de canal", - "lark": "Lark (Feishu)", - "weixin": "WeChat", - "dailyReport": "Informe diario", - "dailyReportTime": "Hora del informe", - "nameRequired": "El nombre del canal es obligatorio.", - "tokenRequired": "El token es obligatorio.", - "chatIdRequired": "El Chat ID es obligatorio.", - "topicMode": "Modo de grupo por temas", - "topicModeHint": "Enruta los temas de foros de Telegram como sesiones Codeg separadas. El bot debe estar en un supergrupo de foro y poder administrar temas.", - "loadFailed": "Error al cargar los canales.", - "saveFailed": "Error al guardar los cambios.", - "connectSuccess": "Canal conectado.", - "connectFailed": "Error al conectar", - "disconnectSuccess": "Canal desconectado.", - "disconnectFailed": "Error al desconectar.", - "testSuccess": "Prueba de conexión exitosa.", - "testFailed": "Prueba de conexión fallida", - "deleteSuccess": "Canal eliminado.", - "deleteFailed": "Error al eliminar el canal.", - "deleteConfirmTitle": "Eliminar canal", - "deleteConfirmMessage": "Se eliminará permanentemente el canal y sus registros de mensajes. ¿Está seguro?", - "cancel": "Cancelar", - "delete": "Eliminar", - "create": "Crear", - "save": "Guardar", - "channelListTitle": "Canales configurados", - "channelListDescription": "Los canales habilitados se conectarán automáticamente al iniciar el servicio.", - "editChannel": "Editar canal", - "editSuccess": "Canal actualizado.", - "tokenPlaceholderKeep": "Dejar vacío para mantener actual", - "weixinScanTitle": "Escanear código QR", - "weixinScanDescription": "Abra WeChat y escanee el código QR para conectarse.", - "weixinQrcodeExpired": "El código QR ha expirado.", - "weixinRefreshQrcode": "Actualizar", - "weixinWaitingScan": "Esperando escaneo...", - "weixinPollError": "Conexión inestable, reintentando...", - "weixinReconnectNotice": "Debido a limitaciones del protocolo iLink, después de cada reconexión debes enviar un mensaje al bot para que los activadores de eventos surtan efecto.", - "connect": "Conectar", - "disconnect": "Desconectar", - "test": "Probar conexión", - "tabs": { - "channels": "Canales", - "commands": "Comandos", - "events": "Eventos", - "other": "Otros" - }, - "commands": { - "title": "Comandos integrados", - "description": "Comandos de bot disponibles en los canales de chat. En chats grupales, se requiere @Bot para procesar mensajes.", - "prefixLabel": "Prefijo de comando", - "prefixDescription": "1-3 caracteres no alfanuméricos para activar comandos del bot (por defecto /).", - "prefixSaved": "Prefijo de comando guardado.", - "prefixSaveFailed": "Error al guardar el prefijo.", - "prefixInvalid": "El prefijo debe ser de 1-3 caracteres no alfanuméricos.", - "save": "Guardar", - "folderDesc": "Seleccionar carpeta de trabajo", - "agentDesc": "Seleccionar agente de IA", - "taskDesc": "Crear sesión y ejecutar tarea", - "sessionsDesc": "Listar sesiones activas en la carpeta", - "resumeDesc": "Conversaciones recientes / reanudar una sesión", - "cancelDesc": "Cancelar tarea actual", - "approveDesc": "Aprobar solicitud de permiso del agente", - "denyDesc": "Denegar solicitud de permiso del agente", - "searchDesc": "Buscar conversaciones por palabra clave", - "todayDesc": "Resumen de actividad de hoy", - "statusDesc": "Estado de conexión del canal", - "helpDesc": "Mostrar ayuda" - }, - "events": { - "title": "Notificaciones de eventos", - "description": "Al habilitar eventos, se enviarán al canal cuando se activen.", - "turnComplete": "Turno completado", - "turnCompleteDesc": "Cuando finaliza un turno del agente", - "error": "Error del agente", - "errorDesc": "Cuando un agente encuentra un error", - "permissionRequest": "Solicitud de permiso", - "permissionRequestDesc": "Cuando un agente solicita permiso para actuar", - "questionRequest": "Pregunta del agente", - "questionRequestDesc": "Cuando un agente te hace una pregunta", - "userPromptSent": "Mensaje del usuario", - "userPromptSentDesc": "Cuando envías un mensaje (el texto del mensaje se incluye en la notificación)", - "saved": "Filtro de eventos actualizado.", - "saveFailed": "Error al guardar el filtro de eventos.", - "loadFailed": "No se pudo cargar la configuración.", - "retry": "Reintentar", - "webhooksTitle": "Webhooks", - "webhooksDescription": "Envía una carga JSON por POST a una o varias URL cuando se activa un evento habilitado. El filtro de eventos anterior también se aplica a los webhooks.", - "webhookUrlPlaceholder": "https://example.com/webhook", - "addWebhook": "Agregar webhook", - "removeWebhook": "Eliminar webhook", - "webhookSave": "Guardar", - "webhooksSaved": "Webhooks guardados.", - "webhooksSaveFailed": "Error al guardar los webhooks.", - "webhookInvalidUrl": "Introduce URL http(s) válidas.", - "docsTitle": "Formato de solicitud", - "docsMethod": "Método", - "docsContentType": "Content-Type", - "docsNote": "Cada evento habilitado se entrega a todas las URL. Los webhooks no tienen antirrebote; el filtro de eventos anterior sigue aplicándose.", - "editWebhook": "Editar webhook", - "enableWebhook": "Activar webhook", - "webhookDuplicate": "Esta URL ya está configurada.", - "cancel": "Cancelar", - "webhooksEmpty": "Aún no hay webhooks configurados.", - "deleteWebhookTitle": "Eliminar webhook", - "deleteWebhookMessage": "¿Eliminar este webhook? Los eventos ya no se enviarán a esta URL.", - "delete": "Eliminar" - }, - "language": { - "title": "Idioma de mensajes", - "description": "Idioma utilizado para las notificaciones de eventos, respuestas de comandos e informes diarios enviados a los canales de chat.", - "saved": "Idioma de mensajes guardado.", - "saveFailed": "Error al guardar el idioma de mensajes.", - "en": "Inglés", - "zh-cn": "Chino simplificado", - "zh-tw": "Chino tradicional", - "ja": "Japonés", - "ko": "Coreano", - "es": "Español", - "de": "Alemán", - "fr": "Francés", - "pt": "Portugués", - "ar": "Árabe" - } - }, - "ModelProviderSettings": { - "sectionTitle": "Proveedores de Modelos", - "sectionDescription": "Gestionar las credenciales de proveedores API para agentes.", - "filterAll": "Todos", - "providerListTitle": "Proveedores Configurados", - "addProvider": "Agregar Proveedor", - "editProvider": "Editar Proveedor", - "noProviders": "Aún no se han configurado proveedores de modelos.", - "providerName": "Nombre", - "providerNamePlaceholder": "Ej. OpenAI, Anthropic", - "apiUrl": "URL de API", - "apiUrlPlaceholder": "https://api.openai.com/v1", - "apiKey": "Clave API", - "apiKeyPlaceholder": "sk-...", - "apiKeyKeepCurrent": "Dejar vacío para mantener actual", - "agentTypes": "Tipos de Agente", - "agentTypesRequired": "Se requiere al menos un tipo de agente.", - "agentType": "Tipo de Agente", - "agentTypeRequired": "El tipo de agente es obligatorio.", - "agentTypeImmutableHint": "El tipo de agente no se puede cambiar después de la creación.", - "model": "Modelo", - "modelPlaceholderCodex": "gpt-5.6-sol / gpt-5.5", - "modelPlaceholderGemini": "gemini-3-pro-preview", - "claudeMainModel": "Modelo Principal", - "claudeReasoningModel": "Modelo de Razonamiento (pensamiento)", - "claudeHaikuDefaultModel": "Modelo Haiku Predeterminado", - "claudeSonnetDefaultModel": "Modelo Sonnet Predeterminado", - "claudeOpusDefaultModel": "Modelo Opus Predeterminado", - "claudeCustomModelOption": "ID de modelo personalizado", - "claudeCustomModelOptionName": "Nombre del modelo personalizado", - "claudeCustomModelOptionDescription": "Descripción del modelo personalizado", - "claudeCustomModelOptionHint": "Añade una única entrada personalizada al selector de modelos de Claude (por ejemplo, un modelo detrás de una pasarela/proxy personalizado). El nombre y la descripción son opcionales y solo afectan a la visualización.", - "nameRequired": "El nombre del proveedor es obligatorio.", - "apiUrlRequired": "La URL de API es obligatoria.", - "apiKeyRequired": "La clave API es obligatoria.", - "loadFailed": "Error al cargar proveedores.", - "saveFailed": "Error al guardar cambios.", - "createSuccess": "Proveedor creado.", - "editSuccess": "Proveedor actualizado.", - "deleteSuccess": "Proveedor eliminado.", - "deleteConfirmTitle": "Eliminar Proveedor", - "deleteConfirmMessage": "Esto eliminará permanentemente el proveedor \"{name}\". ¿Está seguro?", - "deleteBlockedByAgent": "{agents} está usando este proveedor. Desvincúlelo antes de eliminarlo.", - "cancel": "Cancelar", - "delete": "Eliminar", - "create": "Crear", - "save": "Guardar", - "affectedRunningSessions": "{count, plural, one {# sesión activa necesita reconectarse para aplicar el cambio} other {# sesiones activas necesitan reconectarse para aplicar el cambio}}" - }, - "SkillMatrix": { - "loading": "Cargando…", - "searchPlaceholder": "Buscar por nombre, id o descripción", - "empty": "Nada que mostrar.", - "emptySearch": "No hay coincidencias para la búsqueda actual.", - "skillColumn": "Habilidad", - "selectAll": "Seleccionar todo lo visible", - "selectSkill": "Seleccionar {name}", - "everything": { - "label": "En bloque", - "enable": "Activar todo (visible)", - "disable": "Desactivar todo (visible)" - }, - "columnMenu": { - "enableAll": "Activar todas las habilidades", - "disableAll": "Desactivar todas las habilidades" - }, - "rowMenu": { - "label": "Acciones en bloque para {name}", - "enableAll": "Activar para todos los agentes", - "disableAll": "Desactivar para todos los agentes" - }, - "bulk": { - "selected": "{count} seleccionados", - "targetAll": "Todos los agentes", - "targetSome": "{count} agentes", - "enable": "Activar", - "disable": "Desactivar", - "clear": "Limpiar" - }, - "confirm": { - "disableTitle": "¿Desactivar estos enlaces?", - "disableBody": "Esto eliminará {count} enlaces de habilidades gestionados por codeg. Las habilidades que ocupan un directorio personalizado no se modifican. Puedes reactivarlas cuando quieras.", - "cancel": "Cancelar", - "confirm": "Desactivar" - }, - "toasts": { - "loadFailed": "No se pudieron cargar los estados de las habilidades", - "applyFailed": "No se pudieron aplicar los cambios", - "enabled": "{count} enlaces activados", - "disabled": "{count} enlaces desactivados", - "enabledPartial": "{ok} activados, {failed} fallidos", - "disabledPartial": "{ok} desactivados, {failed} fallidos" - }, - "detail": { - "enableForAgents": "Activar para agentes", - "preview": "Vista previa de SKILL.md", - "loadingContent": "Cargando contenido…" - }, - "copyModeHint": "Copiado (no enlazado): vuelve a activarlo tras las actualizaciones para la última versión" - }, - "ExpertsSettings": { - "title": "Habilidades de expertos", - "description": "Habilita flujos de trabajo de habilidades cuidadosamente seleccionadas y probadas en la práctica para tus agentes de codificación de IA. Cada experto es una habilidad independiente del proyecto superpowers — codeg gestiona la copia central y la vincula a los agentes que elijas.", - "loading": "Cargando expertos…", - "loadingContent": "Cargando contenido…", - "emptyExperts": "No hay expertos disponibles. Revisa los registros de la aplicación.", - "emptySelection": "Selecciona un experto para ver su contenido y gestionar la activación.", - "emptySearch": "Ningún experto coincide con la búsqueda actual.", - "searchPlaceholder": "Buscar expertos por nombre, ID o descripción", - "enableForAgents": "Habilitar para agentes", - "noAgents": "No se detectaron agentes ACP.", - "copyModeWarning": "Copiado (no vinculado). Vuelve a habilitarlo después de actualizar codeg para obtener la última versión.", - "previewTitle": "Vista previa de SKILL.md", - "categories": { - "discovery": "Descubrimiento y diseño", - "planning": "Planificación", - "execution": "Ejecución", - "quality": "Calidad y pruebas", - "debugging": "Depuración", - "review": "Revisión e integración", - "meta": "Meta" - }, - "states": { - "not_linked": "No habilitado", - "linked_to_codeg": "Habilitado", - "linked_elsewhere": "Bloqueado — existe otro vínculo", - "blocked_by_real_directory": "Bloqueado — una habilidad personalizada ocupa este nombre", - "broken": "Vínculo roto" - }, - "badges": { - "userModified": "Modificado por el usuario" - }, - "actions": { - "openCentralDir": "Abrir carpeta central", - "refresh": "Actualizar" - }, - "toasts": { - "loadFailed": "Error al cargar los detalles del experto", - "enabled": "Experto habilitado para este agente", - "disabled": "Experto deshabilitado para este agente", - "enableFailed": "Error al habilitar el experto", - "disableFailed": "Error al deshabilitar el experto", - "openFolderFailed": "Error al abrir la carpeta" - } - }, - "ScienceSettings": { - "title": "Habilidades de investigación científica", - "description": "Habilita habilidades de investigación científica seleccionadas para tus agentes de código con IA: generación de hipótesis, diseño experimental, estadística, visualización, evaluación crítica y búsqueda bibliográfica. codeg gestiona una copia central y enlaza cada habilidad a los agentes que elijas.", - "loading": "Cargando habilidades científicas…", - "emptySkills": "No hay habilidades científicas disponibles. Revisa los registros de la aplicación.", - "searchPlaceholder": "Buscar habilidades científicas por nombre, id o descripción", - "categories": { - "ideation": "Ideación", - "design": "Diseño de estudios", - "analysis": "Análisis", - "visualization": "Visualización", - "evaluation": "Evaluación", - "literature": "Literatura" - }, - "states": { - "not_linked": "No habilitado", - "linked_to_codeg": "Habilitado", - "linked_elsewhere": "Bloqueado — existe otro vínculo", - "blocked_by_real_directory": "Bloqueado — una habilidad personalizada ocupa este nombre", - "broken": "Vínculo roto" - }, - "badges": { - "userModified": "Modificado por el usuario", - "needsKey": "Requiere clave", - "needsSetup": "Puede requerir configuración" - }, - "actions": { - "openCentralDir": "Abrir carpeta central", - "refresh": "Actualizar" - }, - "toasts": { - "openFolderFailed": "Error al abrir la carpeta" - } - }, - "OfficeToolsSettings": { - "title": "Herramientas Office", - "description": "Gestiona las habilidades de OfficeCLI para crear archivos Excel, Word y PowerPoint. Instala OfficeCLI, sincroniza habilidades y actívalas por agente.", - "loadingContent": "Cargando contenido…", - "emptySkills": "No hay habilidades disponibles. Instala OfficeCLI y sincroniza las habilidades.", - "emptySelection": "Selecciona una habilidad para ver su contenido y gestionar la activación.", - "emptySearch": "No se encontraron habilidades.", - "searchPlaceholder": "Buscar habilidades por nombre, ID o descripción", - "enableForAgents": "Activar para agentes", - "noAgents": "No se detectaron agentes ACP.", - "installFirst": "Instala OfficeCLI primero para activar habilidades.", - "syncFirst": "Sincroniza las habilidades primero para cargar el contenido.", - "noContent": "Sin contenido disponible.", - "copyModeWarning": "Copiado (no vinculado). Vuelve a sincronizar para obtener la última versión.", - "previewTitle": "Vista previa de SKILL.md", - "detection": { - "installed": "Instalado", - "notInstalled": "No instalado", - "notRunnable": "Instalado pero no ejecutable", - "installHint": "Instala OfficeCLI para habilitar las habilidades de generación de documentos de oficina en tus agentes de IA.", - "install": "Instalar", - "uninstall": "Desinstalar", - "syncSkills": "Sincronizar habilidades" - }, - "categories": { - "general": "General", - "presentations": "Presentaciones", - "documents": "Documentos", - "spreadsheets": "Hojas de cálculo" - }, - "states": { - "not_linked": "No activado", - "linked_to_codeg": "Activado", - "linked_elsewhere": "Bloqueado — existe otro enlace", - "blocked_by_real_directory": "Bloqueado — una habilidad personalizada ocupa este nombre", - "broken": "Enlace roto" - }, - "badges": { - "notSynced": "No sincronizado" - }, - "actions": { - "refresh": "Actualizar" - }, - "toasts": { - "loadFailed": "Error al cargar los detalles de la habilidad", - "enabled": "Habilidad activada para este agente", - "disabled": "Habilidad desactivada para este agente", - "enableFailed": "Error al activar la habilidad", - "disableFailed": "Error al desactivar la habilidad", - "installSuccess": "OfficeCLI instalado correctamente", - "installFailed": "Error al instalar OfficeCLI", - "uninstallSuccess": "OfficeCLI desinstalado", - "uninstallFailed": "Error al desinstalar OfficeCLI", - "syncSuccess": "{synced} habilidades sincronizadas", - "syncPartial": "{synced} sincronizadas, {errors} fallidas", - "syncFailed": "Error al sincronizar habilidades" - }, - "autoPreviewLabel": "Abrir vista previa automáticamente", - "autoPreviewHint": "Cuando un agente crea o edita un archivo de Word, Excel o PowerPoint, abre su vista previa en vivo automáticamente." - }, - "SkillPacksSettings": { - "title": "Paquetes de habilidades", - "description": "Paquetes de habilidades seleccionados que codeg gestiona de forma centralizada y vincula a tus agentes de IA: expertos en programación, investigación científica y herramientas de documentos de oficina. Actívalos por agente abajo.", - "tabs": { - "experts": "Expertos", - "science": "Ciencia", - "office": "Herramientas de oficina", - "custom": "Personalizadas" - }, - "actions": { - "openCentralDir": "Abrir carpeta central", - "refresh": "Actualizar" - }, - "toasts": { - "openFolderFailed": "Error al abrir la carpeta" - } - }, - "QuickMessagesSettings": { - "title": "Mensajes rápidos", - "description": "Gestiona fragmentos de mensajes reutilizables. Arrastra para reordenar.", - "loading": "Cargando mensajes rápidos…", - "emptyList": "Aún no hay mensajes rápidos. Haz clic en \"Nuevo\" para crear uno.", - "emptySelection": "Selecciona un mensaje rápido para editar.", - "searchPlaceholder": "Buscar por título o contenido", - "untitled": "Sin título", - "actions": { - "new": "Nuevo", - "save": "Guardar", - "delete": "Eliminar", - "dragSort": "Arrastra para reordenar", - "dragSortMessage": "Arrastra para reordenar mensaje rápido: {name}" - }, - "fields": { - "title": "Título", - "titlePlaceholder": "Asigna un título corto a este mensaje", - "content": "Contenido", - "contentPlaceholder": "Escribe aquí el contenido del mensaje" - }, - "confirmDelete": { - "title": "¿Eliminar mensaje rápido?", - "message": "Esto eliminará permanentemente \"{name}\". ¿Estás seguro?", - "cancel": "Cancelar", - "confirm": "Eliminar" - }, - "toasts": { - "loadFailed": "Error al cargar mensajes rápidos", - "createFailed": "Error al crear el mensaje rápido", - "saveFailed": "Error al guardar el mensaje rápido", - "deleteFailed": "Error al eliminar el mensaje rápido", - "saveOrderFailed": "Error al guardar el orden", - "created": "Mensaje rápido creado", - "saved": "Mensaje rápido guardado", - "deleted": "Mensaje rápido eliminado" - } - }, - "Pet": { - "badge": { - "running": "{count} en ejecución", - "waiting": "{count} esperando aprobación", - "error": "{count} con error" - }, - "panel": { - "title": "Sesiones activas", - "empty": "No hay sesiones activas", - "emptyHint": "Aquí aparecen los agentes en ejecución y los que te necesitan.", - "statusRunning": "En ejecución", - "statusWaiting": "En espera", - "statusError": "Error", - "subAgentOf": "Subagente de" - }, - "menu": { - "scale": "Escala", - "openManager": "Gestionar mascotas", - "close": "Cerrar" - }, - "loadError": "No se pudo cargar la mascota", - "missingPetIdParam": "No hay mascota seleccionada", - "summonButton": "Mascota", - "manager": { - "title": "Mascotas", - "description": "Compañeros flotantes de escritorio con sprites compatibles con Codex.", - "addPet": "Añadir mascota", - "importFromCodex": "Importar desde Codex", - "noPets": "No hay mascotas. Añade una o impórtala desde Codex.", - "setActive": "Activar", - "active": "Activa", - "edit": "Editar", - "delete": "Eliminar", - "deleteConfirm": "¿Eliminar la mascota «{name}»? Se borrará del disco.", - "summon": "Invocar ventana de la mascota", - "openCodexHelp": "Las mascotas de Codex deben estar en ~/.codex/pets/. No se encontraron.", - "specRequirement": "El sprite debe tener 1536px de ancho y una altura múltiplo de 208px (p. ej. 1872 o 2288), en PNG o WebP con transparencia.", - "form": { - "id": "ID de mascota", - "idHelp": "Letras minúsculas, dígitos, '-' y '_'. Máx 64 chars.", - "displayName": "Nombre", - "description": "Descripción (opcional)", - "spritesheet": "Sprite", - "chooseFile": "Elegir archivo", - "replaceFile": "Reemplazar sprite", - "saveCreate": "Añadir mascota", - "saveUpdate": "Guardar cambios", - "cancel": "Cancelar" - }, - "errors": { - "missingId": "Se requiere ID de mascota", - "missingName": "Se requiere nombre", - "missingSpritesheet": "Se requiere sprite", - "addFailed": "Error al añadir la mascota", - "updateFailed": "Error al actualizar", - "deleteFailed": "Error al eliminar", - "loadFailed": "Error al cargar mascotas", - "setActiveFailed": "Error al activar mascota", - "summonFailed": "Error al invocar la ventana de mascota" - } - }, - "import": { - "title": "Importar desde Codex", - "subtitle": "Mascotas disponibles bajo ~/.codex/pets/.", - "selectAll": "Seleccionar todo", - "alreadyImported": "Ya importada", - "renameOnConflict": "Renombrar conflictos con sufijo -imported", - "import": "Importar selección", - "noneFound": "No hay mascotas Codex importables.", - "imported": "Importación correcta", - "failed": "Importación fallida", - "close": "Cerrar" - }, - "marketplace": { - "openMarketplace": "Mercado de mascotas", - "title": "Mercado de mascotas", - "search": "Buscar mascotas", - "kindFilter": { - "all": "Todas", - "object": "Objeto", - "animal": "Animal", - "person": "Persona", - "creature": "Criatura" - }, - "sortFilter": { - "latest": "Recientes", - "popular": "Populares", - "views": "Más vistas" - }, - "refresh": "Actualizar", - "install": "Instalar", - "installing": "Instalando", - "reinstall": "Reinstalar", - "reinstallConfirm": "¿Sobrescribir la mascota local \"{name}\"? Los datos existentes serán reemplazados.", - "cancel": "Cancelar", - "stats": { - "views": "Vistas", - "downloads": "Descargas", - "likes": "Me gusta" - }, - "actions": { - "idle": "Reposo", - "running_right": "Corre der.", - "running_left": "Corre izq.", - "waving": "Saluda", - "jumping": "Salta", - "failed": "Fallo", - "waiting": "Espera", - "running": "Corre", - "review": "Revisa" - }, - "page": "Página {page} de {total}", - "prev": "Anterior", - "next": "Siguiente", - "empty": "No hay mascotas que coincidan.", - "successInstalled": "\"{name}\" instalada", - "errors": { - "loadFailed": "No se pudo cargar el mercado", - "installFailed": "No se pudo instalar la mascota", - "alreadyInstalled": "La mascota ya existe localmente" - } - } - }, - "RemoteWorkspace": { - "openRemoteWorkspace": "Open remote workspace", - "manage": "Manage remote workspace", - "manageTitle": "Remote Workspace connections", - "empty": "No remote connections", - "searchPlaceholder": "Search remote workspaces", - "orderFailed": "Failed to save remote workspace order", - "dragSort": "Drag to sort", - "dragSortConnection": "Drag to sort {name}", - "newConnection": "New connection", - "loading": "Loading", - "loadingConnection": "Loading remote connection", - "name": "Name", - "baseUrl": "Service URL", - "token": "Access token", - "save": "Save", - "delete": "Delete", - "confirmDelete": { - "title": "Delete remote connection?", - "message": "This will remove \"{name}\" from this device. This action cannot be undone.", - "cancel": "Cancel", - "confirm": "Delete" - }, - "saved": "Remote connection saved.", - "deleted": "Remote connection deleted.", - "loadFailed": "Failed to load remote connections", - "saveFailed": "Failed to save remote connection", - "deleteFailed": "Failed to delete remote connection", - "openFailed": "Failed to open remote workspace", - "connectionLoadFailed": "Failed to load remote connection: {message}", - "connectionExpired": "Remote connection \"{name}\" is expired. Update its token and reload this window." - }, - "ServerFileBrowser": { - "title": "Seleccionar archivo del servidor", - "pathPlaceholder": "Introducir ruta de directorio...", - "goHome": "Ir al directorio personal", - "navigateUp": "Ir al directorio superior", - "select": "Seleccionar", - "cancel": "Cancelar", - "loading": "Cargando...", - "emptyDirectory": "Este directorio está vacío", - "errorLoadingDir": "Error al cargar el directorio", - "selectedCount": "{count} seleccionado(s)" - }, - "BackupSettings": { - "title": "Copia de seguridad y restauración", - "description": "Exporta una copia de seguridad portátil de tus datos de codeg, o restaura desde una.", - "tabs": { - "backup": "Copia de seguridad", - "restore": "Restaurar" - }, - "export": { - "includeExternal": "Incluir el contenido de las conversaciones", - "includeExternalHint": "También archiva las transcripciones de las CLI (Claude, Codex, Gemini, …). Aumenta el tamaño.", - "passphrase": "Frase de contraseña (opcional)", - "passphrasePlaceholder": "Déjala vacía para un archivo sin cifrar", - "passphraseConfirm": "Confirmar la frase de contraseña", - "passphraseMismatch": "Las frases de contraseña no coinciden.", - "noPassphraseWarning": "Esta copia contendrá secretos (claves de API, tokens) en texto plano. Guárdala en un lugar seguro.", - "passphraseLossWarning": "Cifrada con esta frase de contraseña. Si la pierdes, la copia no se podrá recuperar.", - "button": "Exportar copia", - "inProgress": "Creando copia de seguridad…", - "success": "Copia de seguridad creada.", - "started": "Descarga de la copia iniciada." - }, - "restore": { - "selectFile": "Seleccionar archivo de copia", - "passphrasePrompt": "Esta copia está cifrada. Introduce su frase de contraseña.", - "unlock": "Desbloquear", - "preview": { - "title": "Detalles de la copia", - "encrypted": "Cifrada", - "compatible": "Compatible", - "incompatible": "Incompatible", - "createdAt": "Creada: {value}", - "appVersion": "Versión de la app: {value}", - "incompatibleHint": "Esta copia fue creada por una versión más reciente de codeg y no se puede restaurar." - }, - "replaceWarning": "Restaurar reemplaza todos los datos actuales de codeg (base de datos y subidas). Tus datos actuales se guardan primero en una instantánea para poder recuperarlos.", - "keyringNote": "Los tokens de GitHub/chat del escritorio están en el llavero del sistema y no se incluyen; vuelve a introducirlos tras restaurar.", - "button": "Restaurar", - "staging": "Preparando la restauración…", - "staged": "Restauración preparada. Reiniciando…", - "restarting": "Restauración preparada. Reiniciando el servidor…", - "restartTimeout": "El servidor no volvió a tiempo. Recarga la página cuando esté activo.", - "externalSideLocation": "Las transcripciones de conversaciones se restauraron en {path}", - "confirmTitle": "¿Reemplazar todos los datos?", - "confirmBody": "Esto reemplazará tu base de datos y subidas actuales de codeg con la copia y luego reiniciará. Tus datos actuales se guardan primero en una instantánea.", - "cancel": "Cancelar", - "confirmAction": "Reemplazar y reiniciar", - "external": { - "title": "Contenido de las conversaciones", - "hint": "Esta copia incluye transcripciones de las CLI. Elige dónde restaurarlas.", - "modeSkip": "No restaurar", - "modeSide": "Restaurar en una carpeta aparte segura", - "modeOriginal": "Restaurar en las ubicaciones originales de las CLI", - "forceOverwrite": "Sobrescribir archivos existentes", - "forceOverwriteHint": "Reemplaza los archivos que ya existen en las carpetas de las CLI.", - "scanning": "Comprobando conflictos…", - "noConflicts": "No se sobrescribirá ningún archivo existente.", - "conflictCount": "Se verían afectados {count} archivo(s) existente(s).", - "conflictSkipNote": "Los archivos existentes se conservan (se omiten) salvo que actives la sobrescritura." - }, - "restartFailed": "La restauración quedó preparada, pero el servidor no pudo reiniciarse. Reinícialo manualmente para aplicarla." - }, - "remoteUnsupported": "La copia de seguridad y la restauración actúan sobre los datos de la máquina que ejecuta codeg. Estás conectado a un espacio de trabajo remoto: gestiona sus copias desde ese servidor directamente." - }, - "backup": { - "restore": { - "error": { - "badPassphrase": "Frase de contraseña incorrecta o copia dañada.", - "corrupted": "El archivo de copia de seguridad está dañado.", - "unknownFormat": "Este archivo no es una copia de seguridad de codeg reconocida.", - "newerVersion": "Esta copia fue creada por codeg {backupVersion}, más reciente que esta versión ({appVersion}).", - "alreadyPending": "Ya hay una restauración preparada. Reinicia para aplicarla antes de preparar otra." - } - }, - "error": { - "diskSpace": "No hay espacio en disco suficiente para completar la operación.", - "cancelled": "La operación fue cancelada." - } - }, - "WebConnection": { - "disconnectedTitle": "Conexión perdida", - "reconnectingDescription": "Intentando volver a conectar con el servidor. Normalmente se recupera solo en unos segundos.", - "reconnectNow": "Volver a conectar ahora", - "sessionExpiredTitle": "Sesión caducada", - "sessionExpiredDescription": "Tu sesión ya no es válida. Inicia sesión de nuevo para continuar.", - "goToLogin": "Ir al inicio de sesión" - }, - "LiveFeedback": { - "placeholder": "Envía una nota a {agent} mientras trabaja…", - "agentFallback": "el agente", - "ariaLabel": "Nota de comentarios en vivo", - "dialogTitle": "Comentarios en vivo", - "dialogDescription": "Envía una nota al agente mientras trabaja. La leerá en su próxima comprobación, sin interrumpir el paso actual.", - "dialogDescriptionInstant": "Envía una nota al agente mientras trabaja. Se inserta de inmediato en el turno actual: el agente la ve al instante.", - "channelDowngraded": "La inserción instantánea no está disponible en esta sesión: tu nota quedó guardada para que el agente la recoja en su próxima consulta.", - "send": "Enviar", - "cancel": "Cancelar", - "pending": "esperando", - "delivered": "recibida", - "turnEndedUnread": "El agente terminó antes de leer tus comentarios.", - "sendAsMessage": "Enviar como mensaje", - "dismiss": "Descartar", - "turnEndedResent": "El turno terminó: se envió como un mensaje nuevo.", - "turnEnded": "El turno ya terminó.", - "submitFailed": "No se pudo enviar tu nota" - }, - "AgentToolsSettings": { - "title": "Herramientas en la conversación", - "description": "Herramientas adicionales que codeg entrega a un agente dentro de una conversación. Se inyectan al iniciar el agente, así que los cambios se aplican a los agentes iniciados después.", - "feedbackLabel": "Comentarios en vivo", - "feedbackHint": "Envía notas y correcciones a un agente mientras trabaja. Si el agente admite la inserción instantánea, tu nota se inserta de inmediato en el turno en curso; de lo contrario, el agente recibe una herramienta para consultar tus comentarios — esos agentes suelen consultarla solo si lo mencionas en tu prompt, por ejemplo añade \"revisa mi feedback en vivo con regularidad\" a tu mensaje.", - "questionLabel": "Preguntar al usuario", - "questionHint": "Permite que los agentes se detengan y te hagan una pregunta de opción múltiple que aparece encima del cuadro de entrada de la conversación. El agente espera hasta que respondas (u omitas).", - "sessionInfoLabel": "Obtener información de sesión", - "sessionInfoHint": "Permite que los agentes consulten una sesión que mencionas en tu mensaje (una insignia de sesión) para leer su título, agente, estado, espacio de trabajo, uso de tokens y mensajes recientes.", - "automationsLabel": "Crear automatizaciones", - "automationsHint": "Guarda la conversación como una automatización que se ejecuta según un horario. Desactivado por defecto: luego inicia agentes por su cuenta.", - "workTasksLabel": "Crear tareas pendientes", - "workTasksHint": "Añade una tarjeta al tablero de pendientes desde la conversación. Desactivado por defecto: escribe estado de la aplicación.", - "save": "Guardar", - "saving": "Guardando…", - "saved": "Ajustes de herramientas guardados", - "saveFailed": "No se pudieron guardar los ajustes de herramientas", - "loadFailed": "Error al cargar: {detail}" - }, - "NotificationSoundSettings": { - "title": "Sonidos de notificación", - "description": "Reproduce un sonido breve cuando se produce un evento del agente. Son los mismos eventos que se envían a los canales de chat; esta configuración solo se aplica a este dispositivo.", - "enableHint": "Desactivado por defecto. Los sonidos solo suenan en la ventana del espacio de trabajo de este navegador o aplicación.", - "volume": "Volumen", - "preview": "Escuchar", - "previewEvent": "Escuchar el sonido de {event}", - "onlyWhenUnfocused": "Solo cuando la ventana no está enfocada", - "onlyWhenUnfocusedHint": "Permanece en silencio mientras estás mirando Codeg.", - "eventsTitle": "Eventos", - "eventsHint": "Elige un tono para cada evento o «Silencio» para omitirlo. Si el mismo evento se repite en pocos segundos, solo suena una vez.", - "toneNone": "Silencio", - "toneChime": "Campanilla", - "toneDing": "Timbre", - "toneBlip": "Pitido", - "tonePop": "Pop", - "toneAlert": "Alerta", - "toneDescend": "Descendente" - }, - "LogsSettings": { - "loading": "Cargando…", - "sectionTitle": "Registros de ejecución", - "sectionDescription": "Visualiza y configura los registros de diagnóstico de la aplicación. Los registros se escriben en archivos locales y se mantienen en memoria para la vista en vivo.", - "captureTitle": "Nivel de registro", - "captureDescription": "Controla cuánto detalle se captura. Los niveles más altos (Debug, Trace) registran más, pero generan registros más grandes. «Desactivado» deshabilita el registro.", - "captureLabel": "Nivel de captura", - "levels": { - "off": "Desactivado", - "error": "Error", - "warn": "Advertencia", - "info": "Información", - "debug": "Depuración", - "trace": "Rastreo" - }, - "viewerTitle": "Registros recientes", - "viewerDescription": "Vista en vivo de los registros recientes. Filtra por nivel o busca texto.", - "searchPlaceholder": "Buscar mensaje u origen…", - "viewLevels": { - "all": "Todos los niveles", - "error": "Error y superior", - "warn": "Advertencia y superior", - "info": "Información y superior", - "debug": "Depuración y superior", - "trace": "Rastreo y superior" - }, - "pause": "Pausar", - "resume": "En vivo", - "refresh": "Actualizar", - "clear": "Limpiar", - "openFolder": "Abrir carpeta", - "shownCount": "{shown} / {total} mostrados", - "empty": "No hay registros para mostrar.", - "levelSaveFailed": "No se pudo guardar el nivel de registro", - "openFolderFailed": "No se pudo abrir la carpeta de registros", - "downloadFailed": "No se pudo descargar el archivo de registro", - "filesTitle": "Archivos de registro", - "filesDescription": "Descarga archivos de registro completos del disco para ver el historial más allá del búfer en vivo.", - "filesEmpty": "Aún no hay archivos de registro.", - "download": "Descargar", - "downloadTruncated": "El archivo es grande; se descargaron los {size} más recientes. El archivo completo está en el directorio de registros.", - "captureEnvLocked": "El nivel de registro está controlado por la variable de entorno RUST_LOG / CODEG_LOG; cámbialo ahí para que surta efecto.", - "targetsTitle": "Anulaciones por módulo", - "targetsDescription": "Establece un nivel distinto para módulos específicos (p. ej. codeg_lib::acp) sin cambiar el nivel global.", - "targetsAdd": "Añadir", - "targetsRemove": "Quitar anulación", - "toggleDetails": "Mostrar detalles" - }, - "Automations": { - "title": "Automatizaciones", - "new": "Nueva automatización", - "empty": "Aún no hay automatizaciones", - "emptyHint": "Crea una para ejecutar una tarea del agente de forma programada o manual.", - "name": "Nombre", - "namePlaceholder": "p. ej. Revisión nocturna de PR", - "prompt": "Instrucción", - "promptPlaceholder": "¿Qué debe hacer el agente?", - "agent": "Agente", - "folder": "Carpeta del espacio de trabajo", - "folderPlaceholder": "Selecciona una carpeta", - "isolation": "Aislamiento", - "isolationWorktree": "Nuevo worktree por ejecución", - "isolationShared": "Ejecutar en la carpeta", - "isolationSharedCaveat": "Las ejecuciones usan directamente el árbol de trabajo de esta carpeta y pueden entrar en conflicto con tus cambios sin confirmar. Activa la opción de árbol de trabajo para aislar cada ejecución.", - "trigger": "Activador", - "triggerSchedule": "Programado", - "triggerManual": "Solo manual", - "cron": "Programación (cron)", - "cronPlaceholder": "0 9 * * 1-5", - "timezone": "Zona horaria", - "nextRun": "Próxima ejecución", - "branch": "Rama", - "branchOptional": "Rama (opcional)", - "enabled": "Activado", - "save": "Guardar", - "cancel": "Cancelar", - "edit": "Editar", - "delete": "Eliminar", - "runNow": "Ejecutar ahora", - "cancelRun": "Cancelar ejecución", - "runHistory": "Historial de ejecuciones", - "noRuns": "Aún no hay ejecuciones", - "allFolders": "Todas las carpetas", - "filterAll": "Todos", - "noMatches": "No hay automatizaciones que coincidan", - "viewConversation": "Ver conversación", - "lastRun": "Última ejecución", - "never": "Nunca", - "running": "En ejecución", - "deleteTitle": "¿Eliminar la automatización?", - "deleteDescription": "Esto elimina la automatización y su programación. Se conserva el historial.", - "statusRunning": "En ejecución", - "statusSucceeded": "Correcta", - "statusFailed": "Fallida", - "statusCancelled": "Cancelada", - "statusSkipped": "Omitida", - "errorName": "El nombre es obligatorio", - "errorPrompt": "La instrucción es obligatoria", - "errorCron": "Las automatizaciones programadas requieren una expresión cron", - "errorFolder": "Selecciona una carpeta del espacio de trabajo", - "presetHourly": "Cada hora", - "presetDaily": "Diario 9:00", - "presetWeekdays": "Días laborables 9:00", - "presetCustom": "Personalizado", - "probing": "Cargando opciones…", - "retry": "Reintentar", - "configNone": "Este agente no tiene opciones configurables", - "inherit": "Predeterminado del agente", - "mode": "Modo", - "config": "Configuración", - "branchPlaceholder": "(rama predeterminada)", - "selectHint": "Selecciona una automatización para ver los detalles", - "refresh": "Actualizar", - "onboardTitle": "Automatiza tareas rutinarias del agente", - "onboardHint": "Programa un agente para revisar código, actualizar dependencias o clasificar incidencias, de forma periódica o bajo demanda.", - "headerSubtitle": "Tareas del agente programadas y bajo demanda", - "startFromTemplate": "Empezar con una plantilla", - "blankTitle": "Automatización en blanco", - "blankDesc": "Configura una tarea del agente desde cero.", - "backToTemplates": "Plantillas", - "sectionSchedule": "Programación y destino", - "sectionTarget": "Destino", - "sectionAction": "Acción", - "actionLaunchSession": "Ejecutar sesión", - "actionEnqueueTask": "Encolar tarea", - "actionEnqueueTaskHint": "Cada disparo añade una tarea pendiente, titulada como esta automatización, a las tareas pendientes de la carpeta; el motor de tareas la ejecuta según la configuración del tablero.", - "sectionPrompt": "Prompt", - "nextIn": "Próxima en {rel}", - "manual": "Manual", - "schedEveryMinutes": "Cada {n} minutos", - "schedHourly": "Cada hora", - "schedDaily": "Cada día a las {time}", - "schedWeekdays": "Días laborables a las {time}", - "schedWeekly": "Cada {day} a las {time}", - "schedMonthly": "Cada mes el día {day} a las {time}", - "dow0": "domingo", - "dow1": "lunes", - "dow2": "martes", - "dow3": "miércoles", - "dow4": "jueves", - "dow5": "viernes", - "dow6": "sábado", - "tplCodeReviewTitle": "Revisión de código", - "tplCodeReviewDesc": "Revisa los cambios recientes en busca de errores, regresiones y problemas de calidad.", - "tplDependencyUpdatesTitle": "Actualización de dependencias", - "tplDependencyUpdatesDesc": "Encuentra dependencias desactualizadas y propón actualizaciones seguras.", - "tplTestCoverageTitle": "Cobertura de pruebas", - "tplTestCoverageDesc": "Encuentra rutas de código sin probar y añade las pruebas que faltan.", - "tplTodoSweepTitle": "Revisión de TODO", - "tplTodoSweepDesc": "Recopila los comentarios TODO y FIXME y clasifícalos por prioridad.", - "tplCiTriageTitle": "Clasificación de CI", - "tplCiTriageDesc": "Investiga las comprobaciones fallidas recientes y propón soluciones.", - "tplReleaseNotesTitle": "Notas de la versión", - "tplReleaseNotesDesc": "Resume los cambios desde la última versión en un registro de cambios.", - "tplSecurityAuditTitle": "Auditoría de seguridad", - "tplSecurityAuditDesc": "Busca vulnerabilidades y patrones de riesgo, y reporta los hallazgos.", - "enable": "Activar", - "disable": "Desactivar", - "moreActions": "Más acciones", - "statusDisabled": "Desactivada", - "cronBuilderTitle": "Generador de programación", - "cronFreqLabel": "Frecuencia", - "cronFreqMinutes": "Cada N minutos", - "cronFreqHourly": "Cada hora", - "cronFreqDaily": "Diario", - "cronFreqWeekdays": "Días laborables", - "cronFreqWeekly": "Semanal", - "cronFreqMonthly": "Mensual", - "cronFreqCustom": "Personalizado", - "cronEveryLabel": "Intervalo (minutos)", - "cronTimeLabel": "Hora", - "cronHourLabel": "Hora", - "cronMinuteLabel": "Minuto", - "cronDowLabel": "Día de la semana", - "cronDomLabel": "Día del mes", - "cronApply": "Aplicar", - "cronPreviewLabel": "Vista previa", - "cronOpenBuilder": "Abrir el generador de programación", - "branchDefault": "Rama predeterminada", - "branchUseCustom": "Usar «{query}»", - "branchLocal": "Local", - "branchRemote": "Remota", - "branchSearchPlaceholder": "Buscar ramas…", - "branchNone": "Sin ramas" - }, - "Tasks": { - "title": "Tareas pendientes", - "new": "Nueva tarea", - "empty": "Aún no hay tareas", - "emptyHint": "Añade un pendiente y ejecútalo: el agente trabaja en un worktree aislado y tú revisas y fusionas el resultado.", - "emptyColTodo": "Aún no hay pendientes", - "emptyColInProgress": "Nada en curso", - "emptyColAttention": "Nada requiere tu acción", - "emptyColDone": "Aún no hay completadas", - "allFolders": "Todas las carpetas", - "showCanceled": "Mostrar canceladas", - "showArchived": "Mostrar archivadas", - "filter": "Filtrar", - "viewSwitchToBoard": "Cambiar a vista de tablero", - "viewSwitchToList": "Cambiar a vista de lista", - "statusFilter": "Estado", - "statusFilterAll": "Todos los estados", - "listEmpty": "Ninguna tarea coincide con los filtros actuales", - "listColStatus": "Estado", - "listColTask": "Tarea", - "listColLocation": "Ubicación", - "listColChanges": "Cambios", - "listColUpdated": "Actualizado", - "colTodo": "Pendientes", - "colInProgress": "En curso", - "colAttention": "Requiere tu acción", - "colDone": "Completadas", - "statusTodo": "Pendiente", - "statusQueued": "En cola", - "statusPreparing": "Preparando", - "statusRunning": "En ejecución", - "statusAwaitingInput": "Esperando entrada", - "statusReview": "Por revisar", - "statusMerging": "Fusionando", - "statusDone": "Completada", - "statusFailed": "Fallida", - "statusCanceled": "Cancelada", - "statusInterrupted": "Interrumpida", - "badgeCleanupFailed": "Limpieza fallida", - "badgeWorktreeKept": "Worktree conservado", - "badgeWorktreeRemoved": "Worktree eliminado", - "filesChanged": "{count} archivos", - "actionStart": "Iniciar", - "actionSchedule": "Programar", - "actionCancel": "Cancelar", - "actionRetry": "Reintentar", - "actionRequeue": "Reencolar", - "actionViewSession": "Ver conversación", - "actionEdit": "Editar", - "actionDelete": "Eliminar", - "actionRetryCleanup": "Reintentar limpieza", - "actionMerge": "Fusionar", - "actionUnqueueMerge": "Salir de la cola de fusión", - "actionEditQueuedMerge": "Editar la fusión en cola", - "badgeMergeQueued": "En cola para fusionar", - "badgeMergeQueuedRank": "En cola para fusionar · n.º {rank}", - "badgeMergeQueuedHint": "Esperando a que termine la fusión en curso del proyecto; esta empezará sola.", - "actionComplete": "Completar", - "actionAbandon": "Abandonar", - "cancelTitle": "¿Cancelar la tarea?", - "cancelDescription": "La tarea pasa a Cancelada. Su worktree se conserva y podrás reencolarla más tarde.", - "cancelReasonLabel": "Motivo (opcional)", - "cancelReasonPlaceholder": "P. ej. enfoque equivocado: voy a reescribir la descripción", - "cancelKeep": "Mejor no", - "cancelSubmit": "Cancelar tarea", - "restartTitleRetry": "Reintentar la tarea", - "restartTitleRequeue": "Reencolar la tarea", - "restartDescription": "Puedes añadir una nota (opcional): llega al prompt de la próxima ejecución.", - "scheduleTitle": "Programar tarea", - "scheduleDescription": "La tarea sigue en Pendientes y se inicia sola a la hora que elijas. El límite de concurrencia de la carpeta se sigue aplicando.", - "scheduleDateLabel": "Fecha", - "schedulePickDate": "Elegir fecha", - "scheduleTimeLabel": "Hora", - "schedulePreview": "Se ejecuta el {time}", - "schedulePastHint": "Esa hora ya pasó: la tarea empezará en cuanto guardes.", - "scheduleInAnHour": "En 1 hora", - "scheduleInThreeHours": "En 3 horas", - "scheduleTomorrow": "Mañana 9:00", - "scheduleClear": "Quitar programación", - "scheduleBadge": "Inicio programado para el {time}", - "toastScheduled": "Programada para el {time}", - "toastScheduleCleared": "Programación eliminada", - "actionFollowUp": "Continuar", - "actionAddNote": "Añadir una nota", - "followUpSubmit": "Enviar", - "followUpIntentRevise": "Corregir", - "followUpIntentContinue": "Seguir", - "followUpIntentQuestion": "Preguntar", - "followUpIntentVerify": "Revisar", - "followUpPlaceholderRevise": "¿Qué debe cambiar el agente? Continúa en la misma sesión.", - "followUpPlaceholderContinue": "¿Qué sigue? Lo hecho hasta ahora se mantiene.", - "followUpPlaceholderQuestion": "¿Qué quieres saber? El agente responde sin tocar ningún archivo.", - "followUpPlaceholderVerify": "Opcional: ¿algo que deba revisar con atención?", - "followUpPlaceholderRetry": "Opcional: ¿qué debe hacer distinto? P. ej. ejecutar pnpm install primero", - "followUpPlaceholderRequeue": "Opcional: ¿por qué lo cancelaste y qué debe cambiar esta vez?", - "actionArchive": "Archivar", - "actionUnarchive": "Desarchivar", - "archiveAllDone": "Archivar todo", - "dropToStart": "Suelta para iniciar", - "errorView": "Ver", - "notifyReview": "Listo para revisar: {title}", - "notifyFailed": "La tarea falló: {title}", - "createFromMessage": "Crear tarea desde el mensaje", - "detailTokens": "Tokens totales", - "editorTitleNew": "Nueva tarea", - "editorTitleEdit": "Editar tarea", - "templates": "Plantillas", - "templatesEmpty": "Aún no hay plantillas.", - "templateSaveCurrent": "Guardar como plantilla", - "templateDelete": "Eliminar plantilla", - "transcriptTitle": "Conversación de la tarea", - "transcriptDescription": "Vista en vivo de solo lectura de la sesión del agente de la tarea.", - "phaseWork": "Ejecución", - "phaseRetry": "Reintento", - "phaseReturn": "Continuación", - "phaseMerge": "Fusión", - "titleLabel": "Título", - "titlePlaceholder": "¿Qué hay que hacer?", - "promptLabel": "Descripción de la tarea", - "promptPlaceholder": "Describe la tarea para el agente — @ para referenciar archivos, / para comandos", - "folderPlaceholder": "Selecciona una carpeta", - "agentInheritedHint": "Heredado de la configuración de tareas; cámbialo para personalizar esta tarea", - "agentOverrideReset": "Volver a heredar", - "sectionTarget": "Destino", - "errorTitle": "El título es obligatorio", - "errorPrompt": "La descripción es obligatoria", - "errorFolder": "Selecciona una carpeta", - "save": "Guardar", - "cancel": "Cancelar", - "mergeTitle": "Fusionar tarea", - "mergeQueuedTitle": "Fusión en cola", - "mergeQueueHint": "Otra tarea de este proyecto se está fusionando ahora. Esta entra en la cola y empezará sola en cuanto la otra termine.", - "mergeQueueUpdateHint": "Esta tarea ya está esperando para fusionarse. Al enviar se actualiza y conserva su lugar en la cola.", - "mergeDescription": "Fusionar {branch} en {base}. Los cambios sin confirmar del worktree se confirman primero.", - "mergeMessage": "Mensaje de commit", - "mergeMessagePlaceholder": "p. ej. feat: add login validation", - "mergeAutoMessage": "Dejar que el agente escriba el mensaje de commit", - "strategySquash": "Combinar en un solo commit", - "strategySquashHint": "Todos los cambios de la tarea llegan a la rama principal como una sola entrada del historial: un historial más limpio.", - "strategyMerge": "Conservar todo el historial", - "strategyMergeHint": "Se conserva cada commit hecho durante la tarea, más una entrada de fusión: cada paso queda rastreable.", - "mergeDeleteWorktree": "Eliminar el worktree tras fusionar", - "mergeSubmit": "Fusionar", - "mergeSubmitQueue": "Añadir a la cola", - "mergeQueuedToast": "Añadida a la cola de fusión: empezará en cuanto termine la fusión actual.", - "completeTitle": "Completar tarea", - "completeDescription": "Esta tarea no cambió ningún archivo, así que no hay nada que fusionar: se marca como completada directamente.", - "completeDescriptionNoWorktree": "El worktree de esta tarea fue eliminado, así que ya no se puede fusionar: se marca como completada directamente. Una rama de trabajo que aún tenga commits sin fusionar se conserva.", - "completeDeleteWorktree": "Eliminar el worktree al completar", - "completeSubmit": "Completar", - "settingsTitle": "Ajustes de tareas", - "settingsDescription": "Valores por defecto para las tareas de {folder}.", - "settingsScope": "Ámbito", - "settingsScopeGlobal": "Todas las carpetas (valores globales)", - "settingsScopeGlobalHint": "Las carpetas sin configuración propia usan estos valores globales.", - "settingsSource": "Origen de configuración", - "settingsSourceGlobal": "Valores globales", - "settingsSourceCustom": "Personalizada", - "settingsSourceGlobalFollow": "Sigue la configuración global de tareas; los cambios allí se aplican aquí automáticamente.", - "settingsSourceCustomHint": "Guarda configuración propia para esta carpeta y deja de seguir los valores globales.", - "settingsAgent": "Agente por defecto", - "settingsMaxConcurrent": "Tareas concurrentes máx.", - "settingsMaxConcurrentHint": "0 = sin límite", - "settingsAutoProcess": "Procesar automáticamente", - "settingsAutoProcessHint": "Las tareas pendientes se inician solas, hasta el límite de concurrencia.", - "settingsMergeStrategy": "Estrategia de fusión por defecto", - "settingsMergeStrategyHint": "Cómo se registran los cambios de la tarea en el historial de la rama al fusionar.", - "settingsAutoMerge": "Fusionar automáticamente", - "settingsAutoMergeHint": "Una tarea que llega a revisión con cambios que integrar se fusiona como si pulsaras Fusionar: el agente escribe el mensaje de commit y el worktree sigue el valor por defecto de abajo. Si la verificación falla o una fusión falló, la tarea queda esperándote.", - "settingsDeleteWorktree": "Eliminar el worktree tras fusionar", - "settingsDeleteWorktreeHint": "Marca la opción por defecto en el diálogo de fusión; aún puedes cambiarla allí.", - "settingsWorktreeRoot": "Ubicación del worktree", - "settingsWorktreeRootHint": "Directorio donde se crean los worktrees de las tareas nuevas, uno por tarea. Déjalo vacío para crearlos junto a la carpeta del proyecto; «~» es tu carpeta personal y una ruta relativa se resuelve respecto a la carpeta del proyecto.", - "settingsWorktreeRootPlaceholder": "~/codeg-worktrees", - "settingsWorktreeRootBrowse": "Elegir el directorio de worktrees", - "settingsPreflight": "Comando de verificación", - "settingsPreflightHint": "Se ejecuta en el worktree cuando una tarea llega a revisión.", - "settingsPreflightCustomPlaceholder": "pnpm test", - "settingsInitCommand": "Comando de inicialización del worktree", - "settingsInitCommandHint": "Se ejecuta en un worktree recién creado antes de iniciar el agente.", - "settingsInitCommandPlaceholder": "pnpm install", - "settingsTabGeneral": "General", - "settingsTabMerge": "Fusión", - "settingsTabWorktree": "Worktree", - "settingsTabPrompts": "Prompts", - "settingsPromptsIntro": "Cada etapa ya envía su propio prompt integrado: la tarea, las reglas del worktree y, al fusionar, los pasos exactos de git. Lo que añadas aquí se agrega al final como instrucciones extra: matiza esos textos integrados, nunca los sustituye.", - "settingsPromptStageAll": "Todas las fases", - "settingsPromptPlaceholderAll": "p. ej. Sigue las convenciones de AGENTS.md; que el resumen final no pase de dos frases", - "settingsPromptPlaceholderWork": "p. ej. Lee primero las pruebas relacionadas; haz commits pequeños sobre la marcha", - "settingsPromptPlaceholderRetry": "p. ej. Revisa qué hay ya commiteado antes de continuar; no rehagas lo terminado", - "settingsPromptPlaceholderReturn": "P. ej. Atiende cada punto planteado; no refactorices nada ajeno", - "settingsPromptPlaceholderMerge": "p. ej. Escribe el mensaje del commit de integración en español; señala los conflictos que resolviste a mano", - "settingsPromptHintAll": "Se añade a todos los prompts que recibe el agente, incluida la fusión.", - "settingsPromptHintWork": "Se añade cuando una tarea se ejecuta por primera vez.", - "settingsPromptHintRetry": "Se añade al retomar una tarea interrumpida o fallida.", - "settingsPromptHintReturn": "Se añade cuando continúas una tarea en revisión (corregir, ampliar, revisar).", - "settingsPromptHintMerge": "Se añade cuando el agente integra la tarea en la rama base.", - "preflightPassed": "{name} superado", - "preflightFailed": "{name} falló", - "preflightRunning": "{name} en ejecución…", - "detailDescription": "Detalle de la tarea", - "detailSummary": "Resultado", - "detailFiles": "Archivos modificados", - "detailDiffAll": "Ver diff completo", - "detailDiffAllTitle": "Diff completo", - "detailNoChanges": "Aún no hay cambios respecto a la base", - "detailTimeline": "Progreso", - "detailTimelineEmpty": "Sin actividad todavía", - "showMore": "Ver más", - "showLess": "Ver menos", - "detailInfo": "Detalles", - "detailBranch": "Rama", - "detailMergeCommit": "Commit de fusión", - "detailChanges": "Cambios", - "detailScheduled": "Inicio programado", - "detailCreated": "Creada", - "detailStarted": "Iniciada", - "detailFinished": "Finalizada", - "diffLoading": "Cargando diff…", - "deleteConfirmTitle": "¿Eliminar la tarea?", - "deleteConfirmBody": "“{title}” se quitará del tablero. Una ejecución activa se cancela primero.", - "deleteWithWorktree": "Eliminar también su worktree", - "eventCreated": "Creada", - "eventStatusChanged": "Cambio de estado", - "eventConfigEffective": "Configuración de arranque", - "eventInitCommand": "Comando de inicialización", - "eventAgentProgress": "Progreso del agente", - "eventAgentVerdict": "Veredicto del agente", - "eventMergeAttempt": "Fusión iniciada", - "eventMergeQueued": "En cola para fusionar", - "eventMergeConflict": "Conflicto de fusión", - "eventPreflight": "Verificación", - "eventCleanupFailed": "Fallo al limpiar el worktree", - "eventResumeFallback": "La reanudación falló; se usó una sesión nueva", - "eventUserAction": "Acción del usuario", - "eventDiffStat": "Instantánea de cambios" - }, - "CustomSkillsSettings": { - "loading": "Cargando habilidades personalizadas…", - "category": "Personalizadas", - "searchPlaceholder": "Buscar habilidades personalizadas por nombre, ID o descripción", - "states": { - "not_linked": "No habilitada", - "linked_to_codeg": "Habilitada", - "linked_elsewhere": "Vinculada en otro lugar", - "blocked_by_real_directory": "Bloqueada por una carpeta real", - "broken": "Enlace roto" - }, - "actions": { - "new": "Nueva", - "import": "Importar", - "importFromAgent": "Importar de un agente", - "cancel": "Cancelar", - "save": "Guardar" - }, - "rowMenu": { - "edit": "Editar", - "duplicate": "Duplicar", - "delete": "Eliminar" - }, - "bulk": { - "delete": "Eliminar seleccionadas" - }, - "editor": { - "createTitle": "Nueva habilidad personalizada", - "editTitle": "Editar habilidad personalizada", - "description": "Las habilidades personalizadas se guardan en el almacén compartido (~/.codeg/skills) y pueden habilitarse para cualquier agente.", - "idLabel": "ID de habilidad", - "idPlaceholder": "p. ej. my-workflow", - "contentLabel": "SKILL.md", - "contentPlaceholder": "Escribe aquí el SKILL.md de la habilidad…", - "preview": "Vista previa", - "edit": "Editar", - "emptyBody": "Aún no hay contenido." - }, - "duplicate": { - "title": "Duplicar habilidad", - "description": "Crea una copia de «{id}» con un nuevo ID.", - "newIdPlaceholder": "Nuevo ID de habilidad", - "confirm": "Duplicar" - }, - "import": { - "title": "Elige una carpeta de habilidad para importar" - }, - "importFromAgent": { - "title": "Importar habilidades de un agente", - "description": "Copia las habilidades propias de un agente al almacén compartido para poder activarlas en cualquier agente.", - "agentLabel": "Agente", - "agentPlaceholder": "Selecciona un agente", - "selectAll": "Seleccionar todo ({count})", - "loading": "Cargando las habilidades del agente…", - "unsupported": "Este agente no expone un directorio de habilidades.", - "empty": "Este agente no tiene habilidades que importar.", - "alreadyInLibrary": "En la biblioteca", - "confirm": "Importar seleccionadas ({count})" - }, - "delete": { - "title": "¿Eliminar habilidades personalizadas?", - "body": "Se eliminarán {count} habilidad(es) personalizada(s) del almacén central y se desvincularán de todos los agentes. Esta acción no se puede deshacer.", - "confirm": "Eliminar" - }, - "toasts": { - "loadFailed": "No se pudo cargar la habilidad", - "idRequired": "Introduce un ID de habilidad", - "created": "Habilidad personalizada creada", - "updated": "Habilidad personalizada actualizada", - "saveFailed": "No se pudo guardar la habilidad", - "imported": "Habilidad importada", - "importFailed": "No se pudo importar la habilidad", - "duplicated": "Habilidad duplicada", - "duplicateFailed": "No se pudo duplicar la habilidad", - "deleted": "Se eliminaron {count} habilidad(es)", - "deletedPartial": "{ok} eliminadas, {failed} fallidas", - "deleteFailed": "No se pudieron eliminar las habilidades", - "importedFromAgent": "Se importaron {count} habilidad(es)", - "importedFromAgentPartial": "Importadas {ok}, {failed} con error", - "importFromAgentAllSkipped": "Nada que importar: {count} ya están en la biblioteca", - "importFromAgentFailed": "No se pudo importar del agente" - } - }, - "CodexModelEditor": { - "customizedNotice": "Has personalizado la lista de modelos, así que ahora codeg gestiona toda la tabla de modelos de codex. Los modelos oficiales que codex añada después no aparecerán automáticamente: haz clic en el botón actualizar de abajo y guarda de nuevo para sincronizarlos. Borra tus personalizaciones para que codex vuelva a actualizarse automáticamente.", - "officialsTitle": "Modelos oficiales", - "officialsHint": "Se incluyen automáticamente del codex que ejecutas; elimina los que no quieras.", - "officialsEmpty": "No hay modelos oficiales disponibles.", - "refresh": "Actualizar desde codex", - "readdOfficial": "Volver a añadir oficial", - "customsTitle": "Modelos personalizados", - "customsEmpty": "Aún no hay modelos personalizados.", - "addCustom": "Agregar personalizado", - "slugPlaceholder": "id del modelo (slug)", - "displayNamePlaceholder": "Nombre visible", - "contextWindow": "Contexto", - "makeDefault": "Establecer como predeterminado", - "defaultHint": "Modelo predeterminado", - "remove": "Eliminar", - "advanced": "Avanzado", - "baseTemplate": "Plantilla base", - "baseTemplateHint": "Modelo oficial del que clonar los campos obligatorios (prompt del sistema, herramientas, límites).", - "groupBehavior": "Comportamiento y capacidades", - "fieldReasoningLevel": "Razonamiento predeterminado", - "fieldReasoningSummary": "Resumen de razonamiento", - "fieldVerbosity": "Nivel de detalle", - "fieldShellType": "Tipo de shell", - "fieldApplyPatch": "Herramienta apply-patch", - "fieldReasoningSummaries": "Resúmenes de razonamiento", - "fieldSupportVerbosity": "Control de detalle", - "fieldParallelToolCalls": "Llamadas a herramientas en paralelo", - "fieldSearchTool": "Herramienta de búsqueda web", - "optNone": "Ninguno", - "groupInstructions": "Descripción y prompt del sistema", - "fieldDescription": "Descripción", - "baseInstructions": "Prompt del sistema (base_instructions)" - }, - "DiagnosticsSettings": { - "title": "Diagnóstico del entorno", - "description": "Comprueba cómo esta app resuelve la CLI del agente en su propio proceso, que puede diferir de tu terminal.", - "loading": "Ejecutando diagnóstico…", - "error": "El diagnóstico falló", - "rerun": "Volver a ejecutar", - "copyAll": "Copiar todo", - "copied": "Diagnóstico copiado al portapapeles", - "button": "Diagnosticar", - "verdict": { - "ok": "El entorno parece correcto. Si aún aparece como no instalado, reinicia por completo la app para actualizar la caché del prefijo.", - "node_missing": "No se encontró Node.js en el PATH de la app.", - "npm_missing": "No se encontró npm en el PATH de la app.", - "not_installed": "Este agente no parece estar instalado.", - "installed_but_unresolved": "Consta como instalado, pero la app no puede localizar su ejecutable.", - "user_prefix_not_on_path": "Se instaló en el prefijo de reserva (~/.codeg/npm-global), que no está en el PATH de la app. Reinicia por completo la app e inténtalo de nuevo.", - "homebrew_bin_not_on_path": "Se instaló en el bin de Homebrew, que no está en el PATH de la app (división de keg en Apple Silicon).", - "terminal_only_path": "El comando se resuelve en tu terminal pero no en la app: una diferencia de PATH de la GUI. Inicia la app desde una terminal o reinstala desde Ajustes de agentes.", - "npm_prefix_timeout": "npm prefix -g fue demasiado lento (más de 1,5 s), por lo que se omitió la detección de reserva. Reinicia la app e inténtalo de nuevo.", - "node_too_old": "Tu Node.js activo es más antiguo de lo que requiere este agente. Actualiza Node.js.", - "adapter_missing_native_present": "Tu CLI de {agent} sí está instalada, pero Codeg ejecuta un paquete adaptador ACP aparte, y ese todavía no lo está. Instálalo desde la configuración de agentes: no toca tu CLI y comparte la misma sesión.", - "adapter_missing": "Codeg ejecuta un paquete adaptador ACP aparte para {agent} y aún no está instalado. Instálalo desde la configuración de agentes: instalar solo la CLI del proveedor no basta." - } - }, - "TokenUsage": { - "title": "Uso de tokens", - "rangeLabel": "Periodo", - "range7d": "7 días", - "range30d": "30 días", - "range90d": "90 días", - "rangeThisMonth": "Este mes", - "rangeThisYear": "Este año", - "rangeAll": "Todo", - "rangeCustom": "Personalizado", - "moreRanges": "Más", - "customRangePick": "Elegir un intervalo", - "bucketLabel": "Agrupar por", - "bucketDay": "Día", - "bucketWeek": "Semana", - "bucketMonth": "Mes", - "bucketUnitDay": "Día", - "bucketUnitWeek": "Semana", - "bucketUnitMonth": "Mes", - "folderFilter": "Carpetas", - "allFolders": "Todas las carpetas", - "agentFilter": "Agentes", - "allAgents": "Todos los agentes", - "modelFilter": "Modelos", - "allModels": "Todos los modelos", - "searchPlaceholder": "Buscar…", - "noMatches": "Sin coincidencias", - "clearFilter": "Borrar selección", - "resetFilters": "Restablecer filtros", - "refresh": "Actualizar", - "rebuild": "Reconstruir todo", - "rebuildHint": "Descarta lo contabilizado y vuelve a leer todas las transcripciones. Útil si una sesión creció fuera de codeg.", - "syncing": "Contando sesiones…", - "syncProgress": "{done} / {total}", - "syncDone": "{synced} sesiones contabilizadas", - "syncFailed": "No se pudieron leer algunas sesiones", - "syncBusy": "Ya hay una actualización en curso", - "lastSynced": "Actualizado {time}", - "lastSyncedNever": "Nunca actualizado", - "tileTotal": "Tokens totales", - "tileSessions": "Sesiones", - "tileTurns": "Turnos", - "tileActiveDays": "Días activos", - "tileGenTime": "Tiempo de generación", - "vsPrevious": "frente al periodo anterior", - "deltaNew": "nuevo", - "trendTitle": "Uso en el tiempo", - "trendEmpty": "Sin uso en este periodo", - "trendTurns": "Turnos", - "trendSessions": "Sesiones", - "compositionTitle": "En qué se fueron los tokens", - "compositionHint": "La entrada es lo que enviaste, la salida lo que escribió el modelo y las lecturas de caché son contexto que no pagaste a precio completo.", - "compositionNote": "Reenviar esos aciertos de caché a precio completo habría costado otros {value}.", - "inputTokens": "Entrada", - "outputTokens": "Salida", - "cacheWrite": "Escritura de caché", - "cacheRead": "Lectura de caché", - "freshTokens": "Cómputo nuevo", - "cacheHitCaption": "Acierto de caché", - "cacheHeroTitleHigh": "La mayoría del contexto no se reenvió", - "cacheHeroTitleLow": "La mayoría del contexto aún se calcula a precio completo", - "cacheHeroDesc": "La caché cargó con {cached} de contexto; solo {fresh} se calculó de nuevo en este periodo.", - "cacheSavedSuffix": "Eso ahorró reenviar el equivalente a {saved}.", - "avgPerSession": "Media por sesión", - "avgTurnsPerSession": "{count} turnos por sesión de media", - "avgPerActiveDay": "Media por día activo", - "peakBucket": "{bucket} con más uso", - "peakHour": "Hora punta", - "daysValue": "{count} días", - "idleDays": "Días sin actividad", - "byFolderTitle": "Por carpeta", - "byAgentTitle": "Por agente", - "byModelTitle": "Por modelo", - "distributionTitle": "Distribución del uso", - "distributionHint": "Sesiones y tokens agrupados por la dimensión elegida; haz clic en una fila para filtrar por ella.", - "otherLabel": "Otros", - "unknownModel": "Modelo sin registrar", - "emptyBreakdown": "Todavía sin registros", - "sessionsCount": "{count} sesiones", - "heatmapTitle": "Cuándo programas", - "heatmapHint": "Tokens por día de la semana y hora local.", - "heatmapPeakHint": "La franja más densa ronda las {hour}:00.", - "less": "Menos", - "more": "Más", - "heatmapCell": "{weekday} {hour}:00 — {value} tokens", - "weekMon": "Lun", - "weekTue": "Mar", - "weekWed": "Mié", - "weekThu": "Jue", - "weekFri": "Vie", - "weekSat": "Sáb", - "weekSun": "Dom", - "topSessionsTitle": "Sesiones más costosas", - "untitledSession": "Sesión sin título", - "topSessionsEmpty": "Sin sesiones en este periodo", - "streakLongest": "Racha más larga", - "streakLongestDays": "Racha más larga: {count} días", - "share": "Compartir", - "moreActions": "Más acciones", - "shareDialogTitle": "Comparte tu tarjeta de uso", - "shareDialogHint": "Una instantánea del periodo y los filtros que estás viendo.", - "shareSave": "Guardar imagen", - "shareCopy": "Copiar imagen", - "shareCopied": "Copiado al portapapeles", - "shareSaved": "Imagen guardada", - "shareFailed": "No se pudo crear la imagen", - "shareRendering": "Generando…", - "cardHeading": "Mis estadísticas de código con IA", - "cardRangeAll": "Todo el tiempo", - "cardTotalLabel": "Tokens usados", - "cardFooter": "Hecho con codeg", - "cardTopModels": "Modelos principales", - "cardTopProjects": "Proyectos principales", - "archetypeNightOwl": "Ave nocturna", - "archetypeNightOwlDesc": "El {percent}% de tus tokens se quema de noche.", - "archetypeEarlyBird": "Madrugador", - "archetypeEarlyBirdDesc": "El {percent}% de tus tokens cae antes de las 9.", - "archetypeWeekendWarrior": "Guerrero de fin de semana", - "archetypeWeekendWarriorDesc": "El {percent}% de tus tokens ocurre el fin de semana.", - "archetypeCacheMaster": "Maestro de la caché", - "archetypeCacheMasterDesc": "El {percent}% de tu contexto vino de la caché.", - "archetypeMarathoner": "Maratoniano", - "archetypeMarathonerDesc": "{days} días programando sin parar.", - "archetypePolyglot": "Polivalente", - "archetypePolyglotDesc": "{count} agentes en rotación seria.", - "archetypeLaserFocus": "Foco láser", - "archetypeLaserFocusDesc": "El {percent}% de tus tokens fue a un solo proyecto.", - "archetypeDeepDiver": "Buceador", - "archetypeDeepDiverDesc": "{averageK}K tokens en una sesión media.", - "archetypeSteady": "Constructor constante", - "archetypeSteadyDesc": "{days} días entregando.", - "emptyTitle": "Todavía no hay nada contabilizado", - "emptyHint": "Codeg lee los tokens directamente de la transcripción de cada agente. Actualiza para contabilizar lo que ya hay en esta máquina.", - "emptyAction": "Contabilizar mis sesiones", - "loadFailed": "No se pudo cargar el uso", - "truncatedNotice": "Este periodo es muy amplio: las cifras cubren solo su tramo más reciente." - } -} +{ + "Language": { + "followSystem": "Seguir el sistema", + "english": "Inglés", + "simplifiedChinese": "Chino simplificado", + "traditionalChinese": "Chino tradicional", + "japanese": "Japonés", + "korean": "Coreano", + "spanish": "Español", + "german": "Alemán", + "french": "Francés", + "portuguese": "Portugués", + "arabic": "Árabe" + }, + "GitCredentialDialog": { + "title": "Autenticación requerida", + "description": "El servidor remoto requiere credenciales. Introduce tu nombre de usuario y contraseña (o token de acceso personal).", + "username": "Nombre de usuario", + "usernamePlaceholder": "Usuario o correo electrónico", + "password": "Contraseña / Token", + "passwordPlaceholder": "Contraseña o token de acceso personal", + "passwordHint": "Introduce el nombre de usuario y contraseña del servidor.", + "cancel": "Cancelar", + "authenticate": "Autenticar", + "authenticating": "Autenticando...", + "invalidCredentials": "Credenciales inválidas. Inténtalo de nuevo.", + "saveCredentials": "Guardar credenciales para futuras operaciones", + "githubTitle": "Autenticación de GitHub", + "githubDescription": "Introduce un token de acceso personal para conectarte a GitHub. El token se validará y guardará automáticamente.", + "githubToken": "Token de acceso personal", + "githubTokenPlaceholder": "ghp_xxxxxxxxxxxx", + "githubTokenHint": "Genera un token en GitHub → Settings → Developer settings → Personal access tokens.", + "githubAuthenticate": "Validar y conectar", + "generateToken": "Generar token" + }, + "SettingsShell": { + "title": "Configuración", + "preferences": "Preferencias", + "nav": { + "general": "General", + "appearance": "Apariencia", + "agents": "Agentes", + "mcp": "MCP", + "skills": "Skills", + "shortcuts": "Atajos", + "version_control": "Control de versiones", + "system": "Sistema", + "chat_channels": "Canales de chat", + "web_service": "Servicio Web", + "model_providers": "Proveedores de Modelos", + "experts": "Expertos", + "science": "Ciencia", + "office_tools": "Herramientas de oficina", + "skill_packs": "Paquetes de habilidades", + "quick_messages": "Mensajes rápidos", + "logs": "Registros de ejecución" + } + }, + "AppearanceSettings": { + "sectionTitle": "Apariencia del tema", + "sectionDescription": "Elige claro, oscuro o seguir el sistema. La configuración se guarda automáticamente.", + "themeMode": "Modo de tema", + "placeholder": "Selecciona el modo de tema", + "system": "Seguir el sistema", + "light": "Claro", + "dark": "Oscuro", + "currentTheme": "Tema efectivo actual: {theme}", + "resolvedTheme": { + "light": "Claro", + "dark": "Oscuro", + "unknown": "--" + }, + "themeColor": { + "sectionTitle": "Color del tema", + "sectionDescription": "Elige una paleta de colores para acentos, botones y resaltados.", + "current": "Color actual: {color}", + "options": { + "neutral": "Neutral", + "zinc": "Zinc", + "slate": "Slate", + "stone": "Stone", + "gray": "Gray", + "red": "Red", + "rose": "Rose", + "orange": "Orange", + "green": "Green", + "blue": "Blue", + "yellow": "Yellow", + "violet": "Violet" + } + }, + "customStyle": { + "sectionTitle": "Estilo personalizado", + "sectionDescription": "Ajusta los colores del tema actual o inyecta tu propio CSS. Las anulaciones se aplican sobre el preajuste base, así que se conservan al cambiar de preajuste.", + "summarySuspended": "Suspendido", + "summaryDefault": "Preajuste sin cambios", + "summaryTokens": "{count, plural, one {# anulación} other {# anulaciones}}", + "summaryCss": "CSS personalizado", + "suspendedByShortcut": "El estilo personalizado está suspendido. Nada de lo que configures aquí surtirá efecto hasta que lo reanudes.", + "suspendedBySafeParam": "Esta ventana se abrió en modo de apariencia segura, por lo que el estilo personalizado se ignora aquí. Las demás ventanas no se ven afectadas.", + "resume": "Reanudar estilo personalizado", + "enableTheme": "Activar colores personalizados", + "editingLight": "Editando los valores del modo claro. Cambia la aplicación al modo oscuro para configurarlo por separado.", + "editingDark": "Editando los valores del modo oscuro. Cambia la aplicación al modo claro para configurarlo por separado.", + "resetToken": "Restablecer al valor del preajuste", + "radius": "Radio de esquina", + "radiusHint": "De él deriva toda la escala de radios, de sm a 4xl, así que un único control redondea toda la aplicación.", + "advanced": "Avanzado ({count} variables más)", + "enableCss": "Activar CSS personalizado", + "cssRisk": "Función avanzada. El CSS personalizado anula todos los estilos integrados y puede dejar la interfaz inutilizable.", + "editCss": "Editar CSS…", + "cssPresent": "{size} KB guardados", + "cssEmpty": "Todavía no hay nada guardado", + "escapeHint": "¿Interfaz rota? Pulsa {shortcut} para suspender todo el estilo personalizado, o abre una ventana con el parámetro de consulta safeStyle=1.", + "copyTheme": "Copiar JSON del tema", + "importTheme": "Importar tema…", + "clearTheme": "Borrar anulaciones", + "interopHint": "Los temas usan el formato registry:theme de shadcn, así que puedes pegar aquí cualquier tema de shadcn y usar los exportados en cualquier proyecto shadcn.", + "importTitle": "Importar tema", + "importDescription": "Pega un elemento registry:theme de shadcn, un objeto light/dark simple o un mapa plano de tokens.", + "readClipboard": "Leer portapapeles", + "importConfirm": "Importar", + "cancel": "Cancelar", + "apply": "Aplicar", + "toasts": { + "copied": "JSON del tema copiado", + "copyFailed": "No se pudo copiar al portapapeles", + "clipboardReadFailed": "No se pudo leer el portapapeles, pégalo manualmente", + "importFailed": "Ese JSON no contiene variables de tema utilizables", + "imported": "Tema importado" + }, + "css": { + "dialogTitle": "CSS personalizado", + "dialogDescription": "Se aplica a todas las ventanas de codeg. Los cambios se previsualizan en vivo; pulsa Aplicar para guardar.", + "size": "{used} KB / {max} KB", + "ruleCount": "{count} reglas", + "errorTooLarge": "Demasiado grande para guardar. Redúcelo por debajo del límite.", + "errorImportEscaped": "Una regla @import sobrevivió a la eliminación (sintaxis con escapes). Quítala para guardar.", + "warnNoRules": "No se analizó ninguna regla; revisa la sintaxis.", + "noticeImportsRemoved": "Reglas @import eliminadas: {count}. Descargarían hojas de estilo remotas.", + "noticeRemoteUrl": "Contiene una url() remota, que hará una petición de red al aplicarse.", + "noticePreviewSuspended": "El estilo personalizado está suspendido, así que esta vista previa no se aplica.", + "noticeDisabled": "El CSS personalizado está desactivado. Puedes previsualizar aquí, pero no se aplicará hasta que lo actives.", + "hintTokens": "Consejo: tus colores anulados están disponibles como var(--primary), var(--background), etc." + } + }, + "zoomLevel": { + "sectionTitle": "Zoom de ventana", + "sectionDescription": "Escala toda la interfaz. Se aplica al instante y se guarda por dispositivo.", + "placeholder": "Selecciona el nivel de zoom", + "default": "Predeterminado", + "current": "Zoom actual: {zoom}%" + }, + "fonts": { + "sectionTitle": "Fuentes", + "sectionDescription": "Elige las fuentes para la interfaz, el editor de código y el terminal. Las fuentes incluidas se cargan cuando se necesitan; selecciona «Personalizada…» para usar cualquier fuente instalada en tu sistema.", + "interface": "Interfaz", + "editor": "Editor", + "terminal": "Terminal", + "groupSans": "Sans-serif", + "groupMono": "Monoespaciada", + "custom": "Personalizada…", + "customPlaceholder": "Nombre de la fuente, p. ej. Fira Code", + "fontSize": "Tamaño de fuente", + "ligatures": "Activar ligaduras", + "ligaturesUnavailable": "Esta fuente no tiene ligaduras", + "wordWrap": "Activar ajuste de línea", + "terminalLigaturesHint": "Las ligaduras del terminal solo se aplican a las fuentes de programación incluidas.", + "preview": "Vista previa" + }, + "welcomePanel": { + "sectionTitle": "Área de selección de modo", + "sectionDescription": "Las tarjetas de acceso rápido «Desarrollo de código / Ofimática» que se muestran sobre el editor en la página de nueva conversación.", + "showQuickActions": "Mostrar en la página de nueva conversación" + }, + "workspaceBackground": { + "sectionTitle": "Fondo del espacio de trabajo", + "sectionDescription": "Muestra una imagen detrás de todo el espacio de trabajo. La barra lateral y los paneles se vuelven translúcidos y esmerilados para dejar ver la imagen, y una máscara mantiene el texto legible.", + "enable": "Activar imagen de fondo", + "image": "Imagen", + "chooseImage": "Elegir imagen", + "replaceImage": "Reemplazar imagen", + "removeImage": "Quitar", + "fillMode": "Modo de relleno", + "fillModes": { + "cover": "Cubrir", + "contain": "Ajustar", + "center": "Centrar", + "tile": "Mosaico" + }, + "maskOpacity": "Opacidad de la máscara", + "maskOpacityHint": "Los valores más altos difuminan la imagen hacia el color de fondo del tema, mejorando el contraste del texto.", + "imageBlur": "Desenfoque de la imagen", + "panelOpacity": "Opacidad de los paneles", + "panelOpacityHint": "Cuán opacos son la barra lateral, los paneles y las barras de pestañas. Más bajo deja ver más la imagen.", + "errorTooLarge": "La imagen es demasiado grande (máx. 16 MB).", + "errorUploadFailed": "No se pudo establecer la imagen de fondo." + } + }, + "SystemSettings": { + "loading": "Cargando...", + "sectionTitle": "Administración del sistema", + "sectionDescription": "Administra el proxy de red, las actualizaciones de la app y las preferencias de idioma.", + "proxyTitle": "Proxy de red", + "proxyDescription": "Cuando está activado, las solicitudes de red posteriores usarán este proxy preferentemente (incluyendo chat ACP, instalación de agentes y operaciones remotas de Git).", + "loadFailed": "Error al cargar: {message}", + "enableProxy": "Activar proxy del sistema", + "proxyAddress": "Dirección del proxy", + "proxyHint": "Compatible con http(s)/socks5, ejemplo: {example}. Solo funciona cuando el proxy del sistema está activado.", + "save": "Guardar", + "saving": "Guardando...", + "proxyRequired": "Se requiere URL del proxy cuando el proxy está activado", + "saveSuccess": "La configuración del proxy del sistema se guardó", + "saveFailed": "Error al guardar: {message}", + "languageTitle": "Idioma", + "languageDescription": "Configura el idioma de la app. Al seguir el idioma del sistema, los no compatibles vuelven a inglés.", + "appLanguage": "Idioma de la app", + "languageSaveSuccess": "La configuración de idioma se guardó", + "languageSaveFailed": "No se pudo guardar la configuración de idioma: {message}", + "updateTitle": "Actualización de la app", + "versionTitle": "Actualización de software", + "updateDescription": "Comprueba versiones más nuevas en la fuente de versiones configurada e instálalas directamente cuando estén disponibles.", + "currentVersion": "Versión actual", + "upgradableVersion": "Última versión", + "none": "Ninguna", + "lastChecked": "Última comprobación: {time}", + "updateError": "Error de actualización: {message}", + "checking": "Comprobando...", + "checkUpdate": "Buscar actualizaciones", + "updating": "Instalando...", + "downloading": "Descargando...", + "upgradeTo": "Actualizar a v{version}", + "viewRelease": "Ver lanzamiento v{version}", + "foundUpdate": "Nueva versión v{version} encontrada", + "alreadyLatest": "Ya tienes la versión más reciente", + "checkUpdateFailed": "No se pudo buscar actualizaciones: {message}", + "installSuccess": "Actualización instalada. Reiniciando la app.", + "installFailed": "La actualización falló: {message}", + "upgradeSuccess": "Actualización completada. Recargando...", + "restartTimeout": "El servidor no volvió a tiempo. Revisa los registros del contenedor o del servicio.", + "restartingIn": "Reiniciando en {seconds} s...", + "waitingForServer": "Esperando a que el servidor vuelva...", + "restartToUpdate": "Reiniciar para actualizar", + "newVersionBadge": "Nueva v{version}", + "updateAvailableTitle": "Actualización disponible", + "releaseNotesTitle": "Novedades", + "remindLater": "Más tarde", + "retry": "Reintentar", + "stepDownload": "Descarga", + "stepInstall": "Instalación", + "stepRestart": "Reinicio", + "updateReadyHint": "Actualización descargada: reinicia para aplicarla.", + "restarting": "Reiniciando...", + "dockerUpgradeHint": "Esto actualiza el contenedor en ejecución ahora. Se pierde si se recrea el contenedor: para conservarlo, descarga o crea una imagen con la nueva versión y recrea el contenedor.", + "upgradeRolledBack": "La actualización falló; el servidor volvió a la versión anterior.", + "serverUnreachable": "No se pudo conectar con el servidor para iniciar la actualización. Comprueba que esté en ejecución e inténtalo de nuevo.", + "rollbackButton": "Revertir", + "rollingBack": "Revirtiendo...", + "rollbackDescription": "Restaura la versión instalada antes de la última actualización.", + "rollbackConfirmTitle": "¿Revertir a la versión anterior?", + "rollbackConfirmDescription": "El servidor se reiniciará con la versión instalada antes de la última actualización. Una versión más reciente seguirá disponible para instalar de nuevo.", + "rollbackConfirm": "Revertir", + "rollbackCancel": "Cancelar", + "rollbackSuccess": "Se revirtió a la versión anterior. Recargando...", + "rollbackFailed": "Error al revertir. Revisa los registros del servidor.", + "updateErrors": { + "sourceUnavailable": "No se puede acceder al origen de actualización. Revisa tu red o proxy e inténtalo de nuevo.", + "network": "Falló la conexión de red. Revisa tu red o proxy e inténtalo de nuevo.", + "downloadFailed": "No se pudo descargar el paquete de actualización. Inténtalo más tarde.", + "installFailed": "No se pudo instalar la actualización. Cierra la app e inténtalo de nuevo.", + "unknown": "La actualización falló. Inténtalo más tarde." + } + }, + "VersionControlSettings": { + "loading": "Cargando...", + "sectionTitle": "Control de versiones", + "sectionDescription": "Configura el ejecutable de Git y gestiona las cuentas de GitHub.", + "gitTitle": "Configuración de Git", + "gitDescription": "Configura el ejecutable de Git utilizado por la aplicación.", + "gitDetected": "Git detectado", + "gitNotFound": "Git no encontrado en el sistema", + "gitVersion": "Versión", + "gitPath": "Ruta", + "customGitPath": "Ruta personalizada de Git", + "customGitPathPlaceholder": "/usr/bin/git", + "customGitPathHint": "Dejar vacío para usar la ruta detectada automáticamente.", + "test": "Probar", + "testing": "Probando...", + "testSuccess": "El ejecutable de Git es válido.", + "testFailed": "Prueba de Git fallida: {message}", + "save": "Guardar", + "saving": "Guardando...", + "saveSuccess": "Configuración de Git guardada.", + "saveFailed": "Error al guardar: {message}", + "githubTitle": "Cuentas de GitHub", + "githubDescription": "Gestiona las cuentas de GitHub para autenticación. Los tokens se almacenan localmente.", + "noAccounts": "No hay cuentas de GitHub configuradas.", + "addAccount": "Añadir cuenta", + "serverUrl": "URL del servidor", + "serverUrlPlaceholder": "https://github.com", + "token": "Token de acceso personal", + "tokenPlaceholder": "ghp_xxxxxxxxxxxx", + "generateToken": "Generar token", + "tokenHint": "Genera un token en GitHub → Settings → Developer settings → Personal access tokens.", + "validateAndAdd": "Validar y añadir", + "validating": "Validando...", + "addSuccess": "Cuenta {username} añadida correctamente.", + "addFailed": "Error al añadir cuenta: {message}", + "testConnection": "Probar", + "connectionSuccess": "Conexión exitosa.", + "connectionFailed": "Conexión fallida: {message}", + "setDefault": "Establecer como predeterminada", + "defaultLabel": "Predeterminada", + "defaultSet": "Cuenta predeterminada actualizada.", + "removeAccount": "Eliminar", + "removeConfirmTitle": "Eliminar cuenta", + "removeConfirmMessage": "¿Estás seguro de que deseas eliminar la cuenta \"{username}\"?", + "removeConfirm": "Eliminar", + "removeCancel": "Cancelar", + "removeSuccess": "Cuenta eliminada.", + "scopes": "Alcances", + "loadFailed": "Error al cargar configuración: {message}", + "gitAccount": { + "sectionTitle": "Cuentas de servidor Git", + "sectionDescription": "Gestiona credenciales para servidores Git que no son GitHub (GitLab, Bitbucket, autoalojados, etc.).", + "noAccounts": "No hay cuentas de servidor Git configuradas.", + "addAccount": "Añadir cuenta", + "addTitle": "Añadir cuenta Git", + "addDescription": "Introduce la dirección del servidor, nombre de usuario y contraseña o token de acceso.", + "serverUrl": "URL del servidor", + "serverUrlPlaceholder": "https://gitlab.example.com", + "username": "Nombre de usuario", + "usernamePlaceholder": "Usuario o correo electrónico", + "password": "Contraseña / Token", + "passwordPlaceholder": "Contraseña o token de acceso", + "passwordHint": "Introduce tu contraseña o token de acceso del servidor.", + "add": "Añadir", + "serverRequired": "La URL del servidor es obligatoria.", + "usernameRequired": "El nombre de usuario es obligatorio.", + "passwordRequired": "La contraseña es obligatoria." + } + }, + "ShortcutSettings": { + "sectionTitle": "Atajos", + "resetDefault": "Restablecer valores predeterminados", + "recordInstruction": "Haz clic en el botón derecho y luego pulsa una combinación de teclas. Usa Ctrl/Cmd, Alt y Shift. Pulsa Esc para cancelar la grabación.", + "recording": "Pulsa un atajo...", + "toasts": { + "conflict": "El atajo ya está en uso por \"{title}\"", + "updated": "Atajo actualizado", + "invalid": "Atajo no válido, inténtalo de nuevo", + "reset": "Se restauraron los atajos predeterminados" + }, + "actions": { + "toggle_search": { + "title": "Abrir búsqueda", + "description": "Muestra u oculta el panel de búsqueda de conversaciones" + }, + "toggle_sidebar": { + "title": "Alternar barra lateral izquierda", + "description": "Muestra u oculta la barra lateral de lista de conversaciones" + }, + "toggle_terminal": { + "title": "Alternar terminal", + "description": "Muestra u oculta el panel de terminal inferior" + }, + "new_terminal_tab": { + "title": "Nueva terminal", + "description": "Crea una nueva pestaña de terminal cuando el foco está en la terminal" + }, + "close_current_terminal_tab": { + "title": "Cerrar terminal actual", + "description": "Cierra la pestaña de terminal actual cuando el foco está en la terminal" + }, + "toggle_aux_panel": { + "title": "Alternar panel derecho", + "description": "Muestra u oculta el panel de información auxiliar" + }, + "new_conversation": { + "title": "Nueva conversación", + "description": "Crea una nueva pestaña de conversación en la carpeta actual" + }, + "open_folder": { + "title": "Abrir carpeta", + "description": "Abre el selector de carpetas y la carpeta en una nueva ventana" + }, + "open_settings": { + "title": "Abrir configuración", + "description": "Abre la ventana de configuración" + }, + "close_current_tab": { + "title": "Cerrar pestaña actual", + "description": "Cierra la conversación o pestaña de archivo actual" + }, + "close_all_file_tabs": { + "title": "Cerrar todas las pestañas de archivos", + "description": "Cierra todas las pestañas de archivos abiertas cuando el panel de archivos está activo" + }, + "next_tab": { + "title": "Pestaña siguiente", + "description": "Cambiar a la siguiente pestaña de conversación o archivo" + }, + "prev_tab": { + "title": "Pestaña anterior", + "description": "Cambiar a la pestaña anterior de conversación o archivo" + }, + "send_message": { + "title": "Enviar mensaje", + "description": "Enviar el mensaje actual en el cuadro de entrada" + }, + "newline_in_message": { + "title": "Nueva línea en mensaje", + "description": "Insertar una nueva línea en el cuadro de entrada" + }, + "toggle_custom_style": { + "title": "Suspender/reanudar estilo personalizado", + "description": "Vía de escape: desactiva todos los colores y el CSS personalizados, y los vuelve a activar" + } + } + }, + "SkillsSettings": { + "title": "Skills", + "description": "Selecciona una Skill a la izquierda. A la derecha se muestra una vista previa de Markdown por defecto; cambia a edición para modificar y guardar.", + "loadingAgents": "Cargando agentes compatibles con Skills...", + "emptyNoManageableAgents": "No hay agentes disponibles para gestionar Skills.", + "managedTarget": "Objetivo gestionado", + "selectAgentPlaceholder": "Selecciona un agente", + "searchPlaceholder": "Buscar por nombre / ID / ruta...", + "skillsList": "Lista de Skills", + "loadingSkills": "Cargando Skills...", + "agentNotSupported": "El agente actual no admite gestión de Skills.", + "emptySkills": "Aún no hay Skills. Haz clic en \"Nueva Skill\" para crear una.", + "newSkillTitle": "Nueva Skill", + "skillInfo": "Información de la Skill", + "skillIdPlaceholder": "skill-id (letras/números/-/_/.)", + "skillsDirectoryWithPath": "Directorio de Skills: {path}", + "skillsDirectoryNeedId": "Directorio de Skills: introduce el ID de Skill para generar la ruta completa", + "markdownContent": "Contenido Markdown", + "editingStatus": "Editando", + "previewStatus": "Vista previa", + "contentPlaceholder": "Introduce el contenido Markdown de la Skill...", + "metadataTitle": "Metadatos de Skills", + "onlyYamlMetadata": "Esta Skill solo contiene metadatos YAML.", + "emptyContentHint": "Aún no hay contenido. Haz clic en \"Editar\" para empezar.", + "loadingSkill": "Cargando Skill...", + "emptyNoAgents": "No hay agentes disponibles.", + "noSelectionHint": "Selecciona un Skill a la izquierda o haz clic en \"Nuevo Skill\" para crear uno.", + "systemBadge": "Sistema", + "systemHint": "Skill integrado del CLI · solo lectura", + "scope": { + "global": "Global", + "folder": "Carpeta", + "selectFolderPlaceholder": "Seleccionar una carpeta", + "noFolders": "No se encontraron carpetas", + "pickFolderHint": "Selecciona una carpeta para ver sus Skills." + }, + "actions": { + "preview": "Vista previa", + "edit": "Editar", + "openInWindow": "Abrir en nueva ventana", + "delete": "Eliminar", + "deleting": "Eliminando...", + "refresh": "Actualizar", + "newSkill": "Nueva Skill", + "reset": "Restablecer", + "save": "Guardar", + "saving": "Guardando...", + "cancel": "Cancelar" + }, + "deleteDialog": { + "title": "Eliminar Skill", + "confirm": "¿Eliminar la Skill actual? Esta acción no se puede deshacer.", + "confirmWithNamePrefix": "¿Eliminar la Skill", + "confirmWithNameSuffix": "? Esta acción no se puede deshacer." + }, + "toasts": { + "loadFailed": "No se pudo cargar la Skill", + "openFolderFailed": "No se pudo abrir la carpeta", + "noSkillDirectory": "No se encontró un directorio de Skills disponible para el agente actual", + "nameRequired": "El nombre de la Skill no puede estar vacío", + "updated": "Skill actualizada", + "created": "Skill creada", + "saveFailed": "No se pudo guardar la Skill", + "deleted": "Skill eliminada", + "deleteFailed": "No se pudo eliminar la Skill" + }, + "templates": { + "gemini": "---\nname: example-skill\ndescription: Describe when this skill should be used.\n---\n\n# Skill Name\n\nInstructions for the agent when this skill is active.\n\n## Workflow\n\n1. Add actionable step one.\n2. Add actionable step two.\n", + "openCode": "---\nname: example-skill\ndescription: Describe when this skill should be used.\n---\n\n# Purpose\n\nDescribe what this skill helps with.\n\n# Steps\n\n1. Add actionable step one.\n2. Add actionable step two.\n", + "openClaw": "---\nname: example-skill\ndescription: Describe when this skill should be used.\nuser-invocable: true\ndisable-model-invocation: false\n---\n\n# Purpose\n\nDescribe what this skill helps with.\n\n# Instructions\n\n1. Add actionable instruction one.\n2. Add actionable instruction two.\n", + "default": "---\nname: example-skill\ndescription: Describe when this skill should be used.\n---\n\n# Skill: example-skill\n\n## When to use\n\n- Describe trigger conditions.\n\n## Instructions\n\n1. Add actionable instruction one.\n2. Add actionable instruction two.\n" + } + }, + "McpSettings": { + "loading": "Cargando...", + "summary": { + "missingCommand": "(comando faltante)", + "missingUrl": "(URL faltante)" + }, + "protocol": { + "stdio": "Stdio" + }, + "errors": { + "selectInstallProtocol": "Selecciona un protocolo de instalación", + "fieldRequired": "{field} es obligatorio", + "fieldNeedsBoolean": "{field} debe ser true o false", + "fieldNeedsNumber": "{field} debe ser un número", + "fieldNeedsInteger": "{field} debe ser un entero", + "fieldInvalidJson": "{field} tiene JSON inválido: {message}", + "fieldOutOfRange": "El valor de {field} está fuera del rango permitido", + "jsonEmpty": "{name} no puede estar vacío", + "jsonInvalid": "{name} no es un JSON válido: {message}", + "jsonMustBeObject": "{name} debe ser un objeto JSON", + "specMustBeObject": "La configuración de MCP debe ser un objeto JSON.", + "missingType": "Falta el campo type en la configuración de MCP. Indica uno de stdio, http (alias: streamable-http, streamableHttp), sse.", + "unsupportedType": "Tipo de MCP no admitido {type}. Compatibles: stdio, http (alias: streamable-http, streamableHttp), sse.", + "codexEntryUnsupportedType": "La entrada Codex MCP {id} tiene un tipo no admitido {type}. Compatibles: stdio, http (alias: streamable-http, streamableHttp), sse.", + "unsupportedTransportType": "Tipo de transport no admitido {type}. Compatibles: http (alias: streamable-http, streamableHttp), sse.", + "stdioCommandRequired": "Los MCP stdio requieren un campo command no vacío.", + "remoteUrlRequired": "Los MCP remotos requieren un campo url no vacío.", + "appsRequired": "Selecciona al menos una aplicación de destino." + }, + "jsonNames": { + "localConfig": "Configuración MCP", + "installConfig": "Configuración de instalación" + }, + "toasts": { + "uninstalled": "MCP desinstalado", + "uninstallFailed": "Error al desinstalar: {message}", + "selectAtLeastOneApp": "Selecciona al menos una app de destino", + "saveSuccess": "Guardado", + "saveFailed": "Error al guardar: {message}", + "installed": "{name} instalado", + "installFailed": "Error al instalar: {message}", + "serverIdRequired": "Server ID es obligatorio", + "serverIdExists": "El Server ID \"{id}\" ya existe. Edita la entrada existente o usa un nombre diferente.", + "created": "MCP creado" + }, + "installDialog": { + "title": "Confirmar instalación de MCP", + "descriptionWithName": "Instalar {name} en la configuración local.", + "description": "Selecciona las apps de destino para la instalación.", + "protocol": "Protocolo", + "selectProtocol": "Seleccionar protocolo", + "parameters": "Parámetros de configuración", + "booleanPlaceholder": "Selecciona true/false", + "selectOneValue": "Selecciona un valor", + "targetApps": "Apps de destino" + }, + "actions": { + "cancel": "Cancelar", + "confirmInstall": "Confirmar instalación", + "installing": "Instalando", + "uninstall": "Desinstalar", + "uninstalling": "Desinstalando", + "viewDetails": "Ver detalles", + "save": "Guardar", + "saving": "Guardando", + "install": "Instalar", + "refresh": "Actualizar", + "newMcp": "Nuevo MCP", + "create": "Crear", + "creating": "Creando..." + }, + "tabs": { + "local": "MCP local", + "market": "Marketplace MCP" + }, + "local": { + "filterPlaceholder": "Filtrar MCP local...", + "loadFailed": "Error de carga: {message}", + "empty": "No se detectó MCP local.", + "description": "La configuración de MCP local se puede editar y guardar directamente.", + "enabledApps": "Apps habilitadas", + "configJson": "Configuración MCP (JSON)", + "draftTitle": "Nuevo MCP", + "draftDescription": "Indica un Server ID y la configuración para crear un servidor MCP local.", + "serverIdLabel": "Server ID", + "serverIdPlaceholder": "Server ID (p. ej. my-mcp)", + "typeHint": "Tipos admitidos: stdio, http (alias: streamable-http, streamableHttp), sse. env solo se usa con stdio; para MCP remotos usa headers para llevar tokens de autenticación.", + "envOnRemoteWarning": "Se detectó env en un MCP remoto. Solo stdio usa env; los MCP remotos llevan los tokens de autenticación en headers, así que env se ignorará al guardar." + }, + "market": { + "selectMarketplace": "Seleccionar marketplace", + "searchPlaceholder": "Buscar MCP...", + "searchFailed": "Error de búsqueda: {message}", + "loadingList": "Cargando lista de MCP...", + "empty": "Sin resultados de MCP.", + "loadingDetail": "Cargando detalles del marketplace...", + "detailLoadFailed": "No se pudieron cargar los detalles: {message}", + "owner": "Propietario: {owner}", + "namespace": "Espacio de nombres: {namespace}", + "defaultInstallProtocol": "Protocolo de instalación predeterminado", + "currentOptionParameterCount": "Cantidad de parámetros de la opción actual: {count}", + "installConfigDescription": "Configuración de instalación (JSON, editable antes de instalar; las ediciones sobrescribirán el formulario de protocolo/parámetros)", + "selectLeftToView": "Selecciona un MCP del marketplace a la izquierda para ver detalles." + }, + "badges": { + "verified": "Verificado", + "remote": "Remoto", + "hasHomepage": "Tiene página web", + "uses": "{count} usos", + "deployed": "Desplegado", + "notDeployed": "No desplegado" + }, + "selectLeftMcp": "Selecciona un MCP a la izquierda." + }, + "AcpAgentSettings": { + "title": "Gestión del SDK de agentes", + "description": "Gestiona en un solo lugar la conexión del SDK de agentes, estado habilitado, variables de entorno, gestión de configuración e información de preflight de versión.", + "loadingAgents": "Cargando lista de agentes...", + "agentList": "Lista de agentes", + "emptyNoAgent": "No hay agentes disponibles.", + "configManagement": "Gestión de configuración", + "envVars": "Variables de entorno", + "hostTools": { + "label": "Dejar que el agente gestione archivos y comandos", + "description": "codeg deja de atender el acceso a archivos y los comandos de terminal, de modo que el agente los ejecuta en su propio proceso, donde sí se aplican su sandbox y sus reglas de permisos. También se desactiva la delegación a otros agentes, ya que devolvería ese mismo trabajo a codeg. codeg no añade ningún sandbox propio, así que actívalo solo si el agente tiene uno configurado." + }, + "nativeJsonConfig": "Configuración JSON nativa", + "modelHintDefault": "Déjalo vacío para usar el modelo predeterminado del sistema.", + "generalConfigDescriptionClaude": "Admite configuración rápida de API URL, API Key y modelos de Claude, y sincroniza con la configuración JSON nativa.", + "generalConfigDescriptionDefault": "Admite entrada de configuración importante (API URL, API Key, Model) y gestión de configuración JSON nativa.", + "multiAgent": { + "title": "Colaboración multiagente", + "description": "Permite que los agentes activos deleguen subtareas a otros agentes.", + "enable": "Activar delegación", + "enableHint": "Cuando está desactivado, la herramienta delegate_to_agent se oculta del catálogo de herramientas MCP del agente.", + "withheldByHostTools": "{agents} no recibirán las herramientas de delegación: su interruptor por agente «Deja que el agente gestione archivos y comandos» está activado.", + "selfInitiate": "Allow spawn without @", + "selfInitiateHint": "When on, an agent may start a listed sub-agent on its own. An @ mention is still always honored. When off, only an @ mention starts a sub-agent.", + "depthLimit": "Profundidad máxima de delegación", + "depthHint": "Rango permitido: {min}–{max}. Limita la profundidad de recursión de una cadena de delegación (raíz → hijo → nieto …).", + "completedCacheLabel": "Caché de resultados completados (MB)", + "completedCacheHint": "Caché en memoria de los resultados completados de subagentes, que se conserva solo mientras la sesión de delegación está en ejecución y se libera automáticamente cuando esa sesión termina. Al superar este presupuesto, los resultados más antiguos se descartan primero de la memoria (aún visibles en la sesión propia del subagente); 0 = sin límite (igualmente se libera al terminar la sesión).", + "save": "Guardar", + "saving": "Guardando…", + "saved": "Configuración de delegación guardada", + "saveFailed": "Error al guardar la configuración de delegación", + "loadFailed": "Error al cargar la configuración de delegación: {detail}", + "tabGeneral": "General", + "tabAgentDefaults": "Valores por defecto del agente", + "agentDefaultsDescription": "Anulaciones por agente que se aplican cuando Colaboración multiagente inicia un subagente para una llamada de delegación. Las opciones mostradas provienen de un sondeo en vivo: lo que selecciones es exactamente lo que el agente aceptará.", + "probing": "Cargando las opciones disponibles del agente…", + "probeFailed": "Error al cargar las opciones: {detail}", + "retry": "Reintentar", + "noConfigAvailable": "Este agente no tiene opciones configurables.", + "modeLabel": "Modo", + "agentDefaultHint": "Predeterminado del agente: {value}", + "defaultOptionLabel": "Predeterminado ({value})" + }, + "actions": { + "dragSort": "Arrastrar para reordenar", + "dragSortAgent": "Arrastrar para reordenar {name}", + "refreshCheck": "Actualizar comprobación", + "refreshCheckAgent": "Actualizar comprobación de {name}", + "clickEnable": "Haz clic para habilitar {name}", + "clickDisable": "Haz clic para deshabilitar {name}", + "install": "Instalar", + "upgrade": "Actualizar", + "uninstall": "Desinstalar", + "uninstalling": "Desinstalando...", + "saveEnvVars": "Guardar variables de entorno", + "saving": "Guardando...", + "saveGrokConfig": "Guardar configuración de Grok", + "saveCodexConfig": "Guardar configuración de Codex", + "saveGeminiConfig": "Guardar configuración de Gemini", + "saveOpenCodeConfig": "Guardar configuración de OpenCode", + "saveOpenClawConfig": "Guardar configuración de OpenClaw", + "saveConfigManagement": "Guardar gestión de configuración", + "saveCurrentProvider": "Guardar proveedor actual", + "showApiKey": "Mostrar API Key", + "hideApiKey": "Ocultar API Key", + "showKey": "Mostrar clave", + "hideKey": "Ocultar clave", + "showToken": "Mostrar token", + "hideToken": "Ocultar token", + "cancel": "Cancelar", + "delete": "Eliminar", + "deleting": "Eliminando...", + "confirmDelete": "Confirmar eliminación", + "confirmUninstall": "Confirmar desinstalación", + "saveClineConfig": "Guardar configuración de Cline", + "saveHermesConfig": "Guardar configuración de Hermes", + "saveCodeBuddyConfig": "Guardar configuración de CodeBuddy", + "saveKimiCodeConfig": "Guardar configuración de Kimi Code", + "customInstall": "Instalación personalizada", + "saveKimiCodeRawConfig": "Save config.toml", + "saveDeepSeekConfig": "Guardar configuración de DeepSeek", + "diagnose": "Diagnosticar" + }, + "status": { + "enabled": "Habilitado", + "disabled": "Deshabilitado", + "unchecked": "Sin comprobar", + "agentEnabledAria": "{name} habilitado", + "agentEnabledSwitch": "Interruptor de habilitación de {name}" + }, + "preflight": { + "count": "Elementos de preflight: {count}", + "notRun": "Las comprobaciones aún no se han ejecutado." + }, + "grok": { + "configDescription": "Configura Grok aquí. Los controles siguientes —modo de permisos, esfuerzo de razonamiento, un modelo personalizado opcional (endpoint propio) y la compactación— se combinan en ~/.grok/config.toml, conservando tus otras claves y comentarios. El inicio de sesión usa tu XAI_API_KEY o `grok login`. Las demás claves siguen siendo editables en Avanzado.", + "permissionModeLabel": "Modo de permisos", + "permissionDefault": "Preguntar siempre", + "permissionAcceptEdits": "Aprobar ediciones automáticamente", + "permissionAuto": "Aprobación automática inteligente", + "permissionAlwaysApprove": "Aprobar siempre", + "reasoningEffortLabel": "Esfuerzo de razonamiento", + "effortLow": "Bajo (más rápido)", + "effortMedium": "Medio (equilibrado)", + "effortHigh": "Alto", + "effortXhigh": "Máximo", + "optionDefault": "Usar predeterminado", + "authTitle": "Autenticación", + "authMode": "Método de autenticación", + "authModeApiKey": "Clave de API de XAI", + "authModeApiKeyHint": "Autentícate con una XAI_API_KEY de la consola de xAI, para ejecuciones no interactivas o headless. Se guarda en el entorno de este agente.", + "authModeCustom": "Endpoint personalizado", + "authModeCustomHint": "Usa un endpoint propio (BYO): define abajo un modelo personalizado con su propia base URL y clave de API. Se convierte en el modelo predeterminado de Grok.", + "subscriptionHint": "Inicia sesión con `grok login` (SuperGrok / X Premium+). No se guarda ninguna clave de API.", + "loginHint": "Ejecuta esto en una terminal para iniciar sesión y luego vuelve a abrir esta configuración:", + "commandCopied": "Comando copiado al portapapeles", + "copyCommand": "Copiar comando", + "authKeyConfigured": "XAI_API_KEY está configurada.", + "authKeyMissing": "No hay XAI_API_KEY configurada.", + "advancedToggle": "Avanzado (config.toml sin procesar)", + "configTomlNative": "config.toml (nativo)", + "configTomlHint": "Se guarda literalmente como todo el ~/.grok/config.toml. El TOML no válido se rechaza para que una errata no trunque tu archivo.", + "configTomlPlaceholder": "# Claves distintas de los controles de arriba, p. ej.\n# [mcp_servers.*], [cli], reglas [permission].", + "customModelTitle": "Modelo personalizado (endpoint propio)", + "customModelHint": "Apunta Grok a un endpoint personalizado o autoalojado. codeg escribe un bloque `[model.*]` por modelo y lo establece como predeterminado. Deja el ID de modelo vacío para eliminarlo.", + "customModelIdLabel": "ID del modelo", + "customModelIdPlaceholder": "grok-4.5", + "customModelIdHint": "Se registra como un bloque `[model.*]` y se envía a la API como nombre del modelo; también se establece como `[models].default`.", + "customBaseUrlLabel": "URL base", + "customBaseUrlPlaceholder": "https://api.x.ai/v1 (predeterminado)", + "customApiBackendLabel": "Backend de la API", + "backendResponses": "Responses", + "backendChatCompletions": "Chat Completions", + "backendMessages": "Messages (Anthropic)", + "customApiKeyLabel": "Clave de API", + "customApiKeyHint": "Se guarda en línea en `[model.*].api_key`, limitada a este endpoint.", + "customContextWindowLabel": "Ventana de contexto (tokens)", + "customContextWindowHint": "Opcional. Determina el momento de la autocompactación; déjalo vacío para el valor predeterminado del endpoint.", + "autoCompactLabel": "Umbral de autocompactación (%)", + "autoCompactHint": "Compacta la conversación cuando el uso del contexto alcanza este porcentaje (predeterminado de Grok: 85). Se escribe en `[session]`." + }, + "cursor": { + "configDescription": "Configura Cursor aquí. Elige un método de autenticación —suscripción oficial (inicio de sesión en el navegador) o una clave API de Cursor para equipos sin interfaz o servidores— y luego elige un modelo y edita las reglas de permisos y el sandbox del CLI. codeg los escribe en ~/.cursor/cli-config.json, compartido con el CLI cursor-agent.", + "authTitle": "Autenticación", + "authChecking": "Comprobando…", + "authNotInstalled": "cursor-agent no está instalado", + "authLoggedIn": "Sesión iniciada", + "authNotLoggedIn": "Sin sesión", + "loginHint": "Ejecuta esto en una terminal para iniciar sesión con tu cuenta de Cursor (se abre el navegador) y luego pulsa actualizar:", + "apiKeyLabel": "Clave API de Cursor", + "apiKeyPlaceholder": "clave de cursor.com/dashboard", + "apiKeyHint": "CURSOR_API_KEY: una clave de cuenta del panel de Cursor, alternativa al inicio de sesión en el navegador para equipos sin interfaz o servidores. No es una clave de terceros ni de OpenAI.", + "modelTitle": "Modelo predeterminado", + "loadModels": "Cargar modelos", + "modelsUnavailable": "Lista de modelos no disponible", + "modelHint": "Se pasa a la CLI como --model al iniciar la sesión. Déjalo en predeterminado para que Cursor elija.", + "permissionsTitle": "Permisos y sandbox", + "permissionsDescription": "Editor visual de las reglas de permisos de la CLI (cli-config.json). Las reglas permitidas se ejecutan sin confirmación; las denegadas se bloquean siempre.", + "permissionModeLabel": "Modo de permisos", + "permissionModeDefault": "Preguntar antes de ejecutar (predeterminado)", + "permissionModeForce": "Run Everything (--force)", + "permissionModeHint": "Run Everything inicia las sesiones con --force: todas las llamadas de herramientas se permiten automáticamente salvo las reglas de denegación, sin confirmaciones (una política de la organización puede limitarlo a las reglas de permiso). Se aplica a las sesiones nuevas.", + "optionDefault": "Predeterminado (sin definir)", + "sandboxLabel": "Sandbox", + "sandboxEnabled": "Activado", + "sandboxDisabled": "Desactivado", + "allowRulesLabel": "Reglas permitidas", + "denyRulesLabel": "Reglas denegadas", + "addRule": "Añadir regla", + "rulesSyntaxHint": "Sintaxis de reglas: Shell(cmd), Read(ruta/glob), Write(ruta/glob), WebFetch(dominio), Mcp(servidor:herramienta) — las reglas de denegación siempre prevalecen.", + "saveConfig": "Guardar configuración", + "advancedToggle": "Avanzado: cli-config.json sin procesar", + "advancedHint": "El ~/.cursor/cli-config.json completo. Guardar escribe el archivo tal cual; los controles estructurados de arriba se fusionan en él.", + "saveRawConfig": "Guardar archivo", + "authMode": "Método de autenticación", + "subscriptionHint": "Inicia sesión con tu cuenta de Cursor y usa los modelos de Cursor.", + "customApiKeyRequired": "Se requiere una clave API de Cursor.", + "authModeApiKey": "Clave API de Cursor (sin interfaz)", + "authModeApiKeyHint": "Autentícate con una clave API de cuenta de Cursor generada en el panel de Cursor (para equipos sin interfaz o servidores). Es una clave de cuenta de Cursor, no un endpoint de terceros/OpenAI: cursor-agent solo se comunica con el backend de Cursor. Para usar un endpoint compatible con codex/OpenAI, usa el agente Codex en su lugar.", + "modelPickerPlaceholder": "Buscar modelos…", + "modelNoMatch": "Ningún modelo coincide", + "modelsNeedAuth": "Inicia sesión para cargar la lista de modelos.", + "modelDefaultBadge": "predeterminado" + }, + "deepseek": { + "configManagement": "Configuración de DeepSeek Harness", + "configDescription": "El endpoint y la clave son variables de entorno que deepseek-acp lee al arrancar. El modelo y el esfuerzo de razonamiento son selectores por sesión: se eligen en el campo de mensaje.", + "baseUrlLabel": "Endpoint de la API", + "baseUrlHint": "Déjalo vacío para el endpoint oficial. Se aplica a las sesiones iniciadas tras guardar; vuelve a conectar una sesión en curso para que lo tome.", + "baseUrlInvalid": "Introduce una URL http(s) completa y sin cadena de consulta, por ejemplo https://api.deepseek.com", + "apiKeyLabel": "Clave de API", + "apiKeyHint": "Se pasa al agente como DEEPSEEK_API_KEY. Una variable de entorno tiene prioridad sobre el archivo de credenciales, así que déjala vacía si inicias sesión desde la terminal." + }, + "codex": { + "configDescription": "Admite configuración rápida de URL de API, API Key, nombre del modelo y reasoning effort, y sincroniza con `auth.json` / `config.toml`.", + "authMode": "Modo de Autenticación", + "chatgptSubscription": "Suscripción oficial", + "chatgptSubscriptionHint": "Iniciar sesión con suscripción oficial de ChatGPT, sin necesidad de API Key", + "apiKeyHint": "Conectar usando API Key a OpenAI o servicios API compatibles", + "selectProvider": "Seleccionar proveedor", + "modelName": "Nombre del modelo", + "selectReasoningEffort": "Seleccionar Reasoning Effort", + "enableWebsocket": "Habilitar WebSocket", + "enableWebsocketAria": "Habilitar WebSocket para Codex Provider", + "enableSkills": "Habilitar Skills", + "enableSkillsAria": "Habilitar Skills para Codex", + "enableFast": "Habilitar Fast", + "enableFastAria": "Habilitar nivel de servicio Fast para Codex", + "sandboxGroupTitle": "Sandbox y aprobaciones", + "sandboxGroupHint": "Se escribe en el ~/.codex/config.toml global, por lo que también lo ven las sesiones de codex CLI e IDE. Son valores predeterminados del hilo: rigen los turnos que codex inicia por su cuenta (/goal, /review, /compact). Los mensajes normales usan el preajuste de aprobación del compositor. Reinicia una sesión para aplicar los cambios.", + "sandboxShadowedWarning": "config.toml define default_permissions, así que codex resuelve los permisos con ese perfil e ignora sandbox_mode por completo. Elimina default_permissions para usar los controles de abajo.", + "sandboxPermissionsTableWarning": "config.toml define perfiles [permissions] pero no default_permissions, lo que impide que codex arranque. Configúralo en el editor sin formato de abajo.", + "approvalPolicyLabel": "Política de aprobación", + "approvalPolicyUnset": "Sin definir (predeterminado de codex: a petición)", + "approvalPolicy_on-request": "A petición: el modelo decide cuándo preguntar", + "approvalPolicy_untrusted": "No confiable: solo se ejecutan sin supervisión los comandos de solo lectura seguros", + "approvalPolicy_never": "Nunca: sin ninguna solicitud de aprobación", + "approvalPolicy_granular": "Granular: elige por tipo de solicitud", + "approvalPolicyUntrustedAcpWarning": "Untrusted no tiene equivalente entre los tres ajustes de aprobación del adaptador ACP, así que las sesiones de codeg recurren a «a petición»: el modelo decide entonces cuándo preguntar y los comandos que la zona aislada ya permite dejan de pedir confirmación. Restringe mejor el modo de aislamiento de abajo.", + "granularHint": "Desactivado significa que ese tipo de solicitud se rechaza automáticamente en vez de mostrártela.", + "granular_sandbox_approval": "Escalados de comandos de shell", + "granular_rules": "Avisos de reglas de execpolicy", + "granular_skill_approval": "Avisos de scripts de habilidades", + "granular_request_permissions": "Avisos de la herramienta request_permissions", + "granular_mcp_elicitations": "Avisos de elicitación MCP", + "sandboxModeLabel": "Modo de sandbox", + "sandboxModeUnset": "Sin definir (las carpetas de confianza usan escritura en el espacio de trabajo)", + "sandboxMode_read-only": "Solo lectura", + "sandboxMode_workspace-write": "Escritura en el espacio de trabajo", + "sandboxMode_danger-full-access": "Acceso total (sin sandbox)", + "sandboxModeHint": "En Windows, la escritura en el espacio de trabajo baja a solo lectura salvo que actives el sandbox experimental de Windows de codex.", + "sandboxModeSeedsPresetHint": "codeg también lo traduce al ajuste de aprobación inicial de la sesión, así que —a diferencia de la política de aprobación— sí afecta a las peticiones normales. El ajuste elegido en el editor sigue teniendo prioridad.", + "writableRootsLabel": "Carpetas adicionales con escritura", + "writableRootsHint": "Una ruta absoluta por línea, además del directorio de trabajo.", + "sandboxRootsRelativeError": "Debe ser una ruta absoluta: codex resuelve las rutas relativas dentro de ~/.codex: {path}", + "networkAccessLabel": "Permitir acceso a la red", + "excludeTmpdirLabel": "Excluir TMPDIR de las raíces con escritura", + "excludeSlashTmpLabel": "Excluir /tmp de las raíces con escritura", + "authJsonNative": "auth.json (nativo)", + "configTomlNative": "config.toml (nativo)", + "loginButton": "Iniciar sesión con ChatGPT", + "loginRequesting": "Solicitando código de inicio de sesión...", + "loginStep1": "Abre la siguiente URL en tu navegador:", + "loginStep2": "Introduce el siguiente código:", + "loginPolling": "Esperando autorización...", + "loginCancel": "Cancelar", + "loginSuccess": "¡Inicio de sesión exitoso, configuración guardada!", + "loginFailed": "Error de inicio de sesión: {message}", + "loginRetry": "Reintentar", + "loginCodeCopied": "Código copiado", + "loggedIn": "Cuenta conectada", + "loginRelogin": "Reconectar / Cambiar cuenta", + "loginTimeout": "Tiempo de inicio de sesión agotado, inténtalo de nuevo", + "loginSaveFailed": "Inicio de sesión exitoso pero falló al guardar la configuración" + }, + "gemini": { + "authConfig": "Configuración de autenticación de Gemini", + "authConfigDescription": "Alineado con la documentación de autenticación de Gemini CLI, con soporte para endpoint personalizado, inicio de sesión de Google, Gemini API Key y Vertex AI (ADC / cuenta de servicio / API Key).", + "authMode": "Modo de autenticación", + "selectAuthMode": "Seleccionar modo de autenticación", + "viewAuthDoc": "Ver documentación de autenticación", + "mode": { + "custom": "Endpoint personalizado", + "loginGoogle": "Inicio de sesión de Google (OAuth)", + "vertexServiceAccount": "Vertex AI (Cuenta de servicio)" + }, + "hint": { + "custom": "Completa API URL, API Key y Modelo; se mapean a GOOGLE_GEMINI_BASE_URL / GEMINI_API_KEY / GEMINI_MODEL.", + "loginGoogle": "Ejecuta gemini en terminal y completa primero el inicio de sesión de Google; no se requiere API key.", + "geminiApiKey": "Completa GEMINI_API_KEY cuando uses la API de Gemini.", + "vertexAdc": "Usa gcloud ADC; se recomienda configurar GOOGLE_CLOUD_PROJECT y GOOGLE_CLOUD_LOCATION.", + "vertexServiceAccount": "Establece la ruta del JSON de la cuenta de servicio en GOOGLE_APPLICATION_CREDENTIALS.", + "vertexApiKey": "Completa GOOGLE_API_KEY cuando uses API key de Vertex AI." + } + }, + "openCode": { + "configManagement": "Gestión de configuración de OpenCode", + "configDescription": "Alineado con el esquema `provider` de OpenCode, admite gestión de múltiples proveedores y sincronización bidireccional con archivos JSON nativos.", + "providerManagement": "Gestión de proveedores", + "providerCount": "{count} proveedores", + "addProvider": "Agregar proveedor", + "emptyProvider": "Aún no hay proveedores personalizados. Haz clic en Agregar proveedor personalizado para crear uno.", + "providerEnabledState": "Estado habilitado de {providerId}", + "selectProviderNpm": "Seleccionar provider.npm", + "modelManagement": "Gestión de modelos", + "modelCount": "{count} modelos", + "modelDescription": "Alineado con `provider.models` de OpenCode. La gestión rápida actualmente soporta `name` / `id`; otros campos avanzados se conservan y se pueden editar en el JSON nativo de abajo.", + "addModel": "Agregar modelo", + "emptyModel": "Aún no hay modelo. Introduce model id y haz clic en \"Agregar modelo\".", + "modelId": "ID de modelo", + "modelName": "Nombre del modelo", + "deleteModel": "Eliminar modelo {modelId}", + "nativeJsonConfig": "Configuración JSON nativa de OpenCode", + "mainModel": "Modelo principal", + "smallModel": "Modelo pequeño", + "noMatchingModels": "No hay modelos coincidentes", + "connectProvider": "Conectar proveedor", + "connectedProviders": "Proveedores conectados", + "noConnectedProviders": "Aún no hay proveedores del catálogo conectados.", + "advancedProviderConfig": "Proveedores personalizados", + "customProviderConfigHint": "Endpoints compatibles con OpenAI que defines tú mismo: un bloque de provider en opencode.json, con la API key en auth.json.", + "addCustomProvider": "Agregar proveedor personalizado", + "disconnect": "Desconectar", + "editConfig": "Editar", + "customBadge": "Personalizado", + "authKindApi": "Clave API", + "authKindOauth": "OAuth", + "authKindNone": "Sin credencial", + "connect": { + "title": "Conectar un proveedor", + "description": "Elige un proveedor del catálogo de models.dev. Las credenciales se guardan en el archivo auth.json de OpenCode.", + "pick": "Proveedor", + "search": "Buscar proveedores…", + "loading": "Cargando catálogo…", + "catalogLabel": "Catálogo de models.dev", + "modelsAvailable": "{count} modelos disponibles", + "getKey": "Obtener clave API", + "oauthApiKeyNote": "Este proveedor también admite el inicio de sesión por navegador con opencode auth login. El inicio por navegador llegará pronto; por ahora, pega una clave API.", + "apiKey": "Clave API", + "apiKeyHint": "Se guarda en auth.json, nunca en opencode.json.", + "baseUrlOptional": "Anular Base URL (opcional)", + "providerId": "ID del proveedor", + "displayName": "Nombre visible", + "modelsList": "Modelos (uno por línea)", + "modelsHint": "IDs de modelo que acepta el endpoint.", + "action": "Conectar", + "editTitle": "Editar proveedor", + "editDescription": "Actualiza la clave API o la Base URL de este proveedor.", + "saveAction": "Guardar" + }, + "customProvider": { + "title": "Agregar un proveedor personalizado", + "description": "Define un endpoint compatible con OpenAI. La API key se guarda en auth.json; el bloque de provider va a opencode.json.", + "action": "Agregar proveedor", + "idInCatalog": "{providerId} es un proveedor conocido: conéctalo mediante Conectar proveedor." + }, + "refreshCatalog": "Actualizar catálogo", + "reasoningBadge": "razonamiento", + "contextWindow": "Ventana de contexto", + "permissions": { + "title": "Permisos", + "description": "Decide qué acciones se ejecutan solas, cuáles te preguntan primero y cuáles se bloquean. Se escribe en el bloque permission de opencode.json y se aplica al guardar abajo.", + "docsLink": "Documentación de permisos", + "unparsableConfig": "El JSON nativo de abajo no es válido, así que el editor visual está pausado. Corrige el JSON para continuar.", + "invalidBlock": "El bloque permission tiene una forma que codeg no reconoce. Edítalo en el JSON nativo de abajo o usa Restablecer para empezar de nuevo.", + "orderingUnsafe": "Hay una regla comodín escrita después de herramientas concretas, así que OpenCode también se la aplica a ellas: las filas de abajo no son lo que está en vigor. Corregir orden solo devuelve cada comodín al principio de su ámbito, sin cambiar ningún valor.", + "orderingUnsafeManual": "Una regla queda tapada por un patrón posterior más general, así que OpenCode nunca la aplica: las filas de abajo no son lo que está en vigor. Dos patrones que se solapan no tienen un único orden correcto; reordénalos en el JSON nativo para que el más general vaya primero.", + "fixOrder": "Corregir orden", + "agentOverrides": "Estos agentes anulan los permisos y se aplican al final, así que ganan sobre todo lo de aquí: {agents}. Edítalos en el JSON nativo de abajo o activa el aceptar automático para borrarlos.", + "legacyTools": "El mapa tools heredado del nivel superior deniega una herramienta. OpenCode lo fusiona con los permisos, así que se aplica por encima de todo lo que se ve aquí. Edítalo en el JSON nativo de abajo o activa el aceptar automático para borrarlo.", + "autoAcceptTitle": "Aceptar todos los permisos automáticamente", + "autoAcceptHint": "Toda llamada a herramientas —comandos de shell, ediciones de archivos, rutas fuera del proyecto— se ejecuta sin preguntar. Al activarlo, los ajustes por herramienta de abajo se sustituyen por una única regla que lo permite todo, y se borran las anulaciones por agente y los conmutadores tools heredados que si no seguirían bloqueando.", + "globalLabel": "Valor global por defecto", + "globalHint": "La regla *: se aplica a todo lo que las herramientas de abajo no anulen.", + "actionUnset": "Sin definir (valores de OpenCode)", + "actionInherit": "Heredar ({action})", + "actionAllow": "Permitir", + "actionAsk": "Preguntar", + "actionDeny": "Denegar", + "perToolTitle": "Permisos por herramienta", + "reset": "Restablecer", + "ruleCount": "reglas: {count}", + "rulesToggle": "Reglas detalladas de {tool}", + "rulesHint": "Se comparan con la entrada de la herramienta y gana la última coincidencia, así que pon primero los patrones amplios. * coincide con cualquier cantidad de caracteres, ? con exactamente uno, y un ~ inicial se expande a tu carpeta personal.", + "noRules": "Todavía no hay reglas detalladas.", + "addRule": "Añadir regla", + "deleteRule": "Eliminar la regla {pattern}", + "duplicateRule": "Ese patrón ya existe.", + "blankRule": "Una regla necesita un patrón; usa el icono de papelera para eliminarla.", + "customKeys": "Otras claves de permiso del archivo", + "customKeyHint": "No es una herramienta integrada de OpenCode; se conserva tal cual.", + "keys": { + "bash": "Ejecutar comandos de shell, según el comando analizado", + "edit": "Todas las modificaciones de archivos: edit, write y patch", + "read": "Leer archivos, según la ruta", + "external_directory": "Acceder a rutas fuera del directorio de trabajo del proyecto", + "task": "Lanzar subagentes, según el tipo de subagente", + "skill": "Cargar habilidades, según su nombre", + "glob": "Buscar archivos, según el patrón glob", + "grep": "Buscar en el contenido de los archivos, según el patrón", + "list": "Listar el contenido de un directorio", + "webfetch": "Descargar una URL", + "websearch": "Buscar en la web", + "lsp": "Ejecutar consultas LSP", + "todowrite": "Escribir la lista de tareas", + "question": "Hacerte una pregunta", + "doom_loop": "Se activa cuando la misma llamada se repite tres veces con la misma entrada" + } + } + }, + "openClaw": { + "gatewayConfig": "Configuración de Gateway", + "gatewayDescription": "Configura la conexión de OpenClaw Gateway. Admite gateway local o remoto.", + "gatewayUrlHint": "Déjalo vacío para usar gateway.remote.url desde la configuración local de openclaw.", + "gatewayTokenPlaceholder": "Token de autenticación de Gateway", + "gatewayTokenHint": "Usa token-file en lugar de token en texto plano cuando sea posible; configúralo con el CLI de openclaw.", + "sessionKeyHint": "Opcional. Especifica la session key del gateway; si se deja vacío se asigna automáticamente una sesión aislada." + }, + "hermes": { + "configManagement": "Configuración de Hermes", + "configDescription": "Hermes gestiona sus propias credenciales en ~/.hermes/.env y los ajustes en ~/.hermes/config.yaml. Elige un proveedor y luego establece la clave de API y el modelo: codeg escribe ambos archivos por ti.", + "providerLabel": "Proveedor", + "providerHint": "El proveedor determina qué variable de clave de API y qué model.provider usa Hermes. Los proveedores de OAuth se configuran mediante la configuración del terminal que aparece a continuación.", + "groupApiKey": "Proveedores con clave API", + "groupOauth": "Proveedores OAuth", + "groupAws": "AWS", + "apiKeyHint": "Se guarda en ~/.hermes/.env. Nunca se inyecta en el proceso: Hermes la lee de su propia configuración.", + "modelName": "Modelo", + "oauthHint": "Este proveedor usa OAuth. Ejecuta la configuración de abajo para autenticarte en tu terminal.", + "awsHint": "Bedrock usa tus credenciales de AWS (entorno o configuración compartida). Define el ID del modelo arriba y configura el acceso a AWS en tu entorno.", + "unsupportedProvider": "Este proveedor no se puede editar con campos estructurados. Usa el editor de config.yaml de abajo o la configuración por terminal.", + "setupTitle": "Configuración autogestionada", + "setupHint": "La configuración interactiva de Hermes necesita un terminal. Iníciala abajo o copia el comando para ejecutarlo tú mismo.", + "runSetup": "Ejecutar configuración de Hermes", + "configureModel": "Configurar modelo", + "openConfigFolder": "Abrir ~/.hermes", + "copyCommand": "Copiar comando", + "commandCopied": "Comando copiado al portapapeles", + "advancedTitle": "Avanzado: editar config.yaml", + "rawConfigHint": "Edita ~/.hermes/config.yaml directamente. Guardar aquí sobrescribe el archivo tal cual.", + "saveRawConfig": "Guardar config.yaml" + }, + "codebuddy": { + "configManagement": "Configuración de CodeBuddy", + "configDescription": "CodeBuddy se autentica con una clave de API. Las versiones para China continental también requieren establecer el entorno en «China (internal)»; las versiones iOA usan «iOA». La versión internacional lo deja sin definir.", + "apiKeyLabel": "Clave de API", + "apiKeyHint": "Se guarda como CODEBUDDY_API_KEY para este agente. También puedes iniciar sesión con la CLI de CodeBuddy en una terminal.", + "apiKeyHintSelfHosted": "Se guarda como CODEBUDDY_API_KEY para este agente. Usa la clave emitida por tu implementación privada.", + "environmentLabel": "Entorno", + "environmentHint": "Establece CODEBUDDY_INTERNET_ENVIRONMENT. China continental debe usar «China (internal)»; la versión internacional lo deja sin definir.", + "envOverseas": "Internacional (predeterminado)", + "envChina": "China (internal)", + "envIoa": "iOA", + "envSelfHosted": "Autoalojado (implementación privada)", + "baseUrlLabel": "URL de implementación", + "baseUrlPlaceholder": "https://codebuddy.your-company.com", + "baseUrlHint": "Se guarda como CODEBUDDY_BASE_URL y dirige CodeBuddy a tu endpoint privado. En autoalojado, el entorno de red (CODEBUDDY_INTERNET_ENVIRONMENT) queda sin configurar.", + "baseUrlInvalid": "Introduce una URL http(s) válida.", + "loginHint": "¿No tienes clave de API? Ejecuta «codebuddy» en una terminal para iniciar sesión con tu cuenta de Tencent." + }, + "kimiCode": { + "configManagement": "Configuración de Kimi Code", + "configDescription": "`kimi acp` solo acepta un token de sesión almacenado, así que codeg escribe un proveedor gestionado en ~/.kimi-code/config.toml y siembra un token de acceso local: la inferencia sigue usando tu propia clave.", + "statusUnconfigured": "Sin configurar", + "statusDirty": "Cambios sin guardar", + "summaryLabel": "En vigor", + "gateReadyApiKey": "Clave de API escrita en config.toml", + "gateReadyLogin": "Sesión iniciada con una cuenta de Kimi", + "revealConfig": "Mostrar en la carpeta", + "envOverrideWarning": "{keys} está definido y tiene prioridad sobre config.toml. Al guardar aquí se elimina.", + "authModeLabel": "Método de autenticación", + "authModeApiKey": "Clave de API", + "authModeLogin": "Inicio de sesión de Kimi (suscripción)", + "authModeApiKeyHint": "Escribe un proveedor gestionado en config.toml y siembra el token de acceso para que las sesiones puedan abrirse.", + "loginHint": "Ejecuta `kimi login` en una terminal para iniciar sesión con una cuenta de suscripción de Kimi. codeg no guarda nada y reutiliza el inicio de sesión de Kimi. Guardar aquí elimina el token de acceso por clave de API de codeg.", + "credentialTitle": "Credencial", + "interfaceTypeLabel": "Tipo de proveedor", + "interfaceTypeHint": "El protocolo de proveedor que habla Kimi (el `type` de config.toml). Usa Kimi / Moonshot para una clave de Moonshot / platform.kimi.com.", + "endpointLabel": "Endpoint", + "endpointCustom": "Personalizado (compatible con OpenAI)", + "endpointHint": "Internacional = api.moonshot.ai; China (claves de platform.kimi.com) = api.moonshot.cn. Personalizado apunta a cualquier endpoint compatible con OpenAI.", + "regionInternational": "Internacional (api.moonshot.ai)", + "regionChina": "China (api.moonshot.cn)", + "baseUrlLabel": "URL base", + "baseUrlHint": "Déjalo en blanco para usar el valor por defecto del SDK del proveedor.", + "apiKeyLabel": "Clave de API", + "apiKeyHint": "Se escribe en ~/.kimi-code/config.toml y se usa para la inferencia. De platform.kimi.com o platform.kimi.ai.", + "vertexProjectLabel": "Proyecto de GCP (GOOGLE_CLOUD_PROJECT)", + "vertexLocationLabel": "Región de GCP (GOOGLE_CLOUD_LOCATION)", + "vertexHint": "Vertex AI usa las credenciales predeterminadas de aplicación de Google: ejecuta `gcloud auth application-default login` (sin clave de API).", + "modelTitle": "Modelo", + "modelLabel": "Modelo", + "modelHint": "El id de modelo que se escribe en config.toml. Usa «Probar y listar modelos» para ver a cuáles puede acceder tu clave.", + "maxContextLabel": "Tamaño máximo de contexto", + "maxContextHint": "Obligatorio según el esquema de Kimi: sin él, Kimi descarta todo el bloque del modelo y ninguna consulta devuelve respuesta. Por defecto 262144.", + "fetchModels": "Probar y listar modelos", + "fetchModelsOk": "La clave funciona: {count} modelos disponibles", + "fetchModelsEmpty": "La clave funciona, pero no se devolvió ningún modelo", + "fetchModelsFailed": "La prueba falló", + "fetchModelsNeedsKey": "Introduce primero una clave de API y un endpoint", + "modelNotInList": "Este modelo no está en la lista a la que tu clave puede acceder: Kimi fallará con «modelo no encontrado».", + "reasoningTitle": "Razonamiento", + "reasoningEnableLabel": "Activar", + "reasoningDescription": "Kimi solo muestra el selector «Thinking» en el cuadro de mensaje cuando el modelo declara una capacidad de razonamiento, así que codeg la escribe aquí. Se aplica a las sesiones nuevas.", + "effortsLabel": "Niveles ofrecidos", + "effortsHint": "Estos son los niveles que aparecerán en el selector «Thinking». Kimi los reenvía al proveedor tal cual, así que elige los que acepte tu modelo.", + "effortsEmptyHint": "Sin ningún nivel elegido, el cuadro de mensaje se reduce a un simple interruptor Off / On.", + "effortsCustomPlaceholder": "Añadir otro nivel", + "effortsAdd": "Añadir", + "defaultEffortLabel": "Nivel por defecto", + "defaultEffortAuto": "Que elija Kimi", + "alwaysThinkingLabel": "El modelo siempre razona: quitar la opción Off del selector", + "fixErrorsFirst": "Corrige primero los campos marcados", + "errorModelRequired": "El modelo es obligatorio", + "errorMaxContextRequired": "El tamaño máximo de contexto es obligatorio", + "errorMaxContextInvalid": "Debe ser un entero positivo", + "errorApiKeyRequired": "La clave de API es obligatoria", + "errorApiKeyInvalid": "La clave de API no puede contener saltos de línea", + "errorBaseUrlRequired": "La URL base es obligatoria", + "errorBaseUrlInvalid": "Debe empezar por http:// o https://", + "errorVertexProjectRequired": "El proyecto de GCP es obligatorio", + "errorDefaultEffortUnlisted": "Elige uno de los niveles seleccionados arriba", + "advancedTitle": "Avanzado", + "authTypeLabel": "Ubicación de la credencial", + "authTypeApiKey": "api_key en línea", + "authTypeEnv": "Subtabla env del proveedor", + "authTypeHint": "Dónde se escribe la clave de API dentro de config.toml.", + "rawEditorLabel": "Editar config.toml directamente", + "rawEditorWarning": "Guardar aquí sobrescribe el archivo completo tal cual y reemplaza la configuración estructurada de arriba.", + "rawEditorPlaceholder": "[providers.codeg]\ntype = \"kimi\"\nbase_url = \"https://api.moonshot.cn/v1\"\napi_key = \"sk-...\"" + }, + "authModeOfficialSubscription": "Suscripción oficial", + "authModeCustomEndpoint": "Endpoint personalizado", + "authModeCustomEndpointHint": "Configurar manualmente la URL de API y la clave API para un endpoint personalizado.", + "authModeModelProvider": "Proveedor de modelo", + "modelProvider": "Proveedor de modelo", + "modelProviderHint": "Usar la URL de API, la clave API y el modelo de un proveedor de modelo configurado.", + "selectModelProvider": "Seleccionar proveedor de modelo", + "noModelProviderAvailable": "No hay proveedor de modelo configurado para este agente. Vaya a la configuración de proveedores de modelo para agregar uno.", + "claude": { + "authMode": "Modo de autenticación", + "officialSubscription": "Suscripción oficial", + "officialSubscriptionHint": "Usar la suscripción oficial de Anthropic, no se requiere API Key.", + "mainModel": "Modelo principal", + "reasoningModel": "Modelo de razonamiento (thinking)", + "haikuDefaultModel": "Modelo Haiku predeterminado", + "sonnetDefaultModel": "Modelo Sonnet predeterminado", + "opusDefaultModel": "Modelo Opus predeterminado", + "customModelOption": "ID de modelo personalizado", + "customModelOptionName": "Nombre del modelo personalizado", + "customModelOptionDescription": "Descripción del modelo personalizado", + "customModelOptionHint": "Añade una única entrada personalizada al selector de modelos de Claude (por ejemplo, un modelo detrás de una pasarela/proxy personalizado). El nombre y la descripción son opcionales y solo afectan a la visualización.", + "effortLevel": "Nivel de razonamiento", + "effortLevelDefault": "Nivel predeterminado", + "effortLevel_low": "Bajo", + "effortLevel_medium": "Medio", + "effortLevel_high": "Alto", + "effortLevel_xhigh": "Extra Alto", + "sendAttributionHeader": "Enviar identificador de atribución/facturación a la API", + "sendAttributionHeaderAria": "Enviar el identificador de atribución/facturación de Claude Code a la API", + "disableNonessentialTraffic": "Desactivar la telemetría o las solicitudes de red innecesarias", + "disableNonessentialTrafficAria": "Desactivar la telemetría o las solicitudes de red innecesarias de Claude Code" + }, + "dialogs": { + "confirmDeleteProvider": "¿Eliminar proveedor {providerId}?", + "confirmDeleteProviderDescription": "La configuración de OpenCode y auth JSON se actualizarán juntos. Esta acción no se puede deshacer.", + "confirmUninstall": "¿Desinstalar {name}?", + "confirmUninstallDescription": "Esto elimina la versión instalada localmente. Puedes reinstalar más tarde.", + "customInstallTitle": "Instalación personalizada de {name}", + "customInstallDescription": "Introduce la versión que quieres instalar. Se reinstalará y reemplazará la versión instalada actualmente.", + "customInstallVersionLabel": "Número de versión", + "customInstallInvalid": "Introduce un número de versión válido, p. ej. 1.2.3.", + "customInstallSubmit": "Instalar" + }, + "errors": { + "windowsFileLocked": "Los archivos de {name} están en uso por una sesión activa, por lo que Windows no puede reemplazarlos. Cierra todas las sesiones de {name} e inténtalo de nuevo.", + "nativeJsonMustBeObject": "La configuración JSON nativa debe ser un objeto", + "nativeJsonInvalid": "Error de formato en JSON nativo: {message}", + "openCodeAuthMustBeObject": "OpenCode auth.json debe ser un objeto JSON", + "openCodeAuthInvalid": "Error de formato en OpenCode auth.json: {message}", + "authMustBeObject": "auth.json debe ser un objeto JSON", + "authInvalid": "Error de formato en auth.json: {message}", + "providerIdPattern": "El ID de proveedor solo admite letras, números, guion bajo, punto y guion", + "providerExists": "El proveedor {providerId} ya existe", + "modelIdPattern": "El ID de modelo solo admite letras, números, guion bajo, punto, dos puntos y guion", + "modelExists": "El modelo {modelId} ya existe" + }, + "warnings": { + "nativeJsonRecoveredStructured": "La configuración JSON nativa es inválida; se restableció a configuración estructurada", + "nativeJsonRecoveredOpenCode": "La configuración JSON nativa es inválida; se restableció a configuración estructurada de OpenCode", + "openCodeAuthRecovered": "OpenCode auth.json es inválido; se restableció a configuración predeterminada", + "authRecoveredStructured": "auth.json es inválido; se restableció a configuración estructurada" + }, + "toasts": { + "agentActionCompleted": "{name} {action} completado", + "agentActionFailed": "{name} {action} falló", + "localVersion": "Versión local: {version}", + "installCompletedVersionLater": "Instalación completada, la versión se actualizará en la próxima comprobación", + "uninstallCompleted": "Desinstalación de {name} completada", + "uninstallFailed": "Desinstalación de {name} fallida", + "localVersionRemoved": "Versión local eliminada", + "saveAgentOrderFailed": "No se pudo guardar el orden de Agent", + "saveAgentSwitchFailed": "No se pudo guardar el switch de Agent", + "saveEnvFailed": "No se pudieron guardar las variables de entorno", + "grokSaved": "Configuración de Grok guardada", + "saveGrokNativeFailed": "No se pudo guardar la configuración nativa de Grok", + "saveGrokApiKeyFailed": "Ajustes guardados, pero no se pudo guardar la clave API", + "cursorSaved": "Configuración de Cursor guardada", + "saveCursorConfigFailed": "Error al guardar la configuración de Cursor", + "codexSaved": "Configuración de Codex guardada", + "saveCodexNativeFailed": "No se pudo guardar la configuración nativa de Codex", + "geminiSaved": "Configuración de Gemini guardada", + "saveGeminiFailed": "No se pudo guardar la configuración de Gemini", + "providerDeleted": "Proveedor {providerId} eliminado", + "providerDeleteFailed": "No se pudo eliminar el proveedor {providerId}", + "providerSaved": "Proveedor {providerId} guardado", + "saveProviderFailed": "No se pudo guardar el proveedor {providerId}", + "openCodeConfigSynced": "La configuración de OpenCode y auth JSON se sincronizaron.", + "openCodeSaved": "Configuración de OpenCode guardada", + "saveOpenCodeFailed": "No se pudo guardar la configuración de OpenCode", + "openClawSaved": "Configuración de OpenClaw guardada", + "saveOpenClawFailed": "No se pudo guardar la configuración de OpenClaw", + "configSaved": "Configuración guardada", + "configSavedHint": "Las sesiones existentes deben reabrirse para que surta efecto", + "saveConfigManagementFailed": "No se pudo guardar la gestión de configuración", + "clineSaved": "Configuración de Cline guardada", + "saveClineFailed": "Error al guardar la configuración de Cline", + "hermesSaved": "Configuración de Hermes guardada", + "saveHermesFailed": "Error al guardar la configuración de Hermes", + "codeBuddySaved": "Configuración de CodeBuddy guardada", + "saveCodeBuddyFailed": "No se pudo guardar la configuración de CodeBuddy", + "kimiCodeSaved": "Configuración de Kimi Code guardada", + "saveKimiCodeFailed": "Error al guardar la configuración de Kimi Code", + "deepseekSaved": "Configuración de DeepSeek guardada", + "saveDeepSeekFailed": "No se pudo guardar la configuración de DeepSeek", + "modelProviderRequired": "Seleccione un proveedor de modelo antes de guardar.", + "affectedRunningSessions": "{count, plural, one {# sesión activa necesita reconectarse para aplicar el cambio} other {# sesiones activas necesitan reconectarse para aplicar el cambio}}", + "providerConnected": "Conectado {providerId}", + "connectFailed": "Error al conectar {providerId}", + "providerDisconnected": "Desconectado {providerId}", + "disconnectFailed": "Error al desconectar {providerId}", + "catalogRefreshed": "Catálogo actualizado: {count} proveedores", + "catalogRefreshFailed": "Error al actualizar el catálogo", + "piSaved": "Configuración de Pi guardada", + "savePiFailed": "No se pudo guardar la configuración de Pi", + "piRuntimeSaved": "Entorno de Pi guardado", + "savePiRuntimeFailed": "No se pudo guardar el entorno de Pi", + "piBinaryInstalled": "pi instalado", + "piBinaryInstallFailed": "Error al instalar pi", + "piBinaryUninstalled": "pi desinstalado", + "piBinaryUninstallFailed": "Error al desinstalar pi", + "savePiTrustFailed": "Error al guardar la confianza del espacio de trabajo" + }, + "version": { + "statusLabel": "Estado de versión", + "notInstalled": "No instalado", + "remoteLocal": "Remota: {remoteVersion} · Local: {localVersion}", + "localOnly": "Local: {localVersion}", + "localInstalled": "{versionText}. Instalado.", + "platformUnsupported": "{versionText}. La plataforma actual no soporta este agente.", + "uvxNotReady": "{versionText}. El runtime de uv no está instalado: instálalo desde la comprobación de uv de abajo para usar este agente.", + "clickInstall": "{versionText}. Haz clic en Instalar a la derecha.", + "localUnrecognized": "{versionText}. La versión local no es comparable; intenta actualizar para sobrescribir la instalación.", + "upgradeAvailable": "{versionText}. Hay actualización disponible.", + "remoteUnavailable": "{versionText}. La versión remota no está disponible por ahora.", + "latest": "{versionText}. Ya está en la última versión." + }, + "adapter": { + "label": "Adaptador ACP", + "badge": "Adaptador ACP", + "badgeHint": "Para este agente Codeg instala un paquete adaptador ACP, no la CLI del proveedor. Son independientes y comparten la misma configuración.", + "learnMore": "Más información", + "missingWithNative": "Se encontró tu {nativeLabel} en {nativePath}. Codeg habla con los agentes mediante ACP y esa CLI no habla ACP, así que Codeg necesita un paquete adaptador aparte, {adapterPackage}, mantenido por el proyecto Agent Client Protocol (originalmente Zed). Incluye su propio runtime, nunca modifica ni reemplaza tu comando {nativeCmd} y lee el mismo {configDir}: tu sesión y tus ajustes actuales se conservan. Instálalo abajo.", + "missing": "Codeg habla con los agentes mediante ACP y la {nativeLabel} no habla ACP, así que Codeg necesita un paquete adaptador aparte, {adapterPackage}, mantenido por el proyecto Agent Client Protocol (originalmente Zed). Incluye su propio runtime, por lo que no hace falta instalar antes la CLI {nativeCmd}; si ya la tienes, ambas conviven y comparten la sesión y los ajustes de {configDir}. Instálalo abajo.", + "readyWithNative": "El adaptador {adapterCmd} está instalado: es lo que Codeg ejecuta, no tu propio {nativeCmd} en {nativePath}. Son paquetes distintos que conviven y ambos leen {configDir}, así que la sesión y los ajustes son compartidos.", + "ready": "El adaptador {adapterCmd} está instalado: es lo que Codeg ejecuta. Incluye su propio runtime, así que la {nativeLabel} no es necesaria; si la instalas después, ambas conviven y comparten {configDir}." + }, + "cline": { + "configDescription": "Configure el proveedor de API y las credenciales de Cline. La configuración se guarda en ~/.cline/data/." + }, + "opencodePlugins": { + "title": "Plugins de OpenCode", + "declared": "Plugins declarados", + "noPlugins": "No hay plugins declarados en opencode.json", + "status": { + "installed": "Instalado", + "missing": "No instalado" + }, + "installAll": "Instalar todos los faltantes", + "pinVersions": "Fijar versiones @latest", + "install": "Instalar", + "uninstall": "Desinstalar", + "refresh": "Actualizar", + "success": "Todos los plugins se instalaron correctamente", + "failed": "La operación del plugin falló" + }, + "pi": { + "configManagement": "Configuración de Pi", + "configDescription": "Pi se autentica con la clave API de tu proveedor de modelos. La clave se escribe en ~/.pi/agent/auth.json y la selección de modelo en settings.json.", + "providerLabel": "Proveedor", + "modelLabel": "Modelo", + "thinkingLabel": "Razonamiento", + "thinking": { + "off": "Desactivado", + "low": "Bajo", + "medium": "Medio", + "high": "Alto", + "minimal": "Mínimo", + "xhigh": "Muy alto" + }, + "apiKeyLabel": "Clave API", + "apiKeyHint": "Se guarda en ~/.pi/agent/auth.json para el proveedor seleccionado.", + "apiKeySetPlaceholder": "•••••• (guardada — déjalo vacío para mantener)", + "saveConfig": "Guardar configuración de Pi", + "providerModelRequired": "El proveedor y el modelo son obligatorios", + "runtimeTitle": "Entorno de ejecución", + "runtimeDescription": "Elige qué binario de pi se ejecuta. Usa el predeterminado o apunta a tu propia compilación de pi.", + "modeDefault": "pi predeterminado", + "modeDefaultHint": "Usa el adaptador pi-acp integrado con el pi de tu PATH. Instala pi con: npm install -g @earendil-works/pi-coding-agent", + "modeCustom": "pi personalizado", + "modeCustomHint": "Ejecuta tu propia compilación, instalación o envoltorio de pi.", + "commandLabel": "Comando o ruta de pi", + "commandHint": "Una ruta absoluta, un nombre de comando en el PATH o un script envoltorio (p. ej. ./pi-test.sh de un monorepo).", + "commandNotFound": "Comando no encontrado", + "validate": "Validar", + "advanced": "Avanzado", + "configDirLabel": "Directorio de configuración (PI_CODING_AGENT_DIR)", + "sessionDirLabel": "Directorio de sesiones (PI_CODING_AGENT_SESSION_DIR)", + "flagsHint": "pi-acp no reenvía flags personalizados de pi (--approve, -e, …); envuelve pi en un script y apunta el comando a él.", + "customIncomplete": "Introduce un comando de pi para guardar", + "saveRuntime": "Guardar entorno", + "providerPlaceholder": "Seleccionar un proveedor", + "customProvider": "Proveedor personalizado…", + "providerIdLabel": "ID del proveedor", + "apiProtocolLabel": "Protocolo de API", + "baseUrlLabel": "Endpoint de API (Base URL)", + "customProviderHint": "Define un proveedor en ~/.pi/agent/models.json hacia tu endpoint. La mayoría de los servidores autoalojados o proxy usan openai-completions.", + "baseUrlRequired": "El endpoint de API (Base URL) es obligatorio", + "binaryTitle": "binario pi (pi-coding-agent)", + "binaryDescription": "pi-acp ejecuta este binario pi. Instálalo aquí o apunta pi-acp a tu propia compilación más abajo.", + "binaryInstalled": "Instalado", + "binaryMissing": "No instalado", + "binaryChecking": "Comprobando…", + "installBinary": "Instalar pi", + "installing": "Instalando…", + "recheck": "Volver a comprobar", + "configDirSkillsNote": "Con un directorio de configuración personalizado, las habilidades, los expertos y las herramientas de oficina gestionados en Ajustes no se aplican a este pi; gestiona sus habilidades directamente en esa carpeta.", + "projectTrustTitle": "Confianza del proyecto", + "projectTrustDescription": "Carpetas desde las que permitiste que pi cargue archivos del proyecto. Una carpeta de confianza permite que las .pi/extensions de ese repositorio ejecuten código al iniciar pi, se aplica a todas las carpetas que contiene y también se usa cuando ejecutas pi en una terminal.", + "projectTrustLoading": "Cargando…", + "projectTrustEmpty": "Aún no hay carpetas decididas.", + "projectTrustTrusted": "De confianza", + "projectTrustDenied": "Sin confianza", + "projectTrustRevoke": "Revocar", + "reasoningTitle": "Razonamiento", + "reasoningEnableLabel": "Activar", + "reasoningDescription": "pi solo envía un esfuerzo de razonamiento para un modelo que lo declara: en un modelo sin declarar, todos los niveles se reducen a Off, así que el selector del compositor vuelve atrás en cuanto lo tocas. Se escribe en la entrada de este modelo en models.json.", + "levelsLabel": "Niveles disponibles", + "levelsHint": "Serán las filas del selector de razonamiento del compositor. Elige los que acepte tu endpoint; pi rechaza cualquier nivel que no esté aquí.", + "levelsEmptyError": "Elige al menos un nivel: sin ninguno, pi vuelve a Off.", + "wireValuesTitle": "Avanzado: valores enviados al proveedor", + "wireValuesHint": "Déjalo vacío para enviar el nombre del nivel tal cual. Defínelo cuando tu endpoint espere otra cosa: los backends al estilo de Google quieren LOW / HIGH.", + "defaultLevelUnlisted": "Este nivel no está en la lista de arriba: pi lo reduciría." + }, + "addCustomAgent": "Añadir agente personalizado", + "addCustomAgentHint": "Registra cualquier agente compatible con ACP. Elige uno del registro público de ACP o pega su información de registro.", + "customAgentFromRegistry": "Registro ACP", + "customAgentManual": "Manual", + "customAgentSearchPlaceholder": "Buscar agentes…", + "customAgentLoadingCatalog": "Cargando el registro ACP…", + "customAgentRetry": "Reintentar", + "customAgentNoResults": "No hay agentes coincidentes", + "customAgentAdd": "Añadir", + "customAgentAlreadyAdded": "Añadido", + "customAgentUnsupportedPlatform": "No hay compilación disponible para esta plataforma", + "customAgentAdded": "{name} añadido", + "customAgentIdLabel": "ID del registro", + "customAgentNameLabel": "Nombre visible", + "customAgentVersionLabel": "Versión", + "customAgentSpecLabel": "Distribución (JSON)", + "customAgentSpecHint": "Misma forma que el objeto distribution del registro ACP: canales npx, uvx y binary, o pega una entrada completa del registro. En npx/uvx, cmd es el ejecutable que instala el paquete; se deriva del nombre del paquete si se omite, así que indícalo cuando difieran. binary se organiza por clave de plataforma (esta máquina: {platform}); su cmd es la ruta de arranque dentro del archivo y sha256 verifica opcionalmente la descarga.", + "customAgentTemplateLabel": "Plantillas", + "customAgentKindLabel": "Iniciar mediante", + "customAgentInvalidJson": "JSON no válido", + "customAgentNoDistribution": "No se encontró distribución npx, uvx ni binary", + "customAgentCancel": "Cancelar", + "customAgentSave": "Añadir agente", + "customAgentSaveChanges": "Guardar cambios", + "customAgentEdit": "Editar agente", + "customAgentEditHint": "Actualiza el nombre, el icono, la distribución y las declaraciones de skills. El ID del agente no puede cambiarse.", + "customAgentEditNotFound": "No se encontró el agente personalizado {id}", + "customAgentSaved": "{name} guardado", + "customAgentVersionProbeLabel": "Comando de consulta de versión (opcional)", + "customAgentVersionProbeHint": "Comando que imprime la versión instalada localmente. Si se deja vacío, codeg ejecuta el comando del agente con --version.", + "customAgentRemove": "Eliminar agente", + "customAgentRemoveHint": "Elimina la definición del agente. Las conversaciones existentes conservan su historial; el agente simplemente ya no se puede iniciar.", + "customAgentIconLabel": "Icono (opcional)", + "customAgentIconUpload": "Subir", + "customAgentIconReplace": "Reemplazar", + "customAgentIconClear": "Quitar icono", + "customAgentIconHint": "Se guarda junto al agente, así funciona sin conexión. Si no indicas ninguno, se usa una inicial de color.", + "customAgentSkillsLabel": "Skills (.agents/skills compartido)", + "customAgentSkillsHint": "Declara que este agente lee el almacén compartido .agents/skills (directorios global y de proyecto) y lo añade a todas las matrices de habilidades. Las habilidades vinculadas allí son visibles para todos los agentes que leen ese almacén compartido.", + "customAgentSkillsDirLabel": "Directorio de skills dedicado", + "customAgentSkillsDirHint": "Ruta absoluta del directorio desde el que este agente carga skills: su propio almacén, además del compartido o en su lugar. ~ se expande al directorio personal; las skills vinculadas se colocan aquí primero.", + "customAgentMcpLabel": "Compatibilidad con MCP", + "customAgentMcpHint": "Envía el complemento MCP integrado de codeg a este agente al iniciar la sesión: es el canal de la delegación, los comentarios en vivo y las herramientas de tareas. Desactívalo para un agente que rechaza servidores MCP y no llega a conectarse; el cambio se aplica en la próxima conexión.", + "customAgentIconNotAnImage": "Selecciona un archivo de imagen.", + "customAgentIconTooLarge": "El icono debe pesar menos de {limit} KB.", + "customAgentIconReadFailed": "No se pudo leer esa imagen.", + "customAgentRemoveConfirm": "¿Eliminar {name}? Las conversaciones existentes se conservan, pero el agente ya no podrá iniciarse.", + "customAgentRemoveWithData": "Eliminar también su historial de conversaciones registrado", + "customAgentRemoved": "{name} eliminado", + "customAgentBadge": "Personalizado", + "customAgentNotLaunchable": "Este agente no puede iniciarse aquí: {reason}" + }, + "SettingsPages": { + "agentsLoading": "Cargando configuración de agentes...", + "skillPacksLoading": "Cargando paquetes de habilidades…" + }, + "GeneralSettings": { + "loading": "Cargando...", + "sectionTitle": "General", + "sectionDescription": "Preferencias centralizadas para el terminal predeterminado, la aceleración de renderizado y la delegación entre agentes.", + "terminalTitle": "Terminal predeterminada", + "terminalDescription": "Elige el shell que se usa al abrir nuevas pestañas de terminal desde la barra de terminal o el árbol de archivos. Los agentes también lo usan cuando piden a codeg que ejecute una línea de comandos completa.", + "terminalSystemDefault": "Predeterminado del sistema", + "terminalPowerShell7": "PowerShell 7 (pwsh)", + "terminalWindowsPowerShell": "Windows PowerShell", + "terminalCmd": "Símbolo del sistema (cmd)", + "terminalSaveFailed": "Error al guardar la configuración del terminal: {message}", + "terminalShellCustom": "Ruta personalizada", + "terminalShellCustomPath": "Ruta del shell", + "terminalShellCustomPlaceholder": "/usr/local/bin/fish", + "terminalShellCustomSave": "Guardar", + "terminalShellCustomHint": "Indica una ruta absoluta o un nombre resoluble en PATH.", + "terminalShellNotInstalled": "no instalado", + "terminalShellNotFoundWarning": "Esta ruta no existe en este host.", + "terminalCurrentShell": "En uso actualmente: {path}", + "renderingDescription": "Desactiva la aceleración por hardware si la aplicación muestra pantalla negra o fallos de renderizado (común en algunas GPU AMD o Intel integradas). Solo afecta a la versión de escritorio en Windows.", + "disableHardwareAcceleration": "Desactivar aceleración por hardware", + "renderingSaveFailed": "No se pudo guardar la configuración de renderizado: {message}", + "restartRequired": "Guardado. Reinicia la aplicación para aplicar el cambio.", + "restartNow": "Reiniciar ahora", + "restartFailed": "No se pudo reiniciar: {message}", + "loadFailed": "Error al cargar: {message}" + }, + "LoginPage": { + "documentTitle": "Iniciar sesión - codeg", + "brand": "Codeg", + "subtitle": "Introduce tu token de acceso para conectarte a la aplicación de escritorio", + "tokenPlaceholder": "Token de acceso", + "connect": "Conectar", + "connecting": "Conectando...", + "helpText": "Encuentra tu token en la aplicación de escritorio en Configuración → Servicio web", + "invalidToken": "Token no válido. Por favor, comprueba e inténtalo de nuevo.", + "connectionFailed": "Error de conexión (HTTP {status})", + "networkError": "No se puede conectar al servidor" + }, + "CommitPage": { + "title": "Confirmación", + "invalidFolderId": "ID de carpeta no válido", + "loadingRepo": "Cargando repositorio..." + }, + "MergePage": { + "title": "Resolver conflictos", + "invalidFolderId": "ID de carpeta no válido", + "loadingRepo": "Cargando repositorio...", + "localVersion": "Local (Nuestro)", + "result": "Resultado", + "remoteVersion": "Remoto (Suyo)", + "acceptLocal": "Aceptar local", + "acceptRemote": "Aceptar remoto", + "markResolved": "Marcar como resuelto", + "abortMerge": "Abortar", + "completeMerge": "Completar fusión", + "unresolvedConflicts": "Todavía hay marcadores de conflicto sin resolver en este archivo", + "fileResolved": "Archivo resuelto correctamente", + "allResolved": "Todos los conflictos resueltos", + "conflictFiles": "Archivos en conflicto", + "loadingFile": "Cargando archivo...", + "preparingMerge": "Preparando fusión...", + "selectFile": "Seleccionar un archivo para resolver", + "noConflicts": "No hay archivos en conflicto", + "skipFile": "Omitir", + "abortSuccess": "Operación abortada", + "applyAllNonConflicting": "Aplicar todos los cambios sin conflicto", + "applyLeftNonConflicting": "Aplicar local", + "applyRightNonConflicting": "Aplicar remoto" + }, + "ImportSessions": { + "title": "Importar sesiones locales", + "scanningTitle": "Escaneando sesiones locales de los agentes…", + "scanningHint": "Recorriendo el almacén local de sesiones de cada agente. Con historiales grandes puede tardar un momento. Las sesiones ya importadas se actualizan por el camino.", + "scanFailed": "Error al escanear", + "retry": "Reintentar", + "rescan": "Reescanear", + "empty": "No se encontraron sesiones locales", + "emptyHint": "No se encontraron almacenes de sesiones de agentes en este equipo.", + "noMatches": "Ninguna sesión coincide con los filtros actuales", + "searchPlaceholder": "Buscar título o ruta…", + "allAgents": "Todos los agentes", + "onlyImportable": "Solo importables", + "selectAll": "Seleccionar todo", + "clearSelection": "Limpiar", + "expandAll": "Expandir todo", + "collapseAll": "Contraer todo", + "summaryCounts": "{total} sesiones · {importable} importables · {folders} carpetas", + "noFolderSkipped": "{count} sin carpeta de proyecto omitidas", + "folderNew": "Nueva", + "folderCounts": "{importable}/{total} importables", + "toggleFolderAria": "Seleccionar todas las sesiones importables de {name}", + "toggleSessionAria": "Seleccionar la sesión {title}", + "statusImported": "Importada", + "statusDeleted": "Eliminada", + "untitled": "Sesión sin título", + "messageCount": "{count} mensajes", + "selectedCount": "{count} seleccionadas", + "importSelected": "Importar selección", + "importing": "Importando…", + "close": "Cerrar", + "doneTitle": "Importación finalizada", + "doneImported": "Importadas", + "doneUpdated": "Actualizadas", + "doneSkipped": "Omitidas", + "doneCreatedFolders": "Carpetas creadas", + "doneNotFound": "No encontradas", + "doneFailed": "Fallidas", + "continueImport": "Seguir importando", + "toasts": { + "importFailed": "Error al importar: {message}" + } + }, + "Folder": { + "workspaceStatus": { + "degradedTitle": "Actualizaciones en vivo no disponibles", + "degradedHint": "El observador no pudo iniciarse (por ejemplo, permiso denegado). Actualiza manualmente para ver los cambios.", + "retry": "Reintentar", + "retrying": "Reintentando..." + }, + "common": { + "all": "Todo", + "cancel": "Cancelar", + "close": "Cerrar", + "closeOthers": "Cerrar otros", + "closeAll": "Cerrar todo", + "confirm": "Confirmar", + "save": "Guardar", + "delete": "Eliminar", + "rename": "Renombrar", + "loading": "Cargando...", + "refresh": "Actualizar", + "refreshing": "Actualizando...", + "create": "Crear", + "createAndSwitch": "Crear y cambiar", + "openFile": "Abrir archivo", + "viewDiff": "Ver Diff", + "push": "Enviar..." + }, + "statusLabels": { + "in_progress": "En progreso", + "pending_review": "Revisión", + "completed": "Completado", + "cancelled": "Cancelado" + }, + "sidebar": { + "title": "Conversaciones", + "locateActiveConversation": "Ubicar conversación activa", + "expandAllGroups": "Expandir todos los grupos", + "collapseAllGroups": "Colapsar todos los grupos", + "newConversation": "Nueva conversación", + "newConversationShort": "Nueva", + "newChat": "Nueva conversación", + "search": "Buscar", + "noConversationsFound": "No se encontraron conversaciones.", + "importLocalSessions": "Importar sesiones locales", + "importing": "Importando...", + "error": "Error del sistema: {message}", + "completeAllSessions": "Completar todas las sesiones", + "completeAllReviewTitle": "¿Completar todas las sesiones en revisión?", + "completeAllReviewDescription": "Esto marcará como completadas todas las {count, plural, one {# sesión} other {# sesiones}} en Revisión.", + "completing": "Completando...", + "toasts": { + "importedSessions": "Se importaron {imported, plural, one {# sesión} other {# sesiones}}, se omitieron {skipped}", + "importedAndUpdated": "Se importaron {imported, plural, one {# sesión} other {# sesiones}}, se actualizaron {updated, plural, one {# título} other {# títulos}}, se omitieron {skipped}", + "updatedTitles": "Se actualizaron {updated, plural, one {# título} other {# títulos}}, se omitieron {skipped}", + "noNewSessionsFound": "No se encontraron sesiones nuevas (omitidas {skipped})", + "importFailed": "Error al importar: {message}", + "reviewCompleted": "Se marcaron como completadas {count, plural, one {# sesión en revisión} other {# sesiones en revisión}}", + "completeReviewFailed": "Error al completar sesiones en revisión: {message}", + "folderOpened": "Carpeta {name} abierta", + "folderRemoved": "Carpeta {name} eliminada", + "openFolderFailed": "Error al abrir carpeta", + "removeFolderFailed": "Error al eliminar carpeta: {message}", + "reorderFoldersFailed": "Error al reordenar carpetas: {message}", + "changeFolderColorFailed": "Error al cambiar el color: {message}", + "setFolderAliasFailed": "Error al establecer el alias: {message}", + "changeFolderDefaultAgentFailed": "Error al establecer agente predeterminado: {message}" + }, + "statsLabel": "{folders} carpetas · {convos} conversaciones", + "reorderHandle": "Arrastrar para reordenar", + "openFolder": "Abrir carpeta", + "searchPlaceholder": "Buscar conversaciones...", + "viewOptions": "Opciones de visualización", + "showCompleted": "Mostrar conversaciones completadas", + "showWorktrees": "Mostrar carpetas de worktree", + "showRecent": "Mostrar grupo Recientes", + "moreOptions": "Más opciones", + "sortBy": "Ordenar por", + "sortByCreatedAt": "Fecha de creación", + "sortByUpdatedAt": "Fecha de actualización", + "sectionOrder": "Orden de secciones", + "sectionOrderMoveUp": "Subir", + "sectionOrderMoveDown": "Bajar", + "sectionOrderItemLabel": "{name} — posición {position} de {total}", + "statusRunningBadge": "Ejecutando", + "runningCountBadge": "{count, plural, one {# sesión en ejecución} other {# sesiones en ejecución}}", + "statusCancelledBadge": "Cancelado", + "worktreeRemovedBadge": "Worktree de origen eliminado", + "conversationCountUnit": "{count, plural, one {# conversación} other {# conversaciones}}", + "emptyFolderHint": "Sin conversaciones", + "noMatchingConversations": "No hay conversaciones coincidentes", + "noUnfinishedConversations": "No hay conversaciones pendientes. Activa \"Mostrar completadas\" desde el menú superior derecho.", + "removeFolderConfirmTitle": "¿Eliminar carpeta del espacio de trabajo?", + "removeFolderConfirmDescription": "¿Eliminar \"{name}\" del espacio de trabajo? Sus pestañas y terminales se cerrarán.", + "folderHeaderMenu": { + "manageConversations": "Gestionar conversaciones…", + "manageLinks": "Carpetas vinculadas", + "changeColor": "Cambiar color", + "useThemeColor": "Usar tema de la app", + "setDefaultAgent": "Establecer agente predeterminado", + "defaultAgentNone": "Sin valor (usar predeterminado global)", + "agentUnavailableSuffix": "(no disponible)", + "loadingAgents": "Cargando agentes…", + "setAlias": "Establecer alias…", + "setAliasTitle": "Establecer alias de la carpeta", + "setAliasPlaceholder": "Introduce un alias (déjalo vacío para borrarlo)", + "setAliasSave": "Guardar", + "setAliasCancel": "Cancelar", + "removeFromWorkspace": "Quitar del espacio de trabajo" + }, + "manageConversations": { + "title": "Gestionar conversaciones", + "searchPlaceholder": "Buscar por título…", + "agentFilterAll": "Todos los agentes", + "statusFilterAll": "Todos los estados", + "folderFilterAll": "Todas las carpetas", + "branchFilterAll": "Todas las ramas", + "branchNone": "Sin rama", + "branchSearchPlaceholder": "Buscar ramas…", + "noMatchingBranches": "No hay ramas coincidentes", + "selectAllVisible": "Seleccionar todo", + "deselectAll": "Deseleccionar todo", + "selectedCount": "{count} seleccionada(s)", + "matchedCount": "{count} coincidencia(s)", + "untitledConversation": "Conversación sin título", + "setStatus": "Cambiar estado…", + "deleteSelected": "Eliminar", + "noConversations": "No hay conversaciones en esta carpeta.", + "noConversationsWorkspace": "No hay conversaciones en el espacio de trabajo.", + "noMatchingConversations": "Ninguna conversación coincide con los filtros.", + "confirmDeleteTitle": "¿Eliminar {count} conversación(es)?", + "confirmDeleteDescription": "Esta acción no se puede deshacer.", + "toastDeleted": "Se eliminaron {count} conversación(es)", + "toastStatusUpdated": "Estado actualizado para {count} conversación(es)", + "toastOpFailed": "Error en la operación: {message}" + }, + "sectionPinned": "Fijadas", + "sectionFolders": "Carpetas", + "sectionChats": "Chat", + "sectionRecent": "Recientes", + "noChats": "Sin chats", + "noRecent": "Sin conversaciones recientes", + "showMoreRecent": "Mostrar más ({count})", + "noFolders": "No hay carpetas abiertas", + "newChatAction": "Nuevo chat", + "automations": "Automatizaciones", + "tasks": "Tareas pendientes", + "loadingSubsessions": "Cargando subconversaciones…" + }, + "conversation": { + "reloadFailed": "No se pudo recargar la conversación: {message}", + "reloaded": "Conversación recargada", + "reload": "Recargar", + "activeConversationIndicator": "Conversación activa", + "newConversation": "Nueva conversación", + "closeConversation": "Cerrar conversación", + "copyText": "Copiar texto", + "copyTextSuccess": "Copiado", + "copyTextFailed": "Error al copiar", + "forkSession": "Bifurcar sesión", + "forkSessionSuccess": "Sesión bifurcada exitosamente", + "forkSessionFailed": "Error al bifurcar la sesión: {error}", + "exportConversation": "Exportar conversación", + "exportImage": "Imagen", + "exportMarkdown": "Markdown", + "exportHtml": "HTML", + "exportSuccess": "Conversación exportada", + "exportFailed": "Error al exportar", + "exportImageTooLong": "La conversación es demasiado larga para exportar como imagen", + "exportLabels": { + "untitledConversation": "Conversación sin título", + "agent": "Agente", + "model": "Modelo", + "status": "Estado", + "started": "Inicio", + "updated": "Actualizado", + "tokens": "Estadísticas de tokens", + "duration": "Duración", + "inputTokens": "Entrada", + "outputTokens": "Salida", + "cacheRead": "Caché leída", + "cacheWrite": "Caché escrita", + "user": "Usuario", + "assistant": "Asistente", + "system": "Sistema", + "toolResult": "Resultado", + "toolError": "Error" + }, + "moreActions": "Más acciones" + }, + "sessionDetails": { + "menuLabel": "Detalles de la sesión", + "noActiveSession": "No hay ninguna sesión activa", + "title": "Detalles de la sesión", + "subtitle": "Metadatos de la sesión y uso de tokens", + "fieldTitle": "Título", + "untitled": "Conversación sin título", + "sessionId": "ID de sesión", + "externalId": "ID de extensión", + "agent": "Agente", + "model": "Modelo", + "status": "Estado", + "gitBranch": "Rama de Git", + "parentId": "Sesión principal", + "tokensHeading": "Uso de tokens", + "totalTokens": "Total", + "inputTokens": "Entrada", + "outputTokens": "Salida", + "cacheWrite": "Caché escrita", + "cacheRead": "Caché leída", + "contextWindow": "Ventana de contexto", + "duration": "Duración", + "loadingStats": "Cargando uso de tokens…", + "loadFailed": "Error al cargar el uso de tokens", + "noStats": "Sin uso registrado", + "timestampsHeading": "Marcas de tiempo", + "createdAt": "Creado", + "updatedAt": "Actualizado", + "none": "—", + "copyField": "Copiar {field}", + "copiedField": "{field} copiado" + }, + "conversationCard": { + "untitledConversation": "Conversación sin título", + "newConversation": "Nueva conversación", + "rename": "Renombrar", + "status": "Estado", + "delete": "Eliminar", + "importLocalSessions": "Importar sesiones locales", + "importing": "Importando...", + "renameConversation": "Renombrar conversación", + "deleteConversationTitle": "¿Eliminar conversación?", + "deleteConversationDescription": "Esto eliminará \"{title}\". Esta acción no se puede deshacer.", + "cancel": "Cancelar", + "save": "Guardar", + "pin": "Fijar", + "unpin": "Dejar de fijar", + "markCompleted": "Marcar como completada", + "reopen": "Reabrir", + "expandSubsessions": "Expandir subconversaciones", + "collapseSubsessions": "Contraer subconversaciones" + }, + "search": { + "dialogTitle": "Buscar", + "dialogTitleWithFolder": "Buscar — {name}", + "tabConversations": "Conversaciones", + "tabFiles": "Archivos", + "placeholder": "Buscar conversaciones...", + "filePlaceholder": "Buscar archivos o directorios...", + "allAgents": "Todo", + "searching": "Buscando...", + "typeToSearch": "Escribe para buscar conversaciones", + "typeToSearchFiles": "Escribe para buscar archivos o directorios", + "noResults": "No se encontraron resultados.", + "untitledConversation": "Conversación sin título" + }, + "folderTitleBar": { + "showSidebar": "Mostrar barra lateral", + "hideSidebar": "Ocultar barra lateral", + "toggleTerminal": "Alternar terminal", + "toggleAuxPanel": "Alternar panel auxiliar", + "search": "Buscar", + "openSettings": "Abrir configuración", + "backToConversations": "Volver a conversaciones", + "withShortcut": "{label} (atajo: {shortcut})" + }, + "statusBar": { + "connection": { + "connected": "Conectado", + "connecting": "Conectando...", + "prompting": "Respondiendo...", + "error": "Error de conexión", + "disconnected": "Desconectado", + "tooltip": "{agent}: {status}", + "tooltipError": "{agent}: {error}", + "title": "Conexión del agente", + "triggerAria": "Conexión del agente: {status}", + "workingDir": "Directorio de trabajo", + "sessionId": "ID de sesión", + "viewerNote": "Conectado a una sesión que pertenece a otro cliente: reconectar solo vuelve a adjuntar esta vista.", + "reconnectInterrupts": "Reconectar reinicia el agente e interrumpe el trabajo en curso.", + "reconnect": "Reconectar", + "reconnecting": "Reconectando...", + "reconnectUnavailable": "Aún no hay ninguna sesión a la que reconectar." + }, + "tasks": { + "title": "Tareas" + }, + "alerts": { + "title": "Alertas", + "empty": "Sin alertas", + "details": "Detalles" + }, + "stats": { + "conversations": "{count} conversaciones", + "openUsage": "Ver estadísticas de sesiones y uso de tokens" + }, + "tokens": { + "contextWindowUsageAria": "Uso de la ventana de contexto", + "contextWindow": "Ventana de contexto", + "usedMax": "Usado / Máx", + "tokenUsage": "Uso de tokens", + "input": "Entrada", + "output": "Salida", + "cacheRead": "Lectura de caché", + "cacheWrite": "Escritura de caché", + "total": "Total de tokens" + } + }, + "auxPanel": { + "tabs": { + "files": "Archivos", + "changes": "Cambios", + "commits": "Confirmaciones" + }, + "noFolderTitle": "No hay carpeta abierta", + "noFolderHint": "Abre una carpeta para ver su contenido aquí" + }, + "windowControls": { + "minimizeWindow": "Minimizar ventana", + "minimize": "Minimizar", + "maximizeWindow": "Maximizar ventana", + "maximize": "Maximizar", + "restoreWindow": "Restaurar ventana", + "restore": "Restaurar", + "closeWindow": "Cerrar ventana", + "close": "Cerrar" + }, + "tabs": { + "closeConversationTab": "Cerrar pestaña de conversación", + "close": "Cerrar", + "closeOthers": "Cerrar otros", + "splitRight": "Dividir a la derecha", + "splitDown": "Dividir abajo", + "splitAndMoveRight": "Dividir y mover a la derecha", + "splitAndMoveDown": "Dividir y mover abajo", + "moveToOppositeGroup": "Mover al grupo opuesto", + "moveToGroup": "Mover al grupo", + "groupLabel": "Grupo {index}", + "changeSplitterOrientation": "Cambiar orientación del divisor", + "unsplit": "Deshacer división", + "unsplitAll": "Deshacer todas las divisiones", + "closeAll": "Cerrar todo", + "tileDisplay": "Vista en mosaico", + "untileDisplay": "Salir de mosaico" + }, + "fileWorkspace": { + "files": "Archivos", + "closeFileTab": "Cerrar pestaña de archivo", + "close": "Cerrar", + "closeOthers": "Cerrar otros", + "closeAll": "Cerrar todo", + "preview": "Vista previa", + "editSource": "Editar fuente", + "maximize": "Maximizar", + "restore": "Restaurar", + "emptyDirectory": "Carpeta vacía" + }, + "terminal": { + "rename": "Renombrar", + "close": "Cerrar", + "closeOthers": "Cerrar otros", + "closeAll": "Cerrar todo", + "hideTerminal": "Ocultar terminal ({shortcut})", + "openFolderFirst": "Abre primero una carpeta" + }, + "workspaceDialog": { + "title": "Abrir carpeta", + "manageTitle": "Carpetas vinculadas", + "addTargetsTitle": "Añadir carpetas para vincular", + "pickRootDescription": "Elige la carpeta principal de este espacio de trabajo.", + "linksDescription": "Vincula otras carpetas como subdirectorios para que los agentes trabajen en todas ellas desde un solo espacio de trabajo.", + "addTargetsDescription": "Selecciona una o más carpetas. Cada una será un subdirectorio del espacio de trabajo.", + "useSystemPicker": "Selector del sistema", + "next": "Siguiente", + "back": "Atrás", + "done": "Listo", + "change": "Cambiar", + "addFolders": "Añadir carpetas", + "addSelected": "Añadir", + "addSelectedCount": "Añadir {count}", + "createCount": "Vincular {count} carpeta(s)", + "discardPending": "Descartar", + "noLinks": "Todavía no hay carpetas vinculadas.", + "gitExclude": "Mantener los enlaces fuera del estado de git", + "rename": "Renombrar", + "unlink": "Quitar enlace", + "repair": "Recrear enlace", + "saveName": "Guardar", + "cancelRename": "Cancelar", + "removePending": "Quitar", + "willAppearAs": "Aparece como {name} en el espacio de trabajo", + "renamedForDuplicate": "Renombrada: {base} ya lo usa otro enlace", + "renamedForExistingEntry": "Renombrada: {base} ya existe en esta carpeta", + "partiallyCreated": "Solo se pudieron vincular {count} carpeta(s)", + "openFailed": "No se pudo abrir la carpeta", + "previewFailed": "No se pudieron comprobar las carpetas seleccionadas", + "createFailed": "No se pudieron vincular las carpetas", + "renameFailed": "No se pudo renombrar el enlace", + "removeFailed": "No se pudo quitar el enlace", + "repairFailed": "No se pudo recrear el enlace", + "status": { + "ok": "Vinculada", + "missing": "El enlace ya no está en esta carpeta", + "conflicted": "Otra entrada usa ahora este nombre", + "broken": "La carpeta vinculada ya no existe" + }, + "nameIssue": { + "empty": "Escribe un nombre", + "illegalChars": "No puede contener / \\ : * ? \" < > |", + "tooLong": "El nombre es demasiado largo", + "reserved": "Windows reserva este nombre", + "duplicate": "Este nombre ya está en uso" + }, + "rejection": { + "not_found": "No se encontró esta carpeta", + "not_a_directory": "Esta ruta no es una carpeta", + "same_as_root": "Es la propia carpeta del espacio de trabajo", + "ancestor_of_root": "Esta carpeta contiene el espacio de trabajo", + "inside_root": "Ya está dentro del espacio de trabajo", + "already_linked": "Ya está vinculada", + "name_unavailable": "No queda ningún nombre libre para esta carpeta", + "alreadyLinkedAs": "Ya vinculada como {name}" + } + }, + "folderNameDropdown": { + "fallbackFolderName": "Carpeta", + "openFolder": "Abrir carpeta", + "cloneRepository": "Clonar repositorio", + "projectBoot": "Inicializador de proyecto", + "opened": "Abierto", + "recentOpen": "Abiertos recientemente" + }, + "fileWorkspacePanel": { + "addSelectionToChat": "Añadir selección al chat", + "addToChat": "Añadir al chat", + "addSelectionToChatDone": "Se añadió {label} a la conversación", + "addFileToChat": "Añadir archivo al chat", + "toggleWordWrap": "Alternar ajuste de línea", + "addFileToChatDone": "Se añadió {label} a la conversación", + "viewDiff": "Ver Diff", + "openFile": "Abrir archivo", + "fileCount": "{count, plural, one {# archivo} other {# archivos}}", + "openFileOrDiff": "Abre un archivo o diff desde el panel derecho", + "disk": "Disco", + "head": "HEAD (referencia)", + "unsaved": "Sin guardar", + "workingTree": "Árbol de trabajo", + "loading": "Cargando...", + "compareWithBranch": "{path} · comparar con {branch}", + "hunkCount": "{count, plural, one {# bloque} other {# bloques}}", + "prev": "Anterior", + "next": "Siguiente", + "jumpToLine": "Ir a la línea {line}", + "noParsedDiffSections": "No hay secciones de diff analizadas", + "loadingEditor": "Cargando editor...", + "imageZoomIn": "Ampliar", + "imageZoomOut": "Reducir", + "imageZoomReset": "Restablecer zoom", + "htmlPreviewTitle": "Vista previa HTML", + "htmlPreviewTrust": "Habilitar scripts", + "htmlPreviewTrustHint": "Ejecuta los scripts de este archivo y permite el acceso a la red. Actívalo solo para archivos de confianza.", + "officePreviewTitle": "Vista previa de documento de Office", + "officeFullRender": "Renderizado completo", + "officeFullRenderHint": "Renderiza animaciones Morph, 3D y fórmulas (ejecuta los scripts de la diapositiva)", + "officeNotInstalled": "OfficeCLI no está instalado", + "officeNotInstalledHint": "Instala OfficeCLI en Ajustes → Herramientas de Office para previsualizar archivos de Word, Excel y PowerPoint.", + "officeOpenSettings": "Abrir ajustes", + "officeWatchFailed": "No se pudo iniciar la vista previa en vivo", + "officeWatchRetry": "Reintentar", + "officeServerInstallHint": "OfficeCLI debe instalarse en el host del servidor. Ejecuta este comando allí y vuelve a intentarlo:", + "officeRemoteDesktopUnsupported": "La vista previa en vivo no está disponible en una ventana de escritorio remoto. Abre este espacio de trabajo en la interfaz web del servidor para previsualizar archivos de Office." + }, + "branchDropdown": { + "toasts": { + "commitCodeCompleted": "Commit de código completado", + "pushCodeCompleted": "Push de código completado", + "committedFiles": "{count, plural, one {# archivo confirmado} other {# archivos confirmados}}", + "taskCompleted": "{label} completado", + "taskFailed": "{label} falló", + "mergeNoNewCommits": "{branchName} no tiene commits nuevos", + "mergedCommits": "{count, plural, one {# commit fusionado} other {# commits fusionados}}", + "allFilesUpToDate": "Todos los archivos están actualizados", + "updatedFiles": "{count, plural, one {# archivo actualizado} other {# archivos actualizados}}", + "openCommitWindowFailed": "No se pudo abrir la ventana de commit", + "openPushWindowFailed": "Error al abrir la ventana de envío", + "upstreamSet": "La rama upstream se ha configurado", + "upstreamSetAndPushed": "Rama upstream configurada y se enviaron {count, plural, one {# commit} other {# commits}}", + "noCommitsToPush": "No hay commits para enviar", + "pushedCommits": "Se enviaron {count, plural, one {# commit} other {# commits}}", + "switchedToFolder": "Cambiado a {name}", + "switchFailed": "No se pudo cambiar de rama", + "openStashWindowFailed": "No se pudo abrir la ventana de stash" + }, + "tasks": { + "newBranch": "Crear rama {name}", + "newWorktree": "Crear worktree {name}", + "checkoutTo": "Cambiar a {branchName}", + "mergeBranch": "Fusionar {branchName}", + "rebaseTo": "Rebase a {branchName}", + "deleteRemoteBranch": "Eliminar rama remota {branchName}", + "initGitRepo": "Inicializar repositorio Git", + "pullCode": "Hacer pull del código", + "fetchInfo": "Obtener información", + "pushCode": "Enviar código", + "stashChanges": "Guardar cambios en stash", + "stashPop": "Aplicar stash", + "deleteBranch": "Eliminar rama {branchName}", + "removeWorktree": "Eliminar el worktree de {branchName}", + "removeWorktreeAndBranch": "Eliminar el worktree y la rama {branchName}", + "updateBranch": "Actualizar la rama {branchName}" + }, + "confirm": { + "mergeTitle": "Fusionar rama", + "rebaseTitle": "Rebase de rama", + "mergeDescription": "¿Fusionar {branchName} en la rama actual {currentBranch}?", + "rebaseDescription": "¿Hacer rebase de la rama actual {currentBranch} sobre {branchName}?", + "deleteRemoteTitle": "Eliminar rama remota", + "deleteRemoteDescription": "¿Eliminar la rama remota {branchName}? Esto la eliminará del repositorio remoto y no se puede deshacer.", + "deleteTitle": "Eliminar rama", + "deleteDescription": "¿Eliminar la rama {branchName}? Esta acción no se puede deshacer.", + "forceDeleteTitle": "Forzar eliminación de rama", + "forceDeleteDescription": "La rama {branchName} no está completamente fusionada. ¿Estás seguro de que quieres forzar su eliminación? Esta acción no se puede deshacer.", + "deleteWorktreeTitle": "Eliminar worktree", + "deleteWorktreeDescription": "¿Eliminar el directorio del worktree que tiene {branchName} activa? La rama y sus commits se conservan.", + "forceDeleteWorktreeTitle": "Forzar la eliminación del worktree", + "forceDeleteWorktreeDescription": "El worktree de {branchName} tiene archivos sin confirmar o sin seguimiento. ¿Eliminarlo de todos modos? Esos cambios no se podrán recuperar.", + "deleteWorktreeAndBranchTitle": "Eliminar worktree y rama", + "deleteWorktreeAndBranchDescription": "¿Eliminar el worktree de {branchName}, la rama y su carpeta del espacio de trabajo? Sus sesiones pasan a la carpeta del repositorio. Esta acción no se puede deshacer.", + "forceDeleteWorktreeAndBranchTitle": "Forzar la eliminación del worktree y la rama", + "forceDeleteWorktreeAndBranchDescription": "El worktree de {branchName} tiene archivos sin confirmar, o la rama no está totalmente fusionada. ¿Eliminar ambos de todos modos? Esta acción no se puede deshacer." + }, + "current": "Actual", + "switchToBranch": "Cambiar a esta rama", + "mergeBranchIntoCurrent": "Fusionar {branchName} en {currentBranch}", + "rebaseCurrentToBranch": "Rebase de {currentBranch} sobre {branchName}", + "noBranch": "Sin rama", + "detachedHead": "HEAD desacoplado en {sha}", + "initGitRepo": "Inicializar repositorio Git", + "pullCode": "Hacer pull del código", + "fetchRemoteBranches": "Obtener ramas remotas", + "openCommitWindow": "Commit de código...", + "pushCode": "Enviar...", + "pushBranch": "Enviar", + "newBranch": "Nueva rama...", + "newWorktree": "Nuevo worktree...", + "stashChanges": "Guardar cambios...", + "stashPop": "Aplicar stash...", + "manageRemotes": "Gestionar remotos...", + "localBranches": "Ramas locales ({count, plural, one {#} other {#}})", + "noLocalBranches": "Sin ramas locales", + "remoteBranches": "Ramas remotas ({count, plural, one {#} other {#}})", + "noRemoteBranches": "Sin ramas remotas", + "dialogs": { + "newBranchTitle": "Nueva rama", + "newBranchDescription": "Crear una nueva rama desde la rama actual {branch}", + "branchNamePlaceholder": "Nombre de la rama", + "newWorktreeTitle": "Nuevo worktree", + "newWorktreeDescription": "Crear un nuevo worktree desde la rama actual {branch}", + "branchNameLabel": "Nombre de la rama", + "worktreePathLabel": "Ruta del worktree", + "worktreePathPlaceholder": "Ruta del worktree", + "manageRemotesTitle": "Gestionar remotos", + "manageRemotesEmpty": "No hay remotos configurados", + "remoteNamePlaceholder": "Nombre del remoto", + "remoteUrlPlaceholder": "URL del remoto", + "addRemote": "Añadir", + "savingRemotes": "Guardando..." + }, + "conflict": { + "title": "Conflictos de fusión", + "description": "Los siguientes archivos tienen conflictos que necesitan ser resueltos:", + "abort": "Abortar fusión", + "openMergeTool": "Abrir herramienta de fusión", + "completeMerge": "Completar fusión", + "abortSuccess": "Fusión abortada correctamente", + "completeSuccess": "Fusión completada correctamente" + }, + "stashDialog": { + "title": "Guardar cambios en stash", + "description": "Guardar los cambios actuales en el stash", + "messageLabel": "Mensaje", + "messagePlaceholder": "Mensaje del stash (opcional)", + "keepIndex": "Mantener índice (los cambios preparados permanecen preparados)", + "cancel": "Cancelar", + "stash": "Guardar", + "success": "Cambios guardados en stash", + "error": "Error al guardar en stash" + }, + "unstashDialog": { + "title": "Aplicar stash", + "noStashes": "No hay stashes", + "selectFile": "Selecciona un archivo para ver diferencias", + "viewDiff": "Ver diferencias", + "original": "Original", + "modified": "Modificado", + "apply": "Aplicar", + "drop": "Eliminar", + "applySuccess": "Stash aplicado", + "dropSuccess": "Stash eliminado", + "confirmApply": "¿Aplicar stash {ref} al directorio de trabajo?", + "cancel": "Cancelar" + }, + "deleteBranch": "Eliminar rama", + "deleteWorktree": "Eliminar worktree", + "deleteWorktreeAndBranch": "Eliminar worktree y rama", + "searchPlaceholder": "Buscar ramas y acciones", + "searchAriaLabel": "Buscar ramas y acciones", + "branchListLabel": "Ramas y acciones", + "noMatches": "Sin coincidencias" + }, + "commitDialog": { + "toasts": { + "commitCompleted": "Commit de código completado", + "pushFailed": "Error al enviar", + "committedFiles": "{count, plural, one {# archivo confirmado} other {# archivos confirmados}}", + "addedToVcs": "Añadido a VCS", + "addToVcsFailed": "No se pudo añadir a VCS", + "fileDeleted": "Archivo eliminado", + "deleteFailed": "Error al eliminar", + "fileRolledBack": "Archivo revertido", + "rollbackFailed": "Error al revertir", + "dirRolledBack": "Directorio revertido", + "dirDeleted": "Directorio eliminado" + }, + "confirm": { + "deleteTitle": "Confirmar eliminación", + "deleteDescription": "¿Eliminar el archivo \"{file}\"? Esta acción no se puede deshacer.", + "rollbackTitle": "Confirmar reversión", + "rollbackDescription": "¿Revertir el archivo \"{file}\" a HEAD? Se perderán los cambios sin guardar.", + "rollbackDirDescription": "¿Revertir el directorio \"{dir}\" a HEAD? Los cambios no guardados se perderán.", + "deleteDirDescription": "¿Eliminar el directorio \"{dir}\"? Esta acción no se puede deshacer." + }, + "actions": { + "select": "Seleccionar", + "unselect": "Deseleccionar", + "rollback": "Revertir", + "addToVcs": "Añadir a VCS" + }, + "aria": { + "selectFile": "{action}: {path}", + "unselectAllFiles": "Deseleccionar todos los archivos", + "selectAllFiles": "Seleccionar todos los archivos", + "unselectTracked": "Deseleccionar cambios rastreados", + "selectTracked": "Seleccionar cambios rastreados", + "unselectUntracked": "Deseleccionar archivos no rastreados", + "selectUntracked": "Seleccionar archivos no rastreados" + }, + "loading": "Cargando...", + "selectionCount": "{selected} / {total} archivos", + "emptyFiles": "No hay archivos cambiados", + "trackedChanges": "Cambios rastreados ({count})", + "untrackedFiles": "Archivos no rastreados ({count})", + "commitMessage": "Mensaje de commit", + "commitMessagePlaceholder": "Introduce el mensaje de commit...", + "commitButton": "Confirmar ({count})", + "commitAndPushButton": "Confirmar y enviar ({count})", + "head": "HEAD", + "workingTree": "Árbol de trabajo", + "clickFileToDiff": "Haz clic en un nombre de archivo para ver diff", + "loadingDiff": "Cargando diff..." + }, + "pushWindow": { + "title": "Enviar código", + "noUnpushedCommits": "No hay commits sin enviar", + "noRemoteConfigured": "No hay remoto Git configurado\nAñade uno en «Gestionar remotos»", + "newBranchNoPushedCommits": "Nueva rama — enviar para crear rama de seguimiento remota", + "unpushed": "Sin enviar", + "selectFileToViewDiff": "Selecciona un archivo para ver las diferencias", + "before": "Antes", + "after": "Después", + "push": "Enviar", + "toasts": { + "pushSuccess": "Envío exitoso", + "pushFailed": "Error al enviar", + "upstreamSet": "Se ha configurado la rama remota", + "upstreamSetAndPushed": "Rama remota configurada y enviados {count} commits", + "noCommitsToPush": "No hay commits para enviar", + "pushedCommits": "Enviados {count} commits" + } + }, + "gitLogTab": { + "filesTitle": "Archivos", + "expandAllFiles": "Expandir todos los archivos", + "collapseAllFiles": "Colapsar todos los archivos", + "workspace": "espacio de trabajo", + "retry": "Reintentar", + "noCommitsFound": "No se encontraron commits", + "notAGitRepoTitle": "No es un repositorio Git", + "notAGitRepoHint": "Inicializa Git desde el menú de ramas superior, o abre un repositorio existente.", + "hash": "Hash del commit", + "copyHash": "Copiar hash", + "copyMessage": "Copiar mensaje", + "showMore": "Mostrar más", + "showLess": "Mostrar menos", + "author": "Autor", + "noFileChangeDetails": "No hay detalles de cambios de archivo disponibles.", + "loadingFiles": "Cargando archivos...", + "branchesTitle": "Ramas", + "loadingBranches": "Cargando ramas...", + "noContainingBranches": "No se encontraron ramas contenedoras.", + "newBranch": "Nueva rama...", + "resetToHere": "Resetear aquí", + "resetDisabledReasonNotCurrentBranchView": "Disponible solo al ver la rama actual", + "copyFullCommitHashAria": "Copiar hash completo del commit {hash}", + "pushStatus": { + "pushed": "Enviado al remoto", + "notPushed": "No enviado al remoto", + "unknown": "Estado de push desconocido (sin upstream configurado)" + }, + "time": { + "monthsAgo": "{count, plural, one {hace # mes} other {hace # meses}}", + "daysAgo": "{count, plural, one {hace # día} other {hace # días}}", + "hoursAgo": "{count, plural, one {hace # hora} other {hace # horas}}", + "minsAgo": "{count, plural, one {hace # min} other {hace # mins}}", + "justNow": "justo ahora" + }, + "toasts": { + "createdAndSwitchedNewBranch": "Nueva rama creada y activada", + "newBranchFromCommit": "{name} (desde {shortHash})", + "createBranchFailed": "No se pudo crear la rama", + "openPushWindowFailed": "No se pudo abrir la ventana de envío", + "resetSuccess": "Reset completado", + "resetSuccessDescription": "{branch} se reseteó a {shortHash} con {mode}", + "resetFailed": "Falló el reset" + }, + "authorFilter": { + "label": "Autor", + "searchPlaceholder": "Buscar autor", + "noAuthors": "No se encontraron autores", + "you": "tú", + "filterByAuthorAria": "Filtrar commits por autor", + "filterByQuery": "Filtrar por \"{query}\"", + "clearAuthorFilterAria": "Borrar filtro de autor", + "recent": "Recientes", + "matchingAuthors": "Autores coincidentes", + "removeFromRecent": "Quitar {name} de recientes" + }, + "branchSelector": { + "label": "Rama", + "head": "HEAD", + "headHint": "Sigue la rama actual", + "headHintWithBranch": "Sigue la rama actual ({branch})", + "searchBranch": "Buscar rama...", + "noBranches": "Sin ramas", + "selectBranchPlaceholder": "Seleccionar rama...", + "localBranches": "Ramas locales", + "current": "Actual", + "remoteBranches": "Ramas remotas", + "refreshCommitHistory": "Actualizar historial de commits", + "clearBranchFilterAria": "Borrar filtro de rama" + }, + "dialogs": { + "newBranchTitle": "Nueva rama", + "newBranchDescription": "Crea una nueva rama con el commit {shortHash} como último commit.", + "branchNamePlaceholder": "Nombre de la rama", + "reset": { + "title": "Resetear la rama actual hasta aquí", + "branchLabel": "Rama", + "targetLabel": "Commit objetivo", + "messageLabel": "Mensaje", + "modeLabel": "Modo de reset", + "confirmButton": "Resetear", + "modes": { + "soft": { + "label": "--soft", + "description": "Mueve HEAD y el puntero de la rama actual al commit objetivo.\nMantiene Index y Working Tree sin cambios.\nLos cambios de los commits retirados permanecen en estado staged." + }, + "mixed": { + "label": "--mixed (predeterminado)", + "description": "Mueve HEAD al commit objetivo.\nResetea Index al commit objetivo y mantiene los cambios en Working Tree.\nLos cambios pasan de staged a unstaged." + }, + "hard": { + "label": "--hard", + "description": "Mueve HEAD y resetea tanto Index como Working Tree al commit objetivo.\nSe descartan los cambios locales rastreados posteriores al commit objetivo.\nEs una operación destructiva." + }, + "keep": { + "label": "--keep", + "description": "Mueve HEAD al commit objetivo e intenta conservar los cambios locales.\nSolo se conservan cambios que no entren en conflicto.\nSi hay conflictos, el reset se aborta para proteger tu trabajo." + } + } + } + }, + "moreActions": "Más acciones de Git" + }, + "gitChangesTab": { + "workspace": "espacio de trabajo", + "noChanges": "No hay cambios locales", + "notAGitRepoTitle": "No es un repositorio Git", + "notAGitRepoHint": "Inicializa Git desde el menú de ramas superior, o abre un repositorio existente.", + "trackedChanges": "Cambios rastreados ({count})", + "untrackedFiles": "Archivos no rastreados ({count})", + "expandTracked": "Expandir cambios rastreados", + "collapseTracked": "Colapsar cambios rastreados", + "expandUntracked": "Expandir archivos no rastreados", + "collapseUntracked": "Colapsar archivos no rastreados", + "showRemainingItems": "Mostrar {count} elementos más", + "actions": { + "commitCode": "Hacer commit del código", + "rollback": "Revertir", + "addToVcs": "Añadir a VCS", + "delete": "Eliminar", + "moreActions": "Más acciones de Git", + "addAllToVcs": "Añadir todo al VCS", + "rollbackAll": "Revertir todo", + "refresh": "Actualizar" + }, + "toasts": { + "noAddableFilesInDir": "No hay archivos cambiados en este directorio para añadir a VCS", + "noRollbackFilesInDir": "No hay archivos cambiados en este directorio para revertir", + "addedToVcs": "Se añadió {name} a VCS", + "addToVcsFailed": "No se pudo añadir a VCS", + "openCommitWindowFailed": "No se pudo abrir la ventana de commit", + "rolledBack": "Se revirtió {name}", + "rollbackFailed": "Error al revertir", + "addedFilesToVcs": "Se añadieron {count, plural, one {# archivo} other {# archivos}} a VCS", + "rolledBackFiles": "Se revirtieron {count, plural, one {# archivo} other {# archivos}}", + "deleted": "Se eliminó {name}", + "deleteFailed": "Error al eliminar", + "deletedFiles": "Se eliminaron {count} archivos", + "noDeletableFilesInDir": "No hay archivos modificados en este directorio que se puedan eliminar", + "commitFailed": "Error al confirmar" + }, + "directoryDialog": { + "descriptionAdd": "Selecciona archivos bajo el directorio {path} para añadir a VCS.", + "descriptionRollback": "Selecciona archivos bajo el directorio {path} para revertir.", + "descriptionDelete": "Selecciona archivos bajo el directorio {path} para eliminar. Esta acción no se puede deshacer.", + "descriptionFallback": "Selecciona archivos para continuar.", + "selectionCount": "Seleccionados {selected} / {total} archivos", + "selectAll": "Seleccionar todo", + "unselectAll": "Deseleccionar todo", + "loadingCandidates": "Cargando cambios del directorio...", + "noOperableFiles": "No hay archivos operables" + }, + "rollbackConfirm": { + "title": "Confirmar reversión", + "descriptionWithTarget": "¿Revertir cambios locales de {kind} \"{name}\"?", + "descriptionFallback": "¿Revertir cambios locales?", + "kindDirectory": "directorio", + "kindFile": "archivo" + }, + "deleteConfirm": { + "title": "Confirmar eliminación", + "descriptionWithTarget": "¿Eliminar {kind} \"{name}\"? Esta acción no se puede deshacer.", + "descriptionFallback": "Esta acción no se puede deshacer.", + "kindDirectory": "directorio", + "kindFile": "archivo" + }, + "quickCommit": { + "placeholder": "Mensaje del commit (Intro para confirmar)" + } + }, + "tabContext": { + "loadingConversation": "Cargando...", + "untitledConversation": "Conversación sin título", + "newConversation": "Nueva conversación" + }, + "fileTreeTab": { + "workspace": "Espacio de trabajo", + "retry": "Reintentar", + "git": "Git", + "openInFileManager": "Abrir en el gestor de archivos", + "openInFinder": "Abrir en Finder", + "openInExplorer": "Abrir en Explorer", + "attachToCurrentSession": "Agregar a la sesión", + "compareWithBranch": "Comparar con rama...", + "reloadFromDisk": "Recargar desde disco", + "new": "Nuevo", + "newFile": "Archivo", + "newDirectory": "Directorio", + "openIn": "Abrir en", + "openInTerminal": "Abrir en terminal", + "linkedFolder": "Carpeta vinculada", + "copyPath": "Copiar ruta", + "upload": "Subir archivos/carpeta", + "download": "Descargar archivo", + "downloadAsZip": "Descargar como ZIP", + "actions": { + "select": "Seleccionar", + "unselect": "Deseleccionar", + "commitCode": "Confirmar código", + "rollback": "Revertir", + "addToVcs": "Añadir a VCS" + }, + "aria": { + "selectPath": "{action}: {path}" + }, + "toasts": { + "openDirectoryFailed": "No se pudo abrir el directorio", + "openBuiltinTerminalFailed": "No se pudo abrir la terminal integrada", + "openCommitWindowFailed": "No se pudo abrir la ventana de commit", + "noAddableFilesInDir": "No hay archivos modificados en este directorio que se puedan añadir a VCS", + "noRollbackFilesInDir": "No hay archivos modificados en este directorio que se puedan revertir", + "addedToVcs": "Se añadió {name} a VCS", + "addToVcsFailed": "No se pudo añadir a VCS", + "loadBranchesFailed": "No se pudieron cargar las ramas", + "renameFailed": "Error al renombrar", + "moveFailed": "Error al mover", + "deleteFailed": "Error al eliminar", + "rolledBack": "Se revirtió {name}", + "rollbackFailed": "Error al revertir", + "addedFilesToVcs": "{count, plural, one {Se añadió # archivo a VCS} other {Se añadieron # archivos a VCS}}", + "rolledBackFiles": "{count, plural, one {Se revirtió # archivo} other {Se revirtieron # archivos}}", + "savedAsCopy": "Guardado como copia", + "saveCopyFailed": "No se pudo guardar como copia", + "watchStartFailed": "No se pudo iniciar la vigilancia de archivos", + "createFailed": "Error al crear", + "downloadFailed": "No se pudo descargar {name}", + "downloadSaved": "{name} descargado", + "pathCopied": "Ruta copiada", + "copyPathFailed": "No se pudo copiar la ruta" + }, + "createDialog": { + "newFile": "Nuevo archivo", + "newDirectory": "Nuevo directorio", + "description": "Ingrese un nombre para el nuevo {kind}.", + "placeholderFile": "file-name.ext", + "placeholderDirectory": "folder-name" + }, + "renameDialog": { + "renameDirectory": "Renombrar directorio", + "renameFile": "Renombrar archivo", + "description": "Introduce un nuevo nombre (solo nombre, sin ruta).", + "placeholderDirectory": "nuevo-nombre-carpeta", + "placeholderFile": "nuevo-nombre-archivo.ext" + }, + "uploadDialog": { + "title": "Subir al área de trabajo", + "description": "Ajusta el destino si es necesario y añade archivos o carpetas.", + "workspaceRoot": "raíz del área de trabajo", + "targetPathLabel": "Subir a", + "targetPathHint": "Ruta resuelta: {path}", + "dropHint": "Arrastra archivos o carpetas aquí, o usa los botones de abajo", + "dropHintActive": "Suelta para añadir a la cola", + "selectFiles": "Seleccionar archivos", + "selectFolder": "Seleccionar carpeta", + "startUpload": "Iniciar subida", + "clearQueue": "Limpiar finalizados", + "removeItem": "Quitar de la cola", + "retry": "Reintentar", + "dropZoneAria": "Suelta archivos aquí o activa para examinar", + "folderEmpty": "No se encontraron archivos en la carpeta soltada", + "summary": "Total: {total} · Con éxito: {succeeded} · Con error: {failed}", + "status": { + "pending": "En espera", + "uploading": "Subiendo", + "success": "Completado", + "error": "Falló", + "cancelled": "Cancelado" + } + }, + "directoryDialog": { + "descriptionAdd": "Selecciona archivos del directorio {path} para añadir a VCS.", + "descriptionRollback": "Selecciona archivos del directorio {path} para revertir.", + "descriptionFallback": "Selecciona archivos para continuar.", + "selectionCount": "Seleccionados {selected} / {total} archivos", + "selectAll": "Seleccionar todo", + "unselectAll": "Deseleccionar todo", + "loadingCandidates": "Cargando cambios del directorio...", + "noOperableFiles": "No hay archivos operables" + }, + "compareDialog": { + "title": "Comparar con rama", + "descriptionWithTarget": "Selecciona una rama y compara con {kind} {path}", + "descriptionFallback": "Selecciona una rama para comparar.", + "kindDirectory": "directorio", + "kindFile": "archivo", + "filterPlaceholder": "Filtra ramas, p. ej. main / origin/main", + "singleClickHint": "Haz clic en una rama para comparar directamente", + "loadingBranches": "Cargando ramas...", + "recentBranches": "Ramas recientes ({count})", + "noCurrentBranch": "Sin rama actual", + "localBranches": "Ramas locales ({count})", + "remoteBranches": "Ramas remotas ({count})", + "noMatchingBranches": "No hay ramas coincidentes" + }, + "externalConflictDialog": { + "title": "Se detectaron cambios externos en archivos", + "descriptionWithPath": "El archivo {path} cambió en disco y las ediciones actuales no están guardadas.", + "descriptionFallback": "El archivo actual cambió en disco y las ediciones actuales no están guardadas.", + "compare": "Comparar", + "savingCopy": "Guardando copia...", + "saveAsCopy": "Guardar como copia", + "reload": "Recargar" + }, + "deleteConfirm": { + "title": "Confirmar eliminación", + "descriptionWithTarget": "¿Eliminar {kind} \"{name}\"? Esta acción no se puede deshacer.", + "descriptionFallback": "Esta acción no se puede deshacer.", + "kindDirectory": "directorio", + "kindFile": "archivo" + }, + "rollbackConfirm": { + "title": "Confirmar reversión", + "descriptionWithTarget": "¿Revertir cambios locales del archivo \"{name}\"?", + "descriptionFallback": "¿Revertir cambios locales de este archivo?" + }, + "terminalTitle": "Consola · {name}" + }, + "commandDropdown": { + "loading": "Cargando...", + "addCommand": "Agregar comando", + "manageCommands": "Gestionar comandos...", + "runCommandTitle": "Ejecutar: {command}", + "stopCommandTitle": "Detener: {command}", + "manageDialog": { + "title": "Gestionar comandos", + "empty": "Aún no hay comandos", + "noResults": "No hay comandos coincidentes", + "searchPlaceholder": "Buscar comandos", + "newCommand": "Nuevo comando", + "nameLabel": "Nombre", + "commandLabel": "Comando", + "dragSort": "Arrastra para ordenar", + "dragSortCommand": "Arrastra para ordenar {name}", + "orderFailed": "No se pudo guardar el orden de los comandos", + "loadFailed": "No se pudieron cargar los comandos", + "saveFailed": "No se pudo guardar el comando", + "deleteFailed": "No se pudo eliminar el comando", + "confirmDelete": { + "title": "¿Eliminar comando?", + "message": "Esto eliminará \"{name}\". Esta acción no se puede deshacer." + } + } + }, + "workspaceContext": { + "confirmCloseDirtyTab": "¿Cerrar \"{title}\" sin guardar?", + "confirmCloseOtherDirtyTabs": "¿Cerrar otras pestañas con cambios sin guardar?", + "confirmCloseAllDirtyTabs": "¿Cerrar todas las pestañas con cambios sin guardar?", + "unableLoadContent": "No se puede cargar el contenido.\n\n{message}", + "previewRequestTimedOut": "La solicitud de vista previa agotó el tiempo", + "diffRequestTimedOut": "La solicitud de Diff agotó el tiempo", + "branchCompareRequestTimedOut": "La solicitud de comparación de ramas agotó el tiempo", + "commitDiffRequestTimedOut": "La solicitud de Diff de commit agotó el tiempo", + "saveRequestTimedOut": "La solicitud de guardado agotó el tiempo", + "reloadRequestTimedOut": "La solicitud de recarga agotó el tiempo", + "noChanges": "Sin cambios.", + "noDiffOutput": "Sin salida de diff.", + "diffTitleWorkspace": "Diferencias · Espacio de trabajo", + "diffDescriptionWorkingTree": "Árbol de trabajo (HEAD)", + "diffTitleFile": "Diferencias · {name}", + "compareTitleFile": "Comparar · {name}", + "compareTitleBranch": "Comparar · {branch}", + "compareDescriptionPath": "{path} · comparar con {branch}", + "compareDescriptionBranch": "comparar con {branch}", + "diffTitleCommitFile": "Diferencias · {name} @ {hash}", + "diffTitleCommit": "Diferencias · {hash}", + "diffDescriptionCommitPath": "{path} · confirmación {commit}", + "diffDescriptionCommit": "confirmación {commit}", + "diffTitleConflictFile": "Conflicto · {name}", + "diffDescriptionConflict": "{path} · disco vs sin guardar" + }, + "chat": { + "acpConnections": { + "actions": { + "openAgentsSettings": "Abrir ajustes de agentes", + "retry": "Reintentar" + }, + "agentsSetupHint": "Abre Ajustes > Agentes para gestionar la instalación.", + "withSetupHint": "{message}\n{hint}", + "blocked": { + "missingConfig": "No se puede leer la configuración actual del agente.", + "disabled": "{agent} está deshabilitado en Ajustes de agentes. Actívalo antes de conectar.", + "unavailable": "{agent} no está disponible en la plataforma actual.", + "sdkMissing": "El SDK de {agent} no está instalado", + "adapterMissing": "El adaptador ACP de {agent} no está instalado" + }, + "backendErrors": { + "initializeTimeout": "Se agotó el tiempo del handshake de conexión de {agent} (sin respuesta tras 60 segundos). Abre Ajustes para revisar la configuración del agente y de la red.", + "mcpRejectedByAgent": "{agent} rechazó la sesión con el complemento MCP de codeg adjunto: {message} Si este agente no admite MCP, desactiva «Compatibilidad con MCP» en Ajustes y vuelve a conectar.", + "processExited": "El proceso de {agent} terminó inesperadamente.", + "spawnFailed": "No se pudo iniciar {agent}: {message}", + "downloadFailed": "La descarga de {agent} falló: {message}", + "sessionLoadResourceNotFound": "Error al cargar la sesión de {agent}. Recarga para reintentar o inicia una nueva conversación.", + "sessionLoadUnavailable": "{agent} no pudo restaurar esta sesión; es posible que haya finalizado o que el agente se haya detenido. Recarga para reintentar o inicia una nueva conversación.", + "turnFailedRefusal": "{agent} rechazó continuar este turno. Suele indicar un error de backend o pasarela. Revisa los registros del agente.", + "turnFailedMaxTokens": "{agent} alcanzó el límite máximo de tokens para este turno.", + "turnFailedMaxTurnRequests": "{agent} alcanzó el número máximo de solicitudes permitidas para este turno.", + "turnFailedUnknown": "{agent} finalizó el turno con un motivo de parada no reconocido.", + "grokModelSwitchIncompatibleAgent": "{agent} no puede cambiar a ese modelo en una conversación existente. Inicia una nueva sesión para usarlo.", + "turnFailedEmpty": "{agent} finalizó el turno sin producir ninguna respuesta.", + "turnFailedEmptyProtocol": "{agent} produjo una salida que codeg no pudo analizar; la versión del agente podría no coincidir con el protocolo.", + "turnFailedEmptyMetadata": "{agent} solo envió actualizaciones de estado en este turno (plan / modo / uso) y ninguna respuesta.", + "detailsInAlerts": "Abre Alertas en la barra de estado y despliega los detalles para ver la salida del agente." + }, + "unableReadAgentConfig": "No se puede leer la configuración del agente: {message}", + "connectFailedTitle": "Falló la conexión de {agent}", + "toolFallbackTitle": "Herramienta", + "eventErrorTitle": "Error del agente", + "notificationTurnComplete": "{agent} ha terminado de responder", + "notificationError": "{agent} error: {message}", + "claudeApiRetry": { + "fallbackError": "authentication_failed", + "retryingWithMax": "reintentando {attempt}/{max}", + "retryingAttempt": "reintentando intento {attempt}", + "retrying": "reintentando", + "nextRetryIn": "siguiente en {seconds}s", + "line": "{error}{status} · {retry}", + "lineWithDelay": "{error}{status} · {retry}, {delay}", + "httpStatus": " (HTTP {status})" + }, + "configOptionAdjusted": "{agent} estableció {option} en {actual} en lugar de {requested}" + }, + "connectionLifecycle": { + "tasks": { + "connectingTitle": "Conectando con {agent}", + "connectingDescription": "Estableciendo conexión", + "loadingSelectorsTitle": "Cargando selectores de {agent}", + "loadingSelectorsDescription": "Obteniendo opciones de modo y configuración de sesión", + "initSessionTitle": "Initializing {agent} session", + "initSessionDescription": "Creating session and loading configuration" + }, + "errors": { + "connectionFailed": "Conexión fallida", + "sendPromptFailed": "No se pudo enviar el mensaje: {error}" + } + }, + "shared": { + "attachedResources": "Recursos adjuntos", + "toolCallFailed": "Falló la llamada de herramienta" + }, + "messageThread": { + "emptyTitle": "Aún no hay mensajes", + "emptyDescription": "Inicia una conversación para ver mensajes aquí" + }, + "chatInput": { + "connecting": "Conectando...", + "agentResponding": "{agent} está respondiendo...", + "sendMessage": "Enviar un mensaje..." + }, + "messageInput": { + "askAnything": "Pregunta lo que sea...", + "removeAttachmentAria": "Quitar {name}", + "attachFiles": "Adjuntar archivos", + "addActions": "Añadir", + "quickMessages": "Mensajes rápidos", + "quickMessagesEmpty": "Aún no hay mensajes rápidos", + "quickMessagesLoading": "Cargando...", + "pasteAsPlainText": "Pegar como texto sin formato", + "cut": "Cortar", + "copy": "Copiar", + "selectAll": "Seleccionar todo", + "pasteUnavailable": "No se pudo leer el portapapeles. Pulsa Ctrl/⌘V para pegar.", + "clipboardWriteFailed": "No se pudo escribir en el portapapeles. Usa el atajo de teclado.", + "quickMessageUntitled": "Sin título", + "liveFeedback": "Comentarios en vivo", + "liveFeedbackDisabledHint": "Disponible mientras el agente trabaja", + "dropFilesToAttach": "Suelta archivos para adjuntar", + "loadingSettings": "Cargando ajustes...", + "loadingMode": "Cargando modo...", + "modeLabel": "Modo", + "toggleOn": "Activado", + "toggleOff": "Desactivado", + "agentSettings": "Ajustes del agente", + "searchModel": "Buscar modelos...", + "searchModelAria": "Buscar modelos", + "modelListLabel": "Modelos", + "noModels": "No se encontraron modelos", + "cancel": "Cancelar", + "send": "Enviar", + "forkAndSend": "Fork y Enviar", + "queueMessage": "Poner en cola", + "steerIntoTurn": "Insertar en el turno actual", + "steerQueuedInstead": "Se puso en cola: se enviará con el siguiente turno.", + "steerFailed": "No se pudo insertar en el turno actual", + "steerAttachmentsUnsupported": "Solo texto: los borradores con adjuntos pasan por la cola.", + "slashCommands": "Comandos de barra", + "slashSearchPlaceholder": "Buscar comandos...", + "slashSearchEmpty": "Sin comandos coincidentes", + "experts": "Expertos", + "office": "Ofimática", + "research": "Investigación", + "attachLocalUpload": "Subir archivo local", + "attachServerFile": "Seleccionar archivo del servidor", + "attachUploadTooLarge": "{names} supera el límite de carga de {limit}MB y se omitió.", + "attachUploadFailed": "Error al subir {names}.", + "attachUploadNotAFile": "{names} no es un archivo regular (directorio o archivo especial) y se omitió.", + "attachUploadQuotaExceeded": "El servidor se quedó sin espacio para subidas; no se pudo cargar {names}.", + "attachUploadInProgress": "Las imágenes aún se están subiendo; inténtalo de nuevo en un momento.", + "mentionEmpty": "Sin coincidencias", + "mentionLoading": "Buscando…", + "mentionListLabel": "Menciones", + "mentionMore": "Más resultados: sigue escribiendo para filtrar", + "mentionCount": "{count, plural, one {# resultado} other {# resultados}}", + "mentionGroupFile": "Archivos", + "mentionGroupAgent": "Agentes", + "mentionGroupSession": "Sesiones", + "mentionGroupCommit": "Commits", + "mentionGroupSkill": "Habilidades" + }, + "messageQueue": { + "addToQueue": "Agregar a la cola", + "saveEdit": "Guardar", + "cancelEdit": "Cancelar edición", + "editItem": "Editar", + "deleteItem": "Eliminar" + }, + "welcomeInputPanel": { + "agentsSettingsPath": "Ajustes > Agentes", + "autoConnectFallback": "Haz clic para abrir {path} y gestionar la instalación.", + "autoConnectAppend": "{message}. Haz clic para abrir {path} y gestionar la instalación.", + "enableAgentFirstPlaceholder": "Habilita al menos un agente antes de iniciar una sesión...", + "prepareSessionFailed": "No se pudo preparar la sesión de chat. Inténtalo de nuevo.", + "createConversationFailed": "No se pudo crear la conversación. Inténtalo de nuevo.", + "askAnythingPlaceholder": "Pregunta lo que sea...", + "agentNotInstalled": "{agent} no está instalado · abre la configuración de Agents para instalarlo", + "agentAdapterNotInstalled": "El adaptador ACP de {agent} no está instalado (es aparte de tu propia CLI) · abre la configuración de Agents para instalarlo" + }, + "welcomePanel": { + "greeting": "¿Qué te gustaría hacer hoy?", + "tips": { + "tileTabs": "Haz clic derecho en una pestaña de conversación y elige Vista en mosaico para comparar varias sesiones lado a lado.", + "pinTab": "Haz doble clic en una pestaña de conversación para fijarla y que una sesión nueva no la reemplace automáticamente.", + "shortcutsNewSearch": "{newConversation} abre una conversación nueva, {searchConversations} busca en el historial.", + "slashAtMention": "Escribe / en la entrada para activar comandos slash, o @ para referenciar un archivo del proyecto.", + "pasteDropFiles": "Pega una captura de pantalla o arrastra un archivo a la entrada para adjuntarlo.", + "queueMessage": "Mientras el agente responde, sigue escribiendo: tu próximo mensaje se pone en cola y se envía al terminar.", + "draftAutoSave": "Los borradores sin enviar se guardan automáticamente por conversación y se restauran al volver.", + "forkSend": "El desplegable del botón de enviar incluye Bifurcar y enviar, que ramifica desde el punto actual a una pestaña nueva.", + "exportConversation": "Haz clic derecho dentro de la conversación para exportarla como Markdown, HTML o imagen.", + "chatChannels": "Conecta Telegram / Lark / WeChat en Ajustes → Canales de chat para continuar desde el móvil.", + "shortcutsAuxPanel": "{toggleAuxPanel} alterna el panel derecho para ver los archivos tocados y los cambios de Git de esta sesión.", + "shortcutsTerminalSidebar": "{toggleTerminal} abre la terminal integrada, {toggleSidebar} alterna la barra lateral.", + "customShortcuts": "Todos los atajos se pueden reasignar en Ajustes → Atajos.", + "webService": "Activa Ajustes → Servicio web para que tu equipo acceda al mismo codeg desde un navegador.", + "fusionMode": "Abre un archivo o diff para mostrarlo automáticamente junto a la conversación.", + "quickMessages": "Abre el botón + junto a la entrada y elige Mensajes rápidos para insertar un fragmento guardado (gestiónalos en Ajustes → Mensajes rápidos).", + "experts": "El botón + tiene un menú Habilidades expertas: carga roles como Depuración o Planificación con un clic.", + "taskBoard": "Las tareas pendientes ejecutan un trabajo de principio a fin: el agente trabaja en su propio worktree y tú revisas el diff antes de fusionar.", + "automations": "Las Automatizaciones ejecutan un prompt guardado según un horario —una revisión nocturna, un informe recurrente— y cada ejecución puede tener su propio worktree.", + "tokenUsage": "Haz clic en el número de conversaciones de la barra de estado para abrir Uso de tokens, desglosado por día, agente, modelo y carpeta.", + "mentionTargets": "@ no solo trae archivos: menciona a otro agente para delegarle una subtarea, o referencia una sesión anterior, un commit o una habilidad.", + "splitGroups": "Haz clic derecho en una pestaña y elige Dividir a la derecha o Dividir abajo para mantener dos conversaciones en paneles propios.", + "worktrees": "Abre el botón de rama y elige Nuevo worktree para que varios agentes trabajen en el mismo repositorio sin pisarse los archivos.", + "importSessions": "¿Ya ejecutaste sesiones en la terminal? El menú de una carpeta tiene Importar sesiones locales para traer ese historial a codeg.", + "subSessions": "Cuando un agente delega, la subsesión aparece anidada bajo él en la barra lateral: despliega la fila para seguir lo que hizo cada una.", + "liveFeedback": "Comentarios en vivo, en el menú +, inserta una nota en el turno que el agente ya está ejecutando, sin interrumpirlo.", + "skillPacks": "Configuración → Paquetes de habilidades reúne expertos de programación, investigación científica y ofimática; actívalos por agente.", + "modelProviders": "Configuración → Proveedores de Modelos acepta tu propia clave de API o endpoint, y el modelo lo eliges desde el cuadro de entrada.", + "workspaceBackground": "Configuración → Apariencia define una imagen de fondo del espacio de trabajo, la opacidad de los paneles y las fuentes de la app." + }, + "quickActions": { + "excel": "Libro de Excel", + "excelDesc": "Tablas, fórmulas y gráficos", + "word": "Documento de Word", + "wordDesc": "Informes, cartas y notas", + "ppt": "Presentación", + "pptDesc": "Diapositivas con diseño profesional", + "pitchDeck": "Pitch Deck", + "pitchDeckDesc": "Presentación de inversión con métricas", + "morph": "Animación Morph", + "morphDesc": "Transiciones de diapositiva cinematográficas", + "morph3d": "Morph 3D", + "morph3dDesc": "Modelos 3D con movimientos de cámara", + "academic": "Artículo académico", + "academicDesc": "Investigación con citas y estructura", + "financial": "Modelo financiero", + "financialDesc": "Estados, DCF y proyecciones", + "dashboard": "Panel de datos", + "dashboardDesc": "KPIs y análisis a partir de tus datos", + "prompts": { + "excel": "Crea un libro de Excel con los siguientes requisitos:\n\n[describe aquí tus datos, tablas, fórmulas y gráficos]", + "word": "Crea un documento de Word con los siguientes requisitos:\n\n[describe aquí el contenido, la estructura y el formato del documento]", + "ppt": "Crea una presentación de PowerPoint con los siguientes requisitos:\n\n[describe aquí tus diapositivas, contenido y diseño]", + "pitchDeck": "Crea un pitch deck de inversión con los siguientes requisitos:\n\n[describe aquí tu empresa, ronda de financiación y métricas clave]", + "morph": "Crea una presentación con animaciones de transición Morph:\n\n[describe aquí el tema de la presentación y los efectos visuales deseados]", + "morph3d": "Crea una presentación Morph 3D con modelos GLB y movimientos de cámara:\n\n[describe aquí tu tema y concepto visual en 3D]", + "academic": "Escribe un artículo académico en Word con los siguientes requisitos:\n\n[describe aquí tu tema de investigación, metodología y hallazgos clave]", + "financial": "Crea un modelo financiero en Excel con los siguientes requisitos:\n\n[describe aquí tus estados financieros, proyecciones y análisis]", + "dashboard": "Crea un panel de datos en Excel con los siguientes requisitos:\n\n[describe aquí tu fuente de datos, KPIs y gráficos]", + "scientific-brainstorming": "Ayúdame a generar ideas de investigación: explora conexiones interdisciplinares, cuestiona supuestos y detecta vacíos prometedores. El área que exploro: ", + "hypothesis-generation": "Ayúdame a convertir estas observaciones en hipótesis comprobables, con predicciones claras, mecanismos plausibles y experimentos para probarlas. Mis observaciones: ", + "experimental-design": "Ayúdame a diseñar un experimento riguroso antes de recolectar datos: el diseño, la aleatorización, los controles y cómo evitar la confusión. Lo que quiero estudiar: ", + "statistical-power": "Ayúdame a determinar el tamaño muestral que necesito: guíame en un análisis de potencia (tamaño del efecto, alfa, potencia) para mi diseño. Detalles: ", + "statistical-analysis": "Ayúdame a analizar estos datos correctamente: elige la prueba adecuada, verifica los supuestos, informa los tamaños de efecto y redáctalo. Mis datos y pregunta: ", + "exploratory-data-analysis": "Haz un análisis exploratorio de mi archivo de datos: resume su estructura, calidad y patrones destacados, y sugiere próximos pasos. El archivo es: ", + "scientific-visualization": "Ayúdame a crear una figura de calidad de publicación: diseño claro, barras de error honestas, una paleta apta para daltónicos y formato de revista. Lo que quiero mostrar: ", + "scientific-critical-thinking": "Ayúdame a evaluar críticamente este estudio o afirmación: valora la calidad de la evidencia, detecta sesgos y confusores, y pondera las conclusiones. Aquí está: ", + "paper-lookup": "Ayúdame a encontrar artículos relevantes y texto completo de acceso abierto en bases de datos académicas, con citas que pueda reutilizar. Busco: " + }, + "paper-lookup": "Búsqueda de artículos", + "paper-lookupDesc": "Busca en 10 API académicas (PubMed, arXiv, OpenAlex, Crossref…) artículos, citas y texto completo de acceso abierto.", + "scientific-critical-thinking": "Pensamiento crítico", + "scientific-critical-thinkingDesc": "Evalúa afirmaciones científicas y calidad de la evidencia: detecta sesgos y confusores, aplica GRADE y riesgo de sesgo.", + "scientific-visualization": "Visualización científica", + "scientific-visualizationDesc": "Figuras listas para publicar: diseños multipanel, anotaciones de significancia y formato específico de revista.", + "exploratory-data-analysis": "Análisis exploratorio de datos", + "exploratory-data-analysisDesc": "Exploración automatizada de archivos de datos científicos en más de 200 formatos con métricas de calidad e informes.", + "statistical-analysis": "Análisis estadístico", + "statistical-analysisDesc": "Análisis estadístico guiado: selección de pruebas, verificación de supuestos, tamaños de efecto e informe estilo APA.", + "statistical-power": "Potencia estadística", + "statistical-powerDesc": "Análisis de tamaño muestral y potencia: cuántos sujetos necesitas, efectos mínimos detectables y curvas de potencia.", + "experimental-design": "Diseño experimental", + "experimental-designDesc": "Diseña estudios rigurosos antes de recolectar datos: aleatorización, bloqueo, controles y diseños factoriales/DOE.", + "hypothesis-generation": "Generación de hipótesis", + "hypothesis-generationDesc": "Convierte observaciones en hipótesis comprobables con predicciones, mecanismos y experimentos para probarlas.", + "scientific-brainstorming": "Lluvia de ideas científica", + "scientific-brainstormingDesc": "Ideación abierta de investigación: explora conexiones interdisciplinares, cuestiona supuestos y detecta vacíos.", + "tabs": { + "office": "Ofimática", + "coding": "Desarrollo de código", + "research": "Investigación" + }, + "coding": { + "brainstormingDesc": "Explora intención y requisitos antes de construir", + "debuggingDesc": "Encuentra la causa raíz antes de proponer arreglos", + "writingSkillsDesc": "Crea, edita y verifica habilidades reutilizables" + }, + "notEnabled": { + "title": "La habilidad «{skill}» aún no está activada para {agent}", + "description": "Actívala en Ajustes para usarla aquí.", + "action": "Activar", + "hint": "Habilidad no activada" + }, + "scrollPrev": "Mostrar habilidades anteriores", + "scrollNext": "Mostrar más habilidades" + } + }, + "agentSelector": { + "noEnabledAgents": "No hay agentes habilitados", + "openAgentsSettings": "Abrir ajustes de agentes", + "notInstalled": "No instalado", + "moreAgents": "Más agentes ({count})" + }, + "subAgentOverlay": { + "title": "Subagentes", + "collapsedSummary": "Subagentes {count}", + "collapseAria": "Contraer subagentes" + }, + "agentPlanOverlay": { + "title": "Plan del agente", + "collapsePlanAria": "Contraer plan", + "collapsedSummary": "Plan de trabajo {completed}/{total}", + "status": { + "completed": "Completado", + "inProgress": "En progreso", + "pending": "Pendiente", + "unknown": "Desconocido" + }, + "priority": { + "high": "Alta", + "medium": "Media", + "low": "Baja", + "unknown": "Desconocida" + } + }, + "permissionDialog": { + "subtitle": "El agente solicita permiso para continuar este turno.", + "queuedCount": "+{count} en espera", + "kindFallbackTool": "herramienta", + "command": "Comando", + "cwd": "Directorio de trabajo: {cwd}", + "filesSummary": "Archivos: {count}", + "moreFiles": "+{count} archivos más", + "plan": "Plan de trabajo", + "allowedActions": "Acciones permitidas", + "targetMode": "Modo objetivo: {mode}", + "optionGrants": "Lo que concede cada opción", + "changeScopeSession": "Esta sesión", + "changeScopeProcess": "Esta ejecución", + "changeScopeUser": "Guardado en la configuración del usuario", + "changeScopeProject": "Guardado en la configuración del proyecto", + "changeScopeProjectLocal": "Guardado en la configuración local del proyecto", + "changeScopePersistent": "Guardado permanentemente" + }, + "questionDialog": { + "title": "El agente está haciendo una pregunta", + "placeholder": "Escribe tu respuesta...", + "send": "Enviar" + }, + "messageBranch": { + "previousBranchAria": "Rama anterior", + "nextBranchAria": "Rama siguiente", + "pageOf": "{current} de {total}" + }, + "terminal": { + "title": "Consola", + "running": "En ejecución" + }, + "reasoning": { + "thinking": "Pensando…", + "thoughtForFewSeconds": "Pensamiento", + "thoughtForSeconds": "Pensamiento" + }, + "linkSafety": { + "errorCannotOpen": "No se puede abrir el archivo local", + "errorNoWorkspace": "No hay ninguna carpeta de espacio de trabajo activa.", + "errorFailedOpen": "Error al abrir el archivo local", + "errorFailedLink": "Error al abrir el enlace", + "errorUnsupportedLinkProtocol": "Este protocolo de enlace no es compatible." + }, + "fileActions": { + "openInFinder": "Abrir en Finder", + "openInExplorer": "Abrir en Explorer", + "openInFileManager": "Abrir en el gestor de archivos", + "copyRelativePath": "Copiar ruta relativa", + "copyAbsolutePath": "Copiar ruta absoluta", + "pathCopied": "Ruta copiada", + "copyPathFailed": "No se pudo copiar la ruta", + "openFailed": "Error al abrir el archivo local" + }, + "messageList": { + "attachedResources": "Recursos adjuntos", + "loading": "Cargando...", + "loadEarlier": "Cargar mensajes anteriores", + "loadingEarlier": "Cargando mensajes anteriores…", + "error": "Error del chat: {message}", + "errorTitle": "Error al cargar la sesión", + "errorActionReload": "Recargar", + "errorActionNewSession": "Nueva conversación", + "emptyConversation": "No hay mensajes en esta conversación.", + "systemMessage": "Mensaje del sistema", + "copyMessage": "Copiar", + "copied": "Copiado", + "downloadImage": "Descargar imagen", + "downloadFailed": "Descarga fallida: {message}", + "imageGeneration": "Generación de imágenes", + "imageGenerationPending": "Generando imagen…", + "imageGenerationFailed": "Error al generar la imagen", + "model": "Modelo", + "tokenStats": "Uso de tokens", + "tokenInput": "Entrada", + "tokenOutput": "Salida", + "tokenCacheRead": "Lectura de caché", + "tokenCacheWrite": "Escritura de caché", + "duration": "Duración", + "completedAt": "Completado a las", + "jumpToPreviousUserMessage": "Ir al mensaje del usuario", + "showMore": "Mostrar más", + "showLess": "Mostrar menos" + }, + "liveTurnStats": { + "thinking": "Pensando...", + "streaming": "Transmitiendo", + "elapsedHours": "{value} h", + "elapsedMinutes": "{value} min", + "elapsedSeconds": "{value} s", + "outputSpeedAria": "Velocidad de salida estimada", + "outputSpeedTooltip": "Velocidad de salida estimada (texto + razonamiento)" + }, + "jsonTree": { + "viewRaw": "Ver JSON sin formato", + "viewTree": "Ver árbol", + "fields": "{count, plural, one {# campo} other {# campos}}", + "items": "{count, plural, one {# elemento} other {# elementos}}" + }, + "tool": { + "parameters": "Parámetros", + "error": "Error de herramienta", + "result": "Resultado", + "status": { + "approvalRequested": "Esperando aprobación", + "approvalResponded": "Respondido", + "inputAvailable": "En ejecución", + "inputStreaming": "Pendiente", + "outputAvailable": "Completado", + "outputDenied": "Denegado", + "outputError": "Error de salida" + } + }, + "toolCallBlock": { + "tool": "Herramienta", + "error": "Error de ejecución", + "result": "Resultado" + }, + "delegation": { + "subAgentRunning": "Subagente en ejecución…", + "noDetail": "No detail available yet.", + "unknownAgent": "Sub-agente", + "openDetail": "Ver conversación", + "detailTitle": "Conversación del subagente", + "detailDescription": "Vista de solo lectura de la conversación del subagente delegado.", + "waitForResult": "Esperando el resultado de la tarea {task}", + "waitForResultNoTask": "Esperando el resultado de la tarea", + "cancelTask": "Cancelando la tarea {task}", + "cancelTaskNoTask": "Cancelando la tarea", + "resultPageOf": "{current} / {total}", + "prevResult": "Resultado anterior", + "nextResult": "Resultado siguiente", + "noResultText": "Sin resultado en esta comprobación.", + "status": { + "starting": "iniciando", + "running": "en curso", + "checked": "consultado", + "waiting": "esperando aprobación", + "ok": "completado", + "err": { + "default": "fallido", + "delegation_disabled": "deshabilitado", + "depth_limit": "límite de profundidad", + "invalid_agent_type": "agente inválido", + "spawn_failed": "fallo al iniciar", + "send_failed": "fallo al enviar", + "timeout": "tiempo agotado", + "canceled": "cancelado", + "child_refusal": "subagente rechazó", + "child_max_tokens": "subagente: límite de tokens", + "child_max_turn_requests": "subagente: límite de solicitudes", + "child_empty": "subagente sin salida", + "child_unknown": "subagente: error", + "unknown": "tarea desconocida" + } + } + }, + "contentParts": { + "showingTailOutput": "Mostrando la salida final durante el streaming para mejorar el rendimiento.", + "result": "Resultado", + "unknown": "desconocido", + "inputTruncated": "La entrada fue truncada — el diff puede estar incompleto.", + "replaceAll": "REEMPLAZAR TODO", + "filesCount": "Archivos: {count}", + "update": "actualizar", + "moreFiles": "+{count} archivos más", + "timeoutMs": "Tiempo de espera: {timeout}ms", + "backgroundTrue": "Segundo plano: true", + "scriptToolCalls": "{count, plural, one {# llamada a herramienta} other {# llamadas a herramientas}}", + "offset": "Desplazamiento: {offset}", + "limit": "Límite: {limit}", + "pages": "Páginas: {pages}", + "mode": "Modo: {mode}", + "cell": "Celda: {cell}", + "shellSession": "Sesión {id}", + "pathLabel": "Ruta:", + "globLabel": "Patrón glob:", + "typeLabel": "Tipo:", + "outputLabel": "Salida:", + "caseInsensitive": "Sin distinguir mayúsculas/minúsculas", + "multiline": "Multilínea", + "promptLabel": "Instrucción", + "subjectLabel": "Asunto", + "taskLabel": "Tarea", + "nameLabel": "Nombre:", + "agentPromptLabel": "Instrucción", + "agentModelLabel": "Modelo", + "agentRunning": "Ejecutando...", + "agentLiveTranscript": "Actividad en vivo", + "agentProgressTools": "{count} llamadas a herramientas", + "agentProgressTurns": "{count} turnos", + "agentProgressContext": "contexto {pct}%", + "agentSessionAction": "Ver la sesión del subagente", + "agentSessionTitle": "Sesión del subagente", + "agentSessionLoading": "Cargando la transcripción del subagente…", + "agentSessionEmpty": "El subagente aún no ha escrito nada.", + "agentFallbackTitle": "Iniciando subagente…", + "agentCodexLaunchOnly": "Lanzado. Codex no informa de más progreso sobre este subagente: su resultado llega como un mensaje en esta conversación.", + "agentStatsBash": "Comandos", + "agentStatsRead": "Archivos leídos", + "agentStatsSearch": "Búsquedas", + "agentStatsEdit": "Ediciones", + "agentStatsOther": "Otros", + "goal": { + "title": "Objetivo:", + "titleWithStatus": "Objetivo {status}", + "objective": "Objetivo", + "statusLabel": "Estado", + "tokensUsed": "Tokens usados", + "budget": "Presupuesto", + "remaining": "Restante", + "elapsed": "Transcurrido", + "tokens": "tokens", + "pause": "Pausar", + "clear": "Borrar", + "status": { + "active": "activo", + "paused": "pausado", + "blocked": "bloqueado", + "usageLimited": "uso limitado", + "budgetLimited": "presupuesto limitado", + "complete": "completo", + "limited": "límite alcanzado" + } + }, + "field": { + "file": "Archivo", + "notebook": "Cuaderno", + "command": "Comando", + "old": "Anterior", + "new": "Nuevo", + "pattern": "Patrón", + "path": "Ruta", + "query": "Consulta", + "url": "URL:", + "description": "Descripción", + "content": "Contenido", + "source": "Fuente", + "prompt": "Instrucción", + "subject": "Asunto", + "taskId": "ID de tarea", + "status": "Estado", + "skill": "Skill", + "args": "Argumentos", + "offset": "Desplazamiento", + "limit": "Límite", + "glob": "Patrón glob", + "type": "Tipo", + "output": "Salida", + "replaceAll": "Reemplazar todo", + "language": "Idioma", + "timeout": "Tiempo de espera", + "background": "Segundo plano", + "agentType": "Tipo de agente", + "library": "Biblioteca", + "libraryId": "ID de biblioteca" + }, + "title": { + "edit": "Editar", + "command": "Comando", + "script": "Script", + "waitCommand": "Esperar {command}", + "waitCell": "Esperar sesión {id}", + "terminateCommand": "Terminar {command}", + "terminateCell": "Terminar sesión {id}", + "stdinChars": "Entrada {chars}", + "todoWrite": "TodoWrite (actualización de tareas)", + "read": "Leer", + "write": "Escribir", + "notebookEdit": "NotebookEdit (edición de cuaderno)", + "editFiles": "Editar ({count} archivos)", + "editWithTarget": "Editar {target}", + "readWithTarget": "Leer {target}", + "writeWithTarget": "Escribir {target}", + "notebookEditWithTarget": "NotebookEdit ({target})", + "globWithPattern": "Patrón glob {pattern}", + "listFilesWithPath": "Listar archivos {path}", + "grepWithPattern": "Patrón grep {pattern}", + "taskCreateWithSubject": "Crear tarea: {subject}", + "taskUpdateWithStatus": "Actualizar tarea #{id} -> {status}", + "taskUpdate": "Actualizar tarea #{id}", + "webFetchWithUrl": "WebFetch ({url})", + "webSearchWithQuery": "Búsqueda web: {query}", + "todosProgress": "Tareas ({done}/{total})", + "skillWithName": "Skill: {name}", + "genericWithContext": "{tool} ({context})" + }, + "search": { + "noMatches": "Sin coincidencias", + "matchSummary": "{matches, plural, one {# coincidencia} other {# coincidencias}} en {files, plural, one {# archivo} other {# archivos}}", + "fileSummary": "{files, plural, one {# archivo} other {# archivos}}", + "moreResults": "{count, plural, one {# resultado más no mostrado} other {# resultados más no mostrados}}" + }, + "toolGroup": { + "search": "{count, plural, one {Exploró # búsqueda} other {Exploró # búsquedas}}", + "command": "{count, plural, one {Ejecutó # comando} other {Ejecutó # comandos}}", + "read": "{count, plural, one {Leyó archivos # vez} other {Leyó archivos # veces}}", + "memory": "{count, plural, one {Recordó # memoria} other {Recordó # memorias}}", + "edit": "{count, plural, one {Editó archivos # vez} other {Editó archivos # veces}}", + "fetch": "{count, plural, one {Recuperó # recurso} other {Recuperó # recursos}}", + "think": "{count, plural, one {Pensó # vez} other {Pensó # veces}}", + "todo": "{count, plural, one {Actualizó # tarea} other {Actualizó # tareas}}", + "task": "{count, plural, one {Ejecutó # tarea} other {Ejecutó # tareas}}", + "other": "{count, plural, one {Usó # herramienta} other {Usó # herramientas}}", + "errorSuffix": "{count, plural, one {# falló} other {# fallaron}}", + "joiner": " · " + }, + "planMode": { + "entered": "Modo de planificación iniciado", + "planLabel": "Plan", + "reviewApproved": "Plan aprobado: implementando", + "reviewKept": "Se mantuvo en modo plan", + "reviewPending": "Esperando la decisión sobre el plan", + "submitted": "Plan enviado", + "switched": "Modo cambiado" + }, + "backgroundTask": { + "title": "Tarea en segundo plano", + "titleWithId": "Tarea en segundo plano · {id}", + "running": "En ejecución", + "completed": "Completada", + "failed": "Fallida", + "stopped": "Detenida", + "exitCode": "salida {code}", + "polledTimes": "Consultada {count} veces", + "runningInBackground": "Segundo plano", + "launchNote": "Ejecutándose en segundo plano · {id}" + }, + "codexScript": { + "outputMissing": "Codex truncó la salida del script y eliminó el separador de este comando, por lo que no se le pudo atribuir ninguna salida.", + "sharedWith": "También contiene la salida de {commands}: codex truncó sus separadores.", + "truncated": "truncado" + } + }, + "messageNav": { + "title": "Navegación de mensajes", + "collapse": "Contraer navegación de mensajes", + "collapsedSummary": "Mensajes {count}", + "fileCount": "{count, plural, one {# archivo} other {# archivos}}", + "remove": "Quitar", + "noDiffDataAvailable": "No hay datos de diff disponibles para {filePath}" + }, + "replyArtifacts": { + "title": "Archivos modificados", + "fileCount": "{count, plural, one {# archivo} other {# archivos}}", + "newFilesTitle": "Archivos nuevos", + "revealInFolder": "Mostrar en el gestor de archivos", + "openFile": "Abrir {filePath}", + "openInEditor": "Abrir en el editor", + "remove": "Quitar", + "noDiffDataAvailable": "No hay datos de diff disponibles para {filePath}" + }, + "askQuestion": { + "title": "El agente necesita tu elección", + "subtitle": "Responde y luego envía. Puedes omitir en cualquier momento.", + "recommended": "Recomendado", + "other": "Otro", + "otherPlaceholder": "Escribe tu respuesta…", + "singleSelect": "Única", + "multiSelect": "Múltiple", + "skip": "Omitir", + "next": "Siguiente", + "submit": "Enviar", + "submitError": "No se pudo enviar. Inténtalo de nuevo." + }, + "planApproval": { + "title": "El agente tiene un plan: revísalo", + "emptyPlan": "El agente no escribió un plan. Aprueba para empezar a construir o solicita cambios.", + "approve": "Aprobar y construir", + "requestChanges": "Solicitar cambios", + "abandon": "Descartar", + "feedbackPlaceholder": "¿Qué debería cambiar?", + "sendChanges": "Enviar", + "cancel": "Cancelar", + "submitError": "No se pudo enviar. Inténtalo de nuevo." + }, + "feedbackCheckResult": { + "count": "{count, plural, =1 {1 comentario} other {# comentarios}}", + "expand": "Mostrar todos los comentarios", + "collapse": "Contraer", + "errorTitle": "Error al comprobar los comentarios" + }, + "askQuestionResult": { + "title": "Pregunta", + "answeredLabel": "Pregunta y respuesta:", + "awaiting": "Esperando tu respuesta…", + "declined": "Descartaste esto: el agente usó su propio criterio.", + "noSelection": "Sin selección" + }, + "configStale": { + "agentConfigTitle": "Configuración del agente actualizada", + "modelProviderTitle": "Proveedor de modelo actualizado", + "description": "Esta sesión sigue usando su configuración anterior. Vuelve a conectarte para aplicarla (se conserva el historial de la conversación).", + "reconnect": "Reconectar para aplicar", + "reconnecting": "Reconectando…", + "reconnectDisabledDuringTurn": "Disponible cuando termine el turno actual", + "dismiss": "Descartar", + "reconnectFailed": "No se pudo reconectar la sesión", + "applied": "Nueva configuración aplicada" + }, + "piProjectTrust": { + "title": "Este proyecto incluye recursos de pi", + "description": "pi no está cargando los archivos .pi del propio repositorio. Revísalos para decidir.", + "descriptionExecutable": "El repositorio incluye extensiones de pi, que ejecutan código al iniciar. pi no las está cargando. Revísalas antes de decidir.", + "review": "Revisar…", + "dismiss": "Descartar", + "dialogTitle": "¿Confiar en los recursos de pi de este proyecto?", + "dialogDescription": "pi solo carga los archivos .pi del propio repositorio si confías en la carpeta. Confía solo si confías en el contenido de este repositorio.", + "executionWarning": "Las extensiones son código. Al confiar en esta carpeta, el repositorio podrá ejecutarlas al iniciar pi con tus permisos, antes de que envíes ningún mensaje.", + "scopeNote": "La decisión se guarda en el trust.json de pi para esta carpeta, se aplica a todas las carpetas que contiene y también se usa cuando ejecutas pi por tu cuenta en una terminal. Puedes cambiarla en Ajustes → Agentes → Pi.", + "trust": "Confiar en el proyecto", + "decline": "Mantener sin cargar", + "disabledDuringTurn": "Disponible cuando termine el turno actual", + "trustedToast": "Proyecto de confianza: se reconectó para que pi cargue sus recursos", + "declinedToast": "Los recursos del proyecto siguen sin cargarse", + "saveFailed": "No se pudo guardar la decisión de confianza del proyecto", + "grantTitle": "Este proyecto ya es de confianza", + "grantDescription": "pi carga los archivos .pi del propio repositorio. Revisa lo que eso permite.", + "grantInheritedDescription": "Una carpeta superior es de confianza, así que pi carga los archivos .pi del propio repositorio. Revisa lo que eso permite.", + "grantDialogTitle": "Los recursos de pi de este proyecto son de confianza", + "grantDialogDescription": "pi tiene permiso para cargar los archivos .pi del propio repositorio. Versiones anteriores de codeg lo concedían automáticamente al abrir una carpeta, así que puede que nunca te lo preguntaran.", + "grantExecutionWarning": "Las extensiones son código. El repositorio las ejecuta al iniciar pi con tus permisos, antes de que envíes ningún mensaje.", + "inheritedFrom": "Confianza heredada de", + "revoke": "Revocar confianza", + "keepTrusted": "Mantener la confianza", + "revokedToast": "Confianza revocada: se reconectó para que pi deje de cargar los recursos del proyecto", + "trustedNoReconnect": "Proyecto de confianza: se aplicará la próxima vez que se inicie pi", + "revokedNoReconnect": "Confianza revocada: se aplicará la próxima vez que se inicie pi" + }, + "collabAgent": { + "title": "Subagente", + "errorTitle": "La tarea del subagente falló", + "statesLabel": "Subagentes", + "statusRunning": "En ejecución", + "statusCompleted": "Completado", + "statusFailed": "Fallido", + "statusPending": "Iniciando", + "statusInterrupted": "Interrumpido", + "statusClosed": "Cerrado", + "statusNotFound": "No encontrado", + "opSpawn": "Iniciando subagente", + "opWait": "Obteniendo resultado del subagente", + "opClose": "Cerrando subagente", + "opResume": "Reanudando subagente" + }, + "contextCompaction": { + "compacting": "Compactando el contexto…", + "compacted": "Contexto compactado", + "compactedTokens": "Contexto compactado · {before} → {after} tokens", + "failed": "Error al compactar el contexto" + }, + "sessionFailure": { + "category": { + "connection": "Problema de conexión", + "access": "Problema de acceso", + "limit": "Límite alcanzado", + "request": "Solicitud rechazada", + "service": "Problema del servicio", + "unknown": "Problema de sesión" + }, + "action": { + "retry": "Reintentar", + "login": "Iniciar sesión", + "newSession": "Nueva sesión" + }, + "recovered": "Recuperado", + "retryUnavailable": "No hay ningún mensaje anterior para reenviar.", + "toggleDetails": "Mostrar u ocultar detalles" + }, + "backgroundTasks": { + "running": "{count, plural, one {# tarea en segundo plano en ejecución} other {# tareas en segundo plano en ejecución}}", + "settling": "Sincronizando resultados en segundo plano…", + "settledFallback": "Tarea en segundo plano finalizada ({status})", + "cardRunning": "Ejecutándose en segundo plano", + "cardLaunchedPending": "Tarea lanzada en segundo plano", + "cardCompleted": "Tarea en segundo plano completada", + "cardFinishedWithStatus": "Tarea en segundo plano finalizada ({status})", + "cardResultPending": "El resultado aún no ha llegado" + }, + "proposedPlan": { + "title": "Plan propuesto", + "planning": "Planificando…" + } + }, + "diffPreview": { + "mode": { + "added": "Añadido", + "deleted": "Eliminado", + "renamed": "Renombrado", + "modified": "Modificado" + }, + "hunkLabel": "Bloque {index}", + "loadingHunk": "Cargando hunk...", + "noDiffData": "Sin datos de diff", + "showRemainingLines": "Mostrar {count} líneas más" + }, + "conversationContextBar": { + "folderTitle": "Carpeta de trabajo", + "branchTitle": "Rama de trabajo", + "searchFolder": "Search folder...", + "searchBranch": "Search branch...", + "noFolders": "No folders", + "noBranches": "No branches", + "noBranch": "(no branch)", + "chatModeLabel": "Modo de chat", + "commit": "Commit", + "push": "Push", + "merge": "Merge", + "toasts": { + "folderChanged": "Switched to {name}", + "openFolderFailed": "Failed to open folder", + "switchedToChatMode": "Cambiado al modo de chat", + "openStashFailed": "Failed to open stash window", + "openMergeFailed": "Failed to open merge window" + } + }, + "cloneDialog": { + "title": "Clonar repositorio", + "repositoryUrl": "URL del repositorio", + "repositoryUrlPlaceholder": "https://github.com/user/repo.git", + "directory": "Directorio", + "directoryPlaceholder": "Selecciona el directorio de destino...", + "browseDirectory": "Explorar directorio", + "cancel": "Cancelar", + "clone": "Clonar", + "clonePath": "Ruta de clonación: {path}" + }, + "toasts": { + "cloneFailed": "No se pudo clonar el repositorio" + } + }, + "ProjectBoot": { + "title": "Inicio de Proyecto", + "tabs": { + "shadcn": "shadcn", + "hyperframes": "HyperFrames" + }, + "hyperframes": { + "title": "Proyecto de vídeo HyperFrames", + "subtitle": "Genera un proyecto de HTML a vídeo. Luego, el agente del espacio de trabajo puede escribirlo y renderizarlo.", + "resolution": "Resolución", + "skillsTitle": "Skills de agentes", + "skillsDesc": "Instala globalmente las skills de HyperFrames (enlace simbólico) para los agentes seleccionados, para que puedan crear y renderizar vídeo.", + "recheck": "Volver a comprobar", + "installedBadge": "Instalado", + "skillsInstall": "Instalar / actualizar skills", + "skillsInstalling": "Instalando skills…", + "skillsInstalled": "Skills de HyperFrames instaladas", + "skillsInstallFailed": "No se pudieron instalar las skills de HyperFrames" + }, + "config": { + "base": "Base", + "style": "Estilo", + "baseColor": "Color base", + "theme": "Tema", + "chartColor": "Color del gráfico", + "iconLibrary": "Biblioteca de iconos", + "font": "Fuente", + "fontHeading": "Fuente de título", + "menuAccent": "Acento del menú", + "menuColor": "Color del menú", + "radius": "Radio", + "template": "Plantilla", + "createProject": "Crear proyecto", + "sectionStyle": "Estilo", + "sectionColors": "Colores", + "sectionTypography": "Tipografía", + "sectionInterface": "Interfaz" + }, + "preview": { + "loading": "Cargando vista previa..." + }, + "createDialog": { + "title": "Crear proyecto", + "projectName": "Nombre del proyecto", + "projectNamePlaceholder": "my-app", + "frameworkTemplate": "Plantilla del framework", + "packageManager": "Gestor de paquetes", + "saveDirectory": "Directorio de guardado", + "saveDirectoryPlaceholder": "Seleccionar directorio...", + "browseDirectory": "Explorar", + "projectPath": "El proyecto se creará en: {path}", + "advancedOptions": "Opciones Avanzadas", + "base": "Biblioteca Base", + "enableRtl": "Habilitar Soporte RTL", + "enableRtlDescription": "Habilitar soporte de diseño para idiomas de derecha a izquierda (ej. árabe, hebreo)", + "pmChecking": "Verificando...", + "pmNotInstalled": "No instalado", + "cancel": "Cancelar", + "create": "Crear", + "creating": "Creando proyecto..." + }, + "toasts": { + "createFailed": "Error al crear el proyecto", + "createSuccess": "Proyecto creado exitosamente", + "openWorkspaceFailed": "Proyecto creado, pero no se pudo abrir en el espacio de trabajo" + }, + "errors": { + "directoryExists": "El directorio de destino ya existe", + "commandFailed": "El comando de creación del proyecto falló." + } + }, + "WebServiceSettings": { + "addressSwitchHint": "Cambiar solo modifica la dirección que se muestra y se abre aquí; el servicio escucha en todas las interfaces y sigue accesible en cada dirección.", + "sectionTitle": "Servicio Web", + "sectionDescription": "Habilitar para acceder a Codeg de forma remota a través del navegador", + "port": "Puerto", + "status": "Estado", + "autoStart": "Inicio automático", + "autoStartHint": "Iniciar el servicio web al abrir Codeg", + "running": "En ejecución", + "stopped": "Detenido", + "processing": "Procesando...", + "start": "Iniciar", + "stop": "Detener", + "startFailed": "Error al iniciar", + "stopFailed": "Error al detener", + "saveConfigFailed": "No se pudo guardar la configuración del servicio web", + "open": "Abrir", + "hide": "Ocultar", + "show": "Mostrar", + "copy": "Copiar", + "qrcode": "Código QR", + "qrcodeTitle": "Escanear para abrir", + "qrcodeHint": "Escanea con tu teléfono para abrir Codeg en el navegador", + "addressLabel": "Dirección de acceso", + "tokenLabel": "Token de acceso", + "tokenHint": "Ingrese este token al acceder al cliente Web por primera vez", + "tokenPlaceholder": "Dejar vacío para generar automáticamente", + "regenerate": "Regenerar", + "stalePortOccupiedTitle": "El puerto {port} está en uso por otro proceso", + "stalePortUnknownTitle": "Estado del puerto {port} indeterminado", + "stalePortHint": "Codeg no puede vincularse hasta que se libere el puerto. Cambia el puerto arriba o cierra el proceso que lo retiene.", + "errors": { + "alreadyRunning": "El servicio Web ya está en ejecución", + "invalidAddress": "Formato de host o puerto no válido", + "portInUse": "El puerto {port} ya está en uso. Cierre el proceso que lo usa o elija otro puerto.", + "permissionDenied": "Permiso denegado. Utilice un puerto superior a 1024 o ejecute con mayores privilegios.", + "addressUnavailable": "La dirección no está disponible en este equipo", + "bindFailed": "No se pudo enlazar la dirección" + } + }, + "DirectoryBrowser": { + "title": "Explorar directorio", + "pathPlaceholder": "Ingrese la ruta del directorio...", + "goHome": "Ir al directorio principal", + "navigateUp": "Ir al directorio superior", + "select": "Seleccionar", + "cancel": "Cancelar", + "loading": "Cargando...", + "emptyDirectory": "Este directorio está vacío", + "errorLoadingDir": "Error al cargar el directorio", + "permissionDenied": "Permiso denegado" + }, + "ChatChannelSettings": { + "loading": "Cargando...", + "sectionTitle": "Canales de chat", + "sectionDescription": "Configure bots de IM para recibir notificaciones de eventos y consultar actividad de codificación.", + "addChannel": "Agregar canal", + "noChannels": "Aún no se han configurado canales de chat.", + "channelName": "Nombre", + "channelNamePlaceholder": "Mi bot de Telegram", + "channelType": "Tipo de canal", + "lark": "Lark (Feishu)", + "weixin": "WeChat", + "dailyReport": "Informe diario", + "dailyReportTime": "Hora del informe", + "nameRequired": "El nombre del canal es obligatorio.", + "tokenRequired": "El token es obligatorio.", + "chatIdRequired": "El Chat ID es obligatorio.", + "topicMode": "Modo de grupo por temas", + "topicModeHint": "Enruta los temas de foros de Telegram como sesiones Codeg separadas. El bot debe estar en un supergrupo de foro y poder administrar temas.", + "loadFailed": "Error al cargar los canales.", + "saveFailed": "Error al guardar los cambios.", + "connectSuccess": "Canal conectado.", + "connectFailed": "Error al conectar", + "disconnectSuccess": "Canal desconectado.", + "disconnectFailed": "Error al desconectar.", + "testSuccess": "Prueba de conexión exitosa.", + "testFailed": "Prueba de conexión fallida", + "deleteSuccess": "Canal eliminado.", + "deleteFailed": "Error al eliminar el canal.", + "deleteConfirmTitle": "Eliminar canal", + "deleteConfirmMessage": "Se eliminará permanentemente el canal y sus registros de mensajes. ¿Está seguro?", + "cancel": "Cancelar", + "delete": "Eliminar", + "create": "Crear", + "save": "Guardar", + "channelListTitle": "Canales configurados", + "channelListDescription": "Los canales habilitados se conectarán automáticamente al iniciar el servicio.", + "editChannel": "Editar canal", + "editSuccess": "Canal actualizado.", + "tokenPlaceholderKeep": "Dejar vacío para mantener actual", + "weixinScanTitle": "Escanear código QR", + "weixinScanDescription": "Abra WeChat y escanee el código QR para conectarse.", + "weixinQrcodeExpired": "El código QR ha expirado.", + "weixinRefreshQrcode": "Actualizar", + "weixinWaitingScan": "Esperando escaneo...", + "weixinPollError": "Conexión inestable, reintentando...", + "weixinReconnectNotice": "Debido a limitaciones del protocolo iLink, después de cada reconexión debes enviar un mensaje al bot para que los activadores de eventos surtan efecto.", + "connect": "Conectar", + "disconnect": "Desconectar", + "test": "Probar conexión", + "tabs": { + "channels": "Canales", + "commands": "Comandos", + "events": "Eventos", + "other": "Otros" + }, + "commands": { + "title": "Comandos integrados", + "description": "Comandos de bot disponibles en los canales de chat. En chats grupales, se requiere @Bot para procesar mensajes.", + "prefixLabel": "Prefijo de comando", + "prefixDescription": "1-3 caracteres no alfanuméricos para activar comandos del bot (por defecto /).", + "prefixSaved": "Prefijo de comando guardado.", + "prefixSaveFailed": "Error al guardar el prefijo.", + "prefixInvalid": "El prefijo debe ser de 1-3 caracteres no alfanuméricos.", + "save": "Guardar", + "folderDesc": "Seleccionar carpeta de trabajo", + "agentDesc": "Seleccionar agente de IA", + "taskDesc": "Crear sesión y ejecutar tarea", + "sessionsDesc": "Listar sesiones activas en la carpeta", + "resumeDesc": "Conversaciones recientes / reanudar una sesión", + "cancelDesc": "Cancelar tarea actual", + "approveDesc": "Aprobar solicitud de permiso del agente", + "denyDesc": "Denegar solicitud de permiso del agente", + "searchDesc": "Buscar conversaciones por palabra clave", + "todayDesc": "Resumen de actividad de hoy", + "statusDesc": "Estado de conexión del canal", + "helpDesc": "Mostrar ayuda" + }, + "events": { + "title": "Notificaciones de eventos", + "description": "Al habilitar eventos, se enviarán al canal cuando se activen.", + "turnComplete": "Turno completado", + "turnCompleteDesc": "Cuando finaliza un turno del agente", + "error": "Error del agente", + "errorDesc": "Cuando un agente encuentra un error", + "permissionRequest": "Solicitud de permiso", + "permissionRequestDesc": "Cuando un agente solicita permiso para actuar", + "questionRequest": "Pregunta del agente", + "questionRequestDesc": "Cuando un agente te hace una pregunta", + "userPromptSent": "Mensaje del usuario", + "userPromptSentDesc": "Cuando envías un mensaje (el texto del mensaje se incluye en la notificación)", + "saved": "Filtro de eventos actualizado.", + "saveFailed": "Error al guardar el filtro de eventos.", + "loadFailed": "No se pudo cargar la configuración.", + "retry": "Reintentar", + "webhooksTitle": "Webhooks", + "webhooksDescription": "Envía una carga JSON por POST a una o varias URL cuando se activa un evento habilitado. El filtro de eventos anterior también se aplica a los webhooks.", + "webhookUrlPlaceholder": "https://example.com/webhook", + "addWebhook": "Agregar webhook", + "removeWebhook": "Eliminar webhook", + "webhookSave": "Guardar", + "webhooksSaved": "Webhooks guardados.", + "webhooksSaveFailed": "Error al guardar los webhooks.", + "webhookInvalidUrl": "Introduce URL http(s) válidas.", + "docsTitle": "Formato de solicitud", + "docsMethod": "Método", + "docsContentType": "Content-Type", + "docsNote": "Cada evento habilitado se entrega a todas las URL. Los webhooks no tienen antirrebote; el filtro de eventos anterior sigue aplicándose.", + "editWebhook": "Editar webhook", + "enableWebhook": "Activar webhook", + "webhookDuplicate": "Esta URL ya está configurada.", + "cancel": "Cancelar", + "webhooksEmpty": "Aún no hay webhooks configurados.", + "deleteWebhookTitle": "Eliminar webhook", + "deleteWebhookMessage": "¿Eliminar este webhook? Los eventos ya no se enviarán a esta URL.", + "delete": "Eliminar" + }, + "language": { + "title": "Idioma de mensajes", + "description": "Idioma utilizado para las notificaciones de eventos, respuestas de comandos e informes diarios enviados a los canales de chat.", + "saved": "Idioma de mensajes guardado.", + "saveFailed": "Error al guardar el idioma de mensajes.", + "en": "Inglés", + "zh-cn": "Chino simplificado", + "zh-tw": "Chino tradicional", + "ja": "Japonés", + "ko": "Coreano", + "es": "Español", + "de": "Alemán", + "fr": "Francés", + "pt": "Portugués", + "ar": "Árabe" + } + }, + "ModelProviderSettings": { + "sectionTitle": "Proveedores de Modelos", + "sectionDescription": "Gestionar las credenciales de proveedores API para agentes.", + "filterAll": "Todos", + "providerListTitle": "Proveedores Configurados", + "addProvider": "Agregar Proveedor", + "editProvider": "Editar Proveedor", + "noProviders": "Aún no se han configurado proveedores de modelos.", + "providerName": "Nombre", + "providerNamePlaceholder": "Ej. OpenAI, Anthropic", + "apiUrl": "URL de API", + "apiUrlPlaceholder": "https://api.openai.com/v1", + "apiKey": "Clave API", + "apiKeyPlaceholder": "sk-...", + "apiKeyKeepCurrent": "Dejar vacío para mantener actual", + "agentTypes": "Tipos de Agente", + "agentTypesRequired": "Se requiere al menos un tipo de agente.", + "agentType": "Tipo de Agente", + "agentTypeRequired": "El tipo de agente es obligatorio.", + "agentTypeImmutableHint": "El tipo de agente no se puede cambiar después de la creación.", + "model": "Modelo", + "modelPlaceholderCodex": "gpt-5.6-sol / gpt-5.5", + "modelPlaceholderGemini": "gemini-3-pro-preview", + "claudeMainModel": "Modelo Principal", + "claudeReasoningModel": "Modelo de Razonamiento (pensamiento)", + "claudeHaikuDefaultModel": "Modelo Haiku Predeterminado", + "claudeSonnetDefaultModel": "Modelo Sonnet Predeterminado", + "claudeOpusDefaultModel": "Modelo Opus Predeterminado", + "claudeCustomModelOption": "ID de modelo personalizado", + "claudeCustomModelOptionName": "Nombre del modelo personalizado", + "claudeCustomModelOptionDescription": "Descripción del modelo personalizado", + "claudeCustomModelOptionHint": "Añade una única entrada personalizada al selector de modelos de Claude (por ejemplo, un modelo detrás de una pasarela/proxy personalizado). El nombre y la descripción son opcionales y solo afectan a la visualización.", + "nameRequired": "El nombre del proveedor es obligatorio.", + "apiUrlRequired": "La URL de API es obligatoria.", + "apiKeyRequired": "La clave API es obligatoria.", + "loadFailed": "Error al cargar proveedores.", + "saveFailed": "Error al guardar cambios.", + "createSuccess": "Proveedor creado.", + "editSuccess": "Proveedor actualizado.", + "deleteSuccess": "Proveedor eliminado.", + "deleteConfirmTitle": "Eliminar Proveedor", + "deleteConfirmMessage": "Esto eliminará permanentemente el proveedor \"{name}\". ¿Está seguro?", + "deleteBlockedByAgent": "{agents} está usando este proveedor. Desvincúlelo antes de eliminarlo.", + "cancel": "Cancelar", + "delete": "Eliminar", + "create": "Crear", + "save": "Guardar", + "affectedRunningSessions": "{count, plural, one {# sesión activa necesita reconectarse para aplicar el cambio} other {# sesiones activas necesitan reconectarse para aplicar el cambio}}" + }, + "SkillMatrix": { + "loading": "Cargando…", + "searchPlaceholder": "Buscar por nombre, id o descripción", + "empty": "Nada que mostrar.", + "emptySearch": "No hay coincidencias para la búsqueda actual.", + "skillColumn": "Habilidad", + "selectAll": "Seleccionar todo lo visible", + "selectSkill": "Seleccionar {name}", + "everything": { + "label": "En bloque", + "enable": "Activar todo (visible)", + "disable": "Desactivar todo (visible)" + }, + "columnMenu": { + "enableAll": "Activar todas las habilidades", + "disableAll": "Desactivar todas las habilidades" + }, + "rowMenu": { + "label": "Acciones en bloque para {name}", + "enableAll": "Activar para todos los agentes", + "disableAll": "Desactivar para todos los agentes" + }, + "bulk": { + "selected": "{count} seleccionados", + "targetAll": "Todos los agentes", + "targetSome": "{count} agentes", + "enable": "Activar", + "disable": "Desactivar", + "clear": "Limpiar" + }, + "confirm": { + "disableTitle": "¿Desactivar estos enlaces?", + "disableBody": "Esto eliminará {count} enlaces de habilidades gestionados por codeg. Las habilidades que ocupan un directorio personalizado no se modifican. Puedes reactivarlas cuando quieras.", + "cancel": "Cancelar", + "confirm": "Desactivar" + }, + "toasts": { + "loadFailed": "No se pudieron cargar los estados de las habilidades", + "applyFailed": "No se pudieron aplicar los cambios", + "enabled": "{count} enlaces activados", + "disabled": "{count} enlaces desactivados", + "enabledPartial": "{ok} activados, {failed} fallidos", + "disabledPartial": "{ok} desactivados, {failed} fallidos" + }, + "detail": { + "enableForAgents": "Activar para agentes", + "preview": "Vista previa de SKILL.md", + "loadingContent": "Cargando contenido…" + }, + "copyModeHint": "Copiado (no enlazado): vuelve a activarlo tras las actualizaciones para la última versión" + }, + "ExpertsSettings": { + "title": "Habilidades de expertos", + "description": "Habilita flujos de trabajo de habilidades cuidadosamente seleccionadas y probadas en la práctica para tus agentes de codificación de IA. Cada experto es una habilidad independiente del proyecto superpowers — codeg gestiona la copia central y la vincula a los agentes que elijas.", + "loading": "Cargando expertos…", + "loadingContent": "Cargando contenido…", + "emptyExperts": "No hay expertos disponibles. Revisa los registros de la aplicación.", + "emptySelection": "Selecciona un experto para ver su contenido y gestionar la activación.", + "emptySearch": "Ningún experto coincide con la búsqueda actual.", + "searchPlaceholder": "Buscar expertos por nombre, ID o descripción", + "enableForAgents": "Habilitar para agentes", + "noAgents": "No se detectaron agentes ACP.", + "copyModeWarning": "Copiado (no vinculado). Vuelve a habilitarlo después de actualizar codeg para obtener la última versión.", + "previewTitle": "Vista previa de SKILL.md", + "categories": { + "discovery": "Descubrimiento y diseño", + "planning": "Planificación", + "execution": "Ejecución", + "quality": "Calidad y pruebas", + "debugging": "Depuración", + "review": "Revisión e integración", + "meta": "Meta" + }, + "states": { + "not_linked": "No habilitado", + "linked_to_codeg": "Habilitado", + "linked_elsewhere": "Bloqueado — existe otro vínculo", + "blocked_by_real_directory": "Bloqueado — una habilidad personalizada ocupa este nombre", + "broken": "Vínculo roto" + }, + "badges": { + "userModified": "Modificado por el usuario" + }, + "actions": { + "openCentralDir": "Abrir carpeta central", + "refresh": "Actualizar" + }, + "toasts": { + "loadFailed": "Error al cargar los detalles del experto", + "enabled": "Experto habilitado para este agente", + "disabled": "Experto deshabilitado para este agente", + "enableFailed": "Error al habilitar el experto", + "disableFailed": "Error al deshabilitar el experto", + "openFolderFailed": "Error al abrir la carpeta" + } + }, + "ScienceSettings": { + "title": "Habilidades de investigación científica", + "description": "Habilita habilidades de investigación científica seleccionadas para tus agentes de código con IA: generación de hipótesis, diseño experimental, estadística, visualización, evaluación crítica y búsqueda bibliográfica. codeg gestiona una copia central y enlaza cada habilidad a los agentes que elijas.", + "loading": "Cargando habilidades científicas…", + "emptySkills": "No hay habilidades científicas disponibles. Revisa los registros de la aplicación.", + "searchPlaceholder": "Buscar habilidades científicas por nombre, id o descripción", + "categories": { + "ideation": "Ideación", + "design": "Diseño de estudios", + "analysis": "Análisis", + "visualization": "Visualización", + "evaluation": "Evaluación", + "literature": "Literatura" + }, + "states": { + "not_linked": "No habilitado", + "linked_to_codeg": "Habilitado", + "linked_elsewhere": "Bloqueado — existe otro vínculo", + "blocked_by_real_directory": "Bloqueado — una habilidad personalizada ocupa este nombre", + "broken": "Vínculo roto" + }, + "badges": { + "userModified": "Modificado por el usuario", + "needsKey": "Requiere clave", + "needsSetup": "Puede requerir configuración" + }, + "actions": { + "openCentralDir": "Abrir carpeta central", + "refresh": "Actualizar" + }, + "toasts": { + "openFolderFailed": "Error al abrir la carpeta" + } + }, + "OfficeToolsSettings": { + "title": "Herramientas Office", + "description": "Gestiona las habilidades de OfficeCLI para crear archivos Excel, Word y PowerPoint. Instala OfficeCLI, sincroniza habilidades y actívalas por agente.", + "loadingContent": "Cargando contenido…", + "emptySkills": "No hay habilidades disponibles. Instala OfficeCLI y sincroniza las habilidades.", + "emptySelection": "Selecciona una habilidad para ver su contenido y gestionar la activación.", + "emptySearch": "No se encontraron habilidades.", + "searchPlaceholder": "Buscar habilidades por nombre, ID o descripción", + "enableForAgents": "Activar para agentes", + "noAgents": "No se detectaron agentes ACP.", + "installFirst": "Instala OfficeCLI primero para activar habilidades.", + "syncFirst": "Sincroniza las habilidades primero para cargar el contenido.", + "noContent": "Sin contenido disponible.", + "copyModeWarning": "Copiado (no vinculado). Vuelve a sincronizar para obtener la última versión.", + "previewTitle": "Vista previa de SKILL.md", + "detection": { + "installed": "Instalado", + "notInstalled": "No instalado", + "notRunnable": "Instalado pero no ejecutable", + "installHint": "Instala OfficeCLI para habilitar las habilidades de generación de documentos de oficina en tus agentes de IA.", + "install": "Instalar", + "uninstall": "Desinstalar", + "syncSkills": "Sincronizar habilidades" + }, + "categories": { + "general": "General", + "presentations": "Presentaciones", + "documents": "Documentos", + "spreadsheets": "Hojas de cálculo" + }, + "states": { + "not_linked": "No activado", + "linked_to_codeg": "Activado", + "linked_elsewhere": "Bloqueado — existe otro enlace", + "blocked_by_real_directory": "Bloqueado — una habilidad personalizada ocupa este nombre", + "broken": "Enlace roto" + }, + "badges": { + "notSynced": "No sincronizado" + }, + "actions": { + "refresh": "Actualizar" + }, + "toasts": { + "loadFailed": "Error al cargar los detalles de la habilidad", + "enabled": "Habilidad activada para este agente", + "disabled": "Habilidad desactivada para este agente", + "enableFailed": "Error al activar la habilidad", + "disableFailed": "Error al desactivar la habilidad", + "installSuccess": "OfficeCLI instalado correctamente", + "installFailed": "Error al instalar OfficeCLI", + "uninstallSuccess": "OfficeCLI desinstalado", + "uninstallFailed": "Error al desinstalar OfficeCLI", + "syncSuccess": "{synced} habilidades sincronizadas", + "syncPartial": "{synced} sincronizadas, {errors} fallidas", + "syncFailed": "Error al sincronizar habilidades" + }, + "autoPreviewLabel": "Abrir vista previa automáticamente", + "autoPreviewHint": "Cuando un agente crea o edita un archivo de Word, Excel o PowerPoint, abre su vista previa en vivo automáticamente." + }, + "SkillPacksSettings": { + "title": "Paquetes de habilidades", + "description": "Paquetes de habilidades seleccionados que codeg gestiona de forma centralizada y vincula a tus agentes de IA: expertos en programación, investigación científica y herramientas de documentos de oficina. Actívalos por agente abajo.", + "tabs": { + "experts": "Expertos", + "science": "Ciencia", + "office": "Herramientas de oficina", + "custom": "Personalizadas" + }, + "actions": { + "openCentralDir": "Abrir carpeta central", + "refresh": "Actualizar" + }, + "toasts": { + "openFolderFailed": "Error al abrir la carpeta" + } + }, + "QuickMessagesSettings": { + "title": "Mensajes rápidos", + "description": "Gestiona fragmentos de mensajes reutilizables. Arrastra para reordenar.", + "loading": "Cargando mensajes rápidos…", + "emptyList": "Aún no hay mensajes rápidos. Haz clic en \"Nuevo\" para crear uno.", + "emptySelection": "Selecciona un mensaje rápido para editar.", + "searchPlaceholder": "Buscar por título o contenido", + "untitled": "Sin título", + "actions": { + "new": "Nuevo", + "save": "Guardar", + "delete": "Eliminar", + "dragSort": "Arrastra para reordenar", + "dragSortMessage": "Arrastra para reordenar mensaje rápido: {name}" + }, + "fields": { + "title": "Título", + "titlePlaceholder": "Asigna un título corto a este mensaje", + "content": "Contenido", + "contentPlaceholder": "Escribe aquí el contenido del mensaje" + }, + "confirmDelete": { + "title": "¿Eliminar mensaje rápido?", + "message": "Esto eliminará permanentemente \"{name}\". ¿Estás seguro?", + "cancel": "Cancelar", + "confirm": "Eliminar" + }, + "toasts": { + "loadFailed": "Error al cargar mensajes rápidos", + "createFailed": "Error al crear el mensaje rápido", + "saveFailed": "Error al guardar el mensaje rápido", + "deleteFailed": "Error al eliminar el mensaje rápido", + "saveOrderFailed": "Error al guardar el orden", + "created": "Mensaje rápido creado", + "saved": "Mensaje rápido guardado", + "deleted": "Mensaje rápido eliminado" + } + }, + "Pet": { + "badge": { + "running": "{count} en ejecución", + "waiting": "{count} esperando aprobación", + "error": "{count} con error" + }, + "panel": { + "title": "Sesiones activas", + "empty": "No hay sesiones activas", + "emptyHint": "Aquí aparecen los agentes en ejecución y los que te necesitan.", + "statusRunning": "En ejecución", + "statusWaiting": "En espera", + "statusError": "Error", + "subAgentOf": "Subagente de" + }, + "menu": { + "scale": "Escala", + "openManager": "Gestionar mascotas", + "close": "Cerrar" + }, + "loadError": "No se pudo cargar la mascota", + "missingPetIdParam": "No hay mascota seleccionada", + "summonButton": "Mascota", + "manager": { + "title": "Mascotas", + "description": "Compañeros flotantes de escritorio con sprites compatibles con Codex.", + "addPet": "Añadir mascota", + "importFromCodex": "Importar desde Codex", + "noPets": "No hay mascotas. Añade una o impórtala desde Codex.", + "setActive": "Activar", + "active": "Activa", + "edit": "Editar", + "delete": "Eliminar", + "deleteConfirm": "¿Eliminar la mascota «{name}»? Se borrará del disco.", + "summon": "Invocar ventana de la mascota", + "openCodexHelp": "Las mascotas de Codex deben estar en ~/.codex/pets/. No se encontraron.", + "specRequirement": "El sprite debe tener 1536px de ancho y una altura múltiplo de 208px (p. ej. 1872 o 2288), en PNG o WebP con transparencia.", + "form": { + "id": "ID de mascota", + "idHelp": "Letras minúsculas, dígitos, '-' y '_'. Máx 64 chars.", + "displayName": "Nombre", + "description": "Descripción (opcional)", + "spritesheet": "Sprite", + "chooseFile": "Elegir archivo", + "replaceFile": "Reemplazar sprite", + "saveCreate": "Añadir mascota", + "saveUpdate": "Guardar cambios", + "cancel": "Cancelar" + }, + "errors": { + "missingId": "Se requiere ID de mascota", + "missingName": "Se requiere nombre", + "missingSpritesheet": "Se requiere sprite", + "addFailed": "Error al añadir la mascota", + "updateFailed": "Error al actualizar", + "deleteFailed": "Error al eliminar", + "loadFailed": "Error al cargar mascotas", + "setActiveFailed": "Error al activar mascota", + "summonFailed": "Error al invocar la ventana de mascota" + } + }, + "import": { + "title": "Importar desde Codex", + "subtitle": "Mascotas disponibles bajo ~/.codex/pets/.", + "selectAll": "Seleccionar todo", + "alreadyImported": "Ya importada", + "renameOnConflict": "Renombrar conflictos con sufijo -imported", + "import": "Importar selección", + "noneFound": "No hay mascotas Codex importables.", + "imported": "Importación correcta", + "failed": "Importación fallida", + "close": "Cerrar" + }, + "marketplace": { + "openMarketplace": "Mercado de mascotas", + "title": "Mercado de mascotas", + "search": "Buscar mascotas", + "kindFilter": { + "all": "Todas", + "object": "Objeto", + "animal": "Animal", + "person": "Persona", + "creature": "Criatura" + }, + "sortFilter": { + "latest": "Recientes", + "popular": "Populares", + "views": "Más vistas" + }, + "refresh": "Actualizar", + "install": "Instalar", + "installing": "Instalando", + "reinstall": "Reinstalar", + "reinstallConfirm": "¿Sobrescribir la mascota local \"{name}\"? Los datos existentes serán reemplazados.", + "cancel": "Cancelar", + "stats": { + "views": "Vistas", + "downloads": "Descargas", + "likes": "Me gusta" + }, + "actions": { + "idle": "Reposo", + "running_right": "Corre der.", + "running_left": "Corre izq.", + "waving": "Saluda", + "jumping": "Salta", + "failed": "Fallo", + "waiting": "Espera", + "running": "Corre", + "review": "Revisa" + }, + "page": "Página {page} de {total}", + "prev": "Anterior", + "next": "Siguiente", + "empty": "No hay mascotas que coincidan.", + "successInstalled": "\"{name}\" instalada", + "errors": { + "loadFailed": "No se pudo cargar el mercado", + "installFailed": "No se pudo instalar la mascota", + "alreadyInstalled": "La mascota ya existe localmente" + } + } + }, + "RemoteWorkspace": { + "openRemoteWorkspace": "Open remote workspace", + "manage": "Manage remote workspace", + "manageTitle": "Remote Workspace connections", + "empty": "No remote connections", + "searchPlaceholder": "Search remote workspaces", + "orderFailed": "Failed to save remote workspace order", + "dragSort": "Drag to sort", + "dragSortConnection": "Drag to sort {name}", + "newConnection": "New connection", + "loading": "Loading", + "loadingConnection": "Loading remote connection", + "name": "Name", + "baseUrl": "Service URL", + "token": "Access token", + "save": "Save", + "delete": "Delete", + "confirmDelete": { + "title": "Delete remote connection?", + "message": "This will remove \"{name}\" from this device. This action cannot be undone.", + "cancel": "Cancel", + "confirm": "Delete" + }, + "saved": "Remote connection saved.", + "deleted": "Remote connection deleted.", + "loadFailed": "Failed to load remote connections", + "saveFailed": "Failed to save remote connection", + "deleteFailed": "Failed to delete remote connection", + "openFailed": "Failed to open remote workspace", + "connectionLoadFailed": "Failed to load remote connection: {message}", + "connectionExpired": "Remote connection \"{name}\" is expired. Update its token and reload this window." + }, + "ServerFileBrowser": { + "title": "Seleccionar archivo del servidor", + "pathPlaceholder": "Introducir ruta de directorio...", + "goHome": "Ir al directorio personal", + "navigateUp": "Ir al directorio superior", + "select": "Seleccionar", + "cancel": "Cancelar", + "loading": "Cargando...", + "emptyDirectory": "Este directorio está vacío", + "errorLoadingDir": "Error al cargar el directorio", + "selectedCount": "{count} seleccionado(s)" + }, + "BackupSettings": { + "title": "Copia de seguridad y restauración", + "description": "Exporta una copia de seguridad portátil de tus datos de codeg, o restaura desde una.", + "tabs": { + "backup": "Copia de seguridad", + "restore": "Restaurar" + }, + "export": { + "includeExternal": "Incluir el contenido de las conversaciones", + "includeExternalHint": "También archiva las transcripciones de las CLI (Claude, Codex, Gemini, …). Aumenta el tamaño.", + "passphrase": "Frase de contraseña (opcional)", + "passphrasePlaceholder": "Déjala vacía para un archivo sin cifrar", + "passphraseConfirm": "Confirmar la frase de contraseña", + "passphraseMismatch": "Las frases de contraseña no coinciden.", + "noPassphraseWarning": "Esta copia contendrá secretos (claves de API, tokens) en texto plano. Guárdala en un lugar seguro.", + "passphraseLossWarning": "Cifrada con esta frase de contraseña. Si la pierdes, la copia no se podrá recuperar.", + "button": "Exportar copia", + "inProgress": "Creando copia de seguridad…", + "success": "Copia de seguridad creada.", + "started": "Descarga de la copia iniciada." + }, + "restore": { + "selectFile": "Seleccionar archivo de copia", + "passphrasePrompt": "Esta copia está cifrada. Introduce su frase de contraseña.", + "unlock": "Desbloquear", + "preview": { + "title": "Detalles de la copia", + "encrypted": "Cifrada", + "compatible": "Compatible", + "incompatible": "Incompatible", + "createdAt": "Creada: {value}", + "appVersion": "Versión de la app: {value}", + "incompatibleHint": "Esta copia fue creada por una versión más reciente de codeg y no se puede restaurar." + }, + "replaceWarning": "Restaurar reemplaza todos los datos actuales de codeg (base de datos y subidas). Tus datos actuales se guardan primero en una instantánea para poder recuperarlos.", + "keyringNote": "Los tokens de GitHub/chat del escritorio están en el llavero del sistema y no se incluyen; vuelve a introducirlos tras restaurar.", + "button": "Restaurar", + "staging": "Preparando la restauración…", + "staged": "Restauración preparada. Reiniciando…", + "restarting": "Restauración preparada. Reiniciando el servidor…", + "restartTimeout": "El servidor no volvió a tiempo. Recarga la página cuando esté activo.", + "externalSideLocation": "Las transcripciones de conversaciones se restauraron en {path}", + "confirmTitle": "¿Reemplazar todos los datos?", + "confirmBody": "Esto reemplazará tu base de datos y subidas actuales de codeg con la copia y luego reiniciará. Tus datos actuales se guardan primero en una instantánea.", + "cancel": "Cancelar", + "confirmAction": "Reemplazar y reiniciar", + "external": { + "title": "Contenido de las conversaciones", + "hint": "Esta copia incluye transcripciones de las CLI. Elige dónde restaurarlas.", + "modeSkip": "No restaurar", + "modeSide": "Restaurar en una carpeta aparte segura", + "modeOriginal": "Restaurar en las ubicaciones originales de las CLI", + "forceOverwrite": "Sobrescribir archivos existentes", + "forceOverwriteHint": "Reemplaza los archivos que ya existen en las carpetas de las CLI.", + "scanning": "Comprobando conflictos…", + "noConflicts": "No se sobrescribirá ningún archivo existente.", + "conflictCount": "Se verían afectados {count} archivo(s) existente(s).", + "conflictSkipNote": "Los archivos existentes se conservan (se omiten) salvo que actives la sobrescritura." + }, + "restartFailed": "La restauración quedó preparada, pero el servidor no pudo reiniciarse. Reinícialo manualmente para aplicarla." + }, + "remoteUnsupported": "La copia de seguridad y la restauración actúan sobre los datos de la máquina que ejecuta codeg. Estás conectado a un espacio de trabajo remoto: gestiona sus copias desde ese servidor directamente." + }, + "backup": { + "restore": { + "error": { + "badPassphrase": "Frase de contraseña incorrecta o copia dañada.", + "corrupted": "El archivo de copia de seguridad está dañado.", + "unknownFormat": "Este archivo no es una copia de seguridad de codeg reconocida.", + "newerVersion": "Esta copia fue creada por codeg {backupVersion}, más reciente que esta versión ({appVersion}).", + "alreadyPending": "Ya hay una restauración preparada. Reinicia para aplicarla antes de preparar otra." + } + }, + "error": { + "diskSpace": "No hay espacio en disco suficiente para completar la operación.", + "cancelled": "La operación fue cancelada." + } + }, + "WebConnection": { + "disconnectedTitle": "Conexión perdida", + "reconnectingDescription": "Intentando volver a conectar con el servidor. Normalmente se recupera solo en unos segundos.", + "reconnectNow": "Volver a conectar ahora", + "sessionExpiredTitle": "Sesión caducada", + "sessionExpiredDescription": "Tu sesión ya no es válida. Inicia sesión de nuevo para continuar.", + "goToLogin": "Ir al inicio de sesión" + }, + "LiveFeedback": { + "placeholder": "Envía una nota a {agent} mientras trabaja…", + "agentFallback": "el agente", + "ariaLabel": "Nota de comentarios en vivo", + "dialogTitle": "Comentarios en vivo", + "dialogDescription": "Envía una nota al agente mientras trabaja. La leerá en su próxima comprobación, sin interrumpir el paso actual.", + "dialogDescriptionInstant": "Envía una nota al agente mientras trabaja. Se inserta de inmediato en el turno actual: el agente la ve al instante.", + "channelDowngraded": "La inserción instantánea no está disponible en esta sesión: tu nota quedó guardada para que el agente la recoja en su próxima consulta.", + "send": "Enviar", + "cancel": "Cancelar", + "pending": "esperando", + "delivered": "recibida", + "turnEndedUnread": "El agente terminó antes de leer tus comentarios.", + "sendAsMessage": "Enviar como mensaje", + "dismiss": "Descartar", + "turnEndedResent": "El turno terminó: se envió como un mensaje nuevo.", + "turnEnded": "El turno ya terminó.", + "submitFailed": "No se pudo enviar tu nota" + }, + "AgentToolsSettings": { + "title": "Herramientas en la conversación", + "description": "Herramientas adicionales que codeg entrega a un agente dentro de una conversación. Se inyectan al iniciar el agente, así que los cambios se aplican a los agentes iniciados después.", + "feedbackLabel": "Comentarios en vivo", + "feedbackHint": "Envía notas y correcciones a un agente mientras trabaja. Si el agente admite la inserción instantánea, tu nota se inserta de inmediato en el turno en curso; de lo contrario, el agente recibe una herramienta para consultar tus comentarios — esos agentes suelen consultarla solo si lo mencionas en tu prompt, por ejemplo añade \"revisa mi feedback en vivo con regularidad\" a tu mensaje.", + "questionLabel": "Preguntar al usuario", + "questionHint": "Permite que los agentes se detengan y te hagan una pregunta de opción múltiple que aparece encima del cuadro de entrada de la conversación. El agente espera hasta que respondas (u omitas).", + "sessionInfoLabel": "Obtener información de sesión", + "sessionInfoHint": "Permite que los agentes consulten una sesión que mencionas en tu mensaje (una insignia de sesión) para leer su título, agente, estado, espacio de trabajo, uso de tokens y mensajes recientes.", + "automationsLabel": "Crear automatizaciones", + "automationsHint": "Guarda la conversación como una automatización que se ejecuta según un horario. Desactivado por defecto: luego inicia agentes por su cuenta.", + "workTasksLabel": "Crear tareas pendientes", + "workTasksHint": "Añade una tarjeta al tablero de pendientes desde la conversación. Desactivado por defecto: escribe estado de la aplicación.", + "save": "Guardar", + "saving": "Guardando…", + "saved": "Ajustes de herramientas guardados", + "saveFailed": "No se pudieron guardar los ajustes de herramientas", + "loadFailed": "Error al cargar: {detail}" + }, + "NotificationSoundSettings": { + "title": "Sonidos de notificación", + "description": "Reproduce un sonido breve cuando se produce un evento del agente. Son los mismos eventos que se envían a los canales de chat; esta configuración solo se aplica a este dispositivo.", + "enableHint": "Desactivado por defecto. Los sonidos solo suenan en la ventana del espacio de trabajo de este navegador o aplicación.", + "volume": "Volumen", + "preview": "Escuchar", + "previewEvent": "Escuchar el sonido de {event}", + "onlyWhenUnfocused": "Solo cuando la ventana no está enfocada", + "onlyWhenUnfocusedHint": "Permanece en silencio mientras estás mirando Codeg.", + "eventsTitle": "Eventos", + "eventsHint": "Elige un tono para cada evento o «Silencio» para omitirlo. Si el mismo evento se repite en pocos segundos, solo suena una vez.", + "toneNone": "Silencio", + "toneChime": "Campanilla", + "toneDing": "Timbre", + "toneBlip": "Pitido", + "tonePop": "Pop", + "toneAlert": "Alerta", + "toneDescend": "Descendente" + }, + "LogsSettings": { + "loading": "Cargando…", + "sectionTitle": "Registros de ejecución", + "sectionDescription": "Visualiza y configura los registros de diagnóstico de la aplicación. Los registros se escriben en archivos locales y se mantienen en memoria para la vista en vivo.", + "captureTitle": "Nivel de registro", + "captureDescription": "Controla cuánto detalle se captura. Los niveles más altos (Debug, Trace) registran más, pero generan registros más grandes. «Desactivado» deshabilita el registro.", + "captureLabel": "Nivel de captura", + "levels": { + "off": "Desactivado", + "error": "Error", + "warn": "Advertencia", + "info": "Información", + "debug": "Depuración", + "trace": "Rastreo" + }, + "viewerTitle": "Registros recientes", + "viewerDescription": "Vista en vivo de los registros recientes. Filtra por nivel o busca texto.", + "searchPlaceholder": "Buscar mensaje u origen…", + "viewLevels": { + "all": "Todos los niveles", + "error": "Error y superior", + "warn": "Advertencia y superior", + "info": "Información y superior", + "debug": "Depuración y superior", + "trace": "Rastreo y superior" + }, + "pause": "Pausar", + "resume": "En vivo", + "refresh": "Actualizar", + "clear": "Limpiar", + "openFolder": "Abrir carpeta", + "shownCount": "{shown} / {total} mostrados", + "empty": "No hay registros para mostrar.", + "levelSaveFailed": "No se pudo guardar el nivel de registro", + "openFolderFailed": "No se pudo abrir la carpeta de registros", + "downloadFailed": "No se pudo descargar el archivo de registro", + "filesTitle": "Archivos de registro", + "filesDescription": "Descarga archivos de registro completos del disco para ver el historial más allá del búfer en vivo.", + "filesEmpty": "Aún no hay archivos de registro.", + "download": "Descargar", + "downloadTruncated": "El archivo es grande; se descargaron los {size} más recientes. El archivo completo está en el directorio de registros.", + "captureEnvLocked": "El nivel de registro está controlado por la variable de entorno RUST_LOG / CODEG_LOG; cámbialo ahí para que surta efecto.", + "targetsTitle": "Anulaciones por módulo", + "targetsDescription": "Establece un nivel distinto para módulos específicos (p. ej. codeg_lib::acp) sin cambiar el nivel global.", + "targetsAdd": "Añadir", + "targetsRemove": "Quitar anulación", + "toggleDetails": "Mostrar detalles" + }, + "Automations": { + "title": "Automatizaciones", + "new": "Nueva automatización", + "empty": "Aún no hay automatizaciones", + "emptyHint": "Crea una para ejecutar una tarea del agente de forma programada o manual.", + "name": "Nombre", + "namePlaceholder": "p. ej. Revisión nocturna de PR", + "prompt": "Instrucción", + "promptPlaceholder": "¿Qué debe hacer el agente?", + "agent": "Agente", + "folder": "Carpeta del espacio de trabajo", + "folderPlaceholder": "Selecciona una carpeta", + "isolation": "Aislamiento", + "isolationWorktree": "Nuevo worktree por ejecución", + "isolationShared": "Ejecutar en la carpeta", + "isolationSharedCaveat": "Las ejecuciones usan directamente el árbol de trabajo de esta carpeta y pueden entrar en conflicto con tus cambios sin confirmar. Activa la opción de árbol de trabajo para aislar cada ejecución.", + "trigger": "Activador", + "triggerSchedule": "Programado", + "triggerManual": "Solo manual", + "cron": "Programación (cron)", + "cronPlaceholder": "0 9 * * 1-5", + "timezone": "Zona horaria", + "nextRun": "Próxima ejecución", + "branch": "Rama", + "branchOptional": "Rama (opcional)", + "enabled": "Activado", + "save": "Guardar", + "cancel": "Cancelar", + "edit": "Editar", + "delete": "Eliminar", + "runNow": "Ejecutar ahora", + "cancelRun": "Cancelar ejecución", + "runHistory": "Historial de ejecuciones", + "noRuns": "Aún no hay ejecuciones", + "allFolders": "Todas las carpetas", + "filterAll": "Todos", + "noMatches": "No hay automatizaciones que coincidan", + "viewConversation": "Ver conversación", + "lastRun": "Última ejecución", + "never": "Nunca", + "running": "En ejecución", + "deleteTitle": "¿Eliminar la automatización?", + "deleteDescription": "Esto elimina la automatización y su programación. Se conserva el historial.", + "statusRunning": "En ejecución", + "statusSucceeded": "Correcta", + "statusFailed": "Fallida", + "statusCancelled": "Cancelada", + "statusSkipped": "Omitida", + "errorName": "El nombre es obligatorio", + "errorPrompt": "La instrucción es obligatoria", + "errorCron": "Las automatizaciones programadas requieren una expresión cron", + "errorFolder": "Selecciona una carpeta del espacio de trabajo", + "presetHourly": "Cada hora", + "presetDaily": "Diario 9:00", + "presetWeekdays": "Días laborables 9:00", + "presetCustom": "Personalizado", + "probing": "Cargando opciones…", + "retry": "Reintentar", + "configNone": "Este agente no tiene opciones configurables", + "inherit": "Predeterminado del agente", + "mode": "Modo", + "config": "Configuración", + "branchPlaceholder": "(rama predeterminada)", + "selectHint": "Selecciona una automatización para ver los detalles", + "refresh": "Actualizar", + "onboardTitle": "Automatiza tareas rutinarias del agente", + "onboardHint": "Programa un agente para revisar código, actualizar dependencias o clasificar incidencias, de forma periódica o bajo demanda.", + "headerSubtitle": "Tareas del agente programadas y bajo demanda", + "startFromTemplate": "Empezar con una plantilla", + "blankTitle": "Automatización en blanco", + "blankDesc": "Configura una tarea del agente desde cero.", + "backToTemplates": "Plantillas", + "sectionSchedule": "Programación y destino", + "sectionTarget": "Destino", + "sectionAction": "Acción", + "actionLaunchSession": "Ejecutar sesión", + "actionEnqueueTask": "Encolar tarea", + "actionEnqueueTaskHint": "Cada disparo añade una tarea pendiente, titulada como esta automatización, a las tareas pendientes de la carpeta; el motor de tareas la ejecuta según la configuración del tablero.", + "sectionPrompt": "Prompt", + "nextIn": "Próxima en {rel}", + "manual": "Manual", + "schedEveryMinutes": "Cada {n} minutos", + "schedHourly": "Cada hora", + "schedDaily": "Cada día a las {time}", + "schedWeekdays": "Días laborables a las {time}", + "schedWeekly": "Cada {day} a las {time}", + "schedMonthly": "Cada mes el día {day} a las {time}", + "dow0": "domingo", + "dow1": "lunes", + "dow2": "martes", + "dow3": "miércoles", + "dow4": "jueves", + "dow5": "viernes", + "dow6": "sábado", + "tplCodeReviewTitle": "Revisión de código", + "tplCodeReviewDesc": "Revisa los cambios recientes en busca de errores, regresiones y problemas de calidad.", + "tplDependencyUpdatesTitle": "Actualización de dependencias", + "tplDependencyUpdatesDesc": "Encuentra dependencias desactualizadas y propón actualizaciones seguras.", + "tplTestCoverageTitle": "Cobertura de pruebas", + "tplTestCoverageDesc": "Encuentra rutas de código sin probar y añade las pruebas que faltan.", + "tplTodoSweepTitle": "Revisión de TODO", + "tplTodoSweepDesc": "Recopila los comentarios TODO y FIXME y clasifícalos por prioridad.", + "tplCiTriageTitle": "Clasificación de CI", + "tplCiTriageDesc": "Investiga las comprobaciones fallidas recientes y propón soluciones.", + "tplReleaseNotesTitle": "Notas de la versión", + "tplReleaseNotesDesc": "Resume los cambios desde la última versión en un registro de cambios.", + "tplSecurityAuditTitle": "Auditoría de seguridad", + "tplSecurityAuditDesc": "Busca vulnerabilidades y patrones de riesgo, y reporta los hallazgos.", + "enable": "Activar", + "disable": "Desactivar", + "moreActions": "Más acciones", + "statusDisabled": "Desactivada", + "cronBuilderTitle": "Generador de programación", + "cronFreqLabel": "Frecuencia", + "cronFreqMinutes": "Cada N minutos", + "cronFreqHourly": "Cada hora", + "cronFreqDaily": "Diario", + "cronFreqWeekdays": "Días laborables", + "cronFreqWeekly": "Semanal", + "cronFreqMonthly": "Mensual", + "cronFreqCustom": "Personalizado", + "cronEveryLabel": "Intervalo (minutos)", + "cronTimeLabel": "Hora", + "cronHourLabel": "Hora", + "cronMinuteLabel": "Minuto", + "cronDowLabel": "Día de la semana", + "cronDomLabel": "Día del mes", + "cronApply": "Aplicar", + "cronPreviewLabel": "Vista previa", + "cronOpenBuilder": "Abrir el generador de programación", + "branchDefault": "Rama predeterminada", + "branchUseCustom": "Usar «{query}»", + "branchLocal": "Local", + "branchRemote": "Remota", + "branchSearchPlaceholder": "Buscar ramas…", + "branchNone": "Sin ramas" + }, + "Tasks": { + "title": "Tareas pendientes", + "new": "Nueva tarea", + "empty": "Aún no hay tareas", + "emptyHint": "Añade un pendiente y ejecútalo: el agente trabaja en un worktree aislado y tú revisas y fusionas el resultado.", + "emptyColTodo": "Aún no hay pendientes", + "emptyColInProgress": "Nada en curso", + "emptyColAttention": "Nada requiere tu acción", + "emptyColDone": "Aún no hay completadas", + "allFolders": "Todas las carpetas", + "showCanceled": "Mostrar canceladas", + "showArchived": "Mostrar archivadas", + "filter": "Filtrar", + "viewSwitchToBoard": "Cambiar a vista de tablero", + "viewSwitchToList": "Cambiar a vista de lista", + "statusFilter": "Estado", + "statusFilterAll": "Todos los estados", + "listEmpty": "Ninguna tarea coincide con los filtros actuales", + "listColStatus": "Estado", + "listColTask": "Tarea", + "listColLocation": "Ubicación", + "listColChanges": "Cambios", + "listColUpdated": "Actualizado", + "colTodo": "Pendientes", + "colInProgress": "En curso", + "colAttention": "Requiere tu acción", + "colDone": "Completadas", + "statusTodo": "Pendiente", + "statusQueued": "En cola", + "statusPreparing": "Preparando", + "statusRunning": "En ejecución", + "statusAwaitingInput": "Esperando entrada", + "statusReview": "Por revisar", + "statusMerging": "Fusionando", + "statusDone": "Completada", + "statusFailed": "Fallida", + "statusCanceled": "Cancelada", + "statusInterrupted": "Interrumpida", + "badgeCleanupFailed": "Limpieza fallida", + "badgeWorktreeKept": "Worktree conservado", + "badgeWorktreeRemoved": "Worktree eliminado", + "filesChanged": "{count} archivos", + "actionStart": "Iniciar", + "actionSchedule": "Programar", + "actionCancel": "Cancelar", + "actionRetry": "Reintentar", + "actionRequeue": "Reencolar", + "actionViewSession": "Ver conversación", + "actionEdit": "Editar", + "actionDelete": "Eliminar", + "actionRetryCleanup": "Reintentar limpieza", + "actionMerge": "Fusionar", + "actionUnqueueMerge": "Salir de la cola de fusión", + "actionEditQueuedMerge": "Editar la fusión en cola", + "badgeMergeQueued": "En cola para fusionar", + "badgeMergeQueuedRank": "En cola para fusionar · n.º {rank}", + "badgeMergeQueuedHint": "Esperando a que termine la fusión en curso del proyecto; esta empezará sola.", + "actionComplete": "Completar", + "actionAbandon": "Abandonar", + "cancelTitle": "¿Cancelar la tarea?", + "cancelDescription": "La tarea pasa a Cancelada. Su worktree se conserva y podrás reencolarla más tarde.", + "cancelReasonLabel": "Motivo (opcional)", + "cancelReasonPlaceholder": "P. ej. enfoque equivocado: voy a reescribir la descripción", + "cancelKeep": "Mejor no", + "cancelSubmit": "Cancelar tarea", + "restartTitleRetry": "Reintentar la tarea", + "restartTitleRequeue": "Reencolar la tarea", + "restartDescription": "Puedes añadir una nota (opcional): llega al prompt de la próxima ejecución.", + "scheduleTitle": "Programar tarea", + "scheduleDescription": "La tarea sigue en Pendientes y se inicia sola a la hora que elijas. El límite de concurrencia de la carpeta se sigue aplicando.", + "scheduleDateLabel": "Fecha", + "schedulePickDate": "Elegir fecha", + "scheduleTimeLabel": "Hora", + "schedulePreview": "Se ejecuta el {time}", + "schedulePastHint": "Esa hora ya pasó: la tarea empezará en cuanto guardes.", + "scheduleInAnHour": "En 1 hora", + "scheduleInThreeHours": "En 3 horas", + "scheduleTomorrow": "Mañana 9:00", + "scheduleClear": "Quitar programación", + "scheduleBadge": "Inicio programado para el {time}", + "toastScheduled": "Programada para el {time}", + "toastScheduleCleared": "Programación eliminada", + "actionFollowUp": "Continuar", + "actionAddNote": "Añadir una nota", + "followUpSubmit": "Enviar", + "followUpIntentRevise": "Corregir", + "followUpIntentContinue": "Seguir", + "followUpIntentQuestion": "Preguntar", + "followUpIntentVerify": "Revisar", + "followUpPlaceholderRevise": "¿Qué debe cambiar el agente? Continúa en la misma sesión.", + "followUpPlaceholderContinue": "¿Qué sigue? Lo hecho hasta ahora se mantiene.", + "followUpPlaceholderQuestion": "¿Qué quieres saber? El agente responde sin tocar ningún archivo.", + "followUpPlaceholderVerify": "Opcional: ¿algo que deba revisar con atención?", + "followUpPlaceholderRetry": "Opcional: ¿qué debe hacer distinto? P. ej. ejecutar pnpm install primero", + "followUpPlaceholderRequeue": "Opcional: ¿por qué lo cancelaste y qué debe cambiar esta vez?", + "actionArchive": "Archivar", + "actionUnarchive": "Desarchivar", + "archiveAllDone": "Archivar todo", + "dropToStart": "Suelta para iniciar", + "errorView": "Ver", + "notifyReview": "Listo para revisar: {title}", + "notifyFailed": "La tarea falló: {title}", + "createFromMessage": "Crear tarea desde el mensaje", + "detailTokens": "Tokens totales", + "editorTitleNew": "Nueva tarea", + "editorTitleEdit": "Editar tarea", + "templates": "Plantillas", + "templatesEmpty": "Aún no hay plantillas.", + "templateSaveCurrent": "Guardar como plantilla", + "templateDelete": "Eliminar plantilla", + "transcriptTitle": "Conversación de la tarea", + "transcriptDescription": "Vista en vivo de solo lectura de la sesión del agente de la tarea.", + "phaseWork": "Ejecución", + "phaseRetry": "Reintento", + "phaseReturn": "Continuación", + "phaseMerge": "Fusión", + "titleLabel": "Título", + "titlePlaceholder": "¿Qué hay que hacer?", + "promptLabel": "Descripción de la tarea", + "promptPlaceholder": "Describe la tarea para el agente — @ para referenciar archivos, / para comandos", + "folderPlaceholder": "Selecciona una carpeta", + "agentInheritedHint": "Heredado de la configuración de tareas; cámbialo para personalizar esta tarea", + "agentOverrideReset": "Volver a heredar", + "sectionTarget": "Destino", + "errorTitle": "El título es obligatorio", + "errorPrompt": "La descripción es obligatoria", + "errorFolder": "Selecciona una carpeta", + "save": "Guardar", + "cancel": "Cancelar", + "mergeTitle": "Fusionar tarea", + "mergeQueuedTitle": "Fusión en cola", + "mergeQueueHint": "Otra tarea de este proyecto se está fusionando ahora. Esta entra en la cola y empezará sola en cuanto la otra termine.", + "mergeQueueUpdateHint": "Esta tarea ya está esperando para fusionarse. Al enviar se actualiza y conserva su lugar en la cola.", + "mergeDescription": "Fusionar {branch} en {base}. Los cambios sin confirmar del worktree se confirman primero.", + "mergeMessage": "Mensaje de commit", + "mergeMessagePlaceholder": "p. ej. feat: add login validation", + "mergeAutoMessage": "Dejar que el agente escriba el mensaje de commit", + "strategySquash": "Combinar en un solo commit", + "strategySquashHint": "Todos los cambios de la tarea llegan a la rama principal como una sola entrada del historial: un historial más limpio.", + "strategyMerge": "Conservar todo el historial", + "strategyMergeHint": "Se conserva cada commit hecho durante la tarea, más una entrada de fusión: cada paso queda rastreable.", + "mergeDeleteWorktree": "Eliminar el worktree tras fusionar", + "mergeSubmit": "Fusionar", + "mergeSubmitQueue": "Añadir a la cola", + "mergeQueuedToast": "Añadida a la cola de fusión: empezará en cuanto termine la fusión actual.", + "completeTitle": "Completar tarea", + "completeDescription": "Esta tarea no cambió ningún archivo, así que no hay nada que fusionar: se marca como completada directamente.", + "completeDescriptionNoWorktree": "El worktree de esta tarea fue eliminado, así que ya no se puede fusionar: se marca como completada directamente. Una rama de trabajo que aún tenga commits sin fusionar se conserva.", + "completeDeleteWorktree": "Eliminar el worktree al completar", + "completeSubmit": "Completar", + "settingsTitle": "Ajustes de tareas", + "settingsDescription": "Valores por defecto para las tareas de {folder}.", + "settingsScope": "Ámbito", + "settingsScopeGlobal": "Todas las carpetas (valores globales)", + "settingsScopeGlobalHint": "Las carpetas sin configuración propia usan estos valores globales.", + "settingsSource": "Origen de configuración", + "settingsSourceGlobal": "Valores globales", + "settingsSourceCustom": "Personalizada", + "settingsSourceGlobalFollow": "Sigue la configuración global de tareas; los cambios allí se aplican aquí automáticamente.", + "settingsSourceCustomHint": "Guarda configuración propia para esta carpeta y deja de seguir los valores globales.", + "settingsAgent": "Agente por defecto", + "settingsMaxConcurrent": "Tareas concurrentes máx.", + "settingsMaxConcurrentHint": "0 = sin límite", + "settingsAutoProcess": "Procesar automáticamente", + "settingsAutoProcessHint": "Las tareas pendientes se inician solas, hasta el límite de concurrencia.", + "settingsMergeStrategy": "Estrategia de fusión por defecto", + "settingsMergeStrategyHint": "Cómo se registran los cambios de la tarea en el historial de la rama al fusionar.", + "settingsAutoMerge": "Fusionar automáticamente", + "settingsAutoMergeHint": "Una tarea que llega a revisión con cambios que integrar se fusiona como si pulsaras Fusionar: el agente escribe el mensaje de commit y el worktree sigue el valor por defecto de abajo. Si la verificación falla o una fusión falló, la tarea queda esperándote.", + "settingsDeleteWorktree": "Eliminar el worktree tras fusionar", + "settingsDeleteWorktreeHint": "Marca la opción por defecto en el diálogo de fusión; aún puedes cambiarla allí.", + "settingsWorktreeRoot": "Ubicación del worktree", + "settingsWorktreeRootHint": "Directorio donde se crean los worktrees de las tareas nuevas, uno por tarea. Déjalo vacío para crearlos junto a la carpeta del proyecto; «~» es tu carpeta personal y una ruta relativa se resuelve respecto a la carpeta del proyecto.", + "settingsWorktreeRootPlaceholder": "~/codeg-worktrees", + "settingsWorktreeRootBrowse": "Elegir el directorio de worktrees", + "settingsPreflight": "Comando de verificación", + "settingsPreflightHint": "Se ejecuta en el worktree cuando una tarea llega a revisión.", + "settingsPreflightCustomPlaceholder": "pnpm test", + "settingsInitCommand": "Comando de inicialización del worktree", + "settingsInitCommandHint": "Se ejecuta en un worktree recién creado antes de iniciar el agente.", + "settingsInitCommandPlaceholder": "pnpm install", + "settingsTabGeneral": "General", + "settingsTabMerge": "Fusión", + "settingsTabWorktree": "Worktree", + "settingsTabPrompts": "Prompts", + "settingsPromptsIntro": "Cada etapa ya envía su propio prompt integrado: la tarea, las reglas del worktree y, al fusionar, los pasos exactos de git. Lo que añadas aquí se agrega al final como instrucciones extra: matiza esos textos integrados, nunca los sustituye.", + "settingsPromptStageAll": "Todas las fases", + "settingsPromptPlaceholderAll": "p. ej. Sigue las convenciones de AGENTS.md; que el resumen final no pase de dos frases", + "settingsPromptPlaceholderWork": "p. ej. Lee primero las pruebas relacionadas; haz commits pequeños sobre la marcha", + "settingsPromptPlaceholderRetry": "p. ej. Revisa qué hay ya commiteado antes de continuar; no rehagas lo terminado", + "settingsPromptPlaceholderReturn": "P. ej. Atiende cada punto planteado; no refactorices nada ajeno", + "settingsPromptPlaceholderMerge": "p. ej. Escribe el mensaje del commit de integración en español; señala los conflictos que resolviste a mano", + "settingsPromptHintAll": "Se añade a todos los prompts que recibe el agente, incluida la fusión.", + "settingsPromptHintWork": "Se añade cuando una tarea se ejecuta por primera vez.", + "settingsPromptHintRetry": "Se añade al retomar una tarea interrumpida o fallida.", + "settingsPromptHintReturn": "Se añade cuando continúas una tarea en revisión (corregir, ampliar, revisar).", + "settingsPromptHintMerge": "Se añade cuando el agente integra la tarea en la rama base.", + "preflightPassed": "{name} superado", + "preflightFailed": "{name} falló", + "preflightRunning": "{name} en ejecución…", + "detailDescription": "Detalle de la tarea", + "detailSummary": "Resultado", + "detailFiles": "Archivos modificados", + "detailDiffAll": "Ver diff completo", + "detailDiffAllTitle": "Diff completo", + "detailNoChanges": "Aún no hay cambios respecto a la base", + "detailTimeline": "Progreso", + "detailTimelineEmpty": "Sin actividad todavía", + "showMore": "Ver más", + "showLess": "Ver menos", + "detailInfo": "Detalles", + "detailBranch": "Rama", + "detailMergeCommit": "Commit de fusión", + "detailChanges": "Cambios", + "detailScheduled": "Inicio programado", + "detailCreated": "Creada", + "detailStarted": "Iniciada", + "detailFinished": "Finalizada", + "diffLoading": "Cargando diff…", + "deleteConfirmTitle": "¿Eliminar la tarea?", + "deleteConfirmBody": "“{title}” se quitará del tablero. Una ejecución activa se cancela primero.", + "deleteWithWorktree": "Eliminar también su worktree", + "eventCreated": "Creada", + "eventStatusChanged": "Cambio de estado", + "eventConfigEffective": "Configuración de arranque", + "eventInitCommand": "Comando de inicialización", + "eventAgentProgress": "Progreso del agente", + "eventAgentVerdict": "Veredicto del agente", + "eventMergeAttempt": "Fusión iniciada", + "eventMergeQueued": "En cola para fusionar", + "eventMergeConflict": "Conflicto de fusión", + "eventPreflight": "Verificación", + "eventCleanupFailed": "Fallo al limpiar el worktree", + "eventResumeFallback": "La reanudación falló; se usó una sesión nueva", + "eventUserAction": "Acción del usuario", + "eventDiffStat": "Instantánea de cambios" + }, + "CustomSkillsSettings": { + "loading": "Cargando habilidades personalizadas…", + "category": "Personalizadas", + "searchPlaceholder": "Buscar habilidades personalizadas por nombre, ID o descripción", + "states": { + "not_linked": "No habilitada", + "linked_to_codeg": "Habilitada", + "linked_elsewhere": "Vinculada en otro lugar", + "blocked_by_real_directory": "Bloqueada por una carpeta real", + "broken": "Enlace roto" + }, + "actions": { + "new": "Nueva", + "import": "Importar", + "importFromAgent": "Importar de un agente", + "cancel": "Cancelar", + "save": "Guardar" + }, + "rowMenu": { + "edit": "Editar", + "duplicate": "Duplicar", + "delete": "Eliminar" + }, + "bulk": { + "delete": "Eliminar seleccionadas" + }, + "editor": { + "createTitle": "Nueva habilidad personalizada", + "editTitle": "Editar habilidad personalizada", + "description": "Las habilidades personalizadas se guardan en el almacén compartido (~/.codeg/skills) y pueden habilitarse para cualquier agente.", + "idLabel": "ID de habilidad", + "idPlaceholder": "p. ej. my-workflow", + "contentLabel": "SKILL.md", + "contentPlaceholder": "Escribe aquí el SKILL.md de la habilidad…", + "preview": "Vista previa", + "edit": "Editar", + "emptyBody": "Aún no hay contenido." + }, + "duplicate": { + "title": "Duplicar habilidad", + "description": "Crea una copia de «{id}» con un nuevo ID.", + "newIdPlaceholder": "Nuevo ID de habilidad", + "confirm": "Duplicar" + }, + "import": { + "title": "Elige una carpeta de habilidad para importar" + }, + "importFromAgent": { + "title": "Importar habilidades de un agente", + "description": "Copia las habilidades propias de un agente al almacén compartido para poder activarlas en cualquier agente.", + "agentLabel": "Agente", + "agentPlaceholder": "Selecciona un agente", + "selectAll": "Seleccionar todo ({count})", + "loading": "Cargando las habilidades del agente…", + "unsupported": "Este agente no expone un directorio de habilidades.", + "empty": "Este agente no tiene habilidades que importar.", + "alreadyInLibrary": "En la biblioteca", + "confirm": "Importar seleccionadas ({count})" + }, + "delete": { + "title": "¿Eliminar habilidades personalizadas?", + "body": "Se eliminarán {count} habilidad(es) personalizada(s) del almacén central y se desvincularán de todos los agentes. Esta acción no se puede deshacer.", + "confirm": "Eliminar" + }, + "toasts": { + "loadFailed": "No se pudo cargar la habilidad", + "idRequired": "Introduce un ID de habilidad", + "created": "Habilidad personalizada creada", + "updated": "Habilidad personalizada actualizada", + "saveFailed": "No se pudo guardar la habilidad", + "imported": "Habilidad importada", + "importFailed": "No se pudo importar la habilidad", + "duplicated": "Habilidad duplicada", + "duplicateFailed": "No se pudo duplicar la habilidad", + "deleted": "Se eliminaron {count} habilidad(es)", + "deletedPartial": "{ok} eliminadas, {failed} fallidas", + "deleteFailed": "No se pudieron eliminar las habilidades", + "importedFromAgent": "Se importaron {count} habilidad(es)", + "importedFromAgentPartial": "Importadas {ok}, {failed} con error", + "importFromAgentAllSkipped": "Nada que importar: {count} ya están en la biblioteca", + "importFromAgentFailed": "No se pudo importar del agente" + } + }, + "CodexModelEditor": { + "customizedNotice": "Has personalizado la lista de modelos, así que ahora codeg gestiona toda la tabla de modelos de codex. Los modelos oficiales que codex añada después no aparecerán automáticamente: haz clic en el botón actualizar de abajo y guarda de nuevo para sincronizarlos. Borra tus personalizaciones para que codex vuelva a actualizarse automáticamente.", + "officialsTitle": "Modelos oficiales", + "officialsHint": "Se incluyen automáticamente del codex que ejecutas; elimina los que no quieras.", + "officialsEmpty": "No hay modelos oficiales disponibles.", + "refresh": "Actualizar desde codex", + "readdOfficial": "Volver a añadir oficial", + "customsTitle": "Modelos personalizados", + "customsEmpty": "Aún no hay modelos personalizados.", + "addCustom": "Agregar personalizado", + "slugPlaceholder": "id del modelo (slug)", + "displayNamePlaceholder": "Nombre visible", + "contextWindow": "Contexto", + "makeDefault": "Establecer como predeterminado", + "defaultHint": "Modelo predeterminado", + "remove": "Eliminar", + "advanced": "Avanzado", + "baseTemplate": "Plantilla base", + "baseTemplateHint": "Modelo oficial del que clonar los campos obligatorios (prompt del sistema, herramientas, límites).", + "groupBehavior": "Comportamiento y capacidades", + "fieldReasoningLevel": "Razonamiento predeterminado", + "fieldReasoningSummary": "Resumen de razonamiento", + "fieldVerbosity": "Nivel de detalle", + "fieldShellType": "Tipo de shell", + "fieldApplyPatch": "Herramienta apply-patch", + "fieldReasoningSummaries": "Resúmenes de razonamiento", + "fieldSupportVerbosity": "Control de detalle", + "fieldParallelToolCalls": "Llamadas a herramientas en paralelo", + "fieldSearchTool": "Herramienta de búsqueda web", + "optNone": "Ninguno", + "groupInstructions": "Descripción y prompt del sistema", + "fieldDescription": "Descripción", + "baseInstructions": "Prompt del sistema (base_instructions)" + }, + "DiagnosticsSettings": { + "title": "Diagnóstico del entorno", + "description": "Comprueba cómo esta app resuelve la CLI del agente en su propio proceso, que puede diferir de tu terminal.", + "loading": "Ejecutando diagnóstico…", + "error": "El diagnóstico falló", + "rerun": "Volver a ejecutar", + "copyAll": "Copiar todo", + "copied": "Diagnóstico copiado al portapapeles", + "button": "Diagnosticar", + "verdict": { + "ok": "El entorno parece correcto. Si aún aparece como no instalado, reinicia por completo la app para actualizar la caché del prefijo.", + "node_missing": "No se encontró Node.js en el PATH de la app.", + "npm_missing": "No se encontró npm en el PATH de la app.", + "not_installed": "Este agente no parece estar instalado.", + "installed_but_unresolved": "Consta como instalado, pero la app no puede localizar su ejecutable.", + "user_prefix_not_on_path": "Se instaló en el prefijo de reserva (~/.codeg/npm-global), que no está en el PATH de la app. Reinicia por completo la app e inténtalo de nuevo.", + "homebrew_bin_not_on_path": "Se instaló en el bin de Homebrew, que no está en el PATH de la app (división de keg en Apple Silicon).", + "terminal_only_path": "El comando se resuelve en tu terminal pero no en la app: una diferencia de PATH de la GUI. Inicia la app desde una terminal o reinstala desde Ajustes de agentes.", + "npm_prefix_timeout": "npm prefix -g fue demasiado lento (más de 1,5 s), por lo que se omitió la detección de reserva. Reinicia la app e inténtalo de nuevo.", + "node_too_old": "Tu Node.js activo es más antiguo de lo que requiere este agente. Actualiza Node.js.", + "adapter_missing_native_present": "Tu CLI de {agent} sí está instalada, pero Codeg ejecuta un paquete adaptador ACP aparte, y ese todavía no lo está. Instálalo desde la configuración de agentes: no toca tu CLI y comparte la misma sesión.", + "adapter_missing": "Codeg ejecuta un paquete adaptador ACP aparte para {agent} y aún no está instalado. Instálalo desde la configuración de agentes: instalar solo la CLI del proveedor no basta." + } + }, + "TokenUsage": { + "title": "Uso de tokens", + "rangeLabel": "Periodo", + "range7d": "7 días", + "range30d": "30 días", + "range90d": "90 días", + "rangeThisMonth": "Este mes", + "rangeThisYear": "Este año", + "rangeAll": "Todo", + "rangeCustom": "Personalizado", + "moreRanges": "Más", + "customRangePick": "Elegir un intervalo", + "bucketLabel": "Agrupar por", + "bucketDay": "Día", + "bucketWeek": "Semana", + "bucketMonth": "Mes", + "bucketUnitDay": "Día", + "bucketUnitWeek": "Semana", + "bucketUnitMonth": "Mes", + "folderFilter": "Carpetas", + "allFolders": "Todas las carpetas", + "agentFilter": "Agentes", + "allAgents": "Todos los agentes", + "modelFilter": "Modelos", + "allModels": "Todos los modelos", + "searchPlaceholder": "Buscar…", + "noMatches": "Sin coincidencias", + "clearFilter": "Borrar selección", + "resetFilters": "Restablecer filtros", + "refresh": "Actualizar", + "rebuild": "Reconstruir todo", + "rebuildHint": "Descarta lo contabilizado y vuelve a leer todas las transcripciones. Útil si una sesión creció fuera de codeg.", + "syncing": "Contando sesiones…", + "syncProgress": "{done} / {total}", + "syncDone": "{synced} sesiones contabilizadas", + "syncFailed": "No se pudieron leer algunas sesiones", + "syncBusy": "Ya hay una actualización en curso", + "lastSynced": "Actualizado {time}", + "lastSyncedNever": "Nunca actualizado", + "tileTotal": "Tokens totales", + "tileSessions": "Sesiones", + "tileTurns": "Turnos", + "tileActiveDays": "Días activos", + "tileGenTime": "Tiempo de generación", + "vsPrevious": "frente al periodo anterior", + "deltaNew": "nuevo", + "trendTitle": "Uso en el tiempo", + "trendEmpty": "Sin uso en este periodo", + "trendTurns": "Turnos", + "trendSessions": "Sesiones", + "compositionTitle": "En qué se fueron los tokens", + "compositionHint": "La entrada es lo que enviaste, la salida lo que escribió el modelo y las lecturas de caché son contexto que no pagaste a precio completo.", + "compositionNote": "Reenviar esos aciertos de caché a precio completo habría costado otros {value}.", + "inputTokens": "Entrada", + "outputTokens": "Salida", + "cacheWrite": "Escritura de caché", + "cacheRead": "Lectura de caché", + "freshTokens": "Cómputo nuevo", + "cacheHitCaption": "Acierto de caché", + "cacheHeroTitleHigh": "La mayoría del contexto no se reenvió", + "cacheHeroTitleLow": "La mayoría del contexto aún se calcula a precio completo", + "cacheHeroDesc": "La caché cargó con {cached} de contexto; solo {fresh} se calculó de nuevo en este periodo.", + "cacheSavedSuffix": "Eso ahorró reenviar el equivalente a {saved}.", + "avgPerSession": "Media por sesión", + "avgTurnsPerSession": "{count} turnos por sesión de media", + "avgPerActiveDay": "Media por día activo", + "peakBucket": "{bucket} con más uso", + "peakHour": "Hora punta", + "daysValue": "{count} días", + "idleDays": "Días sin actividad", + "byFolderTitle": "Por carpeta", + "byAgentTitle": "Por agente", + "byModelTitle": "Por modelo", + "distributionTitle": "Distribución del uso", + "distributionHint": "Sesiones y tokens agrupados por la dimensión elegida; haz clic en una fila para filtrar por ella.", + "otherLabel": "Otros", + "unknownModel": "Modelo sin registrar", + "emptyBreakdown": "Todavía sin registros", + "sessionsCount": "{count} sesiones", + "heatmapTitle": "Cuándo programas", + "heatmapHint": "Tokens por día de la semana y hora local.", + "heatmapPeakHint": "La franja más densa ronda las {hour}:00.", + "less": "Menos", + "more": "Más", + "heatmapCell": "{weekday} {hour}:00 — {value} tokens", + "weekMon": "Lun", + "weekTue": "Mar", + "weekWed": "Mié", + "weekThu": "Jue", + "weekFri": "Vie", + "weekSat": "Sáb", + "weekSun": "Dom", + "topSessionsTitle": "Sesiones más costosas", + "untitledSession": "Sesión sin título", + "topSessionsEmpty": "Sin sesiones en este periodo", + "streakLongest": "Racha más larga", + "streakLongestDays": "Racha más larga: {count} días", + "share": "Compartir", + "moreActions": "Más acciones", + "shareDialogTitle": "Comparte tu tarjeta de uso", + "shareDialogHint": "Una instantánea del periodo y los filtros que estás viendo.", + "shareSave": "Guardar imagen", + "shareCopy": "Copiar imagen", + "shareCopied": "Copiado al portapapeles", + "shareSaved": "Imagen guardada", + "shareFailed": "No se pudo crear la imagen", + "shareRendering": "Generando…", + "cardHeading": "Mis estadísticas de código con IA", + "cardRangeAll": "Todo el tiempo", + "cardTotalLabel": "Tokens usados", + "cardFooter": "Hecho con codeg", + "cardTopModels": "Modelos principales", + "cardTopProjects": "Proyectos principales", + "archetypeNightOwl": "Ave nocturna", + "archetypeNightOwlDesc": "El {percent}% de tus tokens se quema de noche.", + "archetypeEarlyBird": "Madrugador", + "archetypeEarlyBirdDesc": "El {percent}% de tus tokens cae antes de las 9.", + "archetypeWeekendWarrior": "Guerrero de fin de semana", + "archetypeWeekendWarriorDesc": "El {percent}% de tus tokens ocurre el fin de semana.", + "archetypeCacheMaster": "Maestro de la caché", + "archetypeCacheMasterDesc": "El {percent}% de tu contexto vino de la caché.", + "archetypeMarathoner": "Maratoniano", + "archetypeMarathonerDesc": "{days} días programando sin parar.", + "archetypePolyglot": "Polivalente", + "archetypePolyglotDesc": "{count} agentes en rotación seria.", + "archetypeLaserFocus": "Foco láser", + "archetypeLaserFocusDesc": "El {percent}% de tus tokens fue a un solo proyecto.", + "archetypeDeepDiver": "Buceador", + "archetypeDeepDiverDesc": "{averageK}K tokens en una sesión media.", + "archetypeSteady": "Constructor constante", + "archetypeSteadyDesc": "{days} días entregando.", + "emptyTitle": "Todavía no hay nada contabilizado", + "emptyHint": "Codeg lee los tokens directamente de la transcripción de cada agente. Actualiza para contabilizar lo que ya hay en esta máquina.", + "emptyAction": "Contabilizar mis sesiones", + "loadFailed": "No se pudo cargar el uso", + "truncatedNotice": "Este periodo es muy amplio: las cifras cubren solo su tramo más reciente." + } +} diff --git a/src/i18n/messages/fr.json b/src/i18n/messages/fr.json index 9638508d6..7b0d92303 100644 --- a/src/i18n/messages/fr.json +++ b/src/i18n/messages/fr.json @@ -1,4956 +1,4958 @@ -{ - "Language": { - "followSystem": "Suivre le système", - "english": "Anglais", - "simplifiedChinese": "Chinois simplifié", - "traditionalChinese": "Chinois traditionnel", - "japanese": "Japonais", - "korean": "Coréen", - "spanish": "Espagnol", - "german": "Allemand", - "french": "Français", - "portuguese": "Portugais", - "arabic": "Arabe" - }, - "GitCredentialDialog": { - "title": "Authentification requise", - "description": "Le serveur distant nécessite des identifiants. Entrez votre nom d'utilisateur et votre mot de passe (ou jeton d'accès personnel).", - "username": "Nom d'utilisateur", - "usernamePlaceholder": "Nom d'utilisateur ou e-mail", - "password": "Mot de passe / Jeton", - "passwordPlaceholder": "Mot de passe ou jeton d'accès personnel", - "passwordHint": "Entrez le nom d'utilisateur et le mot de passe du serveur.", - "cancel": "Annuler", - "authenticate": "Authentifier", - "authenticating": "Authentification...", - "invalidCredentials": "Identifiants invalides. Veuillez réessayer.", - "saveCredentials": "Enregistrer les identifiants pour les opérations futures", - "githubTitle": "Authentification GitHub", - "githubDescription": "Entrez un jeton d'accès personnel pour vous connecter à GitHub. Le jeton sera validé et enregistré automatiquement.", - "githubToken": "Jeton d'accès personnel", - "githubTokenPlaceholder": "ghp_xxxxxxxxxxxx", - "githubTokenHint": "Générez un jeton dans GitHub → Settings → Developer settings → Personal access tokens.", - "githubAuthenticate": "Valider et connecter", - "generateToken": "Générer un jeton" - }, - "SettingsShell": { - "title": "Paramètres", - "preferences": "Préférences", - "nav": { - "general": "Général", - "appearance": "Apparence", - "agents": "Agents IA", - "mcp": "MCP", - "skills": "Skills", - "shortcuts": "Raccourcis", - "version_control": "Contrôle de version", - "system": "Système", - "chat_channels": "Canaux de chat", - "web_service": "Service Web", - "model_providers": "Fournisseurs de Modèles", - "experts": "Experts", - "science": "Science", - "office_tools": "Outils bureautiques", - "skill_packs": "Packs de compétences", - "quick_messages": "Messages rapides", - "logs": "Journaux d'exécution" - } - }, - "AppearanceSettings": { - "sectionTitle": "Apparence du thème", - "sectionDescription": "Choisissez clair, sombre ou suivre le système. Les paramètres sont enregistrés automatiquement.", - "themeMode": "Mode du thème", - "placeholder": "Sélectionner le mode du thème", - "system": "Suivre le système", - "light": "Clair", - "dark": "Sombre", - "currentTheme": "Thème effectif actuel : {theme}", - "resolvedTheme": { - "light": "Clair", - "dark": "Sombre", - "unknown": "--" - }, - "themeColor": { - "sectionTitle": "Couleur du thème", - "sectionDescription": "Choisissez une palette pour les accents, les boutons et les surlignages.", - "current": "Couleur actuelle : {color}", - "options": { - "neutral": "Neutre", - "zinc": "Zinc", - "slate": "Ardoise", - "stone": "Pierre", - "gray": "Gris", - "red": "Rouge", - "rose": "Rose", - "orange": "Orange", - "green": "Vert", - "blue": "Bleu", - "yellow": "Jaune", - "violet": "Violet" - } - }, - "customStyle": { - "sectionTitle": "Style personnalisé", - "sectionDescription": "Ajustez les couleurs du thème actuel ou injectez votre propre CSS. Les remplacements se superposent au préréglage de base et sont conservés lorsque vous en changez.", - "summarySuspended": "Suspendu", - "summaryDefault": "Préréglage inchangé", - "summaryTokens": "{count, plural, one {# remplacement} other {# remplacements}}", - "summaryCss": "CSS personnalisé", - "suspendedByShortcut": "Le style personnalisé est suspendu. Rien de ce que vous réglez ici ne s'appliquera tant que vous ne l'aurez pas réactivé.", - "suspendedBySafeParam": "Cette fenêtre a été ouverte en mode d'apparence sûre : le style personnalisé y est ignoré. Les autres fenêtres ne sont pas affectées.", - "resume": "Réactiver le style personnalisé", - "enableTheme": "Activer les couleurs personnalisées", - "editingLight": "Vous modifiez les valeurs du mode clair. Passez l'application en mode sombre pour le régler séparément.", - "editingDark": "Vous modifiez les valeurs du mode sombre. Passez l'application en mode clair pour le régler séparément.", - "resetToken": "Rétablir la valeur du préréglage", - "radius": "Rayon des coins", - "radiusHint": "Toute l'échelle de rayons, de sm à 4xl, en découle : un seul curseur arrondit l'application entière.", - "advanced": "Avancé ({count} variables de plus)", - "enableCss": "Activer le CSS personnalisé", - "cssRisk": "Fonction avancée. Le CSS personnalisé remplace tous les styles intégrés et peut rendre l'interface inutilisable.", - "editCss": "Modifier le CSS…", - "cssPresent": "{size} Ko enregistrés", - "cssEmpty": "Rien d'enregistré pour l'instant", - "escapeHint": "Interface cassée ? Appuyez sur {shortcut} pour suspendre tout le style personnalisé, ou ouvrez une fenêtre avec le paramètre safeStyle=1.", - "copyTheme": "Copier le JSON du thème", - "importTheme": "Importer un thème…", - "clearTheme": "Effacer les remplacements", - "interopHint": "Les thèmes utilisent le format registry:theme de shadcn : collez ici n'importe quel thème shadcn, et réutilisez les vôtres dans n'importe quel projet shadcn.", - "importTitle": "Importer un thème", - "importDescription": "Collez un élément registry:theme de shadcn, un simple objet light/dark, ou une table de tokens à plat.", - "readClipboard": "Lire le presse-papiers", - "importConfirm": "Importer", - "cancel": "Annuler", - "apply": "Appliquer", - "toasts": { - "copied": "JSON du thème copié", - "copyFailed": "Impossible de copier dans le presse-papiers", - "clipboardReadFailed": "Impossible de lire le presse-papiers, collez manuellement", - "importFailed": "Ce JSON ne contient aucune variable de thème utilisable", - "imported": "Thème importé" - }, - "css": { - "dialogTitle": "CSS personnalisé", - "dialogDescription": "S'applique à toutes les fenêtres codeg. Les modifications sont prévisualisées en direct ; cliquez sur Appliquer pour enregistrer.", - "size": "{used} Ko / {max} Ko", - "ruleCount": "{count} règles", - "errorTooLarge": "Trop volumineux pour être enregistré. Réduisez-le sous la limite.", - "errorImportEscaped": "Une règle @import a survécu au retrait (syntaxe échappée). Supprimez-la pour enregistrer.", - "warnNoRules": "Aucune règle analysée, vérifiez la syntaxe.", - "noticeImportsRemoved": "Règles @import supprimées : {count}. Elles chargeraient des feuilles de style distantes.", - "noticeRemoteUrl": "Contient une url() distante, qui déclenchera une requête réseau une fois appliquée.", - "noticePreviewSuspended": "Le style personnalisé est suspendu, cet aperçu n'est donc pas appliqué.", - "noticeDisabled": "Le CSS personnalisé est désactivé. Vous pouvez prévisualiser ici, mais rien ne s'appliquera avant activation.", - "hintTokens": "Astuce : vos couleurs remplacées sont accessibles via var(--primary), var(--background), etc." - } - }, - "zoomLevel": { - "sectionTitle": "Zoom de la fenêtre", - "sectionDescription": "Met à l'échelle toute l'interface. S'applique immédiatement et est enregistré par appareil.", - "placeholder": "Sélectionnez le niveau de zoom", - "default": "Par défaut", - "current": "Zoom actuel : {zoom}%" - }, - "fonts": { - "sectionTitle": "Polices", - "sectionDescription": "Choisissez les polices pour l’interface, l’éditeur de code et le terminal. Les polices intégrées sont chargées à la demande ; sélectionnez « Personnalisée… » pour utiliser n’importe quelle police installée sur votre système.", - "interface": "Interface", - "editor": "Éditeur", - "terminal": "Terminal", - "groupSans": "Sans empattement", - "groupMono": "Monospace", - "custom": "Personnalisée…", - "customPlaceholder": "Nom de la police, par ex. Fira Code", - "fontSize": "Taille de police", - "ligatures": "Activer les ligatures", - "ligaturesUnavailable": "Cette police n’a pas de ligatures", - "wordWrap": "Activer le retour à la ligne", - "terminalLigaturesHint": "Les ligatures du terminal ne s’appliquent qu’aux polices de programmation intégrées.", - "preview": "Aperçu" - }, - "welcomePanel": { - "sectionTitle": "Zone de sélection du mode", - "sectionDescription": "Les cartes de raccourci « Développement / Bureautique » affichées au-dessus du champ de saisie sur la page de nouvelle conversation.", - "showQuickActions": "Afficher sur la page de nouvelle conversation" - }, - "workspaceBackground": { - "sectionTitle": "Arrière-plan de l'espace de travail", - "sectionDescription": "Affiche une image derrière tout l'espace de travail. La barre latérale et les panneaux deviennent translucides et dépolis pour laisser transparaître l'image, et un masque préserve la lisibilité du texte.", - "enable": "Activer l'image d'arrière-plan", - "image": "Image", - "chooseImage": "Choisir une image", - "replaceImage": "Remplacer l'image", - "removeImage": "Supprimer", - "fillMode": "Mode de remplissage", - "fillModes": { - "cover": "Remplir", - "contain": "Ajuster", - "center": "Centrer", - "tile": "Mosaïque" - }, - "maskOpacity": "Opacité du masque", - "maskOpacityHint": "Des valeurs élevées fondent l'image vers la couleur d'arrière-plan du thème, améliorant le contraste du texte.", - "imageBlur": "Flou de l'image", - "panelOpacity": "Opacité des panneaux", - "panelOpacityHint": "Opacité de la barre latérale, des panneaux et des barres d'onglets. Plus c'est bas, plus l'image transparaît.", - "errorTooLarge": "L'image est trop volumineuse (16 Mo maximum).", - "errorUploadFailed": "Échec de la définition de l'image d'arrière-plan." - } - }, - "SystemSettings": { - "loading": "Chargement...", - "sectionTitle": "Gestion du système", - "sectionDescription": "Gérez le proxy réseau, les mises à jour de l’app et les préférences de langue.", - "proxyTitle": "Proxy réseau", - "proxyDescription": "Lorsqu’il est activé, les requêtes réseau suivantes utilisent ce proxy en priorité (y compris le chat ACP, l’installation d’agents et les opérations Git distantes).", - "loadFailed": "Échec du chargement : {message}", - "enableProxy": "Activer le proxy système", - "proxyAddress": "Adresse du proxy", - "proxyHint": "Prend en charge http(s)/socks5, exemple : {example}. Actif uniquement lorsque le proxy système est activé.", - "save": "Enregistrer", - "saving": "Enregistrement...", - "proxyRequired": "L’URL du proxy est requise lorsque le proxy est activé", - "saveSuccess": "Les paramètres du proxy système ont été enregistrés", - "saveFailed": "Échec de l’enregistrement : {message}", - "languageTitle": "Langue", - "languageDescription": "Définissez la langue de l’app. En mode système, les langues non prises en charge reviennent à l’anglais.", - "appLanguage": "Langue de l’app", - "languageSaveSuccess": "Les paramètres de langue ont été enregistrés", - "languageSaveFailed": "Échec de l’enregistrement des paramètres de langue : {message}", - "updateTitle": "Mise à jour de l’app", - "versionTitle": "Mise à jour logicielle", - "updateDescription": "Vérifiez les nouvelles versions depuis la source de publication configurée et installez-les directement si disponibles.", - "currentVersion": "Version actuelle", - "upgradableVersion": "Dernière version", - "none": "Aucune", - "lastChecked": "Dernière vérification : {time}", - "updateError": "Erreur de mise à jour : {message}", - "checking": "Vérification...", - "checkUpdate": "Rechercher les mises à jour", - "updating": "Installation...", - "downloading": "Téléchargement...", - "upgradeTo": "Mettre à jour vers v{version}", - "viewRelease": "Voir la version v{version}", - "foundUpdate": "Nouvelle version v{version} trouvée", - "alreadyLatest": "Vous utilisez déjà la dernière version", - "checkUpdateFailed": "Échec de la recherche de mises à jour : {message}", - "installSuccess": "Mise à jour installée. Redémarrage de l’app.", - "installFailed": "Échec de la mise à jour : {message}", - "upgradeSuccess": "Mise à niveau terminée. Rechargement...", - "restartTimeout": "Le serveur n'est pas revenu à temps. Consultez les journaux du conteneur ou du service.", - "restartingIn": "Redémarrage dans {seconds} s...", - "waitingForServer": "En attente du retour du serveur...", - "restartToUpdate": "Redémarrer pour mettre à jour", - "newVersionBadge": "Nouveau v{version}", - "updateAvailableTitle": "Mise à jour disponible", - "releaseNotesTitle": "Nouveautés", - "remindLater": "Plus tard", - "retry": "Réessayer", - "stepDownload": "Téléchargement", - "stepInstall": "Installation", - "stepRestart": "Redémarrage", - "updateReadyHint": "Mise à jour téléchargée — redémarrez pour l'appliquer.", - "restarting": "Redémarrage...", - "dockerUpgradeHint": "Cela met à jour le conteneur en cours d'exécution. La mise à jour est perdue si le conteneur est recréé — pour la conserver, récupérez ou créez une image à la nouvelle version puis recréez le conteneur.", - "upgradeRolledBack": "Échec de la mise à niveau ; le serveur est revenu à la version précédente.", - "serverUnreachable": "Impossible de joindre le serveur pour démarrer la mise à niveau. Vérifiez qu'il fonctionne et réessayez.", - "rollbackButton": "Revenir en arrière", - "rollingBack": "Restauration...", - "rollbackDescription": "Restaure la version installée avant la dernière mise à niveau.", - "rollbackConfirmTitle": "Revenir à la version précédente ?", - "rollbackConfirmDescription": "Le serveur redémarrera sur la version installée avant la dernière mise à niveau. Une version plus récente reste disponible à la réinstallation.", - "rollbackConfirm": "Revenir en arrière", - "rollbackCancel": "Annuler", - "rollbackSuccess": "Retour à la version précédente. Rechargement...", - "rollbackFailed": "Échec du retour en arrière. Consultez les journaux du serveur.", - "updateErrors": { - "sourceUnavailable": "Impossible d’atteindre la source de mise à jour. Vérifiez votre réseau ou proxy et réessayez.", - "network": "La connexion réseau a échoué. Vérifiez votre réseau ou proxy et réessayez.", - "downloadFailed": "Impossible de télécharger le paquet de mise à jour. Veuillez réessayer plus tard.", - "installFailed": "Impossible d’installer la mise à jour. Fermez l’app puis réessayez.", - "unknown": "La mise à jour a échoué. Veuillez réessayer plus tard." - } - }, - "VersionControlSettings": { - "loading": "Chargement...", - "sectionTitle": "Contrôle de version", - "sectionDescription": "Configurez l'exécutable Git et gérez les comptes GitHub.", - "gitTitle": "Configuration Git", - "gitDescription": "Configurez l'exécutable Git utilisé par l'application.", - "gitDetected": "Git détecté", - "gitNotFound": "Git introuvable sur le système", - "gitVersion": "Version", - "gitPath": "Chemin", - "customGitPath": "Chemin Git personnalisé", - "customGitPathPlaceholder": "/usr/bin/git", - "customGitPathHint": "Laissez vide pour utiliser le chemin détecté automatiquement.", - "test": "Tester", - "testing": "Test en cours...", - "testSuccess": "L'exécutable Git est valide.", - "testFailed": "Test Git échoué : {message}", - "save": "Enregistrer", - "saving": "Enregistrement...", - "saveSuccess": "Paramètres Git enregistrés.", - "saveFailed": "Échec de l'enregistrement : {message}", - "githubTitle": "Comptes GitHub", - "githubDescription": "Gérez les comptes GitHub pour l'authentification. Les jetons sont stockés localement.", - "noAccounts": "Aucun compte GitHub configuré.", - "addAccount": "Ajouter un compte", - "serverUrl": "URL du serveur", - "serverUrlPlaceholder": "https://github.com", - "token": "Jeton d'accès personnel", - "tokenPlaceholder": "ghp_xxxxxxxxxxxx", - "generateToken": "Générer un jeton", - "tokenHint": "Générez un jeton dans GitHub → Settings → Developer settings → Personal access tokens.", - "validateAndAdd": "Valider et ajouter", - "validating": "Validation...", - "addSuccess": "Compte {username} ajouté avec succès.", - "addFailed": "Échec de l'ajout du compte : {message}", - "testConnection": "Tester", - "connectionSuccess": "Connexion réussie.", - "connectionFailed": "Échec de la connexion : {message}", - "setDefault": "Définir par défaut", - "defaultLabel": "Par défaut", - "defaultSet": "Compte par défaut mis à jour.", - "removeAccount": "Supprimer", - "removeConfirmTitle": "Supprimer le compte", - "removeConfirmMessage": "Êtes-vous sûr de vouloir supprimer le compte « {username} » ?", - "removeConfirm": "Supprimer", - "removeCancel": "Annuler", - "removeSuccess": "Compte supprimé.", - "scopes": "Portées", - "loadFailed": "Échec du chargement des paramètres : {message}", - "gitAccount": { - "sectionTitle": "Comptes serveur Git", - "sectionDescription": "Gérez les identifiants pour les serveurs Git non GitHub (GitLab, Bitbucket, auto-hébergé, etc.).", - "noAccounts": "Aucun compte de serveur Git configuré.", - "addAccount": "Ajouter un compte", - "addTitle": "Ajouter un compte Git", - "addDescription": "Entrez l'adresse du serveur, le nom d'utilisateur et le mot de passe ou jeton d'accès.", - "serverUrl": "URL du serveur", - "serverUrlPlaceholder": "https://gitlab.example.com", - "username": "Nom d'utilisateur", - "usernamePlaceholder": "Nom d'utilisateur ou e-mail", - "password": "Mot de passe / Jeton", - "passwordPlaceholder": "Mot de passe ou jeton d'accès", - "passwordHint": "Entrez le mot de passe ou le jeton d'accès du serveur.", - "add": "Ajouter", - "serverRequired": "L'URL du serveur est requise.", - "usernameRequired": "Le nom d'utilisateur est requis.", - "passwordRequired": "Le mot de passe est requis." - } - }, - "ShortcutSettings": { - "sectionTitle": "Raccourcis", - "resetDefault": "Rétablir les valeurs par défaut", - "recordInstruction": "Cliquez sur le bouton à droite, puis appuyez sur une combinaison de touches. Utilisez Ctrl/Cmd, Alt et Shift. Appuyez sur Échap pour annuler l’enregistrement.", - "recording": "Appuyez sur un raccourci...", - "toasts": { - "conflict": "Le raccourci est déjà utilisé par \"{title}\"", - "updated": "Raccourci mis à jour", - "invalid": "Raccourci invalide, veuillez réessayer", - "reset": "Les raccourcis par défaut ont été restaurés" - }, - "actions": { - "toggle_search": { - "title": "Ouvrir la recherche", - "description": "Afficher ou masquer le panneau de recherche de conversations" - }, - "toggle_sidebar": { - "title": "Basculer la barre latérale gauche", - "description": "Afficher ou masquer la barre latérale de liste des conversations" - }, - "toggle_terminal": { - "title": "Basculer le terminal", - "description": "Afficher ou masquer le panneau terminal inférieur" - }, - "new_terminal_tab": { - "title": "Nouveau terminal", - "description": "Créer un nouvel onglet terminal lorsque le terminal a le focus" - }, - "close_current_terminal_tab": { - "title": "Fermer le terminal actuel", - "description": "Fermer l’onglet terminal actuel lorsque le terminal a le focus" - }, - "toggle_aux_panel": { - "title": "Basculer le panneau droit", - "description": "Afficher ou masquer le panneau d’informations auxiliaires" - }, - "new_conversation": { - "title": "Nouvelle conversation", - "description": "Créer un nouvel onglet de conversation dans le dossier actuel" - }, - "open_folder": { - "title": "Ouvrir un dossier", - "description": "Ouvrir le sélecteur de dossier et ouvrir dans une nouvelle fenêtre" - }, - "open_settings": { - "title": "Ouvrir les paramètres", - "description": "Ouvrir la fenêtre des paramètres" - }, - "close_current_tab": { - "title": "Fermer l’onglet actuel", - "description": "Fermer la conversation actuelle ou l’onglet de fichier" - }, - "close_all_file_tabs": { - "title": "Fermer tous les onglets de fichiers", - "description": "Fermer tous les onglets de fichiers ouverts lorsque le panneau de fichiers est actif" - }, - "next_tab": { - "title": "Onglet suivant", - "description": "Passer à l'onglet de conversation ou de fichier suivant" - }, - "prev_tab": { - "title": "Onglet précédent", - "description": "Passer à l'onglet de conversation ou de fichier précédent" - }, - "send_message": { - "title": "Envoyer le message", - "description": "Envoyer le message actuel dans la zone de saisie" - }, - "newline_in_message": { - "title": "Retour à la ligne", - "description": "Insérer un retour à la ligne dans la zone de saisie" - }, - "toggle_custom_style": { - "title": "Suspendre/réactiver le style personnalisé", - "description": "Issue de secours : désactive toutes les couleurs et le CSS personnalisés, puis les réactive" - } - } - }, - "SkillsSettings": { - "title": "Skills", - "description": "Sélectionnez une Skill à gauche. À droite, un aperçu Markdown s’affiche par défaut ; passez en édition pour modifier et enregistrer.", - "loadingAgents": "Chargement des agents qui prennent en charge les Skills...", - "emptyNoManageableAgents": "Aucun agent disponible pour la gestion des Skills.", - "managedTarget": "Cible gérée", - "selectAgentPlaceholder": "Sélectionnez un agent", - "searchPlaceholder": "Rechercher par nom / ID / chemin...", - "skillsList": "Liste des Skills", - "loadingSkills": "Chargement des Skills...", - "agentNotSupported": "L’agent actuel ne prend pas en charge la gestion des Skills.", - "emptySkills": "Aucune Skill pour le moment. Cliquez sur « Nouvelle Skill » pour en créer une.", - "newSkillTitle": "Nouvelle Skill", - "skillInfo": "Infos de la Skill", - "skillIdPlaceholder": "skill-id (lettres/chiffres/-/_/.)", - "skillsDirectoryWithPath": "Répertoire des Skills : {path}", - "skillsDirectoryNeedId": "Répertoire des Skills : saisissez l’ID de Skill pour générer le chemin complet", - "markdownContent": "Contenu Markdown", - "editingStatus": "Édition", - "previewStatus": "Aperçu", - "contentPlaceholder": "Saisissez le contenu Markdown de la Skill...", - "metadataTitle": "Métadonnées des Skills", - "onlyYamlMetadata": "Cette Skill contient uniquement des métadonnées YAML.", - "emptyContentHint": "Aucun contenu pour le moment. Cliquez sur « Éditer » pour commencer.", - "loadingSkill": "Chargement de la Skill...", - "emptyNoAgents": "Aucun agent disponible.", - "noSelectionHint": "Sélectionnez un Skill à gauche ou cliquez sur « Nouveau Skill » pour en créer un.", - "systemBadge": "Système", - "systemHint": "Skill intégré du CLI · lecture seule", - "scope": { - "global": "Global", - "folder": "Dossier", - "selectFolderPlaceholder": "Sélectionner un dossier", - "noFolders": "Aucun dossier trouvé", - "pickFolderHint": "Sélectionnez un dossier pour afficher ses Skills." - }, - "actions": { - "preview": "Aperçu", - "edit": "Éditer", - "openInWindow": "Ouvrir dans une nouvelle fenêtre", - "delete": "Supprimer", - "deleting": "Suppression...", - "refresh": "Actualiser", - "newSkill": "Nouvelle Skill", - "reset": "Réinitialiser", - "save": "Enregistrer", - "saving": "Enregistrement...", - "cancel": "Annuler" - }, - "deleteDialog": { - "title": "Supprimer la Skill", - "confirm": "Supprimer la Skill actuelle ? Cette action est irréversible.", - "confirmWithNamePrefix": "Supprimer la Skill", - "confirmWithNameSuffix": "? Cette action est irréversible." - }, - "toasts": { - "loadFailed": "Échec du chargement de la Skill", - "openFolderFailed": "Échec de l'ouverture du dossier", - "noSkillDirectory": "Aucun répertoire de Skills disponible pour l’agent actuel", - "nameRequired": "Le nom de la Skill ne peut pas être vide", - "updated": "Skill mise à jour", - "created": "Skill créée", - "saveFailed": "Échec de l’enregistrement de la Skill", - "deleted": "Skill supprimée", - "deleteFailed": "Échec de la suppression de la Skill" - }, - "templates": { - "gemini": "---\nname: example-skill\ndescription: Describe when this skill should be used.\n---\n\n# Skill Name\n\nInstructions for the agent when this skill is active.\n\n## Workflow\n\n1. Add actionable step one.\n2. Add actionable step two.\n", - "openCode": "---\nname: example-skill\ndescription: Describe when this skill should be used.\n---\n\n# Purpose\n\nDescribe what this skill helps with.\n\n# Steps\n\n1. Add actionable step one.\n2. Add actionable step two.\n", - "openClaw": "---\nname: example-skill\ndescription: Describe when this skill should be used.\nuser-invocable: true\ndisable-model-invocation: false\n---\n\n# Purpose\n\nDescribe what this skill helps with.\n\n# Instructions\n\n1. Add actionable instruction one.\n2. Add actionable instruction two.\n", - "default": "---\nname: example-skill\ndescription: Describe when this skill should be used.\n---\n\n# Skill: example-skill\n\n## When to use\n\n- Describe trigger conditions.\n\n## Instructions\n\n1. Add actionable instruction one.\n2. Add actionable instruction two.\n" - } - }, - "McpSettings": { - "loading": "Chargement...", - "summary": { - "missingCommand": "(commande manquante)", - "missingUrl": "(URL manquante)" - }, - "protocol": { - "stdio": "Stdio" - }, - "errors": { - "selectInstallProtocol": "Veuillez sélectionner un protocole d’installation", - "fieldRequired": "{field} est requis", - "fieldNeedsBoolean": "{field} doit être true ou false", - "fieldNeedsNumber": "{field} doit être un nombre", - "fieldNeedsInteger": "{field} doit être un entier", - "fieldInvalidJson": "{field} contient un JSON invalide : {message}", - "fieldOutOfRange": "La valeur de {field} est hors de la plage autorisée", - "jsonEmpty": "{name} ne peut pas être vide", - "jsonInvalid": "{name} n’est pas un JSON valide : {message}", - "jsonMustBeObject": "{name} doit être un objet JSON", - "specMustBeObject": "La configuration MCP doit être un objet JSON.", - "missingType": "Le champ type est manquant dans la configuration MCP. Indiquez stdio, http (alias : streamable-http, streamableHttp) ou sse.", - "unsupportedType": "Type MCP non pris en charge {type}. Pris en charge : stdio, http (alias : streamable-http, streamableHttp), sse.", - "codexEntryUnsupportedType": "L’entrée MCP Codex {id} a un type non pris en charge {type}. Pris en charge : stdio, http (alias : streamable-http, streamableHttp), sse.", - "unsupportedTransportType": "Type de transport non pris en charge {type}. Pris en charge : http (alias : streamable-http, streamableHttp), sse.", - "stdioCommandRequired": "Un MCP stdio nécessite un champ command non vide.", - "remoteUrlRequired": "Un MCP distant nécessite un champ url non vide.", - "appsRequired": "Sélectionnez au moins une application cible." - }, - "jsonNames": { - "localConfig": "Configuration MCP", - "installConfig": "Configuration d’installation" - }, - "toasts": { - "uninstalled": "MCP désinstallé", - "uninstallFailed": "Échec de la désinstallation : {message}", - "selectAtLeastOneApp": "Veuillez sélectionner au moins une application cible", - "saveSuccess": "Enregistré", - "saveFailed": "Échec de l’enregistrement : {message}", - "installed": "{name} installé", - "installFailed": "Échec de l’installation : {message}", - "serverIdRequired": "L'ID du serveur est requis", - "serverIdExists": "Le Server ID \"{id}\" existe déjà. Modifiez l'entrée existante ou choisissez un autre nom.", - "created": "MCP créé" - }, - "installDialog": { - "title": "Confirmer l’installation MCP", - "descriptionWithName": "Installer {name} dans la configuration locale.", - "description": "Sélectionnez les applications cibles pour l’installation.", - "protocol": "Protocole", - "selectProtocol": "Sélectionner un protocole", - "parameters": "Paramètres de configuration", - "booleanPlaceholder": "Veuillez sélectionner true/false", - "selectOneValue": "Sélectionner une valeur", - "targetApps": "Applications cibles" - }, - "actions": { - "cancel": "Annuler", - "confirmInstall": "Confirmer l’installation", - "installing": "Installation", - "uninstall": "Désinstaller", - "uninstalling": "Désinstallation", - "viewDetails": "Voir les détails", - "save": "Enregistrer", - "saving": "Enregistrement", - "install": "Installer", - "refresh": "Actualiser", - "newMcp": "Nouveau MCP", - "create": "Créer", - "creating": "Création..." - }, - "tabs": { - "local": "MCP local", - "market": "Marketplace MCP" - }, - "local": { - "filterPlaceholder": "Filtrer les MCP locaux...", - "loadFailed": "Échec du chargement : {message}", - "empty": "Aucun MCP local détecté.", - "description": "La configuration MCP locale peut être modifiée et enregistrée directement.", - "enabledApps": "Applications activées", - "configJson": "Configuration MCP (JSON)", - "draftTitle": "Nouveau MCP", - "draftDescription": "Renseignez un Server ID et une configuration pour créer un serveur MCP local.", - "serverIdLabel": "ID du serveur", - "serverIdPlaceholder": "ID du serveur (ex. my-mcp)", - "typeHint": "Types pris en charge : stdio, http (alias : streamable-http, streamableHttp), sse. env n'est utilisé que par stdio ; pour les MCP distants, utilisez headers pour transporter les jetons d'authentification.", - "envOnRemoteWarning": "env détecté sur un MCP distant. Seul stdio utilise env ; les MCP distants transportent les jetons d'authentification via headers, donc env sera ignoré à l'enregistrement." - }, - "market": { - "selectMarketplace": "Sélectionner un marketplace", - "searchPlaceholder": "Rechercher MCP...", - "searchFailed": "Échec de la recherche : {message}", - "loadingList": "Chargement de la liste MCP...", - "empty": "Aucun résultat MCP.", - "loadingDetail": "Chargement des détails du marketplace...", - "detailLoadFailed": "Échec du chargement des détails : {message}", - "owner": "Propriétaire : {owner}", - "namespace": "Espace de noms : {namespace}", - "defaultInstallProtocol": "Protocole d’installation par défaut", - "currentOptionParameterCount": "Nombre de paramètres de l’option actuelle : {count}", - "installConfigDescription": "Configuration d’installation (JSON, modifiable avant installation ; les modifications remplaceront le formulaire protocole/paramètres)", - "selectLeftToView": "Sélectionnez un MCP du marketplace à gauche pour voir les détails." - }, - "badges": { - "verified": "Vérifié", - "remote": "Distant", - "hasHomepage": "A une page d’accueil", - "uses": "{count} utilisations", - "deployed": "Déployé", - "notDeployed": "Non déployé" - }, - "selectLeftMcp": "Sélectionnez un MCP à gauche." - }, - "AcpAgentSettings": { - "title": "Gestion du SDK des agents", - "description": "Gérez en un seul endroit la connexion SDK des agents, l'état activé, les variables d'environnement, la gestion de configuration et les informations de préflight de version.", - "loadingAgents": "Chargement de la liste des agents...", - "agentList": "Liste des agents", - "emptyNoAgent": "Aucun agent disponible.", - "configManagement": "Gestion de configuration", - "envVars": "Variables d'environnement", - "hostTools": { - "label": "Laisser l'agent gérer les fichiers et les commandes", - "description": "codeg cesse d'assurer l'accès aux fichiers et les commandes de terminal : l'agent les exécute dans son propre processus, là où son bac à sable et ses règles d'autorisation s'appliquent réellement. La délégation à d'autres agents est également désactivée, car elle ferait repasser le même travail par codeg. codeg n'ajoute aucun bac à sable, n'activez donc ceci que si l'agent en a un configuré." - }, - "nativeJsonConfig": "Configuration JSON native", - "modelHintDefault": "Laissez vide pour utiliser le modèle système par défaut.", - "generalConfigDescriptionClaude": "Prend en charge la configuration rapide de l'API URL, API Key et des modèles Claude, et synchronise avec la configuration JSON native.", - "generalConfigDescriptionDefault": "Prend en charge les entrées de configuration importantes (API URL, API Key, Model) et la gestion de la configuration JSON native.", - "multiAgent": { - "title": "Collaboration multi-agent", - "description": "Permet aux agents actifs de déléguer des sous-tâches à d’autres agents.", - "enable": "Activer la délégation", - "enableHint": "Lorsque cette option est désactivée, l’outil delegate_to_agent est masqué du catalogue d’outils MCP de l’agent.", - "withheldByHostTools": "{agents} ne recevront pas les outils de délégation : leur interrupteur par agent « Laisser l’agent gérer les fichiers et les commandes » est activé.", - "depthLimit": "Profondeur maximale de délégation", - "depthHint": "Plage autorisée : {min}–{max}. Limite la profondeur de récursion d’une chaîne de délégation (racine → enfant → petit-enfant …).", - "completedCacheLabel": "Cache des résultats terminés (MB)", - "completedCacheHint": "Cache en mémoire des résultats terminés des sous-agents, conservé uniquement tant que la session de délégation est en cours et libéré automatiquement à la fin de cette session. Au-delà de ce budget, les résultats les plus anciens sont supprimés de la mémoire en premier (toujours consultables dans la session du sous-agent) ; 0 = illimité (libéré quand même à la fin de la session).", - "save": "Enregistrer", - "saving": "Enregistrement…", - "saved": "Paramètres de délégation enregistrés", - "saveFailed": "Échec de l’enregistrement des paramètres de délégation", - "loadFailed": "Échec du chargement des paramètres de délégation : {detail}", - "tabGeneral": "Général", - "tabAgentDefaults": "Valeurs par défaut du sous-agent", - "agentDefaultsDescription": "Remplacements par agent appliqués lorsque la Collaboration multi-agent démarre un sous-agent pour un appel de délégation. Les options affichées proviennent d’une sonde en direct : votre sélection correspond exactement à ce que l’agent acceptera.", - "probing": "Chargement des options disponibles depuis l’agent…", - "probeFailed": "Échec du chargement des options : {detail}", - "retry": "Réessayer", - "noConfigAvailable": "Cet agent n’a aucune option configurable.", - "modeLabel": "Mode", - "agentDefaultHint": "Valeur par défaut de l’agent : {value}", - "defaultOptionLabel": "Par défaut ({value})" - }, - "actions": { - "dragSort": "Glisser pour réordonner", - "dragSortAgent": "Glisser pour réordonner {name}", - "refreshCheck": "Actualiser la vérification", - "refreshCheckAgent": "Actualiser la vérification de {name}", - "clickEnable": "Cliquer pour activer {name}", - "clickDisable": "Cliquer pour désactiver {name}", - "install": "Installer", - "upgrade": "Mettre à niveau", - "uninstall": "Désinstaller", - "uninstalling": "Désinstallation...", - "saveEnvVars": "Enregistrer les variables d’environnement", - "saving": "Enregistrement...", - "saveGrokConfig": "Enregistrer la configuration Grok", - "saveCodexConfig": "Enregistrer la config Codex", - "saveGeminiConfig": "Enregistrer la config Gemini", - "saveOpenCodeConfig": "Enregistrer la config OpenCode", - "saveOpenClawConfig": "Enregistrer la config OpenClaw", - "saveConfigManagement": "Enregistrer la gestion de config", - "saveCurrentProvider": "Enregistrer le provider actuel", - "showApiKey": "Afficher la clé API", - "hideApiKey": "Masquer la clé API", - "showKey": "Afficher la clé", - "hideKey": "Masquer la clé", - "showToken": "Afficher le token", - "hideToken": "Masquer le token", - "cancel": "Annuler", - "delete": "Supprimer", - "deleting": "Suppression...", - "confirmDelete": "Confirmer la suppression", - "confirmUninstall": "Confirmer la désinstallation", - "saveClineConfig": "Enregistrer la configuration Cline", - "saveHermesConfig": "Enregistrer la configuration Hermes", - "saveCodeBuddyConfig": "Enregistrer la configuration CodeBuddy", - "saveKimiCodeConfig": "Enregistrer la configuration de Kimi Code", - "customInstall": "Installation personnalisée", - "saveKimiCodeRawConfig": "Enregistrer config.toml", - "saveDeepSeekConfig": "Enregistrer la configuration DeepSeek", - "diagnose": "Diagnostiquer" - }, - "status": { - "enabled": "Activé", - "disabled": "Désactivé", - "unchecked": "Non vérifié", - "agentEnabledAria": "{name} activé", - "agentEnabledSwitch": "Interrupteur d’activation {name}" - }, - "preflight": { - "count": "Éléments de pré-vérification : {count}", - "notRun": "Les vérifications n’ont pas encore été exécutées." - }, - "grok": { - "configDescription": "Configurez Grok ici. Les contrôles ci-dessous — mode d'autorisation, effort de raisonnement, un modèle personnalisé optionnel (point de terminaison dédié) et le compactage — sont fusionnés dans ~/.grok/config.toml, en préservant vos autres clés et commentaires. La connexion utilise votre XAI_API_KEY ou `grok login`. Les autres clés restent modifiables sous Avancé.", - "permissionModeLabel": "Mode d'autorisation", - "permissionDefault": "Demander à chaque fois", - "permissionAcceptEdits": "Approuver les modifications automatiquement", - "permissionAuto": "Approbation automatique intelligente", - "permissionAlwaysApprove": "Toujours approuver", - "reasoningEffortLabel": "Effort de raisonnement", - "effortLow": "Faible (plus rapide)", - "effortMedium": "Moyen (équilibré)", - "effortHigh": "Élevé", - "effortXhigh": "Maximum", - "optionDefault": "Utiliser la valeur par défaut", - "authTitle": "Authentification", - "authMode": "Méthode d'authentification", - "authModeApiKey": "Clé API XAI", - "authModeApiKeyHint": "Authentifiez-vous avec une XAI_API_KEY de la console xAI, pour les exécutions non interactives ou headless. Enregistrée dans l'environnement de cet agent.", - "authModeCustom": "Point de terminaison personnalisé", - "authModeCustomHint": "Utilisez votre propre point de terminaison (BYO) : définissez ci-dessous un modèle personnalisé avec sa propre URL de base et sa clé API. Il devient le modèle par défaut de Grok.", - "subscriptionHint": "Connectez-vous avec `grok login` (SuperGrok / X Premium+). Aucune clé API n'est enregistrée.", - "loginHint": "Exécutez ceci dans un terminal pour vous connecter, puis rouvrez ces paramètres :", - "commandCopied": "Commande copiée dans le presse-papiers", - "copyCommand": "Copier la commande", - "authKeyConfigured": "XAI_API_KEY est configurée.", - "authKeyMissing": "Aucune XAI_API_KEY définie.", - "advancedToggle": "Avancé (config.toml brut)", - "configTomlNative": "config.toml (natif)", - "configTomlHint": "Enregistré tel quel comme l'intégralité de ~/.grok/config.toml. Le TOML invalide est rejeté afin qu'une faute de frappe ne tronque jamais votre fichier.", - "configTomlPlaceholder": "# Clés autres que les contrôles ci-dessus, p. ex.\n# [mcp_servers.*], [cli], règles [permission].", - "customModelTitle": "Modèle personnalisé (point de terminaison dédié)", - "customModelHint": "Dirigez Grok vers un point de terminaison personnalisé ou auto-hébergé. codeg écrit un bloc `[model.*]` par modèle et le définit comme modèle par défaut. Laissez l'ID de modèle vide pour le supprimer.", - "customModelIdLabel": "ID du modèle", - "customModelIdPlaceholder": "grok-4.5", - "customModelIdHint": "Enregistré comme bloc `[model.*]` et envoyé à l'API comme nom de modèle ; également défini comme `[models].default`.", - "customBaseUrlLabel": "URL de base", - "customBaseUrlPlaceholder": "https://api.x.ai/v1 (par défaut)", - "customApiBackendLabel": "Backend de l'API", - "backendResponses": "Responses", - "backendChatCompletions": "Chat Completions", - "backendMessages": "Messages (Anthropic)", - "customApiKeyLabel": "Clé API", - "customApiKeyHint": "Stockée en ligne dans `[model.*].api_key`, limitée à ce point de terminaison.", - "customContextWindowLabel": "Fenêtre de contexte (tokens)", - "customContextWindowHint": "Facultatif. Détermine le moment du compactage automatique ; laissez vide pour la valeur par défaut du point de terminaison.", - "autoCompactLabel": "Seuil de compactage automatique (%)", - "autoCompactHint": "Compacte la conversation lorsque l'utilisation du contexte atteint ce pourcentage (85 par défaut pour Grok). Écrit dans `[session]`." - }, - "cursor": { - "configDescription": "Configurez Cursor ici. Choisissez une méthode d'authentification — abonnement officiel (connexion par navigateur) ou une clé API Cursor pour les machines sans interface ou serveurs — puis choisissez un modèle et modifiez les règles d'autorisation et le bac à sable du CLI. codeg les écrit dans ~/.cursor/cli-config.json, partagé avec le CLI cursor-agent.", - "authTitle": "Authentification", - "authChecking": "Vérification…", - "authNotInstalled": "cursor-agent n'est pas installé", - "authLoggedIn": "Connecté", - "authNotLoggedIn": "Non connecté", - "loginHint": "Exécutez ceci dans un terminal pour vous connecter à votre compte Cursor (une fenêtre de navigateur s'ouvre), puis cliquez sur actualiser :", - "apiKeyLabel": "Clé API Cursor", - "apiKeyPlaceholder": "clé depuis cursor.com/dashboard", - "apiKeyHint": "CURSOR_API_KEY — une clé de compte du tableau de bord Cursor, alternative à la connexion par navigateur pour les machines sans interface ou serveurs. Ce n'est pas une clé tierce ni OpenAI.", - "modelTitle": "Modèle par défaut", - "loadModels": "Charger les modèles", - "modelsUnavailable": "Liste de modèles indisponible", - "modelHint": "Transmis à la CLI via --model au démarrage de la session. Laissez par défaut pour laisser Cursor choisir.", - "permissionsTitle": "Permissions & bac à sable", - "permissionsDescription": "Éditeur visuel des règles de permissions de la CLI (cli-config.json). Les règles autorisées s'exécutent sans confirmation ; les règles refusées sont toujours bloquées.", - "permissionModeLabel": "Mode d'autorisation", - "permissionModeDefault": "Demander avant d'exécuter (par défaut)", - "permissionModeForce": "Tout exécuter (--force)", - "permissionModeHint": "Tout exécuter lance les sessions avec --force : tous les appels d'outils sont autorisés automatiquement sauf les règles de refus, sans confirmation (une politique d'organisation peut le limiter aux règles d'autorisation). S'applique aux nouvelles sessions.", - "optionDefault": "Défaut (non défini)", - "sandboxLabel": "Bac à sable", - "sandboxEnabled": "Activé", - "sandboxDisabled": "Désactivé", - "allowRulesLabel": "Règles autorisées", - "denyRulesLabel": "Règles refusées", - "addRule": "Ajouter une règle", - "rulesSyntaxHint": "Syntaxe des règles : Shell(cmd), Read(chemin/glob), Write(chemin/glob), WebFetch(domaine), Mcp(serveur:outil) — les règles de refus priment toujours.", - "saveConfig": "Enregistrer la configuration", - "advancedToggle": "Avancé : cli-config.json brut", - "advancedHint": "Le ~/.cursor/cli-config.json complet. Enregistrer écrit le fichier tel quel ; les contrôles structurés ci-dessus y sont fusionnés.", - "saveRawConfig": "Enregistrer le fichier", - "authMode": "Méthode d'authentification", - "subscriptionHint": "Connectez-vous avec votre compte Cursor et utilisez les modèles de Cursor.", - "customApiKeyRequired": "Une clé API Cursor est requise.", - "authModeApiKey": "Clé API Cursor (sans interface)", - "authModeApiKeyHint": "Authentifiez-vous avec une clé API de compte Cursor générée dans le tableau de bord Cursor (pour les machines sans interface ou serveurs). C'est une clé de compte Cursor, pas un point de terminaison tiers/OpenAI : cursor-agent ne communique qu'avec le backend de Cursor. Pour utiliser un point de terminaison compatible codex/OpenAI, utilisez plutôt l'agent Codex.", - "modelPickerPlaceholder": "Rechercher des modèles…", - "modelNoMatch": "Aucun modèle correspondant", - "modelsNeedAuth": "Connectez-vous pour charger la liste des modèles.", - "modelDefaultBadge": "par défaut" - }, - "deepseek": { - "configManagement": "Configuration de DeepSeek Harness", - "configDescription": "Le point de terminaison et la clé sont des variables d'environnement que deepseek-acp lit au démarrage. Le modèle et le niveau de raisonnement sont des sélecteurs par session : ils se choisissent dans le champ de saisie.", - "baseUrlLabel": "Point de terminaison de l'API", - "baseUrlHint": "Laissez vide pour le point de terminaison officiel. S'applique aux sessions démarrées après l'enregistrement ; reconnectez une session en cours pour qu'elle le prenne en compte.", - "baseUrlInvalid": "Saisissez une URL http(s) complète et sans chaîne de requête, par exemple https://api.deepseek.com", - "apiKeyLabel": "Clé d'API", - "apiKeyHint": "Transmise à l'agent via DEEPSEEK_API_KEY. Une variable d'environnement l'emporte sur le fichier d'identifiants : laissez ce champ vide si vous vous connectez depuis le terminal." - }, - "codex": { - "configDescription": "Prend en charge la configuration rapide de l’URL API, de la clé API, du nom du modèle et du reasoning effort, avec synchronisation vers `auth.json` / `config.toml`.", - "authMode": "Mode d’authentification", - "chatgptSubscription": "Abonnement officiel", - "chatgptSubscriptionHint": "Connectez-vous avec l’abonnement officiel ChatGPT, pas besoin d’API Key", - "apiKeyHint": "Connectez-vous avec une API Key à OpenAI ou aux services API compatibles", - "selectProvider": "Sélectionner un provider", - "modelName": "Nom du modèle", - "selectReasoningEffort": "Sélectionner Reasoning Effort", - "enableWebsocket": "Activer WebSocket", - "enableWebsocketAria": "Activer WebSocket pour Codex Provider", - "enableSkills": "Activer Skills", - "enableSkillsAria": "Activer Skills pour Codex", - "enableFast": "Activer Fast", - "enableFastAria": "Activer le niveau de service Fast pour Codex", - "sandboxGroupTitle": "Bac à sable et approbations", - "sandboxGroupHint": "Écrit dans le ~/.codex/config.toml global, donc les sessions codex CLI et IDE en héritent aussi. Ce sont des valeurs par défaut du fil : elles régissent les tours que codex démarre lui-même (/goal, /review, /compact). Les messages ordinaires utilisent le préréglage d'approbation de la zone de saisie. Redémarrez une session pour appliquer les changements.", - "sandboxShadowedWarning": "config.toml définit default_permissions : codex résout les permissions via ce profil et ignore totalement sandbox_mode. Supprimez default_permissions pour utiliser les réglages ci-dessous.", - "sandboxPermissionsTableWarning": "config.toml définit des profils [permissions] sans default_permissions, ce qui empêche codex de démarrer. Renseignez-le dans l'éditeur brut ci-dessous.", - "approvalPolicyLabel": "Politique d'approbation", - "approvalPolicyUnset": "Non définie (défaut codex : à la demande)", - "approvalPolicy_on-request": "À la demande — le modèle décide quand demander", - "approvalPolicy_untrusted": "Non fiable — seules les commandes en lecture seule reconnues sûres s'exécutent sans validation", - "approvalPolicy_never": "Jamais — aucune demande d'approbation", - "approvalPolicy_granular": "Granulaire — au cas par cas selon le type", - "approvalPolicyUntrustedAcpWarning": "« Untrusted » n'a pas d'équivalent parmi les trois préréglages d'approbation de l'adaptateur ACP ; les sessions codeg retombent donc sur « à la demande » : le modèle décide alors quand demander, et les commandes que le bac à sable autorise déjà ne demandent plus rien. Restreignez plutôt le mode de bac à sable ci-dessous.", - "granularHint": "Désactivé signifie que ce type de demande est refusé automatiquement au lieu de vous être présenté.", - "granular_sandbox_approval": "Élévations pour commandes shell", - "granular_rules": "Invites des règles execpolicy", - "granular_skill_approval": "Invites des scripts de compétences", - "granular_request_permissions": "Invites de l'outil request_permissions", - "granular_mcp_elicitations": "Invites d'elicitation MCP", - "sandboxModeLabel": "Mode bac à sable", - "sandboxModeUnset": "Non défini (les dossiers de confiance retombent sur l'écriture dans l'espace de travail)", - "sandboxMode_read-only": "Lecture seule", - "sandboxMode_workspace-write": "Écriture dans l'espace de travail", - "sandboxMode_danger-full-access": "Accès complet (sans bac à sable)", - "sandboxModeHint": "Sous Windows, l'écriture dans l'espace de travail est rétrogradée en lecture seule sauf si le bac à sable Windows expérimental de codex est activé.", - "sandboxModeSeedsPresetHint": "codeg s'en sert aussi pour le préréglage d'approbation initial de la session : contrairement à la politique d'approbation, il agit donc sur les requêtes ordinaires. Le préréglage choisi dans la zone de saisie reste prioritaire.", - "writableRootsLabel": "Dossiers inscriptibles supplémentaires", - "writableRootsHint": "Un chemin absolu par ligne, en plus du répertoire de travail.", - "sandboxRootsRelativeError": "Doit être un chemin absolu — codex résout les chemins relatifs sous ~/.codex : {path}", - "networkAccessLabel": "Autoriser l'accès réseau", - "excludeTmpdirLabel": "Exclure TMPDIR des racines inscriptibles", - "excludeSlashTmpLabel": "Exclure /tmp des racines inscriptibles", - "authJsonNative": "auth.json (natif)", - "configTomlNative": "config.toml (natif)", - "loginButton": "Se connecter avec ChatGPT", - "loginRequesting": "Demande du code de connexion...", - "loginStep1": "Ouvrez l'URL suivante dans votre navigateur :", - "loginStep2": "Entrez le code ci-dessous :", - "loginPolling": "En attente d'autorisation...", - "loginCancel": "Annuler", - "loginSuccess": "Connexion réussie, configuration enregistrée !", - "loginFailed": "Échec de la connexion : {message}", - "loginRetry": "Réessayer", - "loginCodeCopied": "Code copié", - "loggedIn": "Compte connecté", - "loginRelogin": "Reconnecter / Changer de compte", - "loginTimeout": "Connexion expirée, veuillez réessayer", - "loginSaveFailed": "Connexion réussie mais échec de la sauvegarde de la configuration" - }, - "gemini": { - "authConfig": "Configuration d’authentification Gemini", - "authConfigDescription": "Alignée sur la documentation d’authentification Gemini CLI, avec prise en charge d’un endpoint personnalisé, connexion Google, Gemini API Key et Vertex AI (ADC / compte de service / API Key).", - "authMode": "Mode d’authentification", - "selectAuthMode": "Sélectionner un mode d’authentification", - "viewAuthDoc": "Voir la documentation d’authentification", - "mode": { - "custom": "Endpoint personnalisé", - "loginGoogle": "Connexion Google (OAuth)", - "vertexServiceAccount": "Vertex AI (Compte de service)" - }, - "hint": { - "custom": "Renseignez API URL, API Key et Model, mappés sur GOOGLE_GEMINI_BASE_URL / GEMINI_API_KEY / GEMINI_MODEL.", - "loginGoogle": "Exécutez d’abord gemini dans le terminal et terminez la connexion Google ; la clé API n’est pas requise.", - "geminiApiKey": "Renseignez GEMINI_API_KEY lors de l’utilisation de l’API Gemini.", - "vertexAdc": "Utilisez gcloud ADC ; GOOGLE_CLOUD_PROJECT et GOOGLE_CLOUD_LOCATION sont recommandés.", - "vertexServiceAccount": "Définissez le chemin JSON du compte de service dans GOOGLE_APPLICATION_CREDENTIALS.", - "vertexApiKey": "Renseignez GOOGLE_API_KEY lors de l’utilisation d’une clé API Vertex AI." - } - }, - "openCode": { - "configManagement": "Gestion de configuration OpenCode", - "configDescription": "Alignée sur le schéma `provider` d’OpenCode, prend en charge la gestion multi-provider et la synchronisation bidirectionnelle avec les fichiers JSON natifs.", - "providerManagement": "Gestion des providers", - "providerCount": "{count} fournisseurs", - "addProvider": "Ajouter un provider", - "emptyProvider": "Aucun fournisseur personnalisé pour le moment. Cliquez sur Ajouter un fournisseur personnalisé pour en créer un.", - "providerEnabledState": "État activé de {providerId}", - "selectProviderNpm": "Sélectionner provider.npm", - "modelManagement": "Gestion des modèles", - "modelCount": "{count} modèles", - "modelDescription": "Aligné sur `provider.models` d’OpenCode. La gestion rapide prend actuellement en charge `name` / `id` ; les autres champs avancés sont conservés et peuvent être modifiés dans le JSON natif ci-dessous.", - "addModel": "Ajouter un modèle", - "emptyModel": "Aucun modèle pour le moment. Saisissez model id puis cliquez sur « Ajouter un modèle ».", - "modelId": "ID du modèle", - "modelName": "Nom du modèle", - "deleteModel": "Supprimer le modèle {modelId}", - "nativeJsonConfig": "Configuration JSON native OpenCode", - "mainModel": "Modèle principal", - "smallModel": "Petit modèle", - "noMatchingModels": "Aucun modèle correspondant", - "connectProvider": "Connecter un fournisseur", - "connectedProviders": "Fournisseurs connectés", - "noConnectedProviders": "Aucun fournisseur du catalogue connecté pour le moment.", - "advancedProviderConfig": "Fournisseurs personnalisés", - "customProviderConfigHint": "Points de terminaison compatibles OpenAI que vous définissez vous-même — un bloc provider dans opencode.json, avec la clé API dans auth.json.", - "addCustomProvider": "Ajouter un fournisseur personnalisé", - "disconnect": "Déconnecter", - "editConfig": "Modifier", - "customBadge": "Personnalisé", - "authKindApi": "Clé API", - "authKindOauth": "OAuth", - "authKindNone": "Aucun identifiant", - "connect": { - "title": "Connecter un fournisseur", - "description": "Choisissez un fournisseur dans le catalogue models.dev. Les identifiants sont enregistrés dans le fichier auth.json d'OpenCode.", - "pick": "Fournisseur", - "search": "Rechercher des fournisseurs…", - "loading": "Chargement du catalogue…", - "catalogLabel": "Catalogue models.dev", - "modelsAvailable": "{count} modèles disponibles", - "getKey": "Obtenir la clé API", - "oauthApiKeyNote": "Ce fournisseur prend aussi en charge la connexion via navigateur avec opencode auth login. La connexion par navigateur arrive bientôt ; pour le moment, collez une clé API.", - "apiKey": "Clé API", - "apiKeyHint": "Enregistrée dans auth.json, jamais dans opencode.json.", - "baseUrlOptional": "Remplacer l''URL de base (facultatif)", - "providerId": "ID du fournisseur", - "displayName": "Nom affiché", - "modelsList": "Modèles (un par ligne)", - "modelsHint": "Identifiants de modèle acceptés par le point de terminaison.", - "action": "Connecter", - "editTitle": "Modifier le fournisseur", - "editDescription": "Mettez à jour la clé API ou l''URL de base de ce fournisseur.", - "saveAction": "Enregistrer" - }, - "customProvider": { - "title": "Ajouter un fournisseur personnalisé", - "description": "Définissez un point de terminaison compatible OpenAI. La clé API est enregistrée dans auth.json ; le bloc provider va dans opencode.json.", - "action": "Ajouter le fournisseur", - "idInCatalog": "{providerId} est un fournisseur connu — connectez-le plutôt via Connecter un fournisseur." - }, - "refreshCatalog": "Actualiser le catalogue", - "reasoningBadge": "raisonnement", - "contextWindow": "Fenêtre de contexte", - "permissions": { - "title": "Permissions", - "description": "Décidez quelles actions s’exécutent seules, lesquelles demandent votre accord et lesquelles sont bloquées. Écrit dans le bloc permission de opencode.json et appliqué à l’enregistrement ci-dessous.", - "docsLink": "Documentation des permissions", - "unparsableConfig": "Le JSON natif ci-dessous est invalide, l’éditeur visuel est donc en pause. Corrigez le JSON pour reprendre.", - "invalidBlock": "Le bloc permission a une forme que codeg ne reconnaît pas. Modifiez-le dans le JSON natif ci-dessous ou utilisez Réinitialiser pour repartir de zéro.", - "orderingUnsafe": "Une règle joker est écrite après des outils précis, donc OpenCode l’applique aussi à ceux-ci : les lignes ci-dessous ne sont pas ce qui s’applique réellement. Corriger l’ordre ramène simplement chaque joker en tête de sa portée, sans modifier la moindre valeur.", - "orderingUnsafeManual": "Une règle est masquée par un motif plus général placé après elle, donc OpenCode ne l’applique jamais : les lignes ci-dessous ne sont pas ce qui s’applique réellement. Deux motifs qui se chevauchent n’ont pas d’ordre unique correct ; réordonnez-les dans le JSON natif pour que le plus général vienne en premier.", - "fixOrder": "Corriger l’ordre", - "agentOverrides": "Ces agents redéfinissent les permissions et sont appliqués en dernier, ils l’emportent donc sur tout ce qui est ici : {agents}. Modifiez-les dans le JSON natif ci-dessous, ou activez l’acceptation automatique pour les effacer.", - "legacyTools": "L’ancienne table tools de premier niveau refuse un outil. OpenCode la fusionne avec les permissions, elle s’applique donc par-dessus tout ce qui est affiché ici. Modifiez-la dans le JSON natif ci-dessous, ou activez l’acceptation automatique pour l’effacer.", - "autoAcceptTitle": "Accepter automatiquement toutes les permissions", - "autoAcceptHint": "Chaque appel d’outil — commandes shell, modifications de fichiers, chemins hors du projet — s’exécute sans demander. L’activer remplace les réglages par outil ci-dessous par une seule règle tout-autoriser et efface les surcharges par agent ainsi que les anciens interrupteurs tools qui bloqueraient encore.", - "globalLabel": "Valeur globale par défaut", - "globalHint": "La règle * : elle s’applique à tout ce que les outils ci-dessous ne redéfinissent pas.", - "actionUnset": "Non défini (valeurs OpenCode)", - "actionInherit": "Hériter ({action})", - "actionAllow": "Autoriser", - "actionAsk": "Demander", - "actionDeny": "Refuser", - "perToolTitle": "Permissions par outil", - "reset": "Réinitialiser", - "ruleCount": "règles : {count}", - "rulesToggle": "Règles fines de {tool}", - "rulesHint": "Comparées à l’entrée de l’outil, la dernière correspondance l’emporte : placez donc les motifs larges en premier. * correspond à n’importe quels caractères, ? à exactement un, et un ~ initial désigne votre dossier personnel.", - "noRules": "Aucune règle fine pour l’instant.", - "addRule": "Ajouter une règle", - "deleteRule": "Supprimer la règle {pattern}", - "duplicateRule": "Ce motif existe déjà.", - "blankRule": "Une règle a besoin d’un motif — utilisez l’icône corbeille pour la supprimer.", - "customKeys": "Autres clés de permission du fichier", - "customKeyHint": "Ce n’est pas un outil intégré d’OpenCode — conservé tel quel.", - "keys": { - "bash": "Exécuter des commandes shell, selon la commande analysée", - "edit": "Toutes les modifications de fichiers : edit, write et patch", - "read": "Lire des fichiers, selon le chemin", - "external_directory": "Atteindre des chemins hors du répertoire de travail du projet", - "task": "Lancer des sous-agents, selon le type de sous-agent", - "skill": "Charger des skills, selon leur nom", - "glob": "Trouver des fichiers, selon le motif glob", - "grep": "Rechercher dans le contenu des fichiers, selon le motif", - "list": "Lister le contenu d’un répertoire", - "webfetch": "Récupérer une URL", - "websearch": "Rechercher sur le web", - "lsp": "Exécuter des requêtes LSP", - "todowrite": "Écrire la liste de tâches", - "question": "Vous poser une question", - "doom_loop": "Se déclenche quand le même appel se répète trois fois avec la même entrée" - } - } - }, - "openClaw": { - "gatewayConfig": "Configuration Gateway", - "gatewayDescription": "Configure la connexion OpenClaw Gateway. Prend en charge une gateway locale ou distante.", - "gatewayUrlHint": "Laisser vide pour utiliser gateway.remote.url depuis la configuration locale openclaw.", - "gatewayTokenPlaceholder": "Token d’authentification Gateway", - "gatewayTokenHint": "Utilisez token-file plutôt qu’un token en clair si possible ; configurez-le via le CLI openclaw.", - "sessionKeyHint": "Optionnel. Spécifie la session key de la gateway ; laisser vide pour auto-attribuer une session isolée." - }, - "hermes": { - "configManagement": "Configuration de Hermes", - "configDescription": "Hermes gère ses propres identifiants dans ~/.hermes/.env et ses paramètres dans ~/.hermes/config.yaml. Choisissez un fournisseur, puis définissez la clé d'API et le modèle — codeg écrit les deux fichiers pour vous.", - "providerLabel": "Fournisseur", - "providerHint": "Le fournisseur détermine quelle variable de clé d'API et quel model.provider Hermes utilise. Les fournisseurs OAuth se configurent via la configuration du terminal ci-dessous.", - "groupApiKey": "Fournisseurs avec clé API", - "groupOauth": "Fournisseurs OAuth", - "groupAws": "AWS", - "apiKeyHint": "Enregistrée dans ~/.hermes/.env. Elle n'est jamais injectée dans le processus — Hermes la lit depuis sa propre configuration.", - "modelName": "Modèle", - "oauthHint": "Ce fournisseur utilise OAuth. Exécutez la configuration ci-dessous pour vous authentifier dans votre terminal.", - "awsHint": "Bedrock utilise vos identifiants AWS (environnement ou configuration partagée). Définissez l'ID du modèle ci-dessus et configurez l'accès AWS dans votre environnement.", - "unsupportedProvider": "Ce fournisseur n'est pas modifiable via les champs structurés. Utilisez l'éditeur config.yaml ci-dessous ou la configuration par terminal.", - "setupTitle": "Configuration autogérée", - "setupHint": "La configuration interactive de Hermes nécessite un terminal. Lancez-la ci-dessous ou copiez la commande pour l'exécuter vous-même.", - "runSetup": "Exécuter la configuration de Hermes", - "configureModel": "Configurer le modèle", - "openConfigFolder": "Ouvrir ~/.hermes", - "copyCommand": "Copier la commande", - "commandCopied": "Commande copiée dans le presse-papiers", - "advancedTitle": "Avancé : modifier config.yaml", - "rawConfigHint": "Modifiez directement ~/.hermes/config.yaml. Enregistrer ici écrase le fichier tel quel.", - "saveRawConfig": "Enregistrer config.yaml" - }, - "codebuddy": { - "configManagement": "Configuration de CodeBuddy", - "configDescription": "CodeBuddy s'authentifie avec une clé API. Les versions pour la Chine continentale nécessitent aussi de définir l'environnement sur « Chine (internal) » ; les versions iOA utilisent « iOA ». La version internationale la laisse non définie.", - "apiKeyLabel": "Clé API", - "apiKeyHint": "Enregistré en tant que CODEBUDDY_API_KEY pour cet agent. Vous pouvez aussi vous connecter avec la CLI CodeBuddy dans un terminal.", - "apiKeyHintSelfHosted": "Enregistré en tant que CODEBUDDY_API_KEY pour cet agent. Utilisez la clé émise par votre déploiement privé.", - "environmentLabel": "Environnement", - "environmentHint": "Définit CODEBUDDY_INTERNET_ENVIRONMENT. La Chine continentale doit utiliser « Chine (internal) » ; la version internationale la laisse non définie.", - "envOverseas": "International (par défaut)", - "envChina": "Chine (internal)", - "envIoa": "iOA", - "envSelfHosted": "Auto-hébergé (déploiement privé)", - "baseUrlLabel": "URL de déploiement", - "baseUrlPlaceholder": "https://codebuddy.your-company.com", - "baseUrlHint": "Enregistré comme CODEBUDDY_BASE_URL et dirige CodeBuddy vers votre point de terminaison privé. En auto-hébergement, l’environnement réseau (CODEBUDDY_INTERNET_ENVIRONMENT) reste non défini.", - "baseUrlInvalid": "Saisissez une URL http(s) valide.", - "loginHint": "Pas de clé API ? Exécutez « codebuddy » dans un terminal pour vous connecter avec votre compte Tencent." - }, - "kimiCode": { - "configManagement": "Configuration de Kimi Code", - "configDescription": "`kimi acp` n'accepte qu'un jeton de connexion enregistré ; codeg écrit donc un fournisseur géré dans ~/.kimi-code/config.toml et dépose un jeton d'accès local — l'inférence utilise toujours votre propre clé.", - "statusUnconfigured": "Pas encore configuré", - "statusDirty": "Modifications non enregistrées", - "summaryLabel": "En vigueur", - "gateReadyApiKey": "Clé API écrite dans config.toml", - "gateReadyLogin": "Connecté avec un compte Kimi", - "revealConfig": "Afficher dans le dossier", - "envOverrideWarning": "{keys} est défini et prime sur config.toml. Enregistrer ici la supprime.", - "authModeLabel": "Méthode d'authentification", - "authModeApiKey": "Clé API", - "authModeLogin": "Connexion au compte Kimi (abonnement)", - "authModeApiKeyHint": "Écrit un fournisseur géré dans config.toml et dépose le jeton d'accès pour que les sessions puissent s'ouvrir.", - "loginHint": "Exécutez `kimi login` dans un terminal pour vous connecter avec un compte Kimi par abonnement. codeg ne stocke rien et réutilise la connexion de Kimi. Enregistrer ici supprime le jeton d'accès par clé API de codeg.", - "credentialTitle": "Identifiant", - "interfaceTypeLabel": "Type de fournisseur", - "interfaceTypeHint": "Le protocole de fournisseur que parle Kimi (le `type` de config.toml). Choisissez Kimi / Moonshot pour une clé Moonshot / platform.kimi.com.", - "endpointLabel": "Point de terminaison", - "endpointCustom": "Personnalisé (compatible OpenAI)", - "endpointHint": "International = api.moonshot.ai ; Chine (clés platform.kimi.com) = api.moonshot.cn. Personnalisé pointe vers n'importe quel point de terminaison compatible OpenAI.", - "regionInternational": "International (api.moonshot.ai)", - "regionChina": "Chine (api.moonshot.cn)", - "baseUrlLabel": "URL de base", - "baseUrlHint": "Laissez vide pour utiliser la valeur par défaut du SDK du fournisseur.", - "apiKeyLabel": "Clé API", - "apiKeyHint": "Écrite dans ~/.kimi-code/config.toml et utilisée pour l'inférence. Depuis platform.kimi.com ou platform.kimi.ai.", - "vertexProjectLabel": "Projet GCP (GOOGLE_CLOUD_PROJECT)", - "vertexLocationLabel": "Région GCP (GOOGLE_CLOUD_LOCATION)", - "vertexHint": "Vertex AI utilise les identifiants par défaut de l'application Google — exécutez `gcloud auth application-default login` (aucune clé API).", - "modelTitle": "Modèle", - "modelLabel": "Modèle", - "modelHint": "L'id du modèle écrit dans config.toml. Utilisez « Tester et lister les modèles » pour voir ce à quoi votre clé accède réellement.", - "maxContextLabel": "Taille de contexte maximale", - "maxContextHint": "Obligatoire selon le schéma de Kimi : sans elle, Kimi rejette tout le bloc du modèle et chaque requête reste sans réponse. Par défaut 262144.", - "fetchModels": "Tester et lister les modèles", - "fetchModelsOk": "La clé fonctionne — {count} modèles disponibles", - "fetchModelsEmpty": "La clé fonctionne, mais aucun modèle n'a été renvoyé", - "fetchModelsFailed": "Échec du test", - "fetchModelsNeedsKey": "Saisissez d'abord une clé API et un point de terminaison", - "modelNotInList": "Ce modèle ne figure pas dans la liste accessible à votre clé — Kimi échouera avec « modèle introuvable ».", - "reasoningTitle": "Raisonnement", - "reasoningEnableLabel": "Activer", - "reasoningDescription": "Kimi n'affiche le sélecteur « Thinking » dans la zone de saisie que si le modèle déclare une capacité de raisonnement ; codeg l'écrit donc ici. S'applique aux nouvelles sessions.", - "effortsLabel": "Niveaux proposés", - "effortsHint": "Ces niveaux deviennent les entrées du sélecteur « Thinking ». Kimi transmet le niveau au fournisseur tel quel : choisissez ceux que votre modèle accepte.", - "effortsEmptyHint": "Sans aucun niveau sélectionné, la zone de saisie se limite à un simple interrupteur Off / On.", - "effortsCustomPlaceholder": "Ajouter un autre niveau", - "effortsAdd": "Ajouter", - "defaultEffortLabel": "Niveau par défaut", - "defaultEffortAuto": "Laisser Kimi choisir", - "alwaysThinkingLabel": "Le modèle raisonne toujours — retirer l'entrée Off du sélecteur", - "fixErrorsFirst": "Corrigez d'abord les champs signalés", - "errorModelRequired": "Le modèle est obligatoire", - "errorMaxContextRequired": "La taille de contexte maximale est obligatoire", - "errorMaxContextInvalid": "Doit être un entier positif", - "errorApiKeyRequired": "La clé API est obligatoire", - "errorApiKeyInvalid": "La clé API ne doit pas contenir de sauts de ligne", - "errorBaseUrlRequired": "L'URL de base est obligatoire", - "errorBaseUrlInvalid": "Doit commencer par http:// ou https://", - "errorVertexProjectRequired": "Le projet GCP est obligatoire", - "errorDefaultEffortUnlisted": "Choisissez l'un des niveaux sélectionnés ci-dessus", - "advancedTitle": "Avancé", - "authTypeLabel": "Emplacement de l'identifiant", - "authTypeApiKey": "api_key en ligne", - "authTypeEnv": "Sous-table env du fournisseur", - "authTypeHint": "Où la clé API est écrite à l'intérieur de config.toml.", - "rawEditorLabel": "Modifier config.toml directement", - "rawEditorWarning": "Enregistrer ici écrase tout le fichier tel quel et remplace les réglages structurés ci-dessus.", - "rawEditorPlaceholder": "[providers.codeg]\ntype = \"kimi\"\nbase_url = \"https://api.moonshot.cn/v1\"\napi_key = \"sk-...\"" - }, - "authModeOfficialSubscription": "Abonnement officiel", - "authModeCustomEndpoint": "Endpoint personnalisé", - "authModeCustomEndpointHint": "Configurer manuellement l'URL API et la clé API pour un endpoint personnalisé.", - "authModeModelProvider": "Fournisseur de modèle", - "modelProvider": "Fournisseur de modèle", - "modelProviderHint": "Utiliser l'URL API, la clé API et le modèle d'un fournisseur de modèle configuré.", - "selectModelProvider": "Sélectionner un fournisseur de modèle", - "noModelProviderAvailable": "Aucun fournisseur de modèle configuré pour cet agent. Allez dans les paramètres des fournisseurs de modèle pour en ajouter un.", - "claude": { - "authMode": "Mode d’authentification", - "officialSubscription": "Abonnement officiel", - "officialSubscriptionHint": "Utiliser l'abonnement officiel Anthropic, pas de clé API requise.", - "mainModel": "Modèle principal", - "reasoningModel": "Modèle de raisonnement (thinking)", - "haikuDefaultModel": "Modèle Haiku par défaut", - "sonnetDefaultModel": "Modèle Sonnet par défaut", - "opusDefaultModel": "Modèle Opus par défaut", - "customModelOption": "ID de modèle personnalisé", - "customModelOptionName": "Nom du modèle personnalisé", - "customModelOptionDescription": "Description du modèle personnalisé", - "customModelOptionHint": "Ajoute une entrée personnalisée au sélecteur de modèles de Claude (par exemple un modèle derrière une passerelle/un proxy personnalisé). Le nom et la description sont des informations d'affichage facultatives.", - "effortLevel": "Niveau de raisonnement", - "effortLevelDefault": "Niveau par défaut", - "effortLevel_low": "Bas", - "effortLevel_medium": "Moyen", - "effortLevel_high": "Élevé", - "effortLevel_xhigh": "Très Élevé", - "sendAttributionHeader": "Envoyer l'identifiant d'attribution/facturation à l'API", - "sendAttributionHeaderAria": "Envoyer l'identifiant d'attribution/facturation de Claude Code à l'API", - "disableNonessentialTraffic": "Désactiver la télémétrie ou les requêtes réseau superflues", - "disableNonessentialTrafficAria": "Désactiver la télémétrie ou les requêtes réseau superflues de Claude Code" - }, - "dialogs": { - "confirmDeleteProvider": "Supprimer le provider {providerId} ?", - "confirmDeleteProviderDescription": "La configuration OpenCode et auth JSON seront mises à jour ensemble. Cette action est irréversible.", - "confirmUninstall": "Désinstaller {name} ?", - "confirmUninstallDescription": "Cela supprime la version installée localement. Vous pouvez réinstaller plus tard.", - "customInstallTitle": "Installation personnalisée de {name}", - "customInstallDescription": "Saisissez la version à installer. Cela réinstalle et remplace la version actuellement installée.", - "customInstallVersionLabel": "Numéro de version", - "customInstallInvalid": "Saisissez un numéro de version valide, par ex. 1.2.3.", - "customInstallSubmit": "Installer" - }, - "errors": { - "windowsFileLocked": "Les fichiers de {name} sont utilisés par une session en cours, Windows ne peut donc pas les remplacer. Fermez toutes les sessions {name}, puis réessayez.", - "nativeJsonMustBeObject": "La configuration JSON native doit être un objet", - "nativeJsonInvalid": "Erreur de format de configuration JSON native : {message}", - "openCodeAuthMustBeObject": "OpenCode auth.json doit être un objet JSON", - "openCodeAuthInvalid": "Erreur de format OpenCode auth.json : {message}", - "authMustBeObject": "auth.json doit être un objet JSON", - "authInvalid": "Erreur de format auth.json : {message}", - "providerIdPattern": "L’ID du provider n’accepte que lettres, chiffres, underscore, point et tiret", - "providerExists": "Le provider {providerId} existe déjà", - "modelIdPattern": "L’ID du modèle n’accepte que lettres, chiffres, underscore, point, deux-points et tiret", - "modelExists": "Le modèle {modelId} existe déjà" - }, - "warnings": { - "nativeJsonRecoveredStructured": "La configuration JSON native est invalide ; réinitialisée en configuration structurée", - "nativeJsonRecoveredOpenCode": "La configuration JSON native est invalide ; réinitialisée en configuration structurée OpenCode", - "openCodeAuthRecovered": "OpenCode auth.json est invalide ; réinitialisé en configuration par défaut", - "authRecoveredStructured": "auth.json est invalide ; réinitialisé en configuration structurée" - }, - "toasts": { - "agentActionCompleted": "{name} {action} terminé", - "agentActionFailed": "{name} {action} échoué", - "localVersion": "Version locale : {version}", - "installCompletedVersionLater": "Installation terminée, la version sera mise à jour à la prochaine vérification", - "uninstallCompleted": "Désinstallation de {name} terminée", - "uninstallFailed": "Échec de la désinstallation de {name}", - "localVersionRemoved": "Version locale supprimée", - "saveAgentOrderFailed": "Échec de l’enregistrement de l’ordre des agents", - "saveAgentSwitchFailed": "Échec de l’enregistrement du switch agent", - "saveEnvFailed": "Échec de l’enregistrement des variables d’environnement", - "grokSaved": "Configuration Grok enregistrée", - "saveGrokNativeFailed": "Échec de l'enregistrement de la configuration native Grok", - "saveGrokApiKeyFailed": "Paramètres enregistrés, mais la clé API n'a pas pu être enregistrée", - "cursorSaved": "Configuration Cursor enregistrée", - "saveCursorConfigFailed": "Échec de l'enregistrement de la configuration Cursor", - "codexSaved": "Configuration Codex enregistrée", - "saveCodexNativeFailed": "Échec de l’enregistrement de la configuration native Codex", - "geminiSaved": "Configuration Gemini enregistrée", - "saveGeminiFailed": "Échec de l’enregistrement de la configuration Gemini", - "providerDeleted": "Provider {providerId} supprimé", - "providerDeleteFailed": "Échec de suppression du provider {providerId}", - "providerSaved": "Provider {providerId} enregistré", - "saveProviderFailed": "Échec d’enregistrement du provider {providerId}", - "openCodeConfigSynced": "La configuration OpenCode et auth JSON ont été synchronisés.", - "openCodeSaved": "Configuration OpenCode enregistrée", - "saveOpenCodeFailed": "Échec de l’enregistrement de la configuration OpenCode", - "openClawSaved": "Configuration OpenClaw enregistrée", - "saveOpenClawFailed": "Échec de l’enregistrement de la configuration OpenClaw", - "configSaved": "Configuration enregistrée", - "configSavedHint": "Les sessions existantes doivent être rouvertes pour prendre effet", - "saveConfigManagementFailed": "Échec de l’enregistrement de la gestion de configuration", - "clineSaved": "Configuration Cline enregistrée", - "saveClineFailed": "Échec de l'enregistrement de la configuration Cline", - "hermesSaved": "Configuration Hermes enregistrée", - "saveHermesFailed": "Échec de l'enregistrement de la configuration Hermes", - "codeBuddySaved": "Configuration CodeBuddy enregistrée", - "saveCodeBuddyFailed": "Échec de l'enregistrement de la configuration CodeBuddy", - "kimiCodeSaved": "Configuration de Kimi Code enregistrée", - "saveKimiCodeFailed": "Échec de l'enregistrement de la configuration de Kimi Code", - "deepseekSaved": "Configuration DeepSeek enregistrée", - "saveDeepSeekFailed": "Échec de l'enregistrement de la configuration DeepSeek", - "modelProviderRequired": "Veuillez sélectionner un fournisseur de modèle avant d'enregistrer.", - "affectedRunningSessions": "{count, plural, one {# session active doit se reconnecter pour appliquer la modification} other {# sessions actives doivent se reconnecter pour appliquer la modification}}", - "providerConnected": "{providerId} connecté", - "connectFailed": "Échec de la connexion de {providerId}", - "providerDisconnected": "{providerId} déconnecté", - "disconnectFailed": "Échec de la déconnexion de {providerId}", - "catalogRefreshed": "Catalogue actualisé — {count} fournisseurs", - "catalogRefreshFailed": "Échec de l''actualisation du catalogue", - "piSaved": "Configuration Pi enregistrée", - "savePiFailed": "Échec de l'enregistrement de la config Pi", - "piRuntimeSaved": "Exécution Pi enregistrée", - "savePiRuntimeFailed": "Échec de l'enregistrement de l'exécution Pi", - "piBinaryInstalled": "pi installé", - "piBinaryInstallFailed": "Échec de l'installation de pi", - "piBinaryUninstalled": "pi désinstallé", - "piBinaryUninstallFailed": "Échec de la désinstallation de pi", - "savePiTrustFailed": "Échec de l'enregistrement de la confiance de l'espace de travail" - }, - "version": { - "statusLabel": "Statut de version", - "notInstalled": "Non installé", - "remoteLocal": "Distant : {remoteVersion} · Local : {localVersion}", - "localOnly": "Local : {localVersion}", - "localInstalled": "{versionText}. Installé.", - "platformUnsupported": "{versionText}. La plateforme actuelle ne prend pas en charge cet agent.", - "uvxNotReady": "{versionText}. Le runtime uv n'est pas installé — installez-le depuis la vérification uv ci-dessous pour utiliser cet agent.", - "clickInstall": "{versionText}. Cliquez sur Installer à droite.", - "localUnrecognized": "{versionText}. La version locale n’est pas comparable ; essayez une mise à niveau pour écraser l’installation.", - "upgradeAvailable": "{versionText}. Mise à niveau disponible.", - "remoteUnavailable": "{versionText}. La version distante est actuellement indisponible.", - "latest": "{versionText}. Déjà à jour." - }, - "adapter": { - "label": "Adaptateur ACP", - "badge": "Adaptateur ACP", - "badgeHint": "Pour cet agent, Codeg installe un paquet adaptateur ACP, pas la CLI de l'éditeur. Les deux sont indépendants et partagent la même configuration.", - "learnMore": "En savoir plus", - "missingWithNative": "Votre {nativeLabel} a été trouvée dans {nativePath}. Codeg pilote les agents via ACP, or cette CLI ne parle pas ACP : Codeg a donc besoin d'un paquet adaptateur distinct, {adapterPackage}, maintenu par le projet Agent Client Protocol (à l'origine Zed). Il embarque son propre runtime, ne modifie ni ne remplace jamais votre commande {nativeCmd}, et lit le même {configDir} — votre connexion et vos réglages sont conservés. Installez-le ci-dessous.", - "missing": "Codeg pilote les agents via ACP, or la {nativeLabel} ne parle pas ACP : Codeg a donc besoin d'un paquet adaptateur distinct, {adapterPackage}, maintenu par le projet Agent Client Protocol (à l'origine Zed). Il embarque son propre runtime, la CLI {nativeCmd} n'est donc pas un prérequis ; si vous l'avez déjà, les deux coexistent et partagent la connexion et les réglages de {configDir}. Installez-le ci-dessous.", - "readyWithNative": "L'adaptateur {adapterCmd} est installé : c'est lui que Codeg lance, pas votre {nativeCmd} situé dans {nativePath}. Ce sont des paquets distincts qui coexistent, et tous deux lisent {configDir} : connexion et réglages sont partagés.", - "ready": "L'adaptateur {adapterCmd} est installé : c'est lui que Codeg lance. Il embarque son propre runtime, la {nativeLabel} n'est donc pas nécessaire ; si vous l'installez plus tard, les deux coexistent et partagent {configDir}." - }, - "cline": { - "configDescription": "Configurez le fournisseur API et les identifiants Cline. Les paramètres sont enregistrés dans ~/.cline/data/." - }, - "opencodePlugins": { - "title": "Plugins OpenCode", - "declared": "Plugins déclarés", - "noPlugins": "Aucun plugin déclaré dans opencode.json", - "status": { - "installed": "Installé", - "missing": "Non installé" - }, - "installAll": "Installer tous les manquants", - "pinVersions": "Fixer les versions @latest", - "install": "Installer", - "uninstall": "Désinstaller", - "refresh": "Actualiser", - "success": "Tous les plugins ont été installés avec succès", - "failed": "L'opération du plugin a échoué" - }, - "pi": { - "configManagement": "Configuration de Pi", - "configDescription": "Pi s'authentifie via la clé API de votre fournisseur de modèle. La clé est écrite dans ~/.pi/agent/auth.json et le choix du modèle dans settings.json.", - "providerLabel": "Fournisseur", - "modelLabel": "Modèle", - "thinkingLabel": "Réflexion", - "thinking": { - "off": "Désactivé", - "low": "Faible", - "medium": "Moyen", - "high": "Élevé", - "minimal": "Minimal", - "xhigh": "Très élevé" - }, - "apiKeyLabel": "Clé API", - "apiKeyHint": "Enregistrée dans ~/.pi/agent/auth.json pour le fournisseur sélectionné.", - "apiKeySetPlaceholder": "•••••• (enregistrée — laisser vide pour conserver)", - "saveConfig": "Enregistrer la config Pi", - "providerModelRequired": "Le fournisseur et le modèle sont requis", - "runtimeTitle": "Exécution", - "runtimeDescription": "Choisissez quel binaire pi s'exécute. Utilisez celui par défaut ou pointez vers votre propre build de pi.", - "modeDefault": "pi par défaut", - "modeDefaultHint": "Utilise l'adaptateur pi-acp intégré avec le pi de votre PATH. Installer pi : npm install -g @earendil-works/pi-coding-agent", - "modeCustom": "pi personnalisé", - "modeCustomHint": "Exécutez votre propre build, installation ou wrapper de pi.", - "commandLabel": "Commande ou chemin pi", - "commandHint": "Un chemin absolu, un nom de commande dans le PATH, ou un script wrapper (par ex. ./pi-test.sh d'un monorepo).", - "commandNotFound": "Commande introuvable", - "validate": "Valider", - "advanced": "Avancé", - "configDirLabel": "Répertoire de config (PI_CODING_AGENT_DIR)", - "sessionDirLabel": "Répertoire des sessions (PI_CODING_AGENT_SESSION_DIR)", - "flagsHint": "pi-acp ne transmet pas les options pi personnalisées (--approve, -e, …) — encapsulez pi dans un script et pointez-y la commande.", - "customIncomplete": "Saisissez une commande pi pour enregistrer", - "saveRuntime": "Enregistrer l'exécution", - "providerPlaceholder": "Sélectionner un fournisseur", - "customProvider": "Fournisseur personnalisé…", - "providerIdLabel": "ID du fournisseur", - "apiProtocolLabel": "Protocole API", - "baseUrlLabel": "Point de terminaison API (Base URL)", - "customProviderHint": "Définit un fournisseur dans ~/.pi/agent/models.json vers votre point de terminaison. La plupart des serveurs auto-hébergés ou proxy utilisent openai-completions.", - "baseUrlRequired": "Le point de terminaison API (Base URL) est requis", - "binaryTitle": "binaire pi (pi-coding-agent)", - "binaryDescription": "pi-acp exécute ce binaire pi. Installez-le ici, ou faites pointer pi-acp vers votre propre build ci-dessous.", - "binaryInstalled": "Installé", - "binaryMissing": "Non installé", - "binaryChecking": "Vérification…", - "installBinary": "Installer pi", - "installing": "Installation…", - "recheck": "Revérifier", - "configDirSkillsNote": "Avec un répertoire de configuration personnalisé, les compétences, experts et outils bureautiques gérés dans les Paramètres ne s'appliquent pas à ce pi — gérez ses compétences directement dans ce dossier.", - "projectTrustTitle": "Confiance du projet", - "projectTrustDescription": "Dossiers depuis lesquels vous avez autorisé pi à charger des fichiers de projet. Un dossier de confiance permet aux .pi/extensions de ce dépôt d'exécuter du code au démarrage de pi, s'applique à tous les dossiers qu'il contient et sert aussi lorsque vous lancez pi dans un terminal.", - "projectTrustLoading": "Chargement…", - "projectTrustEmpty": "Aucun dossier n'a encore été décidé.", - "projectTrustTrusted": "Approuvé", - "projectTrustDenied": "Non approuvé", - "projectTrustRevoke": "Révoquer", - "reasoningTitle": "Raisonnement", - "reasoningEnableLabel": "Activer", - "reasoningDescription": "pi n'envoie un effort de raisonnement que pour un modèle qui le déclare — sur un modèle non déclaré, tous les niveaux sont ramenés à Off, si bien que le sélecteur du composeur revient en arrière dès qu'on y touche. Écrit dans l'entrée de ce modèle dans models.json.", - "levelsLabel": "Niveaux disponibles", - "levelsHint": "Ils deviennent les lignes du sélecteur de raisonnement du composeur. Choisissez ceux que votre endpoint accepte ; pi refuse tout niveau absent d'ici.", - "levelsEmptyError": "Choisissez au moins un niveau — sans aucun, pi retombe sur Off.", - "wireValuesTitle": "Avancé : valeurs envoyées au fournisseur", - "wireValuesHint": "Laissez vide pour envoyer le nom du niveau tel quel. Renseignez-le si votre endpoint attend autre chose — les backends façon Google veulent LOW / HIGH.", - "defaultLevelUnlisted": "Ce niveau n'est pas dans la liste ci-dessus — pi le ramènerait plus bas." - }, - "addCustomAgent": "Ajouter un agent personnalisé", - "addCustomAgentHint": "Enregistrez n'importe quel agent compatible ACP. Choisissez-en un dans le registre ACP public ou collez ses informations de registre.", - "customAgentFromRegistry": "Registre ACP", - "customAgentManual": "Manuel", - "customAgentSearchPlaceholder": "Rechercher des agents…", - "customAgentLoadingCatalog": "Chargement du registre ACP…", - "customAgentRetry": "Réessayer", - "customAgentNoResults": "Aucun agent correspondant", - "customAgentAdd": "Ajouter", - "customAgentAlreadyAdded": "Ajouté", - "customAgentUnsupportedPlatform": "Aucune version disponible pour cette plateforme", - "customAgentAdded": "{name} ajouté", - "customAgentIdLabel": "ID du registre", - "customAgentNameLabel": "Nom affiché", - "customAgentVersionLabel": "Version", - "customAgentSpecLabel": "Distribution (JSON)", - "customAgentSpecHint": "Même forme que l’objet distribution du registre ACP : canaux npx, uvx et binary, ou collez une entrée de registre complète. Pour npx/uvx, cmd est l’exécutable installé par le paquet — déduit du nom du paquet s’il est omis, à préciser donc quand ils diffèrent. binary est organisé par clé de plateforme (cette machine : {platform}) ; son cmd est le chemin de lancement dans l’archive et sha256 vérifie éventuellement le téléchargement.", - "customAgentTemplateLabel": "Modèles", - "customAgentKindLabel": "Lancer via", - "customAgentInvalidJson": "JSON invalide", - "customAgentNoDistribution": "Aucune distribution npx, uvx ou binary trouvée", - "customAgentCancel": "Annuler", - "customAgentSave": "Ajouter l'agent", - "customAgentSaveChanges": "Enregistrer les modifications", - "customAgentEdit": "Modifier l’agent", - "customAgentEditHint": "Modifiez le nom, l’icône, la distribution et les déclarations de skills. L’ID de l’agent ne peut pas être modifié.", - "customAgentEditNotFound": "Agent personnalisé {id} introuvable", - "customAgentSaved": "{name} enregistré", - "customAgentVersionProbeLabel": "Commande de version (facultatif)", - "customAgentVersionProbeHint": "Commande qui affiche la version installée localement. Laissée vide, codeg exécute la commande de l’agent avec --version.", - "customAgentRemove": "Supprimer l'agent", - "customAgentRemoveHint": "Supprime la définition de l'agent. Les conversations existantes conservent leur historique ; l'agent ne peut simplement plus être lancé.", - "customAgentIconLabel": "Icône (facultatif)", - "customAgentIconUpload": "Téléverser", - "customAgentIconReplace": "Remplacer", - "customAgentIconClear": "Retirer l'icône", - "customAgentIconHint": "Enregistrée avec l'agent, elle fonctionne donc hors ligne. Sans icône, une initiale colorée est utilisée.", - "customAgentSkillsLabel": "Skills (.agents/skills partagé)", - "customAgentSkillsHint": "Déclare que cet agent lit le magasin partagé .agents/skills (répertoires global et projet) et l'ajoute à toutes les matrices de compétences. Les compétences qui y sont liées sont visibles par tous les agents qui lisent ce magasin partagé.", - "customAgentSkillsDirLabel": "Répertoire de skills dédié", - "customAgentSkillsDirHint": "Chemin absolu du répertoire depuis lequel cet agent charge ses skills — son propre magasin, en plus du magasin partagé ou à sa place. ~ est remplacé par le répertoire personnel ; les skills liées y sont placées en premier.", - "customAgentMcpLabel": "Prise en charge de MCP", - "customAgentMcpHint": "Transmet le compagnon MCP intégré de codeg à cet agent au démarrage de la session — le canal derrière la délégation, le retour en direct et les outils de tâches. Désactivez-le pour un agent qui refuse les serveurs MCP et ne parvient pas à se connecter ; le changement s'applique à la prochaine connexion.", - "customAgentIconNotAnImage": "Choisissez un fichier image.", - "customAgentIconTooLarge": "L'icône doit faire moins de {limit} Ko.", - "customAgentIconReadFailed": "Impossible de lire cette image.", - "customAgentRemoveConfirm": "Supprimer {name} ? Les conversations existantes sont conservées, mais l'agent ne pourra plus être lancé.", - "customAgentRemoveWithData": "Supprimer aussi l'historique de conversation enregistré", - "customAgentRemoved": "{name} supprimé", - "customAgentBadge": "Personnalisé", - "customAgentNotLaunchable": "Cet agent ne peut pas démarrer ici : {reason}" - }, - "SettingsPages": { - "agentsLoading": "Chargement des paramètres des agents...", - "skillPacksLoading": "Chargement des packs de compétences…" - }, - "GeneralSettings": { - "loading": "Chargement...", - "sectionTitle": "Général", - "sectionDescription": "Préférences centralisées pour le terminal par défaut, l'accélération du rendu et la délégation multi-agents.", - "terminalTitle": "Terminal par défaut", - "terminalDescription": "Choisissez le shell utilisé à l'ouverture de nouveaux onglets de terminal depuis la barre de terminal ou l'arborescence des fichiers. Les agents l'utilisent aussi lorsqu'ils demandent à codeg d'exécuter une ligne de commande complète.", - "terminalSystemDefault": "Par défaut système", - "terminalPowerShell7": "PowerShell 7 (pwsh)", - "terminalWindowsPowerShell": "Windows PowerShell", - "terminalCmd": "Invite de commandes (cmd)", - "terminalSaveFailed": "Échec de l’enregistrement des paramètres du terminal : {message}", - "terminalShellCustom": "Chemin personnalisé", - "terminalShellCustomPath": "Chemin du shell", - "terminalShellCustomPlaceholder": "/usr/local/bin/fish", - "terminalShellCustomSave": "Enregistrer", - "terminalShellCustomHint": "Indiquez un chemin absolu ou un nom résolvable via PATH.", - "terminalShellNotInstalled": "non installé", - "terminalShellNotFoundWarning": "Ce chemin n’existe pas sur cet hôte.", - "terminalCurrentShell": "Actuellement utilisé : {path}", - "renderingDescription": "Désactivez l’accélération matérielle si l’application affiche un écran noir ou des défauts de rendu (fréquent sur certaines GPU AMD ou GPU Intel intégrées). N’a d’effet que sur la version Windows de bureau.", - "disableHardwareAcceleration": "Désactiver l’accélération matérielle", - "renderingSaveFailed": "Échec de l’enregistrement des paramètres de rendu : {message}", - "restartRequired": "Enregistré. Redémarrez l’application pour appliquer la modification.", - "restartNow": "Redémarrer maintenant", - "restartFailed": "Échec du redémarrage : {message}", - "loadFailed": "Échec du chargement : {message}" - }, - "LoginPage": { - "documentTitle": "Connexion - codeg", - "brand": "Codeg", - "subtitle": "Saisissez votre jeton d'accès pour vous connecter à l'application de bureau", - "tokenPlaceholder": "Jeton d'accès", - "connect": "Se connecter", - "connecting": "Connexion...", - "helpText": "Vous trouverez votre jeton dans l'application de bureau sous Paramètres → Service Web", - "invalidToken": "Jeton invalide. Veuillez vérifier et réessayer.", - "connectionFailed": "Échec de la connexion (HTTP {status})", - "networkError": "Impossible de se connecter au serveur" - }, - "CommitPage": { - "title": "Valider", - "invalidFolderId": "ID de dossier invalide", - "loadingRepo": "Chargement du dépôt..." - }, - "MergePage": { - "title": "Résoudre les conflits", - "invalidFolderId": "ID de dossier invalide", - "loadingRepo": "Chargement du dépôt...", - "localVersion": "Local (Le nôtre)", - "result": "Résultat", - "remoteVersion": "Distant (Le leur)", - "acceptLocal": "Accepter le local", - "acceptRemote": "Accepter le distant", - "markResolved": "Marquer comme résolu", - "abortMerge": "Abandonner", - "completeMerge": "Terminer la fusion", - "unresolvedConflicts": "Il reste des marqueurs de conflit non résolus dans ce fichier", - "fileResolved": "Fichier résolu avec succès", - "allResolved": "Tous les conflits sont résolus", - "conflictFiles": "Fichiers en conflit", - "loadingFile": "Chargement du fichier...", - "preparingMerge": "Préparation de la fusion...", - "selectFile": "Sélectionner un fichier à résoudre", - "noConflicts": "Aucun fichier en conflit", - "skipFile": "Passer", - "abortSuccess": "Opération abandonnée", - "applyAllNonConflicting": "Appliquer tous les changements non conflictuels", - "applyLeftNonConflicting": "Appliquer local", - "applyRightNonConflicting": "Appliquer distant" - }, - "ImportSessions": { - "title": "Importer les sessions locales", - "scanningTitle": "Analyse des sessions locales des agents…", - "scanningHint": "Parcours du stockage local des sessions de chaque agent. Cela peut prendre un moment avec de gros historiques. Les sessions déjà importées sont actualisées au passage.", - "scanFailed": "Échec de l'analyse", - "retry": "Réessayer", - "rescan": "Réanalyser", - "empty": "Aucune session locale trouvée", - "emptyHint": "Aucun stockage de sessions d'agent n'a été trouvé sur cette machine.", - "noMatches": "Aucune session ne correspond aux filtres actuels", - "searchPlaceholder": "Rechercher un titre ou un chemin…", - "allAgents": "Tous les agents", - "onlyImportable": "Importables uniquement", - "selectAll": "Tout sélectionner", - "clearSelection": "Effacer", - "expandAll": "Tout développer", - "collapseAll": "Tout réduire", - "summaryCounts": "{total} sessions · {importable} importables · {folders} dossiers", - "noFolderSkipped": "{count} sans dossier de projet ignorées", - "folderNew": "Nouveau", - "folderCounts": "{importable}/{total} importables", - "toggleFolderAria": "Sélectionner toutes les sessions importables de {name}", - "toggleSessionAria": "Sélectionner la session {title}", - "statusImported": "Importée", - "statusDeleted": "Supprimée", - "untitled": "Session sans titre", - "messageCount": "{count} messages", - "selectedCount": "{count} sélectionnées", - "importSelected": "Importer la sélection", - "importing": "Importation…", - "close": "Fermer", - "doneTitle": "Importation terminée", - "doneImported": "Importées", - "doneUpdated": "Actualisées", - "doneSkipped": "Ignorées", - "doneCreatedFolders": "Dossiers créés", - "doneNotFound": "Introuvables", - "doneFailed": "Échouées", - "continueImport": "Continuer l'import", - "toasts": { - "importFailed": "Échec de l'import : {message}" - } - }, - "Folder": { - "workspaceStatus": { - "degradedTitle": "Mises à jour en temps réel indisponibles", - "degradedHint": "L’observateur n’a pas pu démarrer (par ex. permission refusée). Actualisez manuellement pour voir les modifications.", - "retry": "Réessayer", - "retrying": "Nouvelle tentative..." - }, - "common": { - "all": "Tout", - "cancel": "Annuler", - "close": "Fermer", - "closeOthers": "Fermer les autres", - "closeAll": "Tout fermer", - "confirm": "Confirmer", - "save": "Enregistrer", - "delete": "Supprimer", - "rename": "Renommer", - "loading": "Chargement...", - "refresh": "Actualiser", - "refreshing": "Actualisation...", - "create": "Créer", - "createAndSwitch": "Créer et basculer", - "openFile": "Ouvrir le fichier", - "viewDiff": "Voir le Diff", - "push": "Pousser..." - }, - "statusLabels": { - "in_progress": "En cours", - "pending_review": "Revue", - "completed": "Terminé", - "cancelled": "Annulé" - }, - "sidebar": { - "title": "Discussions", - "locateActiveConversation": "Localiser la conversation active", - "expandAllGroups": "Développer tous les groupes", - "collapseAllGroups": "Réduire tous les groupes", - "newConversation": "Nouvelle conversation", - "newConversationShort": "Nouvelle", - "newChat": "Nouvelle conversation", - "search": "Rechercher", - "noConversationsFound": "Aucune conversation trouvée.", - "importLocalSessions": "Importer les sessions locales", - "importing": "Import en cours...", - "error": "Erreur : {message}", - "completeAllSessions": "Terminer toutes les sessions", - "completeAllReviewTitle": "Terminer toutes les sessions en revue ?", - "completeAllReviewDescription": "Cela marquera comme terminées toutes les {count, plural, one {# session} other {# sessions}} en Revue.", - "completing": "Finalisation...", - "toasts": { - "importedSessions": "{imported, plural, one {# session} other {# sessions}} importée(s), {skipped} ignorée(s)", - "importedAndUpdated": "{imported, plural, one {# session} other {# sessions}} importée(s), {updated, plural, one {# titre} other {# titres}} mis à jour, {skipped} ignorée(s)", - "updatedTitles": "{updated, plural, one {# titre} other {# titres}} mis à jour, {skipped} ignorée(s)", - "noNewSessionsFound": "Aucune nouvelle session trouvée ({skipped} ignorée(s))", - "importFailed": "Échec de l'import : {message}", - "reviewCompleted": "{count, plural, one {# session en revue} other {# sessions en revue}} marquée(s) comme terminée(s)", - "completeReviewFailed": "Échec de la finalisation des sessions en revue : {message}", - "folderOpened": "Dossier {name} ouvert", - "folderRemoved": "Dossier {name} retiré", - "openFolderFailed": "Échec de l'ouverture du dossier", - "removeFolderFailed": "Échec de la suppression du dossier : {message}", - "reorderFoldersFailed": "Échec du réordonnancement des dossiers : {message}", - "changeFolderColorFailed": "Échec du changement de couleur : {message}", - "setFolderAliasFailed": "Échec de la définition de l'alias : {message}", - "changeFolderDefaultAgentFailed": "Échec de la définition de l'agent par défaut : {message}" - }, - "statsLabel": "{folders} dossiers · {convos} conversations", - "reorderHandle": "Glisser pour réorganiser", - "openFolder": "Ouvrir le dossier", - "searchPlaceholder": "Rechercher des conversations...", - "viewOptions": "Options d'affichage", - "showCompleted": "Afficher les conversations terminées", - "showWorktrees": "Afficher les dossiers de worktree", - "showRecent": "Afficher le groupe Récents", - "moreOptions": "Plus d'options", - "sortBy": "Trier par", - "sortByCreatedAt": "Date de création", - "sortByUpdatedAt": "Date de mise à jour", - "sectionOrder": "Ordre des sections", - "sectionOrderMoveUp": "Monter", - "sectionOrderMoveDown": "Descendre", - "sectionOrderItemLabel": "{name} — position {position} sur {total}", - "statusRunningBadge": "En cours", - "runningCountBadge": "{count, plural, one {# session en cours} other {# sessions en cours}}", - "statusCancelledBadge": "Annulé", - "worktreeRemovedBadge": "Worktree d'origine supprimé", - "conversationCountUnit": "{count, plural, one {# conversation} other {# conversations}}", - "emptyFolderHint": "Aucune conversation", - "noMatchingConversations": "Aucune conversation correspondante", - "noUnfinishedConversations": "Aucune conversation en cours. Activez « Afficher les terminées » dans le menu en haut à droite.", - "removeFolderConfirmTitle": "Retirer le dossier de l'espace de travail ?", - "removeFolderConfirmDescription": "Retirer \"{name}\" de l'espace de travail ? Les onglets et terminaux associés seront fermés.", - "folderHeaderMenu": { - "manageConversations": "Gérer les conversations…", - "manageLinks": "Dossiers liés", - "changeColor": "Changer la couleur", - "useThemeColor": "Utiliser le thème de l'app", - "setDefaultAgent": "Définir l'agent par défaut", - "defaultAgentNone": "Aucun (utiliser la valeur globale)", - "agentUnavailableSuffix": "(indisponible)", - "loadingAgents": "Chargement des agents…", - "setAlias": "Définir un alias…", - "setAliasTitle": "Définir l'alias du dossier", - "setAliasPlaceholder": "Saisir un alias (laisser vide pour effacer)", - "setAliasSave": "Enregistrer", - "setAliasCancel": "Annuler", - "removeFromWorkspace": "Retirer de l'espace de travail" - }, - "manageConversations": { - "title": "Gérer les conversations", - "searchPlaceholder": "Rechercher par titre…", - "agentFilterAll": "Tous les agents", - "statusFilterAll": "Tous les statuts", - "folderFilterAll": "Tous les dossiers", - "branchFilterAll": "Toutes les branches", - "branchNone": "Aucune branche", - "branchSearchPlaceholder": "Rechercher des branches…", - "noMatchingBranches": "Aucune branche correspondante", - "selectAllVisible": "Tout sélectionner", - "deselectAll": "Tout désélectionner", - "selectedCount": "{count} sélectionnée(s)", - "matchedCount": "{count} correspondance(s)", - "untitledConversation": "Conversation sans titre", - "setStatus": "Définir le statut…", - "deleteSelected": "Supprimer", - "noConversations": "Aucune conversation dans ce dossier.", - "noConversationsWorkspace": "Aucune conversation dans l'espace de travail.", - "noMatchingConversations": "Aucune conversation ne correspond aux filtres.", - "confirmDeleteTitle": "Supprimer {count} conversation(s) ?", - "confirmDeleteDescription": "Cette action est irréversible.", - "toastDeleted": "{count} conversation(s) supprimée(s)", - "toastStatusUpdated": "Statut mis à jour pour {count} conversation(s)", - "toastOpFailed": "Échec de l'opération : {message}" - }, - "sectionPinned": "Épinglées", - "sectionFolders": "Dossiers", - "sectionChats": "Discussion", - "sectionRecent": "Récents", - "noChats": "Aucune discussion", - "noRecent": "Aucune conversation récente", - "showMoreRecent": "Afficher plus ({count})", - "noFolders": "Aucun dossier ouvert", - "newChatAction": "Nouvelle discussion", - "automations": "Automatisations", - "tasks": "Tâches à faire", - "loadingSubsessions": "Chargement des sous-conversations…" - }, - "conversation": { - "reloadFailed": "Échec du rechargement de la conversation : {message}", - "reloaded": "Conversation rechargée", - "reload": "Recharger", - "activeConversationIndicator": "Conversation active", - "newConversation": "Nouvelle conversation", - "closeConversation": "Fermer la conversation", - "copyText": "Copier le texte", - "copyTextSuccess": "Copié", - "copyTextFailed": "Échec de la copie", - "forkSession": "Dupliquer la session", - "forkSessionSuccess": "Session dupliquée avec succès", - "forkSessionFailed": "Échec de la duplication de la session : {error}", - "exportConversation": "Exporter la conversation", - "exportImage": "Image", - "exportMarkdown": "Markdown", - "exportHtml": "HTML", - "exportSuccess": "Conversation exportée", - "exportFailed": "Échec de l'exportation", - "exportImageTooLong": "La conversation est trop longue pour être exportée en image", - "exportLabels": { - "untitledConversation": "Conversation sans titre", - "agent": "Agent", - "model": "Modèle", - "status": "Statut", - "started": "Début", - "updated": "Mis à jour", - "tokens": "Statistiques de tokens", - "duration": "Durée", - "inputTokens": "Entrée", - "outputTokens": "Sortie", - "cacheRead": "Cache lu", - "cacheWrite": "Cache écrit", - "user": "Utilisateur", - "assistant": "Assistant", - "system": "Système", - "toolResult": "Résultat", - "toolError": "Erreur" - }, - "moreActions": "Plus d’actions" - }, - "sessionDetails": { - "menuLabel": "Détails de la session", - "noActiveSession": "Aucune session active", - "title": "Détails de la session", - "subtitle": "Métadonnées de la session et utilisation des tokens", - "fieldTitle": "Titre", - "untitled": "Conversation sans titre", - "sessionId": "ID de session", - "externalId": "ID d'extension", - "agent": "Agent", - "model": "Modèle", - "status": "Statut", - "gitBranch": "Branche Git", - "parentId": "Session parente", - "tokensHeading": "Utilisation des tokens", - "totalTokens": "Total", - "inputTokens": "Entrée", - "outputTokens": "Sortie", - "cacheWrite": "Cache écrit", - "cacheRead": "Cache lu", - "contextWindow": "Fenêtre de contexte", - "duration": "Durée", - "loadingStats": "Chargement de l'utilisation des tokens…", - "loadFailed": "Échec du chargement de l'utilisation des tokens", - "noStats": "Aucune utilisation enregistrée", - "timestampsHeading": "Horodatage", - "createdAt": "Créé", - "updatedAt": "Mis à jour", - "none": "—", - "copyField": "Copier {field}", - "copiedField": "{field} copié" - }, - "conversationCard": { - "untitledConversation": "Conversation sans titre", - "newConversation": "Nouvelle conversation", - "rename": "Renommer", - "status": "Statut", - "delete": "Supprimer", - "importLocalSessions": "Importer les sessions locales", - "importing": "Import en cours...", - "renameConversation": "Renommer la conversation", - "deleteConversationTitle": "Supprimer la conversation ?", - "deleteConversationDescription": "Cela supprimera \"{title}\". Cette action est irréversible.", - "cancel": "Annuler", - "save": "Enregistrer", - "pin": "Épingler", - "unpin": "Désépingler", - "markCompleted": "Marquer comme terminé", - "reopen": "Rouvrir", - "expandSubsessions": "Développer les sous-conversations", - "collapseSubsessions": "Réduire les sous-conversations" - }, - "search": { - "dialogTitle": "Rechercher", - "dialogTitleWithFolder": "Rechercher — {name}", - "tabConversations": "Conversations", - "tabFiles": "Fichiers", - "placeholder": "Rechercher des conversations...", - "filePlaceholder": "Rechercher des fichiers ou répertoires...", - "allAgents": "Tout", - "searching": "Recherche...", - "typeToSearch": "Tapez pour rechercher des conversations", - "typeToSearchFiles": "Tapez pour rechercher des fichiers ou répertoires", - "noResults": "Aucun résultat trouvé.", - "untitledConversation": "Conversation sans titre" - }, - "folderTitleBar": { - "showSidebar": "Afficher la barre latérale", - "hideSidebar": "Masquer la barre latérale", - "toggleTerminal": "Basculer le terminal", - "toggleAuxPanel": "Basculer le panneau auxiliaire", - "search": "Rechercher", - "openSettings": "Ouvrir les paramètres", - "backToConversations": "Retour aux conversations", - "withShortcut": "{label} (raccourci : {shortcut})" - }, - "statusBar": { - "connection": { - "connected": "Connecté", - "connecting": "Connexion...", - "prompting": "Réponse...", - "error": "Erreur de connexion", - "disconnected": "Déconnecté", - "tooltip": "{agent} : {status}", - "tooltipError": "{agent} : {error}", - "title": "Connexion de l'agent", - "triggerAria": "Connexion de l'agent : {status}", - "workingDir": "Répertoire de travail", - "sessionId": "ID de session", - "viewerNote": "Rattaché à une session appartenant à un autre client : la reconnexion ne rattache que cette vue.", - "reconnectInterrupts": "La reconnexion redémarre l'agent et interrompt le travail en cours.", - "reconnect": "Reconnecter", - "reconnecting": "Reconnexion...", - "reconnectUnavailable": "Aucune session à laquelle se reconnecter pour l'instant." - }, - "tasks": { - "title": "Tâches" - }, - "alerts": { - "title": "Alertes", - "empty": "Aucune alerte", - "details": "Détails" - }, - "stats": { - "conversations": "{count} discussions", - "openUsage": "Voir les statistiques de sessions et l'usage de tokens" - }, - "tokens": { - "contextWindowUsageAria": "Utilisation de la fenêtre de contexte", - "contextWindow": "Fenêtre de contexte", - "usedMax": "Utilisé / Max", - "tokenUsage": "Utilisation des tokens", - "input": "Entrée", - "output": "Sortie", - "cacheRead": "Lecture cache", - "cacheWrite": "Écriture cache", - "total": "Total des tokens" - } - }, - "auxPanel": { - "tabs": { - "files": "Fichiers", - "changes": "Changements", - "commits": "Validations" - }, - "noFolderTitle": "Aucun dossier ouvert", - "noFolderHint": "Ouvrez un dossier pour voir son contenu ici" - }, - "windowControls": { - "minimizeWindow": "Minimiser la fenêtre", - "minimize": "Minimiser", - "maximizeWindow": "Maximiser la fenêtre", - "maximize": "Maximiser", - "restoreWindow": "Restaurer la fenêtre", - "restore": "Restaurer", - "closeWindow": "Fermer la fenêtre", - "close": "Fermer" - }, - "tabs": { - "closeConversationTab": "Fermer l’onglet de conversation", - "close": "Fermer", - "closeOthers": "Fermer les autres", - "splitRight": "Diviser à droite", - "splitDown": "Diviser en bas", - "splitAndMoveRight": "Diviser et déplacer à droite", - "splitAndMoveDown": "Diviser et déplacer en bas", - "moveToOppositeGroup": "Déplacer vers le groupe opposé", - "moveToGroup": "Déplacer vers le groupe", - "groupLabel": "Groupe {index}", - "changeSplitterOrientation": "Changer l'orientation du séparateur", - "unsplit": "Annuler la division", - "unsplitAll": "Annuler toutes les divisions", - "closeAll": "Tout fermer", - "tileDisplay": "Affichage en mosaïque", - "untileDisplay": "Quitter la mosaïque" - }, - "fileWorkspace": { - "files": "Fichiers", - "closeFileTab": "Fermer l’onglet fichier", - "close": "Fermer", - "closeOthers": "Fermer les autres", - "closeAll": "Tout fermer", - "preview": "Aperçu", - "editSource": "Modifier la source", - "maximize": "Agrandir", - "restore": "Restaurer", - "emptyDirectory": "Dossier vide" - }, - "terminal": { - "rename": "Renommer", - "close": "Fermer", - "closeOthers": "Fermer les autres", - "closeAll": "Tout fermer", - "hideTerminal": "Masquer le terminal ({shortcut})", - "openFolderFirst": "Ouvrez d'abord un dossier" - }, - "workspaceDialog": { - "title": "Ouvrir un dossier", - "manageTitle": "Dossiers liés", - "addTargetsTitle": "Ajouter des dossiers à lier", - "pickRootDescription": "Choisissez le dossier principal de cet espace de travail.", - "linksDescription": "Liez d'autres dossiers en sous-répertoires pour que les agents travaillent sur tous depuis un seul espace de travail.", - "addTargetsDescription": "Sélectionnez un ou plusieurs dossiers. Chacun devient un sous-répertoire de l'espace de travail.", - "useSystemPicker": "Sélecteur système", - "next": "Suivant", - "back": "Retour", - "done": "Terminé", - "change": "Modifier", - "addFolders": "Ajouter des dossiers", - "addSelected": "Ajouter", - "addSelectedCount": "Ajouter {count}", - "createCount": "Lier {count} dossier(s)", - "discardPending": "Abandonner", - "noLinks": "Aucun dossier lié pour l'instant.", - "gitExclude": "Garder les liens hors du statut git", - "rename": "Renommer", - "unlink": "Supprimer le lien", - "repair": "Recréer le lien", - "saveName": "Enregistrer", - "cancelRename": "Annuler", - "removePending": "Retirer", - "willAppearAs": "Apparaît sous le nom {name} dans l'espace de travail", - "renamedForDuplicate": "Renommé — {base} est déjà utilisé par un autre lien", - "renamedForExistingEntry": "Renommé — {base} existe déjà dans ce dossier", - "partiallyCreated": "Seuls {count} dossier(s) ont pu être liés", - "openFailed": "Impossible d'ouvrir le dossier", - "previewFailed": "Impossible de vérifier les dossiers sélectionnés", - "createFailed": "Impossible de lier les dossiers", - "renameFailed": "Impossible de renommer le lien", - "removeFailed": "Impossible de supprimer le lien", - "repairFailed": "Impossible de recréer le lien", - "status": { - "ok": "Lié", - "missing": "Le lien a disparu de ce dossier", - "conflicted": "Une autre entrée utilise désormais ce nom", - "broken": "Le dossier lié n'existe plus" - }, - "nameIssue": { - "empty": "Saisissez un nom", - "illegalChars": "Ne peut pas contenir / \\ : * ? \" < > |", - "tooLong": "Nom trop long", - "reserved": "Ce nom est réservé par Windows", - "duplicate": "Ce nom est déjà utilisé" - }, - "rejection": { - "not_found": "Dossier introuvable", - "not_a_directory": "Ce chemin n'est pas un dossier", - "same_as_root": "C'est le dossier de l'espace de travail lui-même", - "ancestor_of_root": "Ce dossier contient l'espace de travail", - "inside_root": "Déjà dans l'espace de travail", - "already_linked": "Déjà lié", - "name_unavailable": "Plus aucun nom disponible pour ce dossier", - "alreadyLinkedAs": "Déjà lié sous le nom {name}" - } - }, - "folderNameDropdown": { - "fallbackFolderName": "Dossier", - "openFolder": "Ouvrir le dossier", - "cloneRepository": "Cloner le dépôt", - "projectBoot": "Lanceur de projet", - "opened": "Ouvert", - "recentOpen": "Ouvert récemment" - }, - "fileWorkspacePanel": { - "addSelectionToChat": "Ajouter la sélection au chat", - "addToChat": "Ajouter au chat", - "addSelectionToChatDone": "{label} ajouté à la conversation", - "addFileToChat": "Ajouter le fichier au chat", - "toggleWordWrap": "Basculer le retour à la ligne", - "addFileToChatDone": "{label} ajouté à la conversation", - "viewDiff": "Voir le Diff", - "openFile": "Ouvrir le fichier", - "fileCount": "{count, plural, one {# fichier} other {# fichiers}}", - "openFileOrDiff": "Ouvrez un fichier ou un diff depuis le panneau de droite", - "disk": "Disque", - "head": "HEAD", - "unsaved": "Non enregistré", - "workingTree": "Arbre de travail", - "loading": "Chargement...", - "compareWithBranch": "{path} · comparer avec {branch}", - "hunkCount": "{count, plural, one {# bloc} other {# blocs}}", - "prev": "Précédent", - "next": "Suivant", - "jumpToLine": "Aller à la ligne {line}", - "noParsedDiffSections": "Aucune section de diff analysée", - "loadingEditor": "Chargement de l’éditeur...", - "imageZoomIn": "Agrandir", - "imageZoomOut": "Réduire", - "imageZoomReset": "Réinitialiser le zoom", - "htmlPreviewTitle": "Aperçu HTML", - "htmlPreviewTrust": "Activer les scripts", - "htmlPreviewTrustHint": "Exécuter les scripts de ce fichier et autoriser l'accès réseau. À activer uniquement pour les fichiers de confiance.", - "officePreviewTitle": "Aperçu du document Office", - "officeFullRender": "Rendu complet", - "officeFullRenderHint": "Affiche les animations Morph, la 3D et les formules (exécute les scripts de la diapositive)", - "officeNotInstalled": "OfficeCLI n'est pas installé", - "officeNotInstalledHint": "Installe OfficeCLI dans Paramètres → Outils Office pour prévisualiser les fichiers Word, Excel et PowerPoint.", - "officeOpenSettings": "Ouvrir les paramètres", - "officeWatchFailed": "Impossible de démarrer l'aperçu en direct", - "officeWatchRetry": "Réessayer", - "officeServerInstallHint": "OfficeCLI doit être installé sur l'hôte du serveur. Exécutez cette commande là-bas, puis réessayez :", - "officeRemoteDesktopUnsupported": "L'aperçu en direct n'est pas disponible dans une fenêtre de bureau à distance. Ouvrez cet espace de travail dans l'interface web du serveur pour prévisualiser les fichiers Office." - }, - "branchDropdown": { - "toasts": { - "commitCodeCompleted": "Commit de code terminé", - "pushCodeCompleted": "Push de code terminé", - "committedFiles": "{count, plural, one {# fichier commit} other {# fichiers commit}}", - "taskCompleted": "{label} terminé", - "taskFailed": "{label} échoué", - "mergeNoNewCommits": "{branchName} n’a pas de nouveaux commits", - "mergedCommits": "{count, plural, one {# commit fusionné} other {# commits fusionnés}}", - "allFilesUpToDate": "Tous les fichiers sont à jour", - "updatedFiles": "{count, plural, one {# fichier mis à jour} other {# fichiers mis à jour}}", - "openCommitWindowFailed": "Impossible d’ouvrir la fenêtre de commit", - "openPushWindowFailed": "Impossible d’ouvrir la fenêtre de push", - "upstreamSet": "La branche upstream a été définie", - "upstreamSetAndPushed": "Branche upstream définie et {count, plural, one {# commit} other {# commits}} poussé(s)", - "noCommitsToPush": "Aucun commit à pousser", - "pushedCommits": "{count, plural, one {# commit poussé} other {# commits poussés}}", - "switchedToFolder": "Basculé vers {name}", - "switchFailed": "Échec du changement de branche", - "openStashWindowFailed": "Échec de l'ouverture de la fenêtre de remisage" - }, - "tasks": { - "newBranch": "Créer la branche {name}", - "newWorktree": "Créer le worktree {name}", - "checkoutTo": "Basculer vers {branchName}", - "mergeBranch": "Fusionner {branchName}", - "rebaseTo": "Rebase vers {branchName}", - "deleteRemoteBranch": "Supprimer la branche distante {branchName}", - "initGitRepo": "Initialiser le dépôt Git", - "pullCode": "Pull du code", - "fetchInfo": "Récupérer les infos", - "pushCode": "Push du code", - "stashChanges": "Stash des changements", - "stashPop": "Appliquer le stash", - "deleteBranch": "Supprimer la branche {branchName}", - "removeWorktree": "Supprimer le worktree de {branchName}", - "removeWorktreeAndBranch": "Supprimer le worktree et la branche {branchName}", - "updateBranch": "Mettre à jour la branche {branchName}" - }, - "confirm": { - "mergeTitle": "Fusionner la branche", - "rebaseTitle": "Rebase de la branche", - "mergeDescription": "Fusionner {branchName} dans la branche actuelle {currentBranch} ?", - "rebaseDescription": "Rebaser la branche actuelle {currentBranch} sur {branchName} ?", - "deleteRemoteTitle": "Supprimer la branche distante", - "deleteRemoteDescription": "Supprimer la branche distante {branchName} ? Cette action la supprimera du dépôt distant et ne pourra pas être annulée.", - "deleteTitle": "Supprimer la branche", - "deleteDescription": "Supprimer la branche {branchName} ? Cette action est irréversible.", - "forceDeleteTitle": "Forcer la suppression de la branche", - "forceDeleteDescription": "La branche {branchName} n'est pas entièrement fusionnée. Êtes-vous sûr de vouloir la supprimer de force ? Cette action est irréversible.", - "deleteWorktreeTitle": "Supprimer le worktree", - "deleteWorktreeDescription": "Supprimer le répertoire du worktree où {branchName} est extraite ? La branche et ses commits sont conservés.", - "forceDeleteWorktreeTitle": "Forcer la suppression du worktree", - "forceDeleteWorktreeDescription": "Le worktree de {branchName} contient des fichiers non validés ou non suivis. Le supprimer quand même ? Ces modifications seront irrécupérables.", - "deleteWorktreeAndBranchTitle": "Supprimer le worktree et la branche", - "deleteWorktreeAndBranchDescription": "Supprimer le worktree de {branchName}, la branche elle-même et son dossier d'espace de travail ? Ses sessions sont déplacées vers le dossier du dépôt. Cette action est irréversible.", - "forceDeleteWorktreeAndBranchTitle": "Forcer la suppression du worktree et de la branche", - "forceDeleteWorktreeAndBranchDescription": "Le worktree de {branchName} contient des fichiers non validés, ou la branche n'est pas entièrement fusionnée. Tout supprimer quand même ? Cette action est irréversible." - }, - "current": "Actuelle", - "switchToBranch": "Basculer vers cette branche", - "mergeBranchIntoCurrent": "Fusionner {branchName} dans {currentBranch}", - "rebaseCurrentToBranch": "Rebaser {currentBranch} sur {branchName}", - "noBranch": "Aucune branche", - "detachedHead": "HEAD détaché sur {sha}", - "initGitRepo": "Initialiser le dépôt Git", - "pullCode": "Pull du code", - "fetchRemoteBranches": "Récupérer les branches distantes", - "openCommitWindow": "Commit du code...", - "pushCode": "Pousser...", - "pushBranch": "Pousser", - "newBranch": "Nouvelle branche...", - "newWorktree": "Nouveau worktree...", - "stashChanges": "Remiser les changements...", - "stashPop": "Appliquer le stash...", - "manageRemotes": "Gérer les dépôts distants...", - "localBranches": "Branches locales ({count, plural, one {#} other {#}})", - "noLocalBranches": "Aucune branche locale", - "remoteBranches": "Branches distantes ({count, plural, one {#} other {#}})", - "noRemoteBranches": "Aucune branche distante", - "dialogs": { - "newBranchTitle": "Nouvelle branche", - "newBranchDescription": "Créer une nouvelle branche depuis la branche actuelle {branch}", - "branchNamePlaceholder": "Nom de la branche", - "newWorktreeTitle": "Nouveau worktree", - "newWorktreeDescription": "Créer un nouveau worktree depuis la branche actuelle {branch}", - "branchNameLabel": "Nom de la branche", - "worktreePathLabel": "Chemin du worktree", - "worktreePathPlaceholder": "Chemin du worktree", - "manageRemotesTitle": "Gérer les dépôts distants", - "manageRemotesEmpty": "Aucun dépôt distant configuré", - "remoteNamePlaceholder": "Nom du dépôt distant", - "remoteUrlPlaceholder": "URL du dépôt distant", - "addRemote": "Ajouter", - "savingRemotes": "Enregistrement..." - }, - "conflict": { - "title": "Conflits de fusion", - "description": "Les fichiers suivants ont des conflits qui doivent être résolus :", - "abort": "Abandonner la fusion", - "openMergeTool": "Ouvrir l'outil de fusion", - "completeMerge": "Terminer la fusion", - "abortSuccess": "Fusion abandonnée avec succès", - "completeSuccess": "Fusion terminée avec succès" - }, - "stashDialog": { - "title": "Remiser les changements", - "description": "Sauvegarder les changements actuels dans la remise", - "messageLabel": "Message", - "messagePlaceholder": "Message de remise (optionnel)", - "keepIndex": "Conserver l'index (les changements indexés restent indexés)", - "cancel": "Annuler", - "stash": "Remiser", - "success": "Changements remisés", - "error": "Échec de la remise" - }, - "unstashDialog": { - "title": "Appliquer la remise", - "noStashes": "Aucune remise trouvée", - "selectFile": "Sélectionner un fichier pour voir le diff", - "viewDiff": "Voir le diff", - "original": "Original", - "modified": "Modifié", - "apply": "Appliquer", - "drop": "Supprimer", - "applySuccess": "Remise appliquée", - "dropSuccess": "Remise supprimée", - "confirmApply": "Appliquer la remise {ref} au répertoire de travail ?", - "cancel": "Annuler" - }, - "deleteBranch": "Supprimer la branche", - "deleteWorktree": "Supprimer le worktree", - "deleteWorktreeAndBranch": "Supprimer le worktree et la branche", - "searchPlaceholder": "Rechercher des branches et actions", - "searchAriaLabel": "Rechercher des branches et actions", - "branchListLabel": "Branches et actions", - "noMatches": "Aucune correspondance" - }, - "commitDialog": { - "toasts": { - "commitCompleted": "Commit de code terminé", - "pushFailed": "Échec du push", - "committedFiles": "{count, plural, one {# fichier commit} other {# fichiers commit}}", - "addedToVcs": "Ajouté à VCS", - "addToVcsFailed": "Échec de l’ajout à VCS", - "fileDeleted": "Fichier supprimé", - "deleteFailed": "Échec de la suppression", - "fileRolledBack": "Fichier restauré", - "rollbackFailed": "Échec du rollback", - "dirRolledBack": "Répertoire restauré", - "dirDeleted": "Répertoire supprimé" - }, - "confirm": { - "deleteTitle": "Confirmer la suppression", - "deleteDescription": "Supprimer le fichier \"{file}\" ? Cette action est irréversible.", - "rollbackTitle": "Confirmer le rollback", - "rollbackDescription": "Restaurer le fichier \"{file}\" vers HEAD ? Les modifications non enregistrées seront perdues.", - "rollbackDirDescription": "Restaurer le répertoire \"{dir}\" vers HEAD ? Les modifications non enregistrées seront perdues.", - "deleteDirDescription": "Supprimer le répertoire \"{dir}\" ? Cette action est irréversible." - }, - "actions": { - "select": "Sélectionner", - "unselect": "Désélectionner", - "rollback": "Annuler", - "addToVcs": "Ajouter à VCS" - }, - "aria": { - "selectFile": "{action} : {path}", - "unselectAllFiles": "Désélectionner tous les fichiers", - "selectAllFiles": "Sélectionner tous les fichiers", - "unselectTracked": "Désélectionner les changements suivis", - "selectTracked": "Sélectionner les changements suivis", - "unselectUntracked": "Désélectionner les fichiers non suivis", - "selectUntracked": "Sélectionner les fichiers non suivis" - }, - "loading": "Chargement...", - "selectionCount": "{selected} / {total} fichiers", - "emptyFiles": "Aucun fichier modifié", - "trackedChanges": "Changements suivis ({count})", - "untrackedFiles": "Fichiers non suivis ({count})", - "commitMessage": "Message de commit", - "commitMessagePlaceholder": "Saisissez le message de commit...", - "commitButton": "Valider ({count})", - "commitAndPushButton": "Valider et pousser ({count})", - "head": "HEAD", - "workingTree": "Arbre de travail", - "clickFileToDiff": "Cliquez sur un nom de fichier pour voir le diff", - "loadingDiff": "Chargement du diff..." - }, - "pushWindow": { - "title": "Pousser le code", - "noUnpushedCommits": "Aucun commit non poussé", - "noRemoteConfigured": "Aucun dépôt distant Git configuré\nAjoutez-en un dans « Gérer les dépôts distants »", - "newBranchNoPushedCommits": "Nouvelle branche — pousser pour créer la branche de suivi distante", - "unpushed": "Non poussé", - "selectFileToViewDiff": "Sélectionnez un fichier pour voir les différences", - "before": "Avant", - "after": "Après", - "push": "Pousser", - "toasts": { - "pushSuccess": "Push réussi", - "pushFailed": "Échec du push", - "upstreamSet": "La branche distante a été configurée", - "upstreamSetAndPushed": "Branche distante configurée et {count} commits poussés", - "noCommitsToPush": "Aucun commit à pousser", - "pushedCommits": "{count} commits poussés" - } - }, - "gitLogTab": { - "filesTitle": "Fichiers", - "expandAllFiles": "Développer tous les fichiers", - "collapseAllFiles": "Réduire tous les fichiers", - "workspace": "espace de travail", - "retry": "Réessayer", - "noCommitsFound": "Aucun commit trouvé", - "notAGitRepoTitle": "Pas un dépôt Git", - "notAGitRepoHint": "Initialisez Git depuis le menu des branches ci-dessus, ou ouvrez un dépôt existant.", - "hash": "Empreinte", - "copyHash": "Copier le hash", - "copyMessage": "Copier le message", - "showMore": "Afficher plus", - "showLess": "Afficher moins", - "author": "Auteur", - "noFileChangeDetails": "Aucun détail de changement de fichier disponible.", - "loadingFiles": "Chargement des fichiers...", - "branchesTitle": "Branches Git", - "loadingBranches": "Chargement des branches...", - "noContainingBranches": "Aucune branche contenant ce commit.", - "newBranch": "Nouvelle branche...", - "resetToHere": "Réinitialiser ici", - "resetDisabledReasonNotCurrentBranchView": "Disponible uniquement en affichant la branche actuelle", - "copyFullCommitHashAria": "Copier le hash complet du commit {hash}", - "pushStatus": { - "pushed": "Poussé vers le remote", - "notPushed": "Non poussé vers le remote", - "unknown": "Statut de push inconnu (aucun upstream configuré)" - }, - "time": { - "monthsAgo": "{count, plural, one {il y a # mois} other {il y a # mois}}", - "daysAgo": "{count, plural, one {il y a # jour} other {il y a # jours}}", - "hoursAgo": "{count, plural, one {il y a # heure} other {il y a # heures}}", - "minsAgo": "{count, plural, one {il y a # min} other {il y a # mins}}", - "justNow": "à l’instant" - }, - "toasts": { - "createdAndSwitchedNewBranch": "Nouvelle branche créée et activée", - "newBranchFromCommit": "{name} (depuis {shortHash})", - "createBranchFailed": "Échec de la création de la branche", - "openPushWindowFailed": "Échec de l'ouverture de la fenêtre de push", - "resetSuccess": "Réinitialisation réussie", - "resetSuccessDescription": "{branch} a été réinitialisée sur {shortHash} avec {mode}", - "resetFailed": "Échec de la réinitialisation" - }, - "authorFilter": { - "label": "Auteur", - "searchPlaceholder": "Rechercher un auteur", - "noAuthors": "Aucun auteur trouvé", - "you": "vous", - "filterByAuthorAria": "Filtrer les commits par auteur", - "filterByQuery": "Filtrer par « {query} »", - "clearAuthorFilterAria": "Effacer le filtre par auteur", - "recent": "Récents", - "matchingAuthors": "Auteurs correspondants", - "removeFromRecent": "Retirer {name} des récents" - }, - "branchSelector": { - "label": "Branche", - "head": "HEAD", - "headHint": "Suit la branche actuelle", - "headHintWithBranch": "Suit la branche actuelle ({branch})", - "searchBranch": "Rechercher une branche...", - "noBranches": "Aucune branche", - "selectBranchPlaceholder": "Sélectionner une branche...", - "localBranches": "Branches locales", - "current": "Actuelle", - "remoteBranches": "Branches distantes", - "refreshCommitHistory": "Actualiser l’historique des commits", - "clearBranchFilterAria": "Effacer le filtre par branche" - }, - "dialogs": { - "newBranchTitle": "Nouvelle branche", - "newBranchDescription": "Créer une nouvelle branche avec le commit {shortHash} comme dernier commit.", - "branchNamePlaceholder": "Nom de la branche", - "reset": { - "title": "Réinitialiser la branche actuelle jusqu’ici", - "branchLabel": "Branche", - "targetLabel": "Commit cible", - "messageLabel": "Message", - "modeLabel": "Mode de réinitialisation", - "confirmButton": "Réinitialiser", - "modes": { - "soft": { - "label": "--soft", - "description": "Déplace HEAD et le pointeur de la branche actuelle vers le commit cible.\nConserve Index et Working Tree inchangés.\nLes changements des commits retirés restent staged." - }, - "mixed": { - "label": "--mixed (par défaut)", - "description": "Déplace HEAD vers le commit cible.\nRéinitialise Index au commit cible tout en conservant les changements du Working Tree.\nLes changements passent de staged à unstaged." - }, - "hard": { - "label": "--hard", - "description": "Déplace HEAD et réinitialise à la fois Index et Working Tree au commit cible.\nLes changements locaux suivis après le commit cible sont supprimés.\nC’est une opération destructive." - }, - "keep": { - "label": "--keep", - "description": "Déplace HEAD vers le commit cible en conservant les changements locaux quand c’est possible.\nSeuls les changements sans conflit sont conservés.\nEn cas de conflit, la réinitialisation est annulée pour protéger votre travail." - } - } - } - }, - "moreActions": "Autres actions Git" - }, - "gitChangesTab": { - "workspace": "espace de travail", - "noChanges": "Aucun changement local", - "notAGitRepoTitle": "Pas un dépôt Git", - "notAGitRepoHint": "Initialisez Git depuis le menu des branches ci-dessus, ou ouvrez un dépôt existant.", - "trackedChanges": "Changements suivis ({count})", - "untrackedFiles": "Fichiers non suivis ({count})", - "expandTracked": "Développer les changements suivis", - "collapseTracked": "Réduire les changements suivis", - "expandUntracked": "Développer les fichiers non suivis", - "collapseUntracked": "Réduire les fichiers non suivis", - "showRemainingItems": "Afficher {count} éléments de plus", - "actions": { - "commitCode": "Commit du code", - "rollback": "Annuler", - "addToVcs": "Ajouter à VCS", - "delete": "Supprimer", - "moreActions": "Autres actions Git", - "addAllToVcs": "Tout ajouter au VCS", - "rollbackAll": "Tout annuler", - "refresh": "Actualiser" - }, - "toasts": { - "noAddableFilesInDir": "Aucun fichier modifié de ce répertoire ne peut être ajouté à VCS", - "noRollbackFilesInDir": "Aucun fichier modifié de ce répertoire ne peut être rollback", - "addedToVcs": "{name} ajouté à VCS", - "addToVcsFailed": "Échec de l’ajout à VCS", - "openCommitWindowFailed": "Impossible d’ouvrir la fenêtre de commit", - "rolledBack": "{name} restauré", - "rollbackFailed": "Échec du rollback", - "addedFilesToVcs": "{count, plural, one {# fichier} other {# fichiers}} ajouté(s) à VCS", - "rolledBackFiles": "{count, plural, one {# fichier restauré} other {# fichiers restaurés}}", - "deleted": "{name} supprimé", - "deleteFailed": "Échec de la suppression", - "deletedFiles": "{count} fichiers supprimés", - "noDeletableFilesInDir": "Aucun fichier modifié dans ce répertoire ne peut être supprimé", - "commitFailed": "Échec du commit" - }, - "directoryDialog": { - "descriptionAdd": "Sélectionnez les fichiers du répertoire {path} à ajouter à VCS.", - "descriptionRollback": "Sélectionnez les fichiers du répertoire {path} à rollback.", - "descriptionDelete": "Sélectionnez les fichiers du répertoire {path} à supprimer. Cette action est irréversible.", - "descriptionFallback": "Sélectionnez les fichiers pour continuer.", - "selectionCount": "{selected} / {total} fichiers sélectionnés", - "selectAll": "Tout sélectionner", - "unselectAll": "Tout désélectionner", - "loadingCandidates": "Chargement des changements du répertoire...", - "noOperableFiles": "Aucun fichier opérable" - }, - "rollbackConfirm": { - "title": "Confirmer le rollback", - "descriptionWithTarget": "Rollback des changements locaux pour {kind} \"{name}\" ?", - "descriptionFallback": "Rollback des changements locaux ?", - "kindDirectory": "répertoire", - "kindFile": "fichier" - }, - "deleteConfirm": { - "title": "Confirmer la suppression", - "descriptionWithTarget": "Supprimer {kind} \"{name}\" ? Cette action est irréversible.", - "descriptionFallback": "Cette action est irréversible.", - "kindDirectory": "répertoire", - "kindFile": "fichier" - }, - "quickCommit": { - "placeholder": "Message du commit (Entrée pour valider)" - } - }, - "tabContext": { - "loadingConversation": "Chargement...", - "untitledConversation": "Conversation sans titre", - "newConversation": "Nouvelle conversation" - }, - "fileTreeTab": { - "workspace": "Espace de travail", - "retry": "Réessayer", - "git": "Git", - "openInFileManager": "Ouvrir dans le gestionnaire de fichiers", - "openInFinder": "Ouvrir dans Finder", - "openInExplorer": "Ouvrir dans Explorer", - "attachToCurrentSession": "Ajouter à la session", - "compareWithBranch": "Comparer avec la branche...", - "reloadFromDisk": "Recharger depuis le disque", - "new": "Nouveau", - "newFile": "Fichier", - "newDirectory": "Répertoire", - "openIn": "Ouvrir dans", - "openInTerminal": "Ouvrir dans le terminal", - "linkedFolder": "Dossier lié", - "copyPath": "Copier le chemin", - "upload": "Téléverser fichiers/dossier", - "download": "Télécharger le fichier", - "downloadAsZip": "Télécharger en ZIP", - "actions": { - "select": "Sélectionner", - "unselect": "Désélectionner", - "commitCode": "Committer le code", - "rollback": "Annuler", - "addToVcs": "Ajouter au VCS" - }, - "aria": { - "selectPath": "{action} : {path}" - }, - "toasts": { - "openDirectoryFailed": "Échec de l'ouverture du dossier", - "openBuiltinTerminalFailed": "Impossible d'ouvrir le terminal intégré", - "openCommitWindowFailed": "Échec de l'ouverture de la fenêtre de commit", - "noAddableFilesInDir": "Aucun fichier modifié de ce dossier ne peut être ajouté au VCS", - "noRollbackFilesInDir": "Aucun fichier modifié de ce dossier ne peut être annulé", - "addedToVcs": "{name} ajouté au VCS", - "addToVcsFailed": "Échec de l'ajout au VCS", - "loadBranchesFailed": "Échec du chargement des branches", - "renameFailed": "Échec du renommage", - "moveFailed": "Échec du déplacement", - "deleteFailed": "Échec de la suppression", - "rolledBack": "{name} annulé", - "rollbackFailed": "Échec de l'annulation", - "addedFilesToVcs": "{count, plural, one {# fichier ajouté au VCS} other {# fichiers ajoutés au VCS}}", - "rolledBackFiles": "{count, plural, one {# fichier annulé} other {# fichiers annulés}}", - "savedAsCopy": "Enregistré en copie", - "saveCopyFailed": "Échec de l'enregistrement en copie", - "watchStartFailed": "Échec du démarrage de la surveillance de fichiers", - "createFailed": "Échec de la création", - "downloadFailed": "Échec du téléchargement de {name}", - "downloadSaved": "{name} téléchargé", - "pathCopied": "Chemin copié", - "copyPathFailed": "Échec de la copie du chemin" - }, - "createDialog": { - "newFile": "Nouveau fichier", - "newDirectory": "Nouveau répertoire", - "description": "Entrez un nom pour le nouveau {kind}.", - "placeholderFile": "nom-du-fichier.ext", - "placeholderDirectory": "nom-du-dossier" - }, - "renameDialog": { - "renameDirectory": "Renommer le dossier", - "renameFile": "Renommer le fichier", - "description": "Saisissez un nouveau nom (nom uniquement, sans chemin).", - "placeholderDirectory": "nouveau-nom-dossier", - "placeholderFile": "nouveau-nom-fichier.ext" - }, - "uploadDialog": { - "title": "Téléverser vers l'espace de travail", - "description": "Ajustez la destination si besoin, puis ajoutez des fichiers ou dossiers.", - "workspaceRoot": "racine de l'espace de travail", - "targetPathLabel": "Téléverser vers", - "targetPathHint": "Chemin résolu : {path}", - "dropHint": "Déposez des fichiers ou dossiers ici, ou utilisez les boutons ci-dessous", - "dropHintActive": "Relâchez pour ajouter à la file d'attente", - "selectFiles": "Sélectionner des fichiers", - "selectFolder": "Sélectionner un dossier", - "startUpload": "Lancer le téléversement", - "clearQueue": "Effacer terminés", - "removeItem": "Retirer de la file", - "retry": "Réessayer", - "dropZoneAria": "Déposez ici ou activez pour parcourir", - "folderEmpty": "Aucun fichier trouvé dans le dossier déposé", - "summary": "Total : {total} · Réussis : {succeeded} · Échoués : {failed}", - "status": { - "pending": "En attente", - "uploading": "Téléversement", - "success": "Terminé", - "error": "Échec", - "cancelled": "Annulé" - } - }, - "directoryDialog": { - "descriptionAdd": "Sélectionnez des fichiers sous le dossier {path} à ajouter au VCS.", - "descriptionRollback": "Sélectionnez des fichiers sous le dossier {path} à annuler.", - "descriptionFallback": "Sélectionnez des fichiers pour continuer.", - "selectionCount": "{selected} / {total} fichiers sélectionnés", - "selectAll": "Tout sélectionner", - "unselectAll": "Tout désélectionner", - "loadingCandidates": "Chargement des changements du dossier...", - "noOperableFiles": "Aucun fichier exploitable" - }, - "compareDialog": { - "title": "Comparer avec la branche", - "descriptionWithTarget": "Sélectionnez une branche et comparez avec {kind} {path}", - "descriptionFallback": "Sélectionnez une branche à comparer.", - "kindDirectory": "dossier", - "kindFile": "fichier", - "filterPlaceholder": "Filtrer les branches, ex. main / origin/main", - "singleClickHint": "Cliquez sur une branche pour comparer directement", - "loadingBranches": "Chargement des branches...", - "recentBranches": "Branches récentes ({count})", - "noCurrentBranch": "Aucune branche courante", - "localBranches": "Branches locales ({count})", - "remoteBranches": "Branches distantes ({count})", - "noMatchingBranches": "Aucune branche correspondante" - }, - "externalConflictDialog": { - "title": "Modifications externes de fichiers détectées", - "descriptionWithPath": "Le fichier {path} a changé sur le disque et les modifications actuelles ne sont pas enregistrées.", - "descriptionFallback": "Le fichier actuel a changé sur le disque et les modifications actuelles ne sont pas enregistrées.", - "compare": "Comparer", - "savingCopy": "Enregistrement de la copie...", - "saveAsCopy": "Enregistrer en copie", - "reload": "Recharger" - }, - "deleteConfirm": { - "title": "Confirmer la suppression", - "descriptionWithTarget": "Supprimer {kind} \"{name}\" ? Cette action est irréversible.", - "descriptionFallback": "Cette action est irréversible.", - "kindDirectory": "dossier", - "kindFile": "fichier" - }, - "rollbackConfirm": { - "title": "Confirmer l'annulation", - "descriptionWithTarget": "Annuler les modifications locales du fichier \"{name}\" ?", - "descriptionFallback": "Annuler les modifications locales de ce fichier ?" - }, - "terminalTitle": "Console · {name}" - }, - "commandDropdown": { - "loading": "Chargement...", - "addCommand": "Ajouter une commande", - "manageCommands": "Gérer les commandes...", - "runCommandTitle": "Exécuter : {command}", - "stopCommandTitle": "Arrêter : {command}", - "manageDialog": { - "title": "Gérer les commandes", - "empty": "Aucune commande pour le moment", - "noResults": "Aucune commande correspondante", - "searchPlaceholder": "Rechercher des commandes", - "newCommand": "Nouvelle commande", - "nameLabel": "Nom", - "commandLabel": "Commande", - "dragSort": "Glisser pour trier", - "dragSortCommand": "Glisser pour trier {name}", - "orderFailed": "Échec de l'enregistrement de l'ordre des commandes", - "loadFailed": "Échec du chargement des commandes", - "saveFailed": "Échec de l'enregistrement de la commande", - "deleteFailed": "Échec de la suppression de la commande", - "confirmDelete": { - "title": "Supprimer la commande ?", - "message": "Cela supprimera \"{name}\". Cette action est irréversible." - } - } - }, - "workspaceContext": { - "confirmCloseDirtyTab": "Fermer « {title} » sans enregistrer ?", - "confirmCloseOtherDirtyTabs": "Fermer les autres onglets avec des modifications non enregistrées ?", - "confirmCloseAllDirtyTabs": "Fermer tous les onglets avec des modifications non enregistrées ?", - "unableLoadContent": "Impossible de charger le contenu.\n\n{message}", - "previewRequestTimedOut": "La requête de prévisualisation a expiré", - "diffRequestTimedOut": "La requête Diff a expiré", - "branchCompareRequestTimedOut": "La requête de comparaison de branches a expiré", - "commitDiffRequestTimedOut": "La requête de Diff de commit a expiré", - "saveRequestTimedOut": "La requête d’enregistrement a expiré", - "reloadRequestTimedOut": "La requête de rechargement a expiré", - "noChanges": "Aucun changement.", - "noDiffOutput": "Aucune sortie diff.", - "diffTitleWorkspace": "Diff · Espace de travail", - "diffDescriptionWorkingTree": "Arbre de travail (HEAD)", - "diffTitleFile": "Différence · {name}", - "compareTitleFile": "Comparer · {name}", - "compareTitleBranch": "Comparer · {branch}", - "compareDescriptionPath": "{path} · comparer avec {branch}", - "compareDescriptionBranch": "comparer avec {branch}", - "diffTitleCommitFile": "Différence · {name} @ {hash}", - "diffTitleCommit": "Différence · {hash}", - "diffDescriptionCommitPath": "{path} · validation {commit}", - "diffDescriptionCommit": "validation {commit}", - "diffTitleConflictFile": "Conflit · {name}", - "diffDescriptionConflict": "{path} · disque vs non enregistré" - }, - "chat": { - "acpConnections": { - "actions": { - "openAgentsSettings": "Ouvrir les paramètres des agents", - "retry": "Réessayer" - }, - "agentsSetupHint": "Ouvrez Paramètres > Agents pour gérer l'installation.", - "withSetupHint": "{message}\n{hint}", - "blocked": { - "missingConfig": "Impossible de lire la configuration actuelle de l'agent.", - "disabled": "{agent} est désactivé dans les paramètres des agents. Activez-le avant de vous connecter.", - "unavailable": "{agent} n'est pas disponible sur la plateforme actuelle.", - "sdkMissing": "Le SDK de {agent} n'est pas installé", - "adapterMissing": "L'adaptateur ACP de {agent} n'est pas installé" - }, - "backendErrors": { - "initializeTimeout": "Le handshake de connexion de {agent} a expiré (aucune réponse après 60 secondes). Ouvrez Paramètres pour vérifier la configuration de l'agent et du réseau.", - "mcpRejectedByAgent": "{agent} a refusé la session alors que le compagnon MCP de codeg était joint : {message} Si cet agent ne prend pas en charge MCP, désactivez « Prise en charge de MCP » dans les Paramètres puis reconnectez-vous.", - "processExited": "Le processus {agent} s'est arrêté de manière inattendue.", - "spawnFailed": "Impossible de démarrer {agent} : {message}", - "downloadFailed": "Échec du téléchargement de {agent} : {message}", - "sessionLoadResourceNotFound": "Échec du chargement de la session de {agent}. Rechargez pour réessayer ou démarrez une nouvelle conversation.", - "sessionLoadUnavailable": "{agent} n'a pas pu restaurer cette session ; elle a peut-être pris fin ou l'agent s'est arrêté. Rechargez pour réessayer ou démarrez une nouvelle conversation.", - "turnFailedRefusal": "{agent} a refusé de poursuivre ce tour. Cela indique souvent une erreur de backend ou de passerelle. Vérifiez les journaux de l'agent.", - "turnFailedMaxTokens": "{agent} a atteint la limite maximale de jetons pour ce tour.", - "turnFailedMaxTurnRequests": "{agent} a atteint le nombre maximal de requêtes autorisées pour ce tour.", - "turnFailedUnknown": "{agent} a terminé le tour avec une raison d'arrêt inconnue.", - "grokModelSwitchIncompatibleAgent": "{agent} ne peut pas basculer vers ce modèle dans une conversation existante. Démarrez une nouvelle session pour l'utiliser.", - "turnFailedEmpty": "{agent} a terminé le tour sans produire de réponse.", - "turnFailedEmptyProtocol": "{agent} a produit une sortie que codeg n'a pas pu analyser — la version de l'agent ne correspond peut-être pas au protocole.", - "turnFailedEmptyMetadata": "{agent} n'a envoyé que des mises à jour d'état ce tour-ci (plan / mode / utilisation) et aucune réponse.", - "detailsInAlerts": "Ouvrez les alertes de la barre d'état et développez les détails pour voir la sortie de l'agent." - }, - "unableReadAgentConfig": "Impossible de lire la configuration de l'agent : {message}", - "connectFailedTitle": "Échec de la connexion de {agent}", - "toolFallbackTitle": "Outil", - "eventErrorTitle": "Erreur de l'agent", - "notificationTurnComplete": "{agent} a terminé de répondre", - "notificationError": "{agent} erreur : {message}", - "claudeApiRetry": { - "fallbackError": "authentication_failed", - "retryingWithMax": "nouvelle tentative {attempt}/{max}", - "retryingAttempt": "nouvelle tentative {attempt}", - "retrying": "nouvelle tentative", - "nextRetryIn": "prochaine dans {seconds}s", - "line": "{error}{status} · {retry}", - "lineWithDelay": "{error}{status} · {retry}, {delay}", - "httpStatus": " (HTTP {status})" - }, - "configOptionAdjusted": "{agent} a réglé {option} sur {actual} au lieu de {requested}" - }, - "connectionLifecycle": { - "tasks": { - "connectingTitle": "Connexion à {agent}", - "connectingDescription": "Établissement de la connexion", - "loadingSelectorsTitle": "Chargement des sélecteurs de {agent}", - "loadingSelectorsDescription": "Récupération des options de mode et de configuration de session", - "initSessionTitle": "Initialisation de la session {agent}", - "initSessionDescription": "Création de la session et chargement de la configuration" - }, - "errors": { - "connectionFailed": "Échec de la connexion", - "sendPromptFailed": "Échec de l'envoi du message : {error}" - } - }, - "shared": { - "attachedResources": "Ressources jointes", - "toolCallFailed": "Échec de l'appel d'outil" - }, - "messageThread": { - "emptyTitle": "Aucun message pour le moment", - "emptyDescription": "Commencez une conversation pour voir les messages ici" - }, - "chatInput": { - "connecting": "Connexion...", - "agentResponding": "{agent} répond...", - "sendMessage": "Envoyer un message..." - }, - "messageInput": { - "askAnything": "Posez n'importe quelle question...", - "removeAttachmentAria": "Retirer {name}", - "attachFiles": "Joindre des fichiers", - "addActions": "Ajouter", - "quickMessages": "Messages rapides", - "quickMessagesEmpty": "Aucun message rapide pour l'instant", - "quickMessagesLoading": "Chargement...", - "pasteAsPlainText": "Coller en texte brut", - "cut": "Couper", - "copy": "Copier", - "selectAll": "Tout sélectionner", - "pasteUnavailable": "Impossible de lire le presse-papiers. Utilisez Ctrl/⌘V pour coller.", - "clipboardWriteFailed": "Impossible d'écrire dans le presse-papiers. Utilisez le raccourci clavier.", - "quickMessageUntitled": "Sans titre", - "liveFeedback": "Retour en direct", - "liveFeedbackDisabledHint": "Disponible pendant que l'agent travaille", - "dropFilesToAttach": "Déposez des fichiers à joindre", - "loadingSettings": "Chargement des paramètres...", - "loadingMode": "Chargement du mode...", - "modeLabel": "Mode", - "toggleOn": "Activé", - "toggleOff": "Désactivé", - "agentSettings": "Paramètres de l'agent", - "searchModel": "Rechercher des modèles...", - "searchModelAria": "Rechercher des modèles", - "modelListLabel": "Modèles", - "noModels": "Aucun modèle trouvé", - "cancel": "Annuler", - "send": "Envoyer", - "forkAndSend": "Fork & Envoyer", - "queueMessage": "Mettre en file d'attente", - "steerIntoTurn": "Insérer dans le tour en cours", - "steerQueuedInstead": "Mis en file d'attente — il sera envoyé au tour suivant.", - "steerFailed": "Impossible d'insérer dans le tour en cours", - "steerAttachmentsUnsupported": "Texte uniquement — les brouillons avec pièces jointes passent par la file d'attente.", - "slashCommands": "Commandes slash", - "slashSearchPlaceholder": "Rechercher des commandes...", - "slashSearchEmpty": "Aucune commande correspondante", - "experts": "Experts", - "office": "Bureautique", - "research": "Recherche", - "attachLocalUpload": "Téléverser un fichier local", - "attachServerFile": "Sélectionner un fichier serveur", - "attachUploadTooLarge": "{names} dépasse la limite de téléversement de {limit} Mo et a été ignoré.", - "attachUploadFailed": "Échec du téléversement de {names}.", - "attachUploadNotAFile": "{names} n'est pas un fichier régulier (répertoire ou fichier spécial) et a été ignoré.", - "attachUploadQuotaExceeded": "Le serveur n'a plus d'espace pour les téléversements ; {names} n'a pas pu être envoyé.", - "attachUploadInProgress": "Les images sont encore en cours d'envoi — réessayez dans un instant.", - "mentionEmpty": "Aucune correspondance", - "mentionLoading": "Recherche…", - "mentionListLabel": "Mentions", - "mentionMore": "Plus de résultats — continuez à taper pour filtrer", - "mentionCount": "{count, plural, one {# résultat} other {# résultats}}", - "mentionGroupFile": "Fichiers", - "mentionGroupAgent": "Agents", - "mentionGroupSession": "Sessions", - "mentionGroupCommit": "Commits", - "mentionGroupSkill": "Compétences" - }, - "messageQueue": { - "addToQueue": "Mettre en file", - "saveEdit": "Enregistrer", - "cancelEdit": "Annuler la modification", - "editItem": "Modifier", - "deleteItem": "Supprimer" - }, - "welcomeInputPanel": { - "agentsSettingsPath": "Paramètres > Agents", - "autoConnectFallback": "Cliquez pour ouvrir {path} et gérer l'installation.", - "autoConnectAppend": "{message}. Cliquez pour ouvrir {path} et gérer l'installation.", - "enableAgentFirstPlaceholder": "Activez au moins un agent avant de démarrer une session...", - "prepareSessionFailed": "Impossible de préparer la session de chat. Veuillez réessayer.", - "createConversationFailed": "Impossible de créer la conversation. Veuillez réessayer.", - "askAnythingPlaceholder": "Posez n'importe quelle question...", - "agentNotInstalled": "{agent} n'est pas installé · ouvrez les paramètres Agents pour l'installer", - "agentAdapterNotInstalled": "L'adaptateur ACP de {agent} n'est pas installé (distinct de votre propre CLI) · ouvrez les paramètres Agents pour l'installer" - }, - "welcomePanel": { - "greeting": "Que souhaites-tu faire aujourd'hui ?", - "tips": { - "tileTabs": "Faites un clic droit sur un onglet de conversation et choisissez Affichage en mosaïque pour comparer plusieurs sessions côte à côte.", - "pinTab": "Double-cliquez sur un onglet de conversation pour l'épingler : une nouvelle session ne le remplacera plus automatiquement.", - "shortcutsNewSearch": "{newConversation} ouvre une nouvelle conversation, {searchConversations} recherche dans l'historique.", - "slashAtMention": "Saisissez / dans la zone de saisie pour les commandes slash, ou @ pour référencer un fichier du projet.", - "pasteDropFiles": "Collez une capture d'écran ou déposez un fichier directement dans la zone de saisie pour le joindre.", - "queueMessage": "Pendant que l'agent répond, continuez à écrire : votre message suivant est mis en file et envoyé automatiquement à la fin.", - "draftAutoSave": "Les brouillons non envoyés sont sauvegardés automatiquement par conversation et restaurés à votre retour.", - "forkSend": "Le menu déroulant du bouton d'envoi propose Bifurquer et envoyer pour ouvrir une branche dans un nouvel onglet à partir du point actuel.", - "exportConversation": "Faites un clic droit dans la conversation pour l'exporter en Markdown, HTML ou image.", - "chatChannels": "Connectez Telegram / Lark / WeChat dans Paramètres → Canaux de discussion pour continuer depuis votre téléphone.", - "shortcutsAuxPanel": "{toggleAuxPanel} bascule le panneau droit pour voir les fichiers modifiés et les changements Git de cette session.", - "shortcutsTerminalSidebar": "{toggleTerminal} ouvre le terminal intégré, {toggleSidebar} bascule la barre latérale.", - "customShortcuts": "Tous les raccourcis peuvent être réassignés dans Paramètres → Raccourcis.", - "webService": "Activez Paramètres → Service Web pour que votre équipe accède au même codeg depuis un navigateur.", - "fusionMode": "Ouvrez un fichier ou un diff pour l'afficher automatiquement à côté de la conversation.", - "quickMessages": "Ouvrez le bouton + à côté de la saisie et choisissez Messages rapides pour insérer un extrait enregistré (à gérer dans Paramètres → Messages rapides).", - "experts": "Le bouton + propose un menu Compétences expertes — chargez en un clic des rôles comme Débogage ou Planification.", - "taskBoard": "Les tâches à faire exécutent un travail de bout en bout : l'agent travaille dans son propre worktree, vous relisez le diff puis fusionnez.", - "automations": "Les Automatisations exécutent un prompt enregistré selon un planning — une revue nocturne, un rapport récurrent — et chaque exécution peut avoir son propre worktree.", - "tokenUsage": "Cliquez sur le nombre de conversations dans la barre d'état pour ouvrir la Consommation de tokens, détaillée par jour, agent, modèle et dossier.", - "mentionTargets": "@ ne sert pas qu'aux fichiers : mentionnez un autre agent pour lui confier une sous-tâche, ou référencez une session passée, un commit ou une compétence.", - "splitGroups": "Faites un clic droit sur un onglet et choisissez Diviser à droite ou Diviser en bas pour garder deux conversations dans leurs propres volets.", - "worktrees": "Ouvrez le bouton de branche et choisissez Nouveau worktree pour que plusieurs agents travaillent sur le même dépôt sans écraser les fichiers des autres.", - "importSessions": "Vous avez déjà lancé des sessions dans le terminal ? Le menu d'un dossier propose Importer les sessions locales pour récupérer cet historique dans codeg.", - "subSessions": "Quand un agent délègue, la sous-session apparaît imbriquée sous lui dans la barre latérale : dépliez la ligne pour suivre ce que chacune a fait.", - "liveFeedback": "Retour en direct, dans le menu +, glisse une note dans le tour que l'agent exécute déjà, sans l'interrompre.", - "skillPacks": "Paramètres → Packs de compétences regroupe experts du code, recherche scientifique et bureautique ; activez-les agent par agent.", - "modelProviders": "Paramètres → Fournisseurs de Modèles accepte votre propre clé d'API ou endpoint, puis vous choisissez le modèle dans la zone de saisie.", - "workspaceBackground": "Paramètres → Apparence définit une image de fond pour l'espace de travail, l'opacité des panneaux et les polices de l'application." - }, - "quickActions": { - "excel": "Classeur Excel", - "excelDesc": "Tableaux, formules et graphiques", - "word": "Document Word", - "wordDesc": "Rapports, lettres et notes", - "ppt": "Présentation", - "pptDesc": "Diapositives au design professionnel", - "pitchDeck": "Pitch Deck", - "pitchDeckDesc": "Présentation de levée avec indicateurs", - "morph": "Animation Morph", - "morphDesc": "Transitions de diapositive cinématographiques", - "morph3d": "Morph 3D", - "morph3dDesc": "Modèles 3D avec mouvements de caméra", - "academic": "Article académique", - "academicDesc": "Recherche avec citations et structure", - "financial": "Modèle financier", - "financialDesc": "États, DCF et projections", - "dashboard": "Tableau de bord", - "dashboardDesc": "KPI et analyses à partir de vos données", - "prompts": { - "excel": "Crée un classeur Excel avec les exigences suivantes :\n\n[décris ici tes données, tableaux, formules et graphiques]", - "word": "Crée un document Word avec les exigences suivantes :\n\n[décris ici le contenu, la structure et la mise en forme du document]", - "ppt": "Crée une présentation PowerPoint avec les exigences suivantes :\n\n[décris ici tes diapositives, le contenu et le design]", - "pitchDeck": "Crée un pitch deck de levée de fonds avec les exigences suivantes :\n\n[décris ici ton entreprise, le tour de financement et les indicateurs clés]", - "morph": "Crée une présentation avec des animations de transition Morph :\n\n[décris ici le sujet de la présentation et les effets visuels souhaités]", - "morph3d": "Crée une présentation Morph 3D avec des modèles GLB et des mouvements de caméra :\n\n[décris ici ton sujet et le concept visuel en 3D]", - "academic": "Rédige un article académique dans Word avec les exigences suivantes :\n\n[décris ici ton sujet de recherche, la méthodologie et les principaux résultats]", - "financial": "Crée un modèle financier dans Excel avec les exigences suivantes :\n\n[décris ici tes états financiers, projections et analyses]", - "dashboard": "Crée un tableau de bord de données dans Excel avec les exigences suivantes :\n\n[décris ici ta source de données, les KPI et les graphiques]", - "scientific-brainstorming": "Aide-moi à imaginer des pistes de recherche : explore les liens interdisciplinaires, questionne les hypothèses et repère les lacunes prometteuses. Le domaine que j'explore : ", - "hypothesis-generation": "Aide-moi à transformer ces observations en hypothèses testables, avec des prédictions claires, des mécanismes plausibles et des expériences. Mes observations : ", - "experimental-design": "Aide-moi à concevoir une expérience rigoureuse avant de collecter des données : le plan, la randomisation, les contrôles et comment éviter les facteurs de confusion. Ce que je veux étudier : ", - "statistical-power": "Aide-moi à déterminer la taille d'échantillon nécessaire : guide-moi dans une analyse de puissance (taille d'effet, alpha, puissance) pour mon plan. Détails : ", - "statistical-analysis": "Aide-moi à analyser ces données correctement : choisir le bon test, vérifier les hypothèses, rapporter les tailles d'effet et rédiger. Mes données et ma question : ", - "exploratory-data-analysis": "Fais une analyse exploratoire de mon fichier de données : résume sa structure, sa qualité et les motifs notables, puis propose les prochaines étapes. Le fichier est : ", - "scientific-visualization": "Aide-moi à créer une figure de qualité publication : mise en page claire, barres d'erreur honnêtes, palette adaptée au daltonisme et mise en forme de revue. Ce que je veux montrer : ", - "scientific-critical-thinking": "Aide-moi à évaluer de façon critique cette étude ou affirmation : apprécie la qualité des preuves, repère les biais et facteurs de confusion, et pèse les conclusions. La voici : ", - "paper-lookup": "Aide-moi à trouver des articles pertinents et du texte intégral en libre accès dans les bases de données savantes, avec des citations réutilisables. Je cherche : " - }, - "paper-lookup": "Recherche d'articles", - "paper-lookupDesc": "Rechercher dans 10 API savantes (PubMed, arXiv, OpenAlex, Crossref…) articles, citations et texte intégral en libre accès.", - "scientific-critical-thinking": "Pensée critique", - "scientific-critical-thinkingDesc": "Évaluer les affirmations scientifiques et la qualité des preuves : repérer biais et facteurs de confusion, appliquer GRADE.", - "scientific-visualization": "Visualisation scientifique", - "scientific-visualizationDesc": "Figures prêtes à publier : dispositions multipanneaux, annotations de significativité et mise en forme par revue.", - "exploratory-data-analysis": "Analyse exploratoire des données", - "exploratory-data-analysisDesc": "Exploration automatisée de fichiers de données scientifiques (200+ formats) avec métriques de qualité et rapports.", - "statistical-analysis": "Analyse statistique", - "statistical-analysisDesc": "Analyse statistique guidée : choix du test, vérification des hypothèses, tailles d'effet et rapport au format APA.", - "statistical-power": "Puissance statistique", - "statistical-powerDesc": "Analyse de la taille d'échantillon et de la puissance : effectifs nécessaires, effets minimaux détectables, courbes de puissance.", - "experimental-design": "Plan d'expérience", - "experimental-designDesc": "Concevoir des études rigoureuses avant la collecte : randomisation, blocs, contrôles et plans factoriels/DOE.", - "hypothesis-generation": "Génération d'hypothèses", - "hypothesis-generationDesc": "Transformer des observations en hypothèses testables avec prédictions, mécanismes et expériences de test.", - "scientific-brainstorming": "Brainstorming scientifique", - "scientific-brainstormingDesc": "Idéation de recherche ouverte : explorer les liens interdisciplinaires, questionner les hypothèses, repérer les lacunes.", - "tabs": { - "office": "Bureautique", - "coding": "Développement", - "research": "Recherche" - }, - "coding": { - "brainstormingDesc": "Explorer intention et besoins avant de coder", - "debuggingDesc": "Trouver la cause racine avant de corriger", - "writingSkillsDesc": "Créer, modifier et vérifier des skills réutilisables" - }, - "notEnabled": { - "title": "La compétence « {skill} » n’est pas encore activée pour {agent}", - "description": "Activez-la dans les Paramètres pour l’utiliser ici.", - "action": "Activer", - "hint": "Compétence non activée" - }, - "scrollPrev": "Afficher les compétences précédentes", - "scrollNext": "Afficher plus de compétences" - } - }, - "agentSelector": { - "noEnabledAgents": "Aucun agent activé", - "openAgentsSettings": "Ouvrir les paramètres des agents", - "notInstalled": "Non installé", - "moreAgents": "Plus d'agents ({count})" - }, - "subAgentOverlay": { - "title": "Sous-agents", - "collapsedSummary": "Sous-agents {count}", - "collapseAria": "Réduire les sous-agents" - }, - "agentPlanOverlay": { - "title": "Plan de l'agent", - "collapsePlanAria": "Réduire le plan", - "collapsedSummary": "Plan de travail {completed}/{total}", - "status": { - "completed": "Terminé", - "inProgress": "En cours", - "pending": "En attente", - "unknown": "Inconnu" - }, - "priority": { - "high": "Haute", - "medium": "Moyenne", - "low": "Basse", - "unknown": "Inconnue" - } - }, - "permissionDialog": { - "subtitle": "L'agent demande une autorisation pour continuer ce tour.", - "queuedCount": "+{count} en attente", - "kindFallbackTool": "outil", - "command": "Commande", - "cwd": "Répertoire de travail : {cwd}", - "filesSummary": "Fichiers : {count}", - "moreFiles": "+{count} fichiers supplémentaires", - "plan": "Plan de travail", - "allowedActions": "Actions autorisées", - "targetMode": "Mode cible : {mode}", - "optionGrants": "Ce que chaque option accorde", - "changeScopeSession": "Cette session", - "changeScopeProcess": "Cette exécution", - "changeScopeUser": "Enregistré dans les paramètres utilisateur", - "changeScopeProject": "Enregistré dans les paramètres du projet", - "changeScopeProjectLocal": "Enregistré dans les paramètres locaux du projet", - "changeScopePersistent": "Enregistré définitivement" - }, - "questionDialog": { - "title": "L'agent pose une question", - "placeholder": "Tapez votre réponse...", - "send": "Envoyer" - }, - "messageBranch": { - "previousBranchAria": "Branche précédente", - "nextBranchAria": "Branche suivante", - "pageOf": "{current} sur {total}" - }, - "terminal": { - "title": "Console", - "running": "En cours" - }, - "reasoning": { - "thinking": "Réflexion…", - "thoughtForFewSeconds": "Réflexion", - "thoughtForSeconds": "Réflexion" - }, - "linkSafety": { - "errorCannotOpen": "Impossible d'ouvrir le fichier local", - "errorNoWorkspace": "Aucun dossier d'espace de travail n'est actuellement actif.", - "errorFailedOpen": "Échec de l'ouverture du fichier local", - "errorFailedLink": "Échec de l'ouverture du lien", - "errorUnsupportedLinkProtocol": "Ce protocole de lien n’est pas pris en charge." - }, - "fileActions": { - "openInFinder": "Ouvrir dans Finder", - "openInExplorer": "Ouvrir dans Explorer", - "openInFileManager": "Ouvrir dans le gestionnaire de fichiers", - "copyRelativePath": "Copier le chemin relatif", - "copyAbsolutePath": "Copier le chemin absolu", - "pathCopied": "Chemin copié", - "copyPathFailed": "Échec de la copie du chemin", - "openFailed": "Échec de l'ouverture du fichier local" - }, - "messageList": { - "attachedResources": "Ressources jointes", - "loading": "Chargement...", - "loadEarlier": "Charger les messages précédents", - "loadingEarlier": "Chargement des messages précédents…", - "error": "Erreur : {message}", - "errorTitle": "Échec du chargement de la session", - "errorActionReload": "Recharger", - "errorActionNewSession": "Nouvelle conversation", - "emptyConversation": "Aucun message dans cette conversation.", - "systemMessage": "Message système", - "copyMessage": "Copier", - "copied": "Copié", - "downloadImage": "Télécharger l'image", - "downloadFailed": "Échec du téléchargement : {message}", - "imageGeneration": "Génération d'image", - "imageGenerationPending": "Génération de l'image…", - "imageGenerationFailed": "Échec de la génération d'image", - "model": "Modèle", - "tokenStats": "Utilisation des tokens", - "tokenInput": "Entrée", - "tokenOutput": "Sortie", - "tokenCacheRead": "Lecture du cache", - "tokenCacheWrite": "Écriture du cache", - "duration": "Durée", - "completedAt": "Terminé à", - "jumpToPreviousUserMessage": "Aller au message utilisateur", - "showMore": "Afficher plus", - "showLess": "Afficher moins" - }, - "liveTurnStats": { - "thinking": "Réflexion...", - "streaming": "Diffusion", - "elapsedHours": "{value} h", - "elapsedMinutes": "{value} min", - "elapsedSeconds": "{value} s", - "outputSpeedAria": "Vitesse de sortie estimée", - "outputSpeedTooltip": "Vitesse de sortie estimée (texte + raisonnement)" - }, - "jsonTree": { - "viewRaw": "Afficher le JSON brut", - "viewTree": "Afficher l'arborescence", - "fields": "{count, plural, one {# champ} other {# champs}}", - "items": "{count, plural, one {# élément} other {# éléments}}" - }, - "tool": { - "parameters": "Paramètres", - "error": "Erreur", - "result": "Résultat", - "status": { - "approvalRequested": "En attente d'approbation", - "approvalResponded": "Répondu", - "inputAvailable": "En cours", - "inputStreaming": "En attente", - "outputAvailable": "Terminé", - "outputDenied": "Refusé", - "outputError": "Erreur" - } - }, - "toolCallBlock": { - "tool": "Outil", - "error": "Erreur", - "result": "Résultat" - }, - "delegation": { - "subAgentRunning": "Sous-agent en cours…", - "noDetail": "Aucun détail disponible pour le moment.", - "unknownAgent": "Sous-agent", - "openDetail": "Voir la conversation", - "detailTitle": "Conversation du sous-agent", - "detailDescription": "Vue en lecture seule de la conversation du sous-agent délégué.", - "waitForResult": "En attente du résultat de la tâche {task}", - "waitForResultNoTask": "En attente du résultat de la tâche", - "cancelTask": "Annulation de la tâche {task}", - "cancelTaskNoTask": "Annulation de la tâche", - "resultPageOf": "{current} / {total}", - "prevResult": "Résultat précédent", - "nextResult": "Résultat suivant", - "noResultText": "Aucun résultat pour cette vérification.", - "status": { - "starting": "démarrage", - "running": "en cours", - "checked": "vérifié", - "waiting": "en attente d'approbation", - "ok": "terminé", - "err": { - "default": "échec", - "delegation_disabled": "désactivé", - "depth_limit": "limite de profondeur", - "invalid_agent_type": "agent invalide", - "spawn_failed": "échec du démarrage", - "send_failed": "échec de l'envoi", - "timeout": "délai dépassé", - "canceled": "annulé", - "child_refusal": "sous-agent refusé", - "child_max_tokens": "sous-agent : limite de jetons", - "child_max_turn_requests": "sous-agent : limite de requêtes", - "child_empty": "sous-agent sans sortie", - "child_unknown": "sous-agent : erreur", - "unknown": "tâche inconnue" - } - } - }, - "contentParts": { - "showingTailOutput": "Affichage de la fin de la sortie pendant le streaming pour de meilleures performances.", - "result": "Résultat", - "unknown": "inconnu", - "inputTruncated": "L'entrée a été tronquée — le diff peut être incomplet.", - "replaceAll": "TOUT REMPLACER", - "filesCount": "Fichiers : {count}", - "update": "mettre à jour", - "moreFiles": "+{count} fichiers supplémentaires", - "timeoutMs": "Délai d'expiration : {timeout}ms", - "backgroundTrue": "Arrière-plan : true", - "scriptToolCalls": "{count, plural, one {# appel d'outil} other {# appels d'outil}}", - "offset": "Décalage : {offset}", - "limit": "Limite : {limit}", - "pages": "Pages : {pages}", - "mode": "Mode : {mode}", - "cell": "Cellule : {cell}", - "shellSession": "Session {id}", - "pathLabel": "Chemin :", - "globLabel": "Glob :", - "typeLabel": "Type :", - "outputLabel": "Sortie :", - "caseInsensitive": "Insensible à la casse", - "multiline": "Multiligne", - "promptLabel": "Instruction", - "subjectLabel": "Sujet", - "taskLabel": "Tâche", - "nameLabel": "Nom :", - "agentPromptLabel": "Instruction", - "agentModelLabel": "Modèle", - "agentRunning": "En cours...", - "agentLiveTranscript": "Activité en direct", - "agentProgressTools": "{count} appels d'outils", - "agentProgressTurns": "{count} tours", - "agentProgressContext": "contexte {pct}%", - "agentSessionAction": "Voir la session du sous-agent", - "agentSessionTitle": "Session du sous-agent", - "agentSessionLoading": "Chargement de la transcription du sous-agent…", - "agentSessionEmpty": "Le sous-agent n'a encore rien écrit.", - "agentFallbackTitle": "Démarrage du sous-agent…", - "agentCodexLaunchOnly": "Lancé. Codex ne signale plus la progression de ce sous-agent : son résultat arrivera sous forme de message dans cette conversation.", - "agentStatsBash": "Commandes", - "agentStatsRead": "Fichiers lus", - "agentStatsSearch": "Recherches", - "agentStatsEdit": "Modifications", - "agentStatsOther": "Autres", - "goal": { - "title": "Objectif :", - "titleWithStatus": "Objectif {status}", - "objective": "Objectif", - "statusLabel": "Statut", - "tokensUsed": "Tokens utilisés", - "budget": "Budget", - "remaining": "Restant", - "elapsed": "Écoulé", - "tokens": "tokens", - "pause": "Pause", - "clear": "Effacer", - "status": { - "active": "actif", - "paused": "en pause", - "blocked": "bloqué", - "usageLimited": "utilisation limitée", - "budgetLimited": "budget limité", - "complete": "terminé", - "limited": "limite atteinte" - } - }, - "field": { - "file": "Fichier", - "notebook": "Carnet", - "command": "Commande", - "old": "Ancien", - "new": "Nouveau", - "pattern": "Motif", - "path": "Chemin", - "query": "Requête", - "url": "URL :", - "description": "Détails", - "content": "Contenu", - "source": "Origine", - "prompt": "Instruction", - "subject": "Sujet", - "taskId": "ID de tâche", - "status": "Statut", - "skill": "Skill", - "args": "Arguments", - "offset": "Décalage", - "limit": "Limite", - "glob": "Motif glob", - "type": "Type de donnée", - "output": "Sortie", - "replaceAll": "Tout remplacer", - "language": "Langue", - "timeout": "Délai", - "background": "Arrière-plan", - "agentType": "Type d'agent", - "library": "Bibliothèque", - "libraryId": "ID de bibliothèque" - }, - "title": { - "edit": "Modifier", - "command": "Commande", - "script": "Script", - "waitCommand": "Attendre {command}", - "waitCell": "Attendre la session {id}", - "terminateCommand": "Terminer {command}", - "terminateCell": "Terminer la session {id}", - "stdinChars": "Entrée {chars}", - "todoWrite": "TodoWrite (mise à jour des tâches)", - "read": "Lire", - "write": "Écrire", - "notebookEdit": "NotebookEdit (édition du carnet)", - "editFiles": "Modifier ({count} fichiers)", - "editWithTarget": "Modifier {target}", - "readWithTarget": "Lire {target}", - "writeWithTarget": "Écrire {target}", - "notebookEditWithTarget": "NotebookEdit ({target})", - "globWithPattern": "Motif glob {pattern}", - "listFilesWithPath": "Lister les fichiers {path}", - "grepWithPattern": "Motif grep {pattern}", - "taskCreateWithSubject": "Créer une tâche : {subject}", - "taskUpdateWithStatus": "Mettre à jour la tâche #{id} -> {status}", - "taskUpdate": "Mettre à jour la tâche #{id}", - "webFetchWithUrl": "WebFetch ({url})", - "webSearchWithQuery": "Recherche web : {query}", - "todosProgress": "Tâches ({done}/{total})", - "skillWithName": "Skill : {name}", - "genericWithContext": "{tool} ({context})" - }, - "search": { - "noMatches": "Aucune correspondance", - "matchSummary": "{matches, plural, one {# correspondance} other {# correspondances}} dans {files, plural, one {# fichier} other {# fichiers}}", - "fileSummary": "{files, plural, one {# fichier} other {# fichiers}}", - "moreResults": "{count, plural, one {# résultat supplémentaire non affiché} other {# résultats supplémentaires non affichés}}" - }, - "toolGroup": { - "search": "{count, plural, one {A exploré # recherche} other {A exploré # recherches}}", - "command": "{count, plural, one {A exécuté # commande} other {A exécuté # commandes}}", - "read": "{count, plural, one {A lu des fichiers # fois} other {A lu des fichiers # fois}}", - "memory": "{count, plural, one {A rappelé # souvenir} other {A rappelé # souvenirs}}", - "edit": "{count, plural, one {A modifié des fichiers # fois} other {A modifié des fichiers # fois}}", - "fetch": "{count, plural, one {A récupéré # ressource} other {A récupéré # ressources}}", - "think": "{count, plural, one {A réfléchi # fois} other {A réfléchi # fois}}", - "todo": "{count, plural, one {A mis à jour # tâche} other {A mis à jour # tâches}}", - "task": "{count, plural, one {A lancé # tâche} other {A lancé # tâches}}", - "other": "{count, plural, one {A utilisé # outil} other {A utilisé # outils}}", - "errorSuffix": "{count, plural, one {# échec} other {# échecs}}", - "joiner": " · " - }, - "planMode": { - "entered": "Mode planification activé", - "planLabel": "Plan", - "reviewApproved": "Plan approuvé — mise en œuvre", - "reviewKept": "Reste en mode plan", - "reviewPending": "En attente de la décision sur le plan", - "submitted": "Plan soumis", - "switched": "Mode changé" - }, - "backgroundTask": { - "title": "Tâche en arrière-plan", - "titleWithId": "Tâche en arrière-plan · {id}", - "running": "En cours", - "completed": "Terminée", - "failed": "Échouée", - "stopped": "Arrêtée", - "exitCode": "sortie {code}", - "polledTimes": "Interrogée {count} fois", - "runningInBackground": "Arrière-plan", - "launchNote": "En cours d'exécution en arrière-plan · {id}" - }, - "codexScript": { - "outputMissing": "Codex a tronqué la sortie du script et supprimé le séparateur de cette commande ; aucune sortie n'a donc pu lui être attribuée.", - "sharedWith": "Contient aussi la sortie de {commands} — codex en a tronqué les séparateurs.", - "truncated": "tronqué" - } - }, - "messageNav": { - "title": "Navigation des messages", - "collapse": "Réduire la navigation des messages", - "collapsedSummary": "Messages {count}", - "fileCount": "{count, plural, one {# fichier} other {# fichiers}}", - "remove": "Retirer", - "noDiffDataAvailable": "Aucune donnée de diff disponible pour {filePath}" - }, - "replyArtifacts": { - "title": "Fichiers modifiés", - "fileCount": "{count, plural, one {# fichier} other {# fichiers}}", - "newFilesTitle": "Nouveaux fichiers", - "revealInFolder": "Afficher dans le gestionnaire de fichiers", - "openFile": "Ouvrir {filePath}", - "openInEditor": "Ouvrir dans l'éditeur", - "remove": "Retirer", - "noDiffDataAvailable": "Aucune donnée de diff disponible pour {filePath}" - }, - "askQuestion": { - "title": "L'agent attend votre choix", - "subtitle": "Répondez puis envoyez. Vous pouvez ignorer à tout moment.", - "recommended": "Recommandé", - "other": "Autre", - "otherPlaceholder": "Saisissez votre réponse…", - "singleSelect": "Unique", - "multiSelect": "Multiple", - "skip": "Ignorer", - "next": "Suivant", - "submit": "Envoyer", - "submitError": "Échec de l'envoi. Veuillez réessayer." - }, - "planApproval": { - "title": "L'agent a un plan — à vérifier", - "emptyPlan": "L'agent n'a pas rédigé de plan. Approuvez pour commencer ou demandez des modifications.", - "approve": "Approuver et lancer", - "requestChanges": "Demander des modifications", - "abandon": "Abandonner", - "feedbackPlaceholder": "Que faut-il changer ?", - "sendChanges": "Envoyer", - "cancel": "Annuler", - "submitError": "Échec de l'envoi. Veuillez réessayer." - }, - "feedbackCheckResult": { - "count": "{count, plural, =1 {1 retour} other {# retours}}", - "expand": "Afficher tous les retours", - "collapse": "Réduire", - "errorTitle": "Échec de la vérification des retours" - }, - "askQuestionResult": { - "title": "Question", - "answeredLabel": "Question et réponse :", - "awaiting": "En attente de ta réponse…", - "declined": "Tu as ignoré cette question — l’agent a utilisé son propre jugement.", - "noSelection": "Aucune sélection" - }, - "configStale": { - "agentConfigTitle": "Paramètres de l'agent mis à jour", - "modelProviderTitle": "Fournisseur de modèle mis à jour", - "description": "Cette session utilise encore son ancienne configuration. Reconnectez-vous pour l'appliquer (l'historique de conversation est conservé).", - "reconnect": "Reconnecter pour appliquer", - "reconnecting": "Reconnexion…", - "reconnectDisabledDuringTurn": "Disponible une fois le tour en cours terminé", - "dismiss": "Ignorer", - "reconnectFailed": "Échec de la reconnexion de la session", - "applied": "Nouvelle configuration appliquée" - }, - "piProjectTrust": { - "title": "Ce projet fournit des ressources pi", - "description": "pi ne charge pas les fichiers .pi du dépôt. Examinez-les pour décider.", - "descriptionExecutable": "Le dépôt fournit des extensions pi, qui exécutent du code au démarrage. pi ne les charge pas. Examinez-les avant de décider.", - "review": "Examiner…", - "dismiss": "Ignorer", - "dialogTitle": "Faire confiance aux ressources pi de ce projet ?", - "dialogDescription": "pi ne charge les fichiers .pi d'un dépôt que si vous faites confiance au dossier. N'accordez votre confiance que si vous avez confiance dans le contenu de ce dépôt.", - "executionWarning": "Les extensions sont du code. En faisant confiance à ce dossier, vous autorisez le dépôt à les exécuter au démarrage de pi avec vos permissions, avant même l'envoi d'un message.", - "scopeNote": "La décision est enregistrée dans le trust.json de pi pour ce dossier, s'applique à tous les dossiers qu'il contient et sert aussi lorsque vous lancez pi vous-même dans un terminal. Vous pourrez la modifier dans Paramètres → Agents → Pi.", - "trust": "Faire confiance au projet", - "decline": "Ne pas charger", - "disabledDuringTurn": "Disponible une fois le tour en cours terminé", - "trustedToast": "Projet approuvé — reconnexion effectuée pour que pi charge ses ressources", - "declinedToast": "Les ressources du projet restent non chargées", - "saveFailed": "Échec de l'enregistrement de la décision de confiance du projet", - "grantTitle": "Ce projet est déjà approuvé", - "grantDescription": "pi charge les fichiers .pi du dépôt. Examinez ce que cela autorise.", - "grantInheritedDescription": "Un dossier parent est approuvé, donc pi charge les fichiers .pi du dépôt. Examinez ce que cela autorise.", - "grantDialogTitle": "Les ressources pi de ce projet sont approuvées", - "grantDialogDescription": "pi est autorisé à charger les fichiers .pi du dépôt. Les versions précédentes de codeg accordaient cela automatiquement à l'ouverture d'un dossier, la question ne vous a donc peut-être jamais été posée.", - "grantExecutionWarning": "Les extensions sont du code. Le dépôt les exécute au démarrage de pi avec vos permissions, avant même l'envoi d'un message.", - "inheritedFrom": "Approuvé via", - "revoke": "Révoquer la confiance", - "keepTrusted": "Conserver la confiance", - "revokedToast": "Confiance révoquée — reconnexion effectuée pour que pi cesse de charger les ressources du projet", - "trustedNoReconnect": "Projet approuvé — effectif au prochain démarrage de pi", - "revokedNoReconnect": "Confiance révoquée — effectif au prochain démarrage de pi" - }, - "collabAgent": { - "title": "Sous-agent", - "errorTitle": "Échec de la tâche du sous-agent", - "statesLabel": "Sous-agents", - "statusRunning": "En cours", - "statusCompleted": "Terminé", - "statusFailed": "Échec", - "statusPending": "Démarrage", - "statusInterrupted": "Interrompu", - "statusClosed": "Fermé", - "statusNotFound": "Introuvable", - "opSpawn": "Démarrage du sous-agent", - "opWait": "Récupération du résultat du sous-agent", - "opClose": "Fermeture du sous-agent", - "opResume": "Reprise du sous-agent" - }, - "contextCompaction": { - "compacting": "Compactage du contexte…", - "compacted": "Contexte compacté", - "compactedTokens": "Contexte compacté · {before} → {after} tokens", - "failed": "Échec de la compaction du contexte" - }, - "sessionFailure": { - "category": { - "connection": "Problème de connexion", - "access": "Problème d'accès", - "limit": "Limite atteinte", - "request": "Requête rejetée", - "service": "Problème de service", - "unknown": "Problème de session" - }, - "action": { - "retry": "Réessayer", - "login": "Se connecter", - "newSession": "Nouvelle session" - }, - "recovered": "Rétabli", - "retryUnavailable": "Aucun message précédent à renvoyer.", - "toggleDetails": "Afficher/masquer les détails" - }, - "backgroundTasks": { - "running": "{count, plural, one {# tâche en arrière-plan en cours} other {# tâches en arrière-plan en cours}}", - "settling": "Synchronisation des résultats d'arrière-plan…", - "settledFallback": "Tâche en arrière-plan terminée ({status})", - "cardRunning": "En cours d'exécution en arrière-plan", - "cardLaunchedPending": "Tâche lancée en arrière-plan", - "cardCompleted": "Tâche en arrière-plan terminée", - "cardFinishedWithStatus": "Tâche en arrière-plan terminée ({status})", - "cardResultPending": "Résultat pas encore reçu" - }, - "proposedPlan": { - "title": "Plan proposé", - "planning": "Planification…" - } - }, - "diffPreview": { - "mode": { - "added": "Ajouté", - "deleted": "Supprimé", - "renamed": "Renommé", - "modified": "Modifié" - }, - "hunkLabel": "Bloc {index}", - "loadingHunk": "Chargement du hunk...", - "noDiffData": "Aucune donnée diff", - "showRemainingLines": "Afficher {count} lignes de plus" - }, - "conversationContextBar": { - "folderTitle": "Dossier de travail", - "branchTitle": "Branche de travail", - "searchFolder": "Rechercher un dossier...", - "searchBranch": "Rechercher une branche...", - "noFolders": "Aucun dossier", - "noBranches": "Aucune branche", - "noBranch": "(aucune branche)", - "chatModeLabel": "Mode chat", - "commit": "Valider", - "push": "Pousser", - "merge": "Fusionner", - "toasts": { - "folderChanged": "Basculé vers {name}", - "openFolderFailed": "Échec de l'ouverture du dossier", - "switchedToChatMode": "Basculé en mode discussion", - "openStashFailed": "Échec de l'ouverture de la fenêtre de remisage", - "openMergeFailed": "Échec de l'ouverture de la fenêtre de fusion" - } - }, - "cloneDialog": { - "title": "Cloner un dépôt", - "repositoryUrl": "URL du dépôt", - "repositoryUrlPlaceholder": "https://github.com/user/repo.git", - "directory": "Répertoire", - "directoryPlaceholder": "Sélectionnez le répertoire cible...", - "browseDirectory": "Parcourir le répertoire", - "cancel": "Annuler", - "clone": "Cloner", - "clonePath": "Chemin de clonage : {path}" - }, - "toasts": { - "cloneFailed": "Échec du clonage du dépôt" - } - }, - "ProjectBoot": { - "title": "Lanceur de projet", - "tabs": { - "shadcn": "shadcn", - "hyperframes": "HyperFrames" - }, - "hyperframes": { - "title": "Projet vidéo HyperFrames", - "subtitle": "Générez un projet HTML-vers-vidéo. L'agent de l'espace de travail peut ensuite l'écrire et le rendre.", - "resolution": "Résolution", - "skillsTitle": "Skills des agents", - "skillsDesc": "Installe globalement les skills HyperFrames (lien symbolique) pour les agents sélectionnés, afin qu'ils puissent créer et rendre des vidéos.", - "recheck": "Revérifier", - "installedBadge": "Installé", - "skillsInstall": "Installer / mettre à jour les skills", - "skillsInstalling": "Installation des skills…", - "skillsInstalled": "Skills HyperFrames installées", - "skillsInstallFailed": "Impossible d'installer les skills HyperFrames" - }, - "config": { - "base": "Base", - "style": "Style", - "baseColor": "Couleur de base", - "theme": "Thème", - "chartColor": "Couleur du graphique", - "iconLibrary": "Bibliothèque d'icônes", - "font": "Police", - "fontHeading": "Police de titre", - "menuAccent": "Accent du menu", - "menuColor": "Couleur du menu", - "radius": "Rayon", - "template": "Modèle", - "createProject": "Créer un projet", - "sectionStyle": "Style", - "sectionColors": "Couleurs", - "sectionTypography": "Typographie", - "sectionInterface": "Interface" - }, - "preview": { - "loading": "Chargement de l'aperçu..." - }, - "createDialog": { - "title": "Créer un projet", - "projectName": "Nom du projet", - "projectNamePlaceholder": "mon-app", - "frameworkTemplate": "Modèle de framework", - "packageManager": "Gestionnaire de paquets", - "saveDirectory": "Répertoire de sauvegarde", - "saveDirectoryPlaceholder": "Sélectionner un répertoire...", - "browseDirectory": "Parcourir", - "projectPath": "Le projet sera créé dans : {path}", - "advancedOptions": "Options avancées", - "base": "Bibliothèque de base", - "enableRtl": "Activer le support RTL", - "enableRtlDescription": "Activer la prise en charge de la mise en page pour les langues de droite à gauche (ex. arabe, hébreu)", - "pmChecking": "Vérification...", - "pmNotInstalled": "Non installé", - "cancel": "Annuler", - "create": "Créer", - "creating": "Création du projet..." - }, - "toasts": { - "createFailed": "Échec de la création du projet", - "createSuccess": "Projet créé avec succès", - "openWorkspaceFailed": "Projet créé, mais impossible de l'ouvrir dans l'espace de travail" - }, - "errors": { - "directoryExists": "Le répertoire cible existe déjà", - "commandFailed": "La commande de création du projet a échoué." - } - }, - "WebServiceSettings": { - "addressSwitchHint": "Changer ne modifie que l'adresse affichée et ouverte ici ; le service écoute sur toutes les interfaces et reste accessible à chaque adresse.", - "sectionTitle": "Service Web", - "sectionDescription": "Activer pour accéder à Codeg à distance via le navigateur", - "port": "Port", - "status": "Statut", - "autoStart": "Démarrage auto", - "autoStartHint": "Démarrer le service Web au lancement de Codeg", - "running": "En cours", - "stopped": "Arrêté", - "processing": "Traitement...", - "start": "Démarrer", - "stop": "Arrêter", - "startFailed": "Échec du démarrage", - "stopFailed": "Échec de l'arrêt", - "saveConfigFailed": "Échec de l'enregistrement des paramètres du service Web", - "open": "Ouvrir", - "hide": "Masquer", - "show": "Afficher", - "copy": "Copier", - "qrcode": "Code QR", - "qrcodeTitle": "Scanner pour ouvrir", - "qrcodeHint": "Scannez avec votre téléphone pour ouvrir Codeg dans un navigateur", - "addressLabel": "Adresse d'accès", - "tokenLabel": "Token d'accès", - "tokenHint": "Entrez ce token lors du premier accès au client Web", - "tokenPlaceholder": "Laisser vide pour générer automatiquement", - "regenerate": "Régénérer", - "stalePortOccupiedTitle": "Le port {port} est utilisé par un autre processus", - "stalePortUnknownTitle": "L'état du port {port} est indéterminé", - "stalePortHint": "Codeg ne peut pas s'attacher tant que le port n'est pas libéré. Changez de port ci-dessus, ou fermez le processus qui le retient.", - "errors": { - "alreadyRunning": "Le service Web est déjà en cours d'exécution", - "invalidAddress": "Format d'hôte ou de port non valide", - "portInUse": "Le port {port} est déjà utilisé. Fermez le processus qui l'utilise ou choisissez un autre port.", - "permissionDenied": "Permission refusée. Utilisez un port supérieur à 1024 ou exécutez avec des privilèges plus élevés.", - "addressUnavailable": "Cette adresse n'est pas disponible sur cette machine", - "bindFailed": "Échec de la liaison à l'adresse" - } - }, - "DirectoryBrowser": { - "title": "Parcourir le répertoire", - "pathPlaceholder": "Entrez le chemin du répertoire...", - "goHome": "Aller au répertoire personnel", - "navigateUp": "Aller au répertoire parent", - "select": "Sélectionner", - "cancel": "Annuler", - "loading": "Chargement...", - "emptyDirectory": "Ce répertoire est vide", - "errorLoadingDir": "Échec du chargement du répertoire", - "permissionDenied": "Permission refusée" - }, - "ChatChannelSettings": { - "loading": "Chargement...", - "sectionTitle": "Canaux de chat", - "sectionDescription": "Configurez des bots IM pour recevoir des notifications d'événements et interroger l'activité de codage.", - "addChannel": "Ajouter un canal", - "noChannels": "Aucun canal de chat configuré pour le moment.", - "channelName": "Nom", - "channelNamePlaceholder": "Mon bot Telegram", - "channelType": "Type de canal", - "lark": "Lark (Feishu)", - "weixin": "WeChat", - "dailyReport": "Rapport quotidien", - "dailyReportTime": "Heure du rapport", - "nameRequired": "Le nom du canal est requis.", - "tokenRequired": "Le token est requis.", - "chatIdRequired": "Le Chat ID est requis.", - "topicMode": "Mode groupe de sujets", - "topicModeHint": "Route les sujets de forum Telegram comme des sessions Codeg séparées. Le bot doit être dans un supergroupe forum et pouvoir gérer les sujets.", - "loadFailed": "Échec du chargement des canaux.", - "saveFailed": "Échec de l'enregistrement.", - "connectSuccess": "Canal connecté.", - "connectFailed": "Échec de la connexion", - "disconnectSuccess": "Canal déconnecté.", - "disconnectFailed": "Échec de la déconnexion.", - "testSuccess": "Test de connexion réussi.", - "testFailed": "Test de connexion échoué", - "deleteSuccess": "Canal supprimé.", - "deleteFailed": "Échec de la suppression du canal.", - "deleteConfirmTitle": "Supprimer le canal", - "deleteConfirmMessage": "Le canal et ses journaux de messages seront définitivement supprimés. Êtes-vous sûr ?", - "cancel": "Annuler", - "delete": "Supprimer", - "create": "Créer", - "save": "Enregistrer", - "channelListTitle": "Canaux configurés", - "channelListDescription": "Les canaux activés se connectent automatiquement au démarrage du service.", - "editChannel": "Modifier le canal", - "editSuccess": "Canal mis à jour.", - "tokenPlaceholderKeep": "Laisser vide pour conserver l'actuel", - "weixinScanTitle": "Scanner le QR code", - "weixinScanDescription": "Ouvrez WeChat et scannez le QR code pour vous connecter.", - "weixinQrcodeExpired": "QR code expiré.", - "weixinRefreshQrcode": "Actualiser", - "weixinWaitingScan": "En attente du scan...", - "weixinPollError": "Connexion instable, nouvelle tentative...", - "weixinReconnectNotice": "En raison des limitations du protocole iLink, après chaque reconnexion vous devez envoyer un message au bot pour que les déclencheurs d'événements prennent effet.", - "connect": "Connecter", - "disconnect": "Déconnecter", - "test": "Tester la connexion", - "tabs": { - "channels": "Canaux", - "commands": "Commandes", - "events": "Événements", - "other": "Autres" - }, - "commands": { - "title": "Commandes intégrées", - "description": "Commandes bot disponibles dans les canaux de chat. Dans les chats de groupe, @Bot est requis pour traiter les messages.", - "prefixLabel": "Préfixe de commande", - "prefixDescription": "1-3 caractères non alphanumériques pour déclencher les commandes du bot (par défaut /).", - "prefixSaved": "Préfixe de commande enregistré.", - "prefixSaveFailed": "Échec de l'enregistrement du préfixe.", - "prefixInvalid": "Le préfixe doit être de 1-3 caractères non alphanumériques.", - "save": "Enregistrer", - "folderDesc": "Sélectionner le dossier de travail", - "agentDesc": "Sélectionner l'agent IA", - "taskDesc": "Créer une session et exécuter la tâche", - "sessionsDesc": "Lister les sessions actives du dossier", - "resumeDesc": "Conversations récentes / reprendre une session", - "cancelDesc": "Annuler la tâche en cours", - "approveDesc": "Approuver la demande de permission de l'agent", - "denyDesc": "Refuser la demande de permission de l'agent", - "searchDesc": "Rechercher des conversations par mot-clé", - "todayDesc": "Résumé de l'activité du jour", - "statusDesc": "État de connexion du canal", - "helpDesc": "Afficher l'aide" - }, - "events": { - "title": "Notifications d'événements", - "description": "Une fois activés, les événements déclenchés seront envoyés au canal.", - "turnComplete": "Tour terminé", - "turnCompleteDesc": "Lorsqu'un tour d'agent se termine", - "error": "Erreur de l'agent", - "errorDesc": "Lorsqu'un agent rencontre une erreur", - "permissionRequest": "Demande d'autorisation", - "permissionRequestDesc": "Lorsqu'un agent demande une autorisation", - "questionRequest": "Question de l'agent", - "questionRequestDesc": "Quand un agent vous pose une question", - "userPromptSent": "Message de l'utilisateur", - "userPromptSentDesc": "Lorsque vous envoyez un message (le texte du message est inclus dans la notification)", - "saved": "Filtre d'événements mis à jour.", - "saveFailed": "Échec de l'enregistrement du filtre d'événements.", - "loadFailed": "Échec du chargement des paramètres.", - "retry": "Réessayer", - "webhooksTitle": "Webhooks", - "webhooksDescription": "Envoie une charge JSON via POST vers une ou plusieurs URL lorsqu'un événement activé se déclenche. Le filtre d'événements ci-dessus s'applique aussi aux webhooks.", - "webhookUrlPlaceholder": "https://example.com/webhook", - "addWebhook": "Ajouter un webhook", - "removeWebhook": "Supprimer le webhook", - "webhookSave": "Enregistrer", - "webhooksSaved": "Webhooks enregistrés.", - "webhooksSaveFailed": "Échec de l'enregistrement des webhooks.", - "webhookInvalidUrl": "Saisissez des URL http(s) valides.", - "docsTitle": "Format de la requête", - "docsMethod": "Méthode", - "docsContentType": "Content-Type", - "docsNote": "Chaque événement activé est envoyé à toutes les URL. Les webhooks ne sont pas anti-rebond ; le filtre d'événements ci-dessus s'applique toujours.", - "editWebhook": "Modifier le webhook", - "enableWebhook": "Activer le webhook", - "webhookDuplicate": "Cette URL est déjà configurée.", - "cancel": "Annuler", - "webhooksEmpty": "Aucun webhook configuré pour le moment.", - "deleteWebhookTitle": "Supprimer le webhook", - "deleteWebhookMessage": "Supprimer ce webhook ? Les événements ne seront plus envoyés à cette URL.", - "delete": "Supprimer" - }, - "language": { - "title": "Langue des messages", - "description": "Langue utilisée pour les notifications d'événements, les réponses aux commandes et les rapports quotidiens envoyés aux canaux de chat.", - "saved": "Langue des messages enregistrée.", - "saveFailed": "Échec de l'enregistrement de la langue des messages.", - "en": "Anglais", - "zh-cn": "Chinois simplifié", - "zh-tw": "Chinois traditionnel", - "ja": "Japonais", - "ko": "Coréen", - "es": "Espagnol", - "de": "Allemand", - "fr": "Français", - "pt": "Portugais", - "ar": "Arabe" - } - }, - "ModelProviderSettings": { - "sectionTitle": "Fournisseurs de Modèles", - "sectionDescription": "Gérer les identifiants des fournisseurs d'API pour les agents.", - "filterAll": "Tous", - "providerListTitle": "Fournisseurs Configurés", - "addProvider": "Ajouter un Fournisseur", - "editProvider": "Modifier le Fournisseur", - "noProviders": "Aucun fournisseur de modèle configuré.", - "providerName": "Nom", - "providerNamePlaceholder": "Ex. OpenAI, Anthropic", - "apiUrl": "URL de l'API", - "apiUrlPlaceholder": "https://api.openai.com/v1", - "apiKey": "Clé API", - "apiKeyPlaceholder": "sk-...", - "apiKeyKeepCurrent": "Laisser vide pour conserver l'actuelle", - "agentTypes": "Types d'Agent", - "agentTypesRequired": "Au moins un type d'agent est requis.", - "agentType": "Type d'Agent", - "agentTypeRequired": "Le type d'agent est requis.", - "agentTypeImmutableHint": "Le type d'agent ne peut pas être modifié après la création.", - "model": "Modèle", - "modelPlaceholderCodex": "gpt-5.6-sol / gpt-5.5", - "modelPlaceholderGemini": "gemini-3-pro-preview", - "claudeMainModel": "Modèle Principal", - "claudeReasoningModel": "Modèle de Raisonnement (réflexion)", - "claudeHaikuDefaultModel": "Modèle Haiku par Défaut", - "claudeSonnetDefaultModel": "Modèle Sonnet par Défaut", - "claudeOpusDefaultModel": "Modèle Opus par Défaut", - "claudeCustomModelOption": "ID de modèle personnalisé", - "claudeCustomModelOptionName": "Nom du modèle personnalisé", - "claudeCustomModelOptionDescription": "Description du modèle personnalisé", - "claudeCustomModelOptionHint": "Ajoute une entrée personnalisée au sélecteur de modèles de Claude (par exemple un modèle derrière une passerelle/un proxy personnalisé). Le nom et la description sont des informations d'affichage facultatives.", - "nameRequired": "Le nom du fournisseur est requis.", - "apiUrlRequired": "L'URL de l'API est requise.", - "apiKeyRequired": "La clé API est requise.", - "loadFailed": "Échec du chargement des fournisseurs.", - "saveFailed": "Échec de la sauvegarde.", - "createSuccess": "Fournisseur créé.", - "editSuccess": "Fournisseur mis à jour.", - "deleteSuccess": "Fournisseur supprimé.", - "deleteConfirmTitle": "Supprimer le Fournisseur", - "deleteConfirmMessage": "Le fournisseur \"{name}\" sera définitivement supprimé. Êtes-vous sûr ?", - "deleteBlockedByAgent": "{agents} utilise ce fournisseur. Veuillez le dissocier avant de supprimer.", - "cancel": "Annuler", - "delete": "Supprimer", - "create": "Créer", - "save": "Enregistrer", - "affectedRunningSessions": "{count, plural, one {# session active doit se reconnecter pour appliquer la modification} other {# sessions actives doivent se reconnecter pour appliquer la modification}}" - }, - "SkillMatrix": { - "loading": "Chargement…", - "searchPlaceholder": "Rechercher par nom, id ou description", - "empty": "Rien à afficher.", - "emptySearch": "Aucun résultat pour la recherche actuelle.", - "skillColumn": "Compétence", - "selectAll": "Tout sélectionner (visible)", - "selectSkill": "Sélectionner {name}", - "everything": { - "label": "En masse", - "enable": "Tout activer (visible)", - "disable": "Tout désactiver (visible)" - }, - "columnMenu": { - "enableAll": "Activer toutes les compétences", - "disableAll": "Désactiver toutes les compétences" - }, - "rowMenu": { - "label": "Actions groupées pour {name}", - "enableAll": "Activer pour tous les agents", - "disableAll": "Désactiver pour tous les agents" - }, - "bulk": { - "selected": "{count} sélectionné(s)", - "targetAll": "Tous les agents", - "targetSome": "{count} agents", - "enable": "Activer", - "disable": "Désactiver", - "clear": "Effacer" - }, - "confirm": { - "disableTitle": "Désactiver ces liens ?", - "disableBody": "Cela supprimera {count} liens de compétences gérés par codeg. Les compétences occupant un répertoire personnalisé ne sont pas touchées. Vous pouvez les réactiver à tout moment.", - "cancel": "Annuler", - "confirm": "Désactiver" - }, - "toasts": { - "loadFailed": "Échec du chargement des états des compétences", - "applyFailed": "Échec de l'application des modifications", - "enabled": "{count} liens activés", - "disabled": "{count} liens désactivés", - "enabledPartial": "{ok} activés, {failed} échoués", - "disabledPartial": "{ok} désactivés, {failed} échoués" - }, - "detail": { - "enableForAgents": "Activer pour les agents", - "preview": "Aperçu de SKILL.md", - "loadingContent": "Chargement du contenu…" - }, - "copyModeHint": "Copié (non lié) — réactivez après les mises à jour pour obtenir la dernière version" - }, - "ExpertsSettings": { - "title": "Compétences d'experts", - "description": "Activez des workflows de compétences soigneusement sélectionnés et éprouvés pour vos agents de codage IA. Chaque expert est une compétence autonome du projet superpowers — codeg gère la copie centrale et la lie aux agents que vous choisissez.", - "loading": "Chargement des experts…", - "loadingContent": "Chargement du contenu…", - "emptyExperts": "Aucun expert disponible. Vérifiez les journaux de l'application.", - "emptySelection": "Sélectionnez un expert pour voir son contenu et gérer son activation.", - "emptySearch": "Aucun expert ne correspond à la recherche actuelle.", - "searchPlaceholder": "Rechercher des experts par nom, ID ou description", - "enableForAgents": "Activer pour les agents", - "noAgents": "Aucun agent ACP détecté.", - "copyModeWarning": "Copié (non lié). Réactivez après les mises à jour de codeg pour obtenir la dernière version.", - "previewTitle": "Aperçu de SKILL.md", - "categories": { - "discovery": "Découverte et conception", - "planning": "Planification", - "execution": "Exécution", - "quality": "Qualité et tests", - "debugging": "Débogage", - "review": "Révision et intégration", - "meta": "Méta" - }, - "states": { - "not_linked": "Non activé", - "linked_to_codeg": "Activé", - "linked_elsewhere": "Bloqué — un autre lien existe", - "blocked_by_real_directory": "Bloqué — une compétence personnalisée occupe ce nom", - "broken": "Lien cassé" - }, - "badges": { - "userModified": "Modifié par l'utilisateur" - }, - "actions": { - "openCentralDir": "Ouvrir le dossier central", - "refresh": "Actualiser" - }, - "toasts": { - "loadFailed": "Échec du chargement des détails de l'expert", - "enabled": "Expert activé pour cet agent", - "disabled": "Expert désactivé pour cet agent", - "enableFailed": "Échec de l'activation de l'expert", - "disableFailed": "Échec de la désactivation de l'expert", - "openFolderFailed": "Échec de l'ouverture du dossier" - } - }, - "ScienceSettings": { - "title": "Compétences de recherche scientifique", - "description": "Activez des compétences de recherche scientifique sélectionnées pour vos agents de codage IA : génération d'hypothèses, plan d'expérience, statistiques, visualisation, évaluation critique et recherche bibliographique. codeg gère une copie centrale et relie chaque compétence aux agents que vous choisissez.", - "loading": "Chargement des compétences scientifiques…", - "emptySkills": "Aucune compétence scientifique disponible. Consultez les journaux de l'application.", - "searchPlaceholder": "Rechercher des compétences scientifiques par nom, id ou description", - "categories": { - "ideation": "Idéation", - "design": "Plan d'étude", - "analysis": "Analyse", - "visualization": "Visualisation", - "evaluation": "Évaluation", - "literature": "Littérature" - }, - "states": { - "not_linked": "Non activé", - "linked_to_codeg": "Activé", - "linked_elsewhere": "Bloqué — un autre lien existe", - "blocked_by_real_directory": "Bloqué — une compétence personnalisée occupe ce nom", - "broken": "Lien cassé" - }, - "badges": { - "userModified": "Modifié par l'utilisateur", - "needsKey": "Clé API requise", - "needsSetup": "Configuration possible" - }, - "actions": { - "openCentralDir": "Ouvrir le dossier central", - "refresh": "Actualiser" - }, - "toasts": { - "openFolderFailed": "Échec de l'ouverture du dossier" - } - }, - "OfficeToolsSettings": { - "title": "Outils Office", - "description": "Gérez les compétences OfficeCLI pour créer des fichiers Excel, Word et PowerPoint. Installez OfficeCLI, synchronisez les compétences et activez-les par agent.", - "loadingContent": "Chargement du contenu…", - "emptySkills": "Aucune compétence disponible. Installez OfficeCLI et synchronisez les compétences.", - "emptySelection": "Sélectionnez une compétence pour voir son contenu et gérer l'activation.", - "emptySearch": "Aucune compétence correspondante.", - "searchPlaceholder": "Rechercher par nom, ID ou description", - "enableForAgents": "Activer pour les agents", - "noAgents": "Aucun agent ACP détecté.", - "installFirst": "Installez d'abord OfficeCLI pour activer les compétences.", - "syncFirst": "Synchronisez d'abord les compétences pour charger le contenu.", - "noContent": "Aucun contenu disponible.", - "copyModeWarning": "Copié (non lié). Resynchronisez pour obtenir la dernière version.", - "previewTitle": "Aperçu SKILL.md", - "detection": { - "installed": "Installé", - "notInstalled": "Non installé", - "notRunnable": "Installé mais non exécutable", - "installHint": "Installez OfficeCLI pour activer les compétences de génération de documents Office pour vos agents IA.", - "install": "Installer", - "uninstall": "Désinstaller", - "syncSkills": "Synchroniser les compétences" - }, - "categories": { - "general": "Général", - "presentations": "Présentations", - "documents": "Documents", - "spreadsheets": "Tableurs" - }, - "states": { - "not_linked": "Non activé", - "linked_to_codeg": "Activé", - "linked_elsewhere": "Bloqué — un autre lien existe", - "blocked_by_real_directory": "Bloqué — une compétence personnalisée occupe ce nom", - "broken": "Lien cassé" - }, - "badges": { - "notSynced": "Non synchronisé" - }, - "actions": { - "refresh": "Actualiser" - }, - "toasts": { - "loadFailed": "Échec du chargement des détails de la compétence", - "enabled": "Compétence activée pour cet agent", - "disabled": "Compétence désactivée pour cet agent", - "enableFailed": "Échec de l'activation de la compétence", - "disableFailed": "Échec de la désactivation de la compétence", - "installSuccess": "OfficeCLI installé avec succès", - "installFailed": "Échec de l'installation d'OfficeCLI", - "uninstallSuccess": "OfficeCLI désinstallé", - "uninstallFailed": "Échec de la désinstallation d'OfficeCLI", - "syncSuccess": "{synced} compétences synchronisées", - "syncPartial": "{synced} synchronisées, {errors} échouées", - "syncFailed": "Échec de la synchronisation des compétences" - }, - "autoPreviewLabel": "Ouvrir l'aperçu automatiquement", - "autoPreviewHint": "Lorsqu'un agent crée ou modifie un fichier Word, Excel ou PowerPoint, ouvrir automatiquement son aperçu en direct." - }, - "SkillPacksSettings": { - "title": "Packs de compétences", - "description": "Ensembles de compétences sélectionnés que codeg gère de manière centralisée et relie à vos agents IA : experts en programmation, recherche scientifique et outils de documents bureautiques. Activez-les par agent ci-dessous.", - "tabs": { - "experts": "Experts", - "science": "Science", - "office": "Outils bureautiques", - "custom": "Personnalisées" - }, - "actions": { - "openCentralDir": "Ouvrir le dossier central", - "refresh": "Actualiser" - }, - "toasts": { - "openFolderFailed": "Échec de l'ouverture du dossier" - } - }, - "QuickMessagesSettings": { - "title": "Messages rapides", - "description": "Gérez des extraits de messages réutilisables. Glissez pour réorganiser.", - "loading": "Chargement des messages rapides…", - "emptyList": "Aucun message rapide. Cliquez sur « Nouveau » pour en créer un.", - "emptySelection": "Sélectionnez un message rapide à modifier.", - "searchPlaceholder": "Rechercher par titre ou contenu", - "untitled": "Sans titre", - "actions": { - "new": "Nouveau", - "save": "Enregistrer", - "delete": "Supprimer", - "dragSort": "Glisser pour réorganiser", - "dragSortMessage": "Réorganiser le message rapide : {name}" - }, - "fields": { - "title": "Titre", - "titlePlaceholder": "Donnez un titre court à ce message", - "content": "Contenu", - "contentPlaceholder": "Saisissez ici le contenu du message" - }, - "confirmDelete": { - "title": "Supprimer le message rapide ?", - "message": "Cela supprimera définitivement « {name} ». Êtes-vous sûr ?", - "cancel": "Annuler", - "confirm": "Supprimer" - }, - "toasts": { - "loadFailed": "Échec du chargement des messages rapides", - "createFailed": "Échec de la création du message rapide", - "saveFailed": "Échec de l'enregistrement du message rapide", - "deleteFailed": "Échec de la suppression du message rapide", - "saveOrderFailed": "Échec de l'enregistrement de l'ordre", - "created": "Message rapide créé", - "saved": "Message rapide enregistré", - "deleted": "Message rapide supprimé" - } - }, - "Pet": { - "badge": { - "running": "{count} en cours", - "waiting": "{count} en attente d'approbation", - "error": "{count} en erreur" - }, - "panel": { - "title": "Sessions actives", - "empty": "Aucune session active", - "emptyHint": "Les agents en cours et ceux qui vous attendent apparaissent ici.", - "statusRunning": "En cours", - "statusWaiting": "En attente", - "statusError": "Erreur", - "subAgentOf": "Sous-agent de" - }, - "menu": { - "scale": "Échelle", - "openManager": "Gérer les mascottes", - "close": "Fermer" - }, - "loadError": "Échec du chargement de la mascotte", - "missingPetIdParam": "Aucune mascotte sélectionnée", - "summonButton": "Mascotte", - "manager": { - "title": "Mascottes", - "description": "Compagnons flottants de bureau avec des sprites compatibles Codex.", - "addPet": "Ajouter une mascotte", - "importFromCodex": "Importer depuis Codex", - "noPets": "Aucune mascotte. Ajoutez-en ou importez depuis Codex.", - "setActive": "Activer", - "active": "Active", - "edit": "Modifier", - "delete": "Supprimer", - "deleteConfirm": "Supprimer la mascotte « {name} » ? Elle sera retirée du disque.", - "summon": "Invoquer la fenêtre de la mascotte", - "openCodexHelp": "Les mascottes Codex doivent être dans ~/.codex/pets/. Aucune trouvée.", - "specRequirement": "Le sprite doit faire 1536px de large avec une hauteur multiple de 208px (par ex. 1872 ou 2288), en PNG/WebP avec transparence.", - "form": { - "id": "ID mascotte", - "idHelp": "Lettres minuscules, chiffres, '-' et '_'. Max 64 caractères.", - "displayName": "Nom affiché", - "description": "Description (facultative)", - "spritesheet": "Sprite", - "chooseFile": "Choisir un fichier", - "replaceFile": "Remplacer le sprite", - "saveCreate": "Ajouter la mascotte", - "saveUpdate": "Enregistrer", - "cancel": "Annuler" - }, - "errors": { - "missingId": "ID requis", - "missingName": "Nom requis", - "missingSpritesheet": "Sprite requis", - "addFailed": "Ajout impossible", - "updateFailed": "Mise à jour impossible", - "deleteFailed": "Suppression impossible", - "loadFailed": "Chargement impossible", - "setActiveFailed": "Activation impossible", - "summonFailed": "Ouverture de la fenêtre impossible" - } - }, - "import": { - "title": "Importer depuis Codex", - "subtitle": "Mascottes disponibles sous ~/.codex/pets/.", - "selectAll": "Tout sélectionner", - "alreadyImported": "Déjà importée", - "renameOnConflict": "Renommer en -imported en cas de conflit", - "import": "Importer la sélection", - "noneFound": "Aucune mascotte Codex importable.", - "imported": "Import réussi", - "failed": "Import échoué", - "close": "Fermer" - }, - "marketplace": { - "openMarketplace": "Marketplace de mascottes", - "title": "Marketplace de mascottes", - "search": "Rechercher des mascottes", - "kindFilter": { - "all": "Toutes", - "object": "Objet", - "animal": "Animal", - "person": "Personne", - "creature": "Créature" - }, - "sortFilter": { - "latest": "Récents", - "popular": "Populaires", - "views": "Vues" - }, - "refresh": "Actualiser", - "install": "Installer", - "installing": "Installation", - "reinstall": "Réinstaller", - "reinstallConfirm": "Remplacer la mascotte locale « {name} » ? Les données existantes seront écrasées.", - "cancel": "Annuler", - "stats": { - "views": "Vues", - "downloads": "Téléchargements", - "likes": "J’aime" - }, - "actions": { - "idle": "Repos", - "running_right": "Course dr.", - "running_left": "Course g.", - "waving": "Salut", - "jumping": "Saut", - "failed": "Échec", - "waiting": "Attente", - "running": "Course", - "review": "Revue" - }, - "page": "Page {page} sur {total}", - "prev": "Précédent", - "next": "Suivant", - "empty": "Aucune mascotte ne correspond.", - "successInstalled": "« {name} » installée", - "errors": { - "loadFailed": "Impossible de charger le marketplace", - "installFailed": "Échec de l’installation", - "alreadyInstalled": "La mascotte existe déjà localement" - } - } - }, - "RemoteWorkspace": { - "openRemoteWorkspace": "Ouvrir l’espace de travail distant", - "manage": "Gérer l’espace de travail distant", - "manageTitle": "Connexions à l’espace de travail distant", - "empty": "Aucune connexion distante", - "searchPlaceholder": "Rechercher un espace de travail distant", - "orderFailed": "Échec de l’enregistrement de l’ordre des espaces de travail distants", - "dragSort": "Glisser pour trier", - "dragSortConnection": "Glisser pour trier {name}", - "newConnection": "Nouvelle connexion", - "loading": "Chargement", - "loadingConnection": "Chargement de la connexion distante", - "name": "Nom", - "baseUrl": "URL du service", - "token": "Jeton d’accès", - "save": "Enregistrer", - "delete": "Supprimer", - "confirmDelete": { - "title": "Supprimer la connexion distante ?", - "message": "Cela retirera « {name} » de cet appareil. Cette action est irréversible.", - "cancel": "Annuler", - "confirm": "Supprimer" - }, - "saved": "Connexion distante enregistrée.", - "deleted": "Connexion distante supprimée.", - "loadFailed": "Échec du chargement des connexions distantes", - "saveFailed": "Échec de l’enregistrement de la connexion distante", - "deleteFailed": "Échec de la suppression de la connexion distante", - "openFailed": "Échec de l’ouverture de l’espace de travail distant", - "connectionLoadFailed": "Échec du chargement de la connexion distante : {message}", - "connectionExpired": "La connexion distante « {name} » a expiré. Mettez son jeton à jour, puis rechargez cette fenêtre." - }, - "ServerFileBrowser": { - "title": "Sélectionner un fichier serveur", - "pathPlaceholder": "Saisir le chemin du dossier...", - "goHome": "Aller au dossier personnel", - "navigateUp": "Aller au dossier parent", - "select": "Sélectionner", - "cancel": "Annuler", - "loading": "Chargement...", - "emptyDirectory": "Ce dossier est vide", - "errorLoadingDir": "Échec du chargement du dossier", - "selectedCount": "{count} sélectionné(s)" - }, - "BackupSettings": { - "title": "Sauvegarde et restauration", - "description": "Exportez une sauvegarde portable de vos données codeg, ou restaurez à partir d'une sauvegarde.", - "tabs": { - "backup": "Sauvegarde", - "restore": "Restauration" - }, - "export": { - "includeExternal": "Inclure le contenu des conversations", - "includeExternalHint": "Archive aussi les transcriptions des CLI (Claude, Codex, Gemini, …). Augmente la taille.", - "passphrase": "Phrase secrète (facultatif)", - "passphrasePlaceholder": "Laissez vide pour une archive non chiffrée", - "passphraseConfirm": "Confirmer la phrase secrète", - "passphraseMismatch": "Les phrases secrètes ne correspondent pas.", - "noPassphraseWarning": "Cette sauvegarde contiendra des secrets (clés d'API, jetons) en clair. Conservez-la en lieu sûr.", - "passphraseLossWarning": "Chiffrée avec cette phrase secrète. Si vous la perdez, la sauvegarde ne pourra pas être récupérée.", - "button": "Exporter la sauvegarde", - "inProgress": "Création de la sauvegarde…", - "success": "Sauvegarde créée.", - "started": "Téléchargement de la sauvegarde lancé." - }, - "restore": { - "selectFile": "Sélectionner le fichier de sauvegarde", - "passphrasePrompt": "Cette sauvegarde est chiffrée. Saisissez sa phrase secrète.", - "unlock": "Déverrouiller", - "preview": { - "title": "Détails de la sauvegarde", - "encrypted": "Chiffrée", - "compatible": "Compatible", - "incompatible": "Incompatible", - "createdAt": "Créée : {value}", - "appVersion": "Version de l'app : {value}", - "incompatibleHint": "Cette sauvegarde a été créée par une version plus récente de codeg et ne peut pas être restaurée." - }, - "replaceWarning": "La restauration remplace toutes les données codeg actuelles (base de données et téléversements). Vos données actuelles sont d'abord sauvegardées en instantané pour pouvoir être récupérées.", - "keyringNote": "Les jetons GitHub/chat du bureau sont dans le trousseau du système et ne sont pas inclus ; ressaisissez-les après la restauration.", - "button": "Restaurer", - "staging": "Préparation de la restauration…", - "staged": "Restauration préparée. Redémarrage…", - "restarting": "Restauration préparée. Redémarrage du serveur…", - "restartTimeout": "Le serveur n'est pas revenu à temps. Rechargez la page une fois qu'il est actif.", - "externalSideLocation": "Les transcriptions de conversations ont été restaurées dans {path}", - "confirmTitle": "Remplacer toutes les données ?", - "confirmBody": "Cela remplacera votre base de données et vos téléversements codeg actuels par la sauvegarde, puis redémarrera. Vos données actuelles sont d'abord sauvegardées en instantané.", - "cancel": "Annuler", - "confirmAction": "Remplacer et redémarrer", - "external": { - "title": "Contenu des conversations", - "hint": "Cette sauvegarde inclut des transcriptions des CLI. Choisissez où les restaurer.", - "modeSkip": "Ne pas restaurer", - "modeSide": "Restaurer dans un dossier annexe sûr", - "modeOriginal": "Restaurer aux emplacements d'origine des CLI", - "forceOverwrite": "Écraser les fichiers existants", - "forceOverwriteHint": "Remplace les fichiers déjà présents dans les dossiers des CLI.", - "scanning": "Vérification des conflits…", - "noConflicts": "Aucun fichier existant ne sera écrasé.", - "conflictCount": "{count} fichier(s) existant(s) seraient concerné(s).", - "conflictSkipNote": "Les fichiers existants sont conservés (ignorés) sauf si vous activez l'écrasement." - }, - "restartFailed": "Restauration préparée, mais le serveur n'a pas pu redémarrer. Redémarrez-le manuellement pour l'appliquer." - }, - "remoteUnsupported": "La sauvegarde et la restauration agissent sur les données de la machine qui exécute codeg. Vous êtes connecté à un espace de travail distant : gérez ses sauvegardes directement depuis ce serveur." - }, - "backup": { - "restore": { - "error": { - "badPassphrase": "Phrase secrète incorrecte ou sauvegarde corrompue.", - "corrupted": "L'archive de sauvegarde est corrompue.", - "unknownFormat": "Ce fichier n'est pas une sauvegarde codeg reconnue.", - "newerVersion": "Cette sauvegarde a été créée par codeg {backupVersion}, plus récent que cette version ({appVersion}).", - "alreadyPending": "Une restauration est déjà préparée. Redémarrez pour l'appliquer avant d'en préparer une autre." - } - }, - "error": { - "diskSpace": "Espace disque insuffisant pour terminer l'opération.", - "cancelled": "L'opération a été annulée." - } - }, - "WebConnection": { - "disconnectedTitle": "Connexion perdue", - "reconnectingDescription": "Tentative de reconnexion au serveur. Cela se rétablit généralement tout seul en quelques secondes.", - "reconnectNow": "Se reconnecter maintenant", - "sessionExpiredTitle": "Session expirée", - "sessionExpiredDescription": "Votre session n'est plus valide. Veuillez vous reconnecter pour continuer.", - "goToLogin": "Aller à la connexion" - }, - "LiveFeedback": { - "placeholder": "Envoyez une note à {agent} pendant qu'il travaille…", - "agentFallback": "l'agent", - "ariaLabel": "Note de retour en direct", - "dialogTitle": "Retour en direct", - "dialogDescription": "Envoyez une note à l'agent pendant qu'il travaille. Il la lira lors de sa prochaine vérification, sans interrompre l'étape en cours.", - "dialogDescriptionInstant": "Envoyez une note à l'agent pendant qu'il travaille. Elle est insérée immédiatement dans le tour en cours — l'agent la voit aussitôt.", - "channelDowngraded": "L'insertion instantanée n'est pas disponible dans cette session — votre note a été enregistrée et sera récupérée au prochain contrôle de l'agent.", - "send": "Envoyer", - "cancel": "Annuler", - "pending": "en attente", - "delivered": "reçue", - "turnEndedUnread": "L'agent a terminé avant de lire votre retour.", - "sendAsMessage": "Envoyer comme message", - "dismiss": "Ignorer", - "turnEndedResent": "Le tour est terminé : envoyé comme nouveau message.", - "turnEnded": "Le tour est déjà terminé.", - "submitFailed": "Impossible d'envoyer votre note" - }, - "AgentToolsSettings": { - "title": "Outils dans la conversation", - "description": "Outils supplémentaires que codeg fournit à un agent au sein d'une conversation. Ils sont injectés au démarrage de l'agent : une modification s'applique donc aux agents démarrés ensuite.", - "feedbackLabel": "Retour en direct", - "feedbackHint": "Envoyez des notes et corrections à un agent pendant qu'il travaille. Si l'agent prend en charge l'insertion instantanée, votre note est insérée immédiatement dans le tour en cours ; sinon, l'agent reçoit un outil pour consulter vos retours — ces agents ne le consultent généralement que si vous le mentionnez dans votre prompt, par exemple ajoutez « vérifie régulièrement mon feedback en direct » à votre message.", - "questionLabel": "Poser une question à l'utilisateur", - "questionHint": "Permet aux agents de s'interrompre et de vous poser une question à choix multiples affichée au-dessus de la zone de saisie de la conversation. L'agent attend votre réponse (ou que vous ignoriez).", - "sessionInfoLabel": "Obtenir les infos de session", - "sessionInfoHint": "Permet aux agents de consulter une session que vous mentionnez dans votre message (un badge de session) pour lire son titre, son agent, son statut, son espace de travail, sa consommation de jetons et ses messages récents.", - "automationsLabel": "Créer des automatisations", - "automationsHint": "Enregistre la conversation comme une automatisation qui s'exécute selon un planning. Désactivé par défaut : elle démarre ensuite des agents d'elle-même.", - "workTasksLabel": "Créer des tâches à faire", - "workTasksHint": "Ajoute une carte au tableau des tâches depuis la conversation. Désactivé par défaut : écrit l'état de l'application.", - "save": "Enregistrer", - "saving": "Enregistrement…", - "saved": "Paramètres des outils enregistrés", - "saveFailed": "Échec de l'enregistrement des paramètres des outils", - "loadFailed": "Échec du chargement : {detail}" - }, - "NotificationSoundSettings": { - "title": "Sons de notification", - "description": "Joue un son bref lorsqu’un événement d’agent se produit. Ce sont les mêmes événements que ceux envoyés aux canaux de discussion ; ce réglage ne s’applique qu’à cet appareil.", - "enableHint": "Désactivé par défaut. Les sons ne sont joués que dans la fenêtre de l’espace de travail de ce navigateur ou de cette application.", - "volume": "Volume", - "preview": "Écouter", - "previewEvent": "Écouter le son de {event}", - "onlyWhenUnfocused": "Uniquement lorsque la fenêtre n’est pas au premier plan", - "onlyWhenUnfocusedHint": "Reste silencieux tant que Codeg est affiché.", - "eventsTitle": "Événements", - "eventsHint": "Choisissez un son par événement, ou « Silencieux » pour l’ignorer. Si le même événement se répète en quelques secondes, il ne sonne qu’une fois.", - "toneNone": "Silencieux", - "toneChime": "Carillon", - "toneDing": "Clochette", - "toneBlip": "Bip", - "tonePop": "Pop", - "toneAlert": "Alerte", - "toneDescend": "Descendant" - }, - "LogsSettings": { - "loading": "Chargement…", - "sectionTitle": "Journaux d'exécution", - "sectionDescription": "Consultez et configurez les journaux de diagnostic de l'application. Les journaux sont écrits dans des fichiers locaux et conservés en mémoire pour l'affichage en direct.", - "captureTitle": "Niveau de journalisation", - "captureDescription": "Contrôle le niveau de détail capturé. Les niveaux plus élevés (Debug, Trace) enregistrent davantage mais produisent des journaux plus volumineux. « Désactivé » désactive la journalisation.", - "captureLabel": "Niveau de capture", - "levels": { - "off": "Désactivé", - "error": "Erreur", - "warn": "Avertissement", - "info": "Info", - "debug": "Débogage", - "trace": "Trace" - }, - "viewerTitle": "Journaux récents", - "viewerDescription": "Affichage en direct des journaux récents. Filtrez par niveau ou recherchez du texte.", - "searchPlaceholder": "Rechercher un message ou une cible…", - "viewLevels": { - "all": "Tous les niveaux", - "error": "Erreur et plus", - "warn": "Avertissement et plus", - "info": "Info et plus", - "debug": "Débogage et plus", - "trace": "Trace et plus" - }, - "pause": "Pause", - "resume": "Direct", - "refresh": "Actualiser", - "clear": "Effacer", - "openFolder": "Ouvrir le dossier", - "shownCount": "{shown} / {total} affichés", - "empty": "Aucun journal à afficher.", - "levelSaveFailed": "Échec de l'enregistrement du niveau de journalisation", - "openFolderFailed": "Échec de l'ouverture du dossier des journaux", - "downloadFailed": "Échec du téléchargement du fichier journal", - "filesTitle": "Fichiers journaux", - "filesDescription": "Téléchargez les fichiers journaux complets depuis le disque pour l'historique au-delà du tampon en direct.", - "filesEmpty": "Aucun fichier journal pour l'instant.", - "download": "Télécharger", - "downloadTruncated": "Le fichier est volumineux ; les {size} les plus récents ont été téléchargés. Le fichier complet se trouve dans le répertoire des journaux.", - "captureEnvLocked": "Le niveau de journalisation est contrôlé par la variable d'environnement RUST_LOG / CODEG_LOG ; modifiez-la là pour qu'elle prenne effet.", - "targetsTitle": "Remplacements par module", - "targetsDescription": "Définissez un niveau différent pour des modules spécifiques (p. ex. codeg_lib::acp) sans changer le niveau global.", - "targetsAdd": "Ajouter", - "targetsRemove": "Supprimer le remplacement", - "toggleDetails": "Afficher les détails" - }, - "Automations": { - "title": "Automatisations", - "new": "Nouvelle automatisation", - "empty": "Aucune automatisation pour l'instant", - "emptyHint": "Créez-en une pour exécuter une tâche d'agent planifiée ou à la demande.", - "name": "Nom", - "namePlaceholder": "ex. Revue de PR nocturne", - "prompt": "Instruction", - "promptPlaceholder": "Que doit faire l'agent ?", - "agent": "Agent", - "folder": "Dossier de l'espace de travail", - "folderPlaceholder": "Sélectionner un dossier", - "isolation": "Isolation", - "isolationWorktree": "Nouveau worktree par exécution", - "isolationShared": "Exécuter dans le dossier", - "isolationSharedCaveat": "Les exécutions utilisent directement l'arbre de travail de ce dossier et peuvent entrer en conflit avec vos modifications non validées. Activez l'option worktree pour isoler chaque exécution.", - "trigger": "Déclencheur", - "triggerSchedule": "Planifié", - "triggerManual": "Manuel uniquement", - "cron": "Planification (cron)", - "cronPlaceholder": "0 9 * * 1-5", - "timezone": "Fuseau horaire", - "nextRun": "Prochaine exécution", - "branch": "Branche", - "branchOptional": "Branche (facultatif)", - "enabled": "Activé", - "save": "Enregistrer", - "cancel": "Annuler", - "edit": "Modifier", - "delete": "Supprimer", - "runNow": "Exécuter maintenant", - "cancelRun": "Annuler l'exécution", - "runHistory": "Historique d'exécution", - "noRuns": "Aucune exécution pour l'instant", - "allFolders": "Tous les dossiers", - "filterAll": "Tous", - "noMatches": "Aucune automatisation correspondante", - "viewConversation": "Voir la conversation", - "lastRun": "Dernière exécution", - "never": "Jamais", - "running": "En cours", - "deleteTitle": "Supprimer l'automatisation ?", - "deleteDescription": "Cela supprime l'automatisation et sa planification. L'historique est conservé.", - "statusRunning": "En cours", - "statusSucceeded": "Réussie", - "statusFailed": "Échouée", - "statusCancelled": "Annulée", - "statusSkipped": "Ignorée", - "errorName": "Le nom est requis", - "errorPrompt": "L'instruction est requise", - "errorCron": "Les automatisations planifiées nécessitent une expression cron", - "errorFolder": "Sélectionnez un dossier d'espace de travail", - "presetHourly": "Toutes les heures", - "presetDaily": "Tous les jours 9 h", - "presetWeekdays": "En semaine 9 h", - "presetCustom": "Personnalisé", - "probing": "Chargement des options…", - "retry": "Réessayer", - "configNone": "Cet agent n'a aucune option configurable", - "inherit": "Par défaut de l'agent", - "mode": "Mode", - "config": "Configuration", - "branchPlaceholder": "(branche par défaut)", - "selectHint": "Sélectionnez une automatisation pour voir les détails", - "refresh": "Actualiser", - "onboardTitle": "Automatisez les tâches récurrentes de l'agent", - "onboardHint": "Planifiez un agent pour relire le code, mettre à jour les dépendances ou trier les problèmes, de façon périodique ou à la demande.", - "headerSubtitle": "Tâches d'agent planifiées et à la demande", - "startFromTemplate": "Partir d'un modèle", - "blankTitle": "Automatisation vierge", - "blankDesc": "Configurez une tâche d'agent à partir de zéro.", - "backToTemplates": "Modèles", - "sectionSchedule": "Planification et cible", - "sectionTarget": "Cible", - "sectionAction": "Action", - "actionLaunchSession": "Lancer une session", - "actionEnqueueTask": "Mettre une tâche en file", - "actionEnqueueTaskHint": "Chaque déclenchement ajoute une tâche à faire, nommée d'après cette automatisation, aux tâches à faire du dossier ; le moteur de tâches l'exécute selon les réglages du tableau.", - "sectionPrompt": "Instruction", - "nextIn": "Prochaine dans {rel}", - "manual": "Manuel", - "schedEveryMinutes": "Toutes les {n} minutes", - "schedHourly": "Toutes les heures", - "schedDaily": "Tous les jours à {time}", - "schedWeekdays": "En semaine à {time}", - "schedWeekly": "Chaque {day} à {time}", - "schedMonthly": "Le {day} de chaque mois à {time}", - "dow0": "dimanche", - "dow1": "lundi", - "dow2": "mardi", - "dow3": "mercredi", - "dow4": "jeudi", - "dow5": "vendredi", - "dow6": "samedi", - "tplCodeReviewTitle": "Revue de code", - "tplCodeReviewDesc": "Examine les modifications récentes à la recherche de bugs, de régressions et de problèmes de qualité.", - "tplDependencyUpdatesTitle": "Mise à jour des dépendances", - "tplDependencyUpdatesDesc": "Repère les dépendances obsolètes et propose des mises à niveau sûres.", - "tplTestCoverageTitle": "Couverture de tests", - "tplTestCoverageDesc": "Repère les chemins de code non testés et ajoute les tests manquants.", - "tplTodoSweepTitle": "Revue des TODO", - "tplTodoSweepDesc": "Rassemble les commentaires TODO et FIXME et les trie par priorité.", - "tplCiTriageTitle": "Tri CI", - "tplCiTriageDesc": "Enquête sur les vérifications récemment en échec et propose des correctifs.", - "tplReleaseNotesTitle": "Notes de version", - "tplReleaseNotesDesc": "Résume les changements depuis la dernière version dans un journal des modifications.", - "tplSecurityAuditTitle": "Audit de sécurité", - "tplSecurityAuditDesc": "Recherche les vulnérabilités et les schémas à risque, puis signale les constats.", - "enable": "Activer", - "disable": "Désactiver", - "moreActions": "Plus d'actions", - "statusDisabled": "Désactivée", - "cronBuilderTitle": "Générateur de planification", - "cronFreqLabel": "Fréquence", - "cronFreqMinutes": "Toutes les N minutes", - "cronFreqHourly": "Toutes les heures", - "cronFreqDaily": "Quotidien", - "cronFreqWeekdays": "Jours ouvrés", - "cronFreqWeekly": "Hebdomadaire", - "cronFreqMonthly": "Mensuel", - "cronFreqCustom": "Personnalisé", - "cronEveryLabel": "Intervalle (minutes)", - "cronTimeLabel": "Heure", - "cronHourLabel": "Heure", - "cronMinuteLabel": "Minute", - "cronDowLabel": "Jour de la semaine", - "cronDomLabel": "Jour du mois", - "cronApply": "Appliquer", - "cronPreviewLabel": "Aperçu", - "cronOpenBuilder": "Ouvrir le générateur de planification", - "branchDefault": "Branche par défaut", - "branchUseCustom": "Utiliser « {query} »", - "branchLocal": "Locale", - "branchRemote": "Distante", - "branchSearchPlaceholder": "Rechercher des branches…", - "branchNone": "Aucune branche" - }, - "Tasks": { - "title": "Tâches à faire", - "new": "Nouvelle tâche", - "empty": "Aucune tâche pour l’instant", - "emptyHint": "Ajoutez une tâche puis lancez-la : l’agent travaille dans un worktree isolé, vous relisez et fusionnez le résultat.", - "emptyColTodo": "Aucune tâche à faire pour l’instant", - "emptyColInProgress": "Rien en cours", - "emptyColAttention": "Rien à traiter", - "emptyColDone": "Rien de terminé pour l’instant", - "allFolders": "Tous les dossiers", - "showCanceled": "Afficher les annulées", - "showArchived": "Afficher les archivées", - "filter": "Filtrer", - "viewSwitchToBoard": "Passer à la vue tableau", - "viewSwitchToList": "Passer à la vue liste", - "statusFilter": "Statut", - "statusFilterAll": "Tous les statuts", - "listEmpty": "Aucune tâche ne correspond aux filtres actuels", - "listColStatus": "Statut", - "listColTask": "Tâche", - "listColLocation": "Emplacement", - "listColChanges": "Modifications", - "listColUpdated": "Mis à jour", - "colTodo": "À faire", - "colInProgress": "En cours", - "colAttention": "À traiter", - "colDone": "Terminées", - "statusTodo": "À faire", - "statusQueued": "En file", - "statusPreparing": "Préparation", - "statusRunning": "En cours", - "statusAwaitingInput": "En attente de saisie", - "statusReview": "À valider", - "statusMerging": "Fusion en cours", - "statusDone": "Terminée", - "statusFailed": "Échouée", - "statusCanceled": "Annulée", - "statusInterrupted": "Interrompue", - "badgeCleanupFailed": "Nettoyage échoué", - "badgeWorktreeKept": "Worktree conservé", - "badgeWorktreeRemoved": "Worktree supprimé", - "filesChanged": "{count} fichiers", - "actionStart": "Démarrer", - "actionSchedule": "Planifier", - "actionCancel": "Annuler", - "actionRetry": "Réessayer", - "actionRequeue": "Remettre en file", - "actionViewSession": "Voir la conversation", - "actionEdit": "Modifier", - "actionDelete": "Supprimer", - "actionRetryCleanup": "Réessayer le nettoyage", - "actionMerge": "Fusionner", - "actionUnqueueMerge": "Quitter la file de fusion", - "actionEditQueuedMerge": "Modifier la fusion en attente", - "badgeMergeQueued": "En attente de fusion", - "badgeMergeQueuedRank": "En attente de fusion · n° {rank}", - "badgeMergeQueuedHint": "En attente de la fin de la fusion en cours du projet ; celle-ci démarrera toute seule.", - "actionComplete": "Terminer", - "actionAbandon": "Abandonner", - "cancelTitle": "Annuler la tâche ?", - "cancelDescription": "La tâche passe à Annulée. Son worktree est conservé et vous pourrez la remettre en file plus tard.", - "cancelReasonLabel": "Raison (facultatif)", - "cancelReasonPlaceholder": "Ex. : mauvaise approche, je vais réécrire la description", - "cancelKeep": "Finalement non", - "cancelSubmit": "Annuler la tâche", - "restartTitleRetry": "Réessayer la tâche", - "restartTitleRequeue": "Remettre la tâche en file", - "restartDescription": "Vous pouvez ajouter une note (facultatif) : elle arrive dans le prompt de la prochaine exécution.", - "scheduleTitle": "Planifier la tâche", - "scheduleDescription": "La tâche reste dans À faire et démarre d'elle-même à l'heure choisie. La limite de concurrence du dossier s'applique toujours.", - "scheduleDateLabel": "Date", - "schedulePickDate": "Choisir une date", - "scheduleTimeLabel": "Heure", - "schedulePreview": "S'exécute le {time}", - "schedulePastHint": "Cette heure est déjà passée : la tâche démarrera dès l'enregistrement.", - "scheduleInAnHour": "Dans 1 heure", - "scheduleInThreeHours": "Dans 3 heures", - "scheduleTomorrow": "Demain 9:00", - "scheduleClear": "Annuler la planification", - "scheduleBadge": "Démarrage prévu le {time}", - "toastScheduled": "Planifiée pour le {time}", - "toastScheduleCleared": "Planification annulée", - "actionFollowUp": "Poursuivre", - "actionAddNote": "Ajouter une note", - "followUpSubmit": "Envoyer", - "followUpIntentRevise": "Corriger", - "followUpIntentContinue": "Continuer", - "followUpIntentQuestion": "Demander", - "followUpIntentVerify": "Vérifier", - "followUpPlaceholderRevise": "Que doit changer l'agent ? Il poursuit dans la même session.", - "followUpPlaceholderContinue": "Et ensuite ? Le travail déjà fait reste en place.", - "followUpPlaceholderQuestion": "Que voulez-vous savoir ? L'agent répond sans toucher aux fichiers.", - "followUpPlaceholderVerify": "Facultatif : quelque chose à examiner de près ?", - "followUpPlaceholderRetry": "Facultatif : que faire différemment ? Ex. : lancer pnpm install d'abord", - "followUpPlaceholderRequeue": "Facultatif : pourquoi l'avoir annulée, et qu'est-ce qui doit changer ?", - "actionArchive": "Archiver", - "actionUnarchive": "Désarchiver", - "archiveAllDone": "Tout archiver", - "dropToStart": "Relâchez pour lancer", - "errorView": "Voir", - "notifyReview": "Prêt pour révision : {title}", - "notifyFailed": "La tâche a échoué : {title}", - "createFromMessage": "Créer une tâche depuis le message", - "detailTokens": "Total de tokens", - "editorTitleNew": "Nouvelle tâche", - "editorTitleEdit": "Modifier la tâche", - "templates": "Modèles", - "templatesEmpty": "Aucun modèle pour l'instant.", - "templateSaveCurrent": "Enregistrer comme modèle", - "templateDelete": "Supprimer le modèle", - "transcriptTitle": "Conversation de la tâche", - "transcriptDescription": "Vue en direct, en lecture seule, de la session de l'agent de la tâche.", - "phaseWork": "Exécution", - "phaseRetry": "Nouvel essai", - "phaseReturn": "Relance", - "phaseMerge": "Fusion", - "titleLabel": "Titre", - "titlePlaceholder": "Que faut-il faire ?", - "promptLabel": "Description de la tâche", - "promptPlaceholder": "Décrivez la tâche pour l’agent — @ pour référencer des fichiers, / pour les commandes", - "folderPlaceholder": "Choisir un dossier", - "agentInheritedHint": "Hérité des réglages des tâches — modifiez-le pour personnaliser cette tâche", - "agentOverrideReset": "Revenir à l'héritage", - "sectionTarget": "Cible", - "errorTitle": "Le titre est requis", - "errorPrompt": "La description est requise", - "errorFolder": "Choisissez un dossier", - "save": "Enregistrer", - "cancel": "Annuler", - "mergeTitle": "Fusionner la tâche", - "mergeQueuedTitle": "Fusion en attente", - "mergeQueueHint": "Une autre tâche de ce projet est en cours de fusion. Celle-ci rejoint la file et démarrera d'elle-même dès que l'autre sera terminée.", - "mergeQueueUpdateHint": "Cette tâche attend déjà de fusionner. L'envoi la met à jour et conserve sa place dans la file.", - "mergeDescription": "Fusionner {branch} dans {base}. Les changements non commités du worktree sont d’abord commités.", - "mergeMessage": "Message de commit", - "mergeMessagePlaceholder": "ex. feat: add login validation", - "mergeAutoMessage": "Laisser l'agent rédiger le message de commit", - "strategySquash": "Regrouper en un seul commit", - "strategySquashHint": "Toutes les modifications de la tâche arrivent dans la branche principale comme une seule entrée d'historique — un historique plus net.", - "strategyMerge": "Conserver tout l'historique", - "strategyMergeHint": "Chaque commit réalisé pendant la tâche est conservé, plus une entrée de fusion — chaque étape reste traçable.", - "mergeDeleteWorktree": "Supprimer le worktree après la fusion", - "mergeSubmit": "Fusionner", - "mergeSubmitQueue": "Ajouter à la file", - "mergeQueuedToast": "Ajoutée à la file de fusion — elle démarrera dès la fin de la fusion en cours.", - "completeTitle": "Terminer la tâche", - "completeDescription": "Cette tâche n'a modifié aucun fichier : il n'y a rien à fusionner, elle est marquée comme terminée directement.", - "completeDescriptionNoWorktree": "Le worktree de cette tâche a été supprimé : plus rien ne peut être fusionné, elle est marquée comme terminée directement. Une branche de travail contenant encore des commits non fusionnés est conservée.", - "completeDeleteWorktree": "Supprimer le worktree après avoir terminé", - "completeSubmit": "Terminer", - "settingsTitle": "Réglages des tâches", - "settingsDescription": "Valeurs par défaut des tâches de {folder}.", - "settingsScope": "Portée", - "settingsScopeGlobal": "Tous les dossiers (valeurs globales)", - "settingsScopeGlobalHint": "Les dossiers sans réglages propres utilisent ces valeurs globales.", - "settingsSource": "Source de configuration", - "settingsSourceGlobal": "Valeurs globales", - "settingsSourceCustom": "Personnalisée", - "settingsSourceGlobalFollow": "Suit les réglages globaux des tâches — les changements globaux s'appliquent ici automatiquement.", - "settingsSourceCustomHint": "Enregistre des réglages propres à ce dossier, qui ne suit plus les valeurs globales.", - "settingsAgent": "Agent par défaut", - "settingsMaxConcurrent": "Tâches simultanées max.", - "settingsMaxConcurrentHint": "0 = illimité", - "settingsAutoProcess": "Traiter automatiquement", - "settingsAutoProcessHint": "Les tâches à faire démarrent seules, dans la limite de concurrence.", - "settingsMergeStrategy": "Stratégie de fusion par défaut", - "settingsMergeStrategyHint": "Comment les modifications de la tâche sont consignées dans l'historique de la branche lors de la fusion.", - "settingsAutoMerge": "Fusionner automatiquement", - "settingsAutoMergeHint": "Une tâche qui arrive en revue avec des changements à intégrer est fusionnée comme si vous cliquiez sur Fusionner : l'agent rédige le message de commit et le worktree suit le réglage par défaut ci-dessous. Si la pré-vérification échoue ou qu'une fusion a échoué, la tâche vous attend.", - "settingsDeleteWorktree": "Supprimer le worktree après la fusion", - "settingsDeleteWorktreeHint": "Coche l’option par défaut dans la boîte de dialogue de fusion ; elle reste modifiable.", - "settingsWorktreeRoot": "Emplacement du worktree", - "settingsWorktreeRootHint": "Répertoire dans lequel les worktrees des nouvelles tâches sont créés, un par tâche. Laissez vide pour les créer à côté du dossier du projet ; « ~ » désigne votre dossier personnel et un chemin relatif est résolu depuis le dossier du projet.", - "settingsWorktreeRootPlaceholder": "~/codeg-worktrees", - "settingsWorktreeRootBrowse": "Choisir le répertoire des worktrees", - "settingsPreflight": "Commande de pré-vérification", - "settingsPreflightHint": "S'exécute dans le worktree quand une tâche passe en revue.", - "settingsPreflightCustomPlaceholder": "pnpm test", - "settingsInitCommand": "Commande d'initialisation du worktree", - "settingsInitCommandHint": "Exécutée dans un worktree fraîchement créé avant le démarrage de l'agent.", - "settingsInitCommandPlaceholder": "pnpm install", - "settingsTabGeneral": "Général", - "settingsTabMerge": "Fusion", - "settingsTabWorktree": "Worktree", - "settingsTabPrompts": "Instructions", - "settingsPromptsIntro": "Chaque étape envoie déjà son propre prompt intégré : la tâche, les règles du worktree et, pour la fusion, les étapes git exactes. Ce que vous ajoutez ici est apposé à la fin comme instructions supplémentaires : cela affine ces textes intégrés, sans jamais les remplacer.", - "settingsPromptStageAll": "Toutes les phases", - "settingsPromptPlaceholderAll": "ex. Respecte les conventions d’AGENTS.md ; limite le résumé final à deux phrases", - "settingsPromptPlaceholderWork": "ex. Lis d’abord les tests concernés ; fais des commits petits et fréquents", - "settingsPromptPlaceholderRetry": "ex. Vérifie ce qui est déjà commité avant de continuer ; ne refais pas le travail terminé", - "settingsPromptPlaceholderReturn": "Ex. : Traitez chaque point soulevé ; ne refactorisez rien d'autre", - "settingsPromptPlaceholderMerge": "ex. Rédige le message du commit d’intégration en français ; signale les conflits résolus à la main", - "settingsPromptHintAll": "Ajouté à chaque prompt reçu par l'agent, fusion comprise.", - "settingsPromptHintWork": "Ajouté lors de la première exécution d'une tâche.", - "settingsPromptHintRetry": "Ajouté lorsqu'une tâche interrompue ou en échec est reprise.", - "settingsPromptHintReturn": "Ajouté quand vous relancez une tâche en revue (correction, ajout, vérification).", - "settingsPromptHintMerge": "Ajouté lorsque l'agent intègre la tâche dans la branche de base.", - "preflightPassed": "{name} réussie", - "preflightFailed": "{name} échouée", - "preflightRunning": "{name} en cours…", - "detailDescription": "Détail de la tâche", - "detailSummary": "Résultat", - "detailFiles": "Fichiers modifiés", - "detailDiffAll": "Voir tout le diff", - "detailDiffAllTitle": "Diff complet", - "detailNoChanges": "Aucun changement par rapport à la base", - "detailTimeline": "Progression", - "detailTimelineEmpty": "Aucune activité pour l’instant", - "showMore": "Afficher plus", - "showLess": "Afficher moins", - "detailInfo": "Détails", - "detailBranch": "Branche", - "detailMergeCommit": "Commit de fusion", - "detailChanges": "Modifications", - "detailScheduled": "Démarrage prévu", - "detailCreated": "Créée", - "detailStarted": "Démarrée", - "detailFinished": "Terminée", - "diffLoading": "Chargement du diff…", - "deleteConfirmTitle": "Supprimer la tâche ?", - "deleteConfirmBody": "« {title} » sera retirée du tableau. Une exécution active est d’abord annulée.", - "deleteWithWorktree": "Supprimer aussi son worktree", - "eventCreated": "Créée", - "eventStatusChanged": "Changement d’état", - "eventConfigEffective": "Configuration de lancement", - "eventInitCommand": "Commande d'initialisation", - "eventAgentProgress": "Progression de l’agent", - "eventAgentVerdict": "Verdict de l’agent", - "eventMergeAttempt": "Fusion démarrée", - "eventMergeQueued": "Mise en file de fusion", - "eventMergeConflict": "Conflit de fusion", - "eventPreflight": "Pré-vérification", - "eventCleanupFailed": "Échec du nettoyage du worktree", - "eventResumeFallback": "Reprise échouée, nouvelle session utilisée", - "eventUserAction": "Action utilisateur", - "eventDiffStat": "Instantané des changements" - }, - "CustomSkillsSettings": { - "loading": "Chargement des compétences personnalisées…", - "category": "Personnalisées", - "searchPlaceholder": "Rechercher des compétences personnalisées par nom, ID ou description", - "states": { - "not_linked": "Non activée", - "linked_to_codeg": "Activée", - "linked_elsewhere": "Liée ailleurs", - "blocked_by_real_directory": "Bloquée par un dossier réel", - "broken": "Lien rompu" - }, - "actions": { - "new": "Nouvelle", - "import": "Importer", - "importFromAgent": "Importer depuis un agent", - "cancel": "Annuler", - "save": "Enregistrer" - }, - "rowMenu": { - "edit": "Modifier", - "duplicate": "Dupliquer", - "delete": "Supprimer" - }, - "bulk": { - "delete": "Supprimer la sélection" - }, - "editor": { - "createTitle": "Nouvelle compétence personnalisée", - "editTitle": "Modifier la compétence personnalisée", - "description": "Les compétences personnalisées sont stockées dans le magasin partagé (~/.codeg/skills) et peuvent être activées pour n'importe quel agent.", - "idLabel": "ID de la compétence", - "idPlaceholder": "ex. my-workflow", - "contentLabel": "SKILL.md", - "contentPlaceholder": "Rédigez ici le SKILL.md de la compétence…", - "preview": "Aperçu", - "edit": "Modifier", - "emptyBody": "Aucun contenu pour le moment." - }, - "duplicate": { - "title": "Dupliquer la compétence", - "description": "Créer une copie de « {id} » avec un nouvel ID.", - "newIdPlaceholder": "Nouvel ID de compétence", - "confirm": "Dupliquer" - }, - "import": { - "title": "Choisir un dossier de compétence à importer" - }, - "importFromAgent": { - "title": "Importer des compétences depuis un agent", - "description": "Copiez les compétences propres à un agent dans le magasin partagé pour les activer sur n'importe quel agent.", - "agentLabel": "Agent", - "agentPlaceholder": "Sélectionner un agent", - "selectAll": "Tout sélectionner ({count})", - "loading": "Chargement des compétences de l'agent…", - "unsupported": "Cet agent n'expose pas de répertoire de compétences.", - "empty": "Cet agent n'a aucune compétence à importer.", - "alreadyInLibrary": "Dans la bibliothèque", - "confirm": "Importer la sélection ({count})" - }, - "delete": { - "title": "Supprimer les compétences personnalisées ?", - "body": "Cela retire {count} compétence(s) personnalisée(s) du magasin central et les dissocie de tous les agents. Action irréversible.", - "confirm": "Supprimer" - }, - "toasts": { - "loadFailed": "Échec du chargement de la compétence", - "idRequired": "Veuillez saisir un ID de compétence", - "created": "Compétence personnalisée créée", - "updated": "Compétence personnalisée mise à jour", - "saveFailed": "Échec de l'enregistrement de la compétence", - "imported": "Compétence importée", - "importFailed": "Échec de l'importation de la compétence", - "duplicated": "Compétence dupliquée", - "duplicateFailed": "Échec de la duplication de la compétence", - "deleted": "{count} compétence(s) supprimée(s)", - "deletedPartial": "{ok} supprimée(s), {failed} en échec", - "deleteFailed": "Échec de la suppression des compétences", - "importedFromAgent": "{count} compétence(s) importée(s)", - "importedFromAgentPartial": "{ok} importée(s), {failed} en échec", - "importFromAgentAllSkipped": "Rien à importer — {count} déjà dans la bibliothèque", - "importFromAgentFailed": "Échec de l'import depuis l'agent" - } - }, - "CodexModelEditor": { - "customizedNotice": "Vous avez personnalisé la liste des modèles, codeg gère donc désormais toute la table des modèles de codex. Les modèles officiels que codex ajoutera plus tard n'apparaîtront pas automatiquement : cliquez sur le bouton actualiser ci-dessous puis enregistrez à nouveau pour les synchroniser. Effacez vos personnalisations pour laisser codex se mettre à jour automatiquement.", - "officialsTitle": "Modèles officiels", - "officialsHint": "Inclus automatiquement depuis le codex que vous lancez ; supprimez ceux dont vous ne voulez pas.", - "officialsEmpty": "Aucun modèle officiel disponible.", - "refresh": "Actualiser depuis codex", - "readdOfficial": "Rajouter un officiel", - "customsTitle": "Modèles personnalisés", - "customsEmpty": "Aucun modèle personnalisé pour l'instant.", - "addCustom": "Ajouter personnalisé", - "slugPlaceholder": "id du modèle (slug)", - "displayNamePlaceholder": "Nom affiché", - "contextWindow": "Contexte", - "makeDefault": "Définir par défaut", - "defaultHint": "Modèle par défaut", - "remove": "Supprimer", - "advanced": "Avancé", - "baseTemplate": "Modèle de base", - "baseTemplateHint": "Modèle officiel à partir duquel cloner les champs requis (invite système, outils, limites).", - "groupBehavior": "Comportement et capacités", - "fieldReasoningLevel": "Raisonnement par défaut", - "fieldReasoningSummary": "Résumé du raisonnement", - "fieldVerbosity": "Verbosité", - "fieldShellType": "Type de shell", - "fieldApplyPatch": "Outil apply-patch", - "fieldReasoningSummaries": "Résumés de raisonnement", - "fieldSupportVerbosity": "Contrôle de la verbosité", - "fieldParallelToolCalls": "Appels d'outils en parallèle", - "fieldSearchTool": "Outil de recherche web", - "optNone": "Aucun", - "groupInstructions": "Description et prompt système", - "fieldDescription": "Description", - "baseInstructions": "Invite système (base_instructions)" - }, - "DiagnosticsSettings": { - "title": "Diagnostic de l'environnement", - "description": "Vérifie comment cette app résout la CLI de l'agent dans son propre processus, ce qui peut différer de votre terminal.", - "loading": "Diagnostic en cours…", - "error": "Échec du diagnostic", - "rerun": "Relancer", - "copyAll": "Tout copier", - "copied": "Diagnostic copié dans le presse-papiers", - "button": "Diagnostiquer", - "verdict": { - "ok": "L'environnement semble sain. S'il indique toujours non installé, redémarrez complètement l'app pour actualiser le cache du préfixe.", - "node_missing": "Node.js est introuvable dans le PATH de l'app.", - "npm_missing": "npm est introuvable dans le PATH de l'app.", - "not_installed": "Cet agent ne semble pas installé.", - "installed_but_unresolved": "Enregistré comme installé, mais l'app ne trouve pas son exécutable.", - "user_prefix_not_on_path": "Installé dans le préfixe de secours (~/.codeg/npm-global), qui n'est pas dans le PATH de l'app. Redémarrez complètement l'app et réessayez.", - "homebrew_bin_not_on_path": "Installé sous le bin de Homebrew, qui n'est pas dans le PATH de l'app (séparation keg Apple Silicon).", - "terminal_only_path": "La commande se résout dans votre terminal mais pas dans l'app : un écart de PATH GUI. Lancez l'app depuis un terminal ou réinstallez depuis les Paramètres des agents.", - "npm_prefix_timeout": "npm prefix -g était trop lent (plus de 1,5 s), la détection de secours a été ignorée. Redémarrez l'app et réessayez.", - "node_too_old": "Votre Node.js actif est plus ancien que ce que cet agent requiert. Mettez à niveau Node.js.", - "adapter_missing_native_present": "Votre CLI {agent} est bien installée, mais Codeg lance un paquet adaptateur ACP distinct, et celui-ci ne l'est pas encore. Installez-le depuis les paramètres des agents : il ne touche pas à votre CLI et partage la même connexion.", - "adapter_missing": "Codeg lance un paquet adaptateur ACP distinct pour {agent}, et il n'est pas encore installé. Installez-le depuis les paramètres des agents — installer seulement la CLI de l'éditeur ne suffit pas." - } - }, - "TokenUsage": { - "title": "Consommation de tokens", - "rangeLabel": "Période", - "range7d": "7 jours", - "range30d": "30 jours", - "range90d": "90 jours", - "rangeThisMonth": "Ce mois-ci", - "rangeThisYear": "Cette année", - "rangeAll": "Tout", - "rangeCustom": "Personnalisée", - "moreRanges": "Plus", - "customRangePick": "Choisir une période", - "bucketLabel": "Regrouper par", - "bucketDay": "Jour", - "bucketWeek": "Semaine", - "bucketMonth": "Mois", - "bucketUnitDay": "Jour", - "bucketUnitWeek": "Semaine", - "bucketUnitMonth": "Mois", - "folderFilter": "Dossiers", - "allFolders": "Tous les dossiers", - "agentFilter": "Agents", - "allAgents": "Tous les agents", - "modelFilter": "Modèles", - "allModels": "Tous les modèles", - "searchPlaceholder": "Rechercher…", - "noMatches": "Aucun résultat", - "clearFilter": "Effacer la sélection", - "resetFilters": "Réinitialiser les filtres", - "refresh": "Actualiser", - "rebuild": "Tout reconstruire", - "rebuildHint": "Efface les données comptées et relit toutes les transcriptions. Utile si une session a grandi hors de codeg.", - "syncing": "Comptage des sessions…", - "syncProgress": "{done} / {total}", - "syncDone": "{synced} sessions comptées", - "syncFailed": "Certaines sessions n'ont pas pu être lues", - "syncBusy": "Une actualisation est déjà en cours", - "lastSynced": "Mis à jour {time}", - "lastSyncedNever": "Jamais mis à jour", - "tileTotal": "Tokens au total", - "tileSessions": "Sessions", - "tileTurns": "Tours", - "tileActiveDays": "Jours actifs", - "tileGenTime": "Temps de génération", - "vsPrevious": "vs période précédente", - "deltaNew": "nouveau", - "trendTitle": "Consommation dans le temps", - "trendEmpty": "Aucune consommation sur cette période", - "trendTurns": "Tours", - "trendSessions": "Sessions", - "compositionTitle": "À quoi sont partis les tokens", - "compositionHint": "L'entrée est ce que vous avez envoyé, la sortie ce que le modèle a écrit, et les lectures de cache du contexte non refacturé au prix fort.", - "compositionNote": "Renvoyer ces lectures de cache au prix fort aurait coûté {value} de plus.", - "inputTokens": "Entrée", - "outputTokens": "Sortie", - "cacheWrite": "Écriture cache", - "cacheRead": "Lecture cache", - "freshTokens": "Calcul frais", - "cacheHitCaption": "Taux de cache", - "cacheHeroTitleHigh": "L'essentiel du contexte n'a pas été renvoyé", - "cacheHeroTitleLow": "L'essentiel du contexte se calcule encore au prix fort", - "cacheHeroDesc": "Le cache a porté {cached} de contexte ; seuls {fresh} ont été réellement recalculés sur la période.", - "cacheSavedSuffix": "Soit l'équivalent de {saved} de renvois économisés.", - "avgPerSession": "Moy. par session", - "avgTurnsPerSession": "{count} tours par session en moyenne", - "avgPerActiveDay": "Moy. par jour actif", - "peakBucket": "{bucket} le plus chargé", - "peakHour": "Heure de pointe", - "daysValue": "{count} jours", - "idleDays": "Jours sans activité", - "byFolderTitle": "Par dossier", - "byAgentTitle": "Par agent", - "byModelTitle": "Par modèle", - "distributionTitle": "Répartition de l'usage", - "distributionHint": "Sessions et tokens regroupés selon la dimension choisie — cliquez sur une ligne pour filtrer.", - "otherLabel": "Autres", - "unknownModel": "Modèle non renseigné", - "emptyBreakdown": "Rien d'enregistré", - "sessionsCount": "{count} sessions", - "heatmapTitle": "Quand vous codez", - "heatmapHint": "Tokens par jour de la semaine et heure locale.", - "heatmapPeakHint": "Le plus dense autour de {hour}:00.", - "less": "Moins", - "more": "Plus", - "heatmapCell": "{weekday} {hour}:00 — {value} tokens", - "weekMon": "Lun", - "weekTue": "Mar", - "weekWed": "Mer", - "weekThu": "Jeu", - "weekFri": "Ven", - "weekSat": "Sam", - "weekSun": "Dim", - "topSessionsTitle": "Sessions les plus gourmandes", - "untitledSession": "Session sans titre", - "topSessionsEmpty": "Aucune session sur cette période", - "streakLongest": "Plus longue série", - "streakLongestDays": "Plus longue série : {count} jours", - "share": "Partager", - "moreActions": "Autres actions", - "shareDialogTitle": "Partagez votre carte de consommation", - "shareDialogHint": "Un instantané de la période et des filtres affichés.", - "shareSave": "Enregistrer l'image", - "shareCopy": "Copier l'image", - "shareCopied": "Copié dans le presse-papiers", - "shareSaved": "Image enregistrée", - "shareFailed": "Impossible de créer l'image", - "shareRendering": "Génération…", - "cardHeading": "Mon bilan de code assisté par IA", - "cardRangeAll": "Depuis le début", - "cardTotalLabel": "Tokens consommés", - "cardFooter": "Réalisé avec codeg", - "cardTopModels": "Modèles principaux", - "cardTopProjects": "Projets principaux", - "archetypeNightOwl": "Oiseau de nuit", - "archetypeNightOwlDesc": "{percent}% de vos tokens brûlent après la tombée de la nuit.", - "archetypeEarlyBird": "Lève-tôt", - "archetypeEarlyBirdDesc": "{percent}% de vos tokens tombent avant 9 h.", - "archetypeWeekendWarrior": "Guerrier du week-end", - "archetypeWeekendWarriorDesc": "{percent}% de vos tokens arrivent le week-end.", - "archetypeCacheMaster": "Maître du cache", - "archetypeCacheMasterDesc": "{percent}% de votre contexte venait du cache.", - "archetypeMarathoner": "Marathonien", - "archetypeMarathonerDesc": "{days} jours de code sans interruption.", - "archetypePolyglot": "Polyvalent", - "archetypePolyglotDesc": "{count} agents utilisés sérieusement.", - "archetypeLaserFocus": "Focus laser", - "archetypeLaserFocusDesc": "{percent}% de vos tokens sur un seul projet.", - "archetypeDeepDiver": "Plongeur", - "archetypeDeepDiverDesc": "{averageK}K tokens par session en moyenne.", - "archetypeSteady": "Bâtisseur régulier", - "archetypeSteadyDesc": "{days} jours de livraison.", - "emptyTitle": "Rien de compté pour l'instant", - "emptyHint": "Codeg lit les tokens directement dans la transcription de chaque agent. Actualisez pour compter ce qui est déjà sur cette machine.", - "emptyAction": "Compter mes sessions", - "loadFailed": "Impossible de charger la consommation", - "truncatedNotice": "Cette période est très large — les chiffres ne couvrent que sa portion la plus récente." - } -} +{ + "Language": { + "followSystem": "Suivre le système", + "english": "Anglais", + "simplifiedChinese": "Chinois simplifié", + "traditionalChinese": "Chinois traditionnel", + "japanese": "Japonais", + "korean": "Coréen", + "spanish": "Espagnol", + "german": "Allemand", + "french": "Français", + "portuguese": "Portugais", + "arabic": "Arabe" + }, + "GitCredentialDialog": { + "title": "Authentification requise", + "description": "Le serveur distant nécessite des identifiants. Entrez votre nom d'utilisateur et votre mot de passe (ou jeton d'accès personnel).", + "username": "Nom d'utilisateur", + "usernamePlaceholder": "Nom d'utilisateur ou e-mail", + "password": "Mot de passe / Jeton", + "passwordPlaceholder": "Mot de passe ou jeton d'accès personnel", + "passwordHint": "Entrez le nom d'utilisateur et le mot de passe du serveur.", + "cancel": "Annuler", + "authenticate": "Authentifier", + "authenticating": "Authentification...", + "invalidCredentials": "Identifiants invalides. Veuillez réessayer.", + "saveCredentials": "Enregistrer les identifiants pour les opérations futures", + "githubTitle": "Authentification GitHub", + "githubDescription": "Entrez un jeton d'accès personnel pour vous connecter à GitHub. Le jeton sera validé et enregistré automatiquement.", + "githubToken": "Jeton d'accès personnel", + "githubTokenPlaceholder": "ghp_xxxxxxxxxxxx", + "githubTokenHint": "Générez un jeton dans GitHub → Settings → Developer settings → Personal access tokens.", + "githubAuthenticate": "Valider et connecter", + "generateToken": "Générer un jeton" + }, + "SettingsShell": { + "title": "Paramètres", + "preferences": "Préférences", + "nav": { + "general": "Général", + "appearance": "Apparence", + "agents": "Agents IA", + "mcp": "MCP", + "skills": "Skills", + "shortcuts": "Raccourcis", + "version_control": "Contrôle de version", + "system": "Système", + "chat_channels": "Canaux de chat", + "web_service": "Service Web", + "model_providers": "Fournisseurs de Modèles", + "experts": "Experts", + "science": "Science", + "office_tools": "Outils bureautiques", + "skill_packs": "Packs de compétences", + "quick_messages": "Messages rapides", + "logs": "Journaux d'exécution" + } + }, + "AppearanceSettings": { + "sectionTitle": "Apparence du thème", + "sectionDescription": "Choisissez clair, sombre ou suivre le système. Les paramètres sont enregistrés automatiquement.", + "themeMode": "Mode du thème", + "placeholder": "Sélectionner le mode du thème", + "system": "Suivre le système", + "light": "Clair", + "dark": "Sombre", + "currentTheme": "Thème effectif actuel : {theme}", + "resolvedTheme": { + "light": "Clair", + "dark": "Sombre", + "unknown": "--" + }, + "themeColor": { + "sectionTitle": "Couleur du thème", + "sectionDescription": "Choisissez une palette pour les accents, les boutons et les surlignages.", + "current": "Couleur actuelle : {color}", + "options": { + "neutral": "Neutre", + "zinc": "Zinc", + "slate": "Ardoise", + "stone": "Pierre", + "gray": "Gris", + "red": "Rouge", + "rose": "Rose", + "orange": "Orange", + "green": "Vert", + "blue": "Bleu", + "yellow": "Jaune", + "violet": "Violet" + } + }, + "customStyle": { + "sectionTitle": "Style personnalisé", + "sectionDescription": "Ajustez les couleurs du thème actuel ou injectez votre propre CSS. Les remplacements se superposent au préréglage de base et sont conservés lorsque vous en changez.", + "summarySuspended": "Suspendu", + "summaryDefault": "Préréglage inchangé", + "summaryTokens": "{count, plural, one {# remplacement} other {# remplacements}}", + "summaryCss": "CSS personnalisé", + "suspendedByShortcut": "Le style personnalisé est suspendu. Rien de ce que vous réglez ici ne s'appliquera tant que vous ne l'aurez pas réactivé.", + "suspendedBySafeParam": "Cette fenêtre a été ouverte en mode d'apparence sûre : le style personnalisé y est ignoré. Les autres fenêtres ne sont pas affectées.", + "resume": "Réactiver le style personnalisé", + "enableTheme": "Activer les couleurs personnalisées", + "editingLight": "Vous modifiez les valeurs du mode clair. Passez l'application en mode sombre pour le régler séparément.", + "editingDark": "Vous modifiez les valeurs du mode sombre. Passez l'application en mode clair pour le régler séparément.", + "resetToken": "Rétablir la valeur du préréglage", + "radius": "Rayon des coins", + "radiusHint": "Toute l'échelle de rayons, de sm à 4xl, en découle : un seul curseur arrondit l'application entière.", + "advanced": "Avancé ({count} variables de plus)", + "enableCss": "Activer le CSS personnalisé", + "cssRisk": "Fonction avancée. Le CSS personnalisé remplace tous les styles intégrés et peut rendre l'interface inutilisable.", + "editCss": "Modifier le CSS…", + "cssPresent": "{size} Ko enregistrés", + "cssEmpty": "Rien d'enregistré pour l'instant", + "escapeHint": "Interface cassée ? Appuyez sur {shortcut} pour suspendre tout le style personnalisé, ou ouvrez une fenêtre avec le paramètre safeStyle=1.", + "copyTheme": "Copier le JSON du thème", + "importTheme": "Importer un thème…", + "clearTheme": "Effacer les remplacements", + "interopHint": "Les thèmes utilisent le format registry:theme de shadcn : collez ici n'importe quel thème shadcn, et réutilisez les vôtres dans n'importe quel projet shadcn.", + "importTitle": "Importer un thème", + "importDescription": "Collez un élément registry:theme de shadcn, un simple objet light/dark, ou une table de tokens à plat.", + "readClipboard": "Lire le presse-papiers", + "importConfirm": "Importer", + "cancel": "Annuler", + "apply": "Appliquer", + "toasts": { + "copied": "JSON du thème copié", + "copyFailed": "Impossible de copier dans le presse-papiers", + "clipboardReadFailed": "Impossible de lire le presse-papiers, collez manuellement", + "importFailed": "Ce JSON ne contient aucune variable de thème utilisable", + "imported": "Thème importé" + }, + "css": { + "dialogTitle": "CSS personnalisé", + "dialogDescription": "S'applique à toutes les fenêtres codeg. Les modifications sont prévisualisées en direct ; cliquez sur Appliquer pour enregistrer.", + "size": "{used} Ko / {max} Ko", + "ruleCount": "{count} règles", + "errorTooLarge": "Trop volumineux pour être enregistré. Réduisez-le sous la limite.", + "errorImportEscaped": "Une règle @import a survécu au retrait (syntaxe échappée). Supprimez-la pour enregistrer.", + "warnNoRules": "Aucune règle analysée, vérifiez la syntaxe.", + "noticeImportsRemoved": "Règles @import supprimées : {count}. Elles chargeraient des feuilles de style distantes.", + "noticeRemoteUrl": "Contient une url() distante, qui déclenchera une requête réseau une fois appliquée.", + "noticePreviewSuspended": "Le style personnalisé est suspendu, cet aperçu n'est donc pas appliqué.", + "noticeDisabled": "Le CSS personnalisé est désactivé. Vous pouvez prévisualiser ici, mais rien ne s'appliquera avant activation.", + "hintTokens": "Astuce : vos couleurs remplacées sont accessibles via var(--primary), var(--background), etc." + } + }, + "zoomLevel": { + "sectionTitle": "Zoom de la fenêtre", + "sectionDescription": "Met à l'échelle toute l'interface. S'applique immédiatement et est enregistré par appareil.", + "placeholder": "Sélectionnez le niveau de zoom", + "default": "Par défaut", + "current": "Zoom actuel : {zoom}%" + }, + "fonts": { + "sectionTitle": "Polices", + "sectionDescription": "Choisissez les polices pour l’interface, l’éditeur de code et le terminal. Les polices intégrées sont chargées à la demande ; sélectionnez « Personnalisée… » pour utiliser n’importe quelle police installée sur votre système.", + "interface": "Interface", + "editor": "Éditeur", + "terminal": "Terminal", + "groupSans": "Sans empattement", + "groupMono": "Monospace", + "custom": "Personnalisée…", + "customPlaceholder": "Nom de la police, par ex. Fira Code", + "fontSize": "Taille de police", + "ligatures": "Activer les ligatures", + "ligaturesUnavailable": "Cette police n’a pas de ligatures", + "wordWrap": "Activer le retour à la ligne", + "terminalLigaturesHint": "Les ligatures du terminal ne s’appliquent qu’aux polices de programmation intégrées.", + "preview": "Aperçu" + }, + "welcomePanel": { + "sectionTitle": "Zone de sélection du mode", + "sectionDescription": "Les cartes de raccourci « Développement / Bureautique » affichées au-dessus du champ de saisie sur la page de nouvelle conversation.", + "showQuickActions": "Afficher sur la page de nouvelle conversation" + }, + "workspaceBackground": { + "sectionTitle": "Arrière-plan de l'espace de travail", + "sectionDescription": "Affiche une image derrière tout l'espace de travail. La barre latérale et les panneaux deviennent translucides et dépolis pour laisser transparaître l'image, et un masque préserve la lisibilité du texte.", + "enable": "Activer l'image d'arrière-plan", + "image": "Image", + "chooseImage": "Choisir une image", + "replaceImage": "Remplacer l'image", + "removeImage": "Supprimer", + "fillMode": "Mode de remplissage", + "fillModes": { + "cover": "Remplir", + "contain": "Ajuster", + "center": "Centrer", + "tile": "Mosaïque" + }, + "maskOpacity": "Opacité du masque", + "maskOpacityHint": "Des valeurs élevées fondent l'image vers la couleur d'arrière-plan du thème, améliorant le contraste du texte.", + "imageBlur": "Flou de l'image", + "panelOpacity": "Opacité des panneaux", + "panelOpacityHint": "Opacité de la barre latérale, des panneaux et des barres d'onglets. Plus c'est bas, plus l'image transparaît.", + "errorTooLarge": "L'image est trop volumineuse (16 Mo maximum).", + "errorUploadFailed": "Échec de la définition de l'image d'arrière-plan." + } + }, + "SystemSettings": { + "loading": "Chargement...", + "sectionTitle": "Gestion du système", + "sectionDescription": "Gérez le proxy réseau, les mises à jour de l’app et les préférences de langue.", + "proxyTitle": "Proxy réseau", + "proxyDescription": "Lorsqu’il est activé, les requêtes réseau suivantes utilisent ce proxy en priorité (y compris le chat ACP, l’installation d’agents et les opérations Git distantes).", + "loadFailed": "Échec du chargement : {message}", + "enableProxy": "Activer le proxy système", + "proxyAddress": "Adresse du proxy", + "proxyHint": "Prend en charge http(s)/socks5, exemple : {example}. Actif uniquement lorsque le proxy système est activé.", + "save": "Enregistrer", + "saving": "Enregistrement...", + "proxyRequired": "L’URL du proxy est requise lorsque le proxy est activé", + "saveSuccess": "Les paramètres du proxy système ont été enregistrés", + "saveFailed": "Échec de l’enregistrement : {message}", + "languageTitle": "Langue", + "languageDescription": "Définissez la langue de l’app. En mode système, les langues non prises en charge reviennent à l’anglais.", + "appLanguage": "Langue de l’app", + "languageSaveSuccess": "Les paramètres de langue ont été enregistrés", + "languageSaveFailed": "Échec de l’enregistrement des paramètres de langue : {message}", + "updateTitle": "Mise à jour de l’app", + "versionTitle": "Mise à jour logicielle", + "updateDescription": "Vérifiez les nouvelles versions depuis la source de publication configurée et installez-les directement si disponibles.", + "currentVersion": "Version actuelle", + "upgradableVersion": "Dernière version", + "none": "Aucune", + "lastChecked": "Dernière vérification : {time}", + "updateError": "Erreur de mise à jour : {message}", + "checking": "Vérification...", + "checkUpdate": "Rechercher les mises à jour", + "updating": "Installation...", + "downloading": "Téléchargement...", + "upgradeTo": "Mettre à jour vers v{version}", + "viewRelease": "Voir la version v{version}", + "foundUpdate": "Nouvelle version v{version} trouvée", + "alreadyLatest": "Vous utilisez déjà la dernière version", + "checkUpdateFailed": "Échec de la recherche de mises à jour : {message}", + "installSuccess": "Mise à jour installée. Redémarrage de l’app.", + "installFailed": "Échec de la mise à jour : {message}", + "upgradeSuccess": "Mise à niveau terminée. Rechargement...", + "restartTimeout": "Le serveur n'est pas revenu à temps. Consultez les journaux du conteneur ou du service.", + "restartingIn": "Redémarrage dans {seconds} s...", + "waitingForServer": "En attente du retour du serveur...", + "restartToUpdate": "Redémarrer pour mettre à jour", + "newVersionBadge": "Nouveau v{version}", + "updateAvailableTitle": "Mise à jour disponible", + "releaseNotesTitle": "Nouveautés", + "remindLater": "Plus tard", + "retry": "Réessayer", + "stepDownload": "Téléchargement", + "stepInstall": "Installation", + "stepRestart": "Redémarrage", + "updateReadyHint": "Mise à jour téléchargée — redémarrez pour l'appliquer.", + "restarting": "Redémarrage...", + "dockerUpgradeHint": "Cela met à jour le conteneur en cours d'exécution. La mise à jour est perdue si le conteneur est recréé — pour la conserver, récupérez ou créez une image à la nouvelle version puis recréez le conteneur.", + "upgradeRolledBack": "Échec de la mise à niveau ; le serveur est revenu à la version précédente.", + "serverUnreachable": "Impossible de joindre le serveur pour démarrer la mise à niveau. Vérifiez qu'il fonctionne et réessayez.", + "rollbackButton": "Revenir en arrière", + "rollingBack": "Restauration...", + "rollbackDescription": "Restaure la version installée avant la dernière mise à niveau.", + "rollbackConfirmTitle": "Revenir à la version précédente ?", + "rollbackConfirmDescription": "Le serveur redémarrera sur la version installée avant la dernière mise à niveau. Une version plus récente reste disponible à la réinstallation.", + "rollbackConfirm": "Revenir en arrière", + "rollbackCancel": "Annuler", + "rollbackSuccess": "Retour à la version précédente. Rechargement...", + "rollbackFailed": "Échec du retour en arrière. Consultez les journaux du serveur.", + "updateErrors": { + "sourceUnavailable": "Impossible d’atteindre la source de mise à jour. Vérifiez votre réseau ou proxy et réessayez.", + "network": "La connexion réseau a échoué. Vérifiez votre réseau ou proxy et réessayez.", + "downloadFailed": "Impossible de télécharger le paquet de mise à jour. Veuillez réessayer plus tard.", + "installFailed": "Impossible d’installer la mise à jour. Fermez l’app puis réessayez.", + "unknown": "La mise à jour a échoué. Veuillez réessayer plus tard." + } + }, + "VersionControlSettings": { + "loading": "Chargement...", + "sectionTitle": "Contrôle de version", + "sectionDescription": "Configurez l'exécutable Git et gérez les comptes GitHub.", + "gitTitle": "Configuration Git", + "gitDescription": "Configurez l'exécutable Git utilisé par l'application.", + "gitDetected": "Git détecté", + "gitNotFound": "Git introuvable sur le système", + "gitVersion": "Version", + "gitPath": "Chemin", + "customGitPath": "Chemin Git personnalisé", + "customGitPathPlaceholder": "/usr/bin/git", + "customGitPathHint": "Laissez vide pour utiliser le chemin détecté automatiquement.", + "test": "Tester", + "testing": "Test en cours...", + "testSuccess": "L'exécutable Git est valide.", + "testFailed": "Test Git échoué : {message}", + "save": "Enregistrer", + "saving": "Enregistrement...", + "saveSuccess": "Paramètres Git enregistrés.", + "saveFailed": "Échec de l'enregistrement : {message}", + "githubTitle": "Comptes GitHub", + "githubDescription": "Gérez les comptes GitHub pour l'authentification. Les jetons sont stockés localement.", + "noAccounts": "Aucun compte GitHub configuré.", + "addAccount": "Ajouter un compte", + "serverUrl": "URL du serveur", + "serverUrlPlaceholder": "https://github.com", + "token": "Jeton d'accès personnel", + "tokenPlaceholder": "ghp_xxxxxxxxxxxx", + "generateToken": "Générer un jeton", + "tokenHint": "Générez un jeton dans GitHub → Settings → Developer settings → Personal access tokens.", + "validateAndAdd": "Valider et ajouter", + "validating": "Validation...", + "addSuccess": "Compte {username} ajouté avec succès.", + "addFailed": "Échec de l'ajout du compte : {message}", + "testConnection": "Tester", + "connectionSuccess": "Connexion réussie.", + "connectionFailed": "Échec de la connexion : {message}", + "setDefault": "Définir par défaut", + "defaultLabel": "Par défaut", + "defaultSet": "Compte par défaut mis à jour.", + "removeAccount": "Supprimer", + "removeConfirmTitle": "Supprimer le compte", + "removeConfirmMessage": "Êtes-vous sûr de vouloir supprimer le compte « {username} » ?", + "removeConfirm": "Supprimer", + "removeCancel": "Annuler", + "removeSuccess": "Compte supprimé.", + "scopes": "Portées", + "loadFailed": "Échec du chargement des paramètres : {message}", + "gitAccount": { + "sectionTitle": "Comptes serveur Git", + "sectionDescription": "Gérez les identifiants pour les serveurs Git non GitHub (GitLab, Bitbucket, auto-hébergé, etc.).", + "noAccounts": "Aucun compte de serveur Git configuré.", + "addAccount": "Ajouter un compte", + "addTitle": "Ajouter un compte Git", + "addDescription": "Entrez l'adresse du serveur, le nom d'utilisateur et le mot de passe ou jeton d'accès.", + "serverUrl": "URL du serveur", + "serverUrlPlaceholder": "https://gitlab.example.com", + "username": "Nom d'utilisateur", + "usernamePlaceholder": "Nom d'utilisateur ou e-mail", + "password": "Mot de passe / Jeton", + "passwordPlaceholder": "Mot de passe ou jeton d'accès", + "passwordHint": "Entrez le mot de passe ou le jeton d'accès du serveur.", + "add": "Ajouter", + "serverRequired": "L'URL du serveur est requise.", + "usernameRequired": "Le nom d'utilisateur est requis.", + "passwordRequired": "Le mot de passe est requis." + } + }, + "ShortcutSettings": { + "sectionTitle": "Raccourcis", + "resetDefault": "Rétablir les valeurs par défaut", + "recordInstruction": "Cliquez sur le bouton à droite, puis appuyez sur une combinaison de touches. Utilisez Ctrl/Cmd, Alt et Shift. Appuyez sur Échap pour annuler l’enregistrement.", + "recording": "Appuyez sur un raccourci...", + "toasts": { + "conflict": "Le raccourci est déjà utilisé par \"{title}\"", + "updated": "Raccourci mis à jour", + "invalid": "Raccourci invalide, veuillez réessayer", + "reset": "Les raccourcis par défaut ont été restaurés" + }, + "actions": { + "toggle_search": { + "title": "Ouvrir la recherche", + "description": "Afficher ou masquer le panneau de recherche de conversations" + }, + "toggle_sidebar": { + "title": "Basculer la barre latérale gauche", + "description": "Afficher ou masquer la barre latérale de liste des conversations" + }, + "toggle_terminal": { + "title": "Basculer le terminal", + "description": "Afficher ou masquer le panneau terminal inférieur" + }, + "new_terminal_tab": { + "title": "Nouveau terminal", + "description": "Créer un nouvel onglet terminal lorsque le terminal a le focus" + }, + "close_current_terminal_tab": { + "title": "Fermer le terminal actuel", + "description": "Fermer l’onglet terminal actuel lorsque le terminal a le focus" + }, + "toggle_aux_panel": { + "title": "Basculer le panneau droit", + "description": "Afficher ou masquer le panneau d’informations auxiliaires" + }, + "new_conversation": { + "title": "Nouvelle conversation", + "description": "Créer un nouvel onglet de conversation dans le dossier actuel" + }, + "open_folder": { + "title": "Ouvrir un dossier", + "description": "Ouvrir le sélecteur de dossier et ouvrir dans une nouvelle fenêtre" + }, + "open_settings": { + "title": "Ouvrir les paramètres", + "description": "Ouvrir la fenêtre des paramètres" + }, + "close_current_tab": { + "title": "Fermer l’onglet actuel", + "description": "Fermer la conversation actuelle ou l’onglet de fichier" + }, + "close_all_file_tabs": { + "title": "Fermer tous les onglets de fichiers", + "description": "Fermer tous les onglets de fichiers ouverts lorsque le panneau de fichiers est actif" + }, + "next_tab": { + "title": "Onglet suivant", + "description": "Passer à l'onglet de conversation ou de fichier suivant" + }, + "prev_tab": { + "title": "Onglet précédent", + "description": "Passer à l'onglet de conversation ou de fichier précédent" + }, + "send_message": { + "title": "Envoyer le message", + "description": "Envoyer le message actuel dans la zone de saisie" + }, + "newline_in_message": { + "title": "Retour à la ligne", + "description": "Insérer un retour à la ligne dans la zone de saisie" + }, + "toggle_custom_style": { + "title": "Suspendre/réactiver le style personnalisé", + "description": "Issue de secours : désactive toutes les couleurs et le CSS personnalisés, puis les réactive" + } + } + }, + "SkillsSettings": { + "title": "Skills", + "description": "Sélectionnez une Skill à gauche. À droite, un aperçu Markdown s’affiche par défaut ; passez en édition pour modifier et enregistrer.", + "loadingAgents": "Chargement des agents qui prennent en charge les Skills...", + "emptyNoManageableAgents": "Aucun agent disponible pour la gestion des Skills.", + "managedTarget": "Cible gérée", + "selectAgentPlaceholder": "Sélectionnez un agent", + "searchPlaceholder": "Rechercher par nom / ID / chemin...", + "skillsList": "Liste des Skills", + "loadingSkills": "Chargement des Skills...", + "agentNotSupported": "L’agent actuel ne prend pas en charge la gestion des Skills.", + "emptySkills": "Aucune Skill pour le moment. Cliquez sur « Nouvelle Skill » pour en créer une.", + "newSkillTitle": "Nouvelle Skill", + "skillInfo": "Infos de la Skill", + "skillIdPlaceholder": "skill-id (lettres/chiffres/-/_/.)", + "skillsDirectoryWithPath": "Répertoire des Skills : {path}", + "skillsDirectoryNeedId": "Répertoire des Skills : saisissez l’ID de Skill pour générer le chemin complet", + "markdownContent": "Contenu Markdown", + "editingStatus": "Édition", + "previewStatus": "Aperçu", + "contentPlaceholder": "Saisissez le contenu Markdown de la Skill...", + "metadataTitle": "Métadonnées des Skills", + "onlyYamlMetadata": "Cette Skill contient uniquement des métadonnées YAML.", + "emptyContentHint": "Aucun contenu pour le moment. Cliquez sur « Éditer » pour commencer.", + "loadingSkill": "Chargement de la Skill...", + "emptyNoAgents": "Aucun agent disponible.", + "noSelectionHint": "Sélectionnez un Skill à gauche ou cliquez sur « Nouveau Skill » pour en créer un.", + "systemBadge": "Système", + "systemHint": "Skill intégré du CLI · lecture seule", + "scope": { + "global": "Global", + "folder": "Dossier", + "selectFolderPlaceholder": "Sélectionner un dossier", + "noFolders": "Aucun dossier trouvé", + "pickFolderHint": "Sélectionnez un dossier pour afficher ses Skills." + }, + "actions": { + "preview": "Aperçu", + "edit": "Éditer", + "openInWindow": "Ouvrir dans une nouvelle fenêtre", + "delete": "Supprimer", + "deleting": "Suppression...", + "refresh": "Actualiser", + "newSkill": "Nouvelle Skill", + "reset": "Réinitialiser", + "save": "Enregistrer", + "saving": "Enregistrement...", + "cancel": "Annuler" + }, + "deleteDialog": { + "title": "Supprimer la Skill", + "confirm": "Supprimer la Skill actuelle ? Cette action est irréversible.", + "confirmWithNamePrefix": "Supprimer la Skill", + "confirmWithNameSuffix": "? Cette action est irréversible." + }, + "toasts": { + "loadFailed": "Échec du chargement de la Skill", + "openFolderFailed": "Échec de l'ouverture du dossier", + "noSkillDirectory": "Aucun répertoire de Skills disponible pour l’agent actuel", + "nameRequired": "Le nom de la Skill ne peut pas être vide", + "updated": "Skill mise à jour", + "created": "Skill créée", + "saveFailed": "Échec de l’enregistrement de la Skill", + "deleted": "Skill supprimée", + "deleteFailed": "Échec de la suppression de la Skill" + }, + "templates": { + "gemini": "---\nname: example-skill\ndescription: Describe when this skill should be used.\n---\n\n# Skill Name\n\nInstructions for the agent when this skill is active.\n\n## Workflow\n\n1. Add actionable step one.\n2. Add actionable step two.\n", + "openCode": "---\nname: example-skill\ndescription: Describe when this skill should be used.\n---\n\n# Purpose\n\nDescribe what this skill helps with.\n\n# Steps\n\n1. Add actionable step one.\n2. Add actionable step two.\n", + "openClaw": "---\nname: example-skill\ndescription: Describe when this skill should be used.\nuser-invocable: true\ndisable-model-invocation: false\n---\n\n# Purpose\n\nDescribe what this skill helps with.\n\n# Instructions\n\n1. Add actionable instruction one.\n2. Add actionable instruction two.\n", + "default": "---\nname: example-skill\ndescription: Describe when this skill should be used.\n---\n\n# Skill: example-skill\n\n## When to use\n\n- Describe trigger conditions.\n\n## Instructions\n\n1. Add actionable instruction one.\n2. Add actionable instruction two.\n" + } + }, + "McpSettings": { + "loading": "Chargement...", + "summary": { + "missingCommand": "(commande manquante)", + "missingUrl": "(URL manquante)" + }, + "protocol": { + "stdio": "Stdio" + }, + "errors": { + "selectInstallProtocol": "Veuillez sélectionner un protocole d’installation", + "fieldRequired": "{field} est requis", + "fieldNeedsBoolean": "{field} doit être true ou false", + "fieldNeedsNumber": "{field} doit être un nombre", + "fieldNeedsInteger": "{field} doit être un entier", + "fieldInvalidJson": "{field} contient un JSON invalide : {message}", + "fieldOutOfRange": "La valeur de {field} est hors de la plage autorisée", + "jsonEmpty": "{name} ne peut pas être vide", + "jsonInvalid": "{name} n’est pas un JSON valide : {message}", + "jsonMustBeObject": "{name} doit être un objet JSON", + "specMustBeObject": "La configuration MCP doit être un objet JSON.", + "missingType": "Le champ type est manquant dans la configuration MCP. Indiquez stdio, http (alias : streamable-http, streamableHttp) ou sse.", + "unsupportedType": "Type MCP non pris en charge {type}. Pris en charge : stdio, http (alias : streamable-http, streamableHttp), sse.", + "codexEntryUnsupportedType": "L’entrée MCP Codex {id} a un type non pris en charge {type}. Pris en charge : stdio, http (alias : streamable-http, streamableHttp), sse.", + "unsupportedTransportType": "Type de transport non pris en charge {type}. Pris en charge : http (alias : streamable-http, streamableHttp), sse.", + "stdioCommandRequired": "Un MCP stdio nécessite un champ command non vide.", + "remoteUrlRequired": "Un MCP distant nécessite un champ url non vide.", + "appsRequired": "Sélectionnez au moins une application cible." + }, + "jsonNames": { + "localConfig": "Configuration MCP", + "installConfig": "Configuration d’installation" + }, + "toasts": { + "uninstalled": "MCP désinstallé", + "uninstallFailed": "Échec de la désinstallation : {message}", + "selectAtLeastOneApp": "Veuillez sélectionner au moins une application cible", + "saveSuccess": "Enregistré", + "saveFailed": "Échec de l’enregistrement : {message}", + "installed": "{name} installé", + "installFailed": "Échec de l’installation : {message}", + "serverIdRequired": "L'ID du serveur est requis", + "serverIdExists": "Le Server ID \"{id}\" existe déjà. Modifiez l'entrée existante ou choisissez un autre nom.", + "created": "MCP créé" + }, + "installDialog": { + "title": "Confirmer l’installation MCP", + "descriptionWithName": "Installer {name} dans la configuration locale.", + "description": "Sélectionnez les applications cibles pour l’installation.", + "protocol": "Protocole", + "selectProtocol": "Sélectionner un protocole", + "parameters": "Paramètres de configuration", + "booleanPlaceholder": "Veuillez sélectionner true/false", + "selectOneValue": "Sélectionner une valeur", + "targetApps": "Applications cibles" + }, + "actions": { + "cancel": "Annuler", + "confirmInstall": "Confirmer l’installation", + "installing": "Installation", + "uninstall": "Désinstaller", + "uninstalling": "Désinstallation", + "viewDetails": "Voir les détails", + "save": "Enregistrer", + "saving": "Enregistrement", + "install": "Installer", + "refresh": "Actualiser", + "newMcp": "Nouveau MCP", + "create": "Créer", + "creating": "Création..." + }, + "tabs": { + "local": "MCP local", + "market": "Marketplace MCP" + }, + "local": { + "filterPlaceholder": "Filtrer les MCP locaux...", + "loadFailed": "Échec du chargement : {message}", + "empty": "Aucun MCP local détecté.", + "description": "La configuration MCP locale peut être modifiée et enregistrée directement.", + "enabledApps": "Applications activées", + "configJson": "Configuration MCP (JSON)", + "draftTitle": "Nouveau MCP", + "draftDescription": "Renseignez un Server ID et une configuration pour créer un serveur MCP local.", + "serverIdLabel": "ID du serveur", + "serverIdPlaceholder": "ID du serveur (ex. my-mcp)", + "typeHint": "Types pris en charge : stdio, http (alias : streamable-http, streamableHttp), sse. env n'est utilisé que par stdio ; pour les MCP distants, utilisez headers pour transporter les jetons d'authentification.", + "envOnRemoteWarning": "env détecté sur un MCP distant. Seul stdio utilise env ; les MCP distants transportent les jetons d'authentification via headers, donc env sera ignoré à l'enregistrement." + }, + "market": { + "selectMarketplace": "Sélectionner un marketplace", + "searchPlaceholder": "Rechercher MCP...", + "searchFailed": "Échec de la recherche : {message}", + "loadingList": "Chargement de la liste MCP...", + "empty": "Aucun résultat MCP.", + "loadingDetail": "Chargement des détails du marketplace...", + "detailLoadFailed": "Échec du chargement des détails : {message}", + "owner": "Propriétaire : {owner}", + "namespace": "Espace de noms : {namespace}", + "defaultInstallProtocol": "Protocole d’installation par défaut", + "currentOptionParameterCount": "Nombre de paramètres de l’option actuelle : {count}", + "installConfigDescription": "Configuration d’installation (JSON, modifiable avant installation ; les modifications remplaceront le formulaire protocole/paramètres)", + "selectLeftToView": "Sélectionnez un MCP du marketplace à gauche pour voir les détails." + }, + "badges": { + "verified": "Vérifié", + "remote": "Distant", + "hasHomepage": "A une page d’accueil", + "uses": "{count} utilisations", + "deployed": "Déployé", + "notDeployed": "Non déployé" + }, + "selectLeftMcp": "Sélectionnez un MCP à gauche." + }, + "AcpAgentSettings": { + "title": "Gestion du SDK des agents", + "description": "Gérez en un seul endroit la connexion SDK des agents, l'état activé, les variables d'environnement, la gestion de configuration et les informations de préflight de version.", + "loadingAgents": "Chargement de la liste des agents...", + "agentList": "Liste des agents", + "emptyNoAgent": "Aucun agent disponible.", + "configManagement": "Gestion de configuration", + "envVars": "Variables d'environnement", + "hostTools": { + "label": "Laisser l'agent gérer les fichiers et les commandes", + "description": "codeg cesse d'assurer l'accès aux fichiers et les commandes de terminal : l'agent les exécute dans son propre processus, là où son bac à sable et ses règles d'autorisation s'appliquent réellement. La délégation à d'autres agents est également désactivée, car elle ferait repasser le même travail par codeg. codeg n'ajoute aucun bac à sable, n'activez donc ceci que si l'agent en a un configuré." + }, + "nativeJsonConfig": "Configuration JSON native", + "modelHintDefault": "Laissez vide pour utiliser le modèle système par défaut.", + "generalConfigDescriptionClaude": "Prend en charge la configuration rapide de l'API URL, API Key et des modèles Claude, et synchronise avec la configuration JSON native.", + "generalConfigDescriptionDefault": "Prend en charge les entrées de configuration importantes (API URL, API Key, Model) et la gestion de la configuration JSON native.", + "multiAgent": { + "title": "Collaboration multi-agent", + "description": "Permet aux agents actifs de déléguer des sous-tâches à d’autres agents.", + "enable": "Activer la délégation", + "enableHint": "Lorsque cette option est désactivée, l’outil delegate_to_agent est masqué du catalogue d’outils MCP de l’agent.", + "withheldByHostTools": "{agents} ne recevront pas les outils de délégation : leur interrupteur par agent « Laisser l’agent gérer les fichiers et les commandes » est activé.", + "selfInitiate": "Allow spawn without @", + "selfInitiateHint": "When on, an agent may start a listed sub-agent on its own. An @ mention is still always honored. When off, only an @ mention starts a sub-agent.", + "depthLimit": "Profondeur maximale de délégation", + "depthHint": "Plage autorisée : {min}–{max}. Limite la profondeur de récursion d’une chaîne de délégation (racine → enfant → petit-enfant …).", + "completedCacheLabel": "Cache des résultats terminés (MB)", + "completedCacheHint": "Cache en mémoire des résultats terminés des sous-agents, conservé uniquement tant que la session de délégation est en cours et libéré automatiquement à la fin de cette session. Au-delà de ce budget, les résultats les plus anciens sont supprimés de la mémoire en premier (toujours consultables dans la session du sous-agent) ; 0 = illimité (libéré quand même à la fin de la session).", + "save": "Enregistrer", + "saving": "Enregistrement…", + "saved": "Paramètres de délégation enregistrés", + "saveFailed": "Échec de l’enregistrement des paramètres de délégation", + "loadFailed": "Échec du chargement des paramètres de délégation : {detail}", + "tabGeneral": "Général", + "tabAgentDefaults": "Valeurs par défaut du sous-agent", + "agentDefaultsDescription": "Remplacements par agent appliqués lorsque la Collaboration multi-agent démarre un sous-agent pour un appel de délégation. Les options affichées proviennent d’une sonde en direct : votre sélection correspond exactement à ce que l’agent acceptera.", + "probing": "Chargement des options disponibles depuis l’agent…", + "probeFailed": "Échec du chargement des options : {detail}", + "retry": "Réessayer", + "noConfigAvailable": "Cet agent n’a aucune option configurable.", + "modeLabel": "Mode", + "agentDefaultHint": "Valeur par défaut de l’agent : {value}", + "defaultOptionLabel": "Par défaut ({value})" + }, + "actions": { + "dragSort": "Glisser pour réordonner", + "dragSortAgent": "Glisser pour réordonner {name}", + "refreshCheck": "Actualiser la vérification", + "refreshCheckAgent": "Actualiser la vérification de {name}", + "clickEnable": "Cliquer pour activer {name}", + "clickDisable": "Cliquer pour désactiver {name}", + "install": "Installer", + "upgrade": "Mettre à niveau", + "uninstall": "Désinstaller", + "uninstalling": "Désinstallation...", + "saveEnvVars": "Enregistrer les variables d’environnement", + "saving": "Enregistrement...", + "saveGrokConfig": "Enregistrer la configuration Grok", + "saveCodexConfig": "Enregistrer la config Codex", + "saveGeminiConfig": "Enregistrer la config Gemini", + "saveOpenCodeConfig": "Enregistrer la config OpenCode", + "saveOpenClawConfig": "Enregistrer la config OpenClaw", + "saveConfigManagement": "Enregistrer la gestion de config", + "saveCurrentProvider": "Enregistrer le provider actuel", + "showApiKey": "Afficher la clé API", + "hideApiKey": "Masquer la clé API", + "showKey": "Afficher la clé", + "hideKey": "Masquer la clé", + "showToken": "Afficher le token", + "hideToken": "Masquer le token", + "cancel": "Annuler", + "delete": "Supprimer", + "deleting": "Suppression...", + "confirmDelete": "Confirmer la suppression", + "confirmUninstall": "Confirmer la désinstallation", + "saveClineConfig": "Enregistrer la configuration Cline", + "saveHermesConfig": "Enregistrer la configuration Hermes", + "saveCodeBuddyConfig": "Enregistrer la configuration CodeBuddy", + "saveKimiCodeConfig": "Enregistrer la configuration de Kimi Code", + "customInstall": "Installation personnalisée", + "saveKimiCodeRawConfig": "Enregistrer config.toml", + "saveDeepSeekConfig": "Enregistrer la configuration DeepSeek", + "diagnose": "Diagnostiquer" + }, + "status": { + "enabled": "Activé", + "disabled": "Désactivé", + "unchecked": "Non vérifié", + "agentEnabledAria": "{name} activé", + "agentEnabledSwitch": "Interrupteur d’activation {name}" + }, + "preflight": { + "count": "Éléments de pré-vérification : {count}", + "notRun": "Les vérifications n’ont pas encore été exécutées." + }, + "grok": { + "configDescription": "Configurez Grok ici. Les contrôles ci-dessous — mode d'autorisation, effort de raisonnement, un modèle personnalisé optionnel (point de terminaison dédié) et le compactage — sont fusionnés dans ~/.grok/config.toml, en préservant vos autres clés et commentaires. La connexion utilise votre XAI_API_KEY ou `grok login`. Les autres clés restent modifiables sous Avancé.", + "permissionModeLabel": "Mode d'autorisation", + "permissionDefault": "Demander à chaque fois", + "permissionAcceptEdits": "Approuver les modifications automatiquement", + "permissionAuto": "Approbation automatique intelligente", + "permissionAlwaysApprove": "Toujours approuver", + "reasoningEffortLabel": "Effort de raisonnement", + "effortLow": "Faible (plus rapide)", + "effortMedium": "Moyen (équilibré)", + "effortHigh": "Élevé", + "effortXhigh": "Maximum", + "optionDefault": "Utiliser la valeur par défaut", + "authTitle": "Authentification", + "authMode": "Méthode d'authentification", + "authModeApiKey": "Clé API XAI", + "authModeApiKeyHint": "Authentifiez-vous avec une XAI_API_KEY de la console xAI, pour les exécutions non interactives ou headless. Enregistrée dans l'environnement de cet agent.", + "authModeCustom": "Point de terminaison personnalisé", + "authModeCustomHint": "Utilisez votre propre point de terminaison (BYO) : définissez ci-dessous un modèle personnalisé avec sa propre URL de base et sa clé API. Il devient le modèle par défaut de Grok.", + "subscriptionHint": "Connectez-vous avec `grok login` (SuperGrok / X Premium+). Aucune clé API n'est enregistrée.", + "loginHint": "Exécutez ceci dans un terminal pour vous connecter, puis rouvrez ces paramètres :", + "commandCopied": "Commande copiée dans le presse-papiers", + "copyCommand": "Copier la commande", + "authKeyConfigured": "XAI_API_KEY est configurée.", + "authKeyMissing": "Aucune XAI_API_KEY définie.", + "advancedToggle": "Avancé (config.toml brut)", + "configTomlNative": "config.toml (natif)", + "configTomlHint": "Enregistré tel quel comme l'intégralité de ~/.grok/config.toml. Le TOML invalide est rejeté afin qu'une faute de frappe ne tronque jamais votre fichier.", + "configTomlPlaceholder": "# Clés autres que les contrôles ci-dessus, p. ex.\n# [mcp_servers.*], [cli], règles [permission].", + "customModelTitle": "Modèle personnalisé (point de terminaison dédié)", + "customModelHint": "Dirigez Grok vers un point de terminaison personnalisé ou auto-hébergé. codeg écrit un bloc `[model.*]` par modèle et le définit comme modèle par défaut. Laissez l'ID de modèle vide pour le supprimer.", + "customModelIdLabel": "ID du modèle", + "customModelIdPlaceholder": "grok-4.5", + "customModelIdHint": "Enregistré comme bloc `[model.*]` et envoyé à l'API comme nom de modèle ; également défini comme `[models].default`.", + "customBaseUrlLabel": "URL de base", + "customBaseUrlPlaceholder": "https://api.x.ai/v1 (par défaut)", + "customApiBackendLabel": "Backend de l'API", + "backendResponses": "Responses", + "backendChatCompletions": "Chat Completions", + "backendMessages": "Messages (Anthropic)", + "customApiKeyLabel": "Clé API", + "customApiKeyHint": "Stockée en ligne dans `[model.*].api_key`, limitée à ce point de terminaison.", + "customContextWindowLabel": "Fenêtre de contexte (tokens)", + "customContextWindowHint": "Facultatif. Détermine le moment du compactage automatique ; laissez vide pour la valeur par défaut du point de terminaison.", + "autoCompactLabel": "Seuil de compactage automatique (%)", + "autoCompactHint": "Compacte la conversation lorsque l'utilisation du contexte atteint ce pourcentage (85 par défaut pour Grok). Écrit dans `[session]`." + }, + "cursor": { + "configDescription": "Configurez Cursor ici. Choisissez une méthode d'authentification — abonnement officiel (connexion par navigateur) ou une clé API Cursor pour les machines sans interface ou serveurs — puis choisissez un modèle et modifiez les règles d'autorisation et le bac à sable du CLI. codeg les écrit dans ~/.cursor/cli-config.json, partagé avec le CLI cursor-agent.", + "authTitle": "Authentification", + "authChecking": "Vérification…", + "authNotInstalled": "cursor-agent n'est pas installé", + "authLoggedIn": "Connecté", + "authNotLoggedIn": "Non connecté", + "loginHint": "Exécutez ceci dans un terminal pour vous connecter à votre compte Cursor (une fenêtre de navigateur s'ouvre), puis cliquez sur actualiser :", + "apiKeyLabel": "Clé API Cursor", + "apiKeyPlaceholder": "clé depuis cursor.com/dashboard", + "apiKeyHint": "CURSOR_API_KEY — une clé de compte du tableau de bord Cursor, alternative à la connexion par navigateur pour les machines sans interface ou serveurs. Ce n'est pas une clé tierce ni OpenAI.", + "modelTitle": "Modèle par défaut", + "loadModels": "Charger les modèles", + "modelsUnavailable": "Liste de modèles indisponible", + "modelHint": "Transmis à la CLI via --model au démarrage de la session. Laissez par défaut pour laisser Cursor choisir.", + "permissionsTitle": "Permissions & bac à sable", + "permissionsDescription": "Éditeur visuel des règles de permissions de la CLI (cli-config.json). Les règles autorisées s'exécutent sans confirmation ; les règles refusées sont toujours bloquées.", + "permissionModeLabel": "Mode d'autorisation", + "permissionModeDefault": "Demander avant d'exécuter (par défaut)", + "permissionModeForce": "Tout exécuter (--force)", + "permissionModeHint": "Tout exécuter lance les sessions avec --force : tous les appels d'outils sont autorisés automatiquement sauf les règles de refus, sans confirmation (une politique d'organisation peut le limiter aux règles d'autorisation). S'applique aux nouvelles sessions.", + "optionDefault": "Défaut (non défini)", + "sandboxLabel": "Bac à sable", + "sandboxEnabled": "Activé", + "sandboxDisabled": "Désactivé", + "allowRulesLabel": "Règles autorisées", + "denyRulesLabel": "Règles refusées", + "addRule": "Ajouter une règle", + "rulesSyntaxHint": "Syntaxe des règles : Shell(cmd), Read(chemin/glob), Write(chemin/glob), WebFetch(domaine), Mcp(serveur:outil) — les règles de refus priment toujours.", + "saveConfig": "Enregistrer la configuration", + "advancedToggle": "Avancé : cli-config.json brut", + "advancedHint": "Le ~/.cursor/cli-config.json complet. Enregistrer écrit le fichier tel quel ; les contrôles structurés ci-dessus y sont fusionnés.", + "saveRawConfig": "Enregistrer le fichier", + "authMode": "Méthode d'authentification", + "subscriptionHint": "Connectez-vous avec votre compte Cursor et utilisez les modèles de Cursor.", + "customApiKeyRequired": "Une clé API Cursor est requise.", + "authModeApiKey": "Clé API Cursor (sans interface)", + "authModeApiKeyHint": "Authentifiez-vous avec une clé API de compte Cursor générée dans le tableau de bord Cursor (pour les machines sans interface ou serveurs). C'est une clé de compte Cursor, pas un point de terminaison tiers/OpenAI : cursor-agent ne communique qu'avec le backend de Cursor. Pour utiliser un point de terminaison compatible codex/OpenAI, utilisez plutôt l'agent Codex.", + "modelPickerPlaceholder": "Rechercher des modèles…", + "modelNoMatch": "Aucun modèle correspondant", + "modelsNeedAuth": "Connectez-vous pour charger la liste des modèles.", + "modelDefaultBadge": "par défaut" + }, + "deepseek": { + "configManagement": "Configuration de DeepSeek Harness", + "configDescription": "Le point de terminaison et la clé sont des variables d'environnement que deepseek-acp lit au démarrage. Le modèle et le niveau de raisonnement sont des sélecteurs par session : ils se choisissent dans le champ de saisie.", + "baseUrlLabel": "Point de terminaison de l'API", + "baseUrlHint": "Laissez vide pour le point de terminaison officiel. S'applique aux sessions démarrées après l'enregistrement ; reconnectez une session en cours pour qu'elle le prenne en compte.", + "baseUrlInvalid": "Saisissez une URL http(s) complète et sans chaîne de requête, par exemple https://api.deepseek.com", + "apiKeyLabel": "Clé d'API", + "apiKeyHint": "Transmise à l'agent via DEEPSEEK_API_KEY. Une variable d'environnement l'emporte sur le fichier d'identifiants : laissez ce champ vide si vous vous connectez depuis le terminal." + }, + "codex": { + "configDescription": "Prend en charge la configuration rapide de l’URL API, de la clé API, du nom du modèle et du reasoning effort, avec synchronisation vers `auth.json` / `config.toml`.", + "authMode": "Mode d’authentification", + "chatgptSubscription": "Abonnement officiel", + "chatgptSubscriptionHint": "Connectez-vous avec l’abonnement officiel ChatGPT, pas besoin d’API Key", + "apiKeyHint": "Connectez-vous avec une API Key à OpenAI ou aux services API compatibles", + "selectProvider": "Sélectionner un provider", + "modelName": "Nom du modèle", + "selectReasoningEffort": "Sélectionner Reasoning Effort", + "enableWebsocket": "Activer WebSocket", + "enableWebsocketAria": "Activer WebSocket pour Codex Provider", + "enableSkills": "Activer Skills", + "enableSkillsAria": "Activer Skills pour Codex", + "enableFast": "Activer Fast", + "enableFastAria": "Activer le niveau de service Fast pour Codex", + "sandboxGroupTitle": "Bac à sable et approbations", + "sandboxGroupHint": "Écrit dans le ~/.codex/config.toml global, donc les sessions codex CLI et IDE en héritent aussi. Ce sont des valeurs par défaut du fil : elles régissent les tours que codex démarre lui-même (/goal, /review, /compact). Les messages ordinaires utilisent le préréglage d'approbation de la zone de saisie. Redémarrez une session pour appliquer les changements.", + "sandboxShadowedWarning": "config.toml définit default_permissions : codex résout les permissions via ce profil et ignore totalement sandbox_mode. Supprimez default_permissions pour utiliser les réglages ci-dessous.", + "sandboxPermissionsTableWarning": "config.toml définit des profils [permissions] sans default_permissions, ce qui empêche codex de démarrer. Renseignez-le dans l'éditeur brut ci-dessous.", + "approvalPolicyLabel": "Politique d'approbation", + "approvalPolicyUnset": "Non définie (défaut codex : à la demande)", + "approvalPolicy_on-request": "À la demande — le modèle décide quand demander", + "approvalPolicy_untrusted": "Non fiable — seules les commandes en lecture seule reconnues sûres s'exécutent sans validation", + "approvalPolicy_never": "Jamais — aucune demande d'approbation", + "approvalPolicy_granular": "Granulaire — au cas par cas selon le type", + "approvalPolicyUntrustedAcpWarning": "« Untrusted » n'a pas d'équivalent parmi les trois préréglages d'approbation de l'adaptateur ACP ; les sessions codeg retombent donc sur « à la demande » : le modèle décide alors quand demander, et les commandes que le bac à sable autorise déjà ne demandent plus rien. Restreignez plutôt le mode de bac à sable ci-dessous.", + "granularHint": "Désactivé signifie que ce type de demande est refusé automatiquement au lieu de vous être présenté.", + "granular_sandbox_approval": "Élévations pour commandes shell", + "granular_rules": "Invites des règles execpolicy", + "granular_skill_approval": "Invites des scripts de compétences", + "granular_request_permissions": "Invites de l'outil request_permissions", + "granular_mcp_elicitations": "Invites d'elicitation MCP", + "sandboxModeLabel": "Mode bac à sable", + "sandboxModeUnset": "Non défini (les dossiers de confiance retombent sur l'écriture dans l'espace de travail)", + "sandboxMode_read-only": "Lecture seule", + "sandboxMode_workspace-write": "Écriture dans l'espace de travail", + "sandboxMode_danger-full-access": "Accès complet (sans bac à sable)", + "sandboxModeHint": "Sous Windows, l'écriture dans l'espace de travail est rétrogradée en lecture seule sauf si le bac à sable Windows expérimental de codex est activé.", + "sandboxModeSeedsPresetHint": "codeg s'en sert aussi pour le préréglage d'approbation initial de la session : contrairement à la politique d'approbation, il agit donc sur les requêtes ordinaires. Le préréglage choisi dans la zone de saisie reste prioritaire.", + "writableRootsLabel": "Dossiers inscriptibles supplémentaires", + "writableRootsHint": "Un chemin absolu par ligne, en plus du répertoire de travail.", + "sandboxRootsRelativeError": "Doit être un chemin absolu — codex résout les chemins relatifs sous ~/.codex : {path}", + "networkAccessLabel": "Autoriser l'accès réseau", + "excludeTmpdirLabel": "Exclure TMPDIR des racines inscriptibles", + "excludeSlashTmpLabel": "Exclure /tmp des racines inscriptibles", + "authJsonNative": "auth.json (natif)", + "configTomlNative": "config.toml (natif)", + "loginButton": "Se connecter avec ChatGPT", + "loginRequesting": "Demande du code de connexion...", + "loginStep1": "Ouvrez l'URL suivante dans votre navigateur :", + "loginStep2": "Entrez le code ci-dessous :", + "loginPolling": "En attente d'autorisation...", + "loginCancel": "Annuler", + "loginSuccess": "Connexion réussie, configuration enregistrée !", + "loginFailed": "Échec de la connexion : {message}", + "loginRetry": "Réessayer", + "loginCodeCopied": "Code copié", + "loggedIn": "Compte connecté", + "loginRelogin": "Reconnecter / Changer de compte", + "loginTimeout": "Connexion expirée, veuillez réessayer", + "loginSaveFailed": "Connexion réussie mais échec de la sauvegarde de la configuration" + }, + "gemini": { + "authConfig": "Configuration d’authentification Gemini", + "authConfigDescription": "Alignée sur la documentation d’authentification Gemini CLI, avec prise en charge d’un endpoint personnalisé, connexion Google, Gemini API Key et Vertex AI (ADC / compte de service / API Key).", + "authMode": "Mode d’authentification", + "selectAuthMode": "Sélectionner un mode d’authentification", + "viewAuthDoc": "Voir la documentation d’authentification", + "mode": { + "custom": "Endpoint personnalisé", + "loginGoogle": "Connexion Google (OAuth)", + "vertexServiceAccount": "Vertex AI (Compte de service)" + }, + "hint": { + "custom": "Renseignez API URL, API Key et Model, mappés sur GOOGLE_GEMINI_BASE_URL / GEMINI_API_KEY / GEMINI_MODEL.", + "loginGoogle": "Exécutez d’abord gemini dans le terminal et terminez la connexion Google ; la clé API n’est pas requise.", + "geminiApiKey": "Renseignez GEMINI_API_KEY lors de l’utilisation de l’API Gemini.", + "vertexAdc": "Utilisez gcloud ADC ; GOOGLE_CLOUD_PROJECT et GOOGLE_CLOUD_LOCATION sont recommandés.", + "vertexServiceAccount": "Définissez le chemin JSON du compte de service dans GOOGLE_APPLICATION_CREDENTIALS.", + "vertexApiKey": "Renseignez GOOGLE_API_KEY lors de l’utilisation d’une clé API Vertex AI." + } + }, + "openCode": { + "configManagement": "Gestion de configuration OpenCode", + "configDescription": "Alignée sur le schéma `provider` d’OpenCode, prend en charge la gestion multi-provider et la synchronisation bidirectionnelle avec les fichiers JSON natifs.", + "providerManagement": "Gestion des providers", + "providerCount": "{count} fournisseurs", + "addProvider": "Ajouter un provider", + "emptyProvider": "Aucun fournisseur personnalisé pour le moment. Cliquez sur Ajouter un fournisseur personnalisé pour en créer un.", + "providerEnabledState": "État activé de {providerId}", + "selectProviderNpm": "Sélectionner provider.npm", + "modelManagement": "Gestion des modèles", + "modelCount": "{count} modèles", + "modelDescription": "Aligné sur `provider.models` d’OpenCode. La gestion rapide prend actuellement en charge `name` / `id` ; les autres champs avancés sont conservés et peuvent être modifiés dans le JSON natif ci-dessous.", + "addModel": "Ajouter un modèle", + "emptyModel": "Aucun modèle pour le moment. Saisissez model id puis cliquez sur « Ajouter un modèle ».", + "modelId": "ID du modèle", + "modelName": "Nom du modèle", + "deleteModel": "Supprimer le modèle {modelId}", + "nativeJsonConfig": "Configuration JSON native OpenCode", + "mainModel": "Modèle principal", + "smallModel": "Petit modèle", + "noMatchingModels": "Aucun modèle correspondant", + "connectProvider": "Connecter un fournisseur", + "connectedProviders": "Fournisseurs connectés", + "noConnectedProviders": "Aucun fournisseur du catalogue connecté pour le moment.", + "advancedProviderConfig": "Fournisseurs personnalisés", + "customProviderConfigHint": "Points de terminaison compatibles OpenAI que vous définissez vous-même — un bloc provider dans opencode.json, avec la clé API dans auth.json.", + "addCustomProvider": "Ajouter un fournisseur personnalisé", + "disconnect": "Déconnecter", + "editConfig": "Modifier", + "customBadge": "Personnalisé", + "authKindApi": "Clé API", + "authKindOauth": "OAuth", + "authKindNone": "Aucun identifiant", + "connect": { + "title": "Connecter un fournisseur", + "description": "Choisissez un fournisseur dans le catalogue models.dev. Les identifiants sont enregistrés dans le fichier auth.json d'OpenCode.", + "pick": "Fournisseur", + "search": "Rechercher des fournisseurs…", + "loading": "Chargement du catalogue…", + "catalogLabel": "Catalogue models.dev", + "modelsAvailable": "{count} modèles disponibles", + "getKey": "Obtenir la clé API", + "oauthApiKeyNote": "Ce fournisseur prend aussi en charge la connexion via navigateur avec opencode auth login. La connexion par navigateur arrive bientôt ; pour le moment, collez une clé API.", + "apiKey": "Clé API", + "apiKeyHint": "Enregistrée dans auth.json, jamais dans opencode.json.", + "baseUrlOptional": "Remplacer l''URL de base (facultatif)", + "providerId": "ID du fournisseur", + "displayName": "Nom affiché", + "modelsList": "Modèles (un par ligne)", + "modelsHint": "Identifiants de modèle acceptés par le point de terminaison.", + "action": "Connecter", + "editTitle": "Modifier le fournisseur", + "editDescription": "Mettez à jour la clé API ou l''URL de base de ce fournisseur.", + "saveAction": "Enregistrer" + }, + "customProvider": { + "title": "Ajouter un fournisseur personnalisé", + "description": "Définissez un point de terminaison compatible OpenAI. La clé API est enregistrée dans auth.json ; le bloc provider va dans opencode.json.", + "action": "Ajouter le fournisseur", + "idInCatalog": "{providerId} est un fournisseur connu — connectez-le plutôt via Connecter un fournisseur." + }, + "refreshCatalog": "Actualiser le catalogue", + "reasoningBadge": "raisonnement", + "contextWindow": "Fenêtre de contexte", + "permissions": { + "title": "Permissions", + "description": "Décidez quelles actions s’exécutent seules, lesquelles demandent votre accord et lesquelles sont bloquées. Écrit dans le bloc permission de opencode.json et appliqué à l’enregistrement ci-dessous.", + "docsLink": "Documentation des permissions", + "unparsableConfig": "Le JSON natif ci-dessous est invalide, l’éditeur visuel est donc en pause. Corrigez le JSON pour reprendre.", + "invalidBlock": "Le bloc permission a une forme que codeg ne reconnaît pas. Modifiez-le dans le JSON natif ci-dessous ou utilisez Réinitialiser pour repartir de zéro.", + "orderingUnsafe": "Une règle joker est écrite après des outils précis, donc OpenCode l’applique aussi à ceux-ci : les lignes ci-dessous ne sont pas ce qui s’applique réellement. Corriger l’ordre ramène simplement chaque joker en tête de sa portée, sans modifier la moindre valeur.", + "orderingUnsafeManual": "Une règle est masquée par un motif plus général placé après elle, donc OpenCode ne l’applique jamais : les lignes ci-dessous ne sont pas ce qui s’applique réellement. Deux motifs qui se chevauchent n’ont pas d’ordre unique correct ; réordonnez-les dans le JSON natif pour que le plus général vienne en premier.", + "fixOrder": "Corriger l’ordre", + "agentOverrides": "Ces agents redéfinissent les permissions et sont appliqués en dernier, ils l’emportent donc sur tout ce qui est ici : {agents}. Modifiez-les dans le JSON natif ci-dessous, ou activez l’acceptation automatique pour les effacer.", + "legacyTools": "L’ancienne table tools de premier niveau refuse un outil. OpenCode la fusionne avec les permissions, elle s’applique donc par-dessus tout ce qui est affiché ici. Modifiez-la dans le JSON natif ci-dessous, ou activez l’acceptation automatique pour l’effacer.", + "autoAcceptTitle": "Accepter automatiquement toutes les permissions", + "autoAcceptHint": "Chaque appel d’outil — commandes shell, modifications de fichiers, chemins hors du projet — s’exécute sans demander. L’activer remplace les réglages par outil ci-dessous par une seule règle tout-autoriser et efface les surcharges par agent ainsi que les anciens interrupteurs tools qui bloqueraient encore.", + "globalLabel": "Valeur globale par défaut", + "globalHint": "La règle * : elle s’applique à tout ce que les outils ci-dessous ne redéfinissent pas.", + "actionUnset": "Non défini (valeurs OpenCode)", + "actionInherit": "Hériter ({action})", + "actionAllow": "Autoriser", + "actionAsk": "Demander", + "actionDeny": "Refuser", + "perToolTitle": "Permissions par outil", + "reset": "Réinitialiser", + "ruleCount": "règles : {count}", + "rulesToggle": "Règles fines de {tool}", + "rulesHint": "Comparées à l’entrée de l’outil, la dernière correspondance l’emporte : placez donc les motifs larges en premier. * correspond à n’importe quels caractères, ? à exactement un, et un ~ initial désigne votre dossier personnel.", + "noRules": "Aucune règle fine pour l’instant.", + "addRule": "Ajouter une règle", + "deleteRule": "Supprimer la règle {pattern}", + "duplicateRule": "Ce motif existe déjà.", + "blankRule": "Une règle a besoin d’un motif — utilisez l’icône corbeille pour la supprimer.", + "customKeys": "Autres clés de permission du fichier", + "customKeyHint": "Ce n’est pas un outil intégré d’OpenCode — conservé tel quel.", + "keys": { + "bash": "Exécuter des commandes shell, selon la commande analysée", + "edit": "Toutes les modifications de fichiers : edit, write et patch", + "read": "Lire des fichiers, selon le chemin", + "external_directory": "Atteindre des chemins hors du répertoire de travail du projet", + "task": "Lancer des sous-agents, selon le type de sous-agent", + "skill": "Charger des skills, selon leur nom", + "glob": "Trouver des fichiers, selon le motif glob", + "grep": "Rechercher dans le contenu des fichiers, selon le motif", + "list": "Lister le contenu d’un répertoire", + "webfetch": "Récupérer une URL", + "websearch": "Rechercher sur le web", + "lsp": "Exécuter des requêtes LSP", + "todowrite": "Écrire la liste de tâches", + "question": "Vous poser une question", + "doom_loop": "Se déclenche quand le même appel se répète trois fois avec la même entrée" + } + } + }, + "openClaw": { + "gatewayConfig": "Configuration Gateway", + "gatewayDescription": "Configure la connexion OpenClaw Gateway. Prend en charge une gateway locale ou distante.", + "gatewayUrlHint": "Laisser vide pour utiliser gateway.remote.url depuis la configuration locale openclaw.", + "gatewayTokenPlaceholder": "Token d’authentification Gateway", + "gatewayTokenHint": "Utilisez token-file plutôt qu’un token en clair si possible ; configurez-le via le CLI openclaw.", + "sessionKeyHint": "Optionnel. Spécifie la session key de la gateway ; laisser vide pour auto-attribuer une session isolée." + }, + "hermes": { + "configManagement": "Configuration de Hermes", + "configDescription": "Hermes gère ses propres identifiants dans ~/.hermes/.env et ses paramètres dans ~/.hermes/config.yaml. Choisissez un fournisseur, puis définissez la clé d'API et le modèle — codeg écrit les deux fichiers pour vous.", + "providerLabel": "Fournisseur", + "providerHint": "Le fournisseur détermine quelle variable de clé d'API et quel model.provider Hermes utilise. Les fournisseurs OAuth se configurent via la configuration du terminal ci-dessous.", + "groupApiKey": "Fournisseurs avec clé API", + "groupOauth": "Fournisseurs OAuth", + "groupAws": "AWS", + "apiKeyHint": "Enregistrée dans ~/.hermes/.env. Elle n'est jamais injectée dans le processus — Hermes la lit depuis sa propre configuration.", + "modelName": "Modèle", + "oauthHint": "Ce fournisseur utilise OAuth. Exécutez la configuration ci-dessous pour vous authentifier dans votre terminal.", + "awsHint": "Bedrock utilise vos identifiants AWS (environnement ou configuration partagée). Définissez l'ID du modèle ci-dessus et configurez l'accès AWS dans votre environnement.", + "unsupportedProvider": "Ce fournisseur n'est pas modifiable via les champs structurés. Utilisez l'éditeur config.yaml ci-dessous ou la configuration par terminal.", + "setupTitle": "Configuration autogérée", + "setupHint": "La configuration interactive de Hermes nécessite un terminal. Lancez-la ci-dessous ou copiez la commande pour l'exécuter vous-même.", + "runSetup": "Exécuter la configuration de Hermes", + "configureModel": "Configurer le modèle", + "openConfigFolder": "Ouvrir ~/.hermes", + "copyCommand": "Copier la commande", + "commandCopied": "Commande copiée dans le presse-papiers", + "advancedTitle": "Avancé : modifier config.yaml", + "rawConfigHint": "Modifiez directement ~/.hermes/config.yaml. Enregistrer ici écrase le fichier tel quel.", + "saveRawConfig": "Enregistrer config.yaml" + }, + "codebuddy": { + "configManagement": "Configuration de CodeBuddy", + "configDescription": "CodeBuddy s'authentifie avec une clé API. Les versions pour la Chine continentale nécessitent aussi de définir l'environnement sur « Chine (internal) » ; les versions iOA utilisent « iOA ». La version internationale la laisse non définie.", + "apiKeyLabel": "Clé API", + "apiKeyHint": "Enregistré en tant que CODEBUDDY_API_KEY pour cet agent. Vous pouvez aussi vous connecter avec la CLI CodeBuddy dans un terminal.", + "apiKeyHintSelfHosted": "Enregistré en tant que CODEBUDDY_API_KEY pour cet agent. Utilisez la clé émise par votre déploiement privé.", + "environmentLabel": "Environnement", + "environmentHint": "Définit CODEBUDDY_INTERNET_ENVIRONMENT. La Chine continentale doit utiliser « Chine (internal) » ; la version internationale la laisse non définie.", + "envOverseas": "International (par défaut)", + "envChina": "Chine (internal)", + "envIoa": "iOA", + "envSelfHosted": "Auto-hébergé (déploiement privé)", + "baseUrlLabel": "URL de déploiement", + "baseUrlPlaceholder": "https://codebuddy.your-company.com", + "baseUrlHint": "Enregistré comme CODEBUDDY_BASE_URL et dirige CodeBuddy vers votre point de terminaison privé. En auto-hébergement, l’environnement réseau (CODEBUDDY_INTERNET_ENVIRONMENT) reste non défini.", + "baseUrlInvalid": "Saisissez une URL http(s) valide.", + "loginHint": "Pas de clé API ? Exécutez « codebuddy » dans un terminal pour vous connecter avec votre compte Tencent." + }, + "kimiCode": { + "configManagement": "Configuration de Kimi Code", + "configDescription": "`kimi acp` n'accepte qu'un jeton de connexion enregistré ; codeg écrit donc un fournisseur géré dans ~/.kimi-code/config.toml et dépose un jeton d'accès local — l'inférence utilise toujours votre propre clé.", + "statusUnconfigured": "Pas encore configuré", + "statusDirty": "Modifications non enregistrées", + "summaryLabel": "En vigueur", + "gateReadyApiKey": "Clé API écrite dans config.toml", + "gateReadyLogin": "Connecté avec un compte Kimi", + "revealConfig": "Afficher dans le dossier", + "envOverrideWarning": "{keys} est défini et prime sur config.toml. Enregistrer ici la supprime.", + "authModeLabel": "Méthode d'authentification", + "authModeApiKey": "Clé API", + "authModeLogin": "Connexion au compte Kimi (abonnement)", + "authModeApiKeyHint": "Écrit un fournisseur géré dans config.toml et dépose le jeton d'accès pour que les sessions puissent s'ouvrir.", + "loginHint": "Exécutez `kimi login` dans un terminal pour vous connecter avec un compte Kimi par abonnement. codeg ne stocke rien et réutilise la connexion de Kimi. Enregistrer ici supprime le jeton d'accès par clé API de codeg.", + "credentialTitle": "Identifiant", + "interfaceTypeLabel": "Type de fournisseur", + "interfaceTypeHint": "Le protocole de fournisseur que parle Kimi (le `type` de config.toml). Choisissez Kimi / Moonshot pour une clé Moonshot / platform.kimi.com.", + "endpointLabel": "Point de terminaison", + "endpointCustom": "Personnalisé (compatible OpenAI)", + "endpointHint": "International = api.moonshot.ai ; Chine (clés platform.kimi.com) = api.moonshot.cn. Personnalisé pointe vers n'importe quel point de terminaison compatible OpenAI.", + "regionInternational": "International (api.moonshot.ai)", + "regionChina": "Chine (api.moonshot.cn)", + "baseUrlLabel": "URL de base", + "baseUrlHint": "Laissez vide pour utiliser la valeur par défaut du SDK du fournisseur.", + "apiKeyLabel": "Clé API", + "apiKeyHint": "Écrite dans ~/.kimi-code/config.toml et utilisée pour l'inférence. Depuis platform.kimi.com ou platform.kimi.ai.", + "vertexProjectLabel": "Projet GCP (GOOGLE_CLOUD_PROJECT)", + "vertexLocationLabel": "Région GCP (GOOGLE_CLOUD_LOCATION)", + "vertexHint": "Vertex AI utilise les identifiants par défaut de l'application Google — exécutez `gcloud auth application-default login` (aucune clé API).", + "modelTitle": "Modèle", + "modelLabel": "Modèle", + "modelHint": "L'id du modèle écrit dans config.toml. Utilisez « Tester et lister les modèles » pour voir ce à quoi votre clé accède réellement.", + "maxContextLabel": "Taille de contexte maximale", + "maxContextHint": "Obligatoire selon le schéma de Kimi : sans elle, Kimi rejette tout le bloc du modèle et chaque requête reste sans réponse. Par défaut 262144.", + "fetchModels": "Tester et lister les modèles", + "fetchModelsOk": "La clé fonctionne — {count} modèles disponibles", + "fetchModelsEmpty": "La clé fonctionne, mais aucun modèle n'a été renvoyé", + "fetchModelsFailed": "Échec du test", + "fetchModelsNeedsKey": "Saisissez d'abord une clé API et un point de terminaison", + "modelNotInList": "Ce modèle ne figure pas dans la liste accessible à votre clé — Kimi échouera avec « modèle introuvable ».", + "reasoningTitle": "Raisonnement", + "reasoningEnableLabel": "Activer", + "reasoningDescription": "Kimi n'affiche le sélecteur « Thinking » dans la zone de saisie que si le modèle déclare une capacité de raisonnement ; codeg l'écrit donc ici. S'applique aux nouvelles sessions.", + "effortsLabel": "Niveaux proposés", + "effortsHint": "Ces niveaux deviennent les entrées du sélecteur « Thinking ». Kimi transmet le niveau au fournisseur tel quel : choisissez ceux que votre modèle accepte.", + "effortsEmptyHint": "Sans aucun niveau sélectionné, la zone de saisie se limite à un simple interrupteur Off / On.", + "effortsCustomPlaceholder": "Ajouter un autre niveau", + "effortsAdd": "Ajouter", + "defaultEffortLabel": "Niveau par défaut", + "defaultEffortAuto": "Laisser Kimi choisir", + "alwaysThinkingLabel": "Le modèle raisonne toujours — retirer l'entrée Off du sélecteur", + "fixErrorsFirst": "Corrigez d'abord les champs signalés", + "errorModelRequired": "Le modèle est obligatoire", + "errorMaxContextRequired": "La taille de contexte maximale est obligatoire", + "errorMaxContextInvalid": "Doit être un entier positif", + "errorApiKeyRequired": "La clé API est obligatoire", + "errorApiKeyInvalid": "La clé API ne doit pas contenir de sauts de ligne", + "errorBaseUrlRequired": "L'URL de base est obligatoire", + "errorBaseUrlInvalid": "Doit commencer par http:// ou https://", + "errorVertexProjectRequired": "Le projet GCP est obligatoire", + "errorDefaultEffortUnlisted": "Choisissez l'un des niveaux sélectionnés ci-dessus", + "advancedTitle": "Avancé", + "authTypeLabel": "Emplacement de l'identifiant", + "authTypeApiKey": "api_key en ligne", + "authTypeEnv": "Sous-table env du fournisseur", + "authTypeHint": "Où la clé API est écrite à l'intérieur de config.toml.", + "rawEditorLabel": "Modifier config.toml directement", + "rawEditorWarning": "Enregistrer ici écrase tout le fichier tel quel et remplace les réglages structurés ci-dessus.", + "rawEditorPlaceholder": "[providers.codeg]\ntype = \"kimi\"\nbase_url = \"https://api.moonshot.cn/v1\"\napi_key = \"sk-...\"" + }, + "authModeOfficialSubscription": "Abonnement officiel", + "authModeCustomEndpoint": "Endpoint personnalisé", + "authModeCustomEndpointHint": "Configurer manuellement l'URL API et la clé API pour un endpoint personnalisé.", + "authModeModelProvider": "Fournisseur de modèle", + "modelProvider": "Fournisseur de modèle", + "modelProviderHint": "Utiliser l'URL API, la clé API et le modèle d'un fournisseur de modèle configuré.", + "selectModelProvider": "Sélectionner un fournisseur de modèle", + "noModelProviderAvailable": "Aucun fournisseur de modèle configuré pour cet agent. Allez dans les paramètres des fournisseurs de modèle pour en ajouter un.", + "claude": { + "authMode": "Mode d’authentification", + "officialSubscription": "Abonnement officiel", + "officialSubscriptionHint": "Utiliser l'abonnement officiel Anthropic, pas de clé API requise.", + "mainModel": "Modèle principal", + "reasoningModel": "Modèle de raisonnement (thinking)", + "haikuDefaultModel": "Modèle Haiku par défaut", + "sonnetDefaultModel": "Modèle Sonnet par défaut", + "opusDefaultModel": "Modèle Opus par défaut", + "customModelOption": "ID de modèle personnalisé", + "customModelOptionName": "Nom du modèle personnalisé", + "customModelOptionDescription": "Description du modèle personnalisé", + "customModelOptionHint": "Ajoute une entrée personnalisée au sélecteur de modèles de Claude (par exemple un modèle derrière une passerelle/un proxy personnalisé). Le nom et la description sont des informations d'affichage facultatives.", + "effortLevel": "Niveau de raisonnement", + "effortLevelDefault": "Niveau par défaut", + "effortLevel_low": "Bas", + "effortLevel_medium": "Moyen", + "effortLevel_high": "Élevé", + "effortLevel_xhigh": "Très Élevé", + "sendAttributionHeader": "Envoyer l'identifiant d'attribution/facturation à l'API", + "sendAttributionHeaderAria": "Envoyer l'identifiant d'attribution/facturation de Claude Code à l'API", + "disableNonessentialTraffic": "Désactiver la télémétrie ou les requêtes réseau superflues", + "disableNonessentialTrafficAria": "Désactiver la télémétrie ou les requêtes réseau superflues de Claude Code" + }, + "dialogs": { + "confirmDeleteProvider": "Supprimer le provider {providerId} ?", + "confirmDeleteProviderDescription": "La configuration OpenCode et auth JSON seront mises à jour ensemble. Cette action est irréversible.", + "confirmUninstall": "Désinstaller {name} ?", + "confirmUninstallDescription": "Cela supprime la version installée localement. Vous pouvez réinstaller plus tard.", + "customInstallTitle": "Installation personnalisée de {name}", + "customInstallDescription": "Saisissez la version à installer. Cela réinstalle et remplace la version actuellement installée.", + "customInstallVersionLabel": "Numéro de version", + "customInstallInvalid": "Saisissez un numéro de version valide, par ex. 1.2.3.", + "customInstallSubmit": "Installer" + }, + "errors": { + "windowsFileLocked": "Les fichiers de {name} sont utilisés par une session en cours, Windows ne peut donc pas les remplacer. Fermez toutes les sessions {name}, puis réessayez.", + "nativeJsonMustBeObject": "La configuration JSON native doit être un objet", + "nativeJsonInvalid": "Erreur de format de configuration JSON native : {message}", + "openCodeAuthMustBeObject": "OpenCode auth.json doit être un objet JSON", + "openCodeAuthInvalid": "Erreur de format OpenCode auth.json : {message}", + "authMustBeObject": "auth.json doit être un objet JSON", + "authInvalid": "Erreur de format auth.json : {message}", + "providerIdPattern": "L’ID du provider n’accepte que lettres, chiffres, underscore, point et tiret", + "providerExists": "Le provider {providerId} existe déjà", + "modelIdPattern": "L’ID du modèle n’accepte que lettres, chiffres, underscore, point, deux-points et tiret", + "modelExists": "Le modèle {modelId} existe déjà" + }, + "warnings": { + "nativeJsonRecoveredStructured": "La configuration JSON native est invalide ; réinitialisée en configuration structurée", + "nativeJsonRecoveredOpenCode": "La configuration JSON native est invalide ; réinitialisée en configuration structurée OpenCode", + "openCodeAuthRecovered": "OpenCode auth.json est invalide ; réinitialisé en configuration par défaut", + "authRecoveredStructured": "auth.json est invalide ; réinitialisé en configuration structurée" + }, + "toasts": { + "agentActionCompleted": "{name} {action} terminé", + "agentActionFailed": "{name} {action} échoué", + "localVersion": "Version locale : {version}", + "installCompletedVersionLater": "Installation terminée, la version sera mise à jour à la prochaine vérification", + "uninstallCompleted": "Désinstallation de {name} terminée", + "uninstallFailed": "Échec de la désinstallation de {name}", + "localVersionRemoved": "Version locale supprimée", + "saveAgentOrderFailed": "Échec de l’enregistrement de l’ordre des agents", + "saveAgentSwitchFailed": "Échec de l’enregistrement du switch agent", + "saveEnvFailed": "Échec de l’enregistrement des variables d’environnement", + "grokSaved": "Configuration Grok enregistrée", + "saveGrokNativeFailed": "Échec de l'enregistrement de la configuration native Grok", + "saveGrokApiKeyFailed": "Paramètres enregistrés, mais la clé API n'a pas pu être enregistrée", + "cursorSaved": "Configuration Cursor enregistrée", + "saveCursorConfigFailed": "Échec de l'enregistrement de la configuration Cursor", + "codexSaved": "Configuration Codex enregistrée", + "saveCodexNativeFailed": "Échec de l’enregistrement de la configuration native Codex", + "geminiSaved": "Configuration Gemini enregistrée", + "saveGeminiFailed": "Échec de l’enregistrement de la configuration Gemini", + "providerDeleted": "Provider {providerId} supprimé", + "providerDeleteFailed": "Échec de suppression du provider {providerId}", + "providerSaved": "Provider {providerId} enregistré", + "saveProviderFailed": "Échec d’enregistrement du provider {providerId}", + "openCodeConfigSynced": "La configuration OpenCode et auth JSON ont été synchronisés.", + "openCodeSaved": "Configuration OpenCode enregistrée", + "saveOpenCodeFailed": "Échec de l’enregistrement de la configuration OpenCode", + "openClawSaved": "Configuration OpenClaw enregistrée", + "saveOpenClawFailed": "Échec de l’enregistrement de la configuration OpenClaw", + "configSaved": "Configuration enregistrée", + "configSavedHint": "Les sessions existantes doivent être rouvertes pour prendre effet", + "saveConfigManagementFailed": "Échec de l’enregistrement de la gestion de configuration", + "clineSaved": "Configuration Cline enregistrée", + "saveClineFailed": "Échec de l'enregistrement de la configuration Cline", + "hermesSaved": "Configuration Hermes enregistrée", + "saveHermesFailed": "Échec de l'enregistrement de la configuration Hermes", + "codeBuddySaved": "Configuration CodeBuddy enregistrée", + "saveCodeBuddyFailed": "Échec de l'enregistrement de la configuration CodeBuddy", + "kimiCodeSaved": "Configuration de Kimi Code enregistrée", + "saveKimiCodeFailed": "Échec de l'enregistrement de la configuration de Kimi Code", + "deepseekSaved": "Configuration DeepSeek enregistrée", + "saveDeepSeekFailed": "Échec de l'enregistrement de la configuration DeepSeek", + "modelProviderRequired": "Veuillez sélectionner un fournisseur de modèle avant d'enregistrer.", + "affectedRunningSessions": "{count, plural, one {# session active doit se reconnecter pour appliquer la modification} other {# sessions actives doivent se reconnecter pour appliquer la modification}}", + "providerConnected": "{providerId} connecté", + "connectFailed": "Échec de la connexion de {providerId}", + "providerDisconnected": "{providerId} déconnecté", + "disconnectFailed": "Échec de la déconnexion de {providerId}", + "catalogRefreshed": "Catalogue actualisé — {count} fournisseurs", + "catalogRefreshFailed": "Échec de l''actualisation du catalogue", + "piSaved": "Configuration Pi enregistrée", + "savePiFailed": "Échec de l'enregistrement de la config Pi", + "piRuntimeSaved": "Exécution Pi enregistrée", + "savePiRuntimeFailed": "Échec de l'enregistrement de l'exécution Pi", + "piBinaryInstalled": "pi installé", + "piBinaryInstallFailed": "Échec de l'installation de pi", + "piBinaryUninstalled": "pi désinstallé", + "piBinaryUninstallFailed": "Échec de la désinstallation de pi", + "savePiTrustFailed": "Échec de l'enregistrement de la confiance de l'espace de travail" + }, + "version": { + "statusLabel": "Statut de version", + "notInstalled": "Non installé", + "remoteLocal": "Distant : {remoteVersion} · Local : {localVersion}", + "localOnly": "Local : {localVersion}", + "localInstalled": "{versionText}. Installé.", + "platformUnsupported": "{versionText}. La plateforme actuelle ne prend pas en charge cet agent.", + "uvxNotReady": "{versionText}. Le runtime uv n'est pas installé — installez-le depuis la vérification uv ci-dessous pour utiliser cet agent.", + "clickInstall": "{versionText}. Cliquez sur Installer à droite.", + "localUnrecognized": "{versionText}. La version locale n’est pas comparable ; essayez une mise à niveau pour écraser l’installation.", + "upgradeAvailable": "{versionText}. Mise à niveau disponible.", + "remoteUnavailable": "{versionText}. La version distante est actuellement indisponible.", + "latest": "{versionText}. Déjà à jour." + }, + "adapter": { + "label": "Adaptateur ACP", + "badge": "Adaptateur ACP", + "badgeHint": "Pour cet agent, Codeg installe un paquet adaptateur ACP, pas la CLI de l'éditeur. Les deux sont indépendants et partagent la même configuration.", + "learnMore": "En savoir plus", + "missingWithNative": "Votre {nativeLabel} a été trouvée dans {nativePath}. Codeg pilote les agents via ACP, or cette CLI ne parle pas ACP : Codeg a donc besoin d'un paquet adaptateur distinct, {adapterPackage}, maintenu par le projet Agent Client Protocol (à l'origine Zed). Il embarque son propre runtime, ne modifie ni ne remplace jamais votre commande {nativeCmd}, et lit le même {configDir} — votre connexion et vos réglages sont conservés. Installez-le ci-dessous.", + "missing": "Codeg pilote les agents via ACP, or la {nativeLabel} ne parle pas ACP : Codeg a donc besoin d'un paquet adaptateur distinct, {adapterPackage}, maintenu par le projet Agent Client Protocol (à l'origine Zed). Il embarque son propre runtime, la CLI {nativeCmd} n'est donc pas un prérequis ; si vous l'avez déjà, les deux coexistent et partagent la connexion et les réglages de {configDir}. Installez-le ci-dessous.", + "readyWithNative": "L'adaptateur {adapterCmd} est installé : c'est lui que Codeg lance, pas votre {nativeCmd} situé dans {nativePath}. Ce sont des paquets distincts qui coexistent, et tous deux lisent {configDir} : connexion et réglages sont partagés.", + "ready": "L'adaptateur {adapterCmd} est installé : c'est lui que Codeg lance. Il embarque son propre runtime, la {nativeLabel} n'est donc pas nécessaire ; si vous l'installez plus tard, les deux coexistent et partagent {configDir}." + }, + "cline": { + "configDescription": "Configurez le fournisseur API et les identifiants Cline. Les paramètres sont enregistrés dans ~/.cline/data/." + }, + "opencodePlugins": { + "title": "Plugins OpenCode", + "declared": "Plugins déclarés", + "noPlugins": "Aucun plugin déclaré dans opencode.json", + "status": { + "installed": "Installé", + "missing": "Non installé" + }, + "installAll": "Installer tous les manquants", + "pinVersions": "Fixer les versions @latest", + "install": "Installer", + "uninstall": "Désinstaller", + "refresh": "Actualiser", + "success": "Tous les plugins ont été installés avec succès", + "failed": "L'opération du plugin a échoué" + }, + "pi": { + "configManagement": "Configuration de Pi", + "configDescription": "Pi s'authentifie via la clé API de votre fournisseur de modèle. La clé est écrite dans ~/.pi/agent/auth.json et le choix du modèle dans settings.json.", + "providerLabel": "Fournisseur", + "modelLabel": "Modèle", + "thinkingLabel": "Réflexion", + "thinking": { + "off": "Désactivé", + "low": "Faible", + "medium": "Moyen", + "high": "Élevé", + "minimal": "Minimal", + "xhigh": "Très élevé" + }, + "apiKeyLabel": "Clé API", + "apiKeyHint": "Enregistrée dans ~/.pi/agent/auth.json pour le fournisseur sélectionné.", + "apiKeySetPlaceholder": "•••••• (enregistrée — laisser vide pour conserver)", + "saveConfig": "Enregistrer la config Pi", + "providerModelRequired": "Le fournisseur et le modèle sont requis", + "runtimeTitle": "Exécution", + "runtimeDescription": "Choisissez quel binaire pi s'exécute. Utilisez celui par défaut ou pointez vers votre propre build de pi.", + "modeDefault": "pi par défaut", + "modeDefaultHint": "Utilise l'adaptateur pi-acp intégré avec le pi de votre PATH. Installer pi : npm install -g @earendil-works/pi-coding-agent", + "modeCustom": "pi personnalisé", + "modeCustomHint": "Exécutez votre propre build, installation ou wrapper de pi.", + "commandLabel": "Commande ou chemin pi", + "commandHint": "Un chemin absolu, un nom de commande dans le PATH, ou un script wrapper (par ex. ./pi-test.sh d'un monorepo).", + "commandNotFound": "Commande introuvable", + "validate": "Valider", + "advanced": "Avancé", + "configDirLabel": "Répertoire de config (PI_CODING_AGENT_DIR)", + "sessionDirLabel": "Répertoire des sessions (PI_CODING_AGENT_SESSION_DIR)", + "flagsHint": "pi-acp ne transmet pas les options pi personnalisées (--approve, -e, …) — encapsulez pi dans un script et pointez-y la commande.", + "customIncomplete": "Saisissez une commande pi pour enregistrer", + "saveRuntime": "Enregistrer l'exécution", + "providerPlaceholder": "Sélectionner un fournisseur", + "customProvider": "Fournisseur personnalisé…", + "providerIdLabel": "ID du fournisseur", + "apiProtocolLabel": "Protocole API", + "baseUrlLabel": "Point de terminaison API (Base URL)", + "customProviderHint": "Définit un fournisseur dans ~/.pi/agent/models.json vers votre point de terminaison. La plupart des serveurs auto-hébergés ou proxy utilisent openai-completions.", + "baseUrlRequired": "Le point de terminaison API (Base URL) est requis", + "binaryTitle": "binaire pi (pi-coding-agent)", + "binaryDescription": "pi-acp exécute ce binaire pi. Installez-le ici, ou faites pointer pi-acp vers votre propre build ci-dessous.", + "binaryInstalled": "Installé", + "binaryMissing": "Non installé", + "binaryChecking": "Vérification…", + "installBinary": "Installer pi", + "installing": "Installation…", + "recheck": "Revérifier", + "configDirSkillsNote": "Avec un répertoire de configuration personnalisé, les compétences, experts et outils bureautiques gérés dans les Paramètres ne s'appliquent pas à ce pi — gérez ses compétences directement dans ce dossier.", + "projectTrustTitle": "Confiance du projet", + "projectTrustDescription": "Dossiers depuis lesquels vous avez autorisé pi à charger des fichiers de projet. Un dossier de confiance permet aux .pi/extensions de ce dépôt d'exécuter du code au démarrage de pi, s'applique à tous les dossiers qu'il contient et sert aussi lorsque vous lancez pi dans un terminal.", + "projectTrustLoading": "Chargement…", + "projectTrustEmpty": "Aucun dossier n'a encore été décidé.", + "projectTrustTrusted": "Approuvé", + "projectTrustDenied": "Non approuvé", + "projectTrustRevoke": "Révoquer", + "reasoningTitle": "Raisonnement", + "reasoningEnableLabel": "Activer", + "reasoningDescription": "pi n'envoie un effort de raisonnement que pour un modèle qui le déclare — sur un modèle non déclaré, tous les niveaux sont ramenés à Off, si bien que le sélecteur du composeur revient en arrière dès qu'on y touche. Écrit dans l'entrée de ce modèle dans models.json.", + "levelsLabel": "Niveaux disponibles", + "levelsHint": "Ils deviennent les lignes du sélecteur de raisonnement du composeur. Choisissez ceux que votre endpoint accepte ; pi refuse tout niveau absent d'ici.", + "levelsEmptyError": "Choisissez au moins un niveau — sans aucun, pi retombe sur Off.", + "wireValuesTitle": "Avancé : valeurs envoyées au fournisseur", + "wireValuesHint": "Laissez vide pour envoyer le nom du niveau tel quel. Renseignez-le si votre endpoint attend autre chose — les backends façon Google veulent LOW / HIGH.", + "defaultLevelUnlisted": "Ce niveau n'est pas dans la liste ci-dessus — pi le ramènerait plus bas." + }, + "addCustomAgent": "Ajouter un agent personnalisé", + "addCustomAgentHint": "Enregistrez n'importe quel agent compatible ACP. Choisissez-en un dans le registre ACP public ou collez ses informations de registre.", + "customAgentFromRegistry": "Registre ACP", + "customAgentManual": "Manuel", + "customAgentSearchPlaceholder": "Rechercher des agents…", + "customAgentLoadingCatalog": "Chargement du registre ACP…", + "customAgentRetry": "Réessayer", + "customAgentNoResults": "Aucun agent correspondant", + "customAgentAdd": "Ajouter", + "customAgentAlreadyAdded": "Ajouté", + "customAgentUnsupportedPlatform": "Aucune version disponible pour cette plateforme", + "customAgentAdded": "{name} ajouté", + "customAgentIdLabel": "ID du registre", + "customAgentNameLabel": "Nom affiché", + "customAgentVersionLabel": "Version", + "customAgentSpecLabel": "Distribution (JSON)", + "customAgentSpecHint": "Même forme que l’objet distribution du registre ACP : canaux npx, uvx et binary, ou collez une entrée de registre complète. Pour npx/uvx, cmd est l’exécutable installé par le paquet — déduit du nom du paquet s’il est omis, à préciser donc quand ils diffèrent. binary est organisé par clé de plateforme (cette machine : {platform}) ; son cmd est le chemin de lancement dans l’archive et sha256 vérifie éventuellement le téléchargement.", + "customAgentTemplateLabel": "Modèles", + "customAgentKindLabel": "Lancer via", + "customAgentInvalidJson": "JSON invalide", + "customAgentNoDistribution": "Aucune distribution npx, uvx ou binary trouvée", + "customAgentCancel": "Annuler", + "customAgentSave": "Ajouter l'agent", + "customAgentSaveChanges": "Enregistrer les modifications", + "customAgentEdit": "Modifier l’agent", + "customAgentEditHint": "Modifiez le nom, l’icône, la distribution et les déclarations de skills. L’ID de l’agent ne peut pas être modifié.", + "customAgentEditNotFound": "Agent personnalisé {id} introuvable", + "customAgentSaved": "{name} enregistré", + "customAgentVersionProbeLabel": "Commande de version (facultatif)", + "customAgentVersionProbeHint": "Commande qui affiche la version installée localement. Laissée vide, codeg exécute la commande de l’agent avec --version.", + "customAgentRemove": "Supprimer l'agent", + "customAgentRemoveHint": "Supprime la définition de l'agent. Les conversations existantes conservent leur historique ; l'agent ne peut simplement plus être lancé.", + "customAgentIconLabel": "Icône (facultatif)", + "customAgentIconUpload": "Téléverser", + "customAgentIconReplace": "Remplacer", + "customAgentIconClear": "Retirer l'icône", + "customAgentIconHint": "Enregistrée avec l'agent, elle fonctionne donc hors ligne. Sans icône, une initiale colorée est utilisée.", + "customAgentSkillsLabel": "Skills (.agents/skills partagé)", + "customAgentSkillsHint": "Déclare que cet agent lit le magasin partagé .agents/skills (répertoires global et projet) et l'ajoute à toutes les matrices de compétences. Les compétences qui y sont liées sont visibles par tous les agents qui lisent ce magasin partagé.", + "customAgentSkillsDirLabel": "Répertoire de skills dédié", + "customAgentSkillsDirHint": "Chemin absolu du répertoire depuis lequel cet agent charge ses skills — son propre magasin, en plus du magasin partagé ou à sa place. ~ est remplacé par le répertoire personnel ; les skills liées y sont placées en premier.", + "customAgentMcpLabel": "Prise en charge de MCP", + "customAgentMcpHint": "Transmet le compagnon MCP intégré de codeg à cet agent au démarrage de la session — le canal derrière la délégation, le retour en direct et les outils de tâches. Désactivez-le pour un agent qui refuse les serveurs MCP et ne parvient pas à se connecter ; le changement s'applique à la prochaine connexion.", + "customAgentIconNotAnImage": "Choisissez un fichier image.", + "customAgentIconTooLarge": "L'icône doit faire moins de {limit} Ko.", + "customAgentIconReadFailed": "Impossible de lire cette image.", + "customAgentRemoveConfirm": "Supprimer {name} ? Les conversations existantes sont conservées, mais l'agent ne pourra plus être lancé.", + "customAgentRemoveWithData": "Supprimer aussi l'historique de conversation enregistré", + "customAgentRemoved": "{name} supprimé", + "customAgentBadge": "Personnalisé", + "customAgentNotLaunchable": "Cet agent ne peut pas démarrer ici : {reason}" + }, + "SettingsPages": { + "agentsLoading": "Chargement des paramètres des agents...", + "skillPacksLoading": "Chargement des packs de compétences…" + }, + "GeneralSettings": { + "loading": "Chargement...", + "sectionTitle": "Général", + "sectionDescription": "Préférences centralisées pour le terminal par défaut, l'accélération du rendu et la délégation multi-agents.", + "terminalTitle": "Terminal par défaut", + "terminalDescription": "Choisissez le shell utilisé à l'ouverture de nouveaux onglets de terminal depuis la barre de terminal ou l'arborescence des fichiers. Les agents l'utilisent aussi lorsqu'ils demandent à codeg d'exécuter une ligne de commande complète.", + "terminalSystemDefault": "Par défaut système", + "terminalPowerShell7": "PowerShell 7 (pwsh)", + "terminalWindowsPowerShell": "Windows PowerShell", + "terminalCmd": "Invite de commandes (cmd)", + "terminalSaveFailed": "Échec de l’enregistrement des paramètres du terminal : {message}", + "terminalShellCustom": "Chemin personnalisé", + "terminalShellCustomPath": "Chemin du shell", + "terminalShellCustomPlaceholder": "/usr/local/bin/fish", + "terminalShellCustomSave": "Enregistrer", + "terminalShellCustomHint": "Indiquez un chemin absolu ou un nom résolvable via PATH.", + "terminalShellNotInstalled": "non installé", + "terminalShellNotFoundWarning": "Ce chemin n’existe pas sur cet hôte.", + "terminalCurrentShell": "Actuellement utilisé : {path}", + "renderingDescription": "Désactivez l’accélération matérielle si l’application affiche un écran noir ou des défauts de rendu (fréquent sur certaines GPU AMD ou GPU Intel intégrées). N’a d’effet que sur la version Windows de bureau.", + "disableHardwareAcceleration": "Désactiver l’accélération matérielle", + "renderingSaveFailed": "Échec de l’enregistrement des paramètres de rendu : {message}", + "restartRequired": "Enregistré. Redémarrez l’application pour appliquer la modification.", + "restartNow": "Redémarrer maintenant", + "restartFailed": "Échec du redémarrage : {message}", + "loadFailed": "Échec du chargement : {message}" + }, + "LoginPage": { + "documentTitle": "Connexion - codeg", + "brand": "Codeg", + "subtitle": "Saisissez votre jeton d'accès pour vous connecter à l'application de bureau", + "tokenPlaceholder": "Jeton d'accès", + "connect": "Se connecter", + "connecting": "Connexion...", + "helpText": "Vous trouverez votre jeton dans l'application de bureau sous Paramètres → Service Web", + "invalidToken": "Jeton invalide. Veuillez vérifier et réessayer.", + "connectionFailed": "Échec de la connexion (HTTP {status})", + "networkError": "Impossible de se connecter au serveur" + }, + "CommitPage": { + "title": "Valider", + "invalidFolderId": "ID de dossier invalide", + "loadingRepo": "Chargement du dépôt..." + }, + "MergePage": { + "title": "Résoudre les conflits", + "invalidFolderId": "ID de dossier invalide", + "loadingRepo": "Chargement du dépôt...", + "localVersion": "Local (Le nôtre)", + "result": "Résultat", + "remoteVersion": "Distant (Le leur)", + "acceptLocal": "Accepter le local", + "acceptRemote": "Accepter le distant", + "markResolved": "Marquer comme résolu", + "abortMerge": "Abandonner", + "completeMerge": "Terminer la fusion", + "unresolvedConflicts": "Il reste des marqueurs de conflit non résolus dans ce fichier", + "fileResolved": "Fichier résolu avec succès", + "allResolved": "Tous les conflits sont résolus", + "conflictFiles": "Fichiers en conflit", + "loadingFile": "Chargement du fichier...", + "preparingMerge": "Préparation de la fusion...", + "selectFile": "Sélectionner un fichier à résoudre", + "noConflicts": "Aucun fichier en conflit", + "skipFile": "Passer", + "abortSuccess": "Opération abandonnée", + "applyAllNonConflicting": "Appliquer tous les changements non conflictuels", + "applyLeftNonConflicting": "Appliquer local", + "applyRightNonConflicting": "Appliquer distant" + }, + "ImportSessions": { + "title": "Importer les sessions locales", + "scanningTitle": "Analyse des sessions locales des agents…", + "scanningHint": "Parcours du stockage local des sessions de chaque agent. Cela peut prendre un moment avec de gros historiques. Les sessions déjà importées sont actualisées au passage.", + "scanFailed": "Échec de l'analyse", + "retry": "Réessayer", + "rescan": "Réanalyser", + "empty": "Aucune session locale trouvée", + "emptyHint": "Aucun stockage de sessions d'agent n'a été trouvé sur cette machine.", + "noMatches": "Aucune session ne correspond aux filtres actuels", + "searchPlaceholder": "Rechercher un titre ou un chemin…", + "allAgents": "Tous les agents", + "onlyImportable": "Importables uniquement", + "selectAll": "Tout sélectionner", + "clearSelection": "Effacer", + "expandAll": "Tout développer", + "collapseAll": "Tout réduire", + "summaryCounts": "{total} sessions · {importable} importables · {folders} dossiers", + "noFolderSkipped": "{count} sans dossier de projet ignorées", + "folderNew": "Nouveau", + "folderCounts": "{importable}/{total} importables", + "toggleFolderAria": "Sélectionner toutes les sessions importables de {name}", + "toggleSessionAria": "Sélectionner la session {title}", + "statusImported": "Importée", + "statusDeleted": "Supprimée", + "untitled": "Session sans titre", + "messageCount": "{count} messages", + "selectedCount": "{count} sélectionnées", + "importSelected": "Importer la sélection", + "importing": "Importation…", + "close": "Fermer", + "doneTitle": "Importation terminée", + "doneImported": "Importées", + "doneUpdated": "Actualisées", + "doneSkipped": "Ignorées", + "doneCreatedFolders": "Dossiers créés", + "doneNotFound": "Introuvables", + "doneFailed": "Échouées", + "continueImport": "Continuer l'import", + "toasts": { + "importFailed": "Échec de l'import : {message}" + } + }, + "Folder": { + "workspaceStatus": { + "degradedTitle": "Mises à jour en temps réel indisponibles", + "degradedHint": "L’observateur n’a pas pu démarrer (par ex. permission refusée). Actualisez manuellement pour voir les modifications.", + "retry": "Réessayer", + "retrying": "Nouvelle tentative..." + }, + "common": { + "all": "Tout", + "cancel": "Annuler", + "close": "Fermer", + "closeOthers": "Fermer les autres", + "closeAll": "Tout fermer", + "confirm": "Confirmer", + "save": "Enregistrer", + "delete": "Supprimer", + "rename": "Renommer", + "loading": "Chargement...", + "refresh": "Actualiser", + "refreshing": "Actualisation...", + "create": "Créer", + "createAndSwitch": "Créer et basculer", + "openFile": "Ouvrir le fichier", + "viewDiff": "Voir le Diff", + "push": "Pousser..." + }, + "statusLabels": { + "in_progress": "En cours", + "pending_review": "Revue", + "completed": "Terminé", + "cancelled": "Annulé" + }, + "sidebar": { + "title": "Discussions", + "locateActiveConversation": "Localiser la conversation active", + "expandAllGroups": "Développer tous les groupes", + "collapseAllGroups": "Réduire tous les groupes", + "newConversation": "Nouvelle conversation", + "newConversationShort": "Nouvelle", + "newChat": "Nouvelle conversation", + "search": "Rechercher", + "noConversationsFound": "Aucune conversation trouvée.", + "importLocalSessions": "Importer les sessions locales", + "importing": "Import en cours...", + "error": "Erreur : {message}", + "completeAllSessions": "Terminer toutes les sessions", + "completeAllReviewTitle": "Terminer toutes les sessions en revue ?", + "completeAllReviewDescription": "Cela marquera comme terminées toutes les {count, plural, one {# session} other {# sessions}} en Revue.", + "completing": "Finalisation...", + "toasts": { + "importedSessions": "{imported, plural, one {# session} other {# sessions}} importée(s), {skipped} ignorée(s)", + "importedAndUpdated": "{imported, plural, one {# session} other {# sessions}} importée(s), {updated, plural, one {# titre} other {# titres}} mis à jour, {skipped} ignorée(s)", + "updatedTitles": "{updated, plural, one {# titre} other {# titres}} mis à jour, {skipped} ignorée(s)", + "noNewSessionsFound": "Aucune nouvelle session trouvée ({skipped} ignorée(s))", + "importFailed": "Échec de l'import : {message}", + "reviewCompleted": "{count, plural, one {# session en revue} other {# sessions en revue}} marquée(s) comme terminée(s)", + "completeReviewFailed": "Échec de la finalisation des sessions en revue : {message}", + "folderOpened": "Dossier {name} ouvert", + "folderRemoved": "Dossier {name} retiré", + "openFolderFailed": "Échec de l'ouverture du dossier", + "removeFolderFailed": "Échec de la suppression du dossier : {message}", + "reorderFoldersFailed": "Échec du réordonnancement des dossiers : {message}", + "changeFolderColorFailed": "Échec du changement de couleur : {message}", + "setFolderAliasFailed": "Échec de la définition de l'alias : {message}", + "changeFolderDefaultAgentFailed": "Échec de la définition de l'agent par défaut : {message}" + }, + "statsLabel": "{folders} dossiers · {convos} conversations", + "reorderHandle": "Glisser pour réorganiser", + "openFolder": "Ouvrir le dossier", + "searchPlaceholder": "Rechercher des conversations...", + "viewOptions": "Options d'affichage", + "showCompleted": "Afficher les conversations terminées", + "showWorktrees": "Afficher les dossiers de worktree", + "showRecent": "Afficher le groupe Récents", + "moreOptions": "Plus d'options", + "sortBy": "Trier par", + "sortByCreatedAt": "Date de création", + "sortByUpdatedAt": "Date de mise à jour", + "sectionOrder": "Ordre des sections", + "sectionOrderMoveUp": "Monter", + "sectionOrderMoveDown": "Descendre", + "sectionOrderItemLabel": "{name} — position {position} sur {total}", + "statusRunningBadge": "En cours", + "runningCountBadge": "{count, plural, one {# session en cours} other {# sessions en cours}}", + "statusCancelledBadge": "Annulé", + "worktreeRemovedBadge": "Worktree d'origine supprimé", + "conversationCountUnit": "{count, plural, one {# conversation} other {# conversations}}", + "emptyFolderHint": "Aucune conversation", + "noMatchingConversations": "Aucune conversation correspondante", + "noUnfinishedConversations": "Aucune conversation en cours. Activez « Afficher les terminées » dans le menu en haut à droite.", + "removeFolderConfirmTitle": "Retirer le dossier de l'espace de travail ?", + "removeFolderConfirmDescription": "Retirer \"{name}\" de l'espace de travail ? Les onglets et terminaux associés seront fermés.", + "folderHeaderMenu": { + "manageConversations": "Gérer les conversations…", + "manageLinks": "Dossiers liés", + "changeColor": "Changer la couleur", + "useThemeColor": "Utiliser le thème de l'app", + "setDefaultAgent": "Définir l'agent par défaut", + "defaultAgentNone": "Aucun (utiliser la valeur globale)", + "agentUnavailableSuffix": "(indisponible)", + "loadingAgents": "Chargement des agents…", + "setAlias": "Définir un alias…", + "setAliasTitle": "Définir l'alias du dossier", + "setAliasPlaceholder": "Saisir un alias (laisser vide pour effacer)", + "setAliasSave": "Enregistrer", + "setAliasCancel": "Annuler", + "removeFromWorkspace": "Retirer de l'espace de travail" + }, + "manageConversations": { + "title": "Gérer les conversations", + "searchPlaceholder": "Rechercher par titre…", + "agentFilterAll": "Tous les agents", + "statusFilterAll": "Tous les statuts", + "folderFilterAll": "Tous les dossiers", + "branchFilterAll": "Toutes les branches", + "branchNone": "Aucune branche", + "branchSearchPlaceholder": "Rechercher des branches…", + "noMatchingBranches": "Aucune branche correspondante", + "selectAllVisible": "Tout sélectionner", + "deselectAll": "Tout désélectionner", + "selectedCount": "{count} sélectionnée(s)", + "matchedCount": "{count} correspondance(s)", + "untitledConversation": "Conversation sans titre", + "setStatus": "Définir le statut…", + "deleteSelected": "Supprimer", + "noConversations": "Aucune conversation dans ce dossier.", + "noConversationsWorkspace": "Aucune conversation dans l'espace de travail.", + "noMatchingConversations": "Aucune conversation ne correspond aux filtres.", + "confirmDeleteTitle": "Supprimer {count} conversation(s) ?", + "confirmDeleteDescription": "Cette action est irréversible.", + "toastDeleted": "{count} conversation(s) supprimée(s)", + "toastStatusUpdated": "Statut mis à jour pour {count} conversation(s)", + "toastOpFailed": "Échec de l'opération : {message}" + }, + "sectionPinned": "Épinglées", + "sectionFolders": "Dossiers", + "sectionChats": "Discussion", + "sectionRecent": "Récents", + "noChats": "Aucune discussion", + "noRecent": "Aucune conversation récente", + "showMoreRecent": "Afficher plus ({count})", + "noFolders": "Aucun dossier ouvert", + "newChatAction": "Nouvelle discussion", + "automations": "Automatisations", + "tasks": "Tâches à faire", + "loadingSubsessions": "Chargement des sous-conversations…" + }, + "conversation": { + "reloadFailed": "Échec du rechargement de la conversation : {message}", + "reloaded": "Conversation rechargée", + "reload": "Recharger", + "activeConversationIndicator": "Conversation active", + "newConversation": "Nouvelle conversation", + "closeConversation": "Fermer la conversation", + "copyText": "Copier le texte", + "copyTextSuccess": "Copié", + "copyTextFailed": "Échec de la copie", + "forkSession": "Dupliquer la session", + "forkSessionSuccess": "Session dupliquée avec succès", + "forkSessionFailed": "Échec de la duplication de la session : {error}", + "exportConversation": "Exporter la conversation", + "exportImage": "Image", + "exportMarkdown": "Markdown", + "exportHtml": "HTML", + "exportSuccess": "Conversation exportée", + "exportFailed": "Échec de l'exportation", + "exportImageTooLong": "La conversation est trop longue pour être exportée en image", + "exportLabels": { + "untitledConversation": "Conversation sans titre", + "agent": "Agent", + "model": "Modèle", + "status": "Statut", + "started": "Début", + "updated": "Mis à jour", + "tokens": "Statistiques de tokens", + "duration": "Durée", + "inputTokens": "Entrée", + "outputTokens": "Sortie", + "cacheRead": "Cache lu", + "cacheWrite": "Cache écrit", + "user": "Utilisateur", + "assistant": "Assistant", + "system": "Système", + "toolResult": "Résultat", + "toolError": "Erreur" + }, + "moreActions": "Plus d’actions" + }, + "sessionDetails": { + "menuLabel": "Détails de la session", + "noActiveSession": "Aucune session active", + "title": "Détails de la session", + "subtitle": "Métadonnées de la session et utilisation des tokens", + "fieldTitle": "Titre", + "untitled": "Conversation sans titre", + "sessionId": "ID de session", + "externalId": "ID d'extension", + "agent": "Agent", + "model": "Modèle", + "status": "Statut", + "gitBranch": "Branche Git", + "parentId": "Session parente", + "tokensHeading": "Utilisation des tokens", + "totalTokens": "Total", + "inputTokens": "Entrée", + "outputTokens": "Sortie", + "cacheWrite": "Cache écrit", + "cacheRead": "Cache lu", + "contextWindow": "Fenêtre de contexte", + "duration": "Durée", + "loadingStats": "Chargement de l'utilisation des tokens…", + "loadFailed": "Échec du chargement de l'utilisation des tokens", + "noStats": "Aucune utilisation enregistrée", + "timestampsHeading": "Horodatage", + "createdAt": "Créé", + "updatedAt": "Mis à jour", + "none": "—", + "copyField": "Copier {field}", + "copiedField": "{field} copié" + }, + "conversationCard": { + "untitledConversation": "Conversation sans titre", + "newConversation": "Nouvelle conversation", + "rename": "Renommer", + "status": "Statut", + "delete": "Supprimer", + "importLocalSessions": "Importer les sessions locales", + "importing": "Import en cours...", + "renameConversation": "Renommer la conversation", + "deleteConversationTitle": "Supprimer la conversation ?", + "deleteConversationDescription": "Cela supprimera \"{title}\". Cette action est irréversible.", + "cancel": "Annuler", + "save": "Enregistrer", + "pin": "Épingler", + "unpin": "Désépingler", + "markCompleted": "Marquer comme terminé", + "reopen": "Rouvrir", + "expandSubsessions": "Développer les sous-conversations", + "collapseSubsessions": "Réduire les sous-conversations" + }, + "search": { + "dialogTitle": "Rechercher", + "dialogTitleWithFolder": "Rechercher — {name}", + "tabConversations": "Conversations", + "tabFiles": "Fichiers", + "placeholder": "Rechercher des conversations...", + "filePlaceholder": "Rechercher des fichiers ou répertoires...", + "allAgents": "Tout", + "searching": "Recherche...", + "typeToSearch": "Tapez pour rechercher des conversations", + "typeToSearchFiles": "Tapez pour rechercher des fichiers ou répertoires", + "noResults": "Aucun résultat trouvé.", + "untitledConversation": "Conversation sans titre" + }, + "folderTitleBar": { + "showSidebar": "Afficher la barre latérale", + "hideSidebar": "Masquer la barre latérale", + "toggleTerminal": "Basculer le terminal", + "toggleAuxPanel": "Basculer le panneau auxiliaire", + "search": "Rechercher", + "openSettings": "Ouvrir les paramètres", + "backToConversations": "Retour aux conversations", + "withShortcut": "{label} (raccourci : {shortcut})" + }, + "statusBar": { + "connection": { + "connected": "Connecté", + "connecting": "Connexion...", + "prompting": "Réponse...", + "error": "Erreur de connexion", + "disconnected": "Déconnecté", + "tooltip": "{agent} : {status}", + "tooltipError": "{agent} : {error}", + "title": "Connexion de l'agent", + "triggerAria": "Connexion de l'agent : {status}", + "workingDir": "Répertoire de travail", + "sessionId": "ID de session", + "viewerNote": "Rattaché à une session appartenant à un autre client : la reconnexion ne rattache que cette vue.", + "reconnectInterrupts": "La reconnexion redémarre l'agent et interrompt le travail en cours.", + "reconnect": "Reconnecter", + "reconnecting": "Reconnexion...", + "reconnectUnavailable": "Aucune session à laquelle se reconnecter pour l'instant." + }, + "tasks": { + "title": "Tâches" + }, + "alerts": { + "title": "Alertes", + "empty": "Aucune alerte", + "details": "Détails" + }, + "stats": { + "conversations": "{count} discussions", + "openUsage": "Voir les statistiques de sessions et l'usage de tokens" + }, + "tokens": { + "contextWindowUsageAria": "Utilisation de la fenêtre de contexte", + "contextWindow": "Fenêtre de contexte", + "usedMax": "Utilisé / Max", + "tokenUsage": "Utilisation des tokens", + "input": "Entrée", + "output": "Sortie", + "cacheRead": "Lecture cache", + "cacheWrite": "Écriture cache", + "total": "Total des tokens" + } + }, + "auxPanel": { + "tabs": { + "files": "Fichiers", + "changes": "Changements", + "commits": "Validations" + }, + "noFolderTitle": "Aucun dossier ouvert", + "noFolderHint": "Ouvrez un dossier pour voir son contenu ici" + }, + "windowControls": { + "minimizeWindow": "Minimiser la fenêtre", + "minimize": "Minimiser", + "maximizeWindow": "Maximiser la fenêtre", + "maximize": "Maximiser", + "restoreWindow": "Restaurer la fenêtre", + "restore": "Restaurer", + "closeWindow": "Fermer la fenêtre", + "close": "Fermer" + }, + "tabs": { + "closeConversationTab": "Fermer l’onglet de conversation", + "close": "Fermer", + "closeOthers": "Fermer les autres", + "splitRight": "Diviser à droite", + "splitDown": "Diviser en bas", + "splitAndMoveRight": "Diviser et déplacer à droite", + "splitAndMoveDown": "Diviser et déplacer en bas", + "moveToOppositeGroup": "Déplacer vers le groupe opposé", + "moveToGroup": "Déplacer vers le groupe", + "groupLabel": "Groupe {index}", + "changeSplitterOrientation": "Changer l'orientation du séparateur", + "unsplit": "Annuler la division", + "unsplitAll": "Annuler toutes les divisions", + "closeAll": "Tout fermer", + "tileDisplay": "Affichage en mosaïque", + "untileDisplay": "Quitter la mosaïque" + }, + "fileWorkspace": { + "files": "Fichiers", + "closeFileTab": "Fermer l’onglet fichier", + "close": "Fermer", + "closeOthers": "Fermer les autres", + "closeAll": "Tout fermer", + "preview": "Aperçu", + "editSource": "Modifier la source", + "maximize": "Agrandir", + "restore": "Restaurer", + "emptyDirectory": "Dossier vide" + }, + "terminal": { + "rename": "Renommer", + "close": "Fermer", + "closeOthers": "Fermer les autres", + "closeAll": "Tout fermer", + "hideTerminal": "Masquer le terminal ({shortcut})", + "openFolderFirst": "Ouvrez d'abord un dossier" + }, + "workspaceDialog": { + "title": "Ouvrir un dossier", + "manageTitle": "Dossiers liés", + "addTargetsTitle": "Ajouter des dossiers à lier", + "pickRootDescription": "Choisissez le dossier principal de cet espace de travail.", + "linksDescription": "Liez d'autres dossiers en sous-répertoires pour que les agents travaillent sur tous depuis un seul espace de travail.", + "addTargetsDescription": "Sélectionnez un ou plusieurs dossiers. Chacun devient un sous-répertoire de l'espace de travail.", + "useSystemPicker": "Sélecteur système", + "next": "Suivant", + "back": "Retour", + "done": "Terminé", + "change": "Modifier", + "addFolders": "Ajouter des dossiers", + "addSelected": "Ajouter", + "addSelectedCount": "Ajouter {count}", + "createCount": "Lier {count} dossier(s)", + "discardPending": "Abandonner", + "noLinks": "Aucun dossier lié pour l'instant.", + "gitExclude": "Garder les liens hors du statut git", + "rename": "Renommer", + "unlink": "Supprimer le lien", + "repair": "Recréer le lien", + "saveName": "Enregistrer", + "cancelRename": "Annuler", + "removePending": "Retirer", + "willAppearAs": "Apparaît sous le nom {name} dans l'espace de travail", + "renamedForDuplicate": "Renommé — {base} est déjà utilisé par un autre lien", + "renamedForExistingEntry": "Renommé — {base} existe déjà dans ce dossier", + "partiallyCreated": "Seuls {count} dossier(s) ont pu être liés", + "openFailed": "Impossible d'ouvrir le dossier", + "previewFailed": "Impossible de vérifier les dossiers sélectionnés", + "createFailed": "Impossible de lier les dossiers", + "renameFailed": "Impossible de renommer le lien", + "removeFailed": "Impossible de supprimer le lien", + "repairFailed": "Impossible de recréer le lien", + "status": { + "ok": "Lié", + "missing": "Le lien a disparu de ce dossier", + "conflicted": "Une autre entrée utilise désormais ce nom", + "broken": "Le dossier lié n'existe plus" + }, + "nameIssue": { + "empty": "Saisissez un nom", + "illegalChars": "Ne peut pas contenir / \\ : * ? \" < > |", + "tooLong": "Nom trop long", + "reserved": "Ce nom est réservé par Windows", + "duplicate": "Ce nom est déjà utilisé" + }, + "rejection": { + "not_found": "Dossier introuvable", + "not_a_directory": "Ce chemin n'est pas un dossier", + "same_as_root": "C'est le dossier de l'espace de travail lui-même", + "ancestor_of_root": "Ce dossier contient l'espace de travail", + "inside_root": "Déjà dans l'espace de travail", + "already_linked": "Déjà lié", + "name_unavailable": "Plus aucun nom disponible pour ce dossier", + "alreadyLinkedAs": "Déjà lié sous le nom {name}" + } + }, + "folderNameDropdown": { + "fallbackFolderName": "Dossier", + "openFolder": "Ouvrir le dossier", + "cloneRepository": "Cloner le dépôt", + "projectBoot": "Lanceur de projet", + "opened": "Ouvert", + "recentOpen": "Ouvert récemment" + }, + "fileWorkspacePanel": { + "addSelectionToChat": "Ajouter la sélection au chat", + "addToChat": "Ajouter au chat", + "addSelectionToChatDone": "{label} ajouté à la conversation", + "addFileToChat": "Ajouter le fichier au chat", + "toggleWordWrap": "Basculer le retour à la ligne", + "addFileToChatDone": "{label} ajouté à la conversation", + "viewDiff": "Voir le Diff", + "openFile": "Ouvrir le fichier", + "fileCount": "{count, plural, one {# fichier} other {# fichiers}}", + "openFileOrDiff": "Ouvrez un fichier ou un diff depuis le panneau de droite", + "disk": "Disque", + "head": "HEAD", + "unsaved": "Non enregistré", + "workingTree": "Arbre de travail", + "loading": "Chargement...", + "compareWithBranch": "{path} · comparer avec {branch}", + "hunkCount": "{count, plural, one {# bloc} other {# blocs}}", + "prev": "Précédent", + "next": "Suivant", + "jumpToLine": "Aller à la ligne {line}", + "noParsedDiffSections": "Aucune section de diff analysée", + "loadingEditor": "Chargement de l’éditeur...", + "imageZoomIn": "Agrandir", + "imageZoomOut": "Réduire", + "imageZoomReset": "Réinitialiser le zoom", + "htmlPreviewTitle": "Aperçu HTML", + "htmlPreviewTrust": "Activer les scripts", + "htmlPreviewTrustHint": "Exécuter les scripts de ce fichier et autoriser l'accès réseau. À activer uniquement pour les fichiers de confiance.", + "officePreviewTitle": "Aperçu du document Office", + "officeFullRender": "Rendu complet", + "officeFullRenderHint": "Affiche les animations Morph, la 3D et les formules (exécute les scripts de la diapositive)", + "officeNotInstalled": "OfficeCLI n'est pas installé", + "officeNotInstalledHint": "Installe OfficeCLI dans Paramètres → Outils Office pour prévisualiser les fichiers Word, Excel et PowerPoint.", + "officeOpenSettings": "Ouvrir les paramètres", + "officeWatchFailed": "Impossible de démarrer l'aperçu en direct", + "officeWatchRetry": "Réessayer", + "officeServerInstallHint": "OfficeCLI doit être installé sur l'hôte du serveur. Exécutez cette commande là-bas, puis réessayez :", + "officeRemoteDesktopUnsupported": "L'aperçu en direct n'est pas disponible dans une fenêtre de bureau à distance. Ouvrez cet espace de travail dans l'interface web du serveur pour prévisualiser les fichiers Office." + }, + "branchDropdown": { + "toasts": { + "commitCodeCompleted": "Commit de code terminé", + "pushCodeCompleted": "Push de code terminé", + "committedFiles": "{count, plural, one {# fichier commit} other {# fichiers commit}}", + "taskCompleted": "{label} terminé", + "taskFailed": "{label} échoué", + "mergeNoNewCommits": "{branchName} n’a pas de nouveaux commits", + "mergedCommits": "{count, plural, one {# commit fusionné} other {# commits fusionnés}}", + "allFilesUpToDate": "Tous les fichiers sont à jour", + "updatedFiles": "{count, plural, one {# fichier mis à jour} other {# fichiers mis à jour}}", + "openCommitWindowFailed": "Impossible d’ouvrir la fenêtre de commit", + "openPushWindowFailed": "Impossible d’ouvrir la fenêtre de push", + "upstreamSet": "La branche upstream a été définie", + "upstreamSetAndPushed": "Branche upstream définie et {count, plural, one {# commit} other {# commits}} poussé(s)", + "noCommitsToPush": "Aucun commit à pousser", + "pushedCommits": "{count, plural, one {# commit poussé} other {# commits poussés}}", + "switchedToFolder": "Basculé vers {name}", + "switchFailed": "Échec du changement de branche", + "openStashWindowFailed": "Échec de l'ouverture de la fenêtre de remisage" + }, + "tasks": { + "newBranch": "Créer la branche {name}", + "newWorktree": "Créer le worktree {name}", + "checkoutTo": "Basculer vers {branchName}", + "mergeBranch": "Fusionner {branchName}", + "rebaseTo": "Rebase vers {branchName}", + "deleteRemoteBranch": "Supprimer la branche distante {branchName}", + "initGitRepo": "Initialiser le dépôt Git", + "pullCode": "Pull du code", + "fetchInfo": "Récupérer les infos", + "pushCode": "Push du code", + "stashChanges": "Stash des changements", + "stashPop": "Appliquer le stash", + "deleteBranch": "Supprimer la branche {branchName}", + "removeWorktree": "Supprimer le worktree de {branchName}", + "removeWorktreeAndBranch": "Supprimer le worktree et la branche {branchName}", + "updateBranch": "Mettre à jour la branche {branchName}" + }, + "confirm": { + "mergeTitle": "Fusionner la branche", + "rebaseTitle": "Rebase de la branche", + "mergeDescription": "Fusionner {branchName} dans la branche actuelle {currentBranch} ?", + "rebaseDescription": "Rebaser la branche actuelle {currentBranch} sur {branchName} ?", + "deleteRemoteTitle": "Supprimer la branche distante", + "deleteRemoteDescription": "Supprimer la branche distante {branchName} ? Cette action la supprimera du dépôt distant et ne pourra pas être annulée.", + "deleteTitle": "Supprimer la branche", + "deleteDescription": "Supprimer la branche {branchName} ? Cette action est irréversible.", + "forceDeleteTitle": "Forcer la suppression de la branche", + "forceDeleteDescription": "La branche {branchName} n'est pas entièrement fusionnée. Êtes-vous sûr de vouloir la supprimer de force ? Cette action est irréversible.", + "deleteWorktreeTitle": "Supprimer le worktree", + "deleteWorktreeDescription": "Supprimer le répertoire du worktree où {branchName} est extraite ? La branche et ses commits sont conservés.", + "forceDeleteWorktreeTitle": "Forcer la suppression du worktree", + "forceDeleteWorktreeDescription": "Le worktree de {branchName} contient des fichiers non validés ou non suivis. Le supprimer quand même ? Ces modifications seront irrécupérables.", + "deleteWorktreeAndBranchTitle": "Supprimer le worktree et la branche", + "deleteWorktreeAndBranchDescription": "Supprimer le worktree de {branchName}, la branche elle-même et son dossier d'espace de travail ? Ses sessions sont déplacées vers le dossier du dépôt. Cette action est irréversible.", + "forceDeleteWorktreeAndBranchTitle": "Forcer la suppression du worktree et de la branche", + "forceDeleteWorktreeAndBranchDescription": "Le worktree de {branchName} contient des fichiers non validés, ou la branche n'est pas entièrement fusionnée. Tout supprimer quand même ? Cette action est irréversible." + }, + "current": "Actuelle", + "switchToBranch": "Basculer vers cette branche", + "mergeBranchIntoCurrent": "Fusionner {branchName} dans {currentBranch}", + "rebaseCurrentToBranch": "Rebaser {currentBranch} sur {branchName}", + "noBranch": "Aucune branche", + "detachedHead": "HEAD détaché sur {sha}", + "initGitRepo": "Initialiser le dépôt Git", + "pullCode": "Pull du code", + "fetchRemoteBranches": "Récupérer les branches distantes", + "openCommitWindow": "Commit du code...", + "pushCode": "Pousser...", + "pushBranch": "Pousser", + "newBranch": "Nouvelle branche...", + "newWorktree": "Nouveau worktree...", + "stashChanges": "Remiser les changements...", + "stashPop": "Appliquer le stash...", + "manageRemotes": "Gérer les dépôts distants...", + "localBranches": "Branches locales ({count, plural, one {#} other {#}})", + "noLocalBranches": "Aucune branche locale", + "remoteBranches": "Branches distantes ({count, plural, one {#} other {#}})", + "noRemoteBranches": "Aucune branche distante", + "dialogs": { + "newBranchTitle": "Nouvelle branche", + "newBranchDescription": "Créer une nouvelle branche depuis la branche actuelle {branch}", + "branchNamePlaceholder": "Nom de la branche", + "newWorktreeTitle": "Nouveau worktree", + "newWorktreeDescription": "Créer un nouveau worktree depuis la branche actuelle {branch}", + "branchNameLabel": "Nom de la branche", + "worktreePathLabel": "Chemin du worktree", + "worktreePathPlaceholder": "Chemin du worktree", + "manageRemotesTitle": "Gérer les dépôts distants", + "manageRemotesEmpty": "Aucun dépôt distant configuré", + "remoteNamePlaceholder": "Nom du dépôt distant", + "remoteUrlPlaceholder": "URL du dépôt distant", + "addRemote": "Ajouter", + "savingRemotes": "Enregistrement..." + }, + "conflict": { + "title": "Conflits de fusion", + "description": "Les fichiers suivants ont des conflits qui doivent être résolus :", + "abort": "Abandonner la fusion", + "openMergeTool": "Ouvrir l'outil de fusion", + "completeMerge": "Terminer la fusion", + "abortSuccess": "Fusion abandonnée avec succès", + "completeSuccess": "Fusion terminée avec succès" + }, + "stashDialog": { + "title": "Remiser les changements", + "description": "Sauvegarder les changements actuels dans la remise", + "messageLabel": "Message", + "messagePlaceholder": "Message de remise (optionnel)", + "keepIndex": "Conserver l'index (les changements indexés restent indexés)", + "cancel": "Annuler", + "stash": "Remiser", + "success": "Changements remisés", + "error": "Échec de la remise" + }, + "unstashDialog": { + "title": "Appliquer la remise", + "noStashes": "Aucune remise trouvée", + "selectFile": "Sélectionner un fichier pour voir le diff", + "viewDiff": "Voir le diff", + "original": "Original", + "modified": "Modifié", + "apply": "Appliquer", + "drop": "Supprimer", + "applySuccess": "Remise appliquée", + "dropSuccess": "Remise supprimée", + "confirmApply": "Appliquer la remise {ref} au répertoire de travail ?", + "cancel": "Annuler" + }, + "deleteBranch": "Supprimer la branche", + "deleteWorktree": "Supprimer le worktree", + "deleteWorktreeAndBranch": "Supprimer le worktree et la branche", + "searchPlaceholder": "Rechercher des branches et actions", + "searchAriaLabel": "Rechercher des branches et actions", + "branchListLabel": "Branches et actions", + "noMatches": "Aucune correspondance" + }, + "commitDialog": { + "toasts": { + "commitCompleted": "Commit de code terminé", + "pushFailed": "Échec du push", + "committedFiles": "{count, plural, one {# fichier commit} other {# fichiers commit}}", + "addedToVcs": "Ajouté à VCS", + "addToVcsFailed": "Échec de l’ajout à VCS", + "fileDeleted": "Fichier supprimé", + "deleteFailed": "Échec de la suppression", + "fileRolledBack": "Fichier restauré", + "rollbackFailed": "Échec du rollback", + "dirRolledBack": "Répertoire restauré", + "dirDeleted": "Répertoire supprimé" + }, + "confirm": { + "deleteTitle": "Confirmer la suppression", + "deleteDescription": "Supprimer le fichier \"{file}\" ? Cette action est irréversible.", + "rollbackTitle": "Confirmer le rollback", + "rollbackDescription": "Restaurer le fichier \"{file}\" vers HEAD ? Les modifications non enregistrées seront perdues.", + "rollbackDirDescription": "Restaurer le répertoire \"{dir}\" vers HEAD ? Les modifications non enregistrées seront perdues.", + "deleteDirDescription": "Supprimer le répertoire \"{dir}\" ? Cette action est irréversible." + }, + "actions": { + "select": "Sélectionner", + "unselect": "Désélectionner", + "rollback": "Annuler", + "addToVcs": "Ajouter à VCS" + }, + "aria": { + "selectFile": "{action} : {path}", + "unselectAllFiles": "Désélectionner tous les fichiers", + "selectAllFiles": "Sélectionner tous les fichiers", + "unselectTracked": "Désélectionner les changements suivis", + "selectTracked": "Sélectionner les changements suivis", + "unselectUntracked": "Désélectionner les fichiers non suivis", + "selectUntracked": "Sélectionner les fichiers non suivis" + }, + "loading": "Chargement...", + "selectionCount": "{selected} / {total} fichiers", + "emptyFiles": "Aucun fichier modifié", + "trackedChanges": "Changements suivis ({count})", + "untrackedFiles": "Fichiers non suivis ({count})", + "commitMessage": "Message de commit", + "commitMessagePlaceholder": "Saisissez le message de commit...", + "commitButton": "Valider ({count})", + "commitAndPushButton": "Valider et pousser ({count})", + "head": "HEAD", + "workingTree": "Arbre de travail", + "clickFileToDiff": "Cliquez sur un nom de fichier pour voir le diff", + "loadingDiff": "Chargement du diff..." + }, + "pushWindow": { + "title": "Pousser le code", + "noUnpushedCommits": "Aucun commit non poussé", + "noRemoteConfigured": "Aucun dépôt distant Git configuré\nAjoutez-en un dans « Gérer les dépôts distants »", + "newBranchNoPushedCommits": "Nouvelle branche — pousser pour créer la branche de suivi distante", + "unpushed": "Non poussé", + "selectFileToViewDiff": "Sélectionnez un fichier pour voir les différences", + "before": "Avant", + "after": "Après", + "push": "Pousser", + "toasts": { + "pushSuccess": "Push réussi", + "pushFailed": "Échec du push", + "upstreamSet": "La branche distante a été configurée", + "upstreamSetAndPushed": "Branche distante configurée et {count} commits poussés", + "noCommitsToPush": "Aucun commit à pousser", + "pushedCommits": "{count} commits poussés" + } + }, + "gitLogTab": { + "filesTitle": "Fichiers", + "expandAllFiles": "Développer tous les fichiers", + "collapseAllFiles": "Réduire tous les fichiers", + "workspace": "espace de travail", + "retry": "Réessayer", + "noCommitsFound": "Aucun commit trouvé", + "notAGitRepoTitle": "Pas un dépôt Git", + "notAGitRepoHint": "Initialisez Git depuis le menu des branches ci-dessus, ou ouvrez un dépôt existant.", + "hash": "Empreinte", + "copyHash": "Copier le hash", + "copyMessage": "Copier le message", + "showMore": "Afficher plus", + "showLess": "Afficher moins", + "author": "Auteur", + "noFileChangeDetails": "Aucun détail de changement de fichier disponible.", + "loadingFiles": "Chargement des fichiers...", + "branchesTitle": "Branches Git", + "loadingBranches": "Chargement des branches...", + "noContainingBranches": "Aucune branche contenant ce commit.", + "newBranch": "Nouvelle branche...", + "resetToHere": "Réinitialiser ici", + "resetDisabledReasonNotCurrentBranchView": "Disponible uniquement en affichant la branche actuelle", + "copyFullCommitHashAria": "Copier le hash complet du commit {hash}", + "pushStatus": { + "pushed": "Poussé vers le remote", + "notPushed": "Non poussé vers le remote", + "unknown": "Statut de push inconnu (aucun upstream configuré)" + }, + "time": { + "monthsAgo": "{count, plural, one {il y a # mois} other {il y a # mois}}", + "daysAgo": "{count, plural, one {il y a # jour} other {il y a # jours}}", + "hoursAgo": "{count, plural, one {il y a # heure} other {il y a # heures}}", + "minsAgo": "{count, plural, one {il y a # min} other {il y a # mins}}", + "justNow": "à l’instant" + }, + "toasts": { + "createdAndSwitchedNewBranch": "Nouvelle branche créée et activée", + "newBranchFromCommit": "{name} (depuis {shortHash})", + "createBranchFailed": "Échec de la création de la branche", + "openPushWindowFailed": "Échec de l'ouverture de la fenêtre de push", + "resetSuccess": "Réinitialisation réussie", + "resetSuccessDescription": "{branch} a été réinitialisée sur {shortHash} avec {mode}", + "resetFailed": "Échec de la réinitialisation" + }, + "authorFilter": { + "label": "Auteur", + "searchPlaceholder": "Rechercher un auteur", + "noAuthors": "Aucun auteur trouvé", + "you": "vous", + "filterByAuthorAria": "Filtrer les commits par auteur", + "filterByQuery": "Filtrer par « {query} »", + "clearAuthorFilterAria": "Effacer le filtre par auteur", + "recent": "Récents", + "matchingAuthors": "Auteurs correspondants", + "removeFromRecent": "Retirer {name} des récents" + }, + "branchSelector": { + "label": "Branche", + "head": "HEAD", + "headHint": "Suit la branche actuelle", + "headHintWithBranch": "Suit la branche actuelle ({branch})", + "searchBranch": "Rechercher une branche...", + "noBranches": "Aucune branche", + "selectBranchPlaceholder": "Sélectionner une branche...", + "localBranches": "Branches locales", + "current": "Actuelle", + "remoteBranches": "Branches distantes", + "refreshCommitHistory": "Actualiser l’historique des commits", + "clearBranchFilterAria": "Effacer le filtre par branche" + }, + "dialogs": { + "newBranchTitle": "Nouvelle branche", + "newBranchDescription": "Créer une nouvelle branche avec le commit {shortHash} comme dernier commit.", + "branchNamePlaceholder": "Nom de la branche", + "reset": { + "title": "Réinitialiser la branche actuelle jusqu’ici", + "branchLabel": "Branche", + "targetLabel": "Commit cible", + "messageLabel": "Message", + "modeLabel": "Mode de réinitialisation", + "confirmButton": "Réinitialiser", + "modes": { + "soft": { + "label": "--soft", + "description": "Déplace HEAD et le pointeur de la branche actuelle vers le commit cible.\nConserve Index et Working Tree inchangés.\nLes changements des commits retirés restent staged." + }, + "mixed": { + "label": "--mixed (par défaut)", + "description": "Déplace HEAD vers le commit cible.\nRéinitialise Index au commit cible tout en conservant les changements du Working Tree.\nLes changements passent de staged à unstaged." + }, + "hard": { + "label": "--hard", + "description": "Déplace HEAD et réinitialise à la fois Index et Working Tree au commit cible.\nLes changements locaux suivis après le commit cible sont supprimés.\nC’est une opération destructive." + }, + "keep": { + "label": "--keep", + "description": "Déplace HEAD vers le commit cible en conservant les changements locaux quand c’est possible.\nSeuls les changements sans conflit sont conservés.\nEn cas de conflit, la réinitialisation est annulée pour protéger votre travail." + } + } + } + }, + "moreActions": "Autres actions Git" + }, + "gitChangesTab": { + "workspace": "espace de travail", + "noChanges": "Aucun changement local", + "notAGitRepoTitle": "Pas un dépôt Git", + "notAGitRepoHint": "Initialisez Git depuis le menu des branches ci-dessus, ou ouvrez un dépôt existant.", + "trackedChanges": "Changements suivis ({count})", + "untrackedFiles": "Fichiers non suivis ({count})", + "expandTracked": "Développer les changements suivis", + "collapseTracked": "Réduire les changements suivis", + "expandUntracked": "Développer les fichiers non suivis", + "collapseUntracked": "Réduire les fichiers non suivis", + "showRemainingItems": "Afficher {count} éléments de plus", + "actions": { + "commitCode": "Commit du code", + "rollback": "Annuler", + "addToVcs": "Ajouter à VCS", + "delete": "Supprimer", + "moreActions": "Autres actions Git", + "addAllToVcs": "Tout ajouter au VCS", + "rollbackAll": "Tout annuler", + "refresh": "Actualiser" + }, + "toasts": { + "noAddableFilesInDir": "Aucun fichier modifié de ce répertoire ne peut être ajouté à VCS", + "noRollbackFilesInDir": "Aucun fichier modifié de ce répertoire ne peut être rollback", + "addedToVcs": "{name} ajouté à VCS", + "addToVcsFailed": "Échec de l’ajout à VCS", + "openCommitWindowFailed": "Impossible d’ouvrir la fenêtre de commit", + "rolledBack": "{name} restauré", + "rollbackFailed": "Échec du rollback", + "addedFilesToVcs": "{count, plural, one {# fichier} other {# fichiers}} ajouté(s) à VCS", + "rolledBackFiles": "{count, plural, one {# fichier restauré} other {# fichiers restaurés}}", + "deleted": "{name} supprimé", + "deleteFailed": "Échec de la suppression", + "deletedFiles": "{count} fichiers supprimés", + "noDeletableFilesInDir": "Aucun fichier modifié dans ce répertoire ne peut être supprimé", + "commitFailed": "Échec du commit" + }, + "directoryDialog": { + "descriptionAdd": "Sélectionnez les fichiers du répertoire {path} à ajouter à VCS.", + "descriptionRollback": "Sélectionnez les fichiers du répertoire {path} à rollback.", + "descriptionDelete": "Sélectionnez les fichiers du répertoire {path} à supprimer. Cette action est irréversible.", + "descriptionFallback": "Sélectionnez les fichiers pour continuer.", + "selectionCount": "{selected} / {total} fichiers sélectionnés", + "selectAll": "Tout sélectionner", + "unselectAll": "Tout désélectionner", + "loadingCandidates": "Chargement des changements du répertoire...", + "noOperableFiles": "Aucun fichier opérable" + }, + "rollbackConfirm": { + "title": "Confirmer le rollback", + "descriptionWithTarget": "Rollback des changements locaux pour {kind} \"{name}\" ?", + "descriptionFallback": "Rollback des changements locaux ?", + "kindDirectory": "répertoire", + "kindFile": "fichier" + }, + "deleteConfirm": { + "title": "Confirmer la suppression", + "descriptionWithTarget": "Supprimer {kind} \"{name}\" ? Cette action est irréversible.", + "descriptionFallback": "Cette action est irréversible.", + "kindDirectory": "répertoire", + "kindFile": "fichier" + }, + "quickCommit": { + "placeholder": "Message du commit (Entrée pour valider)" + } + }, + "tabContext": { + "loadingConversation": "Chargement...", + "untitledConversation": "Conversation sans titre", + "newConversation": "Nouvelle conversation" + }, + "fileTreeTab": { + "workspace": "Espace de travail", + "retry": "Réessayer", + "git": "Git", + "openInFileManager": "Ouvrir dans le gestionnaire de fichiers", + "openInFinder": "Ouvrir dans Finder", + "openInExplorer": "Ouvrir dans Explorer", + "attachToCurrentSession": "Ajouter à la session", + "compareWithBranch": "Comparer avec la branche...", + "reloadFromDisk": "Recharger depuis le disque", + "new": "Nouveau", + "newFile": "Fichier", + "newDirectory": "Répertoire", + "openIn": "Ouvrir dans", + "openInTerminal": "Ouvrir dans le terminal", + "linkedFolder": "Dossier lié", + "copyPath": "Copier le chemin", + "upload": "Téléverser fichiers/dossier", + "download": "Télécharger le fichier", + "downloadAsZip": "Télécharger en ZIP", + "actions": { + "select": "Sélectionner", + "unselect": "Désélectionner", + "commitCode": "Committer le code", + "rollback": "Annuler", + "addToVcs": "Ajouter au VCS" + }, + "aria": { + "selectPath": "{action} : {path}" + }, + "toasts": { + "openDirectoryFailed": "Échec de l'ouverture du dossier", + "openBuiltinTerminalFailed": "Impossible d'ouvrir le terminal intégré", + "openCommitWindowFailed": "Échec de l'ouverture de la fenêtre de commit", + "noAddableFilesInDir": "Aucun fichier modifié de ce dossier ne peut être ajouté au VCS", + "noRollbackFilesInDir": "Aucun fichier modifié de ce dossier ne peut être annulé", + "addedToVcs": "{name} ajouté au VCS", + "addToVcsFailed": "Échec de l'ajout au VCS", + "loadBranchesFailed": "Échec du chargement des branches", + "renameFailed": "Échec du renommage", + "moveFailed": "Échec du déplacement", + "deleteFailed": "Échec de la suppression", + "rolledBack": "{name} annulé", + "rollbackFailed": "Échec de l'annulation", + "addedFilesToVcs": "{count, plural, one {# fichier ajouté au VCS} other {# fichiers ajoutés au VCS}}", + "rolledBackFiles": "{count, plural, one {# fichier annulé} other {# fichiers annulés}}", + "savedAsCopy": "Enregistré en copie", + "saveCopyFailed": "Échec de l'enregistrement en copie", + "watchStartFailed": "Échec du démarrage de la surveillance de fichiers", + "createFailed": "Échec de la création", + "downloadFailed": "Échec du téléchargement de {name}", + "downloadSaved": "{name} téléchargé", + "pathCopied": "Chemin copié", + "copyPathFailed": "Échec de la copie du chemin" + }, + "createDialog": { + "newFile": "Nouveau fichier", + "newDirectory": "Nouveau répertoire", + "description": "Entrez un nom pour le nouveau {kind}.", + "placeholderFile": "nom-du-fichier.ext", + "placeholderDirectory": "nom-du-dossier" + }, + "renameDialog": { + "renameDirectory": "Renommer le dossier", + "renameFile": "Renommer le fichier", + "description": "Saisissez un nouveau nom (nom uniquement, sans chemin).", + "placeholderDirectory": "nouveau-nom-dossier", + "placeholderFile": "nouveau-nom-fichier.ext" + }, + "uploadDialog": { + "title": "Téléverser vers l'espace de travail", + "description": "Ajustez la destination si besoin, puis ajoutez des fichiers ou dossiers.", + "workspaceRoot": "racine de l'espace de travail", + "targetPathLabel": "Téléverser vers", + "targetPathHint": "Chemin résolu : {path}", + "dropHint": "Déposez des fichiers ou dossiers ici, ou utilisez les boutons ci-dessous", + "dropHintActive": "Relâchez pour ajouter à la file d'attente", + "selectFiles": "Sélectionner des fichiers", + "selectFolder": "Sélectionner un dossier", + "startUpload": "Lancer le téléversement", + "clearQueue": "Effacer terminés", + "removeItem": "Retirer de la file", + "retry": "Réessayer", + "dropZoneAria": "Déposez ici ou activez pour parcourir", + "folderEmpty": "Aucun fichier trouvé dans le dossier déposé", + "summary": "Total : {total} · Réussis : {succeeded} · Échoués : {failed}", + "status": { + "pending": "En attente", + "uploading": "Téléversement", + "success": "Terminé", + "error": "Échec", + "cancelled": "Annulé" + } + }, + "directoryDialog": { + "descriptionAdd": "Sélectionnez des fichiers sous le dossier {path} à ajouter au VCS.", + "descriptionRollback": "Sélectionnez des fichiers sous le dossier {path} à annuler.", + "descriptionFallback": "Sélectionnez des fichiers pour continuer.", + "selectionCount": "{selected} / {total} fichiers sélectionnés", + "selectAll": "Tout sélectionner", + "unselectAll": "Tout désélectionner", + "loadingCandidates": "Chargement des changements du dossier...", + "noOperableFiles": "Aucun fichier exploitable" + }, + "compareDialog": { + "title": "Comparer avec la branche", + "descriptionWithTarget": "Sélectionnez une branche et comparez avec {kind} {path}", + "descriptionFallback": "Sélectionnez une branche à comparer.", + "kindDirectory": "dossier", + "kindFile": "fichier", + "filterPlaceholder": "Filtrer les branches, ex. main / origin/main", + "singleClickHint": "Cliquez sur une branche pour comparer directement", + "loadingBranches": "Chargement des branches...", + "recentBranches": "Branches récentes ({count})", + "noCurrentBranch": "Aucune branche courante", + "localBranches": "Branches locales ({count})", + "remoteBranches": "Branches distantes ({count})", + "noMatchingBranches": "Aucune branche correspondante" + }, + "externalConflictDialog": { + "title": "Modifications externes de fichiers détectées", + "descriptionWithPath": "Le fichier {path} a changé sur le disque et les modifications actuelles ne sont pas enregistrées.", + "descriptionFallback": "Le fichier actuel a changé sur le disque et les modifications actuelles ne sont pas enregistrées.", + "compare": "Comparer", + "savingCopy": "Enregistrement de la copie...", + "saveAsCopy": "Enregistrer en copie", + "reload": "Recharger" + }, + "deleteConfirm": { + "title": "Confirmer la suppression", + "descriptionWithTarget": "Supprimer {kind} \"{name}\" ? Cette action est irréversible.", + "descriptionFallback": "Cette action est irréversible.", + "kindDirectory": "dossier", + "kindFile": "fichier" + }, + "rollbackConfirm": { + "title": "Confirmer l'annulation", + "descriptionWithTarget": "Annuler les modifications locales du fichier \"{name}\" ?", + "descriptionFallback": "Annuler les modifications locales de ce fichier ?" + }, + "terminalTitle": "Console · {name}" + }, + "commandDropdown": { + "loading": "Chargement...", + "addCommand": "Ajouter une commande", + "manageCommands": "Gérer les commandes...", + "runCommandTitle": "Exécuter : {command}", + "stopCommandTitle": "Arrêter : {command}", + "manageDialog": { + "title": "Gérer les commandes", + "empty": "Aucune commande pour le moment", + "noResults": "Aucune commande correspondante", + "searchPlaceholder": "Rechercher des commandes", + "newCommand": "Nouvelle commande", + "nameLabel": "Nom", + "commandLabel": "Commande", + "dragSort": "Glisser pour trier", + "dragSortCommand": "Glisser pour trier {name}", + "orderFailed": "Échec de l'enregistrement de l'ordre des commandes", + "loadFailed": "Échec du chargement des commandes", + "saveFailed": "Échec de l'enregistrement de la commande", + "deleteFailed": "Échec de la suppression de la commande", + "confirmDelete": { + "title": "Supprimer la commande ?", + "message": "Cela supprimera \"{name}\". Cette action est irréversible." + } + } + }, + "workspaceContext": { + "confirmCloseDirtyTab": "Fermer « {title} » sans enregistrer ?", + "confirmCloseOtherDirtyTabs": "Fermer les autres onglets avec des modifications non enregistrées ?", + "confirmCloseAllDirtyTabs": "Fermer tous les onglets avec des modifications non enregistrées ?", + "unableLoadContent": "Impossible de charger le contenu.\n\n{message}", + "previewRequestTimedOut": "La requête de prévisualisation a expiré", + "diffRequestTimedOut": "La requête Diff a expiré", + "branchCompareRequestTimedOut": "La requête de comparaison de branches a expiré", + "commitDiffRequestTimedOut": "La requête de Diff de commit a expiré", + "saveRequestTimedOut": "La requête d’enregistrement a expiré", + "reloadRequestTimedOut": "La requête de rechargement a expiré", + "noChanges": "Aucun changement.", + "noDiffOutput": "Aucune sortie diff.", + "diffTitleWorkspace": "Diff · Espace de travail", + "diffDescriptionWorkingTree": "Arbre de travail (HEAD)", + "diffTitleFile": "Différence · {name}", + "compareTitleFile": "Comparer · {name}", + "compareTitleBranch": "Comparer · {branch}", + "compareDescriptionPath": "{path} · comparer avec {branch}", + "compareDescriptionBranch": "comparer avec {branch}", + "diffTitleCommitFile": "Différence · {name} @ {hash}", + "diffTitleCommit": "Différence · {hash}", + "diffDescriptionCommitPath": "{path} · validation {commit}", + "diffDescriptionCommit": "validation {commit}", + "diffTitleConflictFile": "Conflit · {name}", + "diffDescriptionConflict": "{path} · disque vs non enregistré" + }, + "chat": { + "acpConnections": { + "actions": { + "openAgentsSettings": "Ouvrir les paramètres des agents", + "retry": "Réessayer" + }, + "agentsSetupHint": "Ouvrez Paramètres > Agents pour gérer l'installation.", + "withSetupHint": "{message}\n{hint}", + "blocked": { + "missingConfig": "Impossible de lire la configuration actuelle de l'agent.", + "disabled": "{agent} est désactivé dans les paramètres des agents. Activez-le avant de vous connecter.", + "unavailable": "{agent} n'est pas disponible sur la plateforme actuelle.", + "sdkMissing": "Le SDK de {agent} n'est pas installé", + "adapterMissing": "L'adaptateur ACP de {agent} n'est pas installé" + }, + "backendErrors": { + "initializeTimeout": "Le handshake de connexion de {agent} a expiré (aucune réponse après 60 secondes). Ouvrez Paramètres pour vérifier la configuration de l'agent et du réseau.", + "mcpRejectedByAgent": "{agent} a refusé la session alors que le compagnon MCP de codeg était joint : {message} Si cet agent ne prend pas en charge MCP, désactivez « Prise en charge de MCP » dans les Paramètres puis reconnectez-vous.", + "processExited": "Le processus {agent} s'est arrêté de manière inattendue.", + "spawnFailed": "Impossible de démarrer {agent} : {message}", + "downloadFailed": "Échec du téléchargement de {agent} : {message}", + "sessionLoadResourceNotFound": "Échec du chargement de la session de {agent}. Rechargez pour réessayer ou démarrez une nouvelle conversation.", + "sessionLoadUnavailable": "{agent} n'a pas pu restaurer cette session ; elle a peut-être pris fin ou l'agent s'est arrêté. Rechargez pour réessayer ou démarrez une nouvelle conversation.", + "turnFailedRefusal": "{agent} a refusé de poursuivre ce tour. Cela indique souvent une erreur de backend ou de passerelle. Vérifiez les journaux de l'agent.", + "turnFailedMaxTokens": "{agent} a atteint la limite maximale de jetons pour ce tour.", + "turnFailedMaxTurnRequests": "{agent} a atteint le nombre maximal de requêtes autorisées pour ce tour.", + "turnFailedUnknown": "{agent} a terminé le tour avec une raison d'arrêt inconnue.", + "grokModelSwitchIncompatibleAgent": "{agent} ne peut pas basculer vers ce modèle dans une conversation existante. Démarrez une nouvelle session pour l'utiliser.", + "turnFailedEmpty": "{agent} a terminé le tour sans produire de réponse.", + "turnFailedEmptyProtocol": "{agent} a produit une sortie que codeg n'a pas pu analyser — la version de l'agent ne correspond peut-être pas au protocole.", + "turnFailedEmptyMetadata": "{agent} n'a envoyé que des mises à jour d'état ce tour-ci (plan / mode / utilisation) et aucune réponse.", + "detailsInAlerts": "Ouvrez les alertes de la barre d'état et développez les détails pour voir la sortie de l'agent." + }, + "unableReadAgentConfig": "Impossible de lire la configuration de l'agent : {message}", + "connectFailedTitle": "Échec de la connexion de {agent}", + "toolFallbackTitle": "Outil", + "eventErrorTitle": "Erreur de l'agent", + "notificationTurnComplete": "{agent} a terminé de répondre", + "notificationError": "{agent} erreur : {message}", + "claudeApiRetry": { + "fallbackError": "authentication_failed", + "retryingWithMax": "nouvelle tentative {attempt}/{max}", + "retryingAttempt": "nouvelle tentative {attempt}", + "retrying": "nouvelle tentative", + "nextRetryIn": "prochaine dans {seconds}s", + "line": "{error}{status} · {retry}", + "lineWithDelay": "{error}{status} · {retry}, {delay}", + "httpStatus": " (HTTP {status})" + }, + "configOptionAdjusted": "{agent} a réglé {option} sur {actual} au lieu de {requested}" + }, + "connectionLifecycle": { + "tasks": { + "connectingTitle": "Connexion à {agent}", + "connectingDescription": "Établissement de la connexion", + "loadingSelectorsTitle": "Chargement des sélecteurs de {agent}", + "loadingSelectorsDescription": "Récupération des options de mode et de configuration de session", + "initSessionTitle": "Initialisation de la session {agent}", + "initSessionDescription": "Création de la session et chargement de la configuration" + }, + "errors": { + "connectionFailed": "Échec de la connexion", + "sendPromptFailed": "Échec de l'envoi du message : {error}" + } + }, + "shared": { + "attachedResources": "Ressources jointes", + "toolCallFailed": "Échec de l'appel d'outil" + }, + "messageThread": { + "emptyTitle": "Aucun message pour le moment", + "emptyDescription": "Commencez une conversation pour voir les messages ici" + }, + "chatInput": { + "connecting": "Connexion...", + "agentResponding": "{agent} répond...", + "sendMessage": "Envoyer un message..." + }, + "messageInput": { + "askAnything": "Posez n'importe quelle question...", + "removeAttachmentAria": "Retirer {name}", + "attachFiles": "Joindre des fichiers", + "addActions": "Ajouter", + "quickMessages": "Messages rapides", + "quickMessagesEmpty": "Aucun message rapide pour l'instant", + "quickMessagesLoading": "Chargement...", + "pasteAsPlainText": "Coller en texte brut", + "cut": "Couper", + "copy": "Copier", + "selectAll": "Tout sélectionner", + "pasteUnavailable": "Impossible de lire le presse-papiers. Utilisez Ctrl/⌘V pour coller.", + "clipboardWriteFailed": "Impossible d'écrire dans le presse-papiers. Utilisez le raccourci clavier.", + "quickMessageUntitled": "Sans titre", + "liveFeedback": "Retour en direct", + "liveFeedbackDisabledHint": "Disponible pendant que l'agent travaille", + "dropFilesToAttach": "Déposez des fichiers à joindre", + "loadingSettings": "Chargement des paramètres...", + "loadingMode": "Chargement du mode...", + "modeLabel": "Mode", + "toggleOn": "Activé", + "toggleOff": "Désactivé", + "agentSettings": "Paramètres de l'agent", + "searchModel": "Rechercher des modèles...", + "searchModelAria": "Rechercher des modèles", + "modelListLabel": "Modèles", + "noModels": "Aucun modèle trouvé", + "cancel": "Annuler", + "send": "Envoyer", + "forkAndSend": "Fork & Envoyer", + "queueMessage": "Mettre en file d'attente", + "steerIntoTurn": "Insérer dans le tour en cours", + "steerQueuedInstead": "Mis en file d'attente — il sera envoyé au tour suivant.", + "steerFailed": "Impossible d'insérer dans le tour en cours", + "steerAttachmentsUnsupported": "Texte uniquement — les brouillons avec pièces jointes passent par la file d'attente.", + "slashCommands": "Commandes slash", + "slashSearchPlaceholder": "Rechercher des commandes...", + "slashSearchEmpty": "Aucune commande correspondante", + "experts": "Experts", + "office": "Bureautique", + "research": "Recherche", + "attachLocalUpload": "Téléverser un fichier local", + "attachServerFile": "Sélectionner un fichier serveur", + "attachUploadTooLarge": "{names} dépasse la limite de téléversement de {limit} Mo et a été ignoré.", + "attachUploadFailed": "Échec du téléversement de {names}.", + "attachUploadNotAFile": "{names} n'est pas un fichier régulier (répertoire ou fichier spécial) et a été ignoré.", + "attachUploadQuotaExceeded": "Le serveur n'a plus d'espace pour les téléversements ; {names} n'a pas pu être envoyé.", + "attachUploadInProgress": "Les images sont encore en cours d'envoi — réessayez dans un instant.", + "mentionEmpty": "Aucune correspondance", + "mentionLoading": "Recherche…", + "mentionListLabel": "Mentions", + "mentionMore": "Plus de résultats — continuez à taper pour filtrer", + "mentionCount": "{count, plural, one {# résultat} other {# résultats}}", + "mentionGroupFile": "Fichiers", + "mentionGroupAgent": "Agents", + "mentionGroupSession": "Sessions", + "mentionGroupCommit": "Commits", + "mentionGroupSkill": "Compétences" + }, + "messageQueue": { + "addToQueue": "Mettre en file", + "saveEdit": "Enregistrer", + "cancelEdit": "Annuler la modification", + "editItem": "Modifier", + "deleteItem": "Supprimer" + }, + "welcomeInputPanel": { + "agentsSettingsPath": "Paramètres > Agents", + "autoConnectFallback": "Cliquez pour ouvrir {path} et gérer l'installation.", + "autoConnectAppend": "{message}. Cliquez pour ouvrir {path} et gérer l'installation.", + "enableAgentFirstPlaceholder": "Activez au moins un agent avant de démarrer une session...", + "prepareSessionFailed": "Impossible de préparer la session de chat. Veuillez réessayer.", + "createConversationFailed": "Impossible de créer la conversation. Veuillez réessayer.", + "askAnythingPlaceholder": "Posez n'importe quelle question...", + "agentNotInstalled": "{agent} n'est pas installé · ouvrez les paramètres Agents pour l'installer", + "agentAdapterNotInstalled": "L'adaptateur ACP de {agent} n'est pas installé (distinct de votre propre CLI) · ouvrez les paramètres Agents pour l'installer" + }, + "welcomePanel": { + "greeting": "Que souhaites-tu faire aujourd'hui ?", + "tips": { + "tileTabs": "Faites un clic droit sur un onglet de conversation et choisissez Affichage en mosaïque pour comparer plusieurs sessions côte à côte.", + "pinTab": "Double-cliquez sur un onglet de conversation pour l'épingler : une nouvelle session ne le remplacera plus automatiquement.", + "shortcutsNewSearch": "{newConversation} ouvre une nouvelle conversation, {searchConversations} recherche dans l'historique.", + "slashAtMention": "Saisissez / dans la zone de saisie pour les commandes slash, ou @ pour référencer un fichier du projet.", + "pasteDropFiles": "Collez une capture d'écran ou déposez un fichier directement dans la zone de saisie pour le joindre.", + "queueMessage": "Pendant que l'agent répond, continuez à écrire : votre message suivant est mis en file et envoyé automatiquement à la fin.", + "draftAutoSave": "Les brouillons non envoyés sont sauvegardés automatiquement par conversation et restaurés à votre retour.", + "forkSend": "Le menu déroulant du bouton d'envoi propose Bifurquer et envoyer pour ouvrir une branche dans un nouvel onglet à partir du point actuel.", + "exportConversation": "Faites un clic droit dans la conversation pour l'exporter en Markdown, HTML ou image.", + "chatChannels": "Connectez Telegram / Lark / WeChat dans Paramètres → Canaux de discussion pour continuer depuis votre téléphone.", + "shortcutsAuxPanel": "{toggleAuxPanel} bascule le panneau droit pour voir les fichiers modifiés et les changements Git de cette session.", + "shortcutsTerminalSidebar": "{toggleTerminal} ouvre le terminal intégré, {toggleSidebar} bascule la barre latérale.", + "customShortcuts": "Tous les raccourcis peuvent être réassignés dans Paramètres → Raccourcis.", + "webService": "Activez Paramètres → Service Web pour que votre équipe accède au même codeg depuis un navigateur.", + "fusionMode": "Ouvrez un fichier ou un diff pour l'afficher automatiquement à côté de la conversation.", + "quickMessages": "Ouvrez le bouton + à côté de la saisie et choisissez Messages rapides pour insérer un extrait enregistré (à gérer dans Paramètres → Messages rapides).", + "experts": "Le bouton + propose un menu Compétences expertes — chargez en un clic des rôles comme Débogage ou Planification.", + "taskBoard": "Les tâches à faire exécutent un travail de bout en bout : l'agent travaille dans son propre worktree, vous relisez le diff puis fusionnez.", + "automations": "Les Automatisations exécutent un prompt enregistré selon un planning — une revue nocturne, un rapport récurrent — et chaque exécution peut avoir son propre worktree.", + "tokenUsage": "Cliquez sur le nombre de conversations dans la barre d'état pour ouvrir la Consommation de tokens, détaillée par jour, agent, modèle et dossier.", + "mentionTargets": "@ ne sert pas qu'aux fichiers : mentionnez un autre agent pour lui confier une sous-tâche, ou référencez une session passée, un commit ou une compétence.", + "splitGroups": "Faites un clic droit sur un onglet et choisissez Diviser à droite ou Diviser en bas pour garder deux conversations dans leurs propres volets.", + "worktrees": "Ouvrez le bouton de branche et choisissez Nouveau worktree pour que plusieurs agents travaillent sur le même dépôt sans écraser les fichiers des autres.", + "importSessions": "Vous avez déjà lancé des sessions dans le terminal ? Le menu d'un dossier propose Importer les sessions locales pour récupérer cet historique dans codeg.", + "subSessions": "Quand un agent délègue, la sous-session apparaît imbriquée sous lui dans la barre latérale : dépliez la ligne pour suivre ce que chacune a fait.", + "liveFeedback": "Retour en direct, dans le menu +, glisse une note dans le tour que l'agent exécute déjà, sans l'interrompre.", + "skillPacks": "Paramètres → Packs de compétences regroupe experts du code, recherche scientifique et bureautique ; activez-les agent par agent.", + "modelProviders": "Paramètres → Fournisseurs de Modèles accepte votre propre clé d'API ou endpoint, puis vous choisissez le modèle dans la zone de saisie.", + "workspaceBackground": "Paramètres → Apparence définit une image de fond pour l'espace de travail, l'opacité des panneaux et les polices de l'application." + }, + "quickActions": { + "excel": "Classeur Excel", + "excelDesc": "Tableaux, formules et graphiques", + "word": "Document Word", + "wordDesc": "Rapports, lettres et notes", + "ppt": "Présentation", + "pptDesc": "Diapositives au design professionnel", + "pitchDeck": "Pitch Deck", + "pitchDeckDesc": "Présentation de levée avec indicateurs", + "morph": "Animation Morph", + "morphDesc": "Transitions de diapositive cinématographiques", + "morph3d": "Morph 3D", + "morph3dDesc": "Modèles 3D avec mouvements de caméra", + "academic": "Article académique", + "academicDesc": "Recherche avec citations et structure", + "financial": "Modèle financier", + "financialDesc": "États, DCF et projections", + "dashboard": "Tableau de bord", + "dashboardDesc": "KPI et analyses à partir de vos données", + "prompts": { + "excel": "Crée un classeur Excel avec les exigences suivantes :\n\n[décris ici tes données, tableaux, formules et graphiques]", + "word": "Crée un document Word avec les exigences suivantes :\n\n[décris ici le contenu, la structure et la mise en forme du document]", + "ppt": "Crée une présentation PowerPoint avec les exigences suivantes :\n\n[décris ici tes diapositives, le contenu et le design]", + "pitchDeck": "Crée un pitch deck de levée de fonds avec les exigences suivantes :\n\n[décris ici ton entreprise, le tour de financement et les indicateurs clés]", + "morph": "Crée une présentation avec des animations de transition Morph :\n\n[décris ici le sujet de la présentation et les effets visuels souhaités]", + "morph3d": "Crée une présentation Morph 3D avec des modèles GLB et des mouvements de caméra :\n\n[décris ici ton sujet et le concept visuel en 3D]", + "academic": "Rédige un article académique dans Word avec les exigences suivantes :\n\n[décris ici ton sujet de recherche, la méthodologie et les principaux résultats]", + "financial": "Crée un modèle financier dans Excel avec les exigences suivantes :\n\n[décris ici tes états financiers, projections et analyses]", + "dashboard": "Crée un tableau de bord de données dans Excel avec les exigences suivantes :\n\n[décris ici ta source de données, les KPI et les graphiques]", + "scientific-brainstorming": "Aide-moi à imaginer des pistes de recherche : explore les liens interdisciplinaires, questionne les hypothèses et repère les lacunes prometteuses. Le domaine que j'explore : ", + "hypothesis-generation": "Aide-moi à transformer ces observations en hypothèses testables, avec des prédictions claires, des mécanismes plausibles et des expériences. Mes observations : ", + "experimental-design": "Aide-moi à concevoir une expérience rigoureuse avant de collecter des données : le plan, la randomisation, les contrôles et comment éviter les facteurs de confusion. Ce que je veux étudier : ", + "statistical-power": "Aide-moi à déterminer la taille d'échantillon nécessaire : guide-moi dans une analyse de puissance (taille d'effet, alpha, puissance) pour mon plan. Détails : ", + "statistical-analysis": "Aide-moi à analyser ces données correctement : choisir le bon test, vérifier les hypothèses, rapporter les tailles d'effet et rédiger. Mes données et ma question : ", + "exploratory-data-analysis": "Fais une analyse exploratoire de mon fichier de données : résume sa structure, sa qualité et les motifs notables, puis propose les prochaines étapes. Le fichier est : ", + "scientific-visualization": "Aide-moi à créer une figure de qualité publication : mise en page claire, barres d'erreur honnêtes, palette adaptée au daltonisme et mise en forme de revue. Ce que je veux montrer : ", + "scientific-critical-thinking": "Aide-moi à évaluer de façon critique cette étude ou affirmation : apprécie la qualité des preuves, repère les biais et facteurs de confusion, et pèse les conclusions. La voici : ", + "paper-lookup": "Aide-moi à trouver des articles pertinents et du texte intégral en libre accès dans les bases de données savantes, avec des citations réutilisables. Je cherche : " + }, + "paper-lookup": "Recherche d'articles", + "paper-lookupDesc": "Rechercher dans 10 API savantes (PubMed, arXiv, OpenAlex, Crossref…) articles, citations et texte intégral en libre accès.", + "scientific-critical-thinking": "Pensée critique", + "scientific-critical-thinkingDesc": "Évaluer les affirmations scientifiques et la qualité des preuves : repérer biais et facteurs de confusion, appliquer GRADE.", + "scientific-visualization": "Visualisation scientifique", + "scientific-visualizationDesc": "Figures prêtes à publier : dispositions multipanneaux, annotations de significativité et mise en forme par revue.", + "exploratory-data-analysis": "Analyse exploratoire des données", + "exploratory-data-analysisDesc": "Exploration automatisée de fichiers de données scientifiques (200+ formats) avec métriques de qualité et rapports.", + "statistical-analysis": "Analyse statistique", + "statistical-analysisDesc": "Analyse statistique guidée : choix du test, vérification des hypothèses, tailles d'effet et rapport au format APA.", + "statistical-power": "Puissance statistique", + "statistical-powerDesc": "Analyse de la taille d'échantillon et de la puissance : effectifs nécessaires, effets minimaux détectables, courbes de puissance.", + "experimental-design": "Plan d'expérience", + "experimental-designDesc": "Concevoir des études rigoureuses avant la collecte : randomisation, blocs, contrôles et plans factoriels/DOE.", + "hypothesis-generation": "Génération d'hypothèses", + "hypothesis-generationDesc": "Transformer des observations en hypothèses testables avec prédictions, mécanismes et expériences de test.", + "scientific-brainstorming": "Brainstorming scientifique", + "scientific-brainstormingDesc": "Idéation de recherche ouverte : explorer les liens interdisciplinaires, questionner les hypothèses, repérer les lacunes.", + "tabs": { + "office": "Bureautique", + "coding": "Développement", + "research": "Recherche" + }, + "coding": { + "brainstormingDesc": "Explorer intention et besoins avant de coder", + "debuggingDesc": "Trouver la cause racine avant de corriger", + "writingSkillsDesc": "Créer, modifier et vérifier des skills réutilisables" + }, + "notEnabled": { + "title": "La compétence « {skill} » n’est pas encore activée pour {agent}", + "description": "Activez-la dans les Paramètres pour l’utiliser ici.", + "action": "Activer", + "hint": "Compétence non activée" + }, + "scrollPrev": "Afficher les compétences précédentes", + "scrollNext": "Afficher plus de compétences" + } + }, + "agentSelector": { + "noEnabledAgents": "Aucun agent activé", + "openAgentsSettings": "Ouvrir les paramètres des agents", + "notInstalled": "Non installé", + "moreAgents": "Plus d'agents ({count})" + }, + "subAgentOverlay": { + "title": "Sous-agents", + "collapsedSummary": "Sous-agents {count}", + "collapseAria": "Réduire les sous-agents" + }, + "agentPlanOverlay": { + "title": "Plan de l'agent", + "collapsePlanAria": "Réduire le plan", + "collapsedSummary": "Plan de travail {completed}/{total}", + "status": { + "completed": "Terminé", + "inProgress": "En cours", + "pending": "En attente", + "unknown": "Inconnu" + }, + "priority": { + "high": "Haute", + "medium": "Moyenne", + "low": "Basse", + "unknown": "Inconnue" + } + }, + "permissionDialog": { + "subtitle": "L'agent demande une autorisation pour continuer ce tour.", + "queuedCount": "+{count} en attente", + "kindFallbackTool": "outil", + "command": "Commande", + "cwd": "Répertoire de travail : {cwd}", + "filesSummary": "Fichiers : {count}", + "moreFiles": "+{count} fichiers supplémentaires", + "plan": "Plan de travail", + "allowedActions": "Actions autorisées", + "targetMode": "Mode cible : {mode}", + "optionGrants": "Ce que chaque option accorde", + "changeScopeSession": "Cette session", + "changeScopeProcess": "Cette exécution", + "changeScopeUser": "Enregistré dans les paramètres utilisateur", + "changeScopeProject": "Enregistré dans les paramètres du projet", + "changeScopeProjectLocal": "Enregistré dans les paramètres locaux du projet", + "changeScopePersistent": "Enregistré définitivement" + }, + "questionDialog": { + "title": "L'agent pose une question", + "placeholder": "Tapez votre réponse...", + "send": "Envoyer" + }, + "messageBranch": { + "previousBranchAria": "Branche précédente", + "nextBranchAria": "Branche suivante", + "pageOf": "{current} sur {total}" + }, + "terminal": { + "title": "Console", + "running": "En cours" + }, + "reasoning": { + "thinking": "Réflexion…", + "thoughtForFewSeconds": "Réflexion", + "thoughtForSeconds": "Réflexion" + }, + "linkSafety": { + "errorCannotOpen": "Impossible d'ouvrir le fichier local", + "errorNoWorkspace": "Aucun dossier d'espace de travail n'est actuellement actif.", + "errorFailedOpen": "Échec de l'ouverture du fichier local", + "errorFailedLink": "Échec de l'ouverture du lien", + "errorUnsupportedLinkProtocol": "Ce protocole de lien n’est pas pris en charge." + }, + "fileActions": { + "openInFinder": "Ouvrir dans Finder", + "openInExplorer": "Ouvrir dans Explorer", + "openInFileManager": "Ouvrir dans le gestionnaire de fichiers", + "copyRelativePath": "Copier le chemin relatif", + "copyAbsolutePath": "Copier le chemin absolu", + "pathCopied": "Chemin copié", + "copyPathFailed": "Échec de la copie du chemin", + "openFailed": "Échec de l'ouverture du fichier local" + }, + "messageList": { + "attachedResources": "Ressources jointes", + "loading": "Chargement...", + "loadEarlier": "Charger les messages précédents", + "loadingEarlier": "Chargement des messages précédents…", + "error": "Erreur : {message}", + "errorTitle": "Échec du chargement de la session", + "errorActionReload": "Recharger", + "errorActionNewSession": "Nouvelle conversation", + "emptyConversation": "Aucun message dans cette conversation.", + "systemMessage": "Message système", + "copyMessage": "Copier", + "copied": "Copié", + "downloadImage": "Télécharger l'image", + "downloadFailed": "Échec du téléchargement : {message}", + "imageGeneration": "Génération d'image", + "imageGenerationPending": "Génération de l'image…", + "imageGenerationFailed": "Échec de la génération d'image", + "model": "Modèle", + "tokenStats": "Utilisation des tokens", + "tokenInput": "Entrée", + "tokenOutput": "Sortie", + "tokenCacheRead": "Lecture du cache", + "tokenCacheWrite": "Écriture du cache", + "duration": "Durée", + "completedAt": "Terminé à", + "jumpToPreviousUserMessage": "Aller au message utilisateur", + "showMore": "Afficher plus", + "showLess": "Afficher moins" + }, + "liveTurnStats": { + "thinking": "Réflexion...", + "streaming": "Diffusion", + "elapsedHours": "{value} h", + "elapsedMinutes": "{value} min", + "elapsedSeconds": "{value} s", + "outputSpeedAria": "Vitesse de sortie estimée", + "outputSpeedTooltip": "Vitesse de sortie estimée (texte + raisonnement)" + }, + "jsonTree": { + "viewRaw": "Afficher le JSON brut", + "viewTree": "Afficher l'arborescence", + "fields": "{count, plural, one {# champ} other {# champs}}", + "items": "{count, plural, one {# élément} other {# éléments}}" + }, + "tool": { + "parameters": "Paramètres", + "error": "Erreur", + "result": "Résultat", + "status": { + "approvalRequested": "En attente d'approbation", + "approvalResponded": "Répondu", + "inputAvailable": "En cours", + "inputStreaming": "En attente", + "outputAvailable": "Terminé", + "outputDenied": "Refusé", + "outputError": "Erreur" + } + }, + "toolCallBlock": { + "tool": "Outil", + "error": "Erreur", + "result": "Résultat" + }, + "delegation": { + "subAgentRunning": "Sous-agent en cours…", + "noDetail": "Aucun détail disponible pour le moment.", + "unknownAgent": "Sous-agent", + "openDetail": "Voir la conversation", + "detailTitle": "Conversation du sous-agent", + "detailDescription": "Vue en lecture seule de la conversation du sous-agent délégué.", + "waitForResult": "En attente du résultat de la tâche {task}", + "waitForResultNoTask": "En attente du résultat de la tâche", + "cancelTask": "Annulation de la tâche {task}", + "cancelTaskNoTask": "Annulation de la tâche", + "resultPageOf": "{current} / {total}", + "prevResult": "Résultat précédent", + "nextResult": "Résultat suivant", + "noResultText": "Aucun résultat pour cette vérification.", + "status": { + "starting": "démarrage", + "running": "en cours", + "checked": "vérifié", + "waiting": "en attente d'approbation", + "ok": "terminé", + "err": { + "default": "échec", + "delegation_disabled": "désactivé", + "depth_limit": "limite de profondeur", + "invalid_agent_type": "agent invalide", + "spawn_failed": "échec du démarrage", + "send_failed": "échec de l'envoi", + "timeout": "délai dépassé", + "canceled": "annulé", + "child_refusal": "sous-agent refusé", + "child_max_tokens": "sous-agent : limite de jetons", + "child_max_turn_requests": "sous-agent : limite de requêtes", + "child_empty": "sous-agent sans sortie", + "child_unknown": "sous-agent : erreur", + "unknown": "tâche inconnue" + } + } + }, + "contentParts": { + "showingTailOutput": "Affichage de la fin de la sortie pendant le streaming pour de meilleures performances.", + "result": "Résultat", + "unknown": "inconnu", + "inputTruncated": "L'entrée a été tronquée — le diff peut être incomplet.", + "replaceAll": "TOUT REMPLACER", + "filesCount": "Fichiers : {count}", + "update": "mettre à jour", + "moreFiles": "+{count} fichiers supplémentaires", + "timeoutMs": "Délai d'expiration : {timeout}ms", + "backgroundTrue": "Arrière-plan : true", + "scriptToolCalls": "{count, plural, one {# appel d'outil} other {# appels d'outil}}", + "offset": "Décalage : {offset}", + "limit": "Limite : {limit}", + "pages": "Pages : {pages}", + "mode": "Mode : {mode}", + "cell": "Cellule : {cell}", + "shellSession": "Session {id}", + "pathLabel": "Chemin :", + "globLabel": "Glob :", + "typeLabel": "Type :", + "outputLabel": "Sortie :", + "caseInsensitive": "Insensible à la casse", + "multiline": "Multiligne", + "promptLabel": "Instruction", + "subjectLabel": "Sujet", + "taskLabel": "Tâche", + "nameLabel": "Nom :", + "agentPromptLabel": "Instruction", + "agentModelLabel": "Modèle", + "agentRunning": "En cours...", + "agentLiveTranscript": "Activité en direct", + "agentProgressTools": "{count} appels d'outils", + "agentProgressTurns": "{count} tours", + "agentProgressContext": "contexte {pct}%", + "agentSessionAction": "Voir la session du sous-agent", + "agentSessionTitle": "Session du sous-agent", + "agentSessionLoading": "Chargement de la transcription du sous-agent…", + "agentSessionEmpty": "Le sous-agent n'a encore rien écrit.", + "agentFallbackTitle": "Démarrage du sous-agent…", + "agentCodexLaunchOnly": "Lancé. Codex ne signale plus la progression de ce sous-agent : son résultat arrivera sous forme de message dans cette conversation.", + "agentStatsBash": "Commandes", + "agentStatsRead": "Fichiers lus", + "agentStatsSearch": "Recherches", + "agentStatsEdit": "Modifications", + "agentStatsOther": "Autres", + "goal": { + "title": "Objectif :", + "titleWithStatus": "Objectif {status}", + "objective": "Objectif", + "statusLabel": "Statut", + "tokensUsed": "Tokens utilisés", + "budget": "Budget", + "remaining": "Restant", + "elapsed": "Écoulé", + "tokens": "tokens", + "pause": "Pause", + "clear": "Effacer", + "status": { + "active": "actif", + "paused": "en pause", + "blocked": "bloqué", + "usageLimited": "utilisation limitée", + "budgetLimited": "budget limité", + "complete": "terminé", + "limited": "limite atteinte" + } + }, + "field": { + "file": "Fichier", + "notebook": "Carnet", + "command": "Commande", + "old": "Ancien", + "new": "Nouveau", + "pattern": "Motif", + "path": "Chemin", + "query": "Requête", + "url": "URL :", + "description": "Détails", + "content": "Contenu", + "source": "Origine", + "prompt": "Instruction", + "subject": "Sujet", + "taskId": "ID de tâche", + "status": "Statut", + "skill": "Skill", + "args": "Arguments", + "offset": "Décalage", + "limit": "Limite", + "glob": "Motif glob", + "type": "Type de donnée", + "output": "Sortie", + "replaceAll": "Tout remplacer", + "language": "Langue", + "timeout": "Délai", + "background": "Arrière-plan", + "agentType": "Type d'agent", + "library": "Bibliothèque", + "libraryId": "ID de bibliothèque" + }, + "title": { + "edit": "Modifier", + "command": "Commande", + "script": "Script", + "waitCommand": "Attendre {command}", + "waitCell": "Attendre la session {id}", + "terminateCommand": "Terminer {command}", + "terminateCell": "Terminer la session {id}", + "stdinChars": "Entrée {chars}", + "todoWrite": "TodoWrite (mise à jour des tâches)", + "read": "Lire", + "write": "Écrire", + "notebookEdit": "NotebookEdit (édition du carnet)", + "editFiles": "Modifier ({count} fichiers)", + "editWithTarget": "Modifier {target}", + "readWithTarget": "Lire {target}", + "writeWithTarget": "Écrire {target}", + "notebookEditWithTarget": "NotebookEdit ({target})", + "globWithPattern": "Motif glob {pattern}", + "listFilesWithPath": "Lister les fichiers {path}", + "grepWithPattern": "Motif grep {pattern}", + "taskCreateWithSubject": "Créer une tâche : {subject}", + "taskUpdateWithStatus": "Mettre à jour la tâche #{id} -> {status}", + "taskUpdate": "Mettre à jour la tâche #{id}", + "webFetchWithUrl": "WebFetch ({url})", + "webSearchWithQuery": "Recherche web : {query}", + "todosProgress": "Tâches ({done}/{total})", + "skillWithName": "Skill : {name}", + "genericWithContext": "{tool} ({context})" + }, + "search": { + "noMatches": "Aucune correspondance", + "matchSummary": "{matches, plural, one {# correspondance} other {# correspondances}} dans {files, plural, one {# fichier} other {# fichiers}}", + "fileSummary": "{files, plural, one {# fichier} other {# fichiers}}", + "moreResults": "{count, plural, one {# résultat supplémentaire non affiché} other {# résultats supplémentaires non affichés}}" + }, + "toolGroup": { + "search": "{count, plural, one {A exploré # recherche} other {A exploré # recherches}}", + "command": "{count, plural, one {A exécuté # commande} other {A exécuté # commandes}}", + "read": "{count, plural, one {A lu des fichiers # fois} other {A lu des fichiers # fois}}", + "memory": "{count, plural, one {A rappelé # souvenir} other {A rappelé # souvenirs}}", + "edit": "{count, plural, one {A modifié des fichiers # fois} other {A modifié des fichiers # fois}}", + "fetch": "{count, plural, one {A récupéré # ressource} other {A récupéré # ressources}}", + "think": "{count, plural, one {A réfléchi # fois} other {A réfléchi # fois}}", + "todo": "{count, plural, one {A mis à jour # tâche} other {A mis à jour # tâches}}", + "task": "{count, plural, one {A lancé # tâche} other {A lancé # tâches}}", + "other": "{count, plural, one {A utilisé # outil} other {A utilisé # outils}}", + "errorSuffix": "{count, plural, one {# échec} other {# échecs}}", + "joiner": " · " + }, + "planMode": { + "entered": "Mode planification activé", + "planLabel": "Plan", + "reviewApproved": "Plan approuvé — mise en œuvre", + "reviewKept": "Reste en mode plan", + "reviewPending": "En attente de la décision sur le plan", + "submitted": "Plan soumis", + "switched": "Mode changé" + }, + "backgroundTask": { + "title": "Tâche en arrière-plan", + "titleWithId": "Tâche en arrière-plan · {id}", + "running": "En cours", + "completed": "Terminée", + "failed": "Échouée", + "stopped": "Arrêtée", + "exitCode": "sortie {code}", + "polledTimes": "Interrogée {count} fois", + "runningInBackground": "Arrière-plan", + "launchNote": "En cours d'exécution en arrière-plan · {id}" + }, + "codexScript": { + "outputMissing": "Codex a tronqué la sortie du script et supprimé le séparateur de cette commande ; aucune sortie n'a donc pu lui être attribuée.", + "sharedWith": "Contient aussi la sortie de {commands} — codex en a tronqué les séparateurs.", + "truncated": "tronqué" + } + }, + "messageNav": { + "title": "Navigation des messages", + "collapse": "Réduire la navigation des messages", + "collapsedSummary": "Messages {count}", + "fileCount": "{count, plural, one {# fichier} other {# fichiers}}", + "remove": "Retirer", + "noDiffDataAvailable": "Aucune donnée de diff disponible pour {filePath}" + }, + "replyArtifacts": { + "title": "Fichiers modifiés", + "fileCount": "{count, plural, one {# fichier} other {# fichiers}}", + "newFilesTitle": "Nouveaux fichiers", + "revealInFolder": "Afficher dans le gestionnaire de fichiers", + "openFile": "Ouvrir {filePath}", + "openInEditor": "Ouvrir dans l'éditeur", + "remove": "Retirer", + "noDiffDataAvailable": "Aucune donnée de diff disponible pour {filePath}" + }, + "askQuestion": { + "title": "L'agent attend votre choix", + "subtitle": "Répondez puis envoyez. Vous pouvez ignorer à tout moment.", + "recommended": "Recommandé", + "other": "Autre", + "otherPlaceholder": "Saisissez votre réponse…", + "singleSelect": "Unique", + "multiSelect": "Multiple", + "skip": "Ignorer", + "next": "Suivant", + "submit": "Envoyer", + "submitError": "Échec de l'envoi. Veuillez réessayer." + }, + "planApproval": { + "title": "L'agent a un plan — à vérifier", + "emptyPlan": "L'agent n'a pas rédigé de plan. Approuvez pour commencer ou demandez des modifications.", + "approve": "Approuver et lancer", + "requestChanges": "Demander des modifications", + "abandon": "Abandonner", + "feedbackPlaceholder": "Que faut-il changer ?", + "sendChanges": "Envoyer", + "cancel": "Annuler", + "submitError": "Échec de l'envoi. Veuillez réessayer." + }, + "feedbackCheckResult": { + "count": "{count, plural, =1 {1 retour} other {# retours}}", + "expand": "Afficher tous les retours", + "collapse": "Réduire", + "errorTitle": "Échec de la vérification des retours" + }, + "askQuestionResult": { + "title": "Question", + "answeredLabel": "Question et réponse :", + "awaiting": "En attente de ta réponse…", + "declined": "Tu as ignoré cette question — l’agent a utilisé son propre jugement.", + "noSelection": "Aucune sélection" + }, + "configStale": { + "agentConfigTitle": "Paramètres de l'agent mis à jour", + "modelProviderTitle": "Fournisseur de modèle mis à jour", + "description": "Cette session utilise encore son ancienne configuration. Reconnectez-vous pour l'appliquer (l'historique de conversation est conservé).", + "reconnect": "Reconnecter pour appliquer", + "reconnecting": "Reconnexion…", + "reconnectDisabledDuringTurn": "Disponible une fois le tour en cours terminé", + "dismiss": "Ignorer", + "reconnectFailed": "Échec de la reconnexion de la session", + "applied": "Nouvelle configuration appliquée" + }, + "piProjectTrust": { + "title": "Ce projet fournit des ressources pi", + "description": "pi ne charge pas les fichiers .pi du dépôt. Examinez-les pour décider.", + "descriptionExecutable": "Le dépôt fournit des extensions pi, qui exécutent du code au démarrage. pi ne les charge pas. Examinez-les avant de décider.", + "review": "Examiner…", + "dismiss": "Ignorer", + "dialogTitle": "Faire confiance aux ressources pi de ce projet ?", + "dialogDescription": "pi ne charge les fichiers .pi d'un dépôt que si vous faites confiance au dossier. N'accordez votre confiance que si vous avez confiance dans le contenu de ce dépôt.", + "executionWarning": "Les extensions sont du code. En faisant confiance à ce dossier, vous autorisez le dépôt à les exécuter au démarrage de pi avec vos permissions, avant même l'envoi d'un message.", + "scopeNote": "La décision est enregistrée dans le trust.json de pi pour ce dossier, s'applique à tous les dossiers qu'il contient et sert aussi lorsque vous lancez pi vous-même dans un terminal. Vous pourrez la modifier dans Paramètres → Agents → Pi.", + "trust": "Faire confiance au projet", + "decline": "Ne pas charger", + "disabledDuringTurn": "Disponible une fois le tour en cours terminé", + "trustedToast": "Projet approuvé — reconnexion effectuée pour que pi charge ses ressources", + "declinedToast": "Les ressources du projet restent non chargées", + "saveFailed": "Échec de l'enregistrement de la décision de confiance du projet", + "grantTitle": "Ce projet est déjà approuvé", + "grantDescription": "pi charge les fichiers .pi du dépôt. Examinez ce que cela autorise.", + "grantInheritedDescription": "Un dossier parent est approuvé, donc pi charge les fichiers .pi du dépôt. Examinez ce que cela autorise.", + "grantDialogTitle": "Les ressources pi de ce projet sont approuvées", + "grantDialogDescription": "pi est autorisé à charger les fichiers .pi du dépôt. Les versions précédentes de codeg accordaient cela automatiquement à l'ouverture d'un dossier, la question ne vous a donc peut-être jamais été posée.", + "grantExecutionWarning": "Les extensions sont du code. Le dépôt les exécute au démarrage de pi avec vos permissions, avant même l'envoi d'un message.", + "inheritedFrom": "Approuvé via", + "revoke": "Révoquer la confiance", + "keepTrusted": "Conserver la confiance", + "revokedToast": "Confiance révoquée — reconnexion effectuée pour que pi cesse de charger les ressources du projet", + "trustedNoReconnect": "Projet approuvé — effectif au prochain démarrage de pi", + "revokedNoReconnect": "Confiance révoquée — effectif au prochain démarrage de pi" + }, + "collabAgent": { + "title": "Sous-agent", + "errorTitle": "Échec de la tâche du sous-agent", + "statesLabel": "Sous-agents", + "statusRunning": "En cours", + "statusCompleted": "Terminé", + "statusFailed": "Échec", + "statusPending": "Démarrage", + "statusInterrupted": "Interrompu", + "statusClosed": "Fermé", + "statusNotFound": "Introuvable", + "opSpawn": "Démarrage du sous-agent", + "opWait": "Récupération du résultat du sous-agent", + "opClose": "Fermeture du sous-agent", + "opResume": "Reprise du sous-agent" + }, + "contextCompaction": { + "compacting": "Compactage du contexte…", + "compacted": "Contexte compacté", + "compactedTokens": "Contexte compacté · {before} → {after} tokens", + "failed": "Échec de la compaction du contexte" + }, + "sessionFailure": { + "category": { + "connection": "Problème de connexion", + "access": "Problème d'accès", + "limit": "Limite atteinte", + "request": "Requête rejetée", + "service": "Problème de service", + "unknown": "Problème de session" + }, + "action": { + "retry": "Réessayer", + "login": "Se connecter", + "newSession": "Nouvelle session" + }, + "recovered": "Rétabli", + "retryUnavailable": "Aucun message précédent à renvoyer.", + "toggleDetails": "Afficher/masquer les détails" + }, + "backgroundTasks": { + "running": "{count, plural, one {# tâche en arrière-plan en cours} other {# tâches en arrière-plan en cours}}", + "settling": "Synchronisation des résultats d'arrière-plan…", + "settledFallback": "Tâche en arrière-plan terminée ({status})", + "cardRunning": "En cours d'exécution en arrière-plan", + "cardLaunchedPending": "Tâche lancée en arrière-plan", + "cardCompleted": "Tâche en arrière-plan terminée", + "cardFinishedWithStatus": "Tâche en arrière-plan terminée ({status})", + "cardResultPending": "Résultat pas encore reçu" + }, + "proposedPlan": { + "title": "Plan proposé", + "planning": "Planification…" + } + }, + "diffPreview": { + "mode": { + "added": "Ajouté", + "deleted": "Supprimé", + "renamed": "Renommé", + "modified": "Modifié" + }, + "hunkLabel": "Bloc {index}", + "loadingHunk": "Chargement du hunk...", + "noDiffData": "Aucune donnée diff", + "showRemainingLines": "Afficher {count} lignes de plus" + }, + "conversationContextBar": { + "folderTitle": "Dossier de travail", + "branchTitle": "Branche de travail", + "searchFolder": "Rechercher un dossier...", + "searchBranch": "Rechercher une branche...", + "noFolders": "Aucun dossier", + "noBranches": "Aucune branche", + "noBranch": "(aucune branche)", + "chatModeLabel": "Mode chat", + "commit": "Valider", + "push": "Pousser", + "merge": "Fusionner", + "toasts": { + "folderChanged": "Basculé vers {name}", + "openFolderFailed": "Échec de l'ouverture du dossier", + "switchedToChatMode": "Basculé en mode discussion", + "openStashFailed": "Échec de l'ouverture de la fenêtre de remisage", + "openMergeFailed": "Échec de l'ouverture de la fenêtre de fusion" + } + }, + "cloneDialog": { + "title": "Cloner un dépôt", + "repositoryUrl": "URL du dépôt", + "repositoryUrlPlaceholder": "https://github.com/user/repo.git", + "directory": "Répertoire", + "directoryPlaceholder": "Sélectionnez le répertoire cible...", + "browseDirectory": "Parcourir le répertoire", + "cancel": "Annuler", + "clone": "Cloner", + "clonePath": "Chemin de clonage : {path}" + }, + "toasts": { + "cloneFailed": "Échec du clonage du dépôt" + } + }, + "ProjectBoot": { + "title": "Lanceur de projet", + "tabs": { + "shadcn": "shadcn", + "hyperframes": "HyperFrames" + }, + "hyperframes": { + "title": "Projet vidéo HyperFrames", + "subtitle": "Générez un projet HTML-vers-vidéo. L'agent de l'espace de travail peut ensuite l'écrire et le rendre.", + "resolution": "Résolution", + "skillsTitle": "Skills des agents", + "skillsDesc": "Installe globalement les skills HyperFrames (lien symbolique) pour les agents sélectionnés, afin qu'ils puissent créer et rendre des vidéos.", + "recheck": "Revérifier", + "installedBadge": "Installé", + "skillsInstall": "Installer / mettre à jour les skills", + "skillsInstalling": "Installation des skills…", + "skillsInstalled": "Skills HyperFrames installées", + "skillsInstallFailed": "Impossible d'installer les skills HyperFrames" + }, + "config": { + "base": "Base", + "style": "Style", + "baseColor": "Couleur de base", + "theme": "Thème", + "chartColor": "Couleur du graphique", + "iconLibrary": "Bibliothèque d'icônes", + "font": "Police", + "fontHeading": "Police de titre", + "menuAccent": "Accent du menu", + "menuColor": "Couleur du menu", + "radius": "Rayon", + "template": "Modèle", + "createProject": "Créer un projet", + "sectionStyle": "Style", + "sectionColors": "Couleurs", + "sectionTypography": "Typographie", + "sectionInterface": "Interface" + }, + "preview": { + "loading": "Chargement de l'aperçu..." + }, + "createDialog": { + "title": "Créer un projet", + "projectName": "Nom du projet", + "projectNamePlaceholder": "mon-app", + "frameworkTemplate": "Modèle de framework", + "packageManager": "Gestionnaire de paquets", + "saveDirectory": "Répertoire de sauvegarde", + "saveDirectoryPlaceholder": "Sélectionner un répertoire...", + "browseDirectory": "Parcourir", + "projectPath": "Le projet sera créé dans : {path}", + "advancedOptions": "Options avancées", + "base": "Bibliothèque de base", + "enableRtl": "Activer le support RTL", + "enableRtlDescription": "Activer la prise en charge de la mise en page pour les langues de droite à gauche (ex. arabe, hébreu)", + "pmChecking": "Vérification...", + "pmNotInstalled": "Non installé", + "cancel": "Annuler", + "create": "Créer", + "creating": "Création du projet..." + }, + "toasts": { + "createFailed": "Échec de la création du projet", + "createSuccess": "Projet créé avec succès", + "openWorkspaceFailed": "Projet créé, mais impossible de l'ouvrir dans l'espace de travail" + }, + "errors": { + "directoryExists": "Le répertoire cible existe déjà", + "commandFailed": "La commande de création du projet a échoué." + } + }, + "WebServiceSettings": { + "addressSwitchHint": "Changer ne modifie que l'adresse affichée et ouverte ici ; le service écoute sur toutes les interfaces et reste accessible à chaque adresse.", + "sectionTitle": "Service Web", + "sectionDescription": "Activer pour accéder à Codeg à distance via le navigateur", + "port": "Port", + "status": "Statut", + "autoStart": "Démarrage auto", + "autoStartHint": "Démarrer le service Web au lancement de Codeg", + "running": "En cours", + "stopped": "Arrêté", + "processing": "Traitement...", + "start": "Démarrer", + "stop": "Arrêter", + "startFailed": "Échec du démarrage", + "stopFailed": "Échec de l'arrêt", + "saveConfigFailed": "Échec de l'enregistrement des paramètres du service Web", + "open": "Ouvrir", + "hide": "Masquer", + "show": "Afficher", + "copy": "Copier", + "qrcode": "Code QR", + "qrcodeTitle": "Scanner pour ouvrir", + "qrcodeHint": "Scannez avec votre téléphone pour ouvrir Codeg dans un navigateur", + "addressLabel": "Adresse d'accès", + "tokenLabel": "Token d'accès", + "tokenHint": "Entrez ce token lors du premier accès au client Web", + "tokenPlaceholder": "Laisser vide pour générer automatiquement", + "regenerate": "Régénérer", + "stalePortOccupiedTitle": "Le port {port} est utilisé par un autre processus", + "stalePortUnknownTitle": "L'état du port {port} est indéterminé", + "stalePortHint": "Codeg ne peut pas s'attacher tant que le port n'est pas libéré. Changez de port ci-dessus, ou fermez le processus qui le retient.", + "errors": { + "alreadyRunning": "Le service Web est déjà en cours d'exécution", + "invalidAddress": "Format d'hôte ou de port non valide", + "portInUse": "Le port {port} est déjà utilisé. Fermez le processus qui l'utilise ou choisissez un autre port.", + "permissionDenied": "Permission refusée. Utilisez un port supérieur à 1024 ou exécutez avec des privilèges plus élevés.", + "addressUnavailable": "Cette adresse n'est pas disponible sur cette machine", + "bindFailed": "Échec de la liaison à l'adresse" + } + }, + "DirectoryBrowser": { + "title": "Parcourir le répertoire", + "pathPlaceholder": "Entrez le chemin du répertoire...", + "goHome": "Aller au répertoire personnel", + "navigateUp": "Aller au répertoire parent", + "select": "Sélectionner", + "cancel": "Annuler", + "loading": "Chargement...", + "emptyDirectory": "Ce répertoire est vide", + "errorLoadingDir": "Échec du chargement du répertoire", + "permissionDenied": "Permission refusée" + }, + "ChatChannelSettings": { + "loading": "Chargement...", + "sectionTitle": "Canaux de chat", + "sectionDescription": "Configurez des bots IM pour recevoir des notifications d'événements et interroger l'activité de codage.", + "addChannel": "Ajouter un canal", + "noChannels": "Aucun canal de chat configuré pour le moment.", + "channelName": "Nom", + "channelNamePlaceholder": "Mon bot Telegram", + "channelType": "Type de canal", + "lark": "Lark (Feishu)", + "weixin": "WeChat", + "dailyReport": "Rapport quotidien", + "dailyReportTime": "Heure du rapport", + "nameRequired": "Le nom du canal est requis.", + "tokenRequired": "Le token est requis.", + "chatIdRequired": "Le Chat ID est requis.", + "topicMode": "Mode groupe de sujets", + "topicModeHint": "Route les sujets de forum Telegram comme des sessions Codeg séparées. Le bot doit être dans un supergroupe forum et pouvoir gérer les sujets.", + "loadFailed": "Échec du chargement des canaux.", + "saveFailed": "Échec de l'enregistrement.", + "connectSuccess": "Canal connecté.", + "connectFailed": "Échec de la connexion", + "disconnectSuccess": "Canal déconnecté.", + "disconnectFailed": "Échec de la déconnexion.", + "testSuccess": "Test de connexion réussi.", + "testFailed": "Test de connexion échoué", + "deleteSuccess": "Canal supprimé.", + "deleteFailed": "Échec de la suppression du canal.", + "deleteConfirmTitle": "Supprimer le canal", + "deleteConfirmMessage": "Le canal et ses journaux de messages seront définitivement supprimés. Êtes-vous sûr ?", + "cancel": "Annuler", + "delete": "Supprimer", + "create": "Créer", + "save": "Enregistrer", + "channelListTitle": "Canaux configurés", + "channelListDescription": "Les canaux activés se connectent automatiquement au démarrage du service.", + "editChannel": "Modifier le canal", + "editSuccess": "Canal mis à jour.", + "tokenPlaceholderKeep": "Laisser vide pour conserver l'actuel", + "weixinScanTitle": "Scanner le QR code", + "weixinScanDescription": "Ouvrez WeChat et scannez le QR code pour vous connecter.", + "weixinQrcodeExpired": "QR code expiré.", + "weixinRefreshQrcode": "Actualiser", + "weixinWaitingScan": "En attente du scan...", + "weixinPollError": "Connexion instable, nouvelle tentative...", + "weixinReconnectNotice": "En raison des limitations du protocole iLink, après chaque reconnexion vous devez envoyer un message au bot pour que les déclencheurs d'événements prennent effet.", + "connect": "Connecter", + "disconnect": "Déconnecter", + "test": "Tester la connexion", + "tabs": { + "channels": "Canaux", + "commands": "Commandes", + "events": "Événements", + "other": "Autres" + }, + "commands": { + "title": "Commandes intégrées", + "description": "Commandes bot disponibles dans les canaux de chat. Dans les chats de groupe, @Bot est requis pour traiter les messages.", + "prefixLabel": "Préfixe de commande", + "prefixDescription": "1-3 caractères non alphanumériques pour déclencher les commandes du bot (par défaut /).", + "prefixSaved": "Préfixe de commande enregistré.", + "prefixSaveFailed": "Échec de l'enregistrement du préfixe.", + "prefixInvalid": "Le préfixe doit être de 1-3 caractères non alphanumériques.", + "save": "Enregistrer", + "folderDesc": "Sélectionner le dossier de travail", + "agentDesc": "Sélectionner l'agent IA", + "taskDesc": "Créer une session et exécuter la tâche", + "sessionsDesc": "Lister les sessions actives du dossier", + "resumeDesc": "Conversations récentes / reprendre une session", + "cancelDesc": "Annuler la tâche en cours", + "approveDesc": "Approuver la demande de permission de l'agent", + "denyDesc": "Refuser la demande de permission de l'agent", + "searchDesc": "Rechercher des conversations par mot-clé", + "todayDesc": "Résumé de l'activité du jour", + "statusDesc": "État de connexion du canal", + "helpDesc": "Afficher l'aide" + }, + "events": { + "title": "Notifications d'événements", + "description": "Une fois activés, les événements déclenchés seront envoyés au canal.", + "turnComplete": "Tour terminé", + "turnCompleteDesc": "Lorsqu'un tour d'agent se termine", + "error": "Erreur de l'agent", + "errorDesc": "Lorsqu'un agent rencontre une erreur", + "permissionRequest": "Demande d'autorisation", + "permissionRequestDesc": "Lorsqu'un agent demande une autorisation", + "questionRequest": "Question de l'agent", + "questionRequestDesc": "Quand un agent vous pose une question", + "userPromptSent": "Message de l'utilisateur", + "userPromptSentDesc": "Lorsque vous envoyez un message (le texte du message est inclus dans la notification)", + "saved": "Filtre d'événements mis à jour.", + "saveFailed": "Échec de l'enregistrement du filtre d'événements.", + "loadFailed": "Échec du chargement des paramètres.", + "retry": "Réessayer", + "webhooksTitle": "Webhooks", + "webhooksDescription": "Envoie une charge JSON via POST vers une ou plusieurs URL lorsqu'un événement activé se déclenche. Le filtre d'événements ci-dessus s'applique aussi aux webhooks.", + "webhookUrlPlaceholder": "https://example.com/webhook", + "addWebhook": "Ajouter un webhook", + "removeWebhook": "Supprimer le webhook", + "webhookSave": "Enregistrer", + "webhooksSaved": "Webhooks enregistrés.", + "webhooksSaveFailed": "Échec de l'enregistrement des webhooks.", + "webhookInvalidUrl": "Saisissez des URL http(s) valides.", + "docsTitle": "Format de la requête", + "docsMethod": "Méthode", + "docsContentType": "Content-Type", + "docsNote": "Chaque événement activé est envoyé à toutes les URL. Les webhooks ne sont pas anti-rebond ; le filtre d'événements ci-dessus s'applique toujours.", + "editWebhook": "Modifier le webhook", + "enableWebhook": "Activer le webhook", + "webhookDuplicate": "Cette URL est déjà configurée.", + "cancel": "Annuler", + "webhooksEmpty": "Aucun webhook configuré pour le moment.", + "deleteWebhookTitle": "Supprimer le webhook", + "deleteWebhookMessage": "Supprimer ce webhook ? Les événements ne seront plus envoyés à cette URL.", + "delete": "Supprimer" + }, + "language": { + "title": "Langue des messages", + "description": "Langue utilisée pour les notifications d'événements, les réponses aux commandes et les rapports quotidiens envoyés aux canaux de chat.", + "saved": "Langue des messages enregistrée.", + "saveFailed": "Échec de l'enregistrement de la langue des messages.", + "en": "Anglais", + "zh-cn": "Chinois simplifié", + "zh-tw": "Chinois traditionnel", + "ja": "Japonais", + "ko": "Coréen", + "es": "Espagnol", + "de": "Allemand", + "fr": "Français", + "pt": "Portugais", + "ar": "Arabe" + } + }, + "ModelProviderSettings": { + "sectionTitle": "Fournisseurs de Modèles", + "sectionDescription": "Gérer les identifiants des fournisseurs d'API pour les agents.", + "filterAll": "Tous", + "providerListTitle": "Fournisseurs Configurés", + "addProvider": "Ajouter un Fournisseur", + "editProvider": "Modifier le Fournisseur", + "noProviders": "Aucun fournisseur de modèle configuré.", + "providerName": "Nom", + "providerNamePlaceholder": "Ex. OpenAI, Anthropic", + "apiUrl": "URL de l'API", + "apiUrlPlaceholder": "https://api.openai.com/v1", + "apiKey": "Clé API", + "apiKeyPlaceholder": "sk-...", + "apiKeyKeepCurrent": "Laisser vide pour conserver l'actuelle", + "agentTypes": "Types d'Agent", + "agentTypesRequired": "Au moins un type d'agent est requis.", + "agentType": "Type d'Agent", + "agentTypeRequired": "Le type d'agent est requis.", + "agentTypeImmutableHint": "Le type d'agent ne peut pas être modifié après la création.", + "model": "Modèle", + "modelPlaceholderCodex": "gpt-5.6-sol / gpt-5.5", + "modelPlaceholderGemini": "gemini-3-pro-preview", + "claudeMainModel": "Modèle Principal", + "claudeReasoningModel": "Modèle de Raisonnement (réflexion)", + "claudeHaikuDefaultModel": "Modèle Haiku par Défaut", + "claudeSonnetDefaultModel": "Modèle Sonnet par Défaut", + "claudeOpusDefaultModel": "Modèle Opus par Défaut", + "claudeCustomModelOption": "ID de modèle personnalisé", + "claudeCustomModelOptionName": "Nom du modèle personnalisé", + "claudeCustomModelOptionDescription": "Description du modèle personnalisé", + "claudeCustomModelOptionHint": "Ajoute une entrée personnalisée au sélecteur de modèles de Claude (par exemple un modèle derrière une passerelle/un proxy personnalisé). Le nom et la description sont des informations d'affichage facultatives.", + "nameRequired": "Le nom du fournisseur est requis.", + "apiUrlRequired": "L'URL de l'API est requise.", + "apiKeyRequired": "La clé API est requise.", + "loadFailed": "Échec du chargement des fournisseurs.", + "saveFailed": "Échec de la sauvegarde.", + "createSuccess": "Fournisseur créé.", + "editSuccess": "Fournisseur mis à jour.", + "deleteSuccess": "Fournisseur supprimé.", + "deleteConfirmTitle": "Supprimer le Fournisseur", + "deleteConfirmMessage": "Le fournisseur \"{name}\" sera définitivement supprimé. Êtes-vous sûr ?", + "deleteBlockedByAgent": "{agents} utilise ce fournisseur. Veuillez le dissocier avant de supprimer.", + "cancel": "Annuler", + "delete": "Supprimer", + "create": "Créer", + "save": "Enregistrer", + "affectedRunningSessions": "{count, plural, one {# session active doit se reconnecter pour appliquer la modification} other {# sessions actives doivent se reconnecter pour appliquer la modification}}" + }, + "SkillMatrix": { + "loading": "Chargement…", + "searchPlaceholder": "Rechercher par nom, id ou description", + "empty": "Rien à afficher.", + "emptySearch": "Aucun résultat pour la recherche actuelle.", + "skillColumn": "Compétence", + "selectAll": "Tout sélectionner (visible)", + "selectSkill": "Sélectionner {name}", + "everything": { + "label": "En masse", + "enable": "Tout activer (visible)", + "disable": "Tout désactiver (visible)" + }, + "columnMenu": { + "enableAll": "Activer toutes les compétences", + "disableAll": "Désactiver toutes les compétences" + }, + "rowMenu": { + "label": "Actions groupées pour {name}", + "enableAll": "Activer pour tous les agents", + "disableAll": "Désactiver pour tous les agents" + }, + "bulk": { + "selected": "{count} sélectionné(s)", + "targetAll": "Tous les agents", + "targetSome": "{count} agents", + "enable": "Activer", + "disable": "Désactiver", + "clear": "Effacer" + }, + "confirm": { + "disableTitle": "Désactiver ces liens ?", + "disableBody": "Cela supprimera {count} liens de compétences gérés par codeg. Les compétences occupant un répertoire personnalisé ne sont pas touchées. Vous pouvez les réactiver à tout moment.", + "cancel": "Annuler", + "confirm": "Désactiver" + }, + "toasts": { + "loadFailed": "Échec du chargement des états des compétences", + "applyFailed": "Échec de l'application des modifications", + "enabled": "{count} liens activés", + "disabled": "{count} liens désactivés", + "enabledPartial": "{ok} activés, {failed} échoués", + "disabledPartial": "{ok} désactivés, {failed} échoués" + }, + "detail": { + "enableForAgents": "Activer pour les agents", + "preview": "Aperçu de SKILL.md", + "loadingContent": "Chargement du contenu…" + }, + "copyModeHint": "Copié (non lié) — réactivez après les mises à jour pour obtenir la dernière version" + }, + "ExpertsSettings": { + "title": "Compétences d'experts", + "description": "Activez des workflows de compétences soigneusement sélectionnés et éprouvés pour vos agents de codage IA. Chaque expert est une compétence autonome du projet superpowers — codeg gère la copie centrale et la lie aux agents que vous choisissez.", + "loading": "Chargement des experts…", + "loadingContent": "Chargement du contenu…", + "emptyExperts": "Aucun expert disponible. Vérifiez les journaux de l'application.", + "emptySelection": "Sélectionnez un expert pour voir son contenu et gérer son activation.", + "emptySearch": "Aucun expert ne correspond à la recherche actuelle.", + "searchPlaceholder": "Rechercher des experts par nom, ID ou description", + "enableForAgents": "Activer pour les agents", + "noAgents": "Aucun agent ACP détecté.", + "copyModeWarning": "Copié (non lié). Réactivez après les mises à jour de codeg pour obtenir la dernière version.", + "previewTitle": "Aperçu de SKILL.md", + "categories": { + "discovery": "Découverte et conception", + "planning": "Planification", + "execution": "Exécution", + "quality": "Qualité et tests", + "debugging": "Débogage", + "review": "Révision et intégration", + "meta": "Méta" + }, + "states": { + "not_linked": "Non activé", + "linked_to_codeg": "Activé", + "linked_elsewhere": "Bloqué — un autre lien existe", + "blocked_by_real_directory": "Bloqué — une compétence personnalisée occupe ce nom", + "broken": "Lien cassé" + }, + "badges": { + "userModified": "Modifié par l'utilisateur" + }, + "actions": { + "openCentralDir": "Ouvrir le dossier central", + "refresh": "Actualiser" + }, + "toasts": { + "loadFailed": "Échec du chargement des détails de l'expert", + "enabled": "Expert activé pour cet agent", + "disabled": "Expert désactivé pour cet agent", + "enableFailed": "Échec de l'activation de l'expert", + "disableFailed": "Échec de la désactivation de l'expert", + "openFolderFailed": "Échec de l'ouverture du dossier" + } + }, + "ScienceSettings": { + "title": "Compétences de recherche scientifique", + "description": "Activez des compétences de recherche scientifique sélectionnées pour vos agents de codage IA : génération d'hypothèses, plan d'expérience, statistiques, visualisation, évaluation critique et recherche bibliographique. codeg gère une copie centrale et relie chaque compétence aux agents que vous choisissez.", + "loading": "Chargement des compétences scientifiques…", + "emptySkills": "Aucune compétence scientifique disponible. Consultez les journaux de l'application.", + "searchPlaceholder": "Rechercher des compétences scientifiques par nom, id ou description", + "categories": { + "ideation": "Idéation", + "design": "Plan d'étude", + "analysis": "Analyse", + "visualization": "Visualisation", + "evaluation": "Évaluation", + "literature": "Littérature" + }, + "states": { + "not_linked": "Non activé", + "linked_to_codeg": "Activé", + "linked_elsewhere": "Bloqué — un autre lien existe", + "blocked_by_real_directory": "Bloqué — une compétence personnalisée occupe ce nom", + "broken": "Lien cassé" + }, + "badges": { + "userModified": "Modifié par l'utilisateur", + "needsKey": "Clé API requise", + "needsSetup": "Configuration possible" + }, + "actions": { + "openCentralDir": "Ouvrir le dossier central", + "refresh": "Actualiser" + }, + "toasts": { + "openFolderFailed": "Échec de l'ouverture du dossier" + } + }, + "OfficeToolsSettings": { + "title": "Outils Office", + "description": "Gérez les compétences OfficeCLI pour créer des fichiers Excel, Word et PowerPoint. Installez OfficeCLI, synchronisez les compétences et activez-les par agent.", + "loadingContent": "Chargement du contenu…", + "emptySkills": "Aucune compétence disponible. Installez OfficeCLI et synchronisez les compétences.", + "emptySelection": "Sélectionnez une compétence pour voir son contenu et gérer l'activation.", + "emptySearch": "Aucune compétence correspondante.", + "searchPlaceholder": "Rechercher par nom, ID ou description", + "enableForAgents": "Activer pour les agents", + "noAgents": "Aucun agent ACP détecté.", + "installFirst": "Installez d'abord OfficeCLI pour activer les compétences.", + "syncFirst": "Synchronisez d'abord les compétences pour charger le contenu.", + "noContent": "Aucun contenu disponible.", + "copyModeWarning": "Copié (non lié). Resynchronisez pour obtenir la dernière version.", + "previewTitle": "Aperçu SKILL.md", + "detection": { + "installed": "Installé", + "notInstalled": "Non installé", + "notRunnable": "Installé mais non exécutable", + "installHint": "Installez OfficeCLI pour activer les compétences de génération de documents Office pour vos agents IA.", + "install": "Installer", + "uninstall": "Désinstaller", + "syncSkills": "Synchroniser les compétences" + }, + "categories": { + "general": "Général", + "presentations": "Présentations", + "documents": "Documents", + "spreadsheets": "Tableurs" + }, + "states": { + "not_linked": "Non activé", + "linked_to_codeg": "Activé", + "linked_elsewhere": "Bloqué — un autre lien existe", + "blocked_by_real_directory": "Bloqué — une compétence personnalisée occupe ce nom", + "broken": "Lien cassé" + }, + "badges": { + "notSynced": "Non synchronisé" + }, + "actions": { + "refresh": "Actualiser" + }, + "toasts": { + "loadFailed": "Échec du chargement des détails de la compétence", + "enabled": "Compétence activée pour cet agent", + "disabled": "Compétence désactivée pour cet agent", + "enableFailed": "Échec de l'activation de la compétence", + "disableFailed": "Échec de la désactivation de la compétence", + "installSuccess": "OfficeCLI installé avec succès", + "installFailed": "Échec de l'installation d'OfficeCLI", + "uninstallSuccess": "OfficeCLI désinstallé", + "uninstallFailed": "Échec de la désinstallation d'OfficeCLI", + "syncSuccess": "{synced} compétences synchronisées", + "syncPartial": "{synced} synchronisées, {errors} échouées", + "syncFailed": "Échec de la synchronisation des compétences" + }, + "autoPreviewLabel": "Ouvrir l'aperçu automatiquement", + "autoPreviewHint": "Lorsqu'un agent crée ou modifie un fichier Word, Excel ou PowerPoint, ouvrir automatiquement son aperçu en direct." + }, + "SkillPacksSettings": { + "title": "Packs de compétences", + "description": "Ensembles de compétences sélectionnés que codeg gère de manière centralisée et relie à vos agents IA : experts en programmation, recherche scientifique et outils de documents bureautiques. Activez-les par agent ci-dessous.", + "tabs": { + "experts": "Experts", + "science": "Science", + "office": "Outils bureautiques", + "custom": "Personnalisées" + }, + "actions": { + "openCentralDir": "Ouvrir le dossier central", + "refresh": "Actualiser" + }, + "toasts": { + "openFolderFailed": "Échec de l'ouverture du dossier" + } + }, + "QuickMessagesSettings": { + "title": "Messages rapides", + "description": "Gérez des extraits de messages réutilisables. Glissez pour réorganiser.", + "loading": "Chargement des messages rapides…", + "emptyList": "Aucun message rapide. Cliquez sur « Nouveau » pour en créer un.", + "emptySelection": "Sélectionnez un message rapide à modifier.", + "searchPlaceholder": "Rechercher par titre ou contenu", + "untitled": "Sans titre", + "actions": { + "new": "Nouveau", + "save": "Enregistrer", + "delete": "Supprimer", + "dragSort": "Glisser pour réorganiser", + "dragSortMessage": "Réorganiser le message rapide : {name}" + }, + "fields": { + "title": "Titre", + "titlePlaceholder": "Donnez un titre court à ce message", + "content": "Contenu", + "contentPlaceholder": "Saisissez ici le contenu du message" + }, + "confirmDelete": { + "title": "Supprimer le message rapide ?", + "message": "Cela supprimera définitivement « {name} ». Êtes-vous sûr ?", + "cancel": "Annuler", + "confirm": "Supprimer" + }, + "toasts": { + "loadFailed": "Échec du chargement des messages rapides", + "createFailed": "Échec de la création du message rapide", + "saveFailed": "Échec de l'enregistrement du message rapide", + "deleteFailed": "Échec de la suppression du message rapide", + "saveOrderFailed": "Échec de l'enregistrement de l'ordre", + "created": "Message rapide créé", + "saved": "Message rapide enregistré", + "deleted": "Message rapide supprimé" + } + }, + "Pet": { + "badge": { + "running": "{count} en cours", + "waiting": "{count} en attente d'approbation", + "error": "{count} en erreur" + }, + "panel": { + "title": "Sessions actives", + "empty": "Aucune session active", + "emptyHint": "Les agents en cours et ceux qui vous attendent apparaissent ici.", + "statusRunning": "En cours", + "statusWaiting": "En attente", + "statusError": "Erreur", + "subAgentOf": "Sous-agent de" + }, + "menu": { + "scale": "Échelle", + "openManager": "Gérer les mascottes", + "close": "Fermer" + }, + "loadError": "Échec du chargement de la mascotte", + "missingPetIdParam": "Aucune mascotte sélectionnée", + "summonButton": "Mascotte", + "manager": { + "title": "Mascottes", + "description": "Compagnons flottants de bureau avec des sprites compatibles Codex.", + "addPet": "Ajouter une mascotte", + "importFromCodex": "Importer depuis Codex", + "noPets": "Aucune mascotte. Ajoutez-en ou importez depuis Codex.", + "setActive": "Activer", + "active": "Active", + "edit": "Modifier", + "delete": "Supprimer", + "deleteConfirm": "Supprimer la mascotte « {name} » ? Elle sera retirée du disque.", + "summon": "Invoquer la fenêtre de la mascotte", + "openCodexHelp": "Les mascottes Codex doivent être dans ~/.codex/pets/. Aucune trouvée.", + "specRequirement": "Le sprite doit faire 1536px de large avec une hauteur multiple de 208px (par ex. 1872 ou 2288), en PNG/WebP avec transparence.", + "form": { + "id": "ID mascotte", + "idHelp": "Lettres minuscules, chiffres, '-' et '_'. Max 64 caractères.", + "displayName": "Nom affiché", + "description": "Description (facultative)", + "spritesheet": "Sprite", + "chooseFile": "Choisir un fichier", + "replaceFile": "Remplacer le sprite", + "saveCreate": "Ajouter la mascotte", + "saveUpdate": "Enregistrer", + "cancel": "Annuler" + }, + "errors": { + "missingId": "ID requis", + "missingName": "Nom requis", + "missingSpritesheet": "Sprite requis", + "addFailed": "Ajout impossible", + "updateFailed": "Mise à jour impossible", + "deleteFailed": "Suppression impossible", + "loadFailed": "Chargement impossible", + "setActiveFailed": "Activation impossible", + "summonFailed": "Ouverture de la fenêtre impossible" + } + }, + "import": { + "title": "Importer depuis Codex", + "subtitle": "Mascottes disponibles sous ~/.codex/pets/.", + "selectAll": "Tout sélectionner", + "alreadyImported": "Déjà importée", + "renameOnConflict": "Renommer en -imported en cas de conflit", + "import": "Importer la sélection", + "noneFound": "Aucune mascotte Codex importable.", + "imported": "Import réussi", + "failed": "Import échoué", + "close": "Fermer" + }, + "marketplace": { + "openMarketplace": "Marketplace de mascottes", + "title": "Marketplace de mascottes", + "search": "Rechercher des mascottes", + "kindFilter": { + "all": "Toutes", + "object": "Objet", + "animal": "Animal", + "person": "Personne", + "creature": "Créature" + }, + "sortFilter": { + "latest": "Récents", + "popular": "Populaires", + "views": "Vues" + }, + "refresh": "Actualiser", + "install": "Installer", + "installing": "Installation", + "reinstall": "Réinstaller", + "reinstallConfirm": "Remplacer la mascotte locale « {name} » ? Les données existantes seront écrasées.", + "cancel": "Annuler", + "stats": { + "views": "Vues", + "downloads": "Téléchargements", + "likes": "J’aime" + }, + "actions": { + "idle": "Repos", + "running_right": "Course dr.", + "running_left": "Course g.", + "waving": "Salut", + "jumping": "Saut", + "failed": "Échec", + "waiting": "Attente", + "running": "Course", + "review": "Revue" + }, + "page": "Page {page} sur {total}", + "prev": "Précédent", + "next": "Suivant", + "empty": "Aucune mascotte ne correspond.", + "successInstalled": "« {name} » installée", + "errors": { + "loadFailed": "Impossible de charger le marketplace", + "installFailed": "Échec de l’installation", + "alreadyInstalled": "La mascotte existe déjà localement" + } + } + }, + "RemoteWorkspace": { + "openRemoteWorkspace": "Ouvrir l’espace de travail distant", + "manage": "Gérer l’espace de travail distant", + "manageTitle": "Connexions à l’espace de travail distant", + "empty": "Aucune connexion distante", + "searchPlaceholder": "Rechercher un espace de travail distant", + "orderFailed": "Échec de l’enregistrement de l’ordre des espaces de travail distants", + "dragSort": "Glisser pour trier", + "dragSortConnection": "Glisser pour trier {name}", + "newConnection": "Nouvelle connexion", + "loading": "Chargement", + "loadingConnection": "Chargement de la connexion distante", + "name": "Nom", + "baseUrl": "URL du service", + "token": "Jeton d’accès", + "save": "Enregistrer", + "delete": "Supprimer", + "confirmDelete": { + "title": "Supprimer la connexion distante ?", + "message": "Cela retirera « {name} » de cet appareil. Cette action est irréversible.", + "cancel": "Annuler", + "confirm": "Supprimer" + }, + "saved": "Connexion distante enregistrée.", + "deleted": "Connexion distante supprimée.", + "loadFailed": "Échec du chargement des connexions distantes", + "saveFailed": "Échec de l’enregistrement de la connexion distante", + "deleteFailed": "Échec de la suppression de la connexion distante", + "openFailed": "Échec de l’ouverture de l’espace de travail distant", + "connectionLoadFailed": "Échec du chargement de la connexion distante : {message}", + "connectionExpired": "La connexion distante « {name} » a expiré. Mettez son jeton à jour, puis rechargez cette fenêtre." + }, + "ServerFileBrowser": { + "title": "Sélectionner un fichier serveur", + "pathPlaceholder": "Saisir le chemin du dossier...", + "goHome": "Aller au dossier personnel", + "navigateUp": "Aller au dossier parent", + "select": "Sélectionner", + "cancel": "Annuler", + "loading": "Chargement...", + "emptyDirectory": "Ce dossier est vide", + "errorLoadingDir": "Échec du chargement du dossier", + "selectedCount": "{count} sélectionné(s)" + }, + "BackupSettings": { + "title": "Sauvegarde et restauration", + "description": "Exportez une sauvegarde portable de vos données codeg, ou restaurez à partir d'une sauvegarde.", + "tabs": { + "backup": "Sauvegarde", + "restore": "Restauration" + }, + "export": { + "includeExternal": "Inclure le contenu des conversations", + "includeExternalHint": "Archive aussi les transcriptions des CLI (Claude, Codex, Gemini, …). Augmente la taille.", + "passphrase": "Phrase secrète (facultatif)", + "passphrasePlaceholder": "Laissez vide pour une archive non chiffrée", + "passphraseConfirm": "Confirmer la phrase secrète", + "passphraseMismatch": "Les phrases secrètes ne correspondent pas.", + "noPassphraseWarning": "Cette sauvegarde contiendra des secrets (clés d'API, jetons) en clair. Conservez-la en lieu sûr.", + "passphraseLossWarning": "Chiffrée avec cette phrase secrète. Si vous la perdez, la sauvegarde ne pourra pas être récupérée.", + "button": "Exporter la sauvegarde", + "inProgress": "Création de la sauvegarde…", + "success": "Sauvegarde créée.", + "started": "Téléchargement de la sauvegarde lancé." + }, + "restore": { + "selectFile": "Sélectionner le fichier de sauvegarde", + "passphrasePrompt": "Cette sauvegarde est chiffrée. Saisissez sa phrase secrète.", + "unlock": "Déverrouiller", + "preview": { + "title": "Détails de la sauvegarde", + "encrypted": "Chiffrée", + "compatible": "Compatible", + "incompatible": "Incompatible", + "createdAt": "Créée : {value}", + "appVersion": "Version de l'app : {value}", + "incompatibleHint": "Cette sauvegarde a été créée par une version plus récente de codeg et ne peut pas être restaurée." + }, + "replaceWarning": "La restauration remplace toutes les données codeg actuelles (base de données et téléversements). Vos données actuelles sont d'abord sauvegardées en instantané pour pouvoir être récupérées.", + "keyringNote": "Les jetons GitHub/chat du bureau sont dans le trousseau du système et ne sont pas inclus ; ressaisissez-les après la restauration.", + "button": "Restaurer", + "staging": "Préparation de la restauration…", + "staged": "Restauration préparée. Redémarrage…", + "restarting": "Restauration préparée. Redémarrage du serveur…", + "restartTimeout": "Le serveur n'est pas revenu à temps. Rechargez la page une fois qu'il est actif.", + "externalSideLocation": "Les transcriptions de conversations ont été restaurées dans {path}", + "confirmTitle": "Remplacer toutes les données ?", + "confirmBody": "Cela remplacera votre base de données et vos téléversements codeg actuels par la sauvegarde, puis redémarrera. Vos données actuelles sont d'abord sauvegardées en instantané.", + "cancel": "Annuler", + "confirmAction": "Remplacer et redémarrer", + "external": { + "title": "Contenu des conversations", + "hint": "Cette sauvegarde inclut des transcriptions des CLI. Choisissez où les restaurer.", + "modeSkip": "Ne pas restaurer", + "modeSide": "Restaurer dans un dossier annexe sûr", + "modeOriginal": "Restaurer aux emplacements d'origine des CLI", + "forceOverwrite": "Écraser les fichiers existants", + "forceOverwriteHint": "Remplace les fichiers déjà présents dans les dossiers des CLI.", + "scanning": "Vérification des conflits…", + "noConflicts": "Aucun fichier existant ne sera écrasé.", + "conflictCount": "{count} fichier(s) existant(s) seraient concerné(s).", + "conflictSkipNote": "Les fichiers existants sont conservés (ignorés) sauf si vous activez l'écrasement." + }, + "restartFailed": "Restauration préparée, mais le serveur n'a pas pu redémarrer. Redémarrez-le manuellement pour l'appliquer." + }, + "remoteUnsupported": "La sauvegarde et la restauration agissent sur les données de la machine qui exécute codeg. Vous êtes connecté à un espace de travail distant : gérez ses sauvegardes directement depuis ce serveur." + }, + "backup": { + "restore": { + "error": { + "badPassphrase": "Phrase secrète incorrecte ou sauvegarde corrompue.", + "corrupted": "L'archive de sauvegarde est corrompue.", + "unknownFormat": "Ce fichier n'est pas une sauvegarde codeg reconnue.", + "newerVersion": "Cette sauvegarde a été créée par codeg {backupVersion}, plus récent que cette version ({appVersion}).", + "alreadyPending": "Une restauration est déjà préparée. Redémarrez pour l'appliquer avant d'en préparer une autre." + } + }, + "error": { + "diskSpace": "Espace disque insuffisant pour terminer l'opération.", + "cancelled": "L'opération a été annulée." + } + }, + "WebConnection": { + "disconnectedTitle": "Connexion perdue", + "reconnectingDescription": "Tentative de reconnexion au serveur. Cela se rétablit généralement tout seul en quelques secondes.", + "reconnectNow": "Se reconnecter maintenant", + "sessionExpiredTitle": "Session expirée", + "sessionExpiredDescription": "Votre session n'est plus valide. Veuillez vous reconnecter pour continuer.", + "goToLogin": "Aller à la connexion" + }, + "LiveFeedback": { + "placeholder": "Envoyez une note à {agent} pendant qu'il travaille…", + "agentFallback": "l'agent", + "ariaLabel": "Note de retour en direct", + "dialogTitle": "Retour en direct", + "dialogDescription": "Envoyez une note à l'agent pendant qu'il travaille. Il la lira lors de sa prochaine vérification, sans interrompre l'étape en cours.", + "dialogDescriptionInstant": "Envoyez une note à l'agent pendant qu'il travaille. Elle est insérée immédiatement dans le tour en cours — l'agent la voit aussitôt.", + "channelDowngraded": "L'insertion instantanée n'est pas disponible dans cette session — votre note a été enregistrée et sera récupérée au prochain contrôle de l'agent.", + "send": "Envoyer", + "cancel": "Annuler", + "pending": "en attente", + "delivered": "reçue", + "turnEndedUnread": "L'agent a terminé avant de lire votre retour.", + "sendAsMessage": "Envoyer comme message", + "dismiss": "Ignorer", + "turnEndedResent": "Le tour est terminé : envoyé comme nouveau message.", + "turnEnded": "Le tour est déjà terminé.", + "submitFailed": "Impossible d'envoyer votre note" + }, + "AgentToolsSettings": { + "title": "Outils dans la conversation", + "description": "Outils supplémentaires que codeg fournit à un agent au sein d'une conversation. Ils sont injectés au démarrage de l'agent : une modification s'applique donc aux agents démarrés ensuite.", + "feedbackLabel": "Retour en direct", + "feedbackHint": "Envoyez des notes et corrections à un agent pendant qu'il travaille. Si l'agent prend en charge l'insertion instantanée, votre note est insérée immédiatement dans le tour en cours ; sinon, l'agent reçoit un outil pour consulter vos retours — ces agents ne le consultent généralement que si vous le mentionnez dans votre prompt, par exemple ajoutez « vérifie régulièrement mon feedback en direct » à votre message.", + "questionLabel": "Poser une question à l'utilisateur", + "questionHint": "Permet aux agents de s'interrompre et de vous poser une question à choix multiples affichée au-dessus de la zone de saisie de la conversation. L'agent attend votre réponse (ou que vous ignoriez).", + "sessionInfoLabel": "Obtenir les infos de session", + "sessionInfoHint": "Permet aux agents de consulter une session que vous mentionnez dans votre message (un badge de session) pour lire son titre, son agent, son statut, son espace de travail, sa consommation de jetons et ses messages récents.", + "automationsLabel": "Créer des automatisations", + "automationsHint": "Enregistre la conversation comme une automatisation qui s'exécute selon un planning. Désactivé par défaut : elle démarre ensuite des agents d'elle-même.", + "workTasksLabel": "Créer des tâches à faire", + "workTasksHint": "Ajoute une carte au tableau des tâches depuis la conversation. Désactivé par défaut : écrit l'état de l'application.", + "save": "Enregistrer", + "saving": "Enregistrement…", + "saved": "Paramètres des outils enregistrés", + "saveFailed": "Échec de l'enregistrement des paramètres des outils", + "loadFailed": "Échec du chargement : {detail}" + }, + "NotificationSoundSettings": { + "title": "Sons de notification", + "description": "Joue un son bref lorsqu’un événement d’agent se produit. Ce sont les mêmes événements que ceux envoyés aux canaux de discussion ; ce réglage ne s’applique qu’à cet appareil.", + "enableHint": "Désactivé par défaut. Les sons ne sont joués que dans la fenêtre de l’espace de travail de ce navigateur ou de cette application.", + "volume": "Volume", + "preview": "Écouter", + "previewEvent": "Écouter le son de {event}", + "onlyWhenUnfocused": "Uniquement lorsque la fenêtre n’est pas au premier plan", + "onlyWhenUnfocusedHint": "Reste silencieux tant que Codeg est affiché.", + "eventsTitle": "Événements", + "eventsHint": "Choisissez un son par événement, ou « Silencieux » pour l’ignorer. Si le même événement se répète en quelques secondes, il ne sonne qu’une fois.", + "toneNone": "Silencieux", + "toneChime": "Carillon", + "toneDing": "Clochette", + "toneBlip": "Bip", + "tonePop": "Pop", + "toneAlert": "Alerte", + "toneDescend": "Descendant" + }, + "LogsSettings": { + "loading": "Chargement…", + "sectionTitle": "Journaux d'exécution", + "sectionDescription": "Consultez et configurez les journaux de diagnostic de l'application. Les journaux sont écrits dans des fichiers locaux et conservés en mémoire pour l'affichage en direct.", + "captureTitle": "Niveau de journalisation", + "captureDescription": "Contrôle le niveau de détail capturé. Les niveaux plus élevés (Debug, Trace) enregistrent davantage mais produisent des journaux plus volumineux. « Désactivé » désactive la journalisation.", + "captureLabel": "Niveau de capture", + "levels": { + "off": "Désactivé", + "error": "Erreur", + "warn": "Avertissement", + "info": "Info", + "debug": "Débogage", + "trace": "Trace" + }, + "viewerTitle": "Journaux récents", + "viewerDescription": "Affichage en direct des journaux récents. Filtrez par niveau ou recherchez du texte.", + "searchPlaceholder": "Rechercher un message ou une cible…", + "viewLevels": { + "all": "Tous les niveaux", + "error": "Erreur et plus", + "warn": "Avertissement et plus", + "info": "Info et plus", + "debug": "Débogage et plus", + "trace": "Trace et plus" + }, + "pause": "Pause", + "resume": "Direct", + "refresh": "Actualiser", + "clear": "Effacer", + "openFolder": "Ouvrir le dossier", + "shownCount": "{shown} / {total} affichés", + "empty": "Aucun journal à afficher.", + "levelSaveFailed": "Échec de l'enregistrement du niveau de journalisation", + "openFolderFailed": "Échec de l'ouverture du dossier des journaux", + "downloadFailed": "Échec du téléchargement du fichier journal", + "filesTitle": "Fichiers journaux", + "filesDescription": "Téléchargez les fichiers journaux complets depuis le disque pour l'historique au-delà du tampon en direct.", + "filesEmpty": "Aucun fichier journal pour l'instant.", + "download": "Télécharger", + "downloadTruncated": "Le fichier est volumineux ; les {size} les plus récents ont été téléchargés. Le fichier complet se trouve dans le répertoire des journaux.", + "captureEnvLocked": "Le niveau de journalisation est contrôlé par la variable d'environnement RUST_LOG / CODEG_LOG ; modifiez-la là pour qu'elle prenne effet.", + "targetsTitle": "Remplacements par module", + "targetsDescription": "Définissez un niveau différent pour des modules spécifiques (p. ex. codeg_lib::acp) sans changer le niveau global.", + "targetsAdd": "Ajouter", + "targetsRemove": "Supprimer le remplacement", + "toggleDetails": "Afficher les détails" + }, + "Automations": { + "title": "Automatisations", + "new": "Nouvelle automatisation", + "empty": "Aucune automatisation pour l'instant", + "emptyHint": "Créez-en une pour exécuter une tâche d'agent planifiée ou à la demande.", + "name": "Nom", + "namePlaceholder": "ex. Revue de PR nocturne", + "prompt": "Instruction", + "promptPlaceholder": "Que doit faire l'agent ?", + "agent": "Agent", + "folder": "Dossier de l'espace de travail", + "folderPlaceholder": "Sélectionner un dossier", + "isolation": "Isolation", + "isolationWorktree": "Nouveau worktree par exécution", + "isolationShared": "Exécuter dans le dossier", + "isolationSharedCaveat": "Les exécutions utilisent directement l'arbre de travail de ce dossier et peuvent entrer en conflit avec vos modifications non validées. Activez l'option worktree pour isoler chaque exécution.", + "trigger": "Déclencheur", + "triggerSchedule": "Planifié", + "triggerManual": "Manuel uniquement", + "cron": "Planification (cron)", + "cronPlaceholder": "0 9 * * 1-5", + "timezone": "Fuseau horaire", + "nextRun": "Prochaine exécution", + "branch": "Branche", + "branchOptional": "Branche (facultatif)", + "enabled": "Activé", + "save": "Enregistrer", + "cancel": "Annuler", + "edit": "Modifier", + "delete": "Supprimer", + "runNow": "Exécuter maintenant", + "cancelRun": "Annuler l'exécution", + "runHistory": "Historique d'exécution", + "noRuns": "Aucune exécution pour l'instant", + "allFolders": "Tous les dossiers", + "filterAll": "Tous", + "noMatches": "Aucune automatisation correspondante", + "viewConversation": "Voir la conversation", + "lastRun": "Dernière exécution", + "never": "Jamais", + "running": "En cours", + "deleteTitle": "Supprimer l'automatisation ?", + "deleteDescription": "Cela supprime l'automatisation et sa planification. L'historique est conservé.", + "statusRunning": "En cours", + "statusSucceeded": "Réussie", + "statusFailed": "Échouée", + "statusCancelled": "Annulée", + "statusSkipped": "Ignorée", + "errorName": "Le nom est requis", + "errorPrompt": "L'instruction est requise", + "errorCron": "Les automatisations planifiées nécessitent une expression cron", + "errorFolder": "Sélectionnez un dossier d'espace de travail", + "presetHourly": "Toutes les heures", + "presetDaily": "Tous les jours 9 h", + "presetWeekdays": "En semaine 9 h", + "presetCustom": "Personnalisé", + "probing": "Chargement des options…", + "retry": "Réessayer", + "configNone": "Cet agent n'a aucune option configurable", + "inherit": "Par défaut de l'agent", + "mode": "Mode", + "config": "Configuration", + "branchPlaceholder": "(branche par défaut)", + "selectHint": "Sélectionnez une automatisation pour voir les détails", + "refresh": "Actualiser", + "onboardTitle": "Automatisez les tâches récurrentes de l'agent", + "onboardHint": "Planifiez un agent pour relire le code, mettre à jour les dépendances ou trier les problèmes, de façon périodique ou à la demande.", + "headerSubtitle": "Tâches d'agent planifiées et à la demande", + "startFromTemplate": "Partir d'un modèle", + "blankTitle": "Automatisation vierge", + "blankDesc": "Configurez une tâche d'agent à partir de zéro.", + "backToTemplates": "Modèles", + "sectionSchedule": "Planification et cible", + "sectionTarget": "Cible", + "sectionAction": "Action", + "actionLaunchSession": "Lancer une session", + "actionEnqueueTask": "Mettre une tâche en file", + "actionEnqueueTaskHint": "Chaque déclenchement ajoute une tâche à faire, nommée d'après cette automatisation, aux tâches à faire du dossier ; le moteur de tâches l'exécute selon les réglages du tableau.", + "sectionPrompt": "Instruction", + "nextIn": "Prochaine dans {rel}", + "manual": "Manuel", + "schedEveryMinutes": "Toutes les {n} minutes", + "schedHourly": "Toutes les heures", + "schedDaily": "Tous les jours à {time}", + "schedWeekdays": "En semaine à {time}", + "schedWeekly": "Chaque {day} à {time}", + "schedMonthly": "Le {day} de chaque mois à {time}", + "dow0": "dimanche", + "dow1": "lundi", + "dow2": "mardi", + "dow3": "mercredi", + "dow4": "jeudi", + "dow5": "vendredi", + "dow6": "samedi", + "tplCodeReviewTitle": "Revue de code", + "tplCodeReviewDesc": "Examine les modifications récentes à la recherche de bugs, de régressions et de problèmes de qualité.", + "tplDependencyUpdatesTitle": "Mise à jour des dépendances", + "tplDependencyUpdatesDesc": "Repère les dépendances obsolètes et propose des mises à niveau sûres.", + "tplTestCoverageTitle": "Couverture de tests", + "tplTestCoverageDesc": "Repère les chemins de code non testés et ajoute les tests manquants.", + "tplTodoSweepTitle": "Revue des TODO", + "tplTodoSweepDesc": "Rassemble les commentaires TODO et FIXME et les trie par priorité.", + "tplCiTriageTitle": "Tri CI", + "tplCiTriageDesc": "Enquête sur les vérifications récemment en échec et propose des correctifs.", + "tplReleaseNotesTitle": "Notes de version", + "tplReleaseNotesDesc": "Résume les changements depuis la dernière version dans un journal des modifications.", + "tplSecurityAuditTitle": "Audit de sécurité", + "tplSecurityAuditDesc": "Recherche les vulnérabilités et les schémas à risque, puis signale les constats.", + "enable": "Activer", + "disable": "Désactiver", + "moreActions": "Plus d'actions", + "statusDisabled": "Désactivée", + "cronBuilderTitle": "Générateur de planification", + "cronFreqLabel": "Fréquence", + "cronFreqMinutes": "Toutes les N minutes", + "cronFreqHourly": "Toutes les heures", + "cronFreqDaily": "Quotidien", + "cronFreqWeekdays": "Jours ouvrés", + "cronFreqWeekly": "Hebdomadaire", + "cronFreqMonthly": "Mensuel", + "cronFreqCustom": "Personnalisé", + "cronEveryLabel": "Intervalle (minutes)", + "cronTimeLabel": "Heure", + "cronHourLabel": "Heure", + "cronMinuteLabel": "Minute", + "cronDowLabel": "Jour de la semaine", + "cronDomLabel": "Jour du mois", + "cronApply": "Appliquer", + "cronPreviewLabel": "Aperçu", + "cronOpenBuilder": "Ouvrir le générateur de planification", + "branchDefault": "Branche par défaut", + "branchUseCustom": "Utiliser « {query} »", + "branchLocal": "Locale", + "branchRemote": "Distante", + "branchSearchPlaceholder": "Rechercher des branches…", + "branchNone": "Aucune branche" + }, + "Tasks": { + "title": "Tâches à faire", + "new": "Nouvelle tâche", + "empty": "Aucune tâche pour l’instant", + "emptyHint": "Ajoutez une tâche puis lancez-la : l’agent travaille dans un worktree isolé, vous relisez et fusionnez le résultat.", + "emptyColTodo": "Aucune tâche à faire pour l’instant", + "emptyColInProgress": "Rien en cours", + "emptyColAttention": "Rien à traiter", + "emptyColDone": "Rien de terminé pour l’instant", + "allFolders": "Tous les dossiers", + "showCanceled": "Afficher les annulées", + "showArchived": "Afficher les archivées", + "filter": "Filtrer", + "viewSwitchToBoard": "Passer à la vue tableau", + "viewSwitchToList": "Passer à la vue liste", + "statusFilter": "Statut", + "statusFilterAll": "Tous les statuts", + "listEmpty": "Aucune tâche ne correspond aux filtres actuels", + "listColStatus": "Statut", + "listColTask": "Tâche", + "listColLocation": "Emplacement", + "listColChanges": "Modifications", + "listColUpdated": "Mis à jour", + "colTodo": "À faire", + "colInProgress": "En cours", + "colAttention": "À traiter", + "colDone": "Terminées", + "statusTodo": "À faire", + "statusQueued": "En file", + "statusPreparing": "Préparation", + "statusRunning": "En cours", + "statusAwaitingInput": "En attente de saisie", + "statusReview": "À valider", + "statusMerging": "Fusion en cours", + "statusDone": "Terminée", + "statusFailed": "Échouée", + "statusCanceled": "Annulée", + "statusInterrupted": "Interrompue", + "badgeCleanupFailed": "Nettoyage échoué", + "badgeWorktreeKept": "Worktree conservé", + "badgeWorktreeRemoved": "Worktree supprimé", + "filesChanged": "{count} fichiers", + "actionStart": "Démarrer", + "actionSchedule": "Planifier", + "actionCancel": "Annuler", + "actionRetry": "Réessayer", + "actionRequeue": "Remettre en file", + "actionViewSession": "Voir la conversation", + "actionEdit": "Modifier", + "actionDelete": "Supprimer", + "actionRetryCleanup": "Réessayer le nettoyage", + "actionMerge": "Fusionner", + "actionUnqueueMerge": "Quitter la file de fusion", + "actionEditQueuedMerge": "Modifier la fusion en attente", + "badgeMergeQueued": "En attente de fusion", + "badgeMergeQueuedRank": "En attente de fusion · n° {rank}", + "badgeMergeQueuedHint": "En attente de la fin de la fusion en cours du projet ; celle-ci démarrera toute seule.", + "actionComplete": "Terminer", + "actionAbandon": "Abandonner", + "cancelTitle": "Annuler la tâche ?", + "cancelDescription": "La tâche passe à Annulée. Son worktree est conservé et vous pourrez la remettre en file plus tard.", + "cancelReasonLabel": "Raison (facultatif)", + "cancelReasonPlaceholder": "Ex. : mauvaise approche, je vais réécrire la description", + "cancelKeep": "Finalement non", + "cancelSubmit": "Annuler la tâche", + "restartTitleRetry": "Réessayer la tâche", + "restartTitleRequeue": "Remettre la tâche en file", + "restartDescription": "Vous pouvez ajouter une note (facultatif) : elle arrive dans le prompt de la prochaine exécution.", + "scheduleTitle": "Planifier la tâche", + "scheduleDescription": "La tâche reste dans À faire et démarre d'elle-même à l'heure choisie. La limite de concurrence du dossier s'applique toujours.", + "scheduleDateLabel": "Date", + "schedulePickDate": "Choisir une date", + "scheduleTimeLabel": "Heure", + "schedulePreview": "S'exécute le {time}", + "schedulePastHint": "Cette heure est déjà passée : la tâche démarrera dès l'enregistrement.", + "scheduleInAnHour": "Dans 1 heure", + "scheduleInThreeHours": "Dans 3 heures", + "scheduleTomorrow": "Demain 9:00", + "scheduleClear": "Annuler la planification", + "scheduleBadge": "Démarrage prévu le {time}", + "toastScheduled": "Planifiée pour le {time}", + "toastScheduleCleared": "Planification annulée", + "actionFollowUp": "Poursuivre", + "actionAddNote": "Ajouter une note", + "followUpSubmit": "Envoyer", + "followUpIntentRevise": "Corriger", + "followUpIntentContinue": "Continuer", + "followUpIntentQuestion": "Demander", + "followUpIntentVerify": "Vérifier", + "followUpPlaceholderRevise": "Que doit changer l'agent ? Il poursuit dans la même session.", + "followUpPlaceholderContinue": "Et ensuite ? Le travail déjà fait reste en place.", + "followUpPlaceholderQuestion": "Que voulez-vous savoir ? L'agent répond sans toucher aux fichiers.", + "followUpPlaceholderVerify": "Facultatif : quelque chose à examiner de près ?", + "followUpPlaceholderRetry": "Facultatif : que faire différemment ? Ex. : lancer pnpm install d'abord", + "followUpPlaceholderRequeue": "Facultatif : pourquoi l'avoir annulée, et qu'est-ce qui doit changer ?", + "actionArchive": "Archiver", + "actionUnarchive": "Désarchiver", + "archiveAllDone": "Tout archiver", + "dropToStart": "Relâchez pour lancer", + "errorView": "Voir", + "notifyReview": "Prêt pour révision : {title}", + "notifyFailed": "La tâche a échoué : {title}", + "createFromMessage": "Créer une tâche depuis le message", + "detailTokens": "Total de tokens", + "editorTitleNew": "Nouvelle tâche", + "editorTitleEdit": "Modifier la tâche", + "templates": "Modèles", + "templatesEmpty": "Aucun modèle pour l'instant.", + "templateSaveCurrent": "Enregistrer comme modèle", + "templateDelete": "Supprimer le modèle", + "transcriptTitle": "Conversation de la tâche", + "transcriptDescription": "Vue en direct, en lecture seule, de la session de l'agent de la tâche.", + "phaseWork": "Exécution", + "phaseRetry": "Nouvel essai", + "phaseReturn": "Relance", + "phaseMerge": "Fusion", + "titleLabel": "Titre", + "titlePlaceholder": "Que faut-il faire ?", + "promptLabel": "Description de la tâche", + "promptPlaceholder": "Décrivez la tâche pour l’agent — @ pour référencer des fichiers, / pour les commandes", + "folderPlaceholder": "Choisir un dossier", + "agentInheritedHint": "Hérité des réglages des tâches — modifiez-le pour personnaliser cette tâche", + "agentOverrideReset": "Revenir à l'héritage", + "sectionTarget": "Cible", + "errorTitle": "Le titre est requis", + "errorPrompt": "La description est requise", + "errorFolder": "Choisissez un dossier", + "save": "Enregistrer", + "cancel": "Annuler", + "mergeTitle": "Fusionner la tâche", + "mergeQueuedTitle": "Fusion en attente", + "mergeQueueHint": "Une autre tâche de ce projet est en cours de fusion. Celle-ci rejoint la file et démarrera d'elle-même dès que l'autre sera terminée.", + "mergeQueueUpdateHint": "Cette tâche attend déjà de fusionner. L'envoi la met à jour et conserve sa place dans la file.", + "mergeDescription": "Fusionner {branch} dans {base}. Les changements non commités du worktree sont d’abord commités.", + "mergeMessage": "Message de commit", + "mergeMessagePlaceholder": "ex. feat: add login validation", + "mergeAutoMessage": "Laisser l'agent rédiger le message de commit", + "strategySquash": "Regrouper en un seul commit", + "strategySquashHint": "Toutes les modifications de la tâche arrivent dans la branche principale comme une seule entrée d'historique — un historique plus net.", + "strategyMerge": "Conserver tout l'historique", + "strategyMergeHint": "Chaque commit réalisé pendant la tâche est conservé, plus une entrée de fusion — chaque étape reste traçable.", + "mergeDeleteWorktree": "Supprimer le worktree après la fusion", + "mergeSubmit": "Fusionner", + "mergeSubmitQueue": "Ajouter à la file", + "mergeQueuedToast": "Ajoutée à la file de fusion — elle démarrera dès la fin de la fusion en cours.", + "completeTitle": "Terminer la tâche", + "completeDescription": "Cette tâche n'a modifié aucun fichier : il n'y a rien à fusionner, elle est marquée comme terminée directement.", + "completeDescriptionNoWorktree": "Le worktree de cette tâche a été supprimé : plus rien ne peut être fusionné, elle est marquée comme terminée directement. Une branche de travail contenant encore des commits non fusionnés est conservée.", + "completeDeleteWorktree": "Supprimer le worktree après avoir terminé", + "completeSubmit": "Terminer", + "settingsTitle": "Réglages des tâches", + "settingsDescription": "Valeurs par défaut des tâches de {folder}.", + "settingsScope": "Portée", + "settingsScopeGlobal": "Tous les dossiers (valeurs globales)", + "settingsScopeGlobalHint": "Les dossiers sans réglages propres utilisent ces valeurs globales.", + "settingsSource": "Source de configuration", + "settingsSourceGlobal": "Valeurs globales", + "settingsSourceCustom": "Personnalisée", + "settingsSourceGlobalFollow": "Suit les réglages globaux des tâches — les changements globaux s'appliquent ici automatiquement.", + "settingsSourceCustomHint": "Enregistre des réglages propres à ce dossier, qui ne suit plus les valeurs globales.", + "settingsAgent": "Agent par défaut", + "settingsMaxConcurrent": "Tâches simultanées max.", + "settingsMaxConcurrentHint": "0 = illimité", + "settingsAutoProcess": "Traiter automatiquement", + "settingsAutoProcessHint": "Les tâches à faire démarrent seules, dans la limite de concurrence.", + "settingsMergeStrategy": "Stratégie de fusion par défaut", + "settingsMergeStrategyHint": "Comment les modifications de la tâche sont consignées dans l'historique de la branche lors de la fusion.", + "settingsAutoMerge": "Fusionner automatiquement", + "settingsAutoMergeHint": "Une tâche qui arrive en revue avec des changements à intégrer est fusionnée comme si vous cliquiez sur Fusionner : l'agent rédige le message de commit et le worktree suit le réglage par défaut ci-dessous. Si la pré-vérification échoue ou qu'une fusion a échoué, la tâche vous attend.", + "settingsDeleteWorktree": "Supprimer le worktree après la fusion", + "settingsDeleteWorktreeHint": "Coche l’option par défaut dans la boîte de dialogue de fusion ; elle reste modifiable.", + "settingsWorktreeRoot": "Emplacement du worktree", + "settingsWorktreeRootHint": "Répertoire dans lequel les worktrees des nouvelles tâches sont créés, un par tâche. Laissez vide pour les créer à côté du dossier du projet ; « ~ » désigne votre dossier personnel et un chemin relatif est résolu depuis le dossier du projet.", + "settingsWorktreeRootPlaceholder": "~/codeg-worktrees", + "settingsWorktreeRootBrowse": "Choisir le répertoire des worktrees", + "settingsPreflight": "Commande de pré-vérification", + "settingsPreflightHint": "S'exécute dans le worktree quand une tâche passe en revue.", + "settingsPreflightCustomPlaceholder": "pnpm test", + "settingsInitCommand": "Commande d'initialisation du worktree", + "settingsInitCommandHint": "Exécutée dans un worktree fraîchement créé avant le démarrage de l'agent.", + "settingsInitCommandPlaceholder": "pnpm install", + "settingsTabGeneral": "Général", + "settingsTabMerge": "Fusion", + "settingsTabWorktree": "Worktree", + "settingsTabPrompts": "Instructions", + "settingsPromptsIntro": "Chaque étape envoie déjà son propre prompt intégré : la tâche, les règles du worktree et, pour la fusion, les étapes git exactes. Ce que vous ajoutez ici est apposé à la fin comme instructions supplémentaires : cela affine ces textes intégrés, sans jamais les remplacer.", + "settingsPromptStageAll": "Toutes les phases", + "settingsPromptPlaceholderAll": "ex. Respecte les conventions d’AGENTS.md ; limite le résumé final à deux phrases", + "settingsPromptPlaceholderWork": "ex. Lis d’abord les tests concernés ; fais des commits petits et fréquents", + "settingsPromptPlaceholderRetry": "ex. Vérifie ce qui est déjà commité avant de continuer ; ne refais pas le travail terminé", + "settingsPromptPlaceholderReturn": "Ex. : Traitez chaque point soulevé ; ne refactorisez rien d'autre", + "settingsPromptPlaceholderMerge": "ex. Rédige le message du commit d’intégration en français ; signale les conflits résolus à la main", + "settingsPromptHintAll": "Ajouté à chaque prompt reçu par l'agent, fusion comprise.", + "settingsPromptHintWork": "Ajouté lors de la première exécution d'une tâche.", + "settingsPromptHintRetry": "Ajouté lorsqu'une tâche interrompue ou en échec est reprise.", + "settingsPromptHintReturn": "Ajouté quand vous relancez une tâche en revue (correction, ajout, vérification).", + "settingsPromptHintMerge": "Ajouté lorsque l'agent intègre la tâche dans la branche de base.", + "preflightPassed": "{name} réussie", + "preflightFailed": "{name} échouée", + "preflightRunning": "{name} en cours…", + "detailDescription": "Détail de la tâche", + "detailSummary": "Résultat", + "detailFiles": "Fichiers modifiés", + "detailDiffAll": "Voir tout le diff", + "detailDiffAllTitle": "Diff complet", + "detailNoChanges": "Aucun changement par rapport à la base", + "detailTimeline": "Progression", + "detailTimelineEmpty": "Aucune activité pour l’instant", + "showMore": "Afficher plus", + "showLess": "Afficher moins", + "detailInfo": "Détails", + "detailBranch": "Branche", + "detailMergeCommit": "Commit de fusion", + "detailChanges": "Modifications", + "detailScheduled": "Démarrage prévu", + "detailCreated": "Créée", + "detailStarted": "Démarrée", + "detailFinished": "Terminée", + "diffLoading": "Chargement du diff…", + "deleteConfirmTitle": "Supprimer la tâche ?", + "deleteConfirmBody": "« {title} » sera retirée du tableau. Une exécution active est d’abord annulée.", + "deleteWithWorktree": "Supprimer aussi son worktree", + "eventCreated": "Créée", + "eventStatusChanged": "Changement d’état", + "eventConfigEffective": "Configuration de lancement", + "eventInitCommand": "Commande d'initialisation", + "eventAgentProgress": "Progression de l’agent", + "eventAgentVerdict": "Verdict de l’agent", + "eventMergeAttempt": "Fusion démarrée", + "eventMergeQueued": "Mise en file de fusion", + "eventMergeConflict": "Conflit de fusion", + "eventPreflight": "Pré-vérification", + "eventCleanupFailed": "Échec du nettoyage du worktree", + "eventResumeFallback": "Reprise échouée, nouvelle session utilisée", + "eventUserAction": "Action utilisateur", + "eventDiffStat": "Instantané des changements" + }, + "CustomSkillsSettings": { + "loading": "Chargement des compétences personnalisées…", + "category": "Personnalisées", + "searchPlaceholder": "Rechercher des compétences personnalisées par nom, ID ou description", + "states": { + "not_linked": "Non activée", + "linked_to_codeg": "Activée", + "linked_elsewhere": "Liée ailleurs", + "blocked_by_real_directory": "Bloquée par un dossier réel", + "broken": "Lien rompu" + }, + "actions": { + "new": "Nouvelle", + "import": "Importer", + "importFromAgent": "Importer depuis un agent", + "cancel": "Annuler", + "save": "Enregistrer" + }, + "rowMenu": { + "edit": "Modifier", + "duplicate": "Dupliquer", + "delete": "Supprimer" + }, + "bulk": { + "delete": "Supprimer la sélection" + }, + "editor": { + "createTitle": "Nouvelle compétence personnalisée", + "editTitle": "Modifier la compétence personnalisée", + "description": "Les compétences personnalisées sont stockées dans le magasin partagé (~/.codeg/skills) et peuvent être activées pour n'importe quel agent.", + "idLabel": "ID de la compétence", + "idPlaceholder": "ex. my-workflow", + "contentLabel": "SKILL.md", + "contentPlaceholder": "Rédigez ici le SKILL.md de la compétence…", + "preview": "Aperçu", + "edit": "Modifier", + "emptyBody": "Aucun contenu pour le moment." + }, + "duplicate": { + "title": "Dupliquer la compétence", + "description": "Créer une copie de « {id} » avec un nouvel ID.", + "newIdPlaceholder": "Nouvel ID de compétence", + "confirm": "Dupliquer" + }, + "import": { + "title": "Choisir un dossier de compétence à importer" + }, + "importFromAgent": { + "title": "Importer des compétences depuis un agent", + "description": "Copiez les compétences propres à un agent dans le magasin partagé pour les activer sur n'importe quel agent.", + "agentLabel": "Agent", + "agentPlaceholder": "Sélectionner un agent", + "selectAll": "Tout sélectionner ({count})", + "loading": "Chargement des compétences de l'agent…", + "unsupported": "Cet agent n'expose pas de répertoire de compétences.", + "empty": "Cet agent n'a aucune compétence à importer.", + "alreadyInLibrary": "Dans la bibliothèque", + "confirm": "Importer la sélection ({count})" + }, + "delete": { + "title": "Supprimer les compétences personnalisées ?", + "body": "Cela retire {count} compétence(s) personnalisée(s) du magasin central et les dissocie de tous les agents. Action irréversible.", + "confirm": "Supprimer" + }, + "toasts": { + "loadFailed": "Échec du chargement de la compétence", + "idRequired": "Veuillez saisir un ID de compétence", + "created": "Compétence personnalisée créée", + "updated": "Compétence personnalisée mise à jour", + "saveFailed": "Échec de l'enregistrement de la compétence", + "imported": "Compétence importée", + "importFailed": "Échec de l'importation de la compétence", + "duplicated": "Compétence dupliquée", + "duplicateFailed": "Échec de la duplication de la compétence", + "deleted": "{count} compétence(s) supprimée(s)", + "deletedPartial": "{ok} supprimée(s), {failed} en échec", + "deleteFailed": "Échec de la suppression des compétences", + "importedFromAgent": "{count} compétence(s) importée(s)", + "importedFromAgentPartial": "{ok} importée(s), {failed} en échec", + "importFromAgentAllSkipped": "Rien à importer — {count} déjà dans la bibliothèque", + "importFromAgentFailed": "Échec de l'import depuis l'agent" + } + }, + "CodexModelEditor": { + "customizedNotice": "Vous avez personnalisé la liste des modèles, codeg gère donc désormais toute la table des modèles de codex. Les modèles officiels que codex ajoutera plus tard n'apparaîtront pas automatiquement : cliquez sur le bouton actualiser ci-dessous puis enregistrez à nouveau pour les synchroniser. Effacez vos personnalisations pour laisser codex se mettre à jour automatiquement.", + "officialsTitle": "Modèles officiels", + "officialsHint": "Inclus automatiquement depuis le codex que vous lancez ; supprimez ceux dont vous ne voulez pas.", + "officialsEmpty": "Aucun modèle officiel disponible.", + "refresh": "Actualiser depuis codex", + "readdOfficial": "Rajouter un officiel", + "customsTitle": "Modèles personnalisés", + "customsEmpty": "Aucun modèle personnalisé pour l'instant.", + "addCustom": "Ajouter personnalisé", + "slugPlaceholder": "id du modèle (slug)", + "displayNamePlaceholder": "Nom affiché", + "contextWindow": "Contexte", + "makeDefault": "Définir par défaut", + "defaultHint": "Modèle par défaut", + "remove": "Supprimer", + "advanced": "Avancé", + "baseTemplate": "Modèle de base", + "baseTemplateHint": "Modèle officiel à partir duquel cloner les champs requis (invite système, outils, limites).", + "groupBehavior": "Comportement et capacités", + "fieldReasoningLevel": "Raisonnement par défaut", + "fieldReasoningSummary": "Résumé du raisonnement", + "fieldVerbosity": "Verbosité", + "fieldShellType": "Type de shell", + "fieldApplyPatch": "Outil apply-patch", + "fieldReasoningSummaries": "Résumés de raisonnement", + "fieldSupportVerbosity": "Contrôle de la verbosité", + "fieldParallelToolCalls": "Appels d'outils en parallèle", + "fieldSearchTool": "Outil de recherche web", + "optNone": "Aucun", + "groupInstructions": "Description et prompt système", + "fieldDescription": "Description", + "baseInstructions": "Invite système (base_instructions)" + }, + "DiagnosticsSettings": { + "title": "Diagnostic de l'environnement", + "description": "Vérifie comment cette app résout la CLI de l'agent dans son propre processus, ce qui peut différer de votre terminal.", + "loading": "Diagnostic en cours…", + "error": "Échec du diagnostic", + "rerun": "Relancer", + "copyAll": "Tout copier", + "copied": "Diagnostic copié dans le presse-papiers", + "button": "Diagnostiquer", + "verdict": { + "ok": "L'environnement semble sain. S'il indique toujours non installé, redémarrez complètement l'app pour actualiser le cache du préfixe.", + "node_missing": "Node.js est introuvable dans le PATH de l'app.", + "npm_missing": "npm est introuvable dans le PATH de l'app.", + "not_installed": "Cet agent ne semble pas installé.", + "installed_but_unresolved": "Enregistré comme installé, mais l'app ne trouve pas son exécutable.", + "user_prefix_not_on_path": "Installé dans le préfixe de secours (~/.codeg/npm-global), qui n'est pas dans le PATH de l'app. Redémarrez complètement l'app et réessayez.", + "homebrew_bin_not_on_path": "Installé sous le bin de Homebrew, qui n'est pas dans le PATH de l'app (séparation keg Apple Silicon).", + "terminal_only_path": "La commande se résout dans votre terminal mais pas dans l'app : un écart de PATH GUI. Lancez l'app depuis un terminal ou réinstallez depuis les Paramètres des agents.", + "npm_prefix_timeout": "npm prefix -g était trop lent (plus de 1,5 s), la détection de secours a été ignorée. Redémarrez l'app et réessayez.", + "node_too_old": "Votre Node.js actif est plus ancien que ce que cet agent requiert. Mettez à niveau Node.js.", + "adapter_missing_native_present": "Votre CLI {agent} est bien installée, mais Codeg lance un paquet adaptateur ACP distinct, et celui-ci ne l'est pas encore. Installez-le depuis les paramètres des agents : il ne touche pas à votre CLI et partage la même connexion.", + "adapter_missing": "Codeg lance un paquet adaptateur ACP distinct pour {agent}, et il n'est pas encore installé. Installez-le depuis les paramètres des agents — installer seulement la CLI de l'éditeur ne suffit pas." + } + }, + "TokenUsage": { + "title": "Consommation de tokens", + "rangeLabel": "Période", + "range7d": "7 jours", + "range30d": "30 jours", + "range90d": "90 jours", + "rangeThisMonth": "Ce mois-ci", + "rangeThisYear": "Cette année", + "rangeAll": "Tout", + "rangeCustom": "Personnalisée", + "moreRanges": "Plus", + "customRangePick": "Choisir une période", + "bucketLabel": "Regrouper par", + "bucketDay": "Jour", + "bucketWeek": "Semaine", + "bucketMonth": "Mois", + "bucketUnitDay": "Jour", + "bucketUnitWeek": "Semaine", + "bucketUnitMonth": "Mois", + "folderFilter": "Dossiers", + "allFolders": "Tous les dossiers", + "agentFilter": "Agents", + "allAgents": "Tous les agents", + "modelFilter": "Modèles", + "allModels": "Tous les modèles", + "searchPlaceholder": "Rechercher…", + "noMatches": "Aucun résultat", + "clearFilter": "Effacer la sélection", + "resetFilters": "Réinitialiser les filtres", + "refresh": "Actualiser", + "rebuild": "Tout reconstruire", + "rebuildHint": "Efface les données comptées et relit toutes les transcriptions. Utile si une session a grandi hors de codeg.", + "syncing": "Comptage des sessions…", + "syncProgress": "{done} / {total}", + "syncDone": "{synced} sessions comptées", + "syncFailed": "Certaines sessions n'ont pas pu être lues", + "syncBusy": "Une actualisation est déjà en cours", + "lastSynced": "Mis à jour {time}", + "lastSyncedNever": "Jamais mis à jour", + "tileTotal": "Tokens au total", + "tileSessions": "Sessions", + "tileTurns": "Tours", + "tileActiveDays": "Jours actifs", + "tileGenTime": "Temps de génération", + "vsPrevious": "vs période précédente", + "deltaNew": "nouveau", + "trendTitle": "Consommation dans le temps", + "trendEmpty": "Aucune consommation sur cette période", + "trendTurns": "Tours", + "trendSessions": "Sessions", + "compositionTitle": "À quoi sont partis les tokens", + "compositionHint": "L'entrée est ce que vous avez envoyé, la sortie ce que le modèle a écrit, et les lectures de cache du contexte non refacturé au prix fort.", + "compositionNote": "Renvoyer ces lectures de cache au prix fort aurait coûté {value} de plus.", + "inputTokens": "Entrée", + "outputTokens": "Sortie", + "cacheWrite": "Écriture cache", + "cacheRead": "Lecture cache", + "freshTokens": "Calcul frais", + "cacheHitCaption": "Taux de cache", + "cacheHeroTitleHigh": "L'essentiel du contexte n'a pas été renvoyé", + "cacheHeroTitleLow": "L'essentiel du contexte se calcule encore au prix fort", + "cacheHeroDesc": "Le cache a porté {cached} de contexte ; seuls {fresh} ont été réellement recalculés sur la période.", + "cacheSavedSuffix": "Soit l'équivalent de {saved} de renvois économisés.", + "avgPerSession": "Moy. par session", + "avgTurnsPerSession": "{count} tours par session en moyenne", + "avgPerActiveDay": "Moy. par jour actif", + "peakBucket": "{bucket} le plus chargé", + "peakHour": "Heure de pointe", + "daysValue": "{count} jours", + "idleDays": "Jours sans activité", + "byFolderTitle": "Par dossier", + "byAgentTitle": "Par agent", + "byModelTitle": "Par modèle", + "distributionTitle": "Répartition de l'usage", + "distributionHint": "Sessions et tokens regroupés selon la dimension choisie — cliquez sur une ligne pour filtrer.", + "otherLabel": "Autres", + "unknownModel": "Modèle non renseigné", + "emptyBreakdown": "Rien d'enregistré", + "sessionsCount": "{count} sessions", + "heatmapTitle": "Quand vous codez", + "heatmapHint": "Tokens par jour de la semaine et heure locale.", + "heatmapPeakHint": "Le plus dense autour de {hour}:00.", + "less": "Moins", + "more": "Plus", + "heatmapCell": "{weekday} {hour}:00 — {value} tokens", + "weekMon": "Lun", + "weekTue": "Mar", + "weekWed": "Mer", + "weekThu": "Jeu", + "weekFri": "Ven", + "weekSat": "Sam", + "weekSun": "Dim", + "topSessionsTitle": "Sessions les plus gourmandes", + "untitledSession": "Session sans titre", + "topSessionsEmpty": "Aucune session sur cette période", + "streakLongest": "Plus longue série", + "streakLongestDays": "Plus longue série : {count} jours", + "share": "Partager", + "moreActions": "Autres actions", + "shareDialogTitle": "Partagez votre carte de consommation", + "shareDialogHint": "Un instantané de la période et des filtres affichés.", + "shareSave": "Enregistrer l'image", + "shareCopy": "Copier l'image", + "shareCopied": "Copié dans le presse-papiers", + "shareSaved": "Image enregistrée", + "shareFailed": "Impossible de créer l'image", + "shareRendering": "Génération…", + "cardHeading": "Mon bilan de code assisté par IA", + "cardRangeAll": "Depuis le début", + "cardTotalLabel": "Tokens consommés", + "cardFooter": "Réalisé avec codeg", + "cardTopModels": "Modèles principaux", + "cardTopProjects": "Projets principaux", + "archetypeNightOwl": "Oiseau de nuit", + "archetypeNightOwlDesc": "{percent}% de vos tokens brûlent après la tombée de la nuit.", + "archetypeEarlyBird": "Lève-tôt", + "archetypeEarlyBirdDesc": "{percent}% de vos tokens tombent avant 9 h.", + "archetypeWeekendWarrior": "Guerrier du week-end", + "archetypeWeekendWarriorDesc": "{percent}% de vos tokens arrivent le week-end.", + "archetypeCacheMaster": "Maître du cache", + "archetypeCacheMasterDesc": "{percent}% de votre contexte venait du cache.", + "archetypeMarathoner": "Marathonien", + "archetypeMarathonerDesc": "{days} jours de code sans interruption.", + "archetypePolyglot": "Polyvalent", + "archetypePolyglotDesc": "{count} agents utilisés sérieusement.", + "archetypeLaserFocus": "Focus laser", + "archetypeLaserFocusDesc": "{percent}% de vos tokens sur un seul projet.", + "archetypeDeepDiver": "Plongeur", + "archetypeDeepDiverDesc": "{averageK}K tokens par session en moyenne.", + "archetypeSteady": "Bâtisseur régulier", + "archetypeSteadyDesc": "{days} jours de livraison.", + "emptyTitle": "Rien de compté pour l'instant", + "emptyHint": "Codeg lit les tokens directement dans la transcription de chaque agent. Actualisez pour compter ce qui est déjà sur cette machine.", + "emptyAction": "Compter mes sessions", + "loadFailed": "Impossible de charger la consommation", + "truncatedNotice": "Cette période est très large — les chiffres ne couvrent que sa portion la plus récente." + } +} diff --git a/src/i18n/messages/ja.json b/src/i18n/messages/ja.json index f44e8c88d..16016ef45 100644 --- a/src/i18n/messages/ja.json +++ b/src/i18n/messages/ja.json @@ -1,4956 +1,4958 @@ -{ - "Language": { - "followSystem": "システムに従う", - "english": "英語", - "simplifiedChinese": "简体中文", - "traditionalChinese": "繁體中文", - "japanese": "日本語", - "korean": "韓国語", - "spanish": "スペイン語", - "german": "ドイツ語", - "french": "フランス語", - "portuguese": "ポルトガル語", - "arabic": "アラビア語" - }, - "GitCredentialDialog": { - "title": "認証が必要です", - "description": "リモートサーバーが認証情報を要求しています。ユーザー名とパスワード(またはアクセストークン)を入力してください。", - "username": "ユーザー名", - "usernamePlaceholder": "ユーザー名またはメールアドレス", - "password": "パスワード / トークン", - "passwordPlaceholder": "パスワードまたはアクセストークン", - "passwordHint": "サーバーのユーザー名とパスワードを入力してください。", - "cancel": "キャンセル", - "authenticate": "認証", - "authenticating": "認証中...", - "invalidCredentials": "認証情報が無効です。再試行してください。", - "saveCredentials": "今後の操作のために認証情報を保存する", - "githubTitle": "GitHub 認証", - "githubDescription": "個人アクセストークンを入力して GitHub に接続します。トークン検証後、自動的にアカウントに保存されます。", - "githubToken": "個人アクセストークン", - "githubTokenPlaceholder": "ghp_xxxxxxxxxxxx", - "githubTokenHint": "GitHub → Settings → Developer settings → Personal access tokens でトークンを生成してください。", - "githubAuthenticate": "検証して接続", - "generateToken": "トークンを生成" - }, - "SettingsShell": { - "title": "設定", - "preferences": "環境設定", - "nav": { - "general": "一般", - "appearance": "外観", - "agents": "エージェント", - "mcp": "MCP", - "skills": "Skills", - "shortcuts": "ショートカット", - "version_control": "バージョン管理", - "system": "システム", - "chat_channels": "チャットチャンネル", - "web_service": "Webサービス", - "model_providers": "モデルプロバイダー", - "experts": "エキスパート", - "science": "科学研究", - "office_tools": "Officeツール", - "skill_packs": "スキルパック", - "quick_messages": "クイックメッセージ", - "logs": "実行ログ" - } - }, - "AppearanceSettings": { - "sectionTitle": "テーマ外観", - "sectionDescription": "ライト、ダーク、またはシステム追従を選択できます。設定は自動保存されます。", - "themeMode": "テーマモード", - "placeholder": "テーマモードを選択", - "system": "システムに従う", - "light": "ライト", - "dark": "ダーク", - "currentTheme": "現在の有効テーマ: {theme}", - "resolvedTheme": { - "light": "ライト", - "dark": "ダーク", - "unknown": "--" - }, - "themeColor": { - "sectionTitle": "テーマカラー", - "sectionDescription": "ボタンやアクセント、ハイライトに使用する色を選択します。", - "current": "現在のカラー:{color}", - "options": { - "neutral": "Neutral", - "zinc": "Zinc", - "slate": "Slate", - "stone": "Stone", - "gray": "Gray", - "red": "Red", - "rose": "Rose", - "orange": "Orange", - "green": "Green", - "blue": "Blue", - "yellow": "Yellow", - "violet": "Violet" - } - }, - "customStyle": { - "sectionTitle": "カスタムスタイル", - "sectionDescription": "現在のテーマの配色を微調整したり、独自の CSS を適用したりできます。上書きはベースプリセットの上に重なるため、プリセットを切り替えても保持されます。", - "summarySuspended": "一時停止中", - "summaryDefault": "プリセットのまま", - "summaryTokens": "{count, plural, one {上書き # 件} other {上書き # 件}}", - "summaryCss": "カスタム CSS", - "suspendedByShortcut": "カスタムスタイルは一時停止中です。再開するまで、ここでの設定は反映されません。", - "suspendedBySafeParam": "このウィンドウはセーフ外観モードで開かれているため、カスタムスタイルは適用されません。他のウィンドウには影響しません。", - "resume": "カスタムスタイルを再開", - "enableTheme": "カスタム配色を有効にする", - "editingLight": "ライトモードの値を編集しています。ダークモードに切り替えると個別に設定できます。", - "editingDark": "ダークモードの値を編集しています。ライトモードに切り替えると個別に設定できます。", - "resetToken": "プリセット値に戻す", - "radius": "角丸", - "radiusHint": "sm から 4xl までの角丸スケール全体がこの値から導出されるため、スライダー 1 つでアプリ全体の角丸が変わります。", - "advanced": "詳細(他 {count} 個の変数)", - "enableCss": "カスタム CSS を有効にする", - "cssRisk": "上級者向け機能です。カスタム CSS は組み込みスタイルをすべて上書きするため、画面が使用不能になることがあります。", - "editCss": "CSS を編集…", - "cssPresent": "{size} KB 保存済み", - "cssEmpty": "まだ保存されていません", - "escapeHint": "画面が壊れてしまったら、{shortcut} でカスタムスタイルをすべて停止できます。safeStyle=1 のクエリパラメータ付きでウィンドウを開く方法もあります。", - "copyTheme": "テーマ JSON をコピー", - "importTheme": "テーマをインポート…", - "clearTheme": "上書きをクリア", - "interopHint": "テーマは shadcn の registry:theme 形式です。任意の shadcn テーマをそのまま貼り付けられ、書き出したテーマはどの shadcn プロジェクトでも使えます。", - "importTitle": "テーマをインポート", - "importDescription": "shadcn の registry:theme アイテム、light/dark のみのオブジェクト、またはフラットなトークンマップを貼り付けてください。", - "readClipboard": "クリップボードから読み取る", - "importConfirm": "インポート", - "cancel": "キャンセル", - "apply": "適用", - "toasts": { - "copied": "テーマ JSON をコピーしました", - "copyFailed": "クリップボードにコピーできませんでした", - "clipboardReadFailed": "クリップボードを読み取れませんでした。手動で貼り付けてください", - "importFailed": "この JSON には利用できるテーマ変数がありません", - "imported": "テーマをインポートしました" - }, - "css": { - "dialogTitle": "カスタム CSS", - "dialogDescription": "すべての codeg ウィンドウに適用されます。変更はリアルタイムでプレビューされ、「適用」で保存されます。", - "size": "{used} KB / {max} KB", - "ruleCount": "{count} 個のルール", - "errorTooLarge": "サイズが大きすぎて保存できません。上限以下に減らしてください。", - "errorImportEscaped": "除去後も @import が検出されました(エスケープ記法)。手動で削除してください。", - "warnNoRules": "ルールが 1 つも解析されませんでした。構文を確認してください。", - "noticeImportsRemoved": "@import を {count} 件削除しました。リモートのスタイルシートを取得してしまうためです。", - "noticeRemoteUrl": "リモートの url() が含まれています。適用するとネットワークリクエストが発生します。", - "noticePreviewSuspended": "カスタムスタイルが停止中のため、このプレビューは適用されません。", - "noticeDisabled": "カスタム CSS は無効です。ここでプレビューはできますが、有効にするまで反映されません。", - "hintTokens": "ヒント: 上書きした色は var(--primary) や var(--background) などで参照できます。" - } - }, - "zoomLevel": { - "sectionTitle": "ウィンドウズーム", - "sectionDescription": "インターフェイス全体を拡大・縮小します。すぐに反映され、デバイスごとに保存されます。", - "placeholder": "ズームレベルを選択", - "default": "デフォルト", - "current": "現在のズーム:{zoom}%" - }, - "fonts": { - "sectionTitle": "フォント", - "sectionDescription": "インターフェース、コードエディター、ターミナルのフォントをそれぞれ選択します。内蔵フォントは必要に応じて読み込まれます。「カスタム…」を選ぶと、システムにインストールされた任意のフォントを使用できます。", - "interface": "インターフェース", - "editor": "エディター", - "terminal": "ターミナル", - "groupSans": "サンセリフ", - "groupMono": "等幅", - "custom": "カスタム…", - "customPlaceholder": "フォント名(例:Fira Code)", - "fontSize": "フォントサイズ", - "ligatures": "合字を有効にする", - "ligaturesUnavailable": "このフォントには合字がありません", - "wordWrap": "折り返しを有効にする", - "terminalLigaturesHint": "ターミナルの合字は内蔵のコーディングフォントにのみ適用されます。", - "preview": "プレビュー" - }, - "welcomePanel": { - "sectionTitle": "モード選択エリア", - "sectionDescription": "新しい会話ページで入力欄の上に表示される「コード開発 / 日常業務」のショートカットカードです。", - "showQuickActions": "新しい会話ページに表示する" - }, - "workspaceBackground": { - "sectionTitle": "ワークスペースの背景", - "sectionDescription": "ワークスペース全体の背後に画像を表示します。サイドバーやパネルは半透明のすりガラスになり画像が透けて見えます。マスクで文字の可読性を保ちます。", - "enable": "背景画像を有効にする", - "image": "画像", - "chooseImage": "画像を選択", - "replaceImage": "画像を変更", - "removeImage": "削除", - "fillMode": "表示方法", - "fillModes": { - "cover": "全体を覆う", - "contain": "全体を表示", - "center": "中央", - "tile": "タイル" - }, - "maskOpacity": "マスクの不透明度", - "maskOpacityHint": "値を大きくすると画像がテーマの背景色に近づき、文字のコントラストが上がります。", - "imageBlur": "画像のぼかし", - "panelOpacity": "パネルの不透明度", - "panelOpacityHint": "サイドバー・パネル・タブバーの不透明度です。低いほど画像が透けて見えます。", - "errorTooLarge": "画像が大きすぎます(最大 16 MB)。", - "errorUploadFailed": "背景画像の設定に失敗しました。" - } - }, - "SystemSettings": { - "loading": "読み込み中...", - "sectionTitle": "システム管理", - "sectionDescription": "ネットワークプロキシ、アプリ更新、言語設定を管理します。", - "proxyTitle": "ネットワークプロキシ", - "proxyDescription": "有効にすると、以降のネットワークリクエストはこのプロキシを優先して使用します(ACP チャット、エージェントのインストール、Git リモート操作を含む)。", - "loadFailed": "読み込みに失敗しました: {message}", - "enableProxy": "システムプロキシを有効化", - "proxyAddress": "プロキシアドレス", - "proxyHint": "http(s)/socks5 をサポート。例: {example}。システムプロキシ有効時のみ有効です。", - "save": "保存", - "saving": "保存中...", - "proxyRequired": "プロキシ有効時はプロキシ URL が必要です", - "saveSuccess": "システムプロキシ設定を保存しました", - "saveFailed": "保存に失敗しました: {message}", - "languageTitle": "言語", - "languageDescription": "アプリの言語を設定します。システムに従う場合、未対応言語は英語にフォールバックします。", - "appLanguage": "アプリ言語", - "languageSaveSuccess": "言語設定を保存しました", - "languageSaveFailed": "言語設定の保存に失敗しました: {message}", - "updateTitle": "アプリ更新", - "versionTitle": "ソフトウェアアップデート", - "updateDescription": "設定されたリリースソースで新しいバージョンを確認し、利用可能なら直接インストールします。", - "currentVersion": "現在のバージョン", - "upgradableVersion": "最新バージョン", - "none": "なし", - "lastChecked": "最終確認: {time}", - "updateError": "更新エラー: {message}", - "checking": "確認中...", - "checkUpdate": "更新を確認", - "updating": "インストール中...", - "downloading": "ダウンロード中...", - "upgradeTo": "v{version} にアップグレード", - "viewRelease": "v{version} のリリースを表示", - "foundUpdate": "新しいバージョン v{version} が見つかりました", - "alreadyLatest": "すでに最新バージョンです", - "checkUpdateFailed": "更新確認に失敗しました: {message}", - "installSuccess": "更新をインストールしました。アプリを再起動します。", - "installFailed": "更新に失敗しました: {message}", - "upgradeSuccess": "アップグレードが完了しました。再読み込みしています...", - "restartTimeout": "サーバーが時間内に復帰しませんでした。コンテナまたはサービスのログを確認してください。", - "restartingIn": "{seconds} 秒後に再起動します...", - "waitingForServer": "サーバーの復帰を待っています...", - "restartToUpdate": "再起動して更新", - "newVersionBadge": "新バージョン v{version}", - "updateAvailableTitle": "アップデートがあります", - "releaseNotesTitle": "更新内容", - "remindLater": "後で", - "retry": "再試行", - "stepDownload": "ダウンロード", - "stepInstall": "インストール", - "stepRestart": "再起動", - "updateReadyHint": "アップデートをダウンロードしました。再起動して適用してください。", - "restarting": "再起動しています…", - "dockerUpgradeHint": "いま実行中のコンテナを更新します。コンテナを再作成すると失われます。維持するには、新しいバージョンのイメージを取得またはビルドしてコンテナを再作成してください。", - "upgradeRolledBack": "アップグレードに失敗しました。サーバーは前のバージョンにロールバックしました。", - "serverUnreachable": "アップグレードを開始するためにサーバーに接続できませんでした。サーバーが稼働中であることを確認して再試行してください。", - "rollbackButton": "ロールバック", - "rollingBack": "ロールバック中...", - "rollbackDescription": "前回のアップグレード前にインストールされていたバージョンに戻します。", - "rollbackConfirmTitle": "以前のバージョンにロールバックしますか?", - "rollbackConfirmDescription": "サーバーは前回のアップグレード前のバージョンで再起動します。新しいリリースは引き続き再インストールできます。", - "rollbackConfirm": "ロールバック", - "rollbackCancel": "キャンセル", - "rollbackSuccess": "以前のバージョンにロールバックしました。再読み込みしています...", - "rollbackFailed": "ロールバックに失敗しました。サーバーのログを確認してください。", - "updateErrors": { - "sourceUnavailable": "更新ソースに接続できません。ネットワークまたはプロキシを確認して再試行してください。", - "network": "ネットワーク接続に失敗しました。ネットワークまたはプロキシを確認して再試行してください。", - "downloadFailed": "更新パッケージのダウンロードに失敗しました。しばらくしてから再試行してください。", - "installFailed": "更新のインストールに失敗しました。アプリを閉じて再試行してください。", - "unknown": "更新に失敗しました。しばらくしてから再試行してください。" - } - }, - "VersionControlSettings": { - "loading": "読み込み中...", - "sectionTitle": "バージョン管理", - "sectionDescription": "Git 実行ファイルの設定と GitHub アカウントの管理。", - "gitTitle": "Git 設定", - "gitDescription": "アプリケーションで使用する Git 実行ファイルを設定します。", - "gitDetected": "Git が検出されました", - "gitNotFound": "システムに Git が見つかりません", - "gitVersion": "バージョン", - "gitPath": "パス", - "customGitPath": "カスタム Git パス", - "customGitPathPlaceholder": "/usr/bin/git", - "customGitPathHint": "空欄の場合、自動検出されたパスを使用します。", - "test": "テスト", - "testing": "テスト中...", - "testSuccess": "Git 実行ファイルは有効です。", - "testFailed": "Git テスト失敗:{message}", - "save": "保存", - "saving": "保存中...", - "saveSuccess": "Git 設定を保存しました。", - "saveFailed": "保存に失敗しました:{message}", - "githubTitle": "GitHub アカウント", - "githubDescription": "認証用の GitHub アカウントを管理します。トークンはローカルに保存されます。", - "noAccounts": "GitHub アカウントが設定されていません。", - "addAccount": "アカウントを追加", - "serverUrl": "サーバー URL", - "serverUrlPlaceholder": "https://github.com", - "token": "個人アクセストークン", - "tokenPlaceholder": "ghp_xxxxxxxxxxxx", - "generateToken": "トークンを生成", - "tokenHint": "GitHub → Settings → Developer settings → Personal access tokens でトークンを生成してください。", - "validateAndAdd": "検証して追加", - "validating": "検証中...", - "addSuccess": "アカウント {username} を追加しました。", - "addFailed": "アカウントの追加に失敗しました:{message}", - "testConnection": "テスト", - "connectionSuccess": "接続成功。", - "connectionFailed": "接続失敗:{message}", - "setDefault": "デフォルトに設定", - "defaultLabel": "デフォルト", - "defaultSet": "デフォルトアカウントを更新しました。", - "removeAccount": "削除", - "removeConfirmTitle": "アカウントを削除", - "removeConfirmMessage": "アカウント「{username}」を削除してもよろしいですか?", - "removeConfirm": "削除", - "removeCancel": "キャンセル", - "removeSuccess": "アカウントを削除しました。", - "scopes": "スコープ", - "loadFailed": "設定の読み込みに失敗しました:{message}", - "gitAccount": { - "sectionTitle": "Git サーバーアカウント", - "sectionDescription": "GitHub 以外の Git サーバーの認証情報を管理します(GitLab、Bitbucket、セルフホストなど)。", - "noAccounts": "Git サーバーアカウントが設定されていません。", - "addAccount": "アカウントを追加", - "addTitle": "Git アカウントを追加", - "addDescription": "サーバーアドレス、ユーザー名、パスワードまたはアクセストークンを入力してください。", - "serverUrl": "サーバー URL", - "serverUrlPlaceholder": "https://gitlab.example.com", - "username": "ユーザー名", - "usernamePlaceholder": "ユーザー名またはメールアドレス", - "password": "パスワード / トークン", - "passwordPlaceholder": "パスワードまたはアクセストークン", - "passwordHint": "サーバーのパスワードまたはアクセストークンを入力してください。", - "add": "追加", - "serverRequired": "サーバー URL を入力してください。", - "usernameRequired": "ユーザー名を入力してください。", - "passwordRequired": "パスワードを入力してください。" - } - }, - "ShortcutSettings": { - "sectionTitle": "ショートカット", - "resetDefault": "デフォルトに戻す", - "recordInstruction": "右側のボタンをクリックしてからキーの組み合わせを押してください。Ctrl/Cmd、Alt、Shift が使用できます。Esc で記録をキャンセルします。", - "recording": "ショートカットを入力...", - "toasts": { - "conflict": "ショートカットはすでに「{title}」で使用されています", - "updated": "ショートカットを更新しました", - "invalid": "無効なショートカットです。もう一度お試しください", - "reset": "デフォルトのショートカットを復元しました" - }, - "actions": { - "toggle_search": { - "title": "検索を開く", - "description": "会話検索パネルを表示または非表示にします" - }, - "toggle_sidebar": { - "title": "左サイドバーを切り替え", - "description": "会話一覧サイドバーを表示または非表示にします" - }, - "toggle_terminal": { - "title": "ターミナルを切り替え", - "description": "下部ターミナルパネルを表示または非表示にします" - }, - "new_terminal_tab": { - "title": "新しいターミナル", - "description": "ターミナルにフォーカスがあるとき新しいタブを作成します" - }, - "close_current_terminal_tab": { - "title": "現在のターミナルを閉じる", - "description": "ターミナルにフォーカスがあるとき現在のタブを閉じます" - }, - "toggle_aux_panel": { - "title": "右パネルを切り替え", - "description": "補助情報パネルを表示または非表示にします" - }, - "new_conversation": { - "title": "新しい会話", - "description": "現在のフォルダで新しい会話タブを作成します" - }, - "open_folder": { - "title": "フォルダを開く", - "description": "フォルダ選択を開き、新しいウィンドウで開きます" - }, - "open_settings": { - "title": "設定を開く", - "description": "設定ウィンドウを開きます" - }, - "close_current_tab": { - "title": "現在のタブを閉じる", - "description": "現在の会話またはファイルタブを閉じます" - }, - "close_all_file_tabs": { - "title": "すべてのファイルタブを閉じる", - "description": "ファイルペインがアクティブなときに開いているすべてのファイルタブを閉じます" - }, - "next_tab": { - "title": "次のタブ", - "description": "次の会話またはファイルタブに切り替える" - }, - "prev_tab": { - "title": "前のタブ", - "description": "前の会話またはファイルタブに切り替える" - }, - "send_message": { - "title": "メッセージを送信", - "description": "入力欄のメッセージを送信する" - }, - "newline_in_message": { - "title": "メッセージ内で改行", - "description": "入力欄で改行を挿入する" - }, - "toggle_custom_style": { - "title": "カスタムスタイルの停止/再開", - "description": "緊急脱出用: カスタム配色と CSS をすべてオフにし、再度押すと元に戻します" - } - } - }, - "SkillsSettings": { - "title": "Skills", - "description": "左側でSkillを選択します。右側は既定でMarkdownプレビューです。編集に切り替えると変更して保存できます。", - "loadingAgents": "Skill対応エージェントを読み込み中...", - "emptyNoManageableAgents": "Skillを管理できるエージェントがありません。", - "managedTarget": "管理対象", - "selectAgentPlaceholder": "エージェントを選択", - "searchPlaceholder": "名前 / ID / パスで検索...", - "skillsList": "Skill一覧", - "loadingSkills": "Skillを読み込み中...", - "agentNotSupported": "現在のエージェントはSkill管理に対応していません。", - "emptySkills": "まだSkillがありません。「新規Skill」をクリックして作成してください。", - "newSkillTitle": "新規Skill", - "skillInfo": "Skill情報", - "skillIdPlaceholder": "skill-id(英数字/-/_/.)", - "skillsDirectoryWithPath": "Skillディレクトリ: {path}", - "skillsDirectoryNeedId": "Skillディレクトリ: Skill ID を入力すると完全なパスを生成します", - "markdownContent": "Markdown内容", - "editingStatus": "編集中", - "previewStatus": "プレビュー中", - "contentPlaceholder": "SkillのMarkdown内容を入力...", - "metadataTitle": "Skillメタデータ", - "onlyYamlMetadata": "このSkillにはYAMLメタデータのみが含まれています。", - "emptyContentHint": "まだ内容がありません。「編集」をクリックして開始してください。", - "loadingSkill": "Skillを読み込み中...", - "emptyNoAgents": "利用可能なエージェントがありません。", - "noSelectionHint": "左側から Skill を選択するか、「新規 Skill」をクリックして作成してください。", - "systemBadge": "システム", - "systemHint": "CLI 組み込み Skill・読み取り専用", - "scope": { - "global": "グローバル", - "folder": "フォルダ", - "selectFolderPlaceholder": "フォルダを選択", - "noFolders": "フォルダが見つかりません", - "pickFolderHint": "Skills を表示するフォルダを選択してください。" - }, - "actions": { - "preview": "プレビュー", - "edit": "編集", - "openInWindow": "新しいウィンドウで開く", - "delete": "削除", - "deleting": "削除中...", - "refresh": "更新", - "newSkill": "新規Skill", - "reset": "リセット", - "save": "保存", - "saving": "保存中...", - "cancel": "キャンセル" - }, - "deleteDialog": { - "title": "Skillを削除", - "confirm": "現在のSkillを削除しますか?この操作は元に戻せません。", - "confirmWithNamePrefix": "Skill", - "confirmWithNameSuffix": "を削除しますか?この操作は元に戻せません。" - }, - "toasts": { - "loadFailed": "Skillの読み込みに失敗しました", - "openFolderFailed": "フォルダを開けませんでした", - "noSkillDirectory": "現在のエージェントで利用可能なSkillディレクトリが見つかりません", - "nameRequired": "Skill名は空にできません", - "updated": "Skillを更新しました", - "created": "Skillを作成しました", - "saveFailed": "Skillの保存に失敗しました", - "deleted": "Skillを削除しました", - "deleteFailed": "Skillの削除に失敗しました" - }, - "templates": { - "gemini": "---\nname: example-skill\ndescription: Describe when this skill should be used.\n---\n\n# Skill Name\n\nInstructions for the agent when this skill is active.\n\n## Workflow\n\n1. Add actionable step one.\n2. Add actionable step two.\n", - "openCode": "---\nname: example-skill\ndescription: Describe when this skill should be used.\n---\n\n# Purpose\n\nDescribe what this skill helps with.\n\n# Steps\n\n1. Add actionable step one.\n2. Add actionable step two.\n", - "openClaw": "---\nname: example-skill\ndescription: Describe when this skill should be used.\nuser-invocable: true\ndisable-model-invocation: false\n---\n\n# Purpose\n\nDescribe what this skill helps with.\n\n# Instructions\n\n1. Add actionable instruction one.\n2. Add actionable instruction two.\n", - "default": "---\nname: example-skill\ndescription: Describe when this skill should be used.\n---\n\n# Skill: example-skill\n\n## When to use\n\n- Describe trigger conditions.\n\n## Instructions\n\n1. Add actionable instruction one.\n2. Add actionable instruction two.\n" - } - }, - "McpSettings": { - "loading": "読み込み中...", - "summary": { - "missingCommand": "(コマンド未設定)", - "missingUrl": "(URL未設定)" - }, - "protocol": { - "stdio": "Stdio" - }, - "errors": { - "selectInstallProtocol": "インストールプロトコルを選択してください", - "fieldRequired": "{field} は必須です", - "fieldNeedsBoolean": "{field} は true または false である必要があります", - "fieldNeedsNumber": "{field} は数値である必要があります", - "fieldNeedsInteger": "{field} は整数である必要があります", - "fieldInvalidJson": "{field} のJSONが不正です: {message}", - "fieldOutOfRange": "{field} の値が許可範囲外です", - "jsonEmpty": "{name} は空にできません", - "jsonInvalid": "{name} は有効なJSONではありません: {message}", - "jsonMustBeObject": "{name} はJSONオブジェクトである必要があります", - "specMustBeObject": "MCP 設定は JSON オブジェクトである必要があります。", - "missingType": "MCP 設定に type フィールドがありません。stdio、http(エイリアス:streamable-http、streamableHttp)、sse のいずれかを指定してください。", - "unsupportedType": "サポートされていない MCP タイプ {type}。対応:stdio、http(エイリアス:streamable-http、streamableHttp)、sse。", - "codexEntryUnsupportedType": "Codex MCP エントリ {id} のタイプ {type} はサポートされていません。対応:stdio、http(エイリアス:streamable-http、streamableHttp)、sse。", - "unsupportedTransportType": "サポートされていない transport タイプ {type}。対応:http(エイリアス:streamable-http、streamableHttp)、sse。", - "stdioCommandRequired": "stdio タイプの MCP には空でない command フィールドが必要です。", - "remoteUrlRequired": "リモート MCP には空でない url フィールドが必要です。", - "appsRequired": "対象アプリを少なくとも 1 つ選択してください。" - }, - "jsonNames": { - "localConfig": "MCP設定", - "installConfig": "インストール設定" - }, - "toasts": { - "uninstalled": "MCPをアンインストールしました", - "uninstallFailed": "アンインストールに失敗しました: {message}", - "selectAtLeastOneApp": "対象アプリを少なくとも1つ選択してください", - "saveSuccess": "保存しました", - "saveFailed": "保存に失敗しました: {message}", - "installed": "{name} をインストールしました", - "installFailed": "インストールに失敗しました: {message}", - "serverIdRequired": "Server ID は必須です", - "serverIdExists": "Server ID \"{id}\" は既に存在します。既存の項目を編集するか、別の名前を選択してください。", - "created": "MCP を作成しました" - }, - "installDialog": { - "title": "MCPインストールの確認", - "descriptionWithName": "{name} をローカル設定にインストールします。", - "description": "インストール対象アプリを選択してください。", - "protocol": "プロトコル", - "selectProtocol": "プロトコルを選択", - "parameters": "設定パラメータ", - "booleanPlaceholder": "true/false を選択してください", - "selectOneValue": "値を選択", - "targetApps": "対象アプリ" - }, - "actions": { - "cancel": "キャンセル", - "confirmInstall": "インストールを確定", - "installing": "インストール中", - "uninstall": "アンインストール", - "uninstalling": "アンインストール中", - "viewDetails": "詳細を見る", - "save": "保存", - "saving": "保存中", - "install": "インストール", - "refresh": "更新", - "newMcp": "新規 MCP", - "create": "作成", - "creating": "作成中..." - }, - "tabs": { - "local": "ローカル MCP", - "market": "MCP マーケットプレイス" - }, - "local": { - "filterPlaceholder": "ローカルMCPを絞り込み...", - "loadFailed": "読み込み失敗: {message}", - "empty": "ローカルMCPが見つかりません。", - "description": "ローカルMCP設定は直接編集して保存できます。", - "enabledApps": "有効なアプリ", - "configJson": "MCP設定 (JSON)", - "draftTitle": "新規 MCP", - "draftDescription": "Server ID と設定を入力してローカル MCP サーバーを作成します。", - "serverIdLabel": "Server ID", - "serverIdPlaceholder": "Server ID(例:my-mcp)", - "typeHint": "対応タイプ:stdio、http(エイリアス streamable-http、streamableHttp)、sse。env は stdio 専用です。リモート MCP の認証トークンは headers で渡してください。", - "envOnRemoteWarning": "リモート MCP の設定に env が含まれています。env は stdio のみで使用され、リモート MCP の認証トークンは headers に格納します。env は保存時に無視されます。" - }, - "market": { - "selectMarketplace": "マーケットプレイスを選択", - "searchPlaceholder": "MCPを検索...", - "searchFailed": "検索に失敗しました: {message}", - "loadingList": "MCP一覧を読み込み中...", - "empty": "MCPの検索結果がありません。", - "loadingDetail": "マーケットプレイス詳細を読み込み中...", - "detailLoadFailed": "詳細の読み込みに失敗しました: {message}", - "owner": "オーナー: {owner}", - "namespace": "名前空間: {namespace}", - "defaultInstallProtocol": "デフォルトのインストールプロトコル", - "currentOptionParameterCount": "現在のオプションのパラメータ数: {count}", - "installConfigDescription": "インストール設定 (JSON、インストール前に編集可能。編集内容はプロトコル/パラメータフォームより優先されます)", - "selectLeftToView": "詳細を見るには左側のマーケットプレイスMCPを選択してください。" - }, - "badges": { - "verified": "認証済み", - "remote": "リモート", - "hasHomepage": "ホームページあり", - "uses": "{count} 回使用", - "deployed": "デプロイ済み", - "notDeployed": "未デプロイ" - }, - "selectLeftMcp": "左側でMCPを選択してください。" - }, - "AcpAgentSettings": { - "title": "Agent SDK 管理", - "description": "Agent SDK の接続、有効化状態、環境変数、設定管理、バージョン事前チェック情報を一元管理します。", - "loadingAgents": "エージェント一覧を読み込み中...", - "agentList": "エージェント一覧", - "emptyNoAgent": "利用可能なエージェントがありません。", - "configManagement": "設定管理", - "envVars": "環境変数", - "hostTools": { - "label": "ファイルとコマンドをエージェント自身に処理させる", - "description": "codeg がファイルアクセスとターミナルコマンドを代行しなくなり、エージェントが自身のプロセスで実行します。そうすることで初めて、エージェント自身のサンドボックスと権限ルールが適用されます。他のエージェントへの委任も無効になります(同じ処理が codeg 経由に戻ってしまうため)。codeg 自体はサンドボックスを提供しないため、エージェント側でサンドボックスを設定済みの場合にのみ有効にしてください。" - }, - "nativeJsonConfig": "ネイティブ JSON 設定", - "modelHintDefault": "空欄の場合はシステム既定モデルを使用します。", - "generalConfigDescriptionClaude": "API URL、API Key、Claude モデルをすばやく設定でき、ネイティブ JSON 設定と同期します。", - "generalConfigDescriptionDefault": "重要な設定入力(API URL、API Key、Model)とネイティブ JSON 設定管理をサポートします。", - "multiAgent": { - "title": "マルチエージェント連携", - "description": "アクティブなエージェントがサブタスクを他のエージェントに委任できるようにします。", - "enable": "委任を有効化", - "enableHint": "オフにすると、delegate_to_agent ツールはエージェントの MCP ツール一覧から非表示になります。", - "withheldByHostTools": "{agents} には委任ツールが渡りません。エージェントごとの「ファイルとコマンドをエージェント自身に任せる」スイッチがオンになっています。", - "depthLimit": "最大委任深度", - "depthHint": "許可範囲: {min}–{max}。委任チェーン(ルート → 子 → 孫 …)の再帰深度を制限します。", - "completedCacheLabel": "完了結果のキャッシュ(MB)", - "completedCacheHint": "実行中の委任セッションが保持する、完了したサブエージェント結果のメモリ内キャッシュ。そのセッションの実行中のみ保持され、セッション終了時に自動的に破棄されます。この予算を超えると古い結果から順にメモリから破棄されます(サブエージェント自身のセッションでは引き続き閲覧可能)。0 は無制限(それでもセッション終了時に破棄)。", - "save": "保存", - "saving": "保存中…", - "saved": "委任設定を保存しました", - "saveFailed": "委任設定の保存に失敗しました", - "loadFailed": "委任設定の読み込みに失敗しました: {detail}", - "tabGeneral": "一般", - "tabAgentDefaults": "サブエージェント設定", - "agentDefaultsDescription": "マルチエージェント連携が委任呼び出しのためにサブエージェントを起動するときに適用される上書き設定です。ここに表示されるオプションはライブプローブで取得しており、選択した内容がそのままエージェントに渡されます。", - "probing": "エージェントの利用可能な設定項目を読み込み中…", - "probeFailed": "設定項目の読み込みに失敗しました: {detail}", - "retry": "再試行", - "noConfigAvailable": "このエージェントには設定可能な項目がありません。", - "modeLabel": "モード", - "agentDefaultHint": "エージェント既定: {value}", - "defaultOptionLabel": "既定({value})" - }, - "actions": { - "dragSort": "ドラッグして並べ替え", - "dragSortAgent": "{name} をドラッグして並べ替え", - "refreshCheck": "再チェック", - "refreshCheckAgent": "{name} を再チェック", - "clickEnable": "{name} を有効化", - "clickDisable": "{name} を無効化", - "install": "インストール", - "upgrade": "アップグレード", - "uninstall": "アンインストール", - "uninstalling": "アンインストール中...", - "saveEnvVars": "環境変数を保存", - "saving": "保存中...", - "saveGrokConfig": "Grok 設定を保存", - "saveCodexConfig": "Codex設定を保存", - "saveGeminiConfig": "Gemini設定を保存", - "saveOpenCodeConfig": "OpenCode設定を保存", - "saveOpenClawConfig": "OpenClaw設定を保存", - "saveConfigManagement": "設定管理を保存", - "saveCurrentProvider": "現在のプロバイダーを保存", - "showApiKey": "APIキーを表示", - "hideApiKey": "APIキーを非表示", - "showKey": "キーを表示", - "hideKey": "キーを非表示", - "showToken": "トークンを表示", - "hideToken": "トークンを非表示", - "cancel": "キャンセル", - "delete": "削除", - "deleting": "削除中...", - "confirmDelete": "削除を確認", - "confirmUninstall": "アンインストールを確認", - "saveClineConfig": "Cline設定を保存", - "saveHermesConfig": "Hermes設定を保存", - "saveCodeBuddyConfig": "CodeBuddy 設定を保存", - "saveKimiCodeConfig": "Kimi Code の設定を保存", - "customInstall": "カスタムインストール", - "saveKimiCodeRawConfig": "Save config.toml", - "saveDeepSeekConfig": "DeepSeek 設定を保存", - "diagnose": "診断" - }, - "status": { - "enabled": "有効", - "disabled": "無効", - "unchecked": "未チェック", - "agentEnabledAria": "{name} は有効です", - "agentEnabledSwitch": "{name} 有効化スイッチ" - }, - "preflight": { - "count": "事前チェック項目: {count}", - "notRun": "チェックはまだ実行されていません。" - }, - "grok": { - "configDescription": "ここで Grok を設定します。以下のコントロール(権限モード、推論の強さ、任意のカスタム(独自エンドポイント)モデル、圧縮)は ~/.grok/config.toml にマージされ、他のキーやコメントは保持されます。サインインは XAI_API_KEY または `grok login` を使用します。その他のキーは「詳細」で編集できます。", - "permissionModeLabel": "権限モード", - "permissionDefault": "毎回確認", - "permissionAcceptEdits": "編集を自動承認", - "permissionAuto": "スマート自動承認", - "permissionAlwaysApprove": "常に許可", - "reasoningEffortLabel": "推論レベル", - "effortLow": "低(高速)", - "effortMedium": "中(バランス)", - "effortHigh": "高", - "effortXhigh": "最大", - "optionDefault": "デフォルトを使用", - "authTitle": "認証", - "authMode": "認証方式", - "authModeApiKey": "XAI API キー", - "authModeApiKeyHint": "xAI コンソールの XAI_API_KEY で認証します。非対話・ヘッドレス実行向けで、このエージェントの環境変数に保存されます。", - "authModeCustom": "カスタムエンドポイント", - "authModeCustomHint": "独自のエンドポイント(BYO)を使用します。下でベース URL と API キーを持つカスタムモデルを定義すると、それが Grok の既定モデルになります。", - "subscriptionHint": "`grok login` でサインインします(SuperGrok / X Premium+)。API キーは保存されません。", - "loginHint": "ターミナルで次のコマンドを実行してサインインし、この設定を開き直してください:", - "commandCopied": "コマンドをクリップボードにコピーしました", - "copyCommand": "コマンドをコピー", - "authKeyConfigured": "XAI_API_KEY が設定されています。", - "authKeyMissing": "XAI_API_KEY が未設定です。", - "advancedToggle": "詳細(生の config.toml)", - "configTomlNative": "config.toml(ネイティブ)", - "configTomlHint": "~/.grok/config.toml 全体としてそのまま書き込まれます。無効な TOML は拒否され、タイプミスでファイルが切り詰められることはありません。", - "configTomlPlaceholder": "# 上のコントロール以外のキー。例:\n# [mcp_servers.*]、[cli]、[permission] ルール。", - "customModelTitle": "カスタムモデル(独自エンドポイント)", - "customModelHint": "Grok をカスタムまたは自己ホストのエンドポイントに向けます。codeg はモデルごとの `[model.*]` ブロックを書き込み、既定モデルに設定します。モデル ID を空にすると削除されます。", - "customModelIdLabel": "モデル ID", - "customModelIdPlaceholder": "grok-4.5", - "customModelIdHint": "`[model.*]` ブロックとして登録され、モデル名として API に送信されます。`[models].default` にも設定されます。", - "customBaseUrlLabel": "Base URL", - "customBaseUrlPlaceholder": "https://api.x.ai/v1(既定)", - "customApiBackendLabel": "API バックエンド", - "backendResponses": "Responses", - "backendChatCompletions": "Chat Completions", - "backendMessages": "Messages(Anthropic)", - "customApiKeyLabel": "API キー", - "customApiKeyHint": "`[model.*].api_key` にインラインで保存され、このエンドポイントにのみ適用されます。", - "customContextWindowLabel": "コンテキストウィンドウ(トークン)", - "customContextWindowHint": "任意。自動圧縮のタイミングに使われます。空欄の場合はエンドポイントの既定値を使用します。", - "autoCompactLabel": "自動圧縮のしきい値(%)", - "autoCompactHint": "コンテキスト使用率がこの割合に達したら会話を圧縮します(Grok の既定は 85)。`[session]` に書き込まれます。" - }, - "cursor": { - "configDescription": "ここで Cursor を設定します。まず認証方式を選択し——公式サブスクリプション(ブラウザログイン)またはヘッドレス/サーバー用の Cursor API キー——次にモデルを選び、CLI の権限ルールとサンドボックスを編集します。codeg はこれらを ~/.cursor/cli-config.json に書き込み、cursor-agent CLI と共有します。", - "authTitle": "認証", - "authChecking": "確認中…", - "authNotInstalled": "cursor-agent が未インストールです", - "authLoggedIn": "ログイン済み", - "authNotLoggedIn": "未ログイン", - "loginHint": "ターミナルで次のコマンドを実行して Cursor アカウントにログイン(ブラウザが開きます)し、完了後に更新を押してください:", - "apiKeyLabel": "Cursor API キー", - "apiKeyPlaceholder": "cursor.com/dashboard で取得", - "apiKeyHint": "CURSOR_API_KEY —— Cursor ダッシュボードのアカウントキー。ヘッドレス/サーバー環境でブラウザログインの代わりに使用します。サードパーティや OpenAI のキーではありません。", - "modelTitle": "デフォルトモデル", - "loadModels": "モデル一覧を取得", - "modelsUnavailable": "モデル一覧を取得できません", - "modelHint": "セッション開始時に --model として CLI に渡されます。既定のままなら Cursor が選択します。", - "permissionsTitle": "権限とサンドボックス", - "permissionsDescription": "CLI の権限ルール(cli-config.json)のビジュアルエディタ。許可ルールは確認なしで実行、拒否ルールは常にブロックされます。", - "permissionModeLabel": "権限モード", - "permissionModeDefault": "実行前に確認(デフォルト)", - "permissionModeForce": "Run Everything(--force)", - "permissionModeHint": "Run Everything は --force でセッションを起動します:deny ルール以外のツール呼び出しはすべて確認なしで自動許可されます(組織ポリシーにより allow ルール一致のみに制限される場合があります)。新しいセッションから有効です。", - "optionDefault": "既定(未設定)", - "sandboxLabel": "サンドボックス", - "sandboxEnabled": "有効", - "sandboxDisabled": "無効", - "allowRulesLabel": "許可ルール", - "denyRulesLabel": "拒否ルール", - "addRule": "ルールを追加", - "rulesSyntaxHint": "ルール構文:Shell(コマンド)、Read(パス/グロブ)、Write(パス/グロブ)、WebFetch(ドメイン)、Mcp(サーバー:ツール)——deny ルールが常に優先されます。", - "saveConfig": "設定を保存", - "advancedToggle": "詳細:cli-config.json(生ファイル)", - "advancedHint": "~/.cursor/cli-config.json の全文です。ここでの保存はそのまま書き込み、上の構造化コントロールはマージして書き込みます。", - "saveRawConfig": "ファイルを保存", - "authMode": "認証方式", - "subscriptionHint": "Cursor アカウントでサインインし、Cursor のモデルを使用します。", - "customApiKeyRequired": "Cursor API キーが必要です。", - "authModeApiKey": "Cursor API キー(ヘッドレス/サーバー)", - "authModeApiKeyHint": "Cursor ダッシュボードで発行したアカウント API キーで認証します(ヘッドレス/サーバー環境向け)。これは Cursor アカウントのキーであり、サードパーティ/OpenAI エンドポイントではありません——cursor-agent は Cursor 自身のバックエンドにのみ接続します。codex/OpenAI 互換エンドポイントを使うには、代わりに Codex エージェントを使用してください。", - "modelPickerPlaceholder": "モデルを検索…", - "modelNoMatch": "一致するモデルがありません", - "modelsNeedAuth": "サインインするとモデル一覧を読み込みます。", - "modelDefaultBadge": "既定" - }, - "deepseek": { - "configManagement": "DeepSeek Harness の設定", - "configDescription": "エンドポイントと API キーは deepseek-acp が起動時に読み込む環境変数です。モデルと推論レベルはセッションごとのセレクターなので、入力欄で切り替えます。", - "baseUrlLabel": "API エンドポイント", - "baseUrlHint": "空欄なら公式エンドポイントを使います。保存後に開始したセッションから有効になります。実行中のセッションは再接続してください。", - "baseUrlInvalid": "クエリ文字列を含まない完全な http(s) URL を入力してください(例:https://api.deepseek.com)", - "apiKeyLabel": "API キー", - "apiKeyHint": "DEEPSEEK_API_KEY としてエージェントに渡されます。環境変数は認証情報ファイルより優先されるため、ターミナルでログインする場合は空のままにしてください。" - }, - "codex": { - "configDescription": "API URL、API Key、モデル名、reasoning effort を素早く設定でき、`auth.json` / `config.toml` と同期します。", - "authMode": "認証方式", - "chatgptSubscription": "公式サブスクリプション", - "chatgptSubscriptionHint": "ChatGPT 公式サブスクリプションでログイン、API Key 不要", - "apiKeyHint": "API Key で OpenAI または互換 API サービスに接続", - "selectProvider": "プロバイダーを選択", - "modelName": "モデル名", - "selectReasoningEffort": "Reasoning Effort を選択", - "enableWebsocket": "WebSocket を有効化", - "enableWebsocketAria": "Codex Provider の WebSocket を有効化", - "enableSkills": "Skills を有効化", - "enableSkillsAria": "Codex の Skills を有効化", - "enableFast": "Fast を有効化", - "enableFastAria": "Codex の Fast サービスティアを有効化", - "sandboxGroupTitle": "サンドボックスと承認", - "sandboxGroupHint": "グローバルの ~/.codex/config.toml に書き込むため、codex CLI や IDE のセッションにも反映されます。これはスレッドの既定値で、codex 自身が開始するターン(/goal、/review、/compact)にのみ適用されます。通常のプロンプトは入力欄の承認プリセットを使います。変更はセッションを再起動すると有効になります。", - "sandboxShadowedWarning": "config.toml に default_permissions が設定されているため、codex は権限プロファイル経由で解決し sandbox_mode を完全に無視します。以下の設定を使うには default_permissions を削除してください。", - "sandboxPermissionsTableWarning": "config.toml に [permissions] プロファイルがありますが default_permissions が未設定のため、codex は起動を拒否します。下の生エディタで設定してください。", - "approvalPolicyLabel": "承認ポリシー", - "approvalPolicyUnset": "未設定(codex の既定: 要求時)", - "approvalPolicy_on-request": "要求時 — モデルが確認のタイミングを判断", - "approvalPolicy_untrusted": "未信頼 — 安全と分かっている読み取り専用コマンドのみ自動実行", - "approvalPolicy_never": "確認しない — 承認プロンプトを一切出さない", - "approvalPolicy_granular": "詳細設定 — プロンプト種別ごとに指定", - "approvalPolicyUntrustedAcpWarning": "ACP アダプターの 3 つの承認プリセットに untrusted に相当するものはないため、codeg のセッションは「要求時」にフォールバックします。その場合はモデルが尋ねるタイミングを決め、サンドボックスが既に許可しているコマンドは確認されなくなります。代わりに下のサンドボックスモードで制限してください。", - "granularHint": "オフにすると、その種類の要求は表示されずに自動で拒否されます。", - "granular_sandbox_approval": "シェルコマンドの権限昇格", - "granular_rules": "Execpolicy ルールのプロンプト", - "granular_skill_approval": "スキルスクリプトのプロンプト", - "granular_request_permissions": "request_permissions ツールのプロンプト", - "granular_mcp_elicitations": "MCP elicitation のプロンプト", - "sandboxModeLabel": "サンドボックスモード", - "sandboxModeUnset": "未設定(信頼済みフォルダはワークスペース書き込みにフォールバック)", - "sandboxMode_read-only": "読み取り専用", - "sandboxMode_workspace-write": "ワークスペース書き込み", - "sandboxMode_danger-full-access": "フルアクセス(サンドボックスなし)", - "sandboxModeHint": "Windows では、codex の実験的 Windows サンドボックスが無効な場合、ワークスペース書き込みは読み取り専用に降格されます。", - "sandboxModeSeedsPresetHint": "codeg はこれをセッションの初期承認プリセットにも反映するため、承認ポリシーとは異なり通常のプロンプトにも効きます。入力欄のプリセットが指定されている場合はそちらが優先されます。", - "writableRootsLabel": "追加の書き込み可能フォルダ", - "writableRootsHint": "作業ディレクトリに加えて許可する絶対パスを 1 行に 1 つ。", - "sandboxRootsRelativeError": "絶対パスである必要があります — codex は相対パスを ~/.codex 基準で解決します: {path}", - "networkAccessLabel": "ネットワークアクセスを許可", - "excludeTmpdirLabel": "書き込み可能ルートから TMPDIR を除外", - "excludeSlashTmpLabel": "書き込み可能ルートから /tmp を除外", - "authJsonNative": "auth.json(ネイティブ)", - "configTomlNative": "config.toml(ネイティブ)", - "loginButton": "ChatGPT でログイン", - "loginRequesting": "ログインコードを取得中...", - "loginStep1": "ブラウザで以下の URL を開いてください:", - "loginStep2": "以下のコードを入力してください:", - "loginPolling": "認証を待っています...", - "loginCancel": "キャンセル", - "loginSuccess": "ログイン成功、設定を保存しました!", - "loginFailed": "ログインに失敗しました:{message}", - "loginRetry": "再試行", - "loginCodeCopied": "コードをコピーしました", - "loggedIn": "アカウントにログイン済み", - "loginRelogin": "再ログイン / アカウント切替", - "loginTimeout": "ログインがタイムアウトしました。再試行してください", - "loginSaveFailed": "ログインは成功しましたが、設定の保存に失敗しました" - }, - "gemini": { - "authConfig": "Gemini 認証設定", - "authConfigDescription": "Gemini CLI の認証ドキュメントに準拠し、カスタムエンドポイント、Google ログイン、Gemini API Key、Vertex AI(ADC / サービスアカウント / API Key)をサポートします。", - "authMode": "認証モード", - "selectAuthMode": "認証モードを選択", - "viewAuthDoc": "認証ドキュメントを見る", - "mode": { - "custom": "カスタムエンドポイント", - "loginGoogle": "Google ログイン(OAuth)", - "vertexServiceAccount": "Vertex AI(サービスアカウント)" - }, - "hint": { - "custom": "API URL、API Key、Model を入力してください。GOOGLE_GEMINI_BASE_URL / GEMINI_API_KEY / GEMINI_MODEL に対応します。", - "loginGoogle": "先にターミナルで gemini を実行して Google ログインを完了してください。API key は不要です。", - "geminiApiKey": "Gemini API を使う場合は GEMINI_API_KEY を入力してください。", - "vertexAdc": "gcloud ADC を使用します。GOOGLE_CLOUD_PROJECT と GOOGLE_CLOUD_LOCATION の設定を推奨します。", - "vertexServiceAccount": "サービスアカウント JSON のパスを GOOGLE_APPLICATION_CREDENTIALS に設定してください。", - "vertexApiKey": "Vertex AI API key を使う場合は GOOGLE_API_KEY を入力してください。" - } - }, - "openCode": { - "configManagement": "OpenCode 設定管理", - "configDescription": "OpenCode の `provider` スキーマに準拠し、複数プロバイダー管理とネイティブ JSON ファイルとの双方向同期をサポートします。", - "providerManagement": "プロバイダー管理", - "providerCount": "{count} 個のプロバイダー", - "addProvider": "プロバイダーを追加", - "emptyProvider": "カスタムプロバイダーはまだありません。「カスタムプロバイダーを追加」をクリックして作成してください。", - "providerEnabledState": "{providerId} の有効状態", - "selectProviderNpm": "provider.npm を選択", - "modelManagement": "モデル管理", - "modelCount": "{count} 個のモデル", - "modelDescription": "OpenCode の `provider.models` に準拠。高速管理では現在 `name` / `id` をサポートし、その他の高度な項目は保持され、下部のネイティブ JSON で編集できます。", - "addModel": "モデルを追加", - "emptyModel": "まだモデルがありません。model id を入力して「モデルを追加」をクリックしてください。", - "modelId": "モデル ID", - "modelName": "モデル名", - "deleteModel": "モデル {modelId} を削除", - "nativeJsonConfig": "OpenCode ネイティブ JSON 設定", - "mainModel": "メインモデル", - "smallModel": "スモールモデル", - "noMatchingModels": "一致するモデルがありません", - "connectProvider": "プロバイダーを接続", - "connectedProviders": "接続済みプロバイダー", - "noConnectedProviders": "カタログのプロバイダーはまだ接続されていません。", - "advancedProviderConfig": "カスタムプロバイダー", - "customProviderConfigHint": "自分で定義する OpenAI 互換エンドポイント——opencode.json の provider ブロックで、API キーは auth.json に保存されます。", - "addCustomProvider": "カスタムプロバイダーを追加", - "disconnect": "切断", - "editConfig": "編集", - "customBadge": "カスタム", - "authKindApi": "API キー", - "authKindOauth": "OAuth", - "authKindNone": "認証情報なし", - "connect": { - "title": "プロバイダーを接続", - "description": "models.dev カタログからプロバイダーを選択します。認証情報は OpenCode の auth.json に保存されます。", - "pick": "プロバイダー", - "search": "プロバイダーを検索…", - "loading": "カタログを読み込み中…", - "catalogLabel": "models.dev カタログ", - "modelsAvailable": "{count} 個のモデルが利用可能", - "getKey": "API キーを取得", - "oauthApiKeyNote": "このプロバイダーは opencode auth login によるブラウザサインインにも対応しています。ブラウザサインインは近日対応予定です。今は API キーを貼り付けてください。", - "apiKey": "API キー", - "apiKeyHint": "auth.json に保存され、opencode.json には書き込まれません。", - "baseUrlOptional": "Base URL の上書き(任意)", - "providerId": "プロバイダー ID", - "displayName": "表示名", - "modelsList": "モデル(1 行に 1 つ)", - "modelsHint": "エンドポイントが受け付けるモデル ID。", - "action": "接続", - "editTitle": "プロバイダーを編集", - "editDescription": "このプロバイダーの API キーまたは Base URL を更新します。", - "saveAction": "保存" - }, - "customProvider": { - "title": "カスタムプロバイダーを追加", - "description": "OpenAI 互換エンドポイントを定義します。API キーは auth.json に、provider ブロックは opencode.json に保存されます。", - "action": "プロバイダーを追加", - "idInCatalog": "{providerId} は既知のプロバイダーです。「プロバイダーを接続」から接続してください。" - }, - "refreshCatalog": "カタログを更新", - "reasoningBadge": "推論", - "contextWindow": "コンテキストウィンドウ", - "permissions": { - "title": "権限", - "description": "どの操作をそのまま実行し、確認を求め、あるいはブロックするかを決めます。opencode.json の permission 設定に書き込まれ、下の保存で反映されます。", - "docsLink": "権限のドキュメント", - "unparsableConfig": "下のネイティブ JSON が解析できないため、ビジュアル編集を停止しています。JSON を修正すると再開します。", - "invalidBlock": "permission 設定の形式を認識できません。下のネイティブ JSON で編集するか、「リセット」でやり直してください。", - "orderingUnsafe": "ワイルドカードのルールが個別のツールより後に書かれているため、OpenCode はそれらにも適用します。下の各行は実際に有効な設定ではありません。「順序を修正」は値を変えずに、各スコープの先頭へワイルドカードを戻すだけです。", - "orderingUnsafeManual": "あるルールが後方のより広いパターンに隠されており、OpenCode は決して適用しません。下の各行は実際に有効な設定ではありません。重なり合う 2 つのパターンに唯一の正しい順序はないため、下のネイティブ JSON で広いほうを先に並べ替えてください。", - "fixOrder": "順序を修正", - "agentOverrides": "次のエージェントは権限を個別に上書きしており、最後に適用されるためここの設定より優先されます: {agents}。下のネイティブ JSON で編集するか、自動承認をオンにして削除してください。", - "legacyTools": "トップレベルの旧 tools 設定がツールを拒否しています。OpenCode はこれを権限に統合するため、ここに表示されている設定すべての上に適用されます。下のネイティブ JSON で編集するか、自動承認をオンにして削除してください。", - "autoAcceptTitle": "すべての権限を自動承認", - "autoAcceptHint": "シェルコマンド、ファイル編集、プロジェクト外のパスを含むすべてのツール呼び出しを確認なしで実行します。オンにすると、下のツール別設定は 1 つの全許可ルールに置き換わり、そのままではブロックし続けるエージェントごとの権限の上書きと旧 tools 設定も削除されます。", - "globalLabel": "全体のデフォルト", - "globalHint": "* ルールです。下のツールで上書きされていないものすべてに適用されます。", - "actionUnset": "未設定(OpenCode のデフォルト)", - "actionInherit": "デフォルトに従う({action})", - "actionAllow": "許可", - "actionAsk": "確認する", - "actionDeny": "拒否", - "perToolTitle": "ツール別の権限", - "reset": "リセット", - "ruleCount": "ルール: {count}", - "rulesToggle": "{tool} の詳細ルール", - "rulesHint": "ツールの入力に対して照合し、最後に一致したルールが優先されます。広いパターンを先に書いてください。* は任意の文字列、? はちょうど 1 文字に一致し、先頭の ~ はホームディレクトリに展開されます。", - "noRules": "詳細ルールはまだありません。", - "addRule": "ルールを追加", - "deleteRule": "ルール {pattern} を削除", - "duplicateRule": "そのパターンは既に存在します。", - "blankRule": "ルールにはパターンが必要です。削除するにはゴミ箱アイコンを使ってください。", - "customKeys": "ファイル内のその他の権限キー", - "customKeyHint": "OpenCode の組み込みツールではありません。記述どおり保持されます。", - "keys": { - "bash": "シェルコマンドの実行。解析後のコマンドで照合", - "edit": "ファイルへのすべての変更(edit・write・patch)", - "read": "ファイルの読み取り。パスで照合", - "external_directory": "プロジェクトの作業ディレクトリ外のパスへのアクセス", - "task": "サブエージェントの起動。サブエージェントの種類で照合", - "skill": "スキルの読み込み。スキル名で照合", - "glob": "ファイル検索。グロブパターンで照合", - "grep": "ファイル内容の検索。パターンで照合", - "list": "ディレクトリ内容の一覧表示", - "webfetch": "URL の取得", - "websearch": "ウェブ検索", - "lsp": "LSP クエリの実行", - "todowrite": "TODO リストの書き込み", - "question": "あなたへの質問", - "doom_loop": "同じ入力で同じ呼び出しが 3 回繰り返されたときに作動" - } - } - }, - "openClaw": { - "gatewayConfig": "Gateway 設定", - "gatewayDescription": "OpenClaw Gateway 接続を設定します。ローカルまたはリモートの gateway をサポートします。", - "gatewayUrlHint": "空欄の場合はローカル openclaw 設定の gateway.remote.url を使用します。", - "gatewayTokenPlaceholder": "Gateway 認証トークン", - "gatewayTokenHint": "可能な場合は平文トークンではなく token-file の使用を推奨します。openclaw CLI で設定してください。", - "sessionKeyHint": "任意。gateway の session key を指定します。空欄の場合は分離されたセッションが自動割り当てされます。" - }, - "hermes": { - "configManagement": "Hermes 設定", - "configDescription": "Hermes は認証情報を ~/.hermes/.env に、設定を ~/.hermes/config.yaml に独自に管理します。プロバイダーを選択し、API キーとモデルを設定してください。codeg が両方のファイルを書き込みます。", - "providerLabel": "プロバイダー", - "providerHint": "プロバイダーによって、Hermes が使用する API キー変数と model.provider が決まります。OAuth プロバイダーは下のターミナルセットアップから設定します。", - "groupApiKey": "API キー プロバイダー", - "groupOauth": "OAuth プロバイダー", - "groupAws": "AWS", - "apiKeyHint": "~/.hermes/.env に保存されます。プロセスには注入されません。Hermes が独自の設定から読み取ります。", - "modelName": "モデル", - "oauthHint": "このプロバイダーは OAuth を使用します。下のセットアップを実行し、ターミナルで認証してください。", - "awsHint": "Bedrock は AWS の認証情報(環境変数または共有設定)を使用します。上でモデル ID を設定し、環境で AWS アクセスを構成してください。", - "unsupportedProvider": "このプロバイダーは構造化フィールドでは編集できません。下の config.yaml 直接編集またはターミナルセットアップを使用してください。", - "setupTitle": "自己管理セットアップ", - "setupHint": "Hermes の対話型セットアップにはターミナルが必要です。下から起動するか、コマンドをコピーして自分で実行してください。", - "runSetup": "Hermes セットアップを実行", - "configureModel": "モデルを設定", - "openConfigFolder": "~/.hermes を開く", - "copyCommand": "コマンドをコピー", - "commandCopied": "コマンドをクリップボードにコピーしました", - "advancedTitle": "詳細: config.yaml を編集", - "rawConfigHint": "~/.hermes/config.yaml を直接編集します。ここで保存すると、ファイルがそのまま上書きされます。", - "saveRawConfig": "config.yaml を保存" - }, - "codebuddy": { - "configManagement": "CodeBuddy の設定", - "configDescription": "CodeBuddy は API キーで認証します。中国版では環境を「中国版(internal)」に設定する必要があります。iOA 版は「iOA」を使用し、海外版は未設定のままにします。", - "apiKeyLabel": "API キー", - "apiKeyHint": "このエージェントの CODEBUDDY_API_KEY として保存されます。または、ターミナルで CodeBuddy CLI からサインインすることもできます。", - "apiKeyHintSelfHosted": "このエージェントの CODEBUDDY_API_KEY として保存されます。プライベート展開で発行されたキーを使用してください。", - "environmentLabel": "環境", - "environmentHint": "CODEBUDDY_INTERNET_ENVIRONMENT を設定します。中国本土では「中国版(internal)」を使用する必要があります。海外版は未設定のままにします。", - "envOverseas": "海外版(デフォルト)", - "envChina": "中国版(internal)", - "envIoa": "iOA", - "envSelfHosted": "プライベート展開(セルフホスト)", - "baseUrlLabel": "デプロイ URL", - "baseUrlPlaceholder": "https://codebuddy.your-company.com", - "baseUrlHint": "CODEBUDDY_BASE_URL として保存され、CodeBuddy をプライベートエンドポイントに向けます。セルフホストではネットワーク環境(CODEBUDDY_INTERNET_ENVIRONMENT)は設定しません。", - "baseUrlInvalid": "有効な http(s) URL を入力してください。", - "loginHint": "API キーがない場合は、ターミナルで「codebuddy」を実行して Tencent アカウントでサインインすることもできます。" - }, - "kimiCode": { - "configManagement": "Kimi Code の設定", - "configDescription": "`kimi acp` は保存済みのログイントークンしか受け付けないため、codeg は ~/.kimi-code/config.toml に管理対象プロバイダーを書き込み、ローカルにゲートトークンを配置します。推論は引き続きご自身のキーで実行されます。", - "statusUnconfigured": "未設定", - "statusDirty": "未保存の変更あり", - "summaryLabel": "有効な設定", - "gateReadyApiKey": "API キーを config.toml に書き込み済み", - "gateReadyLogin": "Kimi アカウントでログイン済み", - "revealConfig": "フォルダーで表示", - "envOverrideWarning": "{keys} が設定されており、config.toml より優先されます。ここで保存すると自動的に削除されます。", - "authModeLabel": "認証方式", - "authModeApiKey": "API キー", - "authModeLogin": "Kimi アカウントログイン(サブスクリプション)", - "authModeApiKeyHint": "config.toml に管理対象プロバイダーを書き込み、セッションを開けるようゲートトークンを配置します。", - "loginHint": "ターミナルで `kimi login` を実行し、Kimi サブスクリプションアカウントでログインしてください。codeg は資格情報を保存せず、Kimi 自身のログインを再利用します。ここで保存すると codeg の API キー用ゲートトークンが削除されます。", - "credentialTitle": "資格情報", - "interfaceTypeLabel": "プロバイダー種別", - "interfaceTypeHint": "Kimi が話すプロバイダープロトコル(config.toml の `type`)。Moonshot / platform.kimi.com のキーには「Kimi / Moonshot」を選びます。", - "endpointLabel": "エンドポイント", - "endpointCustom": "カスタム(OpenAI 互換)", - "endpointHint": "国際 = api.moonshot.ai、中国(platform.kimi.com のキー)= api.moonshot.cn。カスタムは任意の OpenAI 互換エンドポイントを指定できます。", - "regionInternational": "国際(api.moonshot.ai)", - "regionChina": "中国(api.moonshot.cn)", - "baseUrlLabel": "Base URL", - "baseUrlHint": "空欄の場合はプロバイダー SDK の既定値を使用します。", - "apiKeyLabel": "API キー", - "apiKeyHint": "~/.kimi-code/config.toml に書き込まれ、推論に使用されます。platform.kimi.com または platform.kimi.ai で取得できます。", - "vertexProjectLabel": "GCP プロジェクト(GOOGLE_CLOUD_PROJECT)", - "vertexLocationLabel": "GCP リージョン(GOOGLE_CLOUD_LOCATION)", - "vertexHint": "Vertex AI は Google のアプリケーションデフォルト認証情報を使用します。`gcloud auth application-default login` を実行してください(API キー不要)。", - "modelTitle": "モデル", - "modelLabel": "モデル", - "modelHint": "config.toml に書き込まれるモデル id。「テストしてモデルを取得」でキーが実際にアクセスできるモデルを確認できます。", - "maxContextLabel": "最大コンテキスト長", - "maxContextHint": "Kimi のスキーマ上必須です。未指定だと Kimi がモデルブロック全体を破棄し、どのプロンプトも応答が返らなくなります。既定値は 262144。", - "fetchModels": "テストしてモデルを取得", - "fetchModelsOk": "キーは有効です — {count} 件のモデルが利用可能", - "fetchModelsEmpty": "キーは有効ですが、モデルが返されませんでした", - "fetchModelsFailed": "テストに失敗しました", - "fetchModelsNeedsKey": "先に API キーとエンドポイントを入力してください", - "modelNotInList": "このモデルはキーがアクセスできる一覧に含まれていません。Kimi は「モデルが見つかりません」で失敗します。", - "reasoningTitle": "推論", - "reasoningEnableLabel": "有効にする", - "reasoningDescription": "モデルが推論機能を宣言している場合にのみ Kimi は入力欄に「Thinking」ピッカーを表示するため、その宣言を codeg がここで書き込みます。新しいセッションから有効になります。", - "effortsLabel": "選択できるレベル", - "effortsHint": "ここで選んだ値が入力欄の「Thinking」ピッカーの項目になります。Kimi はレベルをそのままプロバイダーへ渡すので、モデルが受け付ける値を選んでください。", - "effortsEmptyHint": "レベルを 1 つも選ばない場合、入力欄は Off / On の 2 段トグルに退化します。", - "effortsCustomPlaceholder": "他のレベルを追加", - "effortsAdd": "追加", - "defaultEffortLabel": "既定のレベル", - "defaultEffortAuto": "Kimi に任せる", - "alwaysThinkingLabel": "モデルは常に推論する — ピッカーから Off を削除", - "fixErrorsFirst": "先に赤色の項目を修正してください", - "errorModelRequired": "モデルは必須です", - "errorMaxContextRequired": "最大コンテキスト長は必須です", - "errorMaxContextInvalid": "正の整数を入力してください", - "errorApiKeyRequired": "API キーは必須です", - "errorApiKeyInvalid": "API キーに改行を含めることはできません", - "errorBaseUrlRequired": "Base URL は必須です", - "errorBaseUrlInvalid": "http:// または https:// で始める必要があります", - "errorVertexProjectRequired": "GCP プロジェクトは必須です", - "errorDefaultEffortUnlisted": "上で選択したレベルのいずれかを指定してください", - "advancedTitle": "詳細設定", - "authTypeLabel": "資格情報の書き込み先", - "authTypeApiKey": "インライン api_key", - "authTypeEnv": "プロバイダーの env サブテーブル", - "authTypeHint": "config.toml 内で API キーを書き込む場所。", - "rawEditorLabel": "config.toml を直接編集", - "rawEditorWarning": "ここで保存するとファイル全体がそのまま上書きされ、上の構造化設定が置き換えられます。", - "rawEditorPlaceholder": "[providers.codeg]\ntype = \"kimi\"\nbase_url = \"https://api.moonshot.cn/v1\"\napi_key = \"sk-...\"" - }, - "authModeOfficialSubscription": "公式サブスクリプション", - "authModeCustomEndpoint": "カスタムエンドポイント", - "authModeCustomEndpointHint": "API URL と API Key を手動で設定してカスタムエンドポイントに接続します。", - "authModeModelProvider": "モデルプロバイダー", - "modelProvider": "モデルプロバイダー", - "modelProviderHint": "設定済みモデルプロバイダーの API URL、API Key、モデルを使用します。", - "selectModelProvider": "モデルプロバイダーを選択", - "noModelProviderAvailable": "このエージェントにはモデルプロバイダーが設定されていません。モデルプロバイダー設定で追加してください。", - "claude": { - "authMode": "認証方式", - "officialSubscription": "公式サブスクリプション", - "officialSubscriptionHint": "Anthropic 公式サブスクリプションを使用、API Key 不要。", - "mainModel": "メインモデル", - "reasoningModel": "推論モデル(thinking)", - "haikuDefaultModel": "デフォルト Haiku モデル", - "sonnetDefaultModel": "デフォルト Sonnet モデル", - "opusDefaultModel": "デフォルト Opus モデル", - "customModelOption": "カスタムモデル ID", - "customModelOptionName": "カスタムモデル名", - "customModelOptionDescription": "カスタムモデルの説明", - "customModelOptionHint": "Claude のモデル選択メニューにカスタム項目を1つ追加します(例: カスタムゲートウェイ/プロキシ経由のモデル)。名前と説明は任意の表示用設定です。", - "effortLevel": "推論レベル", - "effortLevelDefault": "デフォルトレベル", - "effortLevel_low": "低", - "effortLevel_medium": "中", - "effortLevel_high": "高", - "effortLevel_xhigh": "超高", - "sendAttributionHeader": "API に帰属/課金識別子を送信", - "sendAttributionHeaderAria": "API に Claude Code の帰属/課金識別子を送信", - "disableNonessentialTraffic": "テレメトリや不要なネットワークリクエストを無効化", - "disableNonessentialTrafficAria": "Claude Code のテレメトリや不要なネットワークリクエストを無効化" - }, - "dialogs": { - "confirmDeleteProvider": "Provider {providerId} を削除しますか?", - "confirmDeleteProviderDescription": "OpenCode config と auth JSON は同時に更新されます。この操作は元に戻せません。", - "confirmUninstall": "{name} をアンインストールしますか?", - "confirmUninstallDescription": "ローカルにインストールされたバージョンを削除します。後で再インストールできます。", - "customInstallTitle": "{name} をカスタムインストール", - "customInstallDescription": "インストールするバージョンを入力します。再インストールされ、現在インストールされているバージョンを置き換えます。", - "customInstallVersionLabel": "バージョン番号", - "customInstallInvalid": "有効なバージョン番号を入力してください(例: 1.2.3)。", - "customInstallSubmit": "インストール" - }, - "errors": { - "windowsFileLocked": "{name} のファイルは実行中のセッションが使用中のため、Windows では置き換えられません。{name} のセッションをすべて終了してから再試行してください。", - "nativeJsonMustBeObject": "ネイティブJSON設定はオブジェクトである必要があります", - "nativeJsonInvalid": "ネイティブJSON設定の形式エラー: {message}", - "openCodeAuthMustBeObject": "OpenCode の auth.json はJSONオブジェクトである必要があります", - "openCodeAuthInvalid": "OpenCode の auth.json 形式エラー: {message}", - "authMustBeObject": "auth.json はJSONオブジェクトである必要があります", - "authInvalid": "auth.json 形式エラー: {message}", - "providerIdPattern": "Provider ID は英字・数字・アンダースコア・ドット・ハイフンのみ使用できます", - "providerExists": "Provider {providerId} はすでに存在します", - "modelIdPattern": "Model ID は英字・数字・アンダースコア・ドット・コロン・ハイフンのみ使用できます", - "modelExists": "Model {modelId} はすでに存在します" - }, - "warnings": { - "nativeJsonRecoveredStructured": "ネイティブJSON設定が不正のため、構造化設定にリセットしました", - "nativeJsonRecoveredOpenCode": "ネイティブJSON設定が不正のため、OpenCode構造化設定にリセットしました", - "openCodeAuthRecovered": "OpenCode の auth.json が不正のため、デフォルト設定にリセットしました", - "authRecoveredStructured": "auth.json が不正のため、構造化設定にリセットしました" - }, - "toasts": { - "agentActionCompleted": "{name} の {action} が完了しました", - "agentActionFailed": "{name} の {action} に失敗しました", - "localVersion": "ローカルバージョン: {version}", - "installCompletedVersionLater": "インストールが完了しました。バージョンは次回チェック時に更新されます", - "uninstallCompleted": "{name} のアンインストールが完了しました", - "uninstallFailed": "{name} のアンインストールに失敗しました", - "localVersionRemoved": "ローカルバージョンを削除しました", - "saveAgentOrderFailed": "Agent の並び順の保存に失敗しました", - "saveAgentSwitchFailed": "Agent の有効スイッチ保存に失敗しました", - "saveEnvFailed": "環境変数の保存に失敗しました", - "grokSaved": "Grok 設定を保存しました", - "saveGrokNativeFailed": "Grok のネイティブ設定の保存に失敗しました", - "saveGrokApiKeyFailed": "設定は保存されましたが、API キーを保存できませんでした", - "cursorSaved": "Cursor の設定を保存しました", - "saveCursorConfigFailed": "Cursor の設定の保存に失敗しました", - "codexSaved": "Codex設定を保存しました", - "saveCodexNativeFailed": "Codexネイティブ設定の保存に失敗しました", - "geminiSaved": "Gemini設定を保存しました", - "saveGeminiFailed": "Gemini設定の保存に失敗しました", - "providerDeleted": "Provider {providerId} を削除しました", - "providerDeleteFailed": "Provider {providerId} の削除に失敗しました", - "providerSaved": "Provider {providerId} を保存しました", - "saveProviderFailed": "Provider {providerId} の保存に失敗しました", - "openCodeConfigSynced": "OpenCode config と auth JSON が同期されました。", - "openCodeSaved": "OpenCode設定を保存しました", - "saveOpenCodeFailed": "OpenCode設定の保存に失敗しました", - "openClawSaved": "OpenClaw設定を保存しました", - "saveOpenClawFailed": "OpenClaw設定の保存に失敗しました", - "configSaved": "設定を保存しました", - "configSavedHint": "既存のセッションは再度開く必要があります", - "saveConfigManagementFailed": "設定管理の保存に失敗しました", - "clineSaved": "Cline設定を保存しました", - "saveClineFailed": "Cline設定の保存に失敗しました", - "hermesSaved": "Hermes設定を保存しました", - "saveHermesFailed": "Hermes設定の保存に失敗しました", - "codeBuddySaved": "CodeBuddy の設定を保存しました", - "saveCodeBuddyFailed": "CodeBuddy の設定の保存に失敗しました", - "kimiCodeSaved": "Kimi Code の設定を保存しました", - "saveKimiCodeFailed": "Kimi Code の設定の保存に失敗しました", - "deepseekSaved": "DeepSeek の設定を保存しました", - "saveDeepSeekFailed": "DeepSeek の設定の保存に失敗しました", - "modelProviderRequired": "保存する前にモデルプロバイダーを選択してください。", - "affectedRunningSessions": "{count} 件の実行中セッションは再接続すると変更が適用されます", - "providerConnected": "{providerId} を接続しました", - "connectFailed": "{providerId} の接続に失敗しました", - "providerDisconnected": "{providerId} を切断しました", - "disconnectFailed": "{providerId} の切断に失敗しました", - "catalogRefreshed": "カタログを更新しました — {count} 個のプロバイダー", - "catalogRefreshFailed": "カタログの更新に失敗しました", - "piSaved": "Pi 設定を保存しました", - "savePiFailed": "Pi 設定の保存に失敗しました", - "piRuntimeSaved": "Pi ランタイムを保存しました", - "savePiRuntimeFailed": "Pi ランタイムの保存に失敗しました", - "piBinaryInstalled": "pi をインストールしました", - "piBinaryInstallFailed": "pi のインストールに失敗しました", - "piBinaryUninstalled": "pi をアンインストールしました", - "piBinaryUninstallFailed": "pi のアンインストールに失敗しました", - "savePiTrustFailed": "ワークスペースの信頼設定の保存に失敗しました" - }, - "version": { - "statusLabel": "バージョン状態", - "notInstalled": "未インストール", - "remoteLocal": "リモート: {remoteVersion} · ローカル: {localVersion}", - "localOnly": "ローカル:{localVersion}", - "localInstalled": "{versionText}。インストール済みです。", - "platformUnsupported": "{versionText}。現在のプラットフォームではこのエージェントをサポートしていません。", - "uvxNotReady": "{versionText}。uv ランタイムが未インストールです。下の uv チェックからインストールするとこのエージェントを使用できます。", - "clickInstall": "{versionText}。右側の「インストール」をクリックしてください。", - "localUnrecognized": "{versionText}。ローカルバージョンは比較できません。上書きインストールのためアップグレードを試してください。", - "upgradeAvailable": "{versionText}。アップグレード可能です。", - "remoteUnavailable": "{versionText}。現在リモートバージョンは取得できません。", - "latest": "{versionText}。すでに最新です。" - }, - "adapter": { - "label": "ACP アダプター", - "badge": "ACP アダプター", - "badgeHint": "このエージェントで Codeg がインストールするのはベンダー CLI ではなく ACP アダプターのパッケージです。両者は独立しており、設定は共有されます。", - "learnMore": "詳細", - "missingWithNative": "お使いの {nativeLabel} を {nativePath} で検出しました。Codeg はエージェントを ACP で駆動しますが、この CLI 自体は ACP に対応していないため、別パッケージのアダプター {adapterPackage}(Agent Client Protocol プロジェクトが保守。当初は Zed チーム)が必要です。独自のランタイムを同梱しており、既存の {nativeCmd} コマンドを変更も置き換えもしません。読み込む設定は同じ {configDir} なので、ログインと設定はそのまま引き継がれます。下のボタンからインストールしてください。", - "missing": "Codeg はエージェントを ACP で駆動しますが、{nativeLabel} 自体は ACP に対応していないため、別パッケージのアダプター {adapterPackage}(Agent Client Protocol プロジェクトが保守。当初は Zed チーム)が必要です。独自のランタイムを同梱しているので {nativeCmd} CLI を先に入れる必要はありません。すでにお持ちの場合も両者は共存し、{configDir} のログインと設定を共有します。下のボタンからインストールしてください。", - "readyWithNative": "アダプター {adapterCmd} はインストール済みです。Codeg が起動するのはこちらで、あなたの {nativeCmd}({nativePath})ではありません。両者は独立したパッケージとして共存し、どちらも {configDir} を読むためログインと設定は共有されます。", - "ready": "アダプター {adapterCmd} はインストール済みで、Codeg が起動するのはこれです。独自のランタイムを同梱しているため {nativeLabel} は不要です。後から入れても両者は共存し、{configDir} を共有します。" - }, - "cline": { - "configDescription": "Cline API プロバイダーと認証情報を設定します。設定は ~/.cline/data/ に保存されます。" - }, - "opencodePlugins": { - "title": "OpenCode プラグイン", - "declared": "宣言済みプラグイン", - "noPlugins": "opencode.json にプラグインが宣言されていません", - "status": { - "installed": "インストール済み", - "missing": "未インストール" - }, - "installAll": "不足プラグインをすべてインストール", - "pinVersions": "@latest バージョンを固定", - "install": "インストール", - "uninstall": "アンインストール", - "refresh": "更新", - "success": "すべてのプラグインが正常にインストールされました", - "failed": "プラグイン操作に失敗しました" - }, - "pi": { - "configManagement": "Pi 設定", - "configDescription": "Pi はモデルプロバイダーの API キーで認証します。キーは ~/.pi/agent/auth.json に、モデル選択は settings.json に書き込まれます。", - "providerLabel": "プロバイダー", - "modelLabel": "モデル", - "thinkingLabel": "思考", - "thinking": { - "off": "オフ", - "low": "低", - "medium": "中", - "high": "高", - "minimal": "最小", - "xhigh": "最高" - }, - "apiKeyLabel": "API キー", - "apiKeyHint": "選択したプロバイダーの ~/.pi/agent/auth.json に保存されます。", - "apiKeySetPlaceholder": "••••••(保存済み・空欄で維持)", - "saveConfig": "Pi 設定を保存", - "providerModelRequired": "プロバイダーとモデルは必須です", - "runtimeTitle": "ランタイム", - "runtimeDescription": "どの pi を実行するか選択します。デフォルト、または自分の pi ビルドを指定します。", - "modeDefault": "デフォルト pi", - "modeDefaultHint": "内蔵の pi-acp アダプターで PATH 上の pi を起動します。 pi のインストール:npm install -g @earendil-works/pi-coding-agent", - "modeCustom": "カスタム pi", - "modeCustomHint": "自分の pi ビルド・インストール・ラッパーを実行します。", - "commandLabel": "pi コマンドまたはパス", - "commandHint": "絶対パス、PATH 上のコマンド名、またはラッパースクリプト(例: monorepo の ./pi-test.sh)。", - "commandNotFound": "コマンドが見つかりません", - "validate": "検証", - "advanced": "詳細設定", - "configDirLabel": "設定ディレクトリ (PI_CODING_AGENT_DIR)", - "sessionDirLabel": "セッションディレクトリ (PI_CODING_AGENT_SESSION_DIR)", - "flagsHint": "pi-acp はカスタム pi フラグ(--approve、-e など)を転送しません。pi をスクリプトでラップしてコマンドに指定してください。", - "customIncomplete": "保存するには pi コマンドを入力してください", - "saveRuntime": "ランタイムを保存", - "providerPlaceholder": "プロバイダーを選択", - "customProvider": "カスタムプロバイダー…", - "providerIdLabel": "プロバイダー ID", - "apiProtocolLabel": "API プロトコル", - "baseUrlLabel": "API エンドポイント(Base URL)", - "customProviderHint": "~/.pi/agent/models.json にエンドポイント向けのプロバイダーを定義します。多くのセルフホスト/プロキシは openai-completions を使用します。", - "baseUrlRequired": "API エンドポイント(Base URL)は必須です", - "binaryTitle": "pi バイナリ (pi-coding-agent)", - "binaryDescription": "pi-acp はこの pi バイナリを実行します。ここでインストールするか、下で独自のビルドを指定できます。", - "binaryInstalled": "インストール済み", - "binaryMissing": "未インストール", - "binaryChecking": "確認中…", - "installBinary": "pi をインストール", - "installing": "インストール中…", - "recheck": "再確認", - "configDirSkillsNote": "カスタム設定ディレクトリを指定すると、設定画面で管理するスキル・エキスパート・オフィスツールはこの pi に適用されません。スキルはそのフォルダー内で直接管理してください。", - "projectTrustTitle": "プロジェクトの信頼", - "projectTrustDescription": "pi にプロジェクトファイルの読み込みを許可したフォルダーです。信頼したフォルダーでは、そのリポジトリの .pi/extensions が pi の起動時にコードを実行します。配下のすべてのフォルダーに適用され、ターミナルで pi を実行するときにも使われます。", - "projectTrustLoading": "読み込み中…", - "projectTrustEmpty": "まだ判断したフォルダーはありません。", - "projectTrustTrusted": "信頼済み", - "projectTrustDenied": "信頼しない", - "projectTrustRevoke": "取り消す", - "reasoningTitle": "推論", - "reasoningEnableLabel": "有効にする", - "reasoningDescription": "モデルが推論能力を宣言している場合にのみ、pi は推論強度を送信します。未宣言のモデルではすべてのレベルが Off に丸められるため、入力欄のセレクターは触れた瞬間に戻ってしまいます。models.json のこのモデルの項目に書き込まれます。", - "levelsLabel": "選択できるレベル", - "levelsHint": "入力欄の推論セレクターの項目になります。エンドポイントが受け付ける値を選んでください。ここにないレベルは pi が拒否します。", - "levelsEmptyError": "レベルを 1 つ以上選んでください。1 つも選ばないと pi は Off に戻ります。", - "wireValuesTitle": "詳細: プロバイダーに送る値", - "wireValuesHint": "空欄ならレベル名をそのまま送信します。エンドポイントが別の表記を求める場合のみ設定してください(Google 系は LOW / HIGH)。", - "defaultLevelUnlisted": "このレベルは上の選択リストにありません。pi が丸めてしまいます。" - }, - "addCustomAgent": "カスタムエージェントを追加", - "addCustomAgentHint": "ACP 対応のエージェントを追加できます。公開 ACP レジストリから選ぶか、レジストリ情報を貼り付けてください。", - "customAgentFromRegistry": "ACP レジストリ", - "customAgentManual": "手動入力", - "customAgentSearchPlaceholder": "エージェントを検索…", - "customAgentLoadingCatalog": "ACP レジストリを読み込み中…", - "customAgentRetry": "再試行", - "customAgentNoResults": "該当するエージェントがありません", - "customAgentAdd": "追加", - "customAgentAlreadyAdded": "追加済み", - "customAgentUnsupportedPlatform": "このプラットフォーム向けのビルドがありません", - "customAgentAdded": "{name} を追加しました", - "customAgentIdLabel": "レジストリ ID", - "customAgentNameLabel": "表示名", - "customAgentVersionLabel": "バージョン", - "customAgentSpecLabel": "配布情報(JSON)", - "customAgentSpecHint": "ACP レジストリの distribution オブジェクトと同じ形式です。npx・uvx・binary の各チャネルに対応し、レジストリ項目全体の貼り付けも可能です。npx/uvx の cmd はパッケージがインストールする実行コマンド名で、省略時はパッケージ名から導出されるため、異なる場合は指定してください。binary はプラットフォームキーごとに指定し(このマシンは {platform})、cmd はアーカイブ内の起動パス、sha256 は任意でダウンロードを検証します。", - "customAgentTemplateLabel": "テンプレート", - "customAgentKindLabel": "起動方法", - "customAgentInvalidJson": "JSON として不正です", - "customAgentNoDistribution": "npx・uvx・binary のいずれの配布も見つかりません", - "customAgentCancel": "キャンセル", - "customAgentSave": "エージェントを追加", - "customAgentSaveChanges": "変更を保存", - "customAgentEdit": "エージェントを編集", - "customAgentEditHint": "名前・アイコン・配布情報・スキル宣言を変更できます。エージェント ID は変更できません。", - "customAgentEditNotFound": "カスタムエージェント {id} が見つかりません", - "customAgentSaved": "{name} を保存しました", - "customAgentVersionProbeLabel": "バージョン確認コマンド(任意)", - "customAgentVersionProbeHint": "ローカルにインストールされたバージョンを表示するコマンドです。空欄の場合はエージェントコマンドに --version を付けて実行します。", - "customAgentRemove": "エージェントを削除", - "customAgentRemoveHint": "エージェント定義を削除します。既存の会話の履歴は残り、エージェントを起動できなくなるだけです。", - "customAgentIconLabel": "アイコン(任意)", - "customAgentIconUpload": "アップロード", - "customAgentIconReplace": "変更", - "customAgentIconClear": "アイコンを削除", - "customAgentIconHint": "エージェントと共に保存されるためオフラインでも表示できます。指定しない場合は色付きの頭文字を使います。", - "customAgentSkillsLabel": "Skills(共有 .agents/skills)", - "customAgentSkillsHint": "このエージェントが共有の .agents/skills ディレクトリ(グローバルおよびプロジェクト)を読み取ることを宣言し、すべてのスキルマトリクスに追加します。共有ディレクトリにリンクしたスキルは、同じディレクトリを読むほかのエージェントからも見えます。", - "customAgentSkillsDirLabel": "専用スキルディレクトリ", - "customAgentSkillsDirHint": "このエージェントがスキルを読み込むディレクトリの絶対パスです。共有ストアと併用も単独利用も可能です。~ はホームディレクトリに展開され、リンクしたスキルはまずここに配置されます。", - "customAgentMcpLabel": "MCP サポート", - "customAgentMcpHint": "セッション開始時に codeg 内蔵の codeg-mcp コンパニオンをこのエージェントへ渡します。委任・リアルタイムフィードバック・タスクツールはこの経路を使います。MCP サーバーを受け付けず接続に失敗するエージェントではオフにしてください。設定は次回の接続から有効になります。", - "customAgentIconNotAnImage": "画像ファイルを選んでください。", - "customAgentIconTooLarge": "アイコンは {limit} KB 未満にしてください。", - "customAgentIconReadFailed": "その画像を読み込めませんでした。", - "customAgentRemoveConfirm": "{name} を削除しますか?既存の会話は残りますが、起動できなくなります。", - "customAgentRemoveWithData": "記録された会話履歴も削除する", - "customAgentRemoved": "{name} を削除しました", - "customAgentBadge": "カスタム", - "customAgentNotLaunchable": "この環境では起動できません: {reason}" - }, - "SettingsPages": { - "agentsLoading": "エージェント設定を読み込み中...", - "skillPacksLoading": "スキルパックを読み込み中…" - }, - "GeneralSettings": { - "loading": "読み込み中...", - "sectionTitle": "一般", - "sectionDescription": "デフォルトターミナル、レンダリング高速化、マルチエージェント委譲などの共通設定をここで一括管理します。", - "terminalTitle": "デフォルトターミナル", - "terminalDescription": "ターミナルバーやファイルツリーから新しいターミナルタブを開くときに使用するシェルを選択します。エージェントが codeg にコマンドライン全体の実行を依頼するときにも使われます。", - "terminalSystemDefault": "システムデフォルト", - "terminalPowerShell7": "PowerShell 7 (pwsh)", - "terminalWindowsPowerShell": "Windows PowerShell", - "terminalCmd": "コマンドプロンプト (cmd)", - "terminalSaveFailed": "ターミナル設定の保存に失敗しました: {message}", - "terminalShellCustom": "カスタムパス", - "terminalShellCustomPath": "Shell パス", - "terminalShellCustomPlaceholder": "/usr/local/bin/fish", - "terminalShellCustomSave": "保存", - "terminalShellCustomHint": "絶対パス、または PATH で解決可能なコマンド名を指定します。", - "terminalShellNotInstalled": "未インストール", - "terminalShellNotFoundWarning": "このパスはホスト上に存在しません。", - "terminalCurrentShell": "現在使用中: {path}", - "renderingDescription": "アプリで黒画面や描画不具合が発生する場合(一部の AMD GPU や Intel 内蔵 GPU で報告あり)、ハードウェアアクセラレーションを無効化してください。Windows デスクトップ版のみ有効です。", - "disableHardwareAcceleration": "ハードウェアアクセラレーションを無効化", - "renderingSaveFailed": "レンダリング設定の保存に失敗しました: {message}", - "restartRequired": "保存しました。再起動後に反映されます。", - "restartNow": "今すぐ再起動", - "restartFailed": "再起動に失敗しました: {message}", - "loadFailed": "読み込みに失敗しました: {message}" - }, - "LoginPage": { - "documentTitle": "ログイン - codeg", - "brand": "Codeg", - "subtitle": "デスクトップアプリに接続するためのアクセストークンを入力してください", - "tokenPlaceholder": "アクセストークン", - "connect": "接続", - "connecting": "接続中...", - "helpText": "トークンはデスクトップアプリの 設定 → Web サービス で取得できます", - "invalidToken": "トークンが無効です。確認して再度お試しください", - "connectionFailed": "接続失敗 (HTTP {status})", - "networkError": "サーバーに接続できません" - }, - "CommitPage": { - "title": "コミット", - "invalidFolderId": "無効なフォルダID", - "loadingRepo": "リポジトリを読み込み中..." - }, - "MergePage": { - "title": "コンフリクトの解決", - "invalidFolderId": "無効なフォルダID", - "loadingRepo": "リポジトリを読み込み中...", - "localVersion": "ローカル(自分側)", - "result": "結果", - "remoteVersion": "リモート(相手側)", - "acceptLocal": "ローカルを採用", - "acceptRemote": "リモートを採用", - "markResolved": "解決済みにする", - "abortMerge": "中止", - "completeMerge": "マージ完了", - "unresolvedConflicts": "ファイルに未解決のコンフリクトマーカーがあります", - "fileResolved": "ファイルが解決されました", - "allResolved": "すべてのコンフリクトが解決されました", - "conflictFiles": "コンフリクトファイル", - "loadingFile": "ファイルを読み込み中...", - "preparingMerge": "マージを準備中...", - "selectFile": "解決するファイルを選択してください", - "noConflicts": "コンフリクトファイルなし", - "skipFile": "スキップ", - "abortSuccess": "操作が中止されました", - "applyAllNonConflicting": "競合しない変更をすべて適用", - "applyLeftNonConflicting": "ローカルを適用", - "applyRightNonConflicting": "リモートを適用" - }, - "ImportSessions": { - "title": "ローカルセッションをインポート", - "scanningTitle": "ローカルエージェントのセッションをスキャン中…", - "scanningHint": "各エージェントのローカルセッションストアを走査しています。履歴が多い場合は時間がかかることがあります。インポート済みのセッションはあわせて更新されます。", - "scanFailed": "スキャンに失敗しました", - "retry": "再試行", - "rescan": "再スキャン", - "empty": "ローカルセッションが見つかりません", - "emptyHint": "このマシンにはエージェントのセッションストアが見つかりませんでした。", - "noMatches": "現在のフィルターに一致するセッションはありません", - "searchPlaceholder": "タイトルまたはパスを検索…", - "allAgents": "すべてのエージェント", - "onlyImportable": "インポート可能のみ", - "selectAll": "すべて選択", - "clearSelection": "クリア", - "expandAll": "すべて展開", - "collapseAll": "すべて折りたたむ", - "summaryCounts": "{total} セッション · インポート可能 {importable} · {folders} フォルダー", - "noFolderSkipped": "プロジェクトフォルダーのない {count} 件をスキップしました", - "folderNew": "新規", - "folderCounts": "インポート可能 {importable}/{total}", - "toggleFolderAria": "{name} のインポート可能なセッションをすべて選択", - "toggleSessionAria": "セッション {title} を選択", - "statusImported": "インポート済み", - "statusDeleted": "削除済み", - "untitled": "無題のセッション", - "messageCount": "{count} 件のメッセージ", - "selectedCount": "{count} 件選択中", - "importSelected": "選択項目をインポート", - "importing": "インポート中…", - "close": "閉じる", - "doneTitle": "インポート完了", - "doneImported": "インポート", - "doneUpdated": "更新済み", - "doneSkipped": "スキップ", - "doneCreatedFolders": "作成フォルダー", - "doneNotFound": "見つからず", - "doneFailed": "失敗", - "continueImport": "続けてインポート", - "toasts": { - "importFailed": "インポートに失敗しました: {message}" - } - }, - "Folder": { - "workspaceStatus": { - "degradedTitle": "リアルタイム更新は利用できません", - "degradedHint": "ウォッチャーの起動に失敗しました(アクセス権限エラーなど)。最新の変更を反映するには手動で更新してください。", - "retry": "再試行", - "retrying": "再試行中..." - }, - "common": { - "all": "すべて", - "cancel": "キャンセル", - "close": "閉じる", - "closeOthers": "他を閉じる", - "closeAll": "すべて閉じる", - "confirm": "確認", - "save": "保存", - "delete": "削除", - "rename": "名前を変更", - "loading": "読み込み中...", - "refresh": "更新", - "refreshing": "更新中...", - "create": "作成", - "createAndSwitch": "作成して切り替え", - "openFile": "ファイルを開く", - "viewDiff": "差分を見る", - "push": "プッシュ..." - }, - "statusLabels": { - "in_progress": "進行中", - "pending_review": "レビュー", - "completed": "完了", - "cancelled": "キャンセル済み" - }, - "sidebar": { - "title": "会話", - "locateActiveConversation": "アクティブな会話を表示", - "expandAllGroups": "すべてのグループを展開", - "collapseAllGroups": "すべてのグループを折りたたむ", - "newConversation": "新しい会話", - "newConversationShort": "新規", - "newChat": "新しい会話", - "search": "検索", - "noConversationsFound": "会話が見つかりません。", - "importLocalSessions": "ローカルセッションをインポート", - "importing": "インポート中...", - "error": "エラー: {message}", - "completeAllSessions": "すべてのセッションを完了", - "completeAllReviewTitle": "すべてのレビューセッションを完了しますか?", - "completeAllReviewDescription": "これにより、レビュー中の {count, plural, one {# 件のセッション} other {# 件のセッション}} が完了としてマークされます。", - "completing": "完了処理中...", - "toasts": { - "importedSessions": "{imported, plural, one {# 件のセッション} other {# 件のセッション}} をインポートし、{skipped} 件をスキップしました", - "importedAndUpdated": "{imported, plural, one {# 件のセッション} other {# 件のセッション}} をインポートし、{updated, plural, one {# 件のタイトル} other {# 件のタイトル}} を更新し、{skipped} 件をスキップしました", - "updatedTitles": "{updated, plural, one {# 件のタイトル} other {# 件のタイトル}} を更新し、{skipped} 件をスキップしました", - "noNewSessionsFound": "新しいセッションは見つかりませんでした({skipped} 件をスキップ)", - "importFailed": "インポートに失敗しました: {message}", - "reviewCompleted": "{count, plural, one {# 件のレビューセッション} other {# 件のレビューセッション}} を完了にしました", - "completeReviewFailed": "レビューセッションの完了処理に失敗しました: {message}", - "folderOpened": "フォルダ {name} を開きました", - "folderRemoved": "フォルダ {name} を削除しました", - "openFolderFailed": "フォルダを開けませんでした", - "removeFolderFailed": "フォルダの削除に失敗しました: {message}", - "reorderFoldersFailed": "フォルダの並べ替えに失敗しました: {message}", - "changeFolderColorFailed": "色の変更に失敗しました: {message}", - "setFolderAliasFailed": "エイリアスの設定に失敗しました: {message}", - "changeFolderDefaultAgentFailed": "デフォルトエージェントの設定に失敗しました: {message}" - }, - "statsLabel": "{folders} フォルダ · {convos} 会話", - "reorderHandle": "ドラッグして並べ替え", - "openFolder": "フォルダを開く", - "searchPlaceholder": "会話を検索...", - "viewOptions": "表示オプション", - "showCompleted": "完了した会話を表示", - "showWorktrees": "ワークツリーフォルダを表示", - "showRecent": "「最近」グループを表示", - "moreOptions": "その他のオプション", - "sortBy": "並び替え", - "sortByCreatedAt": "作成時刻順", - "sortByUpdatedAt": "更新時刻順", - "sectionOrder": "セクションの順序", - "sectionOrderMoveUp": "上へ移動", - "sectionOrderMoveDown": "下へ移動", - "sectionOrderItemLabel": "{name} — {total} 件中 {position} 番目", - "statusRunningBadge": "実行中", - "runningCountBadge": "{count} 件の会話が実行中", - "statusCancelledBadge": "キャンセル済み", - "worktreeRemovedBadge": "元の worktree は削除済み", - "conversationCountUnit": "{count} 件", - "emptyFolderHint": "会話がありません", - "noMatchingConversations": "一致する会話がありません", - "noUnfinishedConversations": "未完了の会話はありません。右上のメニューから「完了した会話を表示」を有効にできます。", - "removeFolderConfirmTitle": "このフォルダをワークスペースから削除しますか?", - "removeFolderConfirmDescription": "\"{name}\" をワークスペースから削除しますか?関連するタブとターミナルが閉じられます。", - "folderHeaderMenu": { - "manageConversations": "会話の管理…", - "manageLinks": "リンク済みフォルダー", - "changeColor": "色を変更", - "useThemeColor": "アプリのテーマを使用", - "setDefaultAgent": "デフォルトエージェントを設定", - "defaultAgentNone": "設定なし(グローバルを使用)", - "agentUnavailableSuffix": "(利用不可)", - "loadingAgents": "エージェントを読み込み中…", - "setAlias": "エイリアスを設定…", - "setAliasTitle": "フォルダーのエイリアスを設定", - "setAliasPlaceholder": "エイリアスを入力(空欄でクリア)", - "setAliasSave": "保存", - "setAliasCancel": "キャンセル", - "removeFromWorkspace": "ワークスペースから削除" - }, - "manageConversations": { - "title": "会話の管理", - "searchPlaceholder": "タイトルで検索…", - "agentFilterAll": "すべてのエージェント", - "statusFilterAll": "すべてのステータス", - "folderFilterAll": "すべてのフォルダ", - "branchFilterAll": "すべてのブランチ", - "branchNone": "ブランチなし", - "branchSearchPlaceholder": "ブランチを検索…", - "noMatchingBranches": "一致するブランチがありません", - "selectAllVisible": "すべて選択", - "deselectAll": "選択を解除", - "selectedCount": "{count} 件選択中", - "matchedCount": "{count} 件該当", - "untitledConversation": "無題の会話", - "setStatus": "ステータスを変更…", - "deleteSelected": "削除", - "noConversations": "このフォルダには会話がありません。", - "noConversationsWorkspace": "ワークスペースに会話がありません。", - "noMatchingConversations": "条件に一致する会話がありません。", - "confirmDeleteTitle": "{count} 件の会話を削除しますか?", - "confirmDeleteDescription": "この操作は元に戻せません。", - "toastDeleted": "{count} 件の会話を削除しました", - "toastStatusUpdated": "{count} 件の会話のステータスを更新しました", - "toastOpFailed": "操作に失敗しました: {message}" - }, - "sectionPinned": "ピン留め", - "sectionFolders": "フォルダ", - "sectionChats": "チャット", - "sectionRecent": "最近", - "noChats": "チャットがありません", - "noRecent": "最近の会話はありません", - "showMoreRecent": "さらに表示({count})", - "noFolders": "開いているフォルダがありません", - "newChatAction": "新しいチャット", - "automations": "オートメーション", - "tasks": "ToDo タスク", - "loadingSubsessions": "サブ会話を読み込み中…" - }, - "conversation": { - "reloadFailed": "会話の再読み込みに失敗しました: {message}", - "reloaded": "会話を再読み込みしました", - "reload": "再読み込み", - "activeConversationIndicator": "アクティブな会話", - "newConversation": "新しい会話", - "closeConversation": "会話を閉じる", - "copyText": "テキストをコピー", - "copyTextSuccess": "コピーしました", - "copyTextFailed": "コピーに失敗しました", - "forkSession": "セッションをフォーク", - "forkSessionSuccess": "セッションのフォークに成功しました", - "forkSessionFailed": "セッションのフォークに失敗しました:{error}", - "exportConversation": "会話をエクスポート", - "exportImage": "画像", - "exportMarkdown": "Markdown", - "exportHtml": "HTML", - "exportSuccess": "会話をエクスポートしました", - "exportFailed": "エクスポートに失敗しました", - "exportImageTooLong": "会話が長すぎるため、画像としてエクスポートできません", - "exportLabels": { - "untitledConversation": "無題の会話", - "agent": "エージェント", - "model": "モデル", - "status": "ステータス", - "started": "開始", - "updated": "更新", - "tokens": "トークン統計", - "duration": "所要時間", - "inputTokens": "入力", - "outputTokens": "出力", - "cacheRead": "キャッシュ読取", - "cacheWrite": "キャッシュ書込", - "user": "ユーザー", - "assistant": "アシスタント", - "system": "システム", - "toolResult": "結果", - "toolError": "エラー" - }, - "moreActions": "その他の操作" - }, - "sessionDetails": { - "menuLabel": "セッション詳細", - "noActiveSession": "アクティブなセッションがありません", - "title": "セッション詳細", - "subtitle": "セッションのメタデータとトークン使用量", - "fieldTitle": "タイトル", - "untitled": "無題の会話", - "sessionId": "セッション ID", - "externalId": "拡張 ID", - "agent": "エージェント", - "model": "モデル", - "status": "ステータス", - "gitBranch": "Git ブランチ", - "parentId": "親セッション", - "tokensHeading": "トークン使用量", - "totalTokens": "合計", - "inputTokens": "入力", - "outputTokens": "出力", - "cacheWrite": "キャッシュ書込", - "cacheRead": "キャッシュ読取", - "contextWindow": "コンテキストウィンドウ", - "duration": "所要時間", - "loadingStats": "トークン使用量を読み込み中…", - "loadFailed": "トークン使用量の読み込みに失敗しました", - "noStats": "使用量の記録なし", - "timestampsHeading": "日時", - "createdAt": "作成日時", - "updatedAt": "更新日時", - "none": "—", - "copyField": "{field}をコピー", - "copiedField": "{field}をコピーしました" - }, - "conversationCard": { - "untitledConversation": "無題の会話", - "newConversation": "新しい会話", - "rename": "名前を変更", - "status": "ステータス", - "delete": "削除", - "importLocalSessions": "ローカルセッションをインポート", - "importing": "インポート中...", - "renameConversation": "会話名を変更", - "deleteConversationTitle": "会話を削除しますか?", - "deleteConversationDescription": "\"{title}\" を削除します。この操作は元に戻せません。", - "cancel": "キャンセル", - "save": "保存", - "pin": "ピン留め", - "unpin": "ピン留めを解除", - "markCompleted": "完了にする", - "reopen": "再開する", - "expandSubsessions": "サブ会話を展開", - "collapseSubsessions": "サブ会話を折りたたむ" - }, - "search": { - "dialogTitle": "検索", - "dialogTitleWithFolder": "検索 — {name}", - "tabConversations": "会話", - "tabFiles": "ファイル", - "placeholder": "会話を検索...", - "filePlaceholder": "ファイルまたはディレクトリを検索...", - "allAgents": "すべて", - "searching": "検索中...", - "typeToSearch": "入力して会話を検索", - "typeToSearchFiles": "入力してファイルまたはディレクトリを検索", - "noResults": "結果が見つかりません。", - "untitledConversation": "無題の会話" - }, - "folderTitleBar": { - "showSidebar": "サイドバーを表示", - "hideSidebar": "サイドバーを非表示", - "toggleTerminal": "ターミナルを切り替え", - "toggleAuxPanel": "補助パネルを切り替え", - "search": "検索", - "openSettings": "設定を開く", - "backToConversations": "会話に戻る", - "withShortcut": "{label}({shortcut})" - }, - "statusBar": { - "connection": { - "connected": "接続済み", - "connecting": "接続中...", - "prompting": "応答中...", - "error": "接続エラー", - "disconnected": "未接続", - "tooltip": "{agent}:{status}", - "tooltipError": "{agent}:{error}", - "title": "エージェント接続", - "triggerAria": "エージェント接続: {status}", - "workingDir": "作業ディレクトリ", - "sessionId": "セッション ID", - "viewerNote": "他のクライアントが所有するセッションに接続しています。再接続してもこのビューが接続し直されるだけです。", - "reconnectInterrupts": "再接続するとエージェントが再起動し、進行中の処理が中断されます。", - "reconnect": "再接続", - "reconnecting": "再接続中...", - "reconnectUnavailable": "再接続できるセッションがまだありません。" - }, - "tasks": { - "title": "タスク" - }, - "alerts": { - "title": "アラート", - "empty": "アラートなし", - "details": "詳細" - }, - "stats": { - "conversations": "{count} 件の会話", - "openUsage": "セッション統計とトークン使用量を表示" - }, - "tokens": { - "contextWindowUsageAria": "コンテキストウィンドウ使用率", - "contextWindow": "コンテキストウィンドウ", - "usedMax": "使用 / 最大", - "tokenUsage": "トークン使用量", - "input": "入力", - "output": "出力", - "cacheRead": "キャッシュ読み取り", - "cacheWrite": "キャッシュ書き込み", - "total": "合計" - } - }, - "auxPanel": { - "tabs": { - "files": "ファイル", - "changes": "変更", - "commits": "コミット" - }, - "noFolderTitle": "開いているフォルダがありません", - "noFolderHint": "フォルダを開くとここに表示されます" - }, - "windowControls": { - "minimizeWindow": "ウィンドウを最小化", - "minimize": "最小化", - "maximizeWindow": "ウィンドウを最大化", - "maximize": "最大化", - "restoreWindow": "ウィンドウを元に戻す", - "restore": "元に戻す", - "closeWindow": "ウィンドウを閉じる", - "close": "閉じる" - }, - "tabs": { - "closeConversationTab": "会話タブを閉じる", - "close": "閉じる", - "closeOthers": "他を閉じる", - "splitRight": "右に分割", - "splitDown": "下に分割", - "splitAndMoveRight": "分割して右へ移動", - "splitAndMoveDown": "分割して下へ移動", - "moveToOppositeGroup": "反対側のグループへ移動", - "moveToGroup": "グループへ移動", - "groupLabel": "グループ {index}", - "changeSplitterOrientation": "分割方向を切り替え", - "unsplit": "分割を解除", - "unsplitAll": "すべての分割を解除", - "closeAll": "すべて閉じる", - "tileDisplay": "タイル表示", - "untileDisplay": "タイル解除" - }, - "fileWorkspace": { - "files": "ファイル", - "closeFileTab": "ファイルタブを閉じる", - "close": "閉じる", - "closeOthers": "他を閉じる", - "closeAll": "すべて閉じる", - "preview": "プレビュー", - "editSource": "ソースを編集", - "maximize": "最大化", - "restore": "元に戻す", - "emptyDirectory": "空のフォルダー" - }, - "terminal": { - "rename": "名前を変更", - "close": "閉じる", - "closeOthers": "他を閉じる", - "closeAll": "すべて閉じる", - "hideTerminal": "ターミナルを隠す ({shortcut})", - "openFolderFirst": "先にフォルダを開いてください" - }, - "workspaceDialog": { - "title": "フォルダーを開く", - "manageTitle": "リンク済みフォルダー", - "addTargetsTitle": "リンクするフォルダーを追加", - "pickRootDescription": "このワークスペースのメインフォルダーを選択します。", - "linksDescription": "他のフォルダーをサブディレクトリとしてリンクすると、エージェントは 1 つのワークスペースから横断的に作業できます。", - "addTargetsDescription": "フォルダーを 1 つ以上選択してください。それぞれがワークスペースのサブディレクトリになります。", - "useSystemPicker": "システムの選択画面", - "next": "次へ", - "back": "戻る", - "done": "完了", - "change": "変更", - "addFolders": "フォルダーを追加", - "addSelected": "追加", - "addSelectedCount": "{count} 件を追加", - "createCount": "{count} 件のフォルダーをリンク", - "discardPending": "破棄", - "noLinks": "リンクされたフォルダーはまだありません。", - "gitExclude": "リンクを git status に出さない", - "rename": "名前を変更", - "unlink": "リンクを解除", - "repair": "リンクを作り直す", - "saveName": "保存", - "cancelRename": "キャンセル", - "removePending": "削除", - "willAppearAs": "ワークスペースでは {name} として表示されます", - "renamedForDuplicate": "改名しました — {base} は別のリンクが使用中です", - "renamedForExistingEntry": "改名しました — このフォルダーには既に {base} があります", - "partiallyCreated": "{count} 件のフォルダーのみリンクできました", - "openFailed": "フォルダーを開けませんでした", - "previewFailed": "選択したフォルダーを確認できませんでした", - "createFailed": "フォルダーをリンクできませんでした", - "renameFailed": "名前を変更できませんでした", - "removeFailed": "リンクを解除できませんでした", - "repairFailed": "リンクを作り直せませんでした", - "status": { - "ok": "リンク済み", - "missing": "リンクがこのフォルダーから消えています", - "conflicted": "この名前は別の項目が使用しています", - "broken": "リンク先のフォルダーが存在しません" - }, - "nameIssue": { - "empty": "名前を入力してください", - "illegalChars": "/ \\ : * ? \" < > | は使用できません", - "tooLong": "名前が長すぎます", - "reserved": "この名前は Windows の予約語です", - "duplicate": "この名前は既に使われています" - }, - "rejection": { - "not_found": "このフォルダーが見つかりません", - "not_a_directory": "このパスはフォルダーではありません", - "same_as_root": "ワークスペースのフォルダー自身です", - "ancestor_of_root": "このフォルダーはワークスペースを含んでいます", - "inside_root": "既にワークスペース内にあります", - "already_linked": "既にリンク済みです", - "name_unavailable": "このフォルダーに使える名前が残っていません", - "alreadyLinkedAs": "{name} として既にリンク済みです" - } - }, - "folderNameDropdown": { - "fallbackFolderName": "フォルダ", - "openFolder": "フォルダを開く", - "cloneRepository": "リポジトリをクローン", - "projectBoot": "プロジェクトブート", - "opened": "開いているフォルダ", - "recentOpen": "最近開いたフォルダ" - }, - "fileWorkspacePanel": { - "addSelectionToChat": "選択範囲をチャットに追加", - "addToChat": "チャットに追加", - "addSelectionToChatDone": "{label} を会話に追加しました", - "addFileToChat": "ファイルをチャットに追加", - "toggleWordWrap": "折り返しの切り替え", - "addFileToChatDone": "{label} を会話に追加しました", - "viewDiff": "差分を見る", - "openFile": "ファイルを開く", - "fileCount": "{count, plural, one {# 個のファイル} other {# 個のファイル}}", - "openFileOrDiff": "右側パネルからファイルまたは差分を開いてください", - "disk": "ディスク", - "head": "HEAD", - "unsaved": "未保存", - "workingTree": "作業ツリー", - "loading": "読み込み中...", - "compareWithBranch": "{path} · {branch} と比較", - "hunkCount": "{count, plural, one {# 個のハンク} other {# 個のハンク}}", - "prev": "前", - "next": "次", - "jumpToLine": "{line} 行へ移動", - "noParsedDiffSections": "解析済みの差分セクションがありません", - "loadingEditor": "エディターを読み込み中...", - "imageZoomIn": "拡大", - "imageZoomOut": "縮小", - "imageZoomReset": "ズームをリセット", - "htmlPreviewTitle": "HTML プレビュー", - "htmlPreviewTrust": "スクリプトを有効化", - "htmlPreviewTrustHint": "このファイルのスクリプトを実行し、ネットワークアクセスを許可します。信頼できるファイルでのみ有効にしてください。", - "officePreviewTitle": "Office ドキュメントのプレビュー", - "officeFullRender": "フル描画", - "officeFullRenderHint": "Morph アニメーション・3D・数式を描画します(スライド自身のスクリプトを実行)", - "officeNotInstalled": "OfficeCLI がインストールされていません", - "officeNotInstalledHint": "設定 → Office ツール から OfficeCLI をインストールすると、Word・Excel・PowerPoint ファイルをプレビューできます。", - "officeOpenSettings": "設定を開く", - "officeWatchFailed": "ライブプレビューを開始できませんでした", - "officeWatchRetry": "再試行", - "officeServerInstallHint": "OfficeCLI はサーバーホストにインストールする必要があります。サーバーで次のコマンドを実行してから再試行してください:", - "officeRemoteDesktopUnsupported": "リモートデスクトップウィンドウではライブプレビューを利用できません。Office ファイルをプレビューするには、サーバーの Web UI でこのワークスペースを開いてください。" - }, - "branchDropdown": { - "toasts": { - "commitCodeCompleted": "コードコミットが完了しました", - "pushCodeCompleted": "コードプッシュが完了しました", - "committedFiles": "{count, plural, one {# 個のファイルをコミット} other {# 個のファイルをコミット}}", - "taskCompleted": "{label} が完了しました", - "taskFailed": "{label} が失敗しました", - "mergeNoNewCommits": "{branchName} に新しいコミットはありません", - "mergedCommits": "{count, plural, one {# 件のコミットをマージ} other {# 件のコミットをマージ}}", - "allFilesUpToDate": "すべてのファイルは最新です", - "updatedFiles": "{count, plural, one {# 個のファイルを更新} other {# 個のファイルを更新}}", - "openCommitWindowFailed": "コミットウィンドウを開けませんでした", - "openPushWindowFailed": "プッシュウィンドウを開けませんでした", - "upstreamSet": "アップストリームブランチを設定しました", - "upstreamSetAndPushed": "アップストリームブランチを設定し、{count, plural, one {# 件のコミット} other {# 件のコミット}}をプッシュしました", - "noCommitsToPush": "プッシュするコミットはありません", - "pushedCommits": "{count, plural, one {# 件のコミットをプッシュ} other {# 件のコミットをプッシュ}}", - "switchedToFolder": "{name} に切り替えました", - "switchFailed": "ブランチの切り替えに失敗しました", - "openStashWindowFailed": "stash ウィンドウを開けませんでした" - }, - "tasks": { - "newBranch": "ブランチ {name} を作成", - "newWorktree": "ワークツリー {name} を作成", - "checkoutTo": "{branchName} にチェックアウト", - "mergeBranch": "{branchName} をマージ", - "rebaseTo": "{branchName} にリベース", - "deleteRemoteBranch": "リモートブランチ {branchName} を削除", - "initGitRepo": "Git リポジトリを初期化", - "pullCode": "コードをプル", - "fetchInfo": "情報をフェッチ", - "pushCode": "コードをプッシュ", - "stashChanges": "変更を stash", - "stashPop": "stash を pop", - "deleteBranch": "ブランチ {branchName} を削除", - "removeWorktree": "{branchName} のワークツリーを削除", - "removeWorktreeAndBranch": "ワークツリーとブランチ {branchName} を削除", - "updateBranch": "ブランチ {branchName} を更新" - }, - "confirm": { - "mergeTitle": "ブランチをマージ", - "rebaseTitle": "ブランチをリベース", - "mergeDescription": "{branchName} を現在のブランチ {currentBranch} にマージしますか?", - "rebaseDescription": "現在のブランチ {currentBranch} を {branchName} にリベースしますか?", - "deleteRemoteTitle": "リモートブランチの削除", - "deleteRemoteDescription": "リモートブランチ {branchName} を削除しますか?この操作はリモートリポジトリからブランチを削除し、元に戻せません。", - "deleteTitle": "ブランチを削除", - "deleteDescription": "ブランチ {branchName} を削除しますか?この操作は元に戻せません。", - "forceDeleteTitle": "ブランチを強制削除", - "forceDeleteDescription": "ブランチ {branchName} はまだ完全にマージされていません。強制削除してもよろしいですか?この操作は元に戻せません。", - "deleteWorktreeTitle": "ワークツリーを削除", - "deleteWorktreeDescription": "{branchName} をチェックアウトしているワークツリーのディレクトリを削除しますか?ブランチとそのコミットは残ります。", - "forceDeleteWorktreeTitle": "ワークツリーを強制削除", - "forceDeleteWorktreeDescription": "{branchName} のワークツリーに未コミットまたは未追跡のファイルがあります。それでも削除しますか?その変更は復元できません。", - "deleteWorktreeAndBranchTitle": "ワークツリーとブランチを削除", - "deleteWorktreeAndBranchDescription": "{branchName} のワークツリー、ブランチ自体、そのワークスペースフォルダーを削除しますか?中のセッションはリポジトリのフォルダーに移動します。この操作は取り消せません。", - "forceDeleteWorktreeAndBranchTitle": "ワークツリーとブランチを強制削除", - "forceDeleteWorktreeAndBranchDescription": "{branchName} のワークツリーに未コミットのファイルがあるか、ブランチが完全にマージされていません。それでも両方を削除しますか?この操作は取り消せません。" - }, - "current": "現在", - "switchToBranch": "このブランチに切り替え", - "mergeBranchIntoCurrent": "{branchName} を {currentBranch} にマージ", - "rebaseCurrentToBranch": "{currentBranch} を {branchName} にリベース", - "noBranch": "ブランチなし", - "detachedHead": "切り離された HEAD({sha})", - "initGitRepo": "Git リポジトリを初期化", - "pullCode": "コードをプル", - "fetchRemoteBranches": "リモートブランチをフェッチ", - "openCommitWindow": "コードをコミット...", - "pushCode": "プッシュ...", - "pushBranch": "プッシュ", - "newBranch": "新規ブランチ...", - "newWorktree": "新規ワークツリー...", - "stashChanges": "スタッシュ...", - "stashPop": "stash を pop...", - "manageRemotes": "リモート管理...", - "localBranches": "ローカルブランチ ({count, plural, one {#} other {#}})", - "noLocalBranches": "ローカルブランチはありません", - "remoteBranches": "リモートブランチ ({count, plural, one {#} other {#}})", - "noRemoteBranches": "リモートブランチはありません", - "dialogs": { - "newBranchTitle": "新規ブランチ", - "newBranchDescription": "現在のブランチ {branch} から新しいブランチを作成", - "branchNamePlaceholder": "ブランチ名", - "newWorktreeTitle": "新規ワークツリー", - "newWorktreeDescription": "現在のブランチ {branch} から新しいワークツリーを作成", - "branchNameLabel": "ブランチ名", - "worktreePathLabel": "ワークツリーのパス", - "worktreePathPlaceholder": "ワークツリーのパス", - "manageRemotesTitle": "リモート管理", - "manageRemotesEmpty": "リモートが設定されていません", - "remoteNamePlaceholder": "リモート名", - "remoteUrlPlaceholder": "リモート URL", - "addRemote": "追加", - "savingRemotes": "保存中..." - }, - "conflict": { - "title": "マージコンフリクト", - "description": "以下のファイルにコンフリクトがあります。解決が必要です:", - "abort": "マージを中止", - "openMergeTool": "マージツールを開く", - "completeMerge": "マージ完了", - "abortSuccess": "マージが中止されました", - "completeSuccess": "マージが完了しました" - }, - "stashDialog": { - "title": "変更をスタッシュ", - "description": "現在の変更をスタッシュに保存", - "messageLabel": "メッセージ", - "messagePlaceholder": "スタッシュメッセージ(任意)", - "keepIndex": "インデックスを保持(ステージ済みの変更はそのまま)", - "cancel": "キャンセル", - "stash": "スタッシュ", - "success": "変更がスタッシュされました", - "error": "スタッシュに失敗しました" - }, - "unstashDialog": { - "title": "スタッシュを適用", - "noStashes": "スタッシュがありません", - "selectFile": "ファイルを選択して差分を表示", - "viewDiff": "差分を表示", - "original": "元", - "modified": "変更後", - "apply": "適用", - "drop": "削除", - "applySuccess": "スタッシュを適用しました", - "dropSuccess": "スタッシュを削除しました", - "confirmApply": "スタッシュ {ref} を作業ディレクトリに適用しますか?", - "cancel": "キャンセル" - }, - "deleteBranch": "ブランチを削除", - "deleteWorktree": "ワークツリーを削除", - "deleteWorktreeAndBranch": "ワークツリーとブランチを削除", - "searchPlaceholder": "ブランチと操作を検索", - "searchAriaLabel": "ブランチと操作を検索", - "branchListLabel": "ブランチと操作", - "noMatches": "一致する項目がありません" - }, - "commitDialog": { - "toasts": { - "commitCompleted": "コードコミットが完了しました", - "pushFailed": "プッシュに失敗しました", - "committedFiles": "{count, plural, one {# 個のファイルをコミット} other {# 個のファイルをコミット}}", - "addedToVcs": "VCS に追加しました", - "addToVcsFailed": "VCS への追加に失敗しました", - "fileDeleted": "ファイルを削除しました", - "deleteFailed": "削除に失敗しました", - "fileRolledBack": "ファイルをロールバックしました", - "rollbackFailed": "ロールバックに失敗しました", - "dirRolledBack": "ディレクトリをロールバックしました", - "dirDeleted": "ディレクトリを削除しました" - }, - "confirm": { - "deleteTitle": "削除の確認", - "deleteDescription": "ファイル \"{file}\" を削除しますか?この操作は元に戻せません。", - "rollbackTitle": "ロールバックの確認", - "rollbackDescription": "ファイル \"{file}\" を HEAD にロールバックしますか?未保存の変更は失われます。", - "rollbackDirDescription": "ディレクトリ「{dir}」をHEADにロールバックしますか?未保存の変更は失われます。", - "deleteDirDescription": "ディレクトリ「{dir}」を削除しますか?この操作は元に戻せません。" - }, - "actions": { - "select": "選択", - "unselect": "選択解除", - "rollback": "ロールバック", - "addToVcs": "VCS に追加" - }, - "aria": { - "selectFile": "{action}: {path}", - "unselectAllFiles": "すべてのファイルの選択を解除", - "selectAllFiles": "すべてのファイルを選択", - "unselectTracked": "追跡中の変更の選択を解除", - "selectTracked": "追跡中の変更を選択", - "unselectUntracked": "未追跡ファイルの選択を解除", - "selectUntracked": "未追跡ファイルを選択" - }, - "loading": "読み込み中...", - "selectionCount": "{selected} / {total} ファイル", - "emptyFiles": "変更されたファイルはありません", - "trackedChanges": "追跡中の変更 ({count})", - "untrackedFiles": "未追跡ファイル ({count})", - "commitMessage": "コミットメッセージ", - "commitMessagePlaceholder": "コミットメッセージを入力...", - "commitButton": "コミット ({count})", - "commitAndPushButton": "コミットしてプッシュ ({count})", - "head": "HEAD", - "workingTree": "作業ツリー", - "clickFileToDiff": "ファイル名をクリックして差分を表示", - "loadingDiff": "差分を読み込み中..." - }, - "pushWindow": { - "title": "コードをプッシュ", - "noUnpushedCommits": "未プッシュのコミットはありません", - "noRemoteConfigured": "Git リモートが設定されていません\n「リモート管理」からリモートを追加してください", - "newBranchNoPushedCommits": "新しいブランチ — プッシュしてリモート追跡ブランチを作成", - "unpushed": "未プッシュ", - "selectFileToViewDiff": "ファイルを選択して差分を表示", - "before": "変更前", - "after": "変更後", - "push": "プッシュ", - "toasts": { - "pushSuccess": "プッシュ成功", - "pushFailed": "プッシュ失敗", - "upstreamSet": "リモート追跡ブランチが設定されました", - "upstreamSetAndPushed": "リモート追跡ブランチを設定し、{count}件のコミットをプッシュしました", - "noCommitsToPush": "プッシュするコミットはありません", - "pushedCommits": "{count}件のコミットをプッシュしました" - } - }, - "gitLogTab": { - "filesTitle": "ファイル", - "expandAllFiles": "すべてのファイルを展開", - "collapseAllFiles": "すべてのファイルを折りたたむ", - "workspace": "ワークスペース", - "retry": "再試行", - "noCommitsFound": "コミットが見つかりません", - "notAGitRepoTitle": "Git リポジトリではありません", - "notAGitRepoHint": "上のブランチメニューから Git を初期化するか、既存のリポジトリを開いてください。", - "hash": "ハッシュ", - "copyHash": "ハッシュをコピー", - "copyMessage": "メッセージをコピー", - "showMore": "もっと見る", - "showLess": "折りたたむ", - "author": "作成者", - "noFileChangeDetails": "ファイル変更の詳細はありません。", - "loadingFiles": "ファイルを読み込み中…", - "branchesTitle": "ブランチ", - "loadingBranches": "ブランチを読み込み中...", - "noContainingBranches": "含まれるブランチが見つかりません。", - "newBranch": "新規ブランチ...", - "resetToHere": "ここにリセット", - "resetDisabledReasonNotCurrentBranchView": "現在のブランチ表示時のみ利用できます", - "copyFullCommitHashAria": "完全なコミットハッシュ {hash} をコピー", - "pushStatus": { - "pushed": "リモートにプッシュ済み", - "notPushed": "リモートに未プッシュ", - "unknown": "プッシュ状態不明(upstream 未設定)" - }, - "time": { - "monthsAgo": "{count, plural, one {# か月前} other {# か月前}}", - "daysAgo": "{count, plural, one {# 日前} other {# 日前}}", - "hoursAgo": "{count, plural, one {# 時間前} other {# 時間前}}", - "minsAgo": "{count, plural, one {# 分前} other {# 分前}}", - "justNow": "たった今" - }, - "toasts": { - "createdAndSwitchedNewBranch": "新しいブランチを作成して切り替えました", - "newBranchFromCommit": "{name}({shortHash} から)", - "createBranchFailed": "ブランチ作成に失敗しました", - "openPushWindowFailed": "プッシュウィンドウを開けませんでした", - "resetSuccess": "リセットが完了しました", - "resetSuccessDescription": "{branch} を {mode} で {shortHash} にリセットしました", - "resetFailed": "リセットに失敗しました" - }, - "authorFilter": { - "label": "作成者", - "searchPlaceholder": "作成者を検索", - "noAuthors": "作成者が見つかりません", - "you": "あなた", - "filterByAuthorAria": "作成者でコミットを絞り込む", - "filterByQuery": "「{query}」で絞り込む", - "clearAuthorFilterAria": "作成者フィルターをクリア", - "recent": "最近", - "matchingAuthors": "一致する作成者", - "removeFromRecent": "{name} を最近から削除" - }, - "branchSelector": { - "label": "ブランチ", - "head": "HEAD", - "headHint": "現在のブランチに追従", - "headHintWithBranch": "現在のブランチに追従({branch})", - "searchBranch": "ブランチを検索...", - "noBranches": "ブランチがありません", - "selectBranchPlaceholder": "ブランチを選択...", - "localBranches": "ローカルブランチ", - "current": "現在", - "remoteBranches": "リモートブランチ", - "refreshCommitHistory": "コミット履歴を更新", - "clearBranchFilterAria": "ブランチフィルターをクリア" - }, - "dialogs": { - "newBranchTitle": "新規ブランチ", - "newBranchDescription": "コミット {shortHash} を最新コミットとして新しいブランチを作成します。", - "branchNamePlaceholder": "ブランチ名", - "reset": { - "title": "現在のブランチをこのコミットへリセット", - "branchLabel": "ブランチ", - "targetLabel": "対象コミット", - "messageLabel": "コミットメッセージ", - "modeLabel": "リセットモード", - "confirmButton": "リセット", - "modes": { - "soft": { - "label": "--soft", - "description": "HEAD と現在のブランチ参照を対象コミットへ移動します。\nIndex と Working Tree は変更しません。\n取り消されたコミットの変更は staged のまま残ります。" - }, - "mixed": { - "label": "--mixed(デフォルト)", - "description": "HEAD を対象コミットへ移動します。\nIndex を対象コミットに戻し、Working Tree の変更は維持します。\n変更は staged から unstaged に戻ります。" - }, - "hard": { - "label": "--hard", - "description": "HEAD を移動し、Index と Working Tree を対象コミットに戻します。\n対象コミット以降の追跡中ローカル変更は破棄されます。\n破壊的な操作です。" - }, - "keep": { - "label": "--keep", - "description": "HEAD を対象コミットへ移動し、可能な限りローカル変更を保持します。\n競合しない変更のみ保持されます。\n競合がある場合は保護のため処理を中止します。" - } - } - } - }, - "moreActions": "その他の Git 操作" - }, - "gitChangesTab": { - "workspace": "ワークスペース", - "noChanges": "ローカルの変更はありません", - "notAGitRepoTitle": "Git リポジトリではありません", - "notAGitRepoHint": "上のブランチメニューから Git を初期化するか、既存のリポジトリを開いてください。", - "trackedChanges": "追跡中の変更 ({count})", - "untrackedFiles": "未追跡ファイル ({count})", - "expandTracked": "追跡中の変更を展開", - "collapseTracked": "追跡中の変更を折りたたむ", - "expandUntracked": "未追跡ファイルを展開", - "collapseUntracked": "未追跡ファイルを折りたたむ", - "showRemainingItems": "残り {count} 件を表示", - "actions": { - "commitCode": "コードをコミット", - "rollback": "ロールバック", - "addToVcs": "VCS に追加", - "delete": "削除", - "moreActions": "その他の Git 操作", - "addAllToVcs": "すべて VCS に追加", - "rollbackAll": "すべてロールバック", - "refresh": "更新" - }, - "toasts": { - "noAddableFilesInDir": "このディレクトリには VCS に追加できる変更ファイルがありません", - "noRollbackFilesInDir": "このディレクトリにはロールバックできる変更ファイルがありません", - "addedToVcs": "{name} を VCS に追加しました", - "addToVcsFailed": "VCS への追加に失敗しました", - "openCommitWindowFailed": "コミットウィンドウを開けませんでした", - "rolledBack": "{name} をロールバックしました", - "rollbackFailed": "ロールバックに失敗しました", - "addedFilesToVcs": "{count, plural, one {# 個のファイルを VCS に追加} other {# 個のファイルを VCS に追加}}", - "rolledBackFiles": "{count, plural, one {# 個のファイルをロールバック} other {# 個のファイルをロールバック}}", - "deleted": "{name} を削除しました", - "deleteFailed": "削除に失敗しました", - "deletedFiles": "{count} 個のファイルを削除しました", - "noDeletableFilesInDir": "このディレクトリには削除可能な変更ファイルがありません", - "commitFailed": "コミットに失敗しました" - }, - "directoryDialog": { - "descriptionAdd": "ディレクトリ {path} 配下で VCS に追加するファイルを選択してください。", - "descriptionRollback": "ディレクトリ {path} 配下でロールバックするファイルを選択してください。", - "descriptionDelete": "ディレクトリ {path} 配下で削除するファイルを選択してください。この操作は元に戻せません。", - "descriptionFallback": "続行するファイルを選択してください。", - "selectionCount": "{selected} / {total} を選択", - "selectAll": "すべて選択", - "unselectAll": "すべて選択解除", - "loadingCandidates": "ディレクトリの変更を読み込み中...", - "noOperableFiles": "操作可能なファイルがありません" - }, - "rollbackConfirm": { - "title": "ロールバックの確認", - "descriptionWithTarget": "{kind} \"{name}\" のローカル変更をロールバックしますか?", - "descriptionFallback": "ローカル変更をロールバックしますか?", - "kindDirectory": "ディレクトリ", - "kindFile": "ファイル" - }, - "deleteConfirm": { - "title": "削除の確認", - "descriptionWithTarget": "{kind}「{name}」を削除しますか?この操作は元に戻せません。", - "descriptionFallback": "この操作は元に戻せません。", - "kindDirectory": "ディレクトリ", - "kindFile": "ファイル" - }, - "quickCommit": { - "placeholder": "コミットメッセージ(Enter でコミット)" - } - }, - "tabContext": { - "loadingConversation": "読み込み中...", - "untitledConversation": "無題の会話", - "newConversation": "新しい会話" - }, - "fileTreeTab": { - "workspace": "ワークスペース", - "retry": "再試行", - "git": "Git", - "openInFileManager": "ファイルマネージャーで開く", - "openInFinder": "Finderで開く", - "openInExplorer": "エクスプローラーで開く", - "attachToCurrentSession": "セッションに追加", - "compareWithBranch": "ブランチと比較...", - "reloadFromDisk": "ディスクから再読み込み", - "new": "新規作成", - "newFile": "ファイル", - "newDirectory": "ディレクトリ", - "openIn": "で開く", - "openInTerminal": "ターミナルで開く", - "linkedFolder": "リンク済みフォルダー", - "copyPath": "パスをコピー", - "upload": "ファイル/フォルダをアップロード", - "download": "ファイルをダウンロード", - "downloadAsZip": "ZIP としてダウンロード", - "actions": { - "select": "選択", - "unselect": "選択解除", - "commitCode": "コードをコミット", - "rollback": "ロールバック", - "addToVcs": "VCSに追加" - }, - "aria": { - "selectPath": "{action}: {path}" - }, - "toasts": { - "openDirectoryFailed": "ディレクトリを開けませんでした", - "openBuiltinTerminalFailed": "内蔵ターミナルを開けませんでした", - "openCommitWindowFailed": "コミットウィンドウを開けませんでした", - "noAddableFilesInDir": "このディレクトリには VCS に追加できる変更ファイルがありません", - "noRollbackFilesInDir": "このディレクトリにはロールバックできる変更ファイルがありません", - "addedToVcs": "{name} を VCS に追加しました", - "addToVcsFailed": "VCS への追加に失敗しました", - "loadBranchesFailed": "ブランチの読み込みに失敗しました", - "renameFailed": "名前の変更に失敗しました", - "moveFailed": "移動に失敗しました", - "deleteFailed": "削除に失敗しました", - "rolledBack": "{name} をロールバックしました", - "rollbackFailed": "ロールバックに失敗しました", - "addedFilesToVcs": "{count, plural, one {# 件のファイルを VCS に追加しました} other {# 件のファイルを VCS に追加しました}}", - "rolledBackFiles": "{count, plural, one {# 件のファイルをロールバックしました} other {# 件のファイルをロールバックしました}}", - "savedAsCopy": "コピーとして保存しました", - "saveCopyFailed": "コピーとして保存できませんでした", - "watchStartFailed": "ファイル監視の開始に失敗しました", - "createFailed": "作成に失敗しました", - "downloadFailed": "{name} のダウンロードに失敗しました", - "downloadSaved": "{name} をダウンロードしました", - "pathCopied": "パスをコピーしました", - "copyPathFailed": "パスのコピーに失敗しました" - }, - "createDialog": { - "newFile": "新規ファイル", - "newDirectory": "新規ディレクトリ", - "description": "新しい{kind}の名前を入力してください。", - "placeholderFile": "file-name.ext", - "placeholderDirectory": "folder-name" - }, - "renameDialog": { - "renameDirectory": "ディレクトリ名を変更", - "renameFile": "ファイル名を変更", - "description": "新しい名前を入力してください(名前のみ、パスは不要)。", - "placeholderDirectory": "新しいフォルダ名", - "placeholderFile": "新しいファイル名.ext" - }, - "uploadDialog": { - "title": "ワークスペースへアップロード", - "description": "必要に応じて上書き先を変更し、ファイルやフォルダを追加してください。", - "workspaceRoot": "ワークスペースのルート", - "targetPathLabel": "アップロード先", - "targetPathHint": "実際の場所:{path}", - "dropHint": "ファイルやフォルダをここにドロップ、または下のボタンから選択", - "dropHintActive": "離してキューに追加", - "selectFiles": "ファイルを選択", - "selectFolder": "フォルダを選択", - "startUpload": "アップロード開始", - "clearQueue": "完了したものをクリア", - "removeItem": "キューから削除", - "retry": "再試行", - "dropZoneAria": "ファイルをここにドロップ、または Enter で参照", - "folderEmpty": "ドロップされたフォルダにファイルが見つかりません", - "summary": "合計:{total} · 成功:{succeeded} · 失敗:{failed}", - "status": { - "pending": "待機中", - "uploading": "アップロード中", - "success": "完了", - "error": "失敗", - "cancelled": "キャンセル済み" - } - }, - "directoryDialog": { - "descriptionAdd": "ディレクトリ {path} 配下で VCS に追加するファイルを選択してください。", - "descriptionRollback": "ディレクトリ {path} 配下でロールバックするファイルを選択してください。", - "descriptionFallback": "続行するファイルを選択してください。", - "selectionCount": "{selected} / {total} ファイルを選択", - "selectAll": "すべて選択", - "unselectAll": "すべて選択解除", - "loadingCandidates": "ディレクトリの変更を読み込み中...", - "noOperableFiles": "操作可能なファイルがありません" - }, - "compareDialog": { - "title": "ブランチと比較", - "descriptionWithTarget": "ブランチを選択し、{kind} {path} と比較します", - "descriptionFallback": "比較するブランチを選択してください。", - "kindDirectory": "ディレクトリ", - "kindFile": "ファイル", - "filterPlaceholder": "ブランチを絞り込み(例: main / origin/main)", - "singleClickHint": "ブランチをクリックすると直接比較します", - "loadingBranches": "ブランチを読み込み中...", - "recentBranches": "最近のブランチ ({count})", - "noCurrentBranch": "現在のブランチがありません", - "localBranches": "ローカルブランチ ({count})", - "remoteBranches": "リモートブランチ ({count})", - "noMatchingBranches": "一致するブランチがありません" - }, - "externalConflictDialog": { - "title": "外部ファイルの変更を検出しました", - "descriptionWithPath": "ファイル {path} がディスク上で変更されました。現在の編集は未保存です。", - "descriptionFallback": "現在のファイルがディスク上で変更されました。現在の編集は未保存です。", - "compare": "比較", - "savingCopy": "コピーを保存中...", - "saveAsCopy": "コピーとして保存", - "reload": "再読み込み" - }, - "deleteConfirm": { - "title": "削除の確認", - "descriptionWithTarget": "{kind} \"{name}\" を削除しますか?この操作は元に戻せません。", - "descriptionFallback": "この操作は元に戻せません。", - "kindDirectory": "ディレクトリ", - "kindFile": "ファイル" - }, - "rollbackConfirm": { - "title": "ロールバックの確認", - "descriptionWithTarget": "ファイル \"{name}\" のローカル変更をロールバックしますか?", - "descriptionFallback": "このファイルのローカル変更をロールバックしますか?" - }, - "terminalTitle": "ターミナル · {name}" - }, - "commandDropdown": { - "loading": "読み込み中...", - "addCommand": "コマンドを追加", - "manageCommands": "コマンドを管理...", - "runCommandTitle": "実行: {command}", - "stopCommandTitle": "停止: {command}", - "manageDialog": { - "title": "コマンド管理", - "empty": "コマンドはまだありません", - "noResults": "一致するコマンドがありません", - "searchPlaceholder": "コマンドを検索", - "newCommand": "新しいコマンド", - "nameLabel": "名前", - "commandLabel": "コマンド", - "dragSort": "ドラッグして並び替え", - "dragSortCommand": "{name} をドラッグして並び替え", - "orderFailed": "コマンドの並び順の保存に失敗しました", - "loadFailed": "コマンドの読み込みに失敗しました", - "saveFailed": "コマンドの保存に失敗しました", - "deleteFailed": "コマンドの削除に失敗しました", - "confirmDelete": { - "title": "コマンドを削除しますか?", - "message": "「{name}」を削除します。この操作は元に戻せません。" - } - } - }, - "workspaceContext": { - "confirmCloseDirtyTab": "保存せずに「{title}」を閉じますか?", - "confirmCloseOtherDirtyTabs": "未保存の変更がある他のタブを閉じますか?", - "confirmCloseAllDirtyTabs": "未保存の変更があるすべてのタブを閉じますか?", - "unableLoadContent": "内容を読み込めません。\n\n{message}", - "previewRequestTimedOut": "プレビュー要求がタイムアウトしました", - "diffRequestTimedOut": "Diff 要求がタイムアウトしました", - "branchCompareRequestTimedOut": "ブランチ比較要求がタイムアウトしました", - "commitDiffRequestTimedOut": "コミット Diff 要求がタイムアウトしました", - "saveRequestTimedOut": "保存要求がタイムアウトしました", - "reloadRequestTimedOut": "再読み込み要求がタイムアウトしました", - "noChanges": "変更はありません。", - "noDiffOutput": "Diff 出力がありません。", - "diffTitleWorkspace": "Diff · ワークスペース", - "diffDescriptionWorkingTree": "作業ツリー (HEAD)", - "diffTitleFile": "差分 · {name}", - "compareTitleFile": "比較 · {name}", - "compareTitleBranch": "比較 · {branch}", - "compareDescriptionPath": "{path} · {branch} と比較", - "compareDescriptionBranch": "{branch} と比較", - "diffTitleCommitFile": "差分 · {name} @ {hash}", - "diffTitleCommit": "差分 · {hash}", - "diffDescriptionCommitPath": "{path} · コミット {commit}", - "diffDescriptionCommit": "コミット {commit}", - "diffTitleConflictFile": "競合 · {name}", - "diffDescriptionConflict": "{path} · ディスク vs 未保存" - }, - "chat": { - "acpConnections": { - "actions": { - "openAgentsSettings": "エージェント設定を開く", - "retry": "再試行" - }, - "agentsSetupHint": "インストール管理は「設定 > エージェント」を開いてください。", - "withSetupHint": "{message}\n{hint}", - "blocked": { - "missingConfig": "現在のエージェント設定を読み取れません。", - "disabled": "{agent} はエージェント設定で無効になっています。接続前に有効化してください。", - "unavailable": "{agent} は現在のプラットフォームでは利用できません。", - "sdkMissing": "{agent} SDK がインストールされていません", - "adapterMissing": "{agent} の ACP アダプターがインストールされていません" - }, - "backendErrors": { - "initializeTimeout": "{agent} の接続ハンドシェイクがタイムアウトしました(60 秒以内に応答なし)。設定を開いてエージェントとネットワーク設定を確認してください。", - "mcpRejectedByAgent": "codeg の MCP コンパニオンを渡した際、{agent} がセッションを拒否しました: {message} このエージェントが MCP に対応していない場合は、設定で「MCP サポート」をオフにして再接続してください。", - "processExited": "{agent} プロセスが予期せず終了しました。", - "spawnFailed": "{agent} の起動に失敗しました: {message}", - "downloadFailed": "{agent} のダウンロードに失敗しました: {message}", - "sessionLoadResourceNotFound": "{agent} セッションの読み込みに失敗しました。再読み込みして再試行するか、新しい会話を開始してください。", - "sessionLoadUnavailable": "{agent} はこのセッションを復元できませんでした。セッションが終了したか、エージェントが停止した可能性があります。再読み込みして再試行するか、新しい会話を開始してください。", - "turnFailedRefusal": "{agent} がこのターンの続行を拒否しました。バックエンドまたはゲートウェイのエラーが原因の可能性があります。エージェントのログを確認してください。", - "turnFailedMaxTokens": "{agent} がこのターンの最大トークン数に達しました。", - "turnFailedMaxTurnRequests": "{agent} がこのターンで許可された最大リクエスト数に達しました。", - "turnFailedUnknown": "{agent} が不明な停止理由でターンを終了しました。", - "grokModelSwitchIncompatibleAgent": "{agent} は既存の会話ではこのモデルに切り替えられません。新しいセッションを開始して使用してください。", - "turnFailedEmpty": "{agent} は応答を生成せずにターンを終了しました。", - "turnFailedEmptyProtocol": "{agent} の出力を codeg が解析できませんでした。エージェントのバージョンがプロトコルと一致していない可能性があります。", - "turnFailedEmptyMetadata": "{agent} はこのターンでステータス更新(計画 / モード / 使用量)のみを送信し、応答はありませんでした。", - "detailsInAlerts": "ステータスバーのアラートを開き、詳細を展開するとエージェントの出力を確認できます。" - }, - "unableReadAgentConfig": "エージェント設定を読み取れません: {message}", - "connectFailedTitle": "{agent} の接続に失敗しました", - "toolFallbackTitle": "ツール", - "eventErrorTitle": "エージェントエラー", - "notificationTurnComplete": "{agent} の応答が完了しました", - "notificationError": "{agent} エラー:{message}", - "claudeApiRetry": { - "fallbackError": "authentication_failed", - "retryingWithMax": "再試行中 {attempt}/{max}", - "retryingAttempt": "再試行中({attempt} 回目)", - "retrying": "再試行中", - "nextRetryIn": "{seconds}秒後に再試行", - "line": "{error}{status} · {retry}", - "lineWithDelay": "{error}{status} · {retry}、{delay}", - "httpStatus": " (HTTP {status})" - }, - "configOptionAdjusted": "{agent} は{option}を {requested} ではなく {actual} にしました" - }, - "connectionLifecycle": { - "tasks": { - "connectingTitle": "{agent} に接続中", - "connectingDescription": "接続を確立しています", - "loadingSelectorsTitle": "{agent} のセレクターを読み込み中", - "loadingSelectorsDescription": "モードとセッション設定オプションを取得しています", - "initSessionTitle": "{agent} セッションを初期化中", - "initSessionDescription": "セッションを作成し設定を読み込んでいます" - }, - "errors": { - "connectionFailed": "接続に失敗しました", - "sendPromptFailed": "メッセージの送信に失敗しました: {error}" - } - }, - "shared": { - "attachedResources": "添付リソース", - "toolCallFailed": "ツール呼び出しに失敗しました" - }, - "messageThread": { - "emptyTitle": "まだメッセージはありません", - "emptyDescription": "会話を開始するとここにメッセージが表示されます" - }, - "chatInput": { - "connecting": "接続中...", - "agentResponding": "{agent} が応答中...", - "sendMessage": "メッセージを送信..." - }, - "messageInput": { - "askAnything": "何でも質問してください...", - "removeAttachmentAria": "{name} を削除", - "attachFiles": "ファイルを添付", - "addActions": "追加", - "quickMessages": "クイックメッセージ", - "quickMessagesEmpty": "クイックメッセージはありません", - "quickMessagesLoading": "読み込み中...", - "pasteAsPlainText": "プレーンテキストとして貼り付け", - "cut": "切り取り", - "copy": "コピー", - "selectAll": "すべて選択", - "pasteUnavailable": "クリップボードを読み取れませんでした。Ctrl/⌘V で貼り付けてください。", - "clipboardWriteFailed": "クリップボードに書き込めませんでした。キーボードショートカットをご利用ください。", - "quickMessageUntitled": "無題", - "liveFeedback": "ライブフィードバック", - "liveFeedbackDisabledHint": "エージェントの作業中に送信できます", - "dropFilesToAttach": "ファイルをドロップして添付", - "loadingSettings": "設定を読み込み中...", - "loadingMode": "モードを読み込み中...", - "modeLabel": "モード", - "toggleOn": "オン", - "toggleOff": "オフ", - "agentSettings": "エージェント設定", - "searchModel": "モデルを検索...", - "searchModelAria": "モデルを検索", - "modelListLabel": "モデル", - "noModels": "モデルが見つかりません", - "cancel": "キャンセル", - "send": "送信", - "forkAndSend": "フォークして送信", - "queueMessage": "キューに追加", - "steerIntoTurn": "現在のターンに挿入", - "steerQueuedInstead": "代わりにキューに追加しました。次のターンで送信されます。", - "steerFailed": "現在のターンに挿入できませんでした", - "steerAttachmentsUnsupported": "テキストのみ対応です。添付ファイル付きの下書きはキューをご利用ください。", - "slashCommands": "スラッシュコマンド", - "slashSearchPlaceholder": "コマンドを検索...", - "slashSearchEmpty": "一致するコマンドがありません", - "experts": "エキスパート", - "office": "日常業務", - "research": "科学研究", - "attachLocalUpload": "ローカルファイルを添付", - "attachServerFile": "サーバーファイルを添付", - "attachUploadTooLarge": "{names} は {limit}MB のアップロード上限を超えたためスキップしました。", - "attachUploadFailed": "{names} のアップロードに失敗しました。", - "attachUploadNotAFile": "{names} は通常ファイルではなく(ディレクトリまたは特殊ファイル)、スキップされました。", - "attachUploadQuotaExceeded": "サーバーのアップロード容量が不足しているため、{names} をアップロードできませんでした。", - "attachUploadInProgress": "画像はまだアップロード中です。しばらくしてからもう一度お試しください。", - "mentionEmpty": "一致する項目がありません", - "mentionLoading": "検索中…", - "mentionListLabel": "メンション", - "mentionMore": "他にも結果があります。入力して絞り込んでください", - "mentionCount": "{count, plural, other {# 件の結果}}", - "mentionGroupFile": "ファイル", - "mentionGroupAgent": "エージェント", - "mentionGroupSession": "セッション", - "mentionGroupCommit": "コミット", - "mentionGroupSkill": "スキル" - }, - "messageQueue": { - "addToQueue": "キューに追加", - "saveEdit": "保存", - "cancelEdit": "編集をキャンセル", - "editItem": "編集", - "deleteItem": "削除" - }, - "welcomeInputPanel": { - "agentsSettingsPath": "設定 > エージェント", - "autoConnectFallback": "{path} を開いてインストールを管理してください。", - "autoConnectAppend": "{message}。{path} を開いてインストールを管理してください。", - "enableAgentFirstPlaceholder": "セッション開始前に少なくとも1つのエージェントを有効化してください...", - "prepareSessionFailed": "チャットセッションを準備できませんでした。もう一度お試しください。", - "createConversationFailed": "会話を作成できませんでした。もう一度お試しください。", - "askAnythingPlaceholder": "何でも質問してください...", - "agentNotInstalled": "{agent} はインストールされていません · クリックして Agents 設定でインストール", - "agentAdapterNotInstalled": "{agent} の ACP アダプターが未インストールです(お使いの CLI とは別物)· クリックして Agents 設定でインストール" - }, - "welcomePanel": { - "greeting": "今日は何をしましょうか?", - "tips": { - "tileTabs": "会話タブを右クリックして「タイル表示」を選ぶと、複数のセッションを並べて比較できます", - "pinTab": "会話タブをダブルクリックすると固定でき、新しい会話に自動で置き換えられなくなります", - "shortcutsNewSearch": "{newConversation} で新規会話、{searchConversations} で履歴を検索できます", - "slashAtMention": "入力欄で / を入力するとスラッシュコマンド、@ を入力するとプロジェクト内のファイルを参照できます", - "pasteDropFiles": "スクリーンショットを貼り付けたり、ファイルを入力欄にドロップするだけで添付できます", - "queueMessage": "エージェントの応答中も入力を続けられ、次のメッセージはキューに入って完了後に自動送信されます", - "draftAutoSave": "未送信の下書きは会話ごとに自動保存され、戻ったときに復元されます", - "forkSend": "送信ボタンのドロップダウンで「分岐して送信」を選ぶと、現在の地点から新しいタブに分岐できます", - "exportConversation": "会話内容を右クリックすると Markdown / HTML / 画像としてエクスポートできます", - "chatChannels": "「設定 → チャットチャネル」で Telegram / Lark / WeChat を連携すれば、スマホから続けて操作できます", - "shortcutsAuxPanel": "{toggleAuxPanel} で右側パネルを開き、このセッションで変更したファイルや Git の差分を確認できます", - "shortcutsTerminalSidebar": "{toggleTerminal} で内蔵ターミナル、{toggleSidebar} でサイドバーを切り替えできます", - "customShortcuts": "すべてのショートカットは「設定 → ショートカット」で自由に変更できます", - "webService": "「設定 → Web サービス」を有効にすると、チームメンバーが同じ codeg にブラウザでアクセスできます", - "fusionMode": "ファイルや差分を開くと、会話の横に自動で表示されます。", - "quickMessages": "入力欄横の + ボタンから「クイックメッセージ」を選ぶと、保存済みのスニペットを一発で挿入できます(「設定 → クイックメッセージ」で管理)", - "experts": "+ ボタンの「エキスパートスキル」メニューから、デバッグや計画などのプリセットロールをワンクリックで読み込めます", - "taskBoard": "ToDo タスクは作業を最後まで実行します。エージェントは専用ワークツリーで作業し、あなたは差分を確認してからマージします。", - "automations": "オートメーションは保存したプロンプトをスケジュール実行します(毎晩のレビューなど)。実行ごとに専用ワークツリーを使うこともできます。", - "tokenUsage": "ステータスバーの会話数をクリックするとトークン使用量が開き、日付・エージェント・モデル・フォルダー別の内訳を確認できます。", - "mentionTargets": "@ で参照できるのはファイルだけではありません。別のエージェントをメンションしてサブタスクを任せたり、過去のセッション・コミット・スキルを参照したりできます。", - "splitGroups": "タブを右クリックして「右に分割」または「下に分割」を選ぶと、2 つの会話をそれぞれのペインで開いたままにできます。", - "worktrees": "ブランチボタンから「新規ワークツリー」を選ぶと、複数のエージェントが同じリポジトリで互いのファイルを上書きせずに並行作業できます。", - "importSessions": "すでにターミナルで実行したセッションは、フォルダーのメニューにある「ローカルセッションをインポート」で codeg に取り込めます。", - "subSessions": "エージェントが委任すると、サブセッションがサイドバーの親セッションの下に入れ子で表示されます。行を展開すれば、それぞれの作業を追えます。", - "liveFeedback": "「+」メニューのライブフィードバックを使えば、エージェントが実行中のターンに、中断させずにメモを差し込めます。", - "skillPacks": "設定 → スキルパックには、コーディング専門家・科学研究・オフィス作業のスキルがまとまっています。エージェントごとに有効化できます。", - "modelProviders": "設定 → モデルプロバイダーでは自分の API キーやエンドポイントを登録でき、モデルは入力欄からそのまま切り替えられます。", - "workspaceBackground": "設定 → 外観では、ワークスペースの背景画像・パネルの不透明度・アプリのフォントを変更できます。" - }, - "quickActions": { - "excel": "Excel ブック", - "excelDesc": "データ表・数式・グラフ", - "word": "Word 文書", - "wordDesc": "報告書・手紙・メモ", - "ppt": "プレゼン資料", - "pptDesc": "プロ仕様のスライド", - "pitchDeck": "ピッチデック", - "pitchDeckDesc": "主要指標付きの資金調達資料", - "morph": "Morph アニメ", - "morphDesc": "映画的なスライド遷移", - "morph3d": "3D Morph", - "morph3dDesc": "3D モデルとカメラワーク", - "academic": "学術論文", - "academicDesc": "引用と構成のある研究論文", - "financial": "財務モデル", - "financialDesc": "財務諸表・DCF・予測", - "dashboard": "データダッシュボード", - "dashboardDesc": "データから KPI と分析を生成", - "prompts": { - "excel": "次の要件で Excel ブックを作成してください:\n\n[データ・表・数式・グラフをここに記述]", - "word": "次の要件で Word 文書を作成してください:\n\n[文書の内容・構成・書式をここに記述]", - "ppt": "次の要件で PowerPoint プレゼンを作成してください:\n\n[スライド・内容・デザインをここに記述]", - "pitchDeck": "次の要件で資金調達のピッチデックを作成してください:\n\n[会社・調達ラウンド・主要指標をここに記述]", - "morph": "Morph トランジションアニメーション付きのプレゼンを作成してください:\n\n[プレゼンのテーマと希望する視覚効果をここに記述]", - "morph3d": "GLB モデルとカメラワーク付きの 3D Morph プレゼンを作成してください:\n\n[テーマと 3D ビジュアルの構想をここに記述]", - "academic": "次の要件で Word の学術論文を執筆してください:\n\n[研究テーマ・手法・主要な発見をここに記述]", - "financial": "次の要件で Excel の財務モデルを作成してください:\n\n[財務諸表・予測・分析をここに記述]", - "dashboard": "次の要件で Excel のデータダッシュボードを作成してください:\n\n[データソース・KPI・グラフをここに記述]", - "scientific-brainstorming": "研究の方向性をブレインストーミングしてください。分野横断のつながりを探り、前提を問い直し、有望な空白を見つけます。検討している領域:", - "hypothesis-generation": "これらの観察を検証可能な仮説に変換してください。明確な予測、妥当なメカニズム、検証実験を示します。私の観察:", - "experimental-design": "データ収集前に厳密な実験を設計してください。デザイン、無作為化、対照、交絡の回避方法を含めます。研究したいこと:", - "statistical-power": "必要なサンプルサイズを求めてください。私のデザインについて検出力分析(効果量・有意水準・検出力)を進めます。詳細:", - "statistical-analysis": "このデータを適切に分析してください。適切な検定の選択、前提の確認、効果量の報告、結果の記述を行います。データと問い:", - "exploratory-data-analysis": "私のデータファイルを探索的に分析してください。構造・品質・注目すべきパターンを要約し、次のステップを提案します。ファイル:", - "scientific-visualization": "出版品質の図を作成してください。明確なレイアウト、誠実なエラーバー、色覚に配慮した配色、ジャーナル書式を用います。示したい内容:", - "scientific-critical-thinking": "この研究や主張を批判的に評価してください。エビデンスの質を評価し、バイアスや交絡を見抜き、結論を吟味します。対象:", - "paper-lookup": "学術データベースから関連論文とオープンアクセス全文を探し、再利用できる引用も示してください。探しているもの:" - }, - "paper-lookup": "論文検索", - "paper-lookupDesc": "10 の学術 API(PubMed、arXiv、OpenAlex、Crossref…)で論文・引用・オープンアクセス全文を検索。", - "scientific-critical-thinking": "批判的思考", - "scientific-critical-thinkingDesc": "科学的主張とエビデンスの質を評価。バイアスや交絡を見抜き、GRADE やバイアスリスク枠組みを適用。", - "scientific-visualization": "科学的可視化", - "scientific-visualizationDesc": "出版品質の図。マルチパネル配置、有意差注釈、ジャーナル固有の書式に対応。", - "exploratory-data-analysis": "探索的データ解析", - "exploratory-data-analysisDesc": "200 以上の形式の科学データファイルを自動探索し、品質指標とレポートを生成。", - "statistical-analysis": "統計解析", - "statistical-analysisDesc": "ガイド付き統計解析。検定の選択、前提確認、効果量、APA 形式の報告に対応。", - "statistical-power": "統計的検出力", - "statistical-powerDesc": "サンプルサイズと検出力の分析。必要な被験者数、最小検出可能効果、検出力曲線を算出。", - "experimental-design": "実験計画", - "experimental-designDesc": "データ収集前に厳密な研究を設計。無作為化・ブロック化・対照・要因/DOE 配置に対応。", - "hypothesis-generation": "仮説生成", - "hypothesis-generationDesc": "観察を検証可能な仮説に変換し、予測・メカニズム・検証実験を提示します。", - "scientific-brainstorming": "科学的ブレインストーミング", - "scientific-brainstormingDesc": "自由な研究アイデア出し。分野横断のつながりを探り、前提を問い直し、研究の空白を見つけます。", - "tabs": { - "office": "日常業務", - "coding": "コード開発", - "research": "科学研究" - }, - "coding": { - "brainstormingDesc": "着手前に意図と要件を整理", - "debuggingDesc": "修正の前に根本原因を特定", - "writingSkillsDesc": "再利用可能なスキルを作成・編集・検証" - }, - "notEnabled": { - "title": "「{skill}」スキルは {agent} でまだ有効になっていません", - "description": "設定で有効にすると、ここで使用できます。", - "action": "有効にする", - "hint": "スキルが無効です" - }, - "scrollPrev": "前のスキルを表示", - "scrollNext": "次のスキルを表示" - } - }, - "agentSelector": { - "noEnabledAgents": "有効なエージェントがありません", - "openAgentsSettings": "エージェント設定を開く", - "notInstalled": "未インストール", - "moreAgents": "他のエージェント({count})" - }, - "subAgentOverlay": { - "title": "サブエージェント", - "collapsedSummary": "サブエージェント {count}", - "collapseAria": "サブエージェントを折りたたむ" - }, - "agentPlanOverlay": { - "title": "エージェントプラン", - "collapsePlanAria": "プランを折りたたむ", - "collapsedSummary": "計画 {completed}/{total}", - "status": { - "completed": "完了", - "inProgress": "進行中", - "pending": "保留", - "unknown": "不明" - }, - "priority": { - "high": "高", - "medium": "中", - "low": "低", - "unknown": "不明" - } - }, - "permissionDialog": { - "subtitle": "エージェントがこのターンを続行するための許可を要求しています。", - "queuedCount": "他 {count} 件待機中", - "kindFallbackTool": "ツール", - "command": "コマンド", - "cwd": "作業ディレクトリ: {cwd}", - "filesSummary": "ファイル: {count}", - "moreFiles": "+{count} 件の追加ファイル", - "plan": "計画", - "allowedActions": "許可されたアクション", - "targetMode": "対象モード: {mode}", - "optionGrants": "各選択肢が許可する内容", - "changeScopeSession": "このセッション", - "changeScopeProcess": "この実行", - "changeScopeUser": "ユーザー設定に保存", - "changeScopeProject": "プロジェクト設定に保存", - "changeScopeProjectLocal": "ローカルプロジェクト設定に保存", - "changeScopePersistent": "永続的に保存" - }, - "questionDialog": { - "title": "エージェントが質問しています", - "placeholder": "回答を入力...", - "send": "送信" - }, - "messageBranch": { - "previousBranchAria": "前のブランチ", - "nextBranchAria": "次のブランチ", - "pageOf": "{current} / {total}" - }, - "terminal": { - "title": "ターミナル", - "running": "実行中" - }, - "reasoning": { - "thinking": "考え中…", - "thoughtForFewSeconds": "考えた", - "thoughtForSeconds": "考えた" - }, - "linkSafety": { - "errorCannotOpen": "ローカルファイルを開けません", - "errorNoWorkspace": "現在アクティブなワークスペースフォルダがありません。", - "errorFailedOpen": "ローカルファイルを開けませんでした", - "errorFailedLink": "リンクを開けませんでした", - "errorUnsupportedLinkProtocol": "このリンクプロトコルはサポートされていません。" - }, - "fileActions": { - "openInFinder": "Finderで開く", - "openInExplorer": "エクスプローラーで開く", - "openInFileManager": "ファイルマネージャーで開く", - "copyRelativePath": "相対パスをコピー", - "copyAbsolutePath": "絶対パスをコピー", - "pathCopied": "パスをコピーしました", - "copyPathFailed": "パスのコピーに失敗しました", - "openFailed": "ローカルファイルを開けませんでした" - }, - "messageList": { - "attachedResources": "添付リソース", - "loading": "読み込み中...", - "loadEarlier": "以前のメッセージを読み込む", - "loadingEarlier": "以前のメッセージを読み込み中…", - "error": "エラー: {message}", - "errorTitle": "セッションの読み込みに失敗しました", - "errorActionReload": "再読み込み", - "errorActionNewSession": "新規会話", - "emptyConversation": "この会話にはメッセージがありません。", - "systemMessage": "システムメッセージ", - "copyMessage": "コピー", - "copied": "コピー済み", - "downloadImage": "画像をダウンロード", - "downloadFailed": "ダウンロードに失敗しました: {message}", - "imageGeneration": "画像生成", - "imageGenerationPending": "画像を生成中…", - "imageGenerationFailed": "画像生成に失敗しました", - "model": "モデル", - "tokenStats": "トークン使用量", - "tokenInput": "入力", - "tokenOutput": "出力", - "tokenCacheRead": "キャッシュ読取", - "tokenCacheWrite": "キャッシュ書込", - "duration": "所要時間", - "completedAt": "完了時刻", - "jumpToPreviousUserMessage": "前のユーザーメッセージへ", - "showMore": "もっと見る", - "showLess": "折りたたむ" - }, - "liveTurnStats": { - "thinking": "考え中...", - "streaming": "ストリーミング中", - "elapsedHours": "{value}時間", - "elapsedMinutes": "{value}分", - "elapsedSeconds": "{value}秒", - "outputSpeedAria": "推定出力速度", - "outputSpeedTooltip": "推定出力速度(テキスト + 思考)" - }, - "jsonTree": { - "viewRaw": "生の JSON を表示", - "viewTree": "ツリー表示", - "fields": "{count} 個のフィールド", - "items": "{count} 件" - }, - "tool": { - "parameters": "パラメーター", - "error": "エラー", - "result": "結果", - "status": { - "approvalRequested": "承認待ち", - "approvalResponded": "応答済み", - "inputAvailable": "実行中", - "inputStreaming": "保留中", - "outputAvailable": "完了", - "outputDenied": "拒否", - "outputError": "エラー" - } - }, - "toolCallBlock": { - "tool": "ツール", - "error": "エラー", - "result": "結果" - }, - "delegation": { - "subAgentRunning": "サブエージェント実行中…", - "noDetail": "No detail available yet.", - "unknownAgent": "サブエージェント", - "openDetail": "会話を表示", - "detailTitle": "サブエージェントの会話", - "detailDescription": "委任されたサブエージェントの会話を読み取り専用で表示します。", - "waitForResult": "タスク {task} の実行結果を待機中", - "waitForResultNoTask": "タスクの実行結果を待機中", - "cancelTask": "タスク {task} をキャンセル中", - "cancelTaskNoTask": "タスクをキャンセル中", - "resultPageOf": "{current} / {total}", - "prevResult": "前の結果", - "nextResult": "次の結果", - "noResultText": "このチェックでは結果がありません", - "status": { - "starting": "起動中", - "running": "実行中", - "checked": "確認済み", - "waiting": "承認待ち", - "ok": "完了", - "err": { - "default": "失敗", - "delegation_disabled": "無効", - "depth_limit": "深さ上限", - "invalid_agent_type": "不正なエージェント", - "spawn_failed": "起動失敗", - "send_failed": "送信失敗", - "timeout": "タイムアウト", - "canceled": "キャンセル済み", - "child_refusal": "サブエージェント拒否", - "child_max_tokens": "サブエージェント: トークン上限", - "child_max_turn_requests": "サブエージェント: 要求上限", - "child_empty": "サブエージェント応答なし", - "child_unknown": "サブエージェント: エラー", - "unknown": "不明なタスク" - } - } - }, - "contentParts": { - "showingTailOutput": "パフォーマンスのため、ストリーミング中は末尾出力を表示しています。", - "result": "結果", - "unknown": "不明", - "inputTruncated": "入力が切り詰められました — diff が不完全な可能性があります。", - "replaceAll": "すべて置換", - "filesCount": "ファイル: {count}", - "update": "更新", - "moreFiles": "+{count} 件の追加ファイル", - "timeoutMs": "タイムアウト: {timeout}ms", - "backgroundTrue": "バックグラウンド: true", - "scriptToolCalls": "{count} 個のツールを呼び出し", - "offset": "オフセット: {offset}", - "limit": "上限: {limit}", - "pages": "ページ: {pages}", - "mode": "モード: {mode}", - "cell": "セル: {cell}", - "shellSession": "セッション {id}", - "pathLabel": "パス:", - "globLabel": "Glob パターン:", - "typeLabel": "タイプ:", - "outputLabel": "出力:", - "caseInsensitive": "大文字小文字を区別しない", - "multiline": "複数行", - "promptLabel": "プロンプト", - "subjectLabel": "件名", - "taskLabel": "タスク", - "nameLabel": "名前:", - "agentPromptLabel": "プロンプト", - "agentModelLabel": "モデル", - "agentRunning": "実行中...", - "agentLiveTranscript": "ライブアクティビティ", - "agentProgressTools": "{count} 件のツール呼び出し", - "agentProgressTurns": "{count} ターン", - "agentProgressContext": "コンテキスト {pct}%", - "agentSessionAction": "サブエージェントのセッションを表示", - "agentSessionTitle": "サブエージェントのセッション", - "agentSessionLoading": "サブエージェントの記録を読み込んでいます…", - "agentSessionEmpty": "サブエージェントはまだ何も書き込んでいません。", - "agentFallbackTitle": "サブエージェント起動中…", - "agentCodexLaunchOnly": "起動しました。Codex はこのサブエージェントの進捗をこれ以上通知しません。結果はこの会話のメッセージとして届きます。", - "agentStatsBash": "コマンド", - "agentStatsRead": "ファイル読取", - "agentStatsSearch": "検索", - "agentStatsEdit": "編集", - "agentStatsOther": "その他", - "goal": { - "title": "目標:", - "titleWithStatus": "目標 {status}", - "objective": "目標", - "statusLabel": "ステータス", - "tokensUsed": "使用 tokens", - "budget": "予算", - "remaining": "残り", - "elapsed": "経過時間", - "tokens": "tokens", - "pause": "一時停止", - "clear": "クリア", - "status": { - "active": "実行中", - "paused": "一時停止", - "blocked": "ブロック中", - "usageLimited": "使用量制限", - "budgetLimited": "予算制限", - "complete": "完了", - "limited": "上限到達" - } - }, - "field": { - "file": "ファイル", - "notebook": "ノートブック", - "command": "コマンド", - "old": "旧", - "new": "新", - "pattern": "パターン", - "path": "パス", - "query": "クエリ", - "url": "URL:", - "description": "説明", - "content": "内容", - "source": "ソース", - "prompt": "プロンプト", - "subject": "件名", - "taskId": "タスク ID", - "status": "状態", - "skill": "Skill", - "args": "引数", - "offset": "オフセット", - "limit": "上限", - "glob": "Glob パターン", - "type": "タイプ", - "output": "出力", - "replaceAll": "すべて置換", - "language": "言語", - "timeout": "タイムアウト", - "background": "バックグラウンド", - "agentType": "エージェント種別", - "library": "ライブラリ", - "libraryId": "ライブラリ ID" - }, - "title": { - "edit": "編集", - "command": "コマンド", - "script": "スクリプト", - "waitCommand": "待機 {command}", - "waitCell": "セッション {id} を待機", - "terminateCommand": "停止 {command}", - "terminateCell": "セッション {id} を停止", - "stdinChars": "入力 {chars}", - "todoWrite": "TodoWrite(タスク更新)", - "read": "読み取り", - "write": "書き込み", - "notebookEdit": "NotebookEdit(ノート編集)", - "editFiles": "編集 ({count} 件のファイル)", - "editWithTarget": "{target} を編集", - "readWithTarget": "{target} を読み取り", - "writeWithTarget": "{target} に書き込み", - "notebookEditWithTarget": "NotebookEdit({target})", - "globWithPattern": "Glob パターン {pattern}", - "listFilesWithPath": "ファイル一覧 {path}", - "grepWithPattern": "Grep パターン {pattern}", - "taskCreateWithSubject": "タスク作成: {subject}", - "taskUpdateWithStatus": "タスク更新 #{id} -> {status}", - "taskUpdate": "タスク更新 #{id}", - "webFetchWithUrl": "WebFetch({url})", - "webSearchWithQuery": "WebSearch({query})", - "todosProgress": "タスク ({done}/{total})", - "skillWithName": "Skill: {name}", - "genericWithContext": "{tool}({context})" - }, - "search": { - "noMatches": "一致する結果なし", - "matchSummary": "{matches} 件の一致 · {files} 件のファイル", - "fileSummary": "{files} 件のファイル", - "moreResults": "他に {count} 件の結果は非表示" - }, - "toolGroup": { - "search": "{count} 件を検索", - "command": "{count} 件のコマンドを実行", - "read": "ファイルを {count} 回読み取り", - "memory": "{count} 件の記憶を呼び出し", - "edit": "ファイルを {count} 回編集", - "fetch": "{count} 件のリソースを取得", - "think": "{count} 回思考", - "todo": "{count} 件の TODO を更新", - "task": "{count} 件のタスクを実行", - "other": "{count} 件のツールを使用", - "errorSuffix": "{count} 件失敗", - "joiner": " · " - }, - "planMode": { - "entered": "計画モードを開始", - "planLabel": "計画", - "reviewApproved": "計画を承認 — 実行します", - "reviewKept": "プランモードを維持", - "reviewPending": "計画の判断待ち", - "submitted": "計画を送信しました", - "switched": "モードを切り替え" - }, - "backgroundTask": { - "title": "バックグラウンドタスク", - "titleWithId": "バックグラウンドタスク · {id}", - "running": "実行中", - "completed": "完了", - "failed": "失敗", - "stopped": "停止しました", - "exitCode": "終了コード {code}", - "polledTimes": "{count} 回ポーリング", - "runningInBackground": "バックグラウンド", - "launchNote": "バックグラウンドで実行中 · {id}" - }, - "codexScript": { - "outputMissing": "codex がスクリプト出力を切り詰めた際にこのコマンドの区切り行が失われたため、出力を割り当てられませんでした。", - "sharedWith": "この範囲には {commands} の出力も含まれます — 区切り行が codex により切り捨てられました。", - "truncated": "切り詰め済み" - } - }, - "messageNav": { - "title": "メッセージナビ", - "collapse": "メッセージナビを閉じる", - "collapsedSummary": "メッセージ {count}", - "fileCount": "{count, plural, one {# 個のファイル} other {# 個のファイル}}", - "remove": "削除", - "noDiffDataAvailable": "{filePath} の差分データがありません" - }, - "replyArtifacts": { - "title": "変更されたファイル", - "fileCount": "{count, plural, one {# 個のファイル} other {# 個のファイル}}", - "newFilesTitle": "新規ファイル", - "revealInFolder": "ファイルマネージャーで表示", - "openFile": "{filePath} を開く", - "openInEditor": "エディタで開く", - "remove": "削除", - "noDiffDataAvailable": "{filePath} の差分データがありません" - }, - "askQuestion": { - "title": "エージェントが選択を求めています", - "subtitle": "回答したら送信してください。いつでもスキップできます", - "recommended": "推奨", - "other": "その他", - "otherPlaceholder": "回答を入力…", - "singleSelect": "単一選択", - "multiSelect": "複数選択", - "skip": "スキップ", - "next": "次へ", - "submit": "送信", - "submitError": "送信できませんでした。もう一度お試しください。" - }, - "planApproval": { - "title": "エージェントが計画を提示しました — 確認してください", - "emptyPlan": "エージェントは計画を作成しませんでした。承認して実装を開始するか、変更を依頼してください。", - "approve": "承認して開始", - "requestChanges": "変更を依頼", - "abandon": "破棄", - "feedbackPlaceholder": "何を変更しますか?", - "sendChanges": "送信", - "cancel": "キャンセル", - "submitError": "送信できませんでした。もう一度お試しください。" - }, - "feedbackCheckResult": { - "count": "フィードバック {count} 件", - "expand": "すべてのフィードバックを表示", - "collapse": "折りたたむ", - "errorTitle": "フィードバックの確認に失敗しました" - }, - "askQuestionResult": { - "title": "質問", - "answeredLabel": "質問と回答:", - "awaiting": "回答をお待ちしています…", - "declined": "この質問をスキップしました — エージェントが独自に判断して進めました。", - "noSelection": "選択なし" - }, - "configStale": { - "agentConfigTitle": "エージェント設定が更新されました", - "modelProviderTitle": "モデルプロバイダーが更新されました", - "description": "このセッションは以前の設定のままです。再接続すると適用されます(会話履歴は保持されます)。", - "reconnect": "再接続して適用", - "reconnecting": "再接続中…", - "reconnectDisabledDuringTurn": "現在のターンが完了すると再接続できます", - "dismiss": "閉じる", - "reconnectFailed": "セッションの再接続に失敗しました", - "applied": "新しい設定を適用しました" - }, - "piProjectTrust": { - "title": "このプロジェクトには pi リソースが含まれています", - "description": "pi はリポジトリ自身の .pi ファイルを読み込んでいません。確認して判断してください。", - "descriptionExecutable": "リポジトリには pi 拡張機能が含まれており、起動時にコードを実行します。pi はまだ読み込んでいません。判断する前に確認してください。", - "review": "確認…", - "dismiss": "閉じる", - "dialogTitle": "このプロジェクトの pi リソースを信頼しますか?", - "dialogDescription": "フォルダーを信頼した場合にのみ、pi はリポジトリ自身の .pi ファイルを読み込みます。このリポジトリの内容を信頼できる場合にのみ許可してください。", - "executionWarning": "拡張機能はコードです。このフォルダーを信頼すると、メッセージを送信する前に、リポジトリの拡張機能が pi の起動時にあなたの権限で実行されます。", - "scopeNote": "この判断は pi の trust.json に保存され、その配下のすべてのフォルダーに適用されます。ターミナルで自分で pi を実行するときにも使われます。後から「設定 → エージェント → Pi」で変更できます。", - "trust": "プロジェクトを信頼", - "decline": "読み込まないままにする", - "disabledDuringTurn": "現在のターンが終了すると利用できます", - "trustedToast": "プロジェクトを信頼しました — pi がリソースを読み込むよう再接続しました", - "declinedToast": "プロジェクトのリソースは読み込まれません", - "saveFailed": "プロジェクトの信頼設定の保存に失敗しました", - "grantTitle": "このプロジェクトは既に信頼されています", - "grantDescription": "pi はこのリポジトリ自身の .pi ファイルを読み込みます。何が許可されるか確認してください。", - "grantInheritedDescription": "親フォルダーが信頼されているため、pi はこのリポジトリ自身の .pi ファイルを読み込みます。何が許可されるか確認してください。", - "grantDialogTitle": "このプロジェクトの pi リソースは信頼されています", - "grantDialogDescription": "pi はこのリポジトリ自身の .pi ファイルの読み込みを許可されています。以前のバージョンの codeg はフォルダーを開いた時点で自動的に許可していたため、確認を求められていない可能性があります。", - "grantExecutionWarning": "拡張機能はコードです。リポジトリの拡張機能は、メッセージを送信する前に pi の起動時にあなたの権限で実行されます。", - "inheritedFrom": "信頼の由来", - "revoke": "信頼を取り消す", - "keepTrusted": "信頼を維持", - "revokedToast": "信頼を取り消しました — 再接続したため pi はプロジェクトのリソースを読み込みません", - "trustedNoReconnect": "プロジェクトを信頼しました — pi の次回起動時に適用されます", - "revokedNoReconnect": "信頼を取り消しました — pi の次回起動時に適用されます" - }, - "collabAgent": { - "title": "サブエージェント", - "errorTitle": "サブエージェントのタスクが失敗しました", - "statesLabel": "サブエージェント", - "statusRunning": "実行中", - "statusCompleted": "完了", - "statusFailed": "失敗", - "statusPending": "起動中", - "statusInterrupted": "中断", - "statusClosed": "終了", - "statusNotFound": "見つかりません", - "opSpawn": "サブエージェントを起動中", - "opWait": "サブエージェントの結果を取得中", - "opClose": "サブエージェントを終了中", - "opResume": "サブエージェントを再開中" - }, - "contextCompaction": { - "compacting": "コンテキストを圧縮しています…", - "compacted": "コンテキストを圧縮しました", - "compactedTokens": "コンテキストを圧縮 · {before} → {after} トークン", - "failed": "コンテキストの圧縮に失敗しました" - }, - "sessionFailure": { - "category": { - "connection": "接続の問題", - "access": "アクセスの問題", - "limit": "上限に到達", - "request": "リクエスト拒否", - "service": "サービスの問題", - "unknown": "セッションの問題" - }, - "action": { - "retry": "再試行", - "login": "サインイン", - "newSession": "新しいセッション" - }, - "recovered": "回復済み", - "retryUnavailable": "再送信できるメッセージがありません。", - "toggleDetails": "詳細の切り替え" - }, - "backgroundTasks": { - "running": "{count} 件のバックグラウンドタスクを実行中", - "settling": "バックグラウンド結果を同期中…", - "settledFallback": "バックグラウンドタスクが終了しました({status})", - "cardRunning": "バックグラウンドで実行中", - "cardLaunchedPending": "バックグラウンドタスクを開始しました", - "cardCompleted": "バックグラウンドタスクが完了しました", - "cardFinishedWithStatus": "バックグラウンドタスクが終了しました({status})", - "cardResultPending": "結果はまだ返っていません" - }, - "proposedPlan": { - "title": "提案された計画", - "planning": "計画中…" - } - }, - "diffPreview": { - "mode": { - "added": "追加", - "deleted": "削除", - "renamed": "名前変更", - "modified": "変更" - }, - "hunkLabel": "ハンク {index}", - "loadingHunk": "Hunk を読み込み中...", - "noDiffData": "Diff データがありません", - "showRemainingLines": "残り {count} 行を表示" - }, - "conversationContextBar": { - "folderTitle": "作業フォルダ", - "branchTitle": "作業ブランチ", - "searchFolder": "Search folder...", - "searchBranch": "Search branch...", - "noFolders": "No folders", - "noBranches": "No branches", - "noBranch": "(no branch)", - "chatModeLabel": "チャットモード", - "commit": "Commit", - "push": "Push", - "merge": "Merge", - "toasts": { - "folderChanged": "Switched to {name}", - "openFolderFailed": "Failed to open folder", - "switchedToChatMode": "チャットモードに切り替えました", - "openStashFailed": "Failed to open stash window", - "openMergeFailed": "Failed to open merge window" - } - }, - "cloneDialog": { - "title": "リポジトリをクローン", - "repositoryUrl": "リポジトリ URL", - "repositoryUrlPlaceholder": "https://github.com/user/repo.git", - "directory": "ディレクトリ", - "directoryPlaceholder": "保存先ディレクトリを選択...", - "browseDirectory": "ディレクトリを参照", - "cancel": "キャンセル", - "clone": "クローン", - "clonePath": "クローンパス: {path}" - }, - "toasts": { - "cloneFailed": "リポジトリのクローンに失敗しました" - } - }, - "ProjectBoot": { - "title": "プロジェクトブート", - "tabs": { - "shadcn": "shadcn", - "hyperframes": "HyperFrames" - }, - "hyperframes": { - "title": "HyperFrames 動画プロジェクト", - "subtitle": "HTML から動画を生成するプロジェクトを作成します。ワークスペースのエージェントがそれを記述・レンダリングできます。", - "resolution": "解像度", - "skillsTitle": "エージェントスキル", - "skillsDesc": "選択したエージェント向けに HyperFrames スキルをグローバル(シンボリックリンク)でインストールし、動画の作成・レンダリングを可能にします。", - "recheck": "再チェック", - "installedBadge": "インストール済み", - "skillsInstall": "スキルをインストール / 更新", - "skillsInstalling": "スキルをインストール中…", - "skillsInstalled": "HyperFrames スキルをインストールしました", - "skillsInstallFailed": "HyperFrames スキルのインストールに失敗しました" - }, - "config": { - "base": "ベース", - "style": "スタイル", - "baseColor": "ベースカラー", - "theme": "テーマ", - "chartColor": "チャートカラー", - "iconLibrary": "アイコンライブラリ", - "font": "フォント", - "fontHeading": "見出しフォント", - "menuAccent": "メニューアクセント", - "menuColor": "メニューカラー", - "radius": "角丸", - "template": "テンプレート", - "createProject": "プロジェクトを作成", - "sectionStyle": "スタイル", - "sectionColors": "カラー", - "sectionTypography": "タイポグラフィ", - "sectionInterface": "インターフェース" - }, - "preview": { - "loading": "プレビューを読み込み中..." - }, - "createDialog": { - "title": "プロジェクトを作成", - "projectName": "プロジェクト名", - "projectNamePlaceholder": "my-app", - "frameworkTemplate": "フレームワークテンプレート", - "packageManager": "パッケージマネージャー", - "saveDirectory": "保存先ディレクトリ", - "saveDirectoryPlaceholder": "ディレクトリを選択...", - "browseDirectory": "参照", - "projectPath": "プロジェクトの作成先:{path}", - "advancedOptions": "詳細オプション", - "base": "基盤ライブラリ", - "enableRtl": "RTL サポートを有効にする", - "enableRtlDescription": "右から左に書く言語(アラビア語、ヘブライ語など)のレイアウトサポートを有効にする", - "pmChecking": "確認中...", - "pmNotInstalled": "未インストール", - "cancel": "キャンセル", - "create": "作成", - "creating": "プロジェクトを作成中..." - }, - "toasts": { - "createFailed": "プロジェクトの作成に失敗しました", - "createSuccess": "プロジェクトが正常に作成されました", - "openWorkspaceFailed": "プロジェクトは作成されましたが、ワークスペースで開けませんでした" - }, - "errors": { - "directoryExists": "対象ディレクトリは既に存在します", - "commandFailed": "プロジェクト作成コマンドが失敗しました。" - } - }, - "WebServiceSettings": { - "addressSwitchHint": "切り替えても、ここに表示され開くアドレスが変わるだけです。サービスはすべてのインターフェースで待ち受けており、どのアドレスからもアクセスできます。", - "sectionTitle": "Webサービス", - "sectionDescription": "有効にするとブラウザからCodegにリモートアクセスできます", - "port": "ポート", - "status": "ステータス", - "autoStart": "自動起動", - "autoStartHint": "Codeg の起動時に Web サービスを開始", - "running": "実行中", - "stopped": "停止中", - "processing": "処理中...", - "start": "開始", - "stop": "停止", - "startFailed": "開始に失敗しました", - "stopFailed": "停止に失敗しました", - "saveConfigFailed": "Webサービス設定の保存に失敗しました", - "open": "開く", - "hide": "非表示", - "show": "表示", - "copy": "コピー", - "qrcode": "QRコード", - "qrcodeTitle": "スキャンして開く", - "qrcodeHint": "スマートフォンでスキャンして、ブラウザで Codeg を開きます", - "addressLabel": "アクセスアドレス", - "tokenLabel": "アクセストークン", - "tokenHint": "Webクライアントの初回アクセス時にこのトークンを入力してください", - "tokenPlaceholder": "空欄の場合は自動生成", - "regenerate": "再生成", - "stalePortOccupiedTitle": "ポート {port} は他のプロセスに使用されています", - "stalePortUnknownTitle": "ポート {port} の状態を確認できません", - "stalePortHint": "ポートが解放されるまで Codeg はバインドできません。上のポートを変更するか、占有しているプロセスを終了してください。", - "errors": { - "alreadyRunning": "Web サービスはすでに起動しています", - "invalidAddress": "ホストまたはポートの形式が無効です", - "portInUse": "ポート {port} はすでに使用中です。そのポートを使用しているプロセスを終了するか、別のポートを指定してください", - "permissionDenied": "権限が不足しています。1024 以上のポートを使用するか、より高い権限で実行してください", - "addressUnavailable": "このアドレスはこの端末では利用できません", - "bindFailed": "アドレスのバインドに失敗しました" - } - }, - "DirectoryBrowser": { - "title": "ディレクトリを参照", - "pathPlaceholder": "ディレクトリパスを入力...", - "goHome": "ホームディレクトリへ", - "navigateUp": "親ディレクトリへ", - "select": "選択", - "cancel": "キャンセル", - "loading": "読み込み中...", - "emptyDirectory": "このディレクトリは空です", - "errorLoadingDir": "ディレクトリの読み込みに失敗しました", - "permissionDenied": "アクセス権がありません" - }, - "ChatChannelSettings": { - "loading": "読み込み中...", - "sectionTitle": "チャットチャンネル", - "sectionDescription": "IM ボットを設定して、イベント通知やコーディング活動の照会を行います。", - "addChannel": "チャンネルを追加", - "noChannels": "チャットチャンネルはまだ設定されていません。", - "channelName": "名前", - "channelNamePlaceholder": "My Telegram Bot", - "channelType": "チャンネルタイプ", - "lark": "Lark(飛書)", - "weixin": "WeChat", - "dailyReport": "デイリーレポート", - "dailyReportTime": "送信時刻", - "nameRequired": "チャンネル名を入力してください。", - "tokenRequired": "トークンを入力してください。", - "chatIdRequired": "Chat ID を入力してください。", - "topicMode": "トピックグループモード", - "topicModeHint": "Telegram forum topics を個別の Codeg セッションとしてルーティングします。Bot は forum supergroup に参加し、topics を管理できる必要があります。", - "loadFailed": "チャンネルの読み込みに失敗しました。", - "saveFailed": "保存に失敗しました。", - "connectSuccess": "チャンネルに接続しました。", - "connectFailed": "接続に失敗しました", - "disconnectSuccess": "チャンネルを切断しました。", - "disconnectFailed": "切断に失敗しました。", - "testSuccess": "接続テストに合格しました。", - "testFailed": "接続テストに失敗しました", - "deleteSuccess": "チャンネルを削除しました。", - "deleteFailed": "チャンネルの削除に失敗しました。", - "deleteConfirmTitle": "チャンネルを削除", - "deleteConfirmMessage": "このチャンネルとメッセージログを完全に削除します。よろしいですか?", - "cancel": "キャンセル", - "delete": "削除", - "create": "作成", - "save": "保存", - "channelListTitle": "設定済みチャンネル", - "channelListDescription": "有効なチャンネルはサービス起動時に自動接続されます。", - "editChannel": "チャンネルを編集", - "editSuccess": "チャンネルを更新しました。", - "tokenPlaceholderKeep": "空欄で現在の値を維持", - "weixinScanTitle": "QRコードをスキャン", - "weixinScanDescription": "WeChatを開いてQRコードをスキャンして接続してください。", - "weixinQrcodeExpired": "QRコードの有効期限が切れました。", - "weixinRefreshQrcode": "更新", - "weixinWaitingScan": "スキャン待ち...", - "weixinPollError": "接続が不安定です。再試行中...", - "weixinReconnectNotice": "iLink プロトコルの制限により、再接続のたびにまずボットにメッセージを送信しないとイベントトリガーが有効になりません。", - "connect": "接続", - "disconnect": "切断", - "test": "接続テスト", - "tabs": { - "channels": "チャンネル", - "commands": "コマンド", - "events": "イベント", - "other": "その他" - }, - "commands": { - "title": "組み込みコマンド", - "description": "チャットチャンネルで使用可能な Bot コマンド。グループチャットではメッセージを処理するために @Bot が必要です。", - "prefixLabel": "コマンドプレフィックス", - "prefixDescription": "Bot コマンドを起動するプレフィックス、1-3 文字の英数字以外の文字(デフォルト /)。", - "prefixSaved": "コマンドプレフィックスを保存しました。", - "prefixSaveFailed": "コマンドプレフィックスの保存に失敗しました。", - "prefixInvalid": "プレフィックスは1-3文字の英数字以外の文字である必要があります。", - "save": "保存", - "folderDesc": "作業フォルダを選択", - "agentDesc": "AIエージェントを選択", - "taskDesc": "セッションを作成してタスクを実行", - "sessionsDesc": "フォルダ内のアクティブなセッション一覧", - "resumeDesc": "最近の会話 / セッションを再開", - "cancelDesc": "現在のタスクをキャンセル", - "approveDesc": "エージェントの権限リクエストを承認", - "denyDesc": "エージェントの権限リクエストを拒否", - "searchDesc": "キーワードで会話を検索", - "todayDesc": "本日のアクティビティ概要", - "statusDesc": "チャンネル接続状態", - "helpDesc": "ヘルプを表示" - }, - "events": { - "title": "イベント通知", - "description": "イベントを有効にすると、トリガーされた際にチャンネルにプッシュされます。", - "turnComplete": "ターン完了", - "turnCompleteDesc": "エージェントのターンが終了した時", - "error": "エージェントエラー", - "errorDesc": "エージェントがエラーに遭遇した時", - "permissionRequest": "権限リクエスト", - "permissionRequestDesc": "エージェントが操作の権限を要求した時", - "questionRequest": "エージェントからの質問", - "questionRequestDesc": "エージェントが質問したとき", - "userPromptSent": "ユーザーメッセージ", - "userPromptSentDesc": "メッセージを送信したとき(通知に本文が含まれます)", - "saved": "イベントフィルターを更新しました。", - "saveFailed": "イベントフィルターの保存に失敗しました。", - "loadFailed": "設定の読み込みに失敗しました。", - "retry": "再試行", - "webhooksTitle": "Webhook", - "webhooksDescription": "有効なイベントの発生時に、1 つ以上の URL へ JSON を POST します。上のイベントフィルターは Webhook にも適用されます。", - "webhookUrlPlaceholder": "https://example.com/webhook", - "addWebhook": "Webhook を追加", - "removeWebhook": "Webhook を削除", - "webhookSave": "保存", - "webhooksSaved": "Webhook を保存しました。", - "webhooksSaveFailed": "Webhook の保存に失敗しました。", - "webhookInvalidUrl": "有効な http(s) URL を入力してください。", - "docsTitle": "リクエスト形式", - "docsMethod": "メソッド", - "docsContentType": "Content-Type", - "docsNote": "有効な各イベントはすべての URL に配信されます。Webhook はデバウンスされず、上のイベントフィルターが適用されます。", - "editWebhook": "Webhook を編集", - "enableWebhook": "Webhook を有効化", - "webhookDuplicate": "この URL は既に設定されています。", - "cancel": "キャンセル", - "webhooksEmpty": "Webhook はまだ設定されていません。", - "deleteWebhookTitle": "Webhook を削除", - "deleteWebhookMessage": "この Webhook を削除しますか?このURLにイベントは配信されなくなります。", - "delete": "削除" - }, - "language": { - "title": "メッセージ言語", - "description": "イベント通知、コマンド応答、日次レポートをチャットチャンネルに送信する際に使用する言語。", - "saved": "メッセージ言語を保存しました。", - "saveFailed": "メッセージ言語の保存に失敗しました。", - "en": "英語", - "zh-cn": "簡体字中国語", - "zh-tw": "繁体字中国語", - "ja": "日本語", - "ko": "韓国語", - "es": "スペイン語", - "de": "ドイツ語", - "fr": "フランス語", - "pt": "ポルトガル語", - "ar": "アラビア語" - } - }, - "ModelProviderSettings": { - "sectionTitle": "モデルプロバイダー", - "sectionDescription": "エージェントのAPIプロバイダー認証情報を管理します。", - "filterAll": "すべて", - "providerListTitle": "設定済みプロバイダー", - "addProvider": "プロバイダーを追加", - "editProvider": "プロバイダーを編集", - "noProviders": "モデルプロバイダーはまだ設定されていません。", - "providerName": "名前", - "providerNamePlaceholder": "例: OpenAI、Anthropic", - "apiUrl": "API URL", - "apiUrlPlaceholder": "https://api.openai.com/v1", - "apiKey": "APIキー", - "apiKeyPlaceholder": "sk-...", - "apiKeyKeepCurrent": "空欄のまま現在の値を維持", - "agentTypes": "エージェントタイプ", - "agentTypesRequired": "少なくとも1つのエージェントタイプを選択してください。", - "agentType": "エージェントタイプ", - "agentTypeRequired": "エージェントタイプを選択してください。", - "agentTypeImmutableHint": "エージェントタイプは作成後に変更できません。", - "model": "モデル", - "modelPlaceholderCodex": "gpt-5.6-sol / gpt-5.5", - "modelPlaceholderGemini": "gemini-3-pro-preview", - "claudeMainModel": "メインモデル", - "claudeReasoningModel": "推論モデル(思考)", - "claudeHaikuDefaultModel": "デフォルトの Haiku モデル", - "claudeSonnetDefaultModel": "デフォルトの Sonnet モデル", - "claudeOpusDefaultModel": "デフォルトの Opus モデル", - "claudeCustomModelOption": "カスタムモデル ID", - "claudeCustomModelOptionName": "カスタムモデル名", - "claudeCustomModelOptionDescription": "カスタムモデルの説明", - "claudeCustomModelOptionHint": "Claude のモデル選択メニューにカスタム項目を1つ追加します(例: カスタムゲートウェイ/プロキシ経由のモデル)。名前と説明は任意の表示用設定です。", - "nameRequired": "プロバイダー名は必須です。", - "apiUrlRequired": "API URLは必須です。", - "apiKeyRequired": "APIキーは必須です。", - "loadFailed": "プロバイダーの読み込みに失敗しました。", - "saveFailed": "変更の保存に失敗しました。", - "createSuccess": "プロバイダーを作成しました。", - "editSuccess": "プロバイダーを更新しました。", - "deleteSuccess": "プロバイダーを削除しました。", - "deleteConfirmTitle": "プロバイダーを削除", - "deleteConfirmMessage": "プロバイダー「{name}」を完全に削除しますか?", - "deleteBlockedByAgent": "{agents} がこのプロバイダーを使用中です。削除する前にリンクを解除してください。", - "cancel": "キャンセル", - "delete": "削除", - "create": "作成", - "save": "保存", - "affectedRunningSessions": "{count} 件の実行中セッションは再接続すると変更が適用されます" - }, - "SkillMatrix": { - "loading": "読み込み中…", - "searchPlaceholder": "名前・ID・説明で検索", - "empty": "表示する項目がありません。", - "emptySearch": "現在の検索に一致する項目がありません。", - "skillColumn": "スキル", - "selectAll": "表示中をすべて選択", - "selectSkill": "{name} を選択", - "everything": { - "label": "一括", - "enable": "すべて有効化(表示中)", - "disable": "すべて無効化(表示中)" - }, - "columnMenu": { - "enableAll": "すべてのスキルを有効化", - "disableAll": "すべてのスキルを無効化" - }, - "rowMenu": { - "label": "{name} の一括操作", - "enableAll": "すべてのエージェントで有効化", - "disableAll": "すべてのエージェントで無効化" - }, - "bulk": { - "selected": "{count} 件選択中", - "targetAll": "すべてのエージェント", - "targetSome": "{count} 個のエージェント", - "enable": "有効化", - "disable": "無効化", - "clear": "クリア" - }, - "confirm": { - "disableTitle": "これらのリンクを無効化しますか?", - "disableBody": "codeg が管理する {count} 件のスキルリンクを削除します。カスタムディレクトリを占有しているスキルはそのまま残ります。いつでも再び有効化できます。", - "cancel": "キャンセル", - "confirm": "無効化" - }, - "toasts": { - "loadFailed": "スキルの状態の読み込みに失敗しました", - "applyFailed": "変更の適用に失敗しました", - "enabled": "{count} 件のリンクを有効化しました", - "disabled": "{count} 件のリンクを無効化しました", - "enabledPartial": "{ok} 件を有効化、{failed} 件が失敗しました", - "disabledPartial": "{ok} 件を無効化、{failed} 件が失敗しました" - }, - "detail": { - "enableForAgents": "エージェントで有効化", - "preview": "SKILL.md プレビュー", - "loadingContent": "コンテンツを読み込み中…" - }, - "copyModeHint": "コピー済み(リンクではありません)— 更新後は最新版を取得するため再度有効化してください" - }, - "ExpertsSettings": { - "title": "エキスパートスキル", - "description": "AI コーディングエージェント向けに、厳選され実戦で検証されたスキルワークフローを有効にします。各エキスパートは superpowers プロジェクトの独立したスキルで、codeg が中央コピーを管理し、選択したエージェントにリンクします。", - "loading": "エキスパートを読み込み中…", - "loadingContent": "コンテンツを読み込み中…", - "emptyExperts": "利用可能なエキスパートがありません。アプリケーションログを確認してください。", - "emptySelection": "エキスパートを選択して内容を表示し、有効化を管理します。", - "emptySearch": "現在の検索に一致するエキスパートはありません。", - "searchPlaceholder": "名前、ID、または説明でエキスパートを検索", - "enableForAgents": "エージェントで有効化", - "noAgents": "ACP エージェントが検出されません。", - "copyModeWarning": "コピー済み(リンクなし)。codeg 更新後に最新版を取得するには再度有効化してください。", - "previewTitle": "SKILL.md プレビュー", - "categories": { - "discovery": "発見と設計", - "planning": "計画", - "execution": "実行", - "quality": "品質とテスト", - "debugging": "デバッグ", - "review": "レビューと統合", - "meta": "メタ" - }, - "states": { - "not_linked": "未有効", - "linked_to_codeg": "有効", - "linked_elsewhere": "ブロック — 別のリンクが存在", - "blocked_by_real_directory": "ブロック — カスタムスキルがこの名前を占有", - "broken": "壊れたリンク" - }, - "badges": { - "userModified": "ユーザーにより変更" - }, - "actions": { - "openCentralDir": "中央フォルダを開く", - "refresh": "更新" - }, - "toasts": { - "loadFailed": "エキスパート詳細の読み込みに失敗しました", - "enabled": "このエージェントでエキスパートを有効化しました", - "disabled": "このエージェントでエキスパートを無効化しました", - "enableFailed": "エキスパートの有効化に失敗しました", - "disableFailed": "エキスパートの無効化に失敗しました", - "openFolderFailed": "フォルダを開けませんでした" - } - }, - "ScienceSettings": { - "title": "科学研究スキル", - "description": "AI コーディングエージェント向けに厳選した科学研究スキル(仮説生成・実験計画・統計・可視化・批判的評価・文献検索)を有効化します。codeg が中央コピーを管理し、選んだエージェントに各スキルをリンクします。", - "loading": "科学研究スキルを読み込み中…", - "emptySkills": "利用可能な科学研究スキルがありません。アプリのログを確認してください。", - "searchPlaceholder": "名前・ID・説明で科学研究スキルを検索", - "categories": { - "ideation": "アイデア出し", - "design": "研究デザイン", - "analysis": "分析", - "visualization": "可視化", - "evaluation": "評価", - "literature": "文献" - }, - "states": { - "not_linked": "未有効", - "linked_to_codeg": "有効", - "linked_elsewhere": "ブロック — 別のリンクが存在", - "blocked_by_real_directory": "ブロック — カスタムスキルがこの名前を占有", - "broken": "壊れたリンク" - }, - "badges": { - "userModified": "ユーザーにより変更", - "needsKey": "APIキーが必要", - "needsSetup": "環境構築が必要な場合あり" - }, - "actions": { - "openCentralDir": "中央フォルダを開く", - "refresh": "更新" - }, - "toasts": { - "openFolderFailed": "フォルダを開けませんでした" - } - }, - "OfficeToolsSettings": { - "title": "Office ツール", - "description": "OfficeCLI スキルを管理し、Excel、Word、PowerPoint ファイルを作成します。OfficeCLI をインストールし、スキルを同期して、エージェントごとに有効化できます。", - "loadingContent": "コンテンツを読み込み中…", - "emptySkills": "スキルがありません。OfficeCLI をインストールしてスキルを同期してください。", - "emptySelection": "スキルを選択して内容を確認し、有効化を管理します。", - "emptySearch": "検索に一致するスキルがありません。", - "searchPlaceholder": "名前、ID、説明でスキルを検索", - "enableForAgents": "エージェントに対して有効化", - "noAgents": "ACP エージェントが検出されませんでした。", - "installFirst": "スキルを有効にするには、まず OfficeCLI をインストールしてください。", - "syncFirst": "コンテンツを読み込むには、まずスキルを同期してください。", - "noContent": "コンテンツがありません。", - "copyModeWarning": "コピー済み(リンクなし)。最新版を取得するには再同期してください。", - "previewTitle": "SKILL.md プレビュー", - "detection": { - "installed": "インストール済み", - "notInstalled": "未インストール", - "notRunnable": "インストール済みですが実行できません", - "installHint": "OfficeCLI をインストールして、AI エージェントにオフィスドキュメント生成スキルを有効にします。", - "install": "インストール", - "uninstall": "アンインストール", - "syncSkills": "スキルを同期" - }, - "categories": { - "general": "一般", - "presentations": "プレゼンテーション", - "documents": "ドキュメント", - "spreadsheets": "スプレッドシート" - }, - "states": { - "not_linked": "無効", - "linked_to_codeg": "有効", - "linked_elsewhere": "ブロック — 他のリンクが存在します", - "blocked_by_real_directory": "ブロック — カスタムスキルがこの名前を使用しています", - "broken": "リンク切れ" - }, - "badges": { - "notSynced": "未同期" - }, - "actions": { - "refresh": "更新" - }, - "toasts": { - "loadFailed": "スキル詳細の読み込みに失敗", - "enabled": "このエージェントでスキルを有効化しました", - "disabled": "このエージェントでスキルを無効化しました", - "enableFailed": "スキルの有効化に失敗", - "disableFailed": "スキルの無効化に失敗", - "installSuccess": "OfficeCLI のインストールに成功", - "installFailed": "OfficeCLI のインストールに失敗", - "uninstallSuccess": "OfficeCLI をアンインストールしました", - "uninstallFailed": "OfficeCLI のアンインストールに失敗", - "syncSuccess": "{synced} 個のスキルを同期しました", - "syncPartial": "{synced} 個同期、{errors} 個失敗", - "syncFailed": "スキルの同期に失敗" - }, - "autoPreviewLabel": "プレビューを自動で開く", - "autoPreviewHint": "エージェントが Word、Excel、PowerPoint ファイルを作成または編集したときに、ライブプレビューを自動で開きます。" - }, - "SkillPacksSettings": { - "title": "スキルパック", - "description": "codeg が一元管理し、各 AI エージェントにリンクする厳選スキルの束です——コーディング専門家、科学研究、オフィス文書ツール。下でエージェントごとに有効化できます。", - "tabs": { - "experts": "エキスパート", - "science": "科学研究", - "office": "Officeツール", - "custom": "カスタム" - }, - "actions": { - "openCentralDir": "中央フォルダを開く", - "refresh": "更新" - }, - "toasts": { - "openFolderFailed": "フォルダを開けませんでした" - } - }, - "QuickMessagesSettings": { - "title": "クイックメッセージ", - "description": "再利用可能なメッセージスニペットを管理します。ドラッグして並べ替えできます。", - "loading": "クイックメッセージを読み込み中…", - "emptyList": "クイックメッセージはまだありません。「新規」をクリックして作成してください。", - "emptySelection": "編集するクイックメッセージを選択してください。", - "searchPlaceholder": "タイトルまたは内容で検索", - "untitled": "無題", - "actions": { - "new": "新規", - "save": "保存", - "delete": "削除", - "dragSort": "ドラッグして並べ替え", - "dragSortMessage": "クイックメッセージを並べ替え: {name}" - }, - "fields": { - "title": "タイトル", - "titlePlaceholder": "このメッセージに短いタイトルを付けてください", - "content": "内容", - "contentPlaceholder": "ここにメッセージ内容を入力してください" - }, - "confirmDelete": { - "title": "クイックメッセージを削除しますか?", - "message": "「{name}」を完全に削除します。よろしいですか?", - "cancel": "キャンセル", - "confirm": "削除" - }, - "toasts": { - "loadFailed": "クイックメッセージの読み込みに失敗しました", - "createFailed": "クイックメッセージの作成に失敗しました", - "saveFailed": "クイックメッセージの保存に失敗しました", - "deleteFailed": "クイックメッセージの削除に失敗しました", - "saveOrderFailed": "順序の保存に失敗しました", - "created": "クイックメッセージを作成しました", - "saved": "クイックメッセージを保存しました", - "deleted": "クイックメッセージを削除しました" - } - }, - "Pet": { - "badge": { - "running": "実行中 {count} 件", - "waiting": "承認待ち {count} 件", - "error": "エラー {count} 件" - }, - "panel": { - "title": "アクティブなセッション", - "empty": "アクティブなセッションはありません", - "emptyHint": "実行中、または対応が必要なセッションがここに表示されます。", - "statusRunning": "実行中", - "statusWaiting": "待機中", - "statusError": "エラー", - "subAgentOf": "サブエージェント" - }, - "menu": { - "scale": "拡大率", - "openManager": "ペット管理", - "close": "閉じる" - }, - "loadError": "ペットの読み込みに失敗", - "missingPetIdParam": "ペットが選択されていません", - "summonButton": "ペット", - "manager": { - "title": "デスクトップペット", - "description": "Codex 互換のスプライトシートで動く、デスクトップ常駐のお供。", - "addPet": "ペットを追加", - "importFromCodex": "Codex から取り込む", - "noPets": "ペットがありません。追加するか、Codex から取り込んでください。", - "setActive": "アクティブにする", - "active": "アクティブ", - "edit": "編集", - "delete": "削除", - "deleteConfirm": "ペット「{name}」を削除しますか?ディスクからも削除されます。", - "summon": "ペットウィンドウを呼び出す", - "openCodexHelp": "Codex ペットは ~/.codex/pets/ 配下に配置する必要があります。見つかりません。", - "specRequirement": "スプライトシートは幅 1536 ピクセル、高さは 208 ピクセルの倍数(例: 1872 または 2288)で、透過 PNG / WebP 形式である必要があります。", - "form": { - "id": "ペット ID", - "idHelp": "英小文字、数字、'-'、'_' のみ。最大 64 文字。", - "displayName": "表示名", - "description": "説明 (任意)", - "spritesheet": "スプライトシート", - "chooseFile": "ファイルを選択", - "replaceFile": "スプライトを差し替え", - "saveCreate": "ペットを追加", - "saveUpdate": "変更を保存", - "cancel": "キャンセル" - }, - "errors": { - "missingId": "ペット ID は必須です", - "missingName": "表示名は必須です", - "missingSpritesheet": "スプライトシートは必須です", - "addFailed": "ペットの追加に失敗しました", - "updateFailed": "ペットの更新に失敗しました", - "deleteFailed": "ペットの削除に失敗しました", - "loadFailed": "ペット一覧の取得に失敗しました", - "setActiveFailed": "アクティブなペットの設定に失敗しました", - "summonFailed": "ペットウィンドウの召喚に失敗しました" - } - }, - "import": { - "title": "Codex から取り込む", - "subtitle": "~/.codex/pets/ 配下に見つかったペット一覧。", - "selectAll": "すべて選択", - "alreadyImported": "取り込み済み", - "renameOnConflict": "ID が重複した場合は -imported を付与", - "import": "選択したものを取り込む", - "noneFound": "取り込み可能な Codex ペットが見つかりません。", - "imported": "取り込みに成功", - "failed": "取り込みに失敗", - "close": "閉じる" - }, - "marketplace": { - "openMarketplace": "ペットマーケット", - "title": "ペットマーケット", - "search": "ペットを検索", - "kindFilter": { - "all": "すべて", - "object": "オブジェクト", - "animal": "動物", - "person": "人物", - "creature": "生き物" - }, - "sortFilter": { - "latest": "新着", - "popular": "人気", - "views": "閲覧数順" - }, - "refresh": "更新", - "install": "インストール", - "installing": "インストール中", - "reinstall": "再インストール", - "reinstallConfirm": "ローカルのペット \"{name}\" を上書きしますか?既存のデータは置き換えられます。", - "cancel": "キャンセル", - "stats": { - "views": "閲覧", - "downloads": "ダウンロード", - "likes": "いいね" - }, - "actions": { - "idle": "待機", - "running_right": "右走り", - "running_left": "左走り", - "waving": "手振り", - "jumping": "ジャンプ", - "failed": "失敗", - "waiting": "待ち", - "running": "実行", - "review": "レビュー" - }, - "page": "{page} / {total} ページ", - "prev": "前へ", - "next": "次へ", - "empty": "条件に一致するペットがありません。", - "successInstalled": "\"{name}\" をインストールしました", - "errors": { - "loadFailed": "マーケットの読み込みに失敗しました", - "installFailed": "インストールに失敗しました", - "alreadyInstalled": "そのペットは既に存在します" - } - } - }, - "RemoteWorkspace": { - "openRemoteWorkspace": "Open remote workspace", - "manage": "Manage remote workspace", - "manageTitle": "Remote Workspace connections", - "empty": "No remote connections", - "searchPlaceholder": "Search remote workspaces", - "orderFailed": "Failed to save remote workspace order", - "dragSort": "Drag to sort", - "dragSortConnection": "Drag to sort {name}", - "newConnection": "New connection", - "loading": "Loading", - "loadingConnection": "Loading remote connection", - "name": "Name", - "baseUrl": "Service URL", - "token": "Access token", - "save": "Save", - "delete": "Delete", - "confirmDelete": { - "title": "Delete remote connection?", - "message": "This will remove \"{name}\" from this device. This action cannot be undone.", - "cancel": "Cancel", - "confirm": "Delete" - }, - "saved": "Remote connection saved.", - "deleted": "Remote connection deleted.", - "loadFailed": "Failed to load remote connections", - "saveFailed": "Failed to save remote connection", - "deleteFailed": "Failed to delete remote connection", - "openFailed": "Failed to open remote workspace", - "connectionLoadFailed": "Failed to load remote connection: {message}", - "connectionExpired": "Remote connection \"{name}\" is expired. Update its token and reload this window." - }, - "ServerFileBrowser": { - "title": "サーバーファイルを選択", - "pathPlaceholder": "ディレクトリパスを入力...", - "goHome": "ホームディレクトリへ", - "navigateUp": "上の階層へ", - "select": "選択", - "cancel": "キャンセル", - "loading": "読み込み中...", - "emptyDirectory": "このディレクトリは空です", - "errorLoadingDir": "ディレクトリの読み込みに失敗しました", - "selectedCount": "{count} 件選択中" - }, - "BackupSettings": { - "title": "バックアップと復元", - "description": "codeg データのポータブルなバックアップを書き出すか、バックアップから復元します。", - "tabs": { - "backup": "バックアップ", - "restore": "復元" - }, - "export": { - "includeExternal": "会話内容を含める", - "includeExternalHint": "各 CLI の会話履歴(Claude、Codex、Gemini など)も保存します。サイズが増えます。", - "passphrase": "パスフレーズ(任意)", - "passphrasePlaceholder": "空欄の場合は暗号化されません", - "passphraseConfirm": "パスフレーズの確認", - "passphraseMismatch": "パスフレーズが一致しません。", - "noPassphraseWarning": "このバックアップには秘密情報(API キー、トークン)が平文で含まれます。安全に保管してください。", - "passphraseLossWarning": "このパスフレーズで暗号化します。紛失するとバックアップは復元できません。", - "button": "バックアップを書き出す", - "inProgress": "バックアップを作成中…", - "success": "バックアップを作成しました。", - "started": "バックアップのダウンロードを開始しました。" - }, - "restore": { - "selectFile": "バックアップファイルを選択", - "passphrasePrompt": "このバックアップは暗号化されています。パスフレーズを入力してください。", - "unlock": "ロック解除", - "preview": { - "title": "バックアップの詳細", - "encrypted": "暗号化済み", - "compatible": "互換あり", - "incompatible": "互換なし", - "createdAt": "作成日時: {value}", - "appVersion": "アプリのバージョン: {value}", - "incompatibleHint": "このバックアップは新しいバージョンの codeg で作成されており、復元できません。" - }, - "replaceWarning": "復元すると現在の codeg データ(データベースとアップロード)がすべて置き換えられます。現在のデータは先にスナップショットされ、復旧できます。", - "keyringNote": "デスクトップの GitHub/チャットのトークンは OS のキーチェーンに保存され、含まれません。復元後に再入力してください。", - "button": "復元", - "staging": "復元を準備中…", - "staged": "復元を準備しました。再起動します…", - "restarting": "復元を準備しました。サーバーを再起動します…", - "restartTimeout": "サーバーが時間内に復帰しませんでした。起動後にページを再読み込みしてください。", - "externalSideLocation": "会話履歴を {path} に復元しました", - "confirmTitle": "すべてのデータを置き換えますか?", - "confirmBody": "現在の codeg データベースとアップロードをバックアップで置き換えてから再起動します。現在のデータは先にスナップショットされます。", - "cancel": "キャンセル", - "confirmAction": "置き換えて再起動", - "external": { - "title": "会話内容", - "hint": "このバックアップには CLI の会話履歴が含まれます。復元先を選択してください。", - "modeSkip": "復元しない", - "modeSide": "安全な別フォルダーに復元", - "modeOriginal": "CLI の元の場所に復元", - "forceOverwrite": "既存のファイルを上書き", - "forceOverwriteHint": "CLI フォルダー内の既存ファイルを置き換えます。", - "scanning": "競合を確認中…", - "noConflicts": "既存のファイルは上書きされません。", - "conflictCount": "既存のファイル {count} 件が影響を受けます。", - "conflictSkipNote": "上書きを有効にしない限り、既存ファイルは保持(スキップ)されます。" - }, - "restartFailed": "復元は準備できましたが、サーバーを再起動できませんでした。手動で再起動して復元を適用してください。" - }, - "remoteUnsupported": "バックアップと復元は codeg を実行しているマシンのデータを対象とします。現在リモートワークスペースに接続中です。そのサーバー上で直接バックアップを管理してください。" - }, - "backup": { - "restore": { - "error": { - "badPassphrase": "パスフレーズが正しくないか、バックアップが破損しています。", - "corrupted": "バックアップアーカイブが破損しています。", - "unknownFormat": "このファイルは認識可能な codeg バックアップではありません。", - "newerVersion": "このバックアップは codeg {backupVersion} で作成されており、現在のバージョン({appVersion})より新しいです。", - "alreadyPending": "適用待ちの復元が既にあります。先に再起動して適用してから、新しい復元を準備してください。" - } - }, - "error": { - "diskSpace": "操作を完了するためのディスク容量が足りません。", - "cancelled": "操作はキャンセルされました。" - } - }, - "WebConnection": { - "disconnectedTitle": "接続が切断されました", - "reconnectingDescription": "サーバーへの再接続を試みています。通常は数秒で自動的に復旧します。", - "reconnectNow": "今すぐ再接続", - "sessionExpiredTitle": "セッションの有効期限が切れました", - "sessionExpiredDescription": "セッションが無効になりました。続行するには再度サインインしてください。", - "goToLogin": "ログインへ移動" - }, - "LiveFeedback": { - "placeholder": "{agent} の作業中にメモを送る…", - "agentFallback": "エージェント", - "ariaLabel": "ライブフィードバックのメモ", - "dialogTitle": "ライブフィードバック", - "dialogDescription": "エージェントの作業中にメモを送ります。現在のステップを中断せず、次の確認時に読み取られます。", - "dialogDescriptionInstant": "作業中のエージェントにメモを送ります。メモは現在のターンに即座に挿入され、エージェントはすぐに確認できます。", - "channelDowngraded": "このセッションでは即時挿入を利用できません。メモは保存され、エージェントが次回チェックする際に読み取られます。", - "send": "送信", - "cancel": "キャンセル", - "pending": "待機中", - "delivered": "受領済み", - "turnEndedUnread": "エージェントはフィードバックを読む前にターンを終了しました。", - "sendAsMessage": "新しいメッセージとして送信", - "dismiss": "閉じる", - "turnEndedResent": "ターンが終了したため、新しいメッセージとして送信しました。", - "turnEnded": "ターンはすでに終了しています。", - "submitFailed": "メモを送信できませんでした" - }, - "AgentToolsSettings": { - "title": "会話内ツール", - "description": "codeg が会話の中でエージェントに追加で渡すツールです。エージェントの起動時に注入されるため、変更は以降に起動したエージェントに適用されます。", - "feedbackLabel": "ライブフィードバック", - "feedbackHint": "作業中のエージェントにメモや修正を送れます。即時ステアリングに対応したエージェントでは、メモは実行中のターンへ即座に挿入されます。それ以外のエージェントはフィードバック確認ツールで読み取りますが、通常はプロンプトで言及した場合にのみ確認します。例:「ライブフィードバックを定期的に確認して」とメッセージに追加してください。", - "questionLabel": "ユーザーに質問", - "questionHint": "エージェントが処理を一時停止し、会話の入力欄の上に表示される選択式の質問をできるようにします。回答(またはスキップ)するまでエージェントは待機します。", - "sessionInfoLabel": "セッション情報の取得", - "sessionInfoHint": "メッセージ内で参照したセッション(セッションバッジ)をエージェントが照会し、タイトル・エージェント・ステータス・ワークスペース・トークン使用量・最近のメッセージを読み取れるようにします。", - "automationsLabel": "自動化を作成", - "automationsHint": "会話をスケジュール実行の自動化として保存します。既定はオフ — 自動化はその後、自分でエージェントを起動します。", - "workTasksLabel": "ToDo タスクを作成", - "workTasksHint": "会話から ToDo ボードにカードを追加します。既定はオフ — アプリの状態を書き換えます。", - "save": "保存", - "saving": "保存中…", - "saved": "ツール設定を保存しました", - "saveFailed": "ツール設定の保存に失敗しました", - "loadFailed": "読み込みに失敗しました: {detail}" - }, - "NotificationSoundSettings": { - "title": "通知音", - "description": "エージェントのイベント発生時に短い通知音を鳴らします。対象はチャットチャンネルに送られるものと同じイベントで、この設定はこの端末にのみ適用されます。", - "enableHint": "既定ではオフです。通知音はこのブラウザまたはアプリのワークスペースウィンドウでのみ再生されます。", - "volume": "音量", - "preview": "試聴", - "previewEvent": "「{event}」の通知音を試聴", - "onlyWhenUnfocused": "ウィンドウが非アクティブなときのみ再生", - "onlyWhenUnfocusedHint": "Codeg を表示している間は鳴らしません。", - "eventsTitle": "イベント", - "eventsHint": "イベントごとに音を選びます。「なし」を選ぶと鳴りません。同じイベントが数秒以内に繰り返された場合は 1 回だけ再生されます。", - "toneNone": "なし", - "toneChime": "チャイム", - "toneDing": "ベル", - "toneBlip": "ブリップ", - "tonePop": "ポップ", - "toneAlert": "アラート", - "toneDescend": "下降音" - }, - "LogsSettings": { - "loading": "読み込み中…", - "sectionTitle": "実行ログ", - "sectionDescription": "アプリケーションの診断ログを表示・設定します。ログはローカルファイルに書き込まれ、ライブ表示のためメモリにも保持されます。", - "captureTitle": "ログレベル", - "captureDescription": "記録する詳細度を制御します。レベルが高い(Debug、Trace)ほど多く記録されますが、ログも大きくなります。「オフ」でログ記録を無効にします。", - "captureLabel": "取得レベル", - "levels": { - "off": "オフ", - "error": "エラー", - "warn": "警告", - "info": "情報", - "debug": "デバッグ", - "trace": "トレース" - }, - "viewerTitle": "最近のログ", - "viewerDescription": "最近のログレコードをライブ表示します。レベルで絞り込みやテキスト検索ができます。", - "searchPlaceholder": "メッセージまたはターゲットを検索…", - "viewLevels": { - "all": "すべてのレベル", - "error": "エラー以上", - "warn": "警告以上", - "info": "情報以上", - "debug": "デバッグ以上", - "trace": "トレース以上" - }, - "pause": "一時停止", - "resume": "ライブ", - "refresh": "更新", - "clear": "クリア", - "openFolder": "フォルダーを開く", - "shownCount": "{shown} / {total} 件表示", - "empty": "表示するログがありません。", - "levelSaveFailed": "ログレベルの保存に失敗しました", - "openFolderFailed": "ログフォルダーを開けませんでした", - "downloadFailed": "ログファイルのダウンロードに失敗しました", - "filesTitle": "ログファイル", - "filesDescription": "ライブバッファを超える履歴のために、ディスクから完全なログファイルをダウンロードします。", - "filesEmpty": "ログファイルはまだありません。", - "download": "ダウンロード", - "downloadTruncated": "ファイルが大きいため、最新の {size} をダウンロードしました。完全なファイルはログディレクトリにあります。", - "captureEnvLocked": "ログレベルは RUST_LOG / CODEG_LOG 環境変数で制御されています。変更はそちらで行ってください。", - "targetsTitle": "モジュール別オーバーライド", - "targetsDescription": "グローバルレベルを変えずに、特定モジュール(例: codeg_lib::acp)のレベルを個別に設定します。", - "targetsAdd": "追加", - "targetsRemove": "オーバーライドを削除", - "toggleDetails": "詳細を切り替え" - }, - "Automations": { - "title": "オートメーション", - "new": "新規オートメーション", - "empty": "オートメーションはまだありません", - "emptyHint": "作成すると、エージェントのタスクをスケジュールまたは手動で実行できます。", - "name": "名前", - "namePlaceholder": "例:夜間の PR レビュー", - "prompt": "プロンプト", - "promptPlaceholder": "エージェントに何をさせますか?", - "agent": "エージェント", - "folder": "ワークスペースフォルダ", - "folderPlaceholder": "フォルダを選択", - "isolation": "分離", - "isolationWorktree": "実行ごとに新しい worktree", - "isolationShared": "フォルダ内で実行", - "isolationSharedCaveat": "実行はこのフォルダーの作業ツリーを直接使用するため、コミットしていない変更と競合する可能性があります。実行ごとに分離するにはワークツリーのオプションを有効にしてください。", - "trigger": "トリガー", - "triggerSchedule": "スケジュール", - "triggerManual": "手動のみ", - "cron": "スケジュール(cron)", - "cronPlaceholder": "0 9 * * 1-5", - "timezone": "タイムゾーン", - "nextRun": "次回実行", - "branch": "ブランチ", - "branchOptional": "ブランチ(任意)", - "enabled": "有効", - "save": "保存", - "cancel": "キャンセル", - "edit": "編集", - "delete": "削除", - "runNow": "今すぐ実行", - "cancelRun": "実行をキャンセル", - "runHistory": "実行履歴", - "noRuns": "実行履歴はまだありません", - "allFolders": "すべてのフォルダ", - "filterAll": "すべて", - "noMatches": "一致する自動化はありません", - "viewConversation": "会話を表示", - "lastRun": "前回の実行", - "never": "なし", - "running": "実行中", - "deleteTitle": "このオートメーションを削除しますか?", - "deleteDescription": "オートメーションとそのスケジュールを削除します。実行履歴は保持されます。", - "statusRunning": "実行中", - "statusSucceeded": "成功", - "statusFailed": "失敗", - "statusCancelled": "キャンセル", - "statusSkipped": "スキップ", - "errorName": "名前は必須です", - "errorPrompt": "プロンプトは必須です", - "errorCron": "スケジュール実行には cron 式が必要です", - "errorFolder": "ワークスペースフォルダを選択してください", - "presetHourly": "毎時", - "presetDaily": "毎日 9 時", - "presetWeekdays": "平日 9 時", - "presetCustom": "カスタム", - "probing": "オプションを読み込み中…", - "retry": "再試行", - "configNone": "このエージェントに設定可能な項目はありません", - "inherit": "エージェント既定", - "mode": "モード", - "config": "設定", - "branchPlaceholder": "(既定のブランチ)", - "selectHint": "詳細を表示する自動化を選択してください", - "refresh": "更新", - "onboardTitle": "定型のエージェント作業を自動化", - "onboardHint": "コードのレビュー、依存関係の更新、課題のトリアージを、定期実行またはオンデマンドでエージェントに実行させます。", - "headerSubtitle": "スケジュール実行とオンデマンドのエージェント作業", - "startFromTemplate": "テンプレートから始める", - "blankTitle": "空の自動化", - "blankDesc": "エージェント作業を一から設定します。", - "backToTemplates": "テンプレート", - "sectionSchedule": "スケジュールと対象", - "sectionTarget": "ターゲット", - "sectionAction": "アクション", - "actionLaunchSession": "セッションを起動", - "actionEnqueueTask": "タスクをキューに追加", - "actionEnqueueTaskHint": "実行のたびに、このオートメーション名を冠した ToDo タスクが対象フォルダの ToDo タスクに追加され、タスクエンジンがボードの設定に従って実行します。", - "sectionPrompt": "プロンプト", - "nextIn": "{rel}後に実行", - "manual": "手動", - "schedEveryMinutes": "{n}分ごと", - "schedHourly": "1時間ごと", - "schedDaily": "毎日 {time}", - "schedWeekdays": "平日 {time}", - "schedWeekly": "毎週{day} {time}", - "schedMonthly": "毎月 {day} 日 {time}", - "dow0": "日曜日", - "dow1": "月曜日", - "dow2": "火曜日", - "dow3": "水曜日", - "dow4": "木曜日", - "dow5": "金曜日", - "dow6": "土曜日", - "tplCodeReviewTitle": "コードレビュー", - "tplCodeReviewDesc": "最近の変更をレビューし、バグ・リグレッション・品質の問題を洗い出します。", - "tplDependencyUpdatesTitle": "依存関係の更新", - "tplDependencyUpdatesDesc": "古くなった依存関係を見つけ、安全なアップグレードを提案します。", - "tplTestCoverageTitle": "テストカバレッジ", - "tplTestCoverageDesc": "テストされていないコードパスを見つけ、不足しているテストを追加します。", - "tplTodoSweepTitle": "TODO 整理", - "tplTodoSweepDesc": "TODO と FIXME のコメントを集め、優先度ごとに整理します。", - "tplCiTriageTitle": "CI トリアージ", - "tplCiTriageDesc": "最近失敗したチェックを調査し、修正を提案します。", - "tplReleaseNotesTitle": "リリースノート", - "tplReleaseNotesDesc": "前回のリリース以降の変更をまとめ、変更履歴を作成します。", - "tplSecurityAuditTitle": "セキュリティ監査", - "tplSecurityAuditDesc": "脆弱性やリスクのあるパターンをスキャンし、結果を報告します。", - "enable": "有効化", - "disable": "無効化", - "moreActions": "その他の操作", - "statusDisabled": "無効", - "cronBuilderTitle": "スケジュールビルダー", - "cronFreqLabel": "頻度", - "cronFreqMinutes": "N 分ごと", - "cronFreqHourly": "毎時", - "cronFreqDaily": "毎日", - "cronFreqWeekdays": "平日", - "cronFreqWeekly": "毎週", - "cronFreqMonthly": "毎月", - "cronFreqCustom": "カスタム", - "cronEveryLabel": "間隔(分)", - "cronTimeLabel": "時刻", - "cronHourLabel": "時", - "cronMinuteLabel": "分", - "cronDowLabel": "曜日", - "cronDomLabel": "日", - "cronApply": "適用", - "cronPreviewLabel": "プレビュー", - "cronOpenBuilder": "スケジュールビルダーを開く", - "branchDefault": "デフォルトブランチ", - "branchUseCustom": "「{query}」を使用", - "branchLocal": "ローカル", - "branchRemote": "リモート", - "branchSearchPlaceholder": "ブランチを検索…", - "branchNone": "ブランチがありません" - }, - "Tasks": { - "title": "ToDo タスク", - "new": "新規タスク", - "empty": "タスクはまだありません", - "emptyHint": "ToDo を追加して実行すると、エージェントが独立した worktree で作業し、結果をレビューしてマージできます。", - "emptyColTodo": "ToDoはまだありません", - "emptyColInProgress": "進行中のタスクはありません", - "emptyColAttention": "対応が必要なタスクはありません", - "emptyColDone": "完了したタスクはまだありません", - "allFolders": "すべてのフォルダ", - "showCanceled": "キャンセル済みを表示", - "showArchived": "アーカイブを表示", - "filter": "フィルター", - "viewSwitchToBoard": "ボード表示に切り替え", - "viewSwitchToList": "リスト表示に切り替え", - "statusFilter": "ステータス", - "statusFilterAll": "すべてのステータス", - "listEmpty": "現在の絞り込み条件に一致するタスクはありません", - "listColStatus": "ステータス", - "listColTask": "タスク", - "listColLocation": "場所", - "listColChanges": "変更", - "listColUpdated": "更新", - "colTodo": "ToDo", - "colInProgress": "進行中", - "colAttention": "要対応", - "colDone": "完了", - "statusTodo": "ToDo", - "statusQueued": "待機中", - "statusPreparing": "準備中", - "statusRunning": "実行中", - "statusAwaitingInput": "入力待ち", - "statusReview": "レビュー待ち", - "statusMerging": "マージ中", - "statusDone": "完了", - "statusFailed": "失敗", - "statusCanceled": "キャンセル済み", - "statusInterrupted": "中断", - "badgeCleanupFailed": "クリーンアップ失敗", - "badgeWorktreeKept": "worktree 保持", - "badgeWorktreeRemoved": "worktree 削除済み", - "filesChanged": "{count} ファイル", - "actionStart": "開始", - "actionSchedule": "予約実行", - "actionCancel": "キャンセル", - "actionRetry": "再試行", - "actionRequeue": "再キュー", - "actionViewSession": "会話を表示", - "actionEdit": "編集", - "actionDelete": "削除", - "actionRetryCleanup": "クリーンアップを再試行", - "actionMerge": "マージ", - "actionUnqueueMerge": "マージ待ちを取り消す", - "actionEditQueuedMerge": "待機中のマージを編集", - "badgeMergeQueued": "マージ待ち", - "badgeMergeQueuedRank": "マージ待ち · {rank} 番目", - "badgeMergeQueuedHint": "このプロジェクトの実行中のマージが終わるのを待っています。順番が来ると自動的に開始します。", - "actionComplete": "完了", - "actionAbandon": "破棄", - "cancelTitle": "タスクをキャンセルしますか?", - "cancelDescription": "タスクは「キャンセル済み」になります。worktree は保持され、あとで再キューできます。", - "cancelReasonLabel": "キャンセルの理由(任意)", - "cancelReasonPlaceholder": "例:方針が違うので説明を書き直す", - "cancelKeep": "やめておく", - "cancelSubmit": "タスクをキャンセル", - "restartTitleRetry": "タスクを再試行", - "restartTitleRequeue": "タスクを再キュー", - "restartDescription": "補足(任意)を書けます。次の実行のプロンプトに含めて agent に渡されます。", - "scheduleTitle": "タスクの実行を予約", - "scheduleDescription": "タスクは ToDo のまま、指定した時刻に自動で開始します。フォルダーの同時実行数の上限は引き続き適用されます。", - "scheduleDateLabel": "日付", - "schedulePickDate": "日付を選択", - "scheduleTimeLabel": "時刻", - "schedulePreview": "{time} に実行", - "schedulePastHint": "指定した時刻は過ぎています。保存するとすぐに開始します。", - "scheduleInAnHour": "1 時間後", - "scheduleInThreeHours": "3 時間後", - "scheduleTomorrow": "明日 9:00", - "scheduleClear": "予約を解除", - "scheduleBadge": "{time} に開始予定", - "toastScheduled": "{time} に予約しました", - "toastScheduleCleared": "予約を解除しました", - "actionFollowUp": "追加指示", - "actionAddNote": "補足を追加", - "followUpSubmit": "送信", - "followUpIntentRevise": "修正を依頼", - "followUpIntentContinue": "作業を続ける", - "followUpIntentQuestion": "質問する", - "followUpIntentVerify": "セルフチェック", - "followUpPlaceholderRevise": "どこを直してほしいですか?同じセッションで続けます。", - "followUpPlaceholderContinue": "次に何をしますか?これまでの作業はそのまま残ります。", - "followUpPlaceholderQuestion": "何を知りたいですか?ファイルには一切手を加えず回答します。", - "followUpPlaceholderVerify": "任意:重点的に確認してほしい点はありますか?", - "followUpPlaceholderRetry": "任意:今回はどう変えますか?例:先に pnpm install を実行", - "followUpPlaceholderRequeue": "任意:なぜ中止したのか、今回は何を変えるかを書いてください。", - "actionArchive": "アーカイブ", - "actionUnarchive": "アーカイブ解除", - "archiveAllDone": "すべてアーカイブ", - "dropToStart": "離すと実行を開始", - "errorView": "表示", - "notifyReview": "レビュー待ち: {title}", - "notifyFailed": "タスクが失敗しました: {title}", - "createFromMessage": "このメッセージからタスクを作成", - "detailTokens": "合計トークン", - "editorTitleNew": "新規タスク", - "editorTitleEdit": "タスクを編集", - "templates": "テンプレート", - "templatesEmpty": "テンプレートはまだありません。", - "templateSaveCurrent": "現在の内容をテンプレートとして保存", - "templateDelete": "テンプレートを削除", - "transcriptTitle": "タスクの会話", - "transcriptDescription": "タスクのエージェントセッションの読み取り専用ライブビュー。", - "phaseWork": "タスク実行", - "phaseRetry": "再実行", - "phaseReturn": "追加指示", - "phaseMerge": "マージ", - "titleLabel": "タイトル", - "titlePlaceholder": "何をしますか?", - "promptLabel": "タスクの説明", - "promptPlaceholder": "エージェントへの指示を記述 — @ でファイル参照、/ でコマンド", - "folderPlaceholder": "フォルダを選択", - "agentInheritedHint": "タスク設定から継承 — 変更するとこのタスク専用になります", - "agentOverrideReset": "継承に戻す", - "sectionTarget": "ターゲット", - "errorTitle": "タイトルを入力してください", - "errorPrompt": "タスクの説明を入力してください", - "errorFolder": "フォルダを選択してください", - "save": "保存", - "cancel": "キャンセル", - "mergeTitle": "タスクをマージ", - "mergeQueuedTitle": "待機中のマージ", - "mergeQueueHint": "このプロジェクトでは別のタスクをマージ中です。このタスクは待機列に入り、前のマージが終わり次第自動的に開始します。", - "mergeQueueUpdateHint": "このタスクはすでにマージ待ちです。送信すると内容だけが更新され、待機列の順番はそのままです。", - "mergeDescription": "{branch} を {base} にマージします。worktree の未コミット変更は先にコミットされます。", - "mergeMessage": "コミットメッセージ", - "mergeMessagePlaceholder": "例: feat: add login validation", - "mergeAutoMessage": "コミットメッセージをエージェントに生成させる", - "strategySquash": "1つのコミットにまとめる", - "strategySquashHint": "タスクのすべての変更が1件の履歴としてメインブランチに取り込まれ、履歴がすっきりします。", - "strategyMerge": "履歴をすべて残す", - "strategyMergeHint": "タスク中の各コミットをそのまま残し、マージの記録を1件追加します。各ステップを追跡できます。", - "mergeDeleteWorktree": "マージ後に worktree を削除", - "mergeSubmit": "マージ", - "mergeSubmitQueue": "マージ待ちに追加", - "mergeQueuedToast": "マージ待ちに追加しました。実行中のマージが終わり次第開始します。", - "completeTitle": "タスクを完了", - "completeDescription": "このタスクはファイルを変更していないため、マージするものはありません。そのまま完了にします。", - "completeDescriptionNoWorktree": "このタスクの worktree は削除されているため、マージできません。そのまま完了にします。未マージのコミットが残る作業ブランチは保持されます。", - "completeDeleteWorktree": "完了後に worktree を削除", - "completeSubmit": "完了", - "settingsTitle": "タスク設定", - "settingsDescription": "{folder} のタスクの既定値。", - "settingsScope": "適用範囲", - "settingsScopeGlobal": "すべてのフォルダ(グローバル既定)", - "settingsScopeGlobalHint": "個別設定のないフォルダはこのグローバル既定を使います。", - "settingsSource": "設定ソース", - "settingsSourceGlobal": "グローバル既定", - "settingsSourceCustom": "個別設定", - "settingsSourceGlobalFollow": "グローバルのタスク設定に従います。グローバル側の変更が自動的に反映されます。", - "settingsSourceCustomHint": "このフォルダ専用の設定を保存し、グローバル既定には従わなくなります。", - "settingsAgent": "既定のエージェント", - "settingsMaxConcurrent": "最大同時実行数", - "settingsMaxConcurrentHint": "0 = 無制限", - "settingsAutoProcess": "自動処理", - "settingsAutoProcessHint": "ToDo タスクを自動的に開始します(同時実行数の上限まで)。", - "settingsMergeStrategy": "既定のマージ戦略", - "settingsMergeStrategyHint": "マージ時にタスクの変更をブランチ履歴へどう記録するか。", - "settingsAutoMerge": "自動マージ", - "settingsAutoMergeHint": "レビュー待ちに達しマージできる変更があるタスクは、「マージ」を押したときと同じように自動で取り込まれます。コミットメッセージはエージェントが生成し、worktree の扱いは下の既定に従います。プリフライトが赤のタスクやマージに失敗したタスクはそのまま残ります。", - "settingsDeleteWorktree": "マージ後に worktree を削除", - "settingsDeleteWorktreeHint": "マージ画面で既定でオンになります。その場で変更もできます。", - "settingsWorktreeRoot": "Worktree の作成先", - "settingsWorktreeRootHint": "新しいタスクの worktree をこのディレクトリ配下にタスクごとに作成します。空欄ならプロジェクトフォルダーと同じ階層に作成されます。「~」はホームディレクトリ、相対パスはプロジェクトフォルダー基準です。", - "settingsWorktreeRootPlaceholder": "~/codeg-worktrees", - "settingsWorktreeRootBrowse": "worktree のディレクトリを選択", - "settingsPreflight": "プリフライトコマンド", - "settingsPreflightHint": "タスクがレビューに達したときワークツリーで実行。", - "settingsPreflightCustomPlaceholder": "pnpm test", - "settingsInitCommand": "Worktree 初期化コマンド", - "settingsInitCommandHint": "worktree の新規作成後、エージェント開始前に実行されます。", - "settingsInitCommandPlaceholder": "pnpm install", - "settingsTabGeneral": "一般", - "settingsTabMerge": "マージ", - "settingsTabWorktree": "Worktree", - "settingsTabPrompts": "プロンプト", - "settingsPromptsIntro": "各ステージには既定のプロンプトが組み込まれています(タスク本体、ワークツリーのルール、マージ時は具体的な git 手順)。ここに書いた内容は補足指示として末尾に追加され、既定の内容を補うだけで置き換えることはありません。", - "settingsPromptStageAll": "全段階", - "settingsPromptPlaceholderAll": "例: AGENTS.md のプロジェクト規約に従う。最後のまとめは 2 文以内で", - "settingsPromptPlaceholderWork": "例: 関連するテストを先に読む。小さな単位でこまめにコミットする", - "settingsPromptPlaceholderRetry": "例: 続ける前に既にコミット済みの内容を確認し、完了済みの作業をやり直さない", - "settingsPromptPlaceholderReturn": "例:指摘された点を一つずつ対応する。無関係なリファクタリングはしない", - "settingsPromptPlaceholderMerge": "例: 取り込みコミットのメッセージは日本語で。手動で解決した衝突は明記する", - "settingsPromptHintAll": "マージ実行を含め、エージェントに渡すすべてのプロンプトに追加されます。", - "settingsPromptHintWork": "タスクを初めて実行するときに追加されます。", - "settingsPromptHintRetry": "中断または失敗したタスクを再開するときに追加されます。", - "settingsPromptHintReturn": "レビュー待ちのタスクに追加指示を出すとき(修正・追加作業・セルフチェック)に付加されます。", - "settingsPromptHintMerge": "エージェントがタスクをベースブランチに取り込むときに追加されます。", - "preflightPassed": "{name} 成功", - "preflightFailed": "{name} 失敗", - "preflightRunning": "{name} 実行中…", - "detailDescription": "タスク詳細", - "detailSummary": "結果", - "detailFiles": "変更ファイル", - "detailDiffAll": "差分をすべて表示", - "detailDiffAllTitle": "全差分", - "detailNoChanges": "ベースからの変更はまだありません", - "detailTimeline": "進行履歴", - "detailTimelineEmpty": "まだアクティビティがありません", - "showMore": "もっと見る", - "showLess": "折りたたむ", - "detailInfo": "詳細", - "detailBranch": "ブランチ", - "detailMergeCommit": "マージコミット", - "detailChanges": "変更", - "detailScheduled": "開始予定", - "detailCreated": "作成日時", - "detailStarted": "開始日時", - "detailFinished": "完了日時", - "diffLoading": "差分を読み込み中…", - "deleteConfirmTitle": "タスクを削除しますか?", - "deleteConfirmBody": "「{title}」をボードから削除します。実行中の場合は先にキャンセルされます。", - "deleteWithWorktree": "worktree も削除する", - "eventCreated": "作成", - "eventStatusChanged": "ステータス変更", - "eventConfigEffective": "起動構成", - "eventInitCommand": "初期化コマンド", - "eventAgentProgress": "エージェントの進捗", - "eventAgentVerdict": "エージェントの判定", - "eventMergeAttempt": "マージ開始", - "eventMergeQueued": "マージ待ちに追加", - "eventMergeConflict": "マージ競合", - "eventPreflight": "プリフライト", - "eventCleanupFailed": "worktree のクリーンアップに失敗", - "eventResumeFallback": "セッション再開に失敗し新規セッションへ", - "eventUserAction": "ユーザー操作", - "eventDiffStat": "変更スナップショット" - }, - "CustomSkillsSettings": { - "loading": "カスタムスキルを読み込み中…", - "category": "カスタム", - "searchPlaceholder": "名前・ID・説明でカスタムスキルを検索", - "states": { - "not_linked": "未有効", - "linked_to_codeg": "有効", - "linked_elsewhere": "別の場所にリンク", - "blocked_by_real_directory": "実在フォルダにより占有", - "broken": "リンク切れ" - }, - "actions": { - "new": "新規", - "import": "インポート", - "importFromAgent": "エージェントから取り込む", - "cancel": "キャンセル", - "save": "保存" - }, - "rowMenu": { - "edit": "編集", - "duplicate": "複製", - "delete": "削除" - }, - "bulk": { - "delete": "選択項目を削除" - }, - "editor": { - "createTitle": "カスタムスキルを新規作成", - "editTitle": "カスタムスキルを編集", - "description": "カスタムスキルは共有ストア(~/.codeg/skills)に保存され、任意のエージェントで有効化できます。", - "idLabel": "スキル ID", - "idPlaceholder": "例: my-workflow", - "contentLabel": "SKILL.md", - "contentPlaceholder": "ここにスキルの SKILL.md を記述…", - "preview": "プレビュー", - "edit": "編集", - "emptyBody": "まだ内容がありません。" - }, - "duplicate": { - "title": "スキルを複製", - "description": "「{id}」を元に、新しい ID でコピーを作成します。", - "newIdPlaceholder": "新しいスキル ID", - "confirm": "複製" - }, - "import": { - "title": "インポートするスキルフォルダを選択" - }, - "importFromAgent": { - "title": "エージェントからスキルを取り込む", - "description": "エージェント独自のスキルを共有ストアにコピーすると、どのエージェントでも有効化できます。", - "agentLabel": "エージェント", - "agentPlaceholder": "エージェントを選択", - "selectAll": "すべて選択({count})", - "loading": "エージェントのスキルを読み込み中…", - "unsupported": "このエージェントはスキルディレクトリを提供していません。", - "empty": "このエージェントに取り込めるスキルはありません。", - "alreadyInLibrary": "ライブラリ済み", - "confirm": "選択を取り込む({count})" - }, - "delete": { - "title": "カスタムスキルを削除しますか?", - "body": "{count} 個のカスタムスキルを中央ストアから削除し、すべてのエージェントからリンクを解除します。この操作は取り消せません。", - "confirm": "削除" - }, - "toasts": { - "loadFailed": "スキルの読み込みに失敗しました", - "idRequired": "スキル ID を入力してください", - "created": "カスタムスキルを作成しました", - "updated": "カスタムスキルを更新しました", - "saveFailed": "スキルの保存に失敗しました", - "imported": "スキルをインポートしました", - "importFailed": "スキルのインポートに失敗しました", - "duplicated": "スキルを複製しました", - "duplicateFailed": "スキルの複製に失敗しました", - "deleted": "{count} 個のスキルを削除しました", - "deletedPartial": "{ok} 個を削除、{failed} 個が失敗", - "deleteFailed": "スキルの削除に失敗しました", - "importedFromAgent": "{count} 件のスキルを取り込みました", - "importedFromAgentPartial": "{ok} 件を取り込み、{failed} 件が失敗しました", - "importFromAgentAllSkipped": "取り込み対象なし — {count} 件はすでにライブラリにあります", - "importFromAgentFailed": "エージェントからの取り込みに失敗しました" - } - }, - "CodexModelEditor": { - "customizedNotice": "モデル一覧をカスタマイズしたため、codeg が codex のモデル表全体を管理します。codex が今後追加する公式モデルは自動では表示されません。下の更新をクリックして保存し直すと同期できます。カスタマイズをすべて削除すると codex の自動更新に戻ります。", - "officialsTitle": "公式モデル", - "officialsHint": "起動する codex の公式モデルを自動的に含めます。不要なものは削除できます。", - "officialsEmpty": "利用可能な公式モデルがありません。", - "refresh": "codex から更新", - "readdOfficial": "公式を再追加", - "customsTitle": "カスタムモデル", - "customsEmpty": "カスタムモデルはまだありません。", - "addCustom": "カスタム追加", - "slugPlaceholder": "モデル ID(slug)", - "displayNamePlaceholder": "表示名", - "contextWindow": "コンテキスト", - "makeDefault": "デフォルトに設定", - "defaultHint": "デフォルトモデル", - "remove": "削除", - "advanced": "詳細", - "baseTemplate": "ベーステンプレート", - "baseTemplateHint": "必須フィールド(システムプロンプト、ツール、制限)を複製する公式モデル。", - "groupBehavior": "動作と機能", - "fieldReasoningLevel": "既定の推論レベル", - "fieldReasoningSummary": "推論サマリー", - "fieldVerbosity": "詳細度", - "fieldShellType": "シェルタイプ", - "fieldApplyPatch": "パッチ適用ツール", - "fieldReasoningSummaries": "推論サマリー対応", - "fieldSupportVerbosity": "詳細度の制御", - "fieldParallelToolCalls": "並列ツール呼び出し", - "fieldSearchTool": "Web 検索ツール", - "optNone": "なし", - "groupInstructions": "説明とシステムプロンプト", - "fieldDescription": "説明", - "baseInstructions": "システムプロンプト(base_instructions)" - }, - "DiagnosticsSettings": { - "title": "環境診断", - "description": "このアプリが自身のプロセス内でエージェントの CLI をどう解決するかを確認します(ターミナルとは異なる場合があります)。", - "loading": "診断を実行中…", - "error": "診断に失敗しました", - "rerun": "再実行", - "copyAll": "すべてコピー", - "copied": "診断情報をクリップボードにコピーしました", - "button": "診断", - "verdict": { - "ok": "環境は正常です。それでも未インストールと表示される場合は、アプリを完全に再起動してプレフィックスキャッシュを更新してください。", - "node_missing": "アプリの PATH に Node.js が見つかりませんでした。", - "npm_missing": "アプリの PATH に npm が見つかりませんでした。", - "not_installed": "このエージェントはインストールされていないようです。", - "installed_but_unresolved": "インストール済みと記録されていますが、アプリが実行ファイルを見つけられません。", - "user_prefix_not_on_path": "フォールバックのプレフィックス(~/.codeg/npm-global)にインストールされていますが、アプリの PATH に含まれていません。アプリを完全に再起動して再試行してください。", - "homebrew_bin_not_on_path": "Homebrew の bin にインストールされていますが、アプリの PATH に含まれていません(Apple Silicon の keg 分割)。", - "terminal_only_path": "このコマンドはターミナルでは解決されますが、アプリでは解決されません。GUI の PATH のずれです。ターミナルからアプリを起動するか、エージェント設定から再インストールしてください。", - "npm_prefix_timeout": "npm prefix -g が遅すぎました(1.5 秒超)。フォールバック検出をスキップしました。アプリを再起動して再試行してください。", - "node_too_old": "使用中の Node.js がこのエージェントの要件より古いです。Node.js をアップグレードしてください。", - "adapter_missing_native_present": "お使いの {agent} CLI は確かにインストールされていますが、Codeg が起動するのは別の ACP アダプターパッケージで、そちらが未インストールです。エージェント設定からインストールしてください。既存の CLI には触れず、ログインも共有されます。", - "adapter_missing": "Codeg は {agent} 用に別個の ACP アダプターパッケージを起動しますが、まだインストールされていません。エージェント設定からインストールしてください。ベンダー CLI を入れるだけでは足りません。" - } - }, - "TokenUsage": { - "title": "トークン使用量", - "rangeLabel": "期間", - "range7d": "7日間", - "range30d": "30日間", - "range90d": "90日間", - "rangeThisMonth": "今月", - "rangeThisYear": "今年", - "rangeAll": "全期間", - "rangeCustom": "カスタム", - "moreRanges": "その他", - "customRangePick": "期間を選択", - "bucketLabel": "集計単位", - "bucketDay": "日", - "bucketWeek": "週", - "bucketMonth": "月", - "bucketUnitDay": "日", - "bucketUnitWeek": "週", - "bucketUnitMonth": "月", - "folderFilter": "フォルダ", - "allFolders": "すべてのフォルダ", - "agentFilter": "エージェント", - "allAgents": "すべてのエージェント", - "modelFilter": "モデル", - "allModels": "すべてのモデル", - "searchPlaceholder": "検索…", - "noMatches": "該当なし", - "clearFilter": "選択をクリア", - "resetFilters": "フィルタをリセット", - "refresh": "更新", - "rebuild": "すべて再構築", - "rebuildHint": "集計済みデータを破棄し、すべてのセッション記録を読み直します。codeg 以外の CLI で追記された場合に使います。", - "syncing": "セッションを集計中…", - "syncProgress": "{done} / {total}", - "syncDone": "{synced} 件のセッションを集計しました", - "syncFailed": "一部のセッションを読み取れませんでした", - "syncBusy": "すでに更新が実行中です", - "lastSynced": "{time} に更新", - "lastSyncedNever": "未集計", - "tileTotal": "合計トークン", - "tileSessions": "セッション数", - "tileTurns": "ターン数", - "tileActiveDays": "稼働日数", - "tileGenTime": "生成時間", - "vsPrevious": "前期間との比較", - "deltaNew": "新規", - "trendTitle": "使用量の推移", - "trendEmpty": "この期間の使用量はありません", - "trendTurns": "ターン", - "trendSessions": "セッション", - "compositionTitle": "トークンの内訳", - "compositionHint": "入力は送った内容、出力はモデルが書いた内容、キャッシュ読み取りは再送せずに済んだコンテキストです。", - "compositionNote": "これらのキャッシュ命中を定価で再送すると、あと {value} かかっていました。", - "inputTokens": "入力", - "outputTokens": "出力", - "cacheWrite": "キャッシュ書き込み", - "cacheRead": "キャッシュ読み取り", - "freshTokens": "新規計算トークン", - "cacheHitCaption": "キャッシュ命中", - "cacheHeroTitleHigh": "コンテキストの大半は再送不要でした", - "cacheHeroTitleLow": "コンテキストの大半はまだ全額計算です", - "cacheHeroDesc": "{cached} のコンテキストはキャッシュが担い、この期間に実際に新規計算されたのは {fresh} だけです。", - "cacheSavedSuffix": "再送を {saved} 相当分節約できました。", - "avgPerSession": "セッション平均", - "avgTurnsPerSession": "1 セッションあたり平均 {count} ターン", - "avgPerActiveDay": "稼働日平均", - "peakBucket": "最も多い{bucket}", - "peakHour": "ピーク時間帯", - "daysValue": "{count} 日", - "idleDays": "空き日数", - "byFolderTitle": "フォルダー別", - "byAgentTitle": "エージェント別", - "byModelTitle": "モデル別", - "distributionTitle": "使用量の分布", - "distributionHint": "選択した軸でセッションとトークンを集計。行をクリックすると絞り込めます。", - "otherLabel": "その他", - "unknownModel": "モデル未記録", - "emptyBreakdown": "記録がありません", - "sessionsCount": "{count} セッション", - "heatmapTitle": "作業リズム", - "heatmapHint": "ローカル時間の曜日・時刻ごとのトークン量。", - "heatmapPeakHint": "最も集中しているのは {hour}:00 前後です。", - "less": "少", - "more": "多", - "heatmapCell": "{weekday} {hour}:00 — {value} トークン", - "weekMon": "月", - "weekTue": "火", - "weekWed": "水", - "weekThu": "木", - "weekFri": "金", - "weekSat": "土", - "weekSun": "日", - "topSessionsTitle": "消費の多いセッション", - "untitledSession": "名称未設定のセッション", - "topSessionsEmpty": "この期間にセッションはありません", - "streakLongest": "最長の連続日数", - "streakLongestDays": "最長連続 {count} 日", - "share": "共有", - "moreActions": "その他の操作", - "shareDialogTitle": "使用量カードを共有", - "shareDialogHint": "いま選んでいる期間とフィルタのスナップショットです。", - "shareSave": "画像を保存", - "shareCopy": "画像をコピー", - "shareCopied": "クリップボードにコピーしました", - "shareSaved": "画像を保存しました", - "shareFailed": "画像を生成できませんでした", - "shareRendering": "生成中…", - "cardHeading": "私の AI コーディング記録", - "cardRangeAll": "全期間", - "cardTotalLabel": "使用トークン", - "cardFooter": "codeg で作成", - "cardTopModels": "よく使うモデル", - "cardTopProjects": "主なプロジェクト", - "archetypeNightOwl": "夜型コーダー", - "archetypeNightOwlDesc": "トークンの {percent}% は日没後に使われています。", - "archetypeEarlyBird": "早起きタイプ", - "archetypeEarlyBirdDesc": "トークンの {percent}% は朝 9 時前に使われています。", - "archetypeWeekendWarrior": "週末戦士", - "archetypeWeekendWarriorDesc": "トークンの {percent}% は週末に使われています。", - "archetypeCacheMaster": "キャッシュの達人", - "archetypeCacheMasterDesc": "コンテキストの {percent}% がキャッシュ由来です。", - "archetypeMarathoner": "マラソンランナー", - "archetypeMarathonerDesc": "{days} 日連続で開発を続けました。", - "archetypePolyglot": "マルチプレイヤー", - "archetypePolyglotDesc": "{count} 個のエージェントを本格的に併用しています。", - "archetypeLaserFocus": "一点集中", - "archetypeLaserFocusDesc": "トークンの {percent}% を一つのプロジェクトに投じています。", - "archetypeDeepDiver": "深掘り型", - "archetypeDeepDiverDesc": "1 セッションあたり平均 {averageK}K トークン。", - "archetypeSteady": "安定型ビルダー", - "archetypeSteadyDesc": "のべ {days} 日開発しました。", - "emptyTitle": "集計データがまだありません", - "emptyHint": "codeg は各エージェント自身のセッション記録から直接トークン数を読み取ります。更新すると、このマシンにある記録を集計します。", - "emptyAction": "セッションを集計", - "loadFailed": "使用量を読み込めませんでした", - "truncatedNotice": "期間が非常に長いため、表示中の数値は直近の一部のみを対象としています。" - } -} +{ + "Language": { + "followSystem": "システムに従う", + "english": "英語", + "simplifiedChinese": "简体中文", + "traditionalChinese": "繁體中文", + "japanese": "日本語", + "korean": "韓国語", + "spanish": "スペイン語", + "german": "ドイツ語", + "french": "フランス語", + "portuguese": "ポルトガル語", + "arabic": "アラビア語" + }, + "GitCredentialDialog": { + "title": "認証が必要です", + "description": "リモートサーバーが認証情報を要求しています。ユーザー名とパスワード(またはアクセストークン)を入力してください。", + "username": "ユーザー名", + "usernamePlaceholder": "ユーザー名またはメールアドレス", + "password": "パスワード / トークン", + "passwordPlaceholder": "パスワードまたはアクセストークン", + "passwordHint": "サーバーのユーザー名とパスワードを入力してください。", + "cancel": "キャンセル", + "authenticate": "認証", + "authenticating": "認証中...", + "invalidCredentials": "認証情報が無効です。再試行してください。", + "saveCredentials": "今後の操作のために認証情報を保存する", + "githubTitle": "GitHub 認証", + "githubDescription": "個人アクセストークンを入力して GitHub に接続します。トークン検証後、自動的にアカウントに保存されます。", + "githubToken": "個人アクセストークン", + "githubTokenPlaceholder": "ghp_xxxxxxxxxxxx", + "githubTokenHint": "GitHub → Settings → Developer settings → Personal access tokens でトークンを生成してください。", + "githubAuthenticate": "検証して接続", + "generateToken": "トークンを生成" + }, + "SettingsShell": { + "title": "設定", + "preferences": "環境設定", + "nav": { + "general": "一般", + "appearance": "外観", + "agents": "エージェント", + "mcp": "MCP", + "skills": "Skills", + "shortcuts": "ショートカット", + "version_control": "バージョン管理", + "system": "システム", + "chat_channels": "チャットチャンネル", + "web_service": "Webサービス", + "model_providers": "モデルプロバイダー", + "experts": "エキスパート", + "science": "科学研究", + "office_tools": "Officeツール", + "skill_packs": "スキルパック", + "quick_messages": "クイックメッセージ", + "logs": "実行ログ" + } + }, + "AppearanceSettings": { + "sectionTitle": "テーマ外観", + "sectionDescription": "ライト、ダーク、またはシステム追従を選択できます。設定は自動保存されます。", + "themeMode": "テーマモード", + "placeholder": "テーマモードを選択", + "system": "システムに従う", + "light": "ライト", + "dark": "ダーク", + "currentTheme": "現在の有効テーマ: {theme}", + "resolvedTheme": { + "light": "ライト", + "dark": "ダーク", + "unknown": "--" + }, + "themeColor": { + "sectionTitle": "テーマカラー", + "sectionDescription": "ボタンやアクセント、ハイライトに使用する色を選択します。", + "current": "現在のカラー:{color}", + "options": { + "neutral": "Neutral", + "zinc": "Zinc", + "slate": "Slate", + "stone": "Stone", + "gray": "Gray", + "red": "Red", + "rose": "Rose", + "orange": "Orange", + "green": "Green", + "blue": "Blue", + "yellow": "Yellow", + "violet": "Violet" + } + }, + "customStyle": { + "sectionTitle": "カスタムスタイル", + "sectionDescription": "現在のテーマの配色を微調整したり、独自の CSS を適用したりできます。上書きはベースプリセットの上に重なるため、プリセットを切り替えても保持されます。", + "summarySuspended": "一時停止中", + "summaryDefault": "プリセットのまま", + "summaryTokens": "{count, plural, one {上書き # 件} other {上書き # 件}}", + "summaryCss": "カスタム CSS", + "suspendedByShortcut": "カスタムスタイルは一時停止中です。再開するまで、ここでの設定は反映されません。", + "suspendedBySafeParam": "このウィンドウはセーフ外観モードで開かれているため、カスタムスタイルは適用されません。他のウィンドウには影響しません。", + "resume": "カスタムスタイルを再開", + "enableTheme": "カスタム配色を有効にする", + "editingLight": "ライトモードの値を編集しています。ダークモードに切り替えると個別に設定できます。", + "editingDark": "ダークモードの値を編集しています。ライトモードに切り替えると個別に設定できます。", + "resetToken": "プリセット値に戻す", + "radius": "角丸", + "radiusHint": "sm から 4xl までの角丸スケール全体がこの値から導出されるため、スライダー 1 つでアプリ全体の角丸が変わります。", + "advanced": "詳細(他 {count} 個の変数)", + "enableCss": "カスタム CSS を有効にする", + "cssRisk": "上級者向け機能です。カスタム CSS は組み込みスタイルをすべて上書きするため、画面が使用不能になることがあります。", + "editCss": "CSS を編集…", + "cssPresent": "{size} KB 保存済み", + "cssEmpty": "まだ保存されていません", + "escapeHint": "画面が壊れてしまったら、{shortcut} でカスタムスタイルをすべて停止できます。safeStyle=1 のクエリパラメータ付きでウィンドウを開く方法もあります。", + "copyTheme": "テーマ JSON をコピー", + "importTheme": "テーマをインポート…", + "clearTheme": "上書きをクリア", + "interopHint": "テーマは shadcn の registry:theme 形式です。任意の shadcn テーマをそのまま貼り付けられ、書き出したテーマはどの shadcn プロジェクトでも使えます。", + "importTitle": "テーマをインポート", + "importDescription": "shadcn の registry:theme アイテム、light/dark のみのオブジェクト、またはフラットなトークンマップを貼り付けてください。", + "readClipboard": "クリップボードから読み取る", + "importConfirm": "インポート", + "cancel": "キャンセル", + "apply": "適用", + "toasts": { + "copied": "テーマ JSON をコピーしました", + "copyFailed": "クリップボードにコピーできませんでした", + "clipboardReadFailed": "クリップボードを読み取れませんでした。手動で貼り付けてください", + "importFailed": "この JSON には利用できるテーマ変数がありません", + "imported": "テーマをインポートしました" + }, + "css": { + "dialogTitle": "カスタム CSS", + "dialogDescription": "すべての codeg ウィンドウに適用されます。変更はリアルタイムでプレビューされ、「適用」で保存されます。", + "size": "{used} KB / {max} KB", + "ruleCount": "{count} 個のルール", + "errorTooLarge": "サイズが大きすぎて保存できません。上限以下に減らしてください。", + "errorImportEscaped": "除去後も @import が検出されました(エスケープ記法)。手動で削除してください。", + "warnNoRules": "ルールが 1 つも解析されませんでした。構文を確認してください。", + "noticeImportsRemoved": "@import を {count} 件削除しました。リモートのスタイルシートを取得してしまうためです。", + "noticeRemoteUrl": "リモートの url() が含まれています。適用するとネットワークリクエストが発生します。", + "noticePreviewSuspended": "カスタムスタイルが停止中のため、このプレビューは適用されません。", + "noticeDisabled": "カスタム CSS は無効です。ここでプレビューはできますが、有効にするまで反映されません。", + "hintTokens": "ヒント: 上書きした色は var(--primary) や var(--background) などで参照できます。" + } + }, + "zoomLevel": { + "sectionTitle": "ウィンドウズーム", + "sectionDescription": "インターフェイス全体を拡大・縮小します。すぐに反映され、デバイスごとに保存されます。", + "placeholder": "ズームレベルを選択", + "default": "デフォルト", + "current": "現在のズーム:{zoom}%" + }, + "fonts": { + "sectionTitle": "フォント", + "sectionDescription": "インターフェース、コードエディター、ターミナルのフォントをそれぞれ選択します。内蔵フォントは必要に応じて読み込まれます。「カスタム…」を選ぶと、システムにインストールされた任意のフォントを使用できます。", + "interface": "インターフェース", + "editor": "エディター", + "terminal": "ターミナル", + "groupSans": "サンセリフ", + "groupMono": "等幅", + "custom": "カスタム…", + "customPlaceholder": "フォント名(例:Fira Code)", + "fontSize": "フォントサイズ", + "ligatures": "合字を有効にする", + "ligaturesUnavailable": "このフォントには合字がありません", + "wordWrap": "折り返しを有効にする", + "terminalLigaturesHint": "ターミナルの合字は内蔵のコーディングフォントにのみ適用されます。", + "preview": "プレビュー" + }, + "welcomePanel": { + "sectionTitle": "モード選択エリア", + "sectionDescription": "新しい会話ページで入力欄の上に表示される「コード開発 / 日常業務」のショートカットカードです。", + "showQuickActions": "新しい会話ページに表示する" + }, + "workspaceBackground": { + "sectionTitle": "ワークスペースの背景", + "sectionDescription": "ワークスペース全体の背後に画像を表示します。サイドバーやパネルは半透明のすりガラスになり画像が透けて見えます。マスクで文字の可読性を保ちます。", + "enable": "背景画像を有効にする", + "image": "画像", + "chooseImage": "画像を選択", + "replaceImage": "画像を変更", + "removeImage": "削除", + "fillMode": "表示方法", + "fillModes": { + "cover": "全体を覆う", + "contain": "全体を表示", + "center": "中央", + "tile": "タイル" + }, + "maskOpacity": "マスクの不透明度", + "maskOpacityHint": "値を大きくすると画像がテーマの背景色に近づき、文字のコントラストが上がります。", + "imageBlur": "画像のぼかし", + "panelOpacity": "パネルの不透明度", + "panelOpacityHint": "サイドバー・パネル・タブバーの不透明度です。低いほど画像が透けて見えます。", + "errorTooLarge": "画像が大きすぎます(最大 16 MB)。", + "errorUploadFailed": "背景画像の設定に失敗しました。" + } + }, + "SystemSettings": { + "loading": "読み込み中...", + "sectionTitle": "システム管理", + "sectionDescription": "ネットワークプロキシ、アプリ更新、言語設定を管理します。", + "proxyTitle": "ネットワークプロキシ", + "proxyDescription": "有効にすると、以降のネットワークリクエストはこのプロキシを優先して使用します(ACP チャット、エージェントのインストール、Git リモート操作を含む)。", + "loadFailed": "読み込みに失敗しました: {message}", + "enableProxy": "システムプロキシを有効化", + "proxyAddress": "プロキシアドレス", + "proxyHint": "http(s)/socks5 をサポート。例: {example}。システムプロキシ有効時のみ有効です。", + "save": "保存", + "saving": "保存中...", + "proxyRequired": "プロキシ有効時はプロキシ URL が必要です", + "saveSuccess": "システムプロキシ設定を保存しました", + "saveFailed": "保存に失敗しました: {message}", + "languageTitle": "言語", + "languageDescription": "アプリの言語を設定します。システムに従う場合、未対応言語は英語にフォールバックします。", + "appLanguage": "アプリ言語", + "languageSaveSuccess": "言語設定を保存しました", + "languageSaveFailed": "言語設定の保存に失敗しました: {message}", + "updateTitle": "アプリ更新", + "versionTitle": "ソフトウェアアップデート", + "updateDescription": "設定されたリリースソースで新しいバージョンを確認し、利用可能なら直接インストールします。", + "currentVersion": "現在のバージョン", + "upgradableVersion": "最新バージョン", + "none": "なし", + "lastChecked": "最終確認: {time}", + "updateError": "更新エラー: {message}", + "checking": "確認中...", + "checkUpdate": "更新を確認", + "updating": "インストール中...", + "downloading": "ダウンロード中...", + "upgradeTo": "v{version} にアップグレード", + "viewRelease": "v{version} のリリースを表示", + "foundUpdate": "新しいバージョン v{version} が見つかりました", + "alreadyLatest": "すでに最新バージョンです", + "checkUpdateFailed": "更新確認に失敗しました: {message}", + "installSuccess": "更新をインストールしました。アプリを再起動します。", + "installFailed": "更新に失敗しました: {message}", + "upgradeSuccess": "アップグレードが完了しました。再読み込みしています...", + "restartTimeout": "サーバーが時間内に復帰しませんでした。コンテナまたはサービスのログを確認してください。", + "restartingIn": "{seconds} 秒後に再起動します...", + "waitingForServer": "サーバーの復帰を待っています...", + "restartToUpdate": "再起動して更新", + "newVersionBadge": "新バージョン v{version}", + "updateAvailableTitle": "アップデートがあります", + "releaseNotesTitle": "更新内容", + "remindLater": "後で", + "retry": "再試行", + "stepDownload": "ダウンロード", + "stepInstall": "インストール", + "stepRestart": "再起動", + "updateReadyHint": "アップデートをダウンロードしました。再起動して適用してください。", + "restarting": "再起動しています…", + "dockerUpgradeHint": "いま実行中のコンテナを更新します。コンテナを再作成すると失われます。維持するには、新しいバージョンのイメージを取得またはビルドしてコンテナを再作成してください。", + "upgradeRolledBack": "アップグレードに失敗しました。サーバーは前のバージョンにロールバックしました。", + "serverUnreachable": "アップグレードを開始するためにサーバーに接続できませんでした。サーバーが稼働中であることを確認して再試行してください。", + "rollbackButton": "ロールバック", + "rollingBack": "ロールバック中...", + "rollbackDescription": "前回のアップグレード前にインストールされていたバージョンに戻します。", + "rollbackConfirmTitle": "以前のバージョンにロールバックしますか?", + "rollbackConfirmDescription": "サーバーは前回のアップグレード前のバージョンで再起動します。新しいリリースは引き続き再インストールできます。", + "rollbackConfirm": "ロールバック", + "rollbackCancel": "キャンセル", + "rollbackSuccess": "以前のバージョンにロールバックしました。再読み込みしています...", + "rollbackFailed": "ロールバックに失敗しました。サーバーのログを確認してください。", + "updateErrors": { + "sourceUnavailable": "更新ソースに接続できません。ネットワークまたはプロキシを確認して再試行してください。", + "network": "ネットワーク接続に失敗しました。ネットワークまたはプロキシを確認して再試行してください。", + "downloadFailed": "更新パッケージのダウンロードに失敗しました。しばらくしてから再試行してください。", + "installFailed": "更新のインストールに失敗しました。アプリを閉じて再試行してください。", + "unknown": "更新に失敗しました。しばらくしてから再試行してください。" + } + }, + "VersionControlSettings": { + "loading": "読み込み中...", + "sectionTitle": "バージョン管理", + "sectionDescription": "Git 実行ファイルの設定と GitHub アカウントの管理。", + "gitTitle": "Git 設定", + "gitDescription": "アプリケーションで使用する Git 実行ファイルを設定します。", + "gitDetected": "Git が検出されました", + "gitNotFound": "システムに Git が見つかりません", + "gitVersion": "バージョン", + "gitPath": "パス", + "customGitPath": "カスタム Git パス", + "customGitPathPlaceholder": "/usr/bin/git", + "customGitPathHint": "空欄の場合、自動検出されたパスを使用します。", + "test": "テスト", + "testing": "テスト中...", + "testSuccess": "Git 実行ファイルは有効です。", + "testFailed": "Git テスト失敗:{message}", + "save": "保存", + "saving": "保存中...", + "saveSuccess": "Git 設定を保存しました。", + "saveFailed": "保存に失敗しました:{message}", + "githubTitle": "GitHub アカウント", + "githubDescription": "認証用の GitHub アカウントを管理します。トークンはローカルに保存されます。", + "noAccounts": "GitHub アカウントが設定されていません。", + "addAccount": "アカウントを追加", + "serverUrl": "サーバー URL", + "serverUrlPlaceholder": "https://github.com", + "token": "個人アクセストークン", + "tokenPlaceholder": "ghp_xxxxxxxxxxxx", + "generateToken": "トークンを生成", + "tokenHint": "GitHub → Settings → Developer settings → Personal access tokens でトークンを生成してください。", + "validateAndAdd": "検証して追加", + "validating": "検証中...", + "addSuccess": "アカウント {username} を追加しました。", + "addFailed": "アカウントの追加に失敗しました:{message}", + "testConnection": "テスト", + "connectionSuccess": "接続成功。", + "connectionFailed": "接続失敗:{message}", + "setDefault": "デフォルトに設定", + "defaultLabel": "デフォルト", + "defaultSet": "デフォルトアカウントを更新しました。", + "removeAccount": "削除", + "removeConfirmTitle": "アカウントを削除", + "removeConfirmMessage": "アカウント「{username}」を削除してもよろしいですか?", + "removeConfirm": "削除", + "removeCancel": "キャンセル", + "removeSuccess": "アカウントを削除しました。", + "scopes": "スコープ", + "loadFailed": "設定の読み込みに失敗しました:{message}", + "gitAccount": { + "sectionTitle": "Git サーバーアカウント", + "sectionDescription": "GitHub 以外の Git サーバーの認証情報を管理します(GitLab、Bitbucket、セルフホストなど)。", + "noAccounts": "Git サーバーアカウントが設定されていません。", + "addAccount": "アカウントを追加", + "addTitle": "Git アカウントを追加", + "addDescription": "サーバーアドレス、ユーザー名、パスワードまたはアクセストークンを入力してください。", + "serverUrl": "サーバー URL", + "serverUrlPlaceholder": "https://gitlab.example.com", + "username": "ユーザー名", + "usernamePlaceholder": "ユーザー名またはメールアドレス", + "password": "パスワード / トークン", + "passwordPlaceholder": "パスワードまたはアクセストークン", + "passwordHint": "サーバーのパスワードまたはアクセストークンを入力してください。", + "add": "追加", + "serverRequired": "サーバー URL を入力してください。", + "usernameRequired": "ユーザー名を入力してください。", + "passwordRequired": "パスワードを入力してください。" + } + }, + "ShortcutSettings": { + "sectionTitle": "ショートカット", + "resetDefault": "デフォルトに戻す", + "recordInstruction": "右側のボタンをクリックしてからキーの組み合わせを押してください。Ctrl/Cmd、Alt、Shift が使用できます。Esc で記録をキャンセルします。", + "recording": "ショートカットを入力...", + "toasts": { + "conflict": "ショートカットはすでに「{title}」で使用されています", + "updated": "ショートカットを更新しました", + "invalid": "無効なショートカットです。もう一度お試しください", + "reset": "デフォルトのショートカットを復元しました" + }, + "actions": { + "toggle_search": { + "title": "検索を開く", + "description": "会話検索パネルを表示または非表示にします" + }, + "toggle_sidebar": { + "title": "左サイドバーを切り替え", + "description": "会話一覧サイドバーを表示または非表示にします" + }, + "toggle_terminal": { + "title": "ターミナルを切り替え", + "description": "下部ターミナルパネルを表示または非表示にします" + }, + "new_terminal_tab": { + "title": "新しいターミナル", + "description": "ターミナルにフォーカスがあるとき新しいタブを作成します" + }, + "close_current_terminal_tab": { + "title": "現在のターミナルを閉じる", + "description": "ターミナルにフォーカスがあるとき現在のタブを閉じます" + }, + "toggle_aux_panel": { + "title": "右パネルを切り替え", + "description": "補助情報パネルを表示または非表示にします" + }, + "new_conversation": { + "title": "新しい会話", + "description": "現在のフォルダで新しい会話タブを作成します" + }, + "open_folder": { + "title": "フォルダを開く", + "description": "フォルダ選択を開き、新しいウィンドウで開きます" + }, + "open_settings": { + "title": "設定を開く", + "description": "設定ウィンドウを開きます" + }, + "close_current_tab": { + "title": "現在のタブを閉じる", + "description": "現在の会話またはファイルタブを閉じます" + }, + "close_all_file_tabs": { + "title": "すべてのファイルタブを閉じる", + "description": "ファイルペインがアクティブなときに開いているすべてのファイルタブを閉じます" + }, + "next_tab": { + "title": "次のタブ", + "description": "次の会話またはファイルタブに切り替える" + }, + "prev_tab": { + "title": "前のタブ", + "description": "前の会話またはファイルタブに切り替える" + }, + "send_message": { + "title": "メッセージを送信", + "description": "入力欄のメッセージを送信する" + }, + "newline_in_message": { + "title": "メッセージ内で改行", + "description": "入力欄で改行を挿入する" + }, + "toggle_custom_style": { + "title": "カスタムスタイルの停止/再開", + "description": "緊急脱出用: カスタム配色と CSS をすべてオフにし、再度押すと元に戻します" + } + } + }, + "SkillsSettings": { + "title": "Skills", + "description": "左側でSkillを選択します。右側は既定でMarkdownプレビューです。編集に切り替えると変更して保存できます。", + "loadingAgents": "Skill対応エージェントを読み込み中...", + "emptyNoManageableAgents": "Skillを管理できるエージェントがありません。", + "managedTarget": "管理対象", + "selectAgentPlaceholder": "エージェントを選択", + "searchPlaceholder": "名前 / ID / パスで検索...", + "skillsList": "Skill一覧", + "loadingSkills": "Skillを読み込み中...", + "agentNotSupported": "現在のエージェントはSkill管理に対応していません。", + "emptySkills": "まだSkillがありません。「新規Skill」をクリックして作成してください。", + "newSkillTitle": "新規Skill", + "skillInfo": "Skill情報", + "skillIdPlaceholder": "skill-id(英数字/-/_/.)", + "skillsDirectoryWithPath": "Skillディレクトリ: {path}", + "skillsDirectoryNeedId": "Skillディレクトリ: Skill ID を入力すると完全なパスを生成します", + "markdownContent": "Markdown内容", + "editingStatus": "編集中", + "previewStatus": "プレビュー中", + "contentPlaceholder": "SkillのMarkdown内容を入力...", + "metadataTitle": "Skillメタデータ", + "onlyYamlMetadata": "このSkillにはYAMLメタデータのみが含まれています。", + "emptyContentHint": "まだ内容がありません。「編集」をクリックして開始してください。", + "loadingSkill": "Skillを読み込み中...", + "emptyNoAgents": "利用可能なエージェントがありません。", + "noSelectionHint": "左側から Skill を選択するか、「新規 Skill」をクリックして作成してください。", + "systemBadge": "システム", + "systemHint": "CLI 組み込み Skill・読み取り専用", + "scope": { + "global": "グローバル", + "folder": "フォルダ", + "selectFolderPlaceholder": "フォルダを選択", + "noFolders": "フォルダが見つかりません", + "pickFolderHint": "Skills を表示するフォルダを選択してください。" + }, + "actions": { + "preview": "プレビュー", + "edit": "編集", + "openInWindow": "新しいウィンドウで開く", + "delete": "削除", + "deleting": "削除中...", + "refresh": "更新", + "newSkill": "新規Skill", + "reset": "リセット", + "save": "保存", + "saving": "保存中...", + "cancel": "キャンセル" + }, + "deleteDialog": { + "title": "Skillを削除", + "confirm": "現在のSkillを削除しますか?この操作は元に戻せません。", + "confirmWithNamePrefix": "Skill", + "confirmWithNameSuffix": "を削除しますか?この操作は元に戻せません。" + }, + "toasts": { + "loadFailed": "Skillの読み込みに失敗しました", + "openFolderFailed": "フォルダを開けませんでした", + "noSkillDirectory": "現在のエージェントで利用可能なSkillディレクトリが見つかりません", + "nameRequired": "Skill名は空にできません", + "updated": "Skillを更新しました", + "created": "Skillを作成しました", + "saveFailed": "Skillの保存に失敗しました", + "deleted": "Skillを削除しました", + "deleteFailed": "Skillの削除に失敗しました" + }, + "templates": { + "gemini": "---\nname: example-skill\ndescription: Describe when this skill should be used.\n---\n\n# Skill Name\n\nInstructions for the agent when this skill is active.\n\n## Workflow\n\n1. Add actionable step one.\n2. Add actionable step two.\n", + "openCode": "---\nname: example-skill\ndescription: Describe when this skill should be used.\n---\n\n# Purpose\n\nDescribe what this skill helps with.\n\n# Steps\n\n1. Add actionable step one.\n2. Add actionable step two.\n", + "openClaw": "---\nname: example-skill\ndescription: Describe when this skill should be used.\nuser-invocable: true\ndisable-model-invocation: false\n---\n\n# Purpose\n\nDescribe what this skill helps with.\n\n# Instructions\n\n1. Add actionable instruction one.\n2. Add actionable instruction two.\n", + "default": "---\nname: example-skill\ndescription: Describe when this skill should be used.\n---\n\n# Skill: example-skill\n\n## When to use\n\n- Describe trigger conditions.\n\n## Instructions\n\n1. Add actionable instruction one.\n2. Add actionable instruction two.\n" + } + }, + "McpSettings": { + "loading": "読み込み中...", + "summary": { + "missingCommand": "(コマンド未設定)", + "missingUrl": "(URL未設定)" + }, + "protocol": { + "stdio": "Stdio" + }, + "errors": { + "selectInstallProtocol": "インストールプロトコルを選択してください", + "fieldRequired": "{field} は必須です", + "fieldNeedsBoolean": "{field} は true または false である必要があります", + "fieldNeedsNumber": "{field} は数値である必要があります", + "fieldNeedsInteger": "{field} は整数である必要があります", + "fieldInvalidJson": "{field} のJSONが不正です: {message}", + "fieldOutOfRange": "{field} の値が許可範囲外です", + "jsonEmpty": "{name} は空にできません", + "jsonInvalid": "{name} は有効なJSONではありません: {message}", + "jsonMustBeObject": "{name} はJSONオブジェクトである必要があります", + "specMustBeObject": "MCP 設定は JSON オブジェクトである必要があります。", + "missingType": "MCP 設定に type フィールドがありません。stdio、http(エイリアス:streamable-http、streamableHttp)、sse のいずれかを指定してください。", + "unsupportedType": "サポートされていない MCP タイプ {type}。対応:stdio、http(エイリアス:streamable-http、streamableHttp)、sse。", + "codexEntryUnsupportedType": "Codex MCP エントリ {id} のタイプ {type} はサポートされていません。対応:stdio、http(エイリアス:streamable-http、streamableHttp)、sse。", + "unsupportedTransportType": "サポートされていない transport タイプ {type}。対応:http(エイリアス:streamable-http、streamableHttp)、sse。", + "stdioCommandRequired": "stdio タイプの MCP には空でない command フィールドが必要です。", + "remoteUrlRequired": "リモート MCP には空でない url フィールドが必要です。", + "appsRequired": "対象アプリを少なくとも 1 つ選択してください。" + }, + "jsonNames": { + "localConfig": "MCP設定", + "installConfig": "インストール設定" + }, + "toasts": { + "uninstalled": "MCPをアンインストールしました", + "uninstallFailed": "アンインストールに失敗しました: {message}", + "selectAtLeastOneApp": "対象アプリを少なくとも1つ選択してください", + "saveSuccess": "保存しました", + "saveFailed": "保存に失敗しました: {message}", + "installed": "{name} をインストールしました", + "installFailed": "インストールに失敗しました: {message}", + "serverIdRequired": "Server ID は必須です", + "serverIdExists": "Server ID \"{id}\" は既に存在します。既存の項目を編集するか、別の名前を選択してください。", + "created": "MCP を作成しました" + }, + "installDialog": { + "title": "MCPインストールの確認", + "descriptionWithName": "{name} をローカル設定にインストールします。", + "description": "インストール対象アプリを選択してください。", + "protocol": "プロトコル", + "selectProtocol": "プロトコルを選択", + "parameters": "設定パラメータ", + "booleanPlaceholder": "true/false を選択してください", + "selectOneValue": "値を選択", + "targetApps": "対象アプリ" + }, + "actions": { + "cancel": "キャンセル", + "confirmInstall": "インストールを確定", + "installing": "インストール中", + "uninstall": "アンインストール", + "uninstalling": "アンインストール中", + "viewDetails": "詳細を見る", + "save": "保存", + "saving": "保存中", + "install": "インストール", + "refresh": "更新", + "newMcp": "新規 MCP", + "create": "作成", + "creating": "作成中..." + }, + "tabs": { + "local": "ローカル MCP", + "market": "MCP マーケットプレイス" + }, + "local": { + "filterPlaceholder": "ローカルMCPを絞り込み...", + "loadFailed": "読み込み失敗: {message}", + "empty": "ローカルMCPが見つかりません。", + "description": "ローカルMCP設定は直接編集して保存できます。", + "enabledApps": "有効なアプリ", + "configJson": "MCP設定 (JSON)", + "draftTitle": "新規 MCP", + "draftDescription": "Server ID と設定を入力してローカル MCP サーバーを作成します。", + "serverIdLabel": "Server ID", + "serverIdPlaceholder": "Server ID(例:my-mcp)", + "typeHint": "対応タイプ:stdio、http(エイリアス streamable-http、streamableHttp)、sse。env は stdio 専用です。リモート MCP の認証トークンは headers で渡してください。", + "envOnRemoteWarning": "リモート MCP の設定に env が含まれています。env は stdio のみで使用され、リモート MCP の認証トークンは headers に格納します。env は保存時に無視されます。" + }, + "market": { + "selectMarketplace": "マーケットプレイスを選択", + "searchPlaceholder": "MCPを検索...", + "searchFailed": "検索に失敗しました: {message}", + "loadingList": "MCP一覧を読み込み中...", + "empty": "MCPの検索結果がありません。", + "loadingDetail": "マーケットプレイス詳細を読み込み中...", + "detailLoadFailed": "詳細の読み込みに失敗しました: {message}", + "owner": "オーナー: {owner}", + "namespace": "名前空間: {namespace}", + "defaultInstallProtocol": "デフォルトのインストールプロトコル", + "currentOptionParameterCount": "現在のオプションのパラメータ数: {count}", + "installConfigDescription": "インストール設定 (JSON、インストール前に編集可能。編集内容はプロトコル/パラメータフォームより優先されます)", + "selectLeftToView": "詳細を見るには左側のマーケットプレイスMCPを選択してください。" + }, + "badges": { + "verified": "認証済み", + "remote": "リモート", + "hasHomepage": "ホームページあり", + "uses": "{count} 回使用", + "deployed": "デプロイ済み", + "notDeployed": "未デプロイ" + }, + "selectLeftMcp": "左側でMCPを選択してください。" + }, + "AcpAgentSettings": { + "title": "Agent SDK 管理", + "description": "Agent SDK の接続、有効化状態、環境変数、設定管理、バージョン事前チェック情報を一元管理します。", + "loadingAgents": "エージェント一覧を読み込み中...", + "agentList": "エージェント一覧", + "emptyNoAgent": "利用可能なエージェントがありません。", + "configManagement": "設定管理", + "envVars": "環境変数", + "hostTools": { + "label": "ファイルとコマンドをエージェント自身に処理させる", + "description": "codeg がファイルアクセスとターミナルコマンドを代行しなくなり、エージェントが自身のプロセスで実行します。そうすることで初めて、エージェント自身のサンドボックスと権限ルールが適用されます。他のエージェントへの委任も無効になります(同じ処理が codeg 経由に戻ってしまうため)。codeg 自体はサンドボックスを提供しないため、エージェント側でサンドボックスを設定済みの場合にのみ有効にしてください。" + }, + "nativeJsonConfig": "ネイティブ JSON 設定", + "modelHintDefault": "空欄の場合はシステム既定モデルを使用します。", + "generalConfigDescriptionClaude": "API URL、API Key、Claude モデルをすばやく設定でき、ネイティブ JSON 設定と同期します。", + "generalConfigDescriptionDefault": "重要な設定入力(API URL、API Key、Model)とネイティブ JSON 設定管理をサポートします。", + "multiAgent": { + "title": "マルチエージェント連携", + "description": "アクティブなエージェントがサブタスクを他のエージェントに委任できるようにします。", + "enable": "委任を有効化", + "enableHint": "オフにすると、delegate_to_agent ツールはエージェントの MCP ツール一覧から非表示になります。", + "withheldByHostTools": "{agents} には委任ツールが渡りません。エージェントごとの「ファイルとコマンドをエージェント自身に任せる」スイッチがオンになっています。", + "selfInitiate": "Allow spawn without @", + "selfInitiateHint": "When on, an agent may start a listed sub-agent on its own. An @ mention is still always honored. When off, only an @ mention starts a sub-agent.", + "depthLimit": "最大委任深度", + "depthHint": "許可範囲: {min}–{max}。委任チェーン(ルート → 子 → 孫 …)の再帰深度を制限します。", + "completedCacheLabel": "完了結果のキャッシュ(MB)", + "completedCacheHint": "実行中の委任セッションが保持する、完了したサブエージェント結果のメモリ内キャッシュ。そのセッションの実行中のみ保持され、セッション終了時に自動的に破棄されます。この予算を超えると古い結果から順にメモリから破棄されます(サブエージェント自身のセッションでは引き続き閲覧可能)。0 は無制限(それでもセッション終了時に破棄)。", + "save": "保存", + "saving": "保存中…", + "saved": "委任設定を保存しました", + "saveFailed": "委任設定の保存に失敗しました", + "loadFailed": "委任設定の読み込みに失敗しました: {detail}", + "tabGeneral": "一般", + "tabAgentDefaults": "サブエージェント設定", + "agentDefaultsDescription": "マルチエージェント連携が委任呼び出しのためにサブエージェントを起動するときに適用される上書き設定です。ここに表示されるオプションはライブプローブで取得しており、選択した内容がそのままエージェントに渡されます。", + "probing": "エージェントの利用可能な設定項目を読み込み中…", + "probeFailed": "設定項目の読み込みに失敗しました: {detail}", + "retry": "再試行", + "noConfigAvailable": "このエージェントには設定可能な項目がありません。", + "modeLabel": "モード", + "agentDefaultHint": "エージェント既定: {value}", + "defaultOptionLabel": "既定({value})" + }, + "actions": { + "dragSort": "ドラッグして並べ替え", + "dragSortAgent": "{name} をドラッグして並べ替え", + "refreshCheck": "再チェック", + "refreshCheckAgent": "{name} を再チェック", + "clickEnable": "{name} を有効化", + "clickDisable": "{name} を無効化", + "install": "インストール", + "upgrade": "アップグレード", + "uninstall": "アンインストール", + "uninstalling": "アンインストール中...", + "saveEnvVars": "環境変数を保存", + "saving": "保存中...", + "saveGrokConfig": "Grok 設定を保存", + "saveCodexConfig": "Codex設定を保存", + "saveGeminiConfig": "Gemini設定を保存", + "saveOpenCodeConfig": "OpenCode設定を保存", + "saveOpenClawConfig": "OpenClaw設定を保存", + "saveConfigManagement": "設定管理を保存", + "saveCurrentProvider": "現在のプロバイダーを保存", + "showApiKey": "APIキーを表示", + "hideApiKey": "APIキーを非表示", + "showKey": "キーを表示", + "hideKey": "キーを非表示", + "showToken": "トークンを表示", + "hideToken": "トークンを非表示", + "cancel": "キャンセル", + "delete": "削除", + "deleting": "削除中...", + "confirmDelete": "削除を確認", + "confirmUninstall": "アンインストールを確認", + "saveClineConfig": "Cline設定を保存", + "saveHermesConfig": "Hermes設定を保存", + "saveCodeBuddyConfig": "CodeBuddy 設定を保存", + "saveKimiCodeConfig": "Kimi Code の設定を保存", + "customInstall": "カスタムインストール", + "saveKimiCodeRawConfig": "Save config.toml", + "saveDeepSeekConfig": "DeepSeek 設定を保存", + "diagnose": "診断" + }, + "status": { + "enabled": "有効", + "disabled": "無効", + "unchecked": "未チェック", + "agentEnabledAria": "{name} は有効です", + "agentEnabledSwitch": "{name} 有効化スイッチ" + }, + "preflight": { + "count": "事前チェック項目: {count}", + "notRun": "チェックはまだ実行されていません。" + }, + "grok": { + "configDescription": "ここで Grok を設定します。以下のコントロール(権限モード、推論の強さ、任意のカスタム(独自エンドポイント)モデル、圧縮)は ~/.grok/config.toml にマージされ、他のキーやコメントは保持されます。サインインは XAI_API_KEY または `grok login` を使用します。その他のキーは「詳細」で編集できます。", + "permissionModeLabel": "権限モード", + "permissionDefault": "毎回確認", + "permissionAcceptEdits": "編集を自動承認", + "permissionAuto": "スマート自動承認", + "permissionAlwaysApprove": "常に許可", + "reasoningEffortLabel": "推論レベル", + "effortLow": "低(高速)", + "effortMedium": "中(バランス)", + "effortHigh": "高", + "effortXhigh": "最大", + "optionDefault": "デフォルトを使用", + "authTitle": "認証", + "authMode": "認証方式", + "authModeApiKey": "XAI API キー", + "authModeApiKeyHint": "xAI コンソールの XAI_API_KEY で認証します。非対話・ヘッドレス実行向けで、このエージェントの環境変数に保存されます。", + "authModeCustom": "カスタムエンドポイント", + "authModeCustomHint": "独自のエンドポイント(BYO)を使用します。下でベース URL と API キーを持つカスタムモデルを定義すると、それが Grok の既定モデルになります。", + "subscriptionHint": "`grok login` でサインインします(SuperGrok / X Premium+)。API キーは保存されません。", + "loginHint": "ターミナルで次のコマンドを実行してサインインし、この設定を開き直してください:", + "commandCopied": "コマンドをクリップボードにコピーしました", + "copyCommand": "コマンドをコピー", + "authKeyConfigured": "XAI_API_KEY が設定されています。", + "authKeyMissing": "XAI_API_KEY が未設定です。", + "advancedToggle": "詳細(生の config.toml)", + "configTomlNative": "config.toml(ネイティブ)", + "configTomlHint": "~/.grok/config.toml 全体としてそのまま書き込まれます。無効な TOML は拒否され、タイプミスでファイルが切り詰められることはありません。", + "configTomlPlaceholder": "# 上のコントロール以外のキー。例:\n# [mcp_servers.*]、[cli]、[permission] ルール。", + "customModelTitle": "カスタムモデル(独自エンドポイント)", + "customModelHint": "Grok をカスタムまたは自己ホストのエンドポイントに向けます。codeg はモデルごとの `[model.*]` ブロックを書き込み、既定モデルに設定します。モデル ID を空にすると削除されます。", + "customModelIdLabel": "モデル ID", + "customModelIdPlaceholder": "grok-4.5", + "customModelIdHint": "`[model.*]` ブロックとして登録され、モデル名として API に送信されます。`[models].default` にも設定されます。", + "customBaseUrlLabel": "Base URL", + "customBaseUrlPlaceholder": "https://api.x.ai/v1(既定)", + "customApiBackendLabel": "API バックエンド", + "backendResponses": "Responses", + "backendChatCompletions": "Chat Completions", + "backendMessages": "Messages(Anthropic)", + "customApiKeyLabel": "API キー", + "customApiKeyHint": "`[model.*].api_key` にインラインで保存され、このエンドポイントにのみ適用されます。", + "customContextWindowLabel": "コンテキストウィンドウ(トークン)", + "customContextWindowHint": "任意。自動圧縮のタイミングに使われます。空欄の場合はエンドポイントの既定値を使用します。", + "autoCompactLabel": "自動圧縮のしきい値(%)", + "autoCompactHint": "コンテキスト使用率がこの割合に達したら会話を圧縮します(Grok の既定は 85)。`[session]` に書き込まれます。" + }, + "cursor": { + "configDescription": "ここで Cursor を設定します。まず認証方式を選択し——公式サブスクリプション(ブラウザログイン)またはヘッドレス/サーバー用の Cursor API キー——次にモデルを選び、CLI の権限ルールとサンドボックスを編集します。codeg はこれらを ~/.cursor/cli-config.json に書き込み、cursor-agent CLI と共有します。", + "authTitle": "認証", + "authChecking": "確認中…", + "authNotInstalled": "cursor-agent が未インストールです", + "authLoggedIn": "ログイン済み", + "authNotLoggedIn": "未ログイン", + "loginHint": "ターミナルで次のコマンドを実行して Cursor アカウントにログイン(ブラウザが開きます)し、完了後に更新を押してください:", + "apiKeyLabel": "Cursor API キー", + "apiKeyPlaceholder": "cursor.com/dashboard で取得", + "apiKeyHint": "CURSOR_API_KEY —— Cursor ダッシュボードのアカウントキー。ヘッドレス/サーバー環境でブラウザログインの代わりに使用します。サードパーティや OpenAI のキーではありません。", + "modelTitle": "デフォルトモデル", + "loadModels": "モデル一覧を取得", + "modelsUnavailable": "モデル一覧を取得できません", + "modelHint": "セッション開始時に --model として CLI に渡されます。既定のままなら Cursor が選択します。", + "permissionsTitle": "権限とサンドボックス", + "permissionsDescription": "CLI の権限ルール(cli-config.json)のビジュアルエディタ。許可ルールは確認なしで実行、拒否ルールは常にブロックされます。", + "permissionModeLabel": "権限モード", + "permissionModeDefault": "実行前に確認(デフォルト)", + "permissionModeForce": "Run Everything(--force)", + "permissionModeHint": "Run Everything は --force でセッションを起動します:deny ルール以外のツール呼び出しはすべて確認なしで自動許可されます(組織ポリシーにより allow ルール一致のみに制限される場合があります)。新しいセッションから有効です。", + "optionDefault": "既定(未設定)", + "sandboxLabel": "サンドボックス", + "sandboxEnabled": "有効", + "sandboxDisabled": "無効", + "allowRulesLabel": "許可ルール", + "denyRulesLabel": "拒否ルール", + "addRule": "ルールを追加", + "rulesSyntaxHint": "ルール構文:Shell(コマンド)、Read(パス/グロブ)、Write(パス/グロブ)、WebFetch(ドメイン)、Mcp(サーバー:ツール)——deny ルールが常に優先されます。", + "saveConfig": "設定を保存", + "advancedToggle": "詳細:cli-config.json(生ファイル)", + "advancedHint": "~/.cursor/cli-config.json の全文です。ここでの保存はそのまま書き込み、上の構造化コントロールはマージして書き込みます。", + "saveRawConfig": "ファイルを保存", + "authMode": "認証方式", + "subscriptionHint": "Cursor アカウントでサインインし、Cursor のモデルを使用します。", + "customApiKeyRequired": "Cursor API キーが必要です。", + "authModeApiKey": "Cursor API キー(ヘッドレス/サーバー)", + "authModeApiKeyHint": "Cursor ダッシュボードで発行したアカウント API キーで認証します(ヘッドレス/サーバー環境向け)。これは Cursor アカウントのキーであり、サードパーティ/OpenAI エンドポイントではありません——cursor-agent は Cursor 自身のバックエンドにのみ接続します。codex/OpenAI 互換エンドポイントを使うには、代わりに Codex エージェントを使用してください。", + "modelPickerPlaceholder": "モデルを検索…", + "modelNoMatch": "一致するモデルがありません", + "modelsNeedAuth": "サインインするとモデル一覧を読み込みます。", + "modelDefaultBadge": "既定" + }, + "deepseek": { + "configManagement": "DeepSeek Harness の設定", + "configDescription": "エンドポイントと API キーは deepseek-acp が起動時に読み込む環境変数です。モデルと推論レベルはセッションごとのセレクターなので、入力欄で切り替えます。", + "baseUrlLabel": "API エンドポイント", + "baseUrlHint": "空欄なら公式エンドポイントを使います。保存後に開始したセッションから有効になります。実行中のセッションは再接続してください。", + "baseUrlInvalid": "クエリ文字列を含まない完全な http(s) URL を入力してください(例:https://api.deepseek.com)", + "apiKeyLabel": "API キー", + "apiKeyHint": "DEEPSEEK_API_KEY としてエージェントに渡されます。環境変数は認証情報ファイルより優先されるため、ターミナルでログインする場合は空のままにしてください。" + }, + "codex": { + "configDescription": "API URL、API Key、モデル名、reasoning effort を素早く設定でき、`auth.json` / `config.toml` と同期します。", + "authMode": "認証方式", + "chatgptSubscription": "公式サブスクリプション", + "chatgptSubscriptionHint": "ChatGPT 公式サブスクリプションでログイン、API Key 不要", + "apiKeyHint": "API Key で OpenAI または互換 API サービスに接続", + "selectProvider": "プロバイダーを選択", + "modelName": "モデル名", + "selectReasoningEffort": "Reasoning Effort を選択", + "enableWebsocket": "WebSocket を有効化", + "enableWebsocketAria": "Codex Provider の WebSocket を有効化", + "enableSkills": "Skills を有効化", + "enableSkillsAria": "Codex の Skills を有効化", + "enableFast": "Fast を有効化", + "enableFastAria": "Codex の Fast サービスティアを有効化", + "sandboxGroupTitle": "サンドボックスと承認", + "sandboxGroupHint": "グローバルの ~/.codex/config.toml に書き込むため、codex CLI や IDE のセッションにも反映されます。これはスレッドの既定値で、codex 自身が開始するターン(/goal、/review、/compact)にのみ適用されます。通常のプロンプトは入力欄の承認プリセットを使います。変更はセッションを再起動すると有効になります。", + "sandboxShadowedWarning": "config.toml に default_permissions が設定されているため、codex は権限プロファイル経由で解決し sandbox_mode を完全に無視します。以下の設定を使うには default_permissions を削除してください。", + "sandboxPermissionsTableWarning": "config.toml に [permissions] プロファイルがありますが default_permissions が未設定のため、codex は起動を拒否します。下の生エディタで設定してください。", + "approvalPolicyLabel": "承認ポリシー", + "approvalPolicyUnset": "未設定(codex の既定: 要求時)", + "approvalPolicy_on-request": "要求時 — モデルが確認のタイミングを判断", + "approvalPolicy_untrusted": "未信頼 — 安全と分かっている読み取り専用コマンドのみ自動実行", + "approvalPolicy_never": "確認しない — 承認プロンプトを一切出さない", + "approvalPolicy_granular": "詳細設定 — プロンプト種別ごとに指定", + "approvalPolicyUntrustedAcpWarning": "ACP アダプターの 3 つの承認プリセットに untrusted に相当するものはないため、codeg のセッションは「要求時」にフォールバックします。その場合はモデルが尋ねるタイミングを決め、サンドボックスが既に許可しているコマンドは確認されなくなります。代わりに下のサンドボックスモードで制限してください。", + "granularHint": "オフにすると、その種類の要求は表示されずに自動で拒否されます。", + "granular_sandbox_approval": "シェルコマンドの権限昇格", + "granular_rules": "Execpolicy ルールのプロンプト", + "granular_skill_approval": "スキルスクリプトのプロンプト", + "granular_request_permissions": "request_permissions ツールのプロンプト", + "granular_mcp_elicitations": "MCP elicitation のプロンプト", + "sandboxModeLabel": "サンドボックスモード", + "sandboxModeUnset": "未設定(信頼済みフォルダはワークスペース書き込みにフォールバック)", + "sandboxMode_read-only": "読み取り専用", + "sandboxMode_workspace-write": "ワークスペース書き込み", + "sandboxMode_danger-full-access": "フルアクセス(サンドボックスなし)", + "sandboxModeHint": "Windows では、codex の実験的 Windows サンドボックスが無効な場合、ワークスペース書き込みは読み取り専用に降格されます。", + "sandboxModeSeedsPresetHint": "codeg はこれをセッションの初期承認プリセットにも反映するため、承認ポリシーとは異なり通常のプロンプトにも効きます。入力欄のプリセットが指定されている場合はそちらが優先されます。", + "writableRootsLabel": "追加の書き込み可能フォルダ", + "writableRootsHint": "作業ディレクトリに加えて許可する絶対パスを 1 行に 1 つ。", + "sandboxRootsRelativeError": "絶対パスである必要があります — codex は相対パスを ~/.codex 基準で解決します: {path}", + "networkAccessLabel": "ネットワークアクセスを許可", + "excludeTmpdirLabel": "書き込み可能ルートから TMPDIR を除外", + "excludeSlashTmpLabel": "書き込み可能ルートから /tmp を除外", + "authJsonNative": "auth.json(ネイティブ)", + "configTomlNative": "config.toml(ネイティブ)", + "loginButton": "ChatGPT でログイン", + "loginRequesting": "ログインコードを取得中...", + "loginStep1": "ブラウザで以下の URL を開いてください:", + "loginStep2": "以下のコードを入力してください:", + "loginPolling": "認証を待っています...", + "loginCancel": "キャンセル", + "loginSuccess": "ログイン成功、設定を保存しました!", + "loginFailed": "ログインに失敗しました:{message}", + "loginRetry": "再試行", + "loginCodeCopied": "コードをコピーしました", + "loggedIn": "アカウントにログイン済み", + "loginRelogin": "再ログイン / アカウント切替", + "loginTimeout": "ログインがタイムアウトしました。再試行してください", + "loginSaveFailed": "ログインは成功しましたが、設定の保存に失敗しました" + }, + "gemini": { + "authConfig": "Gemini 認証設定", + "authConfigDescription": "Gemini CLI の認証ドキュメントに準拠し、カスタムエンドポイント、Google ログイン、Gemini API Key、Vertex AI(ADC / サービスアカウント / API Key)をサポートします。", + "authMode": "認証モード", + "selectAuthMode": "認証モードを選択", + "viewAuthDoc": "認証ドキュメントを見る", + "mode": { + "custom": "カスタムエンドポイント", + "loginGoogle": "Google ログイン(OAuth)", + "vertexServiceAccount": "Vertex AI(サービスアカウント)" + }, + "hint": { + "custom": "API URL、API Key、Model を入力してください。GOOGLE_GEMINI_BASE_URL / GEMINI_API_KEY / GEMINI_MODEL に対応します。", + "loginGoogle": "先にターミナルで gemini を実行して Google ログインを完了してください。API key は不要です。", + "geminiApiKey": "Gemini API を使う場合は GEMINI_API_KEY を入力してください。", + "vertexAdc": "gcloud ADC を使用します。GOOGLE_CLOUD_PROJECT と GOOGLE_CLOUD_LOCATION の設定を推奨します。", + "vertexServiceAccount": "サービスアカウント JSON のパスを GOOGLE_APPLICATION_CREDENTIALS に設定してください。", + "vertexApiKey": "Vertex AI API key を使う場合は GOOGLE_API_KEY を入力してください。" + } + }, + "openCode": { + "configManagement": "OpenCode 設定管理", + "configDescription": "OpenCode の `provider` スキーマに準拠し、複数プロバイダー管理とネイティブ JSON ファイルとの双方向同期をサポートします。", + "providerManagement": "プロバイダー管理", + "providerCount": "{count} 個のプロバイダー", + "addProvider": "プロバイダーを追加", + "emptyProvider": "カスタムプロバイダーはまだありません。「カスタムプロバイダーを追加」をクリックして作成してください。", + "providerEnabledState": "{providerId} の有効状態", + "selectProviderNpm": "provider.npm を選択", + "modelManagement": "モデル管理", + "modelCount": "{count} 個のモデル", + "modelDescription": "OpenCode の `provider.models` に準拠。高速管理では現在 `name` / `id` をサポートし、その他の高度な項目は保持され、下部のネイティブ JSON で編集できます。", + "addModel": "モデルを追加", + "emptyModel": "まだモデルがありません。model id を入力して「モデルを追加」をクリックしてください。", + "modelId": "モデル ID", + "modelName": "モデル名", + "deleteModel": "モデル {modelId} を削除", + "nativeJsonConfig": "OpenCode ネイティブ JSON 設定", + "mainModel": "メインモデル", + "smallModel": "スモールモデル", + "noMatchingModels": "一致するモデルがありません", + "connectProvider": "プロバイダーを接続", + "connectedProviders": "接続済みプロバイダー", + "noConnectedProviders": "カタログのプロバイダーはまだ接続されていません。", + "advancedProviderConfig": "カスタムプロバイダー", + "customProviderConfigHint": "自分で定義する OpenAI 互換エンドポイント——opencode.json の provider ブロックで、API キーは auth.json に保存されます。", + "addCustomProvider": "カスタムプロバイダーを追加", + "disconnect": "切断", + "editConfig": "編集", + "customBadge": "カスタム", + "authKindApi": "API キー", + "authKindOauth": "OAuth", + "authKindNone": "認証情報なし", + "connect": { + "title": "プロバイダーを接続", + "description": "models.dev カタログからプロバイダーを選択します。認証情報は OpenCode の auth.json に保存されます。", + "pick": "プロバイダー", + "search": "プロバイダーを検索…", + "loading": "カタログを読み込み中…", + "catalogLabel": "models.dev カタログ", + "modelsAvailable": "{count} 個のモデルが利用可能", + "getKey": "API キーを取得", + "oauthApiKeyNote": "このプロバイダーは opencode auth login によるブラウザサインインにも対応しています。ブラウザサインインは近日対応予定です。今は API キーを貼り付けてください。", + "apiKey": "API キー", + "apiKeyHint": "auth.json に保存され、opencode.json には書き込まれません。", + "baseUrlOptional": "Base URL の上書き(任意)", + "providerId": "プロバイダー ID", + "displayName": "表示名", + "modelsList": "モデル(1 行に 1 つ)", + "modelsHint": "エンドポイントが受け付けるモデル ID。", + "action": "接続", + "editTitle": "プロバイダーを編集", + "editDescription": "このプロバイダーの API キーまたは Base URL を更新します。", + "saveAction": "保存" + }, + "customProvider": { + "title": "カスタムプロバイダーを追加", + "description": "OpenAI 互換エンドポイントを定義します。API キーは auth.json に、provider ブロックは opencode.json に保存されます。", + "action": "プロバイダーを追加", + "idInCatalog": "{providerId} は既知のプロバイダーです。「プロバイダーを接続」から接続してください。" + }, + "refreshCatalog": "カタログを更新", + "reasoningBadge": "推論", + "contextWindow": "コンテキストウィンドウ", + "permissions": { + "title": "権限", + "description": "どの操作をそのまま実行し、確認を求め、あるいはブロックするかを決めます。opencode.json の permission 設定に書き込まれ、下の保存で反映されます。", + "docsLink": "権限のドキュメント", + "unparsableConfig": "下のネイティブ JSON が解析できないため、ビジュアル編集を停止しています。JSON を修正すると再開します。", + "invalidBlock": "permission 設定の形式を認識できません。下のネイティブ JSON で編集するか、「リセット」でやり直してください。", + "orderingUnsafe": "ワイルドカードのルールが個別のツールより後に書かれているため、OpenCode はそれらにも適用します。下の各行は実際に有効な設定ではありません。「順序を修正」は値を変えずに、各スコープの先頭へワイルドカードを戻すだけです。", + "orderingUnsafeManual": "あるルールが後方のより広いパターンに隠されており、OpenCode は決して適用しません。下の各行は実際に有効な設定ではありません。重なり合う 2 つのパターンに唯一の正しい順序はないため、下のネイティブ JSON で広いほうを先に並べ替えてください。", + "fixOrder": "順序を修正", + "agentOverrides": "次のエージェントは権限を個別に上書きしており、最後に適用されるためここの設定より優先されます: {agents}。下のネイティブ JSON で編集するか、自動承認をオンにして削除してください。", + "legacyTools": "トップレベルの旧 tools 設定がツールを拒否しています。OpenCode はこれを権限に統合するため、ここに表示されている設定すべての上に適用されます。下のネイティブ JSON で編集するか、自動承認をオンにして削除してください。", + "autoAcceptTitle": "すべての権限を自動承認", + "autoAcceptHint": "シェルコマンド、ファイル編集、プロジェクト外のパスを含むすべてのツール呼び出しを確認なしで実行します。オンにすると、下のツール別設定は 1 つの全許可ルールに置き換わり、そのままではブロックし続けるエージェントごとの権限の上書きと旧 tools 設定も削除されます。", + "globalLabel": "全体のデフォルト", + "globalHint": "* ルールです。下のツールで上書きされていないものすべてに適用されます。", + "actionUnset": "未設定(OpenCode のデフォルト)", + "actionInherit": "デフォルトに従う({action})", + "actionAllow": "許可", + "actionAsk": "確認する", + "actionDeny": "拒否", + "perToolTitle": "ツール別の権限", + "reset": "リセット", + "ruleCount": "ルール: {count}", + "rulesToggle": "{tool} の詳細ルール", + "rulesHint": "ツールの入力に対して照合し、最後に一致したルールが優先されます。広いパターンを先に書いてください。* は任意の文字列、? はちょうど 1 文字に一致し、先頭の ~ はホームディレクトリに展開されます。", + "noRules": "詳細ルールはまだありません。", + "addRule": "ルールを追加", + "deleteRule": "ルール {pattern} を削除", + "duplicateRule": "そのパターンは既に存在します。", + "blankRule": "ルールにはパターンが必要です。削除するにはゴミ箱アイコンを使ってください。", + "customKeys": "ファイル内のその他の権限キー", + "customKeyHint": "OpenCode の組み込みツールではありません。記述どおり保持されます。", + "keys": { + "bash": "シェルコマンドの実行。解析後のコマンドで照合", + "edit": "ファイルへのすべての変更(edit・write・patch)", + "read": "ファイルの読み取り。パスで照合", + "external_directory": "プロジェクトの作業ディレクトリ外のパスへのアクセス", + "task": "サブエージェントの起動。サブエージェントの種類で照合", + "skill": "スキルの読み込み。スキル名で照合", + "glob": "ファイル検索。グロブパターンで照合", + "grep": "ファイル内容の検索。パターンで照合", + "list": "ディレクトリ内容の一覧表示", + "webfetch": "URL の取得", + "websearch": "ウェブ検索", + "lsp": "LSP クエリの実行", + "todowrite": "TODO リストの書き込み", + "question": "あなたへの質問", + "doom_loop": "同じ入力で同じ呼び出しが 3 回繰り返されたときに作動" + } + } + }, + "openClaw": { + "gatewayConfig": "Gateway 設定", + "gatewayDescription": "OpenClaw Gateway 接続を設定します。ローカルまたはリモートの gateway をサポートします。", + "gatewayUrlHint": "空欄の場合はローカル openclaw 設定の gateway.remote.url を使用します。", + "gatewayTokenPlaceholder": "Gateway 認証トークン", + "gatewayTokenHint": "可能な場合は平文トークンではなく token-file の使用を推奨します。openclaw CLI で設定してください。", + "sessionKeyHint": "任意。gateway の session key を指定します。空欄の場合は分離されたセッションが自動割り当てされます。" + }, + "hermes": { + "configManagement": "Hermes 設定", + "configDescription": "Hermes は認証情報を ~/.hermes/.env に、設定を ~/.hermes/config.yaml に独自に管理します。プロバイダーを選択し、API キーとモデルを設定してください。codeg が両方のファイルを書き込みます。", + "providerLabel": "プロバイダー", + "providerHint": "プロバイダーによって、Hermes が使用する API キー変数と model.provider が決まります。OAuth プロバイダーは下のターミナルセットアップから設定します。", + "groupApiKey": "API キー プロバイダー", + "groupOauth": "OAuth プロバイダー", + "groupAws": "AWS", + "apiKeyHint": "~/.hermes/.env に保存されます。プロセスには注入されません。Hermes が独自の設定から読み取ります。", + "modelName": "モデル", + "oauthHint": "このプロバイダーは OAuth を使用します。下のセットアップを実行し、ターミナルで認証してください。", + "awsHint": "Bedrock は AWS の認証情報(環境変数または共有設定)を使用します。上でモデル ID を設定し、環境で AWS アクセスを構成してください。", + "unsupportedProvider": "このプロバイダーは構造化フィールドでは編集できません。下の config.yaml 直接編集またはターミナルセットアップを使用してください。", + "setupTitle": "自己管理セットアップ", + "setupHint": "Hermes の対話型セットアップにはターミナルが必要です。下から起動するか、コマンドをコピーして自分で実行してください。", + "runSetup": "Hermes セットアップを実行", + "configureModel": "モデルを設定", + "openConfigFolder": "~/.hermes を開く", + "copyCommand": "コマンドをコピー", + "commandCopied": "コマンドをクリップボードにコピーしました", + "advancedTitle": "詳細: config.yaml を編集", + "rawConfigHint": "~/.hermes/config.yaml を直接編集します。ここで保存すると、ファイルがそのまま上書きされます。", + "saveRawConfig": "config.yaml を保存" + }, + "codebuddy": { + "configManagement": "CodeBuddy の設定", + "configDescription": "CodeBuddy は API キーで認証します。中国版では環境を「中国版(internal)」に設定する必要があります。iOA 版は「iOA」を使用し、海外版は未設定のままにします。", + "apiKeyLabel": "API キー", + "apiKeyHint": "このエージェントの CODEBUDDY_API_KEY として保存されます。または、ターミナルで CodeBuddy CLI からサインインすることもできます。", + "apiKeyHintSelfHosted": "このエージェントの CODEBUDDY_API_KEY として保存されます。プライベート展開で発行されたキーを使用してください。", + "environmentLabel": "環境", + "environmentHint": "CODEBUDDY_INTERNET_ENVIRONMENT を設定します。中国本土では「中国版(internal)」を使用する必要があります。海外版は未設定のままにします。", + "envOverseas": "海外版(デフォルト)", + "envChina": "中国版(internal)", + "envIoa": "iOA", + "envSelfHosted": "プライベート展開(セルフホスト)", + "baseUrlLabel": "デプロイ URL", + "baseUrlPlaceholder": "https://codebuddy.your-company.com", + "baseUrlHint": "CODEBUDDY_BASE_URL として保存され、CodeBuddy をプライベートエンドポイントに向けます。セルフホストではネットワーク環境(CODEBUDDY_INTERNET_ENVIRONMENT)は設定しません。", + "baseUrlInvalid": "有効な http(s) URL を入力してください。", + "loginHint": "API キーがない場合は、ターミナルで「codebuddy」を実行して Tencent アカウントでサインインすることもできます。" + }, + "kimiCode": { + "configManagement": "Kimi Code の設定", + "configDescription": "`kimi acp` は保存済みのログイントークンしか受け付けないため、codeg は ~/.kimi-code/config.toml に管理対象プロバイダーを書き込み、ローカルにゲートトークンを配置します。推論は引き続きご自身のキーで実行されます。", + "statusUnconfigured": "未設定", + "statusDirty": "未保存の変更あり", + "summaryLabel": "有効な設定", + "gateReadyApiKey": "API キーを config.toml に書き込み済み", + "gateReadyLogin": "Kimi アカウントでログイン済み", + "revealConfig": "フォルダーで表示", + "envOverrideWarning": "{keys} が設定されており、config.toml より優先されます。ここで保存すると自動的に削除されます。", + "authModeLabel": "認証方式", + "authModeApiKey": "API キー", + "authModeLogin": "Kimi アカウントログイン(サブスクリプション)", + "authModeApiKeyHint": "config.toml に管理対象プロバイダーを書き込み、セッションを開けるようゲートトークンを配置します。", + "loginHint": "ターミナルで `kimi login` を実行し、Kimi サブスクリプションアカウントでログインしてください。codeg は資格情報を保存せず、Kimi 自身のログインを再利用します。ここで保存すると codeg の API キー用ゲートトークンが削除されます。", + "credentialTitle": "資格情報", + "interfaceTypeLabel": "プロバイダー種別", + "interfaceTypeHint": "Kimi が話すプロバイダープロトコル(config.toml の `type`)。Moonshot / platform.kimi.com のキーには「Kimi / Moonshot」を選びます。", + "endpointLabel": "エンドポイント", + "endpointCustom": "カスタム(OpenAI 互換)", + "endpointHint": "国際 = api.moonshot.ai、中国(platform.kimi.com のキー)= api.moonshot.cn。カスタムは任意の OpenAI 互換エンドポイントを指定できます。", + "regionInternational": "国際(api.moonshot.ai)", + "regionChina": "中国(api.moonshot.cn)", + "baseUrlLabel": "Base URL", + "baseUrlHint": "空欄の場合はプロバイダー SDK の既定値を使用します。", + "apiKeyLabel": "API キー", + "apiKeyHint": "~/.kimi-code/config.toml に書き込まれ、推論に使用されます。platform.kimi.com または platform.kimi.ai で取得できます。", + "vertexProjectLabel": "GCP プロジェクト(GOOGLE_CLOUD_PROJECT)", + "vertexLocationLabel": "GCP リージョン(GOOGLE_CLOUD_LOCATION)", + "vertexHint": "Vertex AI は Google のアプリケーションデフォルト認証情報を使用します。`gcloud auth application-default login` を実行してください(API キー不要)。", + "modelTitle": "モデル", + "modelLabel": "モデル", + "modelHint": "config.toml に書き込まれるモデル id。「テストしてモデルを取得」でキーが実際にアクセスできるモデルを確認できます。", + "maxContextLabel": "最大コンテキスト長", + "maxContextHint": "Kimi のスキーマ上必須です。未指定だと Kimi がモデルブロック全体を破棄し、どのプロンプトも応答が返らなくなります。既定値は 262144。", + "fetchModels": "テストしてモデルを取得", + "fetchModelsOk": "キーは有効です — {count} 件のモデルが利用可能", + "fetchModelsEmpty": "キーは有効ですが、モデルが返されませんでした", + "fetchModelsFailed": "テストに失敗しました", + "fetchModelsNeedsKey": "先に API キーとエンドポイントを入力してください", + "modelNotInList": "このモデルはキーがアクセスできる一覧に含まれていません。Kimi は「モデルが見つかりません」で失敗します。", + "reasoningTitle": "推論", + "reasoningEnableLabel": "有効にする", + "reasoningDescription": "モデルが推論機能を宣言している場合にのみ Kimi は入力欄に「Thinking」ピッカーを表示するため、その宣言を codeg がここで書き込みます。新しいセッションから有効になります。", + "effortsLabel": "選択できるレベル", + "effortsHint": "ここで選んだ値が入力欄の「Thinking」ピッカーの項目になります。Kimi はレベルをそのままプロバイダーへ渡すので、モデルが受け付ける値を選んでください。", + "effortsEmptyHint": "レベルを 1 つも選ばない場合、入力欄は Off / On の 2 段トグルに退化します。", + "effortsCustomPlaceholder": "他のレベルを追加", + "effortsAdd": "追加", + "defaultEffortLabel": "既定のレベル", + "defaultEffortAuto": "Kimi に任せる", + "alwaysThinkingLabel": "モデルは常に推論する — ピッカーから Off を削除", + "fixErrorsFirst": "先に赤色の項目を修正してください", + "errorModelRequired": "モデルは必須です", + "errorMaxContextRequired": "最大コンテキスト長は必須です", + "errorMaxContextInvalid": "正の整数を入力してください", + "errorApiKeyRequired": "API キーは必須です", + "errorApiKeyInvalid": "API キーに改行を含めることはできません", + "errorBaseUrlRequired": "Base URL は必須です", + "errorBaseUrlInvalid": "http:// または https:// で始める必要があります", + "errorVertexProjectRequired": "GCP プロジェクトは必須です", + "errorDefaultEffortUnlisted": "上で選択したレベルのいずれかを指定してください", + "advancedTitle": "詳細設定", + "authTypeLabel": "資格情報の書き込み先", + "authTypeApiKey": "インライン api_key", + "authTypeEnv": "プロバイダーの env サブテーブル", + "authTypeHint": "config.toml 内で API キーを書き込む場所。", + "rawEditorLabel": "config.toml を直接編集", + "rawEditorWarning": "ここで保存するとファイル全体がそのまま上書きされ、上の構造化設定が置き換えられます。", + "rawEditorPlaceholder": "[providers.codeg]\ntype = \"kimi\"\nbase_url = \"https://api.moonshot.cn/v1\"\napi_key = \"sk-...\"" + }, + "authModeOfficialSubscription": "公式サブスクリプション", + "authModeCustomEndpoint": "カスタムエンドポイント", + "authModeCustomEndpointHint": "API URL と API Key を手動で設定してカスタムエンドポイントに接続します。", + "authModeModelProvider": "モデルプロバイダー", + "modelProvider": "モデルプロバイダー", + "modelProviderHint": "設定済みモデルプロバイダーの API URL、API Key、モデルを使用します。", + "selectModelProvider": "モデルプロバイダーを選択", + "noModelProviderAvailable": "このエージェントにはモデルプロバイダーが設定されていません。モデルプロバイダー設定で追加してください。", + "claude": { + "authMode": "認証方式", + "officialSubscription": "公式サブスクリプション", + "officialSubscriptionHint": "Anthropic 公式サブスクリプションを使用、API Key 不要。", + "mainModel": "メインモデル", + "reasoningModel": "推論モデル(thinking)", + "haikuDefaultModel": "デフォルト Haiku モデル", + "sonnetDefaultModel": "デフォルト Sonnet モデル", + "opusDefaultModel": "デフォルト Opus モデル", + "customModelOption": "カスタムモデル ID", + "customModelOptionName": "カスタムモデル名", + "customModelOptionDescription": "カスタムモデルの説明", + "customModelOptionHint": "Claude のモデル選択メニューにカスタム項目を1つ追加します(例: カスタムゲートウェイ/プロキシ経由のモデル)。名前と説明は任意の表示用設定です。", + "effortLevel": "推論レベル", + "effortLevelDefault": "デフォルトレベル", + "effortLevel_low": "低", + "effortLevel_medium": "中", + "effortLevel_high": "高", + "effortLevel_xhigh": "超高", + "sendAttributionHeader": "API に帰属/課金識別子を送信", + "sendAttributionHeaderAria": "API に Claude Code の帰属/課金識別子を送信", + "disableNonessentialTraffic": "テレメトリや不要なネットワークリクエストを無効化", + "disableNonessentialTrafficAria": "Claude Code のテレメトリや不要なネットワークリクエストを無効化" + }, + "dialogs": { + "confirmDeleteProvider": "Provider {providerId} を削除しますか?", + "confirmDeleteProviderDescription": "OpenCode config と auth JSON は同時に更新されます。この操作は元に戻せません。", + "confirmUninstall": "{name} をアンインストールしますか?", + "confirmUninstallDescription": "ローカルにインストールされたバージョンを削除します。後で再インストールできます。", + "customInstallTitle": "{name} をカスタムインストール", + "customInstallDescription": "インストールするバージョンを入力します。再インストールされ、現在インストールされているバージョンを置き換えます。", + "customInstallVersionLabel": "バージョン番号", + "customInstallInvalid": "有効なバージョン番号を入力してください(例: 1.2.3)。", + "customInstallSubmit": "インストール" + }, + "errors": { + "windowsFileLocked": "{name} のファイルは実行中のセッションが使用中のため、Windows では置き換えられません。{name} のセッションをすべて終了してから再試行してください。", + "nativeJsonMustBeObject": "ネイティブJSON設定はオブジェクトである必要があります", + "nativeJsonInvalid": "ネイティブJSON設定の形式エラー: {message}", + "openCodeAuthMustBeObject": "OpenCode の auth.json はJSONオブジェクトである必要があります", + "openCodeAuthInvalid": "OpenCode の auth.json 形式エラー: {message}", + "authMustBeObject": "auth.json はJSONオブジェクトである必要があります", + "authInvalid": "auth.json 形式エラー: {message}", + "providerIdPattern": "Provider ID は英字・数字・アンダースコア・ドット・ハイフンのみ使用できます", + "providerExists": "Provider {providerId} はすでに存在します", + "modelIdPattern": "Model ID は英字・数字・アンダースコア・ドット・コロン・ハイフンのみ使用できます", + "modelExists": "Model {modelId} はすでに存在します" + }, + "warnings": { + "nativeJsonRecoveredStructured": "ネイティブJSON設定が不正のため、構造化設定にリセットしました", + "nativeJsonRecoveredOpenCode": "ネイティブJSON設定が不正のため、OpenCode構造化設定にリセットしました", + "openCodeAuthRecovered": "OpenCode の auth.json が不正のため、デフォルト設定にリセットしました", + "authRecoveredStructured": "auth.json が不正のため、構造化設定にリセットしました" + }, + "toasts": { + "agentActionCompleted": "{name} の {action} が完了しました", + "agentActionFailed": "{name} の {action} に失敗しました", + "localVersion": "ローカルバージョン: {version}", + "installCompletedVersionLater": "インストールが完了しました。バージョンは次回チェック時に更新されます", + "uninstallCompleted": "{name} のアンインストールが完了しました", + "uninstallFailed": "{name} のアンインストールに失敗しました", + "localVersionRemoved": "ローカルバージョンを削除しました", + "saveAgentOrderFailed": "Agent の並び順の保存に失敗しました", + "saveAgentSwitchFailed": "Agent の有効スイッチ保存に失敗しました", + "saveEnvFailed": "環境変数の保存に失敗しました", + "grokSaved": "Grok 設定を保存しました", + "saveGrokNativeFailed": "Grok のネイティブ設定の保存に失敗しました", + "saveGrokApiKeyFailed": "設定は保存されましたが、API キーを保存できませんでした", + "cursorSaved": "Cursor の設定を保存しました", + "saveCursorConfigFailed": "Cursor の設定の保存に失敗しました", + "codexSaved": "Codex設定を保存しました", + "saveCodexNativeFailed": "Codexネイティブ設定の保存に失敗しました", + "geminiSaved": "Gemini設定を保存しました", + "saveGeminiFailed": "Gemini設定の保存に失敗しました", + "providerDeleted": "Provider {providerId} を削除しました", + "providerDeleteFailed": "Provider {providerId} の削除に失敗しました", + "providerSaved": "Provider {providerId} を保存しました", + "saveProviderFailed": "Provider {providerId} の保存に失敗しました", + "openCodeConfigSynced": "OpenCode config と auth JSON が同期されました。", + "openCodeSaved": "OpenCode設定を保存しました", + "saveOpenCodeFailed": "OpenCode設定の保存に失敗しました", + "openClawSaved": "OpenClaw設定を保存しました", + "saveOpenClawFailed": "OpenClaw設定の保存に失敗しました", + "configSaved": "設定を保存しました", + "configSavedHint": "既存のセッションは再度開く必要があります", + "saveConfigManagementFailed": "設定管理の保存に失敗しました", + "clineSaved": "Cline設定を保存しました", + "saveClineFailed": "Cline設定の保存に失敗しました", + "hermesSaved": "Hermes設定を保存しました", + "saveHermesFailed": "Hermes設定の保存に失敗しました", + "codeBuddySaved": "CodeBuddy の設定を保存しました", + "saveCodeBuddyFailed": "CodeBuddy の設定の保存に失敗しました", + "kimiCodeSaved": "Kimi Code の設定を保存しました", + "saveKimiCodeFailed": "Kimi Code の設定の保存に失敗しました", + "deepseekSaved": "DeepSeek の設定を保存しました", + "saveDeepSeekFailed": "DeepSeek の設定の保存に失敗しました", + "modelProviderRequired": "保存する前にモデルプロバイダーを選択してください。", + "affectedRunningSessions": "{count} 件の実行中セッションは再接続すると変更が適用されます", + "providerConnected": "{providerId} を接続しました", + "connectFailed": "{providerId} の接続に失敗しました", + "providerDisconnected": "{providerId} を切断しました", + "disconnectFailed": "{providerId} の切断に失敗しました", + "catalogRefreshed": "カタログを更新しました — {count} 個のプロバイダー", + "catalogRefreshFailed": "カタログの更新に失敗しました", + "piSaved": "Pi 設定を保存しました", + "savePiFailed": "Pi 設定の保存に失敗しました", + "piRuntimeSaved": "Pi ランタイムを保存しました", + "savePiRuntimeFailed": "Pi ランタイムの保存に失敗しました", + "piBinaryInstalled": "pi をインストールしました", + "piBinaryInstallFailed": "pi のインストールに失敗しました", + "piBinaryUninstalled": "pi をアンインストールしました", + "piBinaryUninstallFailed": "pi のアンインストールに失敗しました", + "savePiTrustFailed": "ワークスペースの信頼設定の保存に失敗しました" + }, + "version": { + "statusLabel": "バージョン状態", + "notInstalled": "未インストール", + "remoteLocal": "リモート: {remoteVersion} · ローカル: {localVersion}", + "localOnly": "ローカル:{localVersion}", + "localInstalled": "{versionText}。インストール済みです。", + "platformUnsupported": "{versionText}。現在のプラットフォームではこのエージェントをサポートしていません。", + "uvxNotReady": "{versionText}。uv ランタイムが未インストールです。下の uv チェックからインストールするとこのエージェントを使用できます。", + "clickInstall": "{versionText}。右側の「インストール」をクリックしてください。", + "localUnrecognized": "{versionText}。ローカルバージョンは比較できません。上書きインストールのためアップグレードを試してください。", + "upgradeAvailable": "{versionText}。アップグレード可能です。", + "remoteUnavailable": "{versionText}。現在リモートバージョンは取得できません。", + "latest": "{versionText}。すでに最新です。" + }, + "adapter": { + "label": "ACP アダプター", + "badge": "ACP アダプター", + "badgeHint": "このエージェントで Codeg がインストールするのはベンダー CLI ではなく ACP アダプターのパッケージです。両者は独立しており、設定は共有されます。", + "learnMore": "詳細", + "missingWithNative": "お使いの {nativeLabel} を {nativePath} で検出しました。Codeg はエージェントを ACP で駆動しますが、この CLI 自体は ACP に対応していないため、別パッケージのアダプター {adapterPackage}(Agent Client Protocol プロジェクトが保守。当初は Zed チーム)が必要です。独自のランタイムを同梱しており、既存の {nativeCmd} コマンドを変更も置き換えもしません。読み込む設定は同じ {configDir} なので、ログインと設定はそのまま引き継がれます。下のボタンからインストールしてください。", + "missing": "Codeg はエージェントを ACP で駆動しますが、{nativeLabel} 自体は ACP に対応していないため、別パッケージのアダプター {adapterPackage}(Agent Client Protocol プロジェクトが保守。当初は Zed チーム)が必要です。独自のランタイムを同梱しているので {nativeCmd} CLI を先に入れる必要はありません。すでにお持ちの場合も両者は共存し、{configDir} のログインと設定を共有します。下のボタンからインストールしてください。", + "readyWithNative": "アダプター {adapterCmd} はインストール済みです。Codeg が起動するのはこちらで、あなたの {nativeCmd}({nativePath})ではありません。両者は独立したパッケージとして共存し、どちらも {configDir} を読むためログインと設定は共有されます。", + "ready": "アダプター {adapterCmd} はインストール済みで、Codeg が起動するのはこれです。独自のランタイムを同梱しているため {nativeLabel} は不要です。後から入れても両者は共存し、{configDir} を共有します。" + }, + "cline": { + "configDescription": "Cline API プロバイダーと認証情報を設定します。設定は ~/.cline/data/ に保存されます。" + }, + "opencodePlugins": { + "title": "OpenCode プラグイン", + "declared": "宣言済みプラグイン", + "noPlugins": "opencode.json にプラグインが宣言されていません", + "status": { + "installed": "インストール済み", + "missing": "未インストール" + }, + "installAll": "不足プラグインをすべてインストール", + "pinVersions": "@latest バージョンを固定", + "install": "インストール", + "uninstall": "アンインストール", + "refresh": "更新", + "success": "すべてのプラグインが正常にインストールされました", + "failed": "プラグイン操作に失敗しました" + }, + "pi": { + "configManagement": "Pi 設定", + "configDescription": "Pi はモデルプロバイダーの API キーで認証します。キーは ~/.pi/agent/auth.json に、モデル選択は settings.json に書き込まれます。", + "providerLabel": "プロバイダー", + "modelLabel": "モデル", + "thinkingLabel": "思考", + "thinking": { + "off": "オフ", + "low": "低", + "medium": "中", + "high": "高", + "minimal": "最小", + "xhigh": "最高" + }, + "apiKeyLabel": "API キー", + "apiKeyHint": "選択したプロバイダーの ~/.pi/agent/auth.json に保存されます。", + "apiKeySetPlaceholder": "••••••(保存済み・空欄で維持)", + "saveConfig": "Pi 設定を保存", + "providerModelRequired": "プロバイダーとモデルは必須です", + "runtimeTitle": "ランタイム", + "runtimeDescription": "どの pi を実行するか選択します。デフォルト、または自分の pi ビルドを指定します。", + "modeDefault": "デフォルト pi", + "modeDefaultHint": "内蔵の pi-acp アダプターで PATH 上の pi を起動します。 pi のインストール:npm install -g @earendil-works/pi-coding-agent", + "modeCustom": "カスタム pi", + "modeCustomHint": "自分の pi ビルド・インストール・ラッパーを実行します。", + "commandLabel": "pi コマンドまたはパス", + "commandHint": "絶対パス、PATH 上のコマンド名、またはラッパースクリプト(例: monorepo の ./pi-test.sh)。", + "commandNotFound": "コマンドが見つかりません", + "validate": "検証", + "advanced": "詳細設定", + "configDirLabel": "設定ディレクトリ (PI_CODING_AGENT_DIR)", + "sessionDirLabel": "セッションディレクトリ (PI_CODING_AGENT_SESSION_DIR)", + "flagsHint": "pi-acp はカスタム pi フラグ(--approve、-e など)を転送しません。pi をスクリプトでラップしてコマンドに指定してください。", + "customIncomplete": "保存するには pi コマンドを入力してください", + "saveRuntime": "ランタイムを保存", + "providerPlaceholder": "プロバイダーを選択", + "customProvider": "カスタムプロバイダー…", + "providerIdLabel": "プロバイダー ID", + "apiProtocolLabel": "API プロトコル", + "baseUrlLabel": "API エンドポイント(Base URL)", + "customProviderHint": "~/.pi/agent/models.json にエンドポイント向けのプロバイダーを定義します。多くのセルフホスト/プロキシは openai-completions を使用します。", + "baseUrlRequired": "API エンドポイント(Base URL)は必須です", + "binaryTitle": "pi バイナリ (pi-coding-agent)", + "binaryDescription": "pi-acp はこの pi バイナリを実行します。ここでインストールするか、下で独自のビルドを指定できます。", + "binaryInstalled": "インストール済み", + "binaryMissing": "未インストール", + "binaryChecking": "確認中…", + "installBinary": "pi をインストール", + "installing": "インストール中…", + "recheck": "再確認", + "configDirSkillsNote": "カスタム設定ディレクトリを指定すると、設定画面で管理するスキル・エキスパート・オフィスツールはこの pi に適用されません。スキルはそのフォルダー内で直接管理してください。", + "projectTrustTitle": "プロジェクトの信頼", + "projectTrustDescription": "pi にプロジェクトファイルの読み込みを許可したフォルダーです。信頼したフォルダーでは、そのリポジトリの .pi/extensions が pi の起動時にコードを実行します。配下のすべてのフォルダーに適用され、ターミナルで pi を実行するときにも使われます。", + "projectTrustLoading": "読み込み中…", + "projectTrustEmpty": "まだ判断したフォルダーはありません。", + "projectTrustTrusted": "信頼済み", + "projectTrustDenied": "信頼しない", + "projectTrustRevoke": "取り消す", + "reasoningTitle": "推論", + "reasoningEnableLabel": "有効にする", + "reasoningDescription": "モデルが推論能力を宣言している場合にのみ、pi は推論強度を送信します。未宣言のモデルではすべてのレベルが Off に丸められるため、入力欄のセレクターは触れた瞬間に戻ってしまいます。models.json のこのモデルの項目に書き込まれます。", + "levelsLabel": "選択できるレベル", + "levelsHint": "入力欄の推論セレクターの項目になります。エンドポイントが受け付ける値を選んでください。ここにないレベルは pi が拒否します。", + "levelsEmptyError": "レベルを 1 つ以上選んでください。1 つも選ばないと pi は Off に戻ります。", + "wireValuesTitle": "詳細: プロバイダーに送る値", + "wireValuesHint": "空欄ならレベル名をそのまま送信します。エンドポイントが別の表記を求める場合のみ設定してください(Google 系は LOW / HIGH)。", + "defaultLevelUnlisted": "このレベルは上の選択リストにありません。pi が丸めてしまいます。" + }, + "addCustomAgent": "カスタムエージェントを追加", + "addCustomAgentHint": "ACP 対応のエージェントを追加できます。公開 ACP レジストリから選ぶか、レジストリ情報を貼り付けてください。", + "customAgentFromRegistry": "ACP レジストリ", + "customAgentManual": "手動入力", + "customAgentSearchPlaceholder": "エージェントを検索…", + "customAgentLoadingCatalog": "ACP レジストリを読み込み中…", + "customAgentRetry": "再試行", + "customAgentNoResults": "該当するエージェントがありません", + "customAgentAdd": "追加", + "customAgentAlreadyAdded": "追加済み", + "customAgentUnsupportedPlatform": "このプラットフォーム向けのビルドがありません", + "customAgentAdded": "{name} を追加しました", + "customAgentIdLabel": "レジストリ ID", + "customAgentNameLabel": "表示名", + "customAgentVersionLabel": "バージョン", + "customAgentSpecLabel": "配布情報(JSON)", + "customAgentSpecHint": "ACP レジストリの distribution オブジェクトと同じ形式です。npx・uvx・binary の各チャネルに対応し、レジストリ項目全体の貼り付けも可能です。npx/uvx の cmd はパッケージがインストールする実行コマンド名で、省略時はパッケージ名から導出されるため、異なる場合は指定してください。binary はプラットフォームキーごとに指定し(このマシンは {platform})、cmd はアーカイブ内の起動パス、sha256 は任意でダウンロードを検証します。", + "customAgentTemplateLabel": "テンプレート", + "customAgentKindLabel": "起動方法", + "customAgentInvalidJson": "JSON として不正です", + "customAgentNoDistribution": "npx・uvx・binary のいずれの配布も見つかりません", + "customAgentCancel": "キャンセル", + "customAgentSave": "エージェントを追加", + "customAgentSaveChanges": "変更を保存", + "customAgentEdit": "エージェントを編集", + "customAgentEditHint": "名前・アイコン・配布情報・スキル宣言を変更できます。エージェント ID は変更できません。", + "customAgentEditNotFound": "カスタムエージェント {id} が見つかりません", + "customAgentSaved": "{name} を保存しました", + "customAgentVersionProbeLabel": "バージョン確認コマンド(任意)", + "customAgentVersionProbeHint": "ローカルにインストールされたバージョンを表示するコマンドです。空欄の場合はエージェントコマンドに --version を付けて実行します。", + "customAgentRemove": "エージェントを削除", + "customAgentRemoveHint": "エージェント定義を削除します。既存の会話の履歴は残り、エージェントを起動できなくなるだけです。", + "customAgentIconLabel": "アイコン(任意)", + "customAgentIconUpload": "アップロード", + "customAgentIconReplace": "変更", + "customAgentIconClear": "アイコンを削除", + "customAgentIconHint": "エージェントと共に保存されるためオフラインでも表示できます。指定しない場合は色付きの頭文字を使います。", + "customAgentSkillsLabel": "Skills(共有 .agents/skills)", + "customAgentSkillsHint": "このエージェントが共有の .agents/skills ディレクトリ(グローバルおよびプロジェクト)を読み取ることを宣言し、すべてのスキルマトリクスに追加します。共有ディレクトリにリンクしたスキルは、同じディレクトリを読むほかのエージェントからも見えます。", + "customAgentSkillsDirLabel": "専用スキルディレクトリ", + "customAgentSkillsDirHint": "このエージェントがスキルを読み込むディレクトリの絶対パスです。共有ストアと併用も単独利用も可能です。~ はホームディレクトリに展開され、リンクしたスキルはまずここに配置されます。", + "customAgentMcpLabel": "MCP サポート", + "customAgentMcpHint": "セッション開始時に codeg 内蔵の codeg-mcp コンパニオンをこのエージェントへ渡します。委任・リアルタイムフィードバック・タスクツールはこの経路を使います。MCP サーバーを受け付けず接続に失敗するエージェントではオフにしてください。設定は次回の接続から有効になります。", + "customAgentIconNotAnImage": "画像ファイルを選んでください。", + "customAgentIconTooLarge": "アイコンは {limit} KB 未満にしてください。", + "customAgentIconReadFailed": "その画像を読み込めませんでした。", + "customAgentRemoveConfirm": "{name} を削除しますか?既存の会話は残りますが、起動できなくなります。", + "customAgentRemoveWithData": "記録された会話履歴も削除する", + "customAgentRemoved": "{name} を削除しました", + "customAgentBadge": "カスタム", + "customAgentNotLaunchable": "この環境では起動できません: {reason}" + }, + "SettingsPages": { + "agentsLoading": "エージェント設定を読み込み中...", + "skillPacksLoading": "スキルパックを読み込み中…" + }, + "GeneralSettings": { + "loading": "読み込み中...", + "sectionTitle": "一般", + "sectionDescription": "デフォルトターミナル、レンダリング高速化、マルチエージェント委譲などの共通設定をここで一括管理します。", + "terminalTitle": "デフォルトターミナル", + "terminalDescription": "ターミナルバーやファイルツリーから新しいターミナルタブを開くときに使用するシェルを選択します。エージェントが codeg にコマンドライン全体の実行を依頼するときにも使われます。", + "terminalSystemDefault": "システムデフォルト", + "terminalPowerShell7": "PowerShell 7 (pwsh)", + "terminalWindowsPowerShell": "Windows PowerShell", + "terminalCmd": "コマンドプロンプト (cmd)", + "terminalSaveFailed": "ターミナル設定の保存に失敗しました: {message}", + "terminalShellCustom": "カスタムパス", + "terminalShellCustomPath": "Shell パス", + "terminalShellCustomPlaceholder": "/usr/local/bin/fish", + "terminalShellCustomSave": "保存", + "terminalShellCustomHint": "絶対パス、または PATH で解決可能なコマンド名を指定します。", + "terminalShellNotInstalled": "未インストール", + "terminalShellNotFoundWarning": "このパスはホスト上に存在しません。", + "terminalCurrentShell": "現在使用中: {path}", + "renderingDescription": "アプリで黒画面や描画不具合が発生する場合(一部の AMD GPU や Intel 内蔵 GPU で報告あり)、ハードウェアアクセラレーションを無効化してください。Windows デスクトップ版のみ有効です。", + "disableHardwareAcceleration": "ハードウェアアクセラレーションを無効化", + "renderingSaveFailed": "レンダリング設定の保存に失敗しました: {message}", + "restartRequired": "保存しました。再起動後に反映されます。", + "restartNow": "今すぐ再起動", + "restartFailed": "再起動に失敗しました: {message}", + "loadFailed": "読み込みに失敗しました: {message}" + }, + "LoginPage": { + "documentTitle": "ログイン - codeg", + "brand": "Codeg", + "subtitle": "デスクトップアプリに接続するためのアクセストークンを入力してください", + "tokenPlaceholder": "アクセストークン", + "connect": "接続", + "connecting": "接続中...", + "helpText": "トークンはデスクトップアプリの 設定 → Web サービス で取得できます", + "invalidToken": "トークンが無効です。確認して再度お試しください", + "connectionFailed": "接続失敗 (HTTP {status})", + "networkError": "サーバーに接続できません" + }, + "CommitPage": { + "title": "コミット", + "invalidFolderId": "無効なフォルダID", + "loadingRepo": "リポジトリを読み込み中..." + }, + "MergePage": { + "title": "コンフリクトの解決", + "invalidFolderId": "無効なフォルダID", + "loadingRepo": "リポジトリを読み込み中...", + "localVersion": "ローカル(自分側)", + "result": "結果", + "remoteVersion": "リモート(相手側)", + "acceptLocal": "ローカルを採用", + "acceptRemote": "リモートを採用", + "markResolved": "解決済みにする", + "abortMerge": "中止", + "completeMerge": "マージ完了", + "unresolvedConflicts": "ファイルに未解決のコンフリクトマーカーがあります", + "fileResolved": "ファイルが解決されました", + "allResolved": "すべてのコンフリクトが解決されました", + "conflictFiles": "コンフリクトファイル", + "loadingFile": "ファイルを読み込み中...", + "preparingMerge": "マージを準備中...", + "selectFile": "解決するファイルを選択してください", + "noConflicts": "コンフリクトファイルなし", + "skipFile": "スキップ", + "abortSuccess": "操作が中止されました", + "applyAllNonConflicting": "競合しない変更をすべて適用", + "applyLeftNonConflicting": "ローカルを適用", + "applyRightNonConflicting": "リモートを適用" + }, + "ImportSessions": { + "title": "ローカルセッションをインポート", + "scanningTitle": "ローカルエージェントのセッションをスキャン中…", + "scanningHint": "各エージェントのローカルセッションストアを走査しています。履歴が多い場合は時間がかかることがあります。インポート済みのセッションはあわせて更新されます。", + "scanFailed": "スキャンに失敗しました", + "retry": "再試行", + "rescan": "再スキャン", + "empty": "ローカルセッションが見つかりません", + "emptyHint": "このマシンにはエージェントのセッションストアが見つかりませんでした。", + "noMatches": "現在のフィルターに一致するセッションはありません", + "searchPlaceholder": "タイトルまたはパスを検索…", + "allAgents": "すべてのエージェント", + "onlyImportable": "インポート可能のみ", + "selectAll": "すべて選択", + "clearSelection": "クリア", + "expandAll": "すべて展開", + "collapseAll": "すべて折りたたむ", + "summaryCounts": "{total} セッション · インポート可能 {importable} · {folders} フォルダー", + "noFolderSkipped": "プロジェクトフォルダーのない {count} 件をスキップしました", + "folderNew": "新規", + "folderCounts": "インポート可能 {importable}/{total}", + "toggleFolderAria": "{name} のインポート可能なセッションをすべて選択", + "toggleSessionAria": "セッション {title} を選択", + "statusImported": "インポート済み", + "statusDeleted": "削除済み", + "untitled": "無題のセッション", + "messageCount": "{count} 件のメッセージ", + "selectedCount": "{count} 件選択中", + "importSelected": "選択項目をインポート", + "importing": "インポート中…", + "close": "閉じる", + "doneTitle": "インポート完了", + "doneImported": "インポート", + "doneUpdated": "更新済み", + "doneSkipped": "スキップ", + "doneCreatedFolders": "作成フォルダー", + "doneNotFound": "見つからず", + "doneFailed": "失敗", + "continueImport": "続けてインポート", + "toasts": { + "importFailed": "インポートに失敗しました: {message}" + } + }, + "Folder": { + "workspaceStatus": { + "degradedTitle": "リアルタイム更新は利用できません", + "degradedHint": "ウォッチャーの起動に失敗しました(アクセス権限エラーなど)。最新の変更を反映するには手動で更新してください。", + "retry": "再試行", + "retrying": "再試行中..." + }, + "common": { + "all": "すべて", + "cancel": "キャンセル", + "close": "閉じる", + "closeOthers": "他を閉じる", + "closeAll": "すべて閉じる", + "confirm": "確認", + "save": "保存", + "delete": "削除", + "rename": "名前を変更", + "loading": "読み込み中...", + "refresh": "更新", + "refreshing": "更新中...", + "create": "作成", + "createAndSwitch": "作成して切り替え", + "openFile": "ファイルを開く", + "viewDiff": "差分を見る", + "push": "プッシュ..." + }, + "statusLabels": { + "in_progress": "進行中", + "pending_review": "レビュー", + "completed": "完了", + "cancelled": "キャンセル済み" + }, + "sidebar": { + "title": "会話", + "locateActiveConversation": "アクティブな会話を表示", + "expandAllGroups": "すべてのグループを展開", + "collapseAllGroups": "すべてのグループを折りたたむ", + "newConversation": "新しい会話", + "newConversationShort": "新規", + "newChat": "新しい会話", + "search": "検索", + "noConversationsFound": "会話が見つかりません。", + "importLocalSessions": "ローカルセッションをインポート", + "importing": "インポート中...", + "error": "エラー: {message}", + "completeAllSessions": "すべてのセッションを完了", + "completeAllReviewTitle": "すべてのレビューセッションを完了しますか?", + "completeAllReviewDescription": "これにより、レビュー中の {count, plural, one {# 件のセッション} other {# 件のセッション}} が完了としてマークされます。", + "completing": "完了処理中...", + "toasts": { + "importedSessions": "{imported, plural, one {# 件のセッション} other {# 件のセッション}} をインポートし、{skipped} 件をスキップしました", + "importedAndUpdated": "{imported, plural, one {# 件のセッション} other {# 件のセッション}} をインポートし、{updated, plural, one {# 件のタイトル} other {# 件のタイトル}} を更新し、{skipped} 件をスキップしました", + "updatedTitles": "{updated, plural, one {# 件のタイトル} other {# 件のタイトル}} を更新し、{skipped} 件をスキップしました", + "noNewSessionsFound": "新しいセッションは見つかりませんでした({skipped} 件をスキップ)", + "importFailed": "インポートに失敗しました: {message}", + "reviewCompleted": "{count, plural, one {# 件のレビューセッション} other {# 件のレビューセッション}} を完了にしました", + "completeReviewFailed": "レビューセッションの完了処理に失敗しました: {message}", + "folderOpened": "フォルダ {name} を開きました", + "folderRemoved": "フォルダ {name} を削除しました", + "openFolderFailed": "フォルダを開けませんでした", + "removeFolderFailed": "フォルダの削除に失敗しました: {message}", + "reorderFoldersFailed": "フォルダの並べ替えに失敗しました: {message}", + "changeFolderColorFailed": "色の変更に失敗しました: {message}", + "setFolderAliasFailed": "エイリアスの設定に失敗しました: {message}", + "changeFolderDefaultAgentFailed": "デフォルトエージェントの設定に失敗しました: {message}" + }, + "statsLabel": "{folders} フォルダ · {convos} 会話", + "reorderHandle": "ドラッグして並べ替え", + "openFolder": "フォルダを開く", + "searchPlaceholder": "会話を検索...", + "viewOptions": "表示オプション", + "showCompleted": "完了した会話を表示", + "showWorktrees": "ワークツリーフォルダを表示", + "showRecent": "「最近」グループを表示", + "moreOptions": "その他のオプション", + "sortBy": "並び替え", + "sortByCreatedAt": "作成時刻順", + "sortByUpdatedAt": "更新時刻順", + "sectionOrder": "セクションの順序", + "sectionOrderMoveUp": "上へ移動", + "sectionOrderMoveDown": "下へ移動", + "sectionOrderItemLabel": "{name} — {total} 件中 {position} 番目", + "statusRunningBadge": "実行中", + "runningCountBadge": "{count} 件の会話が実行中", + "statusCancelledBadge": "キャンセル済み", + "worktreeRemovedBadge": "元の worktree は削除済み", + "conversationCountUnit": "{count} 件", + "emptyFolderHint": "会話がありません", + "noMatchingConversations": "一致する会話がありません", + "noUnfinishedConversations": "未完了の会話はありません。右上のメニューから「完了した会話を表示」を有効にできます。", + "removeFolderConfirmTitle": "このフォルダをワークスペースから削除しますか?", + "removeFolderConfirmDescription": "\"{name}\" をワークスペースから削除しますか?関連するタブとターミナルが閉じられます。", + "folderHeaderMenu": { + "manageConversations": "会話の管理…", + "manageLinks": "リンク済みフォルダー", + "changeColor": "色を変更", + "useThemeColor": "アプリのテーマを使用", + "setDefaultAgent": "デフォルトエージェントを設定", + "defaultAgentNone": "設定なし(グローバルを使用)", + "agentUnavailableSuffix": "(利用不可)", + "loadingAgents": "エージェントを読み込み中…", + "setAlias": "エイリアスを設定…", + "setAliasTitle": "フォルダーのエイリアスを設定", + "setAliasPlaceholder": "エイリアスを入力(空欄でクリア)", + "setAliasSave": "保存", + "setAliasCancel": "キャンセル", + "removeFromWorkspace": "ワークスペースから削除" + }, + "manageConversations": { + "title": "会話の管理", + "searchPlaceholder": "タイトルで検索…", + "agentFilterAll": "すべてのエージェント", + "statusFilterAll": "すべてのステータス", + "folderFilterAll": "すべてのフォルダ", + "branchFilterAll": "すべてのブランチ", + "branchNone": "ブランチなし", + "branchSearchPlaceholder": "ブランチを検索…", + "noMatchingBranches": "一致するブランチがありません", + "selectAllVisible": "すべて選択", + "deselectAll": "選択を解除", + "selectedCount": "{count} 件選択中", + "matchedCount": "{count} 件該当", + "untitledConversation": "無題の会話", + "setStatus": "ステータスを変更…", + "deleteSelected": "削除", + "noConversations": "このフォルダには会話がありません。", + "noConversationsWorkspace": "ワークスペースに会話がありません。", + "noMatchingConversations": "条件に一致する会話がありません。", + "confirmDeleteTitle": "{count} 件の会話を削除しますか?", + "confirmDeleteDescription": "この操作は元に戻せません。", + "toastDeleted": "{count} 件の会話を削除しました", + "toastStatusUpdated": "{count} 件の会話のステータスを更新しました", + "toastOpFailed": "操作に失敗しました: {message}" + }, + "sectionPinned": "ピン留め", + "sectionFolders": "フォルダ", + "sectionChats": "チャット", + "sectionRecent": "最近", + "noChats": "チャットがありません", + "noRecent": "最近の会話はありません", + "showMoreRecent": "さらに表示({count})", + "noFolders": "開いているフォルダがありません", + "newChatAction": "新しいチャット", + "automations": "オートメーション", + "tasks": "ToDo タスク", + "loadingSubsessions": "サブ会話を読み込み中…" + }, + "conversation": { + "reloadFailed": "会話の再読み込みに失敗しました: {message}", + "reloaded": "会話を再読み込みしました", + "reload": "再読み込み", + "activeConversationIndicator": "アクティブな会話", + "newConversation": "新しい会話", + "closeConversation": "会話を閉じる", + "copyText": "テキストをコピー", + "copyTextSuccess": "コピーしました", + "copyTextFailed": "コピーに失敗しました", + "forkSession": "セッションをフォーク", + "forkSessionSuccess": "セッションのフォークに成功しました", + "forkSessionFailed": "セッションのフォークに失敗しました:{error}", + "exportConversation": "会話をエクスポート", + "exportImage": "画像", + "exportMarkdown": "Markdown", + "exportHtml": "HTML", + "exportSuccess": "会話をエクスポートしました", + "exportFailed": "エクスポートに失敗しました", + "exportImageTooLong": "会話が長すぎるため、画像としてエクスポートできません", + "exportLabels": { + "untitledConversation": "無題の会話", + "agent": "エージェント", + "model": "モデル", + "status": "ステータス", + "started": "開始", + "updated": "更新", + "tokens": "トークン統計", + "duration": "所要時間", + "inputTokens": "入力", + "outputTokens": "出力", + "cacheRead": "キャッシュ読取", + "cacheWrite": "キャッシュ書込", + "user": "ユーザー", + "assistant": "アシスタント", + "system": "システム", + "toolResult": "結果", + "toolError": "エラー" + }, + "moreActions": "その他の操作" + }, + "sessionDetails": { + "menuLabel": "セッション詳細", + "noActiveSession": "アクティブなセッションがありません", + "title": "セッション詳細", + "subtitle": "セッションのメタデータとトークン使用量", + "fieldTitle": "タイトル", + "untitled": "無題の会話", + "sessionId": "セッション ID", + "externalId": "拡張 ID", + "agent": "エージェント", + "model": "モデル", + "status": "ステータス", + "gitBranch": "Git ブランチ", + "parentId": "親セッション", + "tokensHeading": "トークン使用量", + "totalTokens": "合計", + "inputTokens": "入力", + "outputTokens": "出力", + "cacheWrite": "キャッシュ書込", + "cacheRead": "キャッシュ読取", + "contextWindow": "コンテキストウィンドウ", + "duration": "所要時間", + "loadingStats": "トークン使用量を読み込み中…", + "loadFailed": "トークン使用量の読み込みに失敗しました", + "noStats": "使用量の記録なし", + "timestampsHeading": "日時", + "createdAt": "作成日時", + "updatedAt": "更新日時", + "none": "—", + "copyField": "{field}をコピー", + "copiedField": "{field}をコピーしました" + }, + "conversationCard": { + "untitledConversation": "無題の会話", + "newConversation": "新しい会話", + "rename": "名前を変更", + "status": "ステータス", + "delete": "削除", + "importLocalSessions": "ローカルセッションをインポート", + "importing": "インポート中...", + "renameConversation": "会話名を変更", + "deleteConversationTitle": "会話を削除しますか?", + "deleteConversationDescription": "\"{title}\" を削除します。この操作は元に戻せません。", + "cancel": "キャンセル", + "save": "保存", + "pin": "ピン留め", + "unpin": "ピン留めを解除", + "markCompleted": "完了にする", + "reopen": "再開する", + "expandSubsessions": "サブ会話を展開", + "collapseSubsessions": "サブ会話を折りたたむ" + }, + "search": { + "dialogTitle": "検索", + "dialogTitleWithFolder": "検索 — {name}", + "tabConversations": "会話", + "tabFiles": "ファイル", + "placeholder": "会話を検索...", + "filePlaceholder": "ファイルまたはディレクトリを検索...", + "allAgents": "すべて", + "searching": "検索中...", + "typeToSearch": "入力して会話を検索", + "typeToSearchFiles": "入力してファイルまたはディレクトリを検索", + "noResults": "結果が見つかりません。", + "untitledConversation": "無題の会話" + }, + "folderTitleBar": { + "showSidebar": "サイドバーを表示", + "hideSidebar": "サイドバーを非表示", + "toggleTerminal": "ターミナルを切り替え", + "toggleAuxPanel": "補助パネルを切り替え", + "search": "検索", + "openSettings": "設定を開く", + "backToConversations": "会話に戻る", + "withShortcut": "{label}({shortcut})" + }, + "statusBar": { + "connection": { + "connected": "接続済み", + "connecting": "接続中...", + "prompting": "応答中...", + "error": "接続エラー", + "disconnected": "未接続", + "tooltip": "{agent}:{status}", + "tooltipError": "{agent}:{error}", + "title": "エージェント接続", + "triggerAria": "エージェント接続: {status}", + "workingDir": "作業ディレクトリ", + "sessionId": "セッション ID", + "viewerNote": "他のクライアントが所有するセッションに接続しています。再接続してもこのビューが接続し直されるだけです。", + "reconnectInterrupts": "再接続するとエージェントが再起動し、進行中の処理が中断されます。", + "reconnect": "再接続", + "reconnecting": "再接続中...", + "reconnectUnavailable": "再接続できるセッションがまだありません。" + }, + "tasks": { + "title": "タスク" + }, + "alerts": { + "title": "アラート", + "empty": "アラートなし", + "details": "詳細" + }, + "stats": { + "conversations": "{count} 件の会話", + "openUsage": "セッション統計とトークン使用量を表示" + }, + "tokens": { + "contextWindowUsageAria": "コンテキストウィンドウ使用率", + "contextWindow": "コンテキストウィンドウ", + "usedMax": "使用 / 最大", + "tokenUsage": "トークン使用量", + "input": "入力", + "output": "出力", + "cacheRead": "キャッシュ読み取り", + "cacheWrite": "キャッシュ書き込み", + "total": "合計" + } + }, + "auxPanel": { + "tabs": { + "files": "ファイル", + "changes": "変更", + "commits": "コミット" + }, + "noFolderTitle": "開いているフォルダがありません", + "noFolderHint": "フォルダを開くとここに表示されます" + }, + "windowControls": { + "minimizeWindow": "ウィンドウを最小化", + "minimize": "最小化", + "maximizeWindow": "ウィンドウを最大化", + "maximize": "最大化", + "restoreWindow": "ウィンドウを元に戻す", + "restore": "元に戻す", + "closeWindow": "ウィンドウを閉じる", + "close": "閉じる" + }, + "tabs": { + "closeConversationTab": "会話タブを閉じる", + "close": "閉じる", + "closeOthers": "他を閉じる", + "splitRight": "右に分割", + "splitDown": "下に分割", + "splitAndMoveRight": "分割して右へ移動", + "splitAndMoveDown": "分割して下へ移動", + "moveToOppositeGroup": "反対側のグループへ移動", + "moveToGroup": "グループへ移動", + "groupLabel": "グループ {index}", + "changeSplitterOrientation": "分割方向を切り替え", + "unsplit": "分割を解除", + "unsplitAll": "すべての分割を解除", + "closeAll": "すべて閉じる", + "tileDisplay": "タイル表示", + "untileDisplay": "タイル解除" + }, + "fileWorkspace": { + "files": "ファイル", + "closeFileTab": "ファイルタブを閉じる", + "close": "閉じる", + "closeOthers": "他を閉じる", + "closeAll": "すべて閉じる", + "preview": "プレビュー", + "editSource": "ソースを編集", + "maximize": "最大化", + "restore": "元に戻す", + "emptyDirectory": "空のフォルダー" + }, + "terminal": { + "rename": "名前を変更", + "close": "閉じる", + "closeOthers": "他を閉じる", + "closeAll": "すべて閉じる", + "hideTerminal": "ターミナルを隠す ({shortcut})", + "openFolderFirst": "先にフォルダを開いてください" + }, + "workspaceDialog": { + "title": "フォルダーを開く", + "manageTitle": "リンク済みフォルダー", + "addTargetsTitle": "リンクするフォルダーを追加", + "pickRootDescription": "このワークスペースのメインフォルダーを選択します。", + "linksDescription": "他のフォルダーをサブディレクトリとしてリンクすると、エージェントは 1 つのワークスペースから横断的に作業できます。", + "addTargetsDescription": "フォルダーを 1 つ以上選択してください。それぞれがワークスペースのサブディレクトリになります。", + "useSystemPicker": "システムの選択画面", + "next": "次へ", + "back": "戻る", + "done": "完了", + "change": "変更", + "addFolders": "フォルダーを追加", + "addSelected": "追加", + "addSelectedCount": "{count} 件を追加", + "createCount": "{count} 件のフォルダーをリンク", + "discardPending": "破棄", + "noLinks": "リンクされたフォルダーはまだありません。", + "gitExclude": "リンクを git status に出さない", + "rename": "名前を変更", + "unlink": "リンクを解除", + "repair": "リンクを作り直す", + "saveName": "保存", + "cancelRename": "キャンセル", + "removePending": "削除", + "willAppearAs": "ワークスペースでは {name} として表示されます", + "renamedForDuplicate": "改名しました — {base} は別のリンクが使用中です", + "renamedForExistingEntry": "改名しました — このフォルダーには既に {base} があります", + "partiallyCreated": "{count} 件のフォルダーのみリンクできました", + "openFailed": "フォルダーを開けませんでした", + "previewFailed": "選択したフォルダーを確認できませんでした", + "createFailed": "フォルダーをリンクできませんでした", + "renameFailed": "名前を変更できませんでした", + "removeFailed": "リンクを解除できませんでした", + "repairFailed": "リンクを作り直せませんでした", + "status": { + "ok": "リンク済み", + "missing": "リンクがこのフォルダーから消えています", + "conflicted": "この名前は別の項目が使用しています", + "broken": "リンク先のフォルダーが存在しません" + }, + "nameIssue": { + "empty": "名前を入力してください", + "illegalChars": "/ \\ : * ? \" < > | は使用できません", + "tooLong": "名前が長すぎます", + "reserved": "この名前は Windows の予約語です", + "duplicate": "この名前は既に使われています" + }, + "rejection": { + "not_found": "このフォルダーが見つかりません", + "not_a_directory": "このパスはフォルダーではありません", + "same_as_root": "ワークスペースのフォルダー自身です", + "ancestor_of_root": "このフォルダーはワークスペースを含んでいます", + "inside_root": "既にワークスペース内にあります", + "already_linked": "既にリンク済みです", + "name_unavailable": "このフォルダーに使える名前が残っていません", + "alreadyLinkedAs": "{name} として既にリンク済みです" + } + }, + "folderNameDropdown": { + "fallbackFolderName": "フォルダ", + "openFolder": "フォルダを開く", + "cloneRepository": "リポジトリをクローン", + "projectBoot": "プロジェクトブート", + "opened": "開いているフォルダ", + "recentOpen": "最近開いたフォルダ" + }, + "fileWorkspacePanel": { + "addSelectionToChat": "選択範囲をチャットに追加", + "addToChat": "チャットに追加", + "addSelectionToChatDone": "{label} を会話に追加しました", + "addFileToChat": "ファイルをチャットに追加", + "toggleWordWrap": "折り返しの切り替え", + "addFileToChatDone": "{label} を会話に追加しました", + "viewDiff": "差分を見る", + "openFile": "ファイルを開く", + "fileCount": "{count, plural, one {# 個のファイル} other {# 個のファイル}}", + "openFileOrDiff": "右側パネルからファイルまたは差分を開いてください", + "disk": "ディスク", + "head": "HEAD", + "unsaved": "未保存", + "workingTree": "作業ツリー", + "loading": "読み込み中...", + "compareWithBranch": "{path} · {branch} と比較", + "hunkCount": "{count, plural, one {# 個のハンク} other {# 個のハンク}}", + "prev": "前", + "next": "次", + "jumpToLine": "{line} 行へ移動", + "noParsedDiffSections": "解析済みの差分セクションがありません", + "loadingEditor": "エディターを読み込み中...", + "imageZoomIn": "拡大", + "imageZoomOut": "縮小", + "imageZoomReset": "ズームをリセット", + "htmlPreviewTitle": "HTML プレビュー", + "htmlPreviewTrust": "スクリプトを有効化", + "htmlPreviewTrustHint": "このファイルのスクリプトを実行し、ネットワークアクセスを許可します。信頼できるファイルでのみ有効にしてください。", + "officePreviewTitle": "Office ドキュメントのプレビュー", + "officeFullRender": "フル描画", + "officeFullRenderHint": "Morph アニメーション・3D・数式を描画します(スライド自身のスクリプトを実行)", + "officeNotInstalled": "OfficeCLI がインストールされていません", + "officeNotInstalledHint": "設定 → Office ツール から OfficeCLI をインストールすると、Word・Excel・PowerPoint ファイルをプレビューできます。", + "officeOpenSettings": "設定を開く", + "officeWatchFailed": "ライブプレビューを開始できませんでした", + "officeWatchRetry": "再試行", + "officeServerInstallHint": "OfficeCLI はサーバーホストにインストールする必要があります。サーバーで次のコマンドを実行してから再試行してください:", + "officeRemoteDesktopUnsupported": "リモートデスクトップウィンドウではライブプレビューを利用できません。Office ファイルをプレビューするには、サーバーの Web UI でこのワークスペースを開いてください。" + }, + "branchDropdown": { + "toasts": { + "commitCodeCompleted": "コードコミットが完了しました", + "pushCodeCompleted": "コードプッシュが完了しました", + "committedFiles": "{count, plural, one {# 個のファイルをコミット} other {# 個のファイルをコミット}}", + "taskCompleted": "{label} が完了しました", + "taskFailed": "{label} が失敗しました", + "mergeNoNewCommits": "{branchName} に新しいコミットはありません", + "mergedCommits": "{count, plural, one {# 件のコミットをマージ} other {# 件のコミットをマージ}}", + "allFilesUpToDate": "すべてのファイルは最新です", + "updatedFiles": "{count, plural, one {# 個のファイルを更新} other {# 個のファイルを更新}}", + "openCommitWindowFailed": "コミットウィンドウを開けませんでした", + "openPushWindowFailed": "プッシュウィンドウを開けませんでした", + "upstreamSet": "アップストリームブランチを設定しました", + "upstreamSetAndPushed": "アップストリームブランチを設定し、{count, plural, one {# 件のコミット} other {# 件のコミット}}をプッシュしました", + "noCommitsToPush": "プッシュするコミットはありません", + "pushedCommits": "{count, plural, one {# 件のコミットをプッシュ} other {# 件のコミットをプッシュ}}", + "switchedToFolder": "{name} に切り替えました", + "switchFailed": "ブランチの切り替えに失敗しました", + "openStashWindowFailed": "stash ウィンドウを開けませんでした" + }, + "tasks": { + "newBranch": "ブランチ {name} を作成", + "newWorktree": "ワークツリー {name} を作成", + "checkoutTo": "{branchName} にチェックアウト", + "mergeBranch": "{branchName} をマージ", + "rebaseTo": "{branchName} にリベース", + "deleteRemoteBranch": "リモートブランチ {branchName} を削除", + "initGitRepo": "Git リポジトリを初期化", + "pullCode": "コードをプル", + "fetchInfo": "情報をフェッチ", + "pushCode": "コードをプッシュ", + "stashChanges": "変更を stash", + "stashPop": "stash を pop", + "deleteBranch": "ブランチ {branchName} を削除", + "removeWorktree": "{branchName} のワークツリーを削除", + "removeWorktreeAndBranch": "ワークツリーとブランチ {branchName} を削除", + "updateBranch": "ブランチ {branchName} を更新" + }, + "confirm": { + "mergeTitle": "ブランチをマージ", + "rebaseTitle": "ブランチをリベース", + "mergeDescription": "{branchName} を現在のブランチ {currentBranch} にマージしますか?", + "rebaseDescription": "現在のブランチ {currentBranch} を {branchName} にリベースしますか?", + "deleteRemoteTitle": "リモートブランチの削除", + "deleteRemoteDescription": "リモートブランチ {branchName} を削除しますか?この操作はリモートリポジトリからブランチを削除し、元に戻せません。", + "deleteTitle": "ブランチを削除", + "deleteDescription": "ブランチ {branchName} を削除しますか?この操作は元に戻せません。", + "forceDeleteTitle": "ブランチを強制削除", + "forceDeleteDescription": "ブランチ {branchName} はまだ完全にマージされていません。強制削除してもよろしいですか?この操作は元に戻せません。", + "deleteWorktreeTitle": "ワークツリーを削除", + "deleteWorktreeDescription": "{branchName} をチェックアウトしているワークツリーのディレクトリを削除しますか?ブランチとそのコミットは残ります。", + "forceDeleteWorktreeTitle": "ワークツリーを強制削除", + "forceDeleteWorktreeDescription": "{branchName} のワークツリーに未コミットまたは未追跡のファイルがあります。それでも削除しますか?その変更は復元できません。", + "deleteWorktreeAndBranchTitle": "ワークツリーとブランチを削除", + "deleteWorktreeAndBranchDescription": "{branchName} のワークツリー、ブランチ自体、そのワークスペースフォルダーを削除しますか?中のセッションはリポジトリのフォルダーに移動します。この操作は取り消せません。", + "forceDeleteWorktreeAndBranchTitle": "ワークツリーとブランチを強制削除", + "forceDeleteWorktreeAndBranchDescription": "{branchName} のワークツリーに未コミットのファイルがあるか、ブランチが完全にマージされていません。それでも両方を削除しますか?この操作は取り消せません。" + }, + "current": "現在", + "switchToBranch": "このブランチに切り替え", + "mergeBranchIntoCurrent": "{branchName} を {currentBranch} にマージ", + "rebaseCurrentToBranch": "{currentBranch} を {branchName} にリベース", + "noBranch": "ブランチなし", + "detachedHead": "切り離された HEAD({sha})", + "initGitRepo": "Git リポジトリを初期化", + "pullCode": "コードをプル", + "fetchRemoteBranches": "リモートブランチをフェッチ", + "openCommitWindow": "コードをコミット...", + "pushCode": "プッシュ...", + "pushBranch": "プッシュ", + "newBranch": "新規ブランチ...", + "newWorktree": "新規ワークツリー...", + "stashChanges": "スタッシュ...", + "stashPop": "stash を pop...", + "manageRemotes": "リモート管理...", + "localBranches": "ローカルブランチ ({count, plural, one {#} other {#}})", + "noLocalBranches": "ローカルブランチはありません", + "remoteBranches": "リモートブランチ ({count, plural, one {#} other {#}})", + "noRemoteBranches": "リモートブランチはありません", + "dialogs": { + "newBranchTitle": "新規ブランチ", + "newBranchDescription": "現在のブランチ {branch} から新しいブランチを作成", + "branchNamePlaceholder": "ブランチ名", + "newWorktreeTitle": "新規ワークツリー", + "newWorktreeDescription": "現在のブランチ {branch} から新しいワークツリーを作成", + "branchNameLabel": "ブランチ名", + "worktreePathLabel": "ワークツリーのパス", + "worktreePathPlaceholder": "ワークツリーのパス", + "manageRemotesTitle": "リモート管理", + "manageRemotesEmpty": "リモートが設定されていません", + "remoteNamePlaceholder": "リモート名", + "remoteUrlPlaceholder": "リモート URL", + "addRemote": "追加", + "savingRemotes": "保存中..." + }, + "conflict": { + "title": "マージコンフリクト", + "description": "以下のファイルにコンフリクトがあります。解決が必要です:", + "abort": "マージを中止", + "openMergeTool": "マージツールを開く", + "completeMerge": "マージ完了", + "abortSuccess": "マージが中止されました", + "completeSuccess": "マージが完了しました" + }, + "stashDialog": { + "title": "変更をスタッシュ", + "description": "現在の変更をスタッシュに保存", + "messageLabel": "メッセージ", + "messagePlaceholder": "スタッシュメッセージ(任意)", + "keepIndex": "インデックスを保持(ステージ済みの変更はそのまま)", + "cancel": "キャンセル", + "stash": "スタッシュ", + "success": "変更がスタッシュされました", + "error": "スタッシュに失敗しました" + }, + "unstashDialog": { + "title": "スタッシュを適用", + "noStashes": "スタッシュがありません", + "selectFile": "ファイルを選択して差分を表示", + "viewDiff": "差分を表示", + "original": "元", + "modified": "変更後", + "apply": "適用", + "drop": "削除", + "applySuccess": "スタッシュを適用しました", + "dropSuccess": "スタッシュを削除しました", + "confirmApply": "スタッシュ {ref} を作業ディレクトリに適用しますか?", + "cancel": "キャンセル" + }, + "deleteBranch": "ブランチを削除", + "deleteWorktree": "ワークツリーを削除", + "deleteWorktreeAndBranch": "ワークツリーとブランチを削除", + "searchPlaceholder": "ブランチと操作を検索", + "searchAriaLabel": "ブランチと操作を検索", + "branchListLabel": "ブランチと操作", + "noMatches": "一致する項目がありません" + }, + "commitDialog": { + "toasts": { + "commitCompleted": "コードコミットが完了しました", + "pushFailed": "プッシュに失敗しました", + "committedFiles": "{count, plural, one {# 個のファイルをコミット} other {# 個のファイルをコミット}}", + "addedToVcs": "VCS に追加しました", + "addToVcsFailed": "VCS への追加に失敗しました", + "fileDeleted": "ファイルを削除しました", + "deleteFailed": "削除に失敗しました", + "fileRolledBack": "ファイルをロールバックしました", + "rollbackFailed": "ロールバックに失敗しました", + "dirRolledBack": "ディレクトリをロールバックしました", + "dirDeleted": "ディレクトリを削除しました" + }, + "confirm": { + "deleteTitle": "削除の確認", + "deleteDescription": "ファイル \"{file}\" を削除しますか?この操作は元に戻せません。", + "rollbackTitle": "ロールバックの確認", + "rollbackDescription": "ファイル \"{file}\" を HEAD にロールバックしますか?未保存の変更は失われます。", + "rollbackDirDescription": "ディレクトリ「{dir}」をHEADにロールバックしますか?未保存の変更は失われます。", + "deleteDirDescription": "ディレクトリ「{dir}」を削除しますか?この操作は元に戻せません。" + }, + "actions": { + "select": "選択", + "unselect": "選択解除", + "rollback": "ロールバック", + "addToVcs": "VCS に追加" + }, + "aria": { + "selectFile": "{action}: {path}", + "unselectAllFiles": "すべてのファイルの選択を解除", + "selectAllFiles": "すべてのファイルを選択", + "unselectTracked": "追跡中の変更の選択を解除", + "selectTracked": "追跡中の変更を選択", + "unselectUntracked": "未追跡ファイルの選択を解除", + "selectUntracked": "未追跡ファイルを選択" + }, + "loading": "読み込み中...", + "selectionCount": "{selected} / {total} ファイル", + "emptyFiles": "変更されたファイルはありません", + "trackedChanges": "追跡中の変更 ({count})", + "untrackedFiles": "未追跡ファイル ({count})", + "commitMessage": "コミットメッセージ", + "commitMessagePlaceholder": "コミットメッセージを入力...", + "commitButton": "コミット ({count})", + "commitAndPushButton": "コミットしてプッシュ ({count})", + "head": "HEAD", + "workingTree": "作業ツリー", + "clickFileToDiff": "ファイル名をクリックして差分を表示", + "loadingDiff": "差分を読み込み中..." + }, + "pushWindow": { + "title": "コードをプッシュ", + "noUnpushedCommits": "未プッシュのコミットはありません", + "noRemoteConfigured": "Git リモートが設定されていません\n「リモート管理」からリモートを追加してください", + "newBranchNoPushedCommits": "新しいブランチ — プッシュしてリモート追跡ブランチを作成", + "unpushed": "未プッシュ", + "selectFileToViewDiff": "ファイルを選択して差分を表示", + "before": "変更前", + "after": "変更後", + "push": "プッシュ", + "toasts": { + "pushSuccess": "プッシュ成功", + "pushFailed": "プッシュ失敗", + "upstreamSet": "リモート追跡ブランチが設定されました", + "upstreamSetAndPushed": "リモート追跡ブランチを設定し、{count}件のコミットをプッシュしました", + "noCommitsToPush": "プッシュするコミットはありません", + "pushedCommits": "{count}件のコミットをプッシュしました" + } + }, + "gitLogTab": { + "filesTitle": "ファイル", + "expandAllFiles": "すべてのファイルを展開", + "collapseAllFiles": "すべてのファイルを折りたたむ", + "workspace": "ワークスペース", + "retry": "再試行", + "noCommitsFound": "コミットが見つかりません", + "notAGitRepoTitle": "Git リポジトリではありません", + "notAGitRepoHint": "上のブランチメニューから Git を初期化するか、既存のリポジトリを開いてください。", + "hash": "ハッシュ", + "copyHash": "ハッシュをコピー", + "copyMessage": "メッセージをコピー", + "showMore": "もっと見る", + "showLess": "折りたたむ", + "author": "作成者", + "noFileChangeDetails": "ファイル変更の詳細はありません。", + "loadingFiles": "ファイルを読み込み中…", + "branchesTitle": "ブランチ", + "loadingBranches": "ブランチを読み込み中...", + "noContainingBranches": "含まれるブランチが見つかりません。", + "newBranch": "新規ブランチ...", + "resetToHere": "ここにリセット", + "resetDisabledReasonNotCurrentBranchView": "現在のブランチ表示時のみ利用できます", + "copyFullCommitHashAria": "完全なコミットハッシュ {hash} をコピー", + "pushStatus": { + "pushed": "リモートにプッシュ済み", + "notPushed": "リモートに未プッシュ", + "unknown": "プッシュ状態不明(upstream 未設定)" + }, + "time": { + "monthsAgo": "{count, plural, one {# か月前} other {# か月前}}", + "daysAgo": "{count, plural, one {# 日前} other {# 日前}}", + "hoursAgo": "{count, plural, one {# 時間前} other {# 時間前}}", + "minsAgo": "{count, plural, one {# 分前} other {# 分前}}", + "justNow": "たった今" + }, + "toasts": { + "createdAndSwitchedNewBranch": "新しいブランチを作成して切り替えました", + "newBranchFromCommit": "{name}({shortHash} から)", + "createBranchFailed": "ブランチ作成に失敗しました", + "openPushWindowFailed": "プッシュウィンドウを開けませんでした", + "resetSuccess": "リセットが完了しました", + "resetSuccessDescription": "{branch} を {mode} で {shortHash} にリセットしました", + "resetFailed": "リセットに失敗しました" + }, + "authorFilter": { + "label": "作成者", + "searchPlaceholder": "作成者を検索", + "noAuthors": "作成者が見つかりません", + "you": "あなた", + "filterByAuthorAria": "作成者でコミットを絞り込む", + "filterByQuery": "「{query}」で絞り込む", + "clearAuthorFilterAria": "作成者フィルターをクリア", + "recent": "最近", + "matchingAuthors": "一致する作成者", + "removeFromRecent": "{name} を最近から削除" + }, + "branchSelector": { + "label": "ブランチ", + "head": "HEAD", + "headHint": "現在のブランチに追従", + "headHintWithBranch": "現在のブランチに追従({branch})", + "searchBranch": "ブランチを検索...", + "noBranches": "ブランチがありません", + "selectBranchPlaceholder": "ブランチを選択...", + "localBranches": "ローカルブランチ", + "current": "現在", + "remoteBranches": "リモートブランチ", + "refreshCommitHistory": "コミット履歴を更新", + "clearBranchFilterAria": "ブランチフィルターをクリア" + }, + "dialogs": { + "newBranchTitle": "新規ブランチ", + "newBranchDescription": "コミット {shortHash} を最新コミットとして新しいブランチを作成します。", + "branchNamePlaceholder": "ブランチ名", + "reset": { + "title": "現在のブランチをこのコミットへリセット", + "branchLabel": "ブランチ", + "targetLabel": "対象コミット", + "messageLabel": "コミットメッセージ", + "modeLabel": "リセットモード", + "confirmButton": "リセット", + "modes": { + "soft": { + "label": "--soft", + "description": "HEAD と現在のブランチ参照を対象コミットへ移動します。\nIndex と Working Tree は変更しません。\n取り消されたコミットの変更は staged のまま残ります。" + }, + "mixed": { + "label": "--mixed(デフォルト)", + "description": "HEAD を対象コミットへ移動します。\nIndex を対象コミットに戻し、Working Tree の変更は維持します。\n変更は staged から unstaged に戻ります。" + }, + "hard": { + "label": "--hard", + "description": "HEAD を移動し、Index と Working Tree を対象コミットに戻します。\n対象コミット以降の追跡中ローカル変更は破棄されます。\n破壊的な操作です。" + }, + "keep": { + "label": "--keep", + "description": "HEAD を対象コミットへ移動し、可能な限りローカル変更を保持します。\n競合しない変更のみ保持されます。\n競合がある場合は保護のため処理を中止します。" + } + } + } + }, + "moreActions": "その他の Git 操作" + }, + "gitChangesTab": { + "workspace": "ワークスペース", + "noChanges": "ローカルの変更はありません", + "notAGitRepoTitle": "Git リポジトリではありません", + "notAGitRepoHint": "上のブランチメニューから Git を初期化するか、既存のリポジトリを開いてください。", + "trackedChanges": "追跡中の変更 ({count})", + "untrackedFiles": "未追跡ファイル ({count})", + "expandTracked": "追跡中の変更を展開", + "collapseTracked": "追跡中の変更を折りたたむ", + "expandUntracked": "未追跡ファイルを展開", + "collapseUntracked": "未追跡ファイルを折りたたむ", + "showRemainingItems": "残り {count} 件を表示", + "actions": { + "commitCode": "コードをコミット", + "rollback": "ロールバック", + "addToVcs": "VCS に追加", + "delete": "削除", + "moreActions": "その他の Git 操作", + "addAllToVcs": "すべて VCS に追加", + "rollbackAll": "すべてロールバック", + "refresh": "更新" + }, + "toasts": { + "noAddableFilesInDir": "このディレクトリには VCS に追加できる変更ファイルがありません", + "noRollbackFilesInDir": "このディレクトリにはロールバックできる変更ファイルがありません", + "addedToVcs": "{name} を VCS に追加しました", + "addToVcsFailed": "VCS への追加に失敗しました", + "openCommitWindowFailed": "コミットウィンドウを開けませんでした", + "rolledBack": "{name} をロールバックしました", + "rollbackFailed": "ロールバックに失敗しました", + "addedFilesToVcs": "{count, plural, one {# 個のファイルを VCS に追加} other {# 個のファイルを VCS に追加}}", + "rolledBackFiles": "{count, plural, one {# 個のファイルをロールバック} other {# 個のファイルをロールバック}}", + "deleted": "{name} を削除しました", + "deleteFailed": "削除に失敗しました", + "deletedFiles": "{count} 個のファイルを削除しました", + "noDeletableFilesInDir": "このディレクトリには削除可能な変更ファイルがありません", + "commitFailed": "コミットに失敗しました" + }, + "directoryDialog": { + "descriptionAdd": "ディレクトリ {path} 配下で VCS に追加するファイルを選択してください。", + "descriptionRollback": "ディレクトリ {path} 配下でロールバックするファイルを選択してください。", + "descriptionDelete": "ディレクトリ {path} 配下で削除するファイルを選択してください。この操作は元に戻せません。", + "descriptionFallback": "続行するファイルを選択してください。", + "selectionCount": "{selected} / {total} を選択", + "selectAll": "すべて選択", + "unselectAll": "すべて選択解除", + "loadingCandidates": "ディレクトリの変更を読み込み中...", + "noOperableFiles": "操作可能なファイルがありません" + }, + "rollbackConfirm": { + "title": "ロールバックの確認", + "descriptionWithTarget": "{kind} \"{name}\" のローカル変更をロールバックしますか?", + "descriptionFallback": "ローカル変更をロールバックしますか?", + "kindDirectory": "ディレクトリ", + "kindFile": "ファイル" + }, + "deleteConfirm": { + "title": "削除の確認", + "descriptionWithTarget": "{kind}「{name}」を削除しますか?この操作は元に戻せません。", + "descriptionFallback": "この操作は元に戻せません。", + "kindDirectory": "ディレクトリ", + "kindFile": "ファイル" + }, + "quickCommit": { + "placeholder": "コミットメッセージ(Enter でコミット)" + } + }, + "tabContext": { + "loadingConversation": "読み込み中...", + "untitledConversation": "無題の会話", + "newConversation": "新しい会話" + }, + "fileTreeTab": { + "workspace": "ワークスペース", + "retry": "再試行", + "git": "Git", + "openInFileManager": "ファイルマネージャーで開く", + "openInFinder": "Finderで開く", + "openInExplorer": "エクスプローラーで開く", + "attachToCurrentSession": "セッションに追加", + "compareWithBranch": "ブランチと比較...", + "reloadFromDisk": "ディスクから再読み込み", + "new": "新規作成", + "newFile": "ファイル", + "newDirectory": "ディレクトリ", + "openIn": "で開く", + "openInTerminal": "ターミナルで開く", + "linkedFolder": "リンク済みフォルダー", + "copyPath": "パスをコピー", + "upload": "ファイル/フォルダをアップロード", + "download": "ファイルをダウンロード", + "downloadAsZip": "ZIP としてダウンロード", + "actions": { + "select": "選択", + "unselect": "選択解除", + "commitCode": "コードをコミット", + "rollback": "ロールバック", + "addToVcs": "VCSに追加" + }, + "aria": { + "selectPath": "{action}: {path}" + }, + "toasts": { + "openDirectoryFailed": "ディレクトリを開けませんでした", + "openBuiltinTerminalFailed": "内蔵ターミナルを開けませんでした", + "openCommitWindowFailed": "コミットウィンドウを開けませんでした", + "noAddableFilesInDir": "このディレクトリには VCS に追加できる変更ファイルがありません", + "noRollbackFilesInDir": "このディレクトリにはロールバックできる変更ファイルがありません", + "addedToVcs": "{name} を VCS に追加しました", + "addToVcsFailed": "VCS への追加に失敗しました", + "loadBranchesFailed": "ブランチの読み込みに失敗しました", + "renameFailed": "名前の変更に失敗しました", + "moveFailed": "移動に失敗しました", + "deleteFailed": "削除に失敗しました", + "rolledBack": "{name} をロールバックしました", + "rollbackFailed": "ロールバックに失敗しました", + "addedFilesToVcs": "{count, plural, one {# 件のファイルを VCS に追加しました} other {# 件のファイルを VCS に追加しました}}", + "rolledBackFiles": "{count, plural, one {# 件のファイルをロールバックしました} other {# 件のファイルをロールバックしました}}", + "savedAsCopy": "コピーとして保存しました", + "saveCopyFailed": "コピーとして保存できませんでした", + "watchStartFailed": "ファイル監視の開始に失敗しました", + "createFailed": "作成に失敗しました", + "downloadFailed": "{name} のダウンロードに失敗しました", + "downloadSaved": "{name} をダウンロードしました", + "pathCopied": "パスをコピーしました", + "copyPathFailed": "パスのコピーに失敗しました" + }, + "createDialog": { + "newFile": "新規ファイル", + "newDirectory": "新規ディレクトリ", + "description": "新しい{kind}の名前を入力してください。", + "placeholderFile": "file-name.ext", + "placeholderDirectory": "folder-name" + }, + "renameDialog": { + "renameDirectory": "ディレクトリ名を変更", + "renameFile": "ファイル名を変更", + "description": "新しい名前を入力してください(名前のみ、パスは不要)。", + "placeholderDirectory": "新しいフォルダ名", + "placeholderFile": "新しいファイル名.ext" + }, + "uploadDialog": { + "title": "ワークスペースへアップロード", + "description": "必要に応じて上書き先を変更し、ファイルやフォルダを追加してください。", + "workspaceRoot": "ワークスペースのルート", + "targetPathLabel": "アップロード先", + "targetPathHint": "実際の場所:{path}", + "dropHint": "ファイルやフォルダをここにドロップ、または下のボタンから選択", + "dropHintActive": "離してキューに追加", + "selectFiles": "ファイルを選択", + "selectFolder": "フォルダを選択", + "startUpload": "アップロード開始", + "clearQueue": "完了したものをクリア", + "removeItem": "キューから削除", + "retry": "再試行", + "dropZoneAria": "ファイルをここにドロップ、または Enter で参照", + "folderEmpty": "ドロップされたフォルダにファイルが見つかりません", + "summary": "合計:{total} · 成功:{succeeded} · 失敗:{failed}", + "status": { + "pending": "待機中", + "uploading": "アップロード中", + "success": "完了", + "error": "失敗", + "cancelled": "キャンセル済み" + } + }, + "directoryDialog": { + "descriptionAdd": "ディレクトリ {path} 配下で VCS に追加するファイルを選択してください。", + "descriptionRollback": "ディレクトリ {path} 配下でロールバックするファイルを選択してください。", + "descriptionFallback": "続行するファイルを選択してください。", + "selectionCount": "{selected} / {total} ファイルを選択", + "selectAll": "すべて選択", + "unselectAll": "すべて選択解除", + "loadingCandidates": "ディレクトリの変更を読み込み中...", + "noOperableFiles": "操作可能なファイルがありません" + }, + "compareDialog": { + "title": "ブランチと比較", + "descriptionWithTarget": "ブランチを選択し、{kind} {path} と比較します", + "descriptionFallback": "比較するブランチを選択してください。", + "kindDirectory": "ディレクトリ", + "kindFile": "ファイル", + "filterPlaceholder": "ブランチを絞り込み(例: main / origin/main)", + "singleClickHint": "ブランチをクリックすると直接比較します", + "loadingBranches": "ブランチを読み込み中...", + "recentBranches": "最近のブランチ ({count})", + "noCurrentBranch": "現在のブランチがありません", + "localBranches": "ローカルブランチ ({count})", + "remoteBranches": "リモートブランチ ({count})", + "noMatchingBranches": "一致するブランチがありません" + }, + "externalConflictDialog": { + "title": "外部ファイルの変更を検出しました", + "descriptionWithPath": "ファイル {path} がディスク上で変更されました。現在の編集は未保存です。", + "descriptionFallback": "現在のファイルがディスク上で変更されました。現在の編集は未保存です。", + "compare": "比較", + "savingCopy": "コピーを保存中...", + "saveAsCopy": "コピーとして保存", + "reload": "再読み込み" + }, + "deleteConfirm": { + "title": "削除の確認", + "descriptionWithTarget": "{kind} \"{name}\" を削除しますか?この操作は元に戻せません。", + "descriptionFallback": "この操作は元に戻せません。", + "kindDirectory": "ディレクトリ", + "kindFile": "ファイル" + }, + "rollbackConfirm": { + "title": "ロールバックの確認", + "descriptionWithTarget": "ファイル \"{name}\" のローカル変更をロールバックしますか?", + "descriptionFallback": "このファイルのローカル変更をロールバックしますか?" + }, + "terminalTitle": "ターミナル · {name}" + }, + "commandDropdown": { + "loading": "読み込み中...", + "addCommand": "コマンドを追加", + "manageCommands": "コマンドを管理...", + "runCommandTitle": "実行: {command}", + "stopCommandTitle": "停止: {command}", + "manageDialog": { + "title": "コマンド管理", + "empty": "コマンドはまだありません", + "noResults": "一致するコマンドがありません", + "searchPlaceholder": "コマンドを検索", + "newCommand": "新しいコマンド", + "nameLabel": "名前", + "commandLabel": "コマンド", + "dragSort": "ドラッグして並び替え", + "dragSortCommand": "{name} をドラッグして並び替え", + "orderFailed": "コマンドの並び順の保存に失敗しました", + "loadFailed": "コマンドの読み込みに失敗しました", + "saveFailed": "コマンドの保存に失敗しました", + "deleteFailed": "コマンドの削除に失敗しました", + "confirmDelete": { + "title": "コマンドを削除しますか?", + "message": "「{name}」を削除します。この操作は元に戻せません。" + } + } + }, + "workspaceContext": { + "confirmCloseDirtyTab": "保存せずに「{title}」を閉じますか?", + "confirmCloseOtherDirtyTabs": "未保存の変更がある他のタブを閉じますか?", + "confirmCloseAllDirtyTabs": "未保存の変更があるすべてのタブを閉じますか?", + "unableLoadContent": "内容を読み込めません。\n\n{message}", + "previewRequestTimedOut": "プレビュー要求がタイムアウトしました", + "diffRequestTimedOut": "Diff 要求がタイムアウトしました", + "branchCompareRequestTimedOut": "ブランチ比較要求がタイムアウトしました", + "commitDiffRequestTimedOut": "コミット Diff 要求がタイムアウトしました", + "saveRequestTimedOut": "保存要求がタイムアウトしました", + "reloadRequestTimedOut": "再読み込み要求がタイムアウトしました", + "noChanges": "変更はありません。", + "noDiffOutput": "Diff 出力がありません。", + "diffTitleWorkspace": "Diff · ワークスペース", + "diffDescriptionWorkingTree": "作業ツリー (HEAD)", + "diffTitleFile": "差分 · {name}", + "compareTitleFile": "比較 · {name}", + "compareTitleBranch": "比較 · {branch}", + "compareDescriptionPath": "{path} · {branch} と比較", + "compareDescriptionBranch": "{branch} と比較", + "diffTitleCommitFile": "差分 · {name} @ {hash}", + "diffTitleCommit": "差分 · {hash}", + "diffDescriptionCommitPath": "{path} · コミット {commit}", + "diffDescriptionCommit": "コミット {commit}", + "diffTitleConflictFile": "競合 · {name}", + "diffDescriptionConflict": "{path} · ディスク vs 未保存" + }, + "chat": { + "acpConnections": { + "actions": { + "openAgentsSettings": "エージェント設定を開く", + "retry": "再試行" + }, + "agentsSetupHint": "インストール管理は「設定 > エージェント」を開いてください。", + "withSetupHint": "{message}\n{hint}", + "blocked": { + "missingConfig": "現在のエージェント設定を読み取れません。", + "disabled": "{agent} はエージェント設定で無効になっています。接続前に有効化してください。", + "unavailable": "{agent} は現在のプラットフォームでは利用できません。", + "sdkMissing": "{agent} SDK がインストールされていません", + "adapterMissing": "{agent} の ACP アダプターがインストールされていません" + }, + "backendErrors": { + "initializeTimeout": "{agent} の接続ハンドシェイクがタイムアウトしました(60 秒以内に応答なし)。設定を開いてエージェントとネットワーク設定を確認してください。", + "mcpRejectedByAgent": "codeg の MCP コンパニオンを渡した際、{agent} がセッションを拒否しました: {message} このエージェントが MCP に対応していない場合は、設定で「MCP サポート」をオフにして再接続してください。", + "processExited": "{agent} プロセスが予期せず終了しました。", + "spawnFailed": "{agent} の起動に失敗しました: {message}", + "downloadFailed": "{agent} のダウンロードに失敗しました: {message}", + "sessionLoadResourceNotFound": "{agent} セッションの読み込みに失敗しました。再読み込みして再試行するか、新しい会話を開始してください。", + "sessionLoadUnavailable": "{agent} はこのセッションを復元できませんでした。セッションが終了したか、エージェントが停止した可能性があります。再読み込みして再試行するか、新しい会話を開始してください。", + "turnFailedRefusal": "{agent} がこのターンの続行を拒否しました。バックエンドまたはゲートウェイのエラーが原因の可能性があります。エージェントのログを確認してください。", + "turnFailedMaxTokens": "{agent} がこのターンの最大トークン数に達しました。", + "turnFailedMaxTurnRequests": "{agent} がこのターンで許可された最大リクエスト数に達しました。", + "turnFailedUnknown": "{agent} が不明な停止理由でターンを終了しました。", + "grokModelSwitchIncompatibleAgent": "{agent} は既存の会話ではこのモデルに切り替えられません。新しいセッションを開始して使用してください。", + "turnFailedEmpty": "{agent} は応答を生成せずにターンを終了しました。", + "turnFailedEmptyProtocol": "{agent} の出力を codeg が解析できませんでした。エージェントのバージョンがプロトコルと一致していない可能性があります。", + "turnFailedEmptyMetadata": "{agent} はこのターンでステータス更新(計画 / モード / 使用量)のみを送信し、応答はありませんでした。", + "detailsInAlerts": "ステータスバーのアラートを開き、詳細を展開するとエージェントの出力を確認できます。" + }, + "unableReadAgentConfig": "エージェント設定を読み取れません: {message}", + "connectFailedTitle": "{agent} の接続に失敗しました", + "toolFallbackTitle": "ツール", + "eventErrorTitle": "エージェントエラー", + "notificationTurnComplete": "{agent} の応答が完了しました", + "notificationError": "{agent} エラー:{message}", + "claudeApiRetry": { + "fallbackError": "authentication_failed", + "retryingWithMax": "再試行中 {attempt}/{max}", + "retryingAttempt": "再試行中({attempt} 回目)", + "retrying": "再試行中", + "nextRetryIn": "{seconds}秒後に再試行", + "line": "{error}{status} · {retry}", + "lineWithDelay": "{error}{status} · {retry}、{delay}", + "httpStatus": " (HTTP {status})" + }, + "configOptionAdjusted": "{agent} は{option}を {requested} ではなく {actual} にしました" + }, + "connectionLifecycle": { + "tasks": { + "connectingTitle": "{agent} に接続中", + "connectingDescription": "接続を確立しています", + "loadingSelectorsTitle": "{agent} のセレクターを読み込み中", + "loadingSelectorsDescription": "モードとセッション設定オプションを取得しています", + "initSessionTitle": "{agent} セッションを初期化中", + "initSessionDescription": "セッションを作成し設定を読み込んでいます" + }, + "errors": { + "connectionFailed": "接続に失敗しました", + "sendPromptFailed": "メッセージの送信に失敗しました: {error}" + } + }, + "shared": { + "attachedResources": "添付リソース", + "toolCallFailed": "ツール呼び出しに失敗しました" + }, + "messageThread": { + "emptyTitle": "まだメッセージはありません", + "emptyDescription": "会話を開始するとここにメッセージが表示されます" + }, + "chatInput": { + "connecting": "接続中...", + "agentResponding": "{agent} が応答中...", + "sendMessage": "メッセージを送信..." + }, + "messageInput": { + "askAnything": "何でも質問してください...", + "removeAttachmentAria": "{name} を削除", + "attachFiles": "ファイルを添付", + "addActions": "追加", + "quickMessages": "クイックメッセージ", + "quickMessagesEmpty": "クイックメッセージはありません", + "quickMessagesLoading": "読み込み中...", + "pasteAsPlainText": "プレーンテキストとして貼り付け", + "cut": "切り取り", + "copy": "コピー", + "selectAll": "すべて選択", + "pasteUnavailable": "クリップボードを読み取れませんでした。Ctrl/⌘V で貼り付けてください。", + "clipboardWriteFailed": "クリップボードに書き込めませんでした。キーボードショートカットをご利用ください。", + "quickMessageUntitled": "無題", + "liveFeedback": "ライブフィードバック", + "liveFeedbackDisabledHint": "エージェントの作業中に送信できます", + "dropFilesToAttach": "ファイルをドロップして添付", + "loadingSettings": "設定を読み込み中...", + "loadingMode": "モードを読み込み中...", + "modeLabel": "モード", + "toggleOn": "オン", + "toggleOff": "オフ", + "agentSettings": "エージェント設定", + "searchModel": "モデルを検索...", + "searchModelAria": "モデルを検索", + "modelListLabel": "モデル", + "noModels": "モデルが見つかりません", + "cancel": "キャンセル", + "send": "送信", + "forkAndSend": "フォークして送信", + "queueMessage": "キューに追加", + "steerIntoTurn": "現在のターンに挿入", + "steerQueuedInstead": "代わりにキューに追加しました。次のターンで送信されます。", + "steerFailed": "現在のターンに挿入できませんでした", + "steerAttachmentsUnsupported": "テキストのみ対応です。添付ファイル付きの下書きはキューをご利用ください。", + "slashCommands": "スラッシュコマンド", + "slashSearchPlaceholder": "コマンドを検索...", + "slashSearchEmpty": "一致するコマンドがありません", + "experts": "エキスパート", + "office": "日常業務", + "research": "科学研究", + "attachLocalUpload": "ローカルファイルを添付", + "attachServerFile": "サーバーファイルを添付", + "attachUploadTooLarge": "{names} は {limit}MB のアップロード上限を超えたためスキップしました。", + "attachUploadFailed": "{names} のアップロードに失敗しました。", + "attachUploadNotAFile": "{names} は通常ファイルではなく(ディレクトリまたは特殊ファイル)、スキップされました。", + "attachUploadQuotaExceeded": "サーバーのアップロード容量が不足しているため、{names} をアップロードできませんでした。", + "attachUploadInProgress": "画像はまだアップロード中です。しばらくしてからもう一度お試しください。", + "mentionEmpty": "一致する項目がありません", + "mentionLoading": "検索中…", + "mentionListLabel": "メンション", + "mentionMore": "他にも結果があります。入力して絞り込んでください", + "mentionCount": "{count, plural, other {# 件の結果}}", + "mentionGroupFile": "ファイル", + "mentionGroupAgent": "エージェント", + "mentionGroupSession": "セッション", + "mentionGroupCommit": "コミット", + "mentionGroupSkill": "スキル" + }, + "messageQueue": { + "addToQueue": "キューに追加", + "saveEdit": "保存", + "cancelEdit": "編集をキャンセル", + "editItem": "編集", + "deleteItem": "削除" + }, + "welcomeInputPanel": { + "agentsSettingsPath": "設定 > エージェント", + "autoConnectFallback": "{path} を開いてインストールを管理してください。", + "autoConnectAppend": "{message}。{path} を開いてインストールを管理してください。", + "enableAgentFirstPlaceholder": "セッション開始前に少なくとも1つのエージェントを有効化してください...", + "prepareSessionFailed": "チャットセッションを準備できませんでした。もう一度お試しください。", + "createConversationFailed": "会話を作成できませんでした。もう一度お試しください。", + "askAnythingPlaceholder": "何でも質問してください...", + "agentNotInstalled": "{agent} はインストールされていません · クリックして Agents 設定でインストール", + "agentAdapterNotInstalled": "{agent} の ACP アダプターが未インストールです(お使いの CLI とは別物)· クリックして Agents 設定でインストール" + }, + "welcomePanel": { + "greeting": "今日は何をしましょうか?", + "tips": { + "tileTabs": "会話タブを右クリックして「タイル表示」を選ぶと、複数のセッションを並べて比較できます", + "pinTab": "会話タブをダブルクリックすると固定でき、新しい会話に自動で置き換えられなくなります", + "shortcutsNewSearch": "{newConversation} で新規会話、{searchConversations} で履歴を検索できます", + "slashAtMention": "入力欄で / を入力するとスラッシュコマンド、@ を入力するとプロジェクト内のファイルを参照できます", + "pasteDropFiles": "スクリーンショットを貼り付けたり、ファイルを入力欄にドロップするだけで添付できます", + "queueMessage": "エージェントの応答中も入力を続けられ、次のメッセージはキューに入って完了後に自動送信されます", + "draftAutoSave": "未送信の下書きは会話ごとに自動保存され、戻ったときに復元されます", + "forkSend": "送信ボタンのドロップダウンで「分岐して送信」を選ぶと、現在の地点から新しいタブに分岐できます", + "exportConversation": "会話内容を右クリックすると Markdown / HTML / 画像としてエクスポートできます", + "chatChannels": "「設定 → チャットチャネル」で Telegram / Lark / WeChat を連携すれば、スマホから続けて操作できます", + "shortcutsAuxPanel": "{toggleAuxPanel} で右側パネルを開き、このセッションで変更したファイルや Git の差分を確認できます", + "shortcutsTerminalSidebar": "{toggleTerminal} で内蔵ターミナル、{toggleSidebar} でサイドバーを切り替えできます", + "customShortcuts": "すべてのショートカットは「設定 → ショートカット」で自由に変更できます", + "webService": "「設定 → Web サービス」を有効にすると、チームメンバーが同じ codeg にブラウザでアクセスできます", + "fusionMode": "ファイルや差分を開くと、会話の横に自動で表示されます。", + "quickMessages": "入力欄横の + ボタンから「クイックメッセージ」を選ぶと、保存済みのスニペットを一発で挿入できます(「設定 → クイックメッセージ」で管理)", + "experts": "+ ボタンの「エキスパートスキル」メニューから、デバッグや計画などのプリセットロールをワンクリックで読み込めます", + "taskBoard": "ToDo タスクは作業を最後まで実行します。エージェントは専用ワークツリーで作業し、あなたは差分を確認してからマージします。", + "automations": "オートメーションは保存したプロンプトをスケジュール実行します(毎晩のレビューなど)。実行ごとに専用ワークツリーを使うこともできます。", + "tokenUsage": "ステータスバーの会話数をクリックするとトークン使用量が開き、日付・エージェント・モデル・フォルダー別の内訳を確認できます。", + "mentionTargets": "@ で参照できるのはファイルだけではありません。別のエージェントをメンションしてサブタスクを任せたり、過去のセッション・コミット・スキルを参照したりできます。", + "splitGroups": "タブを右クリックして「右に分割」または「下に分割」を選ぶと、2 つの会話をそれぞれのペインで開いたままにできます。", + "worktrees": "ブランチボタンから「新規ワークツリー」を選ぶと、複数のエージェントが同じリポジトリで互いのファイルを上書きせずに並行作業できます。", + "importSessions": "すでにターミナルで実行したセッションは、フォルダーのメニューにある「ローカルセッションをインポート」で codeg に取り込めます。", + "subSessions": "エージェントが委任すると、サブセッションがサイドバーの親セッションの下に入れ子で表示されます。行を展開すれば、それぞれの作業を追えます。", + "liveFeedback": "「+」メニューのライブフィードバックを使えば、エージェントが実行中のターンに、中断させずにメモを差し込めます。", + "skillPacks": "設定 → スキルパックには、コーディング専門家・科学研究・オフィス作業のスキルがまとまっています。エージェントごとに有効化できます。", + "modelProviders": "設定 → モデルプロバイダーでは自分の API キーやエンドポイントを登録でき、モデルは入力欄からそのまま切り替えられます。", + "workspaceBackground": "設定 → 外観では、ワークスペースの背景画像・パネルの不透明度・アプリのフォントを変更できます。" + }, + "quickActions": { + "excel": "Excel ブック", + "excelDesc": "データ表・数式・グラフ", + "word": "Word 文書", + "wordDesc": "報告書・手紙・メモ", + "ppt": "プレゼン資料", + "pptDesc": "プロ仕様のスライド", + "pitchDeck": "ピッチデック", + "pitchDeckDesc": "主要指標付きの資金調達資料", + "morph": "Morph アニメ", + "morphDesc": "映画的なスライド遷移", + "morph3d": "3D Morph", + "morph3dDesc": "3D モデルとカメラワーク", + "academic": "学術論文", + "academicDesc": "引用と構成のある研究論文", + "financial": "財務モデル", + "financialDesc": "財務諸表・DCF・予測", + "dashboard": "データダッシュボード", + "dashboardDesc": "データから KPI と分析を生成", + "prompts": { + "excel": "次の要件で Excel ブックを作成してください:\n\n[データ・表・数式・グラフをここに記述]", + "word": "次の要件で Word 文書を作成してください:\n\n[文書の内容・構成・書式をここに記述]", + "ppt": "次の要件で PowerPoint プレゼンを作成してください:\n\n[スライド・内容・デザインをここに記述]", + "pitchDeck": "次の要件で資金調達のピッチデックを作成してください:\n\n[会社・調達ラウンド・主要指標をここに記述]", + "morph": "Morph トランジションアニメーション付きのプレゼンを作成してください:\n\n[プレゼンのテーマと希望する視覚効果をここに記述]", + "morph3d": "GLB モデルとカメラワーク付きの 3D Morph プレゼンを作成してください:\n\n[テーマと 3D ビジュアルの構想をここに記述]", + "academic": "次の要件で Word の学術論文を執筆してください:\n\n[研究テーマ・手法・主要な発見をここに記述]", + "financial": "次の要件で Excel の財務モデルを作成してください:\n\n[財務諸表・予測・分析をここに記述]", + "dashboard": "次の要件で Excel のデータダッシュボードを作成してください:\n\n[データソース・KPI・グラフをここに記述]", + "scientific-brainstorming": "研究の方向性をブレインストーミングしてください。分野横断のつながりを探り、前提を問い直し、有望な空白を見つけます。検討している領域:", + "hypothesis-generation": "これらの観察を検証可能な仮説に変換してください。明確な予測、妥当なメカニズム、検証実験を示します。私の観察:", + "experimental-design": "データ収集前に厳密な実験を設計してください。デザイン、無作為化、対照、交絡の回避方法を含めます。研究したいこと:", + "statistical-power": "必要なサンプルサイズを求めてください。私のデザインについて検出力分析(効果量・有意水準・検出力)を進めます。詳細:", + "statistical-analysis": "このデータを適切に分析してください。適切な検定の選択、前提の確認、効果量の報告、結果の記述を行います。データと問い:", + "exploratory-data-analysis": "私のデータファイルを探索的に分析してください。構造・品質・注目すべきパターンを要約し、次のステップを提案します。ファイル:", + "scientific-visualization": "出版品質の図を作成してください。明確なレイアウト、誠実なエラーバー、色覚に配慮した配色、ジャーナル書式を用います。示したい内容:", + "scientific-critical-thinking": "この研究や主張を批判的に評価してください。エビデンスの質を評価し、バイアスや交絡を見抜き、結論を吟味します。対象:", + "paper-lookup": "学術データベースから関連論文とオープンアクセス全文を探し、再利用できる引用も示してください。探しているもの:" + }, + "paper-lookup": "論文検索", + "paper-lookupDesc": "10 の学術 API(PubMed、arXiv、OpenAlex、Crossref…)で論文・引用・オープンアクセス全文を検索。", + "scientific-critical-thinking": "批判的思考", + "scientific-critical-thinkingDesc": "科学的主張とエビデンスの質を評価。バイアスや交絡を見抜き、GRADE やバイアスリスク枠組みを適用。", + "scientific-visualization": "科学的可視化", + "scientific-visualizationDesc": "出版品質の図。マルチパネル配置、有意差注釈、ジャーナル固有の書式に対応。", + "exploratory-data-analysis": "探索的データ解析", + "exploratory-data-analysisDesc": "200 以上の形式の科学データファイルを自動探索し、品質指標とレポートを生成。", + "statistical-analysis": "統計解析", + "statistical-analysisDesc": "ガイド付き統計解析。検定の選択、前提確認、効果量、APA 形式の報告に対応。", + "statistical-power": "統計的検出力", + "statistical-powerDesc": "サンプルサイズと検出力の分析。必要な被験者数、最小検出可能効果、検出力曲線を算出。", + "experimental-design": "実験計画", + "experimental-designDesc": "データ収集前に厳密な研究を設計。無作為化・ブロック化・対照・要因/DOE 配置に対応。", + "hypothesis-generation": "仮説生成", + "hypothesis-generationDesc": "観察を検証可能な仮説に変換し、予測・メカニズム・検証実験を提示します。", + "scientific-brainstorming": "科学的ブレインストーミング", + "scientific-brainstormingDesc": "自由な研究アイデア出し。分野横断のつながりを探り、前提を問い直し、研究の空白を見つけます。", + "tabs": { + "office": "日常業務", + "coding": "コード開発", + "research": "科学研究" + }, + "coding": { + "brainstormingDesc": "着手前に意図と要件を整理", + "debuggingDesc": "修正の前に根本原因を特定", + "writingSkillsDesc": "再利用可能なスキルを作成・編集・検証" + }, + "notEnabled": { + "title": "「{skill}」スキルは {agent} でまだ有効になっていません", + "description": "設定で有効にすると、ここで使用できます。", + "action": "有効にする", + "hint": "スキルが無効です" + }, + "scrollPrev": "前のスキルを表示", + "scrollNext": "次のスキルを表示" + } + }, + "agentSelector": { + "noEnabledAgents": "有効なエージェントがありません", + "openAgentsSettings": "エージェント設定を開く", + "notInstalled": "未インストール", + "moreAgents": "他のエージェント({count})" + }, + "subAgentOverlay": { + "title": "サブエージェント", + "collapsedSummary": "サブエージェント {count}", + "collapseAria": "サブエージェントを折りたたむ" + }, + "agentPlanOverlay": { + "title": "エージェントプラン", + "collapsePlanAria": "プランを折りたたむ", + "collapsedSummary": "計画 {completed}/{total}", + "status": { + "completed": "完了", + "inProgress": "進行中", + "pending": "保留", + "unknown": "不明" + }, + "priority": { + "high": "高", + "medium": "中", + "low": "低", + "unknown": "不明" + } + }, + "permissionDialog": { + "subtitle": "エージェントがこのターンを続行するための許可を要求しています。", + "queuedCount": "他 {count} 件待機中", + "kindFallbackTool": "ツール", + "command": "コマンド", + "cwd": "作業ディレクトリ: {cwd}", + "filesSummary": "ファイル: {count}", + "moreFiles": "+{count} 件の追加ファイル", + "plan": "計画", + "allowedActions": "許可されたアクション", + "targetMode": "対象モード: {mode}", + "optionGrants": "各選択肢が許可する内容", + "changeScopeSession": "このセッション", + "changeScopeProcess": "この実行", + "changeScopeUser": "ユーザー設定に保存", + "changeScopeProject": "プロジェクト設定に保存", + "changeScopeProjectLocal": "ローカルプロジェクト設定に保存", + "changeScopePersistent": "永続的に保存" + }, + "questionDialog": { + "title": "エージェントが質問しています", + "placeholder": "回答を入力...", + "send": "送信" + }, + "messageBranch": { + "previousBranchAria": "前のブランチ", + "nextBranchAria": "次のブランチ", + "pageOf": "{current} / {total}" + }, + "terminal": { + "title": "ターミナル", + "running": "実行中" + }, + "reasoning": { + "thinking": "考え中…", + "thoughtForFewSeconds": "考えた", + "thoughtForSeconds": "考えた" + }, + "linkSafety": { + "errorCannotOpen": "ローカルファイルを開けません", + "errorNoWorkspace": "現在アクティブなワークスペースフォルダがありません。", + "errorFailedOpen": "ローカルファイルを開けませんでした", + "errorFailedLink": "リンクを開けませんでした", + "errorUnsupportedLinkProtocol": "このリンクプロトコルはサポートされていません。" + }, + "fileActions": { + "openInFinder": "Finderで開く", + "openInExplorer": "エクスプローラーで開く", + "openInFileManager": "ファイルマネージャーで開く", + "copyRelativePath": "相対パスをコピー", + "copyAbsolutePath": "絶対パスをコピー", + "pathCopied": "パスをコピーしました", + "copyPathFailed": "パスのコピーに失敗しました", + "openFailed": "ローカルファイルを開けませんでした" + }, + "messageList": { + "attachedResources": "添付リソース", + "loading": "読み込み中...", + "loadEarlier": "以前のメッセージを読み込む", + "loadingEarlier": "以前のメッセージを読み込み中…", + "error": "エラー: {message}", + "errorTitle": "セッションの読み込みに失敗しました", + "errorActionReload": "再読み込み", + "errorActionNewSession": "新規会話", + "emptyConversation": "この会話にはメッセージがありません。", + "systemMessage": "システムメッセージ", + "copyMessage": "コピー", + "copied": "コピー済み", + "downloadImage": "画像をダウンロード", + "downloadFailed": "ダウンロードに失敗しました: {message}", + "imageGeneration": "画像生成", + "imageGenerationPending": "画像を生成中…", + "imageGenerationFailed": "画像生成に失敗しました", + "model": "モデル", + "tokenStats": "トークン使用量", + "tokenInput": "入力", + "tokenOutput": "出力", + "tokenCacheRead": "キャッシュ読取", + "tokenCacheWrite": "キャッシュ書込", + "duration": "所要時間", + "completedAt": "完了時刻", + "jumpToPreviousUserMessage": "前のユーザーメッセージへ", + "showMore": "もっと見る", + "showLess": "折りたたむ" + }, + "liveTurnStats": { + "thinking": "考え中...", + "streaming": "ストリーミング中", + "elapsedHours": "{value}時間", + "elapsedMinutes": "{value}分", + "elapsedSeconds": "{value}秒", + "outputSpeedAria": "推定出力速度", + "outputSpeedTooltip": "推定出力速度(テキスト + 思考)" + }, + "jsonTree": { + "viewRaw": "生の JSON を表示", + "viewTree": "ツリー表示", + "fields": "{count} 個のフィールド", + "items": "{count} 件" + }, + "tool": { + "parameters": "パラメーター", + "error": "エラー", + "result": "結果", + "status": { + "approvalRequested": "承認待ち", + "approvalResponded": "応答済み", + "inputAvailable": "実行中", + "inputStreaming": "保留中", + "outputAvailable": "完了", + "outputDenied": "拒否", + "outputError": "エラー" + } + }, + "toolCallBlock": { + "tool": "ツール", + "error": "エラー", + "result": "結果" + }, + "delegation": { + "subAgentRunning": "サブエージェント実行中…", + "noDetail": "No detail available yet.", + "unknownAgent": "サブエージェント", + "openDetail": "会話を表示", + "detailTitle": "サブエージェントの会話", + "detailDescription": "委任されたサブエージェントの会話を読み取り専用で表示します。", + "waitForResult": "タスク {task} の実行結果を待機中", + "waitForResultNoTask": "タスクの実行結果を待機中", + "cancelTask": "タスク {task} をキャンセル中", + "cancelTaskNoTask": "タスクをキャンセル中", + "resultPageOf": "{current} / {total}", + "prevResult": "前の結果", + "nextResult": "次の結果", + "noResultText": "このチェックでは結果がありません", + "status": { + "starting": "起動中", + "running": "実行中", + "checked": "確認済み", + "waiting": "承認待ち", + "ok": "完了", + "err": { + "default": "失敗", + "delegation_disabled": "無効", + "depth_limit": "深さ上限", + "invalid_agent_type": "不正なエージェント", + "spawn_failed": "起動失敗", + "send_failed": "送信失敗", + "timeout": "タイムアウト", + "canceled": "キャンセル済み", + "child_refusal": "サブエージェント拒否", + "child_max_tokens": "サブエージェント: トークン上限", + "child_max_turn_requests": "サブエージェント: 要求上限", + "child_empty": "サブエージェント応答なし", + "child_unknown": "サブエージェント: エラー", + "unknown": "不明なタスク" + } + } + }, + "contentParts": { + "showingTailOutput": "パフォーマンスのため、ストリーミング中は末尾出力を表示しています。", + "result": "結果", + "unknown": "不明", + "inputTruncated": "入力が切り詰められました — diff が不完全な可能性があります。", + "replaceAll": "すべて置換", + "filesCount": "ファイル: {count}", + "update": "更新", + "moreFiles": "+{count} 件の追加ファイル", + "timeoutMs": "タイムアウト: {timeout}ms", + "backgroundTrue": "バックグラウンド: true", + "scriptToolCalls": "{count} 個のツールを呼び出し", + "offset": "オフセット: {offset}", + "limit": "上限: {limit}", + "pages": "ページ: {pages}", + "mode": "モード: {mode}", + "cell": "セル: {cell}", + "shellSession": "セッション {id}", + "pathLabel": "パス:", + "globLabel": "Glob パターン:", + "typeLabel": "タイプ:", + "outputLabel": "出力:", + "caseInsensitive": "大文字小文字を区別しない", + "multiline": "複数行", + "promptLabel": "プロンプト", + "subjectLabel": "件名", + "taskLabel": "タスク", + "nameLabel": "名前:", + "agentPromptLabel": "プロンプト", + "agentModelLabel": "モデル", + "agentRunning": "実行中...", + "agentLiveTranscript": "ライブアクティビティ", + "agentProgressTools": "{count} 件のツール呼び出し", + "agentProgressTurns": "{count} ターン", + "agentProgressContext": "コンテキスト {pct}%", + "agentSessionAction": "サブエージェントのセッションを表示", + "agentSessionTitle": "サブエージェントのセッション", + "agentSessionLoading": "サブエージェントの記録を読み込んでいます…", + "agentSessionEmpty": "サブエージェントはまだ何も書き込んでいません。", + "agentFallbackTitle": "サブエージェント起動中…", + "agentCodexLaunchOnly": "起動しました。Codex はこのサブエージェントの進捗をこれ以上通知しません。結果はこの会話のメッセージとして届きます。", + "agentStatsBash": "コマンド", + "agentStatsRead": "ファイル読取", + "agentStatsSearch": "検索", + "agentStatsEdit": "編集", + "agentStatsOther": "その他", + "goal": { + "title": "目標:", + "titleWithStatus": "目標 {status}", + "objective": "目標", + "statusLabel": "ステータス", + "tokensUsed": "使用 tokens", + "budget": "予算", + "remaining": "残り", + "elapsed": "経過時間", + "tokens": "tokens", + "pause": "一時停止", + "clear": "クリア", + "status": { + "active": "実行中", + "paused": "一時停止", + "blocked": "ブロック中", + "usageLimited": "使用量制限", + "budgetLimited": "予算制限", + "complete": "完了", + "limited": "上限到達" + } + }, + "field": { + "file": "ファイル", + "notebook": "ノートブック", + "command": "コマンド", + "old": "旧", + "new": "新", + "pattern": "パターン", + "path": "パス", + "query": "クエリ", + "url": "URL:", + "description": "説明", + "content": "内容", + "source": "ソース", + "prompt": "プロンプト", + "subject": "件名", + "taskId": "タスク ID", + "status": "状態", + "skill": "Skill", + "args": "引数", + "offset": "オフセット", + "limit": "上限", + "glob": "Glob パターン", + "type": "タイプ", + "output": "出力", + "replaceAll": "すべて置換", + "language": "言語", + "timeout": "タイムアウト", + "background": "バックグラウンド", + "agentType": "エージェント種別", + "library": "ライブラリ", + "libraryId": "ライブラリ ID" + }, + "title": { + "edit": "編集", + "command": "コマンド", + "script": "スクリプト", + "waitCommand": "待機 {command}", + "waitCell": "セッション {id} を待機", + "terminateCommand": "停止 {command}", + "terminateCell": "セッション {id} を停止", + "stdinChars": "入力 {chars}", + "todoWrite": "TodoWrite(タスク更新)", + "read": "読み取り", + "write": "書き込み", + "notebookEdit": "NotebookEdit(ノート編集)", + "editFiles": "編集 ({count} 件のファイル)", + "editWithTarget": "{target} を編集", + "readWithTarget": "{target} を読み取り", + "writeWithTarget": "{target} に書き込み", + "notebookEditWithTarget": "NotebookEdit({target})", + "globWithPattern": "Glob パターン {pattern}", + "listFilesWithPath": "ファイル一覧 {path}", + "grepWithPattern": "Grep パターン {pattern}", + "taskCreateWithSubject": "タスク作成: {subject}", + "taskUpdateWithStatus": "タスク更新 #{id} -> {status}", + "taskUpdate": "タスク更新 #{id}", + "webFetchWithUrl": "WebFetch({url})", + "webSearchWithQuery": "WebSearch({query})", + "todosProgress": "タスク ({done}/{total})", + "skillWithName": "Skill: {name}", + "genericWithContext": "{tool}({context})" + }, + "search": { + "noMatches": "一致する結果なし", + "matchSummary": "{matches} 件の一致 · {files} 件のファイル", + "fileSummary": "{files} 件のファイル", + "moreResults": "他に {count} 件の結果は非表示" + }, + "toolGroup": { + "search": "{count} 件を検索", + "command": "{count} 件のコマンドを実行", + "read": "ファイルを {count} 回読み取り", + "memory": "{count} 件の記憶を呼び出し", + "edit": "ファイルを {count} 回編集", + "fetch": "{count} 件のリソースを取得", + "think": "{count} 回思考", + "todo": "{count} 件の TODO を更新", + "task": "{count} 件のタスクを実行", + "other": "{count} 件のツールを使用", + "errorSuffix": "{count} 件失敗", + "joiner": " · " + }, + "planMode": { + "entered": "計画モードを開始", + "planLabel": "計画", + "reviewApproved": "計画を承認 — 実行します", + "reviewKept": "プランモードを維持", + "reviewPending": "計画の判断待ち", + "submitted": "計画を送信しました", + "switched": "モードを切り替え" + }, + "backgroundTask": { + "title": "バックグラウンドタスク", + "titleWithId": "バックグラウンドタスク · {id}", + "running": "実行中", + "completed": "完了", + "failed": "失敗", + "stopped": "停止しました", + "exitCode": "終了コード {code}", + "polledTimes": "{count} 回ポーリング", + "runningInBackground": "バックグラウンド", + "launchNote": "バックグラウンドで実行中 · {id}" + }, + "codexScript": { + "outputMissing": "codex がスクリプト出力を切り詰めた際にこのコマンドの区切り行が失われたため、出力を割り当てられませんでした。", + "sharedWith": "この範囲には {commands} の出力も含まれます — 区切り行が codex により切り捨てられました。", + "truncated": "切り詰め済み" + } + }, + "messageNav": { + "title": "メッセージナビ", + "collapse": "メッセージナビを閉じる", + "collapsedSummary": "メッセージ {count}", + "fileCount": "{count, plural, one {# 個のファイル} other {# 個のファイル}}", + "remove": "削除", + "noDiffDataAvailable": "{filePath} の差分データがありません" + }, + "replyArtifacts": { + "title": "変更されたファイル", + "fileCount": "{count, plural, one {# 個のファイル} other {# 個のファイル}}", + "newFilesTitle": "新規ファイル", + "revealInFolder": "ファイルマネージャーで表示", + "openFile": "{filePath} を開く", + "openInEditor": "エディタで開く", + "remove": "削除", + "noDiffDataAvailable": "{filePath} の差分データがありません" + }, + "askQuestion": { + "title": "エージェントが選択を求めています", + "subtitle": "回答したら送信してください。いつでもスキップできます", + "recommended": "推奨", + "other": "その他", + "otherPlaceholder": "回答を入力…", + "singleSelect": "単一選択", + "multiSelect": "複数選択", + "skip": "スキップ", + "next": "次へ", + "submit": "送信", + "submitError": "送信できませんでした。もう一度お試しください。" + }, + "planApproval": { + "title": "エージェントが計画を提示しました — 確認してください", + "emptyPlan": "エージェントは計画を作成しませんでした。承認して実装を開始するか、変更を依頼してください。", + "approve": "承認して開始", + "requestChanges": "変更を依頼", + "abandon": "破棄", + "feedbackPlaceholder": "何を変更しますか?", + "sendChanges": "送信", + "cancel": "キャンセル", + "submitError": "送信できませんでした。もう一度お試しください。" + }, + "feedbackCheckResult": { + "count": "フィードバック {count} 件", + "expand": "すべてのフィードバックを表示", + "collapse": "折りたたむ", + "errorTitle": "フィードバックの確認に失敗しました" + }, + "askQuestionResult": { + "title": "質問", + "answeredLabel": "質問と回答:", + "awaiting": "回答をお待ちしています…", + "declined": "この質問をスキップしました — エージェントが独自に判断して進めました。", + "noSelection": "選択なし" + }, + "configStale": { + "agentConfigTitle": "エージェント設定が更新されました", + "modelProviderTitle": "モデルプロバイダーが更新されました", + "description": "このセッションは以前の設定のままです。再接続すると適用されます(会話履歴は保持されます)。", + "reconnect": "再接続して適用", + "reconnecting": "再接続中…", + "reconnectDisabledDuringTurn": "現在のターンが完了すると再接続できます", + "dismiss": "閉じる", + "reconnectFailed": "セッションの再接続に失敗しました", + "applied": "新しい設定を適用しました" + }, + "piProjectTrust": { + "title": "このプロジェクトには pi リソースが含まれています", + "description": "pi はリポジトリ自身の .pi ファイルを読み込んでいません。確認して判断してください。", + "descriptionExecutable": "リポジトリには pi 拡張機能が含まれており、起動時にコードを実行します。pi はまだ読み込んでいません。判断する前に確認してください。", + "review": "確認…", + "dismiss": "閉じる", + "dialogTitle": "このプロジェクトの pi リソースを信頼しますか?", + "dialogDescription": "フォルダーを信頼した場合にのみ、pi はリポジトリ自身の .pi ファイルを読み込みます。このリポジトリの内容を信頼できる場合にのみ許可してください。", + "executionWarning": "拡張機能はコードです。このフォルダーを信頼すると、メッセージを送信する前に、リポジトリの拡張機能が pi の起動時にあなたの権限で実行されます。", + "scopeNote": "この判断は pi の trust.json に保存され、その配下のすべてのフォルダーに適用されます。ターミナルで自分で pi を実行するときにも使われます。後から「設定 → エージェント → Pi」で変更できます。", + "trust": "プロジェクトを信頼", + "decline": "読み込まないままにする", + "disabledDuringTurn": "現在のターンが終了すると利用できます", + "trustedToast": "プロジェクトを信頼しました — pi がリソースを読み込むよう再接続しました", + "declinedToast": "プロジェクトのリソースは読み込まれません", + "saveFailed": "プロジェクトの信頼設定の保存に失敗しました", + "grantTitle": "このプロジェクトは既に信頼されています", + "grantDescription": "pi はこのリポジトリ自身の .pi ファイルを読み込みます。何が許可されるか確認してください。", + "grantInheritedDescription": "親フォルダーが信頼されているため、pi はこのリポジトリ自身の .pi ファイルを読み込みます。何が許可されるか確認してください。", + "grantDialogTitle": "このプロジェクトの pi リソースは信頼されています", + "grantDialogDescription": "pi はこのリポジトリ自身の .pi ファイルの読み込みを許可されています。以前のバージョンの codeg はフォルダーを開いた時点で自動的に許可していたため、確認を求められていない可能性があります。", + "grantExecutionWarning": "拡張機能はコードです。リポジトリの拡張機能は、メッセージを送信する前に pi の起動時にあなたの権限で実行されます。", + "inheritedFrom": "信頼の由来", + "revoke": "信頼を取り消す", + "keepTrusted": "信頼を維持", + "revokedToast": "信頼を取り消しました — 再接続したため pi はプロジェクトのリソースを読み込みません", + "trustedNoReconnect": "プロジェクトを信頼しました — pi の次回起動時に適用されます", + "revokedNoReconnect": "信頼を取り消しました — pi の次回起動時に適用されます" + }, + "collabAgent": { + "title": "サブエージェント", + "errorTitle": "サブエージェントのタスクが失敗しました", + "statesLabel": "サブエージェント", + "statusRunning": "実行中", + "statusCompleted": "完了", + "statusFailed": "失敗", + "statusPending": "起動中", + "statusInterrupted": "中断", + "statusClosed": "終了", + "statusNotFound": "見つかりません", + "opSpawn": "サブエージェントを起動中", + "opWait": "サブエージェントの結果を取得中", + "opClose": "サブエージェントを終了中", + "opResume": "サブエージェントを再開中" + }, + "contextCompaction": { + "compacting": "コンテキストを圧縮しています…", + "compacted": "コンテキストを圧縮しました", + "compactedTokens": "コンテキストを圧縮 · {before} → {after} トークン", + "failed": "コンテキストの圧縮に失敗しました" + }, + "sessionFailure": { + "category": { + "connection": "接続の問題", + "access": "アクセスの問題", + "limit": "上限に到達", + "request": "リクエスト拒否", + "service": "サービスの問題", + "unknown": "セッションの問題" + }, + "action": { + "retry": "再試行", + "login": "サインイン", + "newSession": "新しいセッション" + }, + "recovered": "回復済み", + "retryUnavailable": "再送信できるメッセージがありません。", + "toggleDetails": "詳細の切り替え" + }, + "backgroundTasks": { + "running": "{count} 件のバックグラウンドタスクを実行中", + "settling": "バックグラウンド結果を同期中…", + "settledFallback": "バックグラウンドタスクが終了しました({status})", + "cardRunning": "バックグラウンドで実行中", + "cardLaunchedPending": "バックグラウンドタスクを開始しました", + "cardCompleted": "バックグラウンドタスクが完了しました", + "cardFinishedWithStatus": "バックグラウンドタスクが終了しました({status})", + "cardResultPending": "結果はまだ返っていません" + }, + "proposedPlan": { + "title": "提案された計画", + "planning": "計画中…" + } + }, + "diffPreview": { + "mode": { + "added": "追加", + "deleted": "削除", + "renamed": "名前変更", + "modified": "変更" + }, + "hunkLabel": "ハンク {index}", + "loadingHunk": "Hunk を読み込み中...", + "noDiffData": "Diff データがありません", + "showRemainingLines": "残り {count} 行を表示" + }, + "conversationContextBar": { + "folderTitle": "作業フォルダ", + "branchTitle": "作業ブランチ", + "searchFolder": "Search folder...", + "searchBranch": "Search branch...", + "noFolders": "No folders", + "noBranches": "No branches", + "noBranch": "(no branch)", + "chatModeLabel": "チャットモード", + "commit": "Commit", + "push": "Push", + "merge": "Merge", + "toasts": { + "folderChanged": "Switched to {name}", + "openFolderFailed": "Failed to open folder", + "switchedToChatMode": "チャットモードに切り替えました", + "openStashFailed": "Failed to open stash window", + "openMergeFailed": "Failed to open merge window" + } + }, + "cloneDialog": { + "title": "リポジトリをクローン", + "repositoryUrl": "リポジトリ URL", + "repositoryUrlPlaceholder": "https://github.com/user/repo.git", + "directory": "ディレクトリ", + "directoryPlaceholder": "保存先ディレクトリを選択...", + "browseDirectory": "ディレクトリを参照", + "cancel": "キャンセル", + "clone": "クローン", + "clonePath": "クローンパス: {path}" + }, + "toasts": { + "cloneFailed": "リポジトリのクローンに失敗しました" + } + }, + "ProjectBoot": { + "title": "プロジェクトブート", + "tabs": { + "shadcn": "shadcn", + "hyperframes": "HyperFrames" + }, + "hyperframes": { + "title": "HyperFrames 動画プロジェクト", + "subtitle": "HTML から動画を生成するプロジェクトを作成します。ワークスペースのエージェントがそれを記述・レンダリングできます。", + "resolution": "解像度", + "skillsTitle": "エージェントスキル", + "skillsDesc": "選択したエージェント向けに HyperFrames スキルをグローバル(シンボリックリンク)でインストールし、動画の作成・レンダリングを可能にします。", + "recheck": "再チェック", + "installedBadge": "インストール済み", + "skillsInstall": "スキルをインストール / 更新", + "skillsInstalling": "スキルをインストール中…", + "skillsInstalled": "HyperFrames スキルをインストールしました", + "skillsInstallFailed": "HyperFrames スキルのインストールに失敗しました" + }, + "config": { + "base": "ベース", + "style": "スタイル", + "baseColor": "ベースカラー", + "theme": "テーマ", + "chartColor": "チャートカラー", + "iconLibrary": "アイコンライブラリ", + "font": "フォント", + "fontHeading": "見出しフォント", + "menuAccent": "メニューアクセント", + "menuColor": "メニューカラー", + "radius": "角丸", + "template": "テンプレート", + "createProject": "プロジェクトを作成", + "sectionStyle": "スタイル", + "sectionColors": "カラー", + "sectionTypography": "タイポグラフィ", + "sectionInterface": "インターフェース" + }, + "preview": { + "loading": "プレビューを読み込み中..." + }, + "createDialog": { + "title": "プロジェクトを作成", + "projectName": "プロジェクト名", + "projectNamePlaceholder": "my-app", + "frameworkTemplate": "フレームワークテンプレート", + "packageManager": "パッケージマネージャー", + "saveDirectory": "保存先ディレクトリ", + "saveDirectoryPlaceholder": "ディレクトリを選択...", + "browseDirectory": "参照", + "projectPath": "プロジェクトの作成先:{path}", + "advancedOptions": "詳細オプション", + "base": "基盤ライブラリ", + "enableRtl": "RTL サポートを有効にする", + "enableRtlDescription": "右から左に書く言語(アラビア語、ヘブライ語など)のレイアウトサポートを有効にする", + "pmChecking": "確認中...", + "pmNotInstalled": "未インストール", + "cancel": "キャンセル", + "create": "作成", + "creating": "プロジェクトを作成中..." + }, + "toasts": { + "createFailed": "プロジェクトの作成に失敗しました", + "createSuccess": "プロジェクトが正常に作成されました", + "openWorkspaceFailed": "プロジェクトは作成されましたが、ワークスペースで開けませんでした" + }, + "errors": { + "directoryExists": "対象ディレクトリは既に存在します", + "commandFailed": "プロジェクト作成コマンドが失敗しました。" + } + }, + "WebServiceSettings": { + "addressSwitchHint": "切り替えても、ここに表示され開くアドレスが変わるだけです。サービスはすべてのインターフェースで待ち受けており、どのアドレスからもアクセスできます。", + "sectionTitle": "Webサービス", + "sectionDescription": "有効にするとブラウザからCodegにリモートアクセスできます", + "port": "ポート", + "status": "ステータス", + "autoStart": "自動起動", + "autoStartHint": "Codeg の起動時に Web サービスを開始", + "running": "実行中", + "stopped": "停止中", + "processing": "処理中...", + "start": "開始", + "stop": "停止", + "startFailed": "開始に失敗しました", + "stopFailed": "停止に失敗しました", + "saveConfigFailed": "Webサービス設定の保存に失敗しました", + "open": "開く", + "hide": "非表示", + "show": "表示", + "copy": "コピー", + "qrcode": "QRコード", + "qrcodeTitle": "スキャンして開く", + "qrcodeHint": "スマートフォンでスキャンして、ブラウザで Codeg を開きます", + "addressLabel": "アクセスアドレス", + "tokenLabel": "アクセストークン", + "tokenHint": "Webクライアントの初回アクセス時にこのトークンを入力してください", + "tokenPlaceholder": "空欄の場合は自動生成", + "regenerate": "再生成", + "stalePortOccupiedTitle": "ポート {port} は他のプロセスに使用されています", + "stalePortUnknownTitle": "ポート {port} の状態を確認できません", + "stalePortHint": "ポートが解放されるまで Codeg はバインドできません。上のポートを変更するか、占有しているプロセスを終了してください。", + "errors": { + "alreadyRunning": "Web サービスはすでに起動しています", + "invalidAddress": "ホストまたはポートの形式が無効です", + "portInUse": "ポート {port} はすでに使用中です。そのポートを使用しているプロセスを終了するか、別のポートを指定してください", + "permissionDenied": "権限が不足しています。1024 以上のポートを使用するか、より高い権限で実行してください", + "addressUnavailable": "このアドレスはこの端末では利用できません", + "bindFailed": "アドレスのバインドに失敗しました" + } + }, + "DirectoryBrowser": { + "title": "ディレクトリを参照", + "pathPlaceholder": "ディレクトリパスを入力...", + "goHome": "ホームディレクトリへ", + "navigateUp": "親ディレクトリへ", + "select": "選択", + "cancel": "キャンセル", + "loading": "読み込み中...", + "emptyDirectory": "このディレクトリは空です", + "errorLoadingDir": "ディレクトリの読み込みに失敗しました", + "permissionDenied": "アクセス権がありません" + }, + "ChatChannelSettings": { + "loading": "読み込み中...", + "sectionTitle": "チャットチャンネル", + "sectionDescription": "IM ボットを設定して、イベント通知やコーディング活動の照会を行います。", + "addChannel": "チャンネルを追加", + "noChannels": "チャットチャンネルはまだ設定されていません。", + "channelName": "名前", + "channelNamePlaceholder": "My Telegram Bot", + "channelType": "チャンネルタイプ", + "lark": "Lark(飛書)", + "weixin": "WeChat", + "dailyReport": "デイリーレポート", + "dailyReportTime": "送信時刻", + "nameRequired": "チャンネル名を入力してください。", + "tokenRequired": "トークンを入力してください。", + "chatIdRequired": "Chat ID を入力してください。", + "topicMode": "トピックグループモード", + "topicModeHint": "Telegram forum topics を個別の Codeg セッションとしてルーティングします。Bot は forum supergroup に参加し、topics を管理できる必要があります。", + "loadFailed": "チャンネルの読み込みに失敗しました。", + "saveFailed": "保存に失敗しました。", + "connectSuccess": "チャンネルに接続しました。", + "connectFailed": "接続に失敗しました", + "disconnectSuccess": "チャンネルを切断しました。", + "disconnectFailed": "切断に失敗しました。", + "testSuccess": "接続テストに合格しました。", + "testFailed": "接続テストに失敗しました", + "deleteSuccess": "チャンネルを削除しました。", + "deleteFailed": "チャンネルの削除に失敗しました。", + "deleteConfirmTitle": "チャンネルを削除", + "deleteConfirmMessage": "このチャンネルとメッセージログを完全に削除します。よろしいですか?", + "cancel": "キャンセル", + "delete": "削除", + "create": "作成", + "save": "保存", + "channelListTitle": "設定済みチャンネル", + "channelListDescription": "有効なチャンネルはサービス起動時に自動接続されます。", + "editChannel": "チャンネルを編集", + "editSuccess": "チャンネルを更新しました。", + "tokenPlaceholderKeep": "空欄で現在の値を維持", + "weixinScanTitle": "QRコードをスキャン", + "weixinScanDescription": "WeChatを開いてQRコードをスキャンして接続してください。", + "weixinQrcodeExpired": "QRコードの有効期限が切れました。", + "weixinRefreshQrcode": "更新", + "weixinWaitingScan": "スキャン待ち...", + "weixinPollError": "接続が不安定です。再試行中...", + "weixinReconnectNotice": "iLink プロトコルの制限により、再接続のたびにまずボットにメッセージを送信しないとイベントトリガーが有効になりません。", + "connect": "接続", + "disconnect": "切断", + "test": "接続テスト", + "tabs": { + "channels": "チャンネル", + "commands": "コマンド", + "events": "イベント", + "other": "その他" + }, + "commands": { + "title": "組み込みコマンド", + "description": "チャットチャンネルで使用可能な Bot コマンド。グループチャットではメッセージを処理するために @Bot が必要です。", + "prefixLabel": "コマンドプレフィックス", + "prefixDescription": "Bot コマンドを起動するプレフィックス、1-3 文字の英数字以外の文字(デフォルト /)。", + "prefixSaved": "コマンドプレフィックスを保存しました。", + "prefixSaveFailed": "コマンドプレフィックスの保存に失敗しました。", + "prefixInvalid": "プレフィックスは1-3文字の英数字以外の文字である必要があります。", + "save": "保存", + "folderDesc": "作業フォルダを選択", + "agentDesc": "AIエージェントを選択", + "taskDesc": "セッションを作成してタスクを実行", + "sessionsDesc": "フォルダ内のアクティブなセッション一覧", + "resumeDesc": "最近の会話 / セッションを再開", + "cancelDesc": "現在のタスクをキャンセル", + "approveDesc": "エージェントの権限リクエストを承認", + "denyDesc": "エージェントの権限リクエストを拒否", + "searchDesc": "キーワードで会話を検索", + "todayDesc": "本日のアクティビティ概要", + "statusDesc": "チャンネル接続状態", + "helpDesc": "ヘルプを表示" + }, + "events": { + "title": "イベント通知", + "description": "イベントを有効にすると、トリガーされた際にチャンネルにプッシュされます。", + "turnComplete": "ターン完了", + "turnCompleteDesc": "エージェントのターンが終了した時", + "error": "エージェントエラー", + "errorDesc": "エージェントがエラーに遭遇した時", + "permissionRequest": "権限リクエスト", + "permissionRequestDesc": "エージェントが操作の権限を要求した時", + "questionRequest": "エージェントからの質問", + "questionRequestDesc": "エージェントが質問したとき", + "userPromptSent": "ユーザーメッセージ", + "userPromptSentDesc": "メッセージを送信したとき(通知に本文が含まれます)", + "saved": "イベントフィルターを更新しました。", + "saveFailed": "イベントフィルターの保存に失敗しました。", + "loadFailed": "設定の読み込みに失敗しました。", + "retry": "再試行", + "webhooksTitle": "Webhook", + "webhooksDescription": "有効なイベントの発生時に、1 つ以上の URL へ JSON を POST します。上のイベントフィルターは Webhook にも適用されます。", + "webhookUrlPlaceholder": "https://example.com/webhook", + "addWebhook": "Webhook を追加", + "removeWebhook": "Webhook を削除", + "webhookSave": "保存", + "webhooksSaved": "Webhook を保存しました。", + "webhooksSaveFailed": "Webhook の保存に失敗しました。", + "webhookInvalidUrl": "有効な http(s) URL を入力してください。", + "docsTitle": "リクエスト形式", + "docsMethod": "メソッド", + "docsContentType": "Content-Type", + "docsNote": "有効な各イベントはすべての URL に配信されます。Webhook はデバウンスされず、上のイベントフィルターが適用されます。", + "editWebhook": "Webhook を編集", + "enableWebhook": "Webhook を有効化", + "webhookDuplicate": "この URL は既に設定されています。", + "cancel": "キャンセル", + "webhooksEmpty": "Webhook はまだ設定されていません。", + "deleteWebhookTitle": "Webhook を削除", + "deleteWebhookMessage": "この Webhook を削除しますか?このURLにイベントは配信されなくなります。", + "delete": "削除" + }, + "language": { + "title": "メッセージ言語", + "description": "イベント通知、コマンド応答、日次レポートをチャットチャンネルに送信する際に使用する言語。", + "saved": "メッセージ言語を保存しました。", + "saveFailed": "メッセージ言語の保存に失敗しました。", + "en": "英語", + "zh-cn": "簡体字中国語", + "zh-tw": "繁体字中国語", + "ja": "日本語", + "ko": "韓国語", + "es": "スペイン語", + "de": "ドイツ語", + "fr": "フランス語", + "pt": "ポルトガル語", + "ar": "アラビア語" + } + }, + "ModelProviderSettings": { + "sectionTitle": "モデルプロバイダー", + "sectionDescription": "エージェントのAPIプロバイダー認証情報を管理します。", + "filterAll": "すべて", + "providerListTitle": "設定済みプロバイダー", + "addProvider": "プロバイダーを追加", + "editProvider": "プロバイダーを編集", + "noProviders": "モデルプロバイダーはまだ設定されていません。", + "providerName": "名前", + "providerNamePlaceholder": "例: OpenAI、Anthropic", + "apiUrl": "API URL", + "apiUrlPlaceholder": "https://api.openai.com/v1", + "apiKey": "APIキー", + "apiKeyPlaceholder": "sk-...", + "apiKeyKeepCurrent": "空欄のまま現在の値を維持", + "agentTypes": "エージェントタイプ", + "agentTypesRequired": "少なくとも1つのエージェントタイプを選択してください。", + "agentType": "エージェントタイプ", + "agentTypeRequired": "エージェントタイプを選択してください。", + "agentTypeImmutableHint": "エージェントタイプは作成後に変更できません。", + "model": "モデル", + "modelPlaceholderCodex": "gpt-5.6-sol / gpt-5.5", + "modelPlaceholderGemini": "gemini-3-pro-preview", + "claudeMainModel": "メインモデル", + "claudeReasoningModel": "推論モデル(思考)", + "claudeHaikuDefaultModel": "デフォルトの Haiku モデル", + "claudeSonnetDefaultModel": "デフォルトの Sonnet モデル", + "claudeOpusDefaultModel": "デフォルトの Opus モデル", + "claudeCustomModelOption": "カスタムモデル ID", + "claudeCustomModelOptionName": "カスタムモデル名", + "claudeCustomModelOptionDescription": "カスタムモデルの説明", + "claudeCustomModelOptionHint": "Claude のモデル選択メニューにカスタム項目を1つ追加します(例: カスタムゲートウェイ/プロキシ経由のモデル)。名前と説明は任意の表示用設定です。", + "nameRequired": "プロバイダー名は必須です。", + "apiUrlRequired": "API URLは必須です。", + "apiKeyRequired": "APIキーは必須です。", + "loadFailed": "プロバイダーの読み込みに失敗しました。", + "saveFailed": "変更の保存に失敗しました。", + "createSuccess": "プロバイダーを作成しました。", + "editSuccess": "プロバイダーを更新しました。", + "deleteSuccess": "プロバイダーを削除しました。", + "deleteConfirmTitle": "プロバイダーを削除", + "deleteConfirmMessage": "プロバイダー「{name}」を完全に削除しますか?", + "deleteBlockedByAgent": "{agents} がこのプロバイダーを使用中です。削除する前にリンクを解除してください。", + "cancel": "キャンセル", + "delete": "削除", + "create": "作成", + "save": "保存", + "affectedRunningSessions": "{count} 件の実行中セッションは再接続すると変更が適用されます" + }, + "SkillMatrix": { + "loading": "読み込み中…", + "searchPlaceholder": "名前・ID・説明で検索", + "empty": "表示する項目がありません。", + "emptySearch": "現在の検索に一致する項目がありません。", + "skillColumn": "スキル", + "selectAll": "表示中をすべて選択", + "selectSkill": "{name} を選択", + "everything": { + "label": "一括", + "enable": "すべて有効化(表示中)", + "disable": "すべて無効化(表示中)" + }, + "columnMenu": { + "enableAll": "すべてのスキルを有効化", + "disableAll": "すべてのスキルを無効化" + }, + "rowMenu": { + "label": "{name} の一括操作", + "enableAll": "すべてのエージェントで有効化", + "disableAll": "すべてのエージェントで無効化" + }, + "bulk": { + "selected": "{count} 件選択中", + "targetAll": "すべてのエージェント", + "targetSome": "{count} 個のエージェント", + "enable": "有効化", + "disable": "無効化", + "clear": "クリア" + }, + "confirm": { + "disableTitle": "これらのリンクを無効化しますか?", + "disableBody": "codeg が管理する {count} 件のスキルリンクを削除します。カスタムディレクトリを占有しているスキルはそのまま残ります。いつでも再び有効化できます。", + "cancel": "キャンセル", + "confirm": "無効化" + }, + "toasts": { + "loadFailed": "スキルの状態の読み込みに失敗しました", + "applyFailed": "変更の適用に失敗しました", + "enabled": "{count} 件のリンクを有効化しました", + "disabled": "{count} 件のリンクを無効化しました", + "enabledPartial": "{ok} 件を有効化、{failed} 件が失敗しました", + "disabledPartial": "{ok} 件を無効化、{failed} 件が失敗しました" + }, + "detail": { + "enableForAgents": "エージェントで有効化", + "preview": "SKILL.md プレビュー", + "loadingContent": "コンテンツを読み込み中…" + }, + "copyModeHint": "コピー済み(リンクではありません)— 更新後は最新版を取得するため再度有効化してください" + }, + "ExpertsSettings": { + "title": "エキスパートスキル", + "description": "AI コーディングエージェント向けに、厳選され実戦で検証されたスキルワークフローを有効にします。各エキスパートは superpowers プロジェクトの独立したスキルで、codeg が中央コピーを管理し、選択したエージェントにリンクします。", + "loading": "エキスパートを読み込み中…", + "loadingContent": "コンテンツを読み込み中…", + "emptyExperts": "利用可能なエキスパートがありません。アプリケーションログを確認してください。", + "emptySelection": "エキスパートを選択して内容を表示し、有効化を管理します。", + "emptySearch": "現在の検索に一致するエキスパートはありません。", + "searchPlaceholder": "名前、ID、または説明でエキスパートを検索", + "enableForAgents": "エージェントで有効化", + "noAgents": "ACP エージェントが検出されません。", + "copyModeWarning": "コピー済み(リンクなし)。codeg 更新後に最新版を取得するには再度有効化してください。", + "previewTitle": "SKILL.md プレビュー", + "categories": { + "discovery": "発見と設計", + "planning": "計画", + "execution": "実行", + "quality": "品質とテスト", + "debugging": "デバッグ", + "review": "レビューと統合", + "meta": "メタ" + }, + "states": { + "not_linked": "未有効", + "linked_to_codeg": "有効", + "linked_elsewhere": "ブロック — 別のリンクが存在", + "blocked_by_real_directory": "ブロック — カスタムスキルがこの名前を占有", + "broken": "壊れたリンク" + }, + "badges": { + "userModified": "ユーザーにより変更" + }, + "actions": { + "openCentralDir": "中央フォルダを開く", + "refresh": "更新" + }, + "toasts": { + "loadFailed": "エキスパート詳細の読み込みに失敗しました", + "enabled": "このエージェントでエキスパートを有効化しました", + "disabled": "このエージェントでエキスパートを無効化しました", + "enableFailed": "エキスパートの有効化に失敗しました", + "disableFailed": "エキスパートの無効化に失敗しました", + "openFolderFailed": "フォルダを開けませんでした" + } + }, + "ScienceSettings": { + "title": "科学研究スキル", + "description": "AI コーディングエージェント向けに厳選した科学研究スキル(仮説生成・実験計画・統計・可視化・批判的評価・文献検索)を有効化します。codeg が中央コピーを管理し、選んだエージェントに各スキルをリンクします。", + "loading": "科学研究スキルを読み込み中…", + "emptySkills": "利用可能な科学研究スキルがありません。アプリのログを確認してください。", + "searchPlaceholder": "名前・ID・説明で科学研究スキルを検索", + "categories": { + "ideation": "アイデア出し", + "design": "研究デザイン", + "analysis": "分析", + "visualization": "可視化", + "evaluation": "評価", + "literature": "文献" + }, + "states": { + "not_linked": "未有効", + "linked_to_codeg": "有効", + "linked_elsewhere": "ブロック — 別のリンクが存在", + "blocked_by_real_directory": "ブロック — カスタムスキルがこの名前を占有", + "broken": "壊れたリンク" + }, + "badges": { + "userModified": "ユーザーにより変更", + "needsKey": "APIキーが必要", + "needsSetup": "環境構築が必要な場合あり" + }, + "actions": { + "openCentralDir": "中央フォルダを開く", + "refresh": "更新" + }, + "toasts": { + "openFolderFailed": "フォルダを開けませんでした" + } + }, + "OfficeToolsSettings": { + "title": "Office ツール", + "description": "OfficeCLI スキルを管理し、Excel、Word、PowerPoint ファイルを作成します。OfficeCLI をインストールし、スキルを同期して、エージェントごとに有効化できます。", + "loadingContent": "コンテンツを読み込み中…", + "emptySkills": "スキルがありません。OfficeCLI をインストールしてスキルを同期してください。", + "emptySelection": "スキルを選択して内容を確認し、有効化を管理します。", + "emptySearch": "検索に一致するスキルがありません。", + "searchPlaceholder": "名前、ID、説明でスキルを検索", + "enableForAgents": "エージェントに対して有効化", + "noAgents": "ACP エージェントが検出されませんでした。", + "installFirst": "スキルを有効にするには、まず OfficeCLI をインストールしてください。", + "syncFirst": "コンテンツを読み込むには、まずスキルを同期してください。", + "noContent": "コンテンツがありません。", + "copyModeWarning": "コピー済み(リンクなし)。最新版を取得するには再同期してください。", + "previewTitle": "SKILL.md プレビュー", + "detection": { + "installed": "インストール済み", + "notInstalled": "未インストール", + "notRunnable": "インストール済みですが実行できません", + "installHint": "OfficeCLI をインストールして、AI エージェントにオフィスドキュメント生成スキルを有効にします。", + "install": "インストール", + "uninstall": "アンインストール", + "syncSkills": "スキルを同期" + }, + "categories": { + "general": "一般", + "presentations": "プレゼンテーション", + "documents": "ドキュメント", + "spreadsheets": "スプレッドシート" + }, + "states": { + "not_linked": "無効", + "linked_to_codeg": "有効", + "linked_elsewhere": "ブロック — 他のリンクが存在します", + "blocked_by_real_directory": "ブロック — カスタムスキルがこの名前を使用しています", + "broken": "リンク切れ" + }, + "badges": { + "notSynced": "未同期" + }, + "actions": { + "refresh": "更新" + }, + "toasts": { + "loadFailed": "スキル詳細の読み込みに失敗", + "enabled": "このエージェントでスキルを有効化しました", + "disabled": "このエージェントでスキルを無効化しました", + "enableFailed": "スキルの有効化に失敗", + "disableFailed": "スキルの無効化に失敗", + "installSuccess": "OfficeCLI のインストールに成功", + "installFailed": "OfficeCLI のインストールに失敗", + "uninstallSuccess": "OfficeCLI をアンインストールしました", + "uninstallFailed": "OfficeCLI のアンインストールに失敗", + "syncSuccess": "{synced} 個のスキルを同期しました", + "syncPartial": "{synced} 個同期、{errors} 個失敗", + "syncFailed": "スキルの同期に失敗" + }, + "autoPreviewLabel": "プレビューを自動で開く", + "autoPreviewHint": "エージェントが Word、Excel、PowerPoint ファイルを作成または編集したときに、ライブプレビューを自動で開きます。" + }, + "SkillPacksSettings": { + "title": "スキルパック", + "description": "codeg が一元管理し、各 AI エージェントにリンクする厳選スキルの束です——コーディング専門家、科学研究、オフィス文書ツール。下でエージェントごとに有効化できます。", + "tabs": { + "experts": "エキスパート", + "science": "科学研究", + "office": "Officeツール", + "custom": "カスタム" + }, + "actions": { + "openCentralDir": "中央フォルダを開く", + "refresh": "更新" + }, + "toasts": { + "openFolderFailed": "フォルダを開けませんでした" + } + }, + "QuickMessagesSettings": { + "title": "クイックメッセージ", + "description": "再利用可能なメッセージスニペットを管理します。ドラッグして並べ替えできます。", + "loading": "クイックメッセージを読み込み中…", + "emptyList": "クイックメッセージはまだありません。「新規」をクリックして作成してください。", + "emptySelection": "編集するクイックメッセージを選択してください。", + "searchPlaceholder": "タイトルまたは内容で検索", + "untitled": "無題", + "actions": { + "new": "新規", + "save": "保存", + "delete": "削除", + "dragSort": "ドラッグして並べ替え", + "dragSortMessage": "クイックメッセージを並べ替え: {name}" + }, + "fields": { + "title": "タイトル", + "titlePlaceholder": "このメッセージに短いタイトルを付けてください", + "content": "内容", + "contentPlaceholder": "ここにメッセージ内容を入力してください" + }, + "confirmDelete": { + "title": "クイックメッセージを削除しますか?", + "message": "「{name}」を完全に削除します。よろしいですか?", + "cancel": "キャンセル", + "confirm": "削除" + }, + "toasts": { + "loadFailed": "クイックメッセージの読み込みに失敗しました", + "createFailed": "クイックメッセージの作成に失敗しました", + "saveFailed": "クイックメッセージの保存に失敗しました", + "deleteFailed": "クイックメッセージの削除に失敗しました", + "saveOrderFailed": "順序の保存に失敗しました", + "created": "クイックメッセージを作成しました", + "saved": "クイックメッセージを保存しました", + "deleted": "クイックメッセージを削除しました" + } + }, + "Pet": { + "badge": { + "running": "実行中 {count} 件", + "waiting": "承認待ち {count} 件", + "error": "エラー {count} 件" + }, + "panel": { + "title": "アクティブなセッション", + "empty": "アクティブなセッションはありません", + "emptyHint": "実行中、または対応が必要なセッションがここに表示されます。", + "statusRunning": "実行中", + "statusWaiting": "待機中", + "statusError": "エラー", + "subAgentOf": "サブエージェント" + }, + "menu": { + "scale": "拡大率", + "openManager": "ペット管理", + "close": "閉じる" + }, + "loadError": "ペットの読み込みに失敗", + "missingPetIdParam": "ペットが選択されていません", + "summonButton": "ペット", + "manager": { + "title": "デスクトップペット", + "description": "Codex 互換のスプライトシートで動く、デスクトップ常駐のお供。", + "addPet": "ペットを追加", + "importFromCodex": "Codex から取り込む", + "noPets": "ペットがありません。追加するか、Codex から取り込んでください。", + "setActive": "アクティブにする", + "active": "アクティブ", + "edit": "編集", + "delete": "削除", + "deleteConfirm": "ペット「{name}」を削除しますか?ディスクからも削除されます。", + "summon": "ペットウィンドウを呼び出す", + "openCodexHelp": "Codex ペットは ~/.codex/pets/ 配下に配置する必要があります。見つかりません。", + "specRequirement": "スプライトシートは幅 1536 ピクセル、高さは 208 ピクセルの倍数(例: 1872 または 2288)で、透過 PNG / WebP 形式である必要があります。", + "form": { + "id": "ペット ID", + "idHelp": "英小文字、数字、'-'、'_' のみ。最大 64 文字。", + "displayName": "表示名", + "description": "説明 (任意)", + "spritesheet": "スプライトシート", + "chooseFile": "ファイルを選択", + "replaceFile": "スプライトを差し替え", + "saveCreate": "ペットを追加", + "saveUpdate": "変更を保存", + "cancel": "キャンセル" + }, + "errors": { + "missingId": "ペット ID は必須です", + "missingName": "表示名は必須です", + "missingSpritesheet": "スプライトシートは必須です", + "addFailed": "ペットの追加に失敗しました", + "updateFailed": "ペットの更新に失敗しました", + "deleteFailed": "ペットの削除に失敗しました", + "loadFailed": "ペット一覧の取得に失敗しました", + "setActiveFailed": "アクティブなペットの設定に失敗しました", + "summonFailed": "ペットウィンドウの召喚に失敗しました" + } + }, + "import": { + "title": "Codex から取り込む", + "subtitle": "~/.codex/pets/ 配下に見つかったペット一覧。", + "selectAll": "すべて選択", + "alreadyImported": "取り込み済み", + "renameOnConflict": "ID が重複した場合は -imported を付与", + "import": "選択したものを取り込む", + "noneFound": "取り込み可能な Codex ペットが見つかりません。", + "imported": "取り込みに成功", + "failed": "取り込みに失敗", + "close": "閉じる" + }, + "marketplace": { + "openMarketplace": "ペットマーケット", + "title": "ペットマーケット", + "search": "ペットを検索", + "kindFilter": { + "all": "すべて", + "object": "オブジェクト", + "animal": "動物", + "person": "人物", + "creature": "生き物" + }, + "sortFilter": { + "latest": "新着", + "popular": "人気", + "views": "閲覧数順" + }, + "refresh": "更新", + "install": "インストール", + "installing": "インストール中", + "reinstall": "再インストール", + "reinstallConfirm": "ローカルのペット \"{name}\" を上書きしますか?既存のデータは置き換えられます。", + "cancel": "キャンセル", + "stats": { + "views": "閲覧", + "downloads": "ダウンロード", + "likes": "いいね" + }, + "actions": { + "idle": "待機", + "running_right": "右走り", + "running_left": "左走り", + "waving": "手振り", + "jumping": "ジャンプ", + "failed": "失敗", + "waiting": "待ち", + "running": "実行", + "review": "レビュー" + }, + "page": "{page} / {total} ページ", + "prev": "前へ", + "next": "次へ", + "empty": "条件に一致するペットがありません。", + "successInstalled": "\"{name}\" をインストールしました", + "errors": { + "loadFailed": "マーケットの読み込みに失敗しました", + "installFailed": "インストールに失敗しました", + "alreadyInstalled": "そのペットは既に存在します" + } + } + }, + "RemoteWorkspace": { + "openRemoteWorkspace": "Open remote workspace", + "manage": "Manage remote workspace", + "manageTitle": "Remote Workspace connections", + "empty": "No remote connections", + "searchPlaceholder": "Search remote workspaces", + "orderFailed": "Failed to save remote workspace order", + "dragSort": "Drag to sort", + "dragSortConnection": "Drag to sort {name}", + "newConnection": "New connection", + "loading": "Loading", + "loadingConnection": "Loading remote connection", + "name": "Name", + "baseUrl": "Service URL", + "token": "Access token", + "save": "Save", + "delete": "Delete", + "confirmDelete": { + "title": "Delete remote connection?", + "message": "This will remove \"{name}\" from this device. This action cannot be undone.", + "cancel": "Cancel", + "confirm": "Delete" + }, + "saved": "Remote connection saved.", + "deleted": "Remote connection deleted.", + "loadFailed": "Failed to load remote connections", + "saveFailed": "Failed to save remote connection", + "deleteFailed": "Failed to delete remote connection", + "openFailed": "Failed to open remote workspace", + "connectionLoadFailed": "Failed to load remote connection: {message}", + "connectionExpired": "Remote connection \"{name}\" is expired. Update its token and reload this window." + }, + "ServerFileBrowser": { + "title": "サーバーファイルを選択", + "pathPlaceholder": "ディレクトリパスを入力...", + "goHome": "ホームディレクトリへ", + "navigateUp": "上の階層へ", + "select": "選択", + "cancel": "キャンセル", + "loading": "読み込み中...", + "emptyDirectory": "このディレクトリは空です", + "errorLoadingDir": "ディレクトリの読み込みに失敗しました", + "selectedCount": "{count} 件選択中" + }, + "BackupSettings": { + "title": "バックアップと復元", + "description": "codeg データのポータブルなバックアップを書き出すか、バックアップから復元します。", + "tabs": { + "backup": "バックアップ", + "restore": "復元" + }, + "export": { + "includeExternal": "会話内容を含める", + "includeExternalHint": "各 CLI の会話履歴(Claude、Codex、Gemini など)も保存します。サイズが増えます。", + "passphrase": "パスフレーズ(任意)", + "passphrasePlaceholder": "空欄の場合は暗号化されません", + "passphraseConfirm": "パスフレーズの確認", + "passphraseMismatch": "パスフレーズが一致しません。", + "noPassphraseWarning": "このバックアップには秘密情報(API キー、トークン)が平文で含まれます。安全に保管してください。", + "passphraseLossWarning": "このパスフレーズで暗号化します。紛失するとバックアップは復元できません。", + "button": "バックアップを書き出す", + "inProgress": "バックアップを作成中…", + "success": "バックアップを作成しました。", + "started": "バックアップのダウンロードを開始しました。" + }, + "restore": { + "selectFile": "バックアップファイルを選択", + "passphrasePrompt": "このバックアップは暗号化されています。パスフレーズを入力してください。", + "unlock": "ロック解除", + "preview": { + "title": "バックアップの詳細", + "encrypted": "暗号化済み", + "compatible": "互換あり", + "incompatible": "互換なし", + "createdAt": "作成日時: {value}", + "appVersion": "アプリのバージョン: {value}", + "incompatibleHint": "このバックアップは新しいバージョンの codeg で作成されており、復元できません。" + }, + "replaceWarning": "復元すると現在の codeg データ(データベースとアップロード)がすべて置き換えられます。現在のデータは先にスナップショットされ、復旧できます。", + "keyringNote": "デスクトップの GitHub/チャットのトークンは OS のキーチェーンに保存され、含まれません。復元後に再入力してください。", + "button": "復元", + "staging": "復元を準備中…", + "staged": "復元を準備しました。再起動します…", + "restarting": "復元を準備しました。サーバーを再起動します…", + "restartTimeout": "サーバーが時間内に復帰しませんでした。起動後にページを再読み込みしてください。", + "externalSideLocation": "会話履歴を {path} に復元しました", + "confirmTitle": "すべてのデータを置き換えますか?", + "confirmBody": "現在の codeg データベースとアップロードをバックアップで置き換えてから再起動します。現在のデータは先にスナップショットされます。", + "cancel": "キャンセル", + "confirmAction": "置き換えて再起動", + "external": { + "title": "会話内容", + "hint": "このバックアップには CLI の会話履歴が含まれます。復元先を選択してください。", + "modeSkip": "復元しない", + "modeSide": "安全な別フォルダーに復元", + "modeOriginal": "CLI の元の場所に復元", + "forceOverwrite": "既存のファイルを上書き", + "forceOverwriteHint": "CLI フォルダー内の既存ファイルを置き換えます。", + "scanning": "競合を確認中…", + "noConflicts": "既存のファイルは上書きされません。", + "conflictCount": "既存のファイル {count} 件が影響を受けます。", + "conflictSkipNote": "上書きを有効にしない限り、既存ファイルは保持(スキップ)されます。" + }, + "restartFailed": "復元は準備できましたが、サーバーを再起動できませんでした。手動で再起動して復元を適用してください。" + }, + "remoteUnsupported": "バックアップと復元は codeg を実行しているマシンのデータを対象とします。現在リモートワークスペースに接続中です。そのサーバー上で直接バックアップを管理してください。" + }, + "backup": { + "restore": { + "error": { + "badPassphrase": "パスフレーズが正しくないか、バックアップが破損しています。", + "corrupted": "バックアップアーカイブが破損しています。", + "unknownFormat": "このファイルは認識可能な codeg バックアップではありません。", + "newerVersion": "このバックアップは codeg {backupVersion} で作成されており、現在のバージョン({appVersion})より新しいです。", + "alreadyPending": "適用待ちの復元が既にあります。先に再起動して適用してから、新しい復元を準備してください。" + } + }, + "error": { + "diskSpace": "操作を完了するためのディスク容量が足りません。", + "cancelled": "操作はキャンセルされました。" + } + }, + "WebConnection": { + "disconnectedTitle": "接続が切断されました", + "reconnectingDescription": "サーバーへの再接続を試みています。通常は数秒で自動的に復旧します。", + "reconnectNow": "今すぐ再接続", + "sessionExpiredTitle": "セッションの有効期限が切れました", + "sessionExpiredDescription": "セッションが無効になりました。続行するには再度サインインしてください。", + "goToLogin": "ログインへ移動" + }, + "LiveFeedback": { + "placeholder": "{agent} の作業中にメモを送る…", + "agentFallback": "エージェント", + "ariaLabel": "ライブフィードバックのメモ", + "dialogTitle": "ライブフィードバック", + "dialogDescription": "エージェントの作業中にメモを送ります。現在のステップを中断せず、次の確認時に読み取られます。", + "dialogDescriptionInstant": "作業中のエージェントにメモを送ります。メモは現在のターンに即座に挿入され、エージェントはすぐに確認できます。", + "channelDowngraded": "このセッションでは即時挿入を利用できません。メモは保存され、エージェントが次回チェックする際に読み取られます。", + "send": "送信", + "cancel": "キャンセル", + "pending": "待機中", + "delivered": "受領済み", + "turnEndedUnread": "エージェントはフィードバックを読む前にターンを終了しました。", + "sendAsMessage": "新しいメッセージとして送信", + "dismiss": "閉じる", + "turnEndedResent": "ターンが終了したため、新しいメッセージとして送信しました。", + "turnEnded": "ターンはすでに終了しています。", + "submitFailed": "メモを送信できませんでした" + }, + "AgentToolsSettings": { + "title": "会話内ツール", + "description": "codeg が会話の中でエージェントに追加で渡すツールです。エージェントの起動時に注入されるため、変更は以降に起動したエージェントに適用されます。", + "feedbackLabel": "ライブフィードバック", + "feedbackHint": "作業中のエージェントにメモや修正を送れます。即時ステアリングに対応したエージェントでは、メモは実行中のターンへ即座に挿入されます。それ以外のエージェントはフィードバック確認ツールで読み取りますが、通常はプロンプトで言及した場合にのみ確認します。例:「ライブフィードバックを定期的に確認して」とメッセージに追加してください。", + "questionLabel": "ユーザーに質問", + "questionHint": "エージェントが処理を一時停止し、会話の入力欄の上に表示される選択式の質問をできるようにします。回答(またはスキップ)するまでエージェントは待機します。", + "sessionInfoLabel": "セッション情報の取得", + "sessionInfoHint": "メッセージ内で参照したセッション(セッションバッジ)をエージェントが照会し、タイトル・エージェント・ステータス・ワークスペース・トークン使用量・最近のメッセージを読み取れるようにします。", + "automationsLabel": "自動化を作成", + "automationsHint": "会話をスケジュール実行の自動化として保存します。既定はオフ — 自動化はその後、自分でエージェントを起動します。", + "workTasksLabel": "ToDo タスクを作成", + "workTasksHint": "会話から ToDo ボードにカードを追加します。既定はオフ — アプリの状態を書き換えます。", + "save": "保存", + "saving": "保存中…", + "saved": "ツール設定を保存しました", + "saveFailed": "ツール設定の保存に失敗しました", + "loadFailed": "読み込みに失敗しました: {detail}" + }, + "NotificationSoundSettings": { + "title": "通知音", + "description": "エージェントのイベント発生時に短い通知音を鳴らします。対象はチャットチャンネルに送られるものと同じイベントで、この設定はこの端末にのみ適用されます。", + "enableHint": "既定ではオフです。通知音はこのブラウザまたはアプリのワークスペースウィンドウでのみ再生されます。", + "volume": "音量", + "preview": "試聴", + "previewEvent": "「{event}」の通知音を試聴", + "onlyWhenUnfocused": "ウィンドウが非アクティブなときのみ再生", + "onlyWhenUnfocusedHint": "Codeg を表示している間は鳴らしません。", + "eventsTitle": "イベント", + "eventsHint": "イベントごとに音を選びます。「なし」を選ぶと鳴りません。同じイベントが数秒以内に繰り返された場合は 1 回だけ再生されます。", + "toneNone": "なし", + "toneChime": "チャイム", + "toneDing": "ベル", + "toneBlip": "ブリップ", + "tonePop": "ポップ", + "toneAlert": "アラート", + "toneDescend": "下降音" + }, + "LogsSettings": { + "loading": "読み込み中…", + "sectionTitle": "実行ログ", + "sectionDescription": "アプリケーションの診断ログを表示・設定します。ログはローカルファイルに書き込まれ、ライブ表示のためメモリにも保持されます。", + "captureTitle": "ログレベル", + "captureDescription": "記録する詳細度を制御します。レベルが高い(Debug、Trace)ほど多く記録されますが、ログも大きくなります。「オフ」でログ記録を無効にします。", + "captureLabel": "取得レベル", + "levels": { + "off": "オフ", + "error": "エラー", + "warn": "警告", + "info": "情報", + "debug": "デバッグ", + "trace": "トレース" + }, + "viewerTitle": "最近のログ", + "viewerDescription": "最近のログレコードをライブ表示します。レベルで絞り込みやテキスト検索ができます。", + "searchPlaceholder": "メッセージまたはターゲットを検索…", + "viewLevels": { + "all": "すべてのレベル", + "error": "エラー以上", + "warn": "警告以上", + "info": "情報以上", + "debug": "デバッグ以上", + "trace": "トレース以上" + }, + "pause": "一時停止", + "resume": "ライブ", + "refresh": "更新", + "clear": "クリア", + "openFolder": "フォルダーを開く", + "shownCount": "{shown} / {total} 件表示", + "empty": "表示するログがありません。", + "levelSaveFailed": "ログレベルの保存に失敗しました", + "openFolderFailed": "ログフォルダーを開けませんでした", + "downloadFailed": "ログファイルのダウンロードに失敗しました", + "filesTitle": "ログファイル", + "filesDescription": "ライブバッファを超える履歴のために、ディスクから完全なログファイルをダウンロードします。", + "filesEmpty": "ログファイルはまだありません。", + "download": "ダウンロード", + "downloadTruncated": "ファイルが大きいため、最新の {size} をダウンロードしました。完全なファイルはログディレクトリにあります。", + "captureEnvLocked": "ログレベルは RUST_LOG / CODEG_LOG 環境変数で制御されています。変更はそちらで行ってください。", + "targetsTitle": "モジュール別オーバーライド", + "targetsDescription": "グローバルレベルを変えずに、特定モジュール(例: codeg_lib::acp)のレベルを個別に設定します。", + "targetsAdd": "追加", + "targetsRemove": "オーバーライドを削除", + "toggleDetails": "詳細を切り替え" + }, + "Automations": { + "title": "オートメーション", + "new": "新規オートメーション", + "empty": "オートメーションはまだありません", + "emptyHint": "作成すると、エージェントのタスクをスケジュールまたは手動で実行できます。", + "name": "名前", + "namePlaceholder": "例:夜間の PR レビュー", + "prompt": "プロンプト", + "promptPlaceholder": "エージェントに何をさせますか?", + "agent": "エージェント", + "folder": "ワークスペースフォルダ", + "folderPlaceholder": "フォルダを選択", + "isolation": "分離", + "isolationWorktree": "実行ごとに新しい worktree", + "isolationShared": "フォルダ内で実行", + "isolationSharedCaveat": "実行はこのフォルダーの作業ツリーを直接使用するため、コミットしていない変更と競合する可能性があります。実行ごとに分離するにはワークツリーのオプションを有効にしてください。", + "trigger": "トリガー", + "triggerSchedule": "スケジュール", + "triggerManual": "手動のみ", + "cron": "スケジュール(cron)", + "cronPlaceholder": "0 9 * * 1-5", + "timezone": "タイムゾーン", + "nextRun": "次回実行", + "branch": "ブランチ", + "branchOptional": "ブランチ(任意)", + "enabled": "有効", + "save": "保存", + "cancel": "キャンセル", + "edit": "編集", + "delete": "削除", + "runNow": "今すぐ実行", + "cancelRun": "実行をキャンセル", + "runHistory": "実行履歴", + "noRuns": "実行履歴はまだありません", + "allFolders": "すべてのフォルダ", + "filterAll": "すべて", + "noMatches": "一致する自動化はありません", + "viewConversation": "会話を表示", + "lastRun": "前回の実行", + "never": "なし", + "running": "実行中", + "deleteTitle": "このオートメーションを削除しますか?", + "deleteDescription": "オートメーションとそのスケジュールを削除します。実行履歴は保持されます。", + "statusRunning": "実行中", + "statusSucceeded": "成功", + "statusFailed": "失敗", + "statusCancelled": "キャンセル", + "statusSkipped": "スキップ", + "errorName": "名前は必須です", + "errorPrompt": "プロンプトは必須です", + "errorCron": "スケジュール実行には cron 式が必要です", + "errorFolder": "ワークスペースフォルダを選択してください", + "presetHourly": "毎時", + "presetDaily": "毎日 9 時", + "presetWeekdays": "平日 9 時", + "presetCustom": "カスタム", + "probing": "オプションを読み込み中…", + "retry": "再試行", + "configNone": "このエージェントに設定可能な項目はありません", + "inherit": "エージェント既定", + "mode": "モード", + "config": "設定", + "branchPlaceholder": "(既定のブランチ)", + "selectHint": "詳細を表示する自動化を選択してください", + "refresh": "更新", + "onboardTitle": "定型のエージェント作業を自動化", + "onboardHint": "コードのレビュー、依存関係の更新、課題のトリアージを、定期実行またはオンデマンドでエージェントに実行させます。", + "headerSubtitle": "スケジュール実行とオンデマンドのエージェント作業", + "startFromTemplate": "テンプレートから始める", + "blankTitle": "空の自動化", + "blankDesc": "エージェント作業を一から設定します。", + "backToTemplates": "テンプレート", + "sectionSchedule": "スケジュールと対象", + "sectionTarget": "ターゲット", + "sectionAction": "アクション", + "actionLaunchSession": "セッションを起動", + "actionEnqueueTask": "タスクをキューに追加", + "actionEnqueueTaskHint": "実行のたびに、このオートメーション名を冠した ToDo タスクが対象フォルダの ToDo タスクに追加され、タスクエンジンがボードの設定に従って実行します。", + "sectionPrompt": "プロンプト", + "nextIn": "{rel}後に実行", + "manual": "手動", + "schedEveryMinutes": "{n}分ごと", + "schedHourly": "1時間ごと", + "schedDaily": "毎日 {time}", + "schedWeekdays": "平日 {time}", + "schedWeekly": "毎週{day} {time}", + "schedMonthly": "毎月 {day} 日 {time}", + "dow0": "日曜日", + "dow1": "月曜日", + "dow2": "火曜日", + "dow3": "水曜日", + "dow4": "木曜日", + "dow5": "金曜日", + "dow6": "土曜日", + "tplCodeReviewTitle": "コードレビュー", + "tplCodeReviewDesc": "最近の変更をレビューし、バグ・リグレッション・品質の問題を洗い出します。", + "tplDependencyUpdatesTitle": "依存関係の更新", + "tplDependencyUpdatesDesc": "古くなった依存関係を見つけ、安全なアップグレードを提案します。", + "tplTestCoverageTitle": "テストカバレッジ", + "tplTestCoverageDesc": "テストされていないコードパスを見つけ、不足しているテストを追加します。", + "tplTodoSweepTitle": "TODO 整理", + "tplTodoSweepDesc": "TODO と FIXME のコメントを集め、優先度ごとに整理します。", + "tplCiTriageTitle": "CI トリアージ", + "tplCiTriageDesc": "最近失敗したチェックを調査し、修正を提案します。", + "tplReleaseNotesTitle": "リリースノート", + "tplReleaseNotesDesc": "前回のリリース以降の変更をまとめ、変更履歴を作成します。", + "tplSecurityAuditTitle": "セキュリティ監査", + "tplSecurityAuditDesc": "脆弱性やリスクのあるパターンをスキャンし、結果を報告します。", + "enable": "有効化", + "disable": "無効化", + "moreActions": "その他の操作", + "statusDisabled": "無効", + "cronBuilderTitle": "スケジュールビルダー", + "cronFreqLabel": "頻度", + "cronFreqMinutes": "N 分ごと", + "cronFreqHourly": "毎時", + "cronFreqDaily": "毎日", + "cronFreqWeekdays": "平日", + "cronFreqWeekly": "毎週", + "cronFreqMonthly": "毎月", + "cronFreqCustom": "カスタム", + "cronEveryLabel": "間隔(分)", + "cronTimeLabel": "時刻", + "cronHourLabel": "時", + "cronMinuteLabel": "分", + "cronDowLabel": "曜日", + "cronDomLabel": "日", + "cronApply": "適用", + "cronPreviewLabel": "プレビュー", + "cronOpenBuilder": "スケジュールビルダーを開く", + "branchDefault": "デフォルトブランチ", + "branchUseCustom": "「{query}」を使用", + "branchLocal": "ローカル", + "branchRemote": "リモート", + "branchSearchPlaceholder": "ブランチを検索…", + "branchNone": "ブランチがありません" + }, + "Tasks": { + "title": "ToDo タスク", + "new": "新規タスク", + "empty": "タスクはまだありません", + "emptyHint": "ToDo を追加して実行すると、エージェントが独立した worktree で作業し、結果をレビューしてマージできます。", + "emptyColTodo": "ToDoはまだありません", + "emptyColInProgress": "進行中のタスクはありません", + "emptyColAttention": "対応が必要なタスクはありません", + "emptyColDone": "完了したタスクはまだありません", + "allFolders": "すべてのフォルダ", + "showCanceled": "キャンセル済みを表示", + "showArchived": "アーカイブを表示", + "filter": "フィルター", + "viewSwitchToBoard": "ボード表示に切り替え", + "viewSwitchToList": "リスト表示に切り替え", + "statusFilter": "ステータス", + "statusFilterAll": "すべてのステータス", + "listEmpty": "現在の絞り込み条件に一致するタスクはありません", + "listColStatus": "ステータス", + "listColTask": "タスク", + "listColLocation": "場所", + "listColChanges": "変更", + "listColUpdated": "更新", + "colTodo": "ToDo", + "colInProgress": "進行中", + "colAttention": "要対応", + "colDone": "完了", + "statusTodo": "ToDo", + "statusQueued": "待機中", + "statusPreparing": "準備中", + "statusRunning": "実行中", + "statusAwaitingInput": "入力待ち", + "statusReview": "レビュー待ち", + "statusMerging": "マージ中", + "statusDone": "完了", + "statusFailed": "失敗", + "statusCanceled": "キャンセル済み", + "statusInterrupted": "中断", + "badgeCleanupFailed": "クリーンアップ失敗", + "badgeWorktreeKept": "worktree 保持", + "badgeWorktreeRemoved": "worktree 削除済み", + "filesChanged": "{count} ファイル", + "actionStart": "開始", + "actionSchedule": "予約実行", + "actionCancel": "キャンセル", + "actionRetry": "再試行", + "actionRequeue": "再キュー", + "actionViewSession": "会話を表示", + "actionEdit": "編集", + "actionDelete": "削除", + "actionRetryCleanup": "クリーンアップを再試行", + "actionMerge": "マージ", + "actionUnqueueMerge": "マージ待ちを取り消す", + "actionEditQueuedMerge": "待機中のマージを編集", + "badgeMergeQueued": "マージ待ち", + "badgeMergeQueuedRank": "マージ待ち · {rank} 番目", + "badgeMergeQueuedHint": "このプロジェクトの実行中のマージが終わるのを待っています。順番が来ると自動的に開始します。", + "actionComplete": "完了", + "actionAbandon": "破棄", + "cancelTitle": "タスクをキャンセルしますか?", + "cancelDescription": "タスクは「キャンセル済み」になります。worktree は保持され、あとで再キューできます。", + "cancelReasonLabel": "キャンセルの理由(任意)", + "cancelReasonPlaceholder": "例:方針が違うので説明を書き直す", + "cancelKeep": "やめておく", + "cancelSubmit": "タスクをキャンセル", + "restartTitleRetry": "タスクを再試行", + "restartTitleRequeue": "タスクを再キュー", + "restartDescription": "補足(任意)を書けます。次の実行のプロンプトに含めて agent に渡されます。", + "scheduleTitle": "タスクの実行を予約", + "scheduleDescription": "タスクは ToDo のまま、指定した時刻に自動で開始します。フォルダーの同時実行数の上限は引き続き適用されます。", + "scheduleDateLabel": "日付", + "schedulePickDate": "日付を選択", + "scheduleTimeLabel": "時刻", + "schedulePreview": "{time} に実行", + "schedulePastHint": "指定した時刻は過ぎています。保存するとすぐに開始します。", + "scheduleInAnHour": "1 時間後", + "scheduleInThreeHours": "3 時間後", + "scheduleTomorrow": "明日 9:00", + "scheduleClear": "予約を解除", + "scheduleBadge": "{time} に開始予定", + "toastScheduled": "{time} に予約しました", + "toastScheduleCleared": "予約を解除しました", + "actionFollowUp": "追加指示", + "actionAddNote": "補足を追加", + "followUpSubmit": "送信", + "followUpIntentRevise": "修正を依頼", + "followUpIntentContinue": "作業を続ける", + "followUpIntentQuestion": "質問する", + "followUpIntentVerify": "セルフチェック", + "followUpPlaceholderRevise": "どこを直してほしいですか?同じセッションで続けます。", + "followUpPlaceholderContinue": "次に何をしますか?これまでの作業はそのまま残ります。", + "followUpPlaceholderQuestion": "何を知りたいですか?ファイルには一切手を加えず回答します。", + "followUpPlaceholderVerify": "任意:重点的に確認してほしい点はありますか?", + "followUpPlaceholderRetry": "任意:今回はどう変えますか?例:先に pnpm install を実行", + "followUpPlaceholderRequeue": "任意:なぜ中止したのか、今回は何を変えるかを書いてください。", + "actionArchive": "アーカイブ", + "actionUnarchive": "アーカイブ解除", + "archiveAllDone": "すべてアーカイブ", + "dropToStart": "離すと実行を開始", + "errorView": "表示", + "notifyReview": "レビュー待ち: {title}", + "notifyFailed": "タスクが失敗しました: {title}", + "createFromMessage": "このメッセージからタスクを作成", + "detailTokens": "合計トークン", + "editorTitleNew": "新規タスク", + "editorTitleEdit": "タスクを編集", + "templates": "テンプレート", + "templatesEmpty": "テンプレートはまだありません。", + "templateSaveCurrent": "現在の内容をテンプレートとして保存", + "templateDelete": "テンプレートを削除", + "transcriptTitle": "タスクの会話", + "transcriptDescription": "タスクのエージェントセッションの読み取り専用ライブビュー。", + "phaseWork": "タスク実行", + "phaseRetry": "再実行", + "phaseReturn": "追加指示", + "phaseMerge": "マージ", + "titleLabel": "タイトル", + "titlePlaceholder": "何をしますか?", + "promptLabel": "タスクの説明", + "promptPlaceholder": "エージェントへの指示を記述 — @ でファイル参照、/ でコマンド", + "folderPlaceholder": "フォルダを選択", + "agentInheritedHint": "タスク設定から継承 — 変更するとこのタスク専用になります", + "agentOverrideReset": "継承に戻す", + "sectionTarget": "ターゲット", + "errorTitle": "タイトルを入力してください", + "errorPrompt": "タスクの説明を入力してください", + "errorFolder": "フォルダを選択してください", + "save": "保存", + "cancel": "キャンセル", + "mergeTitle": "タスクをマージ", + "mergeQueuedTitle": "待機中のマージ", + "mergeQueueHint": "このプロジェクトでは別のタスクをマージ中です。このタスクは待機列に入り、前のマージが終わり次第自動的に開始します。", + "mergeQueueUpdateHint": "このタスクはすでにマージ待ちです。送信すると内容だけが更新され、待機列の順番はそのままです。", + "mergeDescription": "{branch} を {base} にマージします。worktree の未コミット変更は先にコミットされます。", + "mergeMessage": "コミットメッセージ", + "mergeMessagePlaceholder": "例: feat: add login validation", + "mergeAutoMessage": "コミットメッセージをエージェントに生成させる", + "strategySquash": "1つのコミットにまとめる", + "strategySquashHint": "タスクのすべての変更が1件の履歴としてメインブランチに取り込まれ、履歴がすっきりします。", + "strategyMerge": "履歴をすべて残す", + "strategyMergeHint": "タスク中の各コミットをそのまま残し、マージの記録を1件追加します。各ステップを追跡できます。", + "mergeDeleteWorktree": "マージ後に worktree を削除", + "mergeSubmit": "マージ", + "mergeSubmitQueue": "マージ待ちに追加", + "mergeQueuedToast": "マージ待ちに追加しました。実行中のマージが終わり次第開始します。", + "completeTitle": "タスクを完了", + "completeDescription": "このタスクはファイルを変更していないため、マージするものはありません。そのまま完了にします。", + "completeDescriptionNoWorktree": "このタスクの worktree は削除されているため、マージできません。そのまま完了にします。未マージのコミットが残る作業ブランチは保持されます。", + "completeDeleteWorktree": "完了後に worktree を削除", + "completeSubmit": "完了", + "settingsTitle": "タスク設定", + "settingsDescription": "{folder} のタスクの既定値。", + "settingsScope": "適用範囲", + "settingsScopeGlobal": "すべてのフォルダ(グローバル既定)", + "settingsScopeGlobalHint": "個別設定のないフォルダはこのグローバル既定を使います。", + "settingsSource": "設定ソース", + "settingsSourceGlobal": "グローバル既定", + "settingsSourceCustom": "個別設定", + "settingsSourceGlobalFollow": "グローバルのタスク設定に従います。グローバル側の変更が自動的に反映されます。", + "settingsSourceCustomHint": "このフォルダ専用の設定を保存し、グローバル既定には従わなくなります。", + "settingsAgent": "既定のエージェント", + "settingsMaxConcurrent": "最大同時実行数", + "settingsMaxConcurrentHint": "0 = 無制限", + "settingsAutoProcess": "自動処理", + "settingsAutoProcessHint": "ToDo タスクを自動的に開始します(同時実行数の上限まで)。", + "settingsMergeStrategy": "既定のマージ戦略", + "settingsMergeStrategyHint": "マージ時にタスクの変更をブランチ履歴へどう記録するか。", + "settingsAutoMerge": "自動マージ", + "settingsAutoMergeHint": "レビュー待ちに達しマージできる変更があるタスクは、「マージ」を押したときと同じように自動で取り込まれます。コミットメッセージはエージェントが生成し、worktree の扱いは下の既定に従います。プリフライトが赤のタスクやマージに失敗したタスクはそのまま残ります。", + "settingsDeleteWorktree": "マージ後に worktree を削除", + "settingsDeleteWorktreeHint": "マージ画面で既定でオンになります。その場で変更もできます。", + "settingsWorktreeRoot": "Worktree の作成先", + "settingsWorktreeRootHint": "新しいタスクの worktree をこのディレクトリ配下にタスクごとに作成します。空欄ならプロジェクトフォルダーと同じ階層に作成されます。「~」はホームディレクトリ、相対パスはプロジェクトフォルダー基準です。", + "settingsWorktreeRootPlaceholder": "~/codeg-worktrees", + "settingsWorktreeRootBrowse": "worktree のディレクトリを選択", + "settingsPreflight": "プリフライトコマンド", + "settingsPreflightHint": "タスクがレビューに達したときワークツリーで実行。", + "settingsPreflightCustomPlaceholder": "pnpm test", + "settingsInitCommand": "Worktree 初期化コマンド", + "settingsInitCommandHint": "worktree の新規作成後、エージェント開始前に実行されます。", + "settingsInitCommandPlaceholder": "pnpm install", + "settingsTabGeneral": "一般", + "settingsTabMerge": "マージ", + "settingsTabWorktree": "Worktree", + "settingsTabPrompts": "プロンプト", + "settingsPromptsIntro": "各ステージには既定のプロンプトが組み込まれています(タスク本体、ワークツリーのルール、マージ時は具体的な git 手順)。ここに書いた内容は補足指示として末尾に追加され、既定の内容を補うだけで置き換えることはありません。", + "settingsPromptStageAll": "全段階", + "settingsPromptPlaceholderAll": "例: AGENTS.md のプロジェクト規約に従う。最後のまとめは 2 文以内で", + "settingsPromptPlaceholderWork": "例: 関連するテストを先に読む。小さな単位でこまめにコミットする", + "settingsPromptPlaceholderRetry": "例: 続ける前に既にコミット済みの内容を確認し、完了済みの作業をやり直さない", + "settingsPromptPlaceholderReturn": "例:指摘された点を一つずつ対応する。無関係なリファクタリングはしない", + "settingsPromptPlaceholderMerge": "例: 取り込みコミットのメッセージは日本語で。手動で解決した衝突は明記する", + "settingsPromptHintAll": "マージ実行を含め、エージェントに渡すすべてのプロンプトに追加されます。", + "settingsPromptHintWork": "タスクを初めて実行するときに追加されます。", + "settingsPromptHintRetry": "中断または失敗したタスクを再開するときに追加されます。", + "settingsPromptHintReturn": "レビュー待ちのタスクに追加指示を出すとき(修正・追加作業・セルフチェック)に付加されます。", + "settingsPromptHintMerge": "エージェントがタスクをベースブランチに取り込むときに追加されます。", + "preflightPassed": "{name} 成功", + "preflightFailed": "{name} 失敗", + "preflightRunning": "{name} 実行中…", + "detailDescription": "タスク詳細", + "detailSummary": "結果", + "detailFiles": "変更ファイル", + "detailDiffAll": "差分をすべて表示", + "detailDiffAllTitle": "全差分", + "detailNoChanges": "ベースからの変更はまだありません", + "detailTimeline": "進行履歴", + "detailTimelineEmpty": "まだアクティビティがありません", + "showMore": "もっと見る", + "showLess": "折りたたむ", + "detailInfo": "詳細", + "detailBranch": "ブランチ", + "detailMergeCommit": "マージコミット", + "detailChanges": "変更", + "detailScheduled": "開始予定", + "detailCreated": "作成日時", + "detailStarted": "開始日時", + "detailFinished": "完了日時", + "diffLoading": "差分を読み込み中…", + "deleteConfirmTitle": "タスクを削除しますか?", + "deleteConfirmBody": "「{title}」をボードから削除します。実行中の場合は先にキャンセルされます。", + "deleteWithWorktree": "worktree も削除する", + "eventCreated": "作成", + "eventStatusChanged": "ステータス変更", + "eventConfigEffective": "起動構成", + "eventInitCommand": "初期化コマンド", + "eventAgentProgress": "エージェントの進捗", + "eventAgentVerdict": "エージェントの判定", + "eventMergeAttempt": "マージ開始", + "eventMergeQueued": "マージ待ちに追加", + "eventMergeConflict": "マージ競合", + "eventPreflight": "プリフライト", + "eventCleanupFailed": "worktree のクリーンアップに失敗", + "eventResumeFallback": "セッション再開に失敗し新規セッションへ", + "eventUserAction": "ユーザー操作", + "eventDiffStat": "変更スナップショット" + }, + "CustomSkillsSettings": { + "loading": "カスタムスキルを読み込み中…", + "category": "カスタム", + "searchPlaceholder": "名前・ID・説明でカスタムスキルを検索", + "states": { + "not_linked": "未有効", + "linked_to_codeg": "有効", + "linked_elsewhere": "別の場所にリンク", + "blocked_by_real_directory": "実在フォルダにより占有", + "broken": "リンク切れ" + }, + "actions": { + "new": "新規", + "import": "インポート", + "importFromAgent": "エージェントから取り込む", + "cancel": "キャンセル", + "save": "保存" + }, + "rowMenu": { + "edit": "編集", + "duplicate": "複製", + "delete": "削除" + }, + "bulk": { + "delete": "選択項目を削除" + }, + "editor": { + "createTitle": "カスタムスキルを新規作成", + "editTitle": "カスタムスキルを編集", + "description": "カスタムスキルは共有ストア(~/.codeg/skills)に保存され、任意のエージェントで有効化できます。", + "idLabel": "スキル ID", + "idPlaceholder": "例: my-workflow", + "contentLabel": "SKILL.md", + "contentPlaceholder": "ここにスキルの SKILL.md を記述…", + "preview": "プレビュー", + "edit": "編集", + "emptyBody": "まだ内容がありません。" + }, + "duplicate": { + "title": "スキルを複製", + "description": "「{id}」を元に、新しい ID でコピーを作成します。", + "newIdPlaceholder": "新しいスキル ID", + "confirm": "複製" + }, + "import": { + "title": "インポートするスキルフォルダを選択" + }, + "importFromAgent": { + "title": "エージェントからスキルを取り込む", + "description": "エージェント独自のスキルを共有ストアにコピーすると、どのエージェントでも有効化できます。", + "agentLabel": "エージェント", + "agentPlaceholder": "エージェントを選択", + "selectAll": "すべて選択({count})", + "loading": "エージェントのスキルを読み込み中…", + "unsupported": "このエージェントはスキルディレクトリを提供していません。", + "empty": "このエージェントに取り込めるスキルはありません。", + "alreadyInLibrary": "ライブラリ済み", + "confirm": "選択を取り込む({count})" + }, + "delete": { + "title": "カスタムスキルを削除しますか?", + "body": "{count} 個のカスタムスキルを中央ストアから削除し、すべてのエージェントからリンクを解除します。この操作は取り消せません。", + "confirm": "削除" + }, + "toasts": { + "loadFailed": "スキルの読み込みに失敗しました", + "idRequired": "スキル ID を入力してください", + "created": "カスタムスキルを作成しました", + "updated": "カスタムスキルを更新しました", + "saveFailed": "スキルの保存に失敗しました", + "imported": "スキルをインポートしました", + "importFailed": "スキルのインポートに失敗しました", + "duplicated": "スキルを複製しました", + "duplicateFailed": "スキルの複製に失敗しました", + "deleted": "{count} 個のスキルを削除しました", + "deletedPartial": "{ok} 個を削除、{failed} 個が失敗", + "deleteFailed": "スキルの削除に失敗しました", + "importedFromAgent": "{count} 件のスキルを取り込みました", + "importedFromAgentPartial": "{ok} 件を取り込み、{failed} 件が失敗しました", + "importFromAgentAllSkipped": "取り込み対象なし — {count} 件はすでにライブラリにあります", + "importFromAgentFailed": "エージェントからの取り込みに失敗しました" + } + }, + "CodexModelEditor": { + "customizedNotice": "モデル一覧をカスタマイズしたため、codeg が codex のモデル表全体を管理します。codex が今後追加する公式モデルは自動では表示されません。下の更新をクリックして保存し直すと同期できます。カスタマイズをすべて削除すると codex の自動更新に戻ります。", + "officialsTitle": "公式モデル", + "officialsHint": "起動する codex の公式モデルを自動的に含めます。不要なものは削除できます。", + "officialsEmpty": "利用可能な公式モデルがありません。", + "refresh": "codex から更新", + "readdOfficial": "公式を再追加", + "customsTitle": "カスタムモデル", + "customsEmpty": "カスタムモデルはまだありません。", + "addCustom": "カスタム追加", + "slugPlaceholder": "モデル ID(slug)", + "displayNamePlaceholder": "表示名", + "contextWindow": "コンテキスト", + "makeDefault": "デフォルトに設定", + "defaultHint": "デフォルトモデル", + "remove": "削除", + "advanced": "詳細", + "baseTemplate": "ベーステンプレート", + "baseTemplateHint": "必須フィールド(システムプロンプト、ツール、制限)を複製する公式モデル。", + "groupBehavior": "動作と機能", + "fieldReasoningLevel": "既定の推論レベル", + "fieldReasoningSummary": "推論サマリー", + "fieldVerbosity": "詳細度", + "fieldShellType": "シェルタイプ", + "fieldApplyPatch": "パッチ適用ツール", + "fieldReasoningSummaries": "推論サマリー対応", + "fieldSupportVerbosity": "詳細度の制御", + "fieldParallelToolCalls": "並列ツール呼び出し", + "fieldSearchTool": "Web 検索ツール", + "optNone": "なし", + "groupInstructions": "説明とシステムプロンプト", + "fieldDescription": "説明", + "baseInstructions": "システムプロンプト(base_instructions)" + }, + "DiagnosticsSettings": { + "title": "環境診断", + "description": "このアプリが自身のプロセス内でエージェントの CLI をどう解決するかを確認します(ターミナルとは異なる場合があります)。", + "loading": "診断を実行中…", + "error": "診断に失敗しました", + "rerun": "再実行", + "copyAll": "すべてコピー", + "copied": "診断情報をクリップボードにコピーしました", + "button": "診断", + "verdict": { + "ok": "環境は正常です。それでも未インストールと表示される場合は、アプリを完全に再起動してプレフィックスキャッシュを更新してください。", + "node_missing": "アプリの PATH に Node.js が見つかりませんでした。", + "npm_missing": "アプリの PATH に npm が見つかりませんでした。", + "not_installed": "このエージェントはインストールされていないようです。", + "installed_but_unresolved": "インストール済みと記録されていますが、アプリが実行ファイルを見つけられません。", + "user_prefix_not_on_path": "フォールバックのプレフィックス(~/.codeg/npm-global)にインストールされていますが、アプリの PATH に含まれていません。アプリを完全に再起動して再試行してください。", + "homebrew_bin_not_on_path": "Homebrew の bin にインストールされていますが、アプリの PATH に含まれていません(Apple Silicon の keg 分割)。", + "terminal_only_path": "このコマンドはターミナルでは解決されますが、アプリでは解決されません。GUI の PATH のずれです。ターミナルからアプリを起動するか、エージェント設定から再インストールしてください。", + "npm_prefix_timeout": "npm prefix -g が遅すぎました(1.5 秒超)。フォールバック検出をスキップしました。アプリを再起動して再試行してください。", + "node_too_old": "使用中の Node.js がこのエージェントの要件より古いです。Node.js をアップグレードしてください。", + "adapter_missing_native_present": "お使いの {agent} CLI は確かにインストールされていますが、Codeg が起動するのは別の ACP アダプターパッケージで、そちらが未インストールです。エージェント設定からインストールしてください。既存の CLI には触れず、ログインも共有されます。", + "adapter_missing": "Codeg は {agent} 用に別個の ACP アダプターパッケージを起動しますが、まだインストールされていません。エージェント設定からインストールしてください。ベンダー CLI を入れるだけでは足りません。" + } + }, + "TokenUsage": { + "title": "トークン使用量", + "rangeLabel": "期間", + "range7d": "7日間", + "range30d": "30日間", + "range90d": "90日間", + "rangeThisMonth": "今月", + "rangeThisYear": "今年", + "rangeAll": "全期間", + "rangeCustom": "カスタム", + "moreRanges": "その他", + "customRangePick": "期間を選択", + "bucketLabel": "集計単位", + "bucketDay": "日", + "bucketWeek": "週", + "bucketMonth": "月", + "bucketUnitDay": "日", + "bucketUnitWeek": "週", + "bucketUnitMonth": "月", + "folderFilter": "フォルダ", + "allFolders": "すべてのフォルダ", + "agentFilter": "エージェント", + "allAgents": "すべてのエージェント", + "modelFilter": "モデル", + "allModels": "すべてのモデル", + "searchPlaceholder": "検索…", + "noMatches": "該当なし", + "clearFilter": "選択をクリア", + "resetFilters": "フィルタをリセット", + "refresh": "更新", + "rebuild": "すべて再構築", + "rebuildHint": "集計済みデータを破棄し、すべてのセッション記録を読み直します。codeg 以外の CLI で追記された場合に使います。", + "syncing": "セッションを集計中…", + "syncProgress": "{done} / {total}", + "syncDone": "{synced} 件のセッションを集計しました", + "syncFailed": "一部のセッションを読み取れませんでした", + "syncBusy": "すでに更新が実行中です", + "lastSynced": "{time} に更新", + "lastSyncedNever": "未集計", + "tileTotal": "合計トークン", + "tileSessions": "セッション数", + "tileTurns": "ターン数", + "tileActiveDays": "稼働日数", + "tileGenTime": "生成時間", + "vsPrevious": "前期間との比較", + "deltaNew": "新規", + "trendTitle": "使用量の推移", + "trendEmpty": "この期間の使用量はありません", + "trendTurns": "ターン", + "trendSessions": "セッション", + "compositionTitle": "トークンの内訳", + "compositionHint": "入力は送った内容、出力はモデルが書いた内容、キャッシュ読み取りは再送せずに済んだコンテキストです。", + "compositionNote": "これらのキャッシュ命中を定価で再送すると、あと {value} かかっていました。", + "inputTokens": "入力", + "outputTokens": "出力", + "cacheWrite": "キャッシュ書き込み", + "cacheRead": "キャッシュ読み取り", + "freshTokens": "新規計算トークン", + "cacheHitCaption": "キャッシュ命中", + "cacheHeroTitleHigh": "コンテキストの大半は再送不要でした", + "cacheHeroTitleLow": "コンテキストの大半はまだ全額計算です", + "cacheHeroDesc": "{cached} のコンテキストはキャッシュが担い、この期間に実際に新規計算されたのは {fresh} だけです。", + "cacheSavedSuffix": "再送を {saved} 相当分節約できました。", + "avgPerSession": "セッション平均", + "avgTurnsPerSession": "1 セッションあたり平均 {count} ターン", + "avgPerActiveDay": "稼働日平均", + "peakBucket": "最も多い{bucket}", + "peakHour": "ピーク時間帯", + "daysValue": "{count} 日", + "idleDays": "空き日数", + "byFolderTitle": "フォルダー別", + "byAgentTitle": "エージェント別", + "byModelTitle": "モデル別", + "distributionTitle": "使用量の分布", + "distributionHint": "選択した軸でセッションとトークンを集計。行をクリックすると絞り込めます。", + "otherLabel": "その他", + "unknownModel": "モデル未記録", + "emptyBreakdown": "記録がありません", + "sessionsCount": "{count} セッション", + "heatmapTitle": "作業リズム", + "heatmapHint": "ローカル時間の曜日・時刻ごとのトークン量。", + "heatmapPeakHint": "最も集中しているのは {hour}:00 前後です。", + "less": "少", + "more": "多", + "heatmapCell": "{weekday} {hour}:00 — {value} トークン", + "weekMon": "月", + "weekTue": "火", + "weekWed": "水", + "weekThu": "木", + "weekFri": "金", + "weekSat": "土", + "weekSun": "日", + "topSessionsTitle": "消費の多いセッション", + "untitledSession": "名称未設定のセッション", + "topSessionsEmpty": "この期間にセッションはありません", + "streakLongest": "最長の連続日数", + "streakLongestDays": "最長連続 {count} 日", + "share": "共有", + "moreActions": "その他の操作", + "shareDialogTitle": "使用量カードを共有", + "shareDialogHint": "いま選んでいる期間とフィルタのスナップショットです。", + "shareSave": "画像を保存", + "shareCopy": "画像をコピー", + "shareCopied": "クリップボードにコピーしました", + "shareSaved": "画像を保存しました", + "shareFailed": "画像を生成できませんでした", + "shareRendering": "生成中…", + "cardHeading": "私の AI コーディング記録", + "cardRangeAll": "全期間", + "cardTotalLabel": "使用トークン", + "cardFooter": "codeg で作成", + "cardTopModels": "よく使うモデル", + "cardTopProjects": "主なプロジェクト", + "archetypeNightOwl": "夜型コーダー", + "archetypeNightOwlDesc": "トークンの {percent}% は日没後に使われています。", + "archetypeEarlyBird": "早起きタイプ", + "archetypeEarlyBirdDesc": "トークンの {percent}% は朝 9 時前に使われています。", + "archetypeWeekendWarrior": "週末戦士", + "archetypeWeekendWarriorDesc": "トークンの {percent}% は週末に使われています。", + "archetypeCacheMaster": "キャッシュの達人", + "archetypeCacheMasterDesc": "コンテキストの {percent}% がキャッシュ由来です。", + "archetypeMarathoner": "マラソンランナー", + "archetypeMarathonerDesc": "{days} 日連続で開発を続けました。", + "archetypePolyglot": "マルチプレイヤー", + "archetypePolyglotDesc": "{count} 個のエージェントを本格的に併用しています。", + "archetypeLaserFocus": "一点集中", + "archetypeLaserFocusDesc": "トークンの {percent}% を一つのプロジェクトに投じています。", + "archetypeDeepDiver": "深掘り型", + "archetypeDeepDiverDesc": "1 セッションあたり平均 {averageK}K トークン。", + "archetypeSteady": "安定型ビルダー", + "archetypeSteadyDesc": "のべ {days} 日開発しました。", + "emptyTitle": "集計データがまだありません", + "emptyHint": "codeg は各エージェント自身のセッション記録から直接トークン数を読み取ります。更新すると、このマシンにある記録を集計します。", + "emptyAction": "セッションを集計", + "loadFailed": "使用量を読み込めませんでした", + "truncatedNotice": "期間が非常に長いため、表示中の数値は直近の一部のみを対象としています。" + } +} diff --git a/src/i18n/messages/ko.json b/src/i18n/messages/ko.json index d8c404715..f8929f829 100644 --- a/src/i18n/messages/ko.json +++ b/src/i18n/messages/ko.json @@ -1,4956 +1,4958 @@ -{ - "Language": { - "followSystem": "시스템 설정 따름", - "english": "영어", - "simplifiedChinese": "简体中文", - "traditionalChinese": "繁體中文", - "japanese": "일본어", - "korean": "한국어", - "spanish": "스페인어", - "german": "독일어", - "french": "프랑스어", - "portuguese": "포르투갈어", - "arabic": "아랍어" - }, - "GitCredentialDialog": { - "title": "인증 필요", - "description": "원격 서버에서 자격 증명을 요구합니다. 사용자 이름과 비밀번호(또는 개인 액세스 토큰)를 입력하세요.", - "username": "사용자 이름", - "usernamePlaceholder": "사용자 이름 또는 이메일", - "password": "비밀번호 / 토큰", - "passwordPlaceholder": "비밀번호 또는 개인 액세스 토큰", - "passwordHint": "서버의 사용자 이름과 비밀번호를 입력하세요.", - "cancel": "취소", - "authenticate": "인증", - "authenticating": "인증 중...", - "invalidCredentials": "자격 증명이 유효하지 않습니다. 다시 시도하세요.", - "saveCredentials": "향후 작업을 위해 자격 증명 저장", - "githubTitle": "GitHub 인증", - "githubDescription": "개인 액세스 토큰을 입력하여 GitHub에 연결합니다. 토큰 확인 후 계정에 자동으로 저장됩니다.", - "githubToken": "개인 액세스 토큰", - "githubTokenPlaceholder": "ghp_xxxxxxxxxxxx", - "githubTokenHint": "GitHub → Settings → Developer settings → Personal access tokens에서 토큰을 생성하세요.", - "githubAuthenticate": "확인 및 연결", - "generateToken": "토큰 생성" - }, - "SettingsShell": { - "title": "설정", - "preferences": "환경설정", - "nav": { - "general": "일반", - "appearance": "외관", - "agents": "에이전트", - "mcp": "MCP", - "skills": "Skills", - "shortcuts": "단축키", - "version_control": "버전 관리", - "system": "시스템", - "chat_channels": "채팅 채널", - "web_service": "웹 서비스", - "model_providers": "모델 제공업체", - "experts": "전문가", - "science": "과학 연구", - "office_tools": "오피스 도구", - "skill_packs": "스킬 팩", - "quick_messages": "빠른 메시지", - "logs": "실행 로그" - } - }, - "AppearanceSettings": { - "sectionTitle": "테마 모양", - "sectionDescription": "라이트, 다크 또는 시스템 설정을 선택할 수 있습니다. 설정은 자동으로 저장됩니다.", - "themeMode": "테마 모드", - "placeholder": "테마 모드 선택", - "system": "시스템 설정 따름", - "light": "라이트", - "dark": "다크", - "currentTheme": "현재 적용된 테마: {theme}", - "resolvedTheme": { - "light": "라이트", - "dark": "다크", - "unknown": "--" - }, - "themeColor": { - "sectionTitle": "테마 색상", - "sectionDescription": "버튼, 강조 색상, 하이라이트에 사용할 색상 팔레트를 선택하세요.", - "current": "현재 색상: {color}", - "options": { - "neutral": "Neutral", - "zinc": "Zinc", - "slate": "Slate", - "stone": "Stone", - "gray": "Gray", - "red": "Red", - "rose": "Rose", - "orange": "Orange", - "green": "Green", - "blue": "Blue", - "yellow": "Yellow", - "violet": "Violet" - } - }, - "customStyle": { - "sectionTitle": "사용자 지정 스타일", - "sectionDescription": "현재 테마의 색상을 미세 조정하거나 직접 작성한 CSS를 적용합니다. 재정의는 기본 프리셋 위에 얹히므로 프리셋을 바꿔도 유지됩니다.", - "summarySuspended": "일시 중지됨", - "summaryDefault": "프리셋 기본값", - "summaryTokens": "{count, plural, one {재정의 #개} other {재정의 #개}}", - "summaryCss": "사용자 지정 CSS", - "suspendedByShortcut": "사용자 지정 스타일이 일시 중지되었습니다. 다시 켜기 전까지 여기서 설정한 내용은 적용되지 않습니다.", - "suspendedBySafeParam": "이 창은 안전 외관 모드로 열려 사용자 지정 스타일이 적용되지 않습니다. 다른 창에는 영향이 없습니다.", - "resume": "사용자 지정 스타일 재개", - "enableTheme": "사용자 지정 색상 사용", - "editingLight": "라이트 모드 값을 편집하고 있습니다. 다크 모드로 전환하면 따로 설정할 수 있습니다.", - "editingDark": "다크 모드 값을 편집하고 있습니다. 라이트 모드로 전환하면 따로 설정할 수 있습니다.", - "resetToken": "프리셋 값으로 되돌리기", - "radius": "모서리 둥글기", - "radiusHint": "sm부터 4xl까지의 둥글기 척도 전체가 이 값에서 파생되므로 슬라이더 하나로 앱 전체가 바뀝니다.", - "advanced": "고급 (변수 {count}개 더)", - "enableCss": "사용자 지정 CSS 사용", - "cssRisk": "고급 기능입니다. 사용자 지정 CSS는 모든 기본 스타일을 덮어쓰므로 화면을 사용할 수 없게 만들 수 있습니다.", - "editCss": "CSS 편집…", - "cssPresent": "{size} KB 저장됨", - "cssEmpty": "아직 저장된 내용이 없습니다", - "escapeHint": "화면이 망가졌나요? {shortcut} 키로 모든 사용자 지정 스타일을 중지할 수 있고, safeStyle=1 쿼리 파라미터로 창을 열 수도 있습니다.", - "copyTheme": "테마 JSON 복사", - "importTheme": "테마 가져오기…", - "clearTheme": "재정의 지우기", - "interopHint": "테마는 shadcn의 registry:theme 형식을 사용합니다. 어떤 shadcn 테마든 붙여넣을 수 있고, 내보낸 테마는 모든 shadcn 프로젝트에서 쓸 수 있습니다.", - "importTitle": "테마 가져오기", - "importDescription": "shadcn의 registry:theme 항목, light/dark 객체, 또는 단층 토큰 맵을 붙여넣으세요.", - "readClipboard": "클립보드 읽기", - "importConfirm": "가져오기", - "cancel": "취소", - "apply": "적용", - "toasts": { - "copied": "테마 JSON을 복사했습니다", - "copyFailed": "클립보드에 복사하지 못했습니다", - "clipboardReadFailed": "클립보드를 읽지 못했습니다. 직접 붙여넣어 주세요", - "importFailed": "이 JSON에는 사용할 수 있는 테마 변수가 없습니다", - "imported": "테마를 가져왔습니다" - }, - "css": { - "dialogTitle": "사용자 지정 CSS", - "dialogDescription": "모든 codeg 창에 적용됩니다. 변경 사항은 실시간으로 미리 보이며 적용을 눌러야 저장됩니다.", - "size": "{used} KB / {max} KB", - "ruleCount": "규칙 {count}개", - "errorTooLarge": "너무 커서 저장할 수 없습니다. 상한 아래로 줄여 주세요.", - "errorImportEscaped": "제거 후에도 @import가 감지되었습니다(이스케이프 표기). 직접 삭제해 주세요.", - "warnNoRules": "해석된 규칙이 없습니다. 문법을 확인하세요.", - "noticeImportsRemoved": "@import 규칙 {count}개를 제거했습니다. 원격 스타일시트를 가져오기 때문입니다.", - "noticeRemoteUrl": "원격 url()이 포함되어 있어 적용 시 네트워크 요청이 발생합니다.", - "noticePreviewSuspended": "사용자 지정 스타일이 중지되어 이 미리보기는 적용되지 않습니다.", - "noticeDisabled": "사용자 지정 CSS가 꺼져 있습니다. 여기서 미리 볼 수는 있지만 켜야 실제로 적용됩니다.", - "hintTokens": "팁: 재정의한 색상은 var(--primary), var(--background) 등으로 참조할 수 있습니다." - } - }, - "zoomLevel": { - "sectionTitle": "창 확대/축소", - "sectionDescription": "전체 인터페이스를 확대하거나 축소합니다. 즉시 적용되며 장치별로 저장됩니다.", - "placeholder": "확대/축소 단계 선택", - "default": "기본값", - "current": "현재 확대/축소: {zoom}%" - }, - "fonts": { - "sectionTitle": "글꼴", - "sectionDescription": "인터페이스, 코드 편집기, 터미널의 글꼴을 각각 선택합니다. 내장 글꼴은 필요할 때 불러옵니다. “사용자 지정…”을 선택하면 시스템에 설치된 모든 글꼴을 사용할 수 있습니다.", - "interface": "인터페이스", - "editor": "편집기", - "terminal": "터미널", - "groupSans": "산세리프", - "groupMono": "고정폭", - "custom": "사용자 지정…", - "customPlaceholder": "글꼴 이름 (예: Fira Code)", - "fontSize": "글꼴 크기", - "ligatures": "합자 사용", - "ligaturesUnavailable": "이 글꼴에는 합자가 없습니다", - "wordWrap": "자동 줄 바꿈 사용", - "terminalLigaturesHint": "터미널 합자는 내장 코딩 글꼴에만 적용됩니다.", - "preview": "미리 보기" - }, - "welcomePanel": { - "sectionTitle": "모드 선택 영역", - "sectionDescription": "새 대화 페이지에서 입력창 위에 표시되는 '코드 개발 / 일상 업무' 바로가기 카드입니다.", - "showQuickActions": "새 대화 페이지에 표시" - }, - "workspaceBackground": { - "sectionTitle": "작업 공간 배경", - "sectionDescription": "작업 공간 전체 뒤에 이미지를 표시합니다. 사이드바와 패널이 반투명 유리 효과로 바뀌어 이미지가 비쳐 보이며, 마스크가 텍스트 가독성을 유지합니다.", - "enable": "배경 이미지 사용", - "image": "이미지", - "chooseImage": "이미지 선택", - "replaceImage": "이미지 변경", - "removeImage": "제거", - "fillMode": "채우기 방식", - "fillModes": { - "cover": "채우기", - "contain": "맞춤", - "center": "가운데", - "tile": "바둑판식" - }, - "maskOpacity": "마스크 불투명도", - "maskOpacityHint": "값이 높을수록 이미지가 테마 배경색으로 흐려져 텍스트 대비가 좋아집니다.", - "imageBlur": "이미지 흐림", - "panelOpacity": "패널 불투명도", - "panelOpacityHint": "사이드바, 패널, 탭 바의 불투명도입니다. 낮을수록 이미지가 더 많이 비쳐 보입니다.", - "errorTooLarge": "이미지가 너무 큽니다(최대 16 MB).", - "errorUploadFailed": "배경 이미지 설정에 실패했습니다." - } - }, - "SystemSettings": { - "loading": "로딩 중...", - "sectionTitle": "시스템 관리", - "sectionDescription": "네트워크 프록시, 앱 업데이트, 언어 설정을 관리합니다.", - "proxyTitle": "네트워크 프록시", - "proxyDescription": "활성화하면 이후 네트워크 요청에서 이 프록시를 우선 사용합니다(ACP 채팅, 에이전트 설치, Git 원격 작업 포함).", - "loadFailed": "불러오기 실패: {message}", - "enableProxy": "시스템 프록시 활성화", - "proxyAddress": "프록시 주소", - "proxyHint": "http(s)/socks5 지원, 예: {example}. 시스템 프록시를 활성화한 경우에만 적용됩니다.", - "save": "저장", - "saving": "저장 중...", - "proxyRequired": "프록시를 활성화하면 프록시 URL이 필요합니다", - "saveSuccess": "시스템 프록시 설정이 저장되었습니다", - "saveFailed": "저장 실패: {message}", - "languageTitle": "언어", - "languageDescription": "앱 언어를 설정합니다. 시스템 언어를 따를 때 지원되지 않는 언어는 영어로 대체됩니다.", - "appLanguage": "앱 언어", - "languageSaveSuccess": "언어 설정이 저장되었습니다", - "languageSaveFailed": "언어 설정 저장 실패: {message}", - "updateTitle": "앱 업데이트", - "versionTitle": "소프트웨어 업데이트", - "updateDescription": "설정된 릴리스 소스에서 새 버전을 확인하고 가능하면 바로 설치합니다.", - "currentVersion": "현재 버전", - "upgradableVersion": "최신 버전", - "none": "없음", - "lastChecked": "마지막 확인: {time}", - "updateError": "업데이트 오류: {message}", - "checking": "확인 중...", - "checkUpdate": "업데이트 확인", - "updating": "설치 중...", - "downloading": "다운로드 중...", - "upgradeTo": "v{version}로 업그레이드", - "viewRelease": "v{version} 릴리스 보기", - "foundUpdate": "새 버전 v{version}을 찾았습니다", - "alreadyLatest": "이미 최신 버전입니다", - "checkUpdateFailed": "업데이트 확인 실패: {message}", - "installSuccess": "업데이트가 설치되었습니다. 앱을 다시 시작합니다.", - "installFailed": "업데이트 실패: {message}", - "upgradeSuccess": "업그레이드가 완료되었습니다. 다시 불러오는 중...", - "restartTimeout": "서버가 제때 복구되지 않았습니다. 컨테이너 또는 서비스 로그를 확인하세요.", - "restartingIn": "{seconds}초 후에 다시 시작합니다...", - "waitingForServer": "서버가 복구되기를 기다리는 중...", - "restartToUpdate": "다시 시작하여 업데이트", - "newVersionBadge": "새 버전 v{version}", - "updateAvailableTitle": "업데이트 있음", - "releaseNotesTitle": "새로운 기능", - "remindLater": "나중에", - "retry": "다시 시도", - "stepDownload": "다운로드", - "stepInstall": "설치", - "stepRestart": "다시 시작", - "updateReadyHint": "업데이트를 다운로드했습니다. 다시 시작하여 적용하세요.", - "restarting": "다시 시작하는 중…", - "dockerUpgradeHint": "지금 실행 중인 컨테이너를 업그레이드합니다. 컨테이너를 다시 만들면 사라집니다. 유지하려면 새 버전 이미지를 가져오거나 빌드한 뒤 컨테이너를 다시 만드세요.", - "upgradeRolledBack": "업그레이드에 실패하여 서버가 이전 버전으로 롤백되었습니다.", - "serverUnreachable": "업그레이드를 시작하기 위해 서버에 연결할 수 없습니다. 서버가 실행 중인지 확인한 후 다시 시도하세요.", - "rollbackButton": "롤백", - "rollingBack": "롤백 중...", - "rollbackDescription": "마지막 업그레이드 이전에 설치된 버전으로 복원합니다.", - "rollbackConfirmTitle": "이전 버전으로 롤백하시겠습니까?", - "rollbackConfirmDescription": "서버가 마지막 업그레이드 이전에 설치된 버전으로 다시 시작됩니다. 최신 릴리스는 다시 설치할 수 있습니다.", - "rollbackConfirm": "롤백", - "rollbackCancel": "취소", - "rollbackSuccess": "이전 버전으로 롤백했습니다. 다시 불러오는 중...", - "rollbackFailed": "롤백에 실패했습니다. 서버 로그를 확인하세요.", - "updateErrors": { - "sourceUnavailable": "업데이트 소스에 연결할 수 없습니다. 네트워크 또는 프록시를 확인한 뒤 다시 시도하세요.", - "network": "네트워크 연결에 실패했습니다. 네트워크 또는 프록시를 확인한 뒤 다시 시도하세요.", - "downloadFailed": "업데이트 패키지 다운로드에 실패했습니다. 잠시 후 다시 시도하세요.", - "installFailed": "업데이트 설치에 실패했습니다. 앱을 종료한 뒤 다시 시도하세요.", - "unknown": "업데이트에 실패했습니다. 잠시 후 다시 시도하세요." - } - }, - "VersionControlSettings": { - "loading": "로딩 중...", - "sectionTitle": "버전 관리", - "sectionDescription": "Git 실행 파일을 설정하고 GitHub 계정을 관리합니다.", - "gitTitle": "Git 설정", - "gitDescription": "애플리케이션에서 사용할 Git 실행 파일을 설정합니다.", - "gitDetected": "Git이 감지되었습니다", - "gitNotFound": "시스템에서 Git을 찾을 수 없습니다", - "gitVersion": "버전", - "gitPath": "경로", - "customGitPath": "사용자 지정 Git 경로", - "customGitPathPlaceholder": "/usr/bin/git", - "customGitPathHint": "비워두면 자동 감지된 경로를 사용합니다.", - "test": "테스트", - "testing": "테스트 중...", - "testSuccess": "Git 실행 파일이 유효합니다.", - "testFailed": "Git 테스트 실패: {message}", - "save": "저장", - "saving": "저장 중...", - "saveSuccess": "Git 설정이 저장되었습니다.", - "saveFailed": "저장 실패: {message}", - "githubTitle": "GitHub 계정", - "githubDescription": "인증용 GitHub 계정을 관리합니다. 토큰은 로컬에 저장됩니다.", - "noAccounts": "설정된 GitHub 계정이 없습니다.", - "addAccount": "계정 추가", - "serverUrl": "서버 URL", - "serverUrlPlaceholder": "https://github.com", - "token": "개인 액세스 토큰", - "tokenPlaceholder": "ghp_xxxxxxxxxxxx", - "generateToken": "토큰 생성", - "tokenHint": "GitHub → Settings → Developer settings → Personal access tokens에서 토큰을 생성하세요.", - "validateAndAdd": "검증 및 추가", - "validating": "검증 중...", - "addSuccess": "계정 {username}이(가) 추가되었습니다.", - "addFailed": "계정 추가 실패: {message}", - "testConnection": "테스트", - "connectionSuccess": "연결 성공.", - "connectionFailed": "연결 실패: {message}", - "setDefault": "기본값으로 설정", - "defaultLabel": "기본", - "defaultSet": "기본 계정이 업데이트되었습니다.", - "removeAccount": "삭제", - "removeConfirmTitle": "계정 삭제", - "removeConfirmMessage": "계정 \"{username}\"을(를) 삭제하시겠습니까?", - "removeConfirm": "삭제", - "removeCancel": "취소", - "removeSuccess": "계정이 삭제되었습니다.", - "scopes": "범위", - "loadFailed": "설정 로드 실패: {message}", - "gitAccount": { - "sectionTitle": "Git 서버 계정", - "sectionDescription": "GitHub 이외의 Git 서버 자격 증명을 관리합니다 (GitLab, Bitbucket, 자체 호스팅 등).", - "noAccounts": "설정된 Git 서버 계정이 없습니다.", - "addAccount": "계정 추가", - "addTitle": "Git 계정 추가", - "addDescription": "서버 주소, 사용자 이름, 비밀번호 또는 액세스 토큰을 입력하세요.", - "serverUrl": "서버 URL", - "serverUrlPlaceholder": "https://gitlab.example.com", - "username": "사용자 이름", - "usernamePlaceholder": "사용자 이름 또는 이메일", - "password": "비밀번호 / 토큰", - "passwordPlaceholder": "비밀번호 또는 액세스 토큰", - "passwordHint": "서버의 비밀번호 또는 액세스 토큰을 입력하세요.", - "add": "추가", - "serverRequired": "서버 URL을 입력하세요.", - "usernameRequired": "사용자 이름을 입력하세요.", - "passwordRequired": "비밀번호를 입력하세요." - } - }, - "ShortcutSettings": { - "sectionTitle": "단축키", - "resetDefault": "기본값으로 재설정", - "recordInstruction": "오른쪽 버튼을 클릭한 다음 키 조합을 누르세요. Ctrl/Cmd, Alt, Shift를 사용할 수 있습니다. Esc를 누르면 기록을 취소합니다.", - "recording": "단축키 입력...", - "toasts": { - "conflict": "단축키가 이미 \"{title}\"에서 사용 중입니다", - "updated": "단축키가 업데이트되었습니다", - "invalid": "유효하지 않은 단축키입니다. 다시 시도하세요", - "reset": "기본 단축키를 복원했습니다" - }, - "actions": { - "toggle_search": { - "title": "검색 열기", - "description": "대화 검색 패널을 표시하거나 숨깁니다" - }, - "toggle_sidebar": { - "title": "왼쪽 사이드바 전환", - "description": "대화 목록 사이드바를 표시하거나 숨깁니다" - }, - "toggle_terminal": { - "title": "터미널 전환", - "description": "하단 터미널 패널을 표시하거나 숨깁니다" - }, - "new_terminal_tab": { - "title": "새 터미널", - "description": "터미널에 포커스가 있을 때 새 터미널 탭을 만듭니다" - }, - "close_current_terminal_tab": { - "title": "현재 터미널 닫기", - "description": "터미널에 포커스가 있을 때 현재 터미널 탭을 닫습니다" - }, - "toggle_aux_panel": { - "title": "오른쪽 패널 전환", - "description": "보조 정보 패널을 표시하거나 숨깁니다" - }, - "new_conversation": { - "title": "새 대화", - "description": "현재 폴더에 새 대화 탭을 만듭니다" - }, - "open_folder": { - "title": "폴더 열기", - "description": "폴더 선택기를 열고 새 창에서 엽니다" - }, - "open_settings": { - "title": "설정 열기", - "description": "설정 창을 엽니다" - }, - "close_current_tab": { - "title": "현재 탭 닫기", - "description": "현재 대화 또는 파일 탭을 닫습니다" - }, - "close_all_file_tabs": { - "title": "모든 파일 탭 닫기", - "description": "파일 패널이 활성 상태일 때 열린 모든 파일 탭을 닫습니다" - }, - "next_tab": { - "title": "다음 탭", - "description": "다음 대화 또는 파일 탭으로 전환" - }, - "prev_tab": { - "title": "이전 탭", - "description": "이전 대화 또는 파일 탭으로 전환" - }, - "send_message": { - "title": "메시지 보내기", - "description": "입력창에서 현재 메시지를 전송" - }, - "newline_in_message": { - "title": "메시지 줄바꿈", - "description": "입력창에 줄바꿈을 삽입" - }, - "toggle_custom_style": { - "title": "사용자 지정 스타일 중지/재개", - "description": "비상 탈출구: 모든 사용자 지정 색상과 CSS를 끄고, 다시 누르면 되돌립니다" - } - } - }, - "SkillsSettings": { - "title": "Skills", - "description": "왼쪽에서 Skill을 선택하세요. 오른쪽은 기본적으로 Markdown 미리보기이며, 편집으로 전환해 수정 후 저장할 수 있습니다.", - "loadingAgents": "Skill을 지원하는 에이전트를 불러오는 중...", - "emptyNoManageableAgents": "Skill을 관리할 수 있는 에이전트가 없습니다.", - "managedTarget": "관리 대상", - "selectAgentPlaceholder": "에이전트 선택", - "searchPlaceholder": "이름 / ID / 경로로 검색...", - "skillsList": "Skill 목록", - "loadingSkills": "Skill 불러오는 중...", - "agentNotSupported": "현재 에이전트는 Skill 관리를 지원하지 않습니다.", - "emptySkills": "아직 Skill이 없습니다. \"새 Skill\"을 클릭해 생성하세요.", - "newSkillTitle": "새 Skill", - "skillInfo": "Skill 정보", - "skillIdPlaceholder": "skill-id(영문/숫자/-/_/.)", - "skillsDirectoryWithPath": "Skill 디렉터리: {path}", - "skillsDirectoryNeedId": "Skill 디렉터리: Skill ID를 입력하면 전체 경로를 생성합니다", - "markdownContent": "Markdown 내용", - "editingStatus": "편집 중", - "previewStatus": "미리보기 중", - "contentPlaceholder": "Skill Markdown 내용을 입력하세요...", - "metadataTitle": "Skill 메타데이터", - "onlyYamlMetadata": "이 Skill에는 YAML 메타데이터만 포함되어 있습니다.", - "emptyContentHint": "아직 내용이 없습니다. \"편집\"을 눌러 시작하세요.", - "loadingSkill": "Skill 불러오는 중...", - "emptyNoAgents": "사용 가능한 에이전트가 없습니다.", - "noSelectionHint": "왼쪽에서 Skill을 선택하거나 \"새 Skill\"을 클릭하여 만드세요.", - "systemBadge": "시스템", - "systemHint": "CLI 내장 Skill · 읽기 전용", - "scope": { - "global": "전역", - "folder": "폴더", - "selectFolderPlaceholder": "폴더 선택", - "noFolders": "폴더를 찾을 수 없습니다", - "pickFolderHint": "Skills을 보려면 폴더를 선택하세요." - }, - "actions": { - "preview": "미리보기", - "edit": "편집", - "openInWindow": "새 창에서 열기", - "delete": "삭제", - "deleting": "삭제 중...", - "refresh": "새로고침", - "newSkill": "새 Skill", - "reset": "초기화", - "save": "저장", - "saving": "저장 중...", - "cancel": "취소" - }, - "deleteDialog": { - "title": "Skill 삭제", - "confirm": "현재 Skill을 삭제하시겠습니까? 이 작업은 되돌릴 수 없습니다.", - "confirmWithNamePrefix": "Skill", - "confirmWithNameSuffix": "을(를) 삭제하시겠습니까? 이 작업은 되돌릴 수 없습니다." - }, - "toasts": { - "loadFailed": "Skill을 불러오지 못했습니다", - "openFolderFailed": "폴더를 열지 못했습니다", - "noSkillDirectory": "현재 에이전트에서 사용할 수 있는 Skill 디렉터리를 찾지 못했습니다", - "nameRequired": "Skill 이름은 비워둘 수 없습니다", - "updated": "Skill이 업데이트되었습니다", - "created": "Skill이 생성되었습니다", - "saveFailed": "Skill 저장에 실패했습니다", - "deleted": "Skill이 삭제되었습니다", - "deleteFailed": "Skill 삭제에 실패했습니다" - }, - "templates": { - "gemini": "---\nname: example-skill\ndescription: Describe when this skill should be used.\n---\n\n# Skill Name\n\nInstructions for the agent when this skill is active.\n\n## Workflow\n\n1. Add actionable step one.\n2. Add actionable step two.\n", - "openCode": "---\nname: example-skill\ndescription: Describe when this skill should be used.\n---\n\n# Purpose\n\nDescribe what this skill helps with.\n\n# Steps\n\n1. Add actionable step one.\n2. Add actionable step two.\n", - "openClaw": "---\nname: example-skill\ndescription: Describe when this skill should be used.\nuser-invocable: true\ndisable-model-invocation: false\n---\n\n# Purpose\n\nDescribe what this skill helps with.\n\n# Instructions\n\n1. Add actionable instruction one.\n2. Add actionable instruction two.\n", - "default": "---\nname: example-skill\ndescription: Describe when this skill should be used.\n---\n\n# Skill: example-skill\n\n## When to use\n\n- Describe trigger conditions.\n\n## Instructions\n\n1. Add actionable instruction one.\n2. Add actionable instruction two.\n" - } - }, - "McpSettings": { - "loading": "로딩 중...", - "summary": { - "missingCommand": "(명령 없음)", - "missingUrl": "(URL 없음)" - }, - "protocol": { - "stdio": "Stdio" - }, - "errors": { - "selectInstallProtocol": "설치 프로토콜을 선택하세요", - "fieldRequired": "{field}은(는) 필수입니다", - "fieldNeedsBoolean": "{field}은(는) true 또는 false여야 합니다", - "fieldNeedsNumber": "{field}은(는) 숫자여야 합니다", - "fieldNeedsInteger": "{field}은(는) 정수여야 합니다", - "fieldInvalidJson": "{field}의 JSON이 잘못되었습니다: {message}", - "fieldOutOfRange": "{field} 값이 허용 범위를 벗어났습니다", - "jsonEmpty": "{name}은(는) 비워둘 수 없습니다", - "jsonInvalid": "{name}은(는) 유효한 JSON이 아닙니다: {message}", - "jsonMustBeObject": "{name}은(는) JSON 객체여야 합니다", - "specMustBeObject": "MCP 구성은 JSON 객체여야 합니다.", - "missingType": "MCP 구성에 type 필드가 없습니다. stdio, http (별칭: streamable-http, streamableHttp), sse 중 하나를 지정하세요.", - "unsupportedType": "지원하지 않는 MCP type {type}. 지원: stdio, http (별칭: streamable-http, streamableHttp), sse.", - "codexEntryUnsupportedType": "Codex MCP 항목 {id}의 type {type}은(는) 지원되지 않습니다. 지원: stdio, http (별칭: streamable-http, streamableHttp), sse.", - "unsupportedTransportType": "지원하지 않는 transport type {type}. 지원: http (별칭: streamable-http, streamableHttp), sse.", - "stdioCommandRequired": "stdio 타입의 MCP에는 비어 있지 않은 command 필드가 필요합니다.", - "remoteUrlRequired": "원격 MCP에는 비어 있지 않은 url 필드가 필요합니다.", - "appsRequired": "대상 앱을 하나 이상 선택하세요." - }, - "jsonNames": { - "localConfig": "MCP 구성", - "installConfig": "설치 구성" - }, - "toasts": { - "uninstalled": "MCP가 제거되었습니다", - "uninstallFailed": "제거 실패: {message}", - "selectAtLeastOneApp": "대상 앱을 최소 하나 선택하세요", - "saveSuccess": "저장됨", - "saveFailed": "저장 실패: {message}", - "installed": "{name} 설치됨", - "installFailed": "설치 실패: {message}", - "serverIdRequired": "Server ID는 필수입니다", - "serverIdExists": "Server ID \"{id}\"이(가) 이미 존재합니다. 기존 항목을 편집하거나 다른 이름을 사용하세요.", - "created": "MCP가 생성되었습니다" - }, - "installDialog": { - "title": "MCP 설치 확인", - "descriptionWithName": "{name}을(를) 로컬 구성에 설치합니다.", - "description": "설치할 대상 앱을 선택하세요.", - "protocol": "프로토콜", - "selectProtocol": "프로토콜 선택", - "parameters": "구성 매개변수", - "booleanPlaceholder": "true/false를 선택하세요", - "selectOneValue": "값 선택", - "targetApps": "대상 앱" - }, - "actions": { - "cancel": "취소", - "confirmInstall": "설치 확인", - "installing": "설치 중", - "uninstall": "제거", - "uninstalling": "제거 중", - "viewDetails": "상세 보기", - "save": "저장", - "saving": "저장 중", - "install": "설치", - "refresh": "새로고침", - "newMcp": "새 MCP", - "create": "생성", - "creating": "생성 중..." - }, - "tabs": { - "local": "로컬 MCP", - "market": "MCP 마켓플레이스" - }, - "local": { - "filterPlaceholder": "로컬 MCP 필터...", - "loadFailed": "로드 실패: {message}", - "empty": "감지된 로컬 MCP가 없습니다.", - "description": "로컬 MCP 구성은 직접 수정하고 저장할 수 있습니다.", - "enabledApps": "활성화된 앱", - "configJson": "MCP 구성 (JSON)", - "draftTitle": "새 MCP", - "draftDescription": "Server ID와 설정을 입력하여 로컬 MCP 서버를 생성합니다.", - "serverIdLabel": "Server ID", - "serverIdPlaceholder": "Server ID (예: my-mcp)", - "typeHint": "지원 타입: stdio, http (별칭: streamable-http, streamableHttp), sse. env는 stdio 전용이며, 원격 MCP는 인증 토큰을 headers로 전달해야 합니다.", - "envOnRemoteWarning": "원격 MCP 설정에 env가 포함되어 있습니다. env는 stdio에서만 사용되며 원격 MCP는 headers로 인증 토큰을 전달합니다. 저장 시 env는 무시됩니다." - }, - "market": { - "selectMarketplace": "마켓플레이스 선택", - "searchPlaceholder": "MCP 검색...", - "searchFailed": "검색 실패: {message}", - "loadingList": "MCP 목록을 불러오는 중...", - "empty": "MCP 검색 결과가 없습니다.", - "loadingDetail": "마켓플레이스 상세 정보를 불러오는 중...", - "detailLoadFailed": "상세 정보를 불러오지 못했습니다: {message}", - "owner": "소유자: {owner}", - "namespace": "네임스페이스: {namespace}", - "defaultInstallProtocol": "기본 설치 프로토콜", - "currentOptionParameterCount": "현재 옵션의 매개변수 수: {count}", - "installConfigDescription": "설치 구성 (JSON, 설치 전에 편집 가능; 편집 내용은 프로토콜/매개변수 폼을 덮어씁니다)", - "selectLeftToView": "상세 정보를 보려면 왼쪽에서 마켓플레이스 MCP를 선택하세요." - }, - "badges": { - "verified": "검증됨", - "remote": "원격", - "hasHomepage": "홈페이지 있음", - "uses": "{count}회 사용", - "deployed": "배포됨", - "notDeployed": "미배포" - }, - "selectLeftMcp": "왼쪽에서 MCP를 선택하세요." - }, - "AcpAgentSettings": { - "title": "Agent SDK 관리", - "description": "Agent SDK 연결, 활성화 상태, 환경 변수, 구성 관리, 버전 사전 점검 정보를 한곳에서 관리합니다.", - "loadingAgents": "에이전트 목록 불러오는 중...", - "agentList": "에이전트 목록", - "emptyNoAgent": "사용 가능한 에이전트가 없습니다.", - "configManagement": "구성 관리", - "envVars": "환경 변수", - "hostTools": { - "label": "파일과 명령을 에이전트가 직접 처리", - "description": "codeg가 파일 접근과 터미널 명령을 대신 처리하지 않고 에이전트가 자체 프로세스에서 실행합니다. 그래야 에이전트 자체의 샌드박스와 권한 규칙이 적용됩니다. 다른 에이전트에 위임하는 기능도 함께 꺼집니다. 같은 작업이 다시 codeg를 거치게 되기 때문입니다. codeg는 자체 샌드박스를 제공하지 않으므로 에이전트에 샌드박스를 구성한 경우에만 켜세요." - }, - "nativeJsonConfig": "네이티브 JSON 구성", - "modelHintDefault": "비워두면 시스템 기본 모델을 사용합니다.", - "generalConfigDescriptionClaude": "API URL, API Key, Claude 모델을 빠르게 설정하고 네이티브 JSON 구성과 동기화합니다.", - "generalConfigDescriptionDefault": "주요 구성 입력(API URL, API Key, Model)과 네이티브 JSON 구성 관리를 지원합니다.", - "multiAgent": { - "title": "다중 에이전트 협업", - "description": "활성 에이전트가 하위 작업을 다른 에이전트에게 위임할 수 있도록 합니다.", - "enable": "위임 사용", - "enableHint": "끄면 delegate_to_agent 도구가 에이전트의 MCP 도구 목록에서 숨겨집니다.", - "withheldByHostTools": "{agents}에는 위임 도구가 제공되지 않습니다. 해당 에이전트의 “파일과 명령을 에이전트가 직접 처리” 스위치가 켜져 있습니다.", - "depthLimit": "최대 위임 깊이", - "depthHint": "허용 범위: {min}–{max}. 위임 체인(루트 → 하위 → 손자 …)의 재귀 깊이를 제한합니다.", - "completedCacheLabel": "완료 결과 캐시(MB)", - "completedCacheHint": "실행 중인 위임 세션이 보관하는 완료된 하위 에이전트 결과의 메모리 내 캐시입니다. 해당 세션이 실행되는 동안에만 유지되며 세션이 종료되면 자동으로 삭제됩니다. 이 예산을 초과하면 오래된 결과부터 메모리에서 삭제됩니다(하위 에이전트 자체 세션에서는 계속 확인 가능). 0은 무제한(세션 종료 시에는 그래도 삭제됨).", - "save": "저장", - "saving": "저장 중…", - "saved": "위임 설정이 저장되었습니다", - "saveFailed": "위임 설정 저장 실패", - "loadFailed": "위임 설정 로드 실패: {detail}", - "tabGeneral": "일반", - "tabAgentDefaults": "하위 에이전트 설정", - "agentDefaultsDescription": "다중 에이전트 협업이 위임 호출을 위해 하위 에이전트를 시작할 때 적용되는 재정의 항목입니다. 아래 옵션은 실시간 프로브로 가져오므로 선택한 항목이 그대로 에이전트에 전달됩니다.", - "probing": "에이전트에서 사용 가능한 옵션을 로드 중…", - "probeFailed": "옵션 로드 실패: {detail}", - "retry": "다시 시도", - "noConfigAvailable": "이 에이전트에는 구성 가능한 옵션이 없습니다.", - "modeLabel": "모드", - "agentDefaultHint": "에이전트 기본값: {value}", - "defaultOptionLabel": "기본값 ({value})" - }, - "actions": { - "dragSort": "드래그하여 순서 변경", - "dragSortAgent": "{name} 순서 변경", - "refreshCheck": "다시 확인", - "refreshCheckAgent": "{name} 다시 확인", - "clickEnable": "{name} 활성화", - "clickDisable": "{name} 비활성화", - "install": "설치", - "upgrade": "업그레이드", - "uninstall": "제거", - "uninstalling": "제거 중...", - "saveEnvVars": "환경 변수 저장", - "saving": "저장 중...", - "saveGrokConfig": "Grok 설정 저장", - "saveCodexConfig": "Codex 설정 저장", - "saveGeminiConfig": "Gemini 설정 저장", - "saveOpenCodeConfig": "OpenCode 설정 저장", - "saveOpenClawConfig": "OpenClaw 설정 저장", - "saveConfigManagement": "구성 관리 저장", - "saveCurrentProvider": "현재 Provider 저장", - "showApiKey": "API 키 보기", - "hideApiKey": "API 키 숨기기", - "showKey": "키 보기", - "hideKey": "키 숨기기", - "showToken": "토큰 보기", - "hideToken": "토큰 숨기기", - "cancel": "취소", - "delete": "삭제", - "deleting": "삭제 중...", - "confirmDelete": "삭제 확인", - "confirmUninstall": "제거 확인", - "saveClineConfig": "Cline 설정 저장", - "saveHermesConfig": "Hermes 설정 저장", - "saveCodeBuddyConfig": "CodeBuddy 구성 저장", - "saveKimiCodeConfig": "Kimi Code 구성 저장", - "customInstall": "사용자 지정 설치", - "saveKimiCodeRawConfig": "Save config.toml", - "saveDeepSeekConfig": "DeepSeek 구성 저장", - "diagnose": "진단" - }, - "status": { - "enabled": "활성화됨", - "disabled": "비활성화됨", - "unchecked": "확인 안 됨", - "agentEnabledAria": "{name} 활성화됨", - "agentEnabledSwitch": "{name} 활성화 스위치" - }, - "preflight": { - "count": "사전 점검 항목: {count}", - "notRun": "점검이 아직 실행되지 않았습니다." - }, - "grok": { - "configDescription": "여기에서 Grok을 설정합니다. 아래 컨트롤(권한 모드, 추론 강도, 선택적 사용자 지정(자체 엔드포인트) 모델, 압축)은 ~/.grok/config.toml에 병합되며 다른 키와 주석은 유지됩니다. 로그인은 XAI_API_KEY 또는 `grok login`을 사용합니다. 기타 키는 '고급'에서 편집할 수 있습니다.", - "permissionModeLabel": "권한 모드", - "permissionDefault": "매번 확인", - "permissionAcceptEdits": "편집 자동 승인", - "permissionAuto": "스마트 자동 승인", - "permissionAlwaysApprove": "항상 허용", - "reasoningEffortLabel": "추론 강도", - "effortLow": "낮음(빠름)", - "effortMedium": "중간(균형)", - "effortHigh": "높음", - "effortXhigh": "최대", - "optionDefault": "기본값 사용", - "authTitle": "인증", - "authMode": "인증 방식", - "authModeApiKey": "XAI API 키", - "authModeApiKeyHint": "xAI 콘솔의 XAI_API_KEY로 인증합니다. 비대화형·헤드리스 실행에 적합하며 이 에이전트의 환경 변수에 저장됩니다.", - "authModeCustom": "사용자 지정 엔드포인트", - "authModeCustomHint": "자체 엔드포인트(BYO)를 사용합니다. 아래에서 자체 base URL과 API 키를 가진 사용자 지정 모델을 정의하면 Grok의 기본 모델이 됩니다.", - "subscriptionHint": "`grok login`으로 로그인합니다(SuperGrok / X Premium+). API 키는 저장되지 않습니다.", - "loginHint": "터미널에서 다음 명령을 실행해 로그인한 뒤 이 설정을 다시 여세요:", - "commandCopied": "명령을 클립보드에 복사했습니다", - "copyCommand": "명령 복사", - "authKeyConfigured": "XAI_API_KEY가 구성되어 있습니다.", - "authKeyMissing": "XAI_API_KEY가 설정되지 않았습니다.", - "advancedToggle": "고급(원본 config.toml)", - "configTomlNative": "config.toml(네이티브)", - "configTomlHint": "~/.grok/config.toml 전체로 그대로 저장됩니다. 잘못된 TOML은 거부되어 오타로 파일이 잘리지 않습니다.", - "configTomlPlaceholder": "# 위 컨트롤 이외의 키, 예:\n# [mcp_servers.*], [cli], [permission] 규칙.", - "customModelTitle": "사용자 지정 모델(자체 엔드포인트)", - "customModelHint": "Grok을 사용자 지정 또는 자체 호스팅 엔드포인트로 연결합니다. codeg는 모델별 `[model.*]` 블록을 작성하고 기본 모델로 설정합니다. 모델 ID를 비우면 제거됩니다.", - "customModelIdLabel": "모델 ID", - "customModelIdPlaceholder": "grok-4.5", - "customModelIdHint": "`[model.*]` 블록으로 등록되어 모델 이름으로 API에 전송되며 `[models].default`로도 설정됩니다.", - "customBaseUrlLabel": "Base URL", - "customBaseUrlPlaceholder": "https://api.x.ai/v1(기본값)", - "customApiBackendLabel": "API 백엔드", - "backendResponses": "Responses", - "backendChatCompletions": "Chat Completions", - "backendMessages": "Messages(Anthropic)", - "customApiKeyLabel": "API 키", - "customApiKeyHint": "`[model.*].api_key`에 인라인으로 저장되며 이 엔드포인트에만 적용됩니다.", - "customContextWindowLabel": "컨텍스트 윈도우(토큰)", - "customContextWindowHint": "선택 사항. 자동 압축 타이밍에 사용됩니다. 비워 두면 엔드포인트 기본값을 사용합니다.", - "autoCompactLabel": "자동 압축 임계값(%)", - "autoCompactHint": "컨텍스트 사용량이 이 비율에 도달하면 대화를 압축합니다(Grok 기본값 85). `[session]`에 기록됩니다." - }, - "cursor": { - "configDescription": "여기에서 Cursor를 설정합니다. 먼저 인증 방식을 선택하세요——공식 구독(브라우저 로그인) 또는 헤드리스/서버용 Cursor API 키——그런 다음 모델을 선택하고 CLI의 권한 규칙과 샌드박스를 편집합니다. codeg는 이를 ~/.cursor/cli-config.json에 기록하며 cursor-agent CLI와 공유합니다.", - "authTitle": "인증", - "authChecking": "확인 중…", - "authNotInstalled": "cursor-agent가 설치되지 않았습니다", - "authLoggedIn": "로그인됨", - "authNotLoggedIn": "로그인되지 않음", - "loginHint": "터미널에서 아래 명령을 실행해 Cursor 계정으로 로그인(브라우저가 열립니다)한 뒤 새로고침을 누르세요:", - "apiKeyLabel": "Cursor API 키", - "apiKeyPlaceholder": "cursor.com/dashboard에서 발급", - "apiKeyHint": "CURSOR_API_KEY —— Cursor 대시보드의 계정 키로, 헤드리스/서버 환경에서 브라우저 로그인 대신 사용합니다. 서드파티나 OpenAI 키가 아닙니다.", - "modelTitle": "기본 모델", - "loadModels": "모델 목록 가져오기", - "modelsUnavailable": "모델 목록을 가져올 수 없음", - "modelHint": "세션 시작 시 --model로 CLI에 전달됩니다. 기본값이면 Cursor가 선택합니다.", - "permissionsTitle": "권한 및 샌드박스", - "permissionsDescription": "CLI 권한 규칙(cli-config.json)의 시각 편집기입니다. 허용 규칙은 확인 없이 실행되고 거부 규칙은 항상 차단됩니다.", - "permissionModeLabel": "권한 모드", - "permissionModeDefault": "실행 전 확인(기본)", - "permissionModeForce": "Run Everything(--force)", - "permissionModeHint": "Run Everything은 --force로 세션을 시작합니다. deny 규칙을 제외한 모든 도구 호출이 확인 없이 자동 허용됩니다(조직 정책에 따라 allow 규칙 일치로 제한될 수 있음). 새 세션부터 적용됩니다.", - "optionDefault": "기본(미설정)", - "sandboxLabel": "샌드박스", - "sandboxEnabled": "사용", - "sandboxDisabled": "사용 안 함", - "allowRulesLabel": "허용 규칙", - "denyRulesLabel": "거부 규칙", - "addRule": "규칙 추가", - "rulesSyntaxHint": "규칙 구문: Shell(명령), Read(경로/글롭), Write(경로/글롭), WebFetch(도메인), Mcp(서버:도구) — deny 규칙이 항상 우선합니다.", - "saveConfig": "설정 저장", - "advancedToggle": "고급: 원본 cli-config.json", - "advancedHint": "~/.cursor/cli-config.json 전체입니다. 여기서 저장하면 그대로 기록되며, 위 구조화 컨트롤은 병합 방식으로 기록됩니다.", - "saveRawConfig": "파일 저장", - "authMode": "인증 방식", - "subscriptionHint": "Cursor 계정으로 로그인하고 Cursor의 모델을 사용합니다.", - "customApiKeyRequired": "Cursor API 키가 필요합니다.", - "authModeApiKey": "Cursor API 키 (헤드리스/서버)", - "authModeApiKeyHint": "Cursor 대시보드에서 발급한 계정 API 키로 인증합니다(헤드리스/서버 환경용). 이는 Cursor 계정 키이며 서드파티/OpenAI 엔드포인트가 아닙니다——cursor-agent는 Cursor 자체 백엔드에만 연결됩니다. codex/OpenAI 호환 엔드포인트를 사용하려면 Codex 에이전트를 대신 사용하세요.", - "modelPickerPlaceholder": "모델 검색…", - "modelNoMatch": "일치하는 모델 없음", - "modelsNeedAuth": "로그인하면 모델 목록을 불러옵니다.", - "modelDefaultBadge": "기본값" - }, - "deepseek": { - "configManagement": "DeepSeek Harness 구성", - "configDescription": "엔드포인트와 API 키는 deepseek-acp가 시작할 때 읽는 환경 변수입니다. 모델과 추론 강도는 세션별 선택기이므로 입력창에서 바꿉니다.", - "baseUrlLabel": "API 엔드포인트", - "baseUrlHint": "비워 두면 공식 엔드포인트를 사용합니다. 저장 후 시작하는 세션부터 적용되며, 실행 중인 세션은 다시 연결해야 반영됩니다.", - "baseUrlInvalid": "쿼리 문자열이 없는 완전한 http(s) URL을 입력하세요. 예: https://api.deepseek.com", - "apiKeyLabel": "API 키", - "apiKeyHint": "DEEPSEEK_API_KEY로 에이전트에 전달됩니다. 환경 변수가 자격 증명 파일보다 우선하므로 터미널로 로그인한다면 비워 두세요." - }, - "codex": { - "configDescription": "API URL, API Key, 모델 이름, reasoning effort를 빠르게 설정하고 `auth.json` / `config.toml`과 동기화합니다.", - "authMode": "인증 방식", - "chatgptSubscription": "공식 구독", - "chatgptSubscriptionHint": "ChatGPT 공식 구독으로 로그인, API Key 불필요", - "apiKeyHint": "API Key로 OpenAI 또는 호환 API 서비스에 연결", - "selectProvider": "Provider 선택", - "modelName": "모델 이름", - "selectReasoningEffort": "Reasoning Effort 선택", - "enableWebsocket": "WebSocket 활성화", - "enableWebsocketAria": "Codex Provider용 WebSocket 활성화", - "enableSkills": "Skills 활성화", - "enableSkillsAria": "Codex용 Skills 활성화", - "enableFast": "Fast 활성화", - "enableFastAria": "Codex용 Fast 서비스 계층 활성화", - "sandboxGroupTitle": "샌드박스 및 승인", - "sandboxGroupHint": "전역 ~/.codex/config.toml에 기록되므로 codex CLI와 IDE 세션에도 적용됩니다. 스레드 기본값이며 codex가 스스로 시작하는 턴(/goal, /review, /compact)에만 적용됩니다. 일반 프롬프트는 입력창의 승인 프리셋을 사용합니다. 변경 사항은 세션을 다시 시작해야 반영됩니다.", - "sandboxShadowedWarning": "config.toml에 default_permissions가 설정되어 있어 codex가 권한 프로필로 해석하고 sandbox_mode를 완전히 무시합니다. 아래 설정을 사용하려면 default_permissions를 제거하세요.", - "sandboxPermissionsTableWarning": "config.toml에 [permissions] 프로필이 있지만 default_permissions가 없어 codex가 시작을 거부합니다. 아래 원본 편집기에서 설정하세요.", - "approvalPolicyLabel": "승인 정책", - "approvalPolicyUnset": "설정 안 함(codex 기본값: 요청 시)", - "approvalPolicy_on-request": "요청 시 — 모델이 확인 시점을 결정", - "approvalPolicy_untrusted": "신뢰 안 함 — 안전이 확인된 읽기 전용 명령만 자동 실행", - "approvalPolicy_never": "묻지 않음 — 승인 창을 전혀 띄우지 않음", - "approvalPolicy_granular": "세부 설정 — 프롬프트 종류별로 지정", - "approvalPolicyUntrustedAcpWarning": "ACP 어댑터의 세 가지 승인 프리셋에는 untrusted에 해당하는 항목이 없으므로 codeg 세션은 \"요청 시\"로 대체됩니다. 이 경우 모델이 물어볼 시점을 스스로 정하며, 샌드박스가 이미 허용한 명령은 더 이상 확인하지 않습니다. 대신 아래 샌드박스 모드로 제한하세요.", - "granularHint": "끄면 해당 종류의 요청은 표시되지 않고 자동으로 거부됩니다.", - "granular_sandbox_approval": "셸 명령 권한 상승", - "granular_rules": "Execpolicy 규칙 프롬프트", - "granular_skill_approval": "스킬 스크립트 프롬프트", - "granular_request_permissions": "request_permissions 도구 프롬프트", - "granular_mcp_elicitations": "MCP elicitation 프롬프트", - "sandboxModeLabel": "샌드박스 모드", - "sandboxModeUnset": "설정 안 함(신뢰된 폴더는 워크스페이스 쓰기로 대체)", - "sandboxMode_read-only": "읽기 전용", - "sandboxMode_workspace-write": "워크스페이스 쓰기", - "sandboxMode_danger-full-access": "전체 접근(샌드박스 없음)", - "sandboxModeHint": "Windows에서는 codex의 실험적 Windows 샌드박스를 켜지 않으면 워크스페이스 쓰기가 읽기 전용으로 낮아집니다.", - "sandboxModeSeedsPresetHint": "codeg는 이 값으로 세션의 초기 승인 프리셋도 정하므로, 승인 정책과 달리 일반 프롬프트에도 적용됩니다. 입력창에서 선택한 프리셋이 이를 덮어씁니다.", - "writableRootsLabel": "추가 쓰기 가능 폴더", - "writableRootsHint": "작업 디렉터리 외에 허용할 절대 경로를 한 줄에 하나씩.", - "sandboxRootsRelativeError": "절대 경로여야 합니다 — codex는 상대 경로를 ~/.codex 기준으로 해석합니다: {path}", - "networkAccessLabel": "네트워크 접근 허용", - "excludeTmpdirLabel": "쓰기 가능 루트에서 TMPDIR 제외", - "excludeSlashTmpLabel": "쓰기 가능 루트에서 /tmp 제외", - "authJsonNative": "auth.json (네이티브)", - "configTomlNative": "config.toml (네이티브)", - "loginButton": "ChatGPT로 로그인", - "loginRequesting": "로그인 코드 요청 중...", - "loginStep1": "브라우저에서 다음 URL을 열어주세요:", - "loginStep2": "아래 코드를 입력하세요:", - "loginPolling": "인증 대기 중...", - "loginCancel": "취소", - "loginSuccess": "로그인 성공, 설정이 저장되었습니다!", - "loginFailed": "로그인 실패: {message}", - "loginRetry": "재시도", - "loginCodeCopied": "코드가 복사되었습니다", - "loggedIn": "계정 로그인됨", - "loginRelogin": "재로그인 / 계정 전환", - "loginTimeout": "로그인 시간 초과, 다시 시도해 주세요", - "loginSaveFailed": "로그인 성공했지만 설정 저장 실패" - }, - "gemini": { - "authConfig": "Gemini 인증 설정", - "authConfigDescription": "Gemini CLI 인증 문서와 정렬되며, 커스텀 엔드포인트, Google 로그인, Gemini API Key, Vertex AI(ADC / 서비스 계정 / API Key)를 지원합니다.", - "authMode": "인증 모드", - "selectAuthMode": "인증 모드 선택", - "viewAuthDoc": "인증 문서 보기", - "mode": { - "custom": "커스텀 엔드포인트", - "loginGoogle": "Google 로그인 (OAuth)", - "vertexServiceAccount": "Vertex AI (서비스 계정)" - }, - "hint": { - "custom": "API URL, API Key, Model을 입력하세요. GOOGLE_GEMINI_BASE_URL / GEMINI_API_KEY / GEMINI_MODEL에 매핑됩니다.", - "loginGoogle": "먼저 터미널에서 gemini를 실행해 Google 로그인을 완료하세요. API key는 필요하지 않습니다.", - "geminiApiKey": "Gemini API 사용 시 GEMINI_API_KEY를 입력하세요.", - "vertexAdc": "gcloud ADC를 사용합니다. GOOGLE_CLOUD_PROJECT와 GOOGLE_CLOUD_LOCATION 설정을 권장합니다.", - "vertexServiceAccount": "서비스 계정 JSON 경로를 GOOGLE_APPLICATION_CREDENTIALS에 설정하세요.", - "vertexApiKey": "Vertex AI API key 사용 시 GOOGLE_API_KEY를 입력하세요." - } - }, - "openCode": { - "configManagement": "OpenCode 구성 관리", - "configDescription": "OpenCode `provider` 스키마에 맞추어 다중 Provider 관리와 네이티브 JSON 파일 양방향 동기화를 지원합니다.", - "providerManagement": "Provider 관리", - "providerCount": "Provider {count}개", - "addProvider": "Provider 추가", - "emptyProvider": "아직 사용자 지정 공급자가 없습니다. '사용자 지정 공급자 추가'를 클릭해 만드세요.", - "providerEnabledState": "{providerId} 활성 상태", - "selectProviderNpm": "provider.npm 선택", - "modelManagement": "모델 관리", - "modelCount": "모델 {count}개", - "modelDescription": "OpenCode `provider.models`와 정렬됩니다. 빠른 관리는 현재 `name` / `id`를 지원하며, 기타 고급 필드는 유지되고 아래 네이티브 JSON에서 편집할 수 있습니다.", - "addModel": "모델 추가", - "emptyModel": "아직 모델이 없습니다. model id를 입력한 뒤 \"모델 추가\"를 클릭하세요.", - "modelId": "모델 ID", - "modelName": "모델 이름", - "deleteModel": "모델 {modelId} 삭제", - "nativeJsonConfig": "OpenCode 네이티브 JSON 구성", - "mainModel": "메인 모델", - "smallModel": "스몰 모델", - "noMatchingModels": "일치하는 모델 없음", - "connectProvider": "공급자 연결", - "connectedProviders": "연결된 공급자", - "noConnectedProviders": "아직 카탈로그 공급자를 연결하지 않았습니다.", - "advancedProviderConfig": "사용자 지정 공급자", - "customProviderConfigHint": "직접 정의하는 OpenAI 호환 엔드포인트입니다 — opencode.json의 provider 블록이며 API 키는 auth.json에 저장됩니다.", - "addCustomProvider": "사용자 지정 공급자 추가", - "disconnect": "연결 해제", - "editConfig": "편집", - "customBadge": "사용자 지정", - "authKindApi": "API 키", - "authKindOauth": "OAuth", - "authKindNone": "자격 증명 없음", - "connect": { - "title": "공급자 연결", - "description": "models.dev 카탈로그에서 공급자를 선택하세요. 자격 증명은 OpenCode의 auth.json 파일에 저장됩니다.", - "pick": "공급자", - "search": "공급자 검색…", - "loading": "카탈로그 불러오는 중…", - "catalogLabel": "models.dev 카탈로그", - "modelsAvailable": "{count}개 모델 사용 가능", - "getKey": "API 키 받기", - "oauthApiKeyNote": "이 공급자는 opencode auth login을 통한 브라우저 로그인도 지원합니다. 브라우저 로그인은 곧 제공됩니다. 지금은 API 키를 붙여넣으세요.", - "apiKey": "API 키", - "apiKeyHint": "auth.json에 저장되며 opencode.json에는 저장되지 않습니다.", - "baseUrlOptional": "Base URL 재정의 (선택)", - "providerId": "공급자 ID", - "displayName": "표시 이름", - "modelsList": "모델 (한 줄에 하나)", - "modelsHint": "엔드포인트가 허용하는 모델 ID.", - "action": "연결", - "editTitle": "공급자 편집", - "editDescription": "이 공급자의 API 키 또는 Base URL을 업데이트합니다.", - "saveAction": "저장" - }, - "customProvider": { - "title": "사용자 지정 공급자 추가", - "description": "OpenAI 호환 엔드포인트를 정의합니다. API 키는 auth.json에, provider 블록은 opencode.json에 저장됩니다.", - "action": "공급자 추가", - "idInCatalog": "{providerId}은(는) 알려진 공급자입니다. 대신 '공급자 연결'로 연결하세요." - }, - "refreshCatalog": "카탈로그 새로고침", - "reasoningBadge": "추론", - "contextWindow": "컨텍스트 윈도우", - "permissions": { - "title": "권한", - "description": "어떤 작업을 바로 실행할지, 먼저 확인할지, 차단할지 정합니다. opencode.json 의 permission 설정에 기록되며 아래에서 저장하면 적용됩니다.", - "docsLink": "권한 문서", - "unparsableConfig": "아래 네이티브 JSON 을 해석할 수 없어 시각적 편집을 멈췄습니다. JSON 을 고치면 다시 사용할 수 있습니다.", - "invalidBlock": "permission 설정의 형태를 인식할 수 없습니다. 아래 네이티브 JSON 에서 수정하거나 [초기화] 로 다시 시작하세요.", - "orderingUnsafe": "와일드카드 규칙이 개별 도구보다 뒤에 적혀 있어 OpenCode 가 그 도구들에도 적용합니다. 아래 행은 실제로 적용되는 값이 아닙니다. [순서 수정] 은 값을 바꾸지 않고 와일드카드를 각 범위 맨 앞으로 되돌립니다.", - "orderingUnsafeManual": "어떤 규칙이 뒤의 더 넓은 패턴에 가려져 OpenCode 가 절대 적용하지 않습니다. 아래 행은 실제로 적용되는 값이 아닙니다. 겹치는 두 패턴에는 정답인 순서가 없으므로, 아래 네이티브 JSON 에서 더 넓은 쪽을 앞으로 옮기세요.", - "fixOrder": "순서 수정", - "agentOverrides": "다음 에이전트가 권한을 재정의하며 마지막에 적용되므로 여기 설정보다 우선합니다: {agents}. 아래 네이티브 JSON 에서 수정하거나 자동 수락을 켜서 지우세요.", - "legacyTools": "최상위 레거시 tools 설정이 어떤 도구를 거부하고 있습니다. OpenCode 가 이를 권한에 합치므로 여기 표시된 모든 설정 위에 적용됩니다. 아래 네이티브 JSON 에서 수정하거나 자동 수락을 켜서 지우세요.", - "autoAcceptTitle": "모든 권한 자동 수락", - "autoAcceptHint": "셸 명령, 파일 수정, 프로젝트 밖 경로를 포함한 모든 도구 호출을 묻지 않고 실행합니다. 켜면 아래 도구별 설정이 전체 허용 규칙 하나로 대체되고, 그대로 두면 계속 막을 에이전트별 권한 재정의와 레거시 tools 설정도 지워집니다.", - "globalLabel": "전역 기본값", - "globalHint": "* 규칙입니다. 아래 도구에서 따로 지정하지 않은 모든 경우에 적용됩니다.", - "actionUnset": "설정 안 함 (OpenCode 기본값)", - "actionInherit": "기본값 따름 ({action})", - "actionAllow": "허용", - "actionAsk": "확인", - "actionDeny": "거부", - "perToolTitle": "도구별 권한", - "reset": "초기화", - "ruleCount": "규칙: {count}", - "rulesToggle": "{tool} 의 세부 규칙", - "rulesHint": "도구 입력과 대조하며 마지막으로 일치한 규칙이 우선하므로 넓은 패턴을 먼저 적으세요. * 는 임의의 문자열, ? 는 정확히 한 글자와 일치하고 맨 앞의 ~ 는 홈 디렉터리로 확장됩니다.", - "noRules": "아직 세부 규칙이 없습니다.", - "addRule": "규칙 추가", - "deleteRule": "규칙 {pattern} 삭제", - "duplicateRule": "이미 있는 패턴입니다.", - "blankRule": "규칙에는 패턴이 필요합니다. 삭제하려면 휴지통 아이콘을 사용하세요.", - "customKeys": "파일에 있는 다른 권한 키", - "customKeyHint": "OpenCode 기본 도구가 아니며 작성된 그대로 유지됩니다.", - "keys": { - "bash": "셸 명령 실행, 파싱된 명령으로 대조", - "edit": "모든 파일 수정: edit, write, patch", - "read": "파일 읽기, 경로로 대조", - "external_directory": "프로젝트 작업 디렉터리 밖 경로 접근", - "task": "서브에이전트 실행, 서브에이전트 유형으로 대조", - "skill": "스킬 로드, 스킬 이름으로 대조", - "glob": "파일 찾기, 글로브 패턴으로 대조", - "grep": "파일 내용 검색, 패턴으로 대조", - "list": "디렉터리 내용 나열", - "webfetch": "URL 가져오기", - "websearch": "웹 검색", - "lsp": "LSP 질의 실행", - "todowrite": "할 일 목록 작성", - "question": "사용자에게 질문", - "doom_loop": "같은 호출이 같은 입력으로 3 번 반복되면 작동" - } - } - }, - "openClaw": { - "gatewayConfig": "Gateway 구성", - "gatewayDescription": "OpenClaw Gateway 연결을 구성합니다. 로컬 또는 원격 gateway를 지원합니다.", - "gatewayUrlHint": "비워두면 로컬 openclaw 설정의 gateway.remote.url을 사용합니다.", - "gatewayTokenPlaceholder": "Gateway 인증 토큰", - "gatewayTokenHint": "가능하면 평문 토큰 대신 token-file을 사용하세요. openclaw CLI로 설정하세요.", - "sessionKeyHint": "선택 사항입니다. gateway 세션 키를 지정합니다. 비워두면 격리된 세션이 자동 할당됩니다." - }, - "hermes": { - "configManagement": "Hermes 구성", - "configDescription": "Hermes는 자격 증명을 ~/.hermes/.env에, 설정을 ~/.hermes/config.yaml에 직접 관리합니다. 공급자를 선택한 다음 API 키와 모델을 설정하세요. codeg가 두 파일을 모두 작성해 줍니다.", - "providerLabel": "공급자", - "providerHint": "공급자에 따라 Hermes가 사용하는 API 키 변수와 model.provider가 결정됩니다. OAuth 공급자는 아래 터미널 설정을 통해 구성합니다.", - "groupApiKey": "API 키 제공자", - "groupOauth": "OAuth 제공자", - "groupAws": "AWS", - "apiKeyHint": "~/.hermes/.env에 저장됩니다. 프로세스에 절대 주입되지 않으며, Hermes가 자체 구성에서 읽어옵니다.", - "modelName": "모델", - "oauthHint": "이 공급자는 OAuth를 사용합니다. 아래 설정을 실행하여 터미널에서 인증하세요.", - "awsHint": "Bedrock은 AWS 자격 증명(환경 변수 또는 공유 구성)을 사용합니다. 위에서 모델 ID를 설정하고 환경에서 AWS 액세스를 구성하세요.", - "unsupportedProvider": "이 제공자는 구조화된 필드로 편집할 수 없습니다. 아래의 config.yaml 원본 편집기나 터미널 설정을 사용하세요.", - "setupTitle": "자체 관리 설정", - "setupHint": "Hermes의 대화형 설정에는 터미널이 필요합니다. 아래에서 실행하거나 명령을 복사하여 직접 실행하세요.", - "runSetup": "Hermes 설정 실행", - "configureModel": "모델 구성", - "openConfigFolder": "~/.hermes 열기", - "copyCommand": "명령 복사", - "commandCopied": "명령을 클립보드에 복사했습니다", - "advancedTitle": "고급: config.yaml 편집", - "rawConfigHint": "~/.hermes/config.yaml을 직접 편집합니다. 여기서 저장하면 파일이 그대로 덮어쓰여집니다.", - "saveRawConfig": "config.yaml 저장" - }, - "codebuddy": { - "configManagement": "CodeBuddy 구성", - "configDescription": "CodeBuddy는 API 키로 인증합니다. 중국 버전은 환경을 ‘중국(internal)’으로 설정해야 하며, iOA 버전은 ‘iOA’를 사용하고, 해외 버전은 설정하지 않습니다.", - "apiKeyLabel": "API 키", - "apiKeyHint": "이 에이전트의 CODEBUDDY_API_KEY로 저장됩니다. 또는 터미널에서 CodeBuddy CLI로 로그인할 수도 있습니다.", - "apiKeyHintSelfHosted": "이 에이전트의 CODEBUDDY_API_KEY로 저장됩니다. 비공개 배포에서 발급한 키를 사용하세요.", - "environmentLabel": "환경", - "environmentHint": "CODEBUDDY_INTERNET_ENVIRONMENT를 설정합니다. 중국 본토는 ‘중국(internal)’을 사용해야 하며, 해외 버전은 설정하지 않습니다.", - "envOverseas": "해외(기본값)", - "envChina": "중국(internal)", - "envIoa": "iOA", - "envSelfHosted": "프라이빗 배포(자체 호스팅)", - "baseUrlLabel": "배포 URL", - "baseUrlPlaceholder": "https://codebuddy.your-company.com", - "baseUrlHint": "CODEBUDDY_BASE_URL로 저장되어 CodeBuddy를 비공개 엔드포인트로 연결합니다. 자체 호스팅에서는 네트워크 환경(CODEBUDDY_INTERNET_ENVIRONMENT)을 설정하지 않습니다.", - "baseUrlInvalid": "유효한 http(s) URL을 입력하세요.", - "loginHint": "API 키가 없나요? 터미널에서 ‘codebuddy’를 실행하여 Tencent 계정으로 로그인할 수도 있습니다." - }, - "kimiCode": { - "configManagement": "Kimi Code 설정", - "configDescription": "`kimi acp`는 저장된 로그인 토큰만 인정하므로, codeg가 ~/.kimi-code/config.toml에 관리형 공급자를 기록하고 로컬에 게이트 토큰을 심습니다. 추론은 여전히 사용자의 키로 실행됩니다.", - "statusUnconfigured": "아직 설정되지 않음", - "statusDirty": "저장되지 않은 변경 사항", - "summaryLabel": "적용된 설정", - "gateReadyApiKey": "API 키가 config.toml에 기록됨", - "gateReadyLogin": "Kimi 계정으로 로그인됨", - "revealConfig": "폴더에서 보기", - "envOverrideWarning": "{keys}이(가) 설정되어 있으며 config.toml보다 우선합니다. 여기서 저장하면 자동으로 삭제됩니다.", - "authModeLabel": "인증 방식", - "authModeApiKey": "API 키", - "authModeLogin": "Kimi 계정 로그인(구독)", - "authModeApiKeyHint": "config.toml에 관리형 공급자를 기록하고, 세션이 열리도록 게이트 토큰을 심습니다.", - "loginHint": "터미널에서 `kimi login`을 실행해 Kimi 구독 계정으로 로그인하세요. codeg는 자격 증명을 저장하지 않고 Kimi 자체 로그인을 재사용합니다. 여기서 저장하면 codeg의 API 키 게이트 토큰이 제거됩니다.", - "credentialTitle": "자격 증명", - "interfaceTypeLabel": "공급자 유형", - "interfaceTypeHint": "Kimi가 사용하는 공급자 프로토콜(config.toml의 `type`). Moonshot / platform.kimi.com 키라면 「Kimi / Moonshot」을 선택하세요.", - "endpointLabel": "엔드포인트", - "endpointCustom": "사용자 지정(OpenAI 호환)", - "endpointHint": "국제 = api.moonshot.ai, 중국(platform.kimi.com 키) = api.moonshot.cn. 사용자 지정은 모든 OpenAI 호환 엔드포인트를 가리킬 수 있습니다.", - "regionInternational": "국제(api.moonshot.ai)", - "regionChina": "중국(api.moonshot.cn)", - "baseUrlLabel": "Base URL", - "baseUrlHint": "비워 두면 공급자 SDK 기본값을 사용합니다.", - "apiKeyLabel": "API 키", - "apiKeyHint": "~/.kimi-code/config.toml에 기록되어 추론에 사용됩니다. platform.kimi.com 또는 platform.kimi.ai에서 발급받습니다.", - "vertexProjectLabel": "GCP 프로젝트(GOOGLE_CLOUD_PROJECT)", - "vertexLocationLabel": "GCP 리전(GOOGLE_CLOUD_LOCATION)", - "vertexHint": "Vertex AI는 Google 애플리케이션 기본 자격 증명을 사용합니다. `gcloud auth application-default login`을 실행하세요(API 키 불필요).", - "modelTitle": "모델", - "modelLabel": "모델", - "modelHint": "config.toml에 기록되는 모델 id입니다. 「테스트 후 모델 가져오기」로 키가 실제로 접근 가능한 모델을 확인하세요.", - "maxContextLabel": "최대 컨텍스트 길이", - "maxContextHint": "Kimi 스키마에서 필수입니다. 값이 없으면 Kimi가 모델 블록 전체를 버려 모든 프롬프트가 응답 없이 끝납니다. 기본값은 262144입니다.", - "fetchModels": "테스트 후 모델 가져오기", - "fetchModelsOk": "키 정상 — 모델 {count}개 사용 가능", - "fetchModelsEmpty": "키는 정상이지만 반환된 모델이 없습니다", - "fetchModelsFailed": "테스트 실패", - "fetchModelsNeedsKey": "먼저 API 키와 엔드포인트를 입력하세요", - "modelNotInList": "이 모델은 키가 접근할 수 있는 목록에 없습니다. Kimi가 「모델을 찾을 수 없음」으로 실패합니다.", - "reasoningTitle": "추론", - "reasoningEnableLabel": "사용", - "reasoningDescription": "모델이 추론 기능을 선언한 경우에만 Kimi가 입력창에 「Thinking」선택기를 표시하므로, codeg가 여기서 그 선언을 기록합니다. 새 세션부터 적용됩니다.", - "effortsLabel": "제공할 단계", - "effortsHint": "여기서 고른 값이 입력창 「Thinking」선택기의 항목이 됩니다. Kimi는 단계를 공급자에게 그대로 전달하므로 모델이 받아들이는 값을 고르세요.", - "effortsEmptyHint": "단계를 하나도 고르지 않으면 입력창은 Off / On 2단 토글로 축소됩니다.", - "effortsCustomPlaceholder": "다른 단계 추가", - "effortsAdd": "추가", - "defaultEffortLabel": "기본 단계", - "defaultEffortAuto": "Kimi에 맡기기", - "alwaysThinkingLabel": "모델이 항상 추론함 — 선택기에서 Off 항목 제거", - "fixErrorsFirst": "먼저 표시된 항목을 수정하세요", - "errorModelRequired": "모델은 필수 항목입니다", - "errorMaxContextRequired": "최대 컨텍스트 길이는 필수 항목입니다", - "errorMaxContextInvalid": "양의 정수여야 합니다", - "errorApiKeyRequired": "API 키는 필수 항목입니다", - "errorApiKeyInvalid": "API 키에는 줄바꿈을 포함할 수 없습니다", - "errorBaseUrlRequired": "Base URL은 필수 항목입니다", - "errorBaseUrlInvalid": "http:// 또는 https://로 시작해야 합니다", - "errorVertexProjectRequired": "GCP 프로젝트는 필수 항목입니다", - "errorDefaultEffortUnlisted": "위에서 선택한 단계 중 하나여야 합니다", - "advancedTitle": "고급", - "authTypeLabel": "자격 증명 기록 위치", - "authTypeApiKey": "인라인 api_key", - "authTypeEnv": "공급자 env 하위 테이블", - "authTypeHint": "config.toml 안에서 API 키를 기록할 위치입니다.", - "rawEditorLabel": "config.toml 직접 편집", - "rawEditorWarning": "여기서 저장하면 파일 전체가 그대로 덮어써져 위의 구조화된 설정이 대체됩니다.", - "rawEditorPlaceholder": "[providers.codeg]\ntype = \"kimi\"\nbase_url = \"https://api.moonshot.cn/v1\"\napi_key = \"sk-...\"" - }, - "authModeOfficialSubscription": "공식 구독", - "authModeCustomEndpoint": "사용자 정의 엔드포인트", - "authModeCustomEndpointHint": "API URL과 API Key를 수동으로 구성하여 사용자 정의 엔드포인트에 연결합니다.", - "authModeModelProvider": "모델 공급자", - "modelProvider": "모델 공급자", - "modelProviderHint": "구성된 모델 공급자의 API URL, API Key 및 모델을 사용합니다.", - "selectModelProvider": "모델 공급자 선택", - "noModelProviderAvailable": "이 에이전트에 구성된 모델 공급자가 없습니다. 모델 공급자 설정에서 추가하세요.", - "claude": { - "authMode": "인증 방식", - "officialSubscription": "공식 구독", - "officialSubscriptionHint": "Anthropic 공식 구독 사용, API Key 불필요.", - "mainModel": "메인 모델", - "reasoningModel": "추론 모델 (thinking)", - "haikuDefaultModel": "기본 Haiku 모델", - "sonnetDefaultModel": "기본 Sonnet 모델", - "opusDefaultModel": "기본 Opus 모델", - "customModelOption": "사용자 지정 모델 ID", - "customModelOptionName": "사용자 지정 모델 이름", - "customModelOptionDescription": "사용자 지정 모델 설명", - "customModelOptionHint": "Claude 모델 선택기에 사용자 지정 항목 하나를 추가합니다(예: 사용자 지정 게이트웨이/프록시를 통해 제공되는 모델). 이름과 설명은 선택적 표시 설정입니다.", - "effortLevel": "추론 수준", - "effortLevelDefault": "기본 수준", - "effortLevel_low": "낮음", - "effortLevel_medium": "중간", - "effortLevel_high": "높음", - "effortLevel_xhigh": "매우 높음", - "sendAttributionHeader": "API에 속성/청구 식별자 전송", - "sendAttributionHeaderAria": "API에 Claude Code 속성/청구 식별자 전송", - "disableNonessentialTraffic": "텔레메트리 또는 불필요한 네트워크 요청 비활성화", - "disableNonessentialTrafficAria": "Claude Code 텔레메트리 또는 불필요한 네트워크 요청 비활성화" - }, - "dialogs": { - "confirmDeleteProvider": "Provider {providerId}를 삭제하시겠습니까?", - "confirmDeleteProviderDescription": "OpenCode config와 auth JSON이 함께 업데이트됩니다. 이 작업은 되돌릴 수 없습니다.", - "confirmUninstall": "{name}을(를) 제거하시겠습니까?", - "confirmUninstallDescription": "로컬 설치 버전을 제거합니다. 나중에 다시 설치할 수 있습니다.", - "customInstallTitle": "{name} 사용자 지정 설치", - "customInstallDescription": "설치할 버전을 입력하세요. 다시 설치되며 현재 설치된 버전을 대체합니다.", - "customInstallVersionLabel": "버전 번호", - "customInstallInvalid": "유효한 버전 번호를 입력하세요. 예: 1.2.3", - "customInstallSubmit": "설치" - }, - "errors": { - "windowsFileLocked": "{name}의 파일이 실행 중인 세션에서 사용 중이어서 Windows에서 교체할 수 없습니다. 모든 {name} 세션을 닫은 후 다시 시도하세요.", - "nativeJsonMustBeObject": "네이티브 JSON 구성은 객체여야 합니다", - "nativeJsonInvalid": "네이티브 JSON 구성 형식 오류: {message}", - "openCodeAuthMustBeObject": "OpenCode auth.json은 JSON 객체여야 합니다", - "openCodeAuthInvalid": "OpenCode auth.json 형식 오류: {message}", - "authMustBeObject": "auth.json은 JSON 객체여야 합니다", - "authInvalid": "auth.json 형식 오류: {message}", - "providerIdPattern": "Provider ID는 문자, 숫자, 밑줄, 점, 하이픈만 지원합니다", - "providerExists": "Provider {providerId}가 이미 존재합니다", - "modelIdPattern": "Model ID는 문자, 숫자, 밑줄, 점, 콜론, 하이픈만 지원합니다", - "modelExists": "Model {modelId}가 이미 존재합니다" - }, - "warnings": { - "nativeJsonRecoveredStructured": "네이티브 JSON 구성이 잘못되어 구조화 구성으로 재설정했습니다", - "nativeJsonRecoveredOpenCode": "네이티브 JSON 구성이 잘못되어 OpenCode 구조화 구성으로 재설정했습니다", - "openCodeAuthRecovered": "OpenCode auth.json이 잘못되어 기본 구성으로 재설정했습니다", - "authRecoveredStructured": "auth.json이 잘못되어 구조화 구성으로 재설정했습니다" - }, - "toasts": { - "agentActionCompleted": "{name} {action} 완료", - "agentActionFailed": "{name} {action} 실패", - "localVersion": "로컬 버전: {version}", - "installCompletedVersionLater": "설치가 완료되었습니다. 버전은 다음 확인 시 업데이트됩니다", - "uninstallCompleted": "{name} 제거 완료", - "uninstallFailed": "{name} 제거 실패", - "localVersionRemoved": "로컬 버전이 제거되었습니다", - "saveAgentOrderFailed": "Agent 순서 저장 실패", - "saveAgentSwitchFailed": "Agent 스위치 저장 실패", - "saveEnvFailed": "환경 변수 저장 실패", - "grokSaved": "Grok 설정이 저장됨", - "saveGrokNativeFailed": "Grok 네이티브 설정 저장 실패", - "saveGrokApiKeyFailed": "설정은 저장되었지만 API 키를 저장하지 못했습니다", - "cursorSaved": "Cursor 설정이 저장되었습니다", - "saveCursorConfigFailed": "Cursor 설정 저장 실패", - "codexSaved": "Codex 설정 저장됨", - "saveCodexNativeFailed": "Codex 네이티브 구성 저장 실패", - "geminiSaved": "Gemini 설정 저장됨", - "saveGeminiFailed": "Gemini 설정 저장 실패", - "providerDeleted": "Provider {providerId} 삭제됨", - "providerDeleteFailed": "Provider {providerId} 삭제 실패", - "providerSaved": "Provider {providerId} 저장됨", - "saveProviderFailed": "Provider {providerId} 저장 실패", - "openCodeConfigSynced": "OpenCode config와 auth JSON이 동기화되었습니다.", - "openCodeSaved": "OpenCode 설정 저장됨", - "saveOpenCodeFailed": "OpenCode 설정 저장 실패", - "openClawSaved": "OpenClaw 설정 저장됨", - "saveOpenClawFailed": "OpenClaw 설정 저장 실패", - "configSaved": "구성이 저장되었습니다", - "configSavedHint": "기존 세션은 다시 열어야 적용됩니다", - "saveConfigManagementFailed": "구성 관리 저장 실패", - "clineSaved": "Cline 설정 저장됨", - "saveClineFailed": "Cline 설정 저장 실패", - "hermesSaved": "Hermes 설정 저장됨", - "saveHermesFailed": "Hermes 설정 저장 실패", - "codeBuddySaved": "CodeBuddy 구성이 저장되었습니다", - "saveCodeBuddyFailed": "CodeBuddy 구성 저장에 실패했습니다", - "kimiCodeSaved": "Kimi Code 구성이 저장되었습니다", - "saveKimiCodeFailed": "Kimi Code 구성 저장 실패", - "deepseekSaved": "DeepSeek 구성을 저장했습니다", - "saveDeepSeekFailed": "DeepSeek 구성 저장 실패", - "modelProviderRequired": "저장하기 전에 모델 공급자를 선택하세요.", - "affectedRunningSessions": "{count}개의 실행 중인 세션은 다시 연결하면 변경 사항이 적용됩니다", - "providerConnected": "{providerId} 연결됨", - "connectFailed": "{providerId} 연결 실패", - "providerDisconnected": "{providerId} 연결 해제됨", - "disconnectFailed": "{providerId} 연결 해제 실패", - "catalogRefreshed": "카탈로그를 새로고침했습니다 — 공급자 {count}개", - "catalogRefreshFailed": "카탈로그 새로고침 실패", - "piSaved": "Pi 설정이 저장됨", - "savePiFailed": "Pi 설정 저장 실패", - "piRuntimeSaved": "Pi 런타임이 저장됨", - "savePiRuntimeFailed": "Pi 런타임 저장 실패", - "piBinaryInstalled": "pi 설치됨", - "piBinaryInstallFailed": "pi 설치 실패", - "piBinaryUninstalled": "pi 제거됨", - "piBinaryUninstallFailed": "pi 제거 실패", - "savePiTrustFailed": "작업 공간 신뢰 저장 실패" - }, - "version": { - "statusLabel": "버전 상태", - "notInstalled": "설치되지 않음", - "remoteLocal": "원격: {remoteVersion} · 로컬: {localVersion}", - "localOnly": "로컬: {localVersion}", - "localInstalled": "{versionText}. 설치되어 있습니다.", - "platformUnsupported": "{versionText}. 현재 플랫폼에서는 이 에이전트를 지원하지 않습니다.", - "uvxNotReady": "{versionText}. uv 런타임이 설치되지 않았습니다. 아래 uv 검사에서 설치하면 이 에이전트를 사용할 수 있습니다.", - "clickInstall": "{versionText}. 오른쪽의 설치를 클릭하세요.", - "localUnrecognized": "{versionText}. 로컬 버전을 비교할 수 없습니다. 덮어쓰기 설치를 위해 업그레이드를 시도하세요.", - "upgradeAvailable": "{versionText}. 업그레이드가 가능합니다.", - "remoteUnavailable": "{versionText}. 현재 원격 버전을 사용할 수 없습니다.", - "latest": "{versionText}. 이미 최신입니다." - }, - "adapter": { - "label": "ACP 어댑터", - "badge": "ACP 어댑터", - "badgeHint": "이 에이전트에 대해 Codeg가 설치하는 것은 벤더 CLI가 아니라 ACP 어댑터 패키지입니다. 둘은 서로 독립적이며 설정을 공유합니다.", - "learnMore": "자세히 보기", - "missingWithNative": "사용 중인 {nativeLabel}을(를) {nativePath}에서 찾았습니다. Codeg는 에이전트를 ACP로 구동하는데 이 CLI 자체는 ACP를 지원하지 않으므로, 별도의 어댑터 패키지 {adapterPackage}(Agent Client Protocol 프로젝트가 관리, 처음에는 Zed 팀)가 필요합니다. 자체 런타임을 포함하고 있어 기존 {nativeCmd} 명령을 수정하거나 대체하지 않으며, 같은 {configDir}를 읽으므로 기존 로그인과 설정이 그대로 적용됩니다. 아래에서 설치하세요.", - "missing": "Codeg는 에이전트를 ACP로 구동하는데 {nativeLabel} 자체는 ACP를 지원하지 않으므로, 별도의 어댑터 패키지 {adapterPackage}(Agent Client Protocol 프로젝트가 관리, 처음에는 Zed 팀)가 필요합니다. 자체 런타임을 포함하므로 {nativeCmd} CLI를 먼저 설치할 필요는 없습니다. 이미 설치했다면 둘은 공존하며 {configDir}의 로그인과 설정을 공유합니다. 아래에서 설치하세요.", - "readyWithNative": "어댑터 {adapterCmd}가 설치되어 있습니다. Codeg가 실행하는 것은 이 어댑터이며, {nativePath}에 있는 사용자의 {nativeCmd}가 아닙니다. 둘은 독립된 패키지로 공존하고 모두 {configDir}를 읽으므로 로그인과 설정을 공유합니다.", - "ready": "어댑터 {adapterCmd}가 설치되어 있으며 Codeg가 실행하는 것이 바로 이것입니다. 자체 런타임을 포함하므로 {nativeLabel}은 필요하지 않습니다. 나중에 설치해도 둘은 공존하며 {configDir}를 공유합니다." - }, - "cline": { - "configDescription": "Cline API 제공자와 자격 증명을 구성합니다. 설정은 ~/.cline/data/에 저장됩니다." - }, - "opencodePlugins": { - "title": "OpenCode 플러그인", - "declared": "선언된 플러그인", - "noPlugins": "opencode.json에 선언된 플러그인이 없습니다", - "status": { - "installed": "설치됨", - "missing": "미설치" - }, - "installAll": "누락된 플러그인 모두 설치", - "pinVersions": "@latest 버전 고정", - "install": "설치", - "uninstall": "제거", - "refresh": "새로고침", - "success": "모든 플러그인이 성공적으로 설치되었습니다", - "failed": "플러그인 작업 실패" - }, - "pi": { - "configManagement": "Pi 설정", - "configDescription": "Pi는 모델 제공자의 API 키로 인증합니다. 키는 ~/.pi/agent/auth.json에, 모델 선택은 settings.json에 저장됩니다.", - "providerLabel": "제공자", - "modelLabel": "모델", - "thinkingLabel": "사고", - "thinking": { - "off": "끔", - "low": "낮음", - "medium": "중간", - "high": "높음", - "minimal": "최소", - "xhigh": "매우 높음" - }, - "apiKeyLabel": "API 키", - "apiKeyHint": "선택한 제공자의 ~/.pi/agent/auth.json에 저장됩니다.", - "apiKeySetPlaceholder": "••••••(저장됨 · 비워두면 유지)", - "saveConfig": "Pi 설정 저장", - "providerModelRequired": "제공자와 모델은 필수입니다", - "runtimeTitle": "런타임", - "runtimeDescription": "어떤 pi를 실행할지 선택합니다. 기본값을 사용하거나 자신의 pi 빌드를 지정하세요.", - "modeDefault": "기본 pi", - "modeDefaultHint": "내장 pi-acp 어댑터로 PATH의 pi를 실행합니다. pi 설치: npm install -g @earendil-works/pi-coding-agent", - "modeCustom": "사용자 지정 pi", - "modeCustomHint": "자신의 pi 빌드, 설치 또는 래퍼를 실행합니다.", - "commandLabel": "pi 명령 또는 경로", - "commandHint": "절대 경로, PATH의 명령 이름 또는 래퍼 스크립트(예: 모노레포의 ./pi-test.sh).", - "commandNotFound": "명령을 찾을 수 없음", - "validate": "검증", - "advanced": "고급", - "configDirLabel": "설정 디렉터리 (PI_CODING_AGENT_DIR)", - "sessionDirLabel": "세션 디렉터리 (PI_CODING_AGENT_SESSION_DIR)", - "flagsHint": "pi-acp는 사용자 지정 pi 플래그(--approve, -e 등)를 전달하지 않습니다. pi를 스크립트로 감싸고 명령이 이를 가리키도록 하세요.", - "customIncomplete": "저장하려면 pi 명령을 입력하세요", - "saveRuntime": "런타임 저장", - "providerPlaceholder": "제공자 선택", - "customProvider": "사용자 지정 제공자…", - "providerIdLabel": "제공자 ID", - "apiProtocolLabel": "API 프로토콜", - "baseUrlLabel": "API 엔드포인트(Base URL)", - "customProviderHint": "~/.pi/agent/models.json에 엔드포인트용 제공자를 정의합니다. 대부분의 자체 호스팅 또는 프록시 서버는 openai-completions를 사용합니다.", - "baseUrlRequired": "API 엔드포인트(Base URL)는 필수입니다", - "binaryTitle": "pi 바이너리 (pi-coding-agent)", - "binaryDescription": "pi-acp가 이 pi 바이너리를 실행합니다. 여기서 설치하거나 아래에서 직접 빌드한 pi를 지정하세요.", - "binaryInstalled": "설치됨", - "binaryMissing": "설치되지 않음", - "binaryChecking": "확인 중…", - "installBinary": "pi 설치", - "installing": "설치 중…", - "recheck": "다시 확인", - "configDirSkillsNote": "사용자 지정 구성 디렉터리를 설정하면 설정에서 관리하는 스킬, 전문가, 오피스 도구가 이 pi에 적용되지 않습니다. 해당 폴더에서 스킬을 직접 관리하세요.", - "projectTrustTitle": "프로젝트 신뢰", - "projectTrustDescription": "pi가 프로젝트 파일을 불러오도록 허용한 폴더입니다. 신뢰한 폴더에서는 해당 저장소의 .pi/extensions가 pi 시작 시 코드를 실행하며, 그 아래 모든 폴더에 적용되고 터미널에서 pi를 실행할 때에도 사용됩니다.", - "projectTrustLoading": "불러오는 중…", - "projectTrustEmpty": "아직 결정한 폴더가 없습니다.", - "projectTrustTrusted": "신뢰함", - "projectTrustDenied": "신뢰 안 함", - "projectTrustRevoke": "취소", - "reasoningTitle": "추론", - "reasoningEnableLabel": "사용", - "reasoningDescription": "모델이 추론 기능을 선언한 경우에만 pi가 추론 강도를 보냅니다. 선언하지 않은 모델은 모든 단계가 Off로 고정되어, 입력창의 선택기가 건드리는 즉시 되돌아갑니다. models.json의 해당 모델 항목에 기록됩니다.", - "levelsLabel": "선택 가능한 단계", - "levelsHint": "입력창 추론 선택기의 항목이 됩니다. 엔드포인트가 받아들이는 값을 고르세요. 여기 없는 단계는 pi가 거부합니다.", - "levelsEmptyError": "단계를 하나 이상 선택하세요. 하나도 없으면 pi는 Off로 되돌아갑니다.", - "wireValuesTitle": "고급: 공급자에게 보내는 값", - "wireValuesHint": "비워 두면 단계 이름을 그대로 보냅니다. 엔드포인트가 다른 표기를 요구할 때만 설정하세요 — Google 계열은 LOW / HIGH가 필요합니다.", - "defaultLevelUnlisted": "이 단계는 위 선택 목록에 없습니다 — pi가 낮춰 버립니다." - }, - "addCustomAgent": "사용자 지정 에이전트 추가", - "addCustomAgentHint": "ACP를 지원하는 모든 에이전트를 등록할 수 있습니다. 공개 ACP 레지스트리에서 선택하거나 레지스트리 정보를 붙여넣으세요.", - "customAgentFromRegistry": "ACP 레지스트리", - "customAgentManual": "직접 입력", - "customAgentSearchPlaceholder": "에이전트 검색…", - "customAgentLoadingCatalog": "ACP 레지스트리를 불러오는 중…", - "customAgentRetry": "다시 시도", - "customAgentNoResults": "일치하는 에이전트가 없습니다", - "customAgentAdd": "추가", - "customAgentAlreadyAdded": "추가됨", - "customAgentUnsupportedPlatform": "이 플랫폼용 빌드가 없습니다", - "customAgentAdded": "{name} 추가됨", - "customAgentIdLabel": "레지스트리 ID", - "customAgentNameLabel": "표시 이름", - "customAgentVersionLabel": "버전", - "customAgentSpecLabel": "배포 정보(JSON)", - "customAgentSpecHint": "ACP 레지스트리의 distribution 객체와 동일한 형식입니다. npx·uvx·binary 채널을 지원하며 레지스트리 항목 전체를 붙여넣어도 됩니다. npx/uvx의 cmd는 패키지가 설치하는 실행 명령 이름으로, 생략하면 패키지 이름에서 유도되므로 서로 다를 때는 지정하세요. binary는 플랫폼 키로 구분하며(이 컴퓨터: {platform}) cmd는 아카이브 내 실행 경로, sha256은 선택 사항으로 다운로드를 검증합니다.", - "customAgentTemplateLabel": "템플릿", - "customAgentKindLabel": "실행 방식", - "customAgentInvalidJson": "올바른 JSON이 아닙니다", - "customAgentNoDistribution": "npx, uvx, binary 배포를 찾을 수 없습니다", - "customAgentCancel": "취소", - "customAgentSave": "에이전트 추가", - "customAgentSaveChanges": "변경 사항 저장", - "customAgentEdit": "에이전트 편집", - "customAgentEditHint": "이름, 아이콘, 배포 정보, 스킬 선언을 수정할 수 있습니다. 에이전트 ID는 변경할 수 없습니다.", - "customAgentEditNotFound": "커스텀 에이전트 {id}을(를) 찾을 수 없습니다", - "customAgentSaved": "{name} 저장됨", - "customAgentVersionProbeLabel": "버전 조회 명령(선택)", - "customAgentVersionProbeHint": "로컬에 설치된 버전을 출력하는 명령입니다. 비워 두면 에이전트 명령에 --version을 붙여 실행합니다.", - "customAgentRemove": "에이전트 제거", - "customAgentRemoveHint": "에이전트 정의를 삭제합니다. 기존 대화 기록은 유지되며 에이전트를 더 이상 실행할 수 없게 될 뿐입니다.", - "customAgentIconLabel": "아이콘(선택)", - "customAgentIconUpload": "업로드", - "customAgentIconReplace": "변경", - "customAgentIconClear": "아이콘 제거", - "customAgentIconHint": "에이전트와 함께 저장되어 오프라인에서도 표시됩니다. 지정하지 않으면 색상 이니셜을 사용합니다.", - "customAgentSkillsLabel": "Skills(공유 .agents/skills)", - "customAgentSkillsHint": "이 에이전트가 공유 .agents/skills 디렉터리(전역 및 프로젝트)를 읽는다고 선언하고 모든 스킬 매트릭스에 추가합니다. 공유 디렉터리에 연결된 스킬은 해당 디렉터리를 읽는 다른 에이전트에게도 보입니다.", - "customAgentSkillsDirLabel": "전용 스킬 디렉터리", - "customAgentSkillsDirHint": "이 에이전트가 스킬을 불러오는 디렉터리의 절대 경로입니다. 공유 저장소와 함께 또는 단독으로 사용할 수 있습니다. ~ 는 홈 디렉터리로 확장되며, 연결된 스킬은 이 디렉터리에 우선 배치됩니다.", - "customAgentMcpLabel": "MCP 지원", - "customAgentMcpHint": "세션을 시작할 때 codeg 내장 codeg-mcp 동반 프로세스를 이 에이전트에 전달합니다. 위임, 실시간 피드백, 작업 도구가 이 채널을 사용합니다. MCP 서버를 거부해 연결에 실패하는 에이전트라면 꺼 두세요. 변경은 다음 연결부터 적용됩니다.", - "customAgentIconNotAnImage": "이미지 파일을 선택하세요.", - "customAgentIconTooLarge": "아이콘은 {limit} KB 미만이어야 합니다.", - "customAgentIconReadFailed": "해당 이미지를 읽을 수 없습니다.", - "customAgentRemoveConfirm": "{name}을(를) 제거할까요? 기존 대화는 유지되지만 더 이상 실행할 수 없습니다.", - "customAgentRemoveWithData": "기록된 대화 기록도 삭제", - "customAgentRemoved": "{name} 제거됨", - "customAgentBadge": "사용자 지정", - "customAgentNotLaunchable": "이 환경에서는 실행할 수 없습니다: {reason}" - }, - "SettingsPages": { - "agentsLoading": "에이전트 설정을 불러오는 중...", - "skillPacksLoading": "스킬 팩 로딩 중…" - }, - "GeneralSettings": { - "loading": "로딩 중...", - "sectionTitle": "일반", - "sectionDescription": "기본 터미널, 렌더링 가속, 다중 에이전트 위임 등 공용 환경설정을 한곳에서 관리합니다.", - "terminalTitle": "기본 터미널", - "terminalDescription": "터미널 바나 파일 트리에서 새 터미널 탭을 열 때 사용할 셸을 선택합니다. 에이전트가 codeg에 전체 명령줄 실행을 요청할 때도 사용됩니다.", - "terminalSystemDefault": "시스템 기본값", - "terminalPowerShell7": "PowerShell 7 (pwsh)", - "terminalWindowsPowerShell": "Windows PowerShell", - "terminalCmd": "명령 프롬프트 (cmd)", - "terminalSaveFailed": "터미널 설정 저장 실패: {message}", - "terminalShellCustom": "사용자 지정 경로", - "terminalShellCustomPath": "Shell 경로", - "terminalShellCustomPlaceholder": "/usr/local/bin/fish", - "terminalShellCustomSave": "저장", - "terminalShellCustomHint": "절대 경로 또는 PATH에서 찾을 수 있는 명령 이름을 입력하세요.", - "terminalShellNotInstalled": "설치되지 않음", - "terminalShellNotFoundWarning": "이 경로는 현재 호스트에 존재하지 않습니다.", - "terminalCurrentShell": "현재 사용 중: {path}", - "renderingDescription": "앱이 검은 화면이 되거나 렌더링 문제가 발생하면(일부 AMD GPU 또는 Intel 내장 GPU에서 보고됨) 하드웨어 가속을 끄세요. Windows 데스크톱에서만 적용됩니다.", - "disableHardwareAcceleration": "하드웨어 가속 비활성화", - "renderingSaveFailed": "렌더링 설정 저장 실패: {message}", - "restartRequired": "저장되었습니다. 변경 사항을 적용하려면 앱을 다시 시작하세요.", - "restartNow": "지금 다시 시작", - "restartFailed": "다시 시작 실패: {message}", - "loadFailed": "불러오기 실패: {message}" - }, - "LoginPage": { - "documentTitle": "로그인 - codeg", - "brand": "Codeg", - "subtitle": "데스크톱 앱에 연결하려면 액세스 토큰을 입력하세요", - "tokenPlaceholder": "액세스 토큰", - "connect": "연결", - "connecting": "연결 중...", - "helpText": "토큰은 데스크톱 앱의 설정 → 웹 서비스에서 확인할 수 있습니다", - "invalidToken": "유효하지 않은 토큰입니다. 확인 후 다시 시도하세요", - "connectionFailed": "연결 실패 (HTTP {status})", - "networkError": "서버에 연결할 수 없습니다" - }, - "CommitPage": { - "title": "커밋", - "invalidFolderId": "유효하지 않은 폴더 ID", - "loadingRepo": "저장소를 불러오는 중..." - }, - "MergePage": { - "title": "충돌 해결", - "invalidFolderId": "잘못된 폴더 ID", - "loadingRepo": "저장소 로딩 중...", - "localVersion": "로컬 (우리 쪽)", - "result": "결과", - "remoteVersion": "원격 (상대 쪽)", - "acceptLocal": "로컬 적용", - "acceptRemote": "원격 적용", - "markResolved": "해결됨으로 표시", - "abortMerge": "중단", - "completeMerge": "병합 완료", - "unresolvedConflicts": "파일에 아직 해결되지 않은 충돌 마커가 있습니다", - "fileResolved": "파일이 해결되었습니다", - "allResolved": "모든 충돌이 해결되었습니다", - "conflictFiles": "충돌 파일", - "loadingFile": "파일 로딩 중...", - "preparingMerge": "병합 준비 중...", - "selectFile": "해결할 파일을 선택하세요", - "noConflicts": "충돌 파일 없음", - "skipFile": "건너뛰기", - "abortSuccess": "작업이 중단되었습니다", - "applyAllNonConflicting": "충돌하지 않는 모든 변경 적용", - "applyLeftNonConflicting": "로컬 적용", - "applyRightNonConflicting": "원격 적용" - }, - "ImportSessions": { - "title": "로컬 세션 가져오기", - "scanningTitle": "로컬 에이전트 세션 검색 중…", - "scanningHint": "각 에이전트의 로컬 세션 저장소를 탐색하고 있습니다. 기록이 많으면 시간이 걸릴 수 있습니다. 이미 가져온 세션은 이 과정에서 함께 갱신됩니다.", - "scanFailed": "검색 실패", - "retry": "다시 시도", - "rescan": "다시 검색", - "empty": "로컬 세션을 찾을 수 없습니다", - "emptyHint": "이 컴퓨터에서 에이전트 세션 저장소를 찾지 못했습니다.", - "noMatches": "현재 필터와 일치하는 세션이 없습니다", - "searchPlaceholder": "제목 또는 경로 검색…", - "allAgents": "모든 에이전트", - "onlyImportable": "가져오기 가능만", - "selectAll": "모두 선택", - "clearSelection": "지우기", - "expandAll": "모두 펼치기", - "collapseAll": "모두 접기", - "summaryCounts": "세션 {total}개 · 가져오기 가능 {importable}개 · 폴더 {folders}개", - "noFolderSkipped": "프로젝트 폴더가 없는 {count}개 건너뜀", - "folderNew": "신규", - "folderCounts": "가져오기 가능 {importable}/{total}", - "toggleFolderAria": "{name}의 가져오기 가능한 세션 모두 선택", - "toggleSessionAria": "세션 {title} 선택", - "statusImported": "가져옴", - "statusDeleted": "삭제됨", - "untitled": "제목 없는 세션", - "messageCount": "메시지 {count}개", - "selectedCount": "{count}개 선택됨", - "importSelected": "선택 항목 가져오기", - "importing": "가져오는 중…", - "close": "닫기", - "doneTitle": "가져오기 완료", - "doneImported": "가져옴", - "doneUpdated": "갱신됨", - "doneSkipped": "건너뜀", - "doneCreatedFolders": "생성된 폴더", - "doneNotFound": "찾을 수 없음", - "doneFailed": "실패", - "continueImport": "계속 가져오기", - "toasts": { - "importFailed": "가져오기 실패: {message}" - } - }, - "Folder": { - "workspaceStatus": { - "degradedTitle": "실시간 업데이트를 사용할 수 없음", - "degradedHint": "감시자 시작 실패(권한 거부 등). 최신 변경 사항을 보려면 수동으로 새로 고치세요.", - "retry": "다시 시도", - "retrying": "다시 시도 중..." - }, - "common": { - "all": "전체", - "cancel": "취소", - "close": "닫기", - "closeOthers": "다른 항목 닫기", - "closeAll": "모두 닫기", - "confirm": "확인", - "save": "저장", - "delete": "삭제", - "rename": "이름 변경", - "loading": "로딩 중...", - "refresh": "새로고침", - "refreshing": "새로고침 중...", - "create": "생성", - "createAndSwitch": "생성 후 전환", - "openFile": "파일 열기", - "viewDiff": "Diff 보기", - "push": "푸시..." - }, - "statusLabels": { - "in_progress": "진행 중", - "pending_review": "검토", - "completed": "완료", - "cancelled": "취소됨" - }, - "sidebar": { - "title": "대화", - "locateActiveConversation": "활성 대화 찾기", - "expandAllGroups": "모든 그룹 펼치기", - "collapseAllGroups": "모든 그룹 접기", - "newConversation": "새 대화", - "newConversationShort": "새로 만들기", - "newChat": "새 대화", - "search": "검색", - "noConversationsFound": "대화를 찾을 수 없습니다.", - "importLocalSessions": "로컬 세션 가져오기", - "importing": "가져오는 중...", - "error": "오류: {message}", - "completeAllSessions": "모든 세션 완료 처리", - "completeAllReviewTitle": "모든 검토 세션을 완료 처리할까요?", - "completeAllReviewDescription": "검토 상태의 {count, plural, one {#개 세션} other {#개 세션}}을 모두 완료로 표시합니다.", - "completing": "완료 처리 중...", - "toasts": { - "importedSessions": "{imported, plural, one {#개 세션} other {#개 세션}}을 가져오고 {skipped}개를 건너뛰었습니다", - "importedAndUpdated": "{imported, plural, one {#개 세션} other {#개 세션}}을 가져오고 {updated, plural, one {#개 제목} other {#개 제목}}을 업데이트하고 {skipped}개를 건너뛰었습니다", - "updatedTitles": "{updated, plural, one {#개 제목} other {#개 제목}}을 업데이트하고 {skipped}개를 건너뛰었습니다", - "noNewSessionsFound": "새 세션이 없습니다 ({skipped}개 건너뜀)", - "importFailed": "가져오기 실패: {message}", - "reviewCompleted": "{count, plural, one {#개 검토 세션} other {#개 검토 세션}}을 완료로 표시했습니다", - "completeReviewFailed": "검토 세션 완료 처리 실패: {message}", - "folderOpened": "폴더 {name}을(를) 열었습니다", - "folderRemoved": "폴더 {name}을(를) 제거했습니다", - "openFolderFailed": "폴더를 열 수 없습니다", - "removeFolderFailed": "폴더 제거 실패: {message}", - "reorderFoldersFailed": "폴더 순서 변경 실패: {message}", - "changeFolderColorFailed": "색상 변경 실패: {message}", - "setFolderAliasFailed": "별칭 설정 실패: {message}", - "changeFolderDefaultAgentFailed": "기본 에이전트 설정 실패: {message}" - }, - "statsLabel": "{folders}개 폴더 · {convos}개 대화", - "reorderHandle": "드래그하여 순서 변경", - "openFolder": "폴더 열기", - "searchPlaceholder": "대화 검색...", - "viewOptions": "보기 옵션", - "showCompleted": "완료된 대화 표시", - "showWorktrees": "워크트리 폴더 표시", - "showRecent": "'최근' 그룹 표시", - "moreOptions": "더 많은 옵션", - "sortBy": "정렬 기준", - "sortByCreatedAt": "생성 시간순", - "sortByUpdatedAt": "업데이트 시간순", - "sectionOrder": "섹션 순서", - "sectionOrderMoveUp": "위로 이동", - "sectionOrderMoveDown": "아래로 이동", - "sectionOrderItemLabel": "{name} — {total}개 중 {position}번째", - "statusRunningBadge": "실행 중", - "runningCountBadge": "{count}개 세션 실행 중", - "statusCancelledBadge": "취소됨", - "worktreeRemovedBadge": "원본 worktree가 삭제됨", - "conversationCountUnit": "{count}개", - "emptyFolderHint": "대화 없음", - "noMatchingConversations": "일치하는 대화가 없습니다", - "noUnfinishedConversations": "미완료 대화가 없습니다. 오른쪽 상단 메뉴에서 \"완료된 대화 표시\"를 활성화할 수 있습니다.", - "removeFolderConfirmTitle": "이 폴더를 워크스페이스에서 제거하시겠습니까?", - "removeFolderConfirmDescription": "워크스페이스에서 \"{name}\"을(를) 제거하시겠습니까? 관련 탭과 터미널이 닫힙니다.", - "folderHeaderMenu": { - "manageConversations": "대화 관리…", - "manageLinks": "연결된 폴더", - "changeColor": "색상 변경", - "useThemeColor": "앱 테마 사용", - "setDefaultAgent": "기본 에이전트 설정", - "defaultAgentNone": "설정 없음(전역 사용)", - "agentUnavailableSuffix": "(사용 불가)", - "loadingAgents": "에이전트 로드 중…", - "setAlias": "별칭 설정…", - "setAliasTitle": "폴더 별칭 설정", - "setAliasPlaceholder": "별칭 입력 (비우면 지움)", - "setAliasSave": "저장", - "setAliasCancel": "취소", - "removeFromWorkspace": "워크스페이스에서 제거" - }, - "manageConversations": { - "title": "대화 관리", - "searchPlaceholder": "제목으로 검색…", - "agentFilterAll": "모든 에이전트", - "statusFilterAll": "모든 상태", - "folderFilterAll": "모든 폴더", - "branchFilterAll": "모든 브랜치", - "branchNone": "브랜치 없음", - "branchSearchPlaceholder": "브랜치 검색…", - "noMatchingBranches": "일치하는 브랜치가 없습니다", - "selectAllVisible": "전체 선택", - "deselectAll": "선택 해제", - "selectedCount": "{count}개 선택됨", - "matchedCount": "{count}개 일치", - "untitledConversation": "제목 없는 대화", - "setStatus": "상태 변경…", - "deleteSelected": "삭제", - "noConversations": "이 폴더에 대화가 없습니다.", - "noConversationsWorkspace": "작업 공간에 대화가 없습니다.", - "noMatchingConversations": "필터에 일치하는 대화가 없습니다.", - "confirmDeleteTitle": "{count}개 대화를 삭제하시겠습니까?", - "confirmDeleteDescription": "이 작업은 되돌릴 수 없습니다.", - "toastDeleted": "{count}개 대화를 삭제했습니다", - "toastStatusUpdated": "{count}개 대화의 상태를 업데이트했습니다", - "toastOpFailed": "작업 실패: {message}" - }, - "sectionPinned": "고정됨", - "sectionFolders": "폴더", - "sectionChats": "채팅", - "sectionRecent": "최근", - "noChats": "채팅 없음", - "noRecent": "최근 대화 없음", - "showMoreRecent": "더 보기 ({count})", - "noFolders": "열린 폴더 없음", - "newChatAction": "새 채팅", - "automations": "자동화", - "tasks": "할 일", - "loadingSubsessions": "하위 대화 로드 중…" - }, - "conversation": { - "reloadFailed": "대화 다시 불러오기 실패: {message}", - "reloaded": "대화를 다시 불러왔습니다", - "reload": "다시 불러오기", - "activeConversationIndicator": "활성 대화", - "newConversation": "새 대화", - "closeConversation": "대화 닫기", - "copyText": "텍스트 복사", - "copyTextSuccess": "복사됨", - "copyTextFailed": "복사 실패", - "forkSession": "세션 포크", - "forkSessionSuccess": "세션 포크 성공", - "forkSessionFailed": "세션 포크 실패: {error}", - "exportConversation": "대화 내보내기", - "exportImage": "이미지", - "exportMarkdown": "Markdown", - "exportHtml": "HTML", - "exportSuccess": "대화를 내보냈습니다", - "exportFailed": "내보내기 실패", - "exportImageTooLong": "대화가 너무 길어 이미지로 내보낼 수 없습니다", - "exportLabels": { - "untitledConversation": "제목 없는 대화", - "agent": "에이전트", - "model": "모델", - "status": "상태", - "started": "시작", - "updated": "업데이트", - "tokens": "토큰 통계", - "duration": "소요 시간", - "inputTokens": "입력", - "outputTokens": "출력", - "cacheRead": "캐시 읽기", - "cacheWrite": "캐시 쓰기", - "user": "사용자", - "assistant": "어시스턴트", - "system": "시스템", - "toolResult": "결과", - "toolError": "오류" - }, - "moreActions": "추가 작업" - }, - "sessionDetails": { - "menuLabel": "세션 세부 정보", - "noActiveSession": "활성 세션이 없습니다", - "title": "세션 세부 정보", - "subtitle": "세션 메타데이터 및 토큰 사용량", - "fieldTitle": "제목", - "untitled": "제목 없는 대화", - "sessionId": "세션 ID", - "externalId": "확장 ID", - "agent": "에이전트", - "model": "모델", - "status": "상태", - "gitBranch": "Git 브랜치", - "parentId": "상위 세션", - "tokensHeading": "토큰 사용량", - "totalTokens": "합계", - "inputTokens": "입력", - "outputTokens": "출력", - "cacheWrite": "캐시 쓰기", - "cacheRead": "캐시 읽기", - "contextWindow": "컨텍스트 창", - "duration": "소요 시간", - "loadingStats": "토큰 사용량 불러오는 중…", - "loadFailed": "토큰 사용량을 불러오지 못했습니다", - "noStats": "사용량 기록 없음", - "timestampsHeading": "타임스탬프", - "createdAt": "생성됨", - "updatedAt": "업데이트됨", - "none": "—", - "copyField": "{field} 복사", - "copiedField": "{field} 복사됨" - }, - "conversationCard": { - "untitledConversation": "제목 없는 대화", - "newConversation": "새 대화", - "rename": "이름 변경", - "status": "상태", - "delete": "삭제", - "importLocalSessions": "로컬 세션 가져오기", - "importing": "가져오는 중...", - "renameConversation": "대화 이름 변경", - "deleteConversationTitle": "대화를 삭제할까요?", - "deleteConversationDescription": "\"{title}\"을(를) 삭제합니다. 이 작업은 되돌릴 수 없습니다.", - "cancel": "취소", - "save": "저장", - "pin": "고정", - "unpin": "고정 해제", - "markCompleted": "완료로 표시", - "reopen": "다시 열기", - "expandSubsessions": "하위 대화 펼치기", - "collapseSubsessions": "하위 대화 접기" - }, - "search": { - "dialogTitle": "검색", - "dialogTitleWithFolder": "검색 — {name}", - "tabConversations": "대화", - "tabFiles": "파일", - "placeholder": "대화 검색...", - "filePlaceholder": "파일 또는 디렉토리 검색...", - "allAgents": "전체", - "searching": "검색 중...", - "typeToSearch": "입력하여 대화를 검색하세요", - "typeToSearchFiles": "입력하여 파일 또는 디렉토리를 검색하세요", - "noResults": "검색 결과가 없습니다.", - "untitledConversation": "제목 없는 대화" - }, - "folderTitleBar": { - "showSidebar": "사이드바 표시", - "hideSidebar": "사이드바 숨기기", - "toggleTerminal": "터미널 전환", - "toggleAuxPanel": "보조 패널 전환", - "search": "검색", - "openSettings": "설정 열기", - "backToConversations": "대화로 돌아가기", - "withShortcut": "{label} ({shortcut} 단축키)" - }, - "statusBar": { - "connection": { - "connected": "연결됨", - "connecting": "연결 중...", - "prompting": "응답 중...", - "error": "연결 오류", - "disconnected": "연결 끊김", - "tooltip": "{agent}: {status}", - "tooltipError": "{agent}: {error}", - "title": "에이전트 연결", - "triggerAria": "에이전트 연결: {status}", - "workingDir": "작업 디렉터리", - "sessionId": "세션 ID", - "viewerNote": "다른 클라이언트가 소유한 세션에 연결되어 있습니다. 다시 연결해도 이 보기만 다시 연결됩니다.", - "reconnectInterrupts": "다시 연결하면 에이전트가 재시작되어 진행 중인 작업이 중단됩니다.", - "reconnect": "다시 연결", - "reconnecting": "다시 연결하는 중...", - "reconnectUnavailable": "아직 다시 연결할 세션이 없습니다." - }, - "tasks": { - "title": "작업" - }, - "alerts": { - "title": "알림", - "empty": "알림 없음", - "details": "세부 정보" - }, - "stats": { - "conversations": "{count}개 대화", - "openUsage": "세션 통계 및 토큰 사용량 보기" - }, - "tokens": { - "contextWindowUsageAria": "컨텍스트 윈도우 사용량", - "contextWindow": "컨텍스트 윈도우", - "usedMax": "사용 / 최대", - "tokenUsage": "토큰 사용량", - "input": "입력", - "output": "출력", - "cacheRead": "캐시 읽기", - "cacheWrite": "캐시 쓰기", - "total": "합계" - } - }, - "auxPanel": { - "tabs": { - "files": "파일", - "changes": "변경사항", - "commits": "커밋" - }, - "noFolderTitle": "열린 폴더 없음", - "noFolderHint": "폴더를 열면 여기에 표시됩니다" - }, - "windowControls": { - "minimizeWindow": "창 최소화", - "minimize": "최소화", - "maximizeWindow": "창 최대화", - "maximize": "최대화", - "restoreWindow": "창 복원", - "restore": "복원", - "closeWindow": "창 닫기", - "close": "닫기" - }, - "tabs": { - "closeConversationTab": "대화 탭 닫기", - "close": "닫기", - "closeOthers": "다른 항목 닫기", - "splitRight": "오른쪽으로 분할", - "splitDown": "아래로 분할", - "splitAndMoveRight": "분할하고 오른쪽으로 이동", - "splitAndMoveDown": "분할하고 아래로 이동", - "moveToOppositeGroup": "반대쪽 그룹으로 이동", - "moveToGroup": "그룹으로 이동", - "groupLabel": "그룹 {index}", - "changeSplitterOrientation": "분할 방향 전환", - "unsplit": "분할 해제", - "unsplitAll": "모든 분할 해제", - "closeAll": "모두 닫기", - "tileDisplay": "타일 표시", - "untileDisplay": "타일 해제" - }, - "fileWorkspace": { - "files": "파일", - "closeFileTab": "파일 탭 닫기", - "close": "닫기", - "closeOthers": "다른 항목 닫기", - "closeAll": "모두 닫기", - "preview": "미리보기", - "editSource": "소스 편집", - "maximize": "최대화", - "restore": "복원", - "emptyDirectory": "빈 폴더" - }, - "terminal": { - "rename": "이름 변경", - "close": "닫기", - "closeOthers": "다른 항목 닫기", - "closeAll": "모두 닫기", - "hideTerminal": "터미널 숨기기 ({shortcut})", - "openFolderFirst": "먼저 폴더를 여세요" - }, - "workspaceDialog": { - "title": "폴더 열기", - "manageTitle": "연결된 폴더", - "addTargetsTitle": "연결할 폴더 추가", - "pickRootDescription": "이 작업 공간의 기본 폴더를 선택하세요.", - "linksDescription": "다른 폴더를 하위 디렉터리로 연결하면 에이전트가 하나의 작업 공간에서 여러 프로젝트를 함께 다룰 수 있습니다.", - "addTargetsDescription": "폴더를 하나 이상 선택하세요. 각각 작업 공간의 하위 디렉터리가 됩니다.", - "useSystemPicker": "시스템 선택기", - "next": "다음", - "back": "뒤로", - "done": "완료", - "change": "변경", - "addFolders": "폴더 추가", - "addSelected": "추가", - "addSelectedCount": "{count}개 추가", - "createCount": "폴더 {count}개 연결", - "discardPending": "취소", - "noLinks": "아직 연결된 폴더가 없습니다.", - "gitExclude": "연결을 git 상태에 노출하지 않기", - "rename": "이름 변경", - "unlink": "연결 해제", - "repair": "연결 다시 만들기", - "saveName": "저장", - "cancelRename": "취소", - "removePending": "제거", - "willAppearAs": "작업 공간에서 {name}(으)로 표시됩니다", - "renamedForDuplicate": "이름이 변경됨 — {base}은(는) 다른 연결이 사용 중입니다", - "renamedForExistingEntry": "이름이 변경됨 — 이 폴더에 이미 {base}이(가) 있습니다", - "partiallyCreated": "폴더 {count}개만 연결되었습니다", - "openFailed": "폴더를 열지 못했습니다", - "previewFailed": "선택한 폴더를 확인하지 못했습니다", - "createFailed": "폴더를 연결하지 못했습니다", - "renameFailed": "이름을 변경하지 못했습니다", - "removeFailed": "연결을 해제하지 못했습니다", - "repairFailed": "연결을 다시 만들지 못했습니다", - "status": { - "ok": "연결됨", - "missing": "이 폴더에서 링크가 사라졌습니다", - "conflicted": "다른 항목이 이 이름을 사용 중입니다", - "broken": "연결된 폴더가 더 이상 존재하지 않습니다" - }, - "nameIssue": { - "empty": "이름을 입력하세요", - "illegalChars": "/ \\ : * ? \" < > | 는 사용할 수 없습니다", - "tooLong": "이름이 너무 깁니다", - "reserved": "Windows 예약어입니다", - "duplicate": "이미 사용 중인 이름입니다" - }, - "rejection": { - "not_found": "폴더를 찾을 수 없습니다", - "not_a_directory": "이 경로는 폴더가 아닙니다", - "same_as_root": "작업 공간 폴더 자신입니다", - "ancestor_of_root": "이 폴더가 작업 공간을 포함합니다", - "inside_root": "이미 작업 공간 안에 있습니다", - "already_linked": "이미 연결되어 있습니다", - "name_unavailable": "이 폴더에 사용할 수 있는 이름이 없습니다", - "alreadyLinkedAs": "{name}(으)로 이미 연결되어 있습니다" - } - }, - "folderNameDropdown": { - "fallbackFolderName": "폴더", - "openFolder": "폴더 열기", - "cloneRepository": "리포지토리 클론", - "projectBoot": "프로젝트 부트", - "opened": "열린 항목", - "recentOpen": "최근 연 항목" - }, - "fileWorkspacePanel": { - "addSelectionToChat": "선택 영역을 대화에 추가", - "addToChat": "대화에 추가", - "addSelectionToChatDone": "{label}을(를) 대화에 추가했습니다", - "addFileToChat": "파일을 대화에 추가", - "toggleWordWrap": "자동 줄 바꿈 전환", - "addFileToChatDone": "{label}을(를) 대화에 추가했습니다", - "viewDiff": "Diff 보기", - "openFile": "파일 열기", - "fileCount": "{count, plural, one {#개 파일} other {#개 파일}}", - "openFileOrDiff": "오른쪽 패널에서 파일 또는 diff를 여세요", - "disk": "디스크", - "head": "HEAD", - "unsaved": "저장되지 않음", - "workingTree": "작업 트리", - "loading": "로딩 중...", - "compareWithBranch": "{path} · {branch}와 비교", - "hunkCount": "{count, plural, one {#개 hunk} other {#개 hunks}}", - "prev": "이전", - "next": "다음", - "jumpToLine": "{line}행으로 이동", - "noParsedDiffSections": "파싱된 diff 섹션이 없습니다", - "loadingEditor": "에디터 로딩 중...", - "imageZoomIn": "확대", - "imageZoomOut": "축소", - "imageZoomReset": "확대/축소 초기화", - "htmlPreviewTitle": "HTML 미리보기", - "htmlPreviewTrust": "스크립트 사용", - "htmlPreviewTrustHint": "이 파일의 스크립트를 실행하고 네트워크 접근을 허용합니다. 신뢰할 수 있는 파일에서만 사용하세요.", - "officePreviewTitle": "Office 문서 미리보기", - "officeFullRender": "전체 렌더링", - "officeFullRenderHint": "Morph 애니메이션, 3D, 수식을 렌더링합니다(슬라이드 자체 스크립트 실행).", - "officeNotInstalled": "OfficeCLI가 설치되지 않았습니다", - "officeNotInstalledHint": "설정 → Office 도구에서 OfficeCLI를 설치하면 Word, Excel, PowerPoint 파일을 미리볼 수 있습니다.", - "officeOpenSettings": "설정 열기", - "officeWatchFailed": "실시간 미리보기를 시작할 수 없습니다", - "officeWatchRetry": "다시 시도", - "officeServerInstallHint": "OfficeCLI는 서버 호스트에 설치해야 합니다. 서버에서 다음 명령을 실행한 후 다시 시도하세요:", - "officeRemoteDesktopUnsupported": "원격 데스크톱 창에서는 실시간 미리보기를 사용할 수 없습니다. Office 파일을 미리 보려면 서버의 웹 UI에서 이 작업 공간을 여세요." - }, - "branchDropdown": { - "toasts": { - "commitCodeCompleted": "코드 커밋이 완료되었습니다", - "pushCodeCompleted": "코드 푸시가 완료되었습니다", - "committedFiles": "{count, plural, one {#개 파일 커밋됨} other {#개 파일 커밋됨}}", - "taskCompleted": "{label} 완료", - "taskFailed": "{label} 실패", - "mergeNoNewCommits": "{branchName}에는 새 커밋이 없습니다", - "mergedCommits": "{count, plural, one {#개 커밋 병합됨} other {#개 커밋 병합됨}}", - "allFilesUpToDate": "모든 파일이 최신 상태입니다", - "updatedFiles": "{count, plural, one {#개 파일 업데이트됨} other {#개 파일 업데이트됨}}", - "openCommitWindowFailed": "커밋 창을 열지 못했습니다", - "openPushWindowFailed": "푸시 창 열기 실패", - "upstreamSet": "업스트림 브랜치가 설정되었습니다", - "upstreamSetAndPushed": "업스트림 브랜치를 설정하고 {count, plural, one {#개 커밋} other {#개 커밋}}을 푸시했습니다", - "noCommitsToPush": "푸시할 커밋이 없습니다", - "pushedCommits": "{count, plural, one {#개 커밋 푸시됨} other {#개 커밋 푸시됨}}", - "switchedToFolder": "{name}(으)로 전환했습니다", - "switchFailed": "브랜치 전환에 실패했습니다", - "openStashWindowFailed": "스태시 창을 열지 못했습니다" - }, - "tasks": { - "newBranch": "브랜치 {name} 생성", - "newWorktree": "워크트리 {name} 생성", - "checkoutTo": "{branchName}(으)로 체크아웃", - "mergeBranch": "{branchName} 병합", - "rebaseTo": "{branchName}로 리베이스", - "deleteRemoteBranch": "원격 브랜치 {branchName} 삭제", - "initGitRepo": "Git 저장소 초기화", - "pullCode": "코드 pull", - "fetchInfo": "정보 fetch", - "pushCode": "코드 push", - "stashChanges": "변경 사항 stash", - "stashPop": "stash pop", - "deleteBranch": "브랜치 {branchName} 삭제", - "removeWorktree": "{branchName}의 워크트리 삭제", - "removeWorktreeAndBranch": "워크트리 및 브랜치 {branchName} 삭제", - "updateBranch": "브랜치 {branchName} 업데이트" - }, - "confirm": { - "mergeTitle": "브랜치 병합", - "rebaseTitle": "브랜치 리베이스", - "mergeDescription": "{branchName}을(를) 현재 브랜치 {currentBranch}에 병합할까요?", - "rebaseDescription": "현재 브랜치 {currentBranch}를 {branchName} 위로 리베이스할까요?", - "deleteRemoteTitle": "원격 브랜치 삭제", - "deleteRemoteDescription": "원격 브랜치 {branchName}을(를) 삭제하시겠습니까? 이 작업은 원격 저장소에서 브랜치를 제거하며 되돌릴 수 없습니다.", - "deleteTitle": "브랜치 삭제", - "deleteDescription": "브랜치 {branchName}을(를) 삭제할까요? 이 작업은 되돌릴 수 없습니다.", - "forceDeleteTitle": "브랜치 강제 삭제", - "forceDeleteDescription": "브랜치 {branchName}가 완전히 병합되지 않았습니다. 강제 삭제하시겠습니까? 이 작업은 되돌릴 수 없습니다.", - "deleteWorktreeTitle": "워크트리 삭제", - "deleteWorktreeDescription": "{branchName}이(가) 체크아웃된 워크트리 디렉터리를 삭제할까요? 브랜치와 커밋은 유지됩니다.", - "forceDeleteWorktreeTitle": "워크트리 강제 삭제", - "forceDeleteWorktreeDescription": "{branchName}의 워크트리에 커밋되지 않았거나 추적되지 않는 파일이 있습니다. 그래도 삭제할까요? 해당 변경 사항은 복구할 수 없습니다.", - "deleteWorktreeAndBranchTitle": "워크트리 및 브랜치 삭제", - "deleteWorktreeAndBranchDescription": "{branchName}의 워크트리와 브랜치, 그리고 워크스페이스 폴더를 삭제할까요? 그 안의 세션은 저장소 폴더로 이동합니다. 이 작업은 되돌릴 수 없습니다.", - "forceDeleteWorktreeAndBranchTitle": "워크트리 및 브랜치 강제 삭제", - "forceDeleteWorktreeAndBranchDescription": "{branchName}의 워크트리에 커밋되지 않은 파일이 있거나 브랜치가 완전히 병합되지 않았습니다. 그래도 둘 다 삭제할까요? 이 작업은 되돌릴 수 없습니다." - }, - "current": "현재", - "switchToBranch": "이 브랜치로 전환", - "mergeBranchIntoCurrent": "{branchName}을(를) {currentBranch}에 병합", - "rebaseCurrentToBranch": "{currentBranch}를 {branchName}로 리베이스", - "noBranch": "브랜치 없음", - "detachedHead": "분리된 HEAD ({sha})", - "initGitRepo": "Git 저장소 초기화", - "pullCode": "코드 pull", - "fetchRemoteBranches": "원격 브랜치 가져오기", - "openCommitWindow": "코드 커밋...", - "pushCode": "푸시...", - "pushBranch": "푸시", - "newBranch": "새 브랜치...", - "newWorktree": "새 워크트리...", - "stashChanges": "스태시...", - "stashPop": "stash pop...", - "manageRemotes": "원격 관리...", - "localBranches": "로컬 브랜치 ({count, plural, one {#} other {#}})", - "noLocalBranches": "로컬 브랜치가 없습니다", - "remoteBranches": "원격 브랜치 ({count, plural, one {#} other {#}})", - "noRemoteBranches": "원격 브랜치가 없습니다", - "dialogs": { - "newBranchTitle": "새 브랜치", - "newBranchDescription": "현재 브랜치 {branch}에서 새 브랜치를 만듭니다", - "branchNamePlaceholder": "브랜치 이름", - "newWorktreeTitle": "새 워크트리", - "newWorktreeDescription": "현재 브랜치 {branch}에서 새 워크트리를 만듭니다", - "branchNameLabel": "브랜치 이름", - "worktreePathLabel": "워크트리 경로", - "worktreePathPlaceholder": "워크트리 경로", - "manageRemotesTitle": "원격 관리", - "manageRemotesEmpty": "구성된 원격이 없습니다", - "remoteNamePlaceholder": "원격 이름", - "remoteUrlPlaceholder": "원격 URL", - "addRemote": "추가", - "savingRemotes": "저장 중..." - }, - "conflict": { - "title": "병합 충돌", - "description": "다음 파일에 충돌이 있어 해결이 필요합니다:", - "abort": "병합 중단", - "openMergeTool": "병합 도구 열기", - "completeMerge": "병합 완료", - "abortSuccess": "병합이 중단되었습니다", - "completeSuccess": "병합이 완료되었습니다" - }, - "stashDialog": { - "title": "변경 사항 스태시", - "description": "현재 변경 사항을 스태시에 저장", - "messageLabel": "메시지", - "messagePlaceholder": "스태시 메시지 (선택사항)", - "keepIndex": "인덱스 유지 (스테이지된 변경 사항 유지)", - "cancel": "취소", - "stash": "스태시", - "success": "변경 사항이 스태시되었습니다", - "error": "스태시 실패" - }, - "unstashDialog": { - "title": "스태시 적용", - "noStashes": "스태시가 없습니다", - "selectFile": "파일을 선택하여 차이 보기", - "viewDiff": "차이 보기", - "original": "원본", - "modified": "수정됨", - "apply": "적용", - "drop": "삭제", - "applySuccess": "스태시가 적용되었습니다", - "dropSuccess": "스태시가 삭제되었습니다", - "confirmApply": "스태시 {ref}을(를) 작업 디렉토리에 적용하시겠습니까?", - "cancel": "취소" - }, - "deleteBranch": "브랜치 삭제", - "deleteWorktree": "워크트리 삭제", - "deleteWorktreeAndBranch": "워크트리 및 브랜치 삭제", - "searchPlaceholder": "브랜치 및 작업 검색", - "searchAriaLabel": "브랜치 및 작업 검색", - "branchListLabel": "브랜치 및 작업", - "noMatches": "일치하는 항목 없음" - }, - "commitDialog": { - "toasts": { - "commitCompleted": "코드 커밋이 완료되었습니다", - "pushFailed": "푸시 실패", - "committedFiles": "{count, plural, one {#개 파일 커밋됨} other {#개 파일 커밋됨}}", - "addedToVcs": "VCS에 추가되었습니다", - "addToVcsFailed": "VCS에 추가하지 못했습니다", - "fileDeleted": "파일이 삭제되었습니다", - "deleteFailed": "삭제에 실패했습니다", - "fileRolledBack": "파일이 롤백되었습니다", - "rollbackFailed": "롤백에 실패했습니다", - "dirRolledBack": "디렉토리가 롤백되었습니다", - "dirDeleted": "디렉토리가 삭제되었습니다" - }, - "confirm": { - "deleteTitle": "삭제 확인", - "deleteDescription": "파일 \"{file}\"을(를) 삭제할까요? 이 작업은 되돌릴 수 없습니다.", - "rollbackTitle": "롤백 확인", - "rollbackDescription": "파일 \"{file}\"을(를) HEAD로 롤백할까요? 저장되지 않은 변경 사항은 사라집니다.", - "rollbackDirDescription": "디렉토리 \"{dir}\"를 HEAD로 롤백하시겠습니까? 저장되지 않은 변경 사항이 손실됩니다.", - "deleteDirDescription": "디렉토리 \"{dir}\"를 삭제하시겠습니까? 이 작업은 되돌릴 수 없습니다." - }, - "actions": { - "select": "선택", - "unselect": "선택 해제", - "rollback": "롤백", - "addToVcs": "VCS에 추가" - }, - "aria": { - "selectFile": "{action}: {path}", - "unselectAllFiles": "모든 파일 선택 해제", - "selectAllFiles": "모든 파일 선택", - "unselectTracked": "추적된 변경 선택 해제", - "selectTracked": "추적된 변경 선택", - "unselectUntracked": "추적되지 않은 파일 선택 해제", - "selectUntracked": "추적되지 않은 파일 선택" - }, - "loading": "로딩 중...", - "selectionCount": "{selected} / {total}개 파일", - "emptyFiles": "변경된 파일이 없습니다", - "trackedChanges": "추적된 변경 ({count})", - "untrackedFiles": "추적되지 않은 파일 ({count})", - "commitMessage": "커밋 메시지", - "commitMessagePlaceholder": "커밋 메시지 입력...", - "commitButton": "커밋 ({count})", - "commitAndPushButton": "커밋 후 푸시 ({count})", - "head": "HEAD", - "workingTree": "작업 트리", - "clickFileToDiff": "파일 이름을 클릭해 diff를 확인하세요", - "loadingDiff": "diff 로딩 중..." - }, - "pushWindow": { - "title": "코드 푸시", - "noUnpushedCommits": "푸시되지 않은 커밋이 없습니다", - "noRemoteConfigured": "Git 원격이 구성되지 않았습니다\n「원격 관리」에서 원격을 추가하세요", - "newBranchNoPushedCommits": "새 브랜치 — 푸시하여 원격 추적 브랜치 생성", - "unpushed": "미푸시", - "selectFileToViewDiff": "파일을 선택하여 차이 보기", - "before": "변경 전", - "after": "변경 후", - "push": "푸시", - "toasts": { - "pushSuccess": "푸시 성공", - "pushFailed": "푸시 실패", - "upstreamSet": "원격 추적 브랜치가 설정되었습니다", - "upstreamSetAndPushed": "원격 추적 브랜치 설정 및 {count}개 커밋 푸시 완료", - "noCommitsToPush": "푸시할 커밋이 없습니다", - "pushedCommits": "{count}개 커밋 푸시 완료" - } - }, - "gitLogTab": { - "filesTitle": "파일", - "expandAllFiles": "모든 파일 펼치기", - "collapseAllFiles": "모든 파일 접기", - "workspace": "작업 공간", - "retry": "다시 시도", - "noCommitsFound": "커밋을 찾을 수 없습니다", - "notAGitRepoTitle": "Git 저장소가 아닙니다", - "notAGitRepoHint": "위의 브랜치 메뉴에서 Git을 초기화하거나 기존 저장소를 여세요.", - "hash": "해시", - "copyHash": "해시 복사", - "copyMessage": "메시지 복사", - "showMore": "더보기", - "showLess": "접기", - "author": "작성자", - "noFileChangeDetails": "파일 변경 상세 정보가 없습니다.", - "loadingFiles": "파일 로딩 중…", - "branchesTitle": "브랜치", - "loadingBranches": "브랜치 로딩 중...", - "noContainingBranches": "포함하는 브랜치를 찾을 수 없습니다.", - "newBranch": "새 브랜치...", - "resetToHere": "여기로 리셋", - "resetDisabledReasonNotCurrentBranchView": "현재 브랜치 보기에서만 사용할 수 있습니다", - "copyFullCommitHashAria": "전체 커밋 해시 {hash} 복사", - "pushStatus": { - "pushed": "원격에 푸시됨", - "notPushed": "원격에 푸시되지 않음", - "unknown": "푸시 상태 알 수 없음 (upstream 미설정)" - }, - "time": { - "monthsAgo": "{count, plural, one {#개월 전} other {#개월 전}}", - "daysAgo": "{count, plural, one {#일 전} other {#일 전}}", - "hoursAgo": "{count, plural, one {#시간 전} other {#시간 전}}", - "minsAgo": "{count, plural, one {#분 전} other {#분 전}}", - "justNow": "방금 전" - }, - "toasts": { - "createdAndSwitchedNewBranch": "새 브랜치를 생성하고 전환했습니다", - "newBranchFromCommit": "{name} ({shortHash}에서 생성)", - "createBranchFailed": "브랜치 생성에 실패했습니다", - "openPushWindowFailed": "푸시 창을 열지 못했습니다", - "resetSuccess": "리셋 완료", - "resetSuccessDescription": "{branch}을(를) {mode}로 {shortHash}에 리셋했습니다", - "resetFailed": "리셋 실패" - }, - "authorFilter": { - "label": "작성자", - "searchPlaceholder": "작성자 검색", - "noAuthors": "작성자를 찾을 수 없습니다", - "you": "나", - "filterByAuthorAria": "작성자별로 커밋 필터링", - "filterByQuery": "\"{query}\"(으)로 필터링", - "clearAuthorFilterAria": "작성자 필터 지우기", - "recent": "최근", - "matchingAuthors": "일치하는 작성자", - "removeFromRecent": "최근에서 {name} 제거" - }, - "branchSelector": { - "label": "브랜치", - "head": "HEAD", - "headHint": "현재 브랜치를 따라감", - "headHintWithBranch": "현재 브랜치를 따라감 ({branch})", - "searchBranch": "브랜치 검색...", - "noBranches": "브랜치 없음", - "selectBranchPlaceholder": "브랜치 선택...", - "localBranches": "로컬 브랜치", - "current": "현재", - "remoteBranches": "원격 브랜치", - "refreshCommitHistory": "커밋 히스토리 새로고침", - "clearBranchFilterAria": "브랜치 필터 지우기" - }, - "dialogs": { - "newBranchTitle": "새 브랜치", - "newBranchDescription": "커밋 {shortHash}를 최신 커밋으로 하여 새 브랜치를 생성합니다.", - "branchNamePlaceholder": "브랜치 이름", - "reset": { - "title": "현재 브랜치를 이 커밋으로 리셋", - "branchLabel": "브랜치", - "targetLabel": "대상 커밋", - "messageLabel": "커밋 메시지", - "modeLabel": "리셋 모드", - "confirmButton": "리셋", - "modes": { - "soft": { - "label": "--soft", - "description": "HEAD와 현재 브랜치 포인터를 대상 커밋으로 이동합니다.\nIndex와 Working Tree는 변경하지 않습니다.\n되돌려진 커밋의 변경 사항은 staged 상태로 유지됩니다." - }, - "mixed": { - "label": "--mixed (기본값)", - "description": "HEAD를 대상 커밋으로 이동합니다.\nIndex를 대상 커밋으로 되돌리고 Working Tree 변경은 유지합니다.\n변경 사항은 staged에서 unstaged로 바뀝니다." - }, - "hard": { - "label": "--hard", - "description": "HEAD를 이동하고 Index와 Working Tree를 모두 대상 커밋으로 되돌립니다.\n대상 커밋 이후의 추적된 로컬 변경은 삭제됩니다.\n파괴적인 작업입니다." - }, - "keep": { - "label": "--keep", - "description": "HEAD를 대상 커밋으로 이동하면서 가능한 한 로컬 변경을 유지합니다.\n충돌하지 않는 변경만 보존됩니다.\n충돌이 감지되면 작업 보호를 위해 리셋이 중단됩니다." - } - } - } - }, - "moreActions": "추가 Git 작업" - }, - "gitChangesTab": { - "workspace": "작업 공간", - "noChanges": "로컬 변경 사항이 없습니다", - "notAGitRepoTitle": "Git 저장소가 아닙니다", - "notAGitRepoHint": "위의 브랜치 메뉴에서 Git을 초기화하거나 기존 저장소를 여세요.", - "trackedChanges": "추적된 변경 ({count})", - "untrackedFiles": "추적되지 않은 파일 ({count})", - "expandTracked": "추적된 변경 펼치기", - "collapseTracked": "추적된 변경 접기", - "expandUntracked": "추적되지 않은 파일 펼치기", - "collapseUntracked": "추적되지 않은 파일 접기", - "showRemainingItems": "나머지 {count}개 표시", - "actions": { - "commitCode": "코드 커밋", - "rollback": "롤백", - "addToVcs": "VCS에 추가", - "delete": "삭제", - "moreActions": "추가 Git 작업", - "addAllToVcs": "모두 VCS에 추가", - "rollbackAll": "모두 롤백", - "refresh": "새로 고침" - }, - "toasts": { - "noAddableFilesInDir": "이 디렉터리에는 VCS에 추가할 수 있는 변경 파일이 없습니다", - "noRollbackFilesInDir": "이 디렉터리에는 롤백할 수 있는 변경 파일이 없습니다", - "addedToVcs": "{name}을(를) VCS에 추가했습니다", - "addToVcsFailed": "VCS에 추가하지 못했습니다", - "openCommitWindowFailed": "커밋 창을 열지 못했습니다", - "rolledBack": "{name}을(를) 롤백했습니다", - "rollbackFailed": "롤백에 실패했습니다", - "addedFilesToVcs": "{count, plural, one {#개 파일을 VCS에 추가} other {#개 파일을 VCS에 추가}}", - "rolledBackFiles": "{count, plural, one {#개 파일 롤백} other {#개 파일 롤백}}", - "deleted": "{name}이(가) 삭제되었습니다", - "deleteFailed": "삭제에 실패했습니다", - "deletedFiles": "{count}개 파일을 삭제했습니다", - "noDeletableFilesInDir": "이 디렉터리에서 삭제할 수 있는 변경된 파일이 없습니다", - "commitFailed": "커밋 실패" - }, - "directoryDialog": { - "descriptionAdd": "디렉터리 {path} 아래에서 VCS에 추가할 파일을 선택하세요.", - "descriptionRollback": "디렉터리 {path} 아래에서 롤백할 파일을 선택하세요.", - "descriptionDelete": "디렉터리 {path} 아래에서 삭제할 파일을 선택하세요. 이 작업은 되돌릴 수 없습니다.", - "descriptionFallback": "계속 진행할 파일을 선택하세요.", - "selectionCount": "{selected} / {total} 선택됨", - "selectAll": "모두 선택", - "unselectAll": "모두 선택 해제", - "loadingCandidates": "디렉터리 변경 사항 로딩 중...", - "noOperableFiles": "작업 가능한 파일이 없습니다" - }, - "rollbackConfirm": { - "title": "롤백 확인", - "descriptionWithTarget": "{kind} \"{name}\"의 로컬 변경 사항을 롤백할까요?", - "descriptionFallback": "로컬 변경 사항을 롤백할까요?", - "kindDirectory": "디렉터리", - "kindFile": "파일" - }, - "deleteConfirm": { - "title": "삭제 확인", - "descriptionWithTarget": "{kind} \"{name}\"을(를) 삭제할까요? 이 작업은 되돌릴 수 없습니다.", - "descriptionFallback": "이 작업은 되돌릴 수 없습니다.", - "kindDirectory": "디렉터리", - "kindFile": "파일" - }, - "quickCommit": { - "placeholder": "커밋 메시지 (Enter로 커밋)" - } - }, - "tabContext": { - "loadingConversation": "로딩 중...", - "untitledConversation": "제목 없는 대화", - "newConversation": "새 대화" - }, - "fileTreeTab": { - "workspace": "작업 공간", - "retry": "다시 시도", - "git": "Git", - "openInFileManager": "파일 관리자에서 열기", - "openInFinder": "Finder에서 열기", - "openInExplorer": "Explorer에서 열기", - "attachToCurrentSession": "세션에 추가", - "compareWithBranch": "브랜치와 비교...", - "reloadFromDisk": "디스크에서 다시 불러오기", - "new": "새로 만들기", - "newFile": "파일", - "newDirectory": "디렉터리", - "openIn": "열기", - "openInTerminal": "터미널에서 열기", - "linkedFolder": "연결된 폴더", - "copyPath": "경로 복사", - "upload": "파일/폴더 업로드", - "download": "파일 다운로드", - "downloadAsZip": "ZIP으로 다운로드", - "actions": { - "select": "선택", - "unselect": "선택 해제", - "commitCode": "코드 커밋", - "rollback": "롤백", - "addToVcs": "VCS에 추가" - }, - "aria": { - "selectPath": "{action}: {path}" - }, - "toasts": { - "openDirectoryFailed": "디렉터리를 열지 못했습니다", - "openBuiltinTerminalFailed": "내장 터미널을 열 수 없습니다", - "openCommitWindowFailed": "커밋 창을 열지 못했습니다", - "noAddableFilesInDir": "이 디렉터리에는 VCS에 추가할 수 있는 변경 파일이 없습니다", - "noRollbackFilesInDir": "이 디렉터리에는 롤백할 수 있는 변경 파일이 없습니다", - "addedToVcs": "{name}을(를) VCS에 추가했습니다", - "addToVcsFailed": "VCS에 추가하지 못했습니다", - "loadBranchesFailed": "브랜치를 불러오지 못했습니다", - "renameFailed": "이름 변경에 실패했습니다", - "moveFailed": "이동에 실패했습니다", - "deleteFailed": "삭제에 실패했습니다", - "rolledBack": "{name}을(를) 롤백했습니다", - "rollbackFailed": "롤백에 실패했습니다", - "addedFilesToVcs": "{count, plural, one {#개 파일을 VCS에 추가했습니다} other {#개 파일을 VCS에 추가했습니다}}", - "rolledBackFiles": "{count, plural, one {#개 파일을 롤백했습니다} other {#개 파일을 롤백했습니다}}", - "savedAsCopy": "사본으로 저장했습니다", - "saveCopyFailed": "사본으로 저장하지 못했습니다", - "watchStartFailed": "파일 감시 시작에 실패했습니다", - "createFailed": "생성 실패", - "downloadFailed": "{name} 다운로드 실패", - "downloadSaved": "{name} 다운로드 완료", - "pathCopied": "경로가 복사되었습니다", - "copyPathFailed": "경로 복사에 실패했습니다" - }, - "createDialog": { - "newFile": "새 파일", - "newDirectory": "새 디렉터리", - "description": "새 {kind}의 이름을 입력하세요.", - "placeholderFile": "file-name.ext", - "placeholderDirectory": "folder-name" - }, - "renameDialog": { - "renameDirectory": "디렉터리 이름 변경", - "renameFile": "파일 이름 변경", - "description": "새 이름을 입력하세요(이름만, 경로 제외).", - "placeholderDirectory": "새-폴더-이름", - "placeholderFile": "새-파일-이름.ext" - }, - "uploadDialog": { - "title": "작업 공간에 업로드", - "description": "필요하면 업로드 위치를 변경한 다음 파일이나 폴더를 추가하세요.", - "workspaceRoot": "작업 공간 루트", - "targetPathLabel": "업로드 위치", - "targetPathHint": "실제 경로: {path}", - "dropHint": "파일 또는 폴더를 여기에 끌어오거나 아래 버튼을 사용하세요", - "dropHintActive": "놓으면 대기열에 추가됩니다", - "selectFiles": "파일 선택", - "selectFolder": "폴더 선택", - "startUpload": "업로드 시작", - "clearQueue": "완료된 항목 지우기", - "removeItem": "대기열에서 제거", - "retry": "다시 시도", - "dropZoneAria": "파일을 여기에 드롭하거나 Enter 키로 찾아보기", - "folderEmpty": "드롭한 폴더에서 파일을 찾을 수 없습니다", - "summary": "합계: {total} · 성공: {succeeded} · 실패: {failed}", - "status": { - "pending": "대기 중", - "uploading": "업로드 중", - "success": "완료", - "error": "실패", - "cancelled": "취소됨" - } - }, - "directoryDialog": { - "descriptionAdd": "디렉터리 {path} 아래에서 VCS에 추가할 파일을 선택하세요.", - "descriptionRollback": "디렉터리 {path} 아래에서 롤백할 파일을 선택하세요.", - "descriptionFallback": "계속할 파일을 선택하세요.", - "selectionCount": "{selected} / {total}개 파일 선택됨", - "selectAll": "모두 선택", - "unselectAll": "모두 선택 해제", - "loadingCandidates": "디렉터리 변경 사항을 불러오는 중...", - "noOperableFiles": "작업 가능한 파일이 없습니다" - }, - "compareDialog": { - "title": "브랜치와 비교", - "descriptionWithTarget": "브랜치를 선택하고 {kind} {path}와(과) 비교하세요", - "descriptionFallback": "비교할 브랜치를 선택하세요.", - "kindDirectory": "디렉터리", - "kindFile": "파일", - "filterPlaceholder": "브랜치 필터링 (예: main / origin/main)", - "singleClickHint": "브랜치를 클릭하면 바로 비교합니다", - "loadingBranches": "브랜치를 불러오는 중...", - "recentBranches": "최근 브랜치 ({count})", - "noCurrentBranch": "현재 브랜치 없음", - "localBranches": "로컬 브랜치 ({count})", - "remoteBranches": "원격 브랜치 ({count})", - "noMatchingBranches": "일치하는 브랜치가 없습니다" - }, - "externalConflictDialog": { - "title": "외부 파일 변경 감지됨", - "descriptionWithPath": "파일 {path} 이(가) 디스크에서 변경되었고 현재 편집 내용은 저장되지 않았습니다.", - "descriptionFallback": "현재 파일이 디스크에서 변경되었고 현재 편집 내용은 저장되지 않았습니다.", - "compare": "비교", - "savingCopy": "사본 저장 중...", - "saveAsCopy": "사본으로 저장", - "reload": "다시 불러오기" - }, - "deleteConfirm": { - "title": "삭제 확인", - "descriptionWithTarget": "{kind} \"{name}\"을(를) 삭제할까요? 이 작업은 되돌릴 수 없습니다.", - "descriptionFallback": "이 작업은 되돌릴 수 없습니다.", - "kindDirectory": "디렉터리", - "kindFile": "파일" - }, - "rollbackConfirm": { - "title": "롤백 확인", - "descriptionWithTarget": "파일 \"{name}\"의 로컬 변경 사항을 롤백할까요?", - "descriptionFallback": "이 파일의 로컬 변경 사항을 롤백할까요?" - }, - "terminalTitle": "터미널 · {name}" - }, - "commandDropdown": { - "loading": "로딩 중...", - "addCommand": "명령 추가", - "manageCommands": "명령 관리...", - "runCommandTitle": "실행: {command}", - "stopCommandTitle": "중지: {command}", - "manageDialog": { - "title": "명령 관리", - "empty": "아직 명령이 없습니다", - "noResults": "일치하는 명령이 없습니다", - "searchPlaceholder": "명령 검색", - "newCommand": "새 명령", - "nameLabel": "이름", - "commandLabel": "명령", - "dragSort": "드래그하여 정렬", - "dragSortCommand": "{name} 드래그하여 정렬", - "orderFailed": "명령 순서 저장에 실패했습니다", - "loadFailed": "명령을 불러오지 못했습니다", - "saveFailed": "명령을 저장하지 못했습니다", - "deleteFailed": "명령을 삭제하지 못했습니다", - "confirmDelete": { - "title": "명령을 삭제하시겠습니까?", - "message": "\"{name}\"을(를) 제거합니다. 이 작업은 되돌릴 수 없습니다." - } - } - }, - "workspaceContext": { - "confirmCloseDirtyTab": "저장하지 않고 \"{title}\" 탭을 닫을까요?", - "confirmCloseOtherDirtyTabs": "저장되지 않은 변경 사항이 있는 다른 탭을 닫을까요?", - "confirmCloseAllDirtyTabs": "저장되지 않은 변경 사항이 있는 모든 탭을 닫을까요?", - "unableLoadContent": "콘텐츠를 불러올 수 없습니다.\n\n{message}", - "previewRequestTimedOut": "미리보기 요청 시간이 초과되었습니다", - "diffRequestTimedOut": "Diff 요청 시간이 초과되었습니다", - "branchCompareRequestTimedOut": "브랜치 비교 요청 시간이 초과되었습니다", - "commitDiffRequestTimedOut": "커밋 Diff 요청 시간이 초과되었습니다", - "saveRequestTimedOut": "저장 요청 시간이 초과되었습니다", - "reloadRequestTimedOut": "다시 불러오기 요청 시간이 초과되었습니다", - "noChanges": "변경 사항이 없습니다.", - "noDiffOutput": "Diff 출력이 없습니다.", - "diffTitleWorkspace": "Diff · 워크스페이스", - "diffDescriptionWorkingTree": "작업 트리 (HEAD)", - "diffTitleFile": "차이 · {name}", - "compareTitleFile": "비교 · {name}", - "compareTitleBranch": "비교 · {branch}", - "compareDescriptionPath": "{path} · {branch}와 비교", - "compareDescriptionBranch": "{branch}와 비교", - "diffTitleCommitFile": "차이 · {name} @ {hash}", - "diffTitleCommit": "차이 · {hash}", - "diffDescriptionCommitPath": "{path} · 커밋 {commit}", - "diffDescriptionCommit": "커밋 {commit}", - "diffTitleConflictFile": "충돌 · {name}", - "diffDescriptionConflict": "{path} · 디스크 vs 저장되지 않음" - }, - "chat": { - "acpConnections": { - "actions": { - "openAgentsSettings": "에이전트 설정 열기", - "retry": "다시 시도" - }, - "agentsSetupHint": "설정 > 에이전트를 열어 설치를 관리하세요.", - "withSetupHint": "{message}\n{hint}", - "blocked": { - "missingConfig": "현재 에이전트 구성을 읽을 수 없습니다.", - "disabled": "{agent}은(는) 에이전트 설정에서 비활성화되어 있습니다. 연결 전에 활성화하세요.", - "unavailable": "{agent}은(는) 현재 플랫폼에서 사용할 수 없습니다.", - "sdkMissing": "{agent} SDK가 설치되어 있지 않습니다", - "adapterMissing": "{agent}의 ACP 어댑터가 설치되어 있지 않습니다" - }, - "backendErrors": { - "initializeTimeout": "{agent} 연결 핸드셰이크가 시간 초과되었습니다(60초 동안 응답 없음). 설정을 열어 에이전트 및 네트워크 구성을 확인하세요.", - "mcpRejectedByAgent": "codeg의 MCP 동반 프로세스를 전달하는 동안 {agent}이(가) 세션을 거부했습니다: {message} 이 에이전트가 MCP를 지원하지 않는다면 설정에서 ‘MCP 지원’을 끄고 다시 연결하세요.", - "processExited": "{agent} 프로세스가 예기치 않게 종료되었습니다.", - "spawnFailed": "{agent} 시작 실패: {message}", - "downloadFailed": "{agent} 다운로드 실패: {message}", - "sessionLoadResourceNotFound": "{agent} 세션 불러오기에 실패했습니다. 다시 불러와 재시도하거나 새 대화를 시작하세요.", - "sessionLoadUnavailable": "{agent}에서 이 세션을 복원할 수 없습니다. 세션이 종료되었거나 에이전트가 중지되었을 수 있습니다. 다시 불러와 재시도하거나 새 대화를 시작하세요.", - "turnFailedRefusal": "{agent}이(가) 이번 턴을 계속하지 않았습니다. 백엔드나 게이트웨이 오류일 수 있습니다. 에이전트 로그를 확인하세요.", - "turnFailedMaxTokens": "{agent}이(가) 이번 턴의 최대 토큰 한도에 도달했습니다.", - "turnFailedMaxTurnRequests": "{agent}이(가) 이번 턴에서 허용된 최대 요청 수에 도달했습니다.", - "turnFailedUnknown": "{agent}이(가) 알 수 없는 중지 사유로 턴을 종료했습니다.", - "grokModelSwitchIncompatibleAgent": "{agent}은(는) 기존 대화에서는 해당 모델로 전환할 수 없습니다. 새 세션을 시작하여 사용하세요.", - "turnFailedEmpty": "{agent}이(가) 어떤 응답도 생성하지 않고 턴을 종료했습니다.", - "turnFailedEmptyProtocol": "{agent}의 출력을 codeg가 구문 분석할 수 없습니다. 에이전트 버전이 프로토콜과 맞지 않을 수 있습니다.", - "turnFailedEmptyMetadata": "{agent}이(가) 이번 턴에 상태 업데이트(계획 / 모드 / 사용량)만 보내고 응답은 없었습니다.", - "detailsInAlerts": "상태 표시줄의 알림을 열고 세부 정보를 펼치면 에이전트 출력을 확인할 수 있습니다." - }, - "unableReadAgentConfig": "에이전트 구성을 읽을 수 없습니다: {message}", - "connectFailedTitle": "{agent} 연결 실패", - "toolFallbackTitle": "도구", - "eventErrorTitle": "에이전트 오류", - "notificationTurnComplete": "{agent} 응답이 완료되었습니다", - "notificationError": "{agent} 오류: {message}", - "claudeApiRetry": { - "fallbackError": "authentication_failed", - "retryingWithMax": "재시도 중 {attempt}/{max}", - "retryingAttempt": "{attempt}번째 재시도 중", - "retrying": "재시도 중", - "nextRetryIn": "{seconds}초 후 재시도", - "line": "{error}{status} · {retry}", - "lineWithDelay": "{error}{status} · {retry}, {delay}", - "httpStatus": " (HTTP {status})" - }, - "configOptionAdjusted": "{agent}이(가) {option}을(를) {requested} 대신 {actual}(으)로 설정했습니다" - }, - "connectionLifecycle": { - "tasks": { - "connectingTitle": "{agent}에 연결 중", - "connectingDescription": "연결을 설정하는 중", - "loadingSelectorsTitle": "{agent} 선택자 불러오는 중", - "loadingSelectorsDescription": "모드 및 세션 구성 옵션을 가져오는 중", - "initSessionTitle": "{agent} 세션 초기화 중", - "initSessionDescription": "세션 생성 및 설정 불러오는 중" - }, - "errors": { - "connectionFailed": "연결 실패", - "sendPromptFailed": "메시지 전송에 실패했습니다: {error}" - } - }, - "shared": { - "attachedResources": "첨부된 리소스", - "toolCallFailed": "도구 호출 실패" - }, - "messageThread": { - "emptyTitle": "아직 메시지가 없습니다", - "emptyDescription": "대화를 시작하면 여기에서 메시지를 볼 수 있습니다" - }, - "chatInput": { - "connecting": "연결 중...", - "agentResponding": "{agent} 응답 중...", - "sendMessage": "메시지 보내기..." - }, - "messageInput": { - "askAnything": "무엇이든 물어보세요...", - "removeAttachmentAria": "{name} 제거", - "attachFiles": "파일 첨부", - "addActions": "추가", - "quickMessages": "빠른 메시지", - "quickMessagesEmpty": "빠른 메시지가 없습니다", - "quickMessagesLoading": "불러오는 중...", - "pasteAsPlainText": "일반 텍스트로 붙여넣기", - "cut": "잘라내기", - "copy": "복사", - "selectAll": "모두 선택", - "pasteUnavailable": "클립보드를 읽을 수 없습니다. Ctrl/⌘V로 붙여넣으세요.", - "clipboardWriteFailed": "클립보드에 쓸 수 없습니다. 키보드 단축키를 사용하세요.", - "quickMessageUntitled": "제목 없음", - "liveFeedback": "라이브 피드백", - "liveFeedbackDisabledHint": "에이전트가 작업 중일 때 보낼 수 있습니다", - "dropFilesToAttach": "파일을 놓아 첨부", - "loadingSettings": "설정 불러오는 중...", - "loadingMode": "모드 불러오는 중...", - "modeLabel": "모드", - "toggleOn": "켬", - "toggleOff": "끔", - "agentSettings": "에이전트 설정", - "searchModel": "모델 검색...", - "searchModelAria": "모델 검색", - "modelListLabel": "모델", - "noModels": "모델을 찾을 수 없습니다", - "cancel": "취소", - "send": "보내기", - "forkAndSend": "포크 & 전송", - "queueMessage": "대기열에 추가", - "steerIntoTurn": "현재 턴에 삽입", - "steerQueuedInstead": "대신 대기열에 추가되었습니다. 다음 턴에 전송됩니다.", - "steerFailed": "현재 턴에 삽입하지 못했습니다", - "steerAttachmentsUnsupported": "텍스트만 지원됩니다. 첨부 파일이 있는 초안은 대기열을 이용하세요.", - "slashCommands": "슬래시 명령", - "slashSearchPlaceholder": "명령 검색...", - "slashSearchEmpty": "일치하는 명령이 없습니다", - "experts": "전문가", - "office": "일상 업무", - "research": "과학 연구", - "attachLocalUpload": "로컬 파일 첨부", - "attachServerFile": "서버 파일 첨부", - "attachUploadTooLarge": "{names}이(가) {limit}MB 업로드 한도를 초과하여 건너뛰었습니다.", - "attachUploadFailed": "{names} 업로드 실패.", - "attachUploadNotAFile": "{names} 은(는) 일반 파일이 아니므로(디렉터리 또는 특수 파일) 건너뛰었습니다.", - "attachUploadQuotaExceeded": "서버 업로드 저장 공간이 부족하여 {names} 을(를) 업로드하지 못했습니다.", - "attachUploadInProgress": "이미지가 아직 업로드 중입니다. 잠시 후 다시 시도하세요.", - "mentionEmpty": "일치하는 항목 없음", - "mentionLoading": "검색 중…", - "mentionListLabel": "멘션", - "mentionMore": "결과가 더 있습니다. 계속 입력하여 필터링하세요", - "mentionCount": "{count, plural, other {결과 #개}}", - "mentionGroupFile": "파일", - "mentionGroupAgent": "에이전트", - "mentionGroupSession": "세션", - "mentionGroupCommit": "커밋", - "mentionGroupSkill": "스킬" - }, - "messageQueue": { - "addToQueue": "대기열에 추가", - "saveEdit": "저장", - "cancelEdit": "편집 취소", - "editItem": "편집", - "deleteItem": "삭제" - }, - "welcomeInputPanel": { - "agentsSettingsPath": "설정 > 에이전트", - "autoConnectFallback": "{path}을(를) 열어 설치를 관리하세요.", - "autoConnectAppend": "{message}. {path}을(를) 열어 설치를 관리하세요.", - "enableAgentFirstPlaceholder": "세션을 시작하기 전에 최소 한 개의 에이전트를 활성화하세요...", - "prepareSessionFailed": "채팅 세션을 준비하지 못했습니다. 다시 시도해 주세요.", - "createConversationFailed": "대화를 만들지 못했습니다. 다시 시도해 주세요.", - "askAnythingPlaceholder": "무엇이든 물어보세요...", - "agentNotInstalled": "{agent}이(가) 설치되지 않았습니다 · 클릭하여 Agents 설정에서 설치하세요", - "agentAdapterNotInstalled": "{agent}의 ACP 어댑터가 설치되지 않았습니다(사용 중인 CLI와는 별개) · 클릭하여 Agents 설정에서 설치하세요" - }, - "welcomePanel": { - "greeting": "오늘은 무엇을 해볼까요?", - "tips": { - "tileTabs": "대화 탭을 우클릭하고 '바둑판 표시'를 선택하면 여러 세션을 나란히 비교할 수 있습니다", - "pinTab": "대화 탭을 더블클릭하면 고정되어 새로 열린 세션이 자동으로 대체하지 않습니다", - "shortcutsNewSearch": "{newConversation}로 새 대화를 열고, {searchConversations}로 기록을 검색할 수 있습니다", - "slashAtMention": "입력창에서 /를 입력하면 슬래시 명령, @를 입력하면 프로젝트 내 파일을 참조할 수 있습니다", - "pasteDropFiles": "스크린샷을 붙여넣거나 파일을 입력창에 드롭하면 바로 첨부됩니다", - "queueMessage": "에이전트가 응답 중일 때도 계속 입력하면 다음 메시지가 대기열에 들어가 응답 후 자동 전송됩니다", - "draftAutoSave": "보내지 않은 초안은 대화별로 자동 저장되어 돌아왔을 때 복원됩니다", - "forkSend": "전송 버튼의 드롭다운에서 '분기 후 전송'을 선택하면 현재 지점에서 새 탭으로 분기할 수 있습니다", - "exportConversation": "대화 내용을 우클릭하면 Markdown / HTML / 이미지로 내보낼 수 있습니다", - "chatChannels": "'설정 → 채팅 채널'에서 Telegram / Lark / WeChat을 연결하면 휴대폰에서 이어서 사용할 수 있습니다", - "shortcutsAuxPanel": "{toggleAuxPanel}로 오른쪽 패널을 열어 이번 세션에서 변경된 파일과 Git 변경 사항을 확인할 수 있습니다", - "shortcutsTerminalSidebar": "{toggleTerminal}로 내장 터미널, {toggleSidebar}로 사이드바를 토글할 수 있습니다", - "customShortcuts": "모든 단축키는 '설정 → 단축키'에서 자유롭게 변경할 수 있습니다", - "webService": "'설정 → 웹 서비스'를 켜면 팀원이 브라우저로 같은 codeg에 접속할 수 있습니다", - "fusionMode": "파일이나 diff를 열면 대화 옆에 자동으로 표시됩니다.", - "quickMessages": "입력창 옆 + 버튼에서 '빠른 메시지'를 선택하면 저장된 스니펫을 한 번에 삽입할 수 있습니다('설정 → 빠른 메시지'에서 관리)", - "experts": "+ 버튼의 '전문가 스킬' 메뉴에서 디버그 / 기획 등 사전 정의된 역할을 한 번에 불러올 수 있습니다", - "taskBoard": "할 일은 작업을 끝까지 처리합니다. 에이전트가 전용 워크트리에서 작업하고, 여러분은 diff를 검토한 뒤 병합합니다.", - "automations": "자동화는 저장한 프롬프트를 일정에 따라 실행합니다(매일 밤 리뷰 등). 실행마다 전용 워크트리를 쓸 수도 있습니다.", - "tokenUsage": "상태 표시줄의 대화 수를 클릭하면 토큰 사용량이 열립니다. 날짜·에이전트·모델·폴더별 사용량을 확인할 수 있습니다.", - "mentionTargets": "@는 파일만 참조하는 것이 아닙니다. 다른 에이전트를 멘션해 하위 작업을 맡기거나, 지난 세션·커밋·스킬을 참조할 수 있습니다.", - "splitGroups": "탭을 우클릭해 「오른쪽으로 분할」 또는 「아래로 분할」을 고르면 두 대화를 각각의 창에 열어 둘 수 있습니다.", - "worktrees": "브랜치 버튼에서 「새 워크트리」를 고르면 여러 에이전트가 같은 저장소에서 서로의 파일을 덮어쓰지 않고 동시에 작업할 수 있습니다.", - "importSessions": "터미널에서 이미 실행한 세션이 있다면 폴더 메뉴의 「로컬 세션 가져오기」로 그 기록을 codeg에 가져올 수 있습니다.", - "subSessions": "에이전트가 위임하면 하위 세션이 사이드바에서 상위 세션 아래에 중첩되어 표시됩니다. 행을 펼치면 각각이 무엇을 했는지 확인할 수 있습니다.", - "liveFeedback": "「+」 메뉴의 라이브 피드백은 에이전트가 진행 중인 턴에 메모를 끼워 넣습니다. 작업을 끊지 않아도 됩니다.", - "skillPacks": "설정 → 스킬 팩에는 코딩 전문가, 과학 연구, 오피스 스킬이 묶여 있습니다. 에이전트별로 켜고 끌 수 있습니다.", - "modelProviders": "설정 → 모델 제공업체에서 직접 API 키나 엔드포인트를 등록하면, 입력창에서 바로 모델을 고를 수 있습니다.", - "workspaceBackground": "설정 → 외관에서 작업 공간 배경 이미지, 패널 불투명도, 앱 글꼴을 바꿀 수 있습니다." - }, - "quickActions": { - "excel": "Excel 통합 문서", - "excelDesc": "데이터 표, 수식, 차트", - "word": "Word 문서", - "wordDesc": "보고서, 편지, 메모", - "ppt": "프레젠테이션", - "pptDesc": "전문 디자인 슬라이드", - "pitchDeck": "피치덱", - "pitchDeckDesc": "핵심 지표가 담긴 투자 자료", - "morph": "Morph 애니메이션", - "morphDesc": "영화 같은 슬라이드 전환", - "morph3d": "3D Morph", - "morph3dDesc": "3D 모델과 카메라 무빙", - "academic": "학술 논문", - "academicDesc": "인용과 구조를 갖춘 연구 논문", - "financial": "재무 모델", - "financialDesc": "재무제표, DCF, 예측", - "dashboard": "데이터 대시보드", - "dashboardDesc": "데이터로 KPI와 분석 생성", - "prompts": { - "excel": "다음 요구 사항으로 Excel 통합 문서를 만들어 주세요:\n\n[데이터, 표, 수식, 차트를 여기에 설명]", - "word": "다음 요구 사항으로 Word 문서를 만들어 주세요:\n\n[문서 내용, 구조, 서식을 여기에 설명]", - "ppt": "다음 요구 사항으로 PowerPoint 프레젠테이션을 만들어 주세요:\n\n[슬라이드, 내용, 디자인을 여기에 설명]", - "pitchDeck": "다음 요구 사항으로 투자 피치덱을 만들어 주세요:\n\n[회사, 투자 라운드, 핵심 지표를 여기에 설명]", - "morph": "Morph 전환 애니메이션이 있는 프레젠테이션을 만들어 주세요:\n\n[발표 주제와 원하는 시각 효과를 여기에 설명]", - "morph3d": "GLB 모델과 카메라 무빙이 있는 3D Morph 프레젠테이션을 만들어 주세요:\n\n[주제와 3D 비주얼 콘셉트를 여기에 설명]", - "academic": "다음 요구 사항으로 Word 학술 논문을 작성해 주세요:\n\n[연구 주제, 방법론, 주요 결과를 여기에 설명]", - "financial": "다음 요구 사항으로 Excel 재무 모델을 만들어 주세요:\n\n[재무제표, 예측, 분석을 여기에 설명]", - "dashboard": "다음 요구 사항으로 Excel 데이터 대시보드를 만들어 주세요:\n\n[데이터 소스, KPI, 차트를 여기에 설명]", - "scientific-brainstorming": "연구 방향을 브레인스토밍해 주세요. 학제 간 연결을 탐색하고 가정을 검토하며 유망한 공백을 찾습니다. 탐색 중인 분야: ", - "hypothesis-generation": "이 관찰을 검증 가능한 가설로 바꿔 주세요. 명확한 예측, 그럴듯한 메커니즘, 검증 실험을 제시합니다. 내 관찰: ", - "experimental-design": "데이터 수집 전에 엄밀한 실험을 설계해 주세요. 설계, 무작위화, 대조, 교란 회피 방법을 포함합니다. 연구하려는 것: ", - "statistical-power": "필요한 표본 크기를 정해 주세요. 내 설계에 대해 검정력 분석(효과크기, 유의수준, 검정력)을 진행합니다. 세부 정보: ", - "statistical-analysis": "이 데이터를 제대로 분석해 주세요. 올바른 검정 선택, 가정 점검, 효과크기 보고, 결과 서술을 합니다. 내 데이터와 질문: ", - "exploratory-data-analysis": "내 데이터 파일을 탐색적으로 분석해 주세요. 구조, 품질, 주목할 패턴을 요약하고 다음 단계를 제안합니다. 파일: ", - "scientific-visualization": "출판 수준의 그림을 만들어 주세요. 명확한 배치, 정직한 오차 막대, 색각 이상을 고려한 팔레트, 저널 서식을 사용합니다. 보여주려는 것: ", - "scientific-critical-thinking": "이 연구나 주장을 비판적으로 평가해 주세요. 근거의 질을 평가하고 편향과 교란을 찾아 결론을 따져봅니다. 대상: ", - "paper-lookup": "학술 데이터베이스에서 관련 논문과 오픈액세스 전문을 찾고 재사용할 수 있는 인용도 제시해 주세요. 찾는 것: " - }, - "paper-lookup": "논문 검색", - "paper-lookupDesc": "10개 학술 API(PubMed, arXiv, OpenAlex, Crossref…)에서 논문·인용·오픈액세스 전문을 검색합니다.", - "scientific-critical-thinking": "비판적 사고", - "scientific-critical-thinkingDesc": "과학적 주장과 근거의 질을 평가 — 편향·교란을 찾고 GRADE 및 비뚤림 위험 프레임워크를 적용.", - "scientific-visualization": "과학적 시각화", - "scientific-visualizationDesc": "출판 수준 그림 — 다중 패널 배치, 유의성 주석, 저널별 서식.", - "exploratory-data-analysis": "탐색적 데이터 분석", - "exploratory-data-analysisDesc": "200종 이상 형식의 과학 데이터 파일을 자동 탐색하고 품질 지표와 보고서를 생성합니다.", - "statistical-analysis": "통계 분석", - "statistical-analysisDesc": "안내형 통계 분석 — 검정 선택, 가정 점검, 효과크기, APA 형식 보고.", - "statistical-power": "통계적 검정력", - "statistical-powerDesc": "표본 크기와 검정력 분석 — 필요한 대상 수, 최소 검출 가능 효과, 검정력 곡선.", - "experimental-design": "실험 설계", - "experimental-designDesc": "데이터 수집 전에 엄밀한 연구를 설계 — 무작위화, 블록화, 대조, 요인/DOE 배치.", - "hypothesis-generation": "가설 생성", - "hypothesis-generationDesc": "관찰을 검증 가능한 가설로 전환하고 예측·메커니즘·검증 실험을 제시합니다.", - "scientific-brainstorming": "과학적 브레인스토밍", - "scientific-brainstormingDesc": "열린 연구 아이디어 발상 — 학제 간 연결을 탐색하고 가정을 검토하며 연구 공백을 찾습니다.", - "tabs": { - "office": "일상 업무", - "coding": "코드 개발", - "research": "과학 연구" - }, - "coding": { - "brainstormingDesc": "구현 전 의도와 요구사항 탐색", - "debuggingDesc": "수정 제안 전에 근본 원인 파악", - "writingSkillsDesc": "재사용 가능한 스킬 생성·편집·검증" - }, - "notEnabled": { - "title": "‘{skill}’ 스킬이 아직 {agent}에서 활성화되지 않았습니다", - "description": "설정에서 활성화하면 여기서 사용할 수 있습니다.", - "action": "활성화하기", - "hint": "스킬이 비활성화됨" - }, - "scrollPrev": "이전 스킬 표시", - "scrollNext": "다음 스킬 표시" - } - }, - "agentSelector": { - "noEnabledAgents": "활성화된 에이전트가 없습니다", - "openAgentsSettings": "에이전트 설정 열기", - "notInstalled": "설치되지 않음", - "moreAgents": "에이전트 더 보기 ({count})" - }, - "subAgentOverlay": { - "title": "서브 에이전트", - "collapsedSummary": "서브 에이전트 {count}", - "collapseAria": "서브 에이전트 접기" - }, - "agentPlanOverlay": { - "title": "에이전트 계획", - "collapsePlanAria": "계획 접기", - "collapsedSummary": "계획 {completed}/{total}", - "status": { - "completed": "완료", - "inProgress": "진행 중", - "pending": "대기", - "unknown": "알 수 없음" - }, - "priority": { - "high": "높음", - "medium": "중간", - "low": "낮음", - "unknown": "알 수 없음" - } - }, - "permissionDialog": { - "subtitle": "에이전트가 이 턴을 계속하기 위한 권한을 요청합니다.", - "queuedCount": "{count}건 대기 중", - "kindFallbackTool": "도구", - "command": "명령", - "cwd": "작업 디렉터리: {cwd}", - "filesSummary": "파일: {count}", - "moreFiles": "+{count}개 파일 더", - "plan": "계획", - "allowedActions": "허용된 작업", - "targetMode": "대상 모드: {mode}", - "optionGrants": "각 옵션이 부여하는 권한", - "changeScopeSession": "이 세션", - "changeScopeProcess": "이 실행", - "changeScopeUser": "사용자 설정에 저장", - "changeScopeProject": "프로젝트 설정에 저장", - "changeScopeProjectLocal": "로컬 프로젝트 설정에 저장", - "changeScopePersistent": "영구 저장" - }, - "questionDialog": { - "title": "에이전트가 질문하고 있습니다", - "placeholder": "답변을 입력하세요...", - "send": "전송" - }, - "messageBranch": { - "previousBranchAria": "이전 브랜치", - "nextBranchAria": "다음 브랜치", - "pageOf": "{current} / {total}" - }, - "terminal": { - "title": "터미널", - "running": "실행 중" - }, - "reasoning": { - "thinking": "생각 중…", - "thoughtForFewSeconds": "생각함", - "thoughtForSeconds": "생각함" - }, - "linkSafety": { - "errorCannotOpen": "로컬 파일을 열 수 없습니다", - "errorNoWorkspace": "현재 활성화된 워크스페이스 폴더가 없습니다.", - "errorFailedOpen": "로컬 파일 열기 실패", - "errorFailedLink": "링크 열기 실패", - "errorUnsupportedLinkProtocol": "이 링크 프로토콜은 지원되지 않습니다." - }, - "fileActions": { - "openInFinder": "Finder에서 열기", - "openInExplorer": "Explorer에서 열기", - "openInFileManager": "파일 관리자에서 열기", - "copyRelativePath": "상대 경로 복사", - "copyAbsolutePath": "절대 경로 복사", - "pathCopied": "경로가 복사되었습니다", - "copyPathFailed": "경로 복사에 실패했습니다", - "openFailed": "로컬 파일 열기 실패" - }, - "messageList": { - "attachedResources": "첨부된 리소스", - "loading": "불러오는 중...", - "loadEarlier": "이전 메시지 불러오기", - "loadingEarlier": "이전 메시지를 불러오는 중…", - "error": "오류: {message}", - "errorTitle": "세션 불러오기 실패", - "errorActionReload": "다시 불러오기", - "errorActionNewSession": "새 대화", - "emptyConversation": "이 대화에는 메시지가 없습니다.", - "systemMessage": "시스템 메시지", - "copyMessage": "복사", - "copied": "복사됨", - "downloadImage": "이미지 다운로드", - "downloadFailed": "다운로드 실패: {message}", - "imageGeneration": "이미지 생성", - "imageGenerationPending": "이미지 생성 중…", - "imageGenerationFailed": "이미지 생성 실패", - "model": "모델", - "tokenStats": "토큰 사용량", - "tokenInput": "입력", - "tokenOutput": "출력", - "tokenCacheRead": "캐시 읽기", - "tokenCacheWrite": "캐시 쓰기", - "duration": "소요 시간", - "completedAt": "완료 시각", - "jumpToPreviousUserMessage": "이전 사용자 메시지로 이동", - "showMore": "더보기", - "showLess": "접기" - }, - "liveTurnStats": { - "thinking": "생각 중...", - "streaming": "스트리밍 중", - "elapsedHours": "{value}시간", - "elapsedMinutes": "{value}분", - "elapsedSeconds": "{value}초", - "outputSpeedAria": "예상 출력 속도", - "outputSpeedTooltip": "예상 출력 속도(텍스트 + 추론)" - }, - "jsonTree": { - "viewRaw": "원본 JSON 보기", - "viewTree": "트리 보기", - "fields": "필드 {count}개", - "items": "항목 {count}개" - }, - "tool": { - "parameters": "매개변수", - "error": "오류", - "result": "결과", - "status": { - "approvalRequested": "승인 대기 중", - "approvalResponded": "응답됨", - "inputAvailable": "실행 중", - "inputStreaming": "대기 중", - "outputAvailable": "완료", - "outputDenied": "거부됨", - "outputError": "오류" - } - }, - "toolCallBlock": { - "tool": "도구", - "error": "오류", - "result": "결과" - }, - "delegation": { - "subAgentRunning": "서브에이전트 실행 중…", - "noDetail": "No detail available yet.", - "unknownAgent": "하위 에이전트", - "openDetail": "대화 보기", - "detailTitle": "서브에이전트 대화", - "detailDescription": "위임된 서브에이전트 대화를 읽기 전용으로 봅니다.", - "waitForResult": "작업 {task} 실행 결과 대기 중", - "waitForResultNoTask": "작업 실행 결과 대기 중", - "cancelTask": "작업 {task} 취소 중", - "cancelTaskNoTask": "작업 취소 중", - "resultPageOf": "{current} / {total}", - "prevResult": "이전 결과", - "nextResult": "다음 결과", - "noResultText": "이 확인에서는 결과가 없습니다", - "status": { - "starting": "시작 중", - "running": "실행 중", - "checked": "확인됨", - "waiting": "승인 대기 중", - "ok": "완료", - "err": { - "default": "실패", - "delegation_disabled": "비활성화됨", - "depth_limit": "깊이 제한", - "invalid_agent_type": "잘못된 에이전트", - "spawn_failed": "시작 실패", - "send_failed": "전송 실패", - "timeout": "시간 초과", - "canceled": "취소됨", - "child_refusal": "서브에이전트 거부", - "child_max_tokens": "서브에이전트: 토큰 한도", - "child_max_turn_requests": "서브에이전트: 요청 한도", - "child_empty": "서브에이전트 응답 없음", - "child_unknown": "서브에이전트: 오류", - "unknown": "알 수 없는 작업" - } - } - }, - "contentParts": { - "showingTailOutput": "성능을 위해 스트리밍 중에는 출력의 끝부분만 표시합니다.", - "result": "결과", - "unknown": "알 수 없음", - "inputTruncated": "입력이 잘렸습니다 — diff가 불완전할 수 있습니다.", - "replaceAll": "모두 바꾸기", - "filesCount": "파일: {count}", - "update": "업데이트", - "moreFiles": "+{count}개 파일 더", - "timeoutMs": "시간 초과: {timeout}ms", - "backgroundTrue": "백그라운드: true", - "scriptToolCalls": "도구 {count}개 호출", - "offset": "오프셋: {offset}", - "limit": "제한: {limit}", - "pages": "페이지: {pages}", - "mode": "모드: {mode}", - "cell": "셀: {cell}", - "shellSession": "세션 {id}", - "pathLabel": "경로:", - "globLabel": "Glob 패턴:", - "typeLabel": "유형:", - "outputLabel": "출력:", - "caseInsensitive": "대소문자 구분 안 함", - "multiline": "여러 줄", - "promptLabel": "프롬프트", - "subjectLabel": "제목", - "taskLabel": "작업", - "nameLabel": "이름:", - "agentPromptLabel": "프롬프트", - "agentModelLabel": "모델", - "agentRunning": "실행 중...", - "agentLiveTranscript": "실시간 활동", - "agentProgressTools": "도구 호출 {count}회", - "agentProgressTurns": "{count} 턴", - "agentProgressContext": "컨텍스트 {pct}%", - "agentSessionAction": "하위 에이전트 세션 보기", - "agentSessionTitle": "하위 에이전트 세션", - "agentSessionLoading": "하위 에이전트의 기록을 불러오는 중…", - "agentSessionEmpty": "하위 에이전트가 아직 아무것도 기록하지 않았습니다.", - "agentFallbackTitle": "서브 에이전트 시작 중…", - "agentCodexLaunchOnly": "시작되었습니다. Codex는 이 하위 에이전트의 진행 상황을 더 이상 알리지 않으며, 결과는 이 대화의 메시지로 도착합니다.", - "agentStatsBash": "명령", - "agentStatsRead": "파일 읽기", - "agentStatsSearch": "검색", - "agentStatsEdit": "편집", - "agentStatsOther": "기타", - "goal": { - "title": "목표:", - "titleWithStatus": "목표 {status}", - "objective": "목표", - "statusLabel": "상태", - "tokensUsed": "사용 tokens", - "budget": "예산", - "remaining": "남음", - "elapsed": "경과", - "tokens": "tokens", - "pause": "일시정지", - "clear": "지우기", - "status": { - "active": "진행 중", - "paused": "일시 중지", - "blocked": "차단됨", - "usageLimited": "사용량 제한", - "budgetLimited": "예산 제한", - "complete": "완료", - "limited": "한도 도달" - } - }, - "field": { - "file": "파일", - "notebook": "노트북", - "command": "명령", - "old": "이전", - "new": "새", - "pattern": "패턴", - "path": "경로", - "query": "쿼리", - "url": "URL:", - "description": "설명", - "content": "내용", - "source": "소스", - "prompt": "프롬프트", - "subject": "제목", - "taskId": "작업 ID", - "status": "상태", - "skill": "Skill", - "args": "인자", - "offset": "오프셋", - "limit": "제한", - "glob": "Glob 패턴", - "type": "유형", - "output": "출력", - "replaceAll": "모두 바꾸기", - "language": "언어", - "timeout": "시간 초과", - "background": "백그라운드", - "agentType": "에이전트 유형", - "library": "라이브러리", - "libraryId": "라이브러리 ID" - }, - "title": { - "edit": "편집", - "command": "명령", - "script": "스크립트", - "waitCommand": "대기 {command}", - "waitCell": "세션 {id} 대기", - "terminateCommand": "종료 {command}", - "terminateCell": "세션 {id} 종료", - "stdinChars": "입력 {chars}", - "todoWrite": "TodoWrite(할 일 업데이트)", - "read": "읽기", - "write": "쓰기", - "notebookEdit": "NotebookEdit(노트북 편집)", - "editFiles": "편집 ({count}개 파일)", - "editWithTarget": "{target} 편집", - "readWithTarget": "{target} 읽기", - "writeWithTarget": "{target} 쓰기", - "notebookEditWithTarget": "NotebookEdit({target})", - "globWithPattern": "Glob 패턴 {pattern}", - "listFilesWithPath": "파일 목록 {path}", - "grepWithPattern": "Grep 패턴 {pattern}", - "taskCreateWithSubject": "작업 생성: {subject}", - "taskUpdateWithStatus": "작업 업데이트 #{id} -> {status}", - "taskUpdate": "작업 업데이트 #{id}", - "webFetchWithUrl": "WebFetch ({url})", - "webSearchWithQuery": "WebSearch ({query})", - "todosProgress": "할 일 ({done}/{total})", - "skillWithName": "Skill: {name}", - "genericWithContext": "{tool} ({context})" - }, - "search": { - "noMatches": "일치하는 결과 없음", - "matchSummary": "{matches}개 일치 · {files}개 파일", - "fileSummary": "{files}개 파일", - "moreResults": "{count}개 결과가 더 있음(표시되지 않음)" - }, - "toolGroup": { - "search": "{count}회 검색", - "command": "명령 {count}개 실행", - "read": "파일 {count}회 읽기", - "memory": "기억 {count}개 회상", - "edit": "파일 {count}회 편집", - "fetch": "리소스 {count}개 가져오기", - "think": "{count}회 사고", - "todo": "할 일 {count}개 업데이트", - "task": "작업 {count}개 실행", - "other": "도구 {count}개 사용", - "errorSuffix": "{count}건 실패", - "joiner": " · " - }, - "planMode": { - "entered": "계획 모드 시작", - "planLabel": "계획", - "reviewApproved": "계획 승인됨 — 실행 중", - "reviewKept": "계획 모드 유지", - "reviewPending": "계획 결정 대기 중", - "submitted": "계획 제출됨", - "switched": "모드 전환됨" - }, - "backgroundTask": { - "title": "백그라운드 작업", - "titleWithId": "백그라운드 작업 · {id}", - "running": "실행 중", - "completed": "완료됨", - "failed": "실패", - "stopped": "중지됨", - "exitCode": "종료 코드 {code}", - "polledTimes": "{count}회 폴링", - "runningInBackground": "백그라운드", - "launchNote": "백그라운드에서 실행 중 · {id}" - }, - "codexScript": { - "outputMissing": "codex가 스크립트 출력을 잘라내면서 이 명령의 구분선이 사라져 출력을 귀속시킬 수 없습니다.", - "sharedWith": "이 구간에는 {commands}의 출력도 포함됩니다 — 구분선이 codex에 의해 잘렸습니다.", - "truncated": "잘림" - } - }, - "messageNav": { - "title": "메시지 탐색", - "collapse": "메시지 탐색 접기", - "collapsedSummary": "메시지 {count}", - "fileCount": "{count, plural, one {#개 파일} other {#개 파일}}", - "remove": "제거", - "noDiffDataAvailable": "{filePath}에 대한 diff 데이터가 없습니다" - }, - "replyArtifacts": { - "title": "변경된 파일", - "fileCount": "{count, plural, one {#개 파일} other {#개 파일}}", - "newFilesTitle": "새 파일", - "revealInFolder": "파일 관리자에서 표시", - "openFile": "{filePath} 열기", - "openInEditor": "편집기에서 열기", - "remove": "제거", - "noDiffDataAvailable": "{filePath}에 대한 diff 데이터가 없습니다" - }, - "askQuestion": { - "title": "에이전트가 선택을 요청합니다", - "subtitle": "답변 후 제출하세요. 언제든 건너뛸 수 있습니다", - "recommended": "추천", - "other": "기타", - "otherPlaceholder": "답변을 입력하세요…", - "singleSelect": "단일 선택", - "multiSelect": "다중 선택", - "skip": "건너뛰기", - "next": "다음", - "submit": "제출", - "submitError": "제출하지 못했습니다. 다시 시도해 주세요." - }, - "planApproval": { - "title": "에이전트가 계획을 제시했습니다 — 검토하세요", - "emptyPlan": "에이전트가 계획을 작성하지 않았습니다. 승인하여 구현을 시작하거나 변경을 요청하세요.", - "approve": "승인하고 시작", - "requestChanges": "변경 요청", - "abandon": "포기", - "feedbackPlaceholder": "무엇을 변경할까요?", - "sendChanges": "보내기", - "cancel": "취소", - "submitError": "제출하지 못했습니다. 다시 시도하세요." - }, - "feedbackCheckResult": { - "count": "피드백 {count}개", - "expand": "모든 피드백 표시", - "collapse": "접기", - "errorTitle": "피드백 확인 실패" - }, - "askQuestionResult": { - "title": "질문", - "answeredLabel": "질문과 답변:", - "awaiting": "답변을 기다리는 중…", - "declined": "이 질문을 건너뛰었습니다 — 에이전트가 자체 판단으로 진행했습니다.", - "noSelection": "선택 없음" - }, - "configStale": { - "agentConfigTitle": "에이전트 설정이 업데이트되었습니다", - "modelProviderTitle": "모델 공급자가 업데이트되었습니다", - "description": "이 세션은 아직 이전 설정을 사용 중입니다. 다시 연결하면 적용됩니다(대화 기록은 유지됩니다).", - "reconnect": "다시 연결하여 적용", - "reconnecting": "다시 연결하는 중…", - "reconnectDisabledDuringTurn": "현재 턴이 끝나면 다시 연결할 수 있습니다", - "dismiss": "닫기", - "reconnectFailed": "세션 다시 연결 실패", - "applied": "새 설정이 적용되었습니다" - }, - "piProjectTrust": { - "title": "이 프로젝트에 pi 리소스가 포함되어 있습니다", - "description": "pi가 저장소 자체의 .pi 파일을 불러오지 않고 있습니다. 확인 후 결정하세요.", - "descriptionExecutable": "저장소에 pi 확장이 포함되어 있으며, 확장은 시작 시 코드를 실행합니다. pi는 아직 불러오지 않았습니다. 결정하기 전에 확인하세요.", - "review": "검토…", - "dismiss": "닫기", - "dialogTitle": "이 프로젝트의 pi 리소스를 신뢰하시겠습니까?", - "dialogDescription": "폴더를 신뢰해야만 pi가 저장소 자체의 .pi 파일을 불러옵니다. 이 저장소의 내용을 신뢰하는 경우에만 허용하세요.", - "executionWarning": "확장은 코드입니다. 이 폴더를 신뢰하면 메시지를 보내기 전에 저장소의 확장이 pi 시작 시 사용자 권한으로 실행됩니다.", - "scopeNote": "이 결정은 pi의 trust.json에 저장되며 해당 폴더 아래의 모든 폴더에 적용되고, 터미널에서 직접 pi를 실행할 때에도 사용됩니다. 나중에 설정 → 에이전트 → Pi에서 변경할 수 있습니다.", - "trust": "프로젝트 신뢰", - "decline": "불러오지 않음", - "disabledDuringTurn": "현재 턴이 끝나면 사용할 수 있습니다", - "trustedToast": "프로젝트를 신뢰했습니다 — pi가 리소스를 불러오도록 다시 연결했습니다", - "declinedToast": "프로젝트 리소스를 불러오지 않습니다", - "saveFailed": "프로젝트 신뢰 설정을 저장하지 못했습니다", - "grantTitle": "이 프로젝트는 이미 신뢰됨", - "grantDescription": "pi가 이 저장소 자체의 .pi 파일을 불러옵니다. 무엇이 허용되는지 확인하세요.", - "grantInheritedDescription": "상위 폴더가 신뢰되어 pi가 이 저장소 자체의 .pi 파일을 불러옵니다. 무엇이 허용되는지 확인하세요.", - "grantDialogTitle": "이 프로젝트의 pi 리소스가 신뢰됨", - "grantDialogDescription": "pi가 이 저장소 자체의 .pi 파일을 불러오도록 허용되어 있습니다. 이전 codeg 버전은 폴더를 열 때 자동으로 이를 허용했으므로 확인을 요청받지 않았을 수 있습니다.", - "grantExecutionWarning": "확장은 코드입니다. 저장소의 확장은 메시지를 보내기 전에 pi 시작 시 사용자 권한으로 실행됩니다.", - "inheritedFrom": "신뢰 출처", - "revoke": "신뢰 취소", - "keepTrusted": "신뢰 유지", - "revokedToast": "신뢰를 취소했습니다 — 다시 연결하여 pi가 프로젝트 리소스를 불러오지 않습니다", - "trustedNoReconnect": "프로젝트를 신뢰했습니다 — pi가 다음에 시작할 때 적용됩니다", - "revokedNoReconnect": "신뢰를 취소했습니다 — pi가 다음에 시작할 때 적용됩니다" - }, - "collabAgent": { - "title": "서브 에이전트", - "errorTitle": "서브 에이전트 작업이 실패했습니다", - "statesLabel": "서브 에이전트", - "statusRunning": "실행 중", - "statusCompleted": "완료됨", - "statusFailed": "실패", - "statusPending": "시작 중", - "statusInterrupted": "중단됨", - "statusClosed": "종료됨", - "statusNotFound": "찾을 수 없음", - "opSpawn": "서브 에이전트 시작 중", - "opWait": "서브 에이전트 결과 가져오는 중", - "opClose": "서브 에이전트 종료 중", - "opResume": "서브 에이전트 재개 중" - }, - "contextCompaction": { - "compacting": "컨텍스트 압축 중…", - "compacted": "컨텍스트 압축 완료", - "compactedTokens": "컨텍스트 압축 완료 · {before} → {after} 토큰", - "failed": "컨텍스트 압축 실패" - }, - "sessionFailure": { - "category": { - "connection": "연결 문제", - "access": "액세스 문제", - "limit": "한도 도달", - "request": "요청 거부됨", - "service": "서비스 문제", - "unknown": "세션 문제" - }, - "action": { - "retry": "다시 시도", - "login": "로그인", - "newSession": "새 세션" - }, - "recovered": "복구됨", - "retryUnavailable": "다시 보낼 메시지가 없습니다.", - "toggleDetails": "세부 정보 전환" - }, - "backgroundTasks": { - "running": "백그라운드 작업 {count}개 실행 중", - "settling": "백그라운드 결과 동기화 중…", - "settledFallback": "백그라운드 작업이 종료되었습니다 ({status})", - "cardRunning": "백그라운드에서 실행 중", - "cardLaunchedPending": "백그라운드 작업 시작됨", - "cardCompleted": "백그라운드 작업 완료", - "cardFinishedWithStatus": "백그라운드 작업 종료 ({status})", - "cardResultPending": "결과가 아직 반환되지 않았습니다" - }, - "proposedPlan": { - "title": "제안된 계획", - "planning": "계획 중…" - } - }, - "diffPreview": { - "mode": { - "added": "추가됨", - "deleted": "삭제됨", - "renamed": "이름 변경됨", - "modified": "수정됨" - }, - "hunkLabel": "청크 {index}", - "loadingHunk": "Hunk 로딩 중...", - "noDiffData": "Diff 데이터 없음", - "showRemainingLines": "나머지 {count}줄 표시" - }, - "conversationContextBar": { - "folderTitle": "작업 폴더", - "branchTitle": "작업 브랜치", - "searchFolder": "Search folder...", - "searchBranch": "Search branch...", - "noFolders": "No folders", - "noBranches": "No branches", - "noBranch": "(no branch)", - "chatModeLabel": "채팅 모드", - "commit": "Commit", - "push": "Push", - "merge": "Merge", - "toasts": { - "folderChanged": "Switched to {name}", - "openFolderFailed": "Failed to open folder", - "switchedToChatMode": "채팅 모드로 전환했습니다", - "openStashFailed": "Failed to open stash window", - "openMergeFailed": "Failed to open merge window" - } - }, - "cloneDialog": { - "title": "저장소 클론", - "repositoryUrl": "저장소 URL", - "repositoryUrlPlaceholder": "https://github.com/user/repo.git", - "directory": "디렉터리", - "directoryPlaceholder": "대상 디렉터리 선택...", - "browseDirectory": "디렉터리 찾아보기", - "cancel": "취소", - "clone": "클론", - "clonePath": "클론 경로: {path}" - }, - "toasts": { - "cloneFailed": "저장소 클론에 실패했습니다" - } - }, - "ProjectBoot": { - "title": "프로젝트 부트", - "tabs": { - "shadcn": "shadcn", - "hyperframes": "HyperFrames" - }, - "hyperframes": { - "title": "HyperFrames 비디오 프로젝트", - "subtitle": "HTML을 비디오로 만드는 프로젝트를 생성합니다. 이후 워크스페이스 에이전트가 작성하고 렌더링할 수 있습니다.", - "resolution": "해상도", - "skillsTitle": "에이전트 스킬", - "skillsDesc": "선택한 에이전트에 HyperFrames 스킬을 전역(심볼릭 링크)으로 설치하여 영상 작성·렌더링을 지원합니다.", - "recheck": "다시 확인", - "installedBadge": "설치됨", - "skillsInstall": "스킬 설치 / 업데이트", - "skillsInstalling": "스킬 설치 중…", - "skillsInstalled": "HyperFrames 스킬 설치 완료", - "skillsInstallFailed": "HyperFrames 스킬 설치 실패" - }, - "config": { - "base": "베이스", - "style": "스타일", - "baseColor": "베이스 색상", - "theme": "테마", - "chartColor": "차트 색상", - "iconLibrary": "아이콘 라이브러리", - "font": "글꼴", - "fontHeading": "제목 글꼴", - "menuAccent": "메뉴 강조", - "menuColor": "메뉴 색상", - "radius": "둥글기", - "template": "템플릿", - "createProject": "프로젝트 만들기", - "sectionStyle": "스타일", - "sectionColors": "색상", - "sectionTypography": "타이포그래피", - "sectionInterface": "인터페이스" - }, - "preview": { - "loading": "미리보기 로딩 중..." - }, - "createDialog": { - "title": "프로젝트 만들기", - "projectName": "프로젝트 이름", - "projectNamePlaceholder": "my-app", - "frameworkTemplate": "프레임워크 템플릿", - "packageManager": "패키지 매니저", - "saveDirectory": "저장 디렉토리", - "saveDirectoryPlaceholder": "디렉토리 선택...", - "browseDirectory": "찾아보기", - "projectPath": "프로젝트 생성 위치: {path}", - "advancedOptions": "고급 옵션", - "base": "기본 라이브러리", - "enableRtl": "RTL 지원 활성화", - "enableRtlDescription": "오른쪽에서 왼쪽으로 쓰는 언어(예: 아랍어, 히브리어)의 레이아웃 지원 활성화", - "pmChecking": "확인 중...", - "pmNotInstalled": "설치되지 않음", - "cancel": "취소", - "create": "만들기", - "creating": "프로젝트 생성 중..." - }, - "toasts": { - "createFailed": "프로젝트 생성에 실패했습니다", - "createSuccess": "프로젝트가 성공적으로 생성되었습니다", - "openWorkspaceFailed": "프로젝트가 생성되었지만 작업 공간에서 열지 못했습니다" - }, - "errors": { - "directoryExists": "대상 디렉터리가 이미 존재합니다", - "commandFailed": "프로젝트 생성 명령이 실패했습니다." - } - }, - "WebServiceSettings": { - "addressSwitchHint": "전환해도 여기에 표시되고 열리는 주소만 바뀝니다. 서비스는 모든 인터페이스에서 수신하며 어떤 주소로도 접속할 수 있습니다.", - "sectionTitle": "웹 서비스", - "sectionDescription": "활성화하면 브라우저를 통해 Codeg에 원격으로 접속할 수 있습니다", - "port": "포트", - "status": "상태", - "autoStart": "자동 시작", - "autoStartHint": "Codeg가 시작될 때 웹 서비스를 시작합니다", - "running": "실행 중", - "stopped": "중지됨", - "processing": "처리 중...", - "start": "시작", - "stop": "중지", - "startFailed": "시작 실패", - "stopFailed": "중지 실패", - "saveConfigFailed": "웹 서비스 설정 저장 실패", - "open": "열기", - "hide": "숨기기", - "show": "표시", - "copy": "복사", - "qrcode": "QR 코드", - "qrcodeTitle": "스캔하여 열기", - "qrcodeHint": "휴대폰으로 스캔하여 브라우저에서 Codeg를 엽니다", - "addressLabel": "접속 주소", - "tokenLabel": "접속 토큰", - "tokenHint": "웹 클라이언트 첫 접속 시 이 토큰을 입력하세요", - "tokenPlaceholder": "비워두면 자동 생성", - "regenerate": "재생성", - "stalePortOccupiedTitle": "포트 {port}이(가) 다른 프로세스에 의해 사용 중입니다", - "stalePortUnknownTitle": "포트 {port}의 상태를 확인할 수 없습니다", - "stalePortHint": "포트가 해제될 때까지 Codeg은 바인딩할 수 없습니다. 위의 포트를 변경하거나 사용 중인 프로세스를 종료하세요.", - "errors": { - "alreadyRunning": "웹 서비스가 이미 실행 중입니다", - "invalidAddress": "호스트 또는 포트 형식이 올바르지 않습니다", - "portInUse": "포트 {port}가 이미 사용 중입니다. 해당 포트를 사용 중인 프로세스를 종료하거나 다른 포트를 선택하세요", - "permissionDenied": "권한이 부족합니다. 1024 이상의 포트를 사용하거나 더 높은 권한으로 실행하세요", - "addressUnavailable": "이 주소는 현재 시스템에서 사용할 수 없습니다", - "bindFailed": "주소 바인딩에 실패했습니다" - } - }, - "DirectoryBrowser": { - "title": "디렉토리 찾아보기", - "pathPlaceholder": "디렉토리 경로 입력...", - "goHome": "홈 디렉토리로 이동", - "navigateUp": "상위 디렉토리로 이동", - "select": "선택", - "cancel": "취소", - "loading": "로딩 중...", - "emptyDirectory": "이 디렉토리는 비어 있습니다", - "errorLoadingDir": "디렉토리 로딩 실패", - "permissionDenied": "권한이 없습니다" - }, - "ChatChannelSettings": { - "loading": "로딩 중...", - "sectionTitle": "채팅 채널", - "sectionDescription": "IM 봇을 설정하여 이벤트 알림을 수신하고 코딩 활동을 조회합니다.", - "addChannel": "채널 추가", - "noChannels": "설정된 채팅 채널이 없습니다.", - "channelName": "이름", - "channelNamePlaceholder": "내 Telegram 봇", - "channelType": "채널 유형", - "lark": "Lark (飛書)", - "weixin": "WeChat", - "dailyReport": "일일 리포트", - "dailyReportTime": "발송 시간", - "nameRequired": "채널 이름을 입력하세요.", - "tokenRequired": "토큰을 입력하세요.", - "chatIdRequired": "Chat ID를 입력하세요.", - "topicMode": "토픽 그룹 모드", - "topicModeHint": "Telegram forum topics를 별도 Codeg 세션으로 라우팅합니다. Bot은 forum supergroup에 있어야 하며 topics 관리 권한이 필요합니다.", - "loadFailed": "채널 로딩에 실패했습니다.", - "saveFailed": "저장에 실패했습니다.", - "connectSuccess": "채널이 연결되었습니다.", - "connectFailed": "연결에 실패했습니다", - "disconnectSuccess": "채널이 연결 해제되었습니다.", - "disconnectFailed": "연결 해제에 실패했습니다.", - "testSuccess": "연결 테스트를 통과했습니다.", - "testFailed": "연결 테스트에 실패했습니다", - "deleteSuccess": "채널이 삭제되었습니다.", - "deleteFailed": "채널 삭제에 실패했습니다.", - "deleteConfirmTitle": "채널 삭제", - "deleteConfirmMessage": "이 채널과 메시지 기록이 영구 삭제됩니다. 계속하시겠습니까?", - "cancel": "취소", - "delete": "삭제", - "create": "생성", - "save": "저장", - "channelListTitle": "설정된 채널", - "channelListDescription": "활성화된 채널은 서비스 시작 시 자동으로 연결됩니다.", - "editChannel": "채널 편집", - "editSuccess": "채널이 업데이트되었습니다.", - "tokenPlaceholderKeep": "비워두면 현재 값 유지", - "weixinScanTitle": "QR 코드 스캔", - "weixinScanDescription": "WeChat을 열고 QR 코드를 스캔하여 연결하세요.", - "weixinQrcodeExpired": "QR 코드가 만료되었습니다.", - "weixinRefreshQrcode": "새로고침", - "weixinWaitingScan": "스캔 대기 중...", - "weixinPollError": "연결이 불안정합니다. 재시도 중...", - "weixinReconnectNotice": "iLink 프로토콜 제한으로 인해, 재연결할 때마다 먼저 봇에게 메시지를 보내야 이벤트 트리거가 활성화됩니다.", - "connect": "연결", - "disconnect": "연결 해제", - "test": "연결 테스트", - "tabs": { - "channels": "채널", - "commands": "명령어", - "events": "이벤트", - "other": "기타" - }, - "commands": { - "title": "내장 명령어", - "description": "채팅 채널에서 사용 가능한 Bot 명령어입니다. 그룹 채팅에서는 메시지를 처리하려면 @Bot이 필요합니다.", - "prefixLabel": "명령어 접두사", - "prefixDescription": "Bot 명령어를 실행하는 접두사, 1-3개의 영숫자가 아닌 문자 (기본값 /).", - "prefixSaved": "명령어 접두사가 저장되었습니다.", - "prefixSaveFailed": "명령어 접두사 저장에 실패했습니다.", - "prefixInvalid": "접두사는 1-3개의 영숫자가 아닌 문자여야 합니다.", - "save": "저장", - "folderDesc": "작업 폴더 선택", - "agentDesc": "AI 에이전트 선택", - "taskDesc": "세션 생성 및 작업 실행", - "sessionsDesc": "폴더 내 활성 세션 목록", - "resumeDesc": "최근 대화 / 세션 재개", - "cancelDesc": "현재 작업 취소", - "approveDesc": "에이전트 권한 요청 승인", - "denyDesc": "에이전트 권한 요청 거부", - "searchDesc": "키워드로 대화 검색", - "todayDesc": "오늘의 활동 요약", - "statusDesc": "채널 연결 상태", - "helpDesc": "도움말 표시" - }, - "events": { - "title": "이벤트 알림", - "description": "이벤트를 활성화하면, 트리거 시 채널로 푸시됩니다.", - "turnComplete": "턴 완료", - "turnCompleteDesc": "에이전트 턴이 종료될 때", - "error": "에이전트 오류", - "errorDesc": "에이전트에 오류가 발생했을 때", - "permissionRequest": "권한 요청", - "permissionRequestDesc": "에이전트가 작업 권한을 요청할 때", - "questionRequest": "에이전트 질문", - "questionRequestDesc": "에이전트가 질문할 때", - "userPromptSent": "사용자 메시지", - "userPromptSentDesc": "메시지를 보낼 때 — 알림에 메시지 내용이 포함됩니다", - "saved": "이벤트 필터가 업데이트되었습니다.", - "saveFailed": "이벤트 필터 저장에 실패했습니다.", - "loadFailed": "설정을 불러오지 못했습니다.", - "retry": "다시 시도", - "webhooksTitle": "Webhook", - "webhooksDescription": "활성화된 이벤트가 발생하면 하나 이상의 URL로 JSON을 POST합니다. 위의 이벤트 필터는 Webhook에도 적용됩니다.", - "webhookUrlPlaceholder": "https://example.com/webhook", - "addWebhook": "Webhook 추가", - "removeWebhook": "Webhook 삭제", - "webhookSave": "저장", - "webhooksSaved": "Webhook을 저장했습니다.", - "webhooksSaveFailed": "Webhook 저장에 실패했습니다.", - "webhookInvalidUrl": "유효한 http(s) URL을 입력하세요.", - "docsTitle": "요청 형식", - "docsMethod": "메서드", - "docsContentType": "Content-Type", - "docsNote": "활성화된 각 이벤트는 모든 URL로 전달됩니다. Webhook은 디바운스되지 않으며 위의 이벤트 필터가 계속 적용됩니다.", - "editWebhook": "Webhook 편집", - "enableWebhook": "Webhook 활성화", - "webhookDuplicate": "이미 설정된 URL입니다.", - "cancel": "취소", - "webhooksEmpty": "아직 구성된 Webhook이 없습니다.", - "deleteWebhookTitle": "Webhook 삭제", - "deleteWebhookMessage": "이 Webhook을 삭제하시겠습니까? 이 URL로 더 이상 이벤트가 전달되지 않습니다.", - "delete": "삭제" - }, - "language": { - "title": "메시지 언어", - "description": "이벤트 알림, 명령 응답, 일일 보고서를 채팅 채널로 전송할 때 사용하는 언어입니다.", - "saved": "메시지 언어가 저장되었습니다.", - "saveFailed": "메시지 언어 저장에 실패했습니다.", - "en": "영어", - "zh-cn": "중국어 간체", - "zh-tw": "중국어 번체", - "ja": "일본어", - "ko": "한국어", - "es": "스페인어", - "de": "독일어", - "fr": "프랑스어", - "pt": "포르투갈어", - "ar": "아랍어" - } - }, - "ModelProviderSettings": { - "sectionTitle": "모델 제공업체", - "sectionDescription": "에이전트의 API 제공업체 자격 증명을 관리합니다.", - "filterAll": "전체", - "providerListTitle": "구성된 제공업체", - "addProvider": "제공업체 추가", - "editProvider": "제공업체 편집", - "noProviders": "아직 구성된 모델 제공업체가 없습니다.", - "providerName": "이름", - "providerNamePlaceholder": "예: OpenAI, Anthropic", - "apiUrl": "API URL", - "apiUrlPlaceholder": "https://api.openai.com/v1", - "apiKey": "API 키", - "apiKeyPlaceholder": "sk-...", - "apiKeyKeepCurrent": "현재 값을 유지하려면 비워두세요", - "agentTypes": "에이전트 유형", - "agentTypesRequired": "최소 하나의 에이전트 유형을 선택하세요.", - "agentType": "에이전트 유형", - "agentTypeRequired": "에이전트 유형을 선택하세요.", - "agentTypeImmutableHint": "에이전트 유형은 생성 후 변경할 수 없습니다.", - "model": "모델", - "modelPlaceholderCodex": "gpt-5.6-sol / gpt-5.5", - "modelPlaceholderGemini": "gemini-3-pro-preview", - "claudeMainModel": "메인 모델", - "claudeReasoningModel": "추론 모델 (사고)", - "claudeHaikuDefaultModel": "기본 Haiku 모델", - "claudeSonnetDefaultModel": "기본 Sonnet 모델", - "claudeOpusDefaultModel": "기본 Opus 모델", - "claudeCustomModelOption": "사용자 지정 모델 ID", - "claudeCustomModelOptionName": "사용자 지정 모델 이름", - "claudeCustomModelOptionDescription": "사용자 지정 모델 설명", - "claudeCustomModelOptionHint": "Claude 모델 선택기에 사용자 지정 항목 하나를 추가합니다(예: 사용자 지정 게이트웨이/프록시를 통해 제공되는 모델). 이름과 설명은 선택적 표시 설정입니다.", - "nameRequired": "제공업체 이름은 필수입니다.", - "apiUrlRequired": "API URL은 필수입니다.", - "apiKeyRequired": "API 키는 필수입니다.", - "loadFailed": "제공업체를 불러오지 못했습니다.", - "saveFailed": "변경 사항을 저장하지 못했습니다.", - "createSuccess": "제공업체가 생성되었습니다.", - "editSuccess": "제공업체가 업데이트되었습니다.", - "deleteSuccess": "제공업체가 삭제되었습니다.", - "deleteConfirmTitle": "제공업체 삭제", - "deleteConfirmMessage": "제공업체 \"{name}\"을(를) 영구적으로 삭제하시겠습니까?", - "deleteBlockedByAgent": "{agents}이(가) 이 공급자를 사용 중입니다. 삭제하기 전에 연결을 해제해 주세요.", - "cancel": "취소", - "delete": "삭제", - "create": "생성", - "save": "저장", - "affectedRunningSessions": "{count}개의 실행 중인 세션은 다시 연결하면 변경 사항이 적용됩니다" - }, - "SkillMatrix": { - "loading": "불러오는 중…", - "searchPlaceholder": "이름, ID 또는 설명으로 검색", - "empty": "표시할 항목이 없습니다.", - "emptySearch": "현재 검색과 일치하는 항목이 없습니다.", - "skillColumn": "스킬", - "selectAll": "표시된 항목 모두 선택", - "selectSkill": "{name} 선택", - "everything": { - "label": "일괄", - "enable": "모두 활성화(표시된 항목)", - "disable": "모두 비활성화(표시된 항목)" - }, - "columnMenu": { - "enableAll": "모든 스킬 활성화", - "disableAll": "모든 스킬 비활성화" - }, - "rowMenu": { - "label": "{name} 일괄 작업", - "enableAll": "모든 에이전트에 활성화", - "disableAll": "모든 에이전트에서 비활성화" - }, - "bulk": { - "selected": "{count}개 선택됨", - "targetAll": "모든 에이전트", - "targetSome": "에이전트 {count}개", - "enable": "활성화", - "disable": "비활성화", - "clear": "지우기" - }, - "confirm": { - "disableTitle": "이 링크를 비활성화할까요?", - "disableBody": "codeg가 관리하는 스킬 링크 {count}개를 제거합니다. 사용자 지정 디렉터리를 차지한 스킬은 그대로 유지됩니다. 언제든지 다시 활성화할 수 있습니다.", - "cancel": "취소", - "confirm": "비활성화" - }, - "toasts": { - "loadFailed": "스킬 상태를 불러오지 못했습니다", - "applyFailed": "변경 사항을 적용하지 못했습니다", - "enabled": "링크 {count}개를 활성화했습니다", - "disabled": "링크 {count}개를 비활성화했습니다", - "enabledPartial": "{ok}개 활성화, {failed}개 실패", - "disabledPartial": "{ok}개 비활성화, {failed}개 실패" - }, - "detail": { - "enableForAgents": "에이전트에 활성화", - "preview": "SKILL.md 미리보기", - "loadingContent": "콘텐츠 불러오는 중…" - }, - "copyModeHint": "복사됨(링크 아님) — 업데이트 후 최신 버전을 받으려면 다시 활성화하세요" - }, - "ExpertsSettings": { - "title": "전문가 스킬", - "description": "AI 코딩 에이전트를 위해 엄선되고 실전 검증된 스킬 워크플로를 활성화하세요. 각 전문가는 superpowers 프로젝트의 독립 실행형 스킬이며 — codeg가 중앙 복사본을 관리하고 선택한 에이전트에 연결합니다.", - "loading": "전문가 로딩 중…", - "loadingContent": "콘텐츠 로딩 중…", - "emptyExperts": "사용 가능한 전문가가 없습니다. 애플리케이션 로그를 확인하세요.", - "emptySelection": "전문가를 선택하여 내용을 보고 활성화를 관리하세요.", - "emptySearch": "현재 검색과 일치하는 전문가가 없습니다.", - "searchPlaceholder": "이름, ID 또는 설명으로 전문가 검색", - "enableForAgents": "에이전트에 활성화", - "noAgents": "ACP 에이전트가 감지되지 않았습니다.", - "copyModeWarning": "복사됨(연결되지 않음). 최신 버전을 받으려면 codeg 업데이트 후 재활성화하세요.", - "previewTitle": "SKILL.md 미리보기", - "categories": { - "discovery": "발견 및 설계", - "planning": "계획", - "execution": "실행", - "quality": "품질 및 테스트", - "debugging": "디버깅", - "review": "검토 및 통합", - "meta": "메타" - }, - "states": { - "not_linked": "활성화되지 않음", - "linked_to_codeg": "활성화됨", - "linked_elsewhere": "차단됨 — 다른 링크가 존재함", - "blocked_by_real_directory": "차단됨 — 사용자 정의 스킬이 이 이름을 점유 중", - "broken": "손상된 링크" - }, - "badges": { - "userModified": "사용자가 수정함" - }, - "actions": { - "openCentralDir": "중앙 폴더 열기", - "refresh": "새로고침" - }, - "toasts": { - "loadFailed": "전문가 세부 정보를 로드하지 못했습니다", - "enabled": "이 에이전트에 전문가가 활성화되었습니다", - "disabled": "이 에이전트에서 전문가가 비활성화되었습니다", - "enableFailed": "전문가 활성화에 실패했습니다", - "disableFailed": "전문가 비활성화에 실패했습니다", - "openFolderFailed": "폴더를 열지 못했습니다" - } - }, - "ScienceSettings": { - "title": "과학 연구 스킬", - "description": "AI 코딩 에이전트를 위한 엄선된 과학 연구 스킬(가설 생성, 실험 설계, 통계, 시각화, 비판적 평가, 문헌 검색)을 활성화합니다. codeg가 중앙 복사본을 관리하고 선택한 에이전트에 각 스킬을 연결합니다.", - "loading": "과학 연구 스킬 불러오는 중…", - "emptySkills": "사용 가능한 과학 연구 스킬이 없습니다. 애플리케이션 로그를 확인하세요.", - "searchPlaceholder": "이름, ID 또는 설명으로 과학 연구 스킬 검색", - "categories": { - "ideation": "아이디어", - "design": "연구 설계", - "analysis": "분석", - "visualization": "시각화", - "evaluation": "평가", - "literature": "문헌" - }, - "states": { - "not_linked": "활성화되지 않음", - "linked_to_codeg": "활성화됨", - "linked_elsewhere": "차단됨 — 다른 링크가 존재함", - "blocked_by_real_directory": "차단됨 — 사용자 정의 스킬이 이 이름을 점유 중", - "broken": "손상된 링크" - }, - "badges": { - "userModified": "사용자가 수정함", - "needsKey": "API 키 필요", - "needsSetup": "설정 필요할 수 있음" - }, - "actions": { - "openCentralDir": "중앙 폴더 열기", - "refresh": "새로고침" - }, - "toasts": { - "openFolderFailed": "폴더를 열지 못했습니다" - } - }, - "OfficeToolsSettings": { - "title": "Office 도구", - "description": "OfficeCLI 스킬을 관리하여 Excel, Word, PowerPoint 파일을 생성합니다. OfficeCLI를 설치하고 스킬을 동기화한 후 에이전트별로 활성화할 수 있습니다.", - "loadingContent": "콘텐츠 로드 중…", - "emptySkills": "스킬이 없습니다. OfficeCLI를 설치하고 스킬을 동기화하세요.", - "emptySelection": "스킬을 선택하여 내용을 확인하고 활성화를 관리합니다.", - "emptySearch": "검색과 일치하는 스킬이 없습니다.", - "searchPlaceholder": "이름, ID 또는 설명으로 스킬 검색", - "enableForAgents": "에이전트에 활성화", - "noAgents": "ACP 에이전트가 감지되지 않았습니다.", - "installFirst": "스킬을 활성화하려면 먼저 OfficeCLI를 설치하세요.", - "syncFirst": "콘텐츠를 로드하려면 먼저 스킬을 동기화하세요.", - "noContent": "콘텐츠가 없습니다.", - "copyModeWarning": "복사됨(링크 아님). 최신 버전을 가져오려면 다시 동기화하세요.", - "previewTitle": "SKILL.md 미리보기", - "detection": { - "installed": "설치됨", - "notInstalled": "미설치", - "notRunnable": "설치됨, 실행 불가", - "installHint": "OfficeCLI를 설치하여 AI 에이전트에 오피스 문서 생성 스킬을 활성화합니다.", - "install": "설치", - "uninstall": "제거", - "syncSkills": "스킬 동기화" - }, - "categories": { - "general": "일반", - "presentations": "프레젠테이션", - "documents": "문서", - "spreadsheets": "스프레드시트" - }, - "states": { - "not_linked": "비활성", - "linked_to_codeg": "활성", - "linked_elsewhere": "차단됨 — 다른 링크가 존재합니다", - "blocked_by_real_directory": "차단됨 — 사용자 정의 스킬이 이 이름을 사용 중", - "broken": "링크 끊김" - }, - "badges": { - "notSynced": "미동기화" - }, - "actions": { - "refresh": "새로고침" - }, - "toasts": { - "loadFailed": "스킬 상세 로드 실패", - "enabled": "이 에이전트에 스킬 활성화됨", - "disabled": "이 에이전트에서 스킬 비활성화됨", - "enableFailed": "스킬 활성화 실패", - "disableFailed": "스킬 비활성화 실패", - "installSuccess": "OfficeCLI 설치 성공", - "installFailed": "OfficeCLI 설치 실패", - "uninstallSuccess": "OfficeCLI 제거됨", - "uninstallFailed": "OfficeCLI 제거 실패", - "syncSuccess": "{synced}개 스킬 동기화 완료", - "syncPartial": "{synced}개 동기화, {errors}개 실패", - "syncFailed": "스킬 동기화 실패" - }, - "autoPreviewLabel": "미리보기 자동 열기", - "autoPreviewHint": "에이전트가 Word, Excel, PowerPoint 파일을 만들거나 편집하면 실시간 미리보기를 자동으로 엽니다." - }, - "SkillPacksSettings": { - "title": "스킬 팩", - "description": "codeg가 중앙에서 관리하고 각 AI 에이전트에 연결하는 엄선된 스킬 모음입니다 — 코딩 전문가, 과학 연구, 오피스 문서 도구. 아래에서 에이전트별로 활성화하세요.", - "tabs": { - "experts": "전문가", - "science": "과학 연구", - "office": "오피스 도구", - "custom": "사용자 지정" - }, - "actions": { - "openCentralDir": "중앙 폴더 열기", - "refresh": "새로고침" - }, - "toasts": { - "openFolderFailed": "폴더를 열지 못했습니다" - } - }, - "QuickMessagesSettings": { - "title": "빠른 메시지", - "description": "재사용 가능한 메시지 스니펫을 관리합니다. 드래그하여 순서를 변경하세요.", - "loading": "빠른 메시지 불러오는 중…", - "emptyList": "빠른 메시지가 없습니다. \"새로 만들기\"를 클릭하여 추가하세요.", - "emptySelection": "편집할 빠른 메시지를 선택하세요.", - "searchPlaceholder": "제목 또는 내용으로 검색", - "untitled": "제목 없음", - "actions": { - "new": "새로 만들기", - "save": "저장", - "delete": "삭제", - "dragSort": "드래그하여 순서 변경", - "dragSortMessage": "빠른 메시지 순서 변경: {name}" - }, - "fields": { - "title": "제목", - "titlePlaceholder": "이 메시지에 짧은 제목을 지정하세요", - "content": "내용", - "contentPlaceholder": "여기에 메시지 내용을 입력하세요" - }, - "confirmDelete": { - "title": "빠른 메시지를 삭제하시겠습니까?", - "message": "\"{name}\" 이(가) 영구적으로 삭제됩니다. 계속하시겠습니까?", - "cancel": "취소", - "confirm": "삭제" - }, - "toasts": { - "loadFailed": "빠른 메시지를 불러오지 못했습니다", - "createFailed": "빠른 메시지를 만들지 못했습니다", - "saveFailed": "빠른 메시지를 저장하지 못했습니다", - "deleteFailed": "빠른 메시지를 삭제하지 못했습니다", - "saveOrderFailed": "순서를 저장하지 못했습니다", - "created": "빠른 메시지가 생성되었습니다", - "saved": "빠른 메시지가 저장되었습니다", - "deleted": "빠른 메시지가 삭제되었습니다" - } - }, - "Pet": { - "badge": { - "running": "실행 중 {count}개", - "waiting": "승인 대기 {count}개", - "error": "오류 {count}개" - }, - "panel": { - "title": "활성 세션", - "empty": "활성 세션 없음", - "emptyHint": "실행 중이거나 사용자의 조치가 필요한 세션이 여기에 표시됩니다.", - "statusRunning": "실행 중", - "statusWaiting": "대기 중", - "statusError": "오류", - "subAgentOf": "하위 에이전트" - }, - "menu": { - "scale": "크기", - "openManager": "펫 관리", - "close": "닫기" - }, - "loadError": "펫을 불러오지 못했습니다", - "missingPetIdParam": "선택된 펫이 없습니다", - "summonButton": "펫", - "manager": { - "title": "데스크톱 펫", - "description": "Codex 호환 스프라이트 시트로 동작하는 데스크톱 동반자.", - "addPet": "펫 추가", - "importFromCodex": "Codex 에서 가져오기", - "noPets": "펫이 아직 없습니다. 새로 추가하거나 Codex 에서 가져오세요.", - "setActive": "활성화", - "active": "활성", - "edit": "편집", - "delete": "삭제", - "deleteConfirm": "펫 \"{name}\"을(를) 삭제할까요? 디스크에서도 함께 제거됩니다.", - "summon": "펫 창 호출", - "openCodexHelp": "Codex 펫은 ~/.codex/pets/ 아래에 설치되어야 합니다. 찾을 수 없습니다.", - "specRequirement": "스프라이트 시트는 너비 1536px, 높이는 208px의 배수(예: 1872 또는 2288)인 투명 PNG 또는 WebP여야 합니다.", - "form": { - "id": "펫 ID", - "idHelp": "소문자/숫자/'-'/'_' 만 가능. 최대 64자.", - "displayName": "표시 이름", - "description": "설명 (선택)", - "spritesheet": "스프라이트 시트", - "chooseFile": "파일 선택", - "replaceFile": "스프라이트 교체", - "saveCreate": "펫 추가", - "saveUpdate": "변경 저장", - "cancel": "취소" - }, - "errors": { - "missingId": "펫 ID 는 필수입니다", - "missingName": "표시 이름은 필수입니다", - "missingSpritesheet": "스프라이트 시트는 필수입니다", - "addFailed": "펫 추가에 실패했습니다", - "updateFailed": "펫 갱신에 실패했습니다", - "deleteFailed": "펫 삭제에 실패했습니다", - "loadFailed": "펫 목록 로드에 실패했습니다", - "setActiveFailed": "활성 펫 설정에 실패했습니다", - "summonFailed": "펫 창 호출에 실패했습니다" - } - }, - "import": { - "title": "Codex 에서 가져오기", - "subtitle": "~/.codex/pets/ 에서 발견된 펫 목록입니다.", - "selectAll": "전체 선택", - "alreadyImported": "이미 가져옴", - "renameOnConflict": "충돌 시 -imported 접미어로 이름 변경", - "import": "선택 항목 가져오기", - "noneFound": "가져올 수 있는 Codex 펫이 없습니다.", - "imported": "가져오기 완료", - "failed": "가져오기 실패", - "close": "닫기" - }, - "marketplace": { - "openMarketplace": "펫 마켓", - "title": "펫 마켓", - "search": "펫 검색", - "kindFilter": { - "all": "전체", - "object": "오브젝트", - "animal": "동물", - "person": "인물", - "creature": "생물" - }, - "sortFilter": { - "latest": "최신", - "popular": "인기", - "views": "조회수순" - }, - "refresh": "새로고침", - "install": "설치", - "installing": "설치 중", - "reinstall": "다시 설치", - "reinstallConfirm": "로컬 펫 \"{name}\" 을(를) 덮어쓰시겠습니까? 기존 데이터가 교체됩니다.", - "cancel": "취소", - "stats": { - "views": "조회수", - "downloads": "다운로드", - "likes": "좋아요" - }, - "actions": { - "idle": "대기", - "running_right": "오른쪽 달리기", - "running_left": "왼쪽 달리기", - "waving": "손 흔들기", - "jumping": "점프", - "failed": "실패", - "waiting": "기다림", - "running": "실행", - "review": "리뷰" - }, - "page": "{page} / {total} 페이지", - "prev": "이전", - "next": "다음", - "empty": "조건에 맞는 펫이 없습니다.", - "successInstalled": "\"{name}\" 을(를) 설치했습니다", - "errors": { - "loadFailed": "마켓을 불러오지 못했습니다", - "installFailed": "설치에 실패했습니다", - "alreadyInstalled": "해당 펫이 이미 존재합니다" - } - } - }, - "RemoteWorkspace": { - "openRemoteWorkspace": "Open remote workspace", - "manage": "Manage remote workspace", - "manageTitle": "Remote Workspace connections", - "empty": "No remote connections", - "searchPlaceholder": "Search remote workspaces", - "orderFailed": "Failed to save remote workspace order", - "dragSort": "Drag to sort", - "dragSortConnection": "Drag to sort {name}", - "newConnection": "New connection", - "loading": "Loading", - "loadingConnection": "Loading remote connection", - "name": "Name", - "baseUrl": "Service URL", - "token": "Access token", - "save": "Save", - "delete": "Delete", - "confirmDelete": { - "title": "Delete remote connection?", - "message": "This will remove \"{name}\" from this device. This action cannot be undone.", - "cancel": "Cancel", - "confirm": "Delete" - }, - "saved": "Remote connection saved.", - "deleted": "Remote connection deleted.", - "loadFailed": "Failed to load remote connections", - "saveFailed": "Failed to save remote connection", - "deleteFailed": "Failed to delete remote connection", - "openFailed": "Failed to open remote workspace", - "connectionLoadFailed": "Failed to load remote connection: {message}", - "connectionExpired": "Remote connection \"{name}\" is expired. Update its token and reload this window." - }, - "ServerFileBrowser": { - "title": "서버 파일 선택", - "pathPlaceholder": "디렉토리 경로 입력...", - "goHome": "홈 디렉토리로", - "navigateUp": "상위 디렉토리로", - "select": "선택", - "cancel": "취소", - "loading": "로드 중...", - "emptyDirectory": "이 디렉토리는 비어 있습니다", - "errorLoadingDir": "디렉토리 로드 실패", - "selectedCount": "{count}개 선택됨" - }, - "BackupSettings": { - "title": "백업 및 복원", - "description": "codeg 데이터의 이동 가능한 백업을 내보내거나 백업에서 복원합니다.", - "tabs": { - "backup": "백업", - "restore": "복원" - }, - "export": { - "includeExternal": "대화 내용 포함", - "includeExternalHint": "각 CLI의 대화 기록(Claude, Codex, Gemini 등)도 함께 보관합니다. 용량이 커집니다.", - "passphrase": "암호문 (선택)", - "passphrasePlaceholder": "비워 두면 암호화하지 않습니다", - "passphraseConfirm": "암호문 확인", - "passphraseMismatch": "암호문이 일치하지 않습니다.", - "noPassphraseWarning": "이 백업에는 비밀 정보(API 키, 토큰)가 평문으로 포함됩니다. 안전한 곳에 보관하세요.", - "passphraseLossWarning": "이 암호문으로 암호화됩니다. 분실하면 백업을 복구할 수 없습니다.", - "button": "백업 내보내기", - "inProgress": "백업 만드는 중…", - "success": "백업을 만들었습니다.", - "started": "백업 다운로드를 시작했습니다." - }, - "restore": { - "selectFile": "백업 파일 선택", - "passphrasePrompt": "이 백업은 암호화되어 있습니다. 암호문을 입력하세요.", - "unlock": "잠금 해제", - "preview": { - "title": "백업 정보", - "encrypted": "암호화됨", - "compatible": "호환됨", - "incompatible": "호환되지 않음", - "createdAt": "생성: {value}", - "appVersion": "앱 버전: {value}", - "incompatibleHint": "이 백업은 더 새로운 버전의 codeg에서 만들어져 복원할 수 없습니다." - }, - "replaceWarning": "복원하면 현재의 모든 codeg 데이터(데이터베이스 및 업로드)가 교체됩니다. 현재 데이터는 먼저 스냅샷되어 복구할 수 있습니다.", - "keyringNote": "데스크톱의 GitHub/채팅 토큰은 OS 키체인에 저장되어 포함되지 않습니다. 복원 후 다시 입력하세요.", - "button": "복원", - "staging": "복원 준비 중…", - "staged": "복원이 준비되었습니다. 다시 시작합니다…", - "restarting": "복원이 준비되었습니다. 서버를 다시 시작합니다…", - "restartTimeout": "서버가 제때 돌아오지 않았습니다. 서버가 켜지면 페이지를 새로 고치세요.", - "externalSideLocation": "대화 기록을 {path}에 복원했습니다", - "confirmTitle": "모든 데이터를 교체할까요?", - "confirmBody": "현재 codeg 데이터베이스와 업로드를 백업으로 교체한 후 다시 시작합니다. 현재 데이터는 먼저 스냅샷됩니다.", - "cancel": "취소", - "confirmAction": "교체 후 다시 시작", - "external": { - "title": "대화 내용", - "hint": "이 백업에는 CLI 대화 기록이 포함됩니다. 복원 위치를 선택하세요.", - "modeSkip": "복원 안 함", - "modeSide": "안전한 별도 폴더에 복원", - "modeOriginal": "CLI 원래 위치에 복원", - "forceOverwrite": "기존 파일 덮어쓰기", - "forceOverwriteHint": "CLI 폴더에 이미 있는 파일을 교체합니다.", - "scanning": "충돌 확인 중…", - "noConflicts": "덮어쓸 기존 파일이 없습니다.", - "conflictCount": "기존 파일 {count}개가 영향을 받습니다.", - "conflictSkipNote": "덮어쓰기를 켜지 않으면 기존 파일은 유지(건너뜀)됩니다." - }, - "restartFailed": "복원이 준비되었지만 서버를 다시 시작하지 못했습니다. 수동으로 다시 시작해 복원을 적용하세요." - }, - "remoteUnsupported": "백업 및 복원은 codeg를 실행 중인 컴퓨터의 데이터를 대상으로 합니다. 현재 원격 작업 공간에 연결되어 있습니다. 해당 서버에서 직접 백업을 관리하세요." - }, - "backup": { - "restore": { - "error": { - "badPassphrase": "암호문이 올바르지 않거나 백업이 손상되었습니다.", - "corrupted": "백업 아카이브가 손상되었습니다.", - "unknownFormat": "이 파일은 인식할 수 있는 codeg 백업이 아닙니다.", - "newerVersion": "이 백업은 codeg {backupVersion}에서 만들어졌으며 현재 버전({appVersion})보다 최신입니다.", - "alreadyPending": "적용 대기 중인 복원이 이미 있습니다. 먼저 다시 시작해 적용한 뒤 새 복원을 준비하세요." - } - }, - "error": { - "diskSpace": "작업을 완료할 디스크 공간이 부족합니다.", - "cancelled": "작업이 취소되었습니다." - } - }, - "WebConnection": { - "disconnectedTitle": "연결이 끊어졌습니다", - "reconnectingDescription": "서버에 다시 연결하는 중입니다. 보통 몇 초 내에 자동으로 복구됩니다.", - "reconnectNow": "지금 다시 연결", - "sessionExpiredTitle": "세션이 만료되었습니다", - "sessionExpiredDescription": "세션이 더 이상 유효하지 않습니다. 계속하려면 다시 로그인하세요.", - "goToLogin": "로그인으로 이동" - }, - "LiveFeedback": { - "placeholder": "{agent}이(가) 작업하는 동안 메모 보내기…", - "agentFallback": "에이전트", - "ariaLabel": "라이브 피드백 메모", - "dialogTitle": "라이브 피드백", - "dialogDescription": "에이전트가 작업하는 동안 메모를 보냅니다. 현재 단계를 중단하지 않고 다음 확인 시 읽습니다.", - "dialogDescriptionInstant": "에이전트가 작업하는 동안 메모를 보냅니다. 메모는 현재 턴에 즉시 삽입되어 에이전트가 바로 확인합니다.", - "channelDowngraded": "이 세션에서는 즉시 삽입을 사용할 수 없습니다. 메모는 저장되어 에이전트가 다음에 확인할 때 전달됩니다.", - "send": "보내기", - "cancel": "취소", - "pending": "대기 중", - "delivered": "수신됨", - "turnEndedUnread": "에이전트가 피드백을 읽기 전에 턴을 마쳤습니다.", - "sendAsMessage": "새 메시지로 보내기", - "dismiss": "닫기", - "turnEndedResent": "턴이 종료되어 새 메시지로 보냈습니다.", - "turnEnded": "턴이 이미 종료되었습니다.", - "submitFailed": "메모를 보내지 못했습니다" - }, - "AgentToolsSettings": { - "title": "대화 내 도구", - "description": "codeg가 대화 안에서 에이전트에게 추가로 제공하는 도구입니다. 에이전트가 시작할 때 주입되므로 변경 사항은 이후에 시작한 에이전트부터 적용됩니다.", - "feedbackLabel": "라이브 피드백", - "feedbackHint": "에이전트가 작업하는 동안 메모와 수정 사항을 보낼 수 있습니다. 즉시 삽입을 지원하는 에이전트는 실행 중인 턴에 메모가 바로 삽입됩니다. 그 외 에이전트는 피드백 확인 도구로 읽는데, 보통 프롬프트에서 언급할 때만 확인합니다. 예: 메시지에 \"실시간 피드백을 정기적으로 확인해\"를 추가하세요.", - "questionLabel": "사용자에게 질문", - "questionHint": "에이전트가 작업을 멈추고 대화 입력창 위에 표시되는 객관식 질문을 할 수 있습니다. 답변(또는 건너뛰기)할 때까지 에이전트는 대기합니다.", - "sessionInfoLabel": "세션 정보 가져오기", - "sessionInfoHint": "메시지에서 참조한 세션(세션 배지)을 에이전트가 조회하여 제목, 에이전트, 상태, 작업 공간, 토큰 사용량, 최근 메시지를 읽을 수 있도록 합니다.", - "automationsLabel": "자동화 만들기", - "automationsHint": "대화를 일정에 따라 실행되는 자동화로 저장합니다. 기본값은 꺼짐 — 자동화는 이후 스스로 에이전트를 시작합니다.", - "workTasksLabel": "할 일 작업 만들기", - "workTasksHint": "대화에서 할 일 보드에 카드를 추가합니다. 기본값은 꺼짐 — 앱 상태를 기록합니다.", - "save": "저장", - "saving": "저장 중…", - "saved": "도구 설정을 저장했습니다", - "saveFailed": "도구 설정 저장에 실패했습니다", - "loadFailed": "불러오기 실패: {detail}" - }, - "NotificationSoundSettings": { - "title": "알림음", - "description": "에이전트 이벤트가 발생하면 짧은 알림음을 재생합니다. 채팅 채널로 전송되는 것과 같은 이벤트이며, 이 설정은 이 기기에만 적용됩니다.", - "enableHint": "기본값은 꺼짐입니다. 알림음은 이 브라우저 또는 앱의 작업 공간 창에서만 재생됩니다.", - "volume": "음량", - "preview": "미리 듣기", - "previewEvent": "{event} 알림음 미리 듣기", - "onlyWhenUnfocused": "창이 활성화되지 않았을 때만 재생", - "onlyWhenUnfocusedHint": "Codeg을 보고 있는 동안에는 소리를 내지 않습니다.", - "eventsTitle": "이벤트", - "eventsHint": "이벤트마다 소리를 선택하세요. “무음”을 선택하면 재생하지 않습니다. 같은 이벤트가 몇 초 안에 반복되면 한 번만 재생됩니다.", - "toneNone": "무음", - "toneChime": "차임", - "toneDing": "딩", - "toneBlip": "블립", - "tonePop": "팝", - "toneAlert": "알림", - "toneDescend": "하강음" - }, - "LogsSettings": { - "loading": "불러오는 중…", - "sectionTitle": "실행 로그", - "sectionDescription": "애플리케이션 진단 로그를 보고 구성합니다. 로그는 로컬 파일에 기록되며 실시간 보기를 위해 메모리에도 보관됩니다.", - "captureTitle": "로그 수준", - "captureDescription": "기록되는 상세 수준을 제어합니다. 수준이 높을수록(Debug, Trace) 더 많이 기록되지만 로그도 커집니다. '끔'은 로깅을 비활성화합니다.", - "captureLabel": "수집 수준", - "levels": { - "off": "끔", - "error": "오류", - "warn": "경고", - "info": "정보", - "debug": "디버그", - "trace": "추적" - }, - "viewerTitle": "최근 로그", - "viewerDescription": "최근 로그 레코드를 실시간으로 봅니다. 수준으로 필터링하거나 텍스트를 검색하세요.", - "searchPlaceholder": "메시지 또는 대상 검색…", - "viewLevels": { - "all": "모든 수준", - "error": "오류 이상", - "warn": "경고 이상", - "info": "정보 이상", - "debug": "디버그 이상", - "trace": "추적 이상" - }, - "pause": "일시정지", - "resume": "실시간", - "refresh": "새로고침", - "clear": "지우기", - "openFolder": "폴더 열기", - "shownCount": "{shown} / {total} 표시됨", - "empty": "표시할 로그가 없습니다.", - "levelSaveFailed": "로그 수준 저장 실패", - "openFolderFailed": "로그 폴더 열기 실패", - "downloadFailed": "로그 파일 다운로드 실패", - "filesTitle": "로그 파일", - "filesDescription": "실시간 버퍼를 넘어선 기록을 위해 디스크에서 전체 로그 파일을 다운로드합니다.", - "filesEmpty": "아직 로그 파일이 없습니다.", - "download": "다운로드", - "downloadTruncated": "파일이 커서 최신 {size}만 다운로드했습니다. 전체 파일은 로그 디렉터리에 있습니다.", - "captureEnvLocked": "로그 수준은 RUST_LOG / CODEG_LOG 환경 변수로 제어됩니다. 변경하려면 해당 변수를 수정하세요.", - "targetsTitle": "모듈별 재정의", - "targetsDescription": "전역 레벨을 바꾸지 않고 특정 모듈(예: codeg_lib::acp)의 레벨을 따로 설정합니다.", - "targetsAdd": "추가", - "targetsRemove": "재정의 제거", - "toggleDetails": "세부 정보 전환" - }, - "Automations": { - "title": "자동화", - "new": "새 자동화", - "empty": "아직 자동화가 없습니다", - "emptyHint": "하나를 만들어 에이전트 작업을 예약하거나 수동으로 실행하세요.", - "name": "이름", - "namePlaceholder": "예: 야간 PR 검토", - "prompt": "프롬프트", - "promptPlaceholder": "에이전트가 무엇을 하길 원하나요?", - "agent": "에이전트", - "folder": "워크스페이스 폴더", - "folderPlaceholder": "폴더 선택", - "isolation": "격리", - "isolationWorktree": "실행마다 새 worktree", - "isolationShared": "폴더에서 실행", - "isolationSharedCaveat": "실행이 이 폴더의 작업 트리를 직접 사용하므로 커밋하지 않은 변경 사항과 충돌할 수 있습니다. 각 실행을 격리하려면 워크트리 옵션을 활성화하세요.", - "trigger": "트리거", - "triggerSchedule": "예약 실행", - "triggerManual": "수동만", - "cron": "예약(cron)", - "cronPlaceholder": "0 9 * * 1-5", - "timezone": "시간대", - "nextRun": "다음 실행", - "branch": "브랜치", - "branchOptional": "브랜치(선택)", - "enabled": "사용", - "save": "저장", - "cancel": "취소", - "edit": "편집", - "delete": "삭제", - "runNow": "지금 실행", - "cancelRun": "실행 취소", - "runHistory": "실행 기록", - "noRuns": "아직 실행 기록이 없습니다", - "allFolders": "모든 폴더", - "filterAll": "전체", - "noMatches": "일치하는 자동화가 없습니다", - "viewConversation": "대화 보기", - "lastRun": "마지막 실행", - "never": "없음", - "running": "실행 중", - "deleteTitle": "이 자동화를 삭제할까요?", - "deleteDescription": "자동화와 예약이 삭제됩니다. 실행 기록은 유지됩니다.", - "statusRunning": "실행 중", - "statusSucceeded": "성공", - "statusFailed": "실패", - "statusCancelled": "취소됨", - "statusSkipped": "건너뜀", - "errorName": "이름은 필수입니다", - "errorPrompt": "프롬프트는 필수입니다", - "errorCron": "예약 자동화에는 cron 식이 필요합니다", - "errorFolder": "워크스페이스 폴더를 선택하세요", - "presetHourly": "매시간", - "presetDaily": "매일 오전 9시", - "presetWeekdays": "평일 오전 9시", - "presetCustom": "사용자 지정", - "probing": "옵션 불러오는 중…", - "retry": "다시 시도", - "configNone": "이 에이전트에는 구성 가능한 옵션이 없습니다", - "inherit": "에이전트 기본값", - "mode": "모드", - "config": "구성", - "branchPlaceholder": "(기본 브랜치)", - "selectHint": "세부 정보를 보려면 자동화를 선택하세요", - "refresh": "새로고침", - "onboardTitle": "반복적인 에이전트 작업 자동화", - "onboardHint": "코드 리뷰, 의존성 업데이트, 이슈 분류를 일정에 따라 또는 필요할 때 에이전트가 수행하도록 예약하세요.", - "headerSubtitle": "예약 및 온디맨드 에이전트 작업", - "startFromTemplate": "템플릿으로 시작", - "blankTitle": "빈 자동화", - "blankDesc": "에이전트 작업을 처음부터 구성합니다.", - "backToTemplates": "템플릿", - "sectionSchedule": "일정 및 대상", - "sectionTarget": "대상", - "sectionAction": "동작", - "actionLaunchSession": "세션 시작", - "actionEnqueueTask": "작업 대기열에 추가", - "actionEnqueueTaskHint": "실행될 때마다 이 자동화 이름을 제목으로 하는 할 일 작업이 대상 폴더의 할 일 목록에 추가되며, 작업 엔진이 보드 설정에 따라 실행합니다.", - "sectionPrompt": "프롬프트", - "nextIn": "{rel} 후 실행", - "manual": "수동", - "schedEveryMinutes": "{n}분마다", - "schedHourly": "1시간마다", - "schedDaily": "매일 {time}", - "schedWeekdays": "평일 {time}", - "schedWeekly": "매주 {day} {time}", - "schedMonthly": "매월 {day}일 {time}", - "dow0": "일요일", - "dow1": "월요일", - "dow2": "화요일", - "dow3": "수요일", - "dow4": "목요일", - "dow5": "금요일", - "dow6": "토요일", - "tplCodeReviewTitle": "코드 리뷰", - "tplCodeReviewDesc": "최근 변경 사항에서 버그, 회귀, 품질 문제를 검토합니다.", - "tplDependencyUpdatesTitle": "의존성 업데이트", - "tplDependencyUpdatesDesc": "오래된 의존성을 찾아 안전한 업그레이드를 제안합니다.", - "tplTestCoverageTitle": "테스트 커버리지", - "tplTestCoverageDesc": "테스트되지 않은 코드 경로를 찾아 누락된 테스트를 추가합니다.", - "tplTodoSweepTitle": "TODO 정리", - "tplTodoSweepDesc": "TODO와 FIXME 주석을 모아 우선순위에 따라 분류합니다.", - "tplCiTriageTitle": "CI 분류", - "tplCiTriageDesc": "최근 실패한 검사를 조사하고 수정을 제안합니다.", - "tplReleaseNotesTitle": "릴리스 노트", - "tplReleaseNotesDesc": "지난 릴리스 이후의 변경 사항을 요약해 변경 로그를 만듭니다.", - "tplSecurityAuditTitle": "보안 감사", - "tplSecurityAuditDesc": "취약점과 위험한 패턴을 스캔하고 결과를 보고합니다.", - "enable": "활성화", - "disable": "비활성화", - "moreActions": "추가 작업", - "statusDisabled": "비활성화됨", - "cronBuilderTitle": "일정 빌더", - "cronFreqLabel": "빈도", - "cronFreqMinutes": "N분마다", - "cronFreqHourly": "매시간", - "cronFreqDaily": "매일", - "cronFreqWeekdays": "평일", - "cronFreqWeekly": "매주", - "cronFreqMonthly": "매월", - "cronFreqCustom": "사용자 지정", - "cronEveryLabel": "간격(분)", - "cronTimeLabel": "시간", - "cronHourLabel": "시", - "cronMinuteLabel": "분", - "cronDowLabel": "요일", - "cronDomLabel": "일", - "cronApply": "적용", - "cronPreviewLabel": "미리 보기", - "cronOpenBuilder": "일정 빌더 열기", - "branchDefault": "기본 브랜치", - "branchUseCustom": "\"{query}\" 사용", - "branchLocal": "로컬", - "branchRemote": "원격", - "branchSearchPlaceholder": "브랜치 검색…", - "branchNone": "브랜치 없음" - }, - "Tasks": { - "title": "할 일", - "new": "새 작업", - "empty": "아직 작업이 없습니다", - "emptyHint": "할 일을 추가하고 실행하세요. 에이전트가 독립된 worktree에서 작업하고, 결과를 검토한 뒤 병합합니다.", - "emptyColTodo": "아직 할 일이 없습니다", - "emptyColInProgress": "진행 중인 작업이 없습니다", - "emptyColAttention": "처리할 작업이 없습니다", - "emptyColDone": "완료된 작업이 아직 없습니다", - "allFolders": "모든 폴더", - "showCanceled": "취소됨 표시", - "showArchived": "보관된 항목 표시", - "filter": "필터", - "viewSwitchToBoard": "보드 보기로 전환", - "viewSwitchToList": "목록 보기로 전환", - "statusFilter": "상태", - "statusFilterAll": "모든 상태", - "listEmpty": "현재 필터와 일치하는 작업이 없습니다", - "listColStatus": "상태", - "listColTask": "작업", - "listColLocation": "위치", - "listColChanges": "변경", - "listColUpdated": "업데이트", - "colTodo": "할 일", - "colInProgress": "진행 중", - "colAttention": "처리 필요", - "colDone": "완료", - "statusTodo": "할 일", - "statusQueued": "대기 중", - "statusPreparing": "준비 중", - "statusRunning": "실행 중", - "statusAwaitingInput": "입력 대기", - "statusReview": "검토 대기", - "statusMerging": "병합 중", - "statusDone": "완료", - "statusFailed": "실패", - "statusCanceled": "취소됨", - "statusInterrupted": "중단됨", - "badgeCleanupFailed": "정리 실패", - "badgeWorktreeKept": "worktree 유지", - "badgeWorktreeRemoved": "worktree 삭제됨", - "filesChanged": "{count}개 파일", - "actionStart": "시작", - "actionSchedule": "예약 실행", - "actionCancel": "취소", - "actionRetry": "다시 시도", - "actionRequeue": "다시 대기열에", - "actionViewSession": "대화 보기", - "actionEdit": "편집", - "actionDelete": "삭제", - "actionRetryCleanup": "정리 다시 시도", - "actionMerge": "병합", - "actionUnqueueMerge": "병합 대기 취소", - "actionEditQueuedMerge": "대기 중인 병합 수정", - "badgeMergeQueued": "병합 대기 중", - "badgeMergeQueuedRank": "병합 대기 · {rank}번째", - "badgeMergeQueuedHint": "이 프로젝트에서 진행 중인 병합이 끝나기를 기다리는 중이며, 차례가 되면 자동으로 시작합니다.", - "actionComplete": "완료", - "actionAbandon": "포기", - "cancelTitle": "작업을 취소할까요?", - "cancelDescription": "작업이 취소됨으로 바뀝니다. worktree는 그대로 두며 나중에 다시 대기열에 넣을 수 있습니다.", - "cancelReasonLabel": "취소 사유 (선택)", - "cancelReasonPlaceholder": "예: 방향이 잘못돼서 설명을 다시 쓸게요", - "cancelKeep": "그대로 두기", - "cancelSubmit": "작업 취소", - "restartTitleRetry": "작업 다시 시도", - "restartTitleRequeue": "작업 다시 대기열에", - "restartDescription": "메모(선택)를 남기면 다음 실행 프롬프트에 담겨 에이전트에게 전달됩니다.", - "scheduleTitle": "작업 실행 예약", - "scheduleDescription": "작업은 '할 일'에 남아 있다가 지정한 시각에 자동으로 시작됩니다. 폴더의 동시 실행 한도는 그대로 적용됩니다.", - "scheduleDateLabel": "날짜", - "schedulePickDate": "날짜 선택", - "scheduleTimeLabel": "시간", - "schedulePreview": "{time}에 실행", - "schedulePastHint": "이미 지난 시각입니다. 저장하면 바로 시작합니다.", - "scheduleInAnHour": "1시간 후", - "scheduleInThreeHours": "3시간 후", - "scheduleTomorrow": "내일 9:00", - "scheduleClear": "예약 해제", - "scheduleBadge": "{time}에 시작 예정", - "toastScheduled": "{time}에 실행하도록 예약했습니다", - "toastScheduleCleared": "예약을 해제했습니다", - "actionFollowUp": "이어서 요청", - "actionAddNote": "메모 추가", - "followUpSubmit": "보내기", - "followUpIntentRevise": "수정 요청", - "followUpIntentContinue": "계속 진행", - "followUpIntentQuestion": "질문하기", - "followUpIntentVerify": "자체 점검", - "followUpPlaceholderRevise": "무엇을 고쳐야 하나요? 같은 세션에서 이어집니다.", - "followUpPlaceholderContinue": "다음은 무엇인가요? 지금까지의 작업은 그대로 둡니다.", - "followUpPlaceholderQuestion": "무엇이 궁금한가요? 파일은 건드리지 않고 답변만 합니다.", - "followUpPlaceholderVerify": "선택: 특별히 확인했으면 하는 부분이 있나요?", - "followUpPlaceholderRetry": "선택: 이번엔 무엇을 다르게 할까요? 예: pnpm install 먼저 실행", - "followUpPlaceholderRequeue": "선택: 왜 취소했고, 이번엔 무엇이 달라져야 하나요?", - "actionArchive": "보관", - "actionUnarchive": "보관 해제", - "archiveAllDone": "모두 보관", - "dropToStart": "놓으면 실행 시작", - "errorView": "보기", - "notifyReview": "검수 대기: {title}", - "notifyFailed": "작업 실패: {title}", - "createFromMessage": "이 메시지로 작업 만들기", - "detailTokens": "총 토큰", - "editorTitleNew": "새 작업", - "editorTitleEdit": "작업 편집", - "templates": "템플릿", - "templatesEmpty": "아직 템플릿이 없습니다.", - "templateSaveCurrent": "현재 내용을 템플릿으로 저장", - "templateDelete": "템플릿 삭제", - "transcriptTitle": "작업 대화", - "transcriptDescription": "작업 에이전트 세션의 읽기 전용 실시간 보기입니다.", - "phaseWork": "작업 실행", - "phaseRetry": "다시 실행", - "phaseReturn": "이어서 요청", - "phaseMerge": "병합", - "titleLabel": "제목", - "titlePlaceholder": "무엇을 해야 하나요?", - "promptLabel": "작업 설명", - "promptPlaceholder": "에이전트에게 작업을 설명하세요 — @로 파일 참조, /로 명령", - "folderPlaceholder": "폴더 선택", - "agentInheritedHint": "작업 설정에서 상속됨 — 변경하면 이 작업에만 적용됩니다", - "agentOverrideReset": "상속으로 되돌리기", - "sectionTarget": "대상", - "errorTitle": "제목을 입력하세요", - "errorPrompt": "작업 설명을 입력하세요", - "errorFolder": "폴더를 선택하세요", - "save": "저장", - "cancel": "취소", - "mergeTitle": "작업 병합", - "mergeQueuedTitle": "대기 중인 병합", - "mergeQueueHint": "이 프로젝트의 다른 작업이 병합 중입니다. 이 작업은 대기열에 들어가며 앞의 병합이 끝나는 대로 자동으로 시작합니다.", - "mergeQueueUpdateHint": "이 작업은 이미 병합을 기다리고 있습니다. 제출하면 내용만 업데이트되고 대기 순서는 그대로 유지됩니다.", - "mergeDescription": "{branch}을(를) {base}에 병합합니다. worktree의 커밋되지 않은 변경은 먼저 커밋됩니다.", - "mergeMessage": "커밋 메시지", - "mergeMessagePlaceholder": "예: feat: add login validation", - "mergeAutoMessage": "커밋 메시지를 에이전트가 작성하도록 하기", - "strategySquash": "하나의 커밋으로 합치기", - "strategySquashHint": "작업의 모든 변경 사항이 하나의 기록으로 메인 브랜치에 반영되어 히스토리가 깔끔해집니다.", - "strategyMerge": "전체 히스토리 유지", - "strategyMergeHint": "작업 중의 모든 커밋을 그대로 유지하고 병합 기록을 하나 추가합니다. 각 단계를 추적할 수 있습니다.", - "mergeDeleteWorktree": "병합 후 worktree 삭제", - "mergeSubmit": "병합", - "mergeSubmitQueue": "병합 대기열에 추가", - "mergeQueuedToast": "병합 대기열에 추가했습니다. 현재 병합이 끝나는 대로 시작합니다.", - "completeTitle": "작업 완료", - "completeDescription": "이 작업은 파일을 변경하지 않아 병합할 것이 없습니다. 그대로 완료로 표시합니다.", - "completeDescriptionNoWorktree": "이 작업의 worktree가 삭제되어 더 이상 병합할 수 없습니다. 그대로 완료로 표시합니다. 병합되지 않은 커밋이 남아 있는 작업 브랜치는 유지됩니다.", - "completeDeleteWorktree": "완료 후 worktree 삭제", - "completeSubmit": "완료", - "settingsTitle": "작업 설정", - "settingsDescription": "{folder}의 작업 기본값입니다.", - "settingsScope": "적용 범위", - "settingsScopeGlobal": "모든 폴더(전역 기본값)", - "settingsScopeGlobalHint": "별도 설정이 없는 폴더는 이 전역 기본값을 사용합니다.", - "settingsSource": "설정 출처", - "settingsSourceGlobal": "전역 기본값 사용", - "settingsSourceCustom": "개별 설정", - "settingsSourceGlobalFollow": "전역 작업 설정을 따릅니다. 전역 변경 사항이 자동으로 적용됩니다.", - "settingsSourceCustomHint": "이 폴더만의 설정을 저장하며 더 이상 전역 기본값을 따르지 않습니다.", - "settingsAgent": "기본 에이전트", - "settingsMaxConcurrent": "최대 동시 작업 수", - "settingsMaxConcurrentHint": "0 = 무제한", - "settingsAutoProcess": "자동 처리", - "settingsAutoProcessHint": "할 일 작업이 동시 실행 한도 내에서 자동으로 시작됩니다.", - "settingsMergeStrategy": "기본 병합 전략", - "settingsMergeStrategyHint": "병합할 때 작업의 변경 사항을 브랜치 히스토리에 어떻게 기록할지 정합니다.", - "settingsAutoMerge": "자동 병합", - "settingsAutoMergeHint": "검토 대기에 도달하고 병합할 변경이 있는 작업은 병합 버튼을 누른 것과 똑같이 자동으로 병합됩니다. 커밋 메시지는 에이전트가 작성하고 worktree 처리는 아래 기본값을 따릅니다. 사전 점검이 실패했거나 병합에 실패한 작업은 남아서 기다립니다.", - "settingsDeleteWorktree": "머지 후 worktree 삭제", - "settingsDeleteWorktreeHint": "머지 대화상자에서 기본으로 선택됩니다. 거기서 바꿀 수도 있습니다.", - "settingsWorktreeRoot": "워크트리 위치", - "settingsWorktreeRootHint": "새 작업의 worktree를 이 디렉터리 아래에 작업마다 하나씩 만듭니다. 비워 두면 프로젝트 폴더와 같은 위치에 만듭니다. \"~\"는 홈 디렉터리이고 상대 경로는 프로젝트 폴더 기준입니다.", - "settingsWorktreeRootPlaceholder": "~/codeg-worktrees", - "settingsWorktreeRootBrowse": "워크트리 디렉터리 선택", - "settingsPreflight": "사전 점검 명령", - "settingsPreflightHint": "작업이 검토 단계에 도달하면 워크트리에서 실행.", - "settingsPreflightCustomPlaceholder": "pnpm test", - "settingsInitCommand": "워크트리 초기화 명령", - "settingsInitCommandHint": "워크트리를 새로 만든 뒤 에이전트 시작 전에 실행됩니다.", - "settingsInitCommandPlaceholder": "pnpm install", - "settingsTabGeneral": "일반", - "settingsTabMerge": "병합", - "settingsTabWorktree": "워크트리", - "settingsTabPrompts": "프롬프트", - "settingsPromptsIntro": "각 단계에는 이미 기본 프롬프트가 들어 있습니다 — 작업 내용, 워크트리 규칙, 머지 단계의 구체적인 git 절차. 여기에 적은 내용은 추가 지시로 맨 뒤에 덧붙으며, 기본 프롬프트를 보완할 뿐 대체하지 않습니다.", - "settingsPromptStageAll": "전체 단계", - "settingsPromptPlaceholderAll": "예: AGENTS.md의 프로젝트 규칙을 따르고, 마지막 요약은 두 문장 이내로", - "settingsPromptPlaceholderWork": "예: 관련 테스트를 먼저 읽고, 작은 단위로 자주 커밋", - "settingsPromptPlaceholderRetry": "예: 이어서 하기 전에 이미 커밋된 내용을 확인하고, 끝난 작업은 다시 하지 말 것", - "settingsPromptPlaceholderReturn": "예: 언급된 항목을 하나씩 처리하고, 관련 없는 리팩터링은 하지 마세요", - "settingsPromptPlaceholderMerge": "예: 최종 반영 커밋 메시지는 한국어로, 수동으로 해결한 충돌은 따로 밝힐 것", - "settingsPromptHintAll": "머지 실행을 포함해 에이전트가 받는 모든 프롬프트에 추가됩니다.", - "settingsPromptHintWork": "작업을 처음 실행할 때 추가됩니다.", - "settingsPromptHintRetry": "중단되거나 실패한 작업을 다시 이어갈 때 추가됩니다.", - "settingsPromptHintReturn": "검토 대기 작업에 이어서 요청할 때(수정·추가 작업·자체 점검) 덧붙습니다.", - "settingsPromptHintMerge": "에이전트가 작업을 기준 브랜치에 병합할 때 추가됩니다.", - "preflightPassed": "{name} 통과", - "preflightFailed": "{name} 실패", - "preflightRunning": "{name} 실행 중…", - "detailDescription": "작업 상세", - "detailSummary": "결과", - "detailFiles": "변경된 파일", - "detailDiffAll": "전체 차이 보기", - "detailDiffAllTitle": "전체 차이", - "detailNoChanges": "기준 대비 변경 사항이 아직 없습니다", - "detailTimeline": "진행 기록", - "detailTimelineEmpty": "아직 활동이 없습니다", - "showMore": "더 보기", - "showLess": "접기", - "detailInfo": "상세 정보", - "detailBranch": "브랜치", - "detailMergeCommit": "병합 커밋", - "detailChanges": "변경 사항", - "detailScheduled": "시작 예정", - "detailCreated": "생성 시간", - "detailStarted": "시작 시간", - "detailFinished": "완료 시간", - "diffLoading": "차이를 불러오는 중…", - "deleteConfirmTitle": "작업을 삭제할까요?", - "deleteConfirmBody": "“{title}”이(가) 보드에서 제거됩니다. 실행 중이면 먼저 취소됩니다.", - "deleteWithWorktree": "worktree도 함께 삭제", - "eventCreated": "생성됨", - "eventStatusChanged": "상태 변경", - "eventConfigEffective": "실행 구성", - "eventInitCommand": "초기화 명령", - "eventAgentProgress": "에이전트 진행", - "eventAgentVerdict": "에이전트 판정", - "eventMergeAttempt": "병합 시작", - "eventMergeQueued": "병합 대기열에 추가", - "eventMergeConflict": "병합 충돌", - "eventPreflight": "사전 점검", - "eventCleanupFailed": "worktree 정리 실패", - "eventResumeFallback": "세션 재개 실패, 새 세션으로 전환", - "eventUserAction": "사용자 작업", - "eventDiffStat": "변경 스냅샷" - }, - "CustomSkillsSettings": { - "loading": "사용자 지정 스킬 불러오는 중…", - "category": "사용자 지정", - "searchPlaceholder": "이름, ID 또는 설명으로 사용자 지정 스킬 검색", - "states": { - "not_linked": "사용 안 함", - "linked_to_codeg": "사용 중", - "linked_elsewhere": "다른 위치에 연결됨", - "blocked_by_real_directory": "실제 폴더가 차지함", - "broken": "손상된 링크" - }, - "actions": { - "new": "새로 만들기", - "import": "가져오기", - "importFromAgent": "에이전트에서 가져오기", - "cancel": "취소", - "save": "저장" - }, - "rowMenu": { - "edit": "편집", - "duplicate": "복제", - "delete": "삭제" - }, - "bulk": { - "delete": "선택 항목 삭제" - }, - "editor": { - "createTitle": "새 사용자 지정 스킬", - "editTitle": "사용자 지정 스킬 편집", - "description": "사용자 지정 스킬은 공유 저장소(~/.codeg/skills)에 있으며 모든 에이전트에서 사용할 수 있습니다.", - "idLabel": "스킬 ID", - "idPlaceholder": "예: my-workflow", - "contentLabel": "SKILL.md", - "contentPlaceholder": "여기에 스킬의 SKILL.md를 작성하세요…", - "preview": "미리보기", - "edit": "편집", - "emptyBody": "아직 내용이 없습니다." - }, - "duplicate": { - "title": "스킬 복제", - "description": "\"{id}\"을(를) 기반으로 새 ID로 복사본을 만듭니다.", - "newIdPlaceholder": "새 스킬 ID", - "confirm": "복제" - }, - "import": { - "title": "가져올 스킬 폴더 선택" - }, - "importFromAgent": { - "title": "에이전트에서 스킬 가져오기", - "description": "에이전트의 자체 스킬을 공유 저장소로 복사하면 어떤 에이전트에서도 사용할 수 있습니다.", - "agentLabel": "에이전트", - "agentPlaceholder": "에이전트 선택", - "selectAll": "모두 선택 ({count})", - "loading": "에이전트의 스킬을 불러오는 중…", - "unsupported": "이 에이전트는 스킬 디렉터리를 제공하지 않습니다.", - "empty": "이 에이전트에는 가져올 스킬이 없습니다.", - "alreadyInLibrary": "라이브러리에 있음", - "confirm": "선택 항목 가져오기 ({count})" - }, - "delete": { - "title": "사용자 지정 스킬을 삭제할까요?", - "body": "{count}개의 사용자 지정 스킬을 중앙 저장소에서 제거하고 모든 에이전트에서 링크를 해제합니다. 이 작업은 취소할 수 없습니다.", - "confirm": "삭제" - }, - "toasts": { - "loadFailed": "스킬 불러오기 실패", - "idRequired": "스킬 ID를 입력하세요", - "created": "사용자 지정 스킬 생성됨", - "updated": "사용자 지정 스킬 업데이트됨", - "saveFailed": "스킬 저장 실패", - "imported": "스킬 가져옴", - "importFailed": "스킬 가져오기 실패", - "duplicated": "스킬 복제됨", - "duplicateFailed": "스킬 복제 실패", - "deleted": "{count}개 스킬 삭제됨", - "deletedPartial": "{ok}개 삭제, {failed}개 실패", - "deleteFailed": "스킬 삭제 실패", - "importedFromAgent": "{count}개의 스킬을 가져왔습니다", - "importedFromAgentPartial": "{ok}개 가져옴, {failed}개 실패", - "importFromAgentAllSkipped": "가져올 항목 없음 — {count}개가 이미 라이브러리에 있습니다", - "importFromAgentFailed": "에이전트에서 가져오기 실패" - } - }, - "CodexModelEditor": { - "customizedNotice": "모델 목록을 사용자 지정했으므로 이제 codeg가 codex의 전체 모델 표를 관리합니다. codex가 이후 추가하는 공식 모델은 자동으로 나타나지 않습니다. 아래의 새로 고침을 클릭한 뒤 다시 저장하면 동기화됩니다. 사용자 지정을 모두 지우면 codex 자동 업데이트로 되돌아갑니다.", - "officialsTitle": "공식 모델", - "officialsHint": "실행하는 codex의 공식 모델을 자동 포함합니다. 필요 없는 항목은 삭제하세요.", - "officialsEmpty": "사용 가능한 공식 모델이 없습니다.", - "refresh": "codex에서 새로고침", - "readdOfficial": "공식 다시 추가", - "customsTitle": "사용자 지정 모델", - "customsEmpty": "사용자 지정 모델이 없습니다.", - "addCustom": "사용자 지정 추가", - "slugPlaceholder": "모델 ID(slug)", - "displayNamePlaceholder": "표시 이름", - "contextWindow": "컨텍스트", - "makeDefault": "기본값으로 설정", - "defaultHint": "기본 모델", - "remove": "제거", - "advanced": "고급", - "baseTemplate": "기본 템플릿", - "baseTemplateHint": "필수 필드(시스템 프롬프트, 도구, 제한)를 복제할 공식 모델.", - "groupBehavior": "동작 및 기능", - "fieldReasoningLevel": "기본 추론 강도", - "fieldReasoningSummary": "추론 요약", - "fieldVerbosity": "상세도", - "fieldShellType": "셸 유형", - "fieldApplyPatch": "패치 적용 도구", - "fieldReasoningSummaries": "추론 요약 지원", - "fieldSupportVerbosity": "상세도 제어", - "fieldParallelToolCalls": "병렬 도구 호출", - "fieldSearchTool": "웹 검색 도구", - "optNone": "없음", - "groupInstructions": "설명 및 시스템 프롬프트", - "fieldDescription": "설명", - "baseInstructions": "시스템 프롬프트(base_instructions)" - }, - "DiagnosticsSettings": { - "title": "환경 진단", - "description": "이 앱이 자체 프로세스에서 에이전트 CLI를 어떻게 확인하는지 점검합니다(터미널과 다를 수 있음).", - "loading": "진단 실행 중…", - "error": "진단 실패", - "rerun": "다시 실행", - "copyAll": "전체 복사", - "copied": "진단 정보를 클립보드에 복사했습니다", - "button": "진단", - "verdict": { - "ok": "환경이 정상입니다. 그래도 설치되지 않았다고 표시되면 앱을 완전히 재시작하여 프리픽스 캐시를 새로 고치세요.", - "node_missing": "앱 PATH에서 Node.js를 찾을 수 없습니다.", - "npm_missing": "앱 PATH에서 npm을 찾을 수 없습니다.", - "not_installed": "이 에이전트가 설치되지 않은 것 같습니다.", - "installed_but_unresolved": "설치된 것으로 기록되어 있지만 앱이 실행 파일을 찾지 못합니다.", - "user_prefix_not_on_path": "폴백 프리픽스(~/.codeg/npm-global)에 설치되었지만 앱 PATH에 없습니다. 앱을 완전히 재시작한 후 다시 시도하세요.", - "homebrew_bin_not_on_path": "Homebrew bin에 설치되었지만 앱 PATH에 없습니다(Apple Silicon keg 분리).", - "terminal_only_path": "이 명령은 터미널에서는 확인되지만 앱에서는 확인되지 않습니다. GUI PATH 불일치입니다. 터미널에서 앱을 실행하거나 에이전트 설정에서 다시 설치하세요.", - "npm_prefix_timeout": "npm prefix -g가 너무 느립니다(1.5초 초과). 폴백 감지를 건너뛰었습니다. 앱을 재시작한 후 다시 시도하세요.", - "node_too_old": "현재 Node.js가 이 에이전트의 요구 버전보다 낮습니다. Node.js를 업그레이드하세요.", - "adapter_missing_native_present": "사용 중인 {agent} CLI는 설치되어 있지만, Codeg가 실행하는 것은 별도의 ACP 어댑터 패키지이며 그것이 아직 설치되지 않았습니다. 에이전트 설정에서 설치하세요. 기존 CLI는 건드리지 않으며 로그인도 공유됩니다.", - "adapter_missing": "Codeg는 {agent}에 대해 별도의 ACP 어댑터 패키지를 실행하는데, 아직 설치되지 않았습니다. 에이전트 설정에서 설치하세요 — 벤더 CLI만 설치하는 것으로는 충분하지 않습니다." - } - }, - "TokenUsage": { - "title": "토큰 사용량", - "rangeLabel": "기간", - "range7d": "7일", - "range30d": "30일", - "range90d": "90일", - "rangeThisMonth": "이번 달", - "rangeThisYear": "올해", - "rangeAll": "전체", - "rangeCustom": "사용자 지정", - "moreRanges": "더보기", - "customRangePick": "기간 선택", - "bucketLabel": "집계 단위", - "bucketDay": "일", - "bucketWeek": "주", - "bucketMonth": "월", - "bucketUnitDay": "날", - "bucketUnitWeek": "주", - "bucketUnitMonth": "월", - "folderFilter": "폴더", - "allFolders": "모든 폴더", - "agentFilter": "에이전트", - "allAgents": "모든 에이전트", - "modelFilter": "모델", - "allModels": "모든 모델", - "searchPlaceholder": "검색…", - "noMatches": "일치하는 항목 없음", - "clearFilter": "선택 해제", - "resetFilters": "필터 초기화", - "refresh": "새로 고침", - "rebuild": "전체 재구성", - "rebuildHint": "집계된 데이터를 버리고 모든 세션 기록을 다시 읽습니다. codeg 밖의 CLI가 기록을 이어썼을 때 사용하세요.", - "syncing": "세션 집계 중…", - "syncProgress": "{done} / {total}", - "syncDone": "{synced}개 세션을 집계했습니다", - "syncFailed": "일부 세션을 읽지 못했습니다", - "syncBusy": "이미 새로 고침이 진행 중입니다", - "lastSynced": "{time}에 업데이트", - "lastSyncedNever": "집계된 적 없음", - "tileTotal": "총 토큰", - "tileSessions": "세션 수", - "tileTurns": "대화 턴", - "tileActiveDays": "활동 일수", - "tileGenTime": "생성 시간", - "vsPrevious": "이전 기간 대비", - "deltaNew": "신규", - "trendTitle": "사용량 추이", - "trendEmpty": "이 기간에는 사용량이 없습니다", - "trendTurns": "턴", - "trendSessions": "세션", - "compositionTitle": "토큰 구성", - "compositionHint": "입력은 보낸 내용, 출력은 모델이 쓴 내용, 캐시 읽기는 다시 보내지 않아도 된 컨텍스트입니다.", - "compositionNote": "이 캐시 적중을 정가로 다시 보냈다면 {value}가 더 들었을 것입니다.", - "inputTokens": "입력", - "outputTokens": "출력", - "cacheWrite": "캐시 쓰기", - "cacheRead": "캐시 읽기", - "freshTokens": "신규 연산 토큰", - "cacheHitCaption": "캐시 적중", - "cacheHeroTitleHigh": "컨텍스트 대부분은 다시 보낼 필요가 없었습니다", - "cacheHeroTitleLow": "컨텍스트 대부분이 아직 정가로 계산됩니다", - "cacheHeroDesc": "{cached}의 컨텍스트를 캐시가 감당했고, 이 기간에 실제로 새로 연산된 것은 {fresh}뿐입니다.", - "cacheSavedSuffix": "재전송을 {saved}만큼 아꼈습니다.", - "avgPerSession": "세션당 평균", - "avgTurnsPerSession": "세션당 평균 {count}턴", - "avgPerActiveDay": "활동일당 평균", - "peakBucket": "가장 많은 {bucket}", - "peakHour": "피크 시간대", - "daysValue": "{count}일", - "idleDays": "쉬어간 날", - "byFolderTitle": "폴더별", - "byAgentTitle": "에이전트별", - "byModelTitle": "모델별", - "distributionTitle": "사용량 분포", - "distributionHint": "선택한 기준으로 세션과 토큰을 집계합니다. 행을 클릭하면 해당 항목으로 필터링됩니다.", - "otherLabel": "기타", - "unknownModel": "모델 미기록", - "emptyBreakdown": "기록이 없습니다", - "sessionsCount": "{count}개 세션", - "heatmapTitle": "작업 리듬", - "heatmapHint": "로컬 요일·시간대별 토큰 분포입니다.", - "heatmapPeakHint": "{hour}:00 전후가 가장 밀집되어 있습니다.", - "less": "적음", - "more": "많음", - "heatmapCell": "{weekday} {hour}:00 — {value} 토큰", - "weekMon": "월", - "weekTue": "화", - "weekWed": "수", - "weekThu": "목", - "weekFri": "금", - "weekSat": "토", - "weekSun": "일", - "topSessionsTitle": "소비가 큰 세션", - "untitledSession": "제목 없는 세션", - "topSessionsEmpty": "이 기간에는 세션이 없습니다", - "streakLongest": "최장 연속", - "streakLongestDays": "최장 연속 {count}일", - "share": "공유", - "moreActions": "기타 작업", - "shareDialogTitle": "사용량 카드 공유", - "shareDialogHint": "지금 보고 있는 기간과 필터의 스냅샷입니다.", - "shareSave": "이미지 저장", - "shareCopy": "이미지 복사", - "shareCopied": "클립보드에 복사했습니다", - "shareSaved": "이미지를 저장했습니다", - "shareFailed": "이미지를 만들지 못했습니다", - "shareRendering": "생성 중…", - "cardHeading": "나의 AI 코딩 기록", - "cardRangeAll": "전체 기간", - "cardTotalLabel": "사용 토큰", - "cardFooter": "codeg로 제작", - "cardTopModels": "주요 모델", - "cardTopProjects": "주요 프로젝트", - "archetypeNightOwl": "야행성 개발자", - "archetypeNightOwlDesc": "토큰의 {percent}%를 해가 진 뒤에 씁니다.", - "archetypeEarlyBird": "아침형 개발자", - "archetypeEarlyBirdDesc": "토큰의 {percent}%를 오전 9시 전에 씁니다.", - "archetypeWeekendWarrior": "주말 전사", - "archetypeWeekendWarriorDesc": "토큰의 {percent}%가 주말에 발생합니다.", - "archetypeCacheMaster": "캐시 마스터", - "archetypeCacheMasterDesc": "컨텍스트의 {percent}%가 캐시에서 왔습니다.", - "archetypeMarathoner": "마라토너", - "archetypeMarathonerDesc": "{days}일 연속으로 개발했습니다.", - "archetypePolyglot": "멀티 플레이어", - "archetypePolyglotDesc": "{count}개 에이전트를 본격적으로 함께 씁니다.", - "archetypeLaserFocus": "한 우물", - "archetypeLaserFocusDesc": "토큰의 {percent}%를 한 프로젝트에 썼습니다.", - "archetypeDeepDiver": "딥 다이버", - "archetypeDeepDiverDesc": "세션당 평균 {averageK}K 토큰.", - "archetypeSteady": "꾸준한 빌더", - "archetypeSteadyDesc": "총 {days}일 동안 개발했습니다.", - "emptyTitle": "아직 집계된 데이터가 없습니다", - "emptyHint": "codeg는 각 에이전트의 세션 기록에서 토큰 수를 직접 읽습니다. 새로 고침하면 이 컴퓨터에 있는 기록을 집계합니다.", - "emptyAction": "내 세션 집계", - "loadFailed": "사용량을 불러오지 못했습니다", - "truncatedNotice": "기간이 매우 길어 표시된 수치는 가장 최근 구간만 반영합니다." - } -} +{ + "Language": { + "followSystem": "시스템 설정 따름", + "english": "영어", + "simplifiedChinese": "简体中文", + "traditionalChinese": "繁體中文", + "japanese": "일본어", + "korean": "한국어", + "spanish": "스페인어", + "german": "독일어", + "french": "프랑스어", + "portuguese": "포르투갈어", + "arabic": "아랍어" + }, + "GitCredentialDialog": { + "title": "인증 필요", + "description": "원격 서버에서 자격 증명을 요구합니다. 사용자 이름과 비밀번호(또는 개인 액세스 토큰)를 입력하세요.", + "username": "사용자 이름", + "usernamePlaceholder": "사용자 이름 또는 이메일", + "password": "비밀번호 / 토큰", + "passwordPlaceholder": "비밀번호 또는 개인 액세스 토큰", + "passwordHint": "서버의 사용자 이름과 비밀번호를 입력하세요.", + "cancel": "취소", + "authenticate": "인증", + "authenticating": "인증 중...", + "invalidCredentials": "자격 증명이 유효하지 않습니다. 다시 시도하세요.", + "saveCredentials": "향후 작업을 위해 자격 증명 저장", + "githubTitle": "GitHub 인증", + "githubDescription": "개인 액세스 토큰을 입력하여 GitHub에 연결합니다. 토큰 확인 후 계정에 자동으로 저장됩니다.", + "githubToken": "개인 액세스 토큰", + "githubTokenPlaceholder": "ghp_xxxxxxxxxxxx", + "githubTokenHint": "GitHub → Settings → Developer settings → Personal access tokens에서 토큰을 생성하세요.", + "githubAuthenticate": "확인 및 연결", + "generateToken": "토큰 생성" + }, + "SettingsShell": { + "title": "설정", + "preferences": "환경설정", + "nav": { + "general": "일반", + "appearance": "외관", + "agents": "에이전트", + "mcp": "MCP", + "skills": "Skills", + "shortcuts": "단축키", + "version_control": "버전 관리", + "system": "시스템", + "chat_channels": "채팅 채널", + "web_service": "웹 서비스", + "model_providers": "모델 제공업체", + "experts": "전문가", + "science": "과학 연구", + "office_tools": "오피스 도구", + "skill_packs": "스킬 팩", + "quick_messages": "빠른 메시지", + "logs": "실행 로그" + } + }, + "AppearanceSettings": { + "sectionTitle": "테마 모양", + "sectionDescription": "라이트, 다크 또는 시스템 설정을 선택할 수 있습니다. 설정은 자동으로 저장됩니다.", + "themeMode": "테마 모드", + "placeholder": "테마 모드 선택", + "system": "시스템 설정 따름", + "light": "라이트", + "dark": "다크", + "currentTheme": "현재 적용된 테마: {theme}", + "resolvedTheme": { + "light": "라이트", + "dark": "다크", + "unknown": "--" + }, + "themeColor": { + "sectionTitle": "테마 색상", + "sectionDescription": "버튼, 강조 색상, 하이라이트에 사용할 색상 팔레트를 선택하세요.", + "current": "현재 색상: {color}", + "options": { + "neutral": "Neutral", + "zinc": "Zinc", + "slate": "Slate", + "stone": "Stone", + "gray": "Gray", + "red": "Red", + "rose": "Rose", + "orange": "Orange", + "green": "Green", + "blue": "Blue", + "yellow": "Yellow", + "violet": "Violet" + } + }, + "customStyle": { + "sectionTitle": "사용자 지정 스타일", + "sectionDescription": "현재 테마의 색상을 미세 조정하거나 직접 작성한 CSS를 적용합니다. 재정의는 기본 프리셋 위에 얹히므로 프리셋을 바꿔도 유지됩니다.", + "summarySuspended": "일시 중지됨", + "summaryDefault": "프리셋 기본값", + "summaryTokens": "{count, plural, one {재정의 #개} other {재정의 #개}}", + "summaryCss": "사용자 지정 CSS", + "suspendedByShortcut": "사용자 지정 스타일이 일시 중지되었습니다. 다시 켜기 전까지 여기서 설정한 내용은 적용되지 않습니다.", + "suspendedBySafeParam": "이 창은 안전 외관 모드로 열려 사용자 지정 스타일이 적용되지 않습니다. 다른 창에는 영향이 없습니다.", + "resume": "사용자 지정 스타일 재개", + "enableTheme": "사용자 지정 색상 사용", + "editingLight": "라이트 모드 값을 편집하고 있습니다. 다크 모드로 전환하면 따로 설정할 수 있습니다.", + "editingDark": "다크 모드 값을 편집하고 있습니다. 라이트 모드로 전환하면 따로 설정할 수 있습니다.", + "resetToken": "프리셋 값으로 되돌리기", + "radius": "모서리 둥글기", + "radiusHint": "sm부터 4xl까지의 둥글기 척도 전체가 이 값에서 파생되므로 슬라이더 하나로 앱 전체가 바뀝니다.", + "advanced": "고급 (변수 {count}개 더)", + "enableCss": "사용자 지정 CSS 사용", + "cssRisk": "고급 기능입니다. 사용자 지정 CSS는 모든 기본 스타일을 덮어쓰므로 화면을 사용할 수 없게 만들 수 있습니다.", + "editCss": "CSS 편집…", + "cssPresent": "{size} KB 저장됨", + "cssEmpty": "아직 저장된 내용이 없습니다", + "escapeHint": "화면이 망가졌나요? {shortcut} 키로 모든 사용자 지정 스타일을 중지할 수 있고, safeStyle=1 쿼리 파라미터로 창을 열 수도 있습니다.", + "copyTheme": "테마 JSON 복사", + "importTheme": "테마 가져오기…", + "clearTheme": "재정의 지우기", + "interopHint": "테마는 shadcn의 registry:theme 형식을 사용합니다. 어떤 shadcn 테마든 붙여넣을 수 있고, 내보낸 테마는 모든 shadcn 프로젝트에서 쓸 수 있습니다.", + "importTitle": "테마 가져오기", + "importDescription": "shadcn의 registry:theme 항목, light/dark 객체, 또는 단층 토큰 맵을 붙여넣으세요.", + "readClipboard": "클립보드 읽기", + "importConfirm": "가져오기", + "cancel": "취소", + "apply": "적용", + "toasts": { + "copied": "테마 JSON을 복사했습니다", + "copyFailed": "클립보드에 복사하지 못했습니다", + "clipboardReadFailed": "클립보드를 읽지 못했습니다. 직접 붙여넣어 주세요", + "importFailed": "이 JSON에는 사용할 수 있는 테마 변수가 없습니다", + "imported": "테마를 가져왔습니다" + }, + "css": { + "dialogTitle": "사용자 지정 CSS", + "dialogDescription": "모든 codeg 창에 적용됩니다. 변경 사항은 실시간으로 미리 보이며 적용을 눌러야 저장됩니다.", + "size": "{used} KB / {max} KB", + "ruleCount": "규칙 {count}개", + "errorTooLarge": "너무 커서 저장할 수 없습니다. 상한 아래로 줄여 주세요.", + "errorImportEscaped": "제거 후에도 @import가 감지되었습니다(이스케이프 표기). 직접 삭제해 주세요.", + "warnNoRules": "해석된 규칙이 없습니다. 문법을 확인하세요.", + "noticeImportsRemoved": "@import 규칙 {count}개를 제거했습니다. 원격 스타일시트를 가져오기 때문입니다.", + "noticeRemoteUrl": "원격 url()이 포함되어 있어 적용 시 네트워크 요청이 발생합니다.", + "noticePreviewSuspended": "사용자 지정 스타일이 중지되어 이 미리보기는 적용되지 않습니다.", + "noticeDisabled": "사용자 지정 CSS가 꺼져 있습니다. 여기서 미리 볼 수는 있지만 켜야 실제로 적용됩니다.", + "hintTokens": "팁: 재정의한 색상은 var(--primary), var(--background) 등으로 참조할 수 있습니다." + } + }, + "zoomLevel": { + "sectionTitle": "창 확대/축소", + "sectionDescription": "전체 인터페이스를 확대하거나 축소합니다. 즉시 적용되며 장치별로 저장됩니다.", + "placeholder": "확대/축소 단계 선택", + "default": "기본값", + "current": "현재 확대/축소: {zoom}%" + }, + "fonts": { + "sectionTitle": "글꼴", + "sectionDescription": "인터페이스, 코드 편집기, 터미널의 글꼴을 각각 선택합니다. 내장 글꼴은 필요할 때 불러옵니다. “사용자 지정…”을 선택하면 시스템에 설치된 모든 글꼴을 사용할 수 있습니다.", + "interface": "인터페이스", + "editor": "편집기", + "terminal": "터미널", + "groupSans": "산세리프", + "groupMono": "고정폭", + "custom": "사용자 지정…", + "customPlaceholder": "글꼴 이름 (예: Fira Code)", + "fontSize": "글꼴 크기", + "ligatures": "합자 사용", + "ligaturesUnavailable": "이 글꼴에는 합자가 없습니다", + "wordWrap": "자동 줄 바꿈 사용", + "terminalLigaturesHint": "터미널 합자는 내장 코딩 글꼴에만 적용됩니다.", + "preview": "미리 보기" + }, + "welcomePanel": { + "sectionTitle": "모드 선택 영역", + "sectionDescription": "새 대화 페이지에서 입력창 위에 표시되는 '코드 개발 / 일상 업무' 바로가기 카드입니다.", + "showQuickActions": "새 대화 페이지에 표시" + }, + "workspaceBackground": { + "sectionTitle": "작업 공간 배경", + "sectionDescription": "작업 공간 전체 뒤에 이미지를 표시합니다. 사이드바와 패널이 반투명 유리 효과로 바뀌어 이미지가 비쳐 보이며, 마스크가 텍스트 가독성을 유지합니다.", + "enable": "배경 이미지 사용", + "image": "이미지", + "chooseImage": "이미지 선택", + "replaceImage": "이미지 변경", + "removeImage": "제거", + "fillMode": "채우기 방식", + "fillModes": { + "cover": "채우기", + "contain": "맞춤", + "center": "가운데", + "tile": "바둑판식" + }, + "maskOpacity": "마스크 불투명도", + "maskOpacityHint": "값이 높을수록 이미지가 테마 배경색으로 흐려져 텍스트 대비가 좋아집니다.", + "imageBlur": "이미지 흐림", + "panelOpacity": "패널 불투명도", + "panelOpacityHint": "사이드바, 패널, 탭 바의 불투명도입니다. 낮을수록 이미지가 더 많이 비쳐 보입니다.", + "errorTooLarge": "이미지가 너무 큽니다(최대 16 MB).", + "errorUploadFailed": "배경 이미지 설정에 실패했습니다." + } + }, + "SystemSettings": { + "loading": "로딩 중...", + "sectionTitle": "시스템 관리", + "sectionDescription": "네트워크 프록시, 앱 업데이트, 언어 설정을 관리합니다.", + "proxyTitle": "네트워크 프록시", + "proxyDescription": "활성화하면 이후 네트워크 요청에서 이 프록시를 우선 사용합니다(ACP 채팅, 에이전트 설치, Git 원격 작업 포함).", + "loadFailed": "불러오기 실패: {message}", + "enableProxy": "시스템 프록시 활성화", + "proxyAddress": "프록시 주소", + "proxyHint": "http(s)/socks5 지원, 예: {example}. 시스템 프록시를 활성화한 경우에만 적용됩니다.", + "save": "저장", + "saving": "저장 중...", + "proxyRequired": "프록시를 활성화하면 프록시 URL이 필요합니다", + "saveSuccess": "시스템 프록시 설정이 저장되었습니다", + "saveFailed": "저장 실패: {message}", + "languageTitle": "언어", + "languageDescription": "앱 언어를 설정합니다. 시스템 언어를 따를 때 지원되지 않는 언어는 영어로 대체됩니다.", + "appLanguage": "앱 언어", + "languageSaveSuccess": "언어 설정이 저장되었습니다", + "languageSaveFailed": "언어 설정 저장 실패: {message}", + "updateTitle": "앱 업데이트", + "versionTitle": "소프트웨어 업데이트", + "updateDescription": "설정된 릴리스 소스에서 새 버전을 확인하고 가능하면 바로 설치합니다.", + "currentVersion": "현재 버전", + "upgradableVersion": "최신 버전", + "none": "없음", + "lastChecked": "마지막 확인: {time}", + "updateError": "업데이트 오류: {message}", + "checking": "확인 중...", + "checkUpdate": "업데이트 확인", + "updating": "설치 중...", + "downloading": "다운로드 중...", + "upgradeTo": "v{version}로 업그레이드", + "viewRelease": "v{version} 릴리스 보기", + "foundUpdate": "새 버전 v{version}을 찾았습니다", + "alreadyLatest": "이미 최신 버전입니다", + "checkUpdateFailed": "업데이트 확인 실패: {message}", + "installSuccess": "업데이트가 설치되었습니다. 앱을 다시 시작합니다.", + "installFailed": "업데이트 실패: {message}", + "upgradeSuccess": "업그레이드가 완료되었습니다. 다시 불러오는 중...", + "restartTimeout": "서버가 제때 복구되지 않았습니다. 컨테이너 또는 서비스 로그를 확인하세요.", + "restartingIn": "{seconds}초 후에 다시 시작합니다...", + "waitingForServer": "서버가 복구되기를 기다리는 중...", + "restartToUpdate": "다시 시작하여 업데이트", + "newVersionBadge": "새 버전 v{version}", + "updateAvailableTitle": "업데이트 있음", + "releaseNotesTitle": "새로운 기능", + "remindLater": "나중에", + "retry": "다시 시도", + "stepDownload": "다운로드", + "stepInstall": "설치", + "stepRestart": "다시 시작", + "updateReadyHint": "업데이트를 다운로드했습니다. 다시 시작하여 적용하세요.", + "restarting": "다시 시작하는 중…", + "dockerUpgradeHint": "지금 실행 중인 컨테이너를 업그레이드합니다. 컨테이너를 다시 만들면 사라집니다. 유지하려면 새 버전 이미지를 가져오거나 빌드한 뒤 컨테이너를 다시 만드세요.", + "upgradeRolledBack": "업그레이드에 실패하여 서버가 이전 버전으로 롤백되었습니다.", + "serverUnreachable": "업그레이드를 시작하기 위해 서버에 연결할 수 없습니다. 서버가 실행 중인지 확인한 후 다시 시도하세요.", + "rollbackButton": "롤백", + "rollingBack": "롤백 중...", + "rollbackDescription": "마지막 업그레이드 이전에 설치된 버전으로 복원합니다.", + "rollbackConfirmTitle": "이전 버전으로 롤백하시겠습니까?", + "rollbackConfirmDescription": "서버가 마지막 업그레이드 이전에 설치된 버전으로 다시 시작됩니다. 최신 릴리스는 다시 설치할 수 있습니다.", + "rollbackConfirm": "롤백", + "rollbackCancel": "취소", + "rollbackSuccess": "이전 버전으로 롤백했습니다. 다시 불러오는 중...", + "rollbackFailed": "롤백에 실패했습니다. 서버 로그를 확인하세요.", + "updateErrors": { + "sourceUnavailable": "업데이트 소스에 연결할 수 없습니다. 네트워크 또는 프록시를 확인한 뒤 다시 시도하세요.", + "network": "네트워크 연결에 실패했습니다. 네트워크 또는 프록시를 확인한 뒤 다시 시도하세요.", + "downloadFailed": "업데이트 패키지 다운로드에 실패했습니다. 잠시 후 다시 시도하세요.", + "installFailed": "업데이트 설치에 실패했습니다. 앱을 종료한 뒤 다시 시도하세요.", + "unknown": "업데이트에 실패했습니다. 잠시 후 다시 시도하세요." + } + }, + "VersionControlSettings": { + "loading": "로딩 중...", + "sectionTitle": "버전 관리", + "sectionDescription": "Git 실행 파일을 설정하고 GitHub 계정을 관리합니다.", + "gitTitle": "Git 설정", + "gitDescription": "애플리케이션에서 사용할 Git 실행 파일을 설정합니다.", + "gitDetected": "Git이 감지되었습니다", + "gitNotFound": "시스템에서 Git을 찾을 수 없습니다", + "gitVersion": "버전", + "gitPath": "경로", + "customGitPath": "사용자 지정 Git 경로", + "customGitPathPlaceholder": "/usr/bin/git", + "customGitPathHint": "비워두면 자동 감지된 경로를 사용합니다.", + "test": "테스트", + "testing": "테스트 중...", + "testSuccess": "Git 실행 파일이 유효합니다.", + "testFailed": "Git 테스트 실패: {message}", + "save": "저장", + "saving": "저장 중...", + "saveSuccess": "Git 설정이 저장되었습니다.", + "saveFailed": "저장 실패: {message}", + "githubTitle": "GitHub 계정", + "githubDescription": "인증용 GitHub 계정을 관리합니다. 토큰은 로컬에 저장됩니다.", + "noAccounts": "설정된 GitHub 계정이 없습니다.", + "addAccount": "계정 추가", + "serverUrl": "서버 URL", + "serverUrlPlaceholder": "https://github.com", + "token": "개인 액세스 토큰", + "tokenPlaceholder": "ghp_xxxxxxxxxxxx", + "generateToken": "토큰 생성", + "tokenHint": "GitHub → Settings → Developer settings → Personal access tokens에서 토큰을 생성하세요.", + "validateAndAdd": "검증 및 추가", + "validating": "검증 중...", + "addSuccess": "계정 {username}이(가) 추가되었습니다.", + "addFailed": "계정 추가 실패: {message}", + "testConnection": "테스트", + "connectionSuccess": "연결 성공.", + "connectionFailed": "연결 실패: {message}", + "setDefault": "기본값으로 설정", + "defaultLabel": "기본", + "defaultSet": "기본 계정이 업데이트되었습니다.", + "removeAccount": "삭제", + "removeConfirmTitle": "계정 삭제", + "removeConfirmMessage": "계정 \"{username}\"을(를) 삭제하시겠습니까?", + "removeConfirm": "삭제", + "removeCancel": "취소", + "removeSuccess": "계정이 삭제되었습니다.", + "scopes": "범위", + "loadFailed": "설정 로드 실패: {message}", + "gitAccount": { + "sectionTitle": "Git 서버 계정", + "sectionDescription": "GitHub 이외의 Git 서버 자격 증명을 관리합니다 (GitLab, Bitbucket, 자체 호스팅 등).", + "noAccounts": "설정된 Git 서버 계정이 없습니다.", + "addAccount": "계정 추가", + "addTitle": "Git 계정 추가", + "addDescription": "서버 주소, 사용자 이름, 비밀번호 또는 액세스 토큰을 입력하세요.", + "serverUrl": "서버 URL", + "serverUrlPlaceholder": "https://gitlab.example.com", + "username": "사용자 이름", + "usernamePlaceholder": "사용자 이름 또는 이메일", + "password": "비밀번호 / 토큰", + "passwordPlaceholder": "비밀번호 또는 액세스 토큰", + "passwordHint": "서버의 비밀번호 또는 액세스 토큰을 입력하세요.", + "add": "추가", + "serverRequired": "서버 URL을 입력하세요.", + "usernameRequired": "사용자 이름을 입력하세요.", + "passwordRequired": "비밀번호를 입력하세요." + } + }, + "ShortcutSettings": { + "sectionTitle": "단축키", + "resetDefault": "기본값으로 재설정", + "recordInstruction": "오른쪽 버튼을 클릭한 다음 키 조합을 누르세요. Ctrl/Cmd, Alt, Shift를 사용할 수 있습니다. Esc를 누르면 기록을 취소합니다.", + "recording": "단축키 입력...", + "toasts": { + "conflict": "단축키가 이미 \"{title}\"에서 사용 중입니다", + "updated": "단축키가 업데이트되었습니다", + "invalid": "유효하지 않은 단축키입니다. 다시 시도하세요", + "reset": "기본 단축키를 복원했습니다" + }, + "actions": { + "toggle_search": { + "title": "검색 열기", + "description": "대화 검색 패널을 표시하거나 숨깁니다" + }, + "toggle_sidebar": { + "title": "왼쪽 사이드바 전환", + "description": "대화 목록 사이드바를 표시하거나 숨깁니다" + }, + "toggle_terminal": { + "title": "터미널 전환", + "description": "하단 터미널 패널을 표시하거나 숨깁니다" + }, + "new_terminal_tab": { + "title": "새 터미널", + "description": "터미널에 포커스가 있을 때 새 터미널 탭을 만듭니다" + }, + "close_current_terminal_tab": { + "title": "현재 터미널 닫기", + "description": "터미널에 포커스가 있을 때 현재 터미널 탭을 닫습니다" + }, + "toggle_aux_panel": { + "title": "오른쪽 패널 전환", + "description": "보조 정보 패널을 표시하거나 숨깁니다" + }, + "new_conversation": { + "title": "새 대화", + "description": "현재 폴더에 새 대화 탭을 만듭니다" + }, + "open_folder": { + "title": "폴더 열기", + "description": "폴더 선택기를 열고 새 창에서 엽니다" + }, + "open_settings": { + "title": "설정 열기", + "description": "설정 창을 엽니다" + }, + "close_current_tab": { + "title": "현재 탭 닫기", + "description": "현재 대화 또는 파일 탭을 닫습니다" + }, + "close_all_file_tabs": { + "title": "모든 파일 탭 닫기", + "description": "파일 패널이 활성 상태일 때 열린 모든 파일 탭을 닫습니다" + }, + "next_tab": { + "title": "다음 탭", + "description": "다음 대화 또는 파일 탭으로 전환" + }, + "prev_tab": { + "title": "이전 탭", + "description": "이전 대화 또는 파일 탭으로 전환" + }, + "send_message": { + "title": "메시지 보내기", + "description": "입력창에서 현재 메시지를 전송" + }, + "newline_in_message": { + "title": "메시지 줄바꿈", + "description": "입력창에 줄바꿈을 삽입" + }, + "toggle_custom_style": { + "title": "사용자 지정 스타일 중지/재개", + "description": "비상 탈출구: 모든 사용자 지정 색상과 CSS를 끄고, 다시 누르면 되돌립니다" + } + } + }, + "SkillsSettings": { + "title": "Skills", + "description": "왼쪽에서 Skill을 선택하세요. 오른쪽은 기본적으로 Markdown 미리보기이며, 편집으로 전환해 수정 후 저장할 수 있습니다.", + "loadingAgents": "Skill을 지원하는 에이전트를 불러오는 중...", + "emptyNoManageableAgents": "Skill을 관리할 수 있는 에이전트가 없습니다.", + "managedTarget": "관리 대상", + "selectAgentPlaceholder": "에이전트 선택", + "searchPlaceholder": "이름 / ID / 경로로 검색...", + "skillsList": "Skill 목록", + "loadingSkills": "Skill 불러오는 중...", + "agentNotSupported": "현재 에이전트는 Skill 관리를 지원하지 않습니다.", + "emptySkills": "아직 Skill이 없습니다. \"새 Skill\"을 클릭해 생성하세요.", + "newSkillTitle": "새 Skill", + "skillInfo": "Skill 정보", + "skillIdPlaceholder": "skill-id(영문/숫자/-/_/.)", + "skillsDirectoryWithPath": "Skill 디렉터리: {path}", + "skillsDirectoryNeedId": "Skill 디렉터리: Skill ID를 입력하면 전체 경로를 생성합니다", + "markdownContent": "Markdown 내용", + "editingStatus": "편집 중", + "previewStatus": "미리보기 중", + "contentPlaceholder": "Skill Markdown 내용을 입력하세요...", + "metadataTitle": "Skill 메타데이터", + "onlyYamlMetadata": "이 Skill에는 YAML 메타데이터만 포함되어 있습니다.", + "emptyContentHint": "아직 내용이 없습니다. \"편집\"을 눌러 시작하세요.", + "loadingSkill": "Skill 불러오는 중...", + "emptyNoAgents": "사용 가능한 에이전트가 없습니다.", + "noSelectionHint": "왼쪽에서 Skill을 선택하거나 \"새 Skill\"을 클릭하여 만드세요.", + "systemBadge": "시스템", + "systemHint": "CLI 내장 Skill · 읽기 전용", + "scope": { + "global": "전역", + "folder": "폴더", + "selectFolderPlaceholder": "폴더 선택", + "noFolders": "폴더를 찾을 수 없습니다", + "pickFolderHint": "Skills을 보려면 폴더를 선택하세요." + }, + "actions": { + "preview": "미리보기", + "edit": "편집", + "openInWindow": "새 창에서 열기", + "delete": "삭제", + "deleting": "삭제 중...", + "refresh": "새로고침", + "newSkill": "새 Skill", + "reset": "초기화", + "save": "저장", + "saving": "저장 중...", + "cancel": "취소" + }, + "deleteDialog": { + "title": "Skill 삭제", + "confirm": "현재 Skill을 삭제하시겠습니까? 이 작업은 되돌릴 수 없습니다.", + "confirmWithNamePrefix": "Skill", + "confirmWithNameSuffix": "을(를) 삭제하시겠습니까? 이 작업은 되돌릴 수 없습니다." + }, + "toasts": { + "loadFailed": "Skill을 불러오지 못했습니다", + "openFolderFailed": "폴더를 열지 못했습니다", + "noSkillDirectory": "현재 에이전트에서 사용할 수 있는 Skill 디렉터리를 찾지 못했습니다", + "nameRequired": "Skill 이름은 비워둘 수 없습니다", + "updated": "Skill이 업데이트되었습니다", + "created": "Skill이 생성되었습니다", + "saveFailed": "Skill 저장에 실패했습니다", + "deleted": "Skill이 삭제되었습니다", + "deleteFailed": "Skill 삭제에 실패했습니다" + }, + "templates": { + "gemini": "---\nname: example-skill\ndescription: Describe when this skill should be used.\n---\n\n# Skill Name\n\nInstructions for the agent when this skill is active.\n\n## Workflow\n\n1. Add actionable step one.\n2. Add actionable step two.\n", + "openCode": "---\nname: example-skill\ndescription: Describe when this skill should be used.\n---\n\n# Purpose\n\nDescribe what this skill helps with.\n\n# Steps\n\n1. Add actionable step one.\n2. Add actionable step two.\n", + "openClaw": "---\nname: example-skill\ndescription: Describe when this skill should be used.\nuser-invocable: true\ndisable-model-invocation: false\n---\n\n# Purpose\n\nDescribe what this skill helps with.\n\n# Instructions\n\n1. Add actionable instruction one.\n2. Add actionable instruction two.\n", + "default": "---\nname: example-skill\ndescription: Describe when this skill should be used.\n---\n\n# Skill: example-skill\n\n## When to use\n\n- Describe trigger conditions.\n\n## Instructions\n\n1. Add actionable instruction one.\n2. Add actionable instruction two.\n" + } + }, + "McpSettings": { + "loading": "로딩 중...", + "summary": { + "missingCommand": "(명령 없음)", + "missingUrl": "(URL 없음)" + }, + "protocol": { + "stdio": "Stdio" + }, + "errors": { + "selectInstallProtocol": "설치 프로토콜을 선택하세요", + "fieldRequired": "{field}은(는) 필수입니다", + "fieldNeedsBoolean": "{field}은(는) true 또는 false여야 합니다", + "fieldNeedsNumber": "{field}은(는) 숫자여야 합니다", + "fieldNeedsInteger": "{field}은(는) 정수여야 합니다", + "fieldInvalidJson": "{field}의 JSON이 잘못되었습니다: {message}", + "fieldOutOfRange": "{field} 값이 허용 범위를 벗어났습니다", + "jsonEmpty": "{name}은(는) 비워둘 수 없습니다", + "jsonInvalid": "{name}은(는) 유효한 JSON이 아닙니다: {message}", + "jsonMustBeObject": "{name}은(는) JSON 객체여야 합니다", + "specMustBeObject": "MCP 구성은 JSON 객체여야 합니다.", + "missingType": "MCP 구성에 type 필드가 없습니다. stdio, http (별칭: streamable-http, streamableHttp), sse 중 하나를 지정하세요.", + "unsupportedType": "지원하지 않는 MCP type {type}. 지원: stdio, http (별칭: streamable-http, streamableHttp), sse.", + "codexEntryUnsupportedType": "Codex MCP 항목 {id}의 type {type}은(는) 지원되지 않습니다. 지원: stdio, http (별칭: streamable-http, streamableHttp), sse.", + "unsupportedTransportType": "지원하지 않는 transport type {type}. 지원: http (별칭: streamable-http, streamableHttp), sse.", + "stdioCommandRequired": "stdio 타입의 MCP에는 비어 있지 않은 command 필드가 필요합니다.", + "remoteUrlRequired": "원격 MCP에는 비어 있지 않은 url 필드가 필요합니다.", + "appsRequired": "대상 앱을 하나 이상 선택하세요." + }, + "jsonNames": { + "localConfig": "MCP 구성", + "installConfig": "설치 구성" + }, + "toasts": { + "uninstalled": "MCP가 제거되었습니다", + "uninstallFailed": "제거 실패: {message}", + "selectAtLeastOneApp": "대상 앱을 최소 하나 선택하세요", + "saveSuccess": "저장됨", + "saveFailed": "저장 실패: {message}", + "installed": "{name} 설치됨", + "installFailed": "설치 실패: {message}", + "serverIdRequired": "Server ID는 필수입니다", + "serverIdExists": "Server ID \"{id}\"이(가) 이미 존재합니다. 기존 항목을 편집하거나 다른 이름을 사용하세요.", + "created": "MCP가 생성되었습니다" + }, + "installDialog": { + "title": "MCP 설치 확인", + "descriptionWithName": "{name}을(를) 로컬 구성에 설치합니다.", + "description": "설치할 대상 앱을 선택하세요.", + "protocol": "프로토콜", + "selectProtocol": "프로토콜 선택", + "parameters": "구성 매개변수", + "booleanPlaceholder": "true/false를 선택하세요", + "selectOneValue": "값 선택", + "targetApps": "대상 앱" + }, + "actions": { + "cancel": "취소", + "confirmInstall": "설치 확인", + "installing": "설치 중", + "uninstall": "제거", + "uninstalling": "제거 중", + "viewDetails": "상세 보기", + "save": "저장", + "saving": "저장 중", + "install": "설치", + "refresh": "새로고침", + "newMcp": "새 MCP", + "create": "생성", + "creating": "생성 중..." + }, + "tabs": { + "local": "로컬 MCP", + "market": "MCP 마켓플레이스" + }, + "local": { + "filterPlaceholder": "로컬 MCP 필터...", + "loadFailed": "로드 실패: {message}", + "empty": "감지된 로컬 MCP가 없습니다.", + "description": "로컬 MCP 구성은 직접 수정하고 저장할 수 있습니다.", + "enabledApps": "활성화된 앱", + "configJson": "MCP 구성 (JSON)", + "draftTitle": "새 MCP", + "draftDescription": "Server ID와 설정을 입력하여 로컬 MCP 서버를 생성합니다.", + "serverIdLabel": "Server ID", + "serverIdPlaceholder": "Server ID (예: my-mcp)", + "typeHint": "지원 타입: stdio, http (별칭: streamable-http, streamableHttp), sse. env는 stdio 전용이며, 원격 MCP는 인증 토큰을 headers로 전달해야 합니다.", + "envOnRemoteWarning": "원격 MCP 설정에 env가 포함되어 있습니다. env는 stdio에서만 사용되며 원격 MCP는 headers로 인증 토큰을 전달합니다. 저장 시 env는 무시됩니다." + }, + "market": { + "selectMarketplace": "마켓플레이스 선택", + "searchPlaceholder": "MCP 검색...", + "searchFailed": "검색 실패: {message}", + "loadingList": "MCP 목록을 불러오는 중...", + "empty": "MCP 검색 결과가 없습니다.", + "loadingDetail": "마켓플레이스 상세 정보를 불러오는 중...", + "detailLoadFailed": "상세 정보를 불러오지 못했습니다: {message}", + "owner": "소유자: {owner}", + "namespace": "네임스페이스: {namespace}", + "defaultInstallProtocol": "기본 설치 프로토콜", + "currentOptionParameterCount": "현재 옵션의 매개변수 수: {count}", + "installConfigDescription": "설치 구성 (JSON, 설치 전에 편집 가능; 편집 내용은 프로토콜/매개변수 폼을 덮어씁니다)", + "selectLeftToView": "상세 정보를 보려면 왼쪽에서 마켓플레이스 MCP를 선택하세요." + }, + "badges": { + "verified": "검증됨", + "remote": "원격", + "hasHomepage": "홈페이지 있음", + "uses": "{count}회 사용", + "deployed": "배포됨", + "notDeployed": "미배포" + }, + "selectLeftMcp": "왼쪽에서 MCP를 선택하세요." + }, + "AcpAgentSettings": { + "title": "Agent SDK 관리", + "description": "Agent SDK 연결, 활성화 상태, 환경 변수, 구성 관리, 버전 사전 점검 정보를 한곳에서 관리합니다.", + "loadingAgents": "에이전트 목록 불러오는 중...", + "agentList": "에이전트 목록", + "emptyNoAgent": "사용 가능한 에이전트가 없습니다.", + "configManagement": "구성 관리", + "envVars": "환경 변수", + "hostTools": { + "label": "파일과 명령을 에이전트가 직접 처리", + "description": "codeg가 파일 접근과 터미널 명령을 대신 처리하지 않고 에이전트가 자체 프로세스에서 실행합니다. 그래야 에이전트 자체의 샌드박스와 권한 규칙이 적용됩니다. 다른 에이전트에 위임하는 기능도 함께 꺼집니다. 같은 작업이 다시 codeg를 거치게 되기 때문입니다. codeg는 자체 샌드박스를 제공하지 않으므로 에이전트에 샌드박스를 구성한 경우에만 켜세요." + }, + "nativeJsonConfig": "네이티브 JSON 구성", + "modelHintDefault": "비워두면 시스템 기본 모델을 사용합니다.", + "generalConfigDescriptionClaude": "API URL, API Key, Claude 모델을 빠르게 설정하고 네이티브 JSON 구성과 동기화합니다.", + "generalConfigDescriptionDefault": "주요 구성 입력(API URL, API Key, Model)과 네이티브 JSON 구성 관리를 지원합니다.", + "multiAgent": { + "title": "다중 에이전트 협업", + "description": "활성 에이전트가 하위 작업을 다른 에이전트에게 위임할 수 있도록 합니다.", + "enable": "위임 사용", + "enableHint": "끄면 delegate_to_agent 도구가 에이전트의 MCP 도구 목록에서 숨겨집니다.", + "withheldByHostTools": "{agents}에는 위임 도구가 제공되지 않습니다. 해당 에이전트의 “파일과 명령을 에이전트가 직접 처리” 스위치가 켜져 있습니다.", + "selfInitiate": "Allow spawn without @", + "selfInitiateHint": "When on, an agent may start a listed sub-agent on its own. An @ mention is still always honored. When off, only an @ mention starts a sub-agent.", + "depthLimit": "최대 위임 깊이", + "depthHint": "허용 범위: {min}–{max}. 위임 체인(루트 → 하위 → 손자 …)의 재귀 깊이를 제한합니다.", + "completedCacheLabel": "완료 결과 캐시(MB)", + "completedCacheHint": "실행 중인 위임 세션이 보관하는 완료된 하위 에이전트 결과의 메모리 내 캐시입니다. 해당 세션이 실행되는 동안에만 유지되며 세션이 종료되면 자동으로 삭제됩니다. 이 예산을 초과하면 오래된 결과부터 메모리에서 삭제됩니다(하위 에이전트 자체 세션에서는 계속 확인 가능). 0은 무제한(세션 종료 시에는 그래도 삭제됨).", + "save": "저장", + "saving": "저장 중…", + "saved": "위임 설정이 저장되었습니다", + "saveFailed": "위임 설정 저장 실패", + "loadFailed": "위임 설정 로드 실패: {detail}", + "tabGeneral": "일반", + "tabAgentDefaults": "하위 에이전트 설정", + "agentDefaultsDescription": "다중 에이전트 협업이 위임 호출을 위해 하위 에이전트를 시작할 때 적용되는 재정의 항목입니다. 아래 옵션은 실시간 프로브로 가져오므로 선택한 항목이 그대로 에이전트에 전달됩니다.", + "probing": "에이전트에서 사용 가능한 옵션을 로드 중…", + "probeFailed": "옵션 로드 실패: {detail}", + "retry": "다시 시도", + "noConfigAvailable": "이 에이전트에는 구성 가능한 옵션이 없습니다.", + "modeLabel": "모드", + "agentDefaultHint": "에이전트 기본값: {value}", + "defaultOptionLabel": "기본값 ({value})" + }, + "actions": { + "dragSort": "드래그하여 순서 변경", + "dragSortAgent": "{name} 순서 변경", + "refreshCheck": "다시 확인", + "refreshCheckAgent": "{name} 다시 확인", + "clickEnable": "{name} 활성화", + "clickDisable": "{name} 비활성화", + "install": "설치", + "upgrade": "업그레이드", + "uninstall": "제거", + "uninstalling": "제거 중...", + "saveEnvVars": "환경 변수 저장", + "saving": "저장 중...", + "saveGrokConfig": "Grok 설정 저장", + "saveCodexConfig": "Codex 설정 저장", + "saveGeminiConfig": "Gemini 설정 저장", + "saveOpenCodeConfig": "OpenCode 설정 저장", + "saveOpenClawConfig": "OpenClaw 설정 저장", + "saveConfigManagement": "구성 관리 저장", + "saveCurrentProvider": "현재 Provider 저장", + "showApiKey": "API 키 보기", + "hideApiKey": "API 키 숨기기", + "showKey": "키 보기", + "hideKey": "키 숨기기", + "showToken": "토큰 보기", + "hideToken": "토큰 숨기기", + "cancel": "취소", + "delete": "삭제", + "deleting": "삭제 중...", + "confirmDelete": "삭제 확인", + "confirmUninstall": "제거 확인", + "saveClineConfig": "Cline 설정 저장", + "saveHermesConfig": "Hermes 설정 저장", + "saveCodeBuddyConfig": "CodeBuddy 구성 저장", + "saveKimiCodeConfig": "Kimi Code 구성 저장", + "customInstall": "사용자 지정 설치", + "saveKimiCodeRawConfig": "Save config.toml", + "saveDeepSeekConfig": "DeepSeek 구성 저장", + "diagnose": "진단" + }, + "status": { + "enabled": "활성화됨", + "disabled": "비활성화됨", + "unchecked": "확인 안 됨", + "agentEnabledAria": "{name} 활성화됨", + "agentEnabledSwitch": "{name} 활성화 스위치" + }, + "preflight": { + "count": "사전 점검 항목: {count}", + "notRun": "점검이 아직 실행되지 않았습니다." + }, + "grok": { + "configDescription": "여기에서 Grok을 설정합니다. 아래 컨트롤(권한 모드, 추론 강도, 선택적 사용자 지정(자체 엔드포인트) 모델, 압축)은 ~/.grok/config.toml에 병합되며 다른 키와 주석은 유지됩니다. 로그인은 XAI_API_KEY 또는 `grok login`을 사용합니다. 기타 키는 '고급'에서 편집할 수 있습니다.", + "permissionModeLabel": "권한 모드", + "permissionDefault": "매번 확인", + "permissionAcceptEdits": "편집 자동 승인", + "permissionAuto": "스마트 자동 승인", + "permissionAlwaysApprove": "항상 허용", + "reasoningEffortLabel": "추론 강도", + "effortLow": "낮음(빠름)", + "effortMedium": "중간(균형)", + "effortHigh": "높음", + "effortXhigh": "최대", + "optionDefault": "기본값 사용", + "authTitle": "인증", + "authMode": "인증 방식", + "authModeApiKey": "XAI API 키", + "authModeApiKeyHint": "xAI 콘솔의 XAI_API_KEY로 인증합니다. 비대화형·헤드리스 실행에 적합하며 이 에이전트의 환경 변수에 저장됩니다.", + "authModeCustom": "사용자 지정 엔드포인트", + "authModeCustomHint": "자체 엔드포인트(BYO)를 사용합니다. 아래에서 자체 base URL과 API 키를 가진 사용자 지정 모델을 정의하면 Grok의 기본 모델이 됩니다.", + "subscriptionHint": "`grok login`으로 로그인합니다(SuperGrok / X Premium+). API 키는 저장되지 않습니다.", + "loginHint": "터미널에서 다음 명령을 실행해 로그인한 뒤 이 설정을 다시 여세요:", + "commandCopied": "명령을 클립보드에 복사했습니다", + "copyCommand": "명령 복사", + "authKeyConfigured": "XAI_API_KEY가 구성되어 있습니다.", + "authKeyMissing": "XAI_API_KEY가 설정되지 않았습니다.", + "advancedToggle": "고급(원본 config.toml)", + "configTomlNative": "config.toml(네이티브)", + "configTomlHint": "~/.grok/config.toml 전체로 그대로 저장됩니다. 잘못된 TOML은 거부되어 오타로 파일이 잘리지 않습니다.", + "configTomlPlaceholder": "# 위 컨트롤 이외의 키, 예:\n# [mcp_servers.*], [cli], [permission] 규칙.", + "customModelTitle": "사용자 지정 모델(자체 엔드포인트)", + "customModelHint": "Grok을 사용자 지정 또는 자체 호스팅 엔드포인트로 연결합니다. codeg는 모델별 `[model.*]` 블록을 작성하고 기본 모델로 설정합니다. 모델 ID를 비우면 제거됩니다.", + "customModelIdLabel": "모델 ID", + "customModelIdPlaceholder": "grok-4.5", + "customModelIdHint": "`[model.*]` 블록으로 등록되어 모델 이름으로 API에 전송되며 `[models].default`로도 설정됩니다.", + "customBaseUrlLabel": "Base URL", + "customBaseUrlPlaceholder": "https://api.x.ai/v1(기본값)", + "customApiBackendLabel": "API 백엔드", + "backendResponses": "Responses", + "backendChatCompletions": "Chat Completions", + "backendMessages": "Messages(Anthropic)", + "customApiKeyLabel": "API 키", + "customApiKeyHint": "`[model.*].api_key`에 인라인으로 저장되며 이 엔드포인트에만 적용됩니다.", + "customContextWindowLabel": "컨텍스트 윈도우(토큰)", + "customContextWindowHint": "선택 사항. 자동 압축 타이밍에 사용됩니다. 비워 두면 엔드포인트 기본값을 사용합니다.", + "autoCompactLabel": "자동 압축 임계값(%)", + "autoCompactHint": "컨텍스트 사용량이 이 비율에 도달하면 대화를 압축합니다(Grok 기본값 85). `[session]`에 기록됩니다." + }, + "cursor": { + "configDescription": "여기에서 Cursor를 설정합니다. 먼저 인증 방식을 선택하세요——공식 구독(브라우저 로그인) 또는 헤드리스/서버용 Cursor API 키——그런 다음 모델을 선택하고 CLI의 권한 규칙과 샌드박스를 편집합니다. codeg는 이를 ~/.cursor/cli-config.json에 기록하며 cursor-agent CLI와 공유합니다.", + "authTitle": "인증", + "authChecking": "확인 중…", + "authNotInstalled": "cursor-agent가 설치되지 않았습니다", + "authLoggedIn": "로그인됨", + "authNotLoggedIn": "로그인되지 않음", + "loginHint": "터미널에서 아래 명령을 실행해 Cursor 계정으로 로그인(브라우저가 열립니다)한 뒤 새로고침을 누르세요:", + "apiKeyLabel": "Cursor API 키", + "apiKeyPlaceholder": "cursor.com/dashboard에서 발급", + "apiKeyHint": "CURSOR_API_KEY —— Cursor 대시보드의 계정 키로, 헤드리스/서버 환경에서 브라우저 로그인 대신 사용합니다. 서드파티나 OpenAI 키가 아닙니다.", + "modelTitle": "기본 모델", + "loadModels": "모델 목록 가져오기", + "modelsUnavailable": "모델 목록을 가져올 수 없음", + "modelHint": "세션 시작 시 --model로 CLI에 전달됩니다. 기본값이면 Cursor가 선택합니다.", + "permissionsTitle": "권한 및 샌드박스", + "permissionsDescription": "CLI 권한 규칙(cli-config.json)의 시각 편집기입니다. 허용 규칙은 확인 없이 실행되고 거부 규칙은 항상 차단됩니다.", + "permissionModeLabel": "권한 모드", + "permissionModeDefault": "실행 전 확인(기본)", + "permissionModeForce": "Run Everything(--force)", + "permissionModeHint": "Run Everything은 --force로 세션을 시작합니다. deny 규칙을 제외한 모든 도구 호출이 확인 없이 자동 허용됩니다(조직 정책에 따라 allow 규칙 일치로 제한될 수 있음). 새 세션부터 적용됩니다.", + "optionDefault": "기본(미설정)", + "sandboxLabel": "샌드박스", + "sandboxEnabled": "사용", + "sandboxDisabled": "사용 안 함", + "allowRulesLabel": "허용 규칙", + "denyRulesLabel": "거부 규칙", + "addRule": "규칙 추가", + "rulesSyntaxHint": "규칙 구문: Shell(명령), Read(경로/글롭), Write(경로/글롭), WebFetch(도메인), Mcp(서버:도구) — deny 규칙이 항상 우선합니다.", + "saveConfig": "설정 저장", + "advancedToggle": "고급: 원본 cli-config.json", + "advancedHint": "~/.cursor/cli-config.json 전체입니다. 여기서 저장하면 그대로 기록되며, 위 구조화 컨트롤은 병합 방식으로 기록됩니다.", + "saveRawConfig": "파일 저장", + "authMode": "인증 방식", + "subscriptionHint": "Cursor 계정으로 로그인하고 Cursor의 모델을 사용합니다.", + "customApiKeyRequired": "Cursor API 키가 필요합니다.", + "authModeApiKey": "Cursor API 키 (헤드리스/서버)", + "authModeApiKeyHint": "Cursor 대시보드에서 발급한 계정 API 키로 인증합니다(헤드리스/서버 환경용). 이는 Cursor 계정 키이며 서드파티/OpenAI 엔드포인트가 아닙니다——cursor-agent는 Cursor 자체 백엔드에만 연결됩니다. codex/OpenAI 호환 엔드포인트를 사용하려면 Codex 에이전트를 대신 사용하세요.", + "modelPickerPlaceholder": "모델 검색…", + "modelNoMatch": "일치하는 모델 없음", + "modelsNeedAuth": "로그인하면 모델 목록을 불러옵니다.", + "modelDefaultBadge": "기본값" + }, + "deepseek": { + "configManagement": "DeepSeek Harness 구성", + "configDescription": "엔드포인트와 API 키는 deepseek-acp가 시작할 때 읽는 환경 변수입니다. 모델과 추론 강도는 세션별 선택기이므로 입력창에서 바꿉니다.", + "baseUrlLabel": "API 엔드포인트", + "baseUrlHint": "비워 두면 공식 엔드포인트를 사용합니다. 저장 후 시작하는 세션부터 적용되며, 실행 중인 세션은 다시 연결해야 반영됩니다.", + "baseUrlInvalid": "쿼리 문자열이 없는 완전한 http(s) URL을 입력하세요. 예: https://api.deepseek.com", + "apiKeyLabel": "API 키", + "apiKeyHint": "DEEPSEEK_API_KEY로 에이전트에 전달됩니다. 환경 변수가 자격 증명 파일보다 우선하므로 터미널로 로그인한다면 비워 두세요." + }, + "codex": { + "configDescription": "API URL, API Key, 모델 이름, reasoning effort를 빠르게 설정하고 `auth.json` / `config.toml`과 동기화합니다.", + "authMode": "인증 방식", + "chatgptSubscription": "공식 구독", + "chatgptSubscriptionHint": "ChatGPT 공식 구독으로 로그인, API Key 불필요", + "apiKeyHint": "API Key로 OpenAI 또는 호환 API 서비스에 연결", + "selectProvider": "Provider 선택", + "modelName": "모델 이름", + "selectReasoningEffort": "Reasoning Effort 선택", + "enableWebsocket": "WebSocket 활성화", + "enableWebsocketAria": "Codex Provider용 WebSocket 활성화", + "enableSkills": "Skills 활성화", + "enableSkillsAria": "Codex용 Skills 활성화", + "enableFast": "Fast 활성화", + "enableFastAria": "Codex용 Fast 서비스 계층 활성화", + "sandboxGroupTitle": "샌드박스 및 승인", + "sandboxGroupHint": "전역 ~/.codex/config.toml에 기록되므로 codex CLI와 IDE 세션에도 적용됩니다. 스레드 기본값이며 codex가 스스로 시작하는 턴(/goal, /review, /compact)에만 적용됩니다. 일반 프롬프트는 입력창의 승인 프리셋을 사용합니다. 변경 사항은 세션을 다시 시작해야 반영됩니다.", + "sandboxShadowedWarning": "config.toml에 default_permissions가 설정되어 있어 codex가 권한 프로필로 해석하고 sandbox_mode를 완전히 무시합니다. 아래 설정을 사용하려면 default_permissions를 제거하세요.", + "sandboxPermissionsTableWarning": "config.toml에 [permissions] 프로필이 있지만 default_permissions가 없어 codex가 시작을 거부합니다. 아래 원본 편집기에서 설정하세요.", + "approvalPolicyLabel": "승인 정책", + "approvalPolicyUnset": "설정 안 함(codex 기본값: 요청 시)", + "approvalPolicy_on-request": "요청 시 — 모델이 확인 시점을 결정", + "approvalPolicy_untrusted": "신뢰 안 함 — 안전이 확인된 읽기 전용 명령만 자동 실행", + "approvalPolicy_never": "묻지 않음 — 승인 창을 전혀 띄우지 않음", + "approvalPolicy_granular": "세부 설정 — 프롬프트 종류별로 지정", + "approvalPolicyUntrustedAcpWarning": "ACP 어댑터의 세 가지 승인 프리셋에는 untrusted에 해당하는 항목이 없으므로 codeg 세션은 \"요청 시\"로 대체됩니다. 이 경우 모델이 물어볼 시점을 스스로 정하며, 샌드박스가 이미 허용한 명령은 더 이상 확인하지 않습니다. 대신 아래 샌드박스 모드로 제한하세요.", + "granularHint": "끄면 해당 종류의 요청은 표시되지 않고 자동으로 거부됩니다.", + "granular_sandbox_approval": "셸 명령 권한 상승", + "granular_rules": "Execpolicy 규칙 프롬프트", + "granular_skill_approval": "스킬 스크립트 프롬프트", + "granular_request_permissions": "request_permissions 도구 프롬프트", + "granular_mcp_elicitations": "MCP elicitation 프롬프트", + "sandboxModeLabel": "샌드박스 모드", + "sandboxModeUnset": "설정 안 함(신뢰된 폴더는 워크스페이스 쓰기로 대체)", + "sandboxMode_read-only": "읽기 전용", + "sandboxMode_workspace-write": "워크스페이스 쓰기", + "sandboxMode_danger-full-access": "전체 접근(샌드박스 없음)", + "sandboxModeHint": "Windows에서는 codex의 실험적 Windows 샌드박스를 켜지 않으면 워크스페이스 쓰기가 읽기 전용으로 낮아집니다.", + "sandboxModeSeedsPresetHint": "codeg는 이 값으로 세션의 초기 승인 프리셋도 정하므로, 승인 정책과 달리 일반 프롬프트에도 적용됩니다. 입력창에서 선택한 프리셋이 이를 덮어씁니다.", + "writableRootsLabel": "추가 쓰기 가능 폴더", + "writableRootsHint": "작업 디렉터리 외에 허용할 절대 경로를 한 줄에 하나씩.", + "sandboxRootsRelativeError": "절대 경로여야 합니다 — codex는 상대 경로를 ~/.codex 기준으로 해석합니다: {path}", + "networkAccessLabel": "네트워크 접근 허용", + "excludeTmpdirLabel": "쓰기 가능 루트에서 TMPDIR 제외", + "excludeSlashTmpLabel": "쓰기 가능 루트에서 /tmp 제외", + "authJsonNative": "auth.json (네이티브)", + "configTomlNative": "config.toml (네이티브)", + "loginButton": "ChatGPT로 로그인", + "loginRequesting": "로그인 코드 요청 중...", + "loginStep1": "브라우저에서 다음 URL을 열어주세요:", + "loginStep2": "아래 코드를 입력하세요:", + "loginPolling": "인증 대기 중...", + "loginCancel": "취소", + "loginSuccess": "로그인 성공, 설정이 저장되었습니다!", + "loginFailed": "로그인 실패: {message}", + "loginRetry": "재시도", + "loginCodeCopied": "코드가 복사되었습니다", + "loggedIn": "계정 로그인됨", + "loginRelogin": "재로그인 / 계정 전환", + "loginTimeout": "로그인 시간 초과, 다시 시도해 주세요", + "loginSaveFailed": "로그인 성공했지만 설정 저장 실패" + }, + "gemini": { + "authConfig": "Gemini 인증 설정", + "authConfigDescription": "Gemini CLI 인증 문서와 정렬되며, 커스텀 엔드포인트, Google 로그인, Gemini API Key, Vertex AI(ADC / 서비스 계정 / API Key)를 지원합니다.", + "authMode": "인증 모드", + "selectAuthMode": "인증 모드 선택", + "viewAuthDoc": "인증 문서 보기", + "mode": { + "custom": "커스텀 엔드포인트", + "loginGoogle": "Google 로그인 (OAuth)", + "vertexServiceAccount": "Vertex AI (서비스 계정)" + }, + "hint": { + "custom": "API URL, API Key, Model을 입력하세요. GOOGLE_GEMINI_BASE_URL / GEMINI_API_KEY / GEMINI_MODEL에 매핑됩니다.", + "loginGoogle": "먼저 터미널에서 gemini를 실행해 Google 로그인을 완료하세요. API key는 필요하지 않습니다.", + "geminiApiKey": "Gemini API 사용 시 GEMINI_API_KEY를 입력하세요.", + "vertexAdc": "gcloud ADC를 사용합니다. GOOGLE_CLOUD_PROJECT와 GOOGLE_CLOUD_LOCATION 설정을 권장합니다.", + "vertexServiceAccount": "서비스 계정 JSON 경로를 GOOGLE_APPLICATION_CREDENTIALS에 설정하세요.", + "vertexApiKey": "Vertex AI API key 사용 시 GOOGLE_API_KEY를 입력하세요." + } + }, + "openCode": { + "configManagement": "OpenCode 구성 관리", + "configDescription": "OpenCode `provider` 스키마에 맞추어 다중 Provider 관리와 네이티브 JSON 파일 양방향 동기화를 지원합니다.", + "providerManagement": "Provider 관리", + "providerCount": "Provider {count}개", + "addProvider": "Provider 추가", + "emptyProvider": "아직 사용자 지정 공급자가 없습니다. '사용자 지정 공급자 추가'를 클릭해 만드세요.", + "providerEnabledState": "{providerId} 활성 상태", + "selectProviderNpm": "provider.npm 선택", + "modelManagement": "모델 관리", + "modelCount": "모델 {count}개", + "modelDescription": "OpenCode `provider.models`와 정렬됩니다. 빠른 관리는 현재 `name` / `id`를 지원하며, 기타 고급 필드는 유지되고 아래 네이티브 JSON에서 편집할 수 있습니다.", + "addModel": "모델 추가", + "emptyModel": "아직 모델이 없습니다. model id를 입력한 뒤 \"모델 추가\"를 클릭하세요.", + "modelId": "모델 ID", + "modelName": "모델 이름", + "deleteModel": "모델 {modelId} 삭제", + "nativeJsonConfig": "OpenCode 네이티브 JSON 구성", + "mainModel": "메인 모델", + "smallModel": "스몰 모델", + "noMatchingModels": "일치하는 모델 없음", + "connectProvider": "공급자 연결", + "connectedProviders": "연결된 공급자", + "noConnectedProviders": "아직 카탈로그 공급자를 연결하지 않았습니다.", + "advancedProviderConfig": "사용자 지정 공급자", + "customProviderConfigHint": "직접 정의하는 OpenAI 호환 엔드포인트입니다 — opencode.json의 provider 블록이며 API 키는 auth.json에 저장됩니다.", + "addCustomProvider": "사용자 지정 공급자 추가", + "disconnect": "연결 해제", + "editConfig": "편집", + "customBadge": "사용자 지정", + "authKindApi": "API 키", + "authKindOauth": "OAuth", + "authKindNone": "자격 증명 없음", + "connect": { + "title": "공급자 연결", + "description": "models.dev 카탈로그에서 공급자를 선택하세요. 자격 증명은 OpenCode의 auth.json 파일에 저장됩니다.", + "pick": "공급자", + "search": "공급자 검색…", + "loading": "카탈로그 불러오는 중…", + "catalogLabel": "models.dev 카탈로그", + "modelsAvailable": "{count}개 모델 사용 가능", + "getKey": "API 키 받기", + "oauthApiKeyNote": "이 공급자는 opencode auth login을 통한 브라우저 로그인도 지원합니다. 브라우저 로그인은 곧 제공됩니다. 지금은 API 키를 붙여넣으세요.", + "apiKey": "API 키", + "apiKeyHint": "auth.json에 저장되며 opencode.json에는 저장되지 않습니다.", + "baseUrlOptional": "Base URL 재정의 (선택)", + "providerId": "공급자 ID", + "displayName": "표시 이름", + "modelsList": "모델 (한 줄에 하나)", + "modelsHint": "엔드포인트가 허용하는 모델 ID.", + "action": "연결", + "editTitle": "공급자 편집", + "editDescription": "이 공급자의 API 키 또는 Base URL을 업데이트합니다.", + "saveAction": "저장" + }, + "customProvider": { + "title": "사용자 지정 공급자 추가", + "description": "OpenAI 호환 엔드포인트를 정의합니다. API 키는 auth.json에, provider 블록은 opencode.json에 저장됩니다.", + "action": "공급자 추가", + "idInCatalog": "{providerId}은(는) 알려진 공급자입니다. 대신 '공급자 연결'로 연결하세요." + }, + "refreshCatalog": "카탈로그 새로고침", + "reasoningBadge": "추론", + "contextWindow": "컨텍스트 윈도우", + "permissions": { + "title": "권한", + "description": "어떤 작업을 바로 실행할지, 먼저 확인할지, 차단할지 정합니다. opencode.json 의 permission 설정에 기록되며 아래에서 저장하면 적용됩니다.", + "docsLink": "권한 문서", + "unparsableConfig": "아래 네이티브 JSON 을 해석할 수 없어 시각적 편집을 멈췄습니다. JSON 을 고치면 다시 사용할 수 있습니다.", + "invalidBlock": "permission 설정의 형태를 인식할 수 없습니다. 아래 네이티브 JSON 에서 수정하거나 [초기화] 로 다시 시작하세요.", + "orderingUnsafe": "와일드카드 규칙이 개별 도구보다 뒤에 적혀 있어 OpenCode 가 그 도구들에도 적용합니다. 아래 행은 실제로 적용되는 값이 아닙니다. [순서 수정] 은 값을 바꾸지 않고 와일드카드를 각 범위 맨 앞으로 되돌립니다.", + "orderingUnsafeManual": "어떤 규칙이 뒤의 더 넓은 패턴에 가려져 OpenCode 가 절대 적용하지 않습니다. 아래 행은 실제로 적용되는 값이 아닙니다. 겹치는 두 패턴에는 정답인 순서가 없으므로, 아래 네이티브 JSON 에서 더 넓은 쪽을 앞으로 옮기세요.", + "fixOrder": "순서 수정", + "agentOverrides": "다음 에이전트가 권한을 재정의하며 마지막에 적용되므로 여기 설정보다 우선합니다: {agents}. 아래 네이티브 JSON 에서 수정하거나 자동 수락을 켜서 지우세요.", + "legacyTools": "최상위 레거시 tools 설정이 어떤 도구를 거부하고 있습니다. OpenCode 가 이를 권한에 합치므로 여기 표시된 모든 설정 위에 적용됩니다. 아래 네이티브 JSON 에서 수정하거나 자동 수락을 켜서 지우세요.", + "autoAcceptTitle": "모든 권한 자동 수락", + "autoAcceptHint": "셸 명령, 파일 수정, 프로젝트 밖 경로를 포함한 모든 도구 호출을 묻지 않고 실행합니다. 켜면 아래 도구별 설정이 전체 허용 규칙 하나로 대체되고, 그대로 두면 계속 막을 에이전트별 권한 재정의와 레거시 tools 설정도 지워집니다.", + "globalLabel": "전역 기본값", + "globalHint": "* 규칙입니다. 아래 도구에서 따로 지정하지 않은 모든 경우에 적용됩니다.", + "actionUnset": "설정 안 함 (OpenCode 기본값)", + "actionInherit": "기본값 따름 ({action})", + "actionAllow": "허용", + "actionAsk": "확인", + "actionDeny": "거부", + "perToolTitle": "도구별 권한", + "reset": "초기화", + "ruleCount": "규칙: {count}", + "rulesToggle": "{tool} 의 세부 규칙", + "rulesHint": "도구 입력과 대조하며 마지막으로 일치한 규칙이 우선하므로 넓은 패턴을 먼저 적으세요. * 는 임의의 문자열, ? 는 정확히 한 글자와 일치하고 맨 앞의 ~ 는 홈 디렉터리로 확장됩니다.", + "noRules": "아직 세부 규칙이 없습니다.", + "addRule": "규칙 추가", + "deleteRule": "규칙 {pattern} 삭제", + "duplicateRule": "이미 있는 패턴입니다.", + "blankRule": "규칙에는 패턴이 필요합니다. 삭제하려면 휴지통 아이콘을 사용하세요.", + "customKeys": "파일에 있는 다른 권한 키", + "customKeyHint": "OpenCode 기본 도구가 아니며 작성된 그대로 유지됩니다.", + "keys": { + "bash": "셸 명령 실행, 파싱된 명령으로 대조", + "edit": "모든 파일 수정: edit, write, patch", + "read": "파일 읽기, 경로로 대조", + "external_directory": "프로젝트 작업 디렉터리 밖 경로 접근", + "task": "서브에이전트 실행, 서브에이전트 유형으로 대조", + "skill": "스킬 로드, 스킬 이름으로 대조", + "glob": "파일 찾기, 글로브 패턴으로 대조", + "grep": "파일 내용 검색, 패턴으로 대조", + "list": "디렉터리 내용 나열", + "webfetch": "URL 가져오기", + "websearch": "웹 검색", + "lsp": "LSP 질의 실행", + "todowrite": "할 일 목록 작성", + "question": "사용자에게 질문", + "doom_loop": "같은 호출이 같은 입력으로 3 번 반복되면 작동" + } + } + }, + "openClaw": { + "gatewayConfig": "Gateway 구성", + "gatewayDescription": "OpenClaw Gateway 연결을 구성합니다. 로컬 또는 원격 gateway를 지원합니다.", + "gatewayUrlHint": "비워두면 로컬 openclaw 설정의 gateway.remote.url을 사용합니다.", + "gatewayTokenPlaceholder": "Gateway 인증 토큰", + "gatewayTokenHint": "가능하면 평문 토큰 대신 token-file을 사용하세요. openclaw CLI로 설정하세요.", + "sessionKeyHint": "선택 사항입니다. gateway 세션 키를 지정합니다. 비워두면 격리된 세션이 자동 할당됩니다." + }, + "hermes": { + "configManagement": "Hermes 구성", + "configDescription": "Hermes는 자격 증명을 ~/.hermes/.env에, 설정을 ~/.hermes/config.yaml에 직접 관리합니다. 공급자를 선택한 다음 API 키와 모델을 설정하세요. codeg가 두 파일을 모두 작성해 줍니다.", + "providerLabel": "공급자", + "providerHint": "공급자에 따라 Hermes가 사용하는 API 키 변수와 model.provider가 결정됩니다. OAuth 공급자는 아래 터미널 설정을 통해 구성합니다.", + "groupApiKey": "API 키 제공자", + "groupOauth": "OAuth 제공자", + "groupAws": "AWS", + "apiKeyHint": "~/.hermes/.env에 저장됩니다. 프로세스에 절대 주입되지 않으며, Hermes가 자체 구성에서 읽어옵니다.", + "modelName": "모델", + "oauthHint": "이 공급자는 OAuth를 사용합니다. 아래 설정을 실행하여 터미널에서 인증하세요.", + "awsHint": "Bedrock은 AWS 자격 증명(환경 변수 또는 공유 구성)을 사용합니다. 위에서 모델 ID를 설정하고 환경에서 AWS 액세스를 구성하세요.", + "unsupportedProvider": "이 제공자는 구조화된 필드로 편집할 수 없습니다. 아래의 config.yaml 원본 편집기나 터미널 설정을 사용하세요.", + "setupTitle": "자체 관리 설정", + "setupHint": "Hermes의 대화형 설정에는 터미널이 필요합니다. 아래에서 실행하거나 명령을 복사하여 직접 실행하세요.", + "runSetup": "Hermes 설정 실행", + "configureModel": "모델 구성", + "openConfigFolder": "~/.hermes 열기", + "copyCommand": "명령 복사", + "commandCopied": "명령을 클립보드에 복사했습니다", + "advancedTitle": "고급: config.yaml 편집", + "rawConfigHint": "~/.hermes/config.yaml을 직접 편집합니다. 여기서 저장하면 파일이 그대로 덮어쓰여집니다.", + "saveRawConfig": "config.yaml 저장" + }, + "codebuddy": { + "configManagement": "CodeBuddy 구성", + "configDescription": "CodeBuddy는 API 키로 인증합니다. 중국 버전은 환경을 ‘중국(internal)’으로 설정해야 하며, iOA 버전은 ‘iOA’를 사용하고, 해외 버전은 설정하지 않습니다.", + "apiKeyLabel": "API 키", + "apiKeyHint": "이 에이전트의 CODEBUDDY_API_KEY로 저장됩니다. 또는 터미널에서 CodeBuddy CLI로 로그인할 수도 있습니다.", + "apiKeyHintSelfHosted": "이 에이전트의 CODEBUDDY_API_KEY로 저장됩니다. 비공개 배포에서 발급한 키를 사용하세요.", + "environmentLabel": "환경", + "environmentHint": "CODEBUDDY_INTERNET_ENVIRONMENT를 설정합니다. 중국 본토는 ‘중국(internal)’을 사용해야 하며, 해외 버전은 설정하지 않습니다.", + "envOverseas": "해외(기본값)", + "envChina": "중국(internal)", + "envIoa": "iOA", + "envSelfHosted": "프라이빗 배포(자체 호스팅)", + "baseUrlLabel": "배포 URL", + "baseUrlPlaceholder": "https://codebuddy.your-company.com", + "baseUrlHint": "CODEBUDDY_BASE_URL로 저장되어 CodeBuddy를 비공개 엔드포인트로 연결합니다. 자체 호스팅에서는 네트워크 환경(CODEBUDDY_INTERNET_ENVIRONMENT)을 설정하지 않습니다.", + "baseUrlInvalid": "유효한 http(s) URL을 입력하세요.", + "loginHint": "API 키가 없나요? 터미널에서 ‘codebuddy’를 실행하여 Tencent 계정으로 로그인할 수도 있습니다." + }, + "kimiCode": { + "configManagement": "Kimi Code 설정", + "configDescription": "`kimi acp`는 저장된 로그인 토큰만 인정하므로, codeg가 ~/.kimi-code/config.toml에 관리형 공급자를 기록하고 로컬에 게이트 토큰을 심습니다. 추론은 여전히 사용자의 키로 실행됩니다.", + "statusUnconfigured": "아직 설정되지 않음", + "statusDirty": "저장되지 않은 변경 사항", + "summaryLabel": "적용된 설정", + "gateReadyApiKey": "API 키가 config.toml에 기록됨", + "gateReadyLogin": "Kimi 계정으로 로그인됨", + "revealConfig": "폴더에서 보기", + "envOverrideWarning": "{keys}이(가) 설정되어 있으며 config.toml보다 우선합니다. 여기서 저장하면 자동으로 삭제됩니다.", + "authModeLabel": "인증 방식", + "authModeApiKey": "API 키", + "authModeLogin": "Kimi 계정 로그인(구독)", + "authModeApiKeyHint": "config.toml에 관리형 공급자를 기록하고, 세션이 열리도록 게이트 토큰을 심습니다.", + "loginHint": "터미널에서 `kimi login`을 실행해 Kimi 구독 계정으로 로그인하세요. codeg는 자격 증명을 저장하지 않고 Kimi 자체 로그인을 재사용합니다. 여기서 저장하면 codeg의 API 키 게이트 토큰이 제거됩니다.", + "credentialTitle": "자격 증명", + "interfaceTypeLabel": "공급자 유형", + "interfaceTypeHint": "Kimi가 사용하는 공급자 프로토콜(config.toml의 `type`). Moonshot / platform.kimi.com 키라면 「Kimi / Moonshot」을 선택하세요.", + "endpointLabel": "엔드포인트", + "endpointCustom": "사용자 지정(OpenAI 호환)", + "endpointHint": "국제 = api.moonshot.ai, 중국(platform.kimi.com 키) = api.moonshot.cn. 사용자 지정은 모든 OpenAI 호환 엔드포인트를 가리킬 수 있습니다.", + "regionInternational": "국제(api.moonshot.ai)", + "regionChina": "중국(api.moonshot.cn)", + "baseUrlLabel": "Base URL", + "baseUrlHint": "비워 두면 공급자 SDK 기본값을 사용합니다.", + "apiKeyLabel": "API 키", + "apiKeyHint": "~/.kimi-code/config.toml에 기록되어 추론에 사용됩니다. platform.kimi.com 또는 platform.kimi.ai에서 발급받습니다.", + "vertexProjectLabel": "GCP 프로젝트(GOOGLE_CLOUD_PROJECT)", + "vertexLocationLabel": "GCP 리전(GOOGLE_CLOUD_LOCATION)", + "vertexHint": "Vertex AI는 Google 애플리케이션 기본 자격 증명을 사용합니다. `gcloud auth application-default login`을 실행하세요(API 키 불필요).", + "modelTitle": "모델", + "modelLabel": "모델", + "modelHint": "config.toml에 기록되는 모델 id입니다. 「테스트 후 모델 가져오기」로 키가 실제로 접근 가능한 모델을 확인하세요.", + "maxContextLabel": "최대 컨텍스트 길이", + "maxContextHint": "Kimi 스키마에서 필수입니다. 값이 없으면 Kimi가 모델 블록 전체를 버려 모든 프롬프트가 응답 없이 끝납니다. 기본값은 262144입니다.", + "fetchModels": "테스트 후 모델 가져오기", + "fetchModelsOk": "키 정상 — 모델 {count}개 사용 가능", + "fetchModelsEmpty": "키는 정상이지만 반환된 모델이 없습니다", + "fetchModelsFailed": "테스트 실패", + "fetchModelsNeedsKey": "먼저 API 키와 엔드포인트를 입력하세요", + "modelNotInList": "이 모델은 키가 접근할 수 있는 목록에 없습니다. Kimi가 「모델을 찾을 수 없음」으로 실패합니다.", + "reasoningTitle": "추론", + "reasoningEnableLabel": "사용", + "reasoningDescription": "모델이 추론 기능을 선언한 경우에만 Kimi가 입력창에 「Thinking」선택기를 표시하므로, codeg가 여기서 그 선언을 기록합니다. 새 세션부터 적용됩니다.", + "effortsLabel": "제공할 단계", + "effortsHint": "여기서 고른 값이 입력창 「Thinking」선택기의 항목이 됩니다. Kimi는 단계를 공급자에게 그대로 전달하므로 모델이 받아들이는 값을 고르세요.", + "effortsEmptyHint": "단계를 하나도 고르지 않으면 입력창은 Off / On 2단 토글로 축소됩니다.", + "effortsCustomPlaceholder": "다른 단계 추가", + "effortsAdd": "추가", + "defaultEffortLabel": "기본 단계", + "defaultEffortAuto": "Kimi에 맡기기", + "alwaysThinkingLabel": "모델이 항상 추론함 — 선택기에서 Off 항목 제거", + "fixErrorsFirst": "먼저 표시된 항목을 수정하세요", + "errorModelRequired": "모델은 필수 항목입니다", + "errorMaxContextRequired": "최대 컨텍스트 길이는 필수 항목입니다", + "errorMaxContextInvalid": "양의 정수여야 합니다", + "errorApiKeyRequired": "API 키는 필수 항목입니다", + "errorApiKeyInvalid": "API 키에는 줄바꿈을 포함할 수 없습니다", + "errorBaseUrlRequired": "Base URL은 필수 항목입니다", + "errorBaseUrlInvalid": "http:// 또는 https://로 시작해야 합니다", + "errorVertexProjectRequired": "GCP 프로젝트는 필수 항목입니다", + "errorDefaultEffortUnlisted": "위에서 선택한 단계 중 하나여야 합니다", + "advancedTitle": "고급", + "authTypeLabel": "자격 증명 기록 위치", + "authTypeApiKey": "인라인 api_key", + "authTypeEnv": "공급자 env 하위 테이블", + "authTypeHint": "config.toml 안에서 API 키를 기록할 위치입니다.", + "rawEditorLabel": "config.toml 직접 편집", + "rawEditorWarning": "여기서 저장하면 파일 전체가 그대로 덮어써져 위의 구조화된 설정이 대체됩니다.", + "rawEditorPlaceholder": "[providers.codeg]\ntype = \"kimi\"\nbase_url = \"https://api.moonshot.cn/v1\"\napi_key = \"sk-...\"" + }, + "authModeOfficialSubscription": "공식 구독", + "authModeCustomEndpoint": "사용자 정의 엔드포인트", + "authModeCustomEndpointHint": "API URL과 API Key를 수동으로 구성하여 사용자 정의 엔드포인트에 연결합니다.", + "authModeModelProvider": "모델 공급자", + "modelProvider": "모델 공급자", + "modelProviderHint": "구성된 모델 공급자의 API URL, API Key 및 모델을 사용합니다.", + "selectModelProvider": "모델 공급자 선택", + "noModelProviderAvailable": "이 에이전트에 구성된 모델 공급자가 없습니다. 모델 공급자 설정에서 추가하세요.", + "claude": { + "authMode": "인증 방식", + "officialSubscription": "공식 구독", + "officialSubscriptionHint": "Anthropic 공식 구독 사용, API Key 불필요.", + "mainModel": "메인 모델", + "reasoningModel": "추론 모델 (thinking)", + "haikuDefaultModel": "기본 Haiku 모델", + "sonnetDefaultModel": "기본 Sonnet 모델", + "opusDefaultModel": "기본 Opus 모델", + "customModelOption": "사용자 지정 모델 ID", + "customModelOptionName": "사용자 지정 모델 이름", + "customModelOptionDescription": "사용자 지정 모델 설명", + "customModelOptionHint": "Claude 모델 선택기에 사용자 지정 항목 하나를 추가합니다(예: 사용자 지정 게이트웨이/프록시를 통해 제공되는 모델). 이름과 설명은 선택적 표시 설정입니다.", + "effortLevel": "추론 수준", + "effortLevelDefault": "기본 수준", + "effortLevel_low": "낮음", + "effortLevel_medium": "중간", + "effortLevel_high": "높음", + "effortLevel_xhigh": "매우 높음", + "sendAttributionHeader": "API에 속성/청구 식별자 전송", + "sendAttributionHeaderAria": "API에 Claude Code 속성/청구 식별자 전송", + "disableNonessentialTraffic": "텔레메트리 또는 불필요한 네트워크 요청 비활성화", + "disableNonessentialTrafficAria": "Claude Code 텔레메트리 또는 불필요한 네트워크 요청 비활성화" + }, + "dialogs": { + "confirmDeleteProvider": "Provider {providerId}를 삭제하시겠습니까?", + "confirmDeleteProviderDescription": "OpenCode config와 auth JSON이 함께 업데이트됩니다. 이 작업은 되돌릴 수 없습니다.", + "confirmUninstall": "{name}을(를) 제거하시겠습니까?", + "confirmUninstallDescription": "로컬 설치 버전을 제거합니다. 나중에 다시 설치할 수 있습니다.", + "customInstallTitle": "{name} 사용자 지정 설치", + "customInstallDescription": "설치할 버전을 입력하세요. 다시 설치되며 현재 설치된 버전을 대체합니다.", + "customInstallVersionLabel": "버전 번호", + "customInstallInvalid": "유효한 버전 번호를 입력하세요. 예: 1.2.3", + "customInstallSubmit": "설치" + }, + "errors": { + "windowsFileLocked": "{name}의 파일이 실행 중인 세션에서 사용 중이어서 Windows에서 교체할 수 없습니다. 모든 {name} 세션을 닫은 후 다시 시도하세요.", + "nativeJsonMustBeObject": "네이티브 JSON 구성은 객체여야 합니다", + "nativeJsonInvalid": "네이티브 JSON 구성 형식 오류: {message}", + "openCodeAuthMustBeObject": "OpenCode auth.json은 JSON 객체여야 합니다", + "openCodeAuthInvalid": "OpenCode auth.json 형식 오류: {message}", + "authMustBeObject": "auth.json은 JSON 객체여야 합니다", + "authInvalid": "auth.json 형식 오류: {message}", + "providerIdPattern": "Provider ID는 문자, 숫자, 밑줄, 점, 하이픈만 지원합니다", + "providerExists": "Provider {providerId}가 이미 존재합니다", + "modelIdPattern": "Model ID는 문자, 숫자, 밑줄, 점, 콜론, 하이픈만 지원합니다", + "modelExists": "Model {modelId}가 이미 존재합니다" + }, + "warnings": { + "nativeJsonRecoveredStructured": "네이티브 JSON 구성이 잘못되어 구조화 구성으로 재설정했습니다", + "nativeJsonRecoveredOpenCode": "네이티브 JSON 구성이 잘못되어 OpenCode 구조화 구성으로 재설정했습니다", + "openCodeAuthRecovered": "OpenCode auth.json이 잘못되어 기본 구성으로 재설정했습니다", + "authRecoveredStructured": "auth.json이 잘못되어 구조화 구성으로 재설정했습니다" + }, + "toasts": { + "agentActionCompleted": "{name} {action} 완료", + "agentActionFailed": "{name} {action} 실패", + "localVersion": "로컬 버전: {version}", + "installCompletedVersionLater": "설치가 완료되었습니다. 버전은 다음 확인 시 업데이트됩니다", + "uninstallCompleted": "{name} 제거 완료", + "uninstallFailed": "{name} 제거 실패", + "localVersionRemoved": "로컬 버전이 제거되었습니다", + "saveAgentOrderFailed": "Agent 순서 저장 실패", + "saveAgentSwitchFailed": "Agent 스위치 저장 실패", + "saveEnvFailed": "환경 변수 저장 실패", + "grokSaved": "Grok 설정이 저장됨", + "saveGrokNativeFailed": "Grok 네이티브 설정 저장 실패", + "saveGrokApiKeyFailed": "설정은 저장되었지만 API 키를 저장하지 못했습니다", + "cursorSaved": "Cursor 설정이 저장되었습니다", + "saveCursorConfigFailed": "Cursor 설정 저장 실패", + "codexSaved": "Codex 설정 저장됨", + "saveCodexNativeFailed": "Codex 네이티브 구성 저장 실패", + "geminiSaved": "Gemini 설정 저장됨", + "saveGeminiFailed": "Gemini 설정 저장 실패", + "providerDeleted": "Provider {providerId} 삭제됨", + "providerDeleteFailed": "Provider {providerId} 삭제 실패", + "providerSaved": "Provider {providerId} 저장됨", + "saveProviderFailed": "Provider {providerId} 저장 실패", + "openCodeConfigSynced": "OpenCode config와 auth JSON이 동기화되었습니다.", + "openCodeSaved": "OpenCode 설정 저장됨", + "saveOpenCodeFailed": "OpenCode 설정 저장 실패", + "openClawSaved": "OpenClaw 설정 저장됨", + "saveOpenClawFailed": "OpenClaw 설정 저장 실패", + "configSaved": "구성이 저장되었습니다", + "configSavedHint": "기존 세션은 다시 열어야 적용됩니다", + "saveConfigManagementFailed": "구성 관리 저장 실패", + "clineSaved": "Cline 설정 저장됨", + "saveClineFailed": "Cline 설정 저장 실패", + "hermesSaved": "Hermes 설정 저장됨", + "saveHermesFailed": "Hermes 설정 저장 실패", + "codeBuddySaved": "CodeBuddy 구성이 저장되었습니다", + "saveCodeBuddyFailed": "CodeBuddy 구성 저장에 실패했습니다", + "kimiCodeSaved": "Kimi Code 구성이 저장되었습니다", + "saveKimiCodeFailed": "Kimi Code 구성 저장 실패", + "deepseekSaved": "DeepSeek 구성을 저장했습니다", + "saveDeepSeekFailed": "DeepSeek 구성 저장 실패", + "modelProviderRequired": "저장하기 전에 모델 공급자를 선택하세요.", + "affectedRunningSessions": "{count}개의 실행 중인 세션은 다시 연결하면 변경 사항이 적용됩니다", + "providerConnected": "{providerId} 연결됨", + "connectFailed": "{providerId} 연결 실패", + "providerDisconnected": "{providerId} 연결 해제됨", + "disconnectFailed": "{providerId} 연결 해제 실패", + "catalogRefreshed": "카탈로그를 새로고침했습니다 — 공급자 {count}개", + "catalogRefreshFailed": "카탈로그 새로고침 실패", + "piSaved": "Pi 설정이 저장됨", + "savePiFailed": "Pi 설정 저장 실패", + "piRuntimeSaved": "Pi 런타임이 저장됨", + "savePiRuntimeFailed": "Pi 런타임 저장 실패", + "piBinaryInstalled": "pi 설치됨", + "piBinaryInstallFailed": "pi 설치 실패", + "piBinaryUninstalled": "pi 제거됨", + "piBinaryUninstallFailed": "pi 제거 실패", + "savePiTrustFailed": "작업 공간 신뢰 저장 실패" + }, + "version": { + "statusLabel": "버전 상태", + "notInstalled": "설치되지 않음", + "remoteLocal": "원격: {remoteVersion} · 로컬: {localVersion}", + "localOnly": "로컬: {localVersion}", + "localInstalled": "{versionText}. 설치되어 있습니다.", + "platformUnsupported": "{versionText}. 현재 플랫폼에서는 이 에이전트를 지원하지 않습니다.", + "uvxNotReady": "{versionText}. uv 런타임이 설치되지 않았습니다. 아래 uv 검사에서 설치하면 이 에이전트를 사용할 수 있습니다.", + "clickInstall": "{versionText}. 오른쪽의 설치를 클릭하세요.", + "localUnrecognized": "{versionText}. 로컬 버전을 비교할 수 없습니다. 덮어쓰기 설치를 위해 업그레이드를 시도하세요.", + "upgradeAvailable": "{versionText}. 업그레이드가 가능합니다.", + "remoteUnavailable": "{versionText}. 현재 원격 버전을 사용할 수 없습니다.", + "latest": "{versionText}. 이미 최신입니다." + }, + "adapter": { + "label": "ACP 어댑터", + "badge": "ACP 어댑터", + "badgeHint": "이 에이전트에 대해 Codeg가 설치하는 것은 벤더 CLI가 아니라 ACP 어댑터 패키지입니다. 둘은 서로 독립적이며 설정을 공유합니다.", + "learnMore": "자세히 보기", + "missingWithNative": "사용 중인 {nativeLabel}을(를) {nativePath}에서 찾았습니다. Codeg는 에이전트를 ACP로 구동하는데 이 CLI 자체는 ACP를 지원하지 않으므로, 별도의 어댑터 패키지 {adapterPackage}(Agent Client Protocol 프로젝트가 관리, 처음에는 Zed 팀)가 필요합니다. 자체 런타임을 포함하고 있어 기존 {nativeCmd} 명령을 수정하거나 대체하지 않으며, 같은 {configDir}를 읽으므로 기존 로그인과 설정이 그대로 적용됩니다. 아래에서 설치하세요.", + "missing": "Codeg는 에이전트를 ACP로 구동하는데 {nativeLabel} 자체는 ACP를 지원하지 않으므로, 별도의 어댑터 패키지 {adapterPackage}(Agent Client Protocol 프로젝트가 관리, 처음에는 Zed 팀)가 필요합니다. 자체 런타임을 포함하므로 {nativeCmd} CLI를 먼저 설치할 필요는 없습니다. 이미 설치했다면 둘은 공존하며 {configDir}의 로그인과 설정을 공유합니다. 아래에서 설치하세요.", + "readyWithNative": "어댑터 {adapterCmd}가 설치되어 있습니다. Codeg가 실행하는 것은 이 어댑터이며, {nativePath}에 있는 사용자의 {nativeCmd}가 아닙니다. 둘은 독립된 패키지로 공존하고 모두 {configDir}를 읽으므로 로그인과 설정을 공유합니다.", + "ready": "어댑터 {adapterCmd}가 설치되어 있으며 Codeg가 실행하는 것이 바로 이것입니다. 자체 런타임을 포함하므로 {nativeLabel}은 필요하지 않습니다. 나중에 설치해도 둘은 공존하며 {configDir}를 공유합니다." + }, + "cline": { + "configDescription": "Cline API 제공자와 자격 증명을 구성합니다. 설정은 ~/.cline/data/에 저장됩니다." + }, + "opencodePlugins": { + "title": "OpenCode 플러그인", + "declared": "선언된 플러그인", + "noPlugins": "opencode.json에 선언된 플러그인이 없습니다", + "status": { + "installed": "설치됨", + "missing": "미설치" + }, + "installAll": "누락된 플러그인 모두 설치", + "pinVersions": "@latest 버전 고정", + "install": "설치", + "uninstall": "제거", + "refresh": "새로고침", + "success": "모든 플러그인이 성공적으로 설치되었습니다", + "failed": "플러그인 작업 실패" + }, + "pi": { + "configManagement": "Pi 설정", + "configDescription": "Pi는 모델 제공자의 API 키로 인증합니다. 키는 ~/.pi/agent/auth.json에, 모델 선택은 settings.json에 저장됩니다.", + "providerLabel": "제공자", + "modelLabel": "모델", + "thinkingLabel": "사고", + "thinking": { + "off": "끔", + "low": "낮음", + "medium": "중간", + "high": "높음", + "minimal": "최소", + "xhigh": "매우 높음" + }, + "apiKeyLabel": "API 키", + "apiKeyHint": "선택한 제공자의 ~/.pi/agent/auth.json에 저장됩니다.", + "apiKeySetPlaceholder": "••••••(저장됨 · 비워두면 유지)", + "saveConfig": "Pi 설정 저장", + "providerModelRequired": "제공자와 모델은 필수입니다", + "runtimeTitle": "런타임", + "runtimeDescription": "어떤 pi를 실행할지 선택합니다. 기본값을 사용하거나 자신의 pi 빌드를 지정하세요.", + "modeDefault": "기본 pi", + "modeDefaultHint": "내장 pi-acp 어댑터로 PATH의 pi를 실행합니다. pi 설치: npm install -g @earendil-works/pi-coding-agent", + "modeCustom": "사용자 지정 pi", + "modeCustomHint": "자신의 pi 빌드, 설치 또는 래퍼를 실행합니다.", + "commandLabel": "pi 명령 또는 경로", + "commandHint": "절대 경로, PATH의 명령 이름 또는 래퍼 스크립트(예: 모노레포의 ./pi-test.sh).", + "commandNotFound": "명령을 찾을 수 없음", + "validate": "검증", + "advanced": "고급", + "configDirLabel": "설정 디렉터리 (PI_CODING_AGENT_DIR)", + "sessionDirLabel": "세션 디렉터리 (PI_CODING_AGENT_SESSION_DIR)", + "flagsHint": "pi-acp는 사용자 지정 pi 플래그(--approve, -e 등)를 전달하지 않습니다. pi를 스크립트로 감싸고 명령이 이를 가리키도록 하세요.", + "customIncomplete": "저장하려면 pi 명령을 입력하세요", + "saveRuntime": "런타임 저장", + "providerPlaceholder": "제공자 선택", + "customProvider": "사용자 지정 제공자…", + "providerIdLabel": "제공자 ID", + "apiProtocolLabel": "API 프로토콜", + "baseUrlLabel": "API 엔드포인트(Base URL)", + "customProviderHint": "~/.pi/agent/models.json에 엔드포인트용 제공자를 정의합니다. 대부분의 자체 호스팅 또는 프록시 서버는 openai-completions를 사용합니다.", + "baseUrlRequired": "API 엔드포인트(Base URL)는 필수입니다", + "binaryTitle": "pi 바이너리 (pi-coding-agent)", + "binaryDescription": "pi-acp가 이 pi 바이너리를 실행합니다. 여기서 설치하거나 아래에서 직접 빌드한 pi를 지정하세요.", + "binaryInstalled": "설치됨", + "binaryMissing": "설치되지 않음", + "binaryChecking": "확인 중…", + "installBinary": "pi 설치", + "installing": "설치 중…", + "recheck": "다시 확인", + "configDirSkillsNote": "사용자 지정 구성 디렉터리를 설정하면 설정에서 관리하는 스킬, 전문가, 오피스 도구가 이 pi에 적용되지 않습니다. 해당 폴더에서 스킬을 직접 관리하세요.", + "projectTrustTitle": "프로젝트 신뢰", + "projectTrustDescription": "pi가 프로젝트 파일을 불러오도록 허용한 폴더입니다. 신뢰한 폴더에서는 해당 저장소의 .pi/extensions가 pi 시작 시 코드를 실행하며, 그 아래 모든 폴더에 적용되고 터미널에서 pi를 실행할 때에도 사용됩니다.", + "projectTrustLoading": "불러오는 중…", + "projectTrustEmpty": "아직 결정한 폴더가 없습니다.", + "projectTrustTrusted": "신뢰함", + "projectTrustDenied": "신뢰 안 함", + "projectTrustRevoke": "취소", + "reasoningTitle": "추론", + "reasoningEnableLabel": "사용", + "reasoningDescription": "모델이 추론 기능을 선언한 경우에만 pi가 추론 강도를 보냅니다. 선언하지 않은 모델은 모든 단계가 Off로 고정되어, 입력창의 선택기가 건드리는 즉시 되돌아갑니다. models.json의 해당 모델 항목에 기록됩니다.", + "levelsLabel": "선택 가능한 단계", + "levelsHint": "입력창 추론 선택기의 항목이 됩니다. 엔드포인트가 받아들이는 값을 고르세요. 여기 없는 단계는 pi가 거부합니다.", + "levelsEmptyError": "단계를 하나 이상 선택하세요. 하나도 없으면 pi는 Off로 되돌아갑니다.", + "wireValuesTitle": "고급: 공급자에게 보내는 값", + "wireValuesHint": "비워 두면 단계 이름을 그대로 보냅니다. 엔드포인트가 다른 표기를 요구할 때만 설정하세요 — Google 계열은 LOW / HIGH가 필요합니다.", + "defaultLevelUnlisted": "이 단계는 위 선택 목록에 없습니다 — pi가 낮춰 버립니다." + }, + "addCustomAgent": "사용자 지정 에이전트 추가", + "addCustomAgentHint": "ACP를 지원하는 모든 에이전트를 등록할 수 있습니다. 공개 ACP 레지스트리에서 선택하거나 레지스트리 정보를 붙여넣으세요.", + "customAgentFromRegistry": "ACP 레지스트리", + "customAgentManual": "직접 입력", + "customAgentSearchPlaceholder": "에이전트 검색…", + "customAgentLoadingCatalog": "ACP 레지스트리를 불러오는 중…", + "customAgentRetry": "다시 시도", + "customAgentNoResults": "일치하는 에이전트가 없습니다", + "customAgentAdd": "추가", + "customAgentAlreadyAdded": "추가됨", + "customAgentUnsupportedPlatform": "이 플랫폼용 빌드가 없습니다", + "customAgentAdded": "{name} 추가됨", + "customAgentIdLabel": "레지스트리 ID", + "customAgentNameLabel": "표시 이름", + "customAgentVersionLabel": "버전", + "customAgentSpecLabel": "배포 정보(JSON)", + "customAgentSpecHint": "ACP 레지스트리의 distribution 객체와 동일한 형식입니다. npx·uvx·binary 채널을 지원하며 레지스트리 항목 전체를 붙여넣어도 됩니다. npx/uvx의 cmd는 패키지가 설치하는 실행 명령 이름으로, 생략하면 패키지 이름에서 유도되므로 서로 다를 때는 지정하세요. binary는 플랫폼 키로 구분하며(이 컴퓨터: {platform}) cmd는 아카이브 내 실행 경로, sha256은 선택 사항으로 다운로드를 검증합니다.", + "customAgentTemplateLabel": "템플릿", + "customAgentKindLabel": "실행 방식", + "customAgentInvalidJson": "올바른 JSON이 아닙니다", + "customAgentNoDistribution": "npx, uvx, binary 배포를 찾을 수 없습니다", + "customAgentCancel": "취소", + "customAgentSave": "에이전트 추가", + "customAgentSaveChanges": "변경 사항 저장", + "customAgentEdit": "에이전트 편집", + "customAgentEditHint": "이름, 아이콘, 배포 정보, 스킬 선언을 수정할 수 있습니다. 에이전트 ID는 변경할 수 없습니다.", + "customAgentEditNotFound": "커스텀 에이전트 {id}을(를) 찾을 수 없습니다", + "customAgentSaved": "{name} 저장됨", + "customAgentVersionProbeLabel": "버전 조회 명령(선택)", + "customAgentVersionProbeHint": "로컬에 설치된 버전을 출력하는 명령입니다. 비워 두면 에이전트 명령에 --version을 붙여 실행합니다.", + "customAgentRemove": "에이전트 제거", + "customAgentRemoveHint": "에이전트 정의를 삭제합니다. 기존 대화 기록은 유지되며 에이전트를 더 이상 실행할 수 없게 될 뿐입니다.", + "customAgentIconLabel": "아이콘(선택)", + "customAgentIconUpload": "업로드", + "customAgentIconReplace": "변경", + "customAgentIconClear": "아이콘 제거", + "customAgentIconHint": "에이전트와 함께 저장되어 오프라인에서도 표시됩니다. 지정하지 않으면 색상 이니셜을 사용합니다.", + "customAgentSkillsLabel": "Skills(공유 .agents/skills)", + "customAgentSkillsHint": "이 에이전트가 공유 .agents/skills 디렉터리(전역 및 프로젝트)를 읽는다고 선언하고 모든 스킬 매트릭스에 추가합니다. 공유 디렉터리에 연결된 스킬은 해당 디렉터리를 읽는 다른 에이전트에게도 보입니다.", + "customAgentSkillsDirLabel": "전용 스킬 디렉터리", + "customAgentSkillsDirHint": "이 에이전트가 스킬을 불러오는 디렉터리의 절대 경로입니다. 공유 저장소와 함께 또는 단독으로 사용할 수 있습니다. ~ 는 홈 디렉터리로 확장되며, 연결된 스킬은 이 디렉터리에 우선 배치됩니다.", + "customAgentMcpLabel": "MCP 지원", + "customAgentMcpHint": "세션을 시작할 때 codeg 내장 codeg-mcp 동반 프로세스를 이 에이전트에 전달합니다. 위임, 실시간 피드백, 작업 도구가 이 채널을 사용합니다. MCP 서버를 거부해 연결에 실패하는 에이전트라면 꺼 두세요. 변경은 다음 연결부터 적용됩니다.", + "customAgentIconNotAnImage": "이미지 파일을 선택하세요.", + "customAgentIconTooLarge": "아이콘은 {limit} KB 미만이어야 합니다.", + "customAgentIconReadFailed": "해당 이미지를 읽을 수 없습니다.", + "customAgentRemoveConfirm": "{name}을(를) 제거할까요? 기존 대화는 유지되지만 더 이상 실행할 수 없습니다.", + "customAgentRemoveWithData": "기록된 대화 기록도 삭제", + "customAgentRemoved": "{name} 제거됨", + "customAgentBadge": "사용자 지정", + "customAgentNotLaunchable": "이 환경에서는 실행할 수 없습니다: {reason}" + }, + "SettingsPages": { + "agentsLoading": "에이전트 설정을 불러오는 중...", + "skillPacksLoading": "스킬 팩 로딩 중…" + }, + "GeneralSettings": { + "loading": "로딩 중...", + "sectionTitle": "일반", + "sectionDescription": "기본 터미널, 렌더링 가속, 다중 에이전트 위임 등 공용 환경설정을 한곳에서 관리합니다.", + "terminalTitle": "기본 터미널", + "terminalDescription": "터미널 바나 파일 트리에서 새 터미널 탭을 열 때 사용할 셸을 선택합니다. 에이전트가 codeg에 전체 명령줄 실행을 요청할 때도 사용됩니다.", + "terminalSystemDefault": "시스템 기본값", + "terminalPowerShell7": "PowerShell 7 (pwsh)", + "terminalWindowsPowerShell": "Windows PowerShell", + "terminalCmd": "명령 프롬프트 (cmd)", + "terminalSaveFailed": "터미널 설정 저장 실패: {message}", + "terminalShellCustom": "사용자 지정 경로", + "terminalShellCustomPath": "Shell 경로", + "terminalShellCustomPlaceholder": "/usr/local/bin/fish", + "terminalShellCustomSave": "저장", + "terminalShellCustomHint": "절대 경로 또는 PATH에서 찾을 수 있는 명령 이름을 입력하세요.", + "terminalShellNotInstalled": "설치되지 않음", + "terminalShellNotFoundWarning": "이 경로는 현재 호스트에 존재하지 않습니다.", + "terminalCurrentShell": "현재 사용 중: {path}", + "renderingDescription": "앱이 검은 화면이 되거나 렌더링 문제가 발생하면(일부 AMD GPU 또는 Intel 내장 GPU에서 보고됨) 하드웨어 가속을 끄세요. Windows 데스크톱에서만 적용됩니다.", + "disableHardwareAcceleration": "하드웨어 가속 비활성화", + "renderingSaveFailed": "렌더링 설정 저장 실패: {message}", + "restartRequired": "저장되었습니다. 변경 사항을 적용하려면 앱을 다시 시작하세요.", + "restartNow": "지금 다시 시작", + "restartFailed": "다시 시작 실패: {message}", + "loadFailed": "불러오기 실패: {message}" + }, + "LoginPage": { + "documentTitle": "로그인 - codeg", + "brand": "Codeg", + "subtitle": "데스크톱 앱에 연결하려면 액세스 토큰을 입력하세요", + "tokenPlaceholder": "액세스 토큰", + "connect": "연결", + "connecting": "연결 중...", + "helpText": "토큰은 데스크톱 앱의 설정 → 웹 서비스에서 확인할 수 있습니다", + "invalidToken": "유효하지 않은 토큰입니다. 확인 후 다시 시도하세요", + "connectionFailed": "연결 실패 (HTTP {status})", + "networkError": "서버에 연결할 수 없습니다" + }, + "CommitPage": { + "title": "커밋", + "invalidFolderId": "유효하지 않은 폴더 ID", + "loadingRepo": "저장소를 불러오는 중..." + }, + "MergePage": { + "title": "충돌 해결", + "invalidFolderId": "잘못된 폴더 ID", + "loadingRepo": "저장소 로딩 중...", + "localVersion": "로컬 (우리 쪽)", + "result": "결과", + "remoteVersion": "원격 (상대 쪽)", + "acceptLocal": "로컬 적용", + "acceptRemote": "원격 적용", + "markResolved": "해결됨으로 표시", + "abortMerge": "중단", + "completeMerge": "병합 완료", + "unresolvedConflicts": "파일에 아직 해결되지 않은 충돌 마커가 있습니다", + "fileResolved": "파일이 해결되었습니다", + "allResolved": "모든 충돌이 해결되었습니다", + "conflictFiles": "충돌 파일", + "loadingFile": "파일 로딩 중...", + "preparingMerge": "병합 준비 중...", + "selectFile": "해결할 파일을 선택하세요", + "noConflicts": "충돌 파일 없음", + "skipFile": "건너뛰기", + "abortSuccess": "작업이 중단되었습니다", + "applyAllNonConflicting": "충돌하지 않는 모든 변경 적용", + "applyLeftNonConflicting": "로컬 적용", + "applyRightNonConflicting": "원격 적용" + }, + "ImportSessions": { + "title": "로컬 세션 가져오기", + "scanningTitle": "로컬 에이전트 세션 검색 중…", + "scanningHint": "각 에이전트의 로컬 세션 저장소를 탐색하고 있습니다. 기록이 많으면 시간이 걸릴 수 있습니다. 이미 가져온 세션은 이 과정에서 함께 갱신됩니다.", + "scanFailed": "검색 실패", + "retry": "다시 시도", + "rescan": "다시 검색", + "empty": "로컬 세션을 찾을 수 없습니다", + "emptyHint": "이 컴퓨터에서 에이전트 세션 저장소를 찾지 못했습니다.", + "noMatches": "현재 필터와 일치하는 세션이 없습니다", + "searchPlaceholder": "제목 또는 경로 검색…", + "allAgents": "모든 에이전트", + "onlyImportable": "가져오기 가능만", + "selectAll": "모두 선택", + "clearSelection": "지우기", + "expandAll": "모두 펼치기", + "collapseAll": "모두 접기", + "summaryCounts": "세션 {total}개 · 가져오기 가능 {importable}개 · 폴더 {folders}개", + "noFolderSkipped": "프로젝트 폴더가 없는 {count}개 건너뜀", + "folderNew": "신규", + "folderCounts": "가져오기 가능 {importable}/{total}", + "toggleFolderAria": "{name}의 가져오기 가능한 세션 모두 선택", + "toggleSessionAria": "세션 {title} 선택", + "statusImported": "가져옴", + "statusDeleted": "삭제됨", + "untitled": "제목 없는 세션", + "messageCount": "메시지 {count}개", + "selectedCount": "{count}개 선택됨", + "importSelected": "선택 항목 가져오기", + "importing": "가져오는 중…", + "close": "닫기", + "doneTitle": "가져오기 완료", + "doneImported": "가져옴", + "doneUpdated": "갱신됨", + "doneSkipped": "건너뜀", + "doneCreatedFolders": "생성된 폴더", + "doneNotFound": "찾을 수 없음", + "doneFailed": "실패", + "continueImport": "계속 가져오기", + "toasts": { + "importFailed": "가져오기 실패: {message}" + } + }, + "Folder": { + "workspaceStatus": { + "degradedTitle": "실시간 업데이트를 사용할 수 없음", + "degradedHint": "감시자 시작 실패(권한 거부 등). 최신 변경 사항을 보려면 수동으로 새로 고치세요.", + "retry": "다시 시도", + "retrying": "다시 시도 중..." + }, + "common": { + "all": "전체", + "cancel": "취소", + "close": "닫기", + "closeOthers": "다른 항목 닫기", + "closeAll": "모두 닫기", + "confirm": "확인", + "save": "저장", + "delete": "삭제", + "rename": "이름 변경", + "loading": "로딩 중...", + "refresh": "새로고침", + "refreshing": "새로고침 중...", + "create": "생성", + "createAndSwitch": "생성 후 전환", + "openFile": "파일 열기", + "viewDiff": "Diff 보기", + "push": "푸시..." + }, + "statusLabels": { + "in_progress": "진행 중", + "pending_review": "검토", + "completed": "완료", + "cancelled": "취소됨" + }, + "sidebar": { + "title": "대화", + "locateActiveConversation": "활성 대화 찾기", + "expandAllGroups": "모든 그룹 펼치기", + "collapseAllGroups": "모든 그룹 접기", + "newConversation": "새 대화", + "newConversationShort": "새로 만들기", + "newChat": "새 대화", + "search": "검색", + "noConversationsFound": "대화를 찾을 수 없습니다.", + "importLocalSessions": "로컬 세션 가져오기", + "importing": "가져오는 중...", + "error": "오류: {message}", + "completeAllSessions": "모든 세션 완료 처리", + "completeAllReviewTitle": "모든 검토 세션을 완료 처리할까요?", + "completeAllReviewDescription": "검토 상태의 {count, plural, one {#개 세션} other {#개 세션}}을 모두 완료로 표시합니다.", + "completing": "완료 처리 중...", + "toasts": { + "importedSessions": "{imported, plural, one {#개 세션} other {#개 세션}}을 가져오고 {skipped}개를 건너뛰었습니다", + "importedAndUpdated": "{imported, plural, one {#개 세션} other {#개 세션}}을 가져오고 {updated, plural, one {#개 제목} other {#개 제목}}을 업데이트하고 {skipped}개를 건너뛰었습니다", + "updatedTitles": "{updated, plural, one {#개 제목} other {#개 제목}}을 업데이트하고 {skipped}개를 건너뛰었습니다", + "noNewSessionsFound": "새 세션이 없습니다 ({skipped}개 건너뜀)", + "importFailed": "가져오기 실패: {message}", + "reviewCompleted": "{count, plural, one {#개 검토 세션} other {#개 검토 세션}}을 완료로 표시했습니다", + "completeReviewFailed": "검토 세션 완료 처리 실패: {message}", + "folderOpened": "폴더 {name}을(를) 열었습니다", + "folderRemoved": "폴더 {name}을(를) 제거했습니다", + "openFolderFailed": "폴더를 열 수 없습니다", + "removeFolderFailed": "폴더 제거 실패: {message}", + "reorderFoldersFailed": "폴더 순서 변경 실패: {message}", + "changeFolderColorFailed": "색상 변경 실패: {message}", + "setFolderAliasFailed": "별칭 설정 실패: {message}", + "changeFolderDefaultAgentFailed": "기본 에이전트 설정 실패: {message}" + }, + "statsLabel": "{folders}개 폴더 · {convos}개 대화", + "reorderHandle": "드래그하여 순서 변경", + "openFolder": "폴더 열기", + "searchPlaceholder": "대화 검색...", + "viewOptions": "보기 옵션", + "showCompleted": "완료된 대화 표시", + "showWorktrees": "워크트리 폴더 표시", + "showRecent": "'최근' 그룹 표시", + "moreOptions": "더 많은 옵션", + "sortBy": "정렬 기준", + "sortByCreatedAt": "생성 시간순", + "sortByUpdatedAt": "업데이트 시간순", + "sectionOrder": "섹션 순서", + "sectionOrderMoveUp": "위로 이동", + "sectionOrderMoveDown": "아래로 이동", + "sectionOrderItemLabel": "{name} — {total}개 중 {position}번째", + "statusRunningBadge": "실행 중", + "runningCountBadge": "{count}개 세션 실행 중", + "statusCancelledBadge": "취소됨", + "worktreeRemovedBadge": "원본 worktree가 삭제됨", + "conversationCountUnit": "{count}개", + "emptyFolderHint": "대화 없음", + "noMatchingConversations": "일치하는 대화가 없습니다", + "noUnfinishedConversations": "미완료 대화가 없습니다. 오른쪽 상단 메뉴에서 \"완료된 대화 표시\"를 활성화할 수 있습니다.", + "removeFolderConfirmTitle": "이 폴더를 워크스페이스에서 제거하시겠습니까?", + "removeFolderConfirmDescription": "워크스페이스에서 \"{name}\"을(를) 제거하시겠습니까? 관련 탭과 터미널이 닫힙니다.", + "folderHeaderMenu": { + "manageConversations": "대화 관리…", + "manageLinks": "연결된 폴더", + "changeColor": "색상 변경", + "useThemeColor": "앱 테마 사용", + "setDefaultAgent": "기본 에이전트 설정", + "defaultAgentNone": "설정 없음(전역 사용)", + "agentUnavailableSuffix": "(사용 불가)", + "loadingAgents": "에이전트 로드 중…", + "setAlias": "별칭 설정…", + "setAliasTitle": "폴더 별칭 설정", + "setAliasPlaceholder": "별칭 입력 (비우면 지움)", + "setAliasSave": "저장", + "setAliasCancel": "취소", + "removeFromWorkspace": "워크스페이스에서 제거" + }, + "manageConversations": { + "title": "대화 관리", + "searchPlaceholder": "제목으로 검색…", + "agentFilterAll": "모든 에이전트", + "statusFilterAll": "모든 상태", + "folderFilterAll": "모든 폴더", + "branchFilterAll": "모든 브랜치", + "branchNone": "브랜치 없음", + "branchSearchPlaceholder": "브랜치 검색…", + "noMatchingBranches": "일치하는 브랜치가 없습니다", + "selectAllVisible": "전체 선택", + "deselectAll": "선택 해제", + "selectedCount": "{count}개 선택됨", + "matchedCount": "{count}개 일치", + "untitledConversation": "제목 없는 대화", + "setStatus": "상태 변경…", + "deleteSelected": "삭제", + "noConversations": "이 폴더에 대화가 없습니다.", + "noConversationsWorkspace": "작업 공간에 대화가 없습니다.", + "noMatchingConversations": "필터에 일치하는 대화가 없습니다.", + "confirmDeleteTitle": "{count}개 대화를 삭제하시겠습니까?", + "confirmDeleteDescription": "이 작업은 되돌릴 수 없습니다.", + "toastDeleted": "{count}개 대화를 삭제했습니다", + "toastStatusUpdated": "{count}개 대화의 상태를 업데이트했습니다", + "toastOpFailed": "작업 실패: {message}" + }, + "sectionPinned": "고정됨", + "sectionFolders": "폴더", + "sectionChats": "채팅", + "sectionRecent": "최근", + "noChats": "채팅 없음", + "noRecent": "최근 대화 없음", + "showMoreRecent": "더 보기 ({count})", + "noFolders": "열린 폴더 없음", + "newChatAction": "새 채팅", + "automations": "자동화", + "tasks": "할 일", + "loadingSubsessions": "하위 대화 로드 중…" + }, + "conversation": { + "reloadFailed": "대화 다시 불러오기 실패: {message}", + "reloaded": "대화를 다시 불러왔습니다", + "reload": "다시 불러오기", + "activeConversationIndicator": "활성 대화", + "newConversation": "새 대화", + "closeConversation": "대화 닫기", + "copyText": "텍스트 복사", + "copyTextSuccess": "복사됨", + "copyTextFailed": "복사 실패", + "forkSession": "세션 포크", + "forkSessionSuccess": "세션 포크 성공", + "forkSessionFailed": "세션 포크 실패: {error}", + "exportConversation": "대화 내보내기", + "exportImage": "이미지", + "exportMarkdown": "Markdown", + "exportHtml": "HTML", + "exportSuccess": "대화를 내보냈습니다", + "exportFailed": "내보내기 실패", + "exportImageTooLong": "대화가 너무 길어 이미지로 내보낼 수 없습니다", + "exportLabels": { + "untitledConversation": "제목 없는 대화", + "agent": "에이전트", + "model": "모델", + "status": "상태", + "started": "시작", + "updated": "업데이트", + "tokens": "토큰 통계", + "duration": "소요 시간", + "inputTokens": "입력", + "outputTokens": "출력", + "cacheRead": "캐시 읽기", + "cacheWrite": "캐시 쓰기", + "user": "사용자", + "assistant": "어시스턴트", + "system": "시스템", + "toolResult": "결과", + "toolError": "오류" + }, + "moreActions": "추가 작업" + }, + "sessionDetails": { + "menuLabel": "세션 세부 정보", + "noActiveSession": "활성 세션이 없습니다", + "title": "세션 세부 정보", + "subtitle": "세션 메타데이터 및 토큰 사용량", + "fieldTitle": "제목", + "untitled": "제목 없는 대화", + "sessionId": "세션 ID", + "externalId": "확장 ID", + "agent": "에이전트", + "model": "모델", + "status": "상태", + "gitBranch": "Git 브랜치", + "parentId": "상위 세션", + "tokensHeading": "토큰 사용량", + "totalTokens": "합계", + "inputTokens": "입력", + "outputTokens": "출력", + "cacheWrite": "캐시 쓰기", + "cacheRead": "캐시 읽기", + "contextWindow": "컨텍스트 창", + "duration": "소요 시간", + "loadingStats": "토큰 사용량 불러오는 중…", + "loadFailed": "토큰 사용량을 불러오지 못했습니다", + "noStats": "사용량 기록 없음", + "timestampsHeading": "타임스탬프", + "createdAt": "생성됨", + "updatedAt": "업데이트됨", + "none": "—", + "copyField": "{field} 복사", + "copiedField": "{field} 복사됨" + }, + "conversationCard": { + "untitledConversation": "제목 없는 대화", + "newConversation": "새 대화", + "rename": "이름 변경", + "status": "상태", + "delete": "삭제", + "importLocalSessions": "로컬 세션 가져오기", + "importing": "가져오는 중...", + "renameConversation": "대화 이름 변경", + "deleteConversationTitle": "대화를 삭제할까요?", + "deleteConversationDescription": "\"{title}\"을(를) 삭제합니다. 이 작업은 되돌릴 수 없습니다.", + "cancel": "취소", + "save": "저장", + "pin": "고정", + "unpin": "고정 해제", + "markCompleted": "완료로 표시", + "reopen": "다시 열기", + "expandSubsessions": "하위 대화 펼치기", + "collapseSubsessions": "하위 대화 접기" + }, + "search": { + "dialogTitle": "검색", + "dialogTitleWithFolder": "검색 — {name}", + "tabConversations": "대화", + "tabFiles": "파일", + "placeholder": "대화 검색...", + "filePlaceholder": "파일 또는 디렉토리 검색...", + "allAgents": "전체", + "searching": "검색 중...", + "typeToSearch": "입력하여 대화를 검색하세요", + "typeToSearchFiles": "입력하여 파일 또는 디렉토리를 검색하세요", + "noResults": "검색 결과가 없습니다.", + "untitledConversation": "제목 없는 대화" + }, + "folderTitleBar": { + "showSidebar": "사이드바 표시", + "hideSidebar": "사이드바 숨기기", + "toggleTerminal": "터미널 전환", + "toggleAuxPanel": "보조 패널 전환", + "search": "검색", + "openSettings": "설정 열기", + "backToConversations": "대화로 돌아가기", + "withShortcut": "{label} ({shortcut} 단축키)" + }, + "statusBar": { + "connection": { + "connected": "연결됨", + "connecting": "연결 중...", + "prompting": "응답 중...", + "error": "연결 오류", + "disconnected": "연결 끊김", + "tooltip": "{agent}: {status}", + "tooltipError": "{agent}: {error}", + "title": "에이전트 연결", + "triggerAria": "에이전트 연결: {status}", + "workingDir": "작업 디렉터리", + "sessionId": "세션 ID", + "viewerNote": "다른 클라이언트가 소유한 세션에 연결되어 있습니다. 다시 연결해도 이 보기만 다시 연결됩니다.", + "reconnectInterrupts": "다시 연결하면 에이전트가 재시작되어 진행 중인 작업이 중단됩니다.", + "reconnect": "다시 연결", + "reconnecting": "다시 연결하는 중...", + "reconnectUnavailable": "아직 다시 연결할 세션이 없습니다." + }, + "tasks": { + "title": "작업" + }, + "alerts": { + "title": "알림", + "empty": "알림 없음", + "details": "세부 정보" + }, + "stats": { + "conversations": "{count}개 대화", + "openUsage": "세션 통계 및 토큰 사용량 보기" + }, + "tokens": { + "contextWindowUsageAria": "컨텍스트 윈도우 사용량", + "contextWindow": "컨텍스트 윈도우", + "usedMax": "사용 / 최대", + "tokenUsage": "토큰 사용량", + "input": "입력", + "output": "출력", + "cacheRead": "캐시 읽기", + "cacheWrite": "캐시 쓰기", + "total": "합계" + } + }, + "auxPanel": { + "tabs": { + "files": "파일", + "changes": "변경사항", + "commits": "커밋" + }, + "noFolderTitle": "열린 폴더 없음", + "noFolderHint": "폴더를 열면 여기에 표시됩니다" + }, + "windowControls": { + "minimizeWindow": "창 최소화", + "minimize": "최소화", + "maximizeWindow": "창 최대화", + "maximize": "최대화", + "restoreWindow": "창 복원", + "restore": "복원", + "closeWindow": "창 닫기", + "close": "닫기" + }, + "tabs": { + "closeConversationTab": "대화 탭 닫기", + "close": "닫기", + "closeOthers": "다른 항목 닫기", + "splitRight": "오른쪽으로 분할", + "splitDown": "아래로 분할", + "splitAndMoveRight": "분할하고 오른쪽으로 이동", + "splitAndMoveDown": "분할하고 아래로 이동", + "moveToOppositeGroup": "반대쪽 그룹으로 이동", + "moveToGroup": "그룹으로 이동", + "groupLabel": "그룹 {index}", + "changeSplitterOrientation": "분할 방향 전환", + "unsplit": "분할 해제", + "unsplitAll": "모든 분할 해제", + "closeAll": "모두 닫기", + "tileDisplay": "타일 표시", + "untileDisplay": "타일 해제" + }, + "fileWorkspace": { + "files": "파일", + "closeFileTab": "파일 탭 닫기", + "close": "닫기", + "closeOthers": "다른 항목 닫기", + "closeAll": "모두 닫기", + "preview": "미리보기", + "editSource": "소스 편집", + "maximize": "최대화", + "restore": "복원", + "emptyDirectory": "빈 폴더" + }, + "terminal": { + "rename": "이름 변경", + "close": "닫기", + "closeOthers": "다른 항목 닫기", + "closeAll": "모두 닫기", + "hideTerminal": "터미널 숨기기 ({shortcut})", + "openFolderFirst": "먼저 폴더를 여세요" + }, + "workspaceDialog": { + "title": "폴더 열기", + "manageTitle": "연결된 폴더", + "addTargetsTitle": "연결할 폴더 추가", + "pickRootDescription": "이 작업 공간의 기본 폴더를 선택하세요.", + "linksDescription": "다른 폴더를 하위 디렉터리로 연결하면 에이전트가 하나의 작업 공간에서 여러 프로젝트를 함께 다룰 수 있습니다.", + "addTargetsDescription": "폴더를 하나 이상 선택하세요. 각각 작업 공간의 하위 디렉터리가 됩니다.", + "useSystemPicker": "시스템 선택기", + "next": "다음", + "back": "뒤로", + "done": "완료", + "change": "변경", + "addFolders": "폴더 추가", + "addSelected": "추가", + "addSelectedCount": "{count}개 추가", + "createCount": "폴더 {count}개 연결", + "discardPending": "취소", + "noLinks": "아직 연결된 폴더가 없습니다.", + "gitExclude": "연결을 git 상태에 노출하지 않기", + "rename": "이름 변경", + "unlink": "연결 해제", + "repair": "연결 다시 만들기", + "saveName": "저장", + "cancelRename": "취소", + "removePending": "제거", + "willAppearAs": "작업 공간에서 {name}(으)로 표시됩니다", + "renamedForDuplicate": "이름이 변경됨 — {base}은(는) 다른 연결이 사용 중입니다", + "renamedForExistingEntry": "이름이 변경됨 — 이 폴더에 이미 {base}이(가) 있습니다", + "partiallyCreated": "폴더 {count}개만 연결되었습니다", + "openFailed": "폴더를 열지 못했습니다", + "previewFailed": "선택한 폴더를 확인하지 못했습니다", + "createFailed": "폴더를 연결하지 못했습니다", + "renameFailed": "이름을 변경하지 못했습니다", + "removeFailed": "연결을 해제하지 못했습니다", + "repairFailed": "연결을 다시 만들지 못했습니다", + "status": { + "ok": "연결됨", + "missing": "이 폴더에서 링크가 사라졌습니다", + "conflicted": "다른 항목이 이 이름을 사용 중입니다", + "broken": "연결된 폴더가 더 이상 존재하지 않습니다" + }, + "nameIssue": { + "empty": "이름을 입력하세요", + "illegalChars": "/ \\ : * ? \" < > | 는 사용할 수 없습니다", + "tooLong": "이름이 너무 깁니다", + "reserved": "Windows 예약어입니다", + "duplicate": "이미 사용 중인 이름입니다" + }, + "rejection": { + "not_found": "폴더를 찾을 수 없습니다", + "not_a_directory": "이 경로는 폴더가 아닙니다", + "same_as_root": "작업 공간 폴더 자신입니다", + "ancestor_of_root": "이 폴더가 작업 공간을 포함합니다", + "inside_root": "이미 작업 공간 안에 있습니다", + "already_linked": "이미 연결되어 있습니다", + "name_unavailable": "이 폴더에 사용할 수 있는 이름이 없습니다", + "alreadyLinkedAs": "{name}(으)로 이미 연결되어 있습니다" + } + }, + "folderNameDropdown": { + "fallbackFolderName": "폴더", + "openFolder": "폴더 열기", + "cloneRepository": "리포지토리 클론", + "projectBoot": "프로젝트 부트", + "opened": "열린 항목", + "recentOpen": "최근 연 항목" + }, + "fileWorkspacePanel": { + "addSelectionToChat": "선택 영역을 대화에 추가", + "addToChat": "대화에 추가", + "addSelectionToChatDone": "{label}을(를) 대화에 추가했습니다", + "addFileToChat": "파일을 대화에 추가", + "toggleWordWrap": "자동 줄 바꿈 전환", + "addFileToChatDone": "{label}을(를) 대화에 추가했습니다", + "viewDiff": "Diff 보기", + "openFile": "파일 열기", + "fileCount": "{count, plural, one {#개 파일} other {#개 파일}}", + "openFileOrDiff": "오른쪽 패널에서 파일 또는 diff를 여세요", + "disk": "디스크", + "head": "HEAD", + "unsaved": "저장되지 않음", + "workingTree": "작업 트리", + "loading": "로딩 중...", + "compareWithBranch": "{path} · {branch}와 비교", + "hunkCount": "{count, plural, one {#개 hunk} other {#개 hunks}}", + "prev": "이전", + "next": "다음", + "jumpToLine": "{line}행으로 이동", + "noParsedDiffSections": "파싱된 diff 섹션이 없습니다", + "loadingEditor": "에디터 로딩 중...", + "imageZoomIn": "확대", + "imageZoomOut": "축소", + "imageZoomReset": "확대/축소 초기화", + "htmlPreviewTitle": "HTML 미리보기", + "htmlPreviewTrust": "스크립트 사용", + "htmlPreviewTrustHint": "이 파일의 스크립트를 실행하고 네트워크 접근을 허용합니다. 신뢰할 수 있는 파일에서만 사용하세요.", + "officePreviewTitle": "Office 문서 미리보기", + "officeFullRender": "전체 렌더링", + "officeFullRenderHint": "Morph 애니메이션, 3D, 수식을 렌더링합니다(슬라이드 자체 스크립트 실행).", + "officeNotInstalled": "OfficeCLI가 설치되지 않았습니다", + "officeNotInstalledHint": "설정 → Office 도구에서 OfficeCLI를 설치하면 Word, Excel, PowerPoint 파일을 미리볼 수 있습니다.", + "officeOpenSettings": "설정 열기", + "officeWatchFailed": "실시간 미리보기를 시작할 수 없습니다", + "officeWatchRetry": "다시 시도", + "officeServerInstallHint": "OfficeCLI는 서버 호스트에 설치해야 합니다. 서버에서 다음 명령을 실행한 후 다시 시도하세요:", + "officeRemoteDesktopUnsupported": "원격 데스크톱 창에서는 실시간 미리보기를 사용할 수 없습니다. Office 파일을 미리 보려면 서버의 웹 UI에서 이 작업 공간을 여세요." + }, + "branchDropdown": { + "toasts": { + "commitCodeCompleted": "코드 커밋이 완료되었습니다", + "pushCodeCompleted": "코드 푸시가 완료되었습니다", + "committedFiles": "{count, plural, one {#개 파일 커밋됨} other {#개 파일 커밋됨}}", + "taskCompleted": "{label} 완료", + "taskFailed": "{label} 실패", + "mergeNoNewCommits": "{branchName}에는 새 커밋이 없습니다", + "mergedCommits": "{count, plural, one {#개 커밋 병합됨} other {#개 커밋 병합됨}}", + "allFilesUpToDate": "모든 파일이 최신 상태입니다", + "updatedFiles": "{count, plural, one {#개 파일 업데이트됨} other {#개 파일 업데이트됨}}", + "openCommitWindowFailed": "커밋 창을 열지 못했습니다", + "openPushWindowFailed": "푸시 창 열기 실패", + "upstreamSet": "업스트림 브랜치가 설정되었습니다", + "upstreamSetAndPushed": "업스트림 브랜치를 설정하고 {count, plural, one {#개 커밋} other {#개 커밋}}을 푸시했습니다", + "noCommitsToPush": "푸시할 커밋이 없습니다", + "pushedCommits": "{count, plural, one {#개 커밋 푸시됨} other {#개 커밋 푸시됨}}", + "switchedToFolder": "{name}(으)로 전환했습니다", + "switchFailed": "브랜치 전환에 실패했습니다", + "openStashWindowFailed": "스태시 창을 열지 못했습니다" + }, + "tasks": { + "newBranch": "브랜치 {name} 생성", + "newWorktree": "워크트리 {name} 생성", + "checkoutTo": "{branchName}(으)로 체크아웃", + "mergeBranch": "{branchName} 병합", + "rebaseTo": "{branchName}로 리베이스", + "deleteRemoteBranch": "원격 브랜치 {branchName} 삭제", + "initGitRepo": "Git 저장소 초기화", + "pullCode": "코드 pull", + "fetchInfo": "정보 fetch", + "pushCode": "코드 push", + "stashChanges": "변경 사항 stash", + "stashPop": "stash pop", + "deleteBranch": "브랜치 {branchName} 삭제", + "removeWorktree": "{branchName}의 워크트리 삭제", + "removeWorktreeAndBranch": "워크트리 및 브랜치 {branchName} 삭제", + "updateBranch": "브랜치 {branchName} 업데이트" + }, + "confirm": { + "mergeTitle": "브랜치 병합", + "rebaseTitle": "브랜치 리베이스", + "mergeDescription": "{branchName}을(를) 현재 브랜치 {currentBranch}에 병합할까요?", + "rebaseDescription": "현재 브랜치 {currentBranch}를 {branchName} 위로 리베이스할까요?", + "deleteRemoteTitle": "원격 브랜치 삭제", + "deleteRemoteDescription": "원격 브랜치 {branchName}을(를) 삭제하시겠습니까? 이 작업은 원격 저장소에서 브랜치를 제거하며 되돌릴 수 없습니다.", + "deleteTitle": "브랜치 삭제", + "deleteDescription": "브랜치 {branchName}을(를) 삭제할까요? 이 작업은 되돌릴 수 없습니다.", + "forceDeleteTitle": "브랜치 강제 삭제", + "forceDeleteDescription": "브랜치 {branchName}가 완전히 병합되지 않았습니다. 강제 삭제하시겠습니까? 이 작업은 되돌릴 수 없습니다.", + "deleteWorktreeTitle": "워크트리 삭제", + "deleteWorktreeDescription": "{branchName}이(가) 체크아웃된 워크트리 디렉터리를 삭제할까요? 브랜치와 커밋은 유지됩니다.", + "forceDeleteWorktreeTitle": "워크트리 강제 삭제", + "forceDeleteWorktreeDescription": "{branchName}의 워크트리에 커밋되지 않았거나 추적되지 않는 파일이 있습니다. 그래도 삭제할까요? 해당 변경 사항은 복구할 수 없습니다.", + "deleteWorktreeAndBranchTitle": "워크트리 및 브랜치 삭제", + "deleteWorktreeAndBranchDescription": "{branchName}의 워크트리와 브랜치, 그리고 워크스페이스 폴더를 삭제할까요? 그 안의 세션은 저장소 폴더로 이동합니다. 이 작업은 되돌릴 수 없습니다.", + "forceDeleteWorktreeAndBranchTitle": "워크트리 및 브랜치 강제 삭제", + "forceDeleteWorktreeAndBranchDescription": "{branchName}의 워크트리에 커밋되지 않은 파일이 있거나 브랜치가 완전히 병합되지 않았습니다. 그래도 둘 다 삭제할까요? 이 작업은 되돌릴 수 없습니다." + }, + "current": "현재", + "switchToBranch": "이 브랜치로 전환", + "mergeBranchIntoCurrent": "{branchName}을(를) {currentBranch}에 병합", + "rebaseCurrentToBranch": "{currentBranch}를 {branchName}로 리베이스", + "noBranch": "브랜치 없음", + "detachedHead": "분리된 HEAD ({sha})", + "initGitRepo": "Git 저장소 초기화", + "pullCode": "코드 pull", + "fetchRemoteBranches": "원격 브랜치 가져오기", + "openCommitWindow": "코드 커밋...", + "pushCode": "푸시...", + "pushBranch": "푸시", + "newBranch": "새 브랜치...", + "newWorktree": "새 워크트리...", + "stashChanges": "스태시...", + "stashPop": "stash pop...", + "manageRemotes": "원격 관리...", + "localBranches": "로컬 브랜치 ({count, plural, one {#} other {#}})", + "noLocalBranches": "로컬 브랜치가 없습니다", + "remoteBranches": "원격 브랜치 ({count, plural, one {#} other {#}})", + "noRemoteBranches": "원격 브랜치가 없습니다", + "dialogs": { + "newBranchTitle": "새 브랜치", + "newBranchDescription": "현재 브랜치 {branch}에서 새 브랜치를 만듭니다", + "branchNamePlaceholder": "브랜치 이름", + "newWorktreeTitle": "새 워크트리", + "newWorktreeDescription": "현재 브랜치 {branch}에서 새 워크트리를 만듭니다", + "branchNameLabel": "브랜치 이름", + "worktreePathLabel": "워크트리 경로", + "worktreePathPlaceholder": "워크트리 경로", + "manageRemotesTitle": "원격 관리", + "manageRemotesEmpty": "구성된 원격이 없습니다", + "remoteNamePlaceholder": "원격 이름", + "remoteUrlPlaceholder": "원격 URL", + "addRemote": "추가", + "savingRemotes": "저장 중..." + }, + "conflict": { + "title": "병합 충돌", + "description": "다음 파일에 충돌이 있어 해결이 필요합니다:", + "abort": "병합 중단", + "openMergeTool": "병합 도구 열기", + "completeMerge": "병합 완료", + "abortSuccess": "병합이 중단되었습니다", + "completeSuccess": "병합이 완료되었습니다" + }, + "stashDialog": { + "title": "변경 사항 스태시", + "description": "현재 변경 사항을 스태시에 저장", + "messageLabel": "메시지", + "messagePlaceholder": "스태시 메시지 (선택사항)", + "keepIndex": "인덱스 유지 (스테이지된 변경 사항 유지)", + "cancel": "취소", + "stash": "스태시", + "success": "변경 사항이 스태시되었습니다", + "error": "스태시 실패" + }, + "unstashDialog": { + "title": "스태시 적용", + "noStashes": "스태시가 없습니다", + "selectFile": "파일을 선택하여 차이 보기", + "viewDiff": "차이 보기", + "original": "원본", + "modified": "수정됨", + "apply": "적용", + "drop": "삭제", + "applySuccess": "스태시가 적용되었습니다", + "dropSuccess": "스태시가 삭제되었습니다", + "confirmApply": "스태시 {ref}을(를) 작업 디렉토리에 적용하시겠습니까?", + "cancel": "취소" + }, + "deleteBranch": "브랜치 삭제", + "deleteWorktree": "워크트리 삭제", + "deleteWorktreeAndBranch": "워크트리 및 브랜치 삭제", + "searchPlaceholder": "브랜치 및 작업 검색", + "searchAriaLabel": "브랜치 및 작업 검색", + "branchListLabel": "브랜치 및 작업", + "noMatches": "일치하는 항목 없음" + }, + "commitDialog": { + "toasts": { + "commitCompleted": "코드 커밋이 완료되었습니다", + "pushFailed": "푸시 실패", + "committedFiles": "{count, plural, one {#개 파일 커밋됨} other {#개 파일 커밋됨}}", + "addedToVcs": "VCS에 추가되었습니다", + "addToVcsFailed": "VCS에 추가하지 못했습니다", + "fileDeleted": "파일이 삭제되었습니다", + "deleteFailed": "삭제에 실패했습니다", + "fileRolledBack": "파일이 롤백되었습니다", + "rollbackFailed": "롤백에 실패했습니다", + "dirRolledBack": "디렉토리가 롤백되었습니다", + "dirDeleted": "디렉토리가 삭제되었습니다" + }, + "confirm": { + "deleteTitle": "삭제 확인", + "deleteDescription": "파일 \"{file}\"을(를) 삭제할까요? 이 작업은 되돌릴 수 없습니다.", + "rollbackTitle": "롤백 확인", + "rollbackDescription": "파일 \"{file}\"을(를) HEAD로 롤백할까요? 저장되지 않은 변경 사항은 사라집니다.", + "rollbackDirDescription": "디렉토리 \"{dir}\"를 HEAD로 롤백하시겠습니까? 저장되지 않은 변경 사항이 손실됩니다.", + "deleteDirDescription": "디렉토리 \"{dir}\"를 삭제하시겠습니까? 이 작업은 되돌릴 수 없습니다." + }, + "actions": { + "select": "선택", + "unselect": "선택 해제", + "rollback": "롤백", + "addToVcs": "VCS에 추가" + }, + "aria": { + "selectFile": "{action}: {path}", + "unselectAllFiles": "모든 파일 선택 해제", + "selectAllFiles": "모든 파일 선택", + "unselectTracked": "추적된 변경 선택 해제", + "selectTracked": "추적된 변경 선택", + "unselectUntracked": "추적되지 않은 파일 선택 해제", + "selectUntracked": "추적되지 않은 파일 선택" + }, + "loading": "로딩 중...", + "selectionCount": "{selected} / {total}개 파일", + "emptyFiles": "변경된 파일이 없습니다", + "trackedChanges": "추적된 변경 ({count})", + "untrackedFiles": "추적되지 않은 파일 ({count})", + "commitMessage": "커밋 메시지", + "commitMessagePlaceholder": "커밋 메시지 입력...", + "commitButton": "커밋 ({count})", + "commitAndPushButton": "커밋 후 푸시 ({count})", + "head": "HEAD", + "workingTree": "작업 트리", + "clickFileToDiff": "파일 이름을 클릭해 diff를 확인하세요", + "loadingDiff": "diff 로딩 중..." + }, + "pushWindow": { + "title": "코드 푸시", + "noUnpushedCommits": "푸시되지 않은 커밋이 없습니다", + "noRemoteConfigured": "Git 원격이 구성되지 않았습니다\n「원격 관리」에서 원격을 추가하세요", + "newBranchNoPushedCommits": "새 브랜치 — 푸시하여 원격 추적 브랜치 생성", + "unpushed": "미푸시", + "selectFileToViewDiff": "파일을 선택하여 차이 보기", + "before": "변경 전", + "after": "변경 후", + "push": "푸시", + "toasts": { + "pushSuccess": "푸시 성공", + "pushFailed": "푸시 실패", + "upstreamSet": "원격 추적 브랜치가 설정되었습니다", + "upstreamSetAndPushed": "원격 추적 브랜치 설정 및 {count}개 커밋 푸시 완료", + "noCommitsToPush": "푸시할 커밋이 없습니다", + "pushedCommits": "{count}개 커밋 푸시 완료" + } + }, + "gitLogTab": { + "filesTitle": "파일", + "expandAllFiles": "모든 파일 펼치기", + "collapseAllFiles": "모든 파일 접기", + "workspace": "작업 공간", + "retry": "다시 시도", + "noCommitsFound": "커밋을 찾을 수 없습니다", + "notAGitRepoTitle": "Git 저장소가 아닙니다", + "notAGitRepoHint": "위의 브랜치 메뉴에서 Git을 초기화하거나 기존 저장소를 여세요.", + "hash": "해시", + "copyHash": "해시 복사", + "copyMessage": "메시지 복사", + "showMore": "더보기", + "showLess": "접기", + "author": "작성자", + "noFileChangeDetails": "파일 변경 상세 정보가 없습니다.", + "loadingFiles": "파일 로딩 중…", + "branchesTitle": "브랜치", + "loadingBranches": "브랜치 로딩 중...", + "noContainingBranches": "포함하는 브랜치를 찾을 수 없습니다.", + "newBranch": "새 브랜치...", + "resetToHere": "여기로 리셋", + "resetDisabledReasonNotCurrentBranchView": "현재 브랜치 보기에서만 사용할 수 있습니다", + "copyFullCommitHashAria": "전체 커밋 해시 {hash} 복사", + "pushStatus": { + "pushed": "원격에 푸시됨", + "notPushed": "원격에 푸시되지 않음", + "unknown": "푸시 상태 알 수 없음 (upstream 미설정)" + }, + "time": { + "monthsAgo": "{count, plural, one {#개월 전} other {#개월 전}}", + "daysAgo": "{count, plural, one {#일 전} other {#일 전}}", + "hoursAgo": "{count, plural, one {#시간 전} other {#시간 전}}", + "minsAgo": "{count, plural, one {#분 전} other {#분 전}}", + "justNow": "방금 전" + }, + "toasts": { + "createdAndSwitchedNewBranch": "새 브랜치를 생성하고 전환했습니다", + "newBranchFromCommit": "{name} ({shortHash}에서 생성)", + "createBranchFailed": "브랜치 생성에 실패했습니다", + "openPushWindowFailed": "푸시 창을 열지 못했습니다", + "resetSuccess": "리셋 완료", + "resetSuccessDescription": "{branch}을(를) {mode}로 {shortHash}에 리셋했습니다", + "resetFailed": "리셋 실패" + }, + "authorFilter": { + "label": "작성자", + "searchPlaceholder": "작성자 검색", + "noAuthors": "작성자를 찾을 수 없습니다", + "you": "나", + "filterByAuthorAria": "작성자별로 커밋 필터링", + "filterByQuery": "\"{query}\"(으)로 필터링", + "clearAuthorFilterAria": "작성자 필터 지우기", + "recent": "최근", + "matchingAuthors": "일치하는 작성자", + "removeFromRecent": "최근에서 {name} 제거" + }, + "branchSelector": { + "label": "브랜치", + "head": "HEAD", + "headHint": "현재 브랜치를 따라감", + "headHintWithBranch": "현재 브랜치를 따라감 ({branch})", + "searchBranch": "브랜치 검색...", + "noBranches": "브랜치 없음", + "selectBranchPlaceholder": "브랜치 선택...", + "localBranches": "로컬 브랜치", + "current": "현재", + "remoteBranches": "원격 브랜치", + "refreshCommitHistory": "커밋 히스토리 새로고침", + "clearBranchFilterAria": "브랜치 필터 지우기" + }, + "dialogs": { + "newBranchTitle": "새 브랜치", + "newBranchDescription": "커밋 {shortHash}를 최신 커밋으로 하여 새 브랜치를 생성합니다.", + "branchNamePlaceholder": "브랜치 이름", + "reset": { + "title": "현재 브랜치를 이 커밋으로 리셋", + "branchLabel": "브랜치", + "targetLabel": "대상 커밋", + "messageLabel": "커밋 메시지", + "modeLabel": "리셋 모드", + "confirmButton": "리셋", + "modes": { + "soft": { + "label": "--soft", + "description": "HEAD와 현재 브랜치 포인터를 대상 커밋으로 이동합니다.\nIndex와 Working Tree는 변경하지 않습니다.\n되돌려진 커밋의 변경 사항은 staged 상태로 유지됩니다." + }, + "mixed": { + "label": "--mixed (기본값)", + "description": "HEAD를 대상 커밋으로 이동합니다.\nIndex를 대상 커밋으로 되돌리고 Working Tree 변경은 유지합니다.\n변경 사항은 staged에서 unstaged로 바뀝니다." + }, + "hard": { + "label": "--hard", + "description": "HEAD를 이동하고 Index와 Working Tree를 모두 대상 커밋으로 되돌립니다.\n대상 커밋 이후의 추적된 로컬 변경은 삭제됩니다.\n파괴적인 작업입니다." + }, + "keep": { + "label": "--keep", + "description": "HEAD를 대상 커밋으로 이동하면서 가능한 한 로컬 변경을 유지합니다.\n충돌하지 않는 변경만 보존됩니다.\n충돌이 감지되면 작업 보호를 위해 리셋이 중단됩니다." + } + } + } + }, + "moreActions": "추가 Git 작업" + }, + "gitChangesTab": { + "workspace": "작업 공간", + "noChanges": "로컬 변경 사항이 없습니다", + "notAGitRepoTitle": "Git 저장소가 아닙니다", + "notAGitRepoHint": "위의 브랜치 메뉴에서 Git을 초기화하거나 기존 저장소를 여세요.", + "trackedChanges": "추적된 변경 ({count})", + "untrackedFiles": "추적되지 않은 파일 ({count})", + "expandTracked": "추적된 변경 펼치기", + "collapseTracked": "추적된 변경 접기", + "expandUntracked": "추적되지 않은 파일 펼치기", + "collapseUntracked": "추적되지 않은 파일 접기", + "showRemainingItems": "나머지 {count}개 표시", + "actions": { + "commitCode": "코드 커밋", + "rollback": "롤백", + "addToVcs": "VCS에 추가", + "delete": "삭제", + "moreActions": "추가 Git 작업", + "addAllToVcs": "모두 VCS에 추가", + "rollbackAll": "모두 롤백", + "refresh": "새로 고침" + }, + "toasts": { + "noAddableFilesInDir": "이 디렉터리에는 VCS에 추가할 수 있는 변경 파일이 없습니다", + "noRollbackFilesInDir": "이 디렉터리에는 롤백할 수 있는 변경 파일이 없습니다", + "addedToVcs": "{name}을(를) VCS에 추가했습니다", + "addToVcsFailed": "VCS에 추가하지 못했습니다", + "openCommitWindowFailed": "커밋 창을 열지 못했습니다", + "rolledBack": "{name}을(를) 롤백했습니다", + "rollbackFailed": "롤백에 실패했습니다", + "addedFilesToVcs": "{count, plural, one {#개 파일을 VCS에 추가} other {#개 파일을 VCS에 추가}}", + "rolledBackFiles": "{count, plural, one {#개 파일 롤백} other {#개 파일 롤백}}", + "deleted": "{name}이(가) 삭제되었습니다", + "deleteFailed": "삭제에 실패했습니다", + "deletedFiles": "{count}개 파일을 삭제했습니다", + "noDeletableFilesInDir": "이 디렉터리에서 삭제할 수 있는 변경된 파일이 없습니다", + "commitFailed": "커밋 실패" + }, + "directoryDialog": { + "descriptionAdd": "디렉터리 {path} 아래에서 VCS에 추가할 파일을 선택하세요.", + "descriptionRollback": "디렉터리 {path} 아래에서 롤백할 파일을 선택하세요.", + "descriptionDelete": "디렉터리 {path} 아래에서 삭제할 파일을 선택하세요. 이 작업은 되돌릴 수 없습니다.", + "descriptionFallback": "계속 진행할 파일을 선택하세요.", + "selectionCount": "{selected} / {total} 선택됨", + "selectAll": "모두 선택", + "unselectAll": "모두 선택 해제", + "loadingCandidates": "디렉터리 변경 사항 로딩 중...", + "noOperableFiles": "작업 가능한 파일이 없습니다" + }, + "rollbackConfirm": { + "title": "롤백 확인", + "descriptionWithTarget": "{kind} \"{name}\"의 로컬 변경 사항을 롤백할까요?", + "descriptionFallback": "로컬 변경 사항을 롤백할까요?", + "kindDirectory": "디렉터리", + "kindFile": "파일" + }, + "deleteConfirm": { + "title": "삭제 확인", + "descriptionWithTarget": "{kind} \"{name}\"을(를) 삭제할까요? 이 작업은 되돌릴 수 없습니다.", + "descriptionFallback": "이 작업은 되돌릴 수 없습니다.", + "kindDirectory": "디렉터리", + "kindFile": "파일" + }, + "quickCommit": { + "placeholder": "커밋 메시지 (Enter로 커밋)" + } + }, + "tabContext": { + "loadingConversation": "로딩 중...", + "untitledConversation": "제목 없는 대화", + "newConversation": "새 대화" + }, + "fileTreeTab": { + "workspace": "작업 공간", + "retry": "다시 시도", + "git": "Git", + "openInFileManager": "파일 관리자에서 열기", + "openInFinder": "Finder에서 열기", + "openInExplorer": "Explorer에서 열기", + "attachToCurrentSession": "세션에 추가", + "compareWithBranch": "브랜치와 비교...", + "reloadFromDisk": "디스크에서 다시 불러오기", + "new": "새로 만들기", + "newFile": "파일", + "newDirectory": "디렉터리", + "openIn": "열기", + "openInTerminal": "터미널에서 열기", + "linkedFolder": "연결된 폴더", + "copyPath": "경로 복사", + "upload": "파일/폴더 업로드", + "download": "파일 다운로드", + "downloadAsZip": "ZIP으로 다운로드", + "actions": { + "select": "선택", + "unselect": "선택 해제", + "commitCode": "코드 커밋", + "rollback": "롤백", + "addToVcs": "VCS에 추가" + }, + "aria": { + "selectPath": "{action}: {path}" + }, + "toasts": { + "openDirectoryFailed": "디렉터리를 열지 못했습니다", + "openBuiltinTerminalFailed": "내장 터미널을 열 수 없습니다", + "openCommitWindowFailed": "커밋 창을 열지 못했습니다", + "noAddableFilesInDir": "이 디렉터리에는 VCS에 추가할 수 있는 변경 파일이 없습니다", + "noRollbackFilesInDir": "이 디렉터리에는 롤백할 수 있는 변경 파일이 없습니다", + "addedToVcs": "{name}을(를) VCS에 추가했습니다", + "addToVcsFailed": "VCS에 추가하지 못했습니다", + "loadBranchesFailed": "브랜치를 불러오지 못했습니다", + "renameFailed": "이름 변경에 실패했습니다", + "moveFailed": "이동에 실패했습니다", + "deleteFailed": "삭제에 실패했습니다", + "rolledBack": "{name}을(를) 롤백했습니다", + "rollbackFailed": "롤백에 실패했습니다", + "addedFilesToVcs": "{count, plural, one {#개 파일을 VCS에 추가했습니다} other {#개 파일을 VCS에 추가했습니다}}", + "rolledBackFiles": "{count, plural, one {#개 파일을 롤백했습니다} other {#개 파일을 롤백했습니다}}", + "savedAsCopy": "사본으로 저장했습니다", + "saveCopyFailed": "사본으로 저장하지 못했습니다", + "watchStartFailed": "파일 감시 시작에 실패했습니다", + "createFailed": "생성 실패", + "downloadFailed": "{name} 다운로드 실패", + "downloadSaved": "{name} 다운로드 완료", + "pathCopied": "경로가 복사되었습니다", + "copyPathFailed": "경로 복사에 실패했습니다" + }, + "createDialog": { + "newFile": "새 파일", + "newDirectory": "새 디렉터리", + "description": "새 {kind}의 이름을 입력하세요.", + "placeholderFile": "file-name.ext", + "placeholderDirectory": "folder-name" + }, + "renameDialog": { + "renameDirectory": "디렉터리 이름 변경", + "renameFile": "파일 이름 변경", + "description": "새 이름을 입력하세요(이름만, 경로 제외).", + "placeholderDirectory": "새-폴더-이름", + "placeholderFile": "새-파일-이름.ext" + }, + "uploadDialog": { + "title": "작업 공간에 업로드", + "description": "필요하면 업로드 위치를 변경한 다음 파일이나 폴더를 추가하세요.", + "workspaceRoot": "작업 공간 루트", + "targetPathLabel": "업로드 위치", + "targetPathHint": "실제 경로: {path}", + "dropHint": "파일 또는 폴더를 여기에 끌어오거나 아래 버튼을 사용하세요", + "dropHintActive": "놓으면 대기열에 추가됩니다", + "selectFiles": "파일 선택", + "selectFolder": "폴더 선택", + "startUpload": "업로드 시작", + "clearQueue": "완료된 항목 지우기", + "removeItem": "대기열에서 제거", + "retry": "다시 시도", + "dropZoneAria": "파일을 여기에 드롭하거나 Enter 키로 찾아보기", + "folderEmpty": "드롭한 폴더에서 파일을 찾을 수 없습니다", + "summary": "합계: {total} · 성공: {succeeded} · 실패: {failed}", + "status": { + "pending": "대기 중", + "uploading": "업로드 중", + "success": "완료", + "error": "실패", + "cancelled": "취소됨" + } + }, + "directoryDialog": { + "descriptionAdd": "디렉터리 {path} 아래에서 VCS에 추가할 파일을 선택하세요.", + "descriptionRollback": "디렉터리 {path} 아래에서 롤백할 파일을 선택하세요.", + "descriptionFallback": "계속할 파일을 선택하세요.", + "selectionCount": "{selected} / {total}개 파일 선택됨", + "selectAll": "모두 선택", + "unselectAll": "모두 선택 해제", + "loadingCandidates": "디렉터리 변경 사항을 불러오는 중...", + "noOperableFiles": "작업 가능한 파일이 없습니다" + }, + "compareDialog": { + "title": "브랜치와 비교", + "descriptionWithTarget": "브랜치를 선택하고 {kind} {path}와(과) 비교하세요", + "descriptionFallback": "비교할 브랜치를 선택하세요.", + "kindDirectory": "디렉터리", + "kindFile": "파일", + "filterPlaceholder": "브랜치 필터링 (예: main / origin/main)", + "singleClickHint": "브랜치를 클릭하면 바로 비교합니다", + "loadingBranches": "브랜치를 불러오는 중...", + "recentBranches": "최근 브랜치 ({count})", + "noCurrentBranch": "현재 브랜치 없음", + "localBranches": "로컬 브랜치 ({count})", + "remoteBranches": "원격 브랜치 ({count})", + "noMatchingBranches": "일치하는 브랜치가 없습니다" + }, + "externalConflictDialog": { + "title": "외부 파일 변경 감지됨", + "descriptionWithPath": "파일 {path} 이(가) 디스크에서 변경되었고 현재 편집 내용은 저장되지 않았습니다.", + "descriptionFallback": "현재 파일이 디스크에서 변경되었고 현재 편집 내용은 저장되지 않았습니다.", + "compare": "비교", + "savingCopy": "사본 저장 중...", + "saveAsCopy": "사본으로 저장", + "reload": "다시 불러오기" + }, + "deleteConfirm": { + "title": "삭제 확인", + "descriptionWithTarget": "{kind} \"{name}\"을(를) 삭제할까요? 이 작업은 되돌릴 수 없습니다.", + "descriptionFallback": "이 작업은 되돌릴 수 없습니다.", + "kindDirectory": "디렉터리", + "kindFile": "파일" + }, + "rollbackConfirm": { + "title": "롤백 확인", + "descriptionWithTarget": "파일 \"{name}\"의 로컬 변경 사항을 롤백할까요?", + "descriptionFallback": "이 파일의 로컬 변경 사항을 롤백할까요?" + }, + "terminalTitle": "터미널 · {name}" + }, + "commandDropdown": { + "loading": "로딩 중...", + "addCommand": "명령 추가", + "manageCommands": "명령 관리...", + "runCommandTitle": "실행: {command}", + "stopCommandTitle": "중지: {command}", + "manageDialog": { + "title": "명령 관리", + "empty": "아직 명령이 없습니다", + "noResults": "일치하는 명령이 없습니다", + "searchPlaceholder": "명령 검색", + "newCommand": "새 명령", + "nameLabel": "이름", + "commandLabel": "명령", + "dragSort": "드래그하여 정렬", + "dragSortCommand": "{name} 드래그하여 정렬", + "orderFailed": "명령 순서 저장에 실패했습니다", + "loadFailed": "명령을 불러오지 못했습니다", + "saveFailed": "명령을 저장하지 못했습니다", + "deleteFailed": "명령을 삭제하지 못했습니다", + "confirmDelete": { + "title": "명령을 삭제하시겠습니까?", + "message": "\"{name}\"을(를) 제거합니다. 이 작업은 되돌릴 수 없습니다." + } + } + }, + "workspaceContext": { + "confirmCloseDirtyTab": "저장하지 않고 \"{title}\" 탭을 닫을까요?", + "confirmCloseOtherDirtyTabs": "저장되지 않은 변경 사항이 있는 다른 탭을 닫을까요?", + "confirmCloseAllDirtyTabs": "저장되지 않은 변경 사항이 있는 모든 탭을 닫을까요?", + "unableLoadContent": "콘텐츠를 불러올 수 없습니다.\n\n{message}", + "previewRequestTimedOut": "미리보기 요청 시간이 초과되었습니다", + "diffRequestTimedOut": "Diff 요청 시간이 초과되었습니다", + "branchCompareRequestTimedOut": "브랜치 비교 요청 시간이 초과되었습니다", + "commitDiffRequestTimedOut": "커밋 Diff 요청 시간이 초과되었습니다", + "saveRequestTimedOut": "저장 요청 시간이 초과되었습니다", + "reloadRequestTimedOut": "다시 불러오기 요청 시간이 초과되었습니다", + "noChanges": "변경 사항이 없습니다.", + "noDiffOutput": "Diff 출력이 없습니다.", + "diffTitleWorkspace": "Diff · 워크스페이스", + "diffDescriptionWorkingTree": "작업 트리 (HEAD)", + "diffTitleFile": "차이 · {name}", + "compareTitleFile": "비교 · {name}", + "compareTitleBranch": "비교 · {branch}", + "compareDescriptionPath": "{path} · {branch}와 비교", + "compareDescriptionBranch": "{branch}와 비교", + "diffTitleCommitFile": "차이 · {name} @ {hash}", + "diffTitleCommit": "차이 · {hash}", + "diffDescriptionCommitPath": "{path} · 커밋 {commit}", + "diffDescriptionCommit": "커밋 {commit}", + "diffTitleConflictFile": "충돌 · {name}", + "diffDescriptionConflict": "{path} · 디스크 vs 저장되지 않음" + }, + "chat": { + "acpConnections": { + "actions": { + "openAgentsSettings": "에이전트 설정 열기", + "retry": "다시 시도" + }, + "agentsSetupHint": "설정 > 에이전트를 열어 설치를 관리하세요.", + "withSetupHint": "{message}\n{hint}", + "blocked": { + "missingConfig": "현재 에이전트 구성을 읽을 수 없습니다.", + "disabled": "{agent}은(는) 에이전트 설정에서 비활성화되어 있습니다. 연결 전에 활성화하세요.", + "unavailable": "{agent}은(는) 현재 플랫폼에서 사용할 수 없습니다.", + "sdkMissing": "{agent} SDK가 설치되어 있지 않습니다", + "adapterMissing": "{agent}의 ACP 어댑터가 설치되어 있지 않습니다" + }, + "backendErrors": { + "initializeTimeout": "{agent} 연결 핸드셰이크가 시간 초과되었습니다(60초 동안 응답 없음). 설정을 열어 에이전트 및 네트워크 구성을 확인하세요.", + "mcpRejectedByAgent": "codeg의 MCP 동반 프로세스를 전달하는 동안 {agent}이(가) 세션을 거부했습니다: {message} 이 에이전트가 MCP를 지원하지 않는다면 설정에서 ‘MCP 지원’을 끄고 다시 연결하세요.", + "processExited": "{agent} 프로세스가 예기치 않게 종료되었습니다.", + "spawnFailed": "{agent} 시작 실패: {message}", + "downloadFailed": "{agent} 다운로드 실패: {message}", + "sessionLoadResourceNotFound": "{agent} 세션 불러오기에 실패했습니다. 다시 불러와 재시도하거나 새 대화를 시작하세요.", + "sessionLoadUnavailable": "{agent}에서 이 세션을 복원할 수 없습니다. 세션이 종료되었거나 에이전트가 중지되었을 수 있습니다. 다시 불러와 재시도하거나 새 대화를 시작하세요.", + "turnFailedRefusal": "{agent}이(가) 이번 턴을 계속하지 않았습니다. 백엔드나 게이트웨이 오류일 수 있습니다. 에이전트 로그를 확인하세요.", + "turnFailedMaxTokens": "{agent}이(가) 이번 턴의 최대 토큰 한도에 도달했습니다.", + "turnFailedMaxTurnRequests": "{agent}이(가) 이번 턴에서 허용된 최대 요청 수에 도달했습니다.", + "turnFailedUnknown": "{agent}이(가) 알 수 없는 중지 사유로 턴을 종료했습니다.", + "grokModelSwitchIncompatibleAgent": "{agent}은(는) 기존 대화에서는 해당 모델로 전환할 수 없습니다. 새 세션을 시작하여 사용하세요.", + "turnFailedEmpty": "{agent}이(가) 어떤 응답도 생성하지 않고 턴을 종료했습니다.", + "turnFailedEmptyProtocol": "{agent}의 출력을 codeg가 구문 분석할 수 없습니다. 에이전트 버전이 프로토콜과 맞지 않을 수 있습니다.", + "turnFailedEmptyMetadata": "{agent}이(가) 이번 턴에 상태 업데이트(계획 / 모드 / 사용량)만 보내고 응답은 없었습니다.", + "detailsInAlerts": "상태 표시줄의 알림을 열고 세부 정보를 펼치면 에이전트 출력을 확인할 수 있습니다." + }, + "unableReadAgentConfig": "에이전트 구성을 읽을 수 없습니다: {message}", + "connectFailedTitle": "{agent} 연결 실패", + "toolFallbackTitle": "도구", + "eventErrorTitle": "에이전트 오류", + "notificationTurnComplete": "{agent} 응답이 완료되었습니다", + "notificationError": "{agent} 오류: {message}", + "claudeApiRetry": { + "fallbackError": "authentication_failed", + "retryingWithMax": "재시도 중 {attempt}/{max}", + "retryingAttempt": "{attempt}번째 재시도 중", + "retrying": "재시도 중", + "nextRetryIn": "{seconds}초 후 재시도", + "line": "{error}{status} · {retry}", + "lineWithDelay": "{error}{status} · {retry}, {delay}", + "httpStatus": " (HTTP {status})" + }, + "configOptionAdjusted": "{agent}이(가) {option}을(를) {requested} 대신 {actual}(으)로 설정했습니다" + }, + "connectionLifecycle": { + "tasks": { + "connectingTitle": "{agent}에 연결 중", + "connectingDescription": "연결을 설정하는 중", + "loadingSelectorsTitle": "{agent} 선택자 불러오는 중", + "loadingSelectorsDescription": "모드 및 세션 구성 옵션을 가져오는 중", + "initSessionTitle": "{agent} 세션 초기화 중", + "initSessionDescription": "세션 생성 및 설정 불러오는 중" + }, + "errors": { + "connectionFailed": "연결 실패", + "sendPromptFailed": "메시지 전송에 실패했습니다: {error}" + } + }, + "shared": { + "attachedResources": "첨부된 리소스", + "toolCallFailed": "도구 호출 실패" + }, + "messageThread": { + "emptyTitle": "아직 메시지가 없습니다", + "emptyDescription": "대화를 시작하면 여기에서 메시지를 볼 수 있습니다" + }, + "chatInput": { + "connecting": "연결 중...", + "agentResponding": "{agent} 응답 중...", + "sendMessage": "메시지 보내기..." + }, + "messageInput": { + "askAnything": "무엇이든 물어보세요...", + "removeAttachmentAria": "{name} 제거", + "attachFiles": "파일 첨부", + "addActions": "추가", + "quickMessages": "빠른 메시지", + "quickMessagesEmpty": "빠른 메시지가 없습니다", + "quickMessagesLoading": "불러오는 중...", + "pasteAsPlainText": "일반 텍스트로 붙여넣기", + "cut": "잘라내기", + "copy": "복사", + "selectAll": "모두 선택", + "pasteUnavailable": "클립보드를 읽을 수 없습니다. Ctrl/⌘V로 붙여넣으세요.", + "clipboardWriteFailed": "클립보드에 쓸 수 없습니다. 키보드 단축키를 사용하세요.", + "quickMessageUntitled": "제목 없음", + "liveFeedback": "라이브 피드백", + "liveFeedbackDisabledHint": "에이전트가 작업 중일 때 보낼 수 있습니다", + "dropFilesToAttach": "파일을 놓아 첨부", + "loadingSettings": "설정 불러오는 중...", + "loadingMode": "모드 불러오는 중...", + "modeLabel": "모드", + "toggleOn": "켬", + "toggleOff": "끔", + "agentSettings": "에이전트 설정", + "searchModel": "모델 검색...", + "searchModelAria": "모델 검색", + "modelListLabel": "모델", + "noModels": "모델을 찾을 수 없습니다", + "cancel": "취소", + "send": "보내기", + "forkAndSend": "포크 & 전송", + "queueMessage": "대기열에 추가", + "steerIntoTurn": "현재 턴에 삽입", + "steerQueuedInstead": "대신 대기열에 추가되었습니다. 다음 턴에 전송됩니다.", + "steerFailed": "현재 턴에 삽입하지 못했습니다", + "steerAttachmentsUnsupported": "텍스트만 지원됩니다. 첨부 파일이 있는 초안은 대기열을 이용하세요.", + "slashCommands": "슬래시 명령", + "slashSearchPlaceholder": "명령 검색...", + "slashSearchEmpty": "일치하는 명령이 없습니다", + "experts": "전문가", + "office": "일상 업무", + "research": "과학 연구", + "attachLocalUpload": "로컬 파일 첨부", + "attachServerFile": "서버 파일 첨부", + "attachUploadTooLarge": "{names}이(가) {limit}MB 업로드 한도를 초과하여 건너뛰었습니다.", + "attachUploadFailed": "{names} 업로드 실패.", + "attachUploadNotAFile": "{names} 은(는) 일반 파일이 아니므로(디렉터리 또는 특수 파일) 건너뛰었습니다.", + "attachUploadQuotaExceeded": "서버 업로드 저장 공간이 부족하여 {names} 을(를) 업로드하지 못했습니다.", + "attachUploadInProgress": "이미지가 아직 업로드 중입니다. 잠시 후 다시 시도하세요.", + "mentionEmpty": "일치하는 항목 없음", + "mentionLoading": "검색 중…", + "mentionListLabel": "멘션", + "mentionMore": "결과가 더 있습니다. 계속 입력하여 필터링하세요", + "mentionCount": "{count, plural, other {결과 #개}}", + "mentionGroupFile": "파일", + "mentionGroupAgent": "에이전트", + "mentionGroupSession": "세션", + "mentionGroupCommit": "커밋", + "mentionGroupSkill": "스킬" + }, + "messageQueue": { + "addToQueue": "대기열에 추가", + "saveEdit": "저장", + "cancelEdit": "편집 취소", + "editItem": "편집", + "deleteItem": "삭제" + }, + "welcomeInputPanel": { + "agentsSettingsPath": "설정 > 에이전트", + "autoConnectFallback": "{path}을(를) 열어 설치를 관리하세요.", + "autoConnectAppend": "{message}. {path}을(를) 열어 설치를 관리하세요.", + "enableAgentFirstPlaceholder": "세션을 시작하기 전에 최소 한 개의 에이전트를 활성화하세요...", + "prepareSessionFailed": "채팅 세션을 준비하지 못했습니다. 다시 시도해 주세요.", + "createConversationFailed": "대화를 만들지 못했습니다. 다시 시도해 주세요.", + "askAnythingPlaceholder": "무엇이든 물어보세요...", + "agentNotInstalled": "{agent}이(가) 설치되지 않았습니다 · 클릭하여 Agents 설정에서 설치하세요", + "agentAdapterNotInstalled": "{agent}의 ACP 어댑터가 설치되지 않았습니다(사용 중인 CLI와는 별개) · 클릭하여 Agents 설정에서 설치하세요" + }, + "welcomePanel": { + "greeting": "오늘은 무엇을 해볼까요?", + "tips": { + "tileTabs": "대화 탭을 우클릭하고 '바둑판 표시'를 선택하면 여러 세션을 나란히 비교할 수 있습니다", + "pinTab": "대화 탭을 더블클릭하면 고정되어 새로 열린 세션이 자동으로 대체하지 않습니다", + "shortcutsNewSearch": "{newConversation}로 새 대화를 열고, {searchConversations}로 기록을 검색할 수 있습니다", + "slashAtMention": "입력창에서 /를 입력하면 슬래시 명령, @를 입력하면 프로젝트 내 파일을 참조할 수 있습니다", + "pasteDropFiles": "스크린샷을 붙여넣거나 파일을 입력창에 드롭하면 바로 첨부됩니다", + "queueMessage": "에이전트가 응답 중일 때도 계속 입력하면 다음 메시지가 대기열에 들어가 응답 후 자동 전송됩니다", + "draftAutoSave": "보내지 않은 초안은 대화별로 자동 저장되어 돌아왔을 때 복원됩니다", + "forkSend": "전송 버튼의 드롭다운에서 '분기 후 전송'을 선택하면 현재 지점에서 새 탭으로 분기할 수 있습니다", + "exportConversation": "대화 내용을 우클릭하면 Markdown / HTML / 이미지로 내보낼 수 있습니다", + "chatChannels": "'설정 → 채팅 채널'에서 Telegram / Lark / WeChat을 연결하면 휴대폰에서 이어서 사용할 수 있습니다", + "shortcutsAuxPanel": "{toggleAuxPanel}로 오른쪽 패널을 열어 이번 세션에서 변경된 파일과 Git 변경 사항을 확인할 수 있습니다", + "shortcutsTerminalSidebar": "{toggleTerminal}로 내장 터미널, {toggleSidebar}로 사이드바를 토글할 수 있습니다", + "customShortcuts": "모든 단축키는 '설정 → 단축키'에서 자유롭게 변경할 수 있습니다", + "webService": "'설정 → 웹 서비스'를 켜면 팀원이 브라우저로 같은 codeg에 접속할 수 있습니다", + "fusionMode": "파일이나 diff를 열면 대화 옆에 자동으로 표시됩니다.", + "quickMessages": "입력창 옆 + 버튼에서 '빠른 메시지'를 선택하면 저장된 스니펫을 한 번에 삽입할 수 있습니다('설정 → 빠른 메시지'에서 관리)", + "experts": "+ 버튼의 '전문가 스킬' 메뉴에서 디버그 / 기획 등 사전 정의된 역할을 한 번에 불러올 수 있습니다", + "taskBoard": "할 일은 작업을 끝까지 처리합니다. 에이전트가 전용 워크트리에서 작업하고, 여러분은 diff를 검토한 뒤 병합합니다.", + "automations": "자동화는 저장한 프롬프트를 일정에 따라 실행합니다(매일 밤 리뷰 등). 실행마다 전용 워크트리를 쓸 수도 있습니다.", + "tokenUsage": "상태 표시줄의 대화 수를 클릭하면 토큰 사용량이 열립니다. 날짜·에이전트·모델·폴더별 사용량을 확인할 수 있습니다.", + "mentionTargets": "@는 파일만 참조하는 것이 아닙니다. 다른 에이전트를 멘션해 하위 작업을 맡기거나, 지난 세션·커밋·스킬을 참조할 수 있습니다.", + "splitGroups": "탭을 우클릭해 「오른쪽으로 분할」 또는 「아래로 분할」을 고르면 두 대화를 각각의 창에 열어 둘 수 있습니다.", + "worktrees": "브랜치 버튼에서 「새 워크트리」를 고르면 여러 에이전트가 같은 저장소에서 서로의 파일을 덮어쓰지 않고 동시에 작업할 수 있습니다.", + "importSessions": "터미널에서 이미 실행한 세션이 있다면 폴더 메뉴의 「로컬 세션 가져오기」로 그 기록을 codeg에 가져올 수 있습니다.", + "subSessions": "에이전트가 위임하면 하위 세션이 사이드바에서 상위 세션 아래에 중첩되어 표시됩니다. 행을 펼치면 각각이 무엇을 했는지 확인할 수 있습니다.", + "liveFeedback": "「+」 메뉴의 라이브 피드백은 에이전트가 진행 중인 턴에 메모를 끼워 넣습니다. 작업을 끊지 않아도 됩니다.", + "skillPacks": "설정 → 스킬 팩에는 코딩 전문가, 과학 연구, 오피스 스킬이 묶여 있습니다. 에이전트별로 켜고 끌 수 있습니다.", + "modelProviders": "설정 → 모델 제공업체에서 직접 API 키나 엔드포인트를 등록하면, 입력창에서 바로 모델을 고를 수 있습니다.", + "workspaceBackground": "설정 → 외관에서 작업 공간 배경 이미지, 패널 불투명도, 앱 글꼴을 바꿀 수 있습니다." + }, + "quickActions": { + "excel": "Excel 통합 문서", + "excelDesc": "데이터 표, 수식, 차트", + "word": "Word 문서", + "wordDesc": "보고서, 편지, 메모", + "ppt": "프레젠테이션", + "pptDesc": "전문 디자인 슬라이드", + "pitchDeck": "피치덱", + "pitchDeckDesc": "핵심 지표가 담긴 투자 자료", + "morph": "Morph 애니메이션", + "morphDesc": "영화 같은 슬라이드 전환", + "morph3d": "3D Morph", + "morph3dDesc": "3D 모델과 카메라 무빙", + "academic": "학술 논문", + "academicDesc": "인용과 구조를 갖춘 연구 논문", + "financial": "재무 모델", + "financialDesc": "재무제표, DCF, 예측", + "dashboard": "데이터 대시보드", + "dashboardDesc": "데이터로 KPI와 분석 생성", + "prompts": { + "excel": "다음 요구 사항으로 Excel 통합 문서를 만들어 주세요:\n\n[데이터, 표, 수식, 차트를 여기에 설명]", + "word": "다음 요구 사항으로 Word 문서를 만들어 주세요:\n\n[문서 내용, 구조, 서식을 여기에 설명]", + "ppt": "다음 요구 사항으로 PowerPoint 프레젠테이션을 만들어 주세요:\n\n[슬라이드, 내용, 디자인을 여기에 설명]", + "pitchDeck": "다음 요구 사항으로 투자 피치덱을 만들어 주세요:\n\n[회사, 투자 라운드, 핵심 지표를 여기에 설명]", + "morph": "Morph 전환 애니메이션이 있는 프레젠테이션을 만들어 주세요:\n\n[발표 주제와 원하는 시각 효과를 여기에 설명]", + "morph3d": "GLB 모델과 카메라 무빙이 있는 3D Morph 프레젠테이션을 만들어 주세요:\n\n[주제와 3D 비주얼 콘셉트를 여기에 설명]", + "academic": "다음 요구 사항으로 Word 학술 논문을 작성해 주세요:\n\n[연구 주제, 방법론, 주요 결과를 여기에 설명]", + "financial": "다음 요구 사항으로 Excel 재무 모델을 만들어 주세요:\n\n[재무제표, 예측, 분석을 여기에 설명]", + "dashboard": "다음 요구 사항으로 Excel 데이터 대시보드를 만들어 주세요:\n\n[데이터 소스, KPI, 차트를 여기에 설명]", + "scientific-brainstorming": "연구 방향을 브레인스토밍해 주세요. 학제 간 연결을 탐색하고 가정을 검토하며 유망한 공백을 찾습니다. 탐색 중인 분야: ", + "hypothesis-generation": "이 관찰을 검증 가능한 가설로 바꿔 주세요. 명확한 예측, 그럴듯한 메커니즘, 검증 실험을 제시합니다. 내 관찰: ", + "experimental-design": "데이터 수집 전에 엄밀한 실험을 설계해 주세요. 설계, 무작위화, 대조, 교란 회피 방법을 포함합니다. 연구하려는 것: ", + "statistical-power": "필요한 표본 크기를 정해 주세요. 내 설계에 대해 검정력 분석(효과크기, 유의수준, 검정력)을 진행합니다. 세부 정보: ", + "statistical-analysis": "이 데이터를 제대로 분석해 주세요. 올바른 검정 선택, 가정 점검, 효과크기 보고, 결과 서술을 합니다. 내 데이터와 질문: ", + "exploratory-data-analysis": "내 데이터 파일을 탐색적으로 분석해 주세요. 구조, 품질, 주목할 패턴을 요약하고 다음 단계를 제안합니다. 파일: ", + "scientific-visualization": "출판 수준의 그림을 만들어 주세요. 명확한 배치, 정직한 오차 막대, 색각 이상을 고려한 팔레트, 저널 서식을 사용합니다. 보여주려는 것: ", + "scientific-critical-thinking": "이 연구나 주장을 비판적으로 평가해 주세요. 근거의 질을 평가하고 편향과 교란을 찾아 결론을 따져봅니다. 대상: ", + "paper-lookup": "학술 데이터베이스에서 관련 논문과 오픈액세스 전문을 찾고 재사용할 수 있는 인용도 제시해 주세요. 찾는 것: " + }, + "paper-lookup": "논문 검색", + "paper-lookupDesc": "10개 학술 API(PubMed, arXiv, OpenAlex, Crossref…)에서 논문·인용·오픈액세스 전문을 검색합니다.", + "scientific-critical-thinking": "비판적 사고", + "scientific-critical-thinkingDesc": "과학적 주장과 근거의 질을 평가 — 편향·교란을 찾고 GRADE 및 비뚤림 위험 프레임워크를 적용.", + "scientific-visualization": "과학적 시각화", + "scientific-visualizationDesc": "출판 수준 그림 — 다중 패널 배치, 유의성 주석, 저널별 서식.", + "exploratory-data-analysis": "탐색적 데이터 분석", + "exploratory-data-analysisDesc": "200종 이상 형식의 과학 데이터 파일을 자동 탐색하고 품질 지표와 보고서를 생성합니다.", + "statistical-analysis": "통계 분석", + "statistical-analysisDesc": "안내형 통계 분석 — 검정 선택, 가정 점검, 효과크기, APA 형식 보고.", + "statistical-power": "통계적 검정력", + "statistical-powerDesc": "표본 크기와 검정력 분석 — 필요한 대상 수, 최소 검출 가능 효과, 검정력 곡선.", + "experimental-design": "실험 설계", + "experimental-designDesc": "데이터 수집 전에 엄밀한 연구를 설계 — 무작위화, 블록화, 대조, 요인/DOE 배치.", + "hypothesis-generation": "가설 생성", + "hypothesis-generationDesc": "관찰을 검증 가능한 가설로 전환하고 예측·메커니즘·검증 실험을 제시합니다.", + "scientific-brainstorming": "과학적 브레인스토밍", + "scientific-brainstormingDesc": "열린 연구 아이디어 발상 — 학제 간 연결을 탐색하고 가정을 검토하며 연구 공백을 찾습니다.", + "tabs": { + "office": "일상 업무", + "coding": "코드 개발", + "research": "과학 연구" + }, + "coding": { + "brainstormingDesc": "구현 전 의도와 요구사항 탐색", + "debuggingDesc": "수정 제안 전에 근본 원인 파악", + "writingSkillsDesc": "재사용 가능한 스킬 생성·편집·검증" + }, + "notEnabled": { + "title": "‘{skill}’ 스킬이 아직 {agent}에서 활성화되지 않았습니다", + "description": "설정에서 활성화하면 여기서 사용할 수 있습니다.", + "action": "활성화하기", + "hint": "스킬이 비활성화됨" + }, + "scrollPrev": "이전 스킬 표시", + "scrollNext": "다음 스킬 표시" + } + }, + "agentSelector": { + "noEnabledAgents": "활성화된 에이전트가 없습니다", + "openAgentsSettings": "에이전트 설정 열기", + "notInstalled": "설치되지 않음", + "moreAgents": "에이전트 더 보기 ({count})" + }, + "subAgentOverlay": { + "title": "서브 에이전트", + "collapsedSummary": "서브 에이전트 {count}", + "collapseAria": "서브 에이전트 접기" + }, + "agentPlanOverlay": { + "title": "에이전트 계획", + "collapsePlanAria": "계획 접기", + "collapsedSummary": "계획 {completed}/{total}", + "status": { + "completed": "완료", + "inProgress": "진행 중", + "pending": "대기", + "unknown": "알 수 없음" + }, + "priority": { + "high": "높음", + "medium": "중간", + "low": "낮음", + "unknown": "알 수 없음" + } + }, + "permissionDialog": { + "subtitle": "에이전트가 이 턴을 계속하기 위한 권한을 요청합니다.", + "queuedCount": "{count}건 대기 중", + "kindFallbackTool": "도구", + "command": "명령", + "cwd": "작업 디렉터리: {cwd}", + "filesSummary": "파일: {count}", + "moreFiles": "+{count}개 파일 더", + "plan": "계획", + "allowedActions": "허용된 작업", + "targetMode": "대상 모드: {mode}", + "optionGrants": "각 옵션이 부여하는 권한", + "changeScopeSession": "이 세션", + "changeScopeProcess": "이 실행", + "changeScopeUser": "사용자 설정에 저장", + "changeScopeProject": "프로젝트 설정에 저장", + "changeScopeProjectLocal": "로컬 프로젝트 설정에 저장", + "changeScopePersistent": "영구 저장" + }, + "questionDialog": { + "title": "에이전트가 질문하고 있습니다", + "placeholder": "답변을 입력하세요...", + "send": "전송" + }, + "messageBranch": { + "previousBranchAria": "이전 브랜치", + "nextBranchAria": "다음 브랜치", + "pageOf": "{current} / {total}" + }, + "terminal": { + "title": "터미널", + "running": "실행 중" + }, + "reasoning": { + "thinking": "생각 중…", + "thoughtForFewSeconds": "생각함", + "thoughtForSeconds": "생각함" + }, + "linkSafety": { + "errorCannotOpen": "로컬 파일을 열 수 없습니다", + "errorNoWorkspace": "현재 활성화된 워크스페이스 폴더가 없습니다.", + "errorFailedOpen": "로컬 파일 열기 실패", + "errorFailedLink": "링크 열기 실패", + "errorUnsupportedLinkProtocol": "이 링크 프로토콜은 지원되지 않습니다." + }, + "fileActions": { + "openInFinder": "Finder에서 열기", + "openInExplorer": "Explorer에서 열기", + "openInFileManager": "파일 관리자에서 열기", + "copyRelativePath": "상대 경로 복사", + "copyAbsolutePath": "절대 경로 복사", + "pathCopied": "경로가 복사되었습니다", + "copyPathFailed": "경로 복사에 실패했습니다", + "openFailed": "로컬 파일 열기 실패" + }, + "messageList": { + "attachedResources": "첨부된 리소스", + "loading": "불러오는 중...", + "loadEarlier": "이전 메시지 불러오기", + "loadingEarlier": "이전 메시지를 불러오는 중…", + "error": "오류: {message}", + "errorTitle": "세션 불러오기 실패", + "errorActionReload": "다시 불러오기", + "errorActionNewSession": "새 대화", + "emptyConversation": "이 대화에는 메시지가 없습니다.", + "systemMessage": "시스템 메시지", + "copyMessage": "복사", + "copied": "복사됨", + "downloadImage": "이미지 다운로드", + "downloadFailed": "다운로드 실패: {message}", + "imageGeneration": "이미지 생성", + "imageGenerationPending": "이미지 생성 중…", + "imageGenerationFailed": "이미지 생성 실패", + "model": "모델", + "tokenStats": "토큰 사용량", + "tokenInput": "입력", + "tokenOutput": "출력", + "tokenCacheRead": "캐시 읽기", + "tokenCacheWrite": "캐시 쓰기", + "duration": "소요 시간", + "completedAt": "완료 시각", + "jumpToPreviousUserMessage": "이전 사용자 메시지로 이동", + "showMore": "더보기", + "showLess": "접기" + }, + "liveTurnStats": { + "thinking": "생각 중...", + "streaming": "스트리밍 중", + "elapsedHours": "{value}시간", + "elapsedMinutes": "{value}분", + "elapsedSeconds": "{value}초", + "outputSpeedAria": "예상 출력 속도", + "outputSpeedTooltip": "예상 출력 속도(텍스트 + 추론)" + }, + "jsonTree": { + "viewRaw": "원본 JSON 보기", + "viewTree": "트리 보기", + "fields": "필드 {count}개", + "items": "항목 {count}개" + }, + "tool": { + "parameters": "매개변수", + "error": "오류", + "result": "결과", + "status": { + "approvalRequested": "승인 대기 중", + "approvalResponded": "응답됨", + "inputAvailable": "실행 중", + "inputStreaming": "대기 중", + "outputAvailable": "완료", + "outputDenied": "거부됨", + "outputError": "오류" + } + }, + "toolCallBlock": { + "tool": "도구", + "error": "오류", + "result": "결과" + }, + "delegation": { + "subAgentRunning": "서브에이전트 실행 중…", + "noDetail": "No detail available yet.", + "unknownAgent": "하위 에이전트", + "openDetail": "대화 보기", + "detailTitle": "서브에이전트 대화", + "detailDescription": "위임된 서브에이전트 대화를 읽기 전용으로 봅니다.", + "waitForResult": "작업 {task} 실행 결과 대기 중", + "waitForResultNoTask": "작업 실행 결과 대기 중", + "cancelTask": "작업 {task} 취소 중", + "cancelTaskNoTask": "작업 취소 중", + "resultPageOf": "{current} / {total}", + "prevResult": "이전 결과", + "nextResult": "다음 결과", + "noResultText": "이 확인에서는 결과가 없습니다", + "status": { + "starting": "시작 중", + "running": "실행 중", + "checked": "확인됨", + "waiting": "승인 대기 중", + "ok": "완료", + "err": { + "default": "실패", + "delegation_disabled": "비활성화됨", + "depth_limit": "깊이 제한", + "invalid_agent_type": "잘못된 에이전트", + "spawn_failed": "시작 실패", + "send_failed": "전송 실패", + "timeout": "시간 초과", + "canceled": "취소됨", + "child_refusal": "서브에이전트 거부", + "child_max_tokens": "서브에이전트: 토큰 한도", + "child_max_turn_requests": "서브에이전트: 요청 한도", + "child_empty": "서브에이전트 응답 없음", + "child_unknown": "서브에이전트: 오류", + "unknown": "알 수 없는 작업" + } + } + }, + "contentParts": { + "showingTailOutput": "성능을 위해 스트리밍 중에는 출력의 끝부분만 표시합니다.", + "result": "결과", + "unknown": "알 수 없음", + "inputTruncated": "입력이 잘렸습니다 — diff가 불완전할 수 있습니다.", + "replaceAll": "모두 바꾸기", + "filesCount": "파일: {count}", + "update": "업데이트", + "moreFiles": "+{count}개 파일 더", + "timeoutMs": "시간 초과: {timeout}ms", + "backgroundTrue": "백그라운드: true", + "scriptToolCalls": "도구 {count}개 호출", + "offset": "오프셋: {offset}", + "limit": "제한: {limit}", + "pages": "페이지: {pages}", + "mode": "모드: {mode}", + "cell": "셀: {cell}", + "shellSession": "세션 {id}", + "pathLabel": "경로:", + "globLabel": "Glob 패턴:", + "typeLabel": "유형:", + "outputLabel": "출력:", + "caseInsensitive": "대소문자 구분 안 함", + "multiline": "여러 줄", + "promptLabel": "프롬프트", + "subjectLabel": "제목", + "taskLabel": "작업", + "nameLabel": "이름:", + "agentPromptLabel": "프롬프트", + "agentModelLabel": "모델", + "agentRunning": "실행 중...", + "agentLiveTranscript": "실시간 활동", + "agentProgressTools": "도구 호출 {count}회", + "agentProgressTurns": "{count} 턴", + "agentProgressContext": "컨텍스트 {pct}%", + "agentSessionAction": "하위 에이전트 세션 보기", + "agentSessionTitle": "하위 에이전트 세션", + "agentSessionLoading": "하위 에이전트의 기록을 불러오는 중…", + "agentSessionEmpty": "하위 에이전트가 아직 아무것도 기록하지 않았습니다.", + "agentFallbackTitle": "서브 에이전트 시작 중…", + "agentCodexLaunchOnly": "시작되었습니다. Codex는 이 하위 에이전트의 진행 상황을 더 이상 알리지 않으며, 결과는 이 대화의 메시지로 도착합니다.", + "agentStatsBash": "명령", + "agentStatsRead": "파일 읽기", + "agentStatsSearch": "검색", + "agentStatsEdit": "편집", + "agentStatsOther": "기타", + "goal": { + "title": "목표:", + "titleWithStatus": "목표 {status}", + "objective": "목표", + "statusLabel": "상태", + "tokensUsed": "사용 tokens", + "budget": "예산", + "remaining": "남음", + "elapsed": "경과", + "tokens": "tokens", + "pause": "일시정지", + "clear": "지우기", + "status": { + "active": "진행 중", + "paused": "일시 중지", + "blocked": "차단됨", + "usageLimited": "사용량 제한", + "budgetLimited": "예산 제한", + "complete": "완료", + "limited": "한도 도달" + } + }, + "field": { + "file": "파일", + "notebook": "노트북", + "command": "명령", + "old": "이전", + "new": "새", + "pattern": "패턴", + "path": "경로", + "query": "쿼리", + "url": "URL:", + "description": "설명", + "content": "내용", + "source": "소스", + "prompt": "프롬프트", + "subject": "제목", + "taskId": "작업 ID", + "status": "상태", + "skill": "Skill", + "args": "인자", + "offset": "오프셋", + "limit": "제한", + "glob": "Glob 패턴", + "type": "유형", + "output": "출력", + "replaceAll": "모두 바꾸기", + "language": "언어", + "timeout": "시간 초과", + "background": "백그라운드", + "agentType": "에이전트 유형", + "library": "라이브러리", + "libraryId": "라이브러리 ID" + }, + "title": { + "edit": "편집", + "command": "명령", + "script": "스크립트", + "waitCommand": "대기 {command}", + "waitCell": "세션 {id} 대기", + "terminateCommand": "종료 {command}", + "terminateCell": "세션 {id} 종료", + "stdinChars": "입력 {chars}", + "todoWrite": "TodoWrite(할 일 업데이트)", + "read": "읽기", + "write": "쓰기", + "notebookEdit": "NotebookEdit(노트북 편집)", + "editFiles": "편집 ({count}개 파일)", + "editWithTarget": "{target} 편집", + "readWithTarget": "{target} 읽기", + "writeWithTarget": "{target} 쓰기", + "notebookEditWithTarget": "NotebookEdit({target})", + "globWithPattern": "Glob 패턴 {pattern}", + "listFilesWithPath": "파일 목록 {path}", + "grepWithPattern": "Grep 패턴 {pattern}", + "taskCreateWithSubject": "작업 생성: {subject}", + "taskUpdateWithStatus": "작업 업데이트 #{id} -> {status}", + "taskUpdate": "작업 업데이트 #{id}", + "webFetchWithUrl": "WebFetch ({url})", + "webSearchWithQuery": "WebSearch ({query})", + "todosProgress": "할 일 ({done}/{total})", + "skillWithName": "Skill: {name}", + "genericWithContext": "{tool} ({context})" + }, + "search": { + "noMatches": "일치하는 결과 없음", + "matchSummary": "{matches}개 일치 · {files}개 파일", + "fileSummary": "{files}개 파일", + "moreResults": "{count}개 결과가 더 있음(표시되지 않음)" + }, + "toolGroup": { + "search": "{count}회 검색", + "command": "명령 {count}개 실행", + "read": "파일 {count}회 읽기", + "memory": "기억 {count}개 회상", + "edit": "파일 {count}회 편집", + "fetch": "리소스 {count}개 가져오기", + "think": "{count}회 사고", + "todo": "할 일 {count}개 업데이트", + "task": "작업 {count}개 실행", + "other": "도구 {count}개 사용", + "errorSuffix": "{count}건 실패", + "joiner": " · " + }, + "planMode": { + "entered": "계획 모드 시작", + "planLabel": "계획", + "reviewApproved": "계획 승인됨 — 실행 중", + "reviewKept": "계획 모드 유지", + "reviewPending": "계획 결정 대기 중", + "submitted": "계획 제출됨", + "switched": "모드 전환됨" + }, + "backgroundTask": { + "title": "백그라운드 작업", + "titleWithId": "백그라운드 작업 · {id}", + "running": "실행 중", + "completed": "완료됨", + "failed": "실패", + "stopped": "중지됨", + "exitCode": "종료 코드 {code}", + "polledTimes": "{count}회 폴링", + "runningInBackground": "백그라운드", + "launchNote": "백그라운드에서 실행 중 · {id}" + }, + "codexScript": { + "outputMissing": "codex가 스크립트 출력을 잘라내면서 이 명령의 구분선이 사라져 출력을 귀속시킬 수 없습니다.", + "sharedWith": "이 구간에는 {commands}의 출력도 포함됩니다 — 구분선이 codex에 의해 잘렸습니다.", + "truncated": "잘림" + } + }, + "messageNav": { + "title": "메시지 탐색", + "collapse": "메시지 탐색 접기", + "collapsedSummary": "메시지 {count}", + "fileCount": "{count, plural, one {#개 파일} other {#개 파일}}", + "remove": "제거", + "noDiffDataAvailable": "{filePath}에 대한 diff 데이터가 없습니다" + }, + "replyArtifacts": { + "title": "변경된 파일", + "fileCount": "{count, plural, one {#개 파일} other {#개 파일}}", + "newFilesTitle": "새 파일", + "revealInFolder": "파일 관리자에서 표시", + "openFile": "{filePath} 열기", + "openInEditor": "편집기에서 열기", + "remove": "제거", + "noDiffDataAvailable": "{filePath}에 대한 diff 데이터가 없습니다" + }, + "askQuestion": { + "title": "에이전트가 선택을 요청합니다", + "subtitle": "답변 후 제출하세요. 언제든 건너뛸 수 있습니다", + "recommended": "추천", + "other": "기타", + "otherPlaceholder": "답변을 입력하세요…", + "singleSelect": "단일 선택", + "multiSelect": "다중 선택", + "skip": "건너뛰기", + "next": "다음", + "submit": "제출", + "submitError": "제출하지 못했습니다. 다시 시도해 주세요." + }, + "planApproval": { + "title": "에이전트가 계획을 제시했습니다 — 검토하세요", + "emptyPlan": "에이전트가 계획을 작성하지 않았습니다. 승인하여 구현을 시작하거나 변경을 요청하세요.", + "approve": "승인하고 시작", + "requestChanges": "변경 요청", + "abandon": "포기", + "feedbackPlaceholder": "무엇을 변경할까요?", + "sendChanges": "보내기", + "cancel": "취소", + "submitError": "제출하지 못했습니다. 다시 시도하세요." + }, + "feedbackCheckResult": { + "count": "피드백 {count}개", + "expand": "모든 피드백 표시", + "collapse": "접기", + "errorTitle": "피드백 확인 실패" + }, + "askQuestionResult": { + "title": "질문", + "answeredLabel": "질문과 답변:", + "awaiting": "답변을 기다리는 중…", + "declined": "이 질문을 건너뛰었습니다 — 에이전트가 자체 판단으로 진행했습니다.", + "noSelection": "선택 없음" + }, + "configStale": { + "agentConfigTitle": "에이전트 설정이 업데이트되었습니다", + "modelProviderTitle": "모델 공급자가 업데이트되었습니다", + "description": "이 세션은 아직 이전 설정을 사용 중입니다. 다시 연결하면 적용됩니다(대화 기록은 유지됩니다).", + "reconnect": "다시 연결하여 적용", + "reconnecting": "다시 연결하는 중…", + "reconnectDisabledDuringTurn": "현재 턴이 끝나면 다시 연결할 수 있습니다", + "dismiss": "닫기", + "reconnectFailed": "세션 다시 연결 실패", + "applied": "새 설정이 적용되었습니다" + }, + "piProjectTrust": { + "title": "이 프로젝트에 pi 리소스가 포함되어 있습니다", + "description": "pi가 저장소 자체의 .pi 파일을 불러오지 않고 있습니다. 확인 후 결정하세요.", + "descriptionExecutable": "저장소에 pi 확장이 포함되어 있으며, 확장은 시작 시 코드를 실행합니다. pi는 아직 불러오지 않았습니다. 결정하기 전에 확인하세요.", + "review": "검토…", + "dismiss": "닫기", + "dialogTitle": "이 프로젝트의 pi 리소스를 신뢰하시겠습니까?", + "dialogDescription": "폴더를 신뢰해야만 pi가 저장소 자체의 .pi 파일을 불러옵니다. 이 저장소의 내용을 신뢰하는 경우에만 허용하세요.", + "executionWarning": "확장은 코드입니다. 이 폴더를 신뢰하면 메시지를 보내기 전에 저장소의 확장이 pi 시작 시 사용자 권한으로 실행됩니다.", + "scopeNote": "이 결정은 pi의 trust.json에 저장되며 해당 폴더 아래의 모든 폴더에 적용되고, 터미널에서 직접 pi를 실행할 때에도 사용됩니다. 나중에 설정 → 에이전트 → Pi에서 변경할 수 있습니다.", + "trust": "프로젝트 신뢰", + "decline": "불러오지 않음", + "disabledDuringTurn": "현재 턴이 끝나면 사용할 수 있습니다", + "trustedToast": "프로젝트를 신뢰했습니다 — pi가 리소스를 불러오도록 다시 연결했습니다", + "declinedToast": "프로젝트 리소스를 불러오지 않습니다", + "saveFailed": "프로젝트 신뢰 설정을 저장하지 못했습니다", + "grantTitle": "이 프로젝트는 이미 신뢰됨", + "grantDescription": "pi가 이 저장소 자체의 .pi 파일을 불러옵니다. 무엇이 허용되는지 확인하세요.", + "grantInheritedDescription": "상위 폴더가 신뢰되어 pi가 이 저장소 자체의 .pi 파일을 불러옵니다. 무엇이 허용되는지 확인하세요.", + "grantDialogTitle": "이 프로젝트의 pi 리소스가 신뢰됨", + "grantDialogDescription": "pi가 이 저장소 자체의 .pi 파일을 불러오도록 허용되어 있습니다. 이전 codeg 버전은 폴더를 열 때 자동으로 이를 허용했으므로 확인을 요청받지 않았을 수 있습니다.", + "grantExecutionWarning": "확장은 코드입니다. 저장소의 확장은 메시지를 보내기 전에 pi 시작 시 사용자 권한으로 실행됩니다.", + "inheritedFrom": "신뢰 출처", + "revoke": "신뢰 취소", + "keepTrusted": "신뢰 유지", + "revokedToast": "신뢰를 취소했습니다 — 다시 연결하여 pi가 프로젝트 리소스를 불러오지 않습니다", + "trustedNoReconnect": "프로젝트를 신뢰했습니다 — pi가 다음에 시작할 때 적용됩니다", + "revokedNoReconnect": "신뢰를 취소했습니다 — pi가 다음에 시작할 때 적용됩니다" + }, + "collabAgent": { + "title": "서브 에이전트", + "errorTitle": "서브 에이전트 작업이 실패했습니다", + "statesLabel": "서브 에이전트", + "statusRunning": "실행 중", + "statusCompleted": "완료됨", + "statusFailed": "실패", + "statusPending": "시작 중", + "statusInterrupted": "중단됨", + "statusClosed": "종료됨", + "statusNotFound": "찾을 수 없음", + "opSpawn": "서브 에이전트 시작 중", + "opWait": "서브 에이전트 결과 가져오는 중", + "opClose": "서브 에이전트 종료 중", + "opResume": "서브 에이전트 재개 중" + }, + "contextCompaction": { + "compacting": "컨텍스트 압축 중…", + "compacted": "컨텍스트 압축 완료", + "compactedTokens": "컨텍스트 압축 완료 · {before} → {after} 토큰", + "failed": "컨텍스트 압축 실패" + }, + "sessionFailure": { + "category": { + "connection": "연결 문제", + "access": "액세스 문제", + "limit": "한도 도달", + "request": "요청 거부됨", + "service": "서비스 문제", + "unknown": "세션 문제" + }, + "action": { + "retry": "다시 시도", + "login": "로그인", + "newSession": "새 세션" + }, + "recovered": "복구됨", + "retryUnavailable": "다시 보낼 메시지가 없습니다.", + "toggleDetails": "세부 정보 전환" + }, + "backgroundTasks": { + "running": "백그라운드 작업 {count}개 실행 중", + "settling": "백그라운드 결과 동기화 중…", + "settledFallback": "백그라운드 작업이 종료되었습니다 ({status})", + "cardRunning": "백그라운드에서 실행 중", + "cardLaunchedPending": "백그라운드 작업 시작됨", + "cardCompleted": "백그라운드 작업 완료", + "cardFinishedWithStatus": "백그라운드 작업 종료 ({status})", + "cardResultPending": "결과가 아직 반환되지 않았습니다" + }, + "proposedPlan": { + "title": "제안된 계획", + "planning": "계획 중…" + } + }, + "diffPreview": { + "mode": { + "added": "추가됨", + "deleted": "삭제됨", + "renamed": "이름 변경됨", + "modified": "수정됨" + }, + "hunkLabel": "청크 {index}", + "loadingHunk": "Hunk 로딩 중...", + "noDiffData": "Diff 데이터 없음", + "showRemainingLines": "나머지 {count}줄 표시" + }, + "conversationContextBar": { + "folderTitle": "작업 폴더", + "branchTitle": "작업 브랜치", + "searchFolder": "Search folder...", + "searchBranch": "Search branch...", + "noFolders": "No folders", + "noBranches": "No branches", + "noBranch": "(no branch)", + "chatModeLabel": "채팅 모드", + "commit": "Commit", + "push": "Push", + "merge": "Merge", + "toasts": { + "folderChanged": "Switched to {name}", + "openFolderFailed": "Failed to open folder", + "switchedToChatMode": "채팅 모드로 전환했습니다", + "openStashFailed": "Failed to open stash window", + "openMergeFailed": "Failed to open merge window" + } + }, + "cloneDialog": { + "title": "저장소 클론", + "repositoryUrl": "저장소 URL", + "repositoryUrlPlaceholder": "https://github.com/user/repo.git", + "directory": "디렉터리", + "directoryPlaceholder": "대상 디렉터리 선택...", + "browseDirectory": "디렉터리 찾아보기", + "cancel": "취소", + "clone": "클론", + "clonePath": "클론 경로: {path}" + }, + "toasts": { + "cloneFailed": "저장소 클론에 실패했습니다" + } + }, + "ProjectBoot": { + "title": "프로젝트 부트", + "tabs": { + "shadcn": "shadcn", + "hyperframes": "HyperFrames" + }, + "hyperframes": { + "title": "HyperFrames 비디오 프로젝트", + "subtitle": "HTML을 비디오로 만드는 프로젝트를 생성합니다. 이후 워크스페이스 에이전트가 작성하고 렌더링할 수 있습니다.", + "resolution": "해상도", + "skillsTitle": "에이전트 스킬", + "skillsDesc": "선택한 에이전트에 HyperFrames 스킬을 전역(심볼릭 링크)으로 설치하여 영상 작성·렌더링을 지원합니다.", + "recheck": "다시 확인", + "installedBadge": "설치됨", + "skillsInstall": "스킬 설치 / 업데이트", + "skillsInstalling": "스킬 설치 중…", + "skillsInstalled": "HyperFrames 스킬 설치 완료", + "skillsInstallFailed": "HyperFrames 스킬 설치 실패" + }, + "config": { + "base": "베이스", + "style": "스타일", + "baseColor": "베이스 색상", + "theme": "테마", + "chartColor": "차트 색상", + "iconLibrary": "아이콘 라이브러리", + "font": "글꼴", + "fontHeading": "제목 글꼴", + "menuAccent": "메뉴 강조", + "menuColor": "메뉴 색상", + "radius": "둥글기", + "template": "템플릿", + "createProject": "프로젝트 만들기", + "sectionStyle": "스타일", + "sectionColors": "색상", + "sectionTypography": "타이포그래피", + "sectionInterface": "인터페이스" + }, + "preview": { + "loading": "미리보기 로딩 중..." + }, + "createDialog": { + "title": "프로젝트 만들기", + "projectName": "프로젝트 이름", + "projectNamePlaceholder": "my-app", + "frameworkTemplate": "프레임워크 템플릿", + "packageManager": "패키지 매니저", + "saveDirectory": "저장 디렉토리", + "saveDirectoryPlaceholder": "디렉토리 선택...", + "browseDirectory": "찾아보기", + "projectPath": "프로젝트 생성 위치: {path}", + "advancedOptions": "고급 옵션", + "base": "기본 라이브러리", + "enableRtl": "RTL 지원 활성화", + "enableRtlDescription": "오른쪽에서 왼쪽으로 쓰는 언어(예: 아랍어, 히브리어)의 레이아웃 지원 활성화", + "pmChecking": "확인 중...", + "pmNotInstalled": "설치되지 않음", + "cancel": "취소", + "create": "만들기", + "creating": "프로젝트 생성 중..." + }, + "toasts": { + "createFailed": "프로젝트 생성에 실패했습니다", + "createSuccess": "프로젝트가 성공적으로 생성되었습니다", + "openWorkspaceFailed": "프로젝트가 생성되었지만 작업 공간에서 열지 못했습니다" + }, + "errors": { + "directoryExists": "대상 디렉터리가 이미 존재합니다", + "commandFailed": "프로젝트 생성 명령이 실패했습니다." + } + }, + "WebServiceSettings": { + "addressSwitchHint": "전환해도 여기에 표시되고 열리는 주소만 바뀝니다. 서비스는 모든 인터페이스에서 수신하며 어떤 주소로도 접속할 수 있습니다.", + "sectionTitle": "웹 서비스", + "sectionDescription": "활성화하면 브라우저를 통해 Codeg에 원격으로 접속할 수 있습니다", + "port": "포트", + "status": "상태", + "autoStart": "자동 시작", + "autoStartHint": "Codeg가 시작될 때 웹 서비스를 시작합니다", + "running": "실행 중", + "stopped": "중지됨", + "processing": "처리 중...", + "start": "시작", + "stop": "중지", + "startFailed": "시작 실패", + "stopFailed": "중지 실패", + "saveConfigFailed": "웹 서비스 설정 저장 실패", + "open": "열기", + "hide": "숨기기", + "show": "표시", + "copy": "복사", + "qrcode": "QR 코드", + "qrcodeTitle": "스캔하여 열기", + "qrcodeHint": "휴대폰으로 스캔하여 브라우저에서 Codeg를 엽니다", + "addressLabel": "접속 주소", + "tokenLabel": "접속 토큰", + "tokenHint": "웹 클라이언트 첫 접속 시 이 토큰을 입력하세요", + "tokenPlaceholder": "비워두면 자동 생성", + "regenerate": "재생성", + "stalePortOccupiedTitle": "포트 {port}이(가) 다른 프로세스에 의해 사용 중입니다", + "stalePortUnknownTitle": "포트 {port}의 상태를 확인할 수 없습니다", + "stalePortHint": "포트가 해제될 때까지 Codeg은 바인딩할 수 없습니다. 위의 포트를 변경하거나 사용 중인 프로세스를 종료하세요.", + "errors": { + "alreadyRunning": "웹 서비스가 이미 실행 중입니다", + "invalidAddress": "호스트 또는 포트 형식이 올바르지 않습니다", + "portInUse": "포트 {port}가 이미 사용 중입니다. 해당 포트를 사용 중인 프로세스를 종료하거나 다른 포트를 선택하세요", + "permissionDenied": "권한이 부족합니다. 1024 이상의 포트를 사용하거나 더 높은 권한으로 실행하세요", + "addressUnavailable": "이 주소는 현재 시스템에서 사용할 수 없습니다", + "bindFailed": "주소 바인딩에 실패했습니다" + } + }, + "DirectoryBrowser": { + "title": "디렉토리 찾아보기", + "pathPlaceholder": "디렉토리 경로 입력...", + "goHome": "홈 디렉토리로 이동", + "navigateUp": "상위 디렉토리로 이동", + "select": "선택", + "cancel": "취소", + "loading": "로딩 중...", + "emptyDirectory": "이 디렉토리는 비어 있습니다", + "errorLoadingDir": "디렉토리 로딩 실패", + "permissionDenied": "권한이 없습니다" + }, + "ChatChannelSettings": { + "loading": "로딩 중...", + "sectionTitle": "채팅 채널", + "sectionDescription": "IM 봇을 설정하여 이벤트 알림을 수신하고 코딩 활동을 조회합니다.", + "addChannel": "채널 추가", + "noChannels": "설정된 채팅 채널이 없습니다.", + "channelName": "이름", + "channelNamePlaceholder": "내 Telegram 봇", + "channelType": "채널 유형", + "lark": "Lark (飛書)", + "weixin": "WeChat", + "dailyReport": "일일 리포트", + "dailyReportTime": "발송 시간", + "nameRequired": "채널 이름을 입력하세요.", + "tokenRequired": "토큰을 입력하세요.", + "chatIdRequired": "Chat ID를 입력하세요.", + "topicMode": "토픽 그룹 모드", + "topicModeHint": "Telegram forum topics를 별도 Codeg 세션으로 라우팅합니다. Bot은 forum supergroup에 있어야 하며 topics 관리 권한이 필요합니다.", + "loadFailed": "채널 로딩에 실패했습니다.", + "saveFailed": "저장에 실패했습니다.", + "connectSuccess": "채널이 연결되었습니다.", + "connectFailed": "연결에 실패했습니다", + "disconnectSuccess": "채널이 연결 해제되었습니다.", + "disconnectFailed": "연결 해제에 실패했습니다.", + "testSuccess": "연결 테스트를 통과했습니다.", + "testFailed": "연결 테스트에 실패했습니다", + "deleteSuccess": "채널이 삭제되었습니다.", + "deleteFailed": "채널 삭제에 실패했습니다.", + "deleteConfirmTitle": "채널 삭제", + "deleteConfirmMessage": "이 채널과 메시지 기록이 영구 삭제됩니다. 계속하시겠습니까?", + "cancel": "취소", + "delete": "삭제", + "create": "생성", + "save": "저장", + "channelListTitle": "설정된 채널", + "channelListDescription": "활성화된 채널은 서비스 시작 시 자동으로 연결됩니다.", + "editChannel": "채널 편집", + "editSuccess": "채널이 업데이트되었습니다.", + "tokenPlaceholderKeep": "비워두면 현재 값 유지", + "weixinScanTitle": "QR 코드 스캔", + "weixinScanDescription": "WeChat을 열고 QR 코드를 스캔하여 연결하세요.", + "weixinQrcodeExpired": "QR 코드가 만료되었습니다.", + "weixinRefreshQrcode": "새로고침", + "weixinWaitingScan": "스캔 대기 중...", + "weixinPollError": "연결이 불안정합니다. 재시도 중...", + "weixinReconnectNotice": "iLink 프로토콜 제한으로 인해, 재연결할 때마다 먼저 봇에게 메시지를 보내야 이벤트 트리거가 활성화됩니다.", + "connect": "연결", + "disconnect": "연결 해제", + "test": "연결 테스트", + "tabs": { + "channels": "채널", + "commands": "명령어", + "events": "이벤트", + "other": "기타" + }, + "commands": { + "title": "내장 명령어", + "description": "채팅 채널에서 사용 가능한 Bot 명령어입니다. 그룹 채팅에서는 메시지를 처리하려면 @Bot이 필요합니다.", + "prefixLabel": "명령어 접두사", + "prefixDescription": "Bot 명령어를 실행하는 접두사, 1-3개의 영숫자가 아닌 문자 (기본값 /).", + "prefixSaved": "명령어 접두사가 저장되었습니다.", + "prefixSaveFailed": "명령어 접두사 저장에 실패했습니다.", + "prefixInvalid": "접두사는 1-3개의 영숫자가 아닌 문자여야 합니다.", + "save": "저장", + "folderDesc": "작업 폴더 선택", + "agentDesc": "AI 에이전트 선택", + "taskDesc": "세션 생성 및 작업 실행", + "sessionsDesc": "폴더 내 활성 세션 목록", + "resumeDesc": "최근 대화 / 세션 재개", + "cancelDesc": "현재 작업 취소", + "approveDesc": "에이전트 권한 요청 승인", + "denyDesc": "에이전트 권한 요청 거부", + "searchDesc": "키워드로 대화 검색", + "todayDesc": "오늘의 활동 요약", + "statusDesc": "채널 연결 상태", + "helpDesc": "도움말 표시" + }, + "events": { + "title": "이벤트 알림", + "description": "이벤트를 활성화하면, 트리거 시 채널로 푸시됩니다.", + "turnComplete": "턴 완료", + "turnCompleteDesc": "에이전트 턴이 종료될 때", + "error": "에이전트 오류", + "errorDesc": "에이전트에 오류가 발생했을 때", + "permissionRequest": "권한 요청", + "permissionRequestDesc": "에이전트가 작업 권한을 요청할 때", + "questionRequest": "에이전트 질문", + "questionRequestDesc": "에이전트가 질문할 때", + "userPromptSent": "사용자 메시지", + "userPromptSentDesc": "메시지를 보낼 때 — 알림에 메시지 내용이 포함됩니다", + "saved": "이벤트 필터가 업데이트되었습니다.", + "saveFailed": "이벤트 필터 저장에 실패했습니다.", + "loadFailed": "설정을 불러오지 못했습니다.", + "retry": "다시 시도", + "webhooksTitle": "Webhook", + "webhooksDescription": "활성화된 이벤트가 발생하면 하나 이상의 URL로 JSON을 POST합니다. 위의 이벤트 필터는 Webhook에도 적용됩니다.", + "webhookUrlPlaceholder": "https://example.com/webhook", + "addWebhook": "Webhook 추가", + "removeWebhook": "Webhook 삭제", + "webhookSave": "저장", + "webhooksSaved": "Webhook을 저장했습니다.", + "webhooksSaveFailed": "Webhook 저장에 실패했습니다.", + "webhookInvalidUrl": "유효한 http(s) URL을 입력하세요.", + "docsTitle": "요청 형식", + "docsMethod": "메서드", + "docsContentType": "Content-Type", + "docsNote": "활성화된 각 이벤트는 모든 URL로 전달됩니다. Webhook은 디바운스되지 않으며 위의 이벤트 필터가 계속 적용됩니다.", + "editWebhook": "Webhook 편집", + "enableWebhook": "Webhook 활성화", + "webhookDuplicate": "이미 설정된 URL입니다.", + "cancel": "취소", + "webhooksEmpty": "아직 구성된 Webhook이 없습니다.", + "deleteWebhookTitle": "Webhook 삭제", + "deleteWebhookMessage": "이 Webhook을 삭제하시겠습니까? 이 URL로 더 이상 이벤트가 전달되지 않습니다.", + "delete": "삭제" + }, + "language": { + "title": "메시지 언어", + "description": "이벤트 알림, 명령 응답, 일일 보고서를 채팅 채널로 전송할 때 사용하는 언어입니다.", + "saved": "메시지 언어가 저장되었습니다.", + "saveFailed": "메시지 언어 저장에 실패했습니다.", + "en": "영어", + "zh-cn": "중국어 간체", + "zh-tw": "중국어 번체", + "ja": "일본어", + "ko": "한국어", + "es": "스페인어", + "de": "독일어", + "fr": "프랑스어", + "pt": "포르투갈어", + "ar": "아랍어" + } + }, + "ModelProviderSettings": { + "sectionTitle": "모델 제공업체", + "sectionDescription": "에이전트의 API 제공업체 자격 증명을 관리합니다.", + "filterAll": "전체", + "providerListTitle": "구성된 제공업체", + "addProvider": "제공업체 추가", + "editProvider": "제공업체 편집", + "noProviders": "아직 구성된 모델 제공업체가 없습니다.", + "providerName": "이름", + "providerNamePlaceholder": "예: OpenAI, Anthropic", + "apiUrl": "API URL", + "apiUrlPlaceholder": "https://api.openai.com/v1", + "apiKey": "API 키", + "apiKeyPlaceholder": "sk-...", + "apiKeyKeepCurrent": "현재 값을 유지하려면 비워두세요", + "agentTypes": "에이전트 유형", + "agentTypesRequired": "최소 하나의 에이전트 유형을 선택하세요.", + "agentType": "에이전트 유형", + "agentTypeRequired": "에이전트 유형을 선택하세요.", + "agentTypeImmutableHint": "에이전트 유형은 생성 후 변경할 수 없습니다.", + "model": "모델", + "modelPlaceholderCodex": "gpt-5.6-sol / gpt-5.5", + "modelPlaceholderGemini": "gemini-3-pro-preview", + "claudeMainModel": "메인 모델", + "claudeReasoningModel": "추론 모델 (사고)", + "claudeHaikuDefaultModel": "기본 Haiku 모델", + "claudeSonnetDefaultModel": "기본 Sonnet 모델", + "claudeOpusDefaultModel": "기본 Opus 모델", + "claudeCustomModelOption": "사용자 지정 모델 ID", + "claudeCustomModelOptionName": "사용자 지정 모델 이름", + "claudeCustomModelOptionDescription": "사용자 지정 모델 설명", + "claudeCustomModelOptionHint": "Claude 모델 선택기에 사용자 지정 항목 하나를 추가합니다(예: 사용자 지정 게이트웨이/프록시를 통해 제공되는 모델). 이름과 설명은 선택적 표시 설정입니다.", + "nameRequired": "제공업체 이름은 필수입니다.", + "apiUrlRequired": "API URL은 필수입니다.", + "apiKeyRequired": "API 키는 필수입니다.", + "loadFailed": "제공업체를 불러오지 못했습니다.", + "saveFailed": "변경 사항을 저장하지 못했습니다.", + "createSuccess": "제공업체가 생성되었습니다.", + "editSuccess": "제공업체가 업데이트되었습니다.", + "deleteSuccess": "제공업체가 삭제되었습니다.", + "deleteConfirmTitle": "제공업체 삭제", + "deleteConfirmMessage": "제공업체 \"{name}\"을(를) 영구적으로 삭제하시겠습니까?", + "deleteBlockedByAgent": "{agents}이(가) 이 공급자를 사용 중입니다. 삭제하기 전에 연결을 해제해 주세요.", + "cancel": "취소", + "delete": "삭제", + "create": "생성", + "save": "저장", + "affectedRunningSessions": "{count}개의 실행 중인 세션은 다시 연결하면 변경 사항이 적용됩니다" + }, + "SkillMatrix": { + "loading": "불러오는 중…", + "searchPlaceholder": "이름, ID 또는 설명으로 검색", + "empty": "표시할 항목이 없습니다.", + "emptySearch": "현재 검색과 일치하는 항목이 없습니다.", + "skillColumn": "스킬", + "selectAll": "표시된 항목 모두 선택", + "selectSkill": "{name} 선택", + "everything": { + "label": "일괄", + "enable": "모두 활성화(표시된 항목)", + "disable": "모두 비활성화(표시된 항목)" + }, + "columnMenu": { + "enableAll": "모든 스킬 활성화", + "disableAll": "모든 스킬 비활성화" + }, + "rowMenu": { + "label": "{name} 일괄 작업", + "enableAll": "모든 에이전트에 활성화", + "disableAll": "모든 에이전트에서 비활성화" + }, + "bulk": { + "selected": "{count}개 선택됨", + "targetAll": "모든 에이전트", + "targetSome": "에이전트 {count}개", + "enable": "활성화", + "disable": "비활성화", + "clear": "지우기" + }, + "confirm": { + "disableTitle": "이 링크를 비활성화할까요?", + "disableBody": "codeg가 관리하는 스킬 링크 {count}개를 제거합니다. 사용자 지정 디렉터리를 차지한 스킬은 그대로 유지됩니다. 언제든지 다시 활성화할 수 있습니다.", + "cancel": "취소", + "confirm": "비활성화" + }, + "toasts": { + "loadFailed": "스킬 상태를 불러오지 못했습니다", + "applyFailed": "변경 사항을 적용하지 못했습니다", + "enabled": "링크 {count}개를 활성화했습니다", + "disabled": "링크 {count}개를 비활성화했습니다", + "enabledPartial": "{ok}개 활성화, {failed}개 실패", + "disabledPartial": "{ok}개 비활성화, {failed}개 실패" + }, + "detail": { + "enableForAgents": "에이전트에 활성화", + "preview": "SKILL.md 미리보기", + "loadingContent": "콘텐츠 불러오는 중…" + }, + "copyModeHint": "복사됨(링크 아님) — 업데이트 후 최신 버전을 받으려면 다시 활성화하세요" + }, + "ExpertsSettings": { + "title": "전문가 스킬", + "description": "AI 코딩 에이전트를 위해 엄선되고 실전 검증된 스킬 워크플로를 활성화하세요. 각 전문가는 superpowers 프로젝트의 독립 실행형 스킬이며 — codeg가 중앙 복사본을 관리하고 선택한 에이전트에 연결합니다.", + "loading": "전문가 로딩 중…", + "loadingContent": "콘텐츠 로딩 중…", + "emptyExperts": "사용 가능한 전문가가 없습니다. 애플리케이션 로그를 확인하세요.", + "emptySelection": "전문가를 선택하여 내용을 보고 활성화를 관리하세요.", + "emptySearch": "현재 검색과 일치하는 전문가가 없습니다.", + "searchPlaceholder": "이름, ID 또는 설명으로 전문가 검색", + "enableForAgents": "에이전트에 활성화", + "noAgents": "ACP 에이전트가 감지되지 않았습니다.", + "copyModeWarning": "복사됨(연결되지 않음). 최신 버전을 받으려면 codeg 업데이트 후 재활성화하세요.", + "previewTitle": "SKILL.md 미리보기", + "categories": { + "discovery": "발견 및 설계", + "planning": "계획", + "execution": "실행", + "quality": "품질 및 테스트", + "debugging": "디버깅", + "review": "검토 및 통합", + "meta": "메타" + }, + "states": { + "not_linked": "활성화되지 않음", + "linked_to_codeg": "활성화됨", + "linked_elsewhere": "차단됨 — 다른 링크가 존재함", + "blocked_by_real_directory": "차단됨 — 사용자 정의 스킬이 이 이름을 점유 중", + "broken": "손상된 링크" + }, + "badges": { + "userModified": "사용자가 수정함" + }, + "actions": { + "openCentralDir": "중앙 폴더 열기", + "refresh": "새로고침" + }, + "toasts": { + "loadFailed": "전문가 세부 정보를 로드하지 못했습니다", + "enabled": "이 에이전트에 전문가가 활성화되었습니다", + "disabled": "이 에이전트에서 전문가가 비활성화되었습니다", + "enableFailed": "전문가 활성화에 실패했습니다", + "disableFailed": "전문가 비활성화에 실패했습니다", + "openFolderFailed": "폴더를 열지 못했습니다" + } + }, + "ScienceSettings": { + "title": "과학 연구 스킬", + "description": "AI 코딩 에이전트를 위한 엄선된 과학 연구 스킬(가설 생성, 실험 설계, 통계, 시각화, 비판적 평가, 문헌 검색)을 활성화합니다. codeg가 중앙 복사본을 관리하고 선택한 에이전트에 각 스킬을 연결합니다.", + "loading": "과학 연구 스킬 불러오는 중…", + "emptySkills": "사용 가능한 과학 연구 스킬이 없습니다. 애플리케이션 로그를 확인하세요.", + "searchPlaceholder": "이름, ID 또는 설명으로 과학 연구 스킬 검색", + "categories": { + "ideation": "아이디어", + "design": "연구 설계", + "analysis": "분석", + "visualization": "시각화", + "evaluation": "평가", + "literature": "문헌" + }, + "states": { + "not_linked": "활성화되지 않음", + "linked_to_codeg": "활성화됨", + "linked_elsewhere": "차단됨 — 다른 링크가 존재함", + "blocked_by_real_directory": "차단됨 — 사용자 정의 스킬이 이 이름을 점유 중", + "broken": "손상된 링크" + }, + "badges": { + "userModified": "사용자가 수정함", + "needsKey": "API 키 필요", + "needsSetup": "설정 필요할 수 있음" + }, + "actions": { + "openCentralDir": "중앙 폴더 열기", + "refresh": "새로고침" + }, + "toasts": { + "openFolderFailed": "폴더를 열지 못했습니다" + } + }, + "OfficeToolsSettings": { + "title": "Office 도구", + "description": "OfficeCLI 스킬을 관리하여 Excel, Word, PowerPoint 파일을 생성합니다. OfficeCLI를 설치하고 스킬을 동기화한 후 에이전트별로 활성화할 수 있습니다.", + "loadingContent": "콘텐츠 로드 중…", + "emptySkills": "스킬이 없습니다. OfficeCLI를 설치하고 스킬을 동기화하세요.", + "emptySelection": "스킬을 선택하여 내용을 확인하고 활성화를 관리합니다.", + "emptySearch": "검색과 일치하는 스킬이 없습니다.", + "searchPlaceholder": "이름, ID 또는 설명으로 스킬 검색", + "enableForAgents": "에이전트에 활성화", + "noAgents": "ACP 에이전트가 감지되지 않았습니다.", + "installFirst": "스킬을 활성화하려면 먼저 OfficeCLI를 설치하세요.", + "syncFirst": "콘텐츠를 로드하려면 먼저 스킬을 동기화하세요.", + "noContent": "콘텐츠가 없습니다.", + "copyModeWarning": "복사됨(링크 아님). 최신 버전을 가져오려면 다시 동기화하세요.", + "previewTitle": "SKILL.md 미리보기", + "detection": { + "installed": "설치됨", + "notInstalled": "미설치", + "notRunnable": "설치됨, 실행 불가", + "installHint": "OfficeCLI를 설치하여 AI 에이전트에 오피스 문서 생성 스킬을 활성화합니다.", + "install": "설치", + "uninstall": "제거", + "syncSkills": "스킬 동기화" + }, + "categories": { + "general": "일반", + "presentations": "프레젠테이션", + "documents": "문서", + "spreadsheets": "스프레드시트" + }, + "states": { + "not_linked": "비활성", + "linked_to_codeg": "활성", + "linked_elsewhere": "차단됨 — 다른 링크가 존재합니다", + "blocked_by_real_directory": "차단됨 — 사용자 정의 스킬이 이 이름을 사용 중", + "broken": "링크 끊김" + }, + "badges": { + "notSynced": "미동기화" + }, + "actions": { + "refresh": "새로고침" + }, + "toasts": { + "loadFailed": "스킬 상세 로드 실패", + "enabled": "이 에이전트에 스킬 활성화됨", + "disabled": "이 에이전트에서 스킬 비활성화됨", + "enableFailed": "스킬 활성화 실패", + "disableFailed": "스킬 비활성화 실패", + "installSuccess": "OfficeCLI 설치 성공", + "installFailed": "OfficeCLI 설치 실패", + "uninstallSuccess": "OfficeCLI 제거됨", + "uninstallFailed": "OfficeCLI 제거 실패", + "syncSuccess": "{synced}개 스킬 동기화 완료", + "syncPartial": "{synced}개 동기화, {errors}개 실패", + "syncFailed": "스킬 동기화 실패" + }, + "autoPreviewLabel": "미리보기 자동 열기", + "autoPreviewHint": "에이전트가 Word, Excel, PowerPoint 파일을 만들거나 편집하면 실시간 미리보기를 자동으로 엽니다." + }, + "SkillPacksSettings": { + "title": "스킬 팩", + "description": "codeg가 중앙에서 관리하고 각 AI 에이전트에 연결하는 엄선된 스킬 모음입니다 — 코딩 전문가, 과학 연구, 오피스 문서 도구. 아래에서 에이전트별로 활성화하세요.", + "tabs": { + "experts": "전문가", + "science": "과학 연구", + "office": "오피스 도구", + "custom": "사용자 지정" + }, + "actions": { + "openCentralDir": "중앙 폴더 열기", + "refresh": "새로고침" + }, + "toasts": { + "openFolderFailed": "폴더를 열지 못했습니다" + } + }, + "QuickMessagesSettings": { + "title": "빠른 메시지", + "description": "재사용 가능한 메시지 스니펫을 관리합니다. 드래그하여 순서를 변경하세요.", + "loading": "빠른 메시지 불러오는 중…", + "emptyList": "빠른 메시지가 없습니다. \"새로 만들기\"를 클릭하여 추가하세요.", + "emptySelection": "편집할 빠른 메시지를 선택하세요.", + "searchPlaceholder": "제목 또는 내용으로 검색", + "untitled": "제목 없음", + "actions": { + "new": "새로 만들기", + "save": "저장", + "delete": "삭제", + "dragSort": "드래그하여 순서 변경", + "dragSortMessage": "빠른 메시지 순서 변경: {name}" + }, + "fields": { + "title": "제목", + "titlePlaceholder": "이 메시지에 짧은 제목을 지정하세요", + "content": "내용", + "contentPlaceholder": "여기에 메시지 내용을 입력하세요" + }, + "confirmDelete": { + "title": "빠른 메시지를 삭제하시겠습니까?", + "message": "\"{name}\" 이(가) 영구적으로 삭제됩니다. 계속하시겠습니까?", + "cancel": "취소", + "confirm": "삭제" + }, + "toasts": { + "loadFailed": "빠른 메시지를 불러오지 못했습니다", + "createFailed": "빠른 메시지를 만들지 못했습니다", + "saveFailed": "빠른 메시지를 저장하지 못했습니다", + "deleteFailed": "빠른 메시지를 삭제하지 못했습니다", + "saveOrderFailed": "순서를 저장하지 못했습니다", + "created": "빠른 메시지가 생성되었습니다", + "saved": "빠른 메시지가 저장되었습니다", + "deleted": "빠른 메시지가 삭제되었습니다" + } + }, + "Pet": { + "badge": { + "running": "실행 중 {count}개", + "waiting": "승인 대기 {count}개", + "error": "오류 {count}개" + }, + "panel": { + "title": "활성 세션", + "empty": "활성 세션 없음", + "emptyHint": "실행 중이거나 사용자의 조치가 필요한 세션이 여기에 표시됩니다.", + "statusRunning": "실행 중", + "statusWaiting": "대기 중", + "statusError": "오류", + "subAgentOf": "하위 에이전트" + }, + "menu": { + "scale": "크기", + "openManager": "펫 관리", + "close": "닫기" + }, + "loadError": "펫을 불러오지 못했습니다", + "missingPetIdParam": "선택된 펫이 없습니다", + "summonButton": "펫", + "manager": { + "title": "데스크톱 펫", + "description": "Codex 호환 스프라이트 시트로 동작하는 데스크톱 동반자.", + "addPet": "펫 추가", + "importFromCodex": "Codex 에서 가져오기", + "noPets": "펫이 아직 없습니다. 새로 추가하거나 Codex 에서 가져오세요.", + "setActive": "활성화", + "active": "활성", + "edit": "편집", + "delete": "삭제", + "deleteConfirm": "펫 \"{name}\"을(를) 삭제할까요? 디스크에서도 함께 제거됩니다.", + "summon": "펫 창 호출", + "openCodexHelp": "Codex 펫은 ~/.codex/pets/ 아래에 설치되어야 합니다. 찾을 수 없습니다.", + "specRequirement": "스프라이트 시트는 너비 1536px, 높이는 208px의 배수(예: 1872 또는 2288)인 투명 PNG 또는 WebP여야 합니다.", + "form": { + "id": "펫 ID", + "idHelp": "소문자/숫자/'-'/'_' 만 가능. 최대 64자.", + "displayName": "표시 이름", + "description": "설명 (선택)", + "spritesheet": "스프라이트 시트", + "chooseFile": "파일 선택", + "replaceFile": "스프라이트 교체", + "saveCreate": "펫 추가", + "saveUpdate": "변경 저장", + "cancel": "취소" + }, + "errors": { + "missingId": "펫 ID 는 필수입니다", + "missingName": "표시 이름은 필수입니다", + "missingSpritesheet": "스프라이트 시트는 필수입니다", + "addFailed": "펫 추가에 실패했습니다", + "updateFailed": "펫 갱신에 실패했습니다", + "deleteFailed": "펫 삭제에 실패했습니다", + "loadFailed": "펫 목록 로드에 실패했습니다", + "setActiveFailed": "활성 펫 설정에 실패했습니다", + "summonFailed": "펫 창 호출에 실패했습니다" + } + }, + "import": { + "title": "Codex 에서 가져오기", + "subtitle": "~/.codex/pets/ 에서 발견된 펫 목록입니다.", + "selectAll": "전체 선택", + "alreadyImported": "이미 가져옴", + "renameOnConflict": "충돌 시 -imported 접미어로 이름 변경", + "import": "선택 항목 가져오기", + "noneFound": "가져올 수 있는 Codex 펫이 없습니다.", + "imported": "가져오기 완료", + "failed": "가져오기 실패", + "close": "닫기" + }, + "marketplace": { + "openMarketplace": "펫 마켓", + "title": "펫 마켓", + "search": "펫 검색", + "kindFilter": { + "all": "전체", + "object": "오브젝트", + "animal": "동물", + "person": "인물", + "creature": "생물" + }, + "sortFilter": { + "latest": "최신", + "popular": "인기", + "views": "조회수순" + }, + "refresh": "새로고침", + "install": "설치", + "installing": "설치 중", + "reinstall": "다시 설치", + "reinstallConfirm": "로컬 펫 \"{name}\" 을(를) 덮어쓰시겠습니까? 기존 데이터가 교체됩니다.", + "cancel": "취소", + "stats": { + "views": "조회수", + "downloads": "다운로드", + "likes": "좋아요" + }, + "actions": { + "idle": "대기", + "running_right": "오른쪽 달리기", + "running_left": "왼쪽 달리기", + "waving": "손 흔들기", + "jumping": "점프", + "failed": "실패", + "waiting": "기다림", + "running": "실행", + "review": "리뷰" + }, + "page": "{page} / {total} 페이지", + "prev": "이전", + "next": "다음", + "empty": "조건에 맞는 펫이 없습니다.", + "successInstalled": "\"{name}\" 을(를) 설치했습니다", + "errors": { + "loadFailed": "마켓을 불러오지 못했습니다", + "installFailed": "설치에 실패했습니다", + "alreadyInstalled": "해당 펫이 이미 존재합니다" + } + } + }, + "RemoteWorkspace": { + "openRemoteWorkspace": "Open remote workspace", + "manage": "Manage remote workspace", + "manageTitle": "Remote Workspace connections", + "empty": "No remote connections", + "searchPlaceholder": "Search remote workspaces", + "orderFailed": "Failed to save remote workspace order", + "dragSort": "Drag to sort", + "dragSortConnection": "Drag to sort {name}", + "newConnection": "New connection", + "loading": "Loading", + "loadingConnection": "Loading remote connection", + "name": "Name", + "baseUrl": "Service URL", + "token": "Access token", + "save": "Save", + "delete": "Delete", + "confirmDelete": { + "title": "Delete remote connection?", + "message": "This will remove \"{name}\" from this device. This action cannot be undone.", + "cancel": "Cancel", + "confirm": "Delete" + }, + "saved": "Remote connection saved.", + "deleted": "Remote connection deleted.", + "loadFailed": "Failed to load remote connections", + "saveFailed": "Failed to save remote connection", + "deleteFailed": "Failed to delete remote connection", + "openFailed": "Failed to open remote workspace", + "connectionLoadFailed": "Failed to load remote connection: {message}", + "connectionExpired": "Remote connection \"{name}\" is expired. Update its token and reload this window." + }, + "ServerFileBrowser": { + "title": "서버 파일 선택", + "pathPlaceholder": "디렉토리 경로 입력...", + "goHome": "홈 디렉토리로", + "navigateUp": "상위 디렉토리로", + "select": "선택", + "cancel": "취소", + "loading": "로드 중...", + "emptyDirectory": "이 디렉토리는 비어 있습니다", + "errorLoadingDir": "디렉토리 로드 실패", + "selectedCount": "{count}개 선택됨" + }, + "BackupSettings": { + "title": "백업 및 복원", + "description": "codeg 데이터의 이동 가능한 백업을 내보내거나 백업에서 복원합니다.", + "tabs": { + "backup": "백업", + "restore": "복원" + }, + "export": { + "includeExternal": "대화 내용 포함", + "includeExternalHint": "각 CLI의 대화 기록(Claude, Codex, Gemini 등)도 함께 보관합니다. 용량이 커집니다.", + "passphrase": "암호문 (선택)", + "passphrasePlaceholder": "비워 두면 암호화하지 않습니다", + "passphraseConfirm": "암호문 확인", + "passphraseMismatch": "암호문이 일치하지 않습니다.", + "noPassphraseWarning": "이 백업에는 비밀 정보(API 키, 토큰)가 평문으로 포함됩니다. 안전한 곳에 보관하세요.", + "passphraseLossWarning": "이 암호문으로 암호화됩니다. 분실하면 백업을 복구할 수 없습니다.", + "button": "백업 내보내기", + "inProgress": "백업 만드는 중…", + "success": "백업을 만들었습니다.", + "started": "백업 다운로드를 시작했습니다." + }, + "restore": { + "selectFile": "백업 파일 선택", + "passphrasePrompt": "이 백업은 암호화되어 있습니다. 암호문을 입력하세요.", + "unlock": "잠금 해제", + "preview": { + "title": "백업 정보", + "encrypted": "암호화됨", + "compatible": "호환됨", + "incompatible": "호환되지 않음", + "createdAt": "생성: {value}", + "appVersion": "앱 버전: {value}", + "incompatibleHint": "이 백업은 더 새로운 버전의 codeg에서 만들어져 복원할 수 없습니다." + }, + "replaceWarning": "복원하면 현재의 모든 codeg 데이터(데이터베이스 및 업로드)가 교체됩니다. 현재 데이터는 먼저 스냅샷되어 복구할 수 있습니다.", + "keyringNote": "데스크톱의 GitHub/채팅 토큰은 OS 키체인에 저장되어 포함되지 않습니다. 복원 후 다시 입력하세요.", + "button": "복원", + "staging": "복원 준비 중…", + "staged": "복원이 준비되었습니다. 다시 시작합니다…", + "restarting": "복원이 준비되었습니다. 서버를 다시 시작합니다…", + "restartTimeout": "서버가 제때 돌아오지 않았습니다. 서버가 켜지면 페이지를 새로 고치세요.", + "externalSideLocation": "대화 기록을 {path}에 복원했습니다", + "confirmTitle": "모든 데이터를 교체할까요?", + "confirmBody": "현재 codeg 데이터베이스와 업로드를 백업으로 교체한 후 다시 시작합니다. 현재 데이터는 먼저 스냅샷됩니다.", + "cancel": "취소", + "confirmAction": "교체 후 다시 시작", + "external": { + "title": "대화 내용", + "hint": "이 백업에는 CLI 대화 기록이 포함됩니다. 복원 위치를 선택하세요.", + "modeSkip": "복원 안 함", + "modeSide": "안전한 별도 폴더에 복원", + "modeOriginal": "CLI 원래 위치에 복원", + "forceOverwrite": "기존 파일 덮어쓰기", + "forceOverwriteHint": "CLI 폴더에 이미 있는 파일을 교체합니다.", + "scanning": "충돌 확인 중…", + "noConflicts": "덮어쓸 기존 파일이 없습니다.", + "conflictCount": "기존 파일 {count}개가 영향을 받습니다.", + "conflictSkipNote": "덮어쓰기를 켜지 않으면 기존 파일은 유지(건너뜀)됩니다." + }, + "restartFailed": "복원이 준비되었지만 서버를 다시 시작하지 못했습니다. 수동으로 다시 시작해 복원을 적용하세요." + }, + "remoteUnsupported": "백업 및 복원은 codeg를 실행 중인 컴퓨터의 데이터를 대상으로 합니다. 현재 원격 작업 공간에 연결되어 있습니다. 해당 서버에서 직접 백업을 관리하세요." + }, + "backup": { + "restore": { + "error": { + "badPassphrase": "암호문이 올바르지 않거나 백업이 손상되었습니다.", + "corrupted": "백업 아카이브가 손상되었습니다.", + "unknownFormat": "이 파일은 인식할 수 있는 codeg 백업이 아닙니다.", + "newerVersion": "이 백업은 codeg {backupVersion}에서 만들어졌으며 현재 버전({appVersion})보다 최신입니다.", + "alreadyPending": "적용 대기 중인 복원이 이미 있습니다. 먼저 다시 시작해 적용한 뒤 새 복원을 준비하세요." + } + }, + "error": { + "diskSpace": "작업을 완료할 디스크 공간이 부족합니다.", + "cancelled": "작업이 취소되었습니다." + } + }, + "WebConnection": { + "disconnectedTitle": "연결이 끊어졌습니다", + "reconnectingDescription": "서버에 다시 연결하는 중입니다. 보통 몇 초 내에 자동으로 복구됩니다.", + "reconnectNow": "지금 다시 연결", + "sessionExpiredTitle": "세션이 만료되었습니다", + "sessionExpiredDescription": "세션이 더 이상 유효하지 않습니다. 계속하려면 다시 로그인하세요.", + "goToLogin": "로그인으로 이동" + }, + "LiveFeedback": { + "placeholder": "{agent}이(가) 작업하는 동안 메모 보내기…", + "agentFallback": "에이전트", + "ariaLabel": "라이브 피드백 메모", + "dialogTitle": "라이브 피드백", + "dialogDescription": "에이전트가 작업하는 동안 메모를 보냅니다. 현재 단계를 중단하지 않고 다음 확인 시 읽습니다.", + "dialogDescriptionInstant": "에이전트가 작업하는 동안 메모를 보냅니다. 메모는 현재 턴에 즉시 삽입되어 에이전트가 바로 확인합니다.", + "channelDowngraded": "이 세션에서는 즉시 삽입을 사용할 수 없습니다. 메모는 저장되어 에이전트가 다음에 확인할 때 전달됩니다.", + "send": "보내기", + "cancel": "취소", + "pending": "대기 중", + "delivered": "수신됨", + "turnEndedUnread": "에이전트가 피드백을 읽기 전에 턴을 마쳤습니다.", + "sendAsMessage": "새 메시지로 보내기", + "dismiss": "닫기", + "turnEndedResent": "턴이 종료되어 새 메시지로 보냈습니다.", + "turnEnded": "턴이 이미 종료되었습니다.", + "submitFailed": "메모를 보내지 못했습니다" + }, + "AgentToolsSettings": { + "title": "대화 내 도구", + "description": "codeg가 대화 안에서 에이전트에게 추가로 제공하는 도구입니다. 에이전트가 시작할 때 주입되므로 변경 사항은 이후에 시작한 에이전트부터 적용됩니다.", + "feedbackLabel": "라이브 피드백", + "feedbackHint": "에이전트가 작업하는 동안 메모와 수정 사항을 보낼 수 있습니다. 즉시 삽입을 지원하는 에이전트는 실행 중인 턴에 메모가 바로 삽입됩니다. 그 외 에이전트는 피드백 확인 도구로 읽는데, 보통 프롬프트에서 언급할 때만 확인합니다. 예: 메시지에 \"실시간 피드백을 정기적으로 확인해\"를 추가하세요.", + "questionLabel": "사용자에게 질문", + "questionHint": "에이전트가 작업을 멈추고 대화 입력창 위에 표시되는 객관식 질문을 할 수 있습니다. 답변(또는 건너뛰기)할 때까지 에이전트는 대기합니다.", + "sessionInfoLabel": "세션 정보 가져오기", + "sessionInfoHint": "메시지에서 참조한 세션(세션 배지)을 에이전트가 조회하여 제목, 에이전트, 상태, 작업 공간, 토큰 사용량, 최근 메시지를 읽을 수 있도록 합니다.", + "automationsLabel": "자동화 만들기", + "automationsHint": "대화를 일정에 따라 실행되는 자동화로 저장합니다. 기본값은 꺼짐 — 자동화는 이후 스스로 에이전트를 시작합니다.", + "workTasksLabel": "할 일 작업 만들기", + "workTasksHint": "대화에서 할 일 보드에 카드를 추가합니다. 기본값은 꺼짐 — 앱 상태를 기록합니다.", + "save": "저장", + "saving": "저장 중…", + "saved": "도구 설정을 저장했습니다", + "saveFailed": "도구 설정 저장에 실패했습니다", + "loadFailed": "불러오기 실패: {detail}" + }, + "NotificationSoundSettings": { + "title": "알림음", + "description": "에이전트 이벤트가 발생하면 짧은 알림음을 재생합니다. 채팅 채널로 전송되는 것과 같은 이벤트이며, 이 설정은 이 기기에만 적용됩니다.", + "enableHint": "기본값은 꺼짐입니다. 알림음은 이 브라우저 또는 앱의 작업 공간 창에서만 재생됩니다.", + "volume": "음량", + "preview": "미리 듣기", + "previewEvent": "{event} 알림음 미리 듣기", + "onlyWhenUnfocused": "창이 활성화되지 않았을 때만 재생", + "onlyWhenUnfocusedHint": "Codeg을 보고 있는 동안에는 소리를 내지 않습니다.", + "eventsTitle": "이벤트", + "eventsHint": "이벤트마다 소리를 선택하세요. “무음”을 선택하면 재생하지 않습니다. 같은 이벤트가 몇 초 안에 반복되면 한 번만 재생됩니다.", + "toneNone": "무음", + "toneChime": "차임", + "toneDing": "딩", + "toneBlip": "블립", + "tonePop": "팝", + "toneAlert": "알림", + "toneDescend": "하강음" + }, + "LogsSettings": { + "loading": "불러오는 중…", + "sectionTitle": "실행 로그", + "sectionDescription": "애플리케이션 진단 로그를 보고 구성합니다. 로그는 로컬 파일에 기록되며 실시간 보기를 위해 메모리에도 보관됩니다.", + "captureTitle": "로그 수준", + "captureDescription": "기록되는 상세 수준을 제어합니다. 수준이 높을수록(Debug, Trace) 더 많이 기록되지만 로그도 커집니다. '끔'은 로깅을 비활성화합니다.", + "captureLabel": "수집 수준", + "levels": { + "off": "끔", + "error": "오류", + "warn": "경고", + "info": "정보", + "debug": "디버그", + "trace": "추적" + }, + "viewerTitle": "최근 로그", + "viewerDescription": "최근 로그 레코드를 실시간으로 봅니다. 수준으로 필터링하거나 텍스트를 검색하세요.", + "searchPlaceholder": "메시지 또는 대상 검색…", + "viewLevels": { + "all": "모든 수준", + "error": "오류 이상", + "warn": "경고 이상", + "info": "정보 이상", + "debug": "디버그 이상", + "trace": "추적 이상" + }, + "pause": "일시정지", + "resume": "실시간", + "refresh": "새로고침", + "clear": "지우기", + "openFolder": "폴더 열기", + "shownCount": "{shown} / {total} 표시됨", + "empty": "표시할 로그가 없습니다.", + "levelSaveFailed": "로그 수준 저장 실패", + "openFolderFailed": "로그 폴더 열기 실패", + "downloadFailed": "로그 파일 다운로드 실패", + "filesTitle": "로그 파일", + "filesDescription": "실시간 버퍼를 넘어선 기록을 위해 디스크에서 전체 로그 파일을 다운로드합니다.", + "filesEmpty": "아직 로그 파일이 없습니다.", + "download": "다운로드", + "downloadTruncated": "파일이 커서 최신 {size}만 다운로드했습니다. 전체 파일은 로그 디렉터리에 있습니다.", + "captureEnvLocked": "로그 수준은 RUST_LOG / CODEG_LOG 환경 변수로 제어됩니다. 변경하려면 해당 변수를 수정하세요.", + "targetsTitle": "모듈별 재정의", + "targetsDescription": "전역 레벨을 바꾸지 않고 특정 모듈(예: codeg_lib::acp)의 레벨을 따로 설정합니다.", + "targetsAdd": "추가", + "targetsRemove": "재정의 제거", + "toggleDetails": "세부 정보 전환" + }, + "Automations": { + "title": "자동화", + "new": "새 자동화", + "empty": "아직 자동화가 없습니다", + "emptyHint": "하나를 만들어 에이전트 작업을 예약하거나 수동으로 실행하세요.", + "name": "이름", + "namePlaceholder": "예: 야간 PR 검토", + "prompt": "프롬프트", + "promptPlaceholder": "에이전트가 무엇을 하길 원하나요?", + "agent": "에이전트", + "folder": "워크스페이스 폴더", + "folderPlaceholder": "폴더 선택", + "isolation": "격리", + "isolationWorktree": "실행마다 새 worktree", + "isolationShared": "폴더에서 실행", + "isolationSharedCaveat": "실행이 이 폴더의 작업 트리를 직접 사용하므로 커밋하지 않은 변경 사항과 충돌할 수 있습니다. 각 실행을 격리하려면 워크트리 옵션을 활성화하세요.", + "trigger": "트리거", + "triggerSchedule": "예약 실행", + "triggerManual": "수동만", + "cron": "예약(cron)", + "cronPlaceholder": "0 9 * * 1-5", + "timezone": "시간대", + "nextRun": "다음 실행", + "branch": "브랜치", + "branchOptional": "브랜치(선택)", + "enabled": "사용", + "save": "저장", + "cancel": "취소", + "edit": "편집", + "delete": "삭제", + "runNow": "지금 실행", + "cancelRun": "실행 취소", + "runHistory": "실행 기록", + "noRuns": "아직 실행 기록이 없습니다", + "allFolders": "모든 폴더", + "filterAll": "전체", + "noMatches": "일치하는 자동화가 없습니다", + "viewConversation": "대화 보기", + "lastRun": "마지막 실행", + "never": "없음", + "running": "실행 중", + "deleteTitle": "이 자동화를 삭제할까요?", + "deleteDescription": "자동화와 예약이 삭제됩니다. 실행 기록은 유지됩니다.", + "statusRunning": "실행 중", + "statusSucceeded": "성공", + "statusFailed": "실패", + "statusCancelled": "취소됨", + "statusSkipped": "건너뜀", + "errorName": "이름은 필수입니다", + "errorPrompt": "프롬프트는 필수입니다", + "errorCron": "예약 자동화에는 cron 식이 필요합니다", + "errorFolder": "워크스페이스 폴더를 선택하세요", + "presetHourly": "매시간", + "presetDaily": "매일 오전 9시", + "presetWeekdays": "평일 오전 9시", + "presetCustom": "사용자 지정", + "probing": "옵션 불러오는 중…", + "retry": "다시 시도", + "configNone": "이 에이전트에는 구성 가능한 옵션이 없습니다", + "inherit": "에이전트 기본값", + "mode": "모드", + "config": "구성", + "branchPlaceholder": "(기본 브랜치)", + "selectHint": "세부 정보를 보려면 자동화를 선택하세요", + "refresh": "새로고침", + "onboardTitle": "반복적인 에이전트 작업 자동화", + "onboardHint": "코드 리뷰, 의존성 업데이트, 이슈 분류를 일정에 따라 또는 필요할 때 에이전트가 수행하도록 예약하세요.", + "headerSubtitle": "예약 및 온디맨드 에이전트 작업", + "startFromTemplate": "템플릿으로 시작", + "blankTitle": "빈 자동화", + "blankDesc": "에이전트 작업을 처음부터 구성합니다.", + "backToTemplates": "템플릿", + "sectionSchedule": "일정 및 대상", + "sectionTarget": "대상", + "sectionAction": "동작", + "actionLaunchSession": "세션 시작", + "actionEnqueueTask": "작업 대기열에 추가", + "actionEnqueueTaskHint": "실행될 때마다 이 자동화 이름을 제목으로 하는 할 일 작업이 대상 폴더의 할 일 목록에 추가되며, 작업 엔진이 보드 설정에 따라 실행합니다.", + "sectionPrompt": "프롬프트", + "nextIn": "{rel} 후 실행", + "manual": "수동", + "schedEveryMinutes": "{n}분마다", + "schedHourly": "1시간마다", + "schedDaily": "매일 {time}", + "schedWeekdays": "평일 {time}", + "schedWeekly": "매주 {day} {time}", + "schedMonthly": "매월 {day}일 {time}", + "dow0": "일요일", + "dow1": "월요일", + "dow2": "화요일", + "dow3": "수요일", + "dow4": "목요일", + "dow5": "금요일", + "dow6": "토요일", + "tplCodeReviewTitle": "코드 리뷰", + "tplCodeReviewDesc": "최근 변경 사항에서 버그, 회귀, 품질 문제를 검토합니다.", + "tplDependencyUpdatesTitle": "의존성 업데이트", + "tplDependencyUpdatesDesc": "오래된 의존성을 찾아 안전한 업그레이드를 제안합니다.", + "tplTestCoverageTitle": "테스트 커버리지", + "tplTestCoverageDesc": "테스트되지 않은 코드 경로를 찾아 누락된 테스트를 추가합니다.", + "tplTodoSweepTitle": "TODO 정리", + "tplTodoSweepDesc": "TODO와 FIXME 주석을 모아 우선순위에 따라 분류합니다.", + "tplCiTriageTitle": "CI 분류", + "tplCiTriageDesc": "최근 실패한 검사를 조사하고 수정을 제안합니다.", + "tplReleaseNotesTitle": "릴리스 노트", + "tplReleaseNotesDesc": "지난 릴리스 이후의 변경 사항을 요약해 변경 로그를 만듭니다.", + "tplSecurityAuditTitle": "보안 감사", + "tplSecurityAuditDesc": "취약점과 위험한 패턴을 스캔하고 결과를 보고합니다.", + "enable": "활성화", + "disable": "비활성화", + "moreActions": "추가 작업", + "statusDisabled": "비활성화됨", + "cronBuilderTitle": "일정 빌더", + "cronFreqLabel": "빈도", + "cronFreqMinutes": "N분마다", + "cronFreqHourly": "매시간", + "cronFreqDaily": "매일", + "cronFreqWeekdays": "평일", + "cronFreqWeekly": "매주", + "cronFreqMonthly": "매월", + "cronFreqCustom": "사용자 지정", + "cronEveryLabel": "간격(분)", + "cronTimeLabel": "시간", + "cronHourLabel": "시", + "cronMinuteLabel": "분", + "cronDowLabel": "요일", + "cronDomLabel": "일", + "cronApply": "적용", + "cronPreviewLabel": "미리 보기", + "cronOpenBuilder": "일정 빌더 열기", + "branchDefault": "기본 브랜치", + "branchUseCustom": "\"{query}\" 사용", + "branchLocal": "로컬", + "branchRemote": "원격", + "branchSearchPlaceholder": "브랜치 검색…", + "branchNone": "브랜치 없음" + }, + "Tasks": { + "title": "할 일", + "new": "새 작업", + "empty": "아직 작업이 없습니다", + "emptyHint": "할 일을 추가하고 실행하세요. 에이전트가 독립된 worktree에서 작업하고, 결과를 검토한 뒤 병합합니다.", + "emptyColTodo": "아직 할 일이 없습니다", + "emptyColInProgress": "진행 중인 작업이 없습니다", + "emptyColAttention": "처리할 작업이 없습니다", + "emptyColDone": "완료된 작업이 아직 없습니다", + "allFolders": "모든 폴더", + "showCanceled": "취소됨 표시", + "showArchived": "보관된 항목 표시", + "filter": "필터", + "viewSwitchToBoard": "보드 보기로 전환", + "viewSwitchToList": "목록 보기로 전환", + "statusFilter": "상태", + "statusFilterAll": "모든 상태", + "listEmpty": "현재 필터와 일치하는 작업이 없습니다", + "listColStatus": "상태", + "listColTask": "작업", + "listColLocation": "위치", + "listColChanges": "변경", + "listColUpdated": "업데이트", + "colTodo": "할 일", + "colInProgress": "진행 중", + "colAttention": "처리 필요", + "colDone": "완료", + "statusTodo": "할 일", + "statusQueued": "대기 중", + "statusPreparing": "준비 중", + "statusRunning": "실행 중", + "statusAwaitingInput": "입력 대기", + "statusReview": "검토 대기", + "statusMerging": "병합 중", + "statusDone": "완료", + "statusFailed": "실패", + "statusCanceled": "취소됨", + "statusInterrupted": "중단됨", + "badgeCleanupFailed": "정리 실패", + "badgeWorktreeKept": "worktree 유지", + "badgeWorktreeRemoved": "worktree 삭제됨", + "filesChanged": "{count}개 파일", + "actionStart": "시작", + "actionSchedule": "예약 실행", + "actionCancel": "취소", + "actionRetry": "다시 시도", + "actionRequeue": "다시 대기열에", + "actionViewSession": "대화 보기", + "actionEdit": "편집", + "actionDelete": "삭제", + "actionRetryCleanup": "정리 다시 시도", + "actionMerge": "병합", + "actionUnqueueMerge": "병합 대기 취소", + "actionEditQueuedMerge": "대기 중인 병합 수정", + "badgeMergeQueued": "병합 대기 중", + "badgeMergeQueuedRank": "병합 대기 · {rank}번째", + "badgeMergeQueuedHint": "이 프로젝트에서 진행 중인 병합이 끝나기를 기다리는 중이며, 차례가 되면 자동으로 시작합니다.", + "actionComplete": "완료", + "actionAbandon": "포기", + "cancelTitle": "작업을 취소할까요?", + "cancelDescription": "작업이 취소됨으로 바뀝니다. worktree는 그대로 두며 나중에 다시 대기열에 넣을 수 있습니다.", + "cancelReasonLabel": "취소 사유 (선택)", + "cancelReasonPlaceholder": "예: 방향이 잘못돼서 설명을 다시 쓸게요", + "cancelKeep": "그대로 두기", + "cancelSubmit": "작업 취소", + "restartTitleRetry": "작업 다시 시도", + "restartTitleRequeue": "작업 다시 대기열에", + "restartDescription": "메모(선택)를 남기면 다음 실행 프롬프트에 담겨 에이전트에게 전달됩니다.", + "scheduleTitle": "작업 실행 예약", + "scheduleDescription": "작업은 '할 일'에 남아 있다가 지정한 시각에 자동으로 시작됩니다. 폴더의 동시 실행 한도는 그대로 적용됩니다.", + "scheduleDateLabel": "날짜", + "schedulePickDate": "날짜 선택", + "scheduleTimeLabel": "시간", + "schedulePreview": "{time}에 실행", + "schedulePastHint": "이미 지난 시각입니다. 저장하면 바로 시작합니다.", + "scheduleInAnHour": "1시간 후", + "scheduleInThreeHours": "3시간 후", + "scheduleTomorrow": "내일 9:00", + "scheduleClear": "예약 해제", + "scheduleBadge": "{time}에 시작 예정", + "toastScheduled": "{time}에 실행하도록 예약했습니다", + "toastScheduleCleared": "예약을 해제했습니다", + "actionFollowUp": "이어서 요청", + "actionAddNote": "메모 추가", + "followUpSubmit": "보내기", + "followUpIntentRevise": "수정 요청", + "followUpIntentContinue": "계속 진행", + "followUpIntentQuestion": "질문하기", + "followUpIntentVerify": "자체 점검", + "followUpPlaceholderRevise": "무엇을 고쳐야 하나요? 같은 세션에서 이어집니다.", + "followUpPlaceholderContinue": "다음은 무엇인가요? 지금까지의 작업은 그대로 둡니다.", + "followUpPlaceholderQuestion": "무엇이 궁금한가요? 파일은 건드리지 않고 답변만 합니다.", + "followUpPlaceholderVerify": "선택: 특별히 확인했으면 하는 부분이 있나요?", + "followUpPlaceholderRetry": "선택: 이번엔 무엇을 다르게 할까요? 예: pnpm install 먼저 실행", + "followUpPlaceholderRequeue": "선택: 왜 취소했고, 이번엔 무엇이 달라져야 하나요?", + "actionArchive": "보관", + "actionUnarchive": "보관 해제", + "archiveAllDone": "모두 보관", + "dropToStart": "놓으면 실행 시작", + "errorView": "보기", + "notifyReview": "검수 대기: {title}", + "notifyFailed": "작업 실패: {title}", + "createFromMessage": "이 메시지로 작업 만들기", + "detailTokens": "총 토큰", + "editorTitleNew": "새 작업", + "editorTitleEdit": "작업 편집", + "templates": "템플릿", + "templatesEmpty": "아직 템플릿이 없습니다.", + "templateSaveCurrent": "현재 내용을 템플릿으로 저장", + "templateDelete": "템플릿 삭제", + "transcriptTitle": "작업 대화", + "transcriptDescription": "작업 에이전트 세션의 읽기 전용 실시간 보기입니다.", + "phaseWork": "작업 실행", + "phaseRetry": "다시 실행", + "phaseReturn": "이어서 요청", + "phaseMerge": "병합", + "titleLabel": "제목", + "titlePlaceholder": "무엇을 해야 하나요?", + "promptLabel": "작업 설명", + "promptPlaceholder": "에이전트에게 작업을 설명하세요 — @로 파일 참조, /로 명령", + "folderPlaceholder": "폴더 선택", + "agentInheritedHint": "작업 설정에서 상속됨 — 변경하면 이 작업에만 적용됩니다", + "agentOverrideReset": "상속으로 되돌리기", + "sectionTarget": "대상", + "errorTitle": "제목을 입력하세요", + "errorPrompt": "작업 설명을 입력하세요", + "errorFolder": "폴더를 선택하세요", + "save": "저장", + "cancel": "취소", + "mergeTitle": "작업 병합", + "mergeQueuedTitle": "대기 중인 병합", + "mergeQueueHint": "이 프로젝트의 다른 작업이 병합 중입니다. 이 작업은 대기열에 들어가며 앞의 병합이 끝나는 대로 자동으로 시작합니다.", + "mergeQueueUpdateHint": "이 작업은 이미 병합을 기다리고 있습니다. 제출하면 내용만 업데이트되고 대기 순서는 그대로 유지됩니다.", + "mergeDescription": "{branch}을(를) {base}에 병합합니다. worktree의 커밋되지 않은 변경은 먼저 커밋됩니다.", + "mergeMessage": "커밋 메시지", + "mergeMessagePlaceholder": "예: feat: add login validation", + "mergeAutoMessage": "커밋 메시지를 에이전트가 작성하도록 하기", + "strategySquash": "하나의 커밋으로 합치기", + "strategySquashHint": "작업의 모든 변경 사항이 하나의 기록으로 메인 브랜치에 반영되어 히스토리가 깔끔해집니다.", + "strategyMerge": "전체 히스토리 유지", + "strategyMergeHint": "작업 중의 모든 커밋을 그대로 유지하고 병합 기록을 하나 추가합니다. 각 단계를 추적할 수 있습니다.", + "mergeDeleteWorktree": "병합 후 worktree 삭제", + "mergeSubmit": "병합", + "mergeSubmitQueue": "병합 대기열에 추가", + "mergeQueuedToast": "병합 대기열에 추가했습니다. 현재 병합이 끝나는 대로 시작합니다.", + "completeTitle": "작업 완료", + "completeDescription": "이 작업은 파일을 변경하지 않아 병합할 것이 없습니다. 그대로 완료로 표시합니다.", + "completeDescriptionNoWorktree": "이 작업의 worktree가 삭제되어 더 이상 병합할 수 없습니다. 그대로 완료로 표시합니다. 병합되지 않은 커밋이 남아 있는 작업 브랜치는 유지됩니다.", + "completeDeleteWorktree": "완료 후 worktree 삭제", + "completeSubmit": "완료", + "settingsTitle": "작업 설정", + "settingsDescription": "{folder}의 작업 기본값입니다.", + "settingsScope": "적용 범위", + "settingsScopeGlobal": "모든 폴더(전역 기본값)", + "settingsScopeGlobalHint": "별도 설정이 없는 폴더는 이 전역 기본값을 사용합니다.", + "settingsSource": "설정 출처", + "settingsSourceGlobal": "전역 기본값 사용", + "settingsSourceCustom": "개별 설정", + "settingsSourceGlobalFollow": "전역 작업 설정을 따릅니다. 전역 변경 사항이 자동으로 적용됩니다.", + "settingsSourceCustomHint": "이 폴더만의 설정을 저장하며 더 이상 전역 기본값을 따르지 않습니다.", + "settingsAgent": "기본 에이전트", + "settingsMaxConcurrent": "최대 동시 작업 수", + "settingsMaxConcurrentHint": "0 = 무제한", + "settingsAutoProcess": "자동 처리", + "settingsAutoProcessHint": "할 일 작업이 동시 실행 한도 내에서 자동으로 시작됩니다.", + "settingsMergeStrategy": "기본 병합 전략", + "settingsMergeStrategyHint": "병합할 때 작업의 변경 사항을 브랜치 히스토리에 어떻게 기록할지 정합니다.", + "settingsAutoMerge": "자동 병합", + "settingsAutoMergeHint": "검토 대기에 도달하고 병합할 변경이 있는 작업은 병합 버튼을 누른 것과 똑같이 자동으로 병합됩니다. 커밋 메시지는 에이전트가 작성하고 worktree 처리는 아래 기본값을 따릅니다. 사전 점검이 실패했거나 병합에 실패한 작업은 남아서 기다립니다.", + "settingsDeleteWorktree": "머지 후 worktree 삭제", + "settingsDeleteWorktreeHint": "머지 대화상자에서 기본으로 선택됩니다. 거기서 바꿀 수도 있습니다.", + "settingsWorktreeRoot": "워크트리 위치", + "settingsWorktreeRootHint": "새 작업의 worktree를 이 디렉터리 아래에 작업마다 하나씩 만듭니다. 비워 두면 프로젝트 폴더와 같은 위치에 만듭니다. \"~\"는 홈 디렉터리이고 상대 경로는 프로젝트 폴더 기준입니다.", + "settingsWorktreeRootPlaceholder": "~/codeg-worktrees", + "settingsWorktreeRootBrowse": "워크트리 디렉터리 선택", + "settingsPreflight": "사전 점검 명령", + "settingsPreflightHint": "작업이 검토 단계에 도달하면 워크트리에서 실행.", + "settingsPreflightCustomPlaceholder": "pnpm test", + "settingsInitCommand": "워크트리 초기화 명령", + "settingsInitCommandHint": "워크트리를 새로 만든 뒤 에이전트 시작 전에 실행됩니다.", + "settingsInitCommandPlaceholder": "pnpm install", + "settingsTabGeneral": "일반", + "settingsTabMerge": "병합", + "settingsTabWorktree": "워크트리", + "settingsTabPrompts": "프롬프트", + "settingsPromptsIntro": "각 단계에는 이미 기본 프롬프트가 들어 있습니다 — 작업 내용, 워크트리 규칙, 머지 단계의 구체적인 git 절차. 여기에 적은 내용은 추가 지시로 맨 뒤에 덧붙으며, 기본 프롬프트를 보완할 뿐 대체하지 않습니다.", + "settingsPromptStageAll": "전체 단계", + "settingsPromptPlaceholderAll": "예: AGENTS.md의 프로젝트 규칙을 따르고, 마지막 요약은 두 문장 이내로", + "settingsPromptPlaceholderWork": "예: 관련 테스트를 먼저 읽고, 작은 단위로 자주 커밋", + "settingsPromptPlaceholderRetry": "예: 이어서 하기 전에 이미 커밋된 내용을 확인하고, 끝난 작업은 다시 하지 말 것", + "settingsPromptPlaceholderReturn": "예: 언급된 항목을 하나씩 처리하고, 관련 없는 리팩터링은 하지 마세요", + "settingsPromptPlaceholderMerge": "예: 최종 반영 커밋 메시지는 한국어로, 수동으로 해결한 충돌은 따로 밝힐 것", + "settingsPromptHintAll": "머지 실행을 포함해 에이전트가 받는 모든 프롬프트에 추가됩니다.", + "settingsPromptHintWork": "작업을 처음 실행할 때 추가됩니다.", + "settingsPromptHintRetry": "중단되거나 실패한 작업을 다시 이어갈 때 추가됩니다.", + "settingsPromptHintReturn": "검토 대기 작업에 이어서 요청할 때(수정·추가 작업·자체 점검) 덧붙습니다.", + "settingsPromptHintMerge": "에이전트가 작업을 기준 브랜치에 병합할 때 추가됩니다.", + "preflightPassed": "{name} 통과", + "preflightFailed": "{name} 실패", + "preflightRunning": "{name} 실행 중…", + "detailDescription": "작업 상세", + "detailSummary": "결과", + "detailFiles": "변경된 파일", + "detailDiffAll": "전체 차이 보기", + "detailDiffAllTitle": "전체 차이", + "detailNoChanges": "기준 대비 변경 사항이 아직 없습니다", + "detailTimeline": "진행 기록", + "detailTimelineEmpty": "아직 활동이 없습니다", + "showMore": "더 보기", + "showLess": "접기", + "detailInfo": "상세 정보", + "detailBranch": "브랜치", + "detailMergeCommit": "병합 커밋", + "detailChanges": "변경 사항", + "detailScheduled": "시작 예정", + "detailCreated": "생성 시간", + "detailStarted": "시작 시간", + "detailFinished": "완료 시간", + "diffLoading": "차이를 불러오는 중…", + "deleteConfirmTitle": "작업을 삭제할까요?", + "deleteConfirmBody": "“{title}”이(가) 보드에서 제거됩니다. 실행 중이면 먼저 취소됩니다.", + "deleteWithWorktree": "worktree도 함께 삭제", + "eventCreated": "생성됨", + "eventStatusChanged": "상태 변경", + "eventConfigEffective": "실행 구성", + "eventInitCommand": "초기화 명령", + "eventAgentProgress": "에이전트 진행", + "eventAgentVerdict": "에이전트 판정", + "eventMergeAttempt": "병합 시작", + "eventMergeQueued": "병합 대기열에 추가", + "eventMergeConflict": "병합 충돌", + "eventPreflight": "사전 점검", + "eventCleanupFailed": "worktree 정리 실패", + "eventResumeFallback": "세션 재개 실패, 새 세션으로 전환", + "eventUserAction": "사용자 작업", + "eventDiffStat": "변경 스냅샷" + }, + "CustomSkillsSettings": { + "loading": "사용자 지정 스킬 불러오는 중…", + "category": "사용자 지정", + "searchPlaceholder": "이름, ID 또는 설명으로 사용자 지정 스킬 검색", + "states": { + "not_linked": "사용 안 함", + "linked_to_codeg": "사용 중", + "linked_elsewhere": "다른 위치에 연결됨", + "blocked_by_real_directory": "실제 폴더가 차지함", + "broken": "손상된 링크" + }, + "actions": { + "new": "새로 만들기", + "import": "가져오기", + "importFromAgent": "에이전트에서 가져오기", + "cancel": "취소", + "save": "저장" + }, + "rowMenu": { + "edit": "편집", + "duplicate": "복제", + "delete": "삭제" + }, + "bulk": { + "delete": "선택 항목 삭제" + }, + "editor": { + "createTitle": "새 사용자 지정 스킬", + "editTitle": "사용자 지정 스킬 편집", + "description": "사용자 지정 스킬은 공유 저장소(~/.codeg/skills)에 있으며 모든 에이전트에서 사용할 수 있습니다.", + "idLabel": "스킬 ID", + "idPlaceholder": "예: my-workflow", + "contentLabel": "SKILL.md", + "contentPlaceholder": "여기에 스킬의 SKILL.md를 작성하세요…", + "preview": "미리보기", + "edit": "편집", + "emptyBody": "아직 내용이 없습니다." + }, + "duplicate": { + "title": "스킬 복제", + "description": "\"{id}\"을(를) 기반으로 새 ID로 복사본을 만듭니다.", + "newIdPlaceholder": "새 스킬 ID", + "confirm": "복제" + }, + "import": { + "title": "가져올 스킬 폴더 선택" + }, + "importFromAgent": { + "title": "에이전트에서 스킬 가져오기", + "description": "에이전트의 자체 스킬을 공유 저장소로 복사하면 어떤 에이전트에서도 사용할 수 있습니다.", + "agentLabel": "에이전트", + "agentPlaceholder": "에이전트 선택", + "selectAll": "모두 선택 ({count})", + "loading": "에이전트의 스킬을 불러오는 중…", + "unsupported": "이 에이전트는 스킬 디렉터리를 제공하지 않습니다.", + "empty": "이 에이전트에는 가져올 스킬이 없습니다.", + "alreadyInLibrary": "라이브러리에 있음", + "confirm": "선택 항목 가져오기 ({count})" + }, + "delete": { + "title": "사용자 지정 스킬을 삭제할까요?", + "body": "{count}개의 사용자 지정 스킬을 중앙 저장소에서 제거하고 모든 에이전트에서 링크를 해제합니다. 이 작업은 취소할 수 없습니다.", + "confirm": "삭제" + }, + "toasts": { + "loadFailed": "스킬 불러오기 실패", + "idRequired": "스킬 ID를 입력하세요", + "created": "사용자 지정 스킬 생성됨", + "updated": "사용자 지정 스킬 업데이트됨", + "saveFailed": "스킬 저장 실패", + "imported": "스킬 가져옴", + "importFailed": "스킬 가져오기 실패", + "duplicated": "스킬 복제됨", + "duplicateFailed": "스킬 복제 실패", + "deleted": "{count}개 스킬 삭제됨", + "deletedPartial": "{ok}개 삭제, {failed}개 실패", + "deleteFailed": "스킬 삭제 실패", + "importedFromAgent": "{count}개의 스킬을 가져왔습니다", + "importedFromAgentPartial": "{ok}개 가져옴, {failed}개 실패", + "importFromAgentAllSkipped": "가져올 항목 없음 — {count}개가 이미 라이브러리에 있습니다", + "importFromAgentFailed": "에이전트에서 가져오기 실패" + } + }, + "CodexModelEditor": { + "customizedNotice": "모델 목록을 사용자 지정했으므로 이제 codeg가 codex의 전체 모델 표를 관리합니다. codex가 이후 추가하는 공식 모델은 자동으로 나타나지 않습니다. 아래의 새로 고침을 클릭한 뒤 다시 저장하면 동기화됩니다. 사용자 지정을 모두 지우면 codex 자동 업데이트로 되돌아갑니다.", + "officialsTitle": "공식 모델", + "officialsHint": "실행하는 codex의 공식 모델을 자동 포함합니다. 필요 없는 항목은 삭제하세요.", + "officialsEmpty": "사용 가능한 공식 모델이 없습니다.", + "refresh": "codex에서 새로고침", + "readdOfficial": "공식 다시 추가", + "customsTitle": "사용자 지정 모델", + "customsEmpty": "사용자 지정 모델이 없습니다.", + "addCustom": "사용자 지정 추가", + "slugPlaceholder": "모델 ID(slug)", + "displayNamePlaceholder": "표시 이름", + "contextWindow": "컨텍스트", + "makeDefault": "기본값으로 설정", + "defaultHint": "기본 모델", + "remove": "제거", + "advanced": "고급", + "baseTemplate": "기본 템플릿", + "baseTemplateHint": "필수 필드(시스템 프롬프트, 도구, 제한)를 복제할 공식 모델.", + "groupBehavior": "동작 및 기능", + "fieldReasoningLevel": "기본 추론 강도", + "fieldReasoningSummary": "추론 요약", + "fieldVerbosity": "상세도", + "fieldShellType": "셸 유형", + "fieldApplyPatch": "패치 적용 도구", + "fieldReasoningSummaries": "추론 요약 지원", + "fieldSupportVerbosity": "상세도 제어", + "fieldParallelToolCalls": "병렬 도구 호출", + "fieldSearchTool": "웹 검색 도구", + "optNone": "없음", + "groupInstructions": "설명 및 시스템 프롬프트", + "fieldDescription": "설명", + "baseInstructions": "시스템 프롬프트(base_instructions)" + }, + "DiagnosticsSettings": { + "title": "환경 진단", + "description": "이 앱이 자체 프로세스에서 에이전트 CLI를 어떻게 확인하는지 점검합니다(터미널과 다를 수 있음).", + "loading": "진단 실행 중…", + "error": "진단 실패", + "rerun": "다시 실행", + "copyAll": "전체 복사", + "copied": "진단 정보를 클립보드에 복사했습니다", + "button": "진단", + "verdict": { + "ok": "환경이 정상입니다. 그래도 설치되지 않았다고 표시되면 앱을 완전히 재시작하여 프리픽스 캐시를 새로 고치세요.", + "node_missing": "앱 PATH에서 Node.js를 찾을 수 없습니다.", + "npm_missing": "앱 PATH에서 npm을 찾을 수 없습니다.", + "not_installed": "이 에이전트가 설치되지 않은 것 같습니다.", + "installed_but_unresolved": "설치된 것으로 기록되어 있지만 앱이 실행 파일을 찾지 못합니다.", + "user_prefix_not_on_path": "폴백 프리픽스(~/.codeg/npm-global)에 설치되었지만 앱 PATH에 없습니다. 앱을 완전히 재시작한 후 다시 시도하세요.", + "homebrew_bin_not_on_path": "Homebrew bin에 설치되었지만 앱 PATH에 없습니다(Apple Silicon keg 분리).", + "terminal_only_path": "이 명령은 터미널에서는 확인되지만 앱에서는 확인되지 않습니다. GUI PATH 불일치입니다. 터미널에서 앱을 실행하거나 에이전트 설정에서 다시 설치하세요.", + "npm_prefix_timeout": "npm prefix -g가 너무 느립니다(1.5초 초과). 폴백 감지를 건너뛰었습니다. 앱을 재시작한 후 다시 시도하세요.", + "node_too_old": "현재 Node.js가 이 에이전트의 요구 버전보다 낮습니다. Node.js를 업그레이드하세요.", + "adapter_missing_native_present": "사용 중인 {agent} CLI는 설치되어 있지만, Codeg가 실행하는 것은 별도의 ACP 어댑터 패키지이며 그것이 아직 설치되지 않았습니다. 에이전트 설정에서 설치하세요. 기존 CLI는 건드리지 않으며 로그인도 공유됩니다.", + "adapter_missing": "Codeg는 {agent}에 대해 별도의 ACP 어댑터 패키지를 실행하는데, 아직 설치되지 않았습니다. 에이전트 설정에서 설치하세요 — 벤더 CLI만 설치하는 것으로는 충분하지 않습니다." + } + }, + "TokenUsage": { + "title": "토큰 사용량", + "rangeLabel": "기간", + "range7d": "7일", + "range30d": "30일", + "range90d": "90일", + "rangeThisMonth": "이번 달", + "rangeThisYear": "올해", + "rangeAll": "전체", + "rangeCustom": "사용자 지정", + "moreRanges": "더보기", + "customRangePick": "기간 선택", + "bucketLabel": "집계 단위", + "bucketDay": "일", + "bucketWeek": "주", + "bucketMonth": "월", + "bucketUnitDay": "날", + "bucketUnitWeek": "주", + "bucketUnitMonth": "월", + "folderFilter": "폴더", + "allFolders": "모든 폴더", + "agentFilter": "에이전트", + "allAgents": "모든 에이전트", + "modelFilter": "모델", + "allModels": "모든 모델", + "searchPlaceholder": "검색…", + "noMatches": "일치하는 항목 없음", + "clearFilter": "선택 해제", + "resetFilters": "필터 초기화", + "refresh": "새로 고침", + "rebuild": "전체 재구성", + "rebuildHint": "집계된 데이터를 버리고 모든 세션 기록을 다시 읽습니다. codeg 밖의 CLI가 기록을 이어썼을 때 사용하세요.", + "syncing": "세션 집계 중…", + "syncProgress": "{done} / {total}", + "syncDone": "{synced}개 세션을 집계했습니다", + "syncFailed": "일부 세션을 읽지 못했습니다", + "syncBusy": "이미 새로 고침이 진행 중입니다", + "lastSynced": "{time}에 업데이트", + "lastSyncedNever": "집계된 적 없음", + "tileTotal": "총 토큰", + "tileSessions": "세션 수", + "tileTurns": "대화 턴", + "tileActiveDays": "활동 일수", + "tileGenTime": "생성 시간", + "vsPrevious": "이전 기간 대비", + "deltaNew": "신규", + "trendTitle": "사용량 추이", + "trendEmpty": "이 기간에는 사용량이 없습니다", + "trendTurns": "턴", + "trendSessions": "세션", + "compositionTitle": "토큰 구성", + "compositionHint": "입력은 보낸 내용, 출력은 모델이 쓴 내용, 캐시 읽기는 다시 보내지 않아도 된 컨텍스트입니다.", + "compositionNote": "이 캐시 적중을 정가로 다시 보냈다면 {value}가 더 들었을 것입니다.", + "inputTokens": "입력", + "outputTokens": "출력", + "cacheWrite": "캐시 쓰기", + "cacheRead": "캐시 읽기", + "freshTokens": "신규 연산 토큰", + "cacheHitCaption": "캐시 적중", + "cacheHeroTitleHigh": "컨텍스트 대부분은 다시 보낼 필요가 없었습니다", + "cacheHeroTitleLow": "컨텍스트 대부분이 아직 정가로 계산됩니다", + "cacheHeroDesc": "{cached}의 컨텍스트를 캐시가 감당했고, 이 기간에 실제로 새로 연산된 것은 {fresh}뿐입니다.", + "cacheSavedSuffix": "재전송을 {saved}만큼 아꼈습니다.", + "avgPerSession": "세션당 평균", + "avgTurnsPerSession": "세션당 평균 {count}턴", + "avgPerActiveDay": "활동일당 평균", + "peakBucket": "가장 많은 {bucket}", + "peakHour": "피크 시간대", + "daysValue": "{count}일", + "idleDays": "쉬어간 날", + "byFolderTitle": "폴더별", + "byAgentTitle": "에이전트별", + "byModelTitle": "모델별", + "distributionTitle": "사용량 분포", + "distributionHint": "선택한 기준으로 세션과 토큰을 집계합니다. 행을 클릭하면 해당 항목으로 필터링됩니다.", + "otherLabel": "기타", + "unknownModel": "모델 미기록", + "emptyBreakdown": "기록이 없습니다", + "sessionsCount": "{count}개 세션", + "heatmapTitle": "작업 리듬", + "heatmapHint": "로컬 요일·시간대별 토큰 분포입니다.", + "heatmapPeakHint": "{hour}:00 전후가 가장 밀집되어 있습니다.", + "less": "적음", + "more": "많음", + "heatmapCell": "{weekday} {hour}:00 — {value} 토큰", + "weekMon": "월", + "weekTue": "화", + "weekWed": "수", + "weekThu": "목", + "weekFri": "금", + "weekSat": "토", + "weekSun": "일", + "topSessionsTitle": "소비가 큰 세션", + "untitledSession": "제목 없는 세션", + "topSessionsEmpty": "이 기간에는 세션이 없습니다", + "streakLongest": "최장 연속", + "streakLongestDays": "최장 연속 {count}일", + "share": "공유", + "moreActions": "기타 작업", + "shareDialogTitle": "사용량 카드 공유", + "shareDialogHint": "지금 보고 있는 기간과 필터의 스냅샷입니다.", + "shareSave": "이미지 저장", + "shareCopy": "이미지 복사", + "shareCopied": "클립보드에 복사했습니다", + "shareSaved": "이미지를 저장했습니다", + "shareFailed": "이미지를 만들지 못했습니다", + "shareRendering": "생성 중…", + "cardHeading": "나의 AI 코딩 기록", + "cardRangeAll": "전체 기간", + "cardTotalLabel": "사용 토큰", + "cardFooter": "codeg로 제작", + "cardTopModels": "주요 모델", + "cardTopProjects": "주요 프로젝트", + "archetypeNightOwl": "야행성 개발자", + "archetypeNightOwlDesc": "토큰의 {percent}%를 해가 진 뒤에 씁니다.", + "archetypeEarlyBird": "아침형 개발자", + "archetypeEarlyBirdDesc": "토큰의 {percent}%를 오전 9시 전에 씁니다.", + "archetypeWeekendWarrior": "주말 전사", + "archetypeWeekendWarriorDesc": "토큰의 {percent}%가 주말에 발생합니다.", + "archetypeCacheMaster": "캐시 마스터", + "archetypeCacheMasterDesc": "컨텍스트의 {percent}%가 캐시에서 왔습니다.", + "archetypeMarathoner": "마라토너", + "archetypeMarathonerDesc": "{days}일 연속으로 개발했습니다.", + "archetypePolyglot": "멀티 플레이어", + "archetypePolyglotDesc": "{count}개 에이전트를 본격적으로 함께 씁니다.", + "archetypeLaserFocus": "한 우물", + "archetypeLaserFocusDesc": "토큰의 {percent}%를 한 프로젝트에 썼습니다.", + "archetypeDeepDiver": "딥 다이버", + "archetypeDeepDiverDesc": "세션당 평균 {averageK}K 토큰.", + "archetypeSteady": "꾸준한 빌더", + "archetypeSteadyDesc": "총 {days}일 동안 개발했습니다.", + "emptyTitle": "아직 집계된 데이터가 없습니다", + "emptyHint": "codeg는 각 에이전트의 세션 기록에서 토큰 수를 직접 읽습니다. 새로 고침하면 이 컴퓨터에 있는 기록을 집계합니다.", + "emptyAction": "내 세션 집계", + "loadFailed": "사용량을 불러오지 못했습니다", + "truncatedNotice": "기간이 매우 길어 표시된 수치는 가장 최근 구간만 반영합니다." + } +} diff --git a/src/i18n/messages/pt.json b/src/i18n/messages/pt.json index 5b31f9ead..bce0354d9 100644 --- a/src/i18n/messages/pt.json +++ b/src/i18n/messages/pt.json @@ -1,4956 +1,4958 @@ -{ - "Language": { - "followSystem": "Seguir o sistema", - "english": "Inglês", - "simplifiedChinese": "Chinês simplificado", - "traditionalChinese": "Chinês tradicional", - "japanese": "Japonês", - "korean": "Coreano", - "spanish": "Espanhol", - "german": "Alemão", - "french": "Francês", - "portuguese": "Português", - "arabic": "Árabe" - }, - "GitCredentialDialog": { - "title": "Autenticação necessária", - "description": "O servidor remoto requer credenciais. Insira seu nome de usuário e senha (ou token de acesso pessoal).", - "username": "Nome de usuário", - "usernamePlaceholder": "Nome de usuário ou e-mail", - "password": "Senha / Token", - "passwordPlaceholder": "Senha ou token de acesso pessoal", - "passwordHint": "Insira o nome de usuário e a senha do servidor.", - "cancel": "Cancelar", - "authenticate": "Autenticar", - "authenticating": "Autenticando...", - "invalidCredentials": "Credenciais inválidas. Tente novamente.", - "saveCredentials": "Salvar credenciais para operações futuras", - "githubTitle": "Autenticação do GitHub", - "githubDescription": "Insira um token de acesso pessoal para se conectar ao GitHub. O token será validado e salvo automaticamente.", - "githubToken": "Token de acesso pessoal", - "githubTokenPlaceholder": "ghp_xxxxxxxxxxxx", - "githubTokenHint": "Gere um token em GitHub → Settings → Developer settings → Personal access tokens.", - "githubAuthenticate": "Validar e conectar", - "generateToken": "Gerar token" - }, - "SettingsShell": { - "title": "Configurações", - "preferences": "Preferências", - "nav": { - "general": "Geral", - "appearance": "Aparência", - "agents": "Agentes", - "mcp": "MCP", - "skills": "Skills", - "shortcuts": "Atalhos", - "version_control": "Controle de versão", - "system": "Sistema", - "chat_channels": "Canais de chat", - "web_service": "Serviço Web", - "model_providers": "Provedores de Modelos", - "experts": "Especialistas", - "science": "Ciência", - "office_tools": "Ferramentas de escritório", - "skill_packs": "Pacotes de habilidades", - "quick_messages": "Mensagens rápidas", - "logs": "Registros de execução" - } - }, - "AppearanceSettings": { - "sectionTitle": "Aparência do tema", - "sectionDescription": "Escolha claro, escuro ou seguir o sistema. As configurações são salvas automaticamente.", - "themeMode": "Modo de tema", - "placeholder": "Selecionar modo de tema", - "system": "Seguir o sistema", - "light": "Claro", - "dark": "Escuro", - "currentTheme": "Tema efetivo atual: {theme}", - "resolvedTheme": { - "light": "Claro", - "dark": "Escuro", - "unknown": "--" - }, - "themeColor": { - "sectionTitle": "Cor do tema", - "sectionDescription": "Escolha uma paleta de cores para acentos, botões e destaques.", - "current": "Cor atual: {color}", - "options": { - "neutral": "Neutral", - "zinc": "Zinc", - "slate": "Slate", - "stone": "Stone", - "gray": "Gray", - "red": "Red", - "rose": "Rose", - "orange": "Orange", - "green": "Green", - "blue": "Blue", - "yellow": "Yellow", - "violet": "Violet" - } - }, - "customStyle": { - "sectionTitle": "Estilo personalizado", - "sectionDescription": "Ajuste as cores do tema atual ou injete o seu próprio CSS. As substituições ficam sobre a predefinição base, por isso permanecem ao trocar de predefinição.", - "summarySuspended": "Suspenso", - "summaryDefault": "Predefinição inalterada", - "summaryTokens": "{count, plural, one {# substituição} other {# substituições}}", - "summaryCss": "CSS personalizado", - "suspendedByShortcut": "O estilo personalizado está suspenso. Nada do que definir aqui terá efeito até retomá-lo.", - "suspendedBySafeParam": "Esta janela foi aberta no modo de aparência segura, por isso o estilo personalizado é ignorado aqui. As outras janelas não são afetadas.", - "resume": "Retomar estilo personalizado", - "enableTheme": "Ativar cores personalizadas", - "editingLight": "A editar os valores do modo claro. Mude a aplicação para o modo escuro para o definir em separado.", - "editingDark": "A editar os valores do modo escuro. Mude a aplicação para o modo claro para o definir em separado.", - "resetToken": "Repor o valor da predefinição", - "radius": "Raio dos cantos", - "radiusHint": "Toda a escala de raios, de sm a 4xl, deriva dele: um único cursor arredonda a aplicação inteira.", - "advanced": "Avançado (mais {count} variáveis)", - "enableCss": "Ativar CSS personalizado", - "cssRisk": "Funcionalidade avançada. O CSS personalizado substitui todos os estilos integrados e pode tornar a interface inutilizável.", - "editCss": "Editar CSS…", - "cssPresent": "{size} KB guardados", - "cssEmpty": "Ainda não há nada guardado", - "escapeHint": "Interface estragada? Prima {shortcut} para suspender todo o estilo personalizado, ou abra uma janela com o parâmetro safeStyle=1.", - "copyTheme": "Copiar JSON do tema", - "importTheme": "Importar tema…", - "clearTheme": "Limpar substituições", - "interopHint": "Os temas usam o formato registry:theme do shadcn, por isso pode colar aqui qualquer tema shadcn e usar os exportados em qualquer projeto shadcn.", - "importTitle": "Importar tema", - "importDescription": "Cole um item registry:theme do shadcn, um objeto light/dark simples ou um mapa plano de tokens.", - "readClipboard": "Ler área de transferência", - "importConfirm": "Importar", - "cancel": "Cancelar", - "apply": "Aplicar", - "toasts": { - "copied": "JSON do tema copiado", - "copyFailed": "Não foi possível copiar para a área de transferência", - "clipboardReadFailed": "Não foi possível ler a área de transferência, cole manualmente", - "importFailed": "Esse JSON não contém variáveis de tema utilizáveis", - "imported": "Tema importado" - }, - "css": { - "dialogTitle": "CSS personalizado", - "dialogDescription": "Aplica-se a todas as janelas do codeg. As alterações são pré-visualizadas ao vivo; carregue em Aplicar para guardar.", - "size": "{used} KB / {max} KB", - "ruleCount": "{count} regras", - "errorTooLarge": "Demasiado grande para guardar. Reduza abaixo do limite.", - "errorImportEscaped": "Uma regra @import sobreviveu à remoção (sintaxe com escapes). Remova-a para guardar.", - "warnNoRules": "Nenhuma regra foi analisada; verifique a sintaxe.", - "noticeImportsRemoved": "Regras @import removidas: {count}. Iriam obter folhas de estilo remotas.", - "noticeRemoteUrl": "Contém um url() remoto, que fará um pedido de rede ao ser aplicado.", - "noticePreviewSuspended": "O estilo personalizado está suspenso, por isso esta pré-visualização não é aplicada.", - "noticeDisabled": "O CSS personalizado está desativado. Pode pré-visualizar aqui, mas nada se aplica até o ativar.", - "hintTokens": "Dica: as cores que substituiu ficam disponíveis como var(--primary), var(--background), etc." - } - }, - "zoomLevel": { - "sectionTitle": "Zoom da janela", - "sectionDescription": "Dimensiona toda a interface. Aplica imediatamente e é salvo por dispositivo.", - "placeholder": "Selecione o nível de zoom", - "default": "Padrão", - "current": "Zoom atual: {zoom}%" - }, - "fonts": { - "sectionTitle": "Fontes", - "sectionDescription": "Escolha as fontes para a interface, o editor de código e o terminal. As fontes incluídas são carregadas sob demanda; selecione “Personalizada…” para usar qualquer fonte instalada no seu sistema.", - "interface": "Interface", - "editor": "Editor", - "terminal": "Terminal", - "groupSans": "Sem serifa", - "groupMono": "Monoespaçada", - "custom": "Personalizada…", - "customPlaceholder": "Nome da fonte, ex.: Fira Code", - "fontSize": "Tamanho da fonte", - "ligatures": "Ativar ligaduras", - "ligaturesUnavailable": "Esta fonte não tem ligaduras", - "wordWrap": "Ativar quebra de linha", - "terminalLigaturesHint": "As ligaduras do terminal aplicam-se apenas às fontes de programação incluídas.", - "preview": "Pré-visualização" - }, - "welcomePanel": { - "sectionTitle": "Área de seleção de modo", - "sectionDescription": "Os cartões de atalho «Desenvolvimento / Escritório» exibidos acima do campo de entrada na página de nova conversa.", - "showQuickActions": "Mostrar na página de nova conversa" - }, - "workspaceBackground": { - "sectionTitle": "Plano de fundo da área de trabalho", - "sectionDescription": "Mostra uma imagem atrás de toda a área de trabalho. A barra lateral e os painéis ficam translúcidos e foscos para deixar a imagem transparecer, e uma máscara mantém o texto legível.", - "enable": "Ativar imagem de fundo", - "image": "Imagem", - "chooseImage": "Escolher imagem", - "replaceImage": "Substituir imagem", - "removeImage": "Remover", - "fillMode": "Modo de preenchimento", - "fillModes": { - "cover": "Preencher", - "contain": "Ajustar", - "center": "Centralizar", - "tile": "Lado a lado" - }, - "maskOpacity": "Opacidade da máscara", - "maskOpacityHint": "Valores mais altos esmaecem a imagem em direção à cor de fundo do tema, melhorando o contraste do texto.", - "imageBlur": "Desfoque da imagem", - "panelOpacity": "Opacidade dos painéis", - "panelOpacityHint": "O quão opacos são a barra lateral, os painéis e as barras de abas. Mais baixo deixa a imagem transparecer mais.", - "errorTooLarge": "A imagem é muito grande (máx. 16 MB).", - "errorUploadFailed": "Falha ao definir a imagem de fundo." - } - }, - "SystemSettings": { - "loading": "Carregando...", - "sectionTitle": "Gerenciamento do sistema", - "sectionDescription": "Gerencie proxy de rede, atualizações do app e preferências de idioma.", - "proxyTitle": "Proxy de rede", - "proxyDescription": "Quando ativado, as solicitações de rede seguintes priorizam este proxy (incluindo chat ACP, instalação de agentes e operações remotas do Git).", - "loadFailed": "Falha ao carregar: {message}", - "enableProxy": "Ativar proxy do sistema", - "proxyAddress": "Endereço do proxy", - "proxyHint": "Suporta http(s)/socks5, exemplo: {example}. Só funciona quando o proxy do sistema está ativado.", - "save": "Salvar", - "saving": "Salvando...", - "proxyRequired": "A URL do proxy é obrigatória quando o proxy está ativado", - "saveSuccess": "As configurações de proxy do sistema foram salvas", - "saveFailed": "Falha ao salvar: {message}", - "languageTitle": "Idioma", - "languageDescription": "Defina o idioma do app. Ao seguir o idioma do sistema, idiomas não suportados voltam para inglês.", - "appLanguage": "Idioma do app", - "languageSaveSuccess": "As configurações de idioma foram salvas", - "languageSaveFailed": "Falha ao salvar as configurações de idioma: {message}", - "updateTitle": "Atualização do app", - "versionTitle": "Atualização de software", - "updateDescription": "Verifique versões mais novas na fonte de releases configurada e instale diretamente quando disponíveis.", - "currentVersion": "Versão atual", - "upgradableVersion": "Versão mais recente", - "none": "Nenhuma", - "lastChecked": "Última verificação: {time}", - "updateError": "Erro de atualização: {message}", - "checking": "Verificando...", - "checkUpdate": "Verificar atualizações", - "updating": "Instalando...", - "downloading": "Baixando...", - "upgradeTo": "Atualizar para v{version}", - "viewRelease": "Ver lançamento v{version}", - "foundUpdate": "Nova versão v{version} encontrada", - "alreadyLatest": "Você já está na versão mais recente", - "checkUpdateFailed": "Falha ao verificar atualizações: {message}", - "installSuccess": "Atualização instalada. Reiniciando o app.", - "installFailed": "Falha na atualização: {message}", - "upgradeSuccess": "Atualização concluída. Recarregando...", - "restartTimeout": "O servidor não voltou a tempo. Verifique os logs do contêiner ou do serviço.", - "restartingIn": "Reiniciando em {seconds} s...", - "waitingForServer": "Aguardando o servidor voltar...", - "restartToUpdate": "Reiniciar para atualizar", - "newVersionBadge": "Nova v{version}", - "updateAvailableTitle": "Atualização disponível", - "releaseNotesTitle": "Novidades", - "remindLater": "Mais tarde", - "retry": "Tentar novamente", - "stepDownload": "Download", - "stepInstall": "Instalação", - "stepRestart": "Reinício", - "updateReadyHint": "Atualização baixada — reinicie para aplicar.", - "restarting": "Reiniciando...", - "dockerUpgradeHint": "Isto atualiza o contêiner em execução agora. Perde-se se o contêiner for recriado — para mantê-lo, baixe ou crie uma imagem na nova versão e recrie o contêiner.", - "upgradeRolledBack": "Falha na atualização; o servidor reverteu para a versão anterior.", - "serverUnreachable": "Não foi possível acessar o servidor para iniciar a atualização. Verifique se ele está em execução e tente novamente.", - "rollbackButton": "Reverter", - "rollingBack": "Revertendo...", - "rollbackDescription": "Restaura a versão instalada antes da última atualização.", - "rollbackConfirmTitle": "Reverter para a versão anterior?", - "rollbackConfirmDescription": "O servidor será reiniciado na versão instalada antes da última atualização. Uma versão mais recente continua disponível para instalar novamente.", - "rollbackConfirm": "Reverter", - "rollbackCancel": "Cancelar", - "rollbackSuccess": "Revertido para a versão anterior. Recarregando...", - "rollbackFailed": "Falha ao reverter. Verifique os registros do servidor.", - "updateErrors": { - "sourceUnavailable": "Não foi possível acessar a fonte de atualização. Verifique sua rede ou proxy e tente novamente.", - "network": "Falha na conexão de rede. Verifique sua rede ou proxy e tente novamente.", - "downloadFailed": "Falha ao baixar o pacote de atualização. Tente novamente mais tarde.", - "installFailed": "Falha ao instalar a atualização. Feche o app e tente novamente.", - "unknown": "Falha na atualização. Tente novamente mais tarde." - } - }, - "VersionControlSettings": { - "loading": "Carregando...", - "sectionTitle": "Controle de versão", - "sectionDescription": "Configure o executável Git e gerencie contas do GitHub.", - "gitTitle": "Configuração do Git", - "gitDescription": "Configure o executável Git usado pelo aplicativo.", - "gitDetected": "Git detectado", - "gitNotFound": "Git não encontrado no sistema", - "gitVersion": "Versão", - "gitPath": "Caminho", - "customGitPath": "Caminho personalizado do Git", - "customGitPathPlaceholder": "/usr/bin/git", - "customGitPathHint": "Deixe vazio para usar o caminho detectado automaticamente.", - "test": "Testar", - "testing": "Testando...", - "testSuccess": "Executável Git é válido.", - "testFailed": "Teste do Git falhou: {message}", - "save": "Salvar", - "saving": "Salvando...", - "saveSuccess": "Configurações do Git salvas.", - "saveFailed": "Falha ao salvar: {message}", - "githubTitle": "Contas do GitHub", - "githubDescription": "Gerencie contas do GitHub para autenticação. Os tokens são armazenados localmente.", - "noAccounts": "Nenhuma conta do GitHub configurada.", - "addAccount": "Adicionar conta", - "serverUrl": "URL do servidor", - "serverUrlPlaceholder": "https://github.com", - "token": "Token de acesso pessoal", - "tokenPlaceholder": "ghp_xxxxxxxxxxxx", - "generateToken": "Gerar token", - "tokenHint": "Gere um token em GitHub → Settings → Developer settings → Personal access tokens.", - "validateAndAdd": "Validar e adicionar", - "validating": "Validando...", - "addSuccess": "Conta {username} adicionada com sucesso.", - "addFailed": "Falha ao adicionar conta: {message}", - "testConnection": "Testar", - "connectionSuccess": "Conexão bem-sucedida.", - "connectionFailed": "Falha na conexão: {message}", - "setDefault": "Definir como padrão", - "defaultLabel": "Padrão", - "defaultSet": "Conta padrão atualizada.", - "removeAccount": "Remover", - "removeConfirmTitle": "Remover conta", - "removeConfirmMessage": "Tem certeza de que deseja remover a conta \"{username}\"?", - "removeConfirm": "Remover", - "removeCancel": "Cancelar", - "removeSuccess": "Conta removida.", - "scopes": "Escopos", - "loadFailed": "Falha ao carregar configurações: {message}", - "gitAccount": { - "sectionTitle": "Contas de servidor Git", - "sectionDescription": "Gerencie credenciais para servidores Git que não são GitHub (GitLab, Bitbucket, auto-hospedados, etc.).", - "noAccounts": "Nenhuma conta de servidor Git configurada.", - "addAccount": "Adicionar conta", - "addTitle": "Adicionar conta Git", - "addDescription": "Insira o endereço do servidor, nome de usuário e senha ou token de acesso.", - "serverUrl": "URL do servidor", - "serverUrlPlaceholder": "https://gitlab.example.com", - "username": "Nome de usuário", - "usernamePlaceholder": "Nome de usuário ou e-mail", - "password": "Senha / Token", - "passwordPlaceholder": "Senha ou token de acesso", - "passwordHint": "Insira a senha ou o token de acesso do servidor.", - "add": "Adicionar", - "serverRequired": "A URL do servidor é obrigatória.", - "usernameRequired": "O nome de usuário é obrigatório.", - "passwordRequired": "A senha é obrigatória." - } - }, - "ShortcutSettings": { - "sectionTitle": "Atalhos", - "resetDefault": "Restaurar padrões", - "recordInstruction": "Clique no botão à direita e pressione uma combinação de teclas. Use Ctrl/Cmd, Alt e Shift. Pressione Esc para cancelar a gravação.", - "recording": "Pressione um atalho...", - "toasts": { - "conflict": "O atalho já está em uso por \"{title}\"", - "updated": "Atalho atualizado", - "invalid": "Atalho inválido, tente novamente", - "reset": "Atalhos padrão restaurados" - }, - "actions": { - "toggle_search": { - "title": "Abrir busca", - "description": "Mostra ou oculta o painel de busca de conversas" - }, - "toggle_sidebar": { - "title": "Alternar barra lateral esquerda", - "description": "Mostra ou oculta a barra lateral da lista de conversas" - }, - "toggle_terminal": { - "title": "Alternar terminal", - "description": "Mostra ou oculta o painel de terminal inferior" - }, - "new_terminal_tab": { - "title": "Novo terminal", - "description": "Cria uma nova aba de terminal quando o foco está no terminal" - }, - "close_current_terminal_tab": { - "title": "Fechar terminal atual", - "description": "Fecha a aba de terminal atual quando o foco está no terminal" - }, - "toggle_aux_panel": { - "title": "Alternar painel direito", - "description": "Mostra ou oculta o painel de informações auxiliares" - }, - "new_conversation": { - "title": "Nova conversa", - "description": "Cria uma nova aba de conversa na pasta atual" - }, - "open_folder": { - "title": "Abrir pasta", - "description": "Abre o seletor de pastas e abre em uma nova janela" - }, - "open_settings": { - "title": "Abrir configurações", - "description": "Abre a janela de configurações" - }, - "close_current_tab": { - "title": "Fechar aba atual", - "description": "Fecha a conversa atual ou aba de arquivo" - }, - "close_all_file_tabs": { - "title": "Fechar todas as abas de arquivo", - "description": "Fecha todas as abas de arquivo abertas quando o painel de arquivos está ativo" - }, - "next_tab": { - "title": "Próxima aba", - "description": "Mudar para a próxima aba de conversa ou arquivo" - }, - "prev_tab": { - "title": "Aba anterior", - "description": "Mudar para a aba anterior de conversa ou arquivo" - }, - "send_message": { - "title": "Enviar mensagem", - "description": "Enviar a mensagem atual na caixa de entrada" - }, - "newline_in_message": { - "title": "Nova linha na mensagem", - "description": "Inserir uma nova linha na caixa de entrada" - }, - "toggle_custom_style": { - "title": "Suspender/retomar estilo personalizado", - "description": "Saída de emergência: desliga todas as cores e o CSS personalizados e volta a ligá-los" - } - } - }, - "SkillsSettings": { - "title": "Skills", - "description": "Selecione uma Skill à esquerda. À direita, a prévia em Markdown é mostrada por padrão; mude para edição para modificar e salvar.", - "loadingAgents": "Carregando agentes que suportam Skills...", - "emptyNoManageableAgents": "Não há agentes disponíveis para gerenciamento de Skills.", - "managedTarget": "Alvo gerenciado", - "selectAgentPlaceholder": "Selecione um agente", - "searchPlaceholder": "Pesquisar por nome / ID / caminho...", - "skillsList": "Lista de Skills", - "loadingSkills": "Carregando Skills...", - "agentNotSupported": "O agente atual não suporta gerenciamento de Skills.", - "emptySkills": "Ainda não há Skills. Clique em \"Nova Skill\" para criar uma.", - "newSkillTitle": "Nova Skill", - "skillInfo": "Informações da Skill", - "skillIdPlaceholder": "skill-id (letras/números/-/_/.)", - "skillsDirectoryWithPath": "Diretório de Skills: {path}", - "skillsDirectoryNeedId": "Diretório de Skills: digite o ID da Skill para gerar o caminho completo", - "markdownContent": "Conteúdo Markdown", - "editingStatus": "Editando", - "previewStatus": "Visualizando", - "contentPlaceholder": "Digite o conteúdo Markdown da Skill...", - "metadataTitle": "Metadados de Skills", - "onlyYamlMetadata": "Esta Skill contém apenas metadados YAML.", - "emptyContentHint": "Ainda não há conteúdo. Clique em \"Editar\" para começar.", - "loadingSkill": "Carregando Skill...", - "emptyNoAgents": "Nenhum agente disponível.", - "noSelectionHint": "Selecione um Skill à esquerda ou clique em \"Novo Skill\" para criar um.", - "systemBadge": "Sistema", - "systemHint": "Skill integrado do CLI · somente leitura", - "scope": { - "global": "Global", - "folder": "Pasta", - "selectFolderPlaceholder": "Selecionar uma pasta", - "noFolders": "Nenhuma pasta encontrada", - "pickFolderHint": "Selecione uma pasta para ver suas Skills." - }, - "actions": { - "preview": "Prévia", - "edit": "Editar", - "openInWindow": "Abrir em nova janela", - "delete": "Excluir", - "deleting": "Excluindo...", - "refresh": "Atualizar", - "newSkill": "Nova Skill", - "reset": "Redefinir", - "save": "Salvar", - "saving": "Salvando...", - "cancel": "Cancelar" - }, - "deleteDialog": { - "title": "Excluir Skill", - "confirm": "Excluir a Skill atual? Esta ação não pode ser desfeita.", - "confirmWithNamePrefix": "Excluir Skill", - "confirmWithNameSuffix": "? Esta ação não pode ser desfeita." - }, - "toasts": { - "loadFailed": "Falha ao carregar Skill", - "openFolderFailed": "Falha ao abrir pasta", - "noSkillDirectory": "Nenhum diretório de Skills disponível para o agente atual", - "nameRequired": "O nome da Skill não pode estar vazio", - "updated": "Skill atualizada", - "created": "Skill criada", - "saveFailed": "Falha ao salvar Skill", - "deleted": "Skill excluída", - "deleteFailed": "Falha ao excluir Skill" - }, - "templates": { - "gemini": "---\nname: example-skill\ndescription: Describe when this skill should be used.\n---\n\n# Skill Name\n\nInstructions for the agent when this skill is active.\n\n## Workflow\n\n1. Add actionable step one.\n2. Add actionable step two.\n", - "openCode": "---\nname: example-skill\ndescription: Describe when this skill should be used.\n---\n\n# Purpose\n\nDescribe what this skill helps with.\n\n# Steps\n\n1. Add actionable step one.\n2. Add actionable step two.\n", - "openClaw": "---\nname: example-skill\ndescription: Describe when this skill should be used.\nuser-invocable: true\ndisable-model-invocation: false\n---\n\n# Purpose\n\nDescribe what this skill helps with.\n\n# Instructions\n\n1. Add actionable instruction one.\n2. Add actionable instruction two.\n", - "default": "---\nname: example-skill\ndescription: Describe when this skill should be used.\n---\n\n# Skill: example-skill\n\n## When to use\n\n- Describe trigger conditions.\n\n## Instructions\n\n1. Add actionable instruction one.\n2. Add actionable instruction two.\n" - } - }, - "McpSettings": { - "loading": "Carregando...", - "summary": { - "missingCommand": "(comando ausente)", - "missingUrl": "(URL ausente)" - }, - "protocol": { - "stdio": "Stdio" - }, - "errors": { - "selectInstallProtocol": "Selecione um protocolo de instalação", - "fieldRequired": "{field} é obrigatório", - "fieldNeedsBoolean": "{field} deve ser true ou false", - "fieldNeedsNumber": "{field} deve ser um número", - "fieldNeedsInteger": "{field} deve ser um inteiro", - "fieldInvalidJson": "{field} tem JSON inválido: {message}", - "fieldOutOfRange": "O valor de {field} está fora do intervalo permitido", - "jsonEmpty": "{name} não pode estar vazio", - "jsonInvalid": "{name} não é um JSON válido: {message}", - "jsonMustBeObject": "{name} deve ser um objeto JSON", - "specMustBeObject": "A configuração do MCP deve ser um objeto JSON.", - "missingType": "Falta o campo type na configuração do MCP. Use stdio, http (aliases: streamable-http, streamableHttp) ou sse.", - "unsupportedType": "Tipo de MCP não suportado {type}. Suportados: stdio, http (aliases: streamable-http, streamableHttp), sse.", - "codexEntryUnsupportedType": "A entrada Codex MCP {id} tem tipo não suportado {type}. Suportados: stdio, http (aliases: streamable-http, streamableHttp), sse.", - "unsupportedTransportType": "Tipo de transport não suportado {type}. Suportados: http (aliases: streamable-http, streamableHttp), sse.", - "stdioCommandRequired": "Um MCP stdio exige um campo command não vazio.", - "remoteUrlRequired": "Um MCP remoto exige um campo url não vazio.", - "appsRequired": "Selecione ao menos um aplicativo alvo." - }, - "jsonNames": { - "localConfig": "Configuração MCP", - "installConfig": "Configuração de instalação" - }, - "toasts": { - "uninstalled": "MCP desinstalado", - "uninstallFailed": "Falha ao desinstalar: {message}", - "selectAtLeastOneApp": "Selecione pelo menos um app de destino", - "saveSuccess": "Salvo", - "saveFailed": "Falha ao salvar: {message}", - "installed": "{name} instalado", - "installFailed": "Falha na instalação: {message}", - "serverIdRequired": "O Server ID é obrigatório", - "serverIdExists": "O Server ID \"{id}\" já existe. Edite a entrada existente ou escolha outro nome.", - "created": "MCP criado" - }, - "installDialog": { - "title": "Confirmar instalação do MCP", - "descriptionWithName": "Instalar {name} na configuração local.", - "description": "Selecione os apps de destino para instalação.", - "protocol": "Protocolo", - "selectProtocol": "Selecionar protocolo", - "parameters": "Parâmetros de configuração", - "booleanPlaceholder": "Selecione true/false", - "selectOneValue": "Selecione um valor", - "targetApps": "Apps de destino" - }, - "actions": { - "cancel": "Cancelar", - "confirmInstall": "Confirmar instalação", - "installing": "Instalando", - "uninstall": "Desinstalar", - "uninstalling": "Desinstalando", - "viewDetails": "Ver detalhes", - "save": "Salvar", - "saving": "Salvando", - "install": "Instalar", - "refresh": "Atualizar", - "newMcp": "Novo MCP", - "create": "Criar", - "creating": "Criando..." - }, - "tabs": { - "local": "MCP local", - "market": "Marketplace MCP" - }, - "local": { - "filterPlaceholder": "Filtrar MCP local...", - "loadFailed": "Falha ao carregar: {message}", - "empty": "Nenhum MCP local detectado.", - "description": "A configuração local de MCP pode ser editada e salva diretamente.", - "enabledApps": "Apps habilitados", - "configJson": "Configuração MCP (JSON)", - "draftTitle": "Novo MCP", - "draftDescription": "Informe um Server ID e a configuração para criar um servidor MCP local.", - "serverIdLabel": "Server ID", - "serverIdPlaceholder": "Server ID (ex.: my-mcp)", - "typeHint": "Tipos suportados: stdio, http (aliases: streamable-http, streamableHttp), sse. env só é usado por stdio; para MCPs remotos use headers para transportar tokens de autenticação.", - "envOnRemoteWarning": "env detectado em um MCP remoto. Apenas stdio usa env; MCPs remotos transportam tokens de autenticação via headers, portanto env será ignorado ao salvar." - }, - "market": { - "selectMarketplace": "Selecionar marketplace", - "searchPlaceholder": "Pesquisar MCP...", - "searchFailed": "Falha na busca: {message}", - "loadingList": "Carregando lista de MCP...", - "empty": "Nenhum resultado de MCP.", - "loadingDetail": "Carregando detalhes do marketplace...", - "detailLoadFailed": "Falha ao carregar detalhes: {message}", - "owner": "Proprietário: {owner}", - "namespace": "Namespace: {namespace}", - "defaultInstallProtocol": "Protocolo de instalação padrão", - "currentOptionParameterCount": "Quantidade de parâmetros da opção atual: {count}", - "installConfigDescription": "Configuração de instalação (JSON, editável antes de instalar; edições substituirão o formulário de protocolo/parâmetros)", - "selectLeftToView": "Selecione um MCP do marketplace à esquerda para ver detalhes." - }, - "badges": { - "verified": "Verificado", - "remote": "Remoto", - "hasHomepage": "Tem homepage", - "uses": "{count} usos", - "deployed": "Implantado", - "notDeployed": "Não implantado" - }, - "selectLeftMcp": "Selecione um MCP à esquerda." - }, - "AcpAgentSettings": { - "title": "Gerenciamento do SDK de agentes", - "description": "Gerencie em um só lugar a conexão do SDK de agentes, estado habilitado, variáveis de ambiente, gerenciamento de configuração e informações de preflight de versão.", - "loadingAgents": "Carregando lista de agentes...", - "agentList": "Lista de agentes", - "emptyNoAgent": "Nenhum agente disponível.", - "configManagement": "Gerenciamento de configuração", - "envVars": "Variáveis de ambiente", - "hostTools": { - "label": "Deixar o agente cuidar de arquivos e comandos", - "description": "O codeg deixa de atender o acesso a arquivos e os comandos de terminal, de modo que o agente os executa no próprio processo — onde o sandbox e as regras de permissão dele realmente se aplicam. A delegação a outros agentes também é desativada, pois levaria o mesmo trabalho de volta ao codeg. O codeg não adiciona sandbox algum, então ative isto apenas se o agente tiver um configurado." - }, - "nativeJsonConfig": "Configuração JSON nativa", - "modelHintDefault": "Deixe em branco para usar o modelo padrão do sistema.", - "generalConfigDescriptionClaude": "Suporta configuração rápida de API URL, API Key e modelos Claude, e sincroniza com a configuração JSON nativa.", - "generalConfigDescriptionDefault": "Suporta entrada de configuração importante (API URL, API Key, Model) e gerenciamento de configuração JSON nativa.", - "multiAgent": { - "title": "Colaboração multiagente", - "description": "Permite que agentes ativos deleguem subtarefas a outros agentes.", - "enable": "Ativar delegação", - "enableHint": "Quando desativado, a ferramenta delegate_to_agent fica oculta no catálogo de ferramentas MCP do agente.", - "withheldByHostTools": "{agents} não receberão as ferramentas de delegação: o interruptor por agente “Deixar o agente lidar com arquivos e comandos” está ligado.", - "depthLimit": "Profundidade máxima de delegação", - "depthHint": "Intervalo permitido: {min}–{max}. Limita a profundidade de recursão de uma cadeia de delegação (raiz → filho → neto …).", - "completedCacheLabel": "Cache de resultados concluídos (MB)", - "completedCacheHint": "Cache em memória dos resultados concluídos de subagentes, mantido apenas enquanto a sessão de delegação está em execução e liberado automaticamente quando essa sessão termina. Acima deste limite, os resultados mais antigos são descartados da memória primeiro (ainda visíveis na sessão do próprio subagente); 0 = ilimitado (ainda assim liberado ao terminar a sessão).", - "save": "Salvar", - "saving": "Salvando…", - "saved": "Configurações de delegação salvas", - "saveFailed": "Falha ao salvar configurações de delegação", - "loadFailed": "Falha ao carregar configurações de delegação: {detail}", - "tabGeneral": "Geral", - "tabAgentDefaults": "Padrões do subagente", - "agentDefaultsDescription": "Substituições por agente aplicadas quando a Colaboração multiagente inicia um subagente para uma chamada de delegação. As opções mostradas vêm de uma sondagem ao vivo: o que você escolhe é exatamente o que o agente aceitará.", - "probing": "Carregando opções disponíveis do agente…", - "probeFailed": "Falha ao carregar opções: {detail}", - "retry": "Tentar novamente", - "noConfigAvailable": "Este agente não possui opções configuráveis.", - "modeLabel": "Modo", - "agentDefaultHint": "Padrão do agente: {value}", - "defaultOptionLabel": "Padrão ({value})" - }, - "actions": { - "dragSort": "Arraste para reordenar", - "dragSortAgent": "Arraste para reordenar {name}", - "refreshCheck": "Atualizar verificação", - "refreshCheckAgent": "Atualizar verificação de {name}", - "clickEnable": "Clique para habilitar {name}", - "clickDisable": "Clique para desabilitar {name}", - "install": "Instalar", - "upgrade": "Atualizar", - "uninstall": "Desinstalar", - "uninstalling": "Desinstalando...", - "saveEnvVars": "Salvar variáveis de ambiente", - "saving": "Salvando...", - "saveGrokConfig": "Salvar configuração do Grok", - "saveCodexConfig": "Salvar configuração do Codex", - "saveGeminiConfig": "Salvar configuração do Gemini", - "saveOpenCodeConfig": "Salvar configuração do OpenCode", - "saveOpenClawConfig": "Salvar configuração do OpenClaw", - "saveConfigManagement": "Salvar gerenciamento de configuração", - "saveCurrentProvider": "Salvar provedor atual", - "showApiKey": "Mostrar API Key", - "hideApiKey": "Ocultar API Key", - "showKey": "Mostrar chave", - "hideKey": "Ocultar chave", - "showToken": "Mostrar token", - "hideToken": "Ocultar token", - "cancel": "Cancelar", - "delete": "Excluir", - "deleting": "Excluindo...", - "confirmDelete": "Confirmar exclusão", - "confirmUninstall": "Confirmar desinstalação", - "saveClineConfig": "Salvar configuração do Cline", - "saveHermesConfig": "Salvar configuração do Hermes", - "saveCodeBuddyConfig": "Salvar configuração do CodeBuddy", - "saveKimiCodeConfig": "Salvar configuração do Kimi Code", - "customInstall": "Instalação personalizada", - "saveKimiCodeRawConfig": "Save config.toml", - "saveDeepSeekConfig": "Salvar configuração do DeepSeek", - "diagnose": "Diagnosticar" - }, - "status": { - "enabled": "Habilitado", - "disabled": "Desabilitado", - "unchecked": "Não verificado", - "agentEnabledAria": "{name} habilitado", - "agentEnabledSwitch": "Chave de habilitação de {name}" - }, - "preflight": { - "count": "Itens de preflight: {count}", - "notRun": "As verificações ainda não foram executadas." - }, - "grok": { - "configDescription": "Configure o Grok aqui. Os controles abaixo — modo de permissão, esforço de raciocínio, um modelo personalizado opcional (endpoint próprio) e a compactação — são mesclados em ~/.grok/config.toml, preservando suas outras chaves e comentários. O login usa seu XAI_API_KEY ou `grok login`. As demais chaves continuam editáveis em Avançado.", - "permissionModeLabel": "Modo de permissão", - "permissionDefault": "Perguntar sempre", - "permissionAcceptEdits": "Aprovar edições automaticamente", - "permissionAuto": "Aprovação automática inteligente", - "permissionAlwaysApprove": "Sempre aprovar", - "reasoningEffortLabel": "Esforço de raciocínio", - "effortLow": "Baixo (mais rápido)", - "effortMedium": "Médio (equilibrado)", - "effortHigh": "Alto", - "effortXhigh": "Máximo", - "optionDefault": "Usar padrão", - "authTitle": "Autenticação", - "authMode": "Método de autenticação", - "authModeApiKey": "Chave de API da XAI", - "authModeApiKeyHint": "Autentique-se com uma XAI_API_KEY do console da xAI, para execuções não interativas ou headless. Armazenada no ambiente deste agente.", - "authModeCustom": "Endpoint personalizado", - "authModeCustomHint": "Use um endpoint próprio (BYO): defina abaixo um modelo personalizado com a sua própria base URL e chave de API. Ele se torna o modelo padrão do Grok.", - "subscriptionHint": "Entre com `grok login` (SuperGrok / X Premium+). Nenhuma chave de API é armazenada.", - "loginHint": "Execute isto num terminal para entrar e depois reabra estas configurações:", - "commandCopied": "Comando copiado para a área de transferência", - "copyCommand": "Copiar comando", - "authKeyConfigured": "XAI_API_KEY está configurada.", - "authKeyMissing": "Nenhuma XAI_API_KEY definida.", - "advancedToggle": "Avançado (config.toml bruto)", - "configTomlNative": "config.toml (nativo)", - "configTomlHint": "Salvo literalmente como todo o ~/.grok/config.toml. TOML inválido é rejeitado para que um erro de digitação nunca trunque seu arquivo.", - "configTomlPlaceholder": "# Chaves além dos controles acima, por ex.\n# [mcp_servers.*], [cli], regras [permission].", - "customModelTitle": "Modelo personalizado (endpoint próprio)", - "customModelHint": "Aponte o Grok para um endpoint personalizado ou auto-hospedado. O codeg grava um bloco `[model.*]` por modelo e o define como padrão. Deixe o ID do modelo vazio para removê-lo.", - "customModelIdLabel": "ID do modelo", - "customModelIdPlaceholder": "grok-4.5", - "customModelIdHint": "Registrado como um bloco `[model.*]` e enviado à API como nome do modelo; também definido como `[models].default`.", - "customBaseUrlLabel": "URL base", - "customBaseUrlPlaceholder": "https://api.x.ai/v1 (padrão)", - "customApiBackendLabel": "Backend da API", - "backendResponses": "Responses", - "backendChatCompletions": "Chat Completions", - "backendMessages": "Messages (Anthropic)", - "customApiKeyLabel": "Chave de API", - "customApiKeyHint": "Armazenada em linha em `[model.*].api_key`, restrita a este endpoint.", - "customContextWindowLabel": "Janela de contexto (tokens)", - "customContextWindowHint": "Opcional. Define o momento da autocompactação; deixe vazio para o padrão do endpoint.", - "autoCompactLabel": "Limite de autocompactação (%)", - "autoCompactHint": "Compacta a conversa quando o uso do contexto atinge esta porcentagem (padrão do Grok: 85). Gravado em `[session]`." - }, - "cursor": { - "configDescription": "Configure o Cursor aqui. Escolha um método de autenticação — assinatura oficial (login pelo navegador) ou uma chave de API do Cursor para máquinas headless ou servidores — depois escolha um modelo e edite as regras de permissão e o sandbox do CLI. O codeg as grava em ~/.cursor/cli-config.json, compartilhado com o CLI cursor-agent.", - "authTitle": "Autenticação", - "authChecking": "Verificando…", - "authNotInstalled": "cursor-agent não está instalado", - "authLoggedIn": "Conectado", - "authNotLoggedIn": "Não conectado", - "loginHint": "Execute isto em um terminal para entrar na sua conta Cursor (uma janela do navegador abre) e depois clique em atualizar:", - "apiKeyLabel": "Chave de API do Cursor", - "apiKeyPlaceholder": "chave de cursor.com/dashboard", - "apiKeyHint": "CURSOR_API_KEY — uma chave de conta do painel do Cursor, alternativa ao login pelo navegador para máquinas headless ou servidores. Não é uma chave de terceiros nem da OpenAI.", - "modelTitle": "Modelo padrão", - "loadModels": "Carregar modelos", - "modelsUnavailable": "Lista de modelos indisponível", - "modelHint": "Passado à CLI como --model ao iniciar a sessão. Deixe no padrão para o Cursor escolher.", - "permissionsTitle": "Permissões e sandbox", - "permissionsDescription": "Editor visual das regras de permissão da CLI (cli-config.json). Regras permitidas executam sem confirmação; regras negadas são sempre bloqueadas.", - "permissionModeLabel": "Modo de permissões", - "permissionModeDefault": "Perguntar antes de executar (padrão)", - "permissionModeForce": "Run Everything (--force)", - "permissionModeHint": "Run Everything inicia as sessões com --force: todas as chamadas de ferramentas são permitidas automaticamente, exceto as regras de negação, sem confirmações (uma política da organização pode limitá-lo às regras de permissão). Vale para novas sessões.", - "optionDefault": "Padrão (não definido)", - "sandboxLabel": "Sandbox", - "sandboxEnabled": "Ativado", - "sandboxDisabled": "Desativado", - "allowRulesLabel": "Regras permitidas", - "denyRulesLabel": "Regras negadas", - "addRule": "Adicionar regra", - "rulesSyntaxHint": "Sintaxe das regras: Shell(cmd), Read(caminho/glob), Write(caminho/glob), WebFetch(domínio), Mcp(servidor:ferramenta) — as regras de negação sempre prevalecem.", - "saveConfig": "Salvar configuração", - "advancedToggle": "Avançado: cli-config.json bruto", - "advancedHint": "O ~/.cursor/cli-config.json completo. Salvar grava o arquivo como está; os controles estruturados acima são mesclados nele.", - "saveRawConfig": "Salvar arquivo", - "authMode": "Método de autenticação", - "subscriptionHint": "Faça login com sua conta Cursor e use os modelos do Cursor.", - "customApiKeyRequired": "É necessária uma chave de API do Cursor.", - "authModeApiKey": "Chave de API do Cursor (headless/servidor)", - "authModeApiKeyHint": "Autentique-se com uma chave de API de conta do Cursor gerada no painel do Cursor (para máquinas headless ou servidores). É uma chave de conta do Cursor, não um endpoint de terceiros/OpenAI: o cursor-agent só se comunica com o backend do próprio Cursor. Para usar um endpoint compatível com codex/OpenAI, use o agente Codex.", - "modelPickerPlaceholder": "Pesquisar modelos…", - "modelNoMatch": "Nenhum modelo correspondente", - "modelsNeedAuth": "Faça login para carregar a lista de modelos.", - "modelDefaultBadge": "padrão" - }, - "deepseek": { - "configManagement": "Configuração do DeepSeek Harness", - "configDescription": "O endpoint e a chave são variáveis de ambiente que o deepseek-acp lê ao iniciar. O modelo e o nível de raciocínio são seletores por sessão — escolha-os no campo de mensagem.", - "baseUrlLabel": "Endpoint da API", - "baseUrlHint": "Deixe vazio para o endpoint oficial. Vale para as sessões iniciadas depois de salvar; reconecte uma sessão em andamento para que ela use o novo valor.", - "baseUrlInvalid": "Informe uma URL http(s) completa e sem query string, por exemplo https://api.deepseek.com", - "apiKeyLabel": "Chave de API", - "apiKeyHint": "Enviada ao agente como DEEPSEEK_API_KEY. Uma variável de ambiente tem precedência sobre o arquivo de credenciais, então deixe em branco se você entrar pelo terminal." - }, - "codex": { - "configDescription": "Suporta configuração rápida de URL da API, API Key, nome do modelo e reasoning effort, com sincronização para `auth.json` / `config.toml`.", - "authMode": "Modo de Autenticação", - "chatgptSubscription": "Assinatura oficial", - "chatgptSubscriptionHint": "Faça login com assinatura oficial do ChatGPT, sem necessidade de API Key", - "apiKeyHint": "Conecte-se usando API Key ao OpenAI ou serviços de API compatíveis", - "selectProvider": "Selecionar provedor", - "modelName": "Nome do modelo", - "selectReasoningEffort": "Selecionar Reasoning Effort", - "enableWebsocket": "Habilitar WebSocket", - "enableWebsocketAria": "Habilitar WebSocket para Codex Provider", - "enableSkills": "Habilitar Skills", - "enableSkillsAria": "Habilitar Skills para Codex", - "enableFast": "Habilitar Fast", - "enableFastAria": "Habilitar nível de serviço Fast para Codex", - "sandboxGroupTitle": "Sandbox e aprovações", - "sandboxGroupHint": "Gravado no ~/.codex/config.toml global, portanto as sessões do codex CLI e do IDE também usam. São padrões do thread: valem para os turnos que o codex inicia sozinho (/goal, /review, /compact). Mensagens comuns usam a predefinição de aprovação do compositor. Reinicie a sessão para aplicar as alterações.", - "sandboxShadowedWarning": "O config.toml define default_permissions, então o codex resolve as permissões por esse perfil e ignora sandbox_mode por completo. Remova default_permissions para usar os controles abaixo.", - "sandboxPermissionsTableWarning": "O config.toml define perfis [permissions] sem default_permissions, o que faz o codex recusar a iniciar. Defina um no editor bruto abaixo.", - "approvalPolicyLabel": "Política de aprovação", - "approvalPolicyUnset": "Não definida (padrão do codex: sob demanda)", - "approvalPolicy_on-request": "Sob demanda — o modelo decide quando perguntar", - "approvalPolicy_untrusted": "Não confiável — só comandos de leitura reconhecidos como seguros rodam sem confirmação", - "approvalPolicy_never": "Nunca — nenhum pedido de aprovação", - "approvalPolicy_granular": "Granular — escolha por tipo de solicitação", - "approvalPolicyUntrustedAcpWarning": "Untrusted não tem equivalente entre os três presets de aprovação do adaptador ACP, então as sessões do codeg voltam para \"quando solicitado\": o modelo passa a decidir quando perguntar, e comandos que o sandbox já permite deixam de pedir confirmação. Restrinja o modo de sandbox abaixo em vez disso.", - "granularHint": "Desligado significa que esse tipo de solicitação é recusado automaticamente em vez de exibido a você.", - "granular_sandbox_approval": "Escalonamentos de comandos de shell", - "granular_rules": "Avisos de regras do execpolicy", - "granular_skill_approval": "Avisos de scripts de habilidades", - "granular_request_permissions": "Avisos da ferramenta request_permissions", - "granular_mcp_elicitations": "Avisos de elicitação MCP", - "sandboxModeLabel": "Modo de sandbox", - "sandboxModeUnset": "Não definido (pastas confiáveis caem para escrita no espaço de trabalho)", - "sandboxMode_read-only": "Somente leitura", - "sandboxMode_workspace-write": "Escrita no espaço de trabalho", - "sandboxMode_danger-full-access": "Acesso total (sem sandbox)", - "sandboxModeHint": "No Windows, a escrita no espaço de trabalho é rebaixada para somente leitura, a menos que o sandbox experimental do Windows do codex esteja ativado.", - "sandboxModeSeedsPresetHint": "O codeg também usa isto para o preset de aprovação inicial da sessão, portanto — ao contrário da política de aprovação — ele afeta os prompts comuns. O preset escolhido no editor continua tendo prioridade.", - "writableRootsLabel": "Pastas graváveis extras", - "writableRootsHint": "Um caminho absoluto por linha, além do diretório de trabalho.", - "sandboxRootsRelativeError": "Precisa ser um caminho absoluto — o codex resolve caminhos relativos dentro de ~/.codex: {path}", - "networkAccessLabel": "Permitir acesso à rede", - "excludeTmpdirLabel": "Excluir TMPDIR das raízes graváveis", - "excludeSlashTmpLabel": "Excluir /tmp das raízes graváveis", - "authJsonNative": "auth.json (nativo)", - "configTomlNative": "config.toml (nativo)", - "loginButton": "Entrar com ChatGPT", - "loginRequesting": "Solicitando código de login...", - "loginStep1": "Abra a seguinte URL no seu navegador:", - "loginStep2": "Digite o código abaixo:", - "loginPolling": "Aguardando autorização...", - "loginCancel": "Cancelar", - "loginSuccess": "Login realizado com sucesso, configuração salva!", - "loginFailed": "Falha no login: {message}", - "loginRetry": "Tentar novamente", - "loginCodeCopied": "Código copiado", - "loggedIn": "Conta conectada", - "loginRelogin": "Reconectar / Trocar conta", - "loginTimeout": "Login expirou, tente novamente", - "loginSaveFailed": "Login realizado com sucesso, mas falha ao salvar configuração" - }, - "gemini": { - "authConfig": "Configuração de autenticação do Gemini", - "authConfigDescription": "Alinhada à documentação de autenticação do Gemini CLI, com suporte a endpoint personalizado, login Google, Gemini API Key e Vertex AI (ADC / conta de serviço / API Key).", - "authMode": "Modo de autenticação", - "selectAuthMode": "Selecionar modo de autenticação", - "viewAuthDoc": "Ver documentação de autenticação", - "mode": { - "custom": "Endpoint personalizado", - "loginGoogle": "Login Google (OAuth)", - "vertexServiceAccount": "Vertex AI (Conta de serviço)" - }, - "hint": { - "custom": "Preencha API URL, API Key e Modelo; mapeados para GOOGLE_GEMINI_BASE_URL / GEMINI_API_KEY / GEMINI_MODEL.", - "loginGoogle": "Execute gemini no terminal e conclua o login Google primeiro; API key não é necessária.", - "geminiApiKey": "Preencha GEMINI_API_KEY ao usar a API Gemini.", - "vertexAdc": "Use gcloud ADC; GOOGLE_CLOUD_PROJECT e GOOGLE_CLOUD_LOCATION são recomendados.", - "vertexServiceAccount": "Defina o caminho do JSON da conta de serviço em GOOGLE_APPLICATION_CREDENTIALS.", - "vertexApiKey": "Preencha GOOGLE_API_KEY ao usar API key do Vertex AI." - } - }, - "openCode": { - "configManagement": "Gerenciamento de configuração do OpenCode", - "configDescription": "Alinhado ao esquema `provider` do OpenCode, com suporte a gerenciamento multi-provedor e sincronização bidirecional com arquivos JSON nativos.", - "providerManagement": "Gerenciamento de provedores", - "providerCount": "{count} provedores", - "addProvider": "Adicionar provedor", - "emptyProvider": "Ainda não há provedores personalizados. Clique em Adicionar provedor personalizado para criar um.", - "providerEnabledState": "Estado habilitado de {providerId}", - "selectProviderNpm": "Selecionar provider.npm", - "modelManagement": "Gerenciamento de modelos", - "modelCount": "{count} modelos", - "modelDescription": "Alinhado ao `provider.models` do OpenCode. O gerenciamento rápido atualmente suporta `name` / `id`; outros campos avançados são preservados e podem ser editados no JSON nativo abaixo.", - "addModel": "Adicionar modelo", - "emptyModel": "Ainda não há modelo. Informe model id e clique em \"Adicionar modelo\".", - "modelId": "ID do modelo", - "modelName": "Nome do modelo", - "deleteModel": "Excluir modelo {modelId}", - "nativeJsonConfig": "Configuração JSON nativa do OpenCode", - "mainModel": "Modelo principal", - "smallModel": "Modelo pequeno", - "noMatchingModels": "Nenhum modelo correspondente", - "connectProvider": "Conectar provedor", - "connectedProviders": "Provedores conectados", - "noConnectedProviders": "Ainda não há provedores do catálogo conectados.", - "advancedProviderConfig": "Provedores personalizados", - "customProviderConfigHint": "Endpoints compatíveis com OpenAI que você mesmo define — um bloco de provider em opencode.json, com a API key em auth.json.", - "addCustomProvider": "Adicionar provedor personalizado", - "disconnect": "Desconectar", - "editConfig": "Editar", - "customBadge": "Personalizado", - "authKindApi": "Chave de API", - "authKindOauth": "OAuth", - "authKindNone": "Sem credencial", - "connect": { - "title": "Conectar um provedor", - "description": "Escolha um provedor no catálogo do models.dev. As credenciais são salvas no arquivo auth.json do OpenCode.", - "pick": "Provedor", - "search": "Pesquisar provedores…", - "loading": "Carregando catálogo…", - "catalogLabel": "Catálogo do models.dev", - "modelsAvailable": "{count} modelos disponíveis", - "getKey": "Obter chave de API", - "oauthApiKeyNote": "Este provedor também oferece login pelo navegador via opencode auth login. O login pelo navegador chegará em breve — por enquanto, cole uma chave de API.", - "apiKey": "Chave de API", - "apiKeyHint": "Salva em auth.json, nunca em opencode.json.", - "baseUrlOptional": "Substituir Base URL (opcional)", - "providerId": "ID do provedor", - "displayName": "Nome de exibição", - "modelsList": "Modelos (um por linha)", - "modelsHint": "IDs de modelo que o endpoint aceita.", - "action": "Conectar", - "editTitle": "Editar provedor", - "editDescription": "Atualize a chave de API ou a Base URL deste provedor.", - "saveAction": "Salvar" - }, - "customProvider": { - "title": "Adicionar um provedor personalizado", - "description": "Defina um endpoint compatível com OpenAI. A API key é salva em auth.json; o bloco de provider vai para opencode.json.", - "action": "Adicionar provedor", - "idInCatalog": "{providerId} é um provedor conhecido — conecte-o via Conectar provedor." - }, - "refreshCatalog": "Atualizar catálogo", - "reasoningBadge": "raciocínio", - "contextWindow": "Janela de contexto", - "permissions": { - "title": "Permissões", - "description": "Decida quais ações rodam sozinhas, quais pedem sua confirmação e quais são bloqueadas. Gravado no bloco permission do opencode.json e aplicado ao salvar abaixo.", - "docsLink": "Documentação de permissões", - "unparsableConfig": "O JSON nativo abaixo não é válido, então o editor visual está pausado. Corrija o JSON para continuar.", - "invalidBlock": "O bloco permission tem um formato que o codeg não reconhece. Edite-o no JSON nativo abaixo ou use Redefinir para começar de novo.", - "orderingUnsafe": "Há uma regra curinga escrita depois de ferramentas específicas, então o OpenCode a aplica a elas também — as linhas abaixo não são o que está em vigor. Corrigir ordem apenas devolve cada curinga ao início do seu escopo, sem mudar nenhum valor.", - "orderingUnsafeManual": "Uma regra fica encoberta por um padrão mais geral escrito depois dela, então o OpenCode nunca a aplica — as linhas abaixo não são o que está em vigor. Dois padrões que se sobrepõem não têm uma única ordem certa; reordene-os no JSON nativo para que o mais geral venha primeiro.", - "fixOrder": "Corrigir ordem", - "agentOverrides": "Estes agentes sobrepõem as permissões e são aplicados por último, então vencem tudo daqui: {agents}. Edite-os no JSON nativo abaixo ou ative o aceite automático para apagá-los.", - "legacyTools": "O mapa tools legado de nível superior nega uma ferramenta. O OpenCode o funde com as permissões, então ele se aplica acima de tudo o que aparece aqui. Edite-o no JSON nativo abaixo ou ative o aceite automático para apagá-lo.", - "autoAcceptTitle": "Aceitar todas as permissões automaticamente", - "autoAcceptHint": "Toda chamada de ferramenta — comandos de shell, edições de arquivos, caminhos fora do projeto — roda sem perguntar. Ao ativar, as configurações por ferramenta abaixo são substituídas por uma única regra que permite tudo, e as sobreposições por agente e os interruptores tools legados que ainda bloqueariam são apagados.", - "globalLabel": "Padrão global", - "globalHint": "A regra *: vale para tudo que as ferramentas abaixo não sobrescreverem.", - "actionUnset": "Não definido (padrões do OpenCode)", - "actionInherit": "Herdar ({action})", - "actionAllow": "Permitir", - "actionAsk": "Perguntar", - "actionDeny": "Negar", - "perToolTitle": "Permissões por ferramenta", - "reset": "Redefinir", - "ruleCount": "regras: {count}", - "rulesToggle": "Regras detalhadas de {tool}", - "rulesHint": "São comparadas com a entrada da ferramenta e a última correspondência vence, então coloque os padrões amplos primeiro. * corresponde a quaisquer caracteres, ? a exatamente um, e um ~ inicial vira sua pasta pessoal.", - "noRules": "Ainda não há regras detalhadas.", - "addRule": "Adicionar regra", - "deleteRule": "Excluir a regra {pattern}", - "duplicateRule": "Esse padrão já existe.", - "blankRule": "Uma regra precisa de um padrão — use o ícone de lixeira para removê-la.", - "customKeys": "Outras chaves de permissão no arquivo", - "customKeyHint": "Não é uma ferramenta integrada do OpenCode — mantida como está.", - "keys": { - "bash": "Executar comandos de shell, pelo comando analisado", - "edit": "Todas as modificações de arquivos: edit, write e patch", - "read": "Ler arquivos, pelo caminho", - "external_directory": "Acessar caminhos fora do diretório de trabalho do projeto", - "task": "Iniciar subagentes, pelo tipo de subagente", - "skill": "Carregar skills, pelo nome", - "glob": "Encontrar arquivos, pelo padrão glob", - "grep": "Pesquisar o conteúdo dos arquivos, pelo padrão", - "list": "Listar o conteúdo de um diretório", - "webfetch": "Buscar uma URL", - "websearch": "Pesquisar na web", - "lsp": "Executar consultas LSP", - "todowrite": "Escrever a lista de tarefas", - "question": "Fazer uma pergunta a você", - "doom_loop": "Dispara quando a mesma chamada se repete três vezes com a mesma entrada" - } - } - }, - "openClaw": { - "gatewayConfig": "Configuração de Gateway", - "gatewayDescription": "Configure a conexão do OpenClaw Gateway. Suporta gateway local ou remoto.", - "gatewayUrlHint": "Deixe vazio para usar gateway.remote.url da configuração local do openclaw.", - "gatewayTokenPlaceholder": "Token de autenticação do Gateway", - "gatewayTokenHint": "Use token-file em vez de token em texto puro quando possível; configure via CLI do openclaw.", - "sessionKeyHint": "Opcional. Especifique a session key do gateway; deixe vazio para atribuição automática de sessão isolada." - }, - "hermes": { - "configManagement": "Configuração do Hermes", - "configDescription": "O Hermes gerencia suas próprias credenciais em ~/.hermes/.env e as configurações em ~/.hermes/config.yaml. Escolha um provedor e, em seguida, defina a chave de API e o modelo — o codeg grava os dois arquivos para você.", - "providerLabel": "Provedor", - "providerHint": "O provedor determina qual variável de chave de API e qual model.provider o Hermes usa. Provedores OAuth são configurados pela configuração de terminal abaixo.", - "groupApiKey": "Provedores com chave de API", - "groupOauth": "Provedores OAuth", - "groupAws": "AWS", - "apiKeyHint": "Salva em ~/.hermes/.env. Ela nunca é injetada no processo — o Hermes a lê da sua própria configuração.", - "modelName": "Modelo", - "oauthHint": "Este provedor usa OAuth. Execute a configuração abaixo para autenticar no seu terminal.", - "awsHint": "O Bedrock usa suas credenciais da AWS (ambiente ou configuração compartilhada). Defina o ID do modelo acima e configure o acesso à AWS no seu ambiente.", - "unsupportedProvider": "Este provedor não pode ser editado com campos estruturados. Use o editor de config.yaml abaixo ou a configuração pelo terminal.", - "setupTitle": "Configuração autogerenciada", - "setupHint": "A configuração interativa do Hermes precisa de um terminal. Inicie-a abaixo ou copie o comando para executá-lo você mesmo.", - "runSetup": "Executar configuração do Hermes", - "configureModel": "Configurar modelo", - "openConfigFolder": "Abrir ~/.hermes", - "copyCommand": "Copiar comando", - "commandCopied": "Comando copiado para a área de transferência", - "advancedTitle": "Avançado: editar config.yaml", - "rawConfigHint": "Edite ~/.hermes/config.yaml diretamente. Salvar aqui sobrescreve o arquivo exatamente como está.", - "saveRawConfig": "Salvar config.yaml" - }, - "codebuddy": { - "configManagement": "Configuração do CodeBuddy", - "configDescription": "O CodeBuddy autentica com uma chave de API. As versões da China continental também exigem o ambiente definido como “China (internal)”; as versões iOA usam “iOA”. A versão internacional deixa sem definir.", - "apiKeyLabel": "Chave de API", - "apiKeyHint": "Salvo como CODEBUDDY_API_KEY para este agente. Como alternativa, faça login com a CLI do CodeBuddy em um terminal.", - "apiKeyHintSelfHosted": "Salvo como CODEBUDDY_API_KEY para este agente. Use a chave emitida pela sua implantação privada.", - "environmentLabel": "Ambiente", - "environmentHint": "Define CODEBUDDY_INTERNET_ENVIRONMENT. A China continental deve usar “China (internal)”; a versão internacional deixa sem definir.", - "envOverseas": "Internacional (padrão)", - "envChina": "China (internal)", - "envIoa": "iOA", - "envSelfHosted": "Auto-hospedado (implantação privada)", - "baseUrlLabel": "URL de implantação", - "baseUrlPlaceholder": "https://codebuddy.your-company.com", - "baseUrlHint": "Salvo como CODEBUDDY_BASE_URL e aponta o CodeBuddy para seu endpoint privado. No auto-hospedado, o ambiente de rede (CODEBUDDY_INTERNET_ENVIRONMENT) fica sem definição.", - "baseUrlInvalid": "Insira uma URL http(s) válida.", - "loginHint": "Sem chave de API? Execute “codebuddy” em um terminal para fazer login com sua conta Tencent." - }, - "kimiCode": { - "configManagement": "Configuração do Kimi Code", - "configDescription": "O `kimi acp` só aceita um token de login armazenado, por isso o codeg grava um provedor gerenciado em ~/.kimi-code/config.toml e cria um token de acesso local — a inferência continua usando a sua própria chave.", - "statusUnconfigured": "Ainda não configurado", - "statusDirty": "Alterações não salvas", - "summaryLabel": "Em vigor", - "gateReadyApiKey": "Chave de API gravada em config.toml", - "gateReadyLogin": "Conectado com uma conta Kimi", - "revealConfig": "Mostrar na pasta", - "envOverrideWarning": "{keys} está definido e tem prioridade sobre o config.toml. Salvar aqui remove essa variável.", - "authModeLabel": "Método de autenticação", - "authModeApiKey": "Chave de API", - "authModeLogin": "Login da conta Kimi (assinatura)", - "authModeApiKeyHint": "Grava um provedor gerenciado no config.toml e cria o token de acesso para que as sessões possam abrir.", - "loginHint": "Execute `kimi login` em um terminal para entrar com uma conta Kimi por assinatura. O codeg não armazena nada e reutiliza o login do próprio Kimi. Salvar aqui remove o token de acesso por chave de API do codeg.", - "credentialTitle": "Credencial", - "interfaceTypeLabel": "Tipo de provedor", - "interfaceTypeHint": "O protocolo de provedor que o Kimi fala (o `type` do config.toml). Use Kimi / Moonshot para uma chave da Moonshot / platform.kimi.com.", - "endpointLabel": "Endpoint", - "endpointCustom": "Personalizado (compatível com OpenAI)", - "endpointHint": "Internacional = api.moonshot.ai; China (chaves de platform.kimi.com) = api.moonshot.cn. Personalizado aponta para qualquer endpoint compatível com OpenAI.", - "regionInternational": "Internacional (api.moonshot.ai)", - "regionChina": "China (api.moonshot.cn)", - "baseUrlLabel": "URL base", - "baseUrlHint": "Deixe em branco para usar o padrão do SDK do provedor.", - "apiKeyLabel": "Chave de API", - "apiKeyHint": "Gravada em ~/.kimi-code/config.toml e usada para inferência. De platform.kimi.com ou platform.kimi.ai.", - "vertexProjectLabel": "Projeto do GCP (GOOGLE_CLOUD_PROJECT)", - "vertexLocationLabel": "Região do GCP (GOOGLE_CLOUD_LOCATION)", - "vertexHint": "O Vertex AI usa as credenciais padrão do aplicativo Google — execute `gcloud auth application-default login` (sem chave de API).", - "modelTitle": "Modelo", - "modelLabel": "Modelo", - "modelHint": "O id do modelo gravado no config.toml. Use «Testar e listar modelos» para ver o que a sua chave realmente acessa.", - "maxContextLabel": "Tamanho máximo de contexto", - "maxContextHint": "Obrigatório pelo esquema do Kimi: sem ele o Kimi descarta todo o bloco do modelo e nenhuma solicitação retorna resposta. Padrão 262144.", - "fetchModels": "Testar e listar modelos", - "fetchModelsOk": "A chave funciona — {count} modelos disponíveis", - "fetchModelsEmpty": "A chave funciona, mas nenhum modelo foi retornado", - "fetchModelsFailed": "Falha no teste", - "fetchModelsNeedsKey": "Informe primeiro uma chave de API e um endpoint", - "modelNotInList": "Este modelo não está na lista acessível pela sua chave — o Kimi falhará com «modelo não encontrado».", - "reasoningTitle": "Raciocínio", - "reasoningEnableLabel": "Ativar", - "reasoningDescription": "O Kimi só mostra o seletor «Thinking» na caixa de mensagem quando o modelo declara uma capacidade de raciocínio, por isso o codeg a grava aqui. Vale para sessões novas.", - "effortsLabel": "Níveis oferecidos", - "effortsHint": "Estes níveis viram as opções do seletor «Thinking». O Kimi repassa o nível ao provedor tal como está, então escolha os que o seu modelo aceita.", - "effortsEmptyHint": "Sem nenhum nível escolhido, a caixa de mensagem fica apenas com um interruptor Off / On.", - "effortsCustomPlaceholder": "Adicionar outro nível", - "effortsAdd": "Adicionar", - "defaultEffortLabel": "Nível padrão", - "defaultEffortAuto": "Deixar o Kimi escolher", - "alwaysThinkingLabel": "O modelo sempre raciocina — remover a opção Off do seletor", - "fixErrorsFirst": "Corrija primeiro os campos destacados", - "errorModelRequired": "O modelo é obrigatório", - "errorMaxContextRequired": "O tamanho máximo de contexto é obrigatório", - "errorMaxContextInvalid": "Deve ser um número inteiro positivo", - "errorApiKeyRequired": "A chave de API é obrigatória", - "errorApiKeyInvalid": "A chave de API não pode conter quebras de linha", - "errorBaseUrlRequired": "A URL base é obrigatória", - "errorBaseUrlInvalid": "Deve começar com http:// ou https://", - "errorVertexProjectRequired": "O projeto do GCP é obrigatório", - "errorDefaultEffortUnlisted": "Escolha um dos níveis selecionados acima", - "advancedTitle": "Avançado", - "authTypeLabel": "Local da credencial", - "authTypeApiKey": "api_key em linha", - "authTypeEnv": "Subtabela env do provedor", - "authTypeHint": "Onde a chave de API é gravada dentro do config.toml.", - "rawEditorLabel": "Editar config.toml diretamente", - "rawEditorWarning": "Salvar aqui sobrescreve o arquivo inteiro literalmente, substituindo as configurações estruturadas acima.", - "rawEditorPlaceholder": "[providers.codeg]\ntype = \"kimi\"\nbase_url = \"https://api.moonshot.cn/v1\"\napi_key = \"sk-...\"" - }, - "authModeOfficialSubscription": "Assinatura oficial", - "authModeCustomEndpoint": "Endpoint personalizado", - "authModeCustomEndpointHint": "Configurar manualmente a URL da API e a chave API para um endpoint personalizado.", - "authModeModelProvider": "Provedor de modelo", - "modelProvider": "Provedor de modelo", - "modelProviderHint": "Usar URL da API, chave API e modelo de um provedor de modelo configurado.", - "selectModelProvider": "Selecionar provedor de modelo", - "noModelProviderAvailable": "Nenhum provedor de modelo configurado para este agente. Vá para as configurações de provedores de modelo para adicionar um.", - "claude": { - "authMode": "Modo de autenticação", - "officialSubscription": "Assinatura oficial", - "officialSubscriptionHint": "Usar assinatura oficial da Anthropic, sem necessidade de API Key.", - "mainModel": "Modelo principal", - "reasoningModel": "Modelo de raciocínio (thinking)", - "haikuDefaultModel": "Modelo Haiku padrão", - "sonnetDefaultModel": "Modelo Sonnet padrão", - "opusDefaultModel": "Modelo Opus padrão", - "customModelOption": "ID do modelo personalizado", - "customModelOptionName": "Nome do modelo personalizado", - "customModelOptionDescription": "Descrição do modelo personalizado", - "customModelOptionHint": "Adiciona uma única entrada personalizada ao seletor de modelos do Claude (por exemplo, um modelo atrás de um gateway/proxy personalizado). Nome e descrição são informações de exibição opcionais.", - "effortLevel": "Nível de raciocínio", - "effortLevelDefault": "Nível padrão", - "effortLevel_low": "Baixo", - "effortLevel_medium": "Médio", - "effortLevel_high": "Alto", - "effortLevel_xhigh": "Extra Alto", - "sendAttributionHeader": "Enviar identificador de atribuição/cobrança para a API", - "sendAttributionHeaderAria": "Enviar o identificador de atribuição/cobrança do Claude Code para a API", - "disableNonessentialTraffic": "Desativar a telemetria ou solicitações de rede desnecessárias", - "disableNonessentialTrafficAria": "Desativar a telemetria ou solicitações de rede desnecessárias do Claude Code" - }, - "dialogs": { - "confirmDeleteProvider": "Excluir o provedor {providerId}?", - "confirmDeleteProviderDescription": "A configuração do OpenCode e o auth JSON serão atualizados juntos. Esta ação não pode ser desfeita.", - "confirmUninstall": "Desinstalar {name}?", - "confirmUninstallDescription": "Isso remove a versão instalada localmente. Você pode reinstalar depois.", - "customInstallTitle": "Instalação personalizada de {name}", - "customInstallDescription": "Digite a versão a instalar. Isso reinstala e substitui a versão instalada atualmente.", - "customInstallVersionLabel": "Número da versão", - "customInstallInvalid": "Digite um número de versão válido, ex.: 1.2.3.", - "customInstallSubmit": "Instalar" - }, - "errors": { - "windowsFileLocked": "Os arquivos de {name} estão em uso por uma sessão ativa, então o Windows não consegue substituí-los. Feche todas as sessões de {name} e tente novamente.", - "nativeJsonMustBeObject": "A configuração JSON nativa deve ser um objeto", - "nativeJsonInvalid": "Erro de formato na configuração JSON nativa: {message}", - "openCodeAuthMustBeObject": "OpenCode auth.json deve ser um objeto JSON", - "openCodeAuthInvalid": "Erro de formato no OpenCode auth.json: {message}", - "authMustBeObject": "auth.json deve ser um objeto JSON", - "authInvalid": "Erro de formato no auth.json: {message}", - "providerIdPattern": "O ID do provedor só aceita letras, números, sublinhado, ponto e hífen", - "providerExists": "O provedor {providerId} já existe", - "modelIdPattern": "O ID do modelo só aceita letras, números, sublinhado, ponto, dois-pontos e hífen", - "modelExists": "O modelo {modelId} já existe" - }, - "warnings": { - "nativeJsonRecoveredStructured": "A configuração JSON nativa é inválida; redefinida para configuração estruturada", - "nativeJsonRecoveredOpenCode": "A configuração JSON nativa é inválida; redefinida para configuração estruturada do OpenCode", - "openCodeAuthRecovered": "OpenCode auth.json é inválido; redefinido para configuração padrão", - "authRecoveredStructured": "auth.json é inválido; redefinido para configuração estruturada" - }, - "toasts": { - "agentActionCompleted": "{name} {action} concluído", - "agentActionFailed": "{name} {action} falhou", - "localVersion": "Versão local: {version}", - "installCompletedVersionLater": "Instalação concluída, a versão será atualizada na próxima verificação", - "uninstallCompleted": "Desinstalação de {name} concluída", - "uninstallFailed": "Desinstalação de {name} falhou", - "localVersionRemoved": "Versão local removida", - "saveAgentOrderFailed": "Falha ao salvar a ordem dos Agents", - "saveAgentSwitchFailed": "Falha ao salvar o switch dos Agents", - "saveEnvFailed": "Falha ao salvar variáveis de ambiente", - "grokSaved": "Configuração do Grok salva", - "saveGrokNativeFailed": "Falha ao salvar a configuração nativa do Grok", - "saveGrokApiKeyFailed": "Configurações salvas, mas não foi possível salvar a chave de API", - "cursorSaved": "Configuração do Cursor salva", - "saveCursorConfigFailed": "Falha ao salvar a configuração do Cursor", - "codexSaved": "Configuração do Codex salva", - "saveCodexNativeFailed": "Falha ao salvar configuração nativa do Codex", - "geminiSaved": "Configuração do Gemini salva", - "saveGeminiFailed": "Falha ao salvar configuração do Gemini", - "providerDeleted": "Provedor {providerId} excluído", - "providerDeleteFailed": "Falha ao excluir o provedor {providerId}", - "providerSaved": "Provedor {providerId} salvo", - "saveProviderFailed": "Falha ao salvar o provedor {providerId}", - "openCodeConfigSynced": "A configuração do OpenCode e o auth JSON foram sincronizados.", - "openCodeSaved": "Configuração do OpenCode salva", - "saveOpenCodeFailed": "Falha ao salvar configuração do OpenCode", - "openClawSaved": "Configuração do OpenClaw salva", - "saveOpenClawFailed": "Falha ao salvar configuração do OpenClaw", - "configSaved": "Configuração salva", - "configSavedHint": "Sessões existentes precisam ser reabertas para que as alterações tenham efeito", - "saveConfigManagementFailed": "Falha ao salvar o gerenciamento de configuração", - "clineSaved": "Configuração do Cline salva", - "saveClineFailed": "Falha ao salvar a configuração do Cline", - "hermesSaved": "Configuração do Hermes salva", - "saveHermesFailed": "Falha ao salvar a configuração do Hermes", - "codeBuddySaved": "Configuração do CodeBuddy salva", - "saveCodeBuddyFailed": "Falha ao salvar a configuração do CodeBuddy", - "kimiCodeSaved": "Configuração do Kimi Code salva", - "saveKimiCodeFailed": "Falha ao salvar a configuração do Kimi Code", - "deepseekSaved": "Configuração do DeepSeek salva", - "saveDeepSeekFailed": "Falha ao salvar a configuração do DeepSeek", - "modelProviderRequired": "Selecione um provedor de modelo antes de salvar.", - "affectedRunningSessions": "{count, plural, one {# sessão ativa precisa reconectar para aplicar a alteração} other {# sessões ativas precisam reconectar para aplicar a alteração}}", - "providerConnected": "{providerId} conectado", - "connectFailed": "Falha ao conectar {providerId}", - "providerDisconnected": "{providerId} desconectado", - "disconnectFailed": "Falha ao desconectar {providerId}", - "catalogRefreshed": "Catálogo atualizado — {count} provedores", - "catalogRefreshFailed": "Falha ao atualizar o catálogo", - "piSaved": "Configuração do Pi salva", - "savePiFailed": "Falha ao salvar a configuração do Pi", - "piRuntimeSaved": "Tempo de execução do Pi salvo", - "savePiRuntimeFailed": "Falha ao salvar o tempo de execução do Pi", - "piBinaryInstalled": "pi instalado", - "piBinaryInstallFailed": "Falha ao instalar o pi", - "piBinaryUninstalled": "pi desinstalado", - "piBinaryUninstallFailed": "Falha ao desinstalar o pi", - "savePiTrustFailed": "Falha ao salvar a confiança do espaço de trabalho" - }, - "version": { - "statusLabel": "Status da versão", - "notInstalled": "Não instalado", - "remoteLocal": "Remoto: {remoteVersion} · Local: {localVersion}", - "localOnly": "Local: {localVersion}", - "localInstalled": "{versionText}. Instalado.", - "platformUnsupported": "{versionText}. A plataforma atual não suporta este agente.", - "uvxNotReady": "{versionText}. O runtime do uv não está instalado — instale-o na verificação do uv abaixo para usar este agente.", - "clickInstall": "{versionText}. Clique em Instalar à direita.", - "localUnrecognized": "{versionText}. A versão local não é comparável; tente atualizar para sobrescrever a instalação.", - "upgradeAvailable": "{versionText}. Atualização disponível.", - "remoteUnavailable": "{versionText}. A versão remota está indisponível no momento.", - "latest": "{versionText}. Já está na versão mais recente." - }, - "adapter": { - "label": "Adaptador ACP", - "badge": "Adaptador ACP", - "badgeHint": "Para este agente o Codeg instala um pacote adaptador ACP, não a CLI do fornecedor. Os dois são independentes e compartilham a mesma configuração.", - "learnMore": "Saiba mais", - "missingWithNative": "Encontramos a sua {nativeLabel} em {nativePath}. O Codeg conversa com os agentes por ACP e essa CLI não fala ACP, então o Codeg precisa de um pacote adaptador separado, {adapterPackage}, mantido pelo projeto Agent Client Protocol (originalmente Zed). Ele traz o próprio runtime, nunca modifica nem substitui o seu comando {nativeCmd} e lê o mesmo {configDir} — seu login e suas configurações continuam valendo. Instale abaixo.", - "missing": "O Codeg conversa com os agentes por ACP e a {nativeLabel} não fala ACP, então o Codeg precisa de um pacote adaptador separado, {adapterPackage}, mantido pelo projeto Agent Client Protocol (originalmente Zed). Ele traz o próprio runtime, então a CLI {nativeCmd} não é pré-requisito; se você já a tem, as duas coexistem e compartilham o login e as configurações de {configDir}. Instale abaixo.", - "readyWithNative": "O adaptador {adapterCmd} está instalado — é ele que o Codeg inicia, não a sua {nativeCmd} em {nativePath}. São pacotes distintos que coexistem e ambos leem {configDir}, então login e configurações são compartilhados.", - "ready": "O adaptador {adapterCmd} está instalado — é ele que o Codeg inicia. Ele traz o próprio runtime, então a {nativeLabel} não é necessária; se instalá-la depois, as duas coexistem e compartilham {configDir}." - }, - "cline": { - "configDescription": "Configure o provedor de API e as credenciais do Cline. As configurações são salvas em ~/.cline/data/." - }, - "opencodePlugins": { - "title": "Plugins do OpenCode", - "declared": "Plugins declarados", - "noPlugins": "Nenhum plugin declarado em opencode.json", - "status": { - "installed": "Instalado", - "missing": "Não instalado" - }, - "installAll": "Instalar todos os ausentes", - "pinVersions": "Fixar versões @latest", - "install": "Instalar", - "uninstall": "Desinstalar", - "refresh": "Atualizar", - "success": "Todos os plugins foram instalados com sucesso", - "failed": "Operação do plugin falhou" - }, - "pi": { - "configManagement": "Configuração do Pi", - "configDescription": "O Pi autentica via a chave de API do seu provedor de modelos. A chave é gravada em ~/.pi/agent/auth.json e a seleção de modelo em settings.json.", - "providerLabel": "Provedor", - "modelLabel": "Modelo", - "thinkingLabel": "Raciocínio", - "thinking": { - "off": "Desligado", - "low": "Baixo", - "medium": "Médio", - "high": "Alto", - "minimal": "Mínimo", - "xhigh": "Muito alto" - }, - "apiKeyLabel": "Chave de API", - "apiKeyHint": "Gravada em ~/.pi/agent/auth.json para o provedor selecionado.", - "apiKeySetPlaceholder": "•••••• (salva — deixe em branco para manter)", - "saveConfig": "Salvar configuração do Pi", - "providerModelRequired": "Provedor e modelo são obrigatórios", - "runtimeTitle": "Tempo de execução", - "runtimeDescription": "Escolha qual binário do pi é executado. Use o padrão ou aponte para sua própria build do pi.", - "modeDefault": "pi padrão", - "modeDefaultHint": "Usa o adaptador pi-acp integrado com o pi no seu PATH. Instale o pi com: npm install -g @earendil-works/pi-coding-agent", - "modeCustom": "pi personalizado", - "modeCustomHint": "Execute sua própria build, instalação ou wrapper do pi.", - "commandLabel": "Comando ou caminho do pi", - "commandHint": "Um caminho absoluto, um nome de comando no PATH ou um script wrapper (ex.: ./pi-test.sh de um monorepo).", - "commandNotFound": "Comando não encontrado", - "validate": "Validar", - "advanced": "Avançado", - "configDirLabel": "Diretório de configuração (PI_CODING_AGENT_DIR)", - "sessionDirLabel": "Diretório de sessões (PI_CODING_AGENT_SESSION_DIR)", - "flagsHint": "O pi-acp não encaminha flags personalizados do pi (--approve, -e, …) — envolva o pi num script e aponte o comando para ele.", - "customIncomplete": "Digite um comando do pi para salvar", - "saveRuntime": "Salvar tempo de execução", - "providerPlaceholder": "Selecionar um provedor", - "customProvider": "Provedor personalizado…", - "providerIdLabel": "ID do provedor", - "apiProtocolLabel": "Protocolo da API", - "baseUrlLabel": "Endpoint da API (Base URL)", - "customProviderHint": "Define um provedor em ~/.pi/agent/models.json para o seu endpoint. A maioria dos servidores auto-hospedados ou proxy usa openai-completions.", - "baseUrlRequired": "O endpoint da API (Base URL) é obrigatório", - "binaryTitle": "binário pi (pi-coding-agent)", - "binaryDescription": "O pi-acp executa este binário pi. Instale-o aqui ou aponte o pi-acp para sua própria build abaixo.", - "binaryInstalled": "Instalado", - "binaryMissing": "Não instalado", - "binaryChecking": "Verificando…", - "installBinary": "Instalar pi", - "installing": "Instalando…", - "recheck": "Verificar novamente", - "configDirSkillsNote": "Com um diretório de configuração personalizado, as habilidades, os especialistas e as ferramentas de escritório gerenciados nas Configurações não se aplicam a este pi — gerencie as habilidades dele diretamente nessa pasta.", - "projectTrustTitle": "Confiança do projeto", - "projectTrustDescription": "Pastas das quais você permitiu que o pi carregue arquivos do projeto. Uma pasta confiável permite que as .pi/extensions daquele repositório executem código ao iniciar o pi, vale para todas as pastas dentro dela e também é usada quando você executa o pi no terminal.", - "projectTrustLoading": "Carregando…", - "projectTrustEmpty": "Nenhuma pasta decidida ainda.", - "projectTrustTrusted": "Confiável", - "projectTrustDenied": "Não confiável", - "projectTrustRevoke": "Revogar", - "reasoningTitle": "Raciocínio", - "reasoningEnableLabel": "Ativar", - "reasoningDescription": "O pi só envia um esforço de raciocínio para um modelo que o declara — num modelo sem declaração, todos os níveis são reduzidos para Off, por isso o seletor do compositor volta atrás assim que se mexe nele. Escrito na entrada deste modelo em models.json.", - "levelsLabel": "Níveis disponíveis", - "levelsHint": "Passam a ser as linhas do seletor de raciocínio do compositor. Escolha os que o seu endpoint aceita; o pi recusa qualquer nível que não esteja aqui.", - "levelsEmptyError": "Escolha pelo menos um nível — sem nenhum, o pi volta para Off.", - "wireValuesTitle": "Avançado: valores enviados ao fornecedor", - "wireValuesHint": "Deixe em branco para enviar o nome do nível tal como está. Defina quando o seu endpoint esperar outra coisa — backends ao estilo Google querem LOW / HIGH.", - "defaultLevelUnlisted": "Este nível não está na lista acima — o pi iria reduzi-lo." - }, - "addCustomAgent": "Adicionar agente personalizado", - "addCustomAgentHint": "Registre qualquer agente compatível com ACP. Escolha um no registro público do ACP ou cole as informações de registro dele.", - "customAgentFromRegistry": "Registro ACP", - "customAgentManual": "Manual", - "customAgentSearchPlaceholder": "Buscar agentes…", - "customAgentLoadingCatalog": "Carregando o registro ACP…", - "customAgentRetry": "Tentar novamente", - "customAgentNoResults": "Nenhum agente correspondente", - "customAgentAdd": "Adicionar", - "customAgentAlreadyAdded": "Adicionado", - "customAgentUnsupportedPlatform": "Nenhuma compilação disponível para esta plataforma", - "customAgentAdded": "{name} adicionado", - "customAgentIdLabel": "ID do registro", - "customAgentNameLabel": "Nome exibido", - "customAgentVersionLabel": "Versão", - "customAgentSpecLabel": "Distribuição (JSON)", - "customAgentSpecHint": "Mesma forma do objeto distribution do registro ACP: canais npx, uvx e binary, ou cole uma entrada completa do registro. Em npx/uvx, cmd é o executável que o pacote instala — derivado do nome do pacote quando omitido, então defina-o quando forem diferentes. binary é organizado por chave de plataforma (esta máquina: {platform}); cmd é o caminho de execução dentro do arquivo e sha256 verifica opcionalmente o download.", - "customAgentTemplateLabel": "Modelos", - "customAgentKindLabel": "Iniciar via", - "customAgentInvalidJson": "JSON inválido", - "customAgentNoDistribution": "Nenhuma distribuição npx, uvx ou binary encontrada", - "customAgentCancel": "Cancelar", - "customAgentSave": "Adicionar agente", - "customAgentSaveChanges": "Salvar alterações", - "customAgentEdit": "Editar agente", - "customAgentEditHint": "Atualize o nome, o ícone, a distribuição e as declarações de skills. O ID do agente não pode ser alterado.", - "customAgentEditNotFound": "Agente personalizado {id} não encontrado", - "customAgentSaved": "{name} salvo", - "customAgentVersionProbeLabel": "Comando de consulta de versão (opcional)", - "customAgentVersionProbeHint": "Comando que imprime a versão instalada localmente. Se ficar vazio, o codeg executa o comando do agente com --version.", - "customAgentRemove": "Remover agente", - "customAgentRemoveHint": "Exclui a definição do agente. As conversas existentes mantêm o histórico; o agente apenas não pode mais ser iniciado.", - "customAgentIconLabel": "Ícone (opcional)", - "customAgentIconUpload": "Enviar", - "customAgentIconReplace": "Substituir", - "customAgentIconClear": "Remover ícone", - "customAgentIconHint": "Salvo junto com o agente, portanto funciona offline. Sem um ícone, usa-se uma inicial colorida.", - "customAgentSkillsLabel": "Skills (.agents/skills compartilhado)", - "customAgentSkillsHint": "Declara que este agente lê o repositório compartilhado .agents/skills (diretórios global e de projeto) e o adiciona a todas as matrizes de habilidades. Habilidades vinculadas lá ficam visíveis para todos os agentes que leem esse repositório compartilhado.", - "customAgentSkillsDirLabel": "Diretório de skills dedicado", - "customAgentSkillsDirHint": "Caminho absoluto do diretório de onde este agente carrega skills — o seu próprio repositório, além do compartilhado ou no lugar dele. ~ expande para o diretório pessoal; skills vinculadas são colocadas aqui primeiro.", - "customAgentMcpLabel": "Suporte a MCP", - "customAgentMcpHint": "Envia o companheiro MCP integrado do codeg para este agente ao iniciar a sessão — o canal por trás da delegação, do feedback ao vivo e das ferramentas de tarefas. Desative para um agente que rejeita servidores MCP e não consegue conectar; a mudança vale a partir da próxima conexão.", - "customAgentIconNotAnImage": "Selecione um arquivo de imagem.", - "customAgentIconTooLarge": "O ícone deve ter menos de {limit} KB.", - "customAgentIconReadFailed": "Não foi possível ler essa imagem.", - "customAgentRemoveConfirm": "Remover {name}? As conversas existentes permanecem, mas o agente não poderá mais ser iniciado.", - "customAgentRemoveWithData": "Excluir também o histórico de conversas registrado", - "customAgentRemoved": "{name} removido", - "customAgentBadge": "Personalizado", - "customAgentNotLaunchable": "Este agente não pode ser iniciado aqui: {reason}" - }, - "SettingsPages": { - "agentsLoading": "Carregando configurações de agentes...", - "skillPacksLoading": "Carregando pacotes de habilidades…" - }, - "GeneralSettings": { - "loading": "Carregando...", - "sectionTitle": "Geral", - "sectionDescription": "Preferências centralizadas para o terminal padrão, aceleração de renderização e delegação multi-agente.", - "terminalTitle": "Terminal padrão", - "terminalDescription": "Escolha o shell usado ao abrir novas abas de terminal pela barra de terminal ou pela árvore de arquivos. Os agentes também o usam quando pedem ao codeg para executar uma linha de comando inteira.", - "terminalSystemDefault": "Padrão do sistema", - "terminalPowerShell7": "PowerShell 7 (pwsh)", - "terminalWindowsPowerShell": "Windows PowerShell", - "terminalCmd": "Prompt de Comando (cmd)", - "terminalSaveFailed": "Falha ao salvar as configurações do terminal: {message}", - "terminalShellCustom": "Caminho personalizado", - "terminalShellCustomPath": "Caminho do shell", - "terminalShellCustomPlaceholder": "/usr/local/bin/fish", - "terminalShellCustomSave": "Salvar", - "terminalShellCustomHint": "Informe um caminho absoluto ou um nome resolvível pelo PATH.", - "terminalShellNotInstalled": "não instalado", - "terminalShellNotFoundWarning": "Este caminho não existe neste host.", - "terminalCurrentShell": "Em uso: {path}", - "renderingDescription": "Desative a aceleração de hardware se o aplicativo apresentar tela preta ou falhas de renderização (comum em certas GPUs AMD ou GPUs Intel integradas). Aplica-se apenas à versão desktop do Windows.", - "disableHardwareAcceleration": "Desativar aceleração de hardware", - "renderingSaveFailed": "Falha ao salvar as configurações de renderização: {message}", - "restartRequired": "Salvo. Reinicie o aplicativo para aplicar a alteração.", - "restartNow": "Reiniciar agora", - "restartFailed": "Falha ao reiniciar: {message}", - "loadFailed": "Falha ao carregar: {message}" - }, - "LoginPage": { - "documentTitle": "Entrar - codeg", - "brand": "Codeg", - "subtitle": "Digite seu token de acesso para conectar ao aplicativo de desktop", - "tokenPlaceholder": "Token de acesso", - "connect": "Conectar", - "connecting": "Conectando...", - "helpText": "Encontre seu token no app de desktop em Configurações → Serviço Web", - "invalidToken": "Token inválido. Verifique e tente novamente.", - "connectionFailed": "Falha na conexão (HTTP {status})", - "networkError": "Não foi possível conectar ao servidor" - }, - "CommitPage": { - "title": "Confirmar", - "invalidFolderId": "ID de pasta inválido", - "loadingRepo": "Carregando repositório..." - }, - "MergePage": { - "title": "Resolver conflitos", - "invalidFolderId": "ID de pasta inválido", - "loadingRepo": "Carregando repositório...", - "localVersion": "Local (Nosso)", - "result": "Resultado", - "remoteVersion": "Remoto (Deles)", - "acceptLocal": "Aceitar local", - "acceptRemote": "Aceitar remoto", - "markResolved": "Marcar como resolvido", - "abortMerge": "Abortar", - "completeMerge": "Concluir merge", - "unresolvedConflicts": "Ainda há marcadores de conflito não resolvidos neste arquivo", - "fileResolved": "Arquivo resolvido com sucesso", - "allResolved": "Todos os conflitos resolvidos", - "conflictFiles": "Arquivos em conflito", - "loadingFile": "Carregando arquivo...", - "preparingMerge": "Preparando mesclagem...", - "selectFile": "Selecione um arquivo para resolver", - "noConflicts": "Nenhum arquivo em conflito", - "skipFile": "Pular", - "abortSuccess": "Operação abortada", - "applyAllNonConflicting": "Aplicar todas as alterações sem conflito", - "applyLeftNonConflicting": "Aplicar local", - "applyRightNonConflicting": "Aplicar remoto" - }, - "ImportSessions": { - "title": "Importar sessões locais", - "scanningTitle": "Verificando sessões locais dos agentes…", - "scanningHint": "Percorrendo o armazenamento local de sessões de cada agente. Históricos grandes podem levar um momento. As sessões já importadas são atualizadas no processo.", - "scanFailed": "Falha na verificação", - "retry": "Tentar novamente", - "rescan": "Verificar novamente", - "empty": "Nenhuma sessão local encontrada", - "emptyHint": "Nenhum armazenamento de sessões de agentes foi encontrado nesta máquina.", - "noMatches": "Nenhuma sessão corresponde aos filtros atuais", - "searchPlaceholder": "Pesquisar título ou caminho…", - "allAgents": "Todos os agentes", - "onlyImportable": "Somente importáveis", - "selectAll": "Selecionar tudo", - "clearSelection": "Limpar", - "expandAll": "Expandir tudo", - "collapseAll": "Recolher tudo", - "summaryCounts": "{total} sessões · {importable} importáveis · {folders} pastas", - "noFolderSkipped": "{count} sem pasta de projeto ignoradas", - "folderNew": "Nova", - "folderCounts": "{importable}/{total} importáveis", - "toggleFolderAria": "Selecionar todas as sessões importáveis de {name}", - "toggleSessionAria": "Selecionar a sessão {title}", - "statusImported": "Importada", - "statusDeleted": "Excluída", - "untitled": "Sessão sem título", - "messageCount": "{count} mensagens", - "selectedCount": "{count} selecionadas", - "importSelected": "Importar seleção", - "importing": "Importando…", - "close": "Fechar", - "doneTitle": "Importação concluída", - "doneImported": "Importadas", - "doneUpdated": "Atualizadas", - "doneSkipped": "Ignoradas", - "doneCreatedFolders": "Pastas criadas", - "doneNotFound": "Não encontradas", - "doneFailed": "Falharam", - "continueImport": "Continuar importando", - "toasts": { - "importFailed": "Falha ao importar: {message}" - } - }, - "Folder": { - "workspaceStatus": { - "degradedTitle": "Atualizações em tempo real indisponíveis", - "degradedHint": "O observador falhou ao iniciar (por exemplo, permissão negada). Atualize manualmente para ver as mudanças.", - "retry": "Tentar novamente", - "retrying": "Tentando novamente..." - }, - "common": { - "all": "Todos", - "cancel": "Cancelar", - "close": "Fechar", - "closeOthers": "Fechar outros", - "closeAll": "Fechar tudo", - "confirm": "Confirmar", - "save": "Salvar", - "delete": "Excluir", - "rename": "Renomear", - "loading": "Carregando...", - "refresh": "Atualizar", - "refreshing": "Atualizando...", - "create": "Criar", - "createAndSwitch": "Criar e alternar", - "openFile": "Abrir arquivo", - "viewDiff": "Ver Diff", - "push": "Enviar..." - }, - "statusLabels": { - "in_progress": "Em andamento", - "pending_review": "Revisão", - "completed": "Concluído", - "cancelled": "Cancelado" - }, - "sidebar": { - "title": "Conversas", - "locateActiveConversation": "Localizar conversa ativa", - "expandAllGroups": "Expandir todos os grupos", - "collapseAllGroups": "Recolher todos os grupos", - "newConversation": "Nova conversa", - "newConversationShort": "Nova", - "newChat": "Nova conversa", - "search": "Buscar", - "noConversationsFound": "Nenhuma conversa encontrada.", - "importLocalSessions": "Importar sessões locais", - "importing": "Importando...", - "error": "Erro: {message}", - "completeAllSessions": "Concluir todas as sessões", - "completeAllReviewTitle": "Concluir todas as sessões em revisão?", - "completeAllReviewDescription": "Isso marcará como concluídas todas as {count, plural, one {# sessão} other {# sessões}} em Revisão.", - "completing": "Concluindo...", - "toasts": { - "importedSessions": "Importadas {imported, plural, one {# sessão} other {# sessões}}, ignoradas {skipped}", - "importedAndUpdated": "Importadas {imported, plural, one {# sessão} other {# sessões}}, atualizados {updated, plural, one {# título} other {# títulos}}, ignoradas {skipped}", - "updatedTitles": "Atualizados {updated, plural, one {# título} other {# títulos}}, ignoradas {skipped}", - "noNewSessionsFound": "Nenhuma nova sessão encontrada (ignoradas {skipped})", - "importFailed": "Falha na importação: {message}", - "reviewCompleted": "Marcadas {count, plural, one {# sessão em revisão} other {# sessões em revisão}} como concluídas", - "completeReviewFailed": "Falha ao concluir sessões em revisão: {message}", - "folderOpened": "Pasta {name} aberta", - "folderRemoved": "Pasta {name} removida", - "openFolderFailed": "Falha ao abrir pasta", - "removeFolderFailed": "Falha ao remover pasta: {message}", - "reorderFoldersFailed": "Falha ao reordenar pastas: {message}", - "changeFolderColorFailed": "Falha ao alterar a cor: {message}", - "setFolderAliasFailed": "Falha ao definir o alias: {message}", - "changeFolderDefaultAgentFailed": "Falha ao definir agente padrão: {message}" - }, - "statsLabel": "{folders} pastas · {convos} conversas", - "reorderHandle": "Arraste para reordenar", - "openFolder": "Abrir pasta", - "searchPlaceholder": "Buscar conversas...", - "viewOptions": "Opções de exibição", - "showCompleted": "Mostrar conversas concluídas", - "showWorktrees": "Mostrar pastas de worktree", - "showRecent": "Mostrar grupo Recentes", - "moreOptions": "Mais opções", - "sortBy": "Ordenar por", - "sortByCreatedAt": "Data de criação", - "sortByUpdatedAt": "Data de atualização", - "sectionOrder": "Ordem das seções", - "sectionOrderMoveUp": "Mover para cima", - "sectionOrderMoveDown": "Mover para baixo", - "sectionOrderItemLabel": "{name} — posição {position} de {total}", - "statusRunningBadge": "Executando", - "runningCountBadge": "{count, plural, one {# sessão em execução} other {# sessões em execução}}", - "statusCancelledBadge": "Cancelado", - "worktreeRemovedBadge": "Worktree de origem removida", - "conversationCountUnit": "{count, plural, one {# conversa} other {# conversas}}", - "emptyFolderHint": "Sem conversas", - "noMatchingConversations": "Nenhuma conversa correspondente", - "noUnfinishedConversations": "Nenhuma conversa pendente. Ative \"Mostrar concluídas\" no menu superior direito.", - "removeFolderConfirmTitle": "Remover pasta do espaço de trabalho?", - "removeFolderConfirmDescription": "Remover \"{name}\" do espaço de trabalho? As abas e terminais relacionados serão fechados.", - "folderHeaderMenu": { - "manageConversations": "Gerenciar conversas…", - "manageLinks": "Pastas vinculadas", - "changeColor": "Alterar cor", - "useThemeColor": "Usar tema do app", - "setDefaultAgent": "Definir agente padrão", - "defaultAgentNone": "Sem padrão (usar global)", - "agentUnavailableSuffix": "(indisponível)", - "loadingAgents": "Carregando agentes…", - "setAlias": "Definir alias…", - "setAliasTitle": "Definir alias da pasta", - "setAliasPlaceholder": "Insira um alias (deixe vazio para limpar)", - "setAliasSave": "Salvar", - "setAliasCancel": "Cancelar", - "removeFromWorkspace": "Remover do espaço de trabalho" - }, - "manageConversations": { - "title": "Gerenciar conversas", - "searchPlaceholder": "Pesquisar por título…", - "agentFilterAll": "Todos os agentes", - "statusFilterAll": "Todos os status", - "folderFilterAll": "Todas as pastas", - "branchFilterAll": "Todas as branches", - "branchNone": "Sem branch", - "branchSearchPlaceholder": "Pesquisar branches…", - "noMatchingBranches": "Nenhuma branch correspondente", - "selectAllVisible": "Selecionar tudo", - "deselectAll": "Desmarcar tudo", - "selectedCount": "{count} selecionada(s)", - "matchedCount": "{count} correspondência(s)", - "untitledConversation": "Conversa sem título", - "setStatus": "Definir status…", - "deleteSelected": "Excluir", - "noConversations": "Sem conversas nesta pasta.", - "noConversationsWorkspace": "Sem conversas na área de trabalho.", - "noMatchingConversations": "Nenhuma conversa corresponde aos filtros.", - "confirmDeleteTitle": "Excluir {count} conversa(s)?", - "confirmDeleteDescription": "Esta ação não pode ser desfeita.", - "toastDeleted": "{count} conversa(s) excluída(s)", - "toastStatusUpdated": "Status atualizado para {count} conversa(s)", - "toastOpFailed": "Falha na operação: {message}" - }, - "sectionPinned": "Fixadas", - "sectionFolders": "Pastas", - "sectionChats": "Chat", - "sectionRecent": "Recentes", - "noChats": "Sem chats", - "noRecent": "Sem conversas recentes", - "showMoreRecent": "Mostrar mais ({count})", - "noFolders": "Nenhuma pasta aberta", - "newChatAction": "Novo chat", - "automations": "Automações", - "tasks": "Tarefas a fazer", - "loadingSubsessions": "Carregando subconversas…" - }, - "conversation": { - "reloadFailed": "Falha ao recarregar conversa: {message}", - "reloaded": "Conversa recarregada", - "reload": "Recarregar", - "activeConversationIndicator": "Conversa ativa", - "newConversation": "Nova conversa", - "closeConversation": "Fechar conversa", - "copyText": "Copiar texto", - "copyTextSuccess": "Copiado", - "copyTextFailed": "Falha ao copiar", - "forkSession": "Bifurcar sessão", - "forkSessionSuccess": "Sessão bifurcada com sucesso", - "forkSessionFailed": "Falha ao bifurcar a sessão: {error}", - "exportConversation": "Exportar conversa", - "exportImage": "Imagem", - "exportMarkdown": "Markdown", - "exportHtml": "HTML", - "exportSuccess": "Conversa exportada", - "exportFailed": "Falha ao exportar", - "exportImageTooLong": "A conversa é muito longa para exportar como imagem", - "exportLabels": { - "untitledConversation": "Conversa sem título", - "agent": "Agente", - "model": "Modelo", - "status": "Estado", - "started": "Início", - "updated": "Atualizado", - "tokens": "Estatísticas de tokens", - "duration": "Duração", - "inputTokens": "Entrada", - "outputTokens": "Saída", - "cacheRead": "Cache lido", - "cacheWrite": "Cache escrito", - "user": "Utilizador", - "assistant": "Assistente", - "system": "Sistema", - "toolResult": "Resultado", - "toolError": "Erro" - }, - "moreActions": "Mais ações" - }, - "sessionDetails": { - "menuLabel": "Detalhes da sessão", - "noActiveSession": "Nenhuma sessão ativa", - "title": "Detalhes da sessão", - "subtitle": "Metadados da sessão e uso de tokens", - "fieldTitle": "Título", - "untitled": "Conversa sem título", - "sessionId": "ID da sessão", - "externalId": "ID da extensão", - "agent": "Agente", - "model": "Modelo", - "status": "Estado", - "gitBranch": "Branch do Git", - "parentId": "Sessão principal", - "tokensHeading": "Uso de tokens", - "totalTokens": "Total", - "inputTokens": "Entrada", - "outputTokens": "Saída", - "cacheWrite": "Cache escrito", - "cacheRead": "Cache lido", - "contextWindow": "Janela de contexto", - "duration": "Duração", - "loadingStats": "Carregando uso de tokens…", - "loadFailed": "Falha ao carregar o uso de tokens", - "noStats": "Nenhum uso registrado", - "timestampsHeading": "Carimbos de data/hora", - "createdAt": "Criado", - "updatedAt": "Atualizado", - "none": "—", - "copyField": "Copiar {field}", - "copiedField": "{field} copiado" - }, - "conversationCard": { - "untitledConversation": "Conversa sem título", - "newConversation": "Nova conversa", - "rename": "Renomear", - "status": "Status", - "delete": "Excluir", - "importLocalSessions": "Importar sessões locais", - "importing": "Importando...", - "renameConversation": "Renomear conversa", - "deleteConversationTitle": "Excluir conversa?", - "deleteConversationDescription": "Isso excluirá \"{title}\". Esta ação não pode ser desfeita.", - "cancel": "Cancelar", - "save": "Salvar", - "pin": "Fixar", - "unpin": "Desafixar", - "markCompleted": "Marcar como concluída", - "reopen": "Reabrir", - "expandSubsessions": "Expandir subconversas", - "collapseSubsessions": "Recolher subconversas" - }, - "search": { - "dialogTitle": "Buscar", - "dialogTitleWithFolder": "Buscar — {name}", - "tabConversations": "Conversas", - "tabFiles": "Arquivos", - "placeholder": "Buscar conversas...", - "filePlaceholder": "Buscar arquivos ou diretórios...", - "allAgents": "Todos", - "searching": "Buscando...", - "typeToSearch": "Digite para buscar conversas", - "typeToSearchFiles": "Digite para buscar arquivos ou diretórios", - "noResults": "Nenhum resultado encontrado.", - "untitledConversation": "Conversa sem título" - }, - "folderTitleBar": { - "showSidebar": "Mostrar barra lateral", - "hideSidebar": "Ocultar barra lateral", - "toggleTerminal": "Alternar terminal", - "toggleAuxPanel": "Alternar painel auxiliar", - "search": "Buscar", - "openSettings": "Abrir configurações", - "backToConversations": "Voltar às conversas", - "withShortcut": "{label} (atalho: {shortcut})" - }, - "statusBar": { - "connection": { - "connected": "Conectado", - "connecting": "Conectando...", - "prompting": "Respondendo...", - "error": "Erro de conexão", - "disconnected": "Desconectado", - "tooltip": "{agent}: {status}", - "tooltipError": "{agent}: {error}", - "title": "Conexão do agente", - "triggerAria": "Conexão do agente: {status}", - "workingDir": "Diretório de trabalho", - "sessionId": "ID da sessão", - "viewerNote": "Anexado a uma sessão de outro cliente — reconectar apenas reanexa esta visualização.", - "reconnectInterrupts": "Reconectar reinicia o agente e interrompe o trabalho em andamento.", - "reconnect": "Reconectar", - "reconnecting": "Reconectando...", - "reconnectUnavailable": "Ainda não há sessão para reconectar." - }, - "tasks": { - "title": "Tarefas" - }, - "alerts": { - "title": "Alertas", - "empty": "Sem alertas", - "details": "Detalhes" - }, - "stats": { - "conversations": "{count} conversas", - "openUsage": "Ver estatísticas de sessões e uso de tokens" - }, - "tokens": { - "contextWindowUsageAria": "Uso da janela de contexto", - "contextWindow": "Janela de contexto", - "usedMax": "Usado / Máx", - "tokenUsage": "Uso de tokens", - "input": "Entrada", - "output": "Saída", - "cacheRead": "Leitura de cache", - "cacheWrite": "Gravação de cache", - "total": "Total de tokens" - } - }, - "auxPanel": { - "tabs": { - "files": "Arquivos", - "changes": "Alterações", - "commits": "Confirmações" - }, - "noFolderTitle": "Nenhuma pasta aberta", - "noFolderHint": "Abra uma pasta para ver seu conteúdo aqui" - }, - "windowControls": { - "minimizeWindow": "Minimizar janela", - "minimize": "Minimizar", - "maximizeWindow": "Maximizar janela", - "maximize": "Maximizar", - "restoreWindow": "Restaurar janela", - "restore": "Restaurar", - "closeWindow": "Fechar janela", - "close": "Fechar" - }, - "tabs": { - "closeConversationTab": "Fechar aba de conversa", - "close": "Fechar", - "closeOthers": "Fechar outros", - "splitRight": "Dividir à direita", - "splitDown": "Dividir abaixo", - "splitAndMoveRight": "Dividir e mover para a direita", - "splitAndMoveDown": "Dividir e mover para baixo", - "moveToOppositeGroup": "Mover para o grupo oposto", - "moveToGroup": "Mover para o grupo", - "groupLabel": "Grupo {index}", - "changeSplitterOrientation": "Alternar orientação do divisor", - "unsplit": "Desfazer divisão", - "unsplitAll": "Desfazer todas as divisões", - "closeAll": "Fechar tudo", - "tileDisplay": "Exibição em mosaico", - "untileDisplay": "Sair do mosaico" - }, - "fileWorkspace": { - "files": "Arquivos", - "closeFileTab": "Fechar aba de arquivo", - "close": "Fechar", - "closeOthers": "Fechar outros", - "closeAll": "Fechar tudo", - "preview": "Visualizar", - "editSource": "Editar fonte", - "maximize": "Maximizar", - "restore": "Restaurar", - "emptyDirectory": "Pasta vazia" - }, - "terminal": { - "rename": "Renomear", - "close": "Fechar", - "closeOthers": "Fechar outros", - "closeAll": "Fechar tudo", - "hideTerminal": "Ocultar terminal ({shortcut})", - "openFolderFirst": "Abra primeiro uma pasta" - }, - "workspaceDialog": { - "title": "Abrir pasta", - "manageTitle": "Pastas vinculadas", - "addTargetsTitle": "Adicionar pastas para vincular", - "pickRootDescription": "Escolha a pasta principal deste espaço de trabalho.", - "linksDescription": "Vincule outras pastas como subdiretórios para que os agentes trabalhem em todas elas a partir de um único espaço de trabalho.", - "addTargetsDescription": "Selecione uma ou mais pastas. Cada uma vira um subdiretório do espaço de trabalho.", - "useSystemPicker": "Seletor do sistema", - "next": "Avançar", - "back": "Voltar", - "done": "Concluir", - "change": "Alterar", - "addFolders": "Adicionar pastas", - "addSelected": "Adicionar", - "addSelectedCount": "Adicionar {count}", - "createCount": "Vincular {count} pasta(s)", - "discardPending": "Descartar", - "noLinks": "Ainda não há pastas vinculadas.", - "gitExclude": "Manter os vínculos fora do status do git", - "rename": "Renomear", - "unlink": "Remover vínculo", - "repair": "Recriar vínculo", - "saveName": "Salvar", - "cancelRename": "Cancelar", - "removePending": "Remover", - "willAppearAs": "Aparece como {name} no espaço de trabalho", - "renamedForDuplicate": "Renomeada — {base} já é usada por outro vínculo", - "renamedForExistingEntry": "Renomeada — {base} já existe nesta pasta", - "partiallyCreated": "Apenas {count} pasta(s) puderam ser vinculadas", - "openFailed": "Falha ao abrir a pasta", - "previewFailed": "Falha ao verificar as pastas selecionadas", - "createFailed": "Falha ao vincular as pastas", - "renameFailed": "Falha ao renomear o vínculo", - "removeFailed": "Falha ao remover o vínculo", - "repairFailed": "Falha ao recriar o vínculo", - "status": { - "ok": "Vinculada", - "missing": "O vínculo sumiu desta pasta", - "conflicted": "Outra entrada usa esse nome agora", - "broken": "A pasta vinculada não existe mais" - }, - "nameIssue": { - "empty": "Digite um nome", - "illegalChars": "Não pode conter / \\ : * ? \" < > |", - "tooLong": "Nome muito longo", - "reserved": "Este nome é reservado pelo Windows", - "duplicate": "Este nome já está em uso" - }, - "rejection": { - "not_found": "Pasta não encontrada", - "not_a_directory": "Este caminho não é uma pasta", - "same_as_root": "É a própria pasta do espaço de trabalho", - "ancestor_of_root": "Esta pasta contém o espaço de trabalho", - "inside_root": "Já está dentro do espaço de trabalho", - "already_linked": "Já vinculada", - "name_unavailable": "Não há mais nomes livres para esta pasta", - "alreadyLinkedAs": "Já vinculada como {name}" - } - }, - "folderNameDropdown": { - "fallbackFolderName": "Pasta", - "openFolder": "Abrir pasta", - "cloneRepository": "Clonar repositório", - "projectBoot": "Inicializador de projeto", - "opened": "Aberto", - "recentOpen": "Abertos recentemente" - }, - "fileWorkspacePanel": { - "addSelectionToChat": "Adicionar seleção ao chat", - "addToChat": "Adicionar ao chat", - "addSelectionToChatDone": "{label} adicionado à conversa", - "addFileToChat": "Adicionar arquivo ao chat", - "toggleWordWrap": "Alternar quebra de linha", - "addFileToChatDone": "{label} adicionado à conversa", - "viewDiff": "Ver Diff", - "openFile": "Abrir arquivo", - "fileCount": "{count, plural, one {# arquivo} other {# arquivos}}", - "openFileOrDiff": "Abra um arquivo ou diff pelo painel direito", - "disk": "Disco", - "head": "HEAD", - "unsaved": "Não salvo", - "workingTree": "Árvore de trabalho", - "loading": "Carregando...", - "compareWithBranch": "{path} · comparar com {branch}", - "hunkCount": "{count, plural, one {# bloco} other {# blocos}}", - "prev": "Anterior", - "next": "Próximo", - "jumpToLine": "Ir para a linha {line}", - "noParsedDiffSections": "Sem seções de diff analisadas", - "loadingEditor": "Carregando editor...", - "imageZoomIn": "Ampliar", - "imageZoomOut": "Reduzir", - "imageZoomReset": "Redefinir zoom", - "htmlPreviewTitle": "Visualização HTML", - "htmlPreviewTrust": "Ativar scripts", - "htmlPreviewTrustHint": "Executa os scripts deste arquivo e permite acesso à rede. Ative apenas para arquivos confiáveis.", - "officePreviewTitle": "Pré-visualização de documento do Office", - "officeFullRender": "Renderização completa", - "officeFullRenderHint": "Renderiza animações Morph, 3D e fórmulas (executa os scripts do próprio slide)", - "officeNotInstalled": "OfficeCLI não está instalado", - "officeNotInstalledHint": "Instale o OfficeCLI em Configurações → Ferramentas do Office para pré-visualizar arquivos do Word, Excel e PowerPoint.", - "officeOpenSettings": "Abrir configurações", - "officeWatchFailed": "Não foi possível iniciar a visualização ao vivo", - "officeWatchRetry": "Tentar novamente", - "officeServerInstallHint": "O OfficeCLI precisa estar instalado no host do servidor. Execute este comando lá e tente novamente:", - "officeRemoteDesktopUnsupported": "A pré-visualização ao vivo não está disponível em uma janela de área de trabalho remota. Abra este espaço de trabalho na interface web do servidor para visualizar arquivos do Office." - }, - "branchDropdown": { - "toasts": { - "commitCodeCompleted": "Commit de código concluído", - "pushCodeCompleted": "Push de código concluído", - "committedFiles": "{count, plural, one {# arquivo commitado} other {# arquivos commitados}}", - "taskCompleted": "{label} concluído", - "taskFailed": "{label} falhou", - "mergeNoNewCommits": "{branchName} não tem novos commits", - "mergedCommits": "{count, plural, one {# commit mesclado} other {# commits mesclados}}", - "allFilesUpToDate": "Todos os arquivos estão atualizados", - "updatedFiles": "{count, plural, one {# arquivo atualizado} other {# arquivos atualizados}}", - "openCommitWindowFailed": "Falha ao abrir a janela de commit", - "openPushWindowFailed": "Falha ao abrir janela de envio", - "upstreamSet": "A branch upstream foi definida", - "upstreamSetAndPushed": "Branch upstream definida e {count, plural, one {# commit} other {# commits}} enviado(s)", - "noCommitsToPush": "Não há commits para enviar", - "pushedCommits": "{count, plural, one {# commit enviado} other {# commits enviados}}", - "switchedToFolder": "Alternado para {name}", - "switchFailed": "Falha ao trocar de branch", - "openStashWindowFailed": "Falha ao abrir a janela de stash" - }, - "tasks": { - "newBranch": "Criar branch {name}", - "newWorktree": "Criar worktree {name}", - "checkoutTo": "Fazer checkout para {branchName}", - "mergeBranch": "Mesclar {branchName}", - "rebaseTo": "Rebase para {branchName}", - "deleteRemoteBranch": "Excluir branch remoto {branchName}", - "initGitRepo": "Inicializar repositório Git", - "pullCode": "Fazer pull do código", - "fetchInfo": "Buscar informações", - "pushCode": "Enviar código", - "stashChanges": "Fazer stash das alterações", - "stashPop": "Aplicar stash", - "deleteBranch": "Excluir branch {branchName}", - "removeWorktree": "Excluir o worktree de {branchName}", - "removeWorktreeAndBranch": "Excluir o worktree e o branch {branchName}", - "updateBranch": "Atualizar o branch {branchName}" - }, - "confirm": { - "mergeTitle": "Mesclar branch", - "rebaseTitle": "Rebase da branch", - "mergeDescription": "Mesclar {branchName} na branch atual {currentBranch}?", - "rebaseDescription": "Fazer rebase da branch atual {currentBranch} sobre {branchName}?", - "deleteRemoteTitle": "Excluir branch remoto", - "deleteRemoteDescription": "Excluir o branch remoto {branchName}? Isso o removerá do repositório remoto e não poderá ser desfeito.", - "deleteTitle": "Excluir branch", - "deleteDescription": "Excluir a branch {branchName}? Esta ação não pode ser desfeita.", - "forceDeleteTitle": "Forçar exclusão do branch", - "forceDeleteDescription": "O branch {branchName} não está totalmente mesclado. Tem certeza de que deseja forçar a exclusão? Esta ação não pode ser desfeita.", - "deleteWorktreeTitle": "Excluir worktree", - "deleteWorktreeDescription": "Excluir o diretório do worktree onde {branchName} está em uso? O branch e seus commits são mantidos.", - "forceDeleteWorktreeTitle": "Forçar a exclusão do worktree", - "forceDeleteWorktreeDescription": "O worktree de {branchName} tem arquivos não commitados ou não rastreados. Excluir mesmo assim? Essas alterações não poderão ser recuperadas.", - "deleteWorktreeAndBranchTitle": "Excluir worktree e branch", - "deleteWorktreeAndBranchDescription": "Excluir o worktree de {branchName}, o próprio branch e a pasta dele no espaço de trabalho? As sessões passam para a pasta do repositório. Esta ação não pode ser desfeita.", - "forceDeleteWorktreeAndBranchTitle": "Forçar a exclusão do worktree e do branch", - "forceDeleteWorktreeAndBranchDescription": "O worktree de {branchName} tem arquivos não commitados, ou o branch não está totalmente mesclado. Excluir os dois mesmo assim? Esta ação não pode ser desfeita." - }, - "current": "Atual", - "switchToBranch": "Mudar para esta branch", - "mergeBranchIntoCurrent": "Mesclar {branchName} em {currentBranch}", - "rebaseCurrentToBranch": "Rebase de {currentBranch} sobre {branchName}", - "noBranch": "Sem ramo", - "detachedHead": "HEAD desanexado em {sha}", - "initGitRepo": "Inicializar repositório Git", - "pullCode": "Fazer pull do código", - "fetchRemoteBranches": "Buscar branches remotas", - "openCommitWindow": "Commit de código...", - "pushCode": "Enviar...", - "pushBranch": "Enviar", - "newBranch": "Nova branch...", - "newWorktree": "Novo worktree...", - "stashChanges": "Guardar alterações...", - "stashPop": "Aplicar stash...", - "manageRemotes": "Gerenciar remotos...", - "localBranches": "Branches locais ({count, plural, one {#} other {#}})", - "noLocalBranches": "Sem branches locais", - "remoteBranches": "Branches remotas ({count, plural, one {#} other {#}})", - "noRemoteBranches": "Sem branches remotas", - "dialogs": { - "newBranchTitle": "Nova branch", - "newBranchDescription": "Criar uma nova branch a partir da branch atual {branch}", - "branchNamePlaceholder": "Nome da branch", - "newWorktreeTitle": "Novo worktree", - "newWorktreeDescription": "Criar um novo worktree a partir da branch atual {branch}", - "branchNameLabel": "Nome da branch", - "worktreePathLabel": "Caminho do worktree", - "worktreePathPlaceholder": "Caminho do worktree", - "manageRemotesTitle": "Gerenciar remotos", - "manageRemotesEmpty": "Nenhum remoto configurado", - "remoteNamePlaceholder": "Nome do remoto", - "remoteUrlPlaceholder": "URL do remoto", - "addRemote": "Adicionar", - "savingRemotes": "Salvando..." - }, - "conflict": { - "title": "Conflitos de merge", - "description": "Os seguintes arquivos têm conflitos que precisam ser resolvidos:", - "abort": "Abortar merge", - "openMergeTool": "Abrir ferramenta de merge", - "completeMerge": "Concluir merge", - "abortSuccess": "Merge abortado com sucesso", - "completeSuccess": "Merge concluído com sucesso" - }, - "stashDialog": { - "title": "Guardar alterações no stash", - "description": "Guardar as alterações atuais no stash", - "messageLabel": "Mensagem", - "messagePlaceholder": "Mensagem do stash (opcional)", - "keepIndex": "Manter índice (alterações preparadas permanecem preparadas)", - "cancel": "Cancelar", - "stash": "Guardar", - "success": "Alterações guardadas no stash", - "error": "Erro ao guardar no stash" - }, - "unstashDialog": { - "title": "Aplicar stash", - "noStashes": "Nenhum stash encontrado", - "selectFile": "Selecione um ficheiro para ver diferenças", - "viewDiff": "Ver diferenças", - "original": "Original", - "modified": "Modificado", - "apply": "Aplicar", - "drop": "Eliminar", - "applySuccess": "Stash aplicado", - "dropSuccess": "Stash eliminado", - "confirmApply": "Aplicar stash {ref} ao diretório de trabalho?", - "cancel": "Cancelar" - }, - "deleteBranch": "Excluir branch", - "deleteWorktree": "Excluir worktree", - "deleteWorktreeAndBranch": "Excluir worktree e branch", - "searchPlaceholder": "Pesquisar ramos e ações", - "searchAriaLabel": "Pesquisar ramos e ações", - "branchListLabel": "Ramos e ações", - "noMatches": "Nenhuma correspondência" - }, - "commitDialog": { - "toasts": { - "commitCompleted": "Commit de código concluído", - "pushFailed": "Falha no envio", - "committedFiles": "{count, plural, one {# arquivo commitado} other {# arquivos commitados}}", - "addedToVcs": "Adicionado ao VCS", - "addToVcsFailed": "Falha ao adicionar ao VCS", - "fileDeleted": "Arquivo excluído", - "deleteFailed": "Falha ao excluir", - "fileRolledBack": "Arquivo revertido", - "rollbackFailed": "Falha no rollback", - "dirRolledBack": "Diretório revertido", - "dirDeleted": "Diretório excluído" - }, - "confirm": { - "deleteTitle": "Confirmar exclusão", - "deleteDescription": "Excluir o arquivo \"{file}\"? Esta ação não pode ser desfeita.", - "rollbackTitle": "Confirmar rollback", - "rollbackDescription": "Reverter o arquivo \"{file}\" para o HEAD? Alterações não salvas serão perdidas.", - "rollbackDirDescription": "Reverter o diretório \"{dir}\" para HEAD? Alterações não salvas serão perdidas.", - "deleteDirDescription": "Excluir o diretório \"{dir}\"? Esta ação não pode ser desfeita." - }, - "actions": { - "select": "Selecionar", - "unselect": "Desmarcar", - "rollback": "Reverter", - "addToVcs": "Adicionar ao VCS" - }, - "aria": { - "selectFile": "{action}: {path}", - "unselectAllFiles": "Desmarcar todos os arquivos", - "selectAllFiles": "Selecionar todos os arquivos", - "unselectTracked": "Desmarcar alterações rastreadas", - "selectTracked": "Selecionar alterações rastreadas", - "unselectUntracked": "Desmarcar arquivos não rastreados", - "selectUntracked": "Selecionar arquivos não rastreados" - }, - "loading": "Carregando...", - "selectionCount": "{selected} / {total} arquivos", - "emptyFiles": "Sem arquivos alterados", - "trackedChanges": "Alterações rastreadas ({count})", - "untrackedFiles": "Arquivos não rastreados ({count})", - "commitMessage": "Mensagem de commit", - "commitMessagePlaceholder": "Digite a mensagem de commit...", - "commitButton": "Confirmar ({count})", - "commitAndPushButton": "Confirmar e enviar ({count})", - "head": "HEAD", - "workingTree": "Árvore de trabalho", - "clickFileToDiff": "Clique no nome do arquivo para ver o diff", - "loadingDiff": "Carregando diff..." - }, - "pushWindow": { - "title": "Enviar código", - "noUnpushedCommits": "Nenhum commit não enviado", - "noRemoteConfigured": "Nenhum remoto Git configurado\nAdicione um em «Gerenciar remotos»", - "newBranchNoPushedCommits": "Nova branch — enviar para criar branch de rastreamento remota", - "unpushed": "Não enviado", - "selectFileToViewDiff": "Selecione um arquivo para ver as diferenças", - "before": "Antes", - "after": "Depois", - "push": "Enviar", - "toasts": { - "pushSuccess": "Envio bem-sucedido", - "pushFailed": "Falha no envio", - "upstreamSet": "Branch remoto foi configurado", - "upstreamSetAndPushed": "Branch remoto configurado e {count} commits enviados", - "noCommitsToPush": "Nenhum commit para enviar", - "pushedCommits": "{count} commits enviados" - } - }, - "gitLogTab": { - "filesTitle": "Arquivos", - "expandAllFiles": "Expandir todos os arquivos", - "collapseAllFiles": "Recolher todos os arquivos", - "workspace": "espaço de trabalho", - "retry": "Tentar novamente", - "noCommitsFound": "Nenhum commit encontrado", - "notAGitRepoTitle": "Não é um repositório Git", - "notAGitRepoHint": "Inicialize o Git pelo menu de ramificações acima, ou abra um repositório existente.", - "hash": "Hash do commit", - "copyHash": "Copiar hash", - "copyMessage": "Copiar mensagem", - "showMore": "Mostrar mais", - "showLess": "Mostrar menos", - "author": "Autor", - "noFileChangeDetails": "Sem detalhes de alteração de arquivos disponíveis.", - "loadingFiles": "Carregando arquivos...", - "branchesTitle": "Branches Git", - "loadingBranches": "Carregando branches...", - "noContainingBranches": "Nenhuma branch contendo este commit foi encontrada.", - "newBranch": "Nova branch...", - "resetToHere": "Resetar para aqui", - "resetDisabledReasonNotCurrentBranchView": "Disponível somente ao visualizar a branch atual", - "copyFullCommitHashAria": "Copiar hash completo do commit {hash}", - "pushStatus": { - "pushed": "Enviado para o remoto", - "notPushed": "Não enviado para o remoto", - "unknown": "Status de push desconhecido (upstream não configurado)" - }, - "time": { - "monthsAgo": "{count, plural, one {há # mês} other {há # meses}}", - "daysAgo": "{count, plural, one {há # dia} other {há # dias}}", - "hoursAgo": "{count, plural, one {há # hora} other {há # horas}}", - "minsAgo": "{count, plural, one {há # min} other {há # mins}}", - "justNow": "agora mesmo" - }, - "toasts": { - "createdAndSwitchedNewBranch": "Nova branch criada e selecionada", - "newBranchFromCommit": "{name} (de {shortHash})", - "createBranchFailed": "Falha ao criar branch", - "openPushWindowFailed": "Falha ao abrir a janela de push", - "resetSuccess": "Reset concluído", - "resetSuccessDescription": "{branch} foi resetada para {shortHash} com {mode}", - "resetFailed": "Falha no reset" - }, - "authorFilter": { - "label": "Autor", - "searchPlaceholder": "Pesquisar autor", - "noAuthors": "Nenhum autor encontrado", - "you": "você", - "filterByAuthorAria": "Filtrar commits por autor", - "filterByQuery": "Filtrar por \"{query}\"", - "clearAuthorFilterAria": "Limpar filtro de autor", - "recent": "Recentes", - "matchingAuthors": "Autores correspondentes", - "removeFromRecent": "Remover {name} dos recentes" - }, - "branchSelector": { - "label": "Branch", - "head": "HEAD", - "headHint": "Acompanha a branch atual", - "headHintWithBranch": "Acompanha a branch atual ({branch})", - "searchBranch": "Pesquisar branch...", - "noBranches": "Nenhum branch", - "selectBranchPlaceholder": "Selecionar branch...", - "localBranches": "Branches locais", - "current": "Atual", - "remoteBranches": "Branches remotas", - "refreshCommitHistory": "Atualizar histórico de commits", - "clearBranchFilterAria": "Limpar filtro de branch" - }, - "dialogs": { - "newBranchTitle": "Nova branch", - "newBranchDescription": "Criar uma nova branch com o commit {shortHash} como commit mais recente.", - "branchNamePlaceholder": "Nome da branch", - "reset": { - "title": "Resetar a branch atual para este commit", - "branchLabel": "Branch", - "targetLabel": "Commit alvo", - "messageLabel": "Mensagem", - "modeLabel": "Modo de reset", - "confirmButton": "Resetar", - "modes": { - "soft": { - "label": "--soft", - "description": "Move o HEAD e o ponteiro da branch atual para o commit alvo.\nMantém Index e Working Tree sem alterações.\nAs mudanças dos commits removidos permanecem staged." - }, - "mixed": { - "label": "--mixed (padrão)", - "description": "Move o HEAD para o commit alvo.\nReseta o Index para o commit alvo e mantém as mudanças no Working Tree.\nAs mudanças passam de staged para unstaged." - }, - "hard": { - "label": "--hard", - "description": "Move o HEAD e reseta tanto Index quanto Working Tree para o commit alvo.\nAs mudanças locais rastreadas após o commit alvo são descartadas.\nEsta é uma operação destrutiva." - }, - "keep": { - "label": "--keep", - "description": "Move o HEAD para o commit alvo e tenta preservar alterações locais.\nSomente alterações sem conflito são mantidas.\nSe houver conflito, o reset é abortado para proteger seu trabalho." - } - } - } - }, - "moreActions": "Mais ações do Git" - }, - "gitChangesTab": { - "workspace": "espaço de trabalho", - "noChanges": "Sem alterações locais", - "notAGitRepoTitle": "Não é um repositório Git", - "notAGitRepoHint": "Inicialize o Git pelo menu de ramificações acima, ou abra um repositório existente.", - "trackedChanges": "Alterações rastreadas ({count})", - "untrackedFiles": "Arquivos não rastreados ({count})", - "expandTracked": "Expandir alterações rastreadas", - "collapseTracked": "Recolher alterações rastreadas", - "expandUntracked": "Expandir arquivos não rastreados", - "collapseUntracked": "Recolher arquivos não rastreados", - "showRemainingItems": "Mostrar mais {count} itens", - "actions": { - "commitCode": "Commit do código", - "rollback": "Reverter", - "addToVcs": "Adicionar ao VCS", - "delete": "Excluir", - "moreActions": "Mais ações do Git", - "addAllToVcs": "Adicionar tudo ao VCS", - "rollbackAll": "Reverter tudo", - "refresh": "Atualizar" - }, - "toasts": { - "noAddableFilesInDir": "Nenhum arquivo alterado neste diretório pode ser adicionado ao VCS", - "noRollbackFilesInDir": "Nenhum arquivo alterado neste diretório pode ser revertido", - "addedToVcs": "{name} adicionado ao VCS", - "addToVcsFailed": "Falha ao adicionar ao VCS", - "openCommitWindowFailed": "Falha ao abrir a janela de commit", - "rolledBack": "{name} revertido", - "rollbackFailed": "Falha no rollback", - "addedFilesToVcs": "{count, plural, one {# arquivo} other {# arquivos}} adicionados ao VCS", - "rolledBackFiles": "{count, plural, one {# arquivo revertido} other {# arquivos revertidos}}", - "deleted": "{name} excluído", - "deleteFailed": "Falha ao excluir", - "deletedFiles": "{count} arquivos excluídos", - "noDeletableFilesInDir": "Nenhum arquivo alterado neste diretório pode ser excluído", - "commitFailed": "Falha ao confirmar" - }, - "directoryDialog": { - "descriptionAdd": "Selecione arquivos sob o diretório {path} para adicionar ao VCS.", - "descriptionRollback": "Selecione arquivos sob o diretório {path} para reverter.", - "descriptionDelete": "Selecione arquivos no diretório {path} para excluir. Esta ação não pode ser desfeita.", - "descriptionFallback": "Selecione arquivos para prosseguir.", - "selectionCount": "Selecionados {selected} / {total} arquivos", - "selectAll": "Selecionar todos", - "unselectAll": "Desmarcar todos", - "loadingCandidates": "Carregando alterações do diretório...", - "noOperableFiles": "Nenhum arquivo operável" - }, - "rollbackConfirm": { - "title": "Confirmar rollback", - "descriptionWithTarget": "Reverter alterações locais de {kind} \"{name}\"?", - "descriptionFallback": "Reverter alterações locais?", - "kindDirectory": "diretório", - "kindFile": "arquivo" - }, - "deleteConfirm": { - "title": "Confirmar exclusão", - "descriptionWithTarget": "Excluir {kind} \"{name}\"? Esta ação não pode ser desfeita.", - "descriptionFallback": "Esta ação não pode ser desfeita.", - "kindDirectory": "diretório", - "kindFile": "arquivo" - }, - "quickCommit": { - "placeholder": "Mensagem do commit (Enter para confirmar)" - } - }, - "tabContext": { - "loadingConversation": "Carregando...", - "untitledConversation": "Conversa sem título", - "newConversation": "Nova conversa" - }, - "fileTreeTab": { - "workspace": "Espaço de trabalho", - "retry": "Tentar novamente", - "git": "Git", - "openInFileManager": "Abrir no gerenciador de arquivos", - "openInFinder": "Abrir no Finder", - "openInExplorer": "Abrir no Explorer", - "attachToCurrentSession": "Adicionar à sessão", - "compareWithBranch": "Comparar com branch...", - "reloadFromDisk": "Recarregar do disco", - "new": "Novo", - "newFile": "Arquivo", - "newDirectory": "Diretório", - "openIn": "Abrir em", - "openInTerminal": "Abrir no terminal", - "linkedFolder": "Pasta vinculada", - "copyPath": "Copiar caminho", - "upload": "Enviar arquivos/pasta", - "download": "Baixar arquivo", - "downloadAsZip": "Baixar como ZIP", - "actions": { - "select": "Selecionar", - "unselect": "Desmarcar", - "commitCode": "Fazer commit do código", - "rollback": "Reverter", - "addToVcs": "Adicionar ao VCS" - }, - "aria": { - "selectPath": "{action}: {path}" - }, - "toasts": { - "openDirectoryFailed": "Falha ao abrir diretório", - "openBuiltinTerminalFailed": "Não foi possível abrir o terminal embutido", - "openCommitWindowFailed": "Falha ao abrir janela de commit", - "noAddableFilesInDir": "Nenhum arquivo alterado neste diretório pode ser adicionado ao VCS", - "noRollbackFilesInDir": "Nenhum arquivo alterado neste diretório pode ser revertido", - "addedToVcs": "{name} adicionado ao VCS", - "addToVcsFailed": "Falha ao adicionar ao VCS", - "loadBranchesFailed": "Falha ao carregar branches", - "renameFailed": "Falha ao renomear", - "moveFailed": "Falha ao mover", - "deleteFailed": "Falha ao excluir", - "rolledBack": "{name} revertido", - "rollbackFailed": "Falha ao reverter", - "addedFilesToVcs": "{count, plural, one {# arquivo adicionado ao VCS} other {# arquivos adicionados ao VCS}}", - "rolledBackFiles": "{count, plural, one {# arquivo revertido} other {# arquivos revertidos}}", - "savedAsCopy": "Salvo como cópia", - "saveCopyFailed": "Falha ao salvar como cópia", - "watchStartFailed": "Falha ao iniciar monitoramento de arquivos", - "createFailed": "Falha ao criar", - "downloadFailed": "Falha ao baixar {name}", - "downloadSaved": "{name} baixado", - "pathCopied": "Caminho copiado", - "copyPathFailed": "Falha ao copiar o caminho" - }, - "createDialog": { - "newFile": "Novo arquivo", - "newDirectory": "Novo diretório", - "description": "Digite um nome para o novo {kind}.", - "placeholderFile": "file-name.ext", - "placeholderDirectory": "folder-name" - }, - "renameDialog": { - "renameDirectory": "Renomear diretório", - "renameFile": "Renomear arquivo", - "description": "Digite um novo nome (apenas nome, sem caminho).", - "placeholderDirectory": "novo-nome-da-pasta", - "placeholderFile": "novo-nome-do-arquivo.ext" - }, - "uploadDialog": { - "title": "Enviar para o workspace", - "description": "Ajuste o destino se necessário e adicione arquivos ou pastas.", - "workspaceRoot": "raiz do workspace", - "targetPathLabel": "Enviar para", - "targetPathHint": "Caminho resolvido: {path}", - "dropHint": "Arraste arquivos ou pastas aqui, ou use os botões abaixo", - "dropHintActive": "Solte para adicionar à fila", - "selectFiles": "Selecionar arquivos", - "selectFolder": "Selecionar pasta", - "startUpload": "Iniciar upload", - "clearQueue": "Limpar finalizados", - "removeItem": "Remover da fila", - "retry": "Tentar novamente", - "dropZoneAria": "Solte arquivos aqui ou ative para procurar", - "folderEmpty": "Nenhum arquivo encontrado na pasta solta", - "summary": "Total: {total} · Sucesso: {succeeded} · Falhas: {failed}", - "status": { - "pending": "Aguardando", - "uploading": "Enviando", - "success": "Concluído", - "error": "Falhou", - "cancelled": "Cancelado" - } - }, - "directoryDialog": { - "descriptionAdd": "Selecione arquivos no diretório {path} para adicionar ao VCS.", - "descriptionRollback": "Selecione arquivos no diretório {path} para reverter.", - "descriptionFallback": "Selecione arquivos para continuar.", - "selectionCount": "{selected} / {total} arquivos selecionados", - "selectAll": "Selecionar tudo", - "unselectAll": "Desmarcar tudo", - "loadingCandidates": "Carregando alterações do diretório...", - "noOperableFiles": "Nenhum arquivo operável" - }, - "compareDialog": { - "title": "Comparar com branch", - "descriptionWithTarget": "Selecione uma branch e compare com {kind} {path}", - "descriptionFallback": "Selecione uma branch para comparar.", - "kindDirectory": "diretório", - "kindFile": "arquivo", - "filterPlaceholder": "Filtre branches, ex.: main / origin/main", - "singleClickHint": "Clique em uma branch para comparar diretamente", - "loadingBranches": "Carregando branches...", - "recentBranches": "Branches recentes ({count})", - "noCurrentBranch": "Sem branch atual", - "localBranches": "Branches locais ({count})", - "remoteBranches": "Branches remotas ({count})", - "noMatchingBranches": "Nenhuma branch correspondente" - }, - "externalConflictDialog": { - "title": "Alterações externas de arquivo detectadas", - "descriptionWithPath": "O arquivo {path} foi alterado no disco e as edições atuais não foram salvas.", - "descriptionFallback": "O arquivo atual foi alterado no disco e as edições atuais não foram salvas.", - "compare": "Comparar", - "savingCopy": "Salvando cópia...", - "saveAsCopy": "Salvar como cópia", - "reload": "Recarregar" - }, - "deleteConfirm": { - "title": "Confirmar exclusão", - "descriptionWithTarget": "Excluir {kind} \"{name}\"? Esta ação não pode ser desfeita.", - "descriptionFallback": "Esta ação não pode ser desfeita.", - "kindDirectory": "diretório", - "kindFile": "arquivo" - }, - "rollbackConfirm": { - "title": "Confirmar reversão", - "descriptionWithTarget": "Reverter alterações locais do arquivo \"{name}\"?", - "descriptionFallback": "Reverter alterações locais deste arquivo?" - }, - "terminalTitle": "Console · {name}" - }, - "commandDropdown": { - "loading": "Carregando...", - "addCommand": "Adicionar comando", - "manageCommands": "Gerenciar comandos...", - "runCommandTitle": "Executar: {command}", - "stopCommandTitle": "Parar: {command}", - "manageDialog": { - "title": "Gerenciar comandos", - "empty": "Ainda não há comandos", - "noResults": "Nenhum comando correspondente", - "searchPlaceholder": "Pesquisar comandos", - "newCommand": "Novo comando", - "nameLabel": "Nome", - "commandLabel": "Comando", - "dragSort": "Arraste para ordenar", - "dragSortCommand": "Arraste para ordenar {name}", - "orderFailed": "Falha ao salvar a ordem dos comandos", - "loadFailed": "Falha ao carregar os comandos", - "saveFailed": "Falha ao salvar o comando", - "deleteFailed": "Falha ao excluir o comando", - "confirmDelete": { - "title": "Excluir comando?", - "message": "Isso removerá \"{name}\". Esta ação não pode ser desfeita." - } - } - }, - "workspaceContext": { - "confirmCloseDirtyTab": "Fechar \"{title}\" sem salvar?", - "confirmCloseOtherDirtyTabs": "Fechar outras abas com alterações não salvas?", - "confirmCloseAllDirtyTabs": "Fechar todas as abas com alterações não salvas?", - "unableLoadContent": "Não foi possível carregar o conteúdo.\n\n{message}", - "previewRequestTimedOut": "A solicitação de preview expirou", - "diffRequestTimedOut": "A solicitação de Diff expirou", - "branchCompareRequestTimedOut": "A solicitação de comparação de branch expirou", - "commitDiffRequestTimedOut": "A solicitação de Diff de commit expirou", - "saveRequestTimedOut": "A solicitação de salvamento expirou", - "reloadRequestTimedOut": "A solicitação de recarga expirou", - "noChanges": "Sem alterações.", - "noDiffOutput": "Sem saída de diff.", - "diffTitleWorkspace": "Diff · Espaço de trabalho", - "diffDescriptionWorkingTree": "Árvore de trabalho (HEAD)", - "diffTitleFile": "Diferença · {name}", - "compareTitleFile": "Comparar · {name}", - "compareTitleBranch": "Comparar · {branch}", - "compareDescriptionPath": "{path} · comparar com {branch}", - "compareDescriptionBranch": "comparar com {branch}", - "diffTitleCommitFile": "Diferença · {name} @ {hash}", - "diffTitleCommit": "Diferença · {hash}", - "diffDescriptionCommitPath": "{path} · confirmação {commit}", - "diffDescriptionCommit": "confirmação {commit}", - "diffTitleConflictFile": "Conflito · {name}", - "diffDescriptionConflict": "{path} · disco vs não salvo" - }, - "chat": { - "acpConnections": { - "actions": { - "openAgentsSettings": "Abrir configurações de agentes", - "retry": "Tentar novamente" - }, - "agentsSetupHint": "Abra Configurações > Agentes para gerenciar a instalação.", - "withSetupHint": "{message}\n{hint}", - "blocked": { - "missingConfig": "Não foi possível ler a configuração atual do agente.", - "disabled": "{agent} está desativado nas configurações de agentes. Ative-o antes de conectar.", - "unavailable": "{agent} está indisponível na plataforma atual.", - "sdkMissing": "O SDK de {agent} não está instalado", - "adapterMissing": "O adaptador ACP de {agent} não está instalado" - }, - "backendErrors": { - "initializeTimeout": "O handshake de conexão de {agent} expirou (sem resposta após 60 segundos). Abra Configurações para verificar a configuração do agente e da rede.", - "mcpRejectedByAgent": "{agent} recusou a sessão com o companheiro MCP do codeg anexado: {message} Se este agente não suporta MCP, desative “Suporte a MCP” nas Configurações e conecte novamente.", - "processExited": "O processo de {agent} encerrou inesperadamente.", - "spawnFailed": "Falha ao iniciar {agent}: {message}", - "downloadFailed": "Falha no download de {agent}: {message}", - "sessionLoadResourceNotFound": "Falha ao carregar a sessão de {agent}. Recarregue para tentar novamente ou inicie uma nova conversa.", - "sessionLoadUnavailable": "{agent} não conseguiu restaurar esta sessão; ela pode ter terminado ou o agente parou. Recarregue para tentar novamente ou inicie uma nova conversa.", - "turnFailedRefusal": "{agent} recusou continuar este turno. Costuma indicar um erro de backend ou gateway. Confira os logs do agente.", - "turnFailedMaxTokens": "{agent} atingiu o limite máximo de tokens para este turno.", - "turnFailedMaxTurnRequests": "{agent} atingiu o número máximo de solicitações permitidas para este turno.", - "turnFailedUnknown": "{agent} encerrou o turno com um motivo de parada desconhecido.", - "grokModelSwitchIncompatibleAgent": "{agent} não pode mudar para esse modelo em uma conversa existente. Inicie uma nova sessão para usá-lo.", - "turnFailedEmpty": "{agent} encerrou o turno sem produzir nenhuma resposta.", - "turnFailedEmptyProtocol": "{agent} produziu uma saída que o codeg não conseguiu analisar — a versão do agente pode não corresponder ao protocolo.", - "turnFailedEmptyMetadata": "{agent} enviou apenas atualizações de status neste turno (plano / modo / uso) e nenhuma resposta.", - "detailsInAlerts": "Abra os alertas na barra de status e expanda os detalhes para ver a saída do agente." - }, - "unableReadAgentConfig": "Não foi possível ler a configuração do agente: {message}", - "connectFailedTitle": "Falha na conexão de {agent}", - "toolFallbackTitle": "Ferramenta", - "eventErrorTitle": "Erro do agente", - "notificationTurnComplete": "{agent} terminou de responder", - "notificationError": "{agent} erro: {message}", - "claudeApiRetry": { - "fallbackError": "authentication_failed", - "retryingWithMax": "tentando novamente {attempt}/{max}", - "retryingAttempt": "tentando novamente tentativa {attempt}", - "retrying": "tentando novamente", - "nextRetryIn": "próxima em {seconds}s", - "line": "{error}{status} · {retry}", - "lineWithDelay": "{error}{status} · {retry}, {delay}", - "httpStatus": " (HTTP {status})" - }, - "configOptionAdjusted": "O {agent} definiu {option} como {actual} em vez de {requested}" - }, - "connectionLifecycle": { - "tasks": { - "connectingTitle": "Conectando a {agent}", - "connectingDescription": "Estabelecendo conexão", - "loadingSelectorsTitle": "Carregando seletores de {agent}", - "loadingSelectorsDescription": "Buscando opções de modo e configuração de sessão", - "initSessionTitle": "Initializing {agent} session", - "initSessionDescription": "Creating session and loading configuration" - }, - "errors": { - "connectionFailed": "Falha na conexão", - "sendPromptFailed": "Falha ao enviar a mensagem: {error}" - } - }, - "shared": { - "attachedResources": "Recursos anexados", - "toolCallFailed": "Falha na chamada da ferramenta" - }, - "messageThread": { - "emptyTitle": "Ainda não há mensagens", - "emptyDescription": "Inicie uma conversa para ver mensagens aqui" - }, - "chatInput": { - "connecting": "Conectando...", - "agentResponding": "{agent} está respondendo...", - "sendMessage": "Envie uma mensagem..." - }, - "messageInput": { - "askAnything": "Pergunte qualquer coisa...", - "removeAttachmentAria": "Remover {name}", - "attachFiles": "Anexar arquivos", - "addActions": "Adicionar", - "quickMessages": "Mensagens rápidas", - "quickMessagesEmpty": "Ainda não há mensagens rápidas", - "quickMessagesLoading": "Carregando...", - "pasteAsPlainText": "Colar como texto simples", - "cut": "Cortar", - "copy": "Copiar", - "selectAll": "Selecionar tudo", - "pasteUnavailable": "Não foi possível ler a área de transferência. Use Ctrl/⌘V para colar.", - "clipboardWriteFailed": "Não foi possível escrever na área de transferência. Use o atalho de teclado.", - "quickMessageUntitled": "Sem título", - "liveFeedback": "Feedback ao vivo", - "liveFeedbackDisabledHint": "Disponível enquanto o agente trabalha", - "dropFilesToAttach": "Solte arquivos para anexar", - "loadingSettings": "Carregando configurações...", - "loadingMode": "Carregando modo...", - "modeLabel": "Modo", - "toggleOn": "Ligado", - "toggleOff": "Desligado", - "agentSettings": "Configurações do agente", - "searchModel": "Buscar modelos...", - "searchModelAria": "Buscar modelos", - "modelListLabel": "Modelos", - "noModels": "Nenhum modelo encontrado", - "cancel": "Cancelar", - "send": "Enviar", - "forkAndSend": "Fork & Enviar", - "queueMessage": "Adicionar à fila", - "steerIntoTurn": "Inserir no turno atual", - "steerQueuedInstead": "Adicionado à fila — será enviado no próximo turno.", - "steerFailed": "Não foi possível inserir no turno atual", - "steerAttachmentsUnsupported": "Somente texto — rascunhos com anexos vão pela fila.", - "slashCommands": "Comandos de barra", - "slashSearchPlaceholder": "Buscar comandos...", - "slashSearchEmpty": "Nenhum comando correspondente", - "experts": "Especialistas", - "office": "Escritório", - "research": "Pesquisa", - "attachLocalUpload": "Carregar arquivo local", - "attachServerFile": "Selecionar arquivo do servidor", - "attachUploadTooLarge": "{names} excede o limite de upload de {limit}MB e foi ignorado.", - "attachUploadFailed": "Falha ao enviar {names}.", - "attachUploadNotAFile": "{names} não é um arquivo regular (diretório ou arquivo especial) e foi ignorado.", - "attachUploadQuotaExceeded": "O servidor ficou sem espaço para uploads; {names} não pôde ser enviado.", - "attachUploadInProgress": "As imagens ainda estão sendo enviadas — tente novamente em instantes.", - "mentionEmpty": "Nenhuma correspondência", - "mentionLoading": "Pesquisando…", - "mentionListLabel": "Menções", - "mentionMore": "Mais resultados — continue digitando para filtrar", - "mentionCount": "{count, plural, one {# resultado} other {# resultados}}", - "mentionGroupFile": "Arquivos", - "mentionGroupAgent": "Agentes", - "mentionGroupSession": "Sessões", - "mentionGroupCommit": "Commits", - "mentionGroupSkill": "Habilidades" - }, - "messageQueue": { - "addToQueue": "Adicionar à fila", - "saveEdit": "Salvar", - "cancelEdit": "Cancelar edição", - "editItem": "Editar", - "deleteItem": "Remover" - }, - "welcomeInputPanel": { - "agentsSettingsPath": "Configurações > Agentes", - "autoConnectFallback": "Clique para abrir {path} e gerenciar a instalação.", - "autoConnectAppend": "{message}. Clique para abrir {path} e gerenciar a instalação.", - "enableAgentFirstPlaceholder": "Ative pelo menos um agente antes de iniciar uma sessão...", - "prepareSessionFailed": "Não foi possível preparar a sessão de chat. Tente novamente.", - "createConversationFailed": "Não foi possível criar a conversa. Tente novamente.", - "askAnythingPlaceholder": "Pergunte qualquer coisa...", - "agentNotInstalled": "{agent} não está instalado · abra as configurações de Agents para instalá-lo", - "agentAdapterNotInstalled": "O adaptador ACP de {agent} não está instalado (separado da sua própria CLI) · abra as configurações de Agents para instalá-lo" - }, - "welcomePanel": { - "greeting": "O que você gostaria de fazer hoje?", - "tips": { - "tileTabs": "Clique com o botão direito em uma aba de conversa e escolha Exibir em mosaico para ver várias sessões lado a lado.", - "pinTab": "Clique duas vezes em uma aba de conversa para fixá-la, evitando que uma nova sessão a substitua automaticamente.", - "shortcutsNewSearch": "{newConversation} abre uma nova conversa, {searchConversations} pesquisa no histórico.", - "slashAtMention": "Digite / na entrada para acionar comandos slash, ou @ para referenciar um arquivo do projeto.", - "pasteDropFiles": "Cole uma captura de tela ou arraste um arquivo direto para a entrada para anexá-lo.", - "queueMessage": "Enquanto o agente responde, continue digitando — sua próxima mensagem entra na fila e é enviada automaticamente ao terminar.", - "draftAutoSave": "Rascunhos não enviados são salvos automaticamente por conversa e restaurados quando você volta.", - "forkSend": "O menu suspenso do botão de enviar tem Bifurcar e enviar — ramifique do ponto atual para uma nova aba.", - "exportConversation": "Clique com o botão direito dentro da conversa para exportá-la como Markdown, HTML ou imagem.", - "chatChannels": "Conecte Telegram / Lark / WeChat em Configurações → Canais de chat para continuar pelo celular.", - "shortcutsAuxPanel": "{toggleAuxPanel} alterna o painel direito para ver os arquivos tocados e as mudanças do Git desta sessão.", - "shortcutsTerminalSidebar": "{toggleTerminal} abre o terminal integrado, {toggleSidebar} alterna a barra lateral.", - "customShortcuts": "Todos os atalhos podem ser reatribuídos em Configurações → Atalhos.", - "webService": "Ative Configurações → Serviço web para que sua equipe acesse o mesmo codeg pelo navegador.", - "fusionMode": "Abra um arquivo ou diff para exibi-lo automaticamente ao lado da conversa.", - "quickMessages": "Abra o botão + ao lado da entrada e escolha Mensagens rápidas para inserir um trecho salvo (gerencie-os em Configurações → Mensagens rápidas).", - "experts": "O botão + tem um menu Habilidades de especialista — carregue papéis como Depuração ou Planejamento com um clique.", - "taskBoard": "As tarefas a fazer executam um trabalho do início ao fim: o agente trabalha no próprio worktree e você revisa o diff antes de mesclar.", - "automations": "As Automações executam um prompt salvo em uma agenda — uma revisão noturna, um relatório recorrente — e cada execução pode ter seu próprio worktree.", - "tokenUsage": "Clique no número de conversas na barra de status para abrir o Uso de tokens, detalhado por dia, agente, modelo e pasta.", - "mentionTargets": "@ não traz só arquivos: mencione outro agente para delegar uma subtarefa, ou referencie uma sessão anterior, um commit ou uma habilidade.", - "splitGroups": "Clique com o botão direito em uma aba e escolha Dividir à direita ou Dividir abaixo para manter duas conversas em painéis próprios.", - "worktrees": "Abra o botão de branch e escolha Novo worktree para vários agentes trabalharem no mesmo repositório sem sobrescrever os arquivos uns dos outros.", - "importSessions": "Já rodou sessões no terminal? O menu de uma pasta tem Importar sessões locais para trazer esse histórico para o codeg.", - "subSessions": "Quando um agente delega, a subsessão aparece aninhada abaixo dele na barra lateral — expanda a linha para acompanhar o que cada uma fez.", - "liveFeedback": "Feedback ao vivo, no menu +, insere uma nota no turno que o agente já está executando, sem interrompê-lo.", - "skillPacks": "Configurações → Pacotes de habilidades reúne especialistas de código, pesquisa científica e escritório; ative por agente.", - "modelProviders": "Configurações → Provedores de Modelos aceita sua própria chave de API ou endpoint, e o modelo você escolhe no campo de entrada.", - "workspaceBackground": "Configurações → Aparência define uma imagem de fundo do espaço de trabalho, a opacidade dos painéis e as fontes do app." - }, - "quickActions": { - "excel": "Pasta do Excel", - "excelDesc": "Tabelas, fórmulas e gráficos", - "word": "Documento do Word", - "wordDesc": "Relatórios, cartas e memorandos", - "ppt": "Apresentação", - "pptDesc": "Slides com design profissional", - "pitchDeck": "Pitch Deck", - "pitchDeckDesc": "Apresentação de captação com métricas", - "morph": "Animação Morph", - "morphDesc": "Transições de slide cinematográficas", - "morph3d": "Morph 3D", - "morph3dDesc": "Modelos 3D com movimentos de câmera", - "academic": "Artigo acadêmico", - "academicDesc": "Pesquisa com citações e estrutura", - "financial": "Modelo financeiro", - "financialDesc": "Demonstrações, DCF e projeções", - "dashboard": "Painel de dados", - "dashboardDesc": "KPIs e análises a partir dos seus dados", - "prompts": { - "excel": "Crie uma pasta do Excel com os seguintes requisitos:\n\n[descreva aqui seus dados, tabelas, fórmulas e gráficos]", - "word": "Crie um documento do Word com os seguintes requisitos:\n\n[descreva aqui o conteúdo, a estrutura e a formatação do documento]", - "ppt": "Crie uma apresentação do PowerPoint com os seguintes requisitos:\n\n[descreva aqui seus slides, conteúdo e design]", - "pitchDeck": "Crie um pitch deck de captação com os seguintes requisitos:\n\n[descreva aqui sua empresa, rodada de investimento e métricas-chave]", - "morph": "Crie uma apresentação com animações de transição Morph:\n\n[descreva aqui o tema da apresentação e os efeitos visuais desejados]", - "morph3d": "Crie uma apresentação Morph 3D com modelos GLB e movimentos de câmera:\n\n[descreva aqui seu tema e conceito visual em 3D]", - "academic": "Escreva um artigo acadêmico no Word com os seguintes requisitos:\n\n[descreva aqui seu tema de pesquisa, metodologia e principais resultados]", - "financial": "Crie um modelo financeiro no Excel com os seguintes requisitos:\n\n[descreva aqui suas demonstrações financeiras, projeções e análises]", - "dashboard": "Crie um painel de dados no Excel com os seguintes requisitos:\n\n[descreva aqui sua fonte de dados, KPIs e gráficos]", - "scientific-brainstorming": "Ajude-me a fazer um brainstorming de direções de pesquisa: explore conexões interdisciplinares, questione premissas e revele lacunas promissoras. A área que estou explorando: ", - "hypothesis-generation": "Ajude-me a transformar estas observações em hipóteses testáveis, com previsões claras, mecanismos plausíveis e experimentos. Minhas observações: ", - "experimental-design": "Ajude-me a planejar um experimento rigoroso antes de coletar dados: o delineamento, a aleatorização, os controles e como evitar confundimento. O que quero estudar: ", - "statistical-power": "Ajude-me a determinar o tamanho amostral necessário: conduza uma análise de poder (tamanho de efeito, alfa, poder) para o meu delineamento. Detalhes: ", - "statistical-analysis": "Ajude-me a analisar estes dados corretamente: escolha o teste certo, verifique os pressupostos, relate os tamanhos de efeito e redija. Meus dados e pergunta: ", - "exploratory-data-analysis": "Faça uma análise exploratória do meu arquivo de dados: resuma sua estrutura, qualidade e padrões notáveis e sugira os próximos passos. O arquivo é: ", - "scientific-visualization": "Ajude-me a criar uma figura com qualidade de publicação: layout claro, barras de erro honestas, uma paleta segura para daltônicos e formatação de periódico. O que quero mostrar: ", - "scientific-critical-thinking": "Ajude-me a avaliar criticamente este estudo ou alegação: avalie a qualidade da evidência, identifique vieses e confundidores e pondere as conclusões. Aqui está: ", - "paper-lookup": "Ajude-me a encontrar artigos relevantes e texto completo de acesso aberto em bases de dados acadêmicas, com citações reutilizáveis. Estou procurando: " - }, - "paper-lookup": "Busca de artigos", - "paper-lookupDesc": "Pesquise em 10 APIs acadêmicas (PubMed, arXiv, OpenAlex, Crossref…) artigos, citações e texto completo de acesso aberto.", - "scientific-critical-thinking": "Pensamento crítico", - "scientific-critical-thinkingDesc": "Avalie alegações científicas e a qualidade da evidência: identifique vieses e confundidores e aplique GRADE.", - "scientific-visualization": "Visualização científica", - "scientific-visualizationDesc": "Figuras prontas para publicação: layouts multipainel, anotações de significância e formatação específica de periódico.", - "exploratory-data-analysis": "Análise exploratória de dados", - "exploratory-data-analysisDesc": "Exploração automatizada de arquivos de dados científicos em mais de 200 formatos com métricas de qualidade e relatórios.", - "statistical-analysis": "Análise estatística", - "statistical-analysisDesc": "Análise estatística guiada: seleção de testes, verificação de pressupostos, tamanhos de efeito e relato no estilo APA.", - "statistical-power": "Poder estatístico", - "statistical-powerDesc": "Análise de tamanho amostral e poder: quantos sujeitos são necessários, efeitos mínimos detectáveis e curvas de poder.", - "experimental-design": "Delineamento experimental", - "experimental-designDesc": "Planeje estudos rigorosos antes de coletar dados: aleatorização, blocagem, controles e delineamentos fatoriais/DOE.", - "hypothesis-generation": "Geração de hipóteses", - "hypothesis-generationDesc": "Transforme observações em hipóteses testáveis com previsões, mecanismos e experimentos para testá-las.", - "scientific-brainstorming": "Brainstorming científico", - "scientific-brainstormingDesc": "Ideação aberta de pesquisa: explore conexões interdisciplinares, questione premissas e revele lacunas.", - "tabs": { - "office": "Escritório", - "coding": "Desenvolvimento", - "research": "Pesquisa" - }, - "coding": { - "brainstormingDesc": "Explore intenção e requisitos antes de construir", - "debuggingDesc": "Encontre a causa raiz antes de propor correções", - "writingSkillsDesc": "Crie, edite e verifique skills reutilizáveis" - }, - "notEnabled": { - "title": "A habilidade “{skill}” ainda não está ativada para {agent}", - "description": "Ative-a nas Configurações para usá-la aqui.", - "action": "Ativar", - "hint": "Habilidade não ativada" - }, - "scrollPrev": "Mostrar habilidades anteriores", - "scrollNext": "Mostrar mais habilidades" - } - }, - "agentSelector": { - "noEnabledAgents": "Nenhum agente habilitado", - "openAgentsSettings": "Abrir configurações de agentes", - "notInstalled": "Não instalado", - "moreAgents": "Mais agentes ({count})" - }, - "subAgentOverlay": { - "title": "Subagentes", - "collapsedSummary": "Subagentes {count}", - "collapseAria": "Recolher subagentes" - }, - "agentPlanOverlay": { - "title": "Plano do agente", - "collapsePlanAria": "Recolher plano", - "collapsedSummary": "Plano {completed}/{total}", - "status": { - "completed": "Concluído", - "inProgress": "Em andamento", - "pending": "Pendente", - "unknown": "Desconhecido" - }, - "priority": { - "high": "Alta", - "medium": "Média", - "low": "Baixa", - "unknown": "Desconhecida" - } - }, - "permissionDialog": { - "subtitle": "O agente solicita permissão para continuar este turno.", - "queuedCount": "+{count} aguardando", - "kindFallbackTool": "ferramenta", - "command": "Comando", - "cwd": "Diretório de trabalho: {cwd}", - "filesSummary": "Arquivos: {count}", - "moreFiles": "+{count} arquivos a mais", - "plan": "Plano", - "allowedActions": "Ações permitidas", - "targetMode": "Modo de destino: {mode}", - "optionGrants": "O que cada opção concede", - "changeScopeSession": "Esta sessão", - "changeScopeProcess": "Esta execução", - "changeScopeUser": "Salvo nas configurações do usuário", - "changeScopeProject": "Salvo nas configurações do projeto", - "changeScopeProjectLocal": "Salvo nas configurações locais do projeto", - "changeScopePersistent": "Salvo permanentemente" - }, - "questionDialog": { - "title": "O agente está fazendo uma pergunta", - "placeholder": "Digite sua resposta...", - "send": "Enviar" - }, - "messageBranch": { - "previousBranchAria": "Branch anterior", - "nextBranchAria": "Próxima branch", - "pageOf": "{current} de {total}" - }, - "terminal": { - "title": "Console", - "running": "Em execução" - }, - "reasoning": { - "thinking": "Pensando…", - "thoughtForFewSeconds": "Pensamento", - "thoughtForSeconds": "Pensamento" - }, - "linkSafety": { - "errorCannotOpen": "Não é possível abrir o arquivo local", - "errorNoWorkspace": "Nenhuma pasta de espaço de trabalho está ativa no momento.", - "errorFailedOpen": "Falha ao abrir o arquivo local", - "errorFailedLink": "Falha ao abrir o link", - "errorUnsupportedLinkProtocol": "Este protocolo de link não é compatível." - }, - "fileActions": { - "openInFinder": "Abrir no Finder", - "openInExplorer": "Abrir no Explorer", - "openInFileManager": "Abrir no gerenciador de arquivos", - "copyRelativePath": "Copiar caminho relativo", - "copyAbsolutePath": "Copiar caminho absoluto", - "pathCopied": "Caminho copiado", - "copyPathFailed": "Falha ao copiar o caminho", - "openFailed": "Falha ao abrir o arquivo local" - }, - "messageList": { - "attachedResources": "Recursos anexados", - "loading": "Carregando...", - "loadEarlier": "Carregar mensagens anteriores", - "loadingEarlier": "Carregando mensagens anteriores…", - "error": "Erro: {message}", - "errorTitle": "Falha ao carregar a sessão", - "errorActionReload": "Recarregar", - "errorActionNewSession": "Nova conversa", - "emptyConversation": "Nenhuma mensagem nesta conversa.", - "systemMessage": "Mensagem do sistema", - "copyMessage": "Copiar", - "copied": "Copiado", - "downloadImage": "Baixar imagem", - "downloadFailed": "Falha no download: {message}", - "imageGeneration": "Geração de imagem", - "imageGenerationPending": "Gerando imagem…", - "imageGenerationFailed": "Falha na geração da imagem", - "model": "Modelo", - "tokenStats": "Uso de tokens", - "tokenInput": "Entrada", - "tokenOutput": "Saída", - "tokenCacheRead": "Leitura de cache", - "tokenCacheWrite": "Escrita de cache", - "duration": "Duração", - "completedAt": "Concluído às", - "jumpToPreviousUserMessage": "Ir para a mensagem do usuário", - "showMore": "Mostrar mais", - "showLess": "Mostrar menos" - }, - "liveTurnStats": { - "thinking": "Pensando...", - "streaming": "Transmitindo", - "elapsedHours": "{value} h", - "elapsedMinutes": "{value} min", - "elapsedSeconds": "{value} s", - "outputSpeedAria": "Velocidade de saída estimada", - "outputSpeedTooltip": "Velocidade de saída estimada (texto + raciocínio)" - }, - "jsonTree": { - "viewRaw": "Ver JSON bruto", - "viewTree": "Ver árvore", - "fields": "{count, plural, one {# campo} other {# campos}}", - "items": "{count, plural, one {# item} other {# itens}}" - }, - "tool": { - "parameters": "Parâmetros", - "error": "Erro", - "result": "Resultado", - "status": { - "approvalRequested": "Aguardando aprovação", - "approvalResponded": "Respondido", - "inputAvailable": "Em execução", - "inputStreaming": "Pendente", - "outputAvailable": "Concluído", - "outputDenied": "Negado", - "outputError": "Erro" - } - }, - "toolCallBlock": { - "tool": "Ferramenta", - "error": "Erro", - "result": "Resultado" - }, - "delegation": { - "subAgentRunning": "Subagente em execução…", - "noDetail": "No detail available yet.", - "unknownAgent": "Subagente", - "openDetail": "Ver conversa", - "detailTitle": "Conversa do subagente", - "detailDescription": "Visualização somente leitura da conversa do subagente delegado.", - "waitForResult": "Aguardando o resultado da tarefa {task}", - "waitForResultNoTask": "Aguardando o resultado da tarefa", - "cancelTask": "Cancelando a tarefa {task}", - "cancelTaskNoTask": "Cancelando a tarefa", - "resultPageOf": "{current} / {total}", - "prevResult": "Resultado anterior", - "nextResult": "Próximo resultado", - "noResultText": "Sem resultado nesta verificação.", - "status": { - "starting": "iniciando", - "running": "em execução", - "checked": "verificado", - "waiting": "aguardando aprovação", - "ok": "concluído", - "err": { - "default": "falhou", - "delegation_disabled": "desativado", - "depth_limit": "limite de profundidade", - "invalid_agent_type": "agente inválido", - "spawn_failed": "falha ao iniciar", - "send_failed": "falha ao enviar", - "timeout": "tempo esgotado", - "canceled": "cancelado", - "child_refusal": "subagente recusou", - "child_max_tokens": "subagente: limite de tokens", - "child_max_turn_requests": "subagente: limite de solicitações", - "child_empty": "subagente sem saída", - "child_unknown": "subagente: erro", - "unknown": "tarefa desconhecida" - } - } - }, - "contentParts": { - "showingTailOutput": "Mostrando a saída final durante o streaming para melhor desempenho.", - "result": "Resultado", - "unknown": "desconhecido", - "inputTruncated": "A entrada foi truncada — o diff pode estar incompleto.", - "replaceAll": "SUBSTITUIR TUDO", - "filesCount": "Arquivos: {count}", - "update": "atualizar", - "moreFiles": "+{count} arquivos a mais", - "timeoutMs": "Tempo limite: {timeout}ms", - "backgroundTrue": "Segundo plano: true", - "scriptToolCalls": "{count, plural, one {# chamada de ferramenta} other {# chamadas de ferramenta}}", - "offset": "Deslocamento: {offset}", - "limit": "Limite: {limit}", - "pages": "Páginas: {pages}", - "mode": "Modo: {mode}", - "cell": "Célula: {cell}", - "shellSession": "Sessão {id}", - "pathLabel": "Caminho:", - "globLabel": "Padrão glob:", - "typeLabel": "Tipo:", - "outputLabel": "Saída:", - "caseInsensitive": "Sem diferenciar maiúsculas/minúsculas", - "multiline": "Multilinha", - "promptLabel": "Instrução", - "subjectLabel": "Assunto", - "taskLabel": "Tarefa", - "nameLabel": "Nome:", - "agentPromptLabel": "Instrução", - "agentModelLabel": "Modelo", - "agentRunning": "Em execução...", - "agentLiveTranscript": "Atividade ao vivo", - "agentProgressTools": "{count} chamadas de ferramentas", - "agentProgressTurns": "{count} turnos", - "agentProgressContext": "contexto {pct}%", - "agentSessionAction": "Ver a sessão do subagente", - "agentSessionTitle": "Sessão do subagente", - "agentSessionLoading": "Carregando a transcrição do subagente…", - "agentSessionEmpty": "O subagente ainda não escreveu nada.", - "agentFallbackTitle": "Iniciando subagente…", - "agentCodexLaunchOnly": "Iniciado. O Codex não informa mais o progresso deste subagente — o resultado chega como uma mensagem nesta conversa.", - "agentStatsBash": "Comandos", - "agentStatsRead": "Arquivos lidos", - "agentStatsSearch": "Pesquisas", - "agentStatsEdit": "Edições", - "agentStatsOther": "Outros", - "goal": { - "title": "Objetivo:", - "titleWithStatus": "Objetivo {status}", - "objective": "Objetivo", - "statusLabel": "Status", - "tokensUsed": "Tokens usados", - "budget": "Orçamento", - "remaining": "Restante", - "elapsed": "Decorrido", - "tokens": "tokens", - "pause": "Pausar", - "clear": "Limpar", - "status": { - "active": "ativo", - "paused": "pausado", - "blocked": "bloqueado", - "usageLimited": "uso limitado", - "budgetLimited": "orçamento limitado", - "complete": "concluído", - "limited": "limite atingido" - } - }, - "field": { - "file": "Arquivo", - "notebook": "Caderno", - "command": "Comando", - "old": "Antigo", - "new": "Novo", - "pattern": "Padrão", - "path": "Caminho", - "query": "Consulta", - "url": "URL:", - "description": "Descrição", - "content": "Conteúdo", - "source": "Fonte", - "prompt": "Instrução", - "subject": "Assunto", - "taskId": "ID da tarefa", - "status": "Situação", - "skill": "Skill", - "args": "Argumentos", - "offset": "Deslocamento", - "limit": "Limite", - "glob": "Padrão glob", - "type": "Tipo", - "output": "Saída", - "replaceAll": "Substituir tudo", - "language": "Idioma", - "timeout": "Tempo limite", - "background": "Segundo plano", - "agentType": "Tipo de agente", - "library": "Biblioteca", - "libraryId": "ID da biblioteca" - }, - "title": { - "edit": "Editar", - "command": "Comando", - "script": "Script", - "waitCommand": "Aguardar {command}", - "waitCell": "Aguardar sessão {id}", - "terminateCommand": "Encerrar {command}", - "terminateCell": "Encerrar sessão {id}", - "stdinChars": "Entrada {chars}", - "todoWrite": "TodoWrite (atualização de tarefas)", - "read": "Ler", - "write": "Escrever", - "notebookEdit": "NotebookEdit (edição de caderno)", - "editFiles": "Editar ({count} arquivos)", - "editWithTarget": "Editar {target}", - "readWithTarget": "Ler {target}", - "writeWithTarget": "Escrever {target}", - "notebookEditWithTarget": "NotebookEdit ({target})", - "globWithPattern": "Padrão glob {pattern}", - "listFilesWithPath": "Listar arquivos {path}", - "grepWithPattern": "Padrão grep {pattern}", - "taskCreateWithSubject": "Criar tarefa: {subject}", - "taskUpdateWithStatus": "Atualizar tarefa #{id} -> {status}", - "taskUpdate": "Atualizar tarefa #{id}", - "webFetchWithUrl": "WebFetch ({url})", - "webSearchWithQuery": "Pesquisa web: {query}", - "todosProgress": "Tarefas ({done}/{total})", - "skillWithName": "Skill: {name}", - "genericWithContext": "{tool} ({context})" - }, - "search": { - "noMatches": "Nenhuma correspondência", - "matchSummary": "{matches, plural, one {# correspondência} other {# correspondências}} em {files, plural, one {# arquivo} other {# arquivos}}", - "fileSummary": "{files, plural, one {# arquivo} other {# arquivos}}", - "moreResults": "{count, plural, one {# resultado adicional não exibido} other {# resultados adicionais não exibidos}}" - }, - "toolGroup": { - "search": "{count, plural, one {Explorou # busca} other {Explorou # buscas}}", - "command": "{count, plural, one {Executou # comando} other {Executou # comandos}}", - "read": "{count, plural, one {Leu arquivos # vez} other {Leu arquivos # vezes}}", - "memory": "{count, plural, one {Recordou # memória} other {Recordou # memórias}}", - "edit": "{count, plural, one {Editou arquivos # vez} other {Editou arquivos # vezes}}", - "fetch": "{count, plural, one {Buscou # recurso} other {Buscou # recursos}}", - "think": "{count, plural, one {Pensou # vez} other {Pensou # vezes}}", - "todo": "{count, plural, one {Atualizou # tarefa} other {Atualizou # tarefas}}", - "task": "{count, plural, one {Executou # tarefa} other {Executou # tarefas}}", - "other": "{count, plural, one {Usou # ferramenta} other {Usou # ferramentas}}", - "errorSuffix": "{count, plural, one {# falhou} other {# falharam}}", - "joiner": " · " - }, - "planMode": { - "entered": "Modo de planejamento iniciado", - "planLabel": "Plano", - "reviewApproved": "Plano aprovado — implementando", - "reviewKept": "Mantido no modo de plano", - "reviewPending": "Aguardando decisão sobre o plano", - "submitted": "Plano enviado", - "switched": "Modo alterado" - }, - "backgroundTask": { - "title": "Tarefa em segundo plano", - "titleWithId": "Tarefa em segundo plano · {id}", - "running": "Em execução", - "completed": "Concluída", - "failed": "Falhou", - "stopped": "Interrompida", - "exitCode": "saída {code}", - "polledTimes": "Consultada {count} vezes", - "runningInBackground": "Segundo plano", - "launchNote": "Em execução em segundo plano · {id}" - }, - "codexScript": { - "outputMissing": "O codex truncou a saída do script e removeu o separador deste comando, então nenhuma saída pôde ser atribuída a ele.", - "sharedWith": "Também contém a saída de {commands} — o codex truncou os separadores delas.", - "truncated": "truncado" - } - }, - "messageNav": { - "title": "Navegação de mensagens", - "collapse": "Recolher navegação de mensagens", - "collapsedSummary": "Mensagens {count}", - "fileCount": "{count, plural, one {# arquivo} other {# arquivos}}", - "remove": "Remover", - "noDiffDataAvailable": "Nenhum dado de diff disponível para {filePath}" - }, - "replyArtifacts": { - "title": "Arquivos alterados", - "fileCount": "{count, plural, one {# arquivo} other {# arquivos}}", - "newFilesTitle": "Novos arquivos", - "revealInFolder": "Mostrar no gerenciador de arquivos", - "openFile": "Abrir {filePath}", - "openInEditor": "Abrir no editor", - "remove": "Remover", - "noDiffDataAvailable": "Nenhum dado de diff disponível para {filePath}" - }, - "askQuestion": { - "title": "O agente precisa da sua escolha", - "subtitle": "Responda e envie. Você pode pular a qualquer momento.", - "recommended": "Recomendado", - "other": "Outro", - "otherPlaceholder": "Digite sua resposta…", - "singleSelect": "Única", - "multiSelect": "Múltipla", - "skip": "Pular", - "next": "Próxima", - "submit": "Enviar", - "submitError": "Falha ao enviar. Tente novamente." - }, - "planApproval": { - "title": "O agente tem um plano — revise", - "emptyPlan": "O agente não escreveu um plano. Aprove para começar ou solicite alterações.", - "approve": "Aprovar e construir", - "requestChanges": "Solicitar alterações", - "abandon": "Descartar", - "feedbackPlaceholder": "O que deve mudar?", - "sendChanges": "Enviar", - "cancel": "Cancelar", - "submitError": "Não foi possível enviar. Tente novamente." - }, - "feedbackCheckResult": { - "count": "{count, plural, =1 {1 comentário} other {# comentários}}", - "expand": "Mostrar todos os comentários", - "collapse": "Recolher", - "errorTitle": "Falha ao verificar comentários" - }, - "askQuestionResult": { - "title": "Pergunta", - "answeredLabel": "Pergunta e resposta:", - "awaiting": "Aguardando sua resposta…", - "declined": "Você ignorou isto — o agente usou o próprio julgamento.", - "noSelection": "Sem seleção" - }, - "configStale": { - "agentConfigTitle": "Configurações do agente atualizadas", - "modelProviderTitle": "Provedor de modelo atualizado", - "description": "Esta sessão ainda está usando a configuração anterior. Reconecte para aplicar (o histórico da conversa é mantido).", - "reconnect": "Reconectar para aplicar", - "reconnecting": "Reconectando…", - "reconnectDisabledDuringTurn": "Disponível quando o turno atual terminar", - "dismiss": "Dispensar", - "reconnectFailed": "Falha ao reconectar a sessão", - "applied": "Nova configuração aplicada" - }, - "piProjectTrust": { - "title": "Este projeto inclui recursos do pi", - "description": "O pi não está carregando os arquivos .pi do próprio repositório. Revise-os para decidir.", - "descriptionExecutable": "O repositório inclui extensões do pi, que executam código na inicialização. O pi não as está carregando. Revise antes de decidir.", - "review": "Revisar…", - "dismiss": "Dispensar", - "dialogTitle": "Confiar nos recursos do pi deste projeto?", - "dialogDescription": "O pi só carrega os arquivos .pi do próprio repositório se você confiar na pasta. Confie apenas se confiar no conteúdo deste repositório.", - "executionWarning": "Extensões são código. Ao confiar nesta pasta, o repositório poderá executá-las na inicialização do pi com suas permissões, antes de você enviar qualquer mensagem.", - "scopeNote": "A decisão é salva no trust.json do pi para esta pasta, vale para todas as pastas dentro dela e também é usada quando você executa o pi no terminal. Você pode alterá-la em Configurações → Agentes → Pi.", - "trust": "Confiar no projeto", - "decline": "Manter sem carregar", - "disabledDuringTurn": "Disponível quando o turno atual terminar", - "trustedToast": "Projeto confiável — reconectado para que o pi carregue seus recursos", - "declinedToast": "Os recursos do projeto continuam sem ser carregados", - "saveFailed": "Falha ao salvar a decisão de confiança do projeto", - "grantTitle": "Este projeto já é confiável", - "grantDescription": "O pi carrega os arquivos .pi do próprio repositório. Revise o que isso permite.", - "grantInheritedDescription": "Uma pasta superior é confiável, então o pi carrega os arquivos .pi do próprio repositório. Revise o que isso permite.", - "grantDialogTitle": "Os recursos do pi deste projeto são confiáveis", - "grantDialogDescription": "O pi tem permissão para carregar os arquivos .pi do próprio repositório. Versões anteriores do codeg concediam isso automaticamente ao abrir uma pasta, então talvez você nunca tenha sido perguntado.", - "grantExecutionWarning": "Extensões são código. O repositório as executa na inicialização do pi com suas permissões, antes de você enviar qualquer mensagem.", - "inheritedFrom": "Confiança herdada de", - "revoke": "Revogar confiança", - "keepTrusted": "Manter confiável", - "revokedToast": "Confiança revogada — reconectado para que o pi pare de carregar os recursos do projeto", - "trustedNoReconnect": "Projeto confiável — será aplicado na próxima inicialização do pi", - "revokedNoReconnect": "Confiança revogada — será aplicada na próxima inicialização do pi" - }, - "collabAgent": { - "title": "Subagente", - "errorTitle": "Falha na tarefa do subagente", - "statesLabel": "Subagentes", - "statusRunning": "Em execução", - "statusCompleted": "Concluído", - "statusFailed": "Falhou", - "statusPending": "Iniciando", - "statusInterrupted": "Interrompido", - "statusClosed": "Encerrado", - "statusNotFound": "Não encontrado", - "opSpawn": "Iniciando subagente", - "opWait": "Obtendo resultado do subagente", - "opClose": "Encerrando subagente", - "opResume": "Retomando subagente" - }, - "contextCompaction": { - "compacting": "Compactando o contexto…", - "compacted": "Contexto compactado", - "compactedTokens": "Contexto compactado · {before} → {after} tokens", - "failed": "Falha ao compactar o contexto" - }, - "sessionFailure": { - "category": { - "connection": "Problema de conexão", - "access": "Problema de acesso", - "limit": "Limite atingido", - "request": "Solicitação rejeitada", - "service": "Problema do serviço", - "unknown": "Problema de sessão" - }, - "action": { - "retry": "Tentar novamente", - "login": "Entrar", - "newSession": "Nova sessão" - }, - "recovered": "Recuperado", - "retryUnavailable": "Nenhuma mensagem anterior para reenviar.", - "toggleDetails": "Alternar detalhes" - }, - "backgroundTasks": { - "running": "{count, plural, one {# tarefa em segundo plano em execução} other {# tarefas em segundo plano em execução}}", - "settling": "Sincronizando resultados em segundo plano…", - "settledFallback": "Tarefa em segundo plano concluída ({status})", - "cardRunning": "Executando em segundo plano", - "cardLaunchedPending": "Tarefa iniciada em segundo plano", - "cardCompleted": "Tarefa em segundo plano concluída", - "cardFinishedWithStatus": "Tarefa em segundo plano encerrada ({status})", - "cardResultPending": "Resultado ainda não retornou" - }, - "proposedPlan": { - "title": "Plano proposto", - "planning": "A planear…" - } - }, - "diffPreview": { - "mode": { - "added": "Adicionado", - "deleted": "Excluído", - "renamed": "Renomeado", - "modified": "Modificado" - }, - "hunkLabel": "Bloco {index}", - "loadingHunk": "Carregando hunk...", - "noDiffData": "Sem dados de diff", - "showRemainingLines": "Mostrar mais {count} linhas" - }, - "conversationContextBar": { - "folderTitle": "Pasta de trabalho", - "branchTitle": "Branch de trabalho", - "searchFolder": "Search folder...", - "searchBranch": "Search branch...", - "noFolders": "No folders", - "noBranches": "No branches", - "noBranch": "(no branch)", - "chatModeLabel": "Modo de chat", - "commit": "Commit", - "push": "Push", - "merge": "Merge", - "toasts": { - "folderChanged": "Switched to {name}", - "openFolderFailed": "Failed to open folder", - "switchedToChatMode": "Alternado para o modo de chat", - "openStashFailed": "Failed to open stash window", - "openMergeFailed": "Failed to open merge window" - } - }, - "cloneDialog": { - "title": "Clonar repositório", - "repositoryUrl": "URL do repositório", - "repositoryUrlPlaceholder": "https://github.com/user/repo.git", - "directory": "Diretório", - "directoryPlaceholder": "Selecione o diretório de destino...", - "browseDirectory": "Procurar diretório", - "cancel": "Cancelar", - "clone": "Clonar", - "clonePath": "Caminho de clonagem: {path}" - }, - "toasts": { - "cloneFailed": "Falha ao clonar o repositório" - } - }, - "ProjectBoot": { - "title": "Inicializador de Projeto", - "tabs": { - "shadcn": "shadcn", - "hyperframes": "HyperFrames" - }, - "hyperframes": { - "title": "Projeto de vídeo HyperFrames", - "subtitle": "Crie um projeto de HTML para vídeo. O agente do espaço de trabalho pode então escrevê-lo e renderizá-lo.", - "resolution": "Resolução", - "skillsTitle": "Skills dos agentes", - "skillsDesc": "Instala globalmente as skills do HyperFrames (link simbólico) para os agentes selecionados, para que possam criar e renderizar vídeo.", - "recheck": "Verificar novamente", - "installedBadge": "Instalado", - "skillsInstall": "Instalar / atualizar skills", - "skillsInstalling": "Instalando skills…", - "skillsInstalled": "Skills do HyperFrames instaladas", - "skillsInstallFailed": "Não foi possível instalar as skills do HyperFrames" - }, - "config": { - "base": "Base", - "style": "Estilo", - "baseColor": "Cor base", - "theme": "Tema", - "chartColor": "Cor do gráfico", - "iconLibrary": "Biblioteca de ícones", - "font": "Fonte", - "fontHeading": "Fonte do título", - "menuAccent": "Destaque do menu", - "menuColor": "Cor do menu", - "radius": "Raio", - "template": "Modelo", - "createProject": "Criar projeto", - "sectionStyle": "Estilo", - "sectionColors": "Cores", - "sectionTypography": "Tipografia", - "sectionInterface": "Interface" - }, - "preview": { - "loading": "Carregando visualização..." - }, - "createDialog": { - "title": "Criar projeto", - "projectName": "Nome do projeto", - "projectNamePlaceholder": "my-app", - "frameworkTemplate": "Modelo de framework", - "packageManager": "Gerenciador de pacotes", - "saveDirectory": "Diretório de salvamento", - "saveDirectoryPlaceholder": "Selecionar diretório...", - "browseDirectory": "Procurar", - "projectPath": "O projeto será criado em: {path}", - "advancedOptions": "Opções Avançadas", - "base": "Biblioteca Base", - "enableRtl": "Ativar Suporte RTL", - "enableRtlDescription": "Ativar suporte de layout para idiomas da direita para a esquerda (ex.: árabe, hebraico)", - "pmChecking": "Verificando...", - "pmNotInstalled": "Não instalado", - "cancel": "Cancelar", - "create": "Criar", - "creating": "Criando projeto..." - }, - "toasts": { - "createFailed": "Falha ao criar o projeto", - "createSuccess": "Projeto criado com sucesso", - "openWorkspaceFailed": "Projeto criado, mas não foi possível abri-lo no espaço de trabalho" - }, - "errors": { - "directoryExists": "O diretório de destino já existe", - "commandFailed": "O comando de criação do projeto falhou." - } - }, - "WebServiceSettings": { - "addressSwitchHint": "Alternar muda apenas o endereço mostrado e aberto aqui; o serviço escuta em todas as interfaces e continua acessível em cada endereço.", - "sectionTitle": "Serviço Web", - "sectionDescription": "Ativar para acessar o Codeg remotamente pelo navegador", - "port": "Porta", - "status": "Status", - "autoStart": "Início automático", - "autoStartHint": "Iniciar o serviço Web ao abrir o Codeg", - "running": "Em execução", - "stopped": "Parado", - "processing": "Processando...", - "start": "Iniciar", - "stop": "Parar", - "startFailed": "Falha ao iniciar", - "stopFailed": "Falha ao parar", - "saveConfigFailed": "Falha ao salvar as configurações do serviço Web", - "open": "Abrir", - "hide": "Ocultar", - "show": "Mostrar", - "copy": "Copiar", - "qrcode": "Código QR", - "qrcodeTitle": "Escanear para abrir", - "qrcodeHint": "Escaneie com seu telefone para abrir o Codeg no navegador", - "addressLabel": "Endereço de acesso", - "tokenLabel": "Token de acesso", - "tokenHint": "Insira este token ao acessar o cliente Web pela primeira vez", - "tokenPlaceholder": "Deixe em branco para gerar automaticamente", - "regenerate": "Regenerar", - "stalePortOccupiedTitle": "A porta {port} está em uso por outro processo", - "stalePortUnknownTitle": "Estado da porta {port} é incerto", - "stalePortHint": "O Codeg não consegue vincular até a porta ser liberada. Altere a porta acima ou feche o processo que a retém.", - "errors": { - "alreadyRunning": "O serviço Web já está em execução", - "invalidAddress": "Formato de host ou porta inválido", - "portInUse": "A porta {port} já está em uso. Feche o processo que a utiliza ou escolha outra porta.", - "permissionDenied": "Permissão negada. Use uma porta acima de 1024 ou execute com privilégios mais altos.", - "addressUnavailable": "O endereço não está disponível nesta máquina", - "bindFailed": "Falha ao vincular o endereço" - } - }, - "DirectoryBrowser": { - "title": "Explorar diretório", - "pathPlaceholder": "Digite o caminho do diretório...", - "goHome": "Ir para o diretório inicial", - "navigateUp": "Ir para o diretório superior", - "select": "Selecionar", - "cancel": "Cancelar", - "loading": "Carregando...", - "emptyDirectory": "Este diretório está vazio", - "errorLoadingDir": "Falha ao carregar o diretório", - "permissionDenied": "Permissão negada" - }, - "ChatChannelSettings": { - "loading": "Carregando...", - "sectionTitle": "Canais de chat", - "sectionDescription": "Configure bots de IM para receber notificações de eventos e consultar atividade de codificação.", - "addChannel": "Adicionar canal", - "noChannels": "Nenhum canal de chat configurado ainda.", - "channelName": "Nome", - "channelNamePlaceholder": "Meu bot do Telegram", - "channelType": "Tipo de canal", - "lark": "Lark (Feishu)", - "weixin": "WeChat", - "dailyReport": "Relatório diário", - "dailyReportTime": "Horário do relatório", - "nameRequired": "O nome do canal é obrigatório.", - "tokenRequired": "O token é obrigatório.", - "chatIdRequired": "O Chat ID é obrigatório.", - "topicMode": "Modo de grupo por tópicos", - "topicModeHint": "Roteia tópicos de fórum do Telegram como sessões Codeg separadas. O bot deve estar em um supergrupo de fórum e poder gerenciar tópicos.", - "loadFailed": "Falha ao carregar os canais.", - "saveFailed": "Falha ao salvar as alterações.", - "connectSuccess": "Canal conectado.", - "connectFailed": "Falha na conexão", - "disconnectSuccess": "Canal desconectado.", - "disconnectFailed": "Falha ao desconectar.", - "testSuccess": "Teste de conexão aprovado.", - "testFailed": "Teste de conexão falhou", - "deleteSuccess": "Canal excluído.", - "deleteFailed": "Falha ao excluir o canal.", - "deleteConfirmTitle": "Excluir canal", - "deleteConfirmMessage": "O canal e seus registros de mensagens serão excluídos permanentemente. Tem certeza?", - "cancel": "Cancelar", - "delete": "Excluir", - "create": "Criar", - "save": "Salvar", - "channelListTitle": "Canais configurados", - "channelListDescription": "Os canais habilitados serão conectados automaticamente ao iniciar o serviço.", - "editChannel": "Editar canal", - "editSuccess": "Canal atualizado.", - "tokenPlaceholderKeep": "Deixar em branco para manter atual", - "weixinScanTitle": "Escanear código QR", - "weixinScanDescription": "Abra o WeChat e escaneie o código QR para conectar.", - "weixinQrcodeExpired": "Código QR expirado.", - "weixinRefreshQrcode": "Atualizar", - "weixinWaitingScan": "Aguardando escaneamento...", - "weixinPollError": "Conexão instável, tentando novamente...", - "weixinReconnectNotice": "Devido a limitações do protocolo iLink, após cada reconexão você precisa enviar uma mensagem ao bot para que os disparadores de eventos tenham efeito.", - "connect": "Conectar", - "disconnect": "Desconectar", - "test": "Testar conexão", - "tabs": { - "channels": "Canais", - "commands": "Comandos", - "events": "Eventos", - "other": "Outros" - }, - "commands": { - "title": "Comandos integrados", - "description": "Comandos de bot disponíveis nos canais de chat. Em chats em grupo, @Bot é necessário para processar mensagens.", - "prefixLabel": "Prefixo de comando", - "prefixDescription": "1-3 caracteres não alfanuméricos para acionar comandos do bot (padrão /).", - "prefixSaved": "Prefixo de comando salvo.", - "prefixSaveFailed": "Falha ao salvar o prefixo.", - "prefixInvalid": "O prefixo deve ser de 1-3 caracteres não alfanuméricos.", - "save": "Salvar", - "folderDesc": "Selecionar pasta de trabalho", - "agentDesc": "Selecionar agente de IA", - "taskDesc": "Criar sessão e executar tarefa", - "sessionsDesc": "Listar sessões ativas na pasta", - "resumeDesc": "Conversas recentes / retomar uma sessão", - "cancelDesc": "Cancelar tarefa atual", - "approveDesc": "Aprovar solicitação de permissão do agente", - "denyDesc": "Negar solicitação de permissão do agente", - "searchDesc": "Pesquisar conversas por palavra-chave", - "todayDesc": "Resumo da atividade de hoje", - "statusDesc": "Status da conexão do canal", - "helpDesc": "Mostrar ajuda" - }, - "events": { - "title": "Notificações de eventos", - "description": "Ao habilitar eventos, eles serão enviados ao canal quando acionados.", - "turnComplete": "Turno concluído", - "turnCompleteDesc": "Quando um turno do agente termina", - "error": "Erro do agente", - "errorDesc": "Quando um agente encontra um erro", - "permissionRequest": "Solicitação de permissão", - "permissionRequestDesc": "Quando um agente solicita permissão para agir", - "questionRequest": "Pergunta do agente", - "questionRequestDesc": "Quando um agente faz uma pergunta", - "userPromptSent": "Mensagem do usuário", - "userPromptSentDesc": "Quando você envia uma mensagem (o texto da mensagem é incluído na notificação)", - "saved": "Filtro de eventos atualizado.", - "saveFailed": "Falha ao salvar o filtro de eventos.", - "loadFailed": "Falha ao carregar as configurações.", - "retry": "Tentar novamente", - "webhooksTitle": "Webhooks", - "webhooksDescription": "Envia uma carga JSON via POST para uma ou mais URLs quando um evento ativado ocorre. O filtro de eventos acima também se aplica aos webhooks.", - "webhookUrlPlaceholder": "https://example.com/webhook", - "addWebhook": "Adicionar webhook", - "removeWebhook": "Remover webhook", - "webhookSave": "Salvar", - "webhooksSaved": "Webhooks salvos.", - "webhooksSaveFailed": "Falha ao salvar os webhooks.", - "webhookInvalidUrl": "Insira URLs http(s) válidas.", - "docsTitle": "Formato da requisição", - "docsMethod": "Método", - "docsContentType": "Content-Type", - "docsNote": "Cada evento ativado é entregue a todas as URLs. Os webhooks não têm debounce; o filtro de eventos acima continua valendo.", - "editWebhook": "Editar webhook", - "enableWebhook": "Ativar webhook", - "webhookDuplicate": "Esta URL já está configurada.", - "cancel": "Cancelar", - "webhooksEmpty": "Nenhum webhook configurado ainda.", - "deleteWebhookTitle": "Excluir webhook", - "deleteWebhookMessage": "Remover este webhook? Os eventos não serão mais entregues a esta URL.", - "delete": "Excluir" - }, - "language": { - "title": "Idioma das mensagens", - "description": "Idioma utilizado para notificações de eventos, respostas de comandos e relatórios diários enviados aos canais de chat.", - "saved": "Idioma das mensagens salvo.", - "saveFailed": "Falha ao salvar o idioma das mensagens.", - "en": "Inglês", - "zh-cn": "Chinês simplificado", - "zh-tw": "Chinês tradicional", - "ja": "Japonês", - "ko": "Coreano", - "es": "Espanhol", - "de": "Alemão", - "fr": "Francês", - "pt": "Português", - "ar": "Árabe" - } - }, - "ModelProviderSettings": { - "sectionTitle": "Provedores de Modelos", - "sectionDescription": "Gerenciar credenciais de provedores de API para agentes.", - "filterAll": "Todos", - "providerListTitle": "Provedores Configurados", - "addProvider": "Adicionar Provedor", - "editProvider": "Editar Provedor", - "noProviders": "Nenhum provedor de modelo configurado.", - "providerName": "Nome", - "providerNamePlaceholder": "Ex. OpenAI, Anthropic", - "apiUrl": "URL da API", - "apiUrlPlaceholder": "https://api.openai.com/v1", - "apiKey": "Chave da API", - "apiKeyPlaceholder": "sk-...", - "apiKeyKeepCurrent": "Deixe em branco para manter atual", - "agentTypes": "Tipos de Agente", - "agentTypesRequired": "Pelo menos um tipo de agente é necessário.", - "agentType": "Tipo de Agente", - "agentTypeRequired": "O tipo de agente é obrigatório.", - "agentTypeImmutableHint": "O tipo de agente não pode ser alterado após a criação.", - "model": "Modelo", - "modelPlaceholderCodex": "gpt-5.6-sol / gpt-5.5", - "modelPlaceholderGemini": "gemini-3-pro-preview", - "claudeMainModel": "Modelo Principal", - "claudeReasoningModel": "Modelo de Raciocínio (pensamento)", - "claudeHaikuDefaultModel": "Modelo Haiku Padrão", - "claudeSonnetDefaultModel": "Modelo Sonnet Padrão", - "claudeOpusDefaultModel": "Modelo Opus Padrão", - "claudeCustomModelOption": "ID do modelo personalizado", - "claudeCustomModelOptionName": "Nome do modelo personalizado", - "claudeCustomModelOptionDescription": "Descrição do modelo personalizado", - "claudeCustomModelOptionHint": "Adiciona uma única entrada personalizada ao seletor de modelos do Claude (por exemplo, um modelo atrás de um gateway/proxy personalizado). Nome e descrição são informações de exibição opcionais.", - "nameRequired": "O nome do provedor é obrigatório.", - "apiUrlRequired": "A URL da API é obrigatória.", - "apiKeyRequired": "A chave da API é obrigatória.", - "loadFailed": "Falha ao carregar provedores.", - "saveFailed": "Falha ao salvar alterações.", - "createSuccess": "Provedor criado.", - "editSuccess": "Provedor atualizado.", - "deleteSuccess": "Provedor excluído.", - "deleteConfirmTitle": "Excluir Provedor", - "deleteConfirmMessage": "O provedor \"{name}\" será excluído permanentemente. Tem certeza?", - "deleteBlockedByAgent": "{agents} está usando este provedor. Desvincule-o antes de excluir.", - "cancel": "Cancelar", - "delete": "Excluir", - "create": "Criar", - "save": "Salvar", - "affectedRunningSessions": "{count, plural, one {# sessão ativa precisa reconectar para aplicar a alteração} other {# sessões ativas precisam reconectar para aplicar a alteração}}" - }, - "SkillMatrix": { - "loading": "Carregando…", - "searchPlaceholder": "Pesquisar por nome, id ou descrição", - "empty": "Nada para mostrar.", - "emptySearch": "Nenhuma correspondência para a pesquisa atual.", - "skillColumn": "Habilidade", - "selectAll": "Selecionar tudo visível", - "selectSkill": "Selecionar {name}", - "everything": { - "label": "Em massa", - "enable": "Ativar tudo (visível)", - "disable": "Desativar tudo (visível)" - }, - "columnMenu": { - "enableAll": "Ativar todas as habilidades", - "disableAll": "Desativar todas as habilidades" - }, - "rowMenu": { - "label": "Ações em massa para {name}", - "enableAll": "Ativar para todos os agentes", - "disableAll": "Desativar para todos os agentes" - }, - "bulk": { - "selected": "{count} selecionados", - "targetAll": "Todos os agentes", - "targetSome": "{count} agentes", - "enable": "Ativar", - "disable": "Desativar", - "clear": "Limpar" - }, - "confirm": { - "disableTitle": "Desativar estes links?", - "disableBody": "Isto remove {count} links de habilidades gerenciados pelo codeg. Habilidades que ocupam um diretório personalizado não são afetadas. Você pode reativá-las a qualquer momento.", - "cancel": "Cancelar", - "confirm": "Desativar" - }, - "toasts": { - "loadFailed": "Falha ao carregar os status das habilidades", - "applyFailed": "Falha ao aplicar as alterações", - "enabled": "{count} links ativados", - "disabled": "{count} links desativados", - "enabledPartial": "{ok} ativados, {failed} falharam", - "disabledPartial": "{ok} desativados, {failed} falharam" - }, - "detail": { - "enableForAgents": "Ativar para agentes", - "preview": "Visualização do SKILL.md", - "loadingContent": "Carregando conteúdo…" - }, - "copyModeHint": "Copiado (não vinculado) — reative após atualizações para obter a versão mais recente" - }, - "ExpertsSettings": { - "title": "Habilidades de Especialista", - "description": "Ative fluxos de trabalho de habilidades selecionados e comprovados em campo para seus agentes de codificação de IA. Cada especialista é uma habilidade independente do projeto superpowers — o codeg gerencia a cópia central e a vincula aos agentes escolhidos.", - "loading": "Carregando especialistas…", - "loadingContent": "Carregando conteúdo…", - "emptyExperts": "Nenhum especialista disponível. Verifique os logs da aplicação.", - "emptySelection": "Selecione um especialista para ver seu conteúdo e gerenciar a ativação.", - "emptySearch": "Nenhum especialista corresponde à pesquisa atual.", - "searchPlaceholder": "Pesquisar especialistas por nome, ID ou descrição", - "enableForAgents": "Ativar para agentes", - "noAgents": "Nenhum agente ACP detectado.", - "copyModeWarning": "Copiado (não vinculado). Reative após as atualizações do codeg para obter a versão mais recente.", - "previewTitle": "Prévia do SKILL.md", - "categories": { - "discovery": "Descoberta e Design", - "planning": "Planejamento", - "execution": "Execução", - "quality": "Qualidade e Testes", - "debugging": "Depuração", - "review": "Revisão e Integração", - "meta": "Meta" - }, - "states": { - "not_linked": "Não ativado", - "linked_to_codeg": "Ativado", - "linked_elsewhere": "Bloqueado — outro vínculo existe", - "blocked_by_real_directory": "Bloqueado — uma habilidade personalizada ocupa este nome", - "broken": "Vínculo quebrado" - }, - "badges": { - "userModified": "Modificado pelo usuário" - }, - "actions": { - "openCentralDir": "Abrir pasta central", - "refresh": "Atualizar" - }, - "toasts": { - "loadFailed": "Falha ao carregar detalhes do especialista", - "enabled": "Especialista ativado para este agente", - "disabled": "Especialista desativado para este agente", - "enableFailed": "Falha ao ativar o especialista", - "disableFailed": "Falha ao desativar o especialista", - "openFolderFailed": "Falha ao abrir a pasta" - } - }, - "ScienceSettings": { - "title": "Habilidades de pesquisa científica", - "description": "Ative habilidades de pesquisa científica selecionadas para seus agentes de código com IA: geração de hipóteses, delineamento experimental, estatística, visualização, avaliação crítica e busca de literatura. O codeg gerencia uma cópia central e vincula cada habilidade aos agentes que você escolher.", - "loading": "Carregando habilidades científicas…", - "emptySkills": "Nenhuma habilidade científica disponível. Verifique os registros do aplicativo.", - "searchPlaceholder": "Pesquisar habilidades científicas por nome, id ou descrição", - "categories": { - "ideation": "Ideação", - "design": "Delineamento", - "analysis": "Análise", - "visualization": "Visualização", - "evaluation": "Avaliação", - "literature": "Literatura" - }, - "states": { - "not_linked": "Não ativado", - "linked_to_codeg": "Ativado", - "linked_elsewhere": "Bloqueado — outro vínculo existe", - "blocked_by_real_directory": "Bloqueado — uma habilidade personalizada ocupa este nome", - "broken": "Vínculo quebrado" - }, - "badges": { - "userModified": "Modificado pelo usuário", - "needsKey": "Requer chave", - "needsSetup": "Pode exigir configuração" - }, - "actions": { - "openCentralDir": "Abrir pasta central", - "refresh": "Atualizar" - }, - "toasts": { - "openFolderFailed": "Falha ao abrir a pasta" - } - }, - "OfficeToolsSettings": { - "title": "Ferramentas Office", - "description": "Gerencie as habilidades do OfficeCLI para criar arquivos Excel, Word e PowerPoint. Instale o OfficeCLI, sincronize as habilidades e ative-as por agente.", - "loadingContent": "Carregando conteúdo…", - "emptySkills": "Nenhuma habilidade disponível. Instale o OfficeCLI e sincronize as habilidades.", - "emptySelection": "Selecione uma habilidade para ver seu conteúdo e gerenciar a ativação.", - "emptySearch": "Nenhuma habilidade encontrada.", - "searchPlaceholder": "Pesquisar habilidades por nome, ID ou descrição", - "enableForAgents": "Ativar para agentes", - "noAgents": "Nenhum agente ACP detectado.", - "installFirst": "Instale o OfficeCLI primeiro para ativar as habilidades.", - "syncFirst": "Sincronize as habilidades primeiro para carregar o conteúdo.", - "noContent": "Nenhum conteúdo disponível.", - "copyModeWarning": "Copiado (não vinculado). Sincronize novamente para obter a versão mais recente.", - "previewTitle": "Pré-visualização SKILL.md", - "detection": { - "installed": "Instalado", - "notInstalled": "Não instalado", - "notRunnable": "Instalado, mas não executável", - "installHint": "Instale o OfficeCLI para habilitar as habilidades de geração de documentos Office para seus agentes de IA.", - "install": "Instalar", - "uninstall": "Desinstalar", - "syncSkills": "Sincronizar habilidades" - }, - "categories": { - "general": "Geral", - "presentations": "Apresentações", - "documents": "Documentos", - "spreadsheets": "Planilhas" - }, - "states": { - "not_linked": "Não ativado", - "linked_to_codeg": "Ativado", - "linked_elsewhere": "Bloqueado — existe outro link", - "blocked_by_real_directory": "Bloqueado — uma habilidade personalizada ocupa este nome", - "broken": "Link quebrado" - }, - "badges": { - "notSynced": "Não sincronizado" - }, - "actions": { - "refresh": "Atualizar" - }, - "toasts": { - "loadFailed": "Falha ao carregar detalhes da habilidade", - "enabled": "Habilidade ativada para este agente", - "disabled": "Habilidade desativada para este agente", - "enableFailed": "Falha ao ativar habilidade", - "disableFailed": "Falha ao desativar habilidade", - "installSuccess": "OfficeCLI instalado com sucesso", - "installFailed": "Falha ao instalar o OfficeCLI", - "uninstallSuccess": "OfficeCLI desinstalado", - "uninstallFailed": "Falha ao desinstalar o OfficeCLI", - "syncSuccess": "{synced} habilidades sincronizadas", - "syncPartial": "{synced} sincronizadas, {errors} falharam", - "syncFailed": "Falha ao sincronizar habilidades" - }, - "autoPreviewLabel": "Abrir visualização automaticamente", - "autoPreviewHint": "Quando um agente cria ou edita um arquivo do Word, Excel ou PowerPoint, abre sua visualização ao vivo automaticamente." - }, - "SkillPacksSettings": { - "title": "Pacotes de habilidades", - "description": "Pacotes de habilidades selecionados que o codeg gerencia de forma centralizada e vincula aos seus agentes de IA — especialistas em programação, pesquisa científica e ferramentas de documentos de escritório. Ative-os por agente abaixo.", - "tabs": { - "experts": "Especialistas", - "science": "Ciência", - "office": "Ferramentas de escritório", - "custom": "Personalizadas" - }, - "actions": { - "openCentralDir": "Abrir pasta central", - "refresh": "Atualizar" - }, - "toasts": { - "openFolderFailed": "Falha ao abrir a pasta" - } - }, - "QuickMessagesSettings": { - "title": "Mensagens rápidas", - "description": "Gerencie trechos de mensagens reutilizáveis. Arraste para reordenar.", - "loading": "Carregando mensagens rápidas…", - "emptyList": "Ainda não há mensagens rápidas. Clique em \"Nova\" para criar uma.", - "emptySelection": "Selecione uma mensagem rápida para editar.", - "searchPlaceholder": "Pesquisar por título ou conteúdo", - "untitled": "Sem título", - "actions": { - "new": "Nova", - "save": "Salvar", - "delete": "Excluir", - "dragSort": "Arraste para reordenar", - "dragSortMessage": "Arrastar para reordenar mensagem rápida: {name}" - }, - "fields": { - "title": "Título", - "titlePlaceholder": "Dê um título curto a esta mensagem", - "content": "Conteúdo", - "contentPlaceholder": "Digite aqui o conteúdo da mensagem" - }, - "confirmDelete": { - "title": "Excluir mensagem rápida?", - "message": "Isso excluirá permanentemente \"{name}\". Tem certeza?", - "cancel": "Cancelar", - "confirm": "Excluir" - }, - "toasts": { - "loadFailed": "Falha ao carregar mensagens rápidas", - "createFailed": "Falha ao criar mensagem rápida", - "saveFailed": "Falha ao salvar mensagem rápida", - "deleteFailed": "Falha ao excluir mensagem rápida", - "saveOrderFailed": "Falha ao salvar a ordem", - "created": "Mensagem rápida criada", - "saved": "Mensagem rápida salva", - "deleted": "Mensagem rápida excluída" - } - }, - "Pet": { - "badge": { - "running": "{count} em execução", - "waiting": "{count} aguardando aprovação", - "error": "{count} com erro" - }, - "panel": { - "title": "Sessões ativas", - "empty": "Nenhuma sessão ativa", - "emptyHint": "Agentes em execução e os que precisam de você aparecem aqui.", - "statusRunning": "Em execução", - "statusWaiting": "Aguardando", - "statusError": "Erro", - "subAgentOf": "Subagente de" - }, - "menu": { - "scale": "Escala", - "openManager": "Gerenciar pets", - "close": "Fechar" - }, - "loadError": "Falha ao carregar pet", - "missingPetIdParam": "Nenhum pet selecionado", - "summonButton": "Pet", - "manager": { - "title": "Pets", - "description": "Companheiros flutuantes de desktop com sprites compatíveis com o Codex.", - "addPet": "Adicionar pet", - "importFromCodex": "Importar do Codex", - "noPets": "Sem pets. Adicione um ou importe do Codex.", - "setActive": "Ativar", - "active": "Ativo", - "edit": "Editar", - "delete": "Excluir", - "deleteConfirm": "Excluir o pet \"{name}\"? Será removido do disco.", - "summon": "Invocar janela do pet", - "openCodexHelp": "Pets do Codex precisam estar em ~/.codex/pets/. Nenhum encontrado.", - "specRequirement": "O sprite precisa ter 1536px de largura e altura múltipla de 208px (ex.: 1872 ou 2288), em PNG ou WebP com transparência.", - "form": { - "id": "ID do pet", - "idHelp": "Minúsculas, dígitos, '-' e '_'. Máx 64 caracteres.", - "displayName": "Nome", - "description": "Descrição (opcional)", - "spritesheet": "Sprite", - "chooseFile": "Escolher arquivo", - "replaceFile": "Substituir sprite", - "saveCreate": "Adicionar pet", - "saveUpdate": "Salvar alterações", - "cancel": "Cancelar" - }, - "errors": { - "missingId": "ID obrigatório", - "missingName": "Nome obrigatório", - "missingSpritesheet": "Sprite obrigatório", - "addFailed": "Falha ao adicionar", - "updateFailed": "Falha ao atualizar", - "deleteFailed": "Falha ao excluir", - "loadFailed": "Falha ao carregar pets", - "setActiveFailed": "Falha ao ativar pet", - "summonFailed": "Falha ao abrir a janela do pet" - } - }, - "import": { - "title": "Importar do Codex", - "subtitle": "Pets disponíveis em ~/.codex/pets/.", - "selectAll": "Selecionar todos", - "alreadyImported": "Já importado", - "renameOnConflict": "Renomear conflitos com sufixo -imported", - "import": "Importar selecionados", - "noneFound": "Nenhum pet do Codex disponível.", - "imported": "Importação concluída", - "failed": "Falha no import", - "close": "Fechar" - }, - "marketplace": { - "openMarketplace": "Mercado de pets", - "title": "Mercado de pets", - "search": "Buscar pets", - "kindFilter": { - "all": "Todos", - "object": "Objeto", - "animal": "Animal", - "person": "Pessoa", - "creature": "Criatura" - }, - "sortFilter": { - "latest": "Recentes", - "popular": "Populares", - "views": "Mais vistos" - }, - "refresh": "Atualizar", - "install": "Instalar", - "installing": "Instalando", - "reinstall": "Reinstalar", - "reinstallConfirm": "Sobrescrever o pet local \"{name}\"? Os dados existentes serão substituídos.", - "cancel": "Cancelar", - "stats": { - "views": "Visualizações", - "downloads": "Downloads", - "likes": "Curtidas" - }, - "actions": { - "idle": "Parado", - "running_right": "Corre dir.", - "running_left": "Corre esq.", - "waving": "Acena", - "jumping": "Pula", - "failed": "Falha", - "waiting": "Espera", - "running": "Corre", - "review": "Revisão" - }, - "page": "Página {page} de {total}", - "prev": "Anterior", - "next": "Próxima", - "empty": "Nenhum pet corresponde.", - "successInstalled": "\"{name}\" instalado", - "errors": { - "loadFailed": "Falha ao carregar o mercado", - "installFailed": "Falha ao instalar o pet", - "alreadyInstalled": "O pet já existe localmente" - } - } - }, - "RemoteWorkspace": { - "openRemoteWorkspace": "Open remote workspace", - "manage": "Manage remote workspace", - "manageTitle": "Remote Workspace connections", - "empty": "No remote connections", - "searchPlaceholder": "Search remote workspaces", - "orderFailed": "Failed to save remote workspace order", - "dragSort": "Drag to sort", - "dragSortConnection": "Drag to sort {name}", - "newConnection": "New connection", - "loading": "Loading", - "loadingConnection": "Loading remote connection", - "name": "Name", - "baseUrl": "Service URL", - "token": "Access token", - "save": "Save", - "delete": "Delete", - "confirmDelete": { - "title": "Delete remote connection?", - "message": "This will remove \"{name}\" from this device. This action cannot be undone.", - "cancel": "Cancel", - "confirm": "Delete" - }, - "saved": "Remote connection saved.", - "deleted": "Remote connection deleted.", - "loadFailed": "Failed to load remote connections", - "saveFailed": "Failed to save remote connection", - "deleteFailed": "Failed to delete remote connection", - "openFailed": "Failed to open remote workspace", - "connectionLoadFailed": "Failed to load remote connection: {message}", - "connectionExpired": "Remote connection \"{name}\" is expired. Update its token and reload this window." - }, - "ServerFileBrowser": { - "title": "Selecionar arquivo do servidor", - "pathPlaceholder": "Inserir caminho do diretório...", - "goHome": "Ir para o diretório inicial", - "navigateUp": "Ir para o diretório acima", - "select": "Selecionar", - "cancel": "Cancelar", - "loading": "Carregando...", - "emptyDirectory": "Este diretório está vazio", - "errorLoadingDir": "Falha ao carregar o diretório", - "selectedCount": "{count} selecionado(s)" - }, - "BackupSettings": { - "title": "Backup e restauração", - "description": "Exporte um backup portátil dos seus dados do codeg ou restaure a partir de um.", - "tabs": { - "backup": "Backup", - "restore": "Restauração" - }, - "export": { - "includeExternal": "Incluir o conteúdo das conversas", - "includeExternalHint": "Também arquiva as transcrições das CLIs (Claude, Codex, Gemini, …). Aumenta o tamanho.", - "passphrase": "Senha (opcional)", - "passphrasePlaceholder": "Deixe em branco para um arquivo sem criptografia", - "passphraseConfirm": "Confirmar a senha", - "passphraseMismatch": "As senhas não coincidem.", - "noPassphraseWarning": "Este backup conterá segredos (chaves de API, tokens) em texto puro. Guarde-o em local seguro.", - "passphraseLossWarning": "Criptografado com esta senha. Se você perdê-la, o backup não poderá ser recuperado.", - "button": "Exportar backup", - "inProgress": "Criando backup…", - "success": "Backup criado.", - "started": "Download do backup iniciado." - }, - "restore": { - "selectFile": "Selecionar arquivo de backup", - "passphrasePrompt": "Este backup está criptografado. Digite a senha dele.", - "unlock": "Desbloquear", - "preview": { - "title": "Detalhes do backup", - "encrypted": "Criptografado", - "compatible": "Compatível", - "incompatible": "Incompatível", - "createdAt": "Criado: {value}", - "appVersion": "Versão do app: {value}", - "incompatibleHint": "Este backup foi criado por uma versão mais recente do codeg e não pode ser restaurado." - }, - "replaceWarning": "Restaurar substitui todos os dados atuais do codeg (banco de dados e uploads). Seus dados atuais são salvos em um snapshot primeiro, para que possam ser recuperados.", - "keyringNote": "Os tokens de GitHub/chat do desktop ficam no chaveiro do sistema e não são incluídos; insira-os novamente após restaurar.", - "button": "Restaurar", - "staging": "Preparando a restauração…", - "staged": "Restauração preparada. Reiniciando…", - "restarting": "Restauração preparada. Reiniciando o servidor…", - "restartTimeout": "O servidor não voltou a tempo. Recarregue a página quando ele estiver ativo.", - "externalSideLocation": "As transcrições de conversas foram restauradas em {path}", - "confirmTitle": "Substituir todos os dados?", - "confirmBody": "Isto substituirá seu banco de dados e uploads atuais do codeg pelo backup e, em seguida, reiniciará. Seus dados atuais são salvos em um snapshot primeiro.", - "cancel": "Cancelar", - "confirmAction": "Substituir e reiniciar", - "external": { - "title": "Conteúdo das conversas", - "hint": "Este backup inclui transcrições das CLIs. Escolha para onde restaurá-las.", - "modeSkip": "Não restaurar", - "modeSide": "Restaurar em uma pasta separada segura", - "modeOriginal": "Restaurar nos locais originais das CLIs", - "forceOverwrite": "Sobrescrever arquivos existentes", - "forceOverwriteHint": "Substitui os arquivos que já existem nas pastas das CLIs.", - "scanning": "Verificando conflitos…", - "noConflicts": "Nenhum arquivo existente será sobrescrito.", - "conflictCount": "{count} arquivo(s) existente(s) seriam afetados.", - "conflictSkipNote": "Os arquivos existentes são mantidos (ignorados) a menos que você ative a sobrescrita." - }, - "restartFailed": "Restauração preparada, mas o servidor não conseguiu reiniciar. Reinicie-o manualmente para aplicá-la." - }, - "remoteUnsupported": "O backup e a restauração atuam sobre os dados da máquina que executa o codeg. Você está conectado a um espaço de trabalho remoto — gerencie os backups dele diretamente nesse servidor." - }, - "backup": { - "restore": { - "error": { - "badPassphrase": "Senha incorreta ou backup corrompido.", - "corrupted": "O arquivo de backup está corrompido.", - "unknownFormat": "Este arquivo não é um backup do codeg reconhecido.", - "newerVersion": "Este backup foi criado pelo codeg {backupVersion}, mais recente que esta versão ({appVersion}).", - "alreadyPending": "Já existe uma restauração preparada. Reinicie para aplicá-la antes de preparar outra." - } - }, - "error": { - "diskSpace": "Espaço em disco insuficiente para concluir a operação.", - "cancelled": "A operação foi cancelada." - } - }, - "WebConnection": { - "disconnectedTitle": "Conexão perdida", - "reconnectingDescription": "Tentando reconectar ao servidor. Normalmente isso se resolve sozinho em alguns segundos.", - "reconnectNow": "Reconectar agora", - "sessionExpiredTitle": "Sessão expirada", - "sessionExpiredDescription": "Sua sessão não é mais válida. Faça login novamente para continuar.", - "goToLogin": "Ir para o login" - }, - "LiveFeedback": { - "placeholder": "Envie uma nota para {agent} enquanto ele trabalha…", - "agentFallback": "o agente", - "ariaLabel": "Nota de feedback ao vivo", - "dialogTitle": "Feedback ao vivo", - "dialogDescription": "Envie uma nota ao agente enquanto ele trabalha. Ele a lerá na próxima verificação, sem interromper a etapa atual.", - "dialogDescriptionInstant": "Envie uma nota ao agente enquanto ele trabalha. Ela é inserida imediatamente no turno atual — o agente a vê na hora.", - "channelDowngraded": "A inserção instantânea não está disponível nesta sessão — sua nota foi salva para o agente ler na próxima verificação.", - "send": "Enviar", - "cancel": "Cancelar", - "pending": "aguardando", - "delivered": "recebida", - "turnEndedUnread": "O agente terminou antes de ler o seu feedback.", - "sendAsMessage": "Enviar como mensagem", - "dismiss": "Dispensar", - "turnEndedResent": "O turno terminou — enviado como nova mensagem.", - "turnEnded": "O turno já terminou.", - "submitFailed": "Não foi possível enviar a sua nota" - }, - "AgentToolsSettings": { - "title": "Ferramentas na conversa", - "description": "Ferramentas extras que o codeg dá a um agente dentro de uma conversa. Elas são injetadas quando o agente inicia, então a mudança vale para os agentes iniciados depois.", - "feedbackLabel": "Feedback ao vivo", - "feedbackHint": "Envie notas e correções a um agente enquanto ele trabalha. Se o agente oferecer inserção instantânea, sua nota entra imediatamente no turno em andamento; caso contrário, o agente recebe uma ferramenta para verificar seu feedback — esses agentes normalmente só verificam quando você menciona isso no prompt, por exemplo, adicione \"verifique meu feedback ao vivo regularmente\" à sua mensagem.", - "questionLabel": "Perguntar ao usuário", - "questionHint": "Permite que os agentes pausem e façam uma pergunta de múltipla escolha que aparece acima da caixa de entrada da conversa. O agente aguarda até você responder (ou pular).", - "sessionInfoLabel": "Obter informações da sessão", - "sessionInfoHint": "Permite que os agentes consultem uma sessão mencionada na sua mensagem (um selo de sessão) para ler o título, agente, status, espaço de trabalho, uso de tokens e mensagens recentes.", - "automationsLabel": "Criar automações", - "automationsHint": "Salva a conversa como uma automação que roda em um agendamento. Desativado por padrão — depois ela inicia agentes por conta própria.", - "workTasksLabel": "Criar tarefas a fazer", - "workTasksHint": "Coloca um cartão no quadro de tarefas a partir da conversa. Desativado por padrão — grava o estado do app.", - "save": "Salvar", - "saving": "Salvando…", - "saved": "Configurações de ferramentas salvas", - "saveFailed": "Falha ao salvar as configurações de ferramentas", - "loadFailed": "Falha ao carregar: {detail}" - }, - "NotificationSoundSettings": { - "title": "Sons de notificação", - "description": "Reproduz um som curto quando ocorre um evento do agente. São os mesmos eventos enviados aos canais de chat; esta configuração vale apenas para este dispositivo.", - "enableHint": "Desativado por padrão. Os sons tocam apenas na janela do espaço de trabalho deste navegador ou aplicativo.", - "volume": "Volume", - "preview": "Ouvir", - "previewEvent": "Ouvir o som de {event}", - "onlyWhenUnfocused": "Somente quando a janela não estiver em foco", - "onlyWhenUnfocusedHint": "Fica em silêncio enquanto você está olhando para o Codeg.", - "eventsTitle": "Eventos", - "eventsHint": "Escolha um som para cada evento ou «Silencioso» para ignorá-lo. Se o mesmo evento se repetir em poucos segundos, ele toca apenas uma vez.", - "toneNone": "Silencioso", - "toneChime": "Carrilhão", - "toneDing": "Sino", - "toneBlip": "Bipe", - "tonePop": "Pop", - "toneAlert": "Alerta", - "toneDescend": "Descendente" - }, - "LogsSettings": { - "loading": "Carregando…", - "sectionTitle": "Registros de execução", - "sectionDescription": "Visualize e configure os registros de diagnóstico do aplicativo. Os registros são gravados em arquivos locais e mantidos na memória para visualização ao vivo.", - "captureTitle": "Nível de registro", - "captureDescription": "Controla quanto detalhe é capturado. Níveis mais altos (Debug, Trace) registram mais, mas geram registros maiores. «Desligado» desativa o registro.", - "captureLabel": "Nível de captura", - "levels": { - "off": "Desligado", - "error": "Erro", - "warn": "Aviso", - "info": "Informação", - "debug": "Depuração", - "trace": "Rastreamento" - }, - "viewerTitle": "Registros recentes", - "viewerDescription": "Visualização ao vivo dos registros recentes. Filtre por nível ou pesquise texto.", - "searchPlaceholder": "Pesquisar mensagem ou origem…", - "viewLevels": { - "all": "Todos os níveis", - "error": "Erro e acima", - "warn": "Aviso e acima", - "info": "Informação e acima", - "debug": "Depuração e acima", - "trace": "Rastreamento e acima" - }, - "pause": "Pausar", - "resume": "Ao vivo", - "refresh": "Atualizar", - "clear": "Limpar", - "openFolder": "Abrir pasta", - "shownCount": "{shown} / {total} exibidos", - "empty": "Nenhum registro para exibir.", - "levelSaveFailed": "Falha ao salvar o nível de registro", - "openFolderFailed": "Falha ao abrir a pasta de registros", - "downloadFailed": "Falha ao baixar o arquivo de registro", - "filesTitle": "Arquivos de registro", - "filesDescription": "Baixe arquivos de registro completos do disco para o histórico além do buffer ao vivo.", - "filesEmpty": "Ainda não há arquivos de registro.", - "download": "Baixar", - "downloadTruncated": "O arquivo é grande; foram baixados os {size} mais recentes. O arquivo completo está no diretório de logs.", - "captureEnvLocked": "O nível de registro é controlado pela variável de ambiente RUST_LOG / CODEG_LOG; altere-a lá para ter efeito.", - "targetsTitle": "Substituições por módulo", - "targetsDescription": "Defina um nível diferente para módulos específicos (ex.: codeg_lib::acp) sem alterar o nível global.", - "targetsAdd": "Adicionar", - "targetsRemove": "Remover substituição", - "toggleDetails": "Alternar detalhes" - }, - "Automations": { - "title": "Automações", - "new": "Nova automação", - "empty": "Ainda não há automações", - "emptyHint": "Crie uma para executar uma tarefa do agente de forma agendada ou manual.", - "name": "Nome", - "namePlaceholder": "ex.: Revisão de PR noturna", - "prompt": "Instrução", - "promptPlaceholder": "O que o agente deve fazer?", - "agent": "Agente", - "folder": "Pasta do espaço de trabalho", - "folderPlaceholder": "Selecione uma pasta", - "isolation": "Isolamento", - "isolationWorktree": "Novo worktree por execução", - "isolationShared": "Executar na pasta", - "isolationSharedCaveat": "As execuções usam diretamente a árvore de trabalho desta pasta e podem entrar em conflito com suas alterações não confirmadas. Ative a opção de worktree para isolar cada execução.", - "trigger": "Gatilho", - "triggerSchedule": "Agendado", - "triggerManual": "Somente manual", - "cron": "Agendamento (cron)", - "cronPlaceholder": "0 9 * * 1-5", - "timezone": "Fuso horário", - "nextRun": "Próxima execução", - "branch": "Branch", - "branchOptional": "Branch (opcional)", - "enabled": "Ativado", - "save": "Salvar", - "cancel": "Cancelar", - "edit": "Editar", - "delete": "Excluir", - "runNow": "Executar agora", - "cancelRun": "Cancelar execução", - "runHistory": "Histórico de execuções", - "noRuns": "Ainda não há execuções", - "allFolders": "Todas as pastas", - "filterAll": "Todos", - "noMatches": "Nenhuma automação correspondente", - "viewConversation": "Ver conversa", - "lastRun": "Última execução", - "never": "Nunca", - "running": "Em execução", - "deleteTitle": "Excluir automação?", - "deleteDescription": "Isso remove a automação e seu agendamento. O histórico é mantido.", - "statusRunning": "Em execução", - "statusSucceeded": "Concluída", - "statusFailed": "Falhou", - "statusCancelled": "Cancelada", - "statusSkipped": "Ignorada", - "errorName": "O nome é obrigatório", - "errorPrompt": "A instrução é obrigatória", - "errorCron": "Automações agendadas exigem uma expressão cron", - "errorFolder": "Selecione uma pasta do espaço de trabalho", - "presetHourly": "A cada hora", - "presetDaily": "Diariamente 9h", - "presetWeekdays": "Dias úteis 9h", - "presetCustom": "Personalizado", - "probing": "Carregando opções…", - "retry": "Tentar novamente", - "configNone": "Este agente não tem opções configuráveis", - "inherit": "Padrão do agente", - "mode": "Modo", - "config": "Configuração", - "branchPlaceholder": "(branch padrão)", - "selectHint": "Selecione uma automação para ver os detalhes", - "refresh": "Atualizar", - "onboardTitle": "Automatize tarefas rotineiras do agente", - "onboardHint": "Agende um agente para revisar código, atualizar dependências ou triar problemas, periodicamente ou sob demanda.", - "headerSubtitle": "Tarefas do agente agendadas e sob demanda", - "startFromTemplate": "Começar com um modelo", - "blankTitle": "Automação em branco", - "blankDesc": "Configure uma tarefa do agente do zero.", - "backToTemplates": "Modelos", - "sectionSchedule": "Agendamento e destino", - "sectionTarget": "Destino", - "sectionAction": "Ação", - "actionLaunchSession": "Executar sessão", - "actionEnqueueTask": "Enfileirar tarefa", - "actionEnqueueTaskHint": "Cada disparo adiciona uma tarefa pendente, com o nome desta automação, às tarefas a fazer da pasta; o motor de tarefas a executa conforme as configurações do quadro.", - "sectionPrompt": "Prompt", - "nextIn": "Próxima em {rel}", - "manual": "Manual", - "schedEveryMinutes": "A cada {n} minutos", - "schedHourly": "De hora em hora", - "schedDaily": "Todos os dias às {time}", - "schedWeekdays": "Dias úteis às {time}", - "schedWeekly": "Toda {day} às {time}", - "schedMonthly": "Mensalmente no dia {day} às {time}", - "dow0": "domingo", - "dow1": "segunda-feira", - "dow2": "terça-feira", - "dow3": "quarta-feira", - "dow4": "quinta-feira", - "dow5": "sexta-feira", - "dow6": "sábado", - "tplCodeReviewTitle": "Revisão de código", - "tplCodeReviewDesc": "Revisa as alterações recentes em busca de bugs, regressões e problemas de qualidade.", - "tplDependencyUpdatesTitle": "Atualização de dependências", - "tplDependencyUpdatesDesc": "Encontra dependências desatualizadas e propõe atualizações seguras.", - "tplTestCoverageTitle": "Cobertura de testes", - "tplTestCoverageDesc": "Encontra caminhos de código sem testes e adiciona os testes que faltam.", - "tplTodoSweepTitle": "Varredura de TODO", - "tplTodoSweepDesc": "Reúne comentários TODO e FIXME e os tria por prioridade.", - "tplCiTriageTitle": "Triagem de CI", - "tplCiTriageDesc": "Investiga verificações que falharam recentemente e propõe correções.", - "tplReleaseNotesTitle": "Notas de versão", - "tplReleaseNotesDesc": "Resume as alterações desde a última versão em um changelog.", - "tplSecurityAuditTitle": "Auditoria de segurança", - "tplSecurityAuditDesc": "Verifica vulnerabilidades e padrões de risco e relata as constatações.", - "enable": "Ativar", - "disable": "Desativar", - "moreActions": "Mais ações", - "statusDisabled": "Desativada", - "cronBuilderTitle": "Gerador de agendamento", - "cronFreqLabel": "Frequência", - "cronFreqMinutes": "A cada N minutos", - "cronFreqHourly": "De hora em hora", - "cronFreqDaily": "Diário", - "cronFreqWeekdays": "Dias úteis", - "cronFreqWeekly": "Semanal", - "cronFreqMonthly": "Mensal", - "cronFreqCustom": "Personalizado", - "cronEveryLabel": "Intervalo (minutos)", - "cronTimeLabel": "Hora", - "cronHourLabel": "Hora", - "cronMinuteLabel": "Minuto", - "cronDowLabel": "Dia da semana", - "cronDomLabel": "Dia do mês", - "cronApply": "Aplicar", - "cronPreviewLabel": "Pré-visualização", - "cronOpenBuilder": "Abrir o gerador de agendamento", - "branchDefault": "Branch padrão", - "branchUseCustom": "Usar \"{query}\"", - "branchLocal": "Local", - "branchRemote": "Remoto", - "branchSearchPlaceholder": "Pesquisar branches…", - "branchNone": "Sem branches" - }, - "Tasks": { - "title": "Tarefas a fazer", - "new": "Nova tarefa", - "empty": "Ainda não há tarefas", - "emptyHint": "Adicione uma pendência e execute — o agente trabalha num worktree isolado e você revisa e faz merge do resultado.", - "emptyColTodo": "Ainda não há tarefas a fazer", - "emptyColInProgress": "Nada em andamento", - "emptyColAttention": "Nada aguardando você", - "emptyColDone": "Ainda não há concluídas", - "allFolders": "Todas as pastas", - "showCanceled": "Mostrar canceladas", - "showArchived": "Mostrar arquivadas", - "filter": "Filtrar", - "viewSwitchToBoard": "Mudar para a visualização de quadro", - "viewSwitchToList": "Mudar para a visualização de lista", - "statusFilter": "Estado", - "statusFilterAll": "Todos os estados", - "listEmpty": "Nenhuma tarefa corresponde aos filtros atuais", - "listColStatus": "Estado", - "listColTask": "Tarefa", - "listColLocation": "Localização", - "listColChanges": "Alterações", - "listColUpdated": "Atualizado", - "colTodo": "A fazer", - "colInProgress": "Em andamento", - "colAttention": "Aguardando você", - "colDone": "Concluídas", - "statusTodo": "A fazer", - "statusQueued": "Na fila", - "statusPreparing": "Preparando", - "statusRunning": "Em execução", - "statusAwaitingInput": "Aguardando entrada", - "statusReview": "Para revisar", - "statusMerging": "Fazendo merge", - "statusDone": "Concluída", - "statusFailed": "Falhou", - "statusCanceled": "Cancelada", - "statusInterrupted": "Interrompida", - "badgeCleanupFailed": "Limpeza falhou", - "badgeWorktreeKept": "Worktree mantido", - "badgeWorktreeRemoved": "Worktree removido", - "filesChanged": "{count} arquivos", - "actionStart": "Iniciar", - "actionSchedule": "Agendar", - "actionCancel": "Cancelar", - "actionRetry": "Tentar novamente", - "actionRequeue": "Reenfileirar", - "actionViewSession": "Ver conversa", - "actionEdit": "Editar", - "actionDelete": "Excluir", - "actionRetryCleanup": "Repetir limpeza", - "actionMerge": "Merge", - "actionUnqueueMerge": "Sair da fila de merge", - "actionEditQueuedMerge": "Editar merge na fila", - "badgeMergeQueued": "Na fila para merge", - "badgeMergeQueuedRank": "Na fila para merge · n.º {rank}", - "badgeMergeQueuedHint": "Aguardando o merge em andamento do projeto terminar; este começa sozinho.", - "actionComplete": "Concluir", - "actionAbandon": "Abandonar", - "cancelTitle": "Cancelar tarefa?", - "cancelDescription": "A tarefa passa para Cancelada. O worktree é mantido e você pode reenfileirá-la depois.", - "cancelReasonLabel": "Motivo (opcional)", - "cancelReasonPlaceholder": "Ex.: abordagem errada — vou reescrever a descrição", - "cancelKeep": "Deixa pra lá", - "cancelSubmit": "Cancelar tarefa", - "restartTitleRetry": "Tentar a tarefa novamente", - "restartTitleRequeue": "Reenfileirar a tarefa", - "restartDescription": "Você pode adicionar uma nota (opcional): ela chega ao prompt da próxima execução.", - "scheduleTitle": "Agendar tarefa", - "scheduleDescription": "A tarefa continua em A fazer e inicia sozinha no horário escolhido. O limite de concorrência da pasta continua valendo.", - "scheduleDateLabel": "Data", - "schedulePickDate": "Escolher data", - "scheduleTimeLabel": "Hora", - "schedulePreview": "Executa em {time}", - "schedulePastHint": "Esse horário já passou: a tarefa começa assim que você salvar.", - "scheduleInAnHour": "Em 1 hora", - "scheduleInThreeHours": "Em 3 horas", - "scheduleTomorrow": "Amanhã 9:00", - "scheduleClear": "Remover agendamento", - "scheduleBadge": "Início agendado para {time}", - "toastScheduled": "Agendada para {time}", - "toastScheduleCleared": "Agendamento removido", - "actionFollowUp": "Continuar", - "actionAddNote": "Adicionar observação", - "followUpSubmit": "Enviar", - "followUpIntentRevise": "Corrigir", - "followUpIntentContinue": "Prosseguir", - "followUpIntentQuestion": "Perguntar", - "followUpIntentVerify": "Revisar", - "followUpPlaceholderRevise": "O que o agente deve mudar? Ele continua na mesma sessão.", - "followUpPlaceholderContinue": "E agora? O que já foi feito permanece.", - "followUpPlaceholderQuestion": "O que você quer saber? O agente responde sem mexer em nenhum arquivo.", - "followUpPlaceholderVerify": "Opcional: algo que deva revisar com atenção?", - "followUpPlaceholderRetry": "Opcional: o que deve ser feito diferente? Ex.: rodar pnpm install antes", - "followUpPlaceholderRequeue": "Opcional: por que você cancelou e o que deve mudar desta vez?", - "actionArchive": "Arquivar", - "actionUnarchive": "Desarquivar", - "archiveAllDone": "Arquivar tudo", - "dropToStart": "Solte para iniciar", - "errorView": "Ver", - "notifyReview": "Pronto para revisão: {title}", - "notifyFailed": "A tarefa falhou: {title}", - "createFromMessage": "Criar tarefa a partir da mensagem", - "detailTokens": "Total de tokens", - "editorTitleNew": "Nova tarefa", - "editorTitleEdit": "Editar tarefa", - "templates": "Modelos", - "templatesEmpty": "Ainda não há modelos.", - "templateSaveCurrent": "Salvar como modelo", - "templateDelete": "Excluir modelo", - "transcriptTitle": "Conversa da tarefa", - "transcriptDescription": "Visão ao vivo somente leitura da sessão do agente da tarefa.", - "phaseWork": "Execução", - "phaseRetry": "Nova tentativa", - "phaseReturn": "Continuação", - "phaseMerge": "Merge", - "titleLabel": "Título", - "titlePlaceholder": "O que precisa ser feito?", - "promptLabel": "Descrição da tarefa", - "promptPlaceholder": "Descreva a tarefa para o agente — @ para referenciar arquivos, / para comandos", - "folderPlaceholder": "Selecione uma pasta", - "agentInheritedHint": "Herdado das configurações de tarefas; altere para personalizar esta tarefa", - "agentOverrideReset": "Voltar a herdar", - "sectionTarget": "Destino", - "errorTitle": "O título é obrigatório", - "errorPrompt": "A descrição é obrigatória", - "errorFolder": "Selecione uma pasta", - "save": "Salvar", - "cancel": "Cancelar", - "mergeTitle": "Merge da tarefa", - "mergeQueuedTitle": "Merge na fila", - "mergeQueueHint": "Outra tarefa deste projeto está sendo mesclada agora. Esta entra na fila e começa sozinha assim que a outra terminar.", - "mergeQueueUpdateHint": "Esta tarefa já está esperando para mesclar. Enviar atualiza o merge e mantém o lugar na fila.", - "mergeDescription": "Fazer merge de {branch} em {base}. Alterações não commitadas no worktree são commitadas antes.", - "mergeMessage": "Mensagem do commit", - "mergeMessagePlaceholder": "ex.: feat: add login validation", - "mergeAutoMessage": "Deixar o agente escrever a mensagem de commit", - "strategySquash": "Combinar em um único commit", - "strategySquashHint": "Todas as mudanças da tarefa entram na branch principal como um único registro — histórico mais limpo.", - "strategyMerge": "Manter o histórico completo", - "strategyMergeHint": "Cada commit feito durante a tarefa é mantido, mais um registro de merge — cada etapa fica rastreável.", - "mergeDeleteWorktree": "Excluir o worktree após o merge", - "mergeSubmit": "Merge", - "mergeSubmitQueue": "Adicionar à fila", - "mergeQueuedToast": "Adicionada à fila de merge — começa assim que o merge atual terminar.", - "completeTitle": "Concluir tarefa", - "completeDescription": "Esta tarefa não alterou nenhum arquivo, então não há nada para fazer merge: ela é marcada como concluída.", - "completeDescriptionNoWorktree": "O worktree desta tarefa foi removido, então não é mais possível fazer merge: ela é marcada como concluída. Um branch de trabalho que ainda tenha commits não mesclados é mantido.", - "completeDeleteWorktree": "Excluir o worktree ao concluir", - "completeSubmit": "Concluir", - "settingsTitle": "Configurações de tarefas", - "settingsDescription": "Padrões para tarefas em {folder}.", - "settingsScope": "Escopo", - "settingsScopeGlobal": "Todas as pastas (padrões globais)", - "settingsScopeGlobalHint": "Pastas sem configurações próprias usam estes padrões globais.", - "settingsSource": "Origem da configuração", - "settingsSourceGlobal": "Padrões globais", - "settingsSourceCustom": "Personalizada", - "settingsSourceGlobalFollow": "Segue as configurações globais de tarefas — mudanças lá se aplicam aqui automaticamente.", - "settingsSourceCustomHint": "Salva configurações próprias desta pasta, que deixa de seguir os padrões globais.", - "settingsAgent": "Agente padrão", - "settingsMaxConcurrent": "Máx. de tarefas simultâneas", - "settingsMaxConcurrentHint": "0 = ilimitado", - "settingsAutoProcess": "Processar automaticamente", - "settingsAutoProcessHint": "As tarefas pendentes iniciam sozinhas, até o limite de concorrência.", - "settingsMergeStrategy": "Estratégia de merge padrão", - "settingsMergeStrategyHint": "Como as mudanças da tarefa são registradas no histórico da branch ao mesclar.", - "settingsAutoMerge": "Merge automático", - "settingsAutoMergeHint": "Uma tarefa que chega à revisão com mudanças a integrar recebe merge como se você clicasse em Merge: o agente escreve a mensagem de commit e o worktree segue o padrão abaixo. Se a pré-verificação falhar ou um merge tiver falhado, a tarefa fica esperando por você.", - "settingsDeleteWorktree": "Excluir o worktree após o merge", - "settingsDeleteWorktreeHint": "Marca a opção por padrão no diálogo de merge; ainda dá para alterar lá.", - "settingsWorktreeRoot": "Local do worktree", - "settingsWorktreeRootHint": "Diretório onde os worktrees das novas tarefas são criados, um por tarefa. Deixe vazio para criá-los ao lado da pasta do projeto; \"~\" é a sua pasta pessoal e um caminho relativo é resolvido a partir da pasta do projeto.", - "settingsWorktreeRootPlaceholder": "~/codeg-worktrees", - "settingsWorktreeRootBrowse": "Escolher o diretório dos worktrees", - "settingsPreflight": "Comando de pré-verificação", - "settingsPreflightHint": "Executa no worktree quando uma tarefa chega à revisão.", - "settingsPreflightCustomPlaceholder": "pnpm test", - "settingsInitCommand": "Comando de inicialização do worktree", - "settingsInitCommandHint": "Executado em um worktree recém-criado antes de o agente iniciar.", - "settingsInitCommandPlaceholder": "pnpm install", - "settingsTabGeneral": "Geral", - "settingsTabMerge": "Merge", - "settingsTabWorktree": "Worktree", - "settingsTabPrompts": "Prompts", - "settingsPromptsIntro": "Cada etapa já envia seu próprio prompt embutido: a tarefa, as regras do worktree e, no merge, os passos exatos do git. O que você escrever aqui é anexado ao final como instruções extras: refina esses textos embutidos, mas nunca os substitui.", - "settingsPromptStageAll": "Todas as fases", - "settingsPromptPlaceholderAll": "ex.: Siga as convenções do AGENTS.md; mantenha o resumo final em duas frases", - "settingsPromptPlaceholderWork": "ex.: Leia primeiro os testes relacionados; faça commits pequenos ao longo do trabalho", - "settingsPromptPlaceholderRetry": "ex.: Verifique o que já está commitado antes de continuar; não refaça o que está pronto", - "settingsPromptPlaceholderReturn": "Ex.: Trate cada ponto levantado; não refatore nada não relacionado", - "settingsPromptPlaceholderMerge": "ex.: Escreva a mensagem do commit de integração em português; aponte os conflitos resolvidos à mão", - "settingsPromptHintAll": "Acrescentado a todos os prompts que o agente recebe, inclusive no merge.", - "settingsPromptHintWork": "Acrescentado quando uma tarefa é executada pela primeira vez.", - "settingsPromptHintRetry": "Acrescentado ao retomar uma tarefa interrompida ou com falha.", - "settingsPromptHintReturn": "Anexado quando você continua uma tarefa em revisão (corrigir, ampliar, revisar).", - "settingsPromptHintMerge": "Acrescentado quando o agente integra a tarefa no branch base.", - "preflightPassed": "{name} aprovado", - "preflightFailed": "{name} falhou", - "preflightRunning": "{name} em execução…", - "detailDescription": "Detalhes da tarefa", - "detailSummary": "Resultado", - "detailFiles": "Arquivos alterados", - "detailDiffAll": "Ver diff completo", - "detailDiffAllTitle": "Diff completo", - "detailNoChanges": "Ainda não há mudanças em relação à base", - "detailTimeline": "Progresso", - "detailTimelineEmpty": "Nenhuma atividade ainda", - "showMore": "Ver mais", - "showLess": "Ver menos", - "detailInfo": "Detalhes", - "detailBranch": "Branch", - "detailMergeCommit": "Commit de merge", - "detailChanges": "Alterações", - "detailScheduled": "Início agendado", - "detailCreated": "Criada", - "detailStarted": "Iniciada", - "detailFinished": "Concluída", - "diffLoading": "Carregando diff…", - "deleteConfirmTitle": "Excluir tarefa?", - "deleteConfirmBody": "“{title}” será removida do quadro. Uma execução ativa é cancelada antes.", - "deleteWithWorktree": "Excluir também o worktree", - "eventCreated": "Criada", - "eventStatusChanged": "Mudança de status", - "eventConfigEffective": "Configuração de execução", - "eventInitCommand": "Comando de inicialização", - "eventAgentProgress": "Progresso do agente", - "eventAgentVerdict": "Veredito do agente", - "eventMergeAttempt": "Merge iniciado", - "eventMergeQueued": "Na fila para merge", - "eventMergeConflict": "Conflito de merge", - "eventPreflight": "Pré-verificação", - "eventCleanupFailed": "Falha na limpeza do worktree", - "eventResumeFallback": "Retomada falhou; nova sessão usada", - "eventUserAction": "Ação do usuário", - "eventDiffStat": "Resumo das mudanças" - }, - "CustomSkillsSettings": { - "loading": "Carregando habilidades personalizadas…", - "category": "Personalizadas", - "searchPlaceholder": "Pesquisar habilidades personalizadas por nome, ID ou descrição", - "states": { - "not_linked": "Não ativada", - "linked_to_codeg": "Ativada", - "linked_elsewhere": "Vinculada em outro lugar", - "blocked_by_real_directory": "Bloqueada por uma pasta real", - "broken": "Link quebrado" - }, - "actions": { - "new": "Nova", - "import": "Importar", - "importFromAgent": "Importar de um agente", - "cancel": "Cancelar", - "save": "Salvar" - }, - "rowMenu": { - "edit": "Editar", - "duplicate": "Duplicar", - "delete": "Excluir" - }, - "bulk": { - "delete": "Excluir selecionadas" - }, - "editor": { - "createTitle": "Nova habilidade personalizada", - "editTitle": "Editar habilidade personalizada", - "description": "As habilidades personalizadas ficam no armazenamento compartilhado (~/.codeg/skills) e podem ser ativadas para qualquer agente.", - "idLabel": "ID da habilidade", - "idPlaceholder": "ex.: my-workflow", - "contentLabel": "SKILL.md", - "contentPlaceholder": "Escreva aqui o SKILL.md da habilidade…", - "preview": "Pré-visualização", - "edit": "Editar", - "emptyBody": "Ainda sem conteúdo." - }, - "duplicate": { - "title": "Duplicar habilidade", - "description": "Criar uma cópia de \"{id}\" com um novo ID.", - "newIdPlaceholder": "Novo ID da habilidade", - "confirm": "Duplicar" - }, - "import": { - "title": "Escolha uma pasta de habilidade para importar" - }, - "importFromAgent": { - "title": "Importar habilidades de um agente", - "description": "Copie as habilidades próprias de um agente para o repositório compartilhado e ative-as em qualquer agente.", - "agentLabel": "Agente", - "agentPlaceholder": "Selecione um agente", - "selectAll": "Selecionar tudo ({count})", - "loading": "Carregando as habilidades do agente…", - "unsupported": "Este agente não expõe um diretório de habilidades.", - "empty": "Este agente não tem habilidades para importar.", - "alreadyInLibrary": "Na biblioteca", - "confirm": "Importar selecionadas ({count})" - }, - "delete": { - "title": "Excluir habilidades personalizadas?", - "body": "Isto remove {count} habilidade(s) personalizada(s) do armazenamento central e as desvincula de todos os agentes. Não pode ser desfeito.", - "confirm": "Excluir" - }, - "toasts": { - "loadFailed": "Falha ao carregar a habilidade", - "idRequired": "Informe um ID de habilidade", - "created": "Habilidade personalizada criada", - "updated": "Habilidade personalizada atualizada", - "saveFailed": "Falha ao salvar a habilidade", - "imported": "Habilidade importada", - "importFailed": "Falha ao importar a habilidade", - "duplicated": "Habilidade duplicada", - "duplicateFailed": "Falha ao duplicar a habilidade", - "deleted": "{count} habilidade(s) excluída(s)", - "deletedPartial": "{ok} excluída(s), {failed} com falha", - "deleteFailed": "Falha ao excluir as habilidades", - "importedFromAgent": "{count} habilidade(s) importada(s)", - "importedFromAgentPartial": "{ok} importada(s), {failed} com falha", - "importFromAgentAllSkipped": "Nada a importar — {count} já na biblioteca", - "importFromAgentFailed": "Falha ao importar do agente" - } - }, - "CodexModelEditor": { - "customizedNotice": "Você personalizou a lista de modelos, então agora o codeg gerencia toda a tabela de modelos do codex. Os modelos oficiais que o codex adicionar depois não aparecerão automaticamente — clique no botão atualizar abaixo e salve novamente para sincronizá-los. Limpe suas personalizações para que o codex volte a atualizar automaticamente.", - "officialsTitle": "Modelos oficiais", - "officialsHint": "Incluídos automaticamente do codex que você inicia; remova os que não quiser.", - "officialsEmpty": "Nenhum modelo oficial disponível.", - "refresh": "Atualizar do codex", - "readdOfficial": "Readicionar oficial", - "customsTitle": "Modelos personalizados", - "customsEmpty": "Ainda não há modelos personalizados.", - "addCustom": "Adicionar personalizado", - "slugPlaceholder": "id do modelo (slug)", - "displayNamePlaceholder": "Nome de exibição", - "contextWindow": "Contexto", - "makeDefault": "Definir como padrão", - "defaultHint": "Modelo padrão", - "remove": "Remover", - "advanced": "Avançado", - "baseTemplate": "Modelo base", - "baseTemplateHint": "Modelo oficial do qual clonar os campos obrigatórios (prompt do sistema, ferramentas, limites).", - "groupBehavior": "Comportamento e recursos", - "fieldReasoningLevel": "Raciocínio padrão", - "fieldReasoningSummary": "Resumo do raciocínio", - "fieldVerbosity": "Verbosidade", - "fieldShellType": "Tipo de shell", - "fieldApplyPatch": "Ferramenta apply-patch", - "fieldReasoningSummaries": "Resumos de raciocínio", - "fieldSupportVerbosity": "Controle de verbosidade", - "fieldParallelToolCalls": "Chamadas de ferramentas em paralelo", - "fieldSearchTool": "Ferramenta de busca na web", - "optNone": "Nenhum", - "groupInstructions": "Descrição e prompt do sistema", - "fieldDescription": "Descrição", - "baseInstructions": "Prompt do sistema (base_instructions)" - }, - "DiagnosticsSettings": { - "title": "Diagnóstico do ambiente", - "description": "Verifica como este app resolve a CLI do agente no próprio processo, que pode diferir do seu terminal.", - "loading": "Executando diagnóstico…", - "error": "Falha no diagnóstico", - "rerun": "Executar novamente", - "copyAll": "Copiar tudo", - "copied": "Diagnóstico copiado para a área de transferência", - "button": "Diagnosticar", - "verdict": { - "ok": "O ambiente parece saudável. Se ainda aparecer como não instalado, reinicie o app completamente para atualizar o cache do prefixo.", - "node_missing": "Node.js não foi encontrado no PATH do app.", - "npm_missing": "npm não foi encontrado no PATH do app.", - "not_installed": "Este agente não parece estar instalado.", - "installed_but_unresolved": "Consta como instalado, mas o app não consegue localizar o executável.", - "user_prefix_not_on_path": "Instalado no prefixo de fallback (~/.codeg/npm-global), que não está no PATH do app. Reinicie o app completamente e tente novamente.", - "homebrew_bin_not_on_path": "Instalado no bin do Homebrew, que não está no PATH do app (divisão de keg no Apple Silicon).", - "terminal_only_path": "O comando é resolvido no seu terminal, mas não no app: uma diferença de PATH da GUI. Inicie o app por um terminal ou reinstale nas Configurações de agentes.", - "npm_prefix_timeout": "npm prefix -g foi muito lento (mais de 1,5 s), então a detecção de fallback foi ignorada. Reinicie o app e tente novamente.", - "node_too_old": "Seu Node.js ativo é mais antigo do que este agente requer. Atualize o Node.js.", - "adapter_missing_native_present": "A sua CLI do {agent} está instalada, mas o Codeg inicia um pacote adaptador ACP separado — e esse ainda não está. Instale-o nas configurações de agentes: ele não mexe na sua CLI e compartilha o mesmo login.", - "adapter_missing": "O Codeg inicia um pacote adaptador ACP separado para o {agent}, e ele ainda não está instalado. Instale-o nas configurações de agentes — instalar só a CLI do fornecedor não basta." - } - }, - "TokenUsage": { - "title": "Uso de tokens", - "rangeLabel": "Período", - "range7d": "7 dias", - "range30d": "30 dias", - "range90d": "90 dias", - "rangeThisMonth": "Este mês", - "rangeThisYear": "Este ano", - "rangeAll": "Tudo", - "rangeCustom": "Personalizado", - "moreRanges": "Mais", - "customRangePick": "Escolher um período", - "bucketLabel": "Agrupar por", - "bucketDay": "Dia", - "bucketWeek": "Semana", - "bucketMonth": "Mês", - "bucketUnitDay": "Dia", - "bucketUnitWeek": "Semana", - "bucketUnitMonth": "Mês", - "folderFilter": "Pastas", - "allFolders": "Todas as pastas", - "agentFilter": "Agentes", - "allAgents": "Todos os agentes", - "modelFilter": "Modelos", - "allModels": "Todos os modelos", - "searchPlaceholder": "Pesquisar…", - "noMatches": "Nenhum resultado", - "clearFilter": "Limpar seleção", - "resetFilters": "Limpar filtros", - "refresh": "Atualizar", - "rebuild": "Reconstruir tudo", - "rebuildHint": "Descarta o que já foi contabilizado e relê todas as transcrições. Útil se uma sessão cresceu fora do codeg.", - "syncing": "Contando sessões…", - "syncProgress": "{done} / {total}", - "syncDone": "{synced} sessões contabilizadas", - "syncFailed": "Não foi possível ler algumas sessões", - "syncBusy": "Já existe uma atualização em andamento", - "lastSynced": "Atualizado {time}", - "lastSyncedNever": "Nunca atualizado", - "tileTotal": "Tokens totais", - "tileSessions": "Sessões", - "tileTurns": "Turnos", - "tileActiveDays": "Dias ativos", - "tileGenTime": "Tempo de geração", - "vsPrevious": "vs. período anterior", - "deltaNew": "novo", - "trendTitle": "Uso ao longo do tempo", - "trendEmpty": "Sem uso neste período", - "trendTurns": "Turnos", - "trendSessions": "Sessões", - "compositionTitle": "Para onde foram os tokens", - "compositionHint": "Entrada é o que você enviou, saída é o que o modelo escreveu e leituras de cache são contexto que não custou preço cheio.", - "compositionNote": "Reenviar esses acertos de cache a preço cheio custaria mais {value}.", - "inputTokens": "Entrada", - "outputTokens": "Saída", - "cacheWrite": "Escrita de cache", - "cacheRead": "Leitura de cache", - "freshTokens": "Cômputo novo", - "cacheHitCaption": "Acerto de cache", - "cacheHeroTitleHigh": "A maior parte do contexto não precisou ser reenviada", - "cacheHeroTitleLow": "A maior parte do contexto ainda é calculada a preço cheio", - "cacheHeroDesc": "O cache carregou {cached} de contexto; só {fresh} foi de fato calculado de novo no período.", - "cacheSavedSuffix": "Isso poupou reenviar o equivalente a {saved}.", - "avgPerSession": "Média por sessão", - "avgTurnsPerSession": "{count} turnos por sessão em média", - "avgPerActiveDay": "Média por dia ativo", - "peakBucket": "{bucket} de pico", - "peakHour": "Hora de pico", - "daysValue": "{count} dias", - "idleDays": "Dias parados", - "byFolderTitle": "Por pasta", - "byAgentTitle": "Por agente", - "byModelTitle": "Por modelo", - "distributionTitle": "Distribuição de uso", - "distributionHint": "Sessões e tokens agrupados pela dimensão escolhida — clique numa linha para filtrar.", - "otherLabel": "Outros", - "unknownModel": "Modelo não registrado", - "emptyBreakdown": "Nada registrado ainda", - "sessionsCount": "{count} sessões", - "heatmapTitle": "Quando você programa", - "heatmapHint": "Tokens por dia da semana e hora local.", - "heatmapPeakHint": "Mais denso por volta das {hour}:00.", - "less": "Menos", - "more": "Mais", - "heatmapCell": "{weekday} {hour}:00 — {value} tokens", - "weekMon": "Seg", - "weekTue": "Ter", - "weekWed": "Qua", - "weekThu": "Qui", - "weekFri": "Sex", - "weekSat": "Sáb", - "weekSun": "Dom", - "topSessionsTitle": "Sessões mais pesadas", - "untitledSession": "Sessão sem título", - "topSessionsEmpty": "Sem sessões neste período", - "streakLongest": "Maior sequência", - "streakLongestDays": "Maior sequência: {count} dias", - "share": "Compartilhar", - "moreActions": "Mais ações", - "shareDialogTitle": "Compartilhe seu cartão de uso", - "shareDialogHint": "Um retrato do período e dos filtros que você está vendo.", - "shareSave": "Salvar imagem", - "shareCopy": "Copiar imagem", - "shareCopied": "Copiado para a área de transferência", - "shareSaved": "Imagem salva", - "shareFailed": "Não foi possível criar a imagem", - "shareRendering": "Gerando…", - "cardHeading": "Minhas estatísticas de código com IA", - "cardRangeAll": "Todo o período", - "cardTotalLabel": "Tokens usados", - "cardFooter": "Feito com codeg", - "cardTopModels": "Principais modelos", - "cardTopProjects": "Principais projetos", - "archetypeNightOwl": "Coruja noturna", - "archetypeNightOwlDesc": "{percent}% dos seus tokens queimam depois do anoitecer.", - "archetypeEarlyBird": "Madrugador", - "archetypeEarlyBirdDesc": "{percent}% dos seus tokens acontecem antes das 9h.", - "archetypeWeekendWarrior": "Guerreiro de fim de semana", - "archetypeWeekendWarriorDesc": "{percent}% dos seus tokens acontecem no fim de semana.", - "archetypeCacheMaster": "Mestre do cache", - "archetypeCacheMasterDesc": "{percent}% do seu contexto veio do cache.", - "archetypeMarathoner": "Maratonista", - "archetypeMarathonerDesc": "{days} dias programando sem parar.", - "archetypePolyglot": "Polivalente", - "archetypePolyglotDesc": "{count} agentes em uso pesado.", - "archetypeLaserFocus": "Foco total", - "archetypeLaserFocusDesc": "{percent}% dos seus tokens foram para um único projeto.", - "archetypeDeepDiver": "Mergulhador", - "archetypeDeepDiverDesc": "{averageK}K tokens numa sessão média.", - "archetypeSteady": "Construtor constante", - "archetypeSteadyDesc": "{days} dias entregando.", - "emptyTitle": "Nada contabilizado ainda", - "emptyHint": "O codeg lê os tokens direto da transcrição de cada agente. Atualize para contabilizar o que já existe nesta máquina.", - "emptyAction": "Contabilizar minhas sessões", - "loadFailed": "Não foi possível carregar o uso", - "truncatedNotice": "Este período é muito amplo — os números cobrem apenas o trecho mais recente." - } -} +{ + "Language": { + "followSystem": "Seguir o sistema", + "english": "Inglês", + "simplifiedChinese": "Chinês simplificado", + "traditionalChinese": "Chinês tradicional", + "japanese": "Japonês", + "korean": "Coreano", + "spanish": "Espanhol", + "german": "Alemão", + "french": "Francês", + "portuguese": "Português", + "arabic": "Árabe" + }, + "GitCredentialDialog": { + "title": "Autenticação necessária", + "description": "O servidor remoto requer credenciais. Insira seu nome de usuário e senha (ou token de acesso pessoal).", + "username": "Nome de usuário", + "usernamePlaceholder": "Nome de usuário ou e-mail", + "password": "Senha / Token", + "passwordPlaceholder": "Senha ou token de acesso pessoal", + "passwordHint": "Insira o nome de usuário e a senha do servidor.", + "cancel": "Cancelar", + "authenticate": "Autenticar", + "authenticating": "Autenticando...", + "invalidCredentials": "Credenciais inválidas. Tente novamente.", + "saveCredentials": "Salvar credenciais para operações futuras", + "githubTitle": "Autenticação do GitHub", + "githubDescription": "Insira um token de acesso pessoal para se conectar ao GitHub. O token será validado e salvo automaticamente.", + "githubToken": "Token de acesso pessoal", + "githubTokenPlaceholder": "ghp_xxxxxxxxxxxx", + "githubTokenHint": "Gere um token em GitHub → Settings → Developer settings → Personal access tokens.", + "githubAuthenticate": "Validar e conectar", + "generateToken": "Gerar token" + }, + "SettingsShell": { + "title": "Configurações", + "preferences": "Preferências", + "nav": { + "general": "Geral", + "appearance": "Aparência", + "agents": "Agentes", + "mcp": "MCP", + "skills": "Skills", + "shortcuts": "Atalhos", + "version_control": "Controle de versão", + "system": "Sistema", + "chat_channels": "Canais de chat", + "web_service": "Serviço Web", + "model_providers": "Provedores de Modelos", + "experts": "Especialistas", + "science": "Ciência", + "office_tools": "Ferramentas de escritório", + "skill_packs": "Pacotes de habilidades", + "quick_messages": "Mensagens rápidas", + "logs": "Registros de execução" + } + }, + "AppearanceSettings": { + "sectionTitle": "Aparência do tema", + "sectionDescription": "Escolha claro, escuro ou seguir o sistema. As configurações são salvas automaticamente.", + "themeMode": "Modo de tema", + "placeholder": "Selecionar modo de tema", + "system": "Seguir o sistema", + "light": "Claro", + "dark": "Escuro", + "currentTheme": "Tema efetivo atual: {theme}", + "resolvedTheme": { + "light": "Claro", + "dark": "Escuro", + "unknown": "--" + }, + "themeColor": { + "sectionTitle": "Cor do tema", + "sectionDescription": "Escolha uma paleta de cores para acentos, botões e destaques.", + "current": "Cor atual: {color}", + "options": { + "neutral": "Neutral", + "zinc": "Zinc", + "slate": "Slate", + "stone": "Stone", + "gray": "Gray", + "red": "Red", + "rose": "Rose", + "orange": "Orange", + "green": "Green", + "blue": "Blue", + "yellow": "Yellow", + "violet": "Violet" + } + }, + "customStyle": { + "sectionTitle": "Estilo personalizado", + "sectionDescription": "Ajuste as cores do tema atual ou injete o seu próprio CSS. As substituições ficam sobre a predefinição base, por isso permanecem ao trocar de predefinição.", + "summarySuspended": "Suspenso", + "summaryDefault": "Predefinição inalterada", + "summaryTokens": "{count, plural, one {# substituição} other {# substituições}}", + "summaryCss": "CSS personalizado", + "suspendedByShortcut": "O estilo personalizado está suspenso. Nada do que definir aqui terá efeito até retomá-lo.", + "suspendedBySafeParam": "Esta janela foi aberta no modo de aparência segura, por isso o estilo personalizado é ignorado aqui. As outras janelas não são afetadas.", + "resume": "Retomar estilo personalizado", + "enableTheme": "Ativar cores personalizadas", + "editingLight": "A editar os valores do modo claro. Mude a aplicação para o modo escuro para o definir em separado.", + "editingDark": "A editar os valores do modo escuro. Mude a aplicação para o modo claro para o definir em separado.", + "resetToken": "Repor o valor da predefinição", + "radius": "Raio dos cantos", + "radiusHint": "Toda a escala de raios, de sm a 4xl, deriva dele: um único cursor arredonda a aplicação inteira.", + "advanced": "Avançado (mais {count} variáveis)", + "enableCss": "Ativar CSS personalizado", + "cssRisk": "Funcionalidade avançada. O CSS personalizado substitui todos os estilos integrados e pode tornar a interface inutilizável.", + "editCss": "Editar CSS…", + "cssPresent": "{size} KB guardados", + "cssEmpty": "Ainda não há nada guardado", + "escapeHint": "Interface estragada? Prima {shortcut} para suspender todo o estilo personalizado, ou abra uma janela com o parâmetro safeStyle=1.", + "copyTheme": "Copiar JSON do tema", + "importTheme": "Importar tema…", + "clearTheme": "Limpar substituições", + "interopHint": "Os temas usam o formato registry:theme do shadcn, por isso pode colar aqui qualquer tema shadcn e usar os exportados em qualquer projeto shadcn.", + "importTitle": "Importar tema", + "importDescription": "Cole um item registry:theme do shadcn, um objeto light/dark simples ou um mapa plano de tokens.", + "readClipboard": "Ler área de transferência", + "importConfirm": "Importar", + "cancel": "Cancelar", + "apply": "Aplicar", + "toasts": { + "copied": "JSON do tema copiado", + "copyFailed": "Não foi possível copiar para a área de transferência", + "clipboardReadFailed": "Não foi possível ler a área de transferência, cole manualmente", + "importFailed": "Esse JSON não contém variáveis de tema utilizáveis", + "imported": "Tema importado" + }, + "css": { + "dialogTitle": "CSS personalizado", + "dialogDescription": "Aplica-se a todas as janelas do codeg. As alterações são pré-visualizadas ao vivo; carregue em Aplicar para guardar.", + "size": "{used} KB / {max} KB", + "ruleCount": "{count} regras", + "errorTooLarge": "Demasiado grande para guardar. Reduza abaixo do limite.", + "errorImportEscaped": "Uma regra @import sobreviveu à remoção (sintaxe com escapes). Remova-a para guardar.", + "warnNoRules": "Nenhuma regra foi analisada; verifique a sintaxe.", + "noticeImportsRemoved": "Regras @import removidas: {count}. Iriam obter folhas de estilo remotas.", + "noticeRemoteUrl": "Contém um url() remoto, que fará um pedido de rede ao ser aplicado.", + "noticePreviewSuspended": "O estilo personalizado está suspenso, por isso esta pré-visualização não é aplicada.", + "noticeDisabled": "O CSS personalizado está desativado. Pode pré-visualizar aqui, mas nada se aplica até o ativar.", + "hintTokens": "Dica: as cores que substituiu ficam disponíveis como var(--primary), var(--background), etc." + } + }, + "zoomLevel": { + "sectionTitle": "Zoom da janela", + "sectionDescription": "Dimensiona toda a interface. Aplica imediatamente e é salvo por dispositivo.", + "placeholder": "Selecione o nível de zoom", + "default": "Padrão", + "current": "Zoom atual: {zoom}%" + }, + "fonts": { + "sectionTitle": "Fontes", + "sectionDescription": "Escolha as fontes para a interface, o editor de código e o terminal. As fontes incluídas são carregadas sob demanda; selecione “Personalizada…” para usar qualquer fonte instalada no seu sistema.", + "interface": "Interface", + "editor": "Editor", + "terminal": "Terminal", + "groupSans": "Sem serifa", + "groupMono": "Monoespaçada", + "custom": "Personalizada…", + "customPlaceholder": "Nome da fonte, ex.: Fira Code", + "fontSize": "Tamanho da fonte", + "ligatures": "Ativar ligaduras", + "ligaturesUnavailable": "Esta fonte não tem ligaduras", + "wordWrap": "Ativar quebra de linha", + "terminalLigaturesHint": "As ligaduras do terminal aplicam-se apenas às fontes de programação incluídas.", + "preview": "Pré-visualização" + }, + "welcomePanel": { + "sectionTitle": "Área de seleção de modo", + "sectionDescription": "Os cartões de atalho «Desenvolvimento / Escritório» exibidos acima do campo de entrada na página de nova conversa.", + "showQuickActions": "Mostrar na página de nova conversa" + }, + "workspaceBackground": { + "sectionTitle": "Plano de fundo da área de trabalho", + "sectionDescription": "Mostra uma imagem atrás de toda a área de trabalho. A barra lateral e os painéis ficam translúcidos e foscos para deixar a imagem transparecer, e uma máscara mantém o texto legível.", + "enable": "Ativar imagem de fundo", + "image": "Imagem", + "chooseImage": "Escolher imagem", + "replaceImage": "Substituir imagem", + "removeImage": "Remover", + "fillMode": "Modo de preenchimento", + "fillModes": { + "cover": "Preencher", + "contain": "Ajustar", + "center": "Centralizar", + "tile": "Lado a lado" + }, + "maskOpacity": "Opacidade da máscara", + "maskOpacityHint": "Valores mais altos esmaecem a imagem em direção à cor de fundo do tema, melhorando o contraste do texto.", + "imageBlur": "Desfoque da imagem", + "panelOpacity": "Opacidade dos painéis", + "panelOpacityHint": "O quão opacos são a barra lateral, os painéis e as barras de abas. Mais baixo deixa a imagem transparecer mais.", + "errorTooLarge": "A imagem é muito grande (máx. 16 MB).", + "errorUploadFailed": "Falha ao definir a imagem de fundo." + } + }, + "SystemSettings": { + "loading": "Carregando...", + "sectionTitle": "Gerenciamento do sistema", + "sectionDescription": "Gerencie proxy de rede, atualizações do app e preferências de idioma.", + "proxyTitle": "Proxy de rede", + "proxyDescription": "Quando ativado, as solicitações de rede seguintes priorizam este proxy (incluindo chat ACP, instalação de agentes e operações remotas do Git).", + "loadFailed": "Falha ao carregar: {message}", + "enableProxy": "Ativar proxy do sistema", + "proxyAddress": "Endereço do proxy", + "proxyHint": "Suporta http(s)/socks5, exemplo: {example}. Só funciona quando o proxy do sistema está ativado.", + "save": "Salvar", + "saving": "Salvando...", + "proxyRequired": "A URL do proxy é obrigatória quando o proxy está ativado", + "saveSuccess": "As configurações de proxy do sistema foram salvas", + "saveFailed": "Falha ao salvar: {message}", + "languageTitle": "Idioma", + "languageDescription": "Defina o idioma do app. Ao seguir o idioma do sistema, idiomas não suportados voltam para inglês.", + "appLanguage": "Idioma do app", + "languageSaveSuccess": "As configurações de idioma foram salvas", + "languageSaveFailed": "Falha ao salvar as configurações de idioma: {message}", + "updateTitle": "Atualização do app", + "versionTitle": "Atualização de software", + "updateDescription": "Verifique versões mais novas na fonte de releases configurada e instale diretamente quando disponíveis.", + "currentVersion": "Versão atual", + "upgradableVersion": "Versão mais recente", + "none": "Nenhuma", + "lastChecked": "Última verificação: {time}", + "updateError": "Erro de atualização: {message}", + "checking": "Verificando...", + "checkUpdate": "Verificar atualizações", + "updating": "Instalando...", + "downloading": "Baixando...", + "upgradeTo": "Atualizar para v{version}", + "viewRelease": "Ver lançamento v{version}", + "foundUpdate": "Nova versão v{version} encontrada", + "alreadyLatest": "Você já está na versão mais recente", + "checkUpdateFailed": "Falha ao verificar atualizações: {message}", + "installSuccess": "Atualização instalada. Reiniciando o app.", + "installFailed": "Falha na atualização: {message}", + "upgradeSuccess": "Atualização concluída. Recarregando...", + "restartTimeout": "O servidor não voltou a tempo. Verifique os logs do contêiner ou do serviço.", + "restartingIn": "Reiniciando em {seconds} s...", + "waitingForServer": "Aguardando o servidor voltar...", + "restartToUpdate": "Reiniciar para atualizar", + "newVersionBadge": "Nova v{version}", + "updateAvailableTitle": "Atualização disponível", + "releaseNotesTitle": "Novidades", + "remindLater": "Mais tarde", + "retry": "Tentar novamente", + "stepDownload": "Download", + "stepInstall": "Instalação", + "stepRestart": "Reinício", + "updateReadyHint": "Atualização baixada — reinicie para aplicar.", + "restarting": "Reiniciando...", + "dockerUpgradeHint": "Isto atualiza o contêiner em execução agora. Perde-se se o contêiner for recriado — para mantê-lo, baixe ou crie uma imagem na nova versão e recrie o contêiner.", + "upgradeRolledBack": "Falha na atualização; o servidor reverteu para a versão anterior.", + "serverUnreachable": "Não foi possível acessar o servidor para iniciar a atualização. Verifique se ele está em execução e tente novamente.", + "rollbackButton": "Reverter", + "rollingBack": "Revertendo...", + "rollbackDescription": "Restaura a versão instalada antes da última atualização.", + "rollbackConfirmTitle": "Reverter para a versão anterior?", + "rollbackConfirmDescription": "O servidor será reiniciado na versão instalada antes da última atualização. Uma versão mais recente continua disponível para instalar novamente.", + "rollbackConfirm": "Reverter", + "rollbackCancel": "Cancelar", + "rollbackSuccess": "Revertido para a versão anterior. Recarregando...", + "rollbackFailed": "Falha ao reverter. Verifique os registros do servidor.", + "updateErrors": { + "sourceUnavailable": "Não foi possível acessar a fonte de atualização. Verifique sua rede ou proxy e tente novamente.", + "network": "Falha na conexão de rede. Verifique sua rede ou proxy e tente novamente.", + "downloadFailed": "Falha ao baixar o pacote de atualização. Tente novamente mais tarde.", + "installFailed": "Falha ao instalar a atualização. Feche o app e tente novamente.", + "unknown": "Falha na atualização. Tente novamente mais tarde." + } + }, + "VersionControlSettings": { + "loading": "Carregando...", + "sectionTitle": "Controle de versão", + "sectionDescription": "Configure o executável Git e gerencie contas do GitHub.", + "gitTitle": "Configuração do Git", + "gitDescription": "Configure o executável Git usado pelo aplicativo.", + "gitDetected": "Git detectado", + "gitNotFound": "Git não encontrado no sistema", + "gitVersion": "Versão", + "gitPath": "Caminho", + "customGitPath": "Caminho personalizado do Git", + "customGitPathPlaceholder": "/usr/bin/git", + "customGitPathHint": "Deixe vazio para usar o caminho detectado automaticamente.", + "test": "Testar", + "testing": "Testando...", + "testSuccess": "Executável Git é válido.", + "testFailed": "Teste do Git falhou: {message}", + "save": "Salvar", + "saving": "Salvando...", + "saveSuccess": "Configurações do Git salvas.", + "saveFailed": "Falha ao salvar: {message}", + "githubTitle": "Contas do GitHub", + "githubDescription": "Gerencie contas do GitHub para autenticação. Os tokens são armazenados localmente.", + "noAccounts": "Nenhuma conta do GitHub configurada.", + "addAccount": "Adicionar conta", + "serverUrl": "URL do servidor", + "serverUrlPlaceholder": "https://github.com", + "token": "Token de acesso pessoal", + "tokenPlaceholder": "ghp_xxxxxxxxxxxx", + "generateToken": "Gerar token", + "tokenHint": "Gere um token em GitHub → Settings → Developer settings → Personal access tokens.", + "validateAndAdd": "Validar e adicionar", + "validating": "Validando...", + "addSuccess": "Conta {username} adicionada com sucesso.", + "addFailed": "Falha ao adicionar conta: {message}", + "testConnection": "Testar", + "connectionSuccess": "Conexão bem-sucedida.", + "connectionFailed": "Falha na conexão: {message}", + "setDefault": "Definir como padrão", + "defaultLabel": "Padrão", + "defaultSet": "Conta padrão atualizada.", + "removeAccount": "Remover", + "removeConfirmTitle": "Remover conta", + "removeConfirmMessage": "Tem certeza de que deseja remover a conta \"{username}\"?", + "removeConfirm": "Remover", + "removeCancel": "Cancelar", + "removeSuccess": "Conta removida.", + "scopes": "Escopos", + "loadFailed": "Falha ao carregar configurações: {message}", + "gitAccount": { + "sectionTitle": "Contas de servidor Git", + "sectionDescription": "Gerencie credenciais para servidores Git que não são GitHub (GitLab, Bitbucket, auto-hospedados, etc.).", + "noAccounts": "Nenhuma conta de servidor Git configurada.", + "addAccount": "Adicionar conta", + "addTitle": "Adicionar conta Git", + "addDescription": "Insira o endereço do servidor, nome de usuário e senha ou token de acesso.", + "serverUrl": "URL do servidor", + "serverUrlPlaceholder": "https://gitlab.example.com", + "username": "Nome de usuário", + "usernamePlaceholder": "Nome de usuário ou e-mail", + "password": "Senha / Token", + "passwordPlaceholder": "Senha ou token de acesso", + "passwordHint": "Insira a senha ou o token de acesso do servidor.", + "add": "Adicionar", + "serverRequired": "A URL do servidor é obrigatória.", + "usernameRequired": "O nome de usuário é obrigatório.", + "passwordRequired": "A senha é obrigatória." + } + }, + "ShortcutSettings": { + "sectionTitle": "Atalhos", + "resetDefault": "Restaurar padrões", + "recordInstruction": "Clique no botão à direita e pressione uma combinação de teclas. Use Ctrl/Cmd, Alt e Shift. Pressione Esc para cancelar a gravação.", + "recording": "Pressione um atalho...", + "toasts": { + "conflict": "O atalho já está em uso por \"{title}\"", + "updated": "Atalho atualizado", + "invalid": "Atalho inválido, tente novamente", + "reset": "Atalhos padrão restaurados" + }, + "actions": { + "toggle_search": { + "title": "Abrir busca", + "description": "Mostra ou oculta o painel de busca de conversas" + }, + "toggle_sidebar": { + "title": "Alternar barra lateral esquerda", + "description": "Mostra ou oculta a barra lateral da lista de conversas" + }, + "toggle_terminal": { + "title": "Alternar terminal", + "description": "Mostra ou oculta o painel de terminal inferior" + }, + "new_terminal_tab": { + "title": "Novo terminal", + "description": "Cria uma nova aba de terminal quando o foco está no terminal" + }, + "close_current_terminal_tab": { + "title": "Fechar terminal atual", + "description": "Fecha a aba de terminal atual quando o foco está no terminal" + }, + "toggle_aux_panel": { + "title": "Alternar painel direito", + "description": "Mostra ou oculta o painel de informações auxiliares" + }, + "new_conversation": { + "title": "Nova conversa", + "description": "Cria uma nova aba de conversa na pasta atual" + }, + "open_folder": { + "title": "Abrir pasta", + "description": "Abre o seletor de pastas e abre em uma nova janela" + }, + "open_settings": { + "title": "Abrir configurações", + "description": "Abre a janela de configurações" + }, + "close_current_tab": { + "title": "Fechar aba atual", + "description": "Fecha a conversa atual ou aba de arquivo" + }, + "close_all_file_tabs": { + "title": "Fechar todas as abas de arquivo", + "description": "Fecha todas as abas de arquivo abertas quando o painel de arquivos está ativo" + }, + "next_tab": { + "title": "Próxima aba", + "description": "Mudar para a próxima aba de conversa ou arquivo" + }, + "prev_tab": { + "title": "Aba anterior", + "description": "Mudar para a aba anterior de conversa ou arquivo" + }, + "send_message": { + "title": "Enviar mensagem", + "description": "Enviar a mensagem atual na caixa de entrada" + }, + "newline_in_message": { + "title": "Nova linha na mensagem", + "description": "Inserir uma nova linha na caixa de entrada" + }, + "toggle_custom_style": { + "title": "Suspender/retomar estilo personalizado", + "description": "Saída de emergência: desliga todas as cores e o CSS personalizados e volta a ligá-los" + } + } + }, + "SkillsSettings": { + "title": "Skills", + "description": "Selecione uma Skill à esquerda. À direita, a prévia em Markdown é mostrada por padrão; mude para edição para modificar e salvar.", + "loadingAgents": "Carregando agentes que suportam Skills...", + "emptyNoManageableAgents": "Não há agentes disponíveis para gerenciamento de Skills.", + "managedTarget": "Alvo gerenciado", + "selectAgentPlaceholder": "Selecione um agente", + "searchPlaceholder": "Pesquisar por nome / ID / caminho...", + "skillsList": "Lista de Skills", + "loadingSkills": "Carregando Skills...", + "agentNotSupported": "O agente atual não suporta gerenciamento de Skills.", + "emptySkills": "Ainda não há Skills. Clique em \"Nova Skill\" para criar uma.", + "newSkillTitle": "Nova Skill", + "skillInfo": "Informações da Skill", + "skillIdPlaceholder": "skill-id (letras/números/-/_/.)", + "skillsDirectoryWithPath": "Diretório de Skills: {path}", + "skillsDirectoryNeedId": "Diretório de Skills: digite o ID da Skill para gerar o caminho completo", + "markdownContent": "Conteúdo Markdown", + "editingStatus": "Editando", + "previewStatus": "Visualizando", + "contentPlaceholder": "Digite o conteúdo Markdown da Skill...", + "metadataTitle": "Metadados de Skills", + "onlyYamlMetadata": "Esta Skill contém apenas metadados YAML.", + "emptyContentHint": "Ainda não há conteúdo. Clique em \"Editar\" para começar.", + "loadingSkill": "Carregando Skill...", + "emptyNoAgents": "Nenhum agente disponível.", + "noSelectionHint": "Selecione um Skill à esquerda ou clique em \"Novo Skill\" para criar um.", + "systemBadge": "Sistema", + "systemHint": "Skill integrado do CLI · somente leitura", + "scope": { + "global": "Global", + "folder": "Pasta", + "selectFolderPlaceholder": "Selecionar uma pasta", + "noFolders": "Nenhuma pasta encontrada", + "pickFolderHint": "Selecione uma pasta para ver suas Skills." + }, + "actions": { + "preview": "Prévia", + "edit": "Editar", + "openInWindow": "Abrir em nova janela", + "delete": "Excluir", + "deleting": "Excluindo...", + "refresh": "Atualizar", + "newSkill": "Nova Skill", + "reset": "Redefinir", + "save": "Salvar", + "saving": "Salvando...", + "cancel": "Cancelar" + }, + "deleteDialog": { + "title": "Excluir Skill", + "confirm": "Excluir a Skill atual? Esta ação não pode ser desfeita.", + "confirmWithNamePrefix": "Excluir Skill", + "confirmWithNameSuffix": "? Esta ação não pode ser desfeita." + }, + "toasts": { + "loadFailed": "Falha ao carregar Skill", + "openFolderFailed": "Falha ao abrir pasta", + "noSkillDirectory": "Nenhum diretório de Skills disponível para o agente atual", + "nameRequired": "O nome da Skill não pode estar vazio", + "updated": "Skill atualizada", + "created": "Skill criada", + "saveFailed": "Falha ao salvar Skill", + "deleted": "Skill excluída", + "deleteFailed": "Falha ao excluir Skill" + }, + "templates": { + "gemini": "---\nname: example-skill\ndescription: Describe when this skill should be used.\n---\n\n# Skill Name\n\nInstructions for the agent when this skill is active.\n\n## Workflow\n\n1. Add actionable step one.\n2. Add actionable step two.\n", + "openCode": "---\nname: example-skill\ndescription: Describe when this skill should be used.\n---\n\n# Purpose\n\nDescribe what this skill helps with.\n\n# Steps\n\n1. Add actionable step one.\n2. Add actionable step two.\n", + "openClaw": "---\nname: example-skill\ndescription: Describe when this skill should be used.\nuser-invocable: true\ndisable-model-invocation: false\n---\n\n# Purpose\n\nDescribe what this skill helps with.\n\n# Instructions\n\n1. Add actionable instruction one.\n2. Add actionable instruction two.\n", + "default": "---\nname: example-skill\ndescription: Describe when this skill should be used.\n---\n\n# Skill: example-skill\n\n## When to use\n\n- Describe trigger conditions.\n\n## Instructions\n\n1. Add actionable instruction one.\n2. Add actionable instruction two.\n" + } + }, + "McpSettings": { + "loading": "Carregando...", + "summary": { + "missingCommand": "(comando ausente)", + "missingUrl": "(URL ausente)" + }, + "protocol": { + "stdio": "Stdio" + }, + "errors": { + "selectInstallProtocol": "Selecione um protocolo de instalação", + "fieldRequired": "{field} é obrigatório", + "fieldNeedsBoolean": "{field} deve ser true ou false", + "fieldNeedsNumber": "{field} deve ser um número", + "fieldNeedsInteger": "{field} deve ser um inteiro", + "fieldInvalidJson": "{field} tem JSON inválido: {message}", + "fieldOutOfRange": "O valor de {field} está fora do intervalo permitido", + "jsonEmpty": "{name} não pode estar vazio", + "jsonInvalid": "{name} não é um JSON válido: {message}", + "jsonMustBeObject": "{name} deve ser um objeto JSON", + "specMustBeObject": "A configuração do MCP deve ser um objeto JSON.", + "missingType": "Falta o campo type na configuração do MCP. Use stdio, http (aliases: streamable-http, streamableHttp) ou sse.", + "unsupportedType": "Tipo de MCP não suportado {type}. Suportados: stdio, http (aliases: streamable-http, streamableHttp), sse.", + "codexEntryUnsupportedType": "A entrada Codex MCP {id} tem tipo não suportado {type}. Suportados: stdio, http (aliases: streamable-http, streamableHttp), sse.", + "unsupportedTransportType": "Tipo de transport não suportado {type}. Suportados: http (aliases: streamable-http, streamableHttp), sse.", + "stdioCommandRequired": "Um MCP stdio exige um campo command não vazio.", + "remoteUrlRequired": "Um MCP remoto exige um campo url não vazio.", + "appsRequired": "Selecione ao menos um aplicativo alvo." + }, + "jsonNames": { + "localConfig": "Configuração MCP", + "installConfig": "Configuração de instalação" + }, + "toasts": { + "uninstalled": "MCP desinstalado", + "uninstallFailed": "Falha ao desinstalar: {message}", + "selectAtLeastOneApp": "Selecione pelo menos um app de destino", + "saveSuccess": "Salvo", + "saveFailed": "Falha ao salvar: {message}", + "installed": "{name} instalado", + "installFailed": "Falha na instalação: {message}", + "serverIdRequired": "O Server ID é obrigatório", + "serverIdExists": "O Server ID \"{id}\" já existe. Edite a entrada existente ou escolha outro nome.", + "created": "MCP criado" + }, + "installDialog": { + "title": "Confirmar instalação do MCP", + "descriptionWithName": "Instalar {name} na configuração local.", + "description": "Selecione os apps de destino para instalação.", + "protocol": "Protocolo", + "selectProtocol": "Selecionar protocolo", + "parameters": "Parâmetros de configuração", + "booleanPlaceholder": "Selecione true/false", + "selectOneValue": "Selecione um valor", + "targetApps": "Apps de destino" + }, + "actions": { + "cancel": "Cancelar", + "confirmInstall": "Confirmar instalação", + "installing": "Instalando", + "uninstall": "Desinstalar", + "uninstalling": "Desinstalando", + "viewDetails": "Ver detalhes", + "save": "Salvar", + "saving": "Salvando", + "install": "Instalar", + "refresh": "Atualizar", + "newMcp": "Novo MCP", + "create": "Criar", + "creating": "Criando..." + }, + "tabs": { + "local": "MCP local", + "market": "Marketplace MCP" + }, + "local": { + "filterPlaceholder": "Filtrar MCP local...", + "loadFailed": "Falha ao carregar: {message}", + "empty": "Nenhum MCP local detectado.", + "description": "A configuração local de MCP pode ser editada e salva diretamente.", + "enabledApps": "Apps habilitados", + "configJson": "Configuração MCP (JSON)", + "draftTitle": "Novo MCP", + "draftDescription": "Informe um Server ID e a configuração para criar um servidor MCP local.", + "serverIdLabel": "Server ID", + "serverIdPlaceholder": "Server ID (ex.: my-mcp)", + "typeHint": "Tipos suportados: stdio, http (aliases: streamable-http, streamableHttp), sse. env só é usado por stdio; para MCPs remotos use headers para transportar tokens de autenticação.", + "envOnRemoteWarning": "env detectado em um MCP remoto. Apenas stdio usa env; MCPs remotos transportam tokens de autenticação via headers, portanto env será ignorado ao salvar." + }, + "market": { + "selectMarketplace": "Selecionar marketplace", + "searchPlaceholder": "Pesquisar MCP...", + "searchFailed": "Falha na busca: {message}", + "loadingList": "Carregando lista de MCP...", + "empty": "Nenhum resultado de MCP.", + "loadingDetail": "Carregando detalhes do marketplace...", + "detailLoadFailed": "Falha ao carregar detalhes: {message}", + "owner": "Proprietário: {owner}", + "namespace": "Namespace: {namespace}", + "defaultInstallProtocol": "Protocolo de instalação padrão", + "currentOptionParameterCount": "Quantidade de parâmetros da opção atual: {count}", + "installConfigDescription": "Configuração de instalação (JSON, editável antes de instalar; edições substituirão o formulário de protocolo/parâmetros)", + "selectLeftToView": "Selecione um MCP do marketplace à esquerda para ver detalhes." + }, + "badges": { + "verified": "Verificado", + "remote": "Remoto", + "hasHomepage": "Tem homepage", + "uses": "{count} usos", + "deployed": "Implantado", + "notDeployed": "Não implantado" + }, + "selectLeftMcp": "Selecione um MCP à esquerda." + }, + "AcpAgentSettings": { + "title": "Gerenciamento do SDK de agentes", + "description": "Gerencie em um só lugar a conexão do SDK de agentes, estado habilitado, variáveis de ambiente, gerenciamento de configuração e informações de preflight de versão.", + "loadingAgents": "Carregando lista de agentes...", + "agentList": "Lista de agentes", + "emptyNoAgent": "Nenhum agente disponível.", + "configManagement": "Gerenciamento de configuração", + "envVars": "Variáveis de ambiente", + "hostTools": { + "label": "Deixar o agente cuidar de arquivos e comandos", + "description": "O codeg deixa de atender o acesso a arquivos e os comandos de terminal, de modo que o agente os executa no próprio processo — onde o sandbox e as regras de permissão dele realmente se aplicam. A delegação a outros agentes também é desativada, pois levaria o mesmo trabalho de volta ao codeg. O codeg não adiciona sandbox algum, então ative isto apenas se o agente tiver um configurado." + }, + "nativeJsonConfig": "Configuração JSON nativa", + "modelHintDefault": "Deixe em branco para usar o modelo padrão do sistema.", + "generalConfigDescriptionClaude": "Suporta configuração rápida de API URL, API Key e modelos Claude, e sincroniza com a configuração JSON nativa.", + "generalConfigDescriptionDefault": "Suporta entrada de configuração importante (API URL, API Key, Model) e gerenciamento de configuração JSON nativa.", + "multiAgent": { + "title": "Colaboração multiagente", + "description": "Permite que agentes ativos deleguem subtarefas a outros agentes.", + "enable": "Ativar delegação", + "enableHint": "Quando desativado, a ferramenta delegate_to_agent fica oculta no catálogo de ferramentas MCP do agente.", + "withheldByHostTools": "{agents} não receberão as ferramentas de delegação: o interruptor por agente “Deixar o agente lidar com arquivos e comandos” está ligado.", + "selfInitiate": "Allow spawn without @", + "selfInitiateHint": "When on, an agent may start a listed sub-agent on its own. An @ mention is still always honored. When off, only an @ mention starts a sub-agent.", + "depthLimit": "Profundidade máxima de delegação", + "depthHint": "Intervalo permitido: {min}–{max}. Limita a profundidade de recursão de uma cadeia de delegação (raiz → filho → neto …).", + "completedCacheLabel": "Cache de resultados concluídos (MB)", + "completedCacheHint": "Cache em memória dos resultados concluídos de subagentes, mantido apenas enquanto a sessão de delegação está em execução e liberado automaticamente quando essa sessão termina. Acima deste limite, os resultados mais antigos são descartados da memória primeiro (ainda visíveis na sessão do próprio subagente); 0 = ilimitado (ainda assim liberado ao terminar a sessão).", + "save": "Salvar", + "saving": "Salvando…", + "saved": "Configurações de delegação salvas", + "saveFailed": "Falha ao salvar configurações de delegação", + "loadFailed": "Falha ao carregar configurações de delegação: {detail}", + "tabGeneral": "Geral", + "tabAgentDefaults": "Padrões do subagente", + "agentDefaultsDescription": "Substituições por agente aplicadas quando a Colaboração multiagente inicia um subagente para uma chamada de delegação. As opções mostradas vêm de uma sondagem ao vivo: o que você escolhe é exatamente o que o agente aceitará.", + "probing": "Carregando opções disponíveis do agente…", + "probeFailed": "Falha ao carregar opções: {detail}", + "retry": "Tentar novamente", + "noConfigAvailable": "Este agente não possui opções configuráveis.", + "modeLabel": "Modo", + "agentDefaultHint": "Padrão do agente: {value}", + "defaultOptionLabel": "Padrão ({value})" + }, + "actions": { + "dragSort": "Arraste para reordenar", + "dragSortAgent": "Arraste para reordenar {name}", + "refreshCheck": "Atualizar verificação", + "refreshCheckAgent": "Atualizar verificação de {name}", + "clickEnable": "Clique para habilitar {name}", + "clickDisable": "Clique para desabilitar {name}", + "install": "Instalar", + "upgrade": "Atualizar", + "uninstall": "Desinstalar", + "uninstalling": "Desinstalando...", + "saveEnvVars": "Salvar variáveis de ambiente", + "saving": "Salvando...", + "saveGrokConfig": "Salvar configuração do Grok", + "saveCodexConfig": "Salvar configuração do Codex", + "saveGeminiConfig": "Salvar configuração do Gemini", + "saveOpenCodeConfig": "Salvar configuração do OpenCode", + "saveOpenClawConfig": "Salvar configuração do OpenClaw", + "saveConfigManagement": "Salvar gerenciamento de configuração", + "saveCurrentProvider": "Salvar provedor atual", + "showApiKey": "Mostrar API Key", + "hideApiKey": "Ocultar API Key", + "showKey": "Mostrar chave", + "hideKey": "Ocultar chave", + "showToken": "Mostrar token", + "hideToken": "Ocultar token", + "cancel": "Cancelar", + "delete": "Excluir", + "deleting": "Excluindo...", + "confirmDelete": "Confirmar exclusão", + "confirmUninstall": "Confirmar desinstalação", + "saveClineConfig": "Salvar configuração do Cline", + "saveHermesConfig": "Salvar configuração do Hermes", + "saveCodeBuddyConfig": "Salvar configuração do CodeBuddy", + "saveKimiCodeConfig": "Salvar configuração do Kimi Code", + "customInstall": "Instalação personalizada", + "saveKimiCodeRawConfig": "Save config.toml", + "saveDeepSeekConfig": "Salvar configuração do DeepSeek", + "diagnose": "Diagnosticar" + }, + "status": { + "enabled": "Habilitado", + "disabled": "Desabilitado", + "unchecked": "Não verificado", + "agentEnabledAria": "{name} habilitado", + "agentEnabledSwitch": "Chave de habilitação de {name}" + }, + "preflight": { + "count": "Itens de preflight: {count}", + "notRun": "As verificações ainda não foram executadas." + }, + "grok": { + "configDescription": "Configure o Grok aqui. Os controles abaixo — modo de permissão, esforço de raciocínio, um modelo personalizado opcional (endpoint próprio) e a compactação — são mesclados em ~/.grok/config.toml, preservando suas outras chaves e comentários. O login usa seu XAI_API_KEY ou `grok login`. As demais chaves continuam editáveis em Avançado.", + "permissionModeLabel": "Modo de permissão", + "permissionDefault": "Perguntar sempre", + "permissionAcceptEdits": "Aprovar edições automaticamente", + "permissionAuto": "Aprovação automática inteligente", + "permissionAlwaysApprove": "Sempre aprovar", + "reasoningEffortLabel": "Esforço de raciocínio", + "effortLow": "Baixo (mais rápido)", + "effortMedium": "Médio (equilibrado)", + "effortHigh": "Alto", + "effortXhigh": "Máximo", + "optionDefault": "Usar padrão", + "authTitle": "Autenticação", + "authMode": "Método de autenticação", + "authModeApiKey": "Chave de API da XAI", + "authModeApiKeyHint": "Autentique-se com uma XAI_API_KEY do console da xAI, para execuções não interativas ou headless. Armazenada no ambiente deste agente.", + "authModeCustom": "Endpoint personalizado", + "authModeCustomHint": "Use um endpoint próprio (BYO): defina abaixo um modelo personalizado com a sua própria base URL e chave de API. Ele se torna o modelo padrão do Grok.", + "subscriptionHint": "Entre com `grok login` (SuperGrok / X Premium+). Nenhuma chave de API é armazenada.", + "loginHint": "Execute isto num terminal para entrar e depois reabra estas configurações:", + "commandCopied": "Comando copiado para a área de transferência", + "copyCommand": "Copiar comando", + "authKeyConfigured": "XAI_API_KEY está configurada.", + "authKeyMissing": "Nenhuma XAI_API_KEY definida.", + "advancedToggle": "Avançado (config.toml bruto)", + "configTomlNative": "config.toml (nativo)", + "configTomlHint": "Salvo literalmente como todo o ~/.grok/config.toml. TOML inválido é rejeitado para que um erro de digitação nunca trunque seu arquivo.", + "configTomlPlaceholder": "# Chaves além dos controles acima, por ex.\n# [mcp_servers.*], [cli], regras [permission].", + "customModelTitle": "Modelo personalizado (endpoint próprio)", + "customModelHint": "Aponte o Grok para um endpoint personalizado ou auto-hospedado. O codeg grava um bloco `[model.*]` por modelo e o define como padrão. Deixe o ID do modelo vazio para removê-lo.", + "customModelIdLabel": "ID do modelo", + "customModelIdPlaceholder": "grok-4.5", + "customModelIdHint": "Registrado como um bloco `[model.*]` e enviado à API como nome do modelo; também definido como `[models].default`.", + "customBaseUrlLabel": "URL base", + "customBaseUrlPlaceholder": "https://api.x.ai/v1 (padrão)", + "customApiBackendLabel": "Backend da API", + "backendResponses": "Responses", + "backendChatCompletions": "Chat Completions", + "backendMessages": "Messages (Anthropic)", + "customApiKeyLabel": "Chave de API", + "customApiKeyHint": "Armazenada em linha em `[model.*].api_key`, restrita a este endpoint.", + "customContextWindowLabel": "Janela de contexto (tokens)", + "customContextWindowHint": "Opcional. Define o momento da autocompactação; deixe vazio para o padrão do endpoint.", + "autoCompactLabel": "Limite de autocompactação (%)", + "autoCompactHint": "Compacta a conversa quando o uso do contexto atinge esta porcentagem (padrão do Grok: 85). Gravado em `[session]`." + }, + "cursor": { + "configDescription": "Configure o Cursor aqui. Escolha um método de autenticação — assinatura oficial (login pelo navegador) ou uma chave de API do Cursor para máquinas headless ou servidores — depois escolha um modelo e edite as regras de permissão e o sandbox do CLI. O codeg as grava em ~/.cursor/cli-config.json, compartilhado com o CLI cursor-agent.", + "authTitle": "Autenticação", + "authChecking": "Verificando…", + "authNotInstalled": "cursor-agent não está instalado", + "authLoggedIn": "Conectado", + "authNotLoggedIn": "Não conectado", + "loginHint": "Execute isto em um terminal para entrar na sua conta Cursor (uma janela do navegador abre) e depois clique em atualizar:", + "apiKeyLabel": "Chave de API do Cursor", + "apiKeyPlaceholder": "chave de cursor.com/dashboard", + "apiKeyHint": "CURSOR_API_KEY — uma chave de conta do painel do Cursor, alternativa ao login pelo navegador para máquinas headless ou servidores. Não é uma chave de terceiros nem da OpenAI.", + "modelTitle": "Modelo padrão", + "loadModels": "Carregar modelos", + "modelsUnavailable": "Lista de modelos indisponível", + "modelHint": "Passado à CLI como --model ao iniciar a sessão. Deixe no padrão para o Cursor escolher.", + "permissionsTitle": "Permissões e sandbox", + "permissionsDescription": "Editor visual das regras de permissão da CLI (cli-config.json). Regras permitidas executam sem confirmação; regras negadas são sempre bloqueadas.", + "permissionModeLabel": "Modo de permissões", + "permissionModeDefault": "Perguntar antes de executar (padrão)", + "permissionModeForce": "Run Everything (--force)", + "permissionModeHint": "Run Everything inicia as sessões com --force: todas as chamadas de ferramentas são permitidas automaticamente, exceto as regras de negação, sem confirmações (uma política da organização pode limitá-lo às regras de permissão). Vale para novas sessões.", + "optionDefault": "Padrão (não definido)", + "sandboxLabel": "Sandbox", + "sandboxEnabled": "Ativado", + "sandboxDisabled": "Desativado", + "allowRulesLabel": "Regras permitidas", + "denyRulesLabel": "Regras negadas", + "addRule": "Adicionar regra", + "rulesSyntaxHint": "Sintaxe das regras: Shell(cmd), Read(caminho/glob), Write(caminho/glob), WebFetch(domínio), Mcp(servidor:ferramenta) — as regras de negação sempre prevalecem.", + "saveConfig": "Salvar configuração", + "advancedToggle": "Avançado: cli-config.json bruto", + "advancedHint": "O ~/.cursor/cli-config.json completo. Salvar grava o arquivo como está; os controles estruturados acima são mesclados nele.", + "saveRawConfig": "Salvar arquivo", + "authMode": "Método de autenticação", + "subscriptionHint": "Faça login com sua conta Cursor e use os modelos do Cursor.", + "customApiKeyRequired": "É necessária uma chave de API do Cursor.", + "authModeApiKey": "Chave de API do Cursor (headless/servidor)", + "authModeApiKeyHint": "Autentique-se com uma chave de API de conta do Cursor gerada no painel do Cursor (para máquinas headless ou servidores). É uma chave de conta do Cursor, não um endpoint de terceiros/OpenAI: o cursor-agent só se comunica com o backend do próprio Cursor. Para usar um endpoint compatível com codex/OpenAI, use o agente Codex.", + "modelPickerPlaceholder": "Pesquisar modelos…", + "modelNoMatch": "Nenhum modelo correspondente", + "modelsNeedAuth": "Faça login para carregar a lista de modelos.", + "modelDefaultBadge": "padrão" + }, + "deepseek": { + "configManagement": "Configuração do DeepSeek Harness", + "configDescription": "O endpoint e a chave são variáveis de ambiente que o deepseek-acp lê ao iniciar. O modelo e o nível de raciocínio são seletores por sessão — escolha-os no campo de mensagem.", + "baseUrlLabel": "Endpoint da API", + "baseUrlHint": "Deixe vazio para o endpoint oficial. Vale para as sessões iniciadas depois de salvar; reconecte uma sessão em andamento para que ela use o novo valor.", + "baseUrlInvalid": "Informe uma URL http(s) completa e sem query string, por exemplo https://api.deepseek.com", + "apiKeyLabel": "Chave de API", + "apiKeyHint": "Enviada ao agente como DEEPSEEK_API_KEY. Uma variável de ambiente tem precedência sobre o arquivo de credenciais, então deixe em branco se você entrar pelo terminal." + }, + "codex": { + "configDescription": "Suporta configuração rápida de URL da API, API Key, nome do modelo e reasoning effort, com sincronização para `auth.json` / `config.toml`.", + "authMode": "Modo de Autenticação", + "chatgptSubscription": "Assinatura oficial", + "chatgptSubscriptionHint": "Faça login com assinatura oficial do ChatGPT, sem necessidade de API Key", + "apiKeyHint": "Conecte-se usando API Key ao OpenAI ou serviços de API compatíveis", + "selectProvider": "Selecionar provedor", + "modelName": "Nome do modelo", + "selectReasoningEffort": "Selecionar Reasoning Effort", + "enableWebsocket": "Habilitar WebSocket", + "enableWebsocketAria": "Habilitar WebSocket para Codex Provider", + "enableSkills": "Habilitar Skills", + "enableSkillsAria": "Habilitar Skills para Codex", + "enableFast": "Habilitar Fast", + "enableFastAria": "Habilitar nível de serviço Fast para Codex", + "sandboxGroupTitle": "Sandbox e aprovações", + "sandboxGroupHint": "Gravado no ~/.codex/config.toml global, portanto as sessões do codex CLI e do IDE também usam. São padrões do thread: valem para os turnos que o codex inicia sozinho (/goal, /review, /compact). Mensagens comuns usam a predefinição de aprovação do compositor. Reinicie a sessão para aplicar as alterações.", + "sandboxShadowedWarning": "O config.toml define default_permissions, então o codex resolve as permissões por esse perfil e ignora sandbox_mode por completo. Remova default_permissions para usar os controles abaixo.", + "sandboxPermissionsTableWarning": "O config.toml define perfis [permissions] sem default_permissions, o que faz o codex recusar a iniciar. Defina um no editor bruto abaixo.", + "approvalPolicyLabel": "Política de aprovação", + "approvalPolicyUnset": "Não definida (padrão do codex: sob demanda)", + "approvalPolicy_on-request": "Sob demanda — o modelo decide quando perguntar", + "approvalPolicy_untrusted": "Não confiável — só comandos de leitura reconhecidos como seguros rodam sem confirmação", + "approvalPolicy_never": "Nunca — nenhum pedido de aprovação", + "approvalPolicy_granular": "Granular — escolha por tipo de solicitação", + "approvalPolicyUntrustedAcpWarning": "Untrusted não tem equivalente entre os três presets de aprovação do adaptador ACP, então as sessões do codeg voltam para \"quando solicitado\": o modelo passa a decidir quando perguntar, e comandos que o sandbox já permite deixam de pedir confirmação. Restrinja o modo de sandbox abaixo em vez disso.", + "granularHint": "Desligado significa que esse tipo de solicitação é recusado automaticamente em vez de exibido a você.", + "granular_sandbox_approval": "Escalonamentos de comandos de shell", + "granular_rules": "Avisos de regras do execpolicy", + "granular_skill_approval": "Avisos de scripts de habilidades", + "granular_request_permissions": "Avisos da ferramenta request_permissions", + "granular_mcp_elicitations": "Avisos de elicitação MCP", + "sandboxModeLabel": "Modo de sandbox", + "sandboxModeUnset": "Não definido (pastas confiáveis caem para escrita no espaço de trabalho)", + "sandboxMode_read-only": "Somente leitura", + "sandboxMode_workspace-write": "Escrita no espaço de trabalho", + "sandboxMode_danger-full-access": "Acesso total (sem sandbox)", + "sandboxModeHint": "No Windows, a escrita no espaço de trabalho é rebaixada para somente leitura, a menos que o sandbox experimental do Windows do codex esteja ativado.", + "sandboxModeSeedsPresetHint": "O codeg também usa isto para o preset de aprovação inicial da sessão, portanto — ao contrário da política de aprovação — ele afeta os prompts comuns. O preset escolhido no editor continua tendo prioridade.", + "writableRootsLabel": "Pastas graváveis extras", + "writableRootsHint": "Um caminho absoluto por linha, além do diretório de trabalho.", + "sandboxRootsRelativeError": "Precisa ser um caminho absoluto — o codex resolve caminhos relativos dentro de ~/.codex: {path}", + "networkAccessLabel": "Permitir acesso à rede", + "excludeTmpdirLabel": "Excluir TMPDIR das raízes graváveis", + "excludeSlashTmpLabel": "Excluir /tmp das raízes graváveis", + "authJsonNative": "auth.json (nativo)", + "configTomlNative": "config.toml (nativo)", + "loginButton": "Entrar com ChatGPT", + "loginRequesting": "Solicitando código de login...", + "loginStep1": "Abra a seguinte URL no seu navegador:", + "loginStep2": "Digite o código abaixo:", + "loginPolling": "Aguardando autorização...", + "loginCancel": "Cancelar", + "loginSuccess": "Login realizado com sucesso, configuração salva!", + "loginFailed": "Falha no login: {message}", + "loginRetry": "Tentar novamente", + "loginCodeCopied": "Código copiado", + "loggedIn": "Conta conectada", + "loginRelogin": "Reconectar / Trocar conta", + "loginTimeout": "Login expirou, tente novamente", + "loginSaveFailed": "Login realizado com sucesso, mas falha ao salvar configuração" + }, + "gemini": { + "authConfig": "Configuração de autenticação do Gemini", + "authConfigDescription": "Alinhada à documentação de autenticação do Gemini CLI, com suporte a endpoint personalizado, login Google, Gemini API Key e Vertex AI (ADC / conta de serviço / API Key).", + "authMode": "Modo de autenticação", + "selectAuthMode": "Selecionar modo de autenticação", + "viewAuthDoc": "Ver documentação de autenticação", + "mode": { + "custom": "Endpoint personalizado", + "loginGoogle": "Login Google (OAuth)", + "vertexServiceAccount": "Vertex AI (Conta de serviço)" + }, + "hint": { + "custom": "Preencha API URL, API Key e Modelo; mapeados para GOOGLE_GEMINI_BASE_URL / GEMINI_API_KEY / GEMINI_MODEL.", + "loginGoogle": "Execute gemini no terminal e conclua o login Google primeiro; API key não é necessária.", + "geminiApiKey": "Preencha GEMINI_API_KEY ao usar a API Gemini.", + "vertexAdc": "Use gcloud ADC; GOOGLE_CLOUD_PROJECT e GOOGLE_CLOUD_LOCATION são recomendados.", + "vertexServiceAccount": "Defina o caminho do JSON da conta de serviço em GOOGLE_APPLICATION_CREDENTIALS.", + "vertexApiKey": "Preencha GOOGLE_API_KEY ao usar API key do Vertex AI." + } + }, + "openCode": { + "configManagement": "Gerenciamento de configuração do OpenCode", + "configDescription": "Alinhado ao esquema `provider` do OpenCode, com suporte a gerenciamento multi-provedor e sincronização bidirecional com arquivos JSON nativos.", + "providerManagement": "Gerenciamento de provedores", + "providerCount": "{count} provedores", + "addProvider": "Adicionar provedor", + "emptyProvider": "Ainda não há provedores personalizados. Clique em Adicionar provedor personalizado para criar um.", + "providerEnabledState": "Estado habilitado de {providerId}", + "selectProviderNpm": "Selecionar provider.npm", + "modelManagement": "Gerenciamento de modelos", + "modelCount": "{count} modelos", + "modelDescription": "Alinhado ao `provider.models` do OpenCode. O gerenciamento rápido atualmente suporta `name` / `id`; outros campos avançados são preservados e podem ser editados no JSON nativo abaixo.", + "addModel": "Adicionar modelo", + "emptyModel": "Ainda não há modelo. Informe model id e clique em \"Adicionar modelo\".", + "modelId": "ID do modelo", + "modelName": "Nome do modelo", + "deleteModel": "Excluir modelo {modelId}", + "nativeJsonConfig": "Configuração JSON nativa do OpenCode", + "mainModel": "Modelo principal", + "smallModel": "Modelo pequeno", + "noMatchingModels": "Nenhum modelo correspondente", + "connectProvider": "Conectar provedor", + "connectedProviders": "Provedores conectados", + "noConnectedProviders": "Ainda não há provedores do catálogo conectados.", + "advancedProviderConfig": "Provedores personalizados", + "customProviderConfigHint": "Endpoints compatíveis com OpenAI que você mesmo define — um bloco de provider em opencode.json, com a API key em auth.json.", + "addCustomProvider": "Adicionar provedor personalizado", + "disconnect": "Desconectar", + "editConfig": "Editar", + "customBadge": "Personalizado", + "authKindApi": "Chave de API", + "authKindOauth": "OAuth", + "authKindNone": "Sem credencial", + "connect": { + "title": "Conectar um provedor", + "description": "Escolha um provedor no catálogo do models.dev. As credenciais são salvas no arquivo auth.json do OpenCode.", + "pick": "Provedor", + "search": "Pesquisar provedores…", + "loading": "Carregando catálogo…", + "catalogLabel": "Catálogo do models.dev", + "modelsAvailable": "{count} modelos disponíveis", + "getKey": "Obter chave de API", + "oauthApiKeyNote": "Este provedor também oferece login pelo navegador via opencode auth login. O login pelo navegador chegará em breve — por enquanto, cole uma chave de API.", + "apiKey": "Chave de API", + "apiKeyHint": "Salva em auth.json, nunca em opencode.json.", + "baseUrlOptional": "Substituir Base URL (opcional)", + "providerId": "ID do provedor", + "displayName": "Nome de exibição", + "modelsList": "Modelos (um por linha)", + "modelsHint": "IDs de modelo que o endpoint aceita.", + "action": "Conectar", + "editTitle": "Editar provedor", + "editDescription": "Atualize a chave de API ou a Base URL deste provedor.", + "saveAction": "Salvar" + }, + "customProvider": { + "title": "Adicionar um provedor personalizado", + "description": "Defina um endpoint compatível com OpenAI. A API key é salva em auth.json; o bloco de provider vai para opencode.json.", + "action": "Adicionar provedor", + "idInCatalog": "{providerId} é um provedor conhecido — conecte-o via Conectar provedor." + }, + "refreshCatalog": "Atualizar catálogo", + "reasoningBadge": "raciocínio", + "contextWindow": "Janela de contexto", + "permissions": { + "title": "Permissões", + "description": "Decida quais ações rodam sozinhas, quais pedem sua confirmação e quais são bloqueadas. Gravado no bloco permission do opencode.json e aplicado ao salvar abaixo.", + "docsLink": "Documentação de permissões", + "unparsableConfig": "O JSON nativo abaixo não é válido, então o editor visual está pausado. Corrija o JSON para continuar.", + "invalidBlock": "O bloco permission tem um formato que o codeg não reconhece. Edite-o no JSON nativo abaixo ou use Redefinir para começar de novo.", + "orderingUnsafe": "Há uma regra curinga escrita depois de ferramentas específicas, então o OpenCode a aplica a elas também — as linhas abaixo não são o que está em vigor. Corrigir ordem apenas devolve cada curinga ao início do seu escopo, sem mudar nenhum valor.", + "orderingUnsafeManual": "Uma regra fica encoberta por um padrão mais geral escrito depois dela, então o OpenCode nunca a aplica — as linhas abaixo não são o que está em vigor. Dois padrões que se sobrepõem não têm uma única ordem certa; reordene-os no JSON nativo para que o mais geral venha primeiro.", + "fixOrder": "Corrigir ordem", + "agentOverrides": "Estes agentes sobrepõem as permissões e são aplicados por último, então vencem tudo daqui: {agents}. Edite-os no JSON nativo abaixo ou ative o aceite automático para apagá-los.", + "legacyTools": "O mapa tools legado de nível superior nega uma ferramenta. O OpenCode o funde com as permissões, então ele se aplica acima de tudo o que aparece aqui. Edite-o no JSON nativo abaixo ou ative o aceite automático para apagá-lo.", + "autoAcceptTitle": "Aceitar todas as permissões automaticamente", + "autoAcceptHint": "Toda chamada de ferramenta — comandos de shell, edições de arquivos, caminhos fora do projeto — roda sem perguntar. Ao ativar, as configurações por ferramenta abaixo são substituídas por uma única regra que permite tudo, e as sobreposições por agente e os interruptores tools legados que ainda bloqueariam são apagados.", + "globalLabel": "Padrão global", + "globalHint": "A regra *: vale para tudo que as ferramentas abaixo não sobrescreverem.", + "actionUnset": "Não definido (padrões do OpenCode)", + "actionInherit": "Herdar ({action})", + "actionAllow": "Permitir", + "actionAsk": "Perguntar", + "actionDeny": "Negar", + "perToolTitle": "Permissões por ferramenta", + "reset": "Redefinir", + "ruleCount": "regras: {count}", + "rulesToggle": "Regras detalhadas de {tool}", + "rulesHint": "São comparadas com a entrada da ferramenta e a última correspondência vence, então coloque os padrões amplos primeiro. * corresponde a quaisquer caracteres, ? a exatamente um, e um ~ inicial vira sua pasta pessoal.", + "noRules": "Ainda não há regras detalhadas.", + "addRule": "Adicionar regra", + "deleteRule": "Excluir a regra {pattern}", + "duplicateRule": "Esse padrão já existe.", + "blankRule": "Uma regra precisa de um padrão — use o ícone de lixeira para removê-la.", + "customKeys": "Outras chaves de permissão no arquivo", + "customKeyHint": "Não é uma ferramenta integrada do OpenCode — mantida como está.", + "keys": { + "bash": "Executar comandos de shell, pelo comando analisado", + "edit": "Todas as modificações de arquivos: edit, write e patch", + "read": "Ler arquivos, pelo caminho", + "external_directory": "Acessar caminhos fora do diretório de trabalho do projeto", + "task": "Iniciar subagentes, pelo tipo de subagente", + "skill": "Carregar skills, pelo nome", + "glob": "Encontrar arquivos, pelo padrão glob", + "grep": "Pesquisar o conteúdo dos arquivos, pelo padrão", + "list": "Listar o conteúdo de um diretório", + "webfetch": "Buscar uma URL", + "websearch": "Pesquisar na web", + "lsp": "Executar consultas LSP", + "todowrite": "Escrever a lista de tarefas", + "question": "Fazer uma pergunta a você", + "doom_loop": "Dispara quando a mesma chamada se repete três vezes com a mesma entrada" + } + } + }, + "openClaw": { + "gatewayConfig": "Configuração de Gateway", + "gatewayDescription": "Configure a conexão do OpenClaw Gateway. Suporta gateway local ou remoto.", + "gatewayUrlHint": "Deixe vazio para usar gateway.remote.url da configuração local do openclaw.", + "gatewayTokenPlaceholder": "Token de autenticação do Gateway", + "gatewayTokenHint": "Use token-file em vez de token em texto puro quando possível; configure via CLI do openclaw.", + "sessionKeyHint": "Opcional. Especifique a session key do gateway; deixe vazio para atribuição automática de sessão isolada." + }, + "hermes": { + "configManagement": "Configuração do Hermes", + "configDescription": "O Hermes gerencia suas próprias credenciais em ~/.hermes/.env e as configurações em ~/.hermes/config.yaml. Escolha um provedor e, em seguida, defina a chave de API e o modelo — o codeg grava os dois arquivos para você.", + "providerLabel": "Provedor", + "providerHint": "O provedor determina qual variável de chave de API e qual model.provider o Hermes usa. Provedores OAuth são configurados pela configuração de terminal abaixo.", + "groupApiKey": "Provedores com chave de API", + "groupOauth": "Provedores OAuth", + "groupAws": "AWS", + "apiKeyHint": "Salva em ~/.hermes/.env. Ela nunca é injetada no processo — o Hermes a lê da sua própria configuração.", + "modelName": "Modelo", + "oauthHint": "Este provedor usa OAuth. Execute a configuração abaixo para autenticar no seu terminal.", + "awsHint": "O Bedrock usa suas credenciais da AWS (ambiente ou configuração compartilhada). Defina o ID do modelo acima e configure o acesso à AWS no seu ambiente.", + "unsupportedProvider": "Este provedor não pode ser editado com campos estruturados. Use o editor de config.yaml abaixo ou a configuração pelo terminal.", + "setupTitle": "Configuração autogerenciada", + "setupHint": "A configuração interativa do Hermes precisa de um terminal. Inicie-a abaixo ou copie o comando para executá-lo você mesmo.", + "runSetup": "Executar configuração do Hermes", + "configureModel": "Configurar modelo", + "openConfigFolder": "Abrir ~/.hermes", + "copyCommand": "Copiar comando", + "commandCopied": "Comando copiado para a área de transferência", + "advancedTitle": "Avançado: editar config.yaml", + "rawConfigHint": "Edite ~/.hermes/config.yaml diretamente. Salvar aqui sobrescreve o arquivo exatamente como está.", + "saveRawConfig": "Salvar config.yaml" + }, + "codebuddy": { + "configManagement": "Configuração do CodeBuddy", + "configDescription": "O CodeBuddy autentica com uma chave de API. As versões da China continental também exigem o ambiente definido como “China (internal)”; as versões iOA usam “iOA”. A versão internacional deixa sem definir.", + "apiKeyLabel": "Chave de API", + "apiKeyHint": "Salvo como CODEBUDDY_API_KEY para este agente. Como alternativa, faça login com a CLI do CodeBuddy em um terminal.", + "apiKeyHintSelfHosted": "Salvo como CODEBUDDY_API_KEY para este agente. Use a chave emitida pela sua implantação privada.", + "environmentLabel": "Ambiente", + "environmentHint": "Define CODEBUDDY_INTERNET_ENVIRONMENT. A China continental deve usar “China (internal)”; a versão internacional deixa sem definir.", + "envOverseas": "Internacional (padrão)", + "envChina": "China (internal)", + "envIoa": "iOA", + "envSelfHosted": "Auto-hospedado (implantação privada)", + "baseUrlLabel": "URL de implantação", + "baseUrlPlaceholder": "https://codebuddy.your-company.com", + "baseUrlHint": "Salvo como CODEBUDDY_BASE_URL e aponta o CodeBuddy para seu endpoint privado. No auto-hospedado, o ambiente de rede (CODEBUDDY_INTERNET_ENVIRONMENT) fica sem definição.", + "baseUrlInvalid": "Insira uma URL http(s) válida.", + "loginHint": "Sem chave de API? Execute “codebuddy” em um terminal para fazer login com sua conta Tencent." + }, + "kimiCode": { + "configManagement": "Configuração do Kimi Code", + "configDescription": "O `kimi acp` só aceita um token de login armazenado, por isso o codeg grava um provedor gerenciado em ~/.kimi-code/config.toml e cria um token de acesso local — a inferência continua usando a sua própria chave.", + "statusUnconfigured": "Ainda não configurado", + "statusDirty": "Alterações não salvas", + "summaryLabel": "Em vigor", + "gateReadyApiKey": "Chave de API gravada em config.toml", + "gateReadyLogin": "Conectado com uma conta Kimi", + "revealConfig": "Mostrar na pasta", + "envOverrideWarning": "{keys} está definido e tem prioridade sobre o config.toml. Salvar aqui remove essa variável.", + "authModeLabel": "Método de autenticação", + "authModeApiKey": "Chave de API", + "authModeLogin": "Login da conta Kimi (assinatura)", + "authModeApiKeyHint": "Grava um provedor gerenciado no config.toml e cria o token de acesso para que as sessões possam abrir.", + "loginHint": "Execute `kimi login` em um terminal para entrar com uma conta Kimi por assinatura. O codeg não armazena nada e reutiliza o login do próprio Kimi. Salvar aqui remove o token de acesso por chave de API do codeg.", + "credentialTitle": "Credencial", + "interfaceTypeLabel": "Tipo de provedor", + "interfaceTypeHint": "O protocolo de provedor que o Kimi fala (o `type` do config.toml). Use Kimi / Moonshot para uma chave da Moonshot / platform.kimi.com.", + "endpointLabel": "Endpoint", + "endpointCustom": "Personalizado (compatível com OpenAI)", + "endpointHint": "Internacional = api.moonshot.ai; China (chaves de platform.kimi.com) = api.moonshot.cn. Personalizado aponta para qualquer endpoint compatível com OpenAI.", + "regionInternational": "Internacional (api.moonshot.ai)", + "regionChina": "China (api.moonshot.cn)", + "baseUrlLabel": "URL base", + "baseUrlHint": "Deixe em branco para usar o padrão do SDK do provedor.", + "apiKeyLabel": "Chave de API", + "apiKeyHint": "Gravada em ~/.kimi-code/config.toml e usada para inferência. De platform.kimi.com ou platform.kimi.ai.", + "vertexProjectLabel": "Projeto do GCP (GOOGLE_CLOUD_PROJECT)", + "vertexLocationLabel": "Região do GCP (GOOGLE_CLOUD_LOCATION)", + "vertexHint": "O Vertex AI usa as credenciais padrão do aplicativo Google — execute `gcloud auth application-default login` (sem chave de API).", + "modelTitle": "Modelo", + "modelLabel": "Modelo", + "modelHint": "O id do modelo gravado no config.toml. Use «Testar e listar modelos» para ver o que a sua chave realmente acessa.", + "maxContextLabel": "Tamanho máximo de contexto", + "maxContextHint": "Obrigatório pelo esquema do Kimi: sem ele o Kimi descarta todo o bloco do modelo e nenhuma solicitação retorna resposta. Padrão 262144.", + "fetchModels": "Testar e listar modelos", + "fetchModelsOk": "A chave funciona — {count} modelos disponíveis", + "fetchModelsEmpty": "A chave funciona, mas nenhum modelo foi retornado", + "fetchModelsFailed": "Falha no teste", + "fetchModelsNeedsKey": "Informe primeiro uma chave de API e um endpoint", + "modelNotInList": "Este modelo não está na lista acessível pela sua chave — o Kimi falhará com «modelo não encontrado».", + "reasoningTitle": "Raciocínio", + "reasoningEnableLabel": "Ativar", + "reasoningDescription": "O Kimi só mostra o seletor «Thinking» na caixa de mensagem quando o modelo declara uma capacidade de raciocínio, por isso o codeg a grava aqui. Vale para sessões novas.", + "effortsLabel": "Níveis oferecidos", + "effortsHint": "Estes níveis viram as opções do seletor «Thinking». O Kimi repassa o nível ao provedor tal como está, então escolha os que o seu modelo aceita.", + "effortsEmptyHint": "Sem nenhum nível escolhido, a caixa de mensagem fica apenas com um interruptor Off / On.", + "effortsCustomPlaceholder": "Adicionar outro nível", + "effortsAdd": "Adicionar", + "defaultEffortLabel": "Nível padrão", + "defaultEffortAuto": "Deixar o Kimi escolher", + "alwaysThinkingLabel": "O modelo sempre raciocina — remover a opção Off do seletor", + "fixErrorsFirst": "Corrija primeiro os campos destacados", + "errorModelRequired": "O modelo é obrigatório", + "errorMaxContextRequired": "O tamanho máximo de contexto é obrigatório", + "errorMaxContextInvalid": "Deve ser um número inteiro positivo", + "errorApiKeyRequired": "A chave de API é obrigatória", + "errorApiKeyInvalid": "A chave de API não pode conter quebras de linha", + "errorBaseUrlRequired": "A URL base é obrigatória", + "errorBaseUrlInvalid": "Deve começar com http:// ou https://", + "errorVertexProjectRequired": "O projeto do GCP é obrigatório", + "errorDefaultEffortUnlisted": "Escolha um dos níveis selecionados acima", + "advancedTitle": "Avançado", + "authTypeLabel": "Local da credencial", + "authTypeApiKey": "api_key em linha", + "authTypeEnv": "Subtabela env do provedor", + "authTypeHint": "Onde a chave de API é gravada dentro do config.toml.", + "rawEditorLabel": "Editar config.toml diretamente", + "rawEditorWarning": "Salvar aqui sobrescreve o arquivo inteiro literalmente, substituindo as configurações estruturadas acima.", + "rawEditorPlaceholder": "[providers.codeg]\ntype = \"kimi\"\nbase_url = \"https://api.moonshot.cn/v1\"\napi_key = \"sk-...\"" + }, + "authModeOfficialSubscription": "Assinatura oficial", + "authModeCustomEndpoint": "Endpoint personalizado", + "authModeCustomEndpointHint": "Configurar manualmente a URL da API e a chave API para um endpoint personalizado.", + "authModeModelProvider": "Provedor de modelo", + "modelProvider": "Provedor de modelo", + "modelProviderHint": "Usar URL da API, chave API e modelo de um provedor de modelo configurado.", + "selectModelProvider": "Selecionar provedor de modelo", + "noModelProviderAvailable": "Nenhum provedor de modelo configurado para este agente. Vá para as configurações de provedores de modelo para adicionar um.", + "claude": { + "authMode": "Modo de autenticação", + "officialSubscription": "Assinatura oficial", + "officialSubscriptionHint": "Usar assinatura oficial da Anthropic, sem necessidade de API Key.", + "mainModel": "Modelo principal", + "reasoningModel": "Modelo de raciocínio (thinking)", + "haikuDefaultModel": "Modelo Haiku padrão", + "sonnetDefaultModel": "Modelo Sonnet padrão", + "opusDefaultModel": "Modelo Opus padrão", + "customModelOption": "ID do modelo personalizado", + "customModelOptionName": "Nome do modelo personalizado", + "customModelOptionDescription": "Descrição do modelo personalizado", + "customModelOptionHint": "Adiciona uma única entrada personalizada ao seletor de modelos do Claude (por exemplo, um modelo atrás de um gateway/proxy personalizado). Nome e descrição são informações de exibição opcionais.", + "effortLevel": "Nível de raciocínio", + "effortLevelDefault": "Nível padrão", + "effortLevel_low": "Baixo", + "effortLevel_medium": "Médio", + "effortLevel_high": "Alto", + "effortLevel_xhigh": "Extra Alto", + "sendAttributionHeader": "Enviar identificador de atribuição/cobrança para a API", + "sendAttributionHeaderAria": "Enviar o identificador de atribuição/cobrança do Claude Code para a API", + "disableNonessentialTraffic": "Desativar a telemetria ou solicitações de rede desnecessárias", + "disableNonessentialTrafficAria": "Desativar a telemetria ou solicitações de rede desnecessárias do Claude Code" + }, + "dialogs": { + "confirmDeleteProvider": "Excluir o provedor {providerId}?", + "confirmDeleteProviderDescription": "A configuração do OpenCode e o auth JSON serão atualizados juntos. Esta ação não pode ser desfeita.", + "confirmUninstall": "Desinstalar {name}?", + "confirmUninstallDescription": "Isso remove a versão instalada localmente. Você pode reinstalar depois.", + "customInstallTitle": "Instalação personalizada de {name}", + "customInstallDescription": "Digite a versão a instalar. Isso reinstala e substitui a versão instalada atualmente.", + "customInstallVersionLabel": "Número da versão", + "customInstallInvalid": "Digite um número de versão válido, ex.: 1.2.3.", + "customInstallSubmit": "Instalar" + }, + "errors": { + "windowsFileLocked": "Os arquivos de {name} estão em uso por uma sessão ativa, então o Windows não consegue substituí-los. Feche todas as sessões de {name} e tente novamente.", + "nativeJsonMustBeObject": "A configuração JSON nativa deve ser um objeto", + "nativeJsonInvalid": "Erro de formato na configuração JSON nativa: {message}", + "openCodeAuthMustBeObject": "OpenCode auth.json deve ser um objeto JSON", + "openCodeAuthInvalid": "Erro de formato no OpenCode auth.json: {message}", + "authMustBeObject": "auth.json deve ser um objeto JSON", + "authInvalid": "Erro de formato no auth.json: {message}", + "providerIdPattern": "O ID do provedor só aceita letras, números, sublinhado, ponto e hífen", + "providerExists": "O provedor {providerId} já existe", + "modelIdPattern": "O ID do modelo só aceita letras, números, sublinhado, ponto, dois-pontos e hífen", + "modelExists": "O modelo {modelId} já existe" + }, + "warnings": { + "nativeJsonRecoveredStructured": "A configuração JSON nativa é inválida; redefinida para configuração estruturada", + "nativeJsonRecoveredOpenCode": "A configuração JSON nativa é inválida; redefinida para configuração estruturada do OpenCode", + "openCodeAuthRecovered": "OpenCode auth.json é inválido; redefinido para configuração padrão", + "authRecoveredStructured": "auth.json é inválido; redefinido para configuração estruturada" + }, + "toasts": { + "agentActionCompleted": "{name} {action} concluído", + "agentActionFailed": "{name} {action} falhou", + "localVersion": "Versão local: {version}", + "installCompletedVersionLater": "Instalação concluída, a versão será atualizada na próxima verificação", + "uninstallCompleted": "Desinstalação de {name} concluída", + "uninstallFailed": "Desinstalação de {name} falhou", + "localVersionRemoved": "Versão local removida", + "saveAgentOrderFailed": "Falha ao salvar a ordem dos Agents", + "saveAgentSwitchFailed": "Falha ao salvar o switch dos Agents", + "saveEnvFailed": "Falha ao salvar variáveis de ambiente", + "grokSaved": "Configuração do Grok salva", + "saveGrokNativeFailed": "Falha ao salvar a configuração nativa do Grok", + "saveGrokApiKeyFailed": "Configurações salvas, mas não foi possível salvar a chave de API", + "cursorSaved": "Configuração do Cursor salva", + "saveCursorConfigFailed": "Falha ao salvar a configuração do Cursor", + "codexSaved": "Configuração do Codex salva", + "saveCodexNativeFailed": "Falha ao salvar configuração nativa do Codex", + "geminiSaved": "Configuração do Gemini salva", + "saveGeminiFailed": "Falha ao salvar configuração do Gemini", + "providerDeleted": "Provedor {providerId} excluído", + "providerDeleteFailed": "Falha ao excluir o provedor {providerId}", + "providerSaved": "Provedor {providerId} salvo", + "saveProviderFailed": "Falha ao salvar o provedor {providerId}", + "openCodeConfigSynced": "A configuração do OpenCode e o auth JSON foram sincronizados.", + "openCodeSaved": "Configuração do OpenCode salva", + "saveOpenCodeFailed": "Falha ao salvar configuração do OpenCode", + "openClawSaved": "Configuração do OpenClaw salva", + "saveOpenClawFailed": "Falha ao salvar configuração do OpenClaw", + "configSaved": "Configuração salva", + "configSavedHint": "Sessões existentes precisam ser reabertas para que as alterações tenham efeito", + "saveConfigManagementFailed": "Falha ao salvar o gerenciamento de configuração", + "clineSaved": "Configuração do Cline salva", + "saveClineFailed": "Falha ao salvar a configuração do Cline", + "hermesSaved": "Configuração do Hermes salva", + "saveHermesFailed": "Falha ao salvar a configuração do Hermes", + "codeBuddySaved": "Configuração do CodeBuddy salva", + "saveCodeBuddyFailed": "Falha ao salvar a configuração do CodeBuddy", + "kimiCodeSaved": "Configuração do Kimi Code salva", + "saveKimiCodeFailed": "Falha ao salvar a configuração do Kimi Code", + "deepseekSaved": "Configuração do DeepSeek salva", + "saveDeepSeekFailed": "Falha ao salvar a configuração do DeepSeek", + "modelProviderRequired": "Selecione um provedor de modelo antes de salvar.", + "affectedRunningSessions": "{count, plural, one {# sessão ativa precisa reconectar para aplicar a alteração} other {# sessões ativas precisam reconectar para aplicar a alteração}}", + "providerConnected": "{providerId} conectado", + "connectFailed": "Falha ao conectar {providerId}", + "providerDisconnected": "{providerId} desconectado", + "disconnectFailed": "Falha ao desconectar {providerId}", + "catalogRefreshed": "Catálogo atualizado — {count} provedores", + "catalogRefreshFailed": "Falha ao atualizar o catálogo", + "piSaved": "Configuração do Pi salva", + "savePiFailed": "Falha ao salvar a configuração do Pi", + "piRuntimeSaved": "Tempo de execução do Pi salvo", + "savePiRuntimeFailed": "Falha ao salvar o tempo de execução do Pi", + "piBinaryInstalled": "pi instalado", + "piBinaryInstallFailed": "Falha ao instalar o pi", + "piBinaryUninstalled": "pi desinstalado", + "piBinaryUninstallFailed": "Falha ao desinstalar o pi", + "savePiTrustFailed": "Falha ao salvar a confiança do espaço de trabalho" + }, + "version": { + "statusLabel": "Status da versão", + "notInstalled": "Não instalado", + "remoteLocal": "Remoto: {remoteVersion} · Local: {localVersion}", + "localOnly": "Local: {localVersion}", + "localInstalled": "{versionText}. Instalado.", + "platformUnsupported": "{versionText}. A plataforma atual não suporta este agente.", + "uvxNotReady": "{versionText}. O runtime do uv não está instalado — instale-o na verificação do uv abaixo para usar este agente.", + "clickInstall": "{versionText}. Clique em Instalar à direita.", + "localUnrecognized": "{versionText}. A versão local não é comparável; tente atualizar para sobrescrever a instalação.", + "upgradeAvailable": "{versionText}. Atualização disponível.", + "remoteUnavailable": "{versionText}. A versão remota está indisponível no momento.", + "latest": "{versionText}. Já está na versão mais recente." + }, + "adapter": { + "label": "Adaptador ACP", + "badge": "Adaptador ACP", + "badgeHint": "Para este agente o Codeg instala um pacote adaptador ACP, não a CLI do fornecedor. Os dois são independentes e compartilham a mesma configuração.", + "learnMore": "Saiba mais", + "missingWithNative": "Encontramos a sua {nativeLabel} em {nativePath}. O Codeg conversa com os agentes por ACP e essa CLI não fala ACP, então o Codeg precisa de um pacote adaptador separado, {adapterPackage}, mantido pelo projeto Agent Client Protocol (originalmente Zed). Ele traz o próprio runtime, nunca modifica nem substitui o seu comando {nativeCmd} e lê o mesmo {configDir} — seu login e suas configurações continuam valendo. Instale abaixo.", + "missing": "O Codeg conversa com os agentes por ACP e a {nativeLabel} não fala ACP, então o Codeg precisa de um pacote adaptador separado, {adapterPackage}, mantido pelo projeto Agent Client Protocol (originalmente Zed). Ele traz o próprio runtime, então a CLI {nativeCmd} não é pré-requisito; se você já a tem, as duas coexistem e compartilham o login e as configurações de {configDir}. Instale abaixo.", + "readyWithNative": "O adaptador {adapterCmd} está instalado — é ele que o Codeg inicia, não a sua {nativeCmd} em {nativePath}. São pacotes distintos que coexistem e ambos leem {configDir}, então login e configurações são compartilhados.", + "ready": "O adaptador {adapterCmd} está instalado — é ele que o Codeg inicia. Ele traz o próprio runtime, então a {nativeLabel} não é necessária; se instalá-la depois, as duas coexistem e compartilham {configDir}." + }, + "cline": { + "configDescription": "Configure o provedor de API e as credenciais do Cline. As configurações são salvas em ~/.cline/data/." + }, + "opencodePlugins": { + "title": "Plugins do OpenCode", + "declared": "Plugins declarados", + "noPlugins": "Nenhum plugin declarado em opencode.json", + "status": { + "installed": "Instalado", + "missing": "Não instalado" + }, + "installAll": "Instalar todos os ausentes", + "pinVersions": "Fixar versões @latest", + "install": "Instalar", + "uninstall": "Desinstalar", + "refresh": "Atualizar", + "success": "Todos os plugins foram instalados com sucesso", + "failed": "Operação do plugin falhou" + }, + "pi": { + "configManagement": "Configuração do Pi", + "configDescription": "O Pi autentica via a chave de API do seu provedor de modelos. A chave é gravada em ~/.pi/agent/auth.json e a seleção de modelo em settings.json.", + "providerLabel": "Provedor", + "modelLabel": "Modelo", + "thinkingLabel": "Raciocínio", + "thinking": { + "off": "Desligado", + "low": "Baixo", + "medium": "Médio", + "high": "Alto", + "minimal": "Mínimo", + "xhigh": "Muito alto" + }, + "apiKeyLabel": "Chave de API", + "apiKeyHint": "Gravada em ~/.pi/agent/auth.json para o provedor selecionado.", + "apiKeySetPlaceholder": "•••••• (salva — deixe em branco para manter)", + "saveConfig": "Salvar configuração do Pi", + "providerModelRequired": "Provedor e modelo são obrigatórios", + "runtimeTitle": "Tempo de execução", + "runtimeDescription": "Escolha qual binário do pi é executado. Use o padrão ou aponte para sua própria build do pi.", + "modeDefault": "pi padrão", + "modeDefaultHint": "Usa o adaptador pi-acp integrado com o pi no seu PATH. Instale o pi com: npm install -g @earendil-works/pi-coding-agent", + "modeCustom": "pi personalizado", + "modeCustomHint": "Execute sua própria build, instalação ou wrapper do pi.", + "commandLabel": "Comando ou caminho do pi", + "commandHint": "Um caminho absoluto, um nome de comando no PATH ou um script wrapper (ex.: ./pi-test.sh de um monorepo).", + "commandNotFound": "Comando não encontrado", + "validate": "Validar", + "advanced": "Avançado", + "configDirLabel": "Diretório de configuração (PI_CODING_AGENT_DIR)", + "sessionDirLabel": "Diretório de sessões (PI_CODING_AGENT_SESSION_DIR)", + "flagsHint": "O pi-acp não encaminha flags personalizados do pi (--approve, -e, …) — envolva o pi num script e aponte o comando para ele.", + "customIncomplete": "Digite um comando do pi para salvar", + "saveRuntime": "Salvar tempo de execução", + "providerPlaceholder": "Selecionar um provedor", + "customProvider": "Provedor personalizado…", + "providerIdLabel": "ID do provedor", + "apiProtocolLabel": "Protocolo da API", + "baseUrlLabel": "Endpoint da API (Base URL)", + "customProviderHint": "Define um provedor em ~/.pi/agent/models.json para o seu endpoint. A maioria dos servidores auto-hospedados ou proxy usa openai-completions.", + "baseUrlRequired": "O endpoint da API (Base URL) é obrigatório", + "binaryTitle": "binário pi (pi-coding-agent)", + "binaryDescription": "O pi-acp executa este binário pi. Instale-o aqui ou aponte o pi-acp para sua própria build abaixo.", + "binaryInstalled": "Instalado", + "binaryMissing": "Não instalado", + "binaryChecking": "Verificando…", + "installBinary": "Instalar pi", + "installing": "Instalando…", + "recheck": "Verificar novamente", + "configDirSkillsNote": "Com um diretório de configuração personalizado, as habilidades, os especialistas e as ferramentas de escritório gerenciados nas Configurações não se aplicam a este pi — gerencie as habilidades dele diretamente nessa pasta.", + "projectTrustTitle": "Confiança do projeto", + "projectTrustDescription": "Pastas das quais você permitiu que o pi carregue arquivos do projeto. Uma pasta confiável permite que as .pi/extensions daquele repositório executem código ao iniciar o pi, vale para todas as pastas dentro dela e também é usada quando você executa o pi no terminal.", + "projectTrustLoading": "Carregando…", + "projectTrustEmpty": "Nenhuma pasta decidida ainda.", + "projectTrustTrusted": "Confiável", + "projectTrustDenied": "Não confiável", + "projectTrustRevoke": "Revogar", + "reasoningTitle": "Raciocínio", + "reasoningEnableLabel": "Ativar", + "reasoningDescription": "O pi só envia um esforço de raciocínio para um modelo que o declara — num modelo sem declaração, todos os níveis são reduzidos para Off, por isso o seletor do compositor volta atrás assim que se mexe nele. Escrito na entrada deste modelo em models.json.", + "levelsLabel": "Níveis disponíveis", + "levelsHint": "Passam a ser as linhas do seletor de raciocínio do compositor. Escolha os que o seu endpoint aceita; o pi recusa qualquer nível que não esteja aqui.", + "levelsEmptyError": "Escolha pelo menos um nível — sem nenhum, o pi volta para Off.", + "wireValuesTitle": "Avançado: valores enviados ao fornecedor", + "wireValuesHint": "Deixe em branco para enviar o nome do nível tal como está. Defina quando o seu endpoint esperar outra coisa — backends ao estilo Google querem LOW / HIGH.", + "defaultLevelUnlisted": "Este nível não está na lista acima — o pi iria reduzi-lo." + }, + "addCustomAgent": "Adicionar agente personalizado", + "addCustomAgentHint": "Registre qualquer agente compatível com ACP. Escolha um no registro público do ACP ou cole as informações de registro dele.", + "customAgentFromRegistry": "Registro ACP", + "customAgentManual": "Manual", + "customAgentSearchPlaceholder": "Buscar agentes…", + "customAgentLoadingCatalog": "Carregando o registro ACP…", + "customAgentRetry": "Tentar novamente", + "customAgentNoResults": "Nenhum agente correspondente", + "customAgentAdd": "Adicionar", + "customAgentAlreadyAdded": "Adicionado", + "customAgentUnsupportedPlatform": "Nenhuma compilação disponível para esta plataforma", + "customAgentAdded": "{name} adicionado", + "customAgentIdLabel": "ID do registro", + "customAgentNameLabel": "Nome exibido", + "customAgentVersionLabel": "Versão", + "customAgentSpecLabel": "Distribuição (JSON)", + "customAgentSpecHint": "Mesma forma do objeto distribution do registro ACP: canais npx, uvx e binary, ou cole uma entrada completa do registro. Em npx/uvx, cmd é o executável que o pacote instala — derivado do nome do pacote quando omitido, então defina-o quando forem diferentes. binary é organizado por chave de plataforma (esta máquina: {platform}); cmd é o caminho de execução dentro do arquivo e sha256 verifica opcionalmente o download.", + "customAgentTemplateLabel": "Modelos", + "customAgentKindLabel": "Iniciar via", + "customAgentInvalidJson": "JSON inválido", + "customAgentNoDistribution": "Nenhuma distribuição npx, uvx ou binary encontrada", + "customAgentCancel": "Cancelar", + "customAgentSave": "Adicionar agente", + "customAgentSaveChanges": "Salvar alterações", + "customAgentEdit": "Editar agente", + "customAgentEditHint": "Atualize o nome, o ícone, a distribuição e as declarações de skills. O ID do agente não pode ser alterado.", + "customAgentEditNotFound": "Agente personalizado {id} não encontrado", + "customAgentSaved": "{name} salvo", + "customAgentVersionProbeLabel": "Comando de consulta de versão (opcional)", + "customAgentVersionProbeHint": "Comando que imprime a versão instalada localmente. Se ficar vazio, o codeg executa o comando do agente com --version.", + "customAgentRemove": "Remover agente", + "customAgentRemoveHint": "Exclui a definição do agente. As conversas existentes mantêm o histórico; o agente apenas não pode mais ser iniciado.", + "customAgentIconLabel": "Ícone (opcional)", + "customAgentIconUpload": "Enviar", + "customAgentIconReplace": "Substituir", + "customAgentIconClear": "Remover ícone", + "customAgentIconHint": "Salvo junto com o agente, portanto funciona offline. Sem um ícone, usa-se uma inicial colorida.", + "customAgentSkillsLabel": "Skills (.agents/skills compartilhado)", + "customAgentSkillsHint": "Declara que este agente lê o repositório compartilhado .agents/skills (diretórios global e de projeto) e o adiciona a todas as matrizes de habilidades. Habilidades vinculadas lá ficam visíveis para todos os agentes que leem esse repositório compartilhado.", + "customAgentSkillsDirLabel": "Diretório de skills dedicado", + "customAgentSkillsDirHint": "Caminho absoluto do diretório de onde este agente carrega skills — o seu próprio repositório, além do compartilhado ou no lugar dele. ~ expande para o diretório pessoal; skills vinculadas são colocadas aqui primeiro.", + "customAgentMcpLabel": "Suporte a MCP", + "customAgentMcpHint": "Envia o companheiro MCP integrado do codeg para este agente ao iniciar a sessão — o canal por trás da delegação, do feedback ao vivo e das ferramentas de tarefas. Desative para um agente que rejeita servidores MCP e não consegue conectar; a mudança vale a partir da próxima conexão.", + "customAgentIconNotAnImage": "Selecione um arquivo de imagem.", + "customAgentIconTooLarge": "O ícone deve ter menos de {limit} KB.", + "customAgentIconReadFailed": "Não foi possível ler essa imagem.", + "customAgentRemoveConfirm": "Remover {name}? As conversas existentes permanecem, mas o agente não poderá mais ser iniciado.", + "customAgentRemoveWithData": "Excluir também o histórico de conversas registrado", + "customAgentRemoved": "{name} removido", + "customAgentBadge": "Personalizado", + "customAgentNotLaunchable": "Este agente não pode ser iniciado aqui: {reason}" + }, + "SettingsPages": { + "agentsLoading": "Carregando configurações de agentes...", + "skillPacksLoading": "Carregando pacotes de habilidades…" + }, + "GeneralSettings": { + "loading": "Carregando...", + "sectionTitle": "Geral", + "sectionDescription": "Preferências centralizadas para o terminal padrão, aceleração de renderização e delegação multi-agente.", + "terminalTitle": "Terminal padrão", + "terminalDescription": "Escolha o shell usado ao abrir novas abas de terminal pela barra de terminal ou pela árvore de arquivos. Os agentes também o usam quando pedem ao codeg para executar uma linha de comando inteira.", + "terminalSystemDefault": "Padrão do sistema", + "terminalPowerShell7": "PowerShell 7 (pwsh)", + "terminalWindowsPowerShell": "Windows PowerShell", + "terminalCmd": "Prompt de Comando (cmd)", + "terminalSaveFailed": "Falha ao salvar as configurações do terminal: {message}", + "terminalShellCustom": "Caminho personalizado", + "terminalShellCustomPath": "Caminho do shell", + "terminalShellCustomPlaceholder": "/usr/local/bin/fish", + "terminalShellCustomSave": "Salvar", + "terminalShellCustomHint": "Informe um caminho absoluto ou um nome resolvível pelo PATH.", + "terminalShellNotInstalled": "não instalado", + "terminalShellNotFoundWarning": "Este caminho não existe neste host.", + "terminalCurrentShell": "Em uso: {path}", + "renderingDescription": "Desative a aceleração de hardware se o aplicativo apresentar tela preta ou falhas de renderização (comum em certas GPUs AMD ou GPUs Intel integradas). Aplica-se apenas à versão desktop do Windows.", + "disableHardwareAcceleration": "Desativar aceleração de hardware", + "renderingSaveFailed": "Falha ao salvar as configurações de renderização: {message}", + "restartRequired": "Salvo. Reinicie o aplicativo para aplicar a alteração.", + "restartNow": "Reiniciar agora", + "restartFailed": "Falha ao reiniciar: {message}", + "loadFailed": "Falha ao carregar: {message}" + }, + "LoginPage": { + "documentTitle": "Entrar - codeg", + "brand": "Codeg", + "subtitle": "Digite seu token de acesso para conectar ao aplicativo de desktop", + "tokenPlaceholder": "Token de acesso", + "connect": "Conectar", + "connecting": "Conectando...", + "helpText": "Encontre seu token no app de desktop em Configurações → Serviço Web", + "invalidToken": "Token inválido. Verifique e tente novamente.", + "connectionFailed": "Falha na conexão (HTTP {status})", + "networkError": "Não foi possível conectar ao servidor" + }, + "CommitPage": { + "title": "Confirmar", + "invalidFolderId": "ID de pasta inválido", + "loadingRepo": "Carregando repositório..." + }, + "MergePage": { + "title": "Resolver conflitos", + "invalidFolderId": "ID de pasta inválido", + "loadingRepo": "Carregando repositório...", + "localVersion": "Local (Nosso)", + "result": "Resultado", + "remoteVersion": "Remoto (Deles)", + "acceptLocal": "Aceitar local", + "acceptRemote": "Aceitar remoto", + "markResolved": "Marcar como resolvido", + "abortMerge": "Abortar", + "completeMerge": "Concluir merge", + "unresolvedConflicts": "Ainda há marcadores de conflito não resolvidos neste arquivo", + "fileResolved": "Arquivo resolvido com sucesso", + "allResolved": "Todos os conflitos resolvidos", + "conflictFiles": "Arquivos em conflito", + "loadingFile": "Carregando arquivo...", + "preparingMerge": "Preparando mesclagem...", + "selectFile": "Selecione um arquivo para resolver", + "noConflicts": "Nenhum arquivo em conflito", + "skipFile": "Pular", + "abortSuccess": "Operação abortada", + "applyAllNonConflicting": "Aplicar todas as alterações sem conflito", + "applyLeftNonConflicting": "Aplicar local", + "applyRightNonConflicting": "Aplicar remoto" + }, + "ImportSessions": { + "title": "Importar sessões locais", + "scanningTitle": "Verificando sessões locais dos agentes…", + "scanningHint": "Percorrendo o armazenamento local de sessões de cada agente. Históricos grandes podem levar um momento. As sessões já importadas são atualizadas no processo.", + "scanFailed": "Falha na verificação", + "retry": "Tentar novamente", + "rescan": "Verificar novamente", + "empty": "Nenhuma sessão local encontrada", + "emptyHint": "Nenhum armazenamento de sessões de agentes foi encontrado nesta máquina.", + "noMatches": "Nenhuma sessão corresponde aos filtros atuais", + "searchPlaceholder": "Pesquisar título ou caminho…", + "allAgents": "Todos os agentes", + "onlyImportable": "Somente importáveis", + "selectAll": "Selecionar tudo", + "clearSelection": "Limpar", + "expandAll": "Expandir tudo", + "collapseAll": "Recolher tudo", + "summaryCounts": "{total} sessões · {importable} importáveis · {folders} pastas", + "noFolderSkipped": "{count} sem pasta de projeto ignoradas", + "folderNew": "Nova", + "folderCounts": "{importable}/{total} importáveis", + "toggleFolderAria": "Selecionar todas as sessões importáveis de {name}", + "toggleSessionAria": "Selecionar a sessão {title}", + "statusImported": "Importada", + "statusDeleted": "Excluída", + "untitled": "Sessão sem título", + "messageCount": "{count} mensagens", + "selectedCount": "{count} selecionadas", + "importSelected": "Importar seleção", + "importing": "Importando…", + "close": "Fechar", + "doneTitle": "Importação concluída", + "doneImported": "Importadas", + "doneUpdated": "Atualizadas", + "doneSkipped": "Ignoradas", + "doneCreatedFolders": "Pastas criadas", + "doneNotFound": "Não encontradas", + "doneFailed": "Falharam", + "continueImport": "Continuar importando", + "toasts": { + "importFailed": "Falha ao importar: {message}" + } + }, + "Folder": { + "workspaceStatus": { + "degradedTitle": "Atualizações em tempo real indisponíveis", + "degradedHint": "O observador falhou ao iniciar (por exemplo, permissão negada). Atualize manualmente para ver as mudanças.", + "retry": "Tentar novamente", + "retrying": "Tentando novamente..." + }, + "common": { + "all": "Todos", + "cancel": "Cancelar", + "close": "Fechar", + "closeOthers": "Fechar outros", + "closeAll": "Fechar tudo", + "confirm": "Confirmar", + "save": "Salvar", + "delete": "Excluir", + "rename": "Renomear", + "loading": "Carregando...", + "refresh": "Atualizar", + "refreshing": "Atualizando...", + "create": "Criar", + "createAndSwitch": "Criar e alternar", + "openFile": "Abrir arquivo", + "viewDiff": "Ver Diff", + "push": "Enviar..." + }, + "statusLabels": { + "in_progress": "Em andamento", + "pending_review": "Revisão", + "completed": "Concluído", + "cancelled": "Cancelado" + }, + "sidebar": { + "title": "Conversas", + "locateActiveConversation": "Localizar conversa ativa", + "expandAllGroups": "Expandir todos os grupos", + "collapseAllGroups": "Recolher todos os grupos", + "newConversation": "Nova conversa", + "newConversationShort": "Nova", + "newChat": "Nova conversa", + "search": "Buscar", + "noConversationsFound": "Nenhuma conversa encontrada.", + "importLocalSessions": "Importar sessões locais", + "importing": "Importando...", + "error": "Erro: {message}", + "completeAllSessions": "Concluir todas as sessões", + "completeAllReviewTitle": "Concluir todas as sessões em revisão?", + "completeAllReviewDescription": "Isso marcará como concluídas todas as {count, plural, one {# sessão} other {# sessões}} em Revisão.", + "completing": "Concluindo...", + "toasts": { + "importedSessions": "Importadas {imported, plural, one {# sessão} other {# sessões}}, ignoradas {skipped}", + "importedAndUpdated": "Importadas {imported, plural, one {# sessão} other {# sessões}}, atualizados {updated, plural, one {# título} other {# títulos}}, ignoradas {skipped}", + "updatedTitles": "Atualizados {updated, plural, one {# título} other {# títulos}}, ignoradas {skipped}", + "noNewSessionsFound": "Nenhuma nova sessão encontrada (ignoradas {skipped})", + "importFailed": "Falha na importação: {message}", + "reviewCompleted": "Marcadas {count, plural, one {# sessão em revisão} other {# sessões em revisão}} como concluídas", + "completeReviewFailed": "Falha ao concluir sessões em revisão: {message}", + "folderOpened": "Pasta {name} aberta", + "folderRemoved": "Pasta {name} removida", + "openFolderFailed": "Falha ao abrir pasta", + "removeFolderFailed": "Falha ao remover pasta: {message}", + "reorderFoldersFailed": "Falha ao reordenar pastas: {message}", + "changeFolderColorFailed": "Falha ao alterar a cor: {message}", + "setFolderAliasFailed": "Falha ao definir o alias: {message}", + "changeFolderDefaultAgentFailed": "Falha ao definir agente padrão: {message}" + }, + "statsLabel": "{folders} pastas · {convos} conversas", + "reorderHandle": "Arraste para reordenar", + "openFolder": "Abrir pasta", + "searchPlaceholder": "Buscar conversas...", + "viewOptions": "Opções de exibição", + "showCompleted": "Mostrar conversas concluídas", + "showWorktrees": "Mostrar pastas de worktree", + "showRecent": "Mostrar grupo Recentes", + "moreOptions": "Mais opções", + "sortBy": "Ordenar por", + "sortByCreatedAt": "Data de criação", + "sortByUpdatedAt": "Data de atualização", + "sectionOrder": "Ordem das seções", + "sectionOrderMoveUp": "Mover para cima", + "sectionOrderMoveDown": "Mover para baixo", + "sectionOrderItemLabel": "{name} — posição {position} de {total}", + "statusRunningBadge": "Executando", + "runningCountBadge": "{count, plural, one {# sessão em execução} other {# sessões em execução}}", + "statusCancelledBadge": "Cancelado", + "worktreeRemovedBadge": "Worktree de origem removida", + "conversationCountUnit": "{count, plural, one {# conversa} other {# conversas}}", + "emptyFolderHint": "Sem conversas", + "noMatchingConversations": "Nenhuma conversa correspondente", + "noUnfinishedConversations": "Nenhuma conversa pendente. Ative \"Mostrar concluídas\" no menu superior direito.", + "removeFolderConfirmTitle": "Remover pasta do espaço de trabalho?", + "removeFolderConfirmDescription": "Remover \"{name}\" do espaço de trabalho? As abas e terminais relacionados serão fechados.", + "folderHeaderMenu": { + "manageConversations": "Gerenciar conversas…", + "manageLinks": "Pastas vinculadas", + "changeColor": "Alterar cor", + "useThemeColor": "Usar tema do app", + "setDefaultAgent": "Definir agente padrão", + "defaultAgentNone": "Sem padrão (usar global)", + "agentUnavailableSuffix": "(indisponível)", + "loadingAgents": "Carregando agentes…", + "setAlias": "Definir alias…", + "setAliasTitle": "Definir alias da pasta", + "setAliasPlaceholder": "Insira um alias (deixe vazio para limpar)", + "setAliasSave": "Salvar", + "setAliasCancel": "Cancelar", + "removeFromWorkspace": "Remover do espaço de trabalho" + }, + "manageConversations": { + "title": "Gerenciar conversas", + "searchPlaceholder": "Pesquisar por título…", + "agentFilterAll": "Todos os agentes", + "statusFilterAll": "Todos os status", + "folderFilterAll": "Todas as pastas", + "branchFilterAll": "Todas as branches", + "branchNone": "Sem branch", + "branchSearchPlaceholder": "Pesquisar branches…", + "noMatchingBranches": "Nenhuma branch correspondente", + "selectAllVisible": "Selecionar tudo", + "deselectAll": "Desmarcar tudo", + "selectedCount": "{count} selecionada(s)", + "matchedCount": "{count} correspondência(s)", + "untitledConversation": "Conversa sem título", + "setStatus": "Definir status…", + "deleteSelected": "Excluir", + "noConversations": "Sem conversas nesta pasta.", + "noConversationsWorkspace": "Sem conversas na área de trabalho.", + "noMatchingConversations": "Nenhuma conversa corresponde aos filtros.", + "confirmDeleteTitle": "Excluir {count} conversa(s)?", + "confirmDeleteDescription": "Esta ação não pode ser desfeita.", + "toastDeleted": "{count} conversa(s) excluída(s)", + "toastStatusUpdated": "Status atualizado para {count} conversa(s)", + "toastOpFailed": "Falha na operação: {message}" + }, + "sectionPinned": "Fixadas", + "sectionFolders": "Pastas", + "sectionChats": "Chat", + "sectionRecent": "Recentes", + "noChats": "Sem chats", + "noRecent": "Sem conversas recentes", + "showMoreRecent": "Mostrar mais ({count})", + "noFolders": "Nenhuma pasta aberta", + "newChatAction": "Novo chat", + "automations": "Automações", + "tasks": "Tarefas a fazer", + "loadingSubsessions": "Carregando subconversas…" + }, + "conversation": { + "reloadFailed": "Falha ao recarregar conversa: {message}", + "reloaded": "Conversa recarregada", + "reload": "Recarregar", + "activeConversationIndicator": "Conversa ativa", + "newConversation": "Nova conversa", + "closeConversation": "Fechar conversa", + "copyText": "Copiar texto", + "copyTextSuccess": "Copiado", + "copyTextFailed": "Falha ao copiar", + "forkSession": "Bifurcar sessão", + "forkSessionSuccess": "Sessão bifurcada com sucesso", + "forkSessionFailed": "Falha ao bifurcar a sessão: {error}", + "exportConversation": "Exportar conversa", + "exportImage": "Imagem", + "exportMarkdown": "Markdown", + "exportHtml": "HTML", + "exportSuccess": "Conversa exportada", + "exportFailed": "Falha ao exportar", + "exportImageTooLong": "A conversa é muito longa para exportar como imagem", + "exportLabels": { + "untitledConversation": "Conversa sem título", + "agent": "Agente", + "model": "Modelo", + "status": "Estado", + "started": "Início", + "updated": "Atualizado", + "tokens": "Estatísticas de tokens", + "duration": "Duração", + "inputTokens": "Entrada", + "outputTokens": "Saída", + "cacheRead": "Cache lido", + "cacheWrite": "Cache escrito", + "user": "Utilizador", + "assistant": "Assistente", + "system": "Sistema", + "toolResult": "Resultado", + "toolError": "Erro" + }, + "moreActions": "Mais ações" + }, + "sessionDetails": { + "menuLabel": "Detalhes da sessão", + "noActiveSession": "Nenhuma sessão ativa", + "title": "Detalhes da sessão", + "subtitle": "Metadados da sessão e uso de tokens", + "fieldTitle": "Título", + "untitled": "Conversa sem título", + "sessionId": "ID da sessão", + "externalId": "ID da extensão", + "agent": "Agente", + "model": "Modelo", + "status": "Estado", + "gitBranch": "Branch do Git", + "parentId": "Sessão principal", + "tokensHeading": "Uso de tokens", + "totalTokens": "Total", + "inputTokens": "Entrada", + "outputTokens": "Saída", + "cacheWrite": "Cache escrito", + "cacheRead": "Cache lido", + "contextWindow": "Janela de contexto", + "duration": "Duração", + "loadingStats": "Carregando uso de tokens…", + "loadFailed": "Falha ao carregar o uso de tokens", + "noStats": "Nenhum uso registrado", + "timestampsHeading": "Carimbos de data/hora", + "createdAt": "Criado", + "updatedAt": "Atualizado", + "none": "—", + "copyField": "Copiar {field}", + "copiedField": "{field} copiado" + }, + "conversationCard": { + "untitledConversation": "Conversa sem título", + "newConversation": "Nova conversa", + "rename": "Renomear", + "status": "Status", + "delete": "Excluir", + "importLocalSessions": "Importar sessões locais", + "importing": "Importando...", + "renameConversation": "Renomear conversa", + "deleteConversationTitle": "Excluir conversa?", + "deleteConversationDescription": "Isso excluirá \"{title}\". Esta ação não pode ser desfeita.", + "cancel": "Cancelar", + "save": "Salvar", + "pin": "Fixar", + "unpin": "Desafixar", + "markCompleted": "Marcar como concluída", + "reopen": "Reabrir", + "expandSubsessions": "Expandir subconversas", + "collapseSubsessions": "Recolher subconversas" + }, + "search": { + "dialogTitle": "Buscar", + "dialogTitleWithFolder": "Buscar — {name}", + "tabConversations": "Conversas", + "tabFiles": "Arquivos", + "placeholder": "Buscar conversas...", + "filePlaceholder": "Buscar arquivos ou diretórios...", + "allAgents": "Todos", + "searching": "Buscando...", + "typeToSearch": "Digite para buscar conversas", + "typeToSearchFiles": "Digite para buscar arquivos ou diretórios", + "noResults": "Nenhum resultado encontrado.", + "untitledConversation": "Conversa sem título" + }, + "folderTitleBar": { + "showSidebar": "Mostrar barra lateral", + "hideSidebar": "Ocultar barra lateral", + "toggleTerminal": "Alternar terminal", + "toggleAuxPanel": "Alternar painel auxiliar", + "search": "Buscar", + "openSettings": "Abrir configurações", + "backToConversations": "Voltar às conversas", + "withShortcut": "{label} (atalho: {shortcut})" + }, + "statusBar": { + "connection": { + "connected": "Conectado", + "connecting": "Conectando...", + "prompting": "Respondendo...", + "error": "Erro de conexão", + "disconnected": "Desconectado", + "tooltip": "{agent}: {status}", + "tooltipError": "{agent}: {error}", + "title": "Conexão do agente", + "triggerAria": "Conexão do agente: {status}", + "workingDir": "Diretório de trabalho", + "sessionId": "ID da sessão", + "viewerNote": "Anexado a uma sessão de outro cliente — reconectar apenas reanexa esta visualização.", + "reconnectInterrupts": "Reconectar reinicia o agente e interrompe o trabalho em andamento.", + "reconnect": "Reconectar", + "reconnecting": "Reconectando...", + "reconnectUnavailable": "Ainda não há sessão para reconectar." + }, + "tasks": { + "title": "Tarefas" + }, + "alerts": { + "title": "Alertas", + "empty": "Sem alertas", + "details": "Detalhes" + }, + "stats": { + "conversations": "{count} conversas", + "openUsage": "Ver estatísticas de sessões e uso de tokens" + }, + "tokens": { + "contextWindowUsageAria": "Uso da janela de contexto", + "contextWindow": "Janela de contexto", + "usedMax": "Usado / Máx", + "tokenUsage": "Uso de tokens", + "input": "Entrada", + "output": "Saída", + "cacheRead": "Leitura de cache", + "cacheWrite": "Gravação de cache", + "total": "Total de tokens" + } + }, + "auxPanel": { + "tabs": { + "files": "Arquivos", + "changes": "Alterações", + "commits": "Confirmações" + }, + "noFolderTitle": "Nenhuma pasta aberta", + "noFolderHint": "Abra uma pasta para ver seu conteúdo aqui" + }, + "windowControls": { + "minimizeWindow": "Minimizar janela", + "minimize": "Minimizar", + "maximizeWindow": "Maximizar janela", + "maximize": "Maximizar", + "restoreWindow": "Restaurar janela", + "restore": "Restaurar", + "closeWindow": "Fechar janela", + "close": "Fechar" + }, + "tabs": { + "closeConversationTab": "Fechar aba de conversa", + "close": "Fechar", + "closeOthers": "Fechar outros", + "splitRight": "Dividir à direita", + "splitDown": "Dividir abaixo", + "splitAndMoveRight": "Dividir e mover para a direita", + "splitAndMoveDown": "Dividir e mover para baixo", + "moveToOppositeGroup": "Mover para o grupo oposto", + "moveToGroup": "Mover para o grupo", + "groupLabel": "Grupo {index}", + "changeSplitterOrientation": "Alternar orientação do divisor", + "unsplit": "Desfazer divisão", + "unsplitAll": "Desfazer todas as divisões", + "closeAll": "Fechar tudo", + "tileDisplay": "Exibição em mosaico", + "untileDisplay": "Sair do mosaico" + }, + "fileWorkspace": { + "files": "Arquivos", + "closeFileTab": "Fechar aba de arquivo", + "close": "Fechar", + "closeOthers": "Fechar outros", + "closeAll": "Fechar tudo", + "preview": "Visualizar", + "editSource": "Editar fonte", + "maximize": "Maximizar", + "restore": "Restaurar", + "emptyDirectory": "Pasta vazia" + }, + "terminal": { + "rename": "Renomear", + "close": "Fechar", + "closeOthers": "Fechar outros", + "closeAll": "Fechar tudo", + "hideTerminal": "Ocultar terminal ({shortcut})", + "openFolderFirst": "Abra primeiro uma pasta" + }, + "workspaceDialog": { + "title": "Abrir pasta", + "manageTitle": "Pastas vinculadas", + "addTargetsTitle": "Adicionar pastas para vincular", + "pickRootDescription": "Escolha a pasta principal deste espaço de trabalho.", + "linksDescription": "Vincule outras pastas como subdiretórios para que os agentes trabalhem em todas elas a partir de um único espaço de trabalho.", + "addTargetsDescription": "Selecione uma ou mais pastas. Cada uma vira um subdiretório do espaço de trabalho.", + "useSystemPicker": "Seletor do sistema", + "next": "Avançar", + "back": "Voltar", + "done": "Concluir", + "change": "Alterar", + "addFolders": "Adicionar pastas", + "addSelected": "Adicionar", + "addSelectedCount": "Adicionar {count}", + "createCount": "Vincular {count} pasta(s)", + "discardPending": "Descartar", + "noLinks": "Ainda não há pastas vinculadas.", + "gitExclude": "Manter os vínculos fora do status do git", + "rename": "Renomear", + "unlink": "Remover vínculo", + "repair": "Recriar vínculo", + "saveName": "Salvar", + "cancelRename": "Cancelar", + "removePending": "Remover", + "willAppearAs": "Aparece como {name} no espaço de trabalho", + "renamedForDuplicate": "Renomeada — {base} já é usada por outro vínculo", + "renamedForExistingEntry": "Renomeada — {base} já existe nesta pasta", + "partiallyCreated": "Apenas {count} pasta(s) puderam ser vinculadas", + "openFailed": "Falha ao abrir a pasta", + "previewFailed": "Falha ao verificar as pastas selecionadas", + "createFailed": "Falha ao vincular as pastas", + "renameFailed": "Falha ao renomear o vínculo", + "removeFailed": "Falha ao remover o vínculo", + "repairFailed": "Falha ao recriar o vínculo", + "status": { + "ok": "Vinculada", + "missing": "O vínculo sumiu desta pasta", + "conflicted": "Outra entrada usa esse nome agora", + "broken": "A pasta vinculada não existe mais" + }, + "nameIssue": { + "empty": "Digite um nome", + "illegalChars": "Não pode conter / \\ : * ? \" < > |", + "tooLong": "Nome muito longo", + "reserved": "Este nome é reservado pelo Windows", + "duplicate": "Este nome já está em uso" + }, + "rejection": { + "not_found": "Pasta não encontrada", + "not_a_directory": "Este caminho não é uma pasta", + "same_as_root": "É a própria pasta do espaço de trabalho", + "ancestor_of_root": "Esta pasta contém o espaço de trabalho", + "inside_root": "Já está dentro do espaço de trabalho", + "already_linked": "Já vinculada", + "name_unavailable": "Não há mais nomes livres para esta pasta", + "alreadyLinkedAs": "Já vinculada como {name}" + } + }, + "folderNameDropdown": { + "fallbackFolderName": "Pasta", + "openFolder": "Abrir pasta", + "cloneRepository": "Clonar repositório", + "projectBoot": "Inicializador de projeto", + "opened": "Aberto", + "recentOpen": "Abertos recentemente" + }, + "fileWorkspacePanel": { + "addSelectionToChat": "Adicionar seleção ao chat", + "addToChat": "Adicionar ao chat", + "addSelectionToChatDone": "{label} adicionado à conversa", + "addFileToChat": "Adicionar arquivo ao chat", + "toggleWordWrap": "Alternar quebra de linha", + "addFileToChatDone": "{label} adicionado à conversa", + "viewDiff": "Ver Diff", + "openFile": "Abrir arquivo", + "fileCount": "{count, plural, one {# arquivo} other {# arquivos}}", + "openFileOrDiff": "Abra um arquivo ou diff pelo painel direito", + "disk": "Disco", + "head": "HEAD", + "unsaved": "Não salvo", + "workingTree": "Árvore de trabalho", + "loading": "Carregando...", + "compareWithBranch": "{path} · comparar com {branch}", + "hunkCount": "{count, plural, one {# bloco} other {# blocos}}", + "prev": "Anterior", + "next": "Próximo", + "jumpToLine": "Ir para a linha {line}", + "noParsedDiffSections": "Sem seções de diff analisadas", + "loadingEditor": "Carregando editor...", + "imageZoomIn": "Ampliar", + "imageZoomOut": "Reduzir", + "imageZoomReset": "Redefinir zoom", + "htmlPreviewTitle": "Visualização HTML", + "htmlPreviewTrust": "Ativar scripts", + "htmlPreviewTrustHint": "Executa os scripts deste arquivo e permite acesso à rede. Ative apenas para arquivos confiáveis.", + "officePreviewTitle": "Pré-visualização de documento do Office", + "officeFullRender": "Renderização completa", + "officeFullRenderHint": "Renderiza animações Morph, 3D e fórmulas (executa os scripts do próprio slide)", + "officeNotInstalled": "OfficeCLI não está instalado", + "officeNotInstalledHint": "Instale o OfficeCLI em Configurações → Ferramentas do Office para pré-visualizar arquivos do Word, Excel e PowerPoint.", + "officeOpenSettings": "Abrir configurações", + "officeWatchFailed": "Não foi possível iniciar a visualização ao vivo", + "officeWatchRetry": "Tentar novamente", + "officeServerInstallHint": "O OfficeCLI precisa estar instalado no host do servidor. Execute este comando lá e tente novamente:", + "officeRemoteDesktopUnsupported": "A pré-visualização ao vivo não está disponível em uma janela de área de trabalho remota. Abra este espaço de trabalho na interface web do servidor para visualizar arquivos do Office." + }, + "branchDropdown": { + "toasts": { + "commitCodeCompleted": "Commit de código concluído", + "pushCodeCompleted": "Push de código concluído", + "committedFiles": "{count, plural, one {# arquivo commitado} other {# arquivos commitados}}", + "taskCompleted": "{label} concluído", + "taskFailed": "{label} falhou", + "mergeNoNewCommits": "{branchName} não tem novos commits", + "mergedCommits": "{count, plural, one {# commit mesclado} other {# commits mesclados}}", + "allFilesUpToDate": "Todos os arquivos estão atualizados", + "updatedFiles": "{count, plural, one {# arquivo atualizado} other {# arquivos atualizados}}", + "openCommitWindowFailed": "Falha ao abrir a janela de commit", + "openPushWindowFailed": "Falha ao abrir janela de envio", + "upstreamSet": "A branch upstream foi definida", + "upstreamSetAndPushed": "Branch upstream definida e {count, plural, one {# commit} other {# commits}} enviado(s)", + "noCommitsToPush": "Não há commits para enviar", + "pushedCommits": "{count, plural, one {# commit enviado} other {# commits enviados}}", + "switchedToFolder": "Alternado para {name}", + "switchFailed": "Falha ao trocar de branch", + "openStashWindowFailed": "Falha ao abrir a janela de stash" + }, + "tasks": { + "newBranch": "Criar branch {name}", + "newWorktree": "Criar worktree {name}", + "checkoutTo": "Fazer checkout para {branchName}", + "mergeBranch": "Mesclar {branchName}", + "rebaseTo": "Rebase para {branchName}", + "deleteRemoteBranch": "Excluir branch remoto {branchName}", + "initGitRepo": "Inicializar repositório Git", + "pullCode": "Fazer pull do código", + "fetchInfo": "Buscar informações", + "pushCode": "Enviar código", + "stashChanges": "Fazer stash das alterações", + "stashPop": "Aplicar stash", + "deleteBranch": "Excluir branch {branchName}", + "removeWorktree": "Excluir o worktree de {branchName}", + "removeWorktreeAndBranch": "Excluir o worktree e o branch {branchName}", + "updateBranch": "Atualizar o branch {branchName}" + }, + "confirm": { + "mergeTitle": "Mesclar branch", + "rebaseTitle": "Rebase da branch", + "mergeDescription": "Mesclar {branchName} na branch atual {currentBranch}?", + "rebaseDescription": "Fazer rebase da branch atual {currentBranch} sobre {branchName}?", + "deleteRemoteTitle": "Excluir branch remoto", + "deleteRemoteDescription": "Excluir o branch remoto {branchName}? Isso o removerá do repositório remoto e não poderá ser desfeito.", + "deleteTitle": "Excluir branch", + "deleteDescription": "Excluir a branch {branchName}? Esta ação não pode ser desfeita.", + "forceDeleteTitle": "Forçar exclusão do branch", + "forceDeleteDescription": "O branch {branchName} não está totalmente mesclado. Tem certeza de que deseja forçar a exclusão? Esta ação não pode ser desfeita.", + "deleteWorktreeTitle": "Excluir worktree", + "deleteWorktreeDescription": "Excluir o diretório do worktree onde {branchName} está em uso? O branch e seus commits são mantidos.", + "forceDeleteWorktreeTitle": "Forçar a exclusão do worktree", + "forceDeleteWorktreeDescription": "O worktree de {branchName} tem arquivos não commitados ou não rastreados. Excluir mesmo assim? Essas alterações não poderão ser recuperadas.", + "deleteWorktreeAndBranchTitle": "Excluir worktree e branch", + "deleteWorktreeAndBranchDescription": "Excluir o worktree de {branchName}, o próprio branch e a pasta dele no espaço de trabalho? As sessões passam para a pasta do repositório. Esta ação não pode ser desfeita.", + "forceDeleteWorktreeAndBranchTitle": "Forçar a exclusão do worktree e do branch", + "forceDeleteWorktreeAndBranchDescription": "O worktree de {branchName} tem arquivos não commitados, ou o branch não está totalmente mesclado. Excluir os dois mesmo assim? Esta ação não pode ser desfeita." + }, + "current": "Atual", + "switchToBranch": "Mudar para esta branch", + "mergeBranchIntoCurrent": "Mesclar {branchName} em {currentBranch}", + "rebaseCurrentToBranch": "Rebase de {currentBranch} sobre {branchName}", + "noBranch": "Sem ramo", + "detachedHead": "HEAD desanexado em {sha}", + "initGitRepo": "Inicializar repositório Git", + "pullCode": "Fazer pull do código", + "fetchRemoteBranches": "Buscar branches remotas", + "openCommitWindow": "Commit de código...", + "pushCode": "Enviar...", + "pushBranch": "Enviar", + "newBranch": "Nova branch...", + "newWorktree": "Novo worktree...", + "stashChanges": "Guardar alterações...", + "stashPop": "Aplicar stash...", + "manageRemotes": "Gerenciar remotos...", + "localBranches": "Branches locais ({count, plural, one {#} other {#}})", + "noLocalBranches": "Sem branches locais", + "remoteBranches": "Branches remotas ({count, plural, one {#} other {#}})", + "noRemoteBranches": "Sem branches remotas", + "dialogs": { + "newBranchTitle": "Nova branch", + "newBranchDescription": "Criar uma nova branch a partir da branch atual {branch}", + "branchNamePlaceholder": "Nome da branch", + "newWorktreeTitle": "Novo worktree", + "newWorktreeDescription": "Criar um novo worktree a partir da branch atual {branch}", + "branchNameLabel": "Nome da branch", + "worktreePathLabel": "Caminho do worktree", + "worktreePathPlaceholder": "Caminho do worktree", + "manageRemotesTitle": "Gerenciar remotos", + "manageRemotesEmpty": "Nenhum remoto configurado", + "remoteNamePlaceholder": "Nome do remoto", + "remoteUrlPlaceholder": "URL do remoto", + "addRemote": "Adicionar", + "savingRemotes": "Salvando..." + }, + "conflict": { + "title": "Conflitos de merge", + "description": "Os seguintes arquivos têm conflitos que precisam ser resolvidos:", + "abort": "Abortar merge", + "openMergeTool": "Abrir ferramenta de merge", + "completeMerge": "Concluir merge", + "abortSuccess": "Merge abortado com sucesso", + "completeSuccess": "Merge concluído com sucesso" + }, + "stashDialog": { + "title": "Guardar alterações no stash", + "description": "Guardar as alterações atuais no stash", + "messageLabel": "Mensagem", + "messagePlaceholder": "Mensagem do stash (opcional)", + "keepIndex": "Manter índice (alterações preparadas permanecem preparadas)", + "cancel": "Cancelar", + "stash": "Guardar", + "success": "Alterações guardadas no stash", + "error": "Erro ao guardar no stash" + }, + "unstashDialog": { + "title": "Aplicar stash", + "noStashes": "Nenhum stash encontrado", + "selectFile": "Selecione um ficheiro para ver diferenças", + "viewDiff": "Ver diferenças", + "original": "Original", + "modified": "Modificado", + "apply": "Aplicar", + "drop": "Eliminar", + "applySuccess": "Stash aplicado", + "dropSuccess": "Stash eliminado", + "confirmApply": "Aplicar stash {ref} ao diretório de trabalho?", + "cancel": "Cancelar" + }, + "deleteBranch": "Excluir branch", + "deleteWorktree": "Excluir worktree", + "deleteWorktreeAndBranch": "Excluir worktree e branch", + "searchPlaceholder": "Pesquisar ramos e ações", + "searchAriaLabel": "Pesquisar ramos e ações", + "branchListLabel": "Ramos e ações", + "noMatches": "Nenhuma correspondência" + }, + "commitDialog": { + "toasts": { + "commitCompleted": "Commit de código concluído", + "pushFailed": "Falha no envio", + "committedFiles": "{count, plural, one {# arquivo commitado} other {# arquivos commitados}}", + "addedToVcs": "Adicionado ao VCS", + "addToVcsFailed": "Falha ao adicionar ao VCS", + "fileDeleted": "Arquivo excluído", + "deleteFailed": "Falha ao excluir", + "fileRolledBack": "Arquivo revertido", + "rollbackFailed": "Falha no rollback", + "dirRolledBack": "Diretório revertido", + "dirDeleted": "Diretório excluído" + }, + "confirm": { + "deleteTitle": "Confirmar exclusão", + "deleteDescription": "Excluir o arquivo \"{file}\"? Esta ação não pode ser desfeita.", + "rollbackTitle": "Confirmar rollback", + "rollbackDescription": "Reverter o arquivo \"{file}\" para o HEAD? Alterações não salvas serão perdidas.", + "rollbackDirDescription": "Reverter o diretório \"{dir}\" para HEAD? Alterações não salvas serão perdidas.", + "deleteDirDescription": "Excluir o diretório \"{dir}\"? Esta ação não pode ser desfeita." + }, + "actions": { + "select": "Selecionar", + "unselect": "Desmarcar", + "rollback": "Reverter", + "addToVcs": "Adicionar ao VCS" + }, + "aria": { + "selectFile": "{action}: {path}", + "unselectAllFiles": "Desmarcar todos os arquivos", + "selectAllFiles": "Selecionar todos os arquivos", + "unselectTracked": "Desmarcar alterações rastreadas", + "selectTracked": "Selecionar alterações rastreadas", + "unselectUntracked": "Desmarcar arquivos não rastreados", + "selectUntracked": "Selecionar arquivos não rastreados" + }, + "loading": "Carregando...", + "selectionCount": "{selected} / {total} arquivos", + "emptyFiles": "Sem arquivos alterados", + "trackedChanges": "Alterações rastreadas ({count})", + "untrackedFiles": "Arquivos não rastreados ({count})", + "commitMessage": "Mensagem de commit", + "commitMessagePlaceholder": "Digite a mensagem de commit...", + "commitButton": "Confirmar ({count})", + "commitAndPushButton": "Confirmar e enviar ({count})", + "head": "HEAD", + "workingTree": "Árvore de trabalho", + "clickFileToDiff": "Clique no nome do arquivo para ver o diff", + "loadingDiff": "Carregando diff..." + }, + "pushWindow": { + "title": "Enviar código", + "noUnpushedCommits": "Nenhum commit não enviado", + "noRemoteConfigured": "Nenhum remoto Git configurado\nAdicione um em «Gerenciar remotos»", + "newBranchNoPushedCommits": "Nova branch — enviar para criar branch de rastreamento remota", + "unpushed": "Não enviado", + "selectFileToViewDiff": "Selecione um arquivo para ver as diferenças", + "before": "Antes", + "after": "Depois", + "push": "Enviar", + "toasts": { + "pushSuccess": "Envio bem-sucedido", + "pushFailed": "Falha no envio", + "upstreamSet": "Branch remoto foi configurado", + "upstreamSetAndPushed": "Branch remoto configurado e {count} commits enviados", + "noCommitsToPush": "Nenhum commit para enviar", + "pushedCommits": "{count} commits enviados" + } + }, + "gitLogTab": { + "filesTitle": "Arquivos", + "expandAllFiles": "Expandir todos os arquivos", + "collapseAllFiles": "Recolher todos os arquivos", + "workspace": "espaço de trabalho", + "retry": "Tentar novamente", + "noCommitsFound": "Nenhum commit encontrado", + "notAGitRepoTitle": "Não é um repositório Git", + "notAGitRepoHint": "Inicialize o Git pelo menu de ramificações acima, ou abra um repositório existente.", + "hash": "Hash do commit", + "copyHash": "Copiar hash", + "copyMessage": "Copiar mensagem", + "showMore": "Mostrar mais", + "showLess": "Mostrar menos", + "author": "Autor", + "noFileChangeDetails": "Sem detalhes de alteração de arquivos disponíveis.", + "loadingFiles": "Carregando arquivos...", + "branchesTitle": "Branches Git", + "loadingBranches": "Carregando branches...", + "noContainingBranches": "Nenhuma branch contendo este commit foi encontrada.", + "newBranch": "Nova branch...", + "resetToHere": "Resetar para aqui", + "resetDisabledReasonNotCurrentBranchView": "Disponível somente ao visualizar a branch atual", + "copyFullCommitHashAria": "Copiar hash completo do commit {hash}", + "pushStatus": { + "pushed": "Enviado para o remoto", + "notPushed": "Não enviado para o remoto", + "unknown": "Status de push desconhecido (upstream não configurado)" + }, + "time": { + "monthsAgo": "{count, plural, one {há # mês} other {há # meses}}", + "daysAgo": "{count, plural, one {há # dia} other {há # dias}}", + "hoursAgo": "{count, plural, one {há # hora} other {há # horas}}", + "minsAgo": "{count, plural, one {há # min} other {há # mins}}", + "justNow": "agora mesmo" + }, + "toasts": { + "createdAndSwitchedNewBranch": "Nova branch criada e selecionada", + "newBranchFromCommit": "{name} (de {shortHash})", + "createBranchFailed": "Falha ao criar branch", + "openPushWindowFailed": "Falha ao abrir a janela de push", + "resetSuccess": "Reset concluído", + "resetSuccessDescription": "{branch} foi resetada para {shortHash} com {mode}", + "resetFailed": "Falha no reset" + }, + "authorFilter": { + "label": "Autor", + "searchPlaceholder": "Pesquisar autor", + "noAuthors": "Nenhum autor encontrado", + "you": "você", + "filterByAuthorAria": "Filtrar commits por autor", + "filterByQuery": "Filtrar por \"{query}\"", + "clearAuthorFilterAria": "Limpar filtro de autor", + "recent": "Recentes", + "matchingAuthors": "Autores correspondentes", + "removeFromRecent": "Remover {name} dos recentes" + }, + "branchSelector": { + "label": "Branch", + "head": "HEAD", + "headHint": "Acompanha a branch atual", + "headHintWithBranch": "Acompanha a branch atual ({branch})", + "searchBranch": "Pesquisar branch...", + "noBranches": "Nenhum branch", + "selectBranchPlaceholder": "Selecionar branch...", + "localBranches": "Branches locais", + "current": "Atual", + "remoteBranches": "Branches remotas", + "refreshCommitHistory": "Atualizar histórico de commits", + "clearBranchFilterAria": "Limpar filtro de branch" + }, + "dialogs": { + "newBranchTitle": "Nova branch", + "newBranchDescription": "Criar uma nova branch com o commit {shortHash} como commit mais recente.", + "branchNamePlaceholder": "Nome da branch", + "reset": { + "title": "Resetar a branch atual para este commit", + "branchLabel": "Branch", + "targetLabel": "Commit alvo", + "messageLabel": "Mensagem", + "modeLabel": "Modo de reset", + "confirmButton": "Resetar", + "modes": { + "soft": { + "label": "--soft", + "description": "Move o HEAD e o ponteiro da branch atual para o commit alvo.\nMantém Index e Working Tree sem alterações.\nAs mudanças dos commits removidos permanecem staged." + }, + "mixed": { + "label": "--mixed (padrão)", + "description": "Move o HEAD para o commit alvo.\nReseta o Index para o commit alvo e mantém as mudanças no Working Tree.\nAs mudanças passam de staged para unstaged." + }, + "hard": { + "label": "--hard", + "description": "Move o HEAD e reseta tanto Index quanto Working Tree para o commit alvo.\nAs mudanças locais rastreadas após o commit alvo são descartadas.\nEsta é uma operação destrutiva." + }, + "keep": { + "label": "--keep", + "description": "Move o HEAD para o commit alvo e tenta preservar alterações locais.\nSomente alterações sem conflito são mantidas.\nSe houver conflito, o reset é abortado para proteger seu trabalho." + } + } + } + }, + "moreActions": "Mais ações do Git" + }, + "gitChangesTab": { + "workspace": "espaço de trabalho", + "noChanges": "Sem alterações locais", + "notAGitRepoTitle": "Não é um repositório Git", + "notAGitRepoHint": "Inicialize o Git pelo menu de ramificações acima, ou abra um repositório existente.", + "trackedChanges": "Alterações rastreadas ({count})", + "untrackedFiles": "Arquivos não rastreados ({count})", + "expandTracked": "Expandir alterações rastreadas", + "collapseTracked": "Recolher alterações rastreadas", + "expandUntracked": "Expandir arquivos não rastreados", + "collapseUntracked": "Recolher arquivos não rastreados", + "showRemainingItems": "Mostrar mais {count} itens", + "actions": { + "commitCode": "Commit do código", + "rollback": "Reverter", + "addToVcs": "Adicionar ao VCS", + "delete": "Excluir", + "moreActions": "Mais ações do Git", + "addAllToVcs": "Adicionar tudo ao VCS", + "rollbackAll": "Reverter tudo", + "refresh": "Atualizar" + }, + "toasts": { + "noAddableFilesInDir": "Nenhum arquivo alterado neste diretório pode ser adicionado ao VCS", + "noRollbackFilesInDir": "Nenhum arquivo alterado neste diretório pode ser revertido", + "addedToVcs": "{name} adicionado ao VCS", + "addToVcsFailed": "Falha ao adicionar ao VCS", + "openCommitWindowFailed": "Falha ao abrir a janela de commit", + "rolledBack": "{name} revertido", + "rollbackFailed": "Falha no rollback", + "addedFilesToVcs": "{count, plural, one {# arquivo} other {# arquivos}} adicionados ao VCS", + "rolledBackFiles": "{count, plural, one {# arquivo revertido} other {# arquivos revertidos}}", + "deleted": "{name} excluído", + "deleteFailed": "Falha ao excluir", + "deletedFiles": "{count} arquivos excluídos", + "noDeletableFilesInDir": "Nenhum arquivo alterado neste diretório pode ser excluído", + "commitFailed": "Falha ao confirmar" + }, + "directoryDialog": { + "descriptionAdd": "Selecione arquivos sob o diretório {path} para adicionar ao VCS.", + "descriptionRollback": "Selecione arquivos sob o diretório {path} para reverter.", + "descriptionDelete": "Selecione arquivos no diretório {path} para excluir. Esta ação não pode ser desfeita.", + "descriptionFallback": "Selecione arquivos para prosseguir.", + "selectionCount": "Selecionados {selected} / {total} arquivos", + "selectAll": "Selecionar todos", + "unselectAll": "Desmarcar todos", + "loadingCandidates": "Carregando alterações do diretório...", + "noOperableFiles": "Nenhum arquivo operável" + }, + "rollbackConfirm": { + "title": "Confirmar rollback", + "descriptionWithTarget": "Reverter alterações locais de {kind} \"{name}\"?", + "descriptionFallback": "Reverter alterações locais?", + "kindDirectory": "diretório", + "kindFile": "arquivo" + }, + "deleteConfirm": { + "title": "Confirmar exclusão", + "descriptionWithTarget": "Excluir {kind} \"{name}\"? Esta ação não pode ser desfeita.", + "descriptionFallback": "Esta ação não pode ser desfeita.", + "kindDirectory": "diretório", + "kindFile": "arquivo" + }, + "quickCommit": { + "placeholder": "Mensagem do commit (Enter para confirmar)" + } + }, + "tabContext": { + "loadingConversation": "Carregando...", + "untitledConversation": "Conversa sem título", + "newConversation": "Nova conversa" + }, + "fileTreeTab": { + "workspace": "Espaço de trabalho", + "retry": "Tentar novamente", + "git": "Git", + "openInFileManager": "Abrir no gerenciador de arquivos", + "openInFinder": "Abrir no Finder", + "openInExplorer": "Abrir no Explorer", + "attachToCurrentSession": "Adicionar à sessão", + "compareWithBranch": "Comparar com branch...", + "reloadFromDisk": "Recarregar do disco", + "new": "Novo", + "newFile": "Arquivo", + "newDirectory": "Diretório", + "openIn": "Abrir em", + "openInTerminal": "Abrir no terminal", + "linkedFolder": "Pasta vinculada", + "copyPath": "Copiar caminho", + "upload": "Enviar arquivos/pasta", + "download": "Baixar arquivo", + "downloadAsZip": "Baixar como ZIP", + "actions": { + "select": "Selecionar", + "unselect": "Desmarcar", + "commitCode": "Fazer commit do código", + "rollback": "Reverter", + "addToVcs": "Adicionar ao VCS" + }, + "aria": { + "selectPath": "{action}: {path}" + }, + "toasts": { + "openDirectoryFailed": "Falha ao abrir diretório", + "openBuiltinTerminalFailed": "Não foi possível abrir o terminal embutido", + "openCommitWindowFailed": "Falha ao abrir janela de commit", + "noAddableFilesInDir": "Nenhum arquivo alterado neste diretório pode ser adicionado ao VCS", + "noRollbackFilesInDir": "Nenhum arquivo alterado neste diretório pode ser revertido", + "addedToVcs": "{name} adicionado ao VCS", + "addToVcsFailed": "Falha ao adicionar ao VCS", + "loadBranchesFailed": "Falha ao carregar branches", + "renameFailed": "Falha ao renomear", + "moveFailed": "Falha ao mover", + "deleteFailed": "Falha ao excluir", + "rolledBack": "{name} revertido", + "rollbackFailed": "Falha ao reverter", + "addedFilesToVcs": "{count, plural, one {# arquivo adicionado ao VCS} other {# arquivos adicionados ao VCS}}", + "rolledBackFiles": "{count, plural, one {# arquivo revertido} other {# arquivos revertidos}}", + "savedAsCopy": "Salvo como cópia", + "saveCopyFailed": "Falha ao salvar como cópia", + "watchStartFailed": "Falha ao iniciar monitoramento de arquivos", + "createFailed": "Falha ao criar", + "downloadFailed": "Falha ao baixar {name}", + "downloadSaved": "{name} baixado", + "pathCopied": "Caminho copiado", + "copyPathFailed": "Falha ao copiar o caminho" + }, + "createDialog": { + "newFile": "Novo arquivo", + "newDirectory": "Novo diretório", + "description": "Digite um nome para o novo {kind}.", + "placeholderFile": "file-name.ext", + "placeholderDirectory": "folder-name" + }, + "renameDialog": { + "renameDirectory": "Renomear diretório", + "renameFile": "Renomear arquivo", + "description": "Digite um novo nome (apenas nome, sem caminho).", + "placeholderDirectory": "novo-nome-da-pasta", + "placeholderFile": "novo-nome-do-arquivo.ext" + }, + "uploadDialog": { + "title": "Enviar para o workspace", + "description": "Ajuste o destino se necessário e adicione arquivos ou pastas.", + "workspaceRoot": "raiz do workspace", + "targetPathLabel": "Enviar para", + "targetPathHint": "Caminho resolvido: {path}", + "dropHint": "Arraste arquivos ou pastas aqui, ou use os botões abaixo", + "dropHintActive": "Solte para adicionar à fila", + "selectFiles": "Selecionar arquivos", + "selectFolder": "Selecionar pasta", + "startUpload": "Iniciar upload", + "clearQueue": "Limpar finalizados", + "removeItem": "Remover da fila", + "retry": "Tentar novamente", + "dropZoneAria": "Solte arquivos aqui ou ative para procurar", + "folderEmpty": "Nenhum arquivo encontrado na pasta solta", + "summary": "Total: {total} · Sucesso: {succeeded} · Falhas: {failed}", + "status": { + "pending": "Aguardando", + "uploading": "Enviando", + "success": "Concluído", + "error": "Falhou", + "cancelled": "Cancelado" + } + }, + "directoryDialog": { + "descriptionAdd": "Selecione arquivos no diretório {path} para adicionar ao VCS.", + "descriptionRollback": "Selecione arquivos no diretório {path} para reverter.", + "descriptionFallback": "Selecione arquivos para continuar.", + "selectionCount": "{selected} / {total} arquivos selecionados", + "selectAll": "Selecionar tudo", + "unselectAll": "Desmarcar tudo", + "loadingCandidates": "Carregando alterações do diretório...", + "noOperableFiles": "Nenhum arquivo operável" + }, + "compareDialog": { + "title": "Comparar com branch", + "descriptionWithTarget": "Selecione uma branch e compare com {kind} {path}", + "descriptionFallback": "Selecione uma branch para comparar.", + "kindDirectory": "diretório", + "kindFile": "arquivo", + "filterPlaceholder": "Filtre branches, ex.: main / origin/main", + "singleClickHint": "Clique em uma branch para comparar diretamente", + "loadingBranches": "Carregando branches...", + "recentBranches": "Branches recentes ({count})", + "noCurrentBranch": "Sem branch atual", + "localBranches": "Branches locais ({count})", + "remoteBranches": "Branches remotas ({count})", + "noMatchingBranches": "Nenhuma branch correspondente" + }, + "externalConflictDialog": { + "title": "Alterações externas de arquivo detectadas", + "descriptionWithPath": "O arquivo {path} foi alterado no disco e as edições atuais não foram salvas.", + "descriptionFallback": "O arquivo atual foi alterado no disco e as edições atuais não foram salvas.", + "compare": "Comparar", + "savingCopy": "Salvando cópia...", + "saveAsCopy": "Salvar como cópia", + "reload": "Recarregar" + }, + "deleteConfirm": { + "title": "Confirmar exclusão", + "descriptionWithTarget": "Excluir {kind} \"{name}\"? Esta ação não pode ser desfeita.", + "descriptionFallback": "Esta ação não pode ser desfeita.", + "kindDirectory": "diretório", + "kindFile": "arquivo" + }, + "rollbackConfirm": { + "title": "Confirmar reversão", + "descriptionWithTarget": "Reverter alterações locais do arquivo \"{name}\"?", + "descriptionFallback": "Reverter alterações locais deste arquivo?" + }, + "terminalTitle": "Console · {name}" + }, + "commandDropdown": { + "loading": "Carregando...", + "addCommand": "Adicionar comando", + "manageCommands": "Gerenciar comandos...", + "runCommandTitle": "Executar: {command}", + "stopCommandTitle": "Parar: {command}", + "manageDialog": { + "title": "Gerenciar comandos", + "empty": "Ainda não há comandos", + "noResults": "Nenhum comando correspondente", + "searchPlaceholder": "Pesquisar comandos", + "newCommand": "Novo comando", + "nameLabel": "Nome", + "commandLabel": "Comando", + "dragSort": "Arraste para ordenar", + "dragSortCommand": "Arraste para ordenar {name}", + "orderFailed": "Falha ao salvar a ordem dos comandos", + "loadFailed": "Falha ao carregar os comandos", + "saveFailed": "Falha ao salvar o comando", + "deleteFailed": "Falha ao excluir o comando", + "confirmDelete": { + "title": "Excluir comando?", + "message": "Isso removerá \"{name}\". Esta ação não pode ser desfeita." + } + } + }, + "workspaceContext": { + "confirmCloseDirtyTab": "Fechar \"{title}\" sem salvar?", + "confirmCloseOtherDirtyTabs": "Fechar outras abas com alterações não salvas?", + "confirmCloseAllDirtyTabs": "Fechar todas as abas com alterações não salvas?", + "unableLoadContent": "Não foi possível carregar o conteúdo.\n\n{message}", + "previewRequestTimedOut": "A solicitação de preview expirou", + "diffRequestTimedOut": "A solicitação de Diff expirou", + "branchCompareRequestTimedOut": "A solicitação de comparação de branch expirou", + "commitDiffRequestTimedOut": "A solicitação de Diff de commit expirou", + "saveRequestTimedOut": "A solicitação de salvamento expirou", + "reloadRequestTimedOut": "A solicitação de recarga expirou", + "noChanges": "Sem alterações.", + "noDiffOutput": "Sem saída de diff.", + "diffTitleWorkspace": "Diff · Espaço de trabalho", + "diffDescriptionWorkingTree": "Árvore de trabalho (HEAD)", + "diffTitleFile": "Diferença · {name}", + "compareTitleFile": "Comparar · {name}", + "compareTitleBranch": "Comparar · {branch}", + "compareDescriptionPath": "{path} · comparar com {branch}", + "compareDescriptionBranch": "comparar com {branch}", + "diffTitleCommitFile": "Diferença · {name} @ {hash}", + "diffTitleCommit": "Diferença · {hash}", + "diffDescriptionCommitPath": "{path} · confirmação {commit}", + "diffDescriptionCommit": "confirmação {commit}", + "diffTitleConflictFile": "Conflito · {name}", + "diffDescriptionConflict": "{path} · disco vs não salvo" + }, + "chat": { + "acpConnections": { + "actions": { + "openAgentsSettings": "Abrir configurações de agentes", + "retry": "Tentar novamente" + }, + "agentsSetupHint": "Abra Configurações > Agentes para gerenciar a instalação.", + "withSetupHint": "{message}\n{hint}", + "blocked": { + "missingConfig": "Não foi possível ler a configuração atual do agente.", + "disabled": "{agent} está desativado nas configurações de agentes. Ative-o antes de conectar.", + "unavailable": "{agent} está indisponível na plataforma atual.", + "sdkMissing": "O SDK de {agent} não está instalado", + "adapterMissing": "O adaptador ACP de {agent} não está instalado" + }, + "backendErrors": { + "initializeTimeout": "O handshake de conexão de {agent} expirou (sem resposta após 60 segundos). Abra Configurações para verificar a configuração do agente e da rede.", + "mcpRejectedByAgent": "{agent} recusou a sessão com o companheiro MCP do codeg anexado: {message} Se este agente não suporta MCP, desative “Suporte a MCP” nas Configurações e conecte novamente.", + "processExited": "O processo de {agent} encerrou inesperadamente.", + "spawnFailed": "Falha ao iniciar {agent}: {message}", + "downloadFailed": "Falha no download de {agent}: {message}", + "sessionLoadResourceNotFound": "Falha ao carregar a sessão de {agent}. Recarregue para tentar novamente ou inicie uma nova conversa.", + "sessionLoadUnavailable": "{agent} não conseguiu restaurar esta sessão; ela pode ter terminado ou o agente parou. Recarregue para tentar novamente ou inicie uma nova conversa.", + "turnFailedRefusal": "{agent} recusou continuar este turno. Costuma indicar um erro de backend ou gateway. Confira os logs do agente.", + "turnFailedMaxTokens": "{agent} atingiu o limite máximo de tokens para este turno.", + "turnFailedMaxTurnRequests": "{agent} atingiu o número máximo de solicitações permitidas para este turno.", + "turnFailedUnknown": "{agent} encerrou o turno com um motivo de parada desconhecido.", + "grokModelSwitchIncompatibleAgent": "{agent} não pode mudar para esse modelo em uma conversa existente. Inicie uma nova sessão para usá-lo.", + "turnFailedEmpty": "{agent} encerrou o turno sem produzir nenhuma resposta.", + "turnFailedEmptyProtocol": "{agent} produziu uma saída que o codeg não conseguiu analisar — a versão do agente pode não corresponder ao protocolo.", + "turnFailedEmptyMetadata": "{agent} enviou apenas atualizações de status neste turno (plano / modo / uso) e nenhuma resposta.", + "detailsInAlerts": "Abra os alertas na barra de status e expanda os detalhes para ver a saída do agente." + }, + "unableReadAgentConfig": "Não foi possível ler a configuração do agente: {message}", + "connectFailedTitle": "Falha na conexão de {agent}", + "toolFallbackTitle": "Ferramenta", + "eventErrorTitle": "Erro do agente", + "notificationTurnComplete": "{agent} terminou de responder", + "notificationError": "{agent} erro: {message}", + "claudeApiRetry": { + "fallbackError": "authentication_failed", + "retryingWithMax": "tentando novamente {attempt}/{max}", + "retryingAttempt": "tentando novamente tentativa {attempt}", + "retrying": "tentando novamente", + "nextRetryIn": "próxima em {seconds}s", + "line": "{error}{status} · {retry}", + "lineWithDelay": "{error}{status} · {retry}, {delay}", + "httpStatus": " (HTTP {status})" + }, + "configOptionAdjusted": "O {agent} definiu {option} como {actual} em vez de {requested}" + }, + "connectionLifecycle": { + "tasks": { + "connectingTitle": "Conectando a {agent}", + "connectingDescription": "Estabelecendo conexão", + "loadingSelectorsTitle": "Carregando seletores de {agent}", + "loadingSelectorsDescription": "Buscando opções de modo e configuração de sessão", + "initSessionTitle": "Initializing {agent} session", + "initSessionDescription": "Creating session and loading configuration" + }, + "errors": { + "connectionFailed": "Falha na conexão", + "sendPromptFailed": "Falha ao enviar a mensagem: {error}" + } + }, + "shared": { + "attachedResources": "Recursos anexados", + "toolCallFailed": "Falha na chamada da ferramenta" + }, + "messageThread": { + "emptyTitle": "Ainda não há mensagens", + "emptyDescription": "Inicie uma conversa para ver mensagens aqui" + }, + "chatInput": { + "connecting": "Conectando...", + "agentResponding": "{agent} está respondendo...", + "sendMessage": "Envie uma mensagem..." + }, + "messageInput": { + "askAnything": "Pergunte qualquer coisa...", + "removeAttachmentAria": "Remover {name}", + "attachFiles": "Anexar arquivos", + "addActions": "Adicionar", + "quickMessages": "Mensagens rápidas", + "quickMessagesEmpty": "Ainda não há mensagens rápidas", + "quickMessagesLoading": "Carregando...", + "pasteAsPlainText": "Colar como texto simples", + "cut": "Cortar", + "copy": "Copiar", + "selectAll": "Selecionar tudo", + "pasteUnavailable": "Não foi possível ler a área de transferência. Use Ctrl/⌘V para colar.", + "clipboardWriteFailed": "Não foi possível escrever na área de transferência. Use o atalho de teclado.", + "quickMessageUntitled": "Sem título", + "liveFeedback": "Feedback ao vivo", + "liveFeedbackDisabledHint": "Disponível enquanto o agente trabalha", + "dropFilesToAttach": "Solte arquivos para anexar", + "loadingSettings": "Carregando configurações...", + "loadingMode": "Carregando modo...", + "modeLabel": "Modo", + "toggleOn": "Ligado", + "toggleOff": "Desligado", + "agentSettings": "Configurações do agente", + "searchModel": "Buscar modelos...", + "searchModelAria": "Buscar modelos", + "modelListLabel": "Modelos", + "noModels": "Nenhum modelo encontrado", + "cancel": "Cancelar", + "send": "Enviar", + "forkAndSend": "Fork & Enviar", + "queueMessage": "Adicionar à fila", + "steerIntoTurn": "Inserir no turno atual", + "steerQueuedInstead": "Adicionado à fila — será enviado no próximo turno.", + "steerFailed": "Não foi possível inserir no turno atual", + "steerAttachmentsUnsupported": "Somente texto — rascunhos com anexos vão pela fila.", + "slashCommands": "Comandos de barra", + "slashSearchPlaceholder": "Buscar comandos...", + "slashSearchEmpty": "Nenhum comando correspondente", + "experts": "Especialistas", + "office": "Escritório", + "research": "Pesquisa", + "attachLocalUpload": "Carregar arquivo local", + "attachServerFile": "Selecionar arquivo do servidor", + "attachUploadTooLarge": "{names} excede o limite de upload de {limit}MB e foi ignorado.", + "attachUploadFailed": "Falha ao enviar {names}.", + "attachUploadNotAFile": "{names} não é um arquivo regular (diretório ou arquivo especial) e foi ignorado.", + "attachUploadQuotaExceeded": "O servidor ficou sem espaço para uploads; {names} não pôde ser enviado.", + "attachUploadInProgress": "As imagens ainda estão sendo enviadas — tente novamente em instantes.", + "mentionEmpty": "Nenhuma correspondência", + "mentionLoading": "Pesquisando…", + "mentionListLabel": "Menções", + "mentionMore": "Mais resultados — continue digitando para filtrar", + "mentionCount": "{count, plural, one {# resultado} other {# resultados}}", + "mentionGroupFile": "Arquivos", + "mentionGroupAgent": "Agentes", + "mentionGroupSession": "Sessões", + "mentionGroupCommit": "Commits", + "mentionGroupSkill": "Habilidades" + }, + "messageQueue": { + "addToQueue": "Adicionar à fila", + "saveEdit": "Salvar", + "cancelEdit": "Cancelar edição", + "editItem": "Editar", + "deleteItem": "Remover" + }, + "welcomeInputPanel": { + "agentsSettingsPath": "Configurações > Agentes", + "autoConnectFallback": "Clique para abrir {path} e gerenciar a instalação.", + "autoConnectAppend": "{message}. Clique para abrir {path} e gerenciar a instalação.", + "enableAgentFirstPlaceholder": "Ative pelo menos um agente antes de iniciar uma sessão...", + "prepareSessionFailed": "Não foi possível preparar a sessão de chat. Tente novamente.", + "createConversationFailed": "Não foi possível criar a conversa. Tente novamente.", + "askAnythingPlaceholder": "Pergunte qualquer coisa...", + "agentNotInstalled": "{agent} não está instalado · abra as configurações de Agents para instalá-lo", + "agentAdapterNotInstalled": "O adaptador ACP de {agent} não está instalado (separado da sua própria CLI) · abra as configurações de Agents para instalá-lo" + }, + "welcomePanel": { + "greeting": "O que você gostaria de fazer hoje?", + "tips": { + "tileTabs": "Clique com o botão direito em uma aba de conversa e escolha Exibir em mosaico para ver várias sessões lado a lado.", + "pinTab": "Clique duas vezes em uma aba de conversa para fixá-la, evitando que uma nova sessão a substitua automaticamente.", + "shortcutsNewSearch": "{newConversation} abre uma nova conversa, {searchConversations} pesquisa no histórico.", + "slashAtMention": "Digite / na entrada para acionar comandos slash, ou @ para referenciar um arquivo do projeto.", + "pasteDropFiles": "Cole uma captura de tela ou arraste um arquivo direto para a entrada para anexá-lo.", + "queueMessage": "Enquanto o agente responde, continue digitando — sua próxima mensagem entra na fila e é enviada automaticamente ao terminar.", + "draftAutoSave": "Rascunhos não enviados são salvos automaticamente por conversa e restaurados quando você volta.", + "forkSend": "O menu suspenso do botão de enviar tem Bifurcar e enviar — ramifique do ponto atual para uma nova aba.", + "exportConversation": "Clique com o botão direito dentro da conversa para exportá-la como Markdown, HTML ou imagem.", + "chatChannels": "Conecte Telegram / Lark / WeChat em Configurações → Canais de chat para continuar pelo celular.", + "shortcutsAuxPanel": "{toggleAuxPanel} alterna o painel direito para ver os arquivos tocados e as mudanças do Git desta sessão.", + "shortcutsTerminalSidebar": "{toggleTerminal} abre o terminal integrado, {toggleSidebar} alterna a barra lateral.", + "customShortcuts": "Todos os atalhos podem ser reatribuídos em Configurações → Atalhos.", + "webService": "Ative Configurações → Serviço web para que sua equipe acesse o mesmo codeg pelo navegador.", + "fusionMode": "Abra um arquivo ou diff para exibi-lo automaticamente ao lado da conversa.", + "quickMessages": "Abra o botão + ao lado da entrada e escolha Mensagens rápidas para inserir um trecho salvo (gerencie-os em Configurações → Mensagens rápidas).", + "experts": "O botão + tem um menu Habilidades de especialista — carregue papéis como Depuração ou Planejamento com um clique.", + "taskBoard": "As tarefas a fazer executam um trabalho do início ao fim: o agente trabalha no próprio worktree e você revisa o diff antes de mesclar.", + "automations": "As Automações executam um prompt salvo em uma agenda — uma revisão noturna, um relatório recorrente — e cada execução pode ter seu próprio worktree.", + "tokenUsage": "Clique no número de conversas na barra de status para abrir o Uso de tokens, detalhado por dia, agente, modelo e pasta.", + "mentionTargets": "@ não traz só arquivos: mencione outro agente para delegar uma subtarefa, ou referencie uma sessão anterior, um commit ou uma habilidade.", + "splitGroups": "Clique com o botão direito em uma aba e escolha Dividir à direita ou Dividir abaixo para manter duas conversas em painéis próprios.", + "worktrees": "Abra o botão de branch e escolha Novo worktree para vários agentes trabalharem no mesmo repositório sem sobrescrever os arquivos uns dos outros.", + "importSessions": "Já rodou sessões no terminal? O menu de uma pasta tem Importar sessões locais para trazer esse histórico para o codeg.", + "subSessions": "Quando um agente delega, a subsessão aparece aninhada abaixo dele na barra lateral — expanda a linha para acompanhar o que cada uma fez.", + "liveFeedback": "Feedback ao vivo, no menu +, insere uma nota no turno que o agente já está executando, sem interrompê-lo.", + "skillPacks": "Configurações → Pacotes de habilidades reúne especialistas de código, pesquisa científica e escritório; ative por agente.", + "modelProviders": "Configurações → Provedores de Modelos aceita sua própria chave de API ou endpoint, e o modelo você escolhe no campo de entrada.", + "workspaceBackground": "Configurações → Aparência define uma imagem de fundo do espaço de trabalho, a opacidade dos painéis e as fontes do app." + }, + "quickActions": { + "excel": "Pasta do Excel", + "excelDesc": "Tabelas, fórmulas e gráficos", + "word": "Documento do Word", + "wordDesc": "Relatórios, cartas e memorandos", + "ppt": "Apresentação", + "pptDesc": "Slides com design profissional", + "pitchDeck": "Pitch Deck", + "pitchDeckDesc": "Apresentação de captação com métricas", + "morph": "Animação Morph", + "morphDesc": "Transições de slide cinematográficas", + "morph3d": "Morph 3D", + "morph3dDesc": "Modelos 3D com movimentos de câmera", + "academic": "Artigo acadêmico", + "academicDesc": "Pesquisa com citações e estrutura", + "financial": "Modelo financeiro", + "financialDesc": "Demonstrações, DCF e projeções", + "dashboard": "Painel de dados", + "dashboardDesc": "KPIs e análises a partir dos seus dados", + "prompts": { + "excel": "Crie uma pasta do Excel com os seguintes requisitos:\n\n[descreva aqui seus dados, tabelas, fórmulas e gráficos]", + "word": "Crie um documento do Word com os seguintes requisitos:\n\n[descreva aqui o conteúdo, a estrutura e a formatação do documento]", + "ppt": "Crie uma apresentação do PowerPoint com os seguintes requisitos:\n\n[descreva aqui seus slides, conteúdo e design]", + "pitchDeck": "Crie um pitch deck de captação com os seguintes requisitos:\n\n[descreva aqui sua empresa, rodada de investimento e métricas-chave]", + "morph": "Crie uma apresentação com animações de transição Morph:\n\n[descreva aqui o tema da apresentação e os efeitos visuais desejados]", + "morph3d": "Crie uma apresentação Morph 3D com modelos GLB e movimentos de câmera:\n\n[descreva aqui seu tema e conceito visual em 3D]", + "academic": "Escreva um artigo acadêmico no Word com os seguintes requisitos:\n\n[descreva aqui seu tema de pesquisa, metodologia e principais resultados]", + "financial": "Crie um modelo financeiro no Excel com os seguintes requisitos:\n\n[descreva aqui suas demonstrações financeiras, projeções e análises]", + "dashboard": "Crie um painel de dados no Excel com os seguintes requisitos:\n\n[descreva aqui sua fonte de dados, KPIs e gráficos]", + "scientific-brainstorming": "Ajude-me a fazer um brainstorming de direções de pesquisa: explore conexões interdisciplinares, questione premissas e revele lacunas promissoras. A área que estou explorando: ", + "hypothesis-generation": "Ajude-me a transformar estas observações em hipóteses testáveis, com previsões claras, mecanismos plausíveis e experimentos. Minhas observações: ", + "experimental-design": "Ajude-me a planejar um experimento rigoroso antes de coletar dados: o delineamento, a aleatorização, os controles e como evitar confundimento. O que quero estudar: ", + "statistical-power": "Ajude-me a determinar o tamanho amostral necessário: conduza uma análise de poder (tamanho de efeito, alfa, poder) para o meu delineamento. Detalhes: ", + "statistical-analysis": "Ajude-me a analisar estes dados corretamente: escolha o teste certo, verifique os pressupostos, relate os tamanhos de efeito e redija. Meus dados e pergunta: ", + "exploratory-data-analysis": "Faça uma análise exploratória do meu arquivo de dados: resuma sua estrutura, qualidade e padrões notáveis e sugira os próximos passos. O arquivo é: ", + "scientific-visualization": "Ajude-me a criar uma figura com qualidade de publicação: layout claro, barras de erro honestas, uma paleta segura para daltônicos e formatação de periódico. O que quero mostrar: ", + "scientific-critical-thinking": "Ajude-me a avaliar criticamente este estudo ou alegação: avalie a qualidade da evidência, identifique vieses e confundidores e pondere as conclusões. Aqui está: ", + "paper-lookup": "Ajude-me a encontrar artigos relevantes e texto completo de acesso aberto em bases de dados acadêmicas, com citações reutilizáveis. Estou procurando: " + }, + "paper-lookup": "Busca de artigos", + "paper-lookupDesc": "Pesquise em 10 APIs acadêmicas (PubMed, arXiv, OpenAlex, Crossref…) artigos, citações e texto completo de acesso aberto.", + "scientific-critical-thinking": "Pensamento crítico", + "scientific-critical-thinkingDesc": "Avalie alegações científicas e a qualidade da evidência: identifique vieses e confundidores e aplique GRADE.", + "scientific-visualization": "Visualização científica", + "scientific-visualizationDesc": "Figuras prontas para publicação: layouts multipainel, anotações de significância e formatação específica de periódico.", + "exploratory-data-analysis": "Análise exploratória de dados", + "exploratory-data-analysisDesc": "Exploração automatizada de arquivos de dados científicos em mais de 200 formatos com métricas de qualidade e relatórios.", + "statistical-analysis": "Análise estatística", + "statistical-analysisDesc": "Análise estatística guiada: seleção de testes, verificação de pressupostos, tamanhos de efeito e relato no estilo APA.", + "statistical-power": "Poder estatístico", + "statistical-powerDesc": "Análise de tamanho amostral e poder: quantos sujeitos são necessários, efeitos mínimos detectáveis e curvas de poder.", + "experimental-design": "Delineamento experimental", + "experimental-designDesc": "Planeje estudos rigorosos antes de coletar dados: aleatorização, blocagem, controles e delineamentos fatoriais/DOE.", + "hypothesis-generation": "Geração de hipóteses", + "hypothesis-generationDesc": "Transforme observações em hipóteses testáveis com previsões, mecanismos e experimentos para testá-las.", + "scientific-brainstorming": "Brainstorming científico", + "scientific-brainstormingDesc": "Ideação aberta de pesquisa: explore conexões interdisciplinares, questione premissas e revele lacunas.", + "tabs": { + "office": "Escritório", + "coding": "Desenvolvimento", + "research": "Pesquisa" + }, + "coding": { + "brainstormingDesc": "Explore intenção e requisitos antes de construir", + "debuggingDesc": "Encontre a causa raiz antes de propor correções", + "writingSkillsDesc": "Crie, edite e verifique skills reutilizáveis" + }, + "notEnabled": { + "title": "A habilidade “{skill}” ainda não está ativada para {agent}", + "description": "Ative-a nas Configurações para usá-la aqui.", + "action": "Ativar", + "hint": "Habilidade não ativada" + }, + "scrollPrev": "Mostrar habilidades anteriores", + "scrollNext": "Mostrar mais habilidades" + } + }, + "agentSelector": { + "noEnabledAgents": "Nenhum agente habilitado", + "openAgentsSettings": "Abrir configurações de agentes", + "notInstalled": "Não instalado", + "moreAgents": "Mais agentes ({count})" + }, + "subAgentOverlay": { + "title": "Subagentes", + "collapsedSummary": "Subagentes {count}", + "collapseAria": "Recolher subagentes" + }, + "agentPlanOverlay": { + "title": "Plano do agente", + "collapsePlanAria": "Recolher plano", + "collapsedSummary": "Plano {completed}/{total}", + "status": { + "completed": "Concluído", + "inProgress": "Em andamento", + "pending": "Pendente", + "unknown": "Desconhecido" + }, + "priority": { + "high": "Alta", + "medium": "Média", + "low": "Baixa", + "unknown": "Desconhecida" + } + }, + "permissionDialog": { + "subtitle": "O agente solicita permissão para continuar este turno.", + "queuedCount": "+{count} aguardando", + "kindFallbackTool": "ferramenta", + "command": "Comando", + "cwd": "Diretório de trabalho: {cwd}", + "filesSummary": "Arquivos: {count}", + "moreFiles": "+{count} arquivos a mais", + "plan": "Plano", + "allowedActions": "Ações permitidas", + "targetMode": "Modo de destino: {mode}", + "optionGrants": "O que cada opção concede", + "changeScopeSession": "Esta sessão", + "changeScopeProcess": "Esta execução", + "changeScopeUser": "Salvo nas configurações do usuário", + "changeScopeProject": "Salvo nas configurações do projeto", + "changeScopeProjectLocal": "Salvo nas configurações locais do projeto", + "changeScopePersistent": "Salvo permanentemente" + }, + "questionDialog": { + "title": "O agente está fazendo uma pergunta", + "placeholder": "Digite sua resposta...", + "send": "Enviar" + }, + "messageBranch": { + "previousBranchAria": "Branch anterior", + "nextBranchAria": "Próxima branch", + "pageOf": "{current} de {total}" + }, + "terminal": { + "title": "Console", + "running": "Em execução" + }, + "reasoning": { + "thinking": "Pensando…", + "thoughtForFewSeconds": "Pensamento", + "thoughtForSeconds": "Pensamento" + }, + "linkSafety": { + "errorCannotOpen": "Não é possível abrir o arquivo local", + "errorNoWorkspace": "Nenhuma pasta de espaço de trabalho está ativa no momento.", + "errorFailedOpen": "Falha ao abrir o arquivo local", + "errorFailedLink": "Falha ao abrir o link", + "errorUnsupportedLinkProtocol": "Este protocolo de link não é compatível." + }, + "fileActions": { + "openInFinder": "Abrir no Finder", + "openInExplorer": "Abrir no Explorer", + "openInFileManager": "Abrir no gerenciador de arquivos", + "copyRelativePath": "Copiar caminho relativo", + "copyAbsolutePath": "Copiar caminho absoluto", + "pathCopied": "Caminho copiado", + "copyPathFailed": "Falha ao copiar o caminho", + "openFailed": "Falha ao abrir o arquivo local" + }, + "messageList": { + "attachedResources": "Recursos anexados", + "loading": "Carregando...", + "loadEarlier": "Carregar mensagens anteriores", + "loadingEarlier": "Carregando mensagens anteriores…", + "error": "Erro: {message}", + "errorTitle": "Falha ao carregar a sessão", + "errorActionReload": "Recarregar", + "errorActionNewSession": "Nova conversa", + "emptyConversation": "Nenhuma mensagem nesta conversa.", + "systemMessage": "Mensagem do sistema", + "copyMessage": "Copiar", + "copied": "Copiado", + "downloadImage": "Baixar imagem", + "downloadFailed": "Falha no download: {message}", + "imageGeneration": "Geração de imagem", + "imageGenerationPending": "Gerando imagem…", + "imageGenerationFailed": "Falha na geração da imagem", + "model": "Modelo", + "tokenStats": "Uso de tokens", + "tokenInput": "Entrada", + "tokenOutput": "Saída", + "tokenCacheRead": "Leitura de cache", + "tokenCacheWrite": "Escrita de cache", + "duration": "Duração", + "completedAt": "Concluído às", + "jumpToPreviousUserMessage": "Ir para a mensagem do usuário", + "showMore": "Mostrar mais", + "showLess": "Mostrar menos" + }, + "liveTurnStats": { + "thinking": "Pensando...", + "streaming": "Transmitindo", + "elapsedHours": "{value} h", + "elapsedMinutes": "{value} min", + "elapsedSeconds": "{value} s", + "outputSpeedAria": "Velocidade de saída estimada", + "outputSpeedTooltip": "Velocidade de saída estimada (texto + raciocínio)" + }, + "jsonTree": { + "viewRaw": "Ver JSON bruto", + "viewTree": "Ver árvore", + "fields": "{count, plural, one {# campo} other {# campos}}", + "items": "{count, plural, one {# item} other {# itens}}" + }, + "tool": { + "parameters": "Parâmetros", + "error": "Erro", + "result": "Resultado", + "status": { + "approvalRequested": "Aguardando aprovação", + "approvalResponded": "Respondido", + "inputAvailable": "Em execução", + "inputStreaming": "Pendente", + "outputAvailable": "Concluído", + "outputDenied": "Negado", + "outputError": "Erro" + } + }, + "toolCallBlock": { + "tool": "Ferramenta", + "error": "Erro", + "result": "Resultado" + }, + "delegation": { + "subAgentRunning": "Subagente em execução…", + "noDetail": "No detail available yet.", + "unknownAgent": "Subagente", + "openDetail": "Ver conversa", + "detailTitle": "Conversa do subagente", + "detailDescription": "Visualização somente leitura da conversa do subagente delegado.", + "waitForResult": "Aguardando o resultado da tarefa {task}", + "waitForResultNoTask": "Aguardando o resultado da tarefa", + "cancelTask": "Cancelando a tarefa {task}", + "cancelTaskNoTask": "Cancelando a tarefa", + "resultPageOf": "{current} / {total}", + "prevResult": "Resultado anterior", + "nextResult": "Próximo resultado", + "noResultText": "Sem resultado nesta verificação.", + "status": { + "starting": "iniciando", + "running": "em execução", + "checked": "verificado", + "waiting": "aguardando aprovação", + "ok": "concluído", + "err": { + "default": "falhou", + "delegation_disabled": "desativado", + "depth_limit": "limite de profundidade", + "invalid_agent_type": "agente inválido", + "spawn_failed": "falha ao iniciar", + "send_failed": "falha ao enviar", + "timeout": "tempo esgotado", + "canceled": "cancelado", + "child_refusal": "subagente recusou", + "child_max_tokens": "subagente: limite de tokens", + "child_max_turn_requests": "subagente: limite de solicitações", + "child_empty": "subagente sem saída", + "child_unknown": "subagente: erro", + "unknown": "tarefa desconhecida" + } + } + }, + "contentParts": { + "showingTailOutput": "Mostrando a saída final durante o streaming para melhor desempenho.", + "result": "Resultado", + "unknown": "desconhecido", + "inputTruncated": "A entrada foi truncada — o diff pode estar incompleto.", + "replaceAll": "SUBSTITUIR TUDO", + "filesCount": "Arquivos: {count}", + "update": "atualizar", + "moreFiles": "+{count} arquivos a mais", + "timeoutMs": "Tempo limite: {timeout}ms", + "backgroundTrue": "Segundo plano: true", + "scriptToolCalls": "{count, plural, one {# chamada de ferramenta} other {# chamadas de ferramenta}}", + "offset": "Deslocamento: {offset}", + "limit": "Limite: {limit}", + "pages": "Páginas: {pages}", + "mode": "Modo: {mode}", + "cell": "Célula: {cell}", + "shellSession": "Sessão {id}", + "pathLabel": "Caminho:", + "globLabel": "Padrão glob:", + "typeLabel": "Tipo:", + "outputLabel": "Saída:", + "caseInsensitive": "Sem diferenciar maiúsculas/minúsculas", + "multiline": "Multilinha", + "promptLabel": "Instrução", + "subjectLabel": "Assunto", + "taskLabel": "Tarefa", + "nameLabel": "Nome:", + "agentPromptLabel": "Instrução", + "agentModelLabel": "Modelo", + "agentRunning": "Em execução...", + "agentLiveTranscript": "Atividade ao vivo", + "agentProgressTools": "{count} chamadas de ferramentas", + "agentProgressTurns": "{count} turnos", + "agentProgressContext": "contexto {pct}%", + "agentSessionAction": "Ver a sessão do subagente", + "agentSessionTitle": "Sessão do subagente", + "agentSessionLoading": "Carregando a transcrição do subagente…", + "agentSessionEmpty": "O subagente ainda não escreveu nada.", + "agentFallbackTitle": "Iniciando subagente…", + "agentCodexLaunchOnly": "Iniciado. O Codex não informa mais o progresso deste subagente — o resultado chega como uma mensagem nesta conversa.", + "agentStatsBash": "Comandos", + "agentStatsRead": "Arquivos lidos", + "agentStatsSearch": "Pesquisas", + "agentStatsEdit": "Edições", + "agentStatsOther": "Outros", + "goal": { + "title": "Objetivo:", + "titleWithStatus": "Objetivo {status}", + "objective": "Objetivo", + "statusLabel": "Status", + "tokensUsed": "Tokens usados", + "budget": "Orçamento", + "remaining": "Restante", + "elapsed": "Decorrido", + "tokens": "tokens", + "pause": "Pausar", + "clear": "Limpar", + "status": { + "active": "ativo", + "paused": "pausado", + "blocked": "bloqueado", + "usageLimited": "uso limitado", + "budgetLimited": "orçamento limitado", + "complete": "concluído", + "limited": "limite atingido" + } + }, + "field": { + "file": "Arquivo", + "notebook": "Caderno", + "command": "Comando", + "old": "Antigo", + "new": "Novo", + "pattern": "Padrão", + "path": "Caminho", + "query": "Consulta", + "url": "URL:", + "description": "Descrição", + "content": "Conteúdo", + "source": "Fonte", + "prompt": "Instrução", + "subject": "Assunto", + "taskId": "ID da tarefa", + "status": "Situação", + "skill": "Skill", + "args": "Argumentos", + "offset": "Deslocamento", + "limit": "Limite", + "glob": "Padrão glob", + "type": "Tipo", + "output": "Saída", + "replaceAll": "Substituir tudo", + "language": "Idioma", + "timeout": "Tempo limite", + "background": "Segundo plano", + "agentType": "Tipo de agente", + "library": "Biblioteca", + "libraryId": "ID da biblioteca" + }, + "title": { + "edit": "Editar", + "command": "Comando", + "script": "Script", + "waitCommand": "Aguardar {command}", + "waitCell": "Aguardar sessão {id}", + "terminateCommand": "Encerrar {command}", + "terminateCell": "Encerrar sessão {id}", + "stdinChars": "Entrada {chars}", + "todoWrite": "TodoWrite (atualização de tarefas)", + "read": "Ler", + "write": "Escrever", + "notebookEdit": "NotebookEdit (edição de caderno)", + "editFiles": "Editar ({count} arquivos)", + "editWithTarget": "Editar {target}", + "readWithTarget": "Ler {target}", + "writeWithTarget": "Escrever {target}", + "notebookEditWithTarget": "NotebookEdit ({target})", + "globWithPattern": "Padrão glob {pattern}", + "listFilesWithPath": "Listar arquivos {path}", + "grepWithPattern": "Padrão grep {pattern}", + "taskCreateWithSubject": "Criar tarefa: {subject}", + "taskUpdateWithStatus": "Atualizar tarefa #{id} -> {status}", + "taskUpdate": "Atualizar tarefa #{id}", + "webFetchWithUrl": "WebFetch ({url})", + "webSearchWithQuery": "Pesquisa web: {query}", + "todosProgress": "Tarefas ({done}/{total})", + "skillWithName": "Skill: {name}", + "genericWithContext": "{tool} ({context})" + }, + "search": { + "noMatches": "Nenhuma correspondência", + "matchSummary": "{matches, plural, one {# correspondência} other {# correspondências}} em {files, plural, one {# arquivo} other {# arquivos}}", + "fileSummary": "{files, plural, one {# arquivo} other {# arquivos}}", + "moreResults": "{count, plural, one {# resultado adicional não exibido} other {# resultados adicionais não exibidos}}" + }, + "toolGroup": { + "search": "{count, plural, one {Explorou # busca} other {Explorou # buscas}}", + "command": "{count, plural, one {Executou # comando} other {Executou # comandos}}", + "read": "{count, plural, one {Leu arquivos # vez} other {Leu arquivos # vezes}}", + "memory": "{count, plural, one {Recordou # memória} other {Recordou # memórias}}", + "edit": "{count, plural, one {Editou arquivos # vez} other {Editou arquivos # vezes}}", + "fetch": "{count, plural, one {Buscou # recurso} other {Buscou # recursos}}", + "think": "{count, plural, one {Pensou # vez} other {Pensou # vezes}}", + "todo": "{count, plural, one {Atualizou # tarefa} other {Atualizou # tarefas}}", + "task": "{count, plural, one {Executou # tarefa} other {Executou # tarefas}}", + "other": "{count, plural, one {Usou # ferramenta} other {Usou # ferramentas}}", + "errorSuffix": "{count, plural, one {# falhou} other {# falharam}}", + "joiner": " · " + }, + "planMode": { + "entered": "Modo de planejamento iniciado", + "planLabel": "Plano", + "reviewApproved": "Plano aprovado — implementando", + "reviewKept": "Mantido no modo de plano", + "reviewPending": "Aguardando decisão sobre o plano", + "submitted": "Plano enviado", + "switched": "Modo alterado" + }, + "backgroundTask": { + "title": "Tarefa em segundo plano", + "titleWithId": "Tarefa em segundo plano · {id}", + "running": "Em execução", + "completed": "Concluída", + "failed": "Falhou", + "stopped": "Interrompida", + "exitCode": "saída {code}", + "polledTimes": "Consultada {count} vezes", + "runningInBackground": "Segundo plano", + "launchNote": "Em execução em segundo plano · {id}" + }, + "codexScript": { + "outputMissing": "O codex truncou a saída do script e removeu o separador deste comando, então nenhuma saída pôde ser atribuída a ele.", + "sharedWith": "Também contém a saída de {commands} — o codex truncou os separadores delas.", + "truncated": "truncado" + } + }, + "messageNav": { + "title": "Navegação de mensagens", + "collapse": "Recolher navegação de mensagens", + "collapsedSummary": "Mensagens {count}", + "fileCount": "{count, plural, one {# arquivo} other {# arquivos}}", + "remove": "Remover", + "noDiffDataAvailable": "Nenhum dado de diff disponível para {filePath}" + }, + "replyArtifacts": { + "title": "Arquivos alterados", + "fileCount": "{count, plural, one {# arquivo} other {# arquivos}}", + "newFilesTitle": "Novos arquivos", + "revealInFolder": "Mostrar no gerenciador de arquivos", + "openFile": "Abrir {filePath}", + "openInEditor": "Abrir no editor", + "remove": "Remover", + "noDiffDataAvailable": "Nenhum dado de diff disponível para {filePath}" + }, + "askQuestion": { + "title": "O agente precisa da sua escolha", + "subtitle": "Responda e envie. Você pode pular a qualquer momento.", + "recommended": "Recomendado", + "other": "Outro", + "otherPlaceholder": "Digite sua resposta…", + "singleSelect": "Única", + "multiSelect": "Múltipla", + "skip": "Pular", + "next": "Próxima", + "submit": "Enviar", + "submitError": "Falha ao enviar. Tente novamente." + }, + "planApproval": { + "title": "O agente tem um plano — revise", + "emptyPlan": "O agente não escreveu um plano. Aprove para começar ou solicite alterações.", + "approve": "Aprovar e construir", + "requestChanges": "Solicitar alterações", + "abandon": "Descartar", + "feedbackPlaceholder": "O que deve mudar?", + "sendChanges": "Enviar", + "cancel": "Cancelar", + "submitError": "Não foi possível enviar. Tente novamente." + }, + "feedbackCheckResult": { + "count": "{count, plural, =1 {1 comentário} other {# comentários}}", + "expand": "Mostrar todos os comentários", + "collapse": "Recolher", + "errorTitle": "Falha ao verificar comentários" + }, + "askQuestionResult": { + "title": "Pergunta", + "answeredLabel": "Pergunta e resposta:", + "awaiting": "Aguardando sua resposta…", + "declined": "Você ignorou isto — o agente usou o próprio julgamento.", + "noSelection": "Sem seleção" + }, + "configStale": { + "agentConfigTitle": "Configurações do agente atualizadas", + "modelProviderTitle": "Provedor de modelo atualizado", + "description": "Esta sessão ainda está usando a configuração anterior. Reconecte para aplicar (o histórico da conversa é mantido).", + "reconnect": "Reconectar para aplicar", + "reconnecting": "Reconectando…", + "reconnectDisabledDuringTurn": "Disponível quando o turno atual terminar", + "dismiss": "Dispensar", + "reconnectFailed": "Falha ao reconectar a sessão", + "applied": "Nova configuração aplicada" + }, + "piProjectTrust": { + "title": "Este projeto inclui recursos do pi", + "description": "O pi não está carregando os arquivos .pi do próprio repositório. Revise-os para decidir.", + "descriptionExecutable": "O repositório inclui extensões do pi, que executam código na inicialização. O pi não as está carregando. Revise antes de decidir.", + "review": "Revisar…", + "dismiss": "Dispensar", + "dialogTitle": "Confiar nos recursos do pi deste projeto?", + "dialogDescription": "O pi só carrega os arquivos .pi do próprio repositório se você confiar na pasta. Confie apenas se confiar no conteúdo deste repositório.", + "executionWarning": "Extensões são código. Ao confiar nesta pasta, o repositório poderá executá-las na inicialização do pi com suas permissões, antes de você enviar qualquer mensagem.", + "scopeNote": "A decisão é salva no trust.json do pi para esta pasta, vale para todas as pastas dentro dela e também é usada quando você executa o pi no terminal. Você pode alterá-la em Configurações → Agentes → Pi.", + "trust": "Confiar no projeto", + "decline": "Manter sem carregar", + "disabledDuringTurn": "Disponível quando o turno atual terminar", + "trustedToast": "Projeto confiável — reconectado para que o pi carregue seus recursos", + "declinedToast": "Os recursos do projeto continuam sem ser carregados", + "saveFailed": "Falha ao salvar a decisão de confiança do projeto", + "grantTitle": "Este projeto já é confiável", + "grantDescription": "O pi carrega os arquivos .pi do próprio repositório. Revise o que isso permite.", + "grantInheritedDescription": "Uma pasta superior é confiável, então o pi carrega os arquivos .pi do próprio repositório. Revise o que isso permite.", + "grantDialogTitle": "Os recursos do pi deste projeto são confiáveis", + "grantDialogDescription": "O pi tem permissão para carregar os arquivos .pi do próprio repositório. Versões anteriores do codeg concediam isso automaticamente ao abrir uma pasta, então talvez você nunca tenha sido perguntado.", + "grantExecutionWarning": "Extensões são código. O repositório as executa na inicialização do pi com suas permissões, antes de você enviar qualquer mensagem.", + "inheritedFrom": "Confiança herdada de", + "revoke": "Revogar confiança", + "keepTrusted": "Manter confiável", + "revokedToast": "Confiança revogada — reconectado para que o pi pare de carregar os recursos do projeto", + "trustedNoReconnect": "Projeto confiável — será aplicado na próxima inicialização do pi", + "revokedNoReconnect": "Confiança revogada — será aplicada na próxima inicialização do pi" + }, + "collabAgent": { + "title": "Subagente", + "errorTitle": "Falha na tarefa do subagente", + "statesLabel": "Subagentes", + "statusRunning": "Em execução", + "statusCompleted": "Concluído", + "statusFailed": "Falhou", + "statusPending": "Iniciando", + "statusInterrupted": "Interrompido", + "statusClosed": "Encerrado", + "statusNotFound": "Não encontrado", + "opSpawn": "Iniciando subagente", + "opWait": "Obtendo resultado do subagente", + "opClose": "Encerrando subagente", + "opResume": "Retomando subagente" + }, + "contextCompaction": { + "compacting": "Compactando o contexto…", + "compacted": "Contexto compactado", + "compactedTokens": "Contexto compactado · {before} → {after} tokens", + "failed": "Falha ao compactar o contexto" + }, + "sessionFailure": { + "category": { + "connection": "Problema de conexão", + "access": "Problema de acesso", + "limit": "Limite atingido", + "request": "Solicitação rejeitada", + "service": "Problema do serviço", + "unknown": "Problema de sessão" + }, + "action": { + "retry": "Tentar novamente", + "login": "Entrar", + "newSession": "Nova sessão" + }, + "recovered": "Recuperado", + "retryUnavailable": "Nenhuma mensagem anterior para reenviar.", + "toggleDetails": "Alternar detalhes" + }, + "backgroundTasks": { + "running": "{count, plural, one {# tarefa em segundo plano em execução} other {# tarefas em segundo plano em execução}}", + "settling": "Sincronizando resultados em segundo plano…", + "settledFallback": "Tarefa em segundo plano concluída ({status})", + "cardRunning": "Executando em segundo plano", + "cardLaunchedPending": "Tarefa iniciada em segundo plano", + "cardCompleted": "Tarefa em segundo plano concluída", + "cardFinishedWithStatus": "Tarefa em segundo plano encerrada ({status})", + "cardResultPending": "Resultado ainda não retornou" + }, + "proposedPlan": { + "title": "Plano proposto", + "planning": "A planear…" + } + }, + "diffPreview": { + "mode": { + "added": "Adicionado", + "deleted": "Excluído", + "renamed": "Renomeado", + "modified": "Modificado" + }, + "hunkLabel": "Bloco {index}", + "loadingHunk": "Carregando hunk...", + "noDiffData": "Sem dados de diff", + "showRemainingLines": "Mostrar mais {count} linhas" + }, + "conversationContextBar": { + "folderTitle": "Pasta de trabalho", + "branchTitle": "Branch de trabalho", + "searchFolder": "Search folder...", + "searchBranch": "Search branch...", + "noFolders": "No folders", + "noBranches": "No branches", + "noBranch": "(no branch)", + "chatModeLabel": "Modo de chat", + "commit": "Commit", + "push": "Push", + "merge": "Merge", + "toasts": { + "folderChanged": "Switched to {name}", + "openFolderFailed": "Failed to open folder", + "switchedToChatMode": "Alternado para o modo de chat", + "openStashFailed": "Failed to open stash window", + "openMergeFailed": "Failed to open merge window" + } + }, + "cloneDialog": { + "title": "Clonar repositório", + "repositoryUrl": "URL do repositório", + "repositoryUrlPlaceholder": "https://github.com/user/repo.git", + "directory": "Diretório", + "directoryPlaceholder": "Selecione o diretório de destino...", + "browseDirectory": "Procurar diretório", + "cancel": "Cancelar", + "clone": "Clonar", + "clonePath": "Caminho de clonagem: {path}" + }, + "toasts": { + "cloneFailed": "Falha ao clonar o repositório" + } + }, + "ProjectBoot": { + "title": "Inicializador de Projeto", + "tabs": { + "shadcn": "shadcn", + "hyperframes": "HyperFrames" + }, + "hyperframes": { + "title": "Projeto de vídeo HyperFrames", + "subtitle": "Crie um projeto de HTML para vídeo. O agente do espaço de trabalho pode então escrevê-lo e renderizá-lo.", + "resolution": "Resolução", + "skillsTitle": "Skills dos agentes", + "skillsDesc": "Instala globalmente as skills do HyperFrames (link simbólico) para os agentes selecionados, para que possam criar e renderizar vídeo.", + "recheck": "Verificar novamente", + "installedBadge": "Instalado", + "skillsInstall": "Instalar / atualizar skills", + "skillsInstalling": "Instalando skills…", + "skillsInstalled": "Skills do HyperFrames instaladas", + "skillsInstallFailed": "Não foi possível instalar as skills do HyperFrames" + }, + "config": { + "base": "Base", + "style": "Estilo", + "baseColor": "Cor base", + "theme": "Tema", + "chartColor": "Cor do gráfico", + "iconLibrary": "Biblioteca de ícones", + "font": "Fonte", + "fontHeading": "Fonte do título", + "menuAccent": "Destaque do menu", + "menuColor": "Cor do menu", + "radius": "Raio", + "template": "Modelo", + "createProject": "Criar projeto", + "sectionStyle": "Estilo", + "sectionColors": "Cores", + "sectionTypography": "Tipografia", + "sectionInterface": "Interface" + }, + "preview": { + "loading": "Carregando visualização..." + }, + "createDialog": { + "title": "Criar projeto", + "projectName": "Nome do projeto", + "projectNamePlaceholder": "my-app", + "frameworkTemplate": "Modelo de framework", + "packageManager": "Gerenciador de pacotes", + "saveDirectory": "Diretório de salvamento", + "saveDirectoryPlaceholder": "Selecionar diretório...", + "browseDirectory": "Procurar", + "projectPath": "O projeto será criado em: {path}", + "advancedOptions": "Opções Avançadas", + "base": "Biblioteca Base", + "enableRtl": "Ativar Suporte RTL", + "enableRtlDescription": "Ativar suporte de layout para idiomas da direita para a esquerda (ex.: árabe, hebraico)", + "pmChecking": "Verificando...", + "pmNotInstalled": "Não instalado", + "cancel": "Cancelar", + "create": "Criar", + "creating": "Criando projeto..." + }, + "toasts": { + "createFailed": "Falha ao criar o projeto", + "createSuccess": "Projeto criado com sucesso", + "openWorkspaceFailed": "Projeto criado, mas não foi possível abri-lo no espaço de trabalho" + }, + "errors": { + "directoryExists": "O diretório de destino já existe", + "commandFailed": "O comando de criação do projeto falhou." + } + }, + "WebServiceSettings": { + "addressSwitchHint": "Alternar muda apenas o endereço mostrado e aberto aqui; o serviço escuta em todas as interfaces e continua acessível em cada endereço.", + "sectionTitle": "Serviço Web", + "sectionDescription": "Ativar para acessar o Codeg remotamente pelo navegador", + "port": "Porta", + "status": "Status", + "autoStart": "Início automático", + "autoStartHint": "Iniciar o serviço Web ao abrir o Codeg", + "running": "Em execução", + "stopped": "Parado", + "processing": "Processando...", + "start": "Iniciar", + "stop": "Parar", + "startFailed": "Falha ao iniciar", + "stopFailed": "Falha ao parar", + "saveConfigFailed": "Falha ao salvar as configurações do serviço Web", + "open": "Abrir", + "hide": "Ocultar", + "show": "Mostrar", + "copy": "Copiar", + "qrcode": "Código QR", + "qrcodeTitle": "Escanear para abrir", + "qrcodeHint": "Escaneie com seu telefone para abrir o Codeg no navegador", + "addressLabel": "Endereço de acesso", + "tokenLabel": "Token de acesso", + "tokenHint": "Insira este token ao acessar o cliente Web pela primeira vez", + "tokenPlaceholder": "Deixe em branco para gerar automaticamente", + "regenerate": "Regenerar", + "stalePortOccupiedTitle": "A porta {port} está em uso por outro processo", + "stalePortUnknownTitle": "Estado da porta {port} é incerto", + "stalePortHint": "O Codeg não consegue vincular até a porta ser liberada. Altere a porta acima ou feche o processo que a retém.", + "errors": { + "alreadyRunning": "O serviço Web já está em execução", + "invalidAddress": "Formato de host ou porta inválido", + "portInUse": "A porta {port} já está em uso. Feche o processo que a utiliza ou escolha outra porta.", + "permissionDenied": "Permissão negada. Use uma porta acima de 1024 ou execute com privilégios mais altos.", + "addressUnavailable": "O endereço não está disponível nesta máquina", + "bindFailed": "Falha ao vincular o endereço" + } + }, + "DirectoryBrowser": { + "title": "Explorar diretório", + "pathPlaceholder": "Digite o caminho do diretório...", + "goHome": "Ir para o diretório inicial", + "navigateUp": "Ir para o diretório superior", + "select": "Selecionar", + "cancel": "Cancelar", + "loading": "Carregando...", + "emptyDirectory": "Este diretório está vazio", + "errorLoadingDir": "Falha ao carregar o diretório", + "permissionDenied": "Permissão negada" + }, + "ChatChannelSettings": { + "loading": "Carregando...", + "sectionTitle": "Canais de chat", + "sectionDescription": "Configure bots de IM para receber notificações de eventos e consultar atividade de codificação.", + "addChannel": "Adicionar canal", + "noChannels": "Nenhum canal de chat configurado ainda.", + "channelName": "Nome", + "channelNamePlaceholder": "Meu bot do Telegram", + "channelType": "Tipo de canal", + "lark": "Lark (Feishu)", + "weixin": "WeChat", + "dailyReport": "Relatório diário", + "dailyReportTime": "Horário do relatório", + "nameRequired": "O nome do canal é obrigatório.", + "tokenRequired": "O token é obrigatório.", + "chatIdRequired": "O Chat ID é obrigatório.", + "topicMode": "Modo de grupo por tópicos", + "topicModeHint": "Roteia tópicos de fórum do Telegram como sessões Codeg separadas. O bot deve estar em um supergrupo de fórum e poder gerenciar tópicos.", + "loadFailed": "Falha ao carregar os canais.", + "saveFailed": "Falha ao salvar as alterações.", + "connectSuccess": "Canal conectado.", + "connectFailed": "Falha na conexão", + "disconnectSuccess": "Canal desconectado.", + "disconnectFailed": "Falha ao desconectar.", + "testSuccess": "Teste de conexão aprovado.", + "testFailed": "Teste de conexão falhou", + "deleteSuccess": "Canal excluído.", + "deleteFailed": "Falha ao excluir o canal.", + "deleteConfirmTitle": "Excluir canal", + "deleteConfirmMessage": "O canal e seus registros de mensagens serão excluídos permanentemente. Tem certeza?", + "cancel": "Cancelar", + "delete": "Excluir", + "create": "Criar", + "save": "Salvar", + "channelListTitle": "Canais configurados", + "channelListDescription": "Os canais habilitados serão conectados automaticamente ao iniciar o serviço.", + "editChannel": "Editar canal", + "editSuccess": "Canal atualizado.", + "tokenPlaceholderKeep": "Deixar em branco para manter atual", + "weixinScanTitle": "Escanear código QR", + "weixinScanDescription": "Abra o WeChat e escaneie o código QR para conectar.", + "weixinQrcodeExpired": "Código QR expirado.", + "weixinRefreshQrcode": "Atualizar", + "weixinWaitingScan": "Aguardando escaneamento...", + "weixinPollError": "Conexão instável, tentando novamente...", + "weixinReconnectNotice": "Devido a limitações do protocolo iLink, após cada reconexão você precisa enviar uma mensagem ao bot para que os disparadores de eventos tenham efeito.", + "connect": "Conectar", + "disconnect": "Desconectar", + "test": "Testar conexão", + "tabs": { + "channels": "Canais", + "commands": "Comandos", + "events": "Eventos", + "other": "Outros" + }, + "commands": { + "title": "Comandos integrados", + "description": "Comandos de bot disponíveis nos canais de chat. Em chats em grupo, @Bot é necessário para processar mensagens.", + "prefixLabel": "Prefixo de comando", + "prefixDescription": "1-3 caracteres não alfanuméricos para acionar comandos do bot (padrão /).", + "prefixSaved": "Prefixo de comando salvo.", + "prefixSaveFailed": "Falha ao salvar o prefixo.", + "prefixInvalid": "O prefixo deve ser de 1-3 caracteres não alfanuméricos.", + "save": "Salvar", + "folderDesc": "Selecionar pasta de trabalho", + "agentDesc": "Selecionar agente de IA", + "taskDesc": "Criar sessão e executar tarefa", + "sessionsDesc": "Listar sessões ativas na pasta", + "resumeDesc": "Conversas recentes / retomar uma sessão", + "cancelDesc": "Cancelar tarefa atual", + "approveDesc": "Aprovar solicitação de permissão do agente", + "denyDesc": "Negar solicitação de permissão do agente", + "searchDesc": "Pesquisar conversas por palavra-chave", + "todayDesc": "Resumo da atividade de hoje", + "statusDesc": "Status da conexão do canal", + "helpDesc": "Mostrar ajuda" + }, + "events": { + "title": "Notificações de eventos", + "description": "Ao habilitar eventos, eles serão enviados ao canal quando acionados.", + "turnComplete": "Turno concluído", + "turnCompleteDesc": "Quando um turno do agente termina", + "error": "Erro do agente", + "errorDesc": "Quando um agente encontra um erro", + "permissionRequest": "Solicitação de permissão", + "permissionRequestDesc": "Quando um agente solicita permissão para agir", + "questionRequest": "Pergunta do agente", + "questionRequestDesc": "Quando um agente faz uma pergunta", + "userPromptSent": "Mensagem do usuário", + "userPromptSentDesc": "Quando você envia uma mensagem (o texto da mensagem é incluído na notificação)", + "saved": "Filtro de eventos atualizado.", + "saveFailed": "Falha ao salvar o filtro de eventos.", + "loadFailed": "Falha ao carregar as configurações.", + "retry": "Tentar novamente", + "webhooksTitle": "Webhooks", + "webhooksDescription": "Envia uma carga JSON via POST para uma ou mais URLs quando um evento ativado ocorre. O filtro de eventos acima também se aplica aos webhooks.", + "webhookUrlPlaceholder": "https://example.com/webhook", + "addWebhook": "Adicionar webhook", + "removeWebhook": "Remover webhook", + "webhookSave": "Salvar", + "webhooksSaved": "Webhooks salvos.", + "webhooksSaveFailed": "Falha ao salvar os webhooks.", + "webhookInvalidUrl": "Insira URLs http(s) válidas.", + "docsTitle": "Formato da requisição", + "docsMethod": "Método", + "docsContentType": "Content-Type", + "docsNote": "Cada evento ativado é entregue a todas as URLs. Os webhooks não têm debounce; o filtro de eventos acima continua valendo.", + "editWebhook": "Editar webhook", + "enableWebhook": "Ativar webhook", + "webhookDuplicate": "Esta URL já está configurada.", + "cancel": "Cancelar", + "webhooksEmpty": "Nenhum webhook configurado ainda.", + "deleteWebhookTitle": "Excluir webhook", + "deleteWebhookMessage": "Remover este webhook? Os eventos não serão mais entregues a esta URL.", + "delete": "Excluir" + }, + "language": { + "title": "Idioma das mensagens", + "description": "Idioma utilizado para notificações de eventos, respostas de comandos e relatórios diários enviados aos canais de chat.", + "saved": "Idioma das mensagens salvo.", + "saveFailed": "Falha ao salvar o idioma das mensagens.", + "en": "Inglês", + "zh-cn": "Chinês simplificado", + "zh-tw": "Chinês tradicional", + "ja": "Japonês", + "ko": "Coreano", + "es": "Espanhol", + "de": "Alemão", + "fr": "Francês", + "pt": "Português", + "ar": "Árabe" + } + }, + "ModelProviderSettings": { + "sectionTitle": "Provedores de Modelos", + "sectionDescription": "Gerenciar credenciais de provedores de API para agentes.", + "filterAll": "Todos", + "providerListTitle": "Provedores Configurados", + "addProvider": "Adicionar Provedor", + "editProvider": "Editar Provedor", + "noProviders": "Nenhum provedor de modelo configurado.", + "providerName": "Nome", + "providerNamePlaceholder": "Ex. OpenAI, Anthropic", + "apiUrl": "URL da API", + "apiUrlPlaceholder": "https://api.openai.com/v1", + "apiKey": "Chave da API", + "apiKeyPlaceholder": "sk-...", + "apiKeyKeepCurrent": "Deixe em branco para manter atual", + "agentTypes": "Tipos de Agente", + "agentTypesRequired": "Pelo menos um tipo de agente é necessário.", + "agentType": "Tipo de Agente", + "agentTypeRequired": "O tipo de agente é obrigatório.", + "agentTypeImmutableHint": "O tipo de agente não pode ser alterado após a criação.", + "model": "Modelo", + "modelPlaceholderCodex": "gpt-5.6-sol / gpt-5.5", + "modelPlaceholderGemini": "gemini-3-pro-preview", + "claudeMainModel": "Modelo Principal", + "claudeReasoningModel": "Modelo de Raciocínio (pensamento)", + "claudeHaikuDefaultModel": "Modelo Haiku Padrão", + "claudeSonnetDefaultModel": "Modelo Sonnet Padrão", + "claudeOpusDefaultModel": "Modelo Opus Padrão", + "claudeCustomModelOption": "ID do modelo personalizado", + "claudeCustomModelOptionName": "Nome do modelo personalizado", + "claudeCustomModelOptionDescription": "Descrição do modelo personalizado", + "claudeCustomModelOptionHint": "Adiciona uma única entrada personalizada ao seletor de modelos do Claude (por exemplo, um modelo atrás de um gateway/proxy personalizado). Nome e descrição são informações de exibição opcionais.", + "nameRequired": "O nome do provedor é obrigatório.", + "apiUrlRequired": "A URL da API é obrigatória.", + "apiKeyRequired": "A chave da API é obrigatória.", + "loadFailed": "Falha ao carregar provedores.", + "saveFailed": "Falha ao salvar alterações.", + "createSuccess": "Provedor criado.", + "editSuccess": "Provedor atualizado.", + "deleteSuccess": "Provedor excluído.", + "deleteConfirmTitle": "Excluir Provedor", + "deleteConfirmMessage": "O provedor \"{name}\" será excluído permanentemente. Tem certeza?", + "deleteBlockedByAgent": "{agents} está usando este provedor. Desvincule-o antes de excluir.", + "cancel": "Cancelar", + "delete": "Excluir", + "create": "Criar", + "save": "Salvar", + "affectedRunningSessions": "{count, plural, one {# sessão ativa precisa reconectar para aplicar a alteração} other {# sessões ativas precisam reconectar para aplicar a alteração}}" + }, + "SkillMatrix": { + "loading": "Carregando…", + "searchPlaceholder": "Pesquisar por nome, id ou descrição", + "empty": "Nada para mostrar.", + "emptySearch": "Nenhuma correspondência para a pesquisa atual.", + "skillColumn": "Habilidade", + "selectAll": "Selecionar tudo visível", + "selectSkill": "Selecionar {name}", + "everything": { + "label": "Em massa", + "enable": "Ativar tudo (visível)", + "disable": "Desativar tudo (visível)" + }, + "columnMenu": { + "enableAll": "Ativar todas as habilidades", + "disableAll": "Desativar todas as habilidades" + }, + "rowMenu": { + "label": "Ações em massa para {name}", + "enableAll": "Ativar para todos os agentes", + "disableAll": "Desativar para todos os agentes" + }, + "bulk": { + "selected": "{count} selecionados", + "targetAll": "Todos os agentes", + "targetSome": "{count} agentes", + "enable": "Ativar", + "disable": "Desativar", + "clear": "Limpar" + }, + "confirm": { + "disableTitle": "Desativar estes links?", + "disableBody": "Isto remove {count} links de habilidades gerenciados pelo codeg. Habilidades que ocupam um diretório personalizado não são afetadas. Você pode reativá-las a qualquer momento.", + "cancel": "Cancelar", + "confirm": "Desativar" + }, + "toasts": { + "loadFailed": "Falha ao carregar os status das habilidades", + "applyFailed": "Falha ao aplicar as alterações", + "enabled": "{count} links ativados", + "disabled": "{count} links desativados", + "enabledPartial": "{ok} ativados, {failed} falharam", + "disabledPartial": "{ok} desativados, {failed} falharam" + }, + "detail": { + "enableForAgents": "Ativar para agentes", + "preview": "Visualização do SKILL.md", + "loadingContent": "Carregando conteúdo…" + }, + "copyModeHint": "Copiado (não vinculado) — reative após atualizações para obter a versão mais recente" + }, + "ExpertsSettings": { + "title": "Habilidades de Especialista", + "description": "Ative fluxos de trabalho de habilidades selecionados e comprovados em campo para seus agentes de codificação de IA. Cada especialista é uma habilidade independente do projeto superpowers — o codeg gerencia a cópia central e a vincula aos agentes escolhidos.", + "loading": "Carregando especialistas…", + "loadingContent": "Carregando conteúdo…", + "emptyExperts": "Nenhum especialista disponível. Verifique os logs da aplicação.", + "emptySelection": "Selecione um especialista para ver seu conteúdo e gerenciar a ativação.", + "emptySearch": "Nenhum especialista corresponde à pesquisa atual.", + "searchPlaceholder": "Pesquisar especialistas por nome, ID ou descrição", + "enableForAgents": "Ativar para agentes", + "noAgents": "Nenhum agente ACP detectado.", + "copyModeWarning": "Copiado (não vinculado). Reative após as atualizações do codeg para obter a versão mais recente.", + "previewTitle": "Prévia do SKILL.md", + "categories": { + "discovery": "Descoberta e Design", + "planning": "Planejamento", + "execution": "Execução", + "quality": "Qualidade e Testes", + "debugging": "Depuração", + "review": "Revisão e Integração", + "meta": "Meta" + }, + "states": { + "not_linked": "Não ativado", + "linked_to_codeg": "Ativado", + "linked_elsewhere": "Bloqueado — outro vínculo existe", + "blocked_by_real_directory": "Bloqueado — uma habilidade personalizada ocupa este nome", + "broken": "Vínculo quebrado" + }, + "badges": { + "userModified": "Modificado pelo usuário" + }, + "actions": { + "openCentralDir": "Abrir pasta central", + "refresh": "Atualizar" + }, + "toasts": { + "loadFailed": "Falha ao carregar detalhes do especialista", + "enabled": "Especialista ativado para este agente", + "disabled": "Especialista desativado para este agente", + "enableFailed": "Falha ao ativar o especialista", + "disableFailed": "Falha ao desativar o especialista", + "openFolderFailed": "Falha ao abrir a pasta" + } + }, + "ScienceSettings": { + "title": "Habilidades de pesquisa científica", + "description": "Ative habilidades de pesquisa científica selecionadas para seus agentes de código com IA: geração de hipóteses, delineamento experimental, estatística, visualização, avaliação crítica e busca de literatura. O codeg gerencia uma cópia central e vincula cada habilidade aos agentes que você escolher.", + "loading": "Carregando habilidades científicas…", + "emptySkills": "Nenhuma habilidade científica disponível. Verifique os registros do aplicativo.", + "searchPlaceholder": "Pesquisar habilidades científicas por nome, id ou descrição", + "categories": { + "ideation": "Ideação", + "design": "Delineamento", + "analysis": "Análise", + "visualization": "Visualização", + "evaluation": "Avaliação", + "literature": "Literatura" + }, + "states": { + "not_linked": "Não ativado", + "linked_to_codeg": "Ativado", + "linked_elsewhere": "Bloqueado — outro vínculo existe", + "blocked_by_real_directory": "Bloqueado — uma habilidade personalizada ocupa este nome", + "broken": "Vínculo quebrado" + }, + "badges": { + "userModified": "Modificado pelo usuário", + "needsKey": "Requer chave", + "needsSetup": "Pode exigir configuração" + }, + "actions": { + "openCentralDir": "Abrir pasta central", + "refresh": "Atualizar" + }, + "toasts": { + "openFolderFailed": "Falha ao abrir a pasta" + } + }, + "OfficeToolsSettings": { + "title": "Ferramentas Office", + "description": "Gerencie as habilidades do OfficeCLI para criar arquivos Excel, Word e PowerPoint. Instale o OfficeCLI, sincronize as habilidades e ative-as por agente.", + "loadingContent": "Carregando conteúdo…", + "emptySkills": "Nenhuma habilidade disponível. Instale o OfficeCLI e sincronize as habilidades.", + "emptySelection": "Selecione uma habilidade para ver seu conteúdo e gerenciar a ativação.", + "emptySearch": "Nenhuma habilidade encontrada.", + "searchPlaceholder": "Pesquisar habilidades por nome, ID ou descrição", + "enableForAgents": "Ativar para agentes", + "noAgents": "Nenhum agente ACP detectado.", + "installFirst": "Instale o OfficeCLI primeiro para ativar as habilidades.", + "syncFirst": "Sincronize as habilidades primeiro para carregar o conteúdo.", + "noContent": "Nenhum conteúdo disponível.", + "copyModeWarning": "Copiado (não vinculado). Sincronize novamente para obter a versão mais recente.", + "previewTitle": "Pré-visualização SKILL.md", + "detection": { + "installed": "Instalado", + "notInstalled": "Não instalado", + "notRunnable": "Instalado, mas não executável", + "installHint": "Instale o OfficeCLI para habilitar as habilidades de geração de documentos Office para seus agentes de IA.", + "install": "Instalar", + "uninstall": "Desinstalar", + "syncSkills": "Sincronizar habilidades" + }, + "categories": { + "general": "Geral", + "presentations": "Apresentações", + "documents": "Documentos", + "spreadsheets": "Planilhas" + }, + "states": { + "not_linked": "Não ativado", + "linked_to_codeg": "Ativado", + "linked_elsewhere": "Bloqueado — existe outro link", + "blocked_by_real_directory": "Bloqueado — uma habilidade personalizada ocupa este nome", + "broken": "Link quebrado" + }, + "badges": { + "notSynced": "Não sincronizado" + }, + "actions": { + "refresh": "Atualizar" + }, + "toasts": { + "loadFailed": "Falha ao carregar detalhes da habilidade", + "enabled": "Habilidade ativada para este agente", + "disabled": "Habilidade desativada para este agente", + "enableFailed": "Falha ao ativar habilidade", + "disableFailed": "Falha ao desativar habilidade", + "installSuccess": "OfficeCLI instalado com sucesso", + "installFailed": "Falha ao instalar o OfficeCLI", + "uninstallSuccess": "OfficeCLI desinstalado", + "uninstallFailed": "Falha ao desinstalar o OfficeCLI", + "syncSuccess": "{synced} habilidades sincronizadas", + "syncPartial": "{synced} sincronizadas, {errors} falharam", + "syncFailed": "Falha ao sincronizar habilidades" + }, + "autoPreviewLabel": "Abrir visualização automaticamente", + "autoPreviewHint": "Quando um agente cria ou edita um arquivo do Word, Excel ou PowerPoint, abre sua visualização ao vivo automaticamente." + }, + "SkillPacksSettings": { + "title": "Pacotes de habilidades", + "description": "Pacotes de habilidades selecionados que o codeg gerencia de forma centralizada e vincula aos seus agentes de IA — especialistas em programação, pesquisa científica e ferramentas de documentos de escritório. Ative-os por agente abaixo.", + "tabs": { + "experts": "Especialistas", + "science": "Ciência", + "office": "Ferramentas de escritório", + "custom": "Personalizadas" + }, + "actions": { + "openCentralDir": "Abrir pasta central", + "refresh": "Atualizar" + }, + "toasts": { + "openFolderFailed": "Falha ao abrir a pasta" + } + }, + "QuickMessagesSettings": { + "title": "Mensagens rápidas", + "description": "Gerencie trechos de mensagens reutilizáveis. Arraste para reordenar.", + "loading": "Carregando mensagens rápidas…", + "emptyList": "Ainda não há mensagens rápidas. Clique em \"Nova\" para criar uma.", + "emptySelection": "Selecione uma mensagem rápida para editar.", + "searchPlaceholder": "Pesquisar por título ou conteúdo", + "untitled": "Sem título", + "actions": { + "new": "Nova", + "save": "Salvar", + "delete": "Excluir", + "dragSort": "Arraste para reordenar", + "dragSortMessage": "Arrastar para reordenar mensagem rápida: {name}" + }, + "fields": { + "title": "Título", + "titlePlaceholder": "Dê um título curto a esta mensagem", + "content": "Conteúdo", + "contentPlaceholder": "Digite aqui o conteúdo da mensagem" + }, + "confirmDelete": { + "title": "Excluir mensagem rápida?", + "message": "Isso excluirá permanentemente \"{name}\". Tem certeza?", + "cancel": "Cancelar", + "confirm": "Excluir" + }, + "toasts": { + "loadFailed": "Falha ao carregar mensagens rápidas", + "createFailed": "Falha ao criar mensagem rápida", + "saveFailed": "Falha ao salvar mensagem rápida", + "deleteFailed": "Falha ao excluir mensagem rápida", + "saveOrderFailed": "Falha ao salvar a ordem", + "created": "Mensagem rápida criada", + "saved": "Mensagem rápida salva", + "deleted": "Mensagem rápida excluída" + } + }, + "Pet": { + "badge": { + "running": "{count} em execução", + "waiting": "{count} aguardando aprovação", + "error": "{count} com erro" + }, + "panel": { + "title": "Sessões ativas", + "empty": "Nenhuma sessão ativa", + "emptyHint": "Agentes em execução e os que precisam de você aparecem aqui.", + "statusRunning": "Em execução", + "statusWaiting": "Aguardando", + "statusError": "Erro", + "subAgentOf": "Subagente de" + }, + "menu": { + "scale": "Escala", + "openManager": "Gerenciar pets", + "close": "Fechar" + }, + "loadError": "Falha ao carregar pet", + "missingPetIdParam": "Nenhum pet selecionado", + "summonButton": "Pet", + "manager": { + "title": "Pets", + "description": "Companheiros flutuantes de desktop com sprites compatíveis com o Codex.", + "addPet": "Adicionar pet", + "importFromCodex": "Importar do Codex", + "noPets": "Sem pets. Adicione um ou importe do Codex.", + "setActive": "Ativar", + "active": "Ativo", + "edit": "Editar", + "delete": "Excluir", + "deleteConfirm": "Excluir o pet \"{name}\"? Será removido do disco.", + "summon": "Invocar janela do pet", + "openCodexHelp": "Pets do Codex precisam estar em ~/.codex/pets/. Nenhum encontrado.", + "specRequirement": "O sprite precisa ter 1536px de largura e altura múltipla de 208px (ex.: 1872 ou 2288), em PNG ou WebP com transparência.", + "form": { + "id": "ID do pet", + "idHelp": "Minúsculas, dígitos, '-' e '_'. Máx 64 caracteres.", + "displayName": "Nome", + "description": "Descrição (opcional)", + "spritesheet": "Sprite", + "chooseFile": "Escolher arquivo", + "replaceFile": "Substituir sprite", + "saveCreate": "Adicionar pet", + "saveUpdate": "Salvar alterações", + "cancel": "Cancelar" + }, + "errors": { + "missingId": "ID obrigatório", + "missingName": "Nome obrigatório", + "missingSpritesheet": "Sprite obrigatório", + "addFailed": "Falha ao adicionar", + "updateFailed": "Falha ao atualizar", + "deleteFailed": "Falha ao excluir", + "loadFailed": "Falha ao carregar pets", + "setActiveFailed": "Falha ao ativar pet", + "summonFailed": "Falha ao abrir a janela do pet" + } + }, + "import": { + "title": "Importar do Codex", + "subtitle": "Pets disponíveis em ~/.codex/pets/.", + "selectAll": "Selecionar todos", + "alreadyImported": "Já importado", + "renameOnConflict": "Renomear conflitos com sufixo -imported", + "import": "Importar selecionados", + "noneFound": "Nenhum pet do Codex disponível.", + "imported": "Importação concluída", + "failed": "Falha no import", + "close": "Fechar" + }, + "marketplace": { + "openMarketplace": "Mercado de pets", + "title": "Mercado de pets", + "search": "Buscar pets", + "kindFilter": { + "all": "Todos", + "object": "Objeto", + "animal": "Animal", + "person": "Pessoa", + "creature": "Criatura" + }, + "sortFilter": { + "latest": "Recentes", + "popular": "Populares", + "views": "Mais vistos" + }, + "refresh": "Atualizar", + "install": "Instalar", + "installing": "Instalando", + "reinstall": "Reinstalar", + "reinstallConfirm": "Sobrescrever o pet local \"{name}\"? Os dados existentes serão substituídos.", + "cancel": "Cancelar", + "stats": { + "views": "Visualizações", + "downloads": "Downloads", + "likes": "Curtidas" + }, + "actions": { + "idle": "Parado", + "running_right": "Corre dir.", + "running_left": "Corre esq.", + "waving": "Acena", + "jumping": "Pula", + "failed": "Falha", + "waiting": "Espera", + "running": "Corre", + "review": "Revisão" + }, + "page": "Página {page} de {total}", + "prev": "Anterior", + "next": "Próxima", + "empty": "Nenhum pet corresponde.", + "successInstalled": "\"{name}\" instalado", + "errors": { + "loadFailed": "Falha ao carregar o mercado", + "installFailed": "Falha ao instalar o pet", + "alreadyInstalled": "O pet já existe localmente" + } + } + }, + "RemoteWorkspace": { + "openRemoteWorkspace": "Open remote workspace", + "manage": "Manage remote workspace", + "manageTitle": "Remote Workspace connections", + "empty": "No remote connections", + "searchPlaceholder": "Search remote workspaces", + "orderFailed": "Failed to save remote workspace order", + "dragSort": "Drag to sort", + "dragSortConnection": "Drag to sort {name}", + "newConnection": "New connection", + "loading": "Loading", + "loadingConnection": "Loading remote connection", + "name": "Name", + "baseUrl": "Service URL", + "token": "Access token", + "save": "Save", + "delete": "Delete", + "confirmDelete": { + "title": "Delete remote connection?", + "message": "This will remove \"{name}\" from this device. This action cannot be undone.", + "cancel": "Cancel", + "confirm": "Delete" + }, + "saved": "Remote connection saved.", + "deleted": "Remote connection deleted.", + "loadFailed": "Failed to load remote connections", + "saveFailed": "Failed to save remote connection", + "deleteFailed": "Failed to delete remote connection", + "openFailed": "Failed to open remote workspace", + "connectionLoadFailed": "Failed to load remote connection: {message}", + "connectionExpired": "Remote connection \"{name}\" is expired. Update its token and reload this window." + }, + "ServerFileBrowser": { + "title": "Selecionar arquivo do servidor", + "pathPlaceholder": "Inserir caminho do diretório...", + "goHome": "Ir para o diretório inicial", + "navigateUp": "Ir para o diretório acima", + "select": "Selecionar", + "cancel": "Cancelar", + "loading": "Carregando...", + "emptyDirectory": "Este diretório está vazio", + "errorLoadingDir": "Falha ao carregar o diretório", + "selectedCount": "{count} selecionado(s)" + }, + "BackupSettings": { + "title": "Backup e restauração", + "description": "Exporte um backup portátil dos seus dados do codeg ou restaure a partir de um.", + "tabs": { + "backup": "Backup", + "restore": "Restauração" + }, + "export": { + "includeExternal": "Incluir o conteúdo das conversas", + "includeExternalHint": "Também arquiva as transcrições das CLIs (Claude, Codex, Gemini, …). Aumenta o tamanho.", + "passphrase": "Senha (opcional)", + "passphrasePlaceholder": "Deixe em branco para um arquivo sem criptografia", + "passphraseConfirm": "Confirmar a senha", + "passphraseMismatch": "As senhas não coincidem.", + "noPassphraseWarning": "Este backup conterá segredos (chaves de API, tokens) em texto puro. Guarde-o em local seguro.", + "passphraseLossWarning": "Criptografado com esta senha. Se você perdê-la, o backup não poderá ser recuperado.", + "button": "Exportar backup", + "inProgress": "Criando backup…", + "success": "Backup criado.", + "started": "Download do backup iniciado." + }, + "restore": { + "selectFile": "Selecionar arquivo de backup", + "passphrasePrompt": "Este backup está criptografado. Digite a senha dele.", + "unlock": "Desbloquear", + "preview": { + "title": "Detalhes do backup", + "encrypted": "Criptografado", + "compatible": "Compatível", + "incompatible": "Incompatível", + "createdAt": "Criado: {value}", + "appVersion": "Versão do app: {value}", + "incompatibleHint": "Este backup foi criado por uma versão mais recente do codeg e não pode ser restaurado." + }, + "replaceWarning": "Restaurar substitui todos os dados atuais do codeg (banco de dados e uploads). Seus dados atuais são salvos em um snapshot primeiro, para que possam ser recuperados.", + "keyringNote": "Os tokens de GitHub/chat do desktop ficam no chaveiro do sistema e não são incluídos; insira-os novamente após restaurar.", + "button": "Restaurar", + "staging": "Preparando a restauração…", + "staged": "Restauração preparada. Reiniciando…", + "restarting": "Restauração preparada. Reiniciando o servidor…", + "restartTimeout": "O servidor não voltou a tempo. Recarregue a página quando ele estiver ativo.", + "externalSideLocation": "As transcrições de conversas foram restauradas em {path}", + "confirmTitle": "Substituir todos os dados?", + "confirmBody": "Isto substituirá seu banco de dados e uploads atuais do codeg pelo backup e, em seguida, reiniciará. Seus dados atuais são salvos em um snapshot primeiro.", + "cancel": "Cancelar", + "confirmAction": "Substituir e reiniciar", + "external": { + "title": "Conteúdo das conversas", + "hint": "Este backup inclui transcrições das CLIs. Escolha para onde restaurá-las.", + "modeSkip": "Não restaurar", + "modeSide": "Restaurar em uma pasta separada segura", + "modeOriginal": "Restaurar nos locais originais das CLIs", + "forceOverwrite": "Sobrescrever arquivos existentes", + "forceOverwriteHint": "Substitui os arquivos que já existem nas pastas das CLIs.", + "scanning": "Verificando conflitos…", + "noConflicts": "Nenhum arquivo existente será sobrescrito.", + "conflictCount": "{count} arquivo(s) existente(s) seriam afetados.", + "conflictSkipNote": "Os arquivos existentes são mantidos (ignorados) a menos que você ative a sobrescrita." + }, + "restartFailed": "Restauração preparada, mas o servidor não conseguiu reiniciar. Reinicie-o manualmente para aplicá-la." + }, + "remoteUnsupported": "O backup e a restauração atuam sobre os dados da máquina que executa o codeg. Você está conectado a um espaço de trabalho remoto — gerencie os backups dele diretamente nesse servidor." + }, + "backup": { + "restore": { + "error": { + "badPassphrase": "Senha incorreta ou backup corrompido.", + "corrupted": "O arquivo de backup está corrompido.", + "unknownFormat": "Este arquivo não é um backup do codeg reconhecido.", + "newerVersion": "Este backup foi criado pelo codeg {backupVersion}, mais recente que esta versão ({appVersion}).", + "alreadyPending": "Já existe uma restauração preparada. Reinicie para aplicá-la antes de preparar outra." + } + }, + "error": { + "diskSpace": "Espaço em disco insuficiente para concluir a operação.", + "cancelled": "A operação foi cancelada." + } + }, + "WebConnection": { + "disconnectedTitle": "Conexão perdida", + "reconnectingDescription": "Tentando reconectar ao servidor. Normalmente isso se resolve sozinho em alguns segundos.", + "reconnectNow": "Reconectar agora", + "sessionExpiredTitle": "Sessão expirada", + "sessionExpiredDescription": "Sua sessão não é mais válida. Faça login novamente para continuar.", + "goToLogin": "Ir para o login" + }, + "LiveFeedback": { + "placeholder": "Envie uma nota para {agent} enquanto ele trabalha…", + "agentFallback": "o agente", + "ariaLabel": "Nota de feedback ao vivo", + "dialogTitle": "Feedback ao vivo", + "dialogDescription": "Envie uma nota ao agente enquanto ele trabalha. Ele a lerá na próxima verificação, sem interromper a etapa atual.", + "dialogDescriptionInstant": "Envie uma nota ao agente enquanto ele trabalha. Ela é inserida imediatamente no turno atual — o agente a vê na hora.", + "channelDowngraded": "A inserção instantânea não está disponível nesta sessão — sua nota foi salva para o agente ler na próxima verificação.", + "send": "Enviar", + "cancel": "Cancelar", + "pending": "aguardando", + "delivered": "recebida", + "turnEndedUnread": "O agente terminou antes de ler o seu feedback.", + "sendAsMessage": "Enviar como mensagem", + "dismiss": "Dispensar", + "turnEndedResent": "O turno terminou — enviado como nova mensagem.", + "turnEnded": "O turno já terminou.", + "submitFailed": "Não foi possível enviar a sua nota" + }, + "AgentToolsSettings": { + "title": "Ferramentas na conversa", + "description": "Ferramentas extras que o codeg dá a um agente dentro de uma conversa. Elas são injetadas quando o agente inicia, então a mudança vale para os agentes iniciados depois.", + "feedbackLabel": "Feedback ao vivo", + "feedbackHint": "Envie notas e correções a um agente enquanto ele trabalha. Se o agente oferecer inserção instantânea, sua nota entra imediatamente no turno em andamento; caso contrário, o agente recebe uma ferramenta para verificar seu feedback — esses agentes normalmente só verificam quando você menciona isso no prompt, por exemplo, adicione \"verifique meu feedback ao vivo regularmente\" à sua mensagem.", + "questionLabel": "Perguntar ao usuário", + "questionHint": "Permite que os agentes pausem e façam uma pergunta de múltipla escolha que aparece acima da caixa de entrada da conversa. O agente aguarda até você responder (ou pular).", + "sessionInfoLabel": "Obter informações da sessão", + "sessionInfoHint": "Permite que os agentes consultem uma sessão mencionada na sua mensagem (um selo de sessão) para ler o título, agente, status, espaço de trabalho, uso de tokens e mensagens recentes.", + "automationsLabel": "Criar automações", + "automationsHint": "Salva a conversa como uma automação que roda em um agendamento. Desativado por padrão — depois ela inicia agentes por conta própria.", + "workTasksLabel": "Criar tarefas a fazer", + "workTasksHint": "Coloca um cartão no quadro de tarefas a partir da conversa. Desativado por padrão — grava o estado do app.", + "save": "Salvar", + "saving": "Salvando…", + "saved": "Configurações de ferramentas salvas", + "saveFailed": "Falha ao salvar as configurações de ferramentas", + "loadFailed": "Falha ao carregar: {detail}" + }, + "NotificationSoundSettings": { + "title": "Sons de notificação", + "description": "Reproduz um som curto quando ocorre um evento do agente. São os mesmos eventos enviados aos canais de chat; esta configuração vale apenas para este dispositivo.", + "enableHint": "Desativado por padrão. Os sons tocam apenas na janela do espaço de trabalho deste navegador ou aplicativo.", + "volume": "Volume", + "preview": "Ouvir", + "previewEvent": "Ouvir o som de {event}", + "onlyWhenUnfocused": "Somente quando a janela não estiver em foco", + "onlyWhenUnfocusedHint": "Fica em silêncio enquanto você está olhando para o Codeg.", + "eventsTitle": "Eventos", + "eventsHint": "Escolha um som para cada evento ou «Silencioso» para ignorá-lo. Se o mesmo evento se repetir em poucos segundos, ele toca apenas uma vez.", + "toneNone": "Silencioso", + "toneChime": "Carrilhão", + "toneDing": "Sino", + "toneBlip": "Bipe", + "tonePop": "Pop", + "toneAlert": "Alerta", + "toneDescend": "Descendente" + }, + "LogsSettings": { + "loading": "Carregando…", + "sectionTitle": "Registros de execução", + "sectionDescription": "Visualize e configure os registros de diagnóstico do aplicativo. Os registros são gravados em arquivos locais e mantidos na memória para visualização ao vivo.", + "captureTitle": "Nível de registro", + "captureDescription": "Controla quanto detalhe é capturado. Níveis mais altos (Debug, Trace) registram mais, mas geram registros maiores. «Desligado» desativa o registro.", + "captureLabel": "Nível de captura", + "levels": { + "off": "Desligado", + "error": "Erro", + "warn": "Aviso", + "info": "Informação", + "debug": "Depuração", + "trace": "Rastreamento" + }, + "viewerTitle": "Registros recentes", + "viewerDescription": "Visualização ao vivo dos registros recentes. Filtre por nível ou pesquise texto.", + "searchPlaceholder": "Pesquisar mensagem ou origem…", + "viewLevels": { + "all": "Todos os níveis", + "error": "Erro e acima", + "warn": "Aviso e acima", + "info": "Informação e acima", + "debug": "Depuração e acima", + "trace": "Rastreamento e acima" + }, + "pause": "Pausar", + "resume": "Ao vivo", + "refresh": "Atualizar", + "clear": "Limpar", + "openFolder": "Abrir pasta", + "shownCount": "{shown} / {total} exibidos", + "empty": "Nenhum registro para exibir.", + "levelSaveFailed": "Falha ao salvar o nível de registro", + "openFolderFailed": "Falha ao abrir a pasta de registros", + "downloadFailed": "Falha ao baixar o arquivo de registro", + "filesTitle": "Arquivos de registro", + "filesDescription": "Baixe arquivos de registro completos do disco para o histórico além do buffer ao vivo.", + "filesEmpty": "Ainda não há arquivos de registro.", + "download": "Baixar", + "downloadTruncated": "O arquivo é grande; foram baixados os {size} mais recentes. O arquivo completo está no diretório de logs.", + "captureEnvLocked": "O nível de registro é controlado pela variável de ambiente RUST_LOG / CODEG_LOG; altere-a lá para ter efeito.", + "targetsTitle": "Substituições por módulo", + "targetsDescription": "Defina um nível diferente para módulos específicos (ex.: codeg_lib::acp) sem alterar o nível global.", + "targetsAdd": "Adicionar", + "targetsRemove": "Remover substituição", + "toggleDetails": "Alternar detalhes" + }, + "Automations": { + "title": "Automações", + "new": "Nova automação", + "empty": "Ainda não há automações", + "emptyHint": "Crie uma para executar uma tarefa do agente de forma agendada ou manual.", + "name": "Nome", + "namePlaceholder": "ex.: Revisão de PR noturna", + "prompt": "Instrução", + "promptPlaceholder": "O que o agente deve fazer?", + "agent": "Agente", + "folder": "Pasta do espaço de trabalho", + "folderPlaceholder": "Selecione uma pasta", + "isolation": "Isolamento", + "isolationWorktree": "Novo worktree por execução", + "isolationShared": "Executar na pasta", + "isolationSharedCaveat": "As execuções usam diretamente a árvore de trabalho desta pasta e podem entrar em conflito com suas alterações não confirmadas. Ative a opção de worktree para isolar cada execução.", + "trigger": "Gatilho", + "triggerSchedule": "Agendado", + "triggerManual": "Somente manual", + "cron": "Agendamento (cron)", + "cronPlaceholder": "0 9 * * 1-5", + "timezone": "Fuso horário", + "nextRun": "Próxima execução", + "branch": "Branch", + "branchOptional": "Branch (opcional)", + "enabled": "Ativado", + "save": "Salvar", + "cancel": "Cancelar", + "edit": "Editar", + "delete": "Excluir", + "runNow": "Executar agora", + "cancelRun": "Cancelar execução", + "runHistory": "Histórico de execuções", + "noRuns": "Ainda não há execuções", + "allFolders": "Todas as pastas", + "filterAll": "Todos", + "noMatches": "Nenhuma automação correspondente", + "viewConversation": "Ver conversa", + "lastRun": "Última execução", + "never": "Nunca", + "running": "Em execução", + "deleteTitle": "Excluir automação?", + "deleteDescription": "Isso remove a automação e seu agendamento. O histórico é mantido.", + "statusRunning": "Em execução", + "statusSucceeded": "Concluída", + "statusFailed": "Falhou", + "statusCancelled": "Cancelada", + "statusSkipped": "Ignorada", + "errorName": "O nome é obrigatório", + "errorPrompt": "A instrução é obrigatória", + "errorCron": "Automações agendadas exigem uma expressão cron", + "errorFolder": "Selecione uma pasta do espaço de trabalho", + "presetHourly": "A cada hora", + "presetDaily": "Diariamente 9h", + "presetWeekdays": "Dias úteis 9h", + "presetCustom": "Personalizado", + "probing": "Carregando opções…", + "retry": "Tentar novamente", + "configNone": "Este agente não tem opções configuráveis", + "inherit": "Padrão do agente", + "mode": "Modo", + "config": "Configuração", + "branchPlaceholder": "(branch padrão)", + "selectHint": "Selecione uma automação para ver os detalhes", + "refresh": "Atualizar", + "onboardTitle": "Automatize tarefas rotineiras do agente", + "onboardHint": "Agende um agente para revisar código, atualizar dependências ou triar problemas, periodicamente ou sob demanda.", + "headerSubtitle": "Tarefas do agente agendadas e sob demanda", + "startFromTemplate": "Começar com um modelo", + "blankTitle": "Automação em branco", + "blankDesc": "Configure uma tarefa do agente do zero.", + "backToTemplates": "Modelos", + "sectionSchedule": "Agendamento e destino", + "sectionTarget": "Destino", + "sectionAction": "Ação", + "actionLaunchSession": "Executar sessão", + "actionEnqueueTask": "Enfileirar tarefa", + "actionEnqueueTaskHint": "Cada disparo adiciona uma tarefa pendente, com o nome desta automação, às tarefas a fazer da pasta; o motor de tarefas a executa conforme as configurações do quadro.", + "sectionPrompt": "Prompt", + "nextIn": "Próxima em {rel}", + "manual": "Manual", + "schedEveryMinutes": "A cada {n} minutos", + "schedHourly": "De hora em hora", + "schedDaily": "Todos os dias às {time}", + "schedWeekdays": "Dias úteis às {time}", + "schedWeekly": "Toda {day} às {time}", + "schedMonthly": "Mensalmente no dia {day} às {time}", + "dow0": "domingo", + "dow1": "segunda-feira", + "dow2": "terça-feira", + "dow3": "quarta-feira", + "dow4": "quinta-feira", + "dow5": "sexta-feira", + "dow6": "sábado", + "tplCodeReviewTitle": "Revisão de código", + "tplCodeReviewDesc": "Revisa as alterações recentes em busca de bugs, regressões e problemas de qualidade.", + "tplDependencyUpdatesTitle": "Atualização de dependências", + "tplDependencyUpdatesDesc": "Encontra dependências desatualizadas e propõe atualizações seguras.", + "tplTestCoverageTitle": "Cobertura de testes", + "tplTestCoverageDesc": "Encontra caminhos de código sem testes e adiciona os testes que faltam.", + "tplTodoSweepTitle": "Varredura de TODO", + "tplTodoSweepDesc": "Reúne comentários TODO e FIXME e os tria por prioridade.", + "tplCiTriageTitle": "Triagem de CI", + "tplCiTriageDesc": "Investiga verificações que falharam recentemente e propõe correções.", + "tplReleaseNotesTitle": "Notas de versão", + "tplReleaseNotesDesc": "Resume as alterações desde a última versão em um changelog.", + "tplSecurityAuditTitle": "Auditoria de segurança", + "tplSecurityAuditDesc": "Verifica vulnerabilidades e padrões de risco e relata as constatações.", + "enable": "Ativar", + "disable": "Desativar", + "moreActions": "Mais ações", + "statusDisabled": "Desativada", + "cronBuilderTitle": "Gerador de agendamento", + "cronFreqLabel": "Frequência", + "cronFreqMinutes": "A cada N minutos", + "cronFreqHourly": "De hora em hora", + "cronFreqDaily": "Diário", + "cronFreqWeekdays": "Dias úteis", + "cronFreqWeekly": "Semanal", + "cronFreqMonthly": "Mensal", + "cronFreqCustom": "Personalizado", + "cronEveryLabel": "Intervalo (minutos)", + "cronTimeLabel": "Hora", + "cronHourLabel": "Hora", + "cronMinuteLabel": "Minuto", + "cronDowLabel": "Dia da semana", + "cronDomLabel": "Dia do mês", + "cronApply": "Aplicar", + "cronPreviewLabel": "Pré-visualização", + "cronOpenBuilder": "Abrir o gerador de agendamento", + "branchDefault": "Branch padrão", + "branchUseCustom": "Usar \"{query}\"", + "branchLocal": "Local", + "branchRemote": "Remoto", + "branchSearchPlaceholder": "Pesquisar branches…", + "branchNone": "Sem branches" + }, + "Tasks": { + "title": "Tarefas a fazer", + "new": "Nova tarefa", + "empty": "Ainda não há tarefas", + "emptyHint": "Adicione uma pendência e execute — o agente trabalha num worktree isolado e você revisa e faz merge do resultado.", + "emptyColTodo": "Ainda não há tarefas a fazer", + "emptyColInProgress": "Nada em andamento", + "emptyColAttention": "Nada aguardando você", + "emptyColDone": "Ainda não há concluídas", + "allFolders": "Todas as pastas", + "showCanceled": "Mostrar canceladas", + "showArchived": "Mostrar arquivadas", + "filter": "Filtrar", + "viewSwitchToBoard": "Mudar para a visualização de quadro", + "viewSwitchToList": "Mudar para a visualização de lista", + "statusFilter": "Estado", + "statusFilterAll": "Todos os estados", + "listEmpty": "Nenhuma tarefa corresponde aos filtros atuais", + "listColStatus": "Estado", + "listColTask": "Tarefa", + "listColLocation": "Localização", + "listColChanges": "Alterações", + "listColUpdated": "Atualizado", + "colTodo": "A fazer", + "colInProgress": "Em andamento", + "colAttention": "Aguardando você", + "colDone": "Concluídas", + "statusTodo": "A fazer", + "statusQueued": "Na fila", + "statusPreparing": "Preparando", + "statusRunning": "Em execução", + "statusAwaitingInput": "Aguardando entrada", + "statusReview": "Para revisar", + "statusMerging": "Fazendo merge", + "statusDone": "Concluída", + "statusFailed": "Falhou", + "statusCanceled": "Cancelada", + "statusInterrupted": "Interrompida", + "badgeCleanupFailed": "Limpeza falhou", + "badgeWorktreeKept": "Worktree mantido", + "badgeWorktreeRemoved": "Worktree removido", + "filesChanged": "{count} arquivos", + "actionStart": "Iniciar", + "actionSchedule": "Agendar", + "actionCancel": "Cancelar", + "actionRetry": "Tentar novamente", + "actionRequeue": "Reenfileirar", + "actionViewSession": "Ver conversa", + "actionEdit": "Editar", + "actionDelete": "Excluir", + "actionRetryCleanup": "Repetir limpeza", + "actionMerge": "Merge", + "actionUnqueueMerge": "Sair da fila de merge", + "actionEditQueuedMerge": "Editar merge na fila", + "badgeMergeQueued": "Na fila para merge", + "badgeMergeQueuedRank": "Na fila para merge · n.º {rank}", + "badgeMergeQueuedHint": "Aguardando o merge em andamento do projeto terminar; este começa sozinho.", + "actionComplete": "Concluir", + "actionAbandon": "Abandonar", + "cancelTitle": "Cancelar tarefa?", + "cancelDescription": "A tarefa passa para Cancelada. O worktree é mantido e você pode reenfileirá-la depois.", + "cancelReasonLabel": "Motivo (opcional)", + "cancelReasonPlaceholder": "Ex.: abordagem errada — vou reescrever a descrição", + "cancelKeep": "Deixa pra lá", + "cancelSubmit": "Cancelar tarefa", + "restartTitleRetry": "Tentar a tarefa novamente", + "restartTitleRequeue": "Reenfileirar a tarefa", + "restartDescription": "Você pode adicionar uma nota (opcional): ela chega ao prompt da próxima execução.", + "scheduleTitle": "Agendar tarefa", + "scheduleDescription": "A tarefa continua em A fazer e inicia sozinha no horário escolhido. O limite de concorrência da pasta continua valendo.", + "scheduleDateLabel": "Data", + "schedulePickDate": "Escolher data", + "scheduleTimeLabel": "Hora", + "schedulePreview": "Executa em {time}", + "schedulePastHint": "Esse horário já passou: a tarefa começa assim que você salvar.", + "scheduleInAnHour": "Em 1 hora", + "scheduleInThreeHours": "Em 3 horas", + "scheduleTomorrow": "Amanhã 9:00", + "scheduleClear": "Remover agendamento", + "scheduleBadge": "Início agendado para {time}", + "toastScheduled": "Agendada para {time}", + "toastScheduleCleared": "Agendamento removido", + "actionFollowUp": "Continuar", + "actionAddNote": "Adicionar observação", + "followUpSubmit": "Enviar", + "followUpIntentRevise": "Corrigir", + "followUpIntentContinue": "Prosseguir", + "followUpIntentQuestion": "Perguntar", + "followUpIntentVerify": "Revisar", + "followUpPlaceholderRevise": "O que o agente deve mudar? Ele continua na mesma sessão.", + "followUpPlaceholderContinue": "E agora? O que já foi feito permanece.", + "followUpPlaceholderQuestion": "O que você quer saber? O agente responde sem mexer em nenhum arquivo.", + "followUpPlaceholderVerify": "Opcional: algo que deva revisar com atenção?", + "followUpPlaceholderRetry": "Opcional: o que deve ser feito diferente? Ex.: rodar pnpm install antes", + "followUpPlaceholderRequeue": "Opcional: por que você cancelou e o que deve mudar desta vez?", + "actionArchive": "Arquivar", + "actionUnarchive": "Desarquivar", + "archiveAllDone": "Arquivar tudo", + "dropToStart": "Solte para iniciar", + "errorView": "Ver", + "notifyReview": "Pronto para revisão: {title}", + "notifyFailed": "A tarefa falhou: {title}", + "createFromMessage": "Criar tarefa a partir da mensagem", + "detailTokens": "Total de tokens", + "editorTitleNew": "Nova tarefa", + "editorTitleEdit": "Editar tarefa", + "templates": "Modelos", + "templatesEmpty": "Ainda não há modelos.", + "templateSaveCurrent": "Salvar como modelo", + "templateDelete": "Excluir modelo", + "transcriptTitle": "Conversa da tarefa", + "transcriptDescription": "Visão ao vivo somente leitura da sessão do agente da tarefa.", + "phaseWork": "Execução", + "phaseRetry": "Nova tentativa", + "phaseReturn": "Continuação", + "phaseMerge": "Merge", + "titleLabel": "Título", + "titlePlaceholder": "O que precisa ser feito?", + "promptLabel": "Descrição da tarefa", + "promptPlaceholder": "Descreva a tarefa para o agente — @ para referenciar arquivos, / para comandos", + "folderPlaceholder": "Selecione uma pasta", + "agentInheritedHint": "Herdado das configurações de tarefas; altere para personalizar esta tarefa", + "agentOverrideReset": "Voltar a herdar", + "sectionTarget": "Destino", + "errorTitle": "O título é obrigatório", + "errorPrompt": "A descrição é obrigatória", + "errorFolder": "Selecione uma pasta", + "save": "Salvar", + "cancel": "Cancelar", + "mergeTitle": "Merge da tarefa", + "mergeQueuedTitle": "Merge na fila", + "mergeQueueHint": "Outra tarefa deste projeto está sendo mesclada agora. Esta entra na fila e começa sozinha assim que a outra terminar.", + "mergeQueueUpdateHint": "Esta tarefa já está esperando para mesclar. Enviar atualiza o merge e mantém o lugar na fila.", + "mergeDescription": "Fazer merge de {branch} em {base}. Alterações não commitadas no worktree são commitadas antes.", + "mergeMessage": "Mensagem do commit", + "mergeMessagePlaceholder": "ex.: feat: add login validation", + "mergeAutoMessage": "Deixar o agente escrever a mensagem de commit", + "strategySquash": "Combinar em um único commit", + "strategySquashHint": "Todas as mudanças da tarefa entram na branch principal como um único registro — histórico mais limpo.", + "strategyMerge": "Manter o histórico completo", + "strategyMergeHint": "Cada commit feito durante a tarefa é mantido, mais um registro de merge — cada etapa fica rastreável.", + "mergeDeleteWorktree": "Excluir o worktree após o merge", + "mergeSubmit": "Merge", + "mergeSubmitQueue": "Adicionar à fila", + "mergeQueuedToast": "Adicionada à fila de merge — começa assim que o merge atual terminar.", + "completeTitle": "Concluir tarefa", + "completeDescription": "Esta tarefa não alterou nenhum arquivo, então não há nada para fazer merge: ela é marcada como concluída.", + "completeDescriptionNoWorktree": "O worktree desta tarefa foi removido, então não é mais possível fazer merge: ela é marcada como concluída. Um branch de trabalho que ainda tenha commits não mesclados é mantido.", + "completeDeleteWorktree": "Excluir o worktree ao concluir", + "completeSubmit": "Concluir", + "settingsTitle": "Configurações de tarefas", + "settingsDescription": "Padrões para tarefas em {folder}.", + "settingsScope": "Escopo", + "settingsScopeGlobal": "Todas as pastas (padrões globais)", + "settingsScopeGlobalHint": "Pastas sem configurações próprias usam estes padrões globais.", + "settingsSource": "Origem da configuração", + "settingsSourceGlobal": "Padrões globais", + "settingsSourceCustom": "Personalizada", + "settingsSourceGlobalFollow": "Segue as configurações globais de tarefas — mudanças lá se aplicam aqui automaticamente.", + "settingsSourceCustomHint": "Salva configurações próprias desta pasta, que deixa de seguir os padrões globais.", + "settingsAgent": "Agente padrão", + "settingsMaxConcurrent": "Máx. de tarefas simultâneas", + "settingsMaxConcurrentHint": "0 = ilimitado", + "settingsAutoProcess": "Processar automaticamente", + "settingsAutoProcessHint": "As tarefas pendentes iniciam sozinhas, até o limite de concorrência.", + "settingsMergeStrategy": "Estratégia de merge padrão", + "settingsMergeStrategyHint": "Como as mudanças da tarefa são registradas no histórico da branch ao mesclar.", + "settingsAutoMerge": "Merge automático", + "settingsAutoMergeHint": "Uma tarefa que chega à revisão com mudanças a integrar recebe merge como se você clicasse em Merge: o agente escreve a mensagem de commit e o worktree segue o padrão abaixo. Se a pré-verificação falhar ou um merge tiver falhado, a tarefa fica esperando por você.", + "settingsDeleteWorktree": "Excluir o worktree após o merge", + "settingsDeleteWorktreeHint": "Marca a opção por padrão no diálogo de merge; ainda dá para alterar lá.", + "settingsWorktreeRoot": "Local do worktree", + "settingsWorktreeRootHint": "Diretório onde os worktrees das novas tarefas são criados, um por tarefa. Deixe vazio para criá-los ao lado da pasta do projeto; \"~\" é a sua pasta pessoal e um caminho relativo é resolvido a partir da pasta do projeto.", + "settingsWorktreeRootPlaceholder": "~/codeg-worktrees", + "settingsWorktreeRootBrowse": "Escolher o diretório dos worktrees", + "settingsPreflight": "Comando de pré-verificação", + "settingsPreflightHint": "Executa no worktree quando uma tarefa chega à revisão.", + "settingsPreflightCustomPlaceholder": "pnpm test", + "settingsInitCommand": "Comando de inicialização do worktree", + "settingsInitCommandHint": "Executado em um worktree recém-criado antes de o agente iniciar.", + "settingsInitCommandPlaceholder": "pnpm install", + "settingsTabGeneral": "Geral", + "settingsTabMerge": "Merge", + "settingsTabWorktree": "Worktree", + "settingsTabPrompts": "Prompts", + "settingsPromptsIntro": "Cada etapa já envia seu próprio prompt embutido: a tarefa, as regras do worktree e, no merge, os passos exatos do git. O que você escrever aqui é anexado ao final como instruções extras: refina esses textos embutidos, mas nunca os substitui.", + "settingsPromptStageAll": "Todas as fases", + "settingsPromptPlaceholderAll": "ex.: Siga as convenções do AGENTS.md; mantenha o resumo final em duas frases", + "settingsPromptPlaceholderWork": "ex.: Leia primeiro os testes relacionados; faça commits pequenos ao longo do trabalho", + "settingsPromptPlaceholderRetry": "ex.: Verifique o que já está commitado antes de continuar; não refaça o que está pronto", + "settingsPromptPlaceholderReturn": "Ex.: Trate cada ponto levantado; não refatore nada não relacionado", + "settingsPromptPlaceholderMerge": "ex.: Escreva a mensagem do commit de integração em português; aponte os conflitos resolvidos à mão", + "settingsPromptHintAll": "Acrescentado a todos os prompts que o agente recebe, inclusive no merge.", + "settingsPromptHintWork": "Acrescentado quando uma tarefa é executada pela primeira vez.", + "settingsPromptHintRetry": "Acrescentado ao retomar uma tarefa interrompida ou com falha.", + "settingsPromptHintReturn": "Anexado quando você continua uma tarefa em revisão (corrigir, ampliar, revisar).", + "settingsPromptHintMerge": "Acrescentado quando o agente integra a tarefa no branch base.", + "preflightPassed": "{name} aprovado", + "preflightFailed": "{name} falhou", + "preflightRunning": "{name} em execução…", + "detailDescription": "Detalhes da tarefa", + "detailSummary": "Resultado", + "detailFiles": "Arquivos alterados", + "detailDiffAll": "Ver diff completo", + "detailDiffAllTitle": "Diff completo", + "detailNoChanges": "Ainda não há mudanças em relação à base", + "detailTimeline": "Progresso", + "detailTimelineEmpty": "Nenhuma atividade ainda", + "showMore": "Ver mais", + "showLess": "Ver menos", + "detailInfo": "Detalhes", + "detailBranch": "Branch", + "detailMergeCommit": "Commit de merge", + "detailChanges": "Alterações", + "detailScheduled": "Início agendado", + "detailCreated": "Criada", + "detailStarted": "Iniciada", + "detailFinished": "Concluída", + "diffLoading": "Carregando diff…", + "deleteConfirmTitle": "Excluir tarefa?", + "deleteConfirmBody": "“{title}” será removida do quadro. Uma execução ativa é cancelada antes.", + "deleteWithWorktree": "Excluir também o worktree", + "eventCreated": "Criada", + "eventStatusChanged": "Mudança de status", + "eventConfigEffective": "Configuração de execução", + "eventInitCommand": "Comando de inicialização", + "eventAgentProgress": "Progresso do agente", + "eventAgentVerdict": "Veredito do agente", + "eventMergeAttempt": "Merge iniciado", + "eventMergeQueued": "Na fila para merge", + "eventMergeConflict": "Conflito de merge", + "eventPreflight": "Pré-verificação", + "eventCleanupFailed": "Falha na limpeza do worktree", + "eventResumeFallback": "Retomada falhou; nova sessão usada", + "eventUserAction": "Ação do usuário", + "eventDiffStat": "Resumo das mudanças" + }, + "CustomSkillsSettings": { + "loading": "Carregando habilidades personalizadas…", + "category": "Personalizadas", + "searchPlaceholder": "Pesquisar habilidades personalizadas por nome, ID ou descrição", + "states": { + "not_linked": "Não ativada", + "linked_to_codeg": "Ativada", + "linked_elsewhere": "Vinculada em outro lugar", + "blocked_by_real_directory": "Bloqueada por uma pasta real", + "broken": "Link quebrado" + }, + "actions": { + "new": "Nova", + "import": "Importar", + "importFromAgent": "Importar de um agente", + "cancel": "Cancelar", + "save": "Salvar" + }, + "rowMenu": { + "edit": "Editar", + "duplicate": "Duplicar", + "delete": "Excluir" + }, + "bulk": { + "delete": "Excluir selecionadas" + }, + "editor": { + "createTitle": "Nova habilidade personalizada", + "editTitle": "Editar habilidade personalizada", + "description": "As habilidades personalizadas ficam no armazenamento compartilhado (~/.codeg/skills) e podem ser ativadas para qualquer agente.", + "idLabel": "ID da habilidade", + "idPlaceholder": "ex.: my-workflow", + "contentLabel": "SKILL.md", + "contentPlaceholder": "Escreva aqui o SKILL.md da habilidade…", + "preview": "Pré-visualização", + "edit": "Editar", + "emptyBody": "Ainda sem conteúdo." + }, + "duplicate": { + "title": "Duplicar habilidade", + "description": "Criar uma cópia de \"{id}\" com um novo ID.", + "newIdPlaceholder": "Novo ID da habilidade", + "confirm": "Duplicar" + }, + "import": { + "title": "Escolha uma pasta de habilidade para importar" + }, + "importFromAgent": { + "title": "Importar habilidades de um agente", + "description": "Copie as habilidades próprias de um agente para o repositório compartilhado e ative-as em qualquer agente.", + "agentLabel": "Agente", + "agentPlaceholder": "Selecione um agente", + "selectAll": "Selecionar tudo ({count})", + "loading": "Carregando as habilidades do agente…", + "unsupported": "Este agente não expõe um diretório de habilidades.", + "empty": "Este agente não tem habilidades para importar.", + "alreadyInLibrary": "Na biblioteca", + "confirm": "Importar selecionadas ({count})" + }, + "delete": { + "title": "Excluir habilidades personalizadas?", + "body": "Isto remove {count} habilidade(s) personalizada(s) do armazenamento central e as desvincula de todos os agentes. Não pode ser desfeito.", + "confirm": "Excluir" + }, + "toasts": { + "loadFailed": "Falha ao carregar a habilidade", + "idRequired": "Informe um ID de habilidade", + "created": "Habilidade personalizada criada", + "updated": "Habilidade personalizada atualizada", + "saveFailed": "Falha ao salvar a habilidade", + "imported": "Habilidade importada", + "importFailed": "Falha ao importar a habilidade", + "duplicated": "Habilidade duplicada", + "duplicateFailed": "Falha ao duplicar a habilidade", + "deleted": "{count} habilidade(s) excluída(s)", + "deletedPartial": "{ok} excluída(s), {failed} com falha", + "deleteFailed": "Falha ao excluir as habilidades", + "importedFromAgent": "{count} habilidade(s) importada(s)", + "importedFromAgentPartial": "{ok} importada(s), {failed} com falha", + "importFromAgentAllSkipped": "Nada a importar — {count} já na biblioteca", + "importFromAgentFailed": "Falha ao importar do agente" + } + }, + "CodexModelEditor": { + "customizedNotice": "Você personalizou a lista de modelos, então agora o codeg gerencia toda a tabela de modelos do codex. Os modelos oficiais que o codex adicionar depois não aparecerão automaticamente — clique no botão atualizar abaixo e salve novamente para sincronizá-los. Limpe suas personalizações para que o codex volte a atualizar automaticamente.", + "officialsTitle": "Modelos oficiais", + "officialsHint": "Incluídos automaticamente do codex que você inicia; remova os que não quiser.", + "officialsEmpty": "Nenhum modelo oficial disponível.", + "refresh": "Atualizar do codex", + "readdOfficial": "Readicionar oficial", + "customsTitle": "Modelos personalizados", + "customsEmpty": "Ainda não há modelos personalizados.", + "addCustom": "Adicionar personalizado", + "slugPlaceholder": "id do modelo (slug)", + "displayNamePlaceholder": "Nome de exibição", + "contextWindow": "Contexto", + "makeDefault": "Definir como padrão", + "defaultHint": "Modelo padrão", + "remove": "Remover", + "advanced": "Avançado", + "baseTemplate": "Modelo base", + "baseTemplateHint": "Modelo oficial do qual clonar os campos obrigatórios (prompt do sistema, ferramentas, limites).", + "groupBehavior": "Comportamento e recursos", + "fieldReasoningLevel": "Raciocínio padrão", + "fieldReasoningSummary": "Resumo do raciocínio", + "fieldVerbosity": "Verbosidade", + "fieldShellType": "Tipo de shell", + "fieldApplyPatch": "Ferramenta apply-patch", + "fieldReasoningSummaries": "Resumos de raciocínio", + "fieldSupportVerbosity": "Controle de verbosidade", + "fieldParallelToolCalls": "Chamadas de ferramentas em paralelo", + "fieldSearchTool": "Ferramenta de busca na web", + "optNone": "Nenhum", + "groupInstructions": "Descrição e prompt do sistema", + "fieldDescription": "Descrição", + "baseInstructions": "Prompt do sistema (base_instructions)" + }, + "DiagnosticsSettings": { + "title": "Diagnóstico do ambiente", + "description": "Verifica como este app resolve a CLI do agente no próprio processo, que pode diferir do seu terminal.", + "loading": "Executando diagnóstico…", + "error": "Falha no diagnóstico", + "rerun": "Executar novamente", + "copyAll": "Copiar tudo", + "copied": "Diagnóstico copiado para a área de transferência", + "button": "Diagnosticar", + "verdict": { + "ok": "O ambiente parece saudável. Se ainda aparecer como não instalado, reinicie o app completamente para atualizar o cache do prefixo.", + "node_missing": "Node.js não foi encontrado no PATH do app.", + "npm_missing": "npm não foi encontrado no PATH do app.", + "not_installed": "Este agente não parece estar instalado.", + "installed_but_unresolved": "Consta como instalado, mas o app não consegue localizar o executável.", + "user_prefix_not_on_path": "Instalado no prefixo de fallback (~/.codeg/npm-global), que não está no PATH do app. Reinicie o app completamente e tente novamente.", + "homebrew_bin_not_on_path": "Instalado no bin do Homebrew, que não está no PATH do app (divisão de keg no Apple Silicon).", + "terminal_only_path": "O comando é resolvido no seu terminal, mas não no app: uma diferença de PATH da GUI. Inicie o app por um terminal ou reinstale nas Configurações de agentes.", + "npm_prefix_timeout": "npm prefix -g foi muito lento (mais de 1,5 s), então a detecção de fallback foi ignorada. Reinicie o app e tente novamente.", + "node_too_old": "Seu Node.js ativo é mais antigo do que este agente requer. Atualize o Node.js.", + "adapter_missing_native_present": "A sua CLI do {agent} está instalada, mas o Codeg inicia um pacote adaptador ACP separado — e esse ainda não está. Instale-o nas configurações de agentes: ele não mexe na sua CLI e compartilha o mesmo login.", + "adapter_missing": "O Codeg inicia um pacote adaptador ACP separado para o {agent}, e ele ainda não está instalado. Instale-o nas configurações de agentes — instalar só a CLI do fornecedor não basta." + } + }, + "TokenUsage": { + "title": "Uso de tokens", + "rangeLabel": "Período", + "range7d": "7 dias", + "range30d": "30 dias", + "range90d": "90 dias", + "rangeThisMonth": "Este mês", + "rangeThisYear": "Este ano", + "rangeAll": "Tudo", + "rangeCustom": "Personalizado", + "moreRanges": "Mais", + "customRangePick": "Escolher um período", + "bucketLabel": "Agrupar por", + "bucketDay": "Dia", + "bucketWeek": "Semana", + "bucketMonth": "Mês", + "bucketUnitDay": "Dia", + "bucketUnitWeek": "Semana", + "bucketUnitMonth": "Mês", + "folderFilter": "Pastas", + "allFolders": "Todas as pastas", + "agentFilter": "Agentes", + "allAgents": "Todos os agentes", + "modelFilter": "Modelos", + "allModels": "Todos os modelos", + "searchPlaceholder": "Pesquisar…", + "noMatches": "Nenhum resultado", + "clearFilter": "Limpar seleção", + "resetFilters": "Limpar filtros", + "refresh": "Atualizar", + "rebuild": "Reconstruir tudo", + "rebuildHint": "Descarta o que já foi contabilizado e relê todas as transcrições. Útil se uma sessão cresceu fora do codeg.", + "syncing": "Contando sessões…", + "syncProgress": "{done} / {total}", + "syncDone": "{synced} sessões contabilizadas", + "syncFailed": "Não foi possível ler algumas sessões", + "syncBusy": "Já existe uma atualização em andamento", + "lastSynced": "Atualizado {time}", + "lastSyncedNever": "Nunca atualizado", + "tileTotal": "Tokens totais", + "tileSessions": "Sessões", + "tileTurns": "Turnos", + "tileActiveDays": "Dias ativos", + "tileGenTime": "Tempo de geração", + "vsPrevious": "vs. período anterior", + "deltaNew": "novo", + "trendTitle": "Uso ao longo do tempo", + "trendEmpty": "Sem uso neste período", + "trendTurns": "Turnos", + "trendSessions": "Sessões", + "compositionTitle": "Para onde foram os tokens", + "compositionHint": "Entrada é o que você enviou, saída é o que o modelo escreveu e leituras de cache são contexto que não custou preço cheio.", + "compositionNote": "Reenviar esses acertos de cache a preço cheio custaria mais {value}.", + "inputTokens": "Entrada", + "outputTokens": "Saída", + "cacheWrite": "Escrita de cache", + "cacheRead": "Leitura de cache", + "freshTokens": "Cômputo novo", + "cacheHitCaption": "Acerto de cache", + "cacheHeroTitleHigh": "A maior parte do contexto não precisou ser reenviada", + "cacheHeroTitleLow": "A maior parte do contexto ainda é calculada a preço cheio", + "cacheHeroDesc": "O cache carregou {cached} de contexto; só {fresh} foi de fato calculado de novo no período.", + "cacheSavedSuffix": "Isso poupou reenviar o equivalente a {saved}.", + "avgPerSession": "Média por sessão", + "avgTurnsPerSession": "{count} turnos por sessão em média", + "avgPerActiveDay": "Média por dia ativo", + "peakBucket": "{bucket} de pico", + "peakHour": "Hora de pico", + "daysValue": "{count} dias", + "idleDays": "Dias parados", + "byFolderTitle": "Por pasta", + "byAgentTitle": "Por agente", + "byModelTitle": "Por modelo", + "distributionTitle": "Distribuição de uso", + "distributionHint": "Sessões e tokens agrupados pela dimensão escolhida — clique numa linha para filtrar.", + "otherLabel": "Outros", + "unknownModel": "Modelo não registrado", + "emptyBreakdown": "Nada registrado ainda", + "sessionsCount": "{count} sessões", + "heatmapTitle": "Quando você programa", + "heatmapHint": "Tokens por dia da semana e hora local.", + "heatmapPeakHint": "Mais denso por volta das {hour}:00.", + "less": "Menos", + "more": "Mais", + "heatmapCell": "{weekday} {hour}:00 — {value} tokens", + "weekMon": "Seg", + "weekTue": "Ter", + "weekWed": "Qua", + "weekThu": "Qui", + "weekFri": "Sex", + "weekSat": "Sáb", + "weekSun": "Dom", + "topSessionsTitle": "Sessões mais pesadas", + "untitledSession": "Sessão sem título", + "topSessionsEmpty": "Sem sessões neste período", + "streakLongest": "Maior sequência", + "streakLongestDays": "Maior sequência: {count} dias", + "share": "Compartilhar", + "moreActions": "Mais ações", + "shareDialogTitle": "Compartilhe seu cartão de uso", + "shareDialogHint": "Um retrato do período e dos filtros que você está vendo.", + "shareSave": "Salvar imagem", + "shareCopy": "Copiar imagem", + "shareCopied": "Copiado para a área de transferência", + "shareSaved": "Imagem salva", + "shareFailed": "Não foi possível criar a imagem", + "shareRendering": "Gerando…", + "cardHeading": "Minhas estatísticas de código com IA", + "cardRangeAll": "Todo o período", + "cardTotalLabel": "Tokens usados", + "cardFooter": "Feito com codeg", + "cardTopModels": "Principais modelos", + "cardTopProjects": "Principais projetos", + "archetypeNightOwl": "Coruja noturna", + "archetypeNightOwlDesc": "{percent}% dos seus tokens queimam depois do anoitecer.", + "archetypeEarlyBird": "Madrugador", + "archetypeEarlyBirdDesc": "{percent}% dos seus tokens acontecem antes das 9h.", + "archetypeWeekendWarrior": "Guerreiro de fim de semana", + "archetypeWeekendWarriorDesc": "{percent}% dos seus tokens acontecem no fim de semana.", + "archetypeCacheMaster": "Mestre do cache", + "archetypeCacheMasterDesc": "{percent}% do seu contexto veio do cache.", + "archetypeMarathoner": "Maratonista", + "archetypeMarathonerDesc": "{days} dias programando sem parar.", + "archetypePolyglot": "Polivalente", + "archetypePolyglotDesc": "{count} agentes em uso pesado.", + "archetypeLaserFocus": "Foco total", + "archetypeLaserFocusDesc": "{percent}% dos seus tokens foram para um único projeto.", + "archetypeDeepDiver": "Mergulhador", + "archetypeDeepDiverDesc": "{averageK}K tokens numa sessão média.", + "archetypeSteady": "Construtor constante", + "archetypeSteadyDesc": "{days} dias entregando.", + "emptyTitle": "Nada contabilizado ainda", + "emptyHint": "O codeg lê os tokens direto da transcrição de cada agente. Atualize para contabilizar o que já existe nesta máquina.", + "emptyAction": "Contabilizar minhas sessões", + "loadFailed": "Não foi possível carregar o uso", + "truncatedNotice": "Este período é muito amplo — os números cobrem apenas o trecho mais recente." + } +} diff --git a/src/i18n/messages/zh-CN.json b/src/i18n/messages/zh-CN.json index f6a2638c1..6c9651365 100644 --- a/src/i18n/messages/zh-CN.json +++ b/src/i18n/messages/zh-CN.json @@ -1,4956 +1,4958 @@ -{ - "Language": { - "followSystem": "跟随系统", - "english": "英语", - "simplifiedChinese": "简体中文", - "traditionalChinese": "繁體中文", - "japanese": "日语", - "korean": "韩语", - "spanish": "西班牙语", - "german": "德语", - "french": "法语", - "portuguese": "葡萄牙语", - "arabic": "阿拉伯语" - }, - "GitCredentialDialog": { - "title": "需要身份验证", - "description": "远程服务器要求输入凭据。请输入用户名和密码(或个人访问令牌)。", - "username": "用户名", - "usernamePlaceholder": "用户名或邮箱", - "password": "密码 / 令牌", - "passwordPlaceholder": "密码或个人访问令牌", - "passwordHint": "请输入服务器的用户名和密码。", - "cancel": "取消", - "authenticate": "认证", - "authenticating": "认证中...", - "invalidCredentials": "凭据无效,请重试。", - "saveCredentials": "保存凭据以供后续操作使用", - "githubTitle": "GitHub 身份验证", - "githubDescription": "输入个人访问令牌以连接 GitHub。令牌验证成功后将自动保存到账号列表。", - "githubToken": "个人访问令牌", - "githubTokenPlaceholder": "ghp_xxxxxxxxxxxx", - "githubTokenHint": "在 GitHub → Settings → Developer settings → Personal access tokens 中生成令牌。", - "githubAuthenticate": "验证并连接", - "generateToken": "生成令牌" - }, - "SettingsShell": { - "title": "设置", - "preferences": "偏好设置", - "nav": { - "general": "常规", - "appearance": "外观", - "agents": "智能体", - "mcp": "MCP", - "skills": "Skills", - "shortcuts": "快捷键", - "version_control": "版本控制", - "system": "系统", - "chat_channels": "消息渠道", - "web_service": "Web 服务", - "model_providers": "模型供应商", - "experts": "专家", - "science": "科学研究", - "office_tools": "办公工具", - "skill_packs": "技能包", - "quick_messages": "快捷消息", - "logs": "运行日志" - } - }, - "AppearanceSettings": { - "sectionTitle": "主题外观", - "sectionDescription": "选择浅色、深色或跟随系统主题,设置会自动保存。", - "themeMode": "主题模式", - "placeholder": "请选择主题模式", - "system": "跟随系统", - "light": "浅色", - "dark": "深色", - "currentTheme": "当前生效主题:{theme}", - "resolvedTheme": { - "light": "浅色", - "dark": "深色", - "unknown": "未知" - }, - "themeColor": { - "sectionTitle": "主题颜色", - "sectionDescription": "选择按钮、强调色和高亮使用的色调。", - "current": "当前颜色:{color}", - "options": { - "neutral": "Neutral", - "zinc": "Zinc", - "slate": "Slate", - "stone": "Stone", - "gray": "Gray", - "red": "Red", - "rose": "Rose", - "orange": "Orange", - "green": "Green", - "blue": "Blue", - "yellow": "Yellow", - "violet": "Violet" - } - }, - "customStyle": { - "sectionTitle": "自定义样式", - "sectionDescription": "在当前主题的基础上微调配色,或写入自己的 CSS。覆盖叠加在基底预设之上,切换预设后依然保留。", - "summarySuspended": "已停用", - "summaryDefault": "跟随预设", - "summaryTokens": "{count, plural, other {# 项覆盖}}", - "summaryCss": "自定义 CSS", - "suspendedByShortcut": "自定义样式已停用。在恢复之前,这里的设置都不会生效。", - "suspendedBySafeParam": "本窗口以安全外观模式打开,自定义样式在此不生效,其它窗口不受影响。", - "resume": "恢复自定义样式", - "enableTheme": "启用自定义配色", - "editingLight": "正在编辑浅色模式的取值。切换到深色模式可单独设置深色。", - "editingDark": "正在编辑深色模式的取值。切换到浅色模式可单独设置浅色。", - "resetToken": "恢复为预设取值", - "radius": "圆角", - "radiusHint": "从 sm 到 4xl 的整套圆角尺寸都由它派生,一个滑块即可改变全局圆角。", - "advanced": "高级(另有 {count} 个变量)", - "enableCss": "启用自定义 CSS", - "cssRisk": "高级功能。自定义 CSS 会压过所有内置样式,写坏可能导致界面不可用。", - "editCss": "编辑 CSS…", - "cssPresent": "已保存 {size} KB", - "cssEmpty": "尚未保存内容", - "escapeHint": "界面被改坏了?按 {shortcut} 可停用全部自定义样式,也可以用 safeStyle=1 查询参数打开窗口。", - "copyTheme": "复制主题 JSON", - "importTheme": "导入主题…", - "clearTheme": "清除覆盖", - "interopHint": "主题采用 shadcn 的 registry:theme 格式,可以直接粘贴任意 shadcn 主题,导出的主题也能用在任何 shadcn 项目里。", - "importTitle": "导入主题", - "importDescription": "粘贴 shadcn 的 registry:theme 条目、裸的 light/dark 对象,或者单层的 token 映射。", - "readClipboard": "读取剪贴板", - "importConfirm": "导入", - "cancel": "取消", - "apply": "应用", - "toasts": { - "copied": "主题 JSON 已复制", - "copyFailed": "无法写入剪贴板", - "clipboardReadFailed": "无法读取剪贴板,请手动粘贴", - "importFailed": "这段 JSON 里没有可用的主题变量", - "imported": "主题已导入" - }, - "css": { - "dialogTitle": "自定义 CSS", - "dialogDescription": "对所有 codeg 窗口生效。修改会实时预览,点击「应用」才会保存。", - "size": "{used} KB / {max} KB", - "ruleCount": "{count} 条规则", - "errorTooLarge": "内容过大,无法保存,请精简到上限以内。", - "errorImportEscaped": "剥离后仍检测到 @import(转义写法),请手动移除后再保存。", - "warnNoRules": "没有解析出任何规则,请检查语法。", - "noticeImportsRemoved": "已移除 {count} 条 @import:它们会拉取远程样式表。", - "noticeRemoteUrl": "含远程 url(),应用后会发起网络请求。", - "noticePreviewSuspended": "自定义样式已停用,此处预览不会生效。", - "noticeDisabled": "自定义 CSS 未启用。这里可以预览,但启用后才会真正生效。", - "hintTokens": "提示:你覆盖的颜色可以直接用 var(--primary)、var(--background) 等引用。" - } - }, - "zoomLevel": { - "sectionTitle": "窗口缩放", - "sectionDescription": "整体放大或缩小界面,立即生效,按设备分别保存。", - "placeholder": "请选择缩放档位", - "default": "默认", - "current": "当前缩放:{zoom}%" - }, - "fonts": { - "sectionTitle": "字体", - "sectionDescription": "为界面、代码编辑器和终端分别选择字体。内置字体按需加载;选择“自定义…”可使用系统已安装的任意字体。", - "interface": "界面", - "editor": "编辑器", - "terminal": "终端", - "groupSans": "无衬线", - "groupMono": "等宽", - "custom": "自定义…", - "customPlaceholder": "字体名称,如 Fira Code", - "fontSize": "字号", - "ligatures": "启用连字", - "ligaturesUnavailable": "该字体不含连字", - "wordWrap": "启用自动换行", - "terminalLigaturesHint": "终端连字仅对内置编程字体生效。", - "preview": "预览" - }, - "welcomePanel": { - "sectionTitle": "模式选择区域", - "sectionDescription": "新会话页面输入框上方显示的「代码开发 / 日常办公」快捷卡片区域。", - "showQuickActions": "在新会话页面显示" - }, - "workspaceBackground": { - "sectionTitle": "工作区背景", - "sectionDescription": "在整个工作区背后显示一张图片。侧栏与面板会变半透明并磨砂让图片透出,遮罩保证文字可读。", - "enable": "启用背景图片", - "image": "图片", - "chooseImage": "选择图片", - "replaceImage": "更换图片", - "removeImage": "移除", - "fillMode": "填充方式", - "fillModes": { - "cover": "覆盖", - "contain": "适应", - "center": "居中", - "tile": "平铺" - }, - "maskOpacity": "遮罩不透明度", - "maskOpacityHint": "数值越高,图片越向主题背景色淡化,文字对比越清晰。", - "imageBlur": "图片模糊", - "panelOpacity": "面板不透明度", - "panelOpacityHint": "侧栏、面板与标签栏的不透明程度。越低,透出的图片越多。", - "errorTooLarge": "图片太大(最大 16 MB)。", - "errorUploadFailed": "设置背景图片失败。" - } - }, - "SystemSettings": { - "loading": "加载中...", - "sectionTitle": "系统管理", - "sectionDescription": "管理网络代理、应用升级与语言偏好。", - "proxyTitle": "网络代理", - "proxyDescription": "开启后,后续网络请求将优先走该代理(包括 ACP 对话、Agent 安装、Git 远程操作等)。", - "loadFailed": "加载失败:{message}", - "enableProxy": "启用系统代理", - "proxyAddress": "代理地址", - "proxyHint": "支持 http(s)/socks5,示例:{example}。仅在启用系统代理时生效。", - "save": "保存", - "saving": "保存中...", - "proxyRequired": "启用代理时必须填写代理地址", - "saveSuccess": "系统代理设置已保存", - "saveFailed": "保存失败:{message}", - "languageTitle": "语言", - "languageDescription": "设置应用语言。跟随系统时,若系统语言不受支持将回退为英文。", - "appLanguage": "应用语言", - "languageSaveSuccess": "语言设置已保存", - "languageSaveFailed": "语言设置保存失败:{message}", - "updateTitle": "应用升级", - "versionTitle": "软件更新", - "updateDescription": "点击检查后会从配置的发布源拉取最新版本信息,有新版本时可直接下载并安装。", - "currentVersion": "当前版本", - "upgradableVersion": "最新版本", - "none": "暂无", - "lastChecked": "上次检查:{time}", - "updateError": "更新异常:{message}", - "checking": "检查中...", - "checkUpdate": "检查更新", - "updating": "升级中...", - "downloading": "下载中...", - "upgradeTo": "升级到 v{version}", - "viewRelease": "查看 v{version} 发布", - "foundUpdate": "发现新版本 v{version}", - "alreadyLatest": "当前已经是最新版本", - "checkUpdateFailed": "检查更新失败:{message}", - "installSuccess": "升级包已安装,正在重启应用", - "installFailed": "升级失败:{message}", - "upgradeSuccess": "升级完成,正在重新加载...", - "restartTimeout": "服务未能按时恢复,请检查容器或服务日志。", - "restartingIn": "将在 {seconds} 秒后重启...", - "waitingForServer": "正在等待服务恢复...", - "restartToUpdate": "重启以更新", - "newVersionBadge": "新版本 v{version}", - "updateAvailableTitle": "发现新版本", - "releaseNotesTitle": "更新内容", - "remindLater": "稍后", - "retry": "重试", - "stepDownload": "下载", - "stepInstall": "安装", - "stepRestart": "重启", - "updateReadyHint": "新版本已下载,重启以完成更新。", - "restarting": "正在重启…", - "dockerUpgradeHint": "现在升级的是正在运行的容器。容器一旦被重建即丢失——如需保留,请拉取或构建新版本镜像后重建容器。", - "upgradeRolledBack": "升级失败,服务器已自动回滚到上一版本。", - "serverUnreachable": "无法连接到服务器以开始升级。请确认服务器正在运行后重试。", - "rollbackButton": "回滚", - "rollingBack": "回滚中...", - "rollbackDescription": "恢复到上次升级前安装的版本。", - "rollbackConfirmTitle": "回滚到上一个版本?", - "rollbackConfirmDescription": "服务器将重启并运行上次升级前安装的版本。更新的版本仍可再次安装。", - "rollbackConfirm": "回滚", - "rollbackCancel": "取消", - "rollbackSuccess": "已回滚到上一个版本,正在重新加载……", - "rollbackFailed": "回滚失败,请检查服务器日志。", - "updateErrors": { - "sourceUnavailable": "无法连接更新源,请检查网络或代理设置后重试。", - "network": "网络连接异常,请检查网络或代理设置后重试。", - "downloadFailed": "下载更新包失败,请稍后重试。", - "installFailed": "安装更新失败,请关闭应用后重试。", - "unknown": "更新失败,请稍后重试。" - } - }, - "VersionControlSettings": { - "loading": "加载中...", - "sectionTitle": "版本控制", - "sectionDescription": "配置 Git 可执行文件并管理 GitHub 账号。", - "gitTitle": "Git 配置", - "gitDescription": "配置应用使用的 Git 可执行文件。", - "gitDetected": "已检测到 Git", - "gitNotFound": "未在系统中找到 Git", - "gitVersion": "版本", - "gitPath": "路径", - "customGitPath": "自定义 Git 路径", - "customGitPathPlaceholder": "/usr/bin/git", - "customGitPathHint": "留空则使用自动检测的路径。", - "test": "测试", - "testing": "测试中...", - "testSuccess": "Git 可执行文件有效。", - "testFailed": "Git 测试失败:{message}", - "save": "保存", - "saving": "保存中...", - "saveSuccess": "Git 设置已保存。", - "saveFailed": "保存失败:{message}", - "githubTitle": "GitHub 账号", - "githubDescription": "管理用于身份验证的 GitHub 账号。令牌存储在本地。", - "noAccounts": "暂无 GitHub 账号。", - "addAccount": "添加账号", - "serverUrl": "服务器地址", - "serverUrlPlaceholder": "https://github.com", - "token": "个人访问令牌", - "tokenPlaceholder": "ghp_xxxxxxxxxxxx", - "generateToken": "生成令牌", - "tokenHint": "在 GitHub → Settings → Developer settings → Personal access tokens 中生成令牌。", - "validateAndAdd": "验证并添加", - "validating": "验证中...", - "addSuccess": "账号 {username} 添加成功。", - "addFailed": "添加账号失败:{message}", - "testConnection": "测试", - "connectionSuccess": "连接成功。", - "connectionFailed": "连接失败:{message}", - "setDefault": "设为默认", - "defaultLabel": "默认", - "defaultSet": "默认账号已更新。", - "removeAccount": "删除", - "removeConfirmTitle": "删除账号", - "removeConfirmMessage": "确定要删除账号「{username}」吗?", - "removeConfirm": "删除", - "removeCancel": "取消", - "removeSuccess": "账号已删除。", - "scopes": "权限范围", - "loadFailed": "加载设置失败:{message}", - "gitAccount": { - "sectionTitle": "Git 服务器账号", - "sectionDescription": "管理非 GitHub 的 Git 服务器凭据(GitLab、Bitbucket、自建服务等)。", - "noAccounts": "暂无 Git 服务器账号。", - "addAccount": "添加账号", - "addTitle": "添加 Git 账号", - "addDescription": "输入服务器地址、用户名和密码或访问令牌。", - "serverUrl": "服务器地址", - "serverUrlPlaceholder": "https://gitlab.example.com", - "username": "用户名", - "usernamePlaceholder": "用户名或邮箱", - "password": "密码 / 令牌", - "passwordPlaceholder": "密码或访问令牌", - "passwordHint": "输入服务器的密码或个人访问令牌。", - "add": "添加", - "serverRequired": "请输入服务器地址。", - "usernameRequired": "请输入用户名。", - "passwordRequired": "请输入密码。" - } - }, - "ShortcutSettings": { - "sectionTitle": "快捷键", - "resetDefault": "恢复默认", - "recordInstruction": "点击右侧按钮后按下组合键即可修改。建议使用 Ctrl/Cmd、Alt、Shift 的组合。按 Esc 可取消录制。", - "recording": "按下快捷键...", - "toasts": { - "conflict": "快捷键已被「{title}」占用", - "updated": "快捷键已更新", - "invalid": "快捷键无效,请重试", - "reset": "已恢复默认快捷键" - }, - "actions": { - "toggle_search": { - "title": "打开搜索", - "description": "打开或关闭会话搜索面板" - }, - "toggle_sidebar": { - "title": "切换左侧边栏", - "description": "显示或隐藏会话列表侧边栏" - }, - "toggle_terminal": { - "title": "切换终端", - "description": "显示或隐藏底部终端面板" - }, - "new_terminal_tab": { - "title": "新建终端", - "description": "当最近鼠标活动在终端时新建终端标签" - }, - "close_current_terminal_tab": { - "title": "关闭当前终端", - "description": "当最近鼠标活动在终端时关闭当前终端标签" - }, - "toggle_aux_panel": { - "title": "切换右侧面板", - "description": "显示或隐藏辅助信息面板" - }, - "new_conversation": { - "title": "新建会话", - "description": "在当前文件夹中创建新的对话标签" - }, - "open_folder": { - "title": "打开文件夹", - "description": "打开文件夹选择器并在新窗口中打开" - }, - "open_settings": { - "title": "打开设置", - "description": "打开设置窗口" - }, - "close_current_tab": { - "title": "关闭当前标签", - "description": "关闭当前会话或文件标签" - }, - "close_all_file_tabs": { - "title": "关闭全部文件标签", - "description": "当文件面板处于活动状态时关闭所有打开的文件标签" - }, - "next_tab": { - "title": "下一个标签页", - "description": "切换到下一个会话或文件标签页" - }, - "prev_tab": { - "title": "上一个标签页", - "description": "切换到上一个会话或文件标签页" - }, - "send_message": { - "title": "发送消息", - "description": "在输入框中发送当前消息" - }, - "newline_in_message": { - "title": "消息换行", - "description": "在输入框中插入换行符" - }, - "toggle_custom_style": { - "title": "停用/恢复自定义样式", - "description": "逃生舱:一键关闭全部自定义配色与 CSS,再按一次恢复" - } - } - }, - "SkillsSettings": { - "title": "Skills", - "description": "左侧选择 Skill,右侧默认预览 Markdown,点击编辑后可修改并保存。", - "loadingAgents": "正在加载支持 Skills 的 Agent...", - "emptyNoManageableAgents": "当前没有可管理 Skills 的 Agent。", - "managedTarget": "管理对象", - "selectAgentPlaceholder": "请选择 Agent", - "searchPlaceholder": "搜索名称 / ID / 路径...", - "skillsList": "Skills 列表", - "loadingSkills": "加载 Skills 中...", - "agentNotSupported": "当前 Agent 暂不支持 Skills 管理。", - "emptySkills": "暂无 Skill,可点击“新建 Skill”。", - "newSkillTitle": "新建 Skill", - "skillInfo": "Skill 信息", - "skillIdPlaceholder": "Skill ID(例如:my-skill)", - "skillsDirectoryWithPath": "Skills目录:{path}", - "skillsDirectoryNeedId": "Skills目录:请输入 Skill ID 以生成完整路径", - "markdownContent": "Markdown 内容", - "editingStatus": "编辑中", - "previewStatus": "预览中", - "contentPlaceholder": "输入 Skill 文本内容...", - "metadataTitle": "Skills 元信息", - "onlyYamlMetadata": "该 Skill 仅包含 YAML 元信息。", - "emptyContentHint": "暂无内容。点击“编辑”开始输入。", - "loadingSkill": "正在加载 Skill...", - "emptyNoAgents": "暂无可用 Agent。", - "noSelectionHint": "从左侧选择一个 Skill,或点击“新建 Skill”创建。", - "systemBadge": "系统", - "systemHint": "CLI 内置 Skill · 只读", - "scope": { - "global": "全局", - "folder": "文件夹", - "selectFolderPlaceholder": "选择文件夹", - "noFolders": "未找到任何文件夹", - "pickFolderHint": "选择一个文件夹以查看其 Skills。" - }, - "actions": { - "preview": "预览", - "edit": "编辑", - "openInWindow": "在新窗口打开", - "delete": "删除", - "deleting": "删除中...", - "refresh": "刷新", - "newSkill": "新建 Skill", - "reset": "重置", - "save": "保存", - "saving": "保存中...", - "cancel": "取消" - }, - "deleteDialog": { - "title": "删除 Skill", - "confirm": "确认删除当前 Skill 吗?该操作无法撤销。", - "confirmWithNamePrefix": "确认删除 Skill", - "confirmWithNameSuffix": "吗?该操作无法撤销。" - }, - "toasts": { - "loadFailed": "加载 Skill 失败", - "openFolderFailed": "打开目录失败", - "noSkillDirectory": "当前 Agent 未找到可用的 Skills 目录", - "nameRequired": "Skill 名称不能为空", - "updated": "Skill 已更新", - "created": "Skill 已创建", - "saveFailed": "保存 Skill 失败", - "deleted": "Skill 已删除", - "deleteFailed": "删除 Skill 失败" - }, - "templates": { - "gemini": "---\nname: example-skill\ndescription: Describe when this skill should be used.\n---\n\n# Skill Name\n\nInstructions for the agent when this skill is active.\n\n## Workflow\n\n1. Add actionable step one.\n2. Add actionable step two.\n", - "openCode": "---\nname: example-skill\ndescription: Describe when this skill should be used.\n---\n\n# Purpose\n\nDescribe what this skill helps with.\n\n# Steps\n\n1. Add actionable step one.\n2. Add actionable step two.\n", - "openClaw": "---\nname: example-skill\ndescription: Describe when this skill should be used.\nuser-invocable: true\ndisable-model-invocation: false\n---\n\n# Purpose\n\nDescribe what this skill helps with.\n\n# Instructions\n\n1. Add actionable instruction one.\n2. Add actionable instruction two.\n", - "default": "---\nname: example-skill\ndescription: Describe when this skill should be used.\n---\n\n# Skill: example-skill\n\n## When to use\n\n- Describe trigger conditions.\n\n## Instructions\n\n1. Add actionable instruction one.\n2. Add actionable instruction two.\n" - } - }, - "McpSettings": { - "loading": "加载中...", - "summary": { - "missingCommand": "(缺少 command)", - "missingUrl": "(缺少 url)" - }, - "protocol": { - "stdio": "Stdio" - }, - "errors": { - "selectInstallProtocol": "请选择安装协议", - "fieldRequired": "{field} 为必填项", - "fieldNeedsBoolean": "{field} 需要 true 或 false", - "fieldNeedsNumber": "{field} 需要数字", - "fieldNeedsInteger": "{field} 需要整数", - "fieldInvalidJson": "{field} JSON 无效:{message}", - "fieldOutOfRange": "{field} 的值不在可选范围内", - "jsonEmpty": "{name} 不能为空", - "jsonInvalid": "{name} 不是合法 JSON:{message}", - "jsonMustBeObject": "{name} 必须是 JSON 对象", - "specMustBeObject": "MCP 配置必须是 JSON 对象。", - "missingType": "MCP 配置缺少 type 字段。请填写 stdio、http(别名 streamable-http、streamableHttp)、sse 之一。", - "unsupportedType": "不支持的 MCP type:{type}。支持的类型:stdio、http(别名 streamable-http、streamableHttp)、sse。", - "codexEntryUnsupportedType": "Codex MCP 条目 {id} 的 type 不受支持:{type}。支持的类型:stdio、http(别名 streamable-http、streamableHttp)、sse。", - "unsupportedTransportType": "不支持的 transport 类型:{type}。支持的类型:http(别名 streamable-http、streamableHttp)、sse。", - "stdioCommandRequired": "stdio 类型的 MCP 必须填写非空的 command 字段。", - "remoteUrlRequired": "远端 MCP 必须填写非空的 url 字段。", - "appsRequired": "请至少选择一个目标 App。" - }, - "jsonNames": { - "localConfig": "MCP 配置", - "installConfig": "安装配置" - }, - "toasts": { - "uninstalled": "已卸载 MCP", - "uninstallFailed": "卸载失败:{message}", - "selectAtLeastOneApp": "请至少选择一个目标应用", - "saveSuccess": "保存成功", - "saveFailed": "保存失败:{message}", - "installed": "已安装 {name}", - "installFailed": "安装失败:{message}", - "serverIdRequired": "Server ID 不能为空", - "serverIdExists": "Server ID \"{id}\" 已存在,请编辑现有项或更换名称", - "created": "MCP 已创建" - }, - "installDialog": { - "title": "确认安装 MCP", - "descriptionWithName": "将 {name} 安装到本地配置。", - "description": "选择安装目标应用。", - "protocol": "协议", - "selectProtocol": "选择协议", - "parameters": "配置参数", - "booleanPlaceholder": "请选择 true/false", - "selectOneValue": "选择一个值", - "targetApps": "目标应用" - }, - "actions": { - "cancel": "取消", - "confirmInstall": "确认安装", - "installing": "安装中", - "uninstall": "卸载", - "uninstalling": "卸载中", - "viewDetails": "查看详情", - "save": "保存", - "saving": "保存中", - "install": "安装", - "refresh": "刷新", - "newMcp": "新建 MCP", - "create": "创建", - "creating": "创建中..." - }, - "tabs": { - "local": "本地 MCP", - "market": "MCP 市场" - }, - "local": { - "filterPlaceholder": "筛选本地 MCP...", - "loadFailed": "加载失败:{message}", - "empty": "当前未检测到本地 MCP。", - "description": "本地 MCP 配置可直接编辑并保存。", - "enabledApps": "启用应用", - "configJson": "MCP 配置(JSON)", - "draftTitle": "新建 MCP", - "draftDescription": "填写 Server ID 与配置以创建本地 MCP 服务器。", - "serverIdLabel": "Server ID", - "serverIdPlaceholder": "Server ID(例如:my-mcp)", - "typeHint": "支持类型:stdio、http(别名 streamable-http、streamableHttp)、sse。env 仅适用于 stdio;远端 MCP 请通过 headers 字段传递鉴权 token。", - "envOnRemoteWarning": "检测到远端 MCP 配置中包含 env 字段。env 仅 stdio 类型使用,远端 MCP 应通过 headers 携带鉴权信息,env 字段保存时会被忽略。" - }, - "market": { - "selectMarketplace": "选择市场", - "searchPlaceholder": "搜索 MCP...", - "searchFailed": "搜索失败:{message}", - "loadingList": "加载 MCP 列表...", - "empty": "暂无 MCP 结果。", - "loadingDetail": "加载市场详情...", - "detailLoadFailed": "加载详情失败:{message}", - "owner": "所有者:{owner}", - "namespace": "命名空间:{namespace}", - "defaultInstallProtocol": "默认安装协议", - "currentOptionParameterCount": "当前选项参数数:{count}", - "installConfigDescription": "安装配置(JSON,可修改后安装;修改后将覆盖协议/参数表单)", - "selectLeftToView": "请选择左侧市场 MCP 查看详情。" - }, - "badges": { - "verified": "已验证", - "remote": "远程", - "hasHomepage": "有主页", - "uses": "{count} 次使用", - "deployed": "已部署", - "notDeployed": "未部署" - }, - "selectLeftMcp": "请选择左侧 MCP。" - }, - "AcpAgentSettings": { - "title": "Agent SDK管理", - "description": "统一管理 Agent 的连接SDK、启用状态、环境变量、配置管理与版本预检信息。", - "loadingAgents": "加载 Agent 列表中...", - "agentList": "Agent 列表", - "emptyNoAgent": "暂无可用 Agent。", - "configManagement": "配置管理", - "envVars": "环境变量", - "hostTools": { - "label": "由 Agent 自行处理文件与命令", - "description": "codeg 不再代为提供文件访问和终端命令,改由 Agent 在自己的进程中执行——只有这样它自带的沙箱与权限规则才会生效。同时会关闭向其他 Agent 委托,否则同样的操作又会绕回 codeg 执行。codeg 本身不提供沙箱,因此请仅在 Agent 已配置沙箱时开启。" - }, - "nativeJsonConfig": "原生 JSON 配置", - "modelHintDefault": "留空则使用系统默认模型。", - "generalConfigDescriptionClaude": "支持 API URL、API Key 与 Claude 模型快捷配置,并与原生 JSON 配置联动。", - "generalConfigDescriptionDefault": "支持重要配置输入(API URL、API Key、Model)和原生 JSON 配置管理。", - "multiAgent": { - "title": "多智能体协同", - "description": "允许活跃的智能体把子任务委托给其他智能体。", - "enable": "启用委托", - "enableHint": "关闭后,delegate_to_agent 工具会从智能体的 MCP 工具清单中隐藏。", - "withheldByHostTools": "{agents} 不会拿到委派工具:它们单独开启了「由 Agent 自行处理文件与命令」。", - "depthLimit": "最大委托深度", - "depthHint": "允许范围:{min}–{max}。限制委托链(根 → 子 → 孙 …)的最大递归深度。", - "completedCacheLabel": "已完成结果缓存(MB)", - "completedCacheHint": "运行中委托会话已完成子智能体结果的内存缓存,仅在该会话运行期间保留,会话结束后自动清除。超出此预算时优先从内存中丢弃最旧的结果(仍可在子智能体自己的会话中查看);0 表示不限(会话结束后仍会清除)。", - "save": "保存", - "saving": "保存中…", - "saved": "委托设置已保存", - "saveFailed": "委托设置保存失败", - "loadFailed": "加载委托设置失败:{detail}", - "tabGeneral": "通用", - "tabAgentDefaults": "子智能体配置", - "agentDefaultsDescription": "多智能体协同在为委托调用启动子智能体时使用这些覆盖项。下方选项通过实时探测获取,所选即所用。", - "probing": "正在加载该智能体的可用配置项…", - "probeFailed": "加载配置项失败:{detail}", - "retry": "重试", - "noConfigAvailable": "该智能体没有可配置项。", - "modeLabel": "模式", - "agentDefaultHint": "智能体默认:{value}", - "defaultOptionLabel": "默认({value})" - }, - "actions": { - "dragSort": "拖拽排序", - "dragSortAgent": "拖拽排序 {name}", - "refreshCheck": "刷新检测", - "refreshCheckAgent": "刷新检测 {name}", - "clickEnable": "点击启用 {name}", - "clickDisable": "点击禁用 {name}", - "install": "安装", - "upgrade": "升级", - "uninstall": "卸载", - "uninstalling": "卸载中...", - "saveEnvVars": "保存环境变量", - "saving": "保存中...", - "saveGrokConfig": "保存 Grok 配置", - "saveCodexConfig": "保存 Codex 配置", - "saveGeminiConfig": "保存 Gemini 配置", - "saveOpenCodeConfig": "保存 OpenCode 配置", - "saveOpenClawConfig": "保存 OpenClaw 配置", - "saveConfigManagement": "保存配置管理", - "saveCurrentProvider": "保存当前 Provider", - "showApiKey": "显示 API Key", - "hideApiKey": "隐藏 API Key", - "showKey": "显示 Key", - "hideKey": "隐藏 Key", - "showToken": "显示 Token", - "hideToken": "隐藏 Token", - "cancel": "取消", - "delete": "删除", - "deleting": "删除中...", - "confirmDelete": "确认删除", - "confirmUninstall": "确认卸载", - "saveClineConfig": "保存 Cline 配置", - "saveHermesConfig": "保存 Hermes 配置", - "saveCodeBuddyConfig": "保存 CodeBuddy 配置", - "saveKimiCodeConfig": "保存 Kimi Code 配置", - "customInstall": "自定义安装", - "saveKimiCodeRawConfig": "保存 config.toml", - "saveDeepSeekConfig": "保存 DeepSeek 配置", - "diagnose": "诊断" - }, - "status": { - "enabled": "启用", - "disabled": "禁用", - "unchecked": "未检测", - "agentEnabledAria": "{name} 已启用", - "agentEnabledSwitch": "{name} 启用" - }, - "preflight": { - "count": "预检项:{count}", - "notRun": "尚未执行检测。" - }, - "grok": { - "configDescription": "在此配置 Grok。下方控件——权限模式、推理强度、可选的自定义(自带端点)模型和压缩——会合并写入 ~/.grok/config.toml,并保留你的其他键与注释。登录使用你的 XAI_API_KEY 或 `grok login`。其他键可在“高级”中编辑。", - "permissionModeLabel": "权限模式", - "permissionDefault": "每次询问", - "permissionAcceptEdits": "自动批准编辑", - "permissionAuto": "智能自动批准", - "permissionAlwaysApprove": "始终允许", - "reasoningEffortLabel": "推理级别", - "effortLow": "低(更快)", - "effortMedium": "中(均衡)", - "effortHigh": "高", - "effortXhigh": "最高", - "optionDefault": "使用默认", - "authTitle": "认证", - "authMode": "认证方式", - "authModeApiKey": "XAI API 密钥", - "authModeApiKeyHint": "使用 xAI 控制台的 XAI_API_KEY 认证——适用于非交互/无头运行。保存在该智能体的环境变量中。", - "authModeCustom": "自定义接口", - "authModeCustomHint": "使用自定义接口(BYO 端点):在下方定义一个带有独立 base URL 和 API 密钥的自定义模型,它将成为 Grok 的默认模型。", - "subscriptionHint": "使用 `grok login` 登录(SuperGrok / X Premium+)。不保存 API 密钥。", - "loginHint": "在终端运行以下命令登录,然后重新打开此设置:", - "commandCopied": "命令已复制到剪贴板", - "copyCommand": "复制命令", - "authKeyConfigured": "已配置 XAI_API_KEY。", - "authKeyMissing": "未设置 XAI_API_KEY。", - "advancedToggle": "高级(原始 config.toml)", - "configTomlNative": "config.toml(原生)", - "configTomlHint": "按原样整体写入 ~/.grok/config.toml。非法 TOML 会被拒绝,绝不因笔误截断文件。", - "configTomlPlaceholder": "# 上面控件之外的键,例如\n# [mcp_servers.*]、[cli]、[permission] 规则。", - "customModelTitle": "自定义模型(自带端点)", - "customModelHint": "让 Grok 指向自定义或自托管端点。codeg 会写入按模型的 `[model.*]` 块并将其设为默认模型。清空模型 ID 即可移除。", - "customModelIdLabel": "模型 ID", - "customModelIdPlaceholder": "grok-4.5", - "customModelIdHint": "注册为 `[model.*]` 块,并作为模型名发送给 API;同时设为 `[models].default`。", - "customBaseUrlLabel": "Base URL", - "customBaseUrlPlaceholder": "https://api.x.ai/v1(默认)", - "customApiBackendLabel": "API 后端", - "backendResponses": "Responses", - "backendChatCompletions": "Chat Completions", - "backendMessages": "Messages(Anthropic)", - "customApiKeyLabel": "API Key", - "customApiKeyHint": "内联存储于 `[model.*].api_key`,仅作用于该端点。", - "customContextWindowLabel": "上下文窗口(tokens)", - "customContextWindowHint": "可选。用于自动压缩计时;留空则使用端点默认值。", - "autoCompactLabel": "自动压缩阈值(%)", - "autoCompactHint": "当上下文使用率达到该百分比时压缩对话(Grok 默认 85)。写入 `[session]`。" - }, - "cursor": { - "configDescription": "在此配置 Cursor。先选择认证方式——官网订阅(浏览器登录)或用于无头/服务器的 Cursor API 密钥——然后选择模型并编辑 CLI 的权限规则与沙箱。codeg 会写入 ~/.cursor/cli-config.json,与 cursor-agent CLI 共享。", - "authTitle": "鉴权", - "authChecking": "检测中…", - "authNotInstalled": "cursor-agent 未安装", - "authLoggedIn": "已登录", - "authNotLoggedIn": "未登录", - "loginHint": "在终端运行以下命令登录 Cursor 账号(会打开浏览器),完成后点刷新:", - "apiKeyLabel": "Cursor API 密钥", - "apiKeyPlaceholder": "在 cursor.com/dashboard 获取", - "apiKeyHint": "CURSOR_API_KEY —— Cursor Dashboard 的账号密钥,在无头/服务器环境下替代浏览器登录。不是第三方或 OpenAI 密钥。", - "modelTitle": "默认模型", - "loadModels": "获取模型列表", - "modelsUnavailable": "模型列表不可用", - "modelHint": "会话启动时通过 --model 传给 CLI;保持默认则由 Cursor 自行选择。", - "permissionsTitle": "权限与沙箱", - "permissionsDescription": "可视化编辑 CLI 权限规则(cli-config.json)。允许规则免确认执行;拒绝规则始终拦截。", - "permissionModeLabel": "权限模式", - "permissionModeDefault": "执行前询问(默认)", - "permissionModeForce": "全部放行 Run Everything(--force)", - "permissionModeHint": "Run Everything 以 --force 启动会话:除 deny 规则外的所有工具调用自动放行、不再弹确认(组织策略可能将其降级为仅按 allow 规则放行)。对新会话生效。", - "optionDefault": "默认(未设置)", - "sandboxLabel": "沙箱", - "sandboxEnabled": "启用", - "sandboxDisabled": "禁用", - "allowRulesLabel": "允许规则", - "denyRulesLabel": "拒绝规则", - "addRule": "添加规则", - "rulesSyntaxHint": "规则语法:Shell(命令)、Read(路径/通配)、Write(路径/通配)、WebFetch(域名)、Mcp(服务器:工具)——deny 规则始终优先。", - "saveConfig": "保存配置", - "advancedToggle": "高级:原始 cli-config.json", - "advancedHint": "完整的 ~/.cursor/cli-config.json。此处保存按原文写入;上方结构化控件则以合并方式写入。", - "saveRawConfig": "保存文件", - "authMode": "认证方式", - "subscriptionHint": "使用 Cursor 账号登录,使用 Cursor 的模型。", - "customApiKeyRequired": "需要填写 Cursor API 密钥。", - "authModeApiKey": "Cursor API 密钥(无头/服务器)", - "authModeApiKeyHint": "用 Cursor 官网 Dashboard 生成的账号 API 密钥认证(适用于无头/服务器环境)。这是 Cursor 账号密钥,不是第三方/OpenAI 端点——cursor-agent 只连 Cursor 自己的后端。要使用 codex/OpenAI 兼容端点,请改用 Codex 智能体。", - "modelPickerPlaceholder": "搜索模型…", - "modelNoMatch": "没有匹配的模型", - "modelsNeedAuth": "登录后加载模型列表。", - "modelDefaultBadge": "默认" - }, - "deepseek": { - "configManagement": "DeepSeek Harness 配置", - "configDescription": "端点与密钥是 deepseek-acp 启动时读取的环境变量。模型和推理档位是会话级选择器,在输入框里切换。", - "baseUrlLabel": "API 端点", - "baseUrlHint": "留空则使用官方端点。保存后对新建的会话生效——正在进行的会话需要重新连接才会切换。", - "baseUrlInvalid": "请填写完整的 http(s) 地址且不带查询参数,例如 https://api.deepseek.com", - "apiKeyLabel": "API 密钥", - "apiKeyHint": "以 DEEPSEEK_API_KEY 传给智能体。环境变量的优先级高于凭据文件,因此若用终端登录,这里留空即可。" - }, - "codex": { - "configDescription": "支持 API URL、API Key、模型名称、Reasoning Effort 快捷配置,并与 `auth.json` / `config.toml` 双向联动。", - "authMode": "认证方式", - "chatgptSubscription": "官网订阅", - "chatgptSubscriptionHint": "使用 ChatGPT 官网订阅登录,无需配置 API Key", - "apiKeyHint": "使用 API Key 连接 OpenAI 或兼容的 API 服务", - "selectProvider": "选择 Provider", - "modelName": "模型名称", - "selectReasoningEffort": "选择 Reasoning Effort", - "enableWebsocket": "启用 WebSocket", - "enableWebsocketAria": "Codex Provider 启用 WebSocket", - "enableSkills": "启用 Skills", - "enableSkillsAria": "Codex 启用 Skills", - "enableFast": "启用 Fast", - "enableFastAria": "Codex 启用 Fast 服务等级", - "sandboxGroupTitle": "沙箱与审批", - "sandboxGroupHint": "写入全局 ~/.codex/config.toml,codex CLI 与 IDE 的会话同样生效。这是线程默认值,只作用于 codex 自行发起的回合(/goal、/review、/compact);普通对话使用输入框里的审批预设。改动需重开会话才生效。", - "sandboxShadowedWarning": "config.toml 里设置了 default_permissions,codex 会改走权限配置档并完全忽略 sandbox_mode。删掉 default_permissions 后下面的选项才会生效。", - "sandboxPermissionsTableWarning": "config.toml 定义了 [permissions] 配置档却没有 default_permissions,codex 会拒绝启动。请在下方原始编辑器里补上。", - "approvalPolicyLabel": "审批策略", - "approvalPolicyUnset": "未设置(codex 默认:按需询问)", - "approvalPolicy_on-request": "按需询问 — 由模型决定何时请求批准", - "approvalPolicy_untrusted": "仅信任只读 — 只有已知安全的只读命令免批准", - "approvalPolicy_never": "从不询问 — 完全不弹审批", - "approvalPolicy_granular": "精细控制 — 按提示类型分别设置", - "approvalPolicyUntrustedAcpWarning": "ACP 适配器只有三种审批预设,untrusted 无对应项,codeg 会话会退回「按需询问」——此时由模型自行决定何时询问,沙箱本就允许的命令不再询问。请改用下方的沙箱模式收紧。", - "granularHint": "关闭表示该类请求被自动拒绝,而不是弹给你确认。", - "granular_sandbox_approval": "Shell 命令越权申请", - "granular_rules": "Execpolicy 规则提示", - "granular_skill_approval": "技能脚本执行提示", - "granular_request_permissions": "request_permissions 工具提示", - "granular_mcp_elicitations": "MCP elicitation 提示", - "sandboxModeLabel": "沙箱模式", - "sandboxModeUnset": "未设置(受信任的文件夹回落为可写工作区)", - "sandboxMode_read-only": "只读", - "sandboxMode_workspace-write": "可写工作区", - "sandboxMode_danger-full-access": "完全放开(无沙箱)", - "sandboxModeHint": "在 Windows 上,未开启 codex 的实验性 Windows 沙箱时,可写工作区会被降级为只读。", - "sandboxModeSeedsPresetHint": "codeg 还会用它推导会话的初始审批预设,因此与审批策略不同,它对普通提问同样生效。输入框中选择的预设仍会覆盖它。", - "writableRootsLabel": "额外可写目录", - "writableRootsHint": "每行一个绝对路径,作为工作目录之外的额外可写位置。", - "sandboxRootsRelativeError": "必须是绝对路径 — codex 会把相对路径解析到 ~/.codex 下:{path}", - "networkAccessLabel": "允许网络访问", - "excludeTmpdirLabel": "从可写目录中排除 TMPDIR", - "excludeSlashTmpLabel": "从可写目录中排除 /tmp", - "authJsonNative": "auth.json(原生)", - "configTomlNative": "config.toml(原生)", - "loginButton": "使用 ChatGPT 登录", - "loginRequesting": "正在请求登录码...", - "loginStep1": "在浏览器中打开以下链接:", - "loginStep2": "输入以下代码:", - "loginPolling": "等待授权中...", - "loginCancel": "取消", - "loginSuccess": "登录成功,配置已保存!", - "loginFailed": "登录失败:{message}", - "loginRetry": "重试", - "loginCodeCopied": "已复制代码", - "loggedIn": "账号已登录", - "loginRelogin": "重新登录 / 切换账号", - "loginTimeout": "登录超时,请重试", - "loginSaveFailed": "登录成功但配置保存失败" - }, - "gemini": { - "authConfig": "Gemini 认证配置", - "authConfigDescription": "对齐 Gemini CLI 认证文档,支持自定义、Google 登录、Gemini API Key、Vertex AI(ADC / 服务账号 / API Key)。", - "authMode": "认证方式", - "selectAuthMode": "选择认证方式", - "viewAuthDoc": "查看认证文档", - "mode": { - "custom": "自定义接口", - "loginGoogle": "Google 登录(OAuth)", - "vertexServiceAccount": "Vertex AI(服务账号)" - }, - "hint": { - "custom": "填写 API URL、API Key 和 Model,分别映射到 GOOGLE_GEMINI_BASE_URL / GEMINI_API_KEY / GEMINI_MODEL。", - "loginGoogle": "首次在终端运行 gemini 并完成 Google 登录;无需填写 API Key。", - "geminiApiKey": "使用 Gemini API 时填写 GEMINI_API_KEY。", - "vertexAdc": "使用 gcloud ADC,建议填写 GOOGLE_CLOUD_PROJECT 与 GOOGLE_CLOUD_LOCATION。", - "vertexServiceAccount": "服务账号 JSON 路径写入 GOOGLE_APPLICATION_CREDENTIALS。", - "vertexApiKey": "使用 Vertex AI API key 时填写 GOOGLE_API_KEY。" - } - }, - "openCode": { - "configManagement": "OpenCode 配置管理", - "configDescription": "对齐 OpenCode `provider` 配置结构,支持多供应商管理,并与原生 JSON 文件双向联动。", - "providerManagement": "Provider 管理", - "providerCount": "共 {count} 个", - "addProvider": "新增 Provider", - "emptyProvider": "还没有自定义 Provider。点击「添加自定义 Provider」创建。", - "providerEnabledState": "{providerId} 启用状态", - "selectProviderNpm": "选择 provider.npm", - "modelManagement": "模型管理", - "modelCount": "共 {count} 个", - "modelDescription": "对齐 OpenCode `provider.models` 结构。当前支持 `name` / `id` 快速管理;其它高级字段会保留,可在下方原生 JSON 中继续编辑。", - "addModel": "添加模型", - "emptyModel": "暂无模型,输入 model id 后点击“添加模型”创建。", - "modelId": "模型 ID", - "modelName": "模型名称", - "deleteModel": "删除模型 {modelId}", - "nativeJsonConfig": "OpenCode 原生 JSON 配置", - "mainModel": "主模型", - "smallModel": "小模型", - "noMatchingModels": "没有匹配的模型", - "connectProvider": "连接 Provider", - "connectedProviders": "已连接的 Provider", - "noConnectedProviders": "还没有从目录连接 Provider。", - "advancedProviderConfig": "自定义 Provider", - "customProviderConfigHint": "你自己定义的 OpenAI 兼容端点——opencode.json 里的一个 provider 配置块,API key 存在 auth.json。", - "addCustomProvider": "添加自定义 Provider", - "disconnect": "断开", - "editConfig": "编辑", - "customBadge": "自定义", - "authKindApi": "API Key", - "authKindOauth": "OAuth", - "authKindNone": "无凭证", - "connect": { - "title": "连接 Provider", - "description": "从 models.dev 目录选择一个 Provider。凭证保存到 OpenCode 的 auth.json 文件。", - "pick": "Provider", - "search": "搜索 Provider…", - "loading": "正在加载目录…", - "catalogLabel": "models.dev 目录", - "modelsAvailable": "{count} 个可用模型", - "getKey": "获取 API Key", - "oauthApiKeyNote": "该 Provider 也支持通过 opencode auth login 浏览器登录。浏览器登录即将推出——目前请粘贴 API Key。", - "apiKey": "API Key", - "apiKeyHint": "保存在 auth.json,绝不写入 opencode.json。", - "baseUrlOptional": "Base URL 覆盖(可选)", - "providerId": "Provider ID", - "displayName": "显示名称", - "modelsList": "模型(每行一个)", - "modelsHint": "端点接受的模型 ID。", - "action": "连接", - "editTitle": "编辑 Provider", - "editDescription": "更新该 Provider 的 API Key 或 Base URL。", - "saveAction": "保存" - }, - "customProvider": { - "title": "添加自定义 Provider", - "description": "定义一个 OpenAI 兼容端点。API key 保存到 auth.json;provider 配置块写入 opencode.json。", - "action": "添加 Provider", - "idInCatalog": "{providerId} 是已知 Provider,请改用「连接 Provider」连接。" - }, - "refreshCatalog": "刷新目录", - "reasoningBadge": "推理", - "contextWindow": "上下文窗口", - "permissions": { - "title": "权限", - "description": "决定哪些操作直接运行、先征求你的同意,还是被阻止。写入 opencode.json 的 permission 配置,点击下方保存后生效。", - "docsLink": "权限文档", - "unparsableConfig": "下方的原生 JSON 当前无法解析,可视化编辑已暂停。修复 JSON 后即可继续。", - "invalidBlock": "permission 配置的结构无法识别。请在下方原生 JSON 中修改,或点击「恢复默认」重来。", - "orderingUnsafe": "通配规则写在了具体工具之后,OpenCode 会把它一并应用到这些工具上——下方各行显示的并非实际生效的规则。「修正顺序」只把通配规则移回各自作用域的最前面,不改动任何取值。", - "orderingUnsafeManual": "有规则被后面更宽泛的模式遮蔽,OpenCode 永远不会应用它——下方各行显示的并非实际生效的规则。两个互相重叠的模式没有唯一正确的顺序,请在下方原生 JSON 中调整,把更宽泛的写在前面。", - "fixOrder": "修正顺序", - "agentOverrides": "以下智能体单独覆盖了权限,且在最后应用,因此会盖过此处的全部设置:{agents}。请在下方原生 JSON 中修改,或开启「自动接受所有权限」将其清除。", - "legacyTools": "顶层的旧版 tools 配置禁用了某个工具。OpenCode 会把它并入权限,因此它会叠加在此处显示的全部设置之上。请在下方原生 JSON 中修改,或开启「自动接受所有权限」将其清除。", - "autoAcceptTitle": "自动接受所有权限", - "autoAcceptHint": "所有工具调用(shell 命令、文件修改、访问项目外路径)都不再询问,直接执行。开启后会用一条全局允许规则替换下方的逐工具设置,并清除各智能体单独的权限覆盖与旧版 tools 开关——否则它们仍会拦截。", - "globalLabel": "全局默认", - "globalHint": "即 * 规则:下方工具未单独覆盖时采用的动作。", - "actionUnset": "未设置(OpenCode 默认)", - "actionInherit": "跟随默认({action})", - "actionAllow": "允许", - "actionAsk": "询问", - "actionDeny": "拒绝", - "perToolTitle": "逐工具权限", - "reset": "恢复默认", - "ruleCount": "细则 {count} 条", - "rulesToggle": "{tool} 的细粒度规则", - "rulesHint": "按工具输入匹配,最后匹配的规则优先,因此请把宽泛的模式写在前面。* 匹配任意多个字符,? 精确匹配一个字符,开头的 ~ 展开为主目录。", - "noRules": "暂无细粒度规则。", - "addRule": "添加规则", - "deleteRule": "删除规则 {pattern}", - "duplicateRule": "该模式已存在。", - "blankRule": "规则必须有模式;如需删除请点击垃圾桶图标。", - "customKeys": "文件中的其他权限键", - "customKeyHint": "并非 OpenCode 内置工具,将按原样保留。", - "keys": { - "bash": "运行 shell 命令,按解析后的命令匹配", - "edit": "所有文件修改:edit、write 与 patch", - "read": "读取文件,按文件路径匹配", - "external_directory": "访问项目工作目录之外的路径", - "task": "启动子代理,按子代理类型匹配", - "skill": "加载技能,按技能名称匹配", - "glob": "查找文件,按通配模式匹配", - "grep": "搜索文件内容,按模式匹配", - "list": "列出目录内容", - "webfetch": "获取 URL", - "websearch": "网页搜索", - "lsp": "运行 LSP 查询", - "todowrite": "写入待办列表", - "question": "向你提问", - "doom_loop": "同一调用以相同输入重复 3 次时触发" - } - } - }, - "openClaw": { - "gatewayConfig": "Gateway 配置", - "gatewayDescription": "配置 OpenClaw Gateway 连接信息。支持本地或远程 Gateway。", - "gatewayUrlHint": "留空则使用 openclaw 本地配置的 gateway.remote.url。", - "gatewayTokenPlaceholder": "Gateway 认证 Token", - "gatewayTokenHint": "建议使用 token-file 替代明文 Token,可通过 openclaw 命令行配置。", - "sessionKeyHint": "可选。指定 Gateway Session Key,留空则自动分配隔离会话。" - }, - "hermes": { - "configManagement": "Hermes 配置", - "configDescription": "Hermes 在 ~/.hermes/.env 中管理自己的凭据,在 ~/.hermes/config.yaml 中管理设置。选择一个供应商,然后设置 API 密钥和模型——codeg 会替你写入这两个文件。", - "providerLabel": "供应商", - "providerHint": "供应商决定 Hermes 使用哪个 API 密钥变量和 model.provider。OAuth 供应商通过下方的终端设置进行配置。", - "groupApiKey": "API 密钥提供商", - "groupOauth": "OAuth 提供商", - "groupAws": "AWS", - "apiKeyHint": "保存到 ~/.hermes/.env。它绝不会被注入进程——Hermes 会从自己的配置中读取它。", - "modelName": "模型", - "oauthHint": "此供应商使用 OAuth。请运行下方的设置流程,在终端中完成认证。", - "awsHint": "Bedrock 使用你的 AWS 凭据(环境变量或共享配置)。请在上方填写模型 ID,并在系统环境中配置 AWS 访问权限。", - "unsupportedProvider": "该提供商无法通过结构化字段编辑。请使用下方的 config.yaml 原始编辑器或终端引导设置。", - "setupTitle": "自管理设置", - "setupHint": "Hermes 的交互式设置需要终端。可在下方启动,或复制命令自行运行。", - "runSetup": "运行 Hermes 设置", - "configureModel": "配置模型", - "openConfigFolder": "打开 ~/.hermes", - "copyCommand": "复制命令", - "commandCopied": "命令已复制到剪贴板", - "advancedTitle": "高级:编辑 config.yaml", - "rawConfigHint": "直接编辑 ~/.hermes/config.yaml。在此保存将原样覆盖该文件。", - "saveRawConfig": "保存 config.yaml" - }, - "codebuddy": { - "configManagement": "CodeBuddy 配置", - "configDescription": "CodeBuddy 使用 API Key 进行认证。中国版还必须将环境设为“中国版(internal)”;iOA 版使用“iOA”;海外版则不设置。", - "apiKeyLabel": "API Key", - "apiKeyHint": "将作为该智能体的 CODEBUDDY_API_KEY 保存。也可以在终端用 CodeBuddy CLI 登录。", - "apiKeyHintSelfHosted": "将作为该智能体的 CODEBUDDY_API_KEY 保存。请使用你的私有化部署签发的密钥。", - "environmentLabel": "环境", - "environmentHint": "设置 CODEBUDDY_INTERNET_ENVIRONMENT。中国大陆必须使用“中国版(internal)”;海外版则不设置。", - "envOverseas": "海外版(默认)", - "envChina": "中国版(internal)", - "envIoa": "iOA", - "envSelfHosted": "私有化部署", - "baseUrlLabel": "私有化部署地址", - "baseUrlPlaceholder": "https://codebuddy.your-company.com", - "baseUrlHint": "保存为 CODEBUDDY_BASE_URL,将 CodeBuddy 指向你的私有端点。私有化部署不设置网络环境(CODEBUDDY_INTERNET_ENVIRONMENT)。", - "baseUrlInvalid": "请输入合法的 http(s) 地址。", - "loginHint": "没有 API Key?也可以在终端运行 “codebuddy” 用腾讯云账号登录。" - }, - "kimiCode": { - "configManagement": "Kimi Code 配置", - "configDescription": "`kimi acp` 只认已存储的登录令牌,所以 codeg 会在 ~/.kimi-code/config.toml 写入受管供应商,并在本地播种一个门控令牌——推理仍然走你自己的 Key。", - "statusUnconfigured": "尚未配置", - "statusDirty": "有未保存的修改", - "summaryLabel": "生效配置", - "gateReadyApiKey": "API Key 已写入 config.toml", - "gateReadyLogin": "已通过 Kimi 账号登录", - "revealConfig": "在文件夹中显示", - "envOverrideWarning": "检测到 {keys},其优先级高于 config.toml。在此保存会自动清除它。", - "authModeLabel": "鉴权方式", - "authModeApiKey": "API Key", - "authModeLogin": "Kimi 账号登录(订阅)", - "authModeApiKeyHint": "在 config.toml 写入受管供应商,并播种门控令牌以便会话能够打开。", - "loginHint": "在终端运行 `kimi login`,用 Kimi 订阅账号登录。codeg 不存储任何凭据,复用 Kimi 自己的登录。在此保存会移除 codeg 的 API Key 门控令牌。", - "credentialTitle": "凭据", - "interfaceTypeLabel": "供应商类型", - "interfaceTypeHint": "Kimi 使用的供应商协议(config.toml 的 `type`)。Moonshot / platform.kimi.com 的 Key 请选「Kimi / Moonshot」。", - "endpointLabel": "接入点", - "endpointCustom": "自定义(OpenAI 兼容)", - "endpointHint": "国际 = api.moonshot.ai;中国(platform.kimi.com 的 Key)= api.moonshot.cn。自定义可指向任意 OpenAI 兼容端点。", - "regionInternational": "国际(api.moonshot.ai)", - "regionChina": "中国(api.moonshot.cn)", - "baseUrlLabel": "Base URL", - "baseUrlHint": "留空则使用供应商 SDK 默认值。", - "apiKeyLabel": "API Key", - "apiKeyHint": "写入 ~/.kimi-code/config.toml 并用于推理。来自 platform.kimi.com 或 platform.kimi.ai。", - "vertexProjectLabel": "GCP 项目(GOOGLE_CLOUD_PROJECT)", - "vertexLocationLabel": "GCP 区域(GOOGLE_CLOUD_LOCATION)", - "vertexHint": "Vertex AI 使用 Google 应用默认凭据——运行 `gcloud auth application-default login`(无需 API Key)。", - "modelTitle": "模型", - "modelLabel": "模型", - "modelHint": "写入 config.toml 的模型 id。点「测试并获取模型」可查看你的 Key 实际能访问哪些模型。", - "maxContextLabel": "最大上下文长度", - "maxContextHint": "Kimi 的配置 schema 要求必填:缺失会让 Kimi 丢弃整个模型块,导致每次对话都没有回复。默认 262144。", - "fetchModels": "测试并获取模型", - "fetchModelsOk": "Key 可用——共 {count} 个模型", - "fetchModelsEmpty": "Key 可用,但未返回任何模型", - "fetchModelsFailed": "测试失败", - "fetchModelsNeedsKey": "请先填写 API Key 和接入点", - "modelNotInList": "该模型不在你的 Key 可访问列表中,Kimi 会报「模型不存在」。", - "reasoningTitle": "推理", - "reasoningEnableLabel": "启用", - "reasoningDescription": "只有当模型声明了推理能力,Kimi 才会在输入框显示「Thinking」选择器,所以这里由 codeg 写入该声明。对新建会话生效。", - "effortsLabel": "可选档位", - "effortsHint": "这些会成为输入框「Thinking」选择器里的档位。Kimi 会把档位原样透传给供应商,请选你的模型能接受的值。", - "effortsEmptyHint": "一个档位都不选时,输入框只会退化成 Off / On 两档开关。", - "effortsCustomPlaceholder": "添加其它档位", - "effortsAdd": "添加", - "defaultEffortLabel": "默认档位", - "defaultEffortAuto": "由 Kimi 决定", - "alwaysThinkingLabel": "模型始终推理——从选择器中去掉 Off 档", - "fixErrorsFirst": "请先修正标红的字段", - "errorModelRequired": "模型为必填项", - "errorMaxContextRequired": "最大上下文长度为必填项", - "errorMaxContextInvalid": "必须是正整数", - "errorApiKeyRequired": "API Key 为必填项", - "errorApiKeyInvalid": "API Key 不能包含换行", - "errorBaseUrlRequired": "Base URL 为必填项", - "errorBaseUrlInvalid": "必须以 http:// 或 https:// 开头", - "errorVertexProjectRequired": "GCP 项目为必填项", - "errorDefaultEffortUnlisted": "必须是上面已选中的档位之一", - "advancedTitle": "高级", - "authTypeLabel": "凭据写入位置", - "authTypeApiKey": "内联 api_key", - "authTypeEnv": "供应商 env 子表", - "authTypeHint": "API Key 在 config.toml 中的写入位置。", - "rawEditorLabel": "直接编辑 config.toml", - "rawEditorWarning": "在此保存会按原文覆盖整个文件,替换掉上方的结构化配置。", - "rawEditorPlaceholder": "[providers.codeg]\ntype = \"kimi\"\nbase_url = \"https://api.moonshot.cn/v1\"\napi_key = \"sk-...\"" - }, - "authModeOfficialSubscription": "官网订阅", - "authModeCustomEndpoint": "自定义接口", - "authModeCustomEndpointHint": "手动配置 API URL 和 API Key 连接自定义接口。", - "authModeModelProvider": "模型供应商", - "modelProvider": "模型供应商", - "modelProviderHint": "使用已配置的模型供应商的 API URL、API Key 和模型。", - "selectModelProvider": "选择模型供应商", - "noModelProviderAvailable": "该代理未配置模型供应商。请前往模型供应商设置添加。", - "claude": { - "authMode": "认证方式", - "officialSubscription": "官方订阅", - "officialSubscriptionHint": "使用 Anthropic 官方订阅,无需 API Key。", - "mainModel": "主模型", - "reasoningModel": "推理模型(thinking)", - "haikuDefaultModel": "Haiku 默认模型", - "sonnetDefaultModel": "Sonnet 默认模型", - "opusDefaultModel": "Opus 默认模型", - "customModelOption": "自定义模型 ID", - "customModelOptionName": "自定义模型名称", - "customModelOptionDescription": "自定义模型描述", - "customModelOptionHint": "在 Claude 模型选择器中追加一个自定义条目(例如经自定义网关/代理提供的模型)。名称与描述为可选的显示信息。", - "effortLevel": "推理级别", - "effortLevelDefault": "默认级别", - "effortLevel_low": "低", - "effortLevel_medium": "中", - "effortLevel_high": "高", - "effortLevel_xhigh": "超高", - "sendAttributionHeader": "向接口发送归属/计费标识", - "sendAttributionHeaderAria": "向接口发送 Claude Code 归属/计费标识", - "disableNonessentialTraffic": "禁用遥测或多余的网络请求", - "disableNonessentialTrafficAria": "禁用 Claude Code 遥测或多余的网络请求" - }, - "dialogs": { - "confirmDeleteProvider": "确认删除 Provider {providerId}?", - "confirmDeleteProviderDescription": "将同步更新 OpenCode 配置与认证 JSON 文件,删除后不可恢复。", - "confirmUninstall": "确认卸载 {name}?", - "confirmUninstallDescription": "这会移除本地安装版本,之后可随时重新安装。", - "customInstallTitle": "自定义安装 {name}", - "customInstallDescription": "输入要安装的版本号。将重新安装并替换当前已安装的版本。", - "customInstallVersionLabel": "版本号", - "customInstallInvalid": "请输入有效的版本号,例如 1.2.3。", - "customInstallSubmit": "安装" - }, - "errors": { - "windowsFileLocked": "{name} 的程序文件正被运行中的会话占用,Windows 下无法替换。请先关闭所有 {name} 会话后重试。", - "nativeJsonMustBeObject": "原生 JSON 配置必须是对象", - "nativeJsonInvalid": "原生 JSON 配置格式错误:{message}", - "openCodeAuthMustBeObject": "OpenCode auth.json 必须是 JSON 对象", - "openCodeAuthInvalid": "OpenCode auth.json 格式错误:{message}", - "authMustBeObject": "auth.json 必须是 JSON 对象", - "authInvalid": "auth.json 格式错误:{message}", - "providerIdPattern": "Provider ID 仅支持字母、数字、下划线、点与中划线", - "providerExists": "Provider {providerId} 已存在", - "modelIdPattern": "模型 ID 仅支持字母、数字、下划线、点、冒号与中划线", - "modelExists": "Model {modelId} 已存在" - }, - "warnings": { - "nativeJsonRecoveredStructured": "原生 JSON 配置格式无效,已重置为结构化配置", - "nativeJsonRecoveredOpenCode": "原生 JSON 配置格式无效,已重置为 OpenCode 结构化配置", - "openCodeAuthRecovered": "OpenCode auth.json 格式无效,已重置为默认配置", - "authRecoveredStructured": "auth.json 格式无效,已重置为结构化配置" - }, - "toasts": { - "agentActionCompleted": "{name}{action}完成", - "agentActionFailed": "{name}{action}失败", - "localVersion": "本地版本:{version}", - "installCompletedVersionLater": "安装完成,版本将在下一次检测时更新", - "uninstallCompleted": "{name}卸载完成", - "uninstallFailed": "{name}卸载失败", - "localVersionRemoved": "本地版本已移除", - "saveAgentOrderFailed": "保存 Agent 排序失败", - "saveAgentSwitchFailed": "保存 Agent 开关失败", - "saveEnvFailed": "保存环境变量失败", - "grokSaved": "Grok 配置已保存", - "saveGrokNativeFailed": "保存 Grok 原生配置失败", - "saveGrokApiKeyFailed": "设置已保存,但 API Key 未能保存", - "cursorSaved": "Cursor 配置已保存", - "saveCursorConfigFailed": "保存 Cursor 配置失败", - "codexSaved": "Codex 配置已保存", - "saveCodexNativeFailed": "保存 Codex 原生配置失败", - "geminiSaved": "Gemini 配置已保存", - "saveGeminiFailed": "保存 Gemini 配置失败", - "providerDeleted": "Provider {providerId} 已删除", - "providerDeleteFailed": "删除 Provider {providerId} 失败", - "providerSaved": "Provider {providerId} 保存成功", - "saveProviderFailed": "保存 Provider {providerId} 失败", - "openCodeConfigSynced": "OpenCode 配置与认证 JSON 已同步保存。", - "openCodeSaved": "OpenCode 配置已保存", - "saveOpenCodeFailed": "保存 OpenCode 配置失败", - "openClawSaved": "OpenClaw 配置已保存", - "saveOpenClawFailed": "保存 OpenClaw 配置失败", - "configSaved": "配置已保存", - "configSavedHint": "已有会话需要重新打开才能生效", - "saveConfigManagementFailed": "保存配置管理失败", - "clineSaved": "Cline 配置已保存", - "saveClineFailed": "保存 Cline 配置失败", - "hermesSaved": "Hermes 配置已保存", - "saveHermesFailed": "保存 Hermes 配置失败", - "codeBuddySaved": "CodeBuddy 配置已保存", - "saveCodeBuddyFailed": "保存 CodeBuddy 配置失败", - "kimiCodeSaved": "Kimi Code 配置已保存", - "saveKimiCodeFailed": "保存 Kimi Code 配置失败", - "deepseekSaved": "DeepSeek 配置已保存", - "saveDeepSeekFailed": "保存 DeepSeek 配置失败", - "modelProviderRequired": "请先选择一个模型供应商再保存。", - "affectedRunningSessions": "{count} 个进行中的会话需重连以应用更改", - "providerConnected": "已连接 {providerId}", - "connectFailed": "连接 {providerId} 失败", - "providerDisconnected": "已断开 {providerId}", - "disconnectFailed": "断开 {providerId} 失败", - "catalogRefreshed": "目录已刷新——{count} 个 provider", - "catalogRefreshFailed": "刷新目录失败", - "piSaved": "Pi 配置已保存", - "savePiFailed": "保存 Pi 配置失败", - "piRuntimeSaved": "Pi 运行时已保存", - "savePiRuntimeFailed": "保存 Pi 运行时失败", - "piBinaryInstalled": "pi 已安装", - "piBinaryInstallFailed": "pi 安装失败", - "piBinaryUninstalled": "pi 已卸载", - "piBinaryUninstallFailed": "pi 卸载失败", - "savePiTrustFailed": "保存工作区信任失败" - }, - "version": { - "statusLabel": "版本状态", - "notInstalled": "未安装", - "remoteLocal": "远程:{remoteVersion} · 本地:{localVersion}", - "localOnly": "本地:{localVersion}", - "localInstalled": "{versionText}。已安装。", - "platformUnsupported": "{versionText}。当前平台不支持该 Agent。", - "uvxNotReady": "{versionText}。uv 运行时未安装——请在下方 uv 预检项中安装后再使用该 Agent。", - "clickInstall": "{versionText}。请点击右侧安装。", - "localUnrecognized": "{versionText}。本地版本无法识别,可尝试升级覆盖安装。", - "upgradeAvailable": "{versionText}。发现可升级版本。", - "remoteUnavailable": "{versionText}。远程版本暂不可用。", - "latest": "{versionText}。已是最新版本。" - }, - "adapter": { - "label": "ACP 适配器", - "badge": "ACP 适配器", - "badgeHint": "Codeg 为该智能体安装的是 ACP 适配器包,而不是厂商 CLI —— 两者互相独立,配置共享。", - "learnMore": "了解详情", - "missingWithNative": "已检测到你本地的 {nativeLabel}:{nativePath}。Codeg 通过 ACP 协议驱动智能体,而该 CLI 本身不支持 ACP,所以 Codeg 需要单独的适配器包 {adapterPackage}(由 Agent Client Protocol 项目维护,最初由 Zed 团队发起)。它自带运行时,不会修改或替换你的 {nativeCmd} 命令,读取的也是同一个 {configDir} —— 已有的登录和配置直接沿用。点击下方安装即可。", - "missing": "Codeg 通过 ACP 协议驱动智能体,而 {nativeLabel} 本身不支持 ACP,所以 Codeg 需要单独的适配器包 {adapterPackage}(由 Agent Client Protocol 项目维护,最初由 Zed 团队发起)。它自带运行时,因此不必先装 {nativeCmd} CLI;如果你已经装了,两者可以共存,并共用 {configDir} 里的登录和配置。点击下方安装即可。", - "readyWithNative": "适配器 {adapterCmd} 已安装 —— Codeg 启动的是它,而不是你本地的 {nativeCmd}({nativePath})。两者是各自独立的包,可以共存,且都读取 {configDir},登录和配置共享。", - "ready": "适配器 {adapterCmd} 已安装 —— Codeg 启动的就是它。它自带运行时,所以不需要另外安装 {nativeLabel};即便以后你装了,两者也能共存并共用 {configDir}。" - }, - "cline": { - "configDescription": "配置 Cline API 提供商和凭证。设置将保存到 ~/.cline/data/。" - }, - "opencodePlugins": { - "title": "OpenCode 插件", - "declared": "已声明的插件", - "noPlugins": "opencode.json 中未声明任何插件", - "status": { - "installed": "已安装", - "missing": "未安装" - }, - "installAll": "安装全部缺失插件", - "pinVersions": "固定 @latest 版本", - "install": "安装", - "uninstall": "卸载", - "refresh": "刷新", - "success": "所有插件安装成功", - "failed": "插件操作失败" - }, - "pi": { - "configManagement": "Pi 配置", - "configDescription": "Pi 通过模型提供方的 API Key 鉴权。Key 写入 ~/.pi/agent/auth.json,模型选择写入 settings.json。", - "providerLabel": "提供方", - "modelLabel": "模型", - "thinkingLabel": "思考", - "thinking": { - "off": "关闭", - "low": "低", - "medium": "中", - "high": "高", - "minimal": "极低", - "xhigh": "极高" - }, - "apiKeyLabel": "API Key", - "apiKeyHint": "为所选提供方写入 ~/.pi/agent/auth.json。", - "apiKeySetPlaceholder": "•••••• (已保存,留空则保持不变)", - "saveConfig": "保存 Pi 配置", - "providerModelRequired": "提供方和模型为必填", - "runtimeTitle": "运行时", - "runtimeDescription": "选择运行哪个 pi。使用默认,或指向你自己的 pi 构建。", - "modeDefault": "默认 pi", - "modeDefaultHint": "使用内置 pi-acp 适配器拉起 PATH 上的 pi。 安装 pi:npm install -g @earendil-works/pi-coding-agent", - "modeCustom": "自定义 pi", - "modeCustomHint": "运行你自己的 pi 构建、安装或包装脚本。", - "commandLabel": "pi 命令或路径", - "commandHint": "绝对路径、PATH 上的命令名,或包装脚本(如 monorepo 的 ./pi-test.sh)。", - "commandNotFound": "未找到命令", - "validate": "验证", - "advanced": "高级", - "configDirLabel": "配置目录 (PI_CODING_AGENT_DIR)", - "sessionDirLabel": "会话目录 (PI_CODING_AGENT_SESSION_DIR)", - "flagsHint": "pi-acp 不转发自定义 pi 参数(--approve、-e 等)——用脚本包装 pi 并将命令指向它。", - "customIncomplete": "请输入 pi 命令以保存", - "saveRuntime": "保存运行时", - "providerPlaceholder": "选择提供方", - "customProvider": "自定义提供方…", - "providerIdLabel": "提供方 ID", - "apiProtocolLabel": "API 协议", - "baseUrlLabel": "接口地址(Base URL)", - "customProviderHint": "在 ~/.pi/agent/models.json 中按你的接口地址定义一个提供方。多数自托管或代理服务使用 openai-completions。", - "baseUrlRequired": "接口地址(Base URL)为必填项", - "binaryTitle": "pi 二进制 (pi-coding-agent)", - "binaryDescription": "pi-acp 运行此 pi 二进制。可在此安装,或在下方指向你自己的构建。", - "binaryInstalled": "已安装", - "binaryMissing": "未安装", - "binaryChecking": "检测中…", - "installBinary": "安装 pi", - "installing": "安装中…", - "recheck": "重新检测", - "configDirSkillsNote": "设置了自定义配置目录后,设置页中管理的技能、专家与办公工具将不会作用于该 pi;请直接在该目录中管理其技能。", - "projectTrustTitle": "项目信任", - "projectTrustDescription": "你允许 pi 从中加载项目文件的目录。被信任的目录会让该仓库的 .pi/extensions 在 pi 启动时执行代码,且对其下所有子目录同样生效,你在终端里运行 pi 时也会沿用。", - "projectTrustLoading": "加载中…", - "projectTrustEmpty": "尚未对任何目录做出决定。", - "projectTrustTrusted": "已信任", - "projectTrustDenied": "不信任", - "projectTrustRevoke": "撤销", - "reasoningTitle": "推理", - "reasoningEnableLabel": "启用", - "reasoningDescription": "只有模型声明了推理能力,pi 才会发送推理强度——未声明的模型所有档位都会被压回 Off,所以输入框里的选择器一改就弹回。这里写入 models.json 中该模型的条目。", - "levelsLabel": "可选档位", - "levelsHint": "这些会成为输入框推理选择器里的档位。请选你的接入点能接受的值;不在这里的档位 pi 一律拒绝。", - "levelsEmptyError": "至少选一个档位——一个都不选时 pi 只会退回 Off。", - "wireValuesTitle": "高级:发给供应商的值", - "wireValuesHint": "留空表示原样发送档位名。接入点需要别的写法时才填——Google 系需要 LOW / HIGH。", - "defaultLevelUnlisted": "该档位不在上面的可选列表里——pi 会把它压下来。" - }, - "addCustomAgent": "添加自定义智能体", - "addCustomAgentHint": "接入任意兼容 ACP 的智能体。可从公开 ACP 注册表中选择,或直接粘贴其注册表信息。", - "customAgentFromRegistry": "ACP 注册表", - "customAgentManual": "手动填写", - "customAgentSearchPlaceholder": "搜索智能体…", - "customAgentLoadingCatalog": "正在加载 ACP 注册表…", - "customAgentRetry": "重试", - "customAgentNoResults": "没有匹配的智能体", - "customAgentAdd": "添加", - "customAgentAlreadyAdded": "已添加", - "customAgentUnsupportedPlatform": "当前平台没有可用的构建", - "customAgentAdded": "已添加 {name}", - "customAgentIdLabel": "注册表 ID", - "customAgentNameLabel": "显示名称", - "customAgentVersionLabel": "版本", - "customAgentSpecLabel": "分发信息(JSON)", - "customAgentSpecHint": "与 ACP 注册表 distribution 对象同构:支持 npx、uvx、binary 三种通道,也可整条粘贴注册表条目。npx/uvx 的 cmd 为包安装的可执行命令名,缺省按包名推导,与包名不同时需填写。binary 按平台键区分(本机为 {platform}),cmd 为压缩包内启动路径,sha256 可选用于校验下载。", - "customAgentTemplateLabel": "模板", - "customAgentKindLabel": "启动方式", - "customAgentInvalidJson": "不是合法的 JSON", - "customAgentNoDistribution": "未找到 npx、uvx 或 binary 分发方式", - "customAgentCancel": "取消", - "customAgentSave": "添加智能体", - "customAgentSaveChanges": "保存修改", - "customAgentEdit": "编辑智能体", - "customAgentEditHint": "修改名称、图标、分发信息与技能声明;智能体 ID 不可修改。", - "customAgentEditNotFound": "未找到自定义智能体 {id}", - "customAgentSaved": "已保存 {name}", - "customAgentVersionProbeLabel": "版本查询命令(可选)", - "customAgentVersionProbeHint": "查询本地安装版本的命令;留空时默认执行智能体命令加 --version。", - "customAgentRemove": "移除智能体", - "customAgentRemoveHint": "删除该智能体定义。已有会话的历史会保留,只是该智能体无法再启动。", - "customAgentIconLabel": "图标(可选)", - "customAgentIconUpload": "上传", - "customAgentIconReplace": "更换", - "customAgentIconClear": "移除图标", - "customAgentIconHint": "随智能体一起保存,离线也能显示。不上传则使用彩色首字母。", - "customAgentSkillsLabel": "Skills(共享 .agents/skills)", - "customAgentSkillsHint": "声明该智能体会读取共享的 .agents/skills 目录(全局与项目级),并将其加入所有技能矩阵。链接到共享目录的技能对读取该目录的其他智能体同样可见。", - "customAgentSkillsDirLabel": "专属技能目录", - "customAgentSkillsDirHint": "该智能体自身加载技能的目录绝对路径 —— 可与共享目录并存,也可单独使用。~ 会展开为主目录;链接技能时优先放入此目录。", - "customAgentMcpLabel": "MCP 支持", - "customAgentMcpHint": "会话建立时向该智能体注入 codeg 内置的 codeg-mcp 伴生进程 —— 委托、实时反馈与任务工具都依赖它。若该智能体不支持 MCP、连接时报错,请关闭此项;设置在下次连接时生效。", - "customAgentIconNotAnImage": "请选择图片文件。", - "customAgentIconTooLarge": "图标需小于 {limit} KB。", - "customAgentIconReadFailed": "无法读取该图片。", - "customAgentRemoveConfirm": "确定移除 {name}?已有会话会保留,但该智能体将无法再启动。", - "customAgentRemoveWithData": "同时删除已记录的会话历史", - "customAgentRemoved": "已移除 {name}", - "customAgentBadge": "自定义", - "customAgentNotLaunchable": "该智能体在此环境无法启动:{reason}" - }, - "SettingsPages": { - "agentsLoading": "加载 Agent 设置中...", - "skillPacksLoading": "正在加载技能包…" - }, - "GeneralSettings": { - "loading": "加载中...", - "sectionTitle": "常规", - "sectionDescription": "集中管理默认终端、渲染加速以及多智能体协同等通用偏好。", - "terminalTitle": "默认终端", - "terminalDescription": "选择从终端栏或文件树打开新终端标签页时使用的 Shell。智能体请求 codeg 代为执行整条命令行时也会使用它。", - "terminalSystemDefault": "系统默认", - "terminalPowerShell7": "PowerShell 7 (pwsh)", - "terminalWindowsPowerShell": "Windows PowerShell", - "terminalCmd": "命令提示符 (cmd)", - "terminalSaveFailed": "保存终端设置失败:{message}", - "terminalShellCustom": "自定义路径", - "terminalShellCustomPath": "Shell 路径", - "terminalShellCustomPlaceholder": "/usr/local/bin/fish", - "terminalShellCustomSave": "保存", - "terminalShellCustomHint": "支持绝对路径,或 PATH 中可解析的命令名。", - "terminalShellNotInstalled": "未安装", - "terminalShellNotFoundWarning": "当前主机上不存在此路径。", - "terminalCurrentShell": "当前使用:{path}", - "renderingDescription": "如果应用出现黑屏或渲染异常(常见于 AMD 显卡或部分 Intel 集成显卡),可关闭硬件加速。仅 Windows 桌面端生效。", - "disableHardwareAcceleration": "禁用硬件加速", - "renderingSaveFailed": "渲染设置保存失败:{message}", - "restartRequired": "已保存,重启应用后生效。", - "restartNow": "立即重启", - "restartFailed": "重启失败:{message}", - "loadFailed": "加载失败:{message}" - }, - "LoginPage": { - "documentTitle": "登录 - codeg", - "brand": "Codeg", - "subtitle": "输入访问 Token 以连接到桌面端", - "tokenPlaceholder": "Access Token", - "connect": "连接", - "connecting": "连接中...", - "helpText": "Token 可在桌面端 设置 → Web 服务 中获取", - "invalidToken": "Token 无效,请检查后重试", - "connectionFailed": "连接失败 (HTTP {status})", - "networkError": "无法连接到服务器" - }, - "CommitPage": { - "title": "提交代码", - "invalidFolderId": "无效的 folderId", - "loadingRepo": "正在加载仓库..." - }, - "MergePage": { - "title": "解决冲突", - "invalidFolderId": "无效的 folderId", - "loadingRepo": "正在加载仓库...", - "localVersion": "本地(我们的)", - "result": "结果", - "remoteVersion": "远程(他们的)", - "acceptLocal": "采用本地", - "acceptRemote": "采用远程", - "markResolved": "标记已解决", - "abortMerge": "中止", - "completeMerge": "完成合并", - "unresolvedConflicts": "文件中仍有未解决的冲突标记", - "fileResolved": "文件已解决", - "allResolved": "所有冲突已解决", - "conflictFiles": "冲突文件", - "loadingFile": "正在加载文件...", - "preparingMerge": "正在准备合并...", - "selectFile": "选择一个文件进行解决", - "noConflicts": "无冲突文件", - "skipFile": "跳过", - "abortSuccess": "操作已中止", - "applyAllNonConflicting": "应用所有非冲突变更", - "applyLeftNonConflicting": "应用本地", - "applyRightNonConflicting": "应用远程" - }, - "ImportSessions": { - "title": "导入本地会话", - "scanningTitle": "正在扫描本地智能体会话…", - "scanningHint": "正在遍历各智能体的本地会话存储,历史较多时可能需要一些时间。已导入的会话会顺带刷新。", - "scanFailed": "扫描失败", - "retry": "重试", - "rescan": "重新扫描", - "empty": "未发现本地会话", - "emptyHint": "本机未找到任何智能体的会话存储。", - "noMatches": "没有匹配当前筛选的会话", - "searchPlaceholder": "搜索标题或路径…", - "allAgents": "全部智能体", - "onlyImportable": "仅显示可导入", - "selectAll": "全选", - "clearSelection": "清空", - "expandAll": "全部展开", - "collapseAll": "全部折叠", - "summaryCounts": "共 {total} 个会话 · {importable} 个可导入 · {folders} 个文件夹", - "noFolderSkipped": "已跳过 {count} 个无项目目录的会话", - "folderNew": "新建", - "folderCounts": "可导入 {importable}/{total}", - "toggleFolderAria": "选择 {name} 中的全部可导入会话", - "toggleSessionAria": "选择会话 {title}", - "statusImported": "已导入", - "statusDeleted": "已删除", - "untitled": "未命名会话", - "messageCount": "{count} 条消息", - "selectedCount": "已选 {count} 个", - "importSelected": "导入所选", - "importing": "导入中…", - "close": "关闭", - "doneTitle": "导入完成", - "doneImported": "新导入", - "doneUpdated": "已刷新", - "doneSkipped": "已跳过", - "doneCreatedFolders": "新建文件夹", - "doneNotFound": "未找到", - "doneFailed": "失败", - "continueImport": "继续导入", - "toasts": { - "importFailed": "导入失败:{message}" - } - }, - "Folder": { - "workspaceStatus": { - "degradedTitle": "实时更新不可用", - "degradedHint": "监听器启动失败(如目录无读取权限)。请手动刷新以获取最新变更。", - "retry": "重试", - "retrying": "重试中..." - }, - "common": { - "all": "全部", - "cancel": "取消", - "close": "关闭", - "closeOthers": "关闭其它", - "closeAll": "关闭所有", - "confirm": "确认", - "save": "保存", - "delete": "删除", - "rename": "重命名", - "loading": "加载中...", - "refresh": "刷新", - "refreshing": "刷新中...", - "create": "创建", - "createAndSwitch": "创建并切换", - "openFile": "打开文件", - "viewDiff": "查看差异", - "push": "推送..." - }, - "statusLabels": { - "in_progress": "进行中", - "pending_review": "待复查", - "completed": "已完成", - "cancelled": "已取消" - }, - "sidebar": { - "title": "会话", - "locateActiveConversation": "定位当前会话", - "expandAllGroups": "展开全部分组", - "collapseAllGroups": "折叠全部分组", - "newConversation": "新建会话", - "newConversationShort": "新建", - "newChat": "新建会话", - "search": "搜索", - "noConversationsFound": "未找到会话。", - "importLocalSessions": "导入本地会话", - "importing": "导入中...", - "error": "错误:{message}", - "completeAllSessions": "完成全部会话", - "completeAllReviewTitle": "完成全部复查会话?", - "completeAllReviewDescription": "这会将复查中的 {count} 个会话全部标记为已完成。", - "completing": "处理中...", - "toasts": { - "importedSessions": "已导入 {imported} 个会话,跳过 {skipped} 个", - "importedAndUpdated": "已导入 {imported} 个会话,更新 {updated} 个标题,跳过 {skipped} 个", - "updatedTitles": "已更新 {updated} 个标题,跳过 {skipped} 个", - "noNewSessionsFound": "没有新会话(已跳过 {skipped} 个)", - "importFailed": "导入失败:{message}", - "reviewCompleted": "已将 {count} 个复查会话标记为已完成", - "completeReviewFailed": "批量完成复查会话失败:{message}", - "folderOpened": "已打开文件夹 {name}", - "folderRemoved": "已移除文件夹 {name}", - "openFolderFailed": "打开文件夹失败", - "removeFolderFailed": "移除文件夹失败:{message}", - "reorderFoldersFailed": "重新排序文件夹失败:{message}", - "changeFolderColorFailed": "修改颜色失败:{message}", - "setFolderAliasFailed": "设置别名失败:{message}", - "changeFolderDefaultAgentFailed": "设置默认智能体失败:{message}" - }, - "statsLabel": "{folders} 个文件夹 · {convos} 个会话", - "reorderHandle": "拖拽排序", - "openFolder": "打开文件夹", - "searchPlaceholder": "搜索会话...", - "viewOptions": "显示选项", - "showCompleted": "显示已完成会话", - "showWorktrees": "显示工作树文件夹", - "showRecent": "显示「最近」分组", - "moreOptions": "更多选项", - "sortBy": "排序方式", - "sortByCreatedAt": "按创建时间排序", - "sortByUpdatedAt": "按更新时间排序", - "sectionOrder": "区域顺序", - "sectionOrderMoveUp": "上移", - "sectionOrderMoveDown": "下移", - "sectionOrderItemLabel": "{name} — 第 {position} 位,共 {total} 位", - "statusRunningBadge": "运行中", - "runningCountBadge": "{count} 个会话进行中", - "statusCancelledBadge": "已取消", - "worktreeRemovedBadge": "源 worktree 已删除", - "conversationCountUnit": "{count} 条", - "emptyFolderHint": "暂无会话", - "noMatchingConversations": "未找到匹配的会话", - "noUnfinishedConversations": "当前暂无未完成会话,右上角可启用显示已完成会话", - "removeFolderConfirmTitle": "从工作区移除该文件夹?", - "removeFolderConfirmDescription": "从工作区移除 \"{name}\"?其相关 Tab 与终端将会关闭。", - "folderHeaderMenu": { - "manageConversations": "会话管理…", - "manageLinks": "关联的文件夹", - "changeColor": "修改颜色", - "useThemeColor": "使用设置主题", - "setDefaultAgent": "设置默认智能体", - "defaultAgentNone": "不设置(使用全局默认)", - "agentUnavailableSuffix": "(不可用)", - "loadingAgents": "正在加载代理…", - "setAlias": "设置别名…", - "setAliasTitle": "设置文件夹别名", - "setAliasPlaceholder": "输入别名(留空清除)", - "setAliasSave": "保存", - "setAliasCancel": "取消", - "removeFromWorkspace": "从工作区移除" - }, - "manageConversations": { - "title": "会话管理", - "searchPlaceholder": "按标题搜索…", - "agentFilterAll": "全部智能体", - "statusFilterAll": "全部状态", - "folderFilterAll": "全部文件夹", - "branchFilterAll": "全部分支", - "branchNone": "无分支", - "branchSearchPlaceholder": "搜索分支…", - "noMatchingBranches": "无匹配分支", - "selectAllVisible": "全选", - "deselectAll": "取消全选", - "selectedCount": "已选 {count} 条", - "matchedCount": "匹配 {count} 条", - "untitledConversation": "未命名会话", - "setStatus": "设为状态…", - "deleteSelected": "删除", - "noConversations": "此文件夹暂无会话。", - "noConversationsWorkspace": "工作区暂无会话。", - "noMatchingConversations": "没有匹配过滤条件的会话。", - "confirmDeleteTitle": "删除 {count} 个会话?", - "confirmDeleteDescription": "此操作不可撤销。", - "toastDeleted": "已删除 {count} 个会话", - "toastStatusUpdated": "已更新 {count} 个会话的状态", - "toastOpFailed": "操作失败:{message}" - }, - "sectionPinned": "已置顶", - "sectionFolders": "文件夹", - "sectionChats": "聊天", - "sectionRecent": "最近", - "noChats": "没有聊天", - "noRecent": "暂无最近会话", - "showMoreRecent": "显示更多({count})", - "noFolders": "没有打开的文件夹", - "newChatAction": "新建聊天", - "automations": "自动化", - "tasks": "待办任务", - "loadingSubsessions": "正在加载子会话…" - }, - "conversation": { - "reloadFailed": "会话重新加载失败:{message}", - "reloaded": "当前会话已重新加载", - "reload": "重新加载", - "activeConversationIndicator": "当前激活会话", - "newConversation": "新建会话", - "closeConversation": "关闭会话", - "copyText": "复制文本", - "copyTextSuccess": "已复制", - "copyTextFailed": "复制失败", - "forkSession": "分叉会话", - "forkSessionSuccess": "会话分叉成功", - "forkSessionFailed": "会话分叉失败:{error}", - "exportConversation": "导出会话", - "exportImage": "图片", - "exportMarkdown": "Markdown", - "exportHtml": "HTML", - "exportSuccess": "会话已导出", - "exportFailed": "导出失败", - "exportImageTooLong": "会话内容过长,不支持导出为图片", - "exportLabels": { - "untitledConversation": "未命名会话", - "agent": "代理", - "model": "模型", - "status": "状态", - "started": "开始时间", - "updated": "更新时间", - "tokens": "令牌统计", - "duration": "时长", - "inputTokens": "输入", - "outputTokens": "输出", - "cacheRead": "缓存读取", - "cacheWrite": "缓存写入", - "user": "用户", - "assistant": "助手", - "system": "系统", - "toolResult": "结果", - "toolError": "错误" - }, - "moreActions": "更多操作" - }, - "sessionDetails": { - "menuLabel": "会话详情", - "noActiveSession": "暂无活动会话", - "title": "会话详情", - "subtitle": "会话元信息与 Token 用量", - "fieldTitle": "标题", - "untitled": "未命名会话", - "sessionId": "会话 ID", - "externalId": "扩展 ID", - "agent": "智能体", - "model": "模型", - "status": "状态", - "gitBranch": "Git 分支", - "parentId": "父会话", - "tokensHeading": "Token 用量", - "totalTokens": "总计", - "inputTokens": "输入", - "outputTokens": "输出", - "cacheWrite": "缓存写入", - "cacheRead": "缓存读取", - "contextWindow": "上下文窗口", - "duration": "时长", - "loadingStats": "正在加载 Token 用量…", - "loadFailed": "加载 Token 用量失败", - "noStats": "暂无用量记录", - "timestampsHeading": "时间", - "createdAt": "创建时间", - "updatedAt": "更新时间", - "none": "—", - "copyField": "复制{field}", - "copiedField": "已复制{field}" - }, - "conversationCard": { - "untitledConversation": "未命名会话", - "newConversation": "新建会话", - "rename": "重命名", - "status": "状态", - "delete": "删除", - "importLocalSessions": "导入本地会话", - "importing": "导入中...", - "renameConversation": "重命名会话", - "deleteConversationTitle": "删除会话?", - "deleteConversationDescription": "会删除“{title}”,此操作不可撤销。", - "cancel": "取消", - "save": "保存", - "pin": "置顶", - "unpin": "取消置顶", - "markCompleted": "标记为已完成", - "reopen": "重新打开", - "expandSubsessions": "展开子会话", - "collapseSubsessions": "折叠子会话" - }, - "search": { - "dialogTitle": "搜索", - "dialogTitleWithFolder": "搜索 — {name}", - "tabConversations": "会话", - "tabFiles": "文件", - "placeholder": "搜索会话...", - "filePlaceholder": "搜索文件或目录...", - "allAgents": "全部", - "searching": "搜索中...", - "typeToSearch": "输入关键词搜索会话", - "typeToSearchFiles": "输入关键词搜索文件或目录", - "noResults": "未找到结果。", - "untitledConversation": "未命名会话" - }, - "folderTitleBar": { - "showSidebar": "显示侧边栏", - "hideSidebar": "隐藏侧边栏", - "toggleTerminal": "切换终端", - "toggleAuxPanel": "切换辅助面板", - "search": "搜索", - "openSettings": "打开设置", - "backToConversations": "返回会话", - "withShortcut": "{label}({shortcut})" - }, - "statusBar": { - "connection": { - "connected": "已连接", - "connecting": "连接中...", - "prompting": "响应中...", - "error": "连接异常", - "disconnected": "未连接", - "tooltip": "{agent}:{status}", - "tooltipError": "{agent}:{error}", - "title": "智能体连接", - "triggerAria": "智能体连接:{status}", - "workingDir": "工作目录", - "sessionId": "会话 ID", - "viewerNote": "已接入其他客户端拥有的会话——重连只会重新接入当前视图。", - "reconnectInterrupts": "重连会重启智能体,并中断正在进行的工作。", - "reconnect": "重新连接", - "reconnecting": "正在重新连接...", - "reconnectUnavailable": "暂无可重连的会话。" - }, - "tasks": { - "title": "任务" - }, - "alerts": { - "title": "告警", - "empty": "暂无告警信息", - "details": "详情" - }, - "stats": { - "conversations": "{count} 个会话", - "openUsage": "查看会话统计与 Token 用量" - }, - "tokens": { - "contextWindowUsageAria": "上下文窗口使用率", - "contextWindow": "上下文窗口", - "usedMax": "已用 / 上限", - "tokenUsage": "Token 用量", - "input": "输入", - "output": "输出", - "cacheRead": "缓存读取", - "cacheWrite": "缓存写入", - "total": "总计" - } - }, - "auxPanel": { - "tabs": { - "files": "文件", - "changes": "变更", - "commits": "提交" - }, - "noFolderTitle": "暂无打开的文件夹", - "noFolderHint": "打开一个文件夹后在这里查看" - }, - "windowControls": { - "minimizeWindow": "最小化窗口", - "minimize": "最小化", - "maximizeWindow": "最大化窗口", - "maximize": "最大化", - "restoreWindow": "还原窗口", - "restore": "还原", - "closeWindow": "关闭窗口", - "close": "关闭" - }, - "tabs": { - "closeConversationTab": "关闭会话标签", - "close": "关闭", - "closeOthers": "关闭其它", - "splitRight": "向右拆分", - "splitDown": "向下拆分", - "splitAndMoveRight": "拆分并右移", - "splitAndMoveDown": "拆分并下移", - "moveToOppositeGroup": "移动到对侧分组", - "moveToGroup": "移动到分组", - "groupLabel": "分组 {index}", - "changeSplitterOrientation": "切换分隔方向", - "unsplit": "取消拆分", - "unsplitAll": "全部取消拆分", - "closeAll": "关闭所有", - "tileDisplay": "平铺显示", - "untileDisplay": "取消平铺" - }, - "fileWorkspace": { - "files": "文件", - "closeFileTab": "关闭文件标签", - "close": "关闭", - "closeOthers": "关闭其它", - "closeAll": "关闭所有", - "preview": "预览", - "editSource": "编辑源码", - "maximize": "最大化", - "restore": "还原", - "emptyDirectory": "空目录" - }, - "terminal": { - "rename": "重命名", - "close": "关闭", - "closeOthers": "关闭其它", - "closeAll": "关闭所有", - "hideTerminal": "隐藏终端({shortcut})", - "openFolderFirst": "请先打开一个文件夹" - }, - "workspaceDialog": { - "title": "打开文件夹", - "manageTitle": "关联的文件夹", - "addTargetsTitle": "添加要关联的文件夹", - "pickRootDescription": "选择该工作空间的主文件夹。", - "linksDescription": "把其它文件夹以子目录的形式关联进来,智能体就能在同一个工作空间里跨项目工作。", - "addTargetsDescription": "选择一个或多个文件夹,每个都会成为工作空间的一个子目录。", - "useSystemPicker": "系统选择器", - "next": "下一步", - "back": "返回", - "done": "完成", - "change": "更改", - "addFolders": "添加文件夹", - "addSelected": "添加", - "addSelectedCount": "添加 {count} 个", - "createCount": "关联 {count} 个文件夹", - "discardPending": "放弃", - "noLinks": "还没有关联任何文件夹。", - "gitExclude": "不让关联目录污染 git 状态", - "rename": "重命名", - "unlink": "解除关联", - "repair": "重建链接", - "saveName": "保存", - "cancelRename": "取消", - "removePending": "移除", - "willAppearAs": "在工作空间中显示为 {name}", - "renamedForDuplicate": "已改名 —— {base} 已被另一个关联占用", - "renamedForExistingEntry": "已改名 —— 该文件夹中已存在 {base}", - "partiallyCreated": "只成功关联了 {count} 个文件夹", - "openFailed": "打开文件夹失败", - "previewFailed": "检查所选文件夹失败", - "createFailed": "关联文件夹失败", - "renameFailed": "重命名失败", - "removeFailed": "解除关联失败", - "repairFailed": "重建链接失败", - "status": { - "ok": "已关联", - "missing": "链接已从该文件夹中消失", - "conflicted": "该名称已被其它条目占用", - "broken": "被关联的文件夹已不存在" - }, - "nameIssue": { - "empty": "请输入名称", - "illegalChars": "不能包含 / \\ : * ? \" < > |", - "tooLong": "名称过长", - "reserved": "该名称是 Windows 保留名", - "duplicate": "该名称已被使用" - }, - "rejection": { - "not_found": "找不到该文件夹", - "not_a_directory": "该路径不是文件夹", - "same_as_root": "这就是工作空间文件夹本身", - "ancestor_of_root": "该文件夹包含了当前工作空间", - "inside_root": "已在工作空间内部", - "already_linked": "已经关联过", - "name_unavailable": "该文件夹已无可用的名称", - "alreadyLinkedAs": "已作为 {name} 关联" - } - }, - "folderNameDropdown": { - "fallbackFolderName": "文件夹", - "openFolder": "打开文件夹", - "cloneRepository": "克隆仓库", - "projectBoot": "项目启动器", - "opened": "已打开", - "recentOpen": "最近打开" - }, - "fileWorkspacePanel": { - "addSelectionToChat": "添加选区到会话", - "addToChat": "加入会话", - "addSelectionToChatDone": "已将 {label} 加入会话", - "addFileToChat": "添加文件到会话", - "toggleWordWrap": "切换自动换行", - "addFileToChatDone": "已将 {label} 加入会话", - "viewDiff": "查看差异", - "openFile": "打开文件", - "fileCount": "{count} 个文件", - "openFileOrDiff": "从右侧面板打开文件或差异", - "disk": "磁盘", - "head": "HEAD(当前提交)", - "unsaved": "未保存", - "workingTree": "工作区", - "loading": "加载中...", - "compareWithBranch": "{path} · 与 {branch} 比较", - "hunkCount": "{count} 个区块", - "prev": "上一个", - "next": "下一个", - "jumpToLine": "跳转到第 {line} 行", - "noParsedDiffSections": "未解析到差异区块", - "loadingEditor": "编辑器加载中...", - "imageZoomIn": "放大", - "imageZoomOut": "缩小", - "imageZoomReset": "重置缩放", - "htmlPreviewTitle": "HTML 预览", - "htmlPreviewTrust": "运行脚本", - "htmlPreviewTrustHint": "运行此文件的脚本并允许网络访问。仅对可信任的文件启用。", - "officePreviewTitle": "办公文档预览", - "officeFullRender": "完整渲染", - "officeFullRenderHint": "渲染 Morph 动画、3D 和公式(会运行幻灯片自带的脚本)", - "officeNotInstalled": "未安装 OfficeCLI", - "officeNotInstalledHint": "在 设置 → 办公工具 中安装 OfficeCLI,即可预览 Word、Excel 和 PowerPoint 文件。", - "officeOpenSettings": "打开设置", - "officeWatchFailed": "无法启动实时预览", - "officeWatchRetry": "重试", - "officeServerInstallHint": "OfficeCLI 需安装在服务器主机上。请在服务器上运行以下命令后重试:", - "officeRemoteDesktopUnsupported": "远程桌面窗口暂不支持实时预览。请在服务器的 Web 界面中打开此工作区来预览 Office 文件。" - }, - "branchDropdown": { - "toasts": { - "commitCodeCompleted": "提交代码完成", - "pushCodeCompleted": "推送代码完成", - "committedFiles": "已提交 {count} 个文件", - "taskCompleted": "{label} 完成", - "taskFailed": "{label} 失败", - "mergeNoNewCommits": "{branchName} 没有新的提交", - "mergedCommits": "已合并 {count} 个提交", - "allFilesUpToDate": "所有文件均为最新版本", - "updatedFiles": "已更新 {count} 个文件", - "openCommitWindowFailed": "打开提交窗口失败", - "openPushWindowFailed": "打开推送窗口失败", - "upstreamSet": "已设置远程跟踪分支", - "upstreamSetAndPushed": "已设置远程跟踪分支并推送 {count} 个提交", - "noCommitsToPush": "没有可推送的提交", - "pushedCommits": "已推送 {count} 个提交", - "switchedToFolder": "已切换到 {name}", - "switchFailed": "切换分支失败", - "openStashWindowFailed": "打开贮藏窗口失败" - }, - "tasks": { - "newBranch": "新建分支 {name}", - "newWorktree": "新建工作树 {name}", - "checkoutTo": "切换到 {branchName}", - "mergeBranch": "合并 {branchName}", - "rebaseTo": "变基到 {branchName}", - "deleteRemoteBranch": "删除远程分支 {branchName}", - "initGitRepo": "初始化 Git 仓库", - "pullCode": "更新代码", - "fetchInfo": "获取信息", - "pushCode": "推送代码", - "stashChanges": "贮藏更改", - "stashPop": "取消贮藏", - "deleteBranch": "删除分支 {branchName}", - "removeWorktree": "删除 {branchName} 的工作树", - "removeWorktreeAndBranch": "删除工作树及分支 {branchName}", - "updateBranch": "更新分支 {branchName}" - }, - "confirm": { - "mergeTitle": "合并分支", - "rebaseTitle": "变基分支", - "mergeDescription": "确定将 {branchName} 合并到当前分支 {currentBranch} 吗?", - "rebaseDescription": "确定将当前分支 {currentBranch} 变基到 {branchName} 吗?", - "deleteRemoteTitle": "删除远程分支", - "deleteRemoteDescription": "确定删除远程分支 {branchName} 吗?此操作将从远程仓库中移除该分支,且不可恢复。", - "deleteTitle": "删除分支", - "deleteDescription": "确定删除分支 {branchName} 吗?此操作不可恢复。", - "forceDeleteTitle": "强制删除分支", - "forceDeleteDescription": "分支 {branchName} 尚未完全合并,确定要强制删除吗?此操作不可恢复。", - "deleteWorktreeTitle": "删除工作树", - "deleteWorktreeDescription": "删除检出了 {branchName} 的工作树目录?分支及其提交会保留。", - "forceDeleteWorktreeTitle": "强制删除工作树", - "forceDeleteWorktreeDescription": "{branchName} 的工作树中有未提交或未跟踪的文件。仍要删除吗?这些改动将无法恢复。", - "deleteWorktreeAndBranchTitle": "删除工作树及分支", - "deleteWorktreeAndBranchDescription": "删除 {branchName} 的工作树、该分支本身及其工作区文件夹?其中的会话会移动到仓库文件夹下。此操作无法撤销。", - "forceDeleteWorktreeAndBranchTitle": "强制删除工作树及分支", - "forceDeleteWorktreeAndBranchDescription": "{branchName} 的工作树中有未提交的文件,或该分支尚未完全合并。仍要一并删除吗?此操作无法撤销。" - }, - "current": "当前", - "switchToBranch": "切换到此分支", - "mergeBranchIntoCurrent": "将 {branchName} 合并到 {currentBranch}", - "rebaseCurrentToBranch": "将 {currentBranch} 变基到 {branchName}", - "noBranch": "无分支", - "detachedHead": "游离 HEAD({sha})", - "initGitRepo": "初始化 Git 仓库", - "pullCode": "更新代码", - "fetchRemoteBranches": "提取远程分支", - "openCommitWindow": "提交代码...", - "pushCode": "推送...", - "pushBranch": "推送", - "newBranch": "新建分支...", - "newWorktree": "新建工作树...", - "stashChanges": "贮藏更改...", - "stashPop": "取消贮藏...", - "manageRemotes": "管理远程...", - "localBranches": "本地分支 ({count})", - "noLocalBranches": "无本地分支", - "remoteBranches": "远程分支 ({count})", - "noRemoteBranches": "无远程分支", - "dialogs": { - "newBranchTitle": "新建分支", - "newBranchDescription": "从当前分支 {branch} 创建新分支", - "branchNamePlaceholder": "分支名称", - "newWorktreeTitle": "新建工作树", - "newWorktreeDescription": "从当前分支 {branch} 创建新的工作树", - "branchNameLabel": "分支名称", - "worktreePathLabel": "工作树路径", - "worktreePathPlaceholder": "工作树路径", - "manageRemotesTitle": "管理远程", - "manageRemotesEmpty": "未配置远程仓库", - "remoteNamePlaceholder": "远程名称", - "remoteUrlPlaceholder": "远程 URL", - "addRemote": "添加", - "savingRemotes": "保存中..." - }, - "conflict": { - "title": "合并冲突", - "description": "以下文件存在冲突,需要手动解决:", - "abort": "中止合并", - "openMergeTool": "打开合并工具", - "completeMerge": "完成合并", - "abortSuccess": "合并已中止", - "completeSuccess": "合并完成" - }, - "stashDialog": { - "title": "贮藏更改", - "description": "将当前更改保存到贮藏区", - "messageLabel": "消息", - "messagePlaceholder": "贮藏消息(可选)", - "keepIndex": "保留暂存区(已暂存的更改保持不变)", - "cancel": "取消", - "stash": "贮藏", - "success": "更改已贮藏", - "error": "贮藏更改失败" - }, - "unstashDialog": { - "title": "取消贮藏", - "noStashes": "没有贮藏记录", - "selectFile": "选择文件查看差异", - "viewDiff": "查看差异", - "original": "原始", - "modified": "修改后", - "apply": "应用", - "drop": "删除", - "applySuccess": "贮藏已应用", - "dropSuccess": "贮藏已删除", - "confirmApply": "将贮藏 {ref} 应用到工作目录?", - "cancel": "取消" - }, - "deleteBranch": "删除分支", - "deleteWorktree": "删除工作树", - "deleteWorktreeAndBranch": "删除工作树及分支", - "searchPlaceholder": "搜索分支和操作", - "searchAriaLabel": "搜索分支和操作", - "branchListLabel": "分支和操作", - "noMatches": "无匹配项" - }, - "commitDialog": { - "toasts": { - "commitCompleted": "提交代码完成", - "pushFailed": "推送失败", - "committedFiles": "已提交 {count} 个文件", - "addedToVcs": "已添加到 VCS", - "addToVcsFailed": "添加到 VCS 失败", - "fileDeleted": "文件已删除", - "deleteFailed": "删除失败", - "fileRolledBack": "文件已回滚", - "rollbackFailed": "回滚失败", - "dirRolledBack": "目录已回滚", - "dirDeleted": "目录已删除" - }, - "confirm": { - "deleteTitle": "确认删除", - "deleteDescription": "确定要删除文件「{file}」吗?此操作不可恢复。", - "rollbackTitle": "确认回滚", - "rollbackDescription": "确定要回滚文件「{file}」到 HEAD 版本吗?未保存的修改将丢失。", - "rollbackDirDescription": "确定要回滚目录「{dir}」到 HEAD 版本吗?未保存的修改将丢失。", - "deleteDirDescription": "确定要删除目录「{dir}」吗?此操作不可恢复。" - }, - "actions": { - "select": "选择", - "unselect": "取消选择", - "rollback": "回滚", - "addToVcs": "添加到 VCS" - }, - "aria": { - "selectFile": "{action}:{path}", - "unselectAllFiles": "取消选择全部文件", - "selectAllFiles": "选择全部文件", - "unselectTracked": "取消选择已跟踪改动", - "selectTracked": "选择已跟踪改动", - "unselectUntracked": "取消选择未跟踪文件", - "selectUntracked": "选择未跟踪文件" - }, - "loading": "加载中...", - "selectionCount": "{selected} / {total} 个文件", - "emptyFiles": "没有改动的文件", - "trackedChanges": "已跟踪改动 ({count})", - "untrackedFiles": "未跟踪文件 ({count})", - "commitMessage": "提交消息", - "commitMessagePlaceholder": "输入提交信息...", - "commitButton": "提交 ({count})", - "commitAndPushButton": "提交并推送 ({count})", - "head": "HEAD(当前提交)", - "workingTree": "工作区", - "clickFileToDiff": "点击文件名查看差异", - "loadingDiff": "加载差异..." - }, - "pushWindow": { - "title": "推送代码", - "noUnpushedCommits": "没有未推送的提交", - "noRemoteConfigured": "未配置 Git 远程仓库\n请在「管理远程」中添加远程地址", - "newBranchNoPushedCommits": "新分支 — 推送以创建远程跟踪分支", - "unpushed": "未推送", - "selectFileToViewDiff": "选择文件查看差异", - "before": "修改前", - "after": "修改后", - "push": "推送", - "toasts": { - "pushSuccess": "推送成功", - "pushFailed": "推送失败", - "upstreamSet": "已设置远程跟踪分支", - "upstreamSetAndPushed": "已设置远程跟踪分支并推送 {count} 个提交", - "noCommitsToPush": "没有可推送的提交", - "pushedCommits": "已推送 {count} 个提交" - } - }, - "gitLogTab": { - "filesTitle": "文件", - "expandAllFiles": "展开全部文件", - "collapseAllFiles": "折叠全部文件", - "workspace": "工作区", - "retry": "重试", - "noCommitsFound": "未找到提交记录", - "notAGitRepoTitle": "不是 Git 仓库", - "notAGitRepoHint": "可从上方分支菜单初始化 Git,或打开已有的 Git 仓库。", - "hash": "Hash", - "copyHash": "复制哈希", - "copyMessage": "复制提交消息", - "showMore": "展开", - "showLess": "收起", - "author": "作者", - "noFileChangeDetails": "暂无文件变更详情。", - "loadingFiles": "正在加载文件…", - "branchesTitle": "分支", - "loadingBranches": "正在加载分支...", - "noContainingBranches": "未找到包含此提交的分支。", - "newBranch": "新建分支...", - "resetToHere": "重置到此处", - "resetDisabledReasonNotCurrentBranchView": "仅在查看当前分支时可用", - "copyFullCommitHashAria": "复制完整提交哈希 {hash}", - "pushStatus": { - "pushed": "已推送到远程", - "notPushed": "未推送到远程", - "unknown": "推送状态未知(未配置上游分支)" - }, - "time": { - "monthsAgo": "{count} 个月前", - "daysAgo": "{count} 天前", - "hoursAgo": "{count} 小时前", - "minsAgo": "{count} 分钟前", - "justNow": "刚刚" - }, - "toasts": { - "createdAndSwitchedNewBranch": "已创建并切换到新分支", - "newBranchFromCommit": "{name}(来自 {shortHash})", - "createBranchFailed": "新建分支失败", - "openPushWindowFailed": "打开推送窗口失败", - "resetSuccess": "重置成功", - "resetSuccessDescription": "已将 {branch} 以 {mode} 重置到 {shortHash}", - "resetFailed": "重置失败" - }, - "authorFilter": { - "label": "作者", - "searchPlaceholder": "搜索作者", - "noAuthors": "未找到作者", - "you": "你", - "filterByAuthorAria": "按作者筛选提交", - "filterByQuery": "按“{query}”过滤", - "clearAuthorFilterAria": "清除作者过滤", - "recent": "最近", - "matchingAuthors": "匹配的作者", - "removeFromRecent": "从最近列表移除 {name}" - }, - "branchSelector": { - "label": "分支", - "head": "HEAD", - "headHint": "跟随当前分支", - "headHintWithBranch": "跟随当前分支({branch})", - "searchBranch": "搜索分支...", - "noBranches": "无分支", - "selectBranchPlaceholder": "选择分支...", - "localBranches": "本地分支", - "current": "当前", - "remoteBranches": "远程分支", - "refreshCommitHistory": "刷新提交记录", - "clearBranchFilterAria": "清除分支过滤" - }, - "dialogs": { - "newBranchTitle": "新建分支", - "newBranchDescription": "以提交 {shortHash} 作为最后提交创建新分支。", - "branchNamePlaceholder": "分支名称", - "reset": { - "title": "将当前分支重置到此提交", - "branchLabel": "分支", - "targetLabel": "目标提交", - "messageLabel": "提交信息", - "modeLabel": "重置模式", - "confirmButton": "重置", - "modes": { - "soft": { - "label": "--soft", - "description": "将 HEAD 和当前分支指针移动到目标提交。\n暂存区(Index)和工作区(Working Tree)保持不变。\n被回退提交对应的改动会保留为“已暂存”状态。" - }, - "mixed": { - "label": "--mixed(默认)", - "description": "将 HEAD 移动到目标提交。\n把暂存区重置为目标提交状态,但保留工作区改动。\n这些改动会从“已暂存”变为“未暂存”。" - }, - "hard": { - "label": "--hard", - "description": "将 HEAD、暂存区和工作区全部重置到目标提交。\n目标提交之后的本地已跟踪改动会被直接丢弃。\n这是破坏性操作。" - }, - "keep": { - "label": "--keep", - "description": "将 HEAD 移动到目标提交,并尽量保留本地改动。\n仅当本地改动与目标提交不冲突时才会保留。\n若存在冲突,操作会中止以避免覆盖你的修改。" - } - } - } - }, - "moreActions": "更多 Git 操作" - }, - "gitChangesTab": { - "workspace": "工作区", - "noChanges": "暂无本地改动", - "notAGitRepoTitle": "不是 Git 仓库", - "notAGitRepoHint": "可从上方分支菜单初始化 Git,或打开已有的 Git 仓库。", - "trackedChanges": "本地已跟踪改动 ({count})", - "untrackedFiles": "本地未跟踪文件 ({count})", - "expandTracked": "展开已跟踪改动", - "collapseTracked": "折叠已跟踪改动", - "expandUntracked": "展开未跟踪文件", - "collapseUntracked": "折叠未跟踪文件", - "showRemainingItems": "显示其余 {count} 项", - "actions": { - "commitCode": "提交代码", - "rollback": "回滚", - "addToVcs": "添加到 VCS", - "delete": "删除", - "moreActions": "更多 Git 操作", - "addAllToVcs": "全部添加到 VCS", - "rollbackAll": "全部回滚", - "refresh": "刷新" - }, - "toasts": { - "noAddableFilesInDir": "该目录下没有可添加到 VCS 的变更文件", - "noRollbackFilesInDir": "该目录下没有可回滚的变更文件", - "addedToVcs": "已添加 {name} 到 VCS", - "addToVcsFailed": "添加到 VCS 失败", - "openCommitWindowFailed": "打开提交窗口失败", - "rolledBack": "已回滚 {name}", - "rollbackFailed": "回滚失败", - "addedFilesToVcs": "已添加 {count} 个文件到 VCS", - "rolledBackFiles": "已回滚 {count} 个文件", - "deleted": "已删除 {name}", - "deleteFailed": "删除失败", - "deletedFiles": "已删除 {count} 个文件", - "noDeletableFilesInDir": "该目录下没有可删除的变更文件", - "commitFailed": "提交失败" - }, - "directoryDialog": { - "descriptionAdd": "选择目录 {path} 下要添加到 VCS 的文件。", - "descriptionRollback": "选择目录 {path} 下要回滚的文件。", - "descriptionDelete": "选择目录 {path} 下要删除的文件。此操作不可撤销。", - "descriptionFallback": "选择要操作的文件。", - "selectionCount": "已选择 {selected} / {total} 个文件", - "selectAll": "全选", - "unselectAll": "取消全选", - "loadingCandidates": "正在加载目录变更...", - "noOperableFiles": "没有可操作的文件" - }, - "rollbackConfirm": { - "title": "确认回滚", - "descriptionWithTarget": "确定回滚{kind}「{name}」的本地修改吗?", - "descriptionFallback": "确定回滚本地修改吗?", - "kindDirectory": "目录", - "kindFile": "文件" - }, - "deleteConfirm": { - "title": "确认删除", - "descriptionWithTarget": "确定删除{kind}「{name}」吗?此操作不可撤销。", - "descriptionFallback": "确定删除吗?此操作不可撤销。", - "kindDirectory": "目录", - "kindFile": "文件" - }, - "quickCommit": { - "placeholder": "提交信息(回车提交)" - } - }, - "tabContext": { - "loadingConversation": "加载中...", - "untitledConversation": "未命名会话", - "newConversation": "新建会话" - }, - "fileTreeTab": { - "workspace": "工作区", - "retry": "重试", - "git": "Git", - "openInFileManager": "在文件管理器打开", - "openInFinder": "在访达打开", - "openInExplorer": "在资源管理器打开", - "attachToCurrentSession": "添加到会话", - "compareWithBranch": "与分支比较...", - "reloadFromDisk": "从磁盘重新加载", - "new": "新建", - "newFile": "文件", - "newDirectory": "目录", - "openIn": "打开于", - "openInTerminal": "在终端打开", - "linkedFolder": "关联的文件夹", - "copyPath": "复制路径", - "upload": "上传文件/目录", - "download": "下载文件", - "downloadAsZip": "下载为 ZIP", - "actions": { - "select": "选择", - "unselect": "取消选择", - "commitCode": "提交代码", - "rollback": "回滚", - "addToVcs": "添加到 VCS" - }, - "aria": { - "selectPath": "{action}:{path}" - }, - "toasts": { - "openDirectoryFailed": "打开目录失败", - "openBuiltinTerminalFailed": "无法打开内置终端", - "openCommitWindowFailed": "打开提交窗口失败", - "noAddableFilesInDir": "该目录下没有可添加到 VCS 的变更文件", - "noRollbackFilesInDir": "该目录下没有可回滚的变更文件", - "addedToVcs": "已添加 {name} 到 VCS", - "addToVcsFailed": "添加到 VCS 失败", - "loadBranchesFailed": "加载分支失败", - "renameFailed": "重命名失败", - "moveFailed": "移动失败", - "deleteFailed": "删除失败", - "rolledBack": "已回滚 {name}", - "rollbackFailed": "回滚失败", - "addedFilesToVcs": "已添加 {count} 个文件到 VCS", - "rolledBackFiles": "已回滚 {count} 个文件", - "savedAsCopy": "已另存为副本", - "saveCopyFailed": "另存为副本失败", - "watchStartFailed": "文件监听启动失败", - "createFailed": "创建失败", - "downloadFailed": "下载 {name} 失败", - "downloadSaved": "已下载 {name}", - "pathCopied": "已复制路径", - "copyPathFailed": "复制路径失败" - }, - "createDialog": { - "newFile": "新建文件", - "newDirectory": "新建目录", - "description": "输入新{kind}的名称。", - "placeholderFile": "文件名.ext", - "placeholderDirectory": "文件夹名" - }, - "renameDialog": { - "renameDirectory": "重命名目录", - "renameFile": "重命名文件", - "description": "输入新的名称(仅名称,不含路径)。", - "placeholderDirectory": "新建文件夹名称", - "placeholderFile": "新建文件名称.ext" - }, - "uploadDialog": { - "title": "上传到工作区", - "description": "可以在下方修改上传目录,然后添加文件或文件夹。", - "workspaceRoot": "工作区根目录", - "targetPathLabel": "上传到", - "targetPathHint": "实际目录:{path}", - "dropHint": "拖拽文件或文件夹到此处,或使用下方按钮", - "dropHintActive": "释放鼠标以加入上传队列", - "selectFiles": "选择文件", - "selectFolder": "选择文件夹", - "startUpload": "开始上传", - "clearQueue": "清除已完成", - "removeItem": "从队列移除", - "retry": "重试", - "dropZoneAria": "拖放文件到此处,或按回车键浏览", - "folderEmpty": "拖入的文件夹中没有可上传的文件", - "summary": "总数:{total} · 成功:{succeeded} · 失败:{failed}", - "status": { - "pending": "等待中", - "uploading": "上传中", - "success": "完成", - "error": "失败", - "cancelled": "已取消" - } - }, - "directoryDialog": { - "descriptionAdd": "选择目录 {path} 下要添加到 VCS 的文件。", - "descriptionRollback": "选择目录 {path} 下要回滚的文件。", - "descriptionFallback": "选择要操作的文件。", - "selectionCount": "已选择 {selected} / {total} 个文件", - "selectAll": "全选", - "unselectAll": "取消全选", - "loadingCandidates": "正在加载目录变更...", - "noOperableFiles": "没有可操作的文件" - }, - "compareDialog": { - "title": "与分支比较", - "descriptionWithTarget": "选择分支并与{kind} {path} 对比", - "descriptionFallback": "选择要比较的分支。", - "kindDirectory": "目录", - "kindFile": "文件", - "filterPlaceholder": "过滤分支,例如 main / origin/main", - "singleClickHint": "单击分支即可直接比较", - "loadingBranches": "正在加载分支...", - "recentBranches": "最近分支 ({count})", - "noCurrentBranch": "无当前分支", - "localBranches": "本地分支 ({count})", - "remoteBranches": "远程分支 ({count})", - "noMatchingBranches": "无匹配分支" - }, - "externalConflictDialog": { - "title": "检测到外部文件变更", - "descriptionWithPath": "文件 {path} 在磁盘已发生变化,当前编辑内容尚未保存。", - "descriptionFallback": "当前文件在磁盘已发生变化,当前编辑内容尚未保存。", - "compare": "对比", - "savingCopy": "另存中...", - "saveAsCopy": "另存为副本", - "reload": "重载" - }, - "deleteConfirm": { - "title": "确认删除", - "descriptionWithTarget": "确定删除{kind} \"{name}\" 吗?此操作不可撤销。", - "descriptionFallback": "此操作不可撤销。", - "kindDirectory": "目录", - "kindFile": "文件" - }, - "rollbackConfirm": { - "title": "确认回滚", - "descriptionWithTarget": "确定回滚文件 \"{name}\" 的本地修改吗?", - "descriptionFallback": "确定回滚该文件的本地修改吗?" - }, - "terminalTitle": "终端 · {name}" - }, - "commandDropdown": { - "loading": "加载中...", - "addCommand": "添加命令", - "manageCommands": "管理命令...", - "runCommandTitle": "运行:{command}", - "stopCommandTitle": "停止:{command}", - "manageDialog": { - "title": "管理命令", - "empty": "暂无命令", - "noResults": "没有匹配的命令", - "searchPlaceholder": "搜索命令", - "newCommand": "新建命令", - "nameLabel": "名称", - "commandLabel": "命令", - "dragSort": "拖拽排序", - "dragSortCommand": "拖拽排序 {name}", - "orderFailed": "保存命令排序失败", - "loadFailed": "加载命令失败", - "saveFailed": "保存命令失败", - "deleteFailed": "删除命令失败", - "confirmDelete": { - "title": "删除命令?", - "message": "这会移除“{name}”,此操作不可撤销。" - } - } - }, - "workspaceContext": { - "confirmCloseDirtyTab": "文件“{title}”有未保存更改,确定关闭吗?", - "confirmCloseOtherDirtyTabs": "其它标签页有未保存更改,确定关闭吗?", - "confirmCloseAllDirtyTabs": "存在未保存更改,确定关闭全部标签页吗?", - "unableLoadContent": "无法加载内容。\n\n{message}", - "previewRequestTimedOut": "预览请求超时", - "diffRequestTimedOut": "Diff 请求超时", - "branchCompareRequestTimedOut": "分支比较请求超时", - "commitDiffRequestTimedOut": "提交差异请求超时", - "saveRequestTimedOut": "保存请求超时", - "reloadRequestTimedOut": "重载请求超时", - "noChanges": "暂无变更。", - "noDiffOutput": "无差异输出。", - "diffTitleWorkspace": "Diff · 工作区", - "diffDescriptionWorkingTree": "工作区变更(HEAD)", - "diffTitleFile": "差异 · {name}", - "compareTitleFile": "比较 · {name}", - "compareTitleBranch": "比较 · {branch}", - "compareDescriptionPath": "{path} · 与 {branch} 比较", - "compareDescriptionBranch": "与 {branch} 比较", - "diffTitleCommitFile": "差异 · {name} @ {hash}", - "diffTitleCommit": "差异 · {hash}", - "diffDescriptionCommitPath": "{path} · 提交 {commit}", - "diffDescriptionCommit": "提交 {commit}", - "diffTitleConflictFile": "冲突 · {name}", - "diffDescriptionConflict": "{path} · 磁盘与未保存内容" - }, - "chat": { - "acpConnections": { - "actions": { - "openAgentsSettings": "打开 Agents 管理", - "retry": "重试" - }, - "agentsSetupHint": "点击前往设置 > Agents 管理安装。", - "withSetupHint": "{message}\n提示:{hint}", - "blocked": { - "missingConfig": "无法读取当前 Agent 配置。", - "disabled": "{agent} 已在 Agents 管理中禁用,请先启用后再连接。", - "unavailable": "{agent} 当前平台不可用。", - "sdkMissing": "{agent} SDK 尚未安装", - "adapterMissing": "{agent} 的 ACP 适配器尚未安装" - }, - "backendErrors": { - "initializeTimeout": "{agent} 连接握手超时(60 秒未响应),请前往设置页面检查智能体和网络配置。", - "mcpRejectedByAgent": "附带 codeg 的 MCP 伴生进程时,{agent} 拒绝了本次会话:{message} 如果该智能体不支持 MCP,请在设置中关闭它的“MCP 支持”后重新连接。", - "processExited": "{agent} 进程意外退出。", - "spawnFailed": "启动 {agent} 失败:{message}", - "downloadFailed": "{agent} 下载失败:{message}", - "sessionLoadResourceNotFound": "{agent} 会话加载失败,可重新加载重试,或开始新会话。", - "sessionLoadUnavailable": "{agent} 无法恢复此会话,它可能已结束或 agent 已停止。可重新加载重试,或开始新会话。", - "turnFailedRefusal": "{agent} 拒绝继续本轮回复,通常意味着后端或网关出错,请检查代理日志。", - "turnFailedMaxTokens": "{agent} 已达到本轮回复的最大 Token 限制。", - "turnFailedMaxTurnRequests": "{agent} 已达到本轮回复允许的最大请求次数。", - "turnFailedUnknown": "{agent} 以未知的停止原因结束了本轮回复。", - "grokModelSwitchIncompatibleAgent": "{agent} 无法在已有对话中切换到该模型,请新建会话以使用它。", - "turnFailedEmpty": "{agent} 本轮没有产生任何回复就结束了。", - "turnFailedEmptyProtocol": "{agent} 本轮的输出 codeg 无法解析,可能是代理版本与协议不匹配。", - "turnFailedEmptyMetadata": "{agent} 本轮只收到状态更新(计划 / 模式 / 用量),没有收到任何回复。", - "detailsInAlerts": "在状态栏的「告警」中展开详情,可查看代理输出。" - }, - "unableReadAgentConfig": "无法读取 Agent 配置:{message}", - "connectFailedTitle": "{agent} 连接失败", - "toolFallbackTitle": "工具", - "eventErrorTitle": "Agent 错误", - "notificationTurnComplete": "{agent} 已完成响应", - "notificationError": "{agent} 错误:{message}", - "claudeApiRetry": { - "fallbackError": "authentication_failed", - "retryingWithMax": "正在重试 {attempt}/{max}", - "retryingAttempt": "正在重试(第 {attempt} 次)", - "retrying": "正在重试", - "nextRetryIn": "{seconds} 秒后重试", - "line": "{error}{status} · {retry}", - "lineWithDelay": "{error}{status} · {retry},{delay}", - "httpStatus": "(HTTP {status})" - }, - "configOptionAdjusted": "{agent} 把{option}设成了 {actual},而不是 {requested}" - }, - "connectionLifecycle": { - "tasks": { - "connectingTitle": "正在连接 {agent}", - "connectingDescription": "正在建立连接", - "loadingSelectorsTitle": "正在加载 {agent} 选择项", - "loadingSelectorsDescription": "正在获取模式和会话配置选项", - "initSessionTitle": "正在初始化 {agent} 会话", - "initSessionDescription": "正在创建会话并加载配置" - }, - "errors": { - "connectionFailed": "连接失败", - "sendPromptFailed": "消息发送失败:{error}" - } - }, - "shared": { - "attachedResources": "附加资源", - "toolCallFailed": "工具调用失败" - }, - "messageThread": { - "emptyTitle": "暂无消息", - "emptyDescription": "开始一个会话后,消息会显示在这里" - }, - "chatInput": { - "connecting": "连接中...", - "agentResponding": "{agent} 正在响应...", - "sendMessage": "发送消息..." - }, - "messageInput": { - "askAnything": "请开始输入...", - "removeAttachmentAria": "移除 {name}", - "attachFiles": "附加文件", - "attachLocalUpload": "附加本地文件", - "attachServerFile": "附加服务端文件", - "addActions": "添加", - "quickMessages": "快捷消息", - "quickMessagesEmpty": "暂无快捷消息", - "quickMessagesLoading": "加载中...", - "pasteAsPlainText": "粘贴为纯文本", - "cut": "剪切", - "copy": "复制", - "selectAll": "全选", - "pasteUnavailable": "无法读取剪贴板,请改用 Ctrl/⌘V 粘贴。", - "clipboardWriteFailed": "无法写入剪贴板,请改用键盘快捷键。", - "quickMessageUntitled": "未命名", - "liveFeedback": "实时反馈", - "liveFeedbackDisabledHint": "智能体工作时可发送", - "dropFilesToAttach": "拖拽文件到此处附加", - "loadingSettings": "正在加载设置...", - "loadingMode": "正在加载模式...", - "modeLabel": "模式", - "toggleOn": "开", - "toggleOff": "关", - "agentSettings": "智能体设置", - "searchModel": "搜索模型...", - "searchModelAria": "搜索模型", - "modelListLabel": "模型", - "noModels": "未找到模型", - "cancel": "取消", - "send": "发送", - "forkAndSend": "分叉发送", - "queueMessage": "加入队列", - "steerIntoTurn": "插入当前回合", - "steerQueuedInstead": "已转入队列——将随下一回合发送。", - "steerFailed": "无法插入当前回合", - "steerAttachmentsUnsupported": "仅支持纯文本——带附件的草稿请走队列。", - "slashCommands": "斜杠命令", - "slashSearchPlaceholder": "搜索命令...", - "slashSearchEmpty": "没有匹配的命令", - "experts": "专家", - "office": "日常办公", - "research": "科学研究", - "attachUploadTooLarge": "{names} 超过 {limit}MB 上传上限,已跳过。", - "attachUploadFailed": "上传失败:{names}。", - "attachUploadNotAFile": "{names} 不是常规文件(目录或特殊文件),已跳过。", - "attachUploadQuotaExceeded": "服务器上传空间已用尽,{names} 未能上传。", - "attachUploadInProgress": "图片仍在上传中,请稍候再发送。", - "mentionEmpty": "无匹配项", - "mentionLoading": "搜索中…", - "mentionListLabel": "提及", - "mentionMore": "还有更多结果,继续输入以筛选", - "mentionCount": "{count, plural, other {# 项结果}}", - "mentionGroupFile": "文件", - "mentionGroupAgent": "智能体", - "mentionGroupSession": "会话", - "mentionGroupCommit": "提交", - "mentionGroupSkill": "技能" - }, - "messageQueue": { - "addToQueue": "加入队列", - "saveEdit": "保存", - "cancelEdit": "取消编辑", - "editItem": "编辑", - "deleteItem": "删除" - }, - "welcomeInputPanel": { - "agentsSettingsPath": "设置 > Agents", - "autoConnectFallback": "点击前往 {path} 管理安装。", - "autoConnectAppend": "{message},点击前往 {path} 管理安装。", - "enableAgentFirstPlaceholder": "请先启用至少一个 Agent 后开始会话...", - "prepareSessionFailed": "无法准备聊天会话,请重试。", - "createConversationFailed": "无法创建会话,请重试。", - "askAnythingPlaceholder": "请开始输入...", - "agentNotInstalled": "{agent} 尚未安装 · 点击前往 Agents 设置安装", - "agentAdapterNotInstalled": "{agent} 的 ACP 适配器尚未安装(与你本地的 CLI 无关)· 点击前往 Agents 设置安装" - }, - "welcomePanel": { - "greeting": "今天准备做些什么呢?", - "tips": { - "tileTabs": "右键点击会话标签选择「平铺显示」,可同屏对比多个会话", - "pinTab": "双击会话标签可将其固定,避免被新打开的会话自动替换", - "shortcutsNewSearch": "{newConversation} 快速新建会话,{searchConversations} 搜索历史会话", - "slashAtMention": "在输入框输入 / 触发斜杠命令,输入 @ 引用项目内文件", - "pasteDropFiles": "直接粘贴截图或把文件拖到输入框,即可作为附件", - "queueMessage": "智能体回复中也能继续输入并排队,回答完毕会自动续发", - "draftAutoSave": "未发送的草稿会自动保存,重新打开会话仍在", - "forkSend": "发送按钮旁的下拉选择「分叉发送」,从当前位置开一条新分支", - "exportConversation": "右键会话内容区可导出为 Markdown / HTML / 图片", - "chatChannels": "在「设置 → 聊天频道」接入 Telegram / 飞书 / 微信,从手机继续操作", - "shortcutsAuxPanel": "{toggleAuxPanel} 切换右侧面板,查看本次会话改动的文件与 Git 变更", - "shortcutsTerminalSidebar": "{toggleTerminal} 打开内置终端,{toggleSidebar} 切换侧边栏", - "customShortcuts": "所有快捷键都可在「设置 → 快捷键」中自定义", - "webService": "开启「设置 → Web 服务」后,团队成员可从浏览器接入同一台 codeg", - "fusionMode": "打开文件或差异后,会自动与会话并排显示", - "quickMessages": "点输入框旁的 + 按钮选择「快捷消息」,可一键插入预存片段(在「设置 → 快捷消息」中管理)", - "experts": "通过 + 按钮里的「专家技能」可一键加载预设角色(调试 / 规划等)", - "taskBoard": "「待办任务」能把一条待办从头跑到尾:智能体在独立工作树里干活,你 review 完差异再合并。", - "automations": "「自动化」按计划定时跑保存好的提示词(比如每晚一次代码评审),还能让每次运行都开一个独立工作树。", - "tokenUsage": "点击状态栏左下角的会话数即可打开「Token 用量」,按天、智能体、模型和文件夹拆分统计。", - "mentionTargets": "@ 不只能引用文件:还能 @ 另一个智能体把子任务交给它,或引用历史会话、某次提交、某个技能。", - "splitGroups": "右键点击标签选择「向右拆分」或「向下拆分」,两个会话各占一个分栏同时开着。", - "worktrees": "点开分支按钮选「新建工作树」,多个智能体就能在同一个仓库并行干活,互不覆盖彼此的文件。", - "importSessions": "之前在终端里跑过的会话,用文件夹右键菜单的「导入本地会话」就能把那段历史接进 codeg。", - "subSessions": "智能体委派出去的子会话会嵌套显示在侧边栏的父会话下面,展开就能跟踪每一个子会话做了什么。", - "liveFeedback": "「+」菜单里的「实时反馈」能把一条便条塞进智能体正在跑的这一轮,不用打断它。", - "skillPacks": "设置 → 技能包 里打包了编程专家、科研和办公三类技能,可以按智能体分别开关。", - "modelProviders": "设置 → 模型供应商 支持填自己的 API key 或接口地址,之后直接在输入框里切换模型。", - "workspaceBackground": "设置 → 外观 里可以换工作区背景图、调面板不透明度,还能换应用字体。" - }, - "quickActions": { - "excel": "Excel 工作簿", - "excelDesc": "数据表、公式和图表", - "word": "Word 文档", - "wordDesc": "报告、信函和备忘录", - "ppt": "演示文稿", - "pptDesc": "专业设计的幻灯片", - "pitchDeck": "融资路演", - "pitchDeckDesc": "含关键指标的路演 PPT", - "morph": "Morph 动画", - "morphDesc": "电影级幻灯片转场", - "morph3d": "3D Morph", - "morph3dDesc": "3D 模型与镜头运动", - "academic": "学术论文", - "academicDesc": "含引用与结构的研究论文", - "financial": "财务模型", - "financialDesc": "报表、DCF 与预测", - "dashboard": "数据仪表盘", - "dashboardDesc": "从数据生成 KPI 与分析", - "prompts": { - "excel": "创建一个 Excel 工作簿,要求如下:\n\n[在此描述你的数据、表格、公式和图表]", - "word": "创建一个 Word 文档,要求如下:\n\n[在此描述文档内容、结构和排版]", - "ppt": "创建一个 PowerPoint 演示文稿,要求如下:\n\n[在此描述幻灯片、内容和设计]", - "pitchDeck": "创建一个融资路演 PPT,要求如下:\n\n[在此描述公司、融资轮次和关键指标]", - "morph": "创建一个带 Morph 转场动画的演示文稿:\n\n[在此描述演示主题和期望的视觉效果]", - "morph3d": "创建一个带 GLB 模型和镜头运动的 3D Morph 演示文稿:\n\n[在此描述主题和 3D 视觉构想]", - "academic": "用 Word 写一篇学术论文,要求如下:\n\n[在此描述研究主题、方法和主要发现]", - "financial": "用 Excel 创建一个财务模型,要求如下:\n\n[在此描述财务报表、预测和分析]", - "dashboard": "用 Excel 创建一个数据仪表盘,要求如下:\n\n[在此描述数据来源、KPI 和图表]", - "scientific-brainstorming": "帮我进行科研头脑风暴:探索跨学科联系、挑战假设、发现有潜力的研究空白。我正在探索的方向:", - "hypothesis-generation": "帮我把这些观察转化为可检验的假设:给出明确预测、合理机制,并设计验证实验。我的观察:", - "experimental-design": "在采集数据前帮我设计严谨的实验:设计方案、随机化、对照,以及如何避免混杂。我想研究的问题:", - "statistical-power": "帮我确定所需样本量:为我的设计做功效分析(效应量、显著性水平、功效)。具体信息:", - "statistical-analysis": "帮我正确分析这份数据:选择合适的检验、检查假设、报告效应量并撰写结论。我的数据与问题:", - "exploratory-data-analysis": "对我的数据文件做探索性分析:概述其结构、质量与值得注意的模式,并建议后续步骤。文件是:", - "scientific-visualization": "帮我制作出版级图表:清晰布局、真实误差棒、色盲友好配色,以及期刊格式。我想展示的内容:", - "scientific-critical-thinking": "帮我批判性评估这项研究或主张:评估证据质量、识别偏倚与混杂,并权衡结论。内容如下:", - "paper-lookup": "帮我在学术数据库中查找相关论文与开放获取全文,并提供可复用的引用。我要找的是:" - }, - "paper-lookup": "论文检索", - "paper-lookupDesc": "检索 10 个学术 API(PubMed、arXiv、OpenAlex、Crossref…)查找论文、引用与开放获取全文。", - "scientific-critical-thinking": "批判性思维", - "scientific-critical-thinkingDesc": "评估科学主张与证据质量:识别偏倚与混杂,运用 GRADE 与偏倚风险框架。", - "scientific-visualization": "科学可视化", - "scientific-visualizationDesc": "出版级图表:多面板布局、显著性标注与期刊专属格式。", - "exploratory-data-analysis": "探索性数据分析", - "exploratory-data-analysisDesc": "对 200+ 种格式的科学数据文件做自动化探索,输出质量指标与报告。", - "statistical-analysis": "统计分析", - "statistical-analysisDesc": "引导式统计分析:检验选择、假设检查、效应量与 APA 格式报告。", - "statistical-power": "统计功效", - "statistical-powerDesc": "样本量与统计功效分析:所需样本数、最小可检测效应与功效曲线。", - "experimental-design": "实验设计", - "experimental-designDesc": "在采集数据前设计严谨研究:随机化、区组、对照与析因/DOE 布局。", - "hypothesis-generation": "假设生成", - "hypothesis-generationDesc": "将观察转化为可检验的假设,给出预测、机制并设计验证实验。", - "scientific-brainstorming": "科学头脑风暴", - "scientific-brainstormingDesc": "开放式科研构思:探索跨学科联系、挑战假设、发现研究空白。", - "tabs": { - "office": "日常办公", - "coding": "代码开发", - "research": "科学研究" - }, - "coding": { - "brainstormingDesc": "动手前先梳理意图与需求", - "debuggingDesc": "先定位根因再提出修复", - "writingSkillsDesc": "创建、编辑并验证可复用技能" - }, - "notEnabled": { - "title": "「{skill}」技能尚未对 {agent} 启用", - "description": "前往设置启用后即可在此使用。", - "action": "去启用", - "hint": "技能未启用" - }, - "scrollPrev": "显示上一组技能", - "scrollNext": "显示下一组技能" - } - }, - "agentSelector": { - "noEnabledAgents": "暂无已启用的 Agent", - "openAgentsSettings": "打开 Agents 设置", - "notInstalled": "未安装", - "moreAgents": "更多 Agent({count})" - }, - "subAgentOverlay": { - "title": "子智能体", - "collapsedSummary": "子智能体 {count}", - "collapseAria": "折叠子智能体" - }, - "agentPlanOverlay": { - "title": "计划任务", - "collapsePlanAria": "折叠计划", - "collapsedSummary": "计划 {completed}/{total}", - "status": { - "completed": "已完成", - "inProgress": "进行中", - "pending": "待处理", - "unknown": "未知" - }, - "priority": { - "high": "高", - "medium": "中", - "low": "低", - "unknown": "未知" - } - }, - "permissionDialog": { - "subtitle": "Agent 请求继续当前轮次的权限。", - "queuedCount": "还有 {count} 项待审批", - "kindFallbackTool": "工具", - "command": "命令", - "cwd": "工作目录:{cwd}", - "filesSummary": "文件:{count}", - "moreFiles": "+{count} 个更多文件", - "plan": "计划", - "allowedActions": "允许的操作", - "targetMode": "目标模式:{mode}", - "optionGrants": "各选项将授予的权限", - "changeScopeSession": "本次会话", - "changeScopeProcess": "本次运行", - "changeScopeUser": "保存到用户设置", - "changeScopeProject": "保存到项目设置", - "changeScopeProjectLocal": "保存到本地项目设置", - "changeScopePersistent": "永久保存" - }, - "questionDialog": { - "title": "代理正在提问", - "placeholder": "输入你的回答...", - "send": "发送" - }, - "messageBranch": { - "previousBranchAria": "上一分支", - "nextBranchAria": "下一分支", - "pageOf": "{current} / {total}" - }, - "terminal": { - "title": "终端", - "running": "运行中" - }, - "reasoning": { - "thinking": "思考中…", - "thoughtForFewSeconds": "思考", - "thoughtForSeconds": "思考" - }, - "linkSafety": { - "errorCannotOpen": "无法打开本地文件", - "errorNoWorkspace": "当前没有活跃的工作区文件夹。", - "errorFailedOpen": "打开本地文件失败", - "errorFailedLink": "打开链接失败", - "errorUnsupportedLinkProtocol": "不支持该链接协议。" - }, - "fileActions": { - "openInFinder": "在访达打开", - "openInExplorer": "在资源管理器打开", - "openInFileManager": "在文件管理器打开", - "copyRelativePath": "复制相对路径", - "copyAbsolutePath": "复制绝对路径", - "pathCopied": "已复制路径", - "copyPathFailed": "复制路径失败", - "openFailed": "打开本地文件失败" - }, - "messageList": { - "attachedResources": "附加资源", - "loading": "加载中...", - "loadEarlier": "加载更早的消息", - "loadingEarlier": "正在加载更早的消息…", - "error": "错误:{message}", - "errorTitle": "会话加载失败", - "errorActionReload": "重新加载", - "errorActionNewSession": "新建会话", - "emptyConversation": "当前会话暂无消息。", - "systemMessage": "系统消息", - "copyMessage": "复制", - "copied": "已复制", - "downloadImage": "下载图片", - "downloadFailed": "下载失败:{message}", - "imageGeneration": "图片生成", - "imageGenerationPending": "正在生成图片…", - "imageGenerationFailed": "图片生成失败", - "model": "模型", - "tokenStats": "Token 使用情况", - "tokenInput": "输入", - "tokenOutput": "输出", - "tokenCacheRead": "缓存读取", - "tokenCacheWrite": "缓存写入", - "duration": "耗时", - "completedAt": "完成时间", - "jumpToPreviousUserMessage": "跳转到上一条用户消息", - "showMore": "展开", - "showLess": "收起" - }, - "liveTurnStats": { - "thinking": "思考中...", - "streaming": "生成中", - "elapsedHours": "{value} 小时", - "elapsedMinutes": "{value} 分钟", - "elapsedSeconds": "{value} 秒", - "outputSpeedAria": "估算输出速度", - "outputSpeedTooltip": "估算输出速度(正文 + 思考)" - }, - "jsonTree": { - "viewRaw": "查看原始 JSON", - "viewTree": "查看树状视图", - "fields": "{count} 个字段", - "items": "{count} 项" - }, - "tool": { - "parameters": "参数", - "error": "错误", - "result": "结果", - "status": { - "approvalRequested": "等待授权", - "approvalResponded": "已响应", - "inputAvailable": "运行中", - "inputStreaming": "等待中", - "outputAvailable": "已完成", - "outputDenied": "已拒绝", - "outputError": "错误" - } - }, - "toolCallBlock": { - "tool": "工具", - "error": "错误", - "result": "结果" - }, - "delegation": { - "subAgentRunning": "子智能体运行中…", - "noDetail": "暂无详情。", - "unknownAgent": "子智能体", - "openDetail": "查看会话", - "detailTitle": "子智能体会话", - "detailDescription": "只读查看委托给子智能体的会话内容。", - "waitForResult": "等待 {task} 任务执行结果", - "waitForResultNoTask": "等待任务执行结果", - "cancelTask": "取消 {task} 任务", - "cancelTaskNoTask": "取消任务", - "resultPageOf": "{current} / {total}", - "prevResult": "上一个结果", - "nextResult": "下一个结果", - "noResultText": "本次检查暂无结果", - "status": { - "starting": "启动中", - "running": "运行中", - "checked": "已查询", - "waiting": "待批准", - "ok": "完成", - "err": { - "default": "失败", - "delegation_disabled": "已禁用", - "depth_limit": "深度超限", - "invalid_agent_type": "代理类型无效", - "spawn_failed": "启动失败", - "send_failed": "发送失败", - "timeout": "超时", - "canceled": "已取消", - "child_refusal": "子代理拒绝", - "child_max_tokens": "子代理超出 token 上限", - "child_max_turn_requests": "子代理超出请求上限", - "child_empty": "子代理无响应", - "child_unknown": "子代理未知错误", - "unknown": "未知任务" - } - } - }, - "contentParts": { - "showingTailOutput": "为保证性能,流式输出时仅显示尾部内容。", - "result": "结果", - "unknown": "未知", - "inputTruncated": "输入已截断,diff 可能不完整。", - "replaceAll": "全部替换", - "filesCount": "文件:{count}", - "update": "更新", - "moreFiles": "+{count} 个更多文件", - "timeoutMs": "超时:{timeout}ms", - "backgroundTrue": "后台:true", - "scriptToolCalls": "调用 {count} 个工具", - "offset": "偏移:{offset}", - "limit": "限制:{limit}", - "pages": "页码:{pages}", - "mode": "模式:{mode}", - "cell": "单元:{cell}", - "shellSession": "会话 {id}", - "pathLabel": "路径:", - "globLabel": "Glob:", - "typeLabel": "类型:", - "outputLabel": "输出:", - "caseInsensitive": "忽略大小写", - "multiline": "多行", - "promptLabel": "提示词", - "subjectLabel": "主题", - "taskLabel": "任务", - "nameLabel": "名称:", - "agentPromptLabel": "提示词", - "agentModelLabel": "模型", - "agentRunning": "运行中...", - "agentLiveTranscript": "实时活动", - "agentProgressTools": "{count} 次工具调用", - "agentProgressTurns": "{count} 轮", - "agentProgressContext": "上下文 {pct}%", - "agentSessionAction": "查看子智能体会话", - "agentSessionTitle": "子智能体会话", - "agentSessionLoading": "正在加载子智能体的会话记录…", - "agentSessionEmpty": "子智能体还没有写入任何内容。", - "agentFallbackTitle": "子智能体启动中…", - "agentCodexLaunchOnly": "已启动。Codex 不会再报告这个子智能体的进展——它的结果会作为一条消息出现在本会话中。", - "agentStatsBash": "命令", - "agentStatsRead": "读取文件", - "agentStatsSearch": "搜索", - "agentStatsEdit": "编辑", - "agentStatsOther": "其他", - "goal": { - "title": "目标:", - "titleWithStatus": "目标{status}", - "objective": "目标", - "statusLabel": "状态", - "tokensUsed": "已用 tokens", - "budget": "预算", - "remaining": "剩余", - "elapsed": "耗时", - "tokens": "tokens", - "pause": "暂停", - "clear": "清除", - "status": { - "active": "进行中", - "paused": "已暂停", - "blocked": "受阻", - "usageLimited": "用量受限", - "budgetLimited": "预算受限", - "complete": "已完成", - "limited": "已达上限" - } - }, - "field": { - "file": "文件", - "notebook": "笔记本", - "command": "命令", - "old": "旧内容", - "new": "新内容", - "pattern": "模式", - "path": "路径", - "query": "查询", - "url": "URL地址", - "description": "描述", - "content": "内容", - "source": "源内容", - "prompt": "提示词", - "subject": "主题", - "taskId": "任务 ID", - "status": "状态", - "skill": "Skill", - "args": "参数", - "offset": "偏移", - "limit": "限制", - "glob": "Glob", - "type": "类型", - "output": "输出", - "replaceAll": "全部替换", - "language": "语言", - "timeout": "超时", - "background": "后台", - "agentType": "Agent 类型", - "library": "库", - "libraryId": "库 ID" - }, - "title": { - "edit": "编辑", - "command": "命令", - "script": "脚本", - "waitCommand": "等待 {command}", - "waitCell": "等待会话 {id}", - "terminateCommand": "终止 {command}", - "terminateCell": "终止会话 {id}", - "stdinChars": "输入 {chars}", - "todoWrite": "待办", - "read": "读取", - "write": "写入", - "notebookEdit": "Notebook 编辑", - "editFiles": "编辑({count} 个文件)", - "editWithTarget": "编辑 {target}", - "readWithTarget": "读取 {target}", - "writeWithTarget": "写入 {target}", - "notebookEditWithTarget": "Notebook 编辑 {target}", - "globWithPattern": "Glob {pattern}", - "listFilesWithPath": "列出文件 {path}", - "grepWithPattern": "Grep {pattern}", - "taskCreateWithSubject": "创建任务:{subject}", - "taskUpdateWithStatus": "更新任务 #{id} -> {status}", - "taskUpdate": "更新任务 #{id}", - "webFetchWithUrl": "抓取网页 {url}", - "webSearchWithQuery": "网页搜索:{query}", - "todosProgress": "待办({done}/{total})", - "skillWithName": "Skill:{name}", - "genericWithContext": "{tool}:{context}" - }, - "search": { - "noMatches": "无匹配结果", - "matchSummary": "{matches} 处匹配 · {files} 个文件", - "fileSummary": "{files} 个文件", - "moreResults": "另有 {count} 条结果未显示" - }, - "toolGroup": { - "search": "搜索 {count} 次", - "command": "运行 {count} 个命令", - "read": "读取 {count} 次文件", - "memory": "回忆 {count} 项记忆", - "edit": "编辑 {count} 次文件", - "fetch": "抓取 {count} 个资源", - "think": "思考 {count} 次", - "todo": "更新 {count} 项待办", - "task": "执行 {count} 个任务", - "other": "调用 {count} 个工具", - "errorSuffix": "{count} 个失败", - "joiner": " · " - }, - "planMode": { - "entered": "进入计划模式", - "planLabel": "计划", - "reviewApproved": "已批准执行计划", - "reviewKept": "保持在计划模式", - "reviewPending": "等待计划决定", - "submitted": "计划已提交", - "switched": "切换模式" - }, - "backgroundTask": { - "title": "后台任务", - "titleWithId": "后台任务 · {id}", - "running": "运行中", - "completed": "已完成", - "failed": "失败", - "stopped": "已停止", - "exitCode": "退出码 {code}", - "polledTimes": "轮询 {count} 次", - "runningInBackground": "后台运行", - "launchNote": "已在后台运行 · {id}" - }, - "codexScript": { - "outputMissing": "codex 截断脚本输出时丢掉了这条命令的分隔行,因此没有输出可以归属给它。", - "sharedWith": "本段还包含 {commands} 的输出——它们的分隔行被 codex 截断丢弃了。", - "truncated": "已截断" - } - }, - "messageNav": { - "title": "消息导航", - "collapse": "收起消息导航", - "collapsedSummary": "消息 {count}", - "fileCount": "{count} 个文件", - "remove": "移除", - "noDiffDataAvailable": "未找到 {filePath} 的差异数据" - }, - "replyArtifacts": { - "title": "改动文件", - "fileCount": "{count} 个文件", - "newFilesTitle": "新增文件", - "revealInFolder": "在访达/资源管理器中显示", - "openFile": "打开 {filePath}", - "openInEditor": "在编辑器中打开", - "remove": "移除", - "noDiffDataAvailable": "未找到 {filePath} 的差异数据" - }, - "askQuestion": { - "title": "智能体需要你的选择", - "subtitle": "回答后点击提交,可随时跳过", - "recommended": "推荐", - "other": "其他", - "otherPlaceholder": "输入你的回答…", - "singleSelect": "单选", - "multiSelect": "多选", - "skip": "跳过", - "next": "下一题", - "submit": "提交", - "submitError": "提交失败,请重试。" - }, - "planApproval": { - "title": "智能体已给出计划——请审阅", - "emptyPlan": "智能体未写入计划。可批准开始实施,或要求修改。", - "approve": "批准并开始", - "requestChanges": "要求修改", - "abandon": "放弃", - "feedbackPlaceholder": "需要修改什么?", - "sendChanges": "发送", - "cancel": "取消", - "submitError": "提交失败,请重试。" - }, - "feedbackCheckResult": { - "count": "{count} 条反馈", - "expand": "展开全部反馈", - "collapse": "收起", - "errorTitle": "反馈检查失败" - }, - "askQuestionResult": { - "title": "提问", - "answeredLabel": "提问回答:", - "awaiting": "等待你的回答…", - "declined": "你已忽略此问题 — 代理已自行判断。", - "noSelection": "未选择" - }, - "configStale": { - "agentConfigTitle": "智能体配置已更新", - "modelProviderTitle": "模型供应商已更新", - "description": "当前会话仍在使用旧配置,重连后生效(对话历史不会丢失)。", - "reconnect": "重连以应用", - "reconnecting": "正在重连…", - "reconnectDisabledDuringTurn": "当前回合结束后可重连", - "dismiss": "忽略", - "reconnectFailed": "重连会话失败", - "applied": "新配置已应用" - }, - "piProjectTrust": { - "title": "该项目自带 pi 资源", - "description": "pi 未加载仓库自带的 .pi 文件。请查看后决定。", - "descriptionExecutable": "仓库自带 pi 扩展,扩展会在启动时执行代码。pi 尚未加载它们,请先查看再决定。", - "review": "查看…", - "dismiss": "忽略", - "dialogTitle": "信任该项目的 pi 资源?", - "dialogDescription": "只有在你信任该目录后,pi 才会加载仓库自带的 .pi 文件。请仅在你信任该仓库内容时才信任。", - "executionWarning": "扩展就是代码。信任该目录后,仓库中的扩展会在 pi 启动时以你的权限执行——早于你发送任何消息。", - "scopeNote": "该决定保存在 pi 的 trust.json 中,对该目录下的所有子目录同样生效,你在终端里自己运行 pi 时也会沿用。之后可在「设置 → 智能体 → Pi」中修改。", - "trust": "信任项目", - "decline": "保持不加载", - "disabledDuringTurn": "当前回合结束后可用", - "trustedToast": "已信任项目——已重连以便 pi 加载其资源", - "declinedToast": "项目资源保持不加载", - "saveFailed": "保存项目信任决定失败", - "grantTitle": "该项目已被信任", - "grantDescription": "pi 会加载该仓库自带的 .pi 文件。请查看这意味着什么。", - "grantInheritedDescription": "某个上级目录已被信任,因此 pi 会加载该仓库自带的 .pi 文件。请查看这意味着什么。", - "grantDialogTitle": "该项目的 pi 资源已被信任", - "grantDialogDescription": "pi 被允许加载该仓库自带的 .pi 文件。旧版本 codeg 会在你打开目录时自动授予该权限,因此你可能从未被询问过。", - "grantExecutionWarning": "扩展就是代码。仓库中的扩展会在 pi 启动时以你的权限执行——早于你发送任何消息。", - "inheritedFrom": "信任来自", - "revoke": "撤销信任", - "keepTrusted": "保持信任", - "revokedToast": "已撤销信任——已重连,pi 不再加载该项目的资源", - "trustedNoReconnect": "已信任项目——将在 pi 下次启动时生效", - "revokedNoReconnect": "已撤销信任——将在 pi 下次启动时生效" - }, - "collabAgent": { - "title": "子智能体", - "errorTitle": "子智能体任务失败", - "statesLabel": "子智能体", - "statusRunning": "运行中", - "statusCompleted": "已完成", - "statusFailed": "失败", - "statusPending": "初始化中", - "statusInterrupted": "已中断", - "statusClosed": "已关闭", - "statusNotFound": "未找到", - "opSpawn": "启动子智能体", - "opWait": "获取子智能体结果", - "opClose": "结束子智能体", - "opResume": "恢复子智能体" - }, - "contextCompaction": { - "compacting": "正在压缩上下文…", - "compacted": "上下文已压缩", - "compactedTokens": "上下文已压缩 · {before} → {after} tokens", - "failed": "上下文压缩失败" - }, - "sessionFailure": { - "category": { - "connection": "连接异常", - "access": "访问受限", - "limit": "已达限制", - "request": "请求被拒绝", - "service": "服务异常", - "unknown": "会话异常" - }, - "action": { - "retry": "重试", - "login": "去登录", - "newSession": "新建会话" - }, - "recovered": "已恢复", - "retryUnavailable": "没有可重发的消息。", - "toggleDetails": "展开/收起详情" - }, - "backgroundTasks": { - "running": "{count} 个后台任务运行中", - "settling": "正在同步后台结果…", - "settledFallback": "后台任务已结束({status})", - "cardRunning": "后台运行中", - "cardLaunchedPending": "已启动后台任务", - "cardCompleted": "后台任务已完成", - "cardFinishedWithStatus": "后台任务已结束({status})", - "cardResultPending": "结果尚未返回" - }, - "proposedPlan": { - "title": "计划提案", - "planning": "规划中…" - } - }, - "diffPreview": { - "mode": { - "added": "新增", - "deleted": "删除", - "renamed": "重命名", - "modified": "修改" - }, - "hunkLabel": "代码块 {index}", - "loadingHunk": "正在加载代码块...", - "noDiffData": "无差异数据", - "showRemainingLines": "显示剩余 {count} 行" - }, - "conversationContextBar": { - "folderTitle": "工作文件夹", - "branchTitle": "工作分支", - "searchFolder": "搜索文件夹...", - "searchBranch": "搜索分支...", - "noFolders": "暂无文件夹", - "noBranches": "暂无分支", - "noBranch": "(无分支)", - "chatModeLabel": "聊天模式", - "commit": "提交", - "push": "推送", - "merge": "合并", - "toasts": { - "folderChanged": "已切换到 {name}", - "openFolderFailed": "打开文件夹失败", - "switchedToChatMode": "已切换到聊天模式", - "openStashFailed": "打开贮藏窗口失败", - "openMergeFailed": "打开合并窗口失败" - } - }, - "cloneDialog": { - "title": "克隆仓库", - "repositoryUrl": "仓库地址", - "repositoryUrlPlaceholder": "https://github.com/user/repo.git", - "directory": "目录", - "directoryPlaceholder": "选择目标目录...", - "browseDirectory": "浏览目录", - "cancel": "取消", - "clone": "克隆", - "clonePath": "克隆路径: {path}" - }, - "toasts": { - "cloneFailed": "克隆仓库失败" - } - }, - "ProjectBoot": { - "title": "项目启动器", - "tabs": { - "shadcn": "shadcn", - "hyperframes": "HyperFrames" - }, - "hyperframes": { - "title": "HyperFrames 视频项目", - "subtitle": "脚手架一个 HTML 转视频项目,随后工作区的智能体即可编写并渲染它。", - "resolution": "分辨率", - "skillsTitle": "智能体技能", - "skillsDesc": "为所选智能体全局安装 HyperFrames 技能(软链接),让它们会编写并渲染视频。", - "recheck": "重新检查", - "installedBadge": "已安装", - "skillsInstall": "安装 / 更新技能", - "skillsInstalling": "正在安装技能…", - "skillsInstalled": "HyperFrames 技能安装成功", - "skillsInstallFailed": "HyperFrames 技能安装失败" - }, - "config": { - "base": "基础库", - "style": "风格", - "baseColor": "基础颜色", - "theme": "主题", - "chartColor": "图表颜色", - "iconLibrary": "图标库", - "font": "字体", - "fontHeading": "标题字体", - "menuAccent": "菜单强调", - "menuColor": "菜单颜色", - "radius": "圆角", - "template": "模板", - "createProject": "创建项目", - "sectionStyle": "风格", - "sectionColors": "配色", - "sectionTypography": "排版", - "sectionInterface": "界面" - }, - "preview": { - "loading": "加载预览..." - }, - "createDialog": { - "title": "创建项目", - "projectName": "项目名称", - "projectNamePlaceholder": "my-app", - "frameworkTemplate": "框架模板", - "packageManager": "包管理器", - "saveDirectory": "保存目录", - "saveDirectoryPlaceholder": "选择目录...", - "browseDirectory": "浏览", - "projectPath": "项目将创建在:{path}", - "advancedOptions": "高级选项", - "base": "基础库", - "enableRtl": "启用 RTL 支持", - "enableRtlDescription": "为从右到左书写的语言(如阿拉伯语、希伯来语)启用布局支持", - "pmChecking": "正在检测...", - "pmNotInstalled": "未安装", - "cancel": "取消", - "create": "创建", - "creating": "正在创建项目..." - }, - "toasts": { - "createFailed": "创建项目失败", - "createSuccess": "项目创建成功", - "openWorkspaceFailed": "项目已创建,但无法在工作区中打开" - }, - "errors": { - "directoryExists": "目标目录已存在", - "commandFailed": "项目创建命令执行失败。" - } - }, - "WebServiceSettings": { - "addressSwitchHint": "切换只改变这里显示和打开的地址;服务监听所有网卡,每个地址都可访问。", - "sectionTitle": "Web 服务", - "sectionDescription": "启用后可通过浏览器远程访问 Codeg", - "port": "端口", - "status": "状态", - "autoStart": "自动启动", - "autoStartHint": "Codeg 启动时自动开启 Web 服务", - "running": "运行中", - "stopped": "已停止", - "processing": "处理中...", - "start": "启动", - "stop": "停止", - "startFailed": "启动失败", - "stopFailed": "停止失败", - "saveConfigFailed": "保存 Web 服务设置失败", - "open": "打开", - "hide": "隐藏", - "show": "显示", - "copy": "复制", - "qrcode": "二维码", - "qrcodeTitle": "扫码打开", - "qrcodeHint": "用手机扫描,在浏览器中打开 Codeg", - "addressLabel": "访问地址", - "tokenLabel": "访问 Token", - "tokenHint": "Web 客户端首次访问时需输入此 Token", - "tokenPlaceholder": "留空则自动生成", - "regenerate": "重新生成", - "stalePortOccupiedTitle": "端口 {port} 已被其他进程占用", - "stalePortUnknownTitle": "端口 {port} 状态未知", - "stalePortHint": "在端口释放前 Codeg 无法绑定。可以更换上方的端口,或结束占用该端口的进程。", - "errors": { - "alreadyRunning": "Web 服务已在运行", - "invalidAddress": "主机或端口格式无效", - "portInUse": "端口 {port} 已被占用,请关闭占用该端口的程序或更换其他端口", - "permissionDenied": "权限不足,请使用 1024 以上的端口,或以更高权限运行", - "addressUnavailable": "该地址在本机不可用", - "bindFailed": "绑定地址失败" - } - }, - "DirectoryBrowser": { - "title": "浏览目录", - "pathPlaceholder": "输入目录路径...", - "goHome": "回到主目录", - "navigateUp": "返回上级目录", - "select": "选择", - "cancel": "取消", - "loading": "加载中...", - "emptyDirectory": "此目录为空", - "errorLoadingDir": "加载目录失败", - "permissionDenied": "权限不足" - }, - "ServerFileBrowser": { - "title": "选择服务端文件", - "pathPlaceholder": "输入目录路径...", - "goHome": "回到主目录", - "navigateUp": "返回上级目录", - "select": "选择", - "cancel": "取消", - "loading": "加载中...", - "emptyDirectory": "此目录为空", - "errorLoadingDir": "加载目录失败", - "selectedCount": "已选 {count} 项" - }, - "ChatChannelSettings": { - "loading": "加载中...", - "sectionTitle": "消息渠道", - "sectionDescription": "配置 IM 机器人,接收事件通知和查询编码活动。", - "addChannel": "添加渠道", - "noChannels": "尚未配置任何消息渠道。", - "channelName": "名称", - "channelNamePlaceholder": "我的 Telegram 机器人", - "channelType": "渠道类型", - "lark": "飞书", - "weixin": "微信", - "dailyReport": "每日报告", - "dailyReportTime": "推送时间", - "nameRequired": "请输入渠道名称。", - "tokenRequired": "请输入 Token。", - "chatIdRequired": "请输入 Chat ID。", - "topicMode": "话题群模式", - "topicModeHint": "将 Telegram forum topics 路由为独立 Codeg 会话。Bot 必须加入 forum supergroup,并拥有管理 topics 权限。", - "loadFailed": "加载渠道失败。", - "saveFailed": "保存失败。", - "connectSuccess": "渠道已连接。", - "connectFailed": "连接失败", - "disconnectSuccess": "渠道已断开。", - "disconnectFailed": "断开连接失败。", - "testSuccess": "连接测试通过。", - "testFailed": "连接测试失败", - "deleteSuccess": "渠道已删除。", - "deleteFailed": "删除渠道失败。", - "deleteConfirmTitle": "删除渠道", - "deleteConfirmMessage": "将永久删除该渠道及其消息日志,确定吗?", - "cancel": "取消", - "delete": "删除", - "create": "创建", - "save": "保存", - "channelListTitle": "已配置渠道", - "channelListDescription": "已启用的渠道在服务启动时会自动连接。", - "editChannel": "编辑渠道", - "editSuccess": "渠道已更新。", - "tokenPlaceholderKeep": "留空保持不变", - "weixinScanTitle": "扫码登录", - "weixinScanDescription": "打开微信扫描二维码以连接。", - "weixinQrcodeExpired": "二维码已过期。", - "weixinRefreshQrcode": "刷新二维码", - "weixinWaitingScan": "等待扫码...", - "weixinPollError": "连接不稳定,正在重试...", - "weixinReconnectNotice": "因 iLink 协议限制,每次重新连接后需先主动向机器人发送一条消息,事件触发才会生效。", - "connect": "连接", - "disconnect": "断开", - "test": "测试连接", - "tabs": { - "channels": "渠道", - "commands": "指令", - "events": "事件", - "other": "其他" - }, - "commands": { - "title": "内置指令", - "description": "消息渠道中可用的 Bot 指令。群聊中需 @Bot 才会处理消息。", - "prefixLabel": "指令前缀", - "prefixDescription": "触发 Bot 指令的前缀,1-3 个非字母数字字符(默认 /)。", - "prefixSaved": "指令前缀已保存。", - "prefixSaveFailed": "保存指令前缀失败。", - "prefixInvalid": "前缀必须是 1-3 个非字母数字字符。", - "save": "保存", - "folderDesc": "选择工作目录", - "agentDesc": "选择 AI Agent", - "taskDesc": "创建会话并执行任务", - "sessionsDesc": "列出当前目录的活跃会话", - "resumeDesc": "最近会话 / 恢复指定会话", - "cancelDesc": "取消当前任务", - "approveDesc": "批准 Agent 权限请求", - "denyDesc": "拒绝 Agent 权限请求", - "searchDesc": "按关键词搜索会话", - "todayDesc": "今日活动汇总", - "statusDesc": "渠道连接状态", - "helpDesc": "显示帮助" - }, - "events": { - "title": "事件通知", - "description": "启用事件后,事件被触发时将推送到渠道。", - "turnComplete": "对话完成", - "turnCompleteDesc": "代理回合结束时", - "error": "代理错误", - "errorDesc": "代理遇到错误时", - "permissionRequest": "权限请求", - "permissionRequestDesc": "智能体请求操作权限时", - "questionRequest": "智能体提问", - "questionRequestDesc": "当智能体向你提问时", - "userPromptSent": "用户消息", - "userPromptSentDesc": "当你发送消息时——通知中会包含消息内容", - "saved": "事件过滤已更新。", - "saveFailed": "保存事件过滤失败。", - "loadFailed": "加载设置失败。", - "retry": "重试", - "webhooksTitle": "Webhook", - "webhooksDescription": "事件触发时,向一个或多个地址 POST 一份 JSON。上方的事件过滤同样作用于 Webhook。", - "webhookUrlPlaceholder": "https://example.com/webhook", - "addWebhook": "添加 Webhook", - "removeWebhook": "删除 Webhook", - "webhookSave": "保存", - "webhooksSaved": "Webhook 已保存。", - "webhooksSaveFailed": "保存 Webhook 失败。", - "webhookInvalidUrl": "请输入有效的 http(s) 地址。", - "docsTitle": "请求格式", - "docsMethod": "请求方式", - "docsContentType": "内容类型", - "docsNote": "每个启用的事件都会投递到所有地址。Webhook 不做去抖;上方的事件过滤仍然生效。", - "editWebhook": "编辑 Webhook", - "enableWebhook": "启用 Webhook", - "webhookDuplicate": "该地址已配置。", - "cancel": "取消", - "webhooksEmpty": "尚未配置 Webhook。", - "deleteWebhookTitle": "删除 Webhook", - "deleteWebhookMessage": "删除此 Webhook?事件将不再投递到该地址。", - "delete": "删除" - }, - "language": { - "title": "消息语言", - "description": "事件通知、指令响应和每日报告推送到消息渠道时使用的语言。", - "saved": "消息语言已保存。", - "saveFailed": "保存消息语言失败。", - "en": "英语", - "zh-cn": "简体中文", - "zh-tw": "繁体中文", - "ja": "日语", - "ko": "韩语", - "es": "西班牙语", - "de": "德语", - "fr": "法语", - "pt": "葡萄牙语", - "ar": "阿拉伯语" - } - }, - "ModelProviderSettings": { - "sectionTitle": "模型供应商", - "sectionDescription": "管理 Agent 的 API 供应商凭据。", - "filterAll": "全部", - "providerListTitle": "已配置的供应商", - "addProvider": "添加供应商", - "editProvider": "编辑供应商", - "noProviders": "尚未配置模型供应商。", - "providerName": "名称", - "providerNamePlaceholder": "例如 OpenAI、Anthropic", - "apiUrl": "API 地址", - "apiUrlPlaceholder": "https://api.openai.com/v1", - "apiKey": "API 密钥", - "apiKeyPlaceholder": "sk-...", - "apiKeyKeepCurrent": "留空则保持不变", - "agentTypes": "代理类型", - "agentTypesRequired": "至少选择一个代理类型。", - "agentType": "智能体类型", - "agentTypeRequired": "请选择智能体类型。", - "agentTypeImmutableHint": "智能体类型创建后不可修改。", - "model": "模型", - "modelPlaceholderCodex": "gpt-5.6-sol / gpt-5.5", - "modelPlaceholderGemini": "gemini-3-pro-preview", - "claudeMainModel": "主模型", - "claudeReasoningModel": "推理模型(思考)", - "claudeHaikuDefaultModel": "默认 Haiku 模型", - "claudeSonnetDefaultModel": "默认 Sonnet 模型", - "claudeOpusDefaultModel": "默认 Opus 模型", - "claudeCustomModelOption": "自定义模型 ID", - "claudeCustomModelOptionName": "自定义模型名称", - "claudeCustomModelOptionDescription": "自定义模型描述", - "claudeCustomModelOptionHint": "在 Claude 模型选择器中追加一个自定义条目(例如经自定义网关/代理提供的模型)。名称与描述为可选的显示信息。", - "nameRequired": "供应商名称不能为空。", - "apiUrlRequired": "API 地址不能为空。", - "apiKeyRequired": "API 密钥不能为空。", - "loadFailed": "加载供应商失败。", - "saveFailed": "保存更改失败。", - "createSuccess": "供应商已创建。", - "editSuccess": "供应商已更新。", - "deleteSuccess": "供应商已删除。", - "deleteConfirmTitle": "删除供应商", - "deleteConfirmMessage": "确定要永久删除供应商「{name}」吗?", - "deleteBlockedByAgent": "{agents} 正在使用该配置,请先解除关联后再删除。", - "cancel": "取消", - "delete": "删除", - "create": "创建", - "save": "保存", - "affectedRunningSessions": "{count} 个进行中的会话需重连以应用更改" - }, - "SkillMatrix": { - "loading": "加载中…", - "searchPlaceholder": "按名称、ID 或描述搜索", - "empty": "暂无内容。", - "emptySearch": "没有匹配当前搜索的结果。", - "skillColumn": "技能", - "selectAll": "全选可见项", - "selectSkill": "选择 {name}", - "everything": { - "label": "批量", - "enable": "全部启用(可见)", - "disable": "全部禁用(可见)" - }, - "columnMenu": { - "enableAll": "启用全部技能", - "disableAll": "禁用全部技能" - }, - "rowMenu": { - "label": "对 {name} 批量操作", - "enableAll": "对所有 agent 启用", - "disableAll": "对所有 agent 禁用" - }, - "bulk": { - "selected": "已选择 {count} 项", - "targetAll": "全部 agent", - "targetSome": "{count} 个 agent", - "enable": "启用", - "disable": "禁用", - "clear": "清除" - }, - "confirm": { - "disableTitle": "禁用这些链接?", - "disableBody": "这将移除 {count} 个由 codeg 管理的技能链接。占用自定义目录的技能不受影响。你可以随时重新启用。", - "cancel": "取消", - "confirm": "禁用" - }, - "toasts": { - "loadFailed": "加载技能状态失败", - "applyFailed": "应用更改失败", - "enabled": "已启用 {count} 个链接", - "disabled": "已禁用 {count} 个链接", - "enabledPartial": "已启用 {ok} 个,{failed} 个失败", - "disabledPartial": "已禁用 {ok} 个,{failed} 个失败" - }, - "detail": { - "enableForAgents": "为 agent 启用", - "preview": "SKILL.md 预览", - "loadingContent": "加载内容中…" - }, - "copyModeHint": "已复制(非链接)——更新后请重新启用以获取最新版本" - }, - "ExpertsSettings": { - "title": "专家技能", - "description": "为 AI 编码代理启用精心挑选、经过实战验证的技能工作流。每个专家都是 superpowers 项目中的独立技能 —— codeg 维护中央副本,并将其软链接到你选择的代理目录。", - "loading": "正在加载专家列表…", - "loadingContent": "正在加载内容…", - "emptyExperts": "当前没有可用的专家,请查看应用日志。", - "emptySelection": "从左侧选择一个专家以查看内容并管理启用状态。", - "emptySearch": "没有匹配当前搜索条件的专家。", - "searchPlaceholder": "按名称、ID 或描述搜索专家", - "enableForAgents": "为代理启用", - "noAgents": "未检测到 ACP 代理。", - "copyModeWarning": "已复制(非软链接)。codeg 更新后需要重新启用以获取最新版本。", - "previewTitle": "SKILL.md 预览", - "categories": { - "discovery": "发现与设计", - "planning": "规划", - "execution": "执行", - "quality": "质量与测试", - "debugging": "调试", - "review": "评审与集成", - "meta": "元技能" - }, - "states": { - "not_linked": "未启用", - "linked_to_codeg": "已启用", - "linked_elsewhere": "冲突 — 已有其他链接", - "blocked_by_real_directory": "冲突 — 已有同名的自定义 skill 占用", - "broken": "链接损坏" - }, - "badges": { - "userModified": "用户修改过" - }, - "actions": { - "openCentralDir": "打开中央目录", - "refresh": "刷新" - }, - "toasts": { - "loadFailed": "加载专家详情失败", - "enabled": "已为该代理启用专家", - "disabled": "已为该代理禁用专家", - "enableFailed": "启用专家失败", - "disableFailed": "禁用专家失败", - "openFolderFailed": "打开目录失败" - } - }, - "ScienceSettings": { - "title": "科学研究技能", - "description": "为你的 AI 编码智能体启用精选的科学研究技能:假设生成、实验设计、统计、可视化、批判性评估与文献检索。codeg 管理中央副本,并将每个技能链接到你选择的智能体。", - "loading": "正在加载科学研究技能…", - "emptySkills": "没有可用的科学研究技能。请检查应用日志。", - "searchPlaceholder": "按名称、ID 或描述搜索科学研究技能", - "categories": { - "ideation": "构思", - "design": "研究设计", - "analysis": "分析", - "visualization": "可视化", - "evaluation": "评估", - "literature": "文献" - }, - "states": { - "not_linked": "未启用", - "linked_to_codeg": "已启用", - "linked_elsewhere": "冲突 — 已有其他链接", - "blocked_by_real_directory": "冲突 — 已有同名的自定义 skill 占用", - "broken": "链接损坏" - }, - "badges": { - "userModified": "用户修改过", - "needsKey": "需要密钥", - "needsSetup": "可能需环境" - }, - "actions": { - "openCentralDir": "打开中央目录", - "refresh": "刷新" - }, - "toasts": { - "openFolderFailed": "打开目录失败" - } - }, - "OfficeToolsSettings": { - "title": "Office 工具", - "description": "管理 OfficeCLI 技能,用于创建 Excel、Word 和 PowerPoint 文件。安装 OfficeCLI,同步技能,并为每个智能体启用。", - "loadingContent": "加载内容中…", - "emptySkills": "暂无技能。请先安装 OfficeCLI 并同步技能。", - "emptySelection": "选择一个技能查看内容和管理激活状态。", - "emptySearch": "没有匹配的技能。", - "searchPlaceholder": "按名称、ID 或描述搜索技能", - "enableForAgents": "为智能体启用", - "noAgents": "未检测到 ACP 智能体。", - "installFirst": "请先安装 OfficeCLI 以启用技能。", - "syncFirst": "请先同步技能以加载内容。", - "noContent": "暂无内容。", - "copyModeWarning": "已复制(非链接)。重新同步以获取最新版本。", - "previewTitle": "SKILL.md 预览", - "detection": { - "installed": "已安装", - "notInstalled": "未安装", - "notRunnable": "已安装但无法运行", - "installHint": "安装 OfficeCLI 以为 AI 智能体启用办公文档生成技能。", - "install": "安装", - "uninstall": "卸载", - "syncSkills": "同步技能" - }, - "categories": { - "general": "通用", - "presentations": "演示文稿", - "documents": "文档", - "spreadsheets": "电子表格" - }, - "states": { - "not_linked": "未启用", - "linked_to_codeg": "已启用", - "linked_elsewhere": "已阻止——存在其他链接", - "blocked_by_real_directory": "已阻止——自定义技能占用此名称", - "broken": "链接已损坏" - }, - "badges": { - "notSynced": "未同步" - }, - "actions": { - "refresh": "刷新" - }, - "toasts": { - "loadFailed": "加载技能详情失败", - "enabled": "已为此智能体启用技能", - "disabled": "已为此智能体禁用技能", - "enableFailed": "启用技能失败", - "disableFailed": "禁用技能失败", - "installSuccess": "OfficeCLI 安装成功", - "installFailed": "安装 OfficeCLI 失败", - "uninstallSuccess": "OfficeCLI 已卸载", - "uninstallFailed": "卸载 OfficeCLI 失败", - "syncSuccess": "已成功同步 {synced} 个技能", - "syncPartial": "已同步 {synced} 个技能,{errors} 个失败", - "syncFailed": "同步技能失败" - }, - "autoPreviewLabel": "自动打开预览", - "autoPreviewHint": "当智能体创建或编辑 Word、Excel、PowerPoint 文件时,自动打开其实时预览。" - }, - "SkillPacksSettings": { - "title": "技能包", - "description": "由 codeg 集中管理、并链接到各 AI 智能体的成套技能——编码专家、科学研究与办公文档工具。可在下方按智能体分别启用。", - "tabs": { - "experts": "专家", - "science": "科学研究", - "office": "办公工具", - "custom": "自定义" - }, - "actions": { - "openCentralDir": "打开中央目录", - "refresh": "刷新" - }, - "toasts": { - "openFolderFailed": "打开目录失败" - } - }, - "QuickMessagesSettings": { - "title": "快捷消息", - "description": "管理可复用的消息片段。拖拽以调整顺序。", - "loading": "加载快捷消息…", - "emptyList": "暂无快捷消息。点击“新建”创建一条。", - "emptySelection": "选择一条快捷消息进行编辑。", - "searchPlaceholder": "按标题或内容搜索", - "untitled": "未命名", - "actions": { - "new": "新建", - "save": "保存", - "delete": "删除", - "dragSort": "拖拽排序", - "dragSortMessage": "拖拽排序快捷消息:{name}" - }, - "fields": { - "title": "标题", - "titlePlaceholder": "为此消息取一个简短的标题", - "content": "内容", - "contentPlaceholder": "在此输入消息内容" - }, - "confirmDelete": { - "title": "删除快捷消息?", - "message": "将永久删除“{name}”。确定吗?", - "cancel": "取消", - "confirm": "删除" - }, - "toasts": { - "loadFailed": "加载快捷消息失败", - "createFailed": "创建快捷消息失败", - "saveFailed": "保存快捷消息失败", - "deleteFailed": "删除快捷消息失败", - "saveOrderFailed": "保存顺序失败", - "created": "已创建快捷消息", - "saved": "已保存快捷消息", - "deleted": "已删除快捷消息" - } - }, - "Pet": { - "badge": { - "running": "{count} 个运行中", - "waiting": "{count} 个待批准", - "error": "{count} 个出错" - }, - "panel": { - "title": "活动会话", - "empty": "没有活动会话", - "emptyHint": "正在运行或需要你处理的会话会显示在这里。", - "statusRunning": "运行中", - "statusWaiting": "等待中", - "statusError": "出错", - "subAgentOf": "子智能体" - }, - "menu": { - "scale": "缩放", - "openManager": "管理宠物", - "close": "关闭" - }, - "loadError": "加载宠物失败", - "missingPetIdParam": "未选中任何宠物", - "summonButton": "宠物", - "manager": { - "title": "桌面宠物", - "description": "悬浮在桌面上的伴侣,使用与 Codex 兼容的精灵图。", - "addPet": "添加宠物", - "importFromCodex": "从 Codex 导入", - "noPets": "暂无宠物。可以添加一只,或从 Codex 导入。", - "setActive": "设为活跃", - "active": "当前活跃", - "edit": "编辑", - "delete": "删除", - "deleteConfirm": "确认删除宠物 \"{name}\" 吗?会从磁盘上一并移除。", - "summon": "召唤宠物窗口", - "openCodexHelp": "Codex 宠物需位于 ~/.codex/pets/ 目录下,但未找到。", - "specRequirement": "精灵图宽度必须为 1536 像素,高度需为 208 像素的整数倍(如 1872 或 2288),并为带透明通道的 PNG 或 WebP。", - "form": { - "id": "宠物 ID", - "idHelp": "仅允许小写字母、数字、'-' 和 '_',最多 64 字符。", - "displayName": "显示名称", - "description": "描述 (可选)", - "spritesheet": "精灵图", - "chooseFile": "选择文件", - "replaceFile": "替换精灵图", - "saveCreate": "添加宠物", - "saveUpdate": "保存修改", - "cancel": "取消" - }, - "errors": { - "missingId": "宠物 ID 不能为空", - "missingName": "显示名称不能为空", - "missingSpritesheet": "必须选择一个精灵图", - "addFailed": "添加宠物失败", - "updateFailed": "更新宠物失败", - "deleteFailed": "删除宠物失败", - "loadFailed": "加载宠物列表失败", - "setActiveFailed": "设置活跃宠物失败", - "summonFailed": "召唤宠物窗口失败" - } - }, - "import": { - "title": "从 Codex 导入", - "subtitle": "在 ~/.codex/pets/ 下找到以下可导入的宠物。", - "selectAll": "全选", - "alreadyImported": "已导入", - "renameOnConflict": "冲突时自动添加 -imported 后缀", - "import": "导入所选", - "noneFound": "未找到可导入的 Codex 宠物。", - "imported": "导入完成", - "failed": "导入失败", - "close": "关闭" - }, - "marketplace": { - "openMarketplace": "宠物市场", - "title": "宠物市场", - "search": "搜索宠物", - "kindFilter": { - "all": "全部", - "object": "物品", - "animal": "动物", - "person": "人物", - "creature": "生物" - }, - "sortFilter": { - "latest": "最新", - "popular": "热门", - "views": "最多浏览" - }, - "refresh": "刷新", - "install": "安装", - "installing": "安装中", - "reinstall": "替换重装", - "reinstallConfirm": "确认覆盖本地宠物 \"{name}\" 吗?现有数据将被替换。", - "cancel": "取消", - "stats": { - "views": "浏览", - "downloads": "下载", - "likes": "点赞" - }, - "actions": { - "idle": "待机", - "running_right": "右跑", - "running_left": "左跑", - "waving": "挥手", - "jumping": "跳跃", - "failed": "失败", - "waiting": "等待", - "running": "运行", - "review": "评审" - }, - "page": "第 {page} / {total} 页", - "prev": "上一页", - "next": "下一页", - "empty": "没有匹配的宠物。", - "successInstalled": "已安装 \"{name}\"", - "errors": { - "loadFailed": "加载市场失败", - "installFailed": "安装失败", - "alreadyInstalled": "该宠物已存在" - } - } - }, - "RemoteWorkspace": { - "openRemoteWorkspace": "打开远端工作区", - "manage": "管理远端工作区", - "manageTitle": "远端工作区连接", - "empty": "暂无远端连接", - "searchPlaceholder": "搜索远端工作区", - "orderFailed": "保存远端工作区排序失败", - "dragSort": "拖拽排序", - "dragSortConnection": "拖拽排序 {name}", - "newConnection": "新建连接", - "loading": "加载中", - "loadingConnection": "正在加载远端连接", - "name": "名称", - "baseUrl": "服务地址", - "token": "访问 Token", - "save": "保存", - "delete": "删除", - "confirmDelete": { - "title": "删除远端连接?", - "message": "这会从当前设备移除“{name}”,此操作不可撤销。", - "cancel": "取消", - "confirm": "删除" - }, - "saved": "远端连接已保存。", - "deleted": "远端连接已删除。", - "loadFailed": "加载远端连接失败", - "saveFailed": "保存远端连接失败", - "deleteFailed": "删除远端连接失败", - "openFailed": "打开远端工作区失败", - "connectionLoadFailed": "加载远端连接失败:{message}", - "connectionExpired": "远端连接“{name}”已失效。请更新 Token 后重新加载此窗口。" - }, - "BackupSettings": { - "title": "备份与恢复", - "description": "导出一份可移植的 codeg 数据备份,或从备份中恢复。", - "tabs": { - "backup": "备份", - "restore": "恢复" - }, - "export": { - "includeExternal": "包含会话内容", - "includeExternalHint": "同时打包各 CLI 的会话记录(Claude、Codex、Gemini 等),体积更大。", - "passphrase": "口令(可选)", - "passphrasePlaceholder": "留空则生成未加密的归档", - "passphraseConfirm": "确认口令", - "passphraseMismatch": "两次输入的口令不一致。", - "noPassphraseWarning": "该备份将以明文包含密钥(API key、token)。请妥善保管。", - "passphraseLossWarning": "将使用此口令加密。口令一旦丢失,备份将无法恢复。", - "button": "导出备份", - "inProgress": "正在创建备份…", - "success": "备份已创建。", - "started": "已开始下载备份。" - }, - "restore": { - "selectFile": "选择备份文件", - "passphrasePrompt": "该备份已加密,请输入其口令。", - "unlock": "解锁", - "preview": { - "title": "备份详情", - "encrypted": "已加密", - "compatible": "兼容", - "incompatible": "不兼容", - "createdAt": "创建时间:{value}", - "appVersion": "应用版本:{value}", - "incompatibleHint": "该备份由更新版本的 codeg 创建,无法恢复。" - }, - "replaceWarning": "恢复将替换当前全部 codeg 数据(数据库与上传文件)。当前数据会先做快照以便回退。", - "keyringNote": "桌面端的 GitHub/聊天 token 存于系统钥匙串,不包含在备份中;恢复后需重新填写。", - "button": "恢复", - "staging": "正在准备恢复…", - "staged": "恢复已就绪,正在重启…", - "restarting": "恢复已就绪,正在重启服务…", - "restartTimeout": "服务未能及时恢复。待其启动后请刷新页面。", - "externalSideLocation": "会话记录已恢复到 {path}", - "confirmTitle": "替换全部数据?", - "confirmBody": "这将用备份替换当前的 codeg 数据库与上传文件,然后重启。当前数据会先做快照。", - "cancel": "取消", - "confirmAction": "替换并重启", - "external": { - "title": "会话内容", - "hint": "该备份包含各 CLI 的会话记录。请选择恢复到何处。", - "modeSkip": "不恢复", - "modeSide": "恢复到安全的旁路目录", - "modeOriginal": "恢复到 CLI 的原始位置", - "forceOverwrite": "覆盖已存在的文件", - "forceOverwriteHint": "替换 CLI 目录中已存在的文件。", - "scanning": "正在检查冲突…", - "noConflicts": "不会覆盖任何已存在的文件。", - "conflictCount": "将影响 {count} 个已存在的文件。", - "conflictSkipNote": "未启用覆盖时,已存在的文件将被保留(跳过)。" - }, - "restartFailed": "恢复已就绪,但服务未能重启。请手动重启以应用此次恢复。" - }, - "remoteUnsupported": "备份与恢复作用于运行 codeg 的那台机器上的数据。你当前连接的是远程工作区——请直接在该服务器上管理其备份。" - }, - "backup": { - "restore": { - "error": { - "badPassphrase": "口令错误或备份已损坏。", - "corrupted": "备份归档已损坏。", - "unknownFormat": "该文件不是可识别的 codeg 备份。", - "newerVersion": "该备份由 codeg {backupVersion} 创建,比当前版本({appVersion})更新。", - "alreadyPending": "已有一个恢复在等待生效。请先重启应用它,再暂存新的恢复。" - } - }, - "error": { - "diskSpace": "磁盘空间不足,无法完成操作。", - "cancelled": "操作已取消。" - } - }, - "WebConnection": { - "disconnectedTitle": "连接已断开", - "reconnectingDescription": "正在尝试重新连接服务器,通常会在几秒内自动恢复。", - "reconnectNow": "立即重连", - "sessionExpiredTitle": "会话已过期", - "sessionExpiredDescription": "登录状态已失效,请重新登录以继续。", - "goToLogin": "前往登录" - }, - "LiveFeedback": { - "placeholder": "在 {agent} 工作时给它留言…", - "agentFallback": "智能体", - "ariaLabel": "实时反馈留言", - "dialogTitle": "实时反馈", - "dialogDescription": "在智能体工作时给它留言。它会在下次检查时读取,不会打断当前步骤。", - "dialogDescriptionInstant": "在智能体工作时给它发一条备注。备注会立即插入当前回合——智能体马上就能看到。", - "channelDowngraded": "本会话无法即时插入——备注已保存,等智能体下次检查时读取。", - "send": "发送", - "cancel": "取消", - "pending": "等待中", - "delivered": "已收到", - "turnEndedUnread": "智能体在读取你的反馈前已结束本轮。", - "sendAsMessage": "作为新消息发送", - "dismiss": "忽略", - "turnEndedResent": "本轮已结束——已改为作为新消息发送。", - "turnEnded": "本轮已结束。", - "submitFailed": "留言发送失败" - }, - "AgentToolsSettings": { - "title": "会话内工具", - "description": "codeg 在会话中额外提供给智能体的工具。工具在智能体启动时注入,改动只对之后启动的智能体生效。", - "feedbackLabel": "实时反馈", - "feedbackHint": "在智能体工作时向它发送备注与纠偏。支持即时插入的智能体会立刻在当前回合中看到你的备注;其他智能体则通过检查反馈的工具读取——这类智能体通常只有在提示词里提到时才会检查,例如在消息中加上“定期检查我的实时反馈”。", - "questionLabel": "向用户提问", - "questionHint": "允许智能体暂停并向你提出多选问题,问题会显示在会话输入框上方。智能体会一直等待,直到你作答(或跳过)。", - "sessionInfoLabel": "获取会话信息", - "sessionInfoHint": "允许智能体查询你在消息中提及的会话(会话徽章),读取其标题、智能体、状态、工作区、Token 用量和最近消息。", - "automationsLabel": "创建自动化", - "automationsHint": "把对话保存为按计划运行的自动化。默认关闭——它之后会自行启动智能体。", - "workTasksLabel": "创建待办任务", - "workTasksHint": "从对话中往待办看板排一张任务卡。默认关闭——它会写入应用状态。", - "save": "保存", - "saving": "保存中…", - "saved": "工具设置已保存", - "saveFailed": "保存工具设置失败", - "loadFailed": "加载失败:{detail}" - }, - "NotificationSoundSettings": { - "title": "提示音", - "description": "智能体事件触发时播放一段简短的提示音。这里的事件与消息渠道推送的完全一致,但设置只对本设备生效。", - "enableHint": "默认关闭。提示音只在当前浏览器或应用的工作区窗口中播放。", - "volume": "音量", - "preview": "试听", - "previewEvent": "试听「{event}」提示音", - "onlyWhenUnfocused": "仅在窗口未聚焦时播放", - "onlyWhenUnfocusedHint": "正在查看 Codeg 时保持静音。", - "eventsTitle": "事件", - "eventsHint": "为每个事件选择一种音效,选择「静音」则不播放。同一事件在数秒内重复触发时只播放一次。", - "toneNone": "静音", - "toneChime": "叮咚", - "toneDing": "清铃", - "toneBlip": "短音", - "tonePop": "轻点", - "toneAlert": "警示", - "toneDescend": "下行音" - }, - "LogsSettings": { - "loading": "加载中…", - "sectionTitle": "运行日志", - "sectionDescription": "查看和配置应用诊断日志。日志会写入本地文件,并保留在内存中以便实时查看。", - "captureTitle": "日志级别", - "captureDescription": "控制记录的详细程度。级别越高(Debug、Trace)记录越多,但日志也越大。“关闭”将停止记录日志。", - "captureLabel": "采集级别", - "levels": { - "off": "关闭", - "error": "错误", - "warn": "警告", - "info": "信息", - "debug": "调试", - "trace": "跟踪" - }, - "viewerTitle": "最近日志", - "viewerDescription": "实时查看最近的日志记录。可按级别筛选或搜索文本。", - "searchPlaceholder": "搜索消息或来源…", - "viewLevels": { - "all": "全部级别", - "error": "错误及以上", - "warn": "警告及以上", - "info": "信息及以上", - "debug": "调试及以上", - "trace": "跟踪及以上" - }, - "pause": "暂停", - "resume": "实时", - "refresh": "刷新", - "clear": "清空", - "openFolder": "打开文件夹", - "shownCount": "已显示 {shown} / {total}", - "empty": "暂无日志。", - "levelSaveFailed": "保存日志级别失败", - "openFolderFailed": "打开日志文件夹失败", - "downloadFailed": "下载日志文件失败", - "filesTitle": "日志文件", - "filesDescription": "从磁盘下载完整日志文件,查看实时缓冲区之外的历史记录。", - "filesEmpty": "暂无日志文件。", - "download": "下载", - "downloadTruncated": "文件较大,已下载最新的 {size}。完整文件请在日志目录中查看。", - "captureEnvLocked": "日志级别由 RUST_LOG / CODEG_LOG 环境变量控制;请在该处修改以生效。", - "targetsTitle": "按模块覆盖", - "targetsDescription": "为特定模块(如 codeg_lib::acp)单独设置级别,不影响全局级别。", - "targetsAdd": "添加", - "targetsRemove": "移除覆盖", - "toggleDetails": "切换详情" - }, - "Automations": { - "title": "自动化", - "new": "新建自动化", - "empty": "暂无自动化", - "emptyHint": "创建一个,让智能体按计划或手动执行任务。", - "name": "名称", - "namePlaceholder": "例如:每晚 PR 审查", - "prompt": "提示词", - "promptPlaceholder": "让智能体做什么?", - "agent": "智能体", - "folder": "工作区文件夹", - "folderPlaceholder": "选择文件夹", - "isolation": "隔离方式", - "isolationWorktree": "每次运行新建 worktree", - "isolationShared": "在文件夹内运行", - "isolationSharedCaveat": "运行会直接使用该文件夹的工作树,可能与你未提交的改动冲突。勾选每次运行新建工作树以隔离每次运行。", - "trigger": "触发方式", - "triggerSchedule": "按计划", - "triggerManual": "仅手动", - "cron": "计划(cron)", - "cronPlaceholder": "0 9 * * 1-5", - "timezone": "时区", - "nextRun": "下次运行", - "branch": "分支", - "branchOptional": "分支(可选)", - "enabled": "已启用", - "save": "保存", - "cancel": "取消", - "edit": "编辑", - "delete": "删除", - "runNow": "立即运行", - "cancelRun": "取消运行", - "runHistory": "运行历史", - "noRuns": "暂无运行记录", - "allFolders": "所有文件夹", - "filterAll": "全部", - "noMatches": "没有匹配的自动化", - "viewConversation": "查看会话", - "lastRun": "上次运行", - "never": "从未", - "running": "运行中", - "deleteTitle": "删除此自动化?", - "deleteDescription": "这将删除该自动化及其计划。运行历史会保留。", - "statusRunning": "运行中", - "statusSucceeded": "成功", - "statusFailed": "失败", - "statusCancelled": "已取消", - "statusSkipped": "已跳过", - "errorName": "名称必填", - "errorPrompt": "提示词必填", - "errorCron": "按计划的自动化需要 cron 表达式", - "errorFolder": "请选择工作区文件夹", - "presetHourly": "每小时", - "presetDaily": "每天 9 点", - "presetWeekdays": "工作日 9 点", - "presetCustom": "自定义", - "probing": "正在加载选项…", - "retry": "重试", - "configNone": "该智能体没有可配置项", - "inherit": "智能体默认", - "mode": "模式", - "config": "配置", - "branchPlaceholder": "(默认分支)", - "selectHint": "选择一个自动化以查看详情", - "refresh": "刷新", - "onboardTitle": "自动化日常智能体任务", - "onboardHint": "安排智能体定时或按需审查代码、更新依赖或处理问题。", - "headerSubtitle": "定时与按需的智能体任务", - "startFromTemplate": "从模板开始", - "blankTitle": "空白自动化", - "blankDesc": "从零配置一个智能体任务。", - "backToTemplates": "模板", - "sectionSchedule": "计划与目标", - "sectionTarget": "运行目标", - "sectionAction": "动作", - "actionLaunchSession": "启动会话", - "actionEnqueueTask": "任务入队", - "actionEnqueueTaskHint": "每次触发都会在目标文件夹的待办任务里加入一个待办任务(标题为本自动化名称),由任务引擎按看板设置执行。", - "sectionPrompt": "提示词", - "nextIn": "{rel}后运行", - "manual": "手动", - "schedEveryMinutes": "每 {n} 分钟", - "schedHourly": "每小时", - "schedDaily": "每天 {time}", - "schedWeekdays": "工作日 {time}", - "schedWeekly": "每{day} {time}", - "schedMonthly": "每月 {day} 日 {time}", - "dow0": "周日", - "dow1": "周一", - "dow2": "周二", - "dow3": "周三", - "dow4": "周四", - "dow5": "周五", - "dow6": "周六", - "tplCodeReviewTitle": "代码审查", - "tplCodeReviewDesc": "审查最近的改动,查找缺陷、回归和质量问题。", - "tplDependencyUpdatesTitle": "依赖更新", - "tplDependencyUpdatesDesc": "查找过时的依赖并提出安全的升级方案。", - "tplTestCoverageTitle": "测试覆盖", - "tplTestCoverageDesc": "找出未覆盖的代码路径并补充缺失的测试。", - "tplTodoSweepTitle": "TODO 清理", - "tplTodoSweepDesc": "收集 TODO 和 FIXME 注释并按优先级整理。", - "tplCiTriageTitle": "CI 排查", - "tplCiTriageDesc": "排查最近失败的检查并提出修复方案。", - "tplReleaseNotesTitle": "发布说明", - "tplReleaseNotesDesc": "汇总自上次发布以来的改动,生成更新日志。", - "tplSecurityAuditTitle": "安全审计", - "tplSecurityAuditDesc": "扫描漏洞和风险模式,并报告发现的问题。", - "enable": "启用", - "disable": "停用", - "moreActions": "更多操作", - "statusDisabled": "已停用", - "cronBuilderTitle": "计划生成器", - "cronFreqLabel": "频率", - "cronFreqMinutes": "每 N 分钟", - "cronFreqHourly": "每小时", - "cronFreqDaily": "每天", - "cronFreqWeekdays": "工作日", - "cronFreqWeekly": "每周", - "cronFreqMonthly": "每月", - "cronFreqCustom": "自定义", - "cronEveryLabel": "间隔(分钟)", - "cronTimeLabel": "时间", - "cronHourLabel": "小时", - "cronMinuteLabel": "分钟", - "cronDowLabel": "星期", - "cronDomLabel": "日期", - "cronApply": "应用", - "cronPreviewLabel": "预览", - "cronOpenBuilder": "打开计划生成器", - "branchDefault": "默认分支", - "branchUseCustom": "使用 “{query}”", - "branchLocal": "本地", - "branchRemote": "远程", - "branchSearchPlaceholder": "搜索分支…", - "branchNone": "无分支" - }, - "Tasks": { - "title": "待办任务", - "new": "新建任务", - "empty": "还没有任务", - "emptyHint": "添加待办后即可处理——agent 在独立 worktree 中工作,你验收并合并结果。", - "emptyColTodo": "还没有待办任务", - "emptyColInProgress": "暂无进行中的任务", - "emptyColAttention": "暂无等你处理的任务", - "emptyColDone": "还没有已完成的任务", - "allFolders": "全部文件夹", - "showCanceled": "显示已取消", - "showArchived": "显示已归档", - "filter": "筛选", - "viewSwitchToBoard": "切换到看板视图", - "viewSwitchToList": "切换到列表视图", - "statusFilter": "状态", - "statusFilterAll": "全部状态", - "listEmpty": "没有符合当前筛选条件的任务", - "listColStatus": "状态", - "listColTask": "任务", - "listColLocation": "位置", - "listColChanges": "变更", - "listColUpdated": "更新", - "colTodo": "待办", - "colInProgress": "进行中", - "colAttention": "等你处理", - "colDone": "已完成", - "statusTodo": "待办", - "statusQueued": "排队中", - "statusPreparing": "初始化中", - "statusRunning": "进行中", - "statusAwaitingInput": "等待输入", - "statusReview": "待验收", - "statusMerging": "合并中", - "statusDone": "已完成", - "statusFailed": "失败", - "statusCanceled": "已取消", - "statusInterrupted": "已中断", - "badgeCleanupFailed": "清理失败", - "badgeWorktreeKept": "保留 worktree", - "badgeWorktreeRemoved": "Worktree 已删除", - "filesChanged": "{count} 个文件", - "actionStart": "开始", - "actionSchedule": "定时运行", - "actionCancel": "取消", - "actionRetry": "重试", - "actionRequeue": "重新排队", - "actionViewSession": "查看会话", - "actionEdit": "编辑", - "actionDelete": "删除", - "actionRetryCleanup": "重试清理", - "actionMerge": "合并", - "actionUnqueueMerge": "取消排队", - "actionEditQueuedMerge": "修改排队的合并", - "badgeMergeQueued": "排队合并中", - "badgeMergeQueuedRank": "排队合并 · 第 {rank} 位", - "badgeMergeQueuedHint": "正在等待该项目当前的合并完成,轮到时会自动开始。", - "actionComplete": "完成", - "actionAbandon": "放弃", - "cancelTitle": "取消任务?", - "cancelDescription": "任务将变为已取消。worktree 会保留,之后可以重新排队。", - "cancelReasonLabel": "取消原因(可选)", - "cancelReasonPlaceholder": "例如:方向不对,我重写一下任务描述", - "cancelKeep": "先不取消", - "cancelSubmit": "取消任务", - "restartTitleRetry": "重试任务", - "restartTitleRequeue": "重新排队", - "restartDescription": "可以补充一段说明(可选),它会随下一轮的提示词一起发给 agent。", - "scheduleTitle": "定时运行任务", - "scheduleDescription": "任务留在「待办」,到点自动开始。文件夹的并发上限依然生效。", - "scheduleDateLabel": "日期", - "schedulePickDate": "选择日期", - "scheduleTimeLabel": "时间", - "schedulePreview": "{time} 运行", - "schedulePastHint": "该时间已过——保存后会立即开始。", - "scheduleInAnHour": "1 小时后", - "scheduleInThreeHours": "3 小时后", - "scheduleTomorrow": "明天 9:00", - "scheduleClear": "清除定时", - "scheduleBadge": "计划于 {time} 开始", - "toastScheduled": "已定时:{time}", - "toastScheduleCleared": "已清除定时", - "actionFollowUp": "继续处理", - "actionAddNote": "补充说明", - "followUpSubmit": "发送", - "followUpIntentRevise": "修改返工", - "followUpIntentContinue": "继续推进", - "followUpIntentQuestion": "提问答疑", - "followUpIntentVerify": "自查验证", - "followUpPlaceholderRevise": "希望 agent 改哪里?会在同一会话里继续。", - "followUpPlaceholderContinue": "接下来还要做什么?已有的工作会保留。", - "followUpPlaceholderQuestion": "想了解什么?agent 只回答,不会改动任何文件。", - "followUpPlaceholderVerify": "可选:有什么想让它重点检查的?", - "followUpPlaceholderRetry": "可选:这次要怎么做才不一样?例如:先跑 pnpm install", - "followUpPlaceholderRequeue": "可选:当时为什么取消?这次要注意什么?", - "actionArchive": "归档", - "actionUnarchive": "取消归档", - "archiveAllDone": "全部归档", - "dropToStart": "松开即开始执行", - "errorView": "查看", - "notifyReview": "待验收:{title}", - "notifyFailed": "任务失败:{title}", - "createFromMessage": "由此消息创建任务", - "detailTokens": "总 token 用量", - "editorTitleNew": "新建任务", - "editorTitleEdit": "编辑任务", - "templates": "模板", - "templatesEmpty": "还没有模板。", - "templateSaveCurrent": "把当前内容存为模板", - "templateDelete": "删除模板", - "transcriptTitle": "任务会话", - "transcriptDescription": "任务智能体会话的只读实时视图。", - "phaseWork": "任务执行", - "phaseRetry": "重试执行", - "phaseReturn": "继续处理", - "phaseMerge": "合并变更", - "titleLabel": "标题", - "titlePlaceholder": "要做什么?", - "promptLabel": "任务描述", - "promptPlaceholder": "向 agent 描述任务——输入 @ 可引用文件,/ 可唤起命令", - "folderPlaceholder": "选择文件夹", - "agentInheritedHint": "继承自任务设置,修改后仅对本任务生效", - "agentOverrideReset": "恢复继承", - "sectionTarget": "目标", - "errorTitle": "请输入标题", - "errorPrompt": "请输入任务描述", - "errorFolder": "请选择文件夹", - "save": "保存", - "cancel": "取消", - "mergeTitle": "合并任务", - "mergeQueuedTitle": "排队中的合并", - "mergeQueueHint": "该项目正在合并另一个任务。此任务会加入队列,等前一个完成后自动开始。", - "mergeQueueUpdateHint": "该任务已在合并队列中。提交将更新它的合并选项,并保留原有的排队位置。", - "mergeDescription": "将 {branch} 合并到 {base}。worktree 中未提交的变更会先自动提交。", - "mergeMessage": "提交信息", - "mergeMessagePlaceholder": "例如 feat: add login validation", - "mergeAutoMessage": "让 agent 自动生成提交信息", - "strategySquash": "合并为一条提交", - "strategySquashHint": "任务的所有修改压缩成一条提交记录并入主分支,历史更简洁。", - "strategyMerge": "保留完整提交历史", - "strategyMergeHint": "保留任务过程中的每一条提交,另加一条合并记录,每一步都可追溯。", - "mergeDeleteWorktree": "合并后删除 worktree", - "mergeSubmit": "合并", - "mergeSubmitQueue": "加入合并队列", - "mergeQueuedToast": "已加入合并队列,等当前合并完成后自动开始。", - "completeTitle": "完成任务", - "completeDescription": "该任务没有改动任何文件,无需合并,将直接标记为已完成。", - "completeDescriptionNoWorktree": "该任务的 worktree 已被删除,无法再合并,将直接标记为已完成。若工作分支上仍有未合并的提交,分支会被保留。", - "completeDeleteWorktree": "完成后删除 worktree", - "completeSubmit": "完成", - "settingsTitle": "任务设置", - "settingsDescription": "{folder} 中任务的默认配置。", - "settingsScope": "作用域", - "settingsScopeGlobal": "全部文件夹(全局默认)", - "settingsScopeGlobalHint": "未单独设置的文件夹将使用这份全局默认配置。", - "settingsSource": "配置来源", - "settingsSourceGlobal": "使用全局默认", - "settingsSourceCustom": "单独配置", - "settingsSourceGlobalFollow": "跟随全局任务设置,全局改动会自动生效。", - "settingsSourceCustomHint": "为此文件夹保存独立设置,不再跟随全局默认。", - "settingsAgent": "默认 agent", - "settingsMaxConcurrent": "最大并发任务数", - "settingsMaxConcurrentHint": "0 表示不限制", - "settingsAutoProcess": "自动处理", - "settingsAutoProcessHint": "待办任务自动开始处理,受并发上限约束。", - "settingsMergeStrategy": "默认合并策略", - "settingsMergeStrategyHint": "合并任务时,这些修改在分支历史里如何记录。", - "settingsAutoMerge": "自动合并", - "settingsAutoMergeHint": "任务进入待验收且有可合并改动时自动落地,与点击「合并」相同:提交信息由 agent 自动生成,是否删除 worktree 沿用下方默认。预检未通过或合并失败的任务会留下等你处理。", - "settingsDeleteWorktree": "合并后删除 worktree", - "settingsDeleteWorktreeHint": "合并对话框里默认勾选,仍可临时改。", - "settingsWorktreeRoot": "Worktree 位置", - "settingsWorktreeRootHint": "新任务的 worktree 创建在该目录下,每个任务一个。留空则创建在项目文件夹的同级目录;「~」表示主目录,相对路径相对于项目文件夹。", - "settingsWorktreeRootPlaceholder": "~/codeg-worktrees", - "settingsWorktreeRootBrowse": "选择 worktree 目录", - "settingsPreflight": "预检命令", - "settingsPreflightHint": "任务进入待验收时在 worktree 中运行。", - "settingsPreflightCustomPlaceholder": "pnpm test", - "settingsInitCommand": "Worktree 初始化命令", - "settingsInitCommandHint": "新建 worktree 后、会话开始前执行。", - "settingsInitCommandPlaceholder": "pnpm install", - "settingsTabGeneral": "常规", - "settingsTabMerge": "合并", - "settingsTabWorktree": "Worktree", - "settingsTabPrompts": "提示词", - "settingsPromptsIntro": "每个阶段都已内置固定的提示词——任务本身、worktree 规则,合并阶段还包含具体的 git 步骤。这里填的内容会作为补充说明追加到末尾:只是对内置提示词的细化,不会替换它们。", - "settingsPromptStageAll": "全部阶段", - "settingsPromptPlaceholderAll": "例如:遵循 AGENTS.md 里的项目约定;始终用中文回复", - "settingsPromptPlaceholderWork": "例如:先读相关测试;小步提交,边做边交", - "settingsPromptPlaceholderRetry": "例如:先看清楚已经提交了哪些改动再继续,别重做已完成的部分", - "settingsPromptPlaceholderReturn": "例如:逐条处理提到的每一点;不要顺手重构无关代码", - "settingsPromptPlaceholderMerge": "例如:最终合并的提交信息用中文;手动解决过的冲突要单独说明", - "settingsPromptHintAll": "追加到每一次发给 agent 的提示词,包括合并那一轮。", - "settingsPromptHintWork": "任务首次执行时追加。", - "settingsPromptHintRetry": "重试被中断或失败的任务时追加。", - "settingsPromptHintReturn": "对待验收的任务继续处理时追加(返工、追加工作、自查)。", - "settingsPromptHintMerge": "agent 把任务合并到基线分支时追加。", - "preflightPassed": "{name} 通过", - "preflightFailed": "{name} 未通过", - "preflightRunning": "{name} 运行中…", - "detailDescription": "任务详情", - "detailSummary": "结果", - "detailFiles": "变更文件", - "detailDiffAll": "查看全部差异", - "detailDiffAllTitle": "全部差异", - "detailNoChanges": "相对基准还没有变更", - "detailTimeline": "推进记录", - "detailTimelineEmpty": "暂无活动", - "showMore": "展开", - "showLess": "收起", - "detailInfo": "详情", - "detailBranch": "分支", - "detailMergeCommit": "合并提交", - "detailChanges": "变更", - "detailScheduled": "计划开始", - "detailCreated": "创建时间", - "detailStarted": "开始时间", - "detailFinished": "完成时间", - "diffLoading": "正在加载差异…", - "deleteConfirmTitle": "删除任务?", - "deleteConfirmBody": "「{title}」将从看板移除。进行中的运行会先被取消。", - "deleteWithWorktree": "同时删除其 worktree", - "eventCreated": "已创建", - "eventStatusChanged": "状态变更", - "eventConfigEffective": "启动配置", - "eventInitCommand": "初始化命令", - "eventAgentProgress": "Agent 进展", - "eventAgentVerdict": "Agent 结论", - "eventMergeAttempt": "开始合并", - "eventMergeQueued": "加入合并队列", - "eventMergeConflict": "合并冲突", - "eventPreflight": "预检", - "eventCleanupFailed": "worktree 清理失败", - "eventResumeFallback": "会话恢复失败,已改用新会话", - "eventUserAction": "用户操作", - "eventDiffStat": "变更快照" - }, - "CustomSkillsSettings": { - "loading": "正在加载自定义技能…", - "category": "自定义", - "searchPlaceholder": "按名称、ID 或描述搜索自定义技能", - "states": { - "not_linked": "未启用", - "linked_to_codeg": "已启用", - "linked_elsewhere": "链接到其他位置", - "blocked_by_real_directory": "被同名真实目录占用", - "broken": "链接已失效" - }, - "actions": { - "new": "新建", - "import": "导入", - "importFromAgent": "从 Agent 导入", - "cancel": "取消", - "save": "保存" - }, - "rowMenu": { - "edit": "编辑", - "duplicate": "复制为新技能", - "delete": "删除" - }, - "bulk": { - "delete": "删除所选" - }, - "editor": { - "createTitle": "新建自定义技能", - "editTitle": "编辑自定义技能", - "description": "自定义技能存放在共享库(~/.codeg/skills),可为任意智能体启用。", - "idLabel": "技能 ID", - "idPlaceholder": "例如 my-workflow", - "contentLabel": "SKILL.md", - "contentPlaceholder": "在此编写技能的 SKILL.md…", - "preview": "预览", - "edit": "编辑", - "emptyBody": "暂无内容。" - }, - "duplicate": { - "title": "复制技能", - "description": "以「{id}」为模板,用新 ID 创建一份副本。", - "newIdPlaceholder": "新技能 ID", - "confirm": "复制" - }, - "import": { - "title": "选择要导入的技能文件夹" - }, - "importFromAgent": { - "title": "从 Agent 导入技能", - "description": "把某个 Agent 自己的技能复制到共享库,即可为任意 Agent 启用。", - "agentLabel": "Agent", - "agentPlaceholder": "选择一个 Agent", - "selectAll": "全选({count})", - "loading": "正在加载该 Agent 的技能…", - "unsupported": "该 Agent 未提供技能目录。", - "empty": "该 Agent 没有可导入的技能。", - "alreadyInLibrary": "已在库中", - "confirm": "导入所选({count})" - }, - "delete": { - "title": "删除自定义技能?", - "body": "将从中央库移除 {count} 个自定义技能,并解除它们在所有智能体中的链接。此操作不可撤销。", - "confirm": "删除" - }, - "toasts": { - "loadFailed": "加载技能失败", - "idRequired": "请输入技能 ID", - "created": "已创建自定义技能", - "updated": "已更新自定义技能", - "saveFailed": "保存技能失败", - "imported": "已导入技能", - "importFailed": "导入技能失败", - "duplicated": "已复制技能", - "duplicateFailed": "复制技能失败", - "deleted": "已删除 {count} 个技能", - "deletedPartial": "已删除 {ok} 个,{failed} 个失败", - "deleteFailed": "删除技能失败", - "importedFromAgent": "已导入 {count} 个技能", - "importedFromAgentPartial": "已导入 {ok} 个,{failed} 个失败", - "importFromAgentAllSkipped": "无需导入——{count} 个已在库中", - "importFromAgentFailed": "从 Agent 导入失败" - } - }, - "CodexModelEditor": { - "customizedNotice": "你已自定义模型列表,codeg 将接管 codex 的完整模型表。codex 日后新增的官方模型不会自动出现——点击下方刷新并重新保存即可同步。清空全部自定义即可交回 codex 自动更新。", - "officialsTitle": "官方模型", - "officialsHint": "自动纳入你启动的 codex 的官方模型;可删除不需要的。", - "officialsEmpty": "暂无官方模型。", - "refresh": "从 codex 刷新", - "readdOfficial": "重新加入官方", - "customsTitle": "自定义模型", - "customsEmpty": "暂无自定义模型。", - "addCustom": "添加自定义", - "slugPlaceholder": "模型 id(slug)", - "displayNamePlaceholder": "显示名", - "contextWindow": "上下文", - "makeDefault": "设为默认", - "defaultHint": "默认模型", - "remove": "删除", - "advanced": "高级", - "baseTemplate": "基础模板", - "baseTemplateHint": "从哪个官方模型克隆必填字段(系统提示词、工具、限制)。", - "groupBehavior": "行为与能力", - "fieldReasoningLevel": "默认推理强度", - "fieldReasoningSummary": "推理摘要", - "fieldVerbosity": "详细程度", - "fieldShellType": "Shell 类型", - "fieldApplyPatch": "应用补丁工具", - "fieldReasoningSummaries": "推理摘要支持", - "fieldSupportVerbosity": "详细程度控制", - "fieldParallelToolCalls": "并行工具调用", - "fieldSearchTool": "联网搜索工具", - "optNone": "无", - "groupInstructions": "描述与系统提示词", - "fieldDescription": "描述", - "baseInstructions": "系统提示词(base_instructions)" - }, - "DiagnosticsSettings": { - "title": "环境诊断", - "description": "检查本应用在自身进程中如何解析该智能体的 CLI——这可能与你的终端不同。", - "loading": "正在运行诊断…", - "error": "诊断失败", - "rerun": "重新运行", - "copyAll": "复制全部", - "copied": "诊断信息已复制到剪贴板", - "button": "诊断", - "verdict": { - "ok": "环境正常。若仍提示未安装,请彻底重启应用以刷新前缀缓存。", - "node_missing": "在应用的 PATH 上未找到 Node.js。", - "npm_missing": "在应用的 PATH 上未找到 npm。", - "not_installed": "该智能体似乎尚未安装。", - "installed_but_unresolved": "记录显示已安装,但应用无法定位其可执行文件。", - "user_prefix_not_on_path": "安装到了回退前缀(~/.codeg/npm-global),但它不在应用的 PATH 上。请彻底重启应用后重试。", - "homebrew_bin_not_on_path": "安装在 Homebrew 的 bin 目录下,但它不在应用的 PATH 上(Apple Silicon keg 拆分)。", - "terminal_only_path": "该命令在你的终端能解析,但在应用中不能——这是 GUI PATH 差异。请从终端启动应用,或在智能体设置中重新安装。", - "npm_prefix_timeout": "npm prefix -g 太慢(超过 1.5 秒),已跳过回退检测。请重启应用后重试。", - "node_too_old": "当前 Node.js 版本低于该智能体的要求。请升级 Node.js。", - "adapter_missing_native_present": "你本地的 {agent} CLI 确实装了,但 Codeg 启动的是另一个 ACP 适配器包,而它还没装。到「智能体设置」里安装即可 —— 它不会动你的 CLI,登录状态也是共享的。", - "adapter_missing": "Codeg 为 {agent} 启动的是单独的 ACP 适配器包,目前尚未安装。请到「智能体设置」里安装 —— 只装厂商 CLI 是不够的。" - } - }, - "TokenUsage": { - "title": "Token 用量", - "rangeLabel": "时间范围", - "range7d": "近 7 天", - "range30d": "近 30 天", - "range90d": "近 90 天", - "rangeThisMonth": "本月", - "rangeThisYear": "今年", - "rangeAll": "全部", - "rangeCustom": "自定义", - "moreRanges": "更多", - "customRangePick": "选择日期范围", - "bucketLabel": "统计粒度", - "bucketDay": "按天", - "bucketWeek": "按周", - "bucketMonth": "按月", - "bucketUnitDay": "天", - "bucketUnitWeek": "周", - "bucketUnitMonth": "月", - "folderFilter": "文件夹", - "allFolders": "全部文件夹", - "agentFilter": "智能体", - "allAgents": "全部智能体", - "modelFilter": "模型", - "allModels": "全部模型", - "searchPlaceholder": "搜索…", - "noMatches": "没有匹配项", - "clearFilter": "清除选择", - "resetFilters": "重置筛选", - "refresh": "刷新数据", - "rebuild": "全量重建", - "rebuildHint": "丢弃已统计的数据并重新解析全部会话记录。会话被 codeg 之外的 CLI 追加过时用它。", - "syncing": "正在统计会话…", - "syncProgress": "{done} / {total}", - "syncDone": "已统计 {synced} 个会话", - "syncFailed": "部分会话读取失败", - "syncBusy": "已有一次刷新在进行中", - "lastSynced": "更新于 {time}", - "lastSyncedNever": "尚未统计", - "tileTotal": "总 Token", - "tileSessions": "会话数", - "tileTurns": "对话轮次", - "tileActiveDays": "活跃天数", - "tileGenTime": "生成时长", - "vsPrevious": "对比上一周期", - "deltaNew": "新增", - "trendTitle": "用量趋势", - "trendEmpty": "该范围内没有用量", - "trendTurns": "轮次", - "trendSessions": "会话", - "compositionTitle": "Token 都花在哪", - "compositionHint": "输入是你发出去的内容,输出是模型写回来的,缓存读取则是不必再按原价重发的上下文。", - "compositionNote": "这些缓存命中若按原价重发,要多花 {value}。", - "inputTokens": "输入", - "outputTokens": "输出", - "cacheWrite": "缓存写入", - "cacheRead": "缓存读取", - "freshTokens": "新算 Token", - "cacheHitCaption": "缓存命中", - "cacheHeroTitleHigh": "上下文大多不必重发", - "cacheHeroTitleLow": "多数上下文仍按原价计算", - "cacheHeroDesc": "{cached} 的上下文由缓存承担,这段时间真正新算的只有 {fresh}。", - "cacheSavedSuffix": "省下的重发量相当于 {saved}。", - "avgPerSession": "平均每会话", - "avgTurnsPerSession": "平均每会话 {count} 轮", - "avgPerActiveDay": "平均每活跃日", - "peakBucket": "最高的一{bucket}", - "peakHour": "高峰时段", - "daysValue": "{count} 天", - "idleDays": "空转天数", - "byFolderTitle": "按文件夹", - "byAgentTitle": "按智能体", - "byModelTitle": "按模型", - "distributionTitle": "用量分布", - "distributionHint": "会话与 Token 按所选维度归集,点任意一行可按它筛选。", - "otherLabel": "其他", - "unknownModel": "未标注模型", - "emptyBreakdown": "还没有记录", - "sessionsCount": "{count} 个会话", - "heatmapTitle": "你的编码作息", - "heatmapHint": "按本地星期与小时统计的 Token 分布。", - "heatmapPeakHint": "最密集的时段在 {hour}:00 前后。", - "less": "少", - "more": "多", - "heatmapCell": "{weekday} {hour}:00 — {value} tokens", - "weekMon": "一", - "weekTue": "二", - "weekWed": "三", - "weekThu": "四", - "weekFri": "五", - "weekSat": "六", - "weekSun": "日", - "topSessionsTitle": "消耗最高的会话", - "untitledSession": "未命名会话", - "topSessionsEmpty": "该范围内没有会话", - "streakLongest": "最长连续", - "streakLongestDays": "最长连续 {count} 天", - "share": "分享", - "moreActions": "更多操作", - "shareDialogTitle": "分享你的用量卡片", - "shareDialogHint": "卡片内容就是你当前所选的时间范围与筛选条件。", - "shareSave": "保存图片", - "shareCopy": "复制图片", - "shareCopied": "已复制到剪贴板", - "shareSaved": "图片已保存", - "shareFailed": "图片生成失败", - "shareRendering": "生成中…", - "cardHeading": "我的 AI 编码战绩", - "cardRangeAll": "全部时间", - "cardTotalLabel": "累计 Token", - "cardFooter": "由 codeg 生成", - "cardTopModels": "常用模型", - "cardTopProjects": "主力项目", - "archetypeNightOwl": "深夜码农", - "archetypeNightOwlDesc": "{percent}% 的 Token 烧在天黑之后。", - "archetypeEarlyBird": "清晨型选手", - "archetypeEarlyBirdDesc": "{percent}% 的 Token 在早上 9 点前就用掉了。", - "archetypeWeekendWarrior": "周末战士", - "archetypeWeekendWarriorDesc": "{percent}% 的 Token 发生在周末。", - "archetypeCacheMaster": "缓存大师", - "archetypeCacheMasterDesc": "{percent}% 的上下文来自缓存。", - "archetypeMarathoner": "长跑选手", - "archetypeMarathonerDesc": "连续 {days} 天没有断更。", - "archetypePolyglot": "多面手", - "archetypePolyglotDesc": "{count} 个智能体都在主力使用。", - "archetypeLaserFocus": "专注一役", - "archetypeLaserFocusDesc": "{percent}% 的 Token 投在同一个项目上。", - "archetypeDeepDiver": "深潜者", - "archetypeDeepDiverDesc": "平均每个会话 {averageK}K tokens。", - "archetypeSteady": "稳定输出", - "archetypeSteadyDesc": "累计 {days} 天在写代码。", - "emptyTitle": "还没有可统计的数据", - "emptyHint": "codeg 直接从各智能体自己的会话记录里读取 Token 数。点一下刷新,把本机已有的会话统计进来。", - "emptyAction": "统计我的会话", - "loadFailed": "用量加载失败", - "truncatedNotice": "该范围过大 —— 下面的数字只覆盖了其中最近的一段。" - } -} +{ + "Language": { + "followSystem": "跟随系统", + "english": "英语", + "simplifiedChinese": "简体中文", + "traditionalChinese": "繁體中文", + "japanese": "日语", + "korean": "韩语", + "spanish": "西班牙语", + "german": "德语", + "french": "法语", + "portuguese": "葡萄牙语", + "arabic": "阿拉伯语" + }, + "GitCredentialDialog": { + "title": "需要身份验证", + "description": "远程服务器要求输入凭据。请输入用户名和密码(或个人访问令牌)。", + "username": "用户名", + "usernamePlaceholder": "用户名或邮箱", + "password": "密码 / 令牌", + "passwordPlaceholder": "密码或个人访问令牌", + "passwordHint": "请输入服务器的用户名和密码。", + "cancel": "取消", + "authenticate": "认证", + "authenticating": "认证中...", + "invalidCredentials": "凭据无效,请重试。", + "saveCredentials": "保存凭据以供后续操作使用", + "githubTitle": "GitHub 身份验证", + "githubDescription": "输入个人访问令牌以连接 GitHub。令牌验证成功后将自动保存到账号列表。", + "githubToken": "个人访问令牌", + "githubTokenPlaceholder": "ghp_xxxxxxxxxxxx", + "githubTokenHint": "在 GitHub → Settings → Developer settings → Personal access tokens 中生成令牌。", + "githubAuthenticate": "验证并连接", + "generateToken": "生成令牌" + }, + "SettingsShell": { + "title": "设置", + "preferences": "偏好设置", + "nav": { + "general": "常规", + "appearance": "外观", + "agents": "智能体", + "mcp": "MCP", + "skills": "Skills", + "shortcuts": "快捷键", + "version_control": "版本控制", + "system": "系统", + "chat_channels": "消息渠道", + "web_service": "Web 服务", + "model_providers": "模型供应商", + "experts": "专家", + "science": "科学研究", + "office_tools": "办公工具", + "skill_packs": "技能包", + "quick_messages": "快捷消息", + "logs": "运行日志" + } + }, + "AppearanceSettings": { + "sectionTitle": "主题外观", + "sectionDescription": "选择浅色、深色或跟随系统主题,设置会自动保存。", + "themeMode": "主题模式", + "placeholder": "请选择主题模式", + "system": "跟随系统", + "light": "浅色", + "dark": "深色", + "currentTheme": "当前生效主题:{theme}", + "resolvedTheme": { + "light": "浅色", + "dark": "深色", + "unknown": "未知" + }, + "themeColor": { + "sectionTitle": "主题颜色", + "sectionDescription": "选择按钮、强调色和高亮使用的色调。", + "current": "当前颜色:{color}", + "options": { + "neutral": "Neutral", + "zinc": "Zinc", + "slate": "Slate", + "stone": "Stone", + "gray": "Gray", + "red": "Red", + "rose": "Rose", + "orange": "Orange", + "green": "Green", + "blue": "Blue", + "yellow": "Yellow", + "violet": "Violet" + } + }, + "customStyle": { + "sectionTitle": "自定义样式", + "sectionDescription": "在当前主题的基础上微调配色,或写入自己的 CSS。覆盖叠加在基底预设之上,切换预设后依然保留。", + "summarySuspended": "已停用", + "summaryDefault": "跟随预设", + "summaryTokens": "{count, plural, other {# 项覆盖}}", + "summaryCss": "自定义 CSS", + "suspendedByShortcut": "自定义样式已停用。在恢复之前,这里的设置都不会生效。", + "suspendedBySafeParam": "本窗口以安全外观模式打开,自定义样式在此不生效,其它窗口不受影响。", + "resume": "恢复自定义样式", + "enableTheme": "启用自定义配色", + "editingLight": "正在编辑浅色模式的取值。切换到深色模式可单独设置深色。", + "editingDark": "正在编辑深色模式的取值。切换到浅色模式可单独设置浅色。", + "resetToken": "恢复为预设取值", + "radius": "圆角", + "radiusHint": "从 sm 到 4xl 的整套圆角尺寸都由它派生,一个滑块即可改变全局圆角。", + "advanced": "高级(另有 {count} 个变量)", + "enableCss": "启用自定义 CSS", + "cssRisk": "高级功能。自定义 CSS 会压过所有内置样式,写坏可能导致界面不可用。", + "editCss": "编辑 CSS…", + "cssPresent": "已保存 {size} KB", + "cssEmpty": "尚未保存内容", + "escapeHint": "界面被改坏了?按 {shortcut} 可停用全部自定义样式,也可以用 safeStyle=1 查询参数打开窗口。", + "copyTheme": "复制主题 JSON", + "importTheme": "导入主题…", + "clearTheme": "清除覆盖", + "interopHint": "主题采用 shadcn 的 registry:theme 格式,可以直接粘贴任意 shadcn 主题,导出的主题也能用在任何 shadcn 项目里。", + "importTitle": "导入主题", + "importDescription": "粘贴 shadcn 的 registry:theme 条目、裸的 light/dark 对象,或者单层的 token 映射。", + "readClipboard": "读取剪贴板", + "importConfirm": "导入", + "cancel": "取消", + "apply": "应用", + "toasts": { + "copied": "主题 JSON 已复制", + "copyFailed": "无法写入剪贴板", + "clipboardReadFailed": "无法读取剪贴板,请手动粘贴", + "importFailed": "这段 JSON 里没有可用的主题变量", + "imported": "主题已导入" + }, + "css": { + "dialogTitle": "自定义 CSS", + "dialogDescription": "对所有 codeg 窗口生效。修改会实时预览,点击「应用」才会保存。", + "size": "{used} KB / {max} KB", + "ruleCount": "{count} 条规则", + "errorTooLarge": "内容过大,无法保存,请精简到上限以内。", + "errorImportEscaped": "剥离后仍检测到 @import(转义写法),请手动移除后再保存。", + "warnNoRules": "没有解析出任何规则,请检查语法。", + "noticeImportsRemoved": "已移除 {count} 条 @import:它们会拉取远程样式表。", + "noticeRemoteUrl": "含远程 url(),应用后会发起网络请求。", + "noticePreviewSuspended": "自定义样式已停用,此处预览不会生效。", + "noticeDisabled": "自定义 CSS 未启用。这里可以预览,但启用后才会真正生效。", + "hintTokens": "提示:你覆盖的颜色可以直接用 var(--primary)、var(--background) 等引用。" + } + }, + "zoomLevel": { + "sectionTitle": "窗口缩放", + "sectionDescription": "整体放大或缩小界面,立即生效,按设备分别保存。", + "placeholder": "请选择缩放档位", + "default": "默认", + "current": "当前缩放:{zoom}%" + }, + "fonts": { + "sectionTitle": "字体", + "sectionDescription": "为界面、代码编辑器和终端分别选择字体。内置字体按需加载;选择“自定义…”可使用系统已安装的任意字体。", + "interface": "界面", + "editor": "编辑器", + "terminal": "终端", + "groupSans": "无衬线", + "groupMono": "等宽", + "custom": "自定义…", + "customPlaceholder": "字体名称,如 Fira Code", + "fontSize": "字号", + "ligatures": "启用连字", + "ligaturesUnavailable": "该字体不含连字", + "wordWrap": "启用自动换行", + "terminalLigaturesHint": "终端连字仅对内置编程字体生效。", + "preview": "预览" + }, + "welcomePanel": { + "sectionTitle": "模式选择区域", + "sectionDescription": "新会话页面输入框上方显示的「代码开发 / 日常办公」快捷卡片区域。", + "showQuickActions": "在新会话页面显示" + }, + "workspaceBackground": { + "sectionTitle": "工作区背景", + "sectionDescription": "在整个工作区背后显示一张图片。侧栏与面板会变半透明并磨砂让图片透出,遮罩保证文字可读。", + "enable": "启用背景图片", + "image": "图片", + "chooseImage": "选择图片", + "replaceImage": "更换图片", + "removeImage": "移除", + "fillMode": "填充方式", + "fillModes": { + "cover": "覆盖", + "contain": "适应", + "center": "居中", + "tile": "平铺" + }, + "maskOpacity": "遮罩不透明度", + "maskOpacityHint": "数值越高,图片越向主题背景色淡化,文字对比越清晰。", + "imageBlur": "图片模糊", + "panelOpacity": "面板不透明度", + "panelOpacityHint": "侧栏、面板与标签栏的不透明程度。越低,透出的图片越多。", + "errorTooLarge": "图片太大(最大 16 MB)。", + "errorUploadFailed": "设置背景图片失败。" + } + }, + "SystemSettings": { + "loading": "加载中...", + "sectionTitle": "系统管理", + "sectionDescription": "管理网络代理、应用升级与语言偏好。", + "proxyTitle": "网络代理", + "proxyDescription": "开启后,后续网络请求将优先走该代理(包括 ACP 对话、Agent 安装、Git 远程操作等)。", + "loadFailed": "加载失败:{message}", + "enableProxy": "启用系统代理", + "proxyAddress": "代理地址", + "proxyHint": "支持 http(s)/socks5,示例:{example}。仅在启用系统代理时生效。", + "save": "保存", + "saving": "保存中...", + "proxyRequired": "启用代理时必须填写代理地址", + "saveSuccess": "系统代理设置已保存", + "saveFailed": "保存失败:{message}", + "languageTitle": "语言", + "languageDescription": "设置应用语言。跟随系统时,若系统语言不受支持将回退为英文。", + "appLanguage": "应用语言", + "languageSaveSuccess": "语言设置已保存", + "languageSaveFailed": "语言设置保存失败:{message}", + "updateTitle": "应用升级", + "versionTitle": "软件更新", + "updateDescription": "点击检查后会从配置的发布源拉取最新版本信息,有新版本时可直接下载并安装。", + "currentVersion": "当前版本", + "upgradableVersion": "最新版本", + "none": "暂无", + "lastChecked": "上次检查:{time}", + "updateError": "更新异常:{message}", + "checking": "检查中...", + "checkUpdate": "检查更新", + "updating": "升级中...", + "downloading": "下载中...", + "upgradeTo": "升级到 v{version}", + "viewRelease": "查看 v{version} 发布", + "foundUpdate": "发现新版本 v{version}", + "alreadyLatest": "当前已经是最新版本", + "checkUpdateFailed": "检查更新失败:{message}", + "installSuccess": "升级包已安装,正在重启应用", + "installFailed": "升级失败:{message}", + "upgradeSuccess": "升级完成,正在重新加载...", + "restartTimeout": "服务未能按时恢复,请检查容器或服务日志。", + "restartingIn": "将在 {seconds} 秒后重启...", + "waitingForServer": "正在等待服务恢复...", + "restartToUpdate": "重启以更新", + "newVersionBadge": "新版本 v{version}", + "updateAvailableTitle": "发现新版本", + "releaseNotesTitle": "更新内容", + "remindLater": "稍后", + "retry": "重试", + "stepDownload": "下载", + "stepInstall": "安装", + "stepRestart": "重启", + "updateReadyHint": "新版本已下载,重启以完成更新。", + "restarting": "正在重启…", + "dockerUpgradeHint": "现在升级的是正在运行的容器。容器一旦被重建即丢失——如需保留,请拉取或构建新版本镜像后重建容器。", + "upgradeRolledBack": "升级失败,服务器已自动回滚到上一版本。", + "serverUnreachable": "无法连接到服务器以开始升级。请确认服务器正在运行后重试。", + "rollbackButton": "回滚", + "rollingBack": "回滚中...", + "rollbackDescription": "恢复到上次升级前安装的版本。", + "rollbackConfirmTitle": "回滚到上一个版本?", + "rollbackConfirmDescription": "服务器将重启并运行上次升级前安装的版本。更新的版本仍可再次安装。", + "rollbackConfirm": "回滚", + "rollbackCancel": "取消", + "rollbackSuccess": "已回滚到上一个版本,正在重新加载……", + "rollbackFailed": "回滚失败,请检查服务器日志。", + "updateErrors": { + "sourceUnavailable": "无法连接更新源,请检查网络或代理设置后重试。", + "network": "网络连接异常,请检查网络或代理设置后重试。", + "downloadFailed": "下载更新包失败,请稍后重试。", + "installFailed": "安装更新失败,请关闭应用后重试。", + "unknown": "更新失败,请稍后重试。" + } + }, + "VersionControlSettings": { + "loading": "加载中...", + "sectionTitle": "版本控制", + "sectionDescription": "配置 Git 可执行文件并管理 GitHub 账号。", + "gitTitle": "Git 配置", + "gitDescription": "配置应用使用的 Git 可执行文件。", + "gitDetected": "已检测到 Git", + "gitNotFound": "未在系统中找到 Git", + "gitVersion": "版本", + "gitPath": "路径", + "customGitPath": "自定义 Git 路径", + "customGitPathPlaceholder": "/usr/bin/git", + "customGitPathHint": "留空则使用自动检测的路径。", + "test": "测试", + "testing": "测试中...", + "testSuccess": "Git 可执行文件有效。", + "testFailed": "Git 测试失败:{message}", + "save": "保存", + "saving": "保存中...", + "saveSuccess": "Git 设置已保存。", + "saveFailed": "保存失败:{message}", + "githubTitle": "GitHub 账号", + "githubDescription": "管理用于身份验证的 GitHub 账号。令牌存储在本地。", + "noAccounts": "暂无 GitHub 账号。", + "addAccount": "添加账号", + "serverUrl": "服务器地址", + "serverUrlPlaceholder": "https://github.com", + "token": "个人访问令牌", + "tokenPlaceholder": "ghp_xxxxxxxxxxxx", + "generateToken": "生成令牌", + "tokenHint": "在 GitHub → Settings → Developer settings → Personal access tokens 中生成令牌。", + "validateAndAdd": "验证并添加", + "validating": "验证中...", + "addSuccess": "账号 {username} 添加成功。", + "addFailed": "添加账号失败:{message}", + "testConnection": "测试", + "connectionSuccess": "连接成功。", + "connectionFailed": "连接失败:{message}", + "setDefault": "设为默认", + "defaultLabel": "默认", + "defaultSet": "默认账号已更新。", + "removeAccount": "删除", + "removeConfirmTitle": "删除账号", + "removeConfirmMessage": "确定要删除账号「{username}」吗?", + "removeConfirm": "删除", + "removeCancel": "取消", + "removeSuccess": "账号已删除。", + "scopes": "权限范围", + "loadFailed": "加载设置失败:{message}", + "gitAccount": { + "sectionTitle": "Git 服务器账号", + "sectionDescription": "管理非 GitHub 的 Git 服务器凭据(GitLab、Bitbucket、自建服务等)。", + "noAccounts": "暂无 Git 服务器账号。", + "addAccount": "添加账号", + "addTitle": "添加 Git 账号", + "addDescription": "输入服务器地址、用户名和密码或访问令牌。", + "serverUrl": "服务器地址", + "serverUrlPlaceholder": "https://gitlab.example.com", + "username": "用户名", + "usernamePlaceholder": "用户名或邮箱", + "password": "密码 / 令牌", + "passwordPlaceholder": "密码或访问令牌", + "passwordHint": "输入服务器的密码或个人访问令牌。", + "add": "添加", + "serverRequired": "请输入服务器地址。", + "usernameRequired": "请输入用户名。", + "passwordRequired": "请输入密码。" + } + }, + "ShortcutSettings": { + "sectionTitle": "快捷键", + "resetDefault": "恢复默认", + "recordInstruction": "点击右侧按钮后按下组合键即可修改。建议使用 Ctrl/Cmd、Alt、Shift 的组合。按 Esc 可取消录制。", + "recording": "按下快捷键...", + "toasts": { + "conflict": "快捷键已被「{title}」占用", + "updated": "快捷键已更新", + "invalid": "快捷键无效,请重试", + "reset": "已恢复默认快捷键" + }, + "actions": { + "toggle_search": { + "title": "打开搜索", + "description": "打开或关闭会话搜索面板" + }, + "toggle_sidebar": { + "title": "切换左侧边栏", + "description": "显示或隐藏会话列表侧边栏" + }, + "toggle_terminal": { + "title": "切换终端", + "description": "显示或隐藏底部终端面板" + }, + "new_terminal_tab": { + "title": "新建终端", + "description": "当最近鼠标活动在终端时新建终端标签" + }, + "close_current_terminal_tab": { + "title": "关闭当前终端", + "description": "当最近鼠标活动在终端时关闭当前终端标签" + }, + "toggle_aux_panel": { + "title": "切换右侧面板", + "description": "显示或隐藏辅助信息面板" + }, + "new_conversation": { + "title": "新建会话", + "description": "在当前文件夹中创建新的对话标签" + }, + "open_folder": { + "title": "打开文件夹", + "description": "打开文件夹选择器并在新窗口中打开" + }, + "open_settings": { + "title": "打开设置", + "description": "打开设置窗口" + }, + "close_current_tab": { + "title": "关闭当前标签", + "description": "关闭当前会话或文件标签" + }, + "close_all_file_tabs": { + "title": "关闭全部文件标签", + "description": "当文件面板处于活动状态时关闭所有打开的文件标签" + }, + "next_tab": { + "title": "下一个标签页", + "description": "切换到下一个会话或文件标签页" + }, + "prev_tab": { + "title": "上一个标签页", + "description": "切换到上一个会话或文件标签页" + }, + "send_message": { + "title": "发送消息", + "description": "在输入框中发送当前消息" + }, + "newline_in_message": { + "title": "消息换行", + "description": "在输入框中插入换行符" + }, + "toggle_custom_style": { + "title": "停用/恢复自定义样式", + "description": "逃生舱:一键关闭全部自定义配色与 CSS,再按一次恢复" + } + } + }, + "SkillsSettings": { + "title": "Skills", + "description": "左侧选择 Skill,右侧默认预览 Markdown,点击编辑后可修改并保存。", + "loadingAgents": "正在加载支持 Skills 的 Agent...", + "emptyNoManageableAgents": "当前没有可管理 Skills 的 Agent。", + "managedTarget": "管理对象", + "selectAgentPlaceholder": "请选择 Agent", + "searchPlaceholder": "搜索名称 / ID / 路径...", + "skillsList": "Skills 列表", + "loadingSkills": "加载 Skills 中...", + "agentNotSupported": "当前 Agent 暂不支持 Skills 管理。", + "emptySkills": "暂无 Skill,可点击“新建 Skill”。", + "newSkillTitle": "新建 Skill", + "skillInfo": "Skill 信息", + "skillIdPlaceholder": "Skill ID(例如:my-skill)", + "skillsDirectoryWithPath": "Skills目录:{path}", + "skillsDirectoryNeedId": "Skills目录:请输入 Skill ID 以生成完整路径", + "markdownContent": "Markdown 内容", + "editingStatus": "编辑中", + "previewStatus": "预览中", + "contentPlaceholder": "输入 Skill 文本内容...", + "metadataTitle": "Skills 元信息", + "onlyYamlMetadata": "该 Skill 仅包含 YAML 元信息。", + "emptyContentHint": "暂无内容。点击“编辑”开始输入。", + "loadingSkill": "正在加载 Skill...", + "emptyNoAgents": "暂无可用 Agent。", + "noSelectionHint": "从左侧选择一个 Skill,或点击“新建 Skill”创建。", + "systemBadge": "系统", + "systemHint": "CLI 内置 Skill · 只读", + "scope": { + "global": "全局", + "folder": "文件夹", + "selectFolderPlaceholder": "选择文件夹", + "noFolders": "未找到任何文件夹", + "pickFolderHint": "选择一个文件夹以查看其 Skills。" + }, + "actions": { + "preview": "预览", + "edit": "编辑", + "openInWindow": "在新窗口打开", + "delete": "删除", + "deleting": "删除中...", + "refresh": "刷新", + "newSkill": "新建 Skill", + "reset": "重置", + "save": "保存", + "saving": "保存中...", + "cancel": "取消" + }, + "deleteDialog": { + "title": "删除 Skill", + "confirm": "确认删除当前 Skill 吗?该操作无法撤销。", + "confirmWithNamePrefix": "确认删除 Skill", + "confirmWithNameSuffix": "吗?该操作无法撤销。" + }, + "toasts": { + "loadFailed": "加载 Skill 失败", + "openFolderFailed": "打开目录失败", + "noSkillDirectory": "当前 Agent 未找到可用的 Skills 目录", + "nameRequired": "Skill 名称不能为空", + "updated": "Skill 已更新", + "created": "Skill 已创建", + "saveFailed": "保存 Skill 失败", + "deleted": "Skill 已删除", + "deleteFailed": "删除 Skill 失败" + }, + "templates": { + "gemini": "---\nname: example-skill\ndescription: Describe when this skill should be used.\n---\n\n# Skill Name\n\nInstructions for the agent when this skill is active.\n\n## Workflow\n\n1. Add actionable step one.\n2. Add actionable step two.\n", + "openCode": "---\nname: example-skill\ndescription: Describe when this skill should be used.\n---\n\n# Purpose\n\nDescribe what this skill helps with.\n\n# Steps\n\n1. Add actionable step one.\n2. Add actionable step two.\n", + "openClaw": "---\nname: example-skill\ndescription: Describe when this skill should be used.\nuser-invocable: true\ndisable-model-invocation: false\n---\n\n# Purpose\n\nDescribe what this skill helps with.\n\n# Instructions\n\n1. Add actionable instruction one.\n2. Add actionable instruction two.\n", + "default": "---\nname: example-skill\ndescription: Describe when this skill should be used.\n---\n\n# Skill: example-skill\n\n## When to use\n\n- Describe trigger conditions.\n\n## Instructions\n\n1. Add actionable instruction one.\n2. Add actionable instruction two.\n" + } + }, + "McpSettings": { + "loading": "加载中...", + "summary": { + "missingCommand": "(缺少 command)", + "missingUrl": "(缺少 url)" + }, + "protocol": { + "stdio": "Stdio" + }, + "errors": { + "selectInstallProtocol": "请选择安装协议", + "fieldRequired": "{field} 为必填项", + "fieldNeedsBoolean": "{field} 需要 true 或 false", + "fieldNeedsNumber": "{field} 需要数字", + "fieldNeedsInteger": "{field} 需要整数", + "fieldInvalidJson": "{field} JSON 无效:{message}", + "fieldOutOfRange": "{field} 的值不在可选范围内", + "jsonEmpty": "{name} 不能为空", + "jsonInvalid": "{name} 不是合法 JSON:{message}", + "jsonMustBeObject": "{name} 必须是 JSON 对象", + "specMustBeObject": "MCP 配置必须是 JSON 对象。", + "missingType": "MCP 配置缺少 type 字段。请填写 stdio、http(别名 streamable-http、streamableHttp)、sse 之一。", + "unsupportedType": "不支持的 MCP type:{type}。支持的类型:stdio、http(别名 streamable-http、streamableHttp)、sse。", + "codexEntryUnsupportedType": "Codex MCP 条目 {id} 的 type 不受支持:{type}。支持的类型:stdio、http(别名 streamable-http、streamableHttp)、sse。", + "unsupportedTransportType": "不支持的 transport 类型:{type}。支持的类型:http(别名 streamable-http、streamableHttp)、sse。", + "stdioCommandRequired": "stdio 类型的 MCP 必须填写非空的 command 字段。", + "remoteUrlRequired": "远端 MCP 必须填写非空的 url 字段。", + "appsRequired": "请至少选择一个目标 App。" + }, + "jsonNames": { + "localConfig": "MCP 配置", + "installConfig": "安装配置" + }, + "toasts": { + "uninstalled": "已卸载 MCP", + "uninstallFailed": "卸载失败:{message}", + "selectAtLeastOneApp": "请至少选择一个目标应用", + "saveSuccess": "保存成功", + "saveFailed": "保存失败:{message}", + "installed": "已安装 {name}", + "installFailed": "安装失败:{message}", + "serverIdRequired": "Server ID 不能为空", + "serverIdExists": "Server ID \"{id}\" 已存在,请编辑现有项或更换名称", + "created": "MCP 已创建" + }, + "installDialog": { + "title": "确认安装 MCP", + "descriptionWithName": "将 {name} 安装到本地配置。", + "description": "选择安装目标应用。", + "protocol": "协议", + "selectProtocol": "选择协议", + "parameters": "配置参数", + "booleanPlaceholder": "请选择 true/false", + "selectOneValue": "选择一个值", + "targetApps": "目标应用" + }, + "actions": { + "cancel": "取消", + "confirmInstall": "确认安装", + "installing": "安装中", + "uninstall": "卸载", + "uninstalling": "卸载中", + "viewDetails": "查看详情", + "save": "保存", + "saving": "保存中", + "install": "安装", + "refresh": "刷新", + "newMcp": "新建 MCP", + "create": "创建", + "creating": "创建中..." + }, + "tabs": { + "local": "本地 MCP", + "market": "MCP 市场" + }, + "local": { + "filterPlaceholder": "筛选本地 MCP...", + "loadFailed": "加载失败:{message}", + "empty": "当前未检测到本地 MCP。", + "description": "本地 MCP 配置可直接编辑并保存。", + "enabledApps": "启用应用", + "configJson": "MCP 配置(JSON)", + "draftTitle": "新建 MCP", + "draftDescription": "填写 Server ID 与配置以创建本地 MCP 服务器。", + "serverIdLabel": "Server ID", + "serverIdPlaceholder": "Server ID(例如:my-mcp)", + "typeHint": "支持类型:stdio、http(别名 streamable-http、streamableHttp)、sse。env 仅适用于 stdio;远端 MCP 请通过 headers 字段传递鉴权 token。", + "envOnRemoteWarning": "检测到远端 MCP 配置中包含 env 字段。env 仅 stdio 类型使用,远端 MCP 应通过 headers 携带鉴权信息,env 字段保存时会被忽略。" + }, + "market": { + "selectMarketplace": "选择市场", + "searchPlaceholder": "搜索 MCP...", + "searchFailed": "搜索失败:{message}", + "loadingList": "加载 MCP 列表...", + "empty": "暂无 MCP 结果。", + "loadingDetail": "加载市场详情...", + "detailLoadFailed": "加载详情失败:{message}", + "owner": "所有者:{owner}", + "namespace": "命名空间:{namespace}", + "defaultInstallProtocol": "默认安装协议", + "currentOptionParameterCount": "当前选项参数数:{count}", + "installConfigDescription": "安装配置(JSON,可修改后安装;修改后将覆盖协议/参数表单)", + "selectLeftToView": "请选择左侧市场 MCP 查看详情。" + }, + "badges": { + "verified": "已验证", + "remote": "远程", + "hasHomepage": "有主页", + "uses": "{count} 次使用", + "deployed": "已部署", + "notDeployed": "未部署" + }, + "selectLeftMcp": "请选择左侧 MCP。" + }, + "AcpAgentSettings": { + "title": "Agent SDK管理", + "description": "统一管理 Agent 的连接SDK、启用状态、环境变量、配置管理与版本预检信息。", + "loadingAgents": "加载 Agent 列表中...", + "agentList": "Agent 列表", + "emptyNoAgent": "暂无可用 Agent。", + "configManagement": "配置管理", + "envVars": "环境变量", + "hostTools": { + "label": "由 Agent 自行处理文件与命令", + "description": "codeg 不再代为提供文件访问和终端命令,改由 Agent 在自己的进程中执行——只有这样它自带的沙箱与权限规则才会生效。同时会关闭向其他 Agent 委托,否则同样的操作又会绕回 codeg 执行。codeg 本身不提供沙箱,因此请仅在 Agent 已配置沙箱时开启。" + }, + "nativeJsonConfig": "原生 JSON 配置", + "modelHintDefault": "留空则使用系统默认模型。", + "generalConfigDescriptionClaude": "支持 API URL、API Key 与 Claude 模型快捷配置,并与原生 JSON 配置联动。", + "generalConfigDescriptionDefault": "支持重要配置输入(API URL、API Key、Model)和原生 JSON 配置管理。", + "multiAgent": { + "title": "多智能体协同", + "description": "允许活跃的智能体把子任务委托给其他智能体。", + "enable": "启用委托", + "enableHint": "关闭后,delegate_to_agent 工具会从智能体的 MCP 工具清单中隐藏。", + "withheldByHostTools": "{agents} 不会拿到委派工具:它们单独开启了「由 Agent 自行处理文件与命令」。", + "selfInitiate": "Allow spawn without @", + "selfInitiateHint": "When on, an agent may start a listed sub-agent on its own. An @ mention is still always honored. When off, only an @ mention starts a sub-agent.", + "depthLimit": "最大委托深度", + "depthHint": "允许范围:{min}–{max}。限制委托链(根 → 子 → 孙 …)的最大递归深度。", + "completedCacheLabel": "已完成结果缓存(MB)", + "completedCacheHint": "运行中委托会话已完成子智能体结果的内存缓存,仅在该会话运行期间保留,会话结束后自动清除。超出此预算时优先从内存中丢弃最旧的结果(仍可在子智能体自己的会话中查看);0 表示不限(会话结束后仍会清除)。", + "save": "保存", + "saving": "保存中…", + "saved": "委托设置已保存", + "saveFailed": "委托设置保存失败", + "loadFailed": "加载委托设置失败:{detail}", + "tabGeneral": "通用", + "tabAgentDefaults": "子智能体配置", + "agentDefaultsDescription": "多智能体协同在为委托调用启动子智能体时使用这些覆盖项。下方选项通过实时探测获取,所选即所用。", + "probing": "正在加载该智能体的可用配置项…", + "probeFailed": "加载配置项失败:{detail}", + "retry": "重试", + "noConfigAvailable": "该智能体没有可配置项。", + "modeLabel": "模式", + "agentDefaultHint": "智能体默认:{value}", + "defaultOptionLabel": "默认({value})" + }, + "actions": { + "dragSort": "拖拽排序", + "dragSortAgent": "拖拽排序 {name}", + "refreshCheck": "刷新检测", + "refreshCheckAgent": "刷新检测 {name}", + "clickEnable": "点击启用 {name}", + "clickDisable": "点击禁用 {name}", + "install": "安装", + "upgrade": "升级", + "uninstall": "卸载", + "uninstalling": "卸载中...", + "saveEnvVars": "保存环境变量", + "saving": "保存中...", + "saveGrokConfig": "保存 Grok 配置", + "saveCodexConfig": "保存 Codex 配置", + "saveGeminiConfig": "保存 Gemini 配置", + "saveOpenCodeConfig": "保存 OpenCode 配置", + "saveOpenClawConfig": "保存 OpenClaw 配置", + "saveConfigManagement": "保存配置管理", + "saveCurrentProvider": "保存当前 Provider", + "showApiKey": "显示 API Key", + "hideApiKey": "隐藏 API Key", + "showKey": "显示 Key", + "hideKey": "隐藏 Key", + "showToken": "显示 Token", + "hideToken": "隐藏 Token", + "cancel": "取消", + "delete": "删除", + "deleting": "删除中...", + "confirmDelete": "确认删除", + "confirmUninstall": "确认卸载", + "saveClineConfig": "保存 Cline 配置", + "saveHermesConfig": "保存 Hermes 配置", + "saveCodeBuddyConfig": "保存 CodeBuddy 配置", + "saveKimiCodeConfig": "保存 Kimi Code 配置", + "customInstall": "自定义安装", + "saveKimiCodeRawConfig": "保存 config.toml", + "saveDeepSeekConfig": "保存 DeepSeek 配置", + "diagnose": "诊断" + }, + "status": { + "enabled": "启用", + "disabled": "禁用", + "unchecked": "未检测", + "agentEnabledAria": "{name} 已启用", + "agentEnabledSwitch": "{name} 启用" + }, + "preflight": { + "count": "预检项:{count}", + "notRun": "尚未执行检测。" + }, + "grok": { + "configDescription": "在此配置 Grok。下方控件——权限模式、推理强度、可选的自定义(自带端点)模型和压缩——会合并写入 ~/.grok/config.toml,并保留你的其他键与注释。登录使用你的 XAI_API_KEY 或 `grok login`。其他键可在“高级”中编辑。", + "permissionModeLabel": "权限模式", + "permissionDefault": "每次询问", + "permissionAcceptEdits": "自动批准编辑", + "permissionAuto": "智能自动批准", + "permissionAlwaysApprove": "始终允许", + "reasoningEffortLabel": "推理级别", + "effortLow": "低(更快)", + "effortMedium": "中(均衡)", + "effortHigh": "高", + "effortXhigh": "最高", + "optionDefault": "使用默认", + "authTitle": "认证", + "authMode": "认证方式", + "authModeApiKey": "XAI API 密钥", + "authModeApiKeyHint": "使用 xAI 控制台的 XAI_API_KEY 认证——适用于非交互/无头运行。保存在该智能体的环境变量中。", + "authModeCustom": "自定义接口", + "authModeCustomHint": "使用自定义接口(BYO 端点):在下方定义一个带有独立 base URL 和 API 密钥的自定义模型,它将成为 Grok 的默认模型。", + "subscriptionHint": "使用 `grok login` 登录(SuperGrok / X Premium+)。不保存 API 密钥。", + "loginHint": "在终端运行以下命令登录,然后重新打开此设置:", + "commandCopied": "命令已复制到剪贴板", + "copyCommand": "复制命令", + "authKeyConfigured": "已配置 XAI_API_KEY。", + "authKeyMissing": "未设置 XAI_API_KEY。", + "advancedToggle": "高级(原始 config.toml)", + "configTomlNative": "config.toml(原生)", + "configTomlHint": "按原样整体写入 ~/.grok/config.toml。非法 TOML 会被拒绝,绝不因笔误截断文件。", + "configTomlPlaceholder": "# 上面控件之外的键,例如\n# [mcp_servers.*]、[cli]、[permission] 规则。", + "customModelTitle": "自定义模型(自带端点)", + "customModelHint": "让 Grok 指向自定义或自托管端点。codeg 会写入按模型的 `[model.*]` 块并将其设为默认模型。清空模型 ID 即可移除。", + "customModelIdLabel": "模型 ID", + "customModelIdPlaceholder": "grok-4.5", + "customModelIdHint": "注册为 `[model.*]` 块,并作为模型名发送给 API;同时设为 `[models].default`。", + "customBaseUrlLabel": "Base URL", + "customBaseUrlPlaceholder": "https://api.x.ai/v1(默认)", + "customApiBackendLabel": "API 后端", + "backendResponses": "Responses", + "backendChatCompletions": "Chat Completions", + "backendMessages": "Messages(Anthropic)", + "customApiKeyLabel": "API Key", + "customApiKeyHint": "内联存储于 `[model.*].api_key`,仅作用于该端点。", + "customContextWindowLabel": "上下文窗口(tokens)", + "customContextWindowHint": "可选。用于自动压缩计时;留空则使用端点默认值。", + "autoCompactLabel": "自动压缩阈值(%)", + "autoCompactHint": "当上下文使用率达到该百分比时压缩对话(Grok 默认 85)。写入 `[session]`。" + }, + "cursor": { + "configDescription": "在此配置 Cursor。先选择认证方式——官网订阅(浏览器登录)或用于无头/服务器的 Cursor API 密钥——然后选择模型并编辑 CLI 的权限规则与沙箱。codeg 会写入 ~/.cursor/cli-config.json,与 cursor-agent CLI 共享。", + "authTitle": "鉴权", + "authChecking": "检测中…", + "authNotInstalled": "cursor-agent 未安装", + "authLoggedIn": "已登录", + "authNotLoggedIn": "未登录", + "loginHint": "在终端运行以下命令登录 Cursor 账号(会打开浏览器),完成后点刷新:", + "apiKeyLabel": "Cursor API 密钥", + "apiKeyPlaceholder": "在 cursor.com/dashboard 获取", + "apiKeyHint": "CURSOR_API_KEY —— Cursor Dashboard 的账号密钥,在无头/服务器环境下替代浏览器登录。不是第三方或 OpenAI 密钥。", + "modelTitle": "默认模型", + "loadModels": "获取模型列表", + "modelsUnavailable": "模型列表不可用", + "modelHint": "会话启动时通过 --model 传给 CLI;保持默认则由 Cursor 自行选择。", + "permissionsTitle": "权限与沙箱", + "permissionsDescription": "可视化编辑 CLI 权限规则(cli-config.json)。允许规则免确认执行;拒绝规则始终拦截。", + "permissionModeLabel": "权限模式", + "permissionModeDefault": "执行前询问(默认)", + "permissionModeForce": "全部放行 Run Everything(--force)", + "permissionModeHint": "Run Everything 以 --force 启动会话:除 deny 规则外的所有工具调用自动放行、不再弹确认(组织策略可能将其降级为仅按 allow 规则放行)。对新会话生效。", + "optionDefault": "默认(未设置)", + "sandboxLabel": "沙箱", + "sandboxEnabled": "启用", + "sandboxDisabled": "禁用", + "allowRulesLabel": "允许规则", + "denyRulesLabel": "拒绝规则", + "addRule": "添加规则", + "rulesSyntaxHint": "规则语法:Shell(命令)、Read(路径/通配)、Write(路径/通配)、WebFetch(域名)、Mcp(服务器:工具)——deny 规则始终优先。", + "saveConfig": "保存配置", + "advancedToggle": "高级:原始 cli-config.json", + "advancedHint": "完整的 ~/.cursor/cli-config.json。此处保存按原文写入;上方结构化控件则以合并方式写入。", + "saveRawConfig": "保存文件", + "authMode": "认证方式", + "subscriptionHint": "使用 Cursor 账号登录,使用 Cursor 的模型。", + "customApiKeyRequired": "需要填写 Cursor API 密钥。", + "authModeApiKey": "Cursor API 密钥(无头/服务器)", + "authModeApiKeyHint": "用 Cursor 官网 Dashboard 生成的账号 API 密钥认证(适用于无头/服务器环境)。这是 Cursor 账号密钥,不是第三方/OpenAI 端点——cursor-agent 只连 Cursor 自己的后端。要使用 codex/OpenAI 兼容端点,请改用 Codex 智能体。", + "modelPickerPlaceholder": "搜索模型…", + "modelNoMatch": "没有匹配的模型", + "modelsNeedAuth": "登录后加载模型列表。", + "modelDefaultBadge": "默认" + }, + "deepseek": { + "configManagement": "DeepSeek Harness 配置", + "configDescription": "端点与密钥是 deepseek-acp 启动时读取的环境变量。模型和推理档位是会话级选择器,在输入框里切换。", + "baseUrlLabel": "API 端点", + "baseUrlHint": "留空则使用官方端点。保存后对新建的会话生效——正在进行的会话需要重新连接才会切换。", + "baseUrlInvalid": "请填写完整的 http(s) 地址且不带查询参数,例如 https://api.deepseek.com", + "apiKeyLabel": "API 密钥", + "apiKeyHint": "以 DEEPSEEK_API_KEY 传给智能体。环境变量的优先级高于凭据文件,因此若用终端登录,这里留空即可。" + }, + "codex": { + "configDescription": "支持 API URL、API Key、模型名称、Reasoning Effort 快捷配置,并与 `auth.json` / `config.toml` 双向联动。", + "authMode": "认证方式", + "chatgptSubscription": "官网订阅", + "chatgptSubscriptionHint": "使用 ChatGPT 官网订阅登录,无需配置 API Key", + "apiKeyHint": "使用 API Key 连接 OpenAI 或兼容的 API 服务", + "selectProvider": "选择 Provider", + "modelName": "模型名称", + "selectReasoningEffort": "选择 Reasoning Effort", + "enableWebsocket": "启用 WebSocket", + "enableWebsocketAria": "Codex Provider 启用 WebSocket", + "enableSkills": "启用 Skills", + "enableSkillsAria": "Codex 启用 Skills", + "enableFast": "启用 Fast", + "enableFastAria": "Codex 启用 Fast 服务等级", + "sandboxGroupTitle": "沙箱与审批", + "sandboxGroupHint": "写入全局 ~/.codex/config.toml,codex CLI 与 IDE 的会话同样生效。这是线程默认值,只作用于 codex 自行发起的回合(/goal、/review、/compact);普通对话使用输入框里的审批预设。改动需重开会话才生效。", + "sandboxShadowedWarning": "config.toml 里设置了 default_permissions,codex 会改走权限配置档并完全忽略 sandbox_mode。删掉 default_permissions 后下面的选项才会生效。", + "sandboxPermissionsTableWarning": "config.toml 定义了 [permissions] 配置档却没有 default_permissions,codex 会拒绝启动。请在下方原始编辑器里补上。", + "approvalPolicyLabel": "审批策略", + "approvalPolicyUnset": "未设置(codex 默认:按需询问)", + "approvalPolicy_on-request": "按需询问 — 由模型决定何时请求批准", + "approvalPolicy_untrusted": "仅信任只读 — 只有已知安全的只读命令免批准", + "approvalPolicy_never": "从不询问 — 完全不弹审批", + "approvalPolicy_granular": "精细控制 — 按提示类型分别设置", + "approvalPolicyUntrustedAcpWarning": "ACP 适配器只有三种审批预设,untrusted 无对应项,codeg 会话会退回「按需询问」——此时由模型自行决定何时询问,沙箱本就允许的命令不再询问。请改用下方的沙箱模式收紧。", + "granularHint": "关闭表示该类请求被自动拒绝,而不是弹给你确认。", + "granular_sandbox_approval": "Shell 命令越权申请", + "granular_rules": "Execpolicy 规则提示", + "granular_skill_approval": "技能脚本执行提示", + "granular_request_permissions": "request_permissions 工具提示", + "granular_mcp_elicitations": "MCP elicitation 提示", + "sandboxModeLabel": "沙箱模式", + "sandboxModeUnset": "未设置(受信任的文件夹回落为可写工作区)", + "sandboxMode_read-only": "只读", + "sandboxMode_workspace-write": "可写工作区", + "sandboxMode_danger-full-access": "完全放开(无沙箱)", + "sandboxModeHint": "在 Windows 上,未开启 codex 的实验性 Windows 沙箱时,可写工作区会被降级为只读。", + "sandboxModeSeedsPresetHint": "codeg 还会用它推导会话的初始审批预设,因此与审批策略不同,它对普通提问同样生效。输入框中选择的预设仍会覆盖它。", + "writableRootsLabel": "额外可写目录", + "writableRootsHint": "每行一个绝对路径,作为工作目录之外的额外可写位置。", + "sandboxRootsRelativeError": "必须是绝对路径 — codex 会把相对路径解析到 ~/.codex 下:{path}", + "networkAccessLabel": "允许网络访问", + "excludeTmpdirLabel": "从可写目录中排除 TMPDIR", + "excludeSlashTmpLabel": "从可写目录中排除 /tmp", + "authJsonNative": "auth.json(原生)", + "configTomlNative": "config.toml(原生)", + "loginButton": "使用 ChatGPT 登录", + "loginRequesting": "正在请求登录码...", + "loginStep1": "在浏览器中打开以下链接:", + "loginStep2": "输入以下代码:", + "loginPolling": "等待授权中...", + "loginCancel": "取消", + "loginSuccess": "登录成功,配置已保存!", + "loginFailed": "登录失败:{message}", + "loginRetry": "重试", + "loginCodeCopied": "已复制代码", + "loggedIn": "账号已登录", + "loginRelogin": "重新登录 / 切换账号", + "loginTimeout": "登录超时,请重试", + "loginSaveFailed": "登录成功但配置保存失败" + }, + "gemini": { + "authConfig": "Gemini 认证配置", + "authConfigDescription": "对齐 Gemini CLI 认证文档,支持自定义、Google 登录、Gemini API Key、Vertex AI(ADC / 服务账号 / API Key)。", + "authMode": "认证方式", + "selectAuthMode": "选择认证方式", + "viewAuthDoc": "查看认证文档", + "mode": { + "custom": "自定义接口", + "loginGoogle": "Google 登录(OAuth)", + "vertexServiceAccount": "Vertex AI(服务账号)" + }, + "hint": { + "custom": "填写 API URL、API Key 和 Model,分别映射到 GOOGLE_GEMINI_BASE_URL / GEMINI_API_KEY / GEMINI_MODEL。", + "loginGoogle": "首次在终端运行 gemini 并完成 Google 登录;无需填写 API Key。", + "geminiApiKey": "使用 Gemini API 时填写 GEMINI_API_KEY。", + "vertexAdc": "使用 gcloud ADC,建议填写 GOOGLE_CLOUD_PROJECT 与 GOOGLE_CLOUD_LOCATION。", + "vertexServiceAccount": "服务账号 JSON 路径写入 GOOGLE_APPLICATION_CREDENTIALS。", + "vertexApiKey": "使用 Vertex AI API key 时填写 GOOGLE_API_KEY。" + } + }, + "openCode": { + "configManagement": "OpenCode 配置管理", + "configDescription": "对齐 OpenCode `provider` 配置结构,支持多供应商管理,并与原生 JSON 文件双向联动。", + "providerManagement": "Provider 管理", + "providerCount": "共 {count} 个", + "addProvider": "新增 Provider", + "emptyProvider": "还没有自定义 Provider。点击「添加自定义 Provider」创建。", + "providerEnabledState": "{providerId} 启用状态", + "selectProviderNpm": "选择 provider.npm", + "modelManagement": "模型管理", + "modelCount": "共 {count} 个", + "modelDescription": "对齐 OpenCode `provider.models` 结构。当前支持 `name` / `id` 快速管理;其它高级字段会保留,可在下方原生 JSON 中继续编辑。", + "addModel": "添加模型", + "emptyModel": "暂无模型,输入 model id 后点击“添加模型”创建。", + "modelId": "模型 ID", + "modelName": "模型名称", + "deleteModel": "删除模型 {modelId}", + "nativeJsonConfig": "OpenCode 原生 JSON 配置", + "mainModel": "主模型", + "smallModel": "小模型", + "noMatchingModels": "没有匹配的模型", + "connectProvider": "连接 Provider", + "connectedProviders": "已连接的 Provider", + "noConnectedProviders": "还没有从目录连接 Provider。", + "advancedProviderConfig": "自定义 Provider", + "customProviderConfigHint": "你自己定义的 OpenAI 兼容端点——opencode.json 里的一个 provider 配置块,API key 存在 auth.json。", + "addCustomProvider": "添加自定义 Provider", + "disconnect": "断开", + "editConfig": "编辑", + "customBadge": "自定义", + "authKindApi": "API Key", + "authKindOauth": "OAuth", + "authKindNone": "无凭证", + "connect": { + "title": "连接 Provider", + "description": "从 models.dev 目录选择一个 Provider。凭证保存到 OpenCode 的 auth.json 文件。", + "pick": "Provider", + "search": "搜索 Provider…", + "loading": "正在加载目录…", + "catalogLabel": "models.dev 目录", + "modelsAvailable": "{count} 个可用模型", + "getKey": "获取 API Key", + "oauthApiKeyNote": "该 Provider 也支持通过 opencode auth login 浏览器登录。浏览器登录即将推出——目前请粘贴 API Key。", + "apiKey": "API Key", + "apiKeyHint": "保存在 auth.json,绝不写入 opencode.json。", + "baseUrlOptional": "Base URL 覆盖(可选)", + "providerId": "Provider ID", + "displayName": "显示名称", + "modelsList": "模型(每行一个)", + "modelsHint": "端点接受的模型 ID。", + "action": "连接", + "editTitle": "编辑 Provider", + "editDescription": "更新该 Provider 的 API Key 或 Base URL。", + "saveAction": "保存" + }, + "customProvider": { + "title": "添加自定义 Provider", + "description": "定义一个 OpenAI 兼容端点。API key 保存到 auth.json;provider 配置块写入 opencode.json。", + "action": "添加 Provider", + "idInCatalog": "{providerId} 是已知 Provider,请改用「连接 Provider」连接。" + }, + "refreshCatalog": "刷新目录", + "reasoningBadge": "推理", + "contextWindow": "上下文窗口", + "permissions": { + "title": "权限", + "description": "决定哪些操作直接运行、先征求你的同意,还是被阻止。写入 opencode.json 的 permission 配置,点击下方保存后生效。", + "docsLink": "权限文档", + "unparsableConfig": "下方的原生 JSON 当前无法解析,可视化编辑已暂停。修复 JSON 后即可继续。", + "invalidBlock": "permission 配置的结构无法识别。请在下方原生 JSON 中修改,或点击「恢复默认」重来。", + "orderingUnsafe": "通配规则写在了具体工具之后,OpenCode 会把它一并应用到这些工具上——下方各行显示的并非实际生效的规则。「修正顺序」只把通配规则移回各自作用域的最前面,不改动任何取值。", + "orderingUnsafeManual": "有规则被后面更宽泛的模式遮蔽,OpenCode 永远不会应用它——下方各行显示的并非实际生效的规则。两个互相重叠的模式没有唯一正确的顺序,请在下方原生 JSON 中调整,把更宽泛的写在前面。", + "fixOrder": "修正顺序", + "agentOverrides": "以下智能体单独覆盖了权限,且在最后应用,因此会盖过此处的全部设置:{agents}。请在下方原生 JSON 中修改,或开启「自动接受所有权限」将其清除。", + "legacyTools": "顶层的旧版 tools 配置禁用了某个工具。OpenCode 会把它并入权限,因此它会叠加在此处显示的全部设置之上。请在下方原生 JSON 中修改,或开启「自动接受所有权限」将其清除。", + "autoAcceptTitle": "自动接受所有权限", + "autoAcceptHint": "所有工具调用(shell 命令、文件修改、访问项目外路径)都不再询问,直接执行。开启后会用一条全局允许规则替换下方的逐工具设置,并清除各智能体单独的权限覆盖与旧版 tools 开关——否则它们仍会拦截。", + "globalLabel": "全局默认", + "globalHint": "即 * 规则:下方工具未单独覆盖时采用的动作。", + "actionUnset": "未设置(OpenCode 默认)", + "actionInherit": "跟随默认({action})", + "actionAllow": "允许", + "actionAsk": "询问", + "actionDeny": "拒绝", + "perToolTitle": "逐工具权限", + "reset": "恢复默认", + "ruleCount": "细则 {count} 条", + "rulesToggle": "{tool} 的细粒度规则", + "rulesHint": "按工具输入匹配,最后匹配的规则优先,因此请把宽泛的模式写在前面。* 匹配任意多个字符,? 精确匹配一个字符,开头的 ~ 展开为主目录。", + "noRules": "暂无细粒度规则。", + "addRule": "添加规则", + "deleteRule": "删除规则 {pattern}", + "duplicateRule": "该模式已存在。", + "blankRule": "规则必须有模式;如需删除请点击垃圾桶图标。", + "customKeys": "文件中的其他权限键", + "customKeyHint": "并非 OpenCode 内置工具,将按原样保留。", + "keys": { + "bash": "运行 shell 命令,按解析后的命令匹配", + "edit": "所有文件修改:edit、write 与 patch", + "read": "读取文件,按文件路径匹配", + "external_directory": "访问项目工作目录之外的路径", + "task": "启动子代理,按子代理类型匹配", + "skill": "加载技能,按技能名称匹配", + "glob": "查找文件,按通配模式匹配", + "grep": "搜索文件内容,按模式匹配", + "list": "列出目录内容", + "webfetch": "获取 URL", + "websearch": "网页搜索", + "lsp": "运行 LSP 查询", + "todowrite": "写入待办列表", + "question": "向你提问", + "doom_loop": "同一调用以相同输入重复 3 次时触发" + } + } + }, + "openClaw": { + "gatewayConfig": "Gateway 配置", + "gatewayDescription": "配置 OpenClaw Gateway 连接信息。支持本地或远程 Gateway。", + "gatewayUrlHint": "留空则使用 openclaw 本地配置的 gateway.remote.url。", + "gatewayTokenPlaceholder": "Gateway 认证 Token", + "gatewayTokenHint": "建议使用 token-file 替代明文 Token,可通过 openclaw 命令行配置。", + "sessionKeyHint": "可选。指定 Gateway Session Key,留空则自动分配隔离会话。" + }, + "hermes": { + "configManagement": "Hermes 配置", + "configDescription": "Hermes 在 ~/.hermes/.env 中管理自己的凭据,在 ~/.hermes/config.yaml 中管理设置。选择一个供应商,然后设置 API 密钥和模型——codeg 会替你写入这两个文件。", + "providerLabel": "供应商", + "providerHint": "供应商决定 Hermes 使用哪个 API 密钥变量和 model.provider。OAuth 供应商通过下方的终端设置进行配置。", + "groupApiKey": "API 密钥提供商", + "groupOauth": "OAuth 提供商", + "groupAws": "AWS", + "apiKeyHint": "保存到 ~/.hermes/.env。它绝不会被注入进程——Hermes 会从自己的配置中读取它。", + "modelName": "模型", + "oauthHint": "此供应商使用 OAuth。请运行下方的设置流程,在终端中完成认证。", + "awsHint": "Bedrock 使用你的 AWS 凭据(环境变量或共享配置)。请在上方填写模型 ID,并在系统环境中配置 AWS 访问权限。", + "unsupportedProvider": "该提供商无法通过结构化字段编辑。请使用下方的 config.yaml 原始编辑器或终端引导设置。", + "setupTitle": "自管理设置", + "setupHint": "Hermes 的交互式设置需要终端。可在下方启动,或复制命令自行运行。", + "runSetup": "运行 Hermes 设置", + "configureModel": "配置模型", + "openConfigFolder": "打开 ~/.hermes", + "copyCommand": "复制命令", + "commandCopied": "命令已复制到剪贴板", + "advancedTitle": "高级:编辑 config.yaml", + "rawConfigHint": "直接编辑 ~/.hermes/config.yaml。在此保存将原样覆盖该文件。", + "saveRawConfig": "保存 config.yaml" + }, + "codebuddy": { + "configManagement": "CodeBuddy 配置", + "configDescription": "CodeBuddy 使用 API Key 进行认证。中国版还必须将环境设为“中国版(internal)”;iOA 版使用“iOA”;海外版则不设置。", + "apiKeyLabel": "API Key", + "apiKeyHint": "将作为该智能体的 CODEBUDDY_API_KEY 保存。也可以在终端用 CodeBuddy CLI 登录。", + "apiKeyHintSelfHosted": "将作为该智能体的 CODEBUDDY_API_KEY 保存。请使用你的私有化部署签发的密钥。", + "environmentLabel": "环境", + "environmentHint": "设置 CODEBUDDY_INTERNET_ENVIRONMENT。中国大陆必须使用“中国版(internal)”;海外版则不设置。", + "envOverseas": "海外版(默认)", + "envChina": "中国版(internal)", + "envIoa": "iOA", + "envSelfHosted": "私有化部署", + "baseUrlLabel": "私有化部署地址", + "baseUrlPlaceholder": "https://codebuddy.your-company.com", + "baseUrlHint": "保存为 CODEBUDDY_BASE_URL,将 CodeBuddy 指向你的私有端点。私有化部署不设置网络环境(CODEBUDDY_INTERNET_ENVIRONMENT)。", + "baseUrlInvalid": "请输入合法的 http(s) 地址。", + "loginHint": "没有 API Key?也可以在终端运行 “codebuddy” 用腾讯云账号登录。" + }, + "kimiCode": { + "configManagement": "Kimi Code 配置", + "configDescription": "`kimi acp` 只认已存储的登录令牌,所以 codeg 会在 ~/.kimi-code/config.toml 写入受管供应商,并在本地播种一个门控令牌——推理仍然走你自己的 Key。", + "statusUnconfigured": "尚未配置", + "statusDirty": "有未保存的修改", + "summaryLabel": "生效配置", + "gateReadyApiKey": "API Key 已写入 config.toml", + "gateReadyLogin": "已通过 Kimi 账号登录", + "revealConfig": "在文件夹中显示", + "envOverrideWarning": "检测到 {keys},其优先级高于 config.toml。在此保存会自动清除它。", + "authModeLabel": "鉴权方式", + "authModeApiKey": "API Key", + "authModeLogin": "Kimi 账号登录(订阅)", + "authModeApiKeyHint": "在 config.toml 写入受管供应商,并播种门控令牌以便会话能够打开。", + "loginHint": "在终端运行 `kimi login`,用 Kimi 订阅账号登录。codeg 不存储任何凭据,复用 Kimi 自己的登录。在此保存会移除 codeg 的 API Key 门控令牌。", + "credentialTitle": "凭据", + "interfaceTypeLabel": "供应商类型", + "interfaceTypeHint": "Kimi 使用的供应商协议(config.toml 的 `type`)。Moonshot / platform.kimi.com 的 Key 请选「Kimi / Moonshot」。", + "endpointLabel": "接入点", + "endpointCustom": "自定义(OpenAI 兼容)", + "endpointHint": "国际 = api.moonshot.ai;中国(platform.kimi.com 的 Key)= api.moonshot.cn。自定义可指向任意 OpenAI 兼容端点。", + "regionInternational": "国际(api.moonshot.ai)", + "regionChina": "中国(api.moonshot.cn)", + "baseUrlLabel": "Base URL", + "baseUrlHint": "留空则使用供应商 SDK 默认值。", + "apiKeyLabel": "API Key", + "apiKeyHint": "写入 ~/.kimi-code/config.toml 并用于推理。来自 platform.kimi.com 或 platform.kimi.ai。", + "vertexProjectLabel": "GCP 项目(GOOGLE_CLOUD_PROJECT)", + "vertexLocationLabel": "GCP 区域(GOOGLE_CLOUD_LOCATION)", + "vertexHint": "Vertex AI 使用 Google 应用默认凭据——运行 `gcloud auth application-default login`(无需 API Key)。", + "modelTitle": "模型", + "modelLabel": "模型", + "modelHint": "写入 config.toml 的模型 id。点「测试并获取模型」可查看你的 Key 实际能访问哪些模型。", + "maxContextLabel": "最大上下文长度", + "maxContextHint": "Kimi 的配置 schema 要求必填:缺失会让 Kimi 丢弃整个模型块,导致每次对话都没有回复。默认 262144。", + "fetchModels": "测试并获取模型", + "fetchModelsOk": "Key 可用——共 {count} 个模型", + "fetchModelsEmpty": "Key 可用,但未返回任何模型", + "fetchModelsFailed": "测试失败", + "fetchModelsNeedsKey": "请先填写 API Key 和接入点", + "modelNotInList": "该模型不在你的 Key 可访问列表中,Kimi 会报「模型不存在」。", + "reasoningTitle": "推理", + "reasoningEnableLabel": "启用", + "reasoningDescription": "只有当模型声明了推理能力,Kimi 才会在输入框显示「Thinking」选择器,所以这里由 codeg 写入该声明。对新建会话生效。", + "effortsLabel": "可选档位", + "effortsHint": "这些会成为输入框「Thinking」选择器里的档位。Kimi 会把档位原样透传给供应商,请选你的模型能接受的值。", + "effortsEmptyHint": "一个档位都不选时,输入框只会退化成 Off / On 两档开关。", + "effortsCustomPlaceholder": "添加其它档位", + "effortsAdd": "添加", + "defaultEffortLabel": "默认档位", + "defaultEffortAuto": "由 Kimi 决定", + "alwaysThinkingLabel": "模型始终推理——从选择器中去掉 Off 档", + "fixErrorsFirst": "请先修正标红的字段", + "errorModelRequired": "模型为必填项", + "errorMaxContextRequired": "最大上下文长度为必填项", + "errorMaxContextInvalid": "必须是正整数", + "errorApiKeyRequired": "API Key 为必填项", + "errorApiKeyInvalid": "API Key 不能包含换行", + "errorBaseUrlRequired": "Base URL 为必填项", + "errorBaseUrlInvalid": "必须以 http:// 或 https:// 开头", + "errorVertexProjectRequired": "GCP 项目为必填项", + "errorDefaultEffortUnlisted": "必须是上面已选中的档位之一", + "advancedTitle": "高级", + "authTypeLabel": "凭据写入位置", + "authTypeApiKey": "内联 api_key", + "authTypeEnv": "供应商 env 子表", + "authTypeHint": "API Key 在 config.toml 中的写入位置。", + "rawEditorLabel": "直接编辑 config.toml", + "rawEditorWarning": "在此保存会按原文覆盖整个文件,替换掉上方的结构化配置。", + "rawEditorPlaceholder": "[providers.codeg]\ntype = \"kimi\"\nbase_url = \"https://api.moonshot.cn/v1\"\napi_key = \"sk-...\"" + }, + "authModeOfficialSubscription": "官网订阅", + "authModeCustomEndpoint": "自定义接口", + "authModeCustomEndpointHint": "手动配置 API URL 和 API Key 连接自定义接口。", + "authModeModelProvider": "模型供应商", + "modelProvider": "模型供应商", + "modelProviderHint": "使用已配置的模型供应商的 API URL、API Key 和模型。", + "selectModelProvider": "选择模型供应商", + "noModelProviderAvailable": "该代理未配置模型供应商。请前往模型供应商设置添加。", + "claude": { + "authMode": "认证方式", + "officialSubscription": "官方订阅", + "officialSubscriptionHint": "使用 Anthropic 官方订阅,无需 API Key。", + "mainModel": "主模型", + "reasoningModel": "推理模型(thinking)", + "haikuDefaultModel": "Haiku 默认模型", + "sonnetDefaultModel": "Sonnet 默认模型", + "opusDefaultModel": "Opus 默认模型", + "customModelOption": "自定义模型 ID", + "customModelOptionName": "自定义模型名称", + "customModelOptionDescription": "自定义模型描述", + "customModelOptionHint": "在 Claude 模型选择器中追加一个自定义条目(例如经自定义网关/代理提供的模型)。名称与描述为可选的显示信息。", + "effortLevel": "推理级别", + "effortLevelDefault": "默认级别", + "effortLevel_low": "低", + "effortLevel_medium": "中", + "effortLevel_high": "高", + "effortLevel_xhigh": "超高", + "sendAttributionHeader": "向接口发送归属/计费标识", + "sendAttributionHeaderAria": "向接口发送 Claude Code 归属/计费标识", + "disableNonessentialTraffic": "禁用遥测或多余的网络请求", + "disableNonessentialTrafficAria": "禁用 Claude Code 遥测或多余的网络请求" + }, + "dialogs": { + "confirmDeleteProvider": "确认删除 Provider {providerId}?", + "confirmDeleteProviderDescription": "将同步更新 OpenCode 配置与认证 JSON 文件,删除后不可恢复。", + "confirmUninstall": "确认卸载 {name}?", + "confirmUninstallDescription": "这会移除本地安装版本,之后可随时重新安装。", + "customInstallTitle": "自定义安装 {name}", + "customInstallDescription": "输入要安装的版本号。将重新安装并替换当前已安装的版本。", + "customInstallVersionLabel": "版本号", + "customInstallInvalid": "请输入有效的版本号,例如 1.2.3。", + "customInstallSubmit": "安装" + }, + "errors": { + "windowsFileLocked": "{name} 的程序文件正被运行中的会话占用,Windows 下无法替换。请先关闭所有 {name} 会话后重试。", + "nativeJsonMustBeObject": "原生 JSON 配置必须是对象", + "nativeJsonInvalid": "原生 JSON 配置格式错误:{message}", + "openCodeAuthMustBeObject": "OpenCode auth.json 必须是 JSON 对象", + "openCodeAuthInvalid": "OpenCode auth.json 格式错误:{message}", + "authMustBeObject": "auth.json 必须是 JSON 对象", + "authInvalid": "auth.json 格式错误:{message}", + "providerIdPattern": "Provider ID 仅支持字母、数字、下划线、点与中划线", + "providerExists": "Provider {providerId} 已存在", + "modelIdPattern": "模型 ID 仅支持字母、数字、下划线、点、冒号与中划线", + "modelExists": "Model {modelId} 已存在" + }, + "warnings": { + "nativeJsonRecoveredStructured": "原生 JSON 配置格式无效,已重置为结构化配置", + "nativeJsonRecoveredOpenCode": "原生 JSON 配置格式无效,已重置为 OpenCode 结构化配置", + "openCodeAuthRecovered": "OpenCode auth.json 格式无效,已重置为默认配置", + "authRecoveredStructured": "auth.json 格式无效,已重置为结构化配置" + }, + "toasts": { + "agentActionCompleted": "{name}{action}完成", + "agentActionFailed": "{name}{action}失败", + "localVersion": "本地版本:{version}", + "installCompletedVersionLater": "安装完成,版本将在下一次检测时更新", + "uninstallCompleted": "{name}卸载完成", + "uninstallFailed": "{name}卸载失败", + "localVersionRemoved": "本地版本已移除", + "saveAgentOrderFailed": "保存 Agent 排序失败", + "saveAgentSwitchFailed": "保存 Agent 开关失败", + "saveEnvFailed": "保存环境变量失败", + "grokSaved": "Grok 配置已保存", + "saveGrokNativeFailed": "保存 Grok 原生配置失败", + "saveGrokApiKeyFailed": "设置已保存,但 API Key 未能保存", + "cursorSaved": "Cursor 配置已保存", + "saveCursorConfigFailed": "保存 Cursor 配置失败", + "codexSaved": "Codex 配置已保存", + "saveCodexNativeFailed": "保存 Codex 原生配置失败", + "geminiSaved": "Gemini 配置已保存", + "saveGeminiFailed": "保存 Gemini 配置失败", + "providerDeleted": "Provider {providerId} 已删除", + "providerDeleteFailed": "删除 Provider {providerId} 失败", + "providerSaved": "Provider {providerId} 保存成功", + "saveProviderFailed": "保存 Provider {providerId} 失败", + "openCodeConfigSynced": "OpenCode 配置与认证 JSON 已同步保存。", + "openCodeSaved": "OpenCode 配置已保存", + "saveOpenCodeFailed": "保存 OpenCode 配置失败", + "openClawSaved": "OpenClaw 配置已保存", + "saveOpenClawFailed": "保存 OpenClaw 配置失败", + "configSaved": "配置已保存", + "configSavedHint": "已有会话需要重新打开才能生效", + "saveConfigManagementFailed": "保存配置管理失败", + "clineSaved": "Cline 配置已保存", + "saveClineFailed": "保存 Cline 配置失败", + "hermesSaved": "Hermes 配置已保存", + "saveHermesFailed": "保存 Hermes 配置失败", + "codeBuddySaved": "CodeBuddy 配置已保存", + "saveCodeBuddyFailed": "保存 CodeBuddy 配置失败", + "kimiCodeSaved": "Kimi Code 配置已保存", + "saveKimiCodeFailed": "保存 Kimi Code 配置失败", + "deepseekSaved": "DeepSeek 配置已保存", + "saveDeepSeekFailed": "保存 DeepSeek 配置失败", + "modelProviderRequired": "请先选择一个模型供应商再保存。", + "affectedRunningSessions": "{count} 个进行中的会话需重连以应用更改", + "providerConnected": "已连接 {providerId}", + "connectFailed": "连接 {providerId} 失败", + "providerDisconnected": "已断开 {providerId}", + "disconnectFailed": "断开 {providerId} 失败", + "catalogRefreshed": "目录已刷新——{count} 个 provider", + "catalogRefreshFailed": "刷新目录失败", + "piSaved": "Pi 配置已保存", + "savePiFailed": "保存 Pi 配置失败", + "piRuntimeSaved": "Pi 运行时已保存", + "savePiRuntimeFailed": "保存 Pi 运行时失败", + "piBinaryInstalled": "pi 已安装", + "piBinaryInstallFailed": "pi 安装失败", + "piBinaryUninstalled": "pi 已卸载", + "piBinaryUninstallFailed": "pi 卸载失败", + "savePiTrustFailed": "保存工作区信任失败" + }, + "version": { + "statusLabel": "版本状态", + "notInstalled": "未安装", + "remoteLocal": "远程:{remoteVersion} · 本地:{localVersion}", + "localOnly": "本地:{localVersion}", + "localInstalled": "{versionText}。已安装。", + "platformUnsupported": "{versionText}。当前平台不支持该 Agent。", + "uvxNotReady": "{versionText}。uv 运行时未安装——请在下方 uv 预检项中安装后再使用该 Agent。", + "clickInstall": "{versionText}。请点击右侧安装。", + "localUnrecognized": "{versionText}。本地版本无法识别,可尝试升级覆盖安装。", + "upgradeAvailable": "{versionText}。发现可升级版本。", + "remoteUnavailable": "{versionText}。远程版本暂不可用。", + "latest": "{versionText}。已是最新版本。" + }, + "adapter": { + "label": "ACP 适配器", + "badge": "ACP 适配器", + "badgeHint": "Codeg 为该智能体安装的是 ACP 适配器包,而不是厂商 CLI —— 两者互相独立,配置共享。", + "learnMore": "了解详情", + "missingWithNative": "已检测到你本地的 {nativeLabel}:{nativePath}。Codeg 通过 ACP 协议驱动智能体,而该 CLI 本身不支持 ACP,所以 Codeg 需要单独的适配器包 {adapterPackage}(由 Agent Client Protocol 项目维护,最初由 Zed 团队发起)。它自带运行时,不会修改或替换你的 {nativeCmd} 命令,读取的也是同一个 {configDir} —— 已有的登录和配置直接沿用。点击下方安装即可。", + "missing": "Codeg 通过 ACP 协议驱动智能体,而 {nativeLabel} 本身不支持 ACP,所以 Codeg 需要单独的适配器包 {adapterPackage}(由 Agent Client Protocol 项目维护,最初由 Zed 团队发起)。它自带运行时,因此不必先装 {nativeCmd} CLI;如果你已经装了,两者可以共存,并共用 {configDir} 里的登录和配置。点击下方安装即可。", + "readyWithNative": "适配器 {adapterCmd} 已安装 —— Codeg 启动的是它,而不是你本地的 {nativeCmd}({nativePath})。两者是各自独立的包,可以共存,且都读取 {configDir},登录和配置共享。", + "ready": "适配器 {adapterCmd} 已安装 —— Codeg 启动的就是它。它自带运行时,所以不需要另外安装 {nativeLabel};即便以后你装了,两者也能共存并共用 {configDir}。" + }, + "cline": { + "configDescription": "配置 Cline API 提供商和凭证。设置将保存到 ~/.cline/data/。" + }, + "opencodePlugins": { + "title": "OpenCode 插件", + "declared": "已声明的插件", + "noPlugins": "opencode.json 中未声明任何插件", + "status": { + "installed": "已安装", + "missing": "未安装" + }, + "installAll": "安装全部缺失插件", + "pinVersions": "固定 @latest 版本", + "install": "安装", + "uninstall": "卸载", + "refresh": "刷新", + "success": "所有插件安装成功", + "failed": "插件操作失败" + }, + "pi": { + "configManagement": "Pi 配置", + "configDescription": "Pi 通过模型提供方的 API Key 鉴权。Key 写入 ~/.pi/agent/auth.json,模型选择写入 settings.json。", + "providerLabel": "提供方", + "modelLabel": "模型", + "thinkingLabel": "思考", + "thinking": { + "off": "关闭", + "low": "低", + "medium": "中", + "high": "高", + "minimal": "极低", + "xhigh": "极高" + }, + "apiKeyLabel": "API Key", + "apiKeyHint": "为所选提供方写入 ~/.pi/agent/auth.json。", + "apiKeySetPlaceholder": "•••••• (已保存,留空则保持不变)", + "saveConfig": "保存 Pi 配置", + "providerModelRequired": "提供方和模型为必填", + "runtimeTitle": "运行时", + "runtimeDescription": "选择运行哪个 pi。使用默认,或指向你自己的 pi 构建。", + "modeDefault": "默认 pi", + "modeDefaultHint": "使用内置 pi-acp 适配器拉起 PATH 上的 pi。 安装 pi:npm install -g @earendil-works/pi-coding-agent", + "modeCustom": "自定义 pi", + "modeCustomHint": "运行你自己的 pi 构建、安装或包装脚本。", + "commandLabel": "pi 命令或路径", + "commandHint": "绝对路径、PATH 上的命令名,或包装脚本(如 monorepo 的 ./pi-test.sh)。", + "commandNotFound": "未找到命令", + "validate": "验证", + "advanced": "高级", + "configDirLabel": "配置目录 (PI_CODING_AGENT_DIR)", + "sessionDirLabel": "会话目录 (PI_CODING_AGENT_SESSION_DIR)", + "flagsHint": "pi-acp 不转发自定义 pi 参数(--approve、-e 等)——用脚本包装 pi 并将命令指向它。", + "customIncomplete": "请输入 pi 命令以保存", + "saveRuntime": "保存运行时", + "providerPlaceholder": "选择提供方", + "customProvider": "自定义提供方…", + "providerIdLabel": "提供方 ID", + "apiProtocolLabel": "API 协议", + "baseUrlLabel": "接口地址(Base URL)", + "customProviderHint": "在 ~/.pi/agent/models.json 中按你的接口地址定义一个提供方。多数自托管或代理服务使用 openai-completions。", + "baseUrlRequired": "接口地址(Base URL)为必填项", + "binaryTitle": "pi 二进制 (pi-coding-agent)", + "binaryDescription": "pi-acp 运行此 pi 二进制。可在此安装,或在下方指向你自己的构建。", + "binaryInstalled": "已安装", + "binaryMissing": "未安装", + "binaryChecking": "检测中…", + "installBinary": "安装 pi", + "installing": "安装中…", + "recheck": "重新检测", + "configDirSkillsNote": "设置了自定义配置目录后,设置页中管理的技能、专家与办公工具将不会作用于该 pi;请直接在该目录中管理其技能。", + "projectTrustTitle": "项目信任", + "projectTrustDescription": "你允许 pi 从中加载项目文件的目录。被信任的目录会让该仓库的 .pi/extensions 在 pi 启动时执行代码,且对其下所有子目录同样生效,你在终端里运行 pi 时也会沿用。", + "projectTrustLoading": "加载中…", + "projectTrustEmpty": "尚未对任何目录做出决定。", + "projectTrustTrusted": "已信任", + "projectTrustDenied": "不信任", + "projectTrustRevoke": "撤销", + "reasoningTitle": "推理", + "reasoningEnableLabel": "启用", + "reasoningDescription": "只有模型声明了推理能力,pi 才会发送推理强度——未声明的模型所有档位都会被压回 Off,所以输入框里的选择器一改就弹回。这里写入 models.json 中该模型的条目。", + "levelsLabel": "可选档位", + "levelsHint": "这些会成为输入框推理选择器里的档位。请选你的接入点能接受的值;不在这里的档位 pi 一律拒绝。", + "levelsEmptyError": "至少选一个档位——一个都不选时 pi 只会退回 Off。", + "wireValuesTitle": "高级:发给供应商的值", + "wireValuesHint": "留空表示原样发送档位名。接入点需要别的写法时才填——Google 系需要 LOW / HIGH。", + "defaultLevelUnlisted": "该档位不在上面的可选列表里——pi 会把它压下来。" + }, + "addCustomAgent": "添加自定义智能体", + "addCustomAgentHint": "接入任意兼容 ACP 的智能体。可从公开 ACP 注册表中选择,或直接粘贴其注册表信息。", + "customAgentFromRegistry": "ACP 注册表", + "customAgentManual": "手动填写", + "customAgentSearchPlaceholder": "搜索智能体…", + "customAgentLoadingCatalog": "正在加载 ACP 注册表…", + "customAgentRetry": "重试", + "customAgentNoResults": "没有匹配的智能体", + "customAgentAdd": "添加", + "customAgentAlreadyAdded": "已添加", + "customAgentUnsupportedPlatform": "当前平台没有可用的构建", + "customAgentAdded": "已添加 {name}", + "customAgentIdLabel": "注册表 ID", + "customAgentNameLabel": "显示名称", + "customAgentVersionLabel": "版本", + "customAgentSpecLabel": "分发信息(JSON)", + "customAgentSpecHint": "与 ACP 注册表 distribution 对象同构:支持 npx、uvx、binary 三种通道,也可整条粘贴注册表条目。npx/uvx 的 cmd 为包安装的可执行命令名,缺省按包名推导,与包名不同时需填写。binary 按平台键区分(本机为 {platform}),cmd 为压缩包内启动路径,sha256 可选用于校验下载。", + "customAgentTemplateLabel": "模板", + "customAgentKindLabel": "启动方式", + "customAgentInvalidJson": "不是合法的 JSON", + "customAgentNoDistribution": "未找到 npx、uvx 或 binary 分发方式", + "customAgentCancel": "取消", + "customAgentSave": "添加智能体", + "customAgentSaveChanges": "保存修改", + "customAgentEdit": "编辑智能体", + "customAgentEditHint": "修改名称、图标、分发信息与技能声明;智能体 ID 不可修改。", + "customAgentEditNotFound": "未找到自定义智能体 {id}", + "customAgentSaved": "已保存 {name}", + "customAgentVersionProbeLabel": "版本查询命令(可选)", + "customAgentVersionProbeHint": "查询本地安装版本的命令;留空时默认执行智能体命令加 --version。", + "customAgentRemove": "移除智能体", + "customAgentRemoveHint": "删除该智能体定义。已有会话的历史会保留,只是该智能体无法再启动。", + "customAgentIconLabel": "图标(可选)", + "customAgentIconUpload": "上传", + "customAgentIconReplace": "更换", + "customAgentIconClear": "移除图标", + "customAgentIconHint": "随智能体一起保存,离线也能显示。不上传则使用彩色首字母。", + "customAgentSkillsLabel": "Skills(共享 .agents/skills)", + "customAgentSkillsHint": "声明该智能体会读取共享的 .agents/skills 目录(全局与项目级),并将其加入所有技能矩阵。链接到共享目录的技能对读取该目录的其他智能体同样可见。", + "customAgentSkillsDirLabel": "专属技能目录", + "customAgentSkillsDirHint": "该智能体自身加载技能的目录绝对路径 —— 可与共享目录并存,也可单独使用。~ 会展开为主目录;链接技能时优先放入此目录。", + "customAgentMcpLabel": "MCP 支持", + "customAgentMcpHint": "会话建立时向该智能体注入 codeg 内置的 codeg-mcp 伴生进程 —— 委托、实时反馈与任务工具都依赖它。若该智能体不支持 MCP、连接时报错,请关闭此项;设置在下次连接时生效。", + "customAgentIconNotAnImage": "请选择图片文件。", + "customAgentIconTooLarge": "图标需小于 {limit} KB。", + "customAgentIconReadFailed": "无法读取该图片。", + "customAgentRemoveConfirm": "确定移除 {name}?已有会话会保留,但该智能体将无法再启动。", + "customAgentRemoveWithData": "同时删除已记录的会话历史", + "customAgentRemoved": "已移除 {name}", + "customAgentBadge": "自定义", + "customAgentNotLaunchable": "该智能体在此环境无法启动:{reason}" + }, + "SettingsPages": { + "agentsLoading": "加载 Agent 设置中...", + "skillPacksLoading": "正在加载技能包…" + }, + "GeneralSettings": { + "loading": "加载中...", + "sectionTitle": "常规", + "sectionDescription": "集中管理默认终端、渲染加速以及多智能体协同等通用偏好。", + "terminalTitle": "默认终端", + "terminalDescription": "选择从终端栏或文件树打开新终端标签页时使用的 Shell。智能体请求 codeg 代为执行整条命令行时也会使用它。", + "terminalSystemDefault": "系统默认", + "terminalPowerShell7": "PowerShell 7 (pwsh)", + "terminalWindowsPowerShell": "Windows PowerShell", + "terminalCmd": "命令提示符 (cmd)", + "terminalSaveFailed": "保存终端设置失败:{message}", + "terminalShellCustom": "自定义路径", + "terminalShellCustomPath": "Shell 路径", + "terminalShellCustomPlaceholder": "/usr/local/bin/fish", + "terminalShellCustomSave": "保存", + "terminalShellCustomHint": "支持绝对路径,或 PATH 中可解析的命令名。", + "terminalShellNotInstalled": "未安装", + "terminalShellNotFoundWarning": "当前主机上不存在此路径。", + "terminalCurrentShell": "当前使用:{path}", + "renderingDescription": "如果应用出现黑屏或渲染异常(常见于 AMD 显卡或部分 Intel 集成显卡),可关闭硬件加速。仅 Windows 桌面端生效。", + "disableHardwareAcceleration": "禁用硬件加速", + "renderingSaveFailed": "渲染设置保存失败:{message}", + "restartRequired": "已保存,重启应用后生效。", + "restartNow": "立即重启", + "restartFailed": "重启失败:{message}", + "loadFailed": "加载失败:{message}" + }, + "LoginPage": { + "documentTitle": "登录 - codeg", + "brand": "Codeg", + "subtitle": "输入访问 Token 以连接到桌面端", + "tokenPlaceholder": "Access Token", + "connect": "连接", + "connecting": "连接中...", + "helpText": "Token 可在桌面端 设置 → Web 服务 中获取", + "invalidToken": "Token 无效,请检查后重试", + "connectionFailed": "连接失败 (HTTP {status})", + "networkError": "无法连接到服务器" + }, + "CommitPage": { + "title": "提交代码", + "invalidFolderId": "无效的 folderId", + "loadingRepo": "正在加载仓库..." + }, + "MergePage": { + "title": "解决冲突", + "invalidFolderId": "无效的 folderId", + "loadingRepo": "正在加载仓库...", + "localVersion": "本地(我们的)", + "result": "结果", + "remoteVersion": "远程(他们的)", + "acceptLocal": "采用本地", + "acceptRemote": "采用远程", + "markResolved": "标记已解决", + "abortMerge": "中止", + "completeMerge": "完成合并", + "unresolvedConflicts": "文件中仍有未解决的冲突标记", + "fileResolved": "文件已解决", + "allResolved": "所有冲突已解决", + "conflictFiles": "冲突文件", + "loadingFile": "正在加载文件...", + "preparingMerge": "正在准备合并...", + "selectFile": "选择一个文件进行解决", + "noConflicts": "无冲突文件", + "skipFile": "跳过", + "abortSuccess": "操作已中止", + "applyAllNonConflicting": "应用所有非冲突变更", + "applyLeftNonConflicting": "应用本地", + "applyRightNonConflicting": "应用远程" + }, + "ImportSessions": { + "title": "导入本地会话", + "scanningTitle": "正在扫描本地智能体会话…", + "scanningHint": "正在遍历各智能体的本地会话存储,历史较多时可能需要一些时间。已导入的会话会顺带刷新。", + "scanFailed": "扫描失败", + "retry": "重试", + "rescan": "重新扫描", + "empty": "未发现本地会话", + "emptyHint": "本机未找到任何智能体的会话存储。", + "noMatches": "没有匹配当前筛选的会话", + "searchPlaceholder": "搜索标题或路径…", + "allAgents": "全部智能体", + "onlyImportable": "仅显示可导入", + "selectAll": "全选", + "clearSelection": "清空", + "expandAll": "全部展开", + "collapseAll": "全部折叠", + "summaryCounts": "共 {total} 个会话 · {importable} 个可导入 · {folders} 个文件夹", + "noFolderSkipped": "已跳过 {count} 个无项目目录的会话", + "folderNew": "新建", + "folderCounts": "可导入 {importable}/{total}", + "toggleFolderAria": "选择 {name} 中的全部可导入会话", + "toggleSessionAria": "选择会话 {title}", + "statusImported": "已导入", + "statusDeleted": "已删除", + "untitled": "未命名会话", + "messageCount": "{count} 条消息", + "selectedCount": "已选 {count} 个", + "importSelected": "导入所选", + "importing": "导入中…", + "close": "关闭", + "doneTitle": "导入完成", + "doneImported": "新导入", + "doneUpdated": "已刷新", + "doneSkipped": "已跳过", + "doneCreatedFolders": "新建文件夹", + "doneNotFound": "未找到", + "doneFailed": "失败", + "continueImport": "继续导入", + "toasts": { + "importFailed": "导入失败:{message}" + } + }, + "Folder": { + "workspaceStatus": { + "degradedTitle": "实时更新不可用", + "degradedHint": "监听器启动失败(如目录无读取权限)。请手动刷新以获取最新变更。", + "retry": "重试", + "retrying": "重试中..." + }, + "common": { + "all": "全部", + "cancel": "取消", + "close": "关闭", + "closeOthers": "关闭其它", + "closeAll": "关闭所有", + "confirm": "确认", + "save": "保存", + "delete": "删除", + "rename": "重命名", + "loading": "加载中...", + "refresh": "刷新", + "refreshing": "刷新中...", + "create": "创建", + "createAndSwitch": "创建并切换", + "openFile": "打开文件", + "viewDiff": "查看差异", + "push": "推送..." + }, + "statusLabels": { + "in_progress": "进行中", + "pending_review": "待复查", + "completed": "已完成", + "cancelled": "已取消" + }, + "sidebar": { + "title": "会话", + "locateActiveConversation": "定位当前会话", + "expandAllGroups": "展开全部分组", + "collapseAllGroups": "折叠全部分组", + "newConversation": "新建会话", + "newConversationShort": "新建", + "newChat": "新建会话", + "search": "搜索", + "noConversationsFound": "未找到会话。", + "importLocalSessions": "导入本地会话", + "importing": "导入中...", + "error": "错误:{message}", + "completeAllSessions": "完成全部会话", + "completeAllReviewTitle": "完成全部复查会话?", + "completeAllReviewDescription": "这会将复查中的 {count} 个会话全部标记为已完成。", + "completing": "处理中...", + "toasts": { + "importedSessions": "已导入 {imported} 个会话,跳过 {skipped} 个", + "importedAndUpdated": "已导入 {imported} 个会话,更新 {updated} 个标题,跳过 {skipped} 个", + "updatedTitles": "已更新 {updated} 个标题,跳过 {skipped} 个", + "noNewSessionsFound": "没有新会话(已跳过 {skipped} 个)", + "importFailed": "导入失败:{message}", + "reviewCompleted": "已将 {count} 个复查会话标记为已完成", + "completeReviewFailed": "批量完成复查会话失败:{message}", + "folderOpened": "已打开文件夹 {name}", + "folderRemoved": "已移除文件夹 {name}", + "openFolderFailed": "打开文件夹失败", + "removeFolderFailed": "移除文件夹失败:{message}", + "reorderFoldersFailed": "重新排序文件夹失败:{message}", + "changeFolderColorFailed": "修改颜色失败:{message}", + "setFolderAliasFailed": "设置别名失败:{message}", + "changeFolderDefaultAgentFailed": "设置默认智能体失败:{message}" + }, + "statsLabel": "{folders} 个文件夹 · {convos} 个会话", + "reorderHandle": "拖拽排序", + "openFolder": "打开文件夹", + "searchPlaceholder": "搜索会话...", + "viewOptions": "显示选项", + "showCompleted": "显示已完成会话", + "showWorktrees": "显示工作树文件夹", + "showRecent": "显示「最近」分组", + "moreOptions": "更多选项", + "sortBy": "排序方式", + "sortByCreatedAt": "按创建时间排序", + "sortByUpdatedAt": "按更新时间排序", + "sectionOrder": "区域顺序", + "sectionOrderMoveUp": "上移", + "sectionOrderMoveDown": "下移", + "sectionOrderItemLabel": "{name} — 第 {position} 位,共 {total} 位", + "statusRunningBadge": "运行中", + "runningCountBadge": "{count} 个会话进行中", + "statusCancelledBadge": "已取消", + "worktreeRemovedBadge": "源 worktree 已删除", + "conversationCountUnit": "{count} 条", + "emptyFolderHint": "暂无会话", + "noMatchingConversations": "未找到匹配的会话", + "noUnfinishedConversations": "当前暂无未完成会话,右上角可启用显示已完成会话", + "removeFolderConfirmTitle": "从工作区移除该文件夹?", + "removeFolderConfirmDescription": "从工作区移除 \"{name}\"?其相关 Tab 与终端将会关闭。", + "folderHeaderMenu": { + "manageConversations": "会话管理…", + "manageLinks": "关联的文件夹", + "changeColor": "修改颜色", + "useThemeColor": "使用设置主题", + "setDefaultAgent": "设置默认智能体", + "defaultAgentNone": "不设置(使用全局默认)", + "agentUnavailableSuffix": "(不可用)", + "loadingAgents": "正在加载代理…", + "setAlias": "设置别名…", + "setAliasTitle": "设置文件夹别名", + "setAliasPlaceholder": "输入别名(留空清除)", + "setAliasSave": "保存", + "setAliasCancel": "取消", + "removeFromWorkspace": "从工作区移除" + }, + "manageConversations": { + "title": "会话管理", + "searchPlaceholder": "按标题搜索…", + "agentFilterAll": "全部智能体", + "statusFilterAll": "全部状态", + "folderFilterAll": "全部文件夹", + "branchFilterAll": "全部分支", + "branchNone": "无分支", + "branchSearchPlaceholder": "搜索分支…", + "noMatchingBranches": "无匹配分支", + "selectAllVisible": "全选", + "deselectAll": "取消全选", + "selectedCount": "已选 {count} 条", + "matchedCount": "匹配 {count} 条", + "untitledConversation": "未命名会话", + "setStatus": "设为状态…", + "deleteSelected": "删除", + "noConversations": "此文件夹暂无会话。", + "noConversationsWorkspace": "工作区暂无会话。", + "noMatchingConversations": "没有匹配过滤条件的会话。", + "confirmDeleteTitle": "删除 {count} 个会话?", + "confirmDeleteDescription": "此操作不可撤销。", + "toastDeleted": "已删除 {count} 个会话", + "toastStatusUpdated": "已更新 {count} 个会话的状态", + "toastOpFailed": "操作失败:{message}" + }, + "sectionPinned": "已置顶", + "sectionFolders": "文件夹", + "sectionChats": "聊天", + "sectionRecent": "最近", + "noChats": "没有聊天", + "noRecent": "暂无最近会话", + "showMoreRecent": "显示更多({count})", + "noFolders": "没有打开的文件夹", + "newChatAction": "新建聊天", + "automations": "自动化", + "tasks": "待办任务", + "loadingSubsessions": "正在加载子会话…" + }, + "conversation": { + "reloadFailed": "会话重新加载失败:{message}", + "reloaded": "当前会话已重新加载", + "reload": "重新加载", + "activeConversationIndicator": "当前激活会话", + "newConversation": "新建会话", + "closeConversation": "关闭会话", + "copyText": "复制文本", + "copyTextSuccess": "已复制", + "copyTextFailed": "复制失败", + "forkSession": "分叉会话", + "forkSessionSuccess": "会话分叉成功", + "forkSessionFailed": "会话分叉失败:{error}", + "exportConversation": "导出会话", + "exportImage": "图片", + "exportMarkdown": "Markdown", + "exportHtml": "HTML", + "exportSuccess": "会话已导出", + "exportFailed": "导出失败", + "exportImageTooLong": "会话内容过长,不支持导出为图片", + "exportLabels": { + "untitledConversation": "未命名会话", + "agent": "代理", + "model": "模型", + "status": "状态", + "started": "开始时间", + "updated": "更新时间", + "tokens": "令牌统计", + "duration": "时长", + "inputTokens": "输入", + "outputTokens": "输出", + "cacheRead": "缓存读取", + "cacheWrite": "缓存写入", + "user": "用户", + "assistant": "助手", + "system": "系统", + "toolResult": "结果", + "toolError": "错误" + }, + "moreActions": "更多操作" + }, + "sessionDetails": { + "menuLabel": "会话详情", + "noActiveSession": "暂无活动会话", + "title": "会话详情", + "subtitle": "会话元信息与 Token 用量", + "fieldTitle": "标题", + "untitled": "未命名会话", + "sessionId": "会话 ID", + "externalId": "扩展 ID", + "agent": "智能体", + "model": "模型", + "status": "状态", + "gitBranch": "Git 分支", + "parentId": "父会话", + "tokensHeading": "Token 用量", + "totalTokens": "总计", + "inputTokens": "输入", + "outputTokens": "输出", + "cacheWrite": "缓存写入", + "cacheRead": "缓存读取", + "contextWindow": "上下文窗口", + "duration": "时长", + "loadingStats": "正在加载 Token 用量…", + "loadFailed": "加载 Token 用量失败", + "noStats": "暂无用量记录", + "timestampsHeading": "时间", + "createdAt": "创建时间", + "updatedAt": "更新时间", + "none": "—", + "copyField": "复制{field}", + "copiedField": "已复制{field}" + }, + "conversationCard": { + "untitledConversation": "未命名会话", + "newConversation": "新建会话", + "rename": "重命名", + "status": "状态", + "delete": "删除", + "importLocalSessions": "导入本地会话", + "importing": "导入中...", + "renameConversation": "重命名会话", + "deleteConversationTitle": "删除会话?", + "deleteConversationDescription": "会删除“{title}”,此操作不可撤销。", + "cancel": "取消", + "save": "保存", + "pin": "置顶", + "unpin": "取消置顶", + "markCompleted": "标记为已完成", + "reopen": "重新打开", + "expandSubsessions": "展开子会话", + "collapseSubsessions": "折叠子会话" + }, + "search": { + "dialogTitle": "搜索", + "dialogTitleWithFolder": "搜索 — {name}", + "tabConversations": "会话", + "tabFiles": "文件", + "placeholder": "搜索会话...", + "filePlaceholder": "搜索文件或目录...", + "allAgents": "全部", + "searching": "搜索中...", + "typeToSearch": "输入关键词搜索会话", + "typeToSearchFiles": "输入关键词搜索文件或目录", + "noResults": "未找到结果。", + "untitledConversation": "未命名会话" + }, + "folderTitleBar": { + "showSidebar": "显示侧边栏", + "hideSidebar": "隐藏侧边栏", + "toggleTerminal": "切换终端", + "toggleAuxPanel": "切换辅助面板", + "search": "搜索", + "openSettings": "打开设置", + "backToConversations": "返回会话", + "withShortcut": "{label}({shortcut})" + }, + "statusBar": { + "connection": { + "connected": "已连接", + "connecting": "连接中...", + "prompting": "响应中...", + "error": "连接异常", + "disconnected": "未连接", + "tooltip": "{agent}:{status}", + "tooltipError": "{agent}:{error}", + "title": "智能体连接", + "triggerAria": "智能体连接:{status}", + "workingDir": "工作目录", + "sessionId": "会话 ID", + "viewerNote": "已接入其他客户端拥有的会话——重连只会重新接入当前视图。", + "reconnectInterrupts": "重连会重启智能体,并中断正在进行的工作。", + "reconnect": "重新连接", + "reconnecting": "正在重新连接...", + "reconnectUnavailable": "暂无可重连的会话。" + }, + "tasks": { + "title": "任务" + }, + "alerts": { + "title": "告警", + "empty": "暂无告警信息", + "details": "详情" + }, + "stats": { + "conversations": "{count} 个会话", + "openUsage": "查看会话统计与 Token 用量" + }, + "tokens": { + "contextWindowUsageAria": "上下文窗口使用率", + "contextWindow": "上下文窗口", + "usedMax": "已用 / 上限", + "tokenUsage": "Token 用量", + "input": "输入", + "output": "输出", + "cacheRead": "缓存读取", + "cacheWrite": "缓存写入", + "total": "总计" + } + }, + "auxPanel": { + "tabs": { + "files": "文件", + "changes": "变更", + "commits": "提交" + }, + "noFolderTitle": "暂无打开的文件夹", + "noFolderHint": "打开一个文件夹后在这里查看" + }, + "windowControls": { + "minimizeWindow": "最小化窗口", + "minimize": "最小化", + "maximizeWindow": "最大化窗口", + "maximize": "最大化", + "restoreWindow": "还原窗口", + "restore": "还原", + "closeWindow": "关闭窗口", + "close": "关闭" + }, + "tabs": { + "closeConversationTab": "关闭会话标签", + "close": "关闭", + "closeOthers": "关闭其它", + "splitRight": "向右拆分", + "splitDown": "向下拆分", + "splitAndMoveRight": "拆分并右移", + "splitAndMoveDown": "拆分并下移", + "moveToOppositeGroup": "移动到对侧分组", + "moveToGroup": "移动到分组", + "groupLabel": "分组 {index}", + "changeSplitterOrientation": "切换分隔方向", + "unsplit": "取消拆分", + "unsplitAll": "全部取消拆分", + "closeAll": "关闭所有", + "tileDisplay": "平铺显示", + "untileDisplay": "取消平铺" + }, + "fileWorkspace": { + "files": "文件", + "closeFileTab": "关闭文件标签", + "close": "关闭", + "closeOthers": "关闭其它", + "closeAll": "关闭所有", + "preview": "预览", + "editSource": "编辑源码", + "maximize": "最大化", + "restore": "还原", + "emptyDirectory": "空目录" + }, + "terminal": { + "rename": "重命名", + "close": "关闭", + "closeOthers": "关闭其它", + "closeAll": "关闭所有", + "hideTerminal": "隐藏终端({shortcut})", + "openFolderFirst": "请先打开一个文件夹" + }, + "workspaceDialog": { + "title": "打开文件夹", + "manageTitle": "关联的文件夹", + "addTargetsTitle": "添加要关联的文件夹", + "pickRootDescription": "选择该工作空间的主文件夹。", + "linksDescription": "把其它文件夹以子目录的形式关联进来,智能体就能在同一个工作空间里跨项目工作。", + "addTargetsDescription": "选择一个或多个文件夹,每个都会成为工作空间的一个子目录。", + "useSystemPicker": "系统选择器", + "next": "下一步", + "back": "返回", + "done": "完成", + "change": "更改", + "addFolders": "添加文件夹", + "addSelected": "添加", + "addSelectedCount": "添加 {count} 个", + "createCount": "关联 {count} 个文件夹", + "discardPending": "放弃", + "noLinks": "还没有关联任何文件夹。", + "gitExclude": "不让关联目录污染 git 状态", + "rename": "重命名", + "unlink": "解除关联", + "repair": "重建链接", + "saveName": "保存", + "cancelRename": "取消", + "removePending": "移除", + "willAppearAs": "在工作空间中显示为 {name}", + "renamedForDuplicate": "已改名 —— {base} 已被另一个关联占用", + "renamedForExistingEntry": "已改名 —— 该文件夹中已存在 {base}", + "partiallyCreated": "只成功关联了 {count} 个文件夹", + "openFailed": "打开文件夹失败", + "previewFailed": "检查所选文件夹失败", + "createFailed": "关联文件夹失败", + "renameFailed": "重命名失败", + "removeFailed": "解除关联失败", + "repairFailed": "重建链接失败", + "status": { + "ok": "已关联", + "missing": "链接已从该文件夹中消失", + "conflicted": "该名称已被其它条目占用", + "broken": "被关联的文件夹已不存在" + }, + "nameIssue": { + "empty": "请输入名称", + "illegalChars": "不能包含 / \\ : * ? \" < > |", + "tooLong": "名称过长", + "reserved": "该名称是 Windows 保留名", + "duplicate": "该名称已被使用" + }, + "rejection": { + "not_found": "找不到该文件夹", + "not_a_directory": "该路径不是文件夹", + "same_as_root": "这就是工作空间文件夹本身", + "ancestor_of_root": "该文件夹包含了当前工作空间", + "inside_root": "已在工作空间内部", + "already_linked": "已经关联过", + "name_unavailable": "该文件夹已无可用的名称", + "alreadyLinkedAs": "已作为 {name} 关联" + } + }, + "folderNameDropdown": { + "fallbackFolderName": "文件夹", + "openFolder": "打开文件夹", + "cloneRepository": "克隆仓库", + "projectBoot": "项目启动器", + "opened": "已打开", + "recentOpen": "最近打开" + }, + "fileWorkspacePanel": { + "addSelectionToChat": "添加选区到会话", + "addToChat": "加入会话", + "addSelectionToChatDone": "已将 {label} 加入会话", + "addFileToChat": "添加文件到会话", + "toggleWordWrap": "切换自动换行", + "addFileToChatDone": "已将 {label} 加入会话", + "viewDiff": "查看差异", + "openFile": "打开文件", + "fileCount": "{count} 个文件", + "openFileOrDiff": "从右侧面板打开文件或差异", + "disk": "磁盘", + "head": "HEAD(当前提交)", + "unsaved": "未保存", + "workingTree": "工作区", + "loading": "加载中...", + "compareWithBranch": "{path} · 与 {branch} 比较", + "hunkCount": "{count} 个区块", + "prev": "上一个", + "next": "下一个", + "jumpToLine": "跳转到第 {line} 行", + "noParsedDiffSections": "未解析到差异区块", + "loadingEditor": "编辑器加载中...", + "imageZoomIn": "放大", + "imageZoomOut": "缩小", + "imageZoomReset": "重置缩放", + "htmlPreviewTitle": "HTML 预览", + "htmlPreviewTrust": "运行脚本", + "htmlPreviewTrustHint": "运行此文件的脚本并允许网络访问。仅对可信任的文件启用。", + "officePreviewTitle": "办公文档预览", + "officeFullRender": "完整渲染", + "officeFullRenderHint": "渲染 Morph 动画、3D 和公式(会运行幻灯片自带的脚本)", + "officeNotInstalled": "未安装 OfficeCLI", + "officeNotInstalledHint": "在 设置 → 办公工具 中安装 OfficeCLI,即可预览 Word、Excel 和 PowerPoint 文件。", + "officeOpenSettings": "打开设置", + "officeWatchFailed": "无法启动实时预览", + "officeWatchRetry": "重试", + "officeServerInstallHint": "OfficeCLI 需安装在服务器主机上。请在服务器上运行以下命令后重试:", + "officeRemoteDesktopUnsupported": "远程桌面窗口暂不支持实时预览。请在服务器的 Web 界面中打开此工作区来预览 Office 文件。" + }, + "branchDropdown": { + "toasts": { + "commitCodeCompleted": "提交代码完成", + "pushCodeCompleted": "推送代码完成", + "committedFiles": "已提交 {count} 个文件", + "taskCompleted": "{label} 完成", + "taskFailed": "{label} 失败", + "mergeNoNewCommits": "{branchName} 没有新的提交", + "mergedCommits": "已合并 {count} 个提交", + "allFilesUpToDate": "所有文件均为最新版本", + "updatedFiles": "已更新 {count} 个文件", + "openCommitWindowFailed": "打开提交窗口失败", + "openPushWindowFailed": "打开推送窗口失败", + "upstreamSet": "已设置远程跟踪分支", + "upstreamSetAndPushed": "已设置远程跟踪分支并推送 {count} 个提交", + "noCommitsToPush": "没有可推送的提交", + "pushedCommits": "已推送 {count} 个提交", + "switchedToFolder": "已切换到 {name}", + "switchFailed": "切换分支失败", + "openStashWindowFailed": "打开贮藏窗口失败" + }, + "tasks": { + "newBranch": "新建分支 {name}", + "newWorktree": "新建工作树 {name}", + "checkoutTo": "切换到 {branchName}", + "mergeBranch": "合并 {branchName}", + "rebaseTo": "变基到 {branchName}", + "deleteRemoteBranch": "删除远程分支 {branchName}", + "initGitRepo": "初始化 Git 仓库", + "pullCode": "更新代码", + "fetchInfo": "获取信息", + "pushCode": "推送代码", + "stashChanges": "贮藏更改", + "stashPop": "取消贮藏", + "deleteBranch": "删除分支 {branchName}", + "removeWorktree": "删除 {branchName} 的工作树", + "removeWorktreeAndBranch": "删除工作树及分支 {branchName}", + "updateBranch": "更新分支 {branchName}" + }, + "confirm": { + "mergeTitle": "合并分支", + "rebaseTitle": "变基分支", + "mergeDescription": "确定将 {branchName} 合并到当前分支 {currentBranch} 吗?", + "rebaseDescription": "确定将当前分支 {currentBranch} 变基到 {branchName} 吗?", + "deleteRemoteTitle": "删除远程分支", + "deleteRemoteDescription": "确定删除远程分支 {branchName} 吗?此操作将从远程仓库中移除该分支,且不可恢复。", + "deleteTitle": "删除分支", + "deleteDescription": "确定删除分支 {branchName} 吗?此操作不可恢复。", + "forceDeleteTitle": "强制删除分支", + "forceDeleteDescription": "分支 {branchName} 尚未完全合并,确定要强制删除吗?此操作不可恢复。", + "deleteWorktreeTitle": "删除工作树", + "deleteWorktreeDescription": "删除检出了 {branchName} 的工作树目录?分支及其提交会保留。", + "forceDeleteWorktreeTitle": "强制删除工作树", + "forceDeleteWorktreeDescription": "{branchName} 的工作树中有未提交或未跟踪的文件。仍要删除吗?这些改动将无法恢复。", + "deleteWorktreeAndBranchTitle": "删除工作树及分支", + "deleteWorktreeAndBranchDescription": "删除 {branchName} 的工作树、该分支本身及其工作区文件夹?其中的会话会移动到仓库文件夹下。此操作无法撤销。", + "forceDeleteWorktreeAndBranchTitle": "强制删除工作树及分支", + "forceDeleteWorktreeAndBranchDescription": "{branchName} 的工作树中有未提交的文件,或该分支尚未完全合并。仍要一并删除吗?此操作无法撤销。" + }, + "current": "当前", + "switchToBranch": "切换到此分支", + "mergeBranchIntoCurrent": "将 {branchName} 合并到 {currentBranch}", + "rebaseCurrentToBranch": "将 {currentBranch} 变基到 {branchName}", + "noBranch": "无分支", + "detachedHead": "游离 HEAD({sha})", + "initGitRepo": "初始化 Git 仓库", + "pullCode": "更新代码", + "fetchRemoteBranches": "提取远程分支", + "openCommitWindow": "提交代码...", + "pushCode": "推送...", + "pushBranch": "推送", + "newBranch": "新建分支...", + "newWorktree": "新建工作树...", + "stashChanges": "贮藏更改...", + "stashPop": "取消贮藏...", + "manageRemotes": "管理远程...", + "localBranches": "本地分支 ({count})", + "noLocalBranches": "无本地分支", + "remoteBranches": "远程分支 ({count})", + "noRemoteBranches": "无远程分支", + "dialogs": { + "newBranchTitle": "新建分支", + "newBranchDescription": "从当前分支 {branch} 创建新分支", + "branchNamePlaceholder": "分支名称", + "newWorktreeTitle": "新建工作树", + "newWorktreeDescription": "从当前分支 {branch} 创建新的工作树", + "branchNameLabel": "分支名称", + "worktreePathLabel": "工作树路径", + "worktreePathPlaceholder": "工作树路径", + "manageRemotesTitle": "管理远程", + "manageRemotesEmpty": "未配置远程仓库", + "remoteNamePlaceholder": "远程名称", + "remoteUrlPlaceholder": "远程 URL", + "addRemote": "添加", + "savingRemotes": "保存中..." + }, + "conflict": { + "title": "合并冲突", + "description": "以下文件存在冲突,需要手动解决:", + "abort": "中止合并", + "openMergeTool": "打开合并工具", + "completeMerge": "完成合并", + "abortSuccess": "合并已中止", + "completeSuccess": "合并完成" + }, + "stashDialog": { + "title": "贮藏更改", + "description": "将当前更改保存到贮藏区", + "messageLabel": "消息", + "messagePlaceholder": "贮藏消息(可选)", + "keepIndex": "保留暂存区(已暂存的更改保持不变)", + "cancel": "取消", + "stash": "贮藏", + "success": "更改已贮藏", + "error": "贮藏更改失败" + }, + "unstashDialog": { + "title": "取消贮藏", + "noStashes": "没有贮藏记录", + "selectFile": "选择文件查看差异", + "viewDiff": "查看差异", + "original": "原始", + "modified": "修改后", + "apply": "应用", + "drop": "删除", + "applySuccess": "贮藏已应用", + "dropSuccess": "贮藏已删除", + "confirmApply": "将贮藏 {ref} 应用到工作目录?", + "cancel": "取消" + }, + "deleteBranch": "删除分支", + "deleteWorktree": "删除工作树", + "deleteWorktreeAndBranch": "删除工作树及分支", + "searchPlaceholder": "搜索分支和操作", + "searchAriaLabel": "搜索分支和操作", + "branchListLabel": "分支和操作", + "noMatches": "无匹配项" + }, + "commitDialog": { + "toasts": { + "commitCompleted": "提交代码完成", + "pushFailed": "推送失败", + "committedFiles": "已提交 {count} 个文件", + "addedToVcs": "已添加到 VCS", + "addToVcsFailed": "添加到 VCS 失败", + "fileDeleted": "文件已删除", + "deleteFailed": "删除失败", + "fileRolledBack": "文件已回滚", + "rollbackFailed": "回滚失败", + "dirRolledBack": "目录已回滚", + "dirDeleted": "目录已删除" + }, + "confirm": { + "deleteTitle": "确认删除", + "deleteDescription": "确定要删除文件「{file}」吗?此操作不可恢复。", + "rollbackTitle": "确认回滚", + "rollbackDescription": "确定要回滚文件「{file}」到 HEAD 版本吗?未保存的修改将丢失。", + "rollbackDirDescription": "确定要回滚目录「{dir}」到 HEAD 版本吗?未保存的修改将丢失。", + "deleteDirDescription": "确定要删除目录「{dir}」吗?此操作不可恢复。" + }, + "actions": { + "select": "选择", + "unselect": "取消选择", + "rollback": "回滚", + "addToVcs": "添加到 VCS" + }, + "aria": { + "selectFile": "{action}:{path}", + "unselectAllFiles": "取消选择全部文件", + "selectAllFiles": "选择全部文件", + "unselectTracked": "取消选择已跟踪改动", + "selectTracked": "选择已跟踪改动", + "unselectUntracked": "取消选择未跟踪文件", + "selectUntracked": "选择未跟踪文件" + }, + "loading": "加载中...", + "selectionCount": "{selected} / {total} 个文件", + "emptyFiles": "没有改动的文件", + "trackedChanges": "已跟踪改动 ({count})", + "untrackedFiles": "未跟踪文件 ({count})", + "commitMessage": "提交消息", + "commitMessagePlaceholder": "输入提交信息...", + "commitButton": "提交 ({count})", + "commitAndPushButton": "提交并推送 ({count})", + "head": "HEAD(当前提交)", + "workingTree": "工作区", + "clickFileToDiff": "点击文件名查看差异", + "loadingDiff": "加载差异..." + }, + "pushWindow": { + "title": "推送代码", + "noUnpushedCommits": "没有未推送的提交", + "noRemoteConfigured": "未配置 Git 远程仓库\n请在「管理远程」中添加远程地址", + "newBranchNoPushedCommits": "新分支 — 推送以创建远程跟踪分支", + "unpushed": "未推送", + "selectFileToViewDiff": "选择文件查看差异", + "before": "修改前", + "after": "修改后", + "push": "推送", + "toasts": { + "pushSuccess": "推送成功", + "pushFailed": "推送失败", + "upstreamSet": "已设置远程跟踪分支", + "upstreamSetAndPushed": "已设置远程跟踪分支并推送 {count} 个提交", + "noCommitsToPush": "没有可推送的提交", + "pushedCommits": "已推送 {count} 个提交" + } + }, + "gitLogTab": { + "filesTitle": "文件", + "expandAllFiles": "展开全部文件", + "collapseAllFiles": "折叠全部文件", + "workspace": "工作区", + "retry": "重试", + "noCommitsFound": "未找到提交记录", + "notAGitRepoTitle": "不是 Git 仓库", + "notAGitRepoHint": "可从上方分支菜单初始化 Git,或打开已有的 Git 仓库。", + "hash": "Hash", + "copyHash": "复制哈希", + "copyMessage": "复制提交消息", + "showMore": "展开", + "showLess": "收起", + "author": "作者", + "noFileChangeDetails": "暂无文件变更详情。", + "loadingFiles": "正在加载文件…", + "branchesTitle": "分支", + "loadingBranches": "正在加载分支...", + "noContainingBranches": "未找到包含此提交的分支。", + "newBranch": "新建分支...", + "resetToHere": "重置到此处", + "resetDisabledReasonNotCurrentBranchView": "仅在查看当前分支时可用", + "copyFullCommitHashAria": "复制完整提交哈希 {hash}", + "pushStatus": { + "pushed": "已推送到远程", + "notPushed": "未推送到远程", + "unknown": "推送状态未知(未配置上游分支)" + }, + "time": { + "monthsAgo": "{count} 个月前", + "daysAgo": "{count} 天前", + "hoursAgo": "{count} 小时前", + "minsAgo": "{count} 分钟前", + "justNow": "刚刚" + }, + "toasts": { + "createdAndSwitchedNewBranch": "已创建并切换到新分支", + "newBranchFromCommit": "{name}(来自 {shortHash})", + "createBranchFailed": "新建分支失败", + "openPushWindowFailed": "打开推送窗口失败", + "resetSuccess": "重置成功", + "resetSuccessDescription": "已将 {branch} 以 {mode} 重置到 {shortHash}", + "resetFailed": "重置失败" + }, + "authorFilter": { + "label": "作者", + "searchPlaceholder": "搜索作者", + "noAuthors": "未找到作者", + "you": "你", + "filterByAuthorAria": "按作者筛选提交", + "filterByQuery": "按“{query}”过滤", + "clearAuthorFilterAria": "清除作者过滤", + "recent": "最近", + "matchingAuthors": "匹配的作者", + "removeFromRecent": "从最近列表移除 {name}" + }, + "branchSelector": { + "label": "分支", + "head": "HEAD", + "headHint": "跟随当前分支", + "headHintWithBranch": "跟随当前分支({branch})", + "searchBranch": "搜索分支...", + "noBranches": "无分支", + "selectBranchPlaceholder": "选择分支...", + "localBranches": "本地分支", + "current": "当前", + "remoteBranches": "远程分支", + "refreshCommitHistory": "刷新提交记录", + "clearBranchFilterAria": "清除分支过滤" + }, + "dialogs": { + "newBranchTitle": "新建分支", + "newBranchDescription": "以提交 {shortHash} 作为最后提交创建新分支。", + "branchNamePlaceholder": "分支名称", + "reset": { + "title": "将当前分支重置到此提交", + "branchLabel": "分支", + "targetLabel": "目标提交", + "messageLabel": "提交信息", + "modeLabel": "重置模式", + "confirmButton": "重置", + "modes": { + "soft": { + "label": "--soft", + "description": "将 HEAD 和当前分支指针移动到目标提交。\n暂存区(Index)和工作区(Working Tree)保持不变。\n被回退提交对应的改动会保留为“已暂存”状态。" + }, + "mixed": { + "label": "--mixed(默认)", + "description": "将 HEAD 移动到目标提交。\n把暂存区重置为目标提交状态,但保留工作区改动。\n这些改动会从“已暂存”变为“未暂存”。" + }, + "hard": { + "label": "--hard", + "description": "将 HEAD、暂存区和工作区全部重置到目标提交。\n目标提交之后的本地已跟踪改动会被直接丢弃。\n这是破坏性操作。" + }, + "keep": { + "label": "--keep", + "description": "将 HEAD 移动到目标提交,并尽量保留本地改动。\n仅当本地改动与目标提交不冲突时才会保留。\n若存在冲突,操作会中止以避免覆盖你的修改。" + } + } + } + }, + "moreActions": "更多 Git 操作" + }, + "gitChangesTab": { + "workspace": "工作区", + "noChanges": "暂无本地改动", + "notAGitRepoTitle": "不是 Git 仓库", + "notAGitRepoHint": "可从上方分支菜单初始化 Git,或打开已有的 Git 仓库。", + "trackedChanges": "本地已跟踪改动 ({count})", + "untrackedFiles": "本地未跟踪文件 ({count})", + "expandTracked": "展开已跟踪改动", + "collapseTracked": "折叠已跟踪改动", + "expandUntracked": "展开未跟踪文件", + "collapseUntracked": "折叠未跟踪文件", + "showRemainingItems": "显示其余 {count} 项", + "actions": { + "commitCode": "提交代码", + "rollback": "回滚", + "addToVcs": "添加到 VCS", + "delete": "删除", + "moreActions": "更多 Git 操作", + "addAllToVcs": "全部添加到 VCS", + "rollbackAll": "全部回滚", + "refresh": "刷新" + }, + "toasts": { + "noAddableFilesInDir": "该目录下没有可添加到 VCS 的变更文件", + "noRollbackFilesInDir": "该目录下没有可回滚的变更文件", + "addedToVcs": "已添加 {name} 到 VCS", + "addToVcsFailed": "添加到 VCS 失败", + "openCommitWindowFailed": "打开提交窗口失败", + "rolledBack": "已回滚 {name}", + "rollbackFailed": "回滚失败", + "addedFilesToVcs": "已添加 {count} 个文件到 VCS", + "rolledBackFiles": "已回滚 {count} 个文件", + "deleted": "已删除 {name}", + "deleteFailed": "删除失败", + "deletedFiles": "已删除 {count} 个文件", + "noDeletableFilesInDir": "该目录下没有可删除的变更文件", + "commitFailed": "提交失败" + }, + "directoryDialog": { + "descriptionAdd": "选择目录 {path} 下要添加到 VCS 的文件。", + "descriptionRollback": "选择目录 {path} 下要回滚的文件。", + "descriptionDelete": "选择目录 {path} 下要删除的文件。此操作不可撤销。", + "descriptionFallback": "选择要操作的文件。", + "selectionCount": "已选择 {selected} / {total} 个文件", + "selectAll": "全选", + "unselectAll": "取消全选", + "loadingCandidates": "正在加载目录变更...", + "noOperableFiles": "没有可操作的文件" + }, + "rollbackConfirm": { + "title": "确认回滚", + "descriptionWithTarget": "确定回滚{kind}「{name}」的本地修改吗?", + "descriptionFallback": "确定回滚本地修改吗?", + "kindDirectory": "目录", + "kindFile": "文件" + }, + "deleteConfirm": { + "title": "确认删除", + "descriptionWithTarget": "确定删除{kind}「{name}」吗?此操作不可撤销。", + "descriptionFallback": "确定删除吗?此操作不可撤销。", + "kindDirectory": "目录", + "kindFile": "文件" + }, + "quickCommit": { + "placeholder": "提交信息(回车提交)" + } + }, + "tabContext": { + "loadingConversation": "加载中...", + "untitledConversation": "未命名会话", + "newConversation": "新建会话" + }, + "fileTreeTab": { + "workspace": "工作区", + "retry": "重试", + "git": "Git", + "openInFileManager": "在文件管理器打开", + "openInFinder": "在访达打开", + "openInExplorer": "在资源管理器打开", + "attachToCurrentSession": "添加到会话", + "compareWithBranch": "与分支比较...", + "reloadFromDisk": "从磁盘重新加载", + "new": "新建", + "newFile": "文件", + "newDirectory": "目录", + "openIn": "打开于", + "openInTerminal": "在终端打开", + "linkedFolder": "关联的文件夹", + "copyPath": "复制路径", + "upload": "上传文件/目录", + "download": "下载文件", + "downloadAsZip": "下载为 ZIP", + "actions": { + "select": "选择", + "unselect": "取消选择", + "commitCode": "提交代码", + "rollback": "回滚", + "addToVcs": "添加到 VCS" + }, + "aria": { + "selectPath": "{action}:{path}" + }, + "toasts": { + "openDirectoryFailed": "打开目录失败", + "openBuiltinTerminalFailed": "无法打开内置终端", + "openCommitWindowFailed": "打开提交窗口失败", + "noAddableFilesInDir": "该目录下没有可添加到 VCS 的变更文件", + "noRollbackFilesInDir": "该目录下没有可回滚的变更文件", + "addedToVcs": "已添加 {name} 到 VCS", + "addToVcsFailed": "添加到 VCS 失败", + "loadBranchesFailed": "加载分支失败", + "renameFailed": "重命名失败", + "moveFailed": "移动失败", + "deleteFailed": "删除失败", + "rolledBack": "已回滚 {name}", + "rollbackFailed": "回滚失败", + "addedFilesToVcs": "已添加 {count} 个文件到 VCS", + "rolledBackFiles": "已回滚 {count} 个文件", + "savedAsCopy": "已另存为副本", + "saveCopyFailed": "另存为副本失败", + "watchStartFailed": "文件监听启动失败", + "createFailed": "创建失败", + "downloadFailed": "下载 {name} 失败", + "downloadSaved": "已下载 {name}", + "pathCopied": "已复制路径", + "copyPathFailed": "复制路径失败" + }, + "createDialog": { + "newFile": "新建文件", + "newDirectory": "新建目录", + "description": "输入新{kind}的名称。", + "placeholderFile": "文件名.ext", + "placeholderDirectory": "文件夹名" + }, + "renameDialog": { + "renameDirectory": "重命名目录", + "renameFile": "重命名文件", + "description": "输入新的名称(仅名称,不含路径)。", + "placeholderDirectory": "新建文件夹名称", + "placeholderFile": "新建文件名称.ext" + }, + "uploadDialog": { + "title": "上传到工作区", + "description": "可以在下方修改上传目录,然后添加文件或文件夹。", + "workspaceRoot": "工作区根目录", + "targetPathLabel": "上传到", + "targetPathHint": "实际目录:{path}", + "dropHint": "拖拽文件或文件夹到此处,或使用下方按钮", + "dropHintActive": "释放鼠标以加入上传队列", + "selectFiles": "选择文件", + "selectFolder": "选择文件夹", + "startUpload": "开始上传", + "clearQueue": "清除已完成", + "removeItem": "从队列移除", + "retry": "重试", + "dropZoneAria": "拖放文件到此处,或按回车键浏览", + "folderEmpty": "拖入的文件夹中没有可上传的文件", + "summary": "总数:{total} · 成功:{succeeded} · 失败:{failed}", + "status": { + "pending": "等待中", + "uploading": "上传中", + "success": "完成", + "error": "失败", + "cancelled": "已取消" + } + }, + "directoryDialog": { + "descriptionAdd": "选择目录 {path} 下要添加到 VCS 的文件。", + "descriptionRollback": "选择目录 {path} 下要回滚的文件。", + "descriptionFallback": "选择要操作的文件。", + "selectionCount": "已选择 {selected} / {total} 个文件", + "selectAll": "全选", + "unselectAll": "取消全选", + "loadingCandidates": "正在加载目录变更...", + "noOperableFiles": "没有可操作的文件" + }, + "compareDialog": { + "title": "与分支比较", + "descriptionWithTarget": "选择分支并与{kind} {path} 对比", + "descriptionFallback": "选择要比较的分支。", + "kindDirectory": "目录", + "kindFile": "文件", + "filterPlaceholder": "过滤分支,例如 main / origin/main", + "singleClickHint": "单击分支即可直接比较", + "loadingBranches": "正在加载分支...", + "recentBranches": "最近分支 ({count})", + "noCurrentBranch": "无当前分支", + "localBranches": "本地分支 ({count})", + "remoteBranches": "远程分支 ({count})", + "noMatchingBranches": "无匹配分支" + }, + "externalConflictDialog": { + "title": "检测到外部文件变更", + "descriptionWithPath": "文件 {path} 在磁盘已发生变化,当前编辑内容尚未保存。", + "descriptionFallback": "当前文件在磁盘已发生变化,当前编辑内容尚未保存。", + "compare": "对比", + "savingCopy": "另存中...", + "saveAsCopy": "另存为副本", + "reload": "重载" + }, + "deleteConfirm": { + "title": "确认删除", + "descriptionWithTarget": "确定删除{kind} \"{name}\" 吗?此操作不可撤销。", + "descriptionFallback": "此操作不可撤销。", + "kindDirectory": "目录", + "kindFile": "文件" + }, + "rollbackConfirm": { + "title": "确认回滚", + "descriptionWithTarget": "确定回滚文件 \"{name}\" 的本地修改吗?", + "descriptionFallback": "确定回滚该文件的本地修改吗?" + }, + "terminalTitle": "终端 · {name}" + }, + "commandDropdown": { + "loading": "加载中...", + "addCommand": "添加命令", + "manageCommands": "管理命令...", + "runCommandTitle": "运行:{command}", + "stopCommandTitle": "停止:{command}", + "manageDialog": { + "title": "管理命令", + "empty": "暂无命令", + "noResults": "没有匹配的命令", + "searchPlaceholder": "搜索命令", + "newCommand": "新建命令", + "nameLabel": "名称", + "commandLabel": "命令", + "dragSort": "拖拽排序", + "dragSortCommand": "拖拽排序 {name}", + "orderFailed": "保存命令排序失败", + "loadFailed": "加载命令失败", + "saveFailed": "保存命令失败", + "deleteFailed": "删除命令失败", + "confirmDelete": { + "title": "删除命令?", + "message": "这会移除“{name}”,此操作不可撤销。" + } + } + }, + "workspaceContext": { + "confirmCloseDirtyTab": "文件“{title}”有未保存更改,确定关闭吗?", + "confirmCloseOtherDirtyTabs": "其它标签页有未保存更改,确定关闭吗?", + "confirmCloseAllDirtyTabs": "存在未保存更改,确定关闭全部标签页吗?", + "unableLoadContent": "无法加载内容。\n\n{message}", + "previewRequestTimedOut": "预览请求超时", + "diffRequestTimedOut": "Diff 请求超时", + "branchCompareRequestTimedOut": "分支比较请求超时", + "commitDiffRequestTimedOut": "提交差异请求超时", + "saveRequestTimedOut": "保存请求超时", + "reloadRequestTimedOut": "重载请求超时", + "noChanges": "暂无变更。", + "noDiffOutput": "无差异输出。", + "diffTitleWorkspace": "Diff · 工作区", + "diffDescriptionWorkingTree": "工作区变更(HEAD)", + "diffTitleFile": "差异 · {name}", + "compareTitleFile": "比较 · {name}", + "compareTitleBranch": "比较 · {branch}", + "compareDescriptionPath": "{path} · 与 {branch} 比较", + "compareDescriptionBranch": "与 {branch} 比较", + "diffTitleCommitFile": "差异 · {name} @ {hash}", + "diffTitleCommit": "差异 · {hash}", + "diffDescriptionCommitPath": "{path} · 提交 {commit}", + "diffDescriptionCommit": "提交 {commit}", + "diffTitleConflictFile": "冲突 · {name}", + "diffDescriptionConflict": "{path} · 磁盘与未保存内容" + }, + "chat": { + "acpConnections": { + "actions": { + "openAgentsSettings": "打开 Agents 管理", + "retry": "重试" + }, + "agentsSetupHint": "点击前往设置 > Agents 管理安装。", + "withSetupHint": "{message}\n提示:{hint}", + "blocked": { + "missingConfig": "无法读取当前 Agent 配置。", + "disabled": "{agent} 已在 Agents 管理中禁用,请先启用后再连接。", + "unavailable": "{agent} 当前平台不可用。", + "sdkMissing": "{agent} SDK 尚未安装", + "adapterMissing": "{agent} 的 ACP 适配器尚未安装" + }, + "backendErrors": { + "initializeTimeout": "{agent} 连接握手超时(60 秒未响应),请前往设置页面检查智能体和网络配置。", + "mcpRejectedByAgent": "附带 codeg 的 MCP 伴生进程时,{agent} 拒绝了本次会话:{message} 如果该智能体不支持 MCP,请在设置中关闭它的“MCP 支持”后重新连接。", + "processExited": "{agent} 进程意外退出。", + "spawnFailed": "启动 {agent} 失败:{message}", + "downloadFailed": "{agent} 下载失败:{message}", + "sessionLoadResourceNotFound": "{agent} 会话加载失败,可重新加载重试,或开始新会话。", + "sessionLoadUnavailable": "{agent} 无法恢复此会话,它可能已结束或 agent 已停止。可重新加载重试,或开始新会话。", + "turnFailedRefusal": "{agent} 拒绝继续本轮回复,通常意味着后端或网关出错,请检查代理日志。", + "turnFailedMaxTokens": "{agent} 已达到本轮回复的最大 Token 限制。", + "turnFailedMaxTurnRequests": "{agent} 已达到本轮回复允许的最大请求次数。", + "turnFailedUnknown": "{agent} 以未知的停止原因结束了本轮回复。", + "grokModelSwitchIncompatibleAgent": "{agent} 无法在已有对话中切换到该模型,请新建会话以使用它。", + "turnFailedEmpty": "{agent} 本轮没有产生任何回复就结束了。", + "turnFailedEmptyProtocol": "{agent} 本轮的输出 codeg 无法解析,可能是代理版本与协议不匹配。", + "turnFailedEmptyMetadata": "{agent} 本轮只收到状态更新(计划 / 模式 / 用量),没有收到任何回复。", + "detailsInAlerts": "在状态栏的「告警」中展开详情,可查看代理输出。" + }, + "unableReadAgentConfig": "无法读取 Agent 配置:{message}", + "connectFailedTitle": "{agent} 连接失败", + "toolFallbackTitle": "工具", + "eventErrorTitle": "Agent 错误", + "notificationTurnComplete": "{agent} 已完成响应", + "notificationError": "{agent} 错误:{message}", + "claudeApiRetry": { + "fallbackError": "authentication_failed", + "retryingWithMax": "正在重试 {attempt}/{max}", + "retryingAttempt": "正在重试(第 {attempt} 次)", + "retrying": "正在重试", + "nextRetryIn": "{seconds} 秒后重试", + "line": "{error}{status} · {retry}", + "lineWithDelay": "{error}{status} · {retry},{delay}", + "httpStatus": "(HTTP {status})" + }, + "configOptionAdjusted": "{agent} 把{option}设成了 {actual},而不是 {requested}" + }, + "connectionLifecycle": { + "tasks": { + "connectingTitle": "正在连接 {agent}", + "connectingDescription": "正在建立连接", + "loadingSelectorsTitle": "正在加载 {agent} 选择项", + "loadingSelectorsDescription": "正在获取模式和会话配置选项", + "initSessionTitle": "正在初始化 {agent} 会话", + "initSessionDescription": "正在创建会话并加载配置" + }, + "errors": { + "connectionFailed": "连接失败", + "sendPromptFailed": "消息发送失败:{error}" + } + }, + "shared": { + "attachedResources": "附加资源", + "toolCallFailed": "工具调用失败" + }, + "messageThread": { + "emptyTitle": "暂无消息", + "emptyDescription": "开始一个会话后,消息会显示在这里" + }, + "chatInput": { + "connecting": "连接中...", + "agentResponding": "{agent} 正在响应...", + "sendMessage": "发送消息..." + }, + "messageInput": { + "askAnything": "请开始输入...", + "removeAttachmentAria": "移除 {name}", + "attachFiles": "附加文件", + "attachLocalUpload": "附加本地文件", + "attachServerFile": "附加服务端文件", + "addActions": "添加", + "quickMessages": "快捷消息", + "quickMessagesEmpty": "暂无快捷消息", + "quickMessagesLoading": "加载中...", + "pasteAsPlainText": "粘贴为纯文本", + "cut": "剪切", + "copy": "复制", + "selectAll": "全选", + "pasteUnavailable": "无法读取剪贴板,请改用 Ctrl/⌘V 粘贴。", + "clipboardWriteFailed": "无法写入剪贴板,请改用键盘快捷键。", + "quickMessageUntitled": "未命名", + "liveFeedback": "实时反馈", + "liveFeedbackDisabledHint": "智能体工作时可发送", + "dropFilesToAttach": "拖拽文件到此处附加", + "loadingSettings": "正在加载设置...", + "loadingMode": "正在加载模式...", + "modeLabel": "模式", + "toggleOn": "开", + "toggleOff": "关", + "agentSettings": "智能体设置", + "searchModel": "搜索模型...", + "searchModelAria": "搜索模型", + "modelListLabel": "模型", + "noModels": "未找到模型", + "cancel": "取消", + "send": "发送", + "forkAndSend": "分叉发送", + "queueMessage": "加入队列", + "steerIntoTurn": "插入当前回合", + "steerQueuedInstead": "已转入队列——将随下一回合发送。", + "steerFailed": "无法插入当前回合", + "steerAttachmentsUnsupported": "仅支持纯文本——带附件的草稿请走队列。", + "slashCommands": "斜杠命令", + "slashSearchPlaceholder": "搜索命令...", + "slashSearchEmpty": "没有匹配的命令", + "experts": "专家", + "office": "日常办公", + "research": "科学研究", + "attachUploadTooLarge": "{names} 超过 {limit}MB 上传上限,已跳过。", + "attachUploadFailed": "上传失败:{names}。", + "attachUploadNotAFile": "{names} 不是常规文件(目录或特殊文件),已跳过。", + "attachUploadQuotaExceeded": "服务器上传空间已用尽,{names} 未能上传。", + "attachUploadInProgress": "图片仍在上传中,请稍候再发送。", + "mentionEmpty": "无匹配项", + "mentionLoading": "搜索中…", + "mentionListLabel": "提及", + "mentionMore": "还有更多结果,继续输入以筛选", + "mentionCount": "{count, plural, other {# 项结果}}", + "mentionGroupFile": "文件", + "mentionGroupAgent": "智能体", + "mentionGroupSession": "会话", + "mentionGroupCommit": "提交", + "mentionGroupSkill": "技能" + }, + "messageQueue": { + "addToQueue": "加入队列", + "saveEdit": "保存", + "cancelEdit": "取消编辑", + "editItem": "编辑", + "deleteItem": "删除" + }, + "welcomeInputPanel": { + "agentsSettingsPath": "设置 > Agents", + "autoConnectFallback": "点击前往 {path} 管理安装。", + "autoConnectAppend": "{message},点击前往 {path} 管理安装。", + "enableAgentFirstPlaceholder": "请先启用至少一个 Agent 后开始会话...", + "prepareSessionFailed": "无法准备聊天会话,请重试。", + "createConversationFailed": "无法创建会话,请重试。", + "askAnythingPlaceholder": "请开始输入...", + "agentNotInstalled": "{agent} 尚未安装 · 点击前往 Agents 设置安装", + "agentAdapterNotInstalled": "{agent} 的 ACP 适配器尚未安装(与你本地的 CLI 无关)· 点击前往 Agents 设置安装" + }, + "welcomePanel": { + "greeting": "今天准备做些什么呢?", + "tips": { + "tileTabs": "右键点击会话标签选择「平铺显示」,可同屏对比多个会话", + "pinTab": "双击会话标签可将其固定,避免被新打开的会话自动替换", + "shortcutsNewSearch": "{newConversation} 快速新建会话,{searchConversations} 搜索历史会话", + "slashAtMention": "在输入框输入 / 触发斜杠命令,输入 @ 引用项目内文件", + "pasteDropFiles": "直接粘贴截图或把文件拖到输入框,即可作为附件", + "queueMessage": "智能体回复中也能继续输入并排队,回答完毕会自动续发", + "draftAutoSave": "未发送的草稿会自动保存,重新打开会话仍在", + "forkSend": "发送按钮旁的下拉选择「分叉发送」,从当前位置开一条新分支", + "exportConversation": "右键会话内容区可导出为 Markdown / HTML / 图片", + "chatChannels": "在「设置 → 聊天频道」接入 Telegram / 飞书 / 微信,从手机继续操作", + "shortcutsAuxPanel": "{toggleAuxPanel} 切换右侧面板,查看本次会话改动的文件与 Git 变更", + "shortcutsTerminalSidebar": "{toggleTerminal} 打开内置终端,{toggleSidebar} 切换侧边栏", + "customShortcuts": "所有快捷键都可在「设置 → 快捷键」中自定义", + "webService": "开启「设置 → Web 服务」后,团队成员可从浏览器接入同一台 codeg", + "fusionMode": "打开文件或差异后,会自动与会话并排显示", + "quickMessages": "点输入框旁的 + 按钮选择「快捷消息」,可一键插入预存片段(在「设置 → 快捷消息」中管理)", + "experts": "通过 + 按钮里的「专家技能」可一键加载预设角色(调试 / 规划等)", + "taskBoard": "「待办任务」能把一条待办从头跑到尾:智能体在独立工作树里干活,你 review 完差异再合并。", + "automations": "「自动化」按计划定时跑保存好的提示词(比如每晚一次代码评审),还能让每次运行都开一个独立工作树。", + "tokenUsage": "点击状态栏左下角的会话数即可打开「Token 用量」,按天、智能体、模型和文件夹拆分统计。", + "mentionTargets": "@ 不只能引用文件:还能 @ 另一个智能体把子任务交给它,或引用历史会话、某次提交、某个技能。", + "splitGroups": "右键点击标签选择「向右拆分」或「向下拆分」,两个会话各占一个分栏同时开着。", + "worktrees": "点开分支按钮选「新建工作树」,多个智能体就能在同一个仓库并行干活,互不覆盖彼此的文件。", + "importSessions": "之前在终端里跑过的会话,用文件夹右键菜单的「导入本地会话」就能把那段历史接进 codeg。", + "subSessions": "智能体委派出去的子会话会嵌套显示在侧边栏的父会话下面,展开就能跟踪每一个子会话做了什么。", + "liveFeedback": "「+」菜单里的「实时反馈」能把一条便条塞进智能体正在跑的这一轮,不用打断它。", + "skillPacks": "设置 → 技能包 里打包了编程专家、科研和办公三类技能,可以按智能体分别开关。", + "modelProviders": "设置 → 模型供应商 支持填自己的 API key 或接口地址,之后直接在输入框里切换模型。", + "workspaceBackground": "设置 → 外观 里可以换工作区背景图、调面板不透明度,还能换应用字体。" + }, + "quickActions": { + "excel": "Excel 工作簿", + "excelDesc": "数据表、公式和图表", + "word": "Word 文档", + "wordDesc": "报告、信函和备忘录", + "ppt": "演示文稿", + "pptDesc": "专业设计的幻灯片", + "pitchDeck": "融资路演", + "pitchDeckDesc": "含关键指标的路演 PPT", + "morph": "Morph 动画", + "morphDesc": "电影级幻灯片转场", + "morph3d": "3D Morph", + "morph3dDesc": "3D 模型与镜头运动", + "academic": "学术论文", + "academicDesc": "含引用与结构的研究论文", + "financial": "财务模型", + "financialDesc": "报表、DCF 与预测", + "dashboard": "数据仪表盘", + "dashboardDesc": "从数据生成 KPI 与分析", + "prompts": { + "excel": "创建一个 Excel 工作簿,要求如下:\n\n[在此描述你的数据、表格、公式和图表]", + "word": "创建一个 Word 文档,要求如下:\n\n[在此描述文档内容、结构和排版]", + "ppt": "创建一个 PowerPoint 演示文稿,要求如下:\n\n[在此描述幻灯片、内容和设计]", + "pitchDeck": "创建一个融资路演 PPT,要求如下:\n\n[在此描述公司、融资轮次和关键指标]", + "morph": "创建一个带 Morph 转场动画的演示文稿:\n\n[在此描述演示主题和期望的视觉效果]", + "morph3d": "创建一个带 GLB 模型和镜头运动的 3D Morph 演示文稿:\n\n[在此描述主题和 3D 视觉构想]", + "academic": "用 Word 写一篇学术论文,要求如下:\n\n[在此描述研究主题、方法和主要发现]", + "financial": "用 Excel 创建一个财务模型,要求如下:\n\n[在此描述财务报表、预测和分析]", + "dashboard": "用 Excel 创建一个数据仪表盘,要求如下:\n\n[在此描述数据来源、KPI 和图表]", + "scientific-brainstorming": "帮我进行科研头脑风暴:探索跨学科联系、挑战假设、发现有潜力的研究空白。我正在探索的方向:", + "hypothesis-generation": "帮我把这些观察转化为可检验的假设:给出明确预测、合理机制,并设计验证实验。我的观察:", + "experimental-design": "在采集数据前帮我设计严谨的实验:设计方案、随机化、对照,以及如何避免混杂。我想研究的问题:", + "statistical-power": "帮我确定所需样本量:为我的设计做功效分析(效应量、显著性水平、功效)。具体信息:", + "statistical-analysis": "帮我正确分析这份数据:选择合适的检验、检查假设、报告效应量并撰写结论。我的数据与问题:", + "exploratory-data-analysis": "对我的数据文件做探索性分析:概述其结构、质量与值得注意的模式,并建议后续步骤。文件是:", + "scientific-visualization": "帮我制作出版级图表:清晰布局、真实误差棒、色盲友好配色,以及期刊格式。我想展示的内容:", + "scientific-critical-thinking": "帮我批判性评估这项研究或主张:评估证据质量、识别偏倚与混杂,并权衡结论。内容如下:", + "paper-lookup": "帮我在学术数据库中查找相关论文与开放获取全文,并提供可复用的引用。我要找的是:" + }, + "paper-lookup": "论文检索", + "paper-lookupDesc": "检索 10 个学术 API(PubMed、arXiv、OpenAlex、Crossref…)查找论文、引用与开放获取全文。", + "scientific-critical-thinking": "批判性思维", + "scientific-critical-thinkingDesc": "评估科学主张与证据质量:识别偏倚与混杂,运用 GRADE 与偏倚风险框架。", + "scientific-visualization": "科学可视化", + "scientific-visualizationDesc": "出版级图表:多面板布局、显著性标注与期刊专属格式。", + "exploratory-data-analysis": "探索性数据分析", + "exploratory-data-analysisDesc": "对 200+ 种格式的科学数据文件做自动化探索,输出质量指标与报告。", + "statistical-analysis": "统计分析", + "statistical-analysisDesc": "引导式统计分析:检验选择、假设检查、效应量与 APA 格式报告。", + "statistical-power": "统计功效", + "statistical-powerDesc": "样本量与统计功效分析:所需样本数、最小可检测效应与功效曲线。", + "experimental-design": "实验设计", + "experimental-designDesc": "在采集数据前设计严谨研究:随机化、区组、对照与析因/DOE 布局。", + "hypothesis-generation": "假设生成", + "hypothesis-generationDesc": "将观察转化为可检验的假设,给出预测、机制并设计验证实验。", + "scientific-brainstorming": "科学头脑风暴", + "scientific-brainstormingDesc": "开放式科研构思:探索跨学科联系、挑战假设、发现研究空白。", + "tabs": { + "office": "日常办公", + "coding": "代码开发", + "research": "科学研究" + }, + "coding": { + "brainstormingDesc": "动手前先梳理意图与需求", + "debuggingDesc": "先定位根因再提出修复", + "writingSkillsDesc": "创建、编辑并验证可复用技能" + }, + "notEnabled": { + "title": "「{skill}」技能尚未对 {agent} 启用", + "description": "前往设置启用后即可在此使用。", + "action": "去启用", + "hint": "技能未启用" + }, + "scrollPrev": "显示上一组技能", + "scrollNext": "显示下一组技能" + } + }, + "agentSelector": { + "noEnabledAgents": "暂无已启用的 Agent", + "openAgentsSettings": "打开 Agents 设置", + "notInstalled": "未安装", + "moreAgents": "更多 Agent({count})" + }, + "subAgentOverlay": { + "title": "子智能体", + "collapsedSummary": "子智能体 {count}", + "collapseAria": "折叠子智能体" + }, + "agentPlanOverlay": { + "title": "计划任务", + "collapsePlanAria": "折叠计划", + "collapsedSummary": "计划 {completed}/{total}", + "status": { + "completed": "已完成", + "inProgress": "进行中", + "pending": "待处理", + "unknown": "未知" + }, + "priority": { + "high": "高", + "medium": "中", + "low": "低", + "unknown": "未知" + } + }, + "permissionDialog": { + "subtitle": "Agent 请求继续当前轮次的权限。", + "queuedCount": "还有 {count} 项待审批", + "kindFallbackTool": "工具", + "command": "命令", + "cwd": "工作目录:{cwd}", + "filesSummary": "文件:{count}", + "moreFiles": "+{count} 个更多文件", + "plan": "计划", + "allowedActions": "允许的操作", + "targetMode": "目标模式:{mode}", + "optionGrants": "各选项将授予的权限", + "changeScopeSession": "本次会话", + "changeScopeProcess": "本次运行", + "changeScopeUser": "保存到用户设置", + "changeScopeProject": "保存到项目设置", + "changeScopeProjectLocal": "保存到本地项目设置", + "changeScopePersistent": "永久保存" + }, + "questionDialog": { + "title": "代理正在提问", + "placeholder": "输入你的回答...", + "send": "发送" + }, + "messageBranch": { + "previousBranchAria": "上一分支", + "nextBranchAria": "下一分支", + "pageOf": "{current} / {total}" + }, + "terminal": { + "title": "终端", + "running": "运行中" + }, + "reasoning": { + "thinking": "思考中…", + "thoughtForFewSeconds": "思考", + "thoughtForSeconds": "思考" + }, + "linkSafety": { + "errorCannotOpen": "无法打开本地文件", + "errorNoWorkspace": "当前没有活跃的工作区文件夹。", + "errorFailedOpen": "打开本地文件失败", + "errorFailedLink": "打开链接失败", + "errorUnsupportedLinkProtocol": "不支持该链接协议。" + }, + "fileActions": { + "openInFinder": "在访达打开", + "openInExplorer": "在资源管理器打开", + "openInFileManager": "在文件管理器打开", + "copyRelativePath": "复制相对路径", + "copyAbsolutePath": "复制绝对路径", + "pathCopied": "已复制路径", + "copyPathFailed": "复制路径失败", + "openFailed": "打开本地文件失败" + }, + "messageList": { + "attachedResources": "附加资源", + "loading": "加载中...", + "loadEarlier": "加载更早的消息", + "loadingEarlier": "正在加载更早的消息…", + "error": "错误:{message}", + "errorTitle": "会话加载失败", + "errorActionReload": "重新加载", + "errorActionNewSession": "新建会话", + "emptyConversation": "当前会话暂无消息。", + "systemMessage": "系统消息", + "copyMessage": "复制", + "copied": "已复制", + "downloadImage": "下载图片", + "downloadFailed": "下载失败:{message}", + "imageGeneration": "图片生成", + "imageGenerationPending": "正在生成图片…", + "imageGenerationFailed": "图片生成失败", + "model": "模型", + "tokenStats": "Token 使用情况", + "tokenInput": "输入", + "tokenOutput": "输出", + "tokenCacheRead": "缓存读取", + "tokenCacheWrite": "缓存写入", + "duration": "耗时", + "completedAt": "完成时间", + "jumpToPreviousUserMessage": "跳转到上一条用户消息", + "showMore": "展开", + "showLess": "收起" + }, + "liveTurnStats": { + "thinking": "思考中...", + "streaming": "生成中", + "elapsedHours": "{value} 小时", + "elapsedMinutes": "{value} 分钟", + "elapsedSeconds": "{value} 秒", + "outputSpeedAria": "估算输出速度", + "outputSpeedTooltip": "估算输出速度(正文 + 思考)" + }, + "jsonTree": { + "viewRaw": "查看原始 JSON", + "viewTree": "查看树状视图", + "fields": "{count} 个字段", + "items": "{count} 项" + }, + "tool": { + "parameters": "参数", + "error": "错误", + "result": "结果", + "status": { + "approvalRequested": "等待授权", + "approvalResponded": "已响应", + "inputAvailable": "运行中", + "inputStreaming": "等待中", + "outputAvailable": "已完成", + "outputDenied": "已拒绝", + "outputError": "错误" + } + }, + "toolCallBlock": { + "tool": "工具", + "error": "错误", + "result": "结果" + }, + "delegation": { + "subAgentRunning": "子智能体运行中…", + "noDetail": "暂无详情。", + "unknownAgent": "子智能体", + "openDetail": "查看会话", + "detailTitle": "子智能体会话", + "detailDescription": "只读查看委托给子智能体的会话内容。", + "waitForResult": "等待 {task} 任务执行结果", + "waitForResultNoTask": "等待任务执行结果", + "cancelTask": "取消 {task} 任务", + "cancelTaskNoTask": "取消任务", + "resultPageOf": "{current} / {total}", + "prevResult": "上一个结果", + "nextResult": "下一个结果", + "noResultText": "本次检查暂无结果", + "status": { + "starting": "启动中", + "running": "运行中", + "checked": "已查询", + "waiting": "待批准", + "ok": "完成", + "err": { + "default": "失败", + "delegation_disabled": "已禁用", + "depth_limit": "深度超限", + "invalid_agent_type": "代理类型无效", + "spawn_failed": "启动失败", + "send_failed": "发送失败", + "timeout": "超时", + "canceled": "已取消", + "child_refusal": "子代理拒绝", + "child_max_tokens": "子代理超出 token 上限", + "child_max_turn_requests": "子代理超出请求上限", + "child_empty": "子代理无响应", + "child_unknown": "子代理未知错误", + "unknown": "未知任务" + } + } + }, + "contentParts": { + "showingTailOutput": "为保证性能,流式输出时仅显示尾部内容。", + "result": "结果", + "unknown": "未知", + "inputTruncated": "输入已截断,diff 可能不完整。", + "replaceAll": "全部替换", + "filesCount": "文件:{count}", + "update": "更新", + "moreFiles": "+{count} 个更多文件", + "timeoutMs": "超时:{timeout}ms", + "backgroundTrue": "后台:true", + "scriptToolCalls": "调用 {count} 个工具", + "offset": "偏移:{offset}", + "limit": "限制:{limit}", + "pages": "页码:{pages}", + "mode": "模式:{mode}", + "cell": "单元:{cell}", + "shellSession": "会话 {id}", + "pathLabel": "路径:", + "globLabel": "Glob:", + "typeLabel": "类型:", + "outputLabel": "输出:", + "caseInsensitive": "忽略大小写", + "multiline": "多行", + "promptLabel": "提示词", + "subjectLabel": "主题", + "taskLabel": "任务", + "nameLabel": "名称:", + "agentPromptLabel": "提示词", + "agentModelLabel": "模型", + "agentRunning": "运行中...", + "agentLiveTranscript": "实时活动", + "agentProgressTools": "{count} 次工具调用", + "agentProgressTurns": "{count} 轮", + "agentProgressContext": "上下文 {pct}%", + "agentSessionAction": "查看子智能体会话", + "agentSessionTitle": "子智能体会话", + "agentSessionLoading": "正在加载子智能体的会话记录…", + "agentSessionEmpty": "子智能体还没有写入任何内容。", + "agentFallbackTitle": "子智能体启动中…", + "agentCodexLaunchOnly": "已启动。Codex 不会再报告这个子智能体的进展——它的结果会作为一条消息出现在本会话中。", + "agentStatsBash": "命令", + "agentStatsRead": "读取文件", + "agentStatsSearch": "搜索", + "agentStatsEdit": "编辑", + "agentStatsOther": "其他", + "goal": { + "title": "目标:", + "titleWithStatus": "目标{status}", + "objective": "目标", + "statusLabel": "状态", + "tokensUsed": "已用 tokens", + "budget": "预算", + "remaining": "剩余", + "elapsed": "耗时", + "tokens": "tokens", + "pause": "暂停", + "clear": "清除", + "status": { + "active": "进行中", + "paused": "已暂停", + "blocked": "受阻", + "usageLimited": "用量受限", + "budgetLimited": "预算受限", + "complete": "已完成", + "limited": "已达上限" + } + }, + "field": { + "file": "文件", + "notebook": "笔记本", + "command": "命令", + "old": "旧内容", + "new": "新内容", + "pattern": "模式", + "path": "路径", + "query": "查询", + "url": "URL地址", + "description": "描述", + "content": "内容", + "source": "源内容", + "prompt": "提示词", + "subject": "主题", + "taskId": "任务 ID", + "status": "状态", + "skill": "Skill", + "args": "参数", + "offset": "偏移", + "limit": "限制", + "glob": "Glob", + "type": "类型", + "output": "输出", + "replaceAll": "全部替换", + "language": "语言", + "timeout": "超时", + "background": "后台", + "agentType": "Agent 类型", + "library": "库", + "libraryId": "库 ID" + }, + "title": { + "edit": "编辑", + "command": "命令", + "script": "脚本", + "waitCommand": "等待 {command}", + "waitCell": "等待会话 {id}", + "terminateCommand": "终止 {command}", + "terminateCell": "终止会话 {id}", + "stdinChars": "输入 {chars}", + "todoWrite": "待办", + "read": "读取", + "write": "写入", + "notebookEdit": "Notebook 编辑", + "editFiles": "编辑({count} 个文件)", + "editWithTarget": "编辑 {target}", + "readWithTarget": "读取 {target}", + "writeWithTarget": "写入 {target}", + "notebookEditWithTarget": "Notebook 编辑 {target}", + "globWithPattern": "Glob {pattern}", + "listFilesWithPath": "列出文件 {path}", + "grepWithPattern": "Grep {pattern}", + "taskCreateWithSubject": "创建任务:{subject}", + "taskUpdateWithStatus": "更新任务 #{id} -> {status}", + "taskUpdate": "更新任务 #{id}", + "webFetchWithUrl": "抓取网页 {url}", + "webSearchWithQuery": "网页搜索:{query}", + "todosProgress": "待办({done}/{total})", + "skillWithName": "Skill:{name}", + "genericWithContext": "{tool}:{context}" + }, + "search": { + "noMatches": "无匹配结果", + "matchSummary": "{matches} 处匹配 · {files} 个文件", + "fileSummary": "{files} 个文件", + "moreResults": "另有 {count} 条结果未显示" + }, + "toolGroup": { + "search": "搜索 {count} 次", + "command": "运行 {count} 个命令", + "read": "读取 {count} 次文件", + "memory": "回忆 {count} 项记忆", + "edit": "编辑 {count} 次文件", + "fetch": "抓取 {count} 个资源", + "think": "思考 {count} 次", + "todo": "更新 {count} 项待办", + "task": "执行 {count} 个任务", + "other": "调用 {count} 个工具", + "errorSuffix": "{count} 个失败", + "joiner": " · " + }, + "planMode": { + "entered": "进入计划模式", + "planLabel": "计划", + "reviewApproved": "已批准执行计划", + "reviewKept": "保持在计划模式", + "reviewPending": "等待计划决定", + "submitted": "计划已提交", + "switched": "切换模式" + }, + "backgroundTask": { + "title": "后台任务", + "titleWithId": "后台任务 · {id}", + "running": "运行中", + "completed": "已完成", + "failed": "失败", + "stopped": "已停止", + "exitCode": "退出码 {code}", + "polledTimes": "轮询 {count} 次", + "runningInBackground": "后台运行", + "launchNote": "已在后台运行 · {id}" + }, + "codexScript": { + "outputMissing": "codex 截断脚本输出时丢掉了这条命令的分隔行,因此没有输出可以归属给它。", + "sharedWith": "本段还包含 {commands} 的输出——它们的分隔行被 codex 截断丢弃了。", + "truncated": "已截断" + } + }, + "messageNav": { + "title": "消息导航", + "collapse": "收起消息导航", + "collapsedSummary": "消息 {count}", + "fileCount": "{count} 个文件", + "remove": "移除", + "noDiffDataAvailable": "未找到 {filePath} 的差异数据" + }, + "replyArtifacts": { + "title": "改动文件", + "fileCount": "{count} 个文件", + "newFilesTitle": "新增文件", + "revealInFolder": "在访达/资源管理器中显示", + "openFile": "打开 {filePath}", + "openInEditor": "在编辑器中打开", + "remove": "移除", + "noDiffDataAvailable": "未找到 {filePath} 的差异数据" + }, + "askQuestion": { + "title": "智能体需要你的选择", + "subtitle": "回答后点击提交,可随时跳过", + "recommended": "推荐", + "other": "其他", + "otherPlaceholder": "输入你的回答…", + "singleSelect": "单选", + "multiSelect": "多选", + "skip": "跳过", + "next": "下一题", + "submit": "提交", + "submitError": "提交失败,请重试。" + }, + "planApproval": { + "title": "智能体已给出计划——请审阅", + "emptyPlan": "智能体未写入计划。可批准开始实施,或要求修改。", + "approve": "批准并开始", + "requestChanges": "要求修改", + "abandon": "放弃", + "feedbackPlaceholder": "需要修改什么?", + "sendChanges": "发送", + "cancel": "取消", + "submitError": "提交失败,请重试。" + }, + "feedbackCheckResult": { + "count": "{count} 条反馈", + "expand": "展开全部反馈", + "collapse": "收起", + "errorTitle": "反馈检查失败" + }, + "askQuestionResult": { + "title": "提问", + "answeredLabel": "提问回答:", + "awaiting": "等待你的回答…", + "declined": "你已忽略此问题 — 代理已自行判断。", + "noSelection": "未选择" + }, + "configStale": { + "agentConfigTitle": "智能体配置已更新", + "modelProviderTitle": "模型供应商已更新", + "description": "当前会话仍在使用旧配置,重连后生效(对话历史不会丢失)。", + "reconnect": "重连以应用", + "reconnecting": "正在重连…", + "reconnectDisabledDuringTurn": "当前回合结束后可重连", + "dismiss": "忽略", + "reconnectFailed": "重连会话失败", + "applied": "新配置已应用" + }, + "piProjectTrust": { + "title": "该项目自带 pi 资源", + "description": "pi 未加载仓库自带的 .pi 文件。请查看后决定。", + "descriptionExecutable": "仓库自带 pi 扩展,扩展会在启动时执行代码。pi 尚未加载它们,请先查看再决定。", + "review": "查看…", + "dismiss": "忽略", + "dialogTitle": "信任该项目的 pi 资源?", + "dialogDescription": "只有在你信任该目录后,pi 才会加载仓库自带的 .pi 文件。请仅在你信任该仓库内容时才信任。", + "executionWarning": "扩展就是代码。信任该目录后,仓库中的扩展会在 pi 启动时以你的权限执行——早于你发送任何消息。", + "scopeNote": "该决定保存在 pi 的 trust.json 中,对该目录下的所有子目录同样生效,你在终端里自己运行 pi 时也会沿用。之后可在「设置 → 智能体 → Pi」中修改。", + "trust": "信任项目", + "decline": "保持不加载", + "disabledDuringTurn": "当前回合结束后可用", + "trustedToast": "已信任项目——已重连以便 pi 加载其资源", + "declinedToast": "项目资源保持不加载", + "saveFailed": "保存项目信任决定失败", + "grantTitle": "该项目已被信任", + "grantDescription": "pi 会加载该仓库自带的 .pi 文件。请查看这意味着什么。", + "grantInheritedDescription": "某个上级目录已被信任,因此 pi 会加载该仓库自带的 .pi 文件。请查看这意味着什么。", + "grantDialogTitle": "该项目的 pi 资源已被信任", + "grantDialogDescription": "pi 被允许加载该仓库自带的 .pi 文件。旧版本 codeg 会在你打开目录时自动授予该权限,因此你可能从未被询问过。", + "grantExecutionWarning": "扩展就是代码。仓库中的扩展会在 pi 启动时以你的权限执行——早于你发送任何消息。", + "inheritedFrom": "信任来自", + "revoke": "撤销信任", + "keepTrusted": "保持信任", + "revokedToast": "已撤销信任——已重连,pi 不再加载该项目的资源", + "trustedNoReconnect": "已信任项目——将在 pi 下次启动时生效", + "revokedNoReconnect": "已撤销信任——将在 pi 下次启动时生效" + }, + "collabAgent": { + "title": "子智能体", + "errorTitle": "子智能体任务失败", + "statesLabel": "子智能体", + "statusRunning": "运行中", + "statusCompleted": "已完成", + "statusFailed": "失败", + "statusPending": "初始化中", + "statusInterrupted": "已中断", + "statusClosed": "已关闭", + "statusNotFound": "未找到", + "opSpawn": "启动子智能体", + "opWait": "获取子智能体结果", + "opClose": "结束子智能体", + "opResume": "恢复子智能体" + }, + "contextCompaction": { + "compacting": "正在压缩上下文…", + "compacted": "上下文已压缩", + "compactedTokens": "上下文已压缩 · {before} → {after} tokens", + "failed": "上下文压缩失败" + }, + "sessionFailure": { + "category": { + "connection": "连接异常", + "access": "访问受限", + "limit": "已达限制", + "request": "请求被拒绝", + "service": "服务异常", + "unknown": "会话异常" + }, + "action": { + "retry": "重试", + "login": "去登录", + "newSession": "新建会话" + }, + "recovered": "已恢复", + "retryUnavailable": "没有可重发的消息。", + "toggleDetails": "展开/收起详情" + }, + "backgroundTasks": { + "running": "{count} 个后台任务运行中", + "settling": "正在同步后台结果…", + "settledFallback": "后台任务已结束({status})", + "cardRunning": "后台运行中", + "cardLaunchedPending": "已启动后台任务", + "cardCompleted": "后台任务已完成", + "cardFinishedWithStatus": "后台任务已结束({status})", + "cardResultPending": "结果尚未返回" + }, + "proposedPlan": { + "title": "计划提案", + "planning": "规划中…" + } + }, + "diffPreview": { + "mode": { + "added": "新增", + "deleted": "删除", + "renamed": "重命名", + "modified": "修改" + }, + "hunkLabel": "代码块 {index}", + "loadingHunk": "正在加载代码块...", + "noDiffData": "无差异数据", + "showRemainingLines": "显示剩余 {count} 行" + }, + "conversationContextBar": { + "folderTitle": "工作文件夹", + "branchTitle": "工作分支", + "searchFolder": "搜索文件夹...", + "searchBranch": "搜索分支...", + "noFolders": "暂无文件夹", + "noBranches": "暂无分支", + "noBranch": "(无分支)", + "chatModeLabel": "聊天模式", + "commit": "提交", + "push": "推送", + "merge": "合并", + "toasts": { + "folderChanged": "已切换到 {name}", + "openFolderFailed": "打开文件夹失败", + "switchedToChatMode": "已切换到聊天模式", + "openStashFailed": "打开贮藏窗口失败", + "openMergeFailed": "打开合并窗口失败" + } + }, + "cloneDialog": { + "title": "克隆仓库", + "repositoryUrl": "仓库地址", + "repositoryUrlPlaceholder": "https://github.com/user/repo.git", + "directory": "目录", + "directoryPlaceholder": "选择目标目录...", + "browseDirectory": "浏览目录", + "cancel": "取消", + "clone": "克隆", + "clonePath": "克隆路径: {path}" + }, + "toasts": { + "cloneFailed": "克隆仓库失败" + } + }, + "ProjectBoot": { + "title": "项目启动器", + "tabs": { + "shadcn": "shadcn", + "hyperframes": "HyperFrames" + }, + "hyperframes": { + "title": "HyperFrames 视频项目", + "subtitle": "脚手架一个 HTML 转视频项目,随后工作区的智能体即可编写并渲染它。", + "resolution": "分辨率", + "skillsTitle": "智能体技能", + "skillsDesc": "为所选智能体全局安装 HyperFrames 技能(软链接),让它们会编写并渲染视频。", + "recheck": "重新检查", + "installedBadge": "已安装", + "skillsInstall": "安装 / 更新技能", + "skillsInstalling": "正在安装技能…", + "skillsInstalled": "HyperFrames 技能安装成功", + "skillsInstallFailed": "HyperFrames 技能安装失败" + }, + "config": { + "base": "基础库", + "style": "风格", + "baseColor": "基础颜色", + "theme": "主题", + "chartColor": "图表颜色", + "iconLibrary": "图标库", + "font": "字体", + "fontHeading": "标题字体", + "menuAccent": "菜单强调", + "menuColor": "菜单颜色", + "radius": "圆角", + "template": "模板", + "createProject": "创建项目", + "sectionStyle": "风格", + "sectionColors": "配色", + "sectionTypography": "排版", + "sectionInterface": "界面" + }, + "preview": { + "loading": "加载预览..." + }, + "createDialog": { + "title": "创建项目", + "projectName": "项目名称", + "projectNamePlaceholder": "my-app", + "frameworkTemplate": "框架模板", + "packageManager": "包管理器", + "saveDirectory": "保存目录", + "saveDirectoryPlaceholder": "选择目录...", + "browseDirectory": "浏览", + "projectPath": "项目将创建在:{path}", + "advancedOptions": "高级选项", + "base": "基础库", + "enableRtl": "启用 RTL 支持", + "enableRtlDescription": "为从右到左书写的语言(如阿拉伯语、希伯来语)启用布局支持", + "pmChecking": "正在检测...", + "pmNotInstalled": "未安装", + "cancel": "取消", + "create": "创建", + "creating": "正在创建项目..." + }, + "toasts": { + "createFailed": "创建项目失败", + "createSuccess": "项目创建成功", + "openWorkspaceFailed": "项目已创建,但无法在工作区中打开" + }, + "errors": { + "directoryExists": "目标目录已存在", + "commandFailed": "项目创建命令执行失败。" + } + }, + "WebServiceSettings": { + "addressSwitchHint": "切换只改变这里显示和打开的地址;服务监听所有网卡,每个地址都可访问。", + "sectionTitle": "Web 服务", + "sectionDescription": "启用后可通过浏览器远程访问 Codeg", + "port": "端口", + "status": "状态", + "autoStart": "自动启动", + "autoStartHint": "Codeg 启动时自动开启 Web 服务", + "running": "运行中", + "stopped": "已停止", + "processing": "处理中...", + "start": "启动", + "stop": "停止", + "startFailed": "启动失败", + "stopFailed": "停止失败", + "saveConfigFailed": "保存 Web 服务设置失败", + "open": "打开", + "hide": "隐藏", + "show": "显示", + "copy": "复制", + "qrcode": "二维码", + "qrcodeTitle": "扫码打开", + "qrcodeHint": "用手机扫描,在浏览器中打开 Codeg", + "addressLabel": "访问地址", + "tokenLabel": "访问 Token", + "tokenHint": "Web 客户端首次访问时需输入此 Token", + "tokenPlaceholder": "留空则自动生成", + "regenerate": "重新生成", + "stalePortOccupiedTitle": "端口 {port} 已被其他进程占用", + "stalePortUnknownTitle": "端口 {port} 状态未知", + "stalePortHint": "在端口释放前 Codeg 无法绑定。可以更换上方的端口,或结束占用该端口的进程。", + "errors": { + "alreadyRunning": "Web 服务已在运行", + "invalidAddress": "主机或端口格式无效", + "portInUse": "端口 {port} 已被占用,请关闭占用该端口的程序或更换其他端口", + "permissionDenied": "权限不足,请使用 1024 以上的端口,或以更高权限运行", + "addressUnavailable": "该地址在本机不可用", + "bindFailed": "绑定地址失败" + } + }, + "DirectoryBrowser": { + "title": "浏览目录", + "pathPlaceholder": "输入目录路径...", + "goHome": "回到主目录", + "navigateUp": "返回上级目录", + "select": "选择", + "cancel": "取消", + "loading": "加载中...", + "emptyDirectory": "此目录为空", + "errorLoadingDir": "加载目录失败", + "permissionDenied": "权限不足" + }, + "ServerFileBrowser": { + "title": "选择服务端文件", + "pathPlaceholder": "输入目录路径...", + "goHome": "回到主目录", + "navigateUp": "返回上级目录", + "select": "选择", + "cancel": "取消", + "loading": "加载中...", + "emptyDirectory": "此目录为空", + "errorLoadingDir": "加载目录失败", + "selectedCount": "已选 {count} 项" + }, + "ChatChannelSettings": { + "loading": "加载中...", + "sectionTitle": "消息渠道", + "sectionDescription": "配置 IM 机器人,接收事件通知和查询编码活动。", + "addChannel": "添加渠道", + "noChannels": "尚未配置任何消息渠道。", + "channelName": "名称", + "channelNamePlaceholder": "我的 Telegram 机器人", + "channelType": "渠道类型", + "lark": "飞书", + "weixin": "微信", + "dailyReport": "每日报告", + "dailyReportTime": "推送时间", + "nameRequired": "请输入渠道名称。", + "tokenRequired": "请输入 Token。", + "chatIdRequired": "请输入 Chat ID。", + "topicMode": "话题群模式", + "topicModeHint": "将 Telegram forum topics 路由为独立 Codeg 会话。Bot 必须加入 forum supergroup,并拥有管理 topics 权限。", + "loadFailed": "加载渠道失败。", + "saveFailed": "保存失败。", + "connectSuccess": "渠道已连接。", + "connectFailed": "连接失败", + "disconnectSuccess": "渠道已断开。", + "disconnectFailed": "断开连接失败。", + "testSuccess": "连接测试通过。", + "testFailed": "连接测试失败", + "deleteSuccess": "渠道已删除。", + "deleteFailed": "删除渠道失败。", + "deleteConfirmTitle": "删除渠道", + "deleteConfirmMessage": "将永久删除该渠道及其消息日志,确定吗?", + "cancel": "取消", + "delete": "删除", + "create": "创建", + "save": "保存", + "channelListTitle": "已配置渠道", + "channelListDescription": "已启用的渠道在服务启动时会自动连接。", + "editChannel": "编辑渠道", + "editSuccess": "渠道已更新。", + "tokenPlaceholderKeep": "留空保持不变", + "weixinScanTitle": "扫码登录", + "weixinScanDescription": "打开微信扫描二维码以连接。", + "weixinQrcodeExpired": "二维码已过期。", + "weixinRefreshQrcode": "刷新二维码", + "weixinWaitingScan": "等待扫码...", + "weixinPollError": "连接不稳定,正在重试...", + "weixinReconnectNotice": "因 iLink 协议限制,每次重新连接后需先主动向机器人发送一条消息,事件触发才会生效。", + "connect": "连接", + "disconnect": "断开", + "test": "测试连接", + "tabs": { + "channels": "渠道", + "commands": "指令", + "events": "事件", + "other": "其他" + }, + "commands": { + "title": "内置指令", + "description": "消息渠道中可用的 Bot 指令。群聊中需 @Bot 才会处理消息。", + "prefixLabel": "指令前缀", + "prefixDescription": "触发 Bot 指令的前缀,1-3 个非字母数字字符(默认 /)。", + "prefixSaved": "指令前缀已保存。", + "prefixSaveFailed": "保存指令前缀失败。", + "prefixInvalid": "前缀必须是 1-3 个非字母数字字符。", + "save": "保存", + "folderDesc": "选择工作目录", + "agentDesc": "选择 AI Agent", + "taskDesc": "创建会话并执行任务", + "sessionsDesc": "列出当前目录的活跃会话", + "resumeDesc": "最近会话 / 恢复指定会话", + "cancelDesc": "取消当前任务", + "approveDesc": "批准 Agent 权限请求", + "denyDesc": "拒绝 Agent 权限请求", + "searchDesc": "按关键词搜索会话", + "todayDesc": "今日活动汇总", + "statusDesc": "渠道连接状态", + "helpDesc": "显示帮助" + }, + "events": { + "title": "事件通知", + "description": "启用事件后,事件被触发时将推送到渠道。", + "turnComplete": "对话完成", + "turnCompleteDesc": "代理回合结束时", + "error": "代理错误", + "errorDesc": "代理遇到错误时", + "permissionRequest": "权限请求", + "permissionRequestDesc": "智能体请求操作权限时", + "questionRequest": "智能体提问", + "questionRequestDesc": "当智能体向你提问时", + "userPromptSent": "用户消息", + "userPromptSentDesc": "当你发送消息时——通知中会包含消息内容", + "saved": "事件过滤已更新。", + "saveFailed": "保存事件过滤失败。", + "loadFailed": "加载设置失败。", + "retry": "重试", + "webhooksTitle": "Webhook", + "webhooksDescription": "事件触发时,向一个或多个地址 POST 一份 JSON。上方的事件过滤同样作用于 Webhook。", + "webhookUrlPlaceholder": "https://example.com/webhook", + "addWebhook": "添加 Webhook", + "removeWebhook": "删除 Webhook", + "webhookSave": "保存", + "webhooksSaved": "Webhook 已保存。", + "webhooksSaveFailed": "保存 Webhook 失败。", + "webhookInvalidUrl": "请输入有效的 http(s) 地址。", + "docsTitle": "请求格式", + "docsMethod": "请求方式", + "docsContentType": "内容类型", + "docsNote": "每个启用的事件都会投递到所有地址。Webhook 不做去抖;上方的事件过滤仍然生效。", + "editWebhook": "编辑 Webhook", + "enableWebhook": "启用 Webhook", + "webhookDuplicate": "该地址已配置。", + "cancel": "取消", + "webhooksEmpty": "尚未配置 Webhook。", + "deleteWebhookTitle": "删除 Webhook", + "deleteWebhookMessage": "删除此 Webhook?事件将不再投递到该地址。", + "delete": "删除" + }, + "language": { + "title": "消息语言", + "description": "事件通知、指令响应和每日报告推送到消息渠道时使用的语言。", + "saved": "消息语言已保存。", + "saveFailed": "保存消息语言失败。", + "en": "英语", + "zh-cn": "简体中文", + "zh-tw": "繁体中文", + "ja": "日语", + "ko": "韩语", + "es": "西班牙语", + "de": "德语", + "fr": "法语", + "pt": "葡萄牙语", + "ar": "阿拉伯语" + } + }, + "ModelProviderSettings": { + "sectionTitle": "模型供应商", + "sectionDescription": "管理 Agent 的 API 供应商凭据。", + "filterAll": "全部", + "providerListTitle": "已配置的供应商", + "addProvider": "添加供应商", + "editProvider": "编辑供应商", + "noProviders": "尚未配置模型供应商。", + "providerName": "名称", + "providerNamePlaceholder": "例如 OpenAI、Anthropic", + "apiUrl": "API 地址", + "apiUrlPlaceholder": "https://api.openai.com/v1", + "apiKey": "API 密钥", + "apiKeyPlaceholder": "sk-...", + "apiKeyKeepCurrent": "留空则保持不变", + "agentTypes": "代理类型", + "agentTypesRequired": "至少选择一个代理类型。", + "agentType": "智能体类型", + "agentTypeRequired": "请选择智能体类型。", + "agentTypeImmutableHint": "智能体类型创建后不可修改。", + "model": "模型", + "modelPlaceholderCodex": "gpt-5.6-sol / gpt-5.5", + "modelPlaceholderGemini": "gemini-3-pro-preview", + "claudeMainModel": "主模型", + "claudeReasoningModel": "推理模型(思考)", + "claudeHaikuDefaultModel": "默认 Haiku 模型", + "claudeSonnetDefaultModel": "默认 Sonnet 模型", + "claudeOpusDefaultModel": "默认 Opus 模型", + "claudeCustomModelOption": "自定义模型 ID", + "claudeCustomModelOptionName": "自定义模型名称", + "claudeCustomModelOptionDescription": "自定义模型描述", + "claudeCustomModelOptionHint": "在 Claude 模型选择器中追加一个自定义条目(例如经自定义网关/代理提供的模型)。名称与描述为可选的显示信息。", + "nameRequired": "供应商名称不能为空。", + "apiUrlRequired": "API 地址不能为空。", + "apiKeyRequired": "API 密钥不能为空。", + "loadFailed": "加载供应商失败。", + "saveFailed": "保存更改失败。", + "createSuccess": "供应商已创建。", + "editSuccess": "供应商已更新。", + "deleteSuccess": "供应商已删除。", + "deleteConfirmTitle": "删除供应商", + "deleteConfirmMessage": "确定要永久删除供应商「{name}」吗?", + "deleteBlockedByAgent": "{agents} 正在使用该配置,请先解除关联后再删除。", + "cancel": "取消", + "delete": "删除", + "create": "创建", + "save": "保存", + "affectedRunningSessions": "{count} 个进行中的会话需重连以应用更改" + }, + "SkillMatrix": { + "loading": "加载中…", + "searchPlaceholder": "按名称、ID 或描述搜索", + "empty": "暂无内容。", + "emptySearch": "没有匹配当前搜索的结果。", + "skillColumn": "技能", + "selectAll": "全选可见项", + "selectSkill": "选择 {name}", + "everything": { + "label": "批量", + "enable": "全部启用(可见)", + "disable": "全部禁用(可见)" + }, + "columnMenu": { + "enableAll": "启用全部技能", + "disableAll": "禁用全部技能" + }, + "rowMenu": { + "label": "对 {name} 批量操作", + "enableAll": "对所有 agent 启用", + "disableAll": "对所有 agent 禁用" + }, + "bulk": { + "selected": "已选择 {count} 项", + "targetAll": "全部 agent", + "targetSome": "{count} 个 agent", + "enable": "启用", + "disable": "禁用", + "clear": "清除" + }, + "confirm": { + "disableTitle": "禁用这些链接?", + "disableBody": "这将移除 {count} 个由 codeg 管理的技能链接。占用自定义目录的技能不受影响。你可以随时重新启用。", + "cancel": "取消", + "confirm": "禁用" + }, + "toasts": { + "loadFailed": "加载技能状态失败", + "applyFailed": "应用更改失败", + "enabled": "已启用 {count} 个链接", + "disabled": "已禁用 {count} 个链接", + "enabledPartial": "已启用 {ok} 个,{failed} 个失败", + "disabledPartial": "已禁用 {ok} 个,{failed} 个失败" + }, + "detail": { + "enableForAgents": "为 agent 启用", + "preview": "SKILL.md 预览", + "loadingContent": "加载内容中…" + }, + "copyModeHint": "已复制(非链接)——更新后请重新启用以获取最新版本" + }, + "ExpertsSettings": { + "title": "专家技能", + "description": "为 AI 编码代理启用精心挑选、经过实战验证的技能工作流。每个专家都是 superpowers 项目中的独立技能 —— codeg 维护中央副本,并将其软链接到你选择的代理目录。", + "loading": "正在加载专家列表…", + "loadingContent": "正在加载内容…", + "emptyExperts": "当前没有可用的专家,请查看应用日志。", + "emptySelection": "从左侧选择一个专家以查看内容并管理启用状态。", + "emptySearch": "没有匹配当前搜索条件的专家。", + "searchPlaceholder": "按名称、ID 或描述搜索专家", + "enableForAgents": "为代理启用", + "noAgents": "未检测到 ACP 代理。", + "copyModeWarning": "已复制(非软链接)。codeg 更新后需要重新启用以获取最新版本。", + "previewTitle": "SKILL.md 预览", + "categories": { + "discovery": "发现与设计", + "planning": "规划", + "execution": "执行", + "quality": "质量与测试", + "debugging": "调试", + "review": "评审与集成", + "meta": "元技能" + }, + "states": { + "not_linked": "未启用", + "linked_to_codeg": "已启用", + "linked_elsewhere": "冲突 — 已有其他链接", + "blocked_by_real_directory": "冲突 — 已有同名的自定义 skill 占用", + "broken": "链接损坏" + }, + "badges": { + "userModified": "用户修改过" + }, + "actions": { + "openCentralDir": "打开中央目录", + "refresh": "刷新" + }, + "toasts": { + "loadFailed": "加载专家详情失败", + "enabled": "已为该代理启用专家", + "disabled": "已为该代理禁用专家", + "enableFailed": "启用专家失败", + "disableFailed": "禁用专家失败", + "openFolderFailed": "打开目录失败" + } + }, + "ScienceSettings": { + "title": "科学研究技能", + "description": "为你的 AI 编码智能体启用精选的科学研究技能:假设生成、实验设计、统计、可视化、批判性评估与文献检索。codeg 管理中央副本,并将每个技能链接到你选择的智能体。", + "loading": "正在加载科学研究技能…", + "emptySkills": "没有可用的科学研究技能。请检查应用日志。", + "searchPlaceholder": "按名称、ID 或描述搜索科学研究技能", + "categories": { + "ideation": "构思", + "design": "研究设计", + "analysis": "分析", + "visualization": "可视化", + "evaluation": "评估", + "literature": "文献" + }, + "states": { + "not_linked": "未启用", + "linked_to_codeg": "已启用", + "linked_elsewhere": "冲突 — 已有其他链接", + "blocked_by_real_directory": "冲突 — 已有同名的自定义 skill 占用", + "broken": "链接损坏" + }, + "badges": { + "userModified": "用户修改过", + "needsKey": "需要密钥", + "needsSetup": "可能需环境" + }, + "actions": { + "openCentralDir": "打开中央目录", + "refresh": "刷新" + }, + "toasts": { + "openFolderFailed": "打开目录失败" + } + }, + "OfficeToolsSettings": { + "title": "Office 工具", + "description": "管理 OfficeCLI 技能,用于创建 Excel、Word 和 PowerPoint 文件。安装 OfficeCLI,同步技能,并为每个智能体启用。", + "loadingContent": "加载内容中…", + "emptySkills": "暂无技能。请先安装 OfficeCLI 并同步技能。", + "emptySelection": "选择一个技能查看内容和管理激活状态。", + "emptySearch": "没有匹配的技能。", + "searchPlaceholder": "按名称、ID 或描述搜索技能", + "enableForAgents": "为智能体启用", + "noAgents": "未检测到 ACP 智能体。", + "installFirst": "请先安装 OfficeCLI 以启用技能。", + "syncFirst": "请先同步技能以加载内容。", + "noContent": "暂无内容。", + "copyModeWarning": "已复制(非链接)。重新同步以获取最新版本。", + "previewTitle": "SKILL.md 预览", + "detection": { + "installed": "已安装", + "notInstalled": "未安装", + "notRunnable": "已安装但无法运行", + "installHint": "安装 OfficeCLI 以为 AI 智能体启用办公文档生成技能。", + "install": "安装", + "uninstall": "卸载", + "syncSkills": "同步技能" + }, + "categories": { + "general": "通用", + "presentations": "演示文稿", + "documents": "文档", + "spreadsheets": "电子表格" + }, + "states": { + "not_linked": "未启用", + "linked_to_codeg": "已启用", + "linked_elsewhere": "已阻止——存在其他链接", + "blocked_by_real_directory": "已阻止——自定义技能占用此名称", + "broken": "链接已损坏" + }, + "badges": { + "notSynced": "未同步" + }, + "actions": { + "refresh": "刷新" + }, + "toasts": { + "loadFailed": "加载技能详情失败", + "enabled": "已为此智能体启用技能", + "disabled": "已为此智能体禁用技能", + "enableFailed": "启用技能失败", + "disableFailed": "禁用技能失败", + "installSuccess": "OfficeCLI 安装成功", + "installFailed": "安装 OfficeCLI 失败", + "uninstallSuccess": "OfficeCLI 已卸载", + "uninstallFailed": "卸载 OfficeCLI 失败", + "syncSuccess": "已成功同步 {synced} 个技能", + "syncPartial": "已同步 {synced} 个技能,{errors} 个失败", + "syncFailed": "同步技能失败" + }, + "autoPreviewLabel": "自动打开预览", + "autoPreviewHint": "当智能体创建或编辑 Word、Excel、PowerPoint 文件时,自动打开其实时预览。" + }, + "SkillPacksSettings": { + "title": "技能包", + "description": "由 codeg 集中管理、并链接到各 AI 智能体的成套技能——编码专家、科学研究与办公文档工具。可在下方按智能体分别启用。", + "tabs": { + "experts": "专家", + "science": "科学研究", + "office": "办公工具", + "custom": "自定义" + }, + "actions": { + "openCentralDir": "打开中央目录", + "refresh": "刷新" + }, + "toasts": { + "openFolderFailed": "打开目录失败" + } + }, + "QuickMessagesSettings": { + "title": "快捷消息", + "description": "管理可复用的消息片段。拖拽以调整顺序。", + "loading": "加载快捷消息…", + "emptyList": "暂无快捷消息。点击“新建”创建一条。", + "emptySelection": "选择一条快捷消息进行编辑。", + "searchPlaceholder": "按标题或内容搜索", + "untitled": "未命名", + "actions": { + "new": "新建", + "save": "保存", + "delete": "删除", + "dragSort": "拖拽排序", + "dragSortMessage": "拖拽排序快捷消息:{name}" + }, + "fields": { + "title": "标题", + "titlePlaceholder": "为此消息取一个简短的标题", + "content": "内容", + "contentPlaceholder": "在此输入消息内容" + }, + "confirmDelete": { + "title": "删除快捷消息?", + "message": "将永久删除“{name}”。确定吗?", + "cancel": "取消", + "confirm": "删除" + }, + "toasts": { + "loadFailed": "加载快捷消息失败", + "createFailed": "创建快捷消息失败", + "saveFailed": "保存快捷消息失败", + "deleteFailed": "删除快捷消息失败", + "saveOrderFailed": "保存顺序失败", + "created": "已创建快捷消息", + "saved": "已保存快捷消息", + "deleted": "已删除快捷消息" + } + }, + "Pet": { + "badge": { + "running": "{count} 个运行中", + "waiting": "{count} 个待批准", + "error": "{count} 个出错" + }, + "panel": { + "title": "活动会话", + "empty": "没有活动会话", + "emptyHint": "正在运行或需要你处理的会话会显示在这里。", + "statusRunning": "运行中", + "statusWaiting": "等待中", + "statusError": "出错", + "subAgentOf": "子智能体" + }, + "menu": { + "scale": "缩放", + "openManager": "管理宠物", + "close": "关闭" + }, + "loadError": "加载宠物失败", + "missingPetIdParam": "未选中任何宠物", + "summonButton": "宠物", + "manager": { + "title": "桌面宠物", + "description": "悬浮在桌面上的伴侣,使用与 Codex 兼容的精灵图。", + "addPet": "添加宠物", + "importFromCodex": "从 Codex 导入", + "noPets": "暂无宠物。可以添加一只,或从 Codex 导入。", + "setActive": "设为活跃", + "active": "当前活跃", + "edit": "编辑", + "delete": "删除", + "deleteConfirm": "确认删除宠物 \"{name}\" 吗?会从磁盘上一并移除。", + "summon": "召唤宠物窗口", + "openCodexHelp": "Codex 宠物需位于 ~/.codex/pets/ 目录下,但未找到。", + "specRequirement": "精灵图宽度必须为 1536 像素,高度需为 208 像素的整数倍(如 1872 或 2288),并为带透明通道的 PNG 或 WebP。", + "form": { + "id": "宠物 ID", + "idHelp": "仅允许小写字母、数字、'-' 和 '_',最多 64 字符。", + "displayName": "显示名称", + "description": "描述 (可选)", + "spritesheet": "精灵图", + "chooseFile": "选择文件", + "replaceFile": "替换精灵图", + "saveCreate": "添加宠物", + "saveUpdate": "保存修改", + "cancel": "取消" + }, + "errors": { + "missingId": "宠物 ID 不能为空", + "missingName": "显示名称不能为空", + "missingSpritesheet": "必须选择一个精灵图", + "addFailed": "添加宠物失败", + "updateFailed": "更新宠物失败", + "deleteFailed": "删除宠物失败", + "loadFailed": "加载宠物列表失败", + "setActiveFailed": "设置活跃宠物失败", + "summonFailed": "召唤宠物窗口失败" + } + }, + "import": { + "title": "从 Codex 导入", + "subtitle": "在 ~/.codex/pets/ 下找到以下可导入的宠物。", + "selectAll": "全选", + "alreadyImported": "已导入", + "renameOnConflict": "冲突时自动添加 -imported 后缀", + "import": "导入所选", + "noneFound": "未找到可导入的 Codex 宠物。", + "imported": "导入完成", + "failed": "导入失败", + "close": "关闭" + }, + "marketplace": { + "openMarketplace": "宠物市场", + "title": "宠物市场", + "search": "搜索宠物", + "kindFilter": { + "all": "全部", + "object": "物品", + "animal": "动物", + "person": "人物", + "creature": "生物" + }, + "sortFilter": { + "latest": "最新", + "popular": "热门", + "views": "最多浏览" + }, + "refresh": "刷新", + "install": "安装", + "installing": "安装中", + "reinstall": "替换重装", + "reinstallConfirm": "确认覆盖本地宠物 \"{name}\" 吗?现有数据将被替换。", + "cancel": "取消", + "stats": { + "views": "浏览", + "downloads": "下载", + "likes": "点赞" + }, + "actions": { + "idle": "待机", + "running_right": "右跑", + "running_left": "左跑", + "waving": "挥手", + "jumping": "跳跃", + "failed": "失败", + "waiting": "等待", + "running": "运行", + "review": "评审" + }, + "page": "第 {page} / {total} 页", + "prev": "上一页", + "next": "下一页", + "empty": "没有匹配的宠物。", + "successInstalled": "已安装 \"{name}\"", + "errors": { + "loadFailed": "加载市场失败", + "installFailed": "安装失败", + "alreadyInstalled": "该宠物已存在" + } + } + }, + "RemoteWorkspace": { + "openRemoteWorkspace": "打开远端工作区", + "manage": "管理远端工作区", + "manageTitle": "远端工作区连接", + "empty": "暂无远端连接", + "searchPlaceholder": "搜索远端工作区", + "orderFailed": "保存远端工作区排序失败", + "dragSort": "拖拽排序", + "dragSortConnection": "拖拽排序 {name}", + "newConnection": "新建连接", + "loading": "加载中", + "loadingConnection": "正在加载远端连接", + "name": "名称", + "baseUrl": "服务地址", + "token": "访问 Token", + "save": "保存", + "delete": "删除", + "confirmDelete": { + "title": "删除远端连接?", + "message": "这会从当前设备移除“{name}”,此操作不可撤销。", + "cancel": "取消", + "confirm": "删除" + }, + "saved": "远端连接已保存。", + "deleted": "远端连接已删除。", + "loadFailed": "加载远端连接失败", + "saveFailed": "保存远端连接失败", + "deleteFailed": "删除远端连接失败", + "openFailed": "打开远端工作区失败", + "connectionLoadFailed": "加载远端连接失败:{message}", + "connectionExpired": "远端连接“{name}”已失效。请更新 Token 后重新加载此窗口。" + }, + "BackupSettings": { + "title": "备份与恢复", + "description": "导出一份可移植的 codeg 数据备份,或从备份中恢复。", + "tabs": { + "backup": "备份", + "restore": "恢复" + }, + "export": { + "includeExternal": "包含会话内容", + "includeExternalHint": "同时打包各 CLI 的会话记录(Claude、Codex、Gemini 等),体积更大。", + "passphrase": "口令(可选)", + "passphrasePlaceholder": "留空则生成未加密的归档", + "passphraseConfirm": "确认口令", + "passphraseMismatch": "两次输入的口令不一致。", + "noPassphraseWarning": "该备份将以明文包含密钥(API key、token)。请妥善保管。", + "passphraseLossWarning": "将使用此口令加密。口令一旦丢失,备份将无法恢复。", + "button": "导出备份", + "inProgress": "正在创建备份…", + "success": "备份已创建。", + "started": "已开始下载备份。" + }, + "restore": { + "selectFile": "选择备份文件", + "passphrasePrompt": "该备份已加密,请输入其口令。", + "unlock": "解锁", + "preview": { + "title": "备份详情", + "encrypted": "已加密", + "compatible": "兼容", + "incompatible": "不兼容", + "createdAt": "创建时间:{value}", + "appVersion": "应用版本:{value}", + "incompatibleHint": "该备份由更新版本的 codeg 创建,无法恢复。" + }, + "replaceWarning": "恢复将替换当前全部 codeg 数据(数据库与上传文件)。当前数据会先做快照以便回退。", + "keyringNote": "桌面端的 GitHub/聊天 token 存于系统钥匙串,不包含在备份中;恢复后需重新填写。", + "button": "恢复", + "staging": "正在准备恢复…", + "staged": "恢复已就绪,正在重启…", + "restarting": "恢复已就绪,正在重启服务…", + "restartTimeout": "服务未能及时恢复。待其启动后请刷新页面。", + "externalSideLocation": "会话记录已恢复到 {path}", + "confirmTitle": "替换全部数据?", + "confirmBody": "这将用备份替换当前的 codeg 数据库与上传文件,然后重启。当前数据会先做快照。", + "cancel": "取消", + "confirmAction": "替换并重启", + "external": { + "title": "会话内容", + "hint": "该备份包含各 CLI 的会话记录。请选择恢复到何处。", + "modeSkip": "不恢复", + "modeSide": "恢复到安全的旁路目录", + "modeOriginal": "恢复到 CLI 的原始位置", + "forceOverwrite": "覆盖已存在的文件", + "forceOverwriteHint": "替换 CLI 目录中已存在的文件。", + "scanning": "正在检查冲突…", + "noConflicts": "不会覆盖任何已存在的文件。", + "conflictCount": "将影响 {count} 个已存在的文件。", + "conflictSkipNote": "未启用覆盖时,已存在的文件将被保留(跳过)。" + }, + "restartFailed": "恢复已就绪,但服务未能重启。请手动重启以应用此次恢复。" + }, + "remoteUnsupported": "备份与恢复作用于运行 codeg 的那台机器上的数据。你当前连接的是远程工作区——请直接在该服务器上管理其备份。" + }, + "backup": { + "restore": { + "error": { + "badPassphrase": "口令错误或备份已损坏。", + "corrupted": "备份归档已损坏。", + "unknownFormat": "该文件不是可识别的 codeg 备份。", + "newerVersion": "该备份由 codeg {backupVersion} 创建,比当前版本({appVersion})更新。", + "alreadyPending": "已有一个恢复在等待生效。请先重启应用它,再暂存新的恢复。" + } + }, + "error": { + "diskSpace": "磁盘空间不足,无法完成操作。", + "cancelled": "操作已取消。" + } + }, + "WebConnection": { + "disconnectedTitle": "连接已断开", + "reconnectingDescription": "正在尝试重新连接服务器,通常会在几秒内自动恢复。", + "reconnectNow": "立即重连", + "sessionExpiredTitle": "会话已过期", + "sessionExpiredDescription": "登录状态已失效,请重新登录以继续。", + "goToLogin": "前往登录" + }, + "LiveFeedback": { + "placeholder": "在 {agent} 工作时给它留言…", + "agentFallback": "智能体", + "ariaLabel": "实时反馈留言", + "dialogTitle": "实时反馈", + "dialogDescription": "在智能体工作时给它留言。它会在下次检查时读取,不会打断当前步骤。", + "dialogDescriptionInstant": "在智能体工作时给它发一条备注。备注会立即插入当前回合——智能体马上就能看到。", + "channelDowngraded": "本会话无法即时插入——备注已保存,等智能体下次检查时读取。", + "send": "发送", + "cancel": "取消", + "pending": "等待中", + "delivered": "已收到", + "turnEndedUnread": "智能体在读取你的反馈前已结束本轮。", + "sendAsMessage": "作为新消息发送", + "dismiss": "忽略", + "turnEndedResent": "本轮已结束——已改为作为新消息发送。", + "turnEnded": "本轮已结束。", + "submitFailed": "留言发送失败" + }, + "AgentToolsSettings": { + "title": "会话内工具", + "description": "codeg 在会话中额外提供给智能体的工具。工具在智能体启动时注入,改动只对之后启动的智能体生效。", + "feedbackLabel": "实时反馈", + "feedbackHint": "在智能体工作时向它发送备注与纠偏。支持即时插入的智能体会立刻在当前回合中看到你的备注;其他智能体则通过检查反馈的工具读取——这类智能体通常只有在提示词里提到时才会检查,例如在消息中加上“定期检查我的实时反馈”。", + "questionLabel": "向用户提问", + "questionHint": "允许智能体暂停并向你提出多选问题,问题会显示在会话输入框上方。智能体会一直等待,直到你作答(或跳过)。", + "sessionInfoLabel": "获取会话信息", + "sessionInfoHint": "允许智能体查询你在消息中提及的会话(会话徽章),读取其标题、智能体、状态、工作区、Token 用量和最近消息。", + "automationsLabel": "创建自动化", + "automationsHint": "把对话保存为按计划运行的自动化。默认关闭——它之后会自行启动智能体。", + "workTasksLabel": "创建待办任务", + "workTasksHint": "从对话中往待办看板排一张任务卡。默认关闭——它会写入应用状态。", + "save": "保存", + "saving": "保存中…", + "saved": "工具设置已保存", + "saveFailed": "保存工具设置失败", + "loadFailed": "加载失败:{detail}" + }, + "NotificationSoundSettings": { + "title": "提示音", + "description": "智能体事件触发时播放一段简短的提示音。这里的事件与消息渠道推送的完全一致,但设置只对本设备生效。", + "enableHint": "默认关闭。提示音只在当前浏览器或应用的工作区窗口中播放。", + "volume": "音量", + "preview": "试听", + "previewEvent": "试听「{event}」提示音", + "onlyWhenUnfocused": "仅在窗口未聚焦时播放", + "onlyWhenUnfocusedHint": "正在查看 Codeg 时保持静音。", + "eventsTitle": "事件", + "eventsHint": "为每个事件选择一种音效,选择「静音」则不播放。同一事件在数秒内重复触发时只播放一次。", + "toneNone": "静音", + "toneChime": "叮咚", + "toneDing": "清铃", + "toneBlip": "短音", + "tonePop": "轻点", + "toneAlert": "警示", + "toneDescend": "下行音" + }, + "LogsSettings": { + "loading": "加载中…", + "sectionTitle": "运行日志", + "sectionDescription": "查看和配置应用诊断日志。日志会写入本地文件,并保留在内存中以便实时查看。", + "captureTitle": "日志级别", + "captureDescription": "控制记录的详细程度。级别越高(Debug、Trace)记录越多,但日志也越大。“关闭”将停止记录日志。", + "captureLabel": "采集级别", + "levels": { + "off": "关闭", + "error": "错误", + "warn": "警告", + "info": "信息", + "debug": "调试", + "trace": "跟踪" + }, + "viewerTitle": "最近日志", + "viewerDescription": "实时查看最近的日志记录。可按级别筛选或搜索文本。", + "searchPlaceholder": "搜索消息或来源…", + "viewLevels": { + "all": "全部级别", + "error": "错误及以上", + "warn": "警告及以上", + "info": "信息及以上", + "debug": "调试及以上", + "trace": "跟踪及以上" + }, + "pause": "暂停", + "resume": "实时", + "refresh": "刷新", + "clear": "清空", + "openFolder": "打开文件夹", + "shownCount": "已显示 {shown} / {total}", + "empty": "暂无日志。", + "levelSaveFailed": "保存日志级别失败", + "openFolderFailed": "打开日志文件夹失败", + "downloadFailed": "下载日志文件失败", + "filesTitle": "日志文件", + "filesDescription": "从磁盘下载完整日志文件,查看实时缓冲区之外的历史记录。", + "filesEmpty": "暂无日志文件。", + "download": "下载", + "downloadTruncated": "文件较大,已下载最新的 {size}。完整文件请在日志目录中查看。", + "captureEnvLocked": "日志级别由 RUST_LOG / CODEG_LOG 环境变量控制;请在该处修改以生效。", + "targetsTitle": "按模块覆盖", + "targetsDescription": "为特定模块(如 codeg_lib::acp)单独设置级别,不影响全局级别。", + "targetsAdd": "添加", + "targetsRemove": "移除覆盖", + "toggleDetails": "切换详情" + }, + "Automations": { + "title": "自动化", + "new": "新建自动化", + "empty": "暂无自动化", + "emptyHint": "创建一个,让智能体按计划或手动执行任务。", + "name": "名称", + "namePlaceholder": "例如:每晚 PR 审查", + "prompt": "提示词", + "promptPlaceholder": "让智能体做什么?", + "agent": "智能体", + "folder": "工作区文件夹", + "folderPlaceholder": "选择文件夹", + "isolation": "隔离方式", + "isolationWorktree": "每次运行新建 worktree", + "isolationShared": "在文件夹内运行", + "isolationSharedCaveat": "运行会直接使用该文件夹的工作树,可能与你未提交的改动冲突。勾选每次运行新建工作树以隔离每次运行。", + "trigger": "触发方式", + "triggerSchedule": "按计划", + "triggerManual": "仅手动", + "cron": "计划(cron)", + "cronPlaceholder": "0 9 * * 1-5", + "timezone": "时区", + "nextRun": "下次运行", + "branch": "分支", + "branchOptional": "分支(可选)", + "enabled": "已启用", + "save": "保存", + "cancel": "取消", + "edit": "编辑", + "delete": "删除", + "runNow": "立即运行", + "cancelRun": "取消运行", + "runHistory": "运行历史", + "noRuns": "暂无运行记录", + "allFolders": "所有文件夹", + "filterAll": "全部", + "noMatches": "没有匹配的自动化", + "viewConversation": "查看会话", + "lastRun": "上次运行", + "never": "从未", + "running": "运行中", + "deleteTitle": "删除此自动化?", + "deleteDescription": "这将删除该自动化及其计划。运行历史会保留。", + "statusRunning": "运行中", + "statusSucceeded": "成功", + "statusFailed": "失败", + "statusCancelled": "已取消", + "statusSkipped": "已跳过", + "errorName": "名称必填", + "errorPrompt": "提示词必填", + "errorCron": "按计划的自动化需要 cron 表达式", + "errorFolder": "请选择工作区文件夹", + "presetHourly": "每小时", + "presetDaily": "每天 9 点", + "presetWeekdays": "工作日 9 点", + "presetCustom": "自定义", + "probing": "正在加载选项…", + "retry": "重试", + "configNone": "该智能体没有可配置项", + "inherit": "智能体默认", + "mode": "模式", + "config": "配置", + "branchPlaceholder": "(默认分支)", + "selectHint": "选择一个自动化以查看详情", + "refresh": "刷新", + "onboardTitle": "自动化日常智能体任务", + "onboardHint": "安排智能体定时或按需审查代码、更新依赖或处理问题。", + "headerSubtitle": "定时与按需的智能体任务", + "startFromTemplate": "从模板开始", + "blankTitle": "空白自动化", + "blankDesc": "从零配置一个智能体任务。", + "backToTemplates": "模板", + "sectionSchedule": "计划与目标", + "sectionTarget": "运行目标", + "sectionAction": "动作", + "actionLaunchSession": "启动会话", + "actionEnqueueTask": "任务入队", + "actionEnqueueTaskHint": "每次触发都会在目标文件夹的待办任务里加入一个待办任务(标题为本自动化名称),由任务引擎按看板设置执行。", + "sectionPrompt": "提示词", + "nextIn": "{rel}后运行", + "manual": "手动", + "schedEveryMinutes": "每 {n} 分钟", + "schedHourly": "每小时", + "schedDaily": "每天 {time}", + "schedWeekdays": "工作日 {time}", + "schedWeekly": "每{day} {time}", + "schedMonthly": "每月 {day} 日 {time}", + "dow0": "周日", + "dow1": "周一", + "dow2": "周二", + "dow3": "周三", + "dow4": "周四", + "dow5": "周五", + "dow6": "周六", + "tplCodeReviewTitle": "代码审查", + "tplCodeReviewDesc": "审查最近的改动,查找缺陷、回归和质量问题。", + "tplDependencyUpdatesTitle": "依赖更新", + "tplDependencyUpdatesDesc": "查找过时的依赖并提出安全的升级方案。", + "tplTestCoverageTitle": "测试覆盖", + "tplTestCoverageDesc": "找出未覆盖的代码路径并补充缺失的测试。", + "tplTodoSweepTitle": "TODO 清理", + "tplTodoSweepDesc": "收集 TODO 和 FIXME 注释并按优先级整理。", + "tplCiTriageTitle": "CI 排查", + "tplCiTriageDesc": "排查最近失败的检查并提出修复方案。", + "tplReleaseNotesTitle": "发布说明", + "tplReleaseNotesDesc": "汇总自上次发布以来的改动,生成更新日志。", + "tplSecurityAuditTitle": "安全审计", + "tplSecurityAuditDesc": "扫描漏洞和风险模式,并报告发现的问题。", + "enable": "启用", + "disable": "停用", + "moreActions": "更多操作", + "statusDisabled": "已停用", + "cronBuilderTitle": "计划生成器", + "cronFreqLabel": "频率", + "cronFreqMinutes": "每 N 分钟", + "cronFreqHourly": "每小时", + "cronFreqDaily": "每天", + "cronFreqWeekdays": "工作日", + "cronFreqWeekly": "每周", + "cronFreqMonthly": "每月", + "cronFreqCustom": "自定义", + "cronEveryLabel": "间隔(分钟)", + "cronTimeLabel": "时间", + "cronHourLabel": "小时", + "cronMinuteLabel": "分钟", + "cronDowLabel": "星期", + "cronDomLabel": "日期", + "cronApply": "应用", + "cronPreviewLabel": "预览", + "cronOpenBuilder": "打开计划生成器", + "branchDefault": "默认分支", + "branchUseCustom": "使用 “{query}”", + "branchLocal": "本地", + "branchRemote": "远程", + "branchSearchPlaceholder": "搜索分支…", + "branchNone": "无分支" + }, + "Tasks": { + "title": "待办任务", + "new": "新建任务", + "empty": "还没有任务", + "emptyHint": "添加待办后即可处理——agent 在独立 worktree 中工作,你验收并合并结果。", + "emptyColTodo": "还没有待办任务", + "emptyColInProgress": "暂无进行中的任务", + "emptyColAttention": "暂无等你处理的任务", + "emptyColDone": "还没有已完成的任务", + "allFolders": "全部文件夹", + "showCanceled": "显示已取消", + "showArchived": "显示已归档", + "filter": "筛选", + "viewSwitchToBoard": "切换到看板视图", + "viewSwitchToList": "切换到列表视图", + "statusFilter": "状态", + "statusFilterAll": "全部状态", + "listEmpty": "没有符合当前筛选条件的任务", + "listColStatus": "状态", + "listColTask": "任务", + "listColLocation": "位置", + "listColChanges": "变更", + "listColUpdated": "更新", + "colTodo": "待办", + "colInProgress": "进行中", + "colAttention": "等你处理", + "colDone": "已完成", + "statusTodo": "待办", + "statusQueued": "排队中", + "statusPreparing": "初始化中", + "statusRunning": "进行中", + "statusAwaitingInput": "等待输入", + "statusReview": "待验收", + "statusMerging": "合并中", + "statusDone": "已完成", + "statusFailed": "失败", + "statusCanceled": "已取消", + "statusInterrupted": "已中断", + "badgeCleanupFailed": "清理失败", + "badgeWorktreeKept": "保留 worktree", + "badgeWorktreeRemoved": "Worktree 已删除", + "filesChanged": "{count} 个文件", + "actionStart": "开始", + "actionSchedule": "定时运行", + "actionCancel": "取消", + "actionRetry": "重试", + "actionRequeue": "重新排队", + "actionViewSession": "查看会话", + "actionEdit": "编辑", + "actionDelete": "删除", + "actionRetryCleanup": "重试清理", + "actionMerge": "合并", + "actionUnqueueMerge": "取消排队", + "actionEditQueuedMerge": "修改排队的合并", + "badgeMergeQueued": "排队合并中", + "badgeMergeQueuedRank": "排队合并 · 第 {rank} 位", + "badgeMergeQueuedHint": "正在等待该项目当前的合并完成,轮到时会自动开始。", + "actionComplete": "完成", + "actionAbandon": "放弃", + "cancelTitle": "取消任务?", + "cancelDescription": "任务将变为已取消。worktree 会保留,之后可以重新排队。", + "cancelReasonLabel": "取消原因(可选)", + "cancelReasonPlaceholder": "例如:方向不对,我重写一下任务描述", + "cancelKeep": "先不取消", + "cancelSubmit": "取消任务", + "restartTitleRetry": "重试任务", + "restartTitleRequeue": "重新排队", + "restartDescription": "可以补充一段说明(可选),它会随下一轮的提示词一起发给 agent。", + "scheduleTitle": "定时运行任务", + "scheduleDescription": "任务留在「待办」,到点自动开始。文件夹的并发上限依然生效。", + "scheduleDateLabel": "日期", + "schedulePickDate": "选择日期", + "scheduleTimeLabel": "时间", + "schedulePreview": "{time} 运行", + "schedulePastHint": "该时间已过——保存后会立即开始。", + "scheduleInAnHour": "1 小时后", + "scheduleInThreeHours": "3 小时后", + "scheduleTomorrow": "明天 9:00", + "scheduleClear": "清除定时", + "scheduleBadge": "计划于 {time} 开始", + "toastScheduled": "已定时:{time}", + "toastScheduleCleared": "已清除定时", + "actionFollowUp": "继续处理", + "actionAddNote": "补充说明", + "followUpSubmit": "发送", + "followUpIntentRevise": "修改返工", + "followUpIntentContinue": "继续推进", + "followUpIntentQuestion": "提问答疑", + "followUpIntentVerify": "自查验证", + "followUpPlaceholderRevise": "希望 agent 改哪里?会在同一会话里继续。", + "followUpPlaceholderContinue": "接下来还要做什么?已有的工作会保留。", + "followUpPlaceholderQuestion": "想了解什么?agent 只回答,不会改动任何文件。", + "followUpPlaceholderVerify": "可选:有什么想让它重点检查的?", + "followUpPlaceholderRetry": "可选:这次要怎么做才不一样?例如:先跑 pnpm install", + "followUpPlaceholderRequeue": "可选:当时为什么取消?这次要注意什么?", + "actionArchive": "归档", + "actionUnarchive": "取消归档", + "archiveAllDone": "全部归档", + "dropToStart": "松开即开始执行", + "errorView": "查看", + "notifyReview": "待验收:{title}", + "notifyFailed": "任务失败:{title}", + "createFromMessage": "由此消息创建任务", + "detailTokens": "总 token 用量", + "editorTitleNew": "新建任务", + "editorTitleEdit": "编辑任务", + "templates": "模板", + "templatesEmpty": "还没有模板。", + "templateSaveCurrent": "把当前内容存为模板", + "templateDelete": "删除模板", + "transcriptTitle": "任务会话", + "transcriptDescription": "任务智能体会话的只读实时视图。", + "phaseWork": "任务执行", + "phaseRetry": "重试执行", + "phaseReturn": "继续处理", + "phaseMerge": "合并变更", + "titleLabel": "标题", + "titlePlaceholder": "要做什么?", + "promptLabel": "任务描述", + "promptPlaceholder": "向 agent 描述任务——输入 @ 可引用文件,/ 可唤起命令", + "folderPlaceholder": "选择文件夹", + "agentInheritedHint": "继承自任务设置,修改后仅对本任务生效", + "agentOverrideReset": "恢复继承", + "sectionTarget": "目标", + "errorTitle": "请输入标题", + "errorPrompt": "请输入任务描述", + "errorFolder": "请选择文件夹", + "save": "保存", + "cancel": "取消", + "mergeTitle": "合并任务", + "mergeQueuedTitle": "排队中的合并", + "mergeQueueHint": "该项目正在合并另一个任务。此任务会加入队列,等前一个完成后自动开始。", + "mergeQueueUpdateHint": "该任务已在合并队列中。提交将更新它的合并选项,并保留原有的排队位置。", + "mergeDescription": "将 {branch} 合并到 {base}。worktree 中未提交的变更会先自动提交。", + "mergeMessage": "提交信息", + "mergeMessagePlaceholder": "例如 feat: add login validation", + "mergeAutoMessage": "让 agent 自动生成提交信息", + "strategySquash": "合并为一条提交", + "strategySquashHint": "任务的所有修改压缩成一条提交记录并入主分支,历史更简洁。", + "strategyMerge": "保留完整提交历史", + "strategyMergeHint": "保留任务过程中的每一条提交,另加一条合并记录,每一步都可追溯。", + "mergeDeleteWorktree": "合并后删除 worktree", + "mergeSubmit": "合并", + "mergeSubmitQueue": "加入合并队列", + "mergeQueuedToast": "已加入合并队列,等当前合并完成后自动开始。", + "completeTitle": "完成任务", + "completeDescription": "该任务没有改动任何文件,无需合并,将直接标记为已完成。", + "completeDescriptionNoWorktree": "该任务的 worktree 已被删除,无法再合并,将直接标记为已完成。若工作分支上仍有未合并的提交,分支会被保留。", + "completeDeleteWorktree": "完成后删除 worktree", + "completeSubmit": "完成", + "settingsTitle": "任务设置", + "settingsDescription": "{folder} 中任务的默认配置。", + "settingsScope": "作用域", + "settingsScopeGlobal": "全部文件夹(全局默认)", + "settingsScopeGlobalHint": "未单独设置的文件夹将使用这份全局默认配置。", + "settingsSource": "配置来源", + "settingsSourceGlobal": "使用全局默认", + "settingsSourceCustom": "单独配置", + "settingsSourceGlobalFollow": "跟随全局任务设置,全局改动会自动生效。", + "settingsSourceCustomHint": "为此文件夹保存独立设置,不再跟随全局默认。", + "settingsAgent": "默认 agent", + "settingsMaxConcurrent": "最大并发任务数", + "settingsMaxConcurrentHint": "0 表示不限制", + "settingsAutoProcess": "自动处理", + "settingsAutoProcessHint": "待办任务自动开始处理,受并发上限约束。", + "settingsMergeStrategy": "默认合并策略", + "settingsMergeStrategyHint": "合并任务时,这些修改在分支历史里如何记录。", + "settingsAutoMerge": "自动合并", + "settingsAutoMergeHint": "任务进入待验收且有可合并改动时自动落地,与点击「合并」相同:提交信息由 agent 自动生成,是否删除 worktree 沿用下方默认。预检未通过或合并失败的任务会留下等你处理。", + "settingsDeleteWorktree": "合并后删除 worktree", + "settingsDeleteWorktreeHint": "合并对话框里默认勾选,仍可临时改。", + "settingsWorktreeRoot": "Worktree 位置", + "settingsWorktreeRootHint": "新任务的 worktree 创建在该目录下,每个任务一个。留空则创建在项目文件夹的同级目录;「~」表示主目录,相对路径相对于项目文件夹。", + "settingsWorktreeRootPlaceholder": "~/codeg-worktrees", + "settingsWorktreeRootBrowse": "选择 worktree 目录", + "settingsPreflight": "预检命令", + "settingsPreflightHint": "任务进入待验收时在 worktree 中运行。", + "settingsPreflightCustomPlaceholder": "pnpm test", + "settingsInitCommand": "Worktree 初始化命令", + "settingsInitCommandHint": "新建 worktree 后、会话开始前执行。", + "settingsInitCommandPlaceholder": "pnpm install", + "settingsTabGeneral": "常规", + "settingsTabMerge": "合并", + "settingsTabWorktree": "Worktree", + "settingsTabPrompts": "提示词", + "settingsPromptsIntro": "每个阶段都已内置固定的提示词——任务本身、worktree 规则,合并阶段还包含具体的 git 步骤。这里填的内容会作为补充说明追加到末尾:只是对内置提示词的细化,不会替换它们。", + "settingsPromptStageAll": "全部阶段", + "settingsPromptPlaceholderAll": "例如:遵循 AGENTS.md 里的项目约定;始终用中文回复", + "settingsPromptPlaceholderWork": "例如:先读相关测试;小步提交,边做边交", + "settingsPromptPlaceholderRetry": "例如:先看清楚已经提交了哪些改动再继续,别重做已完成的部分", + "settingsPromptPlaceholderReturn": "例如:逐条处理提到的每一点;不要顺手重构无关代码", + "settingsPromptPlaceholderMerge": "例如:最终合并的提交信息用中文;手动解决过的冲突要单独说明", + "settingsPromptHintAll": "追加到每一次发给 agent 的提示词,包括合并那一轮。", + "settingsPromptHintWork": "任务首次执行时追加。", + "settingsPromptHintRetry": "重试被中断或失败的任务时追加。", + "settingsPromptHintReturn": "对待验收的任务继续处理时追加(返工、追加工作、自查)。", + "settingsPromptHintMerge": "agent 把任务合并到基线分支时追加。", + "preflightPassed": "{name} 通过", + "preflightFailed": "{name} 未通过", + "preflightRunning": "{name} 运行中…", + "detailDescription": "任务详情", + "detailSummary": "结果", + "detailFiles": "变更文件", + "detailDiffAll": "查看全部差异", + "detailDiffAllTitle": "全部差异", + "detailNoChanges": "相对基准还没有变更", + "detailTimeline": "推进记录", + "detailTimelineEmpty": "暂无活动", + "showMore": "展开", + "showLess": "收起", + "detailInfo": "详情", + "detailBranch": "分支", + "detailMergeCommit": "合并提交", + "detailChanges": "变更", + "detailScheduled": "计划开始", + "detailCreated": "创建时间", + "detailStarted": "开始时间", + "detailFinished": "完成时间", + "diffLoading": "正在加载差异…", + "deleteConfirmTitle": "删除任务?", + "deleteConfirmBody": "「{title}」将从看板移除。进行中的运行会先被取消。", + "deleteWithWorktree": "同时删除其 worktree", + "eventCreated": "已创建", + "eventStatusChanged": "状态变更", + "eventConfigEffective": "启动配置", + "eventInitCommand": "初始化命令", + "eventAgentProgress": "Agent 进展", + "eventAgentVerdict": "Agent 结论", + "eventMergeAttempt": "开始合并", + "eventMergeQueued": "加入合并队列", + "eventMergeConflict": "合并冲突", + "eventPreflight": "预检", + "eventCleanupFailed": "worktree 清理失败", + "eventResumeFallback": "会话恢复失败,已改用新会话", + "eventUserAction": "用户操作", + "eventDiffStat": "变更快照" + }, + "CustomSkillsSettings": { + "loading": "正在加载自定义技能…", + "category": "自定义", + "searchPlaceholder": "按名称、ID 或描述搜索自定义技能", + "states": { + "not_linked": "未启用", + "linked_to_codeg": "已启用", + "linked_elsewhere": "链接到其他位置", + "blocked_by_real_directory": "被同名真实目录占用", + "broken": "链接已失效" + }, + "actions": { + "new": "新建", + "import": "导入", + "importFromAgent": "从 Agent 导入", + "cancel": "取消", + "save": "保存" + }, + "rowMenu": { + "edit": "编辑", + "duplicate": "复制为新技能", + "delete": "删除" + }, + "bulk": { + "delete": "删除所选" + }, + "editor": { + "createTitle": "新建自定义技能", + "editTitle": "编辑自定义技能", + "description": "自定义技能存放在共享库(~/.codeg/skills),可为任意智能体启用。", + "idLabel": "技能 ID", + "idPlaceholder": "例如 my-workflow", + "contentLabel": "SKILL.md", + "contentPlaceholder": "在此编写技能的 SKILL.md…", + "preview": "预览", + "edit": "编辑", + "emptyBody": "暂无内容。" + }, + "duplicate": { + "title": "复制技能", + "description": "以「{id}」为模板,用新 ID 创建一份副本。", + "newIdPlaceholder": "新技能 ID", + "confirm": "复制" + }, + "import": { + "title": "选择要导入的技能文件夹" + }, + "importFromAgent": { + "title": "从 Agent 导入技能", + "description": "把某个 Agent 自己的技能复制到共享库,即可为任意 Agent 启用。", + "agentLabel": "Agent", + "agentPlaceholder": "选择一个 Agent", + "selectAll": "全选({count})", + "loading": "正在加载该 Agent 的技能…", + "unsupported": "该 Agent 未提供技能目录。", + "empty": "该 Agent 没有可导入的技能。", + "alreadyInLibrary": "已在库中", + "confirm": "导入所选({count})" + }, + "delete": { + "title": "删除自定义技能?", + "body": "将从中央库移除 {count} 个自定义技能,并解除它们在所有智能体中的链接。此操作不可撤销。", + "confirm": "删除" + }, + "toasts": { + "loadFailed": "加载技能失败", + "idRequired": "请输入技能 ID", + "created": "已创建自定义技能", + "updated": "已更新自定义技能", + "saveFailed": "保存技能失败", + "imported": "已导入技能", + "importFailed": "导入技能失败", + "duplicated": "已复制技能", + "duplicateFailed": "复制技能失败", + "deleted": "已删除 {count} 个技能", + "deletedPartial": "已删除 {ok} 个,{failed} 个失败", + "deleteFailed": "删除技能失败", + "importedFromAgent": "已导入 {count} 个技能", + "importedFromAgentPartial": "已导入 {ok} 个,{failed} 个失败", + "importFromAgentAllSkipped": "无需导入——{count} 个已在库中", + "importFromAgentFailed": "从 Agent 导入失败" + } + }, + "CodexModelEditor": { + "customizedNotice": "你已自定义模型列表,codeg 将接管 codex 的完整模型表。codex 日后新增的官方模型不会自动出现——点击下方刷新并重新保存即可同步。清空全部自定义即可交回 codex 自动更新。", + "officialsTitle": "官方模型", + "officialsHint": "自动纳入你启动的 codex 的官方模型;可删除不需要的。", + "officialsEmpty": "暂无官方模型。", + "refresh": "从 codex 刷新", + "readdOfficial": "重新加入官方", + "customsTitle": "自定义模型", + "customsEmpty": "暂无自定义模型。", + "addCustom": "添加自定义", + "slugPlaceholder": "模型 id(slug)", + "displayNamePlaceholder": "显示名", + "contextWindow": "上下文", + "makeDefault": "设为默认", + "defaultHint": "默认模型", + "remove": "删除", + "advanced": "高级", + "baseTemplate": "基础模板", + "baseTemplateHint": "从哪个官方模型克隆必填字段(系统提示词、工具、限制)。", + "groupBehavior": "行为与能力", + "fieldReasoningLevel": "默认推理强度", + "fieldReasoningSummary": "推理摘要", + "fieldVerbosity": "详细程度", + "fieldShellType": "Shell 类型", + "fieldApplyPatch": "应用补丁工具", + "fieldReasoningSummaries": "推理摘要支持", + "fieldSupportVerbosity": "详细程度控制", + "fieldParallelToolCalls": "并行工具调用", + "fieldSearchTool": "联网搜索工具", + "optNone": "无", + "groupInstructions": "描述与系统提示词", + "fieldDescription": "描述", + "baseInstructions": "系统提示词(base_instructions)" + }, + "DiagnosticsSettings": { + "title": "环境诊断", + "description": "检查本应用在自身进程中如何解析该智能体的 CLI——这可能与你的终端不同。", + "loading": "正在运行诊断…", + "error": "诊断失败", + "rerun": "重新运行", + "copyAll": "复制全部", + "copied": "诊断信息已复制到剪贴板", + "button": "诊断", + "verdict": { + "ok": "环境正常。若仍提示未安装,请彻底重启应用以刷新前缀缓存。", + "node_missing": "在应用的 PATH 上未找到 Node.js。", + "npm_missing": "在应用的 PATH 上未找到 npm。", + "not_installed": "该智能体似乎尚未安装。", + "installed_but_unresolved": "记录显示已安装,但应用无法定位其可执行文件。", + "user_prefix_not_on_path": "安装到了回退前缀(~/.codeg/npm-global),但它不在应用的 PATH 上。请彻底重启应用后重试。", + "homebrew_bin_not_on_path": "安装在 Homebrew 的 bin 目录下,但它不在应用的 PATH 上(Apple Silicon keg 拆分)。", + "terminal_only_path": "该命令在你的终端能解析,但在应用中不能——这是 GUI PATH 差异。请从终端启动应用,或在智能体设置中重新安装。", + "npm_prefix_timeout": "npm prefix -g 太慢(超过 1.5 秒),已跳过回退检测。请重启应用后重试。", + "node_too_old": "当前 Node.js 版本低于该智能体的要求。请升级 Node.js。", + "adapter_missing_native_present": "你本地的 {agent} CLI 确实装了,但 Codeg 启动的是另一个 ACP 适配器包,而它还没装。到「智能体设置」里安装即可 —— 它不会动你的 CLI,登录状态也是共享的。", + "adapter_missing": "Codeg 为 {agent} 启动的是单独的 ACP 适配器包,目前尚未安装。请到「智能体设置」里安装 —— 只装厂商 CLI 是不够的。" + } + }, + "TokenUsage": { + "title": "Token 用量", + "rangeLabel": "时间范围", + "range7d": "近 7 天", + "range30d": "近 30 天", + "range90d": "近 90 天", + "rangeThisMonth": "本月", + "rangeThisYear": "今年", + "rangeAll": "全部", + "rangeCustom": "自定义", + "moreRanges": "更多", + "customRangePick": "选择日期范围", + "bucketLabel": "统计粒度", + "bucketDay": "按天", + "bucketWeek": "按周", + "bucketMonth": "按月", + "bucketUnitDay": "天", + "bucketUnitWeek": "周", + "bucketUnitMonth": "月", + "folderFilter": "文件夹", + "allFolders": "全部文件夹", + "agentFilter": "智能体", + "allAgents": "全部智能体", + "modelFilter": "模型", + "allModels": "全部模型", + "searchPlaceholder": "搜索…", + "noMatches": "没有匹配项", + "clearFilter": "清除选择", + "resetFilters": "重置筛选", + "refresh": "刷新数据", + "rebuild": "全量重建", + "rebuildHint": "丢弃已统计的数据并重新解析全部会话记录。会话被 codeg 之外的 CLI 追加过时用它。", + "syncing": "正在统计会话…", + "syncProgress": "{done} / {total}", + "syncDone": "已统计 {synced} 个会话", + "syncFailed": "部分会话读取失败", + "syncBusy": "已有一次刷新在进行中", + "lastSynced": "更新于 {time}", + "lastSyncedNever": "尚未统计", + "tileTotal": "总 Token", + "tileSessions": "会话数", + "tileTurns": "对话轮次", + "tileActiveDays": "活跃天数", + "tileGenTime": "生成时长", + "vsPrevious": "对比上一周期", + "deltaNew": "新增", + "trendTitle": "用量趋势", + "trendEmpty": "该范围内没有用量", + "trendTurns": "轮次", + "trendSessions": "会话", + "compositionTitle": "Token 都花在哪", + "compositionHint": "输入是你发出去的内容,输出是模型写回来的,缓存读取则是不必再按原价重发的上下文。", + "compositionNote": "这些缓存命中若按原价重发,要多花 {value}。", + "inputTokens": "输入", + "outputTokens": "输出", + "cacheWrite": "缓存写入", + "cacheRead": "缓存读取", + "freshTokens": "新算 Token", + "cacheHitCaption": "缓存命中", + "cacheHeroTitleHigh": "上下文大多不必重发", + "cacheHeroTitleLow": "多数上下文仍按原价计算", + "cacheHeroDesc": "{cached} 的上下文由缓存承担,这段时间真正新算的只有 {fresh}。", + "cacheSavedSuffix": "省下的重发量相当于 {saved}。", + "avgPerSession": "平均每会话", + "avgTurnsPerSession": "平均每会话 {count} 轮", + "avgPerActiveDay": "平均每活跃日", + "peakBucket": "最高的一{bucket}", + "peakHour": "高峰时段", + "daysValue": "{count} 天", + "idleDays": "空转天数", + "byFolderTitle": "按文件夹", + "byAgentTitle": "按智能体", + "byModelTitle": "按模型", + "distributionTitle": "用量分布", + "distributionHint": "会话与 Token 按所选维度归集,点任意一行可按它筛选。", + "otherLabel": "其他", + "unknownModel": "未标注模型", + "emptyBreakdown": "还没有记录", + "sessionsCount": "{count} 个会话", + "heatmapTitle": "你的编码作息", + "heatmapHint": "按本地星期与小时统计的 Token 分布。", + "heatmapPeakHint": "最密集的时段在 {hour}:00 前后。", + "less": "少", + "more": "多", + "heatmapCell": "{weekday} {hour}:00 — {value} tokens", + "weekMon": "一", + "weekTue": "二", + "weekWed": "三", + "weekThu": "四", + "weekFri": "五", + "weekSat": "六", + "weekSun": "日", + "topSessionsTitle": "消耗最高的会话", + "untitledSession": "未命名会话", + "topSessionsEmpty": "该范围内没有会话", + "streakLongest": "最长连续", + "streakLongestDays": "最长连续 {count} 天", + "share": "分享", + "moreActions": "更多操作", + "shareDialogTitle": "分享你的用量卡片", + "shareDialogHint": "卡片内容就是你当前所选的时间范围与筛选条件。", + "shareSave": "保存图片", + "shareCopy": "复制图片", + "shareCopied": "已复制到剪贴板", + "shareSaved": "图片已保存", + "shareFailed": "图片生成失败", + "shareRendering": "生成中…", + "cardHeading": "我的 AI 编码战绩", + "cardRangeAll": "全部时间", + "cardTotalLabel": "累计 Token", + "cardFooter": "由 codeg 生成", + "cardTopModels": "常用模型", + "cardTopProjects": "主力项目", + "archetypeNightOwl": "深夜码农", + "archetypeNightOwlDesc": "{percent}% 的 Token 烧在天黑之后。", + "archetypeEarlyBird": "清晨型选手", + "archetypeEarlyBirdDesc": "{percent}% 的 Token 在早上 9 点前就用掉了。", + "archetypeWeekendWarrior": "周末战士", + "archetypeWeekendWarriorDesc": "{percent}% 的 Token 发生在周末。", + "archetypeCacheMaster": "缓存大师", + "archetypeCacheMasterDesc": "{percent}% 的上下文来自缓存。", + "archetypeMarathoner": "长跑选手", + "archetypeMarathonerDesc": "连续 {days} 天没有断更。", + "archetypePolyglot": "多面手", + "archetypePolyglotDesc": "{count} 个智能体都在主力使用。", + "archetypeLaserFocus": "专注一役", + "archetypeLaserFocusDesc": "{percent}% 的 Token 投在同一个项目上。", + "archetypeDeepDiver": "深潜者", + "archetypeDeepDiverDesc": "平均每个会话 {averageK}K tokens。", + "archetypeSteady": "稳定输出", + "archetypeSteadyDesc": "累计 {days} 天在写代码。", + "emptyTitle": "还没有可统计的数据", + "emptyHint": "codeg 直接从各智能体自己的会话记录里读取 Token 数。点一下刷新,把本机已有的会话统计进来。", + "emptyAction": "统计我的会话", + "loadFailed": "用量加载失败", + "truncatedNotice": "该范围过大 —— 下面的数字只覆盖了其中最近的一段。" + } +} diff --git a/src/i18n/messages/zh-TW.json b/src/i18n/messages/zh-TW.json index 13e7b6eae..9d2737f10 100644 --- a/src/i18n/messages/zh-TW.json +++ b/src/i18n/messages/zh-TW.json @@ -1,4956 +1,4958 @@ -{ - "Language": { - "followSystem": "跟隨系統", - "english": "英文", - "simplifiedChinese": "簡體中文", - "traditionalChinese": "繁體中文", - "japanese": "日語", - "korean": "韓語", - "spanish": "西班牙語", - "german": "德語", - "french": "法語", - "portuguese": "葡萄牙語", - "arabic": "阿拉伯語" - }, - "GitCredentialDialog": { - "title": "需要身份驗證", - "description": "遠端伺服器要求輸入憑據。請輸入使用者名稱和密碼(或個人存取權杖)。", - "username": "使用者名稱", - "usernamePlaceholder": "使用者名稱或電子郵件", - "password": "密碼 / 權杖", - "passwordPlaceholder": "密碼或個人存取權杖", - "passwordHint": "請輸入伺服器的使用者名稱和密碼。", - "cancel": "取消", - "authenticate": "驗證", - "authenticating": "驗證中...", - "invalidCredentials": "憑據無效,請重試。", - "saveCredentials": "儲存憑據以供後續操作使用", - "githubTitle": "GitHub 身份驗證", - "githubDescription": "輸入個人存取權杖以連線 GitHub。權杖驗證成功後將自動儲存至帳號列表。", - "githubToken": "個人存取權杖", - "githubTokenPlaceholder": "ghp_xxxxxxxxxxxx", - "githubTokenHint": "在 GitHub → Settings → Developer settings → Personal access tokens 中產生權杖。", - "githubAuthenticate": "驗證並連線", - "generateToken": "產生權杖" - }, - "SettingsShell": { - "title": "設定", - "preferences": "偏好設定", - "nav": { - "general": "一般", - "appearance": "外觀", - "agents": "智能體", - "mcp": "MCP", - "skills": "Skills", - "shortcuts": "快捷鍵", - "version_control": "版本控制", - "system": "系統", - "chat_channels": "訊息頻道", - "web_service": "Web 服務", - "model_providers": "模型供應商", - "experts": "專家", - "science": "科學研究", - "office_tools": "辦公工具", - "skill_packs": "技能包", - "quick_messages": "快捷訊息", - "logs": "執行日誌" - } - }, - "AppearanceSettings": { - "sectionTitle": "主題外觀", - "sectionDescription": "選擇淺色、深色或跟隨系統主題,設定會自動儲存。", - "themeMode": "主題模式", - "placeholder": "請選擇主題模式", - "system": "跟隨系統", - "light": "淺色", - "dark": "深色", - "currentTheme": "目前生效主題:{theme}", - "resolvedTheme": { - "light": "淺色", - "dark": "深色", - "unknown": "未知" - }, - "themeColor": { - "sectionTitle": "主題顏色", - "sectionDescription": "選擇按鈕、強調色和高亮使用的色調。", - "current": "目前顏色:{color}", - "options": { - "neutral": "Neutral", - "zinc": "Zinc", - "slate": "Slate", - "stone": "Stone", - "gray": "Gray", - "red": "Red", - "rose": "Rose", - "orange": "Orange", - "green": "Green", - "blue": "Blue", - "yellow": "Yellow", - "violet": "Violet" - } - }, - "customStyle": { - "sectionTitle": "自訂樣式", - "sectionDescription": "在目前主題的基礎上微調配色,或寫入自己的 CSS。覆寫疊加在基底預設之上,切換預設後依然保留。", - "summarySuspended": "已停用", - "summaryDefault": "跟隨預設", - "summaryTokens": "{count, plural, other {# 項覆寫}}", - "summaryCss": "自訂 CSS", - "suspendedByShortcut": "自訂樣式已停用。在恢復之前,這裡的設定都不會生效。", - "suspendedBySafeParam": "本視窗以安全外觀模式開啟,自訂樣式在此不生效,其它視窗不受影響。", - "resume": "恢復自訂樣式", - "enableTheme": "啟用自訂配色", - "editingLight": "正在編輯淺色模式的取值。切換到深色模式可單獨設定深色。", - "editingDark": "正在編輯深色模式的取值。切換到淺色模式可單獨設定淺色。", - "resetToken": "還原為預設取值", - "radius": "圓角", - "radiusHint": "從 sm 到 4xl 的整套圓角尺寸都由它衍生,一個滑桿即可改變全域圓角。", - "advanced": "進階(另有 {count} 個變數)", - "enableCss": "啟用自訂 CSS", - "cssRisk": "進階功能。自訂 CSS 會壓過所有內建樣式,寫壞可能導致介面無法使用。", - "editCss": "編輯 CSS…", - "cssPresent": "已儲存 {size} KB", - "cssEmpty": "尚未儲存內容", - "escapeHint": "介面被改壞了?按 {shortcut} 可停用全部自訂樣式,也可以用 safeStyle=1 查詢參數開啟視窗。", - "copyTheme": "複製主題 JSON", - "importTheme": "匯入主題…", - "clearTheme": "清除覆寫", - "interopHint": "主題採用 shadcn 的 registry:theme 格式,可以直接貼上任意 shadcn 主題,匯出的主題也能用在任何 shadcn 專案裡。", - "importTitle": "匯入主題", - "importDescription": "貼上 shadcn 的 registry:theme 項目、裸的 light/dark 物件,或者單層的 token 對應表。", - "readClipboard": "讀取剪貼簿", - "importConfirm": "匯入", - "cancel": "取消", - "apply": "套用", - "toasts": { - "copied": "主題 JSON 已複製", - "copyFailed": "無法寫入剪貼簿", - "clipboardReadFailed": "無法讀取剪貼簿,請手動貼上", - "importFailed": "這段 JSON 裡沒有可用的主題變數", - "imported": "主題已匯入" - }, - "css": { - "dialogTitle": "自訂 CSS", - "dialogDescription": "對所有 codeg 視窗生效。修改會即時預覽,點擊「套用」才會儲存。", - "size": "{used} KB / {max} KB", - "ruleCount": "{count} 條規則", - "errorTooLarge": "內容過大,無法儲存,請精簡到上限以內。", - "errorImportEscaped": "剝離後仍偵測到 @import(跳脫寫法),請手動移除後再儲存。", - "warnNoRules": "沒有解析出任何規則,請檢查語法。", - "noticeImportsRemoved": "已移除 {count} 條 @import:它們會拉取遠端樣式表。", - "noticeRemoteUrl": "含遠端 url(),套用後會發起網路請求。", - "noticePreviewSuspended": "自訂樣式已停用,此處預覽不會生效。", - "noticeDisabled": "自訂 CSS 未啟用。這裡可以預覽,但啟用後才會真正生效。", - "hintTokens": "提示:你覆寫的顏色可以直接用 var(--primary)、var(--background) 等引用。" - } - }, - "zoomLevel": { - "sectionTitle": "視窗縮放", - "sectionDescription": "整體放大或縮小介面,立即生效,依裝置分別儲存。", - "placeholder": "請選擇縮放檔位", - "default": "預設", - "current": "目前縮放:{zoom}%" - }, - "fonts": { - "sectionTitle": "字型", - "sectionDescription": "為介面、程式碼編輯器與終端機分別選擇字型。內建字型會按需載入;選擇「自訂…」可使用系統已安裝的任意字型。", - "interface": "介面", - "editor": "編輯器", - "terminal": "終端機", - "groupSans": "無襯線", - "groupMono": "等寬", - "custom": "自訂…", - "customPlaceholder": "字型名稱,如 Fira Code", - "fontSize": "字級", - "ligatures": "啟用連字", - "ligaturesUnavailable": "此字型不含連字", - "wordWrap": "啟用自動換行", - "terminalLigaturesHint": "終端機連字僅對內建程式字型生效。", - "preview": "預覽" - }, - "welcomePanel": { - "sectionTitle": "模式選擇區域", - "sectionDescription": "新會話頁面輸入框上方顯示的「程式開發 / 日常辦公」快捷卡片區域。", - "showQuickActions": "在新會話頁面顯示" - }, - "workspaceBackground": { - "sectionTitle": "工作區背景", - "sectionDescription": "在整個工作區背後顯示一張圖片。側邊欄與面板會變半透明並磨砂讓圖片透出,遮罩確保文字可讀。", - "enable": "啟用背景圖片", - "image": "圖片", - "chooseImage": "選擇圖片", - "replaceImage": "更換圖片", - "removeImage": "移除", - "fillMode": "填滿方式", - "fillModes": { - "cover": "覆蓋", - "contain": "適應", - "center": "置中", - "tile": "平鋪" - }, - "maskOpacity": "遮罩不透明度", - "maskOpacityHint": "數值越高,圖片越向主題背景色淡化,文字對比越清晰。", - "imageBlur": "圖片模糊", - "panelOpacity": "面板不透明度", - "panelOpacityHint": "側邊欄、面板與標籤列的不透明程度。越低,透出的圖片越多。", - "errorTooLarge": "圖片太大(最大 16 MB)。", - "errorUploadFailed": "設定背景圖片失敗。" - } - }, - "SystemSettings": { - "loading": "載入中...", - "sectionTitle": "系統管理", - "sectionDescription": "管理網路代理、應用升級與語言偏好。", - "proxyTitle": "網路代理", - "proxyDescription": "啟用後,後續網路請求將優先走該代理(包含 ACP 對話、Agent 安裝、Git 遠端操作等)。", - "loadFailed": "載入失敗:{message}", - "enableProxy": "啟用系統代理", - "proxyAddress": "代理位址", - "proxyHint": "支援 http(s)/socks5,範例:{example}。僅在啟用系統代理時生效。", - "save": "儲存", - "saving": "儲存中...", - "proxyRequired": "啟用代理時必須填寫代理位址", - "saveSuccess": "系統代理設定已儲存", - "saveFailed": "儲存失敗:{message}", - "languageTitle": "語言", - "languageDescription": "設定應用語言。跟隨系統時,若系統語言不受支援將回退為英文。", - "appLanguage": "應用語言", - "languageSaveSuccess": "語言設定已儲存", - "languageSaveFailed": "語言設定儲存失敗:{message}", - "updateTitle": "應用升級", - "versionTitle": "軟體更新", - "updateDescription": "點擊檢查後會從設定的發佈來源拉取最新版本資訊,有新版本時可直接下載並安裝。", - "currentVersion": "目前版本", - "upgradableVersion": "最新版本", - "none": "暫無", - "lastChecked": "上次檢查:{time}", - "updateError": "更新異常:{message}", - "checking": "檢查中...", - "checkUpdate": "檢查更新", - "updating": "升級中...", - "downloading": "下載中...", - "upgradeTo": "升級到 v{version}", - "viewRelease": "查看 v{version} 發布", - "foundUpdate": "發現新版本 v{version}", - "alreadyLatest": "目前已是最新版本", - "checkUpdateFailed": "檢查更新失敗:{message}", - "installSuccess": "升級包已安裝,正在重新啟動應用", - "installFailed": "升級失敗:{message}", - "upgradeSuccess": "升級完成,正在重新載入...", - "restartTimeout": "服務未能即時恢復,請檢查容器或服務記錄。", - "restartingIn": "將在 {seconds} 秒後重新啟動...", - "waitingForServer": "正在等待服務恢復...", - "restartToUpdate": "重新啟動以更新", - "newVersionBadge": "新版本 v{version}", - "updateAvailableTitle": "發現新版本", - "releaseNotesTitle": "更新內容", - "remindLater": "稍後", - "retry": "重試", - "stepDownload": "下載", - "stepInstall": "安裝", - "stepRestart": "重新啟動", - "updateReadyHint": "新版本已下載,重新啟動以完成更新。", - "restarting": "正在重新啟動…", - "dockerUpgradeHint": "現在升級的是正在執行的容器。容器一旦被重新建立即遺失——如需保留,請拉取或建置新版本映像後重新建立容器。", - "upgradeRolledBack": "升級失敗,伺服器已自動回復到上一版本。", - "serverUnreachable": "無法連線到伺服器以開始升級。請確認伺服器正在執行後重試。", - "rollbackButton": "復原", - "rollingBack": "復原中...", - "rollbackDescription": "還原至上次升級前安裝的版本。", - "rollbackConfirmTitle": "復原到上一個版本?", - "rollbackConfirmDescription": "伺服器將重新啟動並執行上次升級前安裝的版本。較新的版本仍可再次安裝。", - "rollbackConfirm": "復原", - "rollbackCancel": "取消", - "rollbackSuccess": "已復原到上一個版本,正在重新載入……", - "rollbackFailed": "復原失敗,請檢查伺服器日誌。", - "updateErrors": { - "sourceUnavailable": "無法連線更新來源,請檢查網路或代理設定後重試。", - "network": "網路連線異常,請檢查網路或代理設定後重試。", - "downloadFailed": "下載更新包失敗,請稍後再試。", - "installFailed": "安裝更新失敗,請關閉應用後重試。", - "unknown": "更新失敗,請稍後再試。" - } - }, - "VersionControlSettings": { - "loading": "載入中...", - "sectionTitle": "版本控制", - "sectionDescription": "設定 Git 執行檔並管理 GitHub 帳號。", - "gitTitle": "Git 設定", - "gitDescription": "設定應用程式使用的 Git 執行檔。", - "gitDetected": "已偵測到 Git", - "gitNotFound": "未在系統中找到 Git", - "gitVersion": "版本", - "gitPath": "路徑", - "customGitPath": "自訂 Git 路徑", - "customGitPathPlaceholder": "/usr/bin/git", - "customGitPathHint": "留空則使用自動偵測的路徑。", - "test": "測試", - "testing": "測試中...", - "testSuccess": "Git 執行檔有效。", - "testFailed": "Git 測試失敗:{message}", - "save": "儲存", - "saving": "儲存中...", - "saveSuccess": "Git 設定已儲存。", - "saveFailed": "儲存失敗:{message}", - "githubTitle": "GitHub 帳號", - "githubDescription": "管理用於身份驗證的 GitHub 帳號。權杖儲存在本機。", - "noAccounts": "尚未設定 GitHub 帳號。", - "addAccount": "新增帳號", - "serverUrl": "伺服器網址", - "serverUrlPlaceholder": "https://github.com", - "token": "個人存取權杖", - "tokenPlaceholder": "ghp_xxxxxxxxxxxx", - "generateToken": "產生權杖", - "tokenHint": "在 GitHub → Settings → Developer settings → Personal access tokens 中產生權杖。", - "validateAndAdd": "驗證並新增", - "validating": "驗證中...", - "addSuccess": "帳號 {username} 新增成功。", - "addFailed": "新增帳號失敗:{message}", - "testConnection": "測試", - "connectionSuccess": "連線成功。", - "connectionFailed": "連線失敗:{message}", - "setDefault": "設為預設", - "defaultLabel": "預設", - "defaultSet": "預設帳號已更新。", - "removeAccount": "刪除", - "removeConfirmTitle": "刪除帳號", - "removeConfirmMessage": "確定要刪除帳號「{username}」嗎?", - "removeConfirm": "刪除", - "removeCancel": "取消", - "removeSuccess": "帳號已刪除。", - "scopes": "權限範圍", - "loadFailed": "載入設定失敗:{message}", - "gitAccount": { - "sectionTitle": "Git 伺服器帳號", - "sectionDescription": "管理非 GitHub 的 Git 伺服器憑據(GitLab、Bitbucket、自建服務等)。", - "noAccounts": "尚未設定 Git 伺服器帳號。", - "addAccount": "新增帳號", - "addTitle": "新增 Git 帳號", - "addDescription": "輸入伺服器網址、使用者名稱和密碼或存取權杖。", - "serverUrl": "伺服器網址", - "serverUrlPlaceholder": "https://gitlab.example.com", - "username": "使用者名稱", - "usernamePlaceholder": "使用者名稱或電子郵件", - "password": "密碼 / 權杖", - "passwordPlaceholder": "密碼或存取權杖", - "passwordHint": "輸入伺服器的密碼或個人存取權杖。", - "add": "新增", - "serverRequired": "請輸入伺服器網址。", - "usernameRequired": "請輸入使用者名稱。", - "passwordRequired": "請輸入密碼。" - } - }, - "ShortcutSettings": { - "sectionTitle": "快捷鍵", - "resetDefault": "恢復預設", - "recordInstruction": "點擊右側按鈕後按下組合鍵即可修改。建議使用 Ctrl/Cmd、Alt、Shift 的組合。按 Esc 可取消錄製。", - "recording": "按下快捷鍵...", - "toasts": { - "conflict": "快捷鍵已被「{title}」占用", - "updated": "快捷鍵已更新", - "invalid": "快捷鍵無效,請重試", - "reset": "已恢復預設快捷鍵" - }, - "actions": { - "toggle_search": { - "title": "打開搜尋", - "description": "打開或關閉會話搜尋面板" - }, - "toggle_sidebar": { - "title": "切換左側邊欄", - "description": "顯示或隱藏會話列表側邊欄" - }, - "toggle_terminal": { - "title": "切換終端", - "description": "顯示或隱藏底部終端面板" - }, - "new_terminal_tab": { - "title": "新增終端", - "description": "當最近滑鼠活動在終端時新增終端分頁" - }, - "close_current_terminal_tab": { - "title": "關閉目前終端", - "description": "當最近滑鼠活動在終端時關閉目前終端分頁" - }, - "toggle_aux_panel": { - "title": "切換右側面板", - "description": "顯示或隱藏輔助資訊面板" - }, - "new_conversation": { - "title": "新增會話", - "description": "在目前資料夾中建立新的對話分頁" - }, - "open_folder": { - "title": "打開資料夾", - "description": "打開資料夾選擇器並在新視窗中開啟" - }, - "open_settings": { - "title": "打開設定", - "description": "打開設定視窗" - }, - "close_current_tab": { - "title": "關閉目前分頁", - "description": "關閉目前會話或檔案分頁" - }, - "close_all_file_tabs": { - "title": "關閉全部檔案分頁", - "description": "當檔案面板處於作用中狀態時關閉所有開啟的檔案分頁" - }, - "next_tab": { - "title": "下一個標籤頁", - "description": "切換到下一個會話或檔案標籤頁" - }, - "prev_tab": { - "title": "上一個標籤頁", - "description": "切換到上一個會話或檔案標籤頁" - }, - "send_message": { - "title": "傳送訊息", - "description": "在輸入框中傳送目前的訊息" - }, - "newline_in_message": { - "title": "訊息換行", - "description": "在輸入框中插入換行符" - }, - "toggle_custom_style": { - "title": "停用/恢復自訂樣式", - "description": "逃生艙:一鍵關閉全部自訂配色與 CSS,再按一次恢復" - } - } - }, - "SkillsSettings": { - "title": "Skills", - "description": "左側選擇 Skill,右側預設預覽 Markdown,點擊編輯後可修改並儲存。", - "loadingAgents": "正在載入支援 Skills 的 Agent...", - "emptyNoManageableAgents": "目前沒有可管理 Skills 的 Agent。", - "managedTarget": "管理對象", - "selectAgentPlaceholder": "請選擇 Agent", - "searchPlaceholder": "搜尋名稱 / ID / 路徑...", - "skillsList": "Skills 列表", - "loadingSkills": "載入 Skills 中...", - "agentNotSupported": "目前 Agent 暫不支援 Skills 管理。", - "emptySkills": "暫無 Skill,可點擊「新增 Skill」。", - "newSkillTitle": "新增 Skill", - "skillInfo": "Skill 資訊", - "skillIdPlaceholder": "Skill ID(例如:my-skill)", - "skillsDirectoryWithPath": "Skills目錄:{path}", - "skillsDirectoryNeedId": "Skills目錄:請輸入 Skill ID 以產生完整路徑", - "markdownContent": "Markdown 內容", - "editingStatus": "編輯中", - "previewStatus": "預覽中", - "contentPlaceholder": "輸入 Skill 文字內容...", - "metadataTitle": "Skills 中繼資訊", - "onlyYamlMetadata": "該 Skill 僅包含 YAML 中繼資訊。", - "emptyContentHint": "暫無內容。點擊「編輯」開始輸入。", - "loadingSkill": "正在載入 Skill...", - "emptyNoAgents": "暫無可用 Agent。", - "noSelectionHint": "從左側選擇一個 Skill,或點擊「新建 Skill」建立。", - "systemBadge": "系統", - "systemHint": "CLI 內建 Skill · 唯讀", - "scope": { - "global": "全域", - "folder": "資料夾", - "selectFolderPlaceholder": "選擇資料夾", - "noFolders": "找不到任何資料夾", - "pickFolderHint": "選擇一個資料夾以檢視其 Skills。" - }, - "actions": { - "preview": "預覽", - "edit": "編輯", - "openInWindow": "在新視窗打開", - "delete": "刪除", - "deleting": "刪除中...", - "refresh": "刷新", - "newSkill": "新增 Skill", - "reset": "重置", - "save": "儲存", - "saving": "儲存中...", - "cancel": "取消" - }, - "deleteDialog": { - "title": "刪除 Skill", - "confirm": "確認刪除目前 Skill 嗎?此操作無法復原。", - "confirmWithNamePrefix": "確認刪除 Skill", - "confirmWithNameSuffix": "嗎?此操作無法復原。" - }, - "toasts": { - "loadFailed": "載入 Skill 失敗", - "openFolderFailed": "打開目錄失敗", - "noSkillDirectory": "目前 Agent 未找到可用的 Skills 目錄", - "nameRequired": "Skill 名稱不能為空", - "updated": "Skill 已更新", - "created": "Skill 已建立", - "saveFailed": "儲存 Skill 失敗", - "deleted": "Skill 已刪除", - "deleteFailed": "刪除 Skill 失敗" - }, - "templates": { - "gemini": "---\nname: example-skill\ndescription: Describe when this skill should be used.\n---\n\n# Skill Name\n\nInstructions for the agent when this skill is active.\n\n## Workflow\n\n1. Add actionable step one.\n2. Add actionable step two.\n", - "openCode": "---\nname: example-skill\ndescription: Describe when this skill should be used.\n---\n\n# Purpose\n\nDescribe what this skill helps with.\n\n# Steps\n\n1. Add actionable step one.\n2. Add actionable step two.\n", - "openClaw": "---\nname: example-skill\ndescription: Describe when this skill should be used.\nuser-invocable: true\ndisable-model-invocation: false\n---\n\n# Purpose\n\nDescribe what this skill helps with.\n\n# Instructions\n\n1. Add actionable instruction one.\n2. Add actionable instruction two.\n", - "default": "---\nname: example-skill\ndescription: Describe when this skill should be used.\n---\n\n# Skill: example-skill\n\n## When to use\n\n- Describe trigger conditions.\n\n## Instructions\n\n1. Add actionable instruction one.\n2. Add actionable instruction two.\n" - } - }, - "McpSettings": { - "loading": "載入中...", - "summary": { - "missingCommand": "(缺少 command)", - "missingUrl": "(缺少 url)" - }, - "protocol": { - "stdio": "Stdio" - }, - "errors": { - "selectInstallProtocol": "請選擇安裝協議", - "fieldRequired": "{field} 為必填項", - "fieldNeedsBoolean": "{field} 需要 true 或 false", - "fieldNeedsNumber": "{field} 需要數字", - "fieldNeedsInteger": "{field} 需要整數", - "fieldInvalidJson": "{field} JSON 無效:{message}", - "fieldOutOfRange": "{field} 的值不在可選範圍內", - "jsonEmpty": "{name} 不能為空", - "jsonInvalid": "{name} 不是合法 JSON:{message}", - "jsonMustBeObject": "{name} 必須是 JSON 物件", - "specMustBeObject": "MCP 設定必須是 JSON 物件。", - "missingType": "MCP 設定缺少 type 欄位。請填寫 stdio、http(別名 streamable-http、streamableHttp)、sse 其中之一。", - "unsupportedType": "不支援的 MCP type:{type}。支援的類型:stdio、http(別名 streamable-http、streamableHttp)、sse。", - "codexEntryUnsupportedType": "Codex MCP 項目 {id} 的 type 不受支援:{type}。支援的類型:stdio、http(別名 streamable-http、streamableHttp)、sse。", - "unsupportedTransportType": "不支援的 transport 類型:{type}。支援的類型:http(別名 streamable-http、streamableHttp)、sse。", - "stdioCommandRequired": "stdio 類型的 MCP 必須填寫非空的 command 欄位。", - "remoteUrlRequired": "遠端 MCP 必須填寫非空的 url 欄位。", - "appsRequired": "請至少選擇一個目標 App。" - }, - "jsonNames": { - "localConfig": "MCP 配置", - "installConfig": "安裝配置" - }, - "toasts": { - "uninstalled": "已卸載 MCP", - "uninstallFailed": "卸載失敗:{message}", - "selectAtLeastOneApp": "請至少選擇一個目標應用", - "saveSuccess": "儲存成功", - "saveFailed": "儲存失敗:{message}", - "installed": "已安裝 {name}", - "installFailed": "安裝失敗:{message}", - "serverIdRequired": "Server ID 不能為空", - "serverIdExists": "Server ID \"{id}\" 已存在,請編輯現有項或更換名稱", - "created": "MCP 已建立" - }, - "installDialog": { - "title": "確認安裝 MCP", - "descriptionWithName": "將 {name} 安裝到本地配置。", - "description": "選擇安裝目標應用。", - "protocol": "協議", - "selectProtocol": "選擇協議", - "parameters": "配置參數", - "booleanPlaceholder": "請選擇 true/false", - "selectOneValue": "選擇一個值", - "targetApps": "目標應用" - }, - "actions": { - "cancel": "取消", - "confirmInstall": "確認安裝", - "installing": "安裝中", - "uninstall": "卸載", - "uninstalling": "卸載中", - "viewDetails": "查看詳情", - "save": "儲存", - "saving": "儲存中", - "install": "安裝", - "refresh": "重新整理", - "newMcp": "新建 MCP", - "create": "建立", - "creating": "建立中..." - }, - "tabs": { - "local": "本地 MCP", - "market": "MCP 市場" - }, - "local": { - "filterPlaceholder": "篩選本地 MCP...", - "loadFailed": "載入失敗:{message}", - "empty": "目前未檢測到本地 MCP。", - "description": "本地 MCP 配置可直接編輯並儲存。", - "enabledApps": "啟用應用", - "configJson": "MCP 配置(JSON)", - "draftTitle": "新建 MCP", - "draftDescription": "填寫 Server ID 與設定以建立本地 MCP 伺服器。", - "serverIdLabel": "Server ID", - "serverIdPlaceholder": "Server ID(例如:my-mcp)", - "typeHint": "支援類型:stdio、http(別名 streamable-http、streamableHttp)、sse。env 僅適用於 stdio;遠端 MCP 請透過 headers 欄位傳遞認證 token。", - "envOnRemoteWarning": "偵測到遠端 MCP 設定中包含 env 欄位。env 僅 stdio 類型使用,遠端 MCP 應透過 headers 攜帶認證資訊,env 欄位儲存時會被忽略。" - }, - "market": { - "selectMarketplace": "選擇市場", - "searchPlaceholder": "搜尋 MCP...", - "searchFailed": "搜尋失敗:{message}", - "loadingList": "載入 MCP 列表...", - "empty": "暫無 MCP 結果。", - "loadingDetail": "載入市場詳情...", - "detailLoadFailed": "載入詳情失敗:{message}", - "owner": "擁有者:{owner}", - "namespace": "命名空間:{namespace}", - "defaultInstallProtocol": "預設安裝協議", - "currentOptionParameterCount": "目前選項參數數:{count}", - "installConfigDescription": "安裝配置(JSON,可修改後安裝;修改後將覆蓋協議/參數表單)", - "selectLeftToView": "請選擇左側市場 MCP 查看詳情。" - }, - "badges": { - "verified": "已驗證", - "remote": "遠端", - "hasHomepage": "有首頁", - "uses": "{count} 次使用", - "deployed": "已部署", - "notDeployed": "未部署" - }, - "selectLeftMcp": "請選擇左側 MCP。" - }, - "AcpAgentSettings": { - "title": "Agent SDK管理", - "description": "統一管理 Agent 的連接SDK、啟用狀態、環境變數、配置管理與版本預檢資訊。", - "loadingAgents": "載入 Agent 列表中...", - "agentList": "Agent 列表", - "emptyNoAgent": "暫無可用 Agent。", - "configManagement": "配置管理", - "envVars": "環境變數", - "hostTools": { - "label": "由 Agent 自行處理檔案與指令", - "description": "codeg 不再代為提供檔案存取與終端指令,改由 Agent 在自己的行程中執行——只有這樣它自帶的沙箱與權限規則才會生效。同時會關閉向其他 Agent 委派,否則同樣的操作又會繞回 codeg 執行。codeg 本身不提供沙箱,因此請僅在 Agent 已設定沙箱時開啟。" - }, - "nativeJsonConfig": "原生 JSON 配置", - "modelHintDefault": "留空則使用系統預設模型。", - "generalConfigDescriptionClaude": "支援 API URL、API Key 與 Claude 模型快捷配置,並與原生 JSON 配置聯動。", - "generalConfigDescriptionDefault": "支援重要配置輸入(API URL、API Key、Model)和原生 JSON 配置管理。", - "multiAgent": { - "title": "多智慧體協同", - "description": "允許活躍的智慧體將子任務委派給其他智慧體。", - "enable": "啟用委派", - "enableHint": "關閉後,delegate_to_agent 工具會從智慧體的 MCP 工具清單中隱藏。", - "withheldByHostTools": "{agents} 不會拿到委派工具:它們單獨開啟了「由 Agent 自行處理檔案與命令」。", - "depthLimit": "最大委派深度", - "depthHint": "允許範圍:{min}–{max}。限制委派鏈(根 → 子 → 孫 …)的最大遞迴深度。", - "completedCacheLabel": "已完成結果快取(MB)", - "completedCacheHint": "執行中委派工作階段已完成子代理結果的記憶體快取,僅在該工作階段執行期間保留,工作階段結束後自動清除。超出此預算時優先從記憶體中捨棄最舊的結果(仍可在子代理自己的工作階段中檢視);0 表示不限(工作階段結束後仍會清除)。", - "save": "儲存", - "saving": "儲存中…", - "saved": "委派設定已儲存", - "saveFailed": "委派設定儲存失敗", - "loadFailed": "載入委派設定失敗:{detail}", - "tabGeneral": "一般", - "tabAgentDefaults": "子智慧體設定", - "agentDefaultsDescription": "多智慧體協同在為委派呼叫啟動子智慧體時使用這些覆寫項。下方選項透過即時探測取得,所選即所用。", - "probing": "正在載入該智慧體的可用設定項…", - "probeFailed": "載入設定項失敗:{detail}", - "retry": "重試", - "noConfigAvailable": "該智慧體沒有可設定項。", - "modeLabel": "模式", - "agentDefaultHint": "智慧體預設:{value}", - "defaultOptionLabel": "預設({value})" - }, - "actions": { - "dragSort": "拖拽排序", - "dragSortAgent": "拖拽排序 {name}", - "refreshCheck": "刷新檢測", - "refreshCheckAgent": "刷新檢測 {name}", - "clickEnable": "點擊啟用 {name}", - "clickDisable": "點擊停用 {name}", - "install": "安裝", - "upgrade": "升級", - "uninstall": "卸載", - "uninstalling": "卸載中...", - "saveEnvVars": "儲存環境變數", - "saving": "儲存中...", - "saveGrokConfig": "儲存 Grok 設定", - "saveCodexConfig": "儲存 Codex 配置", - "saveGeminiConfig": "儲存 Gemini 配置", - "saveOpenCodeConfig": "儲存 OpenCode 配置", - "saveOpenClawConfig": "儲存 OpenClaw 配置", - "saveConfigManagement": "儲存配置管理", - "saveCurrentProvider": "儲存目前 Provider", - "showApiKey": "顯示 API Key", - "hideApiKey": "隱藏 API Key", - "showKey": "顯示 Key", - "hideKey": "隱藏 Key", - "showToken": "顯示 Token", - "hideToken": "隱藏 Token", - "cancel": "取消", - "delete": "刪除", - "deleting": "刪除中...", - "confirmDelete": "確認刪除", - "confirmUninstall": "確認卸載", - "saveClineConfig": "儲存 Cline 配置", - "saveHermesConfig": "儲存 Hermes 配置", - "saveCodeBuddyConfig": "儲存 CodeBuddy 設定", - "saveKimiCodeConfig": "儲存 Kimi Code 設定", - "customInstall": "自訂安裝", - "saveKimiCodeRawConfig": "儲存 config.toml", - "saveDeepSeekConfig": "儲存 DeepSeek 設定", - "diagnose": "診斷" - }, - "status": { - "enabled": "啟用", - "disabled": "停用", - "unchecked": "未檢測", - "agentEnabledAria": "{name} 已啟用", - "agentEnabledSwitch": "{name} 啟用" - }, - "preflight": { - "count": "預檢項:{count}", - "notRun": "尚未執行檢測。" - }, - "grok": { - "configDescription": "在此設定 Grok。下方控制項——權限模式、推理強度、選用的自訂(自帶端點)模型與壓縮——會合併寫入 ~/.grok/config.toml,並保留你的其他鍵與註解。登入使用你的 XAI_API_KEY 或 `grok login`。其他鍵可在「進階」中編輯。", - "permissionModeLabel": "權限模式", - "permissionDefault": "每次詢問", - "permissionAcceptEdits": "自動批准編輯", - "permissionAuto": "智慧自動批准", - "permissionAlwaysApprove": "永遠允許", - "reasoningEffortLabel": "推理級別", - "effortLow": "低(較快)", - "effortMedium": "中(均衡)", - "effortHigh": "高", - "effortXhigh": "最高", - "optionDefault": "使用預設", - "authTitle": "驗證", - "authMode": "認證方式", - "authModeApiKey": "XAI API 金鑰", - "authModeApiKeyHint": "使用 xAI 主控台的 XAI_API_KEY 認證——適用於非互動/無頭執行。儲存在該智慧體的環境變數中。", - "authModeCustom": "自訂接口", - "authModeCustomHint": "使用自訂接口(BYO 端點):在下方定義一個帶有獨立 base URL 和 API 金鑰的自訂模型,它將成為 Grok 的預設模型。", - "subscriptionHint": "使用 `grok login` 登入(SuperGrok / X Premium+)。不會儲存 API 金鑰。", - "loginHint": "在終端機執行以下指令登入,然後重新開啟此設定:", - "commandCopied": "指令已複製到剪貼簿", - "copyCommand": "複製指令", - "authKeyConfigured": "已設定 XAI_API_KEY。", - "authKeyMissing": "未設定 XAI_API_KEY。", - "advancedToggle": "進階(原始 config.toml)", - "configTomlNative": "config.toml(原生)", - "configTomlHint": "按原樣整體寫入 ~/.grok/config.toml。非法 TOML 會被拒絕,絕不因筆誤截斷檔案。", - "configTomlPlaceholder": "# 上面控制項之外的鍵,例如\n# [mcp_servers.*]、[cli]、[permission] 規則。", - "customModelTitle": "自訂模型(自帶端點)", - "customModelHint": "讓 Grok 指向自訂或自架端點。codeg 會寫入按模型的 `[model.*]` 區塊並設為預設模型。清空模型 ID 即可移除。", - "customModelIdLabel": "模型 ID", - "customModelIdPlaceholder": "grok-4.5", - "customModelIdHint": "註冊為 `[model.*]` 區塊,並作為模型名稱傳送給 API;同時設為 `[models].default`。", - "customBaseUrlLabel": "Base URL", - "customBaseUrlPlaceholder": "https://api.x.ai/v1(預設)", - "customApiBackendLabel": "API 後端", - "backendResponses": "Responses", - "backendChatCompletions": "Chat Completions", - "backendMessages": "Messages(Anthropic)", - "customApiKeyLabel": "API Key", - "customApiKeyHint": "內聯儲存於 `[model.*].api_key`,僅作用於此端點。", - "customContextWindowLabel": "上下文視窗(tokens)", - "customContextWindowHint": "選填。用於自動壓縮計時;留空則使用端點預設值。", - "autoCompactLabel": "自動壓縮閾值(%)", - "autoCompactHint": "當上下文使用率達到此百分比時壓縮對話(Grok 預設 85)。寫入 `[session]`。" - }, - "cursor": { - "configDescription": "在此設定 Cursor。先選擇驗證方式——官網訂閱(瀏覽器登入)或用於無頭/伺服器的 Cursor API 金鑰——然後選擇模型並編輯 CLI 的權限規則與沙箱。codeg 會寫入 ~/.cursor/cli-config.json,與 cursor-agent CLI 共用。", - "authTitle": "驗證", - "authChecking": "檢測中…", - "authNotInstalled": "cursor-agent 未安裝", - "authLoggedIn": "已登入", - "authNotLoggedIn": "未登入", - "loginHint": "在終端機執行以下指令登入 Cursor 帳號(會開啟瀏覽器),完成後點重新整理:", - "apiKeyLabel": "Cursor API 金鑰", - "apiKeyPlaceholder": "在 cursor.com/dashboard 取得", - "apiKeyHint": "CURSOR_API_KEY —— Cursor Dashboard 的帳號金鑰,在無頭/伺服器環境下取代瀏覽器登入。不是第三方或 OpenAI 金鑰。", - "modelTitle": "預設模型", - "loadModels": "取得模型清單", - "modelsUnavailable": "模型清單不可用", - "modelHint": "會話啟動時透過 --model 傳給 CLI;保持預設則由 Cursor 自行選擇。", - "permissionsTitle": "權限與沙箱", - "permissionsDescription": "可視化編輯 CLI 權限規則(cli-config.json)。允許規則免確認執行;拒絕規則一律攔截。", - "permissionModeLabel": "權限模式", - "permissionModeDefault": "執行前詢問(預設)", - "permissionModeForce": "全部放行 Run Everything(--force)", - "permissionModeHint": "Run Everything 以 --force 啟動工作階段:除 deny 規則外的所有工具呼叫自動放行、不再跳出確認(組織政策可能將其降級為僅按 allow 規則放行)。對新工作階段生效。", - "optionDefault": "預設(未設定)", - "sandboxLabel": "沙箱", - "sandboxEnabled": "啟用", - "sandboxDisabled": "停用", - "allowRulesLabel": "允許規則", - "denyRulesLabel": "拒絕規則", - "addRule": "新增規則", - "rulesSyntaxHint": "規則語法:Shell(命令)、Read(路徑/萬用字元)、Write(路徑/萬用字元)、WebFetch(網域)、Mcp(伺服器:工具)——deny 規則始終優先。", - "saveConfig": "儲存設定", - "advancedToggle": "進階:原始 cli-config.json", - "advancedHint": "完整的 ~/.cursor/cli-config.json。此處儲存按原文寫入;上方結構化控制項則以合併方式寫入。", - "saveRawConfig": "儲存檔案", - "authMode": "認證方式", - "subscriptionHint": "使用 Cursor 帳號登入,使用 Cursor 的模型。", - "customApiKeyRequired": "需要填寫 Cursor API 金鑰。", - "authModeApiKey": "Cursor API 金鑰(無頭/伺服器)", - "authModeApiKeyHint": "使用 Cursor 官網 Dashboard 產生的帳號 API 金鑰進行驗證(適用於無頭/伺服器環境)。這是 Cursor 帳號金鑰,不是第三方/OpenAI 端點——cursor-agent 只會連線到 Cursor 自己的後端。若要使用 codex/OpenAI 相容端點,請改用 Codex 智慧體。", - "modelPickerPlaceholder": "搜尋模型…", - "modelNoMatch": "沒有相符的模型", - "modelsNeedAuth": "登入後載入模型清單。", - "modelDefaultBadge": "預設" - }, - "deepseek": { - "configManagement": "DeepSeek Harness 設定", - "configDescription": "端點與金鑰是 deepseek-acp 啟動時讀取的環境變數。模型與推理等級是工作階段層級的選擇器,在輸入框裡切換。", - "baseUrlLabel": "API 端點", - "baseUrlHint": "留空則使用官方端點。儲存後對新建的工作階段生效——正在進行的工作階段需要重新連線才會切換。", - "baseUrlInvalid": "請填寫完整的 http(s) 網址且不帶查詢參數,例如 https://api.deepseek.com", - "apiKeyLabel": "API 金鑰", - "apiKeyHint": "以 DEEPSEEK_API_KEY 傳給智慧體。環境變數的優先權高於憑證檔,因此若用終端機登入,這裡留空即可。" - }, - "codex": { - "configDescription": "支援 API URL、API Key、模型名稱、Reasoning Effort 快捷配置,並與 `auth.json` / `config.toml` 雙向聯動。", - "authMode": "認證方式", - "chatgptSubscription": "官網訂閱", - "chatgptSubscriptionHint": "使用 ChatGPT 官網訂閱登入,無需配置 API Key", - "apiKeyHint": "使用 API Key 連接 OpenAI 或相容的 API 服務", - "selectProvider": "選擇 Provider", - "modelName": "模型名稱", - "selectReasoningEffort": "選擇 Reasoning Effort", - "enableWebsocket": "啟用 WebSocket", - "enableWebsocketAria": "Codex Provider 啟用 WebSocket", - "enableSkills": "啟用 Skills", - "enableSkillsAria": "Codex 啟用 Skills", - "enableFast": "啟用 Fast", - "enableFastAria": "Codex 啟用 Fast 服務等級", - "sandboxGroupTitle": "沙箱與審批", - "sandboxGroupHint": "寫入全域 ~/.codex/config.toml,codex CLI 與 IDE 的工作階段同樣生效。這是執行緒預設值,只作用於 codex 自行發起的回合(/goal、/review、/compact);一般對話使用輸入框裡的審批預設。變更需重開工作階段才生效。", - "sandboxShadowedWarning": "config.toml 裡設定了 default_permissions,codex 會改走權限設定檔並完全忽略 sandbox_mode。刪除 default_permissions 後下面的選項才會生效。", - "sandboxPermissionsTableWarning": "config.toml 定義了 [permissions] 設定檔卻沒有 default_permissions,codex 會拒絕啟動。請在下方原始編輯器裡補上。", - "approvalPolicyLabel": "審批策略", - "approvalPolicyUnset": "未設定(codex 預設:依需求詢問)", - "approvalPolicy_on-request": "依需求詢問 — 由模型決定何時請求批准", - "approvalPolicy_untrusted": "僅信任唯讀 — 只有已知安全的唯讀指令免批准", - "approvalPolicy_never": "從不詢問 — 完全不彈審批", - "approvalPolicy_granular": "精細控制 — 依提示類型分別設定", - "approvalPolicyUntrustedAcpWarning": "ACP 轉接器只有三種審批預設,untrusted 無對應項,codeg 工作階段會退回「按需詢問」——此時由模型自行決定何時詢問,沙箱本就允許的命令不再詢問。請改用下方的沙箱模式收緊。", - "granularHint": "關閉表示該類請求會被自動拒絕,而不是彈給你確認。", - "granular_sandbox_approval": "Shell 指令越權申請", - "granular_rules": "Execpolicy 規則提示", - "granular_skill_approval": "技能指令碼執行提示", - "granular_request_permissions": "request_permissions 工具提示", - "granular_mcp_elicitations": "MCP elicitation 提示", - "sandboxModeLabel": "沙箱模式", - "sandboxModeUnset": "未設定(受信任的資料夾回落為可寫工作區)", - "sandboxMode_read-only": "唯讀", - "sandboxMode_workspace-write": "可寫工作區", - "sandboxMode_danger-full-access": "完全開放(無沙箱)", - "sandboxModeHint": "在 Windows 上,未開啟 codex 的實驗性 Windows 沙箱時,可寫工作區會被降級為唯讀。", - "sandboxModeSeedsPresetHint": "codeg 還會用它推導工作階段的初始審批預設,因此與審批策略不同,它對一般提問同樣生效。輸入框中選擇的預設仍會覆蓋它。", - "writableRootsLabel": "額外可寫目錄", - "writableRootsHint": "每行一個絕對路徑,作為工作目錄之外的額外可寫位置。", - "sandboxRootsRelativeError": "必須是絕對路徑 — codex 會把相對路徑解析到 ~/.codex 底下:{path}", - "networkAccessLabel": "允許網路存取", - "excludeTmpdirLabel": "從可寫目錄中排除 TMPDIR", - "excludeSlashTmpLabel": "從可寫目錄中排除 /tmp", - "authJsonNative": "auth.json(原生)", - "configTomlNative": "config.toml(原生)", - "loginButton": "使用 ChatGPT 登入", - "loginRequesting": "正在請求登入碼...", - "loginStep1": "在瀏覽器中打開以下連結:", - "loginStep2": "輸入以下代碼:", - "loginPolling": "等待授權中...", - "loginCancel": "取消", - "loginSuccess": "登入成功,配置已儲存!", - "loginFailed": "登入失敗:{message}", - "loginRetry": "重試", - "loginCodeCopied": "已複製代碼", - "loggedIn": "帳號已登入", - "loginRelogin": "重新登入 / 切換帳號", - "loginTimeout": "登入逾時,請重試", - "loginSaveFailed": "登入成功但配置儲存失敗" - }, - "gemini": { - "authConfig": "Gemini 認證配置", - "authConfigDescription": "對齊 Gemini CLI 認證文件,支援自訂、Google 登入、Gemini API Key、Vertex AI(ADC / 服務帳號 / API Key)。", - "authMode": "認證方式", - "selectAuthMode": "選擇認證方式", - "viewAuthDoc": "查看認證文件", - "mode": { - "custom": "自訂介面", - "loginGoogle": "Google 登入(OAuth)", - "vertexServiceAccount": "Vertex AI(服務帳號)" - }, - "hint": { - "custom": "填寫 API URL、API Key 和 Model,分別映射到 GOOGLE_GEMINI_BASE_URL / GEMINI_API_KEY / GEMINI_MODEL。", - "loginGoogle": "首次在終端執行 gemini 並完成 Google 登入;無需填寫 API Key。", - "geminiApiKey": "使用 Gemini API 時填寫 GEMINI_API_KEY。", - "vertexAdc": "使用 gcloud ADC,建議填寫 GOOGLE_CLOUD_PROJECT 與 GOOGLE_CLOUD_LOCATION。", - "vertexServiceAccount": "服務帳號 JSON 路徑寫入 GOOGLE_APPLICATION_CREDENTIALS。", - "vertexApiKey": "使用 Vertex AI API key 時填寫 GOOGLE_API_KEY。" - } - }, - "openCode": { - "configManagement": "OpenCode 配置管理", - "configDescription": "對齊 OpenCode `provider` 配置結構,支援多供應商管理,並與原生 JSON 檔案雙向聯動。", - "providerManagement": "Provider 管理", - "providerCount": "共 {count} 個", - "addProvider": "新增 Provider", - "emptyProvider": "還沒有自訂 Provider。點擊「新增自訂 Provider」建立。", - "providerEnabledState": "{providerId} 啟用狀態", - "selectProviderNpm": "選擇 provider.npm", - "modelManagement": "模型管理", - "modelCount": "共 {count} 個", - "modelDescription": "對齊 OpenCode `provider.models` 結構。目前支援 `name` / `id` 快速管理;其它進階欄位會保留,可在下方原生 JSON 中繼續編輯。", - "addModel": "新增模型", - "emptyModel": "暫無模型,輸入 model id 後點擊「新增模型」建立。", - "modelId": "模型 ID", - "modelName": "模型名稱", - "deleteModel": "刪除模型 {modelId}", - "nativeJsonConfig": "OpenCode 原生 JSON 配置", - "mainModel": "主模型", - "smallModel": "小模型", - "noMatchingModels": "沒有匹配的模型", - "connectProvider": "連接 Provider", - "connectedProviders": "已連接的 Provider", - "noConnectedProviders": "還沒有從目錄連接 Provider。", - "advancedProviderConfig": "自訂 Provider", - "customProviderConfigHint": "你自己定義的 OpenAI 相容端點——opencode.json 裡的一個 provider 設定區塊,API key 存在 auth.json。", - "addCustomProvider": "新增自訂 Provider", - "disconnect": "中斷連接", - "editConfig": "編輯", - "customBadge": "自訂", - "authKindApi": "API Key", - "authKindOauth": "OAuth", - "authKindNone": "無憑證", - "connect": { - "title": "連接 Provider", - "description": "從 models.dev 目錄選擇一個 Provider。憑證儲存到 OpenCode 的 auth.json 檔案。", - "pick": "Provider", - "search": "搜尋 Provider…", - "loading": "正在載入目錄…", - "catalogLabel": "models.dev 目錄", - "modelsAvailable": "{count} 個可用模型", - "getKey": "取得 API Key", - "oauthApiKeyNote": "此 Provider 也支援透過 opencode auth login 瀏覽器登入。瀏覽器登入即將推出——目前請貼上 API Key。", - "apiKey": "API Key", - "apiKeyHint": "儲存在 auth.json,絕不寫入 opencode.json。", - "baseUrlOptional": "Base URL 覆寫(選填)", - "providerId": "Provider ID", - "displayName": "顯示名稱", - "modelsList": "模型(每行一個)", - "modelsHint": "端點接受的模型 ID。", - "action": "連接", - "editTitle": "編輯 Provider", - "editDescription": "更新該 Provider 的 API Key 或 Base URL。", - "saveAction": "儲存" - }, - "customProvider": { - "title": "新增自訂 Provider", - "description": "定義一個 OpenAI 相容端點。API key 儲存到 auth.json;provider 設定區塊寫入 opencode.json。", - "action": "新增 Provider", - "idInCatalog": "{providerId} 是已知 Provider,請改用「連接 Provider」連接。" - }, - "refreshCatalog": "重新整理目錄", - "reasoningBadge": "推理", - "contextWindow": "上下文視窗", - "permissions": { - "title": "權限", - "description": "決定哪些操作直接執行、先徵求你的同意,還是被阻擋。寫入 opencode.json 的 permission 設定,點擊下方儲存後生效。", - "docsLink": "權限文件", - "unparsableConfig": "下方的原生 JSON 目前無法解析,視覺化編輯已暫停。修正 JSON 後即可繼續。", - "invalidBlock": "permission 設定的結構無法辨識。請在下方原生 JSON 中修改,或點擊「恢復預設」重來。", - "orderingUnsafe": "萬用規則寫在了具體工具之後,OpenCode 會把它一併套用到這些工具上——下方各列顯示的並非實際生效的規則。「修正順序」只把萬用規則移回各自範圍的最前面,不更動任何值。", - "orderingUnsafeManual": "有規則被後面更寬鬆的模式遮蔽,OpenCode 永遠不會套用它——下方各列顯示的並非實際生效的規則。兩個互相重疊的模式沒有唯一正確的順序,請在下方原生 JSON 中調整,把較寬鬆的寫在前面。", - "fixOrder": "修正順序", - "agentOverrides": "下列智慧代理個別覆寫了權限,且在最後套用,因此會蓋過此處的所有設定:{agents}。請在下方原生 JSON 中修改,或開啟「自動接受所有權限」將其清除。", - "legacyTools": "頂層的舊版 tools 設定停用了某個工具。OpenCode 會把它併入權限,因此會疊加在此處顯示的所有設定之上。請在下方原生 JSON 中修改,或開啟「自動接受所有權限」將其清除。", - "autoAcceptTitle": "自動接受所有權限", - "autoAcceptHint": "所有工具呼叫(shell 指令、檔案修改、存取專案外路徑)都不再詢問,直接執行。開啟後會以一條全域允許規則取代下方的逐工具設定,並清除各智慧代理個別的權限覆寫與舊版 tools 開關——否則它們仍會攔截。", - "globalLabel": "全域預設", - "globalHint": "即 * 規則:下方工具未個別覆寫時採用的動作。", - "actionUnset": "未設定(OpenCode 預設)", - "actionInherit": "沿用預設({action})", - "actionAllow": "允許", - "actionAsk": "詢問", - "actionDeny": "拒絕", - "perToolTitle": "逐工具權限", - "reset": "恢復預設", - "ruleCount": "細則 {count} 條", - "rulesToggle": "{tool} 的細緻規則", - "rulesHint": "依工具輸入比對,最後符合的規則優先,因此請把寬鬆的模式寫在前面。* 比對任意多個字元,? 精確比對一個字元,開頭的 ~ 會展開為主目錄。", - "noRules": "尚無細緻規則。", - "addRule": "新增規則", - "deleteRule": "刪除規則 {pattern}", - "duplicateRule": "此模式已存在。", - "blankRule": "規則必須有模式;如需刪除請點擊垃圾桶圖示。", - "customKeys": "檔案中的其他權限鍵", - "customKeyHint": "並非 OpenCode 內建工具,將原樣保留。", - "keys": { - "bash": "執行 shell 指令,依解析後的指令比對", - "edit": "所有檔案修改:edit、write 與 patch", - "read": "讀取檔案,依檔案路徑比對", - "external_directory": "存取專案工作目錄之外的路徑", - "task": "啟動子代理,依子代理類型比對", - "skill": "載入技能,依技能名稱比對", - "glob": "尋找檔案,依萬用字元模式比對", - "grep": "搜尋檔案內容,依模式比對", - "list": "列出目錄內容", - "webfetch": "擷取 URL", - "websearch": "網頁搜尋", - "lsp": "執行 LSP 查詢", - "todowrite": "寫入待辦清單", - "question": "向你提問", - "doom_loop": "同一呼叫以相同輸入重複 3 次時觸發" - } - } - }, - "openClaw": { - "gatewayConfig": "Gateway 配置", - "gatewayDescription": "配置 OpenClaw Gateway 連線資訊。支援本地或遠端 Gateway。", - "gatewayUrlHint": "留空則使用 openclaw 本地配置的 gateway.remote.url。", - "gatewayTokenPlaceholder": "Gateway 認證 Token", - "gatewayTokenHint": "建議使用 token-file 取代明文 Token,可透過 openclaw 命令列配置。", - "sessionKeyHint": "可選。指定 Gateway Session Key,留空則自動分配隔離會話。" - }, - "hermes": { - "configManagement": "Hermes 配置", - "configDescription": "Hermes 在 ~/.hermes/.env 中管理自己的憑證,在 ~/.hermes/config.yaml 中管理設定。選擇一個供應商,然後設定 API 金鑰與模型——codeg 會替你寫入這兩個檔案。", - "providerLabel": "供應商", - "providerHint": "供應商決定 Hermes 使用哪個 API 金鑰變數與 model.provider。OAuth 供應商透過下方的終端機設定進行設定。", - "groupApiKey": "API 金鑰供應商", - "groupOauth": "OAuth 供應商", - "groupAws": "AWS", - "apiKeyHint": "儲存到 ~/.hermes/.env。它絕不會被注入行程——Hermes 會從自己的設定中讀取它。", - "modelName": "模型", - "oauthHint": "此供應商使用 OAuth。請執行下方的設定流程,在終端機中完成驗證。", - "awsHint": "Bedrock 使用你的 AWS 憑證(環境變數或共用設定)。請在上方填寫模型 ID,並在系統環境中設定 AWS 存取權限。", - "unsupportedProvider": "此供應商無法透過結構化欄位編輯。請使用下方的 config.yaml 原始編輯器或終端機引導設定。", - "setupTitle": "自管理設定", - "setupHint": "Hermes 的互動式設定需要終端機。可在下方啟動,或複製指令自行執行。", - "runSetup": "執行 Hermes 設定", - "configureModel": "設定模型", - "openConfigFolder": "開啟 ~/.hermes", - "copyCommand": "複製指令", - "commandCopied": "指令已複製到剪貼簿", - "advancedTitle": "進階:編輯 config.yaml", - "rawConfigHint": "直接編輯 ~/.hermes/config.yaml。在此儲存將原樣覆寫該檔案。", - "saveRawConfig": "儲存 config.yaml" - }, - "codebuddy": { - "configManagement": "CodeBuddy 設定", - "configDescription": "CodeBuddy 使用 API Key 進行驗證。中國版還必須將環境設為「中國版(internal)」;iOA 版使用「iOA」;海外版則不設定。", - "apiKeyLabel": "API Key", - "apiKeyHint": "將作為此智能體的 CODEBUDDY_API_KEY 儲存。也可以在終端機用 CodeBuddy CLI 登入。", - "apiKeyHintSelfHosted": "將作為此智能體的 CODEBUDDY_API_KEY 儲存。請使用你的私有化部署簽發的金鑰。", - "environmentLabel": "環境", - "environmentHint": "設定 CODEBUDDY_INTERNET_ENVIRONMENT。中國大陸必須使用「中國版(internal)」;海外版則不設定。", - "envOverseas": "海外版(預設)", - "envChina": "中國版(internal)", - "envIoa": "iOA", - "envSelfHosted": "私有化部署", - "baseUrlLabel": "私有化部署位址", - "baseUrlPlaceholder": "https://codebuddy.your-company.com", - "baseUrlHint": "儲存為 CODEBUDDY_BASE_URL,將 CodeBuddy 指向你的私有端點。私有化部署不設定網路環境(CODEBUDDY_INTERNET_ENVIRONMENT)。", - "baseUrlInvalid": "請輸入合法的 http(s) 位址。", - "loginHint": "沒有 API Key?也可以在終端機執行「codebuddy」用騰訊雲帳號登入。" - }, - "kimiCode": { - "configManagement": "Kimi Code 設定", - "configDescription": "`kimi acp` 只認已儲存的登入權杖,所以 codeg 會在 ~/.kimi-code/config.toml 寫入受管供應商,並在本機植入一個門控權杖——推論仍然走你自己的 Key。", - "statusUnconfigured": "尚未設定", - "statusDirty": "有未儲存的變更", - "summaryLabel": "生效設定", - "gateReadyApiKey": "API Key 已寫入 config.toml", - "gateReadyLogin": "已透過 Kimi 帳號登入", - "revealConfig": "在資料夾中顯示", - "envOverrideWarning": "偵測到 {keys},其優先權高於 config.toml。在此儲存會自動清除它。", - "authModeLabel": "驗證方式", - "authModeApiKey": "API Key", - "authModeLogin": "Kimi 帳號登入(訂閱)", - "authModeApiKeyHint": "在 config.toml 寫入受管供應商,並植入門控權杖以便工作階段能夠開啟。", - "loginHint": "在終端機執行 `kimi login`,用 Kimi 訂閱帳號登入。codeg 不儲存任何憑證,沿用 Kimi 自己的登入。在此儲存會移除 codeg 的 API Key 門控權杖。", - "credentialTitle": "憑證", - "interfaceTypeLabel": "供應商類型", - "interfaceTypeHint": "Kimi 使用的供應商協定(config.toml 的 `type`)。Moonshot / platform.kimi.com 的 Key 請選「Kimi / Moonshot」。", - "endpointLabel": "接入點", - "endpointCustom": "自訂(OpenAI 相容)", - "endpointHint": "國際 = api.moonshot.ai;中國(platform.kimi.com 的 Key)= api.moonshot.cn。自訂可指向任意 OpenAI 相容端點。", - "regionInternational": "國際(api.moonshot.ai)", - "regionChina": "中國(api.moonshot.cn)", - "baseUrlLabel": "Base URL", - "baseUrlHint": "留空則使用供應商 SDK 預設值。", - "apiKeyLabel": "API Key", - "apiKeyHint": "寫入 ~/.kimi-code/config.toml 並用於推論。來自 platform.kimi.com 或 platform.kimi.ai。", - "vertexProjectLabel": "GCP 專案(GOOGLE_CLOUD_PROJECT)", - "vertexLocationLabel": "GCP 區域(GOOGLE_CLOUD_LOCATION)", - "vertexHint": "Vertex AI 使用 Google 應用程式預設憑證——執行 `gcloud auth application-default login`(不需 API Key)。", - "modelTitle": "模型", - "modelLabel": "模型", - "modelHint": "寫入 config.toml 的模型 id。點「測試並取得模型」可查看你的 Key 實際能存取哪些模型。", - "maxContextLabel": "最大上下文長度", - "maxContextHint": "Kimi 的設定 schema 要求必填:缺少會讓 Kimi 丟棄整個模型區塊,導致每次對話都沒有回覆。預設 262144。", - "fetchModels": "測試並取得模型", - "fetchModelsOk": "Key 可用——共 {count} 個模型", - "fetchModelsEmpty": "Key 可用,但未回傳任何模型", - "fetchModelsFailed": "測試失敗", - "fetchModelsNeedsKey": "請先填寫 API Key 和接入點", - "modelNotInList": "該模型不在你的 Key 可存取清單中,Kimi 會回報「模型不存在」。", - "reasoningTitle": "推理", - "reasoningEnableLabel": "啟用", - "reasoningDescription": "只有當模型宣告了推理能力,Kimi 才會在輸入框顯示「Thinking」選擇器,所以這裡由 codeg 寫入該宣告。對新建工作階段生效。", - "effortsLabel": "可選檔位", - "effortsHint": "這些會成為輸入框「Thinking」選擇器裡的檔位。Kimi 會把檔位原樣轉傳給供應商,請選你的模型能接受的值。", - "effortsEmptyHint": "一個檔位都不選時,輸入框只會退化成 Off / On 兩檔開關。", - "effortsCustomPlaceholder": "新增其他檔位", - "effortsAdd": "新增", - "defaultEffortLabel": "預設檔位", - "defaultEffortAuto": "由 Kimi 決定", - "alwaysThinkingLabel": "模型始終推理——從選擇器中移除 Off 檔", - "fixErrorsFirst": "請先修正標紅的欄位", - "errorModelRequired": "模型為必填欄位", - "errorMaxContextRequired": "最大上下文長度為必填欄位", - "errorMaxContextInvalid": "必須是正整數", - "errorApiKeyRequired": "API Key 為必填欄位", - "errorApiKeyInvalid": "API Key 不能包含換行", - "errorBaseUrlRequired": "Base URL 為必填欄位", - "errorBaseUrlInvalid": "必須以 http:// 或 https:// 開頭", - "errorVertexProjectRequired": "GCP 專案為必填欄位", - "errorDefaultEffortUnlisted": "必須是上面已選取的檔位之一", - "advancedTitle": "進階", - "authTypeLabel": "憑證寫入位置", - "authTypeApiKey": "內聯 api_key", - "authTypeEnv": "供應商 env 子表", - "authTypeHint": "API Key 在 config.toml 中的寫入位置。", - "rawEditorLabel": "直接編輯 config.toml", - "rawEditorWarning": "在此儲存會按原文覆寫整個檔案,取代掉上方的結構化設定。", - "rawEditorPlaceholder": "[providers.codeg]\ntype = \"kimi\"\nbase_url = \"https://api.moonshot.cn/v1\"\napi_key = \"sk-...\"" - }, - "authModeOfficialSubscription": "官網訂閱", - "authModeCustomEndpoint": "自定義介面", - "authModeCustomEndpointHint": "手動配置 API URL 和 API Key 連接自定義介面。", - "authModeModelProvider": "模型供應商", - "modelProvider": "模型供應商", - "modelProviderHint": "使用已配置的模型供應商的 API URL、API Key 和模型。", - "selectModelProvider": "選擇模型供應商", - "noModelProviderAvailable": "該代理未配置模型供應商。請前往模型供應商設定添加。", - "claude": { - "authMode": "認證方式", - "officialSubscription": "官方訂閱", - "officialSubscriptionHint": "使用 Anthropic 官方訂閱,無需 API Key。", - "mainModel": "主模型", - "reasoningModel": "推理模型(thinking)", - "haikuDefaultModel": "Haiku 預設模型", - "sonnetDefaultModel": "Sonnet 預設模型", - "opusDefaultModel": "Opus 預設模型", - "customModelOption": "自訂模型 ID", - "customModelOptionName": "自訂模型名稱", - "customModelOptionDescription": "自訂模型描述", - "customModelOptionHint": "在 Claude 模型選擇器中新增一個自訂項目(例如透過自訂閘道/代理提供的模型)。名稱與描述為選填的顯示資訊。", - "effortLevel": "推理等級", - "effortLevelDefault": "預設等級", - "effortLevel_low": "低", - "effortLevel_medium": "中", - "effortLevel_high": "高", - "effortLevel_xhigh": "超高", - "sendAttributionHeader": "向介面傳送歸屬/計費識別碼", - "sendAttributionHeaderAria": "向介面傳送 Claude Code 歸屬/計費識別碼", - "disableNonessentialTraffic": "停用遙測或多餘的網路請求", - "disableNonessentialTrafficAria": "停用 Claude Code 遙測或多餘的網路請求" - }, - "dialogs": { - "confirmDeleteProvider": "確認刪除 Provider {providerId}?", - "confirmDeleteProviderDescription": "將同步更新 OpenCode 配置與認證 JSON 檔案,刪除後不可恢復。", - "confirmUninstall": "確認卸載 {name}?", - "confirmUninstallDescription": "這會移除本地安裝版本,之後可隨時重新安裝。", - "customInstallTitle": "自訂安裝 {name}", - "customInstallDescription": "輸入要安裝的版本號。將重新安裝並替換目前已安裝的版本。", - "customInstallVersionLabel": "版本號", - "customInstallInvalid": "請輸入有效的版本號,例如 1.2.3。", - "customInstallSubmit": "安裝" - }, - "errors": { - "windowsFileLocked": "{name} 的程式檔案正被執行中的工作階段佔用,Windows 下無法替換。請先關閉所有 {name} 工作階段後重試。", - "nativeJsonMustBeObject": "原生 JSON 配置必須是物件", - "nativeJsonInvalid": "原生 JSON 配置格式錯誤:{message}", - "openCodeAuthMustBeObject": "OpenCode auth.json 必須是 JSON 物件", - "openCodeAuthInvalid": "OpenCode auth.json 格式錯誤:{message}", - "authMustBeObject": "auth.json 必須是 JSON 物件", - "authInvalid": "auth.json 格式錯誤:{message}", - "providerIdPattern": "Provider ID 僅支援字母、數字、底線、點與中劃線", - "providerExists": "Provider {providerId} 已存在", - "modelIdPattern": "模型 ID 僅支援字母、數字、底線、點、冒號與中劃線", - "modelExists": "Model {modelId} 已存在" - }, - "warnings": { - "nativeJsonRecoveredStructured": "原生 JSON 配置格式無效,已重置為結構化配置", - "nativeJsonRecoveredOpenCode": "原生 JSON 配置格式無效,已重置為 OpenCode 結構化配置", - "openCodeAuthRecovered": "OpenCode auth.json 格式無效,已重置為預設配置", - "authRecoveredStructured": "auth.json 格式無效,已重置為結構化配置" - }, - "toasts": { - "agentActionCompleted": "{name}{action}完成", - "agentActionFailed": "{name}{action}失敗", - "localVersion": "本地版本:{version}", - "installCompletedVersionLater": "安裝完成,版本將在下一次檢測時更新", - "uninstallCompleted": "{name}卸載完成", - "uninstallFailed": "{name}卸載失敗", - "localVersionRemoved": "本地版本已移除", - "saveAgentOrderFailed": "儲存 Agent 排序失敗", - "saveAgentSwitchFailed": "儲存 Agent 開關失敗", - "saveEnvFailed": "儲存環境變數失敗", - "grokSaved": "Grok 設定已儲存", - "saveGrokNativeFailed": "儲存 Grok 原生設定失敗", - "saveGrokApiKeyFailed": "設定已儲存,但 API Key 未能儲存", - "cursorSaved": "Cursor 設定已儲存", - "saveCursorConfigFailed": "儲存 Cursor 設定失敗", - "codexSaved": "Codex 配置已儲存", - "saveCodexNativeFailed": "儲存 Codex 原生配置失敗", - "geminiSaved": "Gemini 配置已儲存", - "saveGeminiFailed": "儲存 Gemini 配置失敗", - "providerDeleted": "Provider {providerId} 已刪除", - "providerDeleteFailed": "刪除 Provider {providerId} 失敗", - "providerSaved": "Provider {providerId} 儲存成功", - "saveProviderFailed": "儲存 Provider {providerId} 失敗", - "openCodeConfigSynced": "OpenCode 配置與認證 JSON 已同步儲存。", - "openCodeSaved": "OpenCode 配置已儲存", - "saveOpenCodeFailed": "儲存 OpenCode 配置失敗", - "openClawSaved": "OpenClaw 配置已儲存", - "saveOpenClawFailed": "儲存 OpenClaw 配置失敗", - "configSaved": "配置已儲存", - "configSavedHint": "已有會話需要重新打開才能生效", - "saveConfigManagementFailed": "儲存配置管理失敗", - "clineSaved": "Cline 配置已儲存", - "saveClineFailed": "儲存 Cline 配置失敗", - "hermesSaved": "Hermes 配置已儲存", - "saveHermesFailed": "儲存 Hermes 配置失敗", - "codeBuddySaved": "CodeBuddy 設定已儲存", - "saveCodeBuddyFailed": "儲存 CodeBuddy 設定失敗", - "kimiCodeSaved": "Kimi Code 設定已儲存", - "saveKimiCodeFailed": "儲存 Kimi Code 設定失敗", - "deepseekSaved": "DeepSeek 設定已儲存", - "saveDeepSeekFailed": "儲存 DeepSeek 設定失敗", - "modelProviderRequired": "請先選擇一個模型供應商再儲存。", - "affectedRunningSessions": "{count} 個進行中的工作階段需重新連線以套用變更", - "providerConnected": "已連接 {providerId}", - "connectFailed": "連接 {providerId} 失敗", - "providerDisconnected": "已中斷 {providerId}", - "disconnectFailed": "中斷 {providerId} 失敗", - "catalogRefreshed": "目錄已重新整理——{count} 個 provider", - "catalogRefreshFailed": "重新整理目錄失敗", - "piSaved": "Pi 設定已儲存", - "savePiFailed": "儲存 Pi 設定失敗", - "piRuntimeSaved": "Pi 執行環境已儲存", - "savePiRuntimeFailed": "儲存 Pi 執行環境失敗", - "piBinaryInstalled": "pi 已安裝", - "piBinaryInstallFailed": "pi 安裝失敗", - "piBinaryUninstalled": "pi 已解除安裝", - "piBinaryUninstallFailed": "pi 解除安裝失敗", - "savePiTrustFailed": "儲存工作區信任失敗" - }, - "version": { - "statusLabel": "版本狀態", - "notInstalled": "未安裝", - "remoteLocal": "遠端:{remoteVersion} · 本地:{localVersion}", - "localOnly": "本機:{localVersion}", - "localInstalled": "{versionText}。已安裝。", - "platformUnsupported": "{versionText}。目前平台不支援該 Agent。", - "uvxNotReady": "{versionText}。uv 執行階段未安裝——請在下方 uv 預檢項中安裝後再使用該 Agent。", - "clickInstall": "{versionText}。請點擊右側安裝。", - "localUnrecognized": "{versionText}。本地版本無法識別,可嘗試升級覆蓋安裝。", - "upgradeAvailable": "{versionText}。發現可升級版本。", - "remoteUnavailable": "{versionText}。遠端版本暫不可用。", - "latest": "{versionText}。已是最新版本。" - }, - "adapter": { - "label": "ACP 轉接器", - "badge": "ACP 轉接器", - "badgeHint": "Codeg 為此智能體安裝的是 ACP 轉接器套件,而不是廠商 CLI —— 兩者各自獨立,設定共用。", - "learnMore": "了解詳情", - "missingWithNative": "已偵測到你本機的 {nativeLabel}:{nativePath}。Codeg 透過 ACP 協定驅動智能體,而該 CLI 本身不支援 ACP,所以 Codeg 需要獨立的轉接器套件 {adapterPackage}(由 Agent Client Protocol 專案維護,最初由 Zed 團隊發起)。它自帶執行環境,不會修改或取代你的 {nativeCmd} 指令,讀取的也是同一個 {configDir} —— 既有的登入與設定可直接沿用。點擊下方安裝即可。", - "missing": "Codeg 透過 ACP 協定驅動智能體,而 {nativeLabel} 本身不支援 ACP,所以 Codeg 需要獨立的轉接器套件 {adapterPackage}(由 Agent Client Protocol 專案維護,最初由 Zed 團隊發起)。它自帶執行環境,因此不必先安裝 {nativeCmd} CLI;若你已經安裝,兩者可以並存,並共用 {configDir} 中的登入與設定。點擊下方安裝即可。", - "readyWithNative": "轉接器 {adapterCmd} 已安裝 —— Codeg 啟動的是它,而不是你本機的 {nativeCmd}({nativePath})。兩者是各自獨立的套件,可以並存,且都讀取 {configDir},登入與設定共用。", - "ready": "轉接器 {adapterCmd} 已安裝 —— Codeg 啟動的就是它。它自帶執行環境,所以不需要另外安裝 {nativeLabel};即使日後你安裝了,兩者也能並存並共用 {configDir}。" - }, - "cline": { - "configDescription": "配置 Cline API 提供商和憑證。設定將儲存到 ~/.cline/data/。" - }, - "opencodePlugins": { - "title": "OpenCode 外掛", - "declared": "已宣告的外掛", - "noPlugins": "opencode.json 中未宣告任何外掛", - "status": { - "installed": "已安裝", - "missing": "未安裝" - }, - "installAll": "安裝全部缺失外掛", - "pinVersions": "固定 @latest 版本", - "install": "安裝", - "uninstall": "解除安裝", - "refresh": "重新整理", - "success": "所有外掛安裝成功", - "failed": "外掛操作失敗" - }, - "pi": { - "configManagement": "Pi 設定", - "configDescription": "Pi 透過模型提供方的 API Key 驗證。Key 寫入 ~/.pi/agent/auth.json,模型選擇寫入 settings.json。", - "providerLabel": "提供方", - "modelLabel": "模型", - "thinkingLabel": "思考", - "thinking": { - "off": "關閉", - "low": "低", - "medium": "中", - "high": "高", - "minimal": "極低", - "xhigh": "極高" - }, - "apiKeyLabel": "API Key", - "apiKeyHint": "為所選提供方寫入 ~/.pi/agent/auth.json。", - "apiKeySetPlaceholder": "•••••• (已儲存,留空則保持不變)", - "saveConfig": "儲存 Pi 設定", - "providerModelRequired": "提供方與模型為必填", - "runtimeTitle": "執行環境", - "runtimeDescription": "選擇執行哪個 pi。使用預設,或指向你自己的 pi 建置。", - "modeDefault": "預設 pi", - "modeDefaultHint": "使用內建 pi-acp 轉接器拉起 PATH 上的 pi。 安裝 pi:npm install -g @earendil-works/pi-coding-agent", - "modeCustom": "自訂 pi", - "modeCustomHint": "執行你自己的 pi 建置、安裝或包裝腳本。", - "commandLabel": "pi 命令或路徑", - "commandHint": "絕對路徑、PATH 上的命令名,或包裝腳本(如 monorepo 的 ./pi-test.sh)。", - "commandNotFound": "找不到命令", - "validate": "驗證", - "advanced": "進階", - "configDirLabel": "設定目錄 (PI_CODING_AGENT_DIR)", - "sessionDirLabel": "工作階段目錄 (PI_CODING_AGENT_SESSION_DIR)", - "flagsHint": "pi-acp 不會轉發自訂 pi 參數(--approve、-e 等)——用腳本包裝 pi 並將命令指向它。", - "customIncomplete": "請輸入 pi 命令以儲存", - "saveRuntime": "儲存執行環境", - "providerPlaceholder": "選擇供應方", - "customProvider": "自訂供應方…", - "providerIdLabel": "供應方 ID", - "apiProtocolLabel": "API 協定", - "baseUrlLabel": "介接位址(Base URL)", - "customProviderHint": "在 ~/.pi/agent/models.json 中依你的介接位址定義一個供應方。多數自架或代理服務使用 openai-completions。", - "baseUrlRequired": "介接位址(Base URL)為必填", - "binaryTitle": "pi 二進位 (pi-coding-agent)", - "binaryDescription": "pi-acp 會執行此 pi 二進位。可在此安裝,或在下方指向你自己的組建。", - "binaryInstalled": "已安裝", - "binaryMissing": "未安裝", - "binaryChecking": "偵測中…", - "installBinary": "安裝 pi", - "installing": "安裝中…", - "recheck": "重新偵測", - "configDirSkillsNote": "設定自訂組態目錄後,設定頁中管理的技能、專家與辦公工具將不會套用至該 pi;請直接在該目錄中管理其技能。", - "projectTrustTitle": "專案信任", - "projectTrustDescription": "你允許 pi 從中載入專案檔案的目錄。被信任的目錄會讓該儲存庫的 .pi/extensions 在 pi 啟動時執行程式碼,且對其下所有子目錄同樣生效,你在終端機執行 pi 時也會沿用。", - "projectTrustLoading": "載入中…", - "projectTrustEmpty": "尚未對任何目錄做出決定。", - "projectTrustTrusted": "已信任", - "projectTrustDenied": "不信任", - "projectTrustRevoke": "撤銷", - "reasoningTitle": "推理", - "reasoningEnableLabel": "啟用", - "reasoningDescription": "只有模型宣告了推理能力,pi 才會傳送推理強度——未宣告的模型所有等級都會被壓回 Off,所以輸入框裡的選擇器一改就彈回。這裡寫入 models.json 中該模型的項目。", - "levelsLabel": "可選等級", - "levelsHint": "這些會成為輸入框推理選擇器裡的等級。請選你的端點能接受的值;不在這裡的等級 pi 一律拒絕。", - "levelsEmptyError": "至少選一個等級——一個都不選時 pi 只會退回 Off。", - "wireValuesTitle": "進階:送給供應商的值", - "wireValuesHint": "留空表示原樣送出等級名稱。端點需要別的寫法時才填——Google 系需要 LOW / HIGH。", - "defaultLevelUnlisted": "該等級不在上面的可選清單裡——pi 會把它壓下來。" - }, - "addCustomAgent": "新增自訂智慧體", - "addCustomAgentHint": "接入任何相容 ACP 的智慧體。可從公開 ACP 註冊表中選擇,或直接貼上其註冊表資訊。", - "customAgentFromRegistry": "ACP 註冊表", - "customAgentManual": "手動填寫", - "customAgentSearchPlaceholder": "搜尋智慧體…", - "customAgentLoadingCatalog": "正在載入 ACP 註冊表…", - "customAgentRetry": "重試", - "customAgentNoResults": "沒有符合的智慧體", - "customAgentAdd": "新增", - "customAgentAlreadyAdded": "已新增", - "customAgentUnsupportedPlatform": "目前平台沒有可用的建置", - "customAgentAdded": "已新增 {name}", - "customAgentIdLabel": "註冊表 ID", - "customAgentNameLabel": "顯示名稱", - "customAgentVersionLabel": "版本", - "customAgentSpecLabel": "散發資訊(JSON)", - "customAgentSpecHint": "與 ACP 註冊表 distribution 物件同構:支援 npx、uvx、binary 三種通道,也可整筆貼上註冊表條目。npx/uvx 的 cmd 為套件安裝的可執行命令名稱,預設按套件名稱推導,與套件名稱不同時需填寫。binary 按平台鍵區分(本機為 {platform}),cmd 為壓縮檔內啟動路徑,sha256 可選用於驗證下載。", - "customAgentTemplateLabel": "範本", - "customAgentKindLabel": "啟動方式", - "customAgentInvalidJson": "不是合法的 JSON", - "customAgentNoDistribution": "找不到 npx、uvx 或 binary 散發方式", - "customAgentCancel": "取消", - "customAgentSave": "新增智慧體", - "customAgentSaveChanges": "儲存變更", - "customAgentEdit": "編輯智慧體", - "customAgentEditHint": "修改名稱、圖示、分發資訊與技能宣告;智慧體 ID 不可修改。", - "customAgentEditNotFound": "找不到自訂智慧體 {id}", - "customAgentSaved": "已儲存 {name}", - "customAgentVersionProbeLabel": "版本查詢命令(可選)", - "customAgentVersionProbeHint": "查詢本機安裝版本的命令;留空時預設執行智慧體命令加 --version。", - "customAgentRemove": "移除智慧體", - "customAgentRemoveHint": "刪除該智慧體定義。既有工作階段的歷史會保留,只是該智慧體無法再啟動。", - "customAgentIconLabel": "圖示(選填)", - "customAgentIconUpload": "上傳", - "customAgentIconReplace": "更換", - "customAgentIconClear": "移除圖示", - "customAgentIconHint": "隨智慧體一併儲存,離線也能顯示。未上傳則使用彩色首字母。", - "customAgentSkillsLabel": "Skills(共享 .agents/skills)", - "customAgentSkillsHint": "聲明該智能體會讀取共享的 .agents/skills 目錄(全域與專案級),並將其加入所有技能矩陣。連結到共享目錄的技能對讀取該目錄的其他智能體同樣可見。", - "customAgentSkillsDirLabel": "專屬技能目錄", - "customAgentSkillsDirHint": "該智慧體自身載入技能的目錄絕對路徑 —— 可與共享目錄並存,也可單獨使用。~ 會展開為主目錄;連結技能時優先放入此目錄。", - "customAgentMcpLabel": "MCP 支援", - "customAgentMcpHint": "工作階段建立時向該智慧體注入 codeg 內建的 codeg-mcp 伴生行程 —— 委派、即時回饋與任務工具都依賴它。若該智慧體不支援 MCP、連線時報錯,請關閉此項;設定會在下次連線時生效。", - "customAgentIconNotAnImage": "請選擇圖片檔案。", - "customAgentIconTooLarge": "圖示需小於 {limit} KB。", - "customAgentIconReadFailed": "無法讀取該圖片。", - "customAgentRemoveConfirm": "確定移除 {name}?既有會話會保留,但該智慧體將無法再啟動。", - "customAgentRemoveWithData": "同時刪除已記錄的會話歷史", - "customAgentRemoved": "已移除 {name}", - "customAgentBadge": "自訂", - "customAgentNotLaunchable": "該智慧體在此環境無法啟動:{reason}" - }, - "SettingsPages": { - "agentsLoading": "載入 Agent 設定中...", - "skillPacksLoading": "正在載入技能包…" - }, - "GeneralSettings": { - "loading": "載入中...", - "sectionTitle": "一般", - "sectionDescription": "集中管理預設終端機、渲染加速以及多智能體協同等通用偏好。", - "terminalTitle": "預設終端", - "terminalDescription": "選擇從終端列或檔案樹開啟新終端分頁時使用的 Shell。智慧代理請求 codeg 代為執行整條命令列時也會使用它。", - "terminalSystemDefault": "系統預設", - "terminalPowerShell7": "PowerShell 7 (pwsh)", - "terminalWindowsPowerShell": "Windows PowerShell", - "terminalCmd": "命令提示字元 (cmd)", - "terminalSaveFailed": "儲存終端設定失敗:{message}", - "terminalShellCustom": "自訂路徑", - "terminalShellCustomPath": "Shell 路徑", - "terminalShellCustomPlaceholder": "/usr/local/bin/fish", - "terminalShellCustomSave": "儲存", - "terminalShellCustomHint": "支援絕對路徑,或 PATH 中可解析的命令名。", - "terminalShellNotInstalled": "未安裝", - "terminalShellNotFoundWarning": "目前主機上不存在此路徑。", - "terminalCurrentShell": "目前使用:{path}", - "renderingDescription": "若應用出現黑屏或渲染異常(常見於 AMD 顯示卡或部分 Intel 內顯),可關閉硬體加速。僅 Windows 桌面端生效。", - "disableHardwareAcceleration": "停用硬體加速", - "renderingSaveFailed": "渲染設定儲存失敗:{message}", - "restartRequired": "已儲存,需重新啟動應用程式才會生效。", - "restartNow": "立即重新啟動", - "restartFailed": "重新啟動失敗:{message}", - "loadFailed": "載入失敗:{message}" - }, - "LoginPage": { - "documentTitle": "登入 - codeg", - "brand": "Codeg", - "subtitle": "輸入存取 Token 以連接到桌面端", - "tokenPlaceholder": "Access Token", - "connect": "連接", - "connecting": "連接中...", - "helpText": "Token 可在桌面端 設定 → Web 服務 中取得", - "invalidToken": "Token 無效,請檢查後重試", - "connectionFailed": "連接失敗 (HTTP {status})", - "networkError": "無法連接到伺服器" - }, - "CommitPage": { - "title": "提交程式碼", - "invalidFolderId": "無效的 folderId", - "loadingRepo": "正在載入倉庫..." - }, - "MergePage": { - "title": "解決衝突", - "invalidFolderId": "無效的 folderId", - "loadingRepo": "正在載入倉庫...", - "localVersion": "本地(我們的)", - "result": "結果", - "remoteVersion": "遠端(他們的)", - "acceptLocal": "採用本地", - "acceptRemote": "採用遠端", - "markResolved": "標記已解決", - "abortMerge": "中止", - "completeMerge": "完成合併", - "unresolvedConflicts": "檔案中仍有未解決的衝突標記", - "fileResolved": "檔案已解決", - "allResolved": "所有衝突已解決", - "conflictFiles": "衝突檔案", - "loadingFile": "正在載入檔案...", - "preparingMerge": "正在準備合併...", - "selectFile": "選擇一個檔案進行解決", - "noConflicts": "無衝突檔案", - "skipFile": "跳過", - "abortSuccess": "操作已中止", - "applyAllNonConflicting": "套用所有非衝突變更", - "applyLeftNonConflicting": "套用本地", - "applyRightNonConflicting": "套用遠端" - }, - "ImportSessions": { - "title": "匯入本機工作階段", - "scanningTitle": "正在掃描本機智慧代理工作階段…", - "scanningHint": "正在遍歷各智慧代理的本機工作階段儲存,歷史較多時可能需要一些時間。已匯入的工作階段會順帶重新整理。", - "scanFailed": "掃描失敗", - "retry": "重試", - "rescan": "重新掃描", - "empty": "未發現本機工作階段", - "emptyHint": "本機未找到任何智慧代理的工作階段儲存。", - "noMatches": "沒有符合目前篩選的工作階段", - "searchPlaceholder": "搜尋標題或路徑…", - "allAgents": "全部智慧代理", - "onlyImportable": "僅顯示可匯入", - "selectAll": "全選", - "clearSelection": "清空", - "expandAll": "全部展開", - "collapseAll": "全部摺疊", - "summaryCounts": "共 {total} 個工作階段 · {importable} 個可匯入 · {folders} 個資料夾", - "noFolderSkipped": "已略過 {count} 個無專案目錄的工作階段", - "folderNew": "新建", - "folderCounts": "可匯入 {importable}/{total}", - "toggleFolderAria": "選擇 {name} 中的全部可匯入工作階段", - "toggleSessionAria": "選擇工作階段 {title}", - "statusImported": "已匯入", - "statusDeleted": "已刪除", - "untitled": "未命名工作階段", - "messageCount": "{count} 則訊息", - "selectedCount": "已選 {count} 個", - "importSelected": "匯入所選", - "importing": "匯入中…", - "close": "關閉", - "doneTitle": "匯入完成", - "doneImported": "新匯入", - "doneUpdated": "已重新整理", - "doneSkipped": "已略過", - "doneCreatedFolders": "新建資料夾", - "doneNotFound": "未找到", - "doneFailed": "失敗", - "continueImport": "繼續匯入", - "toasts": { - "importFailed": "匯入失敗:{message}" - } - }, - "Folder": { - "workspaceStatus": { - "degradedTitle": "即時更新不可用", - "degradedHint": "監聽器啟動失敗(如目錄無讀取權限)。請手動重新整理以取得最新變更。", - "retry": "重試", - "retrying": "重試中..." - }, - "common": { - "all": "全部", - "cancel": "取消", - "close": "關閉", - "closeOthers": "關閉其它", - "closeAll": "關閉所有", - "confirm": "確認", - "save": "儲存", - "delete": "刪除", - "rename": "重新命名", - "loading": "載入中...", - "refresh": "刷新", - "refreshing": "刷新中...", - "create": "建立", - "createAndSwitch": "建立並切換", - "openFile": "打開檔案", - "viewDiff": "查看差異", - "push": "推送..." - }, - "statusLabels": { - "in_progress": "進行中", - "pending_review": "待複查", - "completed": "已完成", - "cancelled": "已取消" - }, - "sidebar": { - "title": "會話", - "locateActiveConversation": "定位目前會話", - "expandAllGroups": "展開全部分組", - "collapseAllGroups": "折疊全部分組", - "newConversation": "新增會話", - "newConversationShort": "新增", - "newChat": "新增會話", - "search": "搜尋", - "noConversationsFound": "找不到會話。", - "importLocalSessions": "匯入本地會話", - "importing": "匯入中...", - "error": "錯誤:{message}", - "completeAllSessions": "完成全部會話", - "completeAllReviewTitle": "完成全部複查會話?", - "completeAllReviewDescription": "這會將複查中的 {count} 個會話全部標記為已完成。", - "completing": "處理中...", - "toasts": { - "importedSessions": "已匯入 {imported} 個會話,跳過 {skipped} 個", - "importedAndUpdated": "已匯入 {imported} 個會話,更新 {updated} 個標題,跳過 {skipped} 個", - "updatedTitles": "已更新 {updated} 個標題,跳過 {skipped} 個", - "noNewSessionsFound": "沒有新會話(已跳過 {skipped} 個)", - "importFailed": "匯入失敗:{message}", - "reviewCompleted": "已將 {count} 個複查會話標記為已完成", - "completeReviewFailed": "批次完成複查會話失敗:{message}", - "folderOpened": "已開啟資料夾 {name}", - "folderRemoved": "已移除資料夾 {name}", - "openFolderFailed": "開啟資料夾失敗", - "removeFolderFailed": "移除資料夾失敗:{message}", - "reorderFoldersFailed": "重新排序資料夾失敗:{message}", - "changeFolderColorFailed": "修改顏色失敗:{message}", - "setFolderAliasFailed": "設定別名失敗:{message}", - "changeFolderDefaultAgentFailed": "設定預設智能體失敗:{message}" - }, - "statsLabel": "{folders} 個資料夾 · {convos} 個對話", - "reorderHandle": "拖拽排序", - "openFolder": "開啟資料夾", - "searchPlaceholder": "搜尋對話...", - "viewOptions": "顯示選項", - "showCompleted": "顯示已完成對話", - "showWorktrees": "顯示工作樹資料夾", - "showRecent": "顯示「最近」分組", - "moreOptions": "更多選項", - "sortBy": "排序方式", - "sortByCreatedAt": "按建立時間排序", - "sortByUpdatedAt": "按更新時間排序", - "sectionOrder": "區域順序", - "sectionOrderMoveUp": "上移", - "sectionOrderMoveDown": "下移", - "sectionOrderItemLabel": "{name} — 第 {position} 位,共 {total} 位", - "statusRunningBadge": "運行中", - "runningCountBadge": "{count} 個會話進行中", - "statusCancelledBadge": "已取消", - "worktreeRemovedBadge": "來源 worktree 已刪除", - "conversationCountUnit": "{count} 條", - "emptyFolderHint": "暫無對話", - "noMatchingConversations": "找不到符合的對話", - "noUnfinishedConversations": "目前沒有未完成的會話,右上角可啟用顯示已完成會話", - "removeFolderConfirmTitle": "從工作區移除此資料夾?", - "removeFolderConfirmDescription": "從工作區移除 \"{name}\"?相關分頁與終端機將會關閉。", - "folderHeaderMenu": { - "manageConversations": "會話管理…", - "manageLinks": "已連結的資料夾", - "changeColor": "修改顏色", - "useThemeColor": "使用設定主題", - "setDefaultAgent": "設定預設智能體", - "defaultAgentNone": "不設定(使用全域預設)", - "agentUnavailableSuffix": "(不可用)", - "loadingAgents": "正在載入代理…", - "setAlias": "設定別名…", - "setAliasTitle": "設定資料夾別名", - "setAliasPlaceholder": "輸入別名(留空清除)", - "setAliasSave": "儲存", - "setAliasCancel": "取消", - "removeFromWorkspace": "從工作區移除" - }, - "manageConversations": { - "title": "會話管理", - "searchPlaceholder": "依標題搜尋…", - "agentFilterAll": "全部智能體", - "statusFilterAll": "全部狀態", - "folderFilterAll": "全部資料夾", - "branchFilterAll": "全部分支", - "branchNone": "無分支", - "branchSearchPlaceholder": "搜尋分支…", - "noMatchingBranches": "無匹配分支", - "selectAllVisible": "全選", - "deselectAll": "取消全選", - "selectedCount": "已選 {count} 筆", - "matchedCount": "符合 {count} 筆", - "untitledConversation": "未命名會話", - "setStatus": "設為狀態…", - "deleteSelected": "刪除", - "noConversations": "此資料夾暫無會話。", - "noConversationsWorkspace": "工作區暫無會話。", - "noMatchingConversations": "沒有符合過濾條件的會話。", - "confirmDeleteTitle": "刪除 {count} 個會話?", - "confirmDeleteDescription": "此操作無法復原。", - "toastDeleted": "已刪除 {count} 個會話", - "toastStatusUpdated": "已更新 {count} 個會話的狀態", - "toastOpFailed": "操作失敗:{message}" - }, - "sectionPinned": "已置頂", - "sectionFolders": "資料夾", - "sectionChats": "聊天", - "sectionRecent": "最近", - "noChats": "沒有聊天", - "noRecent": "暫無最近對話", - "showMoreRecent": "顯示更多({count})", - "noFolders": "沒有開啟的資料夾", - "newChatAction": "新增聊天", - "automations": "自動化", - "tasks": "待辦任務", - "loadingSubsessions": "正在載入子會話…" - }, - "conversation": { - "reloadFailed": "會話重新載入失敗:{message}", - "reloaded": "目前會話已重新載入", - "reload": "重新載入", - "activeConversationIndicator": "目前啟用的會話", - "newConversation": "新增會話", - "closeConversation": "關閉會話", - "copyText": "複製文字", - "copyTextSuccess": "已複製", - "copyTextFailed": "複製失敗", - "forkSession": "分叉會話", - "forkSessionSuccess": "會話分叉成功", - "forkSessionFailed": "會話分叉失敗:{error}", - "exportConversation": "匯出對話", - "exportImage": "圖片", - "exportMarkdown": "Markdown", - "exportHtml": "HTML", - "exportSuccess": "對話已匯出", - "exportFailed": "匯出失敗", - "exportImageTooLong": "對話內容過長,不支援匯出為圖片", - "exportLabels": { - "untitledConversation": "未命名對話", - "agent": "代理", - "model": "模型", - "status": "狀態", - "started": "開始時間", - "updated": "更新時間", - "tokens": "令牌統計", - "duration": "時長", - "inputTokens": "輸入", - "outputTokens": "輸出", - "cacheRead": "快取讀取", - "cacheWrite": "快取寫入", - "user": "使用者", - "assistant": "助手", - "system": "系統", - "toolResult": "結果", - "toolError": "錯誤" - }, - "moreActions": "更多操作" - }, - "sessionDetails": { - "menuLabel": "對話詳情", - "noActiveSession": "暫無使用中的對話", - "title": "對話詳情", - "subtitle": "對話中繼資料與 Token 用量", - "fieldTitle": "標題", - "untitled": "未命名對話", - "sessionId": "對話 ID", - "externalId": "擴充 ID", - "agent": "智能體", - "model": "模型", - "status": "狀態", - "gitBranch": "Git 分支", - "parentId": "父對話", - "tokensHeading": "Token 用量", - "totalTokens": "總計", - "inputTokens": "輸入", - "outputTokens": "輸出", - "cacheWrite": "快取寫入", - "cacheRead": "快取讀取", - "contextWindow": "上下文視窗", - "duration": "時長", - "loadingStats": "正在載入 Token 用量…", - "loadFailed": "載入 Token 用量失敗", - "noStats": "尚無用量記錄", - "timestampsHeading": "時間", - "createdAt": "建立時間", - "updatedAt": "更新時間", - "none": "—", - "copyField": "複製{field}", - "copiedField": "已複製{field}" - }, - "conversationCard": { - "untitledConversation": "未命名會話", - "newConversation": "新增會話", - "rename": "重新命名", - "status": "狀態", - "delete": "刪除", - "importLocalSessions": "匯入本地會話", - "importing": "匯入中...", - "renameConversation": "重新命名會話", - "deleteConversationTitle": "刪除會話?", - "deleteConversationDescription": "會刪除「{title}」,此操作無法復原。", - "cancel": "取消", - "save": "儲存", - "pin": "置頂", - "unpin": "取消置頂", - "markCompleted": "標記為已完成", - "reopen": "重新開啟", - "expandSubsessions": "展開子會話", - "collapseSubsessions": "摺疊子會話" - }, - "search": { - "dialogTitle": "搜尋", - "dialogTitleWithFolder": "搜尋 — {name}", - "tabConversations": "會話", - "tabFiles": "檔案", - "placeholder": "搜尋會話...", - "filePlaceholder": "搜尋檔案或目錄...", - "allAgents": "全部", - "searching": "搜尋中...", - "typeToSearch": "輸入關鍵字搜尋會話", - "typeToSearchFiles": "輸入關鍵字搜尋檔案或目錄", - "noResults": "找不到結果。", - "untitledConversation": "未命名會話" - }, - "folderTitleBar": { - "showSidebar": "顯示側邊欄", - "hideSidebar": "隱藏側邊欄", - "toggleTerminal": "切換終端", - "toggleAuxPanel": "切換輔助面板", - "search": "搜尋", - "openSettings": "打開設定", - "backToConversations": "返回會話", - "withShortcut": "{label}({shortcut})" - }, - "statusBar": { - "connection": { - "connected": "已連線", - "connecting": "連線中...", - "prompting": "回應中...", - "error": "連線異常", - "disconnected": "未連線", - "tooltip": "{agent}:{status}", - "tooltipError": "{agent}:{error}", - "title": "智慧體連線", - "triggerAria": "智慧體連線:{status}", - "workingDir": "工作目錄", - "sessionId": "工作階段 ID", - "viewerNote": "已接入其他用戶端擁有的工作階段——重新連線只會重新接入目前檢視。", - "reconnectInterrupts": "重新連線會重啟智慧體,並中斷進行中的工作。", - "reconnect": "重新連線", - "reconnecting": "正在重新連線...", - "reconnectUnavailable": "目前沒有可重新連線的工作階段。" - }, - "tasks": { - "title": "任務" - }, - "alerts": { - "title": "警示", - "empty": "暫無警示資訊", - "details": "詳情" - }, - "stats": { - "conversations": "{count} 個會話", - "openUsage": "檢視會話統計與 Token 用量" - }, - "tokens": { - "contextWindowUsageAria": "上下文視窗使用率", - "contextWindow": "上下文視窗", - "usedMax": "已用 / 上限", - "tokenUsage": "Token 用量", - "input": "輸入", - "output": "輸出", - "cacheRead": "快取讀取", - "cacheWrite": "快取寫入", - "total": "總計" - } - }, - "auxPanel": { - "tabs": { - "files": "檔案", - "changes": "變更", - "commits": "提交" - }, - "noFolderTitle": "尚無開啟的資料夾", - "noFolderHint": "開啟一個資料夾後可在此查看" - }, - "windowControls": { - "minimizeWindow": "最小化視窗", - "minimize": "最小化", - "maximizeWindow": "最大化視窗", - "maximize": "最大化", - "restoreWindow": "還原視窗", - "restore": "還原", - "closeWindow": "關閉視窗", - "close": "關閉" - }, - "tabs": { - "closeConversationTab": "關閉會話分頁", - "close": "關閉", - "closeOthers": "關閉其它", - "splitRight": "向右拆分", - "splitDown": "向下拆分", - "splitAndMoveRight": "拆分並右移", - "splitAndMoveDown": "拆分並下移", - "moveToOppositeGroup": "移動到對側分組", - "moveToGroup": "移動到分組", - "groupLabel": "分組 {index}", - "changeSplitterOrientation": "切換分隔方向", - "unsplit": "取消拆分", - "unsplitAll": "全部取消拆分", - "closeAll": "關閉所有", - "tileDisplay": "平鋪顯示", - "untileDisplay": "取消平鋪" - }, - "fileWorkspace": { - "files": "檔案", - "closeFileTab": "關閉檔案分頁", - "close": "關閉", - "closeOthers": "關閉其它", - "closeAll": "關閉所有", - "preview": "預覽", - "editSource": "編輯原始碼", - "maximize": "最大化", - "restore": "還原", - "emptyDirectory": "空目錄" - }, - "terminal": { - "rename": "重新命名", - "close": "關閉", - "closeOthers": "關閉其它", - "closeAll": "關閉所有", - "hideTerminal": "隱藏終端({shortcut})", - "openFolderFirst": "請先開啟一個資料夾" - }, - "workspaceDialog": { - "title": "開啟資料夾", - "manageTitle": "已連結的資料夾", - "addTargetsTitle": "新增要連結的資料夾", - "pickRootDescription": "選擇這個工作區的主資料夾。", - "linksDescription": "把其他資料夾以子目錄的形式連結進來,代理就能在同一個工作區跨專案工作。", - "addTargetsDescription": "選擇一個或多個資料夾,每個都會成為工作區的一個子目錄。", - "useSystemPicker": "系統選擇器", - "next": "下一步", - "back": "返回", - "done": "完成", - "change": "變更", - "addFolders": "新增資料夾", - "addSelected": "新增", - "addSelectedCount": "新增 {count} 個", - "createCount": "連結 {count} 個資料夾", - "discardPending": "捨棄", - "noLinks": "尚未連結任何資料夾。", - "gitExclude": "不讓連結目錄污染 git 狀態", - "rename": "重新命名", - "unlink": "解除連結", - "repair": "重建連結", - "saveName": "儲存", - "cancelRename": "取消", - "removePending": "移除", - "willAppearAs": "在工作區中顯示為 {name}", - "renamedForDuplicate": "已改名 —— {base} 已被另一個連結佔用", - "renamedForExistingEntry": "已改名 —— 該資料夾中已存在 {base}", - "partiallyCreated": "只成功連結了 {count} 個資料夾", - "openFailed": "開啟資料夾失敗", - "previewFailed": "檢查所選資料夾失敗", - "createFailed": "連結資料夾失敗", - "renameFailed": "重新命名失敗", - "removeFailed": "解除連結失敗", - "repairFailed": "重建連結失敗", - "status": { - "ok": "已連結", - "missing": "連結已從該資料夾中消失", - "conflicted": "該名稱已被其他項目佔用", - "broken": "被連結的資料夾已不存在" - }, - "nameIssue": { - "empty": "請輸入名稱", - "illegalChars": "不能包含 / \\ : * ? \" < > |", - "tooLong": "名稱過長", - "reserved": "該名稱是 Windows 保留名", - "duplicate": "該名稱已被使用" - }, - "rejection": { - "not_found": "找不到該資料夾", - "not_a_directory": "該路徑不是資料夾", - "same_as_root": "這就是工作區資料夾本身", - "ancestor_of_root": "該資料夾包含了目前工作區", - "inside_root": "已在工作區內部", - "already_linked": "已經連結過", - "name_unavailable": "該資料夾已無可用的名稱", - "alreadyLinkedAs": "已作為 {name} 連結" - } - }, - "folderNameDropdown": { - "fallbackFolderName": "資料夾", - "openFolder": "打開資料夾", - "cloneRepository": "複製倉庫", - "projectBoot": "專案啟動器", - "opened": "已打開", - "recentOpen": "最近打開" - }, - "fileWorkspacePanel": { - "addSelectionToChat": "新增選取範圍到對話", - "addToChat": "加入對話", - "addSelectionToChatDone": "已將 {label} 加入對話", - "addFileToChat": "新增檔案到對話", - "toggleWordWrap": "切換自動換行", - "addFileToChatDone": "已將 {label} 加入對話", - "viewDiff": "查看差異", - "openFile": "打開檔案", - "fileCount": "{count} 個檔案", - "openFileOrDiff": "從右側面板打開檔案或差異", - "disk": "磁碟", - "head": "HEAD(目前提交)", - "unsaved": "未儲存", - "workingTree": "工作區", - "loading": "載入中...", - "compareWithBranch": "{path} · 與 {branch} 比較", - "hunkCount": "{count} 個區塊", - "prev": "上一個", - "next": "下一個", - "jumpToLine": "跳到第 {line} 行", - "noParsedDiffSections": "未解析到差異區塊", - "loadingEditor": "編輯器載入中...", - "imageZoomIn": "放大", - "imageZoomOut": "縮小", - "imageZoomReset": "重設縮放", - "htmlPreviewTitle": "HTML 預覽", - "htmlPreviewTrust": "執行指令碼", - "htmlPreviewTrustHint": "執行此檔案的指令碼並允許網路存取。僅對信任的檔案啟用。", - "officePreviewTitle": "辦公文件預覽", - "officeFullRender": "完整渲染", - "officeFullRenderHint": "渲染 Morph 動畫、3D 與公式(會執行投影片自帶的指令碼)", - "officeNotInstalled": "未安裝 OfficeCLI", - "officeNotInstalledHint": "在 設定 → 辦公工具 中安裝 OfficeCLI,即可預覽 Word、Excel 與 PowerPoint 檔案。", - "officeOpenSettings": "開啟設定", - "officeWatchFailed": "無法啟動即時預覽", - "officeWatchRetry": "重試", - "officeServerInstallHint": "OfficeCLI 需安裝在伺服器主機上。請在伺服器上執行以下指令後重試:", - "officeRemoteDesktopUnsupported": "遠端桌面視窗暫不支援即時預覽。請在伺服器的 Web 介面中開啟此工作區以預覽 Office 檔案。" - }, - "branchDropdown": { - "toasts": { - "commitCodeCompleted": "提交程式碼完成", - "pushCodeCompleted": "推送程式碼完成", - "committedFiles": "已提交 {count} 個檔案", - "taskCompleted": "{label} 完成", - "taskFailed": "{label} 失敗", - "mergeNoNewCommits": "{branchName} 沒有新的提交", - "mergedCommits": "已合併 {count} 個提交", - "allFilesUpToDate": "所有檔案均為最新版本", - "updatedFiles": "已更新 {count} 個檔案", - "openCommitWindowFailed": "打開提交視窗失敗", - "openPushWindowFailed": "開啟推送視窗失敗", - "upstreamSet": "已設定遠端追蹤分支", - "upstreamSetAndPushed": "已設定遠端追蹤分支並推送 {count} 個提交", - "noCommitsToPush": "沒有可推送的提交", - "pushedCommits": "已推送 {count} 個提交", - "switchedToFolder": "已切換到 {name}", - "switchFailed": "切換分支失敗", - "openStashWindowFailed": "開啟收藏視窗失敗" - }, - "tasks": { - "newBranch": "新增分支 {name}", - "newWorktree": "新增工作樹 {name}", - "checkoutTo": "切換到 {branchName}", - "mergeBranch": "合併 {branchName}", - "rebaseTo": "變基到 {branchName}", - "deleteRemoteBranch": "刪除遠端分支 {branchName}", - "initGitRepo": "初始化 Git 倉庫", - "pullCode": "更新程式碼", - "fetchInfo": "獲取資訊", - "pushCode": "推送程式碼", - "stashChanges": "暫存變更", - "stashPop": "取消暫存", - "deleteBranch": "刪除分支 {branchName}", - "removeWorktree": "刪除 {branchName} 的工作樹", - "removeWorktreeAndBranch": "刪除工作樹及分支 {branchName}", - "updateBranch": "更新分支 {branchName}" - }, - "confirm": { - "mergeTitle": "合併分支", - "rebaseTitle": "變基分支", - "mergeDescription": "確定將 {branchName} 合併到目前分支 {currentBranch} 嗎?", - "rebaseDescription": "確定將目前分支 {currentBranch} 變基到 {branchName} 嗎?", - "deleteRemoteTitle": "刪除遠端分支", - "deleteRemoteDescription": "確定刪除遠端分支 {branchName} 嗎?此操作將從遠端倉庫中移除該分支,且不可恢復。", - "deleteTitle": "刪除分支", - "deleteDescription": "確定刪除分支 {branchName} 嗎?此操作無法復原。", - "forceDeleteTitle": "強制刪除分支", - "forceDeleteDescription": "分支 {branchName} 尚未完全合併,確定要強制刪除嗎?此操作不可恢復。", - "deleteWorktreeTitle": "刪除工作樹", - "deleteWorktreeDescription": "刪除簽出了 {branchName} 的工作樹目錄?分支及其提交會保留。", - "forceDeleteWorktreeTitle": "強制刪除工作樹", - "forceDeleteWorktreeDescription": "{branchName} 的工作樹中有未提交或未追蹤的檔案。仍要刪除嗎?這些變更將無法復原。", - "deleteWorktreeAndBranchTitle": "刪除工作樹及分支", - "deleteWorktreeAndBranchDescription": "刪除 {branchName} 的工作樹、該分支本身及其工作區資料夾?其中的工作階段會移動到儲存庫資料夾下。此操作無法復原。", - "forceDeleteWorktreeAndBranchTitle": "強制刪除工作樹及分支", - "forceDeleteWorktreeAndBranchDescription": "{branchName} 的工作樹中有未提交的檔案,或該分支尚未完全合併。仍要一併刪除嗎?此操作無法復原。" - }, - "current": "目前", - "switchToBranch": "切換到此分支", - "mergeBranchIntoCurrent": "將 {branchName} 合併到 {currentBranch}", - "rebaseCurrentToBranch": "將 {currentBranch} 變基到 {branchName}", - "noBranch": "無分支", - "detachedHead": "分離 HEAD({sha})", - "initGitRepo": "初始化 Git 倉庫", - "pullCode": "更新程式碼", - "fetchRemoteBranches": "提取遠端分支", - "openCommitWindow": "提交程式碼...", - "pushCode": "推送...", - "pushBranch": "推送", - "newBranch": "新增分支...", - "newWorktree": "新增工作樹...", - "stashChanges": "貯藏更改...", - "stashPop": "取消暫存...", - "manageRemotes": "管理遠端...", - "localBranches": "本地分支 ({count})", - "noLocalBranches": "無本地分支", - "remoteBranches": "遠端分支 ({count})", - "noRemoteBranches": "無遠端分支", - "dialogs": { - "newBranchTitle": "新增分支", - "newBranchDescription": "從目前分支 {branch} 建立新分支", - "branchNamePlaceholder": "分支名稱", - "newWorktreeTitle": "新增工作樹", - "newWorktreeDescription": "從目前分支 {branch} 建立新的工作樹", - "branchNameLabel": "分支名稱", - "worktreePathLabel": "工作樹路徑", - "worktreePathPlaceholder": "工作樹路徑", - "manageRemotesTitle": "管理遠端", - "manageRemotesEmpty": "未設定遠端儲存庫", - "remoteNamePlaceholder": "遠端名稱", - "remoteUrlPlaceholder": "遠端 URL", - "addRemote": "新增", - "savingRemotes": "儲存中..." - }, - "conflict": { - "title": "合併衝突", - "description": "以下檔案存在衝突,需要手動解決:", - "abort": "中止合併", - "openMergeTool": "開啟合併工具", - "completeMerge": "完成合併", - "abortSuccess": "合併已中止", - "completeSuccess": "合併完成" - }, - "stashDialog": { - "title": "貯藏更改", - "description": "將當前更改保存到貯藏區", - "messageLabel": "訊息", - "messagePlaceholder": "貯藏訊息(可選)", - "keepIndex": "保留暫存區(已暫存的更改保持不變)", - "cancel": "取消", - "stash": "貯藏", - "success": "更改已貯藏", - "error": "貯藏更改失敗" - }, - "unstashDialog": { - "title": "取消貯藏", - "noStashes": "沒有貯藏記錄", - "selectFile": "選擇檔案查看差異", - "viewDiff": "查看差異", - "original": "原始", - "modified": "修改後", - "apply": "套用", - "drop": "刪除", - "applySuccess": "貯藏已套用", - "dropSuccess": "貯藏已刪除", - "confirmApply": "將貯藏 {ref} 套用到工作目錄?", - "cancel": "取消" - }, - "deleteBranch": "刪除分支", - "deleteWorktree": "刪除工作樹", - "deleteWorktreeAndBranch": "刪除工作樹及分支", - "searchPlaceholder": "搜尋分支與操作", - "searchAriaLabel": "搜尋分支與操作", - "branchListLabel": "分支與操作", - "noMatches": "無相符項目" - }, - "commitDialog": { - "toasts": { - "commitCompleted": "提交程式碼完成", - "pushFailed": "推送失敗", - "committedFiles": "已提交 {count} 個檔案", - "addedToVcs": "已加入到 VCS", - "addToVcsFailed": "加入到 VCS 失敗", - "fileDeleted": "檔案已刪除", - "deleteFailed": "刪除失敗", - "fileRolledBack": "檔案已回滾", - "rollbackFailed": "回滾失敗", - "dirRolledBack": "目錄已回滾", - "dirDeleted": "目錄已刪除" - }, - "confirm": { - "deleteTitle": "確認刪除", - "deleteDescription": "確定要刪除檔案「{file}」嗎?此操作無法復原。", - "rollbackTitle": "確認回滾", - "rollbackDescription": "確定要回滾檔案「{file}」到 HEAD 版本嗎?未儲存修改將遺失。", - "rollbackDirDescription": "確定要回滾目錄「{dir}」到 HEAD 版本嗎?未儲存的修改將遺失。", - "deleteDirDescription": "確定要刪除目錄「{dir}」嗎?此操作不可恢復。" - }, - "actions": { - "select": "選擇", - "unselect": "取消選擇", - "rollback": "回滾", - "addToVcs": "加入到 VCS" - }, - "aria": { - "selectFile": "{action}:{path}", - "unselectAllFiles": "取消選擇全部檔案", - "selectAllFiles": "選擇全部檔案", - "unselectTracked": "取消選擇已追蹤變更", - "selectTracked": "選擇已追蹤變更", - "unselectUntracked": "取消選擇未追蹤檔案", - "selectUntracked": "選擇未追蹤檔案" - }, - "loading": "載入中...", - "selectionCount": "{selected} / {total} 個檔案", - "emptyFiles": "沒有變更的檔案", - "trackedChanges": "已追蹤變更 ({count})", - "untrackedFiles": "未追蹤檔案 ({count})", - "commitMessage": "提交訊息", - "commitMessagePlaceholder": "輸入提交訊息...", - "commitButton": "提交 ({count})", - "commitAndPushButton": "提交並推送 ({count})", - "head": "HEAD(目前提交)", - "workingTree": "工作目錄", - "clickFileToDiff": "點擊檔案名稱查看差異", - "loadingDiff": "載入差異中..." - }, - "pushWindow": { - "title": "推送程式碼", - "noUnpushedCommits": "沒有未推送的提交", - "noRemoteConfigured": "未設定 Git 遠端儲存庫\n請在「管理遠端」中新增遠端地址", - "newBranchNoPushedCommits": "新分支 — 推送以建立遠端追蹤分支", - "unpushed": "未推送", - "selectFileToViewDiff": "選擇檔案查看差異", - "before": "修改前", - "after": "修改後", - "push": "推送", - "toasts": { - "pushSuccess": "推送成功", - "pushFailed": "推送失敗", - "upstreamSet": "已設定遠端追蹤分支", - "upstreamSetAndPushed": "已設定遠端追蹤分支並推送 {count} 個提交", - "noCommitsToPush": "沒有可推送的提交", - "pushedCommits": "已推送 {count} 個提交" - } - }, - "gitLogTab": { - "filesTitle": "檔案", - "expandAllFiles": "展開全部檔案", - "collapseAllFiles": "折疊全部檔案", - "workspace": "工作區", - "retry": "重試", - "noCommitsFound": "未找到提交記錄", - "notAGitRepoTitle": "不是 Git 儲存庫", - "notAGitRepoHint": "可從上方分支選單初始化 Git,或開啟已有的 Git 儲存庫。", - "hash": "Hash", - "copyHash": "複製雜湊", - "copyMessage": "複製提交訊息", - "showMore": "展開", - "showLess": "收合", - "author": "作者", - "noFileChangeDetails": "暫無檔案變更詳情。", - "loadingFiles": "正在載入檔案…", - "branchesTitle": "分支", - "loadingBranches": "正在載入分支...", - "noContainingBranches": "未找到包含此提交的分支。", - "newBranch": "新增分支...", - "resetToHere": "重設到此處", - "resetDisabledReasonNotCurrentBranchView": "僅在檢視目前分支時可用", - "copyFullCommitHashAria": "複製完整提交雜湊 {hash}", - "pushStatus": { - "pushed": "已推送到遠端", - "notPushed": "未推送到遠端", - "unknown": "推送狀態未知(未配置上游分支)" - }, - "time": { - "monthsAgo": "{count} 個月前", - "daysAgo": "{count} 天前", - "hoursAgo": "{count} 小時前", - "minsAgo": "{count} 分鐘前", - "justNow": "剛剛" - }, - "toasts": { - "createdAndSwitchedNewBranch": "已建立並切換到新分支", - "newBranchFromCommit": "{name}(來自 {shortHash})", - "createBranchFailed": "新增分支失敗", - "openPushWindowFailed": "開啟推送視窗失敗", - "resetSuccess": "重設成功", - "resetSuccessDescription": "已將 {branch} 以 {mode} 重設到 {shortHash}", - "resetFailed": "重設失敗" - }, - "authorFilter": { - "label": "作者", - "searchPlaceholder": "搜尋作者", - "noAuthors": "找不到作者", - "you": "你", - "filterByAuthorAria": "依作者篩選提交", - "filterByQuery": "依「{query}」篩選", - "clearAuthorFilterAria": "清除作者篩選", - "recent": "最近", - "matchingAuthors": "符合的作者", - "removeFromRecent": "從最近列表移除 {name}" - }, - "branchSelector": { - "label": "分支", - "head": "HEAD", - "headHint": "跟隨目前分支", - "headHintWithBranch": "跟隨目前分支({branch})", - "searchBranch": "搜尋分支...", - "noBranches": "無分支", - "selectBranchPlaceholder": "選擇分支...", - "localBranches": "本地分支", - "current": "目前", - "remoteBranches": "遠端分支", - "refreshCommitHistory": "刷新提交記錄", - "clearBranchFilterAria": "清除分支篩選" - }, - "dialogs": { - "newBranchTitle": "新增分支", - "newBranchDescription": "以提交 {shortHash} 作為最後提交建立新分支。", - "branchNamePlaceholder": "分支名稱", - "reset": { - "title": "將目前分支重設到此提交", - "branchLabel": "分支", - "targetLabel": "目標提交", - "messageLabel": "提交訊息", - "modeLabel": "重設模式", - "confirmButton": "重設", - "modes": { - "soft": { - "label": "--soft", - "description": "將 HEAD 與目前分支指標移動到目標提交。\n暫存區(Index)與工作區(Working Tree)保持不變。\n被回退提交的變更會保留為「已暫存」。" - }, - "mixed": { - "label": "--mixed(預設)", - "description": "將 HEAD 移動到目標提交。\n把暫存區重設為目標提交狀態,但保留工作區變更。\n這些變更會由「已暫存」變成「未暫存」。" - }, - "hard": { - "label": "--hard", - "description": "將 HEAD、暫存區與工作區全部重設到目標提交。\n目標提交之後的本地已追蹤變更會被直接捨棄。\n這是破壞性操作。" - }, - "keep": { - "label": "--keep", - "description": "將 HEAD 移動到目標提交,並盡可能保留本地變更。\n僅保留與目標提交不衝突的本地變更。\n若檢測到衝突,操作會中止以保護你的修改。" - } - } - } - }, - "moreActions": "更多 Git 操作" - }, - "gitChangesTab": { - "workspace": "工作區", - "noChanges": "暫無本地變更", - "notAGitRepoTitle": "不是 Git 儲存庫", - "notAGitRepoHint": "可從上方分支選單初始化 Git,或開啟已有的 Git 儲存庫。", - "trackedChanges": "本地已追蹤變更 ({count})", - "untrackedFiles": "本地未追蹤檔案 ({count})", - "expandTracked": "展開已追蹤變更", - "collapseTracked": "折疊已追蹤變更", - "expandUntracked": "展開未追蹤檔案", - "collapseUntracked": "折疊未追蹤檔案", - "showRemainingItems": "顯示其餘 {count} 項", - "actions": { - "commitCode": "提交程式碼", - "rollback": "回滾", - "addToVcs": "加入到 VCS", - "delete": "刪除", - "moreActions": "更多 Git 操作", - "addAllToVcs": "全部加入 VCS", - "rollbackAll": "全部還原", - "refresh": "重新整理" - }, - "toasts": { - "noAddableFilesInDir": "該目錄下沒有可加入到 VCS 的變更檔案", - "noRollbackFilesInDir": "該目錄下沒有可回滾的變更檔案", - "addedToVcs": "已加入 {name} 到 VCS", - "addToVcsFailed": "加入到 VCS 失敗", - "openCommitWindowFailed": "打開提交視窗失敗", - "rolledBack": "已回滾 {name}", - "rollbackFailed": "回滾失敗", - "addedFilesToVcs": "已加入 {count} 個檔案到 VCS", - "rolledBackFiles": "已回滾 {count} 個檔案", - "deleted": "已刪除 {name}", - "deleteFailed": "刪除失敗", - "deletedFiles": "已刪除 {count} 個檔案", - "noDeletableFilesInDir": "此目錄下沒有可刪除的變更檔案", - "commitFailed": "提交失敗" - }, - "directoryDialog": { - "descriptionAdd": "選擇目錄 {path} 下要加入到 VCS 的檔案。", - "descriptionRollback": "選擇目錄 {path} 下要回滾的檔案。", - "descriptionDelete": "選擇目錄 {path} 下要刪除的檔案。此操作不可撤銷。", - "descriptionFallback": "選擇要操作的檔案。", - "selectionCount": "已選擇 {selected} / {total} 個檔案", - "selectAll": "全選", - "unselectAll": "取消全選", - "loadingCandidates": "正在載入目錄變更...", - "noOperableFiles": "沒有可操作的檔案" - }, - "rollbackConfirm": { - "title": "確認回滾", - "descriptionWithTarget": "確定回滾{kind}「{name}」的本地修改嗎?", - "descriptionFallback": "確定回滾本地修改嗎?", - "kindDirectory": "目錄", - "kindFile": "檔案" - }, - "deleteConfirm": { - "title": "確認刪除", - "descriptionWithTarget": "確定刪除{kind}「{name}」嗎?此操作無法撤銷。", - "descriptionFallback": "此操作無法撤銷。", - "kindDirectory": "目錄", - "kindFile": "檔案" - }, - "quickCommit": { - "placeholder": "提交訊息(Enter 提交)" - } - }, - "tabContext": { - "loadingConversation": "載入中...", - "untitledConversation": "未命名會話", - "newConversation": "新增會話" - }, - "fileTreeTab": { - "workspace": "工作區", - "retry": "重試", - "git": "Git", - "openInFileManager": "在檔案管理器開啟", - "openInFinder": "在 Finder 開啟", - "openInExplorer": "在檔案總管開啟", - "attachToCurrentSession": "添加到會話", - "compareWithBranch": "與分支比較...", - "reloadFromDisk": "從磁碟重新載入", - "new": "新建", - "newFile": "檔案", - "newDirectory": "目錄", - "openIn": "開啟於", - "openInTerminal": "在終端開啟", - "linkedFolder": "已連結的資料夾", - "copyPath": "複製路徑", - "upload": "上傳檔案/目錄", - "download": "下載檔案", - "downloadAsZip": "下載為 ZIP", - "actions": { - "select": "選擇", - "unselect": "取消選擇", - "commitCode": "提交程式碼", - "rollback": "回滾", - "addToVcs": "加入到 VCS" - }, - "aria": { - "selectPath": "{action}:{path}" - }, - "toasts": { - "openDirectoryFailed": "開啟目錄失敗", - "openBuiltinTerminalFailed": "無法開啟內建終端", - "openCommitWindowFailed": "打開提交視窗失敗", - "noAddableFilesInDir": "該目錄下沒有可加入到 VCS 的變更檔案", - "noRollbackFilesInDir": "該目錄下沒有可回滾的變更檔案", - "addedToVcs": "已加入 {name} 到 VCS", - "addToVcsFailed": "加入到 VCS 失敗", - "loadBranchesFailed": "載入分支失敗", - "renameFailed": "重新命名失敗", - "moveFailed": "移動失敗", - "deleteFailed": "刪除失敗", - "rolledBack": "已回滾 {name}", - "rollbackFailed": "回滾失敗", - "addedFilesToVcs": "已加入 {count} 個檔案到 VCS", - "rolledBackFiles": "已回滾 {count} 個檔案", - "savedAsCopy": "已另存為副本", - "saveCopyFailed": "另存為副本失敗", - "watchStartFailed": "檔案監聽啟動失敗", - "createFailed": "建立失敗", - "downloadFailed": "下載 {name} 失敗", - "downloadSaved": "已下載 {name}", - "pathCopied": "已複製路徑", - "copyPathFailed": "複製路徑失敗" - }, - "createDialog": { - "newFile": "新建檔案", - "newDirectory": "新建目錄", - "description": "輸入新{kind}的名稱。", - "placeholderFile": "file-name.ext", - "placeholderDirectory": "folder-name" - }, - "renameDialog": { - "renameDirectory": "重新命名目錄", - "renameFile": "重新命名檔案", - "description": "輸入新的名稱(僅名稱,不含路徑)。", - "placeholderDirectory": "新資料夾名稱", - "placeholderFile": "新檔案名稱.ext" - }, - "uploadDialog": { - "title": "上傳到工作區", - "description": "可在下方修改上傳目錄,然後加入檔案或資料夾。", - "workspaceRoot": "工作區根目錄", - "targetPathLabel": "上傳到", - "targetPathHint": "實際目錄:{path}", - "dropHint": "拖曳檔案或資料夾到此處,或使用下方按鈕", - "dropHintActive": "放開以加入上傳佇列", - "selectFiles": "選擇檔案", - "selectFolder": "選擇資料夾", - "startUpload": "開始上傳", - "clearQueue": "清除已完成", - "removeItem": "從佇列移除", - "retry": "重試", - "dropZoneAria": "拖放檔案到此處,或按 Enter 鍵瀏覽", - "folderEmpty": "拖入的資料夾中沒有可上傳的檔案", - "summary": "總數:{total} · 成功:{succeeded} · 失敗:{failed}", - "status": { - "pending": "等待中", - "uploading": "上傳中", - "success": "完成", - "error": "失敗", - "cancelled": "已取消" - } - }, - "directoryDialog": { - "descriptionAdd": "選擇目錄 {path} 下要加入到 VCS 的檔案。", - "descriptionRollback": "選擇目錄 {path} 下要回滾的檔案。", - "descriptionFallback": "選擇要操作的檔案。", - "selectionCount": "已選擇 {selected} / {total} 個檔案", - "selectAll": "全選", - "unselectAll": "取消全選", - "loadingCandidates": "正在載入目錄變更...", - "noOperableFiles": "沒有可操作的檔案" - }, - "compareDialog": { - "title": "與分支比較", - "descriptionWithTarget": "選擇分支並與{kind} {path} 比對", - "descriptionFallback": "選擇要比較的分支。", - "kindDirectory": "目錄", - "kindFile": "檔案", - "filterPlaceholder": "過濾分支,例如 main / origin/main", - "singleClickHint": "單擊分支即可直接比較", - "loadingBranches": "正在載入分支...", - "recentBranches": "最近分支 ({count})", - "noCurrentBranch": "無目前分支", - "localBranches": "本地分支 ({count})", - "remoteBranches": "遠端分支 ({count})", - "noMatchingBranches": "無匹配分支" - }, - "externalConflictDialog": { - "title": "偵測到外部檔案變更", - "descriptionWithPath": "檔案 {path} 在磁碟已發生變化,目前編輯內容尚未儲存。", - "descriptionFallback": "目前檔案在磁碟已發生變化,目前編輯內容尚未儲存。", - "compare": "比較", - "savingCopy": "另存中...", - "saveAsCopy": "另存為副本", - "reload": "重載" - }, - "deleteConfirm": { - "title": "確認刪除", - "descriptionWithTarget": "確定刪除{kind} \"{name}\" 嗎?此操作不可撤銷。", - "descriptionFallback": "此操作不可撤銷。", - "kindDirectory": "目錄", - "kindFile": "檔案" - }, - "rollbackConfirm": { - "title": "確認回滾", - "descriptionWithTarget": "確定回滾檔案 \"{name}\" 的本地修改嗎?", - "descriptionFallback": "確定回滾該檔案的本地修改嗎?" - }, - "terminalTitle": "終端 · {name}" - }, - "commandDropdown": { - "loading": "載入中...", - "addCommand": "新增命令", - "manageCommands": "管理命令...", - "runCommandTitle": "執行:{command}", - "stopCommandTitle": "停止:{command}", - "manageDialog": { - "title": "管理命令", - "empty": "暫無命令", - "noResults": "沒有符合的命令", - "searchPlaceholder": "搜尋命令", - "newCommand": "新增命令", - "nameLabel": "名稱", - "commandLabel": "命令", - "dragSort": "拖曳排序", - "dragSortCommand": "拖曳排序 {name}", - "orderFailed": "儲存命令排序失敗", - "loadFailed": "載入命令失敗", - "saveFailed": "儲存命令失敗", - "deleteFailed": "刪除命令失敗", - "confirmDelete": { - "title": "刪除命令?", - "message": "這會移除「{name}」,此操作無法復原。" - } - } - }, - "workspaceContext": { - "confirmCloseDirtyTab": "檔案「{title}」有未儲存變更,確定關閉嗎?", - "confirmCloseOtherDirtyTabs": "其他分頁有未儲存變更,確定關閉嗎?", - "confirmCloseAllDirtyTabs": "存在未儲存變更,確定關閉全部分頁嗎?", - "unableLoadContent": "無法載入內容。\n\n{message}", - "previewRequestTimedOut": "預覽請求逾時", - "diffRequestTimedOut": "Diff 請求逾時", - "branchCompareRequestTimedOut": "分支比較請求逾時", - "commitDiffRequestTimedOut": "提交差異請求逾時", - "saveRequestTimedOut": "儲存請求逾時", - "reloadRequestTimedOut": "重載請求逾時", - "noChanges": "暫無變更。", - "noDiffOutput": "無差異輸出。", - "diffTitleWorkspace": "Diff · 工作區", - "diffDescriptionWorkingTree": "工作區變更(HEAD)", - "diffTitleFile": "差異 · {name}", - "compareTitleFile": "比較 · {name}", - "compareTitleBranch": "比較 · {branch}", - "compareDescriptionPath": "{path} · 與 {branch} 比較", - "compareDescriptionBranch": "與 {branch} 比較", - "diffTitleCommitFile": "差異 · {name} @ {hash}", - "diffTitleCommit": "差異 · {hash}", - "diffDescriptionCommitPath": "{path} · 提交 {commit}", - "diffDescriptionCommit": "提交 {commit}", - "diffTitleConflictFile": "衝突 · {name}", - "diffDescriptionConflict": "{path} · 磁碟與未儲存內容" - }, - "chat": { - "acpConnections": { - "actions": { - "openAgentsSettings": "打開 Agents 管理", - "retry": "重試" - }, - "agentsSetupHint": "點擊前往設定 > Agents 管理安裝。", - "withSetupHint": "{message}\n提示:{hint}", - "blocked": { - "missingConfig": "無法讀取目前 Agent 設定。", - "disabled": "{agent} 已在 Agents 管理中停用,請先啟用後再連線。", - "unavailable": "{agent} 目前平台不可用。", - "sdkMissing": "{agent} SDK 尚未安裝", - "adapterMissing": "{agent} 的 ACP 轉接器尚未安裝" - }, - "backendErrors": { - "initializeTimeout": "{agent} 連線交握逾時(60 秒未回應),請前往設定頁面檢查智能體與網路設定。", - "mcpRejectedByAgent": "附帶 codeg 的 MCP 伴生程序時,{agent} 拒絕了本次會話:{message} 如果該智能體不支援 MCP,請在設定中關閉它的「MCP 支援」後重新連線。", - "processExited": "{agent} 處理程序意外結束。", - "spawnFailed": "啟動 {agent} 失敗:{message}", - "downloadFailed": "{agent} 下載失敗:{message}", - "sessionLoadResourceNotFound": "{agent} 會話載入失敗,可重新載入重試,或開始新會話。", - "sessionLoadUnavailable": "{agent} 無法還原此會話,它可能已結束或 agent 已停止。可重新載入重試,或開始新會話。", - "turnFailedRefusal": "{agent} 拒絕繼續此輪回覆,通常代表後端或網關出錯,請檢查代理日誌。", - "turnFailedMaxTokens": "{agent} 已達到此輪回覆的最大 Token 限制。", - "turnFailedMaxTurnRequests": "{agent} 已達到此輪回覆允許的最大請求次數。", - "turnFailedUnknown": "{agent} 以未知的停止原因結束了此輪回覆。", - "grokModelSwitchIncompatibleAgent": "{agent} 無法在既有對話中切換到該模型,請新建工作階段以使用它。", - "turnFailedEmpty": "{agent} 此輪沒有產生任何回覆就結束了。", - "turnFailedEmptyProtocol": "{agent} 此輪的輸出 codeg 無法解析,可能是代理版本與協定不相符。", - "turnFailedEmptyMetadata": "{agent} 此輪只收到狀態更新(計畫 / 模式 / 用量),沒有收到任何回覆。", - "detailsInAlerts": "在狀態列的「警示」中展開詳情,即可查看代理輸出。" - }, - "unableReadAgentConfig": "無法讀取 Agent 設定:{message}", - "connectFailedTitle": "{agent} 連線失敗", - "toolFallbackTitle": "工具", - "eventErrorTitle": "Agent 錯誤", - "notificationTurnComplete": "{agent} 已完成回應", - "notificationError": "{agent} 錯誤:{message}", - "claudeApiRetry": { - "fallbackError": "authentication_failed", - "retryingWithMax": "正在重試 {attempt}/{max}", - "retryingAttempt": "正在重試(第 {attempt} 次)", - "retrying": "正在重試", - "nextRetryIn": "{seconds} 秒後重試", - "line": "{error}{status} · {retry}", - "lineWithDelay": "{error}{status} · {retry},{delay}", - "httpStatus": "(HTTP {status})" - }, - "configOptionAdjusted": "{agent} 把{option}設成了 {actual},而不是 {requested}" - }, - "connectionLifecycle": { - "tasks": { - "connectingTitle": "正在連線 {agent}", - "connectingDescription": "正在建立連線", - "loadingSelectorsTitle": "正在載入 {agent} 選擇項", - "loadingSelectorsDescription": "正在取得模式與會話設定選項", - "initSessionTitle": "正在初始化 {agent} 會話", - "initSessionDescription": "正在建立會話並載入設定" - }, - "errors": { - "connectionFailed": "連線失敗", - "sendPromptFailed": "訊息傳送失敗:{error}" - } - }, - "shared": { - "attachedResources": "附加資源", - "toolCallFailed": "工具呼叫失敗" - }, - "messageThread": { - "emptyTitle": "暫無訊息", - "emptyDescription": "開始一個會話後,訊息會顯示在這裡" - }, - "chatInput": { - "connecting": "連線中...", - "agentResponding": "{agent} 正在回應...", - "sendMessage": "傳送訊息..." - }, - "messageInput": { - "askAnything": "請開始輸入...", - "removeAttachmentAria": "移除 {name}", - "attachFiles": "附加檔案", - "addActions": "新增", - "quickMessages": "快捷訊息", - "quickMessagesEmpty": "尚無快捷訊息", - "quickMessagesLoading": "載入中...", - "pasteAsPlainText": "貼上純文字", - "cut": "剪下", - "copy": "複製", - "selectAll": "全選", - "pasteUnavailable": "無法讀取剪貼簿,請改用 Ctrl/⌘V 貼上。", - "clipboardWriteFailed": "無法寫入剪貼簿,請改用鍵盤快速鍵。", - "quickMessageUntitled": "未命名", - "liveFeedback": "即時回饋", - "liveFeedbackDisabledHint": "智能體工作時可傳送", - "dropFilesToAttach": "拖曳檔案到此處附加", - "loadingSettings": "正在載入設定...", - "loadingMode": "正在載入模式...", - "modeLabel": "模式", - "toggleOn": "開", - "toggleOff": "關", - "agentSettings": "智能體設定", - "searchModel": "搜尋模型...", - "searchModelAria": "搜尋模型", - "modelListLabel": "模型", - "noModels": "找不到模型", - "cancel": "取消", - "send": "傳送", - "forkAndSend": "分叉發送", - "queueMessage": "加入佇列", - "steerIntoTurn": "插入目前回合", - "steerQueuedInstead": "已轉入佇列——將隨下一回合傳送。", - "steerFailed": "無法插入目前回合", - "steerAttachmentsUnsupported": "僅支援純文字——帶附件的草稿請走佇列。", - "slashCommands": "斜線命令", - "slashSearchPlaceholder": "搜尋命令...", - "slashSearchEmpty": "沒有符合的指令", - "experts": "專家", - "office": "日常辦公", - "research": "科學研究", - "attachLocalUpload": "附加本機檔案", - "attachServerFile": "附加伺服器檔案", - "attachUploadTooLarge": "{names} 超過 {limit}MB 上傳上限,已略過。", - "attachUploadFailed": "上傳失敗:{names}。", - "attachUploadNotAFile": "{names} 不是常規檔案(目錄或特殊檔案),已略過。", - "attachUploadQuotaExceeded": "伺服器上傳空間已用盡,{names} 未能上傳。", - "attachUploadInProgress": "圖片仍在上傳中,請稍候再傳送。", - "mentionEmpty": "無相符項目", - "mentionLoading": "搜尋中…", - "mentionListLabel": "提及", - "mentionMore": "還有更多結果,繼續輸入以篩選", - "mentionCount": "{count, plural, other {# 項結果}}", - "mentionGroupFile": "檔案", - "mentionGroupAgent": "智能體", - "mentionGroupSession": "工作階段", - "mentionGroupCommit": "提交", - "mentionGroupSkill": "技能" - }, - "messageQueue": { - "addToQueue": "加入佇列", - "saveEdit": "儲存", - "cancelEdit": "取消編輯", - "editItem": "編輯", - "deleteItem": "刪除" - }, - "welcomeInputPanel": { - "agentsSettingsPath": "設定 > Agents", - "autoConnectFallback": "點擊前往 {path} 管理安裝。", - "autoConnectAppend": "{message},點擊前往 {path} 管理安裝。", - "enableAgentFirstPlaceholder": "請先啟用至少一個 Agent 後開始會話...", - "prepareSessionFailed": "無法準備聊天工作階段,請重試。", - "createConversationFailed": "無法建立會話,請重試。", - "askAnythingPlaceholder": "請開始輸入...", - "agentNotInstalled": "{agent} 尚未安裝 · 點擊前往 Agents 設定安裝", - "agentAdapterNotInstalled": "{agent} 的 ACP 轉接器尚未安裝(與你本機的 CLI 無關)· 點擊前往 Agents 設定安裝" - }, - "welcomePanel": { - "greeting": "今天打算做些什麼呢?", - "tips": { - "tileTabs": "右鍵點擊會話標籤選擇「平鋪顯示」,可同螢幕對比多個會話", - "pinTab": "雙擊會話標籤可將其固定,避免被新開啟的會話自動取代", - "shortcutsNewSearch": "{newConversation} 快速新建會話,{searchConversations} 搜尋歷史會話", - "slashAtMention": "在輸入框輸入 / 觸發斜線命令,輸入 @ 引用專案內檔案", - "pasteDropFiles": "直接貼上截圖或把檔案拖到輸入框,即可作為附件", - "queueMessage": "智能體回覆中也能繼續輸入並排隊,回答完畢會自動續發", - "draftAutoSave": "未發送的草稿會自動儲存,重新開啟會話仍在", - "forkSend": "傳送按鈕旁的下拉選擇「分叉傳送」,從目前位置開一條新分支", - "exportConversation": "右鍵會話內容區可匯出為 Markdown / HTML / 圖片", - "chatChannels": "在「設定 → 聊天頻道」接入 Telegram / 飛書 / 微信,從手機繼續操作", - "shortcutsAuxPanel": "{toggleAuxPanel} 切換右側面板,檢視本次會話改動的檔案與 Git 變更", - "shortcutsTerminalSidebar": "{toggleTerminal} 開啟內建終端機,{toggleSidebar} 切換側邊欄", - "customShortcuts": "所有快捷鍵都可在「設定 → 快捷鍵」中自訂", - "webService": "開啟「設定 → Web 服務」後,團隊成員可從瀏覽器接入同一臺 codeg", - "fusionMode": "開啟檔案或差異後,會自動與會話並排顯示", - "quickMessages": "點輸入框旁的 + 按鈕選擇「快捷訊息」,可一鍵插入預存片段(在「設定 → 快捷訊息」中管理)", - "experts": "透過 + 按鈕裡的「專家技能」可一鍵載入預設角色(除錯 / 規劃等)", - "taskBoard": "「待辦任務」能把一條待辦從頭跑到尾:智能體在獨立工作樹裡執行,你檢視完差異再合併。", - "automations": "「自動化」按排程定時執行儲存好的提示詞(例如每晚一次程式碼審查),還能讓每次執行都開一個獨立工作樹。", - "tokenUsage": "點擊狀態列左下角的會話數即可開啟「Token 用量」,按日期、智能體、模型與資料夾拆分統計。", - "mentionTargets": "@ 不只能引用檔案:還能 @ 另一個智能體把子任務交給它,或引用歷史會話、某次提交、某個技能。", - "splitGroups": "右鍵點擊標籤選擇「向右拆分」或「向下拆分」,兩個會話各佔一個分割區同時開著。", - "worktrees": "點開分支按鈕選「新增工作樹」,多個智能體就能在同一個儲存庫並行工作,互不覆蓋彼此的檔案。", - "importSessions": "之前在終端機裡跑過的會話,用資料夾右鍵選單的「匯入本地會話」就能把那段歷史接進 codeg。", - "subSessions": "智能體委派出去的子會話會巢狀顯示在側邊欄的父會話底下,展開就能追蹤每一個子會話做了什麼。", - "liveFeedback": "「+」選單裡的「即時回饋」能把一則便條塞進智能體正在跑的這一輪,不用打斷它。", - "skillPacks": "設定 → 技能包 裡打包了程式專家、科研與辦公三類技能,可以按智能體分別開關。", - "modelProviders": "設定 → 模型供應商 支援填自己的 API key 或端點位址,之後直接在輸入框裡切換模型。", - "workspaceBackground": "設定 → 外觀 裡可以換工作區背景圖、調面板不透明度,還能換應用程式字型。" - }, - "quickActions": { - "excel": "Excel 活頁簿", - "excelDesc": "資料表、公式與圖表", - "word": "Word 文件", - "wordDesc": "報告、信函與備忘錄", - "ppt": "簡報", - "pptDesc": "專業設計的投影片", - "pitchDeck": "募資簡報", - "pitchDeckDesc": "含關鍵指標的募資簡報", - "morph": "Morph 動畫", - "morphDesc": "電影級投影片轉場", - "morph3d": "3D Morph", - "morph3dDesc": "3D 模型與鏡頭運動", - "academic": "學術論文", - "academicDesc": "含引用與結構的研究論文", - "financial": "財務模型", - "financialDesc": "報表、DCF 與預測", - "dashboard": "資料儀表板", - "dashboardDesc": "從資料產生 KPI 與分析", - "prompts": { - "excel": "建立一個 Excel 活頁簿,需求如下:\n\n[在此描述你的資料、表格、公式與圖表]", - "word": "建立一個 Word 文件,需求如下:\n\n[在此描述文件內容、結構與排版]", - "ppt": "建立一個 PowerPoint 簡報,需求如下:\n\n[在此描述投影片、內容與設計]", - "pitchDeck": "建立一個募資簡報,需求如下:\n\n[在此描述公司、募資輪次與關鍵指標]", - "morph": "建立一個帶 Morph 轉場動畫的簡報:\n\n[在此描述簡報主題與期望的視覺效果]", - "morph3d": "建立一個帶 GLB 模型與鏡頭運動的 3D Morph 簡報:\n\n[在此描述主題與 3D 視覺構想]", - "academic": "用 Word 撰寫一篇學術論文,需求如下:\n\n[在此描述研究主題、方法與主要發現]", - "financial": "用 Excel 建立一個財務模型,需求如下:\n\n[在此描述財務報表、預測與分析]", - "dashboard": "用 Excel 建立一個資料儀表板,需求如下:\n\n[在此描述資料來源、KPI 與圖表]", - "scientific-brainstorming": "幫我進行科研腦力激盪:探索跨學科連結、挑戰假設、發掘有潛力的研究缺口。我正在探索的方向:", - "hypothesis-generation": "幫我把這些觀察轉化為可檢驗的假設:提出明確預測、合理機制,並設計驗證實驗。我的觀察:", - "experimental-design": "在蒐集資料前幫我設計嚴謹的實驗:設計方案、隨機化、對照,以及如何避免干擾。我想研究的問題:", - "statistical-power": "幫我確定所需樣本數:為我的設計做檢定力分析(效應量、顯著水準、檢定力)。具體資訊:", - "statistical-analysis": "幫我正確分析這份資料:選擇合適的檢定、檢查假設、報告效應量並撰寫結論。我的資料與問題:", - "exploratory-data-analysis": "對我的資料檔案做探索性分析:概述其結構、品質與值得注意的模式,並建議後續步驟。檔案是:", - "scientific-visualization": "幫我製作出版級圖表:清晰佈局、真實誤差棒、色盲友善配色,以及期刊格式。我想展示的內容:", - "scientific-critical-thinking": "幫我批判性評估這項研究或主張:評估證據品質、辨識偏誤與干擾,並權衡結論。內容如下:", - "paper-lookup": "幫我在學術資料庫中查找相關論文與開放取用全文,並提供可重用的引用。我要找的是:" - }, - "paper-lookup": "論文檢索", - "paper-lookupDesc": "檢索 10 個學術 API(PubMed、arXiv、OpenAlex、Crossref…)查找論文、引用與開放取用全文。", - "scientific-critical-thinking": "批判性思維", - "scientific-critical-thinkingDesc": "評估科學主張與證據品質:辨識偏誤與干擾,運用 GRADE 與偏誤風險框架。", - "scientific-visualization": "科學視覺化", - "scientific-visualizationDesc": "出版級圖表:多面板佈局、顯著性標註與期刊專屬格式。", - "exploratory-data-analysis": "探索性資料分析", - "exploratory-data-analysisDesc": "對 200+ 種格式的科學資料檔案做自動化探索,輸出品質指標與報告。", - "statistical-analysis": "統計分析", - "statistical-analysisDesc": "引導式統計分析:檢定選擇、假設檢查、效應量與 APA 格式報告。", - "statistical-power": "統計檢定力", - "statistical-powerDesc": "樣本數與統計檢定力分析:所需樣本數、最小可檢測效應與檢定力曲線。", - "experimental-design": "實驗設計", - "experimental-designDesc": "在蒐集資料前設計嚴謹研究:隨機化、區集、對照與析因/DOE 佈局。", - "hypothesis-generation": "假設生成", - "hypothesis-generationDesc": "將觀察轉化為可檢驗的假設,提出預測、機制並設計驗證實驗。", - "scientific-brainstorming": "科學腦力激盪", - "scientific-brainstormingDesc": "開放式科研構思:探索跨學科連結、挑戰假設、發掘研究缺口。", - "tabs": { - "office": "日常辦公", - "coding": "程式開發", - "research": "科學研究" - }, - "coding": { - "brainstormingDesc": "動手前先梳理意圖與需求", - "debuggingDesc": "先定位根因再提出修復", - "writingSkillsDesc": "建立、編輯並驗證可重用技能" - }, - "notEnabled": { - "title": "「{skill}」技能尚未對 {agent} 啟用", - "description": "前往設定啟用後即可在此使用。", - "action": "前往啟用", - "hint": "技能未啟用" - }, - "scrollPrev": "顯示上一組技能", - "scrollNext": "顯示下一組技能" - } - }, - "agentSelector": { - "noEnabledAgents": "暫無已啟用的 Agent", - "openAgentsSettings": "開啟 Agents 設定", - "notInstalled": "未安裝", - "moreAgents": "更多 Agent({count})" - }, - "subAgentOverlay": { - "title": "子智能體", - "collapsedSummary": "子智能體 {count}", - "collapseAria": "摺疊子智能體" - }, - "agentPlanOverlay": { - "title": "計畫任務", - "collapsePlanAria": "摺疊計畫", - "collapsedSummary": "計畫 {completed}/{total}", - "status": { - "completed": "已完成", - "inProgress": "進行中", - "pending": "待處理", - "unknown": "未知" - }, - "priority": { - "high": "高", - "medium": "中", - "low": "低", - "unknown": "未知" - } - }, - "permissionDialog": { - "subtitle": "Agent 請求繼續目前輪次的權限。", - "queuedCount": "還有 {count} 項待審批", - "kindFallbackTool": "工具", - "command": "命令", - "cwd": "工作目錄:{cwd}", - "filesSummary": "檔案:{count}", - "moreFiles": "+{count} 個更多檔案", - "plan": "計畫", - "allowedActions": "允許的操作", - "targetMode": "目標模式:{mode}", - "optionGrants": "各選項將授予的權限", - "changeScopeSession": "本次工作階段", - "changeScopeProcess": "本次執行", - "changeScopeUser": "儲存至使用者設定", - "changeScopeProject": "儲存至專案設定", - "changeScopeProjectLocal": "儲存至本機專案設定", - "changeScopePersistent": "永久儲存" - }, - "questionDialog": { - "title": "代理正在提問", - "placeholder": "輸入你的回答...", - "send": "傳送" - }, - "messageBranch": { - "previousBranchAria": "上一個分支", - "nextBranchAria": "下一個分支", - "pageOf": "{current} / {total}" - }, - "terminal": { - "title": "終端", - "running": "執行中" - }, - "reasoning": { - "thinking": "思考中…", - "thoughtForFewSeconds": "思考", - "thoughtForSeconds": "思考" - }, - "linkSafety": { - "errorCannotOpen": "無法開啟本地檔案", - "errorNoWorkspace": "目前沒有活躍的工作區資料夾。", - "errorFailedOpen": "開啟本地檔案失敗", - "errorFailedLink": "開啟連結失敗", - "errorUnsupportedLinkProtocol": "不支援此連結協議。" - }, - "fileActions": { - "openInFinder": "在 Finder 開啟", - "openInExplorer": "在檔案總管開啟", - "openInFileManager": "在檔案管理器開啟", - "copyRelativePath": "複製相對路徑", - "copyAbsolutePath": "複製絕對路徑", - "pathCopied": "已複製路徑", - "copyPathFailed": "複製路徑失敗", - "openFailed": "開啟本地檔案失敗" - }, - "messageList": { - "attachedResources": "附加資源", - "loading": "載入中...", - "loadEarlier": "載入更早的訊息", - "loadingEarlier": "正在載入更早的訊息…", - "error": "錯誤:{message}", - "errorTitle": "會話載入失敗", - "errorActionReload": "重新載入", - "errorActionNewSession": "新建會話", - "emptyConversation": "目前會話暫無訊息。", - "systemMessage": "系統訊息", - "copyMessage": "複製", - "copied": "已複製", - "downloadImage": "下載圖片", - "downloadFailed": "下載失敗:{message}", - "imageGeneration": "圖片生成", - "imageGenerationPending": "正在生成圖片…", - "imageGenerationFailed": "圖片生成失敗", - "model": "模型", - "tokenStats": "Token 使用情況", - "tokenInput": "輸入", - "tokenOutput": "輸出", - "tokenCacheRead": "快取讀取", - "tokenCacheWrite": "快取寫入", - "duration": "耗時", - "completedAt": "完成時間", - "jumpToPreviousUserMessage": "跳轉到上一條使用者訊息", - "showMore": "展開", - "showLess": "收合" - }, - "liveTurnStats": { - "thinking": "思考中...", - "streaming": "生成中", - "elapsedHours": "{value} 小時", - "elapsedMinutes": "{value} 分鐘", - "elapsedSeconds": "{value} 秒", - "outputSpeedAria": "估算輸出速度", - "outputSpeedTooltip": "估算輸出速度(正文 + 思考)" - }, - "jsonTree": { - "viewRaw": "檢視原始 JSON", - "viewTree": "檢視樹狀檢視", - "fields": "{count} 個欄位", - "items": "{count} 項" - }, - "tool": { - "parameters": "參數", - "error": "錯誤", - "result": "結果", - "status": { - "approvalRequested": "等待授權", - "approvalResponded": "已回應", - "inputAvailable": "執行中", - "inputStreaming": "等待中", - "outputAvailable": "已完成", - "outputDenied": "已拒絕", - "outputError": "錯誤" - } - }, - "toolCallBlock": { - "tool": "工具", - "error": "錯誤", - "result": "結果" - }, - "delegation": { - "subAgentRunning": "子代理執行中…", - "noDetail": "暫無詳情。", - "unknownAgent": "子智慧體", - "openDetail": "檢視會話", - "detailTitle": "子智慧體會話", - "detailDescription": "唯讀檢視委派給子智慧體的會話內容。", - "waitForResult": "等待 {task} 任務執行結果", - "waitForResultNoTask": "等待任務執行結果", - "cancelTask": "取消 {task} 任務", - "cancelTaskNoTask": "取消任務", - "resultPageOf": "{current} / {total}", - "prevResult": "上一個結果", - "nextResult": "下一個結果", - "noResultText": "本次檢查暫無結果", - "status": { - "starting": "啟動中", - "running": "執行中", - "checked": "已查詢", - "waiting": "待批准", - "ok": "完成", - "err": { - "default": "失敗", - "delegation_disabled": "已停用", - "depth_limit": "深度超限", - "invalid_agent_type": "代理類型無效", - "spawn_failed": "啟動失敗", - "send_failed": "傳送失敗", - "timeout": "逾時", - "canceled": "已取消", - "child_refusal": "子代理拒絕", - "child_max_tokens": "子代理超出 token 上限", - "child_max_turn_requests": "子代理超出請求上限", - "child_empty": "子代理無回應", - "child_unknown": "子代理未知錯誤", - "unknown": "未知任務" - } - } - }, - "contentParts": { - "showingTailOutput": "為確保效能,串流輸出時僅顯示尾端內容。", - "result": "結果", - "unknown": "未知", - "inputTruncated": "輸入已截斷,diff 可能不完整。", - "replaceAll": "全部替換", - "filesCount": "檔案:{count}", - "update": "更新", - "moreFiles": "+{count} 個更多檔案", - "timeoutMs": "逾時:{timeout}ms", - "backgroundTrue": "背景:true", - "scriptToolCalls": "呼叫 {count} 個工具", - "offset": "位移:{offset}", - "limit": "限制:{limit}", - "pages": "頁碼:{pages}", - "mode": "模式:{mode}", - "cell": "儲存格:{cell}", - "shellSession": "工作階段 {id}", - "pathLabel": "路徑:", - "globLabel": "Glob:", - "typeLabel": "類型:", - "outputLabel": "輸出:", - "caseInsensitive": "不區分大小寫", - "multiline": "多行", - "promptLabel": "提示詞", - "subjectLabel": "主題", - "taskLabel": "任務", - "nameLabel": "名稱:", - "agentPromptLabel": "提示詞", - "agentModelLabel": "模型", - "agentRunning": "執行中...", - "agentLiveTranscript": "即時活動", - "agentProgressTools": "{count} 次工具調用", - "agentProgressTurns": "{count} 輪", - "agentProgressContext": "上下文 {pct}%", - "agentSessionAction": "檢視子智慧體工作階段", - "agentSessionTitle": "子智慧體工作階段", - "agentSessionLoading": "正在載入子智慧體的對話記錄…", - "agentSessionEmpty": "子智慧體尚未寫入任何內容。", - "agentFallbackTitle": "子智能體啟動中…", - "agentCodexLaunchOnly": "已啟動。Codex 不會再回報這個子智能體的進度——它的結果會以一則訊息出現在本工作階段中。", - "agentStatsBash": "命令", - "agentStatsRead": "讀取檔案", - "agentStatsSearch": "搜尋", - "agentStatsEdit": "編輯", - "agentStatsOther": "其他", - "goal": { - "title": "目標:", - "titleWithStatus": "目標{status}", - "objective": "目標", - "statusLabel": "狀態", - "tokensUsed": "已用 tokens", - "budget": "預算", - "remaining": "剩餘", - "elapsed": "耗時", - "tokens": "tokens", - "pause": "暫停", - "clear": "清除", - "status": { - "active": "進行中", - "paused": "已暫停", - "blocked": "受阻", - "usageLimited": "用量受限", - "budgetLimited": "預算受限", - "complete": "已完成", - "limited": "已達上限" - } - }, - "field": { - "file": "檔案", - "notebook": "筆記本", - "command": "命令", - "old": "舊內容", - "new": "新內容", - "pattern": "模式", - "path": "路徑", - "query": "查詢", - "url": "URL 位址", - "description": "描述", - "content": "內容", - "source": "來源內容", - "prompt": "提示詞", - "subject": "主題", - "taskId": "任務 ID", - "status": "狀態", - "skill": "Skill", - "args": "參數", - "offset": "位移", - "limit": "限制", - "glob": "Glob", - "type": "類型", - "output": "輸出", - "replaceAll": "全部替換", - "language": "語言", - "timeout": "逾時", - "background": "背景", - "agentType": "Agent 類型", - "library": "函式庫", - "libraryId": "函式庫 ID" - }, - "title": { - "edit": "編輯", - "command": "命令", - "script": "腳本", - "waitCommand": "等待 {command}", - "waitCell": "等待工作階段 {id}", - "terminateCommand": "終止 {command}", - "terminateCell": "終止工作階段 {id}", - "stdinChars": "輸入 {chars}", - "todoWrite": "待辦", - "read": "讀取", - "write": "寫入", - "notebookEdit": "Notebook 編輯", - "editFiles": "編輯({count} 個檔案)", - "editWithTarget": "編輯 {target}", - "readWithTarget": "讀取 {target}", - "writeWithTarget": "寫入 {target}", - "notebookEditWithTarget": "Notebook 編輯 {target}", - "globWithPattern": "Glob {pattern}", - "listFilesWithPath": "列出檔案 {path}", - "grepWithPattern": "Grep {pattern}", - "taskCreateWithSubject": "建立任務:{subject}", - "taskUpdateWithStatus": "更新任務 #{id} -> {status}", - "taskUpdate": "更新任務 #{id}", - "webFetchWithUrl": "擷取網頁 {url}", - "webSearchWithQuery": "網頁搜尋:{query}", - "todosProgress": "待辦({done}/{total})", - "skillWithName": "Skill:{name}", - "genericWithContext": "{tool}:{context}" - }, - "search": { - "noMatches": "無相符結果", - "matchSummary": "{matches} 處相符 · {files} 個檔案", - "fileSummary": "{files} 個檔案", - "moreResults": "另有 {count} 筆結果未顯示" - }, - "toolGroup": { - "search": "搜尋 {count} 次", - "command": "執行 {count} 個指令", - "read": "讀取 {count} 次檔案", - "memory": "回憶 {count} 項記憶", - "edit": "編輯 {count} 次檔案", - "fetch": "抓取 {count} 個資源", - "think": "思考 {count} 次", - "todo": "更新 {count} 項待辦", - "task": "執行 {count} 個任務", - "other": "呼叫 {count} 個工具", - "errorSuffix": "{count} 個失敗", - "joiner": " · " - }, - "planMode": { - "entered": "進入計畫模式", - "planLabel": "計畫", - "reviewApproved": "已核准執行計畫", - "reviewKept": "維持在計畫模式", - "reviewPending": "等待計畫決定", - "submitted": "計畫已提交", - "switched": "切換模式" - }, - "backgroundTask": { - "title": "背景任務", - "titleWithId": "背景任務 · {id}", - "running": "執行中", - "completed": "已完成", - "failed": "失敗", - "stopped": "已停止", - "exitCode": "退出碼 {code}", - "polledTimes": "輪詢 {count} 次", - "runningInBackground": "背景執行", - "launchNote": "已在背景執行 · {id}" - }, - "codexScript": { - "outputMissing": "codex 截斷指令碼輸出時捨棄了這個命令的分隔行,因此沒有輸出可歸屬給它。", - "sharedWith": "本段還包含 {commands} 的輸出——它們的分隔行已被 codex 截斷捨棄。", - "truncated": "已截斷" - } - }, - "messageNav": { - "title": "訊息導覽", - "collapse": "收合訊息導覽", - "collapsedSummary": "訊息 {count}", - "fileCount": "{count} 個檔案", - "remove": "移除", - "noDiffDataAvailable": "找不到 {filePath} 的差異資料" - }, - "replyArtifacts": { - "title": "變更檔案", - "fileCount": "{count} 個檔案", - "newFilesTitle": "新增檔案", - "revealInFolder": "在 Finder/檔案總管中顯示", - "openFile": "開啟 {filePath}", - "openInEditor": "在編輯器中開啟", - "remove": "移除", - "noDiffDataAvailable": "找不到 {filePath} 的差異資料" - }, - "askQuestion": { - "title": "智能體需要你的選擇", - "subtitle": "回答後點擊提交,可隨時跳過", - "recommended": "推薦", - "other": "其他", - "otherPlaceholder": "輸入你的回答…", - "singleSelect": "單選", - "multiSelect": "多選", - "skip": "略過", - "next": "下一題", - "submit": "提交", - "submitError": "提交失敗,請重試。" - }, - "planApproval": { - "title": "智慧代理已提出計畫——請審閱", - "emptyPlan": "智慧代理未寫入計畫。可核准開始實作,或要求修改。", - "approve": "核准並開始", - "requestChanges": "要求修改", - "abandon": "放棄", - "feedbackPlaceholder": "需要修改什麼?", - "sendChanges": "傳送", - "cancel": "取消", - "submitError": "提交失敗,請重試。" - }, - "feedbackCheckResult": { - "count": "{count} 則回饋", - "expand": "展開全部回饋", - "collapse": "收合", - "errorTitle": "回饋檢查失敗" - }, - "askQuestionResult": { - "title": "提問", - "answeredLabel": "提問回答:", - "awaiting": "等待你的回答…", - "declined": "你已略過此問題 — 代理已自行判斷。", - "noSelection": "未選擇" - }, - "configStale": { - "agentConfigTitle": "智能體設定已更新", - "modelProviderTitle": "模型供應商已更新", - "description": "目前的工作階段仍在使用舊設定,重新連線後生效(對話紀錄不會遺失)。", - "reconnect": "重新連線以套用", - "reconnecting": "正在重新連線…", - "reconnectDisabledDuringTurn": "目前回合結束後可重新連線", - "dismiss": "忽略", - "reconnectFailed": "重新連線工作階段失敗", - "applied": "已套用新設定" - }, - "piProjectTrust": { - "title": "此專案自帶 pi 資源", - "description": "pi 未載入儲存庫自帶的 .pi 檔案。請檢視後決定。", - "descriptionExecutable": "儲存庫自帶 pi 擴充功能,擴充功能會在啟動時執行程式碼。pi 尚未載入它們,請先檢視再決定。", - "review": "檢視…", - "dismiss": "忽略", - "dialogTitle": "信任此專案的 pi 資源?", - "dialogDescription": "只有在你信任該目錄後,pi 才會載入儲存庫自帶的 .pi 檔案。請僅在你信任此儲存庫內容時才信任。", - "executionWarning": "擴充功能就是程式碼。信任該目錄後,儲存庫中的擴充功能會在 pi 啟動時以你的權限執行——早於你送出任何訊息。", - "scopeNote": "此決定儲存在 pi 的 trust.json 中,對該目錄下的所有子目錄同樣生效,你在終端機自行執行 pi 時也會沿用。之後可在「設定 → 智慧代理 → Pi」中修改。", - "trust": "信任專案", - "decline": "保持不載入", - "disabledDuringTurn": "目前回合結束後可用", - "trustedToast": "已信任專案——已重新連線以便 pi 載入其資源", - "declinedToast": "專案資源保持不載入", - "saveFailed": "儲存專案信任決定失敗", - "grantTitle": "此專案已被信任", - "grantDescription": "pi 會載入此儲存庫自帶的 .pi 檔案。請檢視這代表什麼。", - "grantInheritedDescription": "某個上層目錄已被信任,因此 pi 會載入此儲存庫自帶的 .pi 檔案。請檢視這代表什麼。", - "grantDialogTitle": "此專案的 pi 資源已被信任", - "grantDialogDescription": "pi 被允許載入此儲存庫自帶的 .pi 檔案。舊版 codeg 會在你開啟目錄時自動授予此權限,因此你可能從未被詢問過。", - "grantExecutionWarning": "擴充功能就是程式碼。儲存庫中的擴充功能會在 pi 啟動時以你的權限執行——早於你送出任何訊息。", - "inheritedFrom": "信任來自", - "revoke": "撤銷信任", - "keepTrusted": "保持信任", - "revokedToast": "已撤銷信任——已重新連線,pi 不再載入此專案的資源", - "trustedNoReconnect": "已信任專案——將在 pi 下次啟動時生效", - "revokedNoReconnect": "已撤銷信任——將在 pi 下次啟動時生效" - }, - "collabAgent": { - "title": "子智能體", - "errorTitle": "子智能體任務失敗", - "statesLabel": "子智能體", - "statusRunning": "執行中", - "statusCompleted": "已完成", - "statusFailed": "失敗", - "statusPending": "初始化中", - "statusInterrupted": "已中斷", - "statusClosed": "已關閉", - "statusNotFound": "未找到", - "opSpawn": "啟動子智能體", - "opWait": "取得子智能體結果", - "opClose": "結束子智能體", - "opResume": "恢復子智能體" - }, - "contextCompaction": { - "compacting": "正在壓縮上下文…", - "compacted": "上下文已壓縮", - "compactedTokens": "上下文已壓縮 · {before} → {after} tokens", - "failed": "上下文壓縮失敗" - }, - "sessionFailure": { - "category": { - "connection": "連線異常", - "access": "存取受限", - "limit": "已達限制", - "request": "請求被拒絕", - "service": "服務異常", - "unknown": "會話異常" - }, - "action": { - "retry": "重試", - "login": "去登入", - "newSession": "新增會話" - }, - "recovered": "已恢復", - "retryUnavailable": "沒有可重發的訊息。", - "toggleDetails": "展開/收合詳情" - }, - "backgroundTasks": { - "running": "{count} 個背景任務執行中", - "settling": "正在同步背景結果…", - "settledFallback": "背景任務已結束({status})", - "cardRunning": "背景執行中", - "cardLaunchedPending": "已啟動背景任務", - "cardCompleted": "背景任務已完成", - "cardFinishedWithStatus": "背景任務已結束({status})", - "cardResultPending": "結果尚未返回" - }, - "proposedPlan": { - "title": "計劃提案", - "planning": "規劃中…" - } - }, - "diffPreview": { - "mode": { - "added": "新增", - "deleted": "刪除", - "renamed": "重新命名", - "modified": "修改" - }, - "hunkLabel": "區塊 {index}", - "loadingHunk": "正在載入區塊...", - "noDiffData": "無差異資料", - "showRemainingLines": "顯示剩餘 {count} 行" - }, - "conversationContextBar": { - "folderTitle": "工作資料夾", - "branchTitle": "工作分支", - "searchFolder": "Search folder...", - "searchBranch": "Search branch...", - "noFolders": "No folders", - "noBranches": "No branches", - "noBranch": "(no branch)", - "chatModeLabel": "聊天模式", - "commit": "Commit", - "push": "Push", - "merge": "Merge", - "toasts": { - "folderChanged": "Switched to {name}", - "openFolderFailed": "Failed to open folder", - "switchedToChatMode": "已切換到聊天模式", - "openStashFailed": "Failed to open stash window", - "openMergeFailed": "Failed to open merge window" - } - }, - "cloneDialog": { - "title": "複製倉庫", - "repositoryUrl": "倉庫地址", - "repositoryUrlPlaceholder": "https://github.com/user/repo.git", - "directory": "目錄", - "directoryPlaceholder": "選擇目標目錄...", - "browseDirectory": "瀏覽目錄", - "cancel": "取消", - "clone": "複製", - "clonePath": "克隆路徑: {path}" - }, - "toasts": { - "cloneFailed": "複製倉庫失敗" - } - }, - "ProjectBoot": { - "title": "專案啟動器", - "tabs": { - "shadcn": "shadcn", - "hyperframes": "HyperFrames" - }, - "hyperframes": { - "title": "HyperFrames 影片專案", - "subtitle": "建立一個 HTML 轉影片專案,接著工作區的智慧代理即可撰寫並算繪它。", - "resolution": "解析度", - "skillsTitle": "智慧代理技能", - "skillsDesc": "為所選代理全域安裝 HyperFrames 技能(符號連結),讓它們會編寫並算繪影片。", - "recheck": "重新檢查", - "installedBadge": "已安裝", - "skillsInstall": "安裝 / 更新技能", - "skillsInstalling": "正在安裝技能…", - "skillsInstalled": "HyperFrames 技能安裝成功", - "skillsInstallFailed": "HyperFrames 技能安裝失敗" - }, - "config": { - "base": "基礎庫", - "style": "風格", - "baseColor": "基礎顏色", - "theme": "主題", - "chartColor": "圖表顏色", - "iconLibrary": "圖示庫", - "font": "字體", - "fontHeading": "標題字體", - "menuAccent": "選單強調", - "menuColor": "選單顏色", - "radius": "圓角", - "template": "模板", - "createProject": "建立專案", - "sectionStyle": "風格", - "sectionColors": "配色", - "sectionTypography": "排版", - "sectionInterface": "介面" - }, - "preview": { - "loading": "載入預覽..." - }, - "createDialog": { - "title": "建立專案", - "projectName": "專案名稱", - "projectNamePlaceholder": "my-app", - "frameworkTemplate": "框架模板", - "packageManager": "套件管理器", - "saveDirectory": "儲存目錄", - "saveDirectoryPlaceholder": "選擇目錄...", - "browseDirectory": "瀏覽", - "projectPath": "專案將建立在:{path}", - "advancedOptions": "進階選項", - "base": "基礎庫", - "enableRtl": "啟用 RTL 支援", - "enableRtlDescription": "為從右到左書寫的語言(如阿拉伯語、希伯來語)啟用佈局支援", - "pmChecking": "正在檢測...", - "pmNotInstalled": "未安裝", - "cancel": "取消", - "create": "建立", - "creating": "正在建立專案..." - }, - "toasts": { - "createFailed": "建立專案失敗", - "createSuccess": "專案建立成功", - "openWorkspaceFailed": "專案已建立,但無法在工作區中開啟" - }, - "errors": { - "directoryExists": "目標目錄已存在", - "commandFailed": "專案建立命令執行失敗。" - } - }, - "WebServiceSettings": { - "addressSwitchHint": "切換只會改變這裡顯示與開啟的位址;服務會監聽所有網路介面,每個位址都可存取。", - "sectionTitle": "Web 服務", - "sectionDescription": "啟用後可透過瀏覽器遠端存取 Codeg", - "port": "連接埠", - "status": "狀態", - "autoStart": "自動啟動", - "autoStartHint": "Codeg 啟動時自動開啟 Web 服務", - "running": "執行中", - "stopped": "已停止", - "processing": "處理中...", - "start": "啟動", - "stop": "停止", - "startFailed": "啟動失敗", - "stopFailed": "停止失敗", - "saveConfigFailed": "儲存 Web 服務設定失敗", - "open": "開啟", - "hide": "隱藏", - "show": "顯示", - "copy": "複製", - "qrcode": "QR 碼", - "qrcodeTitle": "掃碼開啟", - "qrcodeHint": "用手機掃描,在瀏覽器中開啟 Codeg", - "addressLabel": "存取位址", - "tokenLabel": "存取 Token", - "tokenHint": "Web 用戶端首次存取時需輸入此 Token", - "tokenPlaceholder": "留空則自動產生", - "regenerate": "重新產生", - "stalePortOccupiedTitle": "連接埠 {port} 已被其他行程佔用", - "stalePortUnknownTitle": "連接埠 {port} 狀態不明", - "stalePortHint": "在連接埠釋放前 Codeg 無法繫結。可以更換上方的連接埠,或結束佔用該連接埠的行程。", - "errors": { - "alreadyRunning": "Web 服務已在執行", - "invalidAddress": "主機或連接埠格式無效", - "portInUse": "連接埠 {port} 已被佔用,請關閉佔用的程式或改用其他連接埠", - "permissionDenied": "權限不足,請使用 1024 以上的連接埠,或以更高權限執行", - "addressUnavailable": "該位址在本機不可用", - "bindFailed": "綁定位址失敗" - } - }, - "DirectoryBrowser": { - "title": "瀏覽目錄", - "pathPlaceholder": "輸入目錄路徑...", - "goHome": "回到主目錄", - "navigateUp": "返回上層目錄", - "select": "選擇", - "cancel": "取消", - "loading": "載入中...", - "emptyDirectory": "此目錄為空", - "errorLoadingDir": "載入目錄失敗", - "permissionDenied": "權限不足" - }, - "ChatChannelSettings": { - "loading": "載入中...", - "sectionTitle": "訊息頻道", - "sectionDescription": "設定 IM 機器人,接收事件通知和查詢編碼活動。", - "addChannel": "新增頻道", - "noChannels": "尚未設定任何訊息頻道。", - "channelName": "名稱", - "channelNamePlaceholder": "我的 Telegram 機器人", - "channelType": "頻道類型", - "lark": "飛書", - "weixin": "微信", - "dailyReport": "每日報告", - "dailyReportTime": "推送時間", - "nameRequired": "請輸入頻道名稱。", - "tokenRequired": "請輸入 Token。", - "chatIdRequired": "請輸入 Chat ID。", - "topicMode": "話題群模式", - "topicModeHint": "將 Telegram forum topics 路由為獨立 Codeg 對話。Bot 必須加入 forum supergroup,並擁有管理 topics 權限。", - "loadFailed": "載入頻道失敗。", - "saveFailed": "儲存失敗。", - "connectSuccess": "頻道已連線。", - "connectFailed": "連線失敗", - "disconnectSuccess": "頻道已斷線。", - "disconnectFailed": "斷線失敗。", - "testSuccess": "連線測試通過。", - "testFailed": "連線測試失敗", - "deleteSuccess": "頻道已刪除。", - "deleteFailed": "刪除頻道失敗。", - "deleteConfirmTitle": "刪除頻道", - "deleteConfirmMessage": "將永久刪除該頻道及其訊息紀錄,確定嗎?", - "cancel": "取消", - "delete": "刪除", - "create": "建立", - "save": "儲存", - "channelListTitle": "已設定頻道", - "channelListDescription": "已啟用的頻道在服務啟動時會自動連線。", - "editChannel": "編輯頻道", - "editSuccess": "頻道已更新。", - "tokenPlaceholderKeep": "留空保持不變", - "weixinScanTitle": "掃碼登入", - "weixinScanDescription": "打開微信掃描二維碼以連接。", - "weixinQrcodeExpired": "二維碼已過期。", - "weixinRefreshQrcode": "重新整理", - "weixinWaitingScan": "等待掃碼...", - "weixinPollError": "連接不穩定,正在重試...", - "weixinReconnectNotice": "因 iLink 協議限制,每次重新連接後需先主動向機器人發送一條訊息,事件觸發才會生效。", - "connect": "連線", - "disconnect": "斷開", - "test": "測試連線", - "tabs": { - "channels": "頻道", - "commands": "指令", - "events": "事件", - "other": "其他" - }, - "commands": { - "title": "內建指令", - "description": "訊息頻道中可用的 Bot 指令。群組聊天中需 @Bot 才會處理訊息。", - "prefixLabel": "指令前綴", - "prefixDescription": "觸發 Bot 指令的前綴,1-3 個非字母數字字元(預設 /)。", - "prefixSaved": "指令前綴已儲存。", - "prefixSaveFailed": "儲存指令前綴失敗。", - "prefixInvalid": "前綴必須是 1-3 個非字母數字字元。", - "save": "儲存", - "folderDesc": "選擇工作目錄", - "agentDesc": "選擇 AI Agent", - "taskDesc": "建立會話並執行任務", - "sessionsDesc": "列出當前目錄的活躍會話", - "resumeDesc": "最近對話 / 恢復指定對話", - "cancelDesc": "取消當前任務", - "approveDesc": "批准 Agent 權限請求", - "denyDesc": "拒絕 Agent 權限請求", - "searchDesc": "依關鍵字搜尋對話", - "todayDesc": "今日活動摘要", - "statusDesc": "頻道連線狀態", - "helpDesc": "顯示說明" - }, - "events": { - "title": "事件通知", - "description": "啟用事件後,事件被觸發時將推送到頻道。", - "turnComplete": "對話完成", - "turnCompleteDesc": "代理回合結束時", - "error": "代理錯誤", - "errorDesc": "代理遇到錯誤時", - "permissionRequest": "權限請求", - "permissionRequestDesc": "智慧代理請求操作權限時", - "questionRequest": "智慧代理提問", - "questionRequestDesc": "當智慧代理向你提問時", - "userPromptSent": "使用者訊息", - "userPromptSentDesc": "當你傳送訊息時——通知中會包含訊息內容", - "saved": "事件篩選已更新。", - "saveFailed": "儲存事件篩選失敗。", - "loadFailed": "載入設定失敗。", - "retry": "重試", - "webhooksTitle": "Webhook", - "webhooksDescription": "事件觸發時,向一個或多個位址 POST 一份 JSON。上方的事件篩選同樣作用於 Webhook。", - "webhookUrlPlaceholder": "https://example.com/webhook", - "addWebhook": "新增 Webhook", - "removeWebhook": "刪除 Webhook", - "webhookSave": "儲存", - "webhooksSaved": "Webhook 已儲存。", - "webhooksSaveFailed": "儲存 Webhook 失敗。", - "webhookInvalidUrl": "請輸入有效的 http(s) 位址。", - "docsTitle": "請求格式", - "docsMethod": "請求方式", - "docsContentType": "內容類型", - "docsNote": "每個啟用的事件都會投遞到所有位址。Webhook 不做去抖;上方的事件篩選仍然生效。", - "editWebhook": "編輯 Webhook", - "enableWebhook": "啟用 Webhook", - "webhookDuplicate": "該位址已設定。", - "cancel": "取消", - "webhooksEmpty": "尚未設定 Webhook。", - "deleteWebhookTitle": "刪除 Webhook", - "deleteWebhookMessage": "刪除此 Webhook?事件將不再傳送到該網址。", - "delete": "刪除" - }, - "language": { - "title": "訊息語言", - "description": "事件通知、指令回應和每日報告推送到訊息頻道時使用的語言。", - "saved": "訊息語言已儲存。", - "saveFailed": "儲存訊息語言失敗。", - "en": "英語", - "zh-cn": "簡體中文", - "zh-tw": "繁體中文", - "ja": "日語", - "ko": "韓語", - "es": "西班牙語", - "de": "德語", - "fr": "法語", - "pt": "葡萄牙語", - "ar": "阿拉伯語" - } - }, - "ModelProviderSettings": { - "sectionTitle": "模型供應商", - "sectionDescription": "管理 Agent 的 API 供應商憑據。", - "filterAll": "全部", - "providerListTitle": "已配置的供應商", - "addProvider": "新增供應商", - "editProvider": "編輯供應商", - "noProviders": "尚未配置模型供應商。", - "providerName": "名稱", - "providerNamePlaceholder": "例如 OpenAI、Anthropic", - "apiUrl": "API 位址", - "apiUrlPlaceholder": "https://api.openai.com/v1", - "apiKey": "API 金鑰", - "apiKeyPlaceholder": "sk-...", - "apiKeyKeepCurrent": "留空則保持不變", - "agentTypes": "代理類型", - "agentTypesRequired": "至少選擇一個代理類型。", - "agentType": "智能體類型", - "agentTypeRequired": "請選擇智能體類型。", - "agentTypeImmutableHint": "智能體類型建立後不可修改。", - "model": "模型", - "modelPlaceholderCodex": "gpt-5.6-sol / gpt-5.5", - "modelPlaceholderGemini": "gemini-3-pro-preview", - "claudeMainModel": "主要模型", - "claudeReasoningModel": "推理模型(思考)", - "claudeHaikuDefaultModel": "預設 Haiku 模型", - "claudeSonnetDefaultModel": "預設 Sonnet 模型", - "claudeOpusDefaultModel": "預設 Opus 模型", - "claudeCustomModelOption": "自訂模型 ID", - "claudeCustomModelOptionName": "自訂模型名稱", - "claudeCustomModelOptionDescription": "自訂模型描述", - "claudeCustomModelOptionHint": "在 Claude 模型選擇器中新增一個自訂項目(例如透過自訂閘道/代理提供的模型)。名稱與描述為選填的顯示資訊。", - "nameRequired": "供應商名稱不能為空。", - "apiUrlRequired": "API 位址不能為空。", - "apiKeyRequired": "API 金鑰不能為空。", - "loadFailed": "載入供應商失敗。", - "saveFailed": "儲存變更失敗。", - "createSuccess": "供應商已建立。", - "editSuccess": "供應商已更新。", - "deleteSuccess": "供應商已刪除。", - "deleteConfirmTitle": "刪除供應商", - "deleteConfirmMessage": "確定要永久刪除供應商「{name}」嗎?", - "deleteBlockedByAgent": "{agents} 正在使用此設定,請先解除關聯後再刪除。", - "cancel": "取消", - "delete": "刪除", - "create": "建立", - "save": "儲存", - "affectedRunningSessions": "{count} 個進行中的工作階段需重新連線以套用變更" - }, - "SkillMatrix": { - "loading": "載入中…", - "searchPlaceholder": "依名稱、ID 或描述搜尋", - "empty": "暫無內容。", - "emptySearch": "沒有符合目前搜尋的結果。", - "skillColumn": "技能", - "selectAll": "全選可見項目", - "selectSkill": "選擇 {name}", - "everything": { - "label": "批次", - "enable": "全部啟用(可見)", - "disable": "全部停用(可見)" - }, - "columnMenu": { - "enableAll": "啟用全部技能", - "disableAll": "停用全部技能" - }, - "rowMenu": { - "label": "對 {name} 批次操作", - "enableAll": "對所有 agent 啟用", - "disableAll": "對所有 agent 停用" - }, - "bulk": { - "selected": "已選擇 {count} 項", - "targetAll": "全部 agent", - "targetSome": "{count} 個 agent", - "enable": "啟用", - "disable": "停用", - "clear": "清除" - }, - "confirm": { - "disableTitle": "停用這些連結?", - "disableBody": "這將移除 {count} 個由 codeg 管理的技能連結。佔用自訂目錄的技能不受影響。你可以隨時重新啟用。", - "cancel": "取消", - "confirm": "停用" - }, - "toasts": { - "loadFailed": "載入技能狀態失敗", - "applyFailed": "套用變更失敗", - "enabled": "已啟用 {count} 個連結", - "disabled": "已停用 {count} 個連結", - "enabledPartial": "已啟用 {ok} 個,{failed} 個失敗", - "disabledPartial": "已停用 {ok} 個,{failed} 個失敗" - }, - "detail": { - "enableForAgents": "為 agent 啟用", - "preview": "SKILL.md 預覽", - "loadingContent": "載入內容中…" - }, - "copyModeHint": "已複製(非連結)——更新後請重新啟用以取得最新版本" - }, - "ExpertsSettings": { - "title": "專家技能", - "description": "為 AI 編碼代理啟用精心挑選、經過實戰驗證的技能工作流程。每個專家都是 superpowers 專案中的獨立技能 —— codeg 維護中央副本,並將其軟連結到你選擇的代理目錄。", - "loading": "正在載入專家清單…", - "loadingContent": "正在載入內容…", - "emptyExperts": "目前沒有可用的專家,請查看應用程式日誌。", - "emptySelection": "從左側選擇一個專家以檢視內容並管理啟用狀態。", - "emptySearch": "沒有符合目前搜尋條件的專家。", - "searchPlaceholder": "依名稱、ID 或描述搜尋專家", - "enableForAgents": "為代理啟用", - "noAgents": "未偵測到 ACP 代理。", - "copyModeWarning": "已複製(非軟連結)。codeg 更新後需要重新啟用以取得最新版本。", - "previewTitle": "SKILL.md 預覽", - "categories": { - "discovery": "探索與設計", - "planning": "規劃", - "execution": "執行", - "quality": "品質與測試", - "debugging": "除錯", - "review": "審查與整合", - "meta": "後設技能" - }, - "states": { - "not_linked": "未啟用", - "linked_to_codeg": "已啟用", - "linked_elsewhere": "衝突 — 已有其他連結", - "blocked_by_real_directory": "衝突 — 已有同名的自訂 skill 佔用", - "broken": "連結損壞" - }, - "badges": { - "userModified": "使用者修改過" - }, - "actions": { - "openCentralDir": "開啟中央目錄", - "refresh": "重新整理" - }, - "toasts": { - "loadFailed": "載入專家詳情失敗", - "enabled": "已為該代理啟用專家", - "disabled": "已為該代理停用專家", - "enableFailed": "啟用專家失敗", - "disableFailed": "停用專家失敗", - "openFolderFailed": "開啟目錄失敗" - } - }, - "ScienceSettings": { - "title": "科學研究技能", - "description": "為你的 AI 編碼智能體啟用精選的科學研究技能:假設生成、實驗設計、統計、視覺化、批判性評估與文獻檢索。codeg 管理中央副本,並將每個技能連結到你選擇的智能體。", - "loading": "正在載入科學研究技能…", - "emptySkills": "沒有可用的科學研究技能。請檢查應用程式日誌。", - "searchPlaceholder": "依名稱、ID 或描述搜尋科學研究技能", - "categories": { - "ideation": "構思", - "design": "研究設計", - "analysis": "分析", - "visualization": "視覺化", - "evaluation": "評估", - "literature": "文獻" - }, - "states": { - "not_linked": "未啟用", - "linked_to_codeg": "已啟用", - "linked_elsewhere": "衝突 — 已有其他連結", - "blocked_by_real_directory": "衝突 — 已有同名的自訂 skill 佔用", - "broken": "連結損壞" - }, - "badges": { - "userModified": "使用者修改過", - "needsKey": "需要金鑰", - "needsSetup": "可能需環境" - }, - "actions": { - "openCentralDir": "開啟中央目錄", - "refresh": "重新整理" - }, - "toasts": { - "openFolderFailed": "開啟目錄失敗" - } - }, - "OfficeToolsSettings": { - "title": "Office 工具", - "description": "管理 OfficeCLI 技能,用於建立 Excel、Word 和 PowerPoint 檔案。安裝 OfficeCLI,同步技能,並為每個智慧體啟用。", - "loadingContent": "載入內容中…", - "emptySkills": "暫無技能。請先安裝 OfficeCLI 並同步技能。", - "emptySelection": "選擇一個技能查看內容和管理啟用狀態。", - "emptySearch": "沒有匹配的技能。", - "searchPlaceholder": "按名稱、ID 或描述搜尋技能", - "enableForAgents": "為智慧體啟用", - "noAgents": "未偵測到 ACP 智慧體。", - "installFirst": "請先安裝 OfficeCLI 以啟用技能。", - "syncFirst": "請先同步技能以載入內容。", - "noContent": "暫無內容。", - "copyModeWarning": "已複製(非連結)。重新同步以取得最新版本。", - "previewTitle": "SKILL.md 預覽", - "detection": { - "installed": "已安裝", - "notInstalled": "未安裝", - "notRunnable": "已安裝但無法執行", - "installHint": "安裝 OfficeCLI 以為 AI 智慧體啟用辦公文件生成技能。", - "install": "安裝", - "uninstall": "解除安裝", - "syncSkills": "同步技能" - }, - "categories": { - "general": "通用", - "presentations": "簡報", - "documents": "文件", - "spreadsheets": "試算表" - }, - "states": { - "not_linked": "未啟用", - "linked_to_codeg": "已啟用", - "linked_elsewhere": "已阻止——存在其他連結", - "blocked_by_real_directory": "已阻止——自訂技能佔用此名稱", - "broken": "連結已損壞" - }, - "badges": { - "notSynced": "未同步" - }, - "actions": { - "refresh": "重新整理" - }, - "toasts": { - "loadFailed": "載入技能詳情失敗", - "enabled": "已為此智慧體啟用技能", - "disabled": "已為此智慧體停用技能", - "enableFailed": "啟用技能失敗", - "disableFailed": "停用技能失敗", - "installSuccess": "OfficeCLI 安裝成功", - "installFailed": "安裝 OfficeCLI 失敗", - "uninstallSuccess": "OfficeCLI 已解除安裝", - "uninstallFailed": "解除安裝 OfficeCLI 失敗", - "syncSuccess": "已成功同步 {synced} 個技能", - "syncPartial": "已同步 {synced} 個技能,{errors} 個失敗", - "syncFailed": "同步技能失敗" - }, - "autoPreviewLabel": "自動開啟預覽", - "autoPreviewHint": "當智慧代理建立或編輯 Word、Excel、PowerPoint 檔案時,自動開啟其即時預覽。" - }, - "SkillPacksSettings": { - "title": "技能包", - "description": "由 codeg 集中管理、並連結到各 AI 智慧代理的成套技能——程式設計專家、科學研究與辦公文件工具。可在下方依代理分別啟用。", - "tabs": { - "experts": "專家", - "science": "科學研究", - "office": "辦公工具", - "custom": "自訂" - }, - "actions": { - "openCentralDir": "開啟中央目錄", - "refresh": "重新整理" - }, - "toasts": { - "openFolderFailed": "開啟目錄失敗" - } - }, - "QuickMessagesSettings": { - "title": "快捷訊息", - "description": "管理可重用的訊息片段。拖曳以調整順序。", - "loading": "載入快捷訊息…", - "emptyList": "尚無快捷訊息。點擊「新增」建立一條。", - "emptySelection": "選擇一條快捷訊息進行編輯。", - "searchPlaceholder": "依標題或內容搜尋", - "untitled": "未命名", - "actions": { - "new": "新增", - "save": "儲存", - "delete": "刪除", - "dragSort": "拖曳排序", - "dragSortMessage": "拖曳排序快捷訊息:{name}" - }, - "fields": { - "title": "標題", - "titlePlaceholder": "為此訊息取一個簡短的標題", - "content": "內容", - "contentPlaceholder": "在此輸入訊息內容" - }, - "confirmDelete": { - "title": "刪除快捷訊息?", - "message": "將永久刪除「{name}」。確定嗎?", - "cancel": "取消", - "confirm": "刪除" - }, - "toasts": { - "loadFailed": "載入快捷訊息失敗", - "createFailed": "建立快捷訊息失敗", - "saveFailed": "儲存快捷訊息失敗", - "deleteFailed": "刪除快捷訊息失敗", - "saveOrderFailed": "儲存順序失敗", - "created": "已建立快捷訊息", - "saved": "已儲存快捷訊息", - "deleted": "已刪除快捷訊息" - } - }, - "Pet": { - "badge": { - "running": "{count} 個執行中", - "waiting": "{count} 個待核准", - "error": "{count} 個發生錯誤" - }, - "panel": { - "title": "活動工作階段", - "empty": "沒有活動工作階段", - "emptyHint": "正在執行或需要你處理的工作階段會顯示在這裡。", - "statusRunning": "執行中", - "statusWaiting": "等待中", - "statusError": "發生錯誤", - "subAgentOf": "子智慧代理" - }, - "menu": { - "scale": "縮放", - "openManager": "管理寵物", - "close": "關閉" - }, - "loadError": "載入寵物失敗", - "missingPetIdParam": "未選中任何寵物", - "summonButton": "寵物", - "manager": { - "title": "桌面寵物", - "description": "懸浮在桌面上的夥伴,使用與 Codex 相容的精靈圖。", - "addPet": "新增寵物", - "importFromCodex": "從 Codex 匯入", - "noPets": "暫無寵物。可以新增一隻,或從 Codex 匯入。", - "setActive": "設為使用中", - "active": "使用中", - "edit": "編輯", - "delete": "刪除", - "deleteConfirm": "確認刪除寵物「{name}」嗎?會從磁碟上一併移除。", - "summon": "召喚寵物視窗", - "openCodexHelp": "Codex 寵物需位於 ~/.codex/pets/ 目錄下,但未找到。", - "specRequirement": "精靈圖寬度必須為 1536 像素,高度需為 208 像素的整數倍(如 1872 或 2288),並為帶透明通道的 PNG 或 WebP。", - "form": { - "id": "寵物 ID", - "idHelp": "僅允許小寫字母、數字、'-' 和 '_',最多 64 字元。", - "displayName": "顯示名稱", - "description": "描述 (選填)", - "spritesheet": "精靈圖", - "chooseFile": "選擇檔案", - "replaceFile": "替換精靈圖", - "saveCreate": "新增寵物", - "saveUpdate": "儲存變更", - "cancel": "取消" - }, - "errors": { - "missingId": "寵物 ID 不能為空", - "missingName": "顯示名稱不能為空", - "missingSpritesheet": "必須選擇一個精靈圖", - "addFailed": "新增寵物失敗", - "updateFailed": "更新寵物失敗", - "deleteFailed": "刪除寵物失敗", - "loadFailed": "載入寵物列表失敗", - "setActiveFailed": "設定活躍寵物失敗", - "summonFailed": "召喚寵物視窗失敗" - } - }, - "import": { - "title": "從 Codex 匯入", - "subtitle": "在 ~/.codex/pets/ 下找到以下可匯入的寵物。", - "selectAll": "全選", - "alreadyImported": "已匯入", - "renameOnConflict": "衝突時自動加上 -imported 後綴", - "import": "匯入所選", - "noneFound": "未找到可匯入的 Codex 寵物。", - "imported": "匯入完成", - "failed": "匯入失敗", - "close": "關閉" - }, - "marketplace": { - "openMarketplace": "寵物市集", - "title": "寵物市集", - "search": "搜尋寵物", - "kindFilter": { - "all": "全部", - "object": "物品", - "animal": "動物", - "person": "人物", - "creature": "生物" - }, - "sortFilter": { - "latest": "最新", - "popular": "熱門", - "views": "最多瀏覽" - }, - "refresh": "重新整理", - "install": "安裝", - "installing": "安裝中", - "reinstall": "重新安裝", - "reinstallConfirm": "確認覆蓋本機寵物 \"{name}\" 嗎?現有資料將被取代。", - "cancel": "取消", - "stats": { - "views": "瀏覽", - "downloads": "下載", - "likes": "讚" - }, - "actions": { - "idle": "待機", - "running_right": "右跑", - "running_left": "左跑", - "waving": "揮手", - "jumping": "跳躍", - "failed": "失敗", - "waiting": "等待", - "running": "執行", - "review": "審閱" - }, - "page": "第 {page} / {total} 頁", - "prev": "上一頁", - "next": "下一頁", - "empty": "沒有符合的寵物。", - "successInstalled": "已安裝 \"{name}\"", - "errors": { - "loadFailed": "載入市集失敗", - "installFailed": "安裝失敗", - "alreadyInstalled": "該寵物已存在" - } - } - }, - "RemoteWorkspace": { - "openRemoteWorkspace": "Open remote workspace", - "manage": "Manage remote workspace", - "manageTitle": "Remote Workspace connections", - "empty": "No remote connections", - "searchPlaceholder": "Search remote workspaces", - "orderFailed": "Failed to save remote workspace order", - "dragSort": "Drag to sort", - "dragSortConnection": "Drag to sort {name}", - "newConnection": "New connection", - "loading": "Loading", - "loadingConnection": "Loading remote connection", - "name": "Name", - "baseUrl": "Service URL", - "token": "Access token", - "save": "Save", - "delete": "Delete", - "confirmDelete": { - "title": "Delete remote connection?", - "message": "This will remove \"{name}\" from this device. This action cannot be undone.", - "cancel": "Cancel", - "confirm": "Delete" - }, - "saved": "Remote connection saved.", - "deleted": "Remote connection deleted.", - "loadFailed": "Failed to load remote connections", - "saveFailed": "Failed to save remote connection", - "deleteFailed": "Failed to delete remote connection", - "openFailed": "Failed to open remote workspace", - "connectionLoadFailed": "Failed to load remote connection: {message}", - "connectionExpired": "Remote connection \"{name}\" is expired. Update its token and reload this window." - }, - "ServerFileBrowser": { - "title": "選擇伺服器檔案", - "pathPlaceholder": "輸入目錄路徑...", - "goHome": "回到主目錄", - "navigateUp": "返回上層目錄", - "select": "選擇", - "cancel": "取消", - "loading": "載入中...", - "emptyDirectory": "此目錄為空", - "errorLoadingDir": "載入目錄失敗", - "selectedCount": "已選 {count} 項" - }, - "BackupSettings": { - "title": "備份與還原", - "description": "匯出一份可攜的 codeg 資料備份,或從備份還原。", - "tabs": { - "backup": "備份", - "restore": "還原" - }, - "export": { - "includeExternal": "包含對話內容", - "includeExternalHint": "一併打包各 CLI 的對話記錄(Claude、Codex、Gemini 等),體積更大。", - "passphrase": "通行碼(選填)", - "passphrasePlaceholder": "留空則產生未加密的封存檔", - "passphraseConfirm": "確認通行碼", - "passphraseMismatch": "兩次輸入的通行碼不一致。", - "noPassphraseWarning": "此備份將以明文包含密鑰(API key、token)。請妥善保管。", - "passphraseLossWarning": "將以此通行碼加密。通行碼一旦遺失,備份將無法還原。", - "button": "匯出備份", - "inProgress": "正在建立備份…", - "success": "備份已建立。", - "started": "已開始下載備份。" - }, - "restore": { - "selectFile": "選擇備份檔案", - "passphrasePrompt": "此備份已加密,請輸入其通行碼。", - "unlock": "解鎖", - "preview": { - "title": "備份詳情", - "encrypted": "已加密", - "compatible": "相容", - "incompatible": "不相容", - "createdAt": "建立時間:{value}", - "appVersion": "應用程式版本:{value}", - "incompatibleHint": "此備份由較新版本的 codeg 建立,無法還原。" - }, - "replaceWarning": "還原將取代目前全部 codeg 資料(資料庫與上傳檔案)。目前資料會先做快照以便復原。", - "keyringNote": "桌面端的 GitHub/聊天 token 存於系統鑰匙圈,不包含在備份中;還原後需重新填寫。", - "button": "還原", - "staging": "正在準備還原…", - "staged": "還原已就緒,正在重新啟動…", - "restarting": "還原已就緒,正在重新啟動服務…", - "restartTimeout": "服務未能及時恢復。待其啟動後請重新整理頁面。", - "externalSideLocation": "對話記錄已還原至 {path}", - "confirmTitle": "取代全部資料?", - "confirmBody": "這將以備份取代目前的 codeg 資料庫與上傳檔案,然後重新啟動。目前資料會先做快照。", - "cancel": "取消", - "confirmAction": "取代並重新啟動", - "external": { - "title": "對話內容", - "hint": "此備份包含各 CLI 的對話記錄。請選擇還原到何處。", - "modeSkip": "不還原", - "modeSide": "還原到安全的旁路資料夾", - "modeOriginal": "還原到 CLI 的原始位置", - "forceOverwrite": "覆寫已存在的檔案", - "forceOverwriteHint": "取代 CLI 資料夾中已存在的檔案。", - "scanning": "正在檢查衝突…", - "noConflicts": "不會覆寫任何已存在的檔案。", - "conflictCount": "將影響 {count} 個已存在的檔案。", - "conflictSkipNote": "未啟用覆寫時,已存在的檔案將被保留(略過)。" - }, - "restartFailed": "還原已就緒,但伺服器未能重新啟動。請手動重新啟動以套用此次還原。" - }, - "remoteUnsupported": "備份與還原作用於執行 codeg 的那台機器上的資料。你目前連線的是遠端工作區——請直接在該伺服器上管理其備份。" - }, - "backup": { - "restore": { - "error": { - "badPassphrase": "通行碼錯誤或備份已損毀。", - "corrupted": "備份封存檔已損毀。", - "unknownFormat": "此檔案不是可識別的 codeg 備份。", - "newerVersion": "此備份由 codeg {backupVersion} 建立,比目前版本({appVersion})更新。", - "alreadyPending": "已有一個還原在等待生效。請先重新啟動套用它,再暫存新的還原。" - } - }, - "error": { - "diskSpace": "磁碟空間不足,無法完成操作。", - "cancelled": "操作已取消。" - } - }, - "WebConnection": { - "disconnectedTitle": "連線已中斷", - "reconnectingDescription": "正在嘗試重新連線伺服器,通常會在幾秒內自動恢復。", - "reconnectNow": "立即重新連線", - "sessionExpiredTitle": "工作階段已過期", - "sessionExpiredDescription": "登入狀態已失效,請重新登入以繼續。", - "goToLogin": "前往登入" - }, - "LiveFeedback": { - "placeholder": "在 {agent} 工作時給它留言…", - "agentFallback": "智能體", - "ariaLabel": "即時回饋留言", - "dialogTitle": "即時回饋", - "dialogDescription": "在智能體工作時給它留言。它會在下次檢查時讀取,不會打斷當前步驟。", - "dialogDescriptionInstant": "在智慧代理工作時傳送備註。備註會立即插入目前回合——代理馬上就能看到。", - "channelDowngraded": "本工作階段無法即時插入——備註已儲存,待代理下次檢查時讀取。", - "send": "送出", - "cancel": "取消", - "pending": "等待中", - "delivered": "已收到", - "turnEndedUnread": "智能體在讀取你的回饋前已結束本輪。", - "sendAsMessage": "作為新訊息送出", - "dismiss": "忽略", - "turnEndedResent": "本輪已結束——已改為作為新訊息送出。", - "turnEnded": "本輪已結束。", - "submitFailed": "留言送出失敗" - }, - "AgentToolsSettings": { - "title": "對話內工具", - "description": "codeg 在對話中額外提供給智慧代理的工具。工具會在代理啟動時注入,變更只對之後啟動的代理生效。", - "feedbackLabel": "即時回饋", - "feedbackHint": "在智慧代理工作時向它傳送備註與修正。支援即時插入的代理會立刻在目前回合中看到你的備註;其他代理則透過檢查回饋的工具讀取——這類代理通常只有在提示中提到時才會檢查,例如在訊息中加上「定期檢查我的即時回饋」。", - "questionLabel": "向使用者提問", - "questionHint": "允許智能體暫停並向你提出多選問題,問題會顯示在對話輸入框上方。智能體會一直等待,直到你作答(或略過)。", - "sessionInfoLabel": "取得工作階段資訊", - "sessionInfoHint": "允許智慧代理查詢你在訊息中提及的工作階段(工作階段徽章),讀取其標題、代理、狀態、工作區、Token 用量與最近訊息。", - "automationsLabel": "建立自動化", - "automationsHint": "把對話儲存為按排程執行的自動化。預設關閉——它之後會自行啟動代理。", - "workTasksLabel": "建立待辦任務", - "workTasksHint": "從對話中往待辦看板排一張任務卡。預設關閉——它會寫入應用程式狀態。", - "save": "儲存", - "saving": "儲存中…", - "saved": "工具設定已儲存", - "saveFailed": "儲存工具設定失敗", - "loadFailed": "載入失敗:{detail}" - }, - "NotificationSoundSettings": { - "title": "提示音", - "description": "智慧體事件觸發時播放一段簡短的提示音。這裡的事件與訊息通道推送的完全一致,但設定只對本裝置生效。", - "enableHint": "預設關閉。提示音只在目前瀏覽器或應用程式的工作區視窗中播放。", - "volume": "音量", - "preview": "試聽", - "previewEvent": "試聽「{event}」提示音", - "onlyWhenUnfocused": "僅在視窗未聚焦時播放", - "onlyWhenUnfocusedHint": "正在檢視 Codeg 時保持靜音。", - "eventsTitle": "事件", - "eventsHint": "為每個事件選擇一種音效,選擇「靜音」則不播放。同一事件在數秒內重複觸發時只播放一次。", - "toneNone": "靜音", - "toneChime": "叮咚", - "toneDing": "清鈴", - "toneBlip": "短音", - "tonePop": "輕點", - "toneAlert": "警示", - "toneDescend": "下行音" - }, - "LogsSettings": { - "loading": "載入中…", - "sectionTitle": "執行日誌", - "sectionDescription": "檢視與設定應用程式診斷日誌。日誌會寫入本機檔案,並保留在記憶體中以便即時檢視。", - "captureTitle": "日誌等級", - "captureDescription": "控制記錄的詳細程度。等級越高(Debug、Trace)記錄越多,但日誌也越大。「關閉」會停止記錄日誌。", - "captureLabel": "擷取等級", - "levels": { - "off": "關閉", - "error": "錯誤", - "warn": "警告", - "info": "資訊", - "debug": "除錯", - "trace": "追蹤" - }, - "viewerTitle": "最近日誌", - "viewerDescription": "即時檢視最近的日誌記錄。可依等級篩選或搜尋文字。", - "searchPlaceholder": "搜尋訊息或來源…", - "viewLevels": { - "all": "所有等級", - "error": "錯誤以上", - "warn": "警告以上", - "info": "資訊以上", - "debug": "除錯以上", - "trace": "追蹤以上" - }, - "pause": "暫停", - "resume": "即時", - "refresh": "重新整理", - "clear": "清除", - "openFolder": "開啟資料夾", - "shownCount": "已顯示 {shown} / {total}", - "empty": "尚無日誌。", - "levelSaveFailed": "儲存日誌等級失敗", - "openFolderFailed": "開啟日誌資料夾失敗", - "downloadFailed": "下載日誌檔案失敗", - "filesTitle": "日誌檔案", - "filesDescription": "從磁碟下載完整日誌檔案,檢視即時緩衝區以外的歷史記錄。", - "filesEmpty": "尚無日誌檔案。", - "download": "下載", - "downloadTruncated": "檔案較大,已下載最新的 {size}。完整檔案請在日誌目錄中查看。", - "captureEnvLocked": "日誌等級由 RUST_LOG / CODEG_LOG 環境變數控制;請在該處修改以生效。", - "targetsTitle": "依模組覆寫", - "targetsDescription": "為特定模組(如 codeg_lib::acp)單獨設定級別,不影響全域級別。", - "targetsAdd": "新增", - "targetsRemove": "移除覆寫", - "toggleDetails": "切換詳情" - }, - "Automations": { - "title": "自動化", - "new": "新增自動化", - "empty": "尚無自動化", - "emptyHint": "建立一個,讓代理程式按排程或手動執行任務。", - "name": "名稱", - "namePlaceholder": "例如:每晚 PR 審查", - "prompt": "提示詞", - "promptPlaceholder": "讓代理程式做什麼?", - "agent": "代理程式", - "folder": "工作區資料夾", - "folderPlaceholder": "選擇資料夾", - "isolation": "隔離方式", - "isolationWorktree": "每次執行新增 worktree", - "isolationShared": "在資料夾內執行", - "isolationSharedCaveat": "執行會直接使用該資料夾的工作樹,可能與你未提交的變更衝突。勾選每次執行新建工作樹以隔離每次執行。", - "trigger": "觸發方式", - "triggerSchedule": "按排程", - "triggerManual": "僅手動", - "cron": "排程(cron)", - "cronPlaceholder": "0 9 * * 1-5", - "timezone": "時區", - "nextRun": "下次執行", - "branch": "分支", - "branchOptional": "分支(選填)", - "enabled": "已啟用", - "save": "儲存", - "cancel": "取消", - "edit": "編輯", - "delete": "刪除", - "runNow": "立即執行", - "cancelRun": "取消執行", - "runHistory": "執行紀錄", - "noRuns": "尚無執行紀錄", - "allFolders": "所有資料夾", - "filterAll": "全部", - "noMatches": "沒有符合的自動化", - "viewConversation": "檢視對話", - "lastRun": "上次執行", - "never": "從未", - "running": "執行中", - "deleteTitle": "刪除此自動化?", - "deleteDescription": "這會刪除該自動化及其排程。執行紀錄會保留。", - "statusRunning": "執行中", - "statusSucceeded": "成功", - "statusFailed": "失敗", - "statusCancelled": "已取消", - "statusSkipped": "已略過", - "errorName": "名稱必填", - "errorPrompt": "提示詞必填", - "errorCron": "按排程的自動化需要 cron 運算式", - "errorFolder": "請選擇工作區資料夾", - "presetHourly": "每小時", - "presetDaily": "每天 9 點", - "presetWeekdays": "工作日 9 點", - "presetCustom": "自訂", - "probing": "正在載入選項…", - "retry": "重試", - "configNone": "此代理程式沒有可設定的選項", - "inherit": "代理程式預設", - "mode": "模式", - "config": "設定", - "branchPlaceholder": "(預設分支)", - "selectHint": "選擇一個自動化以查看詳情", - "refresh": "重新整理", - "onboardTitle": "自動化日常代理任務", - "onboardHint": "安排代理定時或隨需審查程式碼、更新相依套件或處理問題。", - "headerSubtitle": "定時與隨需的代理任務", - "startFromTemplate": "從範本開始", - "blankTitle": "空白自動化", - "blankDesc": "從零設定一個代理任務。", - "backToTemplates": "範本", - "sectionSchedule": "排程與目標", - "sectionTarget": "執行目標", - "sectionAction": "動作", - "actionLaunchSession": "啟動會話", - "actionEnqueueTask": "任務入列", - "actionEnqueueTaskHint": "每次觸發都會在目標資料夾的待辦任務裡加入一個待辦任務(標題為本自動化名稱),由任務引擎依看板設定執行。", - "sectionPrompt": "提示詞", - "nextIn": "{rel}後執行", - "manual": "手動", - "schedEveryMinutes": "每 {n} 分鐘", - "schedHourly": "每小時", - "schedDaily": "每天 {time}", - "schedWeekdays": "工作日 {time}", - "schedWeekly": "每{day} {time}", - "schedMonthly": "每月 {day} 日 {time}", - "dow0": "週日", - "dow1": "週一", - "dow2": "週二", - "dow3": "週三", - "dow4": "週四", - "dow5": "週五", - "dow6": "週六", - "tplCodeReviewTitle": "程式碼審查", - "tplCodeReviewDesc": "審查最近的變更,找出缺陷、回歸與品質問題。", - "tplDependencyUpdatesTitle": "相依套件更新", - "tplDependencyUpdatesDesc": "找出過時的相依套件並提出安全的升級方案。", - "tplTestCoverageTitle": "測試涵蓋率", - "tplTestCoverageDesc": "找出未涵蓋的程式碼路徑並補上缺少的測試。", - "tplTodoSweepTitle": "TODO 清理", - "tplTodoSweepDesc": "收集 TODO 與 FIXME 註解並依優先順序整理。", - "tplCiTriageTitle": "CI 排查", - "tplCiTriageDesc": "調查最近失敗的檢查並提出修復方案。", - "tplReleaseNotesTitle": "發行說明", - "tplReleaseNotesDesc": "彙整自上次發行以來的變更,產生更新日誌。", - "tplSecurityAuditTitle": "安全稽核", - "tplSecurityAuditDesc": "掃描漏洞與風險模式,並回報發現的問題。", - "enable": "啟用", - "disable": "停用", - "moreActions": "更多操作", - "statusDisabled": "已停用", - "cronBuilderTitle": "排程產生器", - "cronFreqLabel": "頻率", - "cronFreqMinutes": "每 N 分鐘", - "cronFreqHourly": "每小時", - "cronFreqDaily": "每天", - "cronFreqWeekdays": "工作日", - "cronFreqWeekly": "每週", - "cronFreqMonthly": "每月", - "cronFreqCustom": "自訂", - "cronEveryLabel": "間隔(分鐘)", - "cronTimeLabel": "時間", - "cronHourLabel": "小時", - "cronMinuteLabel": "分鐘", - "cronDowLabel": "星期", - "cronDomLabel": "日期", - "cronApply": "套用", - "cronPreviewLabel": "預覽", - "cronOpenBuilder": "開啟排程產生器", - "branchDefault": "預設分支", - "branchUseCustom": "使用「{query}」", - "branchLocal": "本機", - "branchRemote": "遠端", - "branchSearchPlaceholder": "搜尋分支…", - "branchNone": "無分支" - }, - "Tasks": { - "title": "待辦任務", - "new": "新增任務", - "empty": "還沒有任務", - "emptyHint": "新增待辦後即可處理——agent 在獨立 worktree 中工作,你驗收並合併結果。", - "emptyColTodo": "還沒有待辦任務", - "emptyColInProgress": "暫無進行中的任務", - "emptyColAttention": "暫無等你處理的任務", - "emptyColDone": "還沒有已完成的任務", - "allFolders": "全部資料夾", - "showCanceled": "顯示已取消", - "showArchived": "顯示已封存", - "filter": "篩選", - "viewSwitchToBoard": "切換到看板檢視", - "viewSwitchToList": "切換到清單檢視", - "statusFilter": "狀態", - "statusFilterAll": "全部狀態", - "listEmpty": "沒有符合目前篩選條件的任務", - "listColStatus": "狀態", - "listColTask": "任務", - "listColLocation": "位置", - "listColChanges": "變更", - "listColUpdated": "更新", - "colTodo": "待辦", - "colInProgress": "進行中", - "colAttention": "等你處理", - "colDone": "已完成", - "statusTodo": "待辦", - "statusQueued": "排隊中", - "statusPreparing": "初始化中", - "statusRunning": "進行中", - "statusAwaitingInput": "等待輸入", - "statusReview": "待驗收", - "statusMerging": "合併中", - "statusDone": "已完成", - "statusFailed": "失敗", - "statusCanceled": "已取消", - "statusInterrupted": "已中斷", - "badgeCleanupFailed": "清理失敗", - "badgeWorktreeKept": "保留 worktree", - "badgeWorktreeRemoved": "Worktree 已刪除", - "filesChanged": "{count} 個檔案", - "actionStart": "開始", - "actionSchedule": "定時執行", - "actionCancel": "取消", - "actionRetry": "重試", - "actionRequeue": "重新排隊", - "actionViewSession": "檢視會話", - "actionEdit": "編輯", - "actionDelete": "刪除", - "actionRetryCleanup": "重試清理", - "actionMerge": "合併", - "actionUnqueueMerge": "取消排隊", - "actionEditQueuedMerge": "修改排隊的合併", - "badgeMergeQueued": "排隊合併中", - "badgeMergeQueuedRank": "排隊合併 · 第 {rank} 位", - "badgeMergeQueuedHint": "正在等待該專案目前的合併完成,輪到時會自動開始。", - "actionComplete": "完成", - "actionAbandon": "放棄", - "cancelTitle": "取消任務?", - "cancelDescription": "任務將變為已取消。worktree 會保留,之後可以重新排隊。", - "cancelReasonLabel": "取消原因(選填)", - "cancelReasonPlaceholder": "例如:方向不對,我重寫一下任務描述", - "cancelKeep": "先不取消", - "cancelSubmit": "取消任務", - "restartTitleRetry": "重試任務", - "restartTitleRequeue": "重新排隊", - "restartDescription": "可以補充一段說明(選填),它會隨下一輪的提示詞一起傳給 agent。", - "scheduleTitle": "定時執行任務", - "scheduleDescription": "任務留在「待辦」,到時間自動開始。資料夾的並行上限仍然有效。", - "scheduleDateLabel": "日期", - "schedulePickDate": "選擇日期", - "scheduleTimeLabel": "時間", - "schedulePreview": "{time} 執行", - "schedulePastHint": "該時間已過——儲存後會立即開始。", - "scheduleInAnHour": "1 小時後", - "scheduleInThreeHours": "3 小時後", - "scheduleTomorrow": "明天 9:00", - "scheduleClear": "清除定時", - "scheduleBadge": "預計於 {time} 開始", - "toastScheduled": "已定時:{time}", - "toastScheduleCleared": "已清除定時", - "actionFollowUp": "繼續處理", - "actionAddNote": "補充說明", - "followUpSubmit": "傳送", - "followUpIntentRevise": "修改返工", - "followUpIntentContinue": "繼續推進", - "followUpIntentQuestion": "提問答疑", - "followUpIntentVerify": "自查驗證", - "followUpPlaceholderRevise": "希望 agent 改哪裡?會在同一個工作階段繼續。", - "followUpPlaceholderContinue": "接下來還要做什麼?已有的工作會保留。", - "followUpPlaceholderQuestion": "想了解什麼?agent 只回答,不會改動任何檔案。", - "followUpPlaceholderVerify": "選填:有什麼想讓它重點檢查的?", - "followUpPlaceholderRetry": "選填:這次要怎麼做才不一樣?例如:先跑 pnpm install", - "followUpPlaceholderRequeue": "選填:當時為什麼取消?這次要注意什麼?", - "actionArchive": "封存", - "actionUnarchive": "取消封存", - "archiveAllDone": "全部封存", - "dropToStart": "放開即開始執行", - "errorView": "檢視", - "notifyReview": "待驗收:{title}", - "notifyFailed": "任務失敗:{title}", - "createFromMessage": "由此訊息建立任務", - "detailTokens": "總 token 用量", - "editorTitleNew": "新增任務", - "editorTitleEdit": "編輯任務", - "templates": "範本", - "templatesEmpty": "還沒有範本。", - "templateSaveCurrent": "將目前內容存為範本", - "templateDelete": "刪除範本", - "transcriptTitle": "任務會話", - "transcriptDescription": "任務智慧代理會話的唯讀即時檢視。", - "phaseWork": "任務執行", - "phaseRetry": "重試執行", - "phaseReturn": "繼續處理", - "phaseMerge": "合併變更", - "titleLabel": "標題", - "titlePlaceholder": "要做什麼?", - "promptLabel": "任務描述", - "promptPlaceholder": "向 agent 描述任務——輸入 @ 可引用檔案,/ 可喚起指令", - "folderPlaceholder": "選擇資料夾", - "agentInheritedHint": "繼承自任務設定,修改後僅對本任務生效", - "agentOverrideReset": "恢復繼承", - "sectionTarget": "目標", - "errorTitle": "請輸入標題", - "errorPrompt": "請輸入任務描述", - "errorFolder": "請選擇資料夾", - "save": "儲存", - "cancel": "取消", - "mergeTitle": "合併任務", - "mergeQueuedTitle": "排隊中的合併", - "mergeQueueHint": "該專案正在合併另一個任務。此任務會加入佇列,等前一個完成後自動開始。", - "mergeQueueUpdateHint": "此任務已在合併佇列中。送出將更新它的合併選項,並保留原本的排隊位置。", - "mergeDescription": "將 {branch} 合併到 {base}。worktree 中未提交的變更會先自動提交。", - "mergeMessage": "提交訊息", - "mergeMessagePlaceholder": "例如 feat: add login validation", - "mergeAutoMessage": "讓 agent 自動產生提交訊息", - "strategySquash": "合併為一筆提交", - "strategySquashHint": "任務的所有修改壓縮成一筆提交記錄併入主分支,歷史更簡潔。", - "strategyMerge": "保留完整提交歷史", - "strategyMergeHint": "保留任務過程中的每一筆提交,另加一筆合併記錄,每一步都可追溯。", - "mergeDeleteWorktree": "合併後刪除 worktree", - "mergeSubmit": "合併", - "mergeSubmitQueue": "加入合併佇列", - "mergeQueuedToast": "已加入合併佇列,等目前的合併完成後自動開始。", - "completeTitle": "完成任務", - "completeDescription": "此任務沒有變更任何檔案,無須合併,將直接標記為已完成。", - "completeDescriptionNoWorktree": "此任務的 worktree 已被刪除,無法再合併,將直接標記為已完成。若工作分支上仍有未合併的提交,分支會被保留。", - "completeDeleteWorktree": "完成後刪除 worktree", - "completeSubmit": "完成", - "settingsTitle": "任務設定", - "settingsDescription": "{folder} 中任務的預設配置。", - "settingsScope": "套用範圍", - "settingsScopeGlobal": "全部資料夾(全域預設)", - "settingsScopeGlobalHint": "未單獨設定的資料夾將使用這份全域預設。", - "settingsSource": "設定來源", - "settingsSourceGlobal": "使用全域預設", - "settingsSourceCustom": "單獨設定", - "settingsSourceGlobalFollow": "跟隨全域任務設定,全域變更會自動生效。", - "settingsSourceCustomHint": "為此資料夾儲存獨立設定,不再跟隨全域預設。", - "settingsAgent": "預設 agent", - "settingsMaxConcurrent": "最大並行任務數", - "settingsMaxConcurrentHint": "0 表示不限制", - "settingsAutoProcess": "自動處理", - "settingsAutoProcessHint": "待辦任務自動開始處理,受並行上限約束。", - "settingsMergeStrategy": "預設合併策略", - "settingsMergeStrategyHint": "合併任務時,這些修改在分支歷史裡如何記錄。", - "settingsAutoMerge": "自動合併", - "settingsAutoMergeHint": "任務進入待驗收且有可合併改動時自動落地,與點擊「合併」相同:提交訊息由 agent 自動產生,是否刪除 worktree 沿用下方預設。預檢未通過或合併失敗的任務會留下等你處理。", - "settingsDeleteWorktree": "合併後刪除 worktree", - "settingsDeleteWorktreeHint": "合併對話框裡預設勾選,仍可臨時更改。", - "settingsWorktreeRoot": "Worktree 位置", - "settingsWorktreeRootHint": "新任務的 worktree 會建立在該目錄下,每個任務一個。留空則建立在專案資料夾的同層目錄;「~」表示家目錄,相對路徑相對於專案資料夾。", - "settingsWorktreeRootPlaceholder": "~/codeg-worktrees", - "settingsWorktreeRootBrowse": "選擇 worktree 目錄", - "settingsPreflight": "預檢命令", - "settingsPreflightHint": "任務進入待驗收時在 worktree 中執行。", - "settingsPreflightCustomPlaceholder": "pnpm test", - "settingsInitCommand": "Worktree 初始化命令", - "settingsInitCommandHint": "建立 worktree 後、工作階段開始前執行。", - "settingsInitCommandPlaceholder": "pnpm install", - "settingsTabGeneral": "一般", - "settingsTabMerge": "合併", - "settingsTabWorktree": "Worktree", - "settingsTabPrompts": "提示詞", - "settingsPromptsIntro": "每個階段都已內建固定的提示詞——任務本身、worktree 規則,合併階段還包含具體的 git 步驟。這裡填的內容會作為補充說明追加到最後:只是對內建提示詞的細化,不會取代它們。", - "settingsPromptStageAll": "全部階段", - "settingsPromptPlaceholderAll": "例如:遵循 AGENTS.md 裡的專案慣例;一律用繁體中文回覆", - "settingsPromptPlaceholderWork": "例如:先讀相關測試;小步提交,邊做邊交", - "settingsPromptPlaceholderRetry": "例如:先看清楚已經提交了哪些改動再繼續,別重做已完成的部分", - "settingsPromptPlaceholderReturn": "例如:逐條處理提到的每一點;不要順手重構無關程式碼", - "settingsPromptPlaceholderMerge": "例如:最終合併的提交訊息用繁體中文;手動解決過的衝突要另外說明", - "settingsPromptHintAll": "追加到每一次發給 agent 的提示詞,包括合併那一輪。", - "settingsPromptHintWork": "任務首次執行時追加。", - "settingsPromptHintRetry": "重試被中斷或失敗的任務時追加。", - "settingsPromptHintReturn": "對待驗收的任務繼續處理時追加(返工、追加工作、自查)。", - "settingsPromptHintMerge": "agent 把任務合併到基線分支時追加。", - "preflightPassed": "{name} 通過", - "preflightFailed": "{name} 未通過", - "preflightRunning": "{name} 執行中…", - "detailDescription": "任務詳情", - "detailSummary": "結果", - "detailFiles": "變更檔案", - "detailDiffAll": "檢視全部差異", - "detailDiffAllTitle": "全部差異", - "detailNoChanges": "相對基準還沒有變更", - "detailTimeline": "推進記錄", - "detailTimelineEmpty": "暫無活動", - "showMore": "展開", - "showLess": "收起", - "detailInfo": "詳情", - "detailBranch": "分支", - "detailMergeCommit": "合併提交", - "detailChanges": "變更", - "detailScheduled": "預計開始", - "detailCreated": "建立時間", - "detailStarted": "開始時間", - "detailFinished": "完成時間", - "diffLoading": "正在載入差異…", - "deleteConfirmTitle": "刪除任務?", - "deleteConfirmBody": "「{title}」將從看板移除。進行中的執行會先被取消。", - "deleteWithWorktree": "同時刪除其 worktree", - "eventCreated": "已建立", - "eventStatusChanged": "狀態變更", - "eventConfigEffective": "啟動配置", - "eventInitCommand": "初始化命令", - "eventAgentProgress": "Agent 進展", - "eventAgentVerdict": "Agent 結論", - "eventMergeAttempt": "開始合併", - "eventMergeQueued": "加入合併佇列", - "eventMergeConflict": "合併衝突", - "eventPreflight": "預檢", - "eventCleanupFailed": "worktree 清理失敗", - "eventResumeFallback": "會話恢復失敗,已改用新會話", - "eventUserAction": "使用者操作", - "eventDiffStat": "變更快照" - }, - "CustomSkillsSettings": { - "loading": "正在載入自訂技能…", - "category": "自訂", - "searchPlaceholder": "依名稱、ID 或描述搜尋自訂技能", - "states": { - "not_linked": "未啟用", - "linked_to_codeg": "已啟用", - "linked_elsewhere": "連結到其他位置", - "blocked_by_real_directory": "被同名實體目錄佔用", - "broken": "連結已失效" - }, - "actions": { - "new": "新增", - "import": "匯入", - "importFromAgent": "從 Agent 匯入", - "cancel": "取消", - "save": "儲存" - }, - "rowMenu": { - "edit": "編輯", - "duplicate": "複製為新技能", - "delete": "刪除" - }, - "bulk": { - "delete": "刪除所選" - }, - "editor": { - "createTitle": "新增自訂技能", - "editTitle": "編輯自訂技能", - "description": "自訂技能存放於共用庫(~/.codeg/skills),可為任意智能體啟用。", - "idLabel": "技能 ID", - "idPlaceholder": "例如 my-workflow", - "contentLabel": "SKILL.md", - "contentPlaceholder": "在此撰寫技能的 SKILL.md…", - "preview": "預覽", - "edit": "編輯", - "emptyBody": "尚無內容。" - }, - "duplicate": { - "title": "複製技能", - "description": "以「{id}」為範本,以新 ID 建立一份副本。", - "newIdPlaceholder": "新技能 ID", - "confirm": "複製" - }, - "import": { - "title": "選擇要匯入的技能資料夾" - }, - "importFromAgent": { - "title": "從 Agent 匯入技能", - "description": "將某個 Agent 自己的技能複製到共享庫,即可為任意 Agent 啟用。", - "agentLabel": "Agent", - "agentPlaceholder": "選擇一個 Agent", - "selectAll": "全選({count})", - "loading": "正在載入該 Agent 的技能…", - "unsupported": "此 Agent 未提供技能目錄。", - "empty": "此 Agent 沒有可匯入的技能。", - "alreadyInLibrary": "已在庫中", - "confirm": "匯入所選({count})" - }, - "delete": { - "title": "刪除自訂技能?", - "body": "將從中央庫移除 {count} 個自訂技能,並解除它們在所有智能體中的連結。此操作無法復原。", - "confirm": "刪除" - }, - "toasts": { - "loadFailed": "載入技能失敗", - "idRequired": "請輸入技能 ID", - "created": "已建立自訂技能", - "updated": "已更新自訂技能", - "saveFailed": "儲存技能失敗", - "imported": "已匯入技能", - "importFailed": "匯入技能失敗", - "duplicated": "已複製技能", - "duplicateFailed": "複製技能失敗", - "deleted": "已刪除 {count} 個技能", - "deletedPartial": "已刪除 {ok} 個,{failed} 個失敗", - "deleteFailed": "刪除技能失敗", - "importedFromAgent": "已匯入 {count} 個技能", - "importedFromAgentPartial": "已匯入 {ok} 個,{failed} 個失敗", - "importFromAgentAllSkipped": "無需匯入——{count} 個已在庫中", - "importFromAgentFailed": "從 Agent 匯入失敗" - } - }, - "CodexModelEditor": { - "customizedNotice": "你已自訂模型清單,codeg 將接管 codex 的完整模型表。codex 日後新增的官方模型不會自動出現——點擊下方重新整理並再次儲存即可同步。清空所有自訂即可交回 codex 自動更新。", - "officialsTitle": "官方模型", - "officialsHint": "自動納入你啟動的 codex 的官方模型;可刪除不需要的。", - "officialsEmpty": "暫無官方模型。", - "refresh": "從 codex 重新整理", - "readdOfficial": "重新加入官方", - "customsTitle": "自訂模型", - "customsEmpty": "暫無自訂模型。", - "addCustom": "新增自訂", - "slugPlaceholder": "模型 id(slug)", - "displayNamePlaceholder": "顯示名稱", - "contextWindow": "上下文", - "makeDefault": "設為預設", - "defaultHint": "預設模型", - "remove": "移除", - "advanced": "進階", - "baseTemplate": "基礎範本", - "baseTemplateHint": "從哪個官方模型複製必填欄位(系統提示詞、工具、限制)。", - "groupBehavior": "行為與能力", - "fieldReasoningLevel": "預設推理強度", - "fieldReasoningSummary": "推理摘要", - "fieldVerbosity": "詳細程度", - "fieldShellType": "Shell 類型", - "fieldApplyPatch": "套用修補工具", - "fieldReasoningSummaries": "推理摘要支援", - "fieldSupportVerbosity": "詳細程度控制", - "fieldParallelToolCalls": "並行工具呼叫", - "fieldSearchTool": "網路搜尋工具", - "optNone": "無", - "groupInstructions": "描述與系統提示詞", - "fieldDescription": "描述", - "baseInstructions": "系統提示詞(base_instructions)" - }, - "DiagnosticsSettings": { - "title": "環境診斷", - "description": "檢查本應用在自身行程中如何解析該智能體的 CLI——這可能與你的終端機不同。", - "loading": "正在執行診斷…", - "error": "診斷失敗", - "rerun": "重新執行", - "copyAll": "複製全部", - "copied": "診斷資訊已複製到剪貼簿", - "button": "診斷", - "verdict": { - "ok": "環境正常。若仍提示未安裝,請徹底重新啟動應用以重新整理前綴快取。", - "node_missing": "在應用的 PATH 上找不到 Node.js。", - "npm_missing": "在應用的 PATH 上找不到 npm。", - "not_installed": "此智能體似乎尚未安裝。", - "installed_but_unresolved": "紀錄顯示已安裝,但應用無法定位其執行檔。", - "user_prefix_not_on_path": "安裝到了回退前綴(~/.codeg/npm-global),但它不在應用的 PATH 上。請徹底重新啟動應用後再試。", - "homebrew_bin_not_on_path": "安裝在 Homebrew 的 bin 目錄下,但它不在應用的 PATH 上(Apple Silicon keg 拆分)。", - "terminal_only_path": "此命令在你的終端機能解析,但在應用中不能——這是 GUI PATH 差異。請從終端機啟動應用,或在智能體設定中重新安裝。", - "npm_prefix_timeout": "npm prefix -g 太慢(超過 1.5 秒),已略過回退偵測。請重新啟動應用後再試。", - "node_too_old": "目前 Node.js 版本低於此智能體的要求。請升級 Node.js。", - "adapter_missing_native_present": "你本機的 {agent} CLI 確實安裝了,但 Codeg 啟動的是另一個 ACP 轉接器套件,而它還沒安裝。到「智能體設定」中安裝即可 —— 它不會動到你的 CLI,登入狀態也是共用的。", - "adapter_missing": "Codeg 為 {agent} 啟動的是獨立的 ACP 轉接器套件,目前尚未安裝。請到「智能體設定」中安裝 —— 只安裝廠商 CLI 是不夠的。" - } - }, - "TokenUsage": { - "title": "Token 用量", - "rangeLabel": "時間範圍", - "range7d": "近 7 天", - "range30d": "近 30 天", - "range90d": "近 90 天", - "rangeThisMonth": "本月", - "rangeThisYear": "今年", - "rangeAll": "全部", - "rangeCustom": "自訂", - "moreRanges": "更多", - "customRangePick": "選擇日期範圍", - "bucketLabel": "統計粒度", - "bucketDay": "依天", - "bucketWeek": "依週", - "bucketMonth": "依月", - "bucketUnitDay": "天", - "bucketUnitWeek": "週", - "bucketUnitMonth": "月", - "folderFilter": "資料夾", - "allFolders": "全部資料夾", - "agentFilter": "智慧代理", - "allAgents": "全部智慧代理", - "modelFilter": "模型", - "allModels": "全部模型", - "searchPlaceholder": "搜尋…", - "noMatches": "沒有符合項目", - "clearFilter": "清除選擇", - "resetFilters": "重設篩選", - "refresh": "重新整理", - "rebuild": "全量重建", - "rebuildHint": "捨棄已統計的資料並重新解析全部工作階段紀錄。當紀錄被 codeg 以外的 CLI 追加過時使用。", - "syncing": "正在統計工作階段…", - "syncProgress": "{done} / {total}", - "syncDone": "已統計 {synced} 個工作階段", - "syncFailed": "部分工作階段讀取失敗", - "syncBusy": "已有一次重新整理進行中", - "lastSynced": "更新於 {time}", - "lastSyncedNever": "尚未統計", - "tileTotal": "總 Token", - "tileSessions": "工作階段數", - "tileTurns": "對話輪次", - "tileActiveDays": "活躍天數", - "tileGenTime": "生成時長", - "vsPrevious": "對比上一週期", - "deltaNew": "新增", - "trendTitle": "用量趨勢", - "trendEmpty": "此範圍內沒有用量", - "trendTurns": "輪次", - "trendSessions": "工作階段", - "compositionTitle": "Token 花在哪裡", - "compositionHint": "輸入是你送出的內容,輸出是模型寫回來的,快取讀取則是不必再按原價重送的上下文。", - "compositionNote": "這些快取命中若按原價重送,要多花 {value}。", - "inputTokens": "輸入", - "outputTokens": "輸出", - "cacheWrite": "快取寫入", - "cacheRead": "快取讀取", - "freshTokens": "新算 Token", - "cacheHitCaption": "快取命中", - "cacheHeroTitleHigh": "上下文大多不必重送", - "cacheHeroTitleLow": "多數上下文仍按原價計算", - "cacheHeroDesc": "{cached} 的上下文由快取承擔,這段時間真正新算的只有 {fresh}。", - "cacheSavedSuffix": "省下的重送量相當於 {saved}。", - "avgPerSession": "平均每工作階段", - "avgTurnsPerSession": "平均每個工作階段 {count} 輪", - "avgPerActiveDay": "平均每活躍日", - "peakBucket": "最高的一{bucket}", - "peakHour": "尖峰時段", - "daysValue": "{count} 天", - "idleDays": "空轉天數", - "byFolderTitle": "依資料夾", - "byAgentTitle": "依智慧代理", - "byModelTitle": "依模型", - "distributionTitle": "用量分布", - "distributionHint": "工作階段與 Token 依所選維度歸集,點任一列可依它篩選。", - "otherLabel": "其他", - "unknownModel": "未標註模型", - "emptyBreakdown": "尚無紀錄", - "sessionsCount": "{count} 個工作階段", - "heatmapTitle": "你的編碼作息", - "heatmapHint": "依本地星期與小時統計的 Token 分佈。", - "heatmapPeakHint": "最密集的時段在 {hour}:00 前後。", - "less": "少", - "more": "多", - "heatmapCell": "{weekday} {hour}:00 — {value} tokens", - "weekMon": "一", - "weekTue": "二", - "weekWed": "三", - "weekThu": "四", - "weekFri": "五", - "weekSat": "六", - "weekSun": "日", - "topSessionsTitle": "消耗最高的工作階段", - "untitledSession": "未命名工作階段", - "topSessionsEmpty": "此範圍內沒有工作階段", - "streakLongest": "最長連續", - "streakLongestDays": "最長連續 {count} 天", - "share": "分享", - "moreActions": "更多操作", - "shareDialogTitle": "分享你的用量卡片", - "shareDialogHint": "卡片內容就是你目前所選的時間範圍與篩選條件。", - "shareSave": "儲存圖片", - "shareCopy": "複製圖片", - "shareCopied": "已複製到剪貼簿", - "shareSaved": "圖片已儲存", - "shareFailed": "圖片產生失敗", - "shareRendering": "產生中…", - "cardHeading": "我的 AI 編碼戰績", - "cardRangeAll": "全部時間", - "cardTotalLabel": "累計 Token", - "cardFooter": "由 codeg 產生", - "cardTopModels": "常用模型", - "cardTopProjects": "主力專案", - "archetypeNightOwl": "深夜工程師", - "archetypeNightOwlDesc": "{percent}% 的 Token 燒在天黑之後。", - "archetypeEarlyBird": "清晨型選手", - "archetypeEarlyBirdDesc": "{percent}% 的 Token 在早上 9 點前就用掉了。", - "archetypeWeekendWarrior": "週末戰士", - "archetypeWeekendWarriorDesc": "{percent}% 的 Token 發生在週末。", - "archetypeCacheMaster": "快取大師", - "archetypeCacheMasterDesc": "{percent}% 的上下文來自快取。", - "archetypeMarathoner": "長跑選手", - "archetypeMarathonerDesc": "連續 {days} 天沒有中斷。", - "archetypePolyglot": "多面手", - "archetypePolyglotDesc": "{count} 個智慧代理都在主力使用。", - "archetypeLaserFocus": "專注一役", - "archetypeLaserFocusDesc": "{percent}% 的 Token 投在同一個專案上。", - "archetypeDeepDiver": "深潛者", - "archetypeDeepDiverDesc": "平均每個工作階段 {averageK}K tokens。", - "archetypeSteady": "穩定輸出", - "archetypeSteadyDesc": "累計 {days} 天在寫程式。", - "emptyTitle": "還沒有可統計的資料", - "emptyHint": "codeg 直接從各智慧代理自己的工作階段紀錄讀取 Token 數。點一下重新整理,把本機已有的紀錄統計進來。", - "emptyAction": "統計我的工作階段", - "loadFailed": "用量載入失敗", - "truncatedNotice": "此範圍過大 —— 下面的數字只涵蓋其中最近的一段。" - } -} +{ + "Language": { + "followSystem": "跟隨系統", + "english": "英文", + "simplifiedChinese": "簡體中文", + "traditionalChinese": "繁體中文", + "japanese": "日語", + "korean": "韓語", + "spanish": "西班牙語", + "german": "德語", + "french": "法語", + "portuguese": "葡萄牙語", + "arabic": "阿拉伯語" + }, + "GitCredentialDialog": { + "title": "需要身份驗證", + "description": "遠端伺服器要求輸入憑據。請輸入使用者名稱和密碼(或個人存取權杖)。", + "username": "使用者名稱", + "usernamePlaceholder": "使用者名稱或電子郵件", + "password": "密碼 / 權杖", + "passwordPlaceholder": "密碼或個人存取權杖", + "passwordHint": "請輸入伺服器的使用者名稱和密碼。", + "cancel": "取消", + "authenticate": "驗證", + "authenticating": "驗證中...", + "invalidCredentials": "憑據無效,請重試。", + "saveCredentials": "儲存憑據以供後續操作使用", + "githubTitle": "GitHub 身份驗證", + "githubDescription": "輸入個人存取權杖以連線 GitHub。權杖驗證成功後將自動儲存至帳號列表。", + "githubToken": "個人存取權杖", + "githubTokenPlaceholder": "ghp_xxxxxxxxxxxx", + "githubTokenHint": "在 GitHub → Settings → Developer settings → Personal access tokens 中產生權杖。", + "githubAuthenticate": "驗證並連線", + "generateToken": "產生權杖" + }, + "SettingsShell": { + "title": "設定", + "preferences": "偏好設定", + "nav": { + "general": "一般", + "appearance": "外觀", + "agents": "智能體", + "mcp": "MCP", + "skills": "Skills", + "shortcuts": "快捷鍵", + "version_control": "版本控制", + "system": "系統", + "chat_channels": "訊息頻道", + "web_service": "Web 服務", + "model_providers": "模型供應商", + "experts": "專家", + "science": "科學研究", + "office_tools": "辦公工具", + "skill_packs": "技能包", + "quick_messages": "快捷訊息", + "logs": "執行日誌" + } + }, + "AppearanceSettings": { + "sectionTitle": "主題外觀", + "sectionDescription": "選擇淺色、深色或跟隨系統主題,設定會自動儲存。", + "themeMode": "主題模式", + "placeholder": "請選擇主題模式", + "system": "跟隨系統", + "light": "淺色", + "dark": "深色", + "currentTheme": "目前生效主題:{theme}", + "resolvedTheme": { + "light": "淺色", + "dark": "深色", + "unknown": "未知" + }, + "themeColor": { + "sectionTitle": "主題顏色", + "sectionDescription": "選擇按鈕、強調色和高亮使用的色調。", + "current": "目前顏色:{color}", + "options": { + "neutral": "Neutral", + "zinc": "Zinc", + "slate": "Slate", + "stone": "Stone", + "gray": "Gray", + "red": "Red", + "rose": "Rose", + "orange": "Orange", + "green": "Green", + "blue": "Blue", + "yellow": "Yellow", + "violet": "Violet" + } + }, + "customStyle": { + "sectionTitle": "自訂樣式", + "sectionDescription": "在目前主題的基礎上微調配色,或寫入自己的 CSS。覆寫疊加在基底預設之上,切換預設後依然保留。", + "summarySuspended": "已停用", + "summaryDefault": "跟隨預設", + "summaryTokens": "{count, plural, other {# 項覆寫}}", + "summaryCss": "自訂 CSS", + "suspendedByShortcut": "自訂樣式已停用。在恢復之前,這裡的設定都不會生效。", + "suspendedBySafeParam": "本視窗以安全外觀模式開啟,自訂樣式在此不生效,其它視窗不受影響。", + "resume": "恢復自訂樣式", + "enableTheme": "啟用自訂配色", + "editingLight": "正在編輯淺色模式的取值。切換到深色模式可單獨設定深色。", + "editingDark": "正在編輯深色模式的取值。切換到淺色模式可單獨設定淺色。", + "resetToken": "還原為預設取值", + "radius": "圓角", + "radiusHint": "從 sm 到 4xl 的整套圓角尺寸都由它衍生,一個滑桿即可改變全域圓角。", + "advanced": "進階(另有 {count} 個變數)", + "enableCss": "啟用自訂 CSS", + "cssRisk": "進階功能。自訂 CSS 會壓過所有內建樣式,寫壞可能導致介面無法使用。", + "editCss": "編輯 CSS…", + "cssPresent": "已儲存 {size} KB", + "cssEmpty": "尚未儲存內容", + "escapeHint": "介面被改壞了?按 {shortcut} 可停用全部自訂樣式,也可以用 safeStyle=1 查詢參數開啟視窗。", + "copyTheme": "複製主題 JSON", + "importTheme": "匯入主題…", + "clearTheme": "清除覆寫", + "interopHint": "主題採用 shadcn 的 registry:theme 格式,可以直接貼上任意 shadcn 主題,匯出的主題也能用在任何 shadcn 專案裡。", + "importTitle": "匯入主題", + "importDescription": "貼上 shadcn 的 registry:theme 項目、裸的 light/dark 物件,或者單層的 token 對應表。", + "readClipboard": "讀取剪貼簿", + "importConfirm": "匯入", + "cancel": "取消", + "apply": "套用", + "toasts": { + "copied": "主題 JSON 已複製", + "copyFailed": "無法寫入剪貼簿", + "clipboardReadFailed": "無法讀取剪貼簿,請手動貼上", + "importFailed": "這段 JSON 裡沒有可用的主題變數", + "imported": "主題已匯入" + }, + "css": { + "dialogTitle": "自訂 CSS", + "dialogDescription": "對所有 codeg 視窗生效。修改會即時預覽,點擊「套用」才會儲存。", + "size": "{used} KB / {max} KB", + "ruleCount": "{count} 條規則", + "errorTooLarge": "內容過大,無法儲存,請精簡到上限以內。", + "errorImportEscaped": "剝離後仍偵測到 @import(跳脫寫法),請手動移除後再儲存。", + "warnNoRules": "沒有解析出任何規則,請檢查語法。", + "noticeImportsRemoved": "已移除 {count} 條 @import:它們會拉取遠端樣式表。", + "noticeRemoteUrl": "含遠端 url(),套用後會發起網路請求。", + "noticePreviewSuspended": "自訂樣式已停用,此處預覽不會生效。", + "noticeDisabled": "自訂 CSS 未啟用。這裡可以預覽,但啟用後才會真正生效。", + "hintTokens": "提示:你覆寫的顏色可以直接用 var(--primary)、var(--background) 等引用。" + } + }, + "zoomLevel": { + "sectionTitle": "視窗縮放", + "sectionDescription": "整體放大或縮小介面,立即生效,依裝置分別儲存。", + "placeholder": "請選擇縮放檔位", + "default": "預設", + "current": "目前縮放:{zoom}%" + }, + "fonts": { + "sectionTitle": "字型", + "sectionDescription": "為介面、程式碼編輯器與終端機分別選擇字型。內建字型會按需載入;選擇「自訂…」可使用系統已安裝的任意字型。", + "interface": "介面", + "editor": "編輯器", + "terminal": "終端機", + "groupSans": "無襯線", + "groupMono": "等寬", + "custom": "自訂…", + "customPlaceholder": "字型名稱,如 Fira Code", + "fontSize": "字級", + "ligatures": "啟用連字", + "ligaturesUnavailable": "此字型不含連字", + "wordWrap": "啟用自動換行", + "terminalLigaturesHint": "終端機連字僅對內建程式字型生效。", + "preview": "預覽" + }, + "welcomePanel": { + "sectionTitle": "模式選擇區域", + "sectionDescription": "新會話頁面輸入框上方顯示的「程式開發 / 日常辦公」快捷卡片區域。", + "showQuickActions": "在新會話頁面顯示" + }, + "workspaceBackground": { + "sectionTitle": "工作區背景", + "sectionDescription": "在整個工作區背後顯示一張圖片。側邊欄與面板會變半透明並磨砂讓圖片透出,遮罩確保文字可讀。", + "enable": "啟用背景圖片", + "image": "圖片", + "chooseImage": "選擇圖片", + "replaceImage": "更換圖片", + "removeImage": "移除", + "fillMode": "填滿方式", + "fillModes": { + "cover": "覆蓋", + "contain": "適應", + "center": "置中", + "tile": "平鋪" + }, + "maskOpacity": "遮罩不透明度", + "maskOpacityHint": "數值越高,圖片越向主題背景色淡化,文字對比越清晰。", + "imageBlur": "圖片模糊", + "panelOpacity": "面板不透明度", + "panelOpacityHint": "側邊欄、面板與標籤列的不透明程度。越低,透出的圖片越多。", + "errorTooLarge": "圖片太大(最大 16 MB)。", + "errorUploadFailed": "設定背景圖片失敗。" + } + }, + "SystemSettings": { + "loading": "載入中...", + "sectionTitle": "系統管理", + "sectionDescription": "管理網路代理、應用升級與語言偏好。", + "proxyTitle": "網路代理", + "proxyDescription": "啟用後,後續網路請求將優先走該代理(包含 ACP 對話、Agent 安裝、Git 遠端操作等)。", + "loadFailed": "載入失敗:{message}", + "enableProxy": "啟用系統代理", + "proxyAddress": "代理位址", + "proxyHint": "支援 http(s)/socks5,範例:{example}。僅在啟用系統代理時生效。", + "save": "儲存", + "saving": "儲存中...", + "proxyRequired": "啟用代理時必須填寫代理位址", + "saveSuccess": "系統代理設定已儲存", + "saveFailed": "儲存失敗:{message}", + "languageTitle": "語言", + "languageDescription": "設定應用語言。跟隨系統時,若系統語言不受支援將回退為英文。", + "appLanguage": "應用語言", + "languageSaveSuccess": "語言設定已儲存", + "languageSaveFailed": "語言設定儲存失敗:{message}", + "updateTitle": "應用升級", + "versionTitle": "軟體更新", + "updateDescription": "點擊檢查後會從設定的發佈來源拉取最新版本資訊,有新版本時可直接下載並安裝。", + "currentVersion": "目前版本", + "upgradableVersion": "最新版本", + "none": "暫無", + "lastChecked": "上次檢查:{time}", + "updateError": "更新異常:{message}", + "checking": "檢查中...", + "checkUpdate": "檢查更新", + "updating": "升級中...", + "downloading": "下載中...", + "upgradeTo": "升級到 v{version}", + "viewRelease": "查看 v{version} 發布", + "foundUpdate": "發現新版本 v{version}", + "alreadyLatest": "目前已是最新版本", + "checkUpdateFailed": "檢查更新失敗:{message}", + "installSuccess": "升級包已安裝,正在重新啟動應用", + "installFailed": "升級失敗:{message}", + "upgradeSuccess": "升級完成,正在重新載入...", + "restartTimeout": "服務未能即時恢復,請檢查容器或服務記錄。", + "restartingIn": "將在 {seconds} 秒後重新啟動...", + "waitingForServer": "正在等待服務恢復...", + "restartToUpdate": "重新啟動以更新", + "newVersionBadge": "新版本 v{version}", + "updateAvailableTitle": "發現新版本", + "releaseNotesTitle": "更新內容", + "remindLater": "稍後", + "retry": "重試", + "stepDownload": "下載", + "stepInstall": "安裝", + "stepRestart": "重新啟動", + "updateReadyHint": "新版本已下載,重新啟動以完成更新。", + "restarting": "正在重新啟動…", + "dockerUpgradeHint": "現在升級的是正在執行的容器。容器一旦被重新建立即遺失——如需保留,請拉取或建置新版本映像後重新建立容器。", + "upgradeRolledBack": "升級失敗,伺服器已自動回復到上一版本。", + "serverUnreachable": "無法連線到伺服器以開始升級。請確認伺服器正在執行後重試。", + "rollbackButton": "復原", + "rollingBack": "復原中...", + "rollbackDescription": "還原至上次升級前安裝的版本。", + "rollbackConfirmTitle": "復原到上一個版本?", + "rollbackConfirmDescription": "伺服器將重新啟動並執行上次升級前安裝的版本。較新的版本仍可再次安裝。", + "rollbackConfirm": "復原", + "rollbackCancel": "取消", + "rollbackSuccess": "已復原到上一個版本,正在重新載入……", + "rollbackFailed": "復原失敗,請檢查伺服器日誌。", + "updateErrors": { + "sourceUnavailable": "無法連線更新來源,請檢查網路或代理設定後重試。", + "network": "網路連線異常,請檢查網路或代理設定後重試。", + "downloadFailed": "下載更新包失敗,請稍後再試。", + "installFailed": "安裝更新失敗,請關閉應用後重試。", + "unknown": "更新失敗,請稍後再試。" + } + }, + "VersionControlSettings": { + "loading": "載入中...", + "sectionTitle": "版本控制", + "sectionDescription": "設定 Git 執行檔並管理 GitHub 帳號。", + "gitTitle": "Git 設定", + "gitDescription": "設定應用程式使用的 Git 執行檔。", + "gitDetected": "已偵測到 Git", + "gitNotFound": "未在系統中找到 Git", + "gitVersion": "版本", + "gitPath": "路徑", + "customGitPath": "自訂 Git 路徑", + "customGitPathPlaceholder": "/usr/bin/git", + "customGitPathHint": "留空則使用自動偵測的路徑。", + "test": "測試", + "testing": "測試中...", + "testSuccess": "Git 執行檔有效。", + "testFailed": "Git 測試失敗:{message}", + "save": "儲存", + "saving": "儲存中...", + "saveSuccess": "Git 設定已儲存。", + "saveFailed": "儲存失敗:{message}", + "githubTitle": "GitHub 帳號", + "githubDescription": "管理用於身份驗證的 GitHub 帳號。權杖儲存在本機。", + "noAccounts": "尚未設定 GitHub 帳號。", + "addAccount": "新增帳號", + "serverUrl": "伺服器網址", + "serverUrlPlaceholder": "https://github.com", + "token": "個人存取權杖", + "tokenPlaceholder": "ghp_xxxxxxxxxxxx", + "generateToken": "產生權杖", + "tokenHint": "在 GitHub → Settings → Developer settings → Personal access tokens 中產生權杖。", + "validateAndAdd": "驗證並新增", + "validating": "驗證中...", + "addSuccess": "帳號 {username} 新增成功。", + "addFailed": "新增帳號失敗:{message}", + "testConnection": "測試", + "connectionSuccess": "連線成功。", + "connectionFailed": "連線失敗:{message}", + "setDefault": "設為預設", + "defaultLabel": "預設", + "defaultSet": "預設帳號已更新。", + "removeAccount": "刪除", + "removeConfirmTitle": "刪除帳號", + "removeConfirmMessage": "確定要刪除帳號「{username}」嗎?", + "removeConfirm": "刪除", + "removeCancel": "取消", + "removeSuccess": "帳號已刪除。", + "scopes": "權限範圍", + "loadFailed": "載入設定失敗:{message}", + "gitAccount": { + "sectionTitle": "Git 伺服器帳號", + "sectionDescription": "管理非 GitHub 的 Git 伺服器憑據(GitLab、Bitbucket、自建服務等)。", + "noAccounts": "尚未設定 Git 伺服器帳號。", + "addAccount": "新增帳號", + "addTitle": "新增 Git 帳號", + "addDescription": "輸入伺服器網址、使用者名稱和密碼或存取權杖。", + "serverUrl": "伺服器網址", + "serverUrlPlaceholder": "https://gitlab.example.com", + "username": "使用者名稱", + "usernamePlaceholder": "使用者名稱或電子郵件", + "password": "密碼 / 權杖", + "passwordPlaceholder": "密碼或存取權杖", + "passwordHint": "輸入伺服器的密碼或個人存取權杖。", + "add": "新增", + "serverRequired": "請輸入伺服器網址。", + "usernameRequired": "請輸入使用者名稱。", + "passwordRequired": "請輸入密碼。" + } + }, + "ShortcutSettings": { + "sectionTitle": "快捷鍵", + "resetDefault": "恢復預設", + "recordInstruction": "點擊右側按鈕後按下組合鍵即可修改。建議使用 Ctrl/Cmd、Alt、Shift 的組合。按 Esc 可取消錄製。", + "recording": "按下快捷鍵...", + "toasts": { + "conflict": "快捷鍵已被「{title}」占用", + "updated": "快捷鍵已更新", + "invalid": "快捷鍵無效,請重試", + "reset": "已恢復預設快捷鍵" + }, + "actions": { + "toggle_search": { + "title": "打開搜尋", + "description": "打開或關閉會話搜尋面板" + }, + "toggle_sidebar": { + "title": "切換左側邊欄", + "description": "顯示或隱藏會話列表側邊欄" + }, + "toggle_terminal": { + "title": "切換終端", + "description": "顯示或隱藏底部終端面板" + }, + "new_terminal_tab": { + "title": "新增終端", + "description": "當最近滑鼠活動在終端時新增終端分頁" + }, + "close_current_terminal_tab": { + "title": "關閉目前終端", + "description": "當最近滑鼠活動在終端時關閉目前終端分頁" + }, + "toggle_aux_panel": { + "title": "切換右側面板", + "description": "顯示或隱藏輔助資訊面板" + }, + "new_conversation": { + "title": "新增會話", + "description": "在目前資料夾中建立新的對話分頁" + }, + "open_folder": { + "title": "打開資料夾", + "description": "打開資料夾選擇器並在新視窗中開啟" + }, + "open_settings": { + "title": "打開設定", + "description": "打開設定視窗" + }, + "close_current_tab": { + "title": "關閉目前分頁", + "description": "關閉目前會話或檔案分頁" + }, + "close_all_file_tabs": { + "title": "關閉全部檔案分頁", + "description": "當檔案面板處於作用中狀態時關閉所有開啟的檔案分頁" + }, + "next_tab": { + "title": "下一個標籤頁", + "description": "切換到下一個會話或檔案標籤頁" + }, + "prev_tab": { + "title": "上一個標籤頁", + "description": "切換到上一個會話或檔案標籤頁" + }, + "send_message": { + "title": "傳送訊息", + "description": "在輸入框中傳送目前的訊息" + }, + "newline_in_message": { + "title": "訊息換行", + "description": "在輸入框中插入換行符" + }, + "toggle_custom_style": { + "title": "停用/恢復自訂樣式", + "description": "逃生艙:一鍵關閉全部自訂配色與 CSS,再按一次恢復" + } + } + }, + "SkillsSettings": { + "title": "Skills", + "description": "左側選擇 Skill,右側預設預覽 Markdown,點擊編輯後可修改並儲存。", + "loadingAgents": "正在載入支援 Skills 的 Agent...", + "emptyNoManageableAgents": "目前沒有可管理 Skills 的 Agent。", + "managedTarget": "管理對象", + "selectAgentPlaceholder": "請選擇 Agent", + "searchPlaceholder": "搜尋名稱 / ID / 路徑...", + "skillsList": "Skills 列表", + "loadingSkills": "載入 Skills 中...", + "agentNotSupported": "目前 Agent 暫不支援 Skills 管理。", + "emptySkills": "暫無 Skill,可點擊「新增 Skill」。", + "newSkillTitle": "新增 Skill", + "skillInfo": "Skill 資訊", + "skillIdPlaceholder": "Skill ID(例如:my-skill)", + "skillsDirectoryWithPath": "Skills目錄:{path}", + "skillsDirectoryNeedId": "Skills目錄:請輸入 Skill ID 以產生完整路徑", + "markdownContent": "Markdown 內容", + "editingStatus": "編輯中", + "previewStatus": "預覽中", + "contentPlaceholder": "輸入 Skill 文字內容...", + "metadataTitle": "Skills 中繼資訊", + "onlyYamlMetadata": "該 Skill 僅包含 YAML 中繼資訊。", + "emptyContentHint": "暫無內容。點擊「編輯」開始輸入。", + "loadingSkill": "正在載入 Skill...", + "emptyNoAgents": "暫無可用 Agent。", + "noSelectionHint": "從左側選擇一個 Skill,或點擊「新建 Skill」建立。", + "systemBadge": "系統", + "systemHint": "CLI 內建 Skill · 唯讀", + "scope": { + "global": "全域", + "folder": "資料夾", + "selectFolderPlaceholder": "選擇資料夾", + "noFolders": "找不到任何資料夾", + "pickFolderHint": "選擇一個資料夾以檢視其 Skills。" + }, + "actions": { + "preview": "預覽", + "edit": "編輯", + "openInWindow": "在新視窗打開", + "delete": "刪除", + "deleting": "刪除中...", + "refresh": "刷新", + "newSkill": "新增 Skill", + "reset": "重置", + "save": "儲存", + "saving": "儲存中...", + "cancel": "取消" + }, + "deleteDialog": { + "title": "刪除 Skill", + "confirm": "確認刪除目前 Skill 嗎?此操作無法復原。", + "confirmWithNamePrefix": "確認刪除 Skill", + "confirmWithNameSuffix": "嗎?此操作無法復原。" + }, + "toasts": { + "loadFailed": "載入 Skill 失敗", + "openFolderFailed": "打開目錄失敗", + "noSkillDirectory": "目前 Agent 未找到可用的 Skills 目錄", + "nameRequired": "Skill 名稱不能為空", + "updated": "Skill 已更新", + "created": "Skill 已建立", + "saveFailed": "儲存 Skill 失敗", + "deleted": "Skill 已刪除", + "deleteFailed": "刪除 Skill 失敗" + }, + "templates": { + "gemini": "---\nname: example-skill\ndescription: Describe when this skill should be used.\n---\n\n# Skill Name\n\nInstructions for the agent when this skill is active.\n\n## Workflow\n\n1. Add actionable step one.\n2. Add actionable step two.\n", + "openCode": "---\nname: example-skill\ndescription: Describe when this skill should be used.\n---\n\n# Purpose\n\nDescribe what this skill helps with.\n\n# Steps\n\n1. Add actionable step one.\n2. Add actionable step two.\n", + "openClaw": "---\nname: example-skill\ndescription: Describe when this skill should be used.\nuser-invocable: true\ndisable-model-invocation: false\n---\n\n# Purpose\n\nDescribe what this skill helps with.\n\n# Instructions\n\n1. Add actionable instruction one.\n2. Add actionable instruction two.\n", + "default": "---\nname: example-skill\ndescription: Describe when this skill should be used.\n---\n\n# Skill: example-skill\n\n## When to use\n\n- Describe trigger conditions.\n\n## Instructions\n\n1. Add actionable instruction one.\n2. Add actionable instruction two.\n" + } + }, + "McpSettings": { + "loading": "載入中...", + "summary": { + "missingCommand": "(缺少 command)", + "missingUrl": "(缺少 url)" + }, + "protocol": { + "stdio": "Stdio" + }, + "errors": { + "selectInstallProtocol": "請選擇安裝協議", + "fieldRequired": "{field} 為必填項", + "fieldNeedsBoolean": "{field} 需要 true 或 false", + "fieldNeedsNumber": "{field} 需要數字", + "fieldNeedsInteger": "{field} 需要整數", + "fieldInvalidJson": "{field} JSON 無效:{message}", + "fieldOutOfRange": "{field} 的值不在可選範圍內", + "jsonEmpty": "{name} 不能為空", + "jsonInvalid": "{name} 不是合法 JSON:{message}", + "jsonMustBeObject": "{name} 必須是 JSON 物件", + "specMustBeObject": "MCP 設定必須是 JSON 物件。", + "missingType": "MCP 設定缺少 type 欄位。請填寫 stdio、http(別名 streamable-http、streamableHttp)、sse 其中之一。", + "unsupportedType": "不支援的 MCP type:{type}。支援的類型:stdio、http(別名 streamable-http、streamableHttp)、sse。", + "codexEntryUnsupportedType": "Codex MCP 項目 {id} 的 type 不受支援:{type}。支援的類型:stdio、http(別名 streamable-http、streamableHttp)、sse。", + "unsupportedTransportType": "不支援的 transport 類型:{type}。支援的類型:http(別名 streamable-http、streamableHttp)、sse。", + "stdioCommandRequired": "stdio 類型的 MCP 必須填寫非空的 command 欄位。", + "remoteUrlRequired": "遠端 MCP 必須填寫非空的 url 欄位。", + "appsRequired": "請至少選擇一個目標 App。" + }, + "jsonNames": { + "localConfig": "MCP 配置", + "installConfig": "安裝配置" + }, + "toasts": { + "uninstalled": "已卸載 MCP", + "uninstallFailed": "卸載失敗:{message}", + "selectAtLeastOneApp": "請至少選擇一個目標應用", + "saveSuccess": "儲存成功", + "saveFailed": "儲存失敗:{message}", + "installed": "已安裝 {name}", + "installFailed": "安裝失敗:{message}", + "serverIdRequired": "Server ID 不能為空", + "serverIdExists": "Server ID \"{id}\" 已存在,請編輯現有項或更換名稱", + "created": "MCP 已建立" + }, + "installDialog": { + "title": "確認安裝 MCP", + "descriptionWithName": "將 {name} 安裝到本地配置。", + "description": "選擇安裝目標應用。", + "protocol": "協議", + "selectProtocol": "選擇協議", + "parameters": "配置參數", + "booleanPlaceholder": "請選擇 true/false", + "selectOneValue": "選擇一個值", + "targetApps": "目標應用" + }, + "actions": { + "cancel": "取消", + "confirmInstall": "確認安裝", + "installing": "安裝中", + "uninstall": "卸載", + "uninstalling": "卸載中", + "viewDetails": "查看詳情", + "save": "儲存", + "saving": "儲存中", + "install": "安裝", + "refresh": "重新整理", + "newMcp": "新建 MCP", + "create": "建立", + "creating": "建立中..." + }, + "tabs": { + "local": "本地 MCP", + "market": "MCP 市場" + }, + "local": { + "filterPlaceholder": "篩選本地 MCP...", + "loadFailed": "載入失敗:{message}", + "empty": "目前未檢測到本地 MCP。", + "description": "本地 MCP 配置可直接編輯並儲存。", + "enabledApps": "啟用應用", + "configJson": "MCP 配置(JSON)", + "draftTitle": "新建 MCP", + "draftDescription": "填寫 Server ID 與設定以建立本地 MCP 伺服器。", + "serverIdLabel": "Server ID", + "serverIdPlaceholder": "Server ID(例如:my-mcp)", + "typeHint": "支援類型:stdio、http(別名 streamable-http、streamableHttp)、sse。env 僅適用於 stdio;遠端 MCP 請透過 headers 欄位傳遞認證 token。", + "envOnRemoteWarning": "偵測到遠端 MCP 設定中包含 env 欄位。env 僅 stdio 類型使用,遠端 MCP 應透過 headers 攜帶認證資訊,env 欄位儲存時會被忽略。" + }, + "market": { + "selectMarketplace": "選擇市場", + "searchPlaceholder": "搜尋 MCP...", + "searchFailed": "搜尋失敗:{message}", + "loadingList": "載入 MCP 列表...", + "empty": "暫無 MCP 結果。", + "loadingDetail": "載入市場詳情...", + "detailLoadFailed": "載入詳情失敗:{message}", + "owner": "擁有者:{owner}", + "namespace": "命名空間:{namespace}", + "defaultInstallProtocol": "預設安裝協議", + "currentOptionParameterCount": "目前選項參數數:{count}", + "installConfigDescription": "安裝配置(JSON,可修改後安裝;修改後將覆蓋協議/參數表單)", + "selectLeftToView": "請選擇左側市場 MCP 查看詳情。" + }, + "badges": { + "verified": "已驗證", + "remote": "遠端", + "hasHomepage": "有首頁", + "uses": "{count} 次使用", + "deployed": "已部署", + "notDeployed": "未部署" + }, + "selectLeftMcp": "請選擇左側 MCP。" + }, + "AcpAgentSettings": { + "title": "Agent SDK管理", + "description": "統一管理 Agent 的連接SDK、啟用狀態、環境變數、配置管理與版本預檢資訊。", + "loadingAgents": "載入 Agent 列表中...", + "agentList": "Agent 列表", + "emptyNoAgent": "暫無可用 Agent。", + "configManagement": "配置管理", + "envVars": "環境變數", + "hostTools": { + "label": "由 Agent 自行處理檔案與指令", + "description": "codeg 不再代為提供檔案存取與終端指令,改由 Agent 在自己的行程中執行——只有這樣它自帶的沙箱與權限規則才會生效。同時會關閉向其他 Agent 委派,否則同樣的操作又會繞回 codeg 執行。codeg 本身不提供沙箱,因此請僅在 Agent 已設定沙箱時開啟。" + }, + "nativeJsonConfig": "原生 JSON 配置", + "modelHintDefault": "留空則使用系統預設模型。", + "generalConfigDescriptionClaude": "支援 API URL、API Key 與 Claude 模型快捷配置,並與原生 JSON 配置聯動。", + "generalConfigDescriptionDefault": "支援重要配置輸入(API URL、API Key、Model)和原生 JSON 配置管理。", + "multiAgent": { + "title": "多智慧體協同", + "description": "允許活躍的智慧體將子任務委派給其他智慧體。", + "enable": "啟用委派", + "enableHint": "關閉後,delegate_to_agent 工具會從智慧體的 MCP 工具清單中隱藏。", + "withheldByHostTools": "{agents} 不會拿到委派工具:它們單獨開啟了「由 Agent 自行處理檔案與命令」。", + "selfInitiate": "Allow spawn without @", + "selfInitiateHint": "When on, an agent may start a listed sub-agent on its own. An @ mention is still always honored. When off, only an @ mention starts a sub-agent.", + "depthLimit": "最大委派深度", + "depthHint": "允許範圍:{min}–{max}。限制委派鏈(根 → 子 → 孫 …)的最大遞迴深度。", + "completedCacheLabel": "已完成結果快取(MB)", + "completedCacheHint": "執行中委派工作階段已完成子代理結果的記憶體快取,僅在該工作階段執行期間保留,工作階段結束後自動清除。超出此預算時優先從記憶體中捨棄最舊的結果(仍可在子代理自己的工作階段中檢視);0 表示不限(工作階段結束後仍會清除)。", + "save": "儲存", + "saving": "儲存中…", + "saved": "委派設定已儲存", + "saveFailed": "委派設定儲存失敗", + "loadFailed": "載入委派設定失敗:{detail}", + "tabGeneral": "一般", + "tabAgentDefaults": "子智慧體設定", + "agentDefaultsDescription": "多智慧體協同在為委派呼叫啟動子智慧體時使用這些覆寫項。下方選項透過即時探測取得,所選即所用。", + "probing": "正在載入該智慧體的可用設定項…", + "probeFailed": "載入設定項失敗:{detail}", + "retry": "重試", + "noConfigAvailable": "該智慧體沒有可設定項。", + "modeLabel": "模式", + "agentDefaultHint": "智慧體預設:{value}", + "defaultOptionLabel": "預設({value})" + }, + "actions": { + "dragSort": "拖拽排序", + "dragSortAgent": "拖拽排序 {name}", + "refreshCheck": "刷新檢測", + "refreshCheckAgent": "刷新檢測 {name}", + "clickEnable": "點擊啟用 {name}", + "clickDisable": "點擊停用 {name}", + "install": "安裝", + "upgrade": "升級", + "uninstall": "卸載", + "uninstalling": "卸載中...", + "saveEnvVars": "儲存環境變數", + "saving": "儲存中...", + "saveGrokConfig": "儲存 Grok 設定", + "saveCodexConfig": "儲存 Codex 配置", + "saveGeminiConfig": "儲存 Gemini 配置", + "saveOpenCodeConfig": "儲存 OpenCode 配置", + "saveOpenClawConfig": "儲存 OpenClaw 配置", + "saveConfigManagement": "儲存配置管理", + "saveCurrentProvider": "儲存目前 Provider", + "showApiKey": "顯示 API Key", + "hideApiKey": "隱藏 API Key", + "showKey": "顯示 Key", + "hideKey": "隱藏 Key", + "showToken": "顯示 Token", + "hideToken": "隱藏 Token", + "cancel": "取消", + "delete": "刪除", + "deleting": "刪除中...", + "confirmDelete": "確認刪除", + "confirmUninstall": "確認卸載", + "saveClineConfig": "儲存 Cline 配置", + "saveHermesConfig": "儲存 Hermes 配置", + "saveCodeBuddyConfig": "儲存 CodeBuddy 設定", + "saveKimiCodeConfig": "儲存 Kimi Code 設定", + "customInstall": "自訂安裝", + "saveKimiCodeRawConfig": "儲存 config.toml", + "saveDeepSeekConfig": "儲存 DeepSeek 設定", + "diagnose": "診斷" + }, + "status": { + "enabled": "啟用", + "disabled": "停用", + "unchecked": "未檢測", + "agentEnabledAria": "{name} 已啟用", + "agentEnabledSwitch": "{name} 啟用" + }, + "preflight": { + "count": "預檢項:{count}", + "notRun": "尚未執行檢測。" + }, + "grok": { + "configDescription": "在此設定 Grok。下方控制項——權限模式、推理強度、選用的自訂(自帶端點)模型與壓縮——會合併寫入 ~/.grok/config.toml,並保留你的其他鍵與註解。登入使用你的 XAI_API_KEY 或 `grok login`。其他鍵可在「進階」中編輯。", + "permissionModeLabel": "權限模式", + "permissionDefault": "每次詢問", + "permissionAcceptEdits": "自動批准編輯", + "permissionAuto": "智慧自動批准", + "permissionAlwaysApprove": "永遠允許", + "reasoningEffortLabel": "推理級別", + "effortLow": "低(較快)", + "effortMedium": "中(均衡)", + "effortHigh": "高", + "effortXhigh": "最高", + "optionDefault": "使用預設", + "authTitle": "驗證", + "authMode": "認證方式", + "authModeApiKey": "XAI API 金鑰", + "authModeApiKeyHint": "使用 xAI 主控台的 XAI_API_KEY 認證——適用於非互動/無頭執行。儲存在該智慧體的環境變數中。", + "authModeCustom": "自訂接口", + "authModeCustomHint": "使用自訂接口(BYO 端點):在下方定義一個帶有獨立 base URL 和 API 金鑰的自訂模型,它將成為 Grok 的預設模型。", + "subscriptionHint": "使用 `grok login` 登入(SuperGrok / X Premium+)。不會儲存 API 金鑰。", + "loginHint": "在終端機執行以下指令登入,然後重新開啟此設定:", + "commandCopied": "指令已複製到剪貼簿", + "copyCommand": "複製指令", + "authKeyConfigured": "已設定 XAI_API_KEY。", + "authKeyMissing": "未設定 XAI_API_KEY。", + "advancedToggle": "進階(原始 config.toml)", + "configTomlNative": "config.toml(原生)", + "configTomlHint": "按原樣整體寫入 ~/.grok/config.toml。非法 TOML 會被拒絕,絕不因筆誤截斷檔案。", + "configTomlPlaceholder": "# 上面控制項之外的鍵,例如\n# [mcp_servers.*]、[cli]、[permission] 規則。", + "customModelTitle": "自訂模型(自帶端點)", + "customModelHint": "讓 Grok 指向自訂或自架端點。codeg 會寫入按模型的 `[model.*]` 區塊並設為預設模型。清空模型 ID 即可移除。", + "customModelIdLabel": "模型 ID", + "customModelIdPlaceholder": "grok-4.5", + "customModelIdHint": "註冊為 `[model.*]` 區塊,並作為模型名稱傳送給 API;同時設為 `[models].default`。", + "customBaseUrlLabel": "Base URL", + "customBaseUrlPlaceholder": "https://api.x.ai/v1(預設)", + "customApiBackendLabel": "API 後端", + "backendResponses": "Responses", + "backendChatCompletions": "Chat Completions", + "backendMessages": "Messages(Anthropic)", + "customApiKeyLabel": "API Key", + "customApiKeyHint": "內聯儲存於 `[model.*].api_key`,僅作用於此端點。", + "customContextWindowLabel": "上下文視窗(tokens)", + "customContextWindowHint": "選填。用於自動壓縮計時;留空則使用端點預設值。", + "autoCompactLabel": "自動壓縮閾值(%)", + "autoCompactHint": "當上下文使用率達到此百分比時壓縮對話(Grok 預設 85)。寫入 `[session]`。" + }, + "cursor": { + "configDescription": "在此設定 Cursor。先選擇驗證方式——官網訂閱(瀏覽器登入)或用於無頭/伺服器的 Cursor API 金鑰——然後選擇模型並編輯 CLI 的權限規則與沙箱。codeg 會寫入 ~/.cursor/cli-config.json,與 cursor-agent CLI 共用。", + "authTitle": "驗證", + "authChecking": "檢測中…", + "authNotInstalled": "cursor-agent 未安裝", + "authLoggedIn": "已登入", + "authNotLoggedIn": "未登入", + "loginHint": "在終端機執行以下指令登入 Cursor 帳號(會開啟瀏覽器),完成後點重新整理:", + "apiKeyLabel": "Cursor API 金鑰", + "apiKeyPlaceholder": "在 cursor.com/dashboard 取得", + "apiKeyHint": "CURSOR_API_KEY —— Cursor Dashboard 的帳號金鑰,在無頭/伺服器環境下取代瀏覽器登入。不是第三方或 OpenAI 金鑰。", + "modelTitle": "預設模型", + "loadModels": "取得模型清單", + "modelsUnavailable": "模型清單不可用", + "modelHint": "會話啟動時透過 --model 傳給 CLI;保持預設則由 Cursor 自行選擇。", + "permissionsTitle": "權限與沙箱", + "permissionsDescription": "可視化編輯 CLI 權限規則(cli-config.json)。允許規則免確認執行;拒絕規則一律攔截。", + "permissionModeLabel": "權限模式", + "permissionModeDefault": "執行前詢問(預設)", + "permissionModeForce": "全部放行 Run Everything(--force)", + "permissionModeHint": "Run Everything 以 --force 啟動工作階段:除 deny 規則外的所有工具呼叫自動放行、不再跳出確認(組織政策可能將其降級為僅按 allow 規則放行)。對新工作階段生效。", + "optionDefault": "預設(未設定)", + "sandboxLabel": "沙箱", + "sandboxEnabled": "啟用", + "sandboxDisabled": "停用", + "allowRulesLabel": "允許規則", + "denyRulesLabel": "拒絕規則", + "addRule": "新增規則", + "rulesSyntaxHint": "規則語法:Shell(命令)、Read(路徑/萬用字元)、Write(路徑/萬用字元)、WebFetch(網域)、Mcp(伺服器:工具)——deny 規則始終優先。", + "saveConfig": "儲存設定", + "advancedToggle": "進階:原始 cli-config.json", + "advancedHint": "完整的 ~/.cursor/cli-config.json。此處儲存按原文寫入;上方結構化控制項則以合併方式寫入。", + "saveRawConfig": "儲存檔案", + "authMode": "認證方式", + "subscriptionHint": "使用 Cursor 帳號登入,使用 Cursor 的模型。", + "customApiKeyRequired": "需要填寫 Cursor API 金鑰。", + "authModeApiKey": "Cursor API 金鑰(無頭/伺服器)", + "authModeApiKeyHint": "使用 Cursor 官網 Dashboard 產生的帳號 API 金鑰進行驗證(適用於無頭/伺服器環境)。這是 Cursor 帳號金鑰,不是第三方/OpenAI 端點——cursor-agent 只會連線到 Cursor 自己的後端。若要使用 codex/OpenAI 相容端點,請改用 Codex 智慧體。", + "modelPickerPlaceholder": "搜尋模型…", + "modelNoMatch": "沒有相符的模型", + "modelsNeedAuth": "登入後載入模型清單。", + "modelDefaultBadge": "預設" + }, + "deepseek": { + "configManagement": "DeepSeek Harness 設定", + "configDescription": "端點與金鑰是 deepseek-acp 啟動時讀取的環境變數。模型與推理等級是工作階段層級的選擇器,在輸入框裡切換。", + "baseUrlLabel": "API 端點", + "baseUrlHint": "留空則使用官方端點。儲存後對新建的工作階段生效——正在進行的工作階段需要重新連線才會切換。", + "baseUrlInvalid": "請填寫完整的 http(s) 網址且不帶查詢參數,例如 https://api.deepseek.com", + "apiKeyLabel": "API 金鑰", + "apiKeyHint": "以 DEEPSEEK_API_KEY 傳給智慧體。環境變數的優先權高於憑證檔,因此若用終端機登入,這裡留空即可。" + }, + "codex": { + "configDescription": "支援 API URL、API Key、模型名稱、Reasoning Effort 快捷配置,並與 `auth.json` / `config.toml` 雙向聯動。", + "authMode": "認證方式", + "chatgptSubscription": "官網訂閱", + "chatgptSubscriptionHint": "使用 ChatGPT 官網訂閱登入,無需配置 API Key", + "apiKeyHint": "使用 API Key 連接 OpenAI 或相容的 API 服務", + "selectProvider": "選擇 Provider", + "modelName": "模型名稱", + "selectReasoningEffort": "選擇 Reasoning Effort", + "enableWebsocket": "啟用 WebSocket", + "enableWebsocketAria": "Codex Provider 啟用 WebSocket", + "enableSkills": "啟用 Skills", + "enableSkillsAria": "Codex 啟用 Skills", + "enableFast": "啟用 Fast", + "enableFastAria": "Codex 啟用 Fast 服務等級", + "sandboxGroupTitle": "沙箱與審批", + "sandboxGroupHint": "寫入全域 ~/.codex/config.toml,codex CLI 與 IDE 的工作階段同樣生效。這是執行緒預設值,只作用於 codex 自行發起的回合(/goal、/review、/compact);一般對話使用輸入框裡的審批預設。變更需重開工作階段才生效。", + "sandboxShadowedWarning": "config.toml 裡設定了 default_permissions,codex 會改走權限設定檔並完全忽略 sandbox_mode。刪除 default_permissions 後下面的選項才會生效。", + "sandboxPermissionsTableWarning": "config.toml 定義了 [permissions] 設定檔卻沒有 default_permissions,codex 會拒絕啟動。請在下方原始編輯器裡補上。", + "approvalPolicyLabel": "審批策略", + "approvalPolicyUnset": "未設定(codex 預設:依需求詢問)", + "approvalPolicy_on-request": "依需求詢問 — 由模型決定何時請求批准", + "approvalPolicy_untrusted": "僅信任唯讀 — 只有已知安全的唯讀指令免批准", + "approvalPolicy_never": "從不詢問 — 完全不彈審批", + "approvalPolicy_granular": "精細控制 — 依提示類型分別設定", + "approvalPolicyUntrustedAcpWarning": "ACP 轉接器只有三種審批預設,untrusted 無對應項,codeg 工作階段會退回「按需詢問」——此時由模型自行決定何時詢問,沙箱本就允許的命令不再詢問。請改用下方的沙箱模式收緊。", + "granularHint": "關閉表示該類請求會被自動拒絕,而不是彈給你確認。", + "granular_sandbox_approval": "Shell 指令越權申請", + "granular_rules": "Execpolicy 規則提示", + "granular_skill_approval": "技能指令碼執行提示", + "granular_request_permissions": "request_permissions 工具提示", + "granular_mcp_elicitations": "MCP elicitation 提示", + "sandboxModeLabel": "沙箱模式", + "sandboxModeUnset": "未設定(受信任的資料夾回落為可寫工作區)", + "sandboxMode_read-only": "唯讀", + "sandboxMode_workspace-write": "可寫工作區", + "sandboxMode_danger-full-access": "完全開放(無沙箱)", + "sandboxModeHint": "在 Windows 上,未開啟 codex 的實驗性 Windows 沙箱時,可寫工作區會被降級為唯讀。", + "sandboxModeSeedsPresetHint": "codeg 還會用它推導工作階段的初始審批預設,因此與審批策略不同,它對一般提問同樣生效。輸入框中選擇的預設仍會覆蓋它。", + "writableRootsLabel": "額外可寫目錄", + "writableRootsHint": "每行一個絕對路徑,作為工作目錄之外的額外可寫位置。", + "sandboxRootsRelativeError": "必須是絕對路徑 — codex 會把相對路徑解析到 ~/.codex 底下:{path}", + "networkAccessLabel": "允許網路存取", + "excludeTmpdirLabel": "從可寫目錄中排除 TMPDIR", + "excludeSlashTmpLabel": "從可寫目錄中排除 /tmp", + "authJsonNative": "auth.json(原生)", + "configTomlNative": "config.toml(原生)", + "loginButton": "使用 ChatGPT 登入", + "loginRequesting": "正在請求登入碼...", + "loginStep1": "在瀏覽器中打開以下連結:", + "loginStep2": "輸入以下代碼:", + "loginPolling": "等待授權中...", + "loginCancel": "取消", + "loginSuccess": "登入成功,配置已儲存!", + "loginFailed": "登入失敗:{message}", + "loginRetry": "重試", + "loginCodeCopied": "已複製代碼", + "loggedIn": "帳號已登入", + "loginRelogin": "重新登入 / 切換帳號", + "loginTimeout": "登入逾時,請重試", + "loginSaveFailed": "登入成功但配置儲存失敗" + }, + "gemini": { + "authConfig": "Gemini 認證配置", + "authConfigDescription": "對齊 Gemini CLI 認證文件,支援自訂、Google 登入、Gemini API Key、Vertex AI(ADC / 服務帳號 / API Key)。", + "authMode": "認證方式", + "selectAuthMode": "選擇認證方式", + "viewAuthDoc": "查看認證文件", + "mode": { + "custom": "自訂介面", + "loginGoogle": "Google 登入(OAuth)", + "vertexServiceAccount": "Vertex AI(服務帳號)" + }, + "hint": { + "custom": "填寫 API URL、API Key 和 Model,分別映射到 GOOGLE_GEMINI_BASE_URL / GEMINI_API_KEY / GEMINI_MODEL。", + "loginGoogle": "首次在終端執行 gemini 並完成 Google 登入;無需填寫 API Key。", + "geminiApiKey": "使用 Gemini API 時填寫 GEMINI_API_KEY。", + "vertexAdc": "使用 gcloud ADC,建議填寫 GOOGLE_CLOUD_PROJECT 與 GOOGLE_CLOUD_LOCATION。", + "vertexServiceAccount": "服務帳號 JSON 路徑寫入 GOOGLE_APPLICATION_CREDENTIALS。", + "vertexApiKey": "使用 Vertex AI API key 時填寫 GOOGLE_API_KEY。" + } + }, + "openCode": { + "configManagement": "OpenCode 配置管理", + "configDescription": "對齊 OpenCode `provider` 配置結構,支援多供應商管理,並與原生 JSON 檔案雙向聯動。", + "providerManagement": "Provider 管理", + "providerCount": "共 {count} 個", + "addProvider": "新增 Provider", + "emptyProvider": "還沒有自訂 Provider。點擊「新增自訂 Provider」建立。", + "providerEnabledState": "{providerId} 啟用狀態", + "selectProviderNpm": "選擇 provider.npm", + "modelManagement": "模型管理", + "modelCount": "共 {count} 個", + "modelDescription": "對齊 OpenCode `provider.models` 結構。目前支援 `name` / `id` 快速管理;其它進階欄位會保留,可在下方原生 JSON 中繼續編輯。", + "addModel": "新增模型", + "emptyModel": "暫無模型,輸入 model id 後點擊「新增模型」建立。", + "modelId": "模型 ID", + "modelName": "模型名稱", + "deleteModel": "刪除模型 {modelId}", + "nativeJsonConfig": "OpenCode 原生 JSON 配置", + "mainModel": "主模型", + "smallModel": "小模型", + "noMatchingModels": "沒有匹配的模型", + "connectProvider": "連接 Provider", + "connectedProviders": "已連接的 Provider", + "noConnectedProviders": "還沒有從目錄連接 Provider。", + "advancedProviderConfig": "自訂 Provider", + "customProviderConfigHint": "你自己定義的 OpenAI 相容端點——opencode.json 裡的一個 provider 設定區塊,API key 存在 auth.json。", + "addCustomProvider": "新增自訂 Provider", + "disconnect": "中斷連接", + "editConfig": "編輯", + "customBadge": "自訂", + "authKindApi": "API Key", + "authKindOauth": "OAuth", + "authKindNone": "無憑證", + "connect": { + "title": "連接 Provider", + "description": "從 models.dev 目錄選擇一個 Provider。憑證儲存到 OpenCode 的 auth.json 檔案。", + "pick": "Provider", + "search": "搜尋 Provider…", + "loading": "正在載入目錄…", + "catalogLabel": "models.dev 目錄", + "modelsAvailable": "{count} 個可用模型", + "getKey": "取得 API Key", + "oauthApiKeyNote": "此 Provider 也支援透過 opencode auth login 瀏覽器登入。瀏覽器登入即將推出——目前請貼上 API Key。", + "apiKey": "API Key", + "apiKeyHint": "儲存在 auth.json,絕不寫入 opencode.json。", + "baseUrlOptional": "Base URL 覆寫(選填)", + "providerId": "Provider ID", + "displayName": "顯示名稱", + "modelsList": "模型(每行一個)", + "modelsHint": "端點接受的模型 ID。", + "action": "連接", + "editTitle": "編輯 Provider", + "editDescription": "更新該 Provider 的 API Key 或 Base URL。", + "saveAction": "儲存" + }, + "customProvider": { + "title": "新增自訂 Provider", + "description": "定義一個 OpenAI 相容端點。API key 儲存到 auth.json;provider 設定區塊寫入 opencode.json。", + "action": "新增 Provider", + "idInCatalog": "{providerId} 是已知 Provider,請改用「連接 Provider」連接。" + }, + "refreshCatalog": "重新整理目錄", + "reasoningBadge": "推理", + "contextWindow": "上下文視窗", + "permissions": { + "title": "權限", + "description": "決定哪些操作直接執行、先徵求你的同意,還是被阻擋。寫入 opencode.json 的 permission 設定,點擊下方儲存後生效。", + "docsLink": "權限文件", + "unparsableConfig": "下方的原生 JSON 目前無法解析,視覺化編輯已暫停。修正 JSON 後即可繼續。", + "invalidBlock": "permission 設定的結構無法辨識。請在下方原生 JSON 中修改,或點擊「恢復預設」重來。", + "orderingUnsafe": "萬用規則寫在了具體工具之後,OpenCode 會把它一併套用到這些工具上——下方各列顯示的並非實際生效的規則。「修正順序」只把萬用規則移回各自範圍的最前面,不更動任何值。", + "orderingUnsafeManual": "有規則被後面更寬鬆的模式遮蔽,OpenCode 永遠不會套用它——下方各列顯示的並非實際生效的規則。兩個互相重疊的模式沒有唯一正確的順序,請在下方原生 JSON 中調整,把較寬鬆的寫在前面。", + "fixOrder": "修正順序", + "agentOverrides": "下列智慧代理個別覆寫了權限,且在最後套用,因此會蓋過此處的所有設定:{agents}。請在下方原生 JSON 中修改,或開啟「自動接受所有權限」將其清除。", + "legacyTools": "頂層的舊版 tools 設定停用了某個工具。OpenCode 會把它併入權限,因此會疊加在此處顯示的所有設定之上。請在下方原生 JSON 中修改,或開啟「自動接受所有權限」將其清除。", + "autoAcceptTitle": "自動接受所有權限", + "autoAcceptHint": "所有工具呼叫(shell 指令、檔案修改、存取專案外路徑)都不再詢問,直接執行。開啟後會以一條全域允許規則取代下方的逐工具設定,並清除各智慧代理個別的權限覆寫與舊版 tools 開關——否則它們仍會攔截。", + "globalLabel": "全域預設", + "globalHint": "即 * 規則:下方工具未個別覆寫時採用的動作。", + "actionUnset": "未設定(OpenCode 預設)", + "actionInherit": "沿用預設({action})", + "actionAllow": "允許", + "actionAsk": "詢問", + "actionDeny": "拒絕", + "perToolTitle": "逐工具權限", + "reset": "恢復預設", + "ruleCount": "細則 {count} 條", + "rulesToggle": "{tool} 的細緻規則", + "rulesHint": "依工具輸入比對,最後符合的規則優先,因此請把寬鬆的模式寫在前面。* 比對任意多個字元,? 精確比對一個字元,開頭的 ~ 會展開為主目錄。", + "noRules": "尚無細緻規則。", + "addRule": "新增規則", + "deleteRule": "刪除規則 {pattern}", + "duplicateRule": "此模式已存在。", + "blankRule": "規則必須有模式;如需刪除請點擊垃圾桶圖示。", + "customKeys": "檔案中的其他權限鍵", + "customKeyHint": "並非 OpenCode 內建工具,將原樣保留。", + "keys": { + "bash": "執行 shell 指令,依解析後的指令比對", + "edit": "所有檔案修改:edit、write 與 patch", + "read": "讀取檔案,依檔案路徑比對", + "external_directory": "存取專案工作目錄之外的路徑", + "task": "啟動子代理,依子代理類型比對", + "skill": "載入技能,依技能名稱比對", + "glob": "尋找檔案,依萬用字元模式比對", + "grep": "搜尋檔案內容,依模式比對", + "list": "列出目錄內容", + "webfetch": "擷取 URL", + "websearch": "網頁搜尋", + "lsp": "執行 LSP 查詢", + "todowrite": "寫入待辦清單", + "question": "向你提問", + "doom_loop": "同一呼叫以相同輸入重複 3 次時觸發" + } + } + }, + "openClaw": { + "gatewayConfig": "Gateway 配置", + "gatewayDescription": "配置 OpenClaw Gateway 連線資訊。支援本地或遠端 Gateway。", + "gatewayUrlHint": "留空則使用 openclaw 本地配置的 gateway.remote.url。", + "gatewayTokenPlaceholder": "Gateway 認證 Token", + "gatewayTokenHint": "建議使用 token-file 取代明文 Token,可透過 openclaw 命令列配置。", + "sessionKeyHint": "可選。指定 Gateway Session Key,留空則自動分配隔離會話。" + }, + "hermes": { + "configManagement": "Hermes 配置", + "configDescription": "Hermes 在 ~/.hermes/.env 中管理自己的憑證,在 ~/.hermes/config.yaml 中管理設定。選擇一個供應商,然後設定 API 金鑰與模型——codeg 會替你寫入這兩個檔案。", + "providerLabel": "供應商", + "providerHint": "供應商決定 Hermes 使用哪個 API 金鑰變數與 model.provider。OAuth 供應商透過下方的終端機設定進行設定。", + "groupApiKey": "API 金鑰供應商", + "groupOauth": "OAuth 供應商", + "groupAws": "AWS", + "apiKeyHint": "儲存到 ~/.hermes/.env。它絕不會被注入行程——Hermes 會從自己的設定中讀取它。", + "modelName": "模型", + "oauthHint": "此供應商使用 OAuth。請執行下方的設定流程,在終端機中完成驗證。", + "awsHint": "Bedrock 使用你的 AWS 憑證(環境變數或共用設定)。請在上方填寫模型 ID,並在系統環境中設定 AWS 存取權限。", + "unsupportedProvider": "此供應商無法透過結構化欄位編輯。請使用下方的 config.yaml 原始編輯器或終端機引導設定。", + "setupTitle": "自管理設定", + "setupHint": "Hermes 的互動式設定需要終端機。可在下方啟動,或複製指令自行執行。", + "runSetup": "執行 Hermes 設定", + "configureModel": "設定模型", + "openConfigFolder": "開啟 ~/.hermes", + "copyCommand": "複製指令", + "commandCopied": "指令已複製到剪貼簿", + "advancedTitle": "進階:編輯 config.yaml", + "rawConfigHint": "直接編輯 ~/.hermes/config.yaml。在此儲存將原樣覆寫該檔案。", + "saveRawConfig": "儲存 config.yaml" + }, + "codebuddy": { + "configManagement": "CodeBuddy 設定", + "configDescription": "CodeBuddy 使用 API Key 進行驗證。中國版還必須將環境設為「中國版(internal)」;iOA 版使用「iOA」;海外版則不設定。", + "apiKeyLabel": "API Key", + "apiKeyHint": "將作為此智能體的 CODEBUDDY_API_KEY 儲存。也可以在終端機用 CodeBuddy CLI 登入。", + "apiKeyHintSelfHosted": "將作為此智能體的 CODEBUDDY_API_KEY 儲存。請使用你的私有化部署簽發的金鑰。", + "environmentLabel": "環境", + "environmentHint": "設定 CODEBUDDY_INTERNET_ENVIRONMENT。中國大陸必須使用「中國版(internal)」;海外版則不設定。", + "envOverseas": "海外版(預設)", + "envChina": "中國版(internal)", + "envIoa": "iOA", + "envSelfHosted": "私有化部署", + "baseUrlLabel": "私有化部署位址", + "baseUrlPlaceholder": "https://codebuddy.your-company.com", + "baseUrlHint": "儲存為 CODEBUDDY_BASE_URL,將 CodeBuddy 指向你的私有端點。私有化部署不設定網路環境(CODEBUDDY_INTERNET_ENVIRONMENT)。", + "baseUrlInvalid": "請輸入合法的 http(s) 位址。", + "loginHint": "沒有 API Key?也可以在終端機執行「codebuddy」用騰訊雲帳號登入。" + }, + "kimiCode": { + "configManagement": "Kimi Code 設定", + "configDescription": "`kimi acp` 只認已儲存的登入權杖,所以 codeg 會在 ~/.kimi-code/config.toml 寫入受管供應商,並在本機植入一個門控權杖——推論仍然走你自己的 Key。", + "statusUnconfigured": "尚未設定", + "statusDirty": "有未儲存的變更", + "summaryLabel": "生效設定", + "gateReadyApiKey": "API Key 已寫入 config.toml", + "gateReadyLogin": "已透過 Kimi 帳號登入", + "revealConfig": "在資料夾中顯示", + "envOverrideWarning": "偵測到 {keys},其優先權高於 config.toml。在此儲存會自動清除它。", + "authModeLabel": "驗證方式", + "authModeApiKey": "API Key", + "authModeLogin": "Kimi 帳號登入(訂閱)", + "authModeApiKeyHint": "在 config.toml 寫入受管供應商,並植入門控權杖以便工作階段能夠開啟。", + "loginHint": "在終端機執行 `kimi login`,用 Kimi 訂閱帳號登入。codeg 不儲存任何憑證,沿用 Kimi 自己的登入。在此儲存會移除 codeg 的 API Key 門控權杖。", + "credentialTitle": "憑證", + "interfaceTypeLabel": "供應商類型", + "interfaceTypeHint": "Kimi 使用的供應商協定(config.toml 的 `type`)。Moonshot / platform.kimi.com 的 Key 請選「Kimi / Moonshot」。", + "endpointLabel": "接入點", + "endpointCustom": "自訂(OpenAI 相容)", + "endpointHint": "國際 = api.moonshot.ai;中國(platform.kimi.com 的 Key)= api.moonshot.cn。自訂可指向任意 OpenAI 相容端點。", + "regionInternational": "國際(api.moonshot.ai)", + "regionChina": "中國(api.moonshot.cn)", + "baseUrlLabel": "Base URL", + "baseUrlHint": "留空則使用供應商 SDK 預設值。", + "apiKeyLabel": "API Key", + "apiKeyHint": "寫入 ~/.kimi-code/config.toml 並用於推論。來自 platform.kimi.com 或 platform.kimi.ai。", + "vertexProjectLabel": "GCP 專案(GOOGLE_CLOUD_PROJECT)", + "vertexLocationLabel": "GCP 區域(GOOGLE_CLOUD_LOCATION)", + "vertexHint": "Vertex AI 使用 Google 應用程式預設憑證——執行 `gcloud auth application-default login`(不需 API Key)。", + "modelTitle": "模型", + "modelLabel": "模型", + "modelHint": "寫入 config.toml 的模型 id。點「測試並取得模型」可查看你的 Key 實際能存取哪些模型。", + "maxContextLabel": "最大上下文長度", + "maxContextHint": "Kimi 的設定 schema 要求必填:缺少會讓 Kimi 丟棄整個模型區塊,導致每次對話都沒有回覆。預設 262144。", + "fetchModels": "測試並取得模型", + "fetchModelsOk": "Key 可用——共 {count} 個模型", + "fetchModelsEmpty": "Key 可用,但未回傳任何模型", + "fetchModelsFailed": "測試失敗", + "fetchModelsNeedsKey": "請先填寫 API Key 和接入點", + "modelNotInList": "該模型不在你的 Key 可存取清單中,Kimi 會回報「模型不存在」。", + "reasoningTitle": "推理", + "reasoningEnableLabel": "啟用", + "reasoningDescription": "只有當模型宣告了推理能力,Kimi 才會在輸入框顯示「Thinking」選擇器,所以這裡由 codeg 寫入該宣告。對新建工作階段生效。", + "effortsLabel": "可選檔位", + "effortsHint": "這些會成為輸入框「Thinking」選擇器裡的檔位。Kimi 會把檔位原樣轉傳給供應商,請選你的模型能接受的值。", + "effortsEmptyHint": "一個檔位都不選時,輸入框只會退化成 Off / On 兩檔開關。", + "effortsCustomPlaceholder": "新增其他檔位", + "effortsAdd": "新增", + "defaultEffortLabel": "預設檔位", + "defaultEffortAuto": "由 Kimi 決定", + "alwaysThinkingLabel": "模型始終推理——從選擇器中移除 Off 檔", + "fixErrorsFirst": "請先修正標紅的欄位", + "errorModelRequired": "模型為必填欄位", + "errorMaxContextRequired": "最大上下文長度為必填欄位", + "errorMaxContextInvalid": "必須是正整數", + "errorApiKeyRequired": "API Key 為必填欄位", + "errorApiKeyInvalid": "API Key 不能包含換行", + "errorBaseUrlRequired": "Base URL 為必填欄位", + "errorBaseUrlInvalid": "必須以 http:// 或 https:// 開頭", + "errorVertexProjectRequired": "GCP 專案為必填欄位", + "errorDefaultEffortUnlisted": "必須是上面已選取的檔位之一", + "advancedTitle": "進階", + "authTypeLabel": "憑證寫入位置", + "authTypeApiKey": "內聯 api_key", + "authTypeEnv": "供應商 env 子表", + "authTypeHint": "API Key 在 config.toml 中的寫入位置。", + "rawEditorLabel": "直接編輯 config.toml", + "rawEditorWarning": "在此儲存會按原文覆寫整個檔案,取代掉上方的結構化設定。", + "rawEditorPlaceholder": "[providers.codeg]\ntype = \"kimi\"\nbase_url = \"https://api.moonshot.cn/v1\"\napi_key = \"sk-...\"" + }, + "authModeOfficialSubscription": "官網訂閱", + "authModeCustomEndpoint": "自定義介面", + "authModeCustomEndpointHint": "手動配置 API URL 和 API Key 連接自定義介面。", + "authModeModelProvider": "模型供應商", + "modelProvider": "模型供應商", + "modelProviderHint": "使用已配置的模型供應商的 API URL、API Key 和模型。", + "selectModelProvider": "選擇模型供應商", + "noModelProviderAvailable": "該代理未配置模型供應商。請前往模型供應商設定添加。", + "claude": { + "authMode": "認證方式", + "officialSubscription": "官方訂閱", + "officialSubscriptionHint": "使用 Anthropic 官方訂閱,無需 API Key。", + "mainModel": "主模型", + "reasoningModel": "推理模型(thinking)", + "haikuDefaultModel": "Haiku 預設模型", + "sonnetDefaultModel": "Sonnet 預設模型", + "opusDefaultModel": "Opus 預設模型", + "customModelOption": "自訂模型 ID", + "customModelOptionName": "自訂模型名稱", + "customModelOptionDescription": "自訂模型描述", + "customModelOptionHint": "在 Claude 模型選擇器中新增一個自訂項目(例如透過自訂閘道/代理提供的模型)。名稱與描述為選填的顯示資訊。", + "effortLevel": "推理等級", + "effortLevelDefault": "預設等級", + "effortLevel_low": "低", + "effortLevel_medium": "中", + "effortLevel_high": "高", + "effortLevel_xhigh": "超高", + "sendAttributionHeader": "向介面傳送歸屬/計費識別碼", + "sendAttributionHeaderAria": "向介面傳送 Claude Code 歸屬/計費識別碼", + "disableNonessentialTraffic": "停用遙測或多餘的網路請求", + "disableNonessentialTrafficAria": "停用 Claude Code 遙測或多餘的網路請求" + }, + "dialogs": { + "confirmDeleteProvider": "確認刪除 Provider {providerId}?", + "confirmDeleteProviderDescription": "將同步更新 OpenCode 配置與認證 JSON 檔案,刪除後不可恢復。", + "confirmUninstall": "確認卸載 {name}?", + "confirmUninstallDescription": "這會移除本地安裝版本,之後可隨時重新安裝。", + "customInstallTitle": "自訂安裝 {name}", + "customInstallDescription": "輸入要安裝的版本號。將重新安裝並替換目前已安裝的版本。", + "customInstallVersionLabel": "版本號", + "customInstallInvalid": "請輸入有效的版本號,例如 1.2.3。", + "customInstallSubmit": "安裝" + }, + "errors": { + "windowsFileLocked": "{name} 的程式檔案正被執行中的工作階段佔用,Windows 下無法替換。請先關閉所有 {name} 工作階段後重試。", + "nativeJsonMustBeObject": "原生 JSON 配置必須是物件", + "nativeJsonInvalid": "原生 JSON 配置格式錯誤:{message}", + "openCodeAuthMustBeObject": "OpenCode auth.json 必須是 JSON 物件", + "openCodeAuthInvalid": "OpenCode auth.json 格式錯誤:{message}", + "authMustBeObject": "auth.json 必須是 JSON 物件", + "authInvalid": "auth.json 格式錯誤:{message}", + "providerIdPattern": "Provider ID 僅支援字母、數字、底線、點與中劃線", + "providerExists": "Provider {providerId} 已存在", + "modelIdPattern": "模型 ID 僅支援字母、數字、底線、點、冒號與中劃線", + "modelExists": "Model {modelId} 已存在" + }, + "warnings": { + "nativeJsonRecoveredStructured": "原生 JSON 配置格式無效,已重置為結構化配置", + "nativeJsonRecoveredOpenCode": "原生 JSON 配置格式無效,已重置為 OpenCode 結構化配置", + "openCodeAuthRecovered": "OpenCode auth.json 格式無效,已重置為預設配置", + "authRecoveredStructured": "auth.json 格式無效,已重置為結構化配置" + }, + "toasts": { + "agentActionCompleted": "{name}{action}完成", + "agentActionFailed": "{name}{action}失敗", + "localVersion": "本地版本:{version}", + "installCompletedVersionLater": "安裝完成,版本將在下一次檢測時更新", + "uninstallCompleted": "{name}卸載完成", + "uninstallFailed": "{name}卸載失敗", + "localVersionRemoved": "本地版本已移除", + "saveAgentOrderFailed": "儲存 Agent 排序失敗", + "saveAgentSwitchFailed": "儲存 Agent 開關失敗", + "saveEnvFailed": "儲存環境變數失敗", + "grokSaved": "Grok 設定已儲存", + "saveGrokNativeFailed": "儲存 Grok 原生設定失敗", + "saveGrokApiKeyFailed": "設定已儲存,但 API Key 未能儲存", + "cursorSaved": "Cursor 設定已儲存", + "saveCursorConfigFailed": "儲存 Cursor 設定失敗", + "codexSaved": "Codex 配置已儲存", + "saveCodexNativeFailed": "儲存 Codex 原生配置失敗", + "geminiSaved": "Gemini 配置已儲存", + "saveGeminiFailed": "儲存 Gemini 配置失敗", + "providerDeleted": "Provider {providerId} 已刪除", + "providerDeleteFailed": "刪除 Provider {providerId} 失敗", + "providerSaved": "Provider {providerId} 儲存成功", + "saveProviderFailed": "儲存 Provider {providerId} 失敗", + "openCodeConfigSynced": "OpenCode 配置與認證 JSON 已同步儲存。", + "openCodeSaved": "OpenCode 配置已儲存", + "saveOpenCodeFailed": "儲存 OpenCode 配置失敗", + "openClawSaved": "OpenClaw 配置已儲存", + "saveOpenClawFailed": "儲存 OpenClaw 配置失敗", + "configSaved": "配置已儲存", + "configSavedHint": "已有會話需要重新打開才能生效", + "saveConfigManagementFailed": "儲存配置管理失敗", + "clineSaved": "Cline 配置已儲存", + "saveClineFailed": "儲存 Cline 配置失敗", + "hermesSaved": "Hermes 配置已儲存", + "saveHermesFailed": "儲存 Hermes 配置失敗", + "codeBuddySaved": "CodeBuddy 設定已儲存", + "saveCodeBuddyFailed": "儲存 CodeBuddy 設定失敗", + "kimiCodeSaved": "Kimi Code 設定已儲存", + "saveKimiCodeFailed": "儲存 Kimi Code 設定失敗", + "deepseekSaved": "DeepSeek 設定已儲存", + "saveDeepSeekFailed": "儲存 DeepSeek 設定失敗", + "modelProviderRequired": "請先選擇一個模型供應商再儲存。", + "affectedRunningSessions": "{count} 個進行中的工作階段需重新連線以套用變更", + "providerConnected": "已連接 {providerId}", + "connectFailed": "連接 {providerId} 失敗", + "providerDisconnected": "已中斷 {providerId}", + "disconnectFailed": "中斷 {providerId} 失敗", + "catalogRefreshed": "目錄已重新整理——{count} 個 provider", + "catalogRefreshFailed": "重新整理目錄失敗", + "piSaved": "Pi 設定已儲存", + "savePiFailed": "儲存 Pi 設定失敗", + "piRuntimeSaved": "Pi 執行環境已儲存", + "savePiRuntimeFailed": "儲存 Pi 執行環境失敗", + "piBinaryInstalled": "pi 已安裝", + "piBinaryInstallFailed": "pi 安裝失敗", + "piBinaryUninstalled": "pi 已解除安裝", + "piBinaryUninstallFailed": "pi 解除安裝失敗", + "savePiTrustFailed": "儲存工作區信任失敗" + }, + "version": { + "statusLabel": "版本狀態", + "notInstalled": "未安裝", + "remoteLocal": "遠端:{remoteVersion} · 本地:{localVersion}", + "localOnly": "本機:{localVersion}", + "localInstalled": "{versionText}。已安裝。", + "platformUnsupported": "{versionText}。目前平台不支援該 Agent。", + "uvxNotReady": "{versionText}。uv 執行階段未安裝——請在下方 uv 預檢項中安裝後再使用該 Agent。", + "clickInstall": "{versionText}。請點擊右側安裝。", + "localUnrecognized": "{versionText}。本地版本無法識別,可嘗試升級覆蓋安裝。", + "upgradeAvailable": "{versionText}。發現可升級版本。", + "remoteUnavailable": "{versionText}。遠端版本暫不可用。", + "latest": "{versionText}。已是最新版本。" + }, + "adapter": { + "label": "ACP 轉接器", + "badge": "ACP 轉接器", + "badgeHint": "Codeg 為此智能體安裝的是 ACP 轉接器套件,而不是廠商 CLI —— 兩者各自獨立,設定共用。", + "learnMore": "了解詳情", + "missingWithNative": "已偵測到你本機的 {nativeLabel}:{nativePath}。Codeg 透過 ACP 協定驅動智能體,而該 CLI 本身不支援 ACP,所以 Codeg 需要獨立的轉接器套件 {adapterPackage}(由 Agent Client Protocol 專案維護,最初由 Zed 團隊發起)。它自帶執行環境,不會修改或取代你的 {nativeCmd} 指令,讀取的也是同一個 {configDir} —— 既有的登入與設定可直接沿用。點擊下方安裝即可。", + "missing": "Codeg 透過 ACP 協定驅動智能體,而 {nativeLabel} 本身不支援 ACP,所以 Codeg 需要獨立的轉接器套件 {adapterPackage}(由 Agent Client Protocol 專案維護,最初由 Zed 團隊發起)。它自帶執行環境,因此不必先安裝 {nativeCmd} CLI;若你已經安裝,兩者可以並存,並共用 {configDir} 中的登入與設定。點擊下方安裝即可。", + "readyWithNative": "轉接器 {adapterCmd} 已安裝 —— Codeg 啟動的是它,而不是你本機的 {nativeCmd}({nativePath})。兩者是各自獨立的套件,可以並存,且都讀取 {configDir},登入與設定共用。", + "ready": "轉接器 {adapterCmd} 已安裝 —— Codeg 啟動的就是它。它自帶執行環境,所以不需要另外安裝 {nativeLabel};即使日後你安裝了,兩者也能並存並共用 {configDir}。" + }, + "cline": { + "configDescription": "配置 Cline API 提供商和憑證。設定將儲存到 ~/.cline/data/。" + }, + "opencodePlugins": { + "title": "OpenCode 外掛", + "declared": "已宣告的外掛", + "noPlugins": "opencode.json 中未宣告任何外掛", + "status": { + "installed": "已安裝", + "missing": "未安裝" + }, + "installAll": "安裝全部缺失外掛", + "pinVersions": "固定 @latest 版本", + "install": "安裝", + "uninstall": "解除安裝", + "refresh": "重新整理", + "success": "所有外掛安裝成功", + "failed": "外掛操作失敗" + }, + "pi": { + "configManagement": "Pi 設定", + "configDescription": "Pi 透過模型提供方的 API Key 驗證。Key 寫入 ~/.pi/agent/auth.json,模型選擇寫入 settings.json。", + "providerLabel": "提供方", + "modelLabel": "模型", + "thinkingLabel": "思考", + "thinking": { + "off": "關閉", + "low": "低", + "medium": "中", + "high": "高", + "minimal": "極低", + "xhigh": "極高" + }, + "apiKeyLabel": "API Key", + "apiKeyHint": "為所選提供方寫入 ~/.pi/agent/auth.json。", + "apiKeySetPlaceholder": "•••••• (已儲存,留空則保持不變)", + "saveConfig": "儲存 Pi 設定", + "providerModelRequired": "提供方與模型為必填", + "runtimeTitle": "執行環境", + "runtimeDescription": "選擇執行哪個 pi。使用預設,或指向你自己的 pi 建置。", + "modeDefault": "預設 pi", + "modeDefaultHint": "使用內建 pi-acp 轉接器拉起 PATH 上的 pi。 安裝 pi:npm install -g @earendil-works/pi-coding-agent", + "modeCustom": "自訂 pi", + "modeCustomHint": "執行你自己的 pi 建置、安裝或包裝腳本。", + "commandLabel": "pi 命令或路徑", + "commandHint": "絕對路徑、PATH 上的命令名,或包裝腳本(如 monorepo 的 ./pi-test.sh)。", + "commandNotFound": "找不到命令", + "validate": "驗證", + "advanced": "進階", + "configDirLabel": "設定目錄 (PI_CODING_AGENT_DIR)", + "sessionDirLabel": "工作階段目錄 (PI_CODING_AGENT_SESSION_DIR)", + "flagsHint": "pi-acp 不會轉發自訂 pi 參數(--approve、-e 等)——用腳本包裝 pi 並將命令指向它。", + "customIncomplete": "請輸入 pi 命令以儲存", + "saveRuntime": "儲存執行環境", + "providerPlaceholder": "選擇供應方", + "customProvider": "自訂供應方…", + "providerIdLabel": "供應方 ID", + "apiProtocolLabel": "API 協定", + "baseUrlLabel": "介接位址(Base URL)", + "customProviderHint": "在 ~/.pi/agent/models.json 中依你的介接位址定義一個供應方。多數自架或代理服務使用 openai-completions。", + "baseUrlRequired": "介接位址(Base URL)為必填", + "binaryTitle": "pi 二進位 (pi-coding-agent)", + "binaryDescription": "pi-acp 會執行此 pi 二進位。可在此安裝,或在下方指向你自己的組建。", + "binaryInstalled": "已安裝", + "binaryMissing": "未安裝", + "binaryChecking": "偵測中…", + "installBinary": "安裝 pi", + "installing": "安裝中…", + "recheck": "重新偵測", + "configDirSkillsNote": "設定自訂組態目錄後,設定頁中管理的技能、專家與辦公工具將不會套用至該 pi;請直接在該目錄中管理其技能。", + "projectTrustTitle": "專案信任", + "projectTrustDescription": "你允許 pi 從中載入專案檔案的目錄。被信任的目錄會讓該儲存庫的 .pi/extensions 在 pi 啟動時執行程式碼,且對其下所有子目錄同樣生效,你在終端機執行 pi 時也會沿用。", + "projectTrustLoading": "載入中…", + "projectTrustEmpty": "尚未對任何目錄做出決定。", + "projectTrustTrusted": "已信任", + "projectTrustDenied": "不信任", + "projectTrustRevoke": "撤銷", + "reasoningTitle": "推理", + "reasoningEnableLabel": "啟用", + "reasoningDescription": "只有模型宣告了推理能力,pi 才會傳送推理強度——未宣告的模型所有等級都會被壓回 Off,所以輸入框裡的選擇器一改就彈回。這裡寫入 models.json 中該模型的項目。", + "levelsLabel": "可選等級", + "levelsHint": "這些會成為輸入框推理選擇器裡的等級。請選你的端點能接受的值;不在這裡的等級 pi 一律拒絕。", + "levelsEmptyError": "至少選一個等級——一個都不選時 pi 只會退回 Off。", + "wireValuesTitle": "進階:送給供應商的值", + "wireValuesHint": "留空表示原樣送出等級名稱。端點需要別的寫法時才填——Google 系需要 LOW / HIGH。", + "defaultLevelUnlisted": "該等級不在上面的可選清單裡——pi 會把它壓下來。" + }, + "addCustomAgent": "新增自訂智慧體", + "addCustomAgentHint": "接入任何相容 ACP 的智慧體。可從公開 ACP 註冊表中選擇,或直接貼上其註冊表資訊。", + "customAgentFromRegistry": "ACP 註冊表", + "customAgentManual": "手動填寫", + "customAgentSearchPlaceholder": "搜尋智慧體…", + "customAgentLoadingCatalog": "正在載入 ACP 註冊表…", + "customAgentRetry": "重試", + "customAgentNoResults": "沒有符合的智慧體", + "customAgentAdd": "新增", + "customAgentAlreadyAdded": "已新增", + "customAgentUnsupportedPlatform": "目前平台沒有可用的建置", + "customAgentAdded": "已新增 {name}", + "customAgentIdLabel": "註冊表 ID", + "customAgentNameLabel": "顯示名稱", + "customAgentVersionLabel": "版本", + "customAgentSpecLabel": "散發資訊(JSON)", + "customAgentSpecHint": "與 ACP 註冊表 distribution 物件同構:支援 npx、uvx、binary 三種通道,也可整筆貼上註冊表條目。npx/uvx 的 cmd 為套件安裝的可執行命令名稱,預設按套件名稱推導,與套件名稱不同時需填寫。binary 按平台鍵區分(本機為 {platform}),cmd 為壓縮檔內啟動路徑,sha256 可選用於驗證下載。", + "customAgentTemplateLabel": "範本", + "customAgentKindLabel": "啟動方式", + "customAgentInvalidJson": "不是合法的 JSON", + "customAgentNoDistribution": "找不到 npx、uvx 或 binary 散發方式", + "customAgentCancel": "取消", + "customAgentSave": "新增智慧體", + "customAgentSaveChanges": "儲存變更", + "customAgentEdit": "編輯智慧體", + "customAgentEditHint": "修改名稱、圖示、分發資訊與技能宣告;智慧體 ID 不可修改。", + "customAgentEditNotFound": "找不到自訂智慧體 {id}", + "customAgentSaved": "已儲存 {name}", + "customAgentVersionProbeLabel": "版本查詢命令(可選)", + "customAgentVersionProbeHint": "查詢本機安裝版本的命令;留空時預設執行智慧體命令加 --version。", + "customAgentRemove": "移除智慧體", + "customAgentRemoveHint": "刪除該智慧體定義。既有工作階段的歷史會保留,只是該智慧體無法再啟動。", + "customAgentIconLabel": "圖示(選填)", + "customAgentIconUpload": "上傳", + "customAgentIconReplace": "更換", + "customAgentIconClear": "移除圖示", + "customAgentIconHint": "隨智慧體一併儲存,離線也能顯示。未上傳則使用彩色首字母。", + "customAgentSkillsLabel": "Skills(共享 .agents/skills)", + "customAgentSkillsHint": "聲明該智能體會讀取共享的 .agents/skills 目錄(全域與專案級),並將其加入所有技能矩陣。連結到共享目錄的技能對讀取該目錄的其他智能體同樣可見。", + "customAgentSkillsDirLabel": "專屬技能目錄", + "customAgentSkillsDirHint": "該智慧體自身載入技能的目錄絕對路徑 —— 可與共享目錄並存,也可單獨使用。~ 會展開為主目錄;連結技能時優先放入此目錄。", + "customAgentMcpLabel": "MCP 支援", + "customAgentMcpHint": "工作階段建立時向該智慧體注入 codeg 內建的 codeg-mcp 伴生行程 —— 委派、即時回饋與任務工具都依賴它。若該智慧體不支援 MCP、連線時報錯,請關閉此項;設定會在下次連線時生效。", + "customAgentIconNotAnImage": "請選擇圖片檔案。", + "customAgentIconTooLarge": "圖示需小於 {limit} KB。", + "customAgentIconReadFailed": "無法讀取該圖片。", + "customAgentRemoveConfirm": "確定移除 {name}?既有會話會保留,但該智慧體將無法再啟動。", + "customAgentRemoveWithData": "同時刪除已記錄的會話歷史", + "customAgentRemoved": "已移除 {name}", + "customAgentBadge": "自訂", + "customAgentNotLaunchable": "該智慧體在此環境無法啟動:{reason}" + }, + "SettingsPages": { + "agentsLoading": "載入 Agent 設定中...", + "skillPacksLoading": "正在載入技能包…" + }, + "GeneralSettings": { + "loading": "載入中...", + "sectionTitle": "一般", + "sectionDescription": "集中管理預設終端機、渲染加速以及多智能體協同等通用偏好。", + "terminalTitle": "預設終端", + "terminalDescription": "選擇從終端列或檔案樹開啟新終端分頁時使用的 Shell。智慧代理請求 codeg 代為執行整條命令列時也會使用它。", + "terminalSystemDefault": "系統預設", + "terminalPowerShell7": "PowerShell 7 (pwsh)", + "terminalWindowsPowerShell": "Windows PowerShell", + "terminalCmd": "命令提示字元 (cmd)", + "terminalSaveFailed": "儲存終端設定失敗:{message}", + "terminalShellCustom": "自訂路徑", + "terminalShellCustomPath": "Shell 路徑", + "terminalShellCustomPlaceholder": "/usr/local/bin/fish", + "terminalShellCustomSave": "儲存", + "terminalShellCustomHint": "支援絕對路徑,或 PATH 中可解析的命令名。", + "terminalShellNotInstalled": "未安裝", + "terminalShellNotFoundWarning": "目前主機上不存在此路徑。", + "terminalCurrentShell": "目前使用:{path}", + "renderingDescription": "若應用出現黑屏或渲染異常(常見於 AMD 顯示卡或部分 Intel 內顯),可關閉硬體加速。僅 Windows 桌面端生效。", + "disableHardwareAcceleration": "停用硬體加速", + "renderingSaveFailed": "渲染設定儲存失敗:{message}", + "restartRequired": "已儲存,需重新啟動應用程式才會生效。", + "restartNow": "立即重新啟動", + "restartFailed": "重新啟動失敗:{message}", + "loadFailed": "載入失敗:{message}" + }, + "LoginPage": { + "documentTitle": "登入 - codeg", + "brand": "Codeg", + "subtitle": "輸入存取 Token 以連接到桌面端", + "tokenPlaceholder": "Access Token", + "connect": "連接", + "connecting": "連接中...", + "helpText": "Token 可在桌面端 設定 → Web 服務 中取得", + "invalidToken": "Token 無效,請檢查後重試", + "connectionFailed": "連接失敗 (HTTP {status})", + "networkError": "無法連接到伺服器" + }, + "CommitPage": { + "title": "提交程式碼", + "invalidFolderId": "無效的 folderId", + "loadingRepo": "正在載入倉庫..." + }, + "MergePage": { + "title": "解決衝突", + "invalidFolderId": "無效的 folderId", + "loadingRepo": "正在載入倉庫...", + "localVersion": "本地(我們的)", + "result": "結果", + "remoteVersion": "遠端(他們的)", + "acceptLocal": "採用本地", + "acceptRemote": "採用遠端", + "markResolved": "標記已解決", + "abortMerge": "中止", + "completeMerge": "完成合併", + "unresolvedConflicts": "檔案中仍有未解決的衝突標記", + "fileResolved": "檔案已解決", + "allResolved": "所有衝突已解決", + "conflictFiles": "衝突檔案", + "loadingFile": "正在載入檔案...", + "preparingMerge": "正在準備合併...", + "selectFile": "選擇一個檔案進行解決", + "noConflicts": "無衝突檔案", + "skipFile": "跳過", + "abortSuccess": "操作已中止", + "applyAllNonConflicting": "套用所有非衝突變更", + "applyLeftNonConflicting": "套用本地", + "applyRightNonConflicting": "套用遠端" + }, + "ImportSessions": { + "title": "匯入本機工作階段", + "scanningTitle": "正在掃描本機智慧代理工作階段…", + "scanningHint": "正在遍歷各智慧代理的本機工作階段儲存,歷史較多時可能需要一些時間。已匯入的工作階段會順帶重新整理。", + "scanFailed": "掃描失敗", + "retry": "重試", + "rescan": "重新掃描", + "empty": "未發現本機工作階段", + "emptyHint": "本機未找到任何智慧代理的工作階段儲存。", + "noMatches": "沒有符合目前篩選的工作階段", + "searchPlaceholder": "搜尋標題或路徑…", + "allAgents": "全部智慧代理", + "onlyImportable": "僅顯示可匯入", + "selectAll": "全選", + "clearSelection": "清空", + "expandAll": "全部展開", + "collapseAll": "全部摺疊", + "summaryCounts": "共 {total} 個工作階段 · {importable} 個可匯入 · {folders} 個資料夾", + "noFolderSkipped": "已略過 {count} 個無專案目錄的工作階段", + "folderNew": "新建", + "folderCounts": "可匯入 {importable}/{total}", + "toggleFolderAria": "選擇 {name} 中的全部可匯入工作階段", + "toggleSessionAria": "選擇工作階段 {title}", + "statusImported": "已匯入", + "statusDeleted": "已刪除", + "untitled": "未命名工作階段", + "messageCount": "{count} 則訊息", + "selectedCount": "已選 {count} 個", + "importSelected": "匯入所選", + "importing": "匯入中…", + "close": "關閉", + "doneTitle": "匯入完成", + "doneImported": "新匯入", + "doneUpdated": "已重新整理", + "doneSkipped": "已略過", + "doneCreatedFolders": "新建資料夾", + "doneNotFound": "未找到", + "doneFailed": "失敗", + "continueImport": "繼續匯入", + "toasts": { + "importFailed": "匯入失敗:{message}" + } + }, + "Folder": { + "workspaceStatus": { + "degradedTitle": "即時更新不可用", + "degradedHint": "監聽器啟動失敗(如目錄無讀取權限)。請手動重新整理以取得最新變更。", + "retry": "重試", + "retrying": "重試中..." + }, + "common": { + "all": "全部", + "cancel": "取消", + "close": "關閉", + "closeOthers": "關閉其它", + "closeAll": "關閉所有", + "confirm": "確認", + "save": "儲存", + "delete": "刪除", + "rename": "重新命名", + "loading": "載入中...", + "refresh": "刷新", + "refreshing": "刷新中...", + "create": "建立", + "createAndSwitch": "建立並切換", + "openFile": "打開檔案", + "viewDiff": "查看差異", + "push": "推送..." + }, + "statusLabels": { + "in_progress": "進行中", + "pending_review": "待複查", + "completed": "已完成", + "cancelled": "已取消" + }, + "sidebar": { + "title": "會話", + "locateActiveConversation": "定位目前會話", + "expandAllGroups": "展開全部分組", + "collapseAllGroups": "折疊全部分組", + "newConversation": "新增會話", + "newConversationShort": "新增", + "newChat": "新增會話", + "search": "搜尋", + "noConversationsFound": "找不到會話。", + "importLocalSessions": "匯入本地會話", + "importing": "匯入中...", + "error": "錯誤:{message}", + "completeAllSessions": "完成全部會話", + "completeAllReviewTitle": "完成全部複查會話?", + "completeAllReviewDescription": "這會將複查中的 {count} 個會話全部標記為已完成。", + "completing": "處理中...", + "toasts": { + "importedSessions": "已匯入 {imported} 個會話,跳過 {skipped} 個", + "importedAndUpdated": "已匯入 {imported} 個會話,更新 {updated} 個標題,跳過 {skipped} 個", + "updatedTitles": "已更新 {updated} 個標題,跳過 {skipped} 個", + "noNewSessionsFound": "沒有新會話(已跳過 {skipped} 個)", + "importFailed": "匯入失敗:{message}", + "reviewCompleted": "已將 {count} 個複查會話標記為已完成", + "completeReviewFailed": "批次完成複查會話失敗:{message}", + "folderOpened": "已開啟資料夾 {name}", + "folderRemoved": "已移除資料夾 {name}", + "openFolderFailed": "開啟資料夾失敗", + "removeFolderFailed": "移除資料夾失敗:{message}", + "reorderFoldersFailed": "重新排序資料夾失敗:{message}", + "changeFolderColorFailed": "修改顏色失敗:{message}", + "setFolderAliasFailed": "設定別名失敗:{message}", + "changeFolderDefaultAgentFailed": "設定預設智能體失敗:{message}" + }, + "statsLabel": "{folders} 個資料夾 · {convos} 個對話", + "reorderHandle": "拖拽排序", + "openFolder": "開啟資料夾", + "searchPlaceholder": "搜尋對話...", + "viewOptions": "顯示選項", + "showCompleted": "顯示已完成對話", + "showWorktrees": "顯示工作樹資料夾", + "showRecent": "顯示「最近」分組", + "moreOptions": "更多選項", + "sortBy": "排序方式", + "sortByCreatedAt": "按建立時間排序", + "sortByUpdatedAt": "按更新時間排序", + "sectionOrder": "區域順序", + "sectionOrderMoveUp": "上移", + "sectionOrderMoveDown": "下移", + "sectionOrderItemLabel": "{name} — 第 {position} 位,共 {total} 位", + "statusRunningBadge": "運行中", + "runningCountBadge": "{count} 個會話進行中", + "statusCancelledBadge": "已取消", + "worktreeRemovedBadge": "來源 worktree 已刪除", + "conversationCountUnit": "{count} 條", + "emptyFolderHint": "暫無對話", + "noMatchingConversations": "找不到符合的對話", + "noUnfinishedConversations": "目前沒有未完成的會話,右上角可啟用顯示已完成會話", + "removeFolderConfirmTitle": "從工作區移除此資料夾?", + "removeFolderConfirmDescription": "從工作區移除 \"{name}\"?相關分頁與終端機將會關閉。", + "folderHeaderMenu": { + "manageConversations": "會話管理…", + "manageLinks": "已連結的資料夾", + "changeColor": "修改顏色", + "useThemeColor": "使用設定主題", + "setDefaultAgent": "設定預設智能體", + "defaultAgentNone": "不設定(使用全域預設)", + "agentUnavailableSuffix": "(不可用)", + "loadingAgents": "正在載入代理…", + "setAlias": "設定別名…", + "setAliasTitle": "設定資料夾別名", + "setAliasPlaceholder": "輸入別名(留空清除)", + "setAliasSave": "儲存", + "setAliasCancel": "取消", + "removeFromWorkspace": "從工作區移除" + }, + "manageConversations": { + "title": "會話管理", + "searchPlaceholder": "依標題搜尋…", + "agentFilterAll": "全部智能體", + "statusFilterAll": "全部狀態", + "folderFilterAll": "全部資料夾", + "branchFilterAll": "全部分支", + "branchNone": "無分支", + "branchSearchPlaceholder": "搜尋分支…", + "noMatchingBranches": "無匹配分支", + "selectAllVisible": "全選", + "deselectAll": "取消全選", + "selectedCount": "已選 {count} 筆", + "matchedCount": "符合 {count} 筆", + "untitledConversation": "未命名會話", + "setStatus": "設為狀態…", + "deleteSelected": "刪除", + "noConversations": "此資料夾暫無會話。", + "noConversationsWorkspace": "工作區暫無會話。", + "noMatchingConversations": "沒有符合過濾條件的會話。", + "confirmDeleteTitle": "刪除 {count} 個會話?", + "confirmDeleteDescription": "此操作無法復原。", + "toastDeleted": "已刪除 {count} 個會話", + "toastStatusUpdated": "已更新 {count} 個會話的狀態", + "toastOpFailed": "操作失敗:{message}" + }, + "sectionPinned": "已置頂", + "sectionFolders": "資料夾", + "sectionChats": "聊天", + "sectionRecent": "最近", + "noChats": "沒有聊天", + "noRecent": "暫無最近對話", + "showMoreRecent": "顯示更多({count})", + "noFolders": "沒有開啟的資料夾", + "newChatAction": "新增聊天", + "automations": "自動化", + "tasks": "待辦任務", + "loadingSubsessions": "正在載入子會話…" + }, + "conversation": { + "reloadFailed": "會話重新載入失敗:{message}", + "reloaded": "目前會話已重新載入", + "reload": "重新載入", + "activeConversationIndicator": "目前啟用的會話", + "newConversation": "新增會話", + "closeConversation": "關閉會話", + "copyText": "複製文字", + "copyTextSuccess": "已複製", + "copyTextFailed": "複製失敗", + "forkSession": "分叉會話", + "forkSessionSuccess": "會話分叉成功", + "forkSessionFailed": "會話分叉失敗:{error}", + "exportConversation": "匯出對話", + "exportImage": "圖片", + "exportMarkdown": "Markdown", + "exportHtml": "HTML", + "exportSuccess": "對話已匯出", + "exportFailed": "匯出失敗", + "exportImageTooLong": "對話內容過長,不支援匯出為圖片", + "exportLabels": { + "untitledConversation": "未命名對話", + "agent": "代理", + "model": "模型", + "status": "狀態", + "started": "開始時間", + "updated": "更新時間", + "tokens": "令牌統計", + "duration": "時長", + "inputTokens": "輸入", + "outputTokens": "輸出", + "cacheRead": "快取讀取", + "cacheWrite": "快取寫入", + "user": "使用者", + "assistant": "助手", + "system": "系統", + "toolResult": "結果", + "toolError": "錯誤" + }, + "moreActions": "更多操作" + }, + "sessionDetails": { + "menuLabel": "對話詳情", + "noActiveSession": "暫無使用中的對話", + "title": "對話詳情", + "subtitle": "對話中繼資料與 Token 用量", + "fieldTitle": "標題", + "untitled": "未命名對話", + "sessionId": "對話 ID", + "externalId": "擴充 ID", + "agent": "智能體", + "model": "模型", + "status": "狀態", + "gitBranch": "Git 分支", + "parentId": "父對話", + "tokensHeading": "Token 用量", + "totalTokens": "總計", + "inputTokens": "輸入", + "outputTokens": "輸出", + "cacheWrite": "快取寫入", + "cacheRead": "快取讀取", + "contextWindow": "上下文視窗", + "duration": "時長", + "loadingStats": "正在載入 Token 用量…", + "loadFailed": "載入 Token 用量失敗", + "noStats": "尚無用量記錄", + "timestampsHeading": "時間", + "createdAt": "建立時間", + "updatedAt": "更新時間", + "none": "—", + "copyField": "複製{field}", + "copiedField": "已複製{field}" + }, + "conversationCard": { + "untitledConversation": "未命名會話", + "newConversation": "新增會話", + "rename": "重新命名", + "status": "狀態", + "delete": "刪除", + "importLocalSessions": "匯入本地會話", + "importing": "匯入中...", + "renameConversation": "重新命名會話", + "deleteConversationTitle": "刪除會話?", + "deleteConversationDescription": "會刪除「{title}」,此操作無法復原。", + "cancel": "取消", + "save": "儲存", + "pin": "置頂", + "unpin": "取消置頂", + "markCompleted": "標記為已完成", + "reopen": "重新開啟", + "expandSubsessions": "展開子會話", + "collapseSubsessions": "摺疊子會話" + }, + "search": { + "dialogTitle": "搜尋", + "dialogTitleWithFolder": "搜尋 — {name}", + "tabConversations": "會話", + "tabFiles": "檔案", + "placeholder": "搜尋會話...", + "filePlaceholder": "搜尋檔案或目錄...", + "allAgents": "全部", + "searching": "搜尋中...", + "typeToSearch": "輸入關鍵字搜尋會話", + "typeToSearchFiles": "輸入關鍵字搜尋檔案或目錄", + "noResults": "找不到結果。", + "untitledConversation": "未命名會話" + }, + "folderTitleBar": { + "showSidebar": "顯示側邊欄", + "hideSidebar": "隱藏側邊欄", + "toggleTerminal": "切換終端", + "toggleAuxPanel": "切換輔助面板", + "search": "搜尋", + "openSettings": "打開設定", + "backToConversations": "返回會話", + "withShortcut": "{label}({shortcut})" + }, + "statusBar": { + "connection": { + "connected": "已連線", + "connecting": "連線中...", + "prompting": "回應中...", + "error": "連線異常", + "disconnected": "未連線", + "tooltip": "{agent}:{status}", + "tooltipError": "{agent}:{error}", + "title": "智慧體連線", + "triggerAria": "智慧體連線:{status}", + "workingDir": "工作目錄", + "sessionId": "工作階段 ID", + "viewerNote": "已接入其他用戶端擁有的工作階段——重新連線只會重新接入目前檢視。", + "reconnectInterrupts": "重新連線會重啟智慧體,並中斷進行中的工作。", + "reconnect": "重新連線", + "reconnecting": "正在重新連線...", + "reconnectUnavailable": "目前沒有可重新連線的工作階段。" + }, + "tasks": { + "title": "任務" + }, + "alerts": { + "title": "警示", + "empty": "暫無警示資訊", + "details": "詳情" + }, + "stats": { + "conversations": "{count} 個會話", + "openUsage": "檢視會話統計與 Token 用量" + }, + "tokens": { + "contextWindowUsageAria": "上下文視窗使用率", + "contextWindow": "上下文視窗", + "usedMax": "已用 / 上限", + "tokenUsage": "Token 用量", + "input": "輸入", + "output": "輸出", + "cacheRead": "快取讀取", + "cacheWrite": "快取寫入", + "total": "總計" + } + }, + "auxPanel": { + "tabs": { + "files": "檔案", + "changes": "變更", + "commits": "提交" + }, + "noFolderTitle": "尚無開啟的資料夾", + "noFolderHint": "開啟一個資料夾後可在此查看" + }, + "windowControls": { + "minimizeWindow": "最小化視窗", + "minimize": "最小化", + "maximizeWindow": "最大化視窗", + "maximize": "最大化", + "restoreWindow": "還原視窗", + "restore": "還原", + "closeWindow": "關閉視窗", + "close": "關閉" + }, + "tabs": { + "closeConversationTab": "關閉會話分頁", + "close": "關閉", + "closeOthers": "關閉其它", + "splitRight": "向右拆分", + "splitDown": "向下拆分", + "splitAndMoveRight": "拆分並右移", + "splitAndMoveDown": "拆分並下移", + "moveToOppositeGroup": "移動到對側分組", + "moveToGroup": "移動到分組", + "groupLabel": "分組 {index}", + "changeSplitterOrientation": "切換分隔方向", + "unsplit": "取消拆分", + "unsplitAll": "全部取消拆分", + "closeAll": "關閉所有", + "tileDisplay": "平鋪顯示", + "untileDisplay": "取消平鋪" + }, + "fileWorkspace": { + "files": "檔案", + "closeFileTab": "關閉檔案分頁", + "close": "關閉", + "closeOthers": "關閉其它", + "closeAll": "關閉所有", + "preview": "預覽", + "editSource": "編輯原始碼", + "maximize": "最大化", + "restore": "還原", + "emptyDirectory": "空目錄" + }, + "terminal": { + "rename": "重新命名", + "close": "關閉", + "closeOthers": "關閉其它", + "closeAll": "關閉所有", + "hideTerminal": "隱藏終端({shortcut})", + "openFolderFirst": "請先開啟一個資料夾" + }, + "workspaceDialog": { + "title": "開啟資料夾", + "manageTitle": "已連結的資料夾", + "addTargetsTitle": "新增要連結的資料夾", + "pickRootDescription": "選擇這個工作區的主資料夾。", + "linksDescription": "把其他資料夾以子目錄的形式連結進來,代理就能在同一個工作區跨專案工作。", + "addTargetsDescription": "選擇一個或多個資料夾,每個都會成為工作區的一個子目錄。", + "useSystemPicker": "系統選擇器", + "next": "下一步", + "back": "返回", + "done": "完成", + "change": "變更", + "addFolders": "新增資料夾", + "addSelected": "新增", + "addSelectedCount": "新增 {count} 個", + "createCount": "連結 {count} 個資料夾", + "discardPending": "捨棄", + "noLinks": "尚未連結任何資料夾。", + "gitExclude": "不讓連結目錄污染 git 狀態", + "rename": "重新命名", + "unlink": "解除連結", + "repair": "重建連結", + "saveName": "儲存", + "cancelRename": "取消", + "removePending": "移除", + "willAppearAs": "在工作區中顯示為 {name}", + "renamedForDuplicate": "已改名 —— {base} 已被另一個連結佔用", + "renamedForExistingEntry": "已改名 —— 該資料夾中已存在 {base}", + "partiallyCreated": "只成功連結了 {count} 個資料夾", + "openFailed": "開啟資料夾失敗", + "previewFailed": "檢查所選資料夾失敗", + "createFailed": "連結資料夾失敗", + "renameFailed": "重新命名失敗", + "removeFailed": "解除連結失敗", + "repairFailed": "重建連結失敗", + "status": { + "ok": "已連結", + "missing": "連結已從該資料夾中消失", + "conflicted": "該名稱已被其他項目佔用", + "broken": "被連結的資料夾已不存在" + }, + "nameIssue": { + "empty": "請輸入名稱", + "illegalChars": "不能包含 / \\ : * ? \" < > |", + "tooLong": "名稱過長", + "reserved": "該名稱是 Windows 保留名", + "duplicate": "該名稱已被使用" + }, + "rejection": { + "not_found": "找不到該資料夾", + "not_a_directory": "該路徑不是資料夾", + "same_as_root": "這就是工作區資料夾本身", + "ancestor_of_root": "該資料夾包含了目前工作區", + "inside_root": "已在工作區內部", + "already_linked": "已經連結過", + "name_unavailable": "該資料夾已無可用的名稱", + "alreadyLinkedAs": "已作為 {name} 連結" + } + }, + "folderNameDropdown": { + "fallbackFolderName": "資料夾", + "openFolder": "打開資料夾", + "cloneRepository": "複製倉庫", + "projectBoot": "專案啟動器", + "opened": "已打開", + "recentOpen": "最近打開" + }, + "fileWorkspacePanel": { + "addSelectionToChat": "新增選取範圍到對話", + "addToChat": "加入對話", + "addSelectionToChatDone": "已將 {label} 加入對話", + "addFileToChat": "新增檔案到對話", + "toggleWordWrap": "切換自動換行", + "addFileToChatDone": "已將 {label} 加入對話", + "viewDiff": "查看差異", + "openFile": "打開檔案", + "fileCount": "{count} 個檔案", + "openFileOrDiff": "從右側面板打開檔案或差異", + "disk": "磁碟", + "head": "HEAD(目前提交)", + "unsaved": "未儲存", + "workingTree": "工作區", + "loading": "載入中...", + "compareWithBranch": "{path} · 與 {branch} 比較", + "hunkCount": "{count} 個區塊", + "prev": "上一個", + "next": "下一個", + "jumpToLine": "跳到第 {line} 行", + "noParsedDiffSections": "未解析到差異區塊", + "loadingEditor": "編輯器載入中...", + "imageZoomIn": "放大", + "imageZoomOut": "縮小", + "imageZoomReset": "重設縮放", + "htmlPreviewTitle": "HTML 預覽", + "htmlPreviewTrust": "執行指令碼", + "htmlPreviewTrustHint": "執行此檔案的指令碼並允許網路存取。僅對信任的檔案啟用。", + "officePreviewTitle": "辦公文件預覽", + "officeFullRender": "完整渲染", + "officeFullRenderHint": "渲染 Morph 動畫、3D 與公式(會執行投影片自帶的指令碼)", + "officeNotInstalled": "未安裝 OfficeCLI", + "officeNotInstalledHint": "在 設定 → 辦公工具 中安裝 OfficeCLI,即可預覽 Word、Excel 與 PowerPoint 檔案。", + "officeOpenSettings": "開啟設定", + "officeWatchFailed": "無法啟動即時預覽", + "officeWatchRetry": "重試", + "officeServerInstallHint": "OfficeCLI 需安裝在伺服器主機上。請在伺服器上執行以下指令後重試:", + "officeRemoteDesktopUnsupported": "遠端桌面視窗暫不支援即時預覽。請在伺服器的 Web 介面中開啟此工作區以預覽 Office 檔案。" + }, + "branchDropdown": { + "toasts": { + "commitCodeCompleted": "提交程式碼完成", + "pushCodeCompleted": "推送程式碼完成", + "committedFiles": "已提交 {count} 個檔案", + "taskCompleted": "{label} 完成", + "taskFailed": "{label} 失敗", + "mergeNoNewCommits": "{branchName} 沒有新的提交", + "mergedCommits": "已合併 {count} 個提交", + "allFilesUpToDate": "所有檔案均為最新版本", + "updatedFiles": "已更新 {count} 個檔案", + "openCommitWindowFailed": "打開提交視窗失敗", + "openPushWindowFailed": "開啟推送視窗失敗", + "upstreamSet": "已設定遠端追蹤分支", + "upstreamSetAndPushed": "已設定遠端追蹤分支並推送 {count} 個提交", + "noCommitsToPush": "沒有可推送的提交", + "pushedCommits": "已推送 {count} 個提交", + "switchedToFolder": "已切換到 {name}", + "switchFailed": "切換分支失敗", + "openStashWindowFailed": "開啟收藏視窗失敗" + }, + "tasks": { + "newBranch": "新增分支 {name}", + "newWorktree": "新增工作樹 {name}", + "checkoutTo": "切換到 {branchName}", + "mergeBranch": "合併 {branchName}", + "rebaseTo": "變基到 {branchName}", + "deleteRemoteBranch": "刪除遠端分支 {branchName}", + "initGitRepo": "初始化 Git 倉庫", + "pullCode": "更新程式碼", + "fetchInfo": "獲取資訊", + "pushCode": "推送程式碼", + "stashChanges": "暫存變更", + "stashPop": "取消暫存", + "deleteBranch": "刪除分支 {branchName}", + "removeWorktree": "刪除 {branchName} 的工作樹", + "removeWorktreeAndBranch": "刪除工作樹及分支 {branchName}", + "updateBranch": "更新分支 {branchName}" + }, + "confirm": { + "mergeTitle": "合併分支", + "rebaseTitle": "變基分支", + "mergeDescription": "確定將 {branchName} 合併到目前分支 {currentBranch} 嗎?", + "rebaseDescription": "確定將目前分支 {currentBranch} 變基到 {branchName} 嗎?", + "deleteRemoteTitle": "刪除遠端分支", + "deleteRemoteDescription": "確定刪除遠端分支 {branchName} 嗎?此操作將從遠端倉庫中移除該分支,且不可恢復。", + "deleteTitle": "刪除分支", + "deleteDescription": "確定刪除分支 {branchName} 嗎?此操作無法復原。", + "forceDeleteTitle": "強制刪除分支", + "forceDeleteDescription": "分支 {branchName} 尚未完全合併,確定要強制刪除嗎?此操作不可恢復。", + "deleteWorktreeTitle": "刪除工作樹", + "deleteWorktreeDescription": "刪除簽出了 {branchName} 的工作樹目錄?分支及其提交會保留。", + "forceDeleteWorktreeTitle": "強制刪除工作樹", + "forceDeleteWorktreeDescription": "{branchName} 的工作樹中有未提交或未追蹤的檔案。仍要刪除嗎?這些變更將無法復原。", + "deleteWorktreeAndBranchTitle": "刪除工作樹及分支", + "deleteWorktreeAndBranchDescription": "刪除 {branchName} 的工作樹、該分支本身及其工作區資料夾?其中的工作階段會移動到儲存庫資料夾下。此操作無法復原。", + "forceDeleteWorktreeAndBranchTitle": "強制刪除工作樹及分支", + "forceDeleteWorktreeAndBranchDescription": "{branchName} 的工作樹中有未提交的檔案,或該分支尚未完全合併。仍要一併刪除嗎?此操作無法復原。" + }, + "current": "目前", + "switchToBranch": "切換到此分支", + "mergeBranchIntoCurrent": "將 {branchName} 合併到 {currentBranch}", + "rebaseCurrentToBranch": "將 {currentBranch} 變基到 {branchName}", + "noBranch": "無分支", + "detachedHead": "分離 HEAD({sha})", + "initGitRepo": "初始化 Git 倉庫", + "pullCode": "更新程式碼", + "fetchRemoteBranches": "提取遠端分支", + "openCommitWindow": "提交程式碼...", + "pushCode": "推送...", + "pushBranch": "推送", + "newBranch": "新增分支...", + "newWorktree": "新增工作樹...", + "stashChanges": "貯藏更改...", + "stashPop": "取消暫存...", + "manageRemotes": "管理遠端...", + "localBranches": "本地分支 ({count})", + "noLocalBranches": "無本地分支", + "remoteBranches": "遠端分支 ({count})", + "noRemoteBranches": "無遠端分支", + "dialogs": { + "newBranchTitle": "新增分支", + "newBranchDescription": "從目前分支 {branch} 建立新分支", + "branchNamePlaceholder": "分支名稱", + "newWorktreeTitle": "新增工作樹", + "newWorktreeDescription": "從目前分支 {branch} 建立新的工作樹", + "branchNameLabel": "分支名稱", + "worktreePathLabel": "工作樹路徑", + "worktreePathPlaceholder": "工作樹路徑", + "manageRemotesTitle": "管理遠端", + "manageRemotesEmpty": "未設定遠端儲存庫", + "remoteNamePlaceholder": "遠端名稱", + "remoteUrlPlaceholder": "遠端 URL", + "addRemote": "新增", + "savingRemotes": "儲存中..." + }, + "conflict": { + "title": "合併衝突", + "description": "以下檔案存在衝突,需要手動解決:", + "abort": "中止合併", + "openMergeTool": "開啟合併工具", + "completeMerge": "完成合併", + "abortSuccess": "合併已中止", + "completeSuccess": "合併完成" + }, + "stashDialog": { + "title": "貯藏更改", + "description": "將當前更改保存到貯藏區", + "messageLabel": "訊息", + "messagePlaceholder": "貯藏訊息(可選)", + "keepIndex": "保留暫存區(已暫存的更改保持不變)", + "cancel": "取消", + "stash": "貯藏", + "success": "更改已貯藏", + "error": "貯藏更改失敗" + }, + "unstashDialog": { + "title": "取消貯藏", + "noStashes": "沒有貯藏記錄", + "selectFile": "選擇檔案查看差異", + "viewDiff": "查看差異", + "original": "原始", + "modified": "修改後", + "apply": "套用", + "drop": "刪除", + "applySuccess": "貯藏已套用", + "dropSuccess": "貯藏已刪除", + "confirmApply": "將貯藏 {ref} 套用到工作目錄?", + "cancel": "取消" + }, + "deleteBranch": "刪除分支", + "deleteWorktree": "刪除工作樹", + "deleteWorktreeAndBranch": "刪除工作樹及分支", + "searchPlaceholder": "搜尋分支與操作", + "searchAriaLabel": "搜尋分支與操作", + "branchListLabel": "分支與操作", + "noMatches": "無相符項目" + }, + "commitDialog": { + "toasts": { + "commitCompleted": "提交程式碼完成", + "pushFailed": "推送失敗", + "committedFiles": "已提交 {count} 個檔案", + "addedToVcs": "已加入到 VCS", + "addToVcsFailed": "加入到 VCS 失敗", + "fileDeleted": "檔案已刪除", + "deleteFailed": "刪除失敗", + "fileRolledBack": "檔案已回滾", + "rollbackFailed": "回滾失敗", + "dirRolledBack": "目錄已回滾", + "dirDeleted": "目錄已刪除" + }, + "confirm": { + "deleteTitle": "確認刪除", + "deleteDescription": "確定要刪除檔案「{file}」嗎?此操作無法復原。", + "rollbackTitle": "確認回滾", + "rollbackDescription": "確定要回滾檔案「{file}」到 HEAD 版本嗎?未儲存修改將遺失。", + "rollbackDirDescription": "確定要回滾目錄「{dir}」到 HEAD 版本嗎?未儲存的修改將遺失。", + "deleteDirDescription": "確定要刪除目錄「{dir}」嗎?此操作不可恢復。" + }, + "actions": { + "select": "選擇", + "unselect": "取消選擇", + "rollback": "回滾", + "addToVcs": "加入到 VCS" + }, + "aria": { + "selectFile": "{action}:{path}", + "unselectAllFiles": "取消選擇全部檔案", + "selectAllFiles": "選擇全部檔案", + "unselectTracked": "取消選擇已追蹤變更", + "selectTracked": "選擇已追蹤變更", + "unselectUntracked": "取消選擇未追蹤檔案", + "selectUntracked": "選擇未追蹤檔案" + }, + "loading": "載入中...", + "selectionCount": "{selected} / {total} 個檔案", + "emptyFiles": "沒有變更的檔案", + "trackedChanges": "已追蹤變更 ({count})", + "untrackedFiles": "未追蹤檔案 ({count})", + "commitMessage": "提交訊息", + "commitMessagePlaceholder": "輸入提交訊息...", + "commitButton": "提交 ({count})", + "commitAndPushButton": "提交並推送 ({count})", + "head": "HEAD(目前提交)", + "workingTree": "工作目錄", + "clickFileToDiff": "點擊檔案名稱查看差異", + "loadingDiff": "載入差異中..." + }, + "pushWindow": { + "title": "推送程式碼", + "noUnpushedCommits": "沒有未推送的提交", + "noRemoteConfigured": "未設定 Git 遠端儲存庫\n請在「管理遠端」中新增遠端地址", + "newBranchNoPushedCommits": "新分支 — 推送以建立遠端追蹤分支", + "unpushed": "未推送", + "selectFileToViewDiff": "選擇檔案查看差異", + "before": "修改前", + "after": "修改後", + "push": "推送", + "toasts": { + "pushSuccess": "推送成功", + "pushFailed": "推送失敗", + "upstreamSet": "已設定遠端追蹤分支", + "upstreamSetAndPushed": "已設定遠端追蹤分支並推送 {count} 個提交", + "noCommitsToPush": "沒有可推送的提交", + "pushedCommits": "已推送 {count} 個提交" + } + }, + "gitLogTab": { + "filesTitle": "檔案", + "expandAllFiles": "展開全部檔案", + "collapseAllFiles": "折疊全部檔案", + "workspace": "工作區", + "retry": "重試", + "noCommitsFound": "未找到提交記錄", + "notAGitRepoTitle": "不是 Git 儲存庫", + "notAGitRepoHint": "可從上方分支選單初始化 Git,或開啟已有的 Git 儲存庫。", + "hash": "Hash", + "copyHash": "複製雜湊", + "copyMessage": "複製提交訊息", + "showMore": "展開", + "showLess": "收合", + "author": "作者", + "noFileChangeDetails": "暫無檔案變更詳情。", + "loadingFiles": "正在載入檔案…", + "branchesTitle": "分支", + "loadingBranches": "正在載入分支...", + "noContainingBranches": "未找到包含此提交的分支。", + "newBranch": "新增分支...", + "resetToHere": "重設到此處", + "resetDisabledReasonNotCurrentBranchView": "僅在檢視目前分支時可用", + "copyFullCommitHashAria": "複製完整提交雜湊 {hash}", + "pushStatus": { + "pushed": "已推送到遠端", + "notPushed": "未推送到遠端", + "unknown": "推送狀態未知(未配置上游分支)" + }, + "time": { + "monthsAgo": "{count} 個月前", + "daysAgo": "{count} 天前", + "hoursAgo": "{count} 小時前", + "minsAgo": "{count} 分鐘前", + "justNow": "剛剛" + }, + "toasts": { + "createdAndSwitchedNewBranch": "已建立並切換到新分支", + "newBranchFromCommit": "{name}(來自 {shortHash})", + "createBranchFailed": "新增分支失敗", + "openPushWindowFailed": "開啟推送視窗失敗", + "resetSuccess": "重設成功", + "resetSuccessDescription": "已將 {branch} 以 {mode} 重設到 {shortHash}", + "resetFailed": "重設失敗" + }, + "authorFilter": { + "label": "作者", + "searchPlaceholder": "搜尋作者", + "noAuthors": "找不到作者", + "you": "你", + "filterByAuthorAria": "依作者篩選提交", + "filterByQuery": "依「{query}」篩選", + "clearAuthorFilterAria": "清除作者篩選", + "recent": "最近", + "matchingAuthors": "符合的作者", + "removeFromRecent": "從最近列表移除 {name}" + }, + "branchSelector": { + "label": "分支", + "head": "HEAD", + "headHint": "跟隨目前分支", + "headHintWithBranch": "跟隨目前分支({branch})", + "searchBranch": "搜尋分支...", + "noBranches": "無分支", + "selectBranchPlaceholder": "選擇分支...", + "localBranches": "本地分支", + "current": "目前", + "remoteBranches": "遠端分支", + "refreshCommitHistory": "刷新提交記錄", + "clearBranchFilterAria": "清除分支篩選" + }, + "dialogs": { + "newBranchTitle": "新增分支", + "newBranchDescription": "以提交 {shortHash} 作為最後提交建立新分支。", + "branchNamePlaceholder": "分支名稱", + "reset": { + "title": "將目前分支重設到此提交", + "branchLabel": "分支", + "targetLabel": "目標提交", + "messageLabel": "提交訊息", + "modeLabel": "重設模式", + "confirmButton": "重設", + "modes": { + "soft": { + "label": "--soft", + "description": "將 HEAD 與目前分支指標移動到目標提交。\n暫存區(Index)與工作區(Working Tree)保持不變。\n被回退提交的變更會保留為「已暫存」。" + }, + "mixed": { + "label": "--mixed(預設)", + "description": "將 HEAD 移動到目標提交。\n把暫存區重設為目標提交狀態,但保留工作區變更。\n這些變更會由「已暫存」變成「未暫存」。" + }, + "hard": { + "label": "--hard", + "description": "將 HEAD、暫存區與工作區全部重設到目標提交。\n目標提交之後的本地已追蹤變更會被直接捨棄。\n這是破壞性操作。" + }, + "keep": { + "label": "--keep", + "description": "將 HEAD 移動到目標提交,並盡可能保留本地變更。\n僅保留與目標提交不衝突的本地變更。\n若檢測到衝突,操作會中止以保護你的修改。" + } + } + } + }, + "moreActions": "更多 Git 操作" + }, + "gitChangesTab": { + "workspace": "工作區", + "noChanges": "暫無本地變更", + "notAGitRepoTitle": "不是 Git 儲存庫", + "notAGitRepoHint": "可從上方分支選單初始化 Git,或開啟已有的 Git 儲存庫。", + "trackedChanges": "本地已追蹤變更 ({count})", + "untrackedFiles": "本地未追蹤檔案 ({count})", + "expandTracked": "展開已追蹤變更", + "collapseTracked": "折疊已追蹤變更", + "expandUntracked": "展開未追蹤檔案", + "collapseUntracked": "折疊未追蹤檔案", + "showRemainingItems": "顯示其餘 {count} 項", + "actions": { + "commitCode": "提交程式碼", + "rollback": "回滾", + "addToVcs": "加入到 VCS", + "delete": "刪除", + "moreActions": "更多 Git 操作", + "addAllToVcs": "全部加入 VCS", + "rollbackAll": "全部還原", + "refresh": "重新整理" + }, + "toasts": { + "noAddableFilesInDir": "該目錄下沒有可加入到 VCS 的變更檔案", + "noRollbackFilesInDir": "該目錄下沒有可回滾的變更檔案", + "addedToVcs": "已加入 {name} 到 VCS", + "addToVcsFailed": "加入到 VCS 失敗", + "openCommitWindowFailed": "打開提交視窗失敗", + "rolledBack": "已回滾 {name}", + "rollbackFailed": "回滾失敗", + "addedFilesToVcs": "已加入 {count} 個檔案到 VCS", + "rolledBackFiles": "已回滾 {count} 個檔案", + "deleted": "已刪除 {name}", + "deleteFailed": "刪除失敗", + "deletedFiles": "已刪除 {count} 個檔案", + "noDeletableFilesInDir": "此目錄下沒有可刪除的變更檔案", + "commitFailed": "提交失敗" + }, + "directoryDialog": { + "descriptionAdd": "選擇目錄 {path} 下要加入到 VCS 的檔案。", + "descriptionRollback": "選擇目錄 {path} 下要回滾的檔案。", + "descriptionDelete": "選擇目錄 {path} 下要刪除的檔案。此操作不可撤銷。", + "descriptionFallback": "選擇要操作的檔案。", + "selectionCount": "已選擇 {selected} / {total} 個檔案", + "selectAll": "全選", + "unselectAll": "取消全選", + "loadingCandidates": "正在載入目錄變更...", + "noOperableFiles": "沒有可操作的檔案" + }, + "rollbackConfirm": { + "title": "確認回滾", + "descriptionWithTarget": "確定回滾{kind}「{name}」的本地修改嗎?", + "descriptionFallback": "確定回滾本地修改嗎?", + "kindDirectory": "目錄", + "kindFile": "檔案" + }, + "deleteConfirm": { + "title": "確認刪除", + "descriptionWithTarget": "確定刪除{kind}「{name}」嗎?此操作無法撤銷。", + "descriptionFallback": "此操作無法撤銷。", + "kindDirectory": "目錄", + "kindFile": "檔案" + }, + "quickCommit": { + "placeholder": "提交訊息(Enter 提交)" + } + }, + "tabContext": { + "loadingConversation": "載入中...", + "untitledConversation": "未命名會話", + "newConversation": "新增會話" + }, + "fileTreeTab": { + "workspace": "工作區", + "retry": "重試", + "git": "Git", + "openInFileManager": "在檔案管理器開啟", + "openInFinder": "在 Finder 開啟", + "openInExplorer": "在檔案總管開啟", + "attachToCurrentSession": "添加到會話", + "compareWithBranch": "與分支比較...", + "reloadFromDisk": "從磁碟重新載入", + "new": "新建", + "newFile": "檔案", + "newDirectory": "目錄", + "openIn": "開啟於", + "openInTerminal": "在終端開啟", + "linkedFolder": "已連結的資料夾", + "copyPath": "複製路徑", + "upload": "上傳檔案/目錄", + "download": "下載檔案", + "downloadAsZip": "下載為 ZIP", + "actions": { + "select": "選擇", + "unselect": "取消選擇", + "commitCode": "提交程式碼", + "rollback": "回滾", + "addToVcs": "加入到 VCS" + }, + "aria": { + "selectPath": "{action}:{path}" + }, + "toasts": { + "openDirectoryFailed": "開啟目錄失敗", + "openBuiltinTerminalFailed": "無法開啟內建終端", + "openCommitWindowFailed": "打開提交視窗失敗", + "noAddableFilesInDir": "該目錄下沒有可加入到 VCS 的變更檔案", + "noRollbackFilesInDir": "該目錄下沒有可回滾的變更檔案", + "addedToVcs": "已加入 {name} 到 VCS", + "addToVcsFailed": "加入到 VCS 失敗", + "loadBranchesFailed": "載入分支失敗", + "renameFailed": "重新命名失敗", + "moveFailed": "移動失敗", + "deleteFailed": "刪除失敗", + "rolledBack": "已回滾 {name}", + "rollbackFailed": "回滾失敗", + "addedFilesToVcs": "已加入 {count} 個檔案到 VCS", + "rolledBackFiles": "已回滾 {count} 個檔案", + "savedAsCopy": "已另存為副本", + "saveCopyFailed": "另存為副本失敗", + "watchStartFailed": "檔案監聽啟動失敗", + "createFailed": "建立失敗", + "downloadFailed": "下載 {name} 失敗", + "downloadSaved": "已下載 {name}", + "pathCopied": "已複製路徑", + "copyPathFailed": "複製路徑失敗" + }, + "createDialog": { + "newFile": "新建檔案", + "newDirectory": "新建目錄", + "description": "輸入新{kind}的名稱。", + "placeholderFile": "file-name.ext", + "placeholderDirectory": "folder-name" + }, + "renameDialog": { + "renameDirectory": "重新命名目錄", + "renameFile": "重新命名檔案", + "description": "輸入新的名稱(僅名稱,不含路徑)。", + "placeholderDirectory": "新資料夾名稱", + "placeholderFile": "新檔案名稱.ext" + }, + "uploadDialog": { + "title": "上傳到工作區", + "description": "可在下方修改上傳目錄,然後加入檔案或資料夾。", + "workspaceRoot": "工作區根目錄", + "targetPathLabel": "上傳到", + "targetPathHint": "實際目錄:{path}", + "dropHint": "拖曳檔案或資料夾到此處,或使用下方按鈕", + "dropHintActive": "放開以加入上傳佇列", + "selectFiles": "選擇檔案", + "selectFolder": "選擇資料夾", + "startUpload": "開始上傳", + "clearQueue": "清除已完成", + "removeItem": "從佇列移除", + "retry": "重試", + "dropZoneAria": "拖放檔案到此處,或按 Enter 鍵瀏覽", + "folderEmpty": "拖入的資料夾中沒有可上傳的檔案", + "summary": "總數:{total} · 成功:{succeeded} · 失敗:{failed}", + "status": { + "pending": "等待中", + "uploading": "上傳中", + "success": "完成", + "error": "失敗", + "cancelled": "已取消" + } + }, + "directoryDialog": { + "descriptionAdd": "選擇目錄 {path} 下要加入到 VCS 的檔案。", + "descriptionRollback": "選擇目錄 {path} 下要回滾的檔案。", + "descriptionFallback": "選擇要操作的檔案。", + "selectionCount": "已選擇 {selected} / {total} 個檔案", + "selectAll": "全選", + "unselectAll": "取消全選", + "loadingCandidates": "正在載入目錄變更...", + "noOperableFiles": "沒有可操作的檔案" + }, + "compareDialog": { + "title": "與分支比較", + "descriptionWithTarget": "選擇分支並與{kind} {path} 比對", + "descriptionFallback": "選擇要比較的分支。", + "kindDirectory": "目錄", + "kindFile": "檔案", + "filterPlaceholder": "過濾分支,例如 main / origin/main", + "singleClickHint": "單擊分支即可直接比較", + "loadingBranches": "正在載入分支...", + "recentBranches": "最近分支 ({count})", + "noCurrentBranch": "無目前分支", + "localBranches": "本地分支 ({count})", + "remoteBranches": "遠端分支 ({count})", + "noMatchingBranches": "無匹配分支" + }, + "externalConflictDialog": { + "title": "偵測到外部檔案變更", + "descriptionWithPath": "檔案 {path} 在磁碟已發生變化,目前編輯內容尚未儲存。", + "descriptionFallback": "目前檔案在磁碟已發生變化,目前編輯內容尚未儲存。", + "compare": "比較", + "savingCopy": "另存中...", + "saveAsCopy": "另存為副本", + "reload": "重載" + }, + "deleteConfirm": { + "title": "確認刪除", + "descriptionWithTarget": "確定刪除{kind} \"{name}\" 嗎?此操作不可撤銷。", + "descriptionFallback": "此操作不可撤銷。", + "kindDirectory": "目錄", + "kindFile": "檔案" + }, + "rollbackConfirm": { + "title": "確認回滾", + "descriptionWithTarget": "確定回滾檔案 \"{name}\" 的本地修改嗎?", + "descriptionFallback": "確定回滾該檔案的本地修改嗎?" + }, + "terminalTitle": "終端 · {name}" + }, + "commandDropdown": { + "loading": "載入中...", + "addCommand": "新增命令", + "manageCommands": "管理命令...", + "runCommandTitle": "執行:{command}", + "stopCommandTitle": "停止:{command}", + "manageDialog": { + "title": "管理命令", + "empty": "暫無命令", + "noResults": "沒有符合的命令", + "searchPlaceholder": "搜尋命令", + "newCommand": "新增命令", + "nameLabel": "名稱", + "commandLabel": "命令", + "dragSort": "拖曳排序", + "dragSortCommand": "拖曳排序 {name}", + "orderFailed": "儲存命令排序失敗", + "loadFailed": "載入命令失敗", + "saveFailed": "儲存命令失敗", + "deleteFailed": "刪除命令失敗", + "confirmDelete": { + "title": "刪除命令?", + "message": "這會移除「{name}」,此操作無法復原。" + } + } + }, + "workspaceContext": { + "confirmCloseDirtyTab": "檔案「{title}」有未儲存變更,確定關閉嗎?", + "confirmCloseOtherDirtyTabs": "其他分頁有未儲存變更,確定關閉嗎?", + "confirmCloseAllDirtyTabs": "存在未儲存變更,確定關閉全部分頁嗎?", + "unableLoadContent": "無法載入內容。\n\n{message}", + "previewRequestTimedOut": "預覽請求逾時", + "diffRequestTimedOut": "Diff 請求逾時", + "branchCompareRequestTimedOut": "分支比較請求逾時", + "commitDiffRequestTimedOut": "提交差異請求逾時", + "saveRequestTimedOut": "儲存請求逾時", + "reloadRequestTimedOut": "重載請求逾時", + "noChanges": "暫無變更。", + "noDiffOutput": "無差異輸出。", + "diffTitleWorkspace": "Diff · 工作區", + "diffDescriptionWorkingTree": "工作區變更(HEAD)", + "diffTitleFile": "差異 · {name}", + "compareTitleFile": "比較 · {name}", + "compareTitleBranch": "比較 · {branch}", + "compareDescriptionPath": "{path} · 與 {branch} 比較", + "compareDescriptionBranch": "與 {branch} 比較", + "diffTitleCommitFile": "差異 · {name} @ {hash}", + "diffTitleCommit": "差異 · {hash}", + "diffDescriptionCommitPath": "{path} · 提交 {commit}", + "diffDescriptionCommit": "提交 {commit}", + "diffTitleConflictFile": "衝突 · {name}", + "diffDescriptionConflict": "{path} · 磁碟與未儲存內容" + }, + "chat": { + "acpConnections": { + "actions": { + "openAgentsSettings": "打開 Agents 管理", + "retry": "重試" + }, + "agentsSetupHint": "點擊前往設定 > Agents 管理安裝。", + "withSetupHint": "{message}\n提示:{hint}", + "blocked": { + "missingConfig": "無法讀取目前 Agent 設定。", + "disabled": "{agent} 已在 Agents 管理中停用,請先啟用後再連線。", + "unavailable": "{agent} 目前平台不可用。", + "sdkMissing": "{agent} SDK 尚未安裝", + "adapterMissing": "{agent} 的 ACP 轉接器尚未安裝" + }, + "backendErrors": { + "initializeTimeout": "{agent} 連線交握逾時(60 秒未回應),請前往設定頁面檢查智能體與網路設定。", + "mcpRejectedByAgent": "附帶 codeg 的 MCP 伴生程序時,{agent} 拒絕了本次會話:{message} 如果該智能體不支援 MCP,請在設定中關閉它的「MCP 支援」後重新連線。", + "processExited": "{agent} 處理程序意外結束。", + "spawnFailed": "啟動 {agent} 失敗:{message}", + "downloadFailed": "{agent} 下載失敗:{message}", + "sessionLoadResourceNotFound": "{agent} 會話載入失敗,可重新載入重試,或開始新會話。", + "sessionLoadUnavailable": "{agent} 無法還原此會話,它可能已結束或 agent 已停止。可重新載入重試,或開始新會話。", + "turnFailedRefusal": "{agent} 拒絕繼續此輪回覆,通常代表後端或網關出錯,請檢查代理日誌。", + "turnFailedMaxTokens": "{agent} 已達到此輪回覆的最大 Token 限制。", + "turnFailedMaxTurnRequests": "{agent} 已達到此輪回覆允許的最大請求次數。", + "turnFailedUnknown": "{agent} 以未知的停止原因結束了此輪回覆。", + "grokModelSwitchIncompatibleAgent": "{agent} 無法在既有對話中切換到該模型,請新建工作階段以使用它。", + "turnFailedEmpty": "{agent} 此輪沒有產生任何回覆就結束了。", + "turnFailedEmptyProtocol": "{agent} 此輪的輸出 codeg 無法解析,可能是代理版本與協定不相符。", + "turnFailedEmptyMetadata": "{agent} 此輪只收到狀態更新(計畫 / 模式 / 用量),沒有收到任何回覆。", + "detailsInAlerts": "在狀態列的「警示」中展開詳情,即可查看代理輸出。" + }, + "unableReadAgentConfig": "無法讀取 Agent 設定:{message}", + "connectFailedTitle": "{agent} 連線失敗", + "toolFallbackTitle": "工具", + "eventErrorTitle": "Agent 錯誤", + "notificationTurnComplete": "{agent} 已完成回應", + "notificationError": "{agent} 錯誤:{message}", + "claudeApiRetry": { + "fallbackError": "authentication_failed", + "retryingWithMax": "正在重試 {attempt}/{max}", + "retryingAttempt": "正在重試(第 {attempt} 次)", + "retrying": "正在重試", + "nextRetryIn": "{seconds} 秒後重試", + "line": "{error}{status} · {retry}", + "lineWithDelay": "{error}{status} · {retry},{delay}", + "httpStatus": "(HTTP {status})" + }, + "configOptionAdjusted": "{agent} 把{option}設成了 {actual},而不是 {requested}" + }, + "connectionLifecycle": { + "tasks": { + "connectingTitle": "正在連線 {agent}", + "connectingDescription": "正在建立連線", + "loadingSelectorsTitle": "正在載入 {agent} 選擇項", + "loadingSelectorsDescription": "正在取得模式與會話設定選項", + "initSessionTitle": "正在初始化 {agent} 會話", + "initSessionDescription": "正在建立會話並載入設定" + }, + "errors": { + "connectionFailed": "連線失敗", + "sendPromptFailed": "訊息傳送失敗:{error}" + } + }, + "shared": { + "attachedResources": "附加資源", + "toolCallFailed": "工具呼叫失敗" + }, + "messageThread": { + "emptyTitle": "暫無訊息", + "emptyDescription": "開始一個會話後,訊息會顯示在這裡" + }, + "chatInput": { + "connecting": "連線中...", + "agentResponding": "{agent} 正在回應...", + "sendMessage": "傳送訊息..." + }, + "messageInput": { + "askAnything": "請開始輸入...", + "removeAttachmentAria": "移除 {name}", + "attachFiles": "附加檔案", + "addActions": "新增", + "quickMessages": "快捷訊息", + "quickMessagesEmpty": "尚無快捷訊息", + "quickMessagesLoading": "載入中...", + "pasteAsPlainText": "貼上純文字", + "cut": "剪下", + "copy": "複製", + "selectAll": "全選", + "pasteUnavailable": "無法讀取剪貼簿,請改用 Ctrl/⌘V 貼上。", + "clipboardWriteFailed": "無法寫入剪貼簿,請改用鍵盤快速鍵。", + "quickMessageUntitled": "未命名", + "liveFeedback": "即時回饋", + "liveFeedbackDisabledHint": "智能體工作時可傳送", + "dropFilesToAttach": "拖曳檔案到此處附加", + "loadingSettings": "正在載入設定...", + "loadingMode": "正在載入模式...", + "modeLabel": "模式", + "toggleOn": "開", + "toggleOff": "關", + "agentSettings": "智能體設定", + "searchModel": "搜尋模型...", + "searchModelAria": "搜尋模型", + "modelListLabel": "模型", + "noModels": "找不到模型", + "cancel": "取消", + "send": "傳送", + "forkAndSend": "分叉發送", + "queueMessage": "加入佇列", + "steerIntoTurn": "插入目前回合", + "steerQueuedInstead": "已轉入佇列——將隨下一回合傳送。", + "steerFailed": "無法插入目前回合", + "steerAttachmentsUnsupported": "僅支援純文字——帶附件的草稿請走佇列。", + "slashCommands": "斜線命令", + "slashSearchPlaceholder": "搜尋命令...", + "slashSearchEmpty": "沒有符合的指令", + "experts": "專家", + "office": "日常辦公", + "research": "科學研究", + "attachLocalUpload": "附加本機檔案", + "attachServerFile": "附加伺服器檔案", + "attachUploadTooLarge": "{names} 超過 {limit}MB 上傳上限,已略過。", + "attachUploadFailed": "上傳失敗:{names}。", + "attachUploadNotAFile": "{names} 不是常規檔案(目錄或特殊檔案),已略過。", + "attachUploadQuotaExceeded": "伺服器上傳空間已用盡,{names} 未能上傳。", + "attachUploadInProgress": "圖片仍在上傳中,請稍候再傳送。", + "mentionEmpty": "無相符項目", + "mentionLoading": "搜尋中…", + "mentionListLabel": "提及", + "mentionMore": "還有更多結果,繼續輸入以篩選", + "mentionCount": "{count, plural, other {# 項結果}}", + "mentionGroupFile": "檔案", + "mentionGroupAgent": "智能體", + "mentionGroupSession": "工作階段", + "mentionGroupCommit": "提交", + "mentionGroupSkill": "技能" + }, + "messageQueue": { + "addToQueue": "加入佇列", + "saveEdit": "儲存", + "cancelEdit": "取消編輯", + "editItem": "編輯", + "deleteItem": "刪除" + }, + "welcomeInputPanel": { + "agentsSettingsPath": "設定 > Agents", + "autoConnectFallback": "點擊前往 {path} 管理安裝。", + "autoConnectAppend": "{message},點擊前往 {path} 管理安裝。", + "enableAgentFirstPlaceholder": "請先啟用至少一個 Agent 後開始會話...", + "prepareSessionFailed": "無法準備聊天工作階段,請重試。", + "createConversationFailed": "無法建立會話,請重試。", + "askAnythingPlaceholder": "請開始輸入...", + "agentNotInstalled": "{agent} 尚未安裝 · 點擊前往 Agents 設定安裝", + "agentAdapterNotInstalled": "{agent} 的 ACP 轉接器尚未安裝(與你本機的 CLI 無關)· 點擊前往 Agents 設定安裝" + }, + "welcomePanel": { + "greeting": "今天打算做些什麼呢?", + "tips": { + "tileTabs": "右鍵點擊會話標籤選擇「平鋪顯示」,可同螢幕對比多個會話", + "pinTab": "雙擊會話標籤可將其固定,避免被新開啟的會話自動取代", + "shortcutsNewSearch": "{newConversation} 快速新建會話,{searchConversations} 搜尋歷史會話", + "slashAtMention": "在輸入框輸入 / 觸發斜線命令,輸入 @ 引用專案內檔案", + "pasteDropFiles": "直接貼上截圖或把檔案拖到輸入框,即可作為附件", + "queueMessage": "智能體回覆中也能繼續輸入並排隊,回答完畢會自動續發", + "draftAutoSave": "未發送的草稿會自動儲存,重新開啟會話仍在", + "forkSend": "傳送按鈕旁的下拉選擇「分叉傳送」,從目前位置開一條新分支", + "exportConversation": "右鍵會話內容區可匯出為 Markdown / HTML / 圖片", + "chatChannels": "在「設定 → 聊天頻道」接入 Telegram / 飛書 / 微信,從手機繼續操作", + "shortcutsAuxPanel": "{toggleAuxPanel} 切換右側面板,檢視本次會話改動的檔案與 Git 變更", + "shortcutsTerminalSidebar": "{toggleTerminal} 開啟內建終端機,{toggleSidebar} 切換側邊欄", + "customShortcuts": "所有快捷鍵都可在「設定 → 快捷鍵」中自訂", + "webService": "開啟「設定 → Web 服務」後,團隊成員可從瀏覽器接入同一臺 codeg", + "fusionMode": "開啟檔案或差異後,會自動與會話並排顯示", + "quickMessages": "點輸入框旁的 + 按鈕選擇「快捷訊息」,可一鍵插入預存片段(在「設定 → 快捷訊息」中管理)", + "experts": "透過 + 按鈕裡的「專家技能」可一鍵載入預設角色(除錯 / 規劃等)", + "taskBoard": "「待辦任務」能把一條待辦從頭跑到尾:智能體在獨立工作樹裡執行,你檢視完差異再合併。", + "automations": "「自動化」按排程定時執行儲存好的提示詞(例如每晚一次程式碼審查),還能讓每次執行都開一個獨立工作樹。", + "tokenUsage": "點擊狀態列左下角的會話數即可開啟「Token 用量」,按日期、智能體、模型與資料夾拆分統計。", + "mentionTargets": "@ 不只能引用檔案:還能 @ 另一個智能體把子任務交給它,或引用歷史會話、某次提交、某個技能。", + "splitGroups": "右鍵點擊標籤選擇「向右拆分」或「向下拆分」,兩個會話各佔一個分割區同時開著。", + "worktrees": "點開分支按鈕選「新增工作樹」,多個智能體就能在同一個儲存庫並行工作,互不覆蓋彼此的檔案。", + "importSessions": "之前在終端機裡跑過的會話,用資料夾右鍵選單的「匯入本地會話」就能把那段歷史接進 codeg。", + "subSessions": "智能體委派出去的子會話會巢狀顯示在側邊欄的父會話底下,展開就能追蹤每一個子會話做了什麼。", + "liveFeedback": "「+」選單裡的「即時回饋」能把一則便條塞進智能體正在跑的這一輪,不用打斷它。", + "skillPacks": "設定 → 技能包 裡打包了程式專家、科研與辦公三類技能,可以按智能體分別開關。", + "modelProviders": "設定 → 模型供應商 支援填自己的 API key 或端點位址,之後直接在輸入框裡切換模型。", + "workspaceBackground": "設定 → 外觀 裡可以換工作區背景圖、調面板不透明度,還能換應用程式字型。" + }, + "quickActions": { + "excel": "Excel 活頁簿", + "excelDesc": "資料表、公式與圖表", + "word": "Word 文件", + "wordDesc": "報告、信函與備忘錄", + "ppt": "簡報", + "pptDesc": "專業設計的投影片", + "pitchDeck": "募資簡報", + "pitchDeckDesc": "含關鍵指標的募資簡報", + "morph": "Morph 動畫", + "morphDesc": "電影級投影片轉場", + "morph3d": "3D Morph", + "morph3dDesc": "3D 模型與鏡頭運動", + "academic": "學術論文", + "academicDesc": "含引用與結構的研究論文", + "financial": "財務模型", + "financialDesc": "報表、DCF 與預測", + "dashboard": "資料儀表板", + "dashboardDesc": "從資料產生 KPI 與分析", + "prompts": { + "excel": "建立一個 Excel 活頁簿,需求如下:\n\n[在此描述你的資料、表格、公式與圖表]", + "word": "建立一個 Word 文件,需求如下:\n\n[在此描述文件內容、結構與排版]", + "ppt": "建立一個 PowerPoint 簡報,需求如下:\n\n[在此描述投影片、內容與設計]", + "pitchDeck": "建立一個募資簡報,需求如下:\n\n[在此描述公司、募資輪次與關鍵指標]", + "morph": "建立一個帶 Morph 轉場動畫的簡報:\n\n[在此描述簡報主題與期望的視覺效果]", + "morph3d": "建立一個帶 GLB 模型與鏡頭運動的 3D Morph 簡報:\n\n[在此描述主題與 3D 視覺構想]", + "academic": "用 Word 撰寫一篇學術論文,需求如下:\n\n[在此描述研究主題、方法與主要發現]", + "financial": "用 Excel 建立一個財務模型,需求如下:\n\n[在此描述財務報表、預測與分析]", + "dashboard": "用 Excel 建立一個資料儀表板,需求如下:\n\n[在此描述資料來源、KPI 與圖表]", + "scientific-brainstorming": "幫我進行科研腦力激盪:探索跨學科連結、挑戰假設、發掘有潛力的研究缺口。我正在探索的方向:", + "hypothesis-generation": "幫我把這些觀察轉化為可檢驗的假設:提出明確預測、合理機制,並設計驗證實驗。我的觀察:", + "experimental-design": "在蒐集資料前幫我設計嚴謹的實驗:設計方案、隨機化、對照,以及如何避免干擾。我想研究的問題:", + "statistical-power": "幫我確定所需樣本數:為我的設計做檢定力分析(效應量、顯著水準、檢定力)。具體資訊:", + "statistical-analysis": "幫我正確分析這份資料:選擇合適的檢定、檢查假設、報告效應量並撰寫結論。我的資料與問題:", + "exploratory-data-analysis": "對我的資料檔案做探索性分析:概述其結構、品質與值得注意的模式,並建議後續步驟。檔案是:", + "scientific-visualization": "幫我製作出版級圖表:清晰佈局、真實誤差棒、色盲友善配色,以及期刊格式。我想展示的內容:", + "scientific-critical-thinking": "幫我批判性評估這項研究或主張:評估證據品質、辨識偏誤與干擾,並權衡結論。內容如下:", + "paper-lookup": "幫我在學術資料庫中查找相關論文與開放取用全文,並提供可重用的引用。我要找的是:" + }, + "paper-lookup": "論文檢索", + "paper-lookupDesc": "檢索 10 個學術 API(PubMed、arXiv、OpenAlex、Crossref…)查找論文、引用與開放取用全文。", + "scientific-critical-thinking": "批判性思維", + "scientific-critical-thinkingDesc": "評估科學主張與證據品質:辨識偏誤與干擾,運用 GRADE 與偏誤風險框架。", + "scientific-visualization": "科學視覺化", + "scientific-visualizationDesc": "出版級圖表:多面板佈局、顯著性標註與期刊專屬格式。", + "exploratory-data-analysis": "探索性資料分析", + "exploratory-data-analysisDesc": "對 200+ 種格式的科學資料檔案做自動化探索,輸出品質指標與報告。", + "statistical-analysis": "統計分析", + "statistical-analysisDesc": "引導式統計分析:檢定選擇、假設檢查、效應量與 APA 格式報告。", + "statistical-power": "統計檢定力", + "statistical-powerDesc": "樣本數與統計檢定力分析:所需樣本數、最小可檢測效應與檢定力曲線。", + "experimental-design": "實驗設計", + "experimental-designDesc": "在蒐集資料前設計嚴謹研究:隨機化、區集、對照與析因/DOE 佈局。", + "hypothesis-generation": "假設生成", + "hypothesis-generationDesc": "將觀察轉化為可檢驗的假設,提出預測、機制並設計驗證實驗。", + "scientific-brainstorming": "科學腦力激盪", + "scientific-brainstormingDesc": "開放式科研構思:探索跨學科連結、挑戰假設、發掘研究缺口。", + "tabs": { + "office": "日常辦公", + "coding": "程式開發", + "research": "科學研究" + }, + "coding": { + "brainstormingDesc": "動手前先梳理意圖與需求", + "debuggingDesc": "先定位根因再提出修復", + "writingSkillsDesc": "建立、編輯並驗證可重用技能" + }, + "notEnabled": { + "title": "「{skill}」技能尚未對 {agent} 啟用", + "description": "前往設定啟用後即可在此使用。", + "action": "前往啟用", + "hint": "技能未啟用" + }, + "scrollPrev": "顯示上一組技能", + "scrollNext": "顯示下一組技能" + } + }, + "agentSelector": { + "noEnabledAgents": "暫無已啟用的 Agent", + "openAgentsSettings": "開啟 Agents 設定", + "notInstalled": "未安裝", + "moreAgents": "更多 Agent({count})" + }, + "subAgentOverlay": { + "title": "子智能體", + "collapsedSummary": "子智能體 {count}", + "collapseAria": "摺疊子智能體" + }, + "agentPlanOverlay": { + "title": "計畫任務", + "collapsePlanAria": "摺疊計畫", + "collapsedSummary": "計畫 {completed}/{total}", + "status": { + "completed": "已完成", + "inProgress": "進行中", + "pending": "待處理", + "unknown": "未知" + }, + "priority": { + "high": "高", + "medium": "中", + "low": "低", + "unknown": "未知" + } + }, + "permissionDialog": { + "subtitle": "Agent 請求繼續目前輪次的權限。", + "queuedCount": "還有 {count} 項待審批", + "kindFallbackTool": "工具", + "command": "命令", + "cwd": "工作目錄:{cwd}", + "filesSummary": "檔案:{count}", + "moreFiles": "+{count} 個更多檔案", + "plan": "計畫", + "allowedActions": "允許的操作", + "targetMode": "目標模式:{mode}", + "optionGrants": "各選項將授予的權限", + "changeScopeSession": "本次工作階段", + "changeScopeProcess": "本次執行", + "changeScopeUser": "儲存至使用者設定", + "changeScopeProject": "儲存至專案設定", + "changeScopeProjectLocal": "儲存至本機專案設定", + "changeScopePersistent": "永久儲存" + }, + "questionDialog": { + "title": "代理正在提問", + "placeholder": "輸入你的回答...", + "send": "傳送" + }, + "messageBranch": { + "previousBranchAria": "上一個分支", + "nextBranchAria": "下一個分支", + "pageOf": "{current} / {total}" + }, + "terminal": { + "title": "終端", + "running": "執行中" + }, + "reasoning": { + "thinking": "思考中…", + "thoughtForFewSeconds": "思考", + "thoughtForSeconds": "思考" + }, + "linkSafety": { + "errorCannotOpen": "無法開啟本地檔案", + "errorNoWorkspace": "目前沒有活躍的工作區資料夾。", + "errorFailedOpen": "開啟本地檔案失敗", + "errorFailedLink": "開啟連結失敗", + "errorUnsupportedLinkProtocol": "不支援此連結協議。" + }, + "fileActions": { + "openInFinder": "在 Finder 開啟", + "openInExplorer": "在檔案總管開啟", + "openInFileManager": "在檔案管理器開啟", + "copyRelativePath": "複製相對路徑", + "copyAbsolutePath": "複製絕對路徑", + "pathCopied": "已複製路徑", + "copyPathFailed": "複製路徑失敗", + "openFailed": "開啟本地檔案失敗" + }, + "messageList": { + "attachedResources": "附加資源", + "loading": "載入中...", + "loadEarlier": "載入更早的訊息", + "loadingEarlier": "正在載入更早的訊息…", + "error": "錯誤:{message}", + "errorTitle": "會話載入失敗", + "errorActionReload": "重新載入", + "errorActionNewSession": "新建會話", + "emptyConversation": "目前會話暫無訊息。", + "systemMessage": "系統訊息", + "copyMessage": "複製", + "copied": "已複製", + "downloadImage": "下載圖片", + "downloadFailed": "下載失敗:{message}", + "imageGeneration": "圖片生成", + "imageGenerationPending": "正在生成圖片…", + "imageGenerationFailed": "圖片生成失敗", + "model": "模型", + "tokenStats": "Token 使用情況", + "tokenInput": "輸入", + "tokenOutput": "輸出", + "tokenCacheRead": "快取讀取", + "tokenCacheWrite": "快取寫入", + "duration": "耗時", + "completedAt": "完成時間", + "jumpToPreviousUserMessage": "跳轉到上一條使用者訊息", + "showMore": "展開", + "showLess": "收合" + }, + "liveTurnStats": { + "thinking": "思考中...", + "streaming": "生成中", + "elapsedHours": "{value} 小時", + "elapsedMinutes": "{value} 分鐘", + "elapsedSeconds": "{value} 秒", + "outputSpeedAria": "估算輸出速度", + "outputSpeedTooltip": "估算輸出速度(正文 + 思考)" + }, + "jsonTree": { + "viewRaw": "檢視原始 JSON", + "viewTree": "檢視樹狀檢視", + "fields": "{count} 個欄位", + "items": "{count} 項" + }, + "tool": { + "parameters": "參數", + "error": "錯誤", + "result": "結果", + "status": { + "approvalRequested": "等待授權", + "approvalResponded": "已回應", + "inputAvailable": "執行中", + "inputStreaming": "等待中", + "outputAvailable": "已完成", + "outputDenied": "已拒絕", + "outputError": "錯誤" + } + }, + "toolCallBlock": { + "tool": "工具", + "error": "錯誤", + "result": "結果" + }, + "delegation": { + "subAgentRunning": "子代理執行中…", + "noDetail": "暫無詳情。", + "unknownAgent": "子智慧體", + "openDetail": "檢視會話", + "detailTitle": "子智慧體會話", + "detailDescription": "唯讀檢視委派給子智慧體的會話內容。", + "waitForResult": "等待 {task} 任務執行結果", + "waitForResultNoTask": "等待任務執行結果", + "cancelTask": "取消 {task} 任務", + "cancelTaskNoTask": "取消任務", + "resultPageOf": "{current} / {total}", + "prevResult": "上一個結果", + "nextResult": "下一個結果", + "noResultText": "本次檢查暫無結果", + "status": { + "starting": "啟動中", + "running": "執行中", + "checked": "已查詢", + "waiting": "待批准", + "ok": "完成", + "err": { + "default": "失敗", + "delegation_disabled": "已停用", + "depth_limit": "深度超限", + "invalid_agent_type": "代理類型無效", + "spawn_failed": "啟動失敗", + "send_failed": "傳送失敗", + "timeout": "逾時", + "canceled": "已取消", + "child_refusal": "子代理拒絕", + "child_max_tokens": "子代理超出 token 上限", + "child_max_turn_requests": "子代理超出請求上限", + "child_empty": "子代理無回應", + "child_unknown": "子代理未知錯誤", + "unknown": "未知任務" + } + } + }, + "contentParts": { + "showingTailOutput": "為確保效能,串流輸出時僅顯示尾端內容。", + "result": "結果", + "unknown": "未知", + "inputTruncated": "輸入已截斷,diff 可能不完整。", + "replaceAll": "全部替換", + "filesCount": "檔案:{count}", + "update": "更新", + "moreFiles": "+{count} 個更多檔案", + "timeoutMs": "逾時:{timeout}ms", + "backgroundTrue": "背景:true", + "scriptToolCalls": "呼叫 {count} 個工具", + "offset": "位移:{offset}", + "limit": "限制:{limit}", + "pages": "頁碼:{pages}", + "mode": "模式:{mode}", + "cell": "儲存格:{cell}", + "shellSession": "工作階段 {id}", + "pathLabel": "路徑:", + "globLabel": "Glob:", + "typeLabel": "類型:", + "outputLabel": "輸出:", + "caseInsensitive": "不區分大小寫", + "multiline": "多行", + "promptLabel": "提示詞", + "subjectLabel": "主題", + "taskLabel": "任務", + "nameLabel": "名稱:", + "agentPromptLabel": "提示詞", + "agentModelLabel": "模型", + "agentRunning": "執行中...", + "agentLiveTranscript": "即時活動", + "agentProgressTools": "{count} 次工具調用", + "agentProgressTurns": "{count} 輪", + "agentProgressContext": "上下文 {pct}%", + "agentSessionAction": "檢視子智慧體工作階段", + "agentSessionTitle": "子智慧體工作階段", + "agentSessionLoading": "正在載入子智慧體的對話記錄…", + "agentSessionEmpty": "子智慧體尚未寫入任何內容。", + "agentFallbackTitle": "子智能體啟動中…", + "agentCodexLaunchOnly": "已啟動。Codex 不會再回報這個子智能體的進度——它的結果會以一則訊息出現在本工作階段中。", + "agentStatsBash": "命令", + "agentStatsRead": "讀取檔案", + "agentStatsSearch": "搜尋", + "agentStatsEdit": "編輯", + "agentStatsOther": "其他", + "goal": { + "title": "目標:", + "titleWithStatus": "目標{status}", + "objective": "目標", + "statusLabel": "狀態", + "tokensUsed": "已用 tokens", + "budget": "預算", + "remaining": "剩餘", + "elapsed": "耗時", + "tokens": "tokens", + "pause": "暫停", + "clear": "清除", + "status": { + "active": "進行中", + "paused": "已暫停", + "blocked": "受阻", + "usageLimited": "用量受限", + "budgetLimited": "預算受限", + "complete": "已完成", + "limited": "已達上限" + } + }, + "field": { + "file": "檔案", + "notebook": "筆記本", + "command": "命令", + "old": "舊內容", + "new": "新內容", + "pattern": "模式", + "path": "路徑", + "query": "查詢", + "url": "URL 位址", + "description": "描述", + "content": "內容", + "source": "來源內容", + "prompt": "提示詞", + "subject": "主題", + "taskId": "任務 ID", + "status": "狀態", + "skill": "Skill", + "args": "參數", + "offset": "位移", + "limit": "限制", + "glob": "Glob", + "type": "類型", + "output": "輸出", + "replaceAll": "全部替換", + "language": "語言", + "timeout": "逾時", + "background": "背景", + "agentType": "Agent 類型", + "library": "函式庫", + "libraryId": "函式庫 ID" + }, + "title": { + "edit": "編輯", + "command": "命令", + "script": "腳本", + "waitCommand": "等待 {command}", + "waitCell": "等待工作階段 {id}", + "terminateCommand": "終止 {command}", + "terminateCell": "終止工作階段 {id}", + "stdinChars": "輸入 {chars}", + "todoWrite": "待辦", + "read": "讀取", + "write": "寫入", + "notebookEdit": "Notebook 編輯", + "editFiles": "編輯({count} 個檔案)", + "editWithTarget": "編輯 {target}", + "readWithTarget": "讀取 {target}", + "writeWithTarget": "寫入 {target}", + "notebookEditWithTarget": "Notebook 編輯 {target}", + "globWithPattern": "Glob {pattern}", + "listFilesWithPath": "列出檔案 {path}", + "grepWithPattern": "Grep {pattern}", + "taskCreateWithSubject": "建立任務:{subject}", + "taskUpdateWithStatus": "更新任務 #{id} -> {status}", + "taskUpdate": "更新任務 #{id}", + "webFetchWithUrl": "擷取網頁 {url}", + "webSearchWithQuery": "網頁搜尋:{query}", + "todosProgress": "待辦({done}/{total})", + "skillWithName": "Skill:{name}", + "genericWithContext": "{tool}:{context}" + }, + "search": { + "noMatches": "無相符結果", + "matchSummary": "{matches} 處相符 · {files} 個檔案", + "fileSummary": "{files} 個檔案", + "moreResults": "另有 {count} 筆結果未顯示" + }, + "toolGroup": { + "search": "搜尋 {count} 次", + "command": "執行 {count} 個指令", + "read": "讀取 {count} 次檔案", + "memory": "回憶 {count} 項記憶", + "edit": "編輯 {count} 次檔案", + "fetch": "抓取 {count} 個資源", + "think": "思考 {count} 次", + "todo": "更新 {count} 項待辦", + "task": "執行 {count} 個任務", + "other": "呼叫 {count} 個工具", + "errorSuffix": "{count} 個失敗", + "joiner": " · " + }, + "planMode": { + "entered": "進入計畫模式", + "planLabel": "計畫", + "reviewApproved": "已核准執行計畫", + "reviewKept": "維持在計畫模式", + "reviewPending": "等待計畫決定", + "submitted": "計畫已提交", + "switched": "切換模式" + }, + "backgroundTask": { + "title": "背景任務", + "titleWithId": "背景任務 · {id}", + "running": "執行中", + "completed": "已完成", + "failed": "失敗", + "stopped": "已停止", + "exitCode": "退出碼 {code}", + "polledTimes": "輪詢 {count} 次", + "runningInBackground": "背景執行", + "launchNote": "已在背景執行 · {id}" + }, + "codexScript": { + "outputMissing": "codex 截斷指令碼輸出時捨棄了這個命令的分隔行,因此沒有輸出可歸屬給它。", + "sharedWith": "本段還包含 {commands} 的輸出——它們的分隔行已被 codex 截斷捨棄。", + "truncated": "已截斷" + } + }, + "messageNav": { + "title": "訊息導覽", + "collapse": "收合訊息導覽", + "collapsedSummary": "訊息 {count}", + "fileCount": "{count} 個檔案", + "remove": "移除", + "noDiffDataAvailable": "找不到 {filePath} 的差異資料" + }, + "replyArtifacts": { + "title": "變更檔案", + "fileCount": "{count} 個檔案", + "newFilesTitle": "新增檔案", + "revealInFolder": "在 Finder/檔案總管中顯示", + "openFile": "開啟 {filePath}", + "openInEditor": "在編輯器中開啟", + "remove": "移除", + "noDiffDataAvailable": "找不到 {filePath} 的差異資料" + }, + "askQuestion": { + "title": "智能體需要你的選擇", + "subtitle": "回答後點擊提交,可隨時跳過", + "recommended": "推薦", + "other": "其他", + "otherPlaceholder": "輸入你的回答…", + "singleSelect": "單選", + "multiSelect": "多選", + "skip": "略過", + "next": "下一題", + "submit": "提交", + "submitError": "提交失敗,請重試。" + }, + "planApproval": { + "title": "智慧代理已提出計畫——請審閱", + "emptyPlan": "智慧代理未寫入計畫。可核准開始實作,或要求修改。", + "approve": "核准並開始", + "requestChanges": "要求修改", + "abandon": "放棄", + "feedbackPlaceholder": "需要修改什麼?", + "sendChanges": "傳送", + "cancel": "取消", + "submitError": "提交失敗,請重試。" + }, + "feedbackCheckResult": { + "count": "{count} 則回饋", + "expand": "展開全部回饋", + "collapse": "收合", + "errorTitle": "回饋檢查失敗" + }, + "askQuestionResult": { + "title": "提問", + "answeredLabel": "提問回答:", + "awaiting": "等待你的回答…", + "declined": "你已略過此問題 — 代理已自行判斷。", + "noSelection": "未選擇" + }, + "configStale": { + "agentConfigTitle": "智能體設定已更新", + "modelProviderTitle": "模型供應商已更新", + "description": "目前的工作階段仍在使用舊設定,重新連線後生效(對話紀錄不會遺失)。", + "reconnect": "重新連線以套用", + "reconnecting": "正在重新連線…", + "reconnectDisabledDuringTurn": "目前回合結束後可重新連線", + "dismiss": "忽略", + "reconnectFailed": "重新連線工作階段失敗", + "applied": "已套用新設定" + }, + "piProjectTrust": { + "title": "此專案自帶 pi 資源", + "description": "pi 未載入儲存庫自帶的 .pi 檔案。請檢視後決定。", + "descriptionExecutable": "儲存庫自帶 pi 擴充功能,擴充功能會在啟動時執行程式碼。pi 尚未載入它們,請先檢視再決定。", + "review": "檢視…", + "dismiss": "忽略", + "dialogTitle": "信任此專案的 pi 資源?", + "dialogDescription": "只有在你信任該目錄後,pi 才會載入儲存庫自帶的 .pi 檔案。請僅在你信任此儲存庫內容時才信任。", + "executionWarning": "擴充功能就是程式碼。信任該目錄後,儲存庫中的擴充功能會在 pi 啟動時以你的權限執行——早於你送出任何訊息。", + "scopeNote": "此決定儲存在 pi 的 trust.json 中,對該目錄下的所有子目錄同樣生效,你在終端機自行執行 pi 時也會沿用。之後可在「設定 → 智慧代理 → Pi」中修改。", + "trust": "信任專案", + "decline": "保持不載入", + "disabledDuringTurn": "目前回合結束後可用", + "trustedToast": "已信任專案——已重新連線以便 pi 載入其資源", + "declinedToast": "專案資源保持不載入", + "saveFailed": "儲存專案信任決定失敗", + "grantTitle": "此專案已被信任", + "grantDescription": "pi 會載入此儲存庫自帶的 .pi 檔案。請檢視這代表什麼。", + "grantInheritedDescription": "某個上層目錄已被信任,因此 pi 會載入此儲存庫自帶的 .pi 檔案。請檢視這代表什麼。", + "grantDialogTitle": "此專案的 pi 資源已被信任", + "grantDialogDescription": "pi 被允許載入此儲存庫自帶的 .pi 檔案。舊版 codeg 會在你開啟目錄時自動授予此權限,因此你可能從未被詢問過。", + "grantExecutionWarning": "擴充功能就是程式碼。儲存庫中的擴充功能會在 pi 啟動時以你的權限執行——早於你送出任何訊息。", + "inheritedFrom": "信任來自", + "revoke": "撤銷信任", + "keepTrusted": "保持信任", + "revokedToast": "已撤銷信任——已重新連線,pi 不再載入此專案的資源", + "trustedNoReconnect": "已信任專案——將在 pi 下次啟動時生效", + "revokedNoReconnect": "已撤銷信任——將在 pi 下次啟動時生效" + }, + "collabAgent": { + "title": "子智能體", + "errorTitle": "子智能體任務失敗", + "statesLabel": "子智能體", + "statusRunning": "執行中", + "statusCompleted": "已完成", + "statusFailed": "失敗", + "statusPending": "初始化中", + "statusInterrupted": "已中斷", + "statusClosed": "已關閉", + "statusNotFound": "未找到", + "opSpawn": "啟動子智能體", + "opWait": "取得子智能體結果", + "opClose": "結束子智能體", + "opResume": "恢復子智能體" + }, + "contextCompaction": { + "compacting": "正在壓縮上下文…", + "compacted": "上下文已壓縮", + "compactedTokens": "上下文已壓縮 · {before} → {after} tokens", + "failed": "上下文壓縮失敗" + }, + "sessionFailure": { + "category": { + "connection": "連線異常", + "access": "存取受限", + "limit": "已達限制", + "request": "請求被拒絕", + "service": "服務異常", + "unknown": "會話異常" + }, + "action": { + "retry": "重試", + "login": "去登入", + "newSession": "新增會話" + }, + "recovered": "已恢復", + "retryUnavailable": "沒有可重發的訊息。", + "toggleDetails": "展開/收合詳情" + }, + "backgroundTasks": { + "running": "{count} 個背景任務執行中", + "settling": "正在同步背景結果…", + "settledFallback": "背景任務已結束({status})", + "cardRunning": "背景執行中", + "cardLaunchedPending": "已啟動背景任務", + "cardCompleted": "背景任務已完成", + "cardFinishedWithStatus": "背景任務已結束({status})", + "cardResultPending": "結果尚未返回" + }, + "proposedPlan": { + "title": "計劃提案", + "planning": "規劃中…" + } + }, + "diffPreview": { + "mode": { + "added": "新增", + "deleted": "刪除", + "renamed": "重新命名", + "modified": "修改" + }, + "hunkLabel": "區塊 {index}", + "loadingHunk": "正在載入區塊...", + "noDiffData": "無差異資料", + "showRemainingLines": "顯示剩餘 {count} 行" + }, + "conversationContextBar": { + "folderTitle": "工作資料夾", + "branchTitle": "工作分支", + "searchFolder": "Search folder...", + "searchBranch": "Search branch...", + "noFolders": "No folders", + "noBranches": "No branches", + "noBranch": "(no branch)", + "chatModeLabel": "聊天模式", + "commit": "Commit", + "push": "Push", + "merge": "Merge", + "toasts": { + "folderChanged": "Switched to {name}", + "openFolderFailed": "Failed to open folder", + "switchedToChatMode": "已切換到聊天模式", + "openStashFailed": "Failed to open stash window", + "openMergeFailed": "Failed to open merge window" + } + }, + "cloneDialog": { + "title": "複製倉庫", + "repositoryUrl": "倉庫地址", + "repositoryUrlPlaceholder": "https://github.com/user/repo.git", + "directory": "目錄", + "directoryPlaceholder": "選擇目標目錄...", + "browseDirectory": "瀏覽目錄", + "cancel": "取消", + "clone": "複製", + "clonePath": "克隆路徑: {path}" + }, + "toasts": { + "cloneFailed": "複製倉庫失敗" + } + }, + "ProjectBoot": { + "title": "專案啟動器", + "tabs": { + "shadcn": "shadcn", + "hyperframes": "HyperFrames" + }, + "hyperframes": { + "title": "HyperFrames 影片專案", + "subtitle": "建立一個 HTML 轉影片專案,接著工作區的智慧代理即可撰寫並算繪它。", + "resolution": "解析度", + "skillsTitle": "智慧代理技能", + "skillsDesc": "為所選代理全域安裝 HyperFrames 技能(符號連結),讓它們會編寫並算繪影片。", + "recheck": "重新檢查", + "installedBadge": "已安裝", + "skillsInstall": "安裝 / 更新技能", + "skillsInstalling": "正在安裝技能…", + "skillsInstalled": "HyperFrames 技能安裝成功", + "skillsInstallFailed": "HyperFrames 技能安裝失敗" + }, + "config": { + "base": "基礎庫", + "style": "風格", + "baseColor": "基礎顏色", + "theme": "主題", + "chartColor": "圖表顏色", + "iconLibrary": "圖示庫", + "font": "字體", + "fontHeading": "標題字體", + "menuAccent": "選單強調", + "menuColor": "選單顏色", + "radius": "圓角", + "template": "模板", + "createProject": "建立專案", + "sectionStyle": "風格", + "sectionColors": "配色", + "sectionTypography": "排版", + "sectionInterface": "介面" + }, + "preview": { + "loading": "載入預覽..." + }, + "createDialog": { + "title": "建立專案", + "projectName": "專案名稱", + "projectNamePlaceholder": "my-app", + "frameworkTemplate": "框架模板", + "packageManager": "套件管理器", + "saveDirectory": "儲存目錄", + "saveDirectoryPlaceholder": "選擇目錄...", + "browseDirectory": "瀏覽", + "projectPath": "專案將建立在:{path}", + "advancedOptions": "進階選項", + "base": "基礎庫", + "enableRtl": "啟用 RTL 支援", + "enableRtlDescription": "為從右到左書寫的語言(如阿拉伯語、希伯來語)啟用佈局支援", + "pmChecking": "正在檢測...", + "pmNotInstalled": "未安裝", + "cancel": "取消", + "create": "建立", + "creating": "正在建立專案..." + }, + "toasts": { + "createFailed": "建立專案失敗", + "createSuccess": "專案建立成功", + "openWorkspaceFailed": "專案已建立,但無法在工作區中開啟" + }, + "errors": { + "directoryExists": "目標目錄已存在", + "commandFailed": "專案建立命令執行失敗。" + } + }, + "WebServiceSettings": { + "addressSwitchHint": "切換只會改變這裡顯示與開啟的位址;服務會監聽所有網路介面,每個位址都可存取。", + "sectionTitle": "Web 服務", + "sectionDescription": "啟用後可透過瀏覽器遠端存取 Codeg", + "port": "連接埠", + "status": "狀態", + "autoStart": "自動啟動", + "autoStartHint": "Codeg 啟動時自動開啟 Web 服務", + "running": "執行中", + "stopped": "已停止", + "processing": "處理中...", + "start": "啟動", + "stop": "停止", + "startFailed": "啟動失敗", + "stopFailed": "停止失敗", + "saveConfigFailed": "儲存 Web 服務設定失敗", + "open": "開啟", + "hide": "隱藏", + "show": "顯示", + "copy": "複製", + "qrcode": "QR 碼", + "qrcodeTitle": "掃碼開啟", + "qrcodeHint": "用手機掃描,在瀏覽器中開啟 Codeg", + "addressLabel": "存取位址", + "tokenLabel": "存取 Token", + "tokenHint": "Web 用戶端首次存取時需輸入此 Token", + "tokenPlaceholder": "留空則自動產生", + "regenerate": "重新產生", + "stalePortOccupiedTitle": "連接埠 {port} 已被其他行程佔用", + "stalePortUnknownTitle": "連接埠 {port} 狀態不明", + "stalePortHint": "在連接埠釋放前 Codeg 無法繫結。可以更換上方的連接埠,或結束佔用該連接埠的行程。", + "errors": { + "alreadyRunning": "Web 服務已在執行", + "invalidAddress": "主機或連接埠格式無效", + "portInUse": "連接埠 {port} 已被佔用,請關閉佔用的程式或改用其他連接埠", + "permissionDenied": "權限不足,請使用 1024 以上的連接埠,或以更高權限執行", + "addressUnavailable": "該位址在本機不可用", + "bindFailed": "綁定位址失敗" + } + }, + "DirectoryBrowser": { + "title": "瀏覽目錄", + "pathPlaceholder": "輸入目錄路徑...", + "goHome": "回到主目錄", + "navigateUp": "返回上層目錄", + "select": "選擇", + "cancel": "取消", + "loading": "載入中...", + "emptyDirectory": "此目錄為空", + "errorLoadingDir": "載入目錄失敗", + "permissionDenied": "權限不足" + }, + "ChatChannelSettings": { + "loading": "載入中...", + "sectionTitle": "訊息頻道", + "sectionDescription": "設定 IM 機器人,接收事件通知和查詢編碼活動。", + "addChannel": "新增頻道", + "noChannels": "尚未設定任何訊息頻道。", + "channelName": "名稱", + "channelNamePlaceholder": "我的 Telegram 機器人", + "channelType": "頻道類型", + "lark": "飛書", + "weixin": "微信", + "dailyReport": "每日報告", + "dailyReportTime": "推送時間", + "nameRequired": "請輸入頻道名稱。", + "tokenRequired": "請輸入 Token。", + "chatIdRequired": "請輸入 Chat ID。", + "topicMode": "話題群模式", + "topicModeHint": "將 Telegram forum topics 路由為獨立 Codeg 對話。Bot 必須加入 forum supergroup,並擁有管理 topics 權限。", + "loadFailed": "載入頻道失敗。", + "saveFailed": "儲存失敗。", + "connectSuccess": "頻道已連線。", + "connectFailed": "連線失敗", + "disconnectSuccess": "頻道已斷線。", + "disconnectFailed": "斷線失敗。", + "testSuccess": "連線測試通過。", + "testFailed": "連線測試失敗", + "deleteSuccess": "頻道已刪除。", + "deleteFailed": "刪除頻道失敗。", + "deleteConfirmTitle": "刪除頻道", + "deleteConfirmMessage": "將永久刪除該頻道及其訊息紀錄,確定嗎?", + "cancel": "取消", + "delete": "刪除", + "create": "建立", + "save": "儲存", + "channelListTitle": "已設定頻道", + "channelListDescription": "已啟用的頻道在服務啟動時會自動連線。", + "editChannel": "編輯頻道", + "editSuccess": "頻道已更新。", + "tokenPlaceholderKeep": "留空保持不變", + "weixinScanTitle": "掃碼登入", + "weixinScanDescription": "打開微信掃描二維碼以連接。", + "weixinQrcodeExpired": "二維碼已過期。", + "weixinRefreshQrcode": "重新整理", + "weixinWaitingScan": "等待掃碼...", + "weixinPollError": "連接不穩定,正在重試...", + "weixinReconnectNotice": "因 iLink 協議限制,每次重新連接後需先主動向機器人發送一條訊息,事件觸發才會生效。", + "connect": "連線", + "disconnect": "斷開", + "test": "測試連線", + "tabs": { + "channels": "頻道", + "commands": "指令", + "events": "事件", + "other": "其他" + }, + "commands": { + "title": "內建指令", + "description": "訊息頻道中可用的 Bot 指令。群組聊天中需 @Bot 才會處理訊息。", + "prefixLabel": "指令前綴", + "prefixDescription": "觸發 Bot 指令的前綴,1-3 個非字母數字字元(預設 /)。", + "prefixSaved": "指令前綴已儲存。", + "prefixSaveFailed": "儲存指令前綴失敗。", + "prefixInvalid": "前綴必須是 1-3 個非字母數字字元。", + "save": "儲存", + "folderDesc": "選擇工作目錄", + "agentDesc": "選擇 AI Agent", + "taskDesc": "建立會話並執行任務", + "sessionsDesc": "列出當前目錄的活躍會話", + "resumeDesc": "最近對話 / 恢復指定對話", + "cancelDesc": "取消當前任務", + "approveDesc": "批准 Agent 權限請求", + "denyDesc": "拒絕 Agent 權限請求", + "searchDesc": "依關鍵字搜尋對話", + "todayDesc": "今日活動摘要", + "statusDesc": "頻道連線狀態", + "helpDesc": "顯示說明" + }, + "events": { + "title": "事件通知", + "description": "啟用事件後,事件被觸發時將推送到頻道。", + "turnComplete": "對話完成", + "turnCompleteDesc": "代理回合結束時", + "error": "代理錯誤", + "errorDesc": "代理遇到錯誤時", + "permissionRequest": "權限請求", + "permissionRequestDesc": "智慧代理請求操作權限時", + "questionRequest": "智慧代理提問", + "questionRequestDesc": "當智慧代理向你提問時", + "userPromptSent": "使用者訊息", + "userPromptSentDesc": "當你傳送訊息時——通知中會包含訊息內容", + "saved": "事件篩選已更新。", + "saveFailed": "儲存事件篩選失敗。", + "loadFailed": "載入設定失敗。", + "retry": "重試", + "webhooksTitle": "Webhook", + "webhooksDescription": "事件觸發時,向一個或多個位址 POST 一份 JSON。上方的事件篩選同樣作用於 Webhook。", + "webhookUrlPlaceholder": "https://example.com/webhook", + "addWebhook": "新增 Webhook", + "removeWebhook": "刪除 Webhook", + "webhookSave": "儲存", + "webhooksSaved": "Webhook 已儲存。", + "webhooksSaveFailed": "儲存 Webhook 失敗。", + "webhookInvalidUrl": "請輸入有效的 http(s) 位址。", + "docsTitle": "請求格式", + "docsMethod": "請求方式", + "docsContentType": "內容類型", + "docsNote": "每個啟用的事件都會投遞到所有位址。Webhook 不做去抖;上方的事件篩選仍然生效。", + "editWebhook": "編輯 Webhook", + "enableWebhook": "啟用 Webhook", + "webhookDuplicate": "該位址已設定。", + "cancel": "取消", + "webhooksEmpty": "尚未設定 Webhook。", + "deleteWebhookTitle": "刪除 Webhook", + "deleteWebhookMessage": "刪除此 Webhook?事件將不再傳送到該網址。", + "delete": "刪除" + }, + "language": { + "title": "訊息語言", + "description": "事件通知、指令回應和每日報告推送到訊息頻道時使用的語言。", + "saved": "訊息語言已儲存。", + "saveFailed": "儲存訊息語言失敗。", + "en": "英語", + "zh-cn": "簡體中文", + "zh-tw": "繁體中文", + "ja": "日語", + "ko": "韓語", + "es": "西班牙語", + "de": "德語", + "fr": "法語", + "pt": "葡萄牙語", + "ar": "阿拉伯語" + } + }, + "ModelProviderSettings": { + "sectionTitle": "模型供應商", + "sectionDescription": "管理 Agent 的 API 供應商憑據。", + "filterAll": "全部", + "providerListTitle": "已配置的供應商", + "addProvider": "新增供應商", + "editProvider": "編輯供應商", + "noProviders": "尚未配置模型供應商。", + "providerName": "名稱", + "providerNamePlaceholder": "例如 OpenAI、Anthropic", + "apiUrl": "API 位址", + "apiUrlPlaceholder": "https://api.openai.com/v1", + "apiKey": "API 金鑰", + "apiKeyPlaceholder": "sk-...", + "apiKeyKeepCurrent": "留空則保持不變", + "agentTypes": "代理類型", + "agentTypesRequired": "至少選擇一個代理類型。", + "agentType": "智能體類型", + "agentTypeRequired": "請選擇智能體類型。", + "agentTypeImmutableHint": "智能體類型建立後不可修改。", + "model": "模型", + "modelPlaceholderCodex": "gpt-5.6-sol / gpt-5.5", + "modelPlaceholderGemini": "gemini-3-pro-preview", + "claudeMainModel": "主要模型", + "claudeReasoningModel": "推理模型(思考)", + "claudeHaikuDefaultModel": "預設 Haiku 模型", + "claudeSonnetDefaultModel": "預設 Sonnet 模型", + "claudeOpusDefaultModel": "預設 Opus 模型", + "claudeCustomModelOption": "自訂模型 ID", + "claudeCustomModelOptionName": "自訂模型名稱", + "claudeCustomModelOptionDescription": "自訂模型描述", + "claudeCustomModelOptionHint": "在 Claude 模型選擇器中新增一個自訂項目(例如透過自訂閘道/代理提供的模型)。名稱與描述為選填的顯示資訊。", + "nameRequired": "供應商名稱不能為空。", + "apiUrlRequired": "API 位址不能為空。", + "apiKeyRequired": "API 金鑰不能為空。", + "loadFailed": "載入供應商失敗。", + "saveFailed": "儲存變更失敗。", + "createSuccess": "供應商已建立。", + "editSuccess": "供應商已更新。", + "deleteSuccess": "供應商已刪除。", + "deleteConfirmTitle": "刪除供應商", + "deleteConfirmMessage": "確定要永久刪除供應商「{name}」嗎?", + "deleteBlockedByAgent": "{agents} 正在使用此設定,請先解除關聯後再刪除。", + "cancel": "取消", + "delete": "刪除", + "create": "建立", + "save": "儲存", + "affectedRunningSessions": "{count} 個進行中的工作階段需重新連線以套用變更" + }, + "SkillMatrix": { + "loading": "載入中…", + "searchPlaceholder": "依名稱、ID 或描述搜尋", + "empty": "暫無內容。", + "emptySearch": "沒有符合目前搜尋的結果。", + "skillColumn": "技能", + "selectAll": "全選可見項目", + "selectSkill": "選擇 {name}", + "everything": { + "label": "批次", + "enable": "全部啟用(可見)", + "disable": "全部停用(可見)" + }, + "columnMenu": { + "enableAll": "啟用全部技能", + "disableAll": "停用全部技能" + }, + "rowMenu": { + "label": "對 {name} 批次操作", + "enableAll": "對所有 agent 啟用", + "disableAll": "對所有 agent 停用" + }, + "bulk": { + "selected": "已選擇 {count} 項", + "targetAll": "全部 agent", + "targetSome": "{count} 個 agent", + "enable": "啟用", + "disable": "停用", + "clear": "清除" + }, + "confirm": { + "disableTitle": "停用這些連結?", + "disableBody": "這將移除 {count} 個由 codeg 管理的技能連結。佔用自訂目錄的技能不受影響。你可以隨時重新啟用。", + "cancel": "取消", + "confirm": "停用" + }, + "toasts": { + "loadFailed": "載入技能狀態失敗", + "applyFailed": "套用變更失敗", + "enabled": "已啟用 {count} 個連結", + "disabled": "已停用 {count} 個連結", + "enabledPartial": "已啟用 {ok} 個,{failed} 個失敗", + "disabledPartial": "已停用 {ok} 個,{failed} 個失敗" + }, + "detail": { + "enableForAgents": "為 agent 啟用", + "preview": "SKILL.md 預覽", + "loadingContent": "載入內容中…" + }, + "copyModeHint": "已複製(非連結)——更新後請重新啟用以取得最新版本" + }, + "ExpertsSettings": { + "title": "專家技能", + "description": "為 AI 編碼代理啟用精心挑選、經過實戰驗證的技能工作流程。每個專家都是 superpowers 專案中的獨立技能 —— codeg 維護中央副本,並將其軟連結到你選擇的代理目錄。", + "loading": "正在載入專家清單…", + "loadingContent": "正在載入內容…", + "emptyExperts": "目前沒有可用的專家,請查看應用程式日誌。", + "emptySelection": "從左側選擇一個專家以檢視內容並管理啟用狀態。", + "emptySearch": "沒有符合目前搜尋條件的專家。", + "searchPlaceholder": "依名稱、ID 或描述搜尋專家", + "enableForAgents": "為代理啟用", + "noAgents": "未偵測到 ACP 代理。", + "copyModeWarning": "已複製(非軟連結)。codeg 更新後需要重新啟用以取得最新版本。", + "previewTitle": "SKILL.md 預覽", + "categories": { + "discovery": "探索與設計", + "planning": "規劃", + "execution": "執行", + "quality": "品質與測試", + "debugging": "除錯", + "review": "審查與整合", + "meta": "後設技能" + }, + "states": { + "not_linked": "未啟用", + "linked_to_codeg": "已啟用", + "linked_elsewhere": "衝突 — 已有其他連結", + "blocked_by_real_directory": "衝突 — 已有同名的自訂 skill 佔用", + "broken": "連結損壞" + }, + "badges": { + "userModified": "使用者修改過" + }, + "actions": { + "openCentralDir": "開啟中央目錄", + "refresh": "重新整理" + }, + "toasts": { + "loadFailed": "載入專家詳情失敗", + "enabled": "已為該代理啟用專家", + "disabled": "已為該代理停用專家", + "enableFailed": "啟用專家失敗", + "disableFailed": "停用專家失敗", + "openFolderFailed": "開啟目錄失敗" + } + }, + "ScienceSettings": { + "title": "科學研究技能", + "description": "為你的 AI 編碼智能體啟用精選的科學研究技能:假設生成、實驗設計、統計、視覺化、批判性評估與文獻檢索。codeg 管理中央副本,並將每個技能連結到你選擇的智能體。", + "loading": "正在載入科學研究技能…", + "emptySkills": "沒有可用的科學研究技能。請檢查應用程式日誌。", + "searchPlaceholder": "依名稱、ID 或描述搜尋科學研究技能", + "categories": { + "ideation": "構思", + "design": "研究設計", + "analysis": "分析", + "visualization": "視覺化", + "evaluation": "評估", + "literature": "文獻" + }, + "states": { + "not_linked": "未啟用", + "linked_to_codeg": "已啟用", + "linked_elsewhere": "衝突 — 已有其他連結", + "blocked_by_real_directory": "衝突 — 已有同名的自訂 skill 佔用", + "broken": "連結損壞" + }, + "badges": { + "userModified": "使用者修改過", + "needsKey": "需要金鑰", + "needsSetup": "可能需環境" + }, + "actions": { + "openCentralDir": "開啟中央目錄", + "refresh": "重新整理" + }, + "toasts": { + "openFolderFailed": "開啟目錄失敗" + } + }, + "OfficeToolsSettings": { + "title": "Office 工具", + "description": "管理 OfficeCLI 技能,用於建立 Excel、Word 和 PowerPoint 檔案。安裝 OfficeCLI,同步技能,並為每個智慧體啟用。", + "loadingContent": "載入內容中…", + "emptySkills": "暫無技能。請先安裝 OfficeCLI 並同步技能。", + "emptySelection": "選擇一個技能查看內容和管理啟用狀態。", + "emptySearch": "沒有匹配的技能。", + "searchPlaceholder": "按名稱、ID 或描述搜尋技能", + "enableForAgents": "為智慧體啟用", + "noAgents": "未偵測到 ACP 智慧體。", + "installFirst": "請先安裝 OfficeCLI 以啟用技能。", + "syncFirst": "請先同步技能以載入內容。", + "noContent": "暫無內容。", + "copyModeWarning": "已複製(非連結)。重新同步以取得最新版本。", + "previewTitle": "SKILL.md 預覽", + "detection": { + "installed": "已安裝", + "notInstalled": "未安裝", + "notRunnable": "已安裝但無法執行", + "installHint": "安裝 OfficeCLI 以為 AI 智慧體啟用辦公文件生成技能。", + "install": "安裝", + "uninstall": "解除安裝", + "syncSkills": "同步技能" + }, + "categories": { + "general": "通用", + "presentations": "簡報", + "documents": "文件", + "spreadsheets": "試算表" + }, + "states": { + "not_linked": "未啟用", + "linked_to_codeg": "已啟用", + "linked_elsewhere": "已阻止——存在其他連結", + "blocked_by_real_directory": "已阻止——自訂技能佔用此名稱", + "broken": "連結已損壞" + }, + "badges": { + "notSynced": "未同步" + }, + "actions": { + "refresh": "重新整理" + }, + "toasts": { + "loadFailed": "載入技能詳情失敗", + "enabled": "已為此智慧體啟用技能", + "disabled": "已為此智慧體停用技能", + "enableFailed": "啟用技能失敗", + "disableFailed": "停用技能失敗", + "installSuccess": "OfficeCLI 安裝成功", + "installFailed": "安裝 OfficeCLI 失敗", + "uninstallSuccess": "OfficeCLI 已解除安裝", + "uninstallFailed": "解除安裝 OfficeCLI 失敗", + "syncSuccess": "已成功同步 {synced} 個技能", + "syncPartial": "已同步 {synced} 個技能,{errors} 個失敗", + "syncFailed": "同步技能失敗" + }, + "autoPreviewLabel": "自動開啟預覽", + "autoPreviewHint": "當智慧代理建立或編輯 Word、Excel、PowerPoint 檔案時,自動開啟其即時預覽。" + }, + "SkillPacksSettings": { + "title": "技能包", + "description": "由 codeg 集中管理、並連結到各 AI 智慧代理的成套技能——程式設計專家、科學研究與辦公文件工具。可在下方依代理分別啟用。", + "tabs": { + "experts": "專家", + "science": "科學研究", + "office": "辦公工具", + "custom": "自訂" + }, + "actions": { + "openCentralDir": "開啟中央目錄", + "refresh": "重新整理" + }, + "toasts": { + "openFolderFailed": "開啟目錄失敗" + } + }, + "QuickMessagesSettings": { + "title": "快捷訊息", + "description": "管理可重用的訊息片段。拖曳以調整順序。", + "loading": "載入快捷訊息…", + "emptyList": "尚無快捷訊息。點擊「新增」建立一條。", + "emptySelection": "選擇一條快捷訊息進行編輯。", + "searchPlaceholder": "依標題或內容搜尋", + "untitled": "未命名", + "actions": { + "new": "新增", + "save": "儲存", + "delete": "刪除", + "dragSort": "拖曳排序", + "dragSortMessage": "拖曳排序快捷訊息:{name}" + }, + "fields": { + "title": "標題", + "titlePlaceholder": "為此訊息取一個簡短的標題", + "content": "內容", + "contentPlaceholder": "在此輸入訊息內容" + }, + "confirmDelete": { + "title": "刪除快捷訊息?", + "message": "將永久刪除「{name}」。確定嗎?", + "cancel": "取消", + "confirm": "刪除" + }, + "toasts": { + "loadFailed": "載入快捷訊息失敗", + "createFailed": "建立快捷訊息失敗", + "saveFailed": "儲存快捷訊息失敗", + "deleteFailed": "刪除快捷訊息失敗", + "saveOrderFailed": "儲存順序失敗", + "created": "已建立快捷訊息", + "saved": "已儲存快捷訊息", + "deleted": "已刪除快捷訊息" + } + }, + "Pet": { + "badge": { + "running": "{count} 個執行中", + "waiting": "{count} 個待核准", + "error": "{count} 個發生錯誤" + }, + "panel": { + "title": "活動工作階段", + "empty": "沒有活動工作階段", + "emptyHint": "正在執行或需要你處理的工作階段會顯示在這裡。", + "statusRunning": "執行中", + "statusWaiting": "等待中", + "statusError": "發生錯誤", + "subAgentOf": "子智慧代理" + }, + "menu": { + "scale": "縮放", + "openManager": "管理寵物", + "close": "關閉" + }, + "loadError": "載入寵物失敗", + "missingPetIdParam": "未選中任何寵物", + "summonButton": "寵物", + "manager": { + "title": "桌面寵物", + "description": "懸浮在桌面上的夥伴,使用與 Codex 相容的精靈圖。", + "addPet": "新增寵物", + "importFromCodex": "從 Codex 匯入", + "noPets": "暫無寵物。可以新增一隻,或從 Codex 匯入。", + "setActive": "設為使用中", + "active": "使用中", + "edit": "編輯", + "delete": "刪除", + "deleteConfirm": "確認刪除寵物「{name}」嗎?會從磁碟上一併移除。", + "summon": "召喚寵物視窗", + "openCodexHelp": "Codex 寵物需位於 ~/.codex/pets/ 目錄下,但未找到。", + "specRequirement": "精靈圖寬度必須為 1536 像素,高度需為 208 像素的整數倍(如 1872 或 2288),並為帶透明通道的 PNG 或 WebP。", + "form": { + "id": "寵物 ID", + "idHelp": "僅允許小寫字母、數字、'-' 和 '_',最多 64 字元。", + "displayName": "顯示名稱", + "description": "描述 (選填)", + "spritesheet": "精靈圖", + "chooseFile": "選擇檔案", + "replaceFile": "替換精靈圖", + "saveCreate": "新增寵物", + "saveUpdate": "儲存變更", + "cancel": "取消" + }, + "errors": { + "missingId": "寵物 ID 不能為空", + "missingName": "顯示名稱不能為空", + "missingSpritesheet": "必須選擇一個精靈圖", + "addFailed": "新增寵物失敗", + "updateFailed": "更新寵物失敗", + "deleteFailed": "刪除寵物失敗", + "loadFailed": "載入寵物列表失敗", + "setActiveFailed": "設定活躍寵物失敗", + "summonFailed": "召喚寵物視窗失敗" + } + }, + "import": { + "title": "從 Codex 匯入", + "subtitle": "在 ~/.codex/pets/ 下找到以下可匯入的寵物。", + "selectAll": "全選", + "alreadyImported": "已匯入", + "renameOnConflict": "衝突時自動加上 -imported 後綴", + "import": "匯入所選", + "noneFound": "未找到可匯入的 Codex 寵物。", + "imported": "匯入完成", + "failed": "匯入失敗", + "close": "關閉" + }, + "marketplace": { + "openMarketplace": "寵物市集", + "title": "寵物市集", + "search": "搜尋寵物", + "kindFilter": { + "all": "全部", + "object": "物品", + "animal": "動物", + "person": "人物", + "creature": "生物" + }, + "sortFilter": { + "latest": "最新", + "popular": "熱門", + "views": "最多瀏覽" + }, + "refresh": "重新整理", + "install": "安裝", + "installing": "安裝中", + "reinstall": "重新安裝", + "reinstallConfirm": "確認覆蓋本機寵物 \"{name}\" 嗎?現有資料將被取代。", + "cancel": "取消", + "stats": { + "views": "瀏覽", + "downloads": "下載", + "likes": "讚" + }, + "actions": { + "idle": "待機", + "running_right": "右跑", + "running_left": "左跑", + "waving": "揮手", + "jumping": "跳躍", + "failed": "失敗", + "waiting": "等待", + "running": "執行", + "review": "審閱" + }, + "page": "第 {page} / {total} 頁", + "prev": "上一頁", + "next": "下一頁", + "empty": "沒有符合的寵物。", + "successInstalled": "已安裝 \"{name}\"", + "errors": { + "loadFailed": "載入市集失敗", + "installFailed": "安裝失敗", + "alreadyInstalled": "該寵物已存在" + } + } + }, + "RemoteWorkspace": { + "openRemoteWorkspace": "Open remote workspace", + "manage": "Manage remote workspace", + "manageTitle": "Remote Workspace connections", + "empty": "No remote connections", + "searchPlaceholder": "Search remote workspaces", + "orderFailed": "Failed to save remote workspace order", + "dragSort": "Drag to sort", + "dragSortConnection": "Drag to sort {name}", + "newConnection": "New connection", + "loading": "Loading", + "loadingConnection": "Loading remote connection", + "name": "Name", + "baseUrl": "Service URL", + "token": "Access token", + "save": "Save", + "delete": "Delete", + "confirmDelete": { + "title": "Delete remote connection?", + "message": "This will remove \"{name}\" from this device. This action cannot be undone.", + "cancel": "Cancel", + "confirm": "Delete" + }, + "saved": "Remote connection saved.", + "deleted": "Remote connection deleted.", + "loadFailed": "Failed to load remote connections", + "saveFailed": "Failed to save remote connection", + "deleteFailed": "Failed to delete remote connection", + "openFailed": "Failed to open remote workspace", + "connectionLoadFailed": "Failed to load remote connection: {message}", + "connectionExpired": "Remote connection \"{name}\" is expired. Update its token and reload this window." + }, + "ServerFileBrowser": { + "title": "選擇伺服器檔案", + "pathPlaceholder": "輸入目錄路徑...", + "goHome": "回到主目錄", + "navigateUp": "返回上層目錄", + "select": "選擇", + "cancel": "取消", + "loading": "載入中...", + "emptyDirectory": "此目錄為空", + "errorLoadingDir": "載入目錄失敗", + "selectedCount": "已選 {count} 項" + }, + "BackupSettings": { + "title": "備份與還原", + "description": "匯出一份可攜的 codeg 資料備份,或從備份還原。", + "tabs": { + "backup": "備份", + "restore": "還原" + }, + "export": { + "includeExternal": "包含對話內容", + "includeExternalHint": "一併打包各 CLI 的對話記錄(Claude、Codex、Gemini 等),體積更大。", + "passphrase": "通行碼(選填)", + "passphrasePlaceholder": "留空則產生未加密的封存檔", + "passphraseConfirm": "確認通行碼", + "passphraseMismatch": "兩次輸入的通行碼不一致。", + "noPassphraseWarning": "此備份將以明文包含密鑰(API key、token)。請妥善保管。", + "passphraseLossWarning": "將以此通行碼加密。通行碼一旦遺失,備份將無法還原。", + "button": "匯出備份", + "inProgress": "正在建立備份…", + "success": "備份已建立。", + "started": "已開始下載備份。" + }, + "restore": { + "selectFile": "選擇備份檔案", + "passphrasePrompt": "此備份已加密,請輸入其通行碼。", + "unlock": "解鎖", + "preview": { + "title": "備份詳情", + "encrypted": "已加密", + "compatible": "相容", + "incompatible": "不相容", + "createdAt": "建立時間:{value}", + "appVersion": "應用程式版本:{value}", + "incompatibleHint": "此備份由較新版本的 codeg 建立,無法還原。" + }, + "replaceWarning": "還原將取代目前全部 codeg 資料(資料庫與上傳檔案)。目前資料會先做快照以便復原。", + "keyringNote": "桌面端的 GitHub/聊天 token 存於系統鑰匙圈,不包含在備份中;還原後需重新填寫。", + "button": "還原", + "staging": "正在準備還原…", + "staged": "還原已就緒,正在重新啟動…", + "restarting": "還原已就緒,正在重新啟動服務…", + "restartTimeout": "服務未能及時恢復。待其啟動後請重新整理頁面。", + "externalSideLocation": "對話記錄已還原至 {path}", + "confirmTitle": "取代全部資料?", + "confirmBody": "這將以備份取代目前的 codeg 資料庫與上傳檔案,然後重新啟動。目前資料會先做快照。", + "cancel": "取消", + "confirmAction": "取代並重新啟動", + "external": { + "title": "對話內容", + "hint": "此備份包含各 CLI 的對話記錄。請選擇還原到何處。", + "modeSkip": "不還原", + "modeSide": "還原到安全的旁路資料夾", + "modeOriginal": "還原到 CLI 的原始位置", + "forceOverwrite": "覆寫已存在的檔案", + "forceOverwriteHint": "取代 CLI 資料夾中已存在的檔案。", + "scanning": "正在檢查衝突…", + "noConflicts": "不會覆寫任何已存在的檔案。", + "conflictCount": "將影響 {count} 個已存在的檔案。", + "conflictSkipNote": "未啟用覆寫時,已存在的檔案將被保留(略過)。" + }, + "restartFailed": "還原已就緒,但伺服器未能重新啟動。請手動重新啟動以套用此次還原。" + }, + "remoteUnsupported": "備份與還原作用於執行 codeg 的那台機器上的資料。你目前連線的是遠端工作區——請直接在該伺服器上管理其備份。" + }, + "backup": { + "restore": { + "error": { + "badPassphrase": "通行碼錯誤或備份已損毀。", + "corrupted": "備份封存檔已損毀。", + "unknownFormat": "此檔案不是可識別的 codeg 備份。", + "newerVersion": "此備份由 codeg {backupVersion} 建立,比目前版本({appVersion})更新。", + "alreadyPending": "已有一個還原在等待生效。請先重新啟動套用它,再暫存新的還原。" + } + }, + "error": { + "diskSpace": "磁碟空間不足,無法完成操作。", + "cancelled": "操作已取消。" + } + }, + "WebConnection": { + "disconnectedTitle": "連線已中斷", + "reconnectingDescription": "正在嘗試重新連線伺服器,通常會在幾秒內自動恢復。", + "reconnectNow": "立即重新連線", + "sessionExpiredTitle": "工作階段已過期", + "sessionExpiredDescription": "登入狀態已失效,請重新登入以繼續。", + "goToLogin": "前往登入" + }, + "LiveFeedback": { + "placeholder": "在 {agent} 工作時給它留言…", + "agentFallback": "智能體", + "ariaLabel": "即時回饋留言", + "dialogTitle": "即時回饋", + "dialogDescription": "在智能體工作時給它留言。它會在下次檢查時讀取,不會打斷當前步驟。", + "dialogDescriptionInstant": "在智慧代理工作時傳送備註。備註會立即插入目前回合——代理馬上就能看到。", + "channelDowngraded": "本工作階段無法即時插入——備註已儲存,待代理下次檢查時讀取。", + "send": "送出", + "cancel": "取消", + "pending": "等待中", + "delivered": "已收到", + "turnEndedUnread": "智能體在讀取你的回饋前已結束本輪。", + "sendAsMessage": "作為新訊息送出", + "dismiss": "忽略", + "turnEndedResent": "本輪已結束——已改為作為新訊息送出。", + "turnEnded": "本輪已結束。", + "submitFailed": "留言送出失敗" + }, + "AgentToolsSettings": { + "title": "對話內工具", + "description": "codeg 在對話中額外提供給智慧代理的工具。工具會在代理啟動時注入,變更只對之後啟動的代理生效。", + "feedbackLabel": "即時回饋", + "feedbackHint": "在智慧代理工作時向它傳送備註與修正。支援即時插入的代理會立刻在目前回合中看到你的備註;其他代理則透過檢查回饋的工具讀取——這類代理通常只有在提示中提到時才會檢查,例如在訊息中加上「定期檢查我的即時回饋」。", + "questionLabel": "向使用者提問", + "questionHint": "允許智能體暫停並向你提出多選問題,問題會顯示在對話輸入框上方。智能體會一直等待,直到你作答(或略過)。", + "sessionInfoLabel": "取得工作階段資訊", + "sessionInfoHint": "允許智慧代理查詢你在訊息中提及的工作階段(工作階段徽章),讀取其標題、代理、狀態、工作區、Token 用量與最近訊息。", + "automationsLabel": "建立自動化", + "automationsHint": "把對話儲存為按排程執行的自動化。預設關閉——它之後會自行啟動代理。", + "workTasksLabel": "建立待辦任務", + "workTasksHint": "從對話中往待辦看板排一張任務卡。預設關閉——它會寫入應用程式狀態。", + "save": "儲存", + "saving": "儲存中…", + "saved": "工具設定已儲存", + "saveFailed": "儲存工具設定失敗", + "loadFailed": "載入失敗:{detail}" + }, + "NotificationSoundSettings": { + "title": "提示音", + "description": "智慧體事件觸發時播放一段簡短的提示音。這裡的事件與訊息通道推送的完全一致,但設定只對本裝置生效。", + "enableHint": "預設關閉。提示音只在目前瀏覽器或應用程式的工作區視窗中播放。", + "volume": "音量", + "preview": "試聽", + "previewEvent": "試聽「{event}」提示音", + "onlyWhenUnfocused": "僅在視窗未聚焦時播放", + "onlyWhenUnfocusedHint": "正在檢視 Codeg 時保持靜音。", + "eventsTitle": "事件", + "eventsHint": "為每個事件選擇一種音效,選擇「靜音」則不播放。同一事件在數秒內重複觸發時只播放一次。", + "toneNone": "靜音", + "toneChime": "叮咚", + "toneDing": "清鈴", + "toneBlip": "短音", + "tonePop": "輕點", + "toneAlert": "警示", + "toneDescend": "下行音" + }, + "LogsSettings": { + "loading": "載入中…", + "sectionTitle": "執行日誌", + "sectionDescription": "檢視與設定應用程式診斷日誌。日誌會寫入本機檔案,並保留在記憶體中以便即時檢視。", + "captureTitle": "日誌等級", + "captureDescription": "控制記錄的詳細程度。等級越高(Debug、Trace)記錄越多,但日誌也越大。「關閉」會停止記錄日誌。", + "captureLabel": "擷取等級", + "levels": { + "off": "關閉", + "error": "錯誤", + "warn": "警告", + "info": "資訊", + "debug": "除錯", + "trace": "追蹤" + }, + "viewerTitle": "最近日誌", + "viewerDescription": "即時檢視最近的日誌記錄。可依等級篩選或搜尋文字。", + "searchPlaceholder": "搜尋訊息或來源…", + "viewLevels": { + "all": "所有等級", + "error": "錯誤以上", + "warn": "警告以上", + "info": "資訊以上", + "debug": "除錯以上", + "trace": "追蹤以上" + }, + "pause": "暫停", + "resume": "即時", + "refresh": "重新整理", + "clear": "清除", + "openFolder": "開啟資料夾", + "shownCount": "已顯示 {shown} / {total}", + "empty": "尚無日誌。", + "levelSaveFailed": "儲存日誌等級失敗", + "openFolderFailed": "開啟日誌資料夾失敗", + "downloadFailed": "下載日誌檔案失敗", + "filesTitle": "日誌檔案", + "filesDescription": "從磁碟下載完整日誌檔案,檢視即時緩衝區以外的歷史記錄。", + "filesEmpty": "尚無日誌檔案。", + "download": "下載", + "downloadTruncated": "檔案較大,已下載最新的 {size}。完整檔案請在日誌目錄中查看。", + "captureEnvLocked": "日誌等級由 RUST_LOG / CODEG_LOG 環境變數控制;請在該處修改以生效。", + "targetsTitle": "依模組覆寫", + "targetsDescription": "為特定模組(如 codeg_lib::acp)單獨設定級別,不影響全域級別。", + "targetsAdd": "新增", + "targetsRemove": "移除覆寫", + "toggleDetails": "切換詳情" + }, + "Automations": { + "title": "自動化", + "new": "新增自動化", + "empty": "尚無自動化", + "emptyHint": "建立一個,讓代理程式按排程或手動執行任務。", + "name": "名稱", + "namePlaceholder": "例如:每晚 PR 審查", + "prompt": "提示詞", + "promptPlaceholder": "讓代理程式做什麼?", + "agent": "代理程式", + "folder": "工作區資料夾", + "folderPlaceholder": "選擇資料夾", + "isolation": "隔離方式", + "isolationWorktree": "每次執行新增 worktree", + "isolationShared": "在資料夾內執行", + "isolationSharedCaveat": "執行會直接使用該資料夾的工作樹,可能與你未提交的變更衝突。勾選每次執行新建工作樹以隔離每次執行。", + "trigger": "觸發方式", + "triggerSchedule": "按排程", + "triggerManual": "僅手動", + "cron": "排程(cron)", + "cronPlaceholder": "0 9 * * 1-5", + "timezone": "時區", + "nextRun": "下次執行", + "branch": "分支", + "branchOptional": "分支(選填)", + "enabled": "已啟用", + "save": "儲存", + "cancel": "取消", + "edit": "編輯", + "delete": "刪除", + "runNow": "立即執行", + "cancelRun": "取消執行", + "runHistory": "執行紀錄", + "noRuns": "尚無執行紀錄", + "allFolders": "所有資料夾", + "filterAll": "全部", + "noMatches": "沒有符合的自動化", + "viewConversation": "檢視對話", + "lastRun": "上次執行", + "never": "從未", + "running": "執行中", + "deleteTitle": "刪除此自動化?", + "deleteDescription": "這會刪除該自動化及其排程。執行紀錄會保留。", + "statusRunning": "執行中", + "statusSucceeded": "成功", + "statusFailed": "失敗", + "statusCancelled": "已取消", + "statusSkipped": "已略過", + "errorName": "名稱必填", + "errorPrompt": "提示詞必填", + "errorCron": "按排程的自動化需要 cron 運算式", + "errorFolder": "請選擇工作區資料夾", + "presetHourly": "每小時", + "presetDaily": "每天 9 點", + "presetWeekdays": "工作日 9 點", + "presetCustom": "自訂", + "probing": "正在載入選項…", + "retry": "重試", + "configNone": "此代理程式沒有可設定的選項", + "inherit": "代理程式預設", + "mode": "模式", + "config": "設定", + "branchPlaceholder": "(預設分支)", + "selectHint": "選擇一個自動化以查看詳情", + "refresh": "重新整理", + "onboardTitle": "自動化日常代理任務", + "onboardHint": "安排代理定時或隨需審查程式碼、更新相依套件或處理問題。", + "headerSubtitle": "定時與隨需的代理任務", + "startFromTemplate": "從範本開始", + "blankTitle": "空白自動化", + "blankDesc": "從零設定一個代理任務。", + "backToTemplates": "範本", + "sectionSchedule": "排程與目標", + "sectionTarget": "執行目標", + "sectionAction": "動作", + "actionLaunchSession": "啟動會話", + "actionEnqueueTask": "任務入列", + "actionEnqueueTaskHint": "每次觸發都會在目標資料夾的待辦任務裡加入一個待辦任務(標題為本自動化名稱),由任務引擎依看板設定執行。", + "sectionPrompt": "提示詞", + "nextIn": "{rel}後執行", + "manual": "手動", + "schedEveryMinutes": "每 {n} 分鐘", + "schedHourly": "每小時", + "schedDaily": "每天 {time}", + "schedWeekdays": "工作日 {time}", + "schedWeekly": "每{day} {time}", + "schedMonthly": "每月 {day} 日 {time}", + "dow0": "週日", + "dow1": "週一", + "dow2": "週二", + "dow3": "週三", + "dow4": "週四", + "dow5": "週五", + "dow6": "週六", + "tplCodeReviewTitle": "程式碼審查", + "tplCodeReviewDesc": "審查最近的變更,找出缺陷、回歸與品質問題。", + "tplDependencyUpdatesTitle": "相依套件更新", + "tplDependencyUpdatesDesc": "找出過時的相依套件並提出安全的升級方案。", + "tplTestCoverageTitle": "測試涵蓋率", + "tplTestCoverageDesc": "找出未涵蓋的程式碼路徑並補上缺少的測試。", + "tplTodoSweepTitle": "TODO 清理", + "tplTodoSweepDesc": "收集 TODO 與 FIXME 註解並依優先順序整理。", + "tplCiTriageTitle": "CI 排查", + "tplCiTriageDesc": "調查最近失敗的檢查並提出修復方案。", + "tplReleaseNotesTitle": "發行說明", + "tplReleaseNotesDesc": "彙整自上次發行以來的變更,產生更新日誌。", + "tplSecurityAuditTitle": "安全稽核", + "tplSecurityAuditDesc": "掃描漏洞與風險模式,並回報發現的問題。", + "enable": "啟用", + "disable": "停用", + "moreActions": "更多操作", + "statusDisabled": "已停用", + "cronBuilderTitle": "排程產生器", + "cronFreqLabel": "頻率", + "cronFreqMinutes": "每 N 分鐘", + "cronFreqHourly": "每小時", + "cronFreqDaily": "每天", + "cronFreqWeekdays": "工作日", + "cronFreqWeekly": "每週", + "cronFreqMonthly": "每月", + "cronFreqCustom": "自訂", + "cronEveryLabel": "間隔(分鐘)", + "cronTimeLabel": "時間", + "cronHourLabel": "小時", + "cronMinuteLabel": "分鐘", + "cronDowLabel": "星期", + "cronDomLabel": "日期", + "cronApply": "套用", + "cronPreviewLabel": "預覽", + "cronOpenBuilder": "開啟排程產生器", + "branchDefault": "預設分支", + "branchUseCustom": "使用「{query}」", + "branchLocal": "本機", + "branchRemote": "遠端", + "branchSearchPlaceholder": "搜尋分支…", + "branchNone": "無分支" + }, + "Tasks": { + "title": "待辦任務", + "new": "新增任務", + "empty": "還沒有任務", + "emptyHint": "新增待辦後即可處理——agent 在獨立 worktree 中工作,你驗收並合併結果。", + "emptyColTodo": "還沒有待辦任務", + "emptyColInProgress": "暫無進行中的任務", + "emptyColAttention": "暫無等你處理的任務", + "emptyColDone": "還沒有已完成的任務", + "allFolders": "全部資料夾", + "showCanceled": "顯示已取消", + "showArchived": "顯示已封存", + "filter": "篩選", + "viewSwitchToBoard": "切換到看板檢視", + "viewSwitchToList": "切換到清單檢視", + "statusFilter": "狀態", + "statusFilterAll": "全部狀態", + "listEmpty": "沒有符合目前篩選條件的任務", + "listColStatus": "狀態", + "listColTask": "任務", + "listColLocation": "位置", + "listColChanges": "變更", + "listColUpdated": "更新", + "colTodo": "待辦", + "colInProgress": "進行中", + "colAttention": "等你處理", + "colDone": "已完成", + "statusTodo": "待辦", + "statusQueued": "排隊中", + "statusPreparing": "初始化中", + "statusRunning": "進行中", + "statusAwaitingInput": "等待輸入", + "statusReview": "待驗收", + "statusMerging": "合併中", + "statusDone": "已完成", + "statusFailed": "失敗", + "statusCanceled": "已取消", + "statusInterrupted": "已中斷", + "badgeCleanupFailed": "清理失敗", + "badgeWorktreeKept": "保留 worktree", + "badgeWorktreeRemoved": "Worktree 已刪除", + "filesChanged": "{count} 個檔案", + "actionStart": "開始", + "actionSchedule": "定時執行", + "actionCancel": "取消", + "actionRetry": "重試", + "actionRequeue": "重新排隊", + "actionViewSession": "檢視會話", + "actionEdit": "編輯", + "actionDelete": "刪除", + "actionRetryCleanup": "重試清理", + "actionMerge": "合併", + "actionUnqueueMerge": "取消排隊", + "actionEditQueuedMerge": "修改排隊的合併", + "badgeMergeQueued": "排隊合併中", + "badgeMergeQueuedRank": "排隊合併 · 第 {rank} 位", + "badgeMergeQueuedHint": "正在等待該專案目前的合併完成,輪到時會自動開始。", + "actionComplete": "完成", + "actionAbandon": "放棄", + "cancelTitle": "取消任務?", + "cancelDescription": "任務將變為已取消。worktree 會保留,之後可以重新排隊。", + "cancelReasonLabel": "取消原因(選填)", + "cancelReasonPlaceholder": "例如:方向不對,我重寫一下任務描述", + "cancelKeep": "先不取消", + "cancelSubmit": "取消任務", + "restartTitleRetry": "重試任務", + "restartTitleRequeue": "重新排隊", + "restartDescription": "可以補充一段說明(選填),它會隨下一輪的提示詞一起傳給 agent。", + "scheduleTitle": "定時執行任務", + "scheduleDescription": "任務留在「待辦」,到時間自動開始。資料夾的並行上限仍然有效。", + "scheduleDateLabel": "日期", + "schedulePickDate": "選擇日期", + "scheduleTimeLabel": "時間", + "schedulePreview": "{time} 執行", + "schedulePastHint": "該時間已過——儲存後會立即開始。", + "scheduleInAnHour": "1 小時後", + "scheduleInThreeHours": "3 小時後", + "scheduleTomorrow": "明天 9:00", + "scheduleClear": "清除定時", + "scheduleBadge": "預計於 {time} 開始", + "toastScheduled": "已定時:{time}", + "toastScheduleCleared": "已清除定時", + "actionFollowUp": "繼續處理", + "actionAddNote": "補充說明", + "followUpSubmit": "傳送", + "followUpIntentRevise": "修改返工", + "followUpIntentContinue": "繼續推進", + "followUpIntentQuestion": "提問答疑", + "followUpIntentVerify": "自查驗證", + "followUpPlaceholderRevise": "希望 agent 改哪裡?會在同一個工作階段繼續。", + "followUpPlaceholderContinue": "接下來還要做什麼?已有的工作會保留。", + "followUpPlaceholderQuestion": "想了解什麼?agent 只回答,不會改動任何檔案。", + "followUpPlaceholderVerify": "選填:有什麼想讓它重點檢查的?", + "followUpPlaceholderRetry": "選填:這次要怎麼做才不一樣?例如:先跑 pnpm install", + "followUpPlaceholderRequeue": "選填:當時為什麼取消?這次要注意什麼?", + "actionArchive": "封存", + "actionUnarchive": "取消封存", + "archiveAllDone": "全部封存", + "dropToStart": "放開即開始執行", + "errorView": "檢視", + "notifyReview": "待驗收:{title}", + "notifyFailed": "任務失敗:{title}", + "createFromMessage": "由此訊息建立任務", + "detailTokens": "總 token 用量", + "editorTitleNew": "新增任務", + "editorTitleEdit": "編輯任務", + "templates": "範本", + "templatesEmpty": "還沒有範本。", + "templateSaveCurrent": "將目前內容存為範本", + "templateDelete": "刪除範本", + "transcriptTitle": "任務會話", + "transcriptDescription": "任務智慧代理會話的唯讀即時檢視。", + "phaseWork": "任務執行", + "phaseRetry": "重試執行", + "phaseReturn": "繼續處理", + "phaseMerge": "合併變更", + "titleLabel": "標題", + "titlePlaceholder": "要做什麼?", + "promptLabel": "任務描述", + "promptPlaceholder": "向 agent 描述任務——輸入 @ 可引用檔案,/ 可喚起指令", + "folderPlaceholder": "選擇資料夾", + "agentInheritedHint": "繼承自任務設定,修改後僅對本任務生效", + "agentOverrideReset": "恢復繼承", + "sectionTarget": "目標", + "errorTitle": "請輸入標題", + "errorPrompt": "請輸入任務描述", + "errorFolder": "請選擇資料夾", + "save": "儲存", + "cancel": "取消", + "mergeTitle": "合併任務", + "mergeQueuedTitle": "排隊中的合併", + "mergeQueueHint": "該專案正在合併另一個任務。此任務會加入佇列,等前一個完成後自動開始。", + "mergeQueueUpdateHint": "此任務已在合併佇列中。送出將更新它的合併選項,並保留原本的排隊位置。", + "mergeDescription": "將 {branch} 合併到 {base}。worktree 中未提交的變更會先自動提交。", + "mergeMessage": "提交訊息", + "mergeMessagePlaceholder": "例如 feat: add login validation", + "mergeAutoMessage": "讓 agent 自動產生提交訊息", + "strategySquash": "合併為一筆提交", + "strategySquashHint": "任務的所有修改壓縮成一筆提交記錄併入主分支,歷史更簡潔。", + "strategyMerge": "保留完整提交歷史", + "strategyMergeHint": "保留任務過程中的每一筆提交,另加一筆合併記錄,每一步都可追溯。", + "mergeDeleteWorktree": "合併後刪除 worktree", + "mergeSubmit": "合併", + "mergeSubmitQueue": "加入合併佇列", + "mergeQueuedToast": "已加入合併佇列,等目前的合併完成後自動開始。", + "completeTitle": "完成任務", + "completeDescription": "此任務沒有變更任何檔案,無須合併,將直接標記為已完成。", + "completeDescriptionNoWorktree": "此任務的 worktree 已被刪除,無法再合併,將直接標記為已完成。若工作分支上仍有未合併的提交,分支會被保留。", + "completeDeleteWorktree": "完成後刪除 worktree", + "completeSubmit": "完成", + "settingsTitle": "任務設定", + "settingsDescription": "{folder} 中任務的預設配置。", + "settingsScope": "套用範圍", + "settingsScopeGlobal": "全部資料夾(全域預設)", + "settingsScopeGlobalHint": "未單獨設定的資料夾將使用這份全域預設。", + "settingsSource": "設定來源", + "settingsSourceGlobal": "使用全域預設", + "settingsSourceCustom": "單獨設定", + "settingsSourceGlobalFollow": "跟隨全域任務設定,全域變更會自動生效。", + "settingsSourceCustomHint": "為此資料夾儲存獨立設定,不再跟隨全域預設。", + "settingsAgent": "預設 agent", + "settingsMaxConcurrent": "最大並行任務數", + "settingsMaxConcurrentHint": "0 表示不限制", + "settingsAutoProcess": "自動處理", + "settingsAutoProcessHint": "待辦任務自動開始處理,受並行上限約束。", + "settingsMergeStrategy": "預設合併策略", + "settingsMergeStrategyHint": "合併任務時,這些修改在分支歷史裡如何記錄。", + "settingsAutoMerge": "自動合併", + "settingsAutoMergeHint": "任務進入待驗收且有可合併改動時自動落地,與點擊「合併」相同:提交訊息由 agent 自動產生,是否刪除 worktree 沿用下方預設。預檢未通過或合併失敗的任務會留下等你處理。", + "settingsDeleteWorktree": "合併後刪除 worktree", + "settingsDeleteWorktreeHint": "合併對話框裡預設勾選,仍可臨時更改。", + "settingsWorktreeRoot": "Worktree 位置", + "settingsWorktreeRootHint": "新任務的 worktree 會建立在該目錄下,每個任務一個。留空則建立在專案資料夾的同層目錄;「~」表示家目錄,相對路徑相對於專案資料夾。", + "settingsWorktreeRootPlaceholder": "~/codeg-worktrees", + "settingsWorktreeRootBrowse": "選擇 worktree 目錄", + "settingsPreflight": "預檢命令", + "settingsPreflightHint": "任務進入待驗收時在 worktree 中執行。", + "settingsPreflightCustomPlaceholder": "pnpm test", + "settingsInitCommand": "Worktree 初始化命令", + "settingsInitCommandHint": "建立 worktree 後、工作階段開始前執行。", + "settingsInitCommandPlaceholder": "pnpm install", + "settingsTabGeneral": "一般", + "settingsTabMerge": "合併", + "settingsTabWorktree": "Worktree", + "settingsTabPrompts": "提示詞", + "settingsPromptsIntro": "每個階段都已內建固定的提示詞——任務本身、worktree 規則,合併階段還包含具體的 git 步驟。這裡填的內容會作為補充說明追加到最後:只是對內建提示詞的細化,不會取代它們。", + "settingsPromptStageAll": "全部階段", + "settingsPromptPlaceholderAll": "例如:遵循 AGENTS.md 裡的專案慣例;一律用繁體中文回覆", + "settingsPromptPlaceholderWork": "例如:先讀相關測試;小步提交,邊做邊交", + "settingsPromptPlaceholderRetry": "例如:先看清楚已經提交了哪些改動再繼續,別重做已完成的部分", + "settingsPromptPlaceholderReturn": "例如:逐條處理提到的每一點;不要順手重構無關程式碼", + "settingsPromptPlaceholderMerge": "例如:最終合併的提交訊息用繁體中文;手動解決過的衝突要另外說明", + "settingsPromptHintAll": "追加到每一次發給 agent 的提示詞,包括合併那一輪。", + "settingsPromptHintWork": "任務首次執行時追加。", + "settingsPromptHintRetry": "重試被中斷或失敗的任務時追加。", + "settingsPromptHintReturn": "對待驗收的任務繼續處理時追加(返工、追加工作、自查)。", + "settingsPromptHintMerge": "agent 把任務合併到基線分支時追加。", + "preflightPassed": "{name} 通過", + "preflightFailed": "{name} 未通過", + "preflightRunning": "{name} 執行中…", + "detailDescription": "任務詳情", + "detailSummary": "結果", + "detailFiles": "變更檔案", + "detailDiffAll": "檢視全部差異", + "detailDiffAllTitle": "全部差異", + "detailNoChanges": "相對基準還沒有變更", + "detailTimeline": "推進記錄", + "detailTimelineEmpty": "暫無活動", + "showMore": "展開", + "showLess": "收起", + "detailInfo": "詳情", + "detailBranch": "分支", + "detailMergeCommit": "合併提交", + "detailChanges": "變更", + "detailScheduled": "預計開始", + "detailCreated": "建立時間", + "detailStarted": "開始時間", + "detailFinished": "完成時間", + "diffLoading": "正在載入差異…", + "deleteConfirmTitle": "刪除任務?", + "deleteConfirmBody": "「{title}」將從看板移除。進行中的執行會先被取消。", + "deleteWithWorktree": "同時刪除其 worktree", + "eventCreated": "已建立", + "eventStatusChanged": "狀態變更", + "eventConfigEffective": "啟動配置", + "eventInitCommand": "初始化命令", + "eventAgentProgress": "Agent 進展", + "eventAgentVerdict": "Agent 結論", + "eventMergeAttempt": "開始合併", + "eventMergeQueued": "加入合併佇列", + "eventMergeConflict": "合併衝突", + "eventPreflight": "預檢", + "eventCleanupFailed": "worktree 清理失敗", + "eventResumeFallback": "會話恢復失敗,已改用新會話", + "eventUserAction": "使用者操作", + "eventDiffStat": "變更快照" + }, + "CustomSkillsSettings": { + "loading": "正在載入自訂技能…", + "category": "自訂", + "searchPlaceholder": "依名稱、ID 或描述搜尋自訂技能", + "states": { + "not_linked": "未啟用", + "linked_to_codeg": "已啟用", + "linked_elsewhere": "連結到其他位置", + "blocked_by_real_directory": "被同名實體目錄佔用", + "broken": "連結已失效" + }, + "actions": { + "new": "新增", + "import": "匯入", + "importFromAgent": "從 Agent 匯入", + "cancel": "取消", + "save": "儲存" + }, + "rowMenu": { + "edit": "編輯", + "duplicate": "複製為新技能", + "delete": "刪除" + }, + "bulk": { + "delete": "刪除所選" + }, + "editor": { + "createTitle": "新增自訂技能", + "editTitle": "編輯自訂技能", + "description": "自訂技能存放於共用庫(~/.codeg/skills),可為任意智能體啟用。", + "idLabel": "技能 ID", + "idPlaceholder": "例如 my-workflow", + "contentLabel": "SKILL.md", + "contentPlaceholder": "在此撰寫技能的 SKILL.md…", + "preview": "預覽", + "edit": "編輯", + "emptyBody": "尚無內容。" + }, + "duplicate": { + "title": "複製技能", + "description": "以「{id}」為範本,以新 ID 建立一份副本。", + "newIdPlaceholder": "新技能 ID", + "confirm": "複製" + }, + "import": { + "title": "選擇要匯入的技能資料夾" + }, + "importFromAgent": { + "title": "從 Agent 匯入技能", + "description": "將某個 Agent 自己的技能複製到共享庫,即可為任意 Agent 啟用。", + "agentLabel": "Agent", + "agentPlaceholder": "選擇一個 Agent", + "selectAll": "全選({count})", + "loading": "正在載入該 Agent 的技能…", + "unsupported": "此 Agent 未提供技能目錄。", + "empty": "此 Agent 沒有可匯入的技能。", + "alreadyInLibrary": "已在庫中", + "confirm": "匯入所選({count})" + }, + "delete": { + "title": "刪除自訂技能?", + "body": "將從中央庫移除 {count} 個自訂技能,並解除它們在所有智能體中的連結。此操作無法復原。", + "confirm": "刪除" + }, + "toasts": { + "loadFailed": "載入技能失敗", + "idRequired": "請輸入技能 ID", + "created": "已建立自訂技能", + "updated": "已更新自訂技能", + "saveFailed": "儲存技能失敗", + "imported": "已匯入技能", + "importFailed": "匯入技能失敗", + "duplicated": "已複製技能", + "duplicateFailed": "複製技能失敗", + "deleted": "已刪除 {count} 個技能", + "deletedPartial": "已刪除 {ok} 個,{failed} 個失敗", + "deleteFailed": "刪除技能失敗", + "importedFromAgent": "已匯入 {count} 個技能", + "importedFromAgentPartial": "已匯入 {ok} 個,{failed} 個失敗", + "importFromAgentAllSkipped": "無需匯入——{count} 個已在庫中", + "importFromAgentFailed": "從 Agent 匯入失敗" + } + }, + "CodexModelEditor": { + "customizedNotice": "你已自訂模型清單,codeg 將接管 codex 的完整模型表。codex 日後新增的官方模型不會自動出現——點擊下方重新整理並再次儲存即可同步。清空所有自訂即可交回 codex 自動更新。", + "officialsTitle": "官方模型", + "officialsHint": "自動納入你啟動的 codex 的官方模型;可刪除不需要的。", + "officialsEmpty": "暫無官方模型。", + "refresh": "從 codex 重新整理", + "readdOfficial": "重新加入官方", + "customsTitle": "自訂模型", + "customsEmpty": "暫無自訂模型。", + "addCustom": "新增自訂", + "slugPlaceholder": "模型 id(slug)", + "displayNamePlaceholder": "顯示名稱", + "contextWindow": "上下文", + "makeDefault": "設為預設", + "defaultHint": "預設模型", + "remove": "移除", + "advanced": "進階", + "baseTemplate": "基礎範本", + "baseTemplateHint": "從哪個官方模型複製必填欄位(系統提示詞、工具、限制)。", + "groupBehavior": "行為與能力", + "fieldReasoningLevel": "預設推理強度", + "fieldReasoningSummary": "推理摘要", + "fieldVerbosity": "詳細程度", + "fieldShellType": "Shell 類型", + "fieldApplyPatch": "套用修補工具", + "fieldReasoningSummaries": "推理摘要支援", + "fieldSupportVerbosity": "詳細程度控制", + "fieldParallelToolCalls": "並行工具呼叫", + "fieldSearchTool": "網路搜尋工具", + "optNone": "無", + "groupInstructions": "描述與系統提示詞", + "fieldDescription": "描述", + "baseInstructions": "系統提示詞(base_instructions)" + }, + "DiagnosticsSettings": { + "title": "環境診斷", + "description": "檢查本應用在自身行程中如何解析該智能體的 CLI——這可能與你的終端機不同。", + "loading": "正在執行診斷…", + "error": "診斷失敗", + "rerun": "重新執行", + "copyAll": "複製全部", + "copied": "診斷資訊已複製到剪貼簿", + "button": "診斷", + "verdict": { + "ok": "環境正常。若仍提示未安裝,請徹底重新啟動應用以重新整理前綴快取。", + "node_missing": "在應用的 PATH 上找不到 Node.js。", + "npm_missing": "在應用的 PATH 上找不到 npm。", + "not_installed": "此智能體似乎尚未安裝。", + "installed_but_unresolved": "紀錄顯示已安裝,但應用無法定位其執行檔。", + "user_prefix_not_on_path": "安裝到了回退前綴(~/.codeg/npm-global),但它不在應用的 PATH 上。請徹底重新啟動應用後再試。", + "homebrew_bin_not_on_path": "安裝在 Homebrew 的 bin 目錄下,但它不在應用的 PATH 上(Apple Silicon keg 拆分)。", + "terminal_only_path": "此命令在你的終端機能解析,但在應用中不能——這是 GUI PATH 差異。請從終端機啟動應用,或在智能體設定中重新安裝。", + "npm_prefix_timeout": "npm prefix -g 太慢(超過 1.5 秒),已略過回退偵測。請重新啟動應用後再試。", + "node_too_old": "目前 Node.js 版本低於此智能體的要求。請升級 Node.js。", + "adapter_missing_native_present": "你本機的 {agent} CLI 確實安裝了,但 Codeg 啟動的是另一個 ACP 轉接器套件,而它還沒安裝。到「智能體設定」中安裝即可 —— 它不會動到你的 CLI,登入狀態也是共用的。", + "adapter_missing": "Codeg 為 {agent} 啟動的是獨立的 ACP 轉接器套件,目前尚未安裝。請到「智能體設定」中安裝 —— 只安裝廠商 CLI 是不夠的。" + } + }, + "TokenUsage": { + "title": "Token 用量", + "rangeLabel": "時間範圍", + "range7d": "近 7 天", + "range30d": "近 30 天", + "range90d": "近 90 天", + "rangeThisMonth": "本月", + "rangeThisYear": "今年", + "rangeAll": "全部", + "rangeCustom": "自訂", + "moreRanges": "更多", + "customRangePick": "選擇日期範圍", + "bucketLabel": "統計粒度", + "bucketDay": "依天", + "bucketWeek": "依週", + "bucketMonth": "依月", + "bucketUnitDay": "天", + "bucketUnitWeek": "週", + "bucketUnitMonth": "月", + "folderFilter": "資料夾", + "allFolders": "全部資料夾", + "agentFilter": "智慧代理", + "allAgents": "全部智慧代理", + "modelFilter": "模型", + "allModels": "全部模型", + "searchPlaceholder": "搜尋…", + "noMatches": "沒有符合項目", + "clearFilter": "清除選擇", + "resetFilters": "重設篩選", + "refresh": "重新整理", + "rebuild": "全量重建", + "rebuildHint": "捨棄已統計的資料並重新解析全部工作階段紀錄。當紀錄被 codeg 以外的 CLI 追加過時使用。", + "syncing": "正在統計工作階段…", + "syncProgress": "{done} / {total}", + "syncDone": "已統計 {synced} 個工作階段", + "syncFailed": "部分工作階段讀取失敗", + "syncBusy": "已有一次重新整理進行中", + "lastSynced": "更新於 {time}", + "lastSyncedNever": "尚未統計", + "tileTotal": "總 Token", + "tileSessions": "工作階段數", + "tileTurns": "對話輪次", + "tileActiveDays": "活躍天數", + "tileGenTime": "生成時長", + "vsPrevious": "對比上一週期", + "deltaNew": "新增", + "trendTitle": "用量趨勢", + "trendEmpty": "此範圍內沒有用量", + "trendTurns": "輪次", + "trendSessions": "工作階段", + "compositionTitle": "Token 花在哪裡", + "compositionHint": "輸入是你送出的內容,輸出是模型寫回來的,快取讀取則是不必再按原價重送的上下文。", + "compositionNote": "這些快取命中若按原價重送,要多花 {value}。", + "inputTokens": "輸入", + "outputTokens": "輸出", + "cacheWrite": "快取寫入", + "cacheRead": "快取讀取", + "freshTokens": "新算 Token", + "cacheHitCaption": "快取命中", + "cacheHeroTitleHigh": "上下文大多不必重送", + "cacheHeroTitleLow": "多數上下文仍按原價計算", + "cacheHeroDesc": "{cached} 的上下文由快取承擔,這段時間真正新算的只有 {fresh}。", + "cacheSavedSuffix": "省下的重送量相當於 {saved}。", + "avgPerSession": "平均每工作階段", + "avgTurnsPerSession": "平均每個工作階段 {count} 輪", + "avgPerActiveDay": "平均每活躍日", + "peakBucket": "最高的一{bucket}", + "peakHour": "尖峰時段", + "daysValue": "{count} 天", + "idleDays": "空轉天數", + "byFolderTitle": "依資料夾", + "byAgentTitle": "依智慧代理", + "byModelTitle": "依模型", + "distributionTitle": "用量分布", + "distributionHint": "工作階段與 Token 依所選維度歸集,點任一列可依它篩選。", + "otherLabel": "其他", + "unknownModel": "未標註模型", + "emptyBreakdown": "尚無紀錄", + "sessionsCount": "{count} 個工作階段", + "heatmapTitle": "你的編碼作息", + "heatmapHint": "依本地星期與小時統計的 Token 分佈。", + "heatmapPeakHint": "最密集的時段在 {hour}:00 前後。", + "less": "少", + "more": "多", + "heatmapCell": "{weekday} {hour}:00 — {value} tokens", + "weekMon": "一", + "weekTue": "二", + "weekWed": "三", + "weekThu": "四", + "weekFri": "五", + "weekSat": "六", + "weekSun": "日", + "topSessionsTitle": "消耗最高的工作階段", + "untitledSession": "未命名工作階段", + "topSessionsEmpty": "此範圍內沒有工作階段", + "streakLongest": "最長連續", + "streakLongestDays": "最長連續 {count} 天", + "share": "分享", + "moreActions": "更多操作", + "shareDialogTitle": "分享你的用量卡片", + "shareDialogHint": "卡片內容就是你目前所選的時間範圍與篩選條件。", + "shareSave": "儲存圖片", + "shareCopy": "複製圖片", + "shareCopied": "已複製到剪貼簿", + "shareSaved": "圖片已儲存", + "shareFailed": "圖片產生失敗", + "shareRendering": "產生中…", + "cardHeading": "我的 AI 編碼戰績", + "cardRangeAll": "全部時間", + "cardTotalLabel": "累計 Token", + "cardFooter": "由 codeg 產生", + "cardTopModels": "常用模型", + "cardTopProjects": "主力專案", + "archetypeNightOwl": "深夜工程師", + "archetypeNightOwlDesc": "{percent}% 的 Token 燒在天黑之後。", + "archetypeEarlyBird": "清晨型選手", + "archetypeEarlyBirdDesc": "{percent}% 的 Token 在早上 9 點前就用掉了。", + "archetypeWeekendWarrior": "週末戰士", + "archetypeWeekendWarriorDesc": "{percent}% 的 Token 發生在週末。", + "archetypeCacheMaster": "快取大師", + "archetypeCacheMasterDesc": "{percent}% 的上下文來自快取。", + "archetypeMarathoner": "長跑選手", + "archetypeMarathonerDesc": "連續 {days} 天沒有中斷。", + "archetypePolyglot": "多面手", + "archetypePolyglotDesc": "{count} 個智慧代理都在主力使用。", + "archetypeLaserFocus": "專注一役", + "archetypeLaserFocusDesc": "{percent}% 的 Token 投在同一個專案上。", + "archetypeDeepDiver": "深潛者", + "archetypeDeepDiverDesc": "平均每個工作階段 {averageK}K tokens。", + "archetypeSteady": "穩定輸出", + "archetypeSteadyDesc": "累計 {days} 天在寫程式。", + "emptyTitle": "還沒有可統計的資料", + "emptyHint": "codeg 直接從各智慧代理自己的工作階段紀錄讀取 Token 數。點一下重新整理,把本機已有的紀錄統計進來。", + "emptyAction": "統計我的工作階段", + "loadFailed": "用量載入失敗", + "truncatedNotice": "此範圍過大 —— 下面的數字只涵蓋其中最近的一段。" + } +} diff --git a/src/lib/api.ts b/src/lib/api.ts index 9b547f2cf..cbb475855 100644 --- a/src/lib/api.ts +++ b/src/lib/api.ts @@ -4401,6 +4401,9 @@ export interface DelegationSettings { /** Per-parent byte budget (in MB) for the broker's in-memory cache of * completed sub-agent result text. `0` = unlimited. */ completed_cache_max_mb: number + /** When true, agents may spawn a listed sub-agent without an `@` mention. + * An `@` mention is still always honored. */ + allow_self_initiate?: boolean /** Optional per-agent overrides applied when codeg-mcp spawns a subagent. * Keyed by `agent_type`. Missing entries mean "use agent defaults." */ agent_defaults?: Partial> From 1cffef1332730f30bdc1d1c2b83b4c84851b0156 Mon Sep 17 00:00:00 2001 From: Adam Dalloul <47503782+Adam-Dalloul@users.noreply.github.com> Date: Sun, 16 Aug 2026 10:09:26 -0700 Subject: [PATCH 3/3] chore: keep locale and broker diffs LF-only --- src-tauri/src/acp/delegation/broker.rs | 16990 +++++++++++------------ src/i18n/messages/ar.json | 9916 ++++++------- src/i18n/messages/de.json | 9916 ++++++------- src/i18n/messages/en.json | 9916 ++++++------- src/i18n/messages/es.json | 9916 ++++++------- src/i18n/messages/fr.json | 9916 ++++++------- src/i18n/messages/ja.json | 9916 ++++++------- src/i18n/messages/ko.json | 9916 ++++++------- src/i18n/messages/pt.json | 9916 ++++++------- src/i18n/messages/zh-CN.json | 9916 ++++++------- src/i18n/messages/zh-TW.json | 9916 ++++++------- 11 files changed, 58075 insertions(+), 58075 deletions(-) diff --git a/src-tauri/src/acp/delegation/broker.rs b/src-tauri/src/acp/delegation/broker.rs index ca11e5ea2..3d078451b 100644 --- a/src-tauri/src/acp/delegation/broker.rs +++ b/src-tauri/src/acp/delegation/broker.rs @@ -1,8495 +1,8495 @@ -//! `DelegationBroker` — the coordination unit for multi-agent delegation. -//! -//! Delegation is **asynchronous**: `delegate_to_agent` returns a `task_id` -//! ack as soon as setup finishes; the LLM collects the result later with -//! `get_delegation_status` (optionally long-polling) or stops it with -//! `cancel_delegation`. There is no blocking `oneshot` — a running task is just -//! an entry in the `running` map, and a terminal event migrates it into the -//! `completed` cache (atomically, under one lock) and wakes any long-poll via -//! `result_notify`. -//! -//! Lifecycle of a single task: -//! -//! 1. [`DelegationBroker::start_delegation`] is the broker's entry point. The -//! MCP listener feeds it the LLM-issued `delegate_to_agent` payload. -//! 2. Pre-checks: feature enabled? depth limit ok? Both failures return a -//! terminal report immediately, no child session created. -//! 3. Spawn the child via [`ConnectionSpawner::spawn`]. -//! 4. Send the delegation task as the first prompt via -//! [`ConnectionSpawner::send_prompt_linked_for_delegation`]. The trailing -//! [`DelegationLink`] carries the parent's `tool_use_id` and a -//! broker-internal `call_id` (UUID = `task_id`) — persisted onto the new -//! conversation row so the lifecycle resolver can find it. -//! 5. Register a [`RunningTask`] keyed by `call_id` and return a `Running` ack -//! [`DelegationTaskReport`] (or a terminal report when the child finished -//! during setup / a cancel reached it mid-setup / setup itself failed). -//! 6. Later, a terminal event resolves the task — migrating it `running` → -//! `completed` and tearing the child down: -//! - the lifecycle calling [`DelegationBroker::complete_call`] on -//! `TurnComplete` (happy path), or -//! - a cancel — MCP-side (`notifications/cancelled` → -//! [`DelegationBroker::cancel_by_external_handle`]), child-side -//! ([`DelegationBroker::cancel_by_child_connection`]), parent-side -//! ([`DelegationBroker::cancel_by_parent`] / -//! [`DelegationBroker::cancel_by_parent_turn`]), or the LLM's own -//! [`DelegationBroker::cancel_task_by_id`]. -//! -//! v1 is explicitly one-shot — no session reuse. -//! -//! Result durability: child output is NOT stored in codeg's DB, so the broker -//! caches the completed text in `completed` (parent-scoped, FIFO-capped). Once -//! evicted, [`DelegationBroker::get_task_status`] falls back to the DB for the -//! task's terminal STATUS (via [`ChildStatusLookup`]); the full output is always -//! viewable in the child's own session. -//! -//! Cancellation cascade: when a parent session goes away (user-initiated -//! cancel, parent disconnect), the lifecycle subscriber calls -//! [`DelegationBroker::cancel_by_parent`] which fans out cancel + disconnect -//! to every running child of that parent. A normal `end_turn` does NOT cancel -//! children — they keep running in the background (the whole point of async). - -use std::collections::{BTreeMap, HashMap, HashSet, VecDeque}; -use std::sync::atomic::{AtomicBool, Ordering}; -use std::sync::Arc; -use std::time::{Duration, Instant}; - -use async_trait::async_trait; -use tokio::sync::{Mutex, Notify}; - -use crate::acp::delegation::event_emitter::{DelegationEventEmitter, NoopEventEmitter}; -use crate::acp::delegation::live_reply::{ChildLiveReplyLookup, NoopChildLiveReplyLookup}; -use crate::acp::delegation::meta_writer::{ - build_delegation_meta, is_synthetic_parent_tool_use_id, DelegationMetaWriter, NoopMetaWriter, -}; -use crate::acp::delegation::spawner::{ConnectionSpawner, DelegationLink}; -use crate::acp::delegation::types::{ - AgentDelegationDefaults, BlockedKind, BlockedOn, DelegationError, DelegationOutcome, - DelegationRequest, DelegationTaskReport, TaskStatus, -}; -use crate::acp::types::DelegationResultSummary; -use crate::models::AgentType; - -/// Default per-parent byte budget for cached completed-task result text. The -/// completed-cache lets `get_delegation_status` / `cancel_delegation` return a -/// finished task's result after the lifecycle resolved it; once a parent's -/// retained result text exceeds this budget the OLDEST results are FIFO-evicted -/// (evicted tasks fall back to the DB status lookup, which carries status only). -/// This is the seed value baked into `DelegationConfig::default()`; the live -/// value is user-configurable from the settings page (in MB) and `0` disables -/// eviction entirely. See `PendingInner::completed_cap_bytes`. -const DEFAULT_COMPLETED_CACHE_CAP_BYTES: usize = 512 * 1024 * 1024; - -/// Per-result cap on cached completed text. The full child output always lives -/// in the child's own session (viewable via the frontend's child-session -/// sheet); this only bounds the broker's in-memory copy of a SINGLE result. -/// Because it is far below the per-parent byte budget -/// (`DEFAULT_COMPLETED_CACHE_CAP_BYTES`), the newest result always fits and is -/// never the eviction victim in `insert_completed`. -const COMPLETED_TEXT_CAP: usize = 256 * 1024; - -/// Cap on the `task_preview` carried by the `DelegationStarted` event and the -/// parent-card meta writes. The full task text lives in the MCP call (and, on -/// most hosts, in the parent tool call's own `raw_input`); the preview only -/// has to label the delegation card, so it shares the status-preview budget -/// rather than the multi-KiB result cap. -const TASK_PREVIEW_CAP: usize = 2 * 1024; - -/// Cap on the inline `text_preview` carried by the `DelegationCompleted` event -/// and the terminal meta, so the parent card can render the result inline -/// without re-fetching the child session. -const STATUS_PREVIEW_CAP: usize = 2 * 1024; - -/// Lookup the `parent_id` for a conversation. Abstracted so the broker can be -/// unit-tested against an in-memory chain without touching SeaORM. -#[async_trait] -pub trait ConversationDepthLookup: Send + Sync { - async fn parent_of(&self, conversation_id: i32) -> Result, DelegationError>; -} - -/// Status-level facts the broker recovers from a child conversation row when a -/// task's in-memory completed-cache entry was evicted. Carries NO result text — -/// child output isn't stored in codeg's DB; the full result lives in the -/// child's own session (viewable via the frontend's child-session sheet). -#[derive(Debug, Clone)] -pub struct ChildStatusRecord { - pub child_conversation_id: i32, - pub status: TaskStatus, - pub agent_type: AgentType, - /// The parent conversation id this child was spawned under. Used to scope - /// the DB fallback to the calling parent so one parent can't read another's - /// task by guessing a UUID. - pub parent_id: Option, -} - -/// DB fallback for `get_delegation_status` / `cancel_delegation` once a task's -/// result has aged out of the broker's in-memory completed-cache. Abstracted -/// so broker unit tests can run without SeaORM; production wires -/// [`DbChildStatusLookup`] via [`DelegationBroker::with_status_lookup`]. -#[async_trait] -pub trait ChildStatusLookup: Send + Sync { - async fn find_by_call_id(&self, call_id: &str) -> Option; -} - -/// Default lookup — always "unknown". Used by `DelegationBroker::new` / -/// `with_writers` (tests that don't exercise the DB-fallback path); production -/// replaces it via `with_status_lookup`. -#[derive(Default, Clone)] -pub struct NoopChildStatusLookup; - -#[async_trait] -impl ChildStatusLookup for NoopChildStatusLookup { - async fn find_by_call_id(&self, _call_id: &str) -> Option { - None - } -} - -#[derive(Debug, Clone)] -pub struct DelegationConfig { - pub enabled: bool, - /// Max chain depth a *new* delegation may exist at. With `depth_limit = 2` - /// the chain root → child → grandchild is allowed; the grandchild trying - /// to spawn a great-grandchild is rejected. See spec §5. - pub depth_limit: u32, - /// Per-agent overrides applied when spawning a delegation child. Keyed by - /// the target `agent_type`; missing entries mean "no override." Forwarded - /// to `ConnectionSpawner::spawn` as `preferred_mode_id` / - /// `preferred_config_values`. - pub agent_defaults: BTreeMap, - /// Per-parent byte budget for cached completed-task result text. `0` - /// disables eviction (unlimited). Surfaced from the settings page in MB and - /// converted to bytes in `into_broker_config`. Pushed into the pending-calls - /// bucket by `set_config` so `insert_completed` reads it lock-free. - pub completed_cache_cap_bytes: usize, -} - -impl Default for DelegationConfig { - fn default() -> Self { - Self { - enabled: false, - depth_limit: 1, - agent_defaults: BTreeMap::new(), - completed_cache_cap_bytes: DEFAULT_COMPLETED_CACHE_CAP_BYTES, - } - } -} - -/// A delegation task running in the background after `start_delegation` -/// returned its `Running` ack. The async redesign drops the parked -/// `oneshot::Sender` the old `PendingCall` carried: the parent's -/// `delegate_to_agent` no longer blocks on a channel, so there is nothing to -/// signal. A terminal event instead migrates the entry into `completed` (same -/// lock) and wakes any `get_delegation_status` long-poll via the broker's -/// `result_notify`. -struct RunningTask { - child_connection_id: String, - child_conversation_id: i32, - parent_connection_id: String, - parent_tool_use_id: String, - /// Target agent — surfaced in status reports. - agent_type: AgentType, - /// Bounded preview of the delegated task text ([`TASK_PREVIEW_CAP`]). - /// Carried so TERMINAL meta writes can keep labeling the parent card — - /// meta is replace-wholesale on the ToolCallState, so a terminal write - /// that dropped the task text would erase what the running write supplied. - task_preview: String, - /// The broker-minted task id — duplicates this entry's key in `running` - /// because the cancel/teardown paths hand around the drained - /// `RunningTask` by value without its map key. - task_id: String, - /// MCP-side opaque handle minted by the companion per `tools/call`. The - /// listener forwards it through `DelegationRequest`; we keep it here so - /// `cancel_by_external_handle` can find the entry. `None` for delegations - /// that didn't come through MCP (tests, future internal callers). - external_handle: Option, - /// When the child started running (after `send_prompt` succeeded). Used to - /// compute a real `duration_ms` at terminal time. - started_at: Instant, - /// The last blocking prompt a status query reported to the parent, and when. - /// Makes "the block I told you about" distinguishable from "a NEW block", - /// which is what stops a `wait_ms: 0` poll from returning instantly forever - /// once a child parks on a permission (#447): the first observation - /// returns, a re-poll on the same prompt goes back to waiting, and a second - /// prompt returns again. - /// - /// The timestamp is the safety valve. Marking a block reported is not proof - /// the parent RECEIVED it — the report still has to cross the listener, the - /// companion's stdout and the agent CLI, and an MCP `notifications/cancelled` - /// or a client-side call abort discards it silently. Without the valve that - /// lost report would be the only one ever offered, re-creating the exact - /// stall this fixes. So the same unanswered prompt becomes reportable again - /// after [`BLOCK_RESURFACE_INTERVAL`]. - last_surfaced_block: Option, -} - -/// See [`RunningTask::last_surfaced_block`]. -struct SurfacedBlock { - request_id: String, - at: Instant, -} - -/// A terminal delegation result retained so `get_delegation_status` / -/// `cancel_delegation` can answer after the lifecycle resolved the task. -/// Parent-scoped, FIFO-evicted once the parent's retained result text exceeds -/// `PendingInner::completed_cap_bytes`, and dropped wholesale when the parent -/// connection tears down. -#[derive(Clone)] -struct CompletedTask { - parent_connection_id: String, - child_conversation_id: i32, - agent_type: AgentType, - status: TaskStatus, - /// Result text for `Completed` (capped at [`COMPLETED_TEXT_CAP`]). `None` - /// for failures/cancels. - text: Option, - error_code: Option, - message: Option, - duration_ms: u64, -} - -#[derive(Default)] -struct PendingCalls { - inner: Mutex, -} - -/// Everything guarded by the single pending-calls mutex. Co-locating the parked -/// calls with the early-terminal bookkeeping under ONE lock is what makes the -/// terminal-vs-registration race safe: a terminal event for a delegation that -/// is still mid-setup (its `handle_request` hasn't parked the [`PendingCall`] -/// yet) and the matching registration are serialized on this lock, so the -/// terminal event either finds the parked entry (resolves via `tx`) or buffers -/// its outcome (and `handle_request` drains it the instant it parks) — never -/// both, never neither. Without this, a terminal that fires in the spawn→park -/// window would no-op the resolver and then strand the parked `rx.await`. -/// -/// Both CHILD-terminal pre-park resolvers are covered, because either can win -/// the race against the parent `write_meta` await between `send_prompt` and the -/// park: -/// * `complete_call` — a fast/empty turn's `TurnComplete` (the prompt is only -/// *enqueued* by `send_prompt`; the child loop emits `TurnComplete` -/// independently). Keyed by `call_id`. -/// * `cancel_by_child_connection` — a freshly-spawned child connection dying -/// before its first prompt is answered. Keyed by `child_connection_id`. -/// -/// Parent-side cancels (`cancel_by_parent` / `cancel_by_parent_turn`) are -/// covered symmetrically by the `inflight` registry: `handle_request` registers -/// each setup at entry, and `mark_inflight_canceled_for_parent` runs in the SAME -/// lock acquisition that drains the parked `calls`. A parent cancel landing -/// while a child is still mid-setup therefore flags the in-flight record, and -/// `handle_request` observes the flag at its next checkpoint (or atomically at -/// park) and tears the child down itself — it is no longer left to the child's -/// own terminal / connection-teardown cascade. -/// -/// The reservation records the `child_connection_id` each resolver gates on; -/// `handle_request` drains both buffers at park. -#[derive(Default)] -struct PendingInner { - /// Tasks running in the background after their `Running` ack, keyed by - /// broker `call_id` (= `task_id`). A terminal event migrates an entry from - /// here into `completed` under THIS lock (atomic `running` → `completed` - /// transition), so a concurrent `get_delegation_status` never observes a - /// task as neither running nor completed. - running: HashMap, - /// Terminal results retained for `get_delegation_status` / `cancel_delegation`, - /// keyed by `task_id`. Bounded by the per-parent byte valve - /// (`completed_cap_bytes` over `completed_bytes`, FIFO-evicted via - /// `completed_order`) and dropped per-parent on connection teardown. - /// Evicted/unknown tasks fall back to the DB status lookup. - completed: HashMap, - /// Per-parent FIFO index over `completed` for byte-valve eviction and - /// per-parent teardown. Keyed by `parent_connection_id`; each deque holds - /// that parent's completed `task_id`s oldest-first. - completed_order: HashMap>, - /// Per-parent running total of retained completed result-text bytes (the - /// `CompletedTask::text` lengths). Drives the `completed_cap_bytes` valve in - /// `insert_completed`; kept in sync on insert/evict and cleared per-parent - /// on teardown. - completed_bytes: HashMap, - /// Per-parent byte budget for retained completed result text. `0` = - /// unlimited (no eviction). Seeded by `set_config` from the live - /// `DelegationConfig` (default until then: `0`, but `set_config` always runs - /// at startup via `apply_persisted_config`). Read lock-free by - /// `insert_completed`, which already holds THIS mutex — so the cap is - /// consulted WITHOUT nesting the `config` lock under the pending lock. - completed_cap_bytes: usize, - /// In-setup delegations (spawned + id minted, not yet parked), mapping - /// `call_id` → `child_connection_id`. Gating the early buffers on membership - /// here distinguishes a genuine pre-registration race (still reserved → - /// buffer) from the normal post-resolution teardown that fires on every - /// completion (no longer reserved → ignore). Removed at park / on the - /// send-failure path. - setups: HashMap, - /// Completion outcomes captured by a `TurnComplete` that beat registration - /// (gated by `setups`), keyed by `call_id`. Each carries the `seq` arrival - /// stamp taken when it buffered, so the park can order it against a racing - /// parent cancel (first-terminal-wins). Drained at park. - early_completes: HashMap, - /// Cancel reasons captured by a child failure that beat registration (gated - /// by `setups`), keyed by `child_connection_id`. The value pairs the `seq` - /// arrival stamp (for the park's first-terminal-wins ordering against a - /// racing parent cancel) with the pre-computed `Canceled { reason }` text - /// (same wording the parked `cancel_by_child_connection` path produces); - /// `handle_request` rebuilds the full outcome at park with the real - /// `child_conversation_id` (which the resolver, finding no entry, lacked). - early_cancels: HashMap, - /// In-flight `handle_request` setups, keyed by a unique per-call id and - /// registered at entry (BEFORE the claim poll, so the whole claim→park - /// window is covered). This is the parent-cancel counterpart to `setups`: - /// `setups` lets a *child* terminal reach a not-yet-parked delegation, - /// while `inflight` lets a *parent* cancel reach one. `cancel_by_parent*` - /// flags every entry it owns (`mark_inflight_canceled_for_parent`); - /// `handle_request` consults the flag after claim, after spawn, and - /// atomically at park, tearing the spawned child down itself when set. - /// Removed at park and on every early-return (no Drop guard — see - /// `register_inflight`). - inflight: HashMap, - /// Monotonic arrival clock (see `tick`). Hands out the unique `inflight` - /// keys AND the arrival stamps on buffered child terminals / parent cancels, - /// so the park can resolve a setup-window race by true first-terminal-wins - /// order. Keys and stamps share this sequence but are never cross-compared - /// (keys match by identity, stamps only by `<` against other stamps). - seq: u64, -} - -/// One in-flight `handle_request` setup tracked for parent-cancel coverage. -struct InflightSetup { - parent_connection_id: String, - /// `Some(stamp)` once a parent cancel lands while this delegation is - /// mid-setup (spawned / sending, not yet parked), where `stamp` is the `seq` - /// arrival-clock value at that moment. First-write-wins and never cleared, - /// so a cancel can't be lost between `handle_request`'s checkpoints, and its - /// stamp lets the park order it against a racing child terminal. - canceled_at: Option, -} - -impl PendingInner { - /// Mark a delegation as setting-up (spawned + id minted, not yet parked) so - /// a terminal event racing the park is buffered rather than dropped. - /// - /// No cap: a reservation lives only for the brief spawn→park window and is - /// always released by `unreserve` on every `handle_request` exit (park, or - /// the send-failure path), so `setups` is bounded by the count of - /// concurrently-in-setup delegations — it never accumulates stale entries. - /// A cap here would be actively unsafe: every reservation is live, so - /// evicting one to make room would drop a real in-flight delegation's race - /// guard and reopen the very hang this machinery exists to prevent. - fn reserve(&mut self, call_id: &str, child_connection_id: &str) { - self.setups - .insert(call_id.to_string(), child_connection_id.to_string()); - } - - /// Release a delegation's reservation and discard any un-drained buffered - /// terminal — called once the entry is parked (the buffers were already - /// drained, so the removals are no-ops then) or when setup errors out - /// (discarding a buffer no `handle_request` will pick up). - fn unreserve(&mut self, call_id: &str, child_connection_id: &str) { - self.setups.remove(call_id); - self.early_completes.remove(call_id); - self.early_cancels.remove(child_connection_id); - } - - /// Whether a child connection belongs to a still-in-setup delegation. O(n) - /// over `setups`, but n is the (tiny) count of concurrently-in-setup - /// delegations. - fn is_child_reserved(&self, child_connection_id: &str) -> bool { - self.setups - .values() - .any(|child| child == child_connection_id) - } - - /// Buffer a completion for a still-reserved delegation, stamped with the - /// current arrival clock so the park can order it against a racing parent - /// cancel. No-op when the `call_id` isn't reserved (already resolved by - /// another terminal path), so the buffer only ever holds genuine - /// pre-registration races. - fn buffer_early_complete(&mut self, call_id: &str, outcome: DelegationOutcome) { - if self.setups.contains_key(call_id) { - let stamp = self.tick(); - self.early_completes - .insert(call_id.to_string(), (stamp, outcome)); - } - } - - /// Buffer a child failure for a still-reserved delegation, stamped with the - /// current arrival clock so the park can order it against a racing parent - /// cancel. No-op when the child isn't reserved (normal post-resolution - /// teardown). Stores the pre-computed cancel reason so the park rebuilds the - /// same wording the parked `cancel_by_child_connection` path produces. - fn buffer_child_failure(&mut self, child_connection_id: &str, detail: Option) { - if self.is_child_reserved(child_connection_id) { - let stamp = self.tick(); - self.early_cancels.insert( - child_connection_id.to_string(), - (stamp, child_canceled_reason(detail.as_deref())), - ); - } - } - - /// Drain a buffered completion with its arrival stamp (by `call_id`) — used - /// by `handle_request` at park. - fn take_early_complete(&mut self, call_id: &str) -> Option<(u64, DelegationOutcome)> { - self.early_completes.remove(call_id) - } - - /// Drain a buffered cancel reason with its arrival stamp (by - /// `child_connection_id`) — used by `handle_request` at park. - fn take_early_cancel(&mut self, child_connection_id: &str) -> Option<(u64, String)> { - self.early_cancels.remove(child_connection_id) - } - - /// Advance the monotonic arrival clock, returning the pre-increment value. - /// Strictly increasing (wraps only after 2^64 calls — unreachable), so two - /// events stamped under this lock always compare in their true arrival - /// order. Backs both `inflight` keys and terminal/cancel arrival stamps; the - /// two uses never cross-compare (keys match by identity, stamps by `<`). - fn tick(&mut self) -> u64 { - let v = self.seq; - self.seq = self.seq.wrapping_add(1); - v - } - - /// Register an in-flight setup at `handle_request` entry, returning its - /// unique id. The caller MUST `deregister_inflight` on every exit path - /// (each early-return, and at park). There is deliberately NO Drop guard: - /// the park hand-off — `calls.insert` followed by `deregister_inflight` — - /// has to be atomic under this lock so a concurrent parent cancel sees the - /// entry in exactly one of `inflight` or `calls`, and a guard firing after - /// the lock releases would reopen that window. - fn register_inflight(&mut self, parent_connection_id: &str) -> u64 { - let id = self.tick(); - self.inflight.insert( - id, - InflightSetup { - parent_connection_id: parent_connection_id.to_string(), - canceled_at: None, - }, - ); - id - } - - /// Drop an in-flight setup record (idempotent). - fn deregister_inflight(&mut self, id: u64) { - self.inflight.remove(&id); - } - - /// Whether a parent cancel flagged this in-flight setup. False once the - /// record is gone (already parked / deregistered). Used by the pre-spawn / - /// post-spawn checkpoints, which only need the boolean. - fn inflight_canceled(&self, id: u64) -> bool { - self.inflight - .get(&id) - .map(|s| s.canceled_at.is_some()) - .unwrap_or(false) - } - - /// Arrival stamp of the parent cancel that flagged this in-flight setup, if - /// any (`None` when not canceled, or the record is already gone). Used at - /// park to order the cancel against a buffered child terminal. - fn inflight_canceled_at(&self, id: u64) -> Option { - self.inflight.get(&id).and_then(|s| s.canceled_at) - } - - /// Flag every in-flight setup owned by `parent_connection_id` as canceled, - /// stamping each with one shared arrival-clock value (this cancel is a - /// single event). First-write-wins per setup, so a later cancel can't push - /// an earlier one's stamp forward. Called from `drain_for_parent_cancel` in - /// the SAME lock acquisition that drains the parked `calls`, so each of the - /// parent's delegations is caught either here (still in-flight → flagged; - /// `handle_request` tears its child down at the next checkpoint) or by the - /// parked-call drain (already parked) — never neither. - fn mark_inflight_canceled_for_parent(&mut self, parent_connection_id: &str) { - let stamp = self.tick(); - for setup in self.inflight.values_mut() { - if setup.parent_connection_id == parent_connection_id && setup.canceled_at.is_none() { - setup.canceled_at = Some(stamp); - } - } - } - - /// Insert a terminal result into the completed-cache, then FIFO-evict this - /// parent's OLDEST results until its retained result-text bytes fit - /// `completed_cap_bytes` (`0` = unlimited). Evicted tasks fall back to the - /// DB status lookup (status only — child text lives in the child session). - /// The just-inserted entry is never the victim: a single result is capped - /// at [`COMPLETED_TEXT_CAP`] (256 KiB), far below any MB-scale budget, so - /// the newest result always survives for the LLM's immediate - /// `get_delegation_status`. The caller does the atomic `running.remove` + - /// this insert under one lock, then notifies long-poll waiters AFTER - /// releasing the lock. - fn insert_completed(&mut self, call_id: &str, task: CompletedTask) { - let parent = task.parent_connection_id.clone(); - let task_bytes = task.text.as_ref().map_or(0, |t| t.len()); - self.completed.insert(call_id.to_string(), task); - *self.completed_bytes.entry(parent.clone()).or_insert(0) += task_bytes; - self.completed_order - .entry(parent.clone()) - .or_default() - .push_back(call_id.to_string()); - self.evict_completed_over_cap(&parent); - } - - /// Evict `parent`'s OLDEST completed results until its retained result-text - /// bytes fit `completed_cap_bytes` (`0` = unlimited). Evicted tasks fall - /// back to the DB status lookup (status only — child text lives in the child - /// session). The newest entry is never evicted: a single result is capped at - /// [`COMPLETED_TEXT_CAP`] (256 KiB), far below any MB-scale budget, so the - /// LLM's immediate `get_delegation_status` always hits. - fn evict_completed_over_cap(&mut self, parent: &str) { - let cap = self.completed_cap_bytes; - if cap == 0 { - return; - } - loop { - if self.completed_bytes.get(parent).copied().unwrap_or(0) <= cap { - break; - } - let evicted = match self.completed_order.get_mut(parent) { - Some(order) if order.len() > 1 => order.pop_front(), - _ => None, - }; - let Some(evicted) = evicted else { - break; - }; - if let Some(removed) = self.completed.remove(&evicted) { - let freed = removed.text.as_ref().map_or(0, |t| t.len()); - if let Some(slot) = self.completed_bytes.get_mut(parent) { - *slot = slot.saturating_sub(freed); - } - } - } - } - - /// Re-apply the current `completed_cap_bytes` to EVERY parent. Called by - /// `set_config` when the cap may have been LOWERED at runtime, so - /// already-retained results are pruned promptly — insert-time eviction alone - /// would otherwise strand them until a parent's next completion (which may - /// never arrive). - fn enforce_completed_cap_all_parents(&mut self) { - if self.completed_cap_bytes == 0 { - return; - } - let parents: Vec = self.completed_bytes.keys().cloned().collect(); - for parent in parents { - self.evict_completed_over_cap(&parent); - } - } - - /// Forget every completed result for a parent. Called on connection - /// teardown (the parent is gone — nothing left to query). A turn cancel - /// deliberately does NOT call this: the connection stays alive and the LLM - /// may still query its just-canceled tasks. - fn drop_completed_for_parent(&mut self, parent_connection_id: &str) { - self.completed_bytes.remove(parent_connection_id); - if let Some(ids) = self.completed_order.remove(parent_connection_id) { - for id in ids { - self.completed.remove(&id); - } - } - } -} - -/// Cap result text retained in the completed-cache. The full output always -/// lives in the child session; this only bounds the broker's copy. -fn cap_completed_text(text: &str) -> String { - truncate_on_char_boundary(text, COMPLETED_TEXT_CAP) -} - -/// Build the bounded inline preview carried by the `DelegationCompleted` event -/// and terminal meta. `None` for empty text. -fn build_text_preview(text: &str) -> Option { - if text.trim().is_empty() { - return None; - } - Some(truncate_on_char_boundary(text, STATUS_PREVIEW_CAP)) -} - -/// Truncate `s` so the RESULT (including the appended ellipsis) is at most `cap` -/// bytes, cut on a UTF-8 char boundary. Reserving the ellipsis bytes keeps the -/// output within the advertised cap rather than `cap + 3`. -fn truncate_on_char_boundary(s: &str, cap: usize) -> String { - if s.len() <= cap { - return s.to_string(); - } - const ELLIPSIS: &str = "…"; - // Leave room for the ellipsis; clamp at 0 for pathologically small caps. - let budget = cap.saturating_sub(ELLIPSIS.len()); - let mut end = budget.min(s.len()); - while end > 0 && !s.is_char_boundary(end) { - end -= 1; - } - format!("{}{ELLIPSIS}", &s[..end]) -} - -/// Derive the completed-cache fields (status / text / error_code / message) -/// from a resolved [`DelegationOutcome`]. `Canceled`-coded errors map to -/// [`TaskStatus::Canceled`]; every other error maps to [`TaskStatus::Failed`]. -fn terminal_fields( - outcome: &DelegationOutcome, -) -> (TaskStatus, Option, Option, Option) { - match outcome { - DelegationOutcome::Ok(ok) => ( - TaskStatus::Completed, - Some(cap_completed_text(&ok.text)), - None, - None, - ), - DelegationOutcome::Err { code, message, .. } => { - let status = if code == "canceled" { - TaskStatus::Canceled - } else { - TaskStatus::Failed - }; - (status, None, Some(code.clone()), Some(message.clone())) - } - } -} - -/// Build a [`CompletedTask`] from a resolved outcome for the completed-cache. -fn build_completed( - parent_connection_id: &str, - child_conversation_id: i32, - agent_type: AgentType, - duration_ms: u64, - outcome: &DelegationOutcome, -) -> CompletedTask { - let (status, text, error_code, message) = terminal_fields(outcome); - CompletedTask { - parent_connection_id: parent_connection_id.to_string(), - child_conversation_id, - agent_type, - status, - text, - error_code, - message, - duration_ms, - } -} - -/// A `canceled`-coded [`DelegationOutcome`] carrying the child conversation id. -fn canceled_outcome(child_conversation_id: i32, reason: &str) -> DelegationOutcome { - DelegationOutcome::from_err( - DelegationError::Canceled { - reason: reason.to_string(), - }, - Some(child_conversation_id), - ) -} - -/// Remove `keys` from `running`, recording each as a `Canceled` completed entry -/// (so a `get_delegation_status` still answers) and returning the drained tasks -/// — each paired with the `duration_ms` captured at this drain point — for I/O -/// teardown. MUST be called with the pending lock held so the running → -/// completed migration is atomic. -/// -/// The duration is captured ONCE here and returned so the slow teardown -/// (parent-card meta, report) reuses the exact value recorded into the -/// completed-cache, rather than recomputing `started_at.elapsed()` later — which -/// would inflate it for the backgrounded `cancel_by_parent_turn` teardown and -/// disagree with the `get_delegation_status` / `cancel_delegation` cards. -fn drain_and_record_canceled( - inner: &mut PendingInner, - keys: Vec, - reason: &str, -) -> Vec<(RunningTask, u64)> { - let mut out = Vec::with_capacity(keys.len()); - for k in keys { - let task = inner.running.remove(&k).expect("key just observed"); - let outcome = canceled_outcome(task.child_conversation_id, reason); - let duration_ms = task.started_at.elapsed().as_millis() as u64; - inner.insert_completed( - &k, - build_completed( - &task.parent_connection_id, - task.child_conversation_id, - task.agent_type, - duration_ms, - &outcome, - ), - ); - out.push((task, duration_ms)); - } - out -} - -/// Project a `DelegationOutcome` + broker-measured `duration_ms` onto the -/// wire-stable `DelegationResultSummary` carried by `DelegationCompleted`. -/// Keeps the mapping (and the bounded `text_preview`) in one place. -fn outcome_to_summary(outcome: &DelegationOutcome, duration_ms: u64) -> DelegationResultSummary { - match outcome { - DelegationOutcome::Ok(ok) => DelegationResultSummary::Ok { - duration_ms, - text_preview: build_text_preview(&ok.text), - }, - DelegationOutcome::Err { code, .. } => DelegationResultSummary::Err { - error_code: code.clone(), - }, - } -} - -/// Project a resolved outcome onto a terminal [`DelegationTaskReport`] (used by -/// the setup-window terminal dispositions and the test shim). -fn report_from_outcome( - task_id: Option, - agent_type: Option, - outcome: &DelegationOutcome, - duration_ms: Option, -) -> DelegationTaskReport { - let (status, text, error_code, message) = terminal_fields(outcome); - let child_conversation_id = match outcome { - DelegationOutcome::Ok(ok) => Some(ok.child_conversation_id), - DelegationOutcome::Err { - child_conversation_id, - .. - } => *child_conversation_id, - }; - DelegationTaskReport { - task_id, - status, - child_conversation_id, - agent_type, - text, - error_code, - message, - duration_ms, - // Terminal by construction — nothing is waiting on the user anymore. - blocked_on: None, - } -} - -/// Build a `Failed`/`Canceled` report for a setup error (no task id — setup -/// failed before/around registration, so the LLM has no task to track). -fn report_err( - agent_type: AgentType, - err: DelegationError, - child_conversation_id: Option, -) -> DelegationTaskReport { - let outcome = DelegationOutcome::from_err(err, child_conversation_id); - report_from_outcome(None, Some(agent_type), &outcome, None) -} - -/// The `Running` ack returned by `start_delegation` for a backgrounded task. -fn running_ack( - call_id: String, - child_conversation_id: i32, - agent_type: AgentType, -) -> DelegationTaskReport { - // Embed the literal task_id in the message so it survives clients that only - // surface the MCP `content` text (not `structuredContent`) — without it the - // LLM couldn't call get_delegation_status / cancel_delegation. - let message = format!( - "Delegation successful. task_id={call_id}. Call get_delegation_status \ - with this id in the task_ids array (optionally wait_ms) to collect the \ - result, or cancel_delegation to stop it." - ); - DelegationTaskReport { - task_id: Some(call_id), - status: TaskStatus::Running, - child_conversation_id: Some(child_conversation_id), - agent_type: Some(agent_type), - text: None, - error_code: None, - message: Some(message), - duration_ms: None, - blocked_on: None, - } -} - -/// How long [`DelegationBroker::get_task_status`] may block before returning the -/// current (possibly still-running) snapshot. Derived by the listener from the -/// MCP tool's `wait_ms`: omitted → [`Immediate`], an explicit `0` → [`Infinite`], -/// any positive value → [`Bounded`] (clamped to the listener's hard ceiling). -/// -/// [`Immediate`]: StatusWait::Immediate -/// [`Bounded`]: StatusWait::Bounded -/// [`Infinite`]: StatusWait::Infinite -#[derive(Debug, Clone, Copy, PartialEq, Eq)] -pub enum StatusWait { - /// Return the current snapshot right away — the default poll. - Immediate, - /// Block up to this many milliseconds, then return whatever snapshot we have - /// (the child keeps running past the deadline; the caller re-issues to wait - /// more). - Bounded(u64), - /// Block until the task reaches a terminal state — never time out. Lets a - /// long-running child be awaited in a single call. A parent disconnect or - /// cancel also drives the task terminal (and fires the completion signal), - /// so this never outlives the task itself. - Infinite, -} - -/// How long an already-reported blocking prompt stays suppressed before a -/// status long-poll will surface it again. Two jobs: it keeps a `wait_ms: 0` -/// caller from spinning on a block it has already been told about, and it -/// bounds the damage when a report is generated but never delivered (see -/// [`RunningTask::last_surfaced_block`]) — a lost report costs a delayed notice -/// instead of a permanent stall. Long relative to a human noticing a prompt, -/// short relative to walking away from the machine. -const BLOCK_RESURFACE_INTERVAL: Duration = Duration::from_secs(300); - -/// Second line of a blocked running report's message. The frontend anchors on -/// this exact prefix to keep recognizing the poll as "running" on hosts that -/// persist only the `CallToolResult` content text — see `textRunningStatus` in -/// `src/lib/delegation-status.ts`. Backend protocol string, never localized. -const BLOCKED_LINE_PREFIX: &str = "Awaiting your decision:"; - -/// Mark a running report as parked on a user decision: set the structured -/// `blocked_on` and replace the bare `"Running."` message with a two-line -/// version naming what needs answering. -/// -/// The note goes on its OWN line, for the same reason the live-reply hint does: -/// content-only hosts recognize a still-running poll by the standalone first -/// line `"Running."`, so a *completed* result whose text happens to start with -/// "Running. …" can never be misread as running. -fn attach_blocked(report: &mut DelegationTaskReport, blocked: BlockedOn) { - let what = match (&blocked.kind, blocked.title.as_deref()) { - (_, Some(title)) => title.to_string(), - (BlockedKind::Permission, None) => "a tool permission".to_string(), - (BlockedKind::Question, None) => "a question".to_string(), - (BlockedKind::PlanApproval, None) => "a plan approval".to_string(), - }; - // The third line is guidance for the orchestrating LLM, in the same spirit - // as `running_ack`'s "call get_delegation_status with this id". Keep it in - // step with the tool description in `tool_schema.json`. - report.message = Some(format!( - "Running.\n{BLOCKED_LINE_PREFIX} {what}\nThe sub-agent is parked until \ - a human answers in Codeg — it is not making progress. Tell the user, \ - then wait again." - )); - report.blocked_on = Some(blocked); -} - -/// Status report for a still-running task. -fn running_report(task_id: &str, task: &RunningTask) -> DelegationTaskReport { - DelegationTaskReport { - task_id: Some(task_id.to_string()), - status: TaskStatus::Running, - child_conversation_id: Some(task.child_conversation_id), - agent_type: Some(task.agent_type), - text: None, - error_code: None, - // Bare baseline; `get_task_status` upgrades this to a two-line - // "Running.\nLatest sub-agent reply: …" when the child has live output. - message: Some("Running.".to_string()), - duration_ms: None, - blocked_on: None, - } -} - -/// Status report from a cached completed result. -fn completed_report(task_id: &str, c: &CompletedTask) -> DelegationTaskReport { - DelegationTaskReport { - task_id: Some(task_id.to_string()), - status: c.status, - child_conversation_id: Some(c.child_conversation_id), - agent_type: Some(c.agent_type), - text: c.text.clone(), - error_code: c.error_code.clone(), - message: c.message.clone(), - duration_ms: Some(c.duration_ms), - blocked_on: None, - } -} - -/// Status report when a task id isn't known to the caller (never existed, -/// owned by a different parent, or evicted with no DB record). -fn unknown_report(task_id: &str) -> DelegationTaskReport { - DelegationTaskReport { - task_id: Some(task_id.to_string()), - status: TaskStatus::Unknown, - child_conversation_id: None, - agent_type: None, - text: None, - error_code: None, - message: Some( - "Unknown task id — it never existed, isn't owned by this session, \ - or its result was evicted with no stored record." - .to_string(), - ), - duration_ms: None, - blocked_on: None, - } -} - -/// Status report recovered from the DB after the in-memory result was evicted. -/// Carries status only — the full output lives in the child session. -fn db_report(task_id: &str, rec: &ChildStatusRecord) -> DelegationTaskReport { - DelegationTaskReport { - task_id: Some(task_id.to_string()), - status: rec.status, - child_conversation_id: Some(rec.child_conversation_id), - agent_type: Some(rec.agent_type), - text: None, - error_code: (rec.status == TaskStatus::Canceled).then(|| "canceled".to_string()), - message: Some(format!( - "Result no longer cached; open child session {} for the full output.", - rec.child_conversation_id - )), - duration_ms: None, - blocked_on: None, - } -} - -/// What [`DelegationBroker::claim_new_blocks`] decided for one status pass. -#[derive(Default)] -struct ClaimedBlocks { - /// At least one blocking prompt is reportable now — the wait should return. - any_claimed: bool, - /// Earliest moment a currently-suppressed prompt becomes reportable again. - /// Bounds how long an otherwise-unbounded park may sleep, so the - /// resurface valve actually fires instead of waiting on a notify that will - /// never come (a blocked child emits nothing further on its own). - retry_at: Option, -} - -/// Per-id classification captured under the pending lock during a (possibly -/// batched) status query. The async resolution that can't run under the lock — -/// `attach_live_reply` (a different lock) for a running task, `status_from_db` -/// (a DB round-trip) for one not in memory — is deferred to `assemble_reports` -/// AFTER the lock is released, so a status query never nests the pending lock -/// inside another await. This is the same lock-ordering the single-task path -/// has always used; batching just captures it per id. -enum StatusClass { - /// Terminal/owned-cached, or a cross-parent `unknown` — the report is final. - Settled(DelegationTaskReport), - /// Running and owned — the bare running snapshot plus its child connection - /// id, so `assemble_reports` can attach the latest live reply out of lock. - Running { - report: DelegationTaskReport, - child_connection_id: String, - }, - /// Neither running nor completed in memory — resolve via the DB fallback in - /// `assemble_reports`. A not-in-memory id is, for wait purposes, already - /// settled: it can never transition back to running, so a batch wait need - /// not park on it (and must not hit the DB on every wake). - NotInMemory, -} - -/// Classify one task id against the in-memory maps while the pending lock is -/// held. Mirrors the single-task resolution order — completed cache (parent -/// scoped) → running set (parent scoped) → not-in-memory — and yields a -/// cross-parent hit as `unknown` so a task owned by another parent never leaks. -fn classify_locked(inner: &PendingInner, parent_connection_id: &str, task_id: &str) -> StatusClass { - if let Some(c) = inner.completed.get(task_id) { - if c.parent_connection_id == parent_connection_id { - return StatusClass::Settled(completed_report(task_id, c)); - } - return StatusClass::Settled(unknown_report(task_id)); - } - match inner.running.get(task_id) { - Some(r) if r.parent_connection_id == parent_connection_id => StatusClass::Running { - report: running_report(task_id, r), - child_connection_id: r.child_connection_id.clone(), - }, - Some(_) => StatusClass::Settled(unknown_report(task_id)), - None => StatusClass::NotInMemory, - } -} - -/// Map a terminal [`DelegationTaskReport`] back to a [`DelegationOutcome`] for -/// the test-only `handle_request` shim (so pre-async tests keep asserting on -/// the old outcome shape). -#[cfg(any(test, feature = "test-utils"))] -fn report_to_outcome(report: &DelegationTaskReport) -> DelegationOutcome { - use crate::acp::delegation::types::DelegationSuccess; - match report.status { - TaskStatus::Completed => DelegationOutcome::Ok(DelegationSuccess { - text: report.text.clone().unwrap_or_default(), - child_conversation_id: report.child_conversation_id.unwrap_or(0), - child_agent_type: report.agent_type.unwrap_or(AgentType::ClaudeCode), - turn_count: 1, - duration_ms: report.duration_ms.unwrap_or(0), - token_usage: None, - }), - // Running never reaches here (the shim loops until terminal); the other - // states all project onto Err. - _ => DelegationOutcome::Err { - code: report - .error_code - .clone() - .unwrap_or_else(|| "canceled".to_string()), - message: report.message.clone().unwrap_or_default(), - child_conversation_id: report.child_conversation_id, - }, - } -} - -/// Build the `Canceled { reason }` string for a child that ended without a -/// clean `TurnComplete`, optionally stitching in the terminal `Error` detail. -/// Shared by `cancel_by_child_connection` and `handle_request`'s early-terminal -/// pickup so both surface the same wording. -fn child_canceled_reason(terminal_error: Option<&str>) -> String { - match terminal_error { - Some(detail) if !detail.trim().is_empty() => { - format!("child session ended without TurnComplete: {detail}") - } - _ => "child session ended without TurnComplete".to_string(), - } -} - -/// Set of MCP-side `external_handle` tokens for which the companion -/// already received `notifications/cancelled` BEFORE the matching -/// `handle_request` reached the pending-registration phase. Without -/// this pre-cancel buffer, a fast cancel that lands during the -/// pre-check / spawn window would find no entry in `pending`, drop -/// silently, and let the broker proceed to spawn a child the caller -/// no longer wants. `handle_request` consults this set both at entry -/// (so we never even spawn) and immediately after parking the pending -/// entry (so a cancel landing mid-spawn still wins). -/// -/// Capped at [`PRE_CANCELED_CAP`] so a misbehaving MCP client (or a -/// pathological cancel-for-unknown-id storm) can't grow the set -/// without bound. Eviction is FIFO via the parallel `order` deque, -/// which is fine because pre-cancels only matter for the short window -/// between the cancel and the late-arriving `handle_request`. -#[derive(Default)] -struct PreCanceledHandles { - inner: Mutex, -} - -#[derive(Default)] -struct PreCanceledState { - set: HashSet, - order: VecDeque, -} - -const PRE_CANCELED_CAP: usize = 256; - -/// Per-parent tracking of `tool_call_id`s that the ACP lifecycle -/// observed firing `delegate_to_agent`. MCP clients (Codex, Claude -/// Code) generally do NOT populate `_meta.tool_use_id` when invoking -/// an MCP tool, so the broker can't read the LLM-issued -/// `tool_use_id` from the wire — we capture it from the parallel ACP -/// `tool_call` event stream instead. -/// -/// Each bucket holds two FIFOs under the SAME mutex: -/// -/// * `pending` — ids the lifecycle has registered but the matching -/// broker round-trip has not yet claimed. UNKEYED entries are subject -/// to [`PENDING_TOOL_CALL_TTL`] eviction so an anonymous ACP id whose -/// MCP round-trip never arrives can't linger and FIFO-mis-bind a later -/// delegation. KEYED entries carry no count cap: they are drained only -/// by their exact-match claim, by terminal tombstoning -/// (`tombstone_pending_tool_call`), or by per-parent teardown — because -/// the host may serialize a delegation's round-trip arbitrarily far -/// behind earlier long-running ones, so a count cap would drop a -/// still-pending keyed id and orphan its card. -/// * `consumed` — ids that were already claimed by a prior -/// round-trip, or terminal-tombstoned (`tombstone_pending_tool_call`). -/// NEITHER subject to TTL eviction NOR to a per-bucket -/// cap: a delegated child agent may run for minutes to hours, and -/// the host can re-emit the same `tool_call` (e.g. as a `completed` -/// status flip) at the end of that run, so the consumed memory -/// must outlast the entire parent-side tool call lifetime. It is -/// scoped to the parent connection's lifetime instead, cleared by -/// `drop_pending_tool_calls_for_parent` on disconnect. The growth -/// is bounded by how many entries ever register for the parent: -/// `delegate_to_agent` calls (typically tens at most) plus, on -/// Cursor connections, one identity-less "MCP: tool" candidate per -/// MCP call the session makes (see `acp::lifecycle`'s -/// `CURSOR_IDENTITYLESS_MCP_TITLE` registration) — with each -/// `(String, Instant)` entry costing well under 100 bytes, an -/// unbounded set stays comfortable for realistic sessions without -/// OOM risk in the typical operating envelope. -/// -/// Co-locating the two halves under one lock makes the -/// claim → mark-consumed pair atomic. A host re-emit racing with the -/// claim cannot observe an empty pending queue AND a consumed memory -/// that does not yet remember the id; consequently it cannot inject -/// a stale duplicate that would mis-bind the next delegation. -#[derive(Default)] -struct ToolCallTracker { - inner: Mutex>, -} - -/// The arguments that uniquely identify a `delegate_to_agent` invocation, -/// used to correlate a parent-side ACP `tool_call` to the matching MCP -/// `tools/call` round-trip. All three fields are values the LLM passed -/// identically to both wire paths, so the triple is the deterministic key -/// when a parent fires several `delegate_to_agent` calls in parallel — -/// matching on `task` alone would swap two calls targeting different agents -/// with the same task, and adding `agent_type` alone would still swap two -/// same-agent/same-task calls aimed at different directories (e.g. "run -/// tests" against `/repo-a` vs `/repo-b`). -/// -/// `working_dir` here is the value the LLM EXPLICITLY passed (`None` when -/// omitted), NOT the listener-defaulted spawn directory: the listener -/// defaults a missing MCP `working_dir` to the parent's launch dir, but the -/// ACP `raw_input` omits it then too, so keying on the explicit value keeps -/// both sides symmetric (`None == None`) for the common omitted case while -/// still distinguishing two calls that name different directories. -#[derive(Clone, Debug, PartialEq, Eq)] -pub struct DelegationMatchKey { - pub agent_type: AgentType, - pub task: String, - pub working_dir: Option, -} - -/// One captured parent-side `delegate_to_agent` tool_call awaiting its -/// matching MCP round-trip. -struct PendingToolCall { - tool_call_id: String, - /// The `(agent_type, task, working_dir)` correlation key parsed from the ACP - /// tool_call's `raw_input`. Matched against the MCP round-trip's own - /// key so parallel `delegate_to_agent` calls each bind to their own - /// `tool_call_id` regardless of arrival order — pure arrival-order FIFO - /// can mis-assign them (or, when one MCP round-trip out-races the - /// matching ACP event, orphan to a synthetic id). `None` when the host - /// shipped no parseable `raw_input` at ToolCall time; such entries are - /// claimable ONLY via the post-budget FIFO fallback - /// (`take_pending_tool_call`), never the in-loop key-match path. - match_key: Option, - /// True when the entry came from an identity-less MCP announcement - /// (Cursor's `"MCP: tool"` + empty input — see - /// `lifecycle::CURSOR_IDENTITYLESS_MCP_TITLE`). Such an id belongs to - /// *some* codeg-mcp call whose identity only the companion round-trip can - /// reveal, so it is additionally claimable by - /// [`DelegationBroker::rewrite_identityless_tool_call`] (the - /// `get_delegation_status` / `cancel_delegation` call-time rename), and a - /// `delegate_to_agent` claim that lands on one triggers the identity - /// write. Plain unkeyed entries (a delegation invocation whose args were - /// unparseable) keep `false` and are never renamed. - identityless: bool, - registered_at: Instant, -} - -#[derive(Default)] -struct ToolCallTrackerBucket { - pending: VecDeque, - consumed: VecDeque<(String, Instant)>, - /// Sticky "this parent has EVER announced an identity-less MCP call" flag. - /// Gates [`DelegationBroker::rewrite_identityless_tool_call`]'s poll: on - /// hosts that ship real identities (Claude/Codex/…) no identity-less - /// entry ever registers, the flag stays `false`, and every status/cancel - /// round-trip skips the rename at zero cost instead of burning the poll - /// budget. Never cleared on claim — only with the bucket on teardown. - identityless_seen: bool, -} - -/// Maximum age before a `pending` entry is discarded as stale — but ONLY for -/// UNKEYED entries (anonymous, arrival-order correlated). KEYED entries are -/// retained regardless of age: each is claimed solely by an exact key match, -/// so it can't mis-bind a later delegation, and its MCP round-trip may be -/// serialized arbitrarily far behind earlier long-running delegations (Claude -/// Code runs parallel `delegate_to_agent` calls one-at-a-time — observed gap -/// 77 s). See the retain block in `take_matching_tool_call_at`. -/// 60 s comfortably covers the ACP→MCP race for the unkeyed case (<5 ms -/// typical) while still GC'ing a forgotten anonymous id before it can -/// FIFO-mis-bind a subsequent unkeyed delegation. -/// -/// The `consumed` side has no TTL — see [`ToolCallTrackerBucket`] — because -/// long-running delegations can re-emit the parent-side `tool_call` well past -/// this window. -const PENDING_TOOL_CALL_TTL: Duration = Duration::from_secs(60); - -/// Poll cadence and budget used by `claim_pending_tool_call_with_brief_wait` -/// to correlate an MCP `delegate_to_agent` round-trip to its parent-side -/// ACP `tool_call_id`. The exact-match path returns instantly; this budget is -/// spent while waiting for THIS delegation's own `tool_call` to register (or to -/// backfill its key onto an already-registered entry) so we bind by exact match -/// instead of stealing a parallel sibling's id, or while no claimable id has -/// arrived yet. Unkeyed entries are never claimed in-loop — arrival-order FIFO -/// is deferred to the post-budget last resort, which runs only after the caller -/// has waited the full budget (the correct clock for "this delegation has no -/// key coming"), so a round-trip can't grab a sibling's not-yet-keyed id -/// mid-race. -/// -/// 200 × 10 ms = 2 s. This budget only matters when the MCP round-trip -/// out-races its own ACP `tool_call` registration — i.e. the `tools/call` -/// reaches the broker before the in-process `session/update(tool_call)` (and -/// any slightly-later `ToolCallUpdate` carrying the `agent_type`/`task` args) -/// has registered the key. That race is sub-5ms locally; the headroom covers -/// busier hosts and split arg streaming. The wait is invisible in the happy -/// path (it returns the instant the key matches) and negligible against the -/// multi-second-to-minutes child run it precedes. -/// -/// NOTE: the budget is NOT what protects a *serialized* second delegation -/// whose round-trip lands many seconds after its tool_call registered (Claude -/// Code runs parallel `delegate_to_agent` calls one-at-a-time, so the 2nd may -/// arrive minutes later). That id is already registered and waiting — the -/// thing that used to orphan it was age-eviction, now fixed by retaining keyed -/// entries indefinitely (see `take_matching_tool_call_at`'s retain -/// block). A host that emits no observable ACP `tool_call` at all still falls -/// through to the synthetic id after the budget, exactly as before. -const CLAIM_POLL_INTERVAL: Duration = Duration::from_millis(10); -const CLAIM_POLL_ATTEMPTS: usize = 200; - -/// Poll budget for the status/cancel call-time rename -/// ([`DelegationBroker::rewrite_identityless_tool_call`]): 30 × 10 ms = 300 ms. -/// Much shorter than the delegate claim budget because the rename is -/// best-effort (a miss falls back to the completion-time result sniff) and the -/// poll delays the status snapshot the LLM is waiting on. It only has to -/// absorb the in-process ordering race between the ACP announcement landing in -/// the lifecycle dispatcher and the companion's UDS round-trip reaching the -/// listener — sub-5 ms in practice; the sticky `identityless_seen` gate keeps -/// hosts that never announce identity-less calls at zero cost. -const IDENTITYLESS_RENAME_POLL_ATTEMPTS: usize = 30; - -/// The broker is intentionally `Clone` (cheap — only `Arc`s inside) so -/// listener/handler code can hand copies to spawned tasks without lifetime -/// gymnastics. -#[derive(Clone)] -pub struct DelegationBroker { - spawner: Arc, - depth_lookup: Arc, - /// Writer for `meta["codeg.delegation"]` on the parent's active - /// `delegate_to_agent` ToolCallState. Defaults to a no-op so tests - /// that aren't exercising the meta lifecycle don't need to wire - /// anything; production constructs the broker with the - /// `ConnectionManagerMetaWriter` via `with_writers`. - meta_writer: Arc, - /// Emitter for `AcpEvent::DelegationCompleted` against the parent - /// connection's event stream. Same Noop/Mock/Production scheme as - /// the meta writer — production wires `ConnectionManagerEventEmitter` - /// via `with_writers`; tests that don't observe the event lifecycle - /// take the default Noop. - event_emitter: Arc, - /// DB fallback for `get_delegation_status` / `cancel_delegation` once a - /// task's result aged out of the in-memory completed-cache. Defaults to a - /// no-op ("unknown"); production wires `DbChildStatusLookup` via - /// `with_status_lookup`. - status_lookup: Arc, - /// Peeks a still-running child's live session for a one-line progress hint, - /// used to enrich `get_delegation_status`'s running report. Defaults to a - /// no-op ("no hint"); production wires `ConnectionManagerLiveReplyLookup` via - /// `with_live_reply_lookup`. - live_reply_lookup: Arc, - pending: Arc, - tool_calls: Arc, - pre_canceled_handles: Arc, - config: Arc>, - /// Separate from `DelegationConfig` so existing test literals do not - /// have to name it. Default on: agents may spawn without `@`. The - /// settings toggle can turn it off (mention-only description). - allow_self_initiate: Arc, - /// Woken after every terminal `record_completed` so a `get_delegation_status` - /// long-poll wakes the instant its task finishes instead of busy-polling. - result_notify: Arc, - /// How long an already-reported blocking prompt stays suppressed — - /// [`BLOCK_RESURFACE_INTERVAL`] in production. A field only so tests can - /// shrink it; nothing outside tests ever sets it. - block_resurface: Duration, -} - -impl DelegationBroker { - pub fn new( - spawner: Arc, - depth_lookup: Arc, - ) -> Self { - Self::with_writers( - spawner, - depth_lookup, - Arc::new(NoopMetaWriter) as Arc, - Arc::new(NoopEventEmitter) as Arc, - ) - } - - /// Test-only constructor that injects a meta writer but keeps the - /// default Noop event emitter. Retained so existing meta-focused - /// tests don't have to mention the emitter parameter. New callsites - /// (and production wiring) should prefer `with_writers`. - pub fn with_meta_writer( - spawner: Arc, - depth_lookup: Arc, - meta_writer: Arc, - ) -> Self { - Self::with_writers( - spawner, - depth_lookup, - meta_writer, - Arc::new(NoopEventEmitter) as Arc, - ) - } - - /// Production-grade constructor wiring the broker to both a real - /// meta writer (`ConnectionManagerMetaWriter`) AND an event emitter - /// (`ConnectionManagerEventEmitter`). Tests that observe the full - /// lifecycle (meta writes + DelegationCompleted emits) should use - /// this with `MockMetaWriter` + `MockEventEmitter`. - pub fn with_writers( - spawner: Arc, - depth_lookup: Arc, - meta_writer: Arc, - event_emitter: Arc, - ) -> Self { - Self { - spawner, - depth_lookup, - meta_writer, - event_emitter, - status_lookup: Arc::new(NoopChildStatusLookup), - live_reply_lookup: Arc::new(NoopChildLiveReplyLookup), - pending: Arc::new(PendingCalls::default()), - tool_calls: Arc::new(ToolCallTracker::default()), - pre_canceled_handles: Arc::new(PreCanceledHandles::default()), - config: Arc::new(Mutex::new(DelegationConfig::default())), - allow_self_initiate: Arc::new(AtomicBool::new(true)), - result_notify: Arc::new(Notify::new()), - block_resurface: BLOCK_RESURFACE_INTERVAL, - } - } - - /// Replace the DB status fallback used by `get_delegation_status` / - /// `cancel_delegation` for tasks evicted from the in-memory completed-cache. - /// Builder-style so the production wiring can layer it onto `with_writers` - /// without growing that constructor's arity, and tests can opt in. - pub fn with_status_lookup(mut self, status_lookup: Arc) -> Self { - self.status_lookup = status_lookup; - self - } - - /// Replace the live-reply lookup used to enrich `get_delegation_status`'s - /// running report with the child's latest one-line progress. Builder-style, - /// layered onto `with_writers` by the production wiring; tests opt in with a - /// `MockChildLiveReplyLookup`. - pub fn with_live_reply_lookup( - mut self, - live_reply_lookup: Arc, - ) -> Self { - self.live_reply_lookup = live_reply_lookup; - self - } - - /// Shrink [`BLOCK_RESURFACE_INTERVAL`] so a test can observe the - /// delivery-failure valve without waiting minutes. Test-only by - /// construction — production always keeps the constant. - #[cfg(test)] - fn with_block_resurface(mut self, interval: Duration) -> Self { - self.block_resurface = interval; - self - } - - /// Record a parent ACP `tool_call_id` whose title indicates the LLM is - /// invoking `delegate_to_agent`. The next broker round-trip from the - /// same `parent_connection_id` will claim this id as its - /// `parent_tool_use_id`. Bounded FIFO per connection. - /// - /// Two-tier dedupe against host re-emits of `sessionUpdate(tool_call)` - /// (some hosts use the non-update variant to ship status flips and - /// late-arriving `raw_input` chunks): - /// - /// 1. **In-queue**: if the id is still waiting to be claimed, drop - /// the re-emit — the first push will be consumed by the matching - /// MCP round-trip. - /// 2. **Recently consumed**: if the id was already claimed for an - /// earlier delegation on the same parent, drop the re-emit — - /// otherwise it would sit in the queue as a stale id and mis- - /// bind the **next** delegation's MCP round-trip. The consumed - /// memory persists for the parent connection's lifetime (no - /// TTL, no cap) so a host re-emit at terminal status flip is - /// still rejected even if the delegation ran for hours. - pub async fn register_pending_tool_call( - &self, - parent_connection_id: &str, - tool_call_id: String, - ) { - self.register_pending_tool_call_with_key_at( - parent_connection_id, - tool_call_id, - None, - false, - Instant::now(), - ) - .await; - } - - /// Register an id announced with NO identity at all — Cursor's - /// `"MCP: tool"` + empty-input shape, where the wire never reveals which - /// MCP tool the call is. The entry is unkeyed (claimable by the - /// post-budget FIFO fallback, exactly like a keyless delegation - /// invocation) and additionally marked `identityless`, which (a) makes it - /// claimable by the status/cancel call-time rename - /// ([`Self::rewrite_identityless_tool_call`]) and (b) triggers the - /// identity write when a `delegate_to_agent` claim lands on it. - pub async fn register_identityless_tool_call( - &self, - parent_connection_id: &str, - tool_call_id: String, - ) { - self.register_pending_tool_call_with_key_at( - parent_connection_id, - tool_call_id, - None, - true, - Instant::now(), - ) - .await; - } - - /// `register_pending_tool_call` that also records the - /// `(agent_type, task, working_dir)` correlation key parsed from the - /// tool_call's `raw_input`. The key lets - /// the broker bind this id to its matching MCP round-trip deterministically - /// for parallel `delegate_to_agent` calls that pure arrival-order FIFO can - /// mis-assign. Production registration (from the ACP lifecycle dispatcher) - /// goes through here. - pub async fn register_pending_tool_call_with_key( - &self, - parent_connection_id: &str, - tool_call_id: String, - match_key: Option, - ) { - self.register_pending_tool_call_with_key_at( - parent_connection_id, - tool_call_id, - match_key, - false, - Instant::now(), - ) - .await; - } - - /// Core registration. Holds the [`ToolCallTracker`] mutex across both - /// dedupe tiers AND the push so no concurrent `take` can split the - /// "queue empty + not yet recorded as consumed" window where a host - /// re-emit could otherwise inject a stale duplicate. - /// - /// Two-tier dedupe against host re-emits of `sessionUpdate(tool_call)` - /// (some hosts use the non-update variant to ship status flips and - /// late-arriving `raw_input` chunks): - /// - /// 1. **Recently consumed**: if the id was already claimed for an - /// earlier delegation on the same parent, drop the re-emit — - /// otherwise it would sit in the queue as a stale id and mis-bind - /// the **next** delegation's MCP round-trip. The consumed memory - /// persists for the parent connection's lifetime (no TTL, no cap) - /// so a host re-emit at terminal status flip is still rejected - /// even if the delegation ran for hours. - /// 2. **In-queue**: if the id is still waiting to be claimed, drop the - /// re-emit rather than push a duplicate — EXCEPT we backfill the - /// `match_key` onto an entry registered without one. This is the common - /// case for hosts that emit an arg-less initial `ToolCall` and ship the - /// `agent_type`/`task` arguments on a following `ToolCallUpdate`: the - /// lifecycle dispatcher registers BOTH variants (see - /// `register_delegation_tool_call_from_event`), so the first call lands - /// here unkeyed and the later update re-enters and back-fills the key. - /// Keying the entry this way is what lets it survive past the unkeyed - /// GC TTL (see `take_matching_tool_call_at`'s retain block). - async fn register_pending_tool_call_with_key_at( - &self, - parent_connection_id: &str, - tool_call_id: String, - match_key: Option, - identityless: bool, - now: Instant, - ) { - let mut map = self.tool_calls.inner.lock().await; - let bucket = map.entry(parent_connection_id.to_string()).or_default(); - if identityless { - bucket.identityless_seen = true; - } - // Tier 1: recently consumed. No TTL — the consumed memory must - // outlast the entire parent-side tool call lifetime (minutes - // to hours) so a host re-emit at terminal status flip is - // still rejected. See `ToolCallTrackerBucket` docs. - if bucket.consumed.iter().any(|(id, _)| id == &tool_call_id) { - tracing::info!( - "[delegation] dropping ACP tool_call_id={tool_call_id} on conn={parent_connection_id} (already consumed by an earlier delegation)" - ); - return; - } - // Tier 2: in-queue. A re-emit of an already-queued id: adopt the - // LATEST parseable key rather than only back-filling a missing one. - // Hosts stream `raw_input` incrementally and the MCP side keys on the - // FINAL arguments, so a later `ToolCallUpdate` that completes the key - // (e.g. adds an explicit `working_dir` the first parse lacked) must - // REPLACE the earlier `(agent, task, None)` key — otherwise the MCP - // claim keys on `(agent, task, Some(dir))`, fails to match the stale - // `None`, refuses the keyed fallback, and orphans to a synthetic id - // (the very dead-card failure this whole change fixes). An arg-less or - // identical re-emit changes nothing and is dropped as a duplicate. - if let Some(existing) = bucket - .pending - .iter_mut() - .find(|p| p.tool_call_id == tool_call_id) - { - match match_key { - Some(key) if existing.match_key.as_ref() != Some(&key) => { - existing.match_key = Some(key); - } - _ => { - tracing::info!( - "[delegation] dropping duplicate ACP tool_call_id={tool_call_id} on conn={parent_connection_id}" - ); - } - } - return; - } - bucket.pending.push_back(PendingToolCall { - tool_call_id, - match_key, - identityless, - registered_at: now, - }); - } - - /// Pop the oldest pending `tool_call_id` for the given parent, if any. - /// Skips entries older than [`PENDING_TOOL_CALL_TTL`] so an ACP id whose - /// matching MCP round-trip never arrived cannot mis-bind a later - /// delegation. Mutates the queue in-place; the bucket is removed once - /// drained. - pub async fn take_pending_tool_call(&self, parent_connection_id: &str) -> Option { - self.take_pending_tool_call_at(parent_connection_id, Instant::now()) - .await - .map(|(id, _)| id) - } - - /// `take_pending_tool_call` with an injected "as of" instant. The - /// public entry point pins it to `Instant::now()`; tests can supply - /// a future instant to exercise TTL eviction without sleeping past - /// [`PENDING_TOOL_CALL_TTL`]. - /// - /// Anonymous claim: returns the oldest *unkeyed* pending id (plus its - /// `identityless` mark, so the delegate-claim path knows to restore the - /// call's identity), GC'ing stale unkeyed entries along the way. KEYED - /// entries are stepped over and left in place — they're reserved for - /// their exact-key-match round-trip and must never be handed out by this - /// arrival-order path (doing so would steal an in-flight delegation's - /// id). Returns `None` when no unkeyed entry is claimable, even if keyed - /// entries remain. - async fn take_pending_tool_call_at( - &self, - parent_connection_id: &str, - now: Instant, - ) -> Option<(String, bool)> { - self.take_unkeyed_tool_call_at(parent_connection_id, now, false) - .await - } - - /// Claim the oldest pending entry that was registered as IDENTITY-LESS - /// (Cursor's `"MCP: tool"` announcements) — used by the status/cancel - /// call-time rename. Unlike `take_pending_tool_call_at` this NEVER hands - /// out a plain unkeyed entry: that one is a delegation invocation whose - /// args merely didn't parse, and renaming it to a status tool would - /// mislabel a real delegate card. - async fn take_identityless_tool_call(&self, parent_connection_id: &str) -> Option { - self.take_unkeyed_tool_call_at(parent_connection_id, Instant::now(), true) - .await - .map(|(id, _)| id) - } - - /// Shared FIFO claim over unkeyed entries. `identityless_only` restricts - /// eligibility to entries carrying the identity-less mark; keyed entries - /// are always stepped over (reserved for their exact-key-match - /// round-trip), and stale unkeyed entries are GC'd along the way - /// regardless of the filter so the queue stays bounded from either - /// caller. - async fn take_unkeyed_tool_call_at( - &self, - parent_connection_id: &str, - now: Instant, - identityless_only: bool, - ) -> Option<(String, bool)> { - let mut map = self.tool_calls.inner.lock().await; - let bucket = map.get_mut(parent_connection_id)?; - // Anonymous claim (post-budget last resort + legacy single-delegation - // path): only UNKEYED entries are eligible. A keyed entry identifies a - // specific in-flight delegation and is claimable ONLY by its - // exact-key-match round-trip; grabbing it here would steal that - // delegation's id and make IT the dead card. Walk oldest→newest, - // GC'ing stale unkeyed entries and stepping over keyed ones, until we - // find the oldest fresh eligible id. When only keyed siblings remain we - // return `None` — the delegate caller then mints a synthetic id rather - // than mis-binding a sibling. - let mut claimed: Option<(String, bool)> = None; - let mut idx = 0; - while idx < bucket.pending.len() { - if bucket.pending[idx].match_key.is_some() { - idx += 1; // keyed: leave it for its exact-match round-trip - continue; - } - if now.duration_since(bucket.pending[idx].registered_at) > PENDING_TOOL_CALL_TTL { - if let Some(stale) = bucket.pending.remove(idx) { - let age_secs = now.duration_since(stale.registered_at).as_secs(); - tracing::info!( - "[delegation] evicting stale UNKEYED ACP tool_call_id={} (age={age_secs}s) on conn={parent_connection_id}", - stale.tool_call_id - ); - } - // `remove` shifted later entries left into `idx`; re-check it. - continue; - } - if identityless_only && !bucket.pending[idx].identityless { - idx += 1; // plain unkeyed: reserved for the delegate FIFO path - continue; - } - claimed = bucket - .pending - .remove(idx) - .map(|p| (p.tool_call_id, p.identityless)); - break; - } - // Same mutex span: record the claim into the consumed memory so - // a concurrent re-register cannot observe "pending empty AND - // consumed missing" and inject a stale duplicate. Consumed - // entries persist for the whole parent connection lifetime - // (no TTL, no cap — see `ToolCallTrackerBucket`) and are only - // released when the parent disconnects. - if let Some((id, _)) = &claimed { - bucket.consumed.push_back((id.clone(), now)); - } - if bucket.pending.is_empty() && bucket.consumed.is_empty() && !bucket.identityless_seen { - map.remove(parent_connection_id); - } - claimed - } - - /// Whether this parent has EVER registered an identity-less candidate — - /// the zero-cost gate for [`Self::rewrite_identityless_tool_call`]'s poll. - async fn has_seen_identityless_tool_calls(&self, parent_connection_id: &str) -> bool { - self.tool_calls - .inner - .lock() - .await - .get(parent_connection_id) - .is_some_and(|b| b.identityless_seen) - } - - /// Restore the identity of a pending identity-less MCP tool call at - /// companion round-trip time: claim the oldest such candidate for this - /// parent and rewrite its live `title` + `raw_input` to the actual - /// codeg-mcp tool (`get_delegation_status` / `cancel_delegation`) with - /// its real arguments — flipping the card from the generic "MCP: tool" - /// WHILE the call runs, instead of only at the completion-time result - /// sniff (which, for a `wait_ms`-blocked status long-poll, can be minutes - /// away). - /// - /// Best-effort by design: on hosts that ship real identities the sticky - /// `identityless_seen` gate skips everything at zero cost; on an - /// identity-less host whose announcement hasn't registered yet, a short - /// bounded poll (well under the ACP-vs-companion race in practice) - /// absorbs the ordering, and a miss simply leaves the rename to the - /// completion sniff. Mis-pairing under PARALLEL identity-less calls in - /// one burst is the same accepted arrival-order residual as the delegate - /// FIFO fallback — Cursor executes tool calls sequentially, so announce - /// order matches round-trip order in practice. - pub async fn rewrite_identityless_tool_call( - &self, - parent_connection_id: &str, - title: &str, - raw_input: serde_json::Value, - ) -> Option { - if !self - .has_seen_identityless_tool_calls(parent_connection_id) - .await - { - return None; - } - for attempt in 0..IDENTITYLESS_RENAME_POLL_ATTEMPTS { - if attempt > 0 { - tokio::time::sleep(CLAIM_POLL_INTERVAL).await; - } - if let Some(id) = self.take_identityless_tool_call(parent_connection_id).await { - tracing::info!( - "[delegation] renaming identity-less tool_call_id={id} on conn={parent_connection_id} to {title}" - ); - self.meta_writer - .write_tool_call_identity(parent_connection_id, &id, title, raw_input) - .await; - return Some(id); - } - } - None - } - - /// Claim the pending `tool_call_id` for `parent_connection_id` whose - /// recorded key matches `key` (exact `(agent_type, task, working_dir)` - /// match). This is the ONLY claim this method makes — it never hands out an - /// unkeyed entry, because an unkeyed entry may belong to a *different* - /// parallel delegation whose round-trip simply hasn't registered (or keyed) - /// its `tool_call` yet, and claiming it by arrival order would steal that - /// sibling's id. Returns `None` (so the caller keeps polling) whenever no - /// entry's key matches — whether keyed siblings or only unkeyed entries are - /// present. - /// - /// Arrival-order FIFO for genuinely keyless hosts is deferred to the - /// post-budget last resort `take_pending_tool_call`, which runs only after - /// the caller has waited its full budget (see - /// `claim_pending_tool_call_with_brief_wait`) — the correct clock for "no - /// key is coming", since a host can serialize a round-trip arbitrarily far - /// behind its `tool_call` registration, so the entry's own age can never - /// prove a key won't still arrive. Evicts stale *unkeyed* entries along the - /// way; keyed entries are retained regardless of age (their round-trip may - /// be serialized far behind earlier delegations — see the retain block) and - /// an exact key match claims them at any age. - pub async fn take_matching_tool_call( - &self, - parent_connection_id: &str, - key: &DelegationMatchKey, - ) -> Option { - self.take_matching_tool_call_at(parent_connection_id, key, Instant::now()) - .await - } - - /// `take_matching_tool_call` with an injected "as of" - /// instant for TTL tests. - async fn take_matching_tool_call_at( - &self, - parent_connection_id: &str, - key: &DelegationMatchKey, - now: Instant, - ) -> Option { - let mut map = self.tool_calls.inner.lock().await; - let bucket = map.get_mut(parent_connection_id)?; - - // Evict every stale UNKEYED entry up front. The key-match scan below - // ignores unkeyed entries anyway (they carry no key to match), but - // GC'ing here keeps the queue bounded during the poll loop and - // consistent with `take_pending_tool_call_at`'s view, so the - // post-budget last resort never hands out an aged-out id. Mirrors that - // TTL skip but covers entries at any position (not just the front). - bucket.pending.retain(|p| { - // Keyed entries are NEVER aged out. Each identifies one specific - // `delegate_to_agent` invocation and is claimable ONLY by an exact - // key match (never by FIFO — see below), so it cannot mis-bind a - // different delegation no matter how old it gets. And it MUST - // survive until its MCP round-trip arrives, which the host may - // serialize arbitrarily far behind earlier long-running - // delegations: Claude Code runs parallel `delegate_to_agent` calls - // SEQUENTIALLY, so the 2nd call's round-trip only fires after the - // 1st child finishes. Observed in the wild — a 2nd delegation whose - // tool_call registered, then waited 77s (past the old 60s TTL) for - // its round-trip while the 1st ran; age-evicting it here orphaned - // it to a synthetic id and left the parent card stuck on - // "sub-agent running…". Only UNKEYED (anonymous, arrival-order - // correlated) entries keep the age-based GC, since a stale one - // could be mis-claimed via the FIFO path. Keyed memory stays bounded - // by exact-match claim, terminal tombstoning, and - // `drop_pending_tool_calls_for_parent` on connection teardown — not - // by this TTL. - if p.match_key.is_some() { - return true; - } - let fresh = now.duration_since(p.registered_at) <= PENDING_TOOL_CALL_TTL; - if !fresh { - let age_secs = now.duration_since(p.registered_at).as_secs(); - tracing::info!( - "[delegation] evicting stale UNKEYED ACP tool_call_id={} (age={age_secs}s) on conn={parent_connection_id}", - p.tool_call_id - ); - } - fresh - }); - - let claimed = if let Some(pos) = bucket - .pending - .iter() - .position(|p| p.match_key.as_ref() == Some(key)) - { - // Exact (agent_type, task) match: deterministic correlation - // regardless of ACP-vs-MCP arrival order or how many delegations - // are in flight. - bucket.pending.remove(pos).map(|p| p.tool_call_id) - } else { - // No exact key match. We deliberately do NOT claim an unkeyed entry - // here — not even the oldest, not even the only one. An unkeyed - // pending entry may belong to a DIFFERENT parallel delegation whose - // own round-trip hasn't yet registered (or keyed) its `tool_call`, - // and claiming it by arrival order would steal that sibling's id — - // the mis-bind this machinery exists to prevent. - // - // Crucially, the ENTRY's age is the wrong clock for "no key is - // coming": a host can serialize a round-trip arbitrarily far behind - // its `tool_call` registration (see the retain block / the - // `keyed_entry_survives_past_ttl` case), so even an old lone unkeyed - // entry can still be a sibling's. The CALLER's own wait is the right - // clock. So return `None` and let - // `claim_pending_tool_call_with_brief_wait` poll: if this - // delegation's key lands (initial register or a later backfill) we - // bind by the exact match above; only after the caller has spent the - // FULL budget does its post-budget last resort - // (`take_pending_tool_call`) claim the oldest unkeyed id in arrival - // order — the best a genuinely keyless host allows, and the point at - // which waiting longer cannot improve correlation. - None - }; - - if let Some(id) = &claimed { - bucket.consumed.push_back((id.clone(), now)); - } - if bucket.pending.is_empty() && bucket.consumed.is_empty() { - map.remove(parent_connection_id); - } - claimed - } - - /// Consume an explicit `parent_tool_use_id` that the MCP client supplied - /// directly via `_meta.tool_use_id` (the precise-binding path; most clients - /// omit it). In that case `handle_request` does NOT run the claim path, so - /// the matching pending entry the lifecycle dispatcher registered off the - /// parent's ACP stream would otherwise never be consumed — and because - /// keyed entries are now retained indefinitely, it would linger and could - /// be mis-claimed by a *later* delegation sharing the same - /// `(agent_type, task, working_dir)` key, retargeting that delegation's - /// writes/events at the wrong (already-handled) card. - /// - /// Remove the entry from the pending queue AND record the id as consumed. - /// Recording consumed also covers the MCP-before-ACP race: a later ACP - /// registration for the same id is dropped by the Tier-1 consumed check in - /// `register_pending_tool_call_with_key_at`, so the entry can't reappear - /// regardless of arrival order. - async fn consume_explicit_tool_call(&self, parent_connection_id: &str, tool_call_id: &str) { - let mut map = self.tool_calls.inner.lock().await; - let bucket = map.entry(parent_connection_id.to_string()).or_default(); - bucket.pending.retain(|p| p.tool_call_id != tool_call_id); - if !bucket.consumed.iter().any(|(id, _)| id == tool_call_id) { - bucket - .consumed - .push_back((tool_call_id.to_string(), Instant::now())); - } - } - - /// Tombstone a parent `tool_call_id` whose `delegate_to_agent` reached a - /// TERMINAL ACP status (`completed`/`failed`) so a stale keyed pending entry - /// can't mis-bind a later delegation. The lifecycle dispatcher calls this - /// from its terminal-`ToolCallUpdate` branch, keyed on `tool_call_id` - /// (a bare terminal update carries no parseable key). - /// - /// The hazard: keyed pending entries are retained regardless of age (see the - /// retain block in `take_matching_tool_call_at`), so if a `delegate_to_agent` - /// tool call goes terminal without its MCP round-trip ever reaching the - /// broker (the call failed, the turn was interrupted, the companion never - /// dispatched), its entry would linger forever and a LATER delegation sharing - /// the same `(agent_type, task, working_dir)` key would claim this dead id, - /// retargeting its writes/events at the wrong card. Same hazard - /// `consume_explicit_tool_call` guards on the explicit-id path; this is its - /// terminal-status sibling. - /// - /// Safe synchronously, no grace window: a terminal `completed` can only - /// arrive AFTER the round-trip's claim already removed the entry (the ack - /// that claim produces is what lets the parent's tool call return), and a - /// serialized sibling still awaiting its (observed 77s-late) round-trip is - /// NON-terminal while it waits — so this never evicts a live entry. - /// - /// Records `consumed` ONLY when an entry was actually removed: this runs for - /// EVERY terminal tool-call update (the vast majority are non-delegations), - /// and `consumed` has no TTL/cap, so recording unconditionally would grow it - /// with every completed tool call. Recording on a real removal still drops an - /// out-of-order re-registration of the same id via the Tier-1 consumed check - /// in `register_pending_tool_call_with_key_at`. Returns whether an entry was - /// removed (for the dispatcher's gated log). - pub async fn tombstone_pending_tool_call( - &self, - parent_connection_id: &str, - tool_call_id: &str, - ) -> bool { - let mut map = self.tool_calls.inner.lock().await; - // No bucket → nothing registered for this parent; nothing to tombstone - // and nothing to record (unlike `consume_explicit_tool_call`, no - // MCP-before-ACP race can land a terminal status before registration on - // the single ordered ACP stream, so we never pre-create a bucket here). - let Some(bucket) = map.get_mut(parent_connection_id) else { - return false; - }; - let before = bucket.pending.len(); - bucket.pending.retain(|p| p.tool_call_id != tool_call_id); - let removed = bucket.pending.len() != before; - if removed && !bucket.consumed.iter().any(|(id, _)| id == tool_call_id) { - bucket - .consumed - .push_back((tool_call_id.to_string(), Instant::now())); - } - removed - } - - /// Correlate an MCP `delegate_to_agent` round-trip to the parent's - /// real ACP `tool_call_id`, polling briefly to absorb the race between - /// two independent arrival paths for the same invocation: - /// - /// * ACP `session/update(tool_call)` → in-process bus → lifecycle - /// dispatcher → `register_pending_tool_call_with_key` - /// * MCP `tools/call` → stdio round-trip → companion → `handle_request` - /// - /// Correlation is by the `(agent_type, task, working_dir)` key (carried in - /// both the ACP `raw_input` and the MCP call), so several `delegate_to_agent` - /// calls firing in parallel each bind to their own `tool_call_id` - /// regardless of arrival order — pure FIFO mis-assigned them (swapping - /// the child shown under each card) or, when one MCP round-trip out-raced - /// its ACP event, orphaned the loser to a synthetic `delegation-` - /// (the parent UI then never paints "view session" and the card hangs on - /// "sub-agent running…", because the frontend keys its binding map by - /// the agent's real `tool_call_id`). - /// - /// As a last resort after the budget — and the ONLY place arrival-order - /// FIFO is applied — claim the oldest unkeyed id, so a sibling whose - /// registration was unusually delayed, or a genuinely keyless host, still - /// yields a *real* id rather than a synthetic one. Deferring FIFO until the - /// full budget has elapsed is what makes it safe: in-loop we bind ONLY by - /// exact key match, so a round-trip can't FIFO-steal a sibling's - /// not-yet-keyed id while that sibling's own registration is still in - /// flight (the entry's age is no proof a key won't still arrive). A - /// synthetic id only results when no unkeyed id is claimable for the whole - /// budget — only keyed siblings remain, or the queue stays genuinely empty. - /// Returns the claimed id plus its `identityless` mark — `true` only for - /// the post-budget FIFO claim of an identity-less announcement (Cursor), - /// which tells `start_delegation` to restore the call's identity on the - /// live tool call. Exact-key claims are by definition NOT identity-less - /// (the key was parsed from the wire's own `raw_input`). - async fn claim_pending_tool_call_with_brief_wait( - &self, - parent_connection_id: &str, - key: &DelegationMatchKey, - ) -> Option<(String, bool)> { - if let Some(id) = self - .take_matching_tool_call(parent_connection_id, key) - .await - { - return Some((id, false)); - } - for _ in 0..CLAIM_POLL_ATTEMPTS { - tokio::time::sleep(CLAIM_POLL_INTERVAL).await; - if let Some(id) = self - .take_matching_tool_call(parent_connection_id, key) - .await - { - return Some((id, false)); - } - } - // Budget exhausted with no key match. As a last resort claim the - // oldest UNKEYED pending id (a host that shipped no parseable - // `raw_input`, or a mixed-shape race) — a real id beats a synthetic - // placeholder that orphans the parent UI binding. Crucially this - // never claims a KEYED entry: those belong to specific in-flight - // delegations and are reserved for their own exact-key-match - // round-trip, so when only keyed siblings remain the caller falls - // through to a synthetic id rather than stealing a sibling's binding - // (which would just move the dead card from one delegation to another). - self.take_pending_tool_call_at(parent_connection_id, Instant::now()) - .await - } - - /// Remove `handle` from the pre-cancel set, returning whether it was - /// present. Used by `handle_request` at two checkpoints (entry + just - /// after pending registration) so a cancel that lost the race with the - /// MCP round-trip still wins. The set is single-shot per handle — - /// taking it here means a subsequent `cancel_by_external_handle` will - /// have to find the pending entry on its own. - async fn take_pre_canceled_handle(&self, handle: &str) -> bool { - let mut state = self.pre_canceled_handles.inner.lock().await; - if state.set.remove(handle) { - // Best-effort companion-side cleanup of `order` so a later - // FIFO eviction doesn't burn a slot. Linear scan is fine — - // PRE_CANCELED_CAP is small. - if let Some(pos) = state.order.iter().position(|h| h == handle) { - state.order.remove(pos); - } - true - } else { - false - } - } - - /// Insert `handle` into the pre-cancel set with FIFO eviction at - /// [`PRE_CANCELED_CAP`]. Idempotent — re-inserting an existing handle - /// is a no-op. - async fn buffer_pre_canceled_handle(&self, handle: String) { - let mut state = self.pre_canceled_handles.inner.lock().await; - if !state.set.insert(handle.clone()) { - return; - } - state.order.push_back(handle); - while state.order.len() > PRE_CANCELED_CAP { - if let Some(evicted) = state.order.pop_front() { - state.set.remove(&evicted); - } - } - } - - /// Forget every pending and recently-consumed tool_call id for the - /// given parent. Called when the parent connection tears down so - /// stale ids don't bind to a future reuse of the same connection_id - /// (UUIDs make that unlikely but cheap to defend against), and so a - /// fresh connection on the reused id is not blocked by the - /// consumed memory of the previous one. - pub async fn drop_pending_tool_calls_for_parent(&self, parent_connection_id: &str) { - self.drop_tool_calls_for_parent(parent_connection_id, false) - .await; - } - - /// Core of the tool_call-tracker drop, shared by the two cancel scopes. - /// - /// * `keep_consumed == false` — genuine connection teardown: remove the - /// whole bucket (`pending` + `consumed`). The connection is going away, - /// so nothing it remembered can mis-bind a future delegation, and a - /// reused connection_id must start clean. - /// * `keep_consumed == true` — turn/prompt cancel with the parent - /// connection STILL ALIVE: TOMBSTONE the cancelled turn's unclaimed - /// `pending` ids into `consumed` and RETAIN the existing `consumed`. Both - /// the already-claimed ids AND the just-cancelled turn's unclaimed ids - /// must keep rejecting a host re-emit (e.g. a terminal status-flip): the - /// Tier-1 consumed check in `register_pending_tool_call_with_key_at` drops - /// the re-emit, so a stale id can't re-register as fresh `pending` and - /// mis-bind the next same-key delegation on this live connection. Merely - /// CLEARING the unclaimed ids would leave them re-registerable, reopening - /// that hole for the unclaimed half (the claimed half was already safe via - /// `consumed`). Retention is connection-scoped and released on teardown — - /// the same unbounded-but-bounded-by-delegation-count envelope `consumed` - /// already lives in for normal end_turn delegations (see - /// [`ToolCallTrackerBucket`]). - /// - /// Tombstoning ALL of `pending` here is safe (no turn/generation tag - /// needed): `run_conversation_loop` drives at most ONE `session/prompt` - /// future per connection at a time (see `acp/connection.rs`), and a - /// parent-side `tool_call` only streams while its prompt future is in - /// flight, so every `pending` id belongs to the single active turn — the one - /// being cancelled — or is a stale leftover from an earlier turn that should - /// be tombstoned regardless. (The per-connection `prompt_lock` only - /// serializes the prompt-SEND handshake, not the turn, so it is NOT the - /// source of this invariant.) The cancelled turn's serialized MCP round-trip - /// won't arrive after cancel, so nothing legitimate is lost. - async fn drop_tool_calls_for_parent(&self, parent_connection_id: &str, keep_consumed: bool) { - let mut map = self.tool_calls.inner.lock().await; - if !keep_consumed { - map.remove(parent_connection_id); - return; - } - if let Some(bucket) = map.get_mut(parent_connection_id) { - // Tombstone the cancelled turn's unclaimed pending ids into - // `consumed` rather than just dropping them, so a later host re-emit - // of one is rejected by the Tier-1 consumed check instead of - // re-registering as a claimable stale entry. `drain` empties - // `pending` first so the subsequent `consumed` borrow is disjoint. - let now = Instant::now(); - let cleared: Vec = bucket.pending.drain(..).map(|p| p.tool_call_id).collect(); - for id in cleared { - if !bucket.consumed.iter().any(|(c, _)| c == &id) { - bucket.consumed.push_back((id, now)); - } - } - // Drop the now-empty bucket only when nothing consumed remains — - // otherwise keep it so the retained `consumed` ids keep rejecting - // re-emits for the rest of this connection's lifetime. - if bucket.consumed.is_empty() { - map.remove(parent_connection_id); - } - } - } - - pub async fn set_config(&self, cfg: DelegationConfig) { - let cap_bytes = cfg.completed_cache_cap_bytes; - *self.config.lock().await = cfg; - // Seed the byte cap into the pending-calls bucket so `insert_completed` - // reads it lock-free (it already holds the pending lock). Acquired AFTER - // the config guard above is dropped — sequential, never nested — so no - // path locks `config` under `pending` or vice-versa (deadlock-free). - // Then prune existing per-parent caches: a LOWERED cap must free memory - // now, not lazily on each parent's next completion (which may never - // arrive for an idle parent). - let mut inner = self.pending.inner.lock().await; - inner.completed_cap_bytes = cap_bytes; - inner.enforce_completed_cap_all_parents(); - } - - pub async fn config_snapshot(&self) -> DelegationConfig { - self.config.lock().await.clone() - } - - pub fn set_allow_self_initiate(&self, allow: bool) { - self.allow_self_initiate.store(allow, Ordering::Relaxed); - } - - pub fn allow_self_initiate(&self) -> bool { - self.allow_self_initiate.load(Ordering::Relaxed) - } - - /// If this in-flight setup has been flagged canceled by a parent cancel, - /// deregister it and return true. One lock acquisition; used at the - /// pre-spawn / post-spawn checkpoints in `handle_request`. - async fn take_inflight_cancel(&self, inflight_id: u64) -> bool { - let mut inner = self.pending.inner.lock().await; - if inner.inflight_canceled(inflight_id) { - inner.deregister_inflight(inflight_id); - true - } else { - false - } - } - - /// Drop this setup's in-flight record. Called on each `handle_request` - /// early-return that isn't a park hand-off (the park region deregisters - /// inline, atomically with `calls.insert`). - async fn drop_inflight(&self, inflight_id: u64) { - self.pending - .inner - .lock() - .await - .deregister_inflight(inflight_id); - } - - /// Async entry point for `delegate_to_agent`. Does the bounded setup - /// (claim/depth checks → spawn → send first prompt), registers the task in - /// `running`, and returns a `Running` ack [`DelegationTaskReport`] WITHOUT - /// waiting for the child to finish. The child resolves later via the - /// lifecycle → [`complete_call`] (or a cancel path), which migrates the task - /// into `completed` and wakes any `get_delegation_status` long-poll. - /// - /// Returns a terminal report instead of a `Running` ack in three cases: the - /// child finished during setup (fast/empty turn), a parent cancel reached it - /// mid-setup, or setup itself failed (disabled / depth / spawn / send). - /// - /// All the setup-window race machinery (`setups` / `early_*` / `inflight`) - /// is unchanged — it governs terminals that beat registration, which is - /// orthogonal to whether the caller then blocks. The only change vs. the old - /// `handle_request` is that "park a `oneshot` and await it" becomes "insert a - /// [`RunningTask`] and return the ack." - #[tracing::instrument( - name = "delegation_task", - skip_all, - fields( - parent_connection_id = %req.parent_connection_id, - parent_tool_use_id = %req.parent_tool_use_id, - agent_type = ?req.agent_type, - working_dir = ?req.working_dir, - child_connection_id = tracing::field::Empty, - task_id = tracing::field::Empty, - ) - )] - pub async fn start_delegation(&self, mut req: DelegationRequest) -> DelegationTaskReport { - // Register this setup as the VERY FIRST thing — before the pre-cancel - // check's `.await` and the (possibly multi-second) claim poll — so a - // parent cancel landing ANYWHERE from here to park reaches it, not just - // after park (which is all the `cancel_by_parent*` parked-call drain - // covers on its own). The only residual gap is a cancel firing before - // the broker is even invoked for this request, which no - // in-`handle_request` mechanism can observe. Deregistered on every exit - // path below: each early-return via `drop_inflight` / - // `take_inflight_cancel`, or inline at park (atomically with - // `calls.insert`). - let inflight_id = self - .pending - .inner - .lock() - .await - .register_inflight(&req.parent_connection_id); - // Pre-cancel short-circuit. If the MCP companion already received - // `notifications/cancelled` for this `tools/call` before we even - // started processing (cancel ran ahead of the UDS round-trip), we - // claim the handle from the pre-cancel set and bail without - // spawning anything — the caller will not be receiving our - // response either way (the companion suppresses it per MCP spec). - if let Some(handle) = req.external_handle.as_deref() { - if self.take_pre_canceled_handle(handle).await { - self.drop_inflight(inflight_id).await; - // Bailing here BEFORE the claim path means this delegation never - // consumes the ACP `tool_call_id` the lifecycle keyed for it. As - // keyed entries are retained indefinitely, a leftover would let a - // *later* same-`(agent_type, task, working_dir)` delegation claim - // this canceled call's id and bind its writes/events to the wrong - // card. Drain it now (idempotent; the turn-end tombstone is the - // backstop if the ACP event hasn't registered yet). - if req.parent_tool_use_id.is_empty() { - let key = DelegationMatchKey { - agent_type: req.agent_type, - task: req.task.clone(), - working_dir: req.requested_working_dir.clone(), - }; - let _ = self - .take_matching_tool_call(&req.parent_connection_id, &key) - .await; - } else { - self.consume_explicit_tool_call( - &req.parent_connection_id, - &req.parent_tool_use_id, - ) - .await; - } - return report_err( - req.agent_type, - DelegationError::Canceled { - reason: "canceled before spawn".into(), - }, - None, - ); - } - } - // MCP clients usually don't populate `_meta.tool_use_id`, so the - // listener will pass through an empty string. Claim the matching - // ACP-side `tool_call_id` for this parent by task text — with a brief - // poll loop so an MCP round-trip that out-races the in-process ACP - // `session/update` doesn't fall back to a synthetic id (which breaks - // the parent UI's `parent_tool_use_id` binding). Falls back to a UUID - // placeholder only when no id arrives within the wait budget. - if req.parent_tool_use_id.is_empty() { - let match_key = DelegationMatchKey { - agent_type: req.agent_type, - task: req.task.clone(), - working_dir: req.requested_working_dir.clone(), - }; - let claimed = self - .claim_pending_tool_call_with_brief_wait(&req.parent_connection_id, &match_key) - .await; - let claimed_identityless = matches!(claimed, Some((_, true))); - req.parent_tool_use_id = claimed.map(|(id, _)| id).unwrap_or_else(|| { - tracing::warn!( - "[delegation] synthetic fallback for parent_tool_use_id on conn={} (no ACP tool_call_id arrived within claim budget)", - req.parent_connection_id - ); - format!("delegation-{}", uuid::Uuid::new_v4()) - }); - // The claimed announcement never carried an identity (Cursor's - // "MCP: tool" + "{}" — the wire will not re-send title/arguments): - // restore it NOW, before the multi-second spawn, so the live card - // shows the canonical delegate tool with its real arguments while - // the child is still starting. Hosts whose wire carried the - // identity (keyed or explicit-id claims) are left untouched — a - // reconstructed `raw_input` would clobber host-specific fields. - if claimed_identityless { - let mut raw_input = serde_json::Map::new(); - raw_input.insert("task".into(), serde_json::Value::String(req.task.clone())); - if let Ok(at) = serde_json::to_value(req.agent_type) { - raw_input.insert("agent_type".into(), at); - } - if let Some(dir) = req.requested_working_dir.as_deref() { - raw_input.insert("working_dir".into(), serde_json::Value::String(dir.into())); - } - self.meta_writer - .write_tool_call_identity( - &req.parent_connection_id, - &req.parent_tool_use_id, - crate::acp::delegation::DELEGATE_TOOL_REWRITE_TITLE, - serde_json::Value::Object(raw_input), - ) - .await; - } - } else { - // The client gave us the real ACP tool_call_id directly - // (`_meta.tool_use_id`), so we skip the claim path — but the - // lifecycle dispatcher may already have registered that same id as - // a (now indefinitely-retained) keyed pending entry. Consume it so - // it can't linger and be mis-claimed by a later same-key - // delegation. Idempotent and order-independent (see the method). - self.consume_explicit_tool_call(&req.parent_connection_id, &req.parent_tool_use_id) - .await; - } - let cfg = self.config_snapshot().await; - if !cfg.enabled { - self.drop_inflight(inflight_id).await; - return report_err( - req.agent_type, - DelegationError::Canceled { - reason: "delegation disabled".into(), - }, - None, - ); - } - - // --- Depth pre-check ---------------------------------------------------- - // We walk up to `limit + 1` so we know whether the *new* child would - // sit at >= limit. Cycles/dead chains saturate at the cap. - let lookup = self.depth_lookup.clone(); - let parent_depth = match crate::acp::delegation::depth::compute_depth( - req.parent_conversation_id, - |id| { - let lookup = lookup.clone(); - async move { lookup.parent_of(id).await } - }, - cfg.depth_limit + 1, - ) - .await - { - Ok(d) => d, - Err(e) => { - self.drop_inflight(inflight_id).await; - return report_err(req.agent_type, e, None); - } - }; - // The child the broker is about to create would sit at `parent_depth + 1`. - // Reject only when the *child* depth would strictly exceed the limit; - // a child sitting exactly at `depth_limit` is allowed. - if parent_depth + 1 > cfg.depth_limit { - self.drop_inflight(inflight_id).await; - return report_err( - req.agent_type, - DelegationError::DepthLimitExceeded { - current_depth: parent_depth, - limit: cfg.depth_limit, - }, - None, - ); - } - - // --- Spawn child connection -------------------------------------------- - // Pull per-agent overrides from the broker config (defaults to empty). - // Cloning is cheap — `AgentDelegationDefaults` is at most one Option - // and a small BTreeMap, and the spawner consumes both fields by value. - let (preferred_mode_id, preferred_config_values) = cfg - .agent_defaults - .get(&req.agent_type) - .map(|d: &AgentDelegationDefaults| (d.mode_id.clone(), d.config_values.clone())) - .unwrap_or((None, BTreeMap::new())); - // Checkpoint #1 (opportunistic): if a parent cancel already landed - // during the claim/depth phase, bail before spawning a child the parent - // has abandoned. No child exists yet, so there's nothing to tear down. - if self.take_inflight_cancel(inflight_id).await { - return report_err( - req.agent_type, - DelegationError::Canceled { - reason: "parent canceled".into(), - }, - None, - ); - } - let child_connection_id = match self - .spawner - .spawn( - &req.parent_connection_id, - req.agent_type, - req.working_dir.clone(), - preferred_mode_id, - preferred_config_values, - ) - .await - { - Ok(id) => id, - Err(e) => { - self.drop_inflight(inflight_id).await; - return report_err( - req.agent_type, - DelegationError::SpawnFailed(e.to_string()), - None, - ); - } - }; - - // Checkpoint #2: a parent cancel that landed during spawn() — the child - // now exists but no prompt has been sent, so disconnect it (mirroring - // the send-failure path's disconnect-only teardown) and bail. This is - // the primary guard for the spawn window, which can block while the - // agent process starts up. - if self.take_inflight_cancel(inflight_id).await { - let _ = self.spawner.disconnect(&child_connection_id).await; - return report_err( - req.agent_type, - DelegationError::Canceled { - reason: "parent canceled".into(), - }, - None, - ); - } - - // --- Send linked prompt ------------------------------------------------ - let call_id = uuid::Uuid::new_v4().to_string(); - // Bounded task label used by the started event and every meta write — - // the frontend card's fallback when the parent tool call's `raw_input` - // never carried the arguments (Cursor's identity-less announcements). - let task_preview = truncate_on_char_boundary(&req.task, TASK_PREVIEW_CAP); - // Now that the child connection and task id exist, fill the span's empty - // fields so every subsequent log line in this delegation carries the - // parent→child linkage (see the `delegation_task` span on this fn). - tracing::Span::current().record("child_connection_id", child_connection_id.as_str()); - tracing::Span::current().record("task_id", call_id.as_str()); - let link = DelegationLink { - parent_conversation_id: req.parent_conversation_id, - parent_tool_use_id: req.parent_tool_use_id.clone(), - delegation_call_id: call_id.clone(), - }; - - // Reserve this delegation (both ids) BEFORE sending its first prompt. - // `send_prompt_linked_for_delegation` persists the delegation link onto - // the child row (arming the lifecycle resolver) AND dispatches the - // prompt — after which a fast/empty turn's `TurnComplete` OR an - // immediate child-connection failure can fire before we park the pending - // entry below. The reservation lets those terminal events buffer their - // outcome (see `PendingInner`) for the park to drain, rather than - // no-oping and stranding `rx.await`. There is no `.await` between this - // reservation and `send_prompt` (so nothing the child does can be - // observed before the reservation is in place); it's cleared at park or - // on the send-failure path. Reserving by `call_id` AND - // `child_connection_id` lets each resolver gate on the id it holds — - // `complete_call` the `call_id`, `cancel_by_child_connection` the - // `child_connection_id`. - self.pending - .inner - .lock() - .await - .reserve(&call_id, &child_connection_id); - - let child_conversation_id = match self - .spawner - .send_prompt_linked_for_delegation(&child_connection_id, req.task.clone(), link) - .await - { - Ok(cid) => cid, - Err(e) => { - // Setup failed before parking — release the reservation (and - // discard any terminal that buffered against this delegation in - // the window) so nothing lingers or mis-binds a future id, and - // drop the in-flight record in the same lock acquisition. - { - let mut inner = self.pending.inner.lock().await; - inner.unreserve(&call_id, &child_connection_id); - inner.deregister_inflight(inflight_id); - } - let _ = self.spawner.disconnect(&child_connection_id).await; - return report_err( - req.agent_type, - DelegationError::SpawnFailed(e.to_string()), - None, - ); - } - }; - - // The child is now running. Stamp the start so terminal paths can - // report a real `duration_ms`. - let started_at = Instant::now(); - - // --- Mark the parent's tool call as in-flight ------------------------- - // The frontend's DelegationContext seeds its `parent_tool_use_id`-keyed - // binding map from this meta on snapshot replay, so a page refresh - // mid-delegation can reconstruct the child connection / conversation - // ids without depending on the live `delegation_started` event having - // been received. - self.write_meta_if_real( - &req.parent_connection_id, - &req.parent_tool_use_id, - build_delegation_meta( - "running", - Some(&child_connection_id), - Some(child_conversation_id), - None, - None, - // No meaningful elapsed yet — the child just started. - None, - Some(&task_preview), - Some(&call_id), - ), - ) - .await; - - // Announce the live delegation on the PARENT's event stream so the - // frontend `DelegationContext` binds the child inline and attaches its - // live sub-thread. Symmetric with the terminal `emit_completed_if_real`, - // and — unlike the removed child-stream emit in `send_prompt_linked` — - // delivered on a stream the parent is already attached to in web/server - // mode, carrying the real `parent_connection_id`. - self.emit_started_if_real( - &req.parent_connection_id, - &req.parent_tool_use_id, - &child_connection_id, - child_conversation_id, - req.agent_type, - &task_preview, - &call_id, - ) - .await; - - // --- Register pending, or resolve a terminal that beat us ------------- - // Under a single lock, decide this delegation's fate atomically against - // everything a concurrent resolver may have recorded while we were - // setting up: - // * a child terminal buffered against the reservation — a - // `TurnComplete` via `complete_call` (keyed by `call_id`) OR a child - // failure via `cancel_by_child_connection` (keyed by - // `child_connection_id`); either can race ahead of this park; or - // * a parent cancel that flagged this in-flight setup - // (`mark_inflight_canceled_for_parent`, which runs in the SAME lock - // acquisition that drains the parked `calls`). - // Precedence: strict first-terminal-wins by arrival stamp. Both a child - // terminal and a parent cancel carry the `seq` clock value they were - // recorded at, so whichever landed FIRST wins — a child that completed - // before the cancel keeps its result; a cancel that beat the completion - // discards it (the parent had already abandoned the turn). Ties are - // impossible: every event draws a distinct stamp under this one lock. - // Only when NOTHING beat us do we park for a future resolver, - // deregistering the in-flight record adjacent to `calls.insert` with no - // `.await` between — so a parent cancel serialized AFTER us finds the - // entry in `calls` and drains it, while one serialized BEFORE us is seen - // here via its stamp. When a terminal/cancel DID beat us we deliberately - // DON'T park: resolving inline (never leaving an entry for a second - // resolver to grab) rules out a double-finalize. - enum Disposition { - ChildTerminal(DelegationOutcome), - ParentCanceled, - Running, - } - // Near-zero elapsed for these setup-window races, but measured for - // consistency with the normal terminal paths. - let setup_duration_ms = started_at.elapsed().as_millis() as u64; - let disposition = { - let mut inner = self.pending.inner.lock().await; - // Each buffered child terminal carries (arrival_stamp, outcome). - let child_terminal: Option<(u64, DelegationOutcome)> = - if let Some((stamp, outcome)) = inner.take_early_complete(&call_id) { - Some((stamp, outcome)) - } else { - inner - .take_early_cancel(&child_connection_id) - .map(|(stamp, reason)| { - ( - stamp, - DelegationOutcome::from_err( - DelegationError::Canceled { reason }, - Some(child_conversation_id), - ), - ) - }) - }; - let parent_canceled_at = inner.inflight_canceled_at(inflight_id); - inner.unreserve(&call_id, &child_connection_id); - // For both terminal dispositions we record the completed result - // INSIDE this lock (atomically with unreserve/deregister) so a - // concurrent `get_delegation_status` can never observe the task as - // neither running nor completed. The `Running` arm inserts the live - // task instead of parking a `oneshot` — the caller returns the ack. - let record = |inner: &mut PendingInner, outcome: &DelegationOutcome| { - inner.insert_completed( - &call_id, - build_completed( - &req.parent_connection_id, - child_conversation_id, - req.agent_type, - setup_duration_ms, - outcome, - ), - ); - }; - match (child_terminal, parent_canceled_at) { - // Both raced in the setup window: the earlier arrival stamp wins. - (Some((child_stamp, outcome)), Some(cancel_stamp)) => { - inner.deregister_inflight(inflight_id); - if child_stamp < cancel_stamp { - record(&mut inner, &outcome); - Disposition::ChildTerminal(outcome) - } else { - record( - &mut inner, - &canceled_outcome(child_conversation_id, "parent canceled"), - ); - Disposition::ParentCanceled - } - } - // Only a child terminal fired. - (Some((_, outcome)), None) => { - inner.deregister_inflight(inflight_id); - record(&mut inner, &outcome); - Disposition::ChildTerminal(outcome) - } - // Only a parent cancel fired. - (None, Some(_)) => { - inner.deregister_inflight(inflight_id); - record( - &mut inner, - &canceled_outcome(child_conversation_id, "parent canceled"), - ); - Disposition::ParentCanceled - } - // Nothing beat us — register the running task for a future - // resolver, deregistering the in-flight record adjacent to the - // insert with no `.await` between (so a parent cancel serialized - // AFTER us finds it in `running` and drains it). - (None, None) => { - inner.running.insert( - call_id.clone(), - RunningTask { - child_connection_id: child_connection_id.clone(), - child_conversation_id, - parent_connection_id: req.parent_connection_id.clone(), - parent_tool_use_id: req.parent_tool_use_id.clone(), - agent_type: req.agent_type, - task_preview: task_preview.clone(), - task_id: call_id.clone(), - external_handle: req.external_handle.clone(), - started_at, - last_surfaced_block: None, - }, - ); - inner.deregister_inflight(inflight_id); - Disposition::Running - } - } - }; - - match disposition { - // A child terminal beat registration. Finalize (terminal meta + - // DelegationCompleted event + child teardown) and return the - // terminal report directly. The completed entry was recorded under - // the disposition lock above; wake any long-poll waiter. - Disposition::ChildTerminal(outcome) => { - self.finalize_delegation( - &req.parent_connection_id, - &req.parent_tool_use_id, - &child_connection_id, - child_conversation_id, - req.agent_type, - setup_duration_ms, - &outcome, - &task_preview, - &call_id, - ) - .await; - self.result_notify.notify_waiters(); - return report_from_outcome( - Some(call_id), - Some(req.agent_type), - &outcome, - Some(setup_duration_ms), - ); - } - // A parent cancel reached this delegation mid-setup — after the - // prompt was sent, before we registered. Tear the child down - // ourselves (cancel + disconnect, since a turn is in flight) and - // return a canceled report. The canceled result was recorded above. - Disposition::ParentCanceled => { - self.write_meta_if_real( - &req.parent_connection_id, - &req.parent_tool_use_id, - build_delegation_meta( - "failed", - Some(&child_connection_id), - Some(child_conversation_id), - Some("canceled"), - None, - Some(setup_duration_ms), - Some(&task_preview), - Some(&call_id), - ), - ) - .await; - self.emit_completed_if_real( - &req.parent_connection_id, - &req.parent_tool_use_id, - &child_connection_id, - child_conversation_id, - req.agent_type, - DelegationResultSummary::Err { - error_code: "canceled".to_string(), - }, - ) - .await; - let _ = self.spawner.cancel(&child_connection_id).await; - let _ = self.spawner.disconnect(&child_connection_id).await; - self.result_notify.notify_waiters(); - return report_from_outcome( - Some(call_id), - Some(req.agent_type), - &canceled_outcome(child_conversation_id, "parent canceled"), - Some(setup_duration_ms), - ); - } - // Registered in `running` — fall through to the second pre-cancel - // check, then return the ack. - Disposition::Running => {} - } - - // Second pre-cancel check: a `notifications/cancelled` may have landed - // between the entry-side check and the `running` registration above. If - // so, drain the task ourselves (so a racing `cancel_by_external_handle` - // doesn't double-finalize), record the canceled result, and return a - // canceled report instead of the Running ack. - if let Some(handle) = req.external_handle.as_deref() { - if self.take_pre_canceled_handle(handle).await { - // Capture the elapsed ONCE at terminalization (under the lock, - // when the running task is removed) so the completed-cache, the - // parent-card meta, and the returned report all report the same - // duration. `None` when nothing was drained. - let canceled_duration_ms = { - let mut inner = self.pending.inner.lock().await; - if inner.running.remove(&call_id).is_some() { - let outcome = - canceled_outcome(child_conversation_id, "canceled before await"); - let duration_ms = started_at.elapsed().as_millis() as u64; - inner.insert_completed( - &call_id, - build_completed( - &req.parent_connection_id, - child_conversation_id, - req.agent_type, - duration_ms, - &outcome, - ), - ); - Some(duration_ms) - } else { - None - } - }; - if let Some(duration_ms) = canceled_duration_ms { - self.write_meta_if_real( - &req.parent_connection_id, - &req.parent_tool_use_id, - build_delegation_meta( - "failed", - Some(&child_connection_id), - Some(child_conversation_id), - Some("canceled"), - None, - Some(duration_ms), - Some(&task_preview), - Some(&call_id), - ), - ) - .await; - self.emit_completed_if_real( - &req.parent_connection_id, - &req.parent_tool_use_id, - &child_connection_id, - child_conversation_id, - req.agent_type, - DelegationResultSummary::Err { - error_code: "canceled".to_string(), - }, - ) - .await; - let _ = self.spawner.cancel(&child_connection_id).await; - let _ = self.spawner.disconnect(&child_connection_id).await; - self.result_notify.notify_waiters(); - return report_from_outcome( - Some(call_id), - Some(req.agent_type), - &canceled_outcome(child_conversation_id, "canceled before await"), - Some(duration_ms), - ); - } - } - } - - // Registered and running in the background — return the ack. The child - // resolves later via the lifecycle → `complete_call` (or a cancel path). - running_ack(call_id, child_conversation_id, req.agent_type) - } - - /// Called by the child-session lifecycle subscriber on `TurnComplete` - /// (success path) or by error mappers (failure path). - /// - /// Migrates the task from `running` into `completed` (atomically, under one - /// lock) and then finalizes (terminal meta + `DelegationCompleted` event + - /// child teardown) and wakes any `get_delegation_status` long-poll. - /// - /// If no entry is in `running` under `call_id`, the outcome is buffered for - /// a racing `start_delegation` to drain at registration — but ONLY while the - /// delegation is still reserved (mid-setup). This closes the window where a - /// fast/empty turn's `TurnComplete` propagates through the lifecycle while - /// `start_delegation` is still between `send_prompt` and the `running` - /// insert: the prompt is only *enqueued* by `send_prompt`, and the child - /// loop emits `TurnComplete` independently, so a completion CAN beat it. When - /// the `call_id` is no longer reserved the call was already resolved by - /// another terminal path, so the buffer is skipped (silent no-op). - pub async fn complete_call(&self, call_id: &str, outcome: DelegationOutcome) { - let task = { - let mut inner = self.pending.inner.lock().await; - match inner.running.remove(call_id) { - Some(task) => { - // Atomic running → completed so a concurrent status query - // never sees the task as neither running nor completed. - let duration_ms = task.started_at.elapsed().as_millis() as u64; - inner.insert_completed( - call_id, - build_completed( - &task.parent_connection_id, - task.child_conversation_id, - task.agent_type, - duration_ms, - &outcome, - ), - ); - Some((task, duration_ms)) - } - None => { - // Buffer for the racing `start_delegation` to drain iff still - // reserved (mid-setup); a no-op otherwise, so the clone only - // materializes on the genuine pre-registration race. - inner.buffer_early_complete(call_id, outcome.clone()); - None - } - } - }; - if let Some((task, duration_ms)) = task { - self.finalize_delegation( - &task.parent_connection_id, - &task.parent_tool_use_id, - &task.child_connection_id, - task.child_conversation_id, - task.agent_type, - duration_ms, - &outcome, - &task.task_preview, - &task.task_id, - ) - .await; - self.result_notify.notify_waiters(); - } - } - - /// Write the terminal meta, emit `DelegationCompleted`, and tear down the - /// child for a resolved delegation. Shared by `complete_call` and - /// `start_delegation`'s early-terminal pickup. Mirrors the resolution onto - /// the parent's `delegate_to_agent` ToolCallState meta (including a bounded - /// `text_preview` on the completed path so a post-refresh snapshot renders - /// the result inline) so snapshot recovery shows the final state without the - /// live `delegation_completed` event. Does not touch the pending maps — the - /// caller owns the `running` → `completed` migration. - /// - /// `duration_ms` is the broker-measured elapsed time (from `started_at`), - /// carried onto the event summary so the parent UI shows a real duration. - #[allow(clippy::too_many_arguments)] - async fn finalize_delegation( - &self, - parent_connection_id: &str, - parent_tool_use_id: &str, - child_connection_id: &str, - child_conversation_id: i32, - agent_type: AgentType, - duration_ms: u64, - outcome: &DelegationOutcome, - task_preview: &str, - task_id: &str, - ) { - let meta = match outcome { - DelegationOutcome::Ok(ok) => build_delegation_meta( - "completed", - Some(child_connection_id), - Some(child_conversation_id), - None, - build_text_preview(&ok.text).as_deref(), - Some(duration_ms), - Some(task_preview), - Some(task_id), - ), - DelegationOutcome::Err { code, .. } => build_delegation_meta( - "failed", - Some(child_connection_id), - Some(child_conversation_id), - Some(code), - None, - Some(duration_ms), - Some(task_preview), - Some(task_id), - ), - }; - self.write_meta_if_real(parent_connection_id, parent_tool_use_id, meta) - .await; - self.emit_completed_if_real( - parent_connection_id, - parent_tool_use_id, - child_connection_id, - child_conversation_id, - agent_type, - outcome_to_summary(outcome, duration_ms), - ) - .await; - // v1 one-shot: always tear down the child. - let _ = self.spawner.disconnect(child_connection_id).await; - } - - /// Internal helper — apply the meta write iff the parent's - /// `tool_use_id` refers to a real ACP `tool_call_id`. The - /// broker-synthesized `"delegation-"` placeholder targets no - /// ToolCallState, so emitting a `ToolCallUpdate` against it would be - /// noise that the frontend would route through `apply_tool_call_update` - /// to a non-existent entry. See `meta_writer::is_synthetic_parent_tool_use_id`. - async fn write_meta_if_real( - &self, - parent_connection_id: &str, - parent_tool_use_id: &str, - meta: serde_json::Value, - ) { - if is_synthetic_parent_tool_use_id(parent_tool_use_id) { - return; - } - self.meta_writer - .write_meta(parent_connection_id, parent_tool_use_id, meta) - .await; - } - - /// Internal helper — emit `AcpEvent::DelegationStarted` on the parent's - /// stream iff the `parent_tool_use_id` refers to a real ACP tool_call. - /// Mirror of `emit_completed_if_real`: same synthetic-id skip, and the - /// event rides the parent's stream so the frontend `DelegationContext` - /// receives it via the parent's per-connection attach stream in - /// web/server mode (not only via the desktop firehose). - #[allow(clippy::too_many_arguments)] - async fn emit_started_if_real( - &self, - parent_connection_id: &str, - parent_tool_use_id: &str, - child_connection_id: &str, - child_conversation_id: i32, - agent_type: AgentType, - task_preview: &str, - task_id: &str, - ) { - if is_synthetic_parent_tool_use_id(parent_tool_use_id) { - return; - } - self.event_emitter - .emit_started( - parent_connection_id, - parent_tool_use_id, - child_connection_id, - child_conversation_id, - agent_type, - task_preview, - task_id, - ) - .await; - } - - /// Internal helper — emit `AcpEvent::DelegationCompleted` on the parent's - /// stream iff the `parent_tool_use_id` refers to a real ACP tool_call. - /// Synthetic ids (the `"delegation-"` UUID fallback) map to no - /// live UI binding, so the emit would be wasted noise — same skip - /// criterion as `write_meta_if_real`. - async fn emit_completed_if_real( - &self, - parent_connection_id: &str, - parent_tool_use_id: &str, - child_connection_id: &str, - child_conversation_id: i32, - agent_type: AgentType, - result: DelegationResultSummary, - ) { - if is_synthetic_parent_tool_use_id(parent_tool_use_id) { - return; - } - self.event_emitter - .emit_completed( - parent_connection_id, - parent_tool_use_id, - child_connection_id, - child_conversation_id, - agent_type, - result, - ) - .await; - } - - /// Cancel the pending delegation whose `external_handle` matches. - /// Called by the MCP listener on receipt of `notifications/cancelled` - /// from a companion. When no matching pending entry exists (the - /// cancel arrived before `handle_request` reached the - /// pending-registration phase) the handle is stashed in - /// `pre_canceled_handles` so the in-flight request can drain itself - /// when it tries to register or shortly after. - pub async fn cancel_by_external_handle(&self, external_handle: &str, reason: String) { - let drained = { - let mut inner = self.pending.inner.lock().await; - let keys: Vec = inner - .running - .iter() - .filter(|(_, v)| v.external_handle.as_deref() == Some(external_handle)) - .map(|(k, _)| k.clone()) - .collect(); - drain_and_record_canceled(&mut inner, keys, &reason) - }; - if drained.is_empty() { - // Race: the cancel beat the handle's `running` registration. Buffer - // it (capped, FIFO-evicted) so `start_delegation` can drain itself on - // the next checkpoint instead of proceeding to spawn the child. - self.buffer_pre_canceled_handle(external_handle.to_string()) - .await; - return; - } - for (task, duration_ms) in drained { - // A turn is in flight, so cancel + disconnect. - self.teardown_canceled_child(&task, duration_ms, true).await; - } - self.result_notify.notify_waiters(); - } - - /// Resolve the pending delegation whose child matches - /// `child_connection_id` with a `canceled` outcome. Used when a child - /// session disconnects or errors out without firing a clean - /// TurnComplete — the parent's `tool_use_id` shouldn't dangle. - /// No-op when no matching entry exists. - /// - /// `terminal_error` carries the child connection's last `AcpEvent::Error` - /// detail when the lifecycle worker is dispatching off an `Error` event - /// (vs. a bare `Disconnected`). When present, it gets appended to the - /// `Canceled { reason }` string so the parent agent's tool-call result - /// surfaces the real cause (e.g. "Authentication required", - /// "transport closed") instead of the opaque default. Falls back to - /// the default reason when `None`. - pub async fn cancel_by_child_connection( - &self, - child_connection_id: &str, - terminal_error: Option<&str>, - ) { - let reason = child_canceled_reason(terminal_error); - let drained = { - let mut inner = self.pending.inner.lock().await; - let keys: Vec = inner - .running - .iter() - .filter(|(_, v)| v.child_connection_id == child_connection_id) - .map(|(k, _)| k.clone()) - .collect(); - if keys.is_empty() { - // No running entry. If the child is still reserved, - // `start_delegation` is mid-setup and this failure beat the - // `running` insert — buffer its detail for it to drain at - // registration instead of no-oping. `buffer_child_failure` is a - // no-op when the child isn't reserved, so a normal - // post-resolution child teardown accumulates nothing. - inner.buffer_child_failure( - child_connection_id, - terminal_error.map(|s| s.to_string()), - ); - Vec::new() - } else { - drain_and_record_canceled(&mut inner, keys, &reason) - } - }; - for (task, duration_ms) in drained { - // The child already disconnected/errored — disconnect-only teardown - // (no spawner `cancel`, there's no live turn to interrupt). - self.teardown_canceled_child(&task, duration_ms, false).await; - } - self.result_notify.notify_waiters(); - } - - /// Cascade-cancel every pending delegation owned by `parent_connection_id` - /// when the parent **connection tears down** (disconnect / `run_connection` - /// exit). Drops the parent's entire tool_call tracker bucket (`pending` + - /// `consumed`) since the connection is going away. Runs fully inline — the - /// connection is already exiting, so there is no next prompt to unblock. - pub async fn cancel_by_parent(&self, parent_connection_id: &str) { - let drained = self - .drain_for_parent_cancel(parent_connection_id, false) - .await; - self.finalize_parent_cancel(drained).await; - } - - /// Cascade-cancel every pending delegation owned by `parent_connection_id` - /// for a **turn/prompt cancel** where the parent connection STAYS ALIVE - /// (a non-`end_turn` turn end, or a user Cancel between/within prompts). - /// - /// The fast, turn-scoped part — tombstoning the tool_call tracker and - /// removing this parent's parked calls — runs SYNCHRONOUSLY: the caller - /// awaits it before the connection loop accepts the next prompt, so it can't - /// race a next-turn registration and tombstone/cancel that turn's legitimate - /// entries (the safety the `drop_tool_calls_for_parent` invariant relies - /// on). Only the slow child teardown (meta/emit + spawner `cancel` / - /// `disconnect`, which can block on slow agents) is backgrounded, so the - /// user-visible Cancel path stays responsive. - /// - /// RETAINS the parent's `consumed` tool_call memory (and tombstones the - /// cancelled turn's unclaimed `pending` ids into it): dropping it would let - /// a host re-emit of an already-handled `tool_call_id` re-register and - /// mis-bind the next same-key delegation on this live connection — see - /// `drop_tool_calls_for_parent`. - pub async fn cancel_by_parent_turn(&self, parent_connection_id: &str) { - let drained = self - .drain_for_parent_cancel(parent_connection_id, true) - .await; - // The fast drain above already ran inline (scoped to the just-ended - // turn); background only the slow child teardown. - let broker = self.clone(); - tokio::spawn(async move { - broker.finalize_parent_cancel(drained).await; - }); - } - - /// Fast, lock-guarded part of a parent cancel: drop/tombstone this parent's - /// tool_call tracker (per `keep_consumed`, see `drop_tool_calls_for_parent`) - /// and remove every running task it owns, returning them for the (slow) - /// child teardown. Touches only the two broker mutexes — no spawner I/O — so - /// it is safe to await inline in the connection loop before the next prompt - /// is accepted. - /// - /// `keep_consumed` also governs the completed-cache: a **turn** cancel - /// (`true`) records each drained task as `Canceled` so the still-alive - /// connection's LLM can still query it; a **connection teardown** (`false`) - /// drops the parent's whole completed-cache instead — the parent is gone, so - /// nothing will query it. - async fn drain_for_parent_cancel( - &self, - parent_connection_id: &str, - keep_consumed: bool, - ) -> Vec<(RunningTask, u64)> { - // Also drain any tool_call ids captured ahead of an MCP round-trip that - // never arrived — keeps the map bounded across parent reconnects. - // Teardown drops the whole bucket; a turn cancel keeps `consumed` so a - // later re-emit can't mis-bind the next delegation. - self.drop_tool_calls_for_parent(parent_connection_id, keep_consumed) - .await; - let drained = { - let mut inner = self.pending.inner.lock().await; - // Flag every still-in-flight setup this parent owns in the SAME lock - // acquisition that drains its running tasks: a delegation is then - // caught either here (mid-setup → `start_delegation` tears its child - // down at the next checkpoint) or by the running drain below (already - // registered) — there is no interleaving where both miss it. - inner.mark_inflight_canceled_for_parent(parent_connection_id); - let keys: Vec = inner - .running - .iter() - .filter(|(_, v)| v.parent_connection_id == parent_connection_id) - .map(|(k, _)| k.clone()) - .collect(); - if keep_consumed { - // Turn cancel: connection stays alive → keep each canceled - // result queryable. - drain_and_record_canceled(&mut inner, keys, "parent canceled") - } else { - // Connection teardown: just remove the running tasks and drop the - // whole completed-cache for this parent. No completed entry to - // match, but still capture the elapsed once (at drain time) so - // the teardown meta doesn't recompute it later. - let drained: Vec<(RunningTask, u64)> = keys - .into_iter() - .map(|k| { - let task = inner.running.remove(&k).expect("key just observed"); - let duration_ms = task.started_at.elapsed().as_millis() as u64; - (task, duration_ms) - }) - .collect(); - inner.drop_completed_for_parent(parent_connection_id); - drained - } - }; - self.result_notify.notify_waiters(); - drained - } - - /// Slow part of a parent cancel: for each drained task, patch the parent - /// meta, emit `DelegationCompleted`, and tear the child down. The canceled - /// result was already recorded into `completed` (turn cancel) by - /// `drain_for_parent_cancel` under the lock, so this is pure I/O. Split out - /// so a turn cancel can background it without delaying the fast, turn-scoped - /// drain. - async fn finalize_parent_cancel(&self, drained: Vec<(RunningTask, u64)>) { - for (task, duration_ms) in drained { - // A turn was in flight → cancel + disconnect. - self.teardown_canceled_child(&task, duration_ms, true).await; - } - } - - /// Shared canceled-child teardown: best-effort `failed`/`canceled` meta - /// patch (so a parent-side snapshot post-cancel shows the delegation as - /// canceled rather than stuck on "running"), a `DelegationCompleted` err - /// event, then child teardown. `cancel_turn` is `true` when a turn is in - /// flight (cancel + disconnect) and `false` when the child already - /// disconnected/errored (disconnect only). Does NOT touch the pending maps — - /// the caller already migrated the task into `completed`. - /// - /// `duration_ms` is the elapsed captured by `drain_and_record_canceled` at - /// drain time — reused here (not recomputed) so the parent-card meta matches - /// the completed-cache duration the status/cancel cards report, even when - /// this teardown is backgrounded. - async fn teardown_canceled_child( - &self, - task: &RunningTask, - duration_ms: u64, - cancel_turn: bool, - ) { - self.write_meta_if_real( - &task.parent_connection_id, - &task.parent_tool_use_id, - build_delegation_meta( - "failed", - Some(&task.child_connection_id), - Some(task.child_conversation_id), - Some("canceled"), - None, - Some(duration_ms), - Some(&task.task_preview), - Some(&task.task_id), - ), - ) - .await; - self.emit_completed_if_real( - &task.parent_connection_id, - &task.parent_tool_use_id, - &task.child_connection_id, - task.child_conversation_id, - task.agent_type, - DelegationResultSummary::Err { - error_code: "canceled".to_string(), - }, - ) - .await; - if cancel_turn { - let _ = self.spawner.cancel(&task.child_connection_id).await; - } - let _ = self.spawner.disconnect(&task.child_connection_id).await; - } - - /// Backs the `get_delegation_status` tool for a single task id — a thin - /// wrapper over [`Self::get_tasks_status`] so the single- and batch-poll - /// paths share one snapshot/wait implementation. A one-id batch's - /// "any task settled" wake condition is exactly "this task settled", so the - /// blocking semantics are identical to the historical single-task loop. - pub async fn get_task_status( - &self, - parent_connection_id: &str, - parent_conversation_id: Option, - task_id: &str, - wait: StatusWait, - ) -> DelegationTaskReport { - let ids = [task_id.to_string()]; - self.get_tasks_status(parent_connection_id, parent_conversation_id, &ids, wait) - .await - .pop() - .unwrap_or_else(|| unknown_report(task_id)) - } - - /// Wake every parked status long-poll so it can re-probe its children. - /// - /// Called by the lifecycle dispatcher when ANY connection raises or resolves - /// a blocking prompt — permission, question, or plan approval. Cheap and - /// unconditional: these events are rare, and a wake for a connection that - /// isn't anybody's delegation child just re-snapshots and re-parks, exactly - /// like the spurious wakes `get_tasks_status` already tolerates. - pub fn note_blocking_changed(&self) { - self.result_notify.notify_waiters(); - } - - /// Backs the batch `get_delegation_status` tool. Resolves the status of one - /// or many task ids in a single pass — each from the completed-cache, then - /// the running set, then the DB fallback — scoped to the calling parent (a - /// task owned by another parent reports `Unknown`, never leaking it). Returns - /// one report per requested id, in request order. - /// - /// Blocking obeys [`StatusWait`]: `Immediate` returns the first snapshot. - /// `Bounded`/`Infinite` return as soon as ANY requested task is terminal — - /// INCLUDING one already terminal at entry, so a completed result is never - /// held hostage to a long-running sibling (the caller re-polls the - /// still-running ids to collect the rest) — **or as soon as one becomes - /// blocked on a user decision**. Only an all-running, nothing-newly-blocked - /// batch parks: it wakes when a task settles (the running count drops below - /// the total), when a child raises a blocking prompt, or — for `Bounded` — - /// when the deadline elapses. An all-settled batch returns immediately even - /// under `Infinite`, so it never parks forever. - /// - /// The blocked-return is what closes #447. Without it, a child that hits a - /// permission prompt parks the parent's `wait_ms: 0` call for as long as the - /// user takes to notice — indefinitely, for an unattended run — and the - /// orchestrating LLM cannot even report the stall, because "working" and - /// "waiting on a human" look identical from here. Each blocking prompt is - /// surfaced ONCE (see `RunningTask::last_surfaced_block`), so re-polling an - /// already-reported block goes back to waiting rather than spinning. - pub async fn get_tasks_status( - &self, - parent_connection_id: &str, - parent_conversation_id: Option, - task_ids: &[String], - wait: StatusWait, - ) -> Vec { - if task_ids.is_empty() { - return Vec::new(); - } - // A bounded wait gets a single fixed deadline; Immediate and Infinite - // carry none — Immediate returns on the first pass, Infinite parks on - // `result_notify` until a task is terminal or newly blocked. - let deadline = match wait { - StatusWait::Bounded(ms) => Some(Instant::now() + Duration::from_millis(ms)), - StatusWait::Immediate | StatusWait::Infinite => None, - }; - loop { - // Arm the notify BEFORE the snapshot so a completion landing between - // the snapshot and the await isn't lost (enable() registers now). - let notified = self.result_notify.notified(); - tokio::pin!(notified); - notified.as_mut().enable(); - - // One lock acquisition classifies every requested id. The async - // resolution of running (live reply) / not-in-memory (DB) ids is - // deferred to `assemble_reports`, OUTSIDE this lock. - let classes: Vec = { - let inner = self.pending.inner.lock().await; - task_ids - .iter() - .map(|id| classify_locked(&inner, parent_connection_id, id)) - .collect() - }; - let running_count = classes - .iter() - .filter(|c| matches!(c, StatusClass::Running { .. })) - .count(); - - // Probe each running child for a blocking prompt. Done HERE, after - // the pending lock was dropped at the end of the block above and - // before any early return, because it takes the child's - // `SessionState` lock — the same ordering `attach_live_reply` has - // always used. The result rides along to `assemble_reports` so a - // pass never probes the same child twice. - let blocked = self.probe_blocked(&classes).await; - - // Return now when the poll is Immediate, OR when at least one - // requested task is already (or now) terminal — i.e. not EVERY task - // is still running. This honors the contract "returns as soon as ANY - // requested task reaches a terminal state": a mixed [terminal, - // running] batch surfaces the terminal report immediately instead of - // holding it hostage to a long-running sibling, and the caller - // re-polls (narrowing to the still-running ids) to collect the rest. - // `running_count == 0` (all settled) is the special case that also - // makes Infinite safe. The id set is fixed and a task can only LEAVE - // the running map during a wait (never (re)enter), so once a parked - // all-running batch is woken by a settle the count has dropped below - // the total and this returns; a spurious wake (another parent's task) - // re-snapshots all-running and re-parks. - if matches!(wait, StatusWait::Immediate) || running_count < task_ids.len() { - return self - .assemble_reports(parent_conversation_id, task_ids, classes, blocked) - .await; - } - // Every task is still running, but one of them just parked on the - // user. That is not progress and no completion signal is coming - // until a human acts, so stop waiting and say so. The claim marks - // each prompt as surfaced, so the NEXT poll on the same prompt falls - // through to the park below instead of returning instantly. - let claimed = self.claim_new_blocks(task_ids, &blocked).await; - if claimed.any_claimed { - return self - .assemble_reports(parent_conversation_id, task_ids, classes, blocked) - .await; - } - // A `Bounded` wait gives up at its deadline and returns the running - // snapshot. - let now = Instant::now(); - if deadline.is_some_and(|d| now >= d) { - return self - .assemble_reports(parent_conversation_id, task_ids, classes, blocked) - .await; - } - // Park until the next completion signal — bounded by the deadline - // when there is one, and ALWAYS bounded by `retry_at` when a - // suppressed block is waiting to become reportable again. Without - // that second bound an `Infinite` wait would park on a notify that - // nothing is going to fire: a child parked on a permission emits - // nothing further by itself, so the resurface valve would never get - // a chance to run and a report lost in transit would strand the - // caller for good. - let wake_at = match (deadline, claimed.retry_at) { - (Some(d), Some(r)) => Some(d.min(r)), - (d, r) => d.or(r), - }; - match wake_at { - Some(t) => { - let remaining = t.saturating_duration_since(now); - tokio::select! { - _ = &mut notified => {} - _ = tokio::time::sleep(remaining) => {} - } - } - None => { - notified.await; - } - } - // Loop: re-snapshot (a task likely just completed, the deadline - // passed and the next pass returns the running snapshot, or a - // suppressed block is now reportable again). - } - } - - /// Ask each `Running` entry's child what it is blocked on, position-aligned - /// with `classes` (non-running slots are `None`). One probe per child per - /// pass; must be called with the pending lock RELEASED (it takes the child's - /// `SessionState` lock). - async fn probe_blocked(&self, classes: &[StatusClass]) -> Vec> { - let mut out = Vec::with_capacity(classes.len()); - for class in classes { - let blocked = match class { - StatusClass::Running { - child_connection_id, - .. - } => self.live_reply_lookup.blocked_on(child_connection_id).await, - _ => None, - }; - out.push(blocked); - } - out - } - - /// Claim the blocking prompts in `blocked` that are reportable right now, - /// returning whether any was — and, when none was, the earliest [`Instant`] - /// at which one becomes reportable again. - /// - /// This is the ratchet: a `wait_ms: 0` poll returns the first time a child - /// parks, but a re-poll while the SAME prompt is still unanswered finds - /// nothing new and goes back to waiting — otherwise the caller's wait loop - /// would return instantly forever and burn a round-trip per iteration while - /// the user is simply slow to click. A second, different prompt is new - /// again and returns, and so does the same prompt once - /// [`BLOCK_RESURFACE_INTERVAL`] has passed (the delivery-failure valve — see - /// [`RunningTask::last_surfaced_block`]). - /// - /// Positionally aligned with `task_ids`. Silently skips ids no longer in the - /// running map (settled between the snapshot and here) — those return via - /// the terminal path on the next pass anyway. - async fn claim_new_blocks( - &self, - task_ids: &[String], - blocked: &[Option], - ) -> ClaimedBlocks { - let mut out = ClaimedBlocks::default(); - if blocked.iter().all(|b| b.is_none()) { - return out; - } - let now = Instant::now(); - let mut inner = self.pending.inner.lock().await; - for (id, blocked) in task_ids.iter().zip(blocked) { - let Some(blocked) = blocked else { continue }; - let Some(task) = inner.running.get_mut(id) else { - continue; - }; - if let Some(prev) = task.last_surfaced_block.as_ref() { - if prev.request_id == blocked.request_id { - let due = prev.at + self.block_resurface; - if now < due { - // Not reportable yet. Deliberately does NOT refresh - // `at` — that would push the valve out forever under - // repeated polling. - out.retry_at = Some(out.retry_at.map_or(due, |t: Instant| t.min(due))); - continue; - } - } - } - task.last_surfaced_block = Some(SurfacedBlock { - request_id: blocked.request_id.clone(), - at: now, - }); - out.any_claimed = true; - } - out - } - - /// Finish a batch status pass: resolve each [`StatusClass`] into a final - /// report AFTER the pending lock is released. `Running` ids get their latest - /// live reply (or blocking prompt) attached; `NotInMemory` ids fall back to - /// the DB status lookup. Reports come back in `task_ids` order. - /// - /// `blocked` is the already-probed result from [`Self::probe_blocked`] for - /// this same pass, position-aligned with `classes`. - async fn assemble_reports( - &self, - parent_conversation_id: Option, - task_ids: &[String], - classes: Vec, - blocked: Vec>, - ) -> Vec { - let mut out = Vec::with_capacity(classes.len()); - let mut blocked = blocked.into_iter().chain(std::iter::repeat_with(|| None)); - for (id, class) in task_ids.iter().zip(classes) { - let blocked = blocked.next().flatten(); - let report = match class { - StatusClass::Settled(report) => report, - StatusClass::Running { - mut report, - child_connection_id, - } => { - match blocked { - // A blocked child's last reply is stale by definition — - // it is what it said BEFORE it stopped — so the block - // replaces it rather than competing with it. - Some(blocked) => attach_blocked(&mut report, blocked), - None => { - self.attach_live_reply(&mut report, &child_connection_id) - .await - } - } - report - } - StatusClass::NotInMemory => self.status_from_db(parent_conversation_id, id).await, - }; - out.push(report); - } - out - } - - /// Upgrade a running report's bare `"Running."` message with the child's - /// latest one-line activity, so the parent LLM gets a concrete sign of - /// progress it can report in one shot (instead of polling-and-narrating). - /// Called only on the actual running-return paths, AFTER the pending lock is - /// released. A no-op when the lookup has nothing (default Noop lookup, child - /// gone, or no live output yet) — the report stays `"Running."`. - /// - /// The hint goes on its OWN line (`"Running.\nLatest sub-agent reply: …"`), - /// not appended to the marker line. On hosts that persist only the - /// `CallToolResult` content text (e.g. Claude Code), the frontend recognizes - /// a still-running poll by the standalone first line `"Running."` — keeping - /// the child-controlled reply text on a separate line means a *completed* - /// result that merely starts with "Running. …" can never be misread as - /// running. See `textRunningStatus` in `src/lib/delegation-status.ts`. - async fn attach_live_reply( - &self, - report: &mut DelegationTaskReport, - child_connection_id: &str, - ) { - if let Some(reply) = self - .live_reply_lookup - .latest_reply(child_connection_id) - .await - { - report.message = Some(format!("Running.\nLatest sub-agent reply: {reply}")); - } - } - - /// Backs the `cancel_delegation` tool. Cancels a running task owned by the - /// caller (recording it `Canceled` + tearing the child down) and returns the - /// resulting report. A task that already finished returns its terminal - /// report; one not in memory falls back to the DB status (a finished task - /// can't be canceled). Parent-scoped like `get_task_status`. - pub async fn cancel_task_by_id( - &self, - parent_connection_id: &str, - parent_conversation_id: Option, - task_id: &str, - ) -> DelegationTaskReport { - let drained = { - let mut inner = self.pending.inner.lock().await; - if let Some(c) = inner.completed.get(task_id) { - if c.parent_connection_id == parent_connection_id { - return completed_report(task_id, c); - } - return unknown_report(task_id); - } - match inner.running.get(task_id) { - Some(r) if r.parent_connection_id == parent_connection_id => { - drain_and_record_canceled( - &mut inner, - vec![task_id.to_string()], - "canceled by request", - ) - .pop() - } - Some(_) => return unknown_report(task_id), - None => None, - } - }; - match drained { - Some((task, duration_ms)) => { - // A turn is in flight → cancel + disconnect. Reuse the duration - // captured at drain time for both the teardown meta and the - // report, so all three (completed-cache, meta, report) agree. - self.teardown_canceled_child(&task, duration_ms, true).await; - self.result_notify.notify_waiters(); - report_from_outcome( - Some(task_id.to_string()), - Some(task.agent_type), - &canceled_outcome(task.child_conversation_id, "canceled by request"), - Some(duration_ms), - ) - } - None => self.status_from_db(parent_conversation_id, task_id).await, - } - } - - /// DB status fallback for a task evicted from / never in the in-memory maps. - /// Scopes to the caller's conversation: a child whose `parent_id` doesn't - /// match (or when the caller has no active conversation) reports `Unknown`. - async fn status_from_db( - &self, - parent_conversation_id: Option, - task_id: &str, - ) -> DelegationTaskReport { - match self.status_lookup.find_by_call_id(task_id).await { - Some(rec) - if parent_conversation_id.is_some() && rec.parent_id == parent_conversation_id => - { - db_report(task_id, &rec) - } - _ => unknown_report(task_id), - } - } - - /// Test-only shim preserving the old blocking `handle_request` contract over - /// the async path: start the delegation, then block until it reaches a - /// terminal state (driven by the test's `complete_call` / cancel), mapping - /// the terminal report back to a `DelegationOutcome`. Keeps the broker's - /// extensive setup-window race tests exercising the same lifecycle without - /// each rewriting to the start/poll/collect shape. - #[cfg(any(test, feature = "test-utils"))] - pub async fn handle_request(&self, req: DelegationRequest) -> DelegationOutcome { - let parent_connection_id = req.parent_connection_id.clone(); - let parent_conversation_id = Some(req.parent_conversation_id); - let ack = self.start_delegation(req).await; - let task_id = match ack.task_id.clone() { - Some(id) => id, - // Setup failed before a task existed — the ack itself is terminal. - None => return report_to_outcome(&ack), - }; - if ack.status != TaskStatus::Running { - return report_to_outcome(&ack); - } - // Block until terminal via the long-poll path (re-issued so an - // indefinitely-pending task in a test simply parks here, mirroring the - // old unbounded `rx.await`). - loop { - let report = self - .get_task_status( - &parent_connection_id, - parent_conversation_id, - &task_id, - StatusWait::Bounded(3_600_000), - ) - .await; - if report.status != TaskStatus::Running { - return report_to_outcome(&report); - } - } - } - - #[cfg(any(test, feature = "test-utils"))] - pub async fn peek_first_pending_call_id(&self) -> Option { - self.pending - .inner - .lock() - .await - .running - .keys() - .next() - .cloned() - } - - #[cfg(any(test, feature = "test-utils"))] - pub async fn pending_count(&self) -> usize { - self.pending.inner.lock().await.running.len() - } - - /// Count of cached completed results across all parents. - #[cfg(any(test, feature = "test-utils"))] - pub async fn completed_count(&self) -> usize { - self.pending.inner.lock().await.completed.len() - } - - /// Count of in-flight (registered-at-entry, not-yet-parked / not-yet-exited) - /// `handle_request` setups. Should return to 0 on every exit path. - #[cfg(any(test, feature = "test-utils"))] - pub async fn inflight_count(&self) -> usize { - self.pending.inner.lock().await.inflight.len() - } - - /// Count of in-setup (reserved, not-yet-parked) delegations. Each holds one - /// child and one call_id, so this counts both. - #[cfg(any(test, feature = "test-utils"))] - pub async fn reserved_child_count(&self) -> usize { - self.pending.inner.lock().await.setups.len() - } - - #[cfg(any(test, feature = "test-utils"))] - pub async fn reserved_call_count(&self) -> usize { - self.pending.inner.lock().await.setups.len() - } - - #[cfg(any(test, feature = "test-utils"))] - pub async fn early_cancel_count(&self) -> usize { - self.pending.inner.lock().await.early_cancels.len() - } - - #[cfg(any(test, feature = "test-utils"))] - pub async fn early_complete_count(&self) -> usize { - self.pending.inner.lock().await.early_completes.len() - } - - /// First reserved (mid-setup) `call_id`, if any — lets a test resolve a - /// delegation via `complete_call` while it's pinned in the reserve→park - /// window (its entry isn't parked yet, so `peek_first_pending_call_id` - /// can't see it). - #[cfg(any(test, feature = "test-utils"))] - pub async fn peek_reserved_call_id(&self) -> Option { - self.pending - .inner - .lock() - .await - .setups - .keys() - .next() - .cloned() - } -} - -/// `ConversationDepthLookup` over the live `AppDatabase`. Used by the -/// production wiring; tests use the in-module `MockDepth`. -pub struct DbDepthLookup { - pub db: Arc, -} - -#[async_trait] -impl ConversationDepthLookup for DbDepthLookup { - async fn parent_of(&self, conversation_id: i32) -> Result, DelegationError> { - use sea_orm::EntityTrait; - let row = crate::db::entities::conversation::Entity::find_by_id(conversation_id) - .one(&self.db.conn) - .await - .map_err(|e| DelegationError::SubagentRuntimeError(format!("db: {e}")))?; - Ok(row.and_then(|r| r.parent_id)) - } -} - -/// `ChildStatusLookup` over the live `AppDatabase`. Recovers a delegation -/// task's terminal status (NOT its text — child output isn't in codeg's DB) -/// from the child conversation row once its in-memory result was evicted. -pub struct DbChildStatusLookup { - pub db: Arc, -} - -#[async_trait] -impl ChildStatusLookup for DbChildStatusLookup { - async fn find_by_call_id(&self, call_id: &str) -> Option { - let summary = crate::db::service::conversation_service::get_by_delegation_call_id( - &self.db.conn, - call_id, - ) - .await - .ok() - .flatten()?; - // `summary.status` is the serialized `ConversationStatus` string. - let status = match summary.status.as_str() { - "in_progress" => TaskStatus::Running, - "pending_review" | "completed" => TaskStatus::Completed, - "cancelled" => TaskStatus::Canceled, - _ => TaskStatus::Unknown, - }; - Some(ChildStatusRecord { - child_conversation_id: summary.id, - status, - agent_type: summary.agent_type, - parent_id: summary.parent_id, - }) - } -} - -#[cfg(test)] -mod tests { - use super::*; - use crate::acp::delegation::spawner::{mock::MockSpawner, SpawnerError}; - use crate::acp::delegation::types::DelegationSuccess; - use crate::models::AgentType; - - /// Test-only `ConversationDepthLookup` that resolves against a flat - /// (id, parent_id) table. Unknown ids return `Ok(None)` to keep test - /// setup small. - struct MockDepth(Vec<(i32, Option)>); - - #[async_trait] - impl ConversationDepthLookup for MockDepth { - async fn parent_of(&self, id: i32) -> Result, DelegationError> { - Ok(self.0.iter().find(|(c, _)| *c == id).and_then(|(_, p)| *p)) - } - } - - fn shallow_lookup() -> Arc { - // parent conversation is the root — depth = 0, no rejection. - Arc::new(MockDepth(vec![(1, None)])) as Arc - } - - fn request(parent_conv: i32, tool_use: &str) -> DelegationRequest { - DelegationRequest { - parent_connection_id: "parent-conn".into(), - parent_conversation_id: parent_conv, - parent_tool_use_id: tool_use.into(), - agent_type: AgentType::ClaudeCode, - task: "do x".into(), - working_dir: None, - requested_working_dir: None, - external_handle: None, - } - } - - fn request_with_handle(parent_conv: i32, tool_use: &str, handle: &str) -> DelegationRequest { - let mut r = request(parent_conv, tool_use); - r.external_handle = Some(handle.to_string()); - r - } - - /// Bring the broker's `enabled` switch up before driving any test that - /// hits `handle_request`. Production now defaults to `enabled: false`, - /// so a bare `DelegationBroker::new(...)` would short-circuit before - /// parking a pending entry. Tests that assert disabled behavior set - /// their own config explicitly and skip this helper. - async fn enable_delegation(broker: &DelegationBroker) { - broker - .set_config(DelegationConfig { - enabled: true, - ..DelegationConfig::default() - }) - .await; - } - - // -- Task 4.3 ----------------------------------------------------------- - - #[tokio::test] - async fn config_round_trip() { - let broker = DelegationBroker::new( - Arc::new(MockSpawner::new()) as Arc, - shallow_lookup(), - ); - broker - .set_config(DelegationConfig { - enabled: false, - depth_limit: 5, - ..DelegationConfig::default() - }) - .await; - let got = broker.config_snapshot().await; - assert!(!got.enabled); - assert_eq!(got.depth_limit, 5); - } - - #[tokio::test] - async fn disabled_returns_canceled_without_touching_spawner() { - let mock = Arc::new(MockSpawner::new()); - let broker = - DelegationBroker::new(mock.clone() as Arc, shallow_lookup()); - broker - .set_config(DelegationConfig { - enabled: false, - depth_limit: 2, - ..DelegationConfig::default() - }) - .await; - let outcome = broker.handle_request(request(1, "pt-1")).await; - match outcome { - DelegationOutcome::Err { code, .. } => assert_eq!(code, "canceled"), - _ => panic!("expected Err"), - } - assert!(mock.disconnects.lock().await.is_empty()); - } - - // -- Task 4.4: happy path ---------------------------------------------- - - #[tokio::test] - async fn happy_path_returns_ok_after_complete_call() { - let mock = Arc::new(MockSpawner::new()); - mock.queue_spawn(Ok("child-conn-1".into())).await; - mock.queue_send(Ok(42)).await; - let broker = - DelegationBroker::new(mock.clone() as Arc, shallow_lookup()); - enable_delegation(&broker).await; - - let driver = { - let broker = broker.clone(); - tokio::spawn(async move { broker.handle_request(request(1, "pt-1")).await }) - }; - - // Spin until the broker has registered the pending call so the test - // doesn't race the spawn/send awaits. - let call_id = loop { - if let Some(id) = broker.peek_first_pending_call_id().await { - break id; - } - tokio::time::sleep(Duration::from_millis(5)).await; - }; - - broker - .complete_call( - &call_id, - DelegationOutcome::Ok(DelegationSuccess { - text: "4".into(), - child_conversation_id: 42, - child_agent_type: AgentType::Codex, - turn_count: 1, - duration_ms: 50, - token_usage: None, - }), - ) - .await; - - let outcome = driver.await.unwrap(); - match outcome { - DelegationOutcome::Ok(s) => { - assert_eq!(s.text, "4"); - assert_eq!(s.child_conversation_id, 42); - } - other => panic!("expected Ok, got {other:?}"), - } - assert_eq!(broker.pending_count().await, 0); - // complete_call disconnects the child once. - assert_eq!(mock.disconnects.lock().await.as_slice(), &["child-conn-1"]); - } - - /// `StatusWait::Infinite` (the explicit `wait_ms = 0` escape hatch) must - /// park while the task is still running rather than returning the running - /// snapshot, then resolve to the terminal report once the task completes — - /// no matter how long the child takes. - #[tokio::test] - async fn infinite_wait_parks_until_terminal() { - let mock = Arc::new(MockSpawner::new()); - mock.queue_spawn(Ok("child-conn-1".into())).await; - mock.queue_send(Ok(42)).await; - let broker = - DelegationBroker::new(mock.clone() as Arc, shallow_lookup()); - enable_delegation(&broker).await; - - let ack = broker.start_delegation(request(1, "pt-1")).await; - assert_eq!(ack.status, TaskStatus::Running); - let task_id = ack.task_id.clone().expect("running task carries an id"); - - // Infinite wait: parks on the completion signal instead of returning - // the still-running snapshot. - let waiter = { - let broker = broker.clone(); - let task_id = task_id.clone(); - tokio::spawn(async move { - broker - .get_task_status("parent-conn", Some(1), &task_id, StatusWait::Infinite) - .await - }) - }; - - // Give the waiter a beat — it must still be parked, not finished. - tokio::time::sleep(Duration::from_millis(30)).await; - assert!( - !waiter.is_finished(), - "infinite wait must park while the task is running" - ); - - let call_id = loop { - if let Some(id) = broker.peek_first_pending_call_id().await { - break id; - } - tokio::time::sleep(Duration::from_millis(5)).await; - }; - broker - .complete_call( - &call_id, - DelegationOutcome::Ok(DelegationSuccess { - text: "done".into(), - child_conversation_id: 42, - child_agent_type: AgentType::ClaudeCode, - turn_count: 1, - duration_ms: 5, - token_usage: None, - }), - ) - .await; - - let report = waiter.await.unwrap(); - assert_eq!(report.status, TaskStatus::Completed); - assert_eq!(report.text.as_deref(), Some("done")); - } - - /// A running snapshot upgrades its bare `"Running."` message with the child's - /// latest one-line reply when the live-reply lookup has one. - #[tokio::test] - async fn running_status_appends_live_reply_when_available() { - use crate::acp::delegation::live_reply::mock::MockChildLiveReplyLookup; - - let mock = Arc::new(MockSpawner::new()); - mock.queue_spawn(Ok("child-conn-1".into())).await; - mock.queue_send(Ok(42)).await; - let broker = - DelegationBroker::new(mock.clone() as Arc, shallow_lookup()) - .with_live_reply_lookup(Arc::new(MockChildLiveReplyLookup::new(Some( - "Reading config.rs".into(), - )))); - enable_delegation(&broker).await; - - let ack = broker.start_delegation(request(1, "pt-1")).await; - assert_eq!(ack.status, TaskStatus::Running); - let task_id = ack.task_id.clone().expect("running task carries an id"); - - let report = broker - .get_task_status("parent-conn", Some(1), &task_id, StatusWait::Immediate) - .await; - assert_eq!(report.status, TaskStatus::Running); - // The live hint lands on its own line so a content-only host can anchor - // "still running" to the standalone first line "Running.". - assert_eq!( - report.message.as_deref(), - Some("Running.\nLatest sub-agent reply: Reading config.rs") - ); - } - - /// With no live reply (default Noop lookup / child produced nothing yet) the - /// running snapshot stays the bare `"Running."`. - #[tokio::test] - async fn running_status_stays_bare_without_live_reply() { - let mock = Arc::new(MockSpawner::new()); - mock.queue_spawn(Ok("child-conn-1".into())).await; - mock.queue_send(Ok(42)).await; - let broker = - DelegationBroker::new(mock.clone() as Arc, shallow_lookup()); - enable_delegation(&broker).await; - - let ack = broker.start_delegation(request(1, "pt-1")).await; - let task_id = ack.task_id.clone().expect("running task carries an id"); - - let report = broker - .get_task_status("parent-conn", Some(1), &task_id, StatusWait::Immediate) - .await; - assert_eq!(report.status, TaskStatus::Running); - assert_eq!(report.message.as_deref(), Some("Running.")); - } - - // -- Blocked sub-agents (#447) ----------------------------------------- - - fn permission_block(request_id: &str, title: &str) -> BlockedOn { - BlockedOn { - kind: BlockedKind::Permission, - request_id: request_id.into(), - title: Some(title.into()), - } - } - - /// Spin up a broker whose children all report `blocked` (settable later) and - /// one running task on it. Returns `(broker, lookup, task_id)`. - async fn broker_with_blockable_child() -> ( - DelegationBroker, - Arc, - String, - ) { - // The production interval is minutes; every test but the valve one - // wants "effectively never re-surfaces during this test". - broker_with_blockable_child_resurfacing(Duration::from_secs(3600)).await - } - - async fn broker_with_blockable_child_resurfacing( - resurface: Duration, - ) -> ( - DelegationBroker, - Arc, - String, - ) { - use crate::acp::delegation::live_reply::mock::MockChildLiveReplyLookup; - - let mock = Arc::new(MockSpawner::new()); - mock.queue_spawn(Ok("child-conn-1".into())).await; - mock.queue_send(Ok(42)).await; - let lookup = Arc::new(MockChildLiveReplyLookup::new(Some("Reading x".into()))); - let broker = - DelegationBroker::new(mock.clone() as Arc, shallow_lookup()) - .with_live_reply_lookup(lookup.clone()) - .with_block_resurface(resurface); - enable_delegation(&broker).await; - let task_id = broker - .start_delegation(request(1, "pt-1")) - .await - .task_id - .expect("running task carries an id"); - (broker, lookup, task_id) - } - - /// A child parked on a permission reports `Running` + `blocked_on`, and its - /// message says so INSTEAD of the (now stale) live reply. - #[tokio::test] - async fn blocked_child_reports_blocked_on_over_live_reply() { - let (broker, lookup, task_id) = broker_with_blockable_child().await; - lookup.set_blocked(Some(permission_block("req-1", "rm -rf /tmp/x"))); - - let report = broker - .get_task_status("parent-conn", Some(1), &task_id, StatusWait::Immediate) - .await; - - // Status stays wire-stable `running` — the block rides alongside it, so - // a consumer that predates the field still resolves the poll correctly. - assert_eq!(report.status, TaskStatus::Running); - let blocked = report.blocked_on.expect("blocked_on is set"); - assert_eq!(blocked.kind, BlockedKind::Permission); - assert_eq!(blocked.request_id, "req-1"); - let message = report.message.expect("blocked report carries a message"); - // First line must stay the bare running marker (content-only hosts - // anchor on it), with the note on its own second line. - let mut lines = message.lines(); - assert_eq!(lines.next(), Some("Running.")); - assert_eq!( - lines.next(), - Some("Awaiting your decision: rm -rf /tmp/x"), - "the blocked note replaces the live reply, which is stale by definition" - ); - assert!(!message.contains("Latest sub-agent reply")); - } - - /// The whole point of #447: a `wait_ms: 0` (Infinite) wait must NOT park - /// forever behind a permission prompt. Nothing settles this task — if the - /// block didn't wake it, this test would hang. - #[tokio::test] - async fn infinite_wait_returns_when_the_child_becomes_blocked() { - let (broker, lookup, task_id) = broker_with_blockable_child().await; - lookup.set_blocked(Some(permission_block("req-1", "write to /etc/hosts"))); - - let report = broker - .get_task_status("parent-conn", Some(1), &task_id, StatusWait::Infinite) - .await; - - assert_eq!(report.status, TaskStatus::Running); - assert!(report.blocked_on.is_some()); - } - - /// ...but each prompt is surfaced ONCE. A re-poll while the same prompt is - /// still unanswered goes back to waiting instead of returning instantly, - /// which is what keeps an LLM's wait loop from spinning. A *second*, - /// different prompt is new again and returns. - #[tokio::test] - async fn a_reported_block_does_not_return_twice() { - let (broker, lookup, task_id) = broker_with_blockable_child().await; - lookup.set_blocked(Some(permission_block("req-1", "first"))); - - // First observation returns. - let first = broker - .get_task_status("parent-conn", Some(1), &task_id, StatusWait::Infinite) - .await; - assert_eq!(first.blocked_on.map(|b| b.request_id).as_deref(), Some("req-1")); - - // Same prompt, still unanswered: a bounded wait now runs to its deadline - // rather than returning immediately. - let started = Instant::now(); - let second = broker - .get_task_status("parent-conn", Some(1), &task_id, StatusWait::Bounded(120)) - .await; - assert!( - started.elapsed() >= Duration::from_millis(100), - "an already-reported block must not short-circuit the wait" - ); - // It still REPORTS the block on the way out — only the early return is - // suppressed, never the information. - assert!(second.blocked_on.is_some()); - - // A different prompt is a new event and returns early again. - lookup.set_blocked(Some(permission_block("req-2", "second"))); - let started = Instant::now(); - let third = broker - .get_task_status("parent-conn", Some(1), &task_id, StatusWait::Bounded(5_000)) - .await; - assert!( - started.elapsed() < Duration::from_millis(2_000), - "a NEW blocking prompt must wake the wait" - ); - assert_eq!(third.blocked_on.map(|b| b.request_id).as_deref(), Some("req-2")); - } - - /// The delivery-failure valve: marking a block reported is not proof the - /// parent RECEIVED it (the report still has to cross the listener, the - /// companion's stdout and the agent CLI, and a cancelled or aborted - /// `tools/call` discards it silently). So the SAME unanswered prompt - /// becomes reportable again after the resurface interval — otherwise that - /// one lost report was the only one ever offered and the caller is stranded - /// exactly as before #447. - /// - /// Uses `Infinite`, which has no deadline of its own: if the park weren't - /// bounded by the pending resurface, nothing would ever wake it (a blocked - /// child emits nothing further) and this test would hang. - #[tokio::test] - async fn an_undelivered_block_resurfaces_after_the_interval() { - let (broker, lookup, task_id) = - broker_with_blockable_child_resurfacing(Duration::from_millis(150)).await; - lookup.set_blocked(Some(permission_block("req-1", "first"))); - - // First report — imagine this one never reaches the LLM. - let first = broker - .get_task_status("parent-conn", Some(1), &task_id, StatusWait::Infinite) - .await; - assert!(first.blocked_on.is_some()); - - let started = Instant::now(); - let second = broker - .get_task_status("parent-conn", Some(1), &task_id, StatusWait::Infinite) - .await; - assert_eq!( - second.blocked_on.map(|b| b.request_id).as_deref(), - Some("req-1"), - "the same unanswered prompt must become reportable again" - ); - assert!( - started.elapsed() >= Duration::from_millis(120), - "it must WAIT out the interval, not return instantly (that would be the spin)" - ); - } - - /// An unblocked child is unchanged: no `blocked_on`, live reply intact, and - /// an Infinite wait still parks (proven by a Bounded wait running its full - /// deadline out). - #[tokio::test] - async fn unblocked_child_still_parks_and_keeps_its_live_reply() { - let (broker, _lookup, task_id) = broker_with_blockable_child().await; - - let started = Instant::now(); - let report = broker - .get_task_status("parent-conn", Some(1), &task_id, StatusWait::Bounded(120)) - .await; - assert!(started.elapsed() >= Duration::from_millis(100)); - assert!(report.blocked_on.is_none()); - assert_eq!( - report.message.as_deref(), - Some("Running.\nLatest sub-agent reply: Reading x") - ); - } - - // -- Batch get_tasks_status -------------------------------------------- - - /// Queue one spawn+send pair and start a delegation, returning its task id. - /// Each call consumes one queued `(spawn, send)` from the mock. - async fn start_running( - broker: &DelegationBroker, - mock: &MockSpawner, - child_conn: &str, - child_conv: i32, - tool_use: &str, - ) -> String { - mock.queue_spawn(Ok(child_conn.into())).await; - mock.queue_send(Ok(child_conv)).await; - broker - .start_delegation(request(1, tool_use)) - .await - .task_id - .expect("running task carries an id") - } - - /// The single-id batch agrees with `get_task_status` for a completed task — - /// the refactor that routes the single path through `get_tasks_status` keeps - /// the historical contract. - #[tokio::test] - async fn get_tasks_status_single_matches_get_task_status() { - let mock = Arc::new(MockSpawner::new()); - let broker = - DelegationBroker::new(mock.clone() as Arc, shallow_lookup()); - enable_delegation(&broker).await; - let t1 = start_running(&broker, &mock, "child-1", 42, "pt-1").await; - broker - .complete_call( - &t1, - DelegationOutcome::Ok(DelegationSuccess { - text: "done".into(), - child_conversation_id: 42, - child_agent_type: AgentType::Codex, - turn_count: 1, - duration_ms: 7, - token_usage: None, - }), - ) - .await; - - let single = broker - .get_task_status("parent-conn", Some(1), &t1, StatusWait::Immediate) - .await; - let batch = broker - .get_tasks_status( - "parent-conn", - Some(1), - std::slice::from_ref(&t1), - StatusWait::Immediate, - ) - .await; - assert_eq!(batch.len(), 1); - assert_eq!(batch[0].status, single.status); - assert_eq!(batch[0].text, single.text); - assert_eq!(batch[0].task_id, single.task_id); - } - - /// An immediate batch poll resolves a mix of completed / running / unknown - /// tasks in ONE pass, preserving request order. - #[tokio::test] - async fn batch_status_immediate_mixed_preserves_order() { - let mock = Arc::new(MockSpawner::new()); - let broker = - DelegationBroker::new(mock.clone() as Arc, shallow_lookup()); - enable_delegation(&broker).await; - let t1 = start_running(&broker, &mock, "child-1", 1, "pt-1").await; - let t2 = start_running(&broker, &mock, "child-2", 2, "pt-2").await; - broker - .complete_call( - &t1, - DelegationOutcome::Ok(DelegationSuccess { - text: "first".into(), - child_conversation_id: 1, - child_agent_type: AgentType::Codex, - turn_count: 1, - duration_ms: 3, - token_usage: None, - }), - ) - .await; - - let ids = vec![t1.clone(), t2.clone(), "no-such-id".to_string()]; - let reports = broker - .get_tasks_status("parent-conn", Some(1), &ids, StatusWait::Immediate) - .await; - assert_eq!(reports.len(), 3); - assert_eq!(reports[0].status, TaskStatus::Completed); - assert_eq!(reports[0].text.as_deref(), Some("first")); - assert_eq!(reports[0].task_id.as_deref(), Some(t1.as_str())); - assert_eq!(reports[1].status, TaskStatus::Running); - assert_eq!(reports[1].task_id.as_deref(), Some(t2.as_str())); - assert_eq!(reports[2].status, TaskStatus::Unknown); - } - - /// A batch `Infinite` wait returns as soon as ANY requested task settles, - /// leaving the still-running siblings in the snapshot. - #[tokio::test] - async fn batch_infinite_returns_when_any_settles() { - let mock = Arc::new(MockSpawner::new()); - let broker = - DelegationBroker::new(mock.clone() as Arc, shallow_lookup()); - enable_delegation(&broker).await; - let t1 = start_running(&broker, &mock, "child-1", 1, "pt-1").await; - let t2 = start_running(&broker, &mock, "child-2", 2, "pt-2").await; - - let waiter = { - let broker = broker.clone(); - let ids = vec![t1.clone(), t2.clone()]; - tokio::spawn(async move { - broker - .get_tasks_status("parent-conn", Some(1), &ids, StatusWait::Infinite) - .await - }) - }; - tokio::time::sleep(Duration::from_millis(30)).await; - assert!( - !waiter.is_finished(), - "batch infinite wait must park while both tasks run" - ); - - broker - .complete_call( - &t1, - DelegationOutcome::Ok(DelegationSuccess { - text: "first-done".into(), - child_conversation_id: 1, - child_agent_type: AgentType::Codex, - turn_count: 1, - duration_ms: 4, - token_usage: None, - }), - ) - .await; - - let reports = waiter.await.unwrap(); - assert_eq!(reports.len(), 2); - assert_eq!(reports[0].status, TaskStatus::Completed); - assert_eq!(reports[0].text.as_deref(), Some("first-done")); - assert_eq!(reports[1].status, TaskStatus::Running); - } - - /// A batch `Infinite` wait must NOT hold an already-terminal result hostage - /// to a still-running sibling: when a task is terminal at call ENTRY (it - /// completed before the poll), return immediately with the current snapshot - /// rather than parking for the runner. This is the mixed-at-entry case the - /// transition-only wake used to miss — distinct from - /// [`batch_infinite_returns_when_any_settles`] (both running at entry). - #[tokio::test] - async fn batch_infinite_returns_immediately_when_one_already_terminal() { - let mock = Arc::new(MockSpawner::new()); - let broker = - DelegationBroker::new(mock.clone() as Arc, shallow_lookup()); - enable_delegation(&broker).await; - let t1 = start_running(&broker, &mock, "child-1", 1, "pt-1").await; - let t2 = start_running(&broker, &mock, "child-2", 2, "pt-2").await; - // t1 completes BEFORE the poll; t2 keeps running. - broker - .complete_call( - &t1, - DelegationOutcome::Ok(DelegationSuccess { - text: "first-done".into(), - child_conversation_id: 1, - child_agent_type: AgentType::Codex, - turn_count: 1, - duration_ms: 4, - token_usage: None, - }), - ) - .await; - - // Infinite wait, but one task is already terminal at entry → must return - // at once (a bounded timeout guards against the regression: parking here - // would block until t2 settles, which it never does in this test). - let ids = vec![t1.clone(), t2.clone()]; - let reports = tokio::time::timeout( - Duration::from_secs(2), - broker.get_tasks_status("parent-conn", Some(1), &ids, StatusWait::Infinite), - ) - .await - .expect("a batch with an already-terminal task must not park under Infinite"); - assert_eq!(reports.len(), 2); - assert_eq!(reports[0].status, TaskStatus::Completed); - assert_eq!(reports[0].text.as_deref(), Some("first-done")); - assert_eq!(reports[1].status, TaskStatus::Running); - } - - /// A batch `Infinite` wait where NOTHING is running (all ids unknown) must - /// return immediately rather than parking forever. - #[tokio::test] - async fn batch_infinite_all_settled_returns_immediately() { - let mock = Arc::new(MockSpawner::new()); - let broker = - DelegationBroker::new(mock.clone() as Arc, shallow_lookup()); - enable_delegation(&broker).await; - let ids = vec!["nope-1".to_string(), "nope-2".to_string()]; - let reports = tokio::time::timeout( - Duration::from_secs(2), - broker.get_tasks_status("parent-conn", Some(1), &ids, StatusWait::Infinite), - ) - .await - .expect("all-settled infinite batch must not hang"); - assert_eq!(reports.len(), 2); - assert!(reports.iter().all(|r| r.status == TaskStatus::Unknown)); - } - - /// A bounded batch wait with no completion returns the running snapshot once - /// the deadline elapses (the child keeps running; the caller re-polls). - #[tokio::test] - async fn batch_bounded_deadline_returns_running_snapshot() { - let mock = Arc::new(MockSpawner::new()); - let broker = - DelegationBroker::new(mock.clone() as Arc, shallow_lookup()); - enable_delegation(&broker).await; - let t1 = start_running(&broker, &mock, "child-1", 1, "pt-1").await; - let reports = broker - .get_tasks_status("parent-conn", Some(1), &[t1], StatusWait::Bounded(40)) - .await; - assert_eq!(reports.len(), 1); - assert_eq!(reports[0].status, TaskStatus::Running); - } - - /// A task owned by a different parent reports `Unknown` in a batch — never - /// leaking another parent's task, just like the single-task path. - #[tokio::test] - async fn batch_status_scopes_to_parent() { - let mock = Arc::new(MockSpawner::new()); - let broker = - DelegationBroker::new(mock.clone() as Arc, shallow_lookup()); - enable_delegation(&broker).await; - let t1 = start_running(&broker, &mock, "child-1", 1, "pt-1").await; - let reports = broker - .get_tasks_status("other-parent", Some(2), &[t1], StatusWait::Immediate) - .await; - assert_eq!(reports.len(), 1); - assert_eq!(reports[0].status, TaskStatus::Unknown); - } - - // -- Task 4.5: error paths --------------------------------------------- - - #[tokio::test] - async fn spawn_failure_maps_to_spawn_failed() { - let mock = Arc::new(MockSpawner::new()); - mock.queue_spawn(Err(SpawnerError::Spawn("nope".into()))) - .await; - let broker = DelegationBroker::new(mock as Arc, shallow_lookup()); - enable_delegation(&broker).await; - let outcome = broker.handle_request(request(1, "pt-1")).await; - match outcome { - DelegationOutcome::Err { code, .. } => assert_eq!(code, "spawn_failed"), - other => panic!("expected Err, got {other:?}"), - } - } - - #[tokio::test] - async fn agent_defaults_are_forwarded_to_spawner() { - // Configure broker with per-agent defaults for ClaudeCode and verify - // they reach the spawner. Other agent types should still get the - // empty/None defaults. - let mock = Arc::new(MockSpawner::new()); - mock.queue_spawn(Ok("child-1".into())).await; - mock.queue_send(Err(SpawnerError::Send("stop after spawn".into()))) - .await; - let broker = - DelegationBroker::new(mock.clone() as Arc, shallow_lookup()); - - let mut claude_cfg = BTreeMap::new(); - claude_cfg.insert("model".into(), "claude-sonnet-4-5".into()); - let mut agent_defaults = BTreeMap::new(); - agent_defaults.insert( - AgentType::ClaudeCode, - AgentDelegationDefaults { - mode_id: Some("auto".into()), - config_values: claude_cfg.clone(), - }, - ); - broker - .set_config(DelegationConfig { - enabled: true, - depth_limit: 8, - agent_defaults, - ..DelegationConfig::default() - }) - .await; - - let _ = broker.handle_request(request(1, "pt-1")).await; - - let args = mock.spawn_args.lock().await; - assert_eq!(args.len(), 1); - let call = &args[0]; - assert_eq!(call.agent_type, AgentType::ClaudeCode); - assert_eq!(call.preferred_mode_id.as_deref(), Some("auto")); - assert_eq!(call.preferred_config_values, claude_cfg); - } - - #[tokio::test] - async fn agent_with_no_defaults_gets_empty_preferred_args() { - // ClaudeCode is configured in agent_defaults; a Codex request should - // still receive (None, empty) — no cross-contamination. - let mock = Arc::new(MockSpawner::new()); - mock.queue_spawn(Ok("child-1".into())).await; - mock.queue_send(Err(SpawnerError::Send("stop after spawn".into()))) - .await; - let broker = - DelegationBroker::new(mock.clone() as Arc, shallow_lookup()); - - let mut agent_defaults = BTreeMap::new(); - agent_defaults.insert( - AgentType::ClaudeCode, - AgentDelegationDefaults { - mode_id: Some("auto".into()), - config_values: BTreeMap::new(), - }, - ); - broker - .set_config(DelegationConfig { - enabled: true, - depth_limit: 8, - agent_defaults, - ..DelegationConfig::default() - }) - .await; - - let mut codex_req = request(1, "pt-1"); - codex_req.agent_type = AgentType::Codex; - let _ = broker.handle_request(codex_req).await; - - let args = mock.spawn_args.lock().await; - assert_eq!(args.len(), 1); - assert_eq!(args[0].agent_type, AgentType::Codex); - assert!(args[0].preferred_mode_id.is_none()); - assert!(args[0].preferred_config_values.is_empty()); - } - - #[tokio::test] - async fn send_failure_after_spawn_disconnects_child() { - let mock = Arc::new(MockSpawner::new()); - mock.queue_spawn(Ok("c1".into())).await; - mock.queue_send(Err(SpawnerError::Send("agent rejected prompt".into()))) - .await; - let broker = - DelegationBroker::new(mock.clone() as Arc, shallow_lookup()); - enable_delegation(&broker).await; - let outcome = broker.handle_request(request(1, "pt-1")).await; - match outcome { - DelegationOutcome::Err { code, .. } => assert_eq!(code, "spawn_failed"), - other => panic!("expected Err, got {other:?}"), - } - assert_eq!(mock.disconnects.lock().await.as_slice(), &["c1"]); - } - - #[tokio::test] - async fn handle_request_waits_indefinitely_for_completion() { - // No timeout race anymore: handle_request blocks on `rx.await` until - // complete_call / cancel_* fires. This test asserts the pending entry - // sticks around even after a generous idle window. - let mock = Arc::new(MockSpawner::new()); - mock.queue_spawn(Ok("c1".into())).await; - mock.queue_send(Ok(99)).await; - let broker = - DelegationBroker::new(mock.clone() as Arc, shallow_lookup()); - enable_delegation(&broker).await; - - let driver = { - let broker = broker.clone(); - tokio::spawn(async move { broker.handle_request(request(1, "pt-1")).await }) - }; - - tokio::time::sleep(Duration::from_millis(80)).await; - assert_eq!(broker.pending_count().await, 1); - assert!(mock.cancels.lock().await.is_empty()); - - let call_id = broker.peek_first_pending_call_id().await.unwrap(); - broker - .complete_call( - &call_id, - DelegationOutcome::Ok(DelegationSuccess { - text: "done".into(), - child_conversation_id: 99, - child_agent_type: AgentType::Codex, - turn_count: 1, - duration_ms: 50, - token_usage: None, - }), - ) - .await; - - let outcome = driver.await.unwrap(); - match outcome { - DelegationOutcome::Ok(s) => assert_eq!(s.text, "done"), - other => panic!("expected Ok, got {other:?}"), - } - assert_eq!(mock.disconnects.lock().await.as_slice(), &["c1"]); - } - - // -- Task 4.6: parent-cancel cascade ----------------------------------- - - #[tokio::test] - async fn parent_cancel_cancels_all_pending_children() { - let mock = Arc::new(MockSpawner::new()); - for i in 0..3 { - mock.queue_spawn(Ok(format!("c{i}"))).await; - mock.queue_send(Ok(100 + i)).await; - } - let broker = - DelegationBroker::new(mock.clone() as Arc, shallow_lookup()); - enable_delegation(&broker).await; - - let mut handles = Vec::new(); - for i in 0..3 { - let broker = broker.clone(); - handles.push(tokio::spawn(async move { - broker.handle_request(request(1, &format!("pt-{i}"))).await - })); - } - - // Wait until all three are parked. - while broker.pending_count().await < 3 { - tokio::time::sleep(Duration::from_millis(5)).await; - } - - broker.cancel_by_parent("parent-conn").await; - for h in handles { - let outcome = h.await.unwrap(); - match outcome { - DelegationOutcome::Err { code, .. } => assert_eq!(code, "canceled"), - other => panic!("expected canceled, got {other:?}"), - } - } - assert_eq!(mock.cancels.lock().await.len(), 3); - // Each child disconnects exactly once via cancel_by_parent. - assert_eq!(mock.disconnects.lock().await.len(), 3); - } - - #[tokio::test] - async fn cancel_by_parent_ignores_other_parents() { - let mock = Arc::new(MockSpawner::new()); - mock.queue_spawn(Ok("c1".into())).await; - mock.queue_send(Ok(200)).await; - let broker = - DelegationBroker::new(mock.clone() as Arc, shallow_lookup()); - enable_delegation(&broker).await; - - let driver = { - let broker = broker.clone(); - tokio::spawn(async move { broker.handle_request(request(1, "pt-1")).await }) - }; - while broker.pending_count().await == 0 { - tokio::time::sleep(Duration::from_millis(5)).await; - } - - broker.cancel_by_parent("other-parent").await; - // No effect — pending entry still there. - assert_eq!(broker.pending_count().await, 1); - - let call_id = broker.peek_first_pending_call_id().await.unwrap(); - broker - .complete_call( - &call_id, - DelegationOutcome::Ok(DelegationSuccess { - text: "done".into(), - child_conversation_id: 200, - child_agent_type: AgentType::ClaudeCode, - turn_count: 1, - duration_ms: 10, - token_usage: None, - }), - ) - .await; - let outcome = driver.await.unwrap(); - assert!(matches!(outcome, DelegationOutcome::Ok(_))); - } - - // -- Task 4.7: depth limit --------------------------------------------- - - #[tokio::test] - async fn depth_limit_rejects_before_spawn() { - let mock = Arc::new(MockSpawner::new()); - // No queued spawn results — if the broker tries to spawn, it errors loudly. - // chain: 1 (root, None) <- 2 (child of 1) <- 3 (grandchild of 2). - // Parent = grandchild (id 3): parent_depth = 2. With limit = 2, child - // would sit at depth 3 → reject. - let lookup = Arc::new(MockDepth(vec![(1, None), (2, Some(1)), (3, Some(2))])) - as Arc; - let broker = DelegationBroker::new(mock as Arc, lookup); - broker - .set_config(DelegationConfig { - enabled: true, - depth_limit: 2, - ..DelegationConfig::default() - }) - .await; - let outcome = broker.handle_request(request(3, "pt-1")).await; - match outcome { - DelegationOutcome::Err { code, .. } => assert_eq!(code, "depth_limit"), - other => panic!("expected depth_limit, got {other:?}"), - } - } - - // -- Pending tool_call_id queue (MCP `_meta.tool_use_id` fallback) ---- - - #[tokio::test] - async fn pending_tool_call_register_and_take_is_fifo() { - let broker = DelegationBroker::new( - Arc::new(MockSpawner::new()) as Arc, - shallow_lookup(), - ); - broker.register_pending_tool_call("p1", "tc-a".into()).await; - broker.register_pending_tool_call("p1", "tc-b".into()).await; - assert_eq!( - broker.take_pending_tool_call("p1").await.as_deref(), - Some("tc-a") - ); - assert_eq!( - broker.take_pending_tool_call("p1").await.as_deref(), - Some("tc-b") - ); - assert!(broker.take_pending_tool_call("p1").await.is_none()); - } - - #[tokio::test] - async fn register_dedupes_repeated_tool_call_id() { - // Regression: some hosts re-emit `sessionUpdate(tool_call)` (not - // `tool_call_update`) for the same call as raw_input chunks arrive - // or as the status flips. Without dedupe the second push leaves a - // stale id in the queue that mis-binds the next delegation. - let broker = DelegationBroker::new( - Arc::new(MockSpawner::new()) as Arc, - shallow_lookup(), - ); - broker.register_pending_tool_call("p1", "tc-a".into()).await; - broker.register_pending_tool_call("p1", "tc-a".into()).await; - broker.register_pending_tool_call("p1", "tc-a".into()).await; - assert_eq!( - broker.take_pending_tool_call("p1").await.as_deref(), - Some("tc-a") - ); - assert!( - broker.take_pending_tool_call("p1").await.is_none(), - "duplicate register must not leave a stale id in the queue" - ); - } - - #[tokio::test] - async fn register_after_claim_drops_stale_re_emit() { - // Regression for the post-claim re-emit race: a host re-sends - // `sessionUpdate(tool_call)` for the same id after the matching - // MCP round-trip already consumed it (e.g. shipping the - // `completed` status flip or a settled `raw_input`). The - // in-queue dedupe alone leaves the queue empty at that moment, - // so without the recently-consumed memory the re-emit would - // sneak into the queue and mis-bind the next delegation. - let broker = DelegationBroker::new( - Arc::new(MockSpawner::new()) as Arc, - shallow_lookup(), - ); - broker.register_pending_tool_call("p1", "tc-a".into()).await; - assert_eq!( - broker.take_pending_tool_call("p1").await.as_deref(), - Some("tc-a") - ); - // Re-emit of the same id after it was already claimed. - broker.register_pending_tool_call("p1", "tc-a".into()).await; - assert!( - broker.take_pending_tool_call("p1").await.is_none(), - "post-claim re-emit of the same id must not be re-queued" - ); - // A genuinely new id on the same parent still flows through. - broker.register_pending_tool_call("p1", "tc-b".into()).await; - assert_eq!( - broker.take_pending_tool_call("p1").await.as_deref(), - Some("tc-b") - ); - } - - #[tokio::test] - async fn concurrent_take_and_re_register_never_leaks_stale_duplicate() { - // TOCTOU regression: a host re-emit of the same tool_call_id - // racing against the matching take must never inject a stale - // duplicate. Co-locating `pending` and `consumed` under the - // same mutex guarantees the claim → mark-consumed pair is - // atomic, so the only two legal interleavings are: - // - // * take wins → pending=[], consumed=[id]; re-register sees - // the id in consumed and drops it. - // * register wins → pending=[id] (still the original entry, - // in-queue dedupe drops the re-emit); take then pops it - // and records it in consumed. - // - // In neither case may the queue retain a duplicate id once - // both futures settle. We drive many rounds with `tokio::spawn` - // to stress the interleaving. - let broker = std::sync::Arc::new(DelegationBroker::new( - Arc::new(MockSpawner::new()) as Arc, - shallow_lookup(), - )); - for _ in 0..200 { - broker.register_pending_tool_call("p1", "tc-a".into()).await; - let b_take = broker.clone(); - let b_reg = broker.clone(); - let h_take = tokio::spawn(async move { - b_take.take_pending_tool_call("p1").await; - }); - let h_reg = tokio::spawn(async move { - b_reg.register_pending_tool_call("p1", "tc-a".into()).await; - }); - let _ = tokio::join!(h_take, h_reg); - assert!( - broker.take_pending_tool_call("p1").await.is_none(), - "stale duplicate of tc-a leaked after concurrent take + re-register" - ); - } - } - - #[tokio::test] - async fn consumed_memory_outlives_pending_ttl_for_long_running_delegation() { - // Regression: a delegated child agent can run for - // minutes-to-hours. When it finishes, the host may re-emit - // the parent-side `tool_call` (e.g. as a `completed` status - // flip via the non-update `ToolCall` variant). That re-emit - // arrives well after PENDING_TOOL_CALL_TTL, so the consumed - // memory MUST NOT age out under that TTL — otherwise the - // stale id slips back into pending and mis-binds the next - // delegation. Consumed entries are scoped to the parent - // connection's lifetime instead. - let broker = DelegationBroker::new( - Arc::new(MockSpawner::new()) as Arc, - shallow_lookup(), - ); - broker.register_pending_tool_call("p1", "tc-a".into()).await; - assert_eq!( - broker.take_pending_tool_call("p1").await.as_deref(), - Some("tc-a") - ); - // Simulate the host re-emitting the same tool_call_id 10× - // the pending TTL later (i.e. a long-running delegation that - // finishes after the pending eviction window). - let long_after = Instant::now() + PENDING_TOOL_CALL_TTL * 10; - broker - .register_pending_tool_call_with_key_at("p1", "tc-a".into(), None, false, long_after) - .await; - assert!( - broker - .take_pending_tool_call_at("p1", long_after) - .await - .is_none(), - "consumed memory must outlast the pending TTL so terminal status re-emits cannot leak through" - ); - } - - #[tokio::test] - async fn consumed_memory_unbounded_across_high_fan_out() { - // Regression for the cap removal: a parent session with many - // delegations (well past any prior per-bucket cap) must still - // reject a late re-emit of the very first delegation's id, - // because the consumed half has no cap. A bounded consumed - // set with FIFO eviction would silently re-enable the - // mis-binding bug at high fan-out. - let broker = DelegationBroker::new( - Arc::new(MockSpawner::new()) as Arc, - shallow_lookup(), - ); - let first_id = "tc-first".to_string(); - broker - .register_pending_tool_call("p1", first_id.clone()) - .await; - assert_eq!( - broker.take_pending_tool_call("p1").await.as_deref(), - Some(first_id.as_str()) - ); - // Issue many more delegations than any prior per-bucket cap. With - // no cap on consumed, the first id must remain remembered for the - // lifetime of the parent connection. - for i in 0..128 { - let id = format!("tc-{i}"); - broker.register_pending_tool_call("p1", id.clone()).await; - assert_eq!( - broker.take_pending_tool_call("p1").await.as_deref(), - Some(id.as_str()) - ); - } - // Late re-emit of the very first id (would have been evicted - // by the prior bounded consumed FIFO). - broker - .register_pending_tool_call("p1", first_id.clone()) - .await; - assert!( - broker.take_pending_tool_call("p1").await.is_none(), - "consumed memory must retain the very first id even after high fan-out" - ); - } - - #[tokio::test] - async fn consumed_memory_cleared_on_parent_disconnect() { - // The companion to the long-running invariant above: consumed - // memory is scoped to the parent connection's lifetime, so - // `drop_pending_tool_calls_for_parent` (called when the - // parent disconnects) must clear it. Otherwise a brand-new - // connection reusing the same id (UUID collision is unlikely - // but UUIDs are not the only id scheme in play) would be - // permanently blocked. - let broker = DelegationBroker::new( - Arc::new(MockSpawner::new()) as Arc, - shallow_lookup(), - ); - broker.register_pending_tool_call("p1", "tc-a".into()).await; - assert_eq!( - broker.take_pending_tool_call("p1").await.as_deref(), - Some("tc-a") - ); - broker.drop_pending_tool_calls_for_parent("p1").await; - broker.register_pending_tool_call("p1", "tc-a".into()).await; - assert_eq!( - broker.take_pending_tool_call("p1").await.as_deref(), - Some("tc-a"), - "parent disconnect must clear consumed memory so id reuse is acceptable" - ); - } - - #[tokio::test] - async fn take_skips_entries_older_than_ttl() { - // Regression: an ACP `tool_call` whose matching MCP round-trip - // never arrives (host changed its mind, transport dropped, etc.) - // must not sit in the queue forever and mis-bind a subsequent - // delegation. TTL eviction is exercised by advancing the - // injected `as of` instant past PENDING_TOOL_CALL_TTL. - let broker = DelegationBroker::new( - Arc::new(MockSpawner::new()) as Arc, - shallow_lookup(), - ); - let t0 = Instant::now(); - broker - .register_pending_tool_call("p1", "stale".into()) - .await; - // Fresh id registered "just before" the future `now`. - broker - .register_pending_tool_call("p1", "fresh".into()) - .await; - let future_now = t0 + PENDING_TOOL_CALL_TTL + Duration::from_millis(50); - // Forge "fresh" so it survives the TTL: rewrite its timestamp to - // ~now-relative-to-future-now. Direct field access is OK — we're - // a sibling test in the same module. - { - let mut map = broker.tool_calls.inner.lock().await; - let bucket = map.get_mut("p1").expect("bucket present"); - // Re-stamp the second entry ("fresh") to `future_now`. - if let Some(entry) = bucket - .pending - .iter_mut() - .find(|p| p.tool_call_id == "fresh") - { - entry.registered_at = future_now; - } - } - // First entry ("stale", stamped at ~t0) is past TTL relative to - // future_now; the second ("fresh") was just re-stamped to - // future_now and must survive. - assert_eq!( - broker - .take_pending_tool_call_at("p1", future_now) - .await - .map(|(id, _)| id) - .as_deref(), - Some("fresh") - ); - assert!(broker.take_pending_tool_call("p1").await.is_none()); - } - - #[tokio::test] - async fn pending_tool_call_is_isolated_per_parent() { - let broker = DelegationBroker::new( - Arc::new(MockSpawner::new()) as Arc, - shallow_lookup(), - ); - broker.register_pending_tool_call("p1", "p1-a".into()).await; - broker.register_pending_tool_call("p2", "p2-a".into()).await; - assert_eq!( - broker.take_pending_tool_call("p1").await.as_deref(), - Some("p1-a") - ); - assert_eq!( - broker.take_pending_tool_call("p2").await.as_deref(), - Some("p2-a") - ); - assert!(broker.take_pending_tool_call("p1").await.is_none()); - assert!(broker.take_pending_tool_call("p2").await.is_none()); - } - - // -- (agent_type, task) correlation for parallel delegations ---------- - - /// Build a match key with a fixed agent and no explicit working_dir for - /// the common case where the test only varies the task. Use `key_for` to - /// vary the agent, or `key_with_dir` to vary the directory. - fn task_key(task: &str) -> DelegationMatchKey { - key_for(AgentType::Codex, task) - } - - fn key_for(agent_type: AgentType, task: &str) -> DelegationMatchKey { - DelegationMatchKey { - agent_type, - task: task.to_string(), - working_dir: None, - } - } - - fn key_with_dir(task: &str, working_dir: &str) -> DelegationMatchKey { - DelegationMatchKey { - agent_type: AgentType::Codex, - task: task.to_string(), - working_dir: Some(working_dir.to_string()), - } - } - - #[tokio::test] - async fn parallel_delegations_bind_by_key_regardless_of_order() { - // Two `delegate_to_agent` calls fire in parallel; both ACP tool_call - // events register with their key. The MCP round-trips can claim in - // EITHER order — each must bind to its own id by key match, never - // swap. Pure FIFO would hand the first claimer "tc-A" regardless of - // which call it represented. - let broker = DelegationBroker::new( - Arc::new(MockSpawner::new()) as Arc, - shallow_lookup(), - ); - broker - .register_pending_tool_call_with_key("p1", "tc-A".into(), Some(task_key("task A"))) - .await; - broker - .register_pending_tool_call_with_key("p1", "tc-B".into(), Some(task_key("task B"))) - .await; - // Claim "task B" first (reverse of registration order). - assert_eq!( - broker - .take_matching_tool_call("p1", &task_key("task B")) - .await - .as_deref(), - Some("tc-B") - ); - assert_eq!( - broker - .take_matching_tool_call("p1", &task_key("task A")) - .await - .as_deref(), - Some("tc-A") - ); - // A re-claim of an already-consumed key finds nothing. - assert!(broker - .take_matching_tool_call("p1", &task_key("task A")) - .await - .is_none()); - } - - #[tokio::test] - async fn parallel_same_task_different_agent_do_not_swap() { - // Regression for Codex review: two parallel calls with the SAME task - // text but DIFFERENT agents must bind by the full key, not by task - // alone — otherwise the codex card could show the claude_code child - // and vice versa. - let broker = DelegationBroker::new( - Arc::new(MockSpawner::new()) as Arc, - shallow_lookup(), - ); - broker - .register_pending_tool_call_with_key( - "p1", - "tc-codex".into(), - Some(key_for(AgentType::Codex, "review this")), - ) - .await; - broker - .register_pending_tool_call_with_key( - "p1", - "tc-claude".into(), - Some(key_for(AgentType::ClaudeCode, "review this")), - ) - .await; - // The claude_code round-trip must claim the claude_code id even though - // the codex entry shares the identical task and registered first. - assert_eq!( - broker - .take_matching_tool_call("p1", &key_for(AgentType::ClaudeCode, "review this")) - .await - .as_deref(), - Some("tc-claude") - ); - assert_eq!( - broker - .take_matching_tool_call("p1", &key_for(AgentType::Codex, "review this")) - .await - .as_deref(), - Some("tc-codex") - ); - } - - #[tokio::test] - async fn parallel_same_task_same_agent_different_dir_do_not_swap() { - // Regression for Codex review round 2: two parallel calls with the - // SAME agent and SAME task text but DIFFERENT explicit working_dir - // (e.g. "run tests" against /repo-a vs /repo-b) must bind by the full - // key including working_dir. Claimed in reverse registration order to - // prove it's not arrival-order FIFO. - let broker = DelegationBroker::new( - Arc::new(MockSpawner::new()) as Arc, - shallow_lookup(), - ); - broker - .register_pending_tool_call_with_key( - "p1", - "tc-a".into(), - Some(key_with_dir("run tests", "/repo-a")), - ) - .await; - broker - .register_pending_tool_call_with_key( - "p1", - "tc-b".into(), - Some(key_with_dir("run tests", "/repo-b")), - ) - .await; - assert_eq!( - broker - .take_matching_tool_call("p1", &key_with_dir("run tests", "/repo-b")) - .await - .as_deref(), - Some("tc-b") - ); - assert_eq!( - broker - .take_matching_tool_call("p1", &key_with_dir("run tests", "/repo-a")) - .await - .as_deref(), - Some("tc-a") - ); - } - - #[tokio::test] - async fn claim_does_not_steal_sibling_and_waits_for_own_registration() { - // Regression for the reported bug: with only the SIBLING's keyed id - // registered, a delegation must NOT grab it (which would swap the two - // cards) — it waits for its own id. The brief-wait loop picks it up - // once it registers shortly after. - let broker = std::sync::Arc::new(DelegationBroker::new( - Arc::new(MockSpawner::new()) as Arc, - shallow_lookup(), - )); - broker - .register_pending_tool_call_with_key("p1", "tc-A".into(), Some(task_key("task A"))) - .await; - // Immediate claim for "task B" while only tc-A (task A) is pending - // must refuse to steal tc-A. - assert!( - broker - .take_matching_tool_call("p1", &task_key("task B")) - .await - .is_none(), - "must not steal a sibling's keyed id" - ); - // tc-A is still claimable by its own key. - let broker_bg = broker.clone(); - let register_late = tokio::spawn(async move { - tokio::time::sleep(Duration::from_millis(30)).await; - broker_bg - .register_pending_tool_call_with_key("p1", "tc-B".into(), Some(task_key("task B"))) - .await; - }); - // The brief-wait claim polls until tc-B (task B) registers. - let claimed = broker - .claim_pending_tool_call_with_brief_wait("p1", &task_key("task B")) - .await; - register_late.await.unwrap(); - assert_eq!(claimed.map(|(id, _)| id).as_deref(), Some("tc-B")); - // tc-A remains for its own key. - assert_eq!( - broker - .take_matching_tool_call("p1", &task_key("task A")) - .await - .as_deref(), - Some("tc-A") - ); - } - - #[tokio::test] - async fn lone_unkeyed_entry_is_not_claimed_in_loop_only_post_budget() { - // A host that ships no parseable `raw_input` registers match_key=None. - // The in-loop path NEVER claims it — not even when it's the only entry, - // and regardless of how old it gets (10s here). Entry age is no proof a - // key isn't still coming: a serialized round-trip can register/backfill - // arbitrarily late, and the entry could belong to a parallel sibling - // whose owner hasn't registered yet (the staggered-singleton race — - // Codex review). Arrival-order FIFO is reserved for the post-budget last - // resort, which only runs once the CALLER has waited its full budget. - let broker = DelegationBroker::new( - Arc::new(MockSpawner::new()) as Arc, - shallow_lookup(), - ); - broker.register_pending_tool_call("p1", "tc-A".into()).await; - // Even aged 10s (well past any heuristic grace, still < TTL so not - // evicted), the in-loop claim refuses to hand out the unkeyed id. - let way_aged = Instant::now() + Duration::from_secs(10); - assert!( - broker - .take_matching_tool_call_at("p1", &task_key("whatever"), way_aged) - .await - .is_none(), - "an unkeyed entry must never be claimed in-loop, regardless of age" - ); - // The post-budget last resort is where a genuinely keyless entry binds. - assert_eq!( - broker.take_pending_tool_call("p1").await.as_deref(), - Some("tc-A") - ); - } - - #[tokio::test] - async fn parallel_unkeyed_entries_are_not_claimed_in_loop() { - // THE Finding 1 regression. Two delegations whose initial ToolCalls - // registered UNKEYED (args arrive later on a ToolCallUpdate). Before - // either is keyed, a round-trip arrives. The old `all unkeyed → - // pop_front` handed it the OLDEST entry (tc-A), mis-binding it to the - // wrong delegation. The in-loop claim now withholds (None) because no - // key matches — arrival-order FIFO is left to the post-budget last - // resort. Age never unlocks an in-loop claim. - let broker = DelegationBroker::new( - Arc::new(MockSpawner::new()) as Arc, - shallow_lookup(), - ); - broker.register_pending_tool_call("p1", "tc-A".into()).await; - broker.register_pending_tool_call("p1", "tc-B".into()).await; - // Aged (but < TTL, so not evicted): still withheld in-loop. - let aged = Instant::now() + Duration::from_secs(5); - assert!( - broker - .take_matching_tool_call_at("p1", &task_key("task B"), aged) - .await - .is_none(), - "unkeyed siblings must not be FIFO-claimed in-loop" - ); - // Neither entry was consumed. - let map = broker.tool_calls.inner.lock().await; - assert_eq!(map.get("p1").expect("bucket present").pending.len(), 2); - } - - #[tokio::test] - async fn parallel_unkeyed_resolves_by_backfilled_key_not_fifo() { - // The pay-off: while the claim is withheld, the args arrive and - // backfill a key onto the sibling. The round-trip then binds by EXACT - // MATCH to its own id — never the FIFO-oldest. This is the would-be - // mis-bind turned into a correct correlation. - let broker = DelegationBroker::new( - Arc::new(MockSpawner::new()) as Arc, - shallow_lookup(), - ); - broker.register_pending_tool_call("p1", "tc-A".into()).await; - broker.register_pending_tool_call("p1", "tc-B".into()).await; - // tc-B's args land → backfills its key. - broker - .register_pending_tool_call_with_key("p1", "tc-B".into(), Some(task_key("task B"))) - .await; - // The "task B" round-trip binds to tc-B by key, not to the older tc-A. - assert_eq!( - broker - .take_matching_tool_call("p1", &task_key("task B")) - .await - .as_deref(), - Some("tc-B") - ); - // tc-A is untouched, still pending for its own key/round-trip. - let map = broker.tool_calls.inner.lock().await; - let pending = &map.get("p1").expect("bucket present").pending; - assert_eq!(pending.len(), 1); - assert_eq!(pending[0].tool_call_id, "tc-A"); - } - - #[tokio::test] - async fn post_budget_fallback_still_fifos_parallel_unkeyed() { - // A genuinely keyless host (no key ever lands) must still bind both - // parallel delegations end-to-end. The in-loop claim withholds them, - // but the post-budget last resort `take_pending_tool_call` claims them - // oldest-first — the best a keyless host allows, and unchanged from - // before. Only the premature in-loop FIFO is gone. - let broker = DelegationBroker::new( - Arc::new(MockSpawner::new()) as Arc, - shallow_lookup(), - ); - broker.register_pending_tool_call("p1", "tc-A".into()).await; - broker.register_pending_tool_call("p1", "tc-B".into()).await; - assert_eq!( - broker.take_pending_tool_call("p1").await.as_deref(), - Some("tc-A") - ); - assert_eq!( - broker.take_pending_tool_call("p1").await.as_deref(), - Some("tc-B") - ); - } - - #[tokio::test] - async fn brief_wait_binds_own_late_registration_not_unkeyed_sibling() { - // The staggered-singleton timeline Codex flagged, end-to-end: only an - // UNKEYED sibling (tc-A) is visible when a DIFFERENT delegation's - // round-trip (task B) starts claiming; B's own keyed `tool_call` - // registers a little later, still inside the wait budget. The brief-wait - // loop must bind B to its OWN id (tc-B) by exact match, never FIFO-steal - // the older unkeyed tc-A. The old in-loop FIFO popped tc-A on the very - // first poll (all-unkeyed); a grace gate would still steal it once tc-A - // aged past the grace before tc-B arrived. Deferring all FIFO to the - // post-budget — i.e. binding by exact match in-loop only — is what makes - // this correct. - let broker = std::sync::Arc::new(DelegationBroker::new( - Arc::new(MockSpawner::new()) as Arc, - shallow_lookup(), - )); - broker.register_pending_tool_call("p1", "tc-A".into()).await; - // B's own ACP registration lands ~200ms in — well after any age-based - // heuristic would have fired, but far inside the ~2s claim budget. - let broker_bg = broker.clone(); - let register_late = tokio::spawn(async move { - tokio::time::sleep(Duration::from_millis(200)).await; - broker_bg - .register_pending_tool_call_with_key("p1", "tc-B".into(), Some(task_key("task B"))) - .await; - }); - let claimed = broker - .claim_pending_tool_call_with_brief_wait("p1", &task_key("task B")) - .await; - register_late.await.unwrap(); - assert_eq!( - claimed.map(|(id, _)| id).as_deref(), - Some("tc-B"), - "must wait for its own registration, not FIFO-steal the unkeyed sibling" - ); - // tc-A is untouched, still pending for its own correlation. - let map = broker.tool_calls.inner.lock().await; - let pending = &map.get("p1").expect("bucket present").pending; - assert_eq!(pending.len(), 1); - assert_eq!(pending[0].tool_call_id, "tc-A"); - } - - #[tokio::test] - async fn reemit_backfills_key_onto_unkeyed_entry() { - // A host that re-emits the `session/update(tool_call)` variant: the - // first ToolCall has no parseable args (registers match_key=None), a - // later re-emit carries the full args. The re-emit must backfill the - // key onto the existing entry (not push a duplicate, not be dropped) - // so key matching works. - let broker = DelegationBroker::new( - Arc::new(MockSpawner::new()) as Arc, - shallow_lookup(), - ); - broker.register_pending_tool_call("p1", "tc-A".into()).await; - broker - .register_pending_tool_call_with_key("p1", "tc-A".into(), Some(task_key("task A"))) - .await; - // Now claimable by the backfilled key. - assert_eq!( - broker - .take_matching_tool_call("p1", &task_key("task A")) - .await - .as_deref(), - Some("tc-A") - ); - assert!(broker.take_pending_tool_call("p1").await.is_none()); - } - - #[tokio::test] - async fn fallback_never_steals_a_keyed_sibling() { - // A keyed sibling is pending but the requesting round-trip's key never - // matches (its own tool_call was genuinely lost). The post-budget last - // resort must NOT hand out the keyed sibling — stealing it would just - // move the dead card from this delegation to the sibling. It returns - // None (→ caller mints a synthetic id), and the sibling stays claimable - // by its own round-trip. (Regression: the old behavior FIFO-popped the - // keyed entry here, swapping which delegation broke.) - let broker = DelegationBroker::new( - Arc::new(MockSpawner::new()) as Arc, - shallow_lookup(), - ); - broker - .register_pending_tool_call_with_key("p1", "tc-A".into(), Some(task_key("task A"))) - .await; - // No entry matches "task Z", and a keyed entry is present, so the - // match step refuses to claim. - assert!(broker - .take_matching_tool_call("p1", &task_key("task Z")) - .await - .is_none()); - // The post-budget last resort steps over the keyed entry → None. - assert!( - broker.take_pending_tool_call("p1").await.is_none(), - "must not steal a keyed sibling via the anonymous fallback" - ); - // The keyed sibling is untouched — still claimable by its own key. - assert_eq!( - broker - .take_matching_tool_call("p1", &task_key("task A")) - .await - .as_deref(), - Some("tc-A") - ); - } - - #[tokio::test] - async fn keyed_entry_survives_past_ttl_for_serialized_round_trip() { - // THE headline regression for the reported bug. A 2nd parallel - // delegation's tool_call registers (keyed), then its MCP round-trip is - // serialized far behind the 1st delegation — arriving well past - // PENDING_TOOL_CALL_TTL. The keyed entry must NOT be aged out: an exact - // key match claims it at any age, so the parent card binds instead of - // falling to a synthetic id. (Observed live: round-trip landed 77s - // after registration, past the 60s TTL → evicted → synthetic → dead - // card stuck on "sub-agent running…".) - let broker = DelegationBroker::new( - Arc::new(MockSpawner::new()) as Arc, - shallow_lookup(), - ); - broker - .register_pending_tool_call_with_key( - "p1", - "tc-late".into(), - Some(task_key("slow task")), - ) - .await; - // Claim "as of" long past the TTL — simulates the round-trip arriving - // after a many-times-TTL wait behind a serialized sibling. - let way_past_ttl = Instant::now() + PENDING_TOOL_CALL_TTL * 10; - assert_eq!( - broker - .take_matching_tool_call_at("p1", &task_key("slow task"), way_past_ttl) - .await - .as_deref(), - Some("tc-late"), - "a keyed entry must remain claimable by exact key match regardless of age" - ); - } - - #[tokio::test] - async fn unkeyed_entry_is_still_aged_out() { - // The flip side: UNKEYED entries (host shipped no parseable raw_input) - // remain anonymous and arrival-order-correlated, so a stale one MUST - // still be GC'd by age — otherwise it could mis-bind a much later - // unkeyed delegation via the FIFO path. - let broker = DelegationBroker::new( - Arc::new(MockSpawner::new()) as Arc, - shallow_lookup(), - ); - broker - .register_pending_tool_call("p1", "tc-stale".into()) - .await; - let way_past_ttl = Instant::now() + PENDING_TOOL_CALL_TTL * 10; - // Unkeyed + stale → evicted by the match path's GC → nothing to claim. - assert!(broker - .take_matching_tool_call_at("p1", &task_key("whatever"), way_past_ttl) - .await - .is_none()); - // And the anonymous path agrees it's gone. - assert!(broker - .take_pending_tool_call_at("p1", way_past_ttl) - .await - .is_none()); - } - - #[tokio::test] - async fn explicit_tool_use_id_consumes_pending_entry_acp_first() { - // Codex review fix: client supplies the real id via `_meta.tool_use_id` - // AFTER the dispatcher already registered it (ACP-before-MCP). The - // explicit-id path must consume the keyed pending entry so it can't - // linger (keyed entries are retained indefinitely) and be mis-claimed - // by a later same-key delegation. - let broker = DelegationBroker::new( - Arc::new(MockSpawner::new()) as Arc, - shallow_lookup(), - ); - broker - .register_pending_tool_call_with_key("p1", "tc-x".into(), Some(task_key("task A"))) - .await; - broker.consume_explicit_tool_call("p1", "tc-x").await; - // No longer claimable by its key. - assert!(broker - .take_matching_tool_call("p1", &task_key("task A")) - .await - .is_none()); - // A late ACP re-registration of the same id is dropped (consumed). - broker - .register_pending_tool_call_with_key("p1", "tc-x".into(), Some(task_key("task A"))) - .await; - assert!( - broker - .take_matching_tool_call("p1", &task_key("task A")) - .await - .is_none(), - "a re-registration after explicit consume must stay dropped" - ); - } - - #[tokio::test] - async fn explicit_tool_use_id_consumes_pending_entry_mcp_first() { - // The MCP-before-ACP order: the explicit-id request is handled before - // the ACP tool_call event registers. consume_explicit_tool_call records - // the id as consumed up front, so the later registration is dropped. - let broker = DelegationBroker::new( - Arc::new(MockSpawner::new()) as Arc, - shallow_lookup(), - ); - broker.consume_explicit_tool_call("p1", "tc-y").await; - broker - .register_pending_tool_call_with_key("p1", "tc-y".into(), Some(task_key("task B"))) - .await; - assert!(broker - .take_matching_tool_call("p1", &task_key("task B")) - .await - .is_none()); - } - - #[tokio::test] - async fn tombstone_removes_stale_keyed_entry() { - // A `delegate_to_agent` tool call registered a keyed entry but its MCP - // round-trip never reached the broker (the call failed / the turn was - // interrupted). A terminal `ToolCallUpdate` tombstones the entry so it - // can't linger indefinitely (keyed entries are never aged out). - let broker = DelegationBroker::new( - Arc::new(MockSpawner::new()) as Arc, - shallow_lookup(), - ); - broker - .register_pending_tool_call_with_key("p1", "tc-stale".into(), Some(task_key("task A"))) - .await; - assert!(broker.tombstone_pending_tool_call("p1", "tc-stale").await); - assert!(broker - .take_matching_tool_call("p1", &task_key("task A")) - .await - .is_none()); - } - - #[tokio::test] - async fn tombstone_prevents_same_key_misbind() { - // The High regression: without the tombstone, a stale keyed entry is - // retained forever and a LATER identical-key delegation claims its dead - // id (the exact-key scan returns the oldest match). After tombstoning the - // stale entry, a fresh registration for the same key binds to the FRESH - // id instead. - let broker = DelegationBroker::new( - Arc::new(MockSpawner::new()) as Arc, - shallow_lookup(), - ); - broker - .register_pending_tool_call_with_key("p1", "tc-stale".into(), Some(task_key("task A"))) - .await; - broker.tombstone_pending_tool_call("p1", "tc-stale").await; - broker - .register_pending_tool_call_with_key("p1", "tc-fresh".into(), Some(task_key("task A"))) - .await; - assert_eq!( - broker - .take_matching_tool_call("p1", &task_key("task A")) - .await - .as_deref(), - Some("tc-fresh"), - "a later same-key delegation must claim the fresh id, not the tombstoned one" - ); - } - - #[tokio::test] - async fn tombstone_leaves_other_entries_intact() { - // A terminal update for an unrelated (non-delegation) id no-ops and must - // leave a registered delegation untouched. - let broker = DelegationBroker::new( - Arc::new(MockSpawner::new()) as Arc, - shallow_lookup(), - ); - broker - .register_pending_tool_call_with_key("p1", "tc-keep".into(), Some(task_key("task A"))) - .await; - assert!( - !broker - .tombstone_pending_tool_call("p1", "tc-bash-123") - .await - ); - assert_eq!( - broker - .take_matching_tool_call("p1", &task_key("task A")) - .await - .as_deref(), - Some("tc-keep") - ); - } - - #[tokio::test] - async fn tombstone_then_reregister_same_id_stays_dropped() { - // After tombstoning a real entry, an out-of-order re-registration of the - // same id is dropped by the Tier-1 consumed check — mirrors - // `explicit_tool_use_id_consumes_pending_entry_acp_first`. - let broker = DelegationBroker::new( - Arc::new(MockSpawner::new()) as Arc, - shallow_lookup(), - ); - broker - .register_pending_tool_call_with_key("p1", "tc-stale".into(), Some(task_key("task A"))) - .await; - assert!(broker.tombstone_pending_tool_call("p1", "tc-stale").await); - broker - .register_pending_tool_call_with_key("p1", "tc-stale".into(), Some(task_key("task A"))) - .await; - assert!( - broker - .take_matching_tool_call("p1", &task_key("task A")) - .await - .is_none(), - "a re-registration after tombstone must stay dropped" - ); - } - - #[tokio::test] - async fn tombstone_noop_does_not_record_consumed() { - // The tombstone runs for EVERY terminal tool-call update, most of them - // non-delegations. A no-op tombstone (id not pending) must NOT record - // `consumed` — otherwise `consumed` (no TTL/cap) would grow with every - // completed tool call, and a later legitimate registration of that id - // would be wrongly dropped. - let broker = DelegationBroker::new( - Arc::new(MockSpawner::new()) as Arc, - shallow_lookup(), - ); - assert!(!broker.tombstone_pending_tool_call("p1", "tc-x").await); - broker - .register_pending_tool_call_with_key("p1", "tc-x".into(), Some(task_key("task A"))) - .await; - assert_eq!( - broker - .take_matching_tool_call("p1", &task_key("task A")) - .await - .as_deref(), - Some("tc-x"), - "a no-op tombstone must not record consumed and drop a later registration" - ); - } - - #[tokio::test] - async fn tombstone_removes_only_the_matching_entry_from_a_multi_entry_bucket() { - // Tombstoning a MIDDLE entry removes only that id (retain is by exact - // tool_call_id, position-independent) and leaves the siblings claimable - // by their own keys. - let broker = DelegationBroker::new( - Arc::new(MockSpawner::new()) as Arc, - shallow_lookup(), - ); - broker - .register_pending_tool_call_with_key("p1", "tc-a".into(), Some(task_key("task A"))) - .await; - broker - .register_pending_tool_call_with_key("p1", "tc-b".into(), Some(task_key("task B"))) - .await; - broker - .register_pending_tool_call_with_key("p1", "tc-c".into(), Some(task_key("task C"))) - .await; - assert!(broker.tombstone_pending_tool_call("p1", "tc-b").await); - assert!(broker - .take_matching_tool_call("p1", &task_key("task B")) - .await - .is_none()); - assert_eq!( - broker - .take_matching_tool_call("p1", &task_key("task A")) - .await - .as_deref(), - Some("tc-a") - ); - assert_eq!( - broker - .take_matching_tool_call("p1", &task_key("task C")) - .await - .as_deref(), - Some("tc-c") - ); - } - - #[tokio::test] - async fn keyed_pending_entries_have_no_count_cap() { - // Regression for the PENDING_QUEUE_CAP removal: a high-fan-out parent - // can register hundreds of keyed pending tool_calls — each awaiting its - // own serialized MCP round-trip — and EVERY one is retained. The old - // hard cap evicted the oldest keyed entry past 32, orphaning its card to - // a synthetic id. Keyed entries are now bounded only by claim, terminal - // tombstoning, and per-parent teardown. - let broker = DelegationBroker::new( - Arc::new(MockSpawner::new()) as Arc, - shallow_lookup(), - ); - const N: usize = 256; - for i in 0..N { - broker - .register_pending_tool_call_with_key( - "p1", - format!("tc-{i}"), - Some(task_key(&format!("task {i}"))), - ) - .await; - } - { - let map = broker.tool_calls.inner.lock().await; - let bucket = map.get("p1").expect("bucket present"); - assert_eq!( - bucket.pending.len(), - N, - "all keyed pending entries must be retained — no count cap" - ); - } - // Each entry stays individually claimable by its exact key, in any - // order — proving none were dropped or mis-bound by fan-out. - for i in [0usize, N / 2, N - 1] { - let claimed = broker - .take_matching_tool_call("p1", &task_key(&format!("task {i}"))) - .await; - assert_eq!(claimed.as_deref(), Some(format!("tc-{i}").as_str())); - } - } - - #[tokio::test] - async fn keyed_pending_entry_drains_via_tombstone() { - // The drain path the no-cap design relies on: when the parent-side ACP - // tool_call goes terminal before its MCP round-trip ever claims it, - // `tombstone_pending_tool_call` removes the keyed entry (so it can't - // linger) AND records it consumed (so a late re-emit can't mis-bind a - // later delegation sharing the same key). - let broker = DelegationBroker::new( - Arc::new(MockSpawner::new()) as Arc, - shallow_lookup(), - ); - broker - .register_pending_tool_call_with_key("p1", "tc-x".into(), Some(task_key("task x"))) - .await; - assert!( - broker.tombstone_pending_tool_call("p1", "tc-x").await, - "tombstone must report it removed the pending entry" - ); - assert!( - broker - .take_matching_tool_call("p1", &task_key("task x")) - .await - .is_none(), - "a tombstoned entry must be drained from pending" - ); - // Re-register of the same id after tombstoning is dropped by the - // Tier-1 consumed check, so it can never be claimed. - broker - .register_pending_tool_call_with_key("p1", "tc-x".into(), Some(task_key("task x"))) - .await; - assert!( - broker - .take_matching_tool_call("p1", &task_key("task x")) - .await - .is_none(), - "consumed memory must reject a re-emit of a tombstoned id" - ); - } - - #[tokio::test] - async fn reregistration_refines_key_with_late_working_dir() { - // Codex re-review fix: the same tool_call_id first registers with a key - // LACKING working_dir (an early parseable raw_input), then a later - // ToolCallUpdate completes it with the explicit working_dir. The stored - // key must be REPLACED with the fuller one — otherwise the MCP claim - // keying on Some(dir) can't match the stale None and orphans to a - // synthetic id (dead card for explicit-working-dir delegations). - let broker = DelegationBroker::new( - Arc::new(MockSpawner::new()) as Arc, - shallow_lookup(), - ); - broker - .register_pending_tool_call_with_key( - "p1", - "tc-d".into(), - Some(key_for(AgentType::Codex, "build")), - ) - .await; - // Later update adds the explicit working_dir → key is refined in place. - broker - .register_pending_tool_call_with_key( - "p1", - "tc-d".into(), - Some(key_with_dir("build", "/repo")), - ) - .await; - // The stale `working_dir: None` key no longer matches (it was replaced)… - assert!(broker - .take_matching_tool_call("p1", &key_for(AgentType::Codex, "build")) - .await - .is_none()); - // …and the refined `Some("/repo")` key claims the real id. - assert_eq!( - broker - .take_matching_tool_call("p1", &key_with_dir("build", "/repo")) - .await - .as_deref(), - Some("tc-d"), - "the MCP claim with the explicit working_dir must match the refined key" - ); - } - - #[tokio::test] - async fn empty_parent_tool_use_id_claims_pending_then_completes() { - let mock = Arc::new(MockSpawner::new()); - mock.queue_spawn(Ok("c1".into())).await; - mock.queue_send(Ok(7)).await; - let broker = - DelegationBroker::new(mock.clone() as Arc, shallow_lookup()); - enable_delegation(&broker).await; - broker - .register_pending_tool_call("parent-conn", "tu-from-acp".into()) - .await; - let driver = { - let broker = broker.clone(); - tokio::spawn(async move { broker.handle_request(request(1, "")).await }) - }; - while broker.pending_count().await == 0 { - tokio::time::sleep(Duration::from_millis(5)).await; - } - // The captured ACP id was consumed. - assert!(broker.take_pending_tool_call("parent-conn").await.is_none()); - let call_id = broker.peek_first_pending_call_id().await.unwrap(); - broker - .complete_call( - &call_id, - DelegationOutcome::Ok(DelegationSuccess { - text: "ok".into(), - child_conversation_id: 7, - child_agent_type: AgentType::Codex, - turn_count: 1, - duration_ms: 5, - token_usage: None, - }), - ) - .await; - let outcome = driver.await.unwrap(); - assert!(matches!(outcome, DelegationOutcome::Ok(_))); - } - - #[tokio::test] - async fn empty_parent_tool_use_id_claims_pending_arriving_late() { - // Regression: when the parent's ACP `session/update(tool_call)` - // lands at the lifecycle dispatcher AFTER `broker.handle_request` - // already entered the claim phase, the brief poll loop must still - // pick it up rather than falling back to the synthetic UUID. - let mock = Arc::new(MockSpawner::new()); - mock.queue_spawn(Ok("c-late".into())).await; - mock.queue_send(Ok(13)).await; - let broker = - DelegationBroker::new(mock.clone() as Arc, shallow_lookup()); - enable_delegation(&broker).await; - - let driver = { - let broker = broker.clone(); - tokio::spawn(async move { broker.handle_request(request(1, "")).await }) - }; - - // Give the driver time to enter the claim wait loop on an empty - // queue, then register the ACP id (simulates the dispatcher's - // ToolCall handling landing late). - tokio::time::sleep(Duration::from_millis(30)).await; - broker - .register_pending_tool_call("parent-conn", "tu-late".into()) - .await; - - while broker.pending_count().await == 0 { - tokio::time::sleep(Duration::from_millis(5)).await; - } - // The late-arriving ACP id was consumed by the broker — no leftover - // entry. - assert!(broker.take_pending_tool_call("parent-conn").await.is_none()); - let call_id = broker.peek_first_pending_call_id().await.unwrap(); - broker - .complete_call( - &call_id, - DelegationOutcome::Ok(DelegationSuccess { - text: "late ok".into(), - child_conversation_id: 13, - child_agent_type: AgentType::Codex, - turn_count: 1, - duration_ms: 5, - token_usage: None, - }), - ) - .await; - let outcome = driver.await.unwrap(); - assert!(matches!(outcome, DelegationOutcome::Ok(_))); - } - - #[tokio::test] - async fn empty_parent_tool_use_id_with_no_pending_falls_back_to_uuid() { - let mock = Arc::new(MockSpawner::new()); - mock.queue_spawn(Ok("c1".into())).await; - mock.queue_send(Ok(11)).await; - let broker = - DelegationBroker::new(mock.clone() as Arc, shallow_lookup()); - enable_delegation(&broker).await; - let driver = { - let broker = broker.clone(); - tokio::spawn(async move { broker.handle_request(request(1, "")).await }) - }; - while broker.pending_count().await == 0 { - tokio::time::sleep(Duration::from_millis(5)).await; - } - let call_id = broker.peek_first_pending_call_id().await.unwrap(); - broker - .complete_call( - &call_id, - DelegationOutcome::Ok(DelegationSuccess { - text: "fallback ok".into(), - child_conversation_id: 11, - child_agent_type: AgentType::Codex, - turn_count: 1, - duration_ms: 5, - token_usage: None, - }), - ) - .await; - let outcome = driver.await.unwrap(); - assert!(matches!(outcome, DelegationOutcome::Ok(_))); - } - - #[tokio::test] - async fn cancel_by_parent_also_drops_pending_tool_calls() { - let broker = DelegationBroker::new( - Arc::new(MockSpawner::new()) as Arc, - shallow_lookup(), - ); - broker - .register_pending_tool_call("parent-conn", "tu-1".into()) - .await; - broker.cancel_by_parent("parent-conn").await; - assert!(broker.take_pending_tool_call("parent-conn").await.is_none()); - } - - #[tokio::test] - async fn turn_cancel_keeps_consumed_rejects_reemit() { - // A turn/prompt cancel (parent connection STAYS ALIVE) must NOT drop the - // `consumed` tool_call memory. Otherwise a host re-emit of an - // already-claimed id (e.g. a terminal status-flip) re-registers as fresh - // `pending` and the next same-key delegation mis-binds to it — the - // dead-card/wrong-child class this correlation machinery exists to - // prevent. `cancel_by_parent_turn` retains `consumed`, so the re-emit - // stays rejected by the Tier-1 consumed check. - let broker = DelegationBroker::new( - Arc::new(MockSpawner::new()) as Arc, - shallow_lookup(), - ); - // Register + claim a keyed id (the delegation that just ran). - broker - .register_pending_tool_call_with_key("p1", "tc-A".into(), Some(task_key("task A"))) - .await; - assert_eq!( - broker - .take_matching_tool_call("p1", &task_key("task A")) - .await - .as_deref(), - Some("tc-A"), - ); - // Turn cancel — parent still alive. - broker.cancel_by_parent_turn("p1").await; - // Host re-emits the now-consumed id with the same key. - broker - .register_pending_tool_call_with_key("p1", "tc-A".into(), Some(task_key("task A"))) - .await; - assert!( - broker - .take_matching_tool_call("p1", &task_key("task A")) - .await - .is_none(), - "re-emit of a consumed id must stay rejected across a turn cancel" - ); - } - - #[tokio::test] - async fn turn_cancel_drops_unclaimed_pending() { - // The unclaimed `pending` half is cleared by a turn cancel (tombstoned - // into `consumed`): the cancelled turn's serial round-trip won't arrive, - // so the stale keyed entry must not remain claimable by a later same-key - // delegation. `take_matching` scans only `pending`, so it returns None. - let broker = DelegationBroker::new( - Arc::new(MockSpawner::new()) as Arc, - shallow_lookup(), - ); - broker - .register_pending_tool_call_with_key("p1", "tc-B".into(), Some(task_key("task B"))) - .await; - broker.cancel_by_parent_turn("p1").await; - assert!( - broker - .take_matching_tool_call("p1", &task_key("task B")) - .await - .is_none(), - "unclaimed pending must not stay claimable after a turn cancel" - ); - } - - #[tokio::test] - async fn turn_cancel_tombstones_pending_rejects_late_reemit() { - // Stronger than the clear test: after a turn cancel clears an UNCLAIMED - // keyed pending id, a late host re-emit of that SAME id must not - // resurrect it as a claimable entry — otherwise the next same-key - // delegation would mis-bind to the stale id. The cancel tombstones the - // cleared id into `consumed`, so the re-emit is dropped by the Tier-1 - // consumed check and never re-enters `pending`. - let broker = DelegationBroker::new( - Arc::new(MockSpawner::new()) as Arc, - shallow_lookup(), - ); - broker - .register_pending_tool_call_with_key("p1", "tc-X".into(), Some(task_key("task X"))) - .await; - broker.cancel_by_parent_turn("p1").await; - // Late re-emit of the cancelled turn's unclaimed id (same key). - broker - .register_pending_tool_call_with_key("p1", "tc-X".into(), Some(task_key("task X"))) - .await; - assert!( - broker - .take_matching_tool_call("p1", &task_key("task X")) - .await - .is_none(), - "a re-emit of a tombstoned (cleared-on-cancel) pending id must not be claimable" - ); - } - - #[tokio::test] - async fn teardown_cancel_clears_consumed() { - // The teardown variant (`cancel_by_parent`) DOES drop consumed — the - // connection is going away, so a reused connection_id must start clean. - // Contrast with `turn_cancel_keeps_consumed_rejects_reemit`. - let broker = DelegationBroker::new( - Arc::new(MockSpawner::new()) as Arc, - shallow_lookup(), - ); - broker.register_pending_tool_call("p1", "tc-A".into()).await; - assert_eq!( - broker.take_pending_tool_call("p1").await.as_deref(), - Some("tc-A"), - ); - broker.cancel_by_parent("p1").await; - // consumed cleared → the same id re-registers and is claimable again. - broker.register_pending_tool_call("p1", "tc-A".into()).await; - assert_eq!( - broker.take_pending_tool_call("p1").await.as_deref(), - Some("tc-A"), - "teardown cancel must clear consumed so id reuse is acceptable" - ); - } - - #[tokio::test] - async fn cancel_by_parent_turn_drains_synchronously_then_tears_down_child() { - // The turn cancel must (a) drop the tracker + remove parked calls - // SYNCHRONOUSLY — before the connection loop could accept the next - // prompt — so a delayed cancel can't tombstone/cancel a NEXT turn's - // entries (the invariant `drop_tool_calls_for_parent` relies on); and - // (b) still fully tear the child down (backgrounded), resolving the - // awaiting `handle_request` as canceled exactly once. - let mock = Arc::new(MockSpawner::new()); - mock.queue_spawn(Ok("child-1".into())).await; - mock.queue_send(Ok(7)).await; - let broker = - DelegationBroker::new(mock.clone() as Arc, shallow_lookup()); - enable_delegation(&broker).await; - - // Park a delegation for "parent-conn"... - let driver = { - let broker = broker.clone(); - tokio::spawn(async move { broker.handle_request(request(1, "pt-1")).await }) - }; - while broker.pending_count().await == 0 { - tokio::time::sleep(Duration::from_millis(5)).await; - } - // ...plus a separate unclaimed keyed tracker entry on the same parent. - broker - .register_pending_tool_call_with_key( - "parent-conn", - "tc-Z".into(), - Some(task_key("task Z")), - ) - .await; - - broker.cancel_by_parent_turn("parent-conn").await; - - // (a) Synchronously — no sleep: the parked call is removed and the - // tracker entry is dropped (tombstoned), so neither can leak into a - // next-turn registration that the backgrounded teardown might clobber. - assert_eq!( - broker.pending_count().await, - 0, - "parked call must be drained synchronously by the turn cancel" - ); - assert!( - broker - .take_matching_tool_call("parent-conn", &task_key("task Z")) - .await - .is_none(), - "tracker pending must be dropped synchronously by the turn cancel" - ); - - // (b) The backgrounded child teardown still resolves the driver as - // canceled and tears the child down exactly once. - match driver.await.unwrap() { - DelegationOutcome::Err { code, .. } => assert_eq!(code, "canceled"), - other => panic!("expected canceled, got {other:?}"), - } - assert_eq!(mock.cancels.lock().await.as_slice(), &["child-1"]); - assert_eq!(mock.disconnects.lock().await.as_slice(), &["child-1"]); - } - - #[tokio::test] - async fn depth_limit_allows_root() { - let mock = Arc::new(MockSpawner::new()); - mock.queue_spawn(Ok("c1".into())).await; - mock.queue_send(Ok(7)).await; - let lookup = Arc::new(MockDepth(vec![(1, None)])) as Arc; - let broker = DelegationBroker::new(mock.clone() as Arc, lookup); - broker - .set_config(DelegationConfig { - enabled: true, - depth_limit: 2, - ..DelegationConfig::default() - }) - .await; - - let driver = { - let broker = broker.clone(); - tokio::spawn(async move { broker.handle_request(request(1, "pt-1")).await }) - }; - while broker.pending_count().await == 0 { - tokio::time::sleep(Duration::from_millis(5)).await; - } - let call_id = broker.peek_first_pending_call_id().await.unwrap(); - broker - .complete_call( - &call_id, - DelegationOutcome::Ok(DelegationSuccess { - text: "ok".into(), - child_conversation_id: 7, - child_agent_type: AgentType::ClaudeCode, - turn_count: 1, - duration_ms: 5, - token_usage: None, - }), - ) - .await; - let outcome = driver.await.unwrap(); - assert!(matches!(outcome, DelegationOutcome::Ok(_))); - } - - // -- Meta writer lifecycle -------------------------------------------- - - use crate::acp::delegation::meta_writer::mock::MockMetaWriter; - use crate::acp::delegation::meta_writer::DelegationMetaWriter; - - async fn broker_with_meta( - mock: Arc, - writer: Arc, - ) -> DelegationBroker { - let broker = DelegationBroker::with_meta_writer( - mock as Arc, - shallow_lookup(), - writer as Arc, - ); - enable_delegation(&broker).await; - broker - } - - #[tokio::test] - async fn meta_writes_carry_task_preview_and_task_id_on_every_write() { - // Meta is replace-wholesale on the ToolCallState, so BOTH the running - // and the terminal writes must carry the task label + broker task id — - // they are the persisted card's only label source on hosts whose - // raw_input never carries the arguments (Cursor). - let mock = Arc::new(MockSpawner::new()); - mock.queue_spawn(Ok("child-conn-t".into())).await; - mock.queue_send(Ok(42)).await; - let writer = Arc::new(MockMetaWriter::new()); - let broker = broker_with_meta(mock.clone(), writer.clone()).await; - - let driver = { - let broker = broker.clone(); - tokio::spawn(async move { broker.handle_request(request(1, "pt-task")).await }) - }; - let call_id = loop { - if let Some(id) = broker.peek_first_pending_call_id().await { - break id; - } - tokio::time::sleep(Duration::from_millis(5)).await; - }; - broker - .complete_call( - &call_id, - DelegationOutcome::Ok(DelegationSuccess { - text: "done".into(), - child_conversation_id: 42, - child_agent_type: AgentType::ClaudeCode, - turn_count: 1, - duration_ms: 5, - token_usage: None, - }), - ) - .await; - driver.await.unwrap(); - - let calls = writer.snapshot().await; - assert_eq!(calls.len(), 2); - for call in &calls { - let inner = call - .meta - .get("codeg.delegation") - .unwrap() - .as_object() - .unwrap(); - assert_eq!( - inner.get("task_preview").unwrap().as_str().unwrap(), - "do x", - "every write must keep the task label (status={})", - inner.get("status").unwrap() - ); - assert_eq!( - inner.get("task_id").unwrap().as_str().unwrap(), - &call_id, - "task_id must be the broker call id on every write" - ); - } - } - - #[tokio::test] - async fn identityless_fifo_claim_restores_delegate_identity() { - // Cursor path: the ACP announcement registered an identity-less - // candidate ("MCP: tool" + "{}"), the MCP round-trip arrives with no - // explicit tool_use id. The post-budget FIFO claim must land on the - // candidate AND restore the call's identity (canonical delegate title - // + reconstructed arguments) on the live tool call. - let mock = Arc::new(MockSpawner::new()); - mock.queue_spawn(Ok("child-conn-i".into())).await; - mock.queue_send(Ok(43)).await; - let writer = Arc::new(MockMetaWriter::new()); - let broker = broker_with_meta(mock.clone(), writer.clone()).await; - broker - .register_identityless_tool_call("parent-conn", "call-cursor-7\nfc_x_0".into()) - .await; - - let driver = { - let broker = broker.clone(); - // Empty tool_use id → claim path (2s budget, then FIFO). - tokio::spawn(async move { broker.handle_request(request(1, "")).await }) - }; - let call_id = loop { - if let Some(id) = broker.peek_first_pending_call_id().await { - break id; - } - tokio::time::sleep(Duration::from_millis(5)).await; - }; - broker - .complete_call( - &call_id, - DelegationOutcome::Ok(DelegationSuccess { - text: "done".into(), - child_conversation_id: 43, - child_agent_type: AgentType::ClaudeCode, - turn_count: 1, - duration_ms: 5, - token_usage: None, - }), - ) - .await; - driver.await.unwrap(); - - let identities = writer.identity_snapshot().await; - assert_eq!(identities.len(), 1, "exactly one identity restoration"); - let id_write = &identities[0]; - assert_eq!(id_write.parent_connection_id, "parent-conn"); - assert_eq!(id_write.tool_call_id, "call-cursor-7\nfc_x_0"); - assert_eq!( - id_write.title, - crate::acp::delegation::DELEGATE_TOOL_REWRITE_TITLE - ); - assert_eq!( - id_write.raw_input.get("task").unwrap().as_str().unwrap(), - "do x" - ); - assert_eq!( - id_write - .raw_input - .get("agent_type") - .unwrap() - .as_str() - .unwrap(), - "claude_code" - ); - // The meta writes bound to the REAL claimed id, not a synthetic one. - let metas = writer.snapshot().await; - assert!(metas - .iter() - .all(|m| m.parent_tool_use_id == "call-cursor-7\nfc_x_0")); - } - - #[tokio::test] - async fn keyed_claim_does_not_rewrite_host_identity() { - // A host that shipped real raw_input (keyed registration) keeps its - // own wire identity — reconstructing raw_input would clobber - // host-specific fields. - let mock = Arc::new(MockSpawner::new()); - mock.queue_spawn(Ok("child-conn-k".into())).await; - mock.queue_send(Ok(44)).await; - let writer = Arc::new(MockMetaWriter::new()); - let broker = broker_with_meta(mock.clone(), writer.clone()).await; - broker - .register_pending_tool_call_with_key( - "parent-conn", - "tc-keyed".into(), - Some(DelegationMatchKey { - agent_type: AgentType::ClaudeCode, - task: "do x".into(), - working_dir: None, - }), - ) - .await; - - let driver = { - let broker = broker.clone(); - tokio::spawn(async move { broker.handle_request(request(1, "")).await }) - }; - let call_id = loop { - if let Some(id) = broker.peek_first_pending_call_id().await { - break id; - } - tokio::time::sleep(Duration::from_millis(5)).await; - }; - broker - .complete_call( - &call_id, - DelegationOutcome::Ok(DelegationSuccess { - text: "done".into(), - child_conversation_id: 44, - child_agent_type: AgentType::ClaudeCode, - turn_count: 1, - duration_ms: 5, - token_usage: None, - }), - ) - .await; - driver.await.unwrap(); - - assert!( - writer.identity_snapshot().await.is_empty(), - "keyed (host-identified) claims must not be rewritten" - ); - let metas = writer.snapshot().await; - assert!(metas.iter().all(|m| m.parent_tool_use_id == "tc-keyed")); - } - - #[tokio::test] - async fn rewrite_identityless_tool_call_claims_and_writes_status_identity() { - let writer = Arc::new(MockMetaWriter::new()); - let broker = broker_with_meta(Arc::new(MockSpawner::new()), writer.clone()).await; - broker - .register_identityless_tool_call("parent-conn", "call-status-1".into()) - .await; - - let claimed = broker - .rewrite_identityless_tool_call( - "parent-conn", - crate::acp::delegation::STATUS_TOOL_REWRITE_TITLE, - serde_json::json!({"task_ids": ["t-1"], "wait_ms": 0}), - ) - .await; - assert_eq!(claimed.as_deref(), Some("call-status-1")); - let identities = writer.identity_snapshot().await; - assert_eq!(identities.len(), 1); - assert_eq!( - identities[0].title, - crate::acp::delegation::STATUS_TOOL_REWRITE_TITLE - ); - assert_eq!( - identities[0].raw_input.get("task_ids").unwrap()[0] - .as_str() - .unwrap(), - "t-1" - ); - // Consumed: the candidate can't be claimed again by the delegate FIFO. - assert!(broker.take_pending_tool_call("parent-conn").await.is_none()); - } - - #[tokio::test] - async fn rewrite_skips_connections_that_never_announced_identityless() { - // Plain unkeyed registration (a keyless delegation invocation) must - // NOT be renamed — and the sticky gate must return instantly (no - // 300 ms poll) for such connections. Also: the entry stays claimable - // by the delegate FIFO afterwards. - let writer = Arc::new(MockMetaWriter::new()); - let broker = broker_with_meta(Arc::new(MockSpawner::new()), writer.clone()).await; - broker - .register_pending_tool_call("parent-conn", "tc-plain".into()) - .await; - - let started = std::time::Instant::now(); - let claimed = broker - .rewrite_identityless_tool_call( - "parent-conn", - crate::acp::delegation::STATUS_TOOL_REWRITE_TITLE, - serde_json::json!({"task_ids": ["t-1"]}), - ) - .await; - assert!(claimed.is_none()); - // The poll path sleeps ≥300 ms (30 × 10 ms lower bounds); the gate - // path sleeps zero. 280 ms discriminates the two while leaving slack - // for full-suite parallel-load scheduling jitter. - assert!( - started.elapsed() < Duration::from_millis(280), - "sticky gate must skip the poll for hosts without identity-less announcements" - ); - assert!(writer.identity_snapshot().await.is_empty()); - assert_eq!( - broker - .take_pending_tool_call("parent-conn") - .await - .as_deref(), - Some("tc-plain"), - "the plain unkeyed entry must remain for the delegate FIFO" - ); - } - - #[tokio::test] - async fn meta_writer_records_running_then_completed_on_happy_path() { - let mock = Arc::new(MockSpawner::new()); - mock.queue_spawn(Ok("child-conn-1".into())).await; - mock.queue_send(Ok(42)).await; - let writer = Arc::new(MockMetaWriter::new()); - let broker = broker_with_meta(mock.clone(), writer.clone()).await; - - let driver = { - let broker = broker.clone(); - tokio::spawn(async move { broker.handle_request(request(1, "pt-real")).await }) - }; - let call_id = loop { - if let Some(id) = broker.peek_first_pending_call_id().await { - break id; - } - tokio::time::sleep(Duration::from_millis(5)).await; - }; - broker - .complete_call( - &call_id, - DelegationOutcome::Ok(DelegationSuccess { - text: "done".into(), - child_conversation_id: 42, - child_agent_type: AgentType::ClaudeCode, - turn_count: 1, - duration_ms: 5, - token_usage: None, - }), - ) - .await; - driver.await.unwrap(); - - let calls = writer.snapshot().await; - assert_eq!(calls.len(), 2); - // First write: running, with child connection + conversation ids. - let first = &calls[0]; - assert_eq!(first.parent_tool_use_id, "pt-real"); - let inner_first = first - .meta - .get("codeg.delegation") - .unwrap() - .as_object() - .unwrap(); - assert_eq!( - inner_first.get("status").unwrap().as_str().unwrap(), - "running" - ); - assert_eq!( - inner_first - .get("child_connection_id") - .unwrap() - .as_str() - .unwrap(), - "child-conn-1" - ); - assert_eq!( - inner_first - .get("child_conversation_id") - .unwrap() - .as_i64() - .unwrap(), - 42 - ); - // Second write: completed. - let second = &calls[1]; - let inner_second = second - .meta - .get("codeg.delegation") - .unwrap() - .as_object() - .unwrap(); - assert_eq!( - inner_second.get("status").unwrap().as_str().unwrap(), - "completed" - ); - } - - #[tokio::test] - async fn meta_writer_records_failed_on_err_outcome() { - let mock = Arc::new(MockSpawner::new()); - mock.queue_spawn(Ok("child-conn-2".into())).await; - mock.queue_send(Ok(7)).await; - let writer = Arc::new(MockMetaWriter::new()); - let broker = broker_with_meta(mock.clone(), writer.clone()).await; - - let driver = { - let broker = broker.clone(); - tokio::spawn(async move { broker.handle_request(request(1, "pt-err")).await }) - }; - let call_id = loop { - if let Some(id) = broker.peek_first_pending_call_id().await { - break id; - } - tokio::time::sleep(Duration::from_millis(5)).await; - }; - broker - .complete_call( - &call_id, - DelegationOutcome::from_err( - DelegationError::SubagentRuntimeError("agent died".into()), - Some(7), - ), - ) - .await; - driver.await.unwrap(); - - let calls = writer.snapshot().await; - assert_eq!(calls.len(), 2); - let inner = calls[1] - .meta - .get("codeg.delegation") - .unwrap() - .as_object() - .unwrap(); - assert_eq!(inner.get("status").unwrap().as_str().unwrap(), "failed"); - assert_eq!( - inner.get("error_code").unwrap().as_str().unwrap(), - "subagent_error" - ); - } - - // -- Registration-race: child terminal failure before the entry is parked -- - - /// Headline regression: a child terminal failure (auth error / immediate - /// process death) that fires AFTER the broker reserved the child but BEFORE - /// it parked the pending entry must still resolve the parked request — not - /// no-op and strand it on `rx.await` forever. The `send_gate` pins - /// `handle_request` in exactly that window; we fire the failure, release the - /// gate, and assert the request resolves as canceled (carrying the - /// terminal-error detail) with a single child disconnect and a clean - /// running→failed meta trail. - #[tokio::test] - async fn child_failure_before_park_resolves_instead_of_hanging() { - let mock = Arc::new(MockSpawner::new()); - mock.queue_spawn(Ok("c-fast-fail".into())).await; - mock.queue_send(Ok(55)).await; - let release = mock.install_send_gate().await; - let writer = Arc::new(MockMetaWriter::new()); - let broker = broker_with_meta(mock.clone(), writer.clone()).await; - - let driver = { - let broker = broker.clone(); - tokio::spawn(async move { broker.handle_request(request(1, "pt-fast")).await }) - }; - - // Wait until handle_request has spawned + reserved the child and is - // held inside send_prompt by the gate — entry NOT yet parked. - loop { - if broker.reserved_child_count().await == 1 { - break; - } - tokio::time::sleep(Duration::from_millis(5)).await; - } - assert_eq!(broker.pending_count().await, 0, "entry not parked yet"); - - // Child dies before the entry is parked. With the reservation in place - // this buffers (rather than no-oping on a not-yet-existent entry). - broker - .cancel_by_child_connection("c-fast-fail", Some("Authentication required")) - .await; - assert_eq!(broker.early_cancel_count().await, 1, "failure buffered"); - - // Release send_prompt → handle_request parks, drains the buffered - // failure, and resolves inline instead of hanging. - let _ = release.send(()); - let outcome = driver.await.unwrap(); - match outcome { - DelegationOutcome::Err { - code, - message, - child_conversation_id, - } => { - assert_eq!(code, "canceled"); - assert!( - message.contains("Authentication required"), - "reason should carry the terminal-error detail, got: {message}" - ); - assert_eq!(child_conversation_id, Some(55)); - } - other => panic!("expected canceled Err, got {other:?}"), - } - - // Reservation + buffer drained; child torn down exactly once. - assert_eq!(broker.pending_count().await, 0); - assert_eq!(broker.reserved_child_count().await, 0); - assert_eq!(broker.early_cancel_count().await, 0); - assert_eq!(mock.disconnects.lock().await.as_slice(), &["c-fast-fail"]); - - // Meta trail: running (written pre-park) then failed/canceled (pickup). - let calls = writer.snapshot().await; - assert_eq!(calls.len(), 2); - let running = calls[0] - .meta - .get("codeg.delegation") - .unwrap() - .as_object() - .unwrap(); - assert_eq!(running.get("status").unwrap().as_str().unwrap(), "running"); - let failed = calls[1] - .meta - .get("codeg.delegation") - .unwrap() - .as_object() - .unwrap(); - assert_eq!(failed.get("status").unwrap().as_str().unwrap(), "failed"); - assert_eq!( - failed.get("error_code").unwrap().as_str().unwrap(), - "canceled" - ); - } - - /// The SAME race on the SUCCESS path: a `TurnComplete` whose `complete_call` - /// fires AFTER the delegation reserved but BEFORE `handle_request` parked (a - /// fast/empty turn whose completion propagates while the broker is still - /// awaiting the parent `write_meta`) must still resolve the request. The - /// prompt is only *enqueued* by `send_prompt`, so the child loop can emit - /// `TurnComplete` before the park. The `send_gate` pins `handle_request` in - /// the reserve→park window; we resolve via the reserved `call_id` (the entry - /// isn't parked yet) and assert the request returns Ok instead of hanging. - #[tokio::test] - async fn completion_before_park_resolves_instead_of_hanging() { - let mock = Arc::new(MockSpawner::new()); - mock.queue_spawn(Ok("c-fast-ok".into())).await; - mock.queue_send(Ok(70)).await; - let release = mock.install_send_gate().await; - let writer = Arc::new(MockMetaWriter::new()); - let broker = broker_with_meta(mock.clone(), writer.clone()).await; - - let driver = { - let broker = broker.clone(); - tokio::spawn(async move { broker.handle_request(request(1, "pt-ok")).await }) - }; - - // Wait until reserved (spawned + id minted, held in send_prompt by the - // gate); the entry is NOT parked yet, so grab the call_id from the - // reservation rather than the parked-calls map. - let call_id = loop { - if let Some(id) = broker.peek_reserved_call_id().await { - break id; - } - tokio::time::sleep(Duration::from_millis(5)).await; - }; - assert_eq!(broker.pending_count().await, 0, "entry not parked yet"); - - // TurnComplete beats the park. With the reservation in place this - // buffers (rather than no-oping on a not-yet-existent entry). - broker - .complete_call( - &call_id, - DelegationOutcome::Ok(DelegationSuccess { - text: "fast done".into(), - child_conversation_id: 70, - child_agent_type: AgentType::ClaudeCode, - turn_count: 1, - duration_ms: 5, - token_usage: None, - }), - ) - .await; - assert_eq!( - broker.early_complete_count().await, - 1, - "completion buffered" - ); - - // Release send_prompt → handle_request parks, drains the buffered - // completion, and resolves inline instead of hanging. - let _ = release.send(()); - let outcome = driver.await.unwrap(); - match outcome { - DelegationOutcome::Ok(s) => { - assert_eq!(s.text, "fast done"); - assert_eq!(s.child_conversation_id, 70); - } - other => panic!("expected Ok, got {other:?}"), - } - - assert_eq!(broker.pending_count().await, 0); - assert_eq!(broker.reserved_call_count().await, 0); - assert_eq!(broker.reserved_child_count().await, 0); - assert_eq!(broker.early_complete_count().await, 0); - assert_eq!(mock.disconnects.lock().await.as_slice(), &["c-fast-ok"]); - - // Meta trail: running (written pre-park) then completed (pickup). - let calls = writer.snapshot().await; - assert_eq!(calls.len(), 2); - let running = calls[0] - .meta - .get("codeg.delegation") - .unwrap() - .as_object() - .unwrap(); - assert_eq!(running.get("status").unwrap().as_str().unwrap(), "running"); - let completed = calls[1] - .meta - .get("codeg.delegation") - .unwrap() - .as_object() - .unwrap(); - assert_eq!( - completed.get("status").unwrap().as_str().unwrap(), - "completed" - ); - } - - /// The reservation is released at park, and a SUCCESSFUL completion buffers - /// nothing. The child's post-completion disconnect (normal v1 one-shot - /// teardown) finds the child un-reserved and must NOT buffer a spurious - /// cancel — otherwise every completed delegation would leak a buffer entry. - #[tokio::test] - async fn normal_completion_leaves_no_reservation_or_buffer() { - let mock = Arc::new(MockSpawner::new()); - mock.queue_spawn(Ok("c-clean".into())).await; - mock.queue_send(Ok(60)).await; - let broker = - DelegationBroker::new(mock.clone() as Arc, shallow_lookup()); - enable_delegation(&broker).await; - - let driver = { - let broker = broker.clone(); - tokio::spawn(async move { broker.handle_request(request(1, "pt-clean")).await }) - }; - let call_id = loop { - if let Some(id) = broker.peek_first_pending_call_id().await { - break id; - } - tokio::time::sleep(Duration::from_millis(5)).await; - }; - // Parked → reservation already released. - assert_eq!( - broker.reserved_child_count().await, - 0, - "park releases the reservation" - ); - - broker - .complete_call( - &call_id, - DelegationOutcome::Ok(DelegationSuccess { - text: "ok".into(), - child_conversation_id: 60, - child_agent_type: AgentType::ClaudeCode, - turn_count: 1, - duration_ms: 5, - token_usage: None, - }), - ) - .await; - assert!(matches!(driver.await.unwrap(), DelegationOutcome::Ok(_))); - - // The child's post-completion disconnect arrives. Child is no longer - // reserved → must NOT buffer a spurious cancel. - broker.cancel_by_child_connection("c-clean", None).await; - assert_eq!( - broker.early_cancel_count().await, - 0, - "a post-resolution teardown must not buffer a spurious cancel" - ); - assert_eq!(broker.pending_count().await, 0); - } - - // -- Item 1: parent-cancel coverage of the `handle_request` setup window -- - - /// A parent cancel that lands while `handle_request` is INSIDE `spawn` (the - /// child exists but no prompt has been sent) must disconnect the child and - /// bail — never send it a prompt — instead of no-oping and letting it run - /// orphaned. Pinned with the spawn gate. - #[tokio::test] - async fn parent_cancel_in_spawn_window_disconnects_child_without_sending() { - let mock = Arc::new(MockSpawner::new()); - mock.queue_spawn(Ok("c2".into())).await; - mock.queue_send(Ok(99)).await; // staged but must NOT be consumed - let release = mock.install_spawn_gate().await; - let broker = - DelegationBroker::new(mock.clone() as Arc, shallow_lookup()); - enable_delegation(&broker).await; - - let driver = { - let broker = broker.clone(); - tokio::spawn(async move { broker.handle_request(request(1, "pt-2")).await }) - }; - // Inside spawn (call recorded, held by the gate): registered in-flight, - // not yet reserved. - loop { - if !mock.spawn_args.lock().await.is_empty() { - break; - } - tokio::time::sleep(Duration::from_millis(5)).await; - } - assert_eq!(broker.inflight_count().await, 1); - assert_eq!(broker.reserved_child_count().await, 0, "not reserved yet"); - - broker.cancel_by_parent_turn("parent-conn").await; - let _ = release.send(()); - - match driver.await.unwrap() { - DelegationOutcome::Err { code, .. } => assert_eq!(code, "canceled"), - other => panic!("expected canceled, got {other:?}"), - } - assert_eq!(mock.disconnects.lock().await.as_slice(), &["c2"]); - assert!( - mock.cancels.lock().await.is_empty(), - "no prompt was sent, so no cancel — disconnect only" - ); - assert_eq!( - mock.send_results.lock().await.len(), - 1, - "send must not be consumed — no prompt sent to an abandoned child" - ); - assert_eq!(broker.inflight_count().await, 0); - assert_eq!(broker.reserved_child_count().await, 0); - } - - /// A parent cancel that lands in the reserve→park window (prompt already - /// sent, entry not yet parked) must cancel AND disconnect the child and - /// resolve the request as canceled. Pinned with the send gate; also asserts - /// the running→failed/canceled meta trail. - #[tokio::test] - async fn parent_cancel_in_reserve_park_window_tears_down_child() { - let mock = Arc::new(MockSpawner::new()); - mock.queue_spawn(Ok("c3".into())).await; - mock.queue_send(Ok(33)).await; - let release = mock.install_send_gate().await; - let writer = Arc::new(MockMetaWriter::new()); - let broker = broker_with_meta(mock.clone(), writer.clone()).await; - - let driver = { - let broker = broker.clone(); - tokio::spawn(async move { broker.handle_request(request(1, "pt-3")).await }) - }; - // Spawned + reserved, held inside send_prompt. - loop { - if broker.reserved_child_count().await == 1 { - break; - } - tokio::time::sleep(Duration::from_millis(5)).await; - } - assert_eq!(broker.inflight_count().await, 1); - assert_eq!(broker.pending_count().await, 0, "not parked yet"); - - broker.cancel_by_parent_turn("parent-conn").await; - let _ = release.send(()); - - match driver.await.unwrap() { - DelegationOutcome::Err { - code, - child_conversation_id, - .. - } => { - assert_eq!(code, "canceled"); - assert_eq!(child_conversation_id, Some(33)); - } - other => panic!("expected canceled, got {other:?}"), - } - // Prompt was sent → child cancel()'d AND disconnected. - assert_eq!(mock.cancels.lock().await.as_slice(), &["c3"]); - assert_eq!(mock.disconnects.lock().await.as_slice(), &["c3"]); - assert_eq!(broker.inflight_count().await, 0); - assert_eq!(broker.reserved_child_count().await, 0); - assert_eq!(broker.early_cancel_count().await, 0); - assert_eq!(broker.pending_count().await, 0); - - // Meta trail: running (pre-park) then failed/canceled (ParentCanceled). - let calls = writer.snapshot().await; - assert_eq!(calls.len(), 2); - let running = calls[0] - .meta - .get("codeg.delegation") - .unwrap() - .as_object() - .unwrap(); - assert_eq!(running.get("status").unwrap().as_str().unwrap(), "running"); - let failed = calls[1] - .meta - .get("codeg.delegation") - .unwrap() - .as_object() - .unwrap(); - assert_eq!(failed.get("status").unwrap().as_str().unwrap(), "failed"); - assert_eq!( - failed.get("error_code").unwrap().as_str().unwrap(), - "canceled" - ); - } - - /// Strict first-terminal-wins: when a child completion buffers FIRST and a - /// parent cancel lands afterward, the child's earlier arrival stamp wins and - /// its real result is preserved (the cancel is moot — the child already - /// finished before it). - #[tokio::test] - async fn child_terminal_wins_over_later_parent_cancel() { - let mock = Arc::new(MockSpawner::new()); - mock.queue_spawn(Ok("c4".into())).await; - mock.queue_send(Ok(44)).await; - let release = mock.install_send_gate().await; - let broker = - DelegationBroker::new(mock.clone() as Arc, shallow_lookup()); - enable_delegation(&broker).await; - - let driver = { - let broker = broker.clone(); - tokio::spawn(async move { broker.handle_request(request(1, "pt-4")).await }) - }; - let call_id = loop { - if let Some(id) = broker.peek_reserved_call_id().await { - break id; - } - tokio::time::sleep(Duration::from_millis(5)).await; - }; - assert_eq!(broker.inflight_count().await, 1); - - // Child completes FIRST, then the parent cancels — child result wins. - broker - .complete_call( - &call_id, - DelegationOutcome::Ok(DelegationSuccess { - text: "done".into(), - child_conversation_id: 44, - child_agent_type: AgentType::ClaudeCode, - turn_count: 1, - duration_ms: 5, - token_usage: None, - }), - ) - .await; - broker.cancel_by_parent_turn("parent-conn").await; - let _ = release.send(()); - - assert!(matches!(driver.await.unwrap(), DelegationOutcome::Ok(_))); - assert!( - mock.cancels.lock().await.is_empty(), - "child completed — the moot parent cancel must not cancel it" - ); - assert_eq!(broker.inflight_count().await, 0); - assert_eq!(broker.early_complete_count().await, 0); - } - - /// Strict first-terminal-wins (Item 3): when the parent cancel is recorded - /// BEFORE the child completion buffers, the cancel wins — the late - /// completion is discarded and the child is torn down, because the parent - /// had already abandoned the turn by the time the completion landed. - #[tokio::test] - async fn parent_cancel_wins_when_it_arrives_before_child_terminal() { - let mock = Arc::new(MockSpawner::new()); - mock.queue_spawn(Ok("c5".into())).await; - mock.queue_send(Ok(55)).await; - let release = mock.install_send_gate().await; - let broker = - DelegationBroker::new(mock.clone() as Arc, shallow_lookup()); - enable_delegation(&broker).await; - - let driver = { - let broker = broker.clone(); - tokio::spawn(async move { broker.handle_request(request(1, "pt-5")).await }) - }; - let call_id = loop { - if let Some(id) = broker.peek_reserved_call_id().await { - break id; - } - tokio::time::sleep(Duration::from_millis(5)).await; - }; - - // Parent cancels FIRST (earlier arrival stamp); the child completes - // afterward (later stamp) — first-terminal-wins judges the cancel the - // winner and discards the late completion. - broker.cancel_by_parent_turn("parent-conn").await; - broker - .complete_call( - &call_id, - DelegationOutcome::Ok(DelegationSuccess { - text: "late".into(), - child_conversation_id: 55, - child_agent_type: AgentType::ClaudeCode, - turn_count: 1, - duration_ms: 5, - token_usage: None, - }), - ) - .await; - let _ = release.send(()); - - match driver.await.unwrap() { - DelegationOutcome::Err { - code, - child_conversation_id, - .. - } => { - assert_eq!(code, "canceled"); - assert_eq!(child_conversation_id, Some(55)); - } - other => panic!( - "first-terminal-wins: an earlier parent cancel must beat a later completion, got {other:?}" - ), - } - // The abandoned child is torn down (prompt was sent → cancel + disconnect). - assert_eq!(mock.cancels.lock().await.as_slice(), &["c5"]); - assert_eq!(mock.disconnects.lock().await.as_slice(), &["c5"]); - assert_eq!(broker.inflight_count().await, 0); - // The buffered completion was drained (and discarded), leaving no leak. - assert_eq!(broker.early_complete_count().await, 0); - } - - /// Strict first-terminal-wins through the child-FAILURE buffer: a child - /// failure that buffers BEFORE a parent cancel keeps its (earlier) arrival - /// stamp and wins, so the request resolves with the child's failure detail - /// and the child is torn down once (disconnect only — the child already - /// failed, so there's no in-flight prompt to cancel). Exercises the - /// `early_cancels` stamp path that mirrors the completion case above. - #[tokio::test] - async fn child_failure_wins_over_later_parent_cancel() { - let mock = Arc::new(MockSpawner::new()); - mock.queue_spawn(Ok("cF".into())).await; - mock.queue_send(Ok(66)).await; - let release = mock.install_send_gate().await; - let broker = - DelegationBroker::new(mock.clone() as Arc, shallow_lookup()); - enable_delegation(&broker).await; - - let driver = { - let broker = broker.clone(); - tokio::spawn(async move { broker.handle_request(request(1, "pt-f")).await }) - }; - // Spawned + reserved, held inside send_prompt by the gate. - loop { - if broker.reserved_child_count().await == 1 { - break; - } - tokio::time::sleep(Duration::from_millis(5)).await; - } - - // Child fails FIRST (earlier stamp), then the parent cancels (later - // stamp) — the child terminal wins and carries its failure detail. - broker - .cancel_by_child_connection("cF", Some("boom detail")) - .await; - broker.cancel_by_parent_turn("parent-conn").await; - let _ = release.send(()); - - match driver.await.unwrap() { - DelegationOutcome::Err { - code, - message, - child_conversation_id, - } => { - assert_eq!(code, "canceled"); - assert!( - message.contains("boom detail"), - "child failure detail must survive, got: {message}" - ); - assert_eq!(child_conversation_id, Some(66)); - } - other => panic!("expected child failure Err, got {other:?}"), - } - // Child-terminal path tears down via disconnect only (no cancel). - assert_eq!(mock.disconnects.lock().await.as_slice(), &["cF"]); - assert!( - mock.cancels.lock().await.is_empty(), - "child already failed — the moot parent cancel must not cancel it" - ); - assert_eq!(broker.inflight_count().await, 0); - assert_eq!(broker.early_cancel_count().await, 0); - } - - /// The teardown variant `cancel_by_parent` covers the same reserve→park - /// window as the turn variant — both funnel through `drain_for_parent_cancel` - /// where the in-flight mark is applied. - #[tokio::test] - async fn parent_teardown_in_reserve_park_window_tears_down_child() { - let mock = Arc::new(MockSpawner::new()); - mock.queue_spawn(Ok("c7".into())).await; - mock.queue_send(Ok(77)).await; - let release = mock.install_send_gate().await; - let broker = - DelegationBroker::new(mock.clone() as Arc, shallow_lookup()); - enable_delegation(&broker).await; - - let driver = { - let broker = broker.clone(); - tokio::spawn(async move { broker.handle_request(request(1, "pt-7")).await }) - }; - loop { - if broker.reserved_child_count().await == 1 { - break; - } - tokio::time::sleep(Duration::from_millis(5)).await; - } - broker.cancel_by_parent("parent-conn").await; - let _ = release.send(()); - - match driver.await.unwrap() { - DelegationOutcome::Err { code, .. } => assert_eq!(code, "canceled"), - other => panic!("expected canceled, got {other:?}"), - } - assert_eq!(mock.cancels.lock().await.as_slice(), &["c7"]); - assert_eq!(mock.disconnects.lock().await.as_slice(), &["c7"]); - assert_eq!(broker.inflight_count().await, 0); - } - - /// A cancel targeting a DIFFERENT parent must not flag this setup: it parks - /// normally and resolves via its own child terminal. - #[tokio::test] - async fn parent_cancel_for_other_parent_leaves_setup_intact() { - let mock = Arc::new(MockSpawner::new()); - mock.queue_spawn(Ok("c8".into())).await; - mock.queue_send(Ok(88)).await; - let release = mock.install_send_gate().await; - let broker = - DelegationBroker::new(mock.clone() as Arc, shallow_lookup()); - enable_delegation(&broker).await; - - let driver = { - let broker = broker.clone(); - tokio::spawn(async move { broker.handle_request(request(1, "pt-8")).await }) - }; - loop { - if broker.reserved_child_count().await == 1 { - break; - } - tokio::time::sleep(Duration::from_millis(5)).await; - } - // Wrong-parent cancel — a no-op for this setup. - broker.cancel_by_parent_turn("some-other-parent").await; - let _ = release.send(()); - - // It must park normally; resolve it via its child completion. - let parked = loop { - if let Some(id) = broker.peek_first_pending_call_id().await { - break id; - } - tokio::time::sleep(Duration::from_millis(5)).await; - }; - broker - .complete_call( - &parked, - DelegationOutcome::Ok(DelegationSuccess { - text: "fine".into(), - child_conversation_id: 88, - child_agent_type: AgentType::ClaudeCode, - turn_count: 1, - duration_ms: 5, - token_usage: None, - }), - ) - .await; - assert!(matches!(driver.await.unwrap(), DelegationOutcome::Ok(_))); - assert!( - mock.cancels.lock().await.is_empty(), - "a wrong-parent cancel must not tear this child down" - ); - assert_eq!(broker.inflight_count().await, 0); - } - - /// The in-flight record is deregistered on every exit path: the normal park - /// hand-off, and each early-return (disabled / spawn-fail / send-fail). - #[tokio::test] - async fn inflight_drained_on_normal_park() { - let mock = Arc::new(MockSpawner::new()); - mock.queue_spawn(Ok("c-ok".into())).await; - mock.queue_send(Ok(70)).await; - let broker = - DelegationBroker::new(mock.clone() as Arc, shallow_lookup()); - enable_delegation(&broker).await; - let driver = { - let broker = broker.clone(); - tokio::spawn(async move { broker.handle_request(request(1, "pt-ok")).await }) - }; - let call_id = loop { - if let Some(id) = broker.peek_first_pending_call_id().await { - break id; - } - tokio::time::sleep(Duration::from_millis(5)).await; - }; - // Parked → the in-flight record was handed off (deregistered) at park. - assert_eq!( - broker.inflight_count().await, - 0, - "park deregisters in-flight" - ); - broker - .complete_call( - &call_id, - DelegationOutcome::Ok(DelegationSuccess { - text: "ok".into(), - child_conversation_id: 70, - child_agent_type: AgentType::ClaudeCode, - turn_count: 1, - duration_ms: 5, - token_usage: None, - }), - ) - .await; - assert!(matches!(driver.await.unwrap(), DelegationOutcome::Ok(_))); - assert_eq!(broker.inflight_count().await, 0); - } - - #[tokio::test] - async fn inflight_drained_on_disabled() { - let broker = DelegationBroker::new( - Arc::new(MockSpawner::new()) as Arc, - shallow_lookup(), - ); - // `enabled` defaults to false → short-circuits at the disabled check. - let outcome = broker.handle_request(request(1, "pt-d")).await; - assert!(matches!(outcome, DelegationOutcome::Err { .. })); - assert_eq!(broker.inflight_count().await, 0); - } - - #[tokio::test] - async fn inflight_drained_on_spawn_failure() { - let mock = Arc::new(MockSpawner::new()); - mock.queue_spawn(Err(SpawnerError::Spawn("nope".into()))) - .await; - let broker = - DelegationBroker::new(mock.clone() as Arc, shallow_lookup()); - enable_delegation(&broker).await; - match broker.handle_request(request(1, "pt-sf")).await { - DelegationOutcome::Err { code, .. } => assert_eq!(code, "spawn_failed"), - other => panic!("expected spawn_failed, got {other:?}"), - } - assert_eq!(broker.inflight_count().await, 0); - assert!(mock.disconnects.lock().await.is_empty()); - } - - #[tokio::test] - async fn inflight_drained_on_send_failure() { - let mock = Arc::new(MockSpawner::new()); - mock.queue_spawn(Ok("c6".into())).await; - mock.queue_send(Err(SpawnerError::Send("boom".into()))) - .await; - let broker = - DelegationBroker::new(mock.clone() as Arc, shallow_lookup()); - enable_delegation(&broker).await; - match broker.handle_request(request(1, "pt-sendf")).await { - DelegationOutcome::Err { code, .. } => assert_eq!(code, "spawn_failed"), - other => panic!("expected spawn_failed, got {other:?}"), - } - assert_eq!(broker.inflight_count().await, 0); - assert_eq!(mock.disconnects.lock().await.as_slice(), &["c6"]); - assert!(mock.cancels.lock().await.is_empty()); - } - - /// A terminal failure for a child the broker never reserved (unknown id, or - /// one whose delegation already fully resolved) is a clean no-op — it must - /// not buffer, so the buffer can only ever hold genuine pre-registration - /// races. - #[tokio::test] - async fn cancel_for_unreserved_child_never_buffers() { - let broker = DelegationBroker::new( - Arc::new(MockSpawner::new()) as Arc, - shallow_lookup(), - ); - broker - .cancel_by_child_connection("never-reserved", Some("boom")) - .await; - assert_eq!(broker.early_cancel_count().await, 0); - assert_eq!(broker.pending_count().await, 0); - } - - #[tokio::test] - async fn meta_writer_records_failed_on_parent_cancel() { - let mock = Arc::new(MockSpawner::new()); - mock.queue_spawn(Ok("c-cancel".into())).await; - mock.queue_send(Ok(33)).await; - let writer = Arc::new(MockMetaWriter::new()); - let broker = broker_with_meta(mock.clone(), writer.clone()).await; - - let driver = { - let broker = broker.clone(); - tokio::spawn(async move { broker.handle_request(request(1, "pt-pcancel")).await }) - }; - while broker.pending_count().await == 0 { - tokio::time::sleep(Duration::from_millis(5)).await; - } - broker.cancel_by_parent("parent-conn").await; - let outcome = driver.await.unwrap(); - assert!(matches!(outcome, DelegationOutcome::Err { .. })); - - let calls = writer.snapshot().await; - // running + canceled - assert_eq!(calls.len(), 2); - let inner = calls[1] - .meta - .get("codeg.delegation") - .unwrap() - .as_object() - .unwrap(); - assert_eq!(inner.get("status").unwrap().as_str().unwrap(), "failed"); - assert_eq!( - inner.get("error_code").unwrap().as_str().unwrap(), - "canceled" - ); - } - - #[tokio::test] - async fn meta_writer_skipped_for_synthetic_parent_tool_use_id() { - let mock = Arc::new(MockSpawner::new()); - mock.queue_spawn(Ok("c-synth".into())).await; - mock.queue_send(Ok(8)).await; - let writer = Arc::new(MockMetaWriter::new()); - let broker = broker_with_meta(mock.clone(), writer.clone()).await; - - // Empty `parent_tool_use_id` triggers the broker's UUID fallback — - // `"delegation-"` — which the writer must skip because no - // matching ACP tool_call_id exists. - let driver = { - let broker = broker.clone(); - tokio::spawn(async move { broker.handle_request(request(1, "")).await }) - }; - let call_id = loop { - if let Some(id) = broker.peek_first_pending_call_id().await { - break id; - } - tokio::time::sleep(Duration::from_millis(5)).await; - }; - broker - .complete_call( - &call_id, - DelegationOutcome::Ok(DelegationSuccess { - text: "ok".into(), - child_conversation_id: 8, - child_agent_type: AgentType::Codex, - turn_count: 1, - duration_ms: 5, - token_usage: None, - }), - ) - .await; - driver.await.unwrap(); - - let calls = writer.snapshot().await; - assert!( - calls.is_empty(), - "writer should be skipped for synthetic parent_tool_use_id, got {:?}", - calls - ); - } - - // -- Event emitter lifecycle ------------------------------------------ - // - // Issue: `.docs/issues/2026-05-24-delegation-termination-cascade.md`. - // The broker must emit `AcpEvent::DelegationCompleted` once per drained - // pending entry, regardless of which terminal path drained it (happy - // `complete_call`, MCP `cancel_by_external_handle`, child-disconnect - // cleanup, or parent-cancel cascade). Without these emits the frontend's live - // delegation binding stays at "running" forever — see the issue doc - // for the full path matrix. - - use crate::acp::delegation::event_emitter::mock::MockEventEmitter; - use crate::acp::delegation::event_emitter::DelegationEventEmitter; - use crate::acp::types::DelegationResultSummary; - - async fn broker_with_emitter( - mock: Arc, - writer: Arc, - emitter: Arc, - ) -> DelegationBroker { - let broker = DelegationBroker::with_writers( - mock as Arc, - shallow_lookup(), - writer as Arc, - emitter as Arc, - ); - enable_delegation(&broker).await; - broker - } - - #[tokio::test] - async fn emitter_records_ok_on_complete_call_happy_path() { - let mock = Arc::new(MockSpawner::new()); - mock.queue_spawn(Ok("child-conn-1".into())).await; - mock.queue_send(Ok(42)).await; - let writer = Arc::new(MockMetaWriter::new()); - let emitter = Arc::new(MockEventEmitter::new()); - let broker = broker_with_emitter(mock.clone(), writer.clone(), emitter.clone()).await; - - let driver = { - let broker = broker.clone(); - tokio::spawn(async move { broker.handle_request(request(1, "pt-ok")).await }) - }; - let call_id = loop { - if let Some(id) = broker.peek_first_pending_call_id().await { - break id; - } - tokio::time::sleep(Duration::from_millis(5)).await; - }; - broker - .complete_call( - &call_id, - DelegationOutcome::Ok(DelegationSuccess { - text: "done".into(), - child_conversation_id: 42, - child_agent_type: AgentType::ClaudeCode, - turn_count: 1, - duration_ms: 73, - token_usage: None, - }), - ) - .await; - driver.await.unwrap(); - - let calls = emitter.snapshot().await; - assert_eq!(calls.len(), 1); - let call = &calls[0]; - assert_eq!(call.parent_tool_use_id, "pt-ok"); - assert_eq!(call.child_connection_id, "child-conn-1"); - assert_eq!(call.child_conversation_id, 42); - // The completed event carries the child agent_type (from the running - // task), so a frontend that missed `DelegationStarted` still binds the - // correct agent. `request()` delegates to ClaudeCode. - assert_eq!(call.agent_type, AgentType::ClaudeCode); - // duration_ms is now broker-measured (not the outcome's value); assert - // the Ok variant + the enriched text_preview instead. - assert!( - matches!( - &call.result, - DelegationResultSummary::Ok { text_preview, .. } - if text_preview.as_deref() == Some("done") - ), - "expected Ok with preview, got {:?}", - call.result - ); - } - - #[tokio::test] - async fn emitter_records_started_on_start_delegation_happy_path() { - let mock = Arc::new(MockSpawner::new()); - mock.queue_spawn(Ok("child-conn-start".into())).await; - mock.queue_send(Ok(55)).await; - let writer = Arc::new(MockMetaWriter::new()); - let emitter = Arc::new(MockEventEmitter::new()); - let broker = broker_with_emitter(mock.clone(), writer.clone(), emitter.clone()).await; - - let driver = { - let broker = broker.clone(); - tokio::spawn(async move { broker.handle_request(request(1, "pt-start")).await }) - }; - let call_id = loop { - if let Some(id) = broker.peek_first_pending_call_id().await { - break id; - } - tokio::time::sleep(Duration::from_millis(5)).await; - }; - - // `started` fires during setup, BEFORE the task parks — so it is already - // recorded by the time a pending entry is visible, and it must not be - // conflated with the (not-yet-emitted) terminal. - let started = emitter.started_snapshot().await; - assert_eq!(started.len(), 1, "exactly one DelegationStarted per task"); - let s = &started[0]; - assert_eq!(s.parent_connection_id, "parent-conn"); - assert_eq!(s.parent_tool_use_id, "pt-start"); - assert_eq!(s.child_connection_id, "child-conn-start"); - assert_eq!(s.child_conversation_id, 55); - assert_eq!(s.agent_type, AgentType::ClaudeCode); - assert_eq!( - emitter.count().await, - 0, - "no terminal emit before completion" - ); - - broker - .complete_call( - &call_id, - DelegationOutcome::Ok(DelegationSuccess { - text: "done".into(), - child_conversation_id: 55, - child_agent_type: AgentType::ClaudeCode, - turn_count: 1, - duration_ms: 10, - token_usage: None, - }), - ) - .await; - driver.await.unwrap(); - - // Completion adds exactly one terminal emit; started stays at 1. - assert_eq!(emitter.started_count().await, 1); - assert_eq!(emitter.count().await, 1); - } - - #[tokio::test] - async fn emitter_skips_started_for_synthetic_parent_tool_use_id() { - let mock = Arc::new(MockSpawner::new()); - mock.queue_spawn(Ok("c-synth-start".into())).await; - mock.queue_send(Ok(9)).await; - let writer = Arc::new(MockMetaWriter::new()); - let emitter = Arc::new(MockEventEmitter::new()); - let broker = broker_with_emitter(mock.clone(), writer.clone(), emitter.clone()).await; - - // Empty parent_tool_use_id → broker falls back to a synthetic - // `delegation-` id (no ACP tool_call to claim in a mock harness). - let driver = { - let broker = broker.clone(); - tokio::spawn(async move { broker.handle_request(request(1, "")).await }) - }; - let call_id = loop { - if let Some(id) = broker.peek_first_pending_call_id().await { - break id; - } - tokio::time::sleep(Duration::from_millis(5)).await; - }; - broker - .complete_call( - &call_id, - DelegationOutcome::Ok(DelegationSuccess { - text: "ok".into(), - child_conversation_id: 9, - child_agent_type: AgentType::Codex, - turn_count: 1, - duration_ms: 5, - token_usage: None, - }), - ) - .await; - driver.await.unwrap(); - - assert_eq!( - emitter.started_count().await, - 0, - "started emit must skip synthetic parent_tool_use_id (same rule as the meta writer / completed emit)" - ); - } - - #[tokio::test] - async fn emitter_records_err_on_complete_call_err_outcome() { - let mock = Arc::new(MockSpawner::new()); - mock.queue_spawn(Ok("child-conn-err".into())).await; - mock.queue_send(Ok(11)).await; - let writer = Arc::new(MockMetaWriter::new()); - let emitter = Arc::new(MockEventEmitter::new()); - let broker = broker_with_emitter(mock.clone(), writer.clone(), emitter.clone()).await; - - let driver = { - let broker = broker.clone(); - tokio::spawn(async move { broker.handle_request(request(1, "pt-err")).await }) - }; - let call_id = loop { - if let Some(id) = broker.peek_first_pending_call_id().await { - break id; - } - tokio::time::sleep(Duration::from_millis(5)).await; - }; - broker - .complete_call( - &call_id, - DelegationOutcome::from_err( - DelegationError::SubagentRuntimeError("agent died".into()), - Some(11), - ), - ) - .await; - driver.await.unwrap(); - - let calls = emitter.snapshot().await; - assert_eq!(calls.len(), 1); - match &calls[0].result { - DelegationResultSummary::Err { error_code } => { - assert_eq!(error_code, "subagent_error") - } - other => panic!("expected Err, got {other:?}"), - } - } - - #[tokio::test] - async fn emitter_records_canceled_on_cancel_by_external_handle() { - // MCP-driven cancel path: companion received notifications/cancelled - // and the listener forwarded it to broker.cancel_by_external_handle. - // The broker must drain the pending entry, cancel + disconnect the - // child, and emit DelegationCompleted with error_code = "canceled". - let mock = Arc::new(MockSpawner::new()); - mock.queue_spawn(Ok("child-conn-h".into())).await; - mock.queue_send(Ok(91)).await; - let writer = Arc::new(MockMetaWriter::new()); - let emitter = Arc::new(MockEventEmitter::new()); - let broker = broker_with_emitter(mock.clone(), writer.clone(), emitter.clone()).await; - - let driver = { - let broker = broker.clone(); - tokio::spawn(async move { - broker - .handle_request(request_with_handle(1, "pt-mcp-cancel", "h-1")) - .await - }) - }; - while broker.pending_count().await == 0 { - tokio::time::sleep(Duration::from_millis(5)).await; - } - broker - .cancel_by_external_handle("h-1", "user requested".into()) - .await; - let outcome = driver.await.unwrap(); - assert!(matches!( - outcome, - DelegationOutcome::Err { ref code, .. } if code == "canceled" - )); - - assert_eq!(mock.cancels.lock().await.as_slice(), &["child-conn-h"]); - let calls = emitter.snapshot().await; - assert_eq!(calls.len(), 1, "expected exactly one emit, got {calls:?}"); - let call = &calls[0]; - assert_eq!(call.parent_tool_use_id, "pt-mcp-cancel"); - assert_eq!(call.child_connection_id, "child-conn-h"); - assert_eq!(call.child_conversation_id, 91); - match &call.result { - DelegationResultSummary::Err { error_code } => { - assert_eq!(error_code, "canceled") - } - other => panic!("expected Err{{canceled}}, got {other:?}"), - } - } - - #[tokio::test] - async fn cancel_by_external_handle_no_match_buffers_pre_cancel() { - // Cancel arrives before handle_request reaches pending registration. - // The broker must buffer the handle in pre_canceled_handles so the - // in-flight call drains itself on its post-registration checkpoint. - let mock = Arc::new(MockSpawner::new()); - mock.queue_spawn(Ok("child-conn-pre".into())).await; - mock.queue_send(Ok(13)).await; - let writer = Arc::new(MockMetaWriter::new()); - let emitter = Arc::new(MockEventEmitter::new()); - let broker = broker_with_emitter(mock.clone(), writer.clone(), emitter.clone()).await; - - // Pre-cancel before spawning the driver — handle is unknown to the - // broker right now, but a buffered entry should make the next - // handle_request with the same handle bail out canceled. - broker - .cancel_by_external_handle("h-pre", "early cancel".into()) - .await; - // Pre-cancel set is single-shot: a second call with the same handle - // and no pending entry just buffers it again (idempotent in practice). - let outcome = broker - .handle_request(request_with_handle(1, "pt-pre", "h-pre")) - .await; - match outcome { - DelegationOutcome::Err { code, .. } => assert_eq!(code, "canceled"), - other => panic!("expected canceled, got {other:?}"), - } - // Since the cancel won pre-spawn, no child connection should have - // been opened. - assert!(mock.cancels.lock().await.is_empty()); - assert!(mock.disconnects.lock().await.is_empty()); - // The pre-cancel early-return must also drop the in-flight record - // (registered as handle_request's first statement, before this check). - assert_eq!(broker.inflight_count().await, 0); - } - - /// The real MCP-shaped path carries an `external_handle`. Registration now - /// happens as `handle_request`'s FIRST statement — before the pre-cancel - /// `.await` — so a parent cancel in the setup window reaches these requests - /// too, not just the synthetic-id path. Guards the regression Codex flagged - /// (registration ordered after the pre-cancel await left a miss window). - #[tokio::test] - async fn parent_cancel_covers_external_handle_setup_window() { - let mock = Arc::new(MockSpawner::new()); - mock.queue_spawn(Ok("c-eh".into())).await; - mock.queue_send(Ok(21)).await; - let release = mock.install_send_gate().await; - let broker = - DelegationBroker::new(mock.clone() as Arc, shallow_lookup()); - enable_delegation(&broker).await; - - let driver = { - let broker = broker.clone(); - tokio::spawn(async move { - broker - .handle_request(request_with_handle(1, "pt-eh", "h-eh")) - .await - }) - }; - loop { - if broker.reserved_child_count().await == 1 { - break; - } - tokio::time::sleep(Duration::from_millis(5)).await; - } - assert_eq!(broker.inflight_count().await, 1); - - broker.cancel_by_parent_turn("parent-conn").await; - let _ = release.send(()); - - match driver.await.unwrap() { - DelegationOutcome::Err { code, .. } => assert_eq!(code, "canceled"), - other => panic!("expected canceled, got {other:?}"), - } - assert_eq!(mock.cancels.lock().await.as_slice(), &["c-eh"]); - assert_eq!(mock.disconnects.lock().await.as_slice(), &["c-eh"]); - assert_eq!(broker.inflight_count().await, 0); - } - - #[tokio::test] - async fn emitter_records_canceled_on_cancel_by_child_connection() { - let mock = Arc::new(MockSpawner::new()); - mock.queue_spawn(Ok("c-dropped".into())).await; - mock.queue_send(Ok(55)).await; - let writer = Arc::new(MockMetaWriter::new()); - let emitter = Arc::new(MockEventEmitter::new()); - let broker = broker_with_emitter(mock.clone(), writer.clone(), emitter.clone()).await; - - let driver = { - let broker = broker.clone(); - tokio::spawn(async move { broker.handle_request(request(1, "pt-cbc")).await }) - }; - while broker.pending_count().await == 0 { - tokio::time::sleep(Duration::from_millis(5)).await; - } - broker.cancel_by_child_connection("c-dropped", None).await; - let outcome = driver.await.unwrap(); - match &outcome { - DelegationOutcome::Err { code, message, .. } => { - assert_eq!(code, "canceled"); - // No terminal_error supplied → falls back to default reason. - assert_eq!( - message, - "canceled: child session ended without TurnComplete" - ); - } - other => panic!("expected Err{{canceled}}, got {other:?}"), - } - - let calls = emitter.snapshot().await; - assert_eq!(calls.len(), 1); - match &calls[0].result { - DelegationResultSummary::Err { error_code } => { - assert_eq!(error_code, "canceled") - } - other => panic!("expected Err{{canceled}}, got {other:?}"), - } - } - - #[tokio::test] - async fn cancel_by_child_connection_threads_terminal_error_into_reason() { - // The lifecycle worker forwards the child's last AcpEvent::Error - // detail through `cancel_by_child_connection`. The broker stitches it - // into the `Canceled { reason }` message so the parent's - // `delegate_to_agent` tool-call result surfaces the real failure - // cause (e.g. Gemini OAuth expired) instead of the opaque default. - let mock = Arc::new(MockSpawner::new()); - mock.queue_spawn(Ok("c-auth".into())).await; - mock.queue_send(Ok(77)).await; - let writer = Arc::new(MockMetaWriter::new()); - let emitter = Arc::new(MockEventEmitter::new()); - let broker = broker_with_emitter(mock.clone(), writer.clone(), emitter.clone()).await; - - let driver = { - let broker = broker.clone(); - tokio::spawn(async move { broker.handle_request(request(1, "pt-auth")).await }) - }; - while broker.pending_count().await == 0 { - tokio::time::sleep(Duration::from_millis(5)).await; - } - broker - .cancel_by_child_connection("c-auth", Some("[auth_required] Authentication required")) - .await; - let outcome = driver.await.unwrap(); - match &outcome { - DelegationOutcome::Err { code, message, .. } => { - assert_eq!(code, "canceled"); - assert_eq!( - message, - "canceled: child session ended without TurnComplete: \ - [auth_required] Authentication required" - ); - } - other => panic!("expected Err{{canceled}}, got {other:?}"), - } - } - - #[tokio::test] - async fn cancel_by_child_connection_ignores_empty_terminal_error() { - // Whitespace-only or empty detail strings shouldn't produce a - // dangling "...:" suffix on the reason — fall back to the default. - let mock = Arc::new(MockSpawner::new()); - mock.queue_spawn(Ok("c-empty".into())).await; - mock.queue_send(Ok(78)).await; - let broker = - DelegationBroker::new(mock.clone() as Arc, shallow_lookup()); - enable_delegation(&broker).await; - - let driver = { - let broker = broker.clone(); - tokio::spawn(async move { broker.handle_request(request(1, "pt-empty")).await }) - }; - while broker.pending_count().await == 0 { - tokio::time::sleep(Duration::from_millis(5)).await; - } - broker - .cancel_by_child_connection("c-empty", Some(" ")) - .await; - let outcome = driver.await.unwrap(); - match &outcome { - DelegationOutcome::Err { message, .. } => { - assert_eq!( - message, - "canceled: child session ended without TurnComplete" - ); - } - other => panic!("expected Err, got {other:?}"), - } - } - - #[tokio::test] - async fn emitter_records_one_event_per_drained_entry_on_cancel_by_parent() { - let mock = Arc::new(MockSpawner::new()); - for i in 0..3 { - mock.queue_spawn(Ok(format!("c{i}"))).await; - mock.queue_send(Ok(100 + i)).await; - } - let writer = Arc::new(MockMetaWriter::new()); - let emitter = Arc::new(MockEventEmitter::new()); - let broker = broker_with_emitter(mock.clone(), writer.clone(), emitter.clone()).await; - - let mut handles = Vec::new(); - for i in 0..3 { - let broker = broker.clone(); - handles.push(tokio::spawn(async move { - broker.handle_request(request(1, &format!("pt-{i}"))).await - })); - } - while broker.pending_count().await < 3 { - tokio::time::sleep(Duration::from_millis(5)).await; - } - broker.cancel_by_parent("parent-conn").await; - for h in handles { - let _ = h.await.unwrap(); - } - - let calls = emitter.snapshot().await; - assert_eq!(calls.len(), 3, "expected 3 emits, got {calls:?}"); - let mut parent_tool_use_ids: Vec = - calls.iter().map(|c| c.parent_tool_use_id.clone()).collect(); - parent_tool_use_ids.sort(); - assert_eq!( - parent_tool_use_ids, - vec!["pt-0".to_string(), "pt-1".to_string(), "pt-2".to_string()] - ); - for call in &calls { - match &call.result { - DelegationResultSummary::Err { error_code } => { - assert_eq!(error_code, "canceled") - } - other => panic!("expected Err{{canceled}}, got {other:?}"), - } - } - } - - #[tokio::test] - async fn emitter_does_not_double_emit_on_repeat_cancel_by_parent() { - let mock = Arc::new(MockSpawner::new()); - mock.queue_spawn(Ok("c-once".into())).await; - mock.queue_send(Ok(42)).await; - let writer = Arc::new(MockMetaWriter::new()); - let emitter = Arc::new(MockEventEmitter::new()); - let broker = broker_with_emitter(mock.clone(), writer.clone(), emitter.clone()).await; - - let driver = { - let broker = broker.clone(); - tokio::spawn(async move { broker.handle_request(request(1, "pt-idem")).await }) - }; - while broker.pending_count().await == 0 { - tokio::time::sleep(Duration::from_millis(5)).await; - } - // First call drains the entry + emits one. - broker.cancel_by_parent("parent-conn").await; - // Second call finds the pending map empty — no extra emit. - broker.cancel_by_parent("parent-conn").await; - // Cleanup-guard-style triple call also stays bounded. - broker.cancel_by_parent("parent-conn").await; - let _ = driver.await.unwrap(); - - assert_eq!(emitter.count().await, 1); - } - - #[tokio::test] - async fn emitter_skipped_for_synthetic_parent_tool_use_id() { - let mock = Arc::new(MockSpawner::new()); - mock.queue_spawn(Ok("c-synth".into())).await; - mock.queue_send(Ok(8)).await; - let writer = Arc::new(MockMetaWriter::new()); - let emitter = Arc::new(MockEventEmitter::new()); - let broker = broker_with_emitter(mock.clone(), writer.clone(), emitter.clone()).await; - - let driver = { - let broker = broker.clone(); - tokio::spawn(async move { broker.handle_request(request(1, "")).await }) - }; - let call_id = loop { - if let Some(id) = broker.peek_first_pending_call_id().await { - break id; - } - tokio::time::sleep(Duration::from_millis(5)).await; - }; - broker - .complete_call( - &call_id, - DelegationOutcome::Ok(DelegationSuccess { - text: "ok".into(), - child_conversation_id: 8, - child_agent_type: AgentType::Codex, - turn_count: 1, - duration_ms: 5, - token_usage: None, - }), - ) - .await; - driver.await.unwrap(); - - let calls = emitter.snapshot().await; - assert!( - calls.is_empty(), - "emitter must skip synthetic parent_tool_use_id (same rule as meta writer); got {calls:?}" - ); - } - - #[tokio::test] - async fn emitter_records_after_meta_write_on_complete_call() { - // Frontend's snapshot-recovery path reads `meta["codeg.delegation"]` - // first and the live event second; if the emit lands before the - // meta write, a snapshot taken between them would see "running" - // meta paired with a "completed" event. Enforce meta-before-emit - // by checking the MockMetaWriter has at least one call before the - // emitter records. - let mock = Arc::new(MockSpawner::new()); - mock.queue_spawn(Ok("c-order".into())).await; - mock.queue_send(Ok(7)).await; - let writer = Arc::new(MockMetaWriter::new()); - let emitter = Arc::new(MockEventEmitter::new()); - let broker = broker_with_emitter(mock.clone(), writer.clone(), emitter.clone()).await; - - let driver = { - let broker = broker.clone(); - tokio::spawn(async move { broker.handle_request(request(1, "pt-order")).await }) - }; - let call_id = loop { - if let Some(id) = broker.peek_first_pending_call_id().await { - break id; - } - tokio::time::sleep(Duration::from_millis(5)).await; - }; - broker - .complete_call( - &call_id, - DelegationOutcome::Ok(DelegationSuccess { - text: "ok".into(), - child_conversation_id: 7, - child_agent_type: AgentType::ClaudeCode, - turn_count: 1, - duration_ms: 5, - token_usage: None, - }), - ) - .await; - driver.await.unwrap(); - - let meta_calls = writer.snapshot().await; - let event_calls = emitter.snapshot().await; - // running (from handle_request) + completed (from complete_call) = - // 2 meta writes. The single event must be the "completed" one, - // and it must land AFTER the running meta — guaranteed structurally - // by complete_call's order (write_meta_if_real then emit). - assert_eq!(meta_calls.len(), 2); - assert_eq!(event_calls.len(), 1); - let inner_second = meta_calls[1] - .meta - .get("codeg.delegation") - .unwrap() - .as_object() - .unwrap(); - assert_eq!( - inner_second.get("status").unwrap().as_str().unwrap(), - "completed" - ); - } - - // -- Production-path fanout coverage ---------------------------------- - // - // Every other emitter test in this module uses `MockEventEmitter`. The - // production wiring goes through `ConnectionManagerEventEmitter`, which - // resolves `(state, emitter)` against the live `ConnectionManager` and - // hands the event to `emit_with_state` so it fans out to (1) the parent - // connection's `ConnectionEventStream` (the WS attach path) and (2) the - // `InternalEventBus` (the lifecycle/pet/chat-channel subscriber path). - // These tests exercise that real fanout end-to-end so a regression in - // `get_state_and_emitter` lookup, `emit_with_state` routing, or the - // `EventEmitter::WebOnly { bus, .. }` wiring is caught here even when - // every mock-backed test stays green. - - #[tokio::test] - async fn real_emitter_fans_out_delegation_completed_to_parent_stream_and_bus() { - use crate::acp::delegation::event_emitter::ConnectionManagerEventEmitter; - use crate::acp::manager::ConnectionManager; - use crate::acp::types::AcpEvent; - use crate::web::event_bridge::{EventEmitter, WebEventBroadcaster}; - - // Real ConnectionManager + fake parent wired to a WebOnly emitter so - // the InternalEventBus gets typed envelopes and we can subscribe to - // verify the lifecycle-path delivery alongside the per-connection - // stream delivery. - let manager = ConnectionManager::new(); - let broadcaster = Arc::new(WebEventBroadcaster::new()); - let parent_emitter = EventEmitter::test_web_only(broadcaster); - let bus = parent_emitter - .acp_event_bus() - .expect("WebOnly emitter must expose an InternalEventBus"); - manager - .insert_test_connection("parent-conn", AgentType::ClaudeCode, None, parent_emitter) - .await; - - // Subscribe BEFORE triggering events — broadcast channels drop - // sends that happen with no receivers registered. - let mut bus_rx = bus.subscribe(); - let (parent_state, _) = manager - .get_state_and_emitter("parent-conn") - .await - .expect("parent just inserted"); - let mut stream_rx = parent_state.read().await.event_stream().subscribe(); - - // Build the broker with the PRODUCTION emitter; meta writer can stay - // noop because this test is asserting the event-fanout invariant. - let mock_spawner = Arc::new(MockSpawner::new()); - mock_spawner.queue_spawn(Ok("child-conn-real".into())).await; - mock_spawner.queue_send(Ok(77)).await; - let real_emitter = Arc::new(ConnectionManagerEventEmitter { - manager: Arc::new(manager.clone_ref()), - }); - let broker = DelegationBroker::with_writers( - mock_spawner.clone() as Arc, - shallow_lookup(), - Arc::new(crate::acp::delegation::meta_writer::NoopMetaWriter) - as Arc, - real_emitter as Arc, - ); - enable_delegation(&broker).await; - - // Park a pending entry then trigger cancel_by_parent to drive the - // production emit path. `request()` hard-codes parent_connection_id - // = "parent-conn" which matches the insert above. - let driver = { - let broker = broker.clone(); - tokio::spawn(async move { broker.handle_request(request(1, "pt-fanout")).await }) - }; - while broker.pending_count().await == 0 { - tokio::time::sleep(Duration::from_millis(5)).await; - } - broker.cancel_by_parent("parent-conn").await; - let _ = driver.await.unwrap(); - - // Per-connection stream (WS attach delivery path) must receive the - // envelope tagged with the right connection + payload shape. - // The parent stream now also carries the setup-time DelegationStarted; - // skip past it to the terminal DelegationCompleted. - let envelope = loop { - let env = tokio::time::timeout(Duration::from_millis(500), stream_rx.recv()) - .await - .expect("per-connection stream should receive DelegationCompleted within 500ms") - .expect("envelope recv must not error"); - if matches!(env.payload, AcpEvent::DelegationStarted { .. }) { - continue; - } - break env; - }; - assert_eq!(envelope.connection_id, "parent-conn"); - match &envelope.payload { - AcpEvent::DelegationCompleted { - parent_tool_use_id, - child_connection_id, - child_conversation_id, - result, - .. - } => { - assert_eq!(parent_tool_use_id, "pt-fanout"); - assert_eq!(child_connection_id, "child-conn-real"); - assert_eq!(*child_conversation_id, 77); - match result { - DelegationResultSummary::Err { error_code } => { - assert_eq!(error_code, "canceled"); - } - other => panic!("expected Err{{canceled}}, got {other:?}"), - } - } - other => panic!("expected DelegationCompleted, got {other:?}"), - } - - // InternalEventBus (lifecycle/pet/chat-channel subscriber path) must - // also receive the same envelope — proves the WebOnly emitter's bus - // arm in `emit_with_state` is reached. - let bus_envelope = loop { - let env = tokio::time::timeout(Duration::from_millis(500), bus_rx.recv()) - .await - .expect("InternalEventBus should receive DelegationCompleted within 500ms") - .expect("bus recv must not error"); - if matches!(env.payload, AcpEvent::DelegationStarted { .. }) { - continue; - } - break env; - }; - assert_eq!(bus_envelope.connection_id, "parent-conn"); - assert!(matches!( - bus_envelope.payload, - AcpEvent::DelegationCompleted { .. } - )); - } - - #[tokio::test] - async fn real_emitter_fans_out_delegation_started_to_parent_stream_and_bus() { - use crate::acp::delegation::event_emitter::ConnectionManagerEventEmitter; - use crate::acp::manager::ConnectionManager; - use crate::acp::types::AcpEvent; - use crate::web::event_bridge::{EventEmitter, WebEventBroadcaster}; - - // Web/server delivery shape: a real ConnectionManager + a fake parent on - // a WebOnly emitter. `DelegationStarted` must land on the PARENT's - // per-connection stream (the WS attach path the frontend subscribes to - // in web/server mode) AND the InternalEventBus — mirroring the - // completed-path invariant. This is the regression lock for the - // web-mode live-delegation gap: before moving the emit to the parent - // stream, started rode the (un-attached) child stream and was lost here. - let manager = ConnectionManager::new(); - let broadcaster = Arc::new(WebEventBroadcaster::new()); - let parent_emitter = EventEmitter::test_web_only(broadcaster); - let bus = parent_emitter - .acp_event_bus() - .expect("WebOnly emitter must expose an InternalEventBus"); - manager - .insert_test_connection("parent-conn", AgentType::ClaudeCode, None, parent_emitter) - .await; - - // Subscribe BEFORE triggering events — broadcast channels drop sends - // that happen with no receivers registered. - let mut bus_rx = bus.subscribe(); - let (parent_state, _) = manager - .get_state_and_emitter("parent-conn") - .await - .expect("parent just inserted"); - let mut stream_rx = parent_state.read().await.event_stream().subscribe(); - - let mock_spawner = Arc::new(MockSpawner::new()); - mock_spawner - .queue_spawn(Ok("child-conn-started".into())) - .await; - mock_spawner.queue_send(Ok(88)).await; - let real_emitter = Arc::new(ConnectionManagerEventEmitter { - manager: Arc::new(manager.clone_ref()), - }); - let broker = DelegationBroker::with_writers( - mock_spawner.clone() as Arc, - shallow_lookup(), - Arc::new(crate::acp::delegation::meta_writer::NoopMetaWriter) - as Arc, - real_emitter as Arc, - ); - enable_delegation(&broker).await; - - // `started` fires during setup, before park — drive the request, wait - // for it to park, then assert the envelope already arrived. - let driver = { - let broker = broker.clone(); - tokio::spawn(async move { broker.handle_request(request(1, "pt-started")).await }) - }; - while broker.pending_count().await == 0 { - tokio::time::sleep(Duration::from_millis(5)).await; - } - - let envelope = tokio::time::timeout(Duration::from_millis(500), stream_rx.recv()) - .await - .expect("per-connection stream should receive DelegationStarted within 500ms") - .expect("envelope recv must not error"); - assert_eq!(envelope.connection_id, "parent-conn"); - match &envelope.payload { - AcpEvent::DelegationStarted { - parent_connection_id, - parent_tool_use_id, - child_connection_id, - child_conversation_id, - agent_type, - task_preview, - task_id, - } => { - assert_eq!(parent_connection_id, "parent-conn"); - assert_eq!(parent_tool_use_id, "pt-started"); - assert_eq!(child_connection_id, "child-conn-started"); - assert_eq!(*child_conversation_id, 88); - assert_eq!(*agent_type, AgentType::ClaudeCode); - // The event labels the card even when the parent tool call's - // raw_input never carried the arguments (identity-less hosts). - assert_eq!(task_preview, "do x"); - assert!(!task_id.is_empty(), "broker-minted task id must ride the event"); - } - other => panic!("expected DelegationStarted, got {other:?}"), - } - - let bus_envelope = tokio::time::timeout(Duration::from_millis(500), bus_rx.recv()) - .await - .expect("InternalEventBus should receive DelegationStarted within 500ms") - .expect("bus recv must not error"); - assert_eq!(bus_envelope.connection_id, "parent-conn"); - assert!(matches!( - bus_envelope.payload, - AcpEvent::DelegationStarted { .. } - )); - - // Drain the parked driver so the test doesn't leak the spawned task. - broker.cancel_by_parent("parent-conn").await; - let _ = driver.await.unwrap(); - } - - #[tokio::test] - async fn real_emitter_is_silent_no_op_when_parent_already_detached() { - // Parent torn down mid-delegation: `get_state_and_emitter` returns - // None, the emit silently drops, BUT the broker still drains its - // pending table and surfaces the outcome to the awaiting caller. - // This is the "parent disappeared before terminal" path that the - // mock-backed tests can't observe. - use crate::acp::delegation::event_emitter::ConnectionManagerEventEmitter; - use crate::acp::manager::ConnectionManager; - - let manager = ConnectionManager::new(); - // Intentionally no insert_test_connection — parent is absent. - let real_emitter = Arc::new(ConnectionManagerEventEmitter { - manager: Arc::new(manager.clone_ref()), - }); - let mock_spawner = Arc::new(MockSpawner::new()); - mock_spawner.queue_spawn(Ok("c-orphan".into())).await; - mock_spawner.queue_send(Ok(1)).await; - let broker = DelegationBroker::with_writers( - mock_spawner.clone() as Arc, - shallow_lookup(), - Arc::new(crate::acp::delegation::meta_writer::NoopMetaWriter) - as Arc, - real_emitter as Arc, - ); - enable_delegation(&broker).await; - - let driver = { - let broker = broker.clone(); - tokio::spawn(async move { broker.handle_request(request(1, "pt-orphan")).await }) - }; - while broker.pending_count().await == 0 { - tokio::time::sleep(Duration::from_millis(5)).await; - } - broker.cancel_by_parent("parent-conn").await; - let outcome = driver.await.unwrap(); - - assert!(matches!( - outcome, - DelegationOutcome::Err { ref code, .. } if code == "canceled" - )); - assert_eq!( - broker.pending_count().await, - 0, - "broker must drain pending even when no parent exists to receive the emit" - ); - } - - // -- Async-cutover review regressions ----------------------------------- - - /// A pre-cancel that bails `start_delegation` before the claim path must - /// still drain the keyed ACP tool_call, so a later same-key delegation - /// can't claim the canceled call's id and mis-bind to the wrong card. - #[tokio::test] - async fn pre_cancel_drains_keyed_tool_call_to_avoid_misbinding() { - let broker = DelegationBroker::new( - Arc::new(MockSpawner::new()) as Arc, - shallow_lookup(), - ); - enable_delegation(&broker).await; - let key = DelegationMatchKey { - agent_type: AgentType::ClaudeCode, - task: "do x".into(), - working_dir: None, - }; - // The lifecycle registered the keyed tool_call for this delegation. - broker - .register_pending_tool_call_with_key("parent-conn", "tc-1".into(), Some(key.clone())) - .await; - // notifications/cancelled lands before the round-trip → buffered (no - // running task yet). - broker.cancel_by_external_handle("h-1", "user".into()).await; - // The MCP round-trip arrives (empty parent_tool_use_id, same key) and - // bails at the first pre-cancel check. - let report = broker - .start_delegation(request_with_handle(1, "", "h-1")) - .await; - assert_eq!(report.status, TaskStatus::Canceled); - // The keyed entry must have been drained — not claimable afterward. - assert_eq!( - broker.take_matching_tool_call("parent-conn", &key).await, - None - ); - } - - /// The running ack must carry the literal task_id in its message, so a - /// client that only surfaces MCP `content` text (not `structuredContent`) - /// can still call get_delegation_status / cancel_delegation. - #[test] - fn running_ack_message_embeds_task_id() { - let report = running_ack("task-xyz".into(), 42, AgentType::Codex); - assert_eq!(report.task_id.as_deref(), Some("task-xyz")); - assert!( - report.message.as_deref().unwrap().contains("task-xyz"), - "ack message must embed the literal task_id, got {:?}", - report.message - ); - } - - /// Previews and cached text must stay within their advertised BYTE caps - /// (including the appended ellipsis), and truncate on UTF-8 boundaries. - #[test] - fn previews_and_cached_text_respect_byte_caps() { - let preview = build_text_preview(&"x".repeat(STATUS_PREVIEW_CAP * 2)).unwrap(); - assert!( - preview.len() <= STATUS_PREVIEW_CAP, - "preview {} > cap {STATUS_PREVIEW_CAP}", - preview.len() - ); - let cached = cap_completed_text(&"y".repeat(COMPLETED_TEXT_CAP * 2)); - assert!(cached.len() <= COMPLETED_TEXT_CAP); - // Multibyte safety: 3-byte chars must not be split, and the cap holds. - let multibyte = build_text_preview(&"€".repeat(STATUS_PREVIEW_CAP)).unwrap(); - assert!(multibyte.len() <= STATUS_PREVIEW_CAP); - assert!(std::str::from_utf8(multibyte.as_bytes()).is_ok()); - } - - // -- completed-cache byte valve ---------------------------------------- - - fn completed_with_text(parent: &str, text_len: usize) -> CompletedTask { - CompletedTask { - parent_connection_id: parent.to_string(), - child_conversation_id: 1, - agent_type: AgentType::ClaudeCode, - status: TaskStatus::Completed, - text: Some("x".repeat(text_len)), - error_code: None, - message: None, - duration_ms: 0, - } - } - - #[test] - fn completed_cache_valve_evicts_oldest_over_byte_budget() { - let mut inner = PendingInner { - completed_cap_bytes: 1000, - ..Default::default() - }; - // Three 400-byte results = 1200 bytes > 1000 cap. Oldest must evict. - inner.insert_completed("a", completed_with_text("p1", 400)); - inner.insert_completed("b", completed_with_text("p1", 400)); - inner.insert_completed("c", completed_with_text("p1", 400)); - assert!(!inner.completed.contains_key("a"), "oldest must be evicted"); - assert!(inner.completed.contains_key("b")); - assert!(inner.completed.contains_key("c"), "newest must be retained"); - // Counter + order reflect only the two retained entries. - assert_eq!(inner.completed_bytes.get("p1").copied(), Some(800)); - assert_eq!(inner.completed_order.get("p1").map(|o| o.len()), Some(2)); - // Survivors keep their FULL text — the valve drops whole entries, it - // never truncates a survivor. - assert_eq!( - inner - .completed - .get("c") - .unwrap() - .text - .as_deref() - .map(str::len), - Some(400) - ); - } - - #[test] - fn completed_cache_valve_keeps_newest_even_if_alone_over_budget() { - // A single result larger than the whole budget is still retained — the - // valve never evicts the entry just inserted (the LLM's immediate - // get_delegation_status must hit). Per-result text is independently - // bounded by COMPLETED_TEXT_CAP. - let mut inner = PendingInner { - completed_cap_bytes: 100, - ..Default::default() - }; - inner.insert_completed("solo", completed_with_text("p1", 500)); - assert!(inner.completed.contains_key("solo")); - assert_eq!(inner.completed_bytes.get("p1").copied(), Some(500)); - } - - #[test] - fn completed_cache_unlimited_when_cap_zero() { - let mut inner = PendingInner::default(); // completed_cap_bytes == 0 - for i in 0..50 { - inner.insert_completed(&format!("t{i}"), completed_with_text("p1", 10_000)); - } - assert_eq!(inner.completed.len(), 50, "cap 0 disables eviction"); - assert_eq!(inner.completed_bytes.get("p1").copied(), Some(500_000)); - } - - #[test] - fn completed_cache_valve_is_per_parent() { - let mut inner = PendingInner { - completed_cap_bytes: 1000, - ..Default::default() - }; - // p1 overflows; p2 stays under its own independent budget. - inner.insert_completed("a1", completed_with_text("p1", 600)); - inner.insert_completed("a2", completed_with_text("p1", 600)); // evicts a1 - inner.insert_completed("b1", completed_with_text("p2", 600)); - assert!(!inner.completed.contains_key("a1")); - assert!(inner.completed.contains_key("a2")); - assert!( - inner.completed.contains_key("b1"), - "p2 must be untouched by p1 overflow" - ); - assert_eq!(inner.completed_bytes.get("p1").copied(), Some(600)); - assert_eq!(inner.completed_bytes.get("p2").copied(), Some(600)); - } - - #[test] - fn drop_completed_for_parent_clears_byte_counter() { - let mut inner = PendingInner::default(); // unlimited; teardown still clears - inner.insert_completed("a", completed_with_text("p1", 100)); - inner.insert_completed("b", completed_with_text("p2", 100)); - inner.drop_completed_for_parent("p1"); - assert!(!inner.completed.contains_key("a")); - assert!(inner.completed.contains_key("b")); - assert_eq!( - inner.completed_bytes.get("p1"), - None, - "byte counter must be cleared on teardown" - ); - assert_eq!(inner.completed_bytes.get("p2").copied(), Some(100)); - } - - #[tokio::test] - async fn lowering_cap_prunes_existing_completed_results() { - let broker = DelegationBroker::new( - Arc::new(MockSpawner::new()) as Arc, - shallow_lookup(), - ); - // Start unlimited and retain several results for one parent. - broker - .set_config(DelegationConfig { - completed_cache_cap_bytes: 0, - ..DelegationConfig::default() - }) - .await; - { - let mut inner = broker.pending.inner.lock().await; - for i in 0..5 { - inner.insert_completed(&format!("t{i}"), completed_with_text("p1", 400)); - } - assert_eq!(inner.completed.len(), 5); - assert_eq!(inner.completed_bytes.get("p1").copied(), Some(2000)); - } - // Lower the cap to 1000 bytes — existing results must be pruned NOW, - // not only on the next completion (which may never arrive). - broker - .set_config(DelegationConfig { - completed_cache_cap_bytes: 1000, - ..DelegationConfig::default() - }) - .await; - let inner = broker.pending.inner.lock().await; - assert!( - inner.completed_bytes.get("p1").copied().unwrap_or(0) <= 1000, - "retained bytes must fit the lowered cap" - ); - assert!( - inner.completed.contains_key("t4"), - "newest result must survive pruning" - ); - assert!( - !inner.completed.contains_key("t0"), - "oldest result must be pruned" - ); - } -} +//! `DelegationBroker` — the coordination unit for multi-agent delegation. +//! +//! Delegation is **asynchronous**: `delegate_to_agent` returns a `task_id` +//! ack as soon as setup finishes; the LLM collects the result later with +//! `get_delegation_status` (optionally long-polling) or stops it with +//! `cancel_delegation`. There is no blocking `oneshot` — a running task is just +//! an entry in the `running` map, and a terminal event migrates it into the +//! `completed` cache (atomically, under one lock) and wakes any long-poll via +//! `result_notify`. +//! +//! Lifecycle of a single task: +//! +//! 1. [`DelegationBroker::start_delegation`] is the broker's entry point. The +//! MCP listener feeds it the LLM-issued `delegate_to_agent` payload. +//! 2. Pre-checks: feature enabled? depth limit ok? Both failures return a +//! terminal report immediately, no child session created. +//! 3. Spawn the child via [`ConnectionSpawner::spawn`]. +//! 4. Send the delegation task as the first prompt via +//! [`ConnectionSpawner::send_prompt_linked_for_delegation`]. The trailing +//! [`DelegationLink`] carries the parent's `tool_use_id` and a +//! broker-internal `call_id` (UUID = `task_id`) — persisted onto the new +//! conversation row so the lifecycle resolver can find it. +//! 5. Register a [`RunningTask`] keyed by `call_id` and return a `Running` ack +//! [`DelegationTaskReport`] (or a terminal report when the child finished +//! during setup / a cancel reached it mid-setup / setup itself failed). +//! 6. Later, a terminal event resolves the task — migrating it `running` → +//! `completed` and tearing the child down: +//! - the lifecycle calling [`DelegationBroker::complete_call`] on +//! `TurnComplete` (happy path), or +//! - a cancel — MCP-side (`notifications/cancelled` → +//! [`DelegationBroker::cancel_by_external_handle`]), child-side +//! ([`DelegationBroker::cancel_by_child_connection`]), parent-side +//! ([`DelegationBroker::cancel_by_parent`] / +//! [`DelegationBroker::cancel_by_parent_turn`]), or the LLM's own +//! [`DelegationBroker::cancel_task_by_id`]. +//! +//! v1 is explicitly one-shot — no session reuse. +//! +//! Result durability: child output is NOT stored in codeg's DB, so the broker +//! caches the completed text in `completed` (parent-scoped, FIFO-capped). Once +//! evicted, [`DelegationBroker::get_task_status`] falls back to the DB for the +//! task's terminal STATUS (via [`ChildStatusLookup`]); the full output is always +//! viewable in the child's own session. +//! +//! Cancellation cascade: when a parent session goes away (user-initiated +//! cancel, parent disconnect), the lifecycle subscriber calls +//! [`DelegationBroker::cancel_by_parent`] which fans out cancel + disconnect +//! to every running child of that parent. A normal `end_turn` does NOT cancel +//! children — they keep running in the background (the whole point of async). + +use std::collections::{BTreeMap, HashMap, HashSet, VecDeque}; +use std::sync::atomic::{AtomicBool, Ordering}; +use std::sync::Arc; +use std::time::{Duration, Instant}; + +use async_trait::async_trait; +use tokio::sync::{Mutex, Notify}; + +use crate::acp::delegation::event_emitter::{DelegationEventEmitter, NoopEventEmitter}; +use crate::acp::delegation::live_reply::{ChildLiveReplyLookup, NoopChildLiveReplyLookup}; +use crate::acp::delegation::meta_writer::{ + build_delegation_meta, is_synthetic_parent_tool_use_id, DelegationMetaWriter, NoopMetaWriter, +}; +use crate::acp::delegation::spawner::{ConnectionSpawner, DelegationLink}; +use crate::acp::delegation::types::{ + AgentDelegationDefaults, BlockedKind, BlockedOn, DelegationError, DelegationOutcome, + DelegationRequest, DelegationTaskReport, TaskStatus, +}; +use crate::acp::types::DelegationResultSummary; +use crate::models::AgentType; + +/// Default per-parent byte budget for cached completed-task result text. The +/// completed-cache lets `get_delegation_status` / `cancel_delegation` return a +/// finished task's result after the lifecycle resolved it; once a parent's +/// retained result text exceeds this budget the OLDEST results are FIFO-evicted +/// (evicted tasks fall back to the DB status lookup, which carries status only). +/// This is the seed value baked into `DelegationConfig::default()`; the live +/// value is user-configurable from the settings page (in MB) and `0` disables +/// eviction entirely. See `PendingInner::completed_cap_bytes`. +const DEFAULT_COMPLETED_CACHE_CAP_BYTES: usize = 512 * 1024 * 1024; + +/// Per-result cap on cached completed text. The full child output always lives +/// in the child's own session (viewable via the frontend's child-session +/// sheet); this only bounds the broker's in-memory copy of a SINGLE result. +/// Because it is far below the per-parent byte budget +/// (`DEFAULT_COMPLETED_CACHE_CAP_BYTES`), the newest result always fits and is +/// never the eviction victim in `insert_completed`. +const COMPLETED_TEXT_CAP: usize = 256 * 1024; + +/// Cap on the `task_preview` carried by the `DelegationStarted` event and the +/// parent-card meta writes. The full task text lives in the MCP call (and, on +/// most hosts, in the parent tool call's own `raw_input`); the preview only +/// has to label the delegation card, so it shares the status-preview budget +/// rather than the multi-KiB result cap. +const TASK_PREVIEW_CAP: usize = 2 * 1024; + +/// Cap on the inline `text_preview` carried by the `DelegationCompleted` event +/// and the terminal meta, so the parent card can render the result inline +/// without re-fetching the child session. +const STATUS_PREVIEW_CAP: usize = 2 * 1024; + +/// Lookup the `parent_id` for a conversation. Abstracted so the broker can be +/// unit-tested against an in-memory chain without touching SeaORM. +#[async_trait] +pub trait ConversationDepthLookup: Send + Sync { + async fn parent_of(&self, conversation_id: i32) -> Result, DelegationError>; +} + +/// Status-level facts the broker recovers from a child conversation row when a +/// task's in-memory completed-cache entry was evicted. Carries NO result text — +/// child output isn't stored in codeg's DB; the full result lives in the +/// child's own session (viewable via the frontend's child-session sheet). +#[derive(Debug, Clone)] +pub struct ChildStatusRecord { + pub child_conversation_id: i32, + pub status: TaskStatus, + pub agent_type: AgentType, + /// The parent conversation id this child was spawned under. Used to scope + /// the DB fallback to the calling parent so one parent can't read another's + /// task by guessing a UUID. + pub parent_id: Option, +} + +/// DB fallback for `get_delegation_status` / `cancel_delegation` once a task's +/// result has aged out of the broker's in-memory completed-cache. Abstracted +/// so broker unit tests can run without SeaORM; production wires +/// [`DbChildStatusLookup`] via [`DelegationBroker::with_status_lookup`]. +#[async_trait] +pub trait ChildStatusLookup: Send + Sync { + async fn find_by_call_id(&self, call_id: &str) -> Option; +} + +/// Default lookup — always "unknown". Used by `DelegationBroker::new` / +/// `with_writers` (tests that don't exercise the DB-fallback path); production +/// replaces it via `with_status_lookup`. +#[derive(Default, Clone)] +pub struct NoopChildStatusLookup; + +#[async_trait] +impl ChildStatusLookup for NoopChildStatusLookup { + async fn find_by_call_id(&self, _call_id: &str) -> Option { + None + } +} + +#[derive(Debug, Clone)] +pub struct DelegationConfig { + pub enabled: bool, + /// Max chain depth a *new* delegation may exist at. With `depth_limit = 2` + /// the chain root → child → grandchild is allowed; the grandchild trying + /// to spawn a great-grandchild is rejected. See spec §5. + pub depth_limit: u32, + /// Per-agent overrides applied when spawning a delegation child. Keyed by + /// the target `agent_type`; missing entries mean "no override." Forwarded + /// to `ConnectionSpawner::spawn` as `preferred_mode_id` / + /// `preferred_config_values`. + pub agent_defaults: BTreeMap, + /// Per-parent byte budget for cached completed-task result text. `0` + /// disables eviction (unlimited). Surfaced from the settings page in MB and + /// converted to bytes in `into_broker_config`. Pushed into the pending-calls + /// bucket by `set_config` so `insert_completed` reads it lock-free. + pub completed_cache_cap_bytes: usize, +} + +impl Default for DelegationConfig { + fn default() -> Self { + Self { + enabled: false, + depth_limit: 1, + agent_defaults: BTreeMap::new(), + completed_cache_cap_bytes: DEFAULT_COMPLETED_CACHE_CAP_BYTES, + } + } +} + +/// A delegation task running in the background after `start_delegation` +/// returned its `Running` ack. The async redesign drops the parked +/// `oneshot::Sender` the old `PendingCall` carried: the parent's +/// `delegate_to_agent` no longer blocks on a channel, so there is nothing to +/// signal. A terminal event instead migrates the entry into `completed` (same +/// lock) and wakes any `get_delegation_status` long-poll via the broker's +/// `result_notify`. +struct RunningTask { + child_connection_id: String, + child_conversation_id: i32, + parent_connection_id: String, + parent_tool_use_id: String, + /// Target agent — surfaced in status reports. + agent_type: AgentType, + /// Bounded preview of the delegated task text ([`TASK_PREVIEW_CAP`]). + /// Carried so TERMINAL meta writes can keep labeling the parent card — + /// meta is replace-wholesale on the ToolCallState, so a terminal write + /// that dropped the task text would erase what the running write supplied. + task_preview: String, + /// The broker-minted task id — duplicates this entry's key in `running` + /// because the cancel/teardown paths hand around the drained + /// `RunningTask` by value without its map key. + task_id: String, + /// MCP-side opaque handle minted by the companion per `tools/call`. The + /// listener forwards it through `DelegationRequest`; we keep it here so + /// `cancel_by_external_handle` can find the entry. `None` for delegations + /// that didn't come through MCP (tests, future internal callers). + external_handle: Option, + /// When the child started running (after `send_prompt` succeeded). Used to + /// compute a real `duration_ms` at terminal time. + started_at: Instant, + /// The last blocking prompt a status query reported to the parent, and when. + /// Makes "the block I told you about" distinguishable from "a NEW block", + /// which is what stops a `wait_ms: 0` poll from returning instantly forever + /// once a child parks on a permission (#447): the first observation + /// returns, a re-poll on the same prompt goes back to waiting, and a second + /// prompt returns again. + /// + /// The timestamp is the safety valve. Marking a block reported is not proof + /// the parent RECEIVED it — the report still has to cross the listener, the + /// companion's stdout and the agent CLI, and an MCP `notifications/cancelled` + /// or a client-side call abort discards it silently. Without the valve that + /// lost report would be the only one ever offered, re-creating the exact + /// stall this fixes. So the same unanswered prompt becomes reportable again + /// after [`BLOCK_RESURFACE_INTERVAL`]. + last_surfaced_block: Option, +} + +/// See [`RunningTask::last_surfaced_block`]. +struct SurfacedBlock { + request_id: String, + at: Instant, +} + +/// A terminal delegation result retained so `get_delegation_status` / +/// `cancel_delegation` can answer after the lifecycle resolved the task. +/// Parent-scoped, FIFO-evicted once the parent's retained result text exceeds +/// `PendingInner::completed_cap_bytes`, and dropped wholesale when the parent +/// connection tears down. +#[derive(Clone)] +struct CompletedTask { + parent_connection_id: String, + child_conversation_id: i32, + agent_type: AgentType, + status: TaskStatus, + /// Result text for `Completed` (capped at [`COMPLETED_TEXT_CAP`]). `None` + /// for failures/cancels. + text: Option, + error_code: Option, + message: Option, + duration_ms: u64, +} + +#[derive(Default)] +struct PendingCalls { + inner: Mutex, +} + +/// Everything guarded by the single pending-calls mutex. Co-locating the parked +/// calls with the early-terminal bookkeeping under ONE lock is what makes the +/// terminal-vs-registration race safe: a terminal event for a delegation that +/// is still mid-setup (its `handle_request` hasn't parked the [`PendingCall`] +/// yet) and the matching registration are serialized on this lock, so the +/// terminal event either finds the parked entry (resolves via `tx`) or buffers +/// its outcome (and `handle_request` drains it the instant it parks) — never +/// both, never neither. Without this, a terminal that fires in the spawn→park +/// window would no-op the resolver and then strand the parked `rx.await`. +/// +/// Both CHILD-terminal pre-park resolvers are covered, because either can win +/// the race against the parent `write_meta` await between `send_prompt` and the +/// park: +/// * `complete_call` — a fast/empty turn's `TurnComplete` (the prompt is only +/// *enqueued* by `send_prompt`; the child loop emits `TurnComplete` +/// independently). Keyed by `call_id`. +/// * `cancel_by_child_connection` — a freshly-spawned child connection dying +/// before its first prompt is answered. Keyed by `child_connection_id`. +/// +/// Parent-side cancels (`cancel_by_parent` / `cancel_by_parent_turn`) are +/// covered symmetrically by the `inflight` registry: `handle_request` registers +/// each setup at entry, and `mark_inflight_canceled_for_parent` runs in the SAME +/// lock acquisition that drains the parked `calls`. A parent cancel landing +/// while a child is still mid-setup therefore flags the in-flight record, and +/// `handle_request` observes the flag at its next checkpoint (or atomically at +/// park) and tears the child down itself — it is no longer left to the child's +/// own terminal / connection-teardown cascade. +/// +/// The reservation records the `child_connection_id` each resolver gates on; +/// `handle_request` drains both buffers at park. +#[derive(Default)] +struct PendingInner { + /// Tasks running in the background after their `Running` ack, keyed by + /// broker `call_id` (= `task_id`). A terminal event migrates an entry from + /// here into `completed` under THIS lock (atomic `running` → `completed` + /// transition), so a concurrent `get_delegation_status` never observes a + /// task as neither running nor completed. + running: HashMap, + /// Terminal results retained for `get_delegation_status` / `cancel_delegation`, + /// keyed by `task_id`. Bounded by the per-parent byte valve + /// (`completed_cap_bytes` over `completed_bytes`, FIFO-evicted via + /// `completed_order`) and dropped per-parent on connection teardown. + /// Evicted/unknown tasks fall back to the DB status lookup. + completed: HashMap, + /// Per-parent FIFO index over `completed` for byte-valve eviction and + /// per-parent teardown. Keyed by `parent_connection_id`; each deque holds + /// that parent's completed `task_id`s oldest-first. + completed_order: HashMap>, + /// Per-parent running total of retained completed result-text bytes (the + /// `CompletedTask::text` lengths). Drives the `completed_cap_bytes` valve in + /// `insert_completed`; kept in sync on insert/evict and cleared per-parent + /// on teardown. + completed_bytes: HashMap, + /// Per-parent byte budget for retained completed result text. `0` = + /// unlimited (no eviction). Seeded by `set_config` from the live + /// `DelegationConfig` (default until then: `0`, but `set_config` always runs + /// at startup via `apply_persisted_config`). Read lock-free by + /// `insert_completed`, which already holds THIS mutex — so the cap is + /// consulted WITHOUT nesting the `config` lock under the pending lock. + completed_cap_bytes: usize, + /// In-setup delegations (spawned + id minted, not yet parked), mapping + /// `call_id` → `child_connection_id`. Gating the early buffers on membership + /// here distinguishes a genuine pre-registration race (still reserved → + /// buffer) from the normal post-resolution teardown that fires on every + /// completion (no longer reserved → ignore). Removed at park / on the + /// send-failure path. + setups: HashMap, + /// Completion outcomes captured by a `TurnComplete` that beat registration + /// (gated by `setups`), keyed by `call_id`. Each carries the `seq` arrival + /// stamp taken when it buffered, so the park can order it against a racing + /// parent cancel (first-terminal-wins). Drained at park. + early_completes: HashMap, + /// Cancel reasons captured by a child failure that beat registration (gated + /// by `setups`), keyed by `child_connection_id`. The value pairs the `seq` + /// arrival stamp (for the park's first-terminal-wins ordering against a + /// racing parent cancel) with the pre-computed `Canceled { reason }` text + /// (same wording the parked `cancel_by_child_connection` path produces); + /// `handle_request` rebuilds the full outcome at park with the real + /// `child_conversation_id` (which the resolver, finding no entry, lacked). + early_cancels: HashMap, + /// In-flight `handle_request` setups, keyed by a unique per-call id and + /// registered at entry (BEFORE the claim poll, so the whole claim→park + /// window is covered). This is the parent-cancel counterpart to `setups`: + /// `setups` lets a *child* terminal reach a not-yet-parked delegation, + /// while `inflight` lets a *parent* cancel reach one. `cancel_by_parent*` + /// flags every entry it owns (`mark_inflight_canceled_for_parent`); + /// `handle_request` consults the flag after claim, after spawn, and + /// atomically at park, tearing the spawned child down itself when set. + /// Removed at park and on every early-return (no Drop guard — see + /// `register_inflight`). + inflight: HashMap, + /// Monotonic arrival clock (see `tick`). Hands out the unique `inflight` + /// keys AND the arrival stamps on buffered child terminals / parent cancels, + /// so the park can resolve a setup-window race by true first-terminal-wins + /// order. Keys and stamps share this sequence but are never cross-compared + /// (keys match by identity, stamps only by `<` against other stamps). + seq: u64, +} + +/// One in-flight `handle_request` setup tracked for parent-cancel coverage. +struct InflightSetup { + parent_connection_id: String, + /// `Some(stamp)` once a parent cancel lands while this delegation is + /// mid-setup (spawned / sending, not yet parked), where `stamp` is the `seq` + /// arrival-clock value at that moment. First-write-wins and never cleared, + /// so a cancel can't be lost between `handle_request`'s checkpoints, and its + /// stamp lets the park order it against a racing child terminal. + canceled_at: Option, +} + +impl PendingInner { + /// Mark a delegation as setting-up (spawned + id minted, not yet parked) so + /// a terminal event racing the park is buffered rather than dropped. + /// + /// No cap: a reservation lives only for the brief spawn→park window and is + /// always released by `unreserve` on every `handle_request` exit (park, or + /// the send-failure path), so `setups` is bounded by the count of + /// concurrently-in-setup delegations — it never accumulates stale entries. + /// A cap here would be actively unsafe: every reservation is live, so + /// evicting one to make room would drop a real in-flight delegation's race + /// guard and reopen the very hang this machinery exists to prevent. + fn reserve(&mut self, call_id: &str, child_connection_id: &str) { + self.setups + .insert(call_id.to_string(), child_connection_id.to_string()); + } + + /// Release a delegation's reservation and discard any un-drained buffered + /// terminal — called once the entry is parked (the buffers were already + /// drained, so the removals are no-ops then) or when setup errors out + /// (discarding a buffer no `handle_request` will pick up). + fn unreserve(&mut self, call_id: &str, child_connection_id: &str) { + self.setups.remove(call_id); + self.early_completes.remove(call_id); + self.early_cancels.remove(child_connection_id); + } + + /// Whether a child connection belongs to a still-in-setup delegation. O(n) + /// over `setups`, but n is the (tiny) count of concurrently-in-setup + /// delegations. + fn is_child_reserved(&self, child_connection_id: &str) -> bool { + self.setups + .values() + .any(|child| child == child_connection_id) + } + + /// Buffer a completion for a still-reserved delegation, stamped with the + /// current arrival clock so the park can order it against a racing parent + /// cancel. No-op when the `call_id` isn't reserved (already resolved by + /// another terminal path), so the buffer only ever holds genuine + /// pre-registration races. + fn buffer_early_complete(&mut self, call_id: &str, outcome: DelegationOutcome) { + if self.setups.contains_key(call_id) { + let stamp = self.tick(); + self.early_completes + .insert(call_id.to_string(), (stamp, outcome)); + } + } + + /// Buffer a child failure for a still-reserved delegation, stamped with the + /// current arrival clock so the park can order it against a racing parent + /// cancel. No-op when the child isn't reserved (normal post-resolution + /// teardown). Stores the pre-computed cancel reason so the park rebuilds the + /// same wording the parked `cancel_by_child_connection` path produces. + fn buffer_child_failure(&mut self, child_connection_id: &str, detail: Option) { + if self.is_child_reserved(child_connection_id) { + let stamp = self.tick(); + self.early_cancels.insert( + child_connection_id.to_string(), + (stamp, child_canceled_reason(detail.as_deref())), + ); + } + } + + /// Drain a buffered completion with its arrival stamp (by `call_id`) — used + /// by `handle_request` at park. + fn take_early_complete(&mut self, call_id: &str) -> Option<(u64, DelegationOutcome)> { + self.early_completes.remove(call_id) + } + + /// Drain a buffered cancel reason with its arrival stamp (by + /// `child_connection_id`) — used by `handle_request` at park. + fn take_early_cancel(&mut self, child_connection_id: &str) -> Option<(u64, String)> { + self.early_cancels.remove(child_connection_id) + } + + /// Advance the monotonic arrival clock, returning the pre-increment value. + /// Strictly increasing (wraps only after 2^64 calls — unreachable), so two + /// events stamped under this lock always compare in their true arrival + /// order. Backs both `inflight` keys and terminal/cancel arrival stamps; the + /// two uses never cross-compare (keys match by identity, stamps by `<`). + fn tick(&mut self) -> u64 { + let v = self.seq; + self.seq = self.seq.wrapping_add(1); + v + } + + /// Register an in-flight setup at `handle_request` entry, returning its + /// unique id. The caller MUST `deregister_inflight` on every exit path + /// (each early-return, and at park). There is deliberately NO Drop guard: + /// the park hand-off — `calls.insert` followed by `deregister_inflight` — + /// has to be atomic under this lock so a concurrent parent cancel sees the + /// entry in exactly one of `inflight` or `calls`, and a guard firing after + /// the lock releases would reopen that window. + fn register_inflight(&mut self, parent_connection_id: &str) -> u64 { + let id = self.tick(); + self.inflight.insert( + id, + InflightSetup { + parent_connection_id: parent_connection_id.to_string(), + canceled_at: None, + }, + ); + id + } + + /// Drop an in-flight setup record (idempotent). + fn deregister_inflight(&mut self, id: u64) { + self.inflight.remove(&id); + } + + /// Whether a parent cancel flagged this in-flight setup. False once the + /// record is gone (already parked / deregistered). Used by the pre-spawn / + /// post-spawn checkpoints, which only need the boolean. + fn inflight_canceled(&self, id: u64) -> bool { + self.inflight + .get(&id) + .map(|s| s.canceled_at.is_some()) + .unwrap_or(false) + } + + /// Arrival stamp of the parent cancel that flagged this in-flight setup, if + /// any (`None` when not canceled, or the record is already gone). Used at + /// park to order the cancel against a buffered child terminal. + fn inflight_canceled_at(&self, id: u64) -> Option { + self.inflight.get(&id).and_then(|s| s.canceled_at) + } + + /// Flag every in-flight setup owned by `parent_connection_id` as canceled, + /// stamping each with one shared arrival-clock value (this cancel is a + /// single event). First-write-wins per setup, so a later cancel can't push + /// an earlier one's stamp forward. Called from `drain_for_parent_cancel` in + /// the SAME lock acquisition that drains the parked `calls`, so each of the + /// parent's delegations is caught either here (still in-flight → flagged; + /// `handle_request` tears its child down at the next checkpoint) or by the + /// parked-call drain (already parked) — never neither. + fn mark_inflight_canceled_for_parent(&mut self, parent_connection_id: &str) { + let stamp = self.tick(); + for setup in self.inflight.values_mut() { + if setup.parent_connection_id == parent_connection_id && setup.canceled_at.is_none() { + setup.canceled_at = Some(stamp); + } + } + } + + /// Insert a terminal result into the completed-cache, then FIFO-evict this + /// parent's OLDEST results until its retained result-text bytes fit + /// `completed_cap_bytes` (`0` = unlimited). Evicted tasks fall back to the + /// DB status lookup (status only — child text lives in the child session). + /// The just-inserted entry is never the victim: a single result is capped + /// at [`COMPLETED_TEXT_CAP`] (256 KiB), far below any MB-scale budget, so + /// the newest result always survives for the LLM's immediate + /// `get_delegation_status`. The caller does the atomic `running.remove` + + /// this insert under one lock, then notifies long-poll waiters AFTER + /// releasing the lock. + fn insert_completed(&mut self, call_id: &str, task: CompletedTask) { + let parent = task.parent_connection_id.clone(); + let task_bytes = task.text.as_ref().map_or(0, |t| t.len()); + self.completed.insert(call_id.to_string(), task); + *self.completed_bytes.entry(parent.clone()).or_insert(0) += task_bytes; + self.completed_order + .entry(parent.clone()) + .or_default() + .push_back(call_id.to_string()); + self.evict_completed_over_cap(&parent); + } + + /// Evict `parent`'s OLDEST completed results until its retained result-text + /// bytes fit `completed_cap_bytes` (`0` = unlimited). Evicted tasks fall + /// back to the DB status lookup (status only — child text lives in the child + /// session). The newest entry is never evicted: a single result is capped at + /// [`COMPLETED_TEXT_CAP`] (256 KiB), far below any MB-scale budget, so the + /// LLM's immediate `get_delegation_status` always hits. + fn evict_completed_over_cap(&mut self, parent: &str) { + let cap = self.completed_cap_bytes; + if cap == 0 { + return; + } + loop { + if self.completed_bytes.get(parent).copied().unwrap_or(0) <= cap { + break; + } + let evicted = match self.completed_order.get_mut(parent) { + Some(order) if order.len() > 1 => order.pop_front(), + _ => None, + }; + let Some(evicted) = evicted else { + break; + }; + if let Some(removed) = self.completed.remove(&evicted) { + let freed = removed.text.as_ref().map_or(0, |t| t.len()); + if let Some(slot) = self.completed_bytes.get_mut(parent) { + *slot = slot.saturating_sub(freed); + } + } + } + } + + /// Re-apply the current `completed_cap_bytes` to EVERY parent. Called by + /// `set_config` when the cap may have been LOWERED at runtime, so + /// already-retained results are pruned promptly — insert-time eviction alone + /// would otherwise strand them until a parent's next completion (which may + /// never arrive). + fn enforce_completed_cap_all_parents(&mut self) { + if self.completed_cap_bytes == 0 { + return; + } + let parents: Vec = self.completed_bytes.keys().cloned().collect(); + for parent in parents { + self.evict_completed_over_cap(&parent); + } + } + + /// Forget every completed result for a parent. Called on connection + /// teardown (the parent is gone — nothing left to query). A turn cancel + /// deliberately does NOT call this: the connection stays alive and the LLM + /// may still query its just-canceled tasks. + fn drop_completed_for_parent(&mut self, parent_connection_id: &str) { + self.completed_bytes.remove(parent_connection_id); + if let Some(ids) = self.completed_order.remove(parent_connection_id) { + for id in ids { + self.completed.remove(&id); + } + } + } +} + +/// Cap result text retained in the completed-cache. The full output always +/// lives in the child session; this only bounds the broker's copy. +fn cap_completed_text(text: &str) -> String { + truncate_on_char_boundary(text, COMPLETED_TEXT_CAP) +} + +/// Build the bounded inline preview carried by the `DelegationCompleted` event +/// and terminal meta. `None` for empty text. +fn build_text_preview(text: &str) -> Option { + if text.trim().is_empty() { + return None; + } + Some(truncate_on_char_boundary(text, STATUS_PREVIEW_CAP)) +} + +/// Truncate `s` so the RESULT (including the appended ellipsis) is at most `cap` +/// bytes, cut on a UTF-8 char boundary. Reserving the ellipsis bytes keeps the +/// output within the advertised cap rather than `cap + 3`. +fn truncate_on_char_boundary(s: &str, cap: usize) -> String { + if s.len() <= cap { + return s.to_string(); + } + const ELLIPSIS: &str = "…"; + // Leave room for the ellipsis; clamp at 0 for pathologically small caps. + let budget = cap.saturating_sub(ELLIPSIS.len()); + let mut end = budget.min(s.len()); + while end > 0 && !s.is_char_boundary(end) { + end -= 1; + } + format!("{}{ELLIPSIS}", &s[..end]) +} + +/// Derive the completed-cache fields (status / text / error_code / message) +/// from a resolved [`DelegationOutcome`]. `Canceled`-coded errors map to +/// [`TaskStatus::Canceled`]; every other error maps to [`TaskStatus::Failed`]. +fn terminal_fields( + outcome: &DelegationOutcome, +) -> (TaskStatus, Option, Option, Option) { + match outcome { + DelegationOutcome::Ok(ok) => ( + TaskStatus::Completed, + Some(cap_completed_text(&ok.text)), + None, + None, + ), + DelegationOutcome::Err { code, message, .. } => { + let status = if code == "canceled" { + TaskStatus::Canceled + } else { + TaskStatus::Failed + }; + (status, None, Some(code.clone()), Some(message.clone())) + } + } +} + +/// Build a [`CompletedTask`] from a resolved outcome for the completed-cache. +fn build_completed( + parent_connection_id: &str, + child_conversation_id: i32, + agent_type: AgentType, + duration_ms: u64, + outcome: &DelegationOutcome, +) -> CompletedTask { + let (status, text, error_code, message) = terminal_fields(outcome); + CompletedTask { + parent_connection_id: parent_connection_id.to_string(), + child_conversation_id, + agent_type, + status, + text, + error_code, + message, + duration_ms, + } +} + +/// A `canceled`-coded [`DelegationOutcome`] carrying the child conversation id. +fn canceled_outcome(child_conversation_id: i32, reason: &str) -> DelegationOutcome { + DelegationOutcome::from_err( + DelegationError::Canceled { + reason: reason.to_string(), + }, + Some(child_conversation_id), + ) +} + +/// Remove `keys` from `running`, recording each as a `Canceled` completed entry +/// (so a `get_delegation_status` still answers) and returning the drained tasks +/// — each paired with the `duration_ms` captured at this drain point — for I/O +/// teardown. MUST be called with the pending lock held so the running → +/// completed migration is atomic. +/// +/// The duration is captured ONCE here and returned so the slow teardown +/// (parent-card meta, report) reuses the exact value recorded into the +/// completed-cache, rather than recomputing `started_at.elapsed()` later — which +/// would inflate it for the backgrounded `cancel_by_parent_turn` teardown and +/// disagree with the `get_delegation_status` / `cancel_delegation` cards. +fn drain_and_record_canceled( + inner: &mut PendingInner, + keys: Vec, + reason: &str, +) -> Vec<(RunningTask, u64)> { + let mut out = Vec::with_capacity(keys.len()); + for k in keys { + let task = inner.running.remove(&k).expect("key just observed"); + let outcome = canceled_outcome(task.child_conversation_id, reason); + let duration_ms = task.started_at.elapsed().as_millis() as u64; + inner.insert_completed( + &k, + build_completed( + &task.parent_connection_id, + task.child_conversation_id, + task.agent_type, + duration_ms, + &outcome, + ), + ); + out.push((task, duration_ms)); + } + out +} + +/// Project a `DelegationOutcome` + broker-measured `duration_ms` onto the +/// wire-stable `DelegationResultSummary` carried by `DelegationCompleted`. +/// Keeps the mapping (and the bounded `text_preview`) in one place. +fn outcome_to_summary(outcome: &DelegationOutcome, duration_ms: u64) -> DelegationResultSummary { + match outcome { + DelegationOutcome::Ok(ok) => DelegationResultSummary::Ok { + duration_ms, + text_preview: build_text_preview(&ok.text), + }, + DelegationOutcome::Err { code, .. } => DelegationResultSummary::Err { + error_code: code.clone(), + }, + } +} + +/// Project a resolved outcome onto a terminal [`DelegationTaskReport`] (used by +/// the setup-window terminal dispositions and the test shim). +fn report_from_outcome( + task_id: Option, + agent_type: Option, + outcome: &DelegationOutcome, + duration_ms: Option, +) -> DelegationTaskReport { + let (status, text, error_code, message) = terminal_fields(outcome); + let child_conversation_id = match outcome { + DelegationOutcome::Ok(ok) => Some(ok.child_conversation_id), + DelegationOutcome::Err { + child_conversation_id, + .. + } => *child_conversation_id, + }; + DelegationTaskReport { + task_id, + status, + child_conversation_id, + agent_type, + text, + error_code, + message, + duration_ms, + // Terminal by construction — nothing is waiting on the user anymore. + blocked_on: None, + } +} + +/// Build a `Failed`/`Canceled` report for a setup error (no task id — setup +/// failed before/around registration, so the LLM has no task to track). +fn report_err( + agent_type: AgentType, + err: DelegationError, + child_conversation_id: Option, +) -> DelegationTaskReport { + let outcome = DelegationOutcome::from_err(err, child_conversation_id); + report_from_outcome(None, Some(agent_type), &outcome, None) +} + +/// The `Running` ack returned by `start_delegation` for a backgrounded task. +fn running_ack( + call_id: String, + child_conversation_id: i32, + agent_type: AgentType, +) -> DelegationTaskReport { + // Embed the literal task_id in the message so it survives clients that only + // surface the MCP `content` text (not `structuredContent`) — without it the + // LLM couldn't call get_delegation_status / cancel_delegation. + let message = format!( + "Delegation successful. task_id={call_id}. Call get_delegation_status \ + with this id in the task_ids array (optionally wait_ms) to collect the \ + result, or cancel_delegation to stop it." + ); + DelegationTaskReport { + task_id: Some(call_id), + status: TaskStatus::Running, + child_conversation_id: Some(child_conversation_id), + agent_type: Some(agent_type), + text: None, + error_code: None, + message: Some(message), + duration_ms: None, + blocked_on: None, + } +} + +/// How long [`DelegationBroker::get_task_status`] may block before returning the +/// current (possibly still-running) snapshot. Derived by the listener from the +/// MCP tool's `wait_ms`: omitted → [`Immediate`], an explicit `0` → [`Infinite`], +/// any positive value → [`Bounded`] (clamped to the listener's hard ceiling). +/// +/// [`Immediate`]: StatusWait::Immediate +/// [`Bounded`]: StatusWait::Bounded +/// [`Infinite`]: StatusWait::Infinite +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +pub enum StatusWait { + /// Return the current snapshot right away — the default poll. + Immediate, + /// Block up to this many milliseconds, then return whatever snapshot we have + /// (the child keeps running past the deadline; the caller re-issues to wait + /// more). + Bounded(u64), + /// Block until the task reaches a terminal state — never time out. Lets a + /// long-running child be awaited in a single call. A parent disconnect or + /// cancel also drives the task terminal (and fires the completion signal), + /// so this never outlives the task itself. + Infinite, +} + +/// How long an already-reported blocking prompt stays suppressed before a +/// status long-poll will surface it again. Two jobs: it keeps a `wait_ms: 0` +/// caller from spinning on a block it has already been told about, and it +/// bounds the damage when a report is generated but never delivered (see +/// [`RunningTask::last_surfaced_block`]) — a lost report costs a delayed notice +/// instead of a permanent stall. Long relative to a human noticing a prompt, +/// short relative to walking away from the machine. +const BLOCK_RESURFACE_INTERVAL: Duration = Duration::from_secs(300); + +/// Second line of a blocked running report's message. The frontend anchors on +/// this exact prefix to keep recognizing the poll as "running" on hosts that +/// persist only the `CallToolResult` content text — see `textRunningStatus` in +/// `src/lib/delegation-status.ts`. Backend protocol string, never localized. +const BLOCKED_LINE_PREFIX: &str = "Awaiting your decision:"; + +/// Mark a running report as parked on a user decision: set the structured +/// `blocked_on` and replace the bare `"Running."` message with a two-line +/// version naming what needs answering. +/// +/// The note goes on its OWN line, for the same reason the live-reply hint does: +/// content-only hosts recognize a still-running poll by the standalone first +/// line `"Running."`, so a *completed* result whose text happens to start with +/// "Running. …" can never be misread as running. +fn attach_blocked(report: &mut DelegationTaskReport, blocked: BlockedOn) { + let what = match (&blocked.kind, blocked.title.as_deref()) { + (_, Some(title)) => title.to_string(), + (BlockedKind::Permission, None) => "a tool permission".to_string(), + (BlockedKind::Question, None) => "a question".to_string(), + (BlockedKind::PlanApproval, None) => "a plan approval".to_string(), + }; + // The third line is guidance for the orchestrating LLM, in the same spirit + // as `running_ack`'s "call get_delegation_status with this id". Keep it in + // step with the tool description in `tool_schema.json`. + report.message = Some(format!( + "Running.\n{BLOCKED_LINE_PREFIX} {what}\nThe sub-agent is parked until \ + a human answers in Codeg — it is not making progress. Tell the user, \ + then wait again." + )); + report.blocked_on = Some(blocked); +} + +/// Status report for a still-running task. +fn running_report(task_id: &str, task: &RunningTask) -> DelegationTaskReport { + DelegationTaskReport { + task_id: Some(task_id.to_string()), + status: TaskStatus::Running, + child_conversation_id: Some(task.child_conversation_id), + agent_type: Some(task.agent_type), + text: None, + error_code: None, + // Bare baseline; `get_task_status` upgrades this to a two-line + // "Running.\nLatest sub-agent reply: …" when the child has live output. + message: Some("Running.".to_string()), + duration_ms: None, + blocked_on: None, + } +} + +/// Status report from a cached completed result. +fn completed_report(task_id: &str, c: &CompletedTask) -> DelegationTaskReport { + DelegationTaskReport { + task_id: Some(task_id.to_string()), + status: c.status, + child_conversation_id: Some(c.child_conversation_id), + agent_type: Some(c.agent_type), + text: c.text.clone(), + error_code: c.error_code.clone(), + message: c.message.clone(), + duration_ms: Some(c.duration_ms), + blocked_on: None, + } +} + +/// Status report when a task id isn't known to the caller (never existed, +/// owned by a different parent, or evicted with no DB record). +fn unknown_report(task_id: &str) -> DelegationTaskReport { + DelegationTaskReport { + task_id: Some(task_id.to_string()), + status: TaskStatus::Unknown, + child_conversation_id: None, + agent_type: None, + text: None, + error_code: None, + message: Some( + "Unknown task id — it never existed, isn't owned by this session, \ + or its result was evicted with no stored record." + .to_string(), + ), + duration_ms: None, + blocked_on: None, + } +} + +/// Status report recovered from the DB after the in-memory result was evicted. +/// Carries status only — the full output lives in the child session. +fn db_report(task_id: &str, rec: &ChildStatusRecord) -> DelegationTaskReport { + DelegationTaskReport { + task_id: Some(task_id.to_string()), + status: rec.status, + child_conversation_id: Some(rec.child_conversation_id), + agent_type: Some(rec.agent_type), + text: None, + error_code: (rec.status == TaskStatus::Canceled).then(|| "canceled".to_string()), + message: Some(format!( + "Result no longer cached; open child session {} for the full output.", + rec.child_conversation_id + )), + duration_ms: None, + blocked_on: None, + } +} + +/// What [`DelegationBroker::claim_new_blocks`] decided for one status pass. +#[derive(Default)] +struct ClaimedBlocks { + /// At least one blocking prompt is reportable now — the wait should return. + any_claimed: bool, + /// Earliest moment a currently-suppressed prompt becomes reportable again. + /// Bounds how long an otherwise-unbounded park may sleep, so the + /// resurface valve actually fires instead of waiting on a notify that will + /// never come (a blocked child emits nothing further on its own). + retry_at: Option, +} + +/// Per-id classification captured under the pending lock during a (possibly +/// batched) status query. The async resolution that can't run under the lock — +/// `attach_live_reply` (a different lock) for a running task, `status_from_db` +/// (a DB round-trip) for one not in memory — is deferred to `assemble_reports` +/// AFTER the lock is released, so a status query never nests the pending lock +/// inside another await. This is the same lock-ordering the single-task path +/// has always used; batching just captures it per id. +enum StatusClass { + /// Terminal/owned-cached, or a cross-parent `unknown` — the report is final. + Settled(DelegationTaskReport), + /// Running and owned — the bare running snapshot plus its child connection + /// id, so `assemble_reports` can attach the latest live reply out of lock. + Running { + report: DelegationTaskReport, + child_connection_id: String, + }, + /// Neither running nor completed in memory — resolve via the DB fallback in + /// `assemble_reports`. A not-in-memory id is, for wait purposes, already + /// settled: it can never transition back to running, so a batch wait need + /// not park on it (and must not hit the DB on every wake). + NotInMemory, +} + +/// Classify one task id against the in-memory maps while the pending lock is +/// held. Mirrors the single-task resolution order — completed cache (parent +/// scoped) → running set (parent scoped) → not-in-memory — and yields a +/// cross-parent hit as `unknown` so a task owned by another parent never leaks. +fn classify_locked(inner: &PendingInner, parent_connection_id: &str, task_id: &str) -> StatusClass { + if let Some(c) = inner.completed.get(task_id) { + if c.parent_connection_id == parent_connection_id { + return StatusClass::Settled(completed_report(task_id, c)); + } + return StatusClass::Settled(unknown_report(task_id)); + } + match inner.running.get(task_id) { + Some(r) if r.parent_connection_id == parent_connection_id => StatusClass::Running { + report: running_report(task_id, r), + child_connection_id: r.child_connection_id.clone(), + }, + Some(_) => StatusClass::Settled(unknown_report(task_id)), + None => StatusClass::NotInMemory, + } +} + +/// Map a terminal [`DelegationTaskReport`] back to a [`DelegationOutcome`] for +/// the test-only `handle_request` shim (so pre-async tests keep asserting on +/// the old outcome shape). +#[cfg(any(test, feature = "test-utils"))] +fn report_to_outcome(report: &DelegationTaskReport) -> DelegationOutcome { + use crate::acp::delegation::types::DelegationSuccess; + match report.status { + TaskStatus::Completed => DelegationOutcome::Ok(DelegationSuccess { + text: report.text.clone().unwrap_or_default(), + child_conversation_id: report.child_conversation_id.unwrap_or(0), + child_agent_type: report.agent_type.unwrap_or(AgentType::ClaudeCode), + turn_count: 1, + duration_ms: report.duration_ms.unwrap_or(0), + token_usage: None, + }), + // Running never reaches here (the shim loops until terminal); the other + // states all project onto Err. + _ => DelegationOutcome::Err { + code: report + .error_code + .clone() + .unwrap_or_else(|| "canceled".to_string()), + message: report.message.clone().unwrap_or_default(), + child_conversation_id: report.child_conversation_id, + }, + } +} + +/// Build the `Canceled { reason }` string for a child that ended without a +/// clean `TurnComplete`, optionally stitching in the terminal `Error` detail. +/// Shared by `cancel_by_child_connection` and `handle_request`'s early-terminal +/// pickup so both surface the same wording. +fn child_canceled_reason(terminal_error: Option<&str>) -> String { + match terminal_error { + Some(detail) if !detail.trim().is_empty() => { + format!("child session ended without TurnComplete: {detail}") + } + _ => "child session ended without TurnComplete".to_string(), + } +} + +/// Set of MCP-side `external_handle` tokens for which the companion +/// already received `notifications/cancelled` BEFORE the matching +/// `handle_request` reached the pending-registration phase. Without +/// this pre-cancel buffer, a fast cancel that lands during the +/// pre-check / spawn window would find no entry in `pending`, drop +/// silently, and let the broker proceed to spawn a child the caller +/// no longer wants. `handle_request` consults this set both at entry +/// (so we never even spawn) and immediately after parking the pending +/// entry (so a cancel landing mid-spawn still wins). +/// +/// Capped at [`PRE_CANCELED_CAP`] so a misbehaving MCP client (or a +/// pathological cancel-for-unknown-id storm) can't grow the set +/// without bound. Eviction is FIFO via the parallel `order` deque, +/// which is fine because pre-cancels only matter for the short window +/// between the cancel and the late-arriving `handle_request`. +#[derive(Default)] +struct PreCanceledHandles { + inner: Mutex, +} + +#[derive(Default)] +struct PreCanceledState { + set: HashSet, + order: VecDeque, +} + +const PRE_CANCELED_CAP: usize = 256; + +/// Per-parent tracking of `tool_call_id`s that the ACP lifecycle +/// observed firing `delegate_to_agent`. MCP clients (Codex, Claude +/// Code) generally do NOT populate `_meta.tool_use_id` when invoking +/// an MCP tool, so the broker can't read the LLM-issued +/// `tool_use_id` from the wire — we capture it from the parallel ACP +/// `tool_call` event stream instead. +/// +/// Each bucket holds two FIFOs under the SAME mutex: +/// +/// * `pending` — ids the lifecycle has registered but the matching +/// broker round-trip has not yet claimed. UNKEYED entries are subject +/// to [`PENDING_TOOL_CALL_TTL`] eviction so an anonymous ACP id whose +/// MCP round-trip never arrives can't linger and FIFO-mis-bind a later +/// delegation. KEYED entries carry no count cap: they are drained only +/// by their exact-match claim, by terminal tombstoning +/// (`tombstone_pending_tool_call`), or by per-parent teardown — because +/// the host may serialize a delegation's round-trip arbitrarily far +/// behind earlier long-running ones, so a count cap would drop a +/// still-pending keyed id and orphan its card. +/// * `consumed` — ids that were already claimed by a prior +/// round-trip, or terminal-tombstoned (`tombstone_pending_tool_call`). +/// NEITHER subject to TTL eviction NOR to a per-bucket +/// cap: a delegated child agent may run for minutes to hours, and +/// the host can re-emit the same `tool_call` (e.g. as a `completed` +/// status flip) at the end of that run, so the consumed memory +/// must outlast the entire parent-side tool call lifetime. It is +/// scoped to the parent connection's lifetime instead, cleared by +/// `drop_pending_tool_calls_for_parent` on disconnect. The growth +/// is bounded by how many entries ever register for the parent: +/// `delegate_to_agent` calls (typically tens at most) plus, on +/// Cursor connections, one identity-less "MCP: tool" candidate per +/// MCP call the session makes (see `acp::lifecycle`'s +/// `CURSOR_IDENTITYLESS_MCP_TITLE` registration) — with each +/// `(String, Instant)` entry costing well under 100 bytes, an +/// unbounded set stays comfortable for realistic sessions without +/// OOM risk in the typical operating envelope. +/// +/// Co-locating the two halves under one lock makes the +/// claim → mark-consumed pair atomic. A host re-emit racing with the +/// claim cannot observe an empty pending queue AND a consumed memory +/// that does not yet remember the id; consequently it cannot inject +/// a stale duplicate that would mis-bind the next delegation. +#[derive(Default)] +struct ToolCallTracker { + inner: Mutex>, +} + +/// The arguments that uniquely identify a `delegate_to_agent` invocation, +/// used to correlate a parent-side ACP `tool_call` to the matching MCP +/// `tools/call` round-trip. All three fields are values the LLM passed +/// identically to both wire paths, so the triple is the deterministic key +/// when a parent fires several `delegate_to_agent` calls in parallel — +/// matching on `task` alone would swap two calls targeting different agents +/// with the same task, and adding `agent_type` alone would still swap two +/// same-agent/same-task calls aimed at different directories (e.g. "run +/// tests" against `/repo-a` vs `/repo-b`). +/// +/// `working_dir` here is the value the LLM EXPLICITLY passed (`None` when +/// omitted), NOT the listener-defaulted spawn directory: the listener +/// defaults a missing MCP `working_dir` to the parent's launch dir, but the +/// ACP `raw_input` omits it then too, so keying on the explicit value keeps +/// both sides symmetric (`None == None`) for the common omitted case while +/// still distinguishing two calls that name different directories. +#[derive(Clone, Debug, PartialEq, Eq)] +pub struct DelegationMatchKey { + pub agent_type: AgentType, + pub task: String, + pub working_dir: Option, +} + +/// One captured parent-side `delegate_to_agent` tool_call awaiting its +/// matching MCP round-trip. +struct PendingToolCall { + tool_call_id: String, + /// The `(agent_type, task, working_dir)` correlation key parsed from the ACP + /// tool_call's `raw_input`. Matched against the MCP round-trip's own + /// key so parallel `delegate_to_agent` calls each bind to their own + /// `tool_call_id` regardless of arrival order — pure arrival-order FIFO + /// can mis-assign them (or, when one MCP round-trip out-races the + /// matching ACP event, orphan to a synthetic id). `None` when the host + /// shipped no parseable `raw_input` at ToolCall time; such entries are + /// claimable ONLY via the post-budget FIFO fallback + /// (`take_pending_tool_call`), never the in-loop key-match path. + match_key: Option, + /// True when the entry came from an identity-less MCP announcement + /// (Cursor's `"MCP: tool"` + empty input — see + /// `lifecycle::CURSOR_IDENTITYLESS_MCP_TITLE`). Such an id belongs to + /// *some* codeg-mcp call whose identity only the companion round-trip can + /// reveal, so it is additionally claimable by + /// [`DelegationBroker::rewrite_identityless_tool_call`] (the + /// `get_delegation_status` / `cancel_delegation` call-time rename), and a + /// `delegate_to_agent` claim that lands on one triggers the identity + /// write. Plain unkeyed entries (a delegation invocation whose args were + /// unparseable) keep `false` and are never renamed. + identityless: bool, + registered_at: Instant, +} + +#[derive(Default)] +struct ToolCallTrackerBucket { + pending: VecDeque, + consumed: VecDeque<(String, Instant)>, + /// Sticky "this parent has EVER announced an identity-less MCP call" flag. + /// Gates [`DelegationBroker::rewrite_identityless_tool_call`]'s poll: on + /// hosts that ship real identities (Claude/Codex/…) no identity-less + /// entry ever registers, the flag stays `false`, and every status/cancel + /// round-trip skips the rename at zero cost instead of burning the poll + /// budget. Never cleared on claim — only with the bucket on teardown. + identityless_seen: bool, +} + +/// Maximum age before a `pending` entry is discarded as stale — but ONLY for +/// UNKEYED entries (anonymous, arrival-order correlated). KEYED entries are +/// retained regardless of age: each is claimed solely by an exact key match, +/// so it can't mis-bind a later delegation, and its MCP round-trip may be +/// serialized arbitrarily far behind earlier long-running delegations (Claude +/// Code runs parallel `delegate_to_agent` calls one-at-a-time — observed gap +/// 77 s). See the retain block in `take_matching_tool_call_at`. +/// 60 s comfortably covers the ACP→MCP race for the unkeyed case (<5 ms +/// typical) while still GC'ing a forgotten anonymous id before it can +/// FIFO-mis-bind a subsequent unkeyed delegation. +/// +/// The `consumed` side has no TTL — see [`ToolCallTrackerBucket`] — because +/// long-running delegations can re-emit the parent-side `tool_call` well past +/// this window. +const PENDING_TOOL_CALL_TTL: Duration = Duration::from_secs(60); + +/// Poll cadence and budget used by `claim_pending_tool_call_with_brief_wait` +/// to correlate an MCP `delegate_to_agent` round-trip to its parent-side +/// ACP `tool_call_id`. The exact-match path returns instantly; this budget is +/// spent while waiting for THIS delegation's own `tool_call` to register (or to +/// backfill its key onto an already-registered entry) so we bind by exact match +/// instead of stealing a parallel sibling's id, or while no claimable id has +/// arrived yet. Unkeyed entries are never claimed in-loop — arrival-order FIFO +/// is deferred to the post-budget last resort, which runs only after the caller +/// has waited the full budget (the correct clock for "this delegation has no +/// key coming"), so a round-trip can't grab a sibling's not-yet-keyed id +/// mid-race. +/// +/// 200 × 10 ms = 2 s. This budget only matters when the MCP round-trip +/// out-races its own ACP `tool_call` registration — i.e. the `tools/call` +/// reaches the broker before the in-process `session/update(tool_call)` (and +/// any slightly-later `ToolCallUpdate` carrying the `agent_type`/`task` args) +/// has registered the key. That race is sub-5ms locally; the headroom covers +/// busier hosts and split arg streaming. The wait is invisible in the happy +/// path (it returns the instant the key matches) and negligible against the +/// multi-second-to-minutes child run it precedes. +/// +/// NOTE: the budget is NOT what protects a *serialized* second delegation +/// whose round-trip lands many seconds after its tool_call registered (Claude +/// Code runs parallel `delegate_to_agent` calls one-at-a-time, so the 2nd may +/// arrive minutes later). That id is already registered and waiting — the +/// thing that used to orphan it was age-eviction, now fixed by retaining keyed +/// entries indefinitely (see `take_matching_tool_call_at`'s retain +/// block). A host that emits no observable ACP `tool_call` at all still falls +/// through to the synthetic id after the budget, exactly as before. +const CLAIM_POLL_INTERVAL: Duration = Duration::from_millis(10); +const CLAIM_POLL_ATTEMPTS: usize = 200; + +/// Poll budget for the status/cancel call-time rename +/// ([`DelegationBroker::rewrite_identityless_tool_call`]): 30 × 10 ms = 300 ms. +/// Much shorter than the delegate claim budget because the rename is +/// best-effort (a miss falls back to the completion-time result sniff) and the +/// poll delays the status snapshot the LLM is waiting on. It only has to +/// absorb the in-process ordering race between the ACP announcement landing in +/// the lifecycle dispatcher and the companion's UDS round-trip reaching the +/// listener — sub-5 ms in practice; the sticky `identityless_seen` gate keeps +/// hosts that never announce identity-less calls at zero cost. +const IDENTITYLESS_RENAME_POLL_ATTEMPTS: usize = 30; + +/// The broker is intentionally `Clone` (cheap — only `Arc`s inside) so +/// listener/handler code can hand copies to spawned tasks without lifetime +/// gymnastics. +#[derive(Clone)] +pub struct DelegationBroker { + spawner: Arc, + depth_lookup: Arc, + /// Writer for `meta["codeg.delegation"]` on the parent's active + /// `delegate_to_agent` ToolCallState. Defaults to a no-op so tests + /// that aren't exercising the meta lifecycle don't need to wire + /// anything; production constructs the broker with the + /// `ConnectionManagerMetaWriter` via `with_writers`. + meta_writer: Arc, + /// Emitter for `AcpEvent::DelegationCompleted` against the parent + /// connection's event stream. Same Noop/Mock/Production scheme as + /// the meta writer — production wires `ConnectionManagerEventEmitter` + /// via `with_writers`; tests that don't observe the event lifecycle + /// take the default Noop. + event_emitter: Arc, + /// DB fallback for `get_delegation_status` / `cancel_delegation` once a + /// task's result aged out of the in-memory completed-cache. Defaults to a + /// no-op ("unknown"); production wires `DbChildStatusLookup` via + /// `with_status_lookup`. + status_lookup: Arc, + /// Peeks a still-running child's live session for a one-line progress hint, + /// used to enrich `get_delegation_status`'s running report. Defaults to a + /// no-op ("no hint"); production wires `ConnectionManagerLiveReplyLookup` via + /// `with_live_reply_lookup`. + live_reply_lookup: Arc, + pending: Arc, + tool_calls: Arc, + pre_canceled_handles: Arc, + config: Arc>, + /// Separate from `DelegationConfig` so existing test literals do not + /// have to name it. Default on: agents may spawn without `@`. The + /// settings toggle can turn it off (mention-only description). + allow_self_initiate: Arc, + /// Woken after every terminal `record_completed` so a `get_delegation_status` + /// long-poll wakes the instant its task finishes instead of busy-polling. + result_notify: Arc, + /// How long an already-reported blocking prompt stays suppressed — + /// [`BLOCK_RESURFACE_INTERVAL`] in production. A field only so tests can + /// shrink it; nothing outside tests ever sets it. + block_resurface: Duration, +} + +impl DelegationBroker { + pub fn new( + spawner: Arc, + depth_lookup: Arc, + ) -> Self { + Self::with_writers( + spawner, + depth_lookup, + Arc::new(NoopMetaWriter) as Arc, + Arc::new(NoopEventEmitter) as Arc, + ) + } + + /// Test-only constructor that injects a meta writer but keeps the + /// default Noop event emitter. Retained so existing meta-focused + /// tests don't have to mention the emitter parameter. New callsites + /// (and production wiring) should prefer `with_writers`. + pub fn with_meta_writer( + spawner: Arc, + depth_lookup: Arc, + meta_writer: Arc, + ) -> Self { + Self::with_writers( + spawner, + depth_lookup, + meta_writer, + Arc::new(NoopEventEmitter) as Arc, + ) + } + + /// Production-grade constructor wiring the broker to both a real + /// meta writer (`ConnectionManagerMetaWriter`) AND an event emitter + /// (`ConnectionManagerEventEmitter`). Tests that observe the full + /// lifecycle (meta writes + DelegationCompleted emits) should use + /// this with `MockMetaWriter` + `MockEventEmitter`. + pub fn with_writers( + spawner: Arc, + depth_lookup: Arc, + meta_writer: Arc, + event_emitter: Arc, + ) -> Self { + Self { + spawner, + depth_lookup, + meta_writer, + event_emitter, + status_lookup: Arc::new(NoopChildStatusLookup), + live_reply_lookup: Arc::new(NoopChildLiveReplyLookup), + pending: Arc::new(PendingCalls::default()), + tool_calls: Arc::new(ToolCallTracker::default()), + pre_canceled_handles: Arc::new(PreCanceledHandles::default()), + config: Arc::new(Mutex::new(DelegationConfig::default())), + allow_self_initiate: Arc::new(AtomicBool::new(true)), + result_notify: Arc::new(Notify::new()), + block_resurface: BLOCK_RESURFACE_INTERVAL, + } + } + + /// Replace the DB status fallback used by `get_delegation_status` / + /// `cancel_delegation` for tasks evicted from the in-memory completed-cache. + /// Builder-style so the production wiring can layer it onto `with_writers` + /// without growing that constructor's arity, and tests can opt in. + pub fn with_status_lookup(mut self, status_lookup: Arc) -> Self { + self.status_lookup = status_lookup; + self + } + + /// Replace the live-reply lookup used to enrich `get_delegation_status`'s + /// running report with the child's latest one-line progress. Builder-style, + /// layered onto `with_writers` by the production wiring; tests opt in with a + /// `MockChildLiveReplyLookup`. + pub fn with_live_reply_lookup( + mut self, + live_reply_lookup: Arc, + ) -> Self { + self.live_reply_lookup = live_reply_lookup; + self + } + + /// Shrink [`BLOCK_RESURFACE_INTERVAL`] so a test can observe the + /// delivery-failure valve without waiting minutes. Test-only by + /// construction — production always keeps the constant. + #[cfg(test)] + fn with_block_resurface(mut self, interval: Duration) -> Self { + self.block_resurface = interval; + self + } + + /// Record a parent ACP `tool_call_id` whose title indicates the LLM is + /// invoking `delegate_to_agent`. The next broker round-trip from the + /// same `parent_connection_id` will claim this id as its + /// `parent_tool_use_id`. Bounded FIFO per connection. + /// + /// Two-tier dedupe against host re-emits of `sessionUpdate(tool_call)` + /// (some hosts use the non-update variant to ship status flips and + /// late-arriving `raw_input` chunks): + /// + /// 1. **In-queue**: if the id is still waiting to be claimed, drop + /// the re-emit — the first push will be consumed by the matching + /// MCP round-trip. + /// 2. **Recently consumed**: if the id was already claimed for an + /// earlier delegation on the same parent, drop the re-emit — + /// otherwise it would sit in the queue as a stale id and mis- + /// bind the **next** delegation's MCP round-trip. The consumed + /// memory persists for the parent connection's lifetime (no + /// TTL, no cap) so a host re-emit at terminal status flip is + /// still rejected even if the delegation ran for hours. + pub async fn register_pending_tool_call( + &self, + parent_connection_id: &str, + tool_call_id: String, + ) { + self.register_pending_tool_call_with_key_at( + parent_connection_id, + tool_call_id, + None, + false, + Instant::now(), + ) + .await; + } + + /// Register an id announced with NO identity at all — Cursor's + /// `"MCP: tool"` + empty-input shape, where the wire never reveals which + /// MCP tool the call is. The entry is unkeyed (claimable by the + /// post-budget FIFO fallback, exactly like a keyless delegation + /// invocation) and additionally marked `identityless`, which (a) makes it + /// claimable by the status/cancel call-time rename + /// ([`Self::rewrite_identityless_tool_call`]) and (b) triggers the + /// identity write when a `delegate_to_agent` claim lands on it. + pub async fn register_identityless_tool_call( + &self, + parent_connection_id: &str, + tool_call_id: String, + ) { + self.register_pending_tool_call_with_key_at( + parent_connection_id, + tool_call_id, + None, + true, + Instant::now(), + ) + .await; + } + + /// `register_pending_tool_call` that also records the + /// `(agent_type, task, working_dir)` correlation key parsed from the + /// tool_call's `raw_input`. The key lets + /// the broker bind this id to its matching MCP round-trip deterministically + /// for parallel `delegate_to_agent` calls that pure arrival-order FIFO can + /// mis-assign. Production registration (from the ACP lifecycle dispatcher) + /// goes through here. + pub async fn register_pending_tool_call_with_key( + &self, + parent_connection_id: &str, + tool_call_id: String, + match_key: Option, + ) { + self.register_pending_tool_call_with_key_at( + parent_connection_id, + tool_call_id, + match_key, + false, + Instant::now(), + ) + .await; + } + + /// Core registration. Holds the [`ToolCallTracker`] mutex across both + /// dedupe tiers AND the push so no concurrent `take` can split the + /// "queue empty + not yet recorded as consumed" window where a host + /// re-emit could otherwise inject a stale duplicate. + /// + /// Two-tier dedupe against host re-emits of `sessionUpdate(tool_call)` + /// (some hosts use the non-update variant to ship status flips and + /// late-arriving `raw_input` chunks): + /// + /// 1. **Recently consumed**: if the id was already claimed for an + /// earlier delegation on the same parent, drop the re-emit — + /// otherwise it would sit in the queue as a stale id and mis-bind + /// the **next** delegation's MCP round-trip. The consumed memory + /// persists for the parent connection's lifetime (no TTL, no cap) + /// so a host re-emit at terminal status flip is still rejected + /// even if the delegation ran for hours. + /// 2. **In-queue**: if the id is still waiting to be claimed, drop the + /// re-emit rather than push a duplicate — EXCEPT we backfill the + /// `match_key` onto an entry registered without one. This is the common + /// case for hosts that emit an arg-less initial `ToolCall` and ship the + /// `agent_type`/`task` arguments on a following `ToolCallUpdate`: the + /// lifecycle dispatcher registers BOTH variants (see + /// `register_delegation_tool_call_from_event`), so the first call lands + /// here unkeyed and the later update re-enters and back-fills the key. + /// Keying the entry this way is what lets it survive past the unkeyed + /// GC TTL (see `take_matching_tool_call_at`'s retain block). + async fn register_pending_tool_call_with_key_at( + &self, + parent_connection_id: &str, + tool_call_id: String, + match_key: Option, + identityless: bool, + now: Instant, + ) { + let mut map = self.tool_calls.inner.lock().await; + let bucket = map.entry(parent_connection_id.to_string()).or_default(); + if identityless { + bucket.identityless_seen = true; + } + // Tier 1: recently consumed. No TTL — the consumed memory must + // outlast the entire parent-side tool call lifetime (minutes + // to hours) so a host re-emit at terminal status flip is + // still rejected. See `ToolCallTrackerBucket` docs. + if bucket.consumed.iter().any(|(id, _)| id == &tool_call_id) { + tracing::info!( + "[delegation] dropping ACP tool_call_id={tool_call_id} on conn={parent_connection_id} (already consumed by an earlier delegation)" + ); + return; + } + // Tier 2: in-queue. A re-emit of an already-queued id: adopt the + // LATEST parseable key rather than only back-filling a missing one. + // Hosts stream `raw_input` incrementally and the MCP side keys on the + // FINAL arguments, so a later `ToolCallUpdate` that completes the key + // (e.g. adds an explicit `working_dir` the first parse lacked) must + // REPLACE the earlier `(agent, task, None)` key — otherwise the MCP + // claim keys on `(agent, task, Some(dir))`, fails to match the stale + // `None`, refuses the keyed fallback, and orphans to a synthetic id + // (the very dead-card failure this whole change fixes). An arg-less or + // identical re-emit changes nothing and is dropped as a duplicate. + if let Some(existing) = bucket + .pending + .iter_mut() + .find(|p| p.tool_call_id == tool_call_id) + { + match match_key { + Some(key) if existing.match_key.as_ref() != Some(&key) => { + existing.match_key = Some(key); + } + _ => { + tracing::info!( + "[delegation] dropping duplicate ACP tool_call_id={tool_call_id} on conn={parent_connection_id}" + ); + } + } + return; + } + bucket.pending.push_back(PendingToolCall { + tool_call_id, + match_key, + identityless, + registered_at: now, + }); + } + + /// Pop the oldest pending `tool_call_id` for the given parent, if any. + /// Skips entries older than [`PENDING_TOOL_CALL_TTL`] so an ACP id whose + /// matching MCP round-trip never arrived cannot mis-bind a later + /// delegation. Mutates the queue in-place; the bucket is removed once + /// drained. + pub async fn take_pending_tool_call(&self, parent_connection_id: &str) -> Option { + self.take_pending_tool_call_at(parent_connection_id, Instant::now()) + .await + .map(|(id, _)| id) + } + + /// `take_pending_tool_call` with an injected "as of" instant. The + /// public entry point pins it to `Instant::now()`; tests can supply + /// a future instant to exercise TTL eviction without sleeping past + /// [`PENDING_TOOL_CALL_TTL`]. + /// + /// Anonymous claim: returns the oldest *unkeyed* pending id (plus its + /// `identityless` mark, so the delegate-claim path knows to restore the + /// call's identity), GC'ing stale unkeyed entries along the way. KEYED + /// entries are stepped over and left in place — they're reserved for + /// their exact-key-match round-trip and must never be handed out by this + /// arrival-order path (doing so would steal an in-flight delegation's + /// id). Returns `None` when no unkeyed entry is claimable, even if keyed + /// entries remain. + async fn take_pending_tool_call_at( + &self, + parent_connection_id: &str, + now: Instant, + ) -> Option<(String, bool)> { + self.take_unkeyed_tool_call_at(parent_connection_id, now, false) + .await + } + + /// Claim the oldest pending entry that was registered as IDENTITY-LESS + /// (Cursor's `"MCP: tool"` announcements) — used by the status/cancel + /// call-time rename. Unlike `take_pending_tool_call_at` this NEVER hands + /// out a plain unkeyed entry: that one is a delegation invocation whose + /// args merely didn't parse, and renaming it to a status tool would + /// mislabel a real delegate card. + async fn take_identityless_tool_call(&self, parent_connection_id: &str) -> Option { + self.take_unkeyed_tool_call_at(parent_connection_id, Instant::now(), true) + .await + .map(|(id, _)| id) + } + + /// Shared FIFO claim over unkeyed entries. `identityless_only` restricts + /// eligibility to entries carrying the identity-less mark; keyed entries + /// are always stepped over (reserved for their exact-key-match + /// round-trip), and stale unkeyed entries are GC'd along the way + /// regardless of the filter so the queue stays bounded from either + /// caller. + async fn take_unkeyed_tool_call_at( + &self, + parent_connection_id: &str, + now: Instant, + identityless_only: bool, + ) -> Option<(String, bool)> { + let mut map = self.tool_calls.inner.lock().await; + let bucket = map.get_mut(parent_connection_id)?; + // Anonymous claim (post-budget last resort + legacy single-delegation + // path): only UNKEYED entries are eligible. A keyed entry identifies a + // specific in-flight delegation and is claimable ONLY by its + // exact-key-match round-trip; grabbing it here would steal that + // delegation's id and make IT the dead card. Walk oldest→newest, + // GC'ing stale unkeyed entries and stepping over keyed ones, until we + // find the oldest fresh eligible id. When only keyed siblings remain we + // return `None` — the delegate caller then mints a synthetic id rather + // than mis-binding a sibling. + let mut claimed: Option<(String, bool)> = None; + let mut idx = 0; + while idx < bucket.pending.len() { + if bucket.pending[idx].match_key.is_some() { + idx += 1; // keyed: leave it for its exact-match round-trip + continue; + } + if now.duration_since(bucket.pending[idx].registered_at) > PENDING_TOOL_CALL_TTL { + if let Some(stale) = bucket.pending.remove(idx) { + let age_secs = now.duration_since(stale.registered_at).as_secs(); + tracing::info!( + "[delegation] evicting stale UNKEYED ACP tool_call_id={} (age={age_secs}s) on conn={parent_connection_id}", + stale.tool_call_id + ); + } + // `remove` shifted later entries left into `idx`; re-check it. + continue; + } + if identityless_only && !bucket.pending[idx].identityless { + idx += 1; // plain unkeyed: reserved for the delegate FIFO path + continue; + } + claimed = bucket + .pending + .remove(idx) + .map(|p| (p.tool_call_id, p.identityless)); + break; + } + // Same mutex span: record the claim into the consumed memory so + // a concurrent re-register cannot observe "pending empty AND + // consumed missing" and inject a stale duplicate. Consumed + // entries persist for the whole parent connection lifetime + // (no TTL, no cap — see `ToolCallTrackerBucket`) and are only + // released when the parent disconnects. + if let Some((id, _)) = &claimed { + bucket.consumed.push_back((id.clone(), now)); + } + if bucket.pending.is_empty() && bucket.consumed.is_empty() && !bucket.identityless_seen { + map.remove(parent_connection_id); + } + claimed + } + + /// Whether this parent has EVER registered an identity-less candidate — + /// the zero-cost gate for [`Self::rewrite_identityless_tool_call`]'s poll. + async fn has_seen_identityless_tool_calls(&self, parent_connection_id: &str) -> bool { + self.tool_calls + .inner + .lock() + .await + .get(parent_connection_id) + .is_some_and(|b| b.identityless_seen) + } + + /// Restore the identity of a pending identity-less MCP tool call at + /// companion round-trip time: claim the oldest such candidate for this + /// parent and rewrite its live `title` + `raw_input` to the actual + /// codeg-mcp tool (`get_delegation_status` / `cancel_delegation`) with + /// its real arguments — flipping the card from the generic "MCP: tool" + /// WHILE the call runs, instead of only at the completion-time result + /// sniff (which, for a `wait_ms`-blocked status long-poll, can be minutes + /// away). + /// + /// Best-effort by design: on hosts that ship real identities the sticky + /// `identityless_seen` gate skips everything at zero cost; on an + /// identity-less host whose announcement hasn't registered yet, a short + /// bounded poll (well under the ACP-vs-companion race in practice) + /// absorbs the ordering, and a miss simply leaves the rename to the + /// completion sniff. Mis-pairing under PARALLEL identity-less calls in + /// one burst is the same accepted arrival-order residual as the delegate + /// FIFO fallback — Cursor executes tool calls sequentially, so announce + /// order matches round-trip order in practice. + pub async fn rewrite_identityless_tool_call( + &self, + parent_connection_id: &str, + title: &str, + raw_input: serde_json::Value, + ) -> Option { + if !self + .has_seen_identityless_tool_calls(parent_connection_id) + .await + { + return None; + } + for attempt in 0..IDENTITYLESS_RENAME_POLL_ATTEMPTS { + if attempt > 0 { + tokio::time::sleep(CLAIM_POLL_INTERVAL).await; + } + if let Some(id) = self.take_identityless_tool_call(parent_connection_id).await { + tracing::info!( + "[delegation] renaming identity-less tool_call_id={id} on conn={parent_connection_id} to {title}" + ); + self.meta_writer + .write_tool_call_identity(parent_connection_id, &id, title, raw_input) + .await; + return Some(id); + } + } + None + } + + /// Claim the pending `tool_call_id` for `parent_connection_id` whose + /// recorded key matches `key` (exact `(agent_type, task, working_dir)` + /// match). This is the ONLY claim this method makes — it never hands out an + /// unkeyed entry, because an unkeyed entry may belong to a *different* + /// parallel delegation whose round-trip simply hasn't registered (or keyed) + /// its `tool_call` yet, and claiming it by arrival order would steal that + /// sibling's id. Returns `None` (so the caller keeps polling) whenever no + /// entry's key matches — whether keyed siblings or only unkeyed entries are + /// present. + /// + /// Arrival-order FIFO for genuinely keyless hosts is deferred to the + /// post-budget last resort `take_pending_tool_call`, which runs only after + /// the caller has waited its full budget (see + /// `claim_pending_tool_call_with_brief_wait`) — the correct clock for "no + /// key is coming", since a host can serialize a round-trip arbitrarily far + /// behind its `tool_call` registration, so the entry's own age can never + /// prove a key won't still arrive. Evicts stale *unkeyed* entries along the + /// way; keyed entries are retained regardless of age (their round-trip may + /// be serialized far behind earlier delegations — see the retain block) and + /// an exact key match claims them at any age. + pub async fn take_matching_tool_call( + &self, + parent_connection_id: &str, + key: &DelegationMatchKey, + ) -> Option { + self.take_matching_tool_call_at(parent_connection_id, key, Instant::now()) + .await + } + + /// `take_matching_tool_call` with an injected "as of" + /// instant for TTL tests. + async fn take_matching_tool_call_at( + &self, + parent_connection_id: &str, + key: &DelegationMatchKey, + now: Instant, + ) -> Option { + let mut map = self.tool_calls.inner.lock().await; + let bucket = map.get_mut(parent_connection_id)?; + + // Evict every stale UNKEYED entry up front. The key-match scan below + // ignores unkeyed entries anyway (they carry no key to match), but + // GC'ing here keeps the queue bounded during the poll loop and + // consistent with `take_pending_tool_call_at`'s view, so the + // post-budget last resort never hands out an aged-out id. Mirrors that + // TTL skip but covers entries at any position (not just the front). + bucket.pending.retain(|p| { + // Keyed entries are NEVER aged out. Each identifies one specific + // `delegate_to_agent` invocation and is claimable ONLY by an exact + // key match (never by FIFO — see below), so it cannot mis-bind a + // different delegation no matter how old it gets. And it MUST + // survive until its MCP round-trip arrives, which the host may + // serialize arbitrarily far behind earlier long-running + // delegations: Claude Code runs parallel `delegate_to_agent` calls + // SEQUENTIALLY, so the 2nd call's round-trip only fires after the + // 1st child finishes. Observed in the wild — a 2nd delegation whose + // tool_call registered, then waited 77s (past the old 60s TTL) for + // its round-trip while the 1st ran; age-evicting it here orphaned + // it to a synthetic id and left the parent card stuck on + // "sub-agent running…". Only UNKEYED (anonymous, arrival-order + // correlated) entries keep the age-based GC, since a stale one + // could be mis-claimed via the FIFO path. Keyed memory stays bounded + // by exact-match claim, terminal tombstoning, and + // `drop_pending_tool_calls_for_parent` on connection teardown — not + // by this TTL. + if p.match_key.is_some() { + return true; + } + let fresh = now.duration_since(p.registered_at) <= PENDING_TOOL_CALL_TTL; + if !fresh { + let age_secs = now.duration_since(p.registered_at).as_secs(); + tracing::info!( + "[delegation] evicting stale UNKEYED ACP tool_call_id={} (age={age_secs}s) on conn={parent_connection_id}", + p.tool_call_id + ); + } + fresh + }); + + let claimed = if let Some(pos) = bucket + .pending + .iter() + .position(|p| p.match_key.as_ref() == Some(key)) + { + // Exact (agent_type, task) match: deterministic correlation + // regardless of ACP-vs-MCP arrival order or how many delegations + // are in flight. + bucket.pending.remove(pos).map(|p| p.tool_call_id) + } else { + // No exact key match. We deliberately do NOT claim an unkeyed entry + // here — not even the oldest, not even the only one. An unkeyed + // pending entry may belong to a DIFFERENT parallel delegation whose + // own round-trip hasn't yet registered (or keyed) its `tool_call`, + // and claiming it by arrival order would steal that sibling's id — + // the mis-bind this machinery exists to prevent. + // + // Crucially, the ENTRY's age is the wrong clock for "no key is + // coming": a host can serialize a round-trip arbitrarily far behind + // its `tool_call` registration (see the retain block / the + // `keyed_entry_survives_past_ttl` case), so even an old lone unkeyed + // entry can still be a sibling's. The CALLER's own wait is the right + // clock. So return `None` and let + // `claim_pending_tool_call_with_brief_wait` poll: if this + // delegation's key lands (initial register or a later backfill) we + // bind by the exact match above; only after the caller has spent the + // FULL budget does its post-budget last resort + // (`take_pending_tool_call`) claim the oldest unkeyed id in arrival + // order — the best a genuinely keyless host allows, and the point at + // which waiting longer cannot improve correlation. + None + }; + + if let Some(id) = &claimed { + bucket.consumed.push_back((id.clone(), now)); + } + if bucket.pending.is_empty() && bucket.consumed.is_empty() { + map.remove(parent_connection_id); + } + claimed + } + + /// Consume an explicit `parent_tool_use_id` that the MCP client supplied + /// directly via `_meta.tool_use_id` (the precise-binding path; most clients + /// omit it). In that case `handle_request` does NOT run the claim path, so + /// the matching pending entry the lifecycle dispatcher registered off the + /// parent's ACP stream would otherwise never be consumed — and because + /// keyed entries are now retained indefinitely, it would linger and could + /// be mis-claimed by a *later* delegation sharing the same + /// `(agent_type, task, working_dir)` key, retargeting that delegation's + /// writes/events at the wrong (already-handled) card. + /// + /// Remove the entry from the pending queue AND record the id as consumed. + /// Recording consumed also covers the MCP-before-ACP race: a later ACP + /// registration for the same id is dropped by the Tier-1 consumed check in + /// `register_pending_tool_call_with_key_at`, so the entry can't reappear + /// regardless of arrival order. + async fn consume_explicit_tool_call(&self, parent_connection_id: &str, tool_call_id: &str) { + let mut map = self.tool_calls.inner.lock().await; + let bucket = map.entry(parent_connection_id.to_string()).or_default(); + bucket.pending.retain(|p| p.tool_call_id != tool_call_id); + if !bucket.consumed.iter().any(|(id, _)| id == tool_call_id) { + bucket + .consumed + .push_back((tool_call_id.to_string(), Instant::now())); + } + } + + /// Tombstone a parent `tool_call_id` whose `delegate_to_agent` reached a + /// TERMINAL ACP status (`completed`/`failed`) so a stale keyed pending entry + /// can't mis-bind a later delegation. The lifecycle dispatcher calls this + /// from its terminal-`ToolCallUpdate` branch, keyed on `tool_call_id` + /// (a bare terminal update carries no parseable key). + /// + /// The hazard: keyed pending entries are retained regardless of age (see the + /// retain block in `take_matching_tool_call_at`), so if a `delegate_to_agent` + /// tool call goes terminal without its MCP round-trip ever reaching the + /// broker (the call failed, the turn was interrupted, the companion never + /// dispatched), its entry would linger forever and a LATER delegation sharing + /// the same `(agent_type, task, working_dir)` key would claim this dead id, + /// retargeting its writes/events at the wrong card. Same hazard + /// `consume_explicit_tool_call` guards on the explicit-id path; this is its + /// terminal-status sibling. + /// + /// Safe synchronously, no grace window: a terminal `completed` can only + /// arrive AFTER the round-trip's claim already removed the entry (the ack + /// that claim produces is what lets the parent's tool call return), and a + /// serialized sibling still awaiting its (observed 77s-late) round-trip is + /// NON-terminal while it waits — so this never evicts a live entry. + /// + /// Records `consumed` ONLY when an entry was actually removed: this runs for + /// EVERY terminal tool-call update (the vast majority are non-delegations), + /// and `consumed` has no TTL/cap, so recording unconditionally would grow it + /// with every completed tool call. Recording on a real removal still drops an + /// out-of-order re-registration of the same id via the Tier-1 consumed check + /// in `register_pending_tool_call_with_key_at`. Returns whether an entry was + /// removed (for the dispatcher's gated log). + pub async fn tombstone_pending_tool_call( + &self, + parent_connection_id: &str, + tool_call_id: &str, + ) -> bool { + let mut map = self.tool_calls.inner.lock().await; + // No bucket → nothing registered for this parent; nothing to tombstone + // and nothing to record (unlike `consume_explicit_tool_call`, no + // MCP-before-ACP race can land a terminal status before registration on + // the single ordered ACP stream, so we never pre-create a bucket here). + let Some(bucket) = map.get_mut(parent_connection_id) else { + return false; + }; + let before = bucket.pending.len(); + bucket.pending.retain(|p| p.tool_call_id != tool_call_id); + let removed = bucket.pending.len() != before; + if removed && !bucket.consumed.iter().any(|(id, _)| id == tool_call_id) { + bucket + .consumed + .push_back((tool_call_id.to_string(), Instant::now())); + } + removed + } + + /// Correlate an MCP `delegate_to_agent` round-trip to the parent's + /// real ACP `tool_call_id`, polling briefly to absorb the race between + /// two independent arrival paths for the same invocation: + /// + /// * ACP `session/update(tool_call)` → in-process bus → lifecycle + /// dispatcher → `register_pending_tool_call_with_key` + /// * MCP `tools/call` → stdio round-trip → companion → `handle_request` + /// + /// Correlation is by the `(agent_type, task, working_dir)` key (carried in + /// both the ACP `raw_input` and the MCP call), so several `delegate_to_agent` + /// calls firing in parallel each bind to their own `tool_call_id` + /// regardless of arrival order — pure FIFO mis-assigned them (swapping + /// the child shown under each card) or, when one MCP round-trip out-raced + /// its ACP event, orphaned the loser to a synthetic `delegation-` + /// (the parent UI then never paints "view session" and the card hangs on + /// "sub-agent running…", because the frontend keys its binding map by + /// the agent's real `tool_call_id`). + /// + /// As a last resort after the budget — and the ONLY place arrival-order + /// FIFO is applied — claim the oldest unkeyed id, so a sibling whose + /// registration was unusually delayed, or a genuinely keyless host, still + /// yields a *real* id rather than a synthetic one. Deferring FIFO until the + /// full budget has elapsed is what makes it safe: in-loop we bind ONLY by + /// exact key match, so a round-trip can't FIFO-steal a sibling's + /// not-yet-keyed id while that sibling's own registration is still in + /// flight (the entry's age is no proof a key won't still arrive). A + /// synthetic id only results when no unkeyed id is claimable for the whole + /// budget — only keyed siblings remain, or the queue stays genuinely empty. + /// Returns the claimed id plus its `identityless` mark — `true` only for + /// the post-budget FIFO claim of an identity-less announcement (Cursor), + /// which tells `start_delegation` to restore the call's identity on the + /// live tool call. Exact-key claims are by definition NOT identity-less + /// (the key was parsed from the wire's own `raw_input`). + async fn claim_pending_tool_call_with_brief_wait( + &self, + parent_connection_id: &str, + key: &DelegationMatchKey, + ) -> Option<(String, bool)> { + if let Some(id) = self + .take_matching_tool_call(parent_connection_id, key) + .await + { + return Some((id, false)); + } + for _ in 0..CLAIM_POLL_ATTEMPTS { + tokio::time::sleep(CLAIM_POLL_INTERVAL).await; + if let Some(id) = self + .take_matching_tool_call(parent_connection_id, key) + .await + { + return Some((id, false)); + } + } + // Budget exhausted with no key match. As a last resort claim the + // oldest UNKEYED pending id (a host that shipped no parseable + // `raw_input`, or a mixed-shape race) — a real id beats a synthetic + // placeholder that orphans the parent UI binding. Crucially this + // never claims a KEYED entry: those belong to specific in-flight + // delegations and are reserved for their own exact-key-match + // round-trip, so when only keyed siblings remain the caller falls + // through to a synthetic id rather than stealing a sibling's binding + // (which would just move the dead card from one delegation to another). + self.take_pending_tool_call_at(parent_connection_id, Instant::now()) + .await + } + + /// Remove `handle` from the pre-cancel set, returning whether it was + /// present. Used by `handle_request` at two checkpoints (entry + just + /// after pending registration) so a cancel that lost the race with the + /// MCP round-trip still wins. The set is single-shot per handle — + /// taking it here means a subsequent `cancel_by_external_handle` will + /// have to find the pending entry on its own. + async fn take_pre_canceled_handle(&self, handle: &str) -> bool { + let mut state = self.pre_canceled_handles.inner.lock().await; + if state.set.remove(handle) { + // Best-effort companion-side cleanup of `order` so a later + // FIFO eviction doesn't burn a slot. Linear scan is fine — + // PRE_CANCELED_CAP is small. + if let Some(pos) = state.order.iter().position(|h| h == handle) { + state.order.remove(pos); + } + true + } else { + false + } + } + + /// Insert `handle` into the pre-cancel set with FIFO eviction at + /// [`PRE_CANCELED_CAP`]. Idempotent — re-inserting an existing handle + /// is a no-op. + async fn buffer_pre_canceled_handle(&self, handle: String) { + let mut state = self.pre_canceled_handles.inner.lock().await; + if !state.set.insert(handle.clone()) { + return; + } + state.order.push_back(handle); + while state.order.len() > PRE_CANCELED_CAP { + if let Some(evicted) = state.order.pop_front() { + state.set.remove(&evicted); + } + } + } + + /// Forget every pending and recently-consumed tool_call id for the + /// given parent. Called when the parent connection tears down so + /// stale ids don't bind to a future reuse of the same connection_id + /// (UUIDs make that unlikely but cheap to defend against), and so a + /// fresh connection on the reused id is not blocked by the + /// consumed memory of the previous one. + pub async fn drop_pending_tool_calls_for_parent(&self, parent_connection_id: &str) { + self.drop_tool_calls_for_parent(parent_connection_id, false) + .await; + } + + /// Core of the tool_call-tracker drop, shared by the two cancel scopes. + /// + /// * `keep_consumed == false` — genuine connection teardown: remove the + /// whole bucket (`pending` + `consumed`). The connection is going away, + /// so nothing it remembered can mis-bind a future delegation, and a + /// reused connection_id must start clean. + /// * `keep_consumed == true` — turn/prompt cancel with the parent + /// connection STILL ALIVE: TOMBSTONE the cancelled turn's unclaimed + /// `pending` ids into `consumed` and RETAIN the existing `consumed`. Both + /// the already-claimed ids AND the just-cancelled turn's unclaimed ids + /// must keep rejecting a host re-emit (e.g. a terminal status-flip): the + /// Tier-1 consumed check in `register_pending_tool_call_with_key_at` drops + /// the re-emit, so a stale id can't re-register as fresh `pending` and + /// mis-bind the next same-key delegation on this live connection. Merely + /// CLEARING the unclaimed ids would leave them re-registerable, reopening + /// that hole for the unclaimed half (the claimed half was already safe via + /// `consumed`). Retention is connection-scoped and released on teardown — + /// the same unbounded-but-bounded-by-delegation-count envelope `consumed` + /// already lives in for normal end_turn delegations (see + /// [`ToolCallTrackerBucket`]). + /// + /// Tombstoning ALL of `pending` here is safe (no turn/generation tag + /// needed): `run_conversation_loop` drives at most ONE `session/prompt` + /// future per connection at a time (see `acp/connection.rs`), and a + /// parent-side `tool_call` only streams while its prompt future is in + /// flight, so every `pending` id belongs to the single active turn — the one + /// being cancelled — or is a stale leftover from an earlier turn that should + /// be tombstoned regardless. (The per-connection `prompt_lock` only + /// serializes the prompt-SEND handshake, not the turn, so it is NOT the + /// source of this invariant.) The cancelled turn's serialized MCP round-trip + /// won't arrive after cancel, so nothing legitimate is lost. + async fn drop_tool_calls_for_parent(&self, parent_connection_id: &str, keep_consumed: bool) { + let mut map = self.tool_calls.inner.lock().await; + if !keep_consumed { + map.remove(parent_connection_id); + return; + } + if let Some(bucket) = map.get_mut(parent_connection_id) { + // Tombstone the cancelled turn's unclaimed pending ids into + // `consumed` rather than just dropping them, so a later host re-emit + // of one is rejected by the Tier-1 consumed check instead of + // re-registering as a claimable stale entry. `drain` empties + // `pending` first so the subsequent `consumed` borrow is disjoint. + let now = Instant::now(); + let cleared: Vec = bucket.pending.drain(..).map(|p| p.tool_call_id).collect(); + for id in cleared { + if !bucket.consumed.iter().any(|(c, _)| c == &id) { + bucket.consumed.push_back((id, now)); + } + } + // Drop the now-empty bucket only when nothing consumed remains — + // otherwise keep it so the retained `consumed` ids keep rejecting + // re-emits for the rest of this connection's lifetime. + if bucket.consumed.is_empty() { + map.remove(parent_connection_id); + } + } + } + + pub async fn set_config(&self, cfg: DelegationConfig) { + let cap_bytes = cfg.completed_cache_cap_bytes; + *self.config.lock().await = cfg; + // Seed the byte cap into the pending-calls bucket so `insert_completed` + // reads it lock-free (it already holds the pending lock). Acquired AFTER + // the config guard above is dropped — sequential, never nested — so no + // path locks `config` under `pending` or vice-versa (deadlock-free). + // Then prune existing per-parent caches: a LOWERED cap must free memory + // now, not lazily on each parent's next completion (which may never + // arrive for an idle parent). + let mut inner = self.pending.inner.lock().await; + inner.completed_cap_bytes = cap_bytes; + inner.enforce_completed_cap_all_parents(); + } + + pub async fn config_snapshot(&self) -> DelegationConfig { + self.config.lock().await.clone() + } + + pub fn set_allow_self_initiate(&self, allow: bool) { + self.allow_self_initiate.store(allow, Ordering::Relaxed); + } + + pub fn allow_self_initiate(&self) -> bool { + self.allow_self_initiate.load(Ordering::Relaxed) + } + + /// If this in-flight setup has been flagged canceled by a parent cancel, + /// deregister it and return true. One lock acquisition; used at the + /// pre-spawn / post-spawn checkpoints in `handle_request`. + async fn take_inflight_cancel(&self, inflight_id: u64) -> bool { + let mut inner = self.pending.inner.lock().await; + if inner.inflight_canceled(inflight_id) { + inner.deregister_inflight(inflight_id); + true + } else { + false + } + } + + /// Drop this setup's in-flight record. Called on each `handle_request` + /// early-return that isn't a park hand-off (the park region deregisters + /// inline, atomically with `calls.insert`). + async fn drop_inflight(&self, inflight_id: u64) { + self.pending + .inner + .lock() + .await + .deregister_inflight(inflight_id); + } + + /// Async entry point for `delegate_to_agent`. Does the bounded setup + /// (claim/depth checks → spawn → send first prompt), registers the task in + /// `running`, and returns a `Running` ack [`DelegationTaskReport`] WITHOUT + /// waiting for the child to finish. The child resolves later via the + /// lifecycle → [`complete_call`] (or a cancel path), which migrates the task + /// into `completed` and wakes any `get_delegation_status` long-poll. + /// + /// Returns a terminal report instead of a `Running` ack in three cases: the + /// child finished during setup (fast/empty turn), a parent cancel reached it + /// mid-setup, or setup itself failed (disabled / depth / spawn / send). + /// + /// All the setup-window race machinery (`setups` / `early_*` / `inflight`) + /// is unchanged — it governs terminals that beat registration, which is + /// orthogonal to whether the caller then blocks. The only change vs. the old + /// `handle_request` is that "park a `oneshot` and await it" becomes "insert a + /// [`RunningTask`] and return the ack." + #[tracing::instrument( + name = "delegation_task", + skip_all, + fields( + parent_connection_id = %req.parent_connection_id, + parent_tool_use_id = %req.parent_tool_use_id, + agent_type = ?req.agent_type, + working_dir = ?req.working_dir, + child_connection_id = tracing::field::Empty, + task_id = tracing::field::Empty, + ) + )] + pub async fn start_delegation(&self, mut req: DelegationRequest) -> DelegationTaskReport { + // Register this setup as the VERY FIRST thing — before the pre-cancel + // check's `.await` and the (possibly multi-second) claim poll — so a + // parent cancel landing ANYWHERE from here to park reaches it, not just + // after park (which is all the `cancel_by_parent*` parked-call drain + // covers on its own). The only residual gap is a cancel firing before + // the broker is even invoked for this request, which no + // in-`handle_request` mechanism can observe. Deregistered on every exit + // path below: each early-return via `drop_inflight` / + // `take_inflight_cancel`, or inline at park (atomically with + // `calls.insert`). + let inflight_id = self + .pending + .inner + .lock() + .await + .register_inflight(&req.parent_connection_id); + // Pre-cancel short-circuit. If the MCP companion already received + // `notifications/cancelled` for this `tools/call` before we even + // started processing (cancel ran ahead of the UDS round-trip), we + // claim the handle from the pre-cancel set and bail without + // spawning anything — the caller will not be receiving our + // response either way (the companion suppresses it per MCP spec). + if let Some(handle) = req.external_handle.as_deref() { + if self.take_pre_canceled_handle(handle).await { + self.drop_inflight(inflight_id).await; + // Bailing here BEFORE the claim path means this delegation never + // consumes the ACP `tool_call_id` the lifecycle keyed for it. As + // keyed entries are retained indefinitely, a leftover would let a + // *later* same-`(agent_type, task, working_dir)` delegation claim + // this canceled call's id and bind its writes/events to the wrong + // card. Drain it now (idempotent; the turn-end tombstone is the + // backstop if the ACP event hasn't registered yet). + if req.parent_tool_use_id.is_empty() { + let key = DelegationMatchKey { + agent_type: req.agent_type, + task: req.task.clone(), + working_dir: req.requested_working_dir.clone(), + }; + let _ = self + .take_matching_tool_call(&req.parent_connection_id, &key) + .await; + } else { + self.consume_explicit_tool_call( + &req.parent_connection_id, + &req.parent_tool_use_id, + ) + .await; + } + return report_err( + req.agent_type, + DelegationError::Canceled { + reason: "canceled before spawn".into(), + }, + None, + ); + } + } + // MCP clients usually don't populate `_meta.tool_use_id`, so the + // listener will pass through an empty string. Claim the matching + // ACP-side `tool_call_id` for this parent by task text — with a brief + // poll loop so an MCP round-trip that out-races the in-process ACP + // `session/update` doesn't fall back to a synthetic id (which breaks + // the parent UI's `parent_tool_use_id` binding). Falls back to a UUID + // placeholder only when no id arrives within the wait budget. + if req.parent_tool_use_id.is_empty() { + let match_key = DelegationMatchKey { + agent_type: req.agent_type, + task: req.task.clone(), + working_dir: req.requested_working_dir.clone(), + }; + let claimed = self + .claim_pending_tool_call_with_brief_wait(&req.parent_connection_id, &match_key) + .await; + let claimed_identityless = matches!(claimed, Some((_, true))); + req.parent_tool_use_id = claimed.map(|(id, _)| id).unwrap_or_else(|| { + tracing::warn!( + "[delegation] synthetic fallback for parent_tool_use_id on conn={} (no ACP tool_call_id arrived within claim budget)", + req.parent_connection_id + ); + format!("delegation-{}", uuid::Uuid::new_v4()) + }); + // The claimed announcement never carried an identity (Cursor's + // "MCP: tool" + "{}" — the wire will not re-send title/arguments): + // restore it NOW, before the multi-second spawn, so the live card + // shows the canonical delegate tool with its real arguments while + // the child is still starting. Hosts whose wire carried the + // identity (keyed or explicit-id claims) are left untouched — a + // reconstructed `raw_input` would clobber host-specific fields. + if claimed_identityless { + let mut raw_input = serde_json::Map::new(); + raw_input.insert("task".into(), serde_json::Value::String(req.task.clone())); + if let Ok(at) = serde_json::to_value(req.agent_type) { + raw_input.insert("agent_type".into(), at); + } + if let Some(dir) = req.requested_working_dir.as_deref() { + raw_input.insert("working_dir".into(), serde_json::Value::String(dir.into())); + } + self.meta_writer + .write_tool_call_identity( + &req.parent_connection_id, + &req.parent_tool_use_id, + crate::acp::delegation::DELEGATE_TOOL_REWRITE_TITLE, + serde_json::Value::Object(raw_input), + ) + .await; + } + } else { + // The client gave us the real ACP tool_call_id directly + // (`_meta.tool_use_id`), so we skip the claim path — but the + // lifecycle dispatcher may already have registered that same id as + // a (now indefinitely-retained) keyed pending entry. Consume it so + // it can't linger and be mis-claimed by a later same-key + // delegation. Idempotent and order-independent (see the method). + self.consume_explicit_tool_call(&req.parent_connection_id, &req.parent_tool_use_id) + .await; + } + let cfg = self.config_snapshot().await; + if !cfg.enabled { + self.drop_inflight(inflight_id).await; + return report_err( + req.agent_type, + DelegationError::Canceled { + reason: "delegation disabled".into(), + }, + None, + ); + } + + // --- Depth pre-check ---------------------------------------------------- + // We walk up to `limit + 1` so we know whether the *new* child would + // sit at >= limit. Cycles/dead chains saturate at the cap. + let lookup = self.depth_lookup.clone(); + let parent_depth = match crate::acp::delegation::depth::compute_depth( + req.parent_conversation_id, + |id| { + let lookup = lookup.clone(); + async move { lookup.parent_of(id).await } + }, + cfg.depth_limit + 1, + ) + .await + { + Ok(d) => d, + Err(e) => { + self.drop_inflight(inflight_id).await; + return report_err(req.agent_type, e, None); + } + }; + // The child the broker is about to create would sit at `parent_depth + 1`. + // Reject only when the *child* depth would strictly exceed the limit; + // a child sitting exactly at `depth_limit` is allowed. + if parent_depth + 1 > cfg.depth_limit { + self.drop_inflight(inflight_id).await; + return report_err( + req.agent_type, + DelegationError::DepthLimitExceeded { + current_depth: parent_depth, + limit: cfg.depth_limit, + }, + None, + ); + } + + // --- Spawn child connection -------------------------------------------- + // Pull per-agent overrides from the broker config (defaults to empty). + // Cloning is cheap — `AgentDelegationDefaults` is at most one Option + // and a small BTreeMap, and the spawner consumes both fields by value. + let (preferred_mode_id, preferred_config_values) = cfg + .agent_defaults + .get(&req.agent_type) + .map(|d: &AgentDelegationDefaults| (d.mode_id.clone(), d.config_values.clone())) + .unwrap_or((None, BTreeMap::new())); + // Checkpoint #1 (opportunistic): if a parent cancel already landed + // during the claim/depth phase, bail before spawning a child the parent + // has abandoned. No child exists yet, so there's nothing to tear down. + if self.take_inflight_cancel(inflight_id).await { + return report_err( + req.agent_type, + DelegationError::Canceled { + reason: "parent canceled".into(), + }, + None, + ); + } + let child_connection_id = match self + .spawner + .spawn( + &req.parent_connection_id, + req.agent_type, + req.working_dir.clone(), + preferred_mode_id, + preferred_config_values, + ) + .await + { + Ok(id) => id, + Err(e) => { + self.drop_inflight(inflight_id).await; + return report_err( + req.agent_type, + DelegationError::SpawnFailed(e.to_string()), + None, + ); + } + }; + + // Checkpoint #2: a parent cancel that landed during spawn() — the child + // now exists but no prompt has been sent, so disconnect it (mirroring + // the send-failure path's disconnect-only teardown) and bail. This is + // the primary guard for the spawn window, which can block while the + // agent process starts up. + if self.take_inflight_cancel(inflight_id).await { + let _ = self.spawner.disconnect(&child_connection_id).await; + return report_err( + req.agent_type, + DelegationError::Canceled { + reason: "parent canceled".into(), + }, + None, + ); + } + + // --- Send linked prompt ------------------------------------------------ + let call_id = uuid::Uuid::new_v4().to_string(); + // Bounded task label used by the started event and every meta write — + // the frontend card's fallback when the parent tool call's `raw_input` + // never carried the arguments (Cursor's identity-less announcements). + let task_preview = truncate_on_char_boundary(&req.task, TASK_PREVIEW_CAP); + // Now that the child connection and task id exist, fill the span's empty + // fields so every subsequent log line in this delegation carries the + // parent→child linkage (see the `delegation_task` span on this fn). + tracing::Span::current().record("child_connection_id", child_connection_id.as_str()); + tracing::Span::current().record("task_id", call_id.as_str()); + let link = DelegationLink { + parent_conversation_id: req.parent_conversation_id, + parent_tool_use_id: req.parent_tool_use_id.clone(), + delegation_call_id: call_id.clone(), + }; + + // Reserve this delegation (both ids) BEFORE sending its first prompt. + // `send_prompt_linked_for_delegation` persists the delegation link onto + // the child row (arming the lifecycle resolver) AND dispatches the + // prompt — after which a fast/empty turn's `TurnComplete` OR an + // immediate child-connection failure can fire before we park the pending + // entry below. The reservation lets those terminal events buffer their + // outcome (see `PendingInner`) for the park to drain, rather than + // no-oping and stranding `rx.await`. There is no `.await` between this + // reservation and `send_prompt` (so nothing the child does can be + // observed before the reservation is in place); it's cleared at park or + // on the send-failure path. Reserving by `call_id` AND + // `child_connection_id` lets each resolver gate on the id it holds — + // `complete_call` the `call_id`, `cancel_by_child_connection` the + // `child_connection_id`. + self.pending + .inner + .lock() + .await + .reserve(&call_id, &child_connection_id); + + let child_conversation_id = match self + .spawner + .send_prompt_linked_for_delegation(&child_connection_id, req.task.clone(), link) + .await + { + Ok(cid) => cid, + Err(e) => { + // Setup failed before parking — release the reservation (and + // discard any terminal that buffered against this delegation in + // the window) so nothing lingers or mis-binds a future id, and + // drop the in-flight record in the same lock acquisition. + { + let mut inner = self.pending.inner.lock().await; + inner.unreserve(&call_id, &child_connection_id); + inner.deregister_inflight(inflight_id); + } + let _ = self.spawner.disconnect(&child_connection_id).await; + return report_err( + req.agent_type, + DelegationError::SpawnFailed(e.to_string()), + None, + ); + } + }; + + // The child is now running. Stamp the start so terminal paths can + // report a real `duration_ms`. + let started_at = Instant::now(); + + // --- Mark the parent's tool call as in-flight ------------------------- + // The frontend's DelegationContext seeds its `parent_tool_use_id`-keyed + // binding map from this meta on snapshot replay, so a page refresh + // mid-delegation can reconstruct the child connection / conversation + // ids without depending on the live `delegation_started` event having + // been received. + self.write_meta_if_real( + &req.parent_connection_id, + &req.parent_tool_use_id, + build_delegation_meta( + "running", + Some(&child_connection_id), + Some(child_conversation_id), + None, + None, + // No meaningful elapsed yet — the child just started. + None, + Some(&task_preview), + Some(&call_id), + ), + ) + .await; + + // Announce the live delegation on the PARENT's event stream so the + // frontend `DelegationContext` binds the child inline and attaches its + // live sub-thread. Symmetric with the terminal `emit_completed_if_real`, + // and — unlike the removed child-stream emit in `send_prompt_linked` — + // delivered on a stream the parent is already attached to in web/server + // mode, carrying the real `parent_connection_id`. + self.emit_started_if_real( + &req.parent_connection_id, + &req.parent_tool_use_id, + &child_connection_id, + child_conversation_id, + req.agent_type, + &task_preview, + &call_id, + ) + .await; + + // --- Register pending, or resolve a terminal that beat us ------------- + // Under a single lock, decide this delegation's fate atomically against + // everything a concurrent resolver may have recorded while we were + // setting up: + // * a child terminal buffered against the reservation — a + // `TurnComplete` via `complete_call` (keyed by `call_id`) OR a child + // failure via `cancel_by_child_connection` (keyed by + // `child_connection_id`); either can race ahead of this park; or + // * a parent cancel that flagged this in-flight setup + // (`mark_inflight_canceled_for_parent`, which runs in the SAME lock + // acquisition that drains the parked `calls`). + // Precedence: strict first-terminal-wins by arrival stamp. Both a child + // terminal and a parent cancel carry the `seq` clock value they were + // recorded at, so whichever landed FIRST wins — a child that completed + // before the cancel keeps its result; a cancel that beat the completion + // discards it (the parent had already abandoned the turn). Ties are + // impossible: every event draws a distinct stamp under this one lock. + // Only when NOTHING beat us do we park for a future resolver, + // deregistering the in-flight record adjacent to `calls.insert` with no + // `.await` between — so a parent cancel serialized AFTER us finds the + // entry in `calls` and drains it, while one serialized BEFORE us is seen + // here via its stamp. When a terminal/cancel DID beat us we deliberately + // DON'T park: resolving inline (never leaving an entry for a second + // resolver to grab) rules out a double-finalize. + enum Disposition { + ChildTerminal(DelegationOutcome), + ParentCanceled, + Running, + } + // Near-zero elapsed for these setup-window races, but measured for + // consistency with the normal terminal paths. + let setup_duration_ms = started_at.elapsed().as_millis() as u64; + let disposition = { + let mut inner = self.pending.inner.lock().await; + // Each buffered child terminal carries (arrival_stamp, outcome). + let child_terminal: Option<(u64, DelegationOutcome)> = + if let Some((stamp, outcome)) = inner.take_early_complete(&call_id) { + Some((stamp, outcome)) + } else { + inner + .take_early_cancel(&child_connection_id) + .map(|(stamp, reason)| { + ( + stamp, + DelegationOutcome::from_err( + DelegationError::Canceled { reason }, + Some(child_conversation_id), + ), + ) + }) + }; + let parent_canceled_at = inner.inflight_canceled_at(inflight_id); + inner.unreserve(&call_id, &child_connection_id); + // For both terminal dispositions we record the completed result + // INSIDE this lock (atomically with unreserve/deregister) so a + // concurrent `get_delegation_status` can never observe the task as + // neither running nor completed. The `Running` arm inserts the live + // task instead of parking a `oneshot` — the caller returns the ack. + let record = |inner: &mut PendingInner, outcome: &DelegationOutcome| { + inner.insert_completed( + &call_id, + build_completed( + &req.parent_connection_id, + child_conversation_id, + req.agent_type, + setup_duration_ms, + outcome, + ), + ); + }; + match (child_terminal, parent_canceled_at) { + // Both raced in the setup window: the earlier arrival stamp wins. + (Some((child_stamp, outcome)), Some(cancel_stamp)) => { + inner.deregister_inflight(inflight_id); + if child_stamp < cancel_stamp { + record(&mut inner, &outcome); + Disposition::ChildTerminal(outcome) + } else { + record( + &mut inner, + &canceled_outcome(child_conversation_id, "parent canceled"), + ); + Disposition::ParentCanceled + } + } + // Only a child terminal fired. + (Some((_, outcome)), None) => { + inner.deregister_inflight(inflight_id); + record(&mut inner, &outcome); + Disposition::ChildTerminal(outcome) + } + // Only a parent cancel fired. + (None, Some(_)) => { + inner.deregister_inflight(inflight_id); + record( + &mut inner, + &canceled_outcome(child_conversation_id, "parent canceled"), + ); + Disposition::ParentCanceled + } + // Nothing beat us — register the running task for a future + // resolver, deregistering the in-flight record adjacent to the + // insert with no `.await` between (so a parent cancel serialized + // AFTER us finds it in `running` and drains it). + (None, None) => { + inner.running.insert( + call_id.clone(), + RunningTask { + child_connection_id: child_connection_id.clone(), + child_conversation_id, + parent_connection_id: req.parent_connection_id.clone(), + parent_tool_use_id: req.parent_tool_use_id.clone(), + agent_type: req.agent_type, + task_preview: task_preview.clone(), + task_id: call_id.clone(), + external_handle: req.external_handle.clone(), + started_at, + last_surfaced_block: None, + }, + ); + inner.deregister_inflight(inflight_id); + Disposition::Running + } + } + }; + + match disposition { + // A child terminal beat registration. Finalize (terminal meta + + // DelegationCompleted event + child teardown) and return the + // terminal report directly. The completed entry was recorded under + // the disposition lock above; wake any long-poll waiter. + Disposition::ChildTerminal(outcome) => { + self.finalize_delegation( + &req.parent_connection_id, + &req.parent_tool_use_id, + &child_connection_id, + child_conversation_id, + req.agent_type, + setup_duration_ms, + &outcome, + &task_preview, + &call_id, + ) + .await; + self.result_notify.notify_waiters(); + return report_from_outcome( + Some(call_id), + Some(req.agent_type), + &outcome, + Some(setup_duration_ms), + ); + } + // A parent cancel reached this delegation mid-setup — after the + // prompt was sent, before we registered. Tear the child down + // ourselves (cancel + disconnect, since a turn is in flight) and + // return a canceled report. The canceled result was recorded above. + Disposition::ParentCanceled => { + self.write_meta_if_real( + &req.parent_connection_id, + &req.parent_tool_use_id, + build_delegation_meta( + "failed", + Some(&child_connection_id), + Some(child_conversation_id), + Some("canceled"), + None, + Some(setup_duration_ms), + Some(&task_preview), + Some(&call_id), + ), + ) + .await; + self.emit_completed_if_real( + &req.parent_connection_id, + &req.parent_tool_use_id, + &child_connection_id, + child_conversation_id, + req.agent_type, + DelegationResultSummary::Err { + error_code: "canceled".to_string(), + }, + ) + .await; + let _ = self.spawner.cancel(&child_connection_id).await; + let _ = self.spawner.disconnect(&child_connection_id).await; + self.result_notify.notify_waiters(); + return report_from_outcome( + Some(call_id), + Some(req.agent_type), + &canceled_outcome(child_conversation_id, "parent canceled"), + Some(setup_duration_ms), + ); + } + // Registered in `running` — fall through to the second pre-cancel + // check, then return the ack. + Disposition::Running => {} + } + + // Second pre-cancel check: a `notifications/cancelled` may have landed + // between the entry-side check and the `running` registration above. If + // so, drain the task ourselves (so a racing `cancel_by_external_handle` + // doesn't double-finalize), record the canceled result, and return a + // canceled report instead of the Running ack. + if let Some(handle) = req.external_handle.as_deref() { + if self.take_pre_canceled_handle(handle).await { + // Capture the elapsed ONCE at terminalization (under the lock, + // when the running task is removed) so the completed-cache, the + // parent-card meta, and the returned report all report the same + // duration. `None` when nothing was drained. + let canceled_duration_ms = { + let mut inner = self.pending.inner.lock().await; + if inner.running.remove(&call_id).is_some() { + let outcome = + canceled_outcome(child_conversation_id, "canceled before await"); + let duration_ms = started_at.elapsed().as_millis() as u64; + inner.insert_completed( + &call_id, + build_completed( + &req.parent_connection_id, + child_conversation_id, + req.agent_type, + duration_ms, + &outcome, + ), + ); + Some(duration_ms) + } else { + None + } + }; + if let Some(duration_ms) = canceled_duration_ms { + self.write_meta_if_real( + &req.parent_connection_id, + &req.parent_tool_use_id, + build_delegation_meta( + "failed", + Some(&child_connection_id), + Some(child_conversation_id), + Some("canceled"), + None, + Some(duration_ms), + Some(&task_preview), + Some(&call_id), + ), + ) + .await; + self.emit_completed_if_real( + &req.parent_connection_id, + &req.parent_tool_use_id, + &child_connection_id, + child_conversation_id, + req.agent_type, + DelegationResultSummary::Err { + error_code: "canceled".to_string(), + }, + ) + .await; + let _ = self.spawner.cancel(&child_connection_id).await; + let _ = self.spawner.disconnect(&child_connection_id).await; + self.result_notify.notify_waiters(); + return report_from_outcome( + Some(call_id), + Some(req.agent_type), + &canceled_outcome(child_conversation_id, "canceled before await"), + Some(duration_ms), + ); + } + } + } + + // Registered and running in the background — return the ack. The child + // resolves later via the lifecycle → `complete_call` (or a cancel path). + running_ack(call_id, child_conversation_id, req.agent_type) + } + + /// Called by the child-session lifecycle subscriber on `TurnComplete` + /// (success path) or by error mappers (failure path). + /// + /// Migrates the task from `running` into `completed` (atomically, under one + /// lock) and then finalizes (terminal meta + `DelegationCompleted` event + + /// child teardown) and wakes any `get_delegation_status` long-poll. + /// + /// If no entry is in `running` under `call_id`, the outcome is buffered for + /// a racing `start_delegation` to drain at registration — but ONLY while the + /// delegation is still reserved (mid-setup). This closes the window where a + /// fast/empty turn's `TurnComplete` propagates through the lifecycle while + /// `start_delegation` is still between `send_prompt` and the `running` + /// insert: the prompt is only *enqueued* by `send_prompt`, and the child + /// loop emits `TurnComplete` independently, so a completion CAN beat it. When + /// the `call_id` is no longer reserved the call was already resolved by + /// another terminal path, so the buffer is skipped (silent no-op). + pub async fn complete_call(&self, call_id: &str, outcome: DelegationOutcome) { + let task = { + let mut inner = self.pending.inner.lock().await; + match inner.running.remove(call_id) { + Some(task) => { + // Atomic running → completed so a concurrent status query + // never sees the task as neither running nor completed. + let duration_ms = task.started_at.elapsed().as_millis() as u64; + inner.insert_completed( + call_id, + build_completed( + &task.parent_connection_id, + task.child_conversation_id, + task.agent_type, + duration_ms, + &outcome, + ), + ); + Some((task, duration_ms)) + } + None => { + // Buffer for the racing `start_delegation` to drain iff still + // reserved (mid-setup); a no-op otherwise, so the clone only + // materializes on the genuine pre-registration race. + inner.buffer_early_complete(call_id, outcome.clone()); + None + } + } + }; + if let Some((task, duration_ms)) = task { + self.finalize_delegation( + &task.parent_connection_id, + &task.parent_tool_use_id, + &task.child_connection_id, + task.child_conversation_id, + task.agent_type, + duration_ms, + &outcome, + &task.task_preview, + &task.task_id, + ) + .await; + self.result_notify.notify_waiters(); + } + } + + /// Write the terminal meta, emit `DelegationCompleted`, and tear down the + /// child for a resolved delegation. Shared by `complete_call` and + /// `start_delegation`'s early-terminal pickup. Mirrors the resolution onto + /// the parent's `delegate_to_agent` ToolCallState meta (including a bounded + /// `text_preview` on the completed path so a post-refresh snapshot renders + /// the result inline) so snapshot recovery shows the final state without the + /// live `delegation_completed` event. Does not touch the pending maps — the + /// caller owns the `running` → `completed` migration. + /// + /// `duration_ms` is the broker-measured elapsed time (from `started_at`), + /// carried onto the event summary so the parent UI shows a real duration. + #[allow(clippy::too_many_arguments)] + async fn finalize_delegation( + &self, + parent_connection_id: &str, + parent_tool_use_id: &str, + child_connection_id: &str, + child_conversation_id: i32, + agent_type: AgentType, + duration_ms: u64, + outcome: &DelegationOutcome, + task_preview: &str, + task_id: &str, + ) { + let meta = match outcome { + DelegationOutcome::Ok(ok) => build_delegation_meta( + "completed", + Some(child_connection_id), + Some(child_conversation_id), + None, + build_text_preview(&ok.text).as_deref(), + Some(duration_ms), + Some(task_preview), + Some(task_id), + ), + DelegationOutcome::Err { code, .. } => build_delegation_meta( + "failed", + Some(child_connection_id), + Some(child_conversation_id), + Some(code), + None, + Some(duration_ms), + Some(task_preview), + Some(task_id), + ), + }; + self.write_meta_if_real(parent_connection_id, parent_tool_use_id, meta) + .await; + self.emit_completed_if_real( + parent_connection_id, + parent_tool_use_id, + child_connection_id, + child_conversation_id, + agent_type, + outcome_to_summary(outcome, duration_ms), + ) + .await; + // v1 one-shot: always tear down the child. + let _ = self.spawner.disconnect(child_connection_id).await; + } + + /// Internal helper — apply the meta write iff the parent's + /// `tool_use_id` refers to a real ACP `tool_call_id`. The + /// broker-synthesized `"delegation-"` placeholder targets no + /// ToolCallState, so emitting a `ToolCallUpdate` against it would be + /// noise that the frontend would route through `apply_tool_call_update` + /// to a non-existent entry. See `meta_writer::is_synthetic_parent_tool_use_id`. + async fn write_meta_if_real( + &self, + parent_connection_id: &str, + parent_tool_use_id: &str, + meta: serde_json::Value, + ) { + if is_synthetic_parent_tool_use_id(parent_tool_use_id) { + return; + } + self.meta_writer + .write_meta(parent_connection_id, parent_tool_use_id, meta) + .await; + } + + /// Internal helper — emit `AcpEvent::DelegationStarted` on the parent's + /// stream iff the `parent_tool_use_id` refers to a real ACP tool_call. + /// Mirror of `emit_completed_if_real`: same synthetic-id skip, and the + /// event rides the parent's stream so the frontend `DelegationContext` + /// receives it via the parent's per-connection attach stream in + /// web/server mode (not only via the desktop firehose). + #[allow(clippy::too_many_arguments)] + async fn emit_started_if_real( + &self, + parent_connection_id: &str, + parent_tool_use_id: &str, + child_connection_id: &str, + child_conversation_id: i32, + agent_type: AgentType, + task_preview: &str, + task_id: &str, + ) { + if is_synthetic_parent_tool_use_id(parent_tool_use_id) { + return; + } + self.event_emitter + .emit_started( + parent_connection_id, + parent_tool_use_id, + child_connection_id, + child_conversation_id, + agent_type, + task_preview, + task_id, + ) + .await; + } + + /// Internal helper — emit `AcpEvent::DelegationCompleted` on the parent's + /// stream iff the `parent_tool_use_id` refers to a real ACP tool_call. + /// Synthetic ids (the `"delegation-"` UUID fallback) map to no + /// live UI binding, so the emit would be wasted noise — same skip + /// criterion as `write_meta_if_real`. + async fn emit_completed_if_real( + &self, + parent_connection_id: &str, + parent_tool_use_id: &str, + child_connection_id: &str, + child_conversation_id: i32, + agent_type: AgentType, + result: DelegationResultSummary, + ) { + if is_synthetic_parent_tool_use_id(parent_tool_use_id) { + return; + } + self.event_emitter + .emit_completed( + parent_connection_id, + parent_tool_use_id, + child_connection_id, + child_conversation_id, + agent_type, + result, + ) + .await; + } + + /// Cancel the pending delegation whose `external_handle` matches. + /// Called by the MCP listener on receipt of `notifications/cancelled` + /// from a companion. When no matching pending entry exists (the + /// cancel arrived before `handle_request` reached the + /// pending-registration phase) the handle is stashed in + /// `pre_canceled_handles` so the in-flight request can drain itself + /// when it tries to register or shortly after. + pub async fn cancel_by_external_handle(&self, external_handle: &str, reason: String) { + let drained = { + let mut inner = self.pending.inner.lock().await; + let keys: Vec = inner + .running + .iter() + .filter(|(_, v)| v.external_handle.as_deref() == Some(external_handle)) + .map(|(k, _)| k.clone()) + .collect(); + drain_and_record_canceled(&mut inner, keys, &reason) + }; + if drained.is_empty() { + // Race: the cancel beat the handle's `running` registration. Buffer + // it (capped, FIFO-evicted) so `start_delegation` can drain itself on + // the next checkpoint instead of proceeding to spawn the child. + self.buffer_pre_canceled_handle(external_handle.to_string()) + .await; + return; + } + for (task, duration_ms) in drained { + // A turn is in flight, so cancel + disconnect. + self.teardown_canceled_child(&task, duration_ms, true).await; + } + self.result_notify.notify_waiters(); + } + + /// Resolve the pending delegation whose child matches + /// `child_connection_id` with a `canceled` outcome. Used when a child + /// session disconnects or errors out without firing a clean + /// TurnComplete — the parent's `tool_use_id` shouldn't dangle. + /// No-op when no matching entry exists. + /// + /// `terminal_error` carries the child connection's last `AcpEvent::Error` + /// detail when the lifecycle worker is dispatching off an `Error` event + /// (vs. a bare `Disconnected`). When present, it gets appended to the + /// `Canceled { reason }` string so the parent agent's tool-call result + /// surfaces the real cause (e.g. "Authentication required", + /// "transport closed") instead of the opaque default. Falls back to + /// the default reason when `None`. + pub async fn cancel_by_child_connection( + &self, + child_connection_id: &str, + terminal_error: Option<&str>, + ) { + let reason = child_canceled_reason(terminal_error); + let drained = { + let mut inner = self.pending.inner.lock().await; + let keys: Vec = inner + .running + .iter() + .filter(|(_, v)| v.child_connection_id == child_connection_id) + .map(|(k, _)| k.clone()) + .collect(); + if keys.is_empty() { + // No running entry. If the child is still reserved, + // `start_delegation` is mid-setup and this failure beat the + // `running` insert — buffer its detail for it to drain at + // registration instead of no-oping. `buffer_child_failure` is a + // no-op when the child isn't reserved, so a normal + // post-resolution child teardown accumulates nothing. + inner.buffer_child_failure( + child_connection_id, + terminal_error.map(|s| s.to_string()), + ); + Vec::new() + } else { + drain_and_record_canceled(&mut inner, keys, &reason) + } + }; + for (task, duration_ms) in drained { + // The child already disconnected/errored — disconnect-only teardown + // (no spawner `cancel`, there's no live turn to interrupt). + self.teardown_canceled_child(&task, duration_ms, false).await; + } + self.result_notify.notify_waiters(); + } + + /// Cascade-cancel every pending delegation owned by `parent_connection_id` + /// when the parent **connection tears down** (disconnect / `run_connection` + /// exit). Drops the parent's entire tool_call tracker bucket (`pending` + + /// `consumed`) since the connection is going away. Runs fully inline — the + /// connection is already exiting, so there is no next prompt to unblock. + pub async fn cancel_by_parent(&self, parent_connection_id: &str) { + let drained = self + .drain_for_parent_cancel(parent_connection_id, false) + .await; + self.finalize_parent_cancel(drained).await; + } + + /// Cascade-cancel every pending delegation owned by `parent_connection_id` + /// for a **turn/prompt cancel** where the parent connection STAYS ALIVE + /// (a non-`end_turn` turn end, or a user Cancel between/within prompts). + /// + /// The fast, turn-scoped part — tombstoning the tool_call tracker and + /// removing this parent's parked calls — runs SYNCHRONOUSLY: the caller + /// awaits it before the connection loop accepts the next prompt, so it can't + /// race a next-turn registration and tombstone/cancel that turn's legitimate + /// entries (the safety the `drop_tool_calls_for_parent` invariant relies + /// on). Only the slow child teardown (meta/emit + spawner `cancel` / + /// `disconnect`, which can block on slow agents) is backgrounded, so the + /// user-visible Cancel path stays responsive. + /// + /// RETAINS the parent's `consumed` tool_call memory (and tombstones the + /// cancelled turn's unclaimed `pending` ids into it): dropping it would let + /// a host re-emit of an already-handled `tool_call_id` re-register and + /// mis-bind the next same-key delegation on this live connection — see + /// `drop_tool_calls_for_parent`. + pub async fn cancel_by_parent_turn(&self, parent_connection_id: &str) { + let drained = self + .drain_for_parent_cancel(parent_connection_id, true) + .await; + // The fast drain above already ran inline (scoped to the just-ended + // turn); background only the slow child teardown. + let broker = self.clone(); + tokio::spawn(async move { + broker.finalize_parent_cancel(drained).await; + }); + } + + /// Fast, lock-guarded part of a parent cancel: drop/tombstone this parent's + /// tool_call tracker (per `keep_consumed`, see `drop_tool_calls_for_parent`) + /// and remove every running task it owns, returning them for the (slow) + /// child teardown. Touches only the two broker mutexes — no spawner I/O — so + /// it is safe to await inline in the connection loop before the next prompt + /// is accepted. + /// + /// `keep_consumed` also governs the completed-cache: a **turn** cancel + /// (`true`) records each drained task as `Canceled` so the still-alive + /// connection's LLM can still query it; a **connection teardown** (`false`) + /// drops the parent's whole completed-cache instead — the parent is gone, so + /// nothing will query it. + async fn drain_for_parent_cancel( + &self, + parent_connection_id: &str, + keep_consumed: bool, + ) -> Vec<(RunningTask, u64)> { + // Also drain any tool_call ids captured ahead of an MCP round-trip that + // never arrived — keeps the map bounded across parent reconnects. + // Teardown drops the whole bucket; a turn cancel keeps `consumed` so a + // later re-emit can't mis-bind the next delegation. + self.drop_tool_calls_for_parent(parent_connection_id, keep_consumed) + .await; + let drained = { + let mut inner = self.pending.inner.lock().await; + // Flag every still-in-flight setup this parent owns in the SAME lock + // acquisition that drains its running tasks: a delegation is then + // caught either here (mid-setup → `start_delegation` tears its child + // down at the next checkpoint) or by the running drain below (already + // registered) — there is no interleaving where both miss it. + inner.mark_inflight_canceled_for_parent(parent_connection_id); + let keys: Vec = inner + .running + .iter() + .filter(|(_, v)| v.parent_connection_id == parent_connection_id) + .map(|(k, _)| k.clone()) + .collect(); + if keep_consumed { + // Turn cancel: connection stays alive → keep each canceled + // result queryable. + drain_and_record_canceled(&mut inner, keys, "parent canceled") + } else { + // Connection teardown: just remove the running tasks and drop the + // whole completed-cache for this parent. No completed entry to + // match, but still capture the elapsed once (at drain time) so + // the teardown meta doesn't recompute it later. + let drained: Vec<(RunningTask, u64)> = keys + .into_iter() + .map(|k| { + let task = inner.running.remove(&k).expect("key just observed"); + let duration_ms = task.started_at.elapsed().as_millis() as u64; + (task, duration_ms) + }) + .collect(); + inner.drop_completed_for_parent(parent_connection_id); + drained + } + }; + self.result_notify.notify_waiters(); + drained + } + + /// Slow part of a parent cancel: for each drained task, patch the parent + /// meta, emit `DelegationCompleted`, and tear the child down. The canceled + /// result was already recorded into `completed` (turn cancel) by + /// `drain_for_parent_cancel` under the lock, so this is pure I/O. Split out + /// so a turn cancel can background it without delaying the fast, turn-scoped + /// drain. + async fn finalize_parent_cancel(&self, drained: Vec<(RunningTask, u64)>) { + for (task, duration_ms) in drained { + // A turn was in flight → cancel + disconnect. + self.teardown_canceled_child(&task, duration_ms, true).await; + } + } + + /// Shared canceled-child teardown: best-effort `failed`/`canceled` meta + /// patch (so a parent-side snapshot post-cancel shows the delegation as + /// canceled rather than stuck on "running"), a `DelegationCompleted` err + /// event, then child teardown. `cancel_turn` is `true` when a turn is in + /// flight (cancel + disconnect) and `false` when the child already + /// disconnected/errored (disconnect only). Does NOT touch the pending maps — + /// the caller already migrated the task into `completed`. + /// + /// `duration_ms` is the elapsed captured by `drain_and_record_canceled` at + /// drain time — reused here (not recomputed) so the parent-card meta matches + /// the completed-cache duration the status/cancel cards report, even when + /// this teardown is backgrounded. + async fn teardown_canceled_child( + &self, + task: &RunningTask, + duration_ms: u64, + cancel_turn: bool, + ) { + self.write_meta_if_real( + &task.parent_connection_id, + &task.parent_tool_use_id, + build_delegation_meta( + "failed", + Some(&task.child_connection_id), + Some(task.child_conversation_id), + Some("canceled"), + None, + Some(duration_ms), + Some(&task.task_preview), + Some(&task.task_id), + ), + ) + .await; + self.emit_completed_if_real( + &task.parent_connection_id, + &task.parent_tool_use_id, + &task.child_connection_id, + task.child_conversation_id, + task.agent_type, + DelegationResultSummary::Err { + error_code: "canceled".to_string(), + }, + ) + .await; + if cancel_turn { + let _ = self.spawner.cancel(&task.child_connection_id).await; + } + let _ = self.spawner.disconnect(&task.child_connection_id).await; + } + + /// Backs the `get_delegation_status` tool for a single task id — a thin + /// wrapper over [`Self::get_tasks_status`] so the single- and batch-poll + /// paths share one snapshot/wait implementation. A one-id batch's + /// "any task settled" wake condition is exactly "this task settled", so the + /// blocking semantics are identical to the historical single-task loop. + pub async fn get_task_status( + &self, + parent_connection_id: &str, + parent_conversation_id: Option, + task_id: &str, + wait: StatusWait, + ) -> DelegationTaskReport { + let ids = [task_id.to_string()]; + self.get_tasks_status(parent_connection_id, parent_conversation_id, &ids, wait) + .await + .pop() + .unwrap_or_else(|| unknown_report(task_id)) + } + + /// Wake every parked status long-poll so it can re-probe its children. + /// + /// Called by the lifecycle dispatcher when ANY connection raises or resolves + /// a blocking prompt — permission, question, or plan approval. Cheap and + /// unconditional: these events are rare, and a wake for a connection that + /// isn't anybody's delegation child just re-snapshots and re-parks, exactly + /// like the spurious wakes `get_tasks_status` already tolerates. + pub fn note_blocking_changed(&self) { + self.result_notify.notify_waiters(); + } + + /// Backs the batch `get_delegation_status` tool. Resolves the status of one + /// or many task ids in a single pass — each from the completed-cache, then + /// the running set, then the DB fallback — scoped to the calling parent (a + /// task owned by another parent reports `Unknown`, never leaking it). Returns + /// one report per requested id, in request order. + /// + /// Blocking obeys [`StatusWait`]: `Immediate` returns the first snapshot. + /// `Bounded`/`Infinite` return as soon as ANY requested task is terminal — + /// INCLUDING one already terminal at entry, so a completed result is never + /// held hostage to a long-running sibling (the caller re-polls the + /// still-running ids to collect the rest) — **or as soon as one becomes + /// blocked on a user decision**. Only an all-running, nothing-newly-blocked + /// batch parks: it wakes when a task settles (the running count drops below + /// the total), when a child raises a blocking prompt, or — for `Bounded` — + /// when the deadline elapses. An all-settled batch returns immediately even + /// under `Infinite`, so it never parks forever. + /// + /// The blocked-return is what closes #447. Without it, a child that hits a + /// permission prompt parks the parent's `wait_ms: 0` call for as long as the + /// user takes to notice — indefinitely, for an unattended run — and the + /// orchestrating LLM cannot even report the stall, because "working" and + /// "waiting on a human" look identical from here. Each blocking prompt is + /// surfaced ONCE (see `RunningTask::last_surfaced_block`), so re-polling an + /// already-reported block goes back to waiting rather than spinning. + pub async fn get_tasks_status( + &self, + parent_connection_id: &str, + parent_conversation_id: Option, + task_ids: &[String], + wait: StatusWait, + ) -> Vec { + if task_ids.is_empty() { + return Vec::new(); + } + // A bounded wait gets a single fixed deadline; Immediate and Infinite + // carry none — Immediate returns on the first pass, Infinite parks on + // `result_notify` until a task is terminal or newly blocked. + let deadline = match wait { + StatusWait::Bounded(ms) => Some(Instant::now() + Duration::from_millis(ms)), + StatusWait::Immediate | StatusWait::Infinite => None, + }; + loop { + // Arm the notify BEFORE the snapshot so a completion landing between + // the snapshot and the await isn't lost (enable() registers now). + let notified = self.result_notify.notified(); + tokio::pin!(notified); + notified.as_mut().enable(); + + // One lock acquisition classifies every requested id. The async + // resolution of running (live reply) / not-in-memory (DB) ids is + // deferred to `assemble_reports`, OUTSIDE this lock. + let classes: Vec = { + let inner = self.pending.inner.lock().await; + task_ids + .iter() + .map(|id| classify_locked(&inner, parent_connection_id, id)) + .collect() + }; + let running_count = classes + .iter() + .filter(|c| matches!(c, StatusClass::Running { .. })) + .count(); + + // Probe each running child for a blocking prompt. Done HERE, after + // the pending lock was dropped at the end of the block above and + // before any early return, because it takes the child's + // `SessionState` lock — the same ordering `attach_live_reply` has + // always used. The result rides along to `assemble_reports` so a + // pass never probes the same child twice. + let blocked = self.probe_blocked(&classes).await; + + // Return now when the poll is Immediate, OR when at least one + // requested task is already (or now) terminal — i.e. not EVERY task + // is still running. This honors the contract "returns as soon as ANY + // requested task reaches a terminal state": a mixed [terminal, + // running] batch surfaces the terminal report immediately instead of + // holding it hostage to a long-running sibling, and the caller + // re-polls (narrowing to the still-running ids) to collect the rest. + // `running_count == 0` (all settled) is the special case that also + // makes Infinite safe. The id set is fixed and a task can only LEAVE + // the running map during a wait (never (re)enter), so once a parked + // all-running batch is woken by a settle the count has dropped below + // the total and this returns; a spurious wake (another parent's task) + // re-snapshots all-running and re-parks. + if matches!(wait, StatusWait::Immediate) || running_count < task_ids.len() { + return self + .assemble_reports(parent_conversation_id, task_ids, classes, blocked) + .await; + } + // Every task is still running, but one of them just parked on the + // user. That is not progress and no completion signal is coming + // until a human acts, so stop waiting and say so. The claim marks + // each prompt as surfaced, so the NEXT poll on the same prompt falls + // through to the park below instead of returning instantly. + let claimed = self.claim_new_blocks(task_ids, &blocked).await; + if claimed.any_claimed { + return self + .assemble_reports(parent_conversation_id, task_ids, classes, blocked) + .await; + } + // A `Bounded` wait gives up at its deadline and returns the running + // snapshot. + let now = Instant::now(); + if deadline.is_some_and(|d| now >= d) { + return self + .assemble_reports(parent_conversation_id, task_ids, classes, blocked) + .await; + } + // Park until the next completion signal — bounded by the deadline + // when there is one, and ALWAYS bounded by `retry_at` when a + // suppressed block is waiting to become reportable again. Without + // that second bound an `Infinite` wait would park on a notify that + // nothing is going to fire: a child parked on a permission emits + // nothing further by itself, so the resurface valve would never get + // a chance to run and a report lost in transit would strand the + // caller for good. + let wake_at = match (deadline, claimed.retry_at) { + (Some(d), Some(r)) => Some(d.min(r)), + (d, r) => d.or(r), + }; + match wake_at { + Some(t) => { + let remaining = t.saturating_duration_since(now); + tokio::select! { + _ = &mut notified => {} + _ = tokio::time::sleep(remaining) => {} + } + } + None => { + notified.await; + } + } + // Loop: re-snapshot (a task likely just completed, the deadline + // passed and the next pass returns the running snapshot, or a + // suppressed block is now reportable again). + } + } + + /// Ask each `Running` entry's child what it is blocked on, position-aligned + /// with `classes` (non-running slots are `None`). One probe per child per + /// pass; must be called with the pending lock RELEASED (it takes the child's + /// `SessionState` lock). + async fn probe_blocked(&self, classes: &[StatusClass]) -> Vec> { + let mut out = Vec::with_capacity(classes.len()); + for class in classes { + let blocked = match class { + StatusClass::Running { + child_connection_id, + .. + } => self.live_reply_lookup.blocked_on(child_connection_id).await, + _ => None, + }; + out.push(blocked); + } + out + } + + /// Claim the blocking prompts in `blocked` that are reportable right now, + /// returning whether any was — and, when none was, the earliest [`Instant`] + /// at which one becomes reportable again. + /// + /// This is the ratchet: a `wait_ms: 0` poll returns the first time a child + /// parks, but a re-poll while the SAME prompt is still unanswered finds + /// nothing new and goes back to waiting — otherwise the caller's wait loop + /// would return instantly forever and burn a round-trip per iteration while + /// the user is simply slow to click. A second, different prompt is new + /// again and returns, and so does the same prompt once + /// [`BLOCK_RESURFACE_INTERVAL`] has passed (the delivery-failure valve — see + /// [`RunningTask::last_surfaced_block`]). + /// + /// Positionally aligned with `task_ids`. Silently skips ids no longer in the + /// running map (settled between the snapshot and here) — those return via + /// the terminal path on the next pass anyway. + async fn claim_new_blocks( + &self, + task_ids: &[String], + blocked: &[Option], + ) -> ClaimedBlocks { + let mut out = ClaimedBlocks::default(); + if blocked.iter().all(|b| b.is_none()) { + return out; + } + let now = Instant::now(); + let mut inner = self.pending.inner.lock().await; + for (id, blocked) in task_ids.iter().zip(blocked) { + let Some(blocked) = blocked else { continue }; + let Some(task) = inner.running.get_mut(id) else { + continue; + }; + if let Some(prev) = task.last_surfaced_block.as_ref() { + if prev.request_id == blocked.request_id { + let due = prev.at + self.block_resurface; + if now < due { + // Not reportable yet. Deliberately does NOT refresh + // `at` — that would push the valve out forever under + // repeated polling. + out.retry_at = Some(out.retry_at.map_or(due, |t: Instant| t.min(due))); + continue; + } + } + } + task.last_surfaced_block = Some(SurfacedBlock { + request_id: blocked.request_id.clone(), + at: now, + }); + out.any_claimed = true; + } + out + } + + /// Finish a batch status pass: resolve each [`StatusClass`] into a final + /// report AFTER the pending lock is released. `Running` ids get their latest + /// live reply (or blocking prompt) attached; `NotInMemory` ids fall back to + /// the DB status lookup. Reports come back in `task_ids` order. + /// + /// `blocked` is the already-probed result from [`Self::probe_blocked`] for + /// this same pass, position-aligned with `classes`. + async fn assemble_reports( + &self, + parent_conversation_id: Option, + task_ids: &[String], + classes: Vec, + blocked: Vec>, + ) -> Vec { + let mut out = Vec::with_capacity(classes.len()); + let mut blocked = blocked.into_iter().chain(std::iter::repeat_with(|| None)); + for (id, class) in task_ids.iter().zip(classes) { + let blocked = blocked.next().flatten(); + let report = match class { + StatusClass::Settled(report) => report, + StatusClass::Running { + mut report, + child_connection_id, + } => { + match blocked { + // A blocked child's last reply is stale by definition — + // it is what it said BEFORE it stopped — so the block + // replaces it rather than competing with it. + Some(blocked) => attach_blocked(&mut report, blocked), + None => { + self.attach_live_reply(&mut report, &child_connection_id) + .await + } + } + report + } + StatusClass::NotInMemory => self.status_from_db(parent_conversation_id, id).await, + }; + out.push(report); + } + out + } + + /// Upgrade a running report's bare `"Running."` message with the child's + /// latest one-line activity, so the parent LLM gets a concrete sign of + /// progress it can report in one shot (instead of polling-and-narrating). + /// Called only on the actual running-return paths, AFTER the pending lock is + /// released. A no-op when the lookup has nothing (default Noop lookup, child + /// gone, or no live output yet) — the report stays `"Running."`. + /// + /// The hint goes on its OWN line (`"Running.\nLatest sub-agent reply: …"`), + /// not appended to the marker line. On hosts that persist only the + /// `CallToolResult` content text (e.g. Claude Code), the frontend recognizes + /// a still-running poll by the standalone first line `"Running."` — keeping + /// the child-controlled reply text on a separate line means a *completed* + /// result that merely starts with "Running. …" can never be misread as + /// running. See `textRunningStatus` in `src/lib/delegation-status.ts`. + async fn attach_live_reply( + &self, + report: &mut DelegationTaskReport, + child_connection_id: &str, + ) { + if let Some(reply) = self + .live_reply_lookup + .latest_reply(child_connection_id) + .await + { + report.message = Some(format!("Running.\nLatest sub-agent reply: {reply}")); + } + } + + /// Backs the `cancel_delegation` tool. Cancels a running task owned by the + /// caller (recording it `Canceled` + tearing the child down) and returns the + /// resulting report. A task that already finished returns its terminal + /// report; one not in memory falls back to the DB status (a finished task + /// can't be canceled). Parent-scoped like `get_task_status`. + pub async fn cancel_task_by_id( + &self, + parent_connection_id: &str, + parent_conversation_id: Option, + task_id: &str, + ) -> DelegationTaskReport { + let drained = { + let mut inner = self.pending.inner.lock().await; + if let Some(c) = inner.completed.get(task_id) { + if c.parent_connection_id == parent_connection_id { + return completed_report(task_id, c); + } + return unknown_report(task_id); + } + match inner.running.get(task_id) { + Some(r) if r.parent_connection_id == parent_connection_id => { + drain_and_record_canceled( + &mut inner, + vec![task_id.to_string()], + "canceled by request", + ) + .pop() + } + Some(_) => return unknown_report(task_id), + None => None, + } + }; + match drained { + Some((task, duration_ms)) => { + // A turn is in flight → cancel + disconnect. Reuse the duration + // captured at drain time for both the teardown meta and the + // report, so all three (completed-cache, meta, report) agree. + self.teardown_canceled_child(&task, duration_ms, true).await; + self.result_notify.notify_waiters(); + report_from_outcome( + Some(task_id.to_string()), + Some(task.agent_type), + &canceled_outcome(task.child_conversation_id, "canceled by request"), + Some(duration_ms), + ) + } + None => self.status_from_db(parent_conversation_id, task_id).await, + } + } + + /// DB status fallback for a task evicted from / never in the in-memory maps. + /// Scopes to the caller's conversation: a child whose `parent_id` doesn't + /// match (or when the caller has no active conversation) reports `Unknown`. + async fn status_from_db( + &self, + parent_conversation_id: Option, + task_id: &str, + ) -> DelegationTaskReport { + match self.status_lookup.find_by_call_id(task_id).await { + Some(rec) + if parent_conversation_id.is_some() && rec.parent_id == parent_conversation_id => + { + db_report(task_id, &rec) + } + _ => unknown_report(task_id), + } + } + + /// Test-only shim preserving the old blocking `handle_request` contract over + /// the async path: start the delegation, then block until it reaches a + /// terminal state (driven by the test's `complete_call` / cancel), mapping + /// the terminal report back to a `DelegationOutcome`. Keeps the broker's + /// extensive setup-window race tests exercising the same lifecycle without + /// each rewriting to the start/poll/collect shape. + #[cfg(any(test, feature = "test-utils"))] + pub async fn handle_request(&self, req: DelegationRequest) -> DelegationOutcome { + let parent_connection_id = req.parent_connection_id.clone(); + let parent_conversation_id = Some(req.parent_conversation_id); + let ack = self.start_delegation(req).await; + let task_id = match ack.task_id.clone() { + Some(id) => id, + // Setup failed before a task existed — the ack itself is terminal. + None => return report_to_outcome(&ack), + }; + if ack.status != TaskStatus::Running { + return report_to_outcome(&ack); + } + // Block until terminal via the long-poll path (re-issued so an + // indefinitely-pending task in a test simply parks here, mirroring the + // old unbounded `rx.await`). + loop { + let report = self + .get_task_status( + &parent_connection_id, + parent_conversation_id, + &task_id, + StatusWait::Bounded(3_600_000), + ) + .await; + if report.status != TaskStatus::Running { + return report_to_outcome(&report); + } + } + } + + #[cfg(any(test, feature = "test-utils"))] + pub async fn peek_first_pending_call_id(&self) -> Option { + self.pending + .inner + .lock() + .await + .running + .keys() + .next() + .cloned() + } + + #[cfg(any(test, feature = "test-utils"))] + pub async fn pending_count(&self) -> usize { + self.pending.inner.lock().await.running.len() + } + + /// Count of cached completed results across all parents. + #[cfg(any(test, feature = "test-utils"))] + pub async fn completed_count(&self) -> usize { + self.pending.inner.lock().await.completed.len() + } + + /// Count of in-flight (registered-at-entry, not-yet-parked / not-yet-exited) + /// `handle_request` setups. Should return to 0 on every exit path. + #[cfg(any(test, feature = "test-utils"))] + pub async fn inflight_count(&self) -> usize { + self.pending.inner.lock().await.inflight.len() + } + + /// Count of in-setup (reserved, not-yet-parked) delegations. Each holds one + /// child and one call_id, so this counts both. + #[cfg(any(test, feature = "test-utils"))] + pub async fn reserved_child_count(&self) -> usize { + self.pending.inner.lock().await.setups.len() + } + + #[cfg(any(test, feature = "test-utils"))] + pub async fn reserved_call_count(&self) -> usize { + self.pending.inner.lock().await.setups.len() + } + + #[cfg(any(test, feature = "test-utils"))] + pub async fn early_cancel_count(&self) -> usize { + self.pending.inner.lock().await.early_cancels.len() + } + + #[cfg(any(test, feature = "test-utils"))] + pub async fn early_complete_count(&self) -> usize { + self.pending.inner.lock().await.early_completes.len() + } + + /// First reserved (mid-setup) `call_id`, if any — lets a test resolve a + /// delegation via `complete_call` while it's pinned in the reserve→park + /// window (its entry isn't parked yet, so `peek_first_pending_call_id` + /// can't see it). + #[cfg(any(test, feature = "test-utils"))] + pub async fn peek_reserved_call_id(&self) -> Option { + self.pending + .inner + .lock() + .await + .setups + .keys() + .next() + .cloned() + } +} + +/// `ConversationDepthLookup` over the live `AppDatabase`. Used by the +/// production wiring; tests use the in-module `MockDepth`. +pub struct DbDepthLookup { + pub db: Arc, +} + +#[async_trait] +impl ConversationDepthLookup for DbDepthLookup { + async fn parent_of(&self, conversation_id: i32) -> Result, DelegationError> { + use sea_orm::EntityTrait; + let row = crate::db::entities::conversation::Entity::find_by_id(conversation_id) + .one(&self.db.conn) + .await + .map_err(|e| DelegationError::SubagentRuntimeError(format!("db: {e}")))?; + Ok(row.and_then(|r| r.parent_id)) + } +} + +/// `ChildStatusLookup` over the live `AppDatabase`. Recovers a delegation +/// task's terminal status (NOT its text — child output isn't in codeg's DB) +/// from the child conversation row once its in-memory result was evicted. +pub struct DbChildStatusLookup { + pub db: Arc, +} + +#[async_trait] +impl ChildStatusLookup for DbChildStatusLookup { + async fn find_by_call_id(&self, call_id: &str) -> Option { + let summary = crate::db::service::conversation_service::get_by_delegation_call_id( + &self.db.conn, + call_id, + ) + .await + .ok() + .flatten()?; + // `summary.status` is the serialized `ConversationStatus` string. + let status = match summary.status.as_str() { + "in_progress" => TaskStatus::Running, + "pending_review" | "completed" => TaskStatus::Completed, + "cancelled" => TaskStatus::Canceled, + _ => TaskStatus::Unknown, + }; + Some(ChildStatusRecord { + child_conversation_id: summary.id, + status, + agent_type: summary.agent_type, + parent_id: summary.parent_id, + }) + } +} + +#[cfg(test)] +mod tests { + use super::*; + use crate::acp::delegation::spawner::{mock::MockSpawner, SpawnerError}; + use crate::acp::delegation::types::DelegationSuccess; + use crate::models::AgentType; + + /// Test-only `ConversationDepthLookup` that resolves against a flat + /// (id, parent_id) table. Unknown ids return `Ok(None)` to keep test + /// setup small. + struct MockDepth(Vec<(i32, Option)>); + + #[async_trait] + impl ConversationDepthLookup for MockDepth { + async fn parent_of(&self, id: i32) -> Result, DelegationError> { + Ok(self.0.iter().find(|(c, _)| *c == id).and_then(|(_, p)| *p)) + } + } + + fn shallow_lookup() -> Arc { + // parent conversation is the root — depth = 0, no rejection. + Arc::new(MockDepth(vec![(1, None)])) as Arc + } + + fn request(parent_conv: i32, tool_use: &str) -> DelegationRequest { + DelegationRequest { + parent_connection_id: "parent-conn".into(), + parent_conversation_id: parent_conv, + parent_tool_use_id: tool_use.into(), + agent_type: AgentType::ClaudeCode, + task: "do x".into(), + working_dir: None, + requested_working_dir: None, + external_handle: None, + } + } + + fn request_with_handle(parent_conv: i32, tool_use: &str, handle: &str) -> DelegationRequest { + let mut r = request(parent_conv, tool_use); + r.external_handle = Some(handle.to_string()); + r + } + + /// Bring the broker's `enabled` switch up before driving any test that + /// hits `handle_request`. Production now defaults to `enabled: false`, + /// so a bare `DelegationBroker::new(...)` would short-circuit before + /// parking a pending entry. Tests that assert disabled behavior set + /// their own config explicitly and skip this helper. + async fn enable_delegation(broker: &DelegationBroker) { + broker + .set_config(DelegationConfig { + enabled: true, + ..DelegationConfig::default() + }) + .await; + } + + // -- Task 4.3 ----------------------------------------------------------- + + #[tokio::test] + async fn config_round_trip() { + let broker = DelegationBroker::new( + Arc::new(MockSpawner::new()) as Arc, + shallow_lookup(), + ); + broker + .set_config(DelegationConfig { + enabled: false, + depth_limit: 5, + ..DelegationConfig::default() + }) + .await; + let got = broker.config_snapshot().await; + assert!(!got.enabled); + assert_eq!(got.depth_limit, 5); + } + + #[tokio::test] + async fn disabled_returns_canceled_without_touching_spawner() { + let mock = Arc::new(MockSpawner::new()); + let broker = + DelegationBroker::new(mock.clone() as Arc, shallow_lookup()); + broker + .set_config(DelegationConfig { + enabled: false, + depth_limit: 2, + ..DelegationConfig::default() + }) + .await; + let outcome = broker.handle_request(request(1, "pt-1")).await; + match outcome { + DelegationOutcome::Err { code, .. } => assert_eq!(code, "canceled"), + _ => panic!("expected Err"), + } + assert!(mock.disconnects.lock().await.is_empty()); + } + + // -- Task 4.4: happy path ---------------------------------------------- + + #[tokio::test] + async fn happy_path_returns_ok_after_complete_call() { + let mock = Arc::new(MockSpawner::new()); + mock.queue_spawn(Ok("child-conn-1".into())).await; + mock.queue_send(Ok(42)).await; + let broker = + DelegationBroker::new(mock.clone() as Arc, shallow_lookup()); + enable_delegation(&broker).await; + + let driver = { + let broker = broker.clone(); + tokio::spawn(async move { broker.handle_request(request(1, "pt-1")).await }) + }; + + // Spin until the broker has registered the pending call so the test + // doesn't race the spawn/send awaits. + let call_id = loop { + if let Some(id) = broker.peek_first_pending_call_id().await { + break id; + } + tokio::time::sleep(Duration::from_millis(5)).await; + }; + + broker + .complete_call( + &call_id, + DelegationOutcome::Ok(DelegationSuccess { + text: "4".into(), + child_conversation_id: 42, + child_agent_type: AgentType::Codex, + turn_count: 1, + duration_ms: 50, + token_usage: None, + }), + ) + .await; + + let outcome = driver.await.unwrap(); + match outcome { + DelegationOutcome::Ok(s) => { + assert_eq!(s.text, "4"); + assert_eq!(s.child_conversation_id, 42); + } + other => panic!("expected Ok, got {other:?}"), + } + assert_eq!(broker.pending_count().await, 0); + // complete_call disconnects the child once. + assert_eq!(mock.disconnects.lock().await.as_slice(), &["child-conn-1"]); + } + + /// `StatusWait::Infinite` (the explicit `wait_ms = 0` escape hatch) must + /// park while the task is still running rather than returning the running + /// snapshot, then resolve to the terminal report once the task completes — + /// no matter how long the child takes. + #[tokio::test] + async fn infinite_wait_parks_until_terminal() { + let mock = Arc::new(MockSpawner::new()); + mock.queue_spawn(Ok("child-conn-1".into())).await; + mock.queue_send(Ok(42)).await; + let broker = + DelegationBroker::new(mock.clone() as Arc, shallow_lookup()); + enable_delegation(&broker).await; + + let ack = broker.start_delegation(request(1, "pt-1")).await; + assert_eq!(ack.status, TaskStatus::Running); + let task_id = ack.task_id.clone().expect("running task carries an id"); + + // Infinite wait: parks on the completion signal instead of returning + // the still-running snapshot. + let waiter = { + let broker = broker.clone(); + let task_id = task_id.clone(); + tokio::spawn(async move { + broker + .get_task_status("parent-conn", Some(1), &task_id, StatusWait::Infinite) + .await + }) + }; + + // Give the waiter a beat — it must still be parked, not finished. + tokio::time::sleep(Duration::from_millis(30)).await; + assert!( + !waiter.is_finished(), + "infinite wait must park while the task is running" + ); + + let call_id = loop { + if let Some(id) = broker.peek_first_pending_call_id().await { + break id; + } + tokio::time::sleep(Duration::from_millis(5)).await; + }; + broker + .complete_call( + &call_id, + DelegationOutcome::Ok(DelegationSuccess { + text: "done".into(), + child_conversation_id: 42, + child_agent_type: AgentType::ClaudeCode, + turn_count: 1, + duration_ms: 5, + token_usage: None, + }), + ) + .await; + + let report = waiter.await.unwrap(); + assert_eq!(report.status, TaskStatus::Completed); + assert_eq!(report.text.as_deref(), Some("done")); + } + + /// A running snapshot upgrades its bare `"Running."` message with the child's + /// latest one-line reply when the live-reply lookup has one. + #[tokio::test] + async fn running_status_appends_live_reply_when_available() { + use crate::acp::delegation::live_reply::mock::MockChildLiveReplyLookup; + + let mock = Arc::new(MockSpawner::new()); + mock.queue_spawn(Ok("child-conn-1".into())).await; + mock.queue_send(Ok(42)).await; + let broker = + DelegationBroker::new(mock.clone() as Arc, shallow_lookup()) + .with_live_reply_lookup(Arc::new(MockChildLiveReplyLookup::new(Some( + "Reading config.rs".into(), + )))); + enable_delegation(&broker).await; + + let ack = broker.start_delegation(request(1, "pt-1")).await; + assert_eq!(ack.status, TaskStatus::Running); + let task_id = ack.task_id.clone().expect("running task carries an id"); + + let report = broker + .get_task_status("parent-conn", Some(1), &task_id, StatusWait::Immediate) + .await; + assert_eq!(report.status, TaskStatus::Running); + // The live hint lands on its own line so a content-only host can anchor + // "still running" to the standalone first line "Running.". + assert_eq!( + report.message.as_deref(), + Some("Running.\nLatest sub-agent reply: Reading config.rs") + ); + } + + /// With no live reply (default Noop lookup / child produced nothing yet) the + /// running snapshot stays the bare `"Running."`. + #[tokio::test] + async fn running_status_stays_bare_without_live_reply() { + let mock = Arc::new(MockSpawner::new()); + mock.queue_spawn(Ok("child-conn-1".into())).await; + mock.queue_send(Ok(42)).await; + let broker = + DelegationBroker::new(mock.clone() as Arc, shallow_lookup()); + enable_delegation(&broker).await; + + let ack = broker.start_delegation(request(1, "pt-1")).await; + let task_id = ack.task_id.clone().expect("running task carries an id"); + + let report = broker + .get_task_status("parent-conn", Some(1), &task_id, StatusWait::Immediate) + .await; + assert_eq!(report.status, TaskStatus::Running); + assert_eq!(report.message.as_deref(), Some("Running.")); + } + + // -- Blocked sub-agents (#447) ----------------------------------------- + + fn permission_block(request_id: &str, title: &str) -> BlockedOn { + BlockedOn { + kind: BlockedKind::Permission, + request_id: request_id.into(), + title: Some(title.into()), + } + } + + /// Spin up a broker whose children all report `blocked` (settable later) and + /// one running task on it. Returns `(broker, lookup, task_id)`. + async fn broker_with_blockable_child() -> ( + DelegationBroker, + Arc, + String, + ) { + // The production interval is minutes; every test but the valve one + // wants "effectively never re-surfaces during this test". + broker_with_blockable_child_resurfacing(Duration::from_secs(3600)).await + } + + async fn broker_with_blockable_child_resurfacing( + resurface: Duration, + ) -> ( + DelegationBroker, + Arc, + String, + ) { + use crate::acp::delegation::live_reply::mock::MockChildLiveReplyLookup; + + let mock = Arc::new(MockSpawner::new()); + mock.queue_spawn(Ok("child-conn-1".into())).await; + mock.queue_send(Ok(42)).await; + let lookup = Arc::new(MockChildLiveReplyLookup::new(Some("Reading x".into()))); + let broker = + DelegationBroker::new(mock.clone() as Arc, shallow_lookup()) + .with_live_reply_lookup(lookup.clone()) + .with_block_resurface(resurface); + enable_delegation(&broker).await; + let task_id = broker + .start_delegation(request(1, "pt-1")) + .await + .task_id + .expect("running task carries an id"); + (broker, lookup, task_id) + } + + /// A child parked on a permission reports `Running` + `blocked_on`, and its + /// message says so INSTEAD of the (now stale) live reply. + #[tokio::test] + async fn blocked_child_reports_blocked_on_over_live_reply() { + let (broker, lookup, task_id) = broker_with_blockable_child().await; + lookup.set_blocked(Some(permission_block("req-1", "rm -rf /tmp/x"))); + + let report = broker + .get_task_status("parent-conn", Some(1), &task_id, StatusWait::Immediate) + .await; + + // Status stays wire-stable `running` — the block rides alongside it, so + // a consumer that predates the field still resolves the poll correctly. + assert_eq!(report.status, TaskStatus::Running); + let blocked = report.blocked_on.expect("blocked_on is set"); + assert_eq!(blocked.kind, BlockedKind::Permission); + assert_eq!(blocked.request_id, "req-1"); + let message = report.message.expect("blocked report carries a message"); + // First line must stay the bare running marker (content-only hosts + // anchor on it), with the note on its own second line. + let mut lines = message.lines(); + assert_eq!(lines.next(), Some("Running.")); + assert_eq!( + lines.next(), + Some("Awaiting your decision: rm -rf /tmp/x"), + "the blocked note replaces the live reply, which is stale by definition" + ); + assert!(!message.contains("Latest sub-agent reply")); + } + + /// The whole point of #447: a `wait_ms: 0` (Infinite) wait must NOT park + /// forever behind a permission prompt. Nothing settles this task — if the + /// block didn't wake it, this test would hang. + #[tokio::test] + async fn infinite_wait_returns_when_the_child_becomes_blocked() { + let (broker, lookup, task_id) = broker_with_blockable_child().await; + lookup.set_blocked(Some(permission_block("req-1", "write to /etc/hosts"))); + + let report = broker + .get_task_status("parent-conn", Some(1), &task_id, StatusWait::Infinite) + .await; + + assert_eq!(report.status, TaskStatus::Running); + assert!(report.blocked_on.is_some()); + } + + /// ...but each prompt is surfaced ONCE. A re-poll while the same prompt is + /// still unanswered goes back to waiting instead of returning instantly, + /// which is what keeps an LLM's wait loop from spinning. A *second*, + /// different prompt is new again and returns. + #[tokio::test] + async fn a_reported_block_does_not_return_twice() { + let (broker, lookup, task_id) = broker_with_blockable_child().await; + lookup.set_blocked(Some(permission_block("req-1", "first"))); + + // First observation returns. + let first = broker + .get_task_status("parent-conn", Some(1), &task_id, StatusWait::Infinite) + .await; + assert_eq!(first.blocked_on.map(|b| b.request_id).as_deref(), Some("req-1")); + + // Same prompt, still unanswered: a bounded wait now runs to its deadline + // rather than returning immediately. + let started = Instant::now(); + let second = broker + .get_task_status("parent-conn", Some(1), &task_id, StatusWait::Bounded(120)) + .await; + assert!( + started.elapsed() >= Duration::from_millis(100), + "an already-reported block must not short-circuit the wait" + ); + // It still REPORTS the block on the way out — only the early return is + // suppressed, never the information. + assert!(second.blocked_on.is_some()); + + // A different prompt is a new event and returns early again. + lookup.set_blocked(Some(permission_block("req-2", "second"))); + let started = Instant::now(); + let third = broker + .get_task_status("parent-conn", Some(1), &task_id, StatusWait::Bounded(5_000)) + .await; + assert!( + started.elapsed() < Duration::from_millis(2_000), + "a NEW blocking prompt must wake the wait" + ); + assert_eq!(third.blocked_on.map(|b| b.request_id).as_deref(), Some("req-2")); + } + + /// The delivery-failure valve: marking a block reported is not proof the + /// parent RECEIVED it (the report still has to cross the listener, the + /// companion's stdout and the agent CLI, and a cancelled or aborted + /// `tools/call` discards it silently). So the SAME unanswered prompt + /// becomes reportable again after the resurface interval — otherwise that + /// one lost report was the only one ever offered and the caller is stranded + /// exactly as before #447. + /// + /// Uses `Infinite`, which has no deadline of its own: if the park weren't + /// bounded by the pending resurface, nothing would ever wake it (a blocked + /// child emits nothing further) and this test would hang. + #[tokio::test] + async fn an_undelivered_block_resurfaces_after_the_interval() { + let (broker, lookup, task_id) = + broker_with_blockable_child_resurfacing(Duration::from_millis(150)).await; + lookup.set_blocked(Some(permission_block("req-1", "first"))); + + // First report — imagine this one never reaches the LLM. + let first = broker + .get_task_status("parent-conn", Some(1), &task_id, StatusWait::Infinite) + .await; + assert!(first.blocked_on.is_some()); + + let started = Instant::now(); + let second = broker + .get_task_status("parent-conn", Some(1), &task_id, StatusWait::Infinite) + .await; + assert_eq!( + second.blocked_on.map(|b| b.request_id).as_deref(), + Some("req-1"), + "the same unanswered prompt must become reportable again" + ); + assert!( + started.elapsed() >= Duration::from_millis(120), + "it must WAIT out the interval, not return instantly (that would be the spin)" + ); + } + + /// An unblocked child is unchanged: no `blocked_on`, live reply intact, and + /// an Infinite wait still parks (proven by a Bounded wait running its full + /// deadline out). + #[tokio::test] + async fn unblocked_child_still_parks_and_keeps_its_live_reply() { + let (broker, _lookup, task_id) = broker_with_blockable_child().await; + + let started = Instant::now(); + let report = broker + .get_task_status("parent-conn", Some(1), &task_id, StatusWait::Bounded(120)) + .await; + assert!(started.elapsed() >= Duration::from_millis(100)); + assert!(report.blocked_on.is_none()); + assert_eq!( + report.message.as_deref(), + Some("Running.\nLatest sub-agent reply: Reading x") + ); + } + + // -- Batch get_tasks_status -------------------------------------------- + + /// Queue one spawn+send pair and start a delegation, returning its task id. + /// Each call consumes one queued `(spawn, send)` from the mock. + async fn start_running( + broker: &DelegationBroker, + mock: &MockSpawner, + child_conn: &str, + child_conv: i32, + tool_use: &str, + ) -> String { + mock.queue_spawn(Ok(child_conn.into())).await; + mock.queue_send(Ok(child_conv)).await; + broker + .start_delegation(request(1, tool_use)) + .await + .task_id + .expect("running task carries an id") + } + + /// The single-id batch agrees with `get_task_status` for a completed task — + /// the refactor that routes the single path through `get_tasks_status` keeps + /// the historical contract. + #[tokio::test] + async fn get_tasks_status_single_matches_get_task_status() { + let mock = Arc::new(MockSpawner::new()); + let broker = + DelegationBroker::new(mock.clone() as Arc, shallow_lookup()); + enable_delegation(&broker).await; + let t1 = start_running(&broker, &mock, "child-1", 42, "pt-1").await; + broker + .complete_call( + &t1, + DelegationOutcome::Ok(DelegationSuccess { + text: "done".into(), + child_conversation_id: 42, + child_agent_type: AgentType::Codex, + turn_count: 1, + duration_ms: 7, + token_usage: None, + }), + ) + .await; + + let single = broker + .get_task_status("parent-conn", Some(1), &t1, StatusWait::Immediate) + .await; + let batch = broker + .get_tasks_status( + "parent-conn", + Some(1), + std::slice::from_ref(&t1), + StatusWait::Immediate, + ) + .await; + assert_eq!(batch.len(), 1); + assert_eq!(batch[0].status, single.status); + assert_eq!(batch[0].text, single.text); + assert_eq!(batch[0].task_id, single.task_id); + } + + /// An immediate batch poll resolves a mix of completed / running / unknown + /// tasks in ONE pass, preserving request order. + #[tokio::test] + async fn batch_status_immediate_mixed_preserves_order() { + let mock = Arc::new(MockSpawner::new()); + let broker = + DelegationBroker::new(mock.clone() as Arc, shallow_lookup()); + enable_delegation(&broker).await; + let t1 = start_running(&broker, &mock, "child-1", 1, "pt-1").await; + let t2 = start_running(&broker, &mock, "child-2", 2, "pt-2").await; + broker + .complete_call( + &t1, + DelegationOutcome::Ok(DelegationSuccess { + text: "first".into(), + child_conversation_id: 1, + child_agent_type: AgentType::Codex, + turn_count: 1, + duration_ms: 3, + token_usage: None, + }), + ) + .await; + + let ids = vec![t1.clone(), t2.clone(), "no-such-id".to_string()]; + let reports = broker + .get_tasks_status("parent-conn", Some(1), &ids, StatusWait::Immediate) + .await; + assert_eq!(reports.len(), 3); + assert_eq!(reports[0].status, TaskStatus::Completed); + assert_eq!(reports[0].text.as_deref(), Some("first")); + assert_eq!(reports[0].task_id.as_deref(), Some(t1.as_str())); + assert_eq!(reports[1].status, TaskStatus::Running); + assert_eq!(reports[1].task_id.as_deref(), Some(t2.as_str())); + assert_eq!(reports[2].status, TaskStatus::Unknown); + } + + /// A batch `Infinite` wait returns as soon as ANY requested task settles, + /// leaving the still-running siblings in the snapshot. + #[tokio::test] + async fn batch_infinite_returns_when_any_settles() { + let mock = Arc::new(MockSpawner::new()); + let broker = + DelegationBroker::new(mock.clone() as Arc, shallow_lookup()); + enable_delegation(&broker).await; + let t1 = start_running(&broker, &mock, "child-1", 1, "pt-1").await; + let t2 = start_running(&broker, &mock, "child-2", 2, "pt-2").await; + + let waiter = { + let broker = broker.clone(); + let ids = vec![t1.clone(), t2.clone()]; + tokio::spawn(async move { + broker + .get_tasks_status("parent-conn", Some(1), &ids, StatusWait::Infinite) + .await + }) + }; + tokio::time::sleep(Duration::from_millis(30)).await; + assert!( + !waiter.is_finished(), + "batch infinite wait must park while both tasks run" + ); + + broker + .complete_call( + &t1, + DelegationOutcome::Ok(DelegationSuccess { + text: "first-done".into(), + child_conversation_id: 1, + child_agent_type: AgentType::Codex, + turn_count: 1, + duration_ms: 4, + token_usage: None, + }), + ) + .await; + + let reports = waiter.await.unwrap(); + assert_eq!(reports.len(), 2); + assert_eq!(reports[0].status, TaskStatus::Completed); + assert_eq!(reports[0].text.as_deref(), Some("first-done")); + assert_eq!(reports[1].status, TaskStatus::Running); + } + + /// A batch `Infinite` wait must NOT hold an already-terminal result hostage + /// to a still-running sibling: when a task is terminal at call ENTRY (it + /// completed before the poll), return immediately with the current snapshot + /// rather than parking for the runner. This is the mixed-at-entry case the + /// transition-only wake used to miss — distinct from + /// [`batch_infinite_returns_when_any_settles`] (both running at entry). + #[tokio::test] + async fn batch_infinite_returns_immediately_when_one_already_terminal() { + let mock = Arc::new(MockSpawner::new()); + let broker = + DelegationBroker::new(mock.clone() as Arc, shallow_lookup()); + enable_delegation(&broker).await; + let t1 = start_running(&broker, &mock, "child-1", 1, "pt-1").await; + let t2 = start_running(&broker, &mock, "child-2", 2, "pt-2").await; + // t1 completes BEFORE the poll; t2 keeps running. + broker + .complete_call( + &t1, + DelegationOutcome::Ok(DelegationSuccess { + text: "first-done".into(), + child_conversation_id: 1, + child_agent_type: AgentType::Codex, + turn_count: 1, + duration_ms: 4, + token_usage: None, + }), + ) + .await; + + // Infinite wait, but one task is already terminal at entry → must return + // at once (a bounded timeout guards against the regression: parking here + // would block until t2 settles, which it never does in this test). + let ids = vec![t1.clone(), t2.clone()]; + let reports = tokio::time::timeout( + Duration::from_secs(2), + broker.get_tasks_status("parent-conn", Some(1), &ids, StatusWait::Infinite), + ) + .await + .expect("a batch with an already-terminal task must not park under Infinite"); + assert_eq!(reports.len(), 2); + assert_eq!(reports[0].status, TaskStatus::Completed); + assert_eq!(reports[0].text.as_deref(), Some("first-done")); + assert_eq!(reports[1].status, TaskStatus::Running); + } + + /// A batch `Infinite` wait where NOTHING is running (all ids unknown) must + /// return immediately rather than parking forever. + #[tokio::test] + async fn batch_infinite_all_settled_returns_immediately() { + let mock = Arc::new(MockSpawner::new()); + let broker = + DelegationBroker::new(mock.clone() as Arc, shallow_lookup()); + enable_delegation(&broker).await; + let ids = vec!["nope-1".to_string(), "nope-2".to_string()]; + let reports = tokio::time::timeout( + Duration::from_secs(2), + broker.get_tasks_status("parent-conn", Some(1), &ids, StatusWait::Infinite), + ) + .await + .expect("all-settled infinite batch must not hang"); + assert_eq!(reports.len(), 2); + assert!(reports.iter().all(|r| r.status == TaskStatus::Unknown)); + } + + /// A bounded batch wait with no completion returns the running snapshot once + /// the deadline elapses (the child keeps running; the caller re-polls). + #[tokio::test] + async fn batch_bounded_deadline_returns_running_snapshot() { + let mock = Arc::new(MockSpawner::new()); + let broker = + DelegationBroker::new(mock.clone() as Arc, shallow_lookup()); + enable_delegation(&broker).await; + let t1 = start_running(&broker, &mock, "child-1", 1, "pt-1").await; + let reports = broker + .get_tasks_status("parent-conn", Some(1), &[t1], StatusWait::Bounded(40)) + .await; + assert_eq!(reports.len(), 1); + assert_eq!(reports[0].status, TaskStatus::Running); + } + + /// A task owned by a different parent reports `Unknown` in a batch — never + /// leaking another parent's task, just like the single-task path. + #[tokio::test] + async fn batch_status_scopes_to_parent() { + let mock = Arc::new(MockSpawner::new()); + let broker = + DelegationBroker::new(mock.clone() as Arc, shallow_lookup()); + enable_delegation(&broker).await; + let t1 = start_running(&broker, &mock, "child-1", 1, "pt-1").await; + let reports = broker + .get_tasks_status("other-parent", Some(2), &[t1], StatusWait::Immediate) + .await; + assert_eq!(reports.len(), 1); + assert_eq!(reports[0].status, TaskStatus::Unknown); + } + + // -- Task 4.5: error paths --------------------------------------------- + + #[tokio::test] + async fn spawn_failure_maps_to_spawn_failed() { + let mock = Arc::new(MockSpawner::new()); + mock.queue_spawn(Err(SpawnerError::Spawn("nope".into()))) + .await; + let broker = DelegationBroker::new(mock as Arc, shallow_lookup()); + enable_delegation(&broker).await; + let outcome = broker.handle_request(request(1, "pt-1")).await; + match outcome { + DelegationOutcome::Err { code, .. } => assert_eq!(code, "spawn_failed"), + other => panic!("expected Err, got {other:?}"), + } + } + + #[tokio::test] + async fn agent_defaults_are_forwarded_to_spawner() { + // Configure broker with per-agent defaults for ClaudeCode and verify + // they reach the spawner. Other agent types should still get the + // empty/None defaults. + let mock = Arc::new(MockSpawner::new()); + mock.queue_spawn(Ok("child-1".into())).await; + mock.queue_send(Err(SpawnerError::Send("stop after spawn".into()))) + .await; + let broker = + DelegationBroker::new(mock.clone() as Arc, shallow_lookup()); + + let mut claude_cfg = BTreeMap::new(); + claude_cfg.insert("model".into(), "claude-sonnet-4-5".into()); + let mut agent_defaults = BTreeMap::new(); + agent_defaults.insert( + AgentType::ClaudeCode, + AgentDelegationDefaults { + mode_id: Some("auto".into()), + config_values: claude_cfg.clone(), + }, + ); + broker + .set_config(DelegationConfig { + enabled: true, + depth_limit: 8, + agent_defaults, + ..DelegationConfig::default() + }) + .await; + + let _ = broker.handle_request(request(1, "pt-1")).await; + + let args = mock.spawn_args.lock().await; + assert_eq!(args.len(), 1); + let call = &args[0]; + assert_eq!(call.agent_type, AgentType::ClaudeCode); + assert_eq!(call.preferred_mode_id.as_deref(), Some("auto")); + assert_eq!(call.preferred_config_values, claude_cfg); + } + + #[tokio::test] + async fn agent_with_no_defaults_gets_empty_preferred_args() { + // ClaudeCode is configured in agent_defaults; a Codex request should + // still receive (None, empty) — no cross-contamination. + let mock = Arc::new(MockSpawner::new()); + mock.queue_spawn(Ok("child-1".into())).await; + mock.queue_send(Err(SpawnerError::Send("stop after spawn".into()))) + .await; + let broker = + DelegationBroker::new(mock.clone() as Arc, shallow_lookup()); + + let mut agent_defaults = BTreeMap::new(); + agent_defaults.insert( + AgentType::ClaudeCode, + AgentDelegationDefaults { + mode_id: Some("auto".into()), + config_values: BTreeMap::new(), + }, + ); + broker + .set_config(DelegationConfig { + enabled: true, + depth_limit: 8, + agent_defaults, + ..DelegationConfig::default() + }) + .await; + + let mut codex_req = request(1, "pt-1"); + codex_req.agent_type = AgentType::Codex; + let _ = broker.handle_request(codex_req).await; + + let args = mock.spawn_args.lock().await; + assert_eq!(args.len(), 1); + assert_eq!(args[0].agent_type, AgentType::Codex); + assert!(args[0].preferred_mode_id.is_none()); + assert!(args[0].preferred_config_values.is_empty()); + } + + #[tokio::test] + async fn send_failure_after_spawn_disconnects_child() { + let mock = Arc::new(MockSpawner::new()); + mock.queue_spawn(Ok("c1".into())).await; + mock.queue_send(Err(SpawnerError::Send("agent rejected prompt".into()))) + .await; + let broker = + DelegationBroker::new(mock.clone() as Arc, shallow_lookup()); + enable_delegation(&broker).await; + let outcome = broker.handle_request(request(1, "pt-1")).await; + match outcome { + DelegationOutcome::Err { code, .. } => assert_eq!(code, "spawn_failed"), + other => panic!("expected Err, got {other:?}"), + } + assert_eq!(mock.disconnects.lock().await.as_slice(), &["c1"]); + } + + #[tokio::test] + async fn handle_request_waits_indefinitely_for_completion() { + // No timeout race anymore: handle_request blocks on `rx.await` until + // complete_call / cancel_* fires. This test asserts the pending entry + // sticks around even after a generous idle window. + let mock = Arc::new(MockSpawner::new()); + mock.queue_spawn(Ok("c1".into())).await; + mock.queue_send(Ok(99)).await; + let broker = + DelegationBroker::new(mock.clone() as Arc, shallow_lookup()); + enable_delegation(&broker).await; + + let driver = { + let broker = broker.clone(); + tokio::spawn(async move { broker.handle_request(request(1, "pt-1")).await }) + }; + + tokio::time::sleep(Duration::from_millis(80)).await; + assert_eq!(broker.pending_count().await, 1); + assert!(mock.cancels.lock().await.is_empty()); + + let call_id = broker.peek_first_pending_call_id().await.unwrap(); + broker + .complete_call( + &call_id, + DelegationOutcome::Ok(DelegationSuccess { + text: "done".into(), + child_conversation_id: 99, + child_agent_type: AgentType::Codex, + turn_count: 1, + duration_ms: 50, + token_usage: None, + }), + ) + .await; + + let outcome = driver.await.unwrap(); + match outcome { + DelegationOutcome::Ok(s) => assert_eq!(s.text, "done"), + other => panic!("expected Ok, got {other:?}"), + } + assert_eq!(mock.disconnects.lock().await.as_slice(), &["c1"]); + } + + // -- Task 4.6: parent-cancel cascade ----------------------------------- + + #[tokio::test] + async fn parent_cancel_cancels_all_pending_children() { + let mock = Arc::new(MockSpawner::new()); + for i in 0..3 { + mock.queue_spawn(Ok(format!("c{i}"))).await; + mock.queue_send(Ok(100 + i)).await; + } + let broker = + DelegationBroker::new(mock.clone() as Arc, shallow_lookup()); + enable_delegation(&broker).await; + + let mut handles = Vec::new(); + for i in 0..3 { + let broker = broker.clone(); + handles.push(tokio::spawn(async move { + broker.handle_request(request(1, &format!("pt-{i}"))).await + })); + } + + // Wait until all three are parked. + while broker.pending_count().await < 3 { + tokio::time::sleep(Duration::from_millis(5)).await; + } + + broker.cancel_by_parent("parent-conn").await; + for h in handles { + let outcome = h.await.unwrap(); + match outcome { + DelegationOutcome::Err { code, .. } => assert_eq!(code, "canceled"), + other => panic!("expected canceled, got {other:?}"), + } + } + assert_eq!(mock.cancels.lock().await.len(), 3); + // Each child disconnects exactly once via cancel_by_parent. + assert_eq!(mock.disconnects.lock().await.len(), 3); + } + + #[tokio::test] + async fn cancel_by_parent_ignores_other_parents() { + let mock = Arc::new(MockSpawner::new()); + mock.queue_spawn(Ok("c1".into())).await; + mock.queue_send(Ok(200)).await; + let broker = + DelegationBroker::new(mock.clone() as Arc, shallow_lookup()); + enable_delegation(&broker).await; + + let driver = { + let broker = broker.clone(); + tokio::spawn(async move { broker.handle_request(request(1, "pt-1")).await }) + }; + while broker.pending_count().await == 0 { + tokio::time::sleep(Duration::from_millis(5)).await; + } + + broker.cancel_by_parent("other-parent").await; + // No effect — pending entry still there. + assert_eq!(broker.pending_count().await, 1); + + let call_id = broker.peek_first_pending_call_id().await.unwrap(); + broker + .complete_call( + &call_id, + DelegationOutcome::Ok(DelegationSuccess { + text: "done".into(), + child_conversation_id: 200, + child_agent_type: AgentType::ClaudeCode, + turn_count: 1, + duration_ms: 10, + token_usage: None, + }), + ) + .await; + let outcome = driver.await.unwrap(); + assert!(matches!(outcome, DelegationOutcome::Ok(_))); + } + + // -- Task 4.7: depth limit --------------------------------------------- + + #[tokio::test] + async fn depth_limit_rejects_before_spawn() { + let mock = Arc::new(MockSpawner::new()); + // No queued spawn results — if the broker tries to spawn, it errors loudly. + // chain: 1 (root, None) <- 2 (child of 1) <- 3 (grandchild of 2). + // Parent = grandchild (id 3): parent_depth = 2. With limit = 2, child + // would sit at depth 3 → reject. + let lookup = Arc::new(MockDepth(vec![(1, None), (2, Some(1)), (3, Some(2))])) + as Arc; + let broker = DelegationBroker::new(mock as Arc, lookup); + broker + .set_config(DelegationConfig { + enabled: true, + depth_limit: 2, + ..DelegationConfig::default() + }) + .await; + let outcome = broker.handle_request(request(3, "pt-1")).await; + match outcome { + DelegationOutcome::Err { code, .. } => assert_eq!(code, "depth_limit"), + other => panic!("expected depth_limit, got {other:?}"), + } + } + + // -- Pending tool_call_id queue (MCP `_meta.tool_use_id` fallback) ---- + + #[tokio::test] + async fn pending_tool_call_register_and_take_is_fifo() { + let broker = DelegationBroker::new( + Arc::new(MockSpawner::new()) as Arc, + shallow_lookup(), + ); + broker.register_pending_tool_call("p1", "tc-a".into()).await; + broker.register_pending_tool_call("p1", "tc-b".into()).await; + assert_eq!( + broker.take_pending_tool_call("p1").await.as_deref(), + Some("tc-a") + ); + assert_eq!( + broker.take_pending_tool_call("p1").await.as_deref(), + Some("tc-b") + ); + assert!(broker.take_pending_tool_call("p1").await.is_none()); + } + + #[tokio::test] + async fn register_dedupes_repeated_tool_call_id() { + // Regression: some hosts re-emit `sessionUpdate(tool_call)` (not + // `tool_call_update`) for the same call as raw_input chunks arrive + // or as the status flips. Without dedupe the second push leaves a + // stale id in the queue that mis-binds the next delegation. + let broker = DelegationBroker::new( + Arc::new(MockSpawner::new()) as Arc, + shallow_lookup(), + ); + broker.register_pending_tool_call("p1", "tc-a".into()).await; + broker.register_pending_tool_call("p1", "tc-a".into()).await; + broker.register_pending_tool_call("p1", "tc-a".into()).await; + assert_eq!( + broker.take_pending_tool_call("p1").await.as_deref(), + Some("tc-a") + ); + assert!( + broker.take_pending_tool_call("p1").await.is_none(), + "duplicate register must not leave a stale id in the queue" + ); + } + + #[tokio::test] + async fn register_after_claim_drops_stale_re_emit() { + // Regression for the post-claim re-emit race: a host re-sends + // `sessionUpdate(tool_call)` for the same id after the matching + // MCP round-trip already consumed it (e.g. shipping the + // `completed` status flip or a settled `raw_input`). The + // in-queue dedupe alone leaves the queue empty at that moment, + // so without the recently-consumed memory the re-emit would + // sneak into the queue and mis-bind the next delegation. + let broker = DelegationBroker::new( + Arc::new(MockSpawner::new()) as Arc, + shallow_lookup(), + ); + broker.register_pending_tool_call("p1", "tc-a".into()).await; + assert_eq!( + broker.take_pending_tool_call("p1").await.as_deref(), + Some("tc-a") + ); + // Re-emit of the same id after it was already claimed. + broker.register_pending_tool_call("p1", "tc-a".into()).await; + assert!( + broker.take_pending_tool_call("p1").await.is_none(), + "post-claim re-emit of the same id must not be re-queued" + ); + // A genuinely new id on the same parent still flows through. + broker.register_pending_tool_call("p1", "tc-b".into()).await; + assert_eq!( + broker.take_pending_tool_call("p1").await.as_deref(), + Some("tc-b") + ); + } + + #[tokio::test] + async fn concurrent_take_and_re_register_never_leaks_stale_duplicate() { + // TOCTOU regression: a host re-emit of the same tool_call_id + // racing against the matching take must never inject a stale + // duplicate. Co-locating `pending` and `consumed` under the + // same mutex guarantees the claim → mark-consumed pair is + // atomic, so the only two legal interleavings are: + // + // * take wins → pending=[], consumed=[id]; re-register sees + // the id in consumed and drops it. + // * register wins → pending=[id] (still the original entry, + // in-queue dedupe drops the re-emit); take then pops it + // and records it in consumed. + // + // In neither case may the queue retain a duplicate id once + // both futures settle. We drive many rounds with `tokio::spawn` + // to stress the interleaving. + let broker = std::sync::Arc::new(DelegationBroker::new( + Arc::new(MockSpawner::new()) as Arc, + shallow_lookup(), + )); + for _ in 0..200 { + broker.register_pending_tool_call("p1", "tc-a".into()).await; + let b_take = broker.clone(); + let b_reg = broker.clone(); + let h_take = tokio::spawn(async move { + b_take.take_pending_tool_call("p1").await; + }); + let h_reg = tokio::spawn(async move { + b_reg.register_pending_tool_call("p1", "tc-a".into()).await; + }); + let _ = tokio::join!(h_take, h_reg); + assert!( + broker.take_pending_tool_call("p1").await.is_none(), + "stale duplicate of tc-a leaked after concurrent take + re-register" + ); + } + } + + #[tokio::test] + async fn consumed_memory_outlives_pending_ttl_for_long_running_delegation() { + // Regression: a delegated child agent can run for + // minutes-to-hours. When it finishes, the host may re-emit + // the parent-side `tool_call` (e.g. as a `completed` status + // flip via the non-update `ToolCall` variant). That re-emit + // arrives well after PENDING_TOOL_CALL_TTL, so the consumed + // memory MUST NOT age out under that TTL — otherwise the + // stale id slips back into pending and mis-binds the next + // delegation. Consumed entries are scoped to the parent + // connection's lifetime instead. + let broker = DelegationBroker::new( + Arc::new(MockSpawner::new()) as Arc, + shallow_lookup(), + ); + broker.register_pending_tool_call("p1", "tc-a".into()).await; + assert_eq!( + broker.take_pending_tool_call("p1").await.as_deref(), + Some("tc-a") + ); + // Simulate the host re-emitting the same tool_call_id 10× + // the pending TTL later (i.e. a long-running delegation that + // finishes after the pending eviction window). + let long_after = Instant::now() + PENDING_TOOL_CALL_TTL * 10; + broker + .register_pending_tool_call_with_key_at("p1", "tc-a".into(), None, false, long_after) + .await; + assert!( + broker + .take_pending_tool_call_at("p1", long_after) + .await + .is_none(), + "consumed memory must outlast the pending TTL so terminal status re-emits cannot leak through" + ); + } + + #[tokio::test] + async fn consumed_memory_unbounded_across_high_fan_out() { + // Regression for the cap removal: a parent session with many + // delegations (well past any prior per-bucket cap) must still + // reject a late re-emit of the very first delegation's id, + // because the consumed half has no cap. A bounded consumed + // set with FIFO eviction would silently re-enable the + // mis-binding bug at high fan-out. + let broker = DelegationBroker::new( + Arc::new(MockSpawner::new()) as Arc, + shallow_lookup(), + ); + let first_id = "tc-first".to_string(); + broker + .register_pending_tool_call("p1", first_id.clone()) + .await; + assert_eq!( + broker.take_pending_tool_call("p1").await.as_deref(), + Some(first_id.as_str()) + ); + // Issue many more delegations than any prior per-bucket cap. With + // no cap on consumed, the first id must remain remembered for the + // lifetime of the parent connection. + for i in 0..128 { + let id = format!("tc-{i}"); + broker.register_pending_tool_call("p1", id.clone()).await; + assert_eq!( + broker.take_pending_tool_call("p1").await.as_deref(), + Some(id.as_str()) + ); + } + // Late re-emit of the very first id (would have been evicted + // by the prior bounded consumed FIFO). + broker + .register_pending_tool_call("p1", first_id.clone()) + .await; + assert!( + broker.take_pending_tool_call("p1").await.is_none(), + "consumed memory must retain the very first id even after high fan-out" + ); + } + + #[tokio::test] + async fn consumed_memory_cleared_on_parent_disconnect() { + // The companion to the long-running invariant above: consumed + // memory is scoped to the parent connection's lifetime, so + // `drop_pending_tool_calls_for_parent` (called when the + // parent disconnects) must clear it. Otherwise a brand-new + // connection reusing the same id (UUID collision is unlikely + // but UUIDs are not the only id scheme in play) would be + // permanently blocked. + let broker = DelegationBroker::new( + Arc::new(MockSpawner::new()) as Arc, + shallow_lookup(), + ); + broker.register_pending_tool_call("p1", "tc-a".into()).await; + assert_eq!( + broker.take_pending_tool_call("p1").await.as_deref(), + Some("tc-a") + ); + broker.drop_pending_tool_calls_for_parent("p1").await; + broker.register_pending_tool_call("p1", "tc-a".into()).await; + assert_eq!( + broker.take_pending_tool_call("p1").await.as_deref(), + Some("tc-a"), + "parent disconnect must clear consumed memory so id reuse is acceptable" + ); + } + + #[tokio::test] + async fn take_skips_entries_older_than_ttl() { + // Regression: an ACP `tool_call` whose matching MCP round-trip + // never arrives (host changed its mind, transport dropped, etc.) + // must not sit in the queue forever and mis-bind a subsequent + // delegation. TTL eviction is exercised by advancing the + // injected `as of` instant past PENDING_TOOL_CALL_TTL. + let broker = DelegationBroker::new( + Arc::new(MockSpawner::new()) as Arc, + shallow_lookup(), + ); + let t0 = Instant::now(); + broker + .register_pending_tool_call("p1", "stale".into()) + .await; + // Fresh id registered "just before" the future `now`. + broker + .register_pending_tool_call("p1", "fresh".into()) + .await; + let future_now = t0 + PENDING_TOOL_CALL_TTL + Duration::from_millis(50); + // Forge "fresh" so it survives the TTL: rewrite its timestamp to + // ~now-relative-to-future-now. Direct field access is OK — we're + // a sibling test in the same module. + { + let mut map = broker.tool_calls.inner.lock().await; + let bucket = map.get_mut("p1").expect("bucket present"); + // Re-stamp the second entry ("fresh") to `future_now`. + if let Some(entry) = bucket + .pending + .iter_mut() + .find(|p| p.tool_call_id == "fresh") + { + entry.registered_at = future_now; + } + } + // First entry ("stale", stamped at ~t0) is past TTL relative to + // future_now; the second ("fresh") was just re-stamped to + // future_now and must survive. + assert_eq!( + broker + .take_pending_tool_call_at("p1", future_now) + .await + .map(|(id, _)| id) + .as_deref(), + Some("fresh") + ); + assert!(broker.take_pending_tool_call("p1").await.is_none()); + } + + #[tokio::test] + async fn pending_tool_call_is_isolated_per_parent() { + let broker = DelegationBroker::new( + Arc::new(MockSpawner::new()) as Arc, + shallow_lookup(), + ); + broker.register_pending_tool_call("p1", "p1-a".into()).await; + broker.register_pending_tool_call("p2", "p2-a".into()).await; + assert_eq!( + broker.take_pending_tool_call("p1").await.as_deref(), + Some("p1-a") + ); + assert_eq!( + broker.take_pending_tool_call("p2").await.as_deref(), + Some("p2-a") + ); + assert!(broker.take_pending_tool_call("p1").await.is_none()); + assert!(broker.take_pending_tool_call("p2").await.is_none()); + } + + // -- (agent_type, task) correlation for parallel delegations ---------- + + /// Build a match key with a fixed agent and no explicit working_dir for + /// the common case where the test only varies the task. Use `key_for` to + /// vary the agent, or `key_with_dir` to vary the directory. + fn task_key(task: &str) -> DelegationMatchKey { + key_for(AgentType::Codex, task) + } + + fn key_for(agent_type: AgentType, task: &str) -> DelegationMatchKey { + DelegationMatchKey { + agent_type, + task: task.to_string(), + working_dir: None, + } + } + + fn key_with_dir(task: &str, working_dir: &str) -> DelegationMatchKey { + DelegationMatchKey { + agent_type: AgentType::Codex, + task: task.to_string(), + working_dir: Some(working_dir.to_string()), + } + } + + #[tokio::test] + async fn parallel_delegations_bind_by_key_regardless_of_order() { + // Two `delegate_to_agent` calls fire in parallel; both ACP tool_call + // events register with their key. The MCP round-trips can claim in + // EITHER order — each must bind to its own id by key match, never + // swap. Pure FIFO would hand the first claimer "tc-A" regardless of + // which call it represented. + let broker = DelegationBroker::new( + Arc::new(MockSpawner::new()) as Arc, + shallow_lookup(), + ); + broker + .register_pending_tool_call_with_key("p1", "tc-A".into(), Some(task_key("task A"))) + .await; + broker + .register_pending_tool_call_with_key("p1", "tc-B".into(), Some(task_key("task B"))) + .await; + // Claim "task B" first (reverse of registration order). + assert_eq!( + broker + .take_matching_tool_call("p1", &task_key("task B")) + .await + .as_deref(), + Some("tc-B") + ); + assert_eq!( + broker + .take_matching_tool_call("p1", &task_key("task A")) + .await + .as_deref(), + Some("tc-A") + ); + // A re-claim of an already-consumed key finds nothing. + assert!(broker + .take_matching_tool_call("p1", &task_key("task A")) + .await + .is_none()); + } + + #[tokio::test] + async fn parallel_same_task_different_agent_do_not_swap() { + // Regression for Codex review: two parallel calls with the SAME task + // text but DIFFERENT agents must bind by the full key, not by task + // alone — otherwise the codex card could show the claude_code child + // and vice versa. + let broker = DelegationBroker::new( + Arc::new(MockSpawner::new()) as Arc, + shallow_lookup(), + ); + broker + .register_pending_tool_call_with_key( + "p1", + "tc-codex".into(), + Some(key_for(AgentType::Codex, "review this")), + ) + .await; + broker + .register_pending_tool_call_with_key( + "p1", + "tc-claude".into(), + Some(key_for(AgentType::ClaudeCode, "review this")), + ) + .await; + // The claude_code round-trip must claim the claude_code id even though + // the codex entry shares the identical task and registered first. + assert_eq!( + broker + .take_matching_tool_call("p1", &key_for(AgentType::ClaudeCode, "review this")) + .await + .as_deref(), + Some("tc-claude") + ); + assert_eq!( + broker + .take_matching_tool_call("p1", &key_for(AgentType::Codex, "review this")) + .await + .as_deref(), + Some("tc-codex") + ); + } + + #[tokio::test] + async fn parallel_same_task_same_agent_different_dir_do_not_swap() { + // Regression for Codex review round 2: two parallel calls with the + // SAME agent and SAME task text but DIFFERENT explicit working_dir + // (e.g. "run tests" against /repo-a vs /repo-b) must bind by the full + // key including working_dir. Claimed in reverse registration order to + // prove it's not arrival-order FIFO. + let broker = DelegationBroker::new( + Arc::new(MockSpawner::new()) as Arc, + shallow_lookup(), + ); + broker + .register_pending_tool_call_with_key( + "p1", + "tc-a".into(), + Some(key_with_dir("run tests", "/repo-a")), + ) + .await; + broker + .register_pending_tool_call_with_key( + "p1", + "tc-b".into(), + Some(key_with_dir("run tests", "/repo-b")), + ) + .await; + assert_eq!( + broker + .take_matching_tool_call("p1", &key_with_dir("run tests", "/repo-b")) + .await + .as_deref(), + Some("tc-b") + ); + assert_eq!( + broker + .take_matching_tool_call("p1", &key_with_dir("run tests", "/repo-a")) + .await + .as_deref(), + Some("tc-a") + ); + } + + #[tokio::test] + async fn claim_does_not_steal_sibling_and_waits_for_own_registration() { + // Regression for the reported bug: with only the SIBLING's keyed id + // registered, a delegation must NOT grab it (which would swap the two + // cards) — it waits for its own id. The brief-wait loop picks it up + // once it registers shortly after. + let broker = std::sync::Arc::new(DelegationBroker::new( + Arc::new(MockSpawner::new()) as Arc, + shallow_lookup(), + )); + broker + .register_pending_tool_call_with_key("p1", "tc-A".into(), Some(task_key("task A"))) + .await; + // Immediate claim for "task B" while only tc-A (task A) is pending + // must refuse to steal tc-A. + assert!( + broker + .take_matching_tool_call("p1", &task_key("task B")) + .await + .is_none(), + "must not steal a sibling's keyed id" + ); + // tc-A is still claimable by its own key. + let broker_bg = broker.clone(); + let register_late = tokio::spawn(async move { + tokio::time::sleep(Duration::from_millis(30)).await; + broker_bg + .register_pending_tool_call_with_key("p1", "tc-B".into(), Some(task_key("task B"))) + .await; + }); + // The brief-wait claim polls until tc-B (task B) registers. + let claimed = broker + .claim_pending_tool_call_with_brief_wait("p1", &task_key("task B")) + .await; + register_late.await.unwrap(); + assert_eq!(claimed.map(|(id, _)| id).as_deref(), Some("tc-B")); + // tc-A remains for its own key. + assert_eq!( + broker + .take_matching_tool_call("p1", &task_key("task A")) + .await + .as_deref(), + Some("tc-A") + ); + } + + #[tokio::test] + async fn lone_unkeyed_entry_is_not_claimed_in_loop_only_post_budget() { + // A host that ships no parseable `raw_input` registers match_key=None. + // The in-loop path NEVER claims it — not even when it's the only entry, + // and regardless of how old it gets (10s here). Entry age is no proof a + // key isn't still coming: a serialized round-trip can register/backfill + // arbitrarily late, and the entry could belong to a parallel sibling + // whose owner hasn't registered yet (the staggered-singleton race — + // Codex review). Arrival-order FIFO is reserved for the post-budget last + // resort, which only runs once the CALLER has waited its full budget. + let broker = DelegationBroker::new( + Arc::new(MockSpawner::new()) as Arc, + shallow_lookup(), + ); + broker.register_pending_tool_call("p1", "tc-A".into()).await; + // Even aged 10s (well past any heuristic grace, still < TTL so not + // evicted), the in-loop claim refuses to hand out the unkeyed id. + let way_aged = Instant::now() + Duration::from_secs(10); + assert!( + broker + .take_matching_tool_call_at("p1", &task_key("whatever"), way_aged) + .await + .is_none(), + "an unkeyed entry must never be claimed in-loop, regardless of age" + ); + // The post-budget last resort is where a genuinely keyless entry binds. + assert_eq!( + broker.take_pending_tool_call("p1").await.as_deref(), + Some("tc-A") + ); + } + + #[tokio::test] + async fn parallel_unkeyed_entries_are_not_claimed_in_loop() { + // THE Finding 1 regression. Two delegations whose initial ToolCalls + // registered UNKEYED (args arrive later on a ToolCallUpdate). Before + // either is keyed, a round-trip arrives. The old `all unkeyed → + // pop_front` handed it the OLDEST entry (tc-A), mis-binding it to the + // wrong delegation. The in-loop claim now withholds (None) because no + // key matches — arrival-order FIFO is left to the post-budget last + // resort. Age never unlocks an in-loop claim. + let broker = DelegationBroker::new( + Arc::new(MockSpawner::new()) as Arc, + shallow_lookup(), + ); + broker.register_pending_tool_call("p1", "tc-A".into()).await; + broker.register_pending_tool_call("p1", "tc-B".into()).await; + // Aged (but < TTL, so not evicted): still withheld in-loop. + let aged = Instant::now() + Duration::from_secs(5); + assert!( + broker + .take_matching_tool_call_at("p1", &task_key("task B"), aged) + .await + .is_none(), + "unkeyed siblings must not be FIFO-claimed in-loop" + ); + // Neither entry was consumed. + let map = broker.tool_calls.inner.lock().await; + assert_eq!(map.get("p1").expect("bucket present").pending.len(), 2); + } + + #[tokio::test] + async fn parallel_unkeyed_resolves_by_backfilled_key_not_fifo() { + // The pay-off: while the claim is withheld, the args arrive and + // backfill a key onto the sibling. The round-trip then binds by EXACT + // MATCH to its own id — never the FIFO-oldest. This is the would-be + // mis-bind turned into a correct correlation. + let broker = DelegationBroker::new( + Arc::new(MockSpawner::new()) as Arc, + shallow_lookup(), + ); + broker.register_pending_tool_call("p1", "tc-A".into()).await; + broker.register_pending_tool_call("p1", "tc-B".into()).await; + // tc-B's args land → backfills its key. + broker + .register_pending_tool_call_with_key("p1", "tc-B".into(), Some(task_key("task B"))) + .await; + // The "task B" round-trip binds to tc-B by key, not to the older tc-A. + assert_eq!( + broker + .take_matching_tool_call("p1", &task_key("task B")) + .await + .as_deref(), + Some("tc-B") + ); + // tc-A is untouched, still pending for its own key/round-trip. + let map = broker.tool_calls.inner.lock().await; + let pending = &map.get("p1").expect("bucket present").pending; + assert_eq!(pending.len(), 1); + assert_eq!(pending[0].tool_call_id, "tc-A"); + } + + #[tokio::test] + async fn post_budget_fallback_still_fifos_parallel_unkeyed() { + // A genuinely keyless host (no key ever lands) must still bind both + // parallel delegations end-to-end. The in-loop claim withholds them, + // but the post-budget last resort `take_pending_tool_call` claims them + // oldest-first — the best a keyless host allows, and unchanged from + // before. Only the premature in-loop FIFO is gone. + let broker = DelegationBroker::new( + Arc::new(MockSpawner::new()) as Arc, + shallow_lookup(), + ); + broker.register_pending_tool_call("p1", "tc-A".into()).await; + broker.register_pending_tool_call("p1", "tc-B".into()).await; + assert_eq!( + broker.take_pending_tool_call("p1").await.as_deref(), + Some("tc-A") + ); + assert_eq!( + broker.take_pending_tool_call("p1").await.as_deref(), + Some("tc-B") + ); + } + + #[tokio::test] + async fn brief_wait_binds_own_late_registration_not_unkeyed_sibling() { + // The staggered-singleton timeline Codex flagged, end-to-end: only an + // UNKEYED sibling (tc-A) is visible when a DIFFERENT delegation's + // round-trip (task B) starts claiming; B's own keyed `tool_call` + // registers a little later, still inside the wait budget. The brief-wait + // loop must bind B to its OWN id (tc-B) by exact match, never FIFO-steal + // the older unkeyed tc-A. The old in-loop FIFO popped tc-A on the very + // first poll (all-unkeyed); a grace gate would still steal it once tc-A + // aged past the grace before tc-B arrived. Deferring all FIFO to the + // post-budget — i.e. binding by exact match in-loop only — is what makes + // this correct. + let broker = std::sync::Arc::new(DelegationBroker::new( + Arc::new(MockSpawner::new()) as Arc, + shallow_lookup(), + )); + broker.register_pending_tool_call("p1", "tc-A".into()).await; + // B's own ACP registration lands ~200ms in — well after any age-based + // heuristic would have fired, but far inside the ~2s claim budget. + let broker_bg = broker.clone(); + let register_late = tokio::spawn(async move { + tokio::time::sleep(Duration::from_millis(200)).await; + broker_bg + .register_pending_tool_call_with_key("p1", "tc-B".into(), Some(task_key("task B"))) + .await; + }); + let claimed = broker + .claim_pending_tool_call_with_brief_wait("p1", &task_key("task B")) + .await; + register_late.await.unwrap(); + assert_eq!( + claimed.map(|(id, _)| id).as_deref(), + Some("tc-B"), + "must wait for its own registration, not FIFO-steal the unkeyed sibling" + ); + // tc-A is untouched, still pending for its own correlation. + let map = broker.tool_calls.inner.lock().await; + let pending = &map.get("p1").expect("bucket present").pending; + assert_eq!(pending.len(), 1); + assert_eq!(pending[0].tool_call_id, "tc-A"); + } + + #[tokio::test] + async fn reemit_backfills_key_onto_unkeyed_entry() { + // A host that re-emits the `session/update(tool_call)` variant: the + // first ToolCall has no parseable args (registers match_key=None), a + // later re-emit carries the full args. The re-emit must backfill the + // key onto the existing entry (not push a duplicate, not be dropped) + // so key matching works. + let broker = DelegationBroker::new( + Arc::new(MockSpawner::new()) as Arc, + shallow_lookup(), + ); + broker.register_pending_tool_call("p1", "tc-A".into()).await; + broker + .register_pending_tool_call_with_key("p1", "tc-A".into(), Some(task_key("task A"))) + .await; + // Now claimable by the backfilled key. + assert_eq!( + broker + .take_matching_tool_call("p1", &task_key("task A")) + .await + .as_deref(), + Some("tc-A") + ); + assert!(broker.take_pending_tool_call("p1").await.is_none()); + } + + #[tokio::test] + async fn fallback_never_steals_a_keyed_sibling() { + // A keyed sibling is pending but the requesting round-trip's key never + // matches (its own tool_call was genuinely lost). The post-budget last + // resort must NOT hand out the keyed sibling — stealing it would just + // move the dead card from this delegation to the sibling. It returns + // None (→ caller mints a synthetic id), and the sibling stays claimable + // by its own round-trip. (Regression: the old behavior FIFO-popped the + // keyed entry here, swapping which delegation broke.) + let broker = DelegationBroker::new( + Arc::new(MockSpawner::new()) as Arc, + shallow_lookup(), + ); + broker + .register_pending_tool_call_with_key("p1", "tc-A".into(), Some(task_key("task A"))) + .await; + // No entry matches "task Z", and a keyed entry is present, so the + // match step refuses to claim. + assert!(broker + .take_matching_tool_call("p1", &task_key("task Z")) + .await + .is_none()); + // The post-budget last resort steps over the keyed entry → None. + assert!( + broker.take_pending_tool_call("p1").await.is_none(), + "must not steal a keyed sibling via the anonymous fallback" + ); + // The keyed sibling is untouched — still claimable by its own key. + assert_eq!( + broker + .take_matching_tool_call("p1", &task_key("task A")) + .await + .as_deref(), + Some("tc-A") + ); + } + + #[tokio::test] + async fn keyed_entry_survives_past_ttl_for_serialized_round_trip() { + // THE headline regression for the reported bug. A 2nd parallel + // delegation's tool_call registers (keyed), then its MCP round-trip is + // serialized far behind the 1st delegation — arriving well past + // PENDING_TOOL_CALL_TTL. The keyed entry must NOT be aged out: an exact + // key match claims it at any age, so the parent card binds instead of + // falling to a synthetic id. (Observed live: round-trip landed 77s + // after registration, past the 60s TTL → evicted → synthetic → dead + // card stuck on "sub-agent running…".) + let broker = DelegationBroker::new( + Arc::new(MockSpawner::new()) as Arc, + shallow_lookup(), + ); + broker + .register_pending_tool_call_with_key( + "p1", + "tc-late".into(), + Some(task_key("slow task")), + ) + .await; + // Claim "as of" long past the TTL — simulates the round-trip arriving + // after a many-times-TTL wait behind a serialized sibling. + let way_past_ttl = Instant::now() + PENDING_TOOL_CALL_TTL * 10; + assert_eq!( + broker + .take_matching_tool_call_at("p1", &task_key("slow task"), way_past_ttl) + .await + .as_deref(), + Some("tc-late"), + "a keyed entry must remain claimable by exact key match regardless of age" + ); + } + + #[tokio::test] + async fn unkeyed_entry_is_still_aged_out() { + // The flip side: UNKEYED entries (host shipped no parseable raw_input) + // remain anonymous and arrival-order-correlated, so a stale one MUST + // still be GC'd by age — otherwise it could mis-bind a much later + // unkeyed delegation via the FIFO path. + let broker = DelegationBroker::new( + Arc::new(MockSpawner::new()) as Arc, + shallow_lookup(), + ); + broker + .register_pending_tool_call("p1", "tc-stale".into()) + .await; + let way_past_ttl = Instant::now() + PENDING_TOOL_CALL_TTL * 10; + // Unkeyed + stale → evicted by the match path's GC → nothing to claim. + assert!(broker + .take_matching_tool_call_at("p1", &task_key("whatever"), way_past_ttl) + .await + .is_none()); + // And the anonymous path agrees it's gone. + assert!(broker + .take_pending_tool_call_at("p1", way_past_ttl) + .await + .is_none()); + } + + #[tokio::test] + async fn explicit_tool_use_id_consumes_pending_entry_acp_first() { + // Codex review fix: client supplies the real id via `_meta.tool_use_id` + // AFTER the dispatcher already registered it (ACP-before-MCP). The + // explicit-id path must consume the keyed pending entry so it can't + // linger (keyed entries are retained indefinitely) and be mis-claimed + // by a later same-key delegation. + let broker = DelegationBroker::new( + Arc::new(MockSpawner::new()) as Arc, + shallow_lookup(), + ); + broker + .register_pending_tool_call_with_key("p1", "tc-x".into(), Some(task_key("task A"))) + .await; + broker.consume_explicit_tool_call("p1", "tc-x").await; + // No longer claimable by its key. + assert!(broker + .take_matching_tool_call("p1", &task_key("task A")) + .await + .is_none()); + // A late ACP re-registration of the same id is dropped (consumed). + broker + .register_pending_tool_call_with_key("p1", "tc-x".into(), Some(task_key("task A"))) + .await; + assert!( + broker + .take_matching_tool_call("p1", &task_key("task A")) + .await + .is_none(), + "a re-registration after explicit consume must stay dropped" + ); + } + + #[tokio::test] + async fn explicit_tool_use_id_consumes_pending_entry_mcp_first() { + // The MCP-before-ACP order: the explicit-id request is handled before + // the ACP tool_call event registers. consume_explicit_tool_call records + // the id as consumed up front, so the later registration is dropped. + let broker = DelegationBroker::new( + Arc::new(MockSpawner::new()) as Arc, + shallow_lookup(), + ); + broker.consume_explicit_tool_call("p1", "tc-y").await; + broker + .register_pending_tool_call_with_key("p1", "tc-y".into(), Some(task_key("task B"))) + .await; + assert!(broker + .take_matching_tool_call("p1", &task_key("task B")) + .await + .is_none()); + } + + #[tokio::test] + async fn tombstone_removes_stale_keyed_entry() { + // A `delegate_to_agent` tool call registered a keyed entry but its MCP + // round-trip never reached the broker (the call failed / the turn was + // interrupted). A terminal `ToolCallUpdate` tombstones the entry so it + // can't linger indefinitely (keyed entries are never aged out). + let broker = DelegationBroker::new( + Arc::new(MockSpawner::new()) as Arc, + shallow_lookup(), + ); + broker + .register_pending_tool_call_with_key("p1", "tc-stale".into(), Some(task_key("task A"))) + .await; + assert!(broker.tombstone_pending_tool_call("p1", "tc-stale").await); + assert!(broker + .take_matching_tool_call("p1", &task_key("task A")) + .await + .is_none()); + } + + #[tokio::test] + async fn tombstone_prevents_same_key_misbind() { + // The High regression: without the tombstone, a stale keyed entry is + // retained forever and a LATER identical-key delegation claims its dead + // id (the exact-key scan returns the oldest match). After tombstoning the + // stale entry, a fresh registration for the same key binds to the FRESH + // id instead. + let broker = DelegationBroker::new( + Arc::new(MockSpawner::new()) as Arc, + shallow_lookup(), + ); + broker + .register_pending_tool_call_with_key("p1", "tc-stale".into(), Some(task_key("task A"))) + .await; + broker.tombstone_pending_tool_call("p1", "tc-stale").await; + broker + .register_pending_tool_call_with_key("p1", "tc-fresh".into(), Some(task_key("task A"))) + .await; + assert_eq!( + broker + .take_matching_tool_call("p1", &task_key("task A")) + .await + .as_deref(), + Some("tc-fresh"), + "a later same-key delegation must claim the fresh id, not the tombstoned one" + ); + } + + #[tokio::test] + async fn tombstone_leaves_other_entries_intact() { + // A terminal update for an unrelated (non-delegation) id no-ops and must + // leave a registered delegation untouched. + let broker = DelegationBroker::new( + Arc::new(MockSpawner::new()) as Arc, + shallow_lookup(), + ); + broker + .register_pending_tool_call_with_key("p1", "tc-keep".into(), Some(task_key("task A"))) + .await; + assert!( + !broker + .tombstone_pending_tool_call("p1", "tc-bash-123") + .await + ); + assert_eq!( + broker + .take_matching_tool_call("p1", &task_key("task A")) + .await + .as_deref(), + Some("tc-keep") + ); + } + + #[tokio::test] + async fn tombstone_then_reregister_same_id_stays_dropped() { + // After tombstoning a real entry, an out-of-order re-registration of the + // same id is dropped by the Tier-1 consumed check — mirrors + // `explicit_tool_use_id_consumes_pending_entry_acp_first`. + let broker = DelegationBroker::new( + Arc::new(MockSpawner::new()) as Arc, + shallow_lookup(), + ); + broker + .register_pending_tool_call_with_key("p1", "tc-stale".into(), Some(task_key("task A"))) + .await; + assert!(broker.tombstone_pending_tool_call("p1", "tc-stale").await); + broker + .register_pending_tool_call_with_key("p1", "tc-stale".into(), Some(task_key("task A"))) + .await; + assert!( + broker + .take_matching_tool_call("p1", &task_key("task A")) + .await + .is_none(), + "a re-registration after tombstone must stay dropped" + ); + } + + #[tokio::test] + async fn tombstone_noop_does_not_record_consumed() { + // The tombstone runs for EVERY terminal tool-call update, most of them + // non-delegations. A no-op tombstone (id not pending) must NOT record + // `consumed` — otherwise `consumed` (no TTL/cap) would grow with every + // completed tool call, and a later legitimate registration of that id + // would be wrongly dropped. + let broker = DelegationBroker::new( + Arc::new(MockSpawner::new()) as Arc, + shallow_lookup(), + ); + assert!(!broker.tombstone_pending_tool_call("p1", "tc-x").await); + broker + .register_pending_tool_call_with_key("p1", "tc-x".into(), Some(task_key("task A"))) + .await; + assert_eq!( + broker + .take_matching_tool_call("p1", &task_key("task A")) + .await + .as_deref(), + Some("tc-x"), + "a no-op tombstone must not record consumed and drop a later registration" + ); + } + + #[tokio::test] + async fn tombstone_removes_only_the_matching_entry_from_a_multi_entry_bucket() { + // Tombstoning a MIDDLE entry removes only that id (retain is by exact + // tool_call_id, position-independent) and leaves the siblings claimable + // by their own keys. + let broker = DelegationBroker::new( + Arc::new(MockSpawner::new()) as Arc, + shallow_lookup(), + ); + broker + .register_pending_tool_call_with_key("p1", "tc-a".into(), Some(task_key("task A"))) + .await; + broker + .register_pending_tool_call_with_key("p1", "tc-b".into(), Some(task_key("task B"))) + .await; + broker + .register_pending_tool_call_with_key("p1", "tc-c".into(), Some(task_key("task C"))) + .await; + assert!(broker.tombstone_pending_tool_call("p1", "tc-b").await); + assert!(broker + .take_matching_tool_call("p1", &task_key("task B")) + .await + .is_none()); + assert_eq!( + broker + .take_matching_tool_call("p1", &task_key("task A")) + .await + .as_deref(), + Some("tc-a") + ); + assert_eq!( + broker + .take_matching_tool_call("p1", &task_key("task C")) + .await + .as_deref(), + Some("tc-c") + ); + } + + #[tokio::test] + async fn keyed_pending_entries_have_no_count_cap() { + // Regression for the PENDING_QUEUE_CAP removal: a high-fan-out parent + // can register hundreds of keyed pending tool_calls — each awaiting its + // own serialized MCP round-trip — and EVERY one is retained. The old + // hard cap evicted the oldest keyed entry past 32, orphaning its card to + // a synthetic id. Keyed entries are now bounded only by claim, terminal + // tombstoning, and per-parent teardown. + let broker = DelegationBroker::new( + Arc::new(MockSpawner::new()) as Arc, + shallow_lookup(), + ); + const N: usize = 256; + for i in 0..N { + broker + .register_pending_tool_call_with_key( + "p1", + format!("tc-{i}"), + Some(task_key(&format!("task {i}"))), + ) + .await; + } + { + let map = broker.tool_calls.inner.lock().await; + let bucket = map.get("p1").expect("bucket present"); + assert_eq!( + bucket.pending.len(), + N, + "all keyed pending entries must be retained — no count cap" + ); + } + // Each entry stays individually claimable by its exact key, in any + // order — proving none were dropped or mis-bound by fan-out. + for i in [0usize, N / 2, N - 1] { + let claimed = broker + .take_matching_tool_call("p1", &task_key(&format!("task {i}"))) + .await; + assert_eq!(claimed.as_deref(), Some(format!("tc-{i}").as_str())); + } + } + + #[tokio::test] + async fn keyed_pending_entry_drains_via_tombstone() { + // The drain path the no-cap design relies on: when the parent-side ACP + // tool_call goes terminal before its MCP round-trip ever claims it, + // `tombstone_pending_tool_call` removes the keyed entry (so it can't + // linger) AND records it consumed (so a late re-emit can't mis-bind a + // later delegation sharing the same key). + let broker = DelegationBroker::new( + Arc::new(MockSpawner::new()) as Arc, + shallow_lookup(), + ); + broker + .register_pending_tool_call_with_key("p1", "tc-x".into(), Some(task_key("task x"))) + .await; + assert!( + broker.tombstone_pending_tool_call("p1", "tc-x").await, + "tombstone must report it removed the pending entry" + ); + assert!( + broker + .take_matching_tool_call("p1", &task_key("task x")) + .await + .is_none(), + "a tombstoned entry must be drained from pending" + ); + // Re-register of the same id after tombstoning is dropped by the + // Tier-1 consumed check, so it can never be claimed. + broker + .register_pending_tool_call_with_key("p1", "tc-x".into(), Some(task_key("task x"))) + .await; + assert!( + broker + .take_matching_tool_call("p1", &task_key("task x")) + .await + .is_none(), + "consumed memory must reject a re-emit of a tombstoned id" + ); + } + + #[tokio::test] + async fn reregistration_refines_key_with_late_working_dir() { + // Codex re-review fix: the same tool_call_id first registers with a key + // LACKING working_dir (an early parseable raw_input), then a later + // ToolCallUpdate completes it with the explicit working_dir. The stored + // key must be REPLACED with the fuller one — otherwise the MCP claim + // keying on Some(dir) can't match the stale None and orphans to a + // synthetic id (dead card for explicit-working-dir delegations). + let broker = DelegationBroker::new( + Arc::new(MockSpawner::new()) as Arc, + shallow_lookup(), + ); + broker + .register_pending_tool_call_with_key( + "p1", + "tc-d".into(), + Some(key_for(AgentType::Codex, "build")), + ) + .await; + // Later update adds the explicit working_dir → key is refined in place. + broker + .register_pending_tool_call_with_key( + "p1", + "tc-d".into(), + Some(key_with_dir("build", "/repo")), + ) + .await; + // The stale `working_dir: None` key no longer matches (it was replaced)… + assert!(broker + .take_matching_tool_call("p1", &key_for(AgentType::Codex, "build")) + .await + .is_none()); + // …and the refined `Some("/repo")` key claims the real id. + assert_eq!( + broker + .take_matching_tool_call("p1", &key_with_dir("build", "/repo")) + .await + .as_deref(), + Some("tc-d"), + "the MCP claim with the explicit working_dir must match the refined key" + ); + } + + #[tokio::test] + async fn empty_parent_tool_use_id_claims_pending_then_completes() { + let mock = Arc::new(MockSpawner::new()); + mock.queue_spawn(Ok("c1".into())).await; + mock.queue_send(Ok(7)).await; + let broker = + DelegationBroker::new(mock.clone() as Arc, shallow_lookup()); + enable_delegation(&broker).await; + broker + .register_pending_tool_call("parent-conn", "tu-from-acp".into()) + .await; + let driver = { + let broker = broker.clone(); + tokio::spawn(async move { broker.handle_request(request(1, "")).await }) + }; + while broker.pending_count().await == 0 { + tokio::time::sleep(Duration::from_millis(5)).await; + } + // The captured ACP id was consumed. + assert!(broker.take_pending_tool_call("parent-conn").await.is_none()); + let call_id = broker.peek_first_pending_call_id().await.unwrap(); + broker + .complete_call( + &call_id, + DelegationOutcome::Ok(DelegationSuccess { + text: "ok".into(), + child_conversation_id: 7, + child_agent_type: AgentType::Codex, + turn_count: 1, + duration_ms: 5, + token_usage: None, + }), + ) + .await; + let outcome = driver.await.unwrap(); + assert!(matches!(outcome, DelegationOutcome::Ok(_))); + } + + #[tokio::test] + async fn empty_parent_tool_use_id_claims_pending_arriving_late() { + // Regression: when the parent's ACP `session/update(tool_call)` + // lands at the lifecycle dispatcher AFTER `broker.handle_request` + // already entered the claim phase, the brief poll loop must still + // pick it up rather than falling back to the synthetic UUID. + let mock = Arc::new(MockSpawner::new()); + mock.queue_spawn(Ok("c-late".into())).await; + mock.queue_send(Ok(13)).await; + let broker = + DelegationBroker::new(mock.clone() as Arc, shallow_lookup()); + enable_delegation(&broker).await; + + let driver = { + let broker = broker.clone(); + tokio::spawn(async move { broker.handle_request(request(1, "")).await }) + }; + + // Give the driver time to enter the claim wait loop on an empty + // queue, then register the ACP id (simulates the dispatcher's + // ToolCall handling landing late). + tokio::time::sleep(Duration::from_millis(30)).await; + broker + .register_pending_tool_call("parent-conn", "tu-late".into()) + .await; + + while broker.pending_count().await == 0 { + tokio::time::sleep(Duration::from_millis(5)).await; + } + // The late-arriving ACP id was consumed by the broker — no leftover + // entry. + assert!(broker.take_pending_tool_call("parent-conn").await.is_none()); + let call_id = broker.peek_first_pending_call_id().await.unwrap(); + broker + .complete_call( + &call_id, + DelegationOutcome::Ok(DelegationSuccess { + text: "late ok".into(), + child_conversation_id: 13, + child_agent_type: AgentType::Codex, + turn_count: 1, + duration_ms: 5, + token_usage: None, + }), + ) + .await; + let outcome = driver.await.unwrap(); + assert!(matches!(outcome, DelegationOutcome::Ok(_))); + } + + #[tokio::test] + async fn empty_parent_tool_use_id_with_no_pending_falls_back_to_uuid() { + let mock = Arc::new(MockSpawner::new()); + mock.queue_spawn(Ok("c1".into())).await; + mock.queue_send(Ok(11)).await; + let broker = + DelegationBroker::new(mock.clone() as Arc, shallow_lookup()); + enable_delegation(&broker).await; + let driver = { + let broker = broker.clone(); + tokio::spawn(async move { broker.handle_request(request(1, "")).await }) + }; + while broker.pending_count().await == 0 { + tokio::time::sleep(Duration::from_millis(5)).await; + } + let call_id = broker.peek_first_pending_call_id().await.unwrap(); + broker + .complete_call( + &call_id, + DelegationOutcome::Ok(DelegationSuccess { + text: "fallback ok".into(), + child_conversation_id: 11, + child_agent_type: AgentType::Codex, + turn_count: 1, + duration_ms: 5, + token_usage: None, + }), + ) + .await; + let outcome = driver.await.unwrap(); + assert!(matches!(outcome, DelegationOutcome::Ok(_))); + } + + #[tokio::test] + async fn cancel_by_parent_also_drops_pending_tool_calls() { + let broker = DelegationBroker::new( + Arc::new(MockSpawner::new()) as Arc, + shallow_lookup(), + ); + broker + .register_pending_tool_call("parent-conn", "tu-1".into()) + .await; + broker.cancel_by_parent("parent-conn").await; + assert!(broker.take_pending_tool_call("parent-conn").await.is_none()); + } + + #[tokio::test] + async fn turn_cancel_keeps_consumed_rejects_reemit() { + // A turn/prompt cancel (parent connection STAYS ALIVE) must NOT drop the + // `consumed` tool_call memory. Otherwise a host re-emit of an + // already-claimed id (e.g. a terminal status-flip) re-registers as fresh + // `pending` and the next same-key delegation mis-binds to it — the + // dead-card/wrong-child class this correlation machinery exists to + // prevent. `cancel_by_parent_turn` retains `consumed`, so the re-emit + // stays rejected by the Tier-1 consumed check. + let broker = DelegationBroker::new( + Arc::new(MockSpawner::new()) as Arc, + shallow_lookup(), + ); + // Register + claim a keyed id (the delegation that just ran). + broker + .register_pending_tool_call_with_key("p1", "tc-A".into(), Some(task_key("task A"))) + .await; + assert_eq!( + broker + .take_matching_tool_call("p1", &task_key("task A")) + .await + .as_deref(), + Some("tc-A"), + ); + // Turn cancel — parent still alive. + broker.cancel_by_parent_turn("p1").await; + // Host re-emits the now-consumed id with the same key. + broker + .register_pending_tool_call_with_key("p1", "tc-A".into(), Some(task_key("task A"))) + .await; + assert!( + broker + .take_matching_tool_call("p1", &task_key("task A")) + .await + .is_none(), + "re-emit of a consumed id must stay rejected across a turn cancel" + ); + } + + #[tokio::test] + async fn turn_cancel_drops_unclaimed_pending() { + // The unclaimed `pending` half is cleared by a turn cancel (tombstoned + // into `consumed`): the cancelled turn's serial round-trip won't arrive, + // so the stale keyed entry must not remain claimable by a later same-key + // delegation. `take_matching` scans only `pending`, so it returns None. + let broker = DelegationBroker::new( + Arc::new(MockSpawner::new()) as Arc, + shallow_lookup(), + ); + broker + .register_pending_tool_call_with_key("p1", "tc-B".into(), Some(task_key("task B"))) + .await; + broker.cancel_by_parent_turn("p1").await; + assert!( + broker + .take_matching_tool_call("p1", &task_key("task B")) + .await + .is_none(), + "unclaimed pending must not stay claimable after a turn cancel" + ); + } + + #[tokio::test] + async fn turn_cancel_tombstones_pending_rejects_late_reemit() { + // Stronger than the clear test: after a turn cancel clears an UNCLAIMED + // keyed pending id, a late host re-emit of that SAME id must not + // resurrect it as a claimable entry — otherwise the next same-key + // delegation would mis-bind to the stale id. The cancel tombstones the + // cleared id into `consumed`, so the re-emit is dropped by the Tier-1 + // consumed check and never re-enters `pending`. + let broker = DelegationBroker::new( + Arc::new(MockSpawner::new()) as Arc, + shallow_lookup(), + ); + broker + .register_pending_tool_call_with_key("p1", "tc-X".into(), Some(task_key("task X"))) + .await; + broker.cancel_by_parent_turn("p1").await; + // Late re-emit of the cancelled turn's unclaimed id (same key). + broker + .register_pending_tool_call_with_key("p1", "tc-X".into(), Some(task_key("task X"))) + .await; + assert!( + broker + .take_matching_tool_call("p1", &task_key("task X")) + .await + .is_none(), + "a re-emit of a tombstoned (cleared-on-cancel) pending id must not be claimable" + ); + } + + #[tokio::test] + async fn teardown_cancel_clears_consumed() { + // The teardown variant (`cancel_by_parent`) DOES drop consumed — the + // connection is going away, so a reused connection_id must start clean. + // Contrast with `turn_cancel_keeps_consumed_rejects_reemit`. + let broker = DelegationBroker::new( + Arc::new(MockSpawner::new()) as Arc, + shallow_lookup(), + ); + broker.register_pending_tool_call("p1", "tc-A".into()).await; + assert_eq!( + broker.take_pending_tool_call("p1").await.as_deref(), + Some("tc-A"), + ); + broker.cancel_by_parent("p1").await; + // consumed cleared → the same id re-registers and is claimable again. + broker.register_pending_tool_call("p1", "tc-A".into()).await; + assert_eq!( + broker.take_pending_tool_call("p1").await.as_deref(), + Some("tc-A"), + "teardown cancel must clear consumed so id reuse is acceptable" + ); + } + + #[tokio::test] + async fn cancel_by_parent_turn_drains_synchronously_then_tears_down_child() { + // The turn cancel must (a) drop the tracker + remove parked calls + // SYNCHRONOUSLY — before the connection loop could accept the next + // prompt — so a delayed cancel can't tombstone/cancel a NEXT turn's + // entries (the invariant `drop_tool_calls_for_parent` relies on); and + // (b) still fully tear the child down (backgrounded), resolving the + // awaiting `handle_request` as canceled exactly once. + let mock = Arc::new(MockSpawner::new()); + mock.queue_spawn(Ok("child-1".into())).await; + mock.queue_send(Ok(7)).await; + let broker = + DelegationBroker::new(mock.clone() as Arc, shallow_lookup()); + enable_delegation(&broker).await; + + // Park a delegation for "parent-conn"... + let driver = { + let broker = broker.clone(); + tokio::spawn(async move { broker.handle_request(request(1, "pt-1")).await }) + }; + while broker.pending_count().await == 0 { + tokio::time::sleep(Duration::from_millis(5)).await; + } + // ...plus a separate unclaimed keyed tracker entry on the same parent. + broker + .register_pending_tool_call_with_key( + "parent-conn", + "tc-Z".into(), + Some(task_key("task Z")), + ) + .await; + + broker.cancel_by_parent_turn("parent-conn").await; + + // (a) Synchronously — no sleep: the parked call is removed and the + // tracker entry is dropped (tombstoned), so neither can leak into a + // next-turn registration that the backgrounded teardown might clobber. + assert_eq!( + broker.pending_count().await, + 0, + "parked call must be drained synchronously by the turn cancel" + ); + assert!( + broker + .take_matching_tool_call("parent-conn", &task_key("task Z")) + .await + .is_none(), + "tracker pending must be dropped synchronously by the turn cancel" + ); + + // (b) The backgrounded child teardown still resolves the driver as + // canceled and tears the child down exactly once. + match driver.await.unwrap() { + DelegationOutcome::Err { code, .. } => assert_eq!(code, "canceled"), + other => panic!("expected canceled, got {other:?}"), + } + assert_eq!(mock.cancels.lock().await.as_slice(), &["child-1"]); + assert_eq!(mock.disconnects.lock().await.as_slice(), &["child-1"]); + } + + #[tokio::test] + async fn depth_limit_allows_root() { + let mock = Arc::new(MockSpawner::new()); + mock.queue_spawn(Ok("c1".into())).await; + mock.queue_send(Ok(7)).await; + let lookup = Arc::new(MockDepth(vec![(1, None)])) as Arc; + let broker = DelegationBroker::new(mock.clone() as Arc, lookup); + broker + .set_config(DelegationConfig { + enabled: true, + depth_limit: 2, + ..DelegationConfig::default() + }) + .await; + + let driver = { + let broker = broker.clone(); + tokio::spawn(async move { broker.handle_request(request(1, "pt-1")).await }) + }; + while broker.pending_count().await == 0 { + tokio::time::sleep(Duration::from_millis(5)).await; + } + let call_id = broker.peek_first_pending_call_id().await.unwrap(); + broker + .complete_call( + &call_id, + DelegationOutcome::Ok(DelegationSuccess { + text: "ok".into(), + child_conversation_id: 7, + child_agent_type: AgentType::ClaudeCode, + turn_count: 1, + duration_ms: 5, + token_usage: None, + }), + ) + .await; + let outcome = driver.await.unwrap(); + assert!(matches!(outcome, DelegationOutcome::Ok(_))); + } + + // -- Meta writer lifecycle -------------------------------------------- + + use crate::acp::delegation::meta_writer::mock::MockMetaWriter; + use crate::acp::delegation::meta_writer::DelegationMetaWriter; + + async fn broker_with_meta( + mock: Arc, + writer: Arc, + ) -> DelegationBroker { + let broker = DelegationBroker::with_meta_writer( + mock as Arc, + shallow_lookup(), + writer as Arc, + ); + enable_delegation(&broker).await; + broker + } + + #[tokio::test] + async fn meta_writes_carry_task_preview_and_task_id_on_every_write() { + // Meta is replace-wholesale on the ToolCallState, so BOTH the running + // and the terminal writes must carry the task label + broker task id — + // they are the persisted card's only label source on hosts whose + // raw_input never carries the arguments (Cursor). + let mock = Arc::new(MockSpawner::new()); + mock.queue_spawn(Ok("child-conn-t".into())).await; + mock.queue_send(Ok(42)).await; + let writer = Arc::new(MockMetaWriter::new()); + let broker = broker_with_meta(mock.clone(), writer.clone()).await; + + let driver = { + let broker = broker.clone(); + tokio::spawn(async move { broker.handle_request(request(1, "pt-task")).await }) + }; + let call_id = loop { + if let Some(id) = broker.peek_first_pending_call_id().await { + break id; + } + tokio::time::sleep(Duration::from_millis(5)).await; + }; + broker + .complete_call( + &call_id, + DelegationOutcome::Ok(DelegationSuccess { + text: "done".into(), + child_conversation_id: 42, + child_agent_type: AgentType::ClaudeCode, + turn_count: 1, + duration_ms: 5, + token_usage: None, + }), + ) + .await; + driver.await.unwrap(); + + let calls = writer.snapshot().await; + assert_eq!(calls.len(), 2); + for call in &calls { + let inner = call + .meta + .get("codeg.delegation") + .unwrap() + .as_object() + .unwrap(); + assert_eq!( + inner.get("task_preview").unwrap().as_str().unwrap(), + "do x", + "every write must keep the task label (status={})", + inner.get("status").unwrap() + ); + assert_eq!( + inner.get("task_id").unwrap().as_str().unwrap(), + &call_id, + "task_id must be the broker call id on every write" + ); + } + } + + #[tokio::test] + async fn identityless_fifo_claim_restores_delegate_identity() { + // Cursor path: the ACP announcement registered an identity-less + // candidate ("MCP: tool" + "{}"), the MCP round-trip arrives with no + // explicit tool_use id. The post-budget FIFO claim must land on the + // candidate AND restore the call's identity (canonical delegate title + // + reconstructed arguments) on the live tool call. + let mock = Arc::new(MockSpawner::new()); + mock.queue_spawn(Ok("child-conn-i".into())).await; + mock.queue_send(Ok(43)).await; + let writer = Arc::new(MockMetaWriter::new()); + let broker = broker_with_meta(mock.clone(), writer.clone()).await; + broker + .register_identityless_tool_call("parent-conn", "call-cursor-7\nfc_x_0".into()) + .await; + + let driver = { + let broker = broker.clone(); + // Empty tool_use id → claim path (2s budget, then FIFO). + tokio::spawn(async move { broker.handle_request(request(1, "")).await }) + }; + let call_id = loop { + if let Some(id) = broker.peek_first_pending_call_id().await { + break id; + } + tokio::time::sleep(Duration::from_millis(5)).await; + }; + broker + .complete_call( + &call_id, + DelegationOutcome::Ok(DelegationSuccess { + text: "done".into(), + child_conversation_id: 43, + child_agent_type: AgentType::ClaudeCode, + turn_count: 1, + duration_ms: 5, + token_usage: None, + }), + ) + .await; + driver.await.unwrap(); + + let identities = writer.identity_snapshot().await; + assert_eq!(identities.len(), 1, "exactly one identity restoration"); + let id_write = &identities[0]; + assert_eq!(id_write.parent_connection_id, "parent-conn"); + assert_eq!(id_write.tool_call_id, "call-cursor-7\nfc_x_0"); + assert_eq!( + id_write.title, + crate::acp::delegation::DELEGATE_TOOL_REWRITE_TITLE + ); + assert_eq!( + id_write.raw_input.get("task").unwrap().as_str().unwrap(), + "do x" + ); + assert_eq!( + id_write + .raw_input + .get("agent_type") + .unwrap() + .as_str() + .unwrap(), + "claude_code" + ); + // The meta writes bound to the REAL claimed id, not a synthetic one. + let metas = writer.snapshot().await; + assert!(metas + .iter() + .all(|m| m.parent_tool_use_id == "call-cursor-7\nfc_x_0")); + } + + #[tokio::test] + async fn keyed_claim_does_not_rewrite_host_identity() { + // A host that shipped real raw_input (keyed registration) keeps its + // own wire identity — reconstructing raw_input would clobber + // host-specific fields. + let mock = Arc::new(MockSpawner::new()); + mock.queue_spawn(Ok("child-conn-k".into())).await; + mock.queue_send(Ok(44)).await; + let writer = Arc::new(MockMetaWriter::new()); + let broker = broker_with_meta(mock.clone(), writer.clone()).await; + broker + .register_pending_tool_call_with_key( + "parent-conn", + "tc-keyed".into(), + Some(DelegationMatchKey { + agent_type: AgentType::ClaudeCode, + task: "do x".into(), + working_dir: None, + }), + ) + .await; + + let driver = { + let broker = broker.clone(); + tokio::spawn(async move { broker.handle_request(request(1, "")).await }) + }; + let call_id = loop { + if let Some(id) = broker.peek_first_pending_call_id().await { + break id; + } + tokio::time::sleep(Duration::from_millis(5)).await; + }; + broker + .complete_call( + &call_id, + DelegationOutcome::Ok(DelegationSuccess { + text: "done".into(), + child_conversation_id: 44, + child_agent_type: AgentType::ClaudeCode, + turn_count: 1, + duration_ms: 5, + token_usage: None, + }), + ) + .await; + driver.await.unwrap(); + + assert!( + writer.identity_snapshot().await.is_empty(), + "keyed (host-identified) claims must not be rewritten" + ); + let metas = writer.snapshot().await; + assert!(metas.iter().all(|m| m.parent_tool_use_id == "tc-keyed")); + } + + #[tokio::test] + async fn rewrite_identityless_tool_call_claims_and_writes_status_identity() { + let writer = Arc::new(MockMetaWriter::new()); + let broker = broker_with_meta(Arc::new(MockSpawner::new()), writer.clone()).await; + broker + .register_identityless_tool_call("parent-conn", "call-status-1".into()) + .await; + + let claimed = broker + .rewrite_identityless_tool_call( + "parent-conn", + crate::acp::delegation::STATUS_TOOL_REWRITE_TITLE, + serde_json::json!({"task_ids": ["t-1"], "wait_ms": 0}), + ) + .await; + assert_eq!(claimed.as_deref(), Some("call-status-1")); + let identities = writer.identity_snapshot().await; + assert_eq!(identities.len(), 1); + assert_eq!( + identities[0].title, + crate::acp::delegation::STATUS_TOOL_REWRITE_TITLE + ); + assert_eq!( + identities[0].raw_input.get("task_ids").unwrap()[0] + .as_str() + .unwrap(), + "t-1" + ); + // Consumed: the candidate can't be claimed again by the delegate FIFO. + assert!(broker.take_pending_tool_call("parent-conn").await.is_none()); + } + + #[tokio::test] + async fn rewrite_skips_connections_that_never_announced_identityless() { + // Plain unkeyed registration (a keyless delegation invocation) must + // NOT be renamed — and the sticky gate must return instantly (no + // 300 ms poll) for such connections. Also: the entry stays claimable + // by the delegate FIFO afterwards. + let writer = Arc::new(MockMetaWriter::new()); + let broker = broker_with_meta(Arc::new(MockSpawner::new()), writer.clone()).await; + broker + .register_pending_tool_call("parent-conn", "tc-plain".into()) + .await; + + let started = std::time::Instant::now(); + let claimed = broker + .rewrite_identityless_tool_call( + "parent-conn", + crate::acp::delegation::STATUS_TOOL_REWRITE_TITLE, + serde_json::json!({"task_ids": ["t-1"]}), + ) + .await; + assert!(claimed.is_none()); + // The poll path sleeps ≥300 ms (30 × 10 ms lower bounds); the gate + // path sleeps zero. 280 ms discriminates the two while leaving slack + // for full-suite parallel-load scheduling jitter. + assert!( + started.elapsed() < Duration::from_millis(280), + "sticky gate must skip the poll for hosts without identity-less announcements" + ); + assert!(writer.identity_snapshot().await.is_empty()); + assert_eq!( + broker + .take_pending_tool_call("parent-conn") + .await + .as_deref(), + Some("tc-plain"), + "the plain unkeyed entry must remain for the delegate FIFO" + ); + } + + #[tokio::test] + async fn meta_writer_records_running_then_completed_on_happy_path() { + let mock = Arc::new(MockSpawner::new()); + mock.queue_spawn(Ok("child-conn-1".into())).await; + mock.queue_send(Ok(42)).await; + let writer = Arc::new(MockMetaWriter::new()); + let broker = broker_with_meta(mock.clone(), writer.clone()).await; + + let driver = { + let broker = broker.clone(); + tokio::spawn(async move { broker.handle_request(request(1, "pt-real")).await }) + }; + let call_id = loop { + if let Some(id) = broker.peek_first_pending_call_id().await { + break id; + } + tokio::time::sleep(Duration::from_millis(5)).await; + }; + broker + .complete_call( + &call_id, + DelegationOutcome::Ok(DelegationSuccess { + text: "done".into(), + child_conversation_id: 42, + child_agent_type: AgentType::ClaudeCode, + turn_count: 1, + duration_ms: 5, + token_usage: None, + }), + ) + .await; + driver.await.unwrap(); + + let calls = writer.snapshot().await; + assert_eq!(calls.len(), 2); + // First write: running, with child connection + conversation ids. + let first = &calls[0]; + assert_eq!(first.parent_tool_use_id, "pt-real"); + let inner_first = first + .meta + .get("codeg.delegation") + .unwrap() + .as_object() + .unwrap(); + assert_eq!( + inner_first.get("status").unwrap().as_str().unwrap(), + "running" + ); + assert_eq!( + inner_first + .get("child_connection_id") + .unwrap() + .as_str() + .unwrap(), + "child-conn-1" + ); + assert_eq!( + inner_first + .get("child_conversation_id") + .unwrap() + .as_i64() + .unwrap(), + 42 + ); + // Second write: completed. + let second = &calls[1]; + let inner_second = second + .meta + .get("codeg.delegation") + .unwrap() + .as_object() + .unwrap(); + assert_eq!( + inner_second.get("status").unwrap().as_str().unwrap(), + "completed" + ); + } + + #[tokio::test] + async fn meta_writer_records_failed_on_err_outcome() { + let mock = Arc::new(MockSpawner::new()); + mock.queue_spawn(Ok("child-conn-2".into())).await; + mock.queue_send(Ok(7)).await; + let writer = Arc::new(MockMetaWriter::new()); + let broker = broker_with_meta(mock.clone(), writer.clone()).await; + + let driver = { + let broker = broker.clone(); + tokio::spawn(async move { broker.handle_request(request(1, "pt-err")).await }) + }; + let call_id = loop { + if let Some(id) = broker.peek_first_pending_call_id().await { + break id; + } + tokio::time::sleep(Duration::from_millis(5)).await; + }; + broker + .complete_call( + &call_id, + DelegationOutcome::from_err( + DelegationError::SubagentRuntimeError("agent died".into()), + Some(7), + ), + ) + .await; + driver.await.unwrap(); + + let calls = writer.snapshot().await; + assert_eq!(calls.len(), 2); + let inner = calls[1] + .meta + .get("codeg.delegation") + .unwrap() + .as_object() + .unwrap(); + assert_eq!(inner.get("status").unwrap().as_str().unwrap(), "failed"); + assert_eq!( + inner.get("error_code").unwrap().as_str().unwrap(), + "subagent_error" + ); + } + + // -- Registration-race: child terminal failure before the entry is parked -- + + /// Headline regression: a child terminal failure (auth error / immediate + /// process death) that fires AFTER the broker reserved the child but BEFORE + /// it parked the pending entry must still resolve the parked request — not + /// no-op and strand it on `rx.await` forever. The `send_gate` pins + /// `handle_request` in exactly that window; we fire the failure, release the + /// gate, and assert the request resolves as canceled (carrying the + /// terminal-error detail) with a single child disconnect and a clean + /// running→failed meta trail. + #[tokio::test] + async fn child_failure_before_park_resolves_instead_of_hanging() { + let mock = Arc::new(MockSpawner::new()); + mock.queue_spawn(Ok("c-fast-fail".into())).await; + mock.queue_send(Ok(55)).await; + let release = mock.install_send_gate().await; + let writer = Arc::new(MockMetaWriter::new()); + let broker = broker_with_meta(mock.clone(), writer.clone()).await; + + let driver = { + let broker = broker.clone(); + tokio::spawn(async move { broker.handle_request(request(1, "pt-fast")).await }) + }; + + // Wait until handle_request has spawned + reserved the child and is + // held inside send_prompt by the gate — entry NOT yet parked. + loop { + if broker.reserved_child_count().await == 1 { + break; + } + tokio::time::sleep(Duration::from_millis(5)).await; + } + assert_eq!(broker.pending_count().await, 0, "entry not parked yet"); + + // Child dies before the entry is parked. With the reservation in place + // this buffers (rather than no-oping on a not-yet-existent entry). + broker + .cancel_by_child_connection("c-fast-fail", Some("Authentication required")) + .await; + assert_eq!(broker.early_cancel_count().await, 1, "failure buffered"); + + // Release send_prompt → handle_request parks, drains the buffered + // failure, and resolves inline instead of hanging. + let _ = release.send(()); + let outcome = driver.await.unwrap(); + match outcome { + DelegationOutcome::Err { + code, + message, + child_conversation_id, + } => { + assert_eq!(code, "canceled"); + assert!( + message.contains("Authentication required"), + "reason should carry the terminal-error detail, got: {message}" + ); + assert_eq!(child_conversation_id, Some(55)); + } + other => panic!("expected canceled Err, got {other:?}"), + } + + // Reservation + buffer drained; child torn down exactly once. + assert_eq!(broker.pending_count().await, 0); + assert_eq!(broker.reserved_child_count().await, 0); + assert_eq!(broker.early_cancel_count().await, 0); + assert_eq!(mock.disconnects.lock().await.as_slice(), &["c-fast-fail"]); + + // Meta trail: running (written pre-park) then failed/canceled (pickup). + let calls = writer.snapshot().await; + assert_eq!(calls.len(), 2); + let running = calls[0] + .meta + .get("codeg.delegation") + .unwrap() + .as_object() + .unwrap(); + assert_eq!(running.get("status").unwrap().as_str().unwrap(), "running"); + let failed = calls[1] + .meta + .get("codeg.delegation") + .unwrap() + .as_object() + .unwrap(); + assert_eq!(failed.get("status").unwrap().as_str().unwrap(), "failed"); + assert_eq!( + failed.get("error_code").unwrap().as_str().unwrap(), + "canceled" + ); + } + + /// The SAME race on the SUCCESS path: a `TurnComplete` whose `complete_call` + /// fires AFTER the delegation reserved but BEFORE `handle_request` parked (a + /// fast/empty turn whose completion propagates while the broker is still + /// awaiting the parent `write_meta`) must still resolve the request. The + /// prompt is only *enqueued* by `send_prompt`, so the child loop can emit + /// `TurnComplete` before the park. The `send_gate` pins `handle_request` in + /// the reserve→park window; we resolve via the reserved `call_id` (the entry + /// isn't parked yet) and assert the request returns Ok instead of hanging. + #[tokio::test] + async fn completion_before_park_resolves_instead_of_hanging() { + let mock = Arc::new(MockSpawner::new()); + mock.queue_spawn(Ok("c-fast-ok".into())).await; + mock.queue_send(Ok(70)).await; + let release = mock.install_send_gate().await; + let writer = Arc::new(MockMetaWriter::new()); + let broker = broker_with_meta(mock.clone(), writer.clone()).await; + + let driver = { + let broker = broker.clone(); + tokio::spawn(async move { broker.handle_request(request(1, "pt-ok")).await }) + }; + + // Wait until reserved (spawned + id minted, held in send_prompt by the + // gate); the entry is NOT parked yet, so grab the call_id from the + // reservation rather than the parked-calls map. + let call_id = loop { + if let Some(id) = broker.peek_reserved_call_id().await { + break id; + } + tokio::time::sleep(Duration::from_millis(5)).await; + }; + assert_eq!(broker.pending_count().await, 0, "entry not parked yet"); + + // TurnComplete beats the park. With the reservation in place this + // buffers (rather than no-oping on a not-yet-existent entry). + broker + .complete_call( + &call_id, + DelegationOutcome::Ok(DelegationSuccess { + text: "fast done".into(), + child_conversation_id: 70, + child_agent_type: AgentType::ClaudeCode, + turn_count: 1, + duration_ms: 5, + token_usage: None, + }), + ) + .await; + assert_eq!( + broker.early_complete_count().await, + 1, + "completion buffered" + ); + + // Release send_prompt → handle_request parks, drains the buffered + // completion, and resolves inline instead of hanging. + let _ = release.send(()); + let outcome = driver.await.unwrap(); + match outcome { + DelegationOutcome::Ok(s) => { + assert_eq!(s.text, "fast done"); + assert_eq!(s.child_conversation_id, 70); + } + other => panic!("expected Ok, got {other:?}"), + } + + assert_eq!(broker.pending_count().await, 0); + assert_eq!(broker.reserved_call_count().await, 0); + assert_eq!(broker.reserved_child_count().await, 0); + assert_eq!(broker.early_complete_count().await, 0); + assert_eq!(mock.disconnects.lock().await.as_slice(), &["c-fast-ok"]); + + // Meta trail: running (written pre-park) then completed (pickup). + let calls = writer.snapshot().await; + assert_eq!(calls.len(), 2); + let running = calls[0] + .meta + .get("codeg.delegation") + .unwrap() + .as_object() + .unwrap(); + assert_eq!(running.get("status").unwrap().as_str().unwrap(), "running"); + let completed = calls[1] + .meta + .get("codeg.delegation") + .unwrap() + .as_object() + .unwrap(); + assert_eq!( + completed.get("status").unwrap().as_str().unwrap(), + "completed" + ); + } + + /// The reservation is released at park, and a SUCCESSFUL completion buffers + /// nothing. The child's post-completion disconnect (normal v1 one-shot + /// teardown) finds the child un-reserved and must NOT buffer a spurious + /// cancel — otherwise every completed delegation would leak a buffer entry. + #[tokio::test] + async fn normal_completion_leaves_no_reservation_or_buffer() { + let mock = Arc::new(MockSpawner::new()); + mock.queue_spawn(Ok("c-clean".into())).await; + mock.queue_send(Ok(60)).await; + let broker = + DelegationBroker::new(mock.clone() as Arc, shallow_lookup()); + enable_delegation(&broker).await; + + let driver = { + let broker = broker.clone(); + tokio::spawn(async move { broker.handle_request(request(1, "pt-clean")).await }) + }; + let call_id = loop { + if let Some(id) = broker.peek_first_pending_call_id().await { + break id; + } + tokio::time::sleep(Duration::from_millis(5)).await; + }; + // Parked → reservation already released. + assert_eq!( + broker.reserved_child_count().await, + 0, + "park releases the reservation" + ); + + broker + .complete_call( + &call_id, + DelegationOutcome::Ok(DelegationSuccess { + text: "ok".into(), + child_conversation_id: 60, + child_agent_type: AgentType::ClaudeCode, + turn_count: 1, + duration_ms: 5, + token_usage: None, + }), + ) + .await; + assert!(matches!(driver.await.unwrap(), DelegationOutcome::Ok(_))); + + // The child's post-completion disconnect arrives. Child is no longer + // reserved → must NOT buffer a spurious cancel. + broker.cancel_by_child_connection("c-clean", None).await; + assert_eq!( + broker.early_cancel_count().await, + 0, + "a post-resolution teardown must not buffer a spurious cancel" + ); + assert_eq!(broker.pending_count().await, 0); + } + + // -- Item 1: parent-cancel coverage of the `handle_request` setup window -- + + /// A parent cancel that lands while `handle_request` is INSIDE `spawn` (the + /// child exists but no prompt has been sent) must disconnect the child and + /// bail — never send it a prompt — instead of no-oping and letting it run + /// orphaned. Pinned with the spawn gate. + #[tokio::test] + async fn parent_cancel_in_spawn_window_disconnects_child_without_sending() { + let mock = Arc::new(MockSpawner::new()); + mock.queue_spawn(Ok("c2".into())).await; + mock.queue_send(Ok(99)).await; // staged but must NOT be consumed + let release = mock.install_spawn_gate().await; + let broker = + DelegationBroker::new(mock.clone() as Arc, shallow_lookup()); + enable_delegation(&broker).await; + + let driver = { + let broker = broker.clone(); + tokio::spawn(async move { broker.handle_request(request(1, "pt-2")).await }) + }; + // Inside spawn (call recorded, held by the gate): registered in-flight, + // not yet reserved. + loop { + if !mock.spawn_args.lock().await.is_empty() { + break; + } + tokio::time::sleep(Duration::from_millis(5)).await; + } + assert_eq!(broker.inflight_count().await, 1); + assert_eq!(broker.reserved_child_count().await, 0, "not reserved yet"); + + broker.cancel_by_parent_turn("parent-conn").await; + let _ = release.send(()); + + match driver.await.unwrap() { + DelegationOutcome::Err { code, .. } => assert_eq!(code, "canceled"), + other => panic!("expected canceled, got {other:?}"), + } + assert_eq!(mock.disconnects.lock().await.as_slice(), &["c2"]); + assert!( + mock.cancels.lock().await.is_empty(), + "no prompt was sent, so no cancel — disconnect only" + ); + assert_eq!( + mock.send_results.lock().await.len(), + 1, + "send must not be consumed — no prompt sent to an abandoned child" + ); + assert_eq!(broker.inflight_count().await, 0); + assert_eq!(broker.reserved_child_count().await, 0); + } + + /// A parent cancel that lands in the reserve→park window (prompt already + /// sent, entry not yet parked) must cancel AND disconnect the child and + /// resolve the request as canceled. Pinned with the send gate; also asserts + /// the running→failed/canceled meta trail. + #[tokio::test] + async fn parent_cancel_in_reserve_park_window_tears_down_child() { + let mock = Arc::new(MockSpawner::new()); + mock.queue_spawn(Ok("c3".into())).await; + mock.queue_send(Ok(33)).await; + let release = mock.install_send_gate().await; + let writer = Arc::new(MockMetaWriter::new()); + let broker = broker_with_meta(mock.clone(), writer.clone()).await; + + let driver = { + let broker = broker.clone(); + tokio::spawn(async move { broker.handle_request(request(1, "pt-3")).await }) + }; + // Spawned + reserved, held inside send_prompt. + loop { + if broker.reserved_child_count().await == 1 { + break; + } + tokio::time::sleep(Duration::from_millis(5)).await; + } + assert_eq!(broker.inflight_count().await, 1); + assert_eq!(broker.pending_count().await, 0, "not parked yet"); + + broker.cancel_by_parent_turn("parent-conn").await; + let _ = release.send(()); + + match driver.await.unwrap() { + DelegationOutcome::Err { + code, + child_conversation_id, + .. + } => { + assert_eq!(code, "canceled"); + assert_eq!(child_conversation_id, Some(33)); + } + other => panic!("expected canceled, got {other:?}"), + } + // Prompt was sent → child cancel()'d AND disconnected. + assert_eq!(mock.cancels.lock().await.as_slice(), &["c3"]); + assert_eq!(mock.disconnects.lock().await.as_slice(), &["c3"]); + assert_eq!(broker.inflight_count().await, 0); + assert_eq!(broker.reserved_child_count().await, 0); + assert_eq!(broker.early_cancel_count().await, 0); + assert_eq!(broker.pending_count().await, 0); + + // Meta trail: running (pre-park) then failed/canceled (ParentCanceled). + let calls = writer.snapshot().await; + assert_eq!(calls.len(), 2); + let running = calls[0] + .meta + .get("codeg.delegation") + .unwrap() + .as_object() + .unwrap(); + assert_eq!(running.get("status").unwrap().as_str().unwrap(), "running"); + let failed = calls[1] + .meta + .get("codeg.delegation") + .unwrap() + .as_object() + .unwrap(); + assert_eq!(failed.get("status").unwrap().as_str().unwrap(), "failed"); + assert_eq!( + failed.get("error_code").unwrap().as_str().unwrap(), + "canceled" + ); + } + + /// Strict first-terminal-wins: when a child completion buffers FIRST and a + /// parent cancel lands afterward, the child's earlier arrival stamp wins and + /// its real result is preserved (the cancel is moot — the child already + /// finished before it). + #[tokio::test] + async fn child_terminal_wins_over_later_parent_cancel() { + let mock = Arc::new(MockSpawner::new()); + mock.queue_spawn(Ok("c4".into())).await; + mock.queue_send(Ok(44)).await; + let release = mock.install_send_gate().await; + let broker = + DelegationBroker::new(mock.clone() as Arc, shallow_lookup()); + enable_delegation(&broker).await; + + let driver = { + let broker = broker.clone(); + tokio::spawn(async move { broker.handle_request(request(1, "pt-4")).await }) + }; + let call_id = loop { + if let Some(id) = broker.peek_reserved_call_id().await { + break id; + } + tokio::time::sleep(Duration::from_millis(5)).await; + }; + assert_eq!(broker.inflight_count().await, 1); + + // Child completes FIRST, then the parent cancels — child result wins. + broker + .complete_call( + &call_id, + DelegationOutcome::Ok(DelegationSuccess { + text: "done".into(), + child_conversation_id: 44, + child_agent_type: AgentType::ClaudeCode, + turn_count: 1, + duration_ms: 5, + token_usage: None, + }), + ) + .await; + broker.cancel_by_parent_turn("parent-conn").await; + let _ = release.send(()); + + assert!(matches!(driver.await.unwrap(), DelegationOutcome::Ok(_))); + assert!( + mock.cancels.lock().await.is_empty(), + "child completed — the moot parent cancel must not cancel it" + ); + assert_eq!(broker.inflight_count().await, 0); + assert_eq!(broker.early_complete_count().await, 0); + } + + /// Strict first-terminal-wins (Item 3): when the parent cancel is recorded + /// BEFORE the child completion buffers, the cancel wins — the late + /// completion is discarded and the child is torn down, because the parent + /// had already abandoned the turn by the time the completion landed. + #[tokio::test] + async fn parent_cancel_wins_when_it_arrives_before_child_terminal() { + let mock = Arc::new(MockSpawner::new()); + mock.queue_spawn(Ok("c5".into())).await; + mock.queue_send(Ok(55)).await; + let release = mock.install_send_gate().await; + let broker = + DelegationBroker::new(mock.clone() as Arc, shallow_lookup()); + enable_delegation(&broker).await; + + let driver = { + let broker = broker.clone(); + tokio::spawn(async move { broker.handle_request(request(1, "pt-5")).await }) + }; + let call_id = loop { + if let Some(id) = broker.peek_reserved_call_id().await { + break id; + } + tokio::time::sleep(Duration::from_millis(5)).await; + }; + + // Parent cancels FIRST (earlier arrival stamp); the child completes + // afterward (later stamp) — first-terminal-wins judges the cancel the + // winner and discards the late completion. + broker.cancel_by_parent_turn("parent-conn").await; + broker + .complete_call( + &call_id, + DelegationOutcome::Ok(DelegationSuccess { + text: "late".into(), + child_conversation_id: 55, + child_agent_type: AgentType::ClaudeCode, + turn_count: 1, + duration_ms: 5, + token_usage: None, + }), + ) + .await; + let _ = release.send(()); + + match driver.await.unwrap() { + DelegationOutcome::Err { + code, + child_conversation_id, + .. + } => { + assert_eq!(code, "canceled"); + assert_eq!(child_conversation_id, Some(55)); + } + other => panic!( + "first-terminal-wins: an earlier parent cancel must beat a later completion, got {other:?}" + ), + } + // The abandoned child is torn down (prompt was sent → cancel + disconnect). + assert_eq!(mock.cancels.lock().await.as_slice(), &["c5"]); + assert_eq!(mock.disconnects.lock().await.as_slice(), &["c5"]); + assert_eq!(broker.inflight_count().await, 0); + // The buffered completion was drained (and discarded), leaving no leak. + assert_eq!(broker.early_complete_count().await, 0); + } + + /// Strict first-terminal-wins through the child-FAILURE buffer: a child + /// failure that buffers BEFORE a parent cancel keeps its (earlier) arrival + /// stamp and wins, so the request resolves with the child's failure detail + /// and the child is torn down once (disconnect only — the child already + /// failed, so there's no in-flight prompt to cancel). Exercises the + /// `early_cancels` stamp path that mirrors the completion case above. + #[tokio::test] + async fn child_failure_wins_over_later_parent_cancel() { + let mock = Arc::new(MockSpawner::new()); + mock.queue_spawn(Ok("cF".into())).await; + mock.queue_send(Ok(66)).await; + let release = mock.install_send_gate().await; + let broker = + DelegationBroker::new(mock.clone() as Arc, shallow_lookup()); + enable_delegation(&broker).await; + + let driver = { + let broker = broker.clone(); + tokio::spawn(async move { broker.handle_request(request(1, "pt-f")).await }) + }; + // Spawned + reserved, held inside send_prompt by the gate. + loop { + if broker.reserved_child_count().await == 1 { + break; + } + tokio::time::sleep(Duration::from_millis(5)).await; + } + + // Child fails FIRST (earlier stamp), then the parent cancels (later + // stamp) — the child terminal wins and carries its failure detail. + broker + .cancel_by_child_connection("cF", Some("boom detail")) + .await; + broker.cancel_by_parent_turn("parent-conn").await; + let _ = release.send(()); + + match driver.await.unwrap() { + DelegationOutcome::Err { + code, + message, + child_conversation_id, + } => { + assert_eq!(code, "canceled"); + assert!( + message.contains("boom detail"), + "child failure detail must survive, got: {message}" + ); + assert_eq!(child_conversation_id, Some(66)); + } + other => panic!("expected child failure Err, got {other:?}"), + } + // Child-terminal path tears down via disconnect only (no cancel). + assert_eq!(mock.disconnects.lock().await.as_slice(), &["cF"]); + assert!( + mock.cancels.lock().await.is_empty(), + "child already failed — the moot parent cancel must not cancel it" + ); + assert_eq!(broker.inflight_count().await, 0); + assert_eq!(broker.early_cancel_count().await, 0); + } + + /// The teardown variant `cancel_by_parent` covers the same reserve→park + /// window as the turn variant — both funnel through `drain_for_parent_cancel` + /// where the in-flight mark is applied. + #[tokio::test] + async fn parent_teardown_in_reserve_park_window_tears_down_child() { + let mock = Arc::new(MockSpawner::new()); + mock.queue_spawn(Ok("c7".into())).await; + mock.queue_send(Ok(77)).await; + let release = mock.install_send_gate().await; + let broker = + DelegationBroker::new(mock.clone() as Arc, shallow_lookup()); + enable_delegation(&broker).await; + + let driver = { + let broker = broker.clone(); + tokio::spawn(async move { broker.handle_request(request(1, "pt-7")).await }) + }; + loop { + if broker.reserved_child_count().await == 1 { + break; + } + tokio::time::sleep(Duration::from_millis(5)).await; + } + broker.cancel_by_parent("parent-conn").await; + let _ = release.send(()); + + match driver.await.unwrap() { + DelegationOutcome::Err { code, .. } => assert_eq!(code, "canceled"), + other => panic!("expected canceled, got {other:?}"), + } + assert_eq!(mock.cancels.lock().await.as_slice(), &["c7"]); + assert_eq!(mock.disconnects.lock().await.as_slice(), &["c7"]); + assert_eq!(broker.inflight_count().await, 0); + } + + /// A cancel targeting a DIFFERENT parent must not flag this setup: it parks + /// normally and resolves via its own child terminal. + #[tokio::test] + async fn parent_cancel_for_other_parent_leaves_setup_intact() { + let mock = Arc::new(MockSpawner::new()); + mock.queue_spawn(Ok("c8".into())).await; + mock.queue_send(Ok(88)).await; + let release = mock.install_send_gate().await; + let broker = + DelegationBroker::new(mock.clone() as Arc, shallow_lookup()); + enable_delegation(&broker).await; + + let driver = { + let broker = broker.clone(); + tokio::spawn(async move { broker.handle_request(request(1, "pt-8")).await }) + }; + loop { + if broker.reserved_child_count().await == 1 { + break; + } + tokio::time::sleep(Duration::from_millis(5)).await; + } + // Wrong-parent cancel — a no-op for this setup. + broker.cancel_by_parent_turn("some-other-parent").await; + let _ = release.send(()); + + // It must park normally; resolve it via its child completion. + let parked = loop { + if let Some(id) = broker.peek_first_pending_call_id().await { + break id; + } + tokio::time::sleep(Duration::from_millis(5)).await; + }; + broker + .complete_call( + &parked, + DelegationOutcome::Ok(DelegationSuccess { + text: "fine".into(), + child_conversation_id: 88, + child_agent_type: AgentType::ClaudeCode, + turn_count: 1, + duration_ms: 5, + token_usage: None, + }), + ) + .await; + assert!(matches!(driver.await.unwrap(), DelegationOutcome::Ok(_))); + assert!( + mock.cancels.lock().await.is_empty(), + "a wrong-parent cancel must not tear this child down" + ); + assert_eq!(broker.inflight_count().await, 0); + } + + /// The in-flight record is deregistered on every exit path: the normal park + /// hand-off, and each early-return (disabled / spawn-fail / send-fail). + #[tokio::test] + async fn inflight_drained_on_normal_park() { + let mock = Arc::new(MockSpawner::new()); + mock.queue_spawn(Ok("c-ok".into())).await; + mock.queue_send(Ok(70)).await; + let broker = + DelegationBroker::new(mock.clone() as Arc, shallow_lookup()); + enable_delegation(&broker).await; + let driver = { + let broker = broker.clone(); + tokio::spawn(async move { broker.handle_request(request(1, "pt-ok")).await }) + }; + let call_id = loop { + if let Some(id) = broker.peek_first_pending_call_id().await { + break id; + } + tokio::time::sleep(Duration::from_millis(5)).await; + }; + // Parked → the in-flight record was handed off (deregistered) at park. + assert_eq!( + broker.inflight_count().await, + 0, + "park deregisters in-flight" + ); + broker + .complete_call( + &call_id, + DelegationOutcome::Ok(DelegationSuccess { + text: "ok".into(), + child_conversation_id: 70, + child_agent_type: AgentType::ClaudeCode, + turn_count: 1, + duration_ms: 5, + token_usage: None, + }), + ) + .await; + assert!(matches!(driver.await.unwrap(), DelegationOutcome::Ok(_))); + assert_eq!(broker.inflight_count().await, 0); + } + + #[tokio::test] + async fn inflight_drained_on_disabled() { + let broker = DelegationBroker::new( + Arc::new(MockSpawner::new()) as Arc, + shallow_lookup(), + ); + // `enabled` defaults to false → short-circuits at the disabled check. + let outcome = broker.handle_request(request(1, "pt-d")).await; + assert!(matches!(outcome, DelegationOutcome::Err { .. })); + assert_eq!(broker.inflight_count().await, 0); + } + + #[tokio::test] + async fn inflight_drained_on_spawn_failure() { + let mock = Arc::new(MockSpawner::new()); + mock.queue_spawn(Err(SpawnerError::Spawn("nope".into()))) + .await; + let broker = + DelegationBroker::new(mock.clone() as Arc, shallow_lookup()); + enable_delegation(&broker).await; + match broker.handle_request(request(1, "pt-sf")).await { + DelegationOutcome::Err { code, .. } => assert_eq!(code, "spawn_failed"), + other => panic!("expected spawn_failed, got {other:?}"), + } + assert_eq!(broker.inflight_count().await, 0); + assert!(mock.disconnects.lock().await.is_empty()); + } + + #[tokio::test] + async fn inflight_drained_on_send_failure() { + let mock = Arc::new(MockSpawner::new()); + mock.queue_spawn(Ok("c6".into())).await; + mock.queue_send(Err(SpawnerError::Send("boom".into()))) + .await; + let broker = + DelegationBroker::new(mock.clone() as Arc, shallow_lookup()); + enable_delegation(&broker).await; + match broker.handle_request(request(1, "pt-sendf")).await { + DelegationOutcome::Err { code, .. } => assert_eq!(code, "spawn_failed"), + other => panic!("expected spawn_failed, got {other:?}"), + } + assert_eq!(broker.inflight_count().await, 0); + assert_eq!(mock.disconnects.lock().await.as_slice(), &["c6"]); + assert!(mock.cancels.lock().await.is_empty()); + } + + /// A terminal failure for a child the broker never reserved (unknown id, or + /// one whose delegation already fully resolved) is a clean no-op — it must + /// not buffer, so the buffer can only ever hold genuine pre-registration + /// races. + #[tokio::test] + async fn cancel_for_unreserved_child_never_buffers() { + let broker = DelegationBroker::new( + Arc::new(MockSpawner::new()) as Arc, + shallow_lookup(), + ); + broker + .cancel_by_child_connection("never-reserved", Some("boom")) + .await; + assert_eq!(broker.early_cancel_count().await, 0); + assert_eq!(broker.pending_count().await, 0); + } + + #[tokio::test] + async fn meta_writer_records_failed_on_parent_cancel() { + let mock = Arc::new(MockSpawner::new()); + mock.queue_spawn(Ok("c-cancel".into())).await; + mock.queue_send(Ok(33)).await; + let writer = Arc::new(MockMetaWriter::new()); + let broker = broker_with_meta(mock.clone(), writer.clone()).await; + + let driver = { + let broker = broker.clone(); + tokio::spawn(async move { broker.handle_request(request(1, "pt-pcancel")).await }) + }; + while broker.pending_count().await == 0 { + tokio::time::sleep(Duration::from_millis(5)).await; + } + broker.cancel_by_parent("parent-conn").await; + let outcome = driver.await.unwrap(); + assert!(matches!(outcome, DelegationOutcome::Err { .. })); + + let calls = writer.snapshot().await; + // running + canceled + assert_eq!(calls.len(), 2); + let inner = calls[1] + .meta + .get("codeg.delegation") + .unwrap() + .as_object() + .unwrap(); + assert_eq!(inner.get("status").unwrap().as_str().unwrap(), "failed"); + assert_eq!( + inner.get("error_code").unwrap().as_str().unwrap(), + "canceled" + ); + } + + #[tokio::test] + async fn meta_writer_skipped_for_synthetic_parent_tool_use_id() { + let mock = Arc::new(MockSpawner::new()); + mock.queue_spawn(Ok("c-synth".into())).await; + mock.queue_send(Ok(8)).await; + let writer = Arc::new(MockMetaWriter::new()); + let broker = broker_with_meta(mock.clone(), writer.clone()).await; + + // Empty `parent_tool_use_id` triggers the broker's UUID fallback — + // `"delegation-"` — which the writer must skip because no + // matching ACP tool_call_id exists. + let driver = { + let broker = broker.clone(); + tokio::spawn(async move { broker.handle_request(request(1, "")).await }) + }; + let call_id = loop { + if let Some(id) = broker.peek_first_pending_call_id().await { + break id; + } + tokio::time::sleep(Duration::from_millis(5)).await; + }; + broker + .complete_call( + &call_id, + DelegationOutcome::Ok(DelegationSuccess { + text: "ok".into(), + child_conversation_id: 8, + child_agent_type: AgentType::Codex, + turn_count: 1, + duration_ms: 5, + token_usage: None, + }), + ) + .await; + driver.await.unwrap(); + + let calls = writer.snapshot().await; + assert!( + calls.is_empty(), + "writer should be skipped for synthetic parent_tool_use_id, got {:?}", + calls + ); + } + + // -- Event emitter lifecycle ------------------------------------------ + // + // Issue: `.docs/issues/2026-05-24-delegation-termination-cascade.md`. + // The broker must emit `AcpEvent::DelegationCompleted` once per drained + // pending entry, regardless of which terminal path drained it (happy + // `complete_call`, MCP `cancel_by_external_handle`, child-disconnect + // cleanup, or parent-cancel cascade). Without these emits the frontend's live + // delegation binding stays at "running" forever — see the issue doc + // for the full path matrix. + + use crate::acp::delegation::event_emitter::mock::MockEventEmitter; + use crate::acp::delegation::event_emitter::DelegationEventEmitter; + use crate::acp::types::DelegationResultSummary; + + async fn broker_with_emitter( + mock: Arc, + writer: Arc, + emitter: Arc, + ) -> DelegationBroker { + let broker = DelegationBroker::with_writers( + mock as Arc, + shallow_lookup(), + writer as Arc, + emitter as Arc, + ); + enable_delegation(&broker).await; + broker + } + + #[tokio::test] + async fn emitter_records_ok_on_complete_call_happy_path() { + let mock = Arc::new(MockSpawner::new()); + mock.queue_spawn(Ok("child-conn-1".into())).await; + mock.queue_send(Ok(42)).await; + let writer = Arc::new(MockMetaWriter::new()); + let emitter = Arc::new(MockEventEmitter::new()); + let broker = broker_with_emitter(mock.clone(), writer.clone(), emitter.clone()).await; + + let driver = { + let broker = broker.clone(); + tokio::spawn(async move { broker.handle_request(request(1, "pt-ok")).await }) + }; + let call_id = loop { + if let Some(id) = broker.peek_first_pending_call_id().await { + break id; + } + tokio::time::sleep(Duration::from_millis(5)).await; + }; + broker + .complete_call( + &call_id, + DelegationOutcome::Ok(DelegationSuccess { + text: "done".into(), + child_conversation_id: 42, + child_agent_type: AgentType::ClaudeCode, + turn_count: 1, + duration_ms: 73, + token_usage: None, + }), + ) + .await; + driver.await.unwrap(); + + let calls = emitter.snapshot().await; + assert_eq!(calls.len(), 1); + let call = &calls[0]; + assert_eq!(call.parent_tool_use_id, "pt-ok"); + assert_eq!(call.child_connection_id, "child-conn-1"); + assert_eq!(call.child_conversation_id, 42); + // The completed event carries the child agent_type (from the running + // task), so a frontend that missed `DelegationStarted` still binds the + // correct agent. `request()` delegates to ClaudeCode. + assert_eq!(call.agent_type, AgentType::ClaudeCode); + // duration_ms is now broker-measured (not the outcome's value); assert + // the Ok variant + the enriched text_preview instead. + assert!( + matches!( + &call.result, + DelegationResultSummary::Ok { text_preview, .. } + if text_preview.as_deref() == Some("done") + ), + "expected Ok with preview, got {:?}", + call.result + ); + } + + #[tokio::test] + async fn emitter_records_started_on_start_delegation_happy_path() { + let mock = Arc::new(MockSpawner::new()); + mock.queue_spawn(Ok("child-conn-start".into())).await; + mock.queue_send(Ok(55)).await; + let writer = Arc::new(MockMetaWriter::new()); + let emitter = Arc::new(MockEventEmitter::new()); + let broker = broker_with_emitter(mock.clone(), writer.clone(), emitter.clone()).await; + + let driver = { + let broker = broker.clone(); + tokio::spawn(async move { broker.handle_request(request(1, "pt-start")).await }) + }; + let call_id = loop { + if let Some(id) = broker.peek_first_pending_call_id().await { + break id; + } + tokio::time::sleep(Duration::from_millis(5)).await; + }; + + // `started` fires during setup, BEFORE the task parks — so it is already + // recorded by the time a pending entry is visible, and it must not be + // conflated with the (not-yet-emitted) terminal. + let started = emitter.started_snapshot().await; + assert_eq!(started.len(), 1, "exactly one DelegationStarted per task"); + let s = &started[0]; + assert_eq!(s.parent_connection_id, "parent-conn"); + assert_eq!(s.parent_tool_use_id, "pt-start"); + assert_eq!(s.child_connection_id, "child-conn-start"); + assert_eq!(s.child_conversation_id, 55); + assert_eq!(s.agent_type, AgentType::ClaudeCode); + assert_eq!( + emitter.count().await, + 0, + "no terminal emit before completion" + ); + + broker + .complete_call( + &call_id, + DelegationOutcome::Ok(DelegationSuccess { + text: "done".into(), + child_conversation_id: 55, + child_agent_type: AgentType::ClaudeCode, + turn_count: 1, + duration_ms: 10, + token_usage: None, + }), + ) + .await; + driver.await.unwrap(); + + // Completion adds exactly one terminal emit; started stays at 1. + assert_eq!(emitter.started_count().await, 1); + assert_eq!(emitter.count().await, 1); + } + + #[tokio::test] + async fn emitter_skips_started_for_synthetic_parent_tool_use_id() { + let mock = Arc::new(MockSpawner::new()); + mock.queue_spawn(Ok("c-synth-start".into())).await; + mock.queue_send(Ok(9)).await; + let writer = Arc::new(MockMetaWriter::new()); + let emitter = Arc::new(MockEventEmitter::new()); + let broker = broker_with_emitter(mock.clone(), writer.clone(), emitter.clone()).await; + + // Empty parent_tool_use_id → broker falls back to a synthetic + // `delegation-` id (no ACP tool_call to claim in a mock harness). + let driver = { + let broker = broker.clone(); + tokio::spawn(async move { broker.handle_request(request(1, "")).await }) + }; + let call_id = loop { + if let Some(id) = broker.peek_first_pending_call_id().await { + break id; + } + tokio::time::sleep(Duration::from_millis(5)).await; + }; + broker + .complete_call( + &call_id, + DelegationOutcome::Ok(DelegationSuccess { + text: "ok".into(), + child_conversation_id: 9, + child_agent_type: AgentType::Codex, + turn_count: 1, + duration_ms: 5, + token_usage: None, + }), + ) + .await; + driver.await.unwrap(); + + assert_eq!( + emitter.started_count().await, + 0, + "started emit must skip synthetic parent_tool_use_id (same rule as the meta writer / completed emit)" + ); + } + + #[tokio::test] + async fn emitter_records_err_on_complete_call_err_outcome() { + let mock = Arc::new(MockSpawner::new()); + mock.queue_spawn(Ok("child-conn-err".into())).await; + mock.queue_send(Ok(11)).await; + let writer = Arc::new(MockMetaWriter::new()); + let emitter = Arc::new(MockEventEmitter::new()); + let broker = broker_with_emitter(mock.clone(), writer.clone(), emitter.clone()).await; + + let driver = { + let broker = broker.clone(); + tokio::spawn(async move { broker.handle_request(request(1, "pt-err")).await }) + }; + let call_id = loop { + if let Some(id) = broker.peek_first_pending_call_id().await { + break id; + } + tokio::time::sleep(Duration::from_millis(5)).await; + }; + broker + .complete_call( + &call_id, + DelegationOutcome::from_err( + DelegationError::SubagentRuntimeError("agent died".into()), + Some(11), + ), + ) + .await; + driver.await.unwrap(); + + let calls = emitter.snapshot().await; + assert_eq!(calls.len(), 1); + match &calls[0].result { + DelegationResultSummary::Err { error_code } => { + assert_eq!(error_code, "subagent_error") + } + other => panic!("expected Err, got {other:?}"), + } + } + + #[tokio::test] + async fn emitter_records_canceled_on_cancel_by_external_handle() { + // MCP-driven cancel path: companion received notifications/cancelled + // and the listener forwarded it to broker.cancel_by_external_handle. + // The broker must drain the pending entry, cancel + disconnect the + // child, and emit DelegationCompleted with error_code = "canceled". + let mock = Arc::new(MockSpawner::new()); + mock.queue_spawn(Ok("child-conn-h".into())).await; + mock.queue_send(Ok(91)).await; + let writer = Arc::new(MockMetaWriter::new()); + let emitter = Arc::new(MockEventEmitter::new()); + let broker = broker_with_emitter(mock.clone(), writer.clone(), emitter.clone()).await; + + let driver = { + let broker = broker.clone(); + tokio::spawn(async move { + broker + .handle_request(request_with_handle(1, "pt-mcp-cancel", "h-1")) + .await + }) + }; + while broker.pending_count().await == 0 { + tokio::time::sleep(Duration::from_millis(5)).await; + } + broker + .cancel_by_external_handle("h-1", "user requested".into()) + .await; + let outcome = driver.await.unwrap(); + assert!(matches!( + outcome, + DelegationOutcome::Err { ref code, .. } if code == "canceled" + )); + + assert_eq!(mock.cancels.lock().await.as_slice(), &["child-conn-h"]); + let calls = emitter.snapshot().await; + assert_eq!(calls.len(), 1, "expected exactly one emit, got {calls:?}"); + let call = &calls[0]; + assert_eq!(call.parent_tool_use_id, "pt-mcp-cancel"); + assert_eq!(call.child_connection_id, "child-conn-h"); + assert_eq!(call.child_conversation_id, 91); + match &call.result { + DelegationResultSummary::Err { error_code } => { + assert_eq!(error_code, "canceled") + } + other => panic!("expected Err{{canceled}}, got {other:?}"), + } + } + + #[tokio::test] + async fn cancel_by_external_handle_no_match_buffers_pre_cancel() { + // Cancel arrives before handle_request reaches pending registration. + // The broker must buffer the handle in pre_canceled_handles so the + // in-flight call drains itself on its post-registration checkpoint. + let mock = Arc::new(MockSpawner::new()); + mock.queue_spawn(Ok("child-conn-pre".into())).await; + mock.queue_send(Ok(13)).await; + let writer = Arc::new(MockMetaWriter::new()); + let emitter = Arc::new(MockEventEmitter::new()); + let broker = broker_with_emitter(mock.clone(), writer.clone(), emitter.clone()).await; + + // Pre-cancel before spawning the driver — handle is unknown to the + // broker right now, but a buffered entry should make the next + // handle_request with the same handle bail out canceled. + broker + .cancel_by_external_handle("h-pre", "early cancel".into()) + .await; + // Pre-cancel set is single-shot: a second call with the same handle + // and no pending entry just buffers it again (idempotent in practice). + let outcome = broker + .handle_request(request_with_handle(1, "pt-pre", "h-pre")) + .await; + match outcome { + DelegationOutcome::Err { code, .. } => assert_eq!(code, "canceled"), + other => panic!("expected canceled, got {other:?}"), + } + // Since the cancel won pre-spawn, no child connection should have + // been opened. + assert!(mock.cancels.lock().await.is_empty()); + assert!(mock.disconnects.lock().await.is_empty()); + // The pre-cancel early-return must also drop the in-flight record + // (registered as handle_request's first statement, before this check). + assert_eq!(broker.inflight_count().await, 0); + } + + /// The real MCP-shaped path carries an `external_handle`. Registration now + /// happens as `handle_request`'s FIRST statement — before the pre-cancel + /// `.await` — so a parent cancel in the setup window reaches these requests + /// too, not just the synthetic-id path. Guards the regression Codex flagged + /// (registration ordered after the pre-cancel await left a miss window). + #[tokio::test] + async fn parent_cancel_covers_external_handle_setup_window() { + let mock = Arc::new(MockSpawner::new()); + mock.queue_spawn(Ok("c-eh".into())).await; + mock.queue_send(Ok(21)).await; + let release = mock.install_send_gate().await; + let broker = + DelegationBroker::new(mock.clone() as Arc, shallow_lookup()); + enable_delegation(&broker).await; + + let driver = { + let broker = broker.clone(); + tokio::spawn(async move { + broker + .handle_request(request_with_handle(1, "pt-eh", "h-eh")) + .await + }) + }; + loop { + if broker.reserved_child_count().await == 1 { + break; + } + tokio::time::sleep(Duration::from_millis(5)).await; + } + assert_eq!(broker.inflight_count().await, 1); + + broker.cancel_by_parent_turn("parent-conn").await; + let _ = release.send(()); + + match driver.await.unwrap() { + DelegationOutcome::Err { code, .. } => assert_eq!(code, "canceled"), + other => panic!("expected canceled, got {other:?}"), + } + assert_eq!(mock.cancels.lock().await.as_slice(), &["c-eh"]); + assert_eq!(mock.disconnects.lock().await.as_slice(), &["c-eh"]); + assert_eq!(broker.inflight_count().await, 0); + } + + #[tokio::test] + async fn emitter_records_canceled_on_cancel_by_child_connection() { + let mock = Arc::new(MockSpawner::new()); + mock.queue_spawn(Ok("c-dropped".into())).await; + mock.queue_send(Ok(55)).await; + let writer = Arc::new(MockMetaWriter::new()); + let emitter = Arc::new(MockEventEmitter::new()); + let broker = broker_with_emitter(mock.clone(), writer.clone(), emitter.clone()).await; + + let driver = { + let broker = broker.clone(); + tokio::spawn(async move { broker.handle_request(request(1, "pt-cbc")).await }) + }; + while broker.pending_count().await == 0 { + tokio::time::sleep(Duration::from_millis(5)).await; + } + broker.cancel_by_child_connection("c-dropped", None).await; + let outcome = driver.await.unwrap(); + match &outcome { + DelegationOutcome::Err { code, message, .. } => { + assert_eq!(code, "canceled"); + // No terminal_error supplied → falls back to default reason. + assert_eq!( + message, + "canceled: child session ended without TurnComplete" + ); + } + other => panic!("expected Err{{canceled}}, got {other:?}"), + } + + let calls = emitter.snapshot().await; + assert_eq!(calls.len(), 1); + match &calls[0].result { + DelegationResultSummary::Err { error_code } => { + assert_eq!(error_code, "canceled") + } + other => panic!("expected Err{{canceled}}, got {other:?}"), + } + } + + #[tokio::test] + async fn cancel_by_child_connection_threads_terminal_error_into_reason() { + // The lifecycle worker forwards the child's last AcpEvent::Error + // detail through `cancel_by_child_connection`. The broker stitches it + // into the `Canceled { reason }` message so the parent's + // `delegate_to_agent` tool-call result surfaces the real failure + // cause (e.g. Gemini OAuth expired) instead of the opaque default. + let mock = Arc::new(MockSpawner::new()); + mock.queue_spawn(Ok("c-auth".into())).await; + mock.queue_send(Ok(77)).await; + let writer = Arc::new(MockMetaWriter::new()); + let emitter = Arc::new(MockEventEmitter::new()); + let broker = broker_with_emitter(mock.clone(), writer.clone(), emitter.clone()).await; + + let driver = { + let broker = broker.clone(); + tokio::spawn(async move { broker.handle_request(request(1, "pt-auth")).await }) + }; + while broker.pending_count().await == 0 { + tokio::time::sleep(Duration::from_millis(5)).await; + } + broker + .cancel_by_child_connection("c-auth", Some("[auth_required] Authentication required")) + .await; + let outcome = driver.await.unwrap(); + match &outcome { + DelegationOutcome::Err { code, message, .. } => { + assert_eq!(code, "canceled"); + assert_eq!( + message, + "canceled: child session ended without TurnComplete: \ + [auth_required] Authentication required" + ); + } + other => panic!("expected Err{{canceled}}, got {other:?}"), + } + } + + #[tokio::test] + async fn cancel_by_child_connection_ignores_empty_terminal_error() { + // Whitespace-only or empty detail strings shouldn't produce a + // dangling "...:" suffix on the reason — fall back to the default. + let mock = Arc::new(MockSpawner::new()); + mock.queue_spawn(Ok("c-empty".into())).await; + mock.queue_send(Ok(78)).await; + let broker = + DelegationBroker::new(mock.clone() as Arc, shallow_lookup()); + enable_delegation(&broker).await; + + let driver = { + let broker = broker.clone(); + tokio::spawn(async move { broker.handle_request(request(1, "pt-empty")).await }) + }; + while broker.pending_count().await == 0 { + tokio::time::sleep(Duration::from_millis(5)).await; + } + broker + .cancel_by_child_connection("c-empty", Some(" ")) + .await; + let outcome = driver.await.unwrap(); + match &outcome { + DelegationOutcome::Err { message, .. } => { + assert_eq!( + message, + "canceled: child session ended without TurnComplete" + ); + } + other => panic!("expected Err, got {other:?}"), + } + } + + #[tokio::test] + async fn emitter_records_one_event_per_drained_entry_on_cancel_by_parent() { + let mock = Arc::new(MockSpawner::new()); + for i in 0..3 { + mock.queue_spawn(Ok(format!("c{i}"))).await; + mock.queue_send(Ok(100 + i)).await; + } + let writer = Arc::new(MockMetaWriter::new()); + let emitter = Arc::new(MockEventEmitter::new()); + let broker = broker_with_emitter(mock.clone(), writer.clone(), emitter.clone()).await; + + let mut handles = Vec::new(); + for i in 0..3 { + let broker = broker.clone(); + handles.push(tokio::spawn(async move { + broker.handle_request(request(1, &format!("pt-{i}"))).await + })); + } + while broker.pending_count().await < 3 { + tokio::time::sleep(Duration::from_millis(5)).await; + } + broker.cancel_by_parent("parent-conn").await; + for h in handles { + let _ = h.await.unwrap(); + } + + let calls = emitter.snapshot().await; + assert_eq!(calls.len(), 3, "expected 3 emits, got {calls:?}"); + let mut parent_tool_use_ids: Vec = + calls.iter().map(|c| c.parent_tool_use_id.clone()).collect(); + parent_tool_use_ids.sort(); + assert_eq!( + parent_tool_use_ids, + vec!["pt-0".to_string(), "pt-1".to_string(), "pt-2".to_string()] + ); + for call in &calls { + match &call.result { + DelegationResultSummary::Err { error_code } => { + assert_eq!(error_code, "canceled") + } + other => panic!("expected Err{{canceled}}, got {other:?}"), + } + } + } + + #[tokio::test] + async fn emitter_does_not_double_emit_on_repeat_cancel_by_parent() { + let mock = Arc::new(MockSpawner::new()); + mock.queue_spawn(Ok("c-once".into())).await; + mock.queue_send(Ok(42)).await; + let writer = Arc::new(MockMetaWriter::new()); + let emitter = Arc::new(MockEventEmitter::new()); + let broker = broker_with_emitter(mock.clone(), writer.clone(), emitter.clone()).await; + + let driver = { + let broker = broker.clone(); + tokio::spawn(async move { broker.handle_request(request(1, "pt-idem")).await }) + }; + while broker.pending_count().await == 0 { + tokio::time::sleep(Duration::from_millis(5)).await; + } + // First call drains the entry + emits one. + broker.cancel_by_parent("parent-conn").await; + // Second call finds the pending map empty — no extra emit. + broker.cancel_by_parent("parent-conn").await; + // Cleanup-guard-style triple call also stays bounded. + broker.cancel_by_parent("parent-conn").await; + let _ = driver.await.unwrap(); + + assert_eq!(emitter.count().await, 1); + } + + #[tokio::test] + async fn emitter_skipped_for_synthetic_parent_tool_use_id() { + let mock = Arc::new(MockSpawner::new()); + mock.queue_spawn(Ok("c-synth".into())).await; + mock.queue_send(Ok(8)).await; + let writer = Arc::new(MockMetaWriter::new()); + let emitter = Arc::new(MockEventEmitter::new()); + let broker = broker_with_emitter(mock.clone(), writer.clone(), emitter.clone()).await; + + let driver = { + let broker = broker.clone(); + tokio::spawn(async move { broker.handle_request(request(1, "")).await }) + }; + let call_id = loop { + if let Some(id) = broker.peek_first_pending_call_id().await { + break id; + } + tokio::time::sleep(Duration::from_millis(5)).await; + }; + broker + .complete_call( + &call_id, + DelegationOutcome::Ok(DelegationSuccess { + text: "ok".into(), + child_conversation_id: 8, + child_agent_type: AgentType::Codex, + turn_count: 1, + duration_ms: 5, + token_usage: None, + }), + ) + .await; + driver.await.unwrap(); + + let calls = emitter.snapshot().await; + assert!( + calls.is_empty(), + "emitter must skip synthetic parent_tool_use_id (same rule as meta writer); got {calls:?}" + ); + } + + #[tokio::test] + async fn emitter_records_after_meta_write_on_complete_call() { + // Frontend's snapshot-recovery path reads `meta["codeg.delegation"]` + // first and the live event second; if the emit lands before the + // meta write, a snapshot taken between them would see "running" + // meta paired with a "completed" event. Enforce meta-before-emit + // by checking the MockMetaWriter has at least one call before the + // emitter records. + let mock = Arc::new(MockSpawner::new()); + mock.queue_spawn(Ok("c-order".into())).await; + mock.queue_send(Ok(7)).await; + let writer = Arc::new(MockMetaWriter::new()); + let emitter = Arc::new(MockEventEmitter::new()); + let broker = broker_with_emitter(mock.clone(), writer.clone(), emitter.clone()).await; + + let driver = { + let broker = broker.clone(); + tokio::spawn(async move { broker.handle_request(request(1, "pt-order")).await }) + }; + let call_id = loop { + if let Some(id) = broker.peek_first_pending_call_id().await { + break id; + } + tokio::time::sleep(Duration::from_millis(5)).await; + }; + broker + .complete_call( + &call_id, + DelegationOutcome::Ok(DelegationSuccess { + text: "ok".into(), + child_conversation_id: 7, + child_agent_type: AgentType::ClaudeCode, + turn_count: 1, + duration_ms: 5, + token_usage: None, + }), + ) + .await; + driver.await.unwrap(); + + let meta_calls = writer.snapshot().await; + let event_calls = emitter.snapshot().await; + // running (from handle_request) + completed (from complete_call) = + // 2 meta writes. The single event must be the "completed" one, + // and it must land AFTER the running meta — guaranteed structurally + // by complete_call's order (write_meta_if_real then emit). + assert_eq!(meta_calls.len(), 2); + assert_eq!(event_calls.len(), 1); + let inner_second = meta_calls[1] + .meta + .get("codeg.delegation") + .unwrap() + .as_object() + .unwrap(); + assert_eq!( + inner_second.get("status").unwrap().as_str().unwrap(), + "completed" + ); + } + + // -- Production-path fanout coverage ---------------------------------- + // + // Every other emitter test in this module uses `MockEventEmitter`. The + // production wiring goes through `ConnectionManagerEventEmitter`, which + // resolves `(state, emitter)` against the live `ConnectionManager` and + // hands the event to `emit_with_state` so it fans out to (1) the parent + // connection's `ConnectionEventStream` (the WS attach path) and (2) the + // `InternalEventBus` (the lifecycle/pet/chat-channel subscriber path). + // These tests exercise that real fanout end-to-end so a regression in + // `get_state_and_emitter` lookup, `emit_with_state` routing, or the + // `EventEmitter::WebOnly { bus, .. }` wiring is caught here even when + // every mock-backed test stays green. + + #[tokio::test] + async fn real_emitter_fans_out_delegation_completed_to_parent_stream_and_bus() { + use crate::acp::delegation::event_emitter::ConnectionManagerEventEmitter; + use crate::acp::manager::ConnectionManager; + use crate::acp::types::AcpEvent; + use crate::web::event_bridge::{EventEmitter, WebEventBroadcaster}; + + // Real ConnectionManager + fake parent wired to a WebOnly emitter so + // the InternalEventBus gets typed envelopes and we can subscribe to + // verify the lifecycle-path delivery alongside the per-connection + // stream delivery. + let manager = ConnectionManager::new(); + let broadcaster = Arc::new(WebEventBroadcaster::new()); + let parent_emitter = EventEmitter::test_web_only(broadcaster); + let bus = parent_emitter + .acp_event_bus() + .expect("WebOnly emitter must expose an InternalEventBus"); + manager + .insert_test_connection("parent-conn", AgentType::ClaudeCode, None, parent_emitter) + .await; + + // Subscribe BEFORE triggering events — broadcast channels drop + // sends that happen with no receivers registered. + let mut bus_rx = bus.subscribe(); + let (parent_state, _) = manager + .get_state_and_emitter("parent-conn") + .await + .expect("parent just inserted"); + let mut stream_rx = parent_state.read().await.event_stream().subscribe(); + + // Build the broker with the PRODUCTION emitter; meta writer can stay + // noop because this test is asserting the event-fanout invariant. + let mock_spawner = Arc::new(MockSpawner::new()); + mock_spawner.queue_spawn(Ok("child-conn-real".into())).await; + mock_spawner.queue_send(Ok(77)).await; + let real_emitter = Arc::new(ConnectionManagerEventEmitter { + manager: Arc::new(manager.clone_ref()), + }); + let broker = DelegationBroker::with_writers( + mock_spawner.clone() as Arc, + shallow_lookup(), + Arc::new(crate::acp::delegation::meta_writer::NoopMetaWriter) + as Arc, + real_emitter as Arc, + ); + enable_delegation(&broker).await; + + // Park a pending entry then trigger cancel_by_parent to drive the + // production emit path. `request()` hard-codes parent_connection_id + // = "parent-conn" which matches the insert above. + let driver = { + let broker = broker.clone(); + tokio::spawn(async move { broker.handle_request(request(1, "pt-fanout")).await }) + }; + while broker.pending_count().await == 0 { + tokio::time::sleep(Duration::from_millis(5)).await; + } + broker.cancel_by_parent("parent-conn").await; + let _ = driver.await.unwrap(); + + // Per-connection stream (WS attach delivery path) must receive the + // envelope tagged with the right connection + payload shape. + // The parent stream now also carries the setup-time DelegationStarted; + // skip past it to the terminal DelegationCompleted. + let envelope = loop { + let env = tokio::time::timeout(Duration::from_millis(500), stream_rx.recv()) + .await + .expect("per-connection stream should receive DelegationCompleted within 500ms") + .expect("envelope recv must not error"); + if matches!(env.payload, AcpEvent::DelegationStarted { .. }) { + continue; + } + break env; + }; + assert_eq!(envelope.connection_id, "parent-conn"); + match &envelope.payload { + AcpEvent::DelegationCompleted { + parent_tool_use_id, + child_connection_id, + child_conversation_id, + result, + .. + } => { + assert_eq!(parent_tool_use_id, "pt-fanout"); + assert_eq!(child_connection_id, "child-conn-real"); + assert_eq!(*child_conversation_id, 77); + match result { + DelegationResultSummary::Err { error_code } => { + assert_eq!(error_code, "canceled"); + } + other => panic!("expected Err{{canceled}}, got {other:?}"), + } + } + other => panic!("expected DelegationCompleted, got {other:?}"), + } + + // InternalEventBus (lifecycle/pet/chat-channel subscriber path) must + // also receive the same envelope — proves the WebOnly emitter's bus + // arm in `emit_with_state` is reached. + let bus_envelope = loop { + let env = tokio::time::timeout(Duration::from_millis(500), bus_rx.recv()) + .await + .expect("InternalEventBus should receive DelegationCompleted within 500ms") + .expect("bus recv must not error"); + if matches!(env.payload, AcpEvent::DelegationStarted { .. }) { + continue; + } + break env; + }; + assert_eq!(bus_envelope.connection_id, "parent-conn"); + assert!(matches!( + bus_envelope.payload, + AcpEvent::DelegationCompleted { .. } + )); + } + + #[tokio::test] + async fn real_emitter_fans_out_delegation_started_to_parent_stream_and_bus() { + use crate::acp::delegation::event_emitter::ConnectionManagerEventEmitter; + use crate::acp::manager::ConnectionManager; + use crate::acp::types::AcpEvent; + use crate::web::event_bridge::{EventEmitter, WebEventBroadcaster}; + + // Web/server delivery shape: a real ConnectionManager + a fake parent on + // a WebOnly emitter. `DelegationStarted` must land on the PARENT's + // per-connection stream (the WS attach path the frontend subscribes to + // in web/server mode) AND the InternalEventBus — mirroring the + // completed-path invariant. This is the regression lock for the + // web-mode live-delegation gap: before moving the emit to the parent + // stream, started rode the (un-attached) child stream and was lost here. + let manager = ConnectionManager::new(); + let broadcaster = Arc::new(WebEventBroadcaster::new()); + let parent_emitter = EventEmitter::test_web_only(broadcaster); + let bus = parent_emitter + .acp_event_bus() + .expect("WebOnly emitter must expose an InternalEventBus"); + manager + .insert_test_connection("parent-conn", AgentType::ClaudeCode, None, parent_emitter) + .await; + + // Subscribe BEFORE triggering events — broadcast channels drop sends + // that happen with no receivers registered. + let mut bus_rx = bus.subscribe(); + let (parent_state, _) = manager + .get_state_and_emitter("parent-conn") + .await + .expect("parent just inserted"); + let mut stream_rx = parent_state.read().await.event_stream().subscribe(); + + let mock_spawner = Arc::new(MockSpawner::new()); + mock_spawner + .queue_spawn(Ok("child-conn-started".into())) + .await; + mock_spawner.queue_send(Ok(88)).await; + let real_emitter = Arc::new(ConnectionManagerEventEmitter { + manager: Arc::new(manager.clone_ref()), + }); + let broker = DelegationBroker::with_writers( + mock_spawner.clone() as Arc, + shallow_lookup(), + Arc::new(crate::acp::delegation::meta_writer::NoopMetaWriter) + as Arc, + real_emitter as Arc, + ); + enable_delegation(&broker).await; + + // `started` fires during setup, before park — drive the request, wait + // for it to park, then assert the envelope already arrived. + let driver = { + let broker = broker.clone(); + tokio::spawn(async move { broker.handle_request(request(1, "pt-started")).await }) + }; + while broker.pending_count().await == 0 { + tokio::time::sleep(Duration::from_millis(5)).await; + } + + let envelope = tokio::time::timeout(Duration::from_millis(500), stream_rx.recv()) + .await + .expect("per-connection stream should receive DelegationStarted within 500ms") + .expect("envelope recv must not error"); + assert_eq!(envelope.connection_id, "parent-conn"); + match &envelope.payload { + AcpEvent::DelegationStarted { + parent_connection_id, + parent_tool_use_id, + child_connection_id, + child_conversation_id, + agent_type, + task_preview, + task_id, + } => { + assert_eq!(parent_connection_id, "parent-conn"); + assert_eq!(parent_tool_use_id, "pt-started"); + assert_eq!(child_connection_id, "child-conn-started"); + assert_eq!(*child_conversation_id, 88); + assert_eq!(*agent_type, AgentType::ClaudeCode); + // The event labels the card even when the parent tool call's + // raw_input never carried the arguments (identity-less hosts). + assert_eq!(task_preview, "do x"); + assert!(!task_id.is_empty(), "broker-minted task id must ride the event"); + } + other => panic!("expected DelegationStarted, got {other:?}"), + } + + let bus_envelope = tokio::time::timeout(Duration::from_millis(500), bus_rx.recv()) + .await + .expect("InternalEventBus should receive DelegationStarted within 500ms") + .expect("bus recv must not error"); + assert_eq!(bus_envelope.connection_id, "parent-conn"); + assert!(matches!( + bus_envelope.payload, + AcpEvent::DelegationStarted { .. } + )); + + // Drain the parked driver so the test doesn't leak the spawned task. + broker.cancel_by_parent("parent-conn").await; + let _ = driver.await.unwrap(); + } + + #[tokio::test] + async fn real_emitter_is_silent_no_op_when_parent_already_detached() { + // Parent torn down mid-delegation: `get_state_and_emitter` returns + // None, the emit silently drops, BUT the broker still drains its + // pending table and surfaces the outcome to the awaiting caller. + // This is the "parent disappeared before terminal" path that the + // mock-backed tests can't observe. + use crate::acp::delegation::event_emitter::ConnectionManagerEventEmitter; + use crate::acp::manager::ConnectionManager; + + let manager = ConnectionManager::new(); + // Intentionally no insert_test_connection — parent is absent. + let real_emitter = Arc::new(ConnectionManagerEventEmitter { + manager: Arc::new(manager.clone_ref()), + }); + let mock_spawner = Arc::new(MockSpawner::new()); + mock_spawner.queue_spawn(Ok("c-orphan".into())).await; + mock_spawner.queue_send(Ok(1)).await; + let broker = DelegationBroker::with_writers( + mock_spawner.clone() as Arc, + shallow_lookup(), + Arc::new(crate::acp::delegation::meta_writer::NoopMetaWriter) + as Arc, + real_emitter as Arc, + ); + enable_delegation(&broker).await; + + let driver = { + let broker = broker.clone(); + tokio::spawn(async move { broker.handle_request(request(1, "pt-orphan")).await }) + }; + while broker.pending_count().await == 0 { + tokio::time::sleep(Duration::from_millis(5)).await; + } + broker.cancel_by_parent("parent-conn").await; + let outcome = driver.await.unwrap(); + + assert!(matches!( + outcome, + DelegationOutcome::Err { ref code, .. } if code == "canceled" + )); + assert_eq!( + broker.pending_count().await, + 0, + "broker must drain pending even when no parent exists to receive the emit" + ); + } + + // -- Async-cutover review regressions ----------------------------------- + + /// A pre-cancel that bails `start_delegation` before the claim path must + /// still drain the keyed ACP tool_call, so a later same-key delegation + /// can't claim the canceled call's id and mis-bind to the wrong card. + #[tokio::test] + async fn pre_cancel_drains_keyed_tool_call_to_avoid_misbinding() { + let broker = DelegationBroker::new( + Arc::new(MockSpawner::new()) as Arc, + shallow_lookup(), + ); + enable_delegation(&broker).await; + let key = DelegationMatchKey { + agent_type: AgentType::ClaudeCode, + task: "do x".into(), + working_dir: None, + }; + // The lifecycle registered the keyed tool_call for this delegation. + broker + .register_pending_tool_call_with_key("parent-conn", "tc-1".into(), Some(key.clone())) + .await; + // notifications/cancelled lands before the round-trip → buffered (no + // running task yet). + broker.cancel_by_external_handle("h-1", "user".into()).await; + // The MCP round-trip arrives (empty parent_tool_use_id, same key) and + // bails at the first pre-cancel check. + let report = broker + .start_delegation(request_with_handle(1, "", "h-1")) + .await; + assert_eq!(report.status, TaskStatus::Canceled); + // The keyed entry must have been drained — not claimable afterward. + assert_eq!( + broker.take_matching_tool_call("parent-conn", &key).await, + None + ); + } + + /// The running ack must carry the literal task_id in its message, so a + /// client that only surfaces MCP `content` text (not `structuredContent`) + /// can still call get_delegation_status / cancel_delegation. + #[test] + fn running_ack_message_embeds_task_id() { + let report = running_ack("task-xyz".into(), 42, AgentType::Codex); + assert_eq!(report.task_id.as_deref(), Some("task-xyz")); + assert!( + report.message.as_deref().unwrap().contains("task-xyz"), + "ack message must embed the literal task_id, got {:?}", + report.message + ); + } + + /// Previews and cached text must stay within their advertised BYTE caps + /// (including the appended ellipsis), and truncate on UTF-8 boundaries. + #[test] + fn previews_and_cached_text_respect_byte_caps() { + let preview = build_text_preview(&"x".repeat(STATUS_PREVIEW_CAP * 2)).unwrap(); + assert!( + preview.len() <= STATUS_PREVIEW_CAP, + "preview {} > cap {STATUS_PREVIEW_CAP}", + preview.len() + ); + let cached = cap_completed_text(&"y".repeat(COMPLETED_TEXT_CAP * 2)); + assert!(cached.len() <= COMPLETED_TEXT_CAP); + // Multibyte safety: 3-byte chars must not be split, and the cap holds. + let multibyte = build_text_preview(&"€".repeat(STATUS_PREVIEW_CAP)).unwrap(); + assert!(multibyte.len() <= STATUS_PREVIEW_CAP); + assert!(std::str::from_utf8(multibyte.as_bytes()).is_ok()); + } + + // -- completed-cache byte valve ---------------------------------------- + + fn completed_with_text(parent: &str, text_len: usize) -> CompletedTask { + CompletedTask { + parent_connection_id: parent.to_string(), + child_conversation_id: 1, + agent_type: AgentType::ClaudeCode, + status: TaskStatus::Completed, + text: Some("x".repeat(text_len)), + error_code: None, + message: None, + duration_ms: 0, + } + } + + #[test] + fn completed_cache_valve_evicts_oldest_over_byte_budget() { + let mut inner = PendingInner { + completed_cap_bytes: 1000, + ..Default::default() + }; + // Three 400-byte results = 1200 bytes > 1000 cap. Oldest must evict. + inner.insert_completed("a", completed_with_text("p1", 400)); + inner.insert_completed("b", completed_with_text("p1", 400)); + inner.insert_completed("c", completed_with_text("p1", 400)); + assert!(!inner.completed.contains_key("a"), "oldest must be evicted"); + assert!(inner.completed.contains_key("b")); + assert!(inner.completed.contains_key("c"), "newest must be retained"); + // Counter + order reflect only the two retained entries. + assert_eq!(inner.completed_bytes.get("p1").copied(), Some(800)); + assert_eq!(inner.completed_order.get("p1").map(|o| o.len()), Some(2)); + // Survivors keep their FULL text — the valve drops whole entries, it + // never truncates a survivor. + assert_eq!( + inner + .completed + .get("c") + .unwrap() + .text + .as_deref() + .map(str::len), + Some(400) + ); + } + + #[test] + fn completed_cache_valve_keeps_newest_even_if_alone_over_budget() { + // A single result larger than the whole budget is still retained — the + // valve never evicts the entry just inserted (the LLM's immediate + // get_delegation_status must hit). Per-result text is independently + // bounded by COMPLETED_TEXT_CAP. + let mut inner = PendingInner { + completed_cap_bytes: 100, + ..Default::default() + }; + inner.insert_completed("solo", completed_with_text("p1", 500)); + assert!(inner.completed.contains_key("solo")); + assert_eq!(inner.completed_bytes.get("p1").copied(), Some(500)); + } + + #[test] + fn completed_cache_unlimited_when_cap_zero() { + let mut inner = PendingInner::default(); // completed_cap_bytes == 0 + for i in 0..50 { + inner.insert_completed(&format!("t{i}"), completed_with_text("p1", 10_000)); + } + assert_eq!(inner.completed.len(), 50, "cap 0 disables eviction"); + assert_eq!(inner.completed_bytes.get("p1").copied(), Some(500_000)); + } + + #[test] + fn completed_cache_valve_is_per_parent() { + let mut inner = PendingInner { + completed_cap_bytes: 1000, + ..Default::default() + }; + // p1 overflows; p2 stays under its own independent budget. + inner.insert_completed("a1", completed_with_text("p1", 600)); + inner.insert_completed("a2", completed_with_text("p1", 600)); // evicts a1 + inner.insert_completed("b1", completed_with_text("p2", 600)); + assert!(!inner.completed.contains_key("a1")); + assert!(inner.completed.contains_key("a2")); + assert!( + inner.completed.contains_key("b1"), + "p2 must be untouched by p1 overflow" + ); + assert_eq!(inner.completed_bytes.get("p1").copied(), Some(600)); + assert_eq!(inner.completed_bytes.get("p2").copied(), Some(600)); + } + + #[test] + fn drop_completed_for_parent_clears_byte_counter() { + let mut inner = PendingInner::default(); // unlimited; teardown still clears + inner.insert_completed("a", completed_with_text("p1", 100)); + inner.insert_completed("b", completed_with_text("p2", 100)); + inner.drop_completed_for_parent("p1"); + assert!(!inner.completed.contains_key("a")); + assert!(inner.completed.contains_key("b")); + assert_eq!( + inner.completed_bytes.get("p1"), + None, + "byte counter must be cleared on teardown" + ); + assert_eq!(inner.completed_bytes.get("p2").copied(), Some(100)); + } + + #[tokio::test] + async fn lowering_cap_prunes_existing_completed_results() { + let broker = DelegationBroker::new( + Arc::new(MockSpawner::new()) as Arc, + shallow_lookup(), + ); + // Start unlimited and retain several results for one parent. + broker + .set_config(DelegationConfig { + completed_cache_cap_bytes: 0, + ..DelegationConfig::default() + }) + .await; + { + let mut inner = broker.pending.inner.lock().await; + for i in 0..5 { + inner.insert_completed(&format!("t{i}"), completed_with_text("p1", 400)); + } + assert_eq!(inner.completed.len(), 5); + assert_eq!(inner.completed_bytes.get("p1").copied(), Some(2000)); + } + // Lower the cap to 1000 bytes — existing results must be pruned NOW, + // not only on the next completion (which may never arrive). + broker + .set_config(DelegationConfig { + completed_cache_cap_bytes: 1000, + ..DelegationConfig::default() + }) + .await; + let inner = broker.pending.inner.lock().await; + assert!( + inner.completed_bytes.get("p1").copied().unwrap_or(0) <= 1000, + "retained bytes must fit the lowered cap" + ); + assert!( + inner.completed.contains_key("t4"), + "newest result must survive pruning" + ); + assert!( + !inner.completed.contains_key("t0"), + "oldest result must be pruned" + ); + } +} diff --git a/src/i18n/messages/ar.json b/src/i18n/messages/ar.json index 4f4fa4434..cb4b3c0c8 100644 --- a/src/i18n/messages/ar.json +++ b/src/i18n/messages/ar.json @@ -1,4958 +1,4958 @@ -{ - "Language": { - "followSystem": "اتباع النظام", - "english": "الإنجليزية", - "simplifiedChinese": "الصينية المبسطة", - "traditionalChinese": "الصينية التقليدية", - "japanese": "اليابانية", - "korean": "الكورية", - "spanish": "الإسبانية", - "german": "الألمانية", - "french": "الفرنسية", - "portuguese": "البرتغالية", - "arabic": "العربية" - }, - "GitCredentialDialog": { - "title": "المصادقة مطلوبة", - "description": "يتطلب الخادم البعيد بيانات اعتماد. أدخل اسم المستخدم وكلمة المرور (أو رمز الوصول الشخصي).", - "username": "اسم المستخدم", - "usernamePlaceholder": "اسم المستخدم أو البريد الإلكتروني", - "password": "كلمة المرور / الرمز", - "passwordPlaceholder": "كلمة المرور أو رمز الوصول الشخصي", - "passwordHint": "أدخل اسم المستخدم وكلمة المرور للخادم.", - "cancel": "إلغاء", - "authenticate": "مصادقة", - "authenticating": "جارٍ المصادقة...", - "invalidCredentials": "بيانات الاعتماد غير صالحة. يرجى المحاولة مرة أخرى.", - "saveCredentials": "حفظ بيانات الاعتماد للعمليات المستقبلية", - "githubTitle": "مصادقة GitHub", - "githubDescription": "أدخل رمز وصول شخصي للاتصال بـ GitHub. سيتم التحقق من الرمز وحفظه تلقائيًا.", - "githubToken": "رمز الوصول الشخصي", - "githubTokenPlaceholder": "ghp_xxxxxxxxxxxx", - "githubTokenHint": "أنشئ رمزًا في GitHub → Settings → Developer settings → Personal access tokens.", - "githubAuthenticate": "التحقق والاتصال", - "generateToken": "إنشاء رمز" - }, - "SettingsShell": { - "title": "الإعدادات", - "preferences": "التفضيلات", - "nav": { - "general": "عام", - "appearance": "المظهر", - "agents": "الوكلاء", - "mcp": "MCP", - "skills": "Skills", - "shortcuts": "الاختصارات", - "version_control": "التحكم بالإصدارات", - "system": "النظام", - "chat_channels": "قنوات المحادثة", - "web_service": "خدمة الويب", - "model_providers": "مزودو النماذج", - "experts": "الخبراء", - "science": "البحث العلمي", - "office_tools": "أدوات المكتب", - "skill_packs": "حزم المهارات", - "quick_messages": "رسائل سريعة", - "logs": "سجلات التشغيل" - } - }, - "AppearanceSettings": { - "sectionTitle": "مظهر السمة", - "sectionDescription": "اختر الفاتح أو الداكن أو اتباع النظام. يتم حفظ الإعدادات تلقائيًا.", - "themeMode": "وضع السمة", - "placeholder": "اختر وضع السمة", - "system": "اتباع النظام", - "light": "فاتح", - "dark": "داكن", - "currentTheme": "السمة الفعالة الحالية: {theme}", - "resolvedTheme": { - "light": "فاتح", - "dark": "داكن", - "unknown": "--" - }, - "themeColor": { - "sectionTitle": "لون السمة", - "sectionDescription": "اختر لوحة ألوان للتمييزات والأزرار والإبرازات.", - "current": "اللون الحالي: {color}", - "options": { - "neutral": "Neutral", - "zinc": "Zinc", - "slate": "Slate", - "stone": "Stone", - "gray": "Gray", - "red": "Red", - "rose": "Rose", - "orange": "Orange", - "green": "Green", - "blue": "Blue", - "yellow": "Yellow", - "violet": "Violet" - } - }, - "customStyle": { - "sectionTitle": "نمط مخصص", - "sectionDescription": "اضبط ألوان السمة الحالية بدقة، أو أدرج CSS خاصًا بك. تُطبَّق التجاوزات فوق الإعداد الأساسي، لذا تبقى عند تبديل الإعداد.", - "summarySuspended": "موقوف مؤقتًا", - "summaryDefault": "الإعداد الأساسي دون تغيير", - "summaryTokens": "{count, plural, one {# تجاوز} other {# تجاوزات}}", - "summaryCss": "CSS مخصص", - "suspendedByShortcut": "النمط المخصص موقوف مؤقتًا. لن يسري أي إعداد هنا حتى تستأنفه.", - "suspendedBySafeParam": "فُتحت هذه النافذة في وضع المظهر الآمن، لذا يُتجاهل النمط المخصص هنا. لا تتأثر النوافذ الأخرى.", - "resume": "استئناف النمط المخصص", - "enableTheme": "تفعيل الألوان المخصصة", - "editingLight": "تحرير قيم الوضع الفاتح. بدّل التطبيق إلى الوضع الداكن لضبطه على حدة.", - "editingDark": "تحرير قيم الوضع الداكن. بدّل التطبيق إلى الوضع الفاتح لضبطه على حدة.", - "resetToken": "إعادة التعيين إلى قيمة الإعداد", - "radius": "استدارة الزوايا", - "radiusHint": "يشتق منها مقياس الاستدارة كاملًا من sm إلى 4xl، لذا يكفي شريط واحد لتغيير استدارة التطبيق بأكمله.", - "advanced": "متقدم ({count} متغيرات إضافية)", - "enableCss": "تفعيل CSS المخصص", - "cssRisk": "ميزة متقدمة. يتجاوز CSS المخصص جميع الأنماط المدمجة وقد يجعل الواجهة غير قابلة للاستخدام.", - "editCss": "تحرير CSS…", - "cssPresent": "تم حفظ {size} كيلوبايت", - "cssEmpty": "لا يوجد محتوى محفوظ بعد", - "escapeHint": "هل تعطلت الواجهة؟ اضغط {shortcut} لإيقاف كل النمط المخصص، أو افتح نافذة بمعامل الاستعلام safeStyle=1.", - "copyTheme": "نسخ JSON السمة", - "importTheme": "استيراد سمة…", - "clearTheme": "مسح التجاوزات", - "interopHint": "تستخدم السمات صيغة registry:theme من shadcn، فيمكنك لصق أي سمة shadcn هنا واستخدام سماتك المصدَّرة في أي مشروع shadcn.", - "importTitle": "استيراد سمة", - "importDescription": "الصق عنصر registry:theme من shadcn، أو كائن light/dark مجردًا، أو خريطة رموز مسطحة.", - "readClipboard": "قراءة الحافظة", - "importConfirm": "استيراد", - "cancel": "إلغاء", - "apply": "تطبيق", - "toasts": { - "copied": "تم نسخ JSON السمة", - "copyFailed": "تعذّر النسخ إلى الحافظة", - "clipboardReadFailed": "تعذّرت قراءة الحافظة، الصق يدويًا", - "importFailed": "لا توجد متغيرات سمة صالحة في هذا الـ JSON", - "imported": "تم استيراد السمة" - }, - "css": { - "dialogTitle": "CSS مخصص", - "dialogDescription": "يسري على جميع نوافذ codeg. تُعاين التغييرات مباشرة؛ اضغط تطبيق للحفظ.", - "size": "{used} كيلوبايت / {max} كيلوبايت", - "ruleCount": "{count} قاعدة", - "errorTooLarge": "الحجم كبير جدًا للحفظ. قلّصه إلى ما دون الحد.", - "errorImportEscaped": "بقيت قاعدة @import بعد الإزالة (صيغة هروب). أزلها للحفظ.", - "warnNoRules": "لم يُحلَّل أي قاعدة، تحقق من الصياغة.", - "noticeImportsRemoved": "قواعد @import المُزالة: {count}. كانت ستجلب أوراق أنماط بعيدة.", - "noticeRemoteUrl": "يحتوي على url() بعيد، وسيُصدر طلب شبكة عند التطبيق.", - "noticePreviewSuspended": "النمط المخصص موقوف، لذا لا تُطبَّق هذه المعاينة.", - "noticeDisabled": "CSS المخصص متوقف. يمكنك المعاينة هنا، لكن لن يسري شيء حتى تفعّله.", - "hintTokens": "تلميح: الألوان التي تجاوزتها متاحة عبر var(--primary) و var(--background) وغيرها." - } - }, - "zoomLevel": { - "sectionTitle": "تكبير النافذة", - "sectionDescription": "تكبير أو تصغير الواجهة بالكامل. يتم تطبيقه فوراً ويُحفظ لكل جهاز على حدة.", - "placeholder": "اختر مستوى التكبير", - "default": "افتراضي", - "current": "التكبير الحالي: {zoom}%" - }, - "fonts": { - "sectionTitle": "الخطوط", - "sectionDescription": "اختر خطوطًا للواجهة ومحرّر الأكواد والطرفية. تُحمّل الخطوط المضمّنة عند الحاجة؛ اختر «مخصّص…» لاستخدام أي خط مثبّت على نظامك.", - "interface": "الواجهة", - "editor": "المحرّر", - "terminal": "الطرفية", - "groupSans": "بلا زوائد", - "groupMono": "ثابت العرض", - "custom": "مخصّص…", - "customPlaceholder": "اسم الخط، مثل Fira Code", - "fontSize": "حجم الخط", - "ligatures": "تفعيل الحروف المتصلة", - "ligaturesUnavailable": "هذا الخط لا يحتوي على حروف متصلة", - "wordWrap": "تفعيل التفاف النص", - "terminalLigaturesHint": "تنطبق الحروف المتصلة في الطرفية على خطوط البرمجة المضمّنة فقط.", - "preview": "معاينة" - }, - "welcomePanel": { - "sectionTitle": "منطقة اختيار الوضع", - "sectionDescription": "بطاقات الاختصار «تطوير الكود / الأعمال المكتبية» التي تظهر أعلى مربع الإدخال في صفحة المحادثة الجديدة.", - "showQuickActions": "العرض في صفحة المحادثة الجديدة" - }, - "workspaceBackground": { - "sectionTitle": "خلفية مساحة العمل", - "sectionDescription": "عرض صورة خلف مساحة العمل بالكامل. يصبح الشريط الجانبي واللوحات شبه شفافة ومصنفرة لتظهر الصورة من خلالها، ويحافظ القناع على وضوح النص.", - "enable": "تفعيل صورة الخلفية", - "image": "الصورة", - "chooseImage": "اختيار صورة", - "replaceImage": "استبدال الصورة", - "removeImage": "إزالة", - "fillMode": "وضع الملء", - "fillModes": { - "cover": "تغطية", - "contain": "احتواء", - "center": "توسيط", - "tile": "تكرار" - }, - "maskOpacity": "عتامة القناع", - "maskOpacityHint": "القيم الأعلى تمزج الصورة نحو لون خلفية السمة، مما يحسّن تباين النص.", - "imageBlur": "تمويه الصورة", - "panelOpacity": "عتامة اللوحات", - "panelOpacityHint": "مدى عتامة الشريط الجانبي واللوحات وأشرطة التبويب. الأقل يُظهر المزيد من الصورة.", - "errorTooLarge": "الصورة كبيرة جدًا (16 ميجابايت كحد أقصى).", - "errorUploadFailed": "فشل تعيين صورة الخلفية." - } - }, - "SystemSettings": { - "loading": "جارٍ التحميل...", - "sectionTitle": "إدارة النظام", - "sectionDescription": "إدارة وكيل الشبكة وتحديثات التطبيق وتفضيلات اللغة.", - "proxyTitle": "وكيل الشبكة", - "proxyDescription": "عند التفعيل، ستُفضَّل إعدادات هذا الوكيل في طلبات الشبكة اللاحقة (بما في ذلك دردشة ACP وتثبيت الوكلاء وعمليات Git البعيدة).", - "loadFailed": "فشل التحميل: {message}", - "enableProxy": "تفعيل وكيل النظام", - "proxyAddress": "عنوان الوكيل", - "proxyHint": "يدعم http(s)/socks5، مثال: {example}. يعمل فقط عند تفعيل وكيل النظام.", - "save": "حفظ", - "saving": "جارٍ الحفظ...", - "proxyRequired": "عنوان URL للوكيل مطلوب عند تفعيل الوكيل", - "saveSuccess": "تم حفظ إعدادات وكيل النظام", - "saveFailed": "فشل الحفظ: {message}", - "languageTitle": "اللغة", - "languageDescription": "حدد لغة التطبيق. عند اتباع لغة النظام، ستعود اللغات غير المدعومة إلى الإنجليزية.", - "appLanguage": "لغة التطبيق", - "languageSaveSuccess": "تم حفظ إعدادات اللغة", - "languageSaveFailed": "فشل حفظ إعدادات اللغة: {message}", - "updateTitle": "تحديث التطبيق", - "versionTitle": "تحديث البرنامج", - "updateDescription": "تحقق من المصدر المهيأ للإصدارات الأحدث وثبّت التحديث مباشرة عند توفره.", - "currentVersion": "الإصدار الحالي", - "upgradableVersion": "أحدث إصدار", - "none": "لا يوجد", - "lastChecked": "آخر فحص: {time}", - "updateError": "خطأ في التحديث: {message}", - "checking": "جارٍ التحقق...", - "checkUpdate": "التحقق من التحديثات", - "updating": "جارٍ التثبيت...", - "downloading": "جارٍ التنزيل...", - "upgradeTo": "الترقية إلى v{version}", - "viewRelease": "عرض إصدار v{version}", - "foundUpdate": "تم العثور على إصدار جديد v{version}", - "alreadyLatest": "أنت على أحدث إصدار", - "checkUpdateFailed": "فشل التحقق من التحديثات: {message}", - "installSuccess": "تم تثبيت التحديث. جارٍ إعادة تشغيل التطبيق.", - "installFailed": "فشل التحديث: {message}", - "upgradeSuccess": "اكتملت الترقية. جارٍ إعادة التحميل...", - "restartTimeout": "لم يعد الخادم في الوقت المناسب. تحقق من سجلات الحاوية أو الخدمة.", - "restartingIn": "إعادة التشغيل خلال {seconds} ثانية...", - "waitingForServer": "في انتظار عودة الخادم...", - "restartToUpdate": "أعد التشغيل للتحديث", - "newVersionBadge": "إصدار جديد v{version}", - "updateAvailableTitle": "يتوفر تحديث", - "releaseNotesTitle": "ما الجديد", - "remindLater": "لاحقًا", - "retry": "إعادة المحاولة", - "stepDownload": "التنزيل", - "stepInstall": "التثبيت", - "stepRestart": "إعادة التشغيل", - "updateReadyHint": "تم تنزيل التحديث — أعد التشغيل لتطبيقه.", - "restarting": "جارٍ إعادة التشغيل...", - "dockerUpgradeHint": "يؤدي هذا إلى ترقية الحاوية قيد التشغيل الآن. وتُفقد عند إعادة إنشاء الحاوية — وللاحتفاظ بها، اسحب أو ابنِ صورة بالإصدار الجديد ثم أعد إنشاء الحاوية.", - "upgradeRolledBack": "فشلت الترقية؛ عاد الخادم إلى الإصدار السابق.", - "serverUnreachable": "تعذّر الوصول إلى الخادم لبدء الترقية. تأكد من أنه قيد التشغيل وحاول مرة أخرى.", - "rollbackButton": "التراجع", - "rollingBack": "جارٍ التراجع...", - "rollbackDescription": "استعادة الإصدار المثبَّت قبل آخر ترقية.", - "rollbackConfirmTitle": "التراجع إلى الإصدار السابق؟", - "rollbackConfirmDescription": "ستعيد الخادم التشغيل على الإصدار المثبَّت قبل آخر ترقية. ويبقى الإصدار الأحدث متاحًا لإعادة التثبيت.", - "rollbackConfirm": "التراجع", - "rollbackCancel": "إلغاء", - "rollbackSuccess": "تم التراجع إلى الإصدار السابق. جارٍ إعادة التحميل...", - "rollbackFailed": "فشل التراجع. تحقّق من سجلات الخادم.", - "updateErrors": { - "sourceUnavailable": "تعذر الوصول إلى مصدر التحديث. تحقق من الشبكة أو الوكيل ثم أعد المحاولة.", - "network": "فشل اتصال الشبكة. تحقق من الشبكة أو الوكيل ثم أعد المحاولة.", - "downloadFailed": "فشل تنزيل حزمة التحديث. يرجى المحاولة مرة أخرى لاحقًا.", - "installFailed": "فشل تثبيت التحديث. يرجى إغلاق التطبيق ثم إعادة المحاولة.", - "unknown": "فشل التحديث. يرجى المحاولة مرة أخرى لاحقًا." - } - }, - "VersionControlSettings": { - "loading": "جارٍ التحميل...", - "sectionTitle": "التحكم بالإصدارات", - "sectionDescription": "تكوين ملف Git التنفيذي وإدارة حسابات GitHub.", - "gitTitle": "إعدادات Git", - "gitDescription": "تكوين ملف Git التنفيذي المستخدم بواسطة التطبيق.", - "gitDetected": "تم اكتشاف Git", - "gitNotFound": "لم يتم العثور على Git في النظام", - "gitVersion": "الإصدار", - "gitPath": "المسار", - "customGitPath": "مسار Git مخصص", - "customGitPathPlaceholder": "/usr/bin/git", - "customGitPathHint": "اتركه فارغًا لاستخدام المسار المكتشف تلقائيًا.", - "test": "اختبار", - "testing": "جارٍ الاختبار...", - "testSuccess": "ملف Git التنفيذي صالح.", - "testFailed": "فشل اختبار Git: {message}", - "save": "حفظ", - "saving": "جارٍ الحفظ...", - "saveSuccess": "تم حفظ إعدادات Git.", - "saveFailed": "فشل الحفظ: {message}", - "githubTitle": "حسابات GitHub", - "githubDescription": "إدارة حسابات GitHub للمصادقة. يتم تخزين الرموز محليًا.", - "noAccounts": "لا توجد حسابات GitHub مكوّنة.", - "addAccount": "إضافة حساب", - "serverUrl": "عنوان الخادم", - "serverUrlPlaceholder": "https://github.com", - "token": "رمز الوصول الشخصي", - "tokenPlaceholder": "ghp_xxxxxxxxxxxx", - "generateToken": "إنشاء رمز", - "tokenHint": "أنشئ رمزًا في GitHub → Settings → Developer settings → Personal access tokens.", - "validateAndAdd": "التحقق والإضافة", - "validating": "جارٍ التحقق...", - "addSuccess": "تمت إضافة الحساب {username} بنجاح.", - "addFailed": "فشل إضافة الحساب: {message}", - "testConnection": "اختبار", - "connectionSuccess": "نجح الاتصال.", - "connectionFailed": "فشل الاتصال: {message}", - "setDefault": "تعيين كافتراضي", - "defaultLabel": "افتراضي", - "defaultSet": "تم تحديث الحساب الافتراضي.", - "removeAccount": "إزالة", - "removeConfirmTitle": "إزالة الحساب", - "removeConfirmMessage": "هل أنت متأكد من إزالة الحساب \"{username}\"؟", - "removeConfirm": "إزالة", - "removeCancel": "إلغاء", - "removeSuccess": "تمت إزالة الحساب.", - "scopes": "النطاقات", - "loadFailed": "فشل تحميل الإعدادات: {message}", - "gitAccount": { - "sectionTitle": "حسابات خادم Git", - "sectionDescription": "إدارة بيانات الاعتماد لخوادم Git غير GitHub (GitLab، Bitbucket، الخوادم الذاتية، إلخ).", - "noAccounts": "لا توجد حسابات خادم Git مكوّنة.", - "addAccount": "إضافة حساب", - "addTitle": "إضافة حساب Git", - "addDescription": "أدخل عنوان الخادم واسم المستخدم وكلمة المرور أو رمز الوصول.", - "serverUrl": "عنوان الخادم", - "serverUrlPlaceholder": "https://gitlab.example.com", - "username": "اسم المستخدم", - "usernamePlaceholder": "اسم المستخدم أو البريد الإلكتروني", - "password": "كلمة المرور / الرمز", - "passwordPlaceholder": "كلمة المرور أو رمز الوصول", - "passwordHint": "أدخل كلمة مرور الخادم أو رمز الوصول.", - "add": "إضافة", - "serverRequired": "عنوان الخادم مطلوب.", - "usernameRequired": "اسم المستخدم مطلوب.", - "passwordRequired": "كلمة المرور مطلوبة." - } - }, - "ShortcutSettings": { - "sectionTitle": "الاختصارات", - "resetDefault": "استعادة الإعدادات الافتراضية", - "recordInstruction": "انقر الزر في الجهة اليمنى ثم اضغط تركيبة مفاتيح. استخدم Ctrl/Cmd وAlt وShift. اضغط Esc لإلغاء التسجيل.", - "recording": "اضغط اختصارًا...", - "toasts": { - "conflict": "الاختصار مستخدم بالفعل بواسطة \"{title}\"", - "updated": "تم تحديث الاختصار", - "invalid": "اختصار غير صالح، يرجى المحاولة مرة أخرى", - "reset": "تمت استعادة الاختصارات الافتراضية" - }, - "actions": { - "toggle_search": { - "title": "فتح البحث", - "description": "إظهار أو إخفاء لوحة البحث في المحادثات" - }, - "toggle_sidebar": { - "title": "تبديل الشريط الجانبي الأيسر", - "description": "إظهار أو إخفاء الشريط الجانبي لقائمة المحادثات" - }, - "toggle_terminal": { - "title": "تبديل الطرفية", - "description": "إظهار أو إخفاء لوحة الطرفية السفلية" - }, - "new_terminal_tab": { - "title": "طرفية جديدة", - "description": "إنشاء تبويب طرفية جديد عندما يكون التركيز على الطرفية" - }, - "close_current_terminal_tab": { - "title": "إغلاق الطرفية الحالية", - "description": "إغلاق تبويب الطرفية الحالي عندما يكون التركيز على الطرفية" - }, - "toggle_aux_panel": { - "title": "تبديل اللوحة اليمنى", - "description": "إظهار أو إخفاء لوحة المعلومات المساعدة" - }, - "new_conversation": { - "title": "محادثة جديدة", - "description": "إنشاء تبويب محادثة جديد في المجلد الحالي" - }, - "open_folder": { - "title": "فتح مجلد", - "description": "فتح منتقي المجلدات وفتح المجلد في نافذة جديدة" - }, - "open_settings": { - "title": "فتح الإعدادات", - "description": "فتح نافذة الإعدادات" - }, - "close_current_tab": { - "title": "إغلاق التبويب الحالي", - "description": "إغلاق المحادثة الحالية أو تبويب الملف الحالي" - }, - "close_all_file_tabs": { - "title": "إغلاق جميع تبويبات الملفات", - "description": "إغلاق جميع تبويبات الملفات المفتوحة عندما تكون لوحة الملفات نشطة" - }, - "next_tab": { - "title": "علامة التبويب التالية", - "description": "التبديل إلى علامة تبويب المحادثة أو الملف التالية" - }, - "prev_tab": { - "title": "علامة التبويب السابقة", - "description": "التبديل إلى علامة تبويب المحادثة أو الملف السابقة" - }, - "send_message": { - "title": "إرسال الرسالة", - "description": "إرسال الرسالة الحالية في مربع الإدخال" - }, - "newline_in_message": { - "title": "سطر جديد في الرسالة", - "description": "إدراج سطر جديد في مربع الإدخال" - }, - "toggle_custom_style": { - "title": "إيقاف/استئناف النمط المخصص", - "description": "مخرج طوارئ: يوقف كل الألوان المخصصة وCSS، ويعيد تفعيلها" - } - } - }, - "SkillsSettings": { - "title": "Skills", - "description": "اختر Skill من الجهة اليسرى. تعرض الجهة اليمنى معاينة Markdown بشكل افتراضي؛ انتقل إلى وضع التحرير للتعديل والحفظ.", - "loadingAgents": "جارٍ تحميل الوكلاء الذين يدعمون Skills...", - "emptyNoManageableAgents": "لا توجد وكلاء متاحة لإدارة Skills.", - "managedTarget": "الهدف المُدار", - "selectAgentPlaceholder": "اختر وكيلًا", - "searchPlaceholder": "ابحث بالاسم / المعرّف / المسار...", - "skillsList": "قائمة Skills", - "loadingSkills": "جارٍ تحميل Skills...", - "agentNotSupported": "الوكيل الحالي لا يدعم إدارة Skills.", - "emptySkills": "لا توجد Skills بعد. انقر \"Skill جديدة\" لإنشاء واحدة.", - "newSkillTitle": "Skill جديدة", - "skillInfo": "معلومات Skill", - "skillIdPlaceholder": "skill-id (حروف/أرقام/-/_/.)", - "skillsDirectoryWithPath": "دليل Skills: {path}", - "skillsDirectoryNeedId": "دليل Skills: أدخل معرّف Skill لإنشاء المسار الكامل", - "markdownContent": "محتوى Markdown", - "editingStatus": "جارٍ التحرير", - "previewStatus": "معاينة", - "contentPlaceholder": "أدخل محتوى Markdown للSkill...", - "metadataTitle": "بيانات Skills الوصفية", - "onlyYamlMetadata": "تحتوي هذه Skill على بيانات YAML الوصفية فقط.", - "emptyContentHint": "لا يوجد محتوى بعد. انقر \"تحرير\" للبدء.", - "loadingSkill": "جارٍ تحميل Skill...", - "emptyNoAgents": "لا يوجد وكيل متاح.", - "noSelectionHint": "اختر Skill من اليسار، أو انقر على \"Skill جديد\" لإنشاء واحد.", - "systemBadge": "نظام", - "systemHint": "Skill مدمج في CLI · للقراءة فقط", - "scope": { - "global": "عام", - "folder": "مجلد", - "selectFolderPlaceholder": "اختر مجلدًا", - "noFolders": "لم يتم العثور على مجلدات", - "pickFolderHint": "اختر مجلدًا لعرض مهاراته." - }, - "actions": { - "preview": "معاينة", - "edit": "تحرير", - "openInWindow": "فتح في نافذة جديدة", - "delete": "حذف", - "deleting": "جارٍ الحذف...", - "refresh": "تحديث", - "newSkill": "Skill جديدة", - "reset": "إعادة تعيين", - "save": "حفظ", - "saving": "جارٍ الحفظ...", - "cancel": "إلغاء" - }, - "deleteDialog": { - "title": "حذف Skill", - "confirm": "هل تريد حذف Skill الحالية؟ لا يمكن التراجع عن هذا الإجراء.", - "confirmWithNamePrefix": "حذف Skill", - "confirmWithNameSuffix": "؟ لا يمكن التراجع عن هذا الإجراء." - }, - "toasts": { - "loadFailed": "فشل تحميل Skill", - "openFolderFailed": "فشل فتح المجلد", - "noSkillDirectory": "لم يتم العثور على دليل Skills متاح للوكيل الحالي", - "nameRequired": "لا يمكن أن يكون اسم Skill فارغًا", - "updated": "تم تحديث Skill", - "created": "تم إنشاء Skill", - "saveFailed": "فشل حفظ Skill", - "deleted": "تم حذف Skill", - "deleteFailed": "فشل حذف Skill" - }, - "templates": { - "gemini": "---\nname: example-skill\ndescription: Describe when this skill should be used.\n---\n\n# Skill Name\n\nInstructions for the agent when this skill is active.\n\n## Workflow\n\n1. Add actionable step one.\n2. Add actionable step two.\n", - "openCode": "---\nname: example-skill\ndescription: Describe when this skill should be used.\n---\n\n# Purpose\n\nDescribe what this skill helps with.\n\n# Steps\n\n1. Add actionable step one.\n2. Add actionable step two.\n", - "openClaw": "---\nname: example-skill\ndescription: Describe when this skill should be used.\nuser-invocable: true\ndisable-model-invocation: false\n---\n\n# Purpose\n\nDescribe what this skill helps with.\n\n# Instructions\n\n1. Add actionable instruction one.\n2. Add actionable instruction two.\n", - "default": "---\nname: example-skill\ndescription: Describe when this skill should be used.\n---\n\n# Skill: example-skill\n\n## When to use\n\n- Describe trigger conditions.\n\n## Instructions\n\n1. Add actionable instruction one.\n2. Add actionable instruction two.\n" - } - }, - "McpSettings": { - "loading": "جارٍ التحميل...", - "summary": { - "missingCommand": "(لا يوجد أمر)", - "missingUrl": "(لا يوجد رابط)" - }, - "protocol": { - "stdio": "Stdio" - }, - "errors": { - "selectInstallProtocol": "يرجى اختيار بروتوكول التثبيت", - "fieldRequired": "{field} مطلوب", - "fieldNeedsBoolean": "{field} يجب أن يكون true أو false", - "fieldNeedsNumber": "{field} يجب أن يكون رقمًا", - "fieldNeedsInteger": "{field} يجب أن يكون عددًا صحيحًا", - "fieldInvalidJson": "{field} يحتوي JSON غير صالح: {message}", - "fieldOutOfRange": "قيمة {field} خارج النطاق المسموح", - "jsonEmpty": "{name} لا يمكن أن يكون فارغًا", - "jsonInvalid": "{name} ليس JSON صالحًا: {message}", - "jsonMustBeObject": "{name} يجب أن يكون كائن JSON", - "specMustBeObject": "يجب أن يكون إعداد MCP كائن JSON.", - "missingType": "حقل type غير موجود في إعداد MCP. حدد أحد القيم: stdio أو http (الأسماء البديلة: streamable-http و streamableHttp) أو sse.", - "unsupportedType": "نوع MCP غير مدعوم {type}. المدعوم: stdio و http (الأسماء البديلة: streamable-http و streamableHttp) و sse.", - "codexEntryUnsupportedType": "إدخال Codex MCP {id} له نوع غير مدعوم {type}. المدعوم: stdio و http (الأسماء البديلة: streamable-http و streamableHttp) و sse.", - "unsupportedTransportType": "نوع transport غير مدعوم {type}. المدعوم: http (الأسماء البديلة: streamable-http و streamableHttp) و sse.", - "stdioCommandRequired": "يتطلب MCP من نوع stdio حقل command غير فارغ.", - "remoteUrlRequired": "تتطلب MCP البعيدة حقل url غير فارغ.", - "appsRequired": "حدد تطبيقاً مستهدفاً واحداً على الأقل." - }, - "jsonNames": { - "localConfig": "إعداد MCP", - "installConfig": "إعداد التثبيت" - }, - "toasts": { - "uninstalled": "تمت إزالة MCP", - "uninstallFailed": "فشل الإزالة: {message}", - "selectAtLeastOneApp": "يرجى اختيار تطبيق هدف واحد على الأقل", - "saveSuccess": "تم الحفظ", - "saveFailed": "فشل الحفظ: {message}", - "installed": "تم تثبيت {name}", - "installFailed": "فشل التثبيت: {message}", - "serverIdRequired": "معرّف الخادم مطلوب", - "serverIdExists": "معرّف الخادم \"{id}\" موجود بالفعل. عدّل العنصر الحالي أو اختر اسماً آخر.", - "created": "تم إنشاء MCP" - }, - "installDialog": { - "title": "تأكيد تثبيت MCP", - "descriptionWithName": "تثبيت {name} في الإعداد المحلي.", - "description": "اختر التطبيقات المستهدفة للتثبيت.", - "protocol": "البروتوكول", - "selectProtocol": "اختر البروتوكول", - "parameters": "معلمات الإعداد", - "booleanPlaceholder": "يرجى اختيار true/false", - "selectOneValue": "اختر قيمة", - "targetApps": "التطبيقات المستهدفة" - }, - "actions": { - "cancel": "إلغاء", - "confirmInstall": "تأكيد التثبيت", - "installing": "جارٍ التثبيت", - "uninstall": "إزالة التثبيت", - "uninstalling": "جارٍ الإزالة", - "viewDetails": "عرض التفاصيل", - "save": "حفظ", - "saving": "جارٍ الحفظ", - "install": "تثبيت", - "refresh": "تحديث", - "newMcp": "MCP جديد", - "create": "إنشاء", - "creating": "جارٍ الإنشاء..." - }, - "tabs": { - "local": "MCP المحلي", - "market": "سوق MCP" - }, - "local": { - "filterPlaceholder": "تصفية MCP المحلي...", - "loadFailed": "فشل التحميل: {message}", - "empty": "لم يتم اكتشاف MCP محلي.", - "description": "يمكن تعديل إعداد MCP المحلي وحفظه مباشرة.", - "enabledApps": "التطبيقات المفعلة", - "configJson": "إعداد MCP (JSON)", - "draftTitle": "MCP جديد", - "draftDescription": "أدخل معرّف الخادم والإعدادات لإنشاء خادم MCP محلي.", - "serverIdLabel": "معرّف الخادم", - "serverIdPlaceholder": "معرّف الخادم (مثل: my-mcp)", - "typeHint": "الأنواع المدعومة: stdio و http (الأسماء البديلة: streamable-http و streamableHttp) و sse. يُستخدم env مع stdio فقط؛ خوادم MCP البعيدة تحمل رموز المصادقة عبر headers.", - "envOnRemoteWarning": "تم اكتشاف env على MCP بعيد. يُستخدم env مع stdio فقط؛ خوادم MCP البعيدة تحمل رموز المصادقة عبر headers، لذا سيتم تجاهل env عند الحفظ." - }, - "market": { - "selectMarketplace": "اختر السوق", - "searchPlaceholder": "ابحث عن MCP...", - "searchFailed": "فشل البحث: {message}", - "loadingList": "جارٍ تحميل قائمة MCP...", - "empty": "لا توجد نتائج MCP.", - "loadingDetail": "جارٍ تحميل تفاصيل السوق...", - "detailLoadFailed": "فشل تحميل التفاصيل: {message}", - "owner": "المالك: {owner}", - "namespace": "المجال: {namespace}", - "defaultInstallProtocol": "بروتوكول التثبيت الافتراضي", - "currentOptionParameterCount": "عدد معلمات الخيار الحالي: {count}", - "installConfigDescription": "إعداد التثبيت (JSON، قابل للتعديل قبل التثبيت؛ ستتجاوز التعديلات نموذج البروتوكول/المعلمات)", - "selectLeftToView": "اختر MCP من السوق في الجهة اليسرى لعرض التفاصيل." - }, - "badges": { - "verified": "موثّق", - "remote": "بعيد", - "hasHomepage": "له صفحة رئيسية", - "uses": "{count} استخدام", - "deployed": "منشور", - "notDeployed": "غير منشور" - }, - "selectLeftMcp": "اختر MCP من الجهة اليسرى." - }, - "AcpAgentSettings": { - "title": "إدارة Agent SDK", - "description": "أدر اتصال Agent SDK وحالة التمكين ومتغيرات البيئة وإدارة الإعدادات ومعلومات فحص الإصدار المسبق في مكان واحد.", - "loadingAgents": "جارٍ تحميل قائمة الوكلاء...", - "agentList": "قائمة الوكلاء", - "emptyNoAgent": "لا يوجد وكيل متاح.", - "configManagement": "إدارة الإعدادات", - "envVars": "متغيرات البيئة", - "hostTools": { - "label": "دع الوكيل يتولى الملفات والأوامر بنفسه", - "description": "يتوقف codeg عن تنفيذ الوصول إلى الملفات وأوامر الطرفية، فينفّذها الوكيل داخل عمليته الخاصة — وعندها فقط تُطبَّق البيئة المعزولة وقواعد الأذونات الخاصة به. كما يُعطَّل التفويض إلى وكلاء آخرين، لأنه سيعيد العمل نفسه عبر codeg. لا يضيف codeg بيئة معزولة من عنده، لذا فعّل هذا الخيار فقط إذا كان الوكيل قد أُعِدّت له واحدة." - }, - "nativeJsonConfig": "إعداد JSON أصلي", - "modelHintDefault": "اتركه فارغًا لاستخدام النموذج الافتراضي للنظام.", - "generalConfigDescriptionClaude": "يدعم الإعداد السريع لـ API URL وAPI Key ونماذج Claude، ويتزامن مع إعداد JSON الأصلي.", - "generalConfigDescriptionDefault": "يدعم إدخال الإعدادات المهمة (API URL وAPI Key وModel) وإدارة إعداد JSON الأصلي.", - "multiAgent": { - "title": "تعاون متعدد الوكلاء", - "description": "اسمح للوكلاء النشطين بتفويض المهام الفرعية إلى وكلاء آخرين.", - "enable": "تفعيل التفويض", - "enableHint": "عند الإيقاف، يتم إخفاء أداة delegate_to_agent من قائمة أدوات MCP الخاصة بالوكيل.", - "withheldByHostTools": "لن تحصل {agents} على أدوات التفويض: مفتاح «دع الوكيل يتولى الملفات والأوامر» الخاص بها مُفعّل.", - "selfInitiate": "Allow spawn without @", - "selfInitiateHint": "When on, an agent may start a listed sub-agent on its own. An @ mention is still always honored. When off, only an @ mention starts a sub-agent.", - "depthLimit": "أقصى عمق للتفويض", - "depthHint": "النطاق المسموح: {min}–{max}. يحدّ من عمق سلسلة التفويض (جذر ← فرعي ← حفيد …).", - "completedCacheLabel": "ذاكرة التخزين المؤقت للنتائج المكتملة (MB)", - "completedCacheHint": "ذاكرة تخزين مؤقتة في الذاكرة لنتائج الوكلاء الفرعيين المكتملة، تُحفظ فقط أثناء تشغيل جلسة التفويض وتُحرَّر تلقائيًا عند انتهاء تلك الجلسة. وعند تجاوز هذه الميزانية، تُسقَط أقدم النتائج من الذاكرة أولًا (تظل قابلة للعرض في جلسة الوكيل الفرعي نفسه)؛ 0 = غير محدود (وتُحرَّر مع ذلك عند انتهاء الجلسة).", - "save": "حفظ", - "saving": "جارٍ الحفظ…", - "saved": "تم حفظ إعدادات التفويض", - "saveFailed": "فشل حفظ إعدادات التفويض", - "loadFailed": "فشل تحميل إعدادات التفويض: {detail}", - "tabGeneral": "عام", - "tabAgentDefaults": "إعدادات الوكيل الفرعي", - "agentDefaultsDescription": "تجاوزات لكل وكيل تُطبَّق عندما يقوم التعاون متعدد الوكلاء بتشغيل وكيل فرعي لاستدعاء تفويض. تأتي الخيارات المعروضة هنا من فحص حي، لذا فإن ما تختاره هو بالضبط ما سيقبله الوكيل.", - "probing": "جارٍ تحميل الخيارات المتاحة من الوكيل…", - "probeFailed": "فشل تحميل الخيارات: {detail}", - "retry": "إعادة المحاولة", - "noConfigAvailable": "لا يحتوي هذا الوكيل على خيارات قابلة للضبط.", - "modeLabel": "الوضع", - "agentDefaultHint": "افتراضي الوكيل: {value}", - "defaultOptionLabel": "افتراضي ({value})" - }, - "actions": { - "dragSort": "اسحب لإعادة الترتيب", - "dragSortAgent": "اسحب لإعادة ترتيب {name}", - "refreshCheck": "تحديث الفحص", - "refreshCheckAgent": "تحديث فحص {name}", - "clickEnable": "انقر لتفعيل {name}", - "clickDisable": "انقر لتعطيل {name}", - "install": "تثبيت", - "upgrade": "ترقية", - "uninstall": "إزالة التثبيت", - "uninstalling": "جارٍ إزالة التثبيت...", - "saveEnvVars": "حفظ متغيرات البيئة", - "saving": "جارٍ الحفظ...", - "saveGrokConfig": "حفظ إعدادات Grok", - "saveCodexConfig": "حفظ إعداد Codex", - "saveGeminiConfig": "حفظ إعداد Gemini", - "saveOpenCodeConfig": "حفظ إعداد OpenCode", - "saveOpenClawConfig": "حفظ إعداد OpenClaw", - "saveConfigManagement": "حفظ إدارة الإعدادات", - "saveCurrentProvider": "حفظ المزود الحالي", - "showApiKey": "إظهار مفتاح API", - "hideApiKey": "إخفاء مفتاح API", - "showKey": "إظهار المفتاح", - "hideKey": "إخفاء المفتاح", - "showToken": "إظهار الرمز", - "hideToken": "إخفاء الرمز", - "cancel": "إلغاء", - "delete": "حذف", - "deleting": "جارٍ الحذف...", - "confirmDelete": "تأكيد الحذف", - "confirmUninstall": "تأكيد إزالة التثبيت", - "saveClineConfig": "حفظ تكوين Cline", - "saveHermesConfig": "حفظ تكوين Hermes", - "saveCodeBuddyConfig": "حفظ إعدادات CodeBuddy", - "saveKimiCodeConfig": "حفظ إعدادات Kimi Code", - "customInstall": "تثبيت مخصص", - "saveKimiCodeRawConfig": "Save config.toml", - "saveDeepSeekConfig": "حفظ إعدادات DeepSeek", - "diagnose": "تشخيص" - }, - "status": { - "enabled": "مفعّل", - "disabled": "معطّل", - "unchecked": "غير مفحوص", - "agentEnabledAria": "{name} مفعّل", - "agentEnabledSwitch": "مفتاح تفعيل {name}" - }, - "preflight": { - "count": "عناصر الفحص المسبق: {count}", - "notRun": "لم يتم تشغيل الفحوصات بعد." - }, - "grok": { - "configDescription": "اضبط Grok هنا. عناصر التحكم أدناه — وضع الأذونات، وجهد الاستدلال، ونموذج مخصّص اختياري (نقطة نهاية خاصة)، والضغط — تُدمج في ~/.grok/config.toml مع الحفاظ على مفاتيحك وتعليقاتك الأخرى. يستخدم تسجيل الدخول XAI_API_KEY أو `grok login`. تبقى المفاتيح الأخرى قابلة للتحرير ضمن «متقدم».", - "permissionModeLabel": "وضع الأذونات", - "permissionDefault": "السؤال في كل مرة", - "permissionAcceptEdits": "الموافقة التلقائية على التعديلات", - "permissionAuto": "موافقة تلقائية ذكية", - "permissionAlwaysApprove": "الموافقة دائمًا", - "reasoningEffortLabel": "جهد الاستدلال", - "effortLow": "منخفض (أسرع)", - "effortMedium": "متوسط (متوازن)", - "effortHigh": "مرتفع", - "effortXhigh": "الأقصى", - "optionDefault": "استخدام الافتراضي", - "authTitle": "المصادقة", - "authMode": "طريقة المصادقة", - "authModeApiKey": "مفتاح XAI API", - "authModeApiKeyHint": "المصادقة باستخدام XAI_API_KEY من وحدة تحكم xAI — للتشغيل غير التفاعلي أو بدون واجهة. يُخزَّن في بيئة هذا الوكيل.", - "authModeCustom": "نقطة نهاية مخصّصة", - "authModeCustomHint": "استخدم نقطة نهاية خاصة بك (BYO): عرّف نموذجًا مخصّصًا في الأسفل مع عنوان URL أساسي ومفتاح API خاصين به. يصبح النموذج الافتراضي لـ Grok.", - "subscriptionHint": "سجّل الدخول باستخدام `grok login` (SuperGrok / X Premium+). لا يُخزَّن أي مفتاح API.", - "loginHint": "نفّذ هذا في الطرفية لتسجيل الدخول، ثم أعد فتح هذه الإعدادات:", - "commandCopied": "تم نسخ الأمر إلى الحافظة", - "copyCommand": "نسخ الأمر", - "authKeyConfigured": "XAI_API_KEY مُهيَّأ.", - "authKeyMissing": "لم يتم تعيين XAI_API_KEY.", - "advancedToggle": "متقدم (config.toml الخام)", - "configTomlNative": "config.toml (أصلي)", - "configTomlHint": "يُحفظ حرفيًا كملف ~/.grok/config.toml بالكامل. يُرفض TOML غير الصالح حتى لا يقتطع خطأ مطبعي ملفك أبدًا.", - "configTomlPlaceholder": "# مفاتيح غير عناصر التحكم أعلاه، مثل\n# [mcp_servers.*] و[cli] وقواعد [permission].", - "customModelTitle": "نموذج مخصّص (نقطة نهاية خاصة)", - "customModelHint": "وجِّه Grok إلى نقطة نهاية مخصّصة أو مستضافة ذاتيًا. يكتب codeg كتلة `[model.*]` لكل نموذج ويجعلها النموذج الافتراضي. اترك معرّف النموذج فارغًا لإزالته.", - "customModelIdLabel": "معرّف النموذج", - "customModelIdPlaceholder": "grok-4.5", - "customModelIdHint": "يُسجَّل ككتلة `[model.*]` ويُرسَل إلى الـ API كاسم للنموذج؛ ويُضبط أيضًا كـ `[models].default`.", - "customBaseUrlLabel": "عنوان URL الأساسي", - "customBaseUrlPlaceholder": "https://api.x.ai/v1 (الافتراضي)", - "customApiBackendLabel": "الواجهة الخلفية لـ API", - "backendResponses": "Responses", - "backendChatCompletions": "Chat Completions", - "backendMessages": "Messages (Anthropic)", - "customApiKeyLabel": "مفتاح API", - "customApiKeyHint": "يُخزَّن ضمن `[model.*].api_key`، مقصورًا على نقطة النهاية هذه.", - "customContextWindowLabel": "نافذة السياق (رموز)", - "customContextWindowHint": "اختياري. يحدّد توقيت الضغط التلقائي؛ اتركه فارغًا لاستخدام القيمة الافتراضية لنقطة النهاية.", - "autoCompactLabel": "عتبة الضغط التلقائي (%)", - "autoCompactHint": "يضغط المحادثة عندما يبلغ استخدام السياق هذه النسبة المئوية (الافتراضي في Grok هو 85). يُكتَب في `[session]`." - }, - "cursor": { - "configDescription": "اضبط Cursor هنا. اختر طريقة مصادقة — اشتراك رسمي (تسجيل دخول عبر المتصفح) أو مفتاح Cursor API للأجهزة بدون واجهة أو الخوادم — ثم اختر نموذجًا وحرّر قواعد أذونات CLI وبيئة الحماية. يكتبها codeg في ~/.cursor/cli-config.json، بالمشاركة مع أداة cursor-agent.", - "authTitle": "المصادقة", - "authChecking": "جارٍ التحقق…", - "authNotInstalled": "cursor-agent غير مثبّت", - "authLoggedIn": "تم تسجيل الدخول", - "authNotLoggedIn": "غير مسجّل الدخول", - "loginHint": "شغّل هذا الأمر في الطرفية لتسجيل الدخول إلى حساب Cursor (سيفتح المتصفح)، ثم اضغط تحديث:", - "apiKeyLabel": "مفتاح Cursor API", - "apiKeyPlaceholder": "المفتاح من cursor.com/dashboard", - "apiKeyHint": "CURSOR_API_KEY — مفتاح حساب من لوحة تحكم Cursor، بديل لتسجيل الدخول عبر المتصفح للأجهزة بدون واجهة أو الخوادم. ليس مفتاحًا خارجيًا أو من OpenAI.", - "modelTitle": "النموذج الافتراضي", - "loadModels": "جلب النماذج", - "modelsUnavailable": "قائمة النماذج غير متاحة", - "modelHint": "يُمرَّر إلى CLI عبر ‎--model عند بدء الجلسة. اتركه افتراضيًا ليختار Cursor بنفسه.", - "permissionsTitle": "الأذونات ووضع الحماية", - "permissionsDescription": "محرّر بصري لقواعد أذونات CLI‏ (cli-config.json). القواعد المسموحة تُنفَّذ دون تأكيد؛ والمرفوضة تُحظر دائمًا.", - "permissionModeLabel": "وضع الأذونات", - "permissionModeDefault": "السؤال قبل التنفيذ (افتراضي)", - "permissionModeForce": "تشغيل كل شيء (--force)", - "permissionModeHint": "يبدأ وضع Run Everything الجلسات بـ --force: يُسمح تلقائيًا بجميع استدعاءات الأدوات باستثناء قواعد الرفض دون طلب تأكيد (قد تقيّده سياسة المؤسسة بقواعد السماح فقط). يسري على الجلسات الجديدة.", - "optionDefault": "افتراضي (غير محدد)", - "sandboxLabel": "وضع الحماية", - "sandboxEnabled": "مفعّل", - "sandboxDisabled": "معطّل", - "allowRulesLabel": "قواعد السماح", - "denyRulesLabel": "قواعد الرفض", - "addRule": "إضافة قاعدة", - "rulesSyntaxHint": "صيغة القواعد: Shell(أمر)، Read(مسار/نمط)، Write(مسار/نمط)، WebFetch(نطاق)، Mcp(خادم:أداة) — قواعد الرفض لها الأولوية دائمًا.", - "saveConfig": "حفظ الإعدادات", - "advancedToggle": "متقدم: cli-config.json الخام", - "advancedHint": "ملف ‎~/.cursor/cli-config.json كاملًا. الحفظ هنا يكتب الملف كما هو؛ أما عناصر التحكم أعلاه فتُدمج فيه.", - "saveRawConfig": "حفظ الملف", - "authMode": "طريقة المصادقة", - "subscriptionHint": "سجّل الدخول بحساب Cursor واستخدم نماذج Cursor.", - "customApiKeyRequired": "مفتاح Cursor API مطلوب.", - "authModeApiKey": "مفتاح Cursor API (بدون واجهة/خادم)", - "authModeApiKeyHint": "المصادقة باستخدام مفتاح API لحساب Cursor من لوحة تحكم Cursor (للأجهزة بدون واجهة أو الخوادم). هذا مفتاح حساب Cursor وليس نقطة نهاية خارجية/OpenAI — إذ يتصل cursor-agent بخادم Cursor الخاص فقط. لاستخدام نقطة نهاية متوافقة مع codex/OpenAI، استخدم وكيل Codex بدلاً من ذلك.", - "modelPickerPlaceholder": "ابحث عن النماذج…", - "modelNoMatch": "لا يوجد نموذج مطابق", - "modelsNeedAuth": "سجّل الدخول لتحميل قائمة النماذج.", - "modelDefaultBadge": "افتراضي" - }, - "deepseek": { - "configManagement": "إعدادات DeepSeek Harness", - "configDescription": "نقطة النهاية والمفتاح متغيّرا بيئة يقرأهما deepseek-acp عند الإقلاع. أما النموذج ومستوى الاستدلال فمحدِّدان على مستوى الجلسة، ويُختاران من حقل الإدخال.", - "baseUrlLabel": "نقطة نهاية API", - "baseUrlHint": "اتركه فارغًا لاستخدام نقطة النهاية الرسمية. يسري على الجلسات التي تبدأ بعد الحفظ؛ أعد الاتصال بالجلسة الجارية كي تأخذ القيمة الجديدة.", - "baseUrlInvalid": "أدخل عنوان http(s) كاملًا وبدون سلسلة استعلام، مثل https://api.deepseek.com", - "apiKeyLabel": "مفتاح API", - "apiKeyHint": "يُمرَّر إلى الوكيل باسم DEEPSEEK_API_KEY. متغيّر البيئة له أسبقية على ملف بيانات الاعتماد، لذا اترك الحقل فارغًا إن كنت تسجّل الدخول من الطرفية." - }, - "codex": { - "configDescription": "يدعم الإعداد السريع لعنوان API ومفتاح API واسم النموذج وجهد الاستدلال، مع المزامنة مع `auth.json` / `config.toml`.", - "authMode": "طريقة المصادقة", - "chatgptSubscription": "اشتراك رسمي", - "chatgptSubscriptionHint": "تسجيل الدخول باشتراك ChatGPT الرسمي، لا حاجة لـ API Key", - "apiKeyHint": "الاتصال باستخدام API Key بخدمات OpenAI أو الخدمات المتوافقة", - "selectProvider": "اختر المزود", - "modelName": "اسم النموذج", - "selectReasoningEffort": "اختر Reasoning Effort", - "enableWebsocket": "تفعيل WebSocket", - "enableWebsocketAria": "تفعيل WebSocket لـ Codex Provider", - "enableSkills": "تفعيل Skills", - "enableSkillsAria": "تفعيل Skills لـ Codex", - "enableFast": "تفعيل Fast", - "enableFastAria": "تفعيل مستوى خدمة Fast لـ Codex", - "sandboxGroupTitle": "بيئة العزل والموافقات", - "sandboxGroupHint": "تُكتب في ~/.codex/config.toml العام، لذا تراها أيضًا جلسات codex CLI وبيئة التطوير. هذه قيم افتراضية للمحادثة: تحكم الأدوار التي يبدأها codex بنفسه (‏/goal و‏/review و‏/compact). أما الرسائل العادية فتستخدم إعداد الموافقة المحدد في صندوق الإدخال. أعد تشغيل الجلسة لتطبيق التغييرات.", - "sandboxShadowedWarning": "يضبط config.toml المفتاح default_permissions، لذا يحسم codex الأذونات عبر ذلك الملف الشخصي ويتجاهل sandbox_mode تمامًا. احذف default_permissions لاستخدام عناصر التحكم أدناه.", - "sandboxPermissionsTableWarning": "يعرّف config.toml ملفات [permissions] دون default_permissions، وهو ما يمنع codex من العمل. اضبطه في المحرر الخام أدناه.", - "approvalPolicyLabel": "سياسة الموافقة", - "approvalPolicyUnset": "غير محددة (افتراضي codex: عند الطلب)", - "approvalPolicy_on-request": "عند الطلب — النموذج يقرر متى يسأل", - "approvalPolicy_untrusted": "غير موثوق — تُنفَّذ تلقائيًا أوامر القراءة الآمنة المعروفة فقط", - "approvalPolicy_never": "أبدًا — بدون أي طلبات موافقة", - "approvalPolicy_granular": "تفصيلي — اختر حسب نوع الطلب", - "approvalPolicyUntrustedAcpWarning": "لا يوجد مكافئ لـ untrusted بين إعدادات الموافقة الثلاثة في محوّل ACP، لذا تعود جلسات codeg إلى «عند الطلب»: يقرّر النموذج حينها متى يسأل، وتتوقف الأوامر التي تسمح بها البيئة المعزولة أصلاً عن طلب التأكيد. قيّد وضع العزل أدناه بدلاً من ذلك.", - "granularHint": "الإيقاف يعني رفض هذا النوع من الطلبات تلقائيًا بدلًا من عرضه عليك.", - "granular_sandbox_approval": "تصعيد صلاحيات أوامر الصدفة", - "granular_rules": "مطالبات قواعد execpolicy", - "granular_skill_approval": "مطالبات تنفيذ نصوص المهارات", - "granular_request_permissions": "مطالبات أداة request_permissions", - "granular_mcp_elicitations": "مطالبات elicitation في MCP", - "sandboxModeLabel": "وضع بيئة العزل", - "sandboxModeUnset": "غير محدد (المجلدات الموثوقة تعود إلى الكتابة في مساحة العمل)", - "sandboxMode_read-only": "قراءة فقط", - "sandboxMode_workspace-write": "الكتابة في مساحة العمل", - "sandboxMode_danger-full-access": "وصول كامل (بدون عزل)", - "sandboxModeHint": "على Windows، تُخفَّض الكتابة في مساحة العمل إلى قراءة فقط ما لم تُفعَّل بيئة العزل التجريبية الخاصة بـ codex.", - "sandboxModeSeedsPresetHint": "يستخدم codeg هذا أيضاً لتحديد إعداد الموافقة الأولي للجلسة، لذا فإنه — بخلاف سياسة الموافقة — يؤثر على الطلبات العادية. ويظل الإعداد المختار في مربع الإدخال هو الأسبق.", - "writableRootsLabel": "مجلدات إضافية قابلة للكتابة", - "writableRootsHint": "مسار مطلق واحد في كل سطر، إضافةً إلى مجلد العمل.", - "sandboxRootsRelativeError": "يجب أن يكون مسارًا مطلقًا — يحسم codex المسارات النسبية داخل ~/.codex: {path}", - "networkAccessLabel": "السماح بالوصول إلى الشبكة", - "excludeTmpdirLabel": "استبعاد TMPDIR من الجذور القابلة للكتابة", - "excludeSlashTmpLabel": "استبعاد /tmp من الجذور القابلة للكتابة", - "authJsonNative": "auth.json (أصلي)", - "configTomlNative": "config.toml (أصلي)", - "loginButton": "تسجيل الدخول باستخدام ChatGPT", - "loginRequesting": "جارٍ طلب رمز تسجيل الدخول...", - "loginStep1": "افتح الرابط التالي في متصفحك:", - "loginStep2": "أدخل الرمز أدناه:", - "loginPolling": "في انتظار التفويض...", - "loginCancel": "إلغاء", - "loginSuccess": "تم تسجيل الدخول بنجاح، تم حفظ الإعدادات!", - "loginFailed": "فشل تسجيل الدخول: {message}", - "loginRetry": "إعادة المحاولة", - "loginCodeCopied": "تم نسخ الرمز", - "loggedIn": "تم تسجيل الدخول", - "loginRelogin": "إعادة تسجيل الدخول / تبديل الحساب", - "loginTimeout": "انتهت مهلة تسجيل الدخول، يرجى المحاولة مرة أخرى", - "loginSaveFailed": "تم تسجيل الدخول بنجاح ولكن فشل حفظ الإعدادات" - }, - "gemini": { - "authConfig": "إعداد مصادقة Gemini", - "authConfigDescription": "متوافق مع وثائق مصادقة Gemini CLI، ويدعم endpoint مخصص وتسجيل دخول Google وGemini API Key وVertex AI ‏(ADC / حساب خدمة / API Key).", - "authMode": "وضع المصادقة", - "selectAuthMode": "اختر وضع المصادقة", - "viewAuthDoc": "عرض وثائق المصادقة", - "mode": { - "custom": "Endpoint مخصص", - "loginGoogle": "تسجيل دخول Google (OAuth)", - "vertexServiceAccount": "Vertex AI (حساب خدمة)" - }, - "hint": { - "custom": "أدخل API URL وAPI Key وModel؛ وسيتم ربطها بـ GOOGLE_GEMINI_BASE_URL / GEMINI_API_KEY / GEMINI_MODEL.", - "loginGoogle": "شغّل gemini في الطرفية وأكمل تسجيل دخول Google أولًا؛ لا حاجة إلى API key.", - "geminiApiKey": "أدخل GEMINI_API_KEY عند استخدام Gemini API.", - "vertexAdc": "استخدم gcloud ADC؛ ويوصى بتعيين GOOGLE_CLOUD_PROJECT وGOOGLE_CLOUD_LOCATION.", - "vertexServiceAccount": "عيّن مسار JSON لحساب الخدمة في GOOGLE_APPLICATION_CREDENTIALS.", - "vertexApiKey": "أدخل GOOGLE_API_KEY عند استخدام مفتاح Vertex AI API." - } - }, - "openCode": { - "configManagement": "إدارة إعداد OpenCode", - "configDescription": "متوافق مع مخطط `provider` في OpenCode، ويدعم إدارة متعددة المزودات ومزامنة ثنائية الاتجاه مع ملفات JSON الأصلية.", - "providerManagement": "إدارة المزودات", - "providerCount": "{count} مزودات", - "addProvider": "إضافة مزود", - "emptyProvider": "لا توجد مزودات مخصصة بعد. انقر على «إضافة مزود مخصص» لإنشاء واحد.", - "providerEnabledState": "حالة تفعيل {providerId}", - "selectProviderNpm": "اختر provider.npm", - "modelManagement": "إدارة النماذج", - "modelCount": "{count} نماذج", - "modelDescription": "متوافق مع `provider.models` في OpenCode. الإدارة السريعة تدعم حاليًا `name` / `id`؛ بينما تُحفظ الحقول المتقدمة الأخرى ويمكن تعديلها في JSON الأصلي أدناه.", - "addModel": "إضافة نموذج", - "emptyModel": "لا يوجد نموذج بعد. أدخل model id ثم انقر \"إضافة نموذج\".", - "modelId": "معرّف النموذج", - "modelName": "اسم النموذج", - "deleteModel": "حذف النموذج {modelId}", - "nativeJsonConfig": "إعداد JSON الأصلي لـ OpenCode", - "mainModel": "النموذج الرئيسي", - "smallModel": "النموذج الصغير", - "noMatchingModels": "لا توجد نماذج مطابقة", - "connectProvider": "ربط مزود", - "connectedProviders": "المزودون المتصلون", - "noConnectedProviders": "لم يتم ربط أي مزود من الكتالوج بعد.", - "advancedProviderConfig": "المزودات المخصصة", - "customProviderConfigHint": "نقاط نهاية متوافقة مع OpenAI تحددها بنفسك — كتلة provider في opencode.json، مع مفتاح API في auth.json.", - "addCustomProvider": "إضافة مزود مخصص", - "disconnect": "قطع الاتصال", - "editConfig": "تحرير", - "customBadge": "مخصص", - "authKindApi": "مفتاح API", - "authKindOauth": "OAuth", - "authKindNone": "لا توجد بيانات اعتماد", - "connect": { - "title": "ربط مزود", - "description": "اختر مزودًا من كتالوج models.dev. تُحفظ بيانات الاعتماد في ملف auth.json الخاص بـ OpenCode.", - "pick": "المزود", - "search": "البحث عن المزودين…", - "loading": "جارٍ تحميل الكتالوج…", - "catalogLabel": "كتالوج models.dev", - "modelsAvailable": "{count} نموذجًا متاحًا", - "getKey": "الحصول على مفتاح API", - "oauthApiKeyNote": "يدعم هذا المزود أيضًا تسجيل الدخول عبر المتصفح باستخدام opencode auth login. سيتوفر تسجيل الدخول عبر المتصفح قريبًا — في الوقت الحالي، الصق مفتاح API.", - "apiKey": "مفتاح API", - "apiKeyHint": "تُحفظ في auth.json وليس في opencode.json أبدًا.", - "baseUrlOptional": "تجاوز عنوان URL الأساسي (اختياري)", - "providerId": "معرّف المزود", - "displayName": "الاسم المعروض", - "modelsList": "النماذج (واحد في كل سطر)", - "modelsHint": "معرّفات النماذج التي تقبلها نقطة النهاية.", - "action": "ربط", - "editTitle": "تعديل المزود", - "editDescription": "حدّث مفتاح API أو عنوان URL الأساسي لهذا المزود.", - "saveAction": "حفظ" - }, - "customProvider": { - "title": "إضافة مزود مخصص", - "description": "حدّد نقطة نهاية متوافقة مع OpenAI. يُحفظ مفتاح API في auth.json، وتُكتب كتلة provider في opencode.json.", - "action": "إضافة المزود", - "idInCatalog": "{providerId} مزود معروف — قم بربطه عبر «ربط مزود» بدلاً من ذلك." - }, - "refreshCatalog": "تحديث الكتالوج", - "reasoningBadge": "استدلال", - "contextWindow": "نافذة السياق", - "permissions": { - "title": "الأذونات", - "description": "حدِّد أي الإجراءات تعمل تلقائيًا، وأيها يطلب موافقتك، وأيها يُحظر. يُكتب في مقطع permission داخل opencode.json ويُطبَّق عند الحفظ أدناه.", - "docsLink": "توثيق الأذونات", - "unparsableConfig": "تعذّر تحليل JSON الأصلي أدناه، لذا أُوقف المحرِّر المرئي مؤقتًا. صحّح JSON للمتابعة.", - "invalidBlock": "بنية مقطع permission غير معروفة لدى codeg. عدِّلها في JSON الأصلي أدناه أو استخدم إعادة الضبط للبدء من جديد.", - "orderingUnsafe": "كُتبت قاعدة عامة بعد أدوات محددة، لذا يطبّقها OpenCode عليها أيضًا — الصفوف أدناه ليست ما هو نافذ فعلًا. «تصحيح الترتيب» يعيد كل قاعدة عامة إلى بداية نطاقها فقط، دون تغيير أي قيمة.", - "orderingUnsafeManual": "قاعدة محجوبة بنمط أعمّ مكتوب بعدها، لذا لا يطبّقها OpenCode أبدًا — الصفوف أدناه ليست ما هو نافذ فعلًا. لا يوجد ترتيب صحيح وحيد لنمطين متداخلين؛ أعد ترتيبهما في JSON الأصلي بحيث يأتي الأعمّ أولًا.", - "fixOrder": "تصحيح الترتيب", - "agentOverrides": "هذه الوكلاء تتجاوز الأذونات وتُطبَّق أخيرًا، لذا تتغلب على كل ما هنا: {agents}. عدّلها في JSON الأصلي أدناه، أو فعّل القبول التلقائي لمسحها.", - "legacyTools": "خريطة tools القديمة في المستوى الأعلى ترفض إحدى الأدوات. يدمجها OpenCode ضمن الأذونات، لذا تُطبَّق فوق كل ما يظهر هنا. عدّلها في JSON الأصلي أدناه، أو فعّل القبول التلقائي لمسحها.", - "autoAcceptTitle": "قبول جميع الأذونات تلقائيًا", - "autoAcceptHint": "تُنفَّذ كل استدعاءات الأدوات — أوامر الصدفة وتعديلات الملفات والمسارات خارج المشروع — دون سؤال. تفعيله يستبدل إعدادات كل أداة أدناه بقاعدة واحدة تسمح بكل شيء، ويمسح تجاوزات كل وكيل ومفاتيح tools القديمة التي كانت ستستمر في الحجب.", - "globalLabel": "الإعداد العام الافتراضي", - "globalHint": "قاعدة *: تنطبق على كل ما لا تتجاوزه الأدوات أدناه.", - "actionUnset": "غير محدد (افتراضيات OpenCode)", - "actionInherit": "اتباع الافتراضي ({action})", - "actionAllow": "سماح", - "actionAsk": "سؤال", - "actionDeny": "رفض", - "perToolTitle": "أذونات كل أداة", - "reset": "إعادة الضبط", - "ruleCount": "القواعد: {count}", - "rulesToggle": "القواعد التفصيلية للأداة {tool}", - "rulesHint": "تُطابَق مع مدخلات الأداة، وتفوز آخر مطابقة، لذا ضع الأنماط الواسعة أولًا. الرمز * يطابق أي عدد من المحارف، و? يطابق محرفًا واحدًا بالضبط، و~ في البداية يتوسّع إلى مجلد المنزل.", - "noRules": "لا توجد قواعد تفصيلية بعد.", - "addRule": "إضافة قاعدة", - "deleteRule": "حذف القاعدة {pattern}", - "duplicateRule": "هذا النمط موجود بالفعل.", - "blankRule": "القاعدة تحتاج إلى نمط — استخدم أيقونة سلة المهملات لحذفها.", - "customKeys": "مفاتيح أذونات أخرى في الملف", - "customKeyHint": "ليست أداة مدمجة في OpenCode — تُحفظ كما هي.", - "keys": { - "bash": "تشغيل أوامر الصدفة، بمطابقة الأمر بعد تحليله", - "edit": "كل تعديلات الملفات: edit وwrite وpatch", - "read": "قراءة الملفات، بمطابقة المسار", - "external_directory": "الوصول إلى مسارات خارج مجلد عمل المشروع", - "task": "تشغيل الوكلاء الفرعيين، بمطابقة نوع الوكيل الفرعي", - "skill": "تحميل المهارات، بمطابقة اسم المهارة", - "glob": "العثور على الملفات، بمطابقة نمط glob", - "grep": "البحث في محتوى الملفات، بمطابقة النمط", - "list": "سرد محتويات المجلد", - "webfetch": "جلب عنوان URL", - "websearch": "البحث في الويب", - "lsp": "تشغيل استعلامات LSP", - "todowrite": "كتابة قائمة المهام", - "question": "طرح سؤال عليك", - "doom_loop": "يُفعَّل عند تكرار الاستدعاء نفسه ثلاث مرات بالمدخلات نفسها" - } - } - }, - "openClaw": { - "gatewayConfig": "إعداد Gateway", - "gatewayDescription": "قم بإعداد اتصال OpenClaw Gateway. يدعم gateway محليًا أو بعيدًا.", - "gatewayUrlHint": "اتركه فارغًا لاستخدام gateway.remote.url من إعداد openclaw المحلي.", - "gatewayTokenPlaceholder": "رمز مصادقة Gateway", - "gatewayTokenHint": "يُفضّل استخدام token-file بدل الرمز النصي متى أمكن؛ قم بالإعداد عبر openclaw CLI.", - "sessionKeyHint": "اختياري. حدّد مفتاح جلسة gateway؛ واتركه فارغًا للتعيين التلقائي لجلسة معزولة." - }, - "hermes": { - "configManagement": "تكوين Hermes", - "configDescription": "يدير Hermes بيانات اعتماده الخاصة في ~/.hermes/.env والإعدادات في ~/.hermes/config.yaml. اختر مزوّدًا، ثم عيّن مفتاح API والنموذج — وسيكتب codeg كلا الملفين نيابةً عنك.", - "providerLabel": "المزوّد", - "providerHint": "يحدّد المزوّد متغيّر مفتاح API و model.provider الذي يستخدمه Hermes. تُهيَّأ مزوّدات OAuth عبر إعداد الطرفية أدناه.", - "groupApiKey": "مزودو مفاتيح API", - "groupOauth": "مزودو OAuth", - "groupAws": "AWS", - "apiKeyHint": "يُحفظ في ~/.hermes/.env. ولا يُحقَن أبدًا في العملية — إذ يقرؤه Hermes من تكوينه الخاص.", - "modelName": "النموذج", - "oauthHint": "يستخدم هذا المزوّد OAuth. شغّل الإعداد أدناه للمصادقة في طرفيتك.", - "awsHint": "يستخدم Bedrock بيانات اعتماد AWS الخاصة بك (البيئة أو الإعداد المشترك). حدّد معرّف النموذج أعلاه واضبط وصول AWS في بيئتك.", - "unsupportedProvider": "لا يمكن تحرير هذا المزود عبر الحقول المنظمة. استخدم محرر config.yaml أدناه أو الإعداد عبر الطرفية.", - "setupTitle": "إعداد ذاتي الإدارة", - "setupHint": "يحتاج إعداد Hermes التفاعلي إلى طرفية. شغّله أدناه، أو انسخ الأمر لتشغيله بنفسك.", - "runSetup": "تشغيل إعداد Hermes", - "configureModel": "تهيئة النموذج", - "openConfigFolder": "فتح ~/.hermes", - "copyCommand": "نسخ الأمر", - "commandCopied": "تم نسخ الأمر إلى الحافظة", - "advancedTitle": "متقدّم: تحرير config.yaml", - "rawConfigHint": "حرّر ~/.hermes/config.yaml مباشرةً. الحفظ هنا يستبدل الملف حرفيًا.", - "saveRawConfig": "حفظ config.yaml" - }, - "codebuddy": { - "configManagement": "تكوين CodeBuddy", - "configDescription": "يصادق CodeBuddy باستخدام مفتاح API. تتطلب إصدارات الصين أيضًا ضبط البيئة على «الصين (internal)»؛ وتستخدم إصدارات iOA «iOA». أما الإصدار الخارجي فيتركها غير مضبوطة.", - "apiKeyLabel": "مفتاح API", - "apiKeyHint": "يُحفظ باسم CODEBUDDY_API_KEY لهذا الوكيل. بدلاً من ذلك، يمكنك تسجيل الدخول عبر واجهة CodeBuddy في الطرفية.", - "apiKeyHintSelfHosted": "يُحفظ باسم CODEBUDDY_API_KEY لهذا الوكيل. استخدم المفتاح الصادر عن نشرك الخاص.", - "environmentLabel": "البيئة", - "environmentHint": "يضبط CODEBUDDY_INTERNET_ENVIRONMENT. يجب أن تستخدم الصين «الصين (internal)»؛ أما الإصدار الخارجي فيتركها غير مضبوطة.", - "envOverseas": "الخارجي (افتراضي)", - "envChina": "الصين (internal)", - "envIoa": "iOA", - "envSelfHosted": "استضافة ذاتية (نشر خاص)", - "baseUrlLabel": "عنوان URL للنشر", - "baseUrlPlaceholder": "https://codebuddy.your-company.com", - "baseUrlHint": "يُحفظ باسم CODEBUDDY_BASE_URL ويوجّه CodeBuddy إلى نقطة النهاية الخاصة بك. في الاستضافة الذاتية يبقى إعداد الشبكة (CODEBUDDY_INTERNET_ENVIRONMENT) غير مضبوط.", - "baseUrlInvalid": "أدخل عنوان URL صالحًا بصيغة http(s).", - "loginHint": "لا تملك مفتاح API؟ شغّل «codebuddy» في الطرفية لتسجيل الدخول بحساب Tencent بدلاً من ذلك." - }, - "kimiCode": { - "configManagement": "إعدادات Kimi Code", - "configDescription": "لا يقبل `kimi acp` سوى رمز تسجيل دخول مخزَّن، لذا يكتب codeg مزوّدًا مُدارًا في ~/.kimi-code/config.toml ويزرع رمز بوابة محليًا — أما الاستدلال فيظل يعمل بمفتاحك أنت.", - "statusUnconfigured": "لم يُضبط بعد", - "statusDirty": "تغييرات غير محفوظة", - "summaryLabel": "المطبَّق حاليًا", - "gateReadyApiKey": "تمت كتابة مفتاح API في config.toml", - "gateReadyLogin": "تم تسجيل الدخول بحساب Kimi", - "revealConfig": "إظهار في المجلد", - "envOverrideWarning": "المتغير {keys} مضبوط وله أولوية على config.toml. الحفظ هنا يزيله.", - "authModeLabel": "طريقة المصادقة", - "authModeApiKey": "مفتاح API", - "authModeLogin": "تسجيل الدخول بحساب Kimi (اشتراك)", - "authModeApiKeyHint": "يكتب مزوّدًا مُدارًا في config.toml ويزرع رمز البوابة كي تتمكن الجلسات من الفتح.", - "loginHint": "شغّل `kimi login` في الطرفية لتسجيل الدخول بحساب اشتراك Kimi. لا يخزّن codeg أي بيانات اعتماد بل يعيد استخدام تسجيل دخول Kimi نفسه. الحفظ هنا يزيل رمز بوابة مفتاح API الخاص بـ codeg.", - "credentialTitle": "بيانات الاعتماد", - "interfaceTypeLabel": "نوع المزوّد", - "interfaceTypeHint": "بروتوكول المزوّد الذي يتحدث به Kimi (الحقل `type` في config.toml). اختر Kimi / Moonshot لمفتاح من Moonshot أو platform.kimi.com.", - "endpointLabel": "نقطة النهاية", - "endpointCustom": "مخصّص (متوافق مع OpenAI)", - "endpointHint": "دولي = api.moonshot.ai؛ الصين (مفاتيح platform.kimi.com) = api.moonshot.cn. أما المخصّص فيشير إلى أي نقطة نهاية متوافقة مع OpenAI.", - "regionInternational": "دولي (api.moonshot.ai)", - "regionChina": "الصين (api.moonshot.cn)", - "baseUrlLabel": "عنوان URL الأساسي", - "baseUrlHint": "اتركه فارغًا لاستخدام القيمة الافتراضية لحزمة SDK الخاصة بالمزوّد.", - "apiKeyLabel": "مفتاح API", - "apiKeyHint": "يُكتب في ~/.kimi-code/config.toml ويُستخدم للاستدلال. من platform.kimi.com أو platform.kimi.ai.", - "vertexProjectLabel": "مشروع GCP‏ (GOOGLE_CLOUD_PROJECT)", - "vertexLocationLabel": "منطقة GCP‏ (GOOGLE_CLOUD_LOCATION)", - "vertexHint": "يستخدم Vertex AI بيانات اعتماد التطبيق الافتراضية من Google — شغّل `gcloud auth application-default login` (بدون مفتاح API).", - "modelTitle": "النموذج", - "modelLabel": "النموذج", - "modelHint": "معرّف النموذج الذي يُكتب في config.toml. استخدم «اختبار وجلب النماذج» لمعرفة ما يمكن لمفتاحك الوصول إليه فعليًا.", - "maxContextLabel": "أقصى حجم للسياق", - "maxContextHint": "مطلوب وفق مخطط Kimi: بدونه يتجاهل Kimi كتلة النموذج بالكامل فلا يعود أي طلب بإجابة. القيمة الافتراضية 262144.", - "fetchModels": "اختبار وجلب النماذج", - "fetchModelsOk": "المفتاح يعمل — {count} نموذجًا متاحًا", - "fetchModelsEmpty": "المفتاح يعمل، لكن لم تُرجَع أي نماذج", - "fetchModelsFailed": "فشل الاختبار", - "fetchModelsNeedsKey": "أدخل أولًا مفتاح API ونقطة النهاية", - "modelNotInList": "هذا النموذج ليس ضمن القائمة التي يستطيع مفتاحك الوصول إليها — سيفشل Kimi برسالة «النموذج غير موجود».", - "reasoningTitle": "الاستدلال", - "reasoningEnableLabel": "تفعيل", - "reasoningDescription": "لا يعرض Kimi محدِّد «Thinking» في صندوق الإدخال إلا إذا أعلن النموذج عن قدرة استدلال، ولذلك يكتبها codeg هنا. يسري على الجلسات الجديدة.", - "effortsLabel": "المستويات المتاحة", - "effortsHint": "تصبح هذه المستويات خيارات محدِّد «Thinking». يمرِّر Kimi المستوى إلى المزوّد كما هو، فاختر ما يقبله نموذجك.", - "effortsEmptyHint": "من دون اختيار أي مستوى، يتراجع صندوق الإدخال إلى مفتاح Off / On فقط.", - "effortsCustomPlaceholder": "أضف مستوى آخر", - "effortsAdd": "إضافة", - "defaultEffortLabel": "المستوى الافتراضي", - "defaultEffortAuto": "اترك الاختيار لـ Kimi", - "alwaysThinkingLabel": "النموذج يستدل دائمًا — أزل خيار Off من المحدِّد", - "fixErrorsFirst": "صحّح الحقول المميّزة أولًا", - "errorModelRequired": "النموذج حقل مطلوب", - "errorMaxContextRequired": "أقصى حجم للسياق حقل مطلوب", - "errorMaxContextInvalid": "يجب أن يكون عددًا صحيحًا موجبًا", - "errorApiKeyRequired": "مفتاح API حقل مطلوب", - "errorApiKeyInvalid": "يجب ألا يحتوي مفتاح API على فواصل أسطر", - "errorBaseUrlRequired": "عنوان URL الأساسي حقل مطلوب", - "errorBaseUrlInvalid": "يجب أن يبدأ بـ http:// أو https://", - "errorVertexProjectRequired": "مشروع GCP حقل مطلوب", - "errorDefaultEffortUnlisted": "اختر أحد المستويات المحددة أعلاه", - "advancedTitle": "خيارات متقدمة", - "authTypeLabel": "موضع كتابة بيانات الاعتماد", - "authTypeApiKey": "‏api_key مضمَّن", - "authTypeEnv": "جدول env الفرعي للمزوّد", - "authTypeHint": "الموضع الذي يُكتب فيه مفتاح API داخل config.toml.", - "rawEditorLabel": "تحرير config.toml مباشرة", - "rawEditorWarning": "الحفظ هنا يستبدل الملف بأكمله حرفيًا، ويحل محل الإعدادات المنظَّمة أعلاه.", - "rawEditorPlaceholder": "[providers.codeg]\ntype = \"kimi\"\nbase_url = \"https://api.moonshot.cn/v1\"\napi_key = \"sk-...\"" - }, - "authModeOfficialSubscription": "الاشتراك الرسمي", - "authModeCustomEndpoint": "نقطة نهاية مخصصة", - "authModeCustomEndpointHint": "تكوين عنوان API ومفتاح API يدوياً لنقطة نهاية مخصصة.", - "authModeModelProvider": "مزود النموذج", - "modelProvider": "مزود النموذج", - "modelProviderHint": "استخدم عنوان API ومفتاح API والنموذج من مزود نموذج مُعدّ.", - "selectModelProvider": "اختر مزود النموذج", - "noModelProviderAvailable": "لا يوجد مزود نموذج مُعدّ لهذا الوكيل. انتقل إلى إعدادات مزود النموذج لإضافة واحد.", - "claude": { - "authMode": "وضع المصادقة", - "officialSubscription": "الاشتراك الرسمي", - "officialSubscriptionHint": "استخدم اشتراك Anthropic الرسمي، لا حاجة لمفتاح API.", - "mainModel": "النموذج الرئيسي", - "reasoningModel": "نموذج الاستدلال (thinking)", - "haikuDefaultModel": "نموذج Haiku الافتراضي", - "sonnetDefaultModel": "نموذج Sonnet الافتراضي", - "opusDefaultModel": "نموذج Opus الافتراضي", - "customModelOption": "معرّف النموذج المخصّص", - "customModelOptionName": "اسم النموذج المخصّص", - "customModelOptionDescription": "وصف النموذج المخصّص", - "customModelOptionHint": "يضيف عنصرًا مخصّصًا واحدًا إلى محدِّد نماذج Claude (مثل نموذج خلف بوابة/وكيل مخصّص). الاسم والوصف اختياريان لأغراض العرض فقط.", - "effortLevel": "مستوى الاستدلال", - "effortLevelDefault": "المستوى الافتراضي", - "effortLevel_low": "منخفض", - "effortLevel_medium": "متوسط", - "effortLevel_high": "مرتفع", - "effortLevel_xhigh": "مرتفع جداً", - "sendAttributionHeader": "إرسال معرّف الإسناد/الفوترة إلى الواجهة", - "sendAttributionHeaderAria": "إرسال معرّف الإسناد/الفوترة الخاص بـ Claude Code إلى الواجهة", - "disableNonessentialTraffic": "تعطيل القياس عن بُعد أو طلبات الشبكة غير الضرورية", - "disableNonessentialTrafficAria": "تعطيل القياس عن بُعد أو طلبات الشبكة غير الضرورية في Claude Code" - }, - "dialogs": { - "confirmDeleteProvider": "حذف المزود {providerId}؟", - "confirmDeleteProviderDescription": "سيتم تحديث إعداد OpenCode وauth JSON معًا. لا يمكن التراجع عن هذا الإجراء.", - "confirmUninstall": "إزالة تثبيت {name}؟", - "confirmUninstallDescription": "سيؤدي هذا إلى إزالة الإصدار المثبت محليًا. يمكنك إعادة التثبيت لاحقًا.", - "customInstallTitle": "تثبيت مخصص لـ {name}", - "customInstallDescription": "أدخل الإصدار المراد تثبيته. سيؤدي ذلك إلى إعادة التثبيت واستبدال الإصدار المثبت حاليًا.", - "customInstallVersionLabel": "رقم الإصدار", - "customInstallInvalid": "أدخل رقم إصدار صالحًا، مثل 1.2.3.", - "customInstallSubmit": "تثبيت" - }, - "errors": { - "windowsFileLocked": "ملفات {name} قيد الاستخدام بواسطة جلسة قيد التشغيل، لذا لا يمكن لـ Windows استبدالها. أغلق جميع جلسات {name} ثم حاول مرة أخرى.", - "nativeJsonMustBeObject": "يجب أن يكون إعداد JSON الأصلي كائنًا", - "nativeJsonInvalid": "خطأ في تنسيق إعداد JSON الأصلي: {message}", - "openCodeAuthMustBeObject": "يجب أن يكون OpenCode auth.json كائن JSON", - "openCodeAuthInvalid": "خطأ في تنسيق OpenCode auth.json: {message}", - "authMustBeObject": "يجب أن يكون auth.json كائن JSON", - "authInvalid": "خطأ في تنسيق auth.json: {message}", - "providerIdPattern": "يدعم معرّف المزود الأحرف والأرقام والشرطة السفلية والنقطة والشرطة فقط", - "providerExists": "المزوّد {providerId} موجود بالفعل", - "modelIdPattern": "يدعم معرّف النموذج الأحرف والأرقام والشرطة السفلية والنقطة والنقطتين والشرطة فقط", - "modelExists": "النموذج {modelId} موجود بالفعل" - }, - "warnings": { - "nativeJsonRecoveredStructured": "إعداد JSON الأصلي غير صالح؛ تمت إعادة التعيين إلى إعداد مُهيكل", - "nativeJsonRecoveredOpenCode": "إعداد JSON الأصلي غير صالح؛ تمت إعادة التعيين إلى إعداد OpenCode المُهيكل", - "openCodeAuthRecovered": "ملف OpenCode auth.json غير صالح؛ تمت إعادة التعيين إلى الإعداد الافتراضي", - "authRecoveredStructured": "ملف auth.json غير صالح؛ تمت إعادة التعيين إلى إعداد مُهيكل" - }, - "toasts": { - "agentActionCompleted": "اكتمل {action} لـ {name}", - "agentActionFailed": "فشل {action} لـ {name}", - "localVersion": "الإصدار المحلي: {version}", - "installCompletedVersionLater": "اكتمل التثبيت، سيتم تحديث الإصدار عند الفحص التالي", - "uninstallCompleted": "اكتملت إزالة تثبيت {name}", - "uninstallFailed": "فشلت إزالة تثبيت {name}", - "localVersionRemoved": "تمت إزالة الإصدار المحلي", - "saveAgentOrderFailed": "فشل حفظ ترتيب Agent", - "saveAgentSwitchFailed": "فشل حفظ مفتاح Agent", - "saveEnvFailed": "فشل حفظ متغيرات البيئة", - "grokSaved": "تم حفظ إعدادات Grok", - "saveGrokNativeFailed": "فشل حفظ إعدادات Grok الأصلية", - "saveGrokApiKeyFailed": "تم حفظ الإعدادات، لكن تعذّر حفظ مفتاح API", - "cursorSaved": "تم حفظ إعدادات Cursor", - "saveCursorConfigFailed": "فشل حفظ إعدادات Cursor", - "codexSaved": "تم حفظ إعداد Codex", - "saveCodexNativeFailed": "فشل حفظ إعداد Codex الأصلي", - "geminiSaved": "تم حفظ إعداد Gemini", - "saveGeminiFailed": "فشل حفظ إعداد Gemini", - "providerDeleted": "تم حذف المزود {providerId}", - "providerDeleteFailed": "فشل حذف المزود {providerId}", - "providerSaved": "تم حفظ المزود {providerId}", - "saveProviderFailed": "فشل حفظ المزود {providerId}", - "openCodeConfigSynced": "تمت مزامنة إعداد OpenCode وauth JSON.", - "openCodeSaved": "تم حفظ إعداد OpenCode", - "saveOpenCodeFailed": "فشل حفظ إعداد OpenCode", - "openClawSaved": "تم حفظ إعداد OpenClaw", - "saveOpenClawFailed": "فشل حفظ إعداد OpenClaw", - "configSaved": "تم حفظ الإعداد", - "configSavedHint": "يجب إعادة فتح الجلسات الحالية لتطبيق التغييرات", - "saveConfigManagementFailed": "فشل حفظ إدارة الإعدادات", - "clineSaved": "تم حفظ تكوين Cline", - "saveClineFailed": "فشل في حفظ تكوين Cline", - "hermesSaved": "تم حفظ تكوين Hermes", - "saveHermesFailed": "فشل في حفظ تكوين Hermes", - "codeBuddySaved": "تم حفظ إعدادات CodeBuddy", - "saveCodeBuddyFailed": "فشل حفظ إعدادات CodeBuddy", - "kimiCodeSaved": "تم حفظ إعدادات Kimi Code", - "saveKimiCodeFailed": "فشل حفظ إعدادات Kimi Code", - "deepseekSaved": "تم حفظ إعدادات DeepSeek", - "saveDeepSeekFailed": "تعذّر حفظ إعدادات DeepSeek", - "modelProviderRequired": "يرجى اختيار مزود نموذج قبل الحفظ.", - "affectedRunningSessions": "{count} جلسة نشطة تحتاج إلى إعادة الاتصال لتطبيق التغيير", - "providerConnected": "تم ربط {providerId}", - "connectFailed": "فشل ربط {providerId}", - "providerDisconnected": "تم قطع اتصال {providerId}", - "disconnectFailed": "فشل قطع اتصال {providerId}", - "catalogRefreshed": "تم تحديث الكتالوج — {count} مزودًا", - "catalogRefreshFailed": "فشل تحديث الكتالوج", - "piSaved": "تم حفظ إعدادات Pi", - "savePiFailed": "فشل حفظ إعدادات Pi", - "piRuntimeSaved": "تم حفظ وقت تشغيل Pi", - "savePiRuntimeFailed": "فشل حفظ وقت تشغيل Pi", - "piBinaryInstalled": "تم تثبيت pi", - "piBinaryInstallFailed": "فشل تثبيت pi", - "piBinaryUninstalled": "تم إلغاء تثبيت pi", - "piBinaryUninstallFailed": "فشل إلغاء تثبيت pi", - "savePiTrustFailed": "فشل حفظ الثقة بمساحة العمل" - }, - "version": { - "statusLabel": "حالة الإصدار", - "notInstalled": "غير مثبت", - "remoteLocal": "البعيد: {remoteVersion} · المحلي: {localVersion}", - "localOnly": "المحلي: {localVersion}", - "localInstalled": "{versionText}. مثبت.", - "platformUnsupported": "{versionText}. المنصة الحالية لا تدعم هذا الوكيل.", - "uvxNotReady": "{versionText}. وقت تشغيل uv غير مثبّت — ثبّته من فحص uv بالأسفل لاستخدام هذا الوكيل.", - "clickInstall": "{versionText}. انقر تثبيت في الجهة اليمنى.", - "localUnrecognized": "{versionText}. الإصدار المحلي غير قابل للمقارنة؛ جرّب الترقية للكتابة فوق التثبيت.", - "upgradeAvailable": "{versionText}. تتوفر ترقية.", - "remoteUnavailable": "{versionText}. الإصدار البعيد غير متاح حاليًا.", - "latest": "{versionText}. أنت على أحدث إصدار." - }, - "adapter": { - "label": "محوّل ACP", - "badge": "محوّل ACP", - "badgeHint": "بالنسبة لهذا الوكيل يثبّت Codeg حزمة محوّل ACP وليس واجهة الأوامر الرسمية. الاثنان مستقلان ويتشاركان الإعدادات نفسها.", - "learnMore": "معرفة المزيد", - "missingWithNative": "تم العثور على {nativeLabel} الخاصة بك في {nativePath}. يتواصل Codeg مع الوكلاء عبر ACP، وهذه الواجهة لا تدعم ACP، لذا يحتاج Codeg إلى حزمة محوّل منفصلة هي {adapterPackage}، يتولى صيانتها مشروع Agent Client Protocol (بدأه فريق Zed). تأتي ببيئة تشغيل خاصة بها، ولا تعدّل أمر {nativeCmd} لديك ولا تستبدله، وتقرأ المسار {configDir} نفسه — فتسجيل الدخول والإعدادات الحالية تبقى كما هي. ثبّتها من الأسفل.", - "missing": "يتواصل Codeg مع الوكلاء عبر ACP، و{nativeLabel} لا تدعم ACP، لذا يحتاج Codeg إلى حزمة محوّل منفصلة هي {adapterPackage}، يتولى صيانتها مشروع Agent Client Protocol (بدأه فريق Zed). تأتي ببيئة تشغيل خاصة بها، فلا حاجة لتثبيت {nativeCmd} أولاً؛ وإن كانت لديك فالاثنان يتعايشان ويتشاركان تسجيل الدخول والإعدادات في {configDir}. ثبّتها من الأسفل.", - "readyWithNative": "المحوّل {adapterCmd} مثبّت — وهو ما يشغّله Codeg، وليس {nativeCmd} الخاص بك في {nativePath}. هما حزمتان مستقلتان تتعايشان، وكلتاهما تقرأ {configDir}، لذا فتسجيل الدخول والإعدادات مشتركة.", - "ready": "المحوّل {adapterCmd} مثبّت — وهو ما يشغّله Codeg. يأتي ببيئة تشغيل خاصة به، لذا لا حاجة إلى {nativeLabel}؛ وإن ثبّتها لاحقاً فالاثنان يتعايشان ويتشاركان {configDir}." - }, - "cline": { - "configDescription": "تكوين مزود واجهة برمجة التطبيقات وبيانات اعتماد Cline. يتم حفظ الإعدادات في ~/.cline/data/." - }, - "opencodePlugins": { - "title": "إضافات OpenCode", - "declared": "الإضافات المعلنة", - "noPlugins": "لا توجد إضافات معلنة في opencode.json", - "status": { - "installed": "مثبّت", - "missing": "غير مثبّت" - }, - "installAll": "تثبيت جميع الإضافات المفقودة", - "pinVersions": "تثبيت إصدارات @latest", - "install": "تثبيت", - "uninstall": "إزالة", - "refresh": "تحديث", - "success": "تم تثبيت جميع الإضافات بنجاح", - "failed": "فشلت عملية الإضافة" - }, - "pi": { - "configManagement": "إعدادات Pi", - "configDescription": "يصادق Pi عبر مفتاح API لمزوّد النموذج. يُكتب المفتاح في ~/.pi/agent/auth.json واختيار النموذج في settings.json.", - "providerLabel": "المزوّد", - "modelLabel": "النموذج", - "thinkingLabel": "التفكير", - "thinking": { - "off": "إيقاف", - "low": "منخفض", - "medium": "متوسط", - "high": "مرتفع", - "minimal": "الحد الأدنى", - "xhigh": "مرتفع جدًا" - }, - "apiKeyLabel": "مفتاح API", - "apiKeyHint": "يُحفظ في ~/.pi/agent/auth.json للمزوّد المحدد.", - "apiKeySetPlaceholder": "•••••• (محفوظ — اتركه فارغًا للإبقاء عليه)", - "saveConfig": "حفظ إعدادات Pi", - "providerModelRequired": "المزوّد والنموذج مطلوبان", - "runtimeTitle": "وقت التشغيل", - "runtimeDescription": "اختر أي ملف pi يعمل. استخدم الافتراضي أو أشِر إلى بناء pi الخاص بك.", - "modeDefault": "pi الافتراضي", - "modeDefaultHint": "يستخدم محوّل pi-acp المدمج مع pi الموجود في PATH. ثبّت pi عبر: npm install -g @earendil-works/pi-coding-agent", - "modeCustom": "pi مخصّص", - "modeCustomHint": "شغّل بناء pi أو تثبيته أو غلافه الخاص بك.", - "commandLabel": "أمر pi أو مساره", - "commandHint": "مسار مطلق، أو اسم أمر في PATH، أو نص غلاف (مثل ./pi-test.sh في monorepo).", - "commandNotFound": "الأمر غير موجود", - "validate": "تحقّق", - "advanced": "متقدّم", - "configDirLabel": "دليل الإعدادات (PI_CODING_AGENT_DIR)", - "sessionDirLabel": "دليل الجلسات (PI_CODING_AGENT_SESSION_DIR)", - "flagsHint": "لا يمرّر pi-acp رايات pi المخصّصة (‎--approve، ‎-e، …) — غلّف pi بنص وأشِر الأمر إليه.", - "customIncomplete": "أدخل أمر pi للحفظ", - "saveRuntime": "حفظ وقت التشغيل", - "providerPlaceholder": "اختر مزوّدًا", - "customProvider": "مزوّد مخصّص…", - "providerIdLabel": "معرّف المزوّد", - "apiProtocolLabel": "بروتوكول API", - "baseUrlLabel": "نقطة نهاية API (عنوان URL الأساسي)", - "customProviderHint": "يعرّف مزوّدًا في ~/.pi/agent/models.json عند نقطة النهاية الخاصة بك. تستخدم معظم الخوادم الذاتية الاستضافة أو الوسيطة openai-completions.", - "baseUrlRequired": "نقطة نهاية API (عنوان URL الأساسي) مطلوبة", - "binaryTitle": "ثنائي pi (pi-coding-agent)", - "binaryDescription": "يشغّل pi-acp ثنائي pi هذا. ثبّته هنا، أو وجّه pi-acp إلى نسختك الخاصة أدناه.", - "binaryInstalled": "مثبَّت", - "binaryMissing": "غير مثبَّت", - "binaryChecking": "جارٍ التحقق…", - "installBinary": "تثبيت pi", - "installing": "جارٍ التثبيت…", - "recheck": "إعادة التحقق", - "configDirSkillsNote": "عند تحديد دليل إعدادات مخصص، لن تنطبق المهارات والخبراء وأدوات المكتب المُدارة في الإعدادات على pi هذا — أدِر مهاراته مباشرةً في ذلك المجلد.", - "projectTrustTitle": "ثقة المشروع", - "projectTrustDescription": "المجلدات التي سمحت لـ pi بتحميل ملفات المشروع منها. المجلد الموثوق يتيح لملفات ‎.pi/extensions في ذلك المستودع تنفيذ التعليمات البرمجية عند بدء pi، ويسري على كل المجلدات داخله، ويُستخدم أيضًا عند تشغيل pi في الطرفية.", - "projectTrustLoading": "جارٍ التحميل…", - "projectTrustEmpty": "لم يتم اتخاذ قرار بشأن أي مجلد بعد.", - "projectTrustTrusted": "موثوق", - "projectTrustDenied": "غير موثوق", - "projectTrustRevoke": "إلغاء", - "reasoningTitle": "الاستدلال", - "reasoningEnableLabel": "تفعيل", - "reasoningDescription": "لا يرسل pi مستوى استدلال إلا لنموذج يعلن عنه — أي نموذج غير معلن تُخفَّض كل مستوياته إلى Off، فيعود المحدِّد في صندوق الإدخال إلى وضعه فور لمسه. يُكتب في مدخل هذا النموذج داخل models.json.", - "levelsLabel": "المستويات المتاحة", - "levelsHint": "تصبح هذه هي خيارات محدِّد الاستدلال في صندوق الإدخال. اختر ما تقبله نقطة النهاية لديك؛ فأي مستوى غير مدرج هنا يرفضه pi.", - "levelsEmptyError": "اختر مستوى واحدًا على الأقل — بدون أي مستوى يعود pi إلى Off.", - "wireValuesTitle": "متقدم: القيم المرسلة إلى المزوّد", - "wireValuesHint": "اتركه فارغًا لإرسال اسم المستوى كما هو. اضبطه عندما تتوقع نقطة النهاية صيغة أخرى — الواجهات على نمط Google تحتاج LOW / HIGH.", - "defaultLevelUnlisted": "هذا المستوى ليس ضمن القائمة أعلاه — سيخفّضه pi." - }, - "addCustomAgent": "إضافة وكيل مخصص", - "addCustomAgentHint": "سجّل أي وكيل متوافق مع ACP. اختر واحدًا من سجل ACP العام، أو الصق معلومات السجل الخاصة به.", - "customAgentFromRegistry": "سجل ACP", - "customAgentManual": "يدوي", - "customAgentSearchPlaceholder": "البحث عن الوكلاء…", - "customAgentLoadingCatalog": "جارٍ تحميل سجل ACP…", - "customAgentRetry": "إعادة المحاولة", - "customAgentNoResults": "لا يوجد وكلاء مطابقون", - "customAgentAdd": "إضافة", - "customAgentAlreadyAdded": "تمت الإضافة", - "customAgentUnsupportedPlatform": "لا يوجد إصدار متاح لهذه المنصة", - "customAgentAdded": "تمت إضافة {name}", - "customAgentIdLabel": "معرّف السجل", - "customAgentNameLabel": "الاسم المعروض", - "customAgentVersionLabel": "الإصدار", - "customAgentSpecLabel": "التوزيع (JSON)", - "customAgentSpecHint": "بنفس شكل كائن distribution في سجل ACP: قنوات npx وuvx وbinary، أو الصق مدخل سجل كاملًا. في npx/uvx يكون cmd هو الأمر التنفيذي الذي تثبته الحزمة — يُشتق من اسم الحزمة عند إغفاله، فحدده عندما يختلفان. يُنظَّم binary حسب مفتاح المنصة (هذا الجهاز: {platform})؛ cmd هو مسار التشغيل داخل الأرشيف، وsha256 اختياري للتحقق من التنزيل.", - "customAgentTemplateLabel": "قوالب", - "customAgentKindLabel": "التشغيل عبر", - "customAgentInvalidJson": "JSON غير صالح", - "customAgentNoDistribution": "لم يتم العثور على توزيع npx أو uvx أو binary", - "customAgentCancel": "إلغاء", - "customAgentSave": "إضافة الوكيل", - "customAgentSaveChanges": "حفظ التغييرات", - "customAgentEdit": "تحرير الوكيل", - "customAgentEditHint": "حدّث الاسم والأيقونة ومعلومات التوزيع وإعلانات المهارات. لا يمكن تغيير معرّف الوكيل.", - "customAgentEditNotFound": "لم يُعثر على الوكيل المخصص {id}", - "customAgentSaved": "تم حفظ {name}", - "customAgentVersionProbeLabel": "أمر الاستعلام عن الإصدار (اختياري)", - "customAgentVersionProbeHint": "أمر يطبع الإصدار المثبت محليًا. عند تركه فارغًا يشغّل codeg أمر الوكيل مع ‎--version.", - "customAgentRemove": "إزالة الوكيل", - "customAgentRemoveHint": "يحذف تعريف الوكيل. تحتفظ المحادثات الحالية بسجلها، ولن يصبح بالإمكان تشغيل الوكيل فحسب.", - "customAgentIconLabel": "الأيقونة (اختياري)", - "customAgentIconUpload": "رفع", - "customAgentIconReplace": "استبدال", - "customAgentIconClear": "إزالة الأيقونة", - "customAgentIconHint": "يُحفظ مع الوكيل، لذا يعمل دون اتصال. وبدونه يُستخدم حرف أول ملوّن.", - "customAgentSkillsLabel": "Skills (‎.agents/skills المشترك)", - "customAgentSkillsHint": "يُعلن أن هذا الوكيل يقرأ مخزن .agents/skills المشترك (المجلدين العام والخاص بالمشروع) ويضيفه إلى جميع مصفوفات المهارات. المهارات المرتبطة هناك تكون مرئية لكل وكيل يقرأ هذا المخزن المشترك.", - "customAgentSkillsDirLabel": "دليل مهارات مخصص", - "customAgentSkillsDirHint": "المسار المطلق للدليل الذي يحمّل منه هذا الوكيل المهارات — مخزنه الخاص، إضافةً إلى المخزن المشترك أو بدلًا منه. يتم توسيع ~ إلى الدليل الرئيسي؛ وتوضع المهارات المرتبطة هنا أولًا.", - "customAgentMcpLabel": "دعم MCP", - "customAgentMcpHint": "يرسل رفيق MCP المدمج في codeg إلى هذا الوكيل عند بدء الجلسة — وهو القناة التي تعتمد عليها الإحالة والتغذية الراجعة الحية وأدوات المهام. أوقفه مع الوكلاء الذين يرفضون خوادم MCP ويفشلون في الاتصال؛ ويسري التغيير من الاتصال التالي.", - "customAgentIconNotAnImage": "اختر ملف صورة.", - "customAgentIconTooLarge": "يجب أن يكون حجم الأيقونة أقل من {limit} كيلوبايت.", - "customAgentIconReadFailed": "تعذّرت قراءة تلك الصورة.", - "customAgentRemoveConfirm": "إزالة {name}؟ ستبقى المحادثات الحالية، لكن لن يمكن تشغيل الوكيل بعد الآن.", - "customAgentRemoveWithData": "حذف سجل المحادثات المسجل أيضًا", - "customAgentRemoved": "تمت إزالة {name}", - "customAgentBadge": "مخصص", - "customAgentNotLaunchable": "لا يمكن تشغيل هذا الوكيل هنا: {reason}" - }, - "SettingsPages": { - "agentsLoading": "جارٍ تحميل إعدادات الوكلاء...", - "skillPacksLoading": "جارٍ تحميل حزم المهارات…" - }, - "GeneralSettings": { - "loading": "جارٍ التحميل...", - "sectionTitle": "عام", - "sectionDescription": "تفضيلات موحّدة للطرفية الافتراضية وتسريع العرض وتفويض الوكلاء المتعدّدين.", - "terminalTitle": "الطرفية الافتراضية", - "terminalDescription": "اختر الصدفة المستخدمة عند فتح علامات تبويب طرفية جديدة من شريط الطرفية أو شجرة الملفات. تستخدمها الوكلاء أيضًا عندما تطلب من codeg تنفيذ سطر أوامر كامل نيابةً عنها.", - "terminalSystemDefault": "افتراضي النظام", - "terminalPowerShell7": "PowerShell 7 (pwsh)", - "terminalWindowsPowerShell": "Windows PowerShell", - "terminalCmd": "موجّه الأوامر (cmd)", - "terminalSaveFailed": "فشل حفظ إعدادات الطرفية: {message}", - "terminalShellCustom": "مسار مخصص", - "terminalShellCustomPath": "مسار الصدفة", - "terminalShellCustomPlaceholder": "/usr/local/bin/fish", - "terminalShellCustomSave": "حفظ", - "terminalShellCustomHint": "أدخل مساراً مطلقاً أو اسماً يمكن حلّه عبر PATH.", - "terminalShellNotInstalled": "غير مثبّت", - "terminalShellNotFoundWarning": "هذا المسار غير موجود على هذا المضيف.", - "terminalCurrentShell": "قيد الاستخدام: {path}", - "renderingDescription": "أوقف تشغيل تسريع الأجهزة إذا ظهرت شاشة سوداء أو أخطاء في العرض (شائع على بعض كروت AMD أو كروت Intel المدمجة). يسري على إصدار سطح المكتب لويندوز فقط.", - "disableHardwareAcceleration": "تعطيل تسريع الأجهزة", - "renderingSaveFailed": "فشل حفظ إعدادات العرض: {message}", - "restartRequired": "تم الحفظ. أعد تشغيل التطبيق ليصبح التغيير نافذًا.", - "restartNow": "إعادة التشغيل الآن", - "restartFailed": "فشل إعادة التشغيل: {message}", - "loadFailed": "فشل التحميل: {message}" - }, - "LoginPage": { - "documentTitle": "تسجيل الدخول - codeg", - "brand": "Codeg", - "subtitle": "أدخل رمز الوصول للاتصال بتطبيق سطح المكتب", - "tokenPlaceholder": "رمز الوصول", - "connect": "اتصال", - "connecting": "جارٍ الاتصال...", - "helpText": "يمكنك الحصول على الرمز من تطبيق سطح المكتب عبر الإعدادات → خدمة الويب", - "invalidToken": "رمز غير صالح. يرجى التحقق والمحاولة مرة أخرى.", - "connectionFailed": "فشل الاتصال (HTTP {status})", - "networkError": "تعذر الاتصال بالخادم" - }, - "CommitPage": { - "title": "التزام", - "invalidFolderId": "معرّف المجلد غير صالح", - "loadingRepo": "جارٍ تحميل المستودع..." - }, - "MergePage": { - "title": "حل التعارضات", - "invalidFolderId": "معرّف المجلد غير صالح", - "loadingRepo": "جارٍ تحميل المستودع...", - "localVersion": "محلي (الخاص بنا)", - "result": "النتيجة", - "remoteVersion": "بعيد (الخاص بهم)", - "acceptLocal": "قبول المحلي", - "acceptRemote": "قبول البعيد", - "markResolved": "تحديد كمحلول", - "abortMerge": "إلغاء", - "completeMerge": "إتمام الدمج", - "unresolvedConflicts": "لا تزال هناك علامات تعارض غير محلولة في هذا الملف", - "fileResolved": "تم حل الملف بنجاح", - "allResolved": "تم حل جميع التعارضات", - "conflictFiles": "ملفات متعارضة", - "loadingFile": "جارٍ تحميل الملف...", - "preparingMerge": "جارٍ تحضير الدمج...", - "selectFile": "اختر ملفًا لحله", - "noConflicts": "لا توجد ملفات متعارضة", - "skipFile": "تخطي", - "abortSuccess": "تم إلغاء العملية", - "applyAllNonConflicting": "تطبيق جميع التغييرات غير المتعارضة", - "applyLeftNonConflicting": "تطبيق المحلي", - "applyRightNonConflicting": "تطبيق البعيد" - }, - "ImportSessions": { - "title": "استيراد الجلسات المحلية", - "scanningTitle": "جارٍ فحص جلسات الوكلاء المحلية…", - "scanningHint": "يجري المرور على مخزن الجلسات المحلي لكل وكيل. قد يستغرق ذلك بعض الوقت مع السجلات الكبيرة. ويجري خلال ذلك تحديث الجلسات المستوردة سابقًا.", - "scanFailed": "فشل الفحص", - "retry": "إعادة المحاولة", - "rescan": "إعادة الفحص", - "empty": "لم يُعثر على جلسات محلية", - "emptyHint": "لم يُعثر على مخازن جلسات للوكلاء على هذا الجهاز.", - "noMatches": "لا توجد جلسات مطابقة للمرشحات الحالية", - "searchPlaceholder": "ابحث في العنوان أو المسار…", - "allAgents": "جميع الوكلاء", - "onlyImportable": "القابلة للاستيراد فقط", - "selectAll": "تحديد الكل", - "clearSelection": "مسح", - "expandAll": "توسيع الكل", - "collapseAll": "طي الكل", - "summaryCounts": "{total} جلسة · {importable} قابلة للاستيراد · {folders} مجلدًا", - "noFolderSkipped": "تم تخطي {count} بدون مجلد مشروع", - "folderNew": "جديد", - "folderCounts": "قابلة للاستيراد {importable}/{total}", - "toggleFolderAria": "تحديد كل الجلسات القابلة للاستيراد في {name}", - "toggleSessionAria": "تحديد الجلسة {title}", - "statusImported": "مستوردة", - "statusDeleted": "محذوفة", - "untitled": "جلسة بلا عنوان", - "messageCount": "{count} رسالة", - "selectedCount": "{count} محددة", - "importSelected": "استيراد المحدد", - "importing": "جارٍ الاستيراد…", - "close": "إغلاق", - "doneTitle": "اكتمل الاستيراد", - "doneImported": "مستوردة", - "doneUpdated": "محدّثة", - "doneSkipped": "متخطاة", - "doneCreatedFolders": "مجلدات منشأة", - "doneNotFound": "غير موجودة", - "doneFailed": "فاشلة", - "continueImport": "متابعة الاستيراد", - "toasts": { - "importFailed": "فشل الاستيراد: {message}" - } - }, - "Folder": { - "workspaceStatus": { - "degradedTitle": "التحديثات الفورية غير متاحة", - "degradedHint": "فشل تشغيل المراقب (مثل رفض الإذن). قم بالتحديث يدويًا لرؤية التغييرات.", - "retry": "إعادة المحاولة", - "retrying": "جارٍ إعادة المحاولة..." - }, - "common": { - "all": "الكل", - "cancel": "إلغاء", - "close": "إغلاق", - "closeOthers": "إغلاق البقية", - "closeAll": "إغلاق الكل", - "confirm": "تأكيد", - "save": "حفظ", - "delete": "حذف", - "rename": "إعادة تسمية", - "loading": "جارٍ التحميل...", - "refresh": "تحديث", - "refreshing": "جارٍ التحديث...", - "create": "إنشاء", - "createAndSwitch": "إنشاء والتبديل", - "openFile": "فتح الملف", - "viewDiff": "عرض Diff", - "push": "دفع..." - }, - "statusLabels": { - "in_progress": "قيد التنفيذ", - "pending_review": "مراجعة", - "completed": "مكتمل", - "cancelled": "ملغى" - }, - "sidebar": { - "title": "المحادثات", - "locateActiveConversation": "تحديد المحادثة النشطة", - "expandAllGroups": "توسيع كل المجموعات", - "collapseAllGroups": "طي كل المجموعات", - "newConversation": "محادثة جديدة", - "newConversationShort": "جديدة", - "newChat": "محادثة جديدة", - "search": "بحث", - "noConversationsFound": "لم يتم العثور على محادثات.", - "importLocalSessions": "استيراد الجلسات المحلية", - "importing": "جارٍ الاستيراد...", - "error": "خطأ: {message}", - "completeAllSessions": "إكمال جميع الجلسات", - "completeAllReviewTitle": "إكمال جميع جلسات المراجعة؟", - "completeAllReviewDescription": "سيؤدي ذلك إلى وضع علامة مكتمل على جميع {count, plural, one {# جلسة} other {# جلسات}} في المراجعة.", - "completing": "جارٍ الإكمال...", - "toasts": { - "importedSessions": "تم استيراد {imported, plural, one {# جلسة} other {# جلسات}}، وتم تخطي {skipped}", - "importedAndUpdated": "تم استيراد {imported, plural, one {# جلسة} other {# جلسات}}، وتم تحديث {updated, plural, one {# عنوان} other {# عناوين}}، وتم تخطي {skipped}", - "updatedTitles": "تم تحديث {updated, plural, one {# عنوان} other {# عناوين}}، وتم تخطي {skipped}", - "noNewSessionsFound": "لم يتم العثور على جلسات جديدة (تم تخطي {skipped})", - "importFailed": "فشل الاستيراد: {message}", - "reviewCompleted": "تم وضع علامة مكتمل على {count, plural, one {# جلسة مراجعة} other {# جلسات مراجعة}}", - "completeReviewFailed": "فشل إكمال جلسات المراجعة: {message}", - "folderOpened": "تم فتح المجلد {name}", - "folderRemoved": "تمت إزالة المجلد {name}", - "openFolderFailed": "فشل فتح المجلد", - "removeFolderFailed": "فشل إزالة المجلد: {message}", - "reorderFoldersFailed": "فشل إعادة ترتيب المجلدات: {message}", - "changeFolderColorFailed": "فشل تغيير اللون: {message}", - "setFolderAliasFailed": "فشل تعيين الاسم المستعار: {message}", - "changeFolderDefaultAgentFailed": "فشل تعيين الوكيل الافتراضي: {message}" - }, - "statsLabel": "{folders} مجلدات · {convos} محادثة", - "reorderHandle": "اسحب لإعادة الترتيب", - "openFolder": "فتح مجلد", - "searchPlaceholder": "بحث عن محادثات...", - "viewOptions": "خيارات العرض", - "showCompleted": "عرض المحادثات المكتملة", - "showWorktrees": "عرض مجلدات worktree", - "showRecent": "عرض مجموعة الأحدث", - "moreOptions": "المزيد من الخيارات", - "sortBy": "الترتيب حسب", - "sortByCreatedAt": "وقت الإنشاء", - "sortByUpdatedAt": "وقت التحديث", - "sectionOrder": "ترتيب الأقسام", - "sectionOrderMoveUp": "تحريك لأعلى", - "sectionOrderMoveDown": "تحريك لأسفل", - "sectionOrderItemLabel": "{name} — الموضع {position} من {total}", - "statusRunningBadge": "قيد التشغيل", - "runningCountBadge": "{count} جلسة قيد التشغيل", - "statusCancelledBadge": "ملغى", - "worktreeRemovedBadge": "تمت إزالة شجرة العمل الأصلية", - "conversationCountUnit": "{count} محادثة", - "emptyFolderHint": "لا توجد محادثات", - "noMatchingConversations": "لا توجد محادثات مطابقة", - "noUnfinishedConversations": "لا توجد محادثات غير مكتملة. يمكنك تفعيل \"عرض المكتملة\" من القائمة في أعلى اليمين.", - "removeFolderConfirmTitle": "إزالة المجلد من مساحة العمل؟", - "removeFolderConfirmDescription": "إزالة \"{name}\" من مساحة العمل؟ سيتم إغلاق علامات التبويب والمحطات المرتبطة.", - "folderHeaderMenu": { - "manageConversations": "إدارة المحادثات…", - "manageLinks": "المجلدات المرتبطة", - "changeColor": "تغيير اللون", - "useThemeColor": "استخدام سمة التطبيق", - "setDefaultAgent": "تعيين الوكيل الافتراضي", - "defaultAgentNone": "بدون افتراضي (استخدام العام)", - "agentUnavailableSuffix": "(غير متاح)", - "loadingAgents": "جارٍ تحميل الوكلاء…", - "setAlias": "تعيين اسم مستعار…", - "setAliasTitle": "تعيين اسم مستعار للمجلد", - "setAliasPlaceholder": "أدخل اسمًا مستعارًا (اتركه فارغًا للمسح)", - "setAliasSave": "حفظ", - "setAliasCancel": "إلغاء", - "removeFromWorkspace": "إزالة من مساحة العمل" - }, - "manageConversations": { - "title": "إدارة المحادثات", - "searchPlaceholder": "البحث بالعنوان…", - "agentFilterAll": "جميع الوكلاء", - "statusFilterAll": "جميع الحالات", - "folderFilterAll": "كل المجلدات", - "branchFilterAll": "كل الفروع", - "branchNone": "بدون فرع", - "branchSearchPlaceholder": "بحث في الفروع…", - "noMatchingBranches": "لا توجد فروع مطابقة", - "selectAllVisible": "تحديد الكل", - "deselectAll": "إلغاء التحديد", - "selectedCount": "{count} محدد", - "matchedCount": "{count} مطابق", - "untitledConversation": "محادثة بدون عنوان", - "setStatus": "تعيين الحالة…", - "deleteSelected": "حذف", - "noConversations": "لا توجد محادثات في هذا المجلد.", - "noConversationsWorkspace": "لا توجد محادثات في مساحة العمل.", - "noMatchingConversations": "لا توجد محادثات مطابقة للفلاتر.", - "confirmDeleteTitle": "حذف {count} محادثة؟", - "confirmDeleteDescription": "لا يمكن التراجع عن هذا الإجراء.", - "toastDeleted": "تم حذف {count} محادثة", - "toastStatusUpdated": "تم تحديث حالة {count} محادثة", - "toastOpFailed": "فشلت العملية: {message}" - }, - "sectionPinned": "مثبّتة", - "sectionFolders": "المجلدات", - "sectionChats": "محادثة", - "sectionRecent": "الأحدث", - "noChats": "لا توجد محادثات", - "noRecent": "لا توجد محادثات حديثة", - "showMoreRecent": "عرض المزيد ({count})", - "noFolders": "لا توجد مجلدات مفتوحة", - "newChatAction": "محادثة جديدة", - "automations": "الأتمتة", - "tasks": "المهام قيد الانتظار", - "loadingSubsessions": "جارٍ تحميل المحادثات الفرعية…" - }, - "conversation": { - "reloadFailed": "فشل إعادة تحميل المحادثة: {message}", - "reloaded": "تمت إعادة تحميل المحادثة", - "reload": "إعادة تحميل", - "activeConversationIndicator": "المحادثة النشطة", - "newConversation": "محادثة جديدة", - "closeConversation": "إغلاق المحادثة", - "copyText": "نسخ النص", - "copyTextSuccess": "تم النسخ", - "copyTextFailed": "فشل النسخ", - "forkSession": "تفريع الجلسة", - "forkSessionSuccess": "تم تفريع الجلسة بنجاح", - "forkSessionFailed": "فشل في تفريع الجلسة: {error}", - "exportConversation": "تصدير المحادثة", - "exportImage": "صورة", - "exportMarkdown": "Markdown", - "exportHtml": "HTML", - "exportSuccess": "تم تصدير المحادثة", - "exportFailed": "فشل التصدير", - "exportImageTooLong": "المحادثة طويلة جداً ولا يمكن تصديرها كصورة", - "exportLabels": { - "untitledConversation": "محادثة بدون عنوان", - "agent": "الوكيل", - "model": "النموذج", - "status": "الحالة", - "started": "البداية", - "updated": "التحديث", - "tokens": "إحصائيات الرموز", - "duration": "المدة", - "inputTokens": "الإدخال", - "outputTokens": "الإخراج", - "cacheRead": "قراءة الذاكرة", - "cacheWrite": "كتابة الذاكرة", - "user": "المستخدم", - "assistant": "المساعد", - "system": "النظام", - "toolResult": "النتيجة", - "toolError": "خطأ" - }, - "moreActions": "إجراءات إضافية" - }, - "sessionDetails": { - "menuLabel": "تفاصيل الجلسة", - "noActiveSession": "لا توجد جلسة نشطة", - "title": "تفاصيل الجلسة", - "subtitle": "بيانات الجلسة الوصفية واستخدام الرموز", - "fieldTitle": "العنوان", - "untitled": "محادثة بدون عنوان", - "sessionId": "معرّف الجلسة", - "externalId": "معرّف الامتداد", - "agent": "الوكيل", - "model": "النموذج", - "status": "الحالة", - "gitBranch": "فرع Git", - "parentId": "الجلسة الأصلية", - "tokensHeading": "استخدام الرموز", - "totalTokens": "الإجمالي", - "inputTokens": "الإدخال", - "outputTokens": "الإخراج", - "cacheWrite": "كتابة الذاكرة", - "cacheRead": "قراءة الذاكرة", - "contextWindow": "نافذة السياق", - "duration": "المدة", - "loadingStats": "جارٍ تحميل استخدام الرموز…", - "loadFailed": "فشل تحميل استخدام الرموز", - "noStats": "لا يوجد استخدام مسجّل", - "timestampsHeading": "الطوابع الزمنية", - "createdAt": "تاريخ الإنشاء", - "updatedAt": "تاريخ التحديث", - "none": "—", - "copyField": "نسخ {field}", - "copiedField": "تم نسخ {field}" - }, - "conversationCard": { - "untitledConversation": "محادثة بدون عنوان", - "newConversation": "محادثة جديدة", - "rename": "إعادة تسمية", - "status": "الحالة", - "delete": "حذف", - "importLocalSessions": "استيراد الجلسات المحلية", - "importing": "جارٍ الاستيراد...", - "renameConversation": "إعادة تسمية المحادثة", - "deleteConversationTitle": "حذف المحادثة؟", - "deleteConversationDescription": "سيؤدي ذلك إلى حذف \"{title}\". لا يمكن التراجع عن هذا الإجراء.", - "cancel": "إلغاء", - "save": "حفظ", - "pin": "تثبيت", - "unpin": "إلغاء التثبيت", - "markCompleted": "وضع علامة كمكتمل", - "reopen": "إعادة فتح", - "expandSubsessions": "توسيع المحادثات الفرعية", - "collapseSubsessions": "طي المحادثات الفرعية" - }, - "search": { - "dialogTitle": "بحث", - "dialogTitleWithFolder": "بحث — {name}", - "tabConversations": "المحادثات", - "tabFiles": "الملفات", - "placeholder": "البحث في المحادثات...", - "filePlaceholder": "البحث في الملفات أو المجلدات...", - "allAgents": "الكل", - "searching": "جارٍ البحث...", - "typeToSearch": "اكتب للبحث في المحادثات", - "typeToSearchFiles": "اكتب للبحث في الملفات أو المجلدات", - "noResults": "لم يتم العثور على نتائج.", - "untitledConversation": "محادثة بدون عنوان" - }, - "folderTitleBar": { - "showSidebar": "إظهار الشريط الجانبي", - "hideSidebar": "إخفاء الشريط الجانبي", - "toggleTerminal": "تبديل الطرفية", - "toggleAuxPanel": "تبديل اللوحة المساعدة", - "search": "بحث", - "openSettings": "فتح الإعدادات", - "backToConversations": "العودة إلى المحادثات", - "withShortcut": "{label} (اختصار: {shortcut})" - }, - "statusBar": { - "connection": { - "connected": "متصل", - "connecting": "جارٍ الاتصال...", - "prompting": "جارٍ الرد...", - "error": "خطأ في الاتصال", - "disconnected": "غير متصل", - "tooltip": "{agent}: {status}", - "tooltipError": "{agent}: {error}", - "title": "اتصال الوكيل", - "triggerAria": "اتصال الوكيل: {status}", - "workingDir": "مجلد العمل", - "sessionId": "معرّف الجلسة", - "viewerNote": "متصل بجلسة يملكها عميل آخر — إعادة الاتصال تعيد ربط هذا العرض فقط.", - "reconnectInterrupts": "إعادة الاتصال تعيد تشغيل الوكيل وتقاطع العمل الجاري.", - "reconnect": "إعادة الاتصال", - "reconnecting": "جارٍ إعادة الاتصال...", - "reconnectUnavailable": "لا توجد جلسة لإعادة الاتصال بها بعد." - }, - "tasks": { - "title": "المهام" - }, - "alerts": { - "title": "التنبيهات", - "empty": "لا توجد تنبيهات", - "details": "التفاصيل" - }, - "stats": { - "conversations": "{count} محادثة", - "openUsage": "عرض إحصاءات الجلسات واستخدام الرموز" - }, - "tokens": { - "contextWindowUsageAria": "استخدام نافذة السياق", - "contextWindow": "نافذة السياق", - "usedMax": "المستخدم / الحد الأقصى", - "tokenUsage": "استخدام الرموز", - "input": "إدخال", - "output": "إخراج", - "cacheRead": "قراءة الكاش", - "cacheWrite": "كتابة الكاش", - "total": "الإجمالي" - } - }, - "auxPanel": { - "tabs": { - "files": "الملفات", - "changes": "التغييرات", - "commits": "الالتزامات" - }, - "noFolderTitle": "لا يوجد مجلد مفتوح", - "noFolderHint": "افتح مجلدا لعرض محتواه هنا" - }, - "windowControls": { - "minimizeWindow": "تصغير النافذة", - "minimize": "تصغير", - "maximizeWindow": "تكبير النافذة", - "maximize": "تكبير", - "restoreWindow": "استعادة النافذة", - "restore": "استعادة", - "closeWindow": "إغلاق النافذة", - "close": "إغلاق" - }, - "tabs": { - "closeConversationTab": "إغلاق تبويب المحادثة", - "close": "إغلاق", - "closeOthers": "إغلاق البقية", - "splitRight": "تقسيم لليمين", - "splitDown": "تقسيم للأسفل", - "splitAndMoveRight": "تقسيم ونقل لليمين", - "splitAndMoveDown": "تقسيم ونقل للأسفل", - "moveToOppositeGroup": "نقل إلى المجموعة المقابلة", - "moveToGroup": "نقل إلى مجموعة", - "groupLabel": "المجموعة {index}", - "changeSplitterOrientation": "تبديل اتجاه الفاصل", - "unsplit": "إلغاء التقسيم", - "unsplitAll": "إلغاء كل التقسيمات", - "closeAll": "إغلاق الكل", - "tileDisplay": "عرض متجانب", - "untileDisplay": "إلغاء التجانب" - }, - "fileWorkspace": { - "files": "الملفات", - "closeFileTab": "إغلاق تبويب الملف", - "close": "إغلاق", - "closeOthers": "إغلاق البقية", - "closeAll": "إغلاق الكل", - "preview": "معاينة", - "editSource": "تحرير المصدر", - "maximize": "تكبير", - "restore": "استعادة", - "emptyDirectory": "مجلد فارغ" - }, - "terminal": { - "rename": "إعادة تسمية", - "close": "إغلاق", - "closeOthers": "إغلاق البقية", - "closeAll": "إغلاق الكل", - "hideTerminal": "إخفاء الطرفية ({shortcut})", - "openFolderFirst": "افتح مجلدا أولا" - }, - "workspaceDialog": { - "title": "فتح مجلد", - "manageTitle": "المجلدات المرتبطة", - "addTargetsTitle": "إضافة مجلدات للربط", - "pickRootDescription": "اختر المجلد الرئيسي لمساحة العمل هذه.", - "linksDescription": "اربط مجلدات أخرى كمجلدات فرعية ليتمكن الوكلاء من العمل عليها جميعًا من مساحة عمل واحدة.", - "addTargetsDescription": "اختر مجلدًا واحدًا أو أكثر. سيصبح كل منها مجلدًا فرعيًا في مساحة العمل.", - "useSystemPicker": "منتقي النظام", - "next": "التالي", - "back": "رجوع", - "done": "تم", - "change": "تغيير", - "addFolders": "إضافة مجلدات", - "addSelected": "إضافة", - "addSelectedCount": "إضافة {count}", - "createCount": "ربط {count} مجلد", - "discardPending": "تجاهل", - "noLinks": "لا توجد مجلدات مرتبطة بعد.", - "gitExclude": "إبقاء الروابط خارج حالة git", - "rename": "إعادة تسمية", - "unlink": "إزالة الرابط", - "repair": "إعادة إنشاء الرابط", - "saveName": "حفظ", - "cancelRename": "إلغاء", - "removePending": "إزالة", - "willAppearAs": "يظهر باسم {name} في مساحة العمل", - "renamedForDuplicate": "تمت إعادة التسمية — {base} مستخدم من رابط آخر", - "renamedForExistingEntry": "تمت إعادة التسمية — {base} موجود بالفعل في هذا المجلد", - "partiallyCreated": "تم ربط {count} مجلد فقط", - "openFailed": "تعذر فتح المجلد", - "previewFailed": "تعذر فحص المجلدات المحددة", - "createFailed": "تعذر ربط المجلدات", - "renameFailed": "تعذرت إعادة تسمية الرابط", - "removeFailed": "تعذرت إزالة الرابط", - "repairFailed": "تعذرت إعادة إنشاء الرابط", - "status": { - "ok": "مرتبط", - "missing": "اختفى الرابط من هذا المجلد", - "conflicted": "يستخدم عنصر آخر هذا الاسم الآن", - "broken": "لم يعد المجلد المرتبط موجودًا" - }, - "nameIssue": { - "empty": "أدخل اسمًا", - "illegalChars": "لا يمكن أن يحتوي على / \\ : * ? \" < > |", - "tooLong": "الاسم طويل جدًا", - "reserved": "هذا الاسم محجوز في ويندوز", - "duplicate": "هذا الاسم مستخدم بالفعل" - }, - "rejection": { - "not_found": "تعذر العثور على هذا المجلد", - "not_a_directory": "هذا المسار ليس مجلدًا", - "same_as_root": "هذا هو مجلد مساحة العمل نفسه", - "ancestor_of_root": "هذا المجلد يحتوي على مساحة العمل", - "inside_root": "موجود بالفعل داخل مساحة العمل", - "already_linked": "مرتبط بالفعل", - "name_unavailable": "لم يتبق اسم متاح لهذا المجلد", - "alreadyLinkedAs": "مرتبط بالفعل باسم {name}" - } - }, - "folderNameDropdown": { - "fallbackFolderName": "مجلد", - "openFolder": "فتح مجلد", - "cloneRepository": "استنساخ المستودع", - "projectBoot": "مُنشئ المشروع", - "opened": "مفتوح", - "recentOpen": "المفتوح مؤخرًا" - }, - "fileWorkspacePanel": { - "addSelectionToChat": "إضافة التحديد إلى المحادثة", - "addToChat": "إضافة إلى المحادثة", - "addSelectionToChatDone": "تمت إضافة {label} إلى المحادثة", - "addFileToChat": "إضافة الملف إلى المحادثة", - "toggleWordWrap": "تبديل التفاف النص", - "addFileToChatDone": "تمت إضافة {label} إلى المحادثة", - "viewDiff": "عرض Diff", - "openFile": "فتح الملف", - "fileCount": "{count, plural, one {# ملف} other {# ملفات}}", - "openFileOrDiff": "افتح ملفًا أو diff من اللوحة اليمنى", - "disk": "القرص", - "head": "HEAD", - "unsaved": "غير محفوظ", - "workingTree": "شجرة العمل", - "loading": "جارٍ التحميل...", - "compareWithBranch": "{path} · مقارنة مع {branch}", - "hunkCount": "{count, plural, one {# مقطع} other {# مقاطع}}", - "prev": "السابق", - "next": "التالي", - "jumpToLine": "الانتقال إلى السطر {line}", - "noParsedDiffSections": "لا توجد أقسام diff محللة", - "loadingEditor": "جارٍ تحميل المحرر...", - "imageZoomIn": "تكبير", - "imageZoomOut": "تصغير", - "imageZoomReset": "إعادة تعيين التكبير", - "htmlPreviewTitle": "معاينة HTML", - "htmlPreviewTrust": "تفعيل البرامج النصية", - "htmlPreviewTrustHint": "تشغيل البرامج النصية لهذا الملف والسماح بالوصول إلى الشبكة. فعّلها فقط للملفات الموثوقة.", - "officePreviewTitle": "معاينة مستند Office", - "officeFullRender": "عرض كامل", - "officeFullRenderHint": "يعرض حركات Morph والأبعاد الثلاثية والمعادلات (يشغّل سكربتات الشريحة نفسها)", - "officeNotInstalled": "OfficeCLI غير مثبّت", - "officeNotInstalledHint": "ثبّت OfficeCLI من الإعدادات → أدوات Office لمعاينة ملفات Word و Excel و PowerPoint.", - "officeOpenSettings": "فتح الإعدادات", - "officeWatchFailed": "تعذّر بدء المعاينة المباشرة", - "officeWatchRetry": "إعادة المحاولة", - "officeServerInstallHint": "يجب تثبيت OfficeCLI على مضيف الخادم. شغّل هذا الأمر هناك ثم أعد المحاولة:", - "officeRemoteDesktopUnsupported": "المعاينة المباشرة غير متاحة في نافذة سطح المكتب البعيد. افتح مساحة العمل هذه في واجهة الويب الخاصة بالخادم لمعاينة ملفات Office." - }, - "branchDropdown": { - "toasts": { - "commitCodeCompleted": "اكتمل التزام الكود", - "pushCodeCompleted": "اكتمل دفع الكود", - "committedFiles": "{count, plural, one {# ملف تم الالتزام به} other {# ملفات تم الالتزام بها}}", - "taskCompleted": "اكتمل {label}", - "taskFailed": "فشل {label}", - "mergeNoNewCommits": "{branchName} لا يحتوي على التزامات جديدة", - "mergedCommits": "{count, plural, one {# التزام تم دمجه} other {# التزامات تم دمجها}}", - "allFilesUpToDate": "كل الملفات محدثة", - "updatedFiles": "{count, plural, one {# ملف تم تحديثه} other {# ملفات تم تحديثها}}", - "openCommitWindowFailed": "فشل فتح نافذة الالتزام", - "openPushWindowFailed": "فشل فتح نافذة الدفع", - "upstreamSet": "تم تعيين فرع upstream", - "upstreamSetAndPushed": "تم تعيين فرع upstream ودفع {count, plural, one {# التزام} other {# التزامات}}", - "noCommitsToPush": "لا توجد التزامات للدفع", - "pushedCommits": "تم دفع {count, plural, one {# التزام} other {# التزامات}}", - "switchedToFolder": "تم التبديل إلى {name}", - "switchFailed": "فشل تبديل الفرع", - "openStashWindowFailed": "فشل فتح نافذة الـ stash" - }, - "tasks": { - "newBranch": "إنشاء الفرع {name}", - "newWorktree": "إنشاء worktree {name}", - "checkoutTo": "Checkout إلى {branchName}", - "mergeBranch": "دمج {branchName}", - "rebaseTo": "Rebase إلى {branchName}", - "deleteRemoteBranch": "حذف الفرع البعيد {branchName}", - "initGitRepo": "تهيئة مستودع Git", - "pullCode": "سحب الكود", - "fetchInfo": "جلب المعلومات", - "pushCode": "دفع الكود", - "stashChanges": "تخزين التغييرات في stash", - "stashPop": "استرجاع stash", - "deleteBranch": "حذف الفرع {branchName}", - "removeWorktree": "حذف worktree الخاص بـ {branchName}", - "removeWorktreeAndBranch": "حذف worktree والفرع {branchName}", - "updateBranch": "تحديث الفرع {branchName}" - }, - "confirm": { - "mergeTitle": "دمج الفرع", - "rebaseTitle": "Rebase للفرع", - "mergeDescription": "دمج {branchName} في الفرع الحالي {currentBranch}؟", - "rebaseDescription": "إجراء rebase للفرع الحالي {currentBranch} على {branchName}؟", - "deleteRemoteTitle": "حذف الفرع البعيد", - "deleteRemoteDescription": "هل تريد حذف الفرع البعيد {branchName}؟ سيؤدي ذلك إلى إزالته من المستودع البعيد ولا يمكن التراجع عن هذا الإجراء.", - "deleteTitle": "حذف الفرع", - "deleteDescription": "حذف الفرع {branchName}؟ لا يمكن التراجع عن هذا الإجراء.", - "forceDeleteTitle": "حذف الفرع بالقوة", - "forceDeleteDescription": "الفرع {branchName} لم يتم دمجه بالكامل. هل أنت متأكد من أنك تريد حذفه بالقوة؟ لا يمكن التراجع عن هذا الإجراء.", - "deleteWorktreeTitle": "حذف worktree", - "deleteWorktreeDescription": "حذف مجلد worktree الذي تم سحب {branchName} فيه؟ سيتم الاحتفاظ بالفرع وإيداعاته.", - "forceDeleteWorktreeTitle": "فرض حذف worktree", - "forceDeleteWorktreeDescription": "يحتوي worktree الخاص بـ {branchName} على ملفات غير مودعة أو غير متتبعة. هل تريد حذفه على أي حال؟ لا يمكن استرجاع تلك التغييرات.", - "deleteWorktreeAndBranchTitle": "حذف worktree والفرع", - "deleteWorktreeAndBranchDescription": "حذف worktree الخاص بـ {branchName} والفرع نفسه ومجلده في مساحة العمل؟ ستنتقل جلساته إلى مجلد المستودع. لا يمكن التراجع عن هذا الإجراء.", - "forceDeleteWorktreeAndBranchTitle": "فرض حذف worktree والفرع", - "forceDeleteWorktreeAndBranchDescription": "يحتوي worktree الخاص بـ {branchName} على ملفات غير مودعة، أو أن الفرع غير مدمج بالكامل. هل تريد حذفهما على أي حال؟ لا يمكن التراجع عن هذا الإجراء." - }, - "current": "الحالي", - "switchToBranch": "التبديل إلى هذا الفرع", - "mergeBranchIntoCurrent": "دمج {branchName} في {currentBranch}", - "rebaseCurrentToBranch": "Rebase لـ {currentBranch} على {branchName}", - "noBranch": "بدون فرع", - "detachedHead": "HEAD منفصل عند {sha}", - "initGitRepo": "تهيئة مستودع Git", - "pullCode": "سحب الكود", - "fetchRemoteBranches": "جلب الفروع البعيدة", - "openCommitWindow": "التزام الكود...", - "pushCode": "دفع...", - "pushBranch": "دفع", - "newBranch": "فرع جديد...", - "newWorktree": "Worktree جديد...", - "stashChanges": "...تخبئة التغييرات", - "stashPop": "استرجاع stash...", - "manageRemotes": "إدارة المستودعات البعيدة...", - "localBranches": "الفروع المحلية ({count, plural, one {#} other {#}})", - "noLocalBranches": "لا توجد فروع محلية", - "remoteBranches": "الفروع البعيدة ({count, plural, one {#} other {#}})", - "noRemoteBranches": "لا توجد فروع بعيدة", - "dialogs": { - "newBranchTitle": "فرع جديد", - "newBranchDescription": "إنشاء فرع جديد من الفرع الحالي {branch}", - "branchNamePlaceholder": "اسم الفرع", - "newWorktreeTitle": "Worktree جديد", - "newWorktreeDescription": "إنشاء worktree جديد من الفرع الحالي {branch}", - "branchNameLabel": "اسم الفرع", - "worktreePathLabel": "مسار worktree", - "worktreePathPlaceholder": "مسار worktree", - "manageRemotesTitle": "إدارة المستودعات البعيدة", - "manageRemotesEmpty": "لم يتم تكوين أي مستودعات بعيدة", - "remoteNamePlaceholder": "اسم المستودع البعيد", - "remoteUrlPlaceholder": "عنوان URL للمستودع البعيد", - "addRemote": "إضافة", - "savingRemotes": "جارٍ الحفظ..." - }, - "conflict": { - "title": "تعارضات الدمج", - "description": "الملفات التالية بها تعارضات تحتاج إلى حل:", - "abort": "إلغاء الدمج", - "openMergeTool": "فتح أداة الدمج", - "completeMerge": "إتمام الدمج", - "abortSuccess": "تم إلغاء الدمج بنجاح", - "completeSuccess": "تم إتمام الدمج بنجاح" - }, - "stashDialog": { - "title": "تخبئة التغييرات", - "description": "حفظ التغييرات الحالية في المخبأ", - "messageLabel": "رسالة", - "messagePlaceholder": "رسالة التخبئة (اختياري)", - "keepIndex": "الاحتفاظ بالفهرس (التغييرات المرحلة تبقى مرحلة)", - "cancel": "إلغاء", - "stash": "تخبئة", - "success": "تم تخبئة التغييرات", - "error": "فشل في تخبئة التغييرات" - }, - "unstashDialog": { - "title": "تطبيق المخبأ", - "noStashes": "لا توجد تخبئات", - "selectFile": "اختر ملفاً لعرض الفرق", - "viewDiff": "عرض الفرق", - "original": "الأصلي", - "modified": "المعدل", - "apply": "تطبيق", - "drop": "حذف", - "applySuccess": "تم تطبيق التخبئة", - "dropSuccess": "تم حذف التخبئة", - "confirmApply": "تطبيق التخبئة {ref} على دليل العمل؟", - "cancel": "إلغاء" - }, - "deleteBranch": "حذف الفرع", - "deleteWorktree": "حذف worktree", - "deleteWorktreeAndBranch": "حذف worktree والفرع", - "searchPlaceholder": "البحث في الفروع والإجراءات", - "searchAriaLabel": "البحث في الفروع والإجراءات", - "branchListLabel": "الفروع والإجراءات", - "noMatches": "لا توجد نتائج" - }, - "commitDialog": { - "toasts": { - "commitCompleted": "اكتمل التزام الكود", - "pushFailed": "فشل الدفع", - "committedFiles": "{count, plural, one {# ملف تم الالتزام به} other {# ملفات تم الالتزام بها}}", - "addedToVcs": "تمت الإضافة إلى VCS", - "addToVcsFailed": "فشلت الإضافة إلى VCS", - "fileDeleted": "تم حذف الملف", - "deleteFailed": "فشل الحذف", - "fileRolledBack": "تم التراجع عن الملف", - "rollbackFailed": "فشل التراجع", - "dirRolledBack": "تم استعادة المجلد", - "dirDeleted": "تم حذف المجلد" - }, - "confirm": { - "deleteTitle": "تأكيد الحذف", - "deleteDescription": "حذف الملف \"{file}\"؟ لا يمكن التراجع عن هذا الإجراء.", - "rollbackTitle": "تأكيد التراجع", - "rollbackDescription": "التراجع عن الملف \"{file}\" إلى HEAD؟ ستفقد التغييرات غير المحفوظة.", - "rollbackDirDescription": "هل تريد استعادة المجلد \"{dir}\" إلى HEAD؟ ستفقد التغييرات غير المحفوظة.", - "deleteDirDescription": "هل تريد حذف المجلد \"{dir}\"؟ لا يمكن التراجع عن هذا الإجراء." - }, - "actions": { - "select": "تحديد", - "unselect": "إلغاء التحديد", - "rollback": "تراجع", - "addToVcs": "إضافة إلى VCS" - }, - "aria": { - "selectFile": "{action}: {path}", - "unselectAllFiles": "إلغاء تحديد كل الملفات", - "selectAllFiles": "تحديد كل الملفات", - "unselectTracked": "إلغاء تحديد التغييرات المتعقبة", - "selectTracked": "تحديد التغييرات المتعقبة", - "unselectUntracked": "إلغاء تحديد الملفات غير المتعقبة", - "selectUntracked": "تحديد الملفات غير المتعقبة" - }, - "loading": "جارٍ التحميل...", - "selectionCount": "{selected} / {total} ملفات", - "emptyFiles": "لا توجد ملفات متغيرة", - "trackedChanges": "التغييرات المتعقبة ({count})", - "untrackedFiles": "الملفات غير المتعقبة ({count})", - "commitMessage": "رسالة الالتزام", - "commitMessagePlaceholder": "أدخل رسالة الالتزام...", - "commitButton": "التزام ({count})", - "commitAndPushButton": "إيداع ودفع ({count})", - "head": "HEAD", - "workingTree": "شجرة العمل", - "clickFileToDiff": "انقر اسم الملف لعرض الفرق", - "loadingDiff": "جارٍ تحميل diff..." - }, - "pushWindow": { - "title": "دفع الكود", - "noUnpushedCommits": "لا توجد التزامات غير مدفوعة", - "noRemoteConfigured": "لم يتم تكوين مستودع Git بعيد\nأضف واحدًا في «إدارة المستودعات البعيدة»", - "newBranchNoPushedCommits": "فرع جديد — ادفع لإنشاء فرع تتبع عن بُعد", - "unpushed": "غير مدفوع", - "selectFileToViewDiff": "اختر ملفًا لعرض الفرق", - "before": "قبل", - "after": "بعد", - "push": "دفع", - "toasts": { - "pushSuccess": "تم الدفع بنجاح", - "pushFailed": "فشل الدفع", - "upstreamSet": "تم تعيين الفرع البعيد", - "upstreamSetAndPushed": "تم تعيين الفرع البعيد ودفع {count} التزام", - "noCommitsToPush": "لا توجد التزامات للدفع", - "pushedCommits": "تم دفع {count} التزام" - } - }, - "gitLogTab": { - "filesTitle": "الملفات", - "expandAllFiles": "توسيع كل الملفات", - "collapseAllFiles": "طي كل الملفات", - "workspace": "مساحة العمل", - "retry": "إعادة المحاولة", - "noCommitsFound": "لم يتم العثور على التزامات", - "notAGitRepoTitle": "ليس مستودع Git", - "notAGitRepoHint": "قم بتهيئة Git من قائمة الفروع أعلاه، أو افتح مستودعًا موجودًا.", - "hash": "بصمة الالتزام", - "copyHash": "نسخ الـ hash", - "copyMessage": "نسخ الرسالة", - "showMore": "عرض المزيد", - "showLess": "طي", - "author": "المؤلف", - "noFileChangeDetails": "لا توجد تفاصيل تغييرات ملفات متاحة.", - "loadingFiles": "جارٍ تحميل الملفات...", - "branchesTitle": "الفروع", - "loadingBranches": "جارٍ تحميل الفروع...", - "noContainingBranches": "لم يتم العثور على فروع تحتوي هذا الالتزام.", - "newBranch": "فرع جديد...", - "resetToHere": "إعادة الضبط إلى هنا", - "resetDisabledReasonNotCurrentBranchView": "متاح فقط عند عرض الفرع الحالي", - "copyFullCommitHashAria": "نسخ hash الكامل للالتزام {hash}", - "pushStatus": { - "pushed": "تم الدفع إلى البعيد", - "notPushed": "لم يتم الدفع إلى البعيد", - "unknown": "حالة الدفع غير معروفة (لم يتم إعداد upstream)" - }, - "time": { - "monthsAgo": "{count, plural, one {منذ # شهر} other {منذ # أشهر}}", - "daysAgo": "{count, plural, one {منذ # يوم} other {منذ # أيام}}", - "hoursAgo": "{count, plural, one {منذ # ساعة} other {منذ # ساعات}}", - "minsAgo": "{count, plural, one {منذ # دقيقة} other {منذ # دقائق}}", - "justNow": "الآن" - }, - "toasts": { - "createdAndSwitchedNewBranch": "تم إنشاء فرع جديد والتبديل إليه", - "newBranchFromCommit": "{name} (من {shortHash})", - "createBranchFailed": "فشل إنشاء الفرع", - "openPushWindowFailed": "فشل فتح نافذة الدفع", - "resetSuccess": "تمت إعادة الضبط بنجاح", - "resetSuccessDescription": "تمت إعادة ضبط {branch} إلى {shortHash} باستخدام {mode}", - "resetFailed": "فشلت إعادة الضبط" - }, - "authorFilter": { - "label": "المؤلف", - "searchPlaceholder": "بحث عن مؤلف", - "noAuthors": "لم يتم العثور على مؤلفين", - "you": "أنت", - "filterByAuthorAria": "تصفية الإيداعات حسب المؤلف", - "filterByQuery": "تصفية حسب \"{query}\"", - "clearAuthorFilterAria": "مسح تصفية المؤلف", - "recent": "الأخيرة", - "matchingAuthors": "المؤلفون المطابقون", - "removeFromRecent": "إزالة {name} من الأخيرة" - }, - "branchSelector": { - "label": "الفرع", - "head": "HEAD", - "headHint": "يتبع الفرع الحالي", - "headHintWithBranch": "يتبع الفرع الحالي ({branch})", - "searchBranch": "بحث عن فرع...", - "noBranches": "لا توجد فروع", - "selectBranchPlaceholder": "اختر فرعًا...", - "localBranches": "الفروع المحلية", - "current": "الحالي", - "remoteBranches": "الفروع البعيدة", - "refreshCommitHistory": "تحديث سجل الالتزامات", - "clearBranchFilterAria": "مسح تصفية الفرع" - }, - "dialogs": { - "newBranchTitle": "فرع جديد", - "newBranchDescription": "إنشاء فرع جديد مع الالتزام {shortHash} كأحدث التزام.", - "branchNamePlaceholder": "اسم الفرع", - "reset": { - "title": "إعادة ضبط الفرع الحالي إلى هذا الالتزام", - "branchLabel": "الفرع", - "targetLabel": "الالتزام الهدف", - "messageLabel": "الرسالة", - "modeLabel": "وضع إعادة الضبط", - "confirmButton": "إعادة الضبط", - "modes": { - "soft": { - "label": "--soft", - "description": "ينقل HEAD ومؤشر الفرع الحالي إلى الالتزام الهدف.\nيبقي Index و Working Tree بدون تغيير.\nتظل تغييرات الالتزامات التي تمت إزالتها في حالة staged." - }, - "mixed": { - "label": "--mixed (الافتراضي)", - "description": "ينقل HEAD إلى الالتزام الهدف.\nيعيد ضبط Index إلى الالتزام الهدف مع الإبقاء على تغييرات Working Tree.\nتتحول التغييرات من staged إلى unstaged." - }, - "hard": { - "label": "--hard", - "description": "ينقل HEAD ويعيد ضبط كل من Index و Working Tree إلى الالتزام الهدف.\nسيتم حذف التغييرات المحلية المتتبعة بعد الالتزام الهدف.\nهذه عملية تدميرية." - }, - "keep": { - "label": "--keep", - "description": "ينقل HEAD إلى الالتزام الهدف مع محاولة الاحتفاظ بالتغييرات المحلية.\nيتم الاحتفاظ فقط بالتغييرات غير المتعارضة.\nعند وجود تعارض، يتم إيقاف العملية لحماية عملك." - } - } - } - }, - "moreActions": "إجراءات Git إضافية" - }, - "gitChangesTab": { - "workspace": "مساحة العمل", - "noChanges": "لا توجد تغييرات محلية", - "notAGitRepoTitle": "ليس مستودع Git", - "notAGitRepoHint": "قم بتهيئة Git من قائمة الفروع أعلاه، أو افتح مستودعًا موجودًا.", - "trackedChanges": "التغييرات المتعقبة ({count})", - "untrackedFiles": "الملفات غير المتعقبة ({count})", - "expandTracked": "توسيع التغييرات المتعقبة", - "collapseTracked": "طي التغييرات المتعقبة", - "expandUntracked": "توسيع الملفات غير المتعقبة", - "collapseUntracked": "طي الملفات غير المتعقبة", - "showRemainingItems": "عرض {count} عنصر إضافي", - "actions": { - "commitCode": "التزام الكود", - "rollback": "تراجع", - "addToVcs": "إضافة إلى VCS", - "delete": "حذف", - "moreActions": "إجراءات Git إضافية", - "addAllToVcs": "إضافة الكل إلى VCS", - "rollbackAll": "تراجع عن الكل", - "refresh": "تحديث" - }, - "toasts": { - "noAddableFilesInDir": "لا توجد ملفات متغيرة في هذا الدليل يمكن إضافتها إلى VCS", - "noRollbackFilesInDir": "لا توجد ملفات متغيرة في هذا الدليل يمكن التراجع عنها", - "addedToVcs": "تمت إضافة {name} إلى VCS", - "addToVcsFailed": "فشلت الإضافة إلى VCS", - "openCommitWindowFailed": "فشل فتح نافذة الالتزام", - "rolledBack": "تم التراجع عن {name}", - "rollbackFailed": "فشل التراجع", - "addedFilesToVcs": "تمت إضافة {count, plural, one {# ملف} other {# ملفات}} إلى VCS", - "rolledBackFiles": "تم التراجع عن {count, plural, one {# ملف} other {# ملفات}}", - "deleted": "تم حذف {name}", - "deleteFailed": "فشل الحذف", - "deletedFiles": "تم حذف {count} ملفات", - "noDeletableFilesInDir": "لا توجد ملفات معدّلة في هذا الدليل يمكن حذفها", - "commitFailed": "فشل الالتزام" - }, - "directoryDialog": { - "descriptionAdd": "اختر ملفات داخل الدليل {path} لإضافتها إلى VCS.", - "descriptionRollback": "اختر ملفات داخل الدليل {path} للتراجع عنها.", - "descriptionDelete": "اختر ملفات داخل الدليل {path} لحذفها. لا يمكن التراجع عن هذا الإجراء.", - "descriptionFallback": "اختر ملفات للمتابعة.", - "selectionCount": "تم تحديد {selected} / {total} ملف", - "selectAll": "تحديد الكل", - "unselectAll": "إلغاء تحديد الكل", - "loadingCandidates": "جارٍ تحميل تغييرات الدليل...", - "noOperableFiles": "لا توجد ملفات قابلة للتشغيل" - }, - "rollbackConfirm": { - "title": "تأكيد التراجع", - "descriptionWithTarget": "التراجع عن التغييرات المحلية لـ {kind} \"{name}\"؟", - "descriptionFallback": "التراجع عن التغييرات المحلية؟", - "kindDirectory": "الدليل", - "kindFile": "الملف" - }, - "deleteConfirm": { - "title": "تأكيد الحذف", - "descriptionWithTarget": "حذف {kind} \"{name}\"؟ لا يمكن التراجع عن هذا الإجراء.", - "descriptionFallback": "لا يمكن التراجع عن هذا الإجراء.", - "kindDirectory": "الدليل", - "kindFile": "الملف" - }, - "quickCommit": { - "placeholder": "رسالة الالتزام (اضغط Enter للالتزام)" - } - }, - "tabContext": { - "loadingConversation": "جارٍ التحميل...", - "untitledConversation": "محادثة بدون عنوان", - "newConversation": "محادثة جديدة" - }, - "fileTreeTab": { - "workspace": "مساحة العمل", - "retry": "إعادة المحاولة", - "git": "Git", - "openInFileManager": "فتح في مدير الملفات", - "openInFinder": "فتح في Finder", - "openInExplorer": "فتح في Explorer", - "attachToCurrentSession": "إضافة إلى الجلسة", - "compareWithBranch": "المقارنة مع الفرع...", - "reloadFromDisk": "إعادة التحميل من القرص", - "new": "جديد", - "newFile": "ملف", - "newDirectory": "مجلد", - "openIn": "فتح في", - "openInTerminal": "فتح في الطرفية", - "linkedFolder": "مجلد مرتبط", - "copyPath": "نسخ المسار", - "upload": "رفع ملفات/مجلد", - "download": "تنزيل ملف", - "downloadAsZip": "تنزيل كملف ZIP", - "actions": { - "select": "تحديد", - "unselect": "إلغاء التحديد", - "commitCode": "تنفيذ الالتزام بالكود", - "rollback": "التراجع", - "addToVcs": "إضافة إلى VCS" - }, - "aria": { - "selectPath": "{action}: {path}" - }, - "toasts": { - "openDirectoryFailed": "فشل فتح المجلد", - "openBuiltinTerminalFailed": "تعذر فتح الطرفية المدمجة", - "openCommitWindowFailed": "فشل فتح نافذة الالتزام", - "noAddableFilesInDir": "لا توجد ملفات متغيرة في هذا المجلد يمكن إضافتها إلى VCS", - "noRollbackFilesInDir": "لا توجد ملفات متغيرة في هذا المجلد يمكن التراجع عنها", - "addedToVcs": "تمت إضافة {name} إلى VCS", - "addToVcsFailed": "فشلت الإضافة إلى VCS", - "loadBranchesFailed": "فشل تحميل الفروع", - "renameFailed": "فشل إعادة التسمية", - "moveFailed": "فشل النقل", - "deleteFailed": "فشل الحذف", - "rolledBack": "تم التراجع عن {name}", - "rollbackFailed": "فشل التراجع", - "addedFilesToVcs": "{count, plural, one {تمت إضافة ملف واحد إلى VCS} other {تمت إضافة # ملفات إلى VCS}}", - "rolledBackFiles": "{count, plural, one {تم التراجع عن ملف واحد} other {تم التراجع عن # ملفات}}", - "savedAsCopy": "تم الحفظ كنسخة", - "saveCopyFailed": "فشل الحفظ كنسخة", - "watchStartFailed": "فشل بدء مراقبة الملفات", - "createFailed": "فشل في الإنشاء", - "downloadFailed": "فشل تنزيل {name}", - "downloadSaved": "تم تنزيل {name}", - "pathCopied": "تم نسخ المسار", - "copyPathFailed": "فشل نسخ المسار" - }, - "createDialog": { - "newFile": "ملف جديد", - "newDirectory": "مجلد جديد", - "description": "أدخل اسمًا لـ{kind} الجديد.", - "placeholderFile": "file-name.ext", - "placeholderDirectory": "folder-name" - }, - "renameDialog": { - "renameDirectory": "إعادة تسمية المجلد", - "renameFile": "إعادة تسمية الملف", - "description": "أدخل اسمًا جديدًا (الاسم فقط، بدون مسار).", - "placeholderDirectory": "اسم-مجلد-جديد", - "placeholderFile": "اسم-ملف-جديد.ext" - }, - "uploadDialog": { - "title": "رفع إلى مساحة العمل", - "description": "اضبط الوجهة عند الحاجة، ثم أضف الملفات أو المجلدات.", - "workspaceRoot": "جذر مساحة العمل", - "targetPathLabel": "رفع إلى", - "targetPathHint": "المسار النهائي: {path}", - "dropHint": "اسحب الملفات أو المجلدات هنا، أو استخدم الأزرار أدناه", - "dropHintActive": "حرّر للإضافة إلى قائمة الانتظار", - "selectFiles": "اختيار ملفات", - "selectFolder": "اختيار مجلد", - "startUpload": "بدء الرفع", - "clearQueue": "مسح المنتهية", - "removeItem": "إزالة من قائمة الانتظار", - "retry": "إعادة المحاولة", - "dropZoneAria": "أفلت الملفات هنا أو نشّط للاستعراض", - "folderEmpty": "لم يتم العثور على ملفات في المجلد المسحوب", - "summary": "الإجمالي: {total} · نجح: {succeeded} · فشل: {failed}", - "status": { - "pending": "قيد الانتظار", - "uploading": "جاري الرفع", - "success": "تم", - "error": "فشل", - "cancelled": "ملغى" - } - }, - "directoryDialog": { - "descriptionAdd": "حدد الملفات ضمن المجلد {path} لإضافتها إلى VCS.", - "descriptionRollback": "حدد الملفات ضمن المجلد {path} للتراجع عنها.", - "descriptionFallback": "حدد الملفات للمتابعة.", - "selectionCount": "تم تحديد {selected} من {total} ملف", - "selectAll": "تحديد الكل", - "unselectAll": "إلغاء تحديد الكل", - "loadingCandidates": "جارٍ تحميل تغييرات المجلد...", - "noOperableFiles": "لا توجد ملفات قابلة للمعالجة" - }, - "compareDialog": { - "title": "المقارنة مع الفرع", - "descriptionWithTarget": "حدد فرعًا وقارن مع {kind} {path}", - "descriptionFallback": "حدد فرعًا للمقارنة.", - "kindDirectory": "مجلد", - "kindFile": "ملف", - "filterPlaceholder": "تصفية الفروع، مثال: main / origin/main", - "singleClickHint": "انقر على فرع للمقارنة مباشرة", - "loadingBranches": "جارٍ تحميل الفروع...", - "recentBranches": "الفروع الحديثة ({count})", - "noCurrentBranch": "لا يوجد فرع حالي", - "localBranches": "الفروع المحلية ({count})", - "remoteBranches": "الفروع البعيدة ({count})", - "noMatchingBranches": "لا توجد فروع مطابقة" - }, - "externalConflictDialog": { - "title": "تم اكتشاف تغييرات خارجية في الملفات", - "descriptionWithPath": "تم تغيير الملف {path} على القرص، والتعديلات الحالية غير محفوظة.", - "descriptionFallback": "تم تغيير الملف الحالي على القرص، والتعديلات الحالية غير محفوظة.", - "compare": "مقارنة", - "savingCopy": "جارٍ حفظ نسخة...", - "saveAsCopy": "حفظ كنسخة", - "reload": "إعادة التحميل" - }, - "deleteConfirm": { - "title": "تأكيد الحذف", - "descriptionWithTarget": "حذف {kind} \"{name}\"؟ لا يمكن التراجع عن هذا الإجراء.", - "descriptionFallback": "لا يمكن التراجع عن هذا الإجراء.", - "kindDirectory": "مجلد", - "kindFile": "ملف" - }, - "rollbackConfirm": { - "title": "تأكيد التراجع", - "descriptionWithTarget": "التراجع عن التغييرات المحلية للملف \"{name}\"؟", - "descriptionFallback": "التراجع عن التغييرات المحلية لهذا الملف؟" - }, - "terminalTitle": "الطرفية · {name}" - }, - "commandDropdown": { - "loading": "جارٍ التحميل...", - "addCommand": "إضافة أمر", - "manageCommands": "إدارة الأوامر...", - "runCommandTitle": "تشغيل: {command}", - "stopCommandTitle": "إيقاف: {command}", - "manageDialog": { - "title": "إدارة الأوامر", - "empty": "لا توجد أوامر بعد", - "noResults": "لا توجد أوامر مطابقة", - "searchPlaceholder": "البحث في الأوامر", - "newCommand": "أمر جديد", - "nameLabel": "الاسم", - "commandLabel": "الأمر", - "dragSort": "اسحب للترتيب", - "dragSortCommand": "اسحب لترتيب {name}", - "orderFailed": "فشل حفظ ترتيب الأوامر", - "loadFailed": "فشل تحميل الأوامر", - "saveFailed": "فشل حفظ الأمر", - "deleteFailed": "فشل حذف الأمر", - "confirmDelete": { - "title": "حذف الأمر؟", - "message": "سيؤدي هذا إلى إزالة \"{name}\". لا يمكن التراجع عن هذا الإجراء." - } - } - }, - "workspaceContext": { - "confirmCloseDirtyTab": "إغلاق \"{title}\" بدون حفظ؟", - "confirmCloseOtherDirtyTabs": "إغلاق التبويبات الأخرى التي تحتوي تغييرات غير محفوظة؟", - "confirmCloseAllDirtyTabs": "إغلاق جميع التبويبات التي تحتوي تغييرات غير محفوظة؟", - "unableLoadContent": "تعذر تحميل المحتوى.\n\n{message}", - "previewRequestTimedOut": "انتهت مهلة طلب المعاينة", - "diffRequestTimedOut": "انتهت مهلة طلب Diff", - "branchCompareRequestTimedOut": "انتهت مهلة طلب مقارنة الفروع", - "commitDiffRequestTimedOut": "انتهت مهلة طلب Diff للالتزام", - "saveRequestTimedOut": "انتهت مهلة طلب الحفظ", - "reloadRequestTimedOut": "انتهت مهلة طلب إعادة التحميل", - "noChanges": "لا توجد تغييرات.", - "noDiffOutput": "لا يوجد مخرجات diff.", - "diffTitleWorkspace": "Diff · مساحة العمل", - "diffDescriptionWorkingTree": "شجرة العمل (HEAD)", - "diffTitleFile": "الفرق · {name}", - "compareTitleFile": "مقارنة · {name}", - "compareTitleBranch": "مقارنة · {branch}", - "compareDescriptionPath": "{path} · مقارنة مع {branch}", - "compareDescriptionBranch": "مقارنة مع {branch}", - "diffTitleCommitFile": "الفرق · {name} @ {hash}", - "diffTitleCommit": "الفرق · {hash}", - "diffDescriptionCommitPath": "{path} · الالتزام {commit}", - "diffDescriptionCommit": "الالتزام {commit}", - "diffTitleConflictFile": "تعارض · {name}", - "diffDescriptionConflict": "{path} · القرص مقابل غير المحفوظ" - }, - "chat": { - "acpConnections": { - "actions": { - "openAgentsSettings": "فتح إعدادات الوكلاء", - "retry": "إعادة المحاولة" - }, - "agentsSetupHint": "افتح الإعدادات > الوكلاء لإدارة التثبيت.", - "withSetupHint": "{message}\n{hint}", - "blocked": { - "missingConfig": "تعذر قراءة إعدادات الوكيل الحالية.", - "disabled": "{agent} معطّل في إعدادات الوكلاء. قم بتمكينه قبل الاتصال.", - "unavailable": "{agent} غير متاح على المنصة الحالية.", - "sdkMissing": "لم يتم تثبيت SDK الخاص بـ {agent}", - "adapterMissing": "محوّل ACP الخاص بـ {agent} غير مثبّت" - }, - "backendErrors": { - "initializeTimeout": "انتهت مهلة مصافحة اتصال {agent} (لا استجابة بعد 60 ثانية). افتح الإعدادات للتحقق من إعدادات الوكيل والشبكة.", - "mcpRejectedByAgent": "رفض {agent} الجلسة أثناء إرفاق رفيق MCP الخاص بـ codeg: {message} إن كان هذا الوكيل لا يدعم MCP، فأوقف «دعم MCP» من الإعدادات ثم أعد الاتصال.", - "processExited": "انتهت عملية {agent} بشكل غير متوقع.", - "spawnFailed": "تعذر بدء تشغيل {agent}: {message}", - "downloadFailed": "فشل تنزيل {agent}: {message}", - "sessionLoadResourceNotFound": "فشل تحميل جلسة {agent}. أعد التحميل لإعادة المحاولة، أو ابدأ محادثة جديدة.", - "sessionLoadUnavailable": "تعذّر على {agent} استعادة هذه الجلسة، فقد تكون انتهت أو توقّف الوكيل. أعد التحميل لإعادة المحاولة، أو ابدأ محادثة جديدة.", - "turnFailedRefusal": "رفض {agent} متابعة هذه الجولة. يدل ذلك غالبًا على خطأ في الخلفية أو البوابة. يرجى مراجعة سجلات الوكيل.", - "turnFailedMaxTokens": "بلغ {agent} الحد الأقصى للرموز المسموح بها في هذه الجولة.", - "turnFailedMaxTurnRequests": "بلغ {agent} الحد الأقصى لعدد الطلبات المسموح بها في هذه الجولة.", - "turnFailedUnknown": "أنهى {agent} الجولة بسبب توقف غير معروف.", - "grokModelSwitchIncompatibleAgent": "لا يمكن لـ {agent} التبديل إلى هذا النموذج في محادثة قائمة. ابدأ جلسة جديدة لاستخدامه.", - "turnFailedEmpty": "أنهى {agent} الجولة دون إنتاج أي رد.", - "turnFailedEmptyProtocol": "أنتج {agent} مخرجات تعذّر على codeg تحليلها — قد لا يتوافق إصدار الوكيل مع البروتوكول.", - "turnFailedEmptyMetadata": "أرسل {agent} تحديثات حالة فقط في هذه الجولة (الخطة / الوضع / الاستخدام) دون أي رد.", - "detailsInAlerts": "افتح التنبيهات في شريط الحالة ووسّع التفاصيل لعرض مخرجات الوكيل." - }, - "unableReadAgentConfig": "تعذر قراءة إعدادات الوكيل: {message}", - "connectFailedTitle": "فشل اتصال {agent}", - "toolFallbackTitle": "أداة", - "eventErrorTitle": "خطأ الوكيل", - "notificationTurnComplete": "{agent} أنهى الاستجابة", - "notificationError": "{agent} خطأ: {message}", - "claudeApiRetry": { - "fallbackError": "authentication_failed", - "retryingWithMax": "إعادة المحاولة {attempt}/{max}", - "retryingAttempt": "إعادة المحاولة رقم {attempt}", - "retrying": "جاري إعادة المحاولة", - "nextRetryIn": "المحاولة التالية خلال {seconds}ث", - "line": "{error}{status} · {retry}", - "lineWithDelay": "{error}{status} · {retry}، {delay}", - "httpStatus": " (HTTP {status})" - }, - "configOptionAdjusted": "ضبط {agent} {option} على {actual} بدلاً من {requested}" - }, - "connectionLifecycle": { - "tasks": { - "connectingTitle": "جارٍ الاتصال بـ {agent}", - "connectingDescription": "جارٍ إنشاء الاتصال", - "loadingSelectorsTitle": "جارٍ تحميل محددات {agent}", - "loadingSelectorsDescription": "جارٍ جلب خيارات الوضع وإعدادات الجلسة", - "initSessionTitle": "جارٍ تهيئة جلسة {agent}", - "initSessionDescription": "جارٍ إنشاء الجلسة وتحميل الإعدادات" - }, - "errors": { - "connectionFailed": "فشل الاتصال", - "sendPromptFailed": "فشل إرسال الرسالة: {error}" - } - }, - "shared": { - "attachedResources": "الموارد المرفقة", - "toolCallFailed": "فشل استدعاء الأداة" - }, - "messageThread": { - "emptyTitle": "لا توجد رسائل بعد", - "emptyDescription": "ابدأ محادثة لرؤية الرسائل هنا" - }, - "chatInput": { - "connecting": "جارٍ الاتصال...", - "agentResponding": "{agent} يرد...", - "sendMessage": "أرسل رسالة..." - }, - "messageInput": { - "askAnything": "اسأل أي شيء...", - "removeAttachmentAria": "إزالة {name}", - "attachFiles": "إرفاق ملفات", - "addActions": "إضافة", - "quickMessages": "الرسائل السريعة", - "quickMessagesEmpty": "لا توجد رسائل سريعة بعد", - "quickMessagesLoading": "جارٍ التحميل...", - "pasteAsPlainText": "لصق كنص عادي", - "cut": "قص", - "copy": "نسخ", - "selectAll": "تحديد الكل", - "pasteUnavailable": "تعذّر قراءة الحافظة. استخدم Ctrl/⌘V للصق.", - "clipboardWriteFailed": "تعذّرت الكتابة إلى الحافظة. استخدم اختصار لوحة المفاتيح.", - "quickMessageUntitled": "بدون عنوان", - "liveFeedback": "ملاحظات مباشرة", - "liveFeedbackDisabledHint": "متاح أثناء عمل الوكيل", - "dropFilesToAttach": "أسقط الملفات لإرفاقها", - "loadingSettings": "جارٍ تحميل الإعدادات...", - "loadingMode": "جارٍ تحميل الوضع...", - "modeLabel": "الوضع", - "toggleOn": "تشغيل", - "toggleOff": "إيقاف", - "agentSettings": "إعدادات الوكيل", - "searchModel": "البحث عن النماذج...", - "searchModelAria": "البحث عن النماذج", - "modelListLabel": "النماذج", - "noModels": "لم يتم العثور على نماذج", - "cancel": "إلغاء", - "send": "إرسال", - "forkAndSend": "تفريع وإرسال", - "queueMessage": "إضافة إلى قائمة الانتظار", - "steerIntoTurn": "إدراج في الدور الحالي", - "steerQueuedInstead": "أُضيفت إلى قائمة الانتظار — ستُرسل مع الدور التالي.", - "steerFailed": "تعذّر الإدراج في الدور الحالي", - "steerAttachmentsUnsupported": "نص فقط — المسودات التي تحتوي على مرفقات تمر عبر قائمة الانتظار.", - "slashCommands": "أوامر الشرطة المائلة", - "slashSearchPlaceholder": "البحث عن الأوامر...", - "slashSearchEmpty": "لا توجد أوامر مطابقة", - "experts": "الخبراء", - "office": "الأعمال المكتبية", - "research": "البحث العلمي", - "attachLocalUpload": "تحميل ملف محلي", - "attachServerFile": "اختيار ملف من الخادم", - "attachUploadTooLarge": "{names} يتجاوز حد التحميل {limit}MB وتم تخطيه.", - "attachUploadFailed": "فشل تحميل {names}.", - "attachUploadNotAFile": "{names} ليس ملفاً عادياً (مجلد أو ملف خاص) وتم تخطيه.", - "attachUploadQuotaExceeded": "نفدت مساحة التحميل على الخادم، تعذر رفع {names}.", - "attachUploadInProgress": "لا تزال الصور قيد الرفع — حاول مرة أخرى بعد قليل.", - "mentionEmpty": "لا توجد نتائج مطابقة", - "mentionLoading": "جارٍ البحث…", - "mentionListLabel": "الإشارات", - "mentionMore": "مزيد من النتائج — تابع الكتابة للتصفية", - "mentionCount": "{count, plural, zero {لا نتائج} one {نتيجة واحدة} two {نتيجتان} few {# نتائج} many {# نتيجة} other {# نتيجة}}", - "mentionGroupFile": "الملفات", - "mentionGroupAgent": "الوكلاء", - "mentionGroupSession": "الجلسات", - "mentionGroupCommit": "عمليات الإيداع", - "mentionGroupSkill": "المهارات" - }, - "messageQueue": { - "addToQueue": "إضافة للقائمة", - "saveEdit": "حفظ", - "cancelEdit": "إلغاء التعديل", - "editItem": "تعديل", - "deleteItem": "حذف" - }, - "welcomeInputPanel": { - "agentsSettingsPath": "الإعدادات > الوكلاء", - "autoConnectFallback": "انقر لفتح {path} وإدارة التثبيت.", - "autoConnectAppend": "{message}. انقر لفتح {path} وإدارة التثبيت.", - "enableAgentFirstPlaceholder": "فعّل وكيلًا واحدًا على الأقل قبل بدء جلسة...", - "prepareSessionFailed": "تعذّر تحضير جلسة الدردشة. يرجى المحاولة مرة أخرى.", - "createConversationFailed": "تعذّر إنشاء المحادثة. يرجى المحاولة مرة أخرى.", - "askAnythingPlaceholder": "اسأل أي شيء...", - "agentNotInstalled": "{agent} غير مثبّت · افتح إعدادات Agents لتثبيته", - "agentAdapterNotInstalled": "محوّل ACP الخاص بـ {agent} غير مثبّت (وهو منفصل عن واجهة الأوامر لديك) · افتح إعدادات Agents لتثبيته" - }, - "welcomePanel": { - "greeting": "ماذا تودّ أن تفعل اليوم؟", - "tips": { - "tileTabs": "انقر بزر الفأرة الأيمن على تبويب محادثة واختر «عرض متجانب» لمقارنة عدة جلسات جنبًا إلى جنب.", - "pinTab": "انقر نقرًا مزدوجًا على تبويب محادثة لتثبيته كي لا تستبدله جلسة جديدة تلقائيًا.", - "shortcutsNewSearch": "{newConversation} يفتح محادثة جديدة، و{searchConversations} يبحث في السجل.", - "slashAtMention": "اكتب / في حقل الإدخال لتشغيل أوامر السلاش، أو @ للإشارة إلى ملف من المشروع.", - "pasteDropFiles": "ألصق لقطة شاشة أو اسحب ملفًا مباشرة إلى حقل الإدخال لإرفاقه.", - "queueMessage": "أثناء رد الوكيل، تابع الكتابة — ستوضع رسالتك التالية في الطابور وتُرسل تلقائيًا عند انتهائه.", - "draftAutoSave": "تُحفظ المسودات غير المُرسلة تلقائيًا لكل محادثة وتُستعاد عند العودة.", - "forkSend": "تتضمن قائمة زر الإرسال المنسدلة «تفرّع وأرسل» لإنشاء فرع من النقطة الحالية في تبويب جديد.", - "exportConversation": "انقر بزر الفأرة الأيمن داخل المحادثة لتصديرها بصيغة Markdown أو HTML أو صورة.", - "chatChannels": "اربط Telegram / Lark / WeChat من «الإعدادات → قنوات الدردشة» للمتابعة من هاتفك.", - "shortcutsAuxPanel": "{toggleAuxPanel} يبدّل اللوحة اليمنى لعرض الملفات المعدّلة وتغييرات Git لهذه الجلسة.", - "shortcutsTerminalSidebar": "{toggleTerminal} يفتح الطرفية المدمجة، و{toggleSidebar} يبدّل الشريط الجانبي.", - "customShortcuts": "يمكن إعادة تعيين جميع الاختصارات من «الإعدادات → الاختصارات».", - "webService": "فعّل «الإعدادات → خدمة الويب» ليتمكن أعضاء الفريق من الوصول إلى نفس codeg عبر المتصفح.", - "fusionMode": "افتح ملفًا أو فرقًا لعرضه تلقائيًا بجوار المحادثة.", - "quickMessages": "افتح زر + بجانب الإدخال واختر «الرسائل السريعة» لإدراج مقتطف محفوظ (تُدار من «الإعدادات → الرسائل السريعة»).", - "experts": "يحتوي زر + على قائمة «مهارات الخبراء» — حمّل أدوارًا مثل التصحيح أو التخطيط بنقرة واحدة.", - "taskBoard": "تنفّذ المهام قيد الانتظار عملاً كاملاً من البداية إلى النهاية: يعمل الوكيل في worktree خاص به، ثم تراجع الفروق وتدمجها.", - "automations": "تشغّل الأتمتة موجّهًا محفوظًا وفق جدول زمني — مراجعة ليلية أو تقريرًا دوريًا — ويمكن أن يحصل كل تشغيل على worktree خاص به.", - "tokenUsage": "انقر على عدد المحادثات في شريط الحالة لفتح استهلاك الرموز، موزّعًا حسب اليوم والوكيل والنموذج والمجلد.", - "mentionTargets": "لا تقتصر @ على الملفات: اذكر وكيلًا آخر لتفويض مهمة فرعية، أو أشِر إلى جلسة سابقة أو التزام أو مهارة.", - "splitGroups": "انقر بزر الفأرة الأيمن على تبويب واختر «تقسيم لليمين» أو «تقسيم للأسفل» لإبقاء محادثتين في لوحين منفصلين.", - "worktrees": "افتح زر الفرع واختر «Worktree جديد» ليعمل عدة وكلاء على المستودع نفسه دون أن يستبدل أحدهم ملفات الآخر.", - "importSessions": "هل شغّلت جلسات في الطرفية من قبل؟ تحتوي قائمة المجلد على «استيراد الجلسات المحلية» لجلب ذلك السجل إلى codeg.", - "subSessions": "عندما يفوّض وكيل مهمة، تظهر الجلسة الفرعية متداخلة تحته في الشريط الجانبي — وسّع الصف لتتابع ما فعلته كل واحدة.", - "liveFeedback": "تُدرج «ملاحظات مباشرة» في قائمة + ملاحظةً داخل الدور الذي ينفّذه الوكيل بالفعل، دون مقاطعته.", - "skillPacks": "تجمع الإعدادات ← حزم المهارات خبراء البرمجة والبحث العلمي ومهارات المكتب — فعّلها لكل وكيل على حدة.", - "modelProviders": "تقبل الإعدادات ← مزودو النماذج مفتاح API أو نقطة نهاية خاصة بك، ثم تختار النموذج مباشرة من حقل الإدخال.", - "workspaceBackground": "تحدّد الإعدادات ← المظهر صورة خلفية لمساحة العمل، وشفافية اللوحات، وخطوط التطبيق." - }, - "quickActions": { - "excel": "مصنّف Excel", - "excelDesc": "جداول بيانات وصيغ ومخططات", - "word": "مستند Word", - "wordDesc": "تقارير ورسائل ومذكرات", - "ppt": "عرض تقديمي", - "pptDesc": "شرائح بتصميم احترافي", - "pitchDeck": "عرض استثماري", - "pitchDeckDesc": "عرض تمويل بمؤشرات رئيسية", - "morph": "حركة Morph", - "morphDesc": "انتقالات شرائح سينمائية", - "morph3d": "Morph ثلاثي الأبعاد", - "morph3dDesc": "نماذج ثلاثية الأبعاد وحركات كاميرا", - "academic": "ورقة أكاديمية", - "academicDesc": "بحث باستشهادات وبنية", - "financial": "نموذج مالي", - "financialDesc": "قوائم وDCF وتوقعات", - "dashboard": "لوحة بيانات", - "dashboardDesc": "مؤشرات وتحليلات من بياناتك", - "prompts": { - "excel": "أنشئ مصنّف Excel وفق المتطلبات التالية:\n\n[صف هنا بياناتك وجداولك وصيغك ومخططاتك]", - "word": "أنشئ مستند Word وفق المتطلبات التالية:\n\n[صف هنا محتوى المستند وبنيته وتنسيقه]", - "ppt": "أنشئ عرض PowerPoint تقديمي وفق المتطلبات التالية:\n\n[صف هنا شرائحك ومحتواك وتصميمك]", - "pitchDeck": "أنشئ عرضًا استثماريًا لجمع التمويل وفق المتطلبات التالية:\n\n[صف هنا شركتك وجولة التمويل والمؤشرات الرئيسية]", - "morph": "أنشئ عرضًا تقديميًا بحركات انتقال Morph:\n\n[صف هنا موضوع العرض والمؤثرات المرئية المطلوبة]", - "morph3d": "أنشئ عرض Morph ثلاثي الأبعاد بنماذج GLB وحركات كاميرا:\n\n[صف هنا موضوعك ومفهومك المرئي ثلاثي الأبعاد]", - "academic": "اكتب ورقة أكاديمية في Word وفق المتطلبات التالية:\n\n[صف هنا موضوع بحثك ومنهجيتك وأبرز نتائجك]", - "financial": "أنشئ نموذجًا ماليًا في Excel وفق المتطلبات التالية:\n\n[صف هنا قوائمك المالية وتوقعاتك وتحليلاتك]", - "dashboard": "أنشئ لوحة بيانات في Excel وفق المتطلبات التالية:\n\n[صف هنا مصدر بياناتك ومؤشراتك ومخططاتك]", - "scientific-brainstorming": "ساعدني في توليد أفكار بحثية: استكشف الروابط متعددة التخصصات، وتحدَّ الافتراضات، واكشف الفجوات الواعدة. المجال الذي أستكشفه: ", - "hypothesis-generation": "ساعدني في تحويل هذه الملاحظات إلى فرضيات قابلة للاختبار، مع تنبؤات واضحة وآليات معقولة وتجارب لاختبارها. ملاحظاتي: ", - "experimental-design": "ساعدني في تصميم تجربة دقيقة قبل جمع البيانات: التصميم والعشوائية والضوابط وكيفية تجنّب الالتباس. ما أريد دراسته: ", - "statistical-power": "ساعدني في تحديد حجم العينة المطلوب: أرشدني خلال تحليل القوة الإحصائية (حجم الأثر، ألفا، القوة) لتصميمي. التفاصيل: ", - "statistical-analysis": "ساعدني في تحليل هذه البيانات بشكل صحيح: اختر الاختبار المناسب، وتحقق من الافتراضات، وأبلغ عن أحجام الأثر، واكتب النتائج. بياناتي وسؤالي: ", - "exploratory-data-analysis": "قم بتحليل استكشافي لملف بياناتي: لخّص بنيته وجودته والأنماط اللافتة، ثم اقترح الخطوات التالية. الملف هو: ", - "scientific-visualization": "ساعدني في إنشاء شكل بجودة النشر: تخطيط واضح، وأشرطة خطأ صادقة، ولوحة ألوان مناسبة لعمى الألوان، وتنسيق المجلة. ما أريد عرضه: ", - "scientific-critical-thinking": "ساعدني في التقييم النقدي لهذه الدراسة أو الادعاء: قيّم جودة الأدلة، وارصد التحيّزات والعوامل المربكة، وزِن الاستنتاجات. إليك المحتوى: ", - "paper-lookup": "ساعدني في العثور على أوراق ذات صلة ونص كامل مفتوح الوصول عبر قواعد البيانات الأكاديمية، مع استشهادات يمكنني إعادة استخدامها. أبحث عن: " - }, - "paper-lookup": "البحث عن الأوراق البحثية", - "paper-lookupDesc": "البحث في 10 واجهات برمجية أكاديمية (PubMed وarXiv وOpenAlex وCrossref…) عن الأوراق والاستشهادات والنص الكامل المفتوح.", - "scientific-critical-thinking": "التفكير النقدي", - "scientific-critical-thinkingDesc": "تقييم الادعاءات العلمية وجودة الأدلة: رصد التحيّزات والعوامل المربكة وتطبيق أطر GRADE ومخاطر التحيّز.", - "scientific-visualization": "التصور العلمي", - "scientific-visualizationDesc": "أشكال جاهزة للنشر: تخطيطات متعددة اللوحات، وتعليقات الدلالة الإحصائية، وتنسيق خاص بكل مجلة.", - "exploratory-data-analysis": "تحليل البيانات الاستكشافي", - "exploratory-data-analysisDesc": "استكشاف آلي لملفات البيانات العلمية بأكثر من 200 صيغة مع مقاييس الجودة والتقارير.", - "statistical-analysis": "التحليل الإحصائي", - "statistical-analysisDesc": "تحليل إحصائي موجَّه: اختيار الاختبار، والتحقق من الافتراضات، وأحجام الأثر، والتقارير بأسلوب APA.", - "statistical-power": "القوة الإحصائية", - "statistical-powerDesc": "تحليل حجم العينة والقوة الإحصائية: عدد المشاركين اللازم، وأصغر تأثير قابل للكشف، ومنحنيات القوة.", - "experimental-design": "تصميم التجارب", - "experimental-designDesc": "تصميم دراسات دقيقة قبل جمع البيانات: العشوائية والتجميع والضوابط وتصاميم العوامل/DOE.", - "hypothesis-generation": "توليد الفرضيات", - "hypothesis-generationDesc": "تحويل الملاحظات إلى فرضيات قابلة للاختبار مع تنبؤات وآليات وتجارب لاختبارها.", - "scientific-brainstorming": "العصف الذهني العلمي", - "scientific-brainstormingDesc": "توليد أفكار بحثية مفتوحة: استكشاف الروابط متعددة التخصصات وتحدّي الافتراضات وكشف الفجوات البحثية.", - "tabs": { - "office": "الأعمال المكتبية", - "coding": "تطوير الكود", - "research": "البحث العلمي" - }, - "coding": { - "brainstormingDesc": "استكشف النية والمتطلبات قبل البناء", - "debuggingDesc": "حدد السبب الجذري قبل اقتراح الإصلاحات", - "writingSkillsDesc": "أنشئ وحرّر وتحقق من مهارات قابلة لإعادة الاستخدام" - }, - "notEnabled": { - "title": "المهارة ”{skill}“ غير مُفعّلة بعد لـ {agent}", - "description": "فعّلها من الإعدادات لاستخدامها هنا.", - "action": "تفعيل", - "hint": "المهارة غير مُفعّلة" - }, - "scrollPrev": "عرض المهارات السابقة", - "scrollNext": "عرض المزيد من المهارات" - } - }, - "agentSelector": { - "noEnabledAgents": "لا يوجد وكلاء مفعّلون", - "openAgentsSettings": "فتح إعدادات الوكلاء", - "notInstalled": "غير مثبّت", - "moreAgents": "وكلاء إضافيون ({count})" - }, - "subAgentOverlay": { - "title": "الوكلاء الفرعيون", - "collapsedSummary": "الوكلاء الفرعيون {count}", - "collapseAria": "طي الوكلاء الفرعيين" - }, - "agentPlanOverlay": { - "title": "خطة الوكيل", - "collapsePlanAria": "طي الخطة", - "collapsedSummary": "الخطة {completed}/{total}", - "status": { - "completed": "مكتمل", - "inProgress": "قيد التنفيذ", - "pending": "قيد الانتظار", - "unknown": "غير معروف" - }, - "priority": { - "high": "مرتفع", - "medium": "متوسط", - "low": "منخفض", - "unknown": "غير معروف" - } - }, - "permissionDialog": { - "subtitle": "يطلب الوكيل إذنًا لمتابعة هذا الدور.", - "queuedCount": "+{count} في الانتظار", - "kindFallbackTool": "أداة", - "command": "أمر", - "cwd": "دليل العمل: {cwd}", - "filesSummary": "الملفات: {count}", - "moreFiles": "+{count} ملف إضافي", - "plan": "الخطة", - "allowedActions": "الإجراءات المسموح بها", - "targetMode": "وضع الهدف: {mode}", - "optionGrants": "ما يمنحه كل خيار", - "changeScopeSession": "هذه الجلسة", - "changeScopeProcess": "هذا التشغيل", - "changeScopeUser": "محفوظ في إعدادات المستخدم", - "changeScopeProject": "محفوظ في إعدادات المشروع", - "changeScopeProjectLocal": "محفوظ في إعدادات المشروع المحلية", - "changeScopePersistent": "محفوظ بشكل دائم" - }, - "questionDialog": { - "title": "الوكيل يطرح سؤالاً", - "placeholder": "اكتب إجابتك...", - "send": "إرسال" - }, - "messageBranch": { - "previousBranchAria": "الفرع السابق", - "nextBranchAria": "الفرع التالي", - "pageOf": "{current} من {total}" - }, - "terminal": { - "title": "الطرفية", - "running": "قيد التشغيل" - }, - "reasoning": { - "thinking": "جارٍ التفكير…", - "thoughtForFewSeconds": "تفكير", - "thoughtForSeconds": "تفكير" - }, - "linkSafety": { - "errorCannotOpen": "تعذر فتح الملف المحلي", - "errorNoWorkspace": "لا يوجد مجلد مساحة عمل نشط حالياً.", - "errorFailedOpen": "فشل فتح الملف المحلي", - "errorFailedLink": "فشل فتح الرابط", - "errorUnsupportedLinkProtocol": "بروتوكول الرابط هذا غير مدعوم." - }, - "fileActions": { - "openInFinder": "فتح في Finder", - "openInExplorer": "فتح في Explorer", - "openInFileManager": "فتح في مدير الملفات", - "copyRelativePath": "نسخ المسار النسبي", - "copyAbsolutePath": "نسخ المسار المطلق", - "pathCopied": "تم نسخ المسار", - "copyPathFailed": "فشل نسخ المسار", - "openFailed": "فشل فتح الملف المحلي" - }, - "messageList": { - "attachedResources": "الموارد المرفقة", - "loading": "جارٍ التحميل...", - "loadEarlier": "تحميل الرسائل السابقة", - "loadingEarlier": "جارٍ تحميل الرسائل السابقة…", - "error": "خطأ: {message}", - "errorTitle": "فشل تحميل الجلسة", - "errorActionReload": "إعادة تحميل", - "errorActionNewSession": "محادثة جديدة", - "emptyConversation": "لا توجد رسائل في هذه المحادثة.", - "systemMessage": "رسالة النظام", - "copyMessage": "نسخ", - "copied": "تم النسخ", - "downloadImage": "تنزيل الصورة", - "downloadFailed": "فشل التنزيل: {message}", - "imageGeneration": "إنشاء الصورة", - "imageGenerationPending": "جارٍ إنشاء الصورة…", - "imageGenerationFailed": "فشل إنشاء الصورة", - "model": "النموذج", - "tokenStats": "استخدام الرموز", - "tokenInput": "الإدخال", - "tokenOutput": "الإخراج", - "tokenCacheRead": "قراءة التخزين المؤقت", - "tokenCacheWrite": "كتابة التخزين المؤقت", - "duration": "المدة", - "completedAt": "وقت الإنجاز", - "jumpToPreviousUserMessage": "الانتقال إلى رسالة المستخدم", - "showMore": "عرض المزيد", - "showLess": "طي" - }, - "liveTurnStats": { - "thinking": "جارٍ التفكير...", - "streaming": "جارٍ البث", - "elapsedHours": "{value}س", - "elapsedMinutes": "{value}د", - "elapsedSeconds": "{value}ث", - "outputSpeedAria": "السرعة التقديرية للإخراج", - "outputSpeedTooltip": "السرعة التقديرية للإخراج (نص + تفكير)" - }, - "jsonTree": { - "viewRaw": "عرض JSON الخام", - "viewTree": "عرض الشجرة", - "fields": "{count, plural, zero {لا حقول} one {حقل واحد} two {حقلان} few {# حقول} many {# حقلًا} other {# حقل}}", - "items": "{count, plural, zero {لا عناصر} one {عنصر واحد} two {عنصران} few {# عناصر} many {# عنصرًا} other {# عنصر}}" - }, - "tool": { - "parameters": "المعلمات", - "error": "خطأ", - "result": "النتيجة", - "status": { - "approvalRequested": "بانتظار الموافقة", - "approvalResponded": "تم الرد", - "inputAvailable": "قيد التشغيل", - "inputStreaming": "قيد الانتظار", - "outputAvailable": "مكتمل", - "outputDenied": "مرفوض", - "outputError": "خطأ" - } - }, - "toolCallBlock": { - "tool": "أداة", - "error": "خطأ", - "result": "النتيجة" - }, - "delegation": { - "subAgentRunning": "العميل الفرعي قيد التشغيل…", - "noDetail": "No detail available yet.", - "unknownAgent": "وكيل فرعي", - "openDetail": "عرض المحادثة", - "detailTitle": "محادثة الوكيل الفرعي", - "detailDescription": "عرض للقراءة فقط لمحادثة الوكيل الفرعي المُفوَّض.", - "waitForResult": "في انتظار نتيجة المهمة {task}", - "waitForResultNoTask": "في انتظار نتيجة المهمة", - "cancelTask": "جارٍ إلغاء المهمة {task}", - "cancelTaskNoTask": "جارٍ إلغاء المهمة", - "resultPageOf": "{current} / {total}", - "prevResult": "النتيجة السابقة", - "nextResult": "النتيجة التالية", - "noResultText": "لا توجد نتيجة في هذا الفحص.", - "status": { - "starting": "قيد البدء", - "running": "قيد التشغيل", - "checked": "تم الفحص", - "waiting": "في انتظار الموافقة", - "ok": "اكتمل", - "err": { - "default": "فشل", - "delegation_disabled": "معطل", - "depth_limit": "حد العمق", - "invalid_agent_type": "وكيل غير صالح", - "spawn_failed": "فشل البدء", - "send_failed": "فشل الإرسال", - "timeout": "انتهت المهلة", - "canceled": "ملغى", - "child_refusal": "رفض الوكيل الفرعي", - "child_max_tokens": "الوكيل الفرعي: حد الرموز", - "child_max_turn_requests": "الوكيل الفرعي: حد الطلبات", - "child_empty": "الوكيل الفرعي بدون استجابة", - "child_unknown": "الوكيل الفرعي: خطأ", - "unknown": "مهمة غير معروفة" - } - } - }, - "contentParts": { - "showingTailOutput": "يتم عرض نهاية المخرجات أثناء البث لتحسين الأداء.", - "result": "النتيجة", - "unknown": "غير معروف", - "inputTruncated": "تم اقتطاع الإدخال — قد يكون الفرق غير مكتمل.", - "replaceAll": "استبدال الكل", - "filesCount": "الملفات: {count}", - "update": "تحديث", - "moreFiles": "+{count} ملف إضافي", - "timeoutMs": "المهلة: {timeout}ms", - "backgroundTrue": "الخلفية: true", - "scriptToolCalls": "{count, plural, zero {صفر استدعاء أداة} one {استدعاء أداة واحد} two {استدعاءا أداة} few {# استدعاءات أداة} many {# استدعاء أداة} other {# استدعاء أداة}}", - "offset": "الإزاحة: {offset}", - "limit": "الحد: {limit}", - "pages": "الصفحات: {pages}", - "mode": "الوضع: {mode}", - "cell": "الخلية: {cell}", - "shellSession": "الجلسة {id}", - "pathLabel": "المسار:", - "globLabel": "نمط glob:", - "typeLabel": "النوع:", - "outputLabel": "المخرجات:", - "caseInsensitive": "غير حساس لحالة الأحرف", - "multiline": "متعدد الأسطر", - "promptLabel": "المطالبة", - "subjectLabel": "الموضوع", - "taskLabel": "المهمة", - "nameLabel": "الاسم:", - "agentPromptLabel": "المطالبة", - "agentModelLabel": "النموذج", - "agentRunning": "قيد التشغيل...", - "agentLiveTranscript": "النشاط المباشر", - "agentProgressTools": "{count} استدعاءات أدوات", - "agentProgressTurns": "{count} جولات", - "agentProgressContext": "السياق {pct}%", - "agentSessionAction": "عرض جلسة الوكيل الفرعي", - "agentSessionTitle": "جلسة الوكيل الفرعي", - "agentSessionLoading": "جارٍ تحميل سجل الوكيل الفرعي…", - "agentSessionEmpty": "لم يكتب الوكيل الفرعي أي شيء بعد.", - "agentFallbackTitle": "جارٍ تشغيل الوكيل الفرعي…", - "agentCodexLaunchOnly": "تم التشغيل. لا يبلّغ Codex عن أي تقدّم إضافي لهذا الوكيل الفرعي — وستصل نتيجته كرسالة في هذه المحادثة.", - "agentStatsBash": "الأوامر", - "agentStatsRead": "الملفات المقروءة", - "agentStatsSearch": "عمليات البحث", - "agentStatsEdit": "التعديلات", - "agentStatsOther": "أخرى", - "goal": { - "title": "الهدف:", - "titleWithStatus": "الهدف {status}", - "objective": "الهدف", - "statusLabel": "الحالة", - "tokensUsed": "tokens المستخدمة", - "budget": "الميزانية", - "remaining": "المتبقي", - "elapsed": "المدة", - "tokens": "tokens", - "pause": "إيقاف مؤقت", - "clear": "مسح", - "status": { - "active": "نشط", - "paused": "متوقف مؤقتًا", - "blocked": "محظور", - "usageLimited": "الاستخدام محدود", - "budgetLimited": "الميزانية محدودة", - "complete": "مكتمل", - "limited": "تم بلوغ الحد" - } - }, - "field": { - "file": "ملف", - "notebook": "دفتر", - "command": "أمر", - "old": "قديم", - "new": "جديد", - "pattern": "النمط", - "path": "المسار", - "query": "الاستعلام", - "url": "URL:", - "description": "الوصف", - "content": "المحتوى", - "source": "المصدر", - "prompt": "المطالبة", - "subject": "الموضوع", - "taskId": "معرف المهمة", - "status": "الحالة", - "skill": "Skill", - "args": "الوسائط", - "offset": "الإزاحة", - "limit": "الحد", - "glob": "نمط glob", - "type": "النوع", - "output": "المخرجات", - "replaceAll": "استبدال الكل", - "language": "اللغة", - "timeout": "المهلة", - "background": "الخلفية", - "agentType": "نوع الوكيل", - "library": "المكتبة", - "libraryId": "معرف المكتبة" - }, - "title": { - "edit": "تحرير", - "command": "أمر", - "script": "سكربت", - "waitCommand": "انتظار {command}", - "waitCell": "انتظار الجلسة {id}", - "terminateCommand": "إنهاء {command}", - "terminateCell": "إنهاء الجلسة {id}", - "stdinChars": "إدخال {chars}", - "todoWrite": "TodoWrite (تحديث المهام)", - "read": "قراءة", - "write": "كتابة", - "notebookEdit": "NotebookEdit (تحرير الدفتر)", - "editFiles": "تحرير ({count} ملفًا)", - "editWithTarget": "تحرير {target}", - "readWithTarget": "قراءة {target}", - "writeWithTarget": "كتابة {target}", - "notebookEditWithTarget": "NotebookEdit ({target})", - "globWithPattern": "نمط glob {pattern}", - "listFilesWithPath": "عرض الملفات {path}", - "grepWithPattern": "نمط grep {pattern}", - "taskCreateWithSubject": "إنشاء مهمة: {subject}", - "taskUpdateWithStatus": "تحديث المهمة #{id} -> {status}", - "taskUpdate": "تحديث المهمة #{id}", - "webFetchWithUrl": "WebFetch ({url})", - "webSearchWithQuery": "بحث الويب: {query}", - "todosProgress": "المهام ({done}/{total})", - "skillWithName": "Skill: {name}", - "genericWithContext": "{tool} ({context})" - }, - "search": { - "noMatches": "لا توجد نتائج مطابقة", - "matchSummary": "{matches, plural, zero {صفر تطابق} one {تطابق واحد} two {تطابقان} few {# تطابقات} many {# تطابقاً} other {# تطابق}} في {files, plural, zero {صفر ملف} one {ملف واحد} two {ملفان} few {# ملفات} many {# ملفاً} other {# ملف}}", - "fileSummary": "{files, plural, zero {صفر ملف} one {ملف واحد} two {ملفان} few {# ملفات} many {# ملفاً} other {# ملف}}", - "moreResults": "{count, plural, zero {لا نتائج إضافية} one {نتيجة إضافية واحدة غير معروضة} two {نتيجتان إضافيتان غير معروضتين} few {# نتائج إضافية غير معروضة} many {# نتيجة إضافية غير معروضة} other {# نتيجة إضافية غير معروضة}}" - }, - "toolGroup": { - "search": "{count, plural, zero {بحث صفر مرة} one {بحث مرة واحدة} two {بحث مرتين} few {بحث # مرات} many {بحث # مرة} other {بحث # مرة}}", - "command": "{count, plural, zero {تنفيذ صفر أمر} one {تنفيذ أمر واحد} two {تنفيذ أمرين} few {تنفيذ # أوامر} many {تنفيذ # أمراً} other {تنفيذ # أمر}}", - "read": "{count, plural, zero {قراءة ملفات صفر مرة} one {قراءة ملفات مرة واحدة} two {قراءة ملفات مرتين} few {قراءة ملفات # مرات} many {قراءة ملفات # مرة} other {قراءة ملفات # مرة}}", - "memory": "{count, plural, zero {استرجاع صفر ذاكرة} one {استرجاع ذاكرة واحدة} two {استرجاع ذاكرتين} few {استرجاع # ذكريات} many {استرجاع # ذكرى} other {استرجاع # ذكرى}}", - "edit": "{count, plural, zero {تعديل ملفات صفر مرة} one {تعديل ملفات مرة واحدة} two {تعديل ملفات مرتين} few {تعديل ملفات # مرات} many {تعديل ملفات # مرة} other {تعديل ملفات # مرة}}", - "fetch": "{count, plural, zero {جلب صفر مورد} one {جلب مورد واحد} two {جلب موردين} few {جلب # موارد} many {جلب # مورداً} other {جلب # مورد}}", - "think": "{count, plural, zero {تفكير صفر مرة} one {تفكير مرة واحدة} two {تفكير مرتين} few {تفكير # مرات} many {تفكير # مرة} other {تفكير # مرة}}", - "todo": "{count, plural, zero {تحديث صفر مهمة} one {تحديث مهمة واحدة} two {تحديث مهمتين} few {تحديث # مهام} many {تحديث # مهمة} other {تحديث # مهمة}}", - "task": "{count, plural, zero {تشغيل صفر مهمة} one {تشغيل مهمة واحدة} two {تشغيل مهمتين} few {تشغيل # مهام} many {تشغيل # مهمة} other {تشغيل # مهمة}}", - "other": "{count, plural, zero {استخدام صفر أداة} one {استخدام أداة واحدة} two {استخدام أداتين} few {استخدام # أدوات} many {استخدام # أداة} other {استخدام # أداة}}", - "errorSuffix": "{count, plural, zero {صفر فشل} one {فشل واحد} two {فشلان} few {# فشلوا} many {# فشلاً} other {# فشل}}", - "joiner": " · " - }, - "planMode": { - "entered": "تم بدء وضع التخطيط", - "planLabel": "الخطة", - "reviewApproved": "تمت الموافقة على الخطة — جارٍ التنفيذ", - "reviewKept": "الاستمرار في وضع الخطة", - "reviewPending": "في انتظار قرار الخطة", - "submitted": "تم إرسال الخطة", - "switched": "تم تبديل الوضع" - }, - "backgroundTask": { - "title": "مهمة في الخلفية", - "titleWithId": "مهمة في الخلفية · {id}", - "running": "قيد التشغيل", - "completed": "اكتملت", - "failed": "فشلت", - "stopped": "متوقفة", - "exitCode": "رمز الخروج {code}", - "polledTimes": "تم الاستعلام {count} مرة", - "runningInBackground": "في الخلفية", - "launchNote": "قيد التشغيل في الخلفية · {id}" - }, - "codexScript": { - "outputMissing": "اقتطع codex مُخرَج النص البرمجي وأزال الفاصل الخاص بهذا الأمر، لذا تعذّر نسب أي مُخرَج إليه.", - "sharedWith": "يحتوي هذا المقطع أيضًا على مُخرَج {commands} — إذ اقتطع codex الفواصل الخاصة بها.", - "truncated": "مقتطع" - } - }, - "messageNav": { - "title": "تنقل الرسائل", - "collapse": "طي تنقل الرسائل", - "collapsedSummary": "الرسائل {count}", - "fileCount": "{count, plural, one {# ملف} other {# ملفات}}", - "remove": "إزالة", - "noDiffDataAvailable": "لا توجد بيانات diff متاحة لـ {filePath}" - }, - "replyArtifacts": { - "title": "الملفات المتغيرة", - "fileCount": "{count, plural, one {# ملف} other {# ملفات}}", - "newFilesTitle": "ملفات جديدة", - "revealInFolder": "عرض في مدير الملفات", - "openFile": "فتح {filePath}", - "openInEditor": "فتح في المحرر", - "remove": "إزالة", - "noDiffDataAvailable": "لا توجد بيانات diff متاحة لـ {filePath}" - }, - "askQuestion": { - "title": "يحتاج الوكيل إلى اختيارك", - "subtitle": "أجب ثم أرسل. يمكنك التخطّي في أي وقت.", - "recommended": "موصى به", - "other": "أخرى", - "otherPlaceholder": "اكتب إجابتك…", - "singleSelect": "اختيار واحد", - "multiSelect": "اختيار متعدد", - "skip": "تخطّي", - "next": "التالي", - "submit": "إرسال", - "submitError": "تعذّر الإرسال. حاول مرة أخرى." - }, - "planApproval": { - "title": "لدى الوكيل خطة — راجعها", - "emptyPlan": "لم يكتب الوكيل خطة. وافق للبدء في التنفيذ أو اطلب تعديلات.", - "approve": "الموافقة والبدء", - "requestChanges": "طلب تعديلات", - "abandon": "تجاهل", - "feedbackPlaceholder": "ما الذي ينبغي تغييره؟", - "sendChanges": "إرسال", - "cancel": "إلغاء", - "submitError": "تعذّر الإرسال. حاول مرة أخرى." - }, - "feedbackCheckResult": { - "count": "{count} ملاحظة", - "expand": "عرض كل الملاحظات", - "collapse": "طي", - "errorTitle": "فشل التحقق من الملاحظات" - }, - "askQuestionResult": { - "title": "سؤال", - "answeredLabel": "سؤال وجواب:", - "awaiting": "في انتظار إجابتك…", - "declined": "لقد تجاهلت هذا — استخدم الوكيل حكمه الخاص.", - "noSelection": "لا يوجد اختيار" - }, - "configStale": { - "agentConfigTitle": "تم تحديث إعدادات الوكيل", - "modelProviderTitle": "تم تحديث مزوّد النموذج", - "description": "لا تزال هذه الجلسة تستخدم الإعدادات السابقة. أعد الاتصال لتطبيقها (سيتم الاحتفاظ بسجل المحادثة).", - "reconnect": "أعد الاتصال للتطبيق", - "reconnecting": "جارٍ إعادة الاتصال…", - "reconnectDisabledDuringTurn": "متاح بعد انتهاء الدور الحالي", - "dismiss": "تجاهل", - "reconnectFailed": "فشل في إعادة الاتصال بالجلسة", - "applied": "تم تطبيق الإعدادات الجديدة" - }, - "piProjectTrust": { - "title": "يتضمّن هذا المشروع موارد pi", - "description": "لا يقوم pi بتحميل ملفات ‎.pi الخاصة بالمستودع. راجعها لتقرّر.", - "descriptionExecutable": "يتضمّن المستودع إضافات pi تُنفّذ التعليمات البرمجية عند بدء التشغيل. لا يقوم pi بتحميلها. راجعها قبل أن تقرّر.", - "review": "مراجعة…", - "dismiss": "تجاهل", - "dialogTitle": "هل تثق بموارد pi في هذا المشروع؟", - "dialogDescription": "لا يحمّل pi ملفات ‎.pi الخاصة بالمستودع إلا إذا وثقت بالمجلد. لا تمنح الثقة إلا إذا كنت تثق بمحتوى هذا المستودع.", - "executionWarning": "الإضافات هي تعليمات برمجية. الوثوق بهذا المجلد يتيح للمستودع تشغيلها عند بدء pi بصلاحياتك، وقبل أن ترسل أي رسالة.", - "scopeNote": "يُحفظ القرار في ملف trust.json الخاص بـ pi لهذا المجلد، ويسري على كل المجلدات داخله، ويُستخدم أيضًا عند تشغيلك pi بنفسك في الطرفية. يمكنك تغييره لاحقًا من الإعدادات ← الوكلاء ← Pi.", - "trust": "الوثوق بالمشروع", - "decline": "إبقاؤها غير محمّلة", - "disabledDuringTurn": "متاح بعد انتهاء الدور الحالي", - "trustedToast": "تم الوثوق بالمشروع — أُعيد الاتصال ليحمّل pi موارده", - "declinedToast": "تبقى موارد المشروع غير محمّلة", - "saveFailed": "تعذّر حفظ قرار الثقة بالمشروع", - "grantTitle": "هذا المشروع موثوق بالفعل", - "grantDescription": "يحمّل pi ملفات ‎.pi الخاصة بهذا المستودع. راجع ما الذي يسمح به ذلك.", - "grantInheritedDescription": "أحد المجلدات الأعلى موثوق، لذا يحمّل pi ملفات ‎.pi الخاصة بهذا المستودع. راجع ما الذي يسمح به ذلك.", - "grantDialogTitle": "موارد pi في هذا المشروع موثوقة", - "grantDialogDescription": "يُسمح لـ pi بتحميل ملفات ‎.pi الخاصة بهذا المستودع. كانت إصدارات codeg السابقة تمنح ذلك تلقائيًا عند فتحك لمجلد، لذا ربما لم يُطلب رأيك مطلقًا.", - "grantExecutionWarning": "الإضافات هي تعليمات برمجية. يشغّلها المستودع عند بدء pi بصلاحياتك، قبل أن ترسل أي رسالة.", - "inheritedFrom": "الثقة موروثة من", - "revoke": "إلغاء الثقة", - "keepTrusted": "الإبقاء على الثقة", - "revokedToast": "أُلغيت الثقة — أُعيد الاتصال ليتوقف pi عن تحميل موارد المشروع", - "trustedNoReconnect": "تم الوثوق بالمشروع — سيسري عند بدء pi في المرة القادمة", - "revokedNoReconnect": "أُلغيت الثقة — ستسري عند بدء pi في المرة القادمة" - }, - "collabAgent": { - "title": "وكيل فرعي", - "errorTitle": "فشلت مهمة الوكيل الفرعي", - "statesLabel": "الوكلاء الفرعيون", - "statusRunning": "قيد التشغيل", - "statusCompleted": "مكتمل", - "statusFailed": "فشل", - "statusPending": "قيد البدء", - "statusInterrupted": "متوقف", - "statusClosed": "مغلق", - "statusNotFound": "غير موجود", - "opSpawn": "بدء تشغيل الوكيل الفرعي", - "opWait": "جلب نتيجة الوكيل الفرعي", - "opClose": "إغلاق الوكيل الفرعي", - "opResume": "استئناف الوكيل الفرعي" - }, - "contextCompaction": { - "compacting": "جارٍ ضغط السياق…", - "compacted": "تم ضغط السياق", - "compactedTokens": "تم ضغط السياق · {before} → {after} رمز", - "failed": "فشل ضغط السياق" - }, - "sessionFailure": { - "category": { - "connection": "مشكلة في الاتصال", - "access": "مشكلة في الوصول", - "limit": "تم بلوغ الحد", - "request": "تم رفض الطلب", - "service": "مشكلة في الخدمة", - "unknown": "مشكلة في الجلسة" - }, - "action": { - "retry": "إعادة المحاولة", - "login": "تسجيل الدخول", - "newSession": "جلسة جديدة" - }, - "recovered": "تم التعافي", - "retryUnavailable": "لا توجد رسالة سابقة لإعادة إرسالها.", - "toggleDetails": "تبديل التفاصيل" - }, - "backgroundTasks": { - "running": "{count, plural, one {مهمة خلفية واحدة قيد التشغيل} two {مهمتا خلفية قيد التشغيل} few {# مهام خلفية قيد التشغيل} other {# مهمة خلفية قيد التشغيل}}", - "settling": "جارٍ مزامنة نتائج الخلفية…", - "settledFallback": "انتهت مهمة الخلفية ({status})", - "cardRunning": "قيد التشغيل في الخلفية", - "cardLaunchedPending": "بدأت مهمة الخلفية", - "cardCompleted": "اكتملت مهمة الخلفية", - "cardFinishedWithStatus": "انتهت مهمة الخلفية ({status})", - "cardResultPending": "لم تصل النتيجة بعد" - }, - "proposedPlan": { - "title": "الخطة المقترحة", - "planning": "جارٍ التخطيط…" - } - }, - "diffPreview": { - "mode": { - "added": "تمت الإضافة", - "deleted": "تم الحذف", - "renamed": "تمت إعادة التسمية", - "modified": "تم التعديل" - }, - "hunkLabel": "مقطع {index}", - "loadingHunk": "جارٍ تحميل hunk...", - "noDiffData": "لا توجد بيانات diff", - "showRemainingLines": "عرض {count} سطر إضافي" - }, - "conversationContextBar": { - "folderTitle": "مجلد العمل", - "branchTitle": "فرع العمل", - "searchFolder": "Search folder...", - "searchBranch": "Search branch...", - "noFolders": "No folders", - "noBranches": "No branches", - "noBranch": "(no branch)", - "chatModeLabel": "وضع الدردشة", - "commit": "Commit", - "push": "Push", - "merge": "Merge", - "toasts": { - "folderChanged": "Switched to {name}", - "openFolderFailed": "Failed to open folder", - "switchedToChatMode": "تم التبديل إلى وضع المحادثة", - "openStashFailed": "Failed to open stash window", - "openMergeFailed": "Failed to open merge window" - } - }, - "cloneDialog": { - "title": "استنساخ مستودع", - "repositoryUrl": "رابط المستودع", - "repositoryUrlPlaceholder": "https://github.com/user/repo.git", - "directory": "المجلد", - "directoryPlaceholder": "اختر مجلد الهدف...", - "browseDirectory": "تصفح المجلد", - "cancel": "إلغاء", - "clone": "استنساخ", - "clonePath": "مسار الاستنساخ: {path}" - }, - "toasts": { - "cloneFailed": "فشل استنساخ المستودع" - } - }, - "ProjectBoot": { - "title": "مُنشئ المشروع", - "tabs": { - "shadcn": "shadcn", - "hyperframes": "HyperFrames" - }, - "hyperframes": { - "title": "مشروع فيديو HyperFrames", - "subtitle": "أنشئ مشروعًا لتحويل HTML إلى فيديو. يمكن لوكيل مساحة العمل بعد ذلك كتابته وعرضه.", - "resolution": "الدقة", - "skillsTitle": "مهارات الوكلاء", - "skillsDesc": "ثبّت مهارات HyperFrames عامًّا (رابط رمزي) للوكلاء المحددين حتى يتمكنوا من إنشاء الفيديو وعرضه.", - "recheck": "إعادة الفحص", - "installedBadge": "مثبّت", - "skillsInstall": "تثبيت / تحديث المهارات", - "skillsInstalling": "جارٍ تثبيت المهارات…", - "skillsInstalled": "تم تثبيت مهارات HyperFrames", - "skillsInstallFailed": "تعذّر تثبيت مهارات HyperFrames" - }, - "config": { - "base": "الأساس", - "style": "النمط", - "baseColor": "اللون الأساسي", - "theme": "السمة", - "chartColor": "لون المخطط", - "iconLibrary": "مكتبة الأيقونات", - "font": "الخط", - "fontHeading": "خط العنوان", - "menuAccent": "تمييز القائمة", - "menuColor": "لون القائمة", - "radius": "نصف القطر", - "template": "القالب", - "createProject": "إنشاء مشروع", - "sectionStyle": "النمط", - "sectionColors": "الألوان", - "sectionTypography": "الخطوط", - "sectionInterface": "الواجهة" - }, - "preview": { - "loading": "جاري تحميل المعاينة..." - }, - "createDialog": { - "title": "إنشاء مشروع", - "projectName": "اسم المشروع", - "projectNamePlaceholder": "my-app", - "frameworkTemplate": "قالب الإطار", - "packageManager": "مدير الحزم", - "saveDirectory": "دليل الحفظ", - "saveDirectoryPlaceholder": "اختر الدليل...", - "browseDirectory": "تصفح", - "projectPath": "سيتم إنشاء المشروع في: {path}", - "advancedOptions": "خيارات متقدمة", - "base": "المكتبة الأساسية", - "enableRtl": "تفعيل دعم RTL", - "enableRtlDescription": "تفعيل دعم التخطيط للغات التي تُكتب من اليمين إلى اليسار (مثل العربية والعبرية)", - "pmChecking": "جارٍ التحقق...", - "pmNotInstalled": "غير مثبت", - "cancel": "إلغاء", - "create": "إنشاء", - "creating": "جاري إنشاء المشروع..." - }, - "toasts": { - "createFailed": "فشل إنشاء المشروع", - "createSuccess": "تم إنشاء المشروع بنجاح", - "openWorkspaceFailed": "تم إنشاء المشروع، ولكن تعذّر فتحه في مساحة العمل" - }, - "errors": { - "directoryExists": "الدليل الهدف موجود بالفعل", - "commandFailed": "فشل أمر إنشاء المشروع." - } - }, - "WebServiceSettings": { - "addressSwitchHint": "التبديل يغيّر فقط العنوان المعروض والمفتوح هنا؛ تستمع الخدمة على جميع الواجهات وتبقى قابلة للوصول من كل عنوان.", - "sectionTitle": "خدمة الويب", - "sectionDescription": "تفعيل للوصول إلى Codeg عن بُعد عبر المتصفح", - "port": "المنفذ", - "status": "الحالة", - "autoStart": "تشغيل تلقائي", - "autoStartHint": "تشغيل خدمة الويب عند بدء Codeg", - "running": "قيد التشغيل", - "stopped": "متوقف", - "processing": "جارٍ المعالجة...", - "start": "تشغيل", - "stop": "إيقاف", - "startFailed": "فشل التشغيل", - "stopFailed": "فشل الإيقاف", - "saveConfigFailed": "فشل حفظ إعدادات خدمة الويب", - "open": "فتح", - "hide": "إخفاء", - "show": "إظهار", - "copy": "نسخ", - "qrcode": "رمز QR", - "qrcodeTitle": "امسح للفتح", - "qrcodeHint": "امسح بهاتفك لفتح Codeg في المتصفح", - "addressLabel": "عنوان الوصول", - "tokenLabel": "رمز الوصول", - "tokenHint": "أدخل هذا الرمز عند الوصول إلى عميل الويب لأول مرة", - "tokenPlaceholder": "اتركه فارغاً للتوليد التلقائي", - "regenerate": "إعادة التوليد", - "stalePortOccupiedTitle": "المنفذ {port} مستخدم من قبل عملية أخرى", - "stalePortUnknownTitle": "حالة المنفذ {port} غير واضحة", - "stalePortHint": "لا يستطيع Codeg الربط قبل تحرير المنفذ. غيّر المنفذ أعلاه، أو أغلق العملية التي تحتفظ به.", - "errors": { - "alreadyRunning": "خدمة الويب قيد التشغيل بالفعل", - "invalidAddress": "تنسيق المضيف أو المنفذ غير صالح", - "portInUse": "المنفذ {port} مستخدم بالفعل. أغلق العملية التي تستخدمه أو اختر منفذاً آخر.", - "permissionDenied": "الصلاحيات غير كافية. استخدم منفذاً أعلى من 1024 أو شغّل التطبيق بصلاحيات أعلى.", - "addressUnavailable": "هذا العنوان غير متاح على هذا الجهاز", - "bindFailed": "فشل ربط العنوان" - } - }, - "DirectoryBrowser": { - "title": "تصفح المجلد", - "pathPlaceholder": "أدخل مسار المجلد...", - "goHome": "الذهاب إلى المجلد الرئيسي", - "navigateUp": "الذهاب إلى المجلد الأعلى", - "select": "اختيار", - "cancel": "إلغاء", - "loading": "جاري التحميل...", - "emptyDirectory": "هذا المجلد فارغ", - "errorLoadingDir": "فشل في تحميل المجلد", - "permissionDenied": "تم رفض الإذن" - }, - "ChatChannelSettings": { - "loading": "جاري التحميل...", - "sectionTitle": "قنوات المحادثة", - "sectionDescription": "تكوين بوتات المراسلة لتلقي إشعارات الأحداث واستعلام نشاط البرمجة.", - "addChannel": "إضافة قناة", - "noChannels": "لم يتم تكوين أي قنوات محادثة بعد.", - "channelName": "الاسم", - "channelNamePlaceholder": "بوت Telegram الخاص بي", - "channelType": "نوع القناة", - "lark": "Lark (Feishu)", - "weixin": "WeChat", - "dailyReport": "التقرير اليومي", - "dailyReportTime": "وقت التقرير", - "nameRequired": "اسم القناة مطلوب.", - "tokenRequired": "الرمز مطلوب.", - "chatIdRequired": "معرف المحادثة مطلوب.", - "topicMode": "وضع مجموعة المواضيع", - "topicModeHint": "يوجه مواضيع منتدى Telegram كجلسات Codeg منفصلة. يجب أن يكون البوت في forum supergroup وأن يملك صلاحية إدارة المواضيع.", - "loadFailed": "فشل في تحميل القنوات.", - "saveFailed": "فشل في حفظ التغييرات.", - "connectSuccess": "تم توصيل القناة.", - "connectFailed": "فشل الاتصال", - "disconnectSuccess": "تم قطع اتصال القناة.", - "disconnectFailed": "فشل قطع الاتصال.", - "testSuccess": "نجح اختبار الاتصال.", - "testFailed": "فشل اختبار الاتصال", - "deleteSuccess": "تم حذف القناة.", - "deleteFailed": "فشل في حذف القناة.", - "deleteConfirmTitle": "حذف القناة", - "deleteConfirmMessage": "سيتم حذف القناة وسجلات رسائلها نهائياً. هل أنت متأكد؟", - "cancel": "إلغاء", - "delete": "حذف", - "create": "إنشاء", - "save": "حفظ", - "channelListTitle": "القنوات المُعدة", - "channelListDescription": "القنوات المفعّلة ستتصل تلقائيًا عند بدء تشغيل الخدمة.", - "editChannel": "تعديل القناة", - "editSuccess": "تم تحديث القناة.", - "tokenPlaceholderKeep": "اتركه فارغاً للاحتفاظ بالقيمة الحالية", - "weixinScanTitle": "مسح رمز QR", - "weixinScanDescription": "افتح WeChat وامسح رمز QR للاتصال.", - "weixinQrcodeExpired": "انتهت صلاحية رمز QR.", - "weixinRefreshQrcode": "تحديث", - "weixinWaitingScan": "في انتظار المسح...", - "weixinPollError": "الاتصال غير مستقر، جاري إعادة المحاولة...", - "weixinReconnectNotice": "بسبب قيود بروتوكول iLink، بعد كل إعادة اتصال يجب عليك إرسال رسالة إلى الروبوت حتى تصبح مشغلات الأحداث فعالة.", - "connect": "اتصال", - "disconnect": "قطع الاتصال", - "test": "اختبار الاتصال", - "tabs": { - "channels": "القنوات", - "commands": "الأوامر", - "events": "الأحداث", - "other": "أخرى" - }, - "commands": { - "title": "الأوامر المدمجة", - "description": "أوامر البوت المتاحة في قنوات المحادثة. في المحادثات الجماعية، يلزم @Bot لمعالجة الرسائل.", - "prefixLabel": "بادئة الأمر", - "prefixDescription": "1-3 أحرف غير أبجدية رقمية لتشغيل أوامر البوت (الافتراضي /).", - "prefixSaved": "تم حفظ بادئة الأمر.", - "prefixSaveFailed": "فشل حفظ بادئة الأمر.", - "prefixInvalid": "يجب أن تكون البادئة 1-3 أحرف غير أبجدية رقمية.", - "save": "حفظ", - "folderDesc": "اختيار مجلد العمل", - "agentDesc": "اختيار وكيل الذكاء الاصطناعي", - "taskDesc": "إنشاء جلسة وتنفيذ المهمة", - "sessionsDesc": "عرض الجلسات النشطة في المجلد", - "resumeDesc": "المحادثات الأخيرة / استئناف جلسة", - "cancelDesc": "إلغاء المهمة الحالية", - "approveDesc": "الموافقة على طلب إذن الوكيل", - "denyDesc": "رفض طلب إذن الوكيل", - "searchDesc": "البحث في المحادثات حسب الكلمة المفتاحية", - "todayDesc": "ملخص نشاط اليوم", - "statusDesc": "حالة اتصال القناة", - "helpDesc": "عرض المساعدة" - }, - "events": { - "title": "إشعارات الأحداث", - "description": "عند تفعيل الأحداث، سيتم إرسالها إلى القناة عند تشغيلها.", - "turnComplete": "اكتمال الدور", - "turnCompleteDesc": "عند انتهاء دور الوكيل", - "error": "خطأ الوكيل", - "errorDesc": "عندما يواجه الوكيل خطأ", - "permissionRequest": "طلب إذن", - "permissionRequestDesc": "عندما يطلب الوكيل إذنًا لتنفيذ إجراء", - "questionRequest": "سؤال من الوكيل", - "questionRequestDesc": "عندما يطرح أحد الوكلاء سؤالاً عليك", - "userPromptSent": "رسالة المستخدم", - "userPromptSentDesc": "عند إرسالك رسالة — يُضمَّن نص الرسالة في الإشعار", - "saved": "تم تحديث فلتر الأحداث.", - "saveFailed": "فشل حفظ فلتر الأحداث.", - "loadFailed": "فشل تحميل الإعدادات.", - "retry": "إعادة المحاولة", - "webhooksTitle": "Webhooks", - "webhooksDescription": "يرسل حمولة JSON عبر POST إلى عنوان واحد أو أكثر عند تشغيل حدث مُفعَّل. ينطبق فلتر الأحداث أعلاه على Webhooks أيضًا.", - "webhookUrlPlaceholder": "https://example.com/webhook", - "addWebhook": "إضافة Webhook", - "removeWebhook": "إزالة Webhook", - "webhookSave": "حفظ", - "webhooksSaved": "تم حفظ Webhooks.", - "webhooksSaveFailed": "فشل حفظ Webhooks.", - "webhookInvalidUrl": "أدخل عناوين http(s) صالحة.", - "docsTitle": "تنسيق الطلب", - "docsMethod": "الطريقة", - "docsContentType": "Content-Type", - "docsNote": "يتم تسليم كل حدث مُفعَّل إلى جميع العناوين. لا يتم تأخير Webhooks؛ ولا يزال فلتر الأحداث أعلاه ساريًا.", - "editWebhook": "تعديل Webhook", - "enableWebhook": "تفعيل Webhook", - "webhookDuplicate": "هذا العنوان مُعد بالفعل.", - "cancel": "إلغاء", - "webhooksEmpty": "لا توجد Webhooks مُعدة بعد.", - "deleteWebhookTitle": "حذف Webhook", - "deleteWebhookMessage": "هل تريد حذف هذا الـ Webhook؟ لن يتم تسليم الأحداث إلى هذا العنوان بعد الآن.", - "delete": "حذف" - }, - "language": { - "title": "لغة الرسائل", - "description": "اللغة المستخدمة لإشعارات الأحداث واستجابات الأوامر والتقارير اليومية المرسلة إلى قنوات الدردشة.", - "saved": "تم حفظ لغة الرسائل.", - "saveFailed": "فشل حفظ لغة الرسائل.", - "en": "الإنجليزية", - "zh-cn": "الصينية المبسطة", - "zh-tw": "الصينية التقليدية", - "ja": "اليابانية", - "ko": "الكورية", - "es": "الإسبانية", - "de": "الألمانية", - "fr": "الفرنسية", - "pt": "البرتغالية", - "ar": "العربية" - } - }, - "ModelProviderSettings": { - "sectionTitle": "مزودو النماذج", - "sectionDescription": "إدارة بيانات اعتماد مزودي API للوكلاء.", - "filterAll": "الكل", - "providerListTitle": "المزودون المُعدّون", - "addProvider": "إضافة مزود", - "editProvider": "تعديل المزود", - "noProviders": "لم يتم تكوين أي مزود نماذج بعد.", - "providerName": "الاسم", - "providerNamePlaceholder": "مثال: OpenAI، Anthropic", - "apiUrl": "عنوان API", - "apiUrlPlaceholder": "https://api.openai.com/v1", - "apiKey": "مفتاح API", - "apiKeyPlaceholder": "sk-...", - "apiKeyKeepCurrent": "اتركه فارغاً للإبقاء على الحالي", - "agentTypes": "أنواع الوكلاء", - "agentTypesRequired": "يجب اختيار نوع وكيل واحد على الأقل.", - "agentType": "نوع الوكيل", - "agentTypeRequired": "نوع الوكيل مطلوب.", - "agentTypeImmutableHint": "لا يمكن تغيير نوع الوكيل بعد الإنشاء.", - "model": "النموذج", - "modelPlaceholderCodex": "gpt-5.6-sol / gpt-5.5", - "modelPlaceholderGemini": "gemini-3-pro-preview", - "claudeMainModel": "النموذج الرئيسي", - "claudeReasoningModel": "نموذج الاستدلال (التفكير)", - "claudeHaikuDefaultModel": "نموذج Haiku الافتراضي", - "claudeSonnetDefaultModel": "نموذج Sonnet الافتراضي", - "claudeOpusDefaultModel": "نموذج Opus الافتراضي", - "claudeCustomModelOption": "معرّف النموذج المخصّص", - "claudeCustomModelOptionName": "اسم النموذج المخصّص", - "claudeCustomModelOptionDescription": "وصف النموذج المخصّص", - "claudeCustomModelOptionHint": "يضيف عنصرًا مخصّصًا واحدًا إلى محدِّد نماذج Claude (مثل نموذج خلف بوابة/وكيل مخصّص). الاسم والوصف اختياريان لأغراض العرض فقط.", - "nameRequired": "اسم المزود مطلوب.", - "apiUrlRequired": "عنوان API مطلوب.", - "apiKeyRequired": "مفتاح API مطلوب.", - "loadFailed": "فشل تحميل المزودين.", - "saveFailed": "فشل حفظ التغييرات.", - "createSuccess": "تم إنشاء المزود.", - "editSuccess": "تم تحديث المزود.", - "deleteSuccess": "تم حذف المزود.", - "deleteConfirmTitle": "حذف المزود", - "deleteConfirmMessage": "سيتم حذف المزود \"{name}\" نهائياً. هل أنت متأكد؟", - "deleteBlockedByAgent": "{agents} يستخدم هذا المزود. يرجى إلغاء الربط قبل الحذف.", - "cancel": "إلغاء", - "delete": "حذف", - "create": "إنشاء", - "save": "حفظ", - "affectedRunningSessions": "{count} جلسة نشطة تحتاج إلى إعادة الاتصال لتطبيق التغيير" - }, - "SkillMatrix": { - "loading": "جارٍ التحميل…", - "searchPlaceholder": "البحث بالاسم أو المعرّف أو الوصف", - "empty": "لا شيء لعرضه.", - "emptySearch": "لا توجد نتائج مطابقة للبحث الحالي.", - "skillColumn": "المهارة", - "selectAll": "تحديد كل المرئي", - "selectSkill": "تحديد {name}", - "everything": { - "label": "إجراء جماعي", - "enable": "تفعيل الكل (المرئي)", - "disable": "تعطيل الكل (المرئي)" - }, - "columnMenu": { - "enableAll": "تفعيل كل المهارات", - "disableAll": "تعطيل كل المهارات" - }, - "rowMenu": { - "label": "إجراءات جماعية لـ {name}", - "enableAll": "تفعيل لكل الوكلاء", - "disableAll": "تعطيل لكل الوكلاء" - }, - "bulk": { - "selected": "{count} محدد", - "targetAll": "كل الوكلاء", - "targetSome": "{count} وكلاء", - "enable": "تفعيل", - "disable": "تعطيل", - "clear": "مسح" - }, - "confirm": { - "disableTitle": "تعطيل هذه الروابط؟", - "disableBody": "سيؤدي هذا إلى إزالة {count} من روابط المهارات التي يديرها codeg. المهارات التي تشغل دليلاً مخصصاً تبقى دون تغيير. يمكنك إعادة تفعيلها في أي وقت.", - "cancel": "إلغاء", - "confirm": "تعطيل" - }, - "toasts": { - "loadFailed": "فشل تحميل حالات المهارات", - "applyFailed": "فشل تطبيق التغييرات", - "enabled": "تم تفعيل {count} رابط", - "disabled": "تم تعطيل {count} رابط", - "enabledPartial": "تم تفعيل {ok}، وفشل {failed}", - "disabledPartial": "تم تعطيل {ok}، وفشل {failed}" - }, - "detail": { - "enableForAgents": "التفعيل للوكلاء", - "preview": "معاينة SKILL.md", - "loadingContent": "جارٍ تحميل المحتوى…" - }, - "copyModeHint": "تم النسخ (غير مرتبط) — أعد التفعيل بعد التحديثات للحصول على أحدث إصدار" - }, - "ExpertsSettings": { - "title": "مهارات الخبراء", - "description": "فعّل سير عمل المهارات المختارة بعناية والمختبرة ميدانيًا لوكلاء البرمجة بالذكاء الاصطناعي. كل خبير هو مهارة مستقلة من مشروع superpowers — يدير codeg النسخة المركزية ويربطها بالوكلاء الذين تختارهم.", - "loading": "جاري تحميل الخبراء…", - "loadingContent": "جاري تحميل المحتوى…", - "emptyExperts": "لا يوجد خبراء متاحون. تحقق من سجلات التطبيق.", - "emptySelection": "اختر خبيرًا لرؤية محتواه وإدارة تفعيله.", - "emptySearch": "لا يوجد خبراء يطابقون البحث الحالي.", - "searchPlaceholder": "ابحث عن الخبراء بالاسم أو المعرّف أو الوصف", - "enableForAgents": "تفعيل للوكلاء", - "noAgents": "لم يتم اكتشاف وكلاء ACP.", - "copyModeWarning": "تم النسخ (غير مرتبط). أعد التفعيل بعد تحديثات codeg للحصول على أحدث إصدار.", - "previewTitle": "معاينة SKILL.md", - "categories": { - "discovery": "الاكتشاف والتصميم", - "planning": "التخطيط", - "execution": "التنفيذ", - "quality": "الجودة والاختبار", - "debugging": "التصحيح", - "review": "المراجعة والدمج", - "meta": "ميتا" - }, - "states": { - "not_linked": "غير مُفعَّل", - "linked_to_codeg": "مُفعَّل", - "linked_elsewhere": "محظور — يوجد رابط آخر", - "blocked_by_real_directory": "محظور — مهارة مخصصة تشغل هذا الاسم", - "broken": "رابط معطوب" - }, - "badges": { - "userModified": "عُدِّل من قبل المستخدم" - }, - "actions": { - "openCentralDir": "فتح المجلد المركزي", - "refresh": "تحديث" - }, - "toasts": { - "loadFailed": "فشل تحميل تفاصيل الخبير", - "enabled": "تم تفعيل الخبير لهذا الوكيل", - "disabled": "تم تعطيل الخبير لهذا الوكيل", - "enableFailed": "فشل تفعيل الخبير", - "disableFailed": "فشل تعطيل الخبير", - "openFolderFailed": "فشل فتح المجلد" - } - }, - "ScienceSettings": { - "title": "مهارات البحث العلمي", - "description": "فعّل مهارات البحث العلمي المنسّقة لوكلاء البرمجة بالذكاء الاصطناعي: توليد الفرضيات، وتصميم التجارب، والإحصاء، والتصور، والتقييم النقدي، والبحث في الأدبيات. يدير codeg نسخة مركزية ويربط كل مهارة بالوكلاء الذين تختارهم.", - "loading": "جارٍ تحميل مهارات البحث العلمي…", - "emptySkills": "لا توجد مهارات بحث علمي متاحة. تحقّق من سجلات التطبيق.", - "searchPlaceholder": "ابحث في مهارات البحث العلمي بالاسم أو المعرّف أو الوصف", - "categories": { - "ideation": "توليد الأفكار", - "design": "تصميم الدراسة", - "analysis": "التحليل", - "visualization": "التصور", - "evaluation": "التقييم", - "literature": "الأدبيات" - }, - "states": { - "not_linked": "غير مُفعَّل", - "linked_to_codeg": "مُفعَّل", - "linked_elsewhere": "محظور — يوجد رابط آخر", - "blocked_by_real_directory": "محظور — مهارة مخصصة تشغل هذا الاسم", - "broken": "رابط معطوب" - }, - "badges": { - "userModified": "عُدِّل من قبل المستخدم", - "needsKey": "يتطلب مفتاحًا", - "needsSetup": "قد يتطلب إعدادًا" - }, - "actions": { - "openCentralDir": "فتح المجلد المركزي", - "refresh": "تحديث" - }, - "toasts": { - "openFolderFailed": "فشل فتح المجلد" - } - }, - "OfficeToolsSettings": { - "title": "أدوات Office", - "description": "إدارة مهارات OfficeCLI لإنشاء ملفات Excel وWord وPowerPoint. قم بتثبيت OfficeCLI ومزامنة المهارات وتفعيلها لكل وكيل.", - "loadingContent": "جارٍ تحميل المحتوى…", - "emptySkills": "لا توجد مهارات متاحة. قم بتثبيت OfficeCLI ومزامنة المهارات.", - "emptySelection": "اختر مهارة لعرض محتواها وإدارة التفعيل.", - "emptySearch": "لا توجد مهارات مطابقة.", - "searchPlaceholder": "البحث بالاسم أو المعرف أو الوصف", - "enableForAgents": "تفعيل للوكلاء", - "noAgents": "لم يتم اكتشاف وكلاء ACP.", - "installFirst": "قم بتثبيت OfficeCLI أولاً لتفعيل المهارات.", - "syncFirst": "قم بمزامنة المهارات أولاً لتحميل المحتوى.", - "noContent": "لا يوجد محتوى متاح.", - "copyModeWarning": "تم النسخ (بدون ربط). أعد المزامنة للحصول على أحدث إصدار.", - "previewTitle": "معاينة SKILL.md", - "detection": { - "installed": "مثبّت", - "notInstalled": "غير مثبّت", - "notRunnable": "مثبّت لكن لا يعمل", - "installHint": "قم بتثبيت OfficeCLI لتفعيل مهارات إنشاء مستندات Office لوكلاء الذكاء الاصطناعي.", - "install": "تثبيت", - "uninstall": "إلغاء التثبيت", - "syncSkills": "مزامنة المهارات" - }, - "categories": { - "general": "عام", - "presentations": "عروض تقديمية", - "documents": "مستندات", - "spreadsheets": "جداول بيانات" - }, - "states": { - "not_linked": "غير مفعّل", - "linked_to_codeg": "مفعّل", - "linked_elsewhere": "محظور — يوجد رابط آخر", - "blocked_by_real_directory": "محظور — مهارة مخصصة تشغل هذا الاسم", - "broken": "رابط معطل" - }, - "badges": { - "notSynced": "غير متزامن" - }, - "actions": { - "refresh": "تحديث" - }, - "toasts": { - "loadFailed": "فشل تحميل تفاصيل المهارة", - "enabled": "تم تفعيل المهارة لهذا الوكيل", - "disabled": "تم تعطيل المهارة لهذا الوكيل", - "enableFailed": "فشل تفعيل المهارة", - "disableFailed": "فشل تعطيل المهارة", - "installSuccess": "تم تثبيت OfficeCLI بنجاح", - "installFailed": "فشل تثبيت OfficeCLI", - "uninstallSuccess": "تم إلغاء تثبيت OfficeCLI", - "uninstallFailed": "فشل إلغاء تثبيت OfficeCLI", - "syncSuccess": "تمت مزامنة {synced} مهارة", - "syncPartial": "تمت مزامنة {synced}، فشلت {errors}", - "syncFailed": "فشل مزامنة المهارات" - }, - "autoPreviewLabel": "فتح المعاينة تلقائيًا", - "autoPreviewHint": "عندما ينشئ وكيل ملف Word أو Excel أو PowerPoint أو يعدّله، افتح معاينته المباشرة تلقائيًا." - }, - "SkillPacksSettings": { - "title": "حزم المهارات", - "description": "حزم مهارات منسّقة يديرها codeg مركزيًا ويربطها بوكلاء الذكاء الاصطناعي لديك — خبراء البرمجة، والبحث العلمي، وأدوات مستندات المكتب. فعّلها لكل وكيل أدناه.", - "tabs": { - "experts": "الخبراء", - "science": "البحث العلمي", - "office": "أدوات المكتب", - "custom": "مخصّصة" - }, - "actions": { - "openCentralDir": "فتح المجلد المركزي", - "refresh": "تحديث" - }, - "toasts": { - "openFolderFailed": "فشل فتح المجلد" - } - }, - "QuickMessagesSettings": { - "title": "رسائل سريعة", - "description": "إدارة مقتطفات الرسائل القابلة لإعادة الاستخدام. اسحب لإعادة الترتيب.", - "loading": "جارٍ تحميل الرسائل السريعة…", - "emptyList": "لا توجد رسائل سريعة بعد. انقر على \"جديد\" لإنشاء واحدة.", - "emptySelection": "اختر رسالة سريعة للتعديل.", - "searchPlaceholder": "ابحث حسب العنوان أو المحتوى", - "untitled": "بدون عنوان", - "actions": { - "new": "جديد", - "save": "حفظ", - "delete": "حذف", - "dragSort": "اسحب لإعادة الترتيب", - "dragSortMessage": "اسحب لإعادة ترتيب الرسالة السريعة: {name}" - }, - "fields": { - "title": "العنوان", - "titlePlaceholder": "أعطِ هذه الرسالة عنوانًا قصيرًا", - "content": "المحتوى", - "contentPlaceholder": "اكتب محتوى الرسالة هنا" - }, - "confirmDelete": { - "title": "حذف الرسالة السريعة؟", - "message": "سيؤدي ذلك إلى حذف \"{name}\" نهائيًا. هل أنت متأكد؟", - "cancel": "إلغاء", - "confirm": "حذف" - }, - "toasts": { - "loadFailed": "فشل تحميل الرسائل السريعة", - "createFailed": "فشل إنشاء الرسالة السريعة", - "saveFailed": "فشل حفظ الرسالة السريعة", - "deleteFailed": "فشل حذف الرسالة السريعة", - "saveOrderFailed": "فشل حفظ الترتيب", - "created": "تم إنشاء الرسالة السريعة", - "saved": "تم حفظ الرسالة السريعة", - "deleted": "تم حذف الرسالة السريعة" - } - }, - "Pet": { - "badge": { - "running": "{count} قيد التشغيل", - "waiting": "{count} في انتظار الموافقة", - "error": "{count} بها خطأ" - }, - "panel": { - "title": "الجلسات النشطة", - "empty": "لا توجد جلسات نشطة", - "emptyHint": "تظهر هنا الوكلاء قيد التشغيل وتلك التي تحتاج إليك.", - "statusRunning": "قيد التشغيل", - "statusWaiting": "في الانتظار", - "statusError": "خطأ", - "subAgentOf": "وكيل فرعي لـ" - }, - "menu": { - "scale": "الحجم", - "openManager": "إدارة الحيوانات الأليفة", - "close": "إغلاق" - }, - "loadError": "فشل تحميل الحيوان الأليف", - "missingPetIdParam": "لم يتم اختيار حيوان أليف", - "summonButton": "حيوان أليف", - "manager": { - "title": "حيوانات سطح المكتب", - "description": "رفقاء عائمون لسطح المكتب باستخدام صفائح سبرايت متوافقة مع Codex.", - "addPet": "إضافة حيوان", - "importFromCodex": "استيراد من Codex", - "noPets": "لا يوجد حيوان أليف. أضف واحدًا أو استورد من Codex.", - "setActive": "تفعيل", - "active": "نشط", - "edit": "تعديل", - "delete": "حذف", - "deleteConfirm": "حذف الحيوان «{name}»؟ سيُحذف من القرص.", - "summon": "استدعاء نافذة الحيوان", - "openCodexHelp": "يجب أن توجد حيوانات Codex داخل ~/.codex/pets/. لم يُعثر على شيء.", - "specRequirement": "يجب أن يكون السبرايت بعرض 1536 بكسل وارتفاع من مضاعفات 208 بكسل (مثل 1872 أو 2288)، بصيغة PNG أو WebP مع شفافية.", - "form": { - "id": "معرف الحيوان", - "idHelp": "حروف صغيرة، أرقام، '-' و '_' فقط. حد أقصى 64 حرفًا.", - "displayName": "اسم العرض", - "description": "الوصف (اختياري)", - "spritesheet": "صفيحة السبرايت", - "chooseFile": "اختر ملفًا", - "replaceFile": "استبدال السبرايت", - "saveCreate": "إضافة الحيوان", - "saveUpdate": "حفظ التغييرات", - "cancel": "إلغاء" - }, - "errors": { - "missingId": "المعرف مطلوب", - "missingName": "الاسم مطلوب", - "missingSpritesheet": "السبرايت مطلوب", - "addFailed": "فشل الإضافة", - "updateFailed": "فشل التحديث", - "deleteFailed": "فشل الحذف", - "loadFailed": "فشل تحميل قائمة الحيوانات", - "setActiveFailed": "فشل تعيين الحيوان النشط", - "summonFailed": "فشل فتح نافذة الحيوان" - } - }, - "import": { - "title": "استيراد من Codex", - "subtitle": "الحيوانات الأليفة المتاحة ضمن ~/.codex/pets/.", - "selectAll": "تحديد الكل", - "alreadyImported": "تم استيراده مسبقًا", - "renameOnConflict": "تسمية المتعارضين بإلحاق -imported", - "import": "استيراد المحدد", - "noneFound": "لا توجد حيوانات Codex قابلة للاستيراد.", - "imported": "تم الاستيراد بنجاح", - "failed": "فشل الاستيراد", - "close": "إغلاق" - }, - "marketplace": { - "openMarketplace": "متجر الحيوانات الأليفة", - "title": "متجر الحيوانات الأليفة", - "search": "ابحث عن حيوان أليف", - "kindFilter": { - "all": "الكل", - "object": "كائن", - "animal": "حيوان", - "person": "شخصية", - "creature": "مخلوق" - }, - "sortFilter": { - "latest": "الأحدث", - "popular": "الأكثر شيوعاً", - "views": "الأكثر مشاهدة" - }, - "refresh": "تحديث", - "install": "تثبيت", - "installing": "جاري التثبيت", - "reinstall": "إعادة التثبيت", - "reinstallConfirm": "هل تريد استبدال الحيوان الأليف المحلي \"{name}\"؟ ستُستبدل البيانات الحالية.", - "cancel": "إلغاء", - "stats": { - "views": "المشاهدات", - "downloads": "التنزيلات", - "likes": "الإعجابات" - }, - "actions": { - "idle": "خامل", - "running_right": "ركض يمين", - "running_left": "ركض يسار", - "waving": "تلويح", - "jumping": "قفز", - "failed": "فشل", - "waiting": "انتظار", - "running": "ركض", - "review": "مراجعة" - }, - "page": "صفحة {page} من {total}", - "prev": "السابق", - "next": "التالي", - "empty": "لا يوجد حيوان أليف مطابق.", - "successInstalled": "تم تثبيت \"{name}\"", - "errors": { - "loadFailed": "تعذّر تحميل المتجر", - "installFailed": "فشل التثبيت", - "alreadyInstalled": "هذا الحيوان موجود بالفعل" - } - } - }, - "RemoteWorkspace": { - "openRemoteWorkspace": "Open remote workspace", - "manage": "Manage remote workspace", - "manageTitle": "Remote Workspace connections", - "empty": "No remote connections", - "searchPlaceholder": "Search remote workspaces", - "orderFailed": "Failed to save remote workspace order", - "dragSort": "Drag to sort", - "dragSortConnection": "Drag to sort {name}", - "newConnection": "New connection", - "loading": "Loading", - "loadingConnection": "Loading remote connection", - "name": "Name", - "baseUrl": "Service URL", - "token": "Access token", - "save": "Save", - "delete": "Delete", - "confirmDelete": { - "title": "Delete remote connection?", - "message": "This will remove \"{name}\" from this device. This action cannot be undone.", - "cancel": "Cancel", - "confirm": "Delete" - }, - "saved": "Remote connection saved.", - "deleted": "Remote connection deleted.", - "loadFailed": "Failed to load remote connections", - "saveFailed": "Failed to save remote connection", - "deleteFailed": "Failed to delete remote connection", - "openFailed": "Failed to open remote workspace", - "connectionLoadFailed": "Failed to load remote connection: {message}", - "connectionExpired": "Remote connection \"{name}\" is expired. Update its token and reload this window." - }, - "ServerFileBrowser": { - "title": "اختر ملفًا من الخادم", - "pathPlaceholder": "أدخل مسار الدليل...", - "goHome": "اذهب إلى المجلد الرئيسي", - "navigateUp": "اذهب إلى المجلد الأعلى", - "select": "اختر", - "cancel": "إلغاء", - "loading": "جارٍ التحميل...", - "emptyDirectory": "هذا المجلد فارغ", - "errorLoadingDir": "فشل تحميل المجلد", - "selectedCount": "{count} محدد" - }, - "BackupSettings": { - "title": "النسخ الاحتياطي والاستعادة", - "description": "صدّر نسخة احتياطية محمولة من بيانات codeg، أو استعد من نسخة.", - "tabs": { - "backup": "نسخ احتياطي", - "restore": "استعادة" - }, - "export": { - "includeExternal": "تضمين محتوى المحادثات", - "includeExternalHint": "يؤرشف أيضًا سجلات محادثات أدوات CLI (Claude وCodex وGemini …). يزيد الحجم.", - "passphrase": "عبارة المرور (اختياري)", - "passphrasePlaceholder": "اتركها فارغة للحصول على أرشيف غير مشفّر", - "passphraseConfirm": "تأكيد عبارة المرور", - "passphraseMismatch": "عبارتا المرور غير متطابقتين.", - "noPassphraseWarning": "ستحتوي هذه النسخة على أسرار (مفاتيح API والرموز) بنص واضح. احفظها في مكان آمن.", - "passphraseLossWarning": "مشفّرة بعبارة المرور هذه. إذا فقدتها، فلن يمكن استعادة النسخة الاحتياطية.", - "button": "تصدير النسخة الاحتياطية", - "inProgress": "جارٍ إنشاء النسخة الاحتياطية…", - "success": "تم إنشاء النسخة الاحتياطية.", - "started": "بدأ تنزيل النسخة الاحتياطية." - }, - "restore": { - "selectFile": "اختر ملف النسخة الاحتياطية", - "passphrasePrompt": "هذه النسخة مشفّرة. أدخل عبارة المرور الخاصة بها.", - "unlock": "فتح القفل", - "preview": { - "title": "تفاصيل النسخة الاحتياطية", - "encrypted": "مشفّرة", - "compatible": "متوافقة", - "incompatible": "غير متوافقة", - "createdAt": "أُنشئت: {value}", - "appVersion": "إصدار التطبيق: {value}", - "incompatibleHint": "أُنشئت هذه النسخة بإصدار أحدث من codeg ولا يمكن استعادتها." - }, - "replaceWarning": "تستبدل الاستعادة جميع بيانات codeg الحالية (قاعدة البيانات والملفات المرفوعة). تُلتقط بياناتك الحالية كلقطة أولًا حتى يمكن استرجاعها.", - "keyringNote": "تُخزَّن رموز GitHub/الدردشة لتطبيق سطح المكتب في سلسلة مفاتيح النظام ولا تُضمَّن؛ أعد إدخالها بعد الاستعادة.", - "button": "استعادة", - "staging": "جارٍ تجهيز الاستعادة…", - "staged": "تم تجهيز الاستعادة. جارٍ إعادة التشغيل…", - "restarting": "تم تجهيز الاستعادة. جارٍ إعادة تشغيل الخادم…", - "restartTimeout": "لم يعد الخادم في الوقت المحدد. أعد تحميل الصفحة بعد تشغيله.", - "externalSideLocation": "تمت استعادة سجلات المحادثات إلى {path}", - "confirmTitle": "استبدال جميع البيانات؟", - "confirmBody": "سيؤدي ذلك إلى استبدال قاعدة بيانات codeg والملفات المرفوعة الحالية بالنسخة الاحتياطية ثم إعادة التشغيل. تُلتقط بياناتك الحالية كلقطة أولًا.", - "cancel": "إلغاء", - "confirmAction": "استبدال وإعادة تشغيل", - "external": { - "title": "محتوى المحادثات", - "hint": "تتضمن هذه النسخة سجلات محادثات أدوات CLI. اختر مكان استعادتها.", - "modeSkip": "عدم الاستعادة", - "modeSide": "الاستعادة إلى مجلد جانبي آمن", - "modeOriginal": "الاستعادة إلى المواقع الأصلية لأدوات CLI", - "forceOverwrite": "الكتابة فوق الملفات الموجودة", - "forceOverwriteHint": "استبدال الملفات الموجودة بالفعل في مجلدات أدوات CLI.", - "scanning": "جارٍ التحقق من التعارضات…", - "noConflicts": "لن تتم الكتابة فوق أي ملف موجود.", - "conflictCount": "سيتأثر {count} من الملفات الموجودة.", - "conflictSkipNote": "تُحفظ الملفات الموجودة (تُتخطى) ما لم تفعّل الكتابة فوقها." - }, - "restartFailed": "تم تجهيز الاستعادة، لكن تعذّر إعادة تشغيل الخادم. أعد تشغيله يدويًا لتطبيقها." - }, - "remoteUnsupported": "يعمل النسخ الاحتياطي والاستعادة على بيانات الجهاز الذي يشغّل codeg. أنت متصل بمساحة عمل بعيدة — أدِر نسخها الاحتياطية من ذلك الخادم مباشرة." - }, - "backup": { - "restore": { - "error": { - "badPassphrase": "عبارة المرور غير صحيحة أو النسخة الاحتياطية تالفة.", - "corrupted": "أرشيف النسخة الاحتياطية تالف.", - "unknownFormat": "هذا الملف ليس نسخة احتياطية معروفة من codeg.", - "newerVersion": "أُنشئت هذه النسخة بواسطة codeg {backupVersion}، وهي أحدث من هذا الإصدار ({appVersion}).", - "alreadyPending": "توجد استعادة مُجهّزة بالفعل. أعد التشغيل لتطبيقها قبل تجهيز أخرى." - } - }, - "error": { - "diskSpace": "لا توجد مساحة قرص كافية لإكمال العملية.", - "cancelled": "تم إلغاء العملية." - } - }, - "WebConnection": { - "disconnectedTitle": "انقطع الاتصال", - "reconnectingDescription": "تتم محاولة إعادة الاتصال بالخادم. عادةً ما يُستعاد الاتصال تلقائيًا خلال ثوانٍ قليلة.", - "reconnectNow": "إعادة الاتصال الآن", - "sessionExpiredTitle": "انتهت الجلسة", - "sessionExpiredDescription": "لم تعد جلستك صالحة. يُرجى تسجيل الدخول مرة أخرى للمتابعة.", - "goToLogin": "الانتقال إلى تسجيل الدخول" - }, - "LiveFeedback": { - "placeholder": "أرسل ملاحظة إلى {agent} أثناء عمله…", - "agentFallback": "الوكيل", - "ariaLabel": "ملاحظة مباشرة", - "dialogTitle": "ملاحظات مباشرة", - "dialogDescription": "أرسل ملاحظة إلى الوكيل أثناء عمله. سيقرأها في فحصه التالي دون مقاطعة الخطوة الحالية.", - "dialogDescriptionInstant": "أرسل ملاحظة إلى الوكيل أثناء عمله. تُدرج الملاحظة فورًا في الدور الحالي — يراها الوكيل على الفور.", - "channelDowngraded": "الإدراج الفوري غير متاح في هذه الجلسة — حُفظت ملاحظتك ليقرأها الوكيل عند فحصه التالي.", - "send": "إرسال", - "cancel": "إلغاء", - "pending": "في الانتظار", - "delivered": "تم الاستلام", - "turnEndedUnread": "أنهى الوكيل الجولة قبل قراءة ملاحظاتك.", - "sendAsMessage": "إرسال كرسالة", - "dismiss": "تجاهل", - "turnEndedResent": "انتهت الجولة — تم الإرسال كرسالة جديدة بدلاً من ذلك.", - "turnEnded": "انتهت الجولة بالفعل.", - "submitFailed": "تعذّر إرسال ملاحظتك" - }, - "AgentToolsSettings": { - "title": "أدوات داخل المحادثة", - "description": "أدوات إضافية يمنحها codeg للوكيل داخل المحادثة. تُحقن عند بدء تشغيل الوكيل، لذا يسري أي تغيير على الوكلاء الذين يبدأون بعده.", - "feedbackLabel": "ملاحظات مباشرة", - "feedbackHint": "أرسل ملاحظات وتصحيحات إلى الوكيل أثناء عمله. إذا كان الوكيل يدعم الإدراج الفوري، تُدرج ملاحظتك فورًا في الدور الجاري؛ وإلا يحصل الوكيل على أداة للاطلاع على ملاحظاتك — وهؤلاء الوكلاء عادةً لا يتحققون منها إلا إذا ذكرت ذلك في الموجّه، مثلًا أضف \"تحقق من ملاحظاتي المباشرة بانتظام\" إلى رسالتك.", - "questionLabel": "سؤال المستخدم", - "questionHint": "يسمح للوكلاء بالتوقّف وطرح سؤال متعدّد الخيارات يظهر فوق مربّع إدخال المحادثة. ينتظر الوكيل حتى تجيب (أو تتخطّى).", - "sessionInfoLabel": "الحصول على معلومات الجلسة", - "sessionInfoHint": "يتيح للوكلاء البحث عن جلسة تشير إليها في رسالتك (شارة جلسة) لقراءة عنوانها والوكيل والحالة ومساحة العمل واستهلاك الرموز وأحدث الرسائل.", - "automationsLabel": "إنشاء الأتمتة", - "automationsHint": "يحفظ المحادثة كأتمتة تعمل وفق جدول زمني. مُعطّل افتراضيًا — إذ تبدأ بعد ذلك تشغيل الوكلاء من تلقاء نفسها.", - "workTasksLabel": "إنشاء مهام قيد الانتظار", - "workTasksHint": "يضيف بطاقة إلى لوحة المهام انطلاقًا من المحادثة. مُعطّل افتراضيًا — لأنه يكتب حالة التطبيق.", - "save": "حفظ", - "saving": "جارٍ الحفظ…", - "saved": "تم حفظ إعدادات الأدوات", - "saveFailed": "تعذّر حفظ إعدادات الأدوات", - "loadFailed": "فشل التحميل: {detail}" - }, - "NotificationSoundSettings": { - "title": "أصوات التنبيه", - "description": "تشغيل صوت قصير عند وقوع حدث للوكيل. هي نفس الأحداث التي تُرسل إلى قنوات المحادثة، وهذا الإعداد يخص هذا الجهاز فقط.", - "enableHint": "معطّل افتراضيًا. تُشغَّل الأصوات في نافذة مساحة العمل بهذا المتصفح أو التطبيق فقط.", - "volume": "مستوى الصوت", - "preview": "استماع", - "previewEvent": "استماع لصوت {event}", - "onlyWhenUnfocused": "فقط عندما تكون النافذة غير نشطة", - "onlyWhenUnfocusedHint": "يبقى صامتًا أثناء استخدامك لـ Codeg.", - "eventsTitle": "الأحداث", - "eventsHint": "اختر نغمة لكل حدث، أو «صامت» لتجاهله. إذا تكرر الحدث نفسه خلال ثوانٍ قليلة فسيُشغَّل مرة واحدة فقط.", - "toneNone": "صامت", - "toneChime": "رنين", - "toneDing": "جرس", - "toneBlip": "نبضة", - "tonePop": "طقّة", - "toneAlert": "تنبيه", - "toneDescend": "نغمة هابطة" - }, - "LogsSettings": { - "loading": "جارٍ التحميل…", - "sectionTitle": "سجلات التشغيل", - "sectionDescription": "عرض وتكوين سجلات تشخيص التطبيق. تُكتب السجلات في ملفات محلية وتُحفظ في الذاكرة للعرض المباشر.", - "captureTitle": "مستوى السجل", - "captureDescription": "يتحكم في مقدار التفاصيل الملتقطة. المستويات الأعلى (Debug، Trace) تسجل المزيد لكنها تنتج سجلات أكبر. «إيقاف» يعطّل التسجيل.", - "captureLabel": "مستوى الالتقاط", - "levels": { - "off": "إيقاف", - "error": "خطأ", - "warn": "تحذير", - "info": "معلومات", - "debug": "تصحيح", - "trace": "تتبع" - }, - "viewerTitle": "السجلات الأخيرة", - "viewerDescription": "عرض مباشر لأحدث السجلات. قم بالتصفية حسب المستوى أو ابحث في النص.", - "searchPlaceholder": "ابحث في الرسالة أو المصدر…", - "viewLevels": { - "all": "كل المستويات", - "error": "خطأ فأعلى", - "warn": "تحذير فأعلى", - "info": "معلومات فأعلى", - "debug": "تصحيح فأعلى", - "trace": "تتبع فأعلى" - }, - "pause": "إيقاف مؤقت", - "resume": "مباشر", - "refresh": "تحديث", - "clear": "مسح", - "openFolder": "فتح المجلد", - "shownCount": "{shown} / {total} معروض", - "empty": "لا توجد سجلات للعرض.", - "levelSaveFailed": "فشل حفظ مستوى السجل", - "openFolderFailed": "فشل فتح مجلد السجلات", - "downloadFailed": "فشل تنزيل ملف السجل", - "filesTitle": "ملفات السجل", - "filesDescription": "نزّل ملفات السجل الكاملة من القرص للاطلاع على السجل خارج المخزن المباشر.", - "filesEmpty": "لا توجد ملفات سجل بعد.", - "download": "تنزيل", - "downloadTruncated": "الملف كبير، تم تنزيل أحدث {size}. الملف الكامل موجود في دليل السجلات.", - "captureEnvLocked": "يتم التحكم في مستوى السجل عبر متغير البيئة RUST_LOG / CODEG_LOG؛ غيّره هناك ليصبح ساريًا.", - "targetsTitle": "تجاوزات حسب الوحدة", - "targetsDescription": "عيّن مستوى مختلفًا لوحدات محددة (مثل codeg_lib::acp) دون تغيير المستوى العام.", - "targetsAdd": "إضافة", - "targetsRemove": "إزالة التجاوز", - "toggleDetails": "تبديل التفاصيل" - }, - "Automations": { - "title": "الأتمتة", - "new": "أتمتة جديدة", - "empty": "لا توجد أتمتة بعد", - "emptyHint": "أنشئ واحدة لتشغيل مهمة الوكيل وفق جدول أو يدويًا.", - "name": "الاسم", - "namePlaceholder": "مثال: مراجعة PR الليلية", - "prompt": "الموجّه", - "promptPlaceholder": "ماذا يجب أن يفعل الوكيل؟", - "agent": "الوكيل", - "folder": "مجلد مساحة العمل", - "folderPlaceholder": "اختر مجلدًا", - "isolation": "العزل", - "isolationWorktree": "worktree جديد لكل تشغيل", - "isolationShared": "التشغيل داخل المجلد", - "isolationSharedCaveat": "تستخدم عمليات التشغيل شجرة عمل هذا المجلد مباشرةً، وقد تتعارض مع تغييراتك غير المُلتزَم بها. فعِّل خيار شجرة العمل لعزل كل عملية تشغيل.", - "trigger": "المُشغِّل", - "triggerSchedule": "وفق جدول", - "triggerManual": "يدوي فقط", - "cron": "الجدولة (cron)", - "cronPlaceholder": "0 9 * * 1-5", - "timezone": "المنطقة الزمنية", - "nextRun": "التشغيل التالي", - "branch": "الفرع", - "branchOptional": "الفرع (اختياري)", - "enabled": "مُفعّل", - "save": "حفظ", - "cancel": "إلغاء", - "edit": "تعديل", - "delete": "حذف", - "runNow": "تشغيل الآن", - "cancelRun": "إلغاء التشغيل", - "runHistory": "سجل التشغيل", - "noRuns": "لا توجد عمليات تشغيل بعد", - "allFolders": "كل المجلدات", - "filterAll": "الكل", - "noMatches": "لا توجد أتمتة مطابقة", - "viewConversation": "عرض المحادثة", - "lastRun": "آخر تشغيل", - "never": "أبدًا", - "running": "قيد التشغيل", - "deleteTitle": "حذف الأتمتة؟", - "deleteDescription": "يؤدي هذا إلى إزالة الأتمتة وجدولها. يُحتفظ بسجل التشغيل.", - "statusRunning": "قيد التشغيل", - "statusSucceeded": "نجحت", - "statusFailed": "فشلت", - "statusCancelled": "أُلغيت", - "statusSkipped": "تم تخطيها", - "errorName": "الاسم مطلوب", - "errorPrompt": "الموجّه مطلوب", - "errorCron": "تتطلب الأتمتة المجدولة تعبير cron", - "errorFolder": "اختر مجلد مساحة العمل", - "presetHourly": "كل ساعة", - "presetDaily": "يوميًا 9 صباحًا", - "presetWeekdays": "أيام العمل 9 صباحًا", - "presetCustom": "مخصص", - "probing": "جارٍ تحميل الخيارات…", - "retry": "إعادة المحاولة", - "configNone": "لا توجد خيارات قابلة للضبط لهذا الوكيل", - "inherit": "افتراضي الوكيل", - "mode": "الوضع", - "config": "الإعدادات", - "branchPlaceholder": "(الفرع الافتراضي)", - "selectHint": "اختر أتمتة لعرض التفاصيل", - "refresh": "تحديث", - "onboardTitle": "أتمتة مهام الوكيل الروتينية", - "onboardHint": "اجدول وكيلًا لمراجعة الشيفرة أو تحديث الاعتماديات أو فرز المشكلات، وفق جدول زمني أو عند الطلب.", - "headerSubtitle": "مهام الوكيل المجدولة وعند الطلب", - "startFromTemplate": "ابدأ من قالب", - "blankTitle": "أتمتة فارغة", - "blankDesc": "اضبط مهمة وكيل من البداية.", - "backToTemplates": "القوالب", - "sectionSchedule": "الجدولة والهدف", - "sectionTarget": "الهدف", - "sectionAction": "الإجراء", - "actionLaunchSession": "تشغيل جلسة", - "actionEnqueueTask": "إضافة مهمة إلى قائمة الانتظار", - "actionEnqueueTaskHint": "عند كل تشغيل تُضاف مهمة قيد الانتظار تحمل اسم هذه الأتمتة إلى المهام قيد الانتظار للمجلد، وينفذها محرك المهام وفق إعدادات اللوحة.", - "sectionPrompt": "الموجّه", - "nextIn": "التالي خلال {rel}", - "manual": "يدوي", - "schedEveryMinutes": "كل {n} دقيقة", - "schedHourly": "كل ساعة", - "schedDaily": "يوميًا في {time}", - "schedWeekdays": "أيام العمل في {time}", - "schedWeekly": "كل {day} في {time}", - "schedMonthly": "شهريًا في اليوم {day} عند {time}", - "dow0": "الأحد", - "dow1": "الاثنين", - "dow2": "الثلاثاء", - "dow3": "الأربعاء", - "dow4": "الخميس", - "dow5": "الجمعة", - "dow6": "السبت", - "tplCodeReviewTitle": "مراجعة الشيفرة", - "tplCodeReviewDesc": "يراجع التغييرات الأخيرة بحثًا عن الأخطاء والانحدارات ومشكلات الجودة.", - "tplDependencyUpdatesTitle": "تحديث الاعتماديات", - "tplDependencyUpdatesDesc": "يعثر على الاعتماديات القديمة ويقترح ترقيات آمنة.", - "tplTestCoverageTitle": "تغطية الاختبارات", - "tplTestCoverageDesc": "يعثر على مسارات الشيفرة غير المختبرة ويضيف الاختبارات الناقصة.", - "tplTodoSweepTitle": "تجميع مهام TODO", - "tplTodoSweepDesc": "يجمع تعليقات TODO وFIXME ويفرزها حسب الأولوية.", - "tplCiTriageTitle": "فرز CI", - "tplCiTriageDesc": "يحقق في الفحوصات الفاشلة الأخيرة ويقترح إصلاحات.", - "tplReleaseNotesTitle": "ملاحظات الإصدار", - "tplReleaseNotesDesc": "يلخّص التغييرات منذ الإصدار الأخير في سجل تغييرات.", - "tplSecurityAuditTitle": "تدقيق الأمان", - "tplSecurityAuditDesc": "يفحص الثغرات والأنماط الخطرة ثم يبلّغ عن النتائج.", - "enable": "تفعيل", - "disable": "تعطيل", - "moreActions": "إجراءات إضافية", - "statusDisabled": "معطّلة", - "cronBuilderTitle": "منشئ الجدولة", - "cronFreqLabel": "التكرار", - "cronFreqMinutes": "كل N دقيقة", - "cronFreqHourly": "كل ساعة", - "cronFreqDaily": "يوميًا", - "cronFreqWeekdays": "أيام الأسبوع", - "cronFreqWeekly": "أسبوعيًا", - "cronFreqMonthly": "شهريًا", - "cronFreqCustom": "مخصص", - "cronEveryLabel": "الفاصل (دقائق)", - "cronTimeLabel": "الوقت", - "cronHourLabel": "الساعة", - "cronMinuteLabel": "الدقيقة", - "cronDowLabel": "يوم الأسبوع", - "cronDomLabel": "يوم الشهر", - "cronApply": "تطبيق", - "cronPreviewLabel": "معاينة", - "cronOpenBuilder": "فتح منشئ الجدولة", - "branchDefault": "الفرع الافتراضي", - "branchUseCustom": "استخدام \"{query}\"", - "branchLocal": "محلي", - "branchRemote": "بعيد", - "branchSearchPlaceholder": "بحث في الفروع…", - "branchNone": "لا توجد فروع" - }, - "Tasks": { - "title": "المهام قيد الانتظار", - "new": "مهمة جديدة", - "empty": "لا توجد مهام بعد", - "emptyHint": "أضف مهمة ثم شغّلها — يعمل الوكيل في worktree معزول، وتراجع النتيجة وتدمجها.", - "emptyColTodo": "لا توجد مهام قيد الانتظار بعد", - "emptyColInProgress": "لا توجد مهام قيد التنفيذ", - "emptyColAttention": "لا توجد مهام بانتظارك", - "emptyColDone": "لا توجد مهام مكتملة بعد", - "allFolders": "كل المجلدات", - "showCanceled": "إظهار الملغاة", - "showArchived": "إظهار المؤرشفة", - "filter": "تصفية", - "viewSwitchToBoard": "التبديل إلى عرض اللوحة", - "viewSwitchToList": "التبديل إلى عرض القائمة", - "statusFilter": "الحالة", - "statusFilterAll": "كل الحالات", - "listEmpty": "لا توجد مهام مطابقة لعوامل التصفية الحالية", - "listColStatus": "الحالة", - "listColTask": "المهمة", - "listColLocation": "الموقع", - "listColChanges": "التغييرات", - "listColUpdated": "آخر تحديث", - "colTodo": "قيد الانتظار", - "colInProgress": "قيد التنفيذ", - "colAttention": "بانتظارك", - "colDone": "مكتملة", - "statusTodo": "قيد الانتظار", - "statusQueued": "في قائمة الانتظار", - "statusPreparing": "قيد التهيئة", - "statusRunning": "قيد التنفيذ", - "statusAwaitingInput": "بانتظار الإدخال", - "statusReview": "بانتظار المراجعة", - "statusMerging": "جارٍ الدمج", - "statusDone": "مكتملة", - "statusFailed": "فشلت", - "statusCanceled": "ملغاة", - "statusInterrupted": "توقّفت", - "badgeCleanupFailed": "فشل التنظيف", - "badgeWorktreeKept": "تم الإبقاء على worktree", - "badgeWorktreeRemoved": "تمت إزالة worktree", - "filesChanged": "{count} ملفات", - "actionStart": "بدء", - "actionSchedule": "جدولة", - "actionCancel": "إلغاء", - "actionRetry": "إعادة المحاولة", - "actionRequeue": "إعادة الإدراج", - "actionViewSession": "عرض المحادثة", - "actionEdit": "تحرير", - "actionDelete": "حذف", - "actionRetryCleanup": "إعادة محاولة التنظيف", - "actionMerge": "دمج", - "actionUnqueueMerge": "مغادرة طابور الدمج", - "actionEditQueuedMerge": "تعديل الدمج المنتظر", - "badgeMergeQueued": "في طابور الدمج", - "badgeMergeQueuedRank": "في طابور الدمج · رقم {rank}", - "badgeMergeQueuedHint": "في انتظار انتهاء الدمج الجاري لهذا المشروع، وسيبدأ هذا تلقائيًا عند دوره.", - "actionComplete": "إنهاء", - "actionAbandon": "تخلٍّ", - "cancelTitle": "إلغاء المهمة؟", - "cancelDescription": "ستصبح المهمة ملغاة. يُحتفظ بـ worktree الخاصة بها ويمكنك إعادة إدراجها لاحقًا.", - "cancelReasonLabel": "السبب (اختياري)", - "cancelReasonPlaceholder": "مثلاً: النهج خاطئ، سأعيد كتابة الوصف", - "cancelKeep": "تراجع", - "cancelSubmit": "إلغاء المهمة", - "restartTitleRetry": "إعادة محاولة المهمة", - "restartTitleRequeue": "إعادة إدراج المهمة", - "restartDescription": "يمكنك إضافة ملاحظة (اختيارية) تصل إلى موجّه التشغيل التالي.", - "scheduleTitle": "جدولة المهمة", - "scheduleDescription": "تبقى المهمة في قائمة الانتظار وتبدأ تلقائيًا في الوقت الذي تحدده. ويظل حد التنفيذ المتزامن للمجلد ساريًا.", - "scheduleDateLabel": "التاريخ", - "schedulePickDate": "اختر التاريخ", - "scheduleTimeLabel": "الوقت", - "schedulePreview": "يبدأ في {time}", - "schedulePastHint": "لقد مضى هذا الوقت — ستبدأ المهمة فور الحفظ.", - "scheduleInAnHour": "بعد ساعة", - "scheduleInThreeHours": "بعد 3 ساعات", - "scheduleTomorrow": "غدًا 9:00", - "scheduleClear": "إلغاء الجدولة", - "scheduleBadge": "بدء مجدول في {time}", - "toastScheduled": "تمت الجدولة في {time}", - "toastScheduleCleared": "تم إلغاء الجدولة", - "actionFollowUp": "متابعة", - "actionAddNote": "إضافة ملاحظة", - "followUpSubmit": "إرسال", - "followUpIntentRevise": "إعادة العمل", - "followUpIntentContinue": "المتابعة", - "followUpIntentQuestion": "طرح سؤال", - "followUpIntentVerify": "مراجعة ذاتية", - "followUpPlaceholderRevise": "ما الذي يجب أن يغيّره الوكيل؟ سيتابع في الجلسة نفسها.", - "followUpPlaceholderContinue": "ما التالي؟ سيبقى العمل المنجز كما هو.", - "followUpPlaceholderQuestion": "ما الذي تريد معرفته؟ سيجيب الوكيل دون تعديل أي ملف.", - "followUpPlaceholderVerify": "اختياري: هل من شيء ينبغي فحصه بعناية؟", - "followUpPlaceholderRetry": "اختياري: ما الذي ينبغي فعله بشكل مختلف؟ مثلاً: شغّل pnpm install أولاً", - "followUpPlaceholderRequeue": "اختياري: لماذا ألغيتها، وما الذي يجب أن يتغيّر هذه المرة؟", - "actionArchive": "أرشفة", - "actionUnarchive": "إلغاء الأرشفة", - "archiveAllDone": "أرشفة الكل", - "dropToStart": "أفلِت للبدء", - "errorView": "عرض", - "notifyReview": "جاهزة للمراجعة: {title}", - "notifyFailed": "فشلت المهمة: {title}", - "createFromMessage": "إنشاء مهمة من الرسالة", - "detailTokens": "إجمالي الرموز", - "editorTitleNew": "مهمة جديدة", - "editorTitleEdit": "تحرير المهمة", - "templates": "القوالب", - "templatesEmpty": "لا توجد قوالب بعد.", - "templateSaveCurrent": "حفظ المحتوى الحالي كقالب", - "templateDelete": "حذف القالب", - "transcriptTitle": "محادثة المهمة", - "transcriptDescription": "عرض مباشر للقراءة فقط لجلسة وكيل المهمة.", - "phaseWork": "تنفيذ المهمة", - "phaseRetry": "إعادة التنفيذ", - "phaseReturn": "متابعة", - "phaseMerge": "الدمج", - "titleLabel": "العنوان", - "titlePlaceholder": "ما الذي يجب إنجازه؟", - "promptLabel": "وصف المهمة", - "promptPlaceholder": "صف المهمة للوكيل — استخدم @ للإشارة إلى الملفات و / للأوامر", - "folderPlaceholder": "اختر مجلدًا", - "agentInheritedHint": "موروث من إعدادات المهام — عدِّله ليصبح خاصًا بهذه المهمة", - "agentOverrideReset": "العودة إلى الوراثة", - "sectionTarget": "الهدف", - "errorTitle": "العنوان مطلوب", - "errorPrompt": "وصف المهمة مطلوب", - "errorFolder": "اختر مجلدًا", - "save": "حفظ", - "cancel": "إلغاء", - "mergeTitle": "دمج المهمة", - "mergeQueuedTitle": "دمج في الطابور", - "mergeQueueHint": "تجري الآن عملية دمج لمهمة أخرى في هذا المشروع. ستنضم هذه المهمة إلى الطابور وتبدأ تلقائيًا فور انتهاء تلك العملية.", - "mergeQueueUpdateHint": "هذه المهمة تنتظر الدمج بالفعل. الإرسال يحدّث خياراتها ويحتفظ بمكانها في الطابور.", - "mergeDescription": "دمج {branch} في {base}. تُرسل التغييرات غير المثبتة في worktree أولًا.", - "mergeMessage": "رسالة الالتزام", - "mergeMessagePlaceholder": "مثال: feat: add login validation", - "mergeAutoMessage": "دع الوكيل يكتب رسالة الإيداع", - "strategySquash": "دمج في التزام واحد", - "strategySquashHint": "تصل جميع تغييرات المهمة إلى الفرع الرئيسي كسجل واحد — تاريخ أكثر ترتيبًا.", - "strategyMerge": "الاحتفاظ بالتاريخ الكامل", - "strategyMergeHint": "يُحتفظ بكل التزام أُنشئ أثناء المهمة، مع إضافة سجل دمج واحد — تبقى كل خطوة قابلة للتتبع.", - "mergeDeleteWorktree": "حذف worktree بعد الدمج", - "mergeSubmit": "دمج", - "mergeSubmitQueue": "إضافة إلى طابور الدمج", - "mergeQueuedToast": "تمت الإضافة إلى طابور الدمج — سيبدأ فور انتهاء الدمج الحالي.", - "completeTitle": "إنهاء المهمة", - "completeDescription": "لم تغيّر هذه المهمة أي ملف، لذا لا يوجد ما يُدمج — سيتم وضع علامة مكتملة عليها مباشرة.", - "completeDescriptionNoWorktree": "تمت إزالة worktree هذه المهمة، فلم يعد الدمج ممكنًا — سيتم وضع علامة مكتملة عليها مباشرة. يُحتفظ بفرع العمل إذا كان لا يزال يحوي إيداعات غير مدمجة.", - "completeDeleteWorktree": "حذف worktree بعد الإنهاء", - "completeSubmit": "إنهاء", - "settingsTitle": "إعدادات المهام", - "settingsDescription": "الإعدادات الافتراضية لمهام {folder}.", - "settingsScope": "النطاق", - "settingsScopeGlobal": "كل المجلدات (الإعدادات العامة)", - "settingsScopeGlobalHint": "المجلدات بلا إعدادات خاصة تستخدم هذه الإعدادات العامة.", - "settingsSource": "مصدر الإعدادات", - "settingsSourceGlobal": "الإعدادات العامة", - "settingsSourceCustom": "إعداد خاص", - "settingsSourceGlobalFollow": "يتبع إعدادات المهام العامة — التغييرات هناك تسري هنا تلقائيًا.", - "settingsSourceCustomHint": "يحفظ إعدادات خاصة بهذا المجلد ويتوقف عن اتباع الإعدادات العامة.", - "settingsAgent": "الوكيل الافتراضي", - "settingsMaxConcurrent": "أقصى عدد للمهام المتزامنة", - "settingsMaxConcurrentHint": "0 = بلا حد", - "settingsAutoProcess": "معالجة تلقائية", - "settingsAutoProcessHint": "تبدأ المهام المعلّقة تلقائيًا ضمن حد التنفيذ المتزامن.", - "settingsMergeStrategy": "استراتيجية الدمج الافتراضية", - "settingsMergeStrategyHint": "كيفية تسجيل تغييرات المهمة في تاريخ الفرع عند الدمج.", - "settingsAutoMerge": "دمج تلقائي", - "settingsAutoMergeHint": "المهمة التي تصل إلى المراجعة وفيها تغييرات قابلة للدمج تُدمج كما لو نقرت «دمج»: يكتب الوكيل رسالة الإيداع، ويتبع الـ worktree الإعداد الافتراضي أدناه. أما المهمة التي فشل فحصها المسبق أو فشل دمجها فتبقى بانتظارك.", - "settingsDeleteWorktree": "حذف الـ worktree بعد الدمج", - "settingsDeleteWorktreeHint": "يُفعّل الخيار مسبقًا في نافذة الدمج، ويمكنك تغييره هناك.", - "settingsWorktreeRoot": "موقع الـ worktree", - "settingsWorktreeRootHint": "المجلد الذي تُنشأ فيه worktrees المهام الجديدة، واحدة لكل مهمة. اتركه فارغًا لإنشائها بجوار مجلد المشروع؛ «~» هو مجلد المنزل، والمسار النسبي يُحسب انطلاقًا من مجلد المشروع.", - "settingsWorktreeRootPlaceholder": "~/codeg-worktrees", - "settingsWorktreeRootBrowse": "اختيار مجلد الـ worktree", - "settingsPreflight": "أمر الفحص المسبق", - "settingsPreflightHint": "يعمل في شجرة العمل عندما تصل المهمة إلى المراجعة.", - "settingsPreflightCustomPlaceholder": "pnpm test", - "settingsInitCommand": "أمر تهيئة worktree", - "settingsInitCommandHint": "يعمل داخل worktree جديد قبل بدء الوكيل.", - "settingsInitCommandPlaceholder": "pnpm install", - "settingsTabGeneral": "عام", - "settingsTabMerge": "الدمج", - "settingsTabWorktree": "Worktree", - "settingsTabPrompts": "التوجيهات", - "settingsPromptsIntro": "لكل مرحلة موجّه مدمج بالفعل — المهمة نفسها، وقواعد شجرة العمل، وخطوات git الدقيقة عند الدمج. وما تضيفه هنا يُلحَق في النهاية كتعليمات إضافية: فهو يُهذّب النص المدمج ولا يستبدله أبدًا.", - "settingsPromptStageAll": "كل المراحل", - "settingsPromptPlaceholderAll": "مثال: التزم باصطلاحات ملف AGENTS.md، واجعل الملخص النهائي في جملتين", - "settingsPromptPlaceholderWork": "مثال: اقرأ الاختبارات المرتبطة أولًا، وأودِع التغييرات على خطوات صغيرة", - "settingsPromptPlaceholderRetry": "مثال: تحقق مما تم إيداعه قبل المتابعة، ولا تُعِد ما أُنجز", - "settingsPromptPlaceholderReturn": "مثلاً: عالج كل نقطة مذكورة؛ ولا تُعِد هيكلة أي شيء غير ذي صلة", - "settingsPromptPlaceholderMerge": "مثال: اكتب رسالة إيداع الدمج بالعربية، ونبّه إلى أي تعارض حللته يدويًا", - "settingsPromptHintAll": "يُلحق بكل توجيه يتلقاه الوكيل، بما في ذلك مرحلة الدمج.", - "settingsPromptHintWork": "يُلحق عند تنفيذ المهمة لأول مرة.", - "settingsPromptHintRetry": "يُلحق عند استئناف مهمة متوقفة أو فاشلة.", - "settingsPromptHintReturn": "يُضاف عند متابعة مهمة قيد المراجعة (إعادة عمل، عمل إضافي، مراجعة ذاتية).", - "settingsPromptHintMerge": "يُلحق عندما يدمج الوكيل المهمة في الفرع الأساسي.", - "preflightPassed": "نجح {name}", - "preflightFailed": "فشل {name}", - "preflightRunning": "{name} قيد التشغيل…", - "detailDescription": "تفاصيل المهمة", - "detailSummary": "النتيجة", - "detailFiles": "الملفات المتغيرة", - "detailDiffAll": "عرض كامل الفروق", - "detailDiffAllTitle": "كامل الفروق", - "detailNoChanges": "لا تغييرات بعد مقارنةً بالأساس", - "detailTimeline": "سجل التقدم", - "detailTimelineEmpty": "لا نشاط بعد", - "showMore": "عرض المزيد", - "showLess": "عرض أقل", - "detailInfo": "التفاصيل", - "detailBranch": "الفرع", - "detailMergeCommit": "إيداع الدمج", - "detailChanges": "التغييرات", - "detailScheduled": "البدء المجدول", - "detailCreated": "تاريخ الإنشاء", - "detailStarted": "تاريخ البدء", - "detailFinished": "تاريخ الانتهاء", - "diffLoading": "جارٍ تحميل الفروق…", - "deleteConfirmTitle": "حذف المهمة؟", - "deleteConfirmBody": "ستُزال “{title}” من اللوحة. يُلغى التشغيل النشط أولًا.", - "deleteWithWorktree": "حذف الـ worktree الخاص بها أيضًا", - "eventCreated": "أُنشئت", - "eventStatusChanged": "تغيّر الحالة", - "eventConfigEffective": "إعداد الإطلاق", - "eventInitCommand": "أمر التهيئة", - "eventAgentProgress": "تقدّم الوكيل", - "eventAgentVerdict": "حكم الوكيل", - "eventMergeAttempt": "بدأ الدمج", - "eventMergeQueued": "أُضيف إلى طابور الدمج", - "eventMergeConflict": "تعارض دمج", - "eventPreflight": "فحص مسبق", - "eventCleanupFailed": "فشل تنظيف worktree", - "eventResumeFallback": "فشل استئناف الجلسة؛ استُخدمت جلسة جديدة", - "eventUserAction": "إجراء المستخدم", - "eventDiffStat": "لقطة التغييرات" - }, - "CustomSkillsSettings": { - "loading": "جارٍ تحميل المهارات المخصّصة…", - "category": "مخصّصة", - "searchPlaceholder": "ابحث عن المهارات المخصّصة بالاسم أو المعرّف أو الوصف", - "states": { - "not_linked": "غير مُفعّلة", - "linked_to_codeg": "مُفعّلة", - "linked_elsewhere": "مرتبطة في مكان آخر", - "blocked_by_real_directory": "محجوبة بمجلد فعلي", - "broken": "رابط معطوب" - }, - "actions": { - "new": "جديدة", - "import": "استيراد", - "importFromAgent": "استيراد من وكيل", - "cancel": "إلغاء", - "save": "حفظ" - }, - "rowMenu": { - "edit": "تعديل", - "duplicate": "تكرار", - "delete": "حذف" - }, - "bulk": { - "delete": "حذف المحدد" - }, - "editor": { - "createTitle": "مهارة مخصّصة جديدة", - "editTitle": "تعديل مهارة مخصّصة", - "description": "تُحفَظ المهارات المخصّصة في المخزن المشترك (~/.codeg/skills) ويمكن تفعيلها لأي وكيل.", - "idLabel": "معرّف المهارة", - "idPlaceholder": "مثال: my-workflow", - "contentLabel": "SKILL.md", - "contentPlaceholder": "اكتب هنا ملف SKILL.md للمهارة…", - "preview": "معاينة", - "edit": "تعديل", - "emptyBody": "لا يوجد محتوى بعد." - }, - "duplicate": { - "title": "تكرار المهارة", - "description": "إنشاء نسخة من «{id}» بمعرّف جديد.", - "newIdPlaceholder": "معرّف المهارة الجديد", - "confirm": "تكرار" - }, - "import": { - "title": "اختر مجلد مهارة للاستيراد" - }, - "importFromAgent": { - "title": "استيراد المهارات من وكيل", - "description": "انسخ مهارات الوكيل الخاصة إلى المخزن المشترك لتفعيلها لأي وكيل.", - "agentLabel": "الوكيل", - "agentPlaceholder": "اختر وكيلاً", - "selectAll": "تحديد الكل ({count})", - "loading": "جارٍ تحميل مهارات الوكيل…", - "unsupported": "لا يوفّر هذا الوكيل دليل مهارات.", - "empty": "لا توجد مهارات قابلة للاستيراد لهذا الوكيل.", - "alreadyInLibrary": "في المكتبة", - "confirm": "استيراد المحدد ({count})" - }, - "delete": { - "title": "حذف المهارات المخصّصة؟", - "body": "سيؤدي هذا إلى إزالة {count} مهارة مخصّصة من المخزن المركزي وفصل روابطها من كل وكيل. لا يمكن التراجع عن ذلك.", - "confirm": "حذف" - }, - "toasts": { - "loadFailed": "فشل تحميل المهارة", - "idRequired": "أدخل معرّف المهارة", - "created": "تم إنشاء المهارة المخصّصة", - "updated": "تم تحديث المهارة المخصّصة", - "saveFailed": "فشل حفظ المهارة", - "imported": "تم استيراد المهارة", - "importFailed": "فشل استيراد المهارة", - "duplicated": "تم تكرار المهارة", - "duplicateFailed": "فشل تكرار المهارة", - "deleted": "تم حذف {count} مهارة", - "deletedPartial": "تم حذف {ok}، وفشل {failed}", - "deleteFailed": "فشل حذف المهارات", - "importedFromAgent": "تم استيراد {count} مهارة", - "importedFromAgentPartial": "تم استيراد {ok}، وفشل {failed}", - "importFromAgentAllSkipped": "لا شيء للاستيراد — {count} موجودة بالفعل في المكتبة", - "importFromAgentFailed": "فشل الاستيراد من الوكيل" - } - }, - "CodexModelEditor": { - "customizedNotice": "لقد خصّصت قائمة النماذج، لذا يدير codeg الآن جدول نماذج codex بالكامل. لن تظهر النماذج الرسمية التي يضيفها codex لاحقًا تلقائيًا — انقر على زر التحديث بالأسفل ثم احفظ مرة أخرى لمزامنتها. امسح كل تخصيصاتك ليعود codex إلى التحديث تلقائيًا.", - "officialsTitle": "النماذج الرسمية", - "officialsHint": "تُضاف تلقائيًا من codex الذي تشغّله؛ احذف ما لا تريده.", - "officialsEmpty": "لا توجد نماذج رسمية متاحة.", - "refresh": "تحديث من codex", - "readdOfficial": "إعادة إضافة رسمي", - "customsTitle": "النماذج المخصّصة", - "customsEmpty": "لا توجد نماذج مخصّصة بعد.", - "addCustom": "إضافة مخصص", - "slugPlaceholder": "معرّف النموذج (slug)", - "displayNamePlaceholder": "الاسم المعروض", - "contextWindow": "السياق", - "makeDefault": "تعيين كافتراضي", - "defaultHint": "النموذج الافتراضي", - "remove": "إزالة", - "advanced": "متقدم", - "baseTemplate": "القالب الأساسي", - "baseTemplateHint": "النموذج الرسمي الذي تُنسخ منه الحقول المطلوبة (موجّه النظام، الأدوات، الحدود).", - "groupBehavior": "السلوك والقدرات", - "fieldReasoningLevel": "الاستدلال الافتراضي", - "fieldReasoningSummary": "ملخص الاستدلال", - "fieldVerbosity": "مستوى التفصيل", - "fieldShellType": "نوع الصدفة", - "fieldApplyPatch": "أداة تطبيق التصحيح", - "fieldReasoningSummaries": "ملخصات الاستدلال", - "fieldSupportVerbosity": "التحكم في التفصيل", - "fieldParallelToolCalls": "استدعاءات الأدوات المتوازية", - "fieldSearchTool": "أداة البحث على الويب", - "optNone": "بلا", - "groupInstructions": "الوصف وموجّه النظام", - "fieldDescription": "الوصف", - "baseInstructions": "موجّه النظام (base_instructions)" - }, - "DiagnosticsSettings": { - "title": "تشخيص البيئة", - "description": "يتحقق من كيفية تحليل هذا التطبيق لواجهة سطر أوامر الوكيل داخل عمليته الخاصة، وقد يختلف ذلك عن الطرفية لديك.", - "loading": "جارٍ تشغيل التشخيص…", - "error": "فشل التشخيص", - "rerun": "إعادة التشغيل", - "copyAll": "نسخ الكل", - "copied": "تم نسخ التشخيص إلى الحافظة", - "button": "تشخيص", - "verdict": { - "ok": "تبدو البيئة سليمة. إذا استمر ظهوره كغير مُثبَّت، فأعد تشغيل التطبيق بالكامل لتحديث ذاكرة التخزين المؤقتة للبادئة.", - "node_missing": "لم يتم العثور على Node.js في مسار PATH الخاص بالتطبيق.", - "npm_missing": "لم يتم العثور على npm في مسار PATH الخاص بالتطبيق.", - "not_installed": "يبدو أن هذا الوكيل غير مُثبَّت.", - "installed_but_unresolved": "مُسجَّل كمُثبَّت، لكن لا يستطيع التطبيق تحديد موقع الملف التنفيذي.", - "user_prefix_not_on_path": "تم التثبيت في بادئة الاحتياط (~/.codeg/npm-global)، وهي ليست في مسار PATH الخاص بالتطبيق. أعد تشغيل التطبيق بالكامل وحاول مرة أخرى.", - "homebrew_bin_not_on_path": "تم التثبيت ضمن مجلد bin الخاص بـ Homebrew، وهو ليس في مسار PATH الخاص بالتطبيق (فصل keg على Apple Silicon).", - "terminal_only_path": "يُحلَّل الأمر في الطرفية لديك لكن ليس في التطبيق — وهي فجوة في مسار PATH لواجهة المستخدم الرسومية. شغّل التطبيق من الطرفية أو أعد التثبيت من إعدادات الوكلاء.", - "npm_prefix_timeout": "كان npm prefix -g بطيئًا جدًا (أكثر من 1.5 ثانية)، لذا تم تخطّي الكشف الاحتياطي. أعد تشغيل التطبيق وحاول مرة أخرى.", - "node_too_old": "إصدار Node.js النشط أقدم مما يتطلبه هذا الوكيل. يرجى ترقية Node.js.", - "adapter_missing_native_present": "واجهة {agent} لديك مثبّتة فعلاً، لكن Codeg يشغّل حزمة محوّل ACP منفصلة، وهي غير مثبّتة بعد. ثبّتها من إعدادات الوكلاء؛ فهي لا تمسّ واجهتك وتتشارك تسجيل الدخول نفسه.", - "adapter_missing": "يشغّل Codeg حزمة محوّل ACP منفصلة من أجل {agent}، وهي غير مثبّتة بعد. ثبّتها من إعدادات الوكلاء — لا يكفي تثبيت واجهة الأوامر الرسمية وحدها." - } - }, - "TokenUsage": { - "title": "استهلاك الرموز", - "rangeLabel": "النطاق الزمني", - "range7d": "٧ أيام", - "range30d": "٣٠ يومًا", - "range90d": "٩٠ يومًا", - "rangeThisMonth": "هذا الشهر", - "rangeThisYear": "هذا العام", - "rangeAll": "الكل", - "rangeCustom": "مخصص", - "moreRanges": "المزيد", - "customRangePick": "اختر نطاقاً زمنياً", - "bucketLabel": "التجميع حسب", - "bucketDay": "يوم", - "bucketWeek": "أسبوع", - "bucketMonth": "شهر", - "bucketUnitDay": "يوم", - "bucketUnitWeek": "أسبوع", - "bucketUnitMonth": "شهر", - "folderFilter": "المجلدات", - "allFolders": "كل المجلدات", - "agentFilter": "الوكلاء", - "allAgents": "كل الوكلاء", - "modelFilter": "النماذج", - "allModels": "كل النماذج", - "searchPlaceholder": "بحث…", - "noMatches": "لا توجد نتائج", - "clearFilter": "مسح التحديد", - "resetFilters": "إعادة ضبط المرشحات", - "refresh": "تحديث", - "rebuild": "إعادة بناء الكل", - "rebuildHint": "يتجاهل البيانات المحسوبة ويعيد قراءة كل سجلات الجلسات. استخدمه إذا نمت جلسة خارج codeg.", - "syncing": "جارٍ حساب الجلسات…", - "syncProgress": "{done} / {total}", - "syncDone": "تم حساب {synced} جلسة", - "syncFailed": "تعذّرت قراءة بعض الجلسات", - "syncBusy": "هناك تحديث قيد التشغيل بالفعل", - "lastSynced": "حُدّث {time}", - "lastSyncedNever": "لم يُحدَّث بعد", - "tileTotal": "إجمالي الرموز", - "tileSessions": "الجلسات", - "tileTurns": "الأدوار", - "tileActiveDays": "الأيام النشطة", - "tileGenTime": "زمن التوليد", - "vsPrevious": "مقارنة بالفترة السابقة", - "deltaNew": "جديد", - "trendTitle": "الاستهلاك عبر الزمن", - "trendEmpty": "لا استهلاك في هذا النطاق", - "trendTurns": "الأدوار", - "trendSessions": "الجلسات", - "compositionTitle": "أين ذهبت الرموز", - "compositionHint": "الإدخال هو ما أرسلته، والإخراج ما كتبه النموذج، وقراءات الذاكرة المؤقتة سياق لم تدفع ثمنه كاملًا.", - "compositionNote": "إعادة إرسال هذه الإصابات المؤقتة بالسعر الكامل كانت ستكلف {value} إضافية.", - "inputTokens": "إدخال", - "outputTokens": "إخراج", - "cacheWrite": "كتابة مؤقتة", - "cacheRead": "قراءة مؤقتة", - "freshTokens": "حساب جديد", - "cacheHitCaption": "إصابة مؤقتة", - "cacheHeroTitleHigh": "معظم السياق لم يُعَد إرساله", - "cacheHeroTitleLow": "معظم السياق ما زال يُحسب بالسعر الكامل", - "cacheHeroDesc": "حملت الذاكرة المؤقتة {cached} من السياق، ولم يُحسب من جديد سوى {fresh} في هذه الفترة.", - "cacheSavedSuffix": "وفّر ذلك ما يعادل {saved} من إعادة الإرسال.", - "avgPerSession": "المتوسط لكل جلسة", - "avgTurnsPerSession": "{count} دورة لكل جلسة في المتوسط", - "avgPerActiveDay": "المتوسط لكل يوم نشط", - "peakBucket": "أعلى {bucket}", - "peakHour": "ساعة الذروة", - "daysValue": "{count} يومًا", - "idleDays": "أيام الخمول", - "byFolderTitle": "حسب المجلد", - "byAgentTitle": "حسب الوكيل", - "byModelTitle": "حسب النموذج", - "distributionTitle": "توزيع الاستخدام", - "distributionHint": "تُجمَّع الجلسات والرموز حسب البعد المحدد — انقر أي صف للتصفية به.", - "otherLabel": "أخرى", - "unknownModel": "نموذج غير مسجَّل", - "emptyBreakdown": "لا توجد سجلات بعد", - "sessionsCount": "{count} جلسة", - "heatmapTitle": "إيقاع عملك", - "heatmapHint": "الرموز حسب اليوم والساعة بالتوقيت المحلي.", - "heatmapPeakHint": "الأكثر كثافة حوالي {hour}:00.", - "less": "أقل", - "more": "أكثر", - "heatmapCell": "{weekday} {hour}:00 — {value} رمز", - "weekMon": "إث", - "weekTue": "ثل", - "weekWed": "أر", - "weekThu": "خم", - "weekFri": "جم", - "weekSat": "سب", - "weekSun": "أح", - "topSessionsTitle": "أكثر الجلسات استهلاكًا", - "untitledSession": "جلسة بلا عنوان", - "topSessionsEmpty": "لا جلسات في هذا النطاق", - "streakLongest": "أطول سلسلة", - "streakLongestDays": "أطول سلسلة: {count} يومًا", - "share": "مشاركة", - "moreActions": "مزيد من الإجراءات", - "shareDialogTitle": "شارك بطاقة استهلاكك", - "shareDialogHint": "لقطة للنطاق والمرشحات التي تعرضها الآن.", - "shareSave": "حفظ الصورة", - "shareCopy": "نسخ الصورة", - "shareCopied": "تم النسخ إلى الحافظة", - "shareSaved": "تم حفظ الصورة", - "shareFailed": "تعذّر إنشاء الصورة", - "shareRendering": "جارٍ الإنشاء…", - "cardHeading": "سجلّي في البرمجة بالذكاء الاصطناعي", - "cardRangeAll": "كل الفترات", - "cardTotalLabel": "الرموز المستهلكة", - "cardFooter": "صُنع بواسطة codeg", - "cardTopModels": "أبرز النماذج", - "cardTopProjects": "أبرز المشاريع", - "archetypeNightOwl": "بومة الليل", - "archetypeNightOwlDesc": "{percent}% من رموزك تُستهلك بعد حلول الظلام.", - "archetypeEarlyBird": "المستيقظ باكرًا", - "archetypeEarlyBirdDesc": "{percent}% من رموزك تُستهلك قبل التاسعة صباحًا.", - "archetypeWeekendWarrior": "محارب عطلة الأسبوع", - "archetypeWeekendWarriorDesc": "{percent}% من رموزك تحدث في عطلة الأسبوع.", - "archetypeCacheMaster": "سيد الذاكرة المؤقتة", - "archetypeCacheMasterDesc": "{percent}% من سياقك جاء من الذاكرة المؤقتة.", - "archetypeMarathoner": "عدّاء المسافات", - "archetypeMarathonerDesc": "{days} يومًا من البناء دون انقطاع.", - "archetypePolyglot": "متعدد المهارات", - "archetypePolyglotDesc": "{count} وكلاء في استخدام جادّ.", - "archetypeLaserFocus": "تركيز مطلق", - "archetypeLaserFocusDesc": "{percent}% من رموزك ذهبت لمشروع واحد.", - "archetypeDeepDiver": "الغوّاص", - "archetypeDeepDiverDesc": "{averageK}K رمز في الجلسة الواحدة وسطيًا.", - "archetypeSteady": "بنّاء ثابت", - "archetypeSteadyDesc": "{days} يومًا من الإنجاز.", - "emptyTitle": "لا توجد بيانات محسوبة بعد", - "emptyHint": "يقرأ codeg أعداد الرموز مباشرة من سجل كل وكيل. حدّث لتُحسب الجلسات الموجودة على هذا الجهاز.", - "emptyAction": "احسب جلساتي", - "loadFailed": "تعذّر تحميل بيانات الاستهلاك", - "truncatedNotice": "هذا النطاق واسع جدًا — الأرقام تغطي أحدث جزء منه فقط." - } -} +{ + "Language": { + "followSystem": "اتباع النظام", + "english": "الإنجليزية", + "simplifiedChinese": "الصينية المبسطة", + "traditionalChinese": "الصينية التقليدية", + "japanese": "اليابانية", + "korean": "الكورية", + "spanish": "الإسبانية", + "german": "الألمانية", + "french": "الفرنسية", + "portuguese": "البرتغالية", + "arabic": "العربية" + }, + "GitCredentialDialog": { + "title": "المصادقة مطلوبة", + "description": "يتطلب الخادم البعيد بيانات اعتماد. أدخل اسم المستخدم وكلمة المرور (أو رمز الوصول الشخصي).", + "username": "اسم المستخدم", + "usernamePlaceholder": "اسم المستخدم أو البريد الإلكتروني", + "password": "كلمة المرور / الرمز", + "passwordPlaceholder": "كلمة المرور أو رمز الوصول الشخصي", + "passwordHint": "أدخل اسم المستخدم وكلمة المرور للخادم.", + "cancel": "إلغاء", + "authenticate": "مصادقة", + "authenticating": "جارٍ المصادقة...", + "invalidCredentials": "بيانات الاعتماد غير صالحة. يرجى المحاولة مرة أخرى.", + "saveCredentials": "حفظ بيانات الاعتماد للعمليات المستقبلية", + "githubTitle": "مصادقة GitHub", + "githubDescription": "أدخل رمز وصول شخصي للاتصال بـ GitHub. سيتم التحقق من الرمز وحفظه تلقائيًا.", + "githubToken": "رمز الوصول الشخصي", + "githubTokenPlaceholder": "ghp_xxxxxxxxxxxx", + "githubTokenHint": "أنشئ رمزًا في GitHub → Settings → Developer settings → Personal access tokens.", + "githubAuthenticate": "التحقق والاتصال", + "generateToken": "إنشاء رمز" + }, + "SettingsShell": { + "title": "الإعدادات", + "preferences": "التفضيلات", + "nav": { + "general": "عام", + "appearance": "المظهر", + "agents": "الوكلاء", + "mcp": "MCP", + "skills": "Skills", + "shortcuts": "الاختصارات", + "version_control": "التحكم بالإصدارات", + "system": "النظام", + "chat_channels": "قنوات المحادثة", + "web_service": "خدمة الويب", + "model_providers": "مزودو النماذج", + "experts": "الخبراء", + "science": "البحث العلمي", + "office_tools": "أدوات المكتب", + "skill_packs": "حزم المهارات", + "quick_messages": "رسائل سريعة", + "logs": "سجلات التشغيل" + } + }, + "AppearanceSettings": { + "sectionTitle": "مظهر السمة", + "sectionDescription": "اختر الفاتح أو الداكن أو اتباع النظام. يتم حفظ الإعدادات تلقائيًا.", + "themeMode": "وضع السمة", + "placeholder": "اختر وضع السمة", + "system": "اتباع النظام", + "light": "فاتح", + "dark": "داكن", + "currentTheme": "السمة الفعالة الحالية: {theme}", + "resolvedTheme": { + "light": "فاتح", + "dark": "داكن", + "unknown": "--" + }, + "themeColor": { + "sectionTitle": "لون السمة", + "sectionDescription": "اختر لوحة ألوان للتمييزات والأزرار والإبرازات.", + "current": "اللون الحالي: {color}", + "options": { + "neutral": "Neutral", + "zinc": "Zinc", + "slate": "Slate", + "stone": "Stone", + "gray": "Gray", + "red": "Red", + "rose": "Rose", + "orange": "Orange", + "green": "Green", + "blue": "Blue", + "yellow": "Yellow", + "violet": "Violet" + } + }, + "customStyle": { + "sectionTitle": "نمط مخصص", + "sectionDescription": "اضبط ألوان السمة الحالية بدقة، أو أدرج CSS خاصًا بك. تُطبَّق التجاوزات فوق الإعداد الأساسي، لذا تبقى عند تبديل الإعداد.", + "summarySuspended": "موقوف مؤقتًا", + "summaryDefault": "الإعداد الأساسي دون تغيير", + "summaryTokens": "{count, plural, one {# تجاوز} other {# تجاوزات}}", + "summaryCss": "CSS مخصص", + "suspendedByShortcut": "النمط المخصص موقوف مؤقتًا. لن يسري أي إعداد هنا حتى تستأنفه.", + "suspendedBySafeParam": "فُتحت هذه النافذة في وضع المظهر الآمن، لذا يُتجاهل النمط المخصص هنا. لا تتأثر النوافذ الأخرى.", + "resume": "استئناف النمط المخصص", + "enableTheme": "تفعيل الألوان المخصصة", + "editingLight": "تحرير قيم الوضع الفاتح. بدّل التطبيق إلى الوضع الداكن لضبطه على حدة.", + "editingDark": "تحرير قيم الوضع الداكن. بدّل التطبيق إلى الوضع الفاتح لضبطه على حدة.", + "resetToken": "إعادة التعيين إلى قيمة الإعداد", + "radius": "استدارة الزوايا", + "radiusHint": "يشتق منها مقياس الاستدارة كاملًا من sm إلى 4xl، لذا يكفي شريط واحد لتغيير استدارة التطبيق بأكمله.", + "advanced": "متقدم ({count} متغيرات إضافية)", + "enableCss": "تفعيل CSS المخصص", + "cssRisk": "ميزة متقدمة. يتجاوز CSS المخصص جميع الأنماط المدمجة وقد يجعل الواجهة غير قابلة للاستخدام.", + "editCss": "تحرير CSS…", + "cssPresent": "تم حفظ {size} كيلوبايت", + "cssEmpty": "لا يوجد محتوى محفوظ بعد", + "escapeHint": "هل تعطلت الواجهة؟ اضغط {shortcut} لإيقاف كل النمط المخصص، أو افتح نافذة بمعامل الاستعلام safeStyle=1.", + "copyTheme": "نسخ JSON السمة", + "importTheme": "استيراد سمة…", + "clearTheme": "مسح التجاوزات", + "interopHint": "تستخدم السمات صيغة registry:theme من shadcn، فيمكنك لصق أي سمة shadcn هنا واستخدام سماتك المصدَّرة في أي مشروع shadcn.", + "importTitle": "استيراد سمة", + "importDescription": "الصق عنصر registry:theme من shadcn، أو كائن light/dark مجردًا، أو خريطة رموز مسطحة.", + "readClipboard": "قراءة الحافظة", + "importConfirm": "استيراد", + "cancel": "إلغاء", + "apply": "تطبيق", + "toasts": { + "copied": "تم نسخ JSON السمة", + "copyFailed": "تعذّر النسخ إلى الحافظة", + "clipboardReadFailed": "تعذّرت قراءة الحافظة، الصق يدويًا", + "importFailed": "لا توجد متغيرات سمة صالحة في هذا الـ JSON", + "imported": "تم استيراد السمة" + }, + "css": { + "dialogTitle": "CSS مخصص", + "dialogDescription": "يسري على جميع نوافذ codeg. تُعاين التغييرات مباشرة؛ اضغط تطبيق للحفظ.", + "size": "{used} كيلوبايت / {max} كيلوبايت", + "ruleCount": "{count} قاعدة", + "errorTooLarge": "الحجم كبير جدًا للحفظ. قلّصه إلى ما دون الحد.", + "errorImportEscaped": "بقيت قاعدة @import بعد الإزالة (صيغة هروب). أزلها للحفظ.", + "warnNoRules": "لم يُحلَّل أي قاعدة، تحقق من الصياغة.", + "noticeImportsRemoved": "قواعد @import المُزالة: {count}. كانت ستجلب أوراق أنماط بعيدة.", + "noticeRemoteUrl": "يحتوي على url() بعيد، وسيُصدر طلب شبكة عند التطبيق.", + "noticePreviewSuspended": "النمط المخصص موقوف، لذا لا تُطبَّق هذه المعاينة.", + "noticeDisabled": "CSS المخصص متوقف. يمكنك المعاينة هنا، لكن لن يسري شيء حتى تفعّله.", + "hintTokens": "تلميح: الألوان التي تجاوزتها متاحة عبر var(--primary) و var(--background) وغيرها." + } + }, + "zoomLevel": { + "sectionTitle": "تكبير النافذة", + "sectionDescription": "تكبير أو تصغير الواجهة بالكامل. يتم تطبيقه فوراً ويُحفظ لكل جهاز على حدة.", + "placeholder": "اختر مستوى التكبير", + "default": "افتراضي", + "current": "التكبير الحالي: {zoom}%" + }, + "fonts": { + "sectionTitle": "الخطوط", + "sectionDescription": "اختر خطوطًا للواجهة ومحرّر الأكواد والطرفية. تُحمّل الخطوط المضمّنة عند الحاجة؛ اختر «مخصّص…» لاستخدام أي خط مثبّت على نظامك.", + "interface": "الواجهة", + "editor": "المحرّر", + "terminal": "الطرفية", + "groupSans": "بلا زوائد", + "groupMono": "ثابت العرض", + "custom": "مخصّص…", + "customPlaceholder": "اسم الخط، مثل Fira Code", + "fontSize": "حجم الخط", + "ligatures": "تفعيل الحروف المتصلة", + "ligaturesUnavailable": "هذا الخط لا يحتوي على حروف متصلة", + "wordWrap": "تفعيل التفاف النص", + "terminalLigaturesHint": "تنطبق الحروف المتصلة في الطرفية على خطوط البرمجة المضمّنة فقط.", + "preview": "معاينة" + }, + "welcomePanel": { + "sectionTitle": "منطقة اختيار الوضع", + "sectionDescription": "بطاقات الاختصار «تطوير الكود / الأعمال المكتبية» التي تظهر أعلى مربع الإدخال في صفحة المحادثة الجديدة.", + "showQuickActions": "العرض في صفحة المحادثة الجديدة" + }, + "workspaceBackground": { + "sectionTitle": "خلفية مساحة العمل", + "sectionDescription": "عرض صورة خلف مساحة العمل بالكامل. يصبح الشريط الجانبي واللوحات شبه شفافة ومصنفرة لتظهر الصورة من خلالها، ويحافظ القناع على وضوح النص.", + "enable": "تفعيل صورة الخلفية", + "image": "الصورة", + "chooseImage": "اختيار صورة", + "replaceImage": "استبدال الصورة", + "removeImage": "إزالة", + "fillMode": "وضع الملء", + "fillModes": { + "cover": "تغطية", + "contain": "احتواء", + "center": "توسيط", + "tile": "تكرار" + }, + "maskOpacity": "عتامة القناع", + "maskOpacityHint": "القيم الأعلى تمزج الصورة نحو لون خلفية السمة، مما يحسّن تباين النص.", + "imageBlur": "تمويه الصورة", + "panelOpacity": "عتامة اللوحات", + "panelOpacityHint": "مدى عتامة الشريط الجانبي واللوحات وأشرطة التبويب. الأقل يُظهر المزيد من الصورة.", + "errorTooLarge": "الصورة كبيرة جدًا (16 ميجابايت كحد أقصى).", + "errorUploadFailed": "فشل تعيين صورة الخلفية." + } + }, + "SystemSettings": { + "loading": "جارٍ التحميل...", + "sectionTitle": "إدارة النظام", + "sectionDescription": "إدارة وكيل الشبكة وتحديثات التطبيق وتفضيلات اللغة.", + "proxyTitle": "وكيل الشبكة", + "proxyDescription": "عند التفعيل، ستُفضَّل إعدادات هذا الوكيل في طلبات الشبكة اللاحقة (بما في ذلك دردشة ACP وتثبيت الوكلاء وعمليات Git البعيدة).", + "loadFailed": "فشل التحميل: {message}", + "enableProxy": "تفعيل وكيل النظام", + "proxyAddress": "عنوان الوكيل", + "proxyHint": "يدعم http(s)/socks5، مثال: {example}. يعمل فقط عند تفعيل وكيل النظام.", + "save": "حفظ", + "saving": "جارٍ الحفظ...", + "proxyRequired": "عنوان URL للوكيل مطلوب عند تفعيل الوكيل", + "saveSuccess": "تم حفظ إعدادات وكيل النظام", + "saveFailed": "فشل الحفظ: {message}", + "languageTitle": "اللغة", + "languageDescription": "حدد لغة التطبيق. عند اتباع لغة النظام، ستعود اللغات غير المدعومة إلى الإنجليزية.", + "appLanguage": "لغة التطبيق", + "languageSaveSuccess": "تم حفظ إعدادات اللغة", + "languageSaveFailed": "فشل حفظ إعدادات اللغة: {message}", + "updateTitle": "تحديث التطبيق", + "versionTitle": "تحديث البرنامج", + "updateDescription": "تحقق من المصدر المهيأ للإصدارات الأحدث وثبّت التحديث مباشرة عند توفره.", + "currentVersion": "الإصدار الحالي", + "upgradableVersion": "أحدث إصدار", + "none": "لا يوجد", + "lastChecked": "آخر فحص: {time}", + "updateError": "خطأ في التحديث: {message}", + "checking": "جارٍ التحقق...", + "checkUpdate": "التحقق من التحديثات", + "updating": "جارٍ التثبيت...", + "downloading": "جارٍ التنزيل...", + "upgradeTo": "الترقية إلى v{version}", + "viewRelease": "عرض إصدار v{version}", + "foundUpdate": "تم العثور على إصدار جديد v{version}", + "alreadyLatest": "أنت على أحدث إصدار", + "checkUpdateFailed": "فشل التحقق من التحديثات: {message}", + "installSuccess": "تم تثبيت التحديث. جارٍ إعادة تشغيل التطبيق.", + "installFailed": "فشل التحديث: {message}", + "upgradeSuccess": "اكتملت الترقية. جارٍ إعادة التحميل...", + "restartTimeout": "لم يعد الخادم في الوقت المناسب. تحقق من سجلات الحاوية أو الخدمة.", + "restartingIn": "إعادة التشغيل خلال {seconds} ثانية...", + "waitingForServer": "في انتظار عودة الخادم...", + "restartToUpdate": "أعد التشغيل للتحديث", + "newVersionBadge": "إصدار جديد v{version}", + "updateAvailableTitle": "يتوفر تحديث", + "releaseNotesTitle": "ما الجديد", + "remindLater": "لاحقًا", + "retry": "إعادة المحاولة", + "stepDownload": "التنزيل", + "stepInstall": "التثبيت", + "stepRestart": "إعادة التشغيل", + "updateReadyHint": "تم تنزيل التحديث — أعد التشغيل لتطبيقه.", + "restarting": "جارٍ إعادة التشغيل...", + "dockerUpgradeHint": "يؤدي هذا إلى ترقية الحاوية قيد التشغيل الآن. وتُفقد عند إعادة إنشاء الحاوية — وللاحتفاظ بها، اسحب أو ابنِ صورة بالإصدار الجديد ثم أعد إنشاء الحاوية.", + "upgradeRolledBack": "فشلت الترقية؛ عاد الخادم إلى الإصدار السابق.", + "serverUnreachable": "تعذّر الوصول إلى الخادم لبدء الترقية. تأكد من أنه قيد التشغيل وحاول مرة أخرى.", + "rollbackButton": "التراجع", + "rollingBack": "جارٍ التراجع...", + "rollbackDescription": "استعادة الإصدار المثبَّت قبل آخر ترقية.", + "rollbackConfirmTitle": "التراجع إلى الإصدار السابق؟", + "rollbackConfirmDescription": "ستعيد الخادم التشغيل على الإصدار المثبَّت قبل آخر ترقية. ويبقى الإصدار الأحدث متاحًا لإعادة التثبيت.", + "rollbackConfirm": "التراجع", + "rollbackCancel": "إلغاء", + "rollbackSuccess": "تم التراجع إلى الإصدار السابق. جارٍ إعادة التحميل...", + "rollbackFailed": "فشل التراجع. تحقّق من سجلات الخادم.", + "updateErrors": { + "sourceUnavailable": "تعذر الوصول إلى مصدر التحديث. تحقق من الشبكة أو الوكيل ثم أعد المحاولة.", + "network": "فشل اتصال الشبكة. تحقق من الشبكة أو الوكيل ثم أعد المحاولة.", + "downloadFailed": "فشل تنزيل حزمة التحديث. يرجى المحاولة مرة أخرى لاحقًا.", + "installFailed": "فشل تثبيت التحديث. يرجى إغلاق التطبيق ثم إعادة المحاولة.", + "unknown": "فشل التحديث. يرجى المحاولة مرة أخرى لاحقًا." + } + }, + "VersionControlSettings": { + "loading": "جارٍ التحميل...", + "sectionTitle": "التحكم بالإصدارات", + "sectionDescription": "تكوين ملف Git التنفيذي وإدارة حسابات GitHub.", + "gitTitle": "إعدادات Git", + "gitDescription": "تكوين ملف Git التنفيذي المستخدم بواسطة التطبيق.", + "gitDetected": "تم اكتشاف Git", + "gitNotFound": "لم يتم العثور على Git في النظام", + "gitVersion": "الإصدار", + "gitPath": "المسار", + "customGitPath": "مسار Git مخصص", + "customGitPathPlaceholder": "/usr/bin/git", + "customGitPathHint": "اتركه فارغًا لاستخدام المسار المكتشف تلقائيًا.", + "test": "اختبار", + "testing": "جارٍ الاختبار...", + "testSuccess": "ملف Git التنفيذي صالح.", + "testFailed": "فشل اختبار Git: {message}", + "save": "حفظ", + "saving": "جارٍ الحفظ...", + "saveSuccess": "تم حفظ إعدادات Git.", + "saveFailed": "فشل الحفظ: {message}", + "githubTitle": "حسابات GitHub", + "githubDescription": "إدارة حسابات GitHub للمصادقة. يتم تخزين الرموز محليًا.", + "noAccounts": "لا توجد حسابات GitHub مكوّنة.", + "addAccount": "إضافة حساب", + "serverUrl": "عنوان الخادم", + "serverUrlPlaceholder": "https://github.com", + "token": "رمز الوصول الشخصي", + "tokenPlaceholder": "ghp_xxxxxxxxxxxx", + "generateToken": "إنشاء رمز", + "tokenHint": "أنشئ رمزًا في GitHub → Settings → Developer settings → Personal access tokens.", + "validateAndAdd": "التحقق والإضافة", + "validating": "جارٍ التحقق...", + "addSuccess": "تمت إضافة الحساب {username} بنجاح.", + "addFailed": "فشل إضافة الحساب: {message}", + "testConnection": "اختبار", + "connectionSuccess": "نجح الاتصال.", + "connectionFailed": "فشل الاتصال: {message}", + "setDefault": "تعيين كافتراضي", + "defaultLabel": "افتراضي", + "defaultSet": "تم تحديث الحساب الافتراضي.", + "removeAccount": "إزالة", + "removeConfirmTitle": "إزالة الحساب", + "removeConfirmMessage": "هل أنت متأكد من إزالة الحساب \"{username}\"؟", + "removeConfirm": "إزالة", + "removeCancel": "إلغاء", + "removeSuccess": "تمت إزالة الحساب.", + "scopes": "النطاقات", + "loadFailed": "فشل تحميل الإعدادات: {message}", + "gitAccount": { + "sectionTitle": "حسابات خادم Git", + "sectionDescription": "إدارة بيانات الاعتماد لخوادم Git غير GitHub (GitLab، Bitbucket، الخوادم الذاتية، إلخ).", + "noAccounts": "لا توجد حسابات خادم Git مكوّنة.", + "addAccount": "إضافة حساب", + "addTitle": "إضافة حساب Git", + "addDescription": "أدخل عنوان الخادم واسم المستخدم وكلمة المرور أو رمز الوصول.", + "serverUrl": "عنوان الخادم", + "serverUrlPlaceholder": "https://gitlab.example.com", + "username": "اسم المستخدم", + "usernamePlaceholder": "اسم المستخدم أو البريد الإلكتروني", + "password": "كلمة المرور / الرمز", + "passwordPlaceholder": "كلمة المرور أو رمز الوصول", + "passwordHint": "أدخل كلمة مرور الخادم أو رمز الوصول.", + "add": "إضافة", + "serverRequired": "عنوان الخادم مطلوب.", + "usernameRequired": "اسم المستخدم مطلوب.", + "passwordRequired": "كلمة المرور مطلوبة." + } + }, + "ShortcutSettings": { + "sectionTitle": "الاختصارات", + "resetDefault": "استعادة الإعدادات الافتراضية", + "recordInstruction": "انقر الزر في الجهة اليمنى ثم اضغط تركيبة مفاتيح. استخدم Ctrl/Cmd وAlt وShift. اضغط Esc لإلغاء التسجيل.", + "recording": "اضغط اختصارًا...", + "toasts": { + "conflict": "الاختصار مستخدم بالفعل بواسطة \"{title}\"", + "updated": "تم تحديث الاختصار", + "invalid": "اختصار غير صالح، يرجى المحاولة مرة أخرى", + "reset": "تمت استعادة الاختصارات الافتراضية" + }, + "actions": { + "toggle_search": { + "title": "فتح البحث", + "description": "إظهار أو إخفاء لوحة البحث في المحادثات" + }, + "toggle_sidebar": { + "title": "تبديل الشريط الجانبي الأيسر", + "description": "إظهار أو إخفاء الشريط الجانبي لقائمة المحادثات" + }, + "toggle_terminal": { + "title": "تبديل الطرفية", + "description": "إظهار أو إخفاء لوحة الطرفية السفلية" + }, + "new_terminal_tab": { + "title": "طرفية جديدة", + "description": "إنشاء تبويب طرفية جديد عندما يكون التركيز على الطرفية" + }, + "close_current_terminal_tab": { + "title": "إغلاق الطرفية الحالية", + "description": "إغلاق تبويب الطرفية الحالي عندما يكون التركيز على الطرفية" + }, + "toggle_aux_panel": { + "title": "تبديل اللوحة اليمنى", + "description": "إظهار أو إخفاء لوحة المعلومات المساعدة" + }, + "new_conversation": { + "title": "محادثة جديدة", + "description": "إنشاء تبويب محادثة جديد في المجلد الحالي" + }, + "open_folder": { + "title": "فتح مجلد", + "description": "فتح منتقي المجلدات وفتح المجلد في نافذة جديدة" + }, + "open_settings": { + "title": "فتح الإعدادات", + "description": "فتح نافذة الإعدادات" + }, + "close_current_tab": { + "title": "إغلاق التبويب الحالي", + "description": "إغلاق المحادثة الحالية أو تبويب الملف الحالي" + }, + "close_all_file_tabs": { + "title": "إغلاق جميع تبويبات الملفات", + "description": "إغلاق جميع تبويبات الملفات المفتوحة عندما تكون لوحة الملفات نشطة" + }, + "next_tab": { + "title": "علامة التبويب التالية", + "description": "التبديل إلى علامة تبويب المحادثة أو الملف التالية" + }, + "prev_tab": { + "title": "علامة التبويب السابقة", + "description": "التبديل إلى علامة تبويب المحادثة أو الملف السابقة" + }, + "send_message": { + "title": "إرسال الرسالة", + "description": "إرسال الرسالة الحالية في مربع الإدخال" + }, + "newline_in_message": { + "title": "سطر جديد في الرسالة", + "description": "إدراج سطر جديد في مربع الإدخال" + }, + "toggle_custom_style": { + "title": "إيقاف/استئناف النمط المخصص", + "description": "مخرج طوارئ: يوقف كل الألوان المخصصة وCSS، ويعيد تفعيلها" + } + } + }, + "SkillsSettings": { + "title": "Skills", + "description": "اختر Skill من الجهة اليسرى. تعرض الجهة اليمنى معاينة Markdown بشكل افتراضي؛ انتقل إلى وضع التحرير للتعديل والحفظ.", + "loadingAgents": "جارٍ تحميل الوكلاء الذين يدعمون Skills...", + "emptyNoManageableAgents": "لا توجد وكلاء متاحة لإدارة Skills.", + "managedTarget": "الهدف المُدار", + "selectAgentPlaceholder": "اختر وكيلًا", + "searchPlaceholder": "ابحث بالاسم / المعرّف / المسار...", + "skillsList": "قائمة Skills", + "loadingSkills": "جارٍ تحميل Skills...", + "agentNotSupported": "الوكيل الحالي لا يدعم إدارة Skills.", + "emptySkills": "لا توجد Skills بعد. انقر \"Skill جديدة\" لإنشاء واحدة.", + "newSkillTitle": "Skill جديدة", + "skillInfo": "معلومات Skill", + "skillIdPlaceholder": "skill-id (حروف/أرقام/-/_/.)", + "skillsDirectoryWithPath": "دليل Skills: {path}", + "skillsDirectoryNeedId": "دليل Skills: أدخل معرّف Skill لإنشاء المسار الكامل", + "markdownContent": "محتوى Markdown", + "editingStatus": "جارٍ التحرير", + "previewStatus": "معاينة", + "contentPlaceholder": "أدخل محتوى Markdown للSkill...", + "metadataTitle": "بيانات Skills الوصفية", + "onlyYamlMetadata": "تحتوي هذه Skill على بيانات YAML الوصفية فقط.", + "emptyContentHint": "لا يوجد محتوى بعد. انقر \"تحرير\" للبدء.", + "loadingSkill": "جارٍ تحميل Skill...", + "emptyNoAgents": "لا يوجد وكيل متاح.", + "noSelectionHint": "اختر Skill من اليسار، أو انقر على \"Skill جديد\" لإنشاء واحد.", + "systemBadge": "نظام", + "systemHint": "Skill مدمج في CLI · للقراءة فقط", + "scope": { + "global": "عام", + "folder": "مجلد", + "selectFolderPlaceholder": "اختر مجلدًا", + "noFolders": "لم يتم العثور على مجلدات", + "pickFolderHint": "اختر مجلدًا لعرض مهاراته." + }, + "actions": { + "preview": "معاينة", + "edit": "تحرير", + "openInWindow": "فتح في نافذة جديدة", + "delete": "حذف", + "deleting": "جارٍ الحذف...", + "refresh": "تحديث", + "newSkill": "Skill جديدة", + "reset": "إعادة تعيين", + "save": "حفظ", + "saving": "جارٍ الحفظ...", + "cancel": "إلغاء" + }, + "deleteDialog": { + "title": "حذف Skill", + "confirm": "هل تريد حذف Skill الحالية؟ لا يمكن التراجع عن هذا الإجراء.", + "confirmWithNamePrefix": "حذف Skill", + "confirmWithNameSuffix": "؟ لا يمكن التراجع عن هذا الإجراء." + }, + "toasts": { + "loadFailed": "فشل تحميل Skill", + "openFolderFailed": "فشل فتح المجلد", + "noSkillDirectory": "لم يتم العثور على دليل Skills متاح للوكيل الحالي", + "nameRequired": "لا يمكن أن يكون اسم Skill فارغًا", + "updated": "تم تحديث Skill", + "created": "تم إنشاء Skill", + "saveFailed": "فشل حفظ Skill", + "deleted": "تم حذف Skill", + "deleteFailed": "فشل حذف Skill" + }, + "templates": { + "gemini": "---\nname: example-skill\ndescription: Describe when this skill should be used.\n---\n\n# Skill Name\n\nInstructions for the agent when this skill is active.\n\n## Workflow\n\n1. Add actionable step one.\n2. Add actionable step two.\n", + "openCode": "---\nname: example-skill\ndescription: Describe when this skill should be used.\n---\n\n# Purpose\n\nDescribe what this skill helps with.\n\n# Steps\n\n1. Add actionable step one.\n2. Add actionable step two.\n", + "openClaw": "---\nname: example-skill\ndescription: Describe when this skill should be used.\nuser-invocable: true\ndisable-model-invocation: false\n---\n\n# Purpose\n\nDescribe what this skill helps with.\n\n# Instructions\n\n1. Add actionable instruction one.\n2. Add actionable instruction two.\n", + "default": "---\nname: example-skill\ndescription: Describe when this skill should be used.\n---\n\n# Skill: example-skill\n\n## When to use\n\n- Describe trigger conditions.\n\n## Instructions\n\n1. Add actionable instruction one.\n2. Add actionable instruction two.\n" + } + }, + "McpSettings": { + "loading": "جارٍ التحميل...", + "summary": { + "missingCommand": "(لا يوجد أمر)", + "missingUrl": "(لا يوجد رابط)" + }, + "protocol": { + "stdio": "Stdio" + }, + "errors": { + "selectInstallProtocol": "يرجى اختيار بروتوكول التثبيت", + "fieldRequired": "{field} مطلوب", + "fieldNeedsBoolean": "{field} يجب أن يكون true أو false", + "fieldNeedsNumber": "{field} يجب أن يكون رقمًا", + "fieldNeedsInteger": "{field} يجب أن يكون عددًا صحيحًا", + "fieldInvalidJson": "{field} يحتوي JSON غير صالح: {message}", + "fieldOutOfRange": "قيمة {field} خارج النطاق المسموح", + "jsonEmpty": "{name} لا يمكن أن يكون فارغًا", + "jsonInvalid": "{name} ليس JSON صالحًا: {message}", + "jsonMustBeObject": "{name} يجب أن يكون كائن JSON", + "specMustBeObject": "يجب أن يكون إعداد MCP كائن JSON.", + "missingType": "حقل type غير موجود في إعداد MCP. حدد أحد القيم: stdio أو http (الأسماء البديلة: streamable-http و streamableHttp) أو sse.", + "unsupportedType": "نوع MCP غير مدعوم {type}. المدعوم: stdio و http (الأسماء البديلة: streamable-http و streamableHttp) و sse.", + "codexEntryUnsupportedType": "إدخال Codex MCP {id} له نوع غير مدعوم {type}. المدعوم: stdio و http (الأسماء البديلة: streamable-http و streamableHttp) و sse.", + "unsupportedTransportType": "نوع transport غير مدعوم {type}. المدعوم: http (الأسماء البديلة: streamable-http و streamableHttp) و sse.", + "stdioCommandRequired": "يتطلب MCP من نوع stdio حقل command غير فارغ.", + "remoteUrlRequired": "تتطلب MCP البعيدة حقل url غير فارغ.", + "appsRequired": "حدد تطبيقاً مستهدفاً واحداً على الأقل." + }, + "jsonNames": { + "localConfig": "إعداد MCP", + "installConfig": "إعداد التثبيت" + }, + "toasts": { + "uninstalled": "تمت إزالة MCP", + "uninstallFailed": "فشل الإزالة: {message}", + "selectAtLeastOneApp": "يرجى اختيار تطبيق هدف واحد على الأقل", + "saveSuccess": "تم الحفظ", + "saveFailed": "فشل الحفظ: {message}", + "installed": "تم تثبيت {name}", + "installFailed": "فشل التثبيت: {message}", + "serverIdRequired": "معرّف الخادم مطلوب", + "serverIdExists": "معرّف الخادم \"{id}\" موجود بالفعل. عدّل العنصر الحالي أو اختر اسماً آخر.", + "created": "تم إنشاء MCP" + }, + "installDialog": { + "title": "تأكيد تثبيت MCP", + "descriptionWithName": "تثبيت {name} في الإعداد المحلي.", + "description": "اختر التطبيقات المستهدفة للتثبيت.", + "protocol": "البروتوكول", + "selectProtocol": "اختر البروتوكول", + "parameters": "معلمات الإعداد", + "booleanPlaceholder": "يرجى اختيار true/false", + "selectOneValue": "اختر قيمة", + "targetApps": "التطبيقات المستهدفة" + }, + "actions": { + "cancel": "إلغاء", + "confirmInstall": "تأكيد التثبيت", + "installing": "جارٍ التثبيت", + "uninstall": "إزالة التثبيت", + "uninstalling": "جارٍ الإزالة", + "viewDetails": "عرض التفاصيل", + "save": "حفظ", + "saving": "جارٍ الحفظ", + "install": "تثبيت", + "refresh": "تحديث", + "newMcp": "MCP جديد", + "create": "إنشاء", + "creating": "جارٍ الإنشاء..." + }, + "tabs": { + "local": "MCP المحلي", + "market": "سوق MCP" + }, + "local": { + "filterPlaceholder": "تصفية MCP المحلي...", + "loadFailed": "فشل التحميل: {message}", + "empty": "لم يتم اكتشاف MCP محلي.", + "description": "يمكن تعديل إعداد MCP المحلي وحفظه مباشرة.", + "enabledApps": "التطبيقات المفعلة", + "configJson": "إعداد MCP (JSON)", + "draftTitle": "MCP جديد", + "draftDescription": "أدخل معرّف الخادم والإعدادات لإنشاء خادم MCP محلي.", + "serverIdLabel": "معرّف الخادم", + "serverIdPlaceholder": "معرّف الخادم (مثل: my-mcp)", + "typeHint": "الأنواع المدعومة: stdio و http (الأسماء البديلة: streamable-http و streamableHttp) و sse. يُستخدم env مع stdio فقط؛ خوادم MCP البعيدة تحمل رموز المصادقة عبر headers.", + "envOnRemoteWarning": "تم اكتشاف env على MCP بعيد. يُستخدم env مع stdio فقط؛ خوادم MCP البعيدة تحمل رموز المصادقة عبر headers، لذا سيتم تجاهل env عند الحفظ." + }, + "market": { + "selectMarketplace": "اختر السوق", + "searchPlaceholder": "ابحث عن MCP...", + "searchFailed": "فشل البحث: {message}", + "loadingList": "جارٍ تحميل قائمة MCP...", + "empty": "لا توجد نتائج MCP.", + "loadingDetail": "جارٍ تحميل تفاصيل السوق...", + "detailLoadFailed": "فشل تحميل التفاصيل: {message}", + "owner": "المالك: {owner}", + "namespace": "المجال: {namespace}", + "defaultInstallProtocol": "بروتوكول التثبيت الافتراضي", + "currentOptionParameterCount": "عدد معلمات الخيار الحالي: {count}", + "installConfigDescription": "إعداد التثبيت (JSON، قابل للتعديل قبل التثبيت؛ ستتجاوز التعديلات نموذج البروتوكول/المعلمات)", + "selectLeftToView": "اختر MCP من السوق في الجهة اليسرى لعرض التفاصيل." + }, + "badges": { + "verified": "موثّق", + "remote": "بعيد", + "hasHomepage": "له صفحة رئيسية", + "uses": "{count} استخدام", + "deployed": "منشور", + "notDeployed": "غير منشور" + }, + "selectLeftMcp": "اختر MCP من الجهة اليسرى." + }, + "AcpAgentSettings": { + "title": "إدارة Agent SDK", + "description": "أدر اتصال Agent SDK وحالة التمكين ومتغيرات البيئة وإدارة الإعدادات ومعلومات فحص الإصدار المسبق في مكان واحد.", + "loadingAgents": "جارٍ تحميل قائمة الوكلاء...", + "agentList": "قائمة الوكلاء", + "emptyNoAgent": "لا يوجد وكيل متاح.", + "configManagement": "إدارة الإعدادات", + "envVars": "متغيرات البيئة", + "hostTools": { + "label": "دع الوكيل يتولى الملفات والأوامر بنفسه", + "description": "يتوقف codeg عن تنفيذ الوصول إلى الملفات وأوامر الطرفية، فينفّذها الوكيل داخل عمليته الخاصة — وعندها فقط تُطبَّق البيئة المعزولة وقواعد الأذونات الخاصة به. كما يُعطَّل التفويض إلى وكلاء آخرين، لأنه سيعيد العمل نفسه عبر codeg. لا يضيف codeg بيئة معزولة من عنده، لذا فعّل هذا الخيار فقط إذا كان الوكيل قد أُعِدّت له واحدة." + }, + "nativeJsonConfig": "إعداد JSON أصلي", + "modelHintDefault": "اتركه فارغًا لاستخدام النموذج الافتراضي للنظام.", + "generalConfigDescriptionClaude": "يدعم الإعداد السريع لـ API URL وAPI Key ونماذج Claude، ويتزامن مع إعداد JSON الأصلي.", + "generalConfigDescriptionDefault": "يدعم إدخال الإعدادات المهمة (API URL وAPI Key وModel) وإدارة إعداد JSON الأصلي.", + "multiAgent": { + "title": "تعاون متعدد الوكلاء", + "description": "اسمح للوكلاء النشطين بتفويض المهام الفرعية إلى وكلاء آخرين.", + "enable": "تفعيل التفويض", + "enableHint": "عند الإيقاف، يتم إخفاء أداة delegate_to_agent من قائمة أدوات MCP الخاصة بالوكيل.", + "withheldByHostTools": "لن تحصل {agents} على أدوات التفويض: مفتاح «دع الوكيل يتولى الملفات والأوامر» الخاص بها مُفعّل.", + "selfInitiate": "Allow spawn without @", + "selfInitiateHint": "When on, an agent may start a listed sub-agent on its own. An @ mention is still always honored. When off, only an @ mention starts a sub-agent.", + "depthLimit": "أقصى عمق للتفويض", + "depthHint": "النطاق المسموح: {min}–{max}. يحدّ من عمق سلسلة التفويض (جذر ← فرعي ← حفيد …).", + "completedCacheLabel": "ذاكرة التخزين المؤقت للنتائج المكتملة (MB)", + "completedCacheHint": "ذاكرة تخزين مؤقتة في الذاكرة لنتائج الوكلاء الفرعيين المكتملة، تُحفظ فقط أثناء تشغيل جلسة التفويض وتُحرَّر تلقائيًا عند انتهاء تلك الجلسة. وعند تجاوز هذه الميزانية، تُسقَط أقدم النتائج من الذاكرة أولًا (تظل قابلة للعرض في جلسة الوكيل الفرعي نفسه)؛ 0 = غير محدود (وتُحرَّر مع ذلك عند انتهاء الجلسة).", + "save": "حفظ", + "saving": "جارٍ الحفظ…", + "saved": "تم حفظ إعدادات التفويض", + "saveFailed": "فشل حفظ إعدادات التفويض", + "loadFailed": "فشل تحميل إعدادات التفويض: {detail}", + "tabGeneral": "عام", + "tabAgentDefaults": "إعدادات الوكيل الفرعي", + "agentDefaultsDescription": "تجاوزات لكل وكيل تُطبَّق عندما يقوم التعاون متعدد الوكلاء بتشغيل وكيل فرعي لاستدعاء تفويض. تأتي الخيارات المعروضة هنا من فحص حي، لذا فإن ما تختاره هو بالضبط ما سيقبله الوكيل.", + "probing": "جارٍ تحميل الخيارات المتاحة من الوكيل…", + "probeFailed": "فشل تحميل الخيارات: {detail}", + "retry": "إعادة المحاولة", + "noConfigAvailable": "لا يحتوي هذا الوكيل على خيارات قابلة للضبط.", + "modeLabel": "الوضع", + "agentDefaultHint": "افتراضي الوكيل: {value}", + "defaultOptionLabel": "افتراضي ({value})" + }, + "actions": { + "dragSort": "اسحب لإعادة الترتيب", + "dragSortAgent": "اسحب لإعادة ترتيب {name}", + "refreshCheck": "تحديث الفحص", + "refreshCheckAgent": "تحديث فحص {name}", + "clickEnable": "انقر لتفعيل {name}", + "clickDisable": "انقر لتعطيل {name}", + "install": "تثبيت", + "upgrade": "ترقية", + "uninstall": "إزالة التثبيت", + "uninstalling": "جارٍ إزالة التثبيت...", + "saveEnvVars": "حفظ متغيرات البيئة", + "saving": "جارٍ الحفظ...", + "saveGrokConfig": "حفظ إعدادات Grok", + "saveCodexConfig": "حفظ إعداد Codex", + "saveGeminiConfig": "حفظ إعداد Gemini", + "saveOpenCodeConfig": "حفظ إعداد OpenCode", + "saveOpenClawConfig": "حفظ إعداد OpenClaw", + "saveConfigManagement": "حفظ إدارة الإعدادات", + "saveCurrentProvider": "حفظ المزود الحالي", + "showApiKey": "إظهار مفتاح API", + "hideApiKey": "إخفاء مفتاح API", + "showKey": "إظهار المفتاح", + "hideKey": "إخفاء المفتاح", + "showToken": "إظهار الرمز", + "hideToken": "إخفاء الرمز", + "cancel": "إلغاء", + "delete": "حذف", + "deleting": "جارٍ الحذف...", + "confirmDelete": "تأكيد الحذف", + "confirmUninstall": "تأكيد إزالة التثبيت", + "saveClineConfig": "حفظ تكوين Cline", + "saveHermesConfig": "حفظ تكوين Hermes", + "saveCodeBuddyConfig": "حفظ إعدادات CodeBuddy", + "saveKimiCodeConfig": "حفظ إعدادات Kimi Code", + "customInstall": "تثبيت مخصص", + "saveKimiCodeRawConfig": "Save config.toml", + "saveDeepSeekConfig": "حفظ إعدادات DeepSeek", + "diagnose": "تشخيص" + }, + "status": { + "enabled": "مفعّل", + "disabled": "معطّل", + "unchecked": "غير مفحوص", + "agentEnabledAria": "{name} مفعّل", + "agentEnabledSwitch": "مفتاح تفعيل {name}" + }, + "preflight": { + "count": "عناصر الفحص المسبق: {count}", + "notRun": "لم يتم تشغيل الفحوصات بعد." + }, + "grok": { + "configDescription": "اضبط Grok هنا. عناصر التحكم أدناه — وضع الأذونات، وجهد الاستدلال، ونموذج مخصّص اختياري (نقطة نهاية خاصة)، والضغط — تُدمج في ~/.grok/config.toml مع الحفاظ على مفاتيحك وتعليقاتك الأخرى. يستخدم تسجيل الدخول XAI_API_KEY أو `grok login`. تبقى المفاتيح الأخرى قابلة للتحرير ضمن «متقدم».", + "permissionModeLabel": "وضع الأذونات", + "permissionDefault": "السؤال في كل مرة", + "permissionAcceptEdits": "الموافقة التلقائية على التعديلات", + "permissionAuto": "موافقة تلقائية ذكية", + "permissionAlwaysApprove": "الموافقة دائمًا", + "reasoningEffortLabel": "جهد الاستدلال", + "effortLow": "منخفض (أسرع)", + "effortMedium": "متوسط (متوازن)", + "effortHigh": "مرتفع", + "effortXhigh": "الأقصى", + "optionDefault": "استخدام الافتراضي", + "authTitle": "المصادقة", + "authMode": "طريقة المصادقة", + "authModeApiKey": "مفتاح XAI API", + "authModeApiKeyHint": "المصادقة باستخدام XAI_API_KEY من وحدة تحكم xAI — للتشغيل غير التفاعلي أو بدون واجهة. يُخزَّن في بيئة هذا الوكيل.", + "authModeCustom": "نقطة نهاية مخصّصة", + "authModeCustomHint": "استخدم نقطة نهاية خاصة بك (BYO): عرّف نموذجًا مخصّصًا في الأسفل مع عنوان URL أساسي ومفتاح API خاصين به. يصبح النموذج الافتراضي لـ Grok.", + "subscriptionHint": "سجّل الدخول باستخدام `grok login` (SuperGrok / X Premium+). لا يُخزَّن أي مفتاح API.", + "loginHint": "نفّذ هذا في الطرفية لتسجيل الدخول، ثم أعد فتح هذه الإعدادات:", + "commandCopied": "تم نسخ الأمر إلى الحافظة", + "copyCommand": "نسخ الأمر", + "authKeyConfigured": "XAI_API_KEY مُهيَّأ.", + "authKeyMissing": "لم يتم تعيين XAI_API_KEY.", + "advancedToggle": "متقدم (config.toml الخام)", + "configTomlNative": "config.toml (أصلي)", + "configTomlHint": "يُحفظ حرفيًا كملف ~/.grok/config.toml بالكامل. يُرفض TOML غير الصالح حتى لا يقتطع خطأ مطبعي ملفك أبدًا.", + "configTomlPlaceholder": "# مفاتيح غير عناصر التحكم أعلاه، مثل\n# [mcp_servers.*] و[cli] وقواعد [permission].", + "customModelTitle": "نموذج مخصّص (نقطة نهاية خاصة)", + "customModelHint": "وجِّه Grok إلى نقطة نهاية مخصّصة أو مستضافة ذاتيًا. يكتب codeg كتلة `[model.*]` لكل نموذج ويجعلها النموذج الافتراضي. اترك معرّف النموذج فارغًا لإزالته.", + "customModelIdLabel": "معرّف النموذج", + "customModelIdPlaceholder": "grok-4.5", + "customModelIdHint": "يُسجَّل ككتلة `[model.*]` ويُرسَل إلى الـ API كاسم للنموذج؛ ويُضبط أيضًا كـ `[models].default`.", + "customBaseUrlLabel": "عنوان URL الأساسي", + "customBaseUrlPlaceholder": "https://api.x.ai/v1 (الافتراضي)", + "customApiBackendLabel": "الواجهة الخلفية لـ API", + "backendResponses": "Responses", + "backendChatCompletions": "Chat Completions", + "backendMessages": "Messages (Anthropic)", + "customApiKeyLabel": "مفتاح API", + "customApiKeyHint": "يُخزَّن ضمن `[model.*].api_key`، مقصورًا على نقطة النهاية هذه.", + "customContextWindowLabel": "نافذة السياق (رموز)", + "customContextWindowHint": "اختياري. يحدّد توقيت الضغط التلقائي؛ اتركه فارغًا لاستخدام القيمة الافتراضية لنقطة النهاية.", + "autoCompactLabel": "عتبة الضغط التلقائي (%)", + "autoCompactHint": "يضغط المحادثة عندما يبلغ استخدام السياق هذه النسبة المئوية (الافتراضي في Grok هو 85). يُكتَب في `[session]`." + }, + "cursor": { + "configDescription": "اضبط Cursor هنا. اختر طريقة مصادقة — اشتراك رسمي (تسجيل دخول عبر المتصفح) أو مفتاح Cursor API للأجهزة بدون واجهة أو الخوادم — ثم اختر نموذجًا وحرّر قواعد أذونات CLI وبيئة الحماية. يكتبها codeg في ~/.cursor/cli-config.json، بالمشاركة مع أداة cursor-agent.", + "authTitle": "المصادقة", + "authChecking": "جارٍ التحقق…", + "authNotInstalled": "cursor-agent غير مثبّت", + "authLoggedIn": "تم تسجيل الدخول", + "authNotLoggedIn": "غير مسجّل الدخول", + "loginHint": "شغّل هذا الأمر في الطرفية لتسجيل الدخول إلى حساب Cursor (سيفتح المتصفح)، ثم اضغط تحديث:", + "apiKeyLabel": "مفتاح Cursor API", + "apiKeyPlaceholder": "المفتاح من cursor.com/dashboard", + "apiKeyHint": "CURSOR_API_KEY — مفتاح حساب من لوحة تحكم Cursor، بديل لتسجيل الدخول عبر المتصفح للأجهزة بدون واجهة أو الخوادم. ليس مفتاحًا خارجيًا أو من OpenAI.", + "modelTitle": "النموذج الافتراضي", + "loadModels": "جلب النماذج", + "modelsUnavailable": "قائمة النماذج غير متاحة", + "modelHint": "يُمرَّر إلى CLI عبر ‎--model عند بدء الجلسة. اتركه افتراضيًا ليختار Cursor بنفسه.", + "permissionsTitle": "الأذونات ووضع الحماية", + "permissionsDescription": "محرّر بصري لقواعد أذونات CLI‏ (cli-config.json). القواعد المسموحة تُنفَّذ دون تأكيد؛ والمرفوضة تُحظر دائمًا.", + "permissionModeLabel": "وضع الأذونات", + "permissionModeDefault": "السؤال قبل التنفيذ (افتراضي)", + "permissionModeForce": "تشغيل كل شيء (--force)", + "permissionModeHint": "يبدأ وضع Run Everything الجلسات بـ --force: يُسمح تلقائيًا بجميع استدعاءات الأدوات باستثناء قواعد الرفض دون طلب تأكيد (قد تقيّده سياسة المؤسسة بقواعد السماح فقط). يسري على الجلسات الجديدة.", + "optionDefault": "افتراضي (غير محدد)", + "sandboxLabel": "وضع الحماية", + "sandboxEnabled": "مفعّل", + "sandboxDisabled": "معطّل", + "allowRulesLabel": "قواعد السماح", + "denyRulesLabel": "قواعد الرفض", + "addRule": "إضافة قاعدة", + "rulesSyntaxHint": "صيغة القواعد: Shell(أمر)، Read(مسار/نمط)، Write(مسار/نمط)، WebFetch(نطاق)، Mcp(خادم:أداة) — قواعد الرفض لها الأولوية دائمًا.", + "saveConfig": "حفظ الإعدادات", + "advancedToggle": "متقدم: cli-config.json الخام", + "advancedHint": "ملف ‎~/.cursor/cli-config.json كاملًا. الحفظ هنا يكتب الملف كما هو؛ أما عناصر التحكم أعلاه فتُدمج فيه.", + "saveRawConfig": "حفظ الملف", + "authMode": "طريقة المصادقة", + "subscriptionHint": "سجّل الدخول بحساب Cursor واستخدم نماذج Cursor.", + "customApiKeyRequired": "مفتاح Cursor API مطلوب.", + "authModeApiKey": "مفتاح Cursor API (بدون واجهة/خادم)", + "authModeApiKeyHint": "المصادقة باستخدام مفتاح API لحساب Cursor من لوحة تحكم Cursor (للأجهزة بدون واجهة أو الخوادم). هذا مفتاح حساب Cursor وليس نقطة نهاية خارجية/OpenAI — إذ يتصل cursor-agent بخادم Cursor الخاص فقط. لاستخدام نقطة نهاية متوافقة مع codex/OpenAI، استخدم وكيل Codex بدلاً من ذلك.", + "modelPickerPlaceholder": "ابحث عن النماذج…", + "modelNoMatch": "لا يوجد نموذج مطابق", + "modelsNeedAuth": "سجّل الدخول لتحميل قائمة النماذج.", + "modelDefaultBadge": "افتراضي" + }, + "deepseek": { + "configManagement": "إعدادات DeepSeek Harness", + "configDescription": "نقطة النهاية والمفتاح متغيّرا بيئة يقرأهما deepseek-acp عند الإقلاع. أما النموذج ومستوى الاستدلال فمحدِّدان على مستوى الجلسة، ويُختاران من حقل الإدخال.", + "baseUrlLabel": "نقطة نهاية API", + "baseUrlHint": "اتركه فارغًا لاستخدام نقطة النهاية الرسمية. يسري على الجلسات التي تبدأ بعد الحفظ؛ أعد الاتصال بالجلسة الجارية كي تأخذ القيمة الجديدة.", + "baseUrlInvalid": "أدخل عنوان http(s) كاملًا وبدون سلسلة استعلام، مثل https://api.deepseek.com", + "apiKeyLabel": "مفتاح API", + "apiKeyHint": "يُمرَّر إلى الوكيل باسم DEEPSEEK_API_KEY. متغيّر البيئة له أسبقية على ملف بيانات الاعتماد، لذا اترك الحقل فارغًا إن كنت تسجّل الدخول من الطرفية." + }, + "codex": { + "configDescription": "يدعم الإعداد السريع لعنوان API ومفتاح API واسم النموذج وجهد الاستدلال، مع المزامنة مع `auth.json` / `config.toml`.", + "authMode": "طريقة المصادقة", + "chatgptSubscription": "اشتراك رسمي", + "chatgptSubscriptionHint": "تسجيل الدخول باشتراك ChatGPT الرسمي، لا حاجة لـ API Key", + "apiKeyHint": "الاتصال باستخدام API Key بخدمات OpenAI أو الخدمات المتوافقة", + "selectProvider": "اختر المزود", + "modelName": "اسم النموذج", + "selectReasoningEffort": "اختر Reasoning Effort", + "enableWebsocket": "تفعيل WebSocket", + "enableWebsocketAria": "تفعيل WebSocket لـ Codex Provider", + "enableSkills": "تفعيل Skills", + "enableSkillsAria": "تفعيل Skills لـ Codex", + "enableFast": "تفعيل Fast", + "enableFastAria": "تفعيل مستوى خدمة Fast لـ Codex", + "sandboxGroupTitle": "بيئة العزل والموافقات", + "sandboxGroupHint": "تُكتب في ~/.codex/config.toml العام، لذا تراها أيضًا جلسات codex CLI وبيئة التطوير. هذه قيم افتراضية للمحادثة: تحكم الأدوار التي يبدأها codex بنفسه (‏/goal و‏/review و‏/compact). أما الرسائل العادية فتستخدم إعداد الموافقة المحدد في صندوق الإدخال. أعد تشغيل الجلسة لتطبيق التغييرات.", + "sandboxShadowedWarning": "يضبط config.toml المفتاح default_permissions، لذا يحسم codex الأذونات عبر ذلك الملف الشخصي ويتجاهل sandbox_mode تمامًا. احذف default_permissions لاستخدام عناصر التحكم أدناه.", + "sandboxPermissionsTableWarning": "يعرّف config.toml ملفات [permissions] دون default_permissions، وهو ما يمنع codex من العمل. اضبطه في المحرر الخام أدناه.", + "approvalPolicyLabel": "سياسة الموافقة", + "approvalPolicyUnset": "غير محددة (افتراضي codex: عند الطلب)", + "approvalPolicy_on-request": "عند الطلب — النموذج يقرر متى يسأل", + "approvalPolicy_untrusted": "غير موثوق — تُنفَّذ تلقائيًا أوامر القراءة الآمنة المعروفة فقط", + "approvalPolicy_never": "أبدًا — بدون أي طلبات موافقة", + "approvalPolicy_granular": "تفصيلي — اختر حسب نوع الطلب", + "approvalPolicyUntrustedAcpWarning": "لا يوجد مكافئ لـ untrusted بين إعدادات الموافقة الثلاثة في محوّل ACP، لذا تعود جلسات codeg إلى «عند الطلب»: يقرّر النموذج حينها متى يسأل، وتتوقف الأوامر التي تسمح بها البيئة المعزولة أصلاً عن طلب التأكيد. قيّد وضع العزل أدناه بدلاً من ذلك.", + "granularHint": "الإيقاف يعني رفض هذا النوع من الطلبات تلقائيًا بدلًا من عرضه عليك.", + "granular_sandbox_approval": "تصعيد صلاحيات أوامر الصدفة", + "granular_rules": "مطالبات قواعد execpolicy", + "granular_skill_approval": "مطالبات تنفيذ نصوص المهارات", + "granular_request_permissions": "مطالبات أداة request_permissions", + "granular_mcp_elicitations": "مطالبات elicitation في MCP", + "sandboxModeLabel": "وضع بيئة العزل", + "sandboxModeUnset": "غير محدد (المجلدات الموثوقة تعود إلى الكتابة في مساحة العمل)", + "sandboxMode_read-only": "قراءة فقط", + "sandboxMode_workspace-write": "الكتابة في مساحة العمل", + "sandboxMode_danger-full-access": "وصول كامل (بدون عزل)", + "sandboxModeHint": "على Windows، تُخفَّض الكتابة في مساحة العمل إلى قراءة فقط ما لم تُفعَّل بيئة العزل التجريبية الخاصة بـ codex.", + "sandboxModeSeedsPresetHint": "يستخدم codeg هذا أيضاً لتحديد إعداد الموافقة الأولي للجلسة، لذا فإنه — بخلاف سياسة الموافقة — يؤثر على الطلبات العادية. ويظل الإعداد المختار في مربع الإدخال هو الأسبق.", + "writableRootsLabel": "مجلدات إضافية قابلة للكتابة", + "writableRootsHint": "مسار مطلق واحد في كل سطر، إضافةً إلى مجلد العمل.", + "sandboxRootsRelativeError": "يجب أن يكون مسارًا مطلقًا — يحسم codex المسارات النسبية داخل ~/.codex: {path}", + "networkAccessLabel": "السماح بالوصول إلى الشبكة", + "excludeTmpdirLabel": "استبعاد TMPDIR من الجذور القابلة للكتابة", + "excludeSlashTmpLabel": "استبعاد /tmp من الجذور القابلة للكتابة", + "authJsonNative": "auth.json (أصلي)", + "configTomlNative": "config.toml (أصلي)", + "loginButton": "تسجيل الدخول باستخدام ChatGPT", + "loginRequesting": "جارٍ طلب رمز تسجيل الدخول...", + "loginStep1": "افتح الرابط التالي في متصفحك:", + "loginStep2": "أدخل الرمز أدناه:", + "loginPolling": "في انتظار التفويض...", + "loginCancel": "إلغاء", + "loginSuccess": "تم تسجيل الدخول بنجاح، تم حفظ الإعدادات!", + "loginFailed": "فشل تسجيل الدخول: {message}", + "loginRetry": "إعادة المحاولة", + "loginCodeCopied": "تم نسخ الرمز", + "loggedIn": "تم تسجيل الدخول", + "loginRelogin": "إعادة تسجيل الدخول / تبديل الحساب", + "loginTimeout": "انتهت مهلة تسجيل الدخول، يرجى المحاولة مرة أخرى", + "loginSaveFailed": "تم تسجيل الدخول بنجاح ولكن فشل حفظ الإعدادات" + }, + "gemini": { + "authConfig": "إعداد مصادقة Gemini", + "authConfigDescription": "متوافق مع وثائق مصادقة Gemini CLI، ويدعم endpoint مخصص وتسجيل دخول Google وGemini API Key وVertex AI ‏(ADC / حساب خدمة / API Key).", + "authMode": "وضع المصادقة", + "selectAuthMode": "اختر وضع المصادقة", + "viewAuthDoc": "عرض وثائق المصادقة", + "mode": { + "custom": "Endpoint مخصص", + "loginGoogle": "تسجيل دخول Google (OAuth)", + "vertexServiceAccount": "Vertex AI (حساب خدمة)" + }, + "hint": { + "custom": "أدخل API URL وAPI Key وModel؛ وسيتم ربطها بـ GOOGLE_GEMINI_BASE_URL / GEMINI_API_KEY / GEMINI_MODEL.", + "loginGoogle": "شغّل gemini في الطرفية وأكمل تسجيل دخول Google أولًا؛ لا حاجة إلى API key.", + "geminiApiKey": "أدخل GEMINI_API_KEY عند استخدام Gemini API.", + "vertexAdc": "استخدم gcloud ADC؛ ويوصى بتعيين GOOGLE_CLOUD_PROJECT وGOOGLE_CLOUD_LOCATION.", + "vertexServiceAccount": "عيّن مسار JSON لحساب الخدمة في GOOGLE_APPLICATION_CREDENTIALS.", + "vertexApiKey": "أدخل GOOGLE_API_KEY عند استخدام مفتاح Vertex AI API." + } + }, + "openCode": { + "configManagement": "إدارة إعداد OpenCode", + "configDescription": "متوافق مع مخطط `provider` في OpenCode، ويدعم إدارة متعددة المزودات ومزامنة ثنائية الاتجاه مع ملفات JSON الأصلية.", + "providerManagement": "إدارة المزودات", + "providerCount": "{count} مزودات", + "addProvider": "إضافة مزود", + "emptyProvider": "لا توجد مزودات مخصصة بعد. انقر على «إضافة مزود مخصص» لإنشاء واحد.", + "providerEnabledState": "حالة تفعيل {providerId}", + "selectProviderNpm": "اختر provider.npm", + "modelManagement": "إدارة النماذج", + "modelCount": "{count} نماذج", + "modelDescription": "متوافق مع `provider.models` في OpenCode. الإدارة السريعة تدعم حاليًا `name` / `id`؛ بينما تُحفظ الحقول المتقدمة الأخرى ويمكن تعديلها في JSON الأصلي أدناه.", + "addModel": "إضافة نموذج", + "emptyModel": "لا يوجد نموذج بعد. أدخل model id ثم انقر \"إضافة نموذج\".", + "modelId": "معرّف النموذج", + "modelName": "اسم النموذج", + "deleteModel": "حذف النموذج {modelId}", + "nativeJsonConfig": "إعداد JSON الأصلي لـ OpenCode", + "mainModel": "النموذج الرئيسي", + "smallModel": "النموذج الصغير", + "noMatchingModels": "لا توجد نماذج مطابقة", + "connectProvider": "ربط مزود", + "connectedProviders": "المزودون المتصلون", + "noConnectedProviders": "لم يتم ربط أي مزود من الكتالوج بعد.", + "advancedProviderConfig": "المزودات المخصصة", + "customProviderConfigHint": "نقاط نهاية متوافقة مع OpenAI تحددها بنفسك — كتلة provider في opencode.json، مع مفتاح API في auth.json.", + "addCustomProvider": "إضافة مزود مخصص", + "disconnect": "قطع الاتصال", + "editConfig": "تحرير", + "customBadge": "مخصص", + "authKindApi": "مفتاح API", + "authKindOauth": "OAuth", + "authKindNone": "لا توجد بيانات اعتماد", + "connect": { + "title": "ربط مزود", + "description": "اختر مزودًا من كتالوج models.dev. تُحفظ بيانات الاعتماد في ملف auth.json الخاص بـ OpenCode.", + "pick": "المزود", + "search": "البحث عن المزودين…", + "loading": "جارٍ تحميل الكتالوج…", + "catalogLabel": "كتالوج models.dev", + "modelsAvailable": "{count} نموذجًا متاحًا", + "getKey": "الحصول على مفتاح API", + "oauthApiKeyNote": "يدعم هذا المزود أيضًا تسجيل الدخول عبر المتصفح باستخدام opencode auth login. سيتوفر تسجيل الدخول عبر المتصفح قريبًا — في الوقت الحالي، الصق مفتاح API.", + "apiKey": "مفتاح API", + "apiKeyHint": "تُحفظ في auth.json وليس في opencode.json أبدًا.", + "baseUrlOptional": "تجاوز عنوان URL الأساسي (اختياري)", + "providerId": "معرّف المزود", + "displayName": "الاسم المعروض", + "modelsList": "النماذج (واحد في كل سطر)", + "modelsHint": "معرّفات النماذج التي تقبلها نقطة النهاية.", + "action": "ربط", + "editTitle": "تعديل المزود", + "editDescription": "حدّث مفتاح API أو عنوان URL الأساسي لهذا المزود.", + "saveAction": "حفظ" + }, + "customProvider": { + "title": "إضافة مزود مخصص", + "description": "حدّد نقطة نهاية متوافقة مع OpenAI. يُحفظ مفتاح API في auth.json، وتُكتب كتلة provider في opencode.json.", + "action": "إضافة المزود", + "idInCatalog": "{providerId} مزود معروف — قم بربطه عبر «ربط مزود» بدلاً من ذلك." + }, + "refreshCatalog": "تحديث الكتالوج", + "reasoningBadge": "استدلال", + "contextWindow": "نافذة السياق", + "permissions": { + "title": "الأذونات", + "description": "حدِّد أي الإجراءات تعمل تلقائيًا، وأيها يطلب موافقتك، وأيها يُحظر. يُكتب في مقطع permission داخل opencode.json ويُطبَّق عند الحفظ أدناه.", + "docsLink": "توثيق الأذونات", + "unparsableConfig": "تعذّر تحليل JSON الأصلي أدناه، لذا أُوقف المحرِّر المرئي مؤقتًا. صحّح JSON للمتابعة.", + "invalidBlock": "بنية مقطع permission غير معروفة لدى codeg. عدِّلها في JSON الأصلي أدناه أو استخدم إعادة الضبط للبدء من جديد.", + "orderingUnsafe": "كُتبت قاعدة عامة بعد أدوات محددة، لذا يطبّقها OpenCode عليها أيضًا — الصفوف أدناه ليست ما هو نافذ فعلًا. «تصحيح الترتيب» يعيد كل قاعدة عامة إلى بداية نطاقها فقط، دون تغيير أي قيمة.", + "orderingUnsafeManual": "قاعدة محجوبة بنمط أعمّ مكتوب بعدها، لذا لا يطبّقها OpenCode أبدًا — الصفوف أدناه ليست ما هو نافذ فعلًا. لا يوجد ترتيب صحيح وحيد لنمطين متداخلين؛ أعد ترتيبهما في JSON الأصلي بحيث يأتي الأعمّ أولًا.", + "fixOrder": "تصحيح الترتيب", + "agentOverrides": "هذه الوكلاء تتجاوز الأذونات وتُطبَّق أخيرًا، لذا تتغلب على كل ما هنا: {agents}. عدّلها في JSON الأصلي أدناه، أو فعّل القبول التلقائي لمسحها.", + "legacyTools": "خريطة tools القديمة في المستوى الأعلى ترفض إحدى الأدوات. يدمجها OpenCode ضمن الأذونات، لذا تُطبَّق فوق كل ما يظهر هنا. عدّلها في JSON الأصلي أدناه، أو فعّل القبول التلقائي لمسحها.", + "autoAcceptTitle": "قبول جميع الأذونات تلقائيًا", + "autoAcceptHint": "تُنفَّذ كل استدعاءات الأدوات — أوامر الصدفة وتعديلات الملفات والمسارات خارج المشروع — دون سؤال. تفعيله يستبدل إعدادات كل أداة أدناه بقاعدة واحدة تسمح بكل شيء، ويمسح تجاوزات كل وكيل ومفاتيح tools القديمة التي كانت ستستمر في الحجب.", + "globalLabel": "الإعداد العام الافتراضي", + "globalHint": "قاعدة *: تنطبق على كل ما لا تتجاوزه الأدوات أدناه.", + "actionUnset": "غير محدد (افتراضيات OpenCode)", + "actionInherit": "اتباع الافتراضي ({action})", + "actionAllow": "سماح", + "actionAsk": "سؤال", + "actionDeny": "رفض", + "perToolTitle": "أذونات كل أداة", + "reset": "إعادة الضبط", + "ruleCount": "القواعد: {count}", + "rulesToggle": "القواعد التفصيلية للأداة {tool}", + "rulesHint": "تُطابَق مع مدخلات الأداة، وتفوز آخر مطابقة، لذا ضع الأنماط الواسعة أولًا. الرمز * يطابق أي عدد من المحارف، و? يطابق محرفًا واحدًا بالضبط، و~ في البداية يتوسّع إلى مجلد المنزل.", + "noRules": "لا توجد قواعد تفصيلية بعد.", + "addRule": "إضافة قاعدة", + "deleteRule": "حذف القاعدة {pattern}", + "duplicateRule": "هذا النمط موجود بالفعل.", + "blankRule": "القاعدة تحتاج إلى نمط — استخدم أيقونة سلة المهملات لحذفها.", + "customKeys": "مفاتيح أذونات أخرى في الملف", + "customKeyHint": "ليست أداة مدمجة في OpenCode — تُحفظ كما هي.", + "keys": { + "bash": "تشغيل أوامر الصدفة، بمطابقة الأمر بعد تحليله", + "edit": "كل تعديلات الملفات: edit وwrite وpatch", + "read": "قراءة الملفات، بمطابقة المسار", + "external_directory": "الوصول إلى مسارات خارج مجلد عمل المشروع", + "task": "تشغيل الوكلاء الفرعيين، بمطابقة نوع الوكيل الفرعي", + "skill": "تحميل المهارات، بمطابقة اسم المهارة", + "glob": "العثور على الملفات، بمطابقة نمط glob", + "grep": "البحث في محتوى الملفات، بمطابقة النمط", + "list": "سرد محتويات المجلد", + "webfetch": "جلب عنوان URL", + "websearch": "البحث في الويب", + "lsp": "تشغيل استعلامات LSP", + "todowrite": "كتابة قائمة المهام", + "question": "طرح سؤال عليك", + "doom_loop": "يُفعَّل عند تكرار الاستدعاء نفسه ثلاث مرات بالمدخلات نفسها" + } + } + }, + "openClaw": { + "gatewayConfig": "إعداد Gateway", + "gatewayDescription": "قم بإعداد اتصال OpenClaw Gateway. يدعم gateway محليًا أو بعيدًا.", + "gatewayUrlHint": "اتركه فارغًا لاستخدام gateway.remote.url من إعداد openclaw المحلي.", + "gatewayTokenPlaceholder": "رمز مصادقة Gateway", + "gatewayTokenHint": "يُفضّل استخدام token-file بدل الرمز النصي متى أمكن؛ قم بالإعداد عبر openclaw CLI.", + "sessionKeyHint": "اختياري. حدّد مفتاح جلسة gateway؛ واتركه فارغًا للتعيين التلقائي لجلسة معزولة." + }, + "hermes": { + "configManagement": "تكوين Hermes", + "configDescription": "يدير Hermes بيانات اعتماده الخاصة في ~/.hermes/.env والإعدادات في ~/.hermes/config.yaml. اختر مزوّدًا، ثم عيّن مفتاح API والنموذج — وسيكتب codeg كلا الملفين نيابةً عنك.", + "providerLabel": "المزوّد", + "providerHint": "يحدّد المزوّد متغيّر مفتاح API و model.provider الذي يستخدمه Hermes. تُهيَّأ مزوّدات OAuth عبر إعداد الطرفية أدناه.", + "groupApiKey": "مزودو مفاتيح API", + "groupOauth": "مزودو OAuth", + "groupAws": "AWS", + "apiKeyHint": "يُحفظ في ~/.hermes/.env. ولا يُحقَن أبدًا في العملية — إذ يقرؤه Hermes من تكوينه الخاص.", + "modelName": "النموذج", + "oauthHint": "يستخدم هذا المزوّد OAuth. شغّل الإعداد أدناه للمصادقة في طرفيتك.", + "awsHint": "يستخدم Bedrock بيانات اعتماد AWS الخاصة بك (البيئة أو الإعداد المشترك). حدّد معرّف النموذج أعلاه واضبط وصول AWS في بيئتك.", + "unsupportedProvider": "لا يمكن تحرير هذا المزود عبر الحقول المنظمة. استخدم محرر config.yaml أدناه أو الإعداد عبر الطرفية.", + "setupTitle": "إعداد ذاتي الإدارة", + "setupHint": "يحتاج إعداد Hermes التفاعلي إلى طرفية. شغّله أدناه، أو انسخ الأمر لتشغيله بنفسك.", + "runSetup": "تشغيل إعداد Hermes", + "configureModel": "تهيئة النموذج", + "openConfigFolder": "فتح ~/.hermes", + "copyCommand": "نسخ الأمر", + "commandCopied": "تم نسخ الأمر إلى الحافظة", + "advancedTitle": "متقدّم: تحرير config.yaml", + "rawConfigHint": "حرّر ~/.hermes/config.yaml مباشرةً. الحفظ هنا يستبدل الملف حرفيًا.", + "saveRawConfig": "حفظ config.yaml" + }, + "codebuddy": { + "configManagement": "تكوين CodeBuddy", + "configDescription": "يصادق CodeBuddy باستخدام مفتاح API. تتطلب إصدارات الصين أيضًا ضبط البيئة على «الصين (internal)»؛ وتستخدم إصدارات iOA «iOA». أما الإصدار الخارجي فيتركها غير مضبوطة.", + "apiKeyLabel": "مفتاح API", + "apiKeyHint": "يُحفظ باسم CODEBUDDY_API_KEY لهذا الوكيل. بدلاً من ذلك، يمكنك تسجيل الدخول عبر واجهة CodeBuddy في الطرفية.", + "apiKeyHintSelfHosted": "يُحفظ باسم CODEBUDDY_API_KEY لهذا الوكيل. استخدم المفتاح الصادر عن نشرك الخاص.", + "environmentLabel": "البيئة", + "environmentHint": "يضبط CODEBUDDY_INTERNET_ENVIRONMENT. يجب أن تستخدم الصين «الصين (internal)»؛ أما الإصدار الخارجي فيتركها غير مضبوطة.", + "envOverseas": "الخارجي (افتراضي)", + "envChina": "الصين (internal)", + "envIoa": "iOA", + "envSelfHosted": "استضافة ذاتية (نشر خاص)", + "baseUrlLabel": "عنوان URL للنشر", + "baseUrlPlaceholder": "https://codebuddy.your-company.com", + "baseUrlHint": "يُحفظ باسم CODEBUDDY_BASE_URL ويوجّه CodeBuddy إلى نقطة النهاية الخاصة بك. في الاستضافة الذاتية يبقى إعداد الشبكة (CODEBUDDY_INTERNET_ENVIRONMENT) غير مضبوط.", + "baseUrlInvalid": "أدخل عنوان URL صالحًا بصيغة http(s).", + "loginHint": "لا تملك مفتاح API؟ شغّل «codebuddy» في الطرفية لتسجيل الدخول بحساب Tencent بدلاً من ذلك." + }, + "kimiCode": { + "configManagement": "إعدادات Kimi Code", + "configDescription": "لا يقبل `kimi acp` سوى رمز تسجيل دخول مخزَّن، لذا يكتب codeg مزوّدًا مُدارًا في ~/.kimi-code/config.toml ويزرع رمز بوابة محليًا — أما الاستدلال فيظل يعمل بمفتاحك أنت.", + "statusUnconfigured": "لم يُضبط بعد", + "statusDirty": "تغييرات غير محفوظة", + "summaryLabel": "المطبَّق حاليًا", + "gateReadyApiKey": "تمت كتابة مفتاح API في config.toml", + "gateReadyLogin": "تم تسجيل الدخول بحساب Kimi", + "revealConfig": "إظهار في المجلد", + "envOverrideWarning": "المتغير {keys} مضبوط وله أولوية على config.toml. الحفظ هنا يزيله.", + "authModeLabel": "طريقة المصادقة", + "authModeApiKey": "مفتاح API", + "authModeLogin": "تسجيل الدخول بحساب Kimi (اشتراك)", + "authModeApiKeyHint": "يكتب مزوّدًا مُدارًا في config.toml ويزرع رمز البوابة كي تتمكن الجلسات من الفتح.", + "loginHint": "شغّل `kimi login` في الطرفية لتسجيل الدخول بحساب اشتراك Kimi. لا يخزّن codeg أي بيانات اعتماد بل يعيد استخدام تسجيل دخول Kimi نفسه. الحفظ هنا يزيل رمز بوابة مفتاح API الخاص بـ codeg.", + "credentialTitle": "بيانات الاعتماد", + "interfaceTypeLabel": "نوع المزوّد", + "interfaceTypeHint": "بروتوكول المزوّد الذي يتحدث به Kimi (الحقل `type` في config.toml). اختر Kimi / Moonshot لمفتاح من Moonshot أو platform.kimi.com.", + "endpointLabel": "نقطة النهاية", + "endpointCustom": "مخصّص (متوافق مع OpenAI)", + "endpointHint": "دولي = api.moonshot.ai؛ الصين (مفاتيح platform.kimi.com) = api.moonshot.cn. أما المخصّص فيشير إلى أي نقطة نهاية متوافقة مع OpenAI.", + "regionInternational": "دولي (api.moonshot.ai)", + "regionChina": "الصين (api.moonshot.cn)", + "baseUrlLabel": "عنوان URL الأساسي", + "baseUrlHint": "اتركه فارغًا لاستخدام القيمة الافتراضية لحزمة SDK الخاصة بالمزوّد.", + "apiKeyLabel": "مفتاح API", + "apiKeyHint": "يُكتب في ~/.kimi-code/config.toml ويُستخدم للاستدلال. من platform.kimi.com أو platform.kimi.ai.", + "vertexProjectLabel": "مشروع GCP‏ (GOOGLE_CLOUD_PROJECT)", + "vertexLocationLabel": "منطقة GCP‏ (GOOGLE_CLOUD_LOCATION)", + "vertexHint": "يستخدم Vertex AI بيانات اعتماد التطبيق الافتراضية من Google — شغّل `gcloud auth application-default login` (بدون مفتاح API).", + "modelTitle": "النموذج", + "modelLabel": "النموذج", + "modelHint": "معرّف النموذج الذي يُكتب في config.toml. استخدم «اختبار وجلب النماذج» لمعرفة ما يمكن لمفتاحك الوصول إليه فعليًا.", + "maxContextLabel": "أقصى حجم للسياق", + "maxContextHint": "مطلوب وفق مخطط Kimi: بدونه يتجاهل Kimi كتلة النموذج بالكامل فلا يعود أي طلب بإجابة. القيمة الافتراضية 262144.", + "fetchModels": "اختبار وجلب النماذج", + "fetchModelsOk": "المفتاح يعمل — {count} نموذجًا متاحًا", + "fetchModelsEmpty": "المفتاح يعمل، لكن لم تُرجَع أي نماذج", + "fetchModelsFailed": "فشل الاختبار", + "fetchModelsNeedsKey": "أدخل أولًا مفتاح API ونقطة النهاية", + "modelNotInList": "هذا النموذج ليس ضمن القائمة التي يستطيع مفتاحك الوصول إليها — سيفشل Kimi برسالة «النموذج غير موجود».", + "reasoningTitle": "الاستدلال", + "reasoningEnableLabel": "تفعيل", + "reasoningDescription": "لا يعرض Kimi محدِّد «Thinking» في صندوق الإدخال إلا إذا أعلن النموذج عن قدرة استدلال، ولذلك يكتبها codeg هنا. يسري على الجلسات الجديدة.", + "effortsLabel": "المستويات المتاحة", + "effortsHint": "تصبح هذه المستويات خيارات محدِّد «Thinking». يمرِّر Kimi المستوى إلى المزوّد كما هو، فاختر ما يقبله نموذجك.", + "effortsEmptyHint": "من دون اختيار أي مستوى، يتراجع صندوق الإدخال إلى مفتاح Off / On فقط.", + "effortsCustomPlaceholder": "أضف مستوى آخر", + "effortsAdd": "إضافة", + "defaultEffortLabel": "المستوى الافتراضي", + "defaultEffortAuto": "اترك الاختيار لـ Kimi", + "alwaysThinkingLabel": "النموذج يستدل دائمًا — أزل خيار Off من المحدِّد", + "fixErrorsFirst": "صحّح الحقول المميّزة أولًا", + "errorModelRequired": "النموذج حقل مطلوب", + "errorMaxContextRequired": "أقصى حجم للسياق حقل مطلوب", + "errorMaxContextInvalid": "يجب أن يكون عددًا صحيحًا موجبًا", + "errorApiKeyRequired": "مفتاح API حقل مطلوب", + "errorApiKeyInvalid": "يجب ألا يحتوي مفتاح API على فواصل أسطر", + "errorBaseUrlRequired": "عنوان URL الأساسي حقل مطلوب", + "errorBaseUrlInvalid": "يجب أن يبدأ بـ http:// أو https://", + "errorVertexProjectRequired": "مشروع GCP حقل مطلوب", + "errorDefaultEffortUnlisted": "اختر أحد المستويات المحددة أعلاه", + "advancedTitle": "خيارات متقدمة", + "authTypeLabel": "موضع كتابة بيانات الاعتماد", + "authTypeApiKey": "‏api_key مضمَّن", + "authTypeEnv": "جدول env الفرعي للمزوّد", + "authTypeHint": "الموضع الذي يُكتب فيه مفتاح API داخل config.toml.", + "rawEditorLabel": "تحرير config.toml مباشرة", + "rawEditorWarning": "الحفظ هنا يستبدل الملف بأكمله حرفيًا، ويحل محل الإعدادات المنظَّمة أعلاه.", + "rawEditorPlaceholder": "[providers.codeg]\ntype = \"kimi\"\nbase_url = \"https://api.moonshot.cn/v1\"\napi_key = \"sk-...\"" + }, + "authModeOfficialSubscription": "الاشتراك الرسمي", + "authModeCustomEndpoint": "نقطة نهاية مخصصة", + "authModeCustomEndpointHint": "تكوين عنوان API ومفتاح API يدوياً لنقطة نهاية مخصصة.", + "authModeModelProvider": "مزود النموذج", + "modelProvider": "مزود النموذج", + "modelProviderHint": "استخدم عنوان API ومفتاح API والنموذج من مزود نموذج مُعدّ.", + "selectModelProvider": "اختر مزود النموذج", + "noModelProviderAvailable": "لا يوجد مزود نموذج مُعدّ لهذا الوكيل. انتقل إلى إعدادات مزود النموذج لإضافة واحد.", + "claude": { + "authMode": "وضع المصادقة", + "officialSubscription": "الاشتراك الرسمي", + "officialSubscriptionHint": "استخدم اشتراك Anthropic الرسمي، لا حاجة لمفتاح API.", + "mainModel": "النموذج الرئيسي", + "reasoningModel": "نموذج الاستدلال (thinking)", + "haikuDefaultModel": "نموذج Haiku الافتراضي", + "sonnetDefaultModel": "نموذج Sonnet الافتراضي", + "opusDefaultModel": "نموذج Opus الافتراضي", + "customModelOption": "معرّف النموذج المخصّص", + "customModelOptionName": "اسم النموذج المخصّص", + "customModelOptionDescription": "وصف النموذج المخصّص", + "customModelOptionHint": "يضيف عنصرًا مخصّصًا واحدًا إلى محدِّد نماذج Claude (مثل نموذج خلف بوابة/وكيل مخصّص). الاسم والوصف اختياريان لأغراض العرض فقط.", + "effortLevel": "مستوى الاستدلال", + "effortLevelDefault": "المستوى الافتراضي", + "effortLevel_low": "منخفض", + "effortLevel_medium": "متوسط", + "effortLevel_high": "مرتفع", + "effortLevel_xhigh": "مرتفع جداً", + "sendAttributionHeader": "إرسال معرّف الإسناد/الفوترة إلى الواجهة", + "sendAttributionHeaderAria": "إرسال معرّف الإسناد/الفوترة الخاص بـ Claude Code إلى الواجهة", + "disableNonessentialTraffic": "تعطيل القياس عن بُعد أو طلبات الشبكة غير الضرورية", + "disableNonessentialTrafficAria": "تعطيل القياس عن بُعد أو طلبات الشبكة غير الضرورية في Claude Code" + }, + "dialogs": { + "confirmDeleteProvider": "حذف المزود {providerId}؟", + "confirmDeleteProviderDescription": "سيتم تحديث إعداد OpenCode وauth JSON معًا. لا يمكن التراجع عن هذا الإجراء.", + "confirmUninstall": "إزالة تثبيت {name}؟", + "confirmUninstallDescription": "سيؤدي هذا إلى إزالة الإصدار المثبت محليًا. يمكنك إعادة التثبيت لاحقًا.", + "customInstallTitle": "تثبيت مخصص لـ {name}", + "customInstallDescription": "أدخل الإصدار المراد تثبيته. سيؤدي ذلك إلى إعادة التثبيت واستبدال الإصدار المثبت حاليًا.", + "customInstallVersionLabel": "رقم الإصدار", + "customInstallInvalid": "أدخل رقم إصدار صالحًا، مثل 1.2.3.", + "customInstallSubmit": "تثبيت" + }, + "errors": { + "windowsFileLocked": "ملفات {name} قيد الاستخدام بواسطة جلسة قيد التشغيل، لذا لا يمكن لـ Windows استبدالها. أغلق جميع جلسات {name} ثم حاول مرة أخرى.", + "nativeJsonMustBeObject": "يجب أن يكون إعداد JSON الأصلي كائنًا", + "nativeJsonInvalid": "خطأ في تنسيق إعداد JSON الأصلي: {message}", + "openCodeAuthMustBeObject": "يجب أن يكون OpenCode auth.json كائن JSON", + "openCodeAuthInvalid": "خطأ في تنسيق OpenCode auth.json: {message}", + "authMustBeObject": "يجب أن يكون auth.json كائن JSON", + "authInvalid": "خطأ في تنسيق auth.json: {message}", + "providerIdPattern": "يدعم معرّف المزود الأحرف والأرقام والشرطة السفلية والنقطة والشرطة فقط", + "providerExists": "المزوّد {providerId} موجود بالفعل", + "modelIdPattern": "يدعم معرّف النموذج الأحرف والأرقام والشرطة السفلية والنقطة والنقطتين والشرطة فقط", + "modelExists": "النموذج {modelId} موجود بالفعل" + }, + "warnings": { + "nativeJsonRecoveredStructured": "إعداد JSON الأصلي غير صالح؛ تمت إعادة التعيين إلى إعداد مُهيكل", + "nativeJsonRecoveredOpenCode": "إعداد JSON الأصلي غير صالح؛ تمت إعادة التعيين إلى إعداد OpenCode المُهيكل", + "openCodeAuthRecovered": "ملف OpenCode auth.json غير صالح؛ تمت إعادة التعيين إلى الإعداد الافتراضي", + "authRecoveredStructured": "ملف auth.json غير صالح؛ تمت إعادة التعيين إلى إعداد مُهيكل" + }, + "toasts": { + "agentActionCompleted": "اكتمل {action} لـ {name}", + "agentActionFailed": "فشل {action} لـ {name}", + "localVersion": "الإصدار المحلي: {version}", + "installCompletedVersionLater": "اكتمل التثبيت، سيتم تحديث الإصدار عند الفحص التالي", + "uninstallCompleted": "اكتملت إزالة تثبيت {name}", + "uninstallFailed": "فشلت إزالة تثبيت {name}", + "localVersionRemoved": "تمت إزالة الإصدار المحلي", + "saveAgentOrderFailed": "فشل حفظ ترتيب Agent", + "saveAgentSwitchFailed": "فشل حفظ مفتاح Agent", + "saveEnvFailed": "فشل حفظ متغيرات البيئة", + "grokSaved": "تم حفظ إعدادات Grok", + "saveGrokNativeFailed": "فشل حفظ إعدادات Grok الأصلية", + "saveGrokApiKeyFailed": "تم حفظ الإعدادات، لكن تعذّر حفظ مفتاح API", + "cursorSaved": "تم حفظ إعدادات Cursor", + "saveCursorConfigFailed": "فشل حفظ إعدادات Cursor", + "codexSaved": "تم حفظ إعداد Codex", + "saveCodexNativeFailed": "فشل حفظ إعداد Codex الأصلي", + "geminiSaved": "تم حفظ إعداد Gemini", + "saveGeminiFailed": "فشل حفظ إعداد Gemini", + "providerDeleted": "تم حذف المزود {providerId}", + "providerDeleteFailed": "فشل حذف المزود {providerId}", + "providerSaved": "تم حفظ المزود {providerId}", + "saveProviderFailed": "فشل حفظ المزود {providerId}", + "openCodeConfigSynced": "تمت مزامنة إعداد OpenCode وauth JSON.", + "openCodeSaved": "تم حفظ إعداد OpenCode", + "saveOpenCodeFailed": "فشل حفظ إعداد OpenCode", + "openClawSaved": "تم حفظ إعداد OpenClaw", + "saveOpenClawFailed": "فشل حفظ إعداد OpenClaw", + "configSaved": "تم حفظ الإعداد", + "configSavedHint": "يجب إعادة فتح الجلسات الحالية لتطبيق التغييرات", + "saveConfigManagementFailed": "فشل حفظ إدارة الإعدادات", + "clineSaved": "تم حفظ تكوين Cline", + "saveClineFailed": "فشل في حفظ تكوين Cline", + "hermesSaved": "تم حفظ تكوين Hermes", + "saveHermesFailed": "فشل في حفظ تكوين Hermes", + "codeBuddySaved": "تم حفظ إعدادات CodeBuddy", + "saveCodeBuddyFailed": "فشل حفظ إعدادات CodeBuddy", + "kimiCodeSaved": "تم حفظ إعدادات Kimi Code", + "saveKimiCodeFailed": "فشل حفظ إعدادات Kimi Code", + "deepseekSaved": "تم حفظ إعدادات DeepSeek", + "saveDeepSeekFailed": "تعذّر حفظ إعدادات DeepSeek", + "modelProviderRequired": "يرجى اختيار مزود نموذج قبل الحفظ.", + "affectedRunningSessions": "{count} جلسة نشطة تحتاج إلى إعادة الاتصال لتطبيق التغيير", + "providerConnected": "تم ربط {providerId}", + "connectFailed": "فشل ربط {providerId}", + "providerDisconnected": "تم قطع اتصال {providerId}", + "disconnectFailed": "فشل قطع اتصال {providerId}", + "catalogRefreshed": "تم تحديث الكتالوج — {count} مزودًا", + "catalogRefreshFailed": "فشل تحديث الكتالوج", + "piSaved": "تم حفظ إعدادات Pi", + "savePiFailed": "فشل حفظ إعدادات Pi", + "piRuntimeSaved": "تم حفظ وقت تشغيل Pi", + "savePiRuntimeFailed": "فشل حفظ وقت تشغيل Pi", + "piBinaryInstalled": "تم تثبيت pi", + "piBinaryInstallFailed": "فشل تثبيت pi", + "piBinaryUninstalled": "تم إلغاء تثبيت pi", + "piBinaryUninstallFailed": "فشل إلغاء تثبيت pi", + "savePiTrustFailed": "فشل حفظ الثقة بمساحة العمل" + }, + "version": { + "statusLabel": "حالة الإصدار", + "notInstalled": "غير مثبت", + "remoteLocal": "البعيد: {remoteVersion} · المحلي: {localVersion}", + "localOnly": "المحلي: {localVersion}", + "localInstalled": "{versionText}. مثبت.", + "platformUnsupported": "{versionText}. المنصة الحالية لا تدعم هذا الوكيل.", + "uvxNotReady": "{versionText}. وقت تشغيل uv غير مثبّت — ثبّته من فحص uv بالأسفل لاستخدام هذا الوكيل.", + "clickInstall": "{versionText}. انقر تثبيت في الجهة اليمنى.", + "localUnrecognized": "{versionText}. الإصدار المحلي غير قابل للمقارنة؛ جرّب الترقية للكتابة فوق التثبيت.", + "upgradeAvailable": "{versionText}. تتوفر ترقية.", + "remoteUnavailable": "{versionText}. الإصدار البعيد غير متاح حاليًا.", + "latest": "{versionText}. أنت على أحدث إصدار." + }, + "adapter": { + "label": "محوّل ACP", + "badge": "محوّل ACP", + "badgeHint": "بالنسبة لهذا الوكيل يثبّت Codeg حزمة محوّل ACP وليس واجهة الأوامر الرسمية. الاثنان مستقلان ويتشاركان الإعدادات نفسها.", + "learnMore": "معرفة المزيد", + "missingWithNative": "تم العثور على {nativeLabel} الخاصة بك في {nativePath}. يتواصل Codeg مع الوكلاء عبر ACP، وهذه الواجهة لا تدعم ACP، لذا يحتاج Codeg إلى حزمة محوّل منفصلة هي {adapterPackage}، يتولى صيانتها مشروع Agent Client Protocol (بدأه فريق Zed). تأتي ببيئة تشغيل خاصة بها، ولا تعدّل أمر {nativeCmd} لديك ولا تستبدله، وتقرأ المسار {configDir} نفسه — فتسجيل الدخول والإعدادات الحالية تبقى كما هي. ثبّتها من الأسفل.", + "missing": "يتواصل Codeg مع الوكلاء عبر ACP، و{nativeLabel} لا تدعم ACP، لذا يحتاج Codeg إلى حزمة محوّل منفصلة هي {adapterPackage}، يتولى صيانتها مشروع Agent Client Protocol (بدأه فريق Zed). تأتي ببيئة تشغيل خاصة بها، فلا حاجة لتثبيت {nativeCmd} أولاً؛ وإن كانت لديك فالاثنان يتعايشان ويتشاركان تسجيل الدخول والإعدادات في {configDir}. ثبّتها من الأسفل.", + "readyWithNative": "المحوّل {adapterCmd} مثبّت — وهو ما يشغّله Codeg، وليس {nativeCmd} الخاص بك في {nativePath}. هما حزمتان مستقلتان تتعايشان، وكلتاهما تقرأ {configDir}، لذا فتسجيل الدخول والإعدادات مشتركة.", + "ready": "المحوّل {adapterCmd} مثبّت — وهو ما يشغّله Codeg. يأتي ببيئة تشغيل خاصة به، لذا لا حاجة إلى {nativeLabel}؛ وإن ثبّتها لاحقاً فالاثنان يتعايشان ويتشاركان {configDir}." + }, + "cline": { + "configDescription": "تكوين مزود واجهة برمجة التطبيقات وبيانات اعتماد Cline. يتم حفظ الإعدادات في ~/.cline/data/." + }, + "opencodePlugins": { + "title": "إضافات OpenCode", + "declared": "الإضافات المعلنة", + "noPlugins": "لا توجد إضافات معلنة في opencode.json", + "status": { + "installed": "مثبّت", + "missing": "غير مثبّت" + }, + "installAll": "تثبيت جميع الإضافات المفقودة", + "pinVersions": "تثبيت إصدارات @latest", + "install": "تثبيت", + "uninstall": "إزالة", + "refresh": "تحديث", + "success": "تم تثبيت جميع الإضافات بنجاح", + "failed": "فشلت عملية الإضافة" + }, + "pi": { + "configManagement": "إعدادات Pi", + "configDescription": "يصادق Pi عبر مفتاح API لمزوّد النموذج. يُكتب المفتاح في ~/.pi/agent/auth.json واختيار النموذج في settings.json.", + "providerLabel": "المزوّد", + "modelLabel": "النموذج", + "thinkingLabel": "التفكير", + "thinking": { + "off": "إيقاف", + "low": "منخفض", + "medium": "متوسط", + "high": "مرتفع", + "minimal": "الحد الأدنى", + "xhigh": "مرتفع جدًا" + }, + "apiKeyLabel": "مفتاح API", + "apiKeyHint": "يُحفظ في ~/.pi/agent/auth.json للمزوّد المحدد.", + "apiKeySetPlaceholder": "•••••• (محفوظ — اتركه فارغًا للإبقاء عليه)", + "saveConfig": "حفظ إعدادات Pi", + "providerModelRequired": "المزوّد والنموذج مطلوبان", + "runtimeTitle": "وقت التشغيل", + "runtimeDescription": "اختر أي ملف pi يعمل. استخدم الافتراضي أو أشِر إلى بناء pi الخاص بك.", + "modeDefault": "pi الافتراضي", + "modeDefaultHint": "يستخدم محوّل pi-acp المدمج مع pi الموجود في PATH. ثبّت pi عبر: npm install -g @earendil-works/pi-coding-agent", + "modeCustom": "pi مخصّص", + "modeCustomHint": "شغّل بناء pi أو تثبيته أو غلافه الخاص بك.", + "commandLabel": "أمر pi أو مساره", + "commandHint": "مسار مطلق، أو اسم أمر في PATH، أو نص غلاف (مثل ./pi-test.sh في monorepo).", + "commandNotFound": "الأمر غير موجود", + "validate": "تحقّق", + "advanced": "متقدّم", + "configDirLabel": "دليل الإعدادات (PI_CODING_AGENT_DIR)", + "sessionDirLabel": "دليل الجلسات (PI_CODING_AGENT_SESSION_DIR)", + "flagsHint": "لا يمرّر pi-acp رايات pi المخصّصة (‎--approve، ‎-e، …) — غلّف pi بنص وأشِر الأمر إليه.", + "customIncomplete": "أدخل أمر pi للحفظ", + "saveRuntime": "حفظ وقت التشغيل", + "providerPlaceholder": "اختر مزوّدًا", + "customProvider": "مزوّد مخصّص…", + "providerIdLabel": "معرّف المزوّد", + "apiProtocolLabel": "بروتوكول API", + "baseUrlLabel": "نقطة نهاية API (عنوان URL الأساسي)", + "customProviderHint": "يعرّف مزوّدًا في ~/.pi/agent/models.json عند نقطة النهاية الخاصة بك. تستخدم معظم الخوادم الذاتية الاستضافة أو الوسيطة openai-completions.", + "baseUrlRequired": "نقطة نهاية API (عنوان URL الأساسي) مطلوبة", + "binaryTitle": "ثنائي pi (pi-coding-agent)", + "binaryDescription": "يشغّل pi-acp ثنائي pi هذا. ثبّته هنا، أو وجّه pi-acp إلى نسختك الخاصة أدناه.", + "binaryInstalled": "مثبَّت", + "binaryMissing": "غير مثبَّت", + "binaryChecking": "جارٍ التحقق…", + "installBinary": "تثبيت pi", + "installing": "جارٍ التثبيت…", + "recheck": "إعادة التحقق", + "configDirSkillsNote": "عند تحديد دليل إعدادات مخصص، لن تنطبق المهارات والخبراء وأدوات المكتب المُدارة في الإعدادات على pi هذا — أدِر مهاراته مباشرةً في ذلك المجلد.", + "projectTrustTitle": "ثقة المشروع", + "projectTrustDescription": "المجلدات التي سمحت لـ pi بتحميل ملفات المشروع منها. المجلد الموثوق يتيح لملفات ‎.pi/extensions في ذلك المستودع تنفيذ التعليمات البرمجية عند بدء pi، ويسري على كل المجلدات داخله، ويُستخدم أيضًا عند تشغيل pi في الطرفية.", + "projectTrustLoading": "جارٍ التحميل…", + "projectTrustEmpty": "لم يتم اتخاذ قرار بشأن أي مجلد بعد.", + "projectTrustTrusted": "موثوق", + "projectTrustDenied": "غير موثوق", + "projectTrustRevoke": "إلغاء", + "reasoningTitle": "الاستدلال", + "reasoningEnableLabel": "تفعيل", + "reasoningDescription": "لا يرسل pi مستوى استدلال إلا لنموذج يعلن عنه — أي نموذج غير معلن تُخفَّض كل مستوياته إلى Off، فيعود المحدِّد في صندوق الإدخال إلى وضعه فور لمسه. يُكتب في مدخل هذا النموذج داخل models.json.", + "levelsLabel": "المستويات المتاحة", + "levelsHint": "تصبح هذه هي خيارات محدِّد الاستدلال في صندوق الإدخال. اختر ما تقبله نقطة النهاية لديك؛ فأي مستوى غير مدرج هنا يرفضه pi.", + "levelsEmptyError": "اختر مستوى واحدًا على الأقل — بدون أي مستوى يعود pi إلى Off.", + "wireValuesTitle": "متقدم: القيم المرسلة إلى المزوّد", + "wireValuesHint": "اتركه فارغًا لإرسال اسم المستوى كما هو. اضبطه عندما تتوقع نقطة النهاية صيغة أخرى — الواجهات على نمط Google تحتاج LOW / HIGH.", + "defaultLevelUnlisted": "هذا المستوى ليس ضمن القائمة أعلاه — سيخفّضه pi." + }, + "addCustomAgent": "إضافة وكيل مخصص", + "addCustomAgentHint": "سجّل أي وكيل متوافق مع ACP. اختر واحدًا من سجل ACP العام، أو الصق معلومات السجل الخاصة به.", + "customAgentFromRegistry": "سجل ACP", + "customAgentManual": "يدوي", + "customAgentSearchPlaceholder": "البحث عن الوكلاء…", + "customAgentLoadingCatalog": "جارٍ تحميل سجل ACP…", + "customAgentRetry": "إعادة المحاولة", + "customAgentNoResults": "لا يوجد وكلاء مطابقون", + "customAgentAdd": "إضافة", + "customAgentAlreadyAdded": "تمت الإضافة", + "customAgentUnsupportedPlatform": "لا يوجد إصدار متاح لهذه المنصة", + "customAgentAdded": "تمت إضافة {name}", + "customAgentIdLabel": "معرّف السجل", + "customAgentNameLabel": "الاسم المعروض", + "customAgentVersionLabel": "الإصدار", + "customAgentSpecLabel": "التوزيع (JSON)", + "customAgentSpecHint": "بنفس شكل كائن distribution في سجل ACP: قنوات npx وuvx وbinary، أو الصق مدخل سجل كاملًا. في npx/uvx يكون cmd هو الأمر التنفيذي الذي تثبته الحزمة — يُشتق من اسم الحزمة عند إغفاله، فحدده عندما يختلفان. يُنظَّم binary حسب مفتاح المنصة (هذا الجهاز: {platform})؛ cmd هو مسار التشغيل داخل الأرشيف، وsha256 اختياري للتحقق من التنزيل.", + "customAgentTemplateLabel": "قوالب", + "customAgentKindLabel": "التشغيل عبر", + "customAgentInvalidJson": "JSON غير صالح", + "customAgentNoDistribution": "لم يتم العثور على توزيع npx أو uvx أو binary", + "customAgentCancel": "إلغاء", + "customAgentSave": "إضافة الوكيل", + "customAgentSaveChanges": "حفظ التغييرات", + "customAgentEdit": "تحرير الوكيل", + "customAgentEditHint": "حدّث الاسم والأيقونة ومعلومات التوزيع وإعلانات المهارات. لا يمكن تغيير معرّف الوكيل.", + "customAgentEditNotFound": "لم يُعثر على الوكيل المخصص {id}", + "customAgentSaved": "تم حفظ {name}", + "customAgentVersionProbeLabel": "أمر الاستعلام عن الإصدار (اختياري)", + "customAgentVersionProbeHint": "أمر يطبع الإصدار المثبت محليًا. عند تركه فارغًا يشغّل codeg أمر الوكيل مع ‎--version.", + "customAgentRemove": "إزالة الوكيل", + "customAgentRemoveHint": "يحذف تعريف الوكيل. تحتفظ المحادثات الحالية بسجلها، ولن يصبح بالإمكان تشغيل الوكيل فحسب.", + "customAgentIconLabel": "الأيقونة (اختياري)", + "customAgentIconUpload": "رفع", + "customAgentIconReplace": "استبدال", + "customAgentIconClear": "إزالة الأيقونة", + "customAgentIconHint": "يُحفظ مع الوكيل، لذا يعمل دون اتصال. وبدونه يُستخدم حرف أول ملوّن.", + "customAgentSkillsLabel": "Skills (‎.agents/skills المشترك)", + "customAgentSkillsHint": "يُعلن أن هذا الوكيل يقرأ مخزن .agents/skills المشترك (المجلدين العام والخاص بالمشروع) ويضيفه إلى جميع مصفوفات المهارات. المهارات المرتبطة هناك تكون مرئية لكل وكيل يقرأ هذا المخزن المشترك.", + "customAgentSkillsDirLabel": "دليل مهارات مخصص", + "customAgentSkillsDirHint": "المسار المطلق للدليل الذي يحمّل منه هذا الوكيل المهارات — مخزنه الخاص، إضافةً إلى المخزن المشترك أو بدلًا منه. يتم توسيع ~ إلى الدليل الرئيسي؛ وتوضع المهارات المرتبطة هنا أولًا.", + "customAgentMcpLabel": "دعم MCP", + "customAgentMcpHint": "يرسل رفيق MCP المدمج في codeg إلى هذا الوكيل عند بدء الجلسة — وهو القناة التي تعتمد عليها الإحالة والتغذية الراجعة الحية وأدوات المهام. أوقفه مع الوكلاء الذين يرفضون خوادم MCP ويفشلون في الاتصال؛ ويسري التغيير من الاتصال التالي.", + "customAgentIconNotAnImage": "اختر ملف صورة.", + "customAgentIconTooLarge": "يجب أن يكون حجم الأيقونة أقل من {limit} كيلوبايت.", + "customAgentIconReadFailed": "تعذّرت قراءة تلك الصورة.", + "customAgentRemoveConfirm": "إزالة {name}؟ ستبقى المحادثات الحالية، لكن لن يمكن تشغيل الوكيل بعد الآن.", + "customAgentRemoveWithData": "حذف سجل المحادثات المسجل أيضًا", + "customAgentRemoved": "تمت إزالة {name}", + "customAgentBadge": "مخصص", + "customAgentNotLaunchable": "لا يمكن تشغيل هذا الوكيل هنا: {reason}" + }, + "SettingsPages": { + "agentsLoading": "جارٍ تحميل إعدادات الوكلاء...", + "skillPacksLoading": "جارٍ تحميل حزم المهارات…" + }, + "GeneralSettings": { + "loading": "جارٍ التحميل...", + "sectionTitle": "عام", + "sectionDescription": "تفضيلات موحّدة للطرفية الافتراضية وتسريع العرض وتفويض الوكلاء المتعدّدين.", + "terminalTitle": "الطرفية الافتراضية", + "terminalDescription": "اختر الصدفة المستخدمة عند فتح علامات تبويب طرفية جديدة من شريط الطرفية أو شجرة الملفات. تستخدمها الوكلاء أيضًا عندما تطلب من codeg تنفيذ سطر أوامر كامل نيابةً عنها.", + "terminalSystemDefault": "افتراضي النظام", + "terminalPowerShell7": "PowerShell 7 (pwsh)", + "terminalWindowsPowerShell": "Windows PowerShell", + "terminalCmd": "موجّه الأوامر (cmd)", + "terminalSaveFailed": "فشل حفظ إعدادات الطرفية: {message}", + "terminalShellCustom": "مسار مخصص", + "terminalShellCustomPath": "مسار الصدفة", + "terminalShellCustomPlaceholder": "/usr/local/bin/fish", + "terminalShellCustomSave": "حفظ", + "terminalShellCustomHint": "أدخل مساراً مطلقاً أو اسماً يمكن حلّه عبر PATH.", + "terminalShellNotInstalled": "غير مثبّت", + "terminalShellNotFoundWarning": "هذا المسار غير موجود على هذا المضيف.", + "terminalCurrentShell": "قيد الاستخدام: {path}", + "renderingDescription": "أوقف تشغيل تسريع الأجهزة إذا ظهرت شاشة سوداء أو أخطاء في العرض (شائع على بعض كروت AMD أو كروت Intel المدمجة). يسري على إصدار سطح المكتب لويندوز فقط.", + "disableHardwareAcceleration": "تعطيل تسريع الأجهزة", + "renderingSaveFailed": "فشل حفظ إعدادات العرض: {message}", + "restartRequired": "تم الحفظ. أعد تشغيل التطبيق ليصبح التغيير نافذًا.", + "restartNow": "إعادة التشغيل الآن", + "restartFailed": "فشل إعادة التشغيل: {message}", + "loadFailed": "فشل التحميل: {message}" + }, + "LoginPage": { + "documentTitle": "تسجيل الدخول - codeg", + "brand": "Codeg", + "subtitle": "أدخل رمز الوصول للاتصال بتطبيق سطح المكتب", + "tokenPlaceholder": "رمز الوصول", + "connect": "اتصال", + "connecting": "جارٍ الاتصال...", + "helpText": "يمكنك الحصول على الرمز من تطبيق سطح المكتب عبر الإعدادات → خدمة الويب", + "invalidToken": "رمز غير صالح. يرجى التحقق والمحاولة مرة أخرى.", + "connectionFailed": "فشل الاتصال (HTTP {status})", + "networkError": "تعذر الاتصال بالخادم" + }, + "CommitPage": { + "title": "التزام", + "invalidFolderId": "معرّف المجلد غير صالح", + "loadingRepo": "جارٍ تحميل المستودع..." + }, + "MergePage": { + "title": "حل التعارضات", + "invalidFolderId": "معرّف المجلد غير صالح", + "loadingRepo": "جارٍ تحميل المستودع...", + "localVersion": "محلي (الخاص بنا)", + "result": "النتيجة", + "remoteVersion": "بعيد (الخاص بهم)", + "acceptLocal": "قبول المحلي", + "acceptRemote": "قبول البعيد", + "markResolved": "تحديد كمحلول", + "abortMerge": "إلغاء", + "completeMerge": "إتمام الدمج", + "unresolvedConflicts": "لا تزال هناك علامات تعارض غير محلولة في هذا الملف", + "fileResolved": "تم حل الملف بنجاح", + "allResolved": "تم حل جميع التعارضات", + "conflictFiles": "ملفات متعارضة", + "loadingFile": "جارٍ تحميل الملف...", + "preparingMerge": "جارٍ تحضير الدمج...", + "selectFile": "اختر ملفًا لحله", + "noConflicts": "لا توجد ملفات متعارضة", + "skipFile": "تخطي", + "abortSuccess": "تم إلغاء العملية", + "applyAllNonConflicting": "تطبيق جميع التغييرات غير المتعارضة", + "applyLeftNonConflicting": "تطبيق المحلي", + "applyRightNonConflicting": "تطبيق البعيد" + }, + "ImportSessions": { + "title": "استيراد الجلسات المحلية", + "scanningTitle": "جارٍ فحص جلسات الوكلاء المحلية…", + "scanningHint": "يجري المرور على مخزن الجلسات المحلي لكل وكيل. قد يستغرق ذلك بعض الوقت مع السجلات الكبيرة. ويجري خلال ذلك تحديث الجلسات المستوردة سابقًا.", + "scanFailed": "فشل الفحص", + "retry": "إعادة المحاولة", + "rescan": "إعادة الفحص", + "empty": "لم يُعثر على جلسات محلية", + "emptyHint": "لم يُعثر على مخازن جلسات للوكلاء على هذا الجهاز.", + "noMatches": "لا توجد جلسات مطابقة للمرشحات الحالية", + "searchPlaceholder": "ابحث في العنوان أو المسار…", + "allAgents": "جميع الوكلاء", + "onlyImportable": "القابلة للاستيراد فقط", + "selectAll": "تحديد الكل", + "clearSelection": "مسح", + "expandAll": "توسيع الكل", + "collapseAll": "طي الكل", + "summaryCounts": "{total} جلسة · {importable} قابلة للاستيراد · {folders} مجلدًا", + "noFolderSkipped": "تم تخطي {count} بدون مجلد مشروع", + "folderNew": "جديد", + "folderCounts": "قابلة للاستيراد {importable}/{total}", + "toggleFolderAria": "تحديد كل الجلسات القابلة للاستيراد في {name}", + "toggleSessionAria": "تحديد الجلسة {title}", + "statusImported": "مستوردة", + "statusDeleted": "محذوفة", + "untitled": "جلسة بلا عنوان", + "messageCount": "{count} رسالة", + "selectedCount": "{count} محددة", + "importSelected": "استيراد المحدد", + "importing": "جارٍ الاستيراد…", + "close": "إغلاق", + "doneTitle": "اكتمل الاستيراد", + "doneImported": "مستوردة", + "doneUpdated": "محدّثة", + "doneSkipped": "متخطاة", + "doneCreatedFolders": "مجلدات منشأة", + "doneNotFound": "غير موجودة", + "doneFailed": "فاشلة", + "continueImport": "متابعة الاستيراد", + "toasts": { + "importFailed": "فشل الاستيراد: {message}" + } + }, + "Folder": { + "workspaceStatus": { + "degradedTitle": "التحديثات الفورية غير متاحة", + "degradedHint": "فشل تشغيل المراقب (مثل رفض الإذن). قم بالتحديث يدويًا لرؤية التغييرات.", + "retry": "إعادة المحاولة", + "retrying": "جارٍ إعادة المحاولة..." + }, + "common": { + "all": "الكل", + "cancel": "إلغاء", + "close": "إغلاق", + "closeOthers": "إغلاق البقية", + "closeAll": "إغلاق الكل", + "confirm": "تأكيد", + "save": "حفظ", + "delete": "حذف", + "rename": "إعادة تسمية", + "loading": "جارٍ التحميل...", + "refresh": "تحديث", + "refreshing": "جارٍ التحديث...", + "create": "إنشاء", + "createAndSwitch": "إنشاء والتبديل", + "openFile": "فتح الملف", + "viewDiff": "عرض Diff", + "push": "دفع..." + }, + "statusLabels": { + "in_progress": "قيد التنفيذ", + "pending_review": "مراجعة", + "completed": "مكتمل", + "cancelled": "ملغى" + }, + "sidebar": { + "title": "المحادثات", + "locateActiveConversation": "تحديد المحادثة النشطة", + "expandAllGroups": "توسيع كل المجموعات", + "collapseAllGroups": "طي كل المجموعات", + "newConversation": "محادثة جديدة", + "newConversationShort": "جديدة", + "newChat": "محادثة جديدة", + "search": "بحث", + "noConversationsFound": "لم يتم العثور على محادثات.", + "importLocalSessions": "استيراد الجلسات المحلية", + "importing": "جارٍ الاستيراد...", + "error": "خطأ: {message}", + "completeAllSessions": "إكمال جميع الجلسات", + "completeAllReviewTitle": "إكمال جميع جلسات المراجعة؟", + "completeAllReviewDescription": "سيؤدي ذلك إلى وضع علامة مكتمل على جميع {count, plural, one {# جلسة} other {# جلسات}} في المراجعة.", + "completing": "جارٍ الإكمال...", + "toasts": { + "importedSessions": "تم استيراد {imported, plural, one {# جلسة} other {# جلسات}}، وتم تخطي {skipped}", + "importedAndUpdated": "تم استيراد {imported, plural, one {# جلسة} other {# جلسات}}، وتم تحديث {updated, plural, one {# عنوان} other {# عناوين}}، وتم تخطي {skipped}", + "updatedTitles": "تم تحديث {updated, plural, one {# عنوان} other {# عناوين}}، وتم تخطي {skipped}", + "noNewSessionsFound": "لم يتم العثور على جلسات جديدة (تم تخطي {skipped})", + "importFailed": "فشل الاستيراد: {message}", + "reviewCompleted": "تم وضع علامة مكتمل على {count, plural, one {# جلسة مراجعة} other {# جلسات مراجعة}}", + "completeReviewFailed": "فشل إكمال جلسات المراجعة: {message}", + "folderOpened": "تم فتح المجلد {name}", + "folderRemoved": "تمت إزالة المجلد {name}", + "openFolderFailed": "فشل فتح المجلد", + "removeFolderFailed": "فشل إزالة المجلد: {message}", + "reorderFoldersFailed": "فشل إعادة ترتيب المجلدات: {message}", + "changeFolderColorFailed": "فشل تغيير اللون: {message}", + "setFolderAliasFailed": "فشل تعيين الاسم المستعار: {message}", + "changeFolderDefaultAgentFailed": "فشل تعيين الوكيل الافتراضي: {message}" + }, + "statsLabel": "{folders} مجلدات · {convos} محادثة", + "reorderHandle": "اسحب لإعادة الترتيب", + "openFolder": "فتح مجلد", + "searchPlaceholder": "بحث عن محادثات...", + "viewOptions": "خيارات العرض", + "showCompleted": "عرض المحادثات المكتملة", + "showWorktrees": "عرض مجلدات worktree", + "showRecent": "عرض مجموعة الأحدث", + "moreOptions": "المزيد من الخيارات", + "sortBy": "الترتيب حسب", + "sortByCreatedAt": "وقت الإنشاء", + "sortByUpdatedAt": "وقت التحديث", + "sectionOrder": "ترتيب الأقسام", + "sectionOrderMoveUp": "تحريك لأعلى", + "sectionOrderMoveDown": "تحريك لأسفل", + "sectionOrderItemLabel": "{name} — الموضع {position} من {total}", + "statusRunningBadge": "قيد التشغيل", + "runningCountBadge": "{count} جلسة قيد التشغيل", + "statusCancelledBadge": "ملغى", + "worktreeRemovedBadge": "تمت إزالة شجرة العمل الأصلية", + "conversationCountUnit": "{count} محادثة", + "emptyFolderHint": "لا توجد محادثات", + "noMatchingConversations": "لا توجد محادثات مطابقة", + "noUnfinishedConversations": "لا توجد محادثات غير مكتملة. يمكنك تفعيل \"عرض المكتملة\" من القائمة في أعلى اليمين.", + "removeFolderConfirmTitle": "إزالة المجلد من مساحة العمل؟", + "removeFolderConfirmDescription": "إزالة \"{name}\" من مساحة العمل؟ سيتم إغلاق علامات التبويب والمحطات المرتبطة.", + "folderHeaderMenu": { + "manageConversations": "إدارة المحادثات…", + "manageLinks": "المجلدات المرتبطة", + "changeColor": "تغيير اللون", + "useThemeColor": "استخدام سمة التطبيق", + "setDefaultAgent": "تعيين الوكيل الافتراضي", + "defaultAgentNone": "بدون افتراضي (استخدام العام)", + "agentUnavailableSuffix": "(غير متاح)", + "loadingAgents": "جارٍ تحميل الوكلاء…", + "setAlias": "تعيين اسم مستعار…", + "setAliasTitle": "تعيين اسم مستعار للمجلد", + "setAliasPlaceholder": "أدخل اسمًا مستعارًا (اتركه فارغًا للمسح)", + "setAliasSave": "حفظ", + "setAliasCancel": "إلغاء", + "removeFromWorkspace": "إزالة من مساحة العمل" + }, + "manageConversations": { + "title": "إدارة المحادثات", + "searchPlaceholder": "البحث بالعنوان…", + "agentFilterAll": "جميع الوكلاء", + "statusFilterAll": "جميع الحالات", + "folderFilterAll": "كل المجلدات", + "branchFilterAll": "كل الفروع", + "branchNone": "بدون فرع", + "branchSearchPlaceholder": "بحث في الفروع…", + "noMatchingBranches": "لا توجد فروع مطابقة", + "selectAllVisible": "تحديد الكل", + "deselectAll": "إلغاء التحديد", + "selectedCount": "{count} محدد", + "matchedCount": "{count} مطابق", + "untitledConversation": "محادثة بدون عنوان", + "setStatus": "تعيين الحالة…", + "deleteSelected": "حذف", + "noConversations": "لا توجد محادثات في هذا المجلد.", + "noConversationsWorkspace": "لا توجد محادثات في مساحة العمل.", + "noMatchingConversations": "لا توجد محادثات مطابقة للفلاتر.", + "confirmDeleteTitle": "حذف {count} محادثة؟", + "confirmDeleteDescription": "لا يمكن التراجع عن هذا الإجراء.", + "toastDeleted": "تم حذف {count} محادثة", + "toastStatusUpdated": "تم تحديث حالة {count} محادثة", + "toastOpFailed": "فشلت العملية: {message}" + }, + "sectionPinned": "مثبّتة", + "sectionFolders": "المجلدات", + "sectionChats": "محادثة", + "sectionRecent": "الأحدث", + "noChats": "لا توجد محادثات", + "noRecent": "لا توجد محادثات حديثة", + "showMoreRecent": "عرض المزيد ({count})", + "noFolders": "لا توجد مجلدات مفتوحة", + "newChatAction": "محادثة جديدة", + "automations": "الأتمتة", + "tasks": "المهام قيد الانتظار", + "loadingSubsessions": "جارٍ تحميل المحادثات الفرعية…" + }, + "conversation": { + "reloadFailed": "فشل إعادة تحميل المحادثة: {message}", + "reloaded": "تمت إعادة تحميل المحادثة", + "reload": "إعادة تحميل", + "activeConversationIndicator": "المحادثة النشطة", + "newConversation": "محادثة جديدة", + "closeConversation": "إغلاق المحادثة", + "copyText": "نسخ النص", + "copyTextSuccess": "تم النسخ", + "copyTextFailed": "فشل النسخ", + "forkSession": "تفريع الجلسة", + "forkSessionSuccess": "تم تفريع الجلسة بنجاح", + "forkSessionFailed": "فشل في تفريع الجلسة: {error}", + "exportConversation": "تصدير المحادثة", + "exportImage": "صورة", + "exportMarkdown": "Markdown", + "exportHtml": "HTML", + "exportSuccess": "تم تصدير المحادثة", + "exportFailed": "فشل التصدير", + "exportImageTooLong": "المحادثة طويلة جداً ولا يمكن تصديرها كصورة", + "exportLabels": { + "untitledConversation": "محادثة بدون عنوان", + "agent": "الوكيل", + "model": "النموذج", + "status": "الحالة", + "started": "البداية", + "updated": "التحديث", + "tokens": "إحصائيات الرموز", + "duration": "المدة", + "inputTokens": "الإدخال", + "outputTokens": "الإخراج", + "cacheRead": "قراءة الذاكرة", + "cacheWrite": "كتابة الذاكرة", + "user": "المستخدم", + "assistant": "المساعد", + "system": "النظام", + "toolResult": "النتيجة", + "toolError": "خطأ" + }, + "moreActions": "إجراءات إضافية" + }, + "sessionDetails": { + "menuLabel": "تفاصيل الجلسة", + "noActiveSession": "لا توجد جلسة نشطة", + "title": "تفاصيل الجلسة", + "subtitle": "بيانات الجلسة الوصفية واستخدام الرموز", + "fieldTitle": "العنوان", + "untitled": "محادثة بدون عنوان", + "sessionId": "معرّف الجلسة", + "externalId": "معرّف الامتداد", + "agent": "الوكيل", + "model": "النموذج", + "status": "الحالة", + "gitBranch": "فرع Git", + "parentId": "الجلسة الأصلية", + "tokensHeading": "استخدام الرموز", + "totalTokens": "الإجمالي", + "inputTokens": "الإدخال", + "outputTokens": "الإخراج", + "cacheWrite": "كتابة الذاكرة", + "cacheRead": "قراءة الذاكرة", + "contextWindow": "نافذة السياق", + "duration": "المدة", + "loadingStats": "جارٍ تحميل استخدام الرموز…", + "loadFailed": "فشل تحميل استخدام الرموز", + "noStats": "لا يوجد استخدام مسجّل", + "timestampsHeading": "الطوابع الزمنية", + "createdAt": "تاريخ الإنشاء", + "updatedAt": "تاريخ التحديث", + "none": "—", + "copyField": "نسخ {field}", + "copiedField": "تم نسخ {field}" + }, + "conversationCard": { + "untitledConversation": "محادثة بدون عنوان", + "newConversation": "محادثة جديدة", + "rename": "إعادة تسمية", + "status": "الحالة", + "delete": "حذف", + "importLocalSessions": "استيراد الجلسات المحلية", + "importing": "جارٍ الاستيراد...", + "renameConversation": "إعادة تسمية المحادثة", + "deleteConversationTitle": "حذف المحادثة؟", + "deleteConversationDescription": "سيؤدي ذلك إلى حذف \"{title}\". لا يمكن التراجع عن هذا الإجراء.", + "cancel": "إلغاء", + "save": "حفظ", + "pin": "تثبيت", + "unpin": "إلغاء التثبيت", + "markCompleted": "وضع علامة كمكتمل", + "reopen": "إعادة فتح", + "expandSubsessions": "توسيع المحادثات الفرعية", + "collapseSubsessions": "طي المحادثات الفرعية" + }, + "search": { + "dialogTitle": "بحث", + "dialogTitleWithFolder": "بحث — {name}", + "tabConversations": "المحادثات", + "tabFiles": "الملفات", + "placeholder": "البحث في المحادثات...", + "filePlaceholder": "البحث في الملفات أو المجلدات...", + "allAgents": "الكل", + "searching": "جارٍ البحث...", + "typeToSearch": "اكتب للبحث في المحادثات", + "typeToSearchFiles": "اكتب للبحث في الملفات أو المجلدات", + "noResults": "لم يتم العثور على نتائج.", + "untitledConversation": "محادثة بدون عنوان" + }, + "folderTitleBar": { + "showSidebar": "إظهار الشريط الجانبي", + "hideSidebar": "إخفاء الشريط الجانبي", + "toggleTerminal": "تبديل الطرفية", + "toggleAuxPanel": "تبديل اللوحة المساعدة", + "search": "بحث", + "openSettings": "فتح الإعدادات", + "backToConversations": "العودة إلى المحادثات", + "withShortcut": "{label} (اختصار: {shortcut})" + }, + "statusBar": { + "connection": { + "connected": "متصل", + "connecting": "جارٍ الاتصال...", + "prompting": "جارٍ الرد...", + "error": "خطأ في الاتصال", + "disconnected": "غير متصل", + "tooltip": "{agent}: {status}", + "tooltipError": "{agent}: {error}", + "title": "اتصال الوكيل", + "triggerAria": "اتصال الوكيل: {status}", + "workingDir": "مجلد العمل", + "sessionId": "معرّف الجلسة", + "viewerNote": "متصل بجلسة يملكها عميل آخر — إعادة الاتصال تعيد ربط هذا العرض فقط.", + "reconnectInterrupts": "إعادة الاتصال تعيد تشغيل الوكيل وتقاطع العمل الجاري.", + "reconnect": "إعادة الاتصال", + "reconnecting": "جارٍ إعادة الاتصال...", + "reconnectUnavailable": "لا توجد جلسة لإعادة الاتصال بها بعد." + }, + "tasks": { + "title": "المهام" + }, + "alerts": { + "title": "التنبيهات", + "empty": "لا توجد تنبيهات", + "details": "التفاصيل" + }, + "stats": { + "conversations": "{count} محادثة", + "openUsage": "عرض إحصاءات الجلسات واستخدام الرموز" + }, + "tokens": { + "contextWindowUsageAria": "استخدام نافذة السياق", + "contextWindow": "نافذة السياق", + "usedMax": "المستخدم / الحد الأقصى", + "tokenUsage": "استخدام الرموز", + "input": "إدخال", + "output": "إخراج", + "cacheRead": "قراءة الكاش", + "cacheWrite": "كتابة الكاش", + "total": "الإجمالي" + } + }, + "auxPanel": { + "tabs": { + "files": "الملفات", + "changes": "التغييرات", + "commits": "الالتزامات" + }, + "noFolderTitle": "لا يوجد مجلد مفتوح", + "noFolderHint": "افتح مجلدا لعرض محتواه هنا" + }, + "windowControls": { + "minimizeWindow": "تصغير النافذة", + "minimize": "تصغير", + "maximizeWindow": "تكبير النافذة", + "maximize": "تكبير", + "restoreWindow": "استعادة النافذة", + "restore": "استعادة", + "closeWindow": "إغلاق النافذة", + "close": "إغلاق" + }, + "tabs": { + "closeConversationTab": "إغلاق تبويب المحادثة", + "close": "إغلاق", + "closeOthers": "إغلاق البقية", + "splitRight": "تقسيم لليمين", + "splitDown": "تقسيم للأسفل", + "splitAndMoveRight": "تقسيم ونقل لليمين", + "splitAndMoveDown": "تقسيم ونقل للأسفل", + "moveToOppositeGroup": "نقل إلى المجموعة المقابلة", + "moveToGroup": "نقل إلى مجموعة", + "groupLabel": "المجموعة {index}", + "changeSplitterOrientation": "تبديل اتجاه الفاصل", + "unsplit": "إلغاء التقسيم", + "unsplitAll": "إلغاء كل التقسيمات", + "closeAll": "إغلاق الكل", + "tileDisplay": "عرض متجانب", + "untileDisplay": "إلغاء التجانب" + }, + "fileWorkspace": { + "files": "الملفات", + "closeFileTab": "إغلاق تبويب الملف", + "close": "إغلاق", + "closeOthers": "إغلاق البقية", + "closeAll": "إغلاق الكل", + "preview": "معاينة", + "editSource": "تحرير المصدر", + "maximize": "تكبير", + "restore": "استعادة", + "emptyDirectory": "مجلد فارغ" + }, + "terminal": { + "rename": "إعادة تسمية", + "close": "إغلاق", + "closeOthers": "إغلاق البقية", + "closeAll": "إغلاق الكل", + "hideTerminal": "إخفاء الطرفية ({shortcut})", + "openFolderFirst": "افتح مجلدا أولا" + }, + "workspaceDialog": { + "title": "فتح مجلد", + "manageTitle": "المجلدات المرتبطة", + "addTargetsTitle": "إضافة مجلدات للربط", + "pickRootDescription": "اختر المجلد الرئيسي لمساحة العمل هذه.", + "linksDescription": "اربط مجلدات أخرى كمجلدات فرعية ليتمكن الوكلاء من العمل عليها جميعًا من مساحة عمل واحدة.", + "addTargetsDescription": "اختر مجلدًا واحدًا أو أكثر. سيصبح كل منها مجلدًا فرعيًا في مساحة العمل.", + "useSystemPicker": "منتقي النظام", + "next": "التالي", + "back": "رجوع", + "done": "تم", + "change": "تغيير", + "addFolders": "إضافة مجلدات", + "addSelected": "إضافة", + "addSelectedCount": "إضافة {count}", + "createCount": "ربط {count} مجلد", + "discardPending": "تجاهل", + "noLinks": "لا توجد مجلدات مرتبطة بعد.", + "gitExclude": "إبقاء الروابط خارج حالة git", + "rename": "إعادة تسمية", + "unlink": "إزالة الرابط", + "repair": "إعادة إنشاء الرابط", + "saveName": "حفظ", + "cancelRename": "إلغاء", + "removePending": "إزالة", + "willAppearAs": "يظهر باسم {name} في مساحة العمل", + "renamedForDuplicate": "تمت إعادة التسمية — {base} مستخدم من رابط آخر", + "renamedForExistingEntry": "تمت إعادة التسمية — {base} موجود بالفعل في هذا المجلد", + "partiallyCreated": "تم ربط {count} مجلد فقط", + "openFailed": "تعذر فتح المجلد", + "previewFailed": "تعذر فحص المجلدات المحددة", + "createFailed": "تعذر ربط المجلدات", + "renameFailed": "تعذرت إعادة تسمية الرابط", + "removeFailed": "تعذرت إزالة الرابط", + "repairFailed": "تعذرت إعادة إنشاء الرابط", + "status": { + "ok": "مرتبط", + "missing": "اختفى الرابط من هذا المجلد", + "conflicted": "يستخدم عنصر آخر هذا الاسم الآن", + "broken": "لم يعد المجلد المرتبط موجودًا" + }, + "nameIssue": { + "empty": "أدخل اسمًا", + "illegalChars": "لا يمكن أن يحتوي على / \\ : * ? \" < > |", + "tooLong": "الاسم طويل جدًا", + "reserved": "هذا الاسم محجوز في ويندوز", + "duplicate": "هذا الاسم مستخدم بالفعل" + }, + "rejection": { + "not_found": "تعذر العثور على هذا المجلد", + "not_a_directory": "هذا المسار ليس مجلدًا", + "same_as_root": "هذا هو مجلد مساحة العمل نفسه", + "ancestor_of_root": "هذا المجلد يحتوي على مساحة العمل", + "inside_root": "موجود بالفعل داخل مساحة العمل", + "already_linked": "مرتبط بالفعل", + "name_unavailable": "لم يتبق اسم متاح لهذا المجلد", + "alreadyLinkedAs": "مرتبط بالفعل باسم {name}" + } + }, + "folderNameDropdown": { + "fallbackFolderName": "مجلد", + "openFolder": "فتح مجلد", + "cloneRepository": "استنساخ المستودع", + "projectBoot": "مُنشئ المشروع", + "opened": "مفتوح", + "recentOpen": "المفتوح مؤخرًا" + }, + "fileWorkspacePanel": { + "addSelectionToChat": "إضافة التحديد إلى المحادثة", + "addToChat": "إضافة إلى المحادثة", + "addSelectionToChatDone": "تمت إضافة {label} إلى المحادثة", + "addFileToChat": "إضافة الملف إلى المحادثة", + "toggleWordWrap": "تبديل التفاف النص", + "addFileToChatDone": "تمت إضافة {label} إلى المحادثة", + "viewDiff": "عرض Diff", + "openFile": "فتح الملف", + "fileCount": "{count, plural, one {# ملف} other {# ملفات}}", + "openFileOrDiff": "افتح ملفًا أو diff من اللوحة اليمنى", + "disk": "القرص", + "head": "HEAD", + "unsaved": "غير محفوظ", + "workingTree": "شجرة العمل", + "loading": "جارٍ التحميل...", + "compareWithBranch": "{path} · مقارنة مع {branch}", + "hunkCount": "{count, plural, one {# مقطع} other {# مقاطع}}", + "prev": "السابق", + "next": "التالي", + "jumpToLine": "الانتقال إلى السطر {line}", + "noParsedDiffSections": "لا توجد أقسام diff محللة", + "loadingEditor": "جارٍ تحميل المحرر...", + "imageZoomIn": "تكبير", + "imageZoomOut": "تصغير", + "imageZoomReset": "إعادة تعيين التكبير", + "htmlPreviewTitle": "معاينة HTML", + "htmlPreviewTrust": "تفعيل البرامج النصية", + "htmlPreviewTrustHint": "تشغيل البرامج النصية لهذا الملف والسماح بالوصول إلى الشبكة. فعّلها فقط للملفات الموثوقة.", + "officePreviewTitle": "معاينة مستند Office", + "officeFullRender": "عرض كامل", + "officeFullRenderHint": "يعرض حركات Morph والأبعاد الثلاثية والمعادلات (يشغّل سكربتات الشريحة نفسها)", + "officeNotInstalled": "OfficeCLI غير مثبّت", + "officeNotInstalledHint": "ثبّت OfficeCLI من الإعدادات → أدوات Office لمعاينة ملفات Word و Excel و PowerPoint.", + "officeOpenSettings": "فتح الإعدادات", + "officeWatchFailed": "تعذّر بدء المعاينة المباشرة", + "officeWatchRetry": "إعادة المحاولة", + "officeServerInstallHint": "يجب تثبيت OfficeCLI على مضيف الخادم. شغّل هذا الأمر هناك ثم أعد المحاولة:", + "officeRemoteDesktopUnsupported": "المعاينة المباشرة غير متاحة في نافذة سطح المكتب البعيد. افتح مساحة العمل هذه في واجهة الويب الخاصة بالخادم لمعاينة ملفات Office." + }, + "branchDropdown": { + "toasts": { + "commitCodeCompleted": "اكتمل التزام الكود", + "pushCodeCompleted": "اكتمل دفع الكود", + "committedFiles": "{count, plural, one {# ملف تم الالتزام به} other {# ملفات تم الالتزام بها}}", + "taskCompleted": "اكتمل {label}", + "taskFailed": "فشل {label}", + "mergeNoNewCommits": "{branchName} لا يحتوي على التزامات جديدة", + "mergedCommits": "{count, plural, one {# التزام تم دمجه} other {# التزامات تم دمجها}}", + "allFilesUpToDate": "كل الملفات محدثة", + "updatedFiles": "{count, plural, one {# ملف تم تحديثه} other {# ملفات تم تحديثها}}", + "openCommitWindowFailed": "فشل فتح نافذة الالتزام", + "openPushWindowFailed": "فشل فتح نافذة الدفع", + "upstreamSet": "تم تعيين فرع upstream", + "upstreamSetAndPushed": "تم تعيين فرع upstream ودفع {count, plural, one {# التزام} other {# التزامات}}", + "noCommitsToPush": "لا توجد التزامات للدفع", + "pushedCommits": "تم دفع {count, plural, one {# التزام} other {# التزامات}}", + "switchedToFolder": "تم التبديل إلى {name}", + "switchFailed": "فشل تبديل الفرع", + "openStashWindowFailed": "فشل فتح نافذة الـ stash" + }, + "tasks": { + "newBranch": "إنشاء الفرع {name}", + "newWorktree": "إنشاء worktree {name}", + "checkoutTo": "Checkout إلى {branchName}", + "mergeBranch": "دمج {branchName}", + "rebaseTo": "Rebase إلى {branchName}", + "deleteRemoteBranch": "حذف الفرع البعيد {branchName}", + "initGitRepo": "تهيئة مستودع Git", + "pullCode": "سحب الكود", + "fetchInfo": "جلب المعلومات", + "pushCode": "دفع الكود", + "stashChanges": "تخزين التغييرات في stash", + "stashPop": "استرجاع stash", + "deleteBranch": "حذف الفرع {branchName}", + "removeWorktree": "حذف worktree الخاص بـ {branchName}", + "removeWorktreeAndBranch": "حذف worktree والفرع {branchName}", + "updateBranch": "تحديث الفرع {branchName}" + }, + "confirm": { + "mergeTitle": "دمج الفرع", + "rebaseTitle": "Rebase للفرع", + "mergeDescription": "دمج {branchName} في الفرع الحالي {currentBranch}؟", + "rebaseDescription": "إجراء rebase للفرع الحالي {currentBranch} على {branchName}؟", + "deleteRemoteTitle": "حذف الفرع البعيد", + "deleteRemoteDescription": "هل تريد حذف الفرع البعيد {branchName}؟ سيؤدي ذلك إلى إزالته من المستودع البعيد ولا يمكن التراجع عن هذا الإجراء.", + "deleteTitle": "حذف الفرع", + "deleteDescription": "حذف الفرع {branchName}؟ لا يمكن التراجع عن هذا الإجراء.", + "forceDeleteTitle": "حذف الفرع بالقوة", + "forceDeleteDescription": "الفرع {branchName} لم يتم دمجه بالكامل. هل أنت متأكد من أنك تريد حذفه بالقوة؟ لا يمكن التراجع عن هذا الإجراء.", + "deleteWorktreeTitle": "حذف worktree", + "deleteWorktreeDescription": "حذف مجلد worktree الذي تم سحب {branchName} فيه؟ سيتم الاحتفاظ بالفرع وإيداعاته.", + "forceDeleteWorktreeTitle": "فرض حذف worktree", + "forceDeleteWorktreeDescription": "يحتوي worktree الخاص بـ {branchName} على ملفات غير مودعة أو غير متتبعة. هل تريد حذفه على أي حال؟ لا يمكن استرجاع تلك التغييرات.", + "deleteWorktreeAndBranchTitle": "حذف worktree والفرع", + "deleteWorktreeAndBranchDescription": "حذف worktree الخاص بـ {branchName} والفرع نفسه ومجلده في مساحة العمل؟ ستنتقل جلساته إلى مجلد المستودع. لا يمكن التراجع عن هذا الإجراء.", + "forceDeleteWorktreeAndBranchTitle": "فرض حذف worktree والفرع", + "forceDeleteWorktreeAndBranchDescription": "يحتوي worktree الخاص بـ {branchName} على ملفات غير مودعة، أو أن الفرع غير مدمج بالكامل. هل تريد حذفهما على أي حال؟ لا يمكن التراجع عن هذا الإجراء." + }, + "current": "الحالي", + "switchToBranch": "التبديل إلى هذا الفرع", + "mergeBranchIntoCurrent": "دمج {branchName} في {currentBranch}", + "rebaseCurrentToBranch": "Rebase لـ {currentBranch} على {branchName}", + "noBranch": "بدون فرع", + "detachedHead": "HEAD منفصل عند {sha}", + "initGitRepo": "تهيئة مستودع Git", + "pullCode": "سحب الكود", + "fetchRemoteBranches": "جلب الفروع البعيدة", + "openCommitWindow": "التزام الكود...", + "pushCode": "دفع...", + "pushBranch": "دفع", + "newBranch": "فرع جديد...", + "newWorktree": "Worktree جديد...", + "stashChanges": "...تخبئة التغييرات", + "stashPop": "استرجاع stash...", + "manageRemotes": "إدارة المستودعات البعيدة...", + "localBranches": "الفروع المحلية ({count, plural, one {#} other {#}})", + "noLocalBranches": "لا توجد فروع محلية", + "remoteBranches": "الفروع البعيدة ({count, plural, one {#} other {#}})", + "noRemoteBranches": "لا توجد فروع بعيدة", + "dialogs": { + "newBranchTitle": "فرع جديد", + "newBranchDescription": "إنشاء فرع جديد من الفرع الحالي {branch}", + "branchNamePlaceholder": "اسم الفرع", + "newWorktreeTitle": "Worktree جديد", + "newWorktreeDescription": "إنشاء worktree جديد من الفرع الحالي {branch}", + "branchNameLabel": "اسم الفرع", + "worktreePathLabel": "مسار worktree", + "worktreePathPlaceholder": "مسار worktree", + "manageRemotesTitle": "إدارة المستودعات البعيدة", + "manageRemotesEmpty": "لم يتم تكوين أي مستودعات بعيدة", + "remoteNamePlaceholder": "اسم المستودع البعيد", + "remoteUrlPlaceholder": "عنوان URL للمستودع البعيد", + "addRemote": "إضافة", + "savingRemotes": "جارٍ الحفظ..." + }, + "conflict": { + "title": "تعارضات الدمج", + "description": "الملفات التالية بها تعارضات تحتاج إلى حل:", + "abort": "إلغاء الدمج", + "openMergeTool": "فتح أداة الدمج", + "completeMerge": "إتمام الدمج", + "abortSuccess": "تم إلغاء الدمج بنجاح", + "completeSuccess": "تم إتمام الدمج بنجاح" + }, + "stashDialog": { + "title": "تخبئة التغييرات", + "description": "حفظ التغييرات الحالية في المخبأ", + "messageLabel": "رسالة", + "messagePlaceholder": "رسالة التخبئة (اختياري)", + "keepIndex": "الاحتفاظ بالفهرس (التغييرات المرحلة تبقى مرحلة)", + "cancel": "إلغاء", + "stash": "تخبئة", + "success": "تم تخبئة التغييرات", + "error": "فشل في تخبئة التغييرات" + }, + "unstashDialog": { + "title": "تطبيق المخبأ", + "noStashes": "لا توجد تخبئات", + "selectFile": "اختر ملفاً لعرض الفرق", + "viewDiff": "عرض الفرق", + "original": "الأصلي", + "modified": "المعدل", + "apply": "تطبيق", + "drop": "حذف", + "applySuccess": "تم تطبيق التخبئة", + "dropSuccess": "تم حذف التخبئة", + "confirmApply": "تطبيق التخبئة {ref} على دليل العمل؟", + "cancel": "إلغاء" + }, + "deleteBranch": "حذف الفرع", + "deleteWorktree": "حذف worktree", + "deleteWorktreeAndBranch": "حذف worktree والفرع", + "searchPlaceholder": "البحث في الفروع والإجراءات", + "searchAriaLabel": "البحث في الفروع والإجراءات", + "branchListLabel": "الفروع والإجراءات", + "noMatches": "لا توجد نتائج" + }, + "commitDialog": { + "toasts": { + "commitCompleted": "اكتمل التزام الكود", + "pushFailed": "فشل الدفع", + "committedFiles": "{count, plural, one {# ملف تم الالتزام به} other {# ملفات تم الالتزام بها}}", + "addedToVcs": "تمت الإضافة إلى VCS", + "addToVcsFailed": "فشلت الإضافة إلى VCS", + "fileDeleted": "تم حذف الملف", + "deleteFailed": "فشل الحذف", + "fileRolledBack": "تم التراجع عن الملف", + "rollbackFailed": "فشل التراجع", + "dirRolledBack": "تم استعادة المجلد", + "dirDeleted": "تم حذف المجلد" + }, + "confirm": { + "deleteTitle": "تأكيد الحذف", + "deleteDescription": "حذف الملف \"{file}\"؟ لا يمكن التراجع عن هذا الإجراء.", + "rollbackTitle": "تأكيد التراجع", + "rollbackDescription": "التراجع عن الملف \"{file}\" إلى HEAD؟ ستفقد التغييرات غير المحفوظة.", + "rollbackDirDescription": "هل تريد استعادة المجلد \"{dir}\" إلى HEAD؟ ستفقد التغييرات غير المحفوظة.", + "deleteDirDescription": "هل تريد حذف المجلد \"{dir}\"؟ لا يمكن التراجع عن هذا الإجراء." + }, + "actions": { + "select": "تحديد", + "unselect": "إلغاء التحديد", + "rollback": "تراجع", + "addToVcs": "إضافة إلى VCS" + }, + "aria": { + "selectFile": "{action}: {path}", + "unselectAllFiles": "إلغاء تحديد كل الملفات", + "selectAllFiles": "تحديد كل الملفات", + "unselectTracked": "إلغاء تحديد التغييرات المتعقبة", + "selectTracked": "تحديد التغييرات المتعقبة", + "unselectUntracked": "إلغاء تحديد الملفات غير المتعقبة", + "selectUntracked": "تحديد الملفات غير المتعقبة" + }, + "loading": "جارٍ التحميل...", + "selectionCount": "{selected} / {total} ملفات", + "emptyFiles": "لا توجد ملفات متغيرة", + "trackedChanges": "التغييرات المتعقبة ({count})", + "untrackedFiles": "الملفات غير المتعقبة ({count})", + "commitMessage": "رسالة الالتزام", + "commitMessagePlaceholder": "أدخل رسالة الالتزام...", + "commitButton": "التزام ({count})", + "commitAndPushButton": "إيداع ودفع ({count})", + "head": "HEAD", + "workingTree": "شجرة العمل", + "clickFileToDiff": "انقر اسم الملف لعرض الفرق", + "loadingDiff": "جارٍ تحميل diff..." + }, + "pushWindow": { + "title": "دفع الكود", + "noUnpushedCommits": "لا توجد التزامات غير مدفوعة", + "noRemoteConfigured": "لم يتم تكوين مستودع Git بعيد\nأضف واحدًا في «إدارة المستودعات البعيدة»", + "newBranchNoPushedCommits": "فرع جديد — ادفع لإنشاء فرع تتبع عن بُعد", + "unpushed": "غير مدفوع", + "selectFileToViewDiff": "اختر ملفًا لعرض الفرق", + "before": "قبل", + "after": "بعد", + "push": "دفع", + "toasts": { + "pushSuccess": "تم الدفع بنجاح", + "pushFailed": "فشل الدفع", + "upstreamSet": "تم تعيين الفرع البعيد", + "upstreamSetAndPushed": "تم تعيين الفرع البعيد ودفع {count} التزام", + "noCommitsToPush": "لا توجد التزامات للدفع", + "pushedCommits": "تم دفع {count} التزام" + } + }, + "gitLogTab": { + "filesTitle": "الملفات", + "expandAllFiles": "توسيع كل الملفات", + "collapseAllFiles": "طي كل الملفات", + "workspace": "مساحة العمل", + "retry": "إعادة المحاولة", + "noCommitsFound": "لم يتم العثور على التزامات", + "notAGitRepoTitle": "ليس مستودع Git", + "notAGitRepoHint": "قم بتهيئة Git من قائمة الفروع أعلاه، أو افتح مستودعًا موجودًا.", + "hash": "بصمة الالتزام", + "copyHash": "نسخ الـ hash", + "copyMessage": "نسخ الرسالة", + "showMore": "عرض المزيد", + "showLess": "طي", + "author": "المؤلف", + "noFileChangeDetails": "لا توجد تفاصيل تغييرات ملفات متاحة.", + "loadingFiles": "جارٍ تحميل الملفات...", + "branchesTitle": "الفروع", + "loadingBranches": "جارٍ تحميل الفروع...", + "noContainingBranches": "لم يتم العثور على فروع تحتوي هذا الالتزام.", + "newBranch": "فرع جديد...", + "resetToHere": "إعادة الضبط إلى هنا", + "resetDisabledReasonNotCurrentBranchView": "متاح فقط عند عرض الفرع الحالي", + "copyFullCommitHashAria": "نسخ hash الكامل للالتزام {hash}", + "pushStatus": { + "pushed": "تم الدفع إلى البعيد", + "notPushed": "لم يتم الدفع إلى البعيد", + "unknown": "حالة الدفع غير معروفة (لم يتم إعداد upstream)" + }, + "time": { + "monthsAgo": "{count, plural, one {منذ # شهر} other {منذ # أشهر}}", + "daysAgo": "{count, plural, one {منذ # يوم} other {منذ # أيام}}", + "hoursAgo": "{count, plural, one {منذ # ساعة} other {منذ # ساعات}}", + "minsAgo": "{count, plural, one {منذ # دقيقة} other {منذ # دقائق}}", + "justNow": "الآن" + }, + "toasts": { + "createdAndSwitchedNewBranch": "تم إنشاء فرع جديد والتبديل إليه", + "newBranchFromCommit": "{name} (من {shortHash})", + "createBranchFailed": "فشل إنشاء الفرع", + "openPushWindowFailed": "فشل فتح نافذة الدفع", + "resetSuccess": "تمت إعادة الضبط بنجاح", + "resetSuccessDescription": "تمت إعادة ضبط {branch} إلى {shortHash} باستخدام {mode}", + "resetFailed": "فشلت إعادة الضبط" + }, + "authorFilter": { + "label": "المؤلف", + "searchPlaceholder": "بحث عن مؤلف", + "noAuthors": "لم يتم العثور على مؤلفين", + "you": "أنت", + "filterByAuthorAria": "تصفية الإيداعات حسب المؤلف", + "filterByQuery": "تصفية حسب \"{query}\"", + "clearAuthorFilterAria": "مسح تصفية المؤلف", + "recent": "الأخيرة", + "matchingAuthors": "المؤلفون المطابقون", + "removeFromRecent": "إزالة {name} من الأخيرة" + }, + "branchSelector": { + "label": "الفرع", + "head": "HEAD", + "headHint": "يتبع الفرع الحالي", + "headHintWithBranch": "يتبع الفرع الحالي ({branch})", + "searchBranch": "بحث عن فرع...", + "noBranches": "لا توجد فروع", + "selectBranchPlaceholder": "اختر فرعًا...", + "localBranches": "الفروع المحلية", + "current": "الحالي", + "remoteBranches": "الفروع البعيدة", + "refreshCommitHistory": "تحديث سجل الالتزامات", + "clearBranchFilterAria": "مسح تصفية الفرع" + }, + "dialogs": { + "newBranchTitle": "فرع جديد", + "newBranchDescription": "إنشاء فرع جديد مع الالتزام {shortHash} كأحدث التزام.", + "branchNamePlaceholder": "اسم الفرع", + "reset": { + "title": "إعادة ضبط الفرع الحالي إلى هذا الالتزام", + "branchLabel": "الفرع", + "targetLabel": "الالتزام الهدف", + "messageLabel": "الرسالة", + "modeLabel": "وضع إعادة الضبط", + "confirmButton": "إعادة الضبط", + "modes": { + "soft": { + "label": "--soft", + "description": "ينقل HEAD ومؤشر الفرع الحالي إلى الالتزام الهدف.\nيبقي Index و Working Tree بدون تغيير.\nتظل تغييرات الالتزامات التي تمت إزالتها في حالة staged." + }, + "mixed": { + "label": "--mixed (الافتراضي)", + "description": "ينقل HEAD إلى الالتزام الهدف.\nيعيد ضبط Index إلى الالتزام الهدف مع الإبقاء على تغييرات Working Tree.\nتتحول التغييرات من staged إلى unstaged." + }, + "hard": { + "label": "--hard", + "description": "ينقل HEAD ويعيد ضبط كل من Index و Working Tree إلى الالتزام الهدف.\nسيتم حذف التغييرات المحلية المتتبعة بعد الالتزام الهدف.\nهذه عملية تدميرية." + }, + "keep": { + "label": "--keep", + "description": "ينقل HEAD إلى الالتزام الهدف مع محاولة الاحتفاظ بالتغييرات المحلية.\nيتم الاحتفاظ فقط بالتغييرات غير المتعارضة.\nعند وجود تعارض، يتم إيقاف العملية لحماية عملك." + } + } + } + }, + "moreActions": "إجراءات Git إضافية" + }, + "gitChangesTab": { + "workspace": "مساحة العمل", + "noChanges": "لا توجد تغييرات محلية", + "notAGitRepoTitle": "ليس مستودع Git", + "notAGitRepoHint": "قم بتهيئة Git من قائمة الفروع أعلاه، أو افتح مستودعًا موجودًا.", + "trackedChanges": "التغييرات المتعقبة ({count})", + "untrackedFiles": "الملفات غير المتعقبة ({count})", + "expandTracked": "توسيع التغييرات المتعقبة", + "collapseTracked": "طي التغييرات المتعقبة", + "expandUntracked": "توسيع الملفات غير المتعقبة", + "collapseUntracked": "طي الملفات غير المتعقبة", + "showRemainingItems": "عرض {count} عنصر إضافي", + "actions": { + "commitCode": "التزام الكود", + "rollback": "تراجع", + "addToVcs": "إضافة إلى VCS", + "delete": "حذف", + "moreActions": "إجراءات Git إضافية", + "addAllToVcs": "إضافة الكل إلى VCS", + "rollbackAll": "تراجع عن الكل", + "refresh": "تحديث" + }, + "toasts": { + "noAddableFilesInDir": "لا توجد ملفات متغيرة في هذا الدليل يمكن إضافتها إلى VCS", + "noRollbackFilesInDir": "لا توجد ملفات متغيرة في هذا الدليل يمكن التراجع عنها", + "addedToVcs": "تمت إضافة {name} إلى VCS", + "addToVcsFailed": "فشلت الإضافة إلى VCS", + "openCommitWindowFailed": "فشل فتح نافذة الالتزام", + "rolledBack": "تم التراجع عن {name}", + "rollbackFailed": "فشل التراجع", + "addedFilesToVcs": "تمت إضافة {count, plural, one {# ملف} other {# ملفات}} إلى VCS", + "rolledBackFiles": "تم التراجع عن {count, plural, one {# ملف} other {# ملفات}}", + "deleted": "تم حذف {name}", + "deleteFailed": "فشل الحذف", + "deletedFiles": "تم حذف {count} ملفات", + "noDeletableFilesInDir": "لا توجد ملفات معدّلة في هذا الدليل يمكن حذفها", + "commitFailed": "فشل الالتزام" + }, + "directoryDialog": { + "descriptionAdd": "اختر ملفات داخل الدليل {path} لإضافتها إلى VCS.", + "descriptionRollback": "اختر ملفات داخل الدليل {path} للتراجع عنها.", + "descriptionDelete": "اختر ملفات داخل الدليل {path} لحذفها. لا يمكن التراجع عن هذا الإجراء.", + "descriptionFallback": "اختر ملفات للمتابعة.", + "selectionCount": "تم تحديد {selected} / {total} ملف", + "selectAll": "تحديد الكل", + "unselectAll": "إلغاء تحديد الكل", + "loadingCandidates": "جارٍ تحميل تغييرات الدليل...", + "noOperableFiles": "لا توجد ملفات قابلة للتشغيل" + }, + "rollbackConfirm": { + "title": "تأكيد التراجع", + "descriptionWithTarget": "التراجع عن التغييرات المحلية لـ {kind} \"{name}\"؟", + "descriptionFallback": "التراجع عن التغييرات المحلية؟", + "kindDirectory": "الدليل", + "kindFile": "الملف" + }, + "deleteConfirm": { + "title": "تأكيد الحذف", + "descriptionWithTarget": "حذف {kind} \"{name}\"؟ لا يمكن التراجع عن هذا الإجراء.", + "descriptionFallback": "لا يمكن التراجع عن هذا الإجراء.", + "kindDirectory": "الدليل", + "kindFile": "الملف" + }, + "quickCommit": { + "placeholder": "رسالة الالتزام (اضغط Enter للالتزام)" + } + }, + "tabContext": { + "loadingConversation": "جارٍ التحميل...", + "untitledConversation": "محادثة بدون عنوان", + "newConversation": "محادثة جديدة" + }, + "fileTreeTab": { + "workspace": "مساحة العمل", + "retry": "إعادة المحاولة", + "git": "Git", + "openInFileManager": "فتح في مدير الملفات", + "openInFinder": "فتح في Finder", + "openInExplorer": "فتح في Explorer", + "attachToCurrentSession": "إضافة إلى الجلسة", + "compareWithBranch": "المقارنة مع الفرع...", + "reloadFromDisk": "إعادة التحميل من القرص", + "new": "جديد", + "newFile": "ملف", + "newDirectory": "مجلد", + "openIn": "فتح في", + "openInTerminal": "فتح في الطرفية", + "linkedFolder": "مجلد مرتبط", + "copyPath": "نسخ المسار", + "upload": "رفع ملفات/مجلد", + "download": "تنزيل ملف", + "downloadAsZip": "تنزيل كملف ZIP", + "actions": { + "select": "تحديد", + "unselect": "إلغاء التحديد", + "commitCode": "تنفيذ الالتزام بالكود", + "rollback": "التراجع", + "addToVcs": "إضافة إلى VCS" + }, + "aria": { + "selectPath": "{action}: {path}" + }, + "toasts": { + "openDirectoryFailed": "فشل فتح المجلد", + "openBuiltinTerminalFailed": "تعذر فتح الطرفية المدمجة", + "openCommitWindowFailed": "فشل فتح نافذة الالتزام", + "noAddableFilesInDir": "لا توجد ملفات متغيرة في هذا المجلد يمكن إضافتها إلى VCS", + "noRollbackFilesInDir": "لا توجد ملفات متغيرة في هذا المجلد يمكن التراجع عنها", + "addedToVcs": "تمت إضافة {name} إلى VCS", + "addToVcsFailed": "فشلت الإضافة إلى VCS", + "loadBranchesFailed": "فشل تحميل الفروع", + "renameFailed": "فشل إعادة التسمية", + "moveFailed": "فشل النقل", + "deleteFailed": "فشل الحذف", + "rolledBack": "تم التراجع عن {name}", + "rollbackFailed": "فشل التراجع", + "addedFilesToVcs": "{count, plural, one {تمت إضافة ملف واحد إلى VCS} other {تمت إضافة # ملفات إلى VCS}}", + "rolledBackFiles": "{count, plural, one {تم التراجع عن ملف واحد} other {تم التراجع عن # ملفات}}", + "savedAsCopy": "تم الحفظ كنسخة", + "saveCopyFailed": "فشل الحفظ كنسخة", + "watchStartFailed": "فشل بدء مراقبة الملفات", + "createFailed": "فشل في الإنشاء", + "downloadFailed": "فشل تنزيل {name}", + "downloadSaved": "تم تنزيل {name}", + "pathCopied": "تم نسخ المسار", + "copyPathFailed": "فشل نسخ المسار" + }, + "createDialog": { + "newFile": "ملف جديد", + "newDirectory": "مجلد جديد", + "description": "أدخل اسمًا لـ{kind} الجديد.", + "placeholderFile": "file-name.ext", + "placeholderDirectory": "folder-name" + }, + "renameDialog": { + "renameDirectory": "إعادة تسمية المجلد", + "renameFile": "إعادة تسمية الملف", + "description": "أدخل اسمًا جديدًا (الاسم فقط، بدون مسار).", + "placeholderDirectory": "اسم-مجلد-جديد", + "placeholderFile": "اسم-ملف-جديد.ext" + }, + "uploadDialog": { + "title": "رفع إلى مساحة العمل", + "description": "اضبط الوجهة عند الحاجة، ثم أضف الملفات أو المجلدات.", + "workspaceRoot": "جذر مساحة العمل", + "targetPathLabel": "رفع إلى", + "targetPathHint": "المسار النهائي: {path}", + "dropHint": "اسحب الملفات أو المجلدات هنا، أو استخدم الأزرار أدناه", + "dropHintActive": "حرّر للإضافة إلى قائمة الانتظار", + "selectFiles": "اختيار ملفات", + "selectFolder": "اختيار مجلد", + "startUpload": "بدء الرفع", + "clearQueue": "مسح المنتهية", + "removeItem": "إزالة من قائمة الانتظار", + "retry": "إعادة المحاولة", + "dropZoneAria": "أفلت الملفات هنا أو نشّط للاستعراض", + "folderEmpty": "لم يتم العثور على ملفات في المجلد المسحوب", + "summary": "الإجمالي: {total} · نجح: {succeeded} · فشل: {failed}", + "status": { + "pending": "قيد الانتظار", + "uploading": "جاري الرفع", + "success": "تم", + "error": "فشل", + "cancelled": "ملغى" + } + }, + "directoryDialog": { + "descriptionAdd": "حدد الملفات ضمن المجلد {path} لإضافتها إلى VCS.", + "descriptionRollback": "حدد الملفات ضمن المجلد {path} للتراجع عنها.", + "descriptionFallback": "حدد الملفات للمتابعة.", + "selectionCount": "تم تحديد {selected} من {total} ملف", + "selectAll": "تحديد الكل", + "unselectAll": "إلغاء تحديد الكل", + "loadingCandidates": "جارٍ تحميل تغييرات المجلد...", + "noOperableFiles": "لا توجد ملفات قابلة للمعالجة" + }, + "compareDialog": { + "title": "المقارنة مع الفرع", + "descriptionWithTarget": "حدد فرعًا وقارن مع {kind} {path}", + "descriptionFallback": "حدد فرعًا للمقارنة.", + "kindDirectory": "مجلد", + "kindFile": "ملف", + "filterPlaceholder": "تصفية الفروع، مثال: main / origin/main", + "singleClickHint": "انقر على فرع للمقارنة مباشرة", + "loadingBranches": "جارٍ تحميل الفروع...", + "recentBranches": "الفروع الحديثة ({count})", + "noCurrentBranch": "لا يوجد فرع حالي", + "localBranches": "الفروع المحلية ({count})", + "remoteBranches": "الفروع البعيدة ({count})", + "noMatchingBranches": "لا توجد فروع مطابقة" + }, + "externalConflictDialog": { + "title": "تم اكتشاف تغييرات خارجية في الملفات", + "descriptionWithPath": "تم تغيير الملف {path} على القرص، والتعديلات الحالية غير محفوظة.", + "descriptionFallback": "تم تغيير الملف الحالي على القرص، والتعديلات الحالية غير محفوظة.", + "compare": "مقارنة", + "savingCopy": "جارٍ حفظ نسخة...", + "saveAsCopy": "حفظ كنسخة", + "reload": "إعادة التحميل" + }, + "deleteConfirm": { + "title": "تأكيد الحذف", + "descriptionWithTarget": "حذف {kind} \"{name}\"؟ لا يمكن التراجع عن هذا الإجراء.", + "descriptionFallback": "لا يمكن التراجع عن هذا الإجراء.", + "kindDirectory": "مجلد", + "kindFile": "ملف" + }, + "rollbackConfirm": { + "title": "تأكيد التراجع", + "descriptionWithTarget": "التراجع عن التغييرات المحلية للملف \"{name}\"؟", + "descriptionFallback": "التراجع عن التغييرات المحلية لهذا الملف؟" + }, + "terminalTitle": "الطرفية · {name}" + }, + "commandDropdown": { + "loading": "جارٍ التحميل...", + "addCommand": "إضافة أمر", + "manageCommands": "إدارة الأوامر...", + "runCommandTitle": "تشغيل: {command}", + "stopCommandTitle": "إيقاف: {command}", + "manageDialog": { + "title": "إدارة الأوامر", + "empty": "لا توجد أوامر بعد", + "noResults": "لا توجد أوامر مطابقة", + "searchPlaceholder": "البحث في الأوامر", + "newCommand": "أمر جديد", + "nameLabel": "الاسم", + "commandLabel": "الأمر", + "dragSort": "اسحب للترتيب", + "dragSortCommand": "اسحب لترتيب {name}", + "orderFailed": "فشل حفظ ترتيب الأوامر", + "loadFailed": "فشل تحميل الأوامر", + "saveFailed": "فشل حفظ الأمر", + "deleteFailed": "فشل حذف الأمر", + "confirmDelete": { + "title": "حذف الأمر؟", + "message": "سيؤدي هذا إلى إزالة \"{name}\". لا يمكن التراجع عن هذا الإجراء." + } + } + }, + "workspaceContext": { + "confirmCloseDirtyTab": "إغلاق \"{title}\" بدون حفظ؟", + "confirmCloseOtherDirtyTabs": "إغلاق التبويبات الأخرى التي تحتوي تغييرات غير محفوظة؟", + "confirmCloseAllDirtyTabs": "إغلاق جميع التبويبات التي تحتوي تغييرات غير محفوظة؟", + "unableLoadContent": "تعذر تحميل المحتوى.\n\n{message}", + "previewRequestTimedOut": "انتهت مهلة طلب المعاينة", + "diffRequestTimedOut": "انتهت مهلة طلب Diff", + "branchCompareRequestTimedOut": "انتهت مهلة طلب مقارنة الفروع", + "commitDiffRequestTimedOut": "انتهت مهلة طلب Diff للالتزام", + "saveRequestTimedOut": "انتهت مهلة طلب الحفظ", + "reloadRequestTimedOut": "انتهت مهلة طلب إعادة التحميل", + "noChanges": "لا توجد تغييرات.", + "noDiffOutput": "لا يوجد مخرجات diff.", + "diffTitleWorkspace": "Diff · مساحة العمل", + "diffDescriptionWorkingTree": "شجرة العمل (HEAD)", + "diffTitleFile": "الفرق · {name}", + "compareTitleFile": "مقارنة · {name}", + "compareTitleBranch": "مقارنة · {branch}", + "compareDescriptionPath": "{path} · مقارنة مع {branch}", + "compareDescriptionBranch": "مقارنة مع {branch}", + "diffTitleCommitFile": "الفرق · {name} @ {hash}", + "diffTitleCommit": "الفرق · {hash}", + "diffDescriptionCommitPath": "{path} · الالتزام {commit}", + "diffDescriptionCommit": "الالتزام {commit}", + "diffTitleConflictFile": "تعارض · {name}", + "diffDescriptionConflict": "{path} · القرص مقابل غير المحفوظ" + }, + "chat": { + "acpConnections": { + "actions": { + "openAgentsSettings": "فتح إعدادات الوكلاء", + "retry": "إعادة المحاولة" + }, + "agentsSetupHint": "افتح الإعدادات > الوكلاء لإدارة التثبيت.", + "withSetupHint": "{message}\n{hint}", + "blocked": { + "missingConfig": "تعذر قراءة إعدادات الوكيل الحالية.", + "disabled": "{agent} معطّل في إعدادات الوكلاء. قم بتمكينه قبل الاتصال.", + "unavailable": "{agent} غير متاح على المنصة الحالية.", + "sdkMissing": "لم يتم تثبيت SDK الخاص بـ {agent}", + "adapterMissing": "محوّل ACP الخاص بـ {agent} غير مثبّت" + }, + "backendErrors": { + "initializeTimeout": "انتهت مهلة مصافحة اتصال {agent} (لا استجابة بعد 60 ثانية). افتح الإعدادات للتحقق من إعدادات الوكيل والشبكة.", + "mcpRejectedByAgent": "رفض {agent} الجلسة أثناء إرفاق رفيق MCP الخاص بـ codeg: {message} إن كان هذا الوكيل لا يدعم MCP، فأوقف «دعم MCP» من الإعدادات ثم أعد الاتصال.", + "processExited": "انتهت عملية {agent} بشكل غير متوقع.", + "spawnFailed": "تعذر بدء تشغيل {agent}: {message}", + "downloadFailed": "فشل تنزيل {agent}: {message}", + "sessionLoadResourceNotFound": "فشل تحميل جلسة {agent}. أعد التحميل لإعادة المحاولة، أو ابدأ محادثة جديدة.", + "sessionLoadUnavailable": "تعذّر على {agent} استعادة هذه الجلسة، فقد تكون انتهت أو توقّف الوكيل. أعد التحميل لإعادة المحاولة، أو ابدأ محادثة جديدة.", + "turnFailedRefusal": "رفض {agent} متابعة هذه الجولة. يدل ذلك غالبًا على خطأ في الخلفية أو البوابة. يرجى مراجعة سجلات الوكيل.", + "turnFailedMaxTokens": "بلغ {agent} الحد الأقصى للرموز المسموح بها في هذه الجولة.", + "turnFailedMaxTurnRequests": "بلغ {agent} الحد الأقصى لعدد الطلبات المسموح بها في هذه الجولة.", + "turnFailedUnknown": "أنهى {agent} الجولة بسبب توقف غير معروف.", + "grokModelSwitchIncompatibleAgent": "لا يمكن لـ {agent} التبديل إلى هذا النموذج في محادثة قائمة. ابدأ جلسة جديدة لاستخدامه.", + "turnFailedEmpty": "أنهى {agent} الجولة دون إنتاج أي رد.", + "turnFailedEmptyProtocol": "أنتج {agent} مخرجات تعذّر على codeg تحليلها — قد لا يتوافق إصدار الوكيل مع البروتوكول.", + "turnFailedEmptyMetadata": "أرسل {agent} تحديثات حالة فقط في هذه الجولة (الخطة / الوضع / الاستخدام) دون أي رد.", + "detailsInAlerts": "افتح التنبيهات في شريط الحالة ووسّع التفاصيل لعرض مخرجات الوكيل." + }, + "unableReadAgentConfig": "تعذر قراءة إعدادات الوكيل: {message}", + "connectFailedTitle": "فشل اتصال {agent}", + "toolFallbackTitle": "أداة", + "eventErrorTitle": "خطأ الوكيل", + "notificationTurnComplete": "{agent} أنهى الاستجابة", + "notificationError": "{agent} خطأ: {message}", + "claudeApiRetry": { + "fallbackError": "authentication_failed", + "retryingWithMax": "إعادة المحاولة {attempt}/{max}", + "retryingAttempt": "إعادة المحاولة رقم {attempt}", + "retrying": "جاري إعادة المحاولة", + "nextRetryIn": "المحاولة التالية خلال {seconds}ث", + "line": "{error}{status} · {retry}", + "lineWithDelay": "{error}{status} · {retry}، {delay}", + "httpStatus": " (HTTP {status})" + }, + "configOptionAdjusted": "ضبط {agent} {option} على {actual} بدلاً من {requested}" + }, + "connectionLifecycle": { + "tasks": { + "connectingTitle": "جارٍ الاتصال بـ {agent}", + "connectingDescription": "جارٍ إنشاء الاتصال", + "loadingSelectorsTitle": "جارٍ تحميل محددات {agent}", + "loadingSelectorsDescription": "جارٍ جلب خيارات الوضع وإعدادات الجلسة", + "initSessionTitle": "جارٍ تهيئة جلسة {agent}", + "initSessionDescription": "جارٍ إنشاء الجلسة وتحميل الإعدادات" + }, + "errors": { + "connectionFailed": "فشل الاتصال", + "sendPromptFailed": "فشل إرسال الرسالة: {error}" + } + }, + "shared": { + "attachedResources": "الموارد المرفقة", + "toolCallFailed": "فشل استدعاء الأداة" + }, + "messageThread": { + "emptyTitle": "لا توجد رسائل بعد", + "emptyDescription": "ابدأ محادثة لرؤية الرسائل هنا" + }, + "chatInput": { + "connecting": "جارٍ الاتصال...", + "agentResponding": "{agent} يرد...", + "sendMessage": "أرسل رسالة..." + }, + "messageInput": { + "askAnything": "اسأل أي شيء...", + "removeAttachmentAria": "إزالة {name}", + "attachFiles": "إرفاق ملفات", + "addActions": "إضافة", + "quickMessages": "الرسائل السريعة", + "quickMessagesEmpty": "لا توجد رسائل سريعة بعد", + "quickMessagesLoading": "جارٍ التحميل...", + "pasteAsPlainText": "لصق كنص عادي", + "cut": "قص", + "copy": "نسخ", + "selectAll": "تحديد الكل", + "pasteUnavailable": "تعذّر قراءة الحافظة. استخدم Ctrl/⌘V للصق.", + "clipboardWriteFailed": "تعذّرت الكتابة إلى الحافظة. استخدم اختصار لوحة المفاتيح.", + "quickMessageUntitled": "بدون عنوان", + "liveFeedback": "ملاحظات مباشرة", + "liveFeedbackDisabledHint": "متاح أثناء عمل الوكيل", + "dropFilesToAttach": "أسقط الملفات لإرفاقها", + "loadingSettings": "جارٍ تحميل الإعدادات...", + "loadingMode": "جارٍ تحميل الوضع...", + "modeLabel": "الوضع", + "toggleOn": "تشغيل", + "toggleOff": "إيقاف", + "agentSettings": "إعدادات الوكيل", + "searchModel": "البحث عن النماذج...", + "searchModelAria": "البحث عن النماذج", + "modelListLabel": "النماذج", + "noModels": "لم يتم العثور على نماذج", + "cancel": "إلغاء", + "send": "إرسال", + "forkAndSend": "تفريع وإرسال", + "queueMessage": "إضافة إلى قائمة الانتظار", + "steerIntoTurn": "إدراج في الدور الحالي", + "steerQueuedInstead": "أُضيفت إلى قائمة الانتظار — ستُرسل مع الدور التالي.", + "steerFailed": "تعذّر الإدراج في الدور الحالي", + "steerAttachmentsUnsupported": "نص فقط — المسودات التي تحتوي على مرفقات تمر عبر قائمة الانتظار.", + "slashCommands": "أوامر الشرطة المائلة", + "slashSearchPlaceholder": "البحث عن الأوامر...", + "slashSearchEmpty": "لا توجد أوامر مطابقة", + "experts": "الخبراء", + "office": "الأعمال المكتبية", + "research": "البحث العلمي", + "attachLocalUpload": "تحميل ملف محلي", + "attachServerFile": "اختيار ملف من الخادم", + "attachUploadTooLarge": "{names} يتجاوز حد التحميل {limit}MB وتم تخطيه.", + "attachUploadFailed": "فشل تحميل {names}.", + "attachUploadNotAFile": "{names} ليس ملفاً عادياً (مجلد أو ملف خاص) وتم تخطيه.", + "attachUploadQuotaExceeded": "نفدت مساحة التحميل على الخادم، تعذر رفع {names}.", + "attachUploadInProgress": "لا تزال الصور قيد الرفع — حاول مرة أخرى بعد قليل.", + "mentionEmpty": "لا توجد نتائج مطابقة", + "mentionLoading": "جارٍ البحث…", + "mentionListLabel": "الإشارات", + "mentionMore": "مزيد من النتائج — تابع الكتابة للتصفية", + "mentionCount": "{count, plural, zero {لا نتائج} one {نتيجة واحدة} two {نتيجتان} few {# نتائج} many {# نتيجة} other {# نتيجة}}", + "mentionGroupFile": "الملفات", + "mentionGroupAgent": "الوكلاء", + "mentionGroupSession": "الجلسات", + "mentionGroupCommit": "عمليات الإيداع", + "mentionGroupSkill": "المهارات" + }, + "messageQueue": { + "addToQueue": "إضافة للقائمة", + "saveEdit": "حفظ", + "cancelEdit": "إلغاء التعديل", + "editItem": "تعديل", + "deleteItem": "حذف" + }, + "welcomeInputPanel": { + "agentsSettingsPath": "الإعدادات > الوكلاء", + "autoConnectFallback": "انقر لفتح {path} وإدارة التثبيت.", + "autoConnectAppend": "{message}. انقر لفتح {path} وإدارة التثبيت.", + "enableAgentFirstPlaceholder": "فعّل وكيلًا واحدًا على الأقل قبل بدء جلسة...", + "prepareSessionFailed": "تعذّر تحضير جلسة الدردشة. يرجى المحاولة مرة أخرى.", + "createConversationFailed": "تعذّر إنشاء المحادثة. يرجى المحاولة مرة أخرى.", + "askAnythingPlaceholder": "اسأل أي شيء...", + "agentNotInstalled": "{agent} غير مثبّت · افتح إعدادات Agents لتثبيته", + "agentAdapterNotInstalled": "محوّل ACP الخاص بـ {agent} غير مثبّت (وهو منفصل عن واجهة الأوامر لديك) · افتح إعدادات Agents لتثبيته" + }, + "welcomePanel": { + "greeting": "ماذا تودّ أن تفعل اليوم؟", + "tips": { + "tileTabs": "انقر بزر الفأرة الأيمن على تبويب محادثة واختر «عرض متجانب» لمقارنة عدة جلسات جنبًا إلى جنب.", + "pinTab": "انقر نقرًا مزدوجًا على تبويب محادثة لتثبيته كي لا تستبدله جلسة جديدة تلقائيًا.", + "shortcutsNewSearch": "{newConversation} يفتح محادثة جديدة، و{searchConversations} يبحث في السجل.", + "slashAtMention": "اكتب / في حقل الإدخال لتشغيل أوامر السلاش، أو @ للإشارة إلى ملف من المشروع.", + "pasteDropFiles": "ألصق لقطة شاشة أو اسحب ملفًا مباشرة إلى حقل الإدخال لإرفاقه.", + "queueMessage": "أثناء رد الوكيل، تابع الكتابة — ستوضع رسالتك التالية في الطابور وتُرسل تلقائيًا عند انتهائه.", + "draftAutoSave": "تُحفظ المسودات غير المُرسلة تلقائيًا لكل محادثة وتُستعاد عند العودة.", + "forkSend": "تتضمن قائمة زر الإرسال المنسدلة «تفرّع وأرسل» لإنشاء فرع من النقطة الحالية في تبويب جديد.", + "exportConversation": "انقر بزر الفأرة الأيمن داخل المحادثة لتصديرها بصيغة Markdown أو HTML أو صورة.", + "chatChannels": "اربط Telegram / Lark / WeChat من «الإعدادات → قنوات الدردشة» للمتابعة من هاتفك.", + "shortcutsAuxPanel": "{toggleAuxPanel} يبدّل اللوحة اليمنى لعرض الملفات المعدّلة وتغييرات Git لهذه الجلسة.", + "shortcutsTerminalSidebar": "{toggleTerminal} يفتح الطرفية المدمجة، و{toggleSidebar} يبدّل الشريط الجانبي.", + "customShortcuts": "يمكن إعادة تعيين جميع الاختصارات من «الإعدادات → الاختصارات».", + "webService": "فعّل «الإعدادات → خدمة الويب» ليتمكن أعضاء الفريق من الوصول إلى نفس codeg عبر المتصفح.", + "fusionMode": "افتح ملفًا أو فرقًا لعرضه تلقائيًا بجوار المحادثة.", + "quickMessages": "افتح زر + بجانب الإدخال واختر «الرسائل السريعة» لإدراج مقتطف محفوظ (تُدار من «الإعدادات → الرسائل السريعة»).", + "experts": "يحتوي زر + على قائمة «مهارات الخبراء» — حمّل أدوارًا مثل التصحيح أو التخطيط بنقرة واحدة.", + "taskBoard": "تنفّذ المهام قيد الانتظار عملاً كاملاً من البداية إلى النهاية: يعمل الوكيل في worktree خاص به، ثم تراجع الفروق وتدمجها.", + "automations": "تشغّل الأتمتة موجّهًا محفوظًا وفق جدول زمني — مراجعة ليلية أو تقريرًا دوريًا — ويمكن أن يحصل كل تشغيل على worktree خاص به.", + "tokenUsage": "انقر على عدد المحادثات في شريط الحالة لفتح استهلاك الرموز، موزّعًا حسب اليوم والوكيل والنموذج والمجلد.", + "mentionTargets": "لا تقتصر @ على الملفات: اذكر وكيلًا آخر لتفويض مهمة فرعية، أو أشِر إلى جلسة سابقة أو التزام أو مهارة.", + "splitGroups": "انقر بزر الفأرة الأيمن على تبويب واختر «تقسيم لليمين» أو «تقسيم للأسفل» لإبقاء محادثتين في لوحين منفصلين.", + "worktrees": "افتح زر الفرع واختر «Worktree جديد» ليعمل عدة وكلاء على المستودع نفسه دون أن يستبدل أحدهم ملفات الآخر.", + "importSessions": "هل شغّلت جلسات في الطرفية من قبل؟ تحتوي قائمة المجلد على «استيراد الجلسات المحلية» لجلب ذلك السجل إلى codeg.", + "subSessions": "عندما يفوّض وكيل مهمة، تظهر الجلسة الفرعية متداخلة تحته في الشريط الجانبي — وسّع الصف لتتابع ما فعلته كل واحدة.", + "liveFeedback": "تُدرج «ملاحظات مباشرة» في قائمة + ملاحظةً داخل الدور الذي ينفّذه الوكيل بالفعل، دون مقاطعته.", + "skillPacks": "تجمع الإعدادات ← حزم المهارات خبراء البرمجة والبحث العلمي ومهارات المكتب — فعّلها لكل وكيل على حدة.", + "modelProviders": "تقبل الإعدادات ← مزودو النماذج مفتاح API أو نقطة نهاية خاصة بك، ثم تختار النموذج مباشرة من حقل الإدخال.", + "workspaceBackground": "تحدّد الإعدادات ← المظهر صورة خلفية لمساحة العمل، وشفافية اللوحات، وخطوط التطبيق." + }, + "quickActions": { + "excel": "مصنّف Excel", + "excelDesc": "جداول بيانات وصيغ ومخططات", + "word": "مستند Word", + "wordDesc": "تقارير ورسائل ومذكرات", + "ppt": "عرض تقديمي", + "pptDesc": "شرائح بتصميم احترافي", + "pitchDeck": "عرض استثماري", + "pitchDeckDesc": "عرض تمويل بمؤشرات رئيسية", + "morph": "حركة Morph", + "morphDesc": "انتقالات شرائح سينمائية", + "morph3d": "Morph ثلاثي الأبعاد", + "morph3dDesc": "نماذج ثلاثية الأبعاد وحركات كاميرا", + "academic": "ورقة أكاديمية", + "academicDesc": "بحث باستشهادات وبنية", + "financial": "نموذج مالي", + "financialDesc": "قوائم وDCF وتوقعات", + "dashboard": "لوحة بيانات", + "dashboardDesc": "مؤشرات وتحليلات من بياناتك", + "prompts": { + "excel": "أنشئ مصنّف Excel وفق المتطلبات التالية:\n\n[صف هنا بياناتك وجداولك وصيغك ومخططاتك]", + "word": "أنشئ مستند Word وفق المتطلبات التالية:\n\n[صف هنا محتوى المستند وبنيته وتنسيقه]", + "ppt": "أنشئ عرض PowerPoint تقديمي وفق المتطلبات التالية:\n\n[صف هنا شرائحك ومحتواك وتصميمك]", + "pitchDeck": "أنشئ عرضًا استثماريًا لجمع التمويل وفق المتطلبات التالية:\n\n[صف هنا شركتك وجولة التمويل والمؤشرات الرئيسية]", + "morph": "أنشئ عرضًا تقديميًا بحركات انتقال Morph:\n\n[صف هنا موضوع العرض والمؤثرات المرئية المطلوبة]", + "morph3d": "أنشئ عرض Morph ثلاثي الأبعاد بنماذج GLB وحركات كاميرا:\n\n[صف هنا موضوعك ومفهومك المرئي ثلاثي الأبعاد]", + "academic": "اكتب ورقة أكاديمية في Word وفق المتطلبات التالية:\n\n[صف هنا موضوع بحثك ومنهجيتك وأبرز نتائجك]", + "financial": "أنشئ نموذجًا ماليًا في Excel وفق المتطلبات التالية:\n\n[صف هنا قوائمك المالية وتوقعاتك وتحليلاتك]", + "dashboard": "أنشئ لوحة بيانات في Excel وفق المتطلبات التالية:\n\n[صف هنا مصدر بياناتك ومؤشراتك ومخططاتك]", + "scientific-brainstorming": "ساعدني في توليد أفكار بحثية: استكشف الروابط متعددة التخصصات، وتحدَّ الافتراضات، واكشف الفجوات الواعدة. المجال الذي أستكشفه: ", + "hypothesis-generation": "ساعدني في تحويل هذه الملاحظات إلى فرضيات قابلة للاختبار، مع تنبؤات واضحة وآليات معقولة وتجارب لاختبارها. ملاحظاتي: ", + "experimental-design": "ساعدني في تصميم تجربة دقيقة قبل جمع البيانات: التصميم والعشوائية والضوابط وكيفية تجنّب الالتباس. ما أريد دراسته: ", + "statistical-power": "ساعدني في تحديد حجم العينة المطلوب: أرشدني خلال تحليل القوة الإحصائية (حجم الأثر، ألفا، القوة) لتصميمي. التفاصيل: ", + "statistical-analysis": "ساعدني في تحليل هذه البيانات بشكل صحيح: اختر الاختبار المناسب، وتحقق من الافتراضات، وأبلغ عن أحجام الأثر، واكتب النتائج. بياناتي وسؤالي: ", + "exploratory-data-analysis": "قم بتحليل استكشافي لملف بياناتي: لخّص بنيته وجودته والأنماط اللافتة، ثم اقترح الخطوات التالية. الملف هو: ", + "scientific-visualization": "ساعدني في إنشاء شكل بجودة النشر: تخطيط واضح، وأشرطة خطأ صادقة، ولوحة ألوان مناسبة لعمى الألوان، وتنسيق المجلة. ما أريد عرضه: ", + "scientific-critical-thinking": "ساعدني في التقييم النقدي لهذه الدراسة أو الادعاء: قيّم جودة الأدلة، وارصد التحيّزات والعوامل المربكة، وزِن الاستنتاجات. إليك المحتوى: ", + "paper-lookup": "ساعدني في العثور على أوراق ذات صلة ونص كامل مفتوح الوصول عبر قواعد البيانات الأكاديمية، مع استشهادات يمكنني إعادة استخدامها. أبحث عن: " + }, + "paper-lookup": "البحث عن الأوراق البحثية", + "paper-lookupDesc": "البحث في 10 واجهات برمجية أكاديمية (PubMed وarXiv وOpenAlex وCrossref…) عن الأوراق والاستشهادات والنص الكامل المفتوح.", + "scientific-critical-thinking": "التفكير النقدي", + "scientific-critical-thinkingDesc": "تقييم الادعاءات العلمية وجودة الأدلة: رصد التحيّزات والعوامل المربكة وتطبيق أطر GRADE ومخاطر التحيّز.", + "scientific-visualization": "التصور العلمي", + "scientific-visualizationDesc": "أشكال جاهزة للنشر: تخطيطات متعددة اللوحات، وتعليقات الدلالة الإحصائية، وتنسيق خاص بكل مجلة.", + "exploratory-data-analysis": "تحليل البيانات الاستكشافي", + "exploratory-data-analysisDesc": "استكشاف آلي لملفات البيانات العلمية بأكثر من 200 صيغة مع مقاييس الجودة والتقارير.", + "statistical-analysis": "التحليل الإحصائي", + "statistical-analysisDesc": "تحليل إحصائي موجَّه: اختيار الاختبار، والتحقق من الافتراضات، وأحجام الأثر، والتقارير بأسلوب APA.", + "statistical-power": "القوة الإحصائية", + "statistical-powerDesc": "تحليل حجم العينة والقوة الإحصائية: عدد المشاركين اللازم، وأصغر تأثير قابل للكشف، ومنحنيات القوة.", + "experimental-design": "تصميم التجارب", + "experimental-designDesc": "تصميم دراسات دقيقة قبل جمع البيانات: العشوائية والتجميع والضوابط وتصاميم العوامل/DOE.", + "hypothesis-generation": "توليد الفرضيات", + "hypothesis-generationDesc": "تحويل الملاحظات إلى فرضيات قابلة للاختبار مع تنبؤات وآليات وتجارب لاختبارها.", + "scientific-brainstorming": "العصف الذهني العلمي", + "scientific-brainstormingDesc": "توليد أفكار بحثية مفتوحة: استكشاف الروابط متعددة التخصصات وتحدّي الافتراضات وكشف الفجوات البحثية.", + "tabs": { + "office": "الأعمال المكتبية", + "coding": "تطوير الكود", + "research": "البحث العلمي" + }, + "coding": { + "brainstormingDesc": "استكشف النية والمتطلبات قبل البناء", + "debuggingDesc": "حدد السبب الجذري قبل اقتراح الإصلاحات", + "writingSkillsDesc": "أنشئ وحرّر وتحقق من مهارات قابلة لإعادة الاستخدام" + }, + "notEnabled": { + "title": "المهارة ”{skill}“ غير مُفعّلة بعد لـ {agent}", + "description": "فعّلها من الإعدادات لاستخدامها هنا.", + "action": "تفعيل", + "hint": "المهارة غير مُفعّلة" + }, + "scrollPrev": "عرض المهارات السابقة", + "scrollNext": "عرض المزيد من المهارات" + } + }, + "agentSelector": { + "noEnabledAgents": "لا يوجد وكلاء مفعّلون", + "openAgentsSettings": "فتح إعدادات الوكلاء", + "notInstalled": "غير مثبّت", + "moreAgents": "وكلاء إضافيون ({count})" + }, + "subAgentOverlay": { + "title": "الوكلاء الفرعيون", + "collapsedSummary": "الوكلاء الفرعيون {count}", + "collapseAria": "طي الوكلاء الفرعيين" + }, + "agentPlanOverlay": { + "title": "خطة الوكيل", + "collapsePlanAria": "طي الخطة", + "collapsedSummary": "الخطة {completed}/{total}", + "status": { + "completed": "مكتمل", + "inProgress": "قيد التنفيذ", + "pending": "قيد الانتظار", + "unknown": "غير معروف" + }, + "priority": { + "high": "مرتفع", + "medium": "متوسط", + "low": "منخفض", + "unknown": "غير معروف" + } + }, + "permissionDialog": { + "subtitle": "يطلب الوكيل إذنًا لمتابعة هذا الدور.", + "queuedCount": "+{count} في الانتظار", + "kindFallbackTool": "أداة", + "command": "أمر", + "cwd": "دليل العمل: {cwd}", + "filesSummary": "الملفات: {count}", + "moreFiles": "+{count} ملف إضافي", + "plan": "الخطة", + "allowedActions": "الإجراءات المسموح بها", + "targetMode": "وضع الهدف: {mode}", + "optionGrants": "ما يمنحه كل خيار", + "changeScopeSession": "هذه الجلسة", + "changeScopeProcess": "هذا التشغيل", + "changeScopeUser": "محفوظ في إعدادات المستخدم", + "changeScopeProject": "محفوظ في إعدادات المشروع", + "changeScopeProjectLocal": "محفوظ في إعدادات المشروع المحلية", + "changeScopePersistent": "محفوظ بشكل دائم" + }, + "questionDialog": { + "title": "الوكيل يطرح سؤالاً", + "placeholder": "اكتب إجابتك...", + "send": "إرسال" + }, + "messageBranch": { + "previousBranchAria": "الفرع السابق", + "nextBranchAria": "الفرع التالي", + "pageOf": "{current} من {total}" + }, + "terminal": { + "title": "الطرفية", + "running": "قيد التشغيل" + }, + "reasoning": { + "thinking": "جارٍ التفكير…", + "thoughtForFewSeconds": "تفكير", + "thoughtForSeconds": "تفكير" + }, + "linkSafety": { + "errorCannotOpen": "تعذر فتح الملف المحلي", + "errorNoWorkspace": "لا يوجد مجلد مساحة عمل نشط حالياً.", + "errorFailedOpen": "فشل فتح الملف المحلي", + "errorFailedLink": "فشل فتح الرابط", + "errorUnsupportedLinkProtocol": "بروتوكول الرابط هذا غير مدعوم." + }, + "fileActions": { + "openInFinder": "فتح في Finder", + "openInExplorer": "فتح في Explorer", + "openInFileManager": "فتح في مدير الملفات", + "copyRelativePath": "نسخ المسار النسبي", + "copyAbsolutePath": "نسخ المسار المطلق", + "pathCopied": "تم نسخ المسار", + "copyPathFailed": "فشل نسخ المسار", + "openFailed": "فشل فتح الملف المحلي" + }, + "messageList": { + "attachedResources": "الموارد المرفقة", + "loading": "جارٍ التحميل...", + "loadEarlier": "تحميل الرسائل السابقة", + "loadingEarlier": "جارٍ تحميل الرسائل السابقة…", + "error": "خطأ: {message}", + "errorTitle": "فشل تحميل الجلسة", + "errorActionReload": "إعادة تحميل", + "errorActionNewSession": "محادثة جديدة", + "emptyConversation": "لا توجد رسائل في هذه المحادثة.", + "systemMessage": "رسالة النظام", + "copyMessage": "نسخ", + "copied": "تم النسخ", + "downloadImage": "تنزيل الصورة", + "downloadFailed": "فشل التنزيل: {message}", + "imageGeneration": "إنشاء الصورة", + "imageGenerationPending": "جارٍ إنشاء الصورة…", + "imageGenerationFailed": "فشل إنشاء الصورة", + "model": "النموذج", + "tokenStats": "استخدام الرموز", + "tokenInput": "الإدخال", + "tokenOutput": "الإخراج", + "tokenCacheRead": "قراءة التخزين المؤقت", + "tokenCacheWrite": "كتابة التخزين المؤقت", + "duration": "المدة", + "completedAt": "وقت الإنجاز", + "jumpToPreviousUserMessage": "الانتقال إلى رسالة المستخدم", + "showMore": "عرض المزيد", + "showLess": "طي" + }, + "liveTurnStats": { + "thinking": "جارٍ التفكير...", + "streaming": "جارٍ البث", + "elapsedHours": "{value}س", + "elapsedMinutes": "{value}د", + "elapsedSeconds": "{value}ث", + "outputSpeedAria": "السرعة التقديرية للإخراج", + "outputSpeedTooltip": "السرعة التقديرية للإخراج (نص + تفكير)" + }, + "jsonTree": { + "viewRaw": "عرض JSON الخام", + "viewTree": "عرض الشجرة", + "fields": "{count, plural, zero {لا حقول} one {حقل واحد} two {حقلان} few {# حقول} many {# حقلًا} other {# حقل}}", + "items": "{count, plural, zero {لا عناصر} one {عنصر واحد} two {عنصران} few {# عناصر} many {# عنصرًا} other {# عنصر}}" + }, + "tool": { + "parameters": "المعلمات", + "error": "خطأ", + "result": "النتيجة", + "status": { + "approvalRequested": "بانتظار الموافقة", + "approvalResponded": "تم الرد", + "inputAvailable": "قيد التشغيل", + "inputStreaming": "قيد الانتظار", + "outputAvailable": "مكتمل", + "outputDenied": "مرفوض", + "outputError": "خطأ" + } + }, + "toolCallBlock": { + "tool": "أداة", + "error": "خطأ", + "result": "النتيجة" + }, + "delegation": { + "subAgentRunning": "العميل الفرعي قيد التشغيل…", + "noDetail": "No detail available yet.", + "unknownAgent": "وكيل فرعي", + "openDetail": "عرض المحادثة", + "detailTitle": "محادثة الوكيل الفرعي", + "detailDescription": "عرض للقراءة فقط لمحادثة الوكيل الفرعي المُفوَّض.", + "waitForResult": "في انتظار نتيجة المهمة {task}", + "waitForResultNoTask": "في انتظار نتيجة المهمة", + "cancelTask": "جارٍ إلغاء المهمة {task}", + "cancelTaskNoTask": "جارٍ إلغاء المهمة", + "resultPageOf": "{current} / {total}", + "prevResult": "النتيجة السابقة", + "nextResult": "النتيجة التالية", + "noResultText": "لا توجد نتيجة في هذا الفحص.", + "status": { + "starting": "قيد البدء", + "running": "قيد التشغيل", + "checked": "تم الفحص", + "waiting": "في انتظار الموافقة", + "ok": "اكتمل", + "err": { + "default": "فشل", + "delegation_disabled": "معطل", + "depth_limit": "حد العمق", + "invalid_agent_type": "وكيل غير صالح", + "spawn_failed": "فشل البدء", + "send_failed": "فشل الإرسال", + "timeout": "انتهت المهلة", + "canceled": "ملغى", + "child_refusal": "رفض الوكيل الفرعي", + "child_max_tokens": "الوكيل الفرعي: حد الرموز", + "child_max_turn_requests": "الوكيل الفرعي: حد الطلبات", + "child_empty": "الوكيل الفرعي بدون استجابة", + "child_unknown": "الوكيل الفرعي: خطأ", + "unknown": "مهمة غير معروفة" + } + } + }, + "contentParts": { + "showingTailOutput": "يتم عرض نهاية المخرجات أثناء البث لتحسين الأداء.", + "result": "النتيجة", + "unknown": "غير معروف", + "inputTruncated": "تم اقتطاع الإدخال — قد يكون الفرق غير مكتمل.", + "replaceAll": "استبدال الكل", + "filesCount": "الملفات: {count}", + "update": "تحديث", + "moreFiles": "+{count} ملف إضافي", + "timeoutMs": "المهلة: {timeout}ms", + "backgroundTrue": "الخلفية: true", + "scriptToolCalls": "{count, plural, zero {صفر استدعاء أداة} one {استدعاء أداة واحد} two {استدعاءا أداة} few {# استدعاءات أداة} many {# استدعاء أداة} other {# استدعاء أداة}}", + "offset": "الإزاحة: {offset}", + "limit": "الحد: {limit}", + "pages": "الصفحات: {pages}", + "mode": "الوضع: {mode}", + "cell": "الخلية: {cell}", + "shellSession": "الجلسة {id}", + "pathLabel": "المسار:", + "globLabel": "نمط glob:", + "typeLabel": "النوع:", + "outputLabel": "المخرجات:", + "caseInsensitive": "غير حساس لحالة الأحرف", + "multiline": "متعدد الأسطر", + "promptLabel": "المطالبة", + "subjectLabel": "الموضوع", + "taskLabel": "المهمة", + "nameLabel": "الاسم:", + "agentPromptLabel": "المطالبة", + "agentModelLabel": "النموذج", + "agentRunning": "قيد التشغيل...", + "agentLiveTranscript": "النشاط المباشر", + "agentProgressTools": "{count} استدعاءات أدوات", + "agentProgressTurns": "{count} جولات", + "agentProgressContext": "السياق {pct}%", + "agentSessionAction": "عرض جلسة الوكيل الفرعي", + "agentSessionTitle": "جلسة الوكيل الفرعي", + "agentSessionLoading": "جارٍ تحميل سجل الوكيل الفرعي…", + "agentSessionEmpty": "لم يكتب الوكيل الفرعي أي شيء بعد.", + "agentFallbackTitle": "جارٍ تشغيل الوكيل الفرعي…", + "agentCodexLaunchOnly": "تم التشغيل. لا يبلّغ Codex عن أي تقدّم إضافي لهذا الوكيل الفرعي — وستصل نتيجته كرسالة في هذه المحادثة.", + "agentStatsBash": "الأوامر", + "agentStatsRead": "الملفات المقروءة", + "agentStatsSearch": "عمليات البحث", + "agentStatsEdit": "التعديلات", + "agentStatsOther": "أخرى", + "goal": { + "title": "الهدف:", + "titleWithStatus": "الهدف {status}", + "objective": "الهدف", + "statusLabel": "الحالة", + "tokensUsed": "tokens المستخدمة", + "budget": "الميزانية", + "remaining": "المتبقي", + "elapsed": "المدة", + "tokens": "tokens", + "pause": "إيقاف مؤقت", + "clear": "مسح", + "status": { + "active": "نشط", + "paused": "متوقف مؤقتًا", + "blocked": "محظور", + "usageLimited": "الاستخدام محدود", + "budgetLimited": "الميزانية محدودة", + "complete": "مكتمل", + "limited": "تم بلوغ الحد" + } + }, + "field": { + "file": "ملف", + "notebook": "دفتر", + "command": "أمر", + "old": "قديم", + "new": "جديد", + "pattern": "النمط", + "path": "المسار", + "query": "الاستعلام", + "url": "URL:", + "description": "الوصف", + "content": "المحتوى", + "source": "المصدر", + "prompt": "المطالبة", + "subject": "الموضوع", + "taskId": "معرف المهمة", + "status": "الحالة", + "skill": "Skill", + "args": "الوسائط", + "offset": "الإزاحة", + "limit": "الحد", + "glob": "نمط glob", + "type": "النوع", + "output": "المخرجات", + "replaceAll": "استبدال الكل", + "language": "اللغة", + "timeout": "المهلة", + "background": "الخلفية", + "agentType": "نوع الوكيل", + "library": "المكتبة", + "libraryId": "معرف المكتبة" + }, + "title": { + "edit": "تحرير", + "command": "أمر", + "script": "سكربت", + "waitCommand": "انتظار {command}", + "waitCell": "انتظار الجلسة {id}", + "terminateCommand": "إنهاء {command}", + "terminateCell": "إنهاء الجلسة {id}", + "stdinChars": "إدخال {chars}", + "todoWrite": "TodoWrite (تحديث المهام)", + "read": "قراءة", + "write": "كتابة", + "notebookEdit": "NotebookEdit (تحرير الدفتر)", + "editFiles": "تحرير ({count} ملفًا)", + "editWithTarget": "تحرير {target}", + "readWithTarget": "قراءة {target}", + "writeWithTarget": "كتابة {target}", + "notebookEditWithTarget": "NotebookEdit ({target})", + "globWithPattern": "نمط glob {pattern}", + "listFilesWithPath": "عرض الملفات {path}", + "grepWithPattern": "نمط grep {pattern}", + "taskCreateWithSubject": "إنشاء مهمة: {subject}", + "taskUpdateWithStatus": "تحديث المهمة #{id} -> {status}", + "taskUpdate": "تحديث المهمة #{id}", + "webFetchWithUrl": "WebFetch ({url})", + "webSearchWithQuery": "بحث الويب: {query}", + "todosProgress": "المهام ({done}/{total})", + "skillWithName": "Skill: {name}", + "genericWithContext": "{tool} ({context})" + }, + "search": { + "noMatches": "لا توجد نتائج مطابقة", + "matchSummary": "{matches, plural, zero {صفر تطابق} one {تطابق واحد} two {تطابقان} few {# تطابقات} many {# تطابقاً} other {# تطابق}} في {files, plural, zero {صفر ملف} one {ملف واحد} two {ملفان} few {# ملفات} many {# ملفاً} other {# ملف}}", + "fileSummary": "{files, plural, zero {صفر ملف} one {ملف واحد} two {ملفان} few {# ملفات} many {# ملفاً} other {# ملف}}", + "moreResults": "{count, plural, zero {لا نتائج إضافية} one {نتيجة إضافية واحدة غير معروضة} two {نتيجتان إضافيتان غير معروضتين} few {# نتائج إضافية غير معروضة} many {# نتيجة إضافية غير معروضة} other {# نتيجة إضافية غير معروضة}}" + }, + "toolGroup": { + "search": "{count, plural, zero {بحث صفر مرة} one {بحث مرة واحدة} two {بحث مرتين} few {بحث # مرات} many {بحث # مرة} other {بحث # مرة}}", + "command": "{count, plural, zero {تنفيذ صفر أمر} one {تنفيذ أمر واحد} two {تنفيذ أمرين} few {تنفيذ # أوامر} many {تنفيذ # أمراً} other {تنفيذ # أمر}}", + "read": "{count, plural, zero {قراءة ملفات صفر مرة} one {قراءة ملفات مرة واحدة} two {قراءة ملفات مرتين} few {قراءة ملفات # مرات} many {قراءة ملفات # مرة} other {قراءة ملفات # مرة}}", + "memory": "{count, plural, zero {استرجاع صفر ذاكرة} one {استرجاع ذاكرة واحدة} two {استرجاع ذاكرتين} few {استرجاع # ذكريات} many {استرجاع # ذكرى} other {استرجاع # ذكرى}}", + "edit": "{count, plural, zero {تعديل ملفات صفر مرة} one {تعديل ملفات مرة واحدة} two {تعديل ملفات مرتين} few {تعديل ملفات # مرات} many {تعديل ملفات # مرة} other {تعديل ملفات # مرة}}", + "fetch": "{count, plural, zero {جلب صفر مورد} one {جلب مورد واحد} two {جلب موردين} few {جلب # موارد} many {جلب # مورداً} other {جلب # مورد}}", + "think": "{count, plural, zero {تفكير صفر مرة} one {تفكير مرة واحدة} two {تفكير مرتين} few {تفكير # مرات} many {تفكير # مرة} other {تفكير # مرة}}", + "todo": "{count, plural, zero {تحديث صفر مهمة} one {تحديث مهمة واحدة} two {تحديث مهمتين} few {تحديث # مهام} many {تحديث # مهمة} other {تحديث # مهمة}}", + "task": "{count, plural, zero {تشغيل صفر مهمة} one {تشغيل مهمة واحدة} two {تشغيل مهمتين} few {تشغيل # مهام} many {تشغيل # مهمة} other {تشغيل # مهمة}}", + "other": "{count, plural, zero {استخدام صفر أداة} one {استخدام أداة واحدة} two {استخدام أداتين} few {استخدام # أدوات} many {استخدام # أداة} other {استخدام # أداة}}", + "errorSuffix": "{count, plural, zero {صفر فشل} one {فشل واحد} two {فشلان} few {# فشلوا} many {# فشلاً} other {# فشل}}", + "joiner": " · " + }, + "planMode": { + "entered": "تم بدء وضع التخطيط", + "planLabel": "الخطة", + "reviewApproved": "تمت الموافقة على الخطة — جارٍ التنفيذ", + "reviewKept": "الاستمرار في وضع الخطة", + "reviewPending": "في انتظار قرار الخطة", + "submitted": "تم إرسال الخطة", + "switched": "تم تبديل الوضع" + }, + "backgroundTask": { + "title": "مهمة في الخلفية", + "titleWithId": "مهمة في الخلفية · {id}", + "running": "قيد التشغيل", + "completed": "اكتملت", + "failed": "فشلت", + "stopped": "متوقفة", + "exitCode": "رمز الخروج {code}", + "polledTimes": "تم الاستعلام {count} مرة", + "runningInBackground": "في الخلفية", + "launchNote": "قيد التشغيل في الخلفية · {id}" + }, + "codexScript": { + "outputMissing": "اقتطع codex مُخرَج النص البرمجي وأزال الفاصل الخاص بهذا الأمر، لذا تعذّر نسب أي مُخرَج إليه.", + "sharedWith": "يحتوي هذا المقطع أيضًا على مُخرَج {commands} — إذ اقتطع codex الفواصل الخاصة بها.", + "truncated": "مقتطع" + } + }, + "messageNav": { + "title": "تنقل الرسائل", + "collapse": "طي تنقل الرسائل", + "collapsedSummary": "الرسائل {count}", + "fileCount": "{count, plural, one {# ملف} other {# ملفات}}", + "remove": "إزالة", + "noDiffDataAvailable": "لا توجد بيانات diff متاحة لـ {filePath}" + }, + "replyArtifacts": { + "title": "الملفات المتغيرة", + "fileCount": "{count, plural, one {# ملف} other {# ملفات}}", + "newFilesTitle": "ملفات جديدة", + "revealInFolder": "عرض في مدير الملفات", + "openFile": "فتح {filePath}", + "openInEditor": "فتح في المحرر", + "remove": "إزالة", + "noDiffDataAvailable": "لا توجد بيانات diff متاحة لـ {filePath}" + }, + "askQuestion": { + "title": "يحتاج الوكيل إلى اختيارك", + "subtitle": "أجب ثم أرسل. يمكنك التخطّي في أي وقت.", + "recommended": "موصى به", + "other": "أخرى", + "otherPlaceholder": "اكتب إجابتك…", + "singleSelect": "اختيار واحد", + "multiSelect": "اختيار متعدد", + "skip": "تخطّي", + "next": "التالي", + "submit": "إرسال", + "submitError": "تعذّر الإرسال. حاول مرة أخرى." + }, + "planApproval": { + "title": "لدى الوكيل خطة — راجعها", + "emptyPlan": "لم يكتب الوكيل خطة. وافق للبدء في التنفيذ أو اطلب تعديلات.", + "approve": "الموافقة والبدء", + "requestChanges": "طلب تعديلات", + "abandon": "تجاهل", + "feedbackPlaceholder": "ما الذي ينبغي تغييره؟", + "sendChanges": "إرسال", + "cancel": "إلغاء", + "submitError": "تعذّر الإرسال. حاول مرة أخرى." + }, + "feedbackCheckResult": { + "count": "{count} ملاحظة", + "expand": "عرض كل الملاحظات", + "collapse": "طي", + "errorTitle": "فشل التحقق من الملاحظات" + }, + "askQuestionResult": { + "title": "سؤال", + "answeredLabel": "سؤال وجواب:", + "awaiting": "في انتظار إجابتك…", + "declined": "لقد تجاهلت هذا — استخدم الوكيل حكمه الخاص.", + "noSelection": "لا يوجد اختيار" + }, + "configStale": { + "agentConfigTitle": "تم تحديث إعدادات الوكيل", + "modelProviderTitle": "تم تحديث مزوّد النموذج", + "description": "لا تزال هذه الجلسة تستخدم الإعدادات السابقة. أعد الاتصال لتطبيقها (سيتم الاحتفاظ بسجل المحادثة).", + "reconnect": "أعد الاتصال للتطبيق", + "reconnecting": "جارٍ إعادة الاتصال…", + "reconnectDisabledDuringTurn": "متاح بعد انتهاء الدور الحالي", + "dismiss": "تجاهل", + "reconnectFailed": "فشل في إعادة الاتصال بالجلسة", + "applied": "تم تطبيق الإعدادات الجديدة" + }, + "piProjectTrust": { + "title": "يتضمّن هذا المشروع موارد pi", + "description": "لا يقوم pi بتحميل ملفات ‎.pi الخاصة بالمستودع. راجعها لتقرّر.", + "descriptionExecutable": "يتضمّن المستودع إضافات pi تُنفّذ التعليمات البرمجية عند بدء التشغيل. لا يقوم pi بتحميلها. راجعها قبل أن تقرّر.", + "review": "مراجعة…", + "dismiss": "تجاهل", + "dialogTitle": "هل تثق بموارد pi في هذا المشروع؟", + "dialogDescription": "لا يحمّل pi ملفات ‎.pi الخاصة بالمستودع إلا إذا وثقت بالمجلد. لا تمنح الثقة إلا إذا كنت تثق بمحتوى هذا المستودع.", + "executionWarning": "الإضافات هي تعليمات برمجية. الوثوق بهذا المجلد يتيح للمستودع تشغيلها عند بدء pi بصلاحياتك، وقبل أن ترسل أي رسالة.", + "scopeNote": "يُحفظ القرار في ملف trust.json الخاص بـ pi لهذا المجلد، ويسري على كل المجلدات داخله، ويُستخدم أيضًا عند تشغيلك pi بنفسك في الطرفية. يمكنك تغييره لاحقًا من الإعدادات ← الوكلاء ← Pi.", + "trust": "الوثوق بالمشروع", + "decline": "إبقاؤها غير محمّلة", + "disabledDuringTurn": "متاح بعد انتهاء الدور الحالي", + "trustedToast": "تم الوثوق بالمشروع — أُعيد الاتصال ليحمّل pi موارده", + "declinedToast": "تبقى موارد المشروع غير محمّلة", + "saveFailed": "تعذّر حفظ قرار الثقة بالمشروع", + "grantTitle": "هذا المشروع موثوق بالفعل", + "grantDescription": "يحمّل pi ملفات ‎.pi الخاصة بهذا المستودع. راجع ما الذي يسمح به ذلك.", + "grantInheritedDescription": "أحد المجلدات الأعلى موثوق، لذا يحمّل pi ملفات ‎.pi الخاصة بهذا المستودع. راجع ما الذي يسمح به ذلك.", + "grantDialogTitle": "موارد pi في هذا المشروع موثوقة", + "grantDialogDescription": "يُسمح لـ pi بتحميل ملفات ‎.pi الخاصة بهذا المستودع. كانت إصدارات codeg السابقة تمنح ذلك تلقائيًا عند فتحك لمجلد، لذا ربما لم يُطلب رأيك مطلقًا.", + "grantExecutionWarning": "الإضافات هي تعليمات برمجية. يشغّلها المستودع عند بدء pi بصلاحياتك، قبل أن ترسل أي رسالة.", + "inheritedFrom": "الثقة موروثة من", + "revoke": "إلغاء الثقة", + "keepTrusted": "الإبقاء على الثقة", + "revokedToast": "أُلغيت الثقة — أُعيد الاتصال ليتوقف pi عن تحميل موارد المشروع", + "trustedNoReconnect": "تم الوثوق بالمشروع — سيسري عند بدء pi في المرة القادمة", + "revokedNoReconnect": "أُلغيت الثقة — ستسري عند بدء pi في المرة القادمة" + }, + "collabAgent": { + "title": "وكيل فرعي", + "errorTitle": "فشلت مهمة الوكيل الفرعي", + "statesLabel": "الوكلاء الفرعيون", + "statusRunning": "قيد التشغيل", + "statusCompleted": "مكتمل", + "statusFailed": "فشل", + "statusPending": "قيد البدء", + "statusInterrupted": "متوقف", + "statusClosed": "مغلق", + "statusNotFound": "غير موجود", + "opSpawn": "بدء تشغيل الوكيل الفرعي", + "opWait": "جلب نتيجة الوكيل الفرعي", + "opClose": "إغلاق الوكيل الفرعي", + "opResume": "استئناف الوكيل الفرعي" + }, + "contextCompaction": { + "compacting": "جارٍ ضغط السياق…", + "compacted": "تم ضغط السياق", + "compactedTokens": "تم ضغط السياق · {before} → {after} رمز", + "failed": "فشل ضغط السياق" + }, + "sessionFailure": { + "category": { + "connection": "مشكلة في الاتصال", + "access": "مشكلة في الوصول", + "limit": "تم بلوغ الحد", + "request": "تم رفض الطلب", + "service": "مشكلة في الخدمة", + "unknown": "مشكلة في الجلسة" + }, + "action": { + "retry": "إعادة المحاولة", + "login": "تسجيل الدخول", + "newSession": "جلسة جديدة" + }, + "recovered": "تم التعافي", + "retryUnavailable": "لا توجد رسالة سابقة لإعادة إرسالها.", + "toggleDetails": "تبديل التفاصيل" + }, + "backgroundTasks": { + "running": "{count, plural, one {مهمة خلفية واحدة قيد التشغيل} two {مهمتا خلفية قيد التشغيل} few {# مهام خلفية قيد التشغيل} other {# مهمة خلفية قيد التشغيل}}", + "settling": "جارٍ مزامنة نتائج الخلفية…", + "settledFallback": "انتهت مهمة الخلفية ({status})", + "cardRunning": "قيد التشغيل في الخلفية", + "cardLaunchedPending": "بدأت مهمة الخلفية", + "cardCompleted": "اكتملت مهمة الخلفية", + "cardFinishedWithStatus": "انتهت مهمة الخلفية ({status})", + "cardResultPending": "لم تصل النتيجة بعد" + }, + "proposedPlan": { + "title": "الخطة المقترحة", + "planning": "جارٍ التخطيط…" + } + }, + "diffPreview": { + "mode": { + "added": "تمت الإضافة", + "deleted": "تم الحذف", + "renamed": "تمت إعادة التسمية", + "modified": "تم التعديل" + }, + "hunkLabel": "مقطع {index}", + "loadingHunk": "جارٍ تحميل hunk...", + "noDiffData": "لا توجد بيانات diff", + "showRemainingLines": "عرض {count} سطر إضافي" + }, + "conversationContextBar": { + "folderTitle": "مجلد العمل", + "branchTitle": "فرع العمل", + "searchFolder": "Search folder...", + "searchBranch": "Search branch...", + "noFolders": "No folders", + "noBranches": "No branches", + "noBranch": "(no branch)", + "chatModeLabel": "وضع الدردشة", + "commit": "Commit", + "push": "Push", + "merge": "Merge", + "toasts": { + "folderChanged": "Switched to {name}", + "openFolderFailed": "Failed to open folder", + "switchedToChatMode": "تم التبديل إلى وضع المحادثة", + "openStashFailed": "Failed to open stash window", + "openMergeFailed": "Failed to open merge window" + } + }, + "cloneDialog": { + "title": "استنساخ مستودع", + "repositoryUrl": "رابط المستودع", + "repositoryUrlPlaceholder": "https://github.com/user/repo.git", + "directory": "المجلد", + "directoryPlaceholder": "اختر مجلد الهدف...", + "browseDirectory": "تصفح المجلد", + "cancel": "إلغاء", + "clone": "استنساخ", + "clonePath": "مسار الاستنساخ: {path}" + }, + "toasts": { + "cloneFailed": "فشل استنساخ المستودع" + } + }, + "ProjectBoot": { + "title": "مُنشئ المشروع", + "tabs": { + "shadcn": "shadcn", + "hyperframes": "HyperFrames" + }, + "hyperframes": { + "title": "مشروع فيديو HyperFrames", + "subtitle": "أنشئ مشروعًا لتحويل HTML إلى فيديو. يمكن لوكيل مساحة العمل بعد ذلك كتابته وعرضه.", + "resolution": "الدقة", + "skillsTitle": "مهارات الوكلاء", + "skillsDesc": "ثبّت مهارات HyperFrames عامًّا (رابط رمزي) للوكلاء المحددين حتى يتمكنوا من إنشاء الفيديو وعرضه.", + "recheck": "إعادة الفحص", + "installedBadge": "مثبّت", + "skillsInstall": "تثبيت / تحديث المهارات", + "skillsInstalling": "جارٍ تثبيت المهارات…", + "skillsInstalled": "تم تثبيت مهارات HyperFrames", + "skillsInstallFailed": "تعذّر تثبيت مهارات HyperFrames" + }, + "config": { + "base": "الأساس", + "style": "النمط", + "baseColor": "اللون الأساسي", + "theme": "السمة", + "chartColor": "لون المخطط", + "iconLibrary": "مكتبة الأيقونات", + "font": "الخط", + "fontHeading": "خط العنوان", + "menuAccent": "تمييز القائمة", + "menuColor": "لون القائمة", + "radius": "نصف القطر", + "template": "القالب", + "createProject": "إنشاء مشروع", + "sectionStyle": "النمط", + "sectionColors": "الألوان", + "sectionTypography": "الخطوط", + "sectionInterface": "الواجهة" + }, + "preview": { + "loading": "جاري تحميل المعاينة..." + }, + "createDialog": { + "title": "إنشاء مشروع", + "projectName": "اسم المشروع", + "projectNamePlaceholder": "my-app", + "frameworkTemplate": "قالب الإطار", + "packageManager": "مدير الحزم", + "saveDirectory": "دليل الحفظ", + "saveDirectoryPlaceholder": "اختر الدليل...", + "browseDirectory": "تصفح", + "projectPath": "سيتم إنشاء المشروع في: {path}", + "advancedOptions": "خيارات متقدمة", + "base": "المكتبة الأساسية", + "enableRtl": "تفعيل دعم RTL", + "enableRtlDescription": "تفعيل دعم التخطيط للغات التي تُكتب من اليمين إلى اليسار (مثل العربية والعبرية)", + "pmChecking": "جارٍ التحقق...", + "pmNotInstalled": "غير مثبت", + "cancel": "إلغاء", + "create": "إنشاء", + "creating": "جاري إنشاء المشروع..." + }, + "toasts": { + "createFailed": "فشل إنشاء المشروع", + "createSuccess": "تم إنشاء المشروع بنجاح", + "openWorkspaceFailed": "تم إنشاء المشروع، ولكن تعذّر فتحه في مساحة العمل" + }, + "errors": { + "directoryExists": "الدليل الهدف موجود بالفعل", + "commandFailed": "فشل أمر إنشاء المشروع." + } + }, + "WebServiceSettings": { + "addressSwitchHint": "التبديل يغيّر فقط العنوان المعروض والمفتوح هنا؛ تستمع الخدمة على جميع الواجهات وتبقى قابلة للوصول من كل عنوان.", + "sectionTitle": "خدمة الويب", + "sectionDescription": "تفعيل للوصول إلى Codeg عن بُعد عبر المتصفح", + "port": "المنفذ", + "status": "الحالة", + "autoStart": "تشغيل تلقائي", + "autoStartHint": "تشغيل خدمة الويب عند بدء Codeg", + "running": "قيد التشغيل", + "stopped": "متوقف", + "processing": "جارٍ المعالجة...", + "start": "تشغيل", + "stop": "إيقاف", + "startFailed": "فشل التشغيل", + "stopFailed": "فشل الإيقاف", + "saveConfigFailed": "فشل حفظ إعدادات خدمة الويب", + "open": "فتح", + "hide": "إخفاء", + "show": "إظهار", + "copy": "نسخ", + "qrcode": "رمز QR", + "qrcodeTitle": "امسح للفتح", + "qrcodeHint": "امسح بهاتفك لفتح Codeg في المتصفح", + "addressLabel": "عنوان الوصول", + "tokenLabel": "رمز الوصول", + "tokenHint": "أدخل هذا الرمز عند الوصول إلى عميل الويب لأول مرة", + "tokenPlaceholder": "اتركه فارغاً للتوليد التلقائي", + "regenerate": "إعادة التوليد", + "stalePortOccupiedTitle": "المنفذ {port} مستخدم من قبل عملية أخرى", + "stalePortUnknownTitle": "حالة المنفذ {port} غير واضحة", + "stalePortHint": "لا يستطيع Codeg الربط قبل تحرير المنفذ. غيّر المنفذ أعلاه، أو أغلق العملية التي تحتفظ به.", + "errors": { + "alreadyRunning": "خدمة الويب قيد التشغيل بالفعل", + "invalidAddress": "تنسيق المضيف أو المنفذ غير صالح", + "portInUse": "المنفذ {port} مستخدم بالفعل. أغلق العملية التي تستخدمه أو اختر منفذاً آخر.", + "permissionDenied": "الصلاحيات غير كافية. استخدم منفذاً أعلى من 1024 أو شغّل التطبيق بصلاحيات أعلى.", + "addressUnavailable": "هذا العنوان غير متاح على هذا الجهاز", + "bindFailed": "فشل ربط العنوان" + } + }, + "DirectoryBrowser": { + "title": "تصفح المجلد", + "pathPlaceholder": "أدخل مسار المجلد...", + "goHome": "الذهاب إلى المجلد الرئيسي", + "navigateUp": "الذهاب إلى المجلد الأعلى", + "select": "اختيار", + "cancel": "إلغاء", + "loading": "جاري التحميل...", + "emptyDirectory": "هذا المجلد فارغ", + "errorLoadingDir": "فشل في تحميل المجلد", + "permissionDenied": "تم رفض الإذن" + }, + "ChatChannelSettings": { + "loading": "جاري التحميل...", + "sectionTitle": "قنوات المحادثة", + "sectionDescription": "تكوين بوتات المراسلة لتلقي إشعارات الأحداث واستعلام نشاط البرمجة.", + "addChannel": "إضافة قناة", + "noChannels": "لم يتم تكوين أي قنوات محادثة بعد.", + "channelName": "الاسم", + "channelNamePlaceholder": "بوت Telegram الخاص بي", + "channelType": "نوع القناة", + "lark": "Lark (Feishu)", + "weixin": "WeChat", + "dailyReport": "التقرير اليومي", + "dailyReportTime": "وقت التقرير", + "nameRequired": "اسم القناة مطلوب.", + "tokenRequired": "الرمز مطلوب.", + "chatIdRequired": "معرف المحادثة مطلوب.", + "topicMode": "وضع مجموعة المواضيع", + "topicModeHint": "يوجه مواضيع منتدى Telegram كجلسات Codeg منفصلة. يجب أن يكون البوت في forum supergroup وأن يملك صلاحية إدارة المواضيع.", + "loadFailed": "فشل في تحميل القنوات.", + "saveFailed": "فشل في حفظ التغييرات.", + "connectSuccess": "تم توصيل القناة.", + "connectFailed": "فشل الاتصال", + "disconnectSuccess": "تم قطع اتصال القناة.", + "disconnectFailed": "فشل قطع الاتصال.", + "testSuccess": "نجح اختبار الاتصال.", + "testFailed": "فشل اختبار الاتصال", + "deleteSuccess": "تم حذف القناة.", + "deleteFailed": "فشل في حذف القناة.", + "deleteConfirmTitle": "حذف القناة", + "deleteConfirmMessage": "سيتم حذف القناة وسجلات رسائلها نهائياً. هل أنت متأكد؟", + "cancel": "إلغاء", + "delete": "حذف", + "create": "إنشاء", + "save": "حفظ", + "channelListTitle": "القنوات المُعدة", + "channelListDescription": "القنوات المفعّلة ستتصل تلقائيًا عند بدء تشغيل الخدمة.", + "editChannel": "تعديل القناة", + "editSuccess": "تم تحديث القناة.", + "tokenPlaceholderKeep": "اتركه فارغاً للاحتفاظ بالقيمة الحالية", + "weixinScanTitle": "مسح رمز QR", + "weixinScanDescription": "افتح WeChat وامسح رمز QR للاتصال.", + "weixinQrcodeExpired": "انتهت صلاحية رمز QR.", + "weixinRefreshQrcode": "تحديث", + "weixinWaitingScan": "في انتظار المسح...", + "weixinPollError": "الاتصال غير مستقر، جاري إعادة المحاولة...", + "weixinReconnectNotice": "بسبب قيود بروتوكول iLink، بعد كل إعادة اتصال يجب عليك إرسال رسالة إلى الروبوت حتى تصبح مشغلات الأحداث فعالة.", + "connect": "اتصال", + "disconnect": "قطع الاتصال", + "test": "اختبار الاتصال", + "tabs": { + "channels": "القنوات", + "commands": "الأوامر", + "events": "الأحداث", + "other": "أخرى" + }, + "commands": { + "title": "الأوامر المدمجة", + "description": "أوامر البوت المتاحة في قنوات المحادثة. في المحادثات الجماعية، يلزم @Bot لمعالجة الرسائل.", + "prefixLabel": "بادئة الأمر", + "prefixDescription": "1-3 أحرف غير أبجدية رقمية لتشغيل أوامر البوت (الافتراضي /).", + "prefixSaved": "تم حفظ بادئة الأمر.", + "prefixSaveFailed": "فشل حفظ بادئة الأمر.", + "prefixInvalid": "يجب أن تكون البادئة 1-3 أحرف غير أبجدية رقمية.", + "save": "حفظ", + "folderDesc": "اختيار مجلد العمل", + "agentDesc": "اختيار وكيل الذكاء الاصطناعي", + "taskDesc": "إنشاء جلسة وتنفيذ المهمة", + "sessionsDesc": "عرض الجلسات النشطة في المجلد", + "resumeDesc": "المحادثات الأخيرة / استئناف جلسة", + "cancelDesc": "إلغاء المهمة الحالية", + "approveDesc": "الموافقة على طلب إذن الوكيل", + "denyDesc": "رفض طلب إذن الوكيل", + "searchDesc": "البحث في المحادثات حسب الكلمة المفتاحية", + "todayDesc": "ملخص نشاط اليوم", + "statusDesc": "حالة اتصال القناة", + "helpDesc": "عرض المساعدة" + }, + "events": { + "title": "إشعارات الأحداث", + "description": "عند تفعيل الأحداث، سيتم إرسالها إلى القناة عند تشغيلها.", + "turnComplete": "اكتمال الدور", + "turnCompleteDesc": "عند انتهاء دور الوكيل", + "error": "خطأ الوكيل", + "errorDesc": "عندما يواجه الوكيل خطأ", + "permissionRequest": "طلب إذن", + "permissionRequestDesc": "عندما يطلب الوكيل إذنًا لتنفيذ إجراء", + "questionRequest": "سؤال من الوكيل", + "questionRequestDesc": "عندما يطرح أحد الوكلاء سؤالاً عليك", + "userPromptSent": "رسالة المستخدم", + "userPromptSentDesc": "عند إرسالك رسالة — يُضمَّن نص الرسالة في الإشعار", + "saved": "تم تحديث فلتر الأحداث.", + "saveFailed": "فشل حفظ فلتر الأحداث.", + "loadFailed": "فشل تحميل الإعدادات.", + "retry": "إعادة المحاولة", + "webhooksTitle": "Webhooks", + "webhooksDescription": "يرسل حمولة JSON عبر POST إلى عنوان واحد أو أكثر عند تشغيل حدث مُفعَّل. ينطبق فلتر الأحداث أعلاه على Webhooks أيضًا.", + "webhookUrlPlaceholder": "https://example.com/webhook", + "addWebhook": "إضافة Webhook", + "removeWebhook": "إزالة Webhook", + "webhookSave": "حفظ", + "webhooksSaved": "تم حفظ Webhooks.", + "webhooksSaveFailed": "فشل حفظ Webhooks.", + "webhookInvalidUrl": "أدخل عناوين http(s) صالحة.", + "docsTitle": "تنسيق الطلب", + "docsMethod": "الطريقة", + "docsContentType": "Content-Type", + "docsNote": "يتم تسليم كل حدث مُفعَّل إلى جميع العناوين. لا يتم تأخير Webhooks؛ ولا يزال فلتر الأحداث أعلاه ساريًا.", + "editWebhook": "تعديل Webhook", + "enableWebhook": "تفعيل Webhook", + "webhookDuplicate": "هذا العنوان مُعد بالفعل.", + "cancel": "إلغاء", + "webhooksEmpty": "لا توجد Webhooks مُعدة بعد.", + "deleteWebhookTitle": "حذف Webhook", + "deleteWebhookMessage": "هل تريد حذف هذا الـ Webhook؟ لن يتم تسليم الأحداث إلى هذا العنوان بعد الآن.", + "delete": "حذف" + }, + "language": { + "title": "لغة الرسائل", + "description": "اللغة المستخدمة لإشعارات الأحداث واستجابات الأوامر والتقارير اليومية المرسلة إلى قنوات الدردشة.", + "saved": "تم حفظ لغة الرسائل.", + "saveFailed": "فشل حفظ لغة الرسائل.", + "en": "الإنجليزية", + "zh-cn": "الصينية المبسطة", + "zh-tw": "الصينية التقليدية", + "ja": "اليابانية", + "ko": "الكورية", + "es": "الإسبانية", + "de": "الألمانية", + "fr": "الفرنسية", + "pt": "البرتغالية", + "ar": "العربية" + } + }, + "ModelProviderSettings": { + "sectionTitle": "مزودو النماذج", + "sectionDescription": "إدارة بيانات اعتماد مزودي API للوكلاء.", + "filterAll": "الكل", + "providerListTitle": "المزودون المُعدّون", + "addProvider": "إضافة مزود", + "editProvider": "تعديل المزود", + "noProviders": "لم يتم تكوين أي مزود نماذج بعد.", + "providerName": "الاسم", + "providerNamePlaceholder": "مثال: OpenAI، Anthropic", + "apiUrl": "عنوان API", + "apiUrlPlaceholder": "https://api.openai.com/v1", + "apiKey": "مفتاح API", + "apiKeyPlaceholder": "sk-...", + "apiKeyKeepCurrent": "اتركه فارغاً للإبقاء على الحالي", + "agentTypes": "أنواع الوكلاء", + "agentTypesRequired": "يجب اختيار نوع وكيل واحد على الأقل.", + "agentType": "نوع الوكيل", + "agentTypeRequired": "نوع الوكيل مطلوب.", + "agentTypeImmutableHint": "لا يمكن تغيير نوع الوكيل بعد الإنشاء.", + "model": "النموذج", + "modelPlaceholderCodex": "gpt-5.6-sol / gpt-5.5", + "modelPlaceholderGemini": "gemini-3-pro-preview", + "claudeMainModel": "النموذج الرئيسي", + "claudeReasoningModel": "نموذج الاستدلال (التفكير)", + "claudeHaikuDefaultModel": "نموذج Haiku الافتراضي", + "claudeSonnetDefaultModel": "نموذج Sonnet الافتراضي", + "claudeOpusDefaultModel": "نموذج Opus الافتراضي", + "claudeCustomModelOption": "معرّف النموذج المخصّص", + "claudeCustomModelOptionName": "اسم النموذج المخصّص", + "claudeCustomModelOptionDescription": "وصف النموذج المخصّص", + "claudeCustomModelOptionHint": "يضيف عنصرًا مخصّصًا واحدًا إلى محدِّد نماذج Claude (مثل نموذج خلف بوابة/وكيل مخصّص). الاسم والوصف اختياريان لأغراض العرض فقط.", + "nameRequired": "اسم المزود مطلوب.", + "apiUrlRequired": "عنوان API مطلوب.", + "apiKeyRequired": "مفتاح API مطلوب.", + "loadFailed": "فشل تحميل المزودين.", + "saveFailed": "فشل حفظ التغييرات.", + "createSuccess": "تم إنشاء المزود.", + "editSuccess": "تم تحديث المزود.", + "deleteSuccess": "تم حذف المزود.", + "deleteConfirmTitle": "حذف المزود", + "deleteConfirmMessage": "سيتم حذف المزود \"{name}\" نهائياً. هل أنت متأكد؟", + "deleteBlockedByAgent": "{agents} يستخدم هذا المزود. يرجى إلغاء الربط قبل الحذف.", + "cancel": "إلغاء", + "delete": "حذف", + "create": "إنشاء", + "save": "حفظ", + "affectedRunningSessions": "{count} جلسة نشطة تحتاج إلى إعادة الاتصال لتطبيق التغيير" + }, + "SkillMatrix": { + "loading": "جارٍ التحميل…", + "searchPlaceholder": "البحث بالاسم أو المعرّف أو الوصف", + "empty": "لا شيء لعرضه.", + "emptySearch": "لا توجد نتائج مطابقة للبحث الحالي.", + "skillColumn": "المهارة", + "selectAll": "تحديد كل المرئي", + "selectSkill": "تحديد {name}", + "everything": { + "label": "إجراء جماعي", + "enable": "تفعيل الكل (المرئي)", + "disable": "تعطيل الكل (المرئي)" + }, + "columnMenu": { + "enableAll": "تفعيل كل المهارات", + "disableAll": "تعطيل كل المهارات" + }, + "rowMenu": { + "label": "إجراءات جماعية لـ {name}", + "enableAll": "تفعيل لكل الوكلاء", + "disableAll": "تعطيل لكل الوكلاء" + }, + "bulk": { + "selected": "{count} محدد", + "targetAll": "كل الوكلاء", + "targetSome": "{count} وكلاء", + "enable": "تفعيل", + "disable": "تعطيل", + "clear": "مسح" + }, + "confirm": { + "disableTitle": "تعطيل هذه الروابط؟", + "disableBody": "سيؤدي هذا إلى إزالة {count} من روابط المهارات التي يديرها codeg. المهارات التي تشغل دليلاً مخصصاً تبقى دون تغيير. يمكنك إعادة تفعيلها في أي وقت.", + "cancel": "إلغاء", + "confirm": "تعطيل" + }, + "toasts": { + "loadFailed": "فشل تحميل حالات المهارات", + "applyFailed": "فشل تطبيق التغييرات", + "enabled": "تم تفعيل {count} رابط", + "disabled": "تم تعطيل {count} رابط", + "enabledPartial": "تم تفعيل {ok}، وفشل {failed}", + "disabledPartial": "تم تعطيل {ok}، وفشل {failed}" + }, + "detail": { + "enableForAgents": "التفعيل للوكلاء", + "preview": "معاينة SKILL.md", + "loadingContent": "جارٍ تحميل المحتوى…" + }, + "copyModeHint": "تم النسخ (غير مرتبط) — أعد التفعيل بعد التحديثات للحصول على أحدث إصدار" + }, + "ExpertsSettings": { + "title": "مهارات الخبراء", + "description": "فعّل سير عمل المهارات المختارة بعناية والمختبرة ميدانيًا لوكلاء البرمجة بالذكاء الاصطناعي. كل خبير هو مهارة مستقلة من مشروع superpowers — يدير codeg النسخة المركزية ويربطها بالوكلاء الذين تختارهم.", + "loading": "جاري تحميل الخبراء…", + "loadingContent": "جاري تحميل المحتوى…", + "emptyExperts": "لا يوجد خبراء متاحون. تحقق من سجلات التطبيق.", + "emptySelection": "اختر خبيرًا لرؤية محتواه وإدارة تفعيله.", + "emptySearch": "لا يوجد خبراء يطابقون البحث الحالي.", + "searchPlaceholder": "ابحث عن الخبراء بالاسم أو المعرّف أو الوصف", + "enableForAgents": "تفعيل للوكلاء", + "noAgents": "لم يتم اكتشاف وكلاء ACP.", + "copyModeWarning": "تم النسخ (غير مرتبط). أعد التفعيل بعد تحديثات codeg للحصول على أحدث إصدار.", + "previewTitle": "معاينة SKILL.md", + "categories": { + "discovery": "الاكتشاف والتصميم", + "planning": "التخطيط", + "execution": "التنفيذ", + "quality": "الجودة والاختبار", + "debugging": "التصحيح", + "review": "المراجعة والدمج", + "meta": "ميتا" + }, + "states": { + "not_linked": "غير مُفعَّل", + "linked_to_codeg": "مُفعَّل", + "linked_elsewhere": "محظور — يوجد رابط آخر", + "blocked_by_real_directory": "محظور — مهارة مخصصة تشغل هذا الاسم", + "broken": "رابط معطوب" + }, + "badges": { + "userModified": "عُدِّل من قبل المستخدم" + }, + "actions": { + "openCentralDir": "فتح المجلد المركزي", + "refresh": "تحديث" + }, + "toasts": { + "loadFailed": "فشل تحميل تفاصيل الخبير", + "enabled": "تم تفعيل الخبير لهذا الوكيل", + "disabled": "تم تعطيل الخبير لهذا الوكيل", + "enableFailed": "فشل تفعيل الخبير", + "disableFailed": "فشل تعطيل الخبير", + "openFolderFailed": "فشل فتح المجلد" + } + }, + "ScienceSettings": { + "title": "مهارات البحث العلمي", + "description": "فعّل مهارات البحث العلمي المنسّقة لوكلاء البرمجة بالذكاء الاصطناعي: توليد الفرضيات، وتصميم التجارب، والإحصاء، والتصور، والتقييم النقدي، والبحث في الأدبيات. يدير codeg نسخة مركزية ويربط كل مهارة بالوكلاء الذين تختارهم.", + "loading": "جارٍ تحميل مهارات البحث العلمي…", + "emptySkills": "لا توجد مهارات بحث علمي متاحة. تحقّق من سجلات التطبيق.", + "searchPlaceholder": "ابحث في مهارات البحث العلمي بالاسم أو المعرّف أو الوصف", + "categories": { + "ideation": "توليد الأفكار", + "design": "تصميم الدراسة", + "analysis": "التحليل", + "visualization": "التصور", + "evaluation": "التقييم", + "literature": "الأدبيات" + }, + "states": { + "not_linked": "غير مُفعَّل", + "linked_to_codeg": "مُفعَّل", + "linked_elsewhere": "محظور — يوجد رابط آخر", + "blocked_by_real_directory": "محظور — مهارة مخصصة تشغل هذا الاسم", + "broken": "رابط معطوب" + }, + "badges": { + "userModified": "عُدِّل من قبل المستخدم", + "needsKey": "يتطلب مفتاحًا", + "needsSetup": "قد يتطلب إعدادًا" + }, + "actions": { + "openCentralDir": "فتح المجلد المركزي", + "refresh": "تحديث" + }, + "toasts": { + "openFolderFailed": "فشل فتح المجلد" + } + }, + "OfficeToolsSettings": { + "title": "أدوات Office", + "description": "إدارة مهارات OfficeCLI لإنشاء ملفات Excel وWord وPowerPoint. قم بتثبيت OfficeCLI ومزامنة المهارات وتفعيلها لكل وكيل.", + "loadingContent": "جارٍ تحميل المحتوى…", + "emptySkills": "لا توجد مهارات متاحة. قم بتثبيت OfficeCLI ومزامنة المهارات.", + "emptySelection": "اختر مهارة لعرض محتواها وإدارة التفعيل.", + "emptySearch": "لا توجد مهارات مطابقة.", + "searchPlaceholder": "البحث بالاسم أو المعرف أو الوصف", + "enableForAgents": "تفعيل للوكلاء", + "noAgents": "لم يتم اكتشاف وكلاء ACP.", + "installFirst": "قم بتثبيت OfficeCLI أولاً لتفعيل المهارات.", + "syncFirst": "قم بمزامنة المهارات أولاً لتحميل المحتوى.", + "noContent": "لا يوجد محتوى متاح.", + "copyModeWarning": "تم النسخ (بدون ربط). أعد المزامنة للحصول على أحدث إصدار.", + "previewTitle": "معاينة SKILL.md", + "detection": { + "installed": "مثبّت", + "notInstalled": "غير مثبّت", + "notRunnable": "مثبّت لكن لا يعمل", + "installHint": "قم بتثبيت OfficeCLI لتفعيل مهارات إنشاء مستندات Office لوكلاء الذكاء الاصطناعي.", + "install": "تثبيت", + "uninstall": "إلغاء التثبيت", + "syncSkills": "مزامنة المهارات" + }, + "categories": { + "general": "عام", + "presentations": "عروض تقديمية", + "documents": "مستندات", + "spreadsheets": "جداول بيانات" + }, + "states": { + "not_linked": "غير مفعّل", + "linked_to_codeg": "مفعّل", + "linked_elsewhere": "محظور — يوجد رابط آخر", + "blocked_by_real_directory": "محظور — مهارة مخصصة تشغل هذا الاسم", + "broken": "رابط معطل" + }, + "badges": { + "notSynced": "غير متزامن" + }, + "actions": { + "refresh": "تحديث" + }, + "toasts": { + "loadFailed": "فشل تحميل تفاصيل المهارة", + "enabled": "تم تفعيل المهارة لهذا الوكيل", + "disabled": "تم تعطيل المهارة لهذا الوكيل", + "enableFailed": "فشل تفعيل المهارة", + "disableFailed": "فشل تعطيل المهارة", + "installSuccess": "تم تثبيت OfficeCLI بنجاح", + "installFailed": "فشل تثبيت OfficeCLI", + "uninstallSuccess": "تم إلغاء تثبيت OfficeCLI", + "uninstallFailed": "فشل إلغاء تثبيت OfficeCLI", + "syncSuccess": "تمت مزامنة {synced} مهارة", + "syncPartial": "تمت مزامنة {synced}، فشلت {errors}", + "syncFailed": "فشل مزامنة المهارات" + }, + "autoPreviewLabel": "فتح المعاينة تلقائيًا", + "autoPreviewHint": "عندما ينشئ وكيل ملف Word أو Excel أو PowerPoint أو يعدّله، افتح معاينته المباشرة تلقائيًا." + }, + "SkillPacksSettings": { + "title": "حزم المهارات", + "description": "حزم مهارات منسّقة يديرها codeg مركزيًا ويربطها بوكلاء الذكاء الاصطناعي لديك — خبراء البرمجة، والبحث العلمي، وأدوات مستندات المكتب. فعّلها لكل وكيل أدناه.", + "tabs": { + "experts": "الخبراء", + "science": "البحث العلمي", + "office": "أدوات المكتب", + "custom": "مخصّصة" + }, + "actions": { + "openCentralDir": "فتح المجلد المركزي", + "refresh": "تحديث" + }, + "toasts": { + "openFolderFailed": "فشل فتح المجلد" + } + }, + "QuickMessagesSettings": { + "title": "رسائل سريعة", + "description": "إدارة مقتطفات الرسائل القابلة لإعادة الاستخدام. اسحب لإعادة الترتيب.", + "loading": "جارٍ تحميل الرسائل السريعة…", + "emptyList": "لا توجد رسائل سريعة بعد. انقر على \"جديد\" لإنشاء واحدة.", + "emptySelection": "اختر رسالة سريعة للتعديل.", + "searchPlaceholder": "ابحث حسب العنوان أو المحتوى", + "untitled": "بدون عنوان", + "actions": { + "new": "جديد", + "save": "حفظ", + "delete": "حذف", + "dragSort": "اسحب لإعادة الترتيب", + "dragSortMessage": "اسحب لإعادة ترتيب الرسالة السريعة: {name}" + }, + "fields": { + "title": "العنوان", + "titlePlaceholder": "أعطِ هذه الرسالة عنوانًا قصيرًا", + "content": "المحتوى", + "contentPlaceholder": "اكتب محتوى الرسالة هنا" + }, + "confirmDelete": { + "title": "حذف الرسالة السريعة؟", + "message": "سيؤدي ذلك إلى حذف \"{name}\" نهائيًا. هل أنت متأكد؟", + "cancel": "إلغاء", + "confirm": "حذف" + }, + "toasts": { + "loadFailed": "فشل تحميل الرسائل السريعة", + "createFailed": "فشل إنشاء الرسالة السريعة", + "saveFailed": "فشل حفظ الرسالة السريعة", + "deleteFailed": "فشل حذف الرسالة السريعة", + "saveOrderFailed": "فشل حفظ الترتيب", + "created": "تم إنشاء الرسالة السريعة", + "saved": "تم حفظ الرسالة السريعة", + "deleted": "تم حذف الرسالة السريعة" + } + }, + "Pet": { + "badge": { + "running": "{count} قيد التشغيل", + "waiting": "{count} في انتظار الموافقة", + "error": "{count} بها خطأ" + }, + "panel": { + "title": "الجلسات النشطة", + "empty": "لا توجد جلسات نشطة", + "emptyHint": "تظهر هنا الوكلاء قيد التشغيل وتلك التي تحتاج إليك.", + "statusRunning": "قيد التشغيل", + "statusWaiting": "في الانتظار", + "statusError": "خطأ", + "subAgentOf": "وكيل فرعي لـ" + }, + "menu": { + "scale": "الحجم", + "openManager": "إدارة الحيوانات الأليفة", + "close": "إغلاق" + }, + "loadError": "فشل تحميل الحيوان الأليف", + "missingPetIdParam": "لم يتم اختيار حيوان أليف", + "summonButton": "حيوان أليف", + "manager": { + "title": "حيوانات سطح المكتب", + "description": "رفقاء عائمون لسطح المكتب باستخدام صفائح سبرايت متوافقة مع Codex.", + "addPet": "إضافة حيوان", + "importFromCodex": "استيراد من Codex", + "noPets": "لا يوجد حيوان أليف. أضف واحدًا أو استورد من Codex.", + "setActive": "تفعيل", + "active": "نشط", + "edit": "تعديل", + "delete": "حذف", + "deleteConfirm": "حذف الحيوان «{name}»؟ سيُحذف من القرص.", + "summon": "استدعاء نافذة الحيوان", + "openCodexHelp": "يجب أن توجد حيوانات Codex داخل ~/.codex/pets/. لم يُعثر على شيء.", + "specRequirement": "يجب أن يكون السبرايت بعرض 1536 بكسل وارتفاع من مضاعفات 208 بكسل (مثل 1872 أو 2288)، بصيغة PNG أو WebP مع شفافية.", + "form": { + "id": "معرف الحيوان", + "idHelp": "حروف صغيرة، أرقام، '-' و '_' فقط. حد أقصى 64 حرفًا.", + "displayName": "اسم العرض", + "description": "الوصف (اختياري)", + "spritesheet": "صفيحة السبرايت", + "chooseFile": "اختر ملفًا", + "replaceFile": "استبدال السبرايت", + "saveCreate": "إضافة الحيوان", + "saveUpdate": "حفظ التغييرات", + "cancel": "إلغاء" + }, + "errors": { + "missingId": "المعرف مطلوب", + "missingName": "الاسم مطلوب", + "missingSpritesheet": "السبرايت مطلوب", + "addFailed": "فشل الإضافة", + "updateFailed": "فشل التحديث", + "deleteFailed": "فشل الحذف", + "loadFailed": "فشل تحميل قائمة الحيوانات", + "setActiveFailed": "فشل تعيين الحيوان النشط", + "summonFailed": "فشل فتح نافذة الحيوان" + } + }, + "import": { + "title": "استيراد من Codex", + "subtitle": "الحيوانات الأليفة المتاحة ضمن ~/.codex/pets/.", + "selectAll": "تحديد الكل", + "alreadyImported": "تم استيراده مسبقًا", + "renameOnConflict": "تسمية المتعارضين بإلحاق -imported", + "import": "استيراد المحدد", + "noneFound": "لا توجد حيوانات Codex قابلة للاستيراد.", + "imported": "تم الاستيراد بنجاح", + "failed": "فشل الاستيراد", + "close": "إغلاق" + }, + "marketplace": { + "openMarketplace": "متجر الحيوانات الأليفة", + "title": "متجر الحيوانات الأليفة", + "search": "ابحث عن حيوان أليف", + "kindFilter": { + "all": "الكل", + "object": "كائن", + "animal": "حيوان", + "person": "شخصية", + "creature": "مخلوق" + }, + "sortFilter": { + "latest": "الأحدث", + "popular": "الأكثر شيوعاً", + "views": "الأكثر مشاهدة" + }, + "refresh": "تحديث", + "install": "تثبيت", + "installing": "جاري التثبيت", + "reinstall": "إعادة التثبيت", + "reinstallConfirm": "هل تريد استبدال الحيوان الأليف المحلي \"{name}\"؟ ستُستبدل البيانات الحالية.", + "cancel": "إلغاء", + "stats": { + "views": "المشاهدات", + "downloads": "التنزيلات", + "likes": "الإعجابات" + }, + "actions": { + "idle": "خامل", + "running_right": "ركض يمين", + "running_left": "ركض يسار", + "waving": "تلويح", + "jumping": "قفز", + "failed": "فشل", + "waiting": "انتظار", + "running": "ركض", + "review": "مراجعة" + }, + "page": "صفحة {page} من {total}", + "prev": "السابق", + "next": "التالي", + "empty": "لا يوجد حيوان أليف مطابق.", + "successInstalled": "تم تثبيت \"{name}\"", + "errors": { + "loadFailed": "تعذّر تحميل المتجر", + "installFailed": "فشل التثبيت", + "alreadyInstalled": "هذا الحيوان موجود بالفعل" + } + } + }, + "RemoteWorkspace": { + "openRemoteWorkspace": "Open remote workspace", + "manage": "Manage remote workspace", + "manageTitle": "Remote Workspace connections", + "empty": "No remote connections", + "searchPlaceholder": "Search remote workspaces", + "orderFailed": "Failed to save remote workspace order", + "dragSort": "Drag to sort", + "dragSortConnection": "Drag to sort {name}", + "newConnection": "New connection", + "loading": "Loading", + "loadingConnection": "Loading remote connection", + "name": "Name", + "baseUrl": "Service URL", + "token": "Access token", + "save": "Save", + "delete": "Delete", + "confirmDelete": { + "title": "Delete remote connection?", + "message": "This will remove \"{name}\" from this device. This action cannot be undone.", + "cancel": "Cancel", + "confirm": "Delete" + }, + "saved": "Remote connection saved.", + "deleted": "Remote connection deleted.", + "loadFailed": "Failed to load remote connections", + "saveFailed": "Failed to save remote connection", + "deleteFailed": "Failed to delete remote connection", + "openFailed": "Failed to open remote workspace", + "connectionLoadFailed": "Failed to load remote connection: {message}", + "connectionExpired": "Remote connection \"{name}\" is expired. Update its token and reload this window." + }, + "ServerFileBrowser": { + "title": "اختر ملفًا من الخادم", + "pathPlaceholder": "أدخل مسار الدليل...", + "goHome": "اذهب إلى المجلد الرئيسي", + "navigateUp": "اذهب إلى المجلد الأعلى", + "select": "اختر", + "cancel": "إلغاء", + "loading": "جارٍ التحميل...", + "emptyDirectory": "هذا المجلد فارغ", + "errorLoadingDir": "فشل تحميل المجلد", + "selectedCount": "{count} محدد" + }, + "BackupSettings": { + "title": "النسخ الاحتياطي والاستعادة", + "description": "صدّر نسخة احتياطية محمولة من بيانات codeg، أو استعد من نسخة.", + "tabs": { + "backup": "نسخ احتياطي", + "restore": "استعادة" + }, + "export": { + "includeExternal": "تضمين محتوى المحادثات", + "includeExternalHint": "يؤرشف أيضًا سجلات محادثات أدوات CLI (Claude وCodex وGemini …). يزيد الحجم.", + "passphrase": "عبارة المرور (اختياري)", + "passphrasePlaceholder": "اتركها فارغة للحصول على أرشيف غير مشفّر", + "passphraseConfirm": "تأكيد عبارة المرور", + "passphraseMismatch": "عبارتا المرور غير متطابقتين.", + "noPassphraseWarning": "ستحتوي هذه النسخة على أسرار (مفاتيح API والرموز) بنص واضح. احفظها في مكان آمن.", + "passphraseLossWarning": "مشفّرة بعبارة المرور هذه. إذا فقدتها، فلن يمكن استعادة النسخة الاحتياطية.", + "button": "تصدير النسخة الاحتياطية", + "inProgress": "جارٍ إنشاء النسخة الاحتياطية…", + "success": "تم إنشاء النسخة الاحتياطية.", + "started": "بدأ تنزيل النسخة الاحتياطية." + }, + "restore": { + "selectFile": "اختر ملف النسخة الاحتياطية", + "passphrasePrompt": "هذه النسخة مشفّرة. أدخل عبارة المرور الخاصة بها.", + "unlock": "فتح القفل", + "preview": { + "title": "تفاصيل النسخة الاحتياطية", + "encrypted": "مشفّرة", + "compatible": "متوافقة", + "incompatible": "غير متوافقة", + "createdAt": "أُنشئت: {value}", + "appVersion": "إصدار التطبيق: {value}", + "incompatibleHint": "أُنشئت هذه النسخة بإصدار أحدث من codeg ولا يمكن استعادتها." + }, + "replaceWarning": "تستبدل الاستعادة جميع بيانات codeg الحالية (قاعدة البيانات والملفات المرفوعة). تُلتقط بياناتك الحالية كلقطة أولًا حتى يمكن استرجاعها.", + "keyringNote": "تُخزَّن رموز GitHub/الدردشة لتطبيق سطح المكتب في سلسلة مفاتيح النظام ولا تُضمَّن؛ أعد إدخالها بعد الاستعادة.", + "button": "استعادة", + "staging": "جارٍ تجهيز الاستعادة…", + "staged": "تم تجهيز الاستعادة. جارٍ إعادة التشغيل…", + "restarting": "تم تجهيز الاستعادة. جارٍ إعادة تشغيل الخادم…", + "restartTimeout": "لم يعد الخادم في الوقت المحدد. أعد تحميل الصفحة بعد تشغيله.", + "externalSideLocation": "تمت استعادة سجلات المحادثات إلى {path}", + "confirmTitle": "استبدال جميع البيانات؟", + "confirmBody": "سيؤدي ذلك إلى استبدال قاعدة بيانات codeg والملفات المرفوعة الحالية بالنسخة الاحتياطية ثم إعادة التشغيل. تُلتقط بياناتك الحالية كلقطة أولًا.", + "cancel": "إلغاء", + "confirmAction": "استبدال وإعادة تشغيل", + "external": { + "title": "محتوى المحادثات", + "hint": "تتضمن هذه النسخة سجلات محادثات أدوات CLI. اختر مكان استعادتها.", + "modeSkip": "عدم الاستعادة", + "modeSide": "الاستعادة إلى مجلد جانبي آمن", + "modeOriginal": "الاستعادة إلى المواقع الأصلية لأدوات CLI", + "forceOverwrite": "الكتابة فوق الملفات الموجودة", + "forceOverwriteHint": "استبدال الملفات الموجودة بالفعل في مجلدات أدوات CLI.", + "scanning": "جارٍ التحقق من التعارضات…", + "noConflicts": "لن تتم الكتابة فوق أي ملف موجود.", + "conflictCount": "سيتأثر {count} من الملفات الموجودة.", + "conflictSkipNote": "تُحفظ الملفات الموجودة (تُتخطى) ما لم تفعّل الكتابة فوقها." + }, + "restartFailed": "تم تجهيز الاستعادة، لكن تعذّر إعادة تشغيل الخادم. أعد تشغيله يدويًا لتطبيقها." + }, + "remoteUnsupported": "يعمل النسخ الاحتياطي والاستعادة على بيانات الجهاز الذي يشغّل codeg. أنت متصل بمساحة عمل بعيدة — أدِر نسخها الاحتياطية من ذلك الخادم مباشرة." + }, + "backup": { + "restore": { + "error": { + "badPassphrase": "عبارة المرور غير صحيحة أو النسخة الاحتياطية تالفة.", + "corrupted": "أرشيف النسخة الاحتياطية تالف.", + "unknownFormat": "هذا الملف ليس نسخة احتياطية معروفة من codeg.", + "newerVersion": "أُنشئت هذه النسخة بواسطة codeg {backupVersion}، وهي أحدث من هذا الإصدار ({appVersion}).", + "alreadyPending": "توجد استعادة مُجهّزة بالفعل. أعد التشغيل لتطبيقها قبل تجهيز أخرى." + } + }, + "error": { + "diskSpace": "لا توجد مساحة قرص كافية لإكمال العملية.", + "cancelled": "تم إلغاء العملية." + } + }, + "WebConnection": { + "disconnectedTitle": "انقطع الاتصال", + "reconnectingDescription": "تتم محاولة إعادة الاتصال بالخادم. عادةً ما يُستعاد الاتصال تلقائيًا خلال ثوانٍ قليلة.", + "reconnectNow": "إعادة الاتصال الآن", + "sessionExpiredTitle": "انتهت الجلسة", + "sessionExpiredDescription": "لم تعد جلستك صالحة. يُرجى تسجيل الدخول مرة أخرى للمتابعة.", + "goToLogin": "الانتقال إلى تسجيل الدخول" + }, + "LiveFeedback": { + "placeholder": "أرسل ملاحظة إلى {agent} أثناء عمله…", + "agentFallback": "الوكيل", + "ariaLabel": "ملاحظة مباشرة", + "dialogTitle": "ملاحظات مباشرة", + "dialogDescription": "أرسل ملاحظة إلى الوكيل أثناء عمله. سيقرأها في فحصه التالي دون مقاطعة الخطوة الحالية.", + "dialogDescriptionInstant": "أرسل ملاحظة إلى الوكيل أثناء عمله. تُدرج الملاحظة فورًا في الدور الحالي — يراها الوكيل على الفور.", + "channelDowngraded": "الإدراج الفوري غير متاح في هذه الجلسة — حُفظت ملاحظتك ليقرأها الوكيل عند فحصه التالي.", + "send": "إرسال", + "cancel": "إلغاء", + "pending": "في الانتظار", + "delivered": "تم الاستلام", + "turnEndedUnread": "أنهى الوكيل الجولة قبل قراءة ملاحظاتك.", + "sendAsMessage": "إرسال كرسالة", + "dismiss": "تجاهل", + "turnEndedResent": "انتهت الجولة — تم الإرسال كرسالة جديدة بدلاً من ذلك.", + "turnEnded": "انتهت الجولة بالفعل.", + "submitFailed": "تعذّر إرسال ملاحظتك" + }, + "AgentToolsSettings": { + "title": "أدوات داخل المحادثة", + "description": "أدوات إضافية يمنحها codeg للوكيل داخل المحادثة. تُحقن عند بدء تشغيل الوكيل، لذا يسري أي تغيير على الوكلاء الذين يبدأون بعده.", + "feedbackLabel": "ملاحظات مباشرة", + "feedbackHint": "أرسل ملاحظات وتصحيحات إلى الوكيل أثناء عمله. إذا كان الوكيل يدعم الإدراج الفوري، تُدرج ملاحظتك فورًا في الدور الجاري؛ وإلا يحصل الوكيل على أداة للاطلاع على ملاحظاتك — وهؤلاء الوكلاء عادةً لا يتحققون منها إلا إذا ذكرت ذلك في الموجّه، مثلًا أضف \"تحقق من ملاحظاتي المباشرة بانتظام\" إلى رسالتك.", + "questionLabel": "سؤال المستخدم", + "questionHint": "يسمح للوكلاء بالتوقّف وطرح سؤال متعدّد الخيارات يظهر فوق مربّع إدخال المحادثة. ينتظر الوكيل حتى تجيب (أو تتخطّى).", + "sessionInfoLabel": "الحصول على معلومات الجلسة", + "sessionInfoHint": "يتيح للوكلاء البحث عن جلسة تشير إليها في رسالتك (شارة جلسة) لقراءة عنوانها والوكيل والحالة ومساحة العمل واستهلاك الرموز وأحدث الرسائل.", + "automationsLabel": "إنشاء الأتمتة", + "automationsHint": "يحفظ المحادثة كأتمتة تعمل وفق جدول زمني. مُعطّل افتراضيًا — إذ تبدأ بعد ذلك تشغيل الوكلاء من تلقاء نفسها.", + "workTasksLabel": "إنشاء مهام قيد الانتظار", + "workTasksHint": "يضيف بطاقة إلى لوحة المهام انطلاقًا من المحادثة. مُعطّل افتراضيًا — لأنه يكتب حالة التطبيق.", + "save": "حفظ", + "saving": "جارٍ الحفظ…", + "saved": "تم حفظ إعدادات الأدوات", + "saveFailed": "تعذّر حفظ إعدادات الأدوات", + "loadFailed": "فشل التحميل: {detail}" + }, + "NotificationSoundSettings": { + "title": "أصوات التنبيه", + "description": "تشغيل صوت قصير عند وقوع حدث للوكيل. هي نفس الأحداث التي تُرسل إلى قنوات المحادثة، وهذا الإعداد يخص هذا الجهاز فقط.", + "enableHint": "معطّل افتراضيًا. تُشغَّل الأصوات في نافذة مساحة العمل بهذا المتصفح أو التطبيق فقط.", + "volume": "مستوى الصوت", + "preview": "استماع", + "previewEvent": "استماع لصوت {event}", + "onlyWhenUnfocused": "فقط عندما تكون النافذة غير نشطة", + "onlyWhenUnfocusedHint": "يبقى صامتًا أثناء استخدامك لـ Codeg.", + "eventsTitle": "الأحداث", + "eventsHint": "اختر نغمة لكل حدث، أو «صامت» لتجاهله. إذا تكرر الحدث نفسه خلال ثوانٍ قليلة فسيُشغَّل مرة واحدة فقط.", + "toneNone": "صامت", + "toneChime": "رنين", + "toneDing": "جرس", + "toneBlip": "نبضة", + "tonePop": "طقّة", + "toneAlert": "تنبيه", + "toneDescend": "نغمة هابطة" + }, + "LogsSettings": { + "loading": "جارٍ التحميل…", + "sectionTitle": "سجلات التشغيل", + "sectionDescription": "عرض وتكوين سجلات تشخيص التطبيق. تُكتب السجلات في ملفات محلية وتُحفظ في الذاكرة للعرض المباشر.", + "captureTitle": "مستوى السجل", + "captureDescription": "يتحكم في مقدار التفاصيل الملتقطة. المستويات الأعلى (Debug، Trace) تسجل المزيد لكنها تنتج سجلات أكبر. «إيقاف» يعطّل التسجيل.", + "captureLabel": "مستوى الالتقاط", + "levels": { + "off": "إيقاف", + "error": "خطأ", + "warn": "تحذير", + "info": "معلومات", + "debug": "تصحيح", + "trace": "تتبع" + }, + "viewerTitle": "السجلات الأخيرة", + "viewerDescription": "عرض مباشر لأحدث السجلات. قم بالتصفية حسب المستوى أو ابحث في النص.", + "searchPlaceholder": "ابحث في الرسالة أو المصدر…", + "viewLevels": { + "all": "كل المستويات", + "error": "خطأ فأعلى", + "warn": "تحذير فأعلى", + "info": "معلومات فأعلى", + "debug": "تصحيح فأعلى", + "trace": "تتبع فأعلى" + }, + "pause": "إيقاف مؤقت", + "resume": "مباشر", + "refresh": "تحديث", + "clear": "مسح", + "openFolder": "فتح المجلد", + "shownCount": "{shown} / {total} معروض", + "empty": "لا توجد سجلات للعرض.", + "levelSaveFailed": "فشل حفظ مستوى السجل", + "openFolderFailed": "فشل فتح مجلد السجلات", + "downloadFailed": "فشل تنزيل ملف السجل", + "filesTitle": "ملفات السجل", + "filesDescription": "نزّل ملفات السجل الكاملة من القرص للاطلاع على السجل خارج المخزن المباشر.", + "filesEmpty": "لا توجد ملفات سجل بعد.", + "download": "تنزيل", + "downloadTruncated": "الملف كبير، تم تنزيل أحدث {size}. الملف الكامل موجود في دليل السجلات.", + "captureEnvLocked": "يتم التحكم في مستوى السجل عبر متغير البيئة RUST_LOG / CODEG_LOG؛ غيّره هناك ليصبح ساريًا.", + "targetsTitle": "تجاوزات حسب الوحدة", + "targetsDescription": "عيّن مستوى مختلفًا لوحدات محددة (مثل codeg_lib::acp) دون تغيير المستوى العام.", + "targetsAdd": "إضافة", + "targetsRemove": "إزالة التجاوز", + "toggleDetails": "تبديل التفاصيل" + }, + "Automations": { + "title": "الأتمتة", + "new": "أتمتة جديدة", + "empty": "لا توجد أتمتة بعد", + "emptyHint": "أنشئ واحدة لتشغيل مهمة الوكيل وفق جدول أو يدويًا.", + "name": "الاسم", + "namePlaceholder": "مثال: مراجعة PR الليلية", + "prompt": "الموجّه", + "promptPlaceholder": "ماذا يجب أن يفعل الوكيل؟", + "agent": "الوكيل", + "folder": "مجلد مساحة العمل", + "folderPlaceholder": "اختر مجلدًا", + "isolation": "العزل", + "isolationWorktree": "worktree جديد لكل تشغيل", + "isolationShared": "التشغيل داخل المجلد", + "isolationSharedCaveat": "تستخدم عمليات التشغيل شجرة عمل هذا المجلد مباشرةً، وقد تتعارض مع تغييراتك غير المُلتزَم بها. فعِّل خيار شجرة العمل لعزل كل عملية تشغيل.", + "trigger": "المُشغِّل", + "triggerSchedule": "وفق جدول", + "triggerManual": "يدوي فقط", + "cron": "الجدولة (cron)", + "cronPlaceholder": "0 9 * * 1-5", + "timezone": "المنطقة الزمنية", + "nextRun": "التشغيل التالي", + "branch": "الفرع", + "branchOptional": "الفرع (اختياري)", + "enabled": "مُفعّل", + "save": "حفظ", + "cancel": "إلغاء", + "edit": "تعديل", + "delete": "حذف", + "runNow": "تشغيل الآن", + "cancelRun": "إلغاء التشغيل", + "runHistory": "سجل التشغيل", + "noRuns": "لا توجد عمليات تشغيل بعد", + "allFolders": "كل المجلدات", + "filterAll": "الكل", + "noMatches": "لا توجد أتمتة مطابقة", + "viewConversation": "عرض المحادثة", + "lastRun": "آخر تشغيل", + "never": "أبدًا", + "running": "قيد التشغيل", + "deleteTitle": "حذف الأتمتة؟", + "deleteDescription": "يؤدي هذا إلى إزالة الأتمتة وجدولها. يُحتفظ بسجل التشغيل.", + "statusRunning": "قيد التشغيل", + "statusSucceeded": "نجحت", + "statusFailed": "فشلت", + "statusCancelled": "أُلغيت", + "statusSkipped": "تم تخطيها", + "errorName": "الاسم مطلوب", + "errorPrompt": "الموجّه مطلوب", + "errorCron": "تتطلب الأتمتة المجدولة تعبير cron", + "errorFolder": "اختر مجلد مساحة العمل", + "presetHourly": "كل ساعة", + "presetDaily": "يوميًا 9 صباحًا", + "presetWeekdays": "أيام العمل 9 صباحًا", + "presetCustom": "مخصص", + "probing": "جارٍ تحميل الخيارات…", + "retry": "إعادة المحاولة", + "configNone": "لا توجد خيارات قابلة للضبط لهذا الوكيل", + "inherit": "افتراضي الوكيل", + "mode": "الوضع", + "config": "الإعدادات", + "branchPlaceholder": "(الفرع الافتراضي)", + "selectHint": "اختر أتمتة لعرض التفاصيل", + "refresh": "تحديث", + "onboardTitle": "أتمتة مهام الوكيل الروتينية", + "onboardHint": "اجدول وكيلًا لمراجعة الشيفرة أو تحديث الاعتماديات أو فرز المشكلات، وفق جدول زمني أو عند الطلب.", + "headerSubtitle": "مهام الوكيل المجدولة وعند الطلب", + "startFromTemplate": "ابدأ من قالب", + "blankTitle": "أتمتة فارغة", + "blankDesc": "اضبط مهمة وكيل من البداية.", + "backToTemplates": "القوالب", + "sectionSchedule": "الجدولة والهدف", + "sectionTarget": "الهدف", + "sectionAction": "الإجراء", + "actionLaunchSession": "تشغيل جلسة", + "actionEnqueueTask": "إضافة مهمة إلى قائمة الانتظار", + "actionEnqueueTaskHint": "عند كل تشغيل تُضاف مهمة قيد الانتظار تحمل اسم هذه الأتمتة إلى المهام قيد الانتظار للمجلد، وينفذها محرك المهام وفق إعدادات اللوحة.", + "sectionPrompt": "الموجّه", + "nextIn": "التالي خلال {rel}", + "manual": "يدوي", + "schedEveryMinutes": "كل {n} دقيقة", + "schedHourly": "كل ساعة", + "schedDaily": "يوميًا في {time}", + "schedWeekdays": "أيام العمل في {time}", + "schedWeekly": "كل {day} في {time}", + "schedMonthly": "شهريًا في اليوم {day} عند {time}", + "dow0": "الأحد", + "dow1": "الاثنين", + "dow2": "الثلاثاء", + "dow3": "الأربعاء", + "dow4": "الخميس", + "dow5": "الجمعة", + "dow6": "السبت", + "tplCodeReviewTitle": "مراجعة الشيفرة", + "tplCodeReviewDesc": "يراجع التغييرات الأخيرة بحثًا عن الأخطاء والانحدارات ومشكلات الجودة.", + "tplDependencyUpdatesTitle": "تحديث الاعتماديات", + "tplDependencyUpdatesDesc": "يعثر على الاعتماديات القديمة ويقترح ترقيات آمنة.", + "tplTestCoverageTitle": "تغطية الاختبارات", + "tplTestCoverageDesc": "يعثر على مسارات الشيفرة غير المختبرة ويضيف الاختبارات الناقصة.", + "tplTodoSweepTitle": "تجميع مهام TODO", + "tplTodoSweepDesc": "يجمع تعليقات TODO وFIXME ويفرزها حسب الأولوية.", + "tplCiTriageTitle": "فرز CI", + "tplCiTriageDesc": "يحقق في الفحوصات الفاشلة الأخيرة ويقترح إصلاحات.", + "tplReleaseNotesTitle": "ملاحظات الإصدار", + "tplReleaseNotesDesc": "يلخّص التغييرات منذ الإصدار الأخير في سجل تغييرات.", + "tplSecurityAuditTitle": "تدقيق الأمان", + "tplSecurityAuditDesc": "يفحص الثغرات والأنماط الخطرة ثم يبلّغ عن النتائج.", + "enable": "تفعيل", + "disable": "تعطيل", + "moreActions": "إجراءات إضافية", + "statusDisabled": "معطّلة", + "cronBuilderTitle": "منشئ الجدولة", + "cronFreqLabel": "التكرار", + "cronFreqMinutes": "كل N دقيقة", + "cronFreqHourly": "كل ساعة", + "cronFreqDaily": "يوميًا", + "cronFreqWeekdays": "أيام الأسبوع", + "cronFreqWeekly": "أسبوعيًا", + "cronFreqMonthly": "شهريًا", + "cronFreqCustom": "مخصص", + "cronEveryLabel": "الفاصل (دقائق)", + "cronTimeLabel": "الوقت", + "cronHourLabel": "الساعة", + "cronMinuteLabel": "الدقيقة", + "cronDowLabel": "يوم الأسبوع", + "cronDomLabel": "يوم الشهر", + "cronApply": "تطبيق", + "cronPreviewLabel": "معاينة", + "cronOpenBuilder": "فتح منشئ الجدولة", + "branchDefault": "الفرع الافتراضي", + "branchUseCustom": "استخدام \"{query}\"", + "branchLocal": "محلي", + "branchRemote": "بعيد", + "branchSearchPlaceholder": "بحث في الفروع…", + "branchNone": "لا توجد فروع" + }, + "Tasks": { + "title": "المهام قيد الانتظار", + "new": "مهمة جديدة", + "empty": "لا توجد مهام بعد", + "emptyHint": "أضف مهمة ثم شغّلها — يعمل الوكيل في worktree معزول، وتراجع النتيجة وتدمجها.", + "emptyColTodo": "لا توجد مهام قيد الانتظار بعد", + "emptyColInProgress": "لا توجد مهام قيد التنفيذ", + "emptyColAttention": "لا توجد مهام بانتظارك", + "emptyColDone": "لا توجد مهام مكتملة بعد", + "allFolders": "كل المجلدات", + "showCanceled": "إظهار الملغاة", + "showArchived": "إظهار المؤرشفة", + "filter": "تصفية", + "viewSwitchToBoard": "التبديل إلى عرض اللوحة", + "viewSwitchToList": "التبديل إلى عرض القائمة", + "statusFilter": "الحالة", + "statusFilterAll": "كل الحالات", + "listEmpty": "لا توجد مهام مطابقة لعوامل التصفية الحالية", + "listColStatus": "الحالة", + "listColTask": "المهمة", + "listColLocation": "الموقع", + "listColChanges": "التغييرات", + "listColUpdated": "آخر تحديث", + "colTodo": "قيد الانتظار", + "colInProgress": "قيد التنفيذ", + "colAttention": "بانتظارك", + "colDone": "مكتملة", + "statusTodo": "قيد الانتظار", + "statusQueued": "في قائمة الانتظار", + "statusPreparing": "قيد التهيئة", + "statusRunning": "قيد التنفيذ", + "statusAwaitingInput": "بانتظار الإدخال", + "statusReview": "بانتظار المراجعة", + "statusMerging": "جارٍ الدمج", + "statusDone": "مكتملة", + "statusFailed": "فشلت", + "statusCanceled": "ملغاة", + "statusInterrupted": "توقّفت", + "badgeCleanupFailed": "فشل التنظيف", + "badgeWorktreeKept": "تم الإبقاء على worktree", + "badgeWorktreeRemoved": "تمت إزالة worktree", + "filesChanged": "{count} ملفات", + "actionStart": "بدء", + "actionSchedule": "جدولة", + "actionCancel": "إلغاء", + "actionRetry": "إعادة المحاولة", + "actionRequeue": "إعادة الإدراج", + "actionViewSession": "عرض المحادثة", + "actionEdit": "تحرير", + "actionDelete": "حذف", + "actionRetryCleanup": "إعادة محاولة التنظيف", + "actionMerge": "دمج", + "actionUnqueueMerge": "مغادرة طابور الدمج", + "actionEditQueuedMerge": "تعديل الدمج المنتظر", + "badgeMergeQueued": "في طابور الدمج", + "badgeMergeQueuedRank": "في طابور الدمج · رقم {rank}", + "badgeMergeQueuedHint": "في انتظار انتهاء الدمج الجاري لهذا المشروع، وسيبدأ هذا تلقائيًا عند دوره.", + "actionComplete": "إنهاء", + "actionAbandon": "تخلٍّ", + "cancelTitle": "إلغاء المهمة؟", + "cancelDescription": "ستصبح المهمة ملغاة. يُحتفظ بـ worktree الخاصة بها ويمكنك إعادة إدراجها لاحقًا.", + "cancelReasonLabel": "السبب (اختياري)", + "cancelReasonPlaceholder": "مثلاً: النهج خاطئ، سأعيد كتابة الوصف", + "cancelKeep": "تراجع", + "cancelSubmit": "إلغاء المهمة", + "restartTitleRetry": "إعادة محاولة المهمة", + "restartTitleRequeue": "إعادة إدراج المهمة", + "restartDescription": "يمكنك إضافة ملاحظة (اختيارية) تصل إلى موجّه التشغيل التالي.", + "scheduleTitle": "جدولة المهمة", + "scheduleDescription": "تبقى المهمة في قائمة الانتظار وتبدأ تلقائيًا في الوقت الذي تحدده. ويظل حد التنفيذ المتزامن للمجلد ساريًا.", + "scheduleDateLabel": "التاريخ", + "schedulePickDate": "اختر التاريخ", + "scheduleTimeLabel": "الوقت", + "schedulePreview": "يبدأ في {time}", + "schedulePastHint": "لقد مضى هذا الوقت — ستبدأ المهمة فور الحفظ.", + "scheduleInAnHour": "بعد ساعة", + "scheduleInThreeHours": "بعد 3 ساعات", + "scheduleTomorrow": "غدًا 9:00", + "scheduleClear": "إلغاء الجدولة", + "scheduleBadge": "بدء مجدول في {time}", + "toastScheduled": "تمت الجدولة في {time}", + "toastScheduleCleared": "تم إلغاء الجدولة", + "actionFollowUp": "متابعة", + "actionAddNote": "إضافة ملاحظة", + "followUpSubmit": "إرسال", + "followUpIntentRevise": "إعادة العمل", + "followUpIntentContinue": "المتابعة", + "followUpIntentQuestion": "طرح سؤال", + "followUpIntentVerify": "مراجعة ذاتية", + "followUpPlaceholderRevise": "ما الذي يجب أن يغيّره الوكيل؟ سيتابع في الجلسة نفسها.", + "followUpPlaceholderContinue": "ما التالي؟ سيبقى العمل المنجز كما هو.", + "followUpPlaceholderQuestion": "ما الذي تريد معرفته؟ سيجيب الوكيل دون تعديل أي ملف.", + "followUpPlaceholderVerify": "اختياري: هل من شيء ينبغي فحصه بعناية؟", + "followUpPlaceholderRetry": "اختياري: ما الذي ينبغي فعله بشكل مختلف؟ مثلاً: شغّل pnpm install أولاً", + "followUpPlaceholderRequeue": "اختياري: لماذا ألغيتها، وما الذي يجب أن يتغيّر هذه المرة؟", + "actionArchive": "أرشفة", + "actionUnarchive": "إلغاء الأرشفة", + "archiveAllDone": "أرشفة الكل", + "dropToStart": "أفلِت للبدء", + "errorView": "عرض", + "notifyReview": "جاهزة للمراجعة: {title}", + "notifyFailed": "فشلت المهمة: {title}", + "createFromMessage": "إنشاء مهمة من الرسالة", + "detailTokens": "إجمالي الرموز", + "editorTitleNew": "مهمة جديدة", + "editorTitleEdit": "تحرير المهمة", + "templates": "القوالب", + "templatesEmpty": "لا توجد قوالب بعد.", + "templateSaveCurrent": "حفظ المحتوى الحالي كقالب", + "templateDelete": "حذف القالب", + "transcriptTitle": "محادثة المهمة", + "transcriptDescription": "عرض مباشر للقراءة فقط لجلسة وكيل المهمة.", + "phaseWork": "تنفيذ المهمة", + "phaseRetry": "إعادة التنفيذ", + "phaseReturn": "متابعة", + "phaseMerge": "الدمج", + "titleLabel": "العنوان", + "titlePlaceholder": "ما الذي يجب إنجازه؟", + "promptLabel": "وصف المهمة", + "promptPlaceholder": "صف المهمة للوكيل — استخدم @ للإشارة إلى الملفات و / للأوامر", + "folderPlaceholder": "اختر مجلدًا", + "agentInheritedHint": "موروث من إعدادات المهام — عدِّله ليصبح خاصًا بهذه المهمة", + "agentOverrideReset": "العودة إلى الوراثة", + "sectionTarget": "الهدف", + "errorTitle": "العنوان مطلوب", + "errorPrompt": "وصف المهمة مطلوب", + "errorFolder": "اختر مجلدًا", + "save": "حفظ", + "cancel": "إلغاء", + "mergeTitle": "دمج المهمة", + "mergeQueuedTitle": "دمج في الطابور", + "mergeQueueHint": "تجري الآن عملية دمج لمهمة أخرى في هذا المشروع. ستنضم هذه المهمة إلى الطابور وتبدأ تلقائيًا فور انتهاء تلك العملية.", + "mergeQueueUpdateHint": "هذه المهمة تنتظر الدمج بالفعل. الإرسال يحدّث خياراتها ويحتفظ بمكانها في الطابور.", + "mergeDescription": "دمج {branch} في {base}. تُرسل التغييرات غير المثبتة في worktree أولًا.", + "mergeMessage": "رسالة الالتزام", + "mergeMessagePlaceholder": "مثال: feat: add login validation", + "mergeAutoMessage": "دع الوكيل يكتب رسالة الإيداع", + "strategySquash": "دمج في التزام واحد", + "strategySquashHint": "تصل جميع تغييرات المهمة إلى الفرع الرئيسي كسجل واحد — تاريخ أكثر ترتيبًا.", + "strategyMerge": "الاحتفاظ بالتاريخ الكامل", + "strategyMergeHint": "يُحتفظ بكل التزام أُنشئ أثناء المهمة، مع إضافة سجل دمج واحد — تبقى كل خطوة قابلة للتتبع.", + "mergeDeleteWorktree": "حذف worktree بعد الدمج", + "mergeSubmit": "دمج", + "mergeSubmitQueue": "إضافة إلى طابور الدمج", + "mergeQueuedToast": "تمت الإضافة إلى طابور الدمج — سيبدأ فور انتهاء الدمج الحالي.", + "completeTitle": "إنهاء المهمة", + "completeDescription": "لم تغيّر هذه المهمة أي ملف، لذا لا يوجد ما يُدمج — سيتم وضع علامة مكتملة عليها مباشرة.", + "completeDescriptionNoWorktree": "تمت إزالة worktree هذه المهمة، فلم يعد الدمج ممكنًا — سيتم وضع علامة مكتملة عليها مباشرة. يُحتفظ بفرع العمل إذا كان لا يزال يحوي إيداعات غير مدمجة.", + "completeDeleteWorktree": "حذف worktree بعد الإنهاء", + "completeSubmit": "إنهاء", + "settingsTitle": "إعدادات المهام", + "settingsDescription": "الإعدادات الافتراضية لمهام {folder}.", + "settingsScope": "النطاق", + "settingsScopeGlobal": "كل المجلدات (الإعدادات العامة)", + "settingsScopeGlobalHint": "المجلدات بلا إعدادات خاصة تستخدم هذه الإعدادات العامة.", + "settingsSource": "مصدر الإعدادات", + "settingsSourceGlobal": "الإعدادات العامة", + "settingsSourceCustom": "إعداد خاص", + "settingsSourceGlobalFollow": "يتبع إعدادات المهام العامة — التغييرات هناك تسري هنا تلقائيًا.", + "settingsSourceCustomHint": "يحفظ إعدادات خاصة بهذا المجلد ويتوقف عن اتباع الإعدادات العامة.", + "settingsAgent": "الوكيل الافتراضي", + "settingsMaxConcurrent": "أقصى عدد للمهام المتزامنة", + "settingsMaxConcurrentHint": "0 = بلا حد", + "settingsAutoProcess": "معالجة تلقائية", + "settingsAutoProcessHint": "تبدأ المهام المعلّقة تلقائيًا ضمن حد التنفيذ المتزامن.", + "settingsMergeStrategy": "استراتيجية الدمج الافتراضية", + "settingsMergeStrategyHint": "كيفية تسجيل تغييرات المهمة في تاريخ الفرع عند الدمج.", + "settingsAutoMerge": "دمج تلقائي", + "settingsAutoMergeHint": "المهمة التي تصل إلى المراجعة وفيها تغييرات قابلة للدمج تُدمج كما لو نقرت «دمج»: يكتب الوكيل رسالة الإيداع، ويتبع الـ worktree الإعداد الافتراضي أدناه. أما المهمة التي فشل فحصها المسبق أو فشل دمجها فتبقى بانتظارك.", + "settingsDeleteWorktree": "حذف الـ worktree بعد الدمج", + "settingsDeleteWorktreeHint": "يُفعّل الخيار مسبقًا في نافذة الدمج، ويمكنك تغييره هناك.", + "settingsWorktreeRoot": "موقع الـ worktree", + "settingsWorktreeRootHint": "المجلد الذي تُنشأ فيه worktrees المهام الجديدة، واحدة لكل مهمة. اتركه فارغًا لإنشائها بجوار مجلد المشروع؛ «~» هو مجلد المنزل، والمسار النسبي يُحسب انطلاقًا من مجلد المشروع.", + "settingsWorktreeRootPlaceholder": "~/codeg-worktrees", + "settingsWorktreeRootBrowse": "اختيار مجلد الـ worktree", + "settingsPreflight": "أمر الفحص المسبق", + "settingsPreflightHint": "يعمل في شجرة العمل عندما تصل المهمة إلى المراجعة.", + "settingsPreflightCustomPlaceholder": "pnpm test", + "settingsInitCommand": "أمر تهيئة worktree", + "settingsInitCommandHint": "يعمل داخل worktree جديد قبل بدء الوكيل.", + "settingsInitCommandPlaceholder": "pnpm install", + "settingsTabGeneral": "عام", + "settingsTabMerge": "الدمج", + "settingsTabWorktree": "Worktree", + "settingsTabPrompts": "التوجيهات", + "settingsPromptsIntro": "لكل مرحلة موجّه مدمج بالفعل — المهمة نفسها، وقواعد شجرة العمل، وخطوات git الدقيقة عند الدمج. وما تضيفه هنا يُلحَق في النهاية كتعليمات إضافية: فهو يُهذّب النص المدمج ولا يستبدله أبدًا.", + "settingsPromptStageAll": "كل المراحل", + "settingsPromptPlaceholderAll": "مثال: التزم باصطلاحات ملف AGENTS.md، واجعل الملخص النهائي في جملتين", + "settingsPromptPlaceholderWork": "مثال: اقرأ الاختبارات المرتبطة أولًا، وأودِع التغييرات على خطوات صغيرة", + "settingsPromptPlaceholderRetry": "مثال: تحقق مما تم إيداعه قبل المتابعة، ولا تُعِد ما أُنجز", + "settingsPromptPlaceholderReturn": "مثلاً: عالج كل نقطة مذكورة؛ ولا تُعِد هيكلة أي شيء غير ذي صلة", + "settingsPromptPlaceholderMerge": "مثال: اكتب رسالة إيداع الدمج بالعربية، ونبّه إلى أي تعارض حللته يدويًا", + "settingsPromptHintAll": "يُلحق بكل توجيه يتلقاه الوكيل، بما في ذلك مرحلة الدمج.", + "settingsPromptHintWork": "يُلحق عند تنفيذ المهمة لأول مرة.", + "settingsPromptHintRetry": "يُلحق عند استئناف مهمة متوقفة أو فاشلة.", + "settingsPromptHintReturn": "يُضاف عند متابعة مهمة قيد المراجعة (إعادة عمل، عمل إضافي، مراجعة ذاتية).", + "settingsPromptHintMerge": "يُلحق عندما يدمج الوكيل المهمة في الفرع الأساسي.", + "preflightPassed": "نجح {name}", + "preflightFailed": "فشل {name}", + "preflightRunning": "{name} قيد التشغيل…", + "detailDescription": "تفاصيل المهمة", + "detailSummary": "النتيجة", + "detailFiles": "الملفات المتغيرة", + "detailDiffAll": "عرض كامل الفروق", + "detailDiffAllTitle": "كامل الفروق", + "detailNoChanges": "لا تغييرات بعد مقارنةً بالأساس", + "detailTimeline": "سجل التقدم", + "detailTimelineEmpty": "لا نشاط بعد", + "showMore": "عرض المزيد", + "showLess": "عرض أقل", + "detailInfo": "التفاصيل", + "detailBranch": "الفرع", + "detailMergeCommit": "إيداع الدمج", + "detailChanges": "التغييرات", + "detailScheduled": "البدء المجدول", + "detailCreated": "تاريخ الإنشاء", + "detailStarted": "تاريخ البدء", + "detailFinished": "تاريخ الانتهاء", + "diffLoading": "جارٍ تحميل الفروق…", + "deleteConfirmTitle": "حذف المهمة؟", + "deleteConfirmBody": "ستُزال “{title}” من اللوحة. يُلغى التشغيل النشط أولًا.", + "deleteWithWorktree": "حذف الـ worktree الخاص بها أيضًا", + "eventCreated": "أُنشئت", + "eventStatusChanged": "تغيّر الحالة", + "eventConfigEffective": "إعداد الإطلاق", + "eventInitCommand": "أمر التهيئة", + "eventAgentProgress": "تقدّم الوكيل", + "eventAgentVerdict": "حكم الوكيل", + "eventMergeAttempt": "بدأ الدمج", + "eventMergeQueued": "أُضيف إلى طابور الدمج", + "eventMergeConflict": "تعارض دمج", + "eventPreflight": "فحص مسبق", + "eventCleanupFailed": "فشل تنظيف worktree", + "eventResumeFallback": "فشل استئناف الجلسة؛ استُخدمت جلسة جديدة", + "eventUserAction": "إجراء المستخدم", + "eventDiffStat": "لقطة التغييرات" + }, + "CustomSkillsSettings": { + "loading": "جارٍ تحميل المهارات المخصّصة…", + "category": "مخصّصة", + "searchPlaceholder": "ابحث عن المهارات المخصّصة بالاسم أو المعرّف أو الوصف", + "states": { + "not_linked": "غير مُفعّلة", + "linked_to_codeg": "مُفعّلة", + "linked_elsewhere": "مرتبطة في مكان آخر", + "blocked_by_real_directory": "محجوبة بمجلد فعلي", + "broken": "رابط معطوب" + }, + "actions": { + "new": "جديدة", + "import": "استيراد", + "importFromAgent": "استيراد من وكيل", + "cancel": "إلغاء", + "save": "حفظ" + }, + "rowMenu": { + "edit": "تعديل", + "duplicate": "تكرار", + "delete": "حذف" + }, + "bulk": { + "delete": "حذف المحدد" + }, + "editor": { + "createTitle": "مهارة مخصّصة جديدة", + "editTitle": "تعديل مهارة مخصّصة", + "description": "تُحفَظ المهارات المخصّصة في المخزن المشترك (~/.codeg/skills) ويمكن تفعيلها لأي وكيل.", + "idLabel": "معرّف المهارة", + "idPlaceholder": "مثال: my-workflow", + "contentLabel": "SKILL.md", + "contentPlaceholder": "اكتب هنا ملف SKILL.md للمهارة…", + "preview": "معاينة", + "edit": "تعديل", + "emptyBody": "لا يوجد محتوى بعد." + }, + "duplicate": { + "title": "تكرار المهارة", + "description": "إنشاء نسخة من «{id}» بمعرّف جديد.", + "newIdPlaceholder": "معرّف المهارة الجديد", + "confirm": "تكرار" + }, + "import": { + "title": "اختر مجلد مهارة للاستيراد" + }, + "importFromAgent": { + "title": "استيراد المهارات من وكيل", + "description": "انسخ مهارات الوكيل الخاصة إلى المخزن المشترك لتفعيلها لأي وكيل.", + "agentLabel": "الوكيل", + "agentPlaceholder": "اختر وكيلاً", + "selectAll": "تحديد الكل ({count})", + "loading": "جارٍ تحميل مهارات الوكيل…", + "unsupported": "لا يوفّر هذا الوكيل دليل مهارات.", + "empty": "لا توجد مهارات قابلة للاستيراد لهذا الوكيل.", + "alreadyInLibrary": "في المكتبة", + "confirm": "استيراد المحدد ({count})" + }, + "delete": { + "title": "حذف المهارات المخصّصة؟", + "body": "سيؤدي هذا إلى إزالة {count} مهارة مخصّصة من المخزن المركزي وفصل روابطها من كل وكيل. لا يمكن التراجع عن ذلك.", + "confirm": "حذف" + }, + "toasts": { + "loadFailed": "فشل تحميل المهارة", + "idRequired": "أدخل معرّف المهارة", + "created": "تم إنشاء المهارة المخصّصة", + "updated": "تم تحديث المهارة المخصّصة", + "saveFailed": "فشل حفظ المهارة", + "imported": "تم استيراد المهارة", + "importFailed": "فشل استيراد المهارة", + "duplicated": "تم تكرار المهارة", + "duplicateFailed": "فشل تكرار المهارة", + "deleted": "تم حذف {count} مهارة", + "deletedPartial": "تم حذف {ok}، وفشل {failed}", + "deleteFailed": "فشل حذف المهارات", + "importedFromAgent": "تم استيراد {count} مهارة", + "importedFromAgentPartial": "تم استيراد {ok}، وفشل {failed}", + "importFromAgentAllSkipped": "لا شيء للاستيراد — {count} موجودة بالفعل في المكتبة", + "importFromAgentFailed": "فشل الاستيراد من الوكيل" + } + }, + "CodexModelEditor": { + "customizedNotice": "لقد خصّصت قائمة النماذج، لذا يدير codeg الآن جدول نماذج codex بالكامل. لن تظهر النماذج الرسمية التي يضيفها codex لاحقًا تلقائيًا — انقر على زر التحديث بالأسفل ثم احفظ مرة أخرى لمزامنتها. امسح كل تخصيصاتك ليعود codex إلى التحديث تلقائيًا.", + "officialsTitle": "النماذج الرسمية", + "officialsHint": "تُضاف تلقائيًا من codex الذي تشغّله؛ احذف ما لا تريده.", + "officialsEmpty": "لا توجد نماذج رسمية متاحة.", + "refresh": "تحديث من codex", + "readdOfficial": "إعادة إضافة رسمي", + "customsTitle": "النماذج المخصّصة", + "customsEmpty": "لا توجد نماذج مخصّصة بعد.", + "addCustom": "إضافة مخصص", + "slugPlaceholder": "معرّف النموذج (slug)", + "displayNamePlaceholder": "الاسم المعروض", + "contextWindow": "السياق", + "makeDefault": "تعيين كافتراضي", + "defaultHint": "النموذج الافتراضي", + "remove": "إزالة", + "advanced": "متقدم", + "baseTemplate": "القالب الأساسي", + "baseTemplateHint": "النموذج الرسمي الذي تُنسخ منه الحقول المطلوبة (موجّه النظام، الأدوات، الحدود).", + "groupBehavior": "السلوك والقدرات", + "fieldReasoningLevel": "الاستدلال الافتراضي", + "fieldReasoningSummary": "ملخص الاستدلال", + "fieldVerbosity": "مستوى التفصيل", + "fieldShellType": "نوع الصدفة", + "fieldApplyPatch": "أداة تطبيق التصحيح", + "fieldReasoningSummaries": "ملخصات الاستدلال", + "fieldSupportVerbosity": "التحكم في التفصيل", + "fieldParallelToolCalls": "استدعاءات الأدوات المتوازية", + "fieldSearchTool": "أداة البحث على الويب", + "optNone": "بلا", + "groupInstructions": "الوصف وموجّه النظام", + "fieldDescription": "الوصف", + "baseInstructions": "موجّه النظام (base_instructions)" + }, + "DiagnosticsSettings": { + "title": "تشخيص البيئة", + "description": "يتحقق من كيفية تحليل هذا التطبيق لواجهة سطر أوامر الوكيل داخل عمليته الخاصة، وقد يختلف ذلك عن الطرفية لديك.", + "loading": "جارٍ تشغيل التشخيص…", + "error": "فشل التشخيص", + "rerun": "إعادة التشغيل", + "copyAll": "نسخ الكل", + "copied": "تم نسخ التشخيص إلى الحافظة", + "button": "تشخيص", + "verdict": { + "ok": "تبدو البيئة سليمة. إذا استمر ظهوره كغير مُثبَّت، فأعد تشغيل التطبيق بالكامل لتحديث ذاكرة التخزين المؤقتة للبادئة.", + "node_missing": "لم يتم العثور على Node.js في مسار PATH الخاص بالتطبيق.", + "npm_missing": "لم يتم العثور على npm في مسار PATH الخاص بالتطبيق.", + "not_installed": "يبدو أن هذا الوكيل غير مُثبَّت.", + "installed_but_unresolved": "مُسجَّل كمُثبَّت، لكن لا يستطيع التطبيق تحديد موقع الملف التنفيذي.", + "user_prefix_not_on_path": "تم التثبيت في بادئة الاحتياط (~/.codeg/npm-global)، وهي ليست في مسار PATH الخاص بالتطبيق. أعد تشغيل التطبيق بالكامل وحاول مرة أخرى.", + "homebrew_bin_not_on_path": "تم التثبيت ضمن مجلد bin الخاص بـ Homebrew، وهو ليس في مسار PATH الخاص بالتطبيق (فصل keg على Apple Silicon).", + "terminal_only_path": "يُحلَّل الأمر في الطرفية لديك لكن ليس في التطبيق — وهي فجوة في مسار PATH لواجهة المستخدم الرسومية. شغّل التطبيق من الطرفية أو أعد التثبيت من إعدادات الوكلاء.", + "npm_prefix_timeout": "كان npm prefix -g بطيئًا جدًا (أكثر من 1.5 ثانية)، لذا تم تخطّي الكشف الاحتياطي. أعد تشغيل التطبيق وحاول مرة أخرى.", + "node_too_old": "إصدار Node.js النشط أقدم مما يتطلبه هذا الوكيل. يرجى ترقية Node.js.", + "adapter_missing_native_present": "واجهة {agent} لديك مثبّتة فعلاً، لكن Codeg يشغّل حزمة محوّل ACP منفصلة، وهي غير مثبّتة بعد. ثبّتها من إعدادات الوكلاء؛ فهي لا تمسّ واجهتك وتتشارك تسجيل الدخول نفسه.", + "adapter_missing": "يشغّل Codeg حزمة محوّل ACP منفصلة من أجل {agent}، وهي غير مثبّتة بعد. ثبّتها من إعدادات الوكلاء — لا يكفي تثبيت واجهة الأوامر الرسمية وحدها." + } + }, + "TokenUsage": { + "title": "استهلاك الرموز", + "rangeLabel": "النطاق الزمني", + "range7d": "٧ أيام", + "range30d": "٣٠ يومًا", + "range90d": "٩٠ يومًا", + "rangeThisMonth": "هذا الشهر", + "rangeThisYear": "هذا العام", + "rangeAll": "الكل", + "rangeCustom": "مخصص", + "moreRanges": "المزيد", + "customRangePick": "اختر نطاقاً زمنياً", + "bucketLabel": "التجميع حسب", + "bucketDay": "يوم", + "bucketWeek": "أسبوع", + "bucketMonth": "شهر", + "bucketUnitDay": "يوم", + "bucketUnitWeek": "أسبوع", + "bucketUnitMonth": "شهر", + "folderFilter": "المجلدات", + "allFolders": "كل المجلدات", + "agentFilter": "الوكلاء", + "allAgents": "كل الوكلاء", + "modelFilter": "النماذج", + "allModels": "كل النماذج", + "searchPlaceholder": "بحث…", + "noMatches": "لا توجد نتائج", + "clearFilter": "مسح التحديد", + "resetFilters": "إعادة ضبط المرشحات", + "refresh": "تحديث", + "rebuild": "إعادة بناء الكل", + "rebuildHint": "يتجاهل البيانات المحسوبة ويعيد قراءة كل سجلات الجلسات. استخدمه إذا نمت جلسة خارج codeg.", + "syncing": "جارٍ حساب الجلسات…", + "syncProgress": "{done} / {total}", + "syncDone": "تم حساب {synced} جلسة", + "syncFailed": "تعذّرت قراءة بعض الجلسات", + "syncBusy": "هناك تحديث قيد التشغيل بالفعل", + "lastSynced": "حُدّث {time}", + "lastSyncedNever": "لم يُحدَّث بعد", + "tileTotal": "إجمالي الرموز", + "tileSessions": "الجلسات", + "tileTurns": "الأدوار", + "tileActiveDays": "الأيام النشطة", + "tileGenTime": "زمن التوليد", + "vsPrevious": "مقارنة بالفترة السابقة", + "deltaNew": "جديد", + "trendTitle": "الاستهلاك عبر الزمن", + "trendEmpty": "لا استهلاك في هذا النطاق", + "trendTurns": "الأدوار", + "trendSessions": "الجلسات", + "compositionTitle": "أين ذهبت الرموز", + "compositionHint": "الإدخال هو ما أرسلته، والإخراج ما كتبه النموذج، وقراءات الذاكرة المؤقتة سياق لم تدفع ثمنه كاملًا.", + "compositionNote": "إعادة إرسال هذه الإصابات المؤقتة بالسعر الكامل كانت ستكلف {value} إضافية.", + "inputTokens": "إدخال", + "outputTokens": "إخراج", + "cacheWrite": "كتابة مؤقتة", + "cacheRead": "قراءة مؤقتة", + "freshTokens": "حساب جديد", + "cacheHitCaption": "إصابة مؤقتة", + "cacheHeroTitleHigh": "معظم السياق لم يُعَد إرساله", + "cacheHeroTitleLow": "معظم السياق ما زال يُحسب بالسعر الكامل", + "cacheHeroDesc": "حملت الذاكرة المؤقتة {cached} من السياق، ولم يُحسب من جديد سوى {fresh} في هذه الفترة.", + "cacheSavedSuffix": "وفّر ذلك ما يعادل {saved} من إعادة الإرسال.", + "avgPerSession": "المتوسط لكل جلسة", + "avgTurnsPerSession": "{count} دورة لكل جلسة في المتوسط", + "avgPerActiveDay": "المتوسط لكل يوم نشط", + "peakBucket": "أعلى {bucket}", + "peakHour": "ساعة الذروة", + "daysValue": "{count} يومًا", + "idleDays": "أيام الخمول", + "byFolderTitle": "حسب المجلد", + "byAgentTitle": "حسب الوكيل", + "byModelTitle": "حسب النموذج", + "distributionTitle": "توزيع الاستخدام", + "distributionHint": "تُجمَّع الجلسات والرموز حسب البعد المحدد — انقر أي صف للتصفية به.", + "otherLabel": "أخرى", + "unknownModel": "نموذج غير مسجَّل", + "emptyBreakdown": "لا توجد سجلات بعد", + "sessionsCount": "{count} جلسة", + "heatmapTitle": "إيقاع عملك", + "heatmapHint": "الرموز حسب اليوم والساعة بالتوقيت المحلي.", + "heatmapPeakHint": "الأكثر كثافة حوالي {hour}:00.", + "less": "أقل", + "more": "أكثر", + "heatmapCell": "{weekday} {hour}:00 — {value} رمز", + "weekMon": "إث", + "weekTue": "ثل", + "weekWed": "أر", + "weekThu": "خم", + "weekFri": "جم", + "weekSat": "سب", + "weekSun": "أح", + "topSessionsTitle": "أكثر الجلسات استهلاكًا", + "untitledSession": "جلسة بلا عنوان", + "topSessionsEmpty": "لا جلسات في هذا النطاق", + "streakLongest": "أطول سلسلة", + "streakLongestDays": "أطول سلسلة: {count} يومًا", + "share": "مشاركة", + "moreActions": "مزيد من الإجراءات", + "shareDialogTitle": "شارك بطاقة استهلاكك", + "shareDialogHint": "لقطة للنطاق والمرشحات التي تعرضها الآن.", + "shareSave": "حفظ الصورة", + "shareCopy": "نسخ الصورة", + "shareCopied": "تم النسخ إلى الحافظة", + "shareSaved": "تم حفظ الصورة", + "shareFailed": "تعذّر إنشاء الصورة", + "shareRendering": "جارٍ الإنشاء…", + "cardHeading": "سجلّي في البرمجة بالذكاء الاصطناعي", + "cardRangeAll": "كل الفترات", + "cardTotalLabel": "الرموز المستهلكة", + "cardFooter": "صُنع بواسطة codeg", + "cardTopModels": "أبرز النماذج", + "cardTopProjects": "أبرز المشاريع", + "archetypeNightOwl": "بومة الليل", + "archetypeNightOwlDesc": "{percent}% من رموزك تُستهلك بعد حلول الظلام.", + "archetypeEarlyBird": "المستيقظ باكرًا", + "archetypeEarlyBirdDesc": "{percent}% من رموزك تُستهلك قبل التاسعة صباحًا.", + "archetypeWeekendWarrior": "محارب عطلة الأسبوع", + "archetypeWeekendWarriorDesc": "{percent}% من رموزك تحدث في عطلة الأسبوع.", + "archetypeCacheMaster": "سيد الذاكرة المؤقتة", + "archetypeCacheMasterDesc": "{percent}% من سياقك جاء من الذاكرة المؤقتة.", + "archetypeMarathoner": "عدّاء المسافات", + "archetypeMarathonerDesc": "{days} يومًا من البناء دون انقطاع.", + "archetypePolyglot": "متعدد المهارات", + "archetypePolyglotDesc": "{count} وكلاء في استخدام جادّ.", + "archetypeLaserFocus": "تركيز مطلق", + "archetypeLaserFocusDesc": "{percent}% من رموزك ذهبت لمشروع واحد.", + "archetypeDeepDiver": "الغوّاص", + "archetypeDeepDiverDesc": "{averageK}K رمز في الجلسة الواحدة وسطيًا.", + "archetypeSteady": "بنّاء ثابت", + "archetypeSteadyDesc": "{days} يومًا من الإنجاز.", + "emptyTitle": "لا توجد بيانات محسوبة بعد", + "emptyHint": "يقرأ codeg أعداد الرموز مباشرة من سجل كل وكيل. حدّث لتُحسب الجلسات الموجودة على هذا الجهاز.", + "emptyAction": "احسب جلساتي", + "loadFailed": "تعذّر تحميل بيانات الاستهلاك", + "truncatedNotice": "هذا النطاق واسع جدًا — الأرقام تغطي أحدث جزء منه فقط." + } +} diff --git a/src/i18n/messages/de.json b/src/i18n/messages/de.json index 7e77e7ecf..49a55deca 100644 --- a/src/i18n/messages/de.json +++ b/src/i18n/messages/de.json @@ -1,4958 +1,4958 @@ -{ - "Language": { - "followSystem": "Systemsprache verwenden", - "english": "Englisch", - "simplifiedChinese": "Vereinfachtes Chinesisch", - "traditionalChinese": "Traditionelles Chinesisch", - "japanese": "Japanisch", - "korean": "Koreanisch", - "spanish": "Spanisch", - "german": "Deutsch", - "french": "Französisch", - "portuguese": "Portugiesisch", - "arabic": "Arabisch" - }, - "GitCredentialDialog": { - "title": "Authentifizierung erforderlich", - "description": "Der Remote-Server erfordert Anmeldedaten. Geben Sie Ihren Benutzernamen und Ihr Passwort (oder persönliches Zugriffstoken) ein.", - "username": "Benutzername", - "usernamePlaceholder": "Benutzername oder E-Mail", - "password": "Passwort / Token", - "passwordPlaceholder": "Passwort oder persönliches Zugriffstoken", - "passwordHint": "Geben Sie Benutzername und Passwort des Servers ein.", - "cancel": "Abbrechen", - "authenticate": "Authentifizieren", - "authenticating": "Authentifizierung...", - "invalidCredentials": "Ungültige Anmeldedaten. Bitte versuchen Sie es erneut.", - "saveCredentials": "Anmeldedaten für zukünftige Vorgänge speichern", - "githubTitle": "GitHub-Authentifizierung", - "githubDescription": "Geben Sie ein persönliches Zugriffstoken ein, um sich mit GitHub zu verbinden. Das Token wird validiert und automatisch gespeichert.", - "githubToken": "Persönliches Zugriffstoken", - "githubTokenPlaceholder": "ghp_xxxxxxxxxxxx", - "githubTokenHint": "Erstellen Sie ein Token unter GitHub → Settings → Developer settings → Personal access tokens.", - "githubAuthenticate": "Validieren & verbinden", - "generateToken": "Token erstellen" - }, - "SettingsShell": { - "title": "Einstellungen", - "preferences": "Präferenzen", - "nav": { - "general": "Allgemein", - "appearance": "Darstellung", - "agents": "Agenten", - "mcp": "MCP", - "skills": "Skills", - "shortcuts": "Kurzbefehle", - "version_control": "Versionskontrolle", - "system": "Systemeinstellungen", - "chat_channels": "Chat-Kanäle", - "web_service": "Webdienst", - "model_providers": "Modellanbieter", - "experts": "Experten", - "science": "Wissenschaft", - "office_tools": "Office-Tools", - "skill_packs": "Skill-Pakete", - "quick_messages": "Schnellnachrichten", - "logs": "Laufzeitprotokolle" - } - }, - "AppearanceSettings": { - "sectionTitle": "Design-Erscheinungsbild", - "sectionDescription": "Wähle hell, dunkel oder Systemvorgabe. Einstellungen werden automatisch gespeichert.", - "themeMode": "Designmodus", - "placeholder": "Designmodus auswählen", - "system": "Systemvorgabe", - "light": "Hell", - "dark": "Dunkel", - "currentTheme": "Aktuell wirksames Design: {theme}", - "resolvedTheme": { - "light": "Hell", - "dark": "Dunkel", - "unknown": "--" - }, - "themeColor": { - "sectionTitle": "Themenfarbe", - "sectionDescription": "Wähle eine Farbpalette für Akzente, Schaltflächen und Hervorhebungen.", - "current": "Aktuelle Farbe: {color}", - "options": { - "neutral": "Neutral", - "zinc": "Zinc", - "slate": "Slate", - "stone": "Stone", - "gray": "Gray", - "red": "Red", - "rose": "Rose", - "orange": "Orange", - "green": "Green", - "blue": "Blue", - "yellow": "Yellow", - "violet": "Violet" - } - }, - "customStyle": { - "sectionTitle": "Eigener Stil", - "sectionDescription": "Feinjustiere die Farben des aktuellen Themes oder füge eigenes CSS ein. Überschreibungen liegen über der Basisvorlage und bleiben beim Wechsel der Vorlage erhalten.", - "summarySuspended": "Ausgesetzt", - "summaryDefault": "Vorlage unverändert", - "summaryTokens": "{count, plural, one {# Überschreibung} other {# Überschreibungen}}", - "summaryCss": "Eigenes CSS", - "suspendedByShortcut": "Der eigene Stil ist ausgesetzt. Nichts, was du hier einstellst, wirkt, bis du ihn fortsetzt.", - "suspendedBySafeParam": "Dieses Fenster wurde im sicheren Darstellungsmodus geöffnet, daher wird eigener Stil hier ignoriert. Andere Fenster sind nicht betroffen.", - "resume": "Eigenen Stil fortsetzen", - "enableTheme": "Eigene Farben aktivieren", - "editingLight": "Du bearbeitest die Werte des hellen Modus. Wechsle die App in den dunklen Modus, um diesen separat einzustellen.", - "editingDark": "Du bearbeitest die Werte des dunklen Modus. Wechsle die App in den hellen Modus, um diesen separat einzustellen.", - "resetToken": "Auf Vorlagenwert zurücksetzen", - "radius": "Eckenradius", - "radiusHint": "Daraus leitet sich die gesamte Radiusskala von sm bis 4xl ab – ein Regler rundet die ganze App.", - "advanced": "Erweitert ({count} weitere Variablen)", - "enableCss": "Eigenes CSS aktivieren", - "cssRisk": "Funktion für Fortgeschrittene. Eigenes CSS überschreibt sämtliche eingebauten Stile und kann die Oberfläche unbrauchbar machen.", - "editCss": "CSS bearbeiten…", - "cssPresent": "{size} KB gespeichert", - "cssEmpty": "Noch nichts gespeichert", - "escapeHint": "Oberfläche kaputt? Drücke {shortcut}, um den gesamten eigenen Stil auszusetzen, oder öffne ein Fenster mit dem Query-Parameter safeStyle=1.", - "copyTheme": "Theme-JSON kopieren", - "importTheme": "Theme importieren…", - "clearTheme": "Überschreibungen löschen", - "interopHint": "Themes nutzen das registry:theme-Format von shadcn – du kannst hier jedes shadcn-Theme einfügen und exportierte in jedem shadcn-Projekt verwenden.", - "importTitle": "Theme importieren", - "importDescription": "Füge ein shadcn-registry:theme-Item, ein reines light/dark-Objekt oder eine flache Token-Zuordnung ein.", - "readClipboard": "Zwischenablage lesen", - "importConfirm": "Importieren", - "cancel": "Abbrechen", - "apply": "Anwenden", - "toasts": { - "copied": "Theme-JSON kopiert", - "copyFailed": "Kopieren in die Zwischenablage fehlgeschlagen", - "clipboardReadFailed": "Zwischenablage konnte nicht gelesen werden, bitte manuell einfügen", - "importFailed": "In diesem JSON wurden keine nutzbaren Theme-Variablen gefunden", - "imported": "Theme importiert" - }, - "css": { - "dialogTitle": "Eigenes CSS", - "dialogDescription": "Gilt für alle codeg-Fenster. Änderungen werden live vorschauend angezeigt; zum Speichern auf Anwenden klicken.", - "size": "{used} KB / {max} KB", - "ruleCount": "{count} Regeln", - "errorTooLarge": "Zu groß zum Speichern. Bitte unter das Limit kürzen.", - "errorImportEscaped": "Eine @import-Regel hat das Entfernen überstanden (maskierte Schreibweise). Bitte entfernen, um zu speichern.", - "warnNoRules": "Keine Regeln erkannt – bitte die Syntax prüfen.", - "noticeImportsRemoved": "Entfernte @import-Regeln: {count}. Sie würden entfernte Stylesheets laden.", - "noticeRemoteUrl": "Enthält eine entfernte url(), die beim Anwenden eine Netzwerkanfrage auslöst.", - "noticePreviewSuspended": "Der eigene Stil ist ausgesetzt, daher wird diese Vorschau nicht angewendet.", - "noticeDisabled": "Eigenes CSS ist aus. Du kannst hier eine Vorschau sehen, aber es wirkt erst nach dem Aktivieren.", - "hintTokens": "Tipp: Deine überschriebenen Farben sind als var(--primary), var(--background) usw. verfügbar." - } - }, - "zoomLevel": { - "sectionTitle": "Fensterzoom", - "sectionDescription": "Skaliert die gesamte Oberfläche. Wird sofort übernommen und pro Gerät gespeichert.", - "placeholder": "Zoomstufe wählen", - "default": "Standard", - "current": "Aktueller Zoom: {zoom}%" - }, - "fonts": { - "sectionTitle": "Schriftarten", - "sectionDescription": "Wähle Schriftarten für Oberfläche, Code-Editor und Terminal. Mitgelieferte Schriftarten werden bei Bedarf geladen; wähle „Benutzerdefiniert…“, um eine beliebige auf deinem System installierte Schriftart zu verwenden.", - "interface": "Oberfläche", - "editor": "Editor", - "terminal": "Terminal", - "groupSans": "Serifenlos", - "groupMono": "Monospace", - "custom": "Benutzerdefiniert…", - "customPlaceholder": "Schriftartname, z. B. Fira Code", - "fontSize": "Schriftgröße", - "ligatures": "Ligaturen aktivieren", - "ligaturesUnavailable": "Diese Schriftart hat keine Ligaturen", - "wordWrap": "Zeilenumbruch aktivieren", - "terminalLigaturesHint": "Terminal-Ligaturen gelten nur für mitgelieferte Programmierschriftarten.", - "preview": "Vorschau" - }, - "welcomePanel": { - "sectionTitle": "Modusauswahlbereich", - "sectionDescription": "Die Shortcut-Karten „Code-Entwicklung / Büroarbeit“ über dem Eingabefeld auf der Seite für eine neue Konversation.", - "showQuickActions": "Auf der Seite für neue Konversationen anzeigen" - }, - "workspaceBackground": { - "sectionTitle": "Arbeitsbereich-Hintergrund", - "sectionDescription": "Zeigt ein Bild hinter dem gesamten Arbeitsbereich. Seitenleiste und Panels werden durchscheinend und mattiert, sodass das Bild durchscheint, und eine Maske sorgt für lesbaren Text.", - "enable": "Hintergrundbild aktivieren", - "image": "Bild", - "chooseImage": "Bild auswählen", - "replaceImage": "Bild ersetzen", - "removeImage": "Entfernen", - "fillMode": "Füllmodus", - "fillModes": { - "cover": "Füllen", - "contain": "Einpassen", - "center": "Zentrieren", - "tile": "Kacheln" - }, - "maskOpacity": "Maskendeckkraft", - "maskOpacityHint": "Höhere Werte blenden das Bild zur Hintergrundfarbe des Themes aus und verbessern den Textkontrast.", - "imageBlur": "Bildunschärfe", - "panelOpacity": "Panel-Deckkraft", - "panelOpacityHint": "Wie deckend Seitenleiste, Panels und Tab-Leisten sind. Niedriger lässt mehr vom Bild durchscheinen.", - "errorTooLarge": "Bild ist zu groß (max. 16 MB).", - "errorUploadFailed": "Hintergrundbild konnte nicht festgelegt werden." - } - }, - "SystemSettings": { - "loading": "Wird geladen...", - "sectionTitle": "Systemverwaltung", - "sectionDescription": "Verwalte Netzwerk-Proxy, App-Updates und Spracheinstellungen.", - "proxyTitle": "Netzwerk-Proxy", - "proxyDescription": "Wenn aktiviert, werden nachfolgende Netzwerkanfragen bevorzugt über diesen Proxy ausgeführt (einschließlich ACP-Chat, Agent-Installation und Git-Remote-Operationen).", - "loadFailed": "Laden fehlgeschlagen: {message}", - "enableProxy": "System-Proxy aktivieren", - "proxyAddress": "Proxy-Adresse", - "proxyHint": "Unterstützt http(s)/socks5, Beispiel: {example}. Wirksam nur bei aktiviertem System-Proxy.", - "save": "Speichern", - "saving": "Wird gespeichert...", - "proxyRequired": "Bei aktiviertem Proxy ist eine Proxy-URL erforderlich", - "saveSuccess": "System-Proxy-Einstellungen wurden gespeichert", - "saveFailed": "Speichern fehlgeschlagen: {message}", - "languageTitle": "Sprache", - "languageDescription": "Lege die App-Sprache fest. Bei Systemsprache wird bei nicht unterstützten Sprachen auf Englisch zurückgefallen.", - "appLanguage": "App-Sprache", - "languageSaveSuccess": "Spracheinstellungen wurden gespeichert", - "languageSaveFailed": "Spracheinstellungen konnten nicht gespeichert werden: {message}", - "updateTitle": "App-Update", - "versionTitle": "Softwareupdate", - "updateDescription": "Prüft die konfigurierte Release-Quelle auf neue Versionen und installiert sie bei Verfügbarkeit direkt.", - "currentVersion": "Aktuelle Version", - "upgradableVersion": "Neueste Version", - "none": "Keine", - "lastChecked": "Zuletzt geprüft: {time}", - "updateError": "Update-Fehler: {message}", - "checking": "Wird geprüft...", - "checkUpdate": "Nach Updates suchen", - "updating": "Wird installiert...", - "downloading": "Herunterladen...", - "upgradeTo": "Auf v{version} aktualisieren", - "viewRelease": "Release v{version} anzeigen", - "foundUpdate": "Neue Version v{version} gefunden", - "alreadyLatest": "Du verwendest bereits die neueste Version", - "checkUpdateFailed": "Update-Prüfung fehlgeschlagen: {message}", - "installSuccess": "Update installiert. App wird neu gestartet.", - "installFailed": "Update fehlgeschlagen: {message}", - "upgradeSuccess": "Aktualisierung abgeschlossen. Wird neu geladen...", - "restartTimeout": "Der Server ist nicht rechtzeitig zurückgekehrt. Prüfe die Container- oder Dienstprotokolle.", - "restartingIn": "Neustart in {seconds} s...", - "waitingForServer": "Warten, bis der Server zurückkehrt...", - "restartToUpdate": "Zum Aktualisieren neu starten", - "newVersionBadge": "Neu v{version}", - "updateAvailableTitle": "Update verfügbar", - "releaseNotesTitle": "Neuerungen", - "remindLater": "Später", - "retry": "Erneut versuchen", - "stepDownload": "Download", - "stepInstall": "Installation", - "stepRestart": "Neustart", - "updateReadyHint": "Update heruntergeladen – zum Anwenden neu starten.", - "restarting": "Neustart...", - "dockerUpgradeHint": "Dies aktualisiert jetzt den laufenden Container. Beim Neuerstellen des Containers geht es verloren – zum Beibehalten ein Image mit der neuen Version ziehen oder bauen und den Container neu erstellen.", - "upgradeRolledBack": "Upgrade fehlgeschlagen; der Server wurde auf die vorherige Version zurückgesetzt.", - "serverUnreachable": "Der Server konnte für das Upgrade nicht erreicht werden. Prüfe, ob er läuft, und versuche es erneut.", - "rollbackButton": "Zurücksetzen", - "rollingBack": "Wird zurückgesetzt...", - "rollbackDescription": "Stellt die vor dem letzten Upgrade installierte Version wieder her.", - "rollbackConfirmTitle": "Auf die vorherige Version zurücksetzen?", - "rollbackConfirmDescription": "Der Server startet mit der vor dem letzten Upgrade installierten Version neu. Eine neuere Version kann weiterhin erneut installiert werden.", - "rollbackConfirm": "Zurücksetzen", - "rollbackCancel": "Abbrechen", - "rollbackSuccess": "Auf die vorherige Version zurückgesetzt. Wird neu geladen...", - "rollbackFailed": "Zurücksetzen fehlgeschlagen. Prüfe die Serverprotokolle.", - "updateErrors": { - "sourceUnavailable": "Die Update-Quelle ist nicht erreichbar. Prüfe Netzwerk oder Proxy und versuche es erneut.", - "network": "Netzwerkverbindung fehlgeschlagen. Prüfe Netzwerk oder Proxy und versuche es erneut.", - "downloadFailed": "Das Update-Paket konnte nicht heruntergeladen werden. Bitte später erneut versuchen.", - "installFailed": "Das Update konnte nicht installiert werden. Bitte App schließen und erneut versuchen.", - "unknown": "Update fehlgeschlagen. Bitte später erneut versuchen." - } - }, - "VersionControlSettings": { - "loading": "Laden...", - "sectionTitle": "Versionskontrolle", - "sectionDescription": "Git-Programm konfigurieren und GitHub-Konten verwalten.", - "gitTitle": "Git-Konfiguration", - "gitDescription": "Konfigurieren Sie das von der Anwendung verwendete Git-Programm.", - "gitDetected": "Git erkannt", - "gitNotFound": "Git wurde nicht gefunden", - "gitVersion": "Version", - "gitPath": "Pfad", - "customGitPath": "Benutzerdefinierter Git-Pfad", - "customGitPathPlaceholder": "/usr/bin/git", - "customGitPathHint": "Leer lassen, um den automatisch erkannten Pfad zu verwenden.", - "test": "Testen", - "testing": "Teste...", - "testSuccess": "Git-Programm ist gültig.", - "testFailed": "Git-Test fehlgeschlagen: {message}", - "save": "Speichern", - "saving": "Speichern...", - "saveSuccess": "Git-Einstellungen gespeichert.", - "saveFailed": "Speichern fehlgeschlagen: {message}", - "githubTitle": "GitHub-Konten", - "githubDescription": "GitHub-Konten für die Authentifizierung verwalten. Token werden lokal gespeichert.", - "noAccounts": "Keine GitHub-Konten konfiguriert.", - "addAccount": "Konto hinzufügen", - "serverUrl": "Server-URL", - "serverUrlPlaceholder": "https://github.com", - "token": "Persönlicher Zugriffstoken", - "tokenPlaceholder": "ghp_xxxxxxxxxxxx", - "generateToken": "Token erstellen", - "tokenHint": "Erstellen Sie einen Token unter GitHub → Settings → Developer settings → Personal access tokens.", - "validateAndAdd": "Validieren & hinzufügen", - "validating": "Validiere...", - "addSuccess": "Konto {username} erfolgreich hinzugefügt.", - "addFailed": "Konto konnte nicht hinzugefügt werden: {message}", - "testConnection": "Testen", - "connectionSuccess": "Verbindung erfolgreich.", - "connectionFailed": "Verbindung fehlgeschlagen: {message}", - "setDefault": "Als Standard festlegen", - "defaultLabel": "Standard", - "defaultSet": "Standardkonto aktualisiert.", - "removeAccount": "Entfernen", - "removeConfirmTitle": "Konto entfernen", - "removeConfirmMessage": "Möchten Sie das Konto \"{username}\" wirklich entfernen?", - "removeConfirm": "Entfernen", - "removeCancel": "Abbrechen", - "removeSuccess": "Konto entfernt.", - "scopes": "Berechtigungen", - "loadFailed": "Einstellungen konnten nicht geladen werden: {message}", - "gitAccount": { - "sectionTitle": "Git-Server-Konten", - "sectionDescription": "Verwalten Sie Anmeldedaten für Nicht-GitHub-Git-Server (GitLab, Bitbucket, selbst gehostet usw.).", - "noAccounts": "Keine Git-Server-Konten konfiguriert.", - "addAccount": "Konto hinzufügen", - "addTitle": "Git-Konto hinzufügen", - "addDescription": "Geben Sie Serveradresse, Benutzername und Passwort oder Zugriffstoken ein.", - "serverUrl": "Server-URL", - "serverUrlPlaceholder": "https://gitlab.example.com", - "username": "Benutzername", - "usernamePlaceholder": "Benutzername oder E-Mail", - "password": "Passwort / Token", - "passwordPlaceholder": "Passwort oder Zugriffstoken", - "passwordHint": "Geben Sie das Passwort oder Zugriffstoken des Servers ein.", - "add": "Hinzufügen", - "serverRequired": "Server-URL ist erforderlich.", - "usernameRequired": "Benutzername ist erforderlich.", - "passwordRequired": "Passwort ist erforderlich." - } - }, - "ShortcutSettings": { - "sectionTitle": "Kurzbefehle", - "resetDefault": "Standardwerte zurücksetzen", - "recordInstruction": "Klicke auf die rechte Schaltfläche und drücke dann eine Tastenkombination. Verwende Ctrl/Cmd, Alt und Shift. Drücke Esc, um die Aufzeichnung abzubrechen.", - "recording": "Kurzbefehl drücken...", - "toasts": { - "conflict": "Der Kurzbefehl wird bereits von \"{title}\" verwendet", - "updated": "Kurzbefehl aktualisiert", - "invalid": "Ungültiger Kurzbefehl, bitte erneut versuchen", - "reset": "Standard-Kurzbefehle wurden wiederhergestellt" - }, - "actions": { - "toggle_search": { - "title": "Suche öffnen", - "description": "Zeigt das Konversations-Suchpanel an oder blendet es aus" - }, - "toggle_sidebar": { - "title": "Linke Seitenleiste umschalten", - "description": "Zeigt die Seitenleiste mit der Konversationsliste an oder blendet sie aus" - }, - "toggle_terminal": { - "title": "Terminal umschalten", - "description": "Zeigt das untere Terminal-Panel an oder blendet es aus" - }, - "new_terminal_tab": { - "title": "Neues Terminal", - "description": "Erstellt einen neuen Terminal-Tab, wenn das Terminal fokussiert ist" - }, - "close_current_terminal_tab": { - "title": "Aktuelles Terminal schließen", - "description": "Schließt den aktuellen Terminal-Tab, wenn das Terminal fokussiert ist" - }, - "toggle_aux_panel": { - "title": "Rechtes Panel umschalten", - "description": "Zeigt das Zusatzinformations-Panel an oder blendet es aus" - }, - "new_conversation": { - "title": "Neue Konversation", - "description": "Erstellt einen neuen Konversations-Tab im aktuellen Ordner" - }, - "open_folder": { - "title": "Ordner öffnen", - "description": "Öffnet die Ordnerauswahl und den Ordner in einem neuen Fenster" - }, - "open_settings": { - "title": "Einstellungen öffnen", - "description": "Öffnet das Einstellungsfenster" - }, - "close_current_tab": { - "title": "Aktuellen Tab schließen", - "description": "Schließt den aktuellen Konversations- oder Dateitab" - }, - "close_all_file_tabs": { - "title": "Alle Dateitabs schließen", - "description": "Schließt alle geöffneten Dateitabs, wenn der Dateibereich aktiv ist" - }, - "next_tab": { - "title": "Nächster Tab", - "description": "Zum nächsten Konversations- oder Datei-Tab wechseln" - }, - "prev_tab": { - "title": "Vorheriger Tab", - "description": "Zum vorherigen Konversations- oder Datei-Tab wechseln" - }, - "send_message": { - "title": "Nachricht senden", - "description": "Die aktuelle Nachricht im Eingabefeld senden" - }, - "newline_in_message": { - "title": "Zeilenumbruch einfügen", - "description": "Einen Zeilenumbruch im Eingabefeld einfügen" - }, - "toggle_custom_style": { - "title": "Eigenen Stil aussetzen/fortsetzen", - "description": "Notausstieg: schaltet alle eigenen Farben und CSS aus und wieder ein" - } - } - }, - "SkillsSettings": { - "title": "Skills", - "description": "Wähle links einen Skill aus. Rechts wird standardmäßig eine Markdown-Vorschau angezeigt; wechsle zum Bearbeiten, um zu ändern und zu speichern.", - "loadingAgents": "Agenten mit Skill-Unterstützung werden geladen...", - "emptyNoManageableAgents": "Keine Agenten für Skill-Verwaltung verfügbar.", - "managedTarget": "Verwaltetes Ziel", - "selectAgentPlaceholder": "Agent auswählen", - "searchPlaceholder": "Nach Name / ID / Pfad suchen...", - "skillsList": "Skill-Liste", - "loadingSkills": "Skills werden geladen...", - "agentNotSupported": "Der aktuelle Agent unterstützt keine Skill-Verwaltung.", - "emptySkills": "Noch keine Skills. Klicke auf „Neuer Skill“, um einen zu erstellen.", - "newSkillTitle": "Neuer Skill", - "skillInfo": "Skill-Info", - "skillIdPlaceholder": "skill-id (Buchstaben/Zahlen/-/_/.)", - "skillsDirectoryWithPath": "Skill-Verzeichnis: {path}", - "skillsDirectoryNeedId": "Skill-Verzeichnis: Skill-ID eingeben, um den vollständigen Pfad zu erzeugen", - "markdownContent": "Markdown-Inhalt", - "editingStatus": "Bearbeiten", - "previewStatus": "Vorschau", - "contentPlaceholder": "Markdown-Inhalt des Skills eingeben...", - "metadataTitle": "Skill-Metadaten", - "onlyYamlMetadata": "Dieser Skill enthält nur YAML-Metadaten.", - "emptyContentHint": "Noch kein Inhalt. Klicke auf „Bearbeiten“, um zu starten.", - "loadingSkill": "Skill wird geladen...", - "emptyNoAgents": "Kein verfügbarer Agent.", - "noSelectionHint": "Wählen Sie links einen Skill oder klicken Sie auf „Neuer Skill“, um einen zu erstellen.", - "systemBadge": "System", - "systemHint": "Integrierter CLI-Skill · schreibgeschützt", - "scope": { - "global": "Global", - "folder": "Ordner", - "selectFolderPlaceholder": "Ordner auswählen", - "noFolders": "Keine Ordner gefunden", - "pickFolderHint": "Wählen Sie einen Ordner, um dessen Skills anzuzeigen." - }, - "actions": { - "preview": "Vorschau", - "edit": "Bearbeiten", - "openInWindow": "In neuem Fenster öffnen", - "delete": "Löschen", - "deleting": "Wird gelöscht...", - "refresh": "Aktualisieren", - "newSkill": "Neuer Skill", - "reset": "Zurücksetzen", - "save": "Speichern", - "saving": "Wird gespeichert...", - "cancel": "Abbrechen" - }, - "deleteDialog": { - "title": "Skill löschen", - "confirm": "Aktuellen Skill löschen? Diese Aktion kann nicht rückgängig gemacht werden.", - "confirmWithNamePrefix": "Skill", - "confirmWithNameSuffix": "löschen? Diese Aktion kann nicht rückgängig gemacht werden." - }, - "toasts": { - "loadFailed": "Skill konnte nicht geladen werden", - "openFolderFailed": "Ordner konnte nicht geöffnet werden", - "noSkillDirectory": "Kein verfügbares Skill-Verzeichnis für den aktuellen Agenten gefunden", - "nameRequired": "Skill-Name darf nicht leer sein", - "updated": "Skill aktualisiert", - "created": "Skill erstellt", - "saveFailed": "Skill konnte nicht gespeichert werden", - "deleted": "Skill gelöscht", - "deleteFailed": "Skill konnte nicht gelöscht werden" - }, - "templates": { - "gemini": "---\nname: example-skill\ndescription: Describe when this skill should be used.\n---\n\n# Skill Name\n\nInstructions for the agent when this skill is active.\n\n## Workflow\n\n1. Add actionable step one.\n2. Add actionable step two.\n", - "openCode": "---\nname: example-skill\ndescription: Describe when this skill should be used.\n---\n\n# Purpose\n\nDescribe what this skill helps with.\n\n# Steps\n\n1. Add actionable step one.\n2. Add actionable step two.\n", - "openClaw": "---\nname: example-skill\ndescription: Describe when this skill should be used.\nuser-invocable: true\ndisable-model-invocation: false\n---\n\n# Purpose\n\nDescribe what this skill helps with.\n\n# Instructions\n\n1. Add actionable instruction one.\n2. Add actionable instruction two.\n", - "default": "---\nname: example-skill\ndescription: Describe when this skill should be used.\n---\n\n# Skill: example-skill\n\n## When to use\n\n- Describe trigger conditions.\n\n## Instructions\n\n1. Add actionable instruction one.\n2. Add actionable instruction two.\n" - } - }, - "McpSettings": { - "loading": "Wird geladen...", - "summary": { - "missingCommand": "(fehlender Befehl)", - "missingUrl": "(fehlende URL)" - }, - "protocol": { - "stdio": "Stdio" - }, - "errors": { - "selectInstallProtocol": "Bitte ein Installationsprotokoll auswählen", - "fieldRequired": "{field} ist erforderlich", - "fieldNeedsBoolean": "{field} muss true oder false sein", - "fieldNeedsNumber": "{field} muss eine Zahl sein", - "fieldNeedsInteger": "{field} muss eine Ganzzahl sein", - "fieldInvalidJson": "{field} enthält ungültiges JSON: {message}", - "fieldOutOfRange": "Der Wert von {field} liegt außerhalb des erlaubten Bereichs", - "jsonEmpty": "{name} darf nicht leer sein", - "jsonInvalid": "{name} ist kein gültiges JSON: {message}", - "jsonMustBeObject": "{name} muss ein JSON-Objekt sein", - "specMustBeObject": "Die MCP-Konfiguration muss ein JSON-Objekt sein.", - "missingType": "Der Konfiguration fehlt das Feld type. Bitte stdio, http (Aliase: streamable-http, streamableHttp) oder sse angeben.", - "unsupportedType": "Nicht unterstützter MCP-Typ {type}. Unterstützt: stdio, http (Aliase: streamable-http, streamableHttp), sse.", - "codexEntryUnsupportedType": "Codex-MCP-Eintrag {id} hat den nicht unterstützten Typ {type}. Unterstützt: stdio, http (Aliase: streamable-http, streamableHttp), sse.", - "unsupportedTransportType": "Nicht unterstützter Transport-Typ {type}. Unterstützt: http (Aliase: streamable-http, streamableHttp), sse.", - "stdioCommandRequired": "stdio-MCPs benötigen ein nicht leeres Feld command.", - "remoteUrlRequired": "Remote-MCPs benötigen ein nicht leeres Feld url.", - "appsRequired": "Mindestens eine Ziel-App auswählen." - }, - "jsonNames": { - "localConfig": "MCP-Konfiguration", - "installConfig": "Installationskonfiguration" - }, - "toasts": { - "uninstalled": "MCP deinstalliert", - "uninstallFailed": "Deinstallation fehlgeschlagen: {message}", - "selectAtLeastOneApp": "Bitte mindestens eine Ziel-App auswählen", - "saveSuccess": "Gespeichert", - "saveFailed": "Speichern fehlgeschlagen: {message}", - "installed": "{name} installiert", - "installFailed": "Installation fehlgeschlagen: {message}", - "serverIdRequired": "Server-ID ist erforderlich", - "serverIdExists": "Server-ID \"{id}\" existiert bereits. Bearbeiten Sie den vorhandenen Eintrag oder wählen Sie einen anderen Namen.", - "created": "MCP erstellt" - }, - "installDialog": { - "title": "MCP-Installation bestätigen", - "descriptionWithName": "{name} in lokale Konfiguration installieren.", - "description": "Ziel-Apps für die Installation auswählen.", - "protocol": "Protokoll", - "selectProtocol": "Protokoll auswählen", - "parameters": "Konfigurationsparameter", - "booleanPlaceholder": "Bitte true/false auswählen", - "selectOneValue": "Wert auswählen", - "targetApps": "Ziel-Apps" - }, - "actions": { - "cancel": "Abbrechen", - "confirmInstall": "Installation bestätigen", - "installing": "Installieren", - "uninstall": "Deinstallieren", - "uninstalling": "Deinstallieren", - "viewDetails": "Details anzeigen", - "save": "Speichern", - "saving": "Speichern", - "install": "Installieren", - "refresh": "Aktualisieren", - "newMcp": "Neuer MCP", - "create": "Erstellen", - "creating": "Wird erstellt..." - }, - "tabs": { - "local": "Lokales MCP", - "market": "MCP-Marktplatz" - }, - "local": { - "filterPlaceholder": "Lokales MCP filtern...", - "loadFailed": "Laden fehlgeschlagen: {message}", - "empty": "Kein lokales MCP erkannt.", - "description": "Die lokale MCP-Konfiguration kann direkt bearbeitet und gespeichert werden.", - "enabledApps": "Aktivierte Apps", - "configJson": "MCP-Konfiguration (JSON)", - "draftTitle": "Neuer MCP", - "draftDescription": "Geben Sie eine Server-ID und Konfiguration an, um einen lokalen MCP-Server zu erstellen.", - "serverIdLabel": "Server-ID", - "serverIdPlaceholder": "Server-ID (z. B. my-mcp)", - "typeHint": "Unterstützte Typen: stdio, http (Aliase: streamable-http, streamableHttp), sse. env wird nur von stdio verwendet; für Remote-MCPs Auth-Tokens über headers übermitteln.", - "envOnRemoteWarning": "env wurde in einem Remote-MCP erkannt. Nur stdio verwendet env; Remote-MCPs übermitteln Auth-Tokens über headers, sodass env beim Speichern ignoriert wird." - }, - "market": { - "selectMarketplace": "Marktplatz auswählen", - "searchPlaceholder": "MCP suchen...", - "searchFailed": "Suche fehlgeschlagen: {message}", - "loadingList": "MCP-Liste wird geladen...", - "empty": "Keine MCP-Ergebnisse.", - "loadingDetail": "Marktplatzdetails werden geladen...", - "detailLoadFailed": "Details konnten nicht geladen werden: {message}", - "owner": "Inhaber: {owner}", - "namespace": "Namensraum: {namespace}", - "defaultInstallProtocol": "Standard-Installationsprotokoll", - "currentOptionParameterCount": "Anzahl der Parameter der aktuellen Option: {count}", - "installConfigDescription": "Installationskonfiguration (JSON, vor der Installation bearbeitbar; Änderungen überschreiben das Protokoll-/Parameterformular)", - "selectLeftToView": "Wähle links ein Marktplatz-MCP aus, um Details anzuzeigen." - }, - "badges": { - "verified": "Verifiziert", - "remote": "Remote", - "hasHomepage": "Hat Homepage", - "uses": "{count} Nutzungen", - "deployed": "Bereitgestellt", - "notDeployed": "Nicht bereitgestellt" - }, - "selectLeftMcp": "Wähle links ein MCP aus." - }, - "AcpAgentSettings": { - "title": "Agent SDK-Verwaltung", - "description": "Verwalten Sie Agent-SDK-Verbindung, Aktivierungsstatus, Umgebungsvariablen, Konfigurationsverwaltung und Versions-Preflight-Infos zentral an einem Ort.", - "loadingAgents": "Agentenliste wird geladen...", - "agentList": "Agentenliste", - "emptyNoAgent": "Keine verfügbaren Agenten.", - "configManagement": "Konfigurationsverwaltung", - "envVars": "Umgebungsvariablen", - "hostTools": { - "label": "Dateien und Befehle vom Agenten selbst ausführen lassen", - "description": "codeg übernimmt Dateizugriffe und Terminalbefehle nicht mehr, sodass der Agent sie im eigenen Prozess ausführt – nur dort greifen seine eigene Sandbox und seine Berechtigungsregeln. Auch das Delegieren an andere Agenten wird deaktiviert, da dieselbe Arbeit sonst wieder über codeg liefe. codeg fügt selbst keine Sandbox hinzu; aktivieren Sie dies also nur, wenn im Agenten eine konfiguriert ist." - }, - "nativeJsonConfig": "Natives JSON-Config", - "modelHintDefault": "Leer lassen, um das System-Standardmodell zu verwenden.", - "generalConfigDescriptionClaude": "Unterstützt schnelle Konfiguration von API-URL, API-Key und Claude-Modellen und synchronisiert mit der nativen JSON-Konfiguration.", - "generalConfigDescriptionDefault": "Unterstützt wichtige Konfigurationseingaben (API URL, API Key, Model) und native JSON-Konfigurationsverwaltung.", - "multiAgent": { - "title": "Multi-Agent-Zusammenarbeit", - "description": "Erlaubt aktiven Agenten, Teilaufgaben an andere Agenten zu delegieren.", - "enable": "Delegation aktivieren", - "enableHint": "Wenn deaktiviert, wird das Tool delegate_to_agent im MCP-Toolkatalog des Agenten ausgeblendet.", - "withheldByHostTools": "{agents} erhalten die Delegationswerkzeuge nicht: Ihr agentenspezifischer Schalter „Dateien und Befehle vom Agenten selbst ausführen lassen“ ist aktiv.", - "selfInitiate": "Allow spawn without @", - "selfInitiateHint": "When on, an agent may start a listed sub-agent on its own. An @ mention is still always honored. When off, only an @ mention starts a sub-agent.", - "depthLimit": "Maximale Delegationstiefe", - "depthHint": "Zulässiger Bereich: {min}–{max}. Begrenzt, wie tief eine Delegationskette (Root → Kind → Enkel …) rekursieren kann.", - "completedCacheLabel": "Cache abgeschlossener Ergebnisse (MB)", - "completedCacheHint": "In-Memory-Cache abgeschlossener Subagent-Ergebnisse, der nur gehalten wird, solange die Delegationssitzung läuft, und beim Ende dieser Sitzung automatisch freigegeben wird. Bei Überschreitung dieses Budgets werden die ältesten Ergebnisse zuerst aus dem Speicher verworfen (weiterhin in der eigenen Sitzung des Subagenten einsehbar); 0 = unbegrenzt (wird trotzdem beim Sitzungsende freigegeben).", - "save": "Speichern", - "saving": "Wird gespeichert…", - "saved": "Delegationseinstellungen gespeichert", - "saveFailed": "Delegationseinstellungen konnten nicht gespeichert werden", - "loadFailed": "Delegationseinstellungen konnten nicht geladen werden: {detail}", - "tabGeneral": "Allgemein", - "tabAgentDefaults": "Subagent-Standards", - "agentDefaultsDescription": "Pro-Agent-Überschreibungen, die angewendet werden, wenn die Multi-Agent-Zusammenarbeit einen Subagenten für einen Delegationsaufruf startet. Die hier gezeigten Optionen stammen aus einer Live-Abfrage – Ihre Auswahl ist exakt das, was der Agent akzeptiert.", - "probing": "Verfügbare Optionen vom Agenten werden geladen…", - "probeFailed": "Optionen konnten nicht geladen werden: {detail}", - "retry": "Erneut versuchen", - "noConfigAvailable": "Dieser Agent hat keine konfigurierbaren Optionen.", - "modeLabel": "Modus", - "agentDefaultHint": "Agent-Standard: {value}", - "defaultOptionLabel": "Standard ({value})" - }, - "actions": { - "dragSort": "Zum Neuordnen ziehen", - "dragSortAgent": "{name} zum Neuordnen ziehen", - "refreshCheck": "Prüfung aktualisieren", - "refreshCheckAgent": "Prüfung für {name} aktualisieren", - "clickEnable": "Klicken, um {name} zu aktivieren", - "clickDisable": "Klicken, um {name} zu deaktivieren", - "install": "Installieren", - "upgrade": "Aktualisieren", - "uninstall": "Deinstallieren", - "uninstalling": "Wird deinstalliert...", - "saveEnvVars": "Umgebungsvariablen speichern", - "saving": "Speichern...", - "saveGrokConfig": "Grok-Konfiguration speichern", - "saveCodexConfig": "Codex-Konfiguration speichern", - "saveGeminiConfig": "Gemini-Konfiguration speichern", - "saveOpenCodeConfig": "OpenCode-Konfiguration speichern", - "saveOpenClawConfig": "OpenClaw-Konfiguration speichern", - "saveConfigManagement": "Konfigurationsverwaltung speichern", - "saveCurrentProvider": "Aktuellen Provider speichern", - "showApiKey": "API-Key anzeigen", - "hideApiKey": "API-Key ausblenden", - "showKey": "Schlüssel anzeigen", - "hideKey": "Schlüssel ausblenden", - "showToken": "Token anzeigen", - "hideToken": "Token ausblenden", - "cancel": "Abbrechen", - "delete": "Löschen", - "deleting": "Löschen...", - "confirmDelete": "Löschen bestätigen", - "confirmUninstall": "Deinstallation bestätigen", - "saveClineConfig": "Cline-Konfiguration speichern", - "saveHermesConfig": "Hermes-Konfiguration speichern", - "saveCodeBuddyConfig": "CodeBuddy-Konfiguration speichern", - "saveKimiCodeConfig": "Kimi-Code-Konfiguration speichern", - "customInstall": "Benutzerdefinierte Installation", - "saveKimiCodeRawConfig": "Save config.toml", - "saveDeepSeekConfig": "DeepSeek-Konfiguration speichern", - "diagnose": "Diagnose" - }, - "status": { - "enabled": "Aktiviert", - "disabled": "Deaktiviert", - "unchecked": "Nicht geprüft", - "agentEnabledAria": "{name} aktiviert", - "agentEnabledSwitch": "{name} Aktivierungsschalter" - }, - "preflight": { - "count": "Preflight-Elemente: {count}", - "notRun": "Prüfungen wurden noch nicht ausgeführt." - }, - "grok": { - "configDescription": "Konfiguriere Grok hier. Die folgenden Steuerelemente – Berechtigungsmodus, Reasoning-Aufwand, ein optionales benutzerdefiniertes Modell (eigener Endpunkt) und die Verdichtung – werden in ~/.grok/config.toml zusammengeführt, wobei deine anderen Schlüssel und Kommentare erhalten bleiben. Die Anmeldung nutzt deinen XAI_API_KEY oder `grok login`. Weitere Schlüssel bleiben unter „Erweitert“ bearbeitbar.", - "permissionModeLabel": "Berechtigungsmodus", - "permissionDefault": "Jedes Mal fragen", - "permissionAcceptEdits": "Bearbeitungen automatisch genehmigen", - "permissionAuto": "Intelligente Auto-Genehmigung", - "permissionAlwaysApprove": "Immer zulassen", - "reasoningEffortLabel": "Denkaufwand", - "effortLow": "Niedrig (schneller)", - "effortMedium": "Mittel (ausgewogen)", - "effortHigh": "Hoch", - "effortXhigh": "Maximal", - "optionDefault": "Standard verwenden", - "authTitle": "Authentifizierung", - "authMode": "Authentifizierungsmethode", - "authModeApiKey": "XAI-API-Schlüssel", - "authModeApiKeyHint": "Authentifiziere dich mit einem XAI_API_KEY aus der xAI-Konsole – für nicht-interaktive oder Headless-Läufe. Wird in der Umgebung dieses Agenten gespeichert.", - "authModeCustom": "Benutzerdefinierter Endpunkt", - "authModeCustomHint": "Verwende einen eigenen Endpunkt (BYO): Definiere unten ein benutzerdefiniertes Modell mit eigener Basis-URL und eigenem API-Schlüssel. Es wird zum Standardmodell von Grok.", - "subscriptionHint": "Melde dich mit `grok login` an (SuperGrok / X Premium+). Es wird kein API-Schlüssel gespeichert.", - "loginHint": "Führe dies in einem Terminal aus, um dich anzumelden, und öffne dann diese Einstellungen erneut:", - "commandCopied": "Befehl in die Zwischenablage kopiert", - "copyCommand": "Befehl kopieren", - "authKeyConfigured": "XAI_API_KEY ist konfiguriert.", - "authKeyMissing": "Kein XAI_API_KEY festgelegt.", - "advancedToggle": "Erweitert (rohe config.toml)", - "configTomlNative": "config.toml (nativ)", - "configTomlHint": "Wird wortwörtlich als gesamte ~/.grok/config.toml gespeichert. Ungültiges TOML wird abgelehnt, sodass ein Tippfehler deine Datei nie abschneidet.", - "configTomlPlaceholder": "# Andere Schlüssel als die Steuerelemente oben, z. B.\n# [mcp_servers.*], [cli], [permission]-Regeln.", - "customModelTitle": "Benutzerdefiniertes Modell (eigener Endpunkt)", - "customModelHint": "Richte Grok auf einen benutzerdefinierten oder selbst gehosteten Endpunkt. codeg schreibt einen `[model.*]`-Block pro Modell und legt es als Standard fest. Lasse die Modell-ID leer, um es zu entfernen.", - "customModelIdLabel": "Modell-ID", - "customModelIdPlaceholder": "grok-4.5", - "customModelIdHint": "Wird als `[model.*]`-Block registriert und als Modellname an die API gesendet; außerdem als `[models].default` gesetzt.", - "customBaseUrlLabel": "Basis-URL", - "customBaseUrlPlaceholder": "https://api.x.ai/v1 (Standard)", - "customApiBackendLabel": "API-Backend", - "backendResponses": "Responses", - "backendChatCompletions": "Chat Completions", - "backendMessages": "Messages (Anthropic)", - "customApiKeyLabel": "API-Schlüssel", - "customApiKeyHint": "Inline in `[model.*].api_key` gespeichert, nur für diesen Endpunkt.", - "customContextWindowLabel": "Kontextfenster (Tokens)", - "customContextWindowHint": "Optional. Steuert den Zeitpunkt der automatischen Verdichtung; leer lassen für den Standard des Endpunkts.", - "autoCompactLabel": "Schwellenwert für Auto-Verdichtung (%)", - "autoCompactHint": "Verdichtet die Unterhaltung, wenn die Kontextnutzung diesen Prozentsatz erreicht (Grok-Standard 85). Wird in `[session]` geschrieben." - }, - "cursor": { - "configDescription": "Konfiguriere Cursor hier. Wähle eine Authentifizierungsmethode – offizielles Abo (Browser-Anmeldung) oder einen Cursor-API-Schlüssel für Headless-/Servermaschinen – wähle dann ein Modell und bearbeite die Berechtigungsregeln und die Sandbox des CLI. codeg schreibt sie in ~/.cursor/cli-config.json, gemeinsam mit dem cursor-agent-CLI.", - "authTitle": "Authentifizierung", - "authChecking": "Prüfe…", - "authNotInstalled": "cursor-agent ist nicht installiert", - "authLoggedIn": "Angemeldet", - "authNotLoggedIn": "Nicht angemeldet", - "loginHint": "Führe dies im Terminal aus, um dich mit deinem Cursor-Konto anzumelden (ein Browserfenster öffnet sich), und klicke danach auf Aktualisieren:", - "apiKeyLabel": "Cursor-API-Schlüssel", - "apiKeyPlaceholder": "Schlüssel von cursor.com/dashboard", - "apiKeyHint": "CURSOR_API_KEY – ein Cursor-Dashboard-Kontoschlüssel, Alternative zur Browser-Anmeldung für Headless-/Servermaschinen. Kein Drittanbieter- oder OpenAI-Schlüssel.", - "modelTitle": "Standardmodell", - "loadModels": "Modelle laden", - "modelsUnavailable": "Modellliste nicht verfügbar", - "modelHint": "Wird der CLI beim Sitzungsstart als --model übergeben. Auf Standard lassen, damit Cursor wählt.", - "permissionsTitle": "Berechtigungen & Sandbox", - "permissionsDescription": "Visueller Editor für die Berechtigungsregeln der CLI (cli-config.json). Erlaubte Regeln laufen ohne Rückfrage; verweigerte werden immer blockiert.", - "permissionModeLabel": "Berechtigungsmodus", - "permissionModeDefault": "Vor der Ausführung fragen (Standard)", - "permissionModeForce": "Run Everything (--force)", - "permissionModeHint": "Run Everything startet Sitzungen mit --force: Alle Tool-Aufrufe werden ohne Rückfrage automatisch erlaubt, außer Deny-Regeln (eine Organisationsrichtlinie kann dies auf Allow-Regeln beschränken). Gilt für neue Sitzungen.", - "optionDefault": "Standard (nicht gesetzt)", - "sandboxLabel": "Sandbox", - "sandboxEnabled": "Aktiviert", - "sandboxDisabled": "Deaktiviert", - "allowRulesLabel": "Erlauben-Regeln", - "denyRulesLabel": "Verweigern-Regeln", - "addRule": "Regel hinzufügen", - "rulesSyntaxHint": "Regelsyntax: Shell(Befehl), Read(Pfad/Glob), Write(Pfad/Glob), WebFetch(Domain), Mcp(Server:Tool) — Deny-Regeln haben immer Vorrang.", - "saveConfig": "Konfiguration speichern", - "advancedToggle": "Erweitert: rohe cli-config.json", - "advancedHint": "Die komplette ~/.cursor/cli-config.json. Speichern schreibt die Datei unverändert; die strukturierten Steuerelemente oben werden stattdessen zusammengeführt.", - "saveRawConfig": "Datei speichern", - "authMode": "Authentifizierungsmethode", - "subscriptionHint": "Mit deinem Cursor-Konto anmelden und Cursors Modelle verwenden.", - "customApiKeyRequired": "Ein Cursor-API-Schlüssel ist erforderlich.", - "authModeApiKey": "Cursor-API-Schlüssel (Headless/Server)", - "authModeApiKeyHint": "Mit einem Cursor-Konto-API-Schlüssel aus dem Cursor-Dashboard authentifizieren (für Headless-/Servermaschinen). Das ist ein Cursor-Kontoschlüssel, kein Drittanbieter-/OpenAI-Endpunkt – cursor-agent kommuniziert nur mit dem Cursor-Backend. Um einen codex-/OpenAI-kompatiblen Endpunkt zu nutzen, verwende stattdessen den Codex-Agenten.", - "modelPickerPlaceholder": "Modelle suchen…", - "modelNoMatch": "Kein passendes Modell", - "modelsNeedAuth": "Melde dich an, um die Modellliste zu laden.", - "modelDefaultBadge": "Standard" - }, - "deepseek": { - "configManagement": "DeepSeek-Harness-Konfiguration", - "configDescription": "Endpunkt und Schlüssel sind Umgebungsvariablen, die deepseek-acp beim Start liest. Modell und Denkstufe sind Auswahlfelder pro Sitzung — sie werden im Eingabefeld gewählt.", - "baseUrlLabel": "API-Endpunkt", - "baseUrlHint": "Leer lassen für den offiziellen Endpunkt. Gilt für Sitzungen, die nach dem Speichern starten – eine laufende Sitzung muss neu verbinden.", - "baseUrlInvalid": "Vollständige http(s)-URL ohne Query-String eingeben, zum Beispiel https://api.deepseek.com", - "apiKeyLabel": "API-Schlüssel", - "apiKeyHint": "Wird dem Agenten als DEEPSEEK_API_KEY übergeben. Eine Umgebungsvariable hat Vorrang vor der Zugangsdatendatei – lass das Feld leer, wenn du dich im Terminal anmeldest." - }, - "codex": { - "configDescription": "Unterstützt schnelle Konfiguration von API-URL, API-Key, Modellname und reasoning effort und synchronisiert mit `auth.json` / `config.toml`.", - "authMode": "Authentifizierungsmodus", - "chatgptSubscription": "Offizielles Abonnement", - "chatgptSubscriptionHint": "Mit offiziellem ChatGPT-Abonnement anmelden, kein API Key erforderlich", - "apiKeyHint": "Mit API Key zu OpenAI oder kompatiblen API-Diensten verbinden", - "selectProvider": "Provider auswählen", - "modelName": "Modellname", - "selectReasoningEffort": "Reasoning Effort auswählen", - "enableWebsocket": "WebSocket aktivieren", - "enableWebsocketAria": "WebSocket für Codex Provider aktivieren", - "enableSkills": "Skills aktivieren", - "enableSkillsAria": "Skills für Codex aktivieren", - "enableFast": "Fast aktivieren", - "enableFastAria": "Fast-Servicestufe für Codex aktivieren", - "sandboxGroupTitle": "Sandbox und Freigaben", - "sandboxGroupHint": "Wird in die globale ~/.codex/config.toml geschrieben und gilt daher auch für codex-CLI- und IDE-Sitzungen. Es sind Thread-Standardwerte: Sie gelten für Turns, die codex selbst startet (/goal, /review, /compact). Normale Eingaben nutzen die Freigabe-Voreinstellung des Eingabefelds. Änderungen greifen nach einem Neustart der Sitzung.", - "sandboxShadowedWarning": "config.toml setzt default_permissions, daher löst codex Berechtigungen über dieses Profil auf und ignoriert sandbox_mode vollständig. Entferne default_permissions, um die Optionen unten zu nutzen.", - "sandboxPermissionsTableWarning": "config.toml definiert [permissions]-Profile, aber kein default_permissions — damit verweigert codex den Start. Setze es im Rohtext-Editor unten.", - "approvalPolicyLabel": "Freigaberichtlinie", - "approvalPolicyUnset": "Nicht gesetzt (codex-Standard: auf Anfrage)", - "approvalPolicy_on-request": "Auf Anfrage – das Modell entscheidet, wann es nachfragt", - "approvalPolicy_untrusted": "Nicht vertrauenswürdig – nur bekannt sichere Lesebefehle laufen ohne Nachfrage", - "approvalPolicy_never": "Nie – keinerlei Freigabeabfragen", - "approvalPolicy_granular": "Granular – pro Abfragetyp festlegen", - "approvalPolicyUntrustedAcpWarning": "Für „untrusted“ gibt es unter den drei Freigabe-Voreinstellungen des ACP-Adapters keine Entsprechung, daher fallen codeg-Sitzungen auf „auf Anfrage“ zurück: Das Modell entscheidet dann selbst, wann es fragt, und Befehle, die die Sandbox ohnehin erlaubt, fragen nicht mehr nach. Schränke stattdessen unten den Sandbox-Modus ein.", - "granularHint": "Aus bedeutet, dass Anfragen dieser Art automatisch abgelehnt statt angezeigt werden.", - "granular_sandbox_approval": "Rechteerweiterung für Shell-Befehle", - "granular_rules": "Abfragen aus Execpolicy-Regeln", - "granular_skill_approval": "Abfragen bei Skill-Skripten", - "granular_request_permissions": "Abfragen des request_permissions-Tools", - "granular_mcp_elicitations": "MCP-Elicitation-Abfragen", - "sandboxModeLabel": "Sandbox-Modus", - "sandboxModeUnset": "Nicht gesetzt (vertrauenswürdige Ordner fallen auf Workspace-Schreibzugriff zurück)", - "sandboxMode_read-only": "Nur lesen", - "sandboxMode_workspace-write": "Workspace-Schreibzugriff", - "sandboxMode_danger-full-access": "Vollzugriff (keine Sandbox)", - "sandboxModeHint": "Unter Windows wird Workspace-Schreibzugriff auf Nur-Lesen herabgestuft, sofern die experimentelle Windows-Sandbox von codex nicht aktiviert ist.", - "sandboxModeSeedsPresetHint": "codeg leitet daraus auch die anfängliche Freigabe-Voreinstellung der Sitzung ab — anders als die Freigaberichtlinie wirkt es also auch auf normale Anfragen. Die im Eingabefeld gewählte Voreinstellung hat weiterhin Vorrang.", - "writableRootsLabel": "Zusätzliche beschreibbare Ordner", - "writableRootsHint": "Ein absoluter Pfad pro Zeile, zusätzlich zum Arbeitsverzeichnis.", - "sandboxRootsRelativeError": "Muss ein absoluter Pfad sein – codex löst relative Angaben unter ~/.codex auf: {path}", - "networkAccessLabel": "Netzwerkzugriff erlauben", - "excludeTmpdirLabel": "TMPDIR von den beschreibbaren Wurzeln ausschließen", - "excludeSlashTmpLabel": "/tmp von den beschreibbaren Wurzeln ausschließen", - "authJsonNative": "auth.json (nativ)", - "configTomlNative": "config.toml (nativ)", - "loginButton": "Mit ChatGPT anmelden", - "loginRequesting": "Login-Code wird angefordert...", - "loginStep1": "Öffnen Sie die folgende URL in Ihrem Browser:", - "loginStep2": "Geben Sie den folgenden Code ein:", - "loginPolling": "Warte auf Autorisierung...", - "loginCancel": "Abbrechen", - "loginSuccess": "Erfolgreich angemeldet, Konfiguration gespeichert!", - "loginFailed": "Anmeldung fehlgeschlagen: {message}", - "loginRetry": "Erneut versuchen", - "loginCodeCopied": "Code kopiert", - "loggedIn": "Konto angemeldet", - "loginRelogin": "Erneut anmelden / Konto wechseln", - "loginTimeout": "Anmeldung abgelaufen, bitte erneut versuchen", - "loginSaveFailed": "Anmeldung erfolgreich, aber Konfiguration konnte nicht gespeichert werden" - }, - "gemini": { - "authConfig": "Gemini-Auth-Konfiguration", - "authConfigDescription": "Ausgerichtet an den Gemini CLI-Authentifizierungsdokumenten, mit Unterstützung für benutzerdefinierten Endpoint, Google-Login, Gemini API Key und Vertex AI (ADC / Servicekonto / API Key).", - "authMode": "Auth-Modus", - "selectAuthMode": "Auth-Modus auswählen", - "viewAuthDoc": "Auth-Dokumentation anzeigen", - "mode": { - "custom": "Benutzerdefinierter Endpoint", - "loginGoogle": "Google-Login (OAuth)", - "vertexServiceAccount": "Vertex AI (Servicekonto)" - }, - "hint": { - "custom": "API URL, API Key und Modell ausfüllen; wird auf GOOGLE_GEMINI_BASE_URL / GEMINI_API_KEY / GEMINI_MODEL abgebildet.", - "loginGoogle": "Gemini zuerst im Terminal ausführen und Google-Login abschließen; API key ist nicht erforderlich.", - "geminiApiKey": "Beim Verwenden der Gemini API GEMINI_API_KEY eintragen.", - "vertexAdc": "gcloud ADC verwenden; GOOGLE_CLOUD_PROJECT und GOOGLE_CLOUD_LOCATION werden empfohlen.", - "vertexServiceAccount": "Pfad zur Servicekonto-JSON in GOOGLE_APPLICATION_CREDENTIALS setzen.", - "vertexApiKey": "Beim Verwenden eines Vertex AI API Keys GOOGLE_API_KEY eintragen." - } - }, - "openCode": { - "configManagement": "OpenCode-Konfigurationsverwaltung", - "configDescription": "An OpenCode-`provider`-Schema ausgerichtet, unterstützt Multi-Provider-Verwaltung und bidirektionale Synchronisierung mit nativen JSON-Dateien.", - "providerManagement": "Provider-Verwaltung", - "providerCount": "{count} Provider", - "addProvider": "Provider hinzufügen", - "emptyProvider": "Noch keine benutzerdefinierten Provider. Klicke auf Benutzerdefinierten Provider hinzufügen, um einen zu erstellen.", - "providerEnabledState": "{providerId} Aktivierungsstatus", - "selectProviderNpm": "provider.npm auswählen", - "modelManagement": "Modellverwaltung", - "modelCount": "{count} Modelle", - "modelDescription": "Ausgerichtet an OpenCode `provider.models`. Schnellverwaltung unterstützt derzeit `name` / `id`; andere erweiterte Felder bleiben erhalten und können unten im nativen JSON bearbeitet werden.", - "addModel": "Modell hinzufügen", - "emptyModel": "Noch kein Modell vorhanden. model id eingeben und dann auf „Modell hinzufügen“ klicken.", - "modelId": "Modell-ID", - "modelName": "Modellname", - "deleteModel": "Modell {modelId} löschen", - "nativeJsonConfig": "OpenCode Native JSON-Konfiguration", - "mainModel": "Hauptmodell", - "smallModel": "Kleines Modell", - "noMatchingModels": "Keine passenden Modelle", - "connectProvider": "Provider verbinden", - "connectedProviders": "Verbundene Provider", - "noConnectedProviders": "Noch keine Katalog-Provider verbunden.", - "advancedProviderConfig": "Benutzerdefinierte Provider", - "customProviderConfigHint": "OpenAI-kompatible Endpunkte, die du selbst definierst – ein Provider-Block in opencode.json, mit dem API-Key in auth.json.", - "addCustomProvider": "Benutzerdefinierten Provider hinzufügen", - "disconnect": "Trennen", - "editConfig": "Bearbeiten", - "customBadge": "Benutzerdefiniert", - "authKindApi": "API-Schlüssel", - "authKindOauth": "OAuth", - "authKindNone": "Keine Anmeldedaten", - "connect": { - "title": "Provider verbinden", - "description": "Wähle einen Provider aus dem models.dev-Katalog. Anmeldedaten werden in der auth.json-Datei von OpenCode gespeichert.", - "pick": "Provider", - "search": "Provider suchen…", - "loading": "Katalog wird geladen…", - "catalogLabel": "models.dev-Katalog", - "modelsAvailable": "{count} Modelle verfügbar", - "getKey": "API-Schlüssel holen", - "oauthApiKeyNote": "Dieser Provider unterstützt auch die Browser-Anmeldung über opencode auth login. Die Browser-Anmeldung kommt bald — füge vorerst einen API-Schlüssel ein.", - "apiKey": "API-Schlüssel", - "apiKeyHint": "Wird in auth.json gespeichert, nie in opencode.json.", - "baseUrlOptional": "Basis-URL überschreiben (optional)", - "providerId": "Provider-ID", - "displayName": "Anzeigename", - "modelsList": "Modelle (eins pro Zeile)", - "modelsHint": "Modell-IDs, die der Endpunkt akzeptiert.", - "action": "Verbinden", - "editTitle": "Provider bearbeiten", - "editDescription": "Aktualisiere den API-Schlüssel oder die Basis-URL dieses Providers.", - "saveAction": "Speichern" - }, - "customProvider": { - "title": "Benutzerdefinierten Provider hinzufügen", - "description": "Definiere einen OpenAI-kompatiblen Endpunkt. Der API-Key wird in auth.json gespeichert, der Provider-Block in opencode.json.", - "action": "Provider hinzufügen", - "idInCatalog": "{providerId} ist ein bekannter Provider – verbinde ihn stattdessen über Provider verbinden." - }, - "refreshCatalog": "Katalog aktualisieren", - "reasoningBadge": "Reasoning", - "contextWindow": "Kontextfenster", - "permissions": { - "title": "Berechtigungen", - "description": "Legt fest, welche Aktionen einfach laufen, welche vorher nachfragen und welche blockiert werden. Wird in den permission-Block von opencode.json geschrieben und mit dem Speichern unten übernommen.", - "docsLink": "Dokumentation zu Berechtigungen", - "unparsableConfig": "Das native JSON unten ist ungültig, deshalb pausiert der visuelle Editor. Korrigiere das JSON, um fortzufahren.", - "invalidBlock": "Der permission-Block hat eine Form, die codeg nicht kennt. Bearbeite ihn im nativen JSON unten oder beginne mit Zurücksetzen neu.", - "orderingUnsafe": "Eine Wildcard-Regel steht hinter konkreten Tools, deshalb wendet OpenCode sie auch auf diese an – die Zeilen unten sind nicht das, was tatsächlich gilt. Reihenfolge korrigieren schiebt jede Wildcard nur wieder an den Anfang ihres Bereichs, ohne einen Wert zu ändern.", - "orderingUnsafeManual": "Eine Regel wird von einem späteren, allgemeineren Muster verdeckt, OpenCode wendet sie also nie an – die Zeilen unten sind nicht das, was tatsächlich gilt. Für zwei überlappende Muster gibt es keine eine richtige Reihenfolge; sortiere sie im nativen JSON so, dass das allgemeinere zuerst steht.", - "fixOrder": "Reihenfolge korrigieren", - "agentOverrides": "Diese Agenten überschreiben Berechtigungen und werden zuletzt angewendet, gewinnen also gegen alles hier: {agents}. Bearbeite sie im nativen JSON unten oder schalte die automatische Annahme ein, um sie zu löschen.", - "legacyTools": "Die veraltete tools-Map auf oberster Ebene verweigert ein Tool. OpenCode führt sie mit den Berechtigungen zusammen, sie gilt also über allem hier Gezeigten. Bearbeite sie im nativen JSON unten oder schalte die automatische Annahme ein, um sie zu löschen.", - "autoAcceptTitle": "Alle Berechtigungen automatisch annehmen", - "autoAcceptHint": "Jeder Tool-Aufruf – Shell-Befehle, Dateiänderungen, Pfade außerhalb des Projekts – läuft ohne Rückfrage. Beim Einschalten ersetzt eine einzige Alles-erlauben-Regel die Einstellungen pro Tool unten, und die Overrides einzelner Agenten sowie veraltete tools-Schalter, die sonst weiter blockieren würden, werden gelöscht.", - "globalLabel": "Globaler Standard", - "globalHint": "Die Regel *: gilt für alles, was die Tools unten nicht überschreiben.", - "actionUnset": "Nicht gesetzt (OpenCode-Standard)", - "actionInherit": "Standard übernehmen ({action})", - "actionAllow": "Erlauben", - "actionAsk": "Nachfragen", - "actionDeny": "Verweigern", - "perToolTitle": "Berechtigungen pro Tool", - "reset": "Zurücksetzen", - "ruleCount": "Regeln: {count}", - "rulesToggle": "Feingranulare Regeln für {tool}", - "rulesHint": "Wird gegen die Tool-Eingabe geprüft, die letzte Übereinstimmung gewinnt – schreibe die weiten Muster also zuerst. * passt auf beliebig viele Zeichen, ? auf genau eines, und ein führendes ~ wird zu deinem Home-Verzeichnis.", - "noRules": "Noch keine feingranularen Regeln.", - "addRule": "Regel hinzufügen", - "deleteRule": "Regel {pattern} löschen", - "duplicateRule": "Dieses Muster gibt es bereits.", - "blankRule": "Eine Regel braucht ein Muster – zum Entfernen das Papierkorb-Symbol nutzen.", - "customKeys": "Weitere Berechtigungsschlüssel in der Datei", - "customKeyHint": "Kein eingebautes OpenCode-Tool – bleibt unverändert erhalten.", - "keys": { - "bash": "Shell-Befehle ausführen, geprüft am geparsten Befehl", - "edit": "Alle Dateiänderungen: edit, write und patch", - "read": "Dateien lesen, geprüft am Pfad", - "external_directory": "Pfade außerhalb des Projektarbeitsverzeichnisses erreichen", - "task": "Subagenten starten, geprüft am Subagenten-Typ", - "skill": "Skills laden, geprüft am Skill-Namen", - "glob": "Dateien finden, geprüft am Glob-Muster", - "grep": "Dateiinhalte durchsuchen, geprüft am Muster", - "list": "Verzeichnisinhalte auflisten", - "webfetch": "Eine URL abrufen", - "websearch": "Im Web suchen", - "lsp": "LSP-Abfragen ausführen", - "todowrite": "Die To-do-Liste schreiben", - "question": "Dir eine Frage stellen", - "doom_loop": "Löst aus, wenn sich derselbe Aufruf dreimal mit gleicher Eingabe wiederholt" - } - } - }, - "openClaw": { - "gatewayConfig": "Gateway-Konfiguration", - "gatewayDescription": "OpenClaw-Gateway-Verbindung konfigurieren. Unterstützt lokales oder entferntes Gateway.", - "gatewayUrlHint": "Leer lassen, um gateway.remote.url aus der lokalen openclaw-Konfiguration zu verwenden.", - "gatewayTokenPlaceholder": "Gateway-Auth-Token", - "gatewayTokenHint": "Wenn möglich token-file statt Klartext-Token verwenden; über openclaw CLI konfigurieren.", - "sessionKeyHint": "Optional. Gateway-Session-Key angeben; leer lassen für automatische Zuweisung einer isolierten Session." - }, - "hermes": { - "configManagement": "Hermes-Konfiguration", - "configDescription": "Hermes verwaltet seine eigenen Anmeldedaten in ~/.hermes/.env und die Einstellungen in ~/.hermes/config.yaml. Wähle einen Anbieter und lege dann den API-Schlüssel und das Modell fest – codeg schreibt beide Dateien für dich.", - "providerLabel": "Anbieter", - "providerHint": "Der Anbieter legt fest, welche API-Schlüssel-Variable und welchen model.provider Hermes verwendet. OAuth-Anbieter werden über die Terminal-Einrichtung unten konfiguriert.", - "groupApiKey": "Anbieter mit API-Schlüssel", - "groupOauth": "OAuth-Anbieter", - "groupAws": "AWS", - "apiKeyHint": "Wird in ~/.hermes/.env gespeichert. Er wird niemals in den Prozess eingeschleust – Hermes liest ihn aus seiner eigenen Konfiguration.", - "modelName": "Modell", - "oauthHint": "Dieser Anbieter verwendet OAuth. Führe die Einrichtung unten aus, um dich im Terminal zu authentifizieren.", - "awsHint": "Bedrock verwendet deine AWS-Anmeldedaten (Umgebung oder gemeinsame Konfiguration). Lege oben die Modell-ID fest und konfiguriere den AWS-Zugriff in deiner Umgebung.", - "unsupportedProvider": "Dieser Anbieter lässt sich nicht über strukturierte Felder bearbeiten. Verwende den config.yaml-Editor unten oder die Terminal-Einrichtung.", - "setupTitle": "Selbstverwaltete Einrichtung", - "setupHint": "Die interaktive Einrichtung von Hermes benötigt ein Terminal. Starte sie unten oder kopiere den Befehl, um sie selbst auszuführen.", - "runSetup": "Hermes-Einrichtung ausführen", - "configureModel": "Modell konfigurieren", - "openConfigFolder": "~/.hermes öffnen", - "copyCommand": "Befehl kopieren", - "commandCopied": "Befehl in die Zwischenablage kopiert", - "advancedTitle": "Erweitert: config.yaml bearbeiten", - "rawConfigHint": "Bearbeite ~/.hermes/config.yaml direkt. Das Speichern hier überschreibt die Datei wortwörtlich.", - "saveRawConfig": "config.yaml speichern" - }, - "codebuddy": { - "configManagement": "CodeBuddy-Konfiguration", - "configDescription": "CodeBuddy authentifiziert sich mit einem API-Schlüssel. Builds für Festlandchina erfordern zudem die Umgebung „China (internal)“; iOA-Builds verwenden „iOA“. Der internationale Build lässt sie ungesetzt.", - "apiKeyLabel": "API-Schlüssel", - "apiKeyHint": "Wird als CODEBUDDY_API_KEY für diesen Agenten gespeichert. Alternativ kannst du dich mit der CodeBuddy-CLI im Terminal anmelden.", - "apiKeyHintSelfHosted": "Wird als CODEBUDDY_API_KEY für diesen Agenten gespeichert. Verwende den von deiner privaten Bereitstellung ausgestellten Schlüssel.", - "environmentLabel": "Umgebung", - "environmentHint": "Legt CODEBUDDY_INTERNET_ENVIRONMENT fest. Festlandchina muss „China (internal)“ verwenden; der internationale Build lässt es ungesetzt.", - "envOverseas": "International (Standard)", - "envChina": "China (internal)", - "envIoa": "iOA", - "envSelfHosted": "Selbst gehostet (private Bereitstellung)", - "baseUrlLabel": "Bereitstellungs-URL", - "baseUrlPlaceholder": "https://codebuddy.your-company.com", - "baseUrlHint": "Wird als CODEBUDDY_BASE_URL gespeichert und richtet CodeBuddy auf deinen privaten Endpunkt. Bei Selbsthosting bleibt die Netzwerkumgebung (CODEBUDDY_INTERNET_ENVIRONMENT) ungesetzt.", - "baseUrlInvalid": "Gib eine gültige http(s)-URL ein.", - "loginHint": "Kein API-Schlüssel? Führe „codebuddy“ im Terminal aus, um dich stattdessen mit deinem Tencent-Konto anzumelden." - }, - "kimiCode": { - "configManagement": "Kimi-Code-Konfiguration", - "configDescription": "`kimi acp` akzeptiert nur ein gespeichertes Login-Token, daher schreibt codeg einen verwalteten Provider in ~/.kimi-code/config.toml und legt lokal ein Gate-Token an – die Inferenz läuft weiterhin über deinen eigenen Schlüssel.", - "statusUnconfigured": "Noch nicht konfiguriert", - "statusDirty": "Nicht gespeicherte Änderungen", - "summaryLabel": "Aktiv", - "gateReadyApiKey": "API-Schlüssel in config.toml geschrieben", - "gateReadyLogin": "Mit einem Kimi-Konto angemeldet", - "revealConfig": "Im Ordner anzeigen", - "envOverrideWarning": "{keys} ist gesetzt und hat Vorrang vor config.toml. Beim Speichern hier wird die Variable entfernt.", - "authModeLabel": "Authentifizierungsmethode", - "authModeApiKey": "API-Schlüssel", - "authModeLogin": "Kimi-Konto-Anmeldung (Abo)", - "authModeApiKeyHint": "Schreibt einen verwalteten Provider in config.toml und legt das Gate-Token an, damit Sitzungen geöffnet werden können.", - "loginHint": "Führe `kimi login` im Terminal aus, um dich mit einem Kimi-Abo-Konto anzumelden. codeg speichert nichts und nutzt Kimis eigene Anmeldung. Speichern hier entfernt codegs API-Schlüssel-Gate-Token.", - "credentialTitle": "Zugangsdaten", - "interfaceTypeLabel": "Provider-Typ", - "interfaceTypeHint": "Das Provider-Protokoll, das Kimi spricht (`type` in config.toml). Für einen Moonshot-/platform.kimi.com-Schlüssel Kimi / Moonshot wählen.", - "endpointLabel": "Endpunkt", - "endpointCustom": "Benutzerdefiniert (OpenAI-kompatibel)", - "endpointHint": "International = api.moonshot.ai; China (platform.kimi.com-Schlüssel) = api.moonshot.cn. Benutzerdefiniert zeigt auf einen beliebigen OpenAI-kompatiblen Endpunkt.", - "regionInternational": "International (api.moonshot.ai)", - "regionChina": "China (api.moonshot.cn)", - "baseUrlLabel": "Basis-URL", - "baseUrlHint": "Leer lassen, um den Standardwert des Provider-SDK zu verwenden.", - "apiKeyLabel": "API-Schlüssel", - "apiKeyHint": "Wird in ~/.kimi-code/config.toml geschrieben und für die Inferenz verwendet. Von platform.kimi.com oder platform.kimi.ai.", - "vertexProjectLabel": "GCP-Projekt (GOOGLE_CLOUD_PROJECT)", - "vertexLocationLabel": "GCP-Region (GOOGLE_CLOUD_LOCATION)", - "vertexHint": "Vertex AI nutzt Google Application Default Credentials – führe `gcloud auth application-default login` aus (kein API-Schlüssel nötig).", - "modelTitle": "Modell", - "modelLabel": "Modell", - "modelHint": "Die Modell-ID, die in config.toml geschrieben wird. Über „Testen & Modelle laden“ siehst du, worauf dein Schlüssel tatsächlich zugreifen kann.", - "maxContextLabel": "Maximale Kontextgröße", - "maxContextHint": "Vom Kimi-Schema vorgeschrieben: Fehlt der Wert, verwirft Kimi den gesamten Modellblock und jede Anfrage bleibt ohne Antwort. Standard 262144.", - "fetchModels": "Testen & Modelle laden", - "fetchModelsOk": "Schlüssel funktioniert – {count} Modelle verfügbar", - "fetchModelsEmpty": "Schlüssel funktioniert, es wurden aber keine Modelle zurückgegeben", - "fetchModelsFailed": "Test fehlgeschlagen", - "fetchModelsNeedsKey": "Gib zuerst einen API-Schlüssel und einen Endpunkt ein", - "modelNotInList": "Dieses Modell ist nicht in der Liste, auf die dein Schlüssel zugreifen kann – Kimi scheitert mit „Modell nicht gefunden“.", - "reasoningTitle": "Reasoning", - "reasoningEnableLabel": "Aktivieren", - "reasoningDescription": "Kimi zeigt den „Thinking“-Auswähler im Eingabefeld nur, wenn das Modell eine Reasoning-Fähigkeit deklariert – codeg schreibt sie hier. Gilt ab neuen Sitzungen.", - "effortsLabel": "Angebotene Stufen", - "effortsHint": "Diese Stufen erscheinen im „Thinking“-Auswähler. Kimi reicht die Stufe unverändert an den Provider weiter – wähle also Werte, die dein Modell akzeptiert.", - "effortsEmptyHint": "Ohne ausgewählte Stufe bleibt im Eingabefeld nur ein einfacher Off/On-Schalter.", - "effortsCustomPlaceholder": "Weitere Stufe hinzufügen", - "effortsAdd": "Hinzufügen", - "defaultEffortLabel": "Standardstufe", - "defaultEffortAuto": "Kimi entscheiden lassen", - "alwaysThinkingLabel": "Das Modell denkt immer nach – Off-Eintrag aus dem Auswähler entfernen", - "fixErrorsFirst": "Korrigiere zuerst die markierten Felder", - "errorModelRequired": "Modell ist erforderlich", - "errorMaxContextRequired": "Maximale Kontextgröße ist erforderlich", - "errorMaxContextInvalid": "Muss eine positive ganze Zahl sein", - "errorApiKeyRequired": "API-Schlüssel ist erforderlich", - "errorApiKeyInvalid": "Der API-Schlüssel darf keine Zeilenumbrüche enthalten", - "errorBaseUrlRequired": "Basis-URL ist erforderlich", - "errorBaseUrlInvalid": "Muss mit http:// oder https:// beginnen", - "errorVertexProjectRequired": "GCP-Projekt ist erforderlich", - "errorDefaultEffortUnlisted": "Wähle eine der oben ausgewählten Stufen", - "advancedTitle": "Erweitert", - "authTypeLabel": "Ablageort der Zugangsdaten", - "authTypeApiKey": "Inline api_key", - "authTypeEnv": "env-Untertabelle des Providers", - "authTypeHint": "Wo der API-Schlüssel innerhalb von config.toml abgelegt wird.", - "rawEditorLabel": "config.toml direkt bearbeiten", - "rawEditorWarning": "Speichern hier überschreibt die gesamte Datei wortwörtlich und ersetzt die strukturierten Einstellungen oben.", - "rawEditorPlaceholder": "[providers.codeg]\ntype = \"kimi\"\nbase_url = \"https://api.moonshot.cn/v1\"\napi_key = \"sk-...\"" - }, - "authModeOfficialSubscription": "Offizielles Abonnement", - "authModeCustomEndpoint": "Benutzerdefinierter Endpunkt", - "authModeCustomEndpointHint": "API-URL und API-Key manuell für einen benutzerdefinierten Endpunkt konfigurieren.", - "authModeModelProvider": "Modellanbieter", - "modelProvider": "Modellanbieter", - "modelProviderHint": "API-URL, API-Key und Modell eines konfigurierten Modellanbieters verwenden.", - "selectModelProvider": "Modellanbieter auswählen", - "noModelProviderAvailable": "Kein Modellanbieter für diesen Agent konfiguriert. Gehen Sie zu den Modellanbieter-Einstellungen, um einen hinzuzufügen.", - "claude": { - "authMode": "Authentifizierungsmodus", - "officialSubscription": "Offizielles Abonnement", - "officialSubscriptionHint": "Offizielles Anthropic-Abonnement verwenden, kein API-Key erforderlich.", - "mainModel": "Hauptmodell", - "reasoningModel": "Reasoning-Modell (thinking)", - "haikuDefaultModel": "Standard-Haiku-Modell", - "sonnetDefaultModel": "Standard-Sonnet-Modell", - "opusDefaultModel": "Standard-Opus-Modell", - "customModelOption": "Benutzerdefinierte Modell-ID", - "customModelOptionName": "Name des benutzerdefinierten Modells", - "customModelOptionDescription": "Beschreibung des benutzerdefinierten Modells", - "customModelOptionHint": "Fügt der Modellauswahl von Claude einen einzelnen benutzerdefinierten Eintrag hinzu (z. B. ein Modell hinter einem benutzerdefinierten Gateway/Proxy). Name und Beschreibung sind optionale Anzeigeangaben.", - "effortLevel": "Reasoning-Stufe", - "effortLevelDefault": "Standardstufe", - "effortLevel_low": "Niedrig", - "effortLevel_medium": "Mittel", - "effortLevel_high": "Hoch", - "effortLevel_xhigh": "Sehr Hoch", - "sendAttributionHeader": "Attributions-/Abrechnungskennung an die API senden", - "sendAttributionHeaderAria": "Attributions-/Abrechnungskennung von Claude Code an die API senden", - "disableNonessentialTraffic": "Telemetrie oder überflüssige Netzwerkanfragen deaktivieren", - "disableNonessentialTrafficAria": "Telemetrie oder überflüssige Netzwerkanfragen von Claude Code deaktivieren" - }, - "dialogs": { - "confirmDeleteProvider": "Provider {providerId} löschen?", - "confirmDeleteProviderDescription": "OpenCode-Konfiguration und auth JSON werden zusammen aktualisiert. Diese Aktion kann nicht rückgängig gemacht werden.", - "confirmUninstall": "{name} deinstallieren?", - "confirmUninstallDescription": "Dadurch wird die lokal installierte Version entfernt. Eine Neuinstallation ist später möglich.", - "customInstallTitle": "{name} benutzerdefiniert installieren", - "customInstallDescription": "Geben Sie die zu installierende Version ein. Dies installiert neu und ersetzt die aktuell installierte Version.", - "customInstallVersionLabel": "Versionsnummer", - "customInstallInvalid": "Geben Sie eine gültige Versionsnummer ein, z. B. 1.2.3.", - "customInstallSubmit": "Installieren" - }, - "errors": { - "windowsFileLocked": "Die Dateien von {name} werden von einer laufenden Sitzung verwendet, daher kann Windows sie nicht ersetzen. Schließe alle {name}-Sitzungen und versuche es erneut.", - "nativeJsonMustBeObject": "Native JSON-Konfiguration muss ein Objekt sein", - "nativeJsonInvalid": "Formatfehler in nativer JSON-Konfiguration: {message}", - "openCodeAuthMustBeObject": "OpenCode auth.json muss ein JSON-Objekt sein", - "openCodeAuthInvalid": "Formatfehler in OpenCode auth.json: {message}", - "authMustBeObject": "auth.json muss ein JSON-Objekt sein", - "authInvalid": "Formatfehler in auth.json: {message}", - "providerIdPattern": "Provider-ID unterstützt nur Buchstaben, Zahlen, Unterstrich, Punkt und Bindestrich", - "providerExists": "Provider {providerId} existiert bereits", - "modelIdPattern": "Model-ID unterstützt nur Buchstaben, Zahlen, Unterstrich, Punkt, Doppelpunkt und Bindestrich", - "modelExists": "Model {modelId} existiert bereits" - }, - "warnings": { - "nativeJsonRecoveredStructured": "Native JSON-Konfiguration ist ungültig; auf strukturierte Konfiguration zurückgesetzt", - "nativeJsonRecoveredOpenCode": "Native JSON-Konfiguration ist ungültig; auf OpenCode-strukturierte Konfiguration zurückgesetzt", - "openCodeAuthRecovered": "OpenCode auth.json ist ungültig; auf Standardkonfiguration zurückgesetzt", - "authRecoveredStructured": "auth.json ist ungültig; auf strukturierte Konfiguration zurückgesetzt" - }, - "toasts": { - "agentActionCompleted": "{name} {action} abgeschlossen", - "agentActionFailed": "{name} {action} fehlgeschlagen", - "localVersion": "Lokale Version: {version}", - "installCompletedVersionLater": "Installation abgeschlossen, Version wird bei der nächsten Prüfung aktualisiert", - "uninstallCompleted": "Deinstallation von {name} abgeschlossen", - "uninstallFailed": "Deinstallation von {name} fehlgeschlagen", - "localVersionRemoved": "Lokale Version entfernt", - "saveAgentOrderFailed": "Speichern der Agent-Reihenfolge fehlgeschlagen", - "saveAgentSwitchFailed": "Speichern des Agent-Schalters fehlgeschlagen", - "saveEnvFailed": "Speichern der Umgebungsvariablen fehlgeschlagen", - "grokSaved": "Grok-Konfiguration gespeichert", - "saveGrokNativeFailed": "Grok-Nativkonfiguration konnte nicht gespeichert werden", - "saveGrokApiKeyFailed": "Einstellungen gespeichert, aber der API-Schlüssel konnte nicht gespeichert werden", - "cursorSaved": "Cursor-Konfiguration gespeichert", - "saveCursorConfigFailed": "Cursor-Konfiguration konnte nicht gespeichert werden", - "codexSaved": "Codex-Konfiguration gespeichert", - "saveCodexNativeFailed": "Speichern der nativen Codex-Konfiguration fehlgeschlagen", - "geminiSaved": "Gemini-Konfiguration gespeichert", - "saveGeminiFailed": "Speichern der Gemini-Konfiguration fehlgeschlagen", - "providerDeleted": "Provider {providerId} gelöscht", - "providerDeleteFailed": "Löschen von Provider {providerId} fehlgeschlagen", - "providerSaved": "Provider {providerId} gespeichert", - "saveProviderFailed": "Speichern von Provider {providerId} fehlgeschlagen", - "openCodeConfigSynced": "OpenCode-Konfiguration und auth JSON wurden synchronisiert.", - "openCodeSaved": "OpenCode-Konfiguration gespeichert", - "saveOpenCodeFailed": "Speichern der OpenCode-Konfiguration fehlgeschlagen", - "openClawSaved": "OpenClaw-Konfiguration gespeichert", - "saveOpenClawFailed": "Speichern der OpenClaw-Konfiguration fehlgeschlagen", - "configSaved": "Konfiguration gespeichert", - "configSavedHint": "Bestehende Sitzungen müssen neu geöffnet werden, damit die Änderungen wirksam werden", - "saveConfigManagementFailed": "Speichern der Konfigurationsverwaltung fehlgeschlagen", - "clineSaved": "Cline-Konfiguration gespeichert", - "saveClineFailed": "Cline-Konfiguration konnte nicht gespeichert werden", - "hermesSaved": "Hermes-Konfiguration gespeichert", - "saveHermesFailed": "Hermes-Konfiguration konnte nicht gespeichert werden", - "codeBuddySaved": "CodeBuddy-Konfiguration gespeichert", - "saveCodeBuddyFailed": "CodeBuddy-Konfiguration konnte nicht gespeichert werden", - "kimiCodeSaved": "Kimi-Code-Konfiguration gespeichert", - "saveKimiCodeFailed": "Speichern der Kimi-Code-Konfiguration fehlgeschlagen", - "deepseekSaved": "DeepSeek-Konfiguration gespeichert", - "saveDeepSeekFailed": "DeepSeek-Konfiguration konnte nicht gespeichert werden", - "modelProviderRequired": "Bitte wählen Sie vor dem Speichern einen Modellanbieter aus.", - "affectedRunningSessions": "{count, plural, one {# laufende Sitzung muss zum Anwenden neu verbunden werden} other {# laufende Sitzungen müssen zum Anwenden neu verbunden werden}}", - "providerConnected": "{providerId} verbunden", - "connectFailed": "Verbinden von {providerId} fehlgeschlagen", - "providerDisconnected": "{providerId} getrennt", - "disconnectFailed": "Trennen von {providerId} fehlgeschlagen", - "catalogRefreshed": "Katalog aktualisiert – {count} Provider", - "catalogRefreshFailed": "Aktualisieren des Katalogs fehlgeschlagen", - "piSaved": "Pi-Konfiguration gespeichert", - "savePiFailed": "Pi-Konfiguration konnte nicht gespeichert werden", - "piRuntimeSaved": "Pi-Laufzeit gespeichert", - "savePiRuntimeFailed": "Pi-Laufzeit konnte nicht gespeichert werden", - "piBinaryInstalled": "pi installiert", - "piBinaryInstallFailed": "pi-Installation fehlgeschlagen", - "piBinaryUninstalled": "pi deinstalliert", - "piBinaryUninstallFailed": "pi-Deinstallation fehlgeschlagen", - "savePiTrustFailed": "Speichern des Arbeitsbereich-Vertrauens fehlgeschlagen" - }, - "version": { - "statusLabel": "Versionsstatus", - "notInstalled": "Nicht installiert", - "remoteLocal": "Remote: {remoteVersion} · Lokal: {localVersion}", - "localOnly": "Lokal: {localVersion}", - "localInstalled": "{versionText}. Installiert.", - "platformUnsupported": "{versionText}. Aktuelle Plattform unterstützt diesen Agenten nicht.", - "uvxNotReady": "{versionText}. Die uv-Laufzeit ist nicht installiert – installieren Sie sie über die uv-Prüfung unten, um diesen Agenten zu verwenden.", - "clickInstall": "{versionText}. Rechts auf Installieren klicken.", - "localUnrecognized": "{versionText}. Lokale Version ist nicht vergleichbar; zum Überschreiben bitte Upgrade versuchen.", - "upgradeAvailable": "{versionText}. Upgrade verfügbar.", - "remoteUnavailable": "{versionText}. Remote-Version ist derzeit nicht verfügbar.", - "latest": "{versionText}. Bereits aktuell." - }, - "adapter": { - "label": "ACP-Adapter", - "badge": "ACP-Adapter", - "badgeHint": "Für diesen Agenten installiert Codeg ein ACP-Adapterpaket, nicht die Hersteller-CLI. Beide sind unabhängig und teilen sich dieselbe Konfiguration.", - "learnMore": "Mehr erfahren", - "missingWithNative": "Deine eigene {nativeLabel} wurde unter {nativePath} gefunden. Codeg spricht mit Agenten über ACP, und diese CLI beherrscht kein ACP — deshalb braucht Codeg ein separates Adapterpaket, {adapterPackage}, gepflegt vom Agent-Client-Protocol-Projekt (ursprünglich Zed). Es bringt seine eigene Laufzeit mit, verändert oder ersetzt deinen Befehl {nativeCmd} nie und liest dasselbe {configDir} — Anmeldung und Einstellungen bleiben erhalten. Unten installieren.", - "missing": "Codeg spricht mit Agenten über ACP, und die {nativeLabel} beherrscht kein ACP — deshalb braucht Codeg ein separates Adapterpaket, {adapterPackage}, gepflegt vom Agent-Client-Protocol-Projekt (ursprünglich Zed). Es bringt seine eigene Laufzeit mit, die CLI {nativeCmd} ist also nicht Voraussetzung; hast du sie bereits, koexistieren beide und teilen sich Anmeldung und Einstellungen in {configDir}. Unten installieren.", - "readyWithNative": "Der Adapter {adapterCmd} ist installiert — ihn startet Codeg, nicht dein eigenes {nativeCmd} unter {nativePath}. Es sind getrennte Pakete, die koexistieren, und beide lesen {configDir}, Anmeldung und Einstellungen sind also gemeinsam.", - "ready": "Der Adapter {adapterCmd} ist installiert — ihn startet Codeg. Er bringt seine eigene Laufzeit mit, die {nativeLabel} wird also nicht benötigt; installierst du sie später, koexistieren beide und teilen sich {configDir}." - }, - "cline": { - "configDescription": "Konfigurieren Sie den Cline API-Anbieter und die Anmeldedaten. Einstellungen werden in ~/.cline/data/ gespeichert." - }, - "opencodePlugins": { - "title": "OpenCode-Plugins", - "declared": "Deklarierte Plugins", - "noPlugins": "Keine Plugins in opencode.json deklariert", - "status": { - "installed": "Installiert", - "missing": "Nicht installiert" - }, - "installAll": "Alle fehlenden installieren", - "pinVersions": "@latest-Versionen fixieren", - "install": "Installieren", - "uninstall": "Deinstallieren", - "refresh": "Aktualisieren", - "success": "Alle Plugins wurden erfolgreich installiert", - "failed": "Plugin-Vorgang fehlgeschlagen" - }, - "pi": { - "configManagement": "Pi-Konfiguration", - "configDescription": "Pi authentifiziert sich über den API-Schlüssel deines Modellanbieters. Der Schlüssel wird in ~/.pi/agent/auth.json und die Modellauswahl in settings.json geschrieben.", - "providerLabel": "Anbieter", - "modelLabel": "Modell", - "thinkingLabel": "Denken", - "thinking": { - "off": "Aus", - "low": "Niedrig", - "medium": "Mittel", - "high": "Hoch", - "minimal": "Minimal", - "xhigh": "Sehr hoch" - }, - "apiKeyLabel": "API-Schlüssel", - "apiKeyHint": "Wird in ~/.pi/agent/auth.json für den ausgewählten Anbieter gespeichert.", - "apiKeySetPlaceholder": "•••••• (gespeichert – leer lassen zum Beibehalten)", - "saveConfig": "Pi-Konfiguration speichern", - "providerModelRequired": "Anbieter und Modell sind erforderlich", - "runtimeTitle": "Laufzeit", - "runtimeDescription": "Wähle, welches pi-Binary läuft. Standard verwenden oder auf deinen eigenen pi-Build verweisen.", - "modeDefault": "Standard-pi", - "modeDefaultHint": "Verwendet den integrierten pi-acp-Adapter mit dem pi in deinem PATH. pi installieren: npm install -g @earendil-works/pi-coding-agent", - "modeCustom": "Eigenes pi", - "modeCustomHint": "Führe deinen eigenen pi-Build, deine Installation oder einen Wrapper aus.", - "commandLabel": "pi-Befehl oder -Pfad", - "commandHint": "Ein absoluter Pfad, ein Befehlsname im PATH oder ein Wrapper-Skript (z. B. ./pi-test.sh eines Monorepos).", - "commandNotFound": "Befehl nicht gefunden", - "validate": "Prüfen", - "advanced": "Erweitert", - "configDirLabel": "Konfigurationsverzeichnis (PI_CODING_AGENT_DIR)", - "sessionDirLabel": "Sitzungsverzeichnis (PI_CODING_AGENT_SESSION_DIR)", - "flagsHint": "pi-acp leitet eigene pi-Flags (--approve, -e, …) nicht weiter – umhülle pi mit einem Skript und verweise den Befehl darauf.", - "customIncomplete": "Gib einen pi-Befehl zum Speichern ein", - "saveRuntime": "Laufzeit speichern", - "providerPlaceholder": "Anbieter auswählen", - "customProvider": "Eigener Anbieter…", - "providerIdLabel": "Anbieter-ID", - "apiProtocolLabel": "API-Protokoll", - "baseUrlLabel": "API-Endpunkt (Base URL)", - "customProviderHint": "Definiert einen Anbieter in ~/.pi/agent/models.json an Ihrem Endpunkt. Die meisten selbst gehosteten oder Proxy-Server nutzen openai-completions.", - "baseUrlRequired": "API-Endpunkt (Base URL) ist erforderlich", - "binaryTitle": "pi-Binärdatei (pi-coding-agent)", - "binaryDescription": "pi-acp führt diese pi-Binärdatei aus. Hier installieren oder pi-acp unten auf einen eigenen Build verweisen.", - "binaryInstalled": "Installiert", - "binaryMissing": "Nicht installiert", - "binaryChecking": "Wird geprüft…", - "installBinary": "pi installieren", - "installing": "Wird installiert…", - "recheck": "Erneut prüfen", - "configDirSkillsNote": "Mit einem benutzerdefinierten Konfigurationsverzeichnis gelten die in den Einstellungen verwalteten Skills, Experten und Office-Tools nicht für dieses pi — verwalte seine Skills direkt in diesem Ordner.", - "projectTrustTitle": "Projektvertrauen", - "projectTrustDescription": "Ordner, aus denen pi Projektdateien laden darf. In einem vertrauten Ordner führt das Repository seine .pi/extensions beim Start von pi aus. Die Entscheidung gilt für alle enthaltenen Ordner und auch, wenn du pi im Terminal startest.", - "projectTrustLoading": "Wird geladen…", - "projectTrustEmpty": "Noch keine Ordner entschieden.", - "projectTrustTrusted": "Vertraut", - "projectTrustDenied": "Nicht vertraut", - "projectTrustRevoke": "Widerrufen", - "reasoningTitle": "Reasoning", - "reasoningEnableLabel": "Aktivieren", - "reasoningDescription": "pi sendet einen Reasoning-Aufwand nur für ein Modell, das ihn deklariert — bei einem nicht deklarierten Modell werden alle Stufen auf Off begrenzt, sodass die Auswahl im Eingabefeld sofort zurückspringt. Wird in den Eintrag dieses Modells in models.json geschrieben.", - "levelsLabel": "Verfügbare Stufen", - "levelsHint": "Diese werden zu den Einträgen der Reasoning-Auswahl im Eingabefeld. Wähle die, die dein Endpunkt akzeptiert; jede hier nicht gelistete Stufe lehnt pi ab.", - "levelsEmptyError": "Wähle mindestens eine Stufe — ohne eine fällt pi auf Off zurück.", - "wireValuesTitle": "Erweitert: an den Anbieter gesendete Werte", - "wireValuesHint": "Leer lassen, um den Stufennamen unverändert zu senden. Setze einen Wert, wenn dein Endpunkt etwas anderes erwartet — Google-artige Backends erwarten LOW / HIGH.", - "defaultLevelUnlisted": "Diese Stufe steht nicht in der Liste oben — pi würde sie begrenzen." - }, - "addCustomAgent": "Eigenen Agenten hinzufügen", - "addCustomAgentHint": "Registriere jeden ACP-kompatiblen Agenten. Wähle einen aus der öffentlichen ACP-Registry oder füge seine Registry-Informationen ein.", - "customAgentFromRegistry": "ACP-Registry", - "customAgentManual": "Manuell", - "customAgentSearchPlaceholder": "Agenten suchen…", - "customAgentLoadingCatalog": "ACP-Registry wird geladen…", - "customAgentRetry": "Erneut versuchen", - "customAgentNoResults": "Keine passenden Agenten", - "customAgentAdd": "Hinzufügen", - "customAgentAlreadyAdded": "Hinzugefügt", - "customAgentUnsupportedPlatform": "Kein Build für diese Plattform verfügbar", - "customAgentAdded": "{name} hinzugefügt", - "customAgentIdLabel": "Registry-ID", - "customAgentNameLabel": "Anzeigename", - "customAgentVersionLabel": "Version", - "customAgentSpecLabel": "Distribution (JSON)", - "customAgentSpecHint": "Gleiche Form wie das distribution-Objekt der ACP-Registry: Kanäle npx, uvx und binary, oder ein kompletter Registry-Eintrag zum Einfügen. Bei npx/uvx ist cmd der vom Paket installierte Befehl — bei Weglassen aus dem Paketnamen abgeleitet, bei Abweichung also angeben. binary ist nach Plattformschlüssel gegliedert (diese Maschine: {platform}); cmd ist der Startpfad im Archiv, sha256 prüft optional den Download.", - "customAgentTemplateLabel": "Vorlagen", - "customAgentKindLabel": "Starten über", - "customAgentInvalidJson": "Kein gültiges JSON", - "customAgentNoDistribution": "Keine npx-, uvx- oder binary-Distribution gefunden", - "customAgentCancel": "Abbrechen", - "customAgentSave": "Agent hinzufügen", - "customAgentSaveChanges": "Änderungen speichern", - "customAgentEdit": "Agent bearbeiten", - "customAgentEditHint": "Name, Icon, Distribution und Skills-Deklarationen ändern. Die Agent-ID kann nicht geändert werden.", - "customAgentEditNotFound": "Benutzerdefinierter Agent {id} wurde nicht gefunden", - "customAgentSaved": "{name} gespeichert", - "customAgentVersionProbeLabel": "Versionsabfrage-Befehl (optional)", - "customAgentVersionProbeHint": "Befehl, der die lokal installierte Version ausgibt. Bleibt er leer, führt codeg den Agent-Befehl mit --version aus.", - "customAgentRemove": "Agent entfernen", - "customAgentRemoveHint": "Löscht die Agent-Definition. Bestehende Unterhaltungen behalten ihren Verlauf; der Agent lässt sich nur nicht mehr starten.", - "customAgentIconLabel": "Symbol (optional)", - "customAgentIconUpload": "Hochladen", - "customAgentIconReplace": "Ersetzen", - "customAgentIconClear": "Symbol entfernen", - "customAgentIconHint": "Wird beim Agenten gespeichert und funktioniert daher offline. Ohne Symbol wird ein farbiger Anfangsbuchstabe verwendet.", - "customAgentSkillsLabel": "Skills (gemeinsames .agents/skills)", - "customAgentSkillsHint": "Erklärt, dass dieser Agent den gemeinsamen .agents/skills-Speicher liest (globale und Projekt-Verzeichnisse), und nimmt ihn in alle Skill-Matrizen auf. Dort verknüpfte Skills sind für alle Agenten sichtbar, die diesen Speicher lesen.", - "customAgentSkillsDirLabel": "Dediziertes Skills-Verzeichnis", - "customAgentSkillsDirHint": "Absoluter Pfad des Verzeichnisses, aus dem dieser Agent Skills lädt — sein eigener Speicher, zusätzlich zum geteilten oder an dessen Stelle. ~ wird zum Home-Verzeichnis erweitert; verknüpfte Skills landen zuerst hier.", - "customAgentMcpLabel": "MCP-Unterstützung", - "customAgentMcpHint": "Übergibt den in codeg integrierten MCP-Begleitprozess beim Sitzungsstart an diesen Agenten — der Kanal hinter Delegation, Live-Feedback und Aufgaben-Tools. Für einen Agenten, der MCP-Server ablehnt und deshalb keine Verbindung aufbaut, ausschalten; die Änderung gilt ab der nächsten Verbindung.", - "customAgentIconNotAnImage": "Bitte eine Bilddatei auswählen.", - "customAgentIconTooLarge": "Das Symbol muss kleiner als {limit} KB sein.", - "customAgentIconReadFailed": "Dieses Bild konnte nicht gelesen werden.", - "customAgentRemoveConfirm": "{name} entfernen? Bestehende Unterhaltungen bleiben erhalten, der Agent lässt sich aber nicht mehr starten.", - "customAgentRemoveWithData": "Auch den aufgezeichneten Gesprächsverlauf löschen", - "customAgentRemoved": "{name} entfernt", - "customAgentBadge": "Eigen", - "customAgentNotLaunchable": "Dieser Agent kann hier nicht gestartet werden: {reason}" - }, - "SettingsPages": { - "agentsLoading": "Agent-Einstellungen werden geladen...", - "skillPacksLoading": "Skill-Pakete werden geladen…" - }, - "GeneralSettings": { - "loading": "Wird geladen...", - "sectionTitle": "Allgemein", - "sectionDescription": "Zentrale Einstellungen für das Standardterminal, die Rendering-Beschleunigung und die Multi-Agent-Delegation.", - "terminalTitle": "Standardterminal", - "terminalDescription": "Wählen Sie die Shell, die beim Öffnen neuer Terminal-Tabs über die Terminalleiste oder den Dateibaum verwendet wird. Agenten nutzen sie ebenfalls, wenn sie codeg um die Ausführung einer vollständigen Befehlszeile bitten.", - "terminalSystemDefault": "Systemstandard", - "terminalPowerShell7": "PowerShell 7 (pwsh)", - "terminalWindowsPowerShell": "Windows PowerShell", - "terminalCmd": "Eingabeaufforderung (cmd)", - "terminalSaveFailed": "Speichern der Terminaleinstellungen fehlgeschlagen: {message}", - "terminalShellCustom": "Benutzerdefinierter Pfad", - "terminalShellCustomPath": "Shell-Pfad", - "terminalShellCustomPlaceholder": "/usr/local/bin/fish", - "terminalShellCustomSave": "Speichern", - "terminalShellCustomHint": "Absoluten Pfad oder einen über PATH auflösbaren Namen angeben.", - "terminalShellNotInstalled": "nicht installiert", - "terminalShellNotFoundWarning": "Dieser Pfad existiert auf diesem Host nicht.", - "terminalCurrentShell": "Aktuell verwendet: {path}", - "renderingDescription": "Deaktivieren Sie die Hardwarebeschleunigung, wenn die App einen schwarzen Bildschirm oder Render-Fehler zeigt (häufig bei bestimmten AMD-GPUs oder integrierten Intel-GPUs). Wirkt sich nur auf die Windows-Desktop-Version aus.", - "disableHardwareAcceleration": "Hardwarebeschleunigung deaktivieren", - "renderingSaveFailed": "Render-Einstellungen konnten nicht gespeichert werden: {message}", - "restartRequired": "Gespeichert. Starten Sie die App neu, damit die Änderung wirksam wird.", - "restartNow": "Jetzt neu starten", - "restartFailed": "Neustart fehlgeschlagen: {message}", - "loadFailed": "Laden fehlgeschlagen: {message}" - }, - "LoginPage": { - "documentTitle": "Anmelden - codeg", - "brand": "Codeg", - "subtitle": "Gib dein Zugriffstoken ein, um dich mit der Desktop-App zu verbinden", - "tokenPlaceholder": "Zugriffstoken", - "connect": "Verbinden", - "connecting": "Verbinde...", - "helpText": "Das Token findest du in der Desktop-App unter Einstellungen → Webdienst", - "invalidToken": "Ungültiges Token. Bitte überprüfe es und versuche es erneut.", - "connectionFailed": "Verbindung fehlgeschlagen (HTTP {status})", - "networkError": "Verbindung zum Server nicht möglich" - }, - "CommitPage": { - "title": "Einchecken", - "invalidFolderId": "Ungültige Ordner-ID", - "loadingRepo": "Repository wird geladen..." - }, - "MergePage": { - "title": "Konflikte lösen", - "invalidFolderId": "Ungültige Ordner-ID", - "loadingRepo": "Repository wird geladen...", - "localVersion": "Lokal (Unsere)", - "result": "Ergebnis", - "remoteVersion": "Remote (Deren)", - "acceptLocal": "Lokal übernehmen", - "acceptRemote": "Remote übernehmen", - "markResolved": "Als gelöst markieren", - "abortMerge": "Abbrechen", - "completeMerge": "Merge abschließen", - "unresolvedConflicts": "Es gibt noch ungelöste Konfliktmarkierungen in dieser Datei", - "fileResolved": "Datei erfolgreich gelöst", - "allResolved": "Alle Konflikte gelöst", - "conflictFiles": "Konfliktdateien", - "loadingFile": "Datei wird geladen...", - "preparingMerge": "Merge wird vorbereitet...", - "selectFile": "Datei zum Lösen auswählen", - "noConflicts": "Keine Konfliktdateien", - "skipFile": "Überspringen", - "abortSuccess": "Vorgang abgebrochen", - "applyAllNonConflicting": "Alle konfliktfreien Änderungen anwenden", - "applyLeftNonConflicting": "Lokal anwenden", - "applyRightNonConflicting": "Remote anwenden" - }, - "ImportSessions": { - "title": "Lokale Sitzungen importieren", - "scanningTitle": "Lokale Agentensitzungen werden gescannt…", - "scanningHint": "Die lokalen Sitzungsspeicher der Agenten werden durchsucht. Bei großen Verläufen kann das etwas dauern. Bereits importierte Sitzungen werden dabei aktualisiert.", - "scanFailed": "Scan fehlgeschlagen", - "retry": "Erneut versuchen", - "rescan": "Neu scannen", - "empty": "Keine lokalen Sitzungen gefunden", - "emptyHint": "Auf diesem Rechner wurden keine Sitzungsspeicher von Agenten gefunden.", - "noMatches": "Keine Sitzungen entsprechen den aktuellen Filtern", - "searchPlaceholder": "Titel oder Pfad suchen…", - "allAgents": "Alle Agenten", - "onlyImportable": "Nur importierbare", - "selectAll": "Alle auswählen", - "clearSelection": "Leeren", - "expandAll": "Alle ausklappen", - "collapseAll": "Alle einklappen", - "summaryCounts": "{total} Sitzungen · {importable} importierbar · {folders} Ordner", - "noFolderSkipped": "{count} ohne Projektordner übersprungen", - "folderNew": "Neu", - "folderCounts": "{importable}/{total} importierbar", - "toggleFolderAria": "Alle importierbaren Sitzungen in {name} auswählen", - "toggleSessionAria": "Sitzung {title} auswählen", - "statusImported": "Importiert", - "statusDeleted": "Gelöscht", - "untitled": "Unbenannte Sitzung", - "messageCount": "{count} Nachrichten", - "selectedCount": "{count} ausgewählt", - "importSelected": "Auswahl importieren", - "importing": "Importiere…", - "close": "Schließen", - "doneTitle": "Import abgeschlossen", - "doneImported": "Importiert", - "doneUpdated": "Aktualisiert", - "doneSkipped": "Übersprungen", - "doneCreatedFolders": "Ordner erstellt", - "doneNotFound": "Nicht gefunden", - "doneFailed": "Fehlgeschlagen", - "continueImport": "Weiter importieren", - "toasts": { - "importFailed": "Import fehlgeschlagen: {message}" - } - }, - "Folder": { - "workspaceStatus": { - "degradedTitle": "Live-Aktualisierungen nicht verfügbar", - "degradedHint": "Beobachter konnte nicht gestartet werden (z. B. Berechtigung verweigert). Aktualisiere manuell, um Änderungen zu sehen.", - "retry": "Wiederholen", - "retrying": "Wird wiederholt..." - }, - "common": { - "all": "Alle", - "cancel": "Abbrechen", - "close": "Schließen", - "closeOthers": "Andere schließen", - "closeAll": "Alle schließen", - "confirm": "Bestätigen", - "save": "Speichern", - "delete": "Löschen", - "rename": "Umbenennen", - "loading": "Wird geladen...", - "refresh": "Aktualisieren", - "refreshing": "Aktualisierung...", - "create": "Erstellen", - "createAndSwitch": "Erstellen und wechseln", - "openFile": "Datei öffnen", - "viewDiff": "Diff anzeigen", - "push": "Pushen..." - }, - "statusLabels": { - "in_progress": "In Bearbeitung", - "pending_review": "Prüfung", - "completed": "Abgeschlossen", - "cancelled": "Abgebrochen" - }, - "sidebar": { - "title": "Konversationen", - "locateActiveConversation": "Aktive Konversation finden", - "expandAllGroups": "Alle Gruppen erweitern", - "collapseAllGroups": "Alle Gruppen einklappen", - "newConversation": "Neue Konversation", - "newConversationShort": "Neu", - "newChat": "Neue Konversation", - "search": "Suchen", - "noConversationsFound": "Keine Konversationen gefunden.", - "importLocalSessions": "Lokale Sitzungen importieren", - "importing": "Importiere...", - "error": "Fehler: {message}", - "completeAllSessions": "Alle Sitzungen abschließen", - "completeAllReviewTitle": "Alle Review-Sitzungen abschließen?", - "completeAllReviewDescription": "Dadurch werden alle {count, plural, one {# Sitzung} other {# Sitzungen}} im Review als abgeschlossen markiert.", - "completing": "Abschließen...", - "toasts": { - "importedSessions": "{imported, plural, one {# Sitzung} other {# Sitzungen}} importiert, {skipped} übersprungen", - "importedAndUpdated": "{imported, plural, one {# Sitzung} other {# Sitzungen}} importiert, {updated, plural, one {# Titel} other {# Titel}} aktualisiert, {skipped} übersprungen", - "updatedTitles": "{updated, plural, one {# Titel} other {# Titel}} aktualisiert, {skipped} übersprungen", - "noNewSessionsFound": "Keine neuen Sitzungen gefunden ({skipped} übersprungen)", - "importFailed": "Import fehlgeschlagen: {message}", - "reviewCompleted": "{count, plural, one {# Review-Sitzung} other {# Review-Sitzungen}} als abgeschlossen markiert", - "completeReviewFailed": "Review-Sitzungen konnten nicht abgeschlossen werden: {message}", - "folderOpened": "Ordner {name} geöffnet", - "folderRemoved": "Ordner {name} entfernt", - "openFolderFailed": "Ordner konnte nicht geöffnet werden", - "removeFolderFailed": "Ordner konnte nicht entfernt werden: {message}", - "reorderFoldersFailed": "Ordner konnten nicht neu sortiert werden: {message}", - "changeFolderColorFailed": "Farbe konnte nicht geändert werden: {message}", - "setFolderAliasFailed": "Alias konnte nicht festgelegt werden: {message}", - "changeFolderDefaultAgentFailed": "Standard-Agent konnte nicht gesetzt werden: {message}" - }, - "statsLabel": "{folders} Ordner · {convos} Konversationen", - "reorderHandle": "Zum Neuordnen ziehen", - "openFolder": "Ordner öffnen", - "searchPlaceholder": "Konversationen suchen...", - "viewOptions": "Anzeigeoptionen", - "showCompleted": "Abgeschlossene Konversationen anzeigen", - "showWorktrees": "Worktree-Ordner anzeigen", - "showRecent": "Gruppe „Zuletzt“ anzeigen", - "moreOptions": "Weitere Optionen", - "sortBy": "Sortieren nach", - "sortByCreatedAt": "Erstellungszeit", - "sortByUpdatedAt": "Aktualisierungszeit", - "sectionOrder": "Abschnittsreihenfolge", - "sectionOrderMoveUp": "Nach oben", - "sectionOrderMoveDown": "Nach unten", - "sectionOrderItemLabel": "{name} — Position {position} von {total}", - "statusRunningBadge": "Läuft", - "runningCountBadge": "{count, plural, one {# laufende Sitzung} other {# laufende Sitzungen}}", - "statusCancelledBadge": "Abgebrochen", - "worktreeRemovedBadge": "Quell-Worktree entfernt", - "conversationCountUnit": "{count, plural, one {# Konversation} other {# Konversationen}}", - "emptyFolderHint": "Keine Konversationen", - "noMatchingConversations": "Keine passenden Konversationen", - "noUnfinishedConversations": "Keine offenen Konversationen. Aktiviere \"Abgeschlossene anzeigen\" im Menü oben rechts.", - "removeFolderConfirmTitle": "Ordner aus Arbeitsbereich entfernen?", - "removeFolderConfirmDescription": "\"{name}\" aus dem Arbeitsbereich entfernen? Zugehörige Tabs und Terminals werden geschlossen.", - "folderHeaderMenu": { - "manageConversations": "Konversationen verwalten…", - "manageLinks": "Verknüpfte Ordner", - "changeColor": "Farbe ändern", - "useThemeColor": "App-Design verwenden", - "setDefaultAgent": "Standard-Agent festlegen", - "defaultAgentNone": "Kein Standard (global verwenden)", - "agentUnavailableSuffix": "(nicht verfügbar)", - "loadingAgents": "Agenten werden geladen…", - "setAlias": "Alias festlegen…", - "setAliasTitle": "Ordner-Alias festlegen", - "setAliasPlaceholder": "Alias eingeben (zum Entfernen leer lassen)", - "setAliasSave": "Speichern", - "setAliasCancel": "Abbrechen", - "removeFromWorkspace": "Aus Arbeitsbereich entfernen" - }, - "manageConversations": { - "title": "Konversationen verwalten", - "searchPlaceholder": "Nach Titel suchen…", - "agentFilterAll": "Alle Agenten", - "statusFilterAll": "Alle Status", - "folderFilterAll": "Alle Ordner", - "branchFilterAll": "Alle Branches", - "branchNone": "Kein Branch", - "branchSearchPlaceholder": "Branches suchen…", - "noMatchingBranches": "Keine passenden Branches", - "selectAllVisible": "Alle auswählen", - "deselectAll": "Auswahl aufheben", - "selectedCount": "{count} ausgewählt", - "matchedCount": "{count} Treffer", - "untitledConversation": "Unbenannte Konversation", - "setStatus": "Status setzen…", - "deleteSelected": "Löschen", - "noConversations": "Keine Konversationen in diesem Ordner.", - "noConversationsWorkspace": "Keine Konversationen im Arbeitsbereich.", - "noMatchingConversations": "Keine Konversationen entsprechen den Filtern.", - "confirmDeleteTitle": "{count} Konversation(en) löschen?", - "confirmDeleteDescription": "Diese Aktion kann nicht rückgängig gemacht werden.", - "toastDeleted": "{count} Konversation(en) gelöscht", - "toastStatusUpdated": "Status von {count} Konversation(en) aktualisiert", - "toastOpFailed": "Aktion fehlgeschlagen: {message}" - }, - "sectionPinned": "Angeheftet", - "sectionFolders": "Ordner", - "sectionChats": "Chat", - "sectionRecent": "Zuletzt", - "noChats": "Keine Chats", - "noRecent": "Keine kürzlichen Konversationen", - "showMoreRecent": "Mehr anzeigen ({count})", - "noFolders": "Keine Ordner geöffnet", - "newChatAction": "Neuer Chat", - "automations": "Automatisierungen", - "tasks": "To-dos", - "loadingSubsessions": "Unterkonversationen werden geladen…" - }, - "conversation": { - "reloadFailed": "Konversation konnte nicht neu geladen werden: {message}", - "reloaded": "Konversation neu geladen", - "reload": "Neu laden", - "activeConversationIndicator": "Aktive Konversation", - "newConversation": "Neue Konversation", - "closeConversation": "Konversation schließen", - "copyText": "Text kopieren", - "copyTextSuccess": "Kopiert", - "copyTextFailed": "Kopieren fehlgeschlagen", - "forkSession": "Sitzung forken", - "forkSessionSuccess": "Sitzung erfolgreich geforkt", - "forkSessionFailed": "Sitzung konnte nicht geforkt werden: {error}", - "exportConversation": "Konversation exportieren", - "exportImage": "Bild", - "exportMarkdown": "Markdown", - "exportHtml": "HTML", - "exportSuccess": "Konversation exportiert", - "exportFailed": "Export fehlgeschlagen", - "exportImageTooLong": "Konversation ist zu lang für den Bildexport", - "exportLabels": { - "untitledConversation": "Unbenannte Konversation", - "agent": "Agent", - "model": "Modell", - "status": "Status", - "started": "Gestartet", - "updated": "Aktualisiert", - "tokens": "Token-Statistik", - "duration": "Dauer", - "inputTokens": "Eingabe", - "outputTokens": "Ausgabe", - "cacheRead": "Cache gelesen", - "cacheWrite": "Cache geschrieben", - "user": "Benutzer", - "assistant": "Assistent", - "system": "System", - "toolResult": "Ergebnis", - "toolError": "Fehler" - }, - "moreActions": "Weitere Aktionen" - }, - "sessionDetails": { - "menuLabel": "Sitzungsdetails", - "noActiveSession": "Keine aktive Sitzung", - "title": "Sitzungsdetails", - "subtitle": "Sitzungsmetadaten und Token-Nutzung", - "fieldTitle": "Titel", - "untitled": "Unbenannte Konversation", - "sessionId": "Sitzungs-ID", - "externalId": "Erweiterungs-ID", - "agent": "Agent", - "model": "Modell", - "status": "Status", - "gitBranch": "Git-Branch", - "parentId": "Übergeordnete Sitzung", - "tokensHeading": "Token-Nutzung", - "totalTokens": "Gesamt", - "inputTokens": "Eingabe", - "outputTokens": "Ausgabe", - "cacheWrite": "Cache geschrieben", - "cacheRead": "Cache gelesen", - "contextWindow": "Kontextfenster", - "duration": "Dauer", - "loadingStats": "Token-Nutzung wird geladen…", - "loadFailed": "Token-Nutzung konnte nicht geladen werden", - "noStats": "Keine Nutzung erfasst", - "timestampsHeading": "Zeitstempel", - "createdAt": "Erstellt", - "updatedAt": "Aktualisiert", - "none": "—", - "copyField": "{field} kopieren", - "copiedField": "{field} kopiert" - }, - "conversationCard": { - "untitledConversation": "Unbenannte Konversation", - "newConversation": "Neue Konversation", - "rename": "Umbenennen", - "status": "Zustand", - "delete": "Löschen", - "importLocalSessions": "Lokale Sitzungen importieren", - "importing": "Importiere...", - "renameConversation": "Konversation umbenennen", - "deleteConversationTitle": "Konversation löschen?", - "deleteConversationDescription": "\"{title}\" wird gelöscht. Diese Aktion kann nicht rückgängig gemacht werden.", - "cancel": "Abbrechen", - "save": "Speichern", - "pin": "Anheften", - "unpin": "Loslösen", - "markCompleted": "Als abgeschlossen markieren", - "reopen": "Erneut öffnen", - "expandSubsessions": "Unterkonversationen einblenden", - "collapseSubsessions": "Unterkonversationen ausblenden" - }, - "search": { - "dialogTitle": "Suchen", - "dialogTitleWithFolder": "Suchen — {name}", - "tabConversations": "Konversationen", - "tabFiles": "Dateien", - "placeholder": "Konversationen suchen...", - "filePlaceholder": "Dateien oder Verzeichnisse suchen...", - "allAgents": "Alle", - "searching": "Suche...", - "typeToSearch": "Tippen, um Konversationen zu suchen", - "typeToSearchFiles": "Tippen, um Dateien oder Verzeichnisse zu suchen", - "noResults": "Keine Ergebnisse gefunden.", - "untitledConversation": "Unbenannte Konversation" - }, - "folderTitleBar": { - "showSidebar": "Seitenleiste anzeigen", - "hideSidebar": "Seitenleiste ausblenden", - "toggleTerminal": "Terminal umschalten", - "toggleAuxPanel": "Hilfspaneel umschalten", - "search": "Suchen", - "openSettings": "Einstellungen öffnen", - "backToConversations": "Zurück zu Konversationen", - "withShortcut": "{label} (Tastenkürzel: {shortcut})" - }, - "statusBar": { - "connection": { - "connected": "Verbunden", - "connecting": "Verbinde...", - "prompting": "Antworte...", - "error": "Verbindungsfehler", - "disconnected": "Getrennt", - "tooltip": "{agent}: {status}", - "tooltipError": "{agent}: {error}", - "title": "Agent-Verbindung", - "triggerAria": "Agent-Verbindung: {status}", - "workingDir": "Arbeitsverzeichnis", - "sessionId": "Sitzungs-ID", - "viewerNote": "Mit einer Sitzung verbunden, die einem anderen Client gehört – ein Neuverbinden hängt nur diese Ansicht erneut an.", - "reconnectInterrupts": "Neu verbinden startet den Agenten neu und unterbricht die laufende Arbeit.", - "reconnect": "Neu verbinden", - "reconnecting": "Verbinde neu...", - "reconnectUnavailable": "Noch keine Sitzung zum Neuverbinden." - }, - "tasks": { - "title": "Aufgaben" - }, - "alerts": { - "title": "Warnungen", - "empty": "Keine Warnungen", - "details": "Details" - }, - "stats": { - "conversations": "{count} Konversationen", - "openUsage": "Sitzungsstatistik und Token-Nutzung anzeigen" - }, - "tokens": { - "contextWindowUsageAria": "Kontextfenster-Nutzung", - "contextWindow": "Kontextfenster", - "usedMax": "Verwendet / Max", - "tokenUsage": "Token-Nutzung", - "input": "Eingabe", - "output": "Ausgabe", - "cacheRead": "Cache lesen", - "cacheWrite": "Cache schreiben", - "total": "Gesamt" - } - }, - "auxPanel": { - "tabs": { - "files": "Dateien", - "changes": "Änderungen", - "commits": "Einträge" - }, - "noFolderTitle": "Kein Ordner geöffnet", - "noFolderHint": "Öffnen Sie einen Ordner, um seinen Inhalt hier zu sehen" - }, - "windowControls": { - "minimizeWindow": "Fenster minimieren", - "minimize": "Minimieren", - "maximizeWindow": "Fenster maximieren", - "maximize": "Maximieren", - "restoreWindow": "Fenster wiederherstellen", - "restore": "Wiederherstellen", - "closeWindow": "Fenster schließen", - "close": "Schließen" - }, - "tabs": { - "closeConversationTab": "Konversationstab schließen", - "close": "Schließen", - "closeOthers": "Andere schließen", - "splitRight": "Nach rechts teilen", - "splitDown": "Nach unten teilen", - "splitAndMoveRight": "Teilen und nach rechts verschieben", - "splitAndMoveDown": "Teilen und nach unten verschieben", - "moveToOppositeGroup": "In gegenüberliegende Gruppe verschieben", - "moveToGroup": "In Gruppe verschieben", - "groupLabel": "Gruppe {index}", - "changeSplitterOrientation": "Teiler-Ausrichtung wechseln", - "unsplit": "Teilung aufheben", - "unsplitAll": "Alle Teilungen aufheben", - "closeAll": "Alle schließen", - "tileDisplay": "Kachelansicht", - "untileDisplay": "Kachel beenden" - }, - "fileWorkspace": { - "files": "Dateien", - "closeFileTab": "Dateitab schließen", - "close": "Schließen", - "closeOthers": "Andere schließen", - "closeAll": "Alle schließen", - "preview": "Vorschau", - "editSource": "Quelle bearbeiten", - "maximize": "Maximieren", - "restore": "Wiederherstellen", - "emptyDirectory": "Leerer Ordner" - }, - "terminal": { - "rename": "Umbenennen", - "close": "Schließen", - "closeOthers": "Andere schließen", - "closeAll": "Alle schließen", - "hideTerminal": "Terminal ausblenden ({shortcut})", - "openFolderFirst": "Öffnen Sie zuerst einen Ordner" - }, - "workspaceDialog": { - "title": "Ordner öffnen", - "manageTitle": "Verknüpfte Ordner", - "addTargetsTitle": "Ordner zum Verknüpfen hinzufügen", - "pickRootDescription": "Wähle den Hauptordner für diesen Arbeitsbereich.", - "linksDescription": "Verknüpfe weitere Ordner als Unterverzeichnisse, damit Agenten aus einem Arbeitsbereich heraus über alle hinweg arbeiten können.", - "addTargetsDescription": "Wähle einen oder mehrere Ordner. Jeder wird zu einem Unterverzeichnis des Arbeitsbereichs.", - "useSystemPicker": "Systemauswahl", - "next": "Weiter", - "back": "Zurück", - "done": "Fertig", - "change": "Ändern", - "addFolders": "Ordner hinzufügen", - "addSelected": "Hinzufügen", - "addSelectedCount": "{count} hinzufügen", - "createCount": "{count} Ordner verknüpfen", - "discardPending": "Verwerfen", - "noLinks": "Noch keine verknüpften Ordner.", - "gitExclude": "Verknüpfungen aus dem Git-Status heraushalten", - "rename": "Umbenennen", - "unlink": "Verknüpfung entfernen", - "repair": "Verknüpfung neu anlegen", - "saveName": "Speichern", - "cancelRename": "Abbrechen", - "removePending": "Entfernen", - "willAppearAs": "Erscheint im Arbeitsbereich als {name}", - "renamedForDuplicate": "Umbenannt – {base} wird bereits von einer anderen Verknüpfung genutzt", - "renamedForExistingEntry": "Umbenannt – {base} existiert in diesem Ordner bereits", - "partiallyCreated": "Nur {count} Ordner konnten verknüpft werden", - "openFailed": "Ordner konnte nicht geöffnet werden", - "previewFailed": "Ausgewählte Ordner konnten nicht geprüft werden", - "createFailed": "Ordner konnten nicht verknüpft werden", - "renameFailed": "Verknüpfung konnte nicht umbenannt werden", - "removeFailed": "Verknüpfung konnte nicht entfernt werden", - "repairFailed": "Verknüpfung konnte nicht neu angelegt werden", - "status": { - "ok": "Verknüpft", - "missing": "Die Verknüpfung ist aus diesem Ordner verschwunden", - "conflicted": "Ein anderer Eintrag nutzt jetzt diesen Namen", - "broken": "Der verknüpfte Ordner existiert nicht mehr" - }, - "nameIssue": { - "empty": "Namen eingeben", - "illegalChars": "Darf / \\ : * ? \" < > | nicht enthalten", - "tooLong": "Name ist zu lang", - "reserved": "Dieser Name ist unter Windows reserviert", - "duplicate": "Dieser Name wird bereits verwendet" - }, - "rejection": { - "not_found": "Dieser Ordner wurde nicht gefunden", - "not_a_directory": "Dieser Pfad ist kein Ordner", - "same_as_root": "Das ist der Arbeitsbereichsordner selbst", - "ancestor_of_root": "Dieser Ordner enthält den Arbeitsbereich", - "inside_root": "Liegt bereits im Arbeitsbereich", - "already_linked": "Bereits verknüpft", - "name_unavailable": "Für diesen Ordner ist kein Name mehr frei", - "alreadyLinkedAs": "Bereits als {name} verknüpft" - } - }, - "folderNameDropdown": { - "fallbackFolderName": "Ordner", - "openFolder": "Ordner öffnen", - "cloneRepository": "Repository klonen", - "projectBoot": "Projekt-Boot", - "opened": "Geöffnet", - "recentOpen": "Zuletzt geöffnet" - }, - "fileWorkspacePanel": { - "addSelectionToChat": "Auswahl zum Chat hinzufügen", - "addToChat": "Zum Chat hinzufügen", - "addSelectionToChatDone": "{label} zur Unterhaltung hinzugefügt", - "addFileToChat": "Datei zum Chat hinzufügen", - "toggleWordWrap": "Zeilenumbruch umschalten", - "addFileToChatDone": "{label} zur Unterhaltung hinzugefügt", - "viewDiff": "Diff anzeigen", - "openFile": "Datei öffnen", - "fileCount": "{count, plural, one {# Datei} other {# Dateien}}", - "openFileOrDiff": "Öffne eine Datei oder Diff im rechten Panel", - "disk": "Datenträger", - "head": "HEAD", - "unsaved": "Ungespeichert", - "workingTree": "Arbeitsverzeichnis", - "loading": "Wird geladen...", - "compareWithBranch": "{path} · vergleichen mit {branch}", - "hunkCount": "{count, plural, one {# Hunk} other {# Hunks}}", - "prev": "Zurück", - "next": "Weiter", - "jumpToLine": "Zu Zeile {line} springen", - "noParsedDiffSections": "Keine geparsten Diff-Abschnitte", - "loadingEditor": "Editor wird geladen...", - "imageZoomIn": "Vergrößern", - "imageZoomOut": "Verkleinern", - "imageZoomReset": "Zoom zurücksetzen", - "htmlPreviewTitle": "HTML-Vorschau", - "htmlPreviewTrust": "Skripte aktivieren", - "htmlPreviewTrustHint": "Skripte dieser Datei ausführen und Netzwerkzugriff erlauben. Nur für vertrauenswürdige Dateien aktivieren.", - "officePreviewTitle": "Office-Dokumentvorschau", - "officeFullRender": "Vollständige Darstellung", - "officeFullRenderHint": "Stellt Morph-Animationen, 3D und Formeln dar (führt die Skripte der Folie aus)", - "officeNotInstalled": "OfficeCLI ist nicht installiert", - "officeNotInstalledHint": "Installiere OfficeCLI unter Einstellungen → Office-Tools, um Word-, Excel- und PowerPoint-Dateien vorzuschauen.", - "officeOpenSettings": "Einstellungen öffnen", - "officeWatchFailed": "Live-Vorschau konnte nicht gestartet werden", - "officeWatchRetry": "Erneut versuchen", - "officeServerInstallHint": "OfficeCLI muss auf dem Server-Host installiert sein. Führe diesen Befehl dort aus und versuche es erneut:", - "officeRemoteDesktopUnsupported": "Die Live-Vorschau ist in einem Remote-Desktop-Fenster nicht verfügbar. Öffne diesen Arbeitsbereich in der Web-Oberfläche des Servers, um Office-Dateien anzusehen." - }, - "branchDropdown": { - "toasts": { - "commitCodeCompleted": "Code-Commit abgeschlossen", - "pushCodeCompleted": "Code-Push abgeschlossen", - "committedFiles": "{count, plural, one {# Datei committet} other {# Dateien committet}}", - "taskCompleted": "{label} abgeschlossen", - "taskFailed": "{label} fehlgeschlagen", - "mergeNoNewCommits": "{branchName} hat keine neuen Commits", - "mergedCommits": "{count, plural, one {# Commit zusammengeführt} other {# Commits zusammengeführt}}", - "allFilesUpToDate": "Alle Dateien sind aktuell", - "updatedFiles": "{count, plural, one {# Datei aktualisiert} other {# Dateien aktualisiert}}", - "openCommitWindowFailed": "Commit-Fenster konnte nicht geöffnet werden", - "openPushWindowFailed": "Push-Fenster konnte nicht geöffnet werden", - "upstreamSet": "Upstream-Branch wurde gesetzt", - "upstreamSetAndPushed": "Upstream-Branch gesetzt und {count, plural, one {# Commit} other {# Commits}} gepusht", - "noCommitsToPush": "Keine Commits zum Pushen", - "pushedCommits": "{count, plural, one {# Commit gepusht} other {# Commits gepusht}}", - "switchedToFolder": "Zu {name} gewechselt", - "switchFailed": "Branch konnte nicht gewechselt werden", - "openStashWindowFailed": "Stash-Fenster konnte nicht geöffnet werden" - }, - "tasks": { - "newBranch": "Branch {name} erstellen", - "newWorktree": "Worktree {name} erstellen", - "checkoutTo": "Zu {branchName} wechseln", - "mergeBranch": "{branchName} mergen", - "rebaseTo": "Auf {branchName} rebasen", - "deleteRemoteBranch": "Remote-Branch {branchName} löschen", - "initGitRepo": "Git-Repository initialisieren", - "pullCode": "Code pullen", - "fetchInfo": "Informationen fetchen", - "pushCode": "Code pushen", - "stashChanges": "Änderungen stashen", - "stashPop": "Stash anwenden", - "deleteBranch": "Branch {branchName} löschen", - "removeWorktree": "Worktree von {branchName} löschen", - "removeWorktreeAndBranch": "Worktree und Branch {branchName} löschen", - "updateBranch": "Branch {branchName} aktualisieren" - }, - "confirm": { - "mergeTitle": "Branch mergen", - "rebaseTitle": "Branch rebasen", - "mergeDescription": "{branchName} in den aktuellen Branch {currentBranch} mergen?", - "rebaseDescription": "Aktuellen Branch {currentBranch} auf {branchName} rebasen?", - "deleteRemoteTitle": "Remote-Branch löschen", - "deleteRemoteDescription": "Remote-Branch {branchName} löschen? Dies entfernt ihn aus dem Remote-Repository und kann nicht rückgängig gemacht werden.", - "deleteTitle": "Branch löschen", - "deleteDescription": "Branch {branchName} löschen? Diese Aktion kann nicht rückgängig gemacht werden.", - "forceDeleteTitle": "Branch erzwungen löschen", - "forceDeleteDescription": "Der Branch {branchName} ist nicht vollständig gemergt. Möchten Sie ihn wirklich erzwungen löschen? Diese Aktion kann nicht rückgängig gemacht werden.", - "deleteWorktreeTitle": "Worktree löschen", - "deleteWorktreeDescription": "Das Worktree-Verzeichnis löschen, in dem {branchName} ausgecheckt ist? Der Branch und seine Commits bleiben erhalten.", - "forceDeleteWorktreeTitle": "Worktree erzwungen löschen", - "forceDeleteWorktreeDescription": "Im Worktree von {branchName} gibt es nicht committete oder nicht verfolgte Dateien. Trotzdem löschen? Diese Änderungen lassen sich nicht wiederherstellen.", - "deleteWorktreeAndBranchTitle": "Worktree und Branch löschen", - "deleteWorktreeAndBranchDescription": "Den Worktree von {branchName}, den Branch selbst und seinen Arbeitsbereich-Ordner löschen? Seine Sitzungen wandern in den Repository-Ordner. Diese Aktion kann nicht rückgängig gemacht werden.", - "forceDeleteWorktreeAndBranchTitle": "Worktree und Branch erzwungen löschen", - "forceDeleteWorktreeAndBranchDescription": "Im Worktree von {branchName} gibt es nicht committete Dateien, oder der Branch ist nicht vollständig gemergt. Trotzdem beides löschen? Diese Aktion kann nicht rückgängig gemacht werden." - }, - "current": "Aktuell", - "switchToBranch": "Zu diesem Branch wechseln", - "mergeBranchIntoCurrent": "{branchName} in {currentBranch} mergen", - "rebaseCurrentToBranch": "{currentBranch} auf {branchName} rebasen", - "noBranch": "Kein Branch", - "detachedHead": "Losgelöster HEAD bei {sha}", - "initGitRepo": "Git-Repository initialisieren", - "pullCode": "Code pullen", - "fetchRemoteBranches": "Remote-Branches fetchen", - "openCommitWindow": "Code committen...", - "pushCode": "Hochladen...", - "pushBranch": "Hochladen", - "newBranch": "Neuer Branch...", - "newWorktree": "Neuer Worktree...", - "stashChanges": "Änderungen stashen...", - "stashPop": "Stash anwenden...", - "manageRemotes": "Remotes verwalten...", - "localBranches": "Lokale Branches ({count, plural, one {#} other {#}})", - "noLocalBranches": "Keine lokalen Branches", - "remoteBranches": "Remote-Branches ({count, plural, one {#} other {#}})", - "noRemoteBranches": "Keine Remote-Branches", - "dialogs": { - "newBranchTitle": "Neuer Branch", - "newBranchDescription": "Neuen Branch vom aktuellen Branch {branch} erstellen", - "branchNamePlaceholder": "Branch-Name", - "newWorktreeTitle": "Neuer Worktree", - "newWorktreeDescription": "Neuen Worktree vom aktuellen Branch {branch} erstellen", - "branchNameLabel": "Branch-Name", - "worktreePathLabel": "Worktree-Pfad", - "worktreePathPlaceholder": "Worktree-Pfad", - "manageRemotesTitle": "Remotes verwalten", - "manageRemotesEmpty": "Keine Remotes konfiguriert", - "remoteNamePlaceholder": "Remote-Name", - "remoteUrlPlaceholder": "Remote-URL", - "addRemote": "Hinzufügen", - "savingRemotes": "Speichern..." - }, - "conflict": { - "title": "Merge-Konflikte", - "description": "Die folgenden Dateien haben Konflikte, die gelöst werden müssen:", - "abort": "Merge abbrechen", - "openMergeTool": "Merge-Tool öffnen", - "completeMerge": "Merge abschließen", - "abortSuccess": "Merge erfolgreich abgebrochen", - "completeSuccess": "Merge erfolgreich abgeschlossen" - }, - "stashDialog": { - "title": "Änderungen stashen", - "description": "Aktuelle Änderungen im Stash speichern", - "messageLabel": "Nachricht", - "messagePlaceholder": "Stash-Nachricht (optional)", - "keepIndex": "Index beibehalten (gestagete Änderungen bleiben erhalten)", - "cancel": "Abbrechen", - "stash": "Stashen", - "success": "Änderungen wurden gestasht", - "error": "Stash fehlgeschlagen" - }, - "unstashDialog": { - "title": "Stash anwenden", - "noStashes": "Keine Stashes vorhanden", - "selectFile": "Datei auswählen um Diff anzuzeigen", - "viewDiff": "Diff anzeigen", - "original": "Original", - "modified": "Geändert", - "apply": "Anwenden", - "drop": "Löschen", - "applySuccess": "Stash angewendet", - "dropSuccess": "Stash gelöscht", - "confirmApply": "Stash {ref} auf das Arbeitsverzeichnis anwenden?", - "cancel": "Abbrechen" - }, - "deleteBranch": "Branch löschen", - "deleteWorktree": "Worktree löschen", - "deleteWorktreeAndBranch": "Worktree und Branch löschen", - "searchPlaceholder": "Branches und Aktionen suchen", - "searchAriaLabel": "Branches und Aktionen suchen", - "branchListLabel": "Branches und Aktionen", - "noMatches": "Keine Treffer" - }, - "commitDialog": { - "toasts": { - "commitCompleted": "Code-Commit abgeschlossen", - "pushFailed": "Push fehlgeschlagen", - "committedFiles": "{count, plural, one {# Datei committet} other {# Dateien committet}}", - "addedToVcs": "Zu VCS hinzugefügt", - "addToVcsFailed": "Hinzufügen zu VCS fehlgeschlagen", - "fileDeleted": "Datei gelöscht", - "deleteFailed": "Löschen fehlgeschlagen", - "fileRolledBack": "Datei zurückgesetzt", - "rollbackFailed": "Rollback fehlgeschlagen", - "dirRolledBack": "Verzeichnis zurückgesetzt", - "dirDeleted": "Verzeichnis gelöscht" - }, - "confirm": { - "deleteTitle": "Löschen bestätigen", - "deleteDescription": "Datei \"{file}\" löschen? Diese Aktion kann nicht rückgängig gemacht werden.", - "rollbackTitle": "Rollback bestätigen", - "rollbackDescription": "Datei \"{file}\" auf HEAD zurücksetzen? Ungespeicherte Änderungen gehen verloren.", - "rollbackDirDescription": "Verzeichnis \"{dir}\" auf HEAD zurücksetzen? Nicht gespeicherte Änderungen gehen verloren.", - "deleteDirDescription": "Verzeichnis \"{dir}\" löschen? Diese Aktion kann nicht rückgängig gemacht werden." - }, - "actions": { - "select": "Auswählen", - "unselect": "Auswahl aufheben", - "rollback": "Zurücksetzen", - "addToVcs": "Zu VCS hinzufügen" - }, - "aria": { - "selectFile": "{action}: {path}", - "unselectAllFiles": "Auswahl aller Dateien aufheben", - "selectAllFiles": "Alle Dateien auswählen", - "unselectTracked": "Auswahl verfolgter Änderungen aufheben", - "selectTracked": "Verfolgte Änderungen auswählen", - "unselectUntracked": "Auswahl nicht verfolgter Dateien aufheben", - "selectUntracked": "Nicht verfolgte Dateien auswählen" - }, - "loading": "Wird geladen...", - "selectionCount": "{selected} / {total} Dateien", - "emptyFiles": "Keine geänderten Dateien", - "trackedChanges": "Verfolgte Änderungen ({count})", - "untrackedFiles": "Nicht verfolgte Dateien ({count})", - "commitMessage": "Commit-Nachricht", - "commitMessagePlaceholder": "Commit-Nachricht eingeben...", - "commitButton": "Einchecken ({count})", - "commitAndPushButton": "Committen und pushen ({count})", - "head": "HEAD", - "workingTree": "Arbeitsverzeichnis", - "clickFileToDiff": "Dateinamen anklicken, um Diff zu sehen", - "loadingDiff": "Diff wird geladen..." - }, - "pushWindow": { - "title": "Code pushen", - "noUnpushedCommits": "Keine ungepushten Commits", - "noRemoteConfigured": "Kein Git-Remote konfiguriert\nFüge einen unter Remotes verwalten hinzu", - "newBranchNoPushedCommits": "Neuer Branch — pushen, um Remote-Tracking-Branch zu erstellen", - "unpushed": "Nicht gepusht", - "selectFileToViewDiff": "Datei auswählen, um Unterschiede anzuzeigen", - "before": "Vorher", - "after": "Nachher", - "push": "Pushen", - "toasts": { - "pushSuccess": "Push erfolgreich", - "pushFailed": "Push fehlgeschlagen", - "upstreamSet": "Remote-Tracking-Branch wurde eingerichtet", - "upstreamSetAndPushed": "Remote-Tracking-Branch eingerichtet und {count} Commits gepusht", - "noCommitsToPush": "Keine Commits zum Pushen", - "pushedCommits": "{count} Commits gepusht" - } - }, - "gitLogTab": { - "filesTitle": "Dateien", - "expandAllFiles": "Alle Dateien ausklappen", - "collapseAllFiles": "Alle Dateien einklappen", - "workspace": "Arbeitsbereich", - "retry": "Erneut versuchen", - "noCommitsFound": "Keine Commits gefunden", - "notAGitRepoTitle": "Kein Git-Repository", - "notAGitRepoHint": "Initialisiere Git über das Branch-Menü oben oder öffne ein bestehendes Repository.", - "hash": "Hash-Wert", - "copyHash": "Hash kopieren", - "copyMessage": "Nachricht kopieren", - "showMore": "Mehr anzeigen", - "showLess": "Weniger anzeigen", - "author": "Autor", - "noFileChangeDetails": "Keine Details zu Dateiänderungen verfügbar.", - "loadingFiles": "Dateien werden geladen...", - "branchesTitle": "Zweige", - "loadingBranches": "Branches werden geladen...", - "noContainingBranches": "Keine enthaltenen Branches gefunden.", - "newBranch": "Neuer Branch...", - "resetToHere": "Auf diesen Stand zurücksetzen", - "resetDisabledReasonNotCurrentBranchView": "Nur in der Ansicht des aktuellen Branches verfügbar", - "copyFullCommitHashAria": "Vollständigen Commit-Hash {hash} kopieren", - "pushStatus": { - "pushed": "Zum Remote gepusht", - "notPushed": "Nicht zum Remote gepusht", - "unknown": "Push-Status unbekannt (kein Upstream konfiguriert)" - }, - "time": { - "monthsAgo": "{count, plural, one {vor # Monat} other {vor # Monaten}}", - "daysAgo": "{count, plural, one {vor # Tag} other {vor # Tagen}}", - "hoursAgo": "{count, plural, one {vor # Stunde} other {vor # Stunden}}", - "minsAgo": "{count, plural, one {vor # Min} other {vor # Min}}", - "justNow": "gerade eben" - }, - "toasts": { - "createdAndSwitchedNewBranch": "Neuen Branch erstellt und gewechselt", - "newBranchFromCommit": "{name} (aus {shortHash})", - "createBranchFailed": "Branch konnte nicht erstellt werden", - "openPushWindowFailed": "Push-Fenster konnte nicht geöffnet werden", - "resetSuccess": "Zurücksetzen erfolgreich", - "resetSuccessDescription": "{branch} wurde mit {mode} auf {shortHash} zurückgesetzt", - "resetFailed": "Zurücksetzen fehlgeschlagen" - }, - "authorFilter": { - "label": "Autor", - "searchPlaceholder": "Autor suchen", - "noAuthors": "Keine Autoren gefunden", - "you": "du", - "filterByAuthorAria": "Commits nach Autor filtern", - "filterByQuery": "Nach \"{query}\" filtern", - "clearAuthorFilterAria": "Autorfilter löschen", - "recent": "Zuletzt verwendet", - "matchingAuthors": "Passende Autoren", - "removeFromRecent": "{name} aus „Zuletzt verwendet“ entfernen" - }, - "branchSelector": { - "label": "Branch", - "head": "HEAD", - "headHint": "Folgt dem aktuellen Branch", - "headHintWithBranch": "Folgt dem aktuellen Branch ({branch})", - "searchBranch": "Branch suchen...", - "noBranches": "Keine Branches", - "selectBranchPlaceholder": "Branch auswählen...", - "localBranches": "Lokale Branches", - "current": "Aktuell", - "remoteBranches": "Remote-Branches", - "refreshCommitHistory": "Commit-Verlauf aktualisieren", - "clearBranchFilterAria": "Branch-Filter löschen" - }, - "dialogs": { - "newBranchTitle": "Neuer Branch", - "newBranchDescription": "Erstelle einen neuen Branch mit Commit {shortHash} als letztem Commit.", - "branchNamePlaceholder": "Branch-Name", - "reset": { - "title": "Aktuellen Branch auf diesen Commit zurücksetzen", - "branchLabel": "Branch", - "targetLabel": "Ziel-Commit", - "messageLabel": "Nachricht", - "modeLabel": "Reset-Modus", - "confirmButton": "Zurücksetzen", - "modes": { - "soft": { - "label": "--soft", - "description": "Verschiebt HEAD und den Zeiger des aktuellen Branches auf den Ziel-Commit.\nIndex und Working Tree bleiben unverändert.\nÄnderungen aus den entfernten Commits bleiben staged." - }, - "mixed": { - "label": "--mixed (Standard)", - "description": "Verschiebt HEAD auf den Ziel-Commit.\nSetzt den Index auf den Ziel-Commit zurück und behält Änderungen im Working Tree.\nÄnderungen wechseln von staged zu unstaged." - }, - "hard": { - "label": "--hard", - "description": "Verschiebt HEAD und setzt sowohl Index als auch Working Tree auf den Ziel-Commit zurück.\nLokale verfolgte Änderungen nach dem Ziel-Commit werden verworfen.\nDies ist eine destruktive Operation." - }, - "keep": { - "label": "--keep", - "description": "Verschiebt HEAD auf den Ziel-Commit und versucht lokale Änderungen zu behalten.\nNur nicht-konfliktierende Änderungen bleiben erhalten.\nBei Konflikten wird der Reset zum Schutz der Änderungen abgebrochen." - } - } - } - }, - "moreActions": "Weitere Git-Aktionen" - }, - "gitChangesTab": { - "workspace": "Arbeitsbereich", - "noChanges": "Keine lokalen Änderungen", - "notAGitRepoTitle": "Kein Git-Repository", - "notAGitRepoHint": "Initialisiere Git über das Branch-Menü oben oder öffne ein bestehendes Repository.", - "trackedChanges": "Verfolgte Änderungen ({count})", - "untrackedFiles": "Nicht verfolgte Dateien ({count})", - "expandTracked": "Verfolgte Änderungen ausklappen", - "collapseTracked": "Verfolgte Änderungen einklappen", - "expandUntracked": "Nicht verfolgte Dateien ausklappen", - "collapseUntracked": "Nicht verfolgte Dateien einklappen", - "showRemainingItems": "{count} weitere Einträge anzeigen", - "actions": { - "commitCode": "Code committen", - "rollback": "Zurücksetzen", - "addToVcs": "Zu VCS hinzufügen", - "delete": "Löschen", - "moreActions": "Weitere Git-Aktionen", - "addAllToVcs": "Alle zur VCS hinzufügen", - "rollbackAll": "Alle zurücksetzen", - "refresh": "Aktualisieren" - }, - "toasts": { - "noAddableFilesInDir": "Keine geänderten Dateien in diesem Verzeichnis können zu VCS hinzugefügt werden", - "noRollbackFilesInDir": "Keine geänderten Dateien in diesem Verzeichnis können zurückgesetzt werden", - "addedToVcs": "{name} zu VCS hinzugefügt", - "addToVcsFailed": "Hinzufügen zu VCS fehlgeschlagen", - "openCommitWindowFailed": "Commit-Fenster konnte nicht geöffnet werden", - "rolledBack": "{name} zurückgesetzt", - "rollbackFailed": "Rollback fehlgeschlagen", - "addedFilesToVcs": "{count, plural, one {# Datei} other {# Dateien}} zu VCS hinzugefügt", - "rolledBackFiles": "{count, plural, one {# Datei zurückgesetzt} other {# Dateien zurückgesetzt}}", - "deleted": "{name} gelöscht", - "deleteFailed": "Löschen fehlgeschlagen", - "deletedFiles": "{count} Dateien gelöscht", - "noDeletableFilesInDir": "In diesem Verzeichnis gibt es keine löschbaren geänderten Dateien", - "commitFailed": "Commit fehlgeschlagen" - }, - "directoryDialog": { - "descriptionAdd": "Dateien unter Verzeichnis {path} auswählen, um sie zu VCS hinzuzufügen.", - "descriptionRollback": "Dateien unter Verzeichnis {path} auswählen, um sie zurückzusetzen.", - "descriptionDelete": "Dateien unter Verzeichnis {path} auswählen, um sie zu löschen. Diese Aktion kann nicht rückgängig gemacht werden.", - "descriptionFallback": "Dateien auswählen, um fortzufahren.", - "selectionCount": "{selected} / {total} Dateien ausgewählt", - "selectAll": "Alle auswählen", - "unselectAll": "Auswahl aller aufheben", - "loadingCandidates": "Verzeichnisänderungen werden geladen...", - "noOperableFiles": "Keine bearbeitbaren Dateien" - }, - "rollbackConfirm": { - "title": "Rollback bestätigen", - "descriptionWithTarget": "Lokale Änderungen für {kind} \"{name}\" zurücksetzen?", - "descriptionFallback": "Lokale Änderungen zurücksetzen?", - "kindDirectory": "Verzeichnis", - "kindFile": "Datei" - }, - "deleteConfirm": { - "title": "Löschen bestätigen", - "descriptionWithTarget": "{kind} \"{name}\" löschen? Diese Aktion kann nicht rückgängig gemacht werden.", - "descriptionFallback": "Diese Aktion kann nicht rückgängig gemacht werden.", - "kindDirectory": "Verzeichnis", - "kindFile": "Datei" - }, - "quickCommit": { - "placeholder": "Commit-Nachricht (Enter zum Committen)" - } - }, - "tabContext": { - "loadingConversation": "Wird geladen...", - "untitledConversation": "Unbenannte Konversation", - "newConversation": "Neue Konversation" - }, - "fileTreeTab": { - "workspace": "Arbeitsbereich", - "retry": "Erneut versuchen", - "git": "Git", - "openInFileManager": "Im Dateimanager öffnen", - "openInFinder": "In Finder öffnen", - "openInExplorer": "In Explorer öffnen", - "attachToCurrentSession": "Zur Sitzung hinzufügen", - "compareWithBranch": "Mit Branch vergleichen...", - "reloadFromDisk": "Von Datenträger neu laden", - "new": "Neu", - "newFile": "Datei", - "newDirectory": "Verzeichnis", - "openIn": "Öffnen in", - "openInTerminal": "Im Terminal öffnen", - "linkedFolder": "Verknüpfter Ordner", - "copyPath": "Pfad kopieren", - "upload": "Dateien/Ordner hochladen", - "download": "Datei herunterladen", - "downloadAsZip": "Als ZIP herunterladen", - "actions": { - "select": "Auswählen", - "unselect": "Auswahl aufheben", - "commitCode": "Code committen", - "rollback": "Zurücksetzen", - "addToVcs": "Zu VCS hinzufügen" - }, - "aria": { - "selectPath": "{action}: {path}" - }, - "toasts": { - "openDirectoryFailed": "Verzeichnis konnte nicht geöffnet werden", - "openBuiltinTerminalFailed": "Integriertes Terminal konnte nicht geöffnet werden", - "openCommitWindowFailed": "Commit-Fenster konnte nicht geöffnet werden", - "noAddableFilesInDir": "Keine geänderten Dateien in diesem Verzeichnis können zu VCS hinzugefügt werden", - "noRollbackFilesInDir": "Keine geänderten Dateien in diesem Verzeichnis können zurückgesetzt werden", - "addedToVcs": "{name} zu VCS hinzugefügt", - "addToVcsFailed": "Hinzufügen zu VCS fehlgeschlagen", - "loadBranchesFailed": "Branches konnten nicht geladen werden", - "renameFailed": "Umbenennen fehlgeschlagen", - "moveFailed": "Verschieben fehlgeschlagen", - "deleteFailed": "Löschen fehlgeschlagen", - "rolledBack": "{name} zurückgesetzt", - "rollbackFailed": "Zurücksetzen fehlgeschlagen", - "addedFilesToVcs": "{count, plural, one {# Datei zu VCS hinzugefügt} other {# Dateien zu VCS hinzugefügt}}", - "rolledBackFiles": "{count, plural, one {# Datei zurückgesetzt} other {# Dateien zurückgesetzt}}", - "savedAsCopy": "Als Kopie gespeichert", - "saveCopyFailed": "Speichern als Kopie fehlgeschlagen", - "watchStartFailed": "Dateiwatch konnte nicht gestartet werden", - "createFailed": "Erstellen fehlgeschlagen", - "downloadFailed": "Herunterladen von {name} fehlgeschlagen", - "downloadSaved": "{name} heruntergeladen", - "pathCopied": "Pfad kopiert", - "copyPathFailed": "Pfad konnte nicht kopiert werden" - }, - "createDialog": { - "newFile": "Neue Datei", - "newDirectory": "Neues Verzeichnis", - "description": "Geben Sie einen Namen für das neue {kind} ein.", - "placeholderFile": "file-name.ext", - "placeholderDirectory": "folder-name" - }, - "renameDialog": { - "renameDirectory": "Verzeichnis umbenennen", - "renameFile": "Datei umbenennen", - "description": "Geben Sie einen neuen Namen ein (nur Name, kein Pfad).", - "placeholderDirectory": "neuer-ordnername", - "placeholderFile": "neuer-dateiname.ext" - }, - "uploadDialog": { - "title": "In den Arbeitsbereich hochladen", - "description": "Passe das Ziel bei Bedarf an und füge Dateien oder Ordner hinzu.", - "workspaceRoot": "Arbeitsbereich-Stammverzeichnis", - "targetPathLabel": "Hochladen nach", - "targetPathHint": "Aufgelöster Pfad: {path}", - "dropHint": "Dateien oder Ordner hier ablegen oder die Schaltflächen unten verwenden", - "dropHintActive": "Loslassen, um zur Warteschlange hinzuzufügen", - "selectFiles": "Dateien auswählen", - "selectFolder": "Ordner auswählen", - "startUpload": "Upload starten", - "clearQueue": "Erledigte entfernen", - "removeItem": "Aus der Warteschlange entfernen", - "retry": "Wiederholen", - "dropZoneAria": "Dateien hier ablegen oder aktivieren zum Durchsuchen", - "folderEmpty": "Keine Dateien im abgelegten Ordner gefunden", - "summary": "Gesamt: {total} · Erfolgreich: {succeeded} · Fehlgeschlagen: {failed}", - "status": { - "pending": "Wartet", - "uploading": "Wird hochgeladen", - "success": "Fertig", - "error": "Fehlgeschlagen", - "cancelled": "Abgebrochen" - } - }, - "directoryDialog": { - "descriptionAdd": "Wählen Sie Dateien im Verzeichnis {path} aus, um sie zu VCS hinzuzufügen.", - "descriptionRollback": "Wählen Sie Dateien im Verzeichnis {path} aus, um sie zurückzusetzen.", - "descriptionFallback": "Wählen Sie Dateien aus, um fortzufahren.", - "selectionCount": "{selected} / {total} Dateien ausgewählt", - "selectAll": "Alle auswählen", - "unselectAll": "Auswahl aufheben", - "loadingCandidates": "Verzeichnisänderungen werden geladen...", - "noOperableFiles": "Keine bearbeitbaren Dateien" - }, - "compareDialog": { - "title": "Mit Branch vergleichen", - "descriptionWithTarget": "Wählen Sie einen Branch und vergleichen Sie mit {kind} {path}", - "descriptionFallback": "Wählen Sie einen Branch zum Vergleichen.", - "kindDirectory": "Verzeichnis", - "kindFile": "Datei", - "filterPlaceholder": "Branches filtern, z. B. main / origin/main", - "singleClickHint": "Klicken Sie auf einen Branch, um direkt zu vergleichen", - "loadingBranches": "Branches werden geladen...", - "recentBranches": "Letzte Branches ({count})", - "noCurrentBranch": "Kein aktueller Branch", - "localBranches": "Lokale Branches ({count})", - "remoteBranches": "Remote-Branches ({count})", - "noMatchingBranches": "Keine passenden Branches" - }, - "externalConflictDialog": { - "title": "Externe Dateiänderungen erkannt", - "descriptionWithPath": "Datei {path} wurde auf dem Datenträger geändert, und aktuelle Bearbeitungen sind nicht gespeichert.", - "descriptionFallback": "Aktuelle Datei wurde auf dem Datenträger geändert, und aktuelle Bearbeitungen sind nicht gespeichert.", - "compare": "Vergleichen", - "savingCopy": "Kopie wird gespeichert...", - "saveAsCopy": "Als Kopie speichern", - "reload": "Neu laden" - }, - "deleteConfirm": { - "title": "Löschen bestätigen", - "descriptionWithTarget": "{kind} \"{name}\" löschen? Diese Aktion kann nicht rückgängig gemacht werden.", - "descriptionFallback": "Diese Aktion kann nicht rückgängig gemacht werden.", - "kindDirectory": "Verzeichnis", - "kindFile": "Datei" - }, - "rollbackConfirm": { - "title": "Zurücksetzen bestätigen", - "descriptionWithTarget": "Lokale Änderungen für Datei \"{name}\" zurücksetzen?", - "descriptionFallback": "Lokale Änderungen für diese Datei zurücksetzen?" - }, - "terminalTitle": "Konsole · {name}" - }, - "commandDropdown": { - "loading": "Wird geladen...", - "addCommand": "Befehl hinzufügen", - "manageCommands": "Befehle verwalten...", - "runCommandTitle": "Ausführen: {command}", - "stopCommandTitle": "Stoppen: {command}", - "manageDialog": { - "title": "Befehle verwalten", - "empty": "Noch keine Befehle", - "noResults": "Keine passenden Befehle", - "searchPlaceholder": "Befehle suchen", - "newCommand": "Neuer Befehl", - "nameLabel": "Bezeichnung", - "commandLabel": "Befehl", - "dragSort": "Zum Sortieren ziehen", - "dragSortCommand": "{name} zum Sortieren ziehen", - "orderFailed": "Befehlsreihenfolge konnte nicht gespeichert werden", - "loadFailed": "Befehle konnten nicht geladen werden", - "saveFailed": "Befehl konnte nicht gespeichert werden", - "deleteFailed": "Befehl konnte nicht gelöscht werden", - "confirmDelete": { - "title": "Befehl löschen?", - "message": "Dadurch wird \"{name}\" entfernt. Diese Aktion kann nicht rückgängig gemacht werden." - } - } - }, - "workspaceContext": { - "confirmCloseDirtyTab": "„{title}“ ohne Speichern schließen?", - "confirmCloseOtherDirtyTabs": "Andere Tabs mit ungespeicherten Änderungen schließen?", - "confirmCloseAllDirtyTabs": "Alle Tabs mit ungespeicherten Änderungen schließen?", - "unableLoadContent": "Inhalt konnte nicht geladen werden.\n\n{message}", - "previewRequestTimedOut": "Vorschauanfrage hat das Zeitlimit überschritten", - "diffRequestTimedOut": "Diff-Anfrage hat das Zeitlimit überschritten", - "branchCompareRequestTimedOut": "Branch-Vergleichsanfrage hat das Zeitlimit überschritten", - "commitDiffRequestTimedOut": "Commit-Diff-Anfrage hat das Zeitlimit überschritten", - "saveRequestTimedOut": "Speicheranfrage hat das Zeitlimit überschritten", - "reloadRequestTimedOut": "Neuladeanfrage hat das Zeitlimit überschritten", - "noChanges": "Keine Änderungen.", - "noDiffOutput": "Keine Diff-Ausgabe.", - "diffTitleWorkspace": "Diff · Arbeitsbereich", - "diffDescriptionWorkingTree": "Working Tree (HEAD)", - "diffTitleFile": "Unterschied · {name}", - "compareTitleFile": "Vergleich · {name}", - "compareTitleBranch": "Vergleich · {branch}", - "compareDescriptionPath": "{path} · vergleichen mit {branch}", - "compareDescriptionBranch": "vergleichen mit {branch}", - "diffTitleCommitFile": "Unterschied · {name} @ {hash}", - "diffTitleCommit": "Unterschied · {hash}", - "diffDescriptionCommitPath": "{path} · Commit {commit}", - "diffDescriptionCommit": "Commit {commit}", - "diffTitleConflictFile": "Konflikt · {name}", - "diffDescriptionConflict": "{path} · Disk vs ungespeichert" - }, - "chat": { - "acpConnections": { - "actions": { - "openAgentsSettings": "Agenten-Einstellungen öffnen", - "retry": "Erneut versuchen" - }, - "agentsSetupHint": "Öffnen Sie Einstellungen > Agenten, um die Installation zu verwalten.", - "withSetupHint": "{message}\n{hint}", - "blocked": { - "missingConfig": "Aktuelle Agenten-Konfiguration kann nicht gelesen werden.", - "disabled": "{agent} ist in den Agenten-Einstellungen deaktiviert. Aktivieren Sie ihn vor dem Verbinden.", - "unavailable": "{agent} ist auf der aktuellen Plattform nicht verfügbar.", - "sdkMissing": "{agent} SDK ist nicht installiert", - "adapterMissing": "Der ACP-Adapter von {agent} ist nicht installiert" - }, - "backendErrors": { - "initializeTimeout": "Der Verbindungs-Handshake von {agent} hat nach 60 Sekunden das Zeitlimit überschritten. Öffnen Sie die Einstellungen, um Agenten- und Netzwerkkonfiguration zu prüfen.", - "mcpRejectedByAgent": "{agent} hat die Sitzung abgelehnt, während codegs MCP-Begleitprozess angehängt war: {message} Falls dieser Agent MCP nicht unterstützt, deaktivieren Sie „MCP-Unterstützung“ in den Einstellungen und verbinden Sie erneut.", - "processExited": "{agent}-Prozess wurde unerwartet beendet.", - "spawnFailed": "{agent} konnte nicht gestartet werden: {message}", - "downloadFailed": "{agent}-Download fehlgeschlagen: {message}", - "sessionLoadResourceNotFound": "{agent}-Sitzung konnte nicht geladen werden. Neu laden, um es erneut zu versuchen, oder eine neue Konversation starten.", - "sessionLoadUnavailable": "{agent} konnte diese Sitzung nicht wiederherstellen – sie wurde möglicherweise beendet oder der Agent wurde gestoppt. Neu laden, um es erneut zu versuchen, oder eine neue Konversation starten.", - "turnFailedRefusal": "{agent} hat die Fortsetzung dieser Runde abgelehnt. Häufig deutet das auf einen Backend- oder Gateway-Fehler hin. Bitte prüfen Sie die Agent-Logs.", - "turnFailedMaxTokens": "{agent} hat das Token-Limit für diese Runde erreicht.", - "turnFailedMaxTurnRequests": "{agent} hat die maximale Anzahl zulässiger Anfragen für diese Runde erreicht.", - "turnFailedUnknown": "{agent} hat die Runde mit einem unbekannten Stoppgrund beendet.", - "grokModelSwitchIncompatibleAgent": "{agent} kann in einer bestehenden Unterhaltung nicht zu diesem Modell wechseln. Starte eine neue Sitzung, um es zu verwenden.", - "turnFailedEmpty": "{agent} hat die Runde ohne jegliche Antwort beendet.", - "turnFailedEmptyProtocol": "{agent} hat eine Ausgabe erzeugt, die codeg nicht auswerten konnte — die Agent-Version passt möglicherweise nicht zum Protokoll.", - "turnFailedEmptyMetadata": "{agent} hat in dieser Runde nur Statusaktualisierungen gesendet (Plan / Modus / Verbrauch) und keine Antwort.", - "detailsInAlerts": "Öffnen Sie die Warnungen in der Statusleiste und klappen Sie die Details auf, um die Ausgabe des Agents zu sehen." - }, - "unableReadAgentConfig": "Agenten-Konfiguration kann nicht gelesen werden: {message}", - "connectFailedTitle": "{agent} Verbindung fehlgeschlagen", - "toolFallbackTitle": "Werkzeug", - "eventErrorTitle": "Agentenfehler", - "notificationTurnComplete": "{agent} hat die Antwort abgeschlossen", - "notificationError": "{agent} Fehler: {message}", - "claudeApiRetry": { - "fallbackError": "authentication_failed", - "retryingWithMax": "erneuter Versuch {attempt}/{max}", - "retryingAttempt": "erneuter Versuch {attempt}", - "retrying": "erneuter Versuch", - "nextRetryIn": "nächster in {seconds}s", - "line": "{error}{status} · {retry}", - "lineWithDelay": "{error}{status} · {retry}, {delay}", - "httpStatus": " (HTTP {status})" - }, - "configOptionAdjusted": "{agent} hat {option} auf {actual} statt {requested} gesetzt" - }, - "connectionLifecycle": { - "tasks": { - "connectingTitle": "Verbinde mit {agent}", - "connectingDescription": "Verbindung wird hergestellt", - "loadingSelectorsTitle": "{agent}-Selektoren werden geladen", - "loadingSelectorsDescription": "Modus- und Sitzungsoptionen werden abgerufen", - "initSessionTitle": "Initializing {agent} session", - "initSessionDescription": "Creating session and loading configuration" - }, - "errors": { - "connectionFailed": "Verbindung fehlgeschlagen", - "sendPromptFailed": "Nachricht konnte nicht gesendet werden: {error}" - } - }, - "shared": { - "attachedResources": "Angehängte Ressourcen", - "toolCallFailed": "Tool-Aufruf fehlgeschlagen" - }, - "messageThread": { - "emptyTitle": "Noch keine Nachrichten", - "emptyDescription": "Starten Sie eine Unterhaltung, um hier Nachrichten zu sehen" - }, - "chatInput": { - "connecting": "Verbinden...", - "agentResponding": "{agent} antwortet...", - "sendMessage": "Nachricht senden..." - }, - "messageInput": { - "askAnything": "Fragen Sie alles...", - "removeAttachmentAria": "{name} entfernen", - "attachFiles": "Dateien anhängen", - "addActions": "Hinzufügen", - "quickMessages": "Schnellnachrichten", - "quickMessagesEmpty": "Noch keine Schnellnachrichten", - "quickMessagesLoading": "Wird geladen...", - "pasteAsPlainText": "Als reinen Text einfügen", - "cut": "Ausschneiden", - "copy": "Kopieren", - "selectAll": "Alles auswählen", - "pasteUnavailable": "Zwischenablage konnte nicht gelesen werden. Mit Strg/⌘V einfügen.", - "clipboardWriteFailed": "Schreiben in die Zwischenablage fehlgeschlagen. Bitte das Tastenkürzel verwenden.", - "quickMessageUntitled": "Ohne Titel", - "liveFeedback": "Live-Feedback", - "liveFeedbackDisabledHint": "Verfügbar, während der Agent arbeitet", - "dropFilesToAttach": "Dateien zum Anhängen ablegen", - "loadingSettings": "Einstellungen werden geladen...", - "loadingMode": "Modus wird geladen...", - "modeLabel": "Modus", - "toggleOn": "Ein", - "toggleOff": "Aus", - "agentSettings": "Agent-Einstellungen", - "searchModel": "Modelle suchen...", - "searchModelAria": "Modelle suchen", - "modelListLabel": "Modelle", - "noModels": "Keine Modelle gefunden", - "cancel": "Abbrechen", - "send": "Senden", - "forkAndSend": "Fork & Senden", - "queueMessage": "In Warteschlange stellen", - "steerIntoTurn": "In laufenden Turn einfügen", - "steerQueuedInstead": "Stattdessen in die Warteschlange gestellt – wird mit dem nächsten Turn gesendet.", - "steerFailed": "Konnte nicht in den laufenden Turn eingefügt werden", - "steerAttachmentsUnsupported": "Nur Text – Entwürfe mit Anhängen laufen über die Warteschlange.", - "slashCommands": "Slash-Befehle", - "slashSearchPlaceholder": "Befehle suchen...", - "slashSearchEmpty": "Keine passenden Befehle", - "experts": "Experten", - "office": "Büroarbeit", - "research": "Forschung", - "attachLocalUpload": "Lokale Datei hochladen", - "attachServerFile": "Serverdatei auswählen", - "attachUploadTooLarge": "{names} überschreitet das Upload-Limit von {limit}MB und wurde übersprungen.", - "attachUploadFailed": "Upload fehlgeschlagen: {names}.", - "attachUploadNotAFile": "{names} ist keine reguläre Datei (Verzeichnis oder Spezialdatei) und wurde übersprungen.", - "attachUploadQuotaExceeded": "Auf dem Server ist kein Upload-Speicher mehr verfügbar; {names} konnte nicht hochgeladen werden.", - "attachUploadInProgress": "Bilder werden noch hochgeladen – versuche es gleich noch einmal.", - "mentionEmpty": "Keine Treffer", - "mentionLoading": "Suche läuft…", - "mentionListLabel": "Erwähnungen", - "mentionMore": "Weitere Ergebnisse – tippe weiter, um zu filtern", - "mentionCount": "{count, plural, one {# Ergebnis} other {# Ergebnisse}}", - "mentionGroupFile": "Dateien", - "mentionGroupAgent": "Agenten", - "mentionGroupSession": "Sitzungen", - "mentionGroupCommit": "Commits", - "mentionGroupSkill": "Fähigkeiten" - }, - "messageQueue": { - "addToQueue": "Zur Warteschlange", - "saveEdit": "Speichern", - "cancelEdit": "Bearbeitung abbrechen", - "editItem": "Bearbeiten", - "deleteItem": "Entfernen" - }, - "welcomeInputPanel": { - "agentsSettingsPath": "Einstellungen > Agenten", - "autoConnectFallback": "Klicken Sie, um {path} zu öffnen und die Installation zu verwalten.", - "autoConnectAppend": "{message}. Klicken Sie, um {path} zu öffnen und die Installation zu verwalten.", - "enableAgentFirstPlaceholder": "Aktivieren Sie mindestens einen Agenten, bevor Sie eine Sitzung starten...", - "prepareSessionFailed": "Die Chat-Sitzung konnte nicht vorbereitet werden. Bitte versuche es erneut.", - "createConversationFailed": "Die Konversation konnte nicht erstellt werden. Bitte versuche es erneut.", - "askAnythingPlaceholder": "Fragen Sie alles...", - "agentNotInstalled": "{agent} ist nicht installiert · in den Agents-Einstellungen installieren", - "agentAdapterNotInstalled": "Der ACP-Adapter von {agent} ist nicht installiert (unabhängig von deiner eigenen CLI) · in den Agents-Einstellungen installieren" - }, - "welcomePanel": { - "greeting": "Was möchtest du heute machen?", - "tips": { - "tileTabs": "Klicke mit der rechten Maustaste auf einen Konversations-Tab und wähle Kachelansicht, um mehrere Sitzungen nebeneinander zu sehen.", - "pinTab": "Doppelklicke auf einen Konversations-Tab, um ihn anzuheften – so wird er nicht von einer neuen Sitzung automatisch ersetzt.", - "shortcutsNewSearch": "{newConversation} öffnet eine neue Konversation, {searchConversations} durchsucht den Verlauf.", - "slashAtMention": "Tippe / im Eingabefeld für Slash-Befehle oder @, um eine Datei aus dem Projekt zu referenzieren.", - "pasteDropFiles": "Füge einen Screenshot ein oder ziehe eine Datei direkt ins Eingabefeld, um sie anzuhängen.", - "queueMessage": "Während der Agent antwortet, kannst du weitertippen – deine nächste Nachricht wird in die Warteschlange gestellt und automatisch gesendet.", - "draftAutoSave": "Nicht gesendete Entwürfe werden pro Konversation automatisch gespeichert und beim Zurückkehren wiederhergestellt.", - "forkSend": "Im Dropdown der Senden-Schaltfläche gibt es Verzweigen und senden – verzweige vom aktuellen Punkt in einen neuen Tab.", - "exportConversation": "Klicke mit der rechten Maustaste in die Konversation, um sie als Markdown, HTML oder Bild zu exportieren.", - "chatChannels": "Verbinde Telegram / Lark / WeChat unter Einstellungen → Chat-Kanäle, um vom Handy aus weiterzuarbeiten.", - "shortcutsAuxPanel": "{toggleAuxPanel} blendet das rechte Panel ein – mit den geänderten Dateien und Git-Änderungen dieser Sitzung.", - "shortcutsTerminalSidebar": "{toggleTerminal} öffnet das eingebaute Terminal, {toggleSidebar} schaltet die Seitenleiste um.", - "customShortcuts": "Alle Tastenkürzel lassen sich unter Einstellungen → Tastenkürzel frei belegen.", - "webService": "Aktiviere Einstellungen → Webdienst, damit Teammitglieder dasselbe codeg im Browser nutzen können.", - "fusionMode": "Öffne eine Datei oder ein Diff, um es automatisch neben der Konversation zu sehen.", - "quickMessages": "Klicke auf die +-Schaltfläche neben der Eingabe und wähle Schnellnachrichten, um ein gespeichertes Snippet einzufügen (verwaltbar unter Einstellungen → Schnellnachrichten).", - "experts": "Die +-Schaltfläche hat ein Menü Expertenfähigkeiten – lade Rollen wie Debugging oder Planung mit einem Klick.", - "taskBoard": "To-dos führen eine Aufgabe von Anfang bis Ende aus: Der Agent arbeitet in einem eigenen Worktree, du prüfst das Diff und mergest.", - "automations": "Automatisierungen führen einen gespeicherten Prompt nach Zeitplan aus – etwa ein nächtliches Review – und jeder Lauf kann einen eigenen Worktree bekommen.", - "tokenUsage": "Klicke auf die Konversationszahl in der Statusleiste, um den Token-Verbrauch zu öffnen – aufgeschlüsselt nach Tag, Agent, Modell und Ordner.", - "mentionTargets": "@ holt mehr als Dateien: Erwähne einen anderen Agenten, um eine Teilaufgabe abzugeben, oder verweise auf eine frühere Sitzung, einen Commit oder einen Skill.", - "splitGroups": "Rechtsklick auf einen Tab, dann Nach rechts teilen oder Nach unten teilen – so bleiben zwei Konversationen in eigenen Bereichen offen.", - "worktrees": "Öffne die Branch-Schaltfläche und wähle Neuer Worktree, damit mehrere Agenten dasselbe Repository bearbeiten, ohne sich gegenseitig die Dateien zu überschreiben.", - "importSessions": "Schon Sitzungen im Terminal gelaufen? Im Menü eines Ordners holt Lokale Sitzungen importieren diesen Verlauf nach codeg.", - "subSessions": "Delegiert ein Agent, erscheint die Untersitzung in der Seitenleiste verschachtelt darunter – klapp die Zeile auf, um jeder einzeln zu folgen.", - "liveFeedback": "Live-Feedback im +-Menü schiebt eine Notiz in den Zug, den der Agent gerade ausführt – ohne ihn zu unterbrechen.", - "skillPacks": "Einstellungen → Skill-Pakete bündelt Coding-Experten, wissenschaftliche Recherche und Office-Skills – pro Agent aktivierbar.", - "modelProviders": "Einstellungen → Modellanbieter nimmt deinen eigenen API-Key oder Endpunkt entgegen; das Modell wählst du danach direkt im Eingabefeld.", - "workspaceBackground": "Einstellungen → Darstellung setzt ein Hintergrundbild für den Arbeitsbereich, die Panel-Deckkraft und die Schriftarten der App." - }, - "quickActions": { - "excel": "Excel-Arbeitsmappe", - "excelDesc": "Datentabellen, Formeln & Diagramme", - "word": "Word-Dokument", - "wordDesc": "Berichte, Briefe & Memos", - "ppt": "Präsentation", - "pptDesc": "Folien mit professionellem Design", - "pitchDeck": "Pitch Deck", - "pitchDeckDesc": "Investoren-Deck mit Kennzahlen", - "morph": "Morph-Animation", - "morphDesc": "Filmreife Folienübergänge", - "morph3d": "3D-Morph", - "morph3dDesc": "3D-Modelle mit Kamerafahrten", - "academic": "Wissenschaftliche Arbeit", - "academicDesc": "Forschung mit Zitaten & Struktur", - "financial": "Finanzmodell", - "financialDesc": "Abschlüsse, DCF & Prognosen", - "dashboard": "Daten-Dashboard", - "dashboardDesc": "KPIs & Analysen aus deinen Daten", - "prompts": { - "excel": "Erstelle eine Excel-Arbeitsmappe mit den folgenden Anforderungen:\n\n[beschreibe hier deine Daten, Tabellen, Formeln und Diagramme]", - "word": "Erstelle ein Word-Dokument mit den folgenden Anforderungen:\n\n[beschreibe hier Inhalt, Struktur und Formatierung des Dokuments]", - "ppt": "Erstelle eine PowerPoint-Präsentation mit den folgenden Anforderungen:\n\n[beschreibe hier deine Folien, Inhalte und das Design]", - "pitchDeck": "Erstelle ein Investoren-Pitch-Deck mit den folgenden Anforderungen:\n\n[beschreibe hier dein Unternehmen, die Finanzierungsrunde und die wichtigsten Kennzahlen]", - "morph": "Erstelle eine Präsentation mit Morph-Übergangsanimationen:\n\n[beschreibe hier das Thema der Präsentation und die gewünschten visuellen Effekte]", - "morph3d": "Erstelle eine 3D-Morph-Präsentation mit GLB-Modellen und Kamerafahrten:\n\n[beschreibe hier dein Thema und das visuelle 3D-Konzept]", - "academic": "Schreibe eine wissenschaftliche Arbeit in Word mit den folgenden Anforderungen:\n\n[beschreibe hier dein Forschungsthema, die Methodik und die wichtigsten Ergebnisse]", - "financial": "Erstelle ein Finanzmodell in Excel mit den folgenden Anforderungen:\n\n[beschreibe hier deine Finanzabschlüsse, Prognosen und Analysen]", - "dashboard": "Erstelle ein Daten-Dashboard in Excel mit den folgenden Anforderungen:\n\n[beschreibe hier deine Datenquelle, KPIs und Diagramme]", - "scientific-brainstorming": "Hilf mir beim Brainstorming von Forschungsrichtungen — erkunde interdisziplinäre Verbindungen, hinterfrage Annahmen und finde vielversprechende Lücken. Mein Themenbereich: ", - "hypothesis-generation": "Hilf mir, diese Beobachtungen in prüfbare Hypothesen zu überführen — mit klaren Vorhersagen, plausiblen Mechanismen und Experimenten. Meine Beobachtungen: ", - "experimental-design": "Hilf mir, vor der Datenerhebung ein rigoroses Experiment zu planen — Design, Randomisierung, Kontrollen und wie man Confounding vermeidet. Was ich untersuchen möchte: ", - "statistical-power": "Hilf mir, die benötigte Stichprobengröße zu bestimmen — führe mich durch eine Poweranalyse (Effektstärke, Alpha, Power) für mein Design. Details: ", - "statistical-analysis": "Hilf mir, diese Daten korrekt zu analysieren — den richtigen Test wählen, Annahmen prüfen, Effektstärken berichten und alles aufschreiben. Meine Daten und Frage: ", - "exploratory-data-analysis": "Führe eine explorative Analyse meiner Datendatei durch — fasse Struktur, Qualität und auffällige Muster zusammen und schlage nächste Schritte vor. Die Datei ist: ", - "scientific-visualization": "Hilf mir, eine publikationsreife Abbildung zu erstellen — klares Layout, ehrliche Fehlerbalken, eine farbenblindensichere Palette und Journal-Formatierung. Was ich zeigen möchte: ", - "scientific-critical-thinking": "Hilf mir, diese Studie oder Behauptung kritisch zu bewerten — beurteile die Evidenzqualität, erkenne Verzerrungen und Confounder und wäge die Schlussfolgerungen ab. Hier ist sie: ", - "paper-lookup": "Hilf mir, relevante Artikel und Open-Access-Volltexte in wissenschaftlichen Datenbanken zu finden, mit wiederverwendbaren Zitaten. Ich suche: " - }, - "paper-lookup": "Publikationssuche", - "paper-lookupDesc": "10 wissenschaftliche APIs (PubMed, arXiv, OpenAlex, Crossref…) nach Artikeln, Zitationen und Open-Access-Volltext durchsuchen.", - "scientific-critical-thinking": "Kritisches Denken", - "scientific-critical-thinkingDesc": "Wissenschaftliche Aussagen und Evidenzqualität beurteilen — Verzerrungen und Confounder erkennen, GRADE anwenden.", - "scientific-visualization": "Wissenschaftliche Visualisierung", - "scientific-visualizationDesc": "Publikationsreife Abbildungen — Mehrfeld-Layouts, Signifikanz-Annotationen und journalspezifische Formate.", - "exploratory-data-analysis": "Explorative Datenanalyse", - "exploratory-data-analysisDesc": "Automatisierte Exploration wissenschaftlicher Datendateien in über 200 Formaten mit Qualitätsmetriken und Berichten.", - "statistical-analysis": "Statistische Analyse", - "statistical-analysisDesc": "Geführte statistische Analyse — Testauswahl, Annahmenprüfung, Effektstärken und Bericht im APA-Stil.", - "statistical-power": "Teststärke", - "statistical-powerDesc": "Stichprobengröße und Teststärke — benötigte Fallzahl, minimal nachweisbare Effekte und Powerkurven.", - "experimental-design": "Versuchsplanung", - "experimental-designDesc": "Rigorose Studien vor der Datenerhebung planen — Randomisierung, Blockbildung, Kontrollen und faktorielle/DOE-Designs.", - "hypothesis-generation": "Hypothesengenerierung", - "hypothesis-generationDesc": "Beobachtungen in prüfbare Hypothesen mit Vorhersagen, Mechanismen und Experimenten überführen.", - "scientific-brainstorming": "Wissenschaftliches Brainstorming", - "scientific-brainstormingDesc": "Offene Forschungsideen — interdisziplinäre Verbindungen erkunden, Annahmen hinterfragen, Forschungslücken finden.", - "tabs": { - "office": "Büroarbeit", - "coding": "Code-Entwicklung", - "research": "Forschung" - }, - "coding": { - "brainstormingDesc": "Absicht & Anforderungen vor dem Bauen klären", - "debuggingDesc": "Erst die Ursache finden, dann Fixes vorschlagen", - "writingSkillsDesc": "Wiederverwendbare Skills erstellen, bearbeiten & prüfen" - }, - "notEnabled": { - "title": "Skill „{skill}“ ist für {agent} noch nicht aktiviert", - "description": "Aktiviere ihn in den Einstellungen, um ihn hier zu nutzen.", - "action": "Aktivieren", - "hint": "Skill nicht aktiviert" - }, - "scrollPrev": "Vorherige Skills anzeigen", - "scrollNext": "Weitere Skills anzeigen" - } - }, - "agentSelector": { - "noEnabledAgents": "Keine aktivierten Agenten", - "openAgentsSettings": "Agenten-Einstellungen öffnen", - "notInstalled": "Nicht installiert", - "moreAgents": "Weitere Agenten ({count})" - }, - "subAgentOverlay": { - "title": "Subagenten", - "collapsedSummary": "Subagenten {count}", - "collapseAria": "Subagenten einklappen" - }, - "agentPlanOverlay": { - "title": "Agentenplan", - "collapsePlanAria": "Plan einklappen", - "collapsedSummary": "Arbeitsplan {completed}/{total}", - "status": { - "completed": "Abgeschlossen", - "inProgress": "In Bearbeitung", - "pending": "Ausstehend", - "unknown": "Unbekannt" - }, - "priority": { - "high": "Hoch", - "medium": "Mittel", - "low": "Niedrig", - "unknown": "Unbekannt" - } - }, - "permissionDialog": { - "subtitle": "Agent fordert Berechtigung an, um diesen Zug fortzusetzen.", - "queuedCount": "+{count} wartend", - "kindFallbackTool": "Tool", - "command": "Befehl", - "cwd": "Arbeitsverzeichnis: {cwd}", - "filesSummary": "Dateien: {count}", - "moreFiles": "+{count} weitere Dateien", - "plan": "Arbeitsplan", - "allowedActions": "Erlaubte Aktionen", - "targetMode": "Zielmodus: {mode}", - "optionGrants": "Was jede Option gewährt", - "changeScopeSession": "Diese Sitzung", - "changeScopeProcess": "Dieser Lauf", - "changeScopeUser": "In Benutzereinstellungen gespeichert", - "changeScopeProject": "In Projekteinstellungen gespeichert", - "changeScopeProjectLocal": "In lokalen Projekteinstellungen gespeichert", - "changeScopePersistent": "Dauerhaft gespeichert" - }, - "questionDialog": { - "title": "Agent stellt eine Frage", - "placeholder": "Antwort eingeben...", - "send": "Senden" - }, - "messageBranch": { - "previousBranchAria": "Vorheriger Branch", - "nextBranchAria": "Nächster Branch", - "pageOf": "{current} von {total}" - }, - "terminal": { - "title": "Konsole", - "running": "Läuft" - }, - "reasoning": { - "thinking": "Denkt nach…", - "thoughtForFewSeconds": "Nachgedacht", - "thoughtForSeconds": "Nachgedacht" - }, - "linkSafety": { - "errorCannotOpen": "Lokale Datei kann nicht geöffnet werden", - "errorNoWorkspace": "Es ist kein Arbeitsbereichsordner aktiv.", - "errorFailedOpen": "Lokale Datei konnte nicht geöffnet werden", - "errorFailedLink": "Link konnte nicht geöffnet werden", - "errorUnsupportedLinkProtocol": "Dieses Linkprotokoll wird nicht unterstützt." - }, - "fileActions": { - "openInFinder": "In Finder öffnen", - "openInExplorer": "In Explorer öffnen", - "openInFileManager": "Im Dateimanager öffnen", - "copyRelativePath": "Relativen Pfad kopieren", - "copyAbsolutePath": "Absoluten Pfad kopieren", - "pathCopied": "Pfad kopiert", - "copyPathFailed": "Pfad konnte nicht kopiert werden", - "openFailed": "Lokale Datei konnte nicht geöffnet werden" - }, - "messageList": { - "attachedResources": "Angehängte Ressourcen", - "loading": "Lädt...", - "loadEarlier": "Frühere Nachrichten laden", - "loadingEarlier": "Frühere Nachrichten werden geladen…", - "error": "Fehler: {message}", - "errorTitle": "Sitzung konnte nicht geladen werden", - "errorActionReload": "Neu laden", - "errorActionNewSession": "Neue Konversation", - "emptyConversation": "Keine Nachrichten in dieser Unterhaltung.", - "systemMessage": "Systemnachricht", - "copyMessage": "Kopieren", - "copied": "Kopiert", - "downloadImage": "Bild herunterladen", - "downloadFailed": "Download fehlgeschlagen: {message}", - "imageGeneration": "Bildgenerierung", - "imageGenerationPending": "Bild wird generiert…", - "imageGenerationFailed": "Bildgenerierung fehlgeschlagen", - "model": "Modell", - "tokenStats": "Token-Nutzung", - "tokenInput": "Eingabe", - "tokenOutput": "Ausgabe", - "tokenCacheRead": "Cache-Lesen", - "tokenCacheWrite": "Cache-Schreiben", - "duration": "Dauer", - "completedAt": "Abgeschlossen um", - "jumpToPreviousUserMessage": "Zur Benutzernachricht springen", - "showMore": "Mehr anzeigen", - "showLess": "Weniger anzeigen" - }, - "liveTurnStats": { - "thinking": "Denkt nach...", - "streaming": "Übertragung", - "elapsedHours": "{value} Std", - "elapsedMinutes": "{value} Min", - "elapsedSeconds": "{value} Sek", - "outputSpeedAria": "Geschätzte Ausgabegeschwindigkeit", - "outputSpeedTooltip": "Geschätzte Ausgabegeschwindigkeit (Text + Denken)" - }, - "jsonTree": { - "viewRaw": "Rohes JSON anzeigen", - "viewTree": "Baum anzeigen", - "fields": "{count, plural, one {# Feld} other {# Felder}}", - "items": "{count, plural, one {# Eintrag} other {# Einträge}}" - }, - "tool": { - "parameters": "Parameter", - "error": "Fehler", - "result": "Ergebnis", - "status": { - "approvalRequested": "Warten auf Genehmigung", - "approvalResponded": "Beantwortet", - "inputAvailable": "Läuft", - "inputStreaming": "Ausstehend", - "outputAvailable": "Abgeschlossen", - "outputDenied": "Abgelehnt", - "outputError": "Fehler" - } - }, - "toolCallBlock": { - "tool": "Werkzeug", - "error": "Fehler", - "result": "Ergebnis" - }, - "delegation": { - "subAgentRunning": "Unteragent läuft…", - "noDetail": "No detail available yet.", - "unknownAgent": "Sub-Agent", - "openDetail": "Konversation anzeigen", - "detailTitle": "Unteragent-Konversation", - "detailDescription": "Schreibgeschützte Ansicht der delegierten Unteragent-Konversation.", - "waitForResult": "Warte auf das Ergebnis von Aufgabe {task}", - "waitForResultNoTask": "Warte auf das Aufgabenergebnis", - "cancelTask": "Aufgabe {task} wird abgebrochen", - "cancelTaskNoTask": "Aufgabe wird abgebrochen", - "resultPageOf": "{current} / {total}", - "prevResult": "Vorheriges Ergebnis", - "nextResult": "Nächstes Ergebnis", - "noResultText": "Kein Ergebnis bei dieser Prüfung.", - "status": { - "starting": "startet", - "running": "läuft", - "checked": "geprüft", - "waiting": "Genehmigung ausstehend", - "ok": "fertig", - "err": { - "default": "fehlgeschlagen", - "delegation_disabled": "deaktiviert", - "depth_limit": "Tiefenlimit", - "invalid_agent_type": "ungültiger Agent", - "spawn_failed": "Start fehlgeschlagen", - "send_failed": "Senden fehlgeschlagen", - "timeout": "Zeitüberschreitung", - "canceled": "abgebrochen", - "child_refusal": "Subagent verweigerte", - "child_max_tokens": "Subagent: Token-Limit", - "child_max_turn_requests": "Subagent: Anfragelimit", - "child_empty": "Subagent ohne Ausgabe", - "child_unknown": "Subagent: Fehler", - "unknown": "unbekannte Aufgabe" - } - } - }, - "contentParts": { - "showingTailOutput": "Zur besseren Performance wird während des Streamings nur die Endausgabe angezeigt.", - "result": "Ergebnis", - "unknown": "unbekannt", - "inputTruncated": "Eingabe wurde gekürzt — Diff ist möglicherweise unvollständig.", - "replaceAll": "ALLES ERSETZEN", - "filesCount": "Dateien: {count}", - "update": "aktualisieren", - "moreFiles": "+{count} weitere Dateien", - "timeoutMs": "Zeitlimit: {timeout}ms", - "backgroundTrue": "Hintergrund: true", - "scriptToolCalls": "{count, plural, one {# Tool-Aufruf} other {# Tool-Aufrufe}}", - "offset": "Versatz: {offset}", - "limit": "Grenze: {limit}", - "pages": "Seiten: {pages}", - "mode": "Modus: {mode}", - "cell": "Zelle: {cell}", - "shellSession": "Sitzung {id}", - "pathLabel": "Pfad:", - "globLabel": "Glob-Muster:", - "typeLabel": "Typ:", - "outputLabel": "Ausgabe:", - "caseInsensitive": "Groß-/Kleinschreibung ignorieren", - "multiline": "Mehrzeilig", - "promptLabel": "Eingabe", - "subjectLabel": "Betreff", - "taskLabel": "Aufgabe", - "nameLabel": "Bezeichnung:", - "agentPromptLabel": "Eingabe", - "agentModelLabel": "Modell", - "agentRunning": "Läuft...", - "agentLiveTranscript": "Live-Aktivität", - "agentProgressTools": "{count} Tool-Aufrufe", - "agentProgressTurns": "{count} Runden", - "agentProgressContext": "Kontext {pct}%", - "agentSessionAction": "Subagent-Sitzung ansehen", - "agentSessionTitle": "Subagent-Sitzung", - "agentSessionLoading": "Protokoll des Subagenten wird geladen…", - "agentSessionEmpty": "Der Subagent hat noch nichts geschrieben.", - "agentFallbackTitle": "Sub-Agent wird gestartet…", - "agentCodexLaunchOnly": "Gestartet. Codex meldet keinen weiteren Fortschritt dieses Sub-Agenten – sein Ergebnis trifft als Nachricht in dieser Unterhaltung ein.", - "agentStatsBash": "Befehle", - "agentStatsRead": "Dateien gelesen", - "agentStatsSearch": "Suchen", - "agentStatsEdit": "Bearbeitungen", - "agentStatsOther": "Sonstige", - "goal": { - "title": "Ziel:", - "titleWithStatus": "Ziel {status}", - "objective": "Ziel", - "statusLabel": "Status", - "tokensUsed": "Verwendete tokens", - "budget": "Budget", - "remaining": "Verbleibend", - "elapsed": "Verstrichen", - "tokens": "tokens", - "pause": "Pausieren", - "clear": "Löschen", - "status": { - "active": "aktiv", - "paused": "pausiert", - "blocked": "blockiert", - "usageLimited": "Nutzung begrenzt", - "budgetLimited": "Budget begrenzt", - "complete": "abgeschlossen", - "limited": "Limit erreicht" - } - }, - "field": { - "file": "Datei", - "notebook": "Notizbuch", - "command": "Befehl", - "old": "Alt", - "new": "Neu", - "pattern": "Muster", - "path": "Pfad", - "query": "Abfrage", - "url": "URL:", - "description": "Beschreibung", - "content": "Inhalt", - "source": "Quelle", - "prompt": "Eingabe", - "subject": "Betreff", - "taskId": "Aufgaben-ID", - "status": "Zustand", - "skill": "Skill", - "args": "Argumente", - "offset": "Versatz", - "limit": "Grenze", - "glob": "Glob-Muster", - "type": "Typ", - "output": "Ausgabe", - "replaceAll": "Alles ersetzen", - "language": "Sprache", - "timeout": "Zeitlimit", - "background": "Hintergrund", - "agentType": "Agent-Typ", - "library": "Bibliothek", - "libraryId": "Bibliotheks-ID" - }, - "title": { - "edit": "Bearbeiten", - "command": "Befehl", - "script": "Skript", - "waitCommand": "Warten {command}", - "waitCell": "Sitzung {id} abwarten", - "terminateCommand": "Beenden {command}", - "terminateCell": "Sitzung {id} beenden", - "stdinChars": "Eingabe {chars}", - "todoWrite": "TodoWrite (Aufgaben aktualisieren)", - "read": "Lesen", - "write": "Schreiben", - "notebookEdit": "NotebookEdit (Notizbuch bearbeiten)", - "editFiles": "Bearbeiten ({count} Dateien)", - "editWithTarget": "{target} bearbeiten", - "readWithTarget": "{target} lesen", - "writeWithTarget": "{target} schreiben", - "notebookEditWithTarget": "NotebookEdit ({target})", - "globWithPattern": "Glob-Muster {pattern}", - "listFilesWithPath": "Dateien auflisten {path}", - "grepWithPattern": "Grep-Muster {pattern}", - "taskCreateWithSubject": "Aufgabe erstellen: {subject}", - "taskUpdateWithStatus": "Aufgabe aktualisieren #{id} -> {status}", - "taskUpdate": "Aufgabe aktualisieren #{id}", - "webFetchWithUrl": "WebFetch ({url})", - "webSearchWithQuery": "Websuche: {query}", - "todosProgress": "Aufgaben ({done}/{total})", - "skillWithName": "Skill: {name}", - "genericWithContext": "{tool} ({context})" - }, - "search": { - "noMatches": "Keine Treffer", - "matchSummary": "{matches, plural, one {# Treffer} other {# Treffer}} in {files, plural, one {# Datei} other {# Dateien}}", - "fileSummary": "{files, plural, one {# Datei} other {# Dateien}}", - "moreResults": "{count, plural, one {# weiteres Ergebnis nicht angezeigt} other {# weitere Ergebnisse nicht angezeigt}}" - }, - "toolGroup": { - "search": "{count, plural, one {# Suche durchgeführt} other {# Suchen durchgeführt}}", - "command": "{count, plural, one {# Befehl ausgeführt} other {# Befehle ausgeführt}}", - "read": "{count, plural, one {Dateien # Mal gelesen} other {Dateien # Mal gelesen}}", - "memory": "{count, plural, one {# Erinnerung abgerufen} other {# Erinnerungen abgerufen}}", - "edit": "{count, plural, one {Dateien # Mal bearbeitet} other {Dateien # Mal bearbeitet}}", - "fetch": "{count, plural, one {# Ressource abgerufen} other {# Ressourcen abgerufen}}", - "think": "{count, plural, one {# Mal nachgedacht} other {# Mal nachgedacht}}", - "todo": "{count, plural, one {# Aufgabe aktualisiert} other {# Aufgaben aktualisiert}}", - "task": "{count, plural, one {# Aufgabe ausgeführt} other {# Aufgaben ausgeführt}}", - "other": "{count, plural, one {# Werkzeug verwendet} other {# Werkzeuge verwendet}}", - "errorSuffix": "{count, plural, one {# fehlgeschlagen} other {# fehlgeschlagen}}", - "joiner": " · " - }, - "planMode": { - "entered": "Planungsmodus gestartet", - "planLabel": "Plan", - "reviewApproved": "Plan genehmigt – wird umgesetzt", - "reviewKept": "Im Planmodus geblieben", - "reviewPending": "Warte auf Planentscheidung", - "submitted": "Plan eingereicht", - "switched": "Modus gewechselt" - }, - "backgroundTask": { - "title": "Hintergrundaufgabe", - "titleWithId": "Hintergrundaufgabe · {id}", - "running": "Läuft", - "completed": "Abgeschlossen", - "failed": "Fehlgeschlagen", - "stopped": "Gestoppt", - "exitCode": "Exit {code}", - "polledTimes": "{count}-mal abgefragt", - "runningInBackground": "Hintergrund", - "launchNote": "Läuft im Hintergrund · {id}" - }, - "codexScript": { - "outputMissing": "Codex hat die Skriptausgabe gekürzt und dabei das Trennzeichen dieses Befehls entfernt, sodass ihm keine Ausgabe zugeordnet werden konnte.", - "sharedWith": "Enthält auch die Ausgabe von {commands} – codex hat deren Trennzeichen abgeschnitten.", - "truncated": "gekürzt" - } - }, - "messageNav": { - "title": "Nachrichtennavigation", - "collapse": "Nachrichtennavigation ausblenden", - "collapsedSummary": "Nachrichten {count}", - "fileCount": "{count, plural, one {# Datei} other {# Dateien}}", - "remove": "Entfernen", - "noDiffDataAvailable": "Keine Diff-Daten verfügbar für {filePath}" - }, - "replyArtifacts": { - "title": "Geänderte Dateien", - "fileCount": "{count, plural, one {# Datei} other {# Dateien}}", - "newFilesTitle": "Neue Dateien", - "revealInFolder": "Im Dateimanager anzeigen", - "openFile": "{filePath} öffnen", - "openInEditor": "Im Editor öffnen", - "remove": "Entfernen", - "noDiffDataAvailable": "Keine Diff-Daten verfügbar für {filePath}" - }, - "askQuestion": { - "title": "Der Agent benötigt deine Auswahl", - "subtitle": "Antworten und absenden. Du kannst jederzeit überspringen.", - "recommended": "Empfohlen", - "other": "Andere", - "otherPlaceholder": "Antwort eingeben…", - "singleSelect": "Einfach", - "multiSelect": "Mehrfach", - "skip": "Überspringen", - "next": "Weiter", - "submit": "Senden", - "submitError": "Senden fehlgeschlagen. Bitte versuche es erneut." - }, - "planApproval": { - "title": "Der Agent hat einen Plan – bitte prüfen", - "emptyPlan": "Der Agent hat keinen Plan geschrieben. Genehmige, um zu starten, oder fordere Änderungen an.", - "approve": "Genehmigen & starten", - "requestChanges": "Änderungen anfordern", - "abandon": "Verwerfen", - "feedbackPlaceholder": "Was soll geändert werden?", - "sendChanges": "Senden", - "cancel": "Abbrechen", - "submitError": "Senden fehlgeschlagen. Bitte erneut versuchen." - }, - "feedbackCheckResult": { - "count": "{count, plural, =1 {1 Rückmeldung} other {# Rückmeldungen}}", - "expand": "Alle Rückmeldungen anzeigen", - "collapse": "Einklappen", - "errorTitle": "Feedback-Prüfung fehlgeschlagen" - }, - "askQuestionResult": { - "title": "Frage", - "answeredLabel": "Frage & Antwort:", - "awaiting": "Warten auf deine Antwort…", - "declined": "Du hast dies verworfen – der Agent hat nach eigenem Ermessen entschieden.", - "noSelection": "Keine Auswahl" - }, - "configStale": { - "agentConfigTitle": "Agent-Einstellungen aktualisiert", - "modelProviderTitle": "Modellanbieter aktualisiert", - "description": "Diese Sitzung verwendet weiterhin die bisherige Konfiguration. Zum Anwenden neu verbinden (der Gesprächsverlauf bleibt erhalten).", - "reconnect": "Zum Anwenden neu verbinden", - "reconnecting": "Wird neu verbunden…", - "reconnectDisabledDuringTurn": "Verfügbar, sobald die aktuelle Runde abgeschlossen ist", - "dismiss": "Schließen", - "reconnectFailed": "Sitzung konnte nicht neu verbunden werden", - "applied": "Neue Konfiguration angewendet" - }, - "piProjectTrust": { - "title": "Dieses Projekt enthält pi-Ressourcen", - "description": "pi lädt die .pi-Dateien des Repositorys nicht. Prüfe sie, um zu entscheiden.", - "descriptionExecutable": "Das Repository enthält pi-Erweiterungen, die beim Start Code ausführen. pi lädt sie nicht. Prüfe sie, bevor du entscheidest.", - "review": "Prüfen…", - "dismiss": "Ausblenden", - "dialogTitle": "Den pi-Ressourcen dieses Projekts vertrauen?", - "dialogDescription": "pi lädt die .pi-Dateien eines Repositorys nur, wenn du dem Ordner vertraust. Vertraue nur, wenn du dem Inhalt dieses Repositorys vertraust.", - "executionWarning": "Erweiterungen sind Code. Wenn du diesem Ordner vertraust, führt das Repository sie beim Start von pi mit deinen Rechten aus – noch bevor du eine Nachricht sendest.", - "scopeNote": "Die Entscheidung wird in der trust.json von pi für diesen Ordner gespeichert, gilt für alle darin enthaltenen Ordner und wird auch verwendet, wenn du pi selbst im Terminal startest. Du kannst sie später unter Einstellungen → Agenten → Pi ändern.", - "trust": "Projekt vertrauen", - "decline": "Nicht laden", - "disabledDuringTurn": "Verfügbar, sobald der aktuelle Zug beendet ist", - "trustedToast": "Projekt vertraut – neu verbunden, damit pi seine Ressourcen lädt", - "declinedToast": "Projektressourcen bleiben ungeladen", - "saveFailed": "Die Vertrauensentscheidung für das Projekt konnte nicht gespeichert werden", - "grantTitle": "Diesem Projekt wird bereits vertraut", - "grantDescription": "pi lädt die .pi-Dateien dieses Repositorys. Sieh dir an, was das erlaubt.", - "grantInheritedDescription": "Einem übergeordneten Ordner wird vertraut, daher lädt pi die .pi-Dateien dieses Repositorys. Sieh dir an, was das erlaubt.", - "grantDialogTitle": "Den pi-Ressourcen dieses Projekts wird vertraut", - "grantDialogDescription": "pi darf die .pi-Dateien dieses Repositorys laden. Frühere codeg-Versionen haben das beim Öffnen eines Ordners automatisch erteilt, du wurdest also womöglich nie gefragt.", - "grantExecutionWarning": "Erweiterungen sind Code. Das Repository führt sie beim Start von pi mit deinen Rechten aus, bevor du eine Nachricht sendest.", - "inheritedFrom": "Vertraut über", - "revoke": "Vertrauen widerrufen", - "keepTrusted": "Vertrauen behalten", - "revokedToast": "Vertrauen widerrufen – neu verbunden, damit pi die Projektressourcen nicht mehr lädt", - "trustedNoReconnect": "Projekt vertraut – gilt ab dem nächsten Start von pi", - "revokedNoReconnect": "Vertrauen widerrufen – gilt ab dem nächsten Start von pi" - }, - "collabAgent": { - "title": "Subagent", - "errorTitle": "Subagent-Aufgabe fehlgeschlagen", - "statesLabel": "Subagenten", - "statusRunning": "Läuft", - "statusCompleted": "Abgeschlossen", - "statusFailed": "Fehlgeschlagen", - "statusPending": "Wird gestartet", - "statusInterrupted": "Unterbrochen", - "statusClosed": "Geschlossen", - "statusNotFound": "Nicht gefunden", - "opSpawn": "Sub-Agent wird gestartet", - "opWait": "Sub-Agent-Ergebnis wird abgerufen", - "opClose": "Sub-Agent wird geschlossen", - "opResume": "Sub-Agent wird fortgesetzt" - }, - "contextCompaction": { - "compacting": "Kontext wird komprimiert…", - "compacted": "Kontext komprimiert", - "compactedTokens": "Kontext komprimiert · {before} → {after} Tokens", - "failed": "Kontextkomprimierung fehlgeschlagen" - }, - "sessionFailure": { - "category": { - "connection": "Verbindungsproblem", - "access": "Zugriffsproblem", - "limit": "Limit erreicht", - "request": "Anfrage abgelehnt", - "service": "Dienstproblem", - "unknown": "Sitzungsproblem" - }, - "action": { - "retry": "Erneut versuchen", - "login": "Anmelden", - "newSession": "Neue Sitzung" - }, - "recovered": "Wiederhergestellt", - "retryUnavailable": "Keine vorherige Nachricht zum erneuten Senden.", - "toggleDetails": "Details umschalten" - }, - "backgroundTasks": { - "running": "{count, plural, one {# Hintergrundaufgabe läuft} other {# Hintergrundaufgaben laufen}}", - "settling": "Hintergrundergebnisse werden synchronisiert…", - "settledFallback": "Hintergrundaufgabe beendet ({status})", - "cardRunning": "Läuft im Hintergrund", - "cardLaunchedPending": "Hintergrundaufgabe gestartet", - "cardCompleted": "Hintergrundaufgabe abgeschlossen", - "cardFinishedWithStatus": "Hintergrundaufgabe beendet ({status})", - "cardResultPending": "Ergebnis steht noch aus" - }, - "proposedPlan": { - "title": "Vorgeschlagener Plan", - "planning": "Wird geplant…" - } - }, - "diffPreview": { - "mode": { - "added": "Hinzugefügt", - "deleted": "Gelöscht", - "renamed": "Umbenannt", - "modified": "Geändert" - }, - "hunkLabel": "Block {index}", - "loadingHunk": "Hunk wird geladen...", - "noDiffData": "Keine Diff-Daten", - "showRemainingLines": "{count} weitere Zeilen anzeigen" - }, - "conversationContextBar": { - "folderTitle": "Arbeitsordner", - "branchTitle": "Arbeits-Branch", - "searchFolder": "Search folder...", - "searchBranch": "Search branch...", - "noFolders": "No folders", - "noBranches": "No branches", - "noBranch": "(no branch)", - "chatModeLabel": "Chat-Modus", - "commit": "Commit", - "push": "Push", - "merge": "Merge", - "toasts": { - "folderChanged": "Switched to {name}", - "openFolderFailed": "Failed to open folder", - "switchedToChatMode": "In den Chat-Modus gewechselt", - "openStashFailed": "Failed to open stash window", - "openMergeFailed": "Failed to open merge window" - } - }, - "cloneDialog": { - "title": "Repository klonen", - "repositoryUrl": "Repository-URL", - "repositoryUrlPlaceholder": "https://github.com/user/repo.git", - "directory": "Verzeichnis", - "directoryPlaceholder": "Zielverzeichnis auswählen...", - "browseDirectory": "Verzeichnis durchsuchen", - "cancel": "Abbrechen", - "clone": "Klonen", - "clonePath": "Klonpfad: {path}" - }, - "toasts": { - "cloneFailed": "Repository konnte nicht geklont werden" - } - }, - "ProjectBoot": { - "title": "Projekt-Starter", - "tabs": { - "shadcn": "shadcn", - "hyperframes": "HyperFrames" - }, - "hyperframes": { - "title": "HyperFrames-Videoprojekt", - "subtitle": "Erstelle ein HTML-zu-Video-Projekt. Der Agent im Arbeitsbereich kann es dann schreiben und rendern.", - "resolution": "Auflösung", - "skillsTitle": "Agenten-Skills", - "skillsDesc": "Installiert die HyperFrames-Skills global (Symlink) für die ausgewählten Agenten, damit sie Videos erstellen und rendern können.", - "recheck": "Erneut prüfen", - "installedBadge": "Installiert", - "skillsInstall": "Skills installieren / aktualisieren", - "skillsInstalling": "Skills werden installiert…", - "skillsInstalled": "HyperFrames-Skills installiert", - "skillsInstallFailed": "HyperFrames-Skills konnten nicht installiert werden" - }, - "config": { - "base": "Basis", - "style": "Stil", - "baseColor": "Basisfarbe", - "theme": "Thema", - "chartColor": "Diagrammfarbe", - "iconLibrary": "Icon-Bibliothek", - "font": "Schriftart", - "fontHeading": "Überschrift-Schriftart", - "menuAccent": "Menü-Akzent", - "menuColor": "Menü-Farbe", - "radius": "Radius", - "template": "Vorlage", - "createProject": "Projekt erstellen", - "sectionStyle": "Stil", - "sectionColors": "Farben", - "sectionTypography": "Typografie", - "sectionInterface": "Oberfläche" - }, - "preview": { - "loading": "Vorschau wird geladen..." - }, - "createDialog": { - "title": "Projekt erstellen", - "projectName": "Projektname", - "projectNamePlaceholder": "my-app", - "frameworkTemplate": "Framework-Vorlage", - "packageManager": "Paketmanager", - "saveDirectory": "Speicherverzeichnis", - "saveDirectoryPlaceholder": "Verzeichnis auswählen...", - "browseDirectory": "Durchsuchen", - "projectPath": "Projekt wird erstellt in: {path}", - "advancedOptions": "Erweiterte Optionen", - "base": "Basisbibliothek", - "enableRtl": "RTL-Unterstützung aktivieren", - "enableRtlDescription": "Layout-Unterstützung für Rechts-nach-links-Sprachen (z.B. Arabisch, Hebräisch) aktivieren", - "pmChecking": "Wird überprüft...", - "pmNotInstalled": "Nicht installiert", - "cancel": "Abbrechen", - "create": "Erstellen", - "creating": "Projekt wird erstellt..." - }, - "toasts": { - "createFailed": "Projekt konnte nicht erstellt werden", - "createSuccess": "Projekt erfolgreich erstellt", - "openWorkspaceFailed": "Projekt erstellt, konnte aber nicht im Arbeitsbereich geöffnet werden" - }, - "errors": { - "directoryExists": "Zielverzeichnis existiert bereits", - "commandFailed": "Projekterstellungsbefehl fehlgeschlagen." - } - }, - "WebServiceSettings": { - "addressSwitchHint": "Das Umschalten ändert nur die hier angezeigte und geöffnete Adresse – der Dienst lauscht auf allen Schnittstellen und bleibt unter jeder Adresse erreichbar.", - "sectionTitle": "Webdienst", - "sectionDescription": "Aktivieren Sie den Fernzugriff auf Codeg über den Browser", - "port": "Port", - "status": "Status", - "autoStart": "Automatisch starten", - "autoStartHint": "Webdienst beim Start von Codeg starten", - "running": "Läuft", - "stopped": "Gestoppt", - "processing": "Verarbeitung...", - "start": "Starten", - "stop": "Stoppen", - "startFailed": "Start fehlgeschlagen", - "stopFailed": "Stopp fehlgeschlagen", - "saveConfigFailed": "Webdienst-Einstellungen konnten nicht gespeichert werden", - "open": "Öffnen", - "hide": "Ausblenden", - "show": "Einblenden", - "copy": "Kopieren", - "qrcode": "QR-Code", - "qrcodeTitle": "Zum Öffnen scannen", - "qrcodeHint": "Scanne mit deinem Handy, um Codeg im Browser zu öffnen", - "addressLabel": "Zugriffsadresse", - "tokenLabel": "Zugriffstoken", - "tokenHint": "Geben Sie dieses Token beim ersten Zugriff auf den Web-Client ein", - "tokenPlaceholder": "Leer lassen für automatische Generierung", - "regenerate": "Neu generieren", - "stalePortOccupiedTitle": "Port {port} wird von einem anderen Prozess belegt", - "stalePortUnknownTitle": "Status von Port {port} unklar", - "stalePortHint": "Codeg kann sich nicht binden, bis der Port freigegeben ist. Ändere den Port oben oder beende den Prozess, der ihn hält.", - "errors": { - "alreadyRunning": "Der Web-Dienst läuft bereits", - "invalidAddress": "Host- oder Portformat ungültig", - "portInUse": "Port {port} wird bereits verwendet. Beenden Sie den Prozess oder wählen Sie einen anderen Port.", - "permissionDenied": "Zugriff verweigert. Verwenden Sie einen Port über 1024 oder starten Sie mit höheren Rechten.", - "addressUnavailable": "Die Adresse ist auf diesem Computer nicht verfügbar", - "bindFailed": "Adresse konnte nicht gebunden werden" - } - }, - "DirectoryBrowser": { - "title": "Verzeichnis durchsuchen", - "pathPlaceholder": "Verzeichnispfad eingeben...", - "goHome": "Zum Heimverzeichnis", - "navigateUp": "Zum übergeordneten Verzeichnis", - "select": "Auswählen", - "cancel": "Abbrechen", - "loading": "Wird geladen...", - "emptyDirectory": "Dieses Verzeichnis ist leer", - "errorLoadingDir": "Verzeichnis konnte nicht geladen werden", - "permissionDenied": "Zugriff verweigert" - }, - "ChatChannelSettings": { - "loading": "Wird geladen...", - "sectionTitle": "Chat-Kanäle", - "sectionDescription": "Konfigurieren Sie IM-Bots, um Ereignisbenachrichtigungen zu empfangen und Codieraktivitäten abzufragen.", - "addChannel": "Kanal hinzufügen", - "noChannels": "Noch keine Chat-Kanäle konfiguriert.", - "channelName": "Name", - "channelNamePlaceholder": "Mein Telegram Bot", - "channelType": "Kanaltyp", - "lark": "Lark (Feishu)", - "weixin": "WeChat", - "dailyReport": "Tagesbericht", - "dailyReportTime": "Berichtszeit", - "nameRequired": "Kanalname ist erforderlich.", - "tokenRequired": "Token ist erforderlich.", - "chatIdRequired": "Chat-ID ist erforderlich.", - "topicMode": "Themengruppenmodus", - "topicModeHint": "Leitet Telegram-Forum-Themen als separate Codeg-Sitzungen weiter. Der Bot muss in einer Forum-Supergruppe sein und Themen verwalten dürfen.", - "loadFailed": "Kanäle konnten nicht geladen werden.", - "saveFailed": "Änderungen konnten nicht gespeichert werden.", - "connectSuccess": "Kanal verbunden.", - "connectFailed": "Verbindung fehlgeschlagen", - "disconnectSuccess": "Kanal getrennt.", - "disconnectFailed": "Trennung fehlgeschlagen.", - "testSuccess": "Verbindungstest bestanden.", - "testFailed": "Verbindungstest fehlgeschlagen", - "deleteSuccess": "Kanal gelöscht.", - "deleteFailed": "Kanal konnte nicht gelöscht werden.", - "deleteConfirmTitle": "Kanal löschen", - "deleteConfirmMessage": "Der Kanal und seine Nachrichtenprotokolle werden dauerhaft gelöscht. Sind Sie sicher?", - "cancel": "Abbrechen", - "delete": "Löschen", - "create": "Erstellen", - "save": "Speichern", - "channelListTitle": "Konfigurierte Kanäle", - "channelListDescription": "Aktivierte Kanäle werden beim Dienststart automatisch verbunden.", - "editChannel": "Kanal bearbeiten", - "editSuccess": "Kanal aktualisiert.", - "tokenPlaceholderKeep": "Leer lassen, um aktuellen Wert beizubehalten", - "weixinScanTitle": "QR-Code scannen", - "weixinScanDescription": "Öffnen Sie WeChat und scannen Sie den QR-Code, um eine Verbindung herzustellen.", - "weixinQrcodeExpired": "QR-Code abgelaufen.", - "weixinRefreshQrcode": "Aktualisieren", - "weixinWaitingScan": "Warten auf Scan...", - "weixinPollError": "Verbindung instabil, erneuter Versuch...", - "weixinReconnectNotice": "Aufgrund von Einschränkungen des iLink-Protokolls müssen Sie nach jeder erneuten Verbindung dem Bot eine Nachricht senden, damit Ereignisauslöser wirksam werden.", - "connect": "Verbinden", - "disconnect": "Trennen", - "test": "Verbindung testen", - "tabs": { - "channels": "Kanäle", - "commands": "Befehle", - "events": "Ereignisse", - "other": "Sonstiges" - }, - "commands": { - "title": "Integrierte Befehle", - "description": "Im Chat-Kanal verfügbare Bot-Befehle. In Gruppenchats ist @Bot erforderlich, um Nachrichten zu verarbeiten.", - "prefixLabel": "Befehlspräfix", - "prefixDescription": "1-3 nicht-alphanumerische Zeichen zum Auslösen von Bot-Befehlen (Standard /).", - "prefixSaved": "Befehlspräfix gespeichert.", - "prefixSaveFailed": "Fehler beim Speichern des Präfixes.", - "prefixInvalid": "Das Präfix muss 1-3 nicht-alphanumerische Zeichen sein.", - "save": "Speichern", - "folderDesc": "Arbeitsordner auswählen", - "agentDesc": "KI-Agent auswählen", - "taskDesc": "Sitzung erstellen und Aufgabe ausführen", - "sessionsDesc": "Aktive Sitzungen im Ordner anzeigen", - "resumeDesc": "Neueste Konversationen / Sitzung fortsetzen", - "cancelDesc": "Aktuelle Aufgabe abbrechen", - "approveDesc": "Berechtigungsanfrage des Agenten genehmigen", - "denyDesc": "Berechtigungsanfrage des Agenten ablehnen", - "searchDesc": "Konversationen nach Stichwort suchen", - "todayDesc": "Heutige Aktivitätsübersicht", - "statusDesc": "Kanal-Verbindungsstatus", - "helpDesc": "Hilfe anzeigen" - }, - "events": { - "title": "Ereignisbenachrichtigungen", - "description": "Nach Aktivierung werden ausgelöste Ereignisse an den Kanal gesendet.", - "turnComplete": "Runde abgeschlossen", - "turnCompleteDesc": "Wenn eine Agentenrunde endet", - "error": "Agentenfehler", - "errorDesc": "Wenn ein Agent einen Fehler feststellt", - "permissionRequest": "Berechtigungsanfrage", - "permissionRequestDesc": "Wenn ein Agent eine Berechtigung anfordert", - "questionRequest": "Frage des Agenten", - "questionRequestDesc": "Wenn ein Agent dir eine Frage stellt", - "userPromptSent": "Benutzernachricht", - "userPromptSentDesc": "Wenn du eine Nachricht sendest – der Nachrichtentext ist in der Benachrichtigung enthalten", - "saved": "Ereignisfilter aktualisiert.", - "saveFailed": "Fehler beim Speichern des Ereignisfilters.", - "loadFailed": "Einstellungen konnten nicht geladen werden.", - "retry": "Erneut versuchen", - "webhooksTitle": "Webhooks", - "webhooksDescription": "Sendet bei einem aktivierten Ereignis eine JSON-Nutzlast per POST an eine oder mehrere URLs. Der Ereignisfilter oben gilt auch für Webhooks.", - "webhookUrlPlaceholder": "https://example.com/webhook", - "addWebhook": "Webhook hinzufügen", - "removeWebhook": "Webhook entfernen", - "webhookSave": "Speichern", - "webhooksSaved": "Webhooks gespeichert.", - "webhooksSaveFailed": "Fehler beim Speichern der Webhooks.", - "webhookInvalidUrl": "Gültige http(s)-URLs eingeben.", - "docsTitle": "Anfrageformat", - "docsMethod": "Methode", - "docsContentType": "Content-Type", - "docsNote": "Jedes aktivierte Ereignis wird an alle URLs gesendet. Webhooks werden nicht entprellt; der Ereignisfilter oben gilt weiterhin.", - "editWebhook": "Webhook bearbeiten", - "enableWebhook": "Webhook aktivieren", - "webhookDuplicate": "Diese URL ist bereits konfiguriert.", - "cancel": "Abbrechen", - "webhooksEmpty": "Noch keine Webhooks konfiguriert.", - "deleteWebhookTitle": "Webhook löschen", - "deleteWebhookMessage": "Diesen Webhook entfernen? Ereignisse werden nicht mehr an diese URL gesendet.", - "delete": "Löschen" - }, - "language": { - "title": "Nachrichtensprache", - "description": "Sprache für Ereignisbenachrichtigungen, Befehlsantworten und tägliche Berichte, die an Chat-Kanäle gesendet werden.", - "saved": "Nachrichtensprache gespeichert.", - "saveFailed": "Fehler beim Speichern der Nachrichtensprache.", - "en": "Englisch", - "zh-cn": "Vereinfachtes Chinesisch", - "zh-tw": "Traditionelles Chinesisch", - "ja": "Japanisch", - "ko": "Koreanisch", - "es": "Spanisch", - "de": "Deutsch", - "fr": "Französisch", - "pt": "Portugiesisch", - "ar": "Arabisch" - } - }, - "ModelProviderSettings": { - "sectionTitle": "Modellanbieter", - "sectionDescription": "API-Anbieter-Zugangsdaten für Agenten verwalten.", - "filterAll": "Alle", - "providerListTitle": "Konfigurierte Anbieter", - "addProvider": "Anbieter hinzufügen", - "editProvider": "Anbieter bearbeiten", - "noProviders": "Noch keine Modellanbieter konfiguriert.", - "providerName": "Name", - "providerNamePlaceholder": "z.B. OpenAI, Anthropic", - "apiUrl": "API-URL", - "apiUrlPlaceholder": "https://api.openai.com/v1", - "apiKey": "API-Schlüssel", - "apiKeyPlaceholder": "sk-...", - "apiKeyKeepCurrent": "Leer lassen, um aktuellen Wert beizubehalten", - "agentTypes": "Agententypen", - "agentTypesRequired": "Mindestens ein Agententyp ist erforderlich.", - "agentType": "Agententyp", - "agentTypeRequired": "Agententyp ist erforderlich.", - "agentTypeImmutableHint": "Der Agententyp kann nach der Erstellung nicht mehr geändert werden.", - "model": "Modell", - "modelPlaceholderCodex": "gpt-5.6-sol / gpt-5.5", - "modelPlaceholderGemini": "gemini-3-pro-preview", - "claudeMainModel": "Hauptmodell", - "claudeReasoningModel": "Reasoning-Modell (Thinking)", - "claudeHaikuDefaultModel": "Standard Haiku-Modell", - "claudeSonnetDefaultModel": "Standard Sonnet-Modell", - "claudeOpusDefaultModel": "Standard Opus-Modell", - "claudeCustomModelOption": "Benutzerdefinierte Modell-ID", - "claudeCustomModelOptionName": "Name des benutzerdefinierten Modells", - "claudeCustomModelOptionDescription": "Beschreibung des benutzerdefinierten Modells", - "claudeCustomModelOptionHint": "Fügt der Modellauswahl von Claude einen einzelnen benutzerdefinierten Eintrag hinzu (z. B. ein Modell hinter einem benutzerdefinierten Gateway/Proxy). Name und Beschreibung sind optionale Anzeigeangaben.", - "nameRequired": "Anbietername ist erforderlich.", - "apiUrlRequired": "API-URL ist erforderlich.", - "apiKeyRequired": "API-Schlüssel ist erforderlich.", - "loadFailed": "Anbieter konnten nicht geladen werden.", - "saveFailed": "Änderungen konnten nicht gespeichert werden.", - "createSuccess": "Anbieter erstellt.", - "editSuccess": "Anbieter aktualisiert.", - "deleteSuccess": "Anbieter gelöscht.", - "deleteConfirmTitle": "Anbieter löschen", - "deleteConfirmMessage": "Der Anbieter \"{name}\" wird dauerhaft gelöscht. Sind Sie sicher?", - "deleteBlockedByAgent": "{agents} verwendet diesen Anbieter. Bitte trennen Sie die Verbindung vor dem Löschen.", - "cancel": "Abbrechen", - "delete": "Löschen", - "create": "Erstellen", - "save": "Speichern", - "affectedRunningSessions": "{count, plural, one {# laufende Sitzung muss zum Anwenden neu verbunden werden} other {# laufende Sitzungen müssen zum Anwenden neu verbunden werden}}" - }, - "SkillMatrix": { - "loading": "Wird geladen…", - "searchPlaceholder": "Nach Name, ID oder Beschreibung suchen", - "empty": "Nichts anzuzeigen.", - "emptySearch": "Keine Treffer für die aktuelle Suche.", - "skillColumn": "Skill", - "selectAll": "Alle sichtbaren auswählen", - "selectSkill": "{name} auswählen", - "everything": { - "label": "Sammelaktion", - "enable": "Alle aktivieren (sichtbar)", - "disable": "Alle deaktivieren (sichtbar)" - }, - "columnMenu": { - "enableAll": "Alle Skills aktivieren", - "disableAll": "Alle Skills deaktivieren" - }, - "rowMenu": { - "label": "Sammelaktionen für {name}", - "enableAll": "Für alle Agenten aktivieren", - "disableAll": "Für alle Agenten deaktivieren" - }, - "bulk": { - "selected": "{count} ausgewählt", - "targetAll": "Alle Agenten", - "targetSome": "{count} Agenten", - "enable": "Aktivieren", - "disable": "Deaktivieren", - "clear": "Leeren" - }, - "confirm": { - "disableTitle": "Diese Verknüpfungen deaktivieren?", - "disableBody": "Dadurch werden {count} von codeg verwaltete Skill-Verknüpfungen entfernt. Skills, die ein eigenes Verzeichnis belegen, bleiben unberührt. Du kannst sie jederzeit wieder aktivieren.", - "cancel": "Abbrechen", - "confirm": "Deaktivieren" - }, - "toasts": { - "loadFailed": "Skill-Status konnte nicht geladen werden", - "applyFailed": "Änderungen konnten nicht angewendet werden", - "enabled": "{count} Verknüpfungen aktiviert", - "disabled": "{count} Verknüpfungen deaktiviert", - "enabledPartial": "{ok} aktiviert, {failed} fehlgeschlagen", - "disabledPartial": "{ok} deaktiviert, {failed} fehlgeschlagen" - }, - "detail": { - "enableForAgents": "Für Agenten aktivieren", - "preview": "SKILL.md-Vorschau", - "loadingContent": "Inhalt wird geladen…" - }, - "copyModeHint": "Kopiert (nicht verknüpft) – nach Updates erneut aktivieren, um die neueste Version zu erhalten" - }, - "ExpertsSettings": { - "title": "Experten-Skills", - "description": "Aktivieren Sie kuratierte, praxiserprobte Skill-Workflows für Ihre KI-Coding-Agents. Jeder Experte ist ein eigenständiger Skill aus dem superpowers-Projekt — codeg verwaltet die zentrale Kopie und verknüpft sie mit den von Ihnen ausgewählten Agents.", - "loading": "Experten werden geladen…", - "loadingContent": "Inhalt wird geladen…", - "emptyExperts": "Keine Experten verfügbar. Prüfen Sie die Anwendungsprotokolle.", - "emptySelection": "Wählen Sie einen Experten aus, um seinen Inhalt anzuzeigen und die Aktivierung zu verwalten.", - "emptySearch": "Keine Experten entsprechen der aktuellen Suche.", - "searchPlaceholder": "Experten nach Name, ID oder Beschreibung suchen", - "enableForAgents": "Für Agents aktivieren", - "noAgents": "Keine ACP-Agents erkannt.", - "copyModeWarning": "Kopiert (nicht verknüpft). Nach codeg-Updates erneut aktivieren, um die neueste Version zu erhalten.", - "previewTitle": "SKILL.md-Vorschau", - "categories": { - "discovery": "Entdeckung & Design", - "planning": "Planung", - "execution": "Ausführung", - "quality": "Qualität & Tests", - "debugging": "Debugging", - "review": "Review & Integration", - "meta": "Meta" - }, - "states": { - "not_linked": "Nicht aktiviert", - "linked_to_codeg": "Aktiviert", - "linked_elsewhere": "Blockiert — ein anderer Link existiert", - "blocked_by_real_directory": "Blockiert — ein benutzerdefinierter Skill belegt diesen Namen", - "broken": "Defekter Link" - }, - "badges": { - "userModified": "Vom Benutzer geändert" - }, - "actions": { - "openCentralDir": "Zentralen Ordner öffnen", - "refresh": "Aktualisieren" - }, - "toasts": { - "loadFailed": "Laden der Expertendetails fehlgeschlagen", - "enabled": "Experte für diesen Agent aktiviert", - "disabled": "Experte für diesen Agent deaktiviert", - "enableFailed": "Aktivieren des Experten fehlgeschlagen", - "disableFailed": "Deaktivieren des Experten fehlgeschlagen", - "openFolderFailed": "Ordner konnte nicht geöffnet werden" - } - }, - "ScienceSettings": { - "title": "Wissenschaftliche Skills", - "description": "Aktiviere kuratierte wissenschaftliche Skills für deine KI-Coding-Agents — Hypothesengenerierung, Versuchsplanung, Statistik, Visualisierung, kritische Bewertung und Literatursuche. codeg verwaltet eine zentrale Kopie und verlinkt jeden Skill in die von dir gewählten Agents.", - "loading": "Wissenschaftliche Skills werden geladen…", - "emptySkills": "Keine wissenschaftlichen Skills verfügbar. Prüfe die Anwendungsprotokolle.", - "searchPlaceholder": "Wissenschaftliche Skills nach Name, ID oder Beschreibung suchen", - "categories": { - "ideation": "Ideenfindung", - "design": "Studiendesign", - "analysis": "Analyse", - "visualization": "Visualisierung", - "evaluation": "Bewertung", - "literature": "Literatur" - }, - "states": { - "not_linked": "Nicht aktiviert", - "linked_to_codeg": "Aktiviert", - "linked_elsewhere": "Blockiert — ein anderer Link existiert", - "blocked_by_real_directory": "Blockiert — ein benutzerdefinierter Skill belegt diesen Namen", - "broken": "Defekter Link" - }, - "badges": { - "userModified": "Vom Benutzer geändert", - "needsKey": "API-Schlüssel nötig", - "needsSetup": "Ggf. Einrichtung nötig" - }, - "actions": { - "openCentralDir": "Zentralen Ordner öffnen", - "refresh": "Aktualisieren" - }, - "toasts": { - "openFolderFailed": "Ordner konnte nicht geöffnet werden" - } - }, - "OfficeToolsSettings": { - "title": "Office-Tools", - "description": "Verwalten Sie OfficeCLI-Skills zum Erstellen von Excel-, Word- und PowerPoint-Dateien. Installieren Sie OfficeCLI, synchronisieren Sie Skills und aktivieren Sie sie pro Agent.", - "loadingContent": "Inhalt wird geladen…", - "emptySkills": "Keine Skills verfügbar. Installieren Sie OfficeCLI und synchronisieren Sie die Skills.", - "emptySelection": "Wählen Sie einen Skill aus, um den Inhalt anzuzeigen und die Aktivierung zu verwalten.", - "emptySearch": "Keine übereinstimmenden Skills gefunden.", - "searchPlaceholder": "Skills nach Name, ID oder Beschreibung suchen", - "enableForAgents": "Für Agenten aktivieren", - "noAgents": "Keine ACP-Agenten erkannt.", - "installFirst": "Installieren Sie zuerst OfficeCLI, um Skills zu aktivieren.", - "syncFirst": "Synchronisieren Sie zuerst die Skills, um den Inhalt zu laden.", - "noContent": "Kein Inhalt verfügbar.", - "copyModeWarning": "Kopiert (nicht verknüpft). Erneut synchronisieren, um die neueste Version zu erhalten.", - "previewTitle": "SKILL.md-Vorschau", - "detection": { - "installed": "Installiert", - "notInstalled": "Nicht installiert", - "notRunnable": "Installiert, aber nicht lauffähig", - "installHint": "Installieren Sie OfficeCLI, um Office-Dokumentenerstellungs-Skills für Ihre KI-Agenten zu aktivieren.", - "install": "Installieren", - "uninstall": "Deinstallieren", - "syncSkills": "Skills synchronisieren" - }, - "categories": { - "general": "Allgemein", - "presentations": "Präsentationen", - "documents": "Dokumente", - "spreadsheets": "Tabellenkalkulationen" - }, - "states": { - "not_linked": "Nicht aktiviert", - "linked_to_codeg": "Aktiviert", - "linked_elsewhere": "Blockiert — ein anderer Link existiert", - "blocked_by_real_directory": "Blockiert — ein benutzerdefinierter Skill belegt diesen Namen", - "broken": "Defekter Link" - }, - "badges": { - "notSynced": "Nicht synchronisiert" - }, - "actions": { - "refresh": "Aktualisieren" - }, - "toasts": { - "loadFailed": "Skill-Details konnten nicht geladen werden", - "enabled": "Skill für diesen Agenten aktiviert", - "disabled": "Skill für diesen Agenten deaktiviert", - "enableFailed": "Skill konnte nicht aktiviert werden", - "disableFailed": "Skill konnte nicht deaktiviert werden", - "installSuccess": "OfficeCLI erfolgreich installiert", - "installFailed": "OfficeCLI konnte nicht installiert werden", - "uninstallSuccess": "OfficeCLI deinstalliert", - "uninstallFailed": "OfficeCLI konnte nicht deinstalliert werden", - "syncSuccess": "{synced} Skills erfolgreich synchronisiert", - "syncPartial": "{synced} synchronisiert, {errors} fehlgeschlagen", - "syncFailed": "Skills konnten nicht synchronisiert werden" - }, - "autoPreviewLabel": "Vorschau automatisch öffnen", - "autoPreviewHint": "Wenn ein Agent eine Word-, Excel- oder PowerPoint-Datei erstellt oder bearbeitet, wird die Live-Vorschau automatisch geöffnet." - }, - "SkillPacksSettings": { - "title": "Skill-Pakete", - "description": "Kuratierte Skill-Pakete, die codeg zentral verwaltet und mit deinen KI-Agenten verknüpft – Programmierexperten, wissenschaftliche Forschung und Office-Dokumenttools. Unten pro Agent aktivierbar.", - "tabs": { - "experts": "Experten", - "science": "Wissenschaft", - "office": "Office-Tools", - "custom": "Benutzerdefiniert" - }, - "actions": { - "openCentralDir": "Zentralen Ordner öffnen", - "refresh": "Aktualisieren" - }, - "toasts": { - "openFolderFailed": "Ordner konnte nicht geöffnet werden" - } - }, - "QuickMessagesSettings": { - "title": "Schnellnachrichten", - "description": "Verwalte wiederverwendbare Nachrichtenbausteine. Ziehe zum Neuordnen.", - "loading": "Schnellnachrichten werden geladen…", - "emptyList": "Noch keine Schnellnachrichten. Klicke auf \"Neu\", um eine zu erstellen.", - "emptySelection": "Wähle eine Schnellnachricht zum Bearbeiten aus.", - "searchPlaceholder": "Nach Titel oder Inhalt suchen", - "untitled": "Ohne Titel", - "actions": { - "new": "Neu", - "save": "Speichern", - "delete": "Löschen", - "dragSort": "Zum Neuordnen ziehen", - "dragSortMessage": "Schnellnachricht neu ordnen: {name}" - }, - "fields": { - "title": "Titel", - "titlePlaceholder": "Gib dieser Nachricht einen kurzen Titel", - "content": "Inhalt", - "contentPlaceholder": "Gib hier den Nachrichteninhalt ein" - }, - "confirmDelete": { - "title": "Schnellnachricht löschen?", - "message": "Dadurch wird \"{name}\" dauerhaft gelöscht. Bist du sicher?", - "cancel": "Abbrechen", - "confirm": "Löschen" - }, - "toasts": { - "loadFailed": "Laden der Schnellnachrichten fehlgeschlagen", - "createFailed": "Erstellen der Schnellnachricht fehlgeschlagen", - "saveFailed": "Speichern der Schnellnachricht fehlgeschlagen", - "deleteFailed": "Löschen der Schnellnachricht fehlgeschlagen", - "saveOrderFailed": "Reihenfolge konnte nicht gespeichert werden", - "created": "Schnellnachricht erstellt", - "saved": "Schnellnachricht gespeichert", - "deleted": "Schnellnachricht gelöscht" - } - }, - "Pet": { - "badge": { - "running": "{count} laufend", - "waiting": "{count} warten auf Freigabe", - "error": "{count} fehlgeschlagen" - }, - "panel": { - "title": "Aktive Sitzungen", - "empty": "Keine aktiven Sitzungen", - "emptyHint": "Laufende Agenten und solche, die dich brauchen, erscheinen hier.", - "statusRunning": "Läuft", - "statusWaiting": "Wartet", - "statusError": "Fehler", - "subAgentOf": "Sub-Agent von" - }, - "menu": { - "scale": "Skalierung", - "openManager": "Pets verwalten", - "close": "Schließen" - }, - "loadError": "Pet konnte nicht geladen werden", - "missingPetIdParam": "Kein Pet ausgewählt", - "summonButton": "Pet", - "manager": { - "title": "Desktop-Pets", - "description": "Schwebende Begleiter mit Codex-kompatiblen Sprite-Sheets.", - "addPet": "Pet hinzufügen", - "importFromCodex": "Aus Codex importieren", - "noPets": "Keine Pets. Lege eines an oder importiere aus Codex.", - "setActive": "Aktivieren", - "active": "Aktiv", - "edit": "Bearbeiten", - "delete": "Löschen", - "deleteConfirm": "Pet „{name}\" löschen? Auch von der Festplatte entfernt.", - "summon": "Pet-Fenster aufrufen", - "openCodexHelp": "Codex-Pets müssen in ~/.codex/pets/ liegen. Nichts gefunden.", - "specRequirement": "Sprite-Sheet muss 1536px breit sein, mit einer Höhe als Vielfaches von 208px (z. B. 1872 oder 2288), als PNG oder WebP mit Transparenz.", - "form": { - "id": "Pet-ID", - "idHelp": "Kleinbuchstaben, Ziffern, '-' und '_'. Max 64 Zeichen.", - "displayName": "Anzeigename", - "description": "Beschreibung (optional)", - "spritesheet": "Sprite-Sheet", - "chooseFile": "Datei wählen", - "replaceFile": "Sprite ersetzen", - "saveCreate": "Pet hinzufügen", - "saveUpdate": "Änderungen speichern", - "cancel": "Abbrechen" - }, - "errors": { - "missingId": "Pet-ID erforderlich", - "missingName": "Anzeigename erforderlich", - "missingSpritesheet": "Sprite erforderlich", - "addFailed": "Hinzufügen fehlgeschlagen", - "updateFailed": "Aktualisieren fehlgeschlagen", - "deleteFailed": "Löschen fehlgeschlagen", - "loadFailed": "Pet-Liste konnte nicht geladen werden", - "setActiveFailed": "Aktivieren fehlgeschlagen", - "summonFailed": "Pet-Fenster konnte nicht geöffnet werden" - } - }, - "import": { - "title": "Aus Codex importieren", - "subtitle": "Pets unter ~/.codex/pets/.", - "selectAll": "Alle auswählen", - "alreadyImported": "Bereits importiert", - "renameOnConflict": "Konflikte mit Suffix -imported umbenennen", - "import": "Auswahl importieren", - "noneFound": "Keine importierbaren Codex-Pets gefunden.", - "imported": "Erfolgreich importiert", - "failed": "Import fehlgeschlagen", - "close": "Schließen" - }, - "marketplace": { - "openMarketplace": "Pet-Marketplace", - "title": "Pet-Marketplace", - "search": "Pets suchen", - "kindFilter": { - "all": "Alle", - "object": "Objekt", - "animal": "Tier", - "person": "Person", - "creature": "Kreatur" - }, - "sortFilter": { - "latest": "Neueste", - "popular": "Beliebt", - "views": "Aufrufe" - }, - "refresh": "Aktualisieren", - "install": "Installieren", - "installing": "Wird installiert", - "reinstall": "Neu installieren", - "reinstallConfirm": "Lokales Pet \"{name}\" überschreiben? Vorhandene Daten werden ersetzt.", - "cancel": "Abbrechen", - "stats": { - "views": "Aufrufe", - "downloads": "Downloads", - "likes": "Likes" - }, - "actions": { - "idle": "Idle", - "running_right": "Rechtslauf", - "running_left": "Linkslauf", - "waving": "Winken", - "jumping": "Springen", - "failed": "Fehler", - "waiting": "Warten", - "running": "Laufen", - "review": "Review" - }, - "page": "Seite {page} von {total}", - "prev": "Zurück", - "next": "Weiter", - "empty": "Keine Pets entsprechen dem Filter.", - "successInstalled": "\"{name}\" installiert", - "errors": { - "loadFailed": "Marketplace konnte nicht geladen werden", - "installFailed": "Installation fehlgeschlagen", - "alreadyInstalled": "Pet existiert bereits lokal" - } - } - }, - "RemoteWorkspace": { - "openRemoteWorkspace": "Open remote workspace", - "manage": "Manage remote workspace", - "manageTitle": "Remote Workspace connections", - "empty": "No remote connections", - "searchPlaceholder": "Search remote workspaces", - "orderFailed": "Failed to save remote workspace order", - "dragSort": "Drag to sort", - "dragSortConnection": "Drag to sort {name}", - "newConnection": "New connection", - "loading": "Loading", - "loadingConnection": "Loading remote connection", - "name": "Name", - "baseUrl": "Service URL", - "token": "Access token", - "save": "Save", - "delete": "Delete", - "confirmDelete": { - "title": "Delete remote connection?", - "message": "This will remove \"{name}\" from this device. This action cannot be undone.", - "cancel": "Cancel", - "confirm": "Delete" - }, - "saved": "Remote connection saved.", - "deleted": "Remote connection deleted.", - "loadFailed": "Failed to load remote connections", - "saveFailed": "Failed to save remote connection", - "deleteFailed": "Failed to delete remote connection", - "openFailed": "Failed to open remote workspace", - "connectionLoadFailed": "Failed to load remote connection: {message}", - "connectionExpired": "Remote connection \"{name}\" is expired. Update its token and reload this window." - }, - "ServerFileBrowser": { - "title": "Serverdatei auswählen", - "pathPlaceholder": "Verzeichnispfad eingeben...", - "goHome": "Zum Home-Verzeichnis", - "navigateUp": "Zum übergeordneten Verzeichnis", - "select": "Auswählen", - "cancel": "Abbrechen", - "loading": "Laden...", - "emptyDirectory": "Dieses Verzeichnis ist leer", - "errorLoadingDir": "Verzeichnis konnte nicht geladen werden", - "selectedCount": "{count} ausgewählt" - }, - "BackupSettings": { - "title": "Sicherung & Wiederherstellung", - "description": "Exportiere eine portable Sicherung deiner codeg-Daten oder stelle aus einer Sicherung wieder her.", - "tabs": { - "backup": "Sicherung", - "restore": "Wiederherstellung" - }, - "export": { - "includeExternal": "Gesprächsinhalte einschließen", - "includeExternalHint": "Archiviert auch die CLI-Transkripte (Claude, Codex, Gemini, …). Erhöht die Größe.", - "passphrase": "Passphrase (optional)", - "passphrasePlaceholder": "Leer lassen für ein unverschlüsseltes Archiv", - "passphraseConfirm": "Passphrase bestätigen", - "passphraseMismatch": "Die Passphrasen stimmen nicht überein.", - "noPassphraseWarning": "Diese Sicherung enthält Geheimnisse (API-Schlüssel, Tokens) im Klartext. Bewahre sie sicher auf.", - "passphraseLossWarning": "Mit dieser Passphrase verschlüsselt. Wenn du sie verlierst, kann die Sicherung nicht wiederhergestellt werden.", - "button": "Sicherung exportieren", - "inProgress": "Sicherung wird erstellt…", - "success": "Sicherung erstellt.", - "started": "Download der Sicherung gestartet." - }, - "restore": { - "selectFile": "Sicherungsdatei auswählen", - "passphrasePrompt": "Diese Sicherung ist verschlüsselt. Gib ihre Passphrase ein.", - "unlock": "Entsperren", - "preview": { - "title": "Sicherungsdetails", - "encrypted": "Verschlüsselt", - "compatible": "Kompatibel", - "incompatible": "Inkompatibel", - "createdAt": "Erstellt: {value}", - "appVersion": "App-Version: {value}", - "incompatibleHint": "Diese Sicherung wurde mit einer neueren Version von codeg erstellt und kann nicht wiederhergestellt werden." - }, - "replaceWarning": "Beim Wiederherstellen werden alle aktuellen codeg-Daten (Datenbank und Uploads) ersetzt. Deine aktuellen Daten werden zuvor als Snapshot gesichert.", - "keyringNote": "GitHub-/Chat-Tokens der Desktop-App liegen im Schlüsselbund des Betriebssystems und sind nicht enthalten; gib sie nach dem Wiederherstellen erneut ein.", - "button": "Wiederherstellen", - "staging": "Wiederherstellung wird vorbereitet…", - "staged": "Wiederherstellung vorbereitet. Neustart…", - "restarting": "Wiederherstellung vorbereitet. Server wird neu gestartet…", - "restartTimeout": "Der Server kam nicht rechtzeitig zurück. Lade die Seite neu, sobald er läuft.", - "externalSideLocation": "Gesprächstranskripte wurden nach {path} wiederhergestellt", - "confirmTitle": "Alle Daten ersetzen?", - "confirmBody": "Dadurch werden deine aktuelle codeg-Datenbank und Uploads durch die Sicherung ersetzt und anschließend neu gestartet. Deine aktuellen Daten werden zuvor als Snapshot gesichert.", - "cancel": "Abbrechen", - "confirmAction": "Ersetzen & neu starten", - "external": { - "title": "Gesprächsinhalte", - "hint": "Diese Sicherung enthält CLI-Transkripte. Wähle, wohin sie wiederhergestellt werden.", - "modeSkip": "Nicht wiederherstellen", - "modeSide": "In einen sicheren Nebenordner wiederherstellen", - "modeOriginal": "An den ursprünglichen CLI-Speicherorten wiederherstellen", - "forceOverwrite": "Vorhandene Dateien überschreiben", - "forceOverwriteHint": "Ersetzt Dateien, die bereits in den CLI-Ordnern vorhanden sind.", - "scanning": "Konflikte werden geprüft…", - "noConflicts": "Es werden keine vorhandenen Dateien überschrieben.", - "conflictCount": "{count} vorhandene Datei(en) wären betroffen.", - "conflictSkipNote": "Vorhandene Dateien bleiben erhalten (übersprungen), sofern du das Überschreiben nicht aktivierst." - }, - "restartFailed": "Wiederherstellung vorbereitet, aber der Server konnte nicht neu starten. Starte ihn manuell neu, um sie anzuwenden." - }, - "remoteUnsupported": "Sicherung & Wiederherstellung wirken auf die Daten des Rechners, auf dem codeg läuft. Du bist mit einem entfernten Arbeitsbereich verbunden – verwalte dessen Sicherungen direkt auf jenem Server." - }, - "backup": { - "restore": { - "error": { - "badPassphrase": "Falsche Passphrase oder beschädigte Sicherung.", - "corrupted": "Das Sicherungsarchiv ist beschädigt.", - "unknownFormat": "Diese Datei ist keine erkannte codeg-Sicherung.", - "newerVersion": "Diese Sicherung wurde mit codeg {backupVersion} erstellt, neuer als diese Version ({appVersion}).", - "alreadyPending": "Es ist bereits eine Wiederherstellung vorbereitet. Starte neu, um sie anzuwenden, bevor du eine weitere vorbereitest." - } - }, - "error": { - "diskSpace": "Nicht genügend Speicherplatz, um den Vorgang abzuschließen.", - "cancelled": "Der Vorgang wurde abgebrochen." - } - }, - "WebConnection": { - "disconnectedTitle": "Verbindung getrennt", - "reconnectingDescription": "Verbindung zum Server wird wiederhergestellt. Das geschieht normalerweise innerhalb weniger Sekunden automatisch.", - "reconnectNow": "Jetzt neu verbinden", - "sessionExpiredTitle": "Sitzung abgelaufen", - "sessionExpiredDescription": "Deine Sitzung ist nicht mehr gültig. Bitte melde dich erneut an, um fortzufahren.", - "goToLogin": "Zur Anmeldung" - }, - "LiveFeedback": { - "placeholder": "Sende {agent} eine Notiz, während er arbeitet…", - "agentFallback": "der Agent", - "ariaLabel": "Live-Feedback-Notiz", - "dialogTitle": "Live-Feedback", - "dialogDescription": "Sende dem Agenten eine Notiz, während er arbeitet. Er liest sie bei der nächsten Prüfung – ohne den aktuellen Schritt zu unterbrechen.", - "dialogDescriptionInstant": "Sende dem Agenten eine Notiz, während er arbeitet. Sie wird sofort in den laufenden Turn eingefügt – der Agent sieht sie umgehend.", - "channelDowngraded": "Sofortiges Einfügen ist in dieser Sitzung nicht verfügbar – deine Notiz wurde gespeichert; der Agent holt sie bei seinem nächsten Check ab.", - "send": "Senden", - "cancel": "Abbrechen", - "pending": "wartet", - "delivered": "erhalten", - "turnEndedUnread": "Der Agent hat die Runde beendet, bevor er dein Feedback gelesen hat.", - "sendAsMessage": "Als Nachricht senden", - "dismiss": "Verwerfen", - "turnEndedResent": "Die Runde endete – stattdessen als neue Nachricht gesendet.", - "turnEnded": "Die Runde ist bereits beendet.", - "submitFailed": "Deine Notiz konnte nicht gesendet werden" - }, - "AgentToolsSettings": { - "title": "Tools in der Unterhaltung", - "description": "Zusätzliche Tools, die codeg einem Agenten innerhalb einer Unterhaltung gibt. Sie werden beim Start des Agenten injiziert – eine Änderung gilt daher für danach gestartete Agenten.", - "feedbackLabel": "Live-Feedback", - "feedbackHint": "Sende einem Agenten Notizen und Korrekturen, während er arbeitet. Unterstützt der Agent sofortiges Einfügen, landet deine Notiz umgehend im laufenden Turn; andernfalls erhält der Agent ein Tool zum Abrufen deines Feedbacks – solche Agenten prüfen es meist nur, wenn du es im Prompt erwähnst, z. B. mit \"prüfe regelmäßig mein Live-Feedback\".", - "questionLabel": "Benutzer fragen", - "questionHint": "Erlaubt Agenten, anzuhalten und dir eine Multiple-Choice-Frage zu stellen, die über dem Eingabefeld der Unterhaltung erscheint. Der Agent wartet, bis du antwortest (oder überspringst).", - "sessionInfoLabel": "Sitzungsinformationen abrufen", - "sessionInfoHint": "Erlaubt Agenten, eine in deiner Nachricht referenzierte Sitzung (ein Sitzungs-Badge) nachzuschlagen, um Titel, Agent, Status, Arbeitsbereich, Token-Verbrauch und letzte Nachrichten zu lesen.", - "automationsLabel": "Automatisierungen erstellen", - "automationsHint": "Speichert die Unterhaltung als Automatisierung, die nach Zeitplan läuft. Standardmäßig aus – sie startet danach selbst Agenten.", - "workTasksLabel": "To-do-Aufgaben erstellen", - "workTasksHint": "Stellt aus der Unterhaltung heraus eine Karte auf das To-do-Board. Standardmäßig aus – schreibt App-Zustand.", - "save": "Speichern", - "saving": "Wird gespeichert…", - "saved": "Tool-Einstellungen gespeichert", - "saveFailed": "Tool-Einstellungen konnten nicht gespeichert werden", - "loadFailed": "Laden fehlgeschlagen: {detail}" - }, - "NotificationSoundSettings": { - "title": "Benachrichtigungstöne", - "description": "Spielt einen kurzen Ton ab, wenn ein Agent-Ereignis eintritt. Es sind dieselben Ereignisse, die an die Chat-Kanäle gesendet werden; diese Einstellung gilt nur für dieses Gerät.", - "enableHint": "Standardmäßig aus. Töne werden nur im Arbeitsbereich-Fenster dieses Browsers oder dieser App abgespielt.", - "volume": "Lautstärke", - "preview": "Anhören", - "previewEvent": "Ton für {event} anhören", - "onlyWhenUnfocused": "Nur wenn das Fenster nicht im Fokus ist", - "onlyWhenUnfocusedHint": "Bleibt stumm, solange du Codeg ansiehst.", - "eventsTitle": "Ereignisse", - "eventsHint": "Wähle pro Ereignis einen Ton oder „Stumm“, um es zu überspringen. Wiederholt sich dasselbe Ereignis innerhalb weniger Sekunden, erklingt es nur einmal.", - "toneNone": "Stumm", - "toneChime": "Glockenspiel", - "toneDing": "Klingel", - "toneBlip": "Blip", - "tonePop": "Pop", - "toneAlert": "Alarm", - "toneDescend": "Absteigend" - }, - "LogsSettings": { - "loading": "Wird geladen…", - "sectionTitle": "Laufzeitprotokolle", - "sectionDescription": "Diagnoseprotokolle der Anwendung anzeigen und konfigurieren. Protokolle werden in lokale Dateien geschrieben und für die Live-Ansicht im Speicher gehalten.", - "captureTitle": "Protokollebene", - "captureDescription": "Steuert, wie viele Details erfasst werden. Höhere Stufen (Debug, Trace) zeichnen mehr auf, erzeugen aber größere Protokolle. „Aus“ deaktiviert die Protokollierung.", - "captureLabel": "Erfassungsebene", - "levels": { - "off": "Aus", - "error": "Fehler", - "warn": "Warnung", - "info": "Info", - "debug": "Debug", - "trace": "Trace" - }, - "viewerTitle": "Aktuelle Protokolle", - "viewerDescription": "Live-Ansicht der letzten Protokolleinträge. Nach Ebene filtern oder Text suchen.", - "searchPlaceholder": "Nachricht oder Ziel suchen…", - "viewLevels": { - "all": "Alle Ebenen", - "error": "Fehler und höher", - "warn": "Warnung und höher", - "info": "Info und höher", - "debug": "Debug und höher", - "trace": "Trace und höher" - }, - "pause": "Pause", - "resume": "Live", - "refresh": "Aktualisieren", - "clear": "Leeren", - "openFolder": "Ordner öffnen", - "shownCount": "{shown} / {total} angezeigt", - "empty": "Keine Protokolle vorhanden.", - "levelSaveFailed": "Protokollebene konnte nicht gespeichert werden", - "openFolderFailed": "Protokollordner konnte nicht geöffnet werden", - "downloadFailed": "Protokolldatei konnte nicht heruntergeladen werden", - "filesTitle": "Protokolldateien", - "filesDescription": "Vollständige Protokolldateien von der Festplatte herunterladen, um den Verlauf über den Live-Puffer hinaus anzuzeigen.", - "filesEmpty": "Noch keine Protokolldateien.", - "download": "Herunterladen", - "downloadTruncated": "Die Datei ist groß; die neuesten {size} wurden heruntergeladen. Die vollständige Datei befindet sich im Log-Verzeichnis.", - "captureEnvLocked": "Die Protokollebene wird durch die Umgebungsvariable RUST_LOG / CODEG_LOG gesteuert; ändere sie dort, damit es wirksam wird.", - "targetsTitle": "Modulspezifische Überschreibungen", - "targetsDescription": "Lege für bestimmte Module (z. B. codeg_lib::acp) eine andere Stufe fest, ohne die globale Stufe zu ändern.", - "targetsAdd": "Hinzufügen", - "targetsRemove": "Überschreibung entfernen", - "toggleDetails": "Details umschalten" - }, - "Automations": { - "title": "Automatisierungen", - "new": "Neue Automatisierung", - "empty": "Noch keine Automatisierungen", - "emptyHint": "Erstelle eine, um eine Agentenaufgabe geplant oder manuell auszuführen.", - "name": "Name", - "namePlaceholder": "z. B. Nächtliche PR-Prüfung", - "prompt": "Eingabe", - "promptPlaceholder": "Was soll der Agent tun?", - "agent": "Agent", - "folder": "Arbeitsbereich-Ordner", - "folderPlaceholder": "Ordner auswählen", - "isolation": "Isolierung", - "isolationWorktree": "Neues Worktree pro Lauf", - "isolationShared": "Im Ordner ausführen", - "isolationSharedCaveat": "Ausführungen verwenden den Arbeitsbaum dieses Ordners direkt und können mit deinen nicht committeten Änderungen kollidieren. Aktiviere die Worktree-Option, um jede Ausführung zu isolieren.", - "trigger": "Auslöser", - "triggerSchedule": "Nach Zeitplan", - "triggerManual": "Nur manuell", - "cron": "Zeitplan (Cron)", - "cronPlaceholder": "0 9 * * 1-5", - "timezone": "Zeitzone", - "nextRun": "Nächster Lauf", - "branch": "Branch", - "branchOptional": "Branch (optional)", - "enabled": "Aktiviert", - "save": "Speichern", - "cancel": "Abbrechen", - "edit": "Bearbeiten", - "delete": "Löschen", - "runNow": "Jetzt ausführen", - "cancelRun": "Lauf abbrechen", - "runHistory": "Laufverlauf", - "noRuns": "Noch keine Läufe", - "allFolders": "Alle Ordner", - "filterAll": "Alle", - "noMatches": "Keine passenden Automatisierungen", - "viewConversation": "Konversation ansehen", - "lastRun": "Letzter Lauf", - "never": "Nie", - "running": "Läuft", - "deleteTitle": "Automatisierung löschen?", - "deleteDescription": "Dies entfernt die Automatisierung und ihren Zeitplan. Der Laufverlauf bleibt erhalten.", - "statusRunning": "Läuft", - "statusSucceeded": "Erfolgreich", - "statusFailed": "Fehlgeschlagen", - "statusCancelled": "Abgebrochen", - "statusSkipped": "Übersprungen", - "errorName": "Name ist erforderlich", - "errorPrompt": "Eingabe ist erforderlich", - "errorCron": "Geplante Automatisierungen benötigen einen Cron-Ausdruck", - "errorFolder": "Wähle einen Arbeitsbereich-Ordner", - "presetHourly": "Stündlich", - "presetDaily": "Täglich 9 Uhr", - "presetWeekdays": "Werktags 9 Uhr", - "presetCustom": "Benutzerdefiniert", - "probing": "Optionen werden geladen…", - "retry": "Erneut versuchen", - "configNone": "Dieser Agent hat keine konfigurierbaren Optionen", - "inherit": "Agent-Standard", - "mode": "Modus", - "config": "Konfiguration", - "branchPlaceholder": "(Standard-Branch)", - "selectHint": "Wähle eine Automatisierung, um Details zu sehen", - "refresh": "Aktualisieren", - "onboardTitle": "Routineaufgaben des Agenten automatisieren", - "onboardHint": "Plane einen Agenten, der Code überprüft, Abhängigkeiten aktualisiert oder Probleme sichtet – nach Zeitplan oder bei Bedarf.", - "headerSubtitle": "Geplante und bedarfsgesteuerte Agentenaufgaben", - "startFromTemplate": "Mit einer Vorlage beginnen", - "blankTitle": "Leere Automatisierung", - "blankDesc": "Eine Agentenaufgabe von Grund auf konfigurieren.", - "backToTemplates": "Vorlagen", - "sectionSchedule": "Zeitplan & Ziel", - "sectionTarget": "Ziel", - "sectionAction": "Aktion", - "actionLaunchSession": "Sitzung starten", - "actionEnqueueTask": "Aufgabe einreihen", - "actionEnqueueTaskHint": "Jede Auslösung fügt den To-dos des Ordners eine To-do-Aufgabe mit dem Namen dieser Automatisierung hinzu; die Task-Engine führt sie gemäß den Board-Einstellungen aus.", - "sectionPrompt": "Prompt", - "nextIn": "Nächste in {rel}", - "manual": "Manuell", - "schedEveryMinutes": "Alle {n} Minuten", - "schedHourly": "Stündlich", - "schedDaily": "Täglich um {time}", - "schedWeekdays": "Wochentags um {time}", - "schedWeekly": "Jeden {day} um {time}", - "schedMonthly": "Monatlich am {day}. um {time}", - "dow0": "Sonntag", - "dow1": "Montag", - "dow2": "Dienstag", - "dow3": "Mittwoch", - "dow4": "Donnerstag", - "dow5": "Freitag", - "dow6": "Samstag", - "tplCodeReviewTitle": "Code-Review", - "tplCodeReviewDesc": "Überprüft aktuelle Änderungen auf Fehler, Regressionen und Qualitätsprobleme.", - "tplDependencyUpdatesTitle": "Abhängigkeits-Updates", - "tplDependencyUpdatesDesc": "Findet veraltete Abhängigkeiten und schlägt sichere Upgrades vor.", - "tplTestCoverageTitle": "Testabdeckung", - "tplTestCoverageDesc": "Findet ungetestete Codepfade und ergänzt die fehlenden Tests.", - "tplTodoSweepTitle": "TODO-Durchsicht", - "tplTodoSweepDesc": "Sammelt TODO- und FIXME-Kommentare und sortiert sie nach Priorität.", - "tplCiTriageTitle": "CI-Sichtung", - "tplCiTriageDesc": "Untersucht kürzlich fehlgeschlagene Prüfungen und schlägt Korrekturen vor.", - "tplReleaseNotesTitle": "Release Notes", - "tplReleaseNotesDesc": "Fasst Änderungen seit dem letzten Release in einem Changelog zusammen.", - "tplSecurityAuditTitle": "Sicherheitsaudit", - "tplSecurityAuditDesc": "Sucht nach Schwachstellen und riskanten Mustern und meldet die Ergebnisse.", - "enable": "Aktivieren", - "disable": "Deaktivieren", - "moreActions": "Weitere Aktionen", - "statusDisabled": "Deaktiviert", - "cronBuilderTitle": "Zeitplan-Generator", - "cronFreqLabel": "Häufigkeit", - "cronFreqMinutes": "Alle N Minuten", - "cronFreqHourly": "Stündlich", - "cronFreqDaily": "Täglich", - "cronFreqWeekdays": "Wochentags", - "cronFreqWeekly": "Wöchentlich", - "cronFreqMonthly": "Monatlich", - "cronFreqCustom": "Benutzerdefiniert", - "cronEveryLabel": "Intervall (Minuten)", - "cronTimeLabel": "Uhrzeit", - "cronHourLabel": "Stunde", - "cronMinuteLabel": "Minute", - "cronDowLabel": "Wochentag", - "cronDomLabel": "Tag des Monats", - "cronApply": "Anwenden", - "cronPreviewLabel": "Vorschau", - "cronOpenBuilder": "Zeitplan-Generator öffnen", - "branchDefault": "Standard-Branch", - "branchUseCustom": "„{query}“ verwenden", - "branchLocal": "Lokal", - "branchRemote": "Remote", - "branchSearchPlaceholder": "Branches suchen…", - "branchNone": "Keine Branches" - }, - "Tasks": { - "title": "To-dos", - "new": "Neue Aufgabe", - "empty": "Noch keine Aufgaben", - "emptyHint": "Füge ein To-do hinzu und starte es — der Agent arbeitet in einem isolierten Worktree, du prüfst und mergst das Ergebnis.", - "emptyColTodo": "Noch keine To-dos", - "emptyColInProgress": "Nichts in Arbeit", - "emptyColAttention": "Nichts wartet auf dich", - "emptyColDone": "Noch nichts fertig", - "allFolders": "Alle Ordner", - "showCanceled": "Abgebrochene anzeigen", - "showArchived": "Archivierte anzeigen", - "filter": "Filter", - "viewSwitchToBoard": "Zur Board-Ansicht wechseln", - "viewSwitchToList": "Zur Listenansicht wechseln", - "statusFilter": "Status", - "statusFilterAll": "Alle Status", - "listEmpty": "Keine Aufgabe entspricht den aktuellen Filtern", - "listColStatus": "Status", - "listColTask": "Aufgabe", - "listColLocation": "Ort", - "listColChanges": "Änderungen", - "listColUpdated": "Aktualisiert", - "colTodo": "To-do", - "colInProgress": "In Arbeit", - "colAttention": "Wartet auf dich", - "colDone": "Fertig", - "statusTodo": "To-do", - "statusQueued": "In Warteschlange", - "statusPreparing": "Wird vorbereitet", - "statusRunning": "Läuft", - "statusAwaitingInput": "Wartet auf Eingabe", - "statusReview": "Zur Prüfung", - "statusMerging": "Wird gemergt", - "statusDone": "Fertig", - "statusFailed": "Fehlgeschlagen", - "statusCanceled": "Abgebrochen", - "statusInterrupted": "Unterbrochen", - "badgeCleanupFailed": "Aufräumen fehlgeschlagen", - "badgeWorktreeKept": "Worktree behalten", - "badgeWorktreeRemoved": "Worktree entfernt", - "filesChanged": "{count} Dateien", - "actionStart": "Starten", - "actionSchedule": "Planen", - "actionCancel": "Abbrechen", - "actionRetry": "Erneut versuchen", - "actionRequeue": "Erneut einreihen", - "actionViewSession": "Konversation anzeigen", - "actionEdit": "Bearbeiten", - "actionDelete": "Löschen", - "actionRetryCleanup": "Aufräumen wiederholen", - "actionMerge": "Mergen", - "actionUnqueueMerge": "Merge-Warteschlange verlassen", - "actionEditQueuedMerge": "Wartenden Merge bearbeiten", - "badgeMergeQueued": "Wartet auf Merge", - "badgeMergeQueuedRank": "Wartet auf Merge · Nr. {rank}", - "badgeMergeQueuedHint": "Wartet, bis der laufende Merge des Projekts fertig ist; dieser startet dann von selbst.", - "actionComplete": "Abschließen", - "actionAbandon": "Verwerfen", - "cancelTitle": "Aufgabe abbrechen?", - "cancelDescription": "Die Aufgabe wird auf Abgebrochen gesetzt. Ihr Worktree bleibt erhalten und du kannst sie später erneut einreihen.", - "cancelReasonLabel": "Grund (optional)", - "cancelReasonPlaceholder": "Z. B. falscher Ansatz – ich schreibe die Beschreibung neu", - "cancelKeep": "Doch nicht", - "cancelSubmit": "Aufgabe abbrechen", - "restartTitleRetry": "Aufgabe erneut versuchen", - "restartTitleRequeue": "Aufgabe erneut einreihen", - "restartDescription": "Du kannst eine Notiz ergänzen (optional) – sie landet im Prompt des nächsten Laufs.", - "scheduleTitle": "Aufgabe planen", - "scheduleDescription": "Die Aufgabe bleibt im To-do und startet zur gewählten Zeit von selbst. Das Parallelitätslimit des Ordners gilt weiterhin.", - "scheduleDateLabel": "Datum", - "schedulePickDate": "Datum wählen", - "scheduleTimeLabel": "Uhrzeit", - "schedulePreview": "Läuft am {time}", - "schedulePastHint": "Dieser Zeitpunkt liegt in der Vergangenheit – die Aufgabe startet direkt nach dem Speichern.", - "scheduleInAnHour": "In 1 Stunde", - "scheduleInThreeHours": "In 3 Stunden", - "scheduleTomorrow": "Morgen 9:00", - "scheduleClear": "Planung entfernen", - "scheduleBadge": "Geplanter Start: {time}", - "toastScheduled": "Geplant für {time}", - "toastScheduleCleared": "Planung entfernt", - "actionFollowUp": "Nachfassen", - "actionAddNote": "Hinweis ergänzen", - "followUpSubmit": "Senden", - "followUpIntentRevise": "Überarbeiten", - "followUpIntentContinue": "Weitermachen", - "followUpIntentQuestion": "Nachfragen", - "followUpIntentVerify": "Selbstprüfung", - "followUpPlaceholderRevise": "Was soll der Agent ändern? Er macht in derselben Sitzung weiter.", - "followUpPlaceholderContinue": "Was kommt als Nächstes? Das Bisherige bleibt bestehen.", - "followUpPlaceholderQuestion": "Was möchtest du wissen? Der Agent antwortet, ohne Dateien anzufassen.", - "followUpPlaceholderVerify": "Optional: Worauf soll es besonders achten?", - "followUpPlaceholderRetry": "Optional: Was soll diesmal anders laufen? Z. B. zuerst pnpm install ausführen", - "followUpPlaceholderRequeue": "Optional: Warum hast du abgebrochen, und was soll diesmal anders sein?", - "actionArchive": "Archivieren", - "actionUnarchive": "Dearchivieren", - "archiveAllDone": "Alle archivieren", - "dropToStart": "Loslassen zum Starten", - "errorView": "Ansehen", - "notifyReview": "Bereit zur Abnahme: {title}", - "notifyFailed": "Aufgabe fehlgeschlagen: {title}", - "createFromMessage": "Aufgabe aus Nachricht erstellen", - "detailTokens": "Token insgesamt", - "editorTitleNew": "Neue Aufgabe", - "editorTitleEdit": "Aufgabe bearbeiten", - "templates": "Vorlagen", - "templatesEmpty": "Noch keine Vorlagen.", - "templateSaveCurrent": "Aktuelles als Vorlage speichern", - "templateDelete": "Vorlage löschen", - "transcriptTitle": "Aufgaben-Konversation", - "transcriptDescription": "Schreibgeschützte Live-Ansicht der Agentensitzung dieser Aufgabe.", - "phaseWork": "Ausführung", - "phaseRetry": "Neuversuch", - "phaseReturn": "Nachfassen", - "phaseMerge": "Merge", - "titleLabel": "Titel", - "titlePlaceholder": "Was ist zu tun?", - "promptLabel": "Aufgabenbeschreibung", - "promptPlaceholder": "Beschreibe die Aufgabe für den Agenten — @ für Dateiverweise, / für Befehle", - "folderPlaceholder": "Ordner wählen", - "agentInheritedHint": "Aus den Aufgaben-Einstellungen geerbt — Änderungen gelten nur für diese Aufgabe", - "agentOverrideReset": "Wieder erben", - "sectionTarget": "Ziel", - "errorTitle": "Titel ist erforderlich", - "errorPrompt": "Beschreibung ist erforderlich", - "errorFolder": "Ordner wählen", - "save": "Speichern", - "cancel": "Abbrechen", - "mergeTitle": "Aufgabe mergen", - "mergeQueuedTitle": "Wartender Merge", - "mergeQueueHint": "Eine andere Aufgabe dieses Projekts wird gerade gemergt. Diese reiht sich ein und startet von selbst, sobald die andere fertig ist.", - "mergeQueueUpdateHint": "Diese Aufgabe wartet bereits auf den Merge. Beim Absenden wird sie aktualisiert und behält ihren Platz in der Warteschlange.", - "mergeDescription": "{branch} in {base} mergen. Nicht committete Änderungen im Worktree werden zuerst committet.", - "mergeMessage": "Commit-Nachricht", - "mergeMessagePlaceholder": "z. B. feat: add login validation", - "mergeAutoMessage": "Commit-Nachricht vom Agenten schreiben lassen", - "strategySquash": "Zu einem Commit zusammenfassen", - "strategySquashHint": "Alle Änderungen der Aufgabe landen als ein einzelner Eintrag im Verlauf des Hauptbranchs — der Verlauf bleibt übersichtlich.", - "strategyMerge": "Gesamten Verlauf behalten", - "strategyMergeHint": "Jeder während der Aufgabe erstellte Commit bleibt erhalten, plus ein Merge-Eintrag — jeder Schritt bleibt nachvollziehbar.", - "mergeDeleteWorktree": "Worktree nach dem Merge löschen", - "mergeSubmit": "Mergen", - "mergeSubmitQueue": "In die Warteschlange", - "mergeQueuedToast": "Zur Merge-Warteschlange hinzugefügt – startet, sobald der laufende Merge fertig ist.", - "completeTitle": "Aufgabe abschließen", - "completeDescription": "Diese Aufgabe hat keine Dateien geändert – es gibt nichts zu mergen, sie wird direkt als fertig markiert.", - "completeDescriptionNoWorktree": "Der Worktree dieser Aufgabe wurde entfernt – es kann nichts mehr gemergt werden, sie wird direkt als fertig markiert. Ein Arbeitsbranch mit noch nicht gemergten Commits bleibt erhalten.", - "completeDeleteWorktree": "Worktree nach dem Abschließen löschen", - "completeSubmit": "Abschließen", - "settingsTitle": "Aufgaben-Einstellungen", - "settingsDescription": "Standardwerte für Aufgaben in {folder}.", - "settingsScope": "Geltungsbereich", - "settingsScopeGlobal": "Alle Ordner (globale Standardwerte)", - "settingsScopeGlobalHint": "Ordner ohne eigene Einstellungen verwenden diese globalen Standardwerte.", - "settingsSource": "Konfigurationsquelle", - "settingsSourceGlobal": "Globale Standards", - "settingsSourceCustom": "Eigene", - "settingsSourceGlobalFollow": "Folgt den globalen Aufgaben-Einstellungen — Änderungen dort gelten hier automatisch.", - "settingsSourceCustomHint": "Speichert eigene Einstellungen für diesen Ordner; die globalen Standards gelten dann nicht mehr.", - "settingsAgent": "Standard-Agent", - "settingsMaxConcurrent": "Max. gleichzeitige Aufgaben", - "settingsMaxConcurrentHint": "0 = unbegrenzt", - "settingsAutoProcess": "Automatisch verarbeiten", - "settingsAutoProcessHint": "Offene Aufgaben starten von selbst, bis zum Parallelitätslimit.", - "settingsMergeStrategy": "Standard-Merge-Strategie", - "settingsMergeStrategyHint": "Wie die Änderungen der Aufgabe beim Mergen im Branch-Verlauf festgehalten werden.", - "settingsAutoMerge": "Automatisch mergen", - "settingsAutoMergeHint": "Eine Aufgabe, die mit landbaren Änderungen das Review erreicht, wird gemergt, als hättest du auf Mergen geklickt: Der Agent schreibt die Commit-Nachricht, der Worktree folgt der Voreinstellung unten. Bei rotem Preflight oder einem fehlgeschlagenen Merge wartet die Aufgabe auf dich.", - "settingsDeleteWorktree": "Worktree nach dem Mergen löschen", - "settingsDeleteWorktreeHint": "Aktiviert die Option im Merge-Dialog vor; dort lässt sie sich weiterhin ändern.", - "settingsWorktreeRoot": "Worktree-Verzeichnis", - "settingsWorktreeRootHint": "Verzeichnis, in dem neue Aufgaben-Worktrees angelegt werden – eines pro Aufgabe. Leer lassen, um sie neben dem Projektordner anzulegen; „~“ ist dein Home-Verzeichnis, ein relativer Pfad gilt relativ zum Projektordner.", - "settingsWorktreeRootPlaceholder": "~/codeg-worktrees", - "settingsWorktreeRootBrowse": "Worktree-Verzeichnis auswählen", - "settingsPreflight": "Preflight-Befehl", - "settingsPreflightHint": "Läuft im Worktree, sobald eine Aufgabe das Review erreicht.", - "settingsPreflightCustomPlaceholder": "pnpm test", - "settingsInitCommand": "Worktree-Init-Befehl", - "settingsInitCommandHint": "Läuft in einem frisch erstellten Worktree, bevor der Agent startet.", - "settingsInitCommandPlaceholder": "pnpm install", - "settingsTabGeneral": "Allgemein", - "settingsTabMerge": "Merge", - "settingsTabWorktree": "Worktree", - "settingsTabPrompts": "Prompts", - "settingsPromptsIntro": "Jede Phase sendet bereits einen eingebauten Prompt — die Aufgabe selbst, die Worktree-Regeln und beim Mergen die genauen Git-Schritte. Was du hier ergänzt, wird als zusätzliche Anweisung ans Ende gehängt: Es verfeinert den eingebauten Text, ersetzt ihn aber nie.", - "settingsPromptStageAll": "Alle Phasen", - "settingsPromptPlaceholderAll": "z. B. Halte dich an die Konventionen in AGENTS.md; fasse am Ende in zwei Sätzen zusammen", - "settingsPromptPlaceholderWork": "z. B. Lies zuerst die zugehörigen Tests; committe in kleinen Schritten", - "settingsPromptPlaceholderRetry": "z. B. Prüfe vor dem Weitermachen, was bereits committet ist; wiederhole nichts Fertiges", - "settingsPromptPlaceholderReturn": "Z. B. Arbeite jeden genannten Punkt ab; refaktoriere nichts Fremdes", - "settingsPromptPlaceholderMerge": "z. B. Schreibe die Merge-Commit-Nachricht auf Deutsch; nenne jeden manuell gelösten Konflikt", - "settingsPromptHintAll": "Wird an jeden Prompt des Agents angehängt, auch beim Merge-Lauf.", - "settingsPromptHintWork": "Wird angehängt, wenn eine Aufgabe zum ersten Mal läuft.", - "settingsPromptHintRetry": "Wird angehängt, wenn eine unterbrochene oder fehlgeschlagene Aufgabe fortgesetzt wird.", - "settingsPromptHintReturn": "Wird ergänzt, wenn du bei einer Aufgabe in Prüfung nachfasst (überarbeiten, erweitern, prüfen).", - "settingsPromptHintMerge": "Wird angehängt, wenn der Agent die Aufgabe in den Basis-Branch übernimmt.", - "preflightPassed": "{name} bestanden", - "preflightFailed": "{name} fehlgeschlagen", - "preflightRunning": "{name} läuft…", - "detailDescription": "Aufgabendetails", - "detailSummary": "Ergebnis", - "detailFiles": "Geänderte Dateien", - "detailDiffAll": "Gesamtes Diff anzeigen", - "detailDiffAllTitle": "Gesamtes Diff", - "detailNoChanges": "Noch keine Änderungen gegenüber der Basis", - "detailTimeline": "Verlauf", - "detailTimelineEmpty": "Noch keine Aktivität", - "showMore": "Mehr anzeigen", - "showLess": "Weniger anzeigen", - "detailInfo": "Details", - "detailBranch": "Branch", - "detailMergeCommit": "Merge-Commit", - "detailChanges": "Änderungen", - "detailScheduled": "Geplanter Start", - "detailCreated": "Erstellt", - "detailStarted": "Gestartet", - "detailFinished": "Abgeschlossen", - "diffLoading": "Diff wird geladen…", - "deleteConfirmTitle": "Aufgabe löschen?", - "deleteConfirmBody": "„{title}“ wird vom Board entfernt. Ein aktiver Lauf wird zuerst abgebrochen.", - "deleteWithWorktree": "Auch den Worktree löschen", - "eventCreated": "Erstellt", - "eventStatusChanged": "Statusänderung", - "eventConfigEffective": "Startkonfiguration", - "eventInitCommand": "Init-Befehl", - "eventAgentProgress": "Agent-Fortschritt", - "eventAgentVerdict": "Agent-Urteil", - "eventMergeAttempt": "Merge gestartet", - "eventMergeQueued": "In Merge-Warteschlange", - "eventMergeConflict": "Merge-Konflikt", - "eventPreflight": "Preflight", - "eventCleanupFailed": "Worktree-Aufräumen fehlgeschlagen", - "eventResumeFallback": "Sitzungsfortsetzung fehlgeschlagen, neue Sitzung", - "eventUserAction": "Benutzeraktion", - "eventDiffStat": "Änderungs-Snapshot" - }, - "CustomSkillsSettings": { - "loading": "Benutzerdefinierte Skills werden geladen…", - "category": "Benutzerdefiniert", - "searchPlaceholder": "Benutzerdefinierte Skills nach Name, ID oder Beschreibung suchen", - "states": { - "not_linked": "Nicht aktiviert", - "linked_to_codeg": "Aktiviert", - "linked_elsewhere": "Anderweitig verknüpft", - "blocked_by_real_directory": "Durch echten Ordner blockiert", - "broken": "Defekter Link" - }, - "actions": { - "new": "Neu", - "import": "Importieren", - "importFromAgent": "Von Agent importieren", - "cancel": "Abbrechen", - "save": "Speichern" - }, - "rowMenu": { - "edit": "Bearbeiten", - "duplicate": "Duplizieren", - "delete": "Löschen" - }, - "bulk": { - "delete": "Auswahl löschen" - }, - "editor": { - "createTitle": "Neuer benutzerdefinierter Skill", - "editTitle": "Benutzerdefinierten Skill bearbeiten", - "description": "Benutzerdefinierte Skills liegen im gemeinsamen Speicher (~/.codeg/skills) und können für jeden Agenten aktiviert werden.", - "idLabel": "Skill-ID", - "idPlaceholder": "z. B. my-workflow", - "contentLabel": "SKILL.md", - "contentPlaceholder": "Hier die SKILL.md des Skills schreiben…", - "preview": "Vorschau", - "edit": "Bearbeiten", - "emptyBody": "Noch kein Inhalt." - }, - "duplicate": { - "title": "Skill duplizieren", - "description": "Eine Kopie von „{id}“ mit einer neuen ID erstellen.", - "newIdPlaceholder": "Neue Skill-ID", - "confirm": "Duplizieren" - }, - "import": { - "title": "Skill-Ordner zum Importieren wählen" - }, - "importFromAgent": { - "title": "Skills von einem Agenten importieren", - "description": "Kopiere die eigenen Skills eines Agenten in den gemeinsamen Speicher, um sie für jeden Agenten zu aktivieren.", - "agentLabel": "Agent", - "agentPlaceholder": "Agent auswählen", - "selectAll": "Alle auswählen ({count})", - "loading": "Skills des Agenten werden geladen…", - "unsupported": "Dieser Agent stellt kein Skill-Verzeichnis bereit.", - "empty": "Dieser Agent hat keine importierbaren Skills.", - "alreadyInLibrary": "In Bibliothek", - "confirm": "Auswahl importieren ({count})" - }, - "delete": { - "title": "Benutzerdefinierte Skills löschen?", - "body": "Dadurch werden {count} benutzerdefinierte Skill(s) aus dem zentralen Speicher entfernt und von allen Agenten getrennt. Dies kann nicht rückgängig gemacht werden.", - "confirm": "Löschen" - }, - "toasts": { - "loadFailed": "Skill konnte nicht geladen werden", - "idRequired": "Bitte eine Skill-ID eingeben", - "created": "Benutzerdefinierter Skill erstellt", - "updated": "Benutzerdefinierter Skill aktualisiert", - "saveFailed": "Skill konnte nicht gespeichert werden", - "imported": "Skill importiert", - "importFailed": "Skill konnte nicht importiert werden", - "duplicated": "Skill dupliziert", - "duplicateFailed": "Skill konnte nicht dupliziert werden", - "deleted": "{count} Skill(s) gelöscht", - "deletedPartial": "{ok} gelöscht, {failed} fehlgeschlagen", - "deleteFailed": "Skills konnten nicht gelöscht werden", - "importedFromAgent": "{count} Skill(s) importiert", - "importedFromAgentPartial": "{ok} importiert, {failed} fehlgeschlagen", - "importFromAgentAllSkipped": "Nichts zu importieren – {count} bereits in der Bibliothek", - "importFromAgentFailed": "Import vom Agenten fehlgeschlagen" - } - }, - "CodexModelEditor": { - "customizedNotice": "Du hast die Modellliste angepasst, daher verwaltet codeg jetzt die gesamte Modelltabelle von codex. Offizielle Modelle, die codex später hinzufügt, erscheinen nicht automatisch – klicke unten auf Aktualisieren und speichere erneut, um sie zu übernehmen. Entferne alle Anpassungen, damit codex sich wieder automatisch aktualisiert.", - "officialsTitle": "Offizielle Modelle", - "officialsHint": "Automatisch aus dem gestarteten codex übernommen; nicht benötigte entfernen.", - "officialsEmpty": "Keine offiziellen Modelle verfügbar.", - "refresh": "Aus codex aktualisieren", - "readdOfficial": "Offizielles erneut hinzufügen", - "customsTitle": "Benutzerdefinierte Modelle", - "customsEmpty": "Noch keine benutzerdefinierten Modelle.", - "addCustom": "Benutzerdefiniert hinzufügen", - "slugPlaceholder": "Modell-ID (Slug)", - "displayNamePlaceholder": "Anzeigename", - "contextWindow": "Kontext", - "makeDefault": "Als Standard festlegen", - "defaultHint": "Standardmodell", - "remove": "Entfernen", - "advanced": "Erweitert", - "baseTemplate": "Basisvorlage", - "baseTemplateHint": "Offizielles Modell, von dem Pflichtfelder (System-Prompt, Tools, Limits) geklont werden.", - "groupBehavior": "Verhalten & Funktionen", - "fieldReasoningLevel": "Standard-Reasoning", - "fieldReasoningSummary": "Reasoning-Zusammenfassung", - "fieldVerbosity": "Ausführlichkeit", - "fieldShellType": "Shell-Typ", - "fieldApplyPatch": "Apply-Patch-Tool", - "fieldReasoningSummaries": "Reasoning-Zusammenfassungen", - "fieldSupportVerbosity": "Ausführlichkeitssteuerung", - "fieldParallelToolCalls": "Parallele Tool-Aufrufe", - "fieldSearchTool": "Websuche-Tool", - "optNone": "Keine", - "groupInstructions": "Beschreibung & System-Prompt", - "fieldDescription": "Beschreibung", - "baseInstructions": "System-Prompt (base_instructions)" - }, - "DiagnosticsSettings": { - "title": "Umgebungsdiagnose", - "description": "Prüft, wie diese App die Agent-CLI im eigenen Prozess auflöst – das kann sich von deinem Terminal unterscheiden.", - "loading": "Diagnose wird ausgeführt…", - "error": "Diagnose fehlgeschlagen", - "rerun": "Erneut ausführen", - "copyAll": "Alles kopieren", - "copied": "Diagnose in die Zwischenablage kopiert", - "button": "Diagnose", - "verdict": { - "ok": "Die Umgebung sieht in Ordnung aus. Wird trotzdem „nicht installiert“ angezeigt, starte die App komplett neu, um den Prefix-Cache zu aktualisieren.", - "node_missing": "Node.js wurde im PATH der App nicht gefunden.", - "npm_missing": "npm wurde im PATH der App nicht gefunden.", - "not_installed": "Dieser Agent scheint nicht installiert zu sein.", - "installed_but_unresolved": "Als installiert vermerkt, aber die App findet die ausführbare Datei nicht.", - "user_prefix_not_on_path": "In das Ausweich-Prefix (~/.codeg/npm-global) installiert, das nicht im PATH der App liegt. Starte die App komplett neu und versuche es erneut.", - "homebrew_bin_not_on_path": "Unter dem Homebrew-bin installiert, das nicht im PATH der App liegt (Apple-Silicon-Keg-Trennung).", - "terminal_only_path": "Der Befehl wird in deinem Terminal aufgelöst, aber nicht in der App – eine GUI-PATH-Lücke. Starte die App aus einem Terminal oder installiere sie in den Agent-Einstellungen neu.", - "npm_prefix_timeout": "npm prefix -g war zu langsam (über 1,5 s), daher wurde die Ausweicherkennung übersprungen. Starte die App neu und versuche es erneut.", - "node_too_old": "Dein aktives Node.js ist älter als von diesem Agenten benötigt. Aktualisiere Node.js.", - "adapter_missing_native_present": "Deine eigene {agent}-CLI ist installiert, aber Codeg startet ein separates ACP-Adapterpaket — und das fehlt noch. Installiere es in den Agenten-Einstellungen; es rührt deine CLI nicht an und teilt sich dieselbe Anmeldung.", - "adapter_missing": "Codeg startet für {agent} ein separates ACP-Adapterpaket, das noch nicht installiert ist. Installiere es in den Agenten-Einstellungen — die Hersteller-CLI allein genügt nicht." - } - }, - "TokenUsage": { - "title": "Token-Verbrauch", - "rangeLabel": "Zeitraum", - "range7d": "7 Tage", - "range30d": "30 Tage", - "range90d": "90 Tage", - "rangeThisMonth": "Dieser Monat", - "rangeThisYear": "Dieses Jahr", - "rangeAll": "Gesamt", - "rangeCustom": "Benutzerdefiniert", - "moreRanges": "Mehr", - "customRangePick": "Zeitraum wählen", - "bucketLabel": "Gruppieren nach", - "bucketDay": "Tag", - "bucketWeek": "Woche", - "bucketMonth": "Monat", - "bucketUnitDay": "Tag", - "bucketUnitWeek": "Woche", - "bucketUnitMonth": "Monat", - "folderFilter": "Ordner", - "allFolders": "Alle Ordner", - "agentFilter": "Agenten", - "allAgents": "Alle Agenten", - "modelFilter": "Modelle", - "allModels": "Alle Modelle", - "searchPlaceholder": "Suchen…", - "noMatches": "Keine Treffer", - "clearFilter": "Auswahl löschen", - "resetFilters": "Filter zurücksetzen", - "refresh": "Aktualisieren", - "rebuild": "Alles neu aufbauen", - "rebuildHint": "Verwirft die gezählten Daten und liest alle Sitzungsprotokolle neu ein. Nützlich, wenn eine Sitzung außerhalb von codeg gewachsen ist.", - "syncing": "Sitzungen werden gezählt…", - "syncProgress": "{done} / {total}", - "syncDone": "{synced} Sitzungen gezählt", - "syncFailed": "Einige Sitzungen konnten nicht gelesen werden", - "syncBusy": "Eine Aktualisierung läuft bereits", - "lastSynced": "Aktualisiert {time}", - "lastSyncedNever": "Noch nie aktualisiert", - "tileTotal": "Tokens gesamt", - "tileSessions": "Sitzungen", - "tileTurns": "Turns", - "tileActiveDays": "Aktive Tage", - "tileGenTime": "Generierungszeit", - "vsPrevious": "ggü. Vorperiode", - "deltaNew": "neu", - "trendTitle": "Verbrauch im Zeitverlauf", - "trendEmpty": "Kein Verbrauch in diesem Zeitraum", - "trendTurns": "Turns", - "trendSessions": "Sitzungen", - "compositionTitle": "Wofür die Tokens draufgingen", - "compositionHint": "Eingabe ist, was du gesendet hast, Ausgabe, was das Modell geschrieben hat, und Cache-Lesevorgänge sind Kontext, den du nicht voll bezahlt hast.", - "compositionNote": "Diese Cache-Treffer zum vollen Preis erneut zu senden hätte weitere {value} gekostet.", - "inputTokens": "Eingabe", - "outputTokens": "Ausgabe", - "cacheWrite": "Cache-Schreiben", - "cacheRead": "Cache-Lesen", - "freshTokens": "Frisch berechnet", - "cacheHitCaption": "Cache-Treffer", - "cacheHeroTitleHigh": "Der Großteil des Kontexts musste nie erneut gesendet werden", - "cacheHeroTitleLow": "Der Großteil des Kontexts wird noch voll berechnet", - "cacheHeroDesc": "{cached} des Kontexts trug der Cache — nur {fresh} wurde in diesem Zeitraum wirklich neu berechnet.", - "cacheSavedSuffix": "Das sparte erneutes Senden im Umfang von {saved}.", - "avgPerSession": "Ø pro Sitzung", - "avgTurnsPerSession": "Ø {count} Turns pro Sitzung", - "avgPerActiveDay": "Ø pro aktivem Tag", - "peakBucket": "Stärkste(r) {bucket}", - "peakHour": "Spitzenstunde", - "daysValue": "{count} Tage", - "idleDays": "Leerlauftage", - "byFolderTitle": "Nach Ordner", - "byAgentTitle": "Nach Agent", - "byModelTitle": "Nach Modell", - "distributionTitle": "Verteilung der Nutzung", - "distributionHint": "Sitzungen und Tokens nach gewählter Dimension gebündelt — Klick auf eine Zeile filtert danach.", - "otherLabel": "Sonstige", - "unknownModel": "Modell nicht erfasst", - "emptyBreakdown": "Noch nichts erfasst", - "sessionsCount": "{count} Sitzungen", - "heatmapTitle": "Wann du baust", - "heatmapHint": "Tokens nach lokalem Wochentag und Stunde.", - "heatmapPeakHint": "Am dichtesten gegen {hour}:00 Uhr.", - "less": "Weniger", - "more": "Mehr", - "heatmapCell": "{weekday} {hour}:00 — {value} Tokens", - "weekMon": "Mo", - "weekTue": "Di", - "weekWed": "Mi", - "weekThu": "Do", - "weekFri": "Fr", - "weekSat": "Sa", - "weekSun": "So", - "topSessionsTitle": "Teuerste Sitzungen", - "untitledSession": "Unbenannte Sitzung", - "topSessionsEmpty": "Keine Sitzungen in diesem Zeitraum", - "streakLongest": "Längste Serie", - "streakLongestDays": "Längste Serie: {count} Tage", - "share": "Teilen", - "moreActions": "Weitere Aktionen", - "shareDialogTitle": "Teile deine Verbrauchskarte", - "shareDialogHint": "Eine Momentaufnahme des gewählten Zeitraums und der Filter.", - "shareSave": "Bild speichern", - "shareCopy": "Bild kopieren", - "shareCopied": "In die Zwischenablage kopiert", - "shareSaved": "Bild gespeichert", - "shareFailed": "Bild konnte nicht erstellt werden", - "shareRendering": "Wird erstellt…", - "cardHeading": "Meine KI-Coding-Bilanz", - "cardRangeAll": "Gesamter Zeitraum", - "cardTotalLabel": "Verbrauchte Tokens", - "cardFooter": "Erstellt mit codeg", - "cardTopModels": "Top-Modelle", - "cardTopProjects": "Top-Projekte", - "archetypeNightOwl": "Nachteule", - "archetypeNightOwlDesc": "{percent}% deiner Tokens gehen nach Einbruch der Dunkelheit drauf.", - "archetypeEarlyBird": "Frühaufsteher", - "archetypeEarlyBirdDesc": "{percent}% deiner Tokens fallen vor 9 Uhr an.", - "archetypeWeekendWarrior": "Wochenendkrieger", - "archetypeWeekendWarriorDesc": "{percent}% deiner Tokens entstehen am Wochenende.", - "archetypeCacheMaster": "Cache-Meister", - "archetypeCacheMasterDesc": "{percent}% deines Kontexts kamen aus dem Cache.", - "archetypeMarathoner": "Marathonläufer", - "archetypeMarathonerDesc": "{days} Tage am Stück gebaut.", - "archetypePolyglot": "Allrounder", - "archetypePolyglotDesc": "{count} Agenten im ernsthaften Einsatz.", - "archetypeLaserFocus": "Laserfokus", - "archetypeLaserFocusDesc": "{percent}% deiner Tokens gingen in ein einziges Projekt.", - "archetypeDeepDiver": "Tieftaucher", - "archetypeDeepDiverDesc": "{averageK}K Tokens in einer durchschnittlichen Sitzung.", - "archetypeSteady": "Stetiger Bauer", - "archetypeSteadyDesc": "{days} Tage geliefert.", - "emptyTitle": "Noch nichts gezählt", - "emptyHint": "Codeg liest die Token-Zahlen direkt aus dem Protokoll jedes Agenten. Aktualisiere, um zu zählen, was schon auf diesem Rechner liegt.", - "emptyAction": "Meine Sitzungen zählen", - "loadFailed": "Verbrauch konnte nicht geladen werden", - "truncatedNotice": "Dieser Zeitraum ist sehr groß — die Zahlen decken nur seinen jüngsten Abschnitt ab." - } -} +{ + "Language": { + "followSystem": "Systemsprache verwenden", + "english": "Englisch", + "simplifiedChinese": "Vereinfachtes Chinesisch", + "traditionalChinese": "Traditionelles Chinesisch", + "japanese": "Japanisch", + "korean": "Koreanisch", + "spanish": "Spanisch", + "german": "Deutsch", + "french": "Französisch", + "portuguese": "Portugiesisch", + "arabic": "Arabisch" + }, + "GitCredentialDialog": { + "title": "Authentifizierung erforderlich", + "description": "Der Remote-Server erfordert Anmeldedaten. Geben Sie Ihren Benutzernamen und Ihr Passwort (oder persönliches Zugriffstoken) ein.", + "username": "Benutzername", + "usernamePlaceholder": "Benutzername oder E-Mail", + "password": "Passwort / Token", + "passwordPlaceholder": "Passwort oder persönliches Zugriffstoken", + "passwordHint": "Geben Sie Benutzername und Passwort des Servers ein.", + "cancel": "Abbrechen", + "authenticate": "Authentifizieren", + "authenticating": "Authentifizierung...", + "invalidCredentials": "Ungültige Anmeldedaten. Bitte versuchen Sie es erneut.", + "saveCredentials": "Anmeldedaten für zukünftige Vorgänge speichern", + "githubTitle": "GitHub-Authentifizierung", + "githubDescription": "Geben Sie ein persönliches Zugriffstoken ein, um sich mit GitHub zu verbinden. Das Token wird validiert und automatisch gespeichert.", + "githubToken": "Persönliches Zugriffstoken", + "githubTokenPlaceholder": "ghp_xxxxxxxxxxxx", + "githubTokenHint": "Erstellen Sie ein Token unter GitHub → Settings → Developer settings → Personal access tokens.", + "githubAuthenticate": "Validieren & verbinden", + "generateToken": "Token erstellen" + }, + "SettingsShell": { + "title": "Einstellungen", + "preferences": "Präferenzen", + "nav": { + "general": "Allgemein", + "appearance": "Darstellung", + "agents": "Agenten", + "mcp": "MCP", + "skills": "Skills", + "shortcuts": "Kurzbefehle", + "version_control": "Versionskontrolle", + "system": "Systemeinstellungen", + "chat_channels": "Chat-Kanäle", + "web_service": "Webdienst", + "model_providers": "Modellanbieter", + "experts": "Experten", + "science": "Wissenschaft", + "office_tools": "Office-Tools", + "skill_packs": "Skill-Pakete", + "quick_messages": "Schnellnachrichten", + "logs": "Laufzeitprotokolle" + } + }, + "AppearanceSettings": { + "sectionTitle": "Design-Erscheinungsbild", + "sectionDescription": "Wähle hell, dunkel oder Systemvorgabe. Einstellungen werden automatisch gespeichert.", + "themeMode": "Designmodus", + "placeholder": "Designmodus auswählen", + "system": "Systemvorgabe", + "light": "Hell", + "dark": "Dunkel", + "currentTheme": "Aktuell wirksames Design: {theme}", + "resolvedTheme": { + "light": "Hell", + "dark": "Dunkel", + "unknown": "--" + }, + "themeColor": { + "sectionTitle": "Themenfarbe", + "sectionDescription": "Wähle eine Farbpalette für Akzente, Schaltflächen und Hervorhebungen.", + "current": "Aktuelle Farbe: {color}", + "options": { + "neutral": "Neutral", + "zinc": "Zinc", + "slate": "Slate", + "stone": "Stone", + "gray": "Gray", + "red": "Red", + "rose": "Rose", + "orange": "Orange", + "green": "Green", + "blue": "Blue", + "yellow": "Yellow", + "violet": "Violet" + } + }, + "customStyle": { + "sectionTitle": "Eigener Stil", + "sectionDescription": "Feinjustiere die Farben des aktuellen Themes oder füge eigenes CSS ein. Überschreibungen liegen über der Basisvorlage und bleiben beim Wechsel der Vorlage erhalten.", + "summarySuspended": "Ausgesetzt", + "summaryDefault": "Vorlage unverändert", + "summaryTokens": "{count, plural, one {# Überschreibung} other {# Überschreibungen}}", + "summaryCss": "Eigenes CSS", + "suspendedByShortcut": "Der eigene Stil ist ausgesetzt. Nichts, was du hier einstellst, wirkt, bis du ihn fortsetzt.", + "suspendedBySafeParam": "Dieses Fenster wurde im sicheren Darstellungsmodus geöffnet, daher wird eigener Stil hier ignoriert. Andere Fenster sind nicht betroffen.", + "resume": "Eigenen Stil fortsetzen", + "enableTheme": "Eigene Farben aktivieren", + "editingLight": "Du bearbeitest die Werte des hellen Modus. Wechsle die App in den dunklen Modus, um diesen separat einzustellen.", + "editingDark": "Du bearbeitest die Werte des dunklen Modus. Wechsle die App in den hellen Modus, um diesen separat einzustellen.", + "resetToken": "Auf Vorlagenwert zurücksetzen", + "radius": "Eckenradius", + "radiusHint": "Daraus leitet sich die gesamte Radiusskala von sm bis 4xl ab – ein Regler rundet die ganze App.", + "advanced": "Erweitert ({count} weitere Variablen)", + "enableCss": "Eigenes CSS aktivieren", + "cssRisk": "Funktion für Fortgeschrittene. Eigenes CSS überschreibt sämtliche eingebauten Stile und kann die Oberfläche unbrauchbar machen.", + "editCss": "CSS bearbeiten…", + "cssPresent": "{size} KB gespeichert", + "cssEmpty": "Noch nichts gespeichert", + "escapeHint": "Oberfläche kaputt? Drücke {shortcut}, um den gesamten eigenen Stil auszusetzen, oder öffne ein Fenster mit dem Query-Parameter safeStyle=1.", + "copyTheme": "Theme-JSON kopieren", + "importTheme": "Theme importieren…", + "clearTheme": "Überschreibungen löschen", + "interopHint": "Themes nutzen das registry:theme-Format von shadcn – du kannst hier jedes shadcn-Theme einfügen und exportierte in jedem shadcn-Projekt verwenden.", + "importTitle": "Theme importieren", + "importDescription": "Füge ein shadcn-registry:theme-Item, ein reines light/dark-Objekt oder eine flache Token-Zuordnung ein.", + "readClipboard": "Zwischenablage lesen", + "importConfirm": "Importieren", + "cancel": "Abbrechen", + "apply": "Anwenden", + "toasts": { + "copied": "Theme-JSON kopiert", + "copyFailed": "Kopieren in die Zwischenablage fehlgeschlagen", + "clipboardReadFailed": "Zwischenablage konnte nicht gelesen werden, bitte manuell einfügen", + "importFailed": "In diesem JSON wurden keine nutzbaren Theme-Variablen gefunden", + "imported": "Theme importiert" + }, + "css": { + "dialogTitle": "Eigenes CSS", + "dialogDescription": "Gilt für alle codeg-Fenster. Änderungen werden live vorschauend angezeigt; zum Speichern auf Anwenden klicken.", + "size": "{used} KB / {max} KB", + "ruleCount": "{count} Regeln", + "errorTooLarge": "Zu groß zum Speichern. Bitte unter das Limit kürzen.", + "errorImportEscaped": "Eine @import-Regel hat das Entfernen überstanden (maskierte Schreibweise). Bitte entfernen, um zu speichern.", + "warnNoRules": "Keine Regeln erkannt – bitte die Syntax prüfen.", + "noticeImportsRemoved": "Entfernte @import-Regeln: {count}. Sie würden entfernte Stylesheets laden.", + "noticeRemoteUrl": "Enthält eine entfernte url(), die beim Anwenden eine Netzwerkanfrage auslöst.", + "noticePreviewSuspended": "Der eigene Stil ist ausgesetzt, daher wird diese Vorschau nicht angewendet.", + "noticeDisabled": "Eigenes CSS ist aus. Du kannst hier eine Vorschau sehen, aber es wirkt erst nach dem Aktivieren.", + "hintTokens": "Tipp: Deine überschriebenen Farben sind als var(--primary), var(--background) usw. verfügbar." + } + }, + "zoomLevel": { + "sectionTitle": "Fensterzoom", + "sectionDescription": "Skaliert die gesamte Oberfläche. Wird sofort übernommen und pro Gerät gespeichert.", + "placeholder": "Zoomstufe wählen", + "default": "Standard", + "current": "Aktueller Zoom: {zoom}%" + }, + "fonts": { + "sectionTitle": "Schriftarten", + "sectionDescription": "Wähle Schriftarten für Oberfläche, Code-Editor und Terminal. Mitgelieferte Schriftarten werden bei Bedarf geladen; wähle „Benutzerdefiniert…“, um eine beliebige auf deinem System installierte Schriftart zu verwenden.", + "interface": "Oberfläche", + "editor": "Editor", + "terminal": "Terminal", + "groupSans": "Serifenlos", + "groupMono": "Monospace", + "custom": "Benutzerdefiniert…", + "customPlaceholder": "Schriftartname, z. B. Fira Code", + "fontSize": "Schriftgröße", + "ligatures": "Ligaturen aktivieren", + "ligaturesUnavailable": "Diese Schriftart hat keine Ligaturen", + "wordWrap": "Zeilenumbruch aktivieren", + "terminalLigaturesHint": "Terminal-Ligaturen gelten nur für mitgelieferte Programmierschriftarten.", + "preview": "Vorschau" + }, + "welcomePanel": { + "sectionTitle": "Modusauswahlbereich", + "sectionDescription": "Die Shortcut-Karten „Code-Entwicklung / Büroarbeit“ über dem Eingabefeld auf der Seite für eine neue Konversation.", + "showQuickActions": "Auf der Seite für neue Konversationen anzeigen" + }, + "workspaceBackground": { + "sectionTitle": "Arbeitsbereich-Hintergrund", + "sectionDescription": "Zeigt ein Bild hinter dem gesamten Arbeitsbereich. Seitenleiste und Panels werden durchscheinend und mattiert, sodass das Bild durchscheint, und eine Maske sorgt für lesbaren Text.", + "enable": "Hintergrundbild aktivieren", + "image": "Bild", + "chooseImage": "Bild auswählen", + "replaceImage": "Bild ersetzen", + "removeImage": "Entfernen", + "fillMode": "Füllmodus", + "fillModes": { + "cover": "Füllen", + "contain": "Einpassen", + "center": "Zentrieren", + "tile": "Kacheln" + }, + "maskOpacity": "Maskendeckkraft", + "maskOpacityHint": "Höhere Werte blenden das Bild zur Hintergrundfarbe des Themes aus und verbessern den Textkontrast.", + "imageBlur": "Bildunschärfe", + "panelOpacity": "Panel-Deckkraft", + "panelOpacityHint": "Wie deckend Seitenleiste, Panels und Tab-Leisten sind. Niedriger lässt mehr vom Bild durchscheinen.", + "errorTooLarge": "Bild ist zu groß (max. 16 MB).", + "errorUploadFailed": "Hintergrundbild konnte nicht festgelegt werden." + } + }, + "SystemSettings": { + "loading": "Wird geladen...", + "sectionTitle": "Systemverwaltung", + "sectionDescription": "Verwalte Netzwerk-Proxy, App-Updates und Spracheinstellungen.", + "proxyTitle": "Netzwerk-Proxy", + "proxyDescription": "Wenn aktiviert, werden nachfolgende Netzwerkanfragen bevorzugt über diesen Proxy ausgeführt (einschließlich ACP-Chat, Agent-Installation und Git-Remote-Operationen).", + "loadFailed": "Laden fehlgeschlagen: {message}", + "enableProxy": "System-Proxy aktivieren", + "proxyAddress": "Proxy-Adresse", + "proxyHint": "Unterstützt http(s)/socks5, Beispiel: {example}. Wirksam nur bei aktiviertem System-Proxy.", + "save": "Speichern", + "saving": "Wird gespeichert...", + "proxyRequired": "Bei aktiviertem Proxy ist eine Proxy-URL erforderlich", + "saveSuccess": "System-Proxy-Einstellungen wurden gespeichert", + "saveFailed": "Speichern fehlgeschlagen: {message}", + "languageTitle": "Sprache", + "languageDescription": "Lege die App-Sprache fest. Bei Systemsprache wird bei nicht unterstützten Sprachen auf Englisch zurückgefallen.", + "appLanguage": "App-Sprache", + "languageSaveSuccess": "Spracheinstellungen wurden gespeichert", + "languageSaveFailed": "Spracheinstellungen konnten nicht gespeichert werden: {message}", + "updateTitle": "App-Update", + "versionTitle": "Softwareupdate", + "updateDescription": "Prüft die konfigurierte Release-Quelle auf neue Versionen und installiert sie bei Verfügbarkeit direkt.", + "currentVersion": "Aktuelle Version", + "upgradableVersion": "Neueste Version", + "none": "Keine", + "lastChecked": "Zuletzt geprüft: {time}", + "updateError": "Update-Fehler: {message}", + "checking": "Wird geprüft...", + "checkUpdate": "Nach Updates suchen", + "updating": "Wird installiert...", + "downloading": "Herunterladen...", + "upgradeTo": "Auf v{version} aktualisieren", + "viewRelease": "Release v{version} anzeigen", + "foundUpdate": "Neue Version v{version} gefunden", + "alreadyLatest": "Du verwendest bereits die neueste Version", + "checkUpdateFailed": "Update-Prüfung fehlgeschlagen: {message}", + "installSuccess": "Update installiert. App wird neu gestartet.", + "installFailed": "Update fehlgeschlagen: {message}", + "upgradeSuccess": "Aktualisierung abgeschlossen. Wird neu geladen...", + "restartTimeout": "Der Server ist nicht rechtzeitig zurückgekehrt. Prüfe die Container- oder Dienstprotokolle.", + "restartingIn": "Neustart in {seconds} s...", + "waitingForServer": "Warten, bis der Server zurückkehrt...", + "restartToUpdate": "Zum Aktualisieren neu starten", + "newVersionBadge": "Neu v{version}", + "updateAvailableTitle": "Update verfügbar", + "releaseNotesTitle": "Neuerungen", + "remindLater": "Später", + "retry": "Erneut versuchen", + "stepDownload": "Download", + "stepInstall": "Installation", + "stepRestart": "Neustart", + "updateReadyHint": "Update heruntergeladen – zum Anwenden neu starten.", + "restarting": "Neustart...", + "dockerUpgradeHint": "Dies aktualisiert jetzt den laufenden Container. Beim Neuerstellen des Containers geht es verloren – zum Beibehalten ein Image mit der neuen Version ziehen oder bauen und den Container neu erstellen.", + "upgradeRolledBack": "Upgrade fehlgeschlagen; der Server wurde auf die vorherige Version zurückgesetzt.", + "serverUnreachable": "Der Server konnte für das Upgrade nicht erreicht werden. Prüfe, ob er läuft, und versuche es erneut.", + "rollbackButton": "Zurücksetzen", + "rollingBack": "Wird zurückgesetzt...", + "rollbackDescription": "Stellt die vor dem letzten Upgrade installierte Version wieder her.", + "rollbackConfirmTitle": "Auf die vorherige Version zurücksetzen?", + "rollbackConfirmDescription": "Der Server startet mit der vor dem letzten Upgrade installierten Version neu. Eine neuere Version kann weiterhin erneut installiert werden.", + "rollbackConfirm": "Zurücksetzen", + "rollbackCancel": "Abbrechen", + "rollbackSuccess": "Auf die vorherige Version zurückgesetzt. Wird neu geladen...", + "rollbackFailed": "Zurücksetzen fehlgeschlagen. Prüfe die Serverprotokolle.", + "updateErrors": { + "sourceUnavailable": "Die Update-Quelle ist nicht erreichbar. Prüfe Netzwerk oder Proxy und versuche es erneut.", + "network": "Netzwerkverbindung fehlgeschlagen. Prüfe Netzwerk oder Proxy und versuche es erneut.", + "downloadFailed": "Das Update-Paket konnte nicht heruntergeladen werden. Bitte später erneut versuchen.", + "installFailed": "Das Update konnte nicht installiert werden. Bitte App schließen und erneut versuchen.", + "unknown": "Update fehlgeschlagen. Bitte später erneut versuchen." + } + }, + "VersionControlSettings": { + "loading": "Laden...", + "sectionTitle": "Versionskontrolle", + "sectionDescription": "Git-Programm konfigurieren und GitHub-Konten verwalten.", + "gitTitle": "Git-Konfiguration", + "gitDescription": "Konfigurieren Sie das von der Anwendung verwendete Git-Programm.", + "gitDetected": "Git erkannt", + "gitNotFound": "Git wurde nicht gefunden", + "gitVersion": "Version", + "gitPath": "Pfad", + "customGitPath": "Benutzerdefinierter Git-Pfad", + "customGitPathPlaceholder": "/usr/bin/git", + "customGitPathHint": "Leer lassen, um den automatisch erkannten Pfad zu verwenden.", + "test": "Testen", + "testing": "Teste...", + "testSuccess": "Git-Programm ist gültig.", + "testFailed": "Git-Test fehlgeschlagen: {message}", + "save": "Speichern", + "saving": "Speichern...", + "saveSuccess": "Git-Einstellungen gespeichert.", + "saveFailed": "Speichern fehlgeschlagen: {message}", + "githubTitle": "GitHub-Konten", + "githubDescription": "GitHub-Konten für die Authentifizierung verwalten. Token werden lokal gespeichert.", + "noAccounts": "Keine GitHub-Konten konfiguriert.", + "addAccount": "Konto hinzufügen", + "serverUrl": "Server-URL", + "serverUrlPlaceholder": "https://github.com", + "token": "Persönlicher Zugriffstoken", + "tokenPlaceholder": "ghp_xxxxxxxxxxxx", + "generateToken": "Token erstellen", + "tokenHint": "Erstellen Sie einen Token unter GitHub → Settings → Developer settings → Personal access tokens.", + "validateAndAdd": "Validieren & hinzufügen", + "validating": "Validiere...", + "addSuccess": "Konto {username} erfolgreich hinzugefügt.", + "addFailed": "Konto konnte nicht hinzugefügt werden: {message}", + "testConnection": "Testen", + "connectionSuccess": "Verbindung erfolgreich.", + "connectionFailed": "Verbindung fehlgeschlagen: {message}", + "setDefault": "Als Standard festlegen", + "defaultLabel": "Standard", + "defaultSet": "Standardkonto aktualisiert.", + "removeAccount": "Entfernen", + "removeConfirmTitle": "Konto entfernen", + "removeConfirmMessage": "Möchten Sie das Konto \"{username}\" wirklich entfernen?", + "removeConfirm": "Entfernen", + "removeCancel": "Abbrechen", + "removeSuccess": "Konto entfernt.", + "scopes": "Berechtigungen", + "loadFailed": "Einstellungen konnten nicht geladen werden: {message}", + "gitAccount": { + "sectionTitle": "Git-Server-Konten", + "sectionDescription": "Verwalten Sie Anmeldedaten für Nicht-GitHub-Git-Server (GitLab, Bitbucket, selbst gehostet usw.).", + "noAccounts": "Keine Git-Server-Konten konfiguriert.", + "addAccount": "Konto hinzufügen", + "addTitle": "Git-Konto hinzufügen", + "addDescription": "Geben Sie Serveradresse, Benutzername und Passwort oder Zugriffstoken ein.", + "serverUrl": "Server-URL", + "serverUrlPlaceholder": "https://gitlab.example.com", + "username": "Benutzername", + "usernamePlaceholder": "Benutzername oder E-Mail", + "password": "Passwort / Token", + "passwordPlaceholder": "Passwort oder Zugriffstoken", + "passwordHint": "Geben Sie das Passwort oder Zugriffstoken des Servers ein.", + "add": "Hinzufügen", + "serverRequired": "Server-URL ist erforderlich.", + "usernameRequired": "Benutzername ist erforderlich.", + "passwordRequired": "Passwort ist erforderlich." + } + }, + "ShortcutSettings": { + "sectionTitle": "Kurzbefehle", + "resetDefault": "Standardwerte zurücksetzen", + "recordInstruction": "Klicke auf die rechte Schaltfläche und drücke dann eine Tastenkombination. Verwende Ctrl/Cmd, Alt und Shift. Drücke Esc, um die Aufzeichnung abzubrechen.", + "recording": "Kurzbefehl drücken...", + "toasts": { + "conflict": "Der Kurzbefehl wird bereits von \"{title}\" verwendet", + "updated": "Kurzbefehl aktualisiert", + "invalid": "Ungültiger Kurzbefehl, bitte erneut versuchen", + "reset": "Standard-Kurzbefehle wurden wiederhergestellt" + }, + "actions": { + "toggle_search": { + "title": "Suche öffnen", + "description": "Zeigt das Konversations-Suchpanel an oder blendet es aus" + }, + "toggle_sidebar": { + "title": "Linke Seitenleiste umschalten", + "description": "Zeigt die Seitenleiste mit der Konversationsliste an oder blendet sie aus" + }, + "toggle_terminal": { + "title": "Terminal umschalten", + "description": "Zeigt das untere Terminal-Panel an oder blendet es aus" + }, + "new_terminal_tab": { + "title": "Neues Terminal", + "description": "Erstellt einen neuen Terminal-Tab, wenn das Terminal fokussiert ist" + }, + "close_current_terminal_tab": { + "title": "Aktuelles Terminal schließen", + "description": "Schließt den aktuellen Terminal-Tab, wenn das Terminal fokussiert ist" + }, + "toggle_aux_panel": { + "title": "Rechtes Panel umschalten", + "description": "Zeigt das Zusatzinformations-Panel an oder blendet es aus" + }, + "new_conversation": { + "title": "Neue Konversation", + "description": "Erstellt einen neuen Konversations-Tab im aktuellen Ordner" + }, + "open_folder": { + "title": "Ordner öffnen", + "description": "Öffnet die Ordnerauswahl und den Ordner in einem neuen Fenster" + }, + "open_settings": { + "title": "Einstellungen öffnen", + "description": "Öffnet das Einstellungsfenster" + }, + "close_current_tab": { + "title": "Aktuellen Tab schließen", + "description": "Schließt den aktuellen Konversations- oder Dateitab" + }, + "close_all_file_tabs": { + "title": "Alle Dateitabs schließen", + "description": "Schließt alle geöffneten Dateitabs, wenn der Dateibereich aktiv ist" + }, + "next_tab": { + "title": "Nächster Tab", + "description": "Zum nächsten Konversations- oder Datei-Tab wechseln" + }, + "prev_tab": { + "title": "Vorheriger Tab", + "description": "Zum vorherigen Konversations- oder Datei-Tab wechseln" + }, + "send_message": { + "title": "Nachricht senden", + "description": "Die aktuelle Nachricht im Eingabefeld senden" + }, + "newline_in_message": { + "title": "Zeilenumbruch einfügen", + "description": "Einen Zeilenumbruch im Eingabefeld einfügen" + }, + "toggle_custom_style": { + "title": "Eigenen Stil aussetzen/fortsetzen", + "description": "Notausstieg: schaltet alle eigenen Farben und CSS aus und wieder ein" + } + } + }, + "SkillsSettings": { + "title": "Skills", + "description": "Wähle links einen Skill aus. Rechts wird standardmäßig eine Markdown-Vorschau angezeigt; wechsle zum Bearbeiten, um zu ändern und zu speichern.", + "loadingAgents": "Agenten mit Skill-Unterstützung werden geladen...", + "emptyNoManageableAgents": "Keine Agenten für Skill-Verwaltung verfügbar.", + "managedTarget": "Verwaltetes Ziel", + "selectAgentPlaceholder": "Agent auswählen", + "searchPlaceholder": "Nach Name / ID / Pfad suchen...", + "skillsList": "Skill-Liste", + "loadingSkills": "Skills werden geladen...", + "agentNotSupported": "Der aktuelle Agent unterstützt keine Skill-Verwaltung.", + "emptySkills": "Noch keine Skills. Klicke auf „Neuer Skill“, um einen zu erstellen.", + "newSkillTitle": "Neuer Skill", + "skillInfo": "Skill-Info", + "skillIdPlaceholder": "skill-id (Buchstaben/Zahlen/-/_/.)", + "skillsDirectoryWithPath": "Skill-Verzeichnis: {path}", + "skillsDirectoryNeedId": "Skill-Verzeichnis: Skill-ID eingeben, um den vollständigen Pfad zu erzeugen", + "markdownContent": "Markdown-Inhalt", + "editingStatus": "Bearbeiten", + "previewStatus": "Vorschau", + "contentPlaceholder": "Markdown-Inhalt des Skills eingeben...", + "metadataTitle": "Skill-Metadaten", + "onlyYamlMetadata": "Dieser Skill enthält nur YAML-Metadaten.", + "emptyContentHint": "Noch kein Inhalt. Klicke auf „Bearbeiten“, um zu starten.", + "loadingSkill": "Skill wird geladen...", + "emptyNoAgents": "Kein verfügbarer Agent.", + "noSelectionHint": "Wählen Sie links einen Skill oder klicken Sie auf „Neuer Skill“, um einen zu erstellen.", + "systemBadge": "System", + "systemHint": "Integrierter CLI-Skill · schreibgeschützt", + "scope": { + "global": "Global", + "folder": "Ordner", + "selectFolderPlaceholder": "Ordner auswählen", + "noFolders": "Keine Ordner gefunden", + "pickFolderHint": "Wählen Sie einen Ordner, um dessen Skills anzuzeigen." + }, + "actions": { + "preview": "Vorschau", + "edit": "Bearbeiten", + "openInWindow": "In neuem Fenster öffnen", + "delete": "Löschen", + "deleting": "Wird gelöscht...", + "refresh": "Aktualisieren", + "newSkill": "Neuer Skill", + "reset": "Zurücksetzen", + "save": "Speichern", + "saving": "Wird gespeichert...", + "cancel": "Abbrechen" + }, + "deleteDialog": { + "title": "Skill löschen", + "confirm": "Aktuellen Skill löschen? Diese Aktion kann nicht rückgängig gemacht werden.", + "confirmWithNamePrefix": "Skill", + "confirmWithNameSuffix": "löschen? Diese Aktion kann nicht rückgängig gemacht werden." + }, + "toasts": { + "loadFailed": "Skill konnte nicht geladen werden", + "openFolderFailed": "Ordner konnte nicht geöffnet werden", + "noSkillDirectory": "Kein verfügbares Skill-Verzeichnis für den aktuellen Agenten gefunden", + "nameRequired": "Skill-Name darf nicht leer sein", + "updated": "Skill aktualisiert", + "created": "Skill erstellt", + "saveFailed": "Skill konnte nicht gespeichert werden", + "deleted": "Skill gelöscht", + "deleteFailed": "Skill konnte nicht gelöscht werden" + }, + "templates": { + "gemini": "---\nname: example-skill\ndescription: Describe when this skill should be used.\n---\n\n# Skill Name\n\nInstructions for the agent when this skill is active.\n\n## Workflow\n\n1. Add actionable step one.\n2. Add actionable step two.\n", + "openCode": "---\nname: example-skill\ndescription: Describe when this skill should be used.\n---\n\n# Purpose\n\nDescribe what this skill helps with.\n\n# Steps\n\n1. Add actionable step one.\n2. Add actionable step two.\n", + "openClaw": "---\nname: example-skill\ndescription: Describe when this skill should be used.\nuser-invocable: true\ndisable-model-invocation: false\n---\n\n# Purpose\n\nDescribe what this skill helps with.\n\n# Instructions\n\n1. Add actionable instruction one.\n2. Add actionable instruction two.\n", + "default": "---\nname: example-skill\ndescription: Describe when this skill should be used.\n---\n\n# Skill: example-skill\n\n## When to use\n\n- Describe trigger conditions.\n\n## Instructions\n\n1. Add actionable instruction one.\n2. Add actionable instruction two.\n" + } + }, + "McpSettings": { + "loading": "Wird geladen...", + "summary": { + "missingCommand": "(fehlender Befehl)", + "missingUrl": "(fehlende URL)" + }, + "protocol": { + "stdio": "Stdio" + }, + "errors": { + "selectInstallProtocol": "Bitte ein Installationsprotokoll auswählen", + "fieldRequired": "{field} ist erforderlich", + "fieldNeedsBoolean": "{field} muss true oder false sein", + "fieldNeedsNumber": "{field} muss eine Zahl sein", + "fieldNeedsInteger": "{field} muss eine Ganzzahl sein", + "fieldInvalidJson": "{field} enthält ungültiges JSON: {message}", + "fieldOutOfRange": "Der Wert von {field} liegt außerhalb des erlaubten Bereichs", + "jsonEmpty": "{name} darf nicht leer sein", + "jsonInvalid": "{name} ist kein gültiges JSON: {message}", + "jsonMustBeObject": "{name} muss ein JSON-Objekt sein", + "specMustBeObject": "Die MCP-Konfiguration muss ein JSON-Objekt sein.", + "missingType": "Der Konfiguration fehlt das Feld type. Bitte stdio, http (Aliase: streamable-http, streamableHttp) oder sse angeben.", + "unsupportedType": "Nicht unterstützter MCP-Typ {type}. Unterstützt: stdio, http (Aliase: streamable-http, streamableHttp), sse.", + "codexEntryUnsupportedType": "Codex-MCP-Eintrag {id} hat den nicht unterstützten Typ {type}. Unterstützt: stdio, http (Aliase: streamable-http, streamableHttp), sse.", + "unsupportedTransportType": "Nicht unterstützter Transport-Typ {type}. Unterstützt: http (Aliase: streamable-http, streamableHttp), sse.", + "stdioCommandRequired": "stdio-MCPs benötigen ein nicht leeres Feld command.", + "remoteUrlRequired": "Remote-MCPs benötigen ein nicht leeres Feld url.", + "appsRequired": "Mindestens eine Ziel-App auswählen." + }, + "jsonNames": { + "localConfig": "MCP-Konfiguration", + "installConfig": "Installationskonfiguration" + }, + "toasts": { + "uninstalled": "MCP deinstalliert", + "uninstallFailed": "Deinstallation fehlgeschlagen: {message}", + "selectAtLeastOneApp": "Bitte mindestens eine Ziel-App auswählen", + "saveSuccess": "Gespeichert", + "saveFailed": "Speichern fehlgeschlagen: {message}", + "installed": "{name} installiert", + "installFailed": "Installation fehlgeschlagen: {message}", + "serverIdRequired": "Server-ID ist erforderlich", + "serverIdExists": "Server-ID \"{id}\" existiert bereits. Bearbeiten Sie den vorhandenen Eintrag oder wählen Sie einen anderen Namen.", + "created": "MCP erstellt" + }, + "installDialog": { + "title": "MCP-Installation bestätigen", + "descriptionWithName": "{name} in lokale Konfiguration installieren.", + "description": "Ziel-Apps für die Installation auswählen.", + "protocol": "Protokoll", + "selectProtocol": "Protokoll auswählen", + "parameters": "Konfigurationsparameter", + "booleanPlaceholder": "Bitte true/false auswählen", + "selectOneValue": "Wert auswählen", + "targetApps": "Ziel-Apps" + }, + "actions": { + "cancel": "Abbrechen", + "confirmInstall": "Installation bestätigen", + "installing": "Installieren", + "uninstall": "Deinstallieren", + "uninstalling": "Deinstallieren", + "viewDetails": "Details anzeigen", + "save": "Speichern", + "saving": "Speichern", + "install": "Installieren", + "refresh": "Aktualisieren", + "newMcp": "Neuer MCP", + "create": "Erstellen", + "creating": "Wird erstellt..." + }, + "tabs": { + "local": "Lokales MCP", + "market": "MCP-Marktplatz" + }, + "local": { + "filterPlaceholder": "Lokales MCP filtern...", + "loadFailed": "Laden fehlgeschlagen: {message}", + "empty": "Kein lokales MCP erkannt.", + "description": "Die lokale MCP-Konfiguration kann direkt bearbeitet und gespeichert werden.", + "enabledApps": "Aktivierte Apps", + "configJson": "MCP-Konfiguration (JSON)", + "draftTitle": "Neuer MCP", + "draftDescription": "Geben Sie eine Server-ID und Konfiguration an, um einen lokalen MCP-Server zu erstellen.", + "serverIdLabel": "Server-ID", + "serverIdPlaceholder": "Server-ID (z. B. my-mcp)", + "typeHint": "Unterstützte Typen: stdio, http (Aliase: streamable-http, streamableHttp), sse. env wird nur von stdio verwendet; für Remote-MCPs Auth-Tokens über headers übermitteln.", + "envOnRemoteWarning": "env wurde in einem Remote-MCP erkannt. Nur stdio verwendet env; Remote-MCPs übermitteln Auth-Tokens über headers, sodass env beim Speichern ignoriert wird." + }, + "market": { + "selectMarketplace": "Marktplatz auswählen", + "searchPlaceholder": "MCP suchen...", + "searchFailed": "Suche fehlgeschlagen: {message}", + "loadingList": "MCP-Liste wird geladen...", + "empty": "Keine MCP-Ergebnisse.", + "loadingDetail": "Marktplatzdetails werden geladen...", + "detailLoadFailed": "Details konnten nicht geladen werden: {message}", + "owner": "Inhaber: {owner}", + "namespace": "Namensraum: {namespace}", + "defaultInstallProtocol": "Standard-Installationsprotokoll", + "currentOptionParameterCount": "Anzahl der Parameter der aktuellen Option: {count}", + "installConfigDescription": "Installationskonfiguration (JSON, vor der Installation bearbeitbar; Änderungen überschreiben das Protokoll-/Parameterformular)", + "selectLeftToView": "Wähle links ein Marktplatz-MCP aus, um Details anzuzeigen." + }, + "badges": { + "verified": "Verifiziert", + "remote": "Remote", + "hasHomepage": "Hat Homepage", + "uses": "{count} Nutzungen", + "deployed": "Bereitgestellt", + "notDeployed": "Nicht bereitgestellt" + }, + "selectLeftMcp": "Wähle links ein MCP aus." + }, + "AcpAgentSettings": { + "title": "Agent SDK-Verwaltung", + "description": "Verwalten Sie Agent-SDK-Verbindung, Aktivierungsstatus, Umgebungsvariablen, Konfigurationsverwaltung und Versions-Preflight-Infos zentral an einem Ort.", + "loadingAgents": "Agentenliste wird geladen...", + "agentList": "Agentenliste", + "emptyNoAgent": "Keine verfügbaren Agenten.", + "configManagement": "Konfigurationsverwaltung", + "envVars": "Umgebungsvariablen", + "hostTools": { + "label": "Dateien und Befehle vom Agenten selbst ausführen lassen", + "description": "codeg übernimmt Dateizugriffe und Terminalbefehle nicht mehr, sodass der Agent sie im eigenen Prozess ausführt – nur dort greifen seine eigene Sandbox und seine Berechtigungsregeln. Auch das Delegieren an andere Agenten wird deaktiviert, da dieselbe Arbeit sonst wieder über codeg liefe. codeg fügt selbst keine Sandbox hinzu; aktivieren Sie dies also nur, wenn im Agenten eine konfiguriert ist." + }, + "nativeJsonConfig": "Natives JSON-Config", + "modelHintDefault": "Leer lassen, um das System-Standardmodell zu verwenden.", + "generalConfigDescriptionClaude": "Unterstützt schnelle Konfiguration von API-URL, API-Key und Claude-Modellen und synchronisiert mit der nativen JSON-Konfiguration.", + "generalConfigDescriptionDefault": "Unterstützt wichtige Konfigurationseingaben (API URL, API Key, Model) und native JSON-Konfigurationsverwaltung.", + "multiAgent": { + "title": "Multi-Agent-Zusammenarbeit", + "description": "Erlaubt aktiven Agenten, Teilaufgaben an andere Agenten zu delegieren.", + "enable": "Delegation aktivieren", + "enableHint": "Wenn deaktiviert, wird das Tool delegate_to_agent im MCP-Toolkatalog des Agenten ausgeblendet.", + "withheldByHostTools": "{agents} erhalten die Delegationswerkzeuge nicht: Ihr agentenspezifischer Schalter „Dateien und Befehle vom Agenten selbst ausführen lassen“ ist aktiv.", + "selfInitiate": "Allow spawn without @", + "selfInitiateHint": "When on, an agent may start a listed sub-agent on its own. An @ mention is still always honored. When off, only an @ mention starts a sub-agent.", + "depthLimit": "Maximale Delegationstiefe", + "depthHint": "Zulässiger Bereich: {min}–{max}. Begrenzt, wie tief eine Delegationskette (Root → Kind → Enkel …) rekursieren kann.", + "completedCacheLabel": "Cache abgeschlossener Ergebnisse (MB)", + "completedCacheHint": "In-Memory-Cache abgeschlossener Subagent-Ergebnisse, der nur gehalten wird, solange die Delegationssitzung läuft, und beim Ende dieser Sitzung automatisch freigegeben wird. Bei Überschreitung dieses Budgets werden die ältesten Ergebnisse zuerst aus dem Speicher verworfen (weiterhin in der eigenen Sitzung des Subagenten einsehbar); 0 = unbegrenzt (wird trotzdem beim Sitzungsende freigegeben).", + "save": "Speichern", + "saving": "Wird gespeichert…", + "saved": "Delegationseinstellungen gespeichert", + "saveFailed": "Delegationseinstellungen konnten nicht gespeichert werden", + "loadFailed": "Delegationseinstellungen konnten nicht geladen werden: {detail}", + "tabGeneral": "Allgemein", + "tabAgentDefaults": "Subagent-Standards", + "agentDefaultsDescription": "Pro-Agent-Überschreibungen, die angewendet werden, wenn die Multi-Agent-Zusammenarbeit einen Subagenten für einen Delegationsaufruf startet. Die hier gezeigten Optionen stammen aus einer Live-Abfrage – Ihre Auswahl ist exakt das, was der Agent akzeptiert.", + "probing": "Verfügbare Optionen vom Agenten werden geladen…", + "probeFailed": "Optionen konnten nicht geladen werden: {detail}", + "retry": "Erneut versuchen", + "noConfigAvailable": "Dieser Agent hat keine konfigurierbaren Optionen.", + "modeLabel": "Modus", + "agentDefaultHint": "Agent-Standard: {value}", + "defaultOptionLabel": "Standard ({value})" + }, + "actions": { + "dragSort": "Zum Neuordnen ziehen", + "dragSortAgent": "{name} zum Neuordnen ziehen", + "refreshCheck": "Prüfung aktualisieren", + "refreshCheckAgent": "Prüfung für {name} aktualisieren", + "clickEnable": "Klicken, um {name} zu aktivieren", + "clickDisable": "Klicken, um {name} zu deaktivieren", + "install": "Installieren", + "upgrade": "Aktualisieren", + "uninstall": "Deinstallieren", + "uninstalling": "Wird deinstalliert...", + "saveEnvVars": "Umgebungsvariablen speichern", + "saving": "Speichern...", + "saveGrokConfig": "Grok-Konfiguration speichern", + "saveCodexConfig": "Codex-Konfiguration speichern", + "saveGeminiConfig": "Gemini-Konfiguration speichern", + "saveOpenCodeConfig": "OpenCode-Konfiguration speichern", + "saveOpenClawConfig": "OpenClaw-Konfiguration speichern", + "saveConfigManagement": "Konfigurationsverwaltung speichern", + "saveCurrentProvider": "Aktuellen Provider speichern", + "showApiKey": "API-Key anzeigen", + "hideApiKey": "API-Key ausblenden", + "showKey": "Schlüssel anzeigen", + "hideKey": "Schlüssel ausblenden", + "showToken": "Token anzeigen", + "hideToken": "Token ausblenden", + "cancel": "Abbrechen", + "delete": "Löschen", + "deleting": "Löschen...", + "confirmDelete": "Löschen bestätigen", + "confirmUninstall": "Deinstallation bestätigen", + "saveClineConfig": "Cline-Konfiguration speichern", + "saveHermesConfig": "Hermes-Konfiguration speichern", + "saveCodeBuddyConfig": "CodeBuddy-Konfiguration speichern", + "saveKimiCodeConfig": "Kimi-Code-Konfiguration speichern", + "customInstall": "Benutzerdefinierte Installation", + "saveKimiCodeRawConfig": "Save config.toml", + "saveDeepSeekConfig": "DeepSeek-Konfiguration speichern", + "diagnose": "Diagnose" + }, + "status": { + "enabled": "Aktiviert", + "disabled": "Deaktiviert", + "unchecked": "Nicht geprüft", + "agentEnabledAria": "{name} aktiviert", + "agentEnabledSwitch": "{name} Aktivierungsschalter" + }, + "preflight": { + "count": "Preflight-Elemente: {count}", + "notRun": "Prüfungen wurden noch nicht ausgeführt." + }, + "grok": { + "configDescription": "Konfiguriere Grok hier. Die folgenden Steuerelemente – Berechtigungsmodus, Reasoning-Aufwand, ein optionales benutzerdefiniertes Modell (eigener Endpunkt) und die Verdichtung – werden in ~/.grok/config.toml zusammengeführt, wobei deine anderen Schlüssel und Kommentare erhalten bleiben. Die Anmeldung nutzt deinen XAI_API_KEY oder `grok login`. Weitere Schlüssel bleiben unter „Erweitert“ bearbeitbar.", + "permissionModeLabel": "Berechtigungsmodus", + "permissionDefault": "Jedes Mal fragen", + "permissionAcceptEdits": "Bearbeitungen automatisch genehmigen", + "permissionAuto": "Intelligente Auto-Genehmigung", + "permissionAlwaysApprove": "Immer zulassen", + "reasoningEffortLabel": "Denkaufwand", + "effortLow": "Niedrig (schneller)", + "effortMedium": "Mittel (ausgewogen)", + "effortHigh": "Hoch", + "effortXhigh": "Maximal", + "optionDefault": "Standard verwenden", + "authTitle": "Authentifizierung", + "authMode": "Authentifizierungsmethode", + "authModeApiKey": "XAI-API-Schlüssel", + "authModeApiKeyHint": "Authentifiziere dich mit einem XAI_API_KEY aus der xAI-Konsole – für nicht-interaktive oder Headless-Läufe. Wird in der Umgebung dieses Agenten gespeichert.", + "authModeCustom": "Benutzerdefinierter Endpunkt", + "authModeCustomHint": "Verwende einen eigenen Endpunkt (BYO): Definiere unten ein benutzerdefiniertes Modell mit eigener Basis-URL und eigenem API-Schlüssel. Es wird zum Standardmodell von Grok.", + "subscriptionHint": "Melde dich mit `grok login` an (SuperGrok / X Premium+). Es wird kein API-Schlüssel gespeichert.", + "loginHint": "Führe dies in einem Terminal aus, um dich anzumelden, und öffne dann diese Einstellungen erneut:", + "commandCopied": "Befehl in die Zwischenablage kopiert", + "copyCommand": "Befehl kopieren", + "authKeyConfigured": "XAI_API_KEY ist konfiguriert.", + "authKeyMissing": "Kein XAI_API_KEY festgelegt.", + "advancedToggle": "Erweitert (rohe config.toml)", + "configTomlNative": "config.toml (nativ)", + "configTomlHint": "Wird wortwörtlich als gesamte ~/.grok/config.toml gespeichert. Ungültiges TOML wird abgelehnt, sodass ein Tippfehler deine Datei nie abschneidet.", + "configTomlPlaceholder": "# Andere Schlüssel als die Steuerelemente oben, z. B.\n# [mcp_servers.*], [cli], [permission]-Regeln.", + "customModelTitle": "Benutzerdefiniertes Modell (eigener Endpunkt)", + "customModelHint": "Richte Grok auf einen benutzerdefinierten oder selbst gehosteten Endpunkt. codeg schreibt einen `[model.*]`-Block pro Modell und legt es als Standard fest. Lasse die Modell-ID leer, um es zu entfernen.", + "customModelIdLabel": "Modell-ID", + "customModelIdPlaceholder": "grok-4.5", + "customModelIdHint": "Wird als `[model.*]`-Block registriert und als Modellname an die API gesendet; außerdem als `[models].default` gesetzt.", + "customBaseUrlLabel": "Basis-URL", + "customBaseUrlPlaceholder": "https://api.x.ai/v1 (Standard)", + "customApiBackendLabel": "API-Backend", + "backendResponses": "Responses", + "backendChatCompletions": "Chat Completions", + "backendMessages": "Messages (Anthropic)", + "customApiKeyLabel": "API-Schlüssel", + "customApiKeyHint": "Inline in `[model.*].api_key` gespeichert, nur für diesen Endpunkt.", + "customContextWindowLabel": "Kontextfenster (Tokens)", + "customContextWindowHint": "Optional. Steuert den Zeitpunkt der automatischen Verdichtung; leer lassen für den Standard des Endpunkts.", + "autoCompactLabel": "Schwellenwert für Auto-Verdichtung (%)", + "autoCompactHint": "Verdichtet die Unterhaltung, wenn die Kontextnutzung diesen Prozentsatz erreicht (Grok-Standard 85). Wird in `[session]` geschrieben." + }, + "cursor": { + "configDescription": "Konfiguriere Cursor hier. Wähle eine Authentifizierungsmethode – offizielles Abo (Browser-Anmeldung) oder einen Cursor-API-Schlüssel für Headless-/Servermaschinen – wähle dann ein Modell und bearbeite die Berechtigungsregeln und die Sandbox des CLI. codeg schreibt sie in ~/.cursor/cli-config.json, gemeinsam mit dem cursor-agent-CLI.", + "authTitle": "Authentifizierung", + "authChecking": "Prüfe…", + "authNotInstalled": "cursor-agent ist nicht installiert", + "authLoggedIn": "Angemeldet", + "authNotLoggedIn": "Nicht angemeldet", + "loginHint": "Führe dies im Terminal aus, um dich mit deinem Cursor-Konto anzumelden (ein Browserfenster öffnet sich), und klicke danach auf Aktualisieren:", + "apiKeyLabel": "Cursor-API-Schlüssel", + "apiKeyPlaceholder": "Schlüssel von cursor.com/dashboard", + "apiKeyHint": "CURSOR_API_KEY – ein Cursor-Dashboard-Kontoschlüssel, Alternative zur Browser-Anmeldung für Headless-/Servermaschinen. Kein Drittanbieter- oder OpenAI-Schlüssel.", + "modelTitle": "Standardmodell", + "loadModels": "Modelle laden", + "modelsUnavailable": "Modellliste nicht verfügbar", + "modelHint": "Wird der CLI beim Sitzungsstart als --model übergeben. Auf Standard lassen, damit Cursor wählt.", + "permissionsTitle": "Berechtigungen & Sandbox", + "permissionsDescription": "Visueller Editor für die Berechtigungsregeln der CLI (cli-config.json). Erlaubte Regeln laufen ohne Rückfrage; verweigerte werden immer blockiert.", + "permissionModeLabel": "Berechtigungsmodus", + "permissionModeDefault": "Vor der Ausführung fragen (Standard)", + "permissionModeForce": "Run Everything (--force)", + "permissionModeHint": "Run Everything startet Sitzungen mit --force: Alle Tool-Aufrufe werden ohne Rückfrage automatisch erlaubt, außer Deny-Regeln (eine Organisationsrichtlinie kann dies auf Allow-Regeln beschränken). Gilt für neue Sitzungen.", + "optionDefault": "Standard (nicht gesetzt)", + "sandboxLabel": "Sandbox", + "sandboxEnabled": "Aktiviert", + "sandboxDisabled": "Deaktiviert", + "allowRulesLabel": "Erlauben-Regeln", + "denyRulesLabel": "Verweigern-Regeln", + "addRule": "Regel hinzufügen", + "rulesSyntaxHint": "Regelsyntax: Shell(Befehl), Read(Pfad/Glob), Write(Pfad/Glob), WebFetch(Domain), Mcp(Server:Tool) — Deny-Regeln haben immer Vorrang.", + "saveConfig": "Konfiguration speichern", + "advancedToggle": "Erweitert: rohe cli-config.json", + "advancedHint": "Die komplette ~/.cursor/cli-config.json. Speichern schreibt die Datei unverändert; die strukturierten Steuerelemente oben werden stattdessen zusammengeführt.", + "saveRawConfig": "Datei speichern", + "authMode": "Authentifizierungsmethode", + "subscriptionHint": "Mit deinem Cursor-Konto anmelden und Cursors Modelle verwenden.", + "customApiKeyRequired": "Ein Cursor-API-Schlüssel ist erforderlich.", + "authModeApiKey": "Cursor-API-Schlüssel (Headless/Server)", + "authModeApiKeyHint": "Mit einem Cursor-Konto-API-Schlüssel aus dem Cursor-Dashboard authentifizieren (für Headless-/Servermaschinen). Das ist ein Cursor-Kontoschlüssel, kein Drittanbieter-/OpenAI-Endpunkt – cursor-agent kommuniziert nur mit dem Cursor-Backend. Um einen codex-/OpenAI-kompatiblen Endpunkt zu nutzen, verwende stattdessen den Codex-Agenten.", + "modelPickerPlaceholder": "Modelle suchen…", + "modelNoMatch": "Kein passendes Modell", + "modelsNeedAuth": "Melde dich an, um die Modellliste zu laden.", + "modelDefaultBadge": "Standard" + }, + "deepseek": { + "configManagement": "DeepSeek-Harness-Konfiguration", + "configDescription": "Endpunkt und Schlüssel sind Umgebungsvariablen, die deepseek-acp beim Start liest. Modell und Denkstufe sind Auswahlfelder pro Sitzung — sie werden im Eingabefeld gewählt.", + "baseUrlLabel": "API-Endpunkt", + "baseUrlHint": "Leer lassen für den offiziellen Endpunkt. Gilt für Sitzungen, die nach dem Speichern starten – eine laufende Sitzung muss neu verbinden.", + "baseUrlInvalid": "Vollständige http(s)-URL ohne Query-String eingeben, zum Beispiel https://api.deepseek.com", + "apiKeyLabel": "API-Schlüssel", + "apiKeyHint": "Wird dem Agenten als DEEPSEEK_API_KEY übergeben. Eine Umgebungsvariable hat Vorrang vor der Zugangsdatendatei – lass das Feld leer, wenn du dich im Terminal anmeldest." + }, + "codex": { + "configDescription": "Unterstützt schnelle Konfiguration von API-URL, API-Key, Modellname und reasoning effort und synchronisiert mit `auth.json` / `config.toml`.", + "authMode": "Authentifizierungsmodus", + "chatgptSubscription": "Offizielles Abonnement", + "chatgptSubscriptionHint": "Mit offiziellem ChatGPT-Abonnement anmelden, kein API Key erforderlich", + "apiKeyHint": "Mit API Key zu OpenAI oder kompatiblen API-Diensten verbinden", + "selectProvider": "Provider auswählen", + "modelName": "Modellname", + "selectReasoningEffort": "Reasoning Effort auswählen", + "enableWebsocket": "WebSocket aktivieren", + "enableWebsocketAria": "WebSocket für Codex Provider aktivieren", + "enableSkills": "Skills aktivieren", + "enableSkillsAria": "Skills für Codex aktivieren", + "enableFast": "Fast aktivieren", + "enableFastAria": "Fast-Servicestufe für Codex aktivieren", + "sandboxGroupTitle": "Sandbox und Freigaben", + "sandboxGroupHint": "Wird in die globale ~/.codex/config.toml geschrieben und gilt daher auch für codex-CLI- und IDE-Sitzungen. Es sind Thread-Standardwerte: Sie gelten für Turns, die codex selbst startet (/goal, /review, /compact). Normale Eingaben nutzen die Freigabe-Voreinstellung des Eingabefelds. Änderungen greifen nach einem Neustart der Sitzung.", + "sandboxShadowedWarning": "config.toml setzt default_permissions, daher löst codex Berechtigungen über dieses Profil auf und ignoriert sandbox_mode vollständig. Entferne default_permissions, um die Optionen unten zu nutzen.", + "sandboxPermissionsTableWarning": "config.toml definiert [permissions]-Profile, aber kein default_permissions — damit verweigert codex den Start. Setze es im Rohtext-Editor unten.", + "approvalPolicyLabel": "Freigaberichtlinie", + "approvalPolicyUnset": "Nicht gesetzt (codex-Standard: auf Anfrage)", + "approvalPolicy_on-request": "Auf Anfrage – das Modell entscheidet, wann es nachfragt", + "approvalPolicy_untrusted": "Nicht vertrauenswürdig – nur bekannt sichere Lesebefehle laufen ohne Nachfrage", + "approvalPolicy_never": "Nie – keinerlei Freigabeabfragen", + "approvalPolicy_granular": "Granular – pro Abfragetyp festlegen", + "approvalPolicyUntrustedAcpWarning": "Für „untrusted“ gibt es unter den drei Freigabe-Voreinstellungen des ACP-Adapters keine Entsprechung, daher fallen codeg-Sitzungen auf „auf Anfrage“ zurück: Das Modell entscheidet dann selbst, wann es fragt, und Befehle, die die Sandbox ohnehin erlaubt, fragen nicht mehr nach. Schränke stattdessen unten den Sandbox-Modus ein.", + "granularHint": "Aus bedeutet, dass Anfragen dieser Art automatisch abgelehnt statt angezeigt werden.", + "granular_sandbox_approval": "Rechteerweiterung für Shell-Befehle", + "granular_rules": "Abfragen aus Execpolicy-Regeln", + "granular_skill_approval": "Abfragen bei Skill-Skripten", + "granular_request_permissions": "Abfragen des request_permissions-Tools", + "granular_mcp_elicitations": "MCP-Elicitation-Abfragen", + "sandboxModeLabel": "Sandbox-Modus", + "sandboxModeUnset": "Nicht gesetzt (vertrauenswürdige Ordner fallen auf Workspace-Schreibzugriff zurück)", + "sandboxMode_read-only": "Nur lesen", + "sandboxMode_workspace-write": "Workspace-Schreibzugriff", + "sandboxMode_danger-full-access": "Vollzugriff (keine Sandbox)", + "sandboxModeHint": "Unter Windows wird Workspace-Schreibzugriff auf Nur-Lesen herabgestuft, sofern die experimentelle Windows-Sandbox von codex nicht aktiviert ist.", + "sandboxModeSeedsPresetHint": "codeg leitet daraus auch die anfängliche Freigabe-Voreinstellung der Sitzung ab — anders als die Freigaberichtlinie wirkt es also auch auf normale Anfragen. Die im Eingabefeld gewählte Voreinstellung hat weiterhin Vorrang.", + "writableRootsLabel": "Zusätzliche beschreibbare Ordner", + "writableRootsHint": "Ein absoluter Pfad pro Zeile, zusätzlich zum Arbeitsverzeichnis.", + "sandboxRootsRelativeError": "Muss ein absoluter Pfad sein – codex löst relative Angaben unter ~/.codex auf: {path}", + "networkAccessLabel": "Netzwerkzugriff erlauben", + "excludeTmpdirLabel": "TMPDIR von den beschreibbaren Wurzeln ausschließen", + "excludeSlashTmpLabel": "/tmp von den beschreibbaren Wurzeln ausschließen", + "authJsonNative": "auth.json (nativ)", + "configTomlNative": "config.toml (nativ)", + "loginButton": "Mit ChatGPT anmelden", + "loginRequesting": "Login-Code wird angefordert...", + "loginStep1": "Öffnen Sie die folgende URL in Ihrem Browser:", + "loginStep2": "Geben Sie den folgenden Code ein:", + "loginPolling": "Warte auf Autorisierung...", + "loginCancel": "Abbrechen", + "loginSuccess": "Erfolgreich angemeldet, Konfiguration gespeichert!", + "loginFailed": "Anmeldung fehlgeschlagen: {message}", + "loginRetry": "Erneut versuchen", + "loginCodeCopied": "Code kopiert", + "loggedIn": "Konto angemeldet", + "loginRelogin": "Erneut anmelden / Konto wechseln", + "loginTimeout": "Anmeldung abgelaufen, bitte erneut versuchen", + "loginSaveFailed": "Anmeldung erfolgreich, aber Konfiguration konnte nicht gespeichert werden" + }, + "gemini": { + "authConfig": "Gemini-Auth-Konfiguration", + "authConfigDescription": "Ausgerichtet an den Gemini CLI-Authentifizierungsdokumenten, mit Unterstützung für benutzerdefinierten Endpoint, Google-Login, Gemini API Key und Vertex AI (ADC / Servicekonto / API Key).", + "authMode": "Auth-Modus", + "selectAuthMode": "Auth-Modus auswählen", + "viewAuthDoc": "Auth-Dokumentation anzeigen", + "mode": { + "custom": "Benutzerdefinierter Endpoint", + "loginGoogle": "Google-Login (OAuth)", + "vertexServiceAccount": "Vertex AI (Servicekonto)" + }, + "hint": { + "custom": "API URL, API Key und Modell ausfüllen; wird auf GOOGLE_GEMINI_BASE_URL / GEMINI_API_KEY / GEMINI_MODEL abgebildet.", + "loginGoogle": "Gemini zuerst im Terminal ausführen und Google-Login abschließen; API key ist nicht erforderlich.", + "geminiApiKey": "Beim Verwenden der Gemini API GEMINI_API_KEY eintragen.", + "vertexAdc": "gcloud ADC verwenden; GOOGLE_CLOUD_PROJECT und GOOGLE_CLOUD_LOCATION werden empfohlen.", + "vertexServiceAccount": "Pfad zur Servicekonto-JSON in GOOGLE_APPLICATION_CREDENTIALS setzen.", + "vertexApiKey": "Beim Verwenden eines Vertex AI API Keys GOOGLE_API_KEY eintragen." + } + }, + "openCode": { + "configManagement": "OpenCode-Konfigurationsverwaltung", + "configDescription": "An OpenCode-`provider`-Schema ausgerichtet, unterstützt Multi-Provider-Verwaltung und bidirektionale Synchronisierung mit nativen JSON-Dateien.", + "providerManagement": "Provider-Verwaltung", + "providerCount": "{count} Provider", + "addProvider": "Provider hinzufügen", + "emptyProvider": "Noch keine benutzerdefinierten Provider. Klicke auf Benutzerdefinierten Provider hinzufügen, um einen zu erstellen.", + "providerEnabledState": "{providerId} Aktivierungsstatus", + "selectProviderNpm": "provider.npm auswählen", + "modelManagement": "Modellverwaltung", + "modelCount": "{count} Modelle", + "modelDescription": "Ausgerichtet an OpenCode `provider.models`. Schnellverwaltung unterstützt derzeit `name` / `id`; andere erweiterte Felder bleiben erhalten und können unten im nativen JSON bearbeitet werden.", + "addModel": "Modell hinzufügen", + "emptyModel": "Noch kein Modell vorhanden. model id eingeben und dann auf „Modell hinzufügen“ klicken.", + "modelId": "Modell-ID", + "modelName": "Modellname", + "deleteModel": "Modell {modelId} löschen", + "nativeJsonConfig": "OpenCode Native JSON-Konfiguration", + "mainModel": "Hauptmodell", + "smallModel": "Kleines Modell", + "noMatchingModels": "Keine passenden Modelle", + "connectProvider": "Provider verbinden", + "connectedProviders": "Verbundene Provider", + "noConnectedProviders": "Noch keine Katalog-Provider verbunden.", + "advancedProviderConfig": "Benutzerdefinierte Provider", + "customProviderConfigHint": "OpenAI-kompatible Endpunkte, die du selbst definierst – ein Provider-Block in opencode.json, mit dem API-Key in auth.json.", + "addCustomProvider": "Benutzerdefinierten Provider hinzufügen", + "disconnect": "Trennen", + "editConfig": "Bearbeiten", + "customBadge": "Benutzerdefiniert", + "authKindApi": "API-Schlüssel", + "authKindOauth": "OAuth", + "authKindNone": "Keine Anmeldedaten", + "connect": { + "title": "Provider verbinden", + "description": "Wähle einen Provider aus dem models.dev-Katalog. Anmeldedaten werden in der auth.json-Datei von OpenCode gespeichert.", + "pick": "Provider", + "search": "Provider suchen…", + "loading": "Katalog wird geladen…", + "catalogLabel": "models.dev-Katalog", + "modelsAvailable": "{count} Modelle verfügbar", + "getKey": "API-Schlüssel holen", + "oauthApiKeyNote": "Dieser Provider unterstützt auch die Browser-Anmeldung über opencode auth login. Die Browser-Anmeldung kommt bald — füge vorerst einen API-Schlüssel ein.", + "apiKey": "API-Schlüssel", + "apiKeyHint": "Wird in auth.json gespeichert, nie in opencode.json.", + "baseUrlOptional": "Basis-URL überschreiben (optional)", + "providerId": "Provider-ID", + "displayName": "Anzeigename", + "modelsList": "Modelle (eins pro Zeile)", + "modelsHint": "Modell-IDs, die der Endpunkt akzeptiert.", + "action": "Verbinden", + "editTitle": "Provider bearbeiten", + "editDescription": "Aktualisiere den API-Schlüssel oder die Basis-URL dieses Providers.", + "saveAction": "Speichern" + }, + "customProvider": { + "title": "Benutzerdefinierten Provider hinzufügen", + "description": "Definiere einen OpenAI-kompatiblen Endpunkt. Der API-Key wird in auth.json gespeichert, der Provider-Block in opencode.json.", + "action": "Provider hinzufügen", + "idInCatalog": "{providerId} ist ein bekannter Provider – verbinde ihn stattdessen über Provider verbinden." + }, + "refreshCatalog": "Katalog aktualisieren", + "reasoningBadge": "Reasoning", + "contextWindow": "Kontextfenster", + "permissions": { + "title": "Berechtigungen", + "description": "Legt fest, welche Aktionen einfach laufen, welche vorher nachfragen und welche blockiert werden. Wird in den permission-Block von opencode.json geschrieben und mit dem Speichern unten übernommen.", + "docsLink": "Dokumentation zu Berechtigungen", + "unparsableConfig": "Das native JSON unten ist ungültig, deshalb pausiert der visuelle Editor. Korrigiere das JSON, um fortzufahren.", + "invalidBlock": "Der permission-Block hat eine Form, die codeg nicht kennt. Bearbeite ihn im nativen JSON unten oder beginne mit Zurücksetzen neu.", + "orderingUnsafe": "Eine Wildcard-Regel steht hinter konkreten Tools, deshalb wendet OpenCode sie auch auf diese an – die Zeilen unten sind nicht das, was tatsächlich gilt. Reihenfolge korrigieren schiebt jede Wildcard nur wieder an den Anfang ihres Bereichs, ohne einen Wert zu ändern.", + "orderingUnsafeManual": "Eine Regel wird von einem späteren, allgemeineren Muster verdeckt, OpenCode wendet sie also nie an – die Zeilen unten sind nicht das, was tatsächlich gilt. Für zwei überlappende Muster gibt es keine eine richtige Reihenfolge; sortiere sie im nativen JSON so, dass das allgemeinere zuerst steht.", + "fixOrder": "Reihenfolge korrigieren", + "agentOverrides": "Diese Agenten überschreiben Berechtigungen und werden zuletzt angewendet, gewinnen also gegen alles hier: {agents}. Bearbeite sie im nativen JSON unten oder schalte die automatische Annahme ein, um sie zu löschen.", + "legacyTools": "Die veraltete tools-Map auf oberster Ebene verweigert ein Tool. OpenCode führt sie mit den Berechtigungen zusammen, sie gilt also über allem hier Gezeigten. Bearbeite sie im nativen JSON unten oder schalte die automatische Annahme ein, um sie zu löschen.", + "autoAcceptTitle": "Alle Berechtigungen automatisch annehmen", + "autoAcceptHint": "Jeder Tool-Aufruf – Shell-Befehle, Dateiänderungen, Pfade außerhalb des Projekts – läuft ohne Rückfrage. Beim Einschalten ersetzt eine einzige Alles-erlauben-Regel die Einstellungen pro Tool unten, und die Overrides einzelner Agenten sowie veraltete tools-Schalter, die sonst weiter blockieren würden, werden gelöscht.", + "globalLabel": "Globaler Standard", + "globalHint": "Die Regel *: gilt für alles, was die Tools unten nicht überschreiben.", + "actionUnset": "Nicht gesetzt (OpenCode-Standard)", + "actionInherit": "Standard übernehmen ({action})", + "actionAllow": "Erlauben", + "actionAsk": "Nachfragen", + "actionDeny": "Verweigern", + "perToolTitle": "Berechtigungen pro Tool", + "reset": "Zurücksetzen", + "ruleCount": "Regeln: {count}", + "rulesToggle": "Feingranulare Regeln für {tool}", + "rulesHint": "Wird gegen die Tool-Eingabe geprüft, die letzte Übereinstimmung gewinnt – schreibe die weiten Muster also zuerst. * passt auf beliebig viele Zeichen, ? auf genau eines, und ein führendes ~ wird zu deinem Home-Verzeichnis.", + "noRules": "Noch keine feingranularen Regeln.", + "addRule": "Regel hinzufügen", + "deleteRule": "Regel {pattern} löschen", + "duplicateRule": "Dieses Muster gibt es bereits.", + "blankRule": "Eine Regel braucht ein Muster – zum Entfernen das Papierkorb-Symbol nutzen.", + "customKeys": "Weitere Berechtigungsschlüssel in der Datei", + "customKeyHint": "Kein eingebautes OpenCode-Tool – bleibt unverändert erhalten.", + "keys": { + "bash": "Shell-Befehle ausführen, geprüft am geparsten Befehl", + "edit": "Alle Dateiänderungen: edit, write und patch", + "read": "Dateien lesen, geprüft am Pfad", + "external_directory": "Pfade außerhalb des Projektarbeitsverzeichnisses erreichen", + "task": "Subagenten starten, geprüft am Subagenten-Typ", + "skill": "Skills laden, geprüft am Skill-Namen", + "glob": "Dateien finden, geprüft am Glob-Muster", + "grep": "Dateiinhalte durchsuchen, geprüft am Muster", + "list": "Verzeichnisinhalte auflisten", + "webfetch": "Eine URL abrufen", + "websearch": "Im Web suchen", + "lsp": "LSP-Abfragen ausführen", + "todowrite": "Die To-do-Liste schreiben", + "question": "Dir eine Frage stellen", + "doom_loop": "Löst aus, wenn sich derselbe Aufruf dreimal mit gleicher Eingabe wiederholt" + } + } + }, + "openClaw": { + "gatewayConfig": "Gateway-Konfiguration", + "gatewayDescription": "OpenClaw-Gateway-Verbindung konfigurieren. Unterstützt lokales oder entferntes Gateway.", + "gatewayUrlHint": "Leer lassen, um gateway.remote.url aus der lokalen openclaw-Konfiguration zu verwenden.", + "gatewayTokenPlaceholder": "Gateway-Auth-Token", + "gatewayTokenHint": "Wenn möglich token-file statt Klartext-Token verwenden; über openclaw CLI konfigurieren.", + "sessionKeyHint": "Optional. Gateway-Session-Key angeben; leer lassen für automatische Zuweisung einer isolierten Session." + }, + "hermes": { + "configManagement": "Hermes-Konfiguration", + "configDescription": "Hermes verwaltet seine eigenen Anmeldedaten in ~/.hermes/.env und die Einstellungen in ~/.hermes/config.yaml. Wähle einen Anbieter und lege dann den API-Schlüssel und das Modell fest – codeg schreibt beide Dateien für dich.", + "providerLabel": "Anbieter", + "providerHint": "Der Anbieter legt fest, welche API-Schlüssel-Variable und welchen model.provider Hermes verwendet. OAuth-Anbieter werden über die Terminal-Einrichtung unten konfiguriert.", + "groupApiKey": "Anbieter mit API-Schlüssel", + "groupOauth": "OAuth-Anbieter", + "groupAws": "AWS", + "apiKeyHint": "Wird in ~/.hermes/.env gespeichert. Er wird niemals in den Prozess eingeschleust – Hermes liest ihn aus seiner eigenen Konfiguration.", + "modelName": "Modell", + "oauthHint": "Dieser Anbieter verwendet OAuth. Führe die Einrichtung unten aus, um dich im Terminal zu authentifizieren.", + "awsHint": "Bedrock verwendet deine AWS-Anmeldedaten (Umgebung oder gemeinsame Konfiguration). Lege oben die Modell-ID fest und konfiguriere den AWS-Zugriff in deiner Umgebung.", + "unsupportedProvider": "Dieser Anbieter lässt sich nicht über strukturierte Felder bearbeiten. Verwende den config.yaml-Editor unten oder die Terminal-Einrichtung.", + "setupTitle": "Selbstverwaltete Einrichtung", + "setupHint": "Die interaktive Einrichtung von Hermes benötigt ein Terminal. Starte sie unten oder kopiere den Befehl, um sie selbst auszuführen.", + "runSetup": "Hermes-Einrichtung ausführen", + "configureModel": "Modell konfigurieren", + "openConfigFolder": "~/.hermes öffnen", + "copyCommand": "Befehl kopieren", + "commandCopied": "Befehl in die Zwischenablage kopiert", + "advancedTitle": "Erweitert: config.yaml bearbeiten", + "rawConfigHint": "Bearbeite ~/.hermes/config.yaml direkt. Das Speichern hier überschreibt die Datei wortwörtlich.", + "saveRawConfig": "config.yaml speichern" + }, + "codebuddy": { + "configManagement": "CodeBuddy-Konfiguration", + "configDescription": "CodeBuddy authentifiziert sich mit einem API-Schlüssel. Builds für Festlandchina erfordern zudem die Umgebung „China (internal)“; iOA-Builds verwenden „iOA“. Der internationale Build lässt sie ungesetzt.", + "apiKeyLabel": "API-Schlüssel", + "apiKeyHint": "Wird als CODEBUDDY_API_KEY für diesen Agenten gespeichert. Alternativ kannst du dich mit der CodeBuddy-CLI im Terminal anmelden.", + "apiKeyHintSelfHosted": "Wird als CODEBUDDY_API_KEY für diesen Agenten gespeichert. Verwende den von deiner privaten Bereitstellung ausgestellten Schlüssel.", + "environmentLabel": "Umgebung", + "environmentHint": "Legt CODEBUDDY_INTERNET_ENVIRONMENT fest. Festlandchina muss „China (internal)“ verwenden; der internationale Build lässt es ungesetzt.", + "envOverseas": "International (Standard)", + "envChina": "China (internal)", + "envIoa": "iOA", + "envSelfHosted": "Selbst gehostet (private Bereitstellung)", + "baseUrlLabel": "Bereitstellungs-URL", + "baseUrlPlaceholder": "https://codebuddy.your-company.com", + "baseUrlHint": "Wird als CODEBUDDY_BASE_URL gespeichert und richtet CodeBuddy auf deinen privaten Endpunkt. Bei Selbsthosting bleibt die Netzwerkumgebung (CODEBUDDY_INTERNET_ENVIRONMENT) ungesetzt.", + "baseUrlInvalid": "Gib eine gültige http(s)-URL ein.", + "loginHint": "Kein API-Schlüssel? Führe „codebuddy“ im Terminal aus, um dich stattdessen mit deinem Tencent-Konto anzumelden." + }, + "kimiCode": { + "configManagement": "Kimi-Code-Konfiguration", + "configDescription": "`kimi acp` akzeptiert nur ein gespeichertes Login-Token, daher schreibt codeg einen verwalteten Provider in ~/.kimi-code/config.toml und legt lokal ein Gate-Token an – die Inferenz läuft weiterhin über deinen eigenen Schlüssel.", + "statusUnconfigured": "Noch nicht konfiguriert", + "statusDirty": "Nicht gespeicherte Änderungen", + "summaryLabel": "Aktiv", + "gateReadyApiKey": "API-Schlüssel in config.toml geschrieben", + "gateReadyLogin": "Mit einem Kimi-Konto angemeldet", + "revealConfig": "Im Ordner anzeigen", + "envOverrideWarning": "{keys} ist gesetzt und hat Vorrang vor config.toml. Beim Speichern hier wird die Variable entfernt.", + "authModeLabel": "Authentifizierungsmethode", + "authModeApiKey": "API-Schlüssel", + "authModeLogin": "Kimi-Konto-Anmeldung (Abo)", + "authModeApiKeyHint": "Schreibt einen verwalteten Provider in config.toml und legt das Gate-Token an, damit Sitzungen geöffnet werden können.", + "loginHint": "Führe `kimi login` im Terminal aus, um dich mit einem Kimi-Abo-Konto anzumelden. codeg speichert nichts und nutzt Kimis eigene Anmeldung. Speichern hier entfernt codegs API-Schlüssel-Gate-Token.", + "credentialTitle": "Zugangsdaten", + "interfaceTypeLabel": "Provider-Typ", + "interfaceTypeHint": "Das Provider-Protokoll, das Kimi spricht (`type` in config.toml). Für einen Moonshot-/platform.kimi.com-Schlüssel Kimi / Moonshot wählen.", + "endpointLabel": "Endpunkt", + "endpointCustom": "Benutzerdefiniert (OpenAI-kompatibel)", + "endpointHint": "International = api.moonshot.ai; China (platform.kimi.com-Schlüssel) = api.moonshot.cn. Benutzerdefiniert zeigt auf einen beliebigen OpenAI-kompatiblen Endpunkt.", + "regionInternational": "International (api.moonshot.ai)", + "regionChina": "China (api.moonshot.cn)", + "baseUrlLabel": "Basis-URL", + "baseUrlHint": "Leer lassen, um den Standardwert des Provider-SDK zu verwenden.", + "apiKeyLabel": "API-Schlüssel", + "apiKeyHint": "Wird in ~/.kimi-code/config.toml geschrieben und für die Inferenz verwendet. Von platform.kimi.com oder platform.kimi.ai.", + "vertexProjectLabel": "GCP-Projekt (GOOGLE_CLOUD_PROJECT)", + "vertexLocationLabel": "GCP-Region (GOOGLE_CLOUD_LOCATION)", + "vertexHint": "Vertex AI nutzt Google Application Default Credentials – führe `gcloud auth application-default login` aus (kein API-Schlüssel nötig).", + "modelTitle": "Modell", + "modelLabel": "Modell", + "modelHint": "Die Modell-ID, die in config.toml geschrieben wird. Über „Testen & Modelle laden“ siehst du, worauf dein Schlüssel tatsächlich zugreifen kann.", + "maxContextLabel": "Maximale Kontextgröße", + "maxContextHint": "Vom Kimi-Schema vorgeschrieben: Fehlt der Wert, verwirft Kimi den gesamten Modellblock und jede Anfrage bleibt ohne Antwort. Standard 262144.", + "fetchModels": "Testen & Modelle laden", + "fetchModelsOk": "Schlüssel funktioniert – {count} Modelle verfügbar", + "fetchModelsEmpty": "Schlüssel funktioniert, es wurden aber keine Modelle zurückgegeben", + "fetchModelsFailed": "Test fehlgeschlagen", + "fetchModelsNeedsKey": "Gib zuerst einen API-Schlüssel und einen Endpunkt ein", + "modelNotInList": "Dieses Modell ist nicht in der Liste, auf die dein Schlüssel zugreifen kann – Kimi scheitert mit „Modell nicht gefunden“.", + "reasoningTitle": "Reasoning", + "reasoningEnableLabel": "Aktivieren", + "reasoningDescription": "Kimi zeigt den „Thinking“-Auswähler im Eingabefeld nur, wenn das Modell eine Reasoning-Fähigkeit deklariert – codeg schreibt sie hier. Gilt ab neuen Sitzungen.", + "effortsLabel": "Angebotene Stufen", + "effortsHint": "Diese Stufen erscheinen im „Thinking“-Auswähler. Kimi reicht die Stufe unverändert an den Provider weiter – wähle also Werte, die dein Modell akzeptiert.", + "effortsEmptyHint": "Ohne ausgewählte Stufe bleibt im Eingabefeld nur ein einfacher Off/On-Schalter.", + "effortsCustomPlaceholder": "Weitere Stufe hinzufügen", + "effortsAdd": "Hinzufügen", + "defaultEffortLabel": "Standardstufe", + "defaultEffortAuto": "Kimi entscheiden lassen", + "alwaysThinkingLabel": "Das Modell denkt immer nach – Off-Eintrag aus dem Auswähler entfernen", + "fixErrorsFirst": "Korrigiere zuerst die markierten Felder", + "errorModelRequired": "Modell ist erforderlich", + "errorMaxContextRequired": "Maximale Kontextgröße ist erforderlich", + "errorMaxContextInvalid": "Muss eine positive ganze Zahl sein", + "errorApiKeyRequired": "API-Schlüssel ist erforderlich", + "errorApiKeyInvalid": "Der API-Schlüssel darf keine Zeilenumbrüche enthalten", + "errorBaseUrlRequired": "Basis-URL ist erforderlich", + "errorBaseUrlInvalid": "Muss mit http:// oder https:// beginnen", + "errorVertexProjectRequired": "GCP-Projekt ist erforderlich", + "errorDefaultEffortUnlisted": "Wähle eine der oben ausgewählten Stufen", + "advancedTitle": "Erweitert", + "authTypeLabel": "Ablageort der Zugangsdaten", + "authTypeApiKey": "Inline api_key", + "authTypeEnv": "env-Untertabelle des Providers", + "authTypeHint": "Wo der API-Schlüssel innerhalb von config.toml abgelegt wird.", + "rawEditorLabel": "config.toml direkt bearbeiten", + "rawEditorWarning": "Speichern hier überschreibt die gesamte Datei wortwörtlich und ersetzt die strukturierten Einstellungen oben.", + "rawEditorPlaceholder": "[providers.codeg]\ntype = \"kimi\"\nbase_url = \"https://api.moonshot.cn/v1\"\napi_key = \"sk-...\"" + }, + "authModeOfficialSubscription": "Offizielles Abonnement", + "authModeCustomEndpoint": "Benutzerdefinierter Endpunkt", + "authModeCustomEndpointHint": "API-URL und API-Key manuell für einen benutzerdefinierten Endpunkt konfigurieren.", + "authModeModelProvider": "Modellanbieter", + "modelProvider": "Modellanbieter", + "modelProviderHint": "API-URL, API-Key und Modell eines konfigurierten Modellanbieters verwenden.", + "selectModelProvider": "Modellanbieter auswählen", + "noModelProviderAvailable": "Kein Modellanbieter für diesen Agent konfiguriert. Gehen Sie zu den Modellanbieter-Einstellungen, um einen hinzuzufügen.", + "claude": { + "authMode": "Authentifizierungsmodus", + "officialSubscription": "Offizielles Abonnement", + "officialSubscriptionHint": "Offizielles Anthropic-Abonnement verwenden, kein API-Key erforderlich.", + "mainModel": "Hauptmodell", + "reasoningModel": "Reasoning-Modell (thinking)", + "haikuDefaultModel": "Standard-Haiku-Modell", + "sonnetDefaultModel": "Standard-Sonnet-Modell", + "opusDefaultModel": "Standard-Opus-Modell", + "customModelOption": "Benutzerdefinierte Modell-ID", + "customModelOptionName": "Name des benutzerdefinierten Modells", + "customModelOptionDescription": "Beschreibung des benutzerdefinierten Modells", + "customModelOptionHint": "Fügt der Modellauswahl von Claude einen einzelnen benutzerdefinierten Eintrag hinzu (z. B. ein Modell hinter einem benutzerdefinierten Gateway/Proxy). Name und Beschreibung sind optionale Anzeigeangaben.", + "effortLevel": "Reasoning-Stufe", + "effortLevelDefault": "Standardstufe", + "effortLevel_low": "Niedrig", + "effortLevel_medium": "Mittel", + "effortLevel_high": "Hoch", + "effortLevel_xhigh": "Sehr Hoch", + "sendAttributionHeader": "Attributions-/Abrechnungskennung an die API senden", + "sendAttributionHeaderAria": "Attributions-/Abrechnungskennung von Claude Code an die API senden", + "disableNonessentialTraffic": "Telemetrie oder überflüssige Netzwerkanfragen deaktivieren", + "disableNonessentialTrafficAria": "Telemetrie oder überflüssige Netzwerkanfragen von Claude Code deaktivieren" + }, + "dialogs": { + "confirmDeleteProvider": "Provider {providerId} löschen?", + "confirmDeleteProviderDescription": "OpenCode-Konfiguration und auth JSON werden zusammen aktualisiert. Diese Aktion kann nicht rückgängig gemacht werden.", + "confirmUninstall": "{name} deinstallieren?", + "confirmUninstallDescription": "Dadurch wird die lokal installierte Version entfernt. Eine Neuinstallation ist später möglich.", + "customInstallTitle": "{name} benutzerdefiniert installieren", + "customInstallDescription": "Geben Sie die zu installierende Version ein. Dies installiert neu und ersetzt die aktuell installierte Version.", + "customInstallVersionLabel": "Versionsnummer", + "customInstallInvalid": "Geben Sie eine gültige Versionsnummer ein, z. B. 1.2.3.", + "customInstallSubmit": "Installieren" + }, + "errors": { + "windowsFileLocked": "Die Dateien von {name} werden von einer laufenden Sitzung verwendet, daher kann Windows sie nicht ersetzen. Schließe alle {name}-Sitzungen und versuche es erneut.", + "nativeJsonMustBeObject": "Native JSON-Konfiguration muss ein Objekt sein", + "nativeJsonInvalid": "Formatfehler in nativer JSON-Konfiguration: {message}", + "openCodeAuthMustBeObject": "OpenCode auth.json muss ein JSON-Objekt sein", + "openCodeAuthInvalid": "Formatfehler in OpenCode auth.json: {message}", + "authMustBeObject": "auth.json muss ein JSON-Objekt sein", + "authInvalid": "Formatfehler in auth.json: {message}", + "providerIdPattern": "Provider-ID unterstützt nur Buchstaben, Zahlen, Unterstrich, Punkt und Bindestrich", + "providerExists": "Provider {providerId} existiert bereits", + "modelIdPattern": "Model-ID unterstützt nur Buchstaben, Zahlen, Unterstrich, Punkt, Doppelpunkt und Bindestrich", + "modelExists": "Model {modelId} existiert bereits" + }, + "warnings": { + "nativeJsonRecoveredStructured": "Native JSON-Konfiguration ist ungültig; auf strukturierte Konfiguration zurückgesetzt", + "nativeJsonRecoveredOpenCode": "Native JSON-Konfiguration ist ungültig; auf OpenCode-strukturierte Konfiguration zurückgesetzt", + "openCodeAuthRecovered": "OpenCode auth.json ist ungültig; auf Standardkonfiguration zurückgesetzt", + "authRecoveredStructured": "auth.json ist ungültig; auf strukturierte Konfiguration zurückgesetzt" + }, + "toasts": { + "agentActionCompleted": "{name} {action} abgeschlossen", + "agentActionFailed": "{name} {action} fehlgeschlagen", + "localVersion": "Lokale Version: {version}", + "installCompletedVersionLater": "Installation abgeschlossen, Version wird bei der nächsten Prüfung aktualisiert", + "uninstallCompleted": "Deinstallation von {name} abgeschlossen", + "uninstallFailed": "Deinstallation von {name} fehlgeschlagen", + "localVersionRemoved": "Lokale Version entfernt", + "saveAgentOrderFailed": "Speichern der Agent-Reihenfolge fehlgeschlagen", + "saveAgentSwitchFailed": "Speichern des Agent-Schalters fehlgeschlagen", + "saveEnvFailed": "Speichern der Umgebungsvariablen fehlgeschlagen", + "grokSaved": "Grok-Konfiguration gespeichert", + "saveGrokNativeFailed": "Grok-Nativkonfiguration konnte nicht gespeichert werden", + "saveGrokApiKeyFailed": "Einstellungen gespeichert, aber der API-Schlüssel konnte nicht gespeichert werden", + "cursorSaved": "Cursor-Konfiguration gespeichert", + "saveCursorConfigFailed": "Cursor-Konfiguration konnte nicht gespeichert werden", + "codexSaved": "Codex-Konfiguration gespeichert", + "saveCodexNativeFailed": "Speichern der nativen Codex-Konfiguration fehlgeschlagen", + "geminiSaved": "Gemini-Konfiguration gespeichert", + "saveGeminiFailed": "Speichern der Gemini-Konfiguration fehlgeschlagen", + "providerDeleted": "Provider {providerId} gelöscht", + "providerDeleteFailed": "Löschen von Provider {providerId} fehlgeschlagen", + "providerSaved": "Provider {providerId} gespeichert", + "saveProviderFailed": "Speichern von Provider {providerId} fehlgeschlagen", + "openCodeConfigSynced": "OpenCode-Konfiguration und auth JSON wurden synchronisiert.", + "openCodeSaved": "OpenCode-Konfiguration gespeichert", + "saveOpenCodeFailed": "Speichern der OpenCode-Konfiguration fehlgeschlagen", + "openClawSaved": "OpenClaw-Konfiguration gespeichert", + "saveOpenClawFailed": "Speichern der OpenClaw-Konfiguration fehlgeschlagen", + "configSaved": "Konfiguration gespeichert", + "configSavedHint": "Bestehende Sitzungen müssen neu geöffnet werden, damit die Änderungen wirksam werden", + "saveConfigManagementFailed": "Speichern der Konfigurationsverwaltung fehlgeschlagen", + "clineSaved": "Cline-Konfiguration gespeichert", + "saveClineFailed": "Cline-Konfiguration konnte nicht gespeichert werden", + "hermesSaved": "Hermes-Konfiguration gespeichert", + "saveHermesFailed": "Hermes-Konfiguration konnte nicht gespeichert werden", + "codeBuddySaved": "CodeBuddy-Konfiguration gespeichert", + "saveCodeBuddyFailed": "CodeBuddy-Konfiguration konnte nicht gespeichert werden", + "kimiCodeSaved": "Kimi-Code-Konfiguration gespeichert", + "saveKimiCodeFailed": "Speichern der Kimi-Code-Konfiguration fehlgeschlagen", + "deepseekSaved": "DeepSeek-Konfiguration gespeichert", + "saveDeepSeekFailed": "DeepSeek-Konfiguration konnte nicht gespeichert werden", + "modelProviderRequired": "Bitte wählen Sie vor dem Speichern einen Modellanbieter aus.", + "affectedRunningSessions": "{count, plural, one {# laufende Sitzung muss zum Anwenden neu verbunden werden} other {# laufende Sitzungen müssen zum Anwenden neu verbunden werden}}", + "providerConnected": "{providerId} verbunden", + "connectFailed": "Verbinden von {providerId} fehlgeschlagen", + "providerDisconnected": "{providerId} getrennt", + "disconnectFailed": "Trennen von {providerId} fehlgeschlagen", + "catalogRefreshed": "Katalog aktualisiert – {count} Provider", + "catalogRefreshFailed": "Aktualisieren des Katalogs fehlgeschlagen", + "piSaved": "Pi-Konfiguration gespeichert", + "savePiFailed": "Pi-Konfiguration konnte nicht gespeichert werden", + "piRuntimeSaved": "Pi-Laufzeit gespeichert", + "savePiRuntimeFailed": "Pi-Laufzeit konnte nicht gespeichert werden", + "piBinaryInstalled": "pi installiert", + "piBinaryInstallFailed": "pi-Installation fehlgeschlagen", + "piBinaryUninstalled": "pi deinstalliert", + "piBinaryUninstallFailed": "pi-Deinstallation fehlgeschlagen", + "savePiTrustFailed": "Speichern des Arbeitsbereich-Vertrauens fehlgeschlagen" + }, + "version": { + "statusLabel": "Versionsstatus", + "notInstalled": "Nicht installiert", + "remoteLocal": "Remote: {remoteVersion} · Lokal: {localVersion}", + "localOnly": "Lokal: {localVersion}", + "localInstalled": "{versionText}. Installiert.", + "platformUnsupported": "{versionText}. Aktuelle Plattform unterstützt diesen Agenten nicht.", + "uvxNotReady": "{versionText}. Die uv-Laufzeit ist nicht installiert – installieren Sie sie über die uv-Prüfung unten, um diesen Agenten zu verwenden.", + "clickInstall": "{versionText}. Rechts auf Installieren klicken.", + "localUnrecognized": "{versionText}. Lokale Version ist nicht vergleichbar; zum Überschreiben bitte Upgrade versuchen.", + "upgradeAvailable": "{versionText}. Upgrade verfügbar.", + "remoteUnavailable": "{versionText}. Remote-Version ist derzeit nicht verfügbar.", + "latest": "{versionText}. Bereits aktuell." + }, + "adapter": { + "label": "ACP-Adapter", + "badge": "ACP-Adapter", + "badgeHint": "Für diesen Agenten installiert Codeg ein ACP-Adapterpaket, nicht die Hersteller-CLI. Beide sind unabhängig und teilen sich dieselbe Konfiguration.", + "learnMore": "Mehr erfahren", + "missingWithNative": "Deine eigene {nativeLabel} wurde unter {nativePath} gefunden. Codeg spricht mit Agenten über ACP, und diese CLI beherrscht kein ACP — deshalb braucht Codeg ein separates Adapterpaket, {adapterPackage}, gepflegt vom Agent-Client-Protocol-Projekt (ursprünglich Zed). Es bringt seine eigene Laufzeit mit, verändert oder ersetzt deinen Befehl {nativeCmd} nie und liest dasselbe {configDir} — Anmeldung und Einstellungen bleiben erhalten. Unten installieren.", + "missing": "Codeg spricht mit Agenten über ACP, und die {nativeLabel} beherrscht kein ACP — deshalb braucht Codeg ein separates Adapterpaket, {adapterPackage}, gepflegt vom Agent-Client-Protocol-Projekt (ursprünglich Zed). Es bringt seine eigene Laufzeit mit, die CLI {nativeCmd} ist also nicht Voraussetzung; hast du sie bereits, koexistieren beide und teilen sich Anmeldung und Einstellungen in {configDir}. Unten installieren.", + "readyWithNative": "Der Adapter {adapterCmd} ist installiert — ihn startet Codeg, nicht dein eigenes {nativeCmd} unter {nativePath}. Es sind getrennte Pakete, die koexistieren, und beide lesen {configDir}, Anmeldung und Einstellungen sind also gemeinsam.", + "ready": "Der Adapter {adapterCmd} ist installiert — ihn startet Codeg. Er bringt seine eigene Laufzeit mit, die {nativeLabel} wird also nicht benötigt; installierst du sie später, koexistieren beide und teilen sich {configDir}." + }, + "cline": { + "configDescription": "Konfigurieren Sie den Cline API-Anbieter und die Anmeldedaten. Einstellungen werden in ~/.cline/data/ gespeichert." + }, + "opencodePlugins": { + "title": "OpenCode-Plugins", + "declared": "Deklarierte Plugins", + "noPlugins": "Keine Plugins in opencode.json deklariert", + "status": { + "installed": "Installiert", + "missing": "Nicht installiert" + }, + "installAll": "Alle fehlenden installieren", + "pinVersions": "@latest-Versionen fixieren", + "install": "Installieren", + "uninstall": "Deinstallieren", + "refresh": "Aktualisieren", + "success": "Alle Plugins wurden erfolgreich installiert", + "failed": "Plugin-Vorgang fehlgeschlagen" + }, + "pi": { + "configManagement": "Pi-Konfiguration", + "configDescription": "Pi authentifiziert sich über den API-Schlüssel deines Modellanbieters. Der Schlüssel wird in ~/.pi/agent/auth.json und die Modellauswahl in settings.json geschrieben.", + "providerLabel": "Anbieter", + "modelLabel": "Modell", + "thinkingLabel": "Denken", + "thinking": { + "off": "Aus", + "low": "Niedrig", + "medium": "Mittel", + "high": "Hoch", + "minimal": "Minimal", + "xhigh": "Sehr hoch" + }, + "apiKeyLabel": "API-Schlüssel", + "apiKeyHint": "Wird in ~/.pi/agent/auth.json für den ausgewählten Anbieter gespeichert.", + "apiKeySetPlaceholder": "•••••• (gespeichert – leer lassen zum Beibehalten)", + "saveConfig": "Pi-Konfiguration speichern", + "providerModelRequired": "Anbieter und Modell sind erforderlich", + "runtimeTitle": "Laufzeit", + "runtimeDescription": "Wähle, welches pi-Binary läuft. Standard verwenden oder auf deinen eigenen pi-Build verweisen.", + "modeDefault": "Standard-pi", + "modeDefaultHint": "Verwendet den integrierten pi-acp-Adapter mit dem pi in deinem PATH. pi installieren: npm install -g @earendil-works/pi-coding-agent", + "modeCustom": "Eigenes pi", + "modeCustomHint": "Führe deinen eigenen pi-Build, deine Installation oder einen Wrapper aus.", + "commandLabel": "pi-Befehl oder -Pfad", + "commandHint": "Ein absoluter Pfad, ein Befehlsname im PATH oder ein Wrapper-Skript (z. B. ./pi-test.sh eines Monorepos).", + "commandNotFound": "Befehl nicht gefunden", + "validate": "Prüfen", + "advanced": "Erweitert", + "configDirLabel": "Konfigurationsverzeichnis (PI_CODING_AGENT_DIR)", + "sessionDirLabel": "Sitzungsverzeichnis (PI_CODING_AGENT_SESSION_DIR)", + "flagsHint": "pi-acp leitet eigene pi-Flags (--approve, -e, …) nicht weiter – umhülle pi mit einem Skript und verweise den Befehl darauf.", + "customIncomplete": "Gib einen pi-Befehl zum Speichern ein", + "saveRuntime": "Laufzeit speichern", + "providerPlaceholder": "Anbieter auswählen", + "customProvider": "Eigener Anbieter…", + "providerIdLabel": "Anbieter-ID", + "apiProtocolLabel": "API-Protokoll", + "baseUrlLabel": "API-Endpunkt (Base URL)", + "customProviderHint": "Definiert einen Anbieter in ~/.pi/agent/models.json an Ihrem Endpunkt. Die meisten selbst gehosteten oder Proxy-Server nutzen openai-completions.", + "baseUrlRequired": "API-Endpunkt (Base URL) ist erforderlich", + "binaryTitle": "pi-Binärdatei (pi-coding-agent)", + "binaryDescription": "pi-acp führt diese pi-Binärdatei aus. Hier installieren oder pi-acp unten auf einen eigenen Build verweisen.", + "binaryInstalled": "Installiert", + "binaryMissing": "Nicht installiert", + "binaryChecking": "Wird geprüft…", + "installBinary": "pi installieren", + "installing": "Wird installiert…", + "recheck": "Erneut prüfen", + "configDirSkillsNote": "Mit einem benutzerdefinierten Konfigurationsverzeichnis gelten die in den Einstellungen verwalteten Skills, Experten und Office-Tools nicht für dieses pi — verwalte seine Skills direkt in diesem Ordner.", + "projectTrustTitle": "Projektvertrauen", + "projectTrustDescription": "Ordner, aus denen pi Projektdateien laden darf. In einem vertrauten Ordner führt das Repository seine .pi/extensions beim Start von pi aus. Die Entscheidung gilt für alle enthaltenen Ordner und auch, wenn du pi im Terminal startest.", + "projectTrustLoading": "Wird geladen…", + "projectTrustEmpty": "Noch keine Ordner entschieden.", + "projectTrustTrusted": "Vertraut", + "projectTrustDenied": "Nicht vertraut", + "projectTrustRevoke": "Widerrufen", + "reasoningTitle": "Reasoning", + "reasoningEnableLabel": "Aktivieren", + "reasoningDescription": "pi sendet einen Reasoning-Aufwand nur für ein Modell, das ihn deklariert — bei einem nicht deklarierten Modell werden alle Stufen auf Off begrenzt, sodass die Auswahl im Eingabefeld sofort zurückspringt. Wird in den Eintrag dieses Modells in models.json geschrieben.", + "levelsLabel": "Verfügbare Stufen", + "levelsHint": "Diese werden zu den Einträgen der Reasoning-Auswahl im Eingabefeld. Wähle die, die dein Endpunkt akzeptiert; jede hier nicht gelistete Stufe lehnt pi ab.", + "levelsEmptyError": "Wähle mindestens eine Stufe — ohne eine fällt pi auf Off zurück.", + "wireValuesTitle": "Erweitert: an den Anbieter gesendete Werte", + "wireValuesHint": "Leer lassen, um den Stufennamen unverändert zu senden. Setze einen Wert, wenn dein Endpunkt etwas anderes erwartet — Google-artige Backends erwarten LOW / HIGH.", + "defaultLevelUnlisted": "Diese Stufe steht nicht in der Liste oben — pi würde sie begrenzen." + }, + "addCustomAgent": "Eigenen Agenten hinzufügen", + "addCustomAgentHint": "Registriere jeden ACP-kompatiblen Agenten. Wähle einen aus der öffentlichen ACP-Registry oder füge seine Registry-Informationen ein.", + "customAgentFromRegistry": "ACP-Registry", + "customAgentManual": "Manuell", + "customAgentSearchPlaceholder": "Agenten suchen…", + "customAgentLoadingCatalog": "ACP-Registry wird geladen…", + "customAgentRetry": "Erneut versuchen", + "customAgentNoResults": "Keine passenden Agenten", + "customAgentAdd": "Hinzufügen", + "customAgentAlreadyAdded": "Hinzugefügt", + "customAgentUnsupportedPlatform": "Kein Build für diese Plattform verfügbar", + "customAgentAdded": "{name} hinzugefügt", + "customAgentIdLabel": "Registry-ID", + "customAgentNameLabel": "Anzeigename", + "customAgentVersionLabel": "Version", + "customAgentSpecLabel": "Distribution (JSON)", + "customAgentSpecHint": "Gleiche Form wie das distribution-Objekt der ACP-Registry: Kanäle npx, uvx und binary, oder ein kompletter Registry-Eintrag zum Einfügen. Bei npx/uvx ist cmd der vom Paket installierte Befehl — bei Weglassen aus dem Paketnamen abgeleitet, bei Abweichung also angeben. binary ist nach Plattformschlüssel gegliedert (diese Maschine: {platform}); cmd ist der Startpfad im Archiv, sha256 prüft optional den Download.", + "customAgentTemplateLabel": "Vorlagen", + "customAgentKindLabel": "Starten über", + "customAgentInvalidJson": "Kein gültiges JSON", + "customAgentNoDistribution": "Keine npx-, uvx- oder binary-Distribution gefunden", + "customAgentCancel": "Abbrechen", + "customAgentSave": "Agent hinzufügen", + "customAgentSaveChanges": "Änderungen speichern", + "customAgentEdit": "Agent bearbeiten", + "customAgentEditHint": "Name, Icon, Distribution und Skills-Deklarationen ändern. Die Agent-ID kann nicht geändert werden.", + "customAgentEditNotFound": "Benutzerdefinierter Agent {id} wurde nicht gefunden", + "customAgentSaved": "{name} gespeichert", + "customAgentVersionProbeLabel": "Versionsabfrage-Befehl (optional)", + "customAgentVersionProbeHint": "Befehl, der die lokal installierte Version ausgibt. Bleibt er leer, führt codeg den Agent-Befehl mit --version aus.", + "customAgentRemove": "Agent entfernen", + "customAgentRemoveHint": "Löscht die Agent-Definition. Bestehende Unterhaltungen behalten ihren Verlauf; der Agent lässt sich nur nicht mehr starten.", + "customAgentIconLabel": "Symbol (optional)", + "customAgentIconUpload": "Hochladen", + "customAgentIconReplace": "Ersetzen", + "customAgentIconClear": "Symbol entfernen", + "customAgentIconHint": "Wird beim Agenten gespeichert und funktioniert daher offline. Ohne Symbol wird ein farbiger Anfangsbuchstabe verwendet.", + "customAgentSkillsLabel": "Skills (gemeinsames .agents/skills)", + "customAgentSkillsHint": "Erklärt, dass dieser Agent den gemeinsamen .agents/skills-Speicher liest (globale und Projekt-Verzeichnisse), und nimmt ihn in alle Skill-Matrizen auf. Dort verknüpfte Skills sind für alle Agenten sichtbar, die diesen Speicher lesen.", + "customAgentSkillsDirLabel": "Dediziertes Skills-Verzeichnis", + "customAgentSkillsDirHint": "Absoluter Pfad des Verzeichnisses, aus dem dieser Agent Skills lädt — sein eigener Speicher, zusätzlich zum geteilten oder an dessen Stelle. ~ wird zum Home-Verzeichnis erweitert; verknüpfte Skills landen zuerst hier.", + "customAgentMcpLabel": "MCP-Unterstützung", + "customAgentMcpHint": "Übergibt den in codeg integrierten MCP-Begleitprozess beim Sitzungsstart an diesen Agenten — der Kanal hinter Delegation, Live-Feedback und Aufgaben-Tools. Für einen Agenten, der MCP-Server ablehnt und deshalb keine Verbindung aufbaut, ausschalten; die Änderung gilt ab der nächsten Verbindung.", + "customAgentIconNotAnImage": "Bitte eine Bilddatei auswählen.", + "customAgentIconTooLarge": "Das Symbol muss kleiner als {limit} KB sein.", + "customAgentIconReadFailed": "Dieses Bild konnte nicht gelesen werden.", + "customAgentRemoveConfirm": "{name} entfernen? Bestehende Unterhaltungen bleiben erhalten, der Agent lässt sich aber nicht mehr starten.", + "customAgentRemoveWithData": "Auch den aufgezeichneten Gesprächsverlauf löschen", + "customAgentRemoved": "{name} entfernt", + "customAgentBadge": "Eigen", + "customAgentNotLaunchable": "Dieser Agent kann hier nicht gestartet werden: {reason}" + }, + "SettingsPages": { + "agentsLoading": "Agent-Einstellungen werden geladen...", + "skillPacksLoading": "Skill-Pakete werden geladen…" + }, + "GeneralSettings": { + "loading": "Wird geladen...", + "sectionTitle": "Allgemein", + "sectionDescription": "Zentrale Einstellungen für das Standardterminal, die Rendering-Beschleunigung und die Multi-Agent-Delegation.", + "terminalTitle": "Standardterminal", + "terminalDescription": "Wählen Sie die Shell, die beim Öffnen neuer Terminal-Tabs über die Terminalleiste oder den Dateibaum verwendet wird. Agenten nutzen sie ebenfalls, wenn sie codeg um die Ausführung einer vollständigen Befehlszeile bitten.", + "terminalSystemDefault": "Systemstandard", + "terminalPowerShell7": "PowerShell 7 (pwsh)", + "terminalWindowsPowerShell": "Windows PowerShell", + "terminalCmd": "Eingabeaufforderung (cmd)", + "terminalSaveFailed": "Speichern der Terminaleinstellungen fehlgeschlagen: {message}", + "terminalShellCustom": "Benutzerdefinierter Pfad", + "terminalShellCustomPath": "Shell-Pfad", + "terminalShellCustomPlaceholder": "/usr/local/bin/fish", + "terminalShellCustomSave": "Speichern", + "terminalShellCustomHint": "Absoluten Pfad oder einen über PATH auflösbaren Namen angeben.", + "terminalShellNotInstalled": "nicht installiert", + "terminalShellNotFoundWarning": "Dieser Pfad existiert auf diesem Host nicht.", + "terminalCurrentShell": "Aktuell verwendet: {path}", + "renderingDescription": "Deaktivieren Sie die Hardwarebeschleunigung, wenn die App einen schwarzen Bildschirm oder Render-Fehler zeigt (häufig bei bestimmten AMD-GPUs oder integrierten Intel-GPUs). Wirkt sich nur auf die Windows-Desktop-Version aus.", + "disableHardwareAcceleration": "Hardwarebeschleunigung deaktivieren", + "renderingSaveFailed": "Render-Einstellungen konnten nicht gespeichert werden: {message}", + "restartRequired": "Gespeichert. Starten Sie die App neu, damit die Änderung wirksam wird.", + "restartNow": "Jetzt neu starten", + "restartFailed": "Neustart fehlgeschlagen: {message}", + "loadFailed": "Laden fehlgeschlagen: {message}" + }, + "LoginPage": { + "documentTitle": "Anmelden - codeg", + "brand": "Codeg", + "subtitle": "Gib dein Zugriffstoken ein, um dich mit der Desktop-App zu verbinden", + "tokenPlaceholder": "Zugriffstoken", + "connect": "Verbinden", + "connecting": "Verbinde...", + "helpText": "Das Token findest du in der Desktop-App unter Einstellungen → Webdienst", + "invalidToken": "Ungültiges Token. Bitte überprüfe es und versuche es erneut.", + "connectionFailed": "Verbindung fehlgeschlagen (HTTP {status})", + "networkError": "Verbindung zum Server nicht möglich" + }, + "CommitPage": { + "title": "Einchecken", + "invalidFolderId": "Ungültige Ordner-ID", + "loadingRepo": "Repository wird geladen..." + }, + "MergePage": { + "title": "Konflikte lösen", + "invalidFolderId": "Ungültige Ordner-ID", + "loadingRepo": "Repository wird geladen...", + "localVersion": "Lokal (Unsere)", + "result": "Ergebnis", + "remoteVersion": "Remote (Deren)", + "acceptLocal": "Lokal übernehmen", + "acceptRemote": "Remote übernehmen", + "markResolved": "Als gelöst markieren", + "abortMerge": "Abbrechen", + "completeMerge": "Merge abschließen", + "unresolvedConflicts": "Es gibt noch ungelöste Konfliktmarkierungen in dieser Datei", + "fileResolved": "Datei erfolgreich gelöst", + "allResolved": "Alle Konflikte gelöst", + "conflictFiles": "Konfliktdateien", + "loadingFile": "Datei wird geladen...", + "preparingMerge": "Merge wird vorbereitet...", + "selectFile": "Datei zum Lösen auswählen", + "noConflicts": "Keine Konfliktdateien", + "skipFile": "Überspringen", + "abortSuccess": "Vorgang abgebrochen", + "applyAllNonConflicting": "Alle konfliktfreien Änderungen anwenden", + "applyLeftNonConflicting": "Lokal anwenden", + "applyRightNonConflicting": "Remote anwenden" + }, + "ImportSessions": { + "title": "Lokale Sitzungen importieren", + "scanningTitle": "Lokale Agentensitzungen werden gescannt…", + "scanningHint": "Die lokalen Sitzungsspeicher der Agenten werden durchsucht. Bei großen Verläufen kann das etwas dauern. Bereits importierte Sitzungen werden dabei aktualisiert.", + "scanFailed": "Scan fehlgeschlagen", + "retry": "Erneut versuchen", + "rescan": "Neu scannen", + "empty": "Keine lokalen Sitzungen gefunden", + "emptyHint": "Auf diesem Rechner wurden keine Sitzungsspeicher von Agenten gefunden.", + "noMatches": "Keine Sitzungen entsprechen den aktuellen Filtern", + "searchPlaceholder": "Titel oder Pfad suchen…", + "allAgents": "Alle Agenten", + "onlyImportable": "Nur importierbare", + "selectAll": "Alle auswählen", + "clearSelection": "Leeren", + "expandAll": "Alle ausklappen", + "collapseAll": "Alle einklappen", + "summaryCounts": "{total} Sitzungen · {importable} importierbar · {folders} Ordner", + "noFolderSkipped": "{count} ohne Projektordner übersprungen", + "folderNew": "Neu", + "folderCounts": "{importable}/{total} importierbar", + "toggleFolderAria": "Alle importierbaren Sitzungen in {name} auswählen", + "toggleSessionAria": "Sitzung {title} auswählen", + "statusImported": "Importiert", + "statusDeleted": "Gelöscht", + "untitled": "Unbenannte Sitzung", + "messageCount": "{count} Nachrichten", + "selectedCount": "{count} ausgewählt", + "importSelected": "Auswahl importieren", + "importing": "Importiere…", + "close": "Schließen", + "doneTitle": "Import abgeschlossen", + "doneImported": "Importiert", + "doneUpdated": "Aktualisiert", + "doneSkipped": "Übersprungen", + "doneCreatedFolders": "Ordner erstellt", + "doneNotFound": "Nicht gefunden", + "doneFailed": "Fehlgeschlagen", + "continueImport": "Weiter importieren", + "toasts": { + "importFailed": "Import fehlgeschlagen: {message}" + } + }, + "Folder": { + "workspaceStatus": { + "degradedTitle": "Live-Aktualisierungen nicht verfügbar", + "degradedHint": "Beobachter konnte nicht gestartet werden (z. B. Berechtigung verweigert). Aktualisiere manuell, um Änderungen zu sehen.", + "retry": "Wiederholen", + "retrying": "Wird wiederholt..." + }, + "common": { + "all": "Alle", + "cancel": "Abbrechen", + "close": "Schließen", + "closeOthers": "Andere schließen", + "closeAll": "Alle schließen", + "confirm": "Bestätigen", + "save": "Speichern", + "delete": "Löschen", + "rename": "Umbenennen", + "loading": "Wird geladen...", + "refresh": "Aktualisieren", + "refreshing": "Aktualisierung...", + "create": "Erstellen", + "createAndSwitch": "Erstellen und wechseln", + "openFile": "Datei öffnen", + "viewDiff": "Diff anzeigen", + "push": "Pushen..." + }, + "statusLabels": { + "in_progress": "In Bearbeitung", + "pending_review": "Prüfung", + "completed": "Abgeschlossen", + "cancelled": "Abgebrochen" + }, + "sidebar": { + "title": "Konversationen", + "locateActiveConversation": "Aktive Konversation finden", + "expandAllGroups": "Alle Gruppen erweitern", + "collapseAllGroups": "Alle Gruppen einklappen", + "newConversation": "Neue Konversation", + "newConversationShort": "Neu", + "newChat": "Neue Konversation", + "search": "Suchen", + "noConversationsFound": "Keine Konversationen gefunden.", + "importLocalSessions": "Lokale Sitzungen importieren", + "importing": "Importiere...", + "error": "Fehler: {message}", + "completeAllSessions": "Alle Sitzungen abschließen", + "completeAllReviewTitle": "Alle Review-Sitzungen abschließen?", + "completeAllReviewDescription": "Dadurch werden alle {count, plural, one {# Sitzung} other {# Sitzungen}} im Review als abgeschlossen markiert.", + "completing": "Abschließen...", + "toasts": { + "importedSessions": "{imported, plural, one {# Sitzung} other {# Sitzungen}} importiert, {skipped} übersprungen", + "importedAndUpdated": "{imported, plural, one {# Sitzung} other {# Sitzungen}} importiert, {updated, plural, one {# Titel} other {# Titel}} aktualisiert, {skipped} übersprungen", + "updatedTitles": "{updated, plural, one {# Titel} other {# Titel}} aktualisiert, {skipped} übersprungen", + "noNewSessionsFound": "Keine neuen Sitzungen gefunden ({skipped} übersprungen)", + "importFailed": "Import fehlgeschlagen: {message}", + "reviewCompleted": "{count, plural, one {# Review-Sitzung} other {# Review-Sitzungen}} als abgeschlossen markiert", + "completeReviewFailed": "Review-Sitzungen konnten nicht abgeschlossen werden: {message}", + "folderOpened": "Ordner {name} geöffnet", + "folderRemoved": "Ordner {name} entfernt", + "openFolderFailed": "Ordner konnte nicht geöffnet werden", + "removeFolderFailed": "Ordner konnte nicht entfernt werden: {message}", + "reorderFoldersFailed": "Ordner konnten nicht neu sortiert werden: {message}", + "changeFolderColorFailed": "Farbe konnte nicht geändert werden: {message}", + "setFolderAliasFailed": "Alias konnte nicht festgelegt werden: {message}", + "changeFolderDefaultAgentFailed": "Standard-Agent konnte nicht gesetzt werden: {message}" + }, + "statsLabel": "{folders} Ordner · {convos} Konversationen", + "reorderHandle": "Zum Neuordnen ziehen", + "openFolder": "Ordner öffnen", + "searchPlaceholder": "Konversationen suchen...", + "viewOptions": "Anzeigeoptionen", + "showCompleted": "Abgeschlossene Konversationen anzeigen", + "showWorktrees": "Worktree-Ordner anzeigen", + "showRecent": "Gruppe „Zuletzt“ anzeigen", + "moreOptions": "Weitere Optionen", + "sortBy": "Sortieren nach", + "sortByCreatedAt": "Erstellungszeit", + "sortByUpdatedAt": "Aktualisierungszeit", + "sectionOrder": "Abschnittsreihenfolge", + "sectionOrderMoveUp": "Nach oben", + "sectionOrderMoveDown": "Nach unten", + "sectionOrderItemLabel": "{name} — Position {position} von {total}", + "statusRunningBadge": "Läuft", + "runningCountBadge": "{count, plural, one {# laufende Sitzung} other {# laufende Sitzungen}}", + "statusCancelledBadge": "Abgebrochen", + "worktreeRemovedBadge": "Quell-Worktree entfernt", + "conversationCountUnit": "{count, plural, one {# Konversation} other {# Konversationen}}", + "emptyFolderHint": "Keine Konversationen", + "noMatchingConversations": "Keine passenden Konversationen", + "noUnfinishedConversations": "Keine offenen Konversationen. Aktiviere \"Abgeschlossene anzeigen\" im Menü oben rechts.", + "removeFolderConfirmTitle": "Ordner aus Arbeitsbereich entfernen?", + "removeFolderConfirmDescription": "\"{name}\" aus dem Arbeitsbereich entfernen? Zugehörige Tabs und Terminals werden geschlossen.", + "folderHeaderMenu": { + "manageConversations": "Konversationen verwalten…", + "manageLinks": "Verknüpfte Ordner", + "changeColor": "Farbe ändern", + "useThemeColor": "App-Design verwenden", + "setDefaultAgent": "Standard-Agent festlegen", + "defaultAgentNone": "Kein Standard (global verwenden)", + "agentUnavailableSuffix": "(nicht verfügbar)", + "loadingAgents": "Agenten werden geladen…", + "setAlias": "Alias festlegen…", + "setAliasTitle": "Ordner-Alias festlegen", + "setAliasPlaceholder": "Alias eingeben (zum Entfernen leer lassen)", + "setAliasSave": "Speichern", + "setAliasCancel": "Abbrechen", + "removeFromWorkspace": "Aus Arbeitsbereich entfernen" + }, + "manageConversations": { + "title": "Konversationen verwalten", + "searchPlaceholder": "Nach Titel suchen…", + "agentFilterAll": "Alle Agenten", + "statusFilterAll": "Alle Status", + "folderFilterAll": "Alle Ordner", + "branchFilterAll": "Alle Branches", + "branchNone": "Kein Branch", + "branchSearchPlaceholder": "Branches suchen…", + "noMatchingBranches": "Keine passenden Branches", + "selectAllVisible": "Alle auswählen", + "deselectAll": "Auswahl aufheben", + "selectedCount": "{count} ausgewählt", + "matchedCount": "{count} Treffer", + "untitledConversation": "Unbenannte Konversation", + "setStatus": "Status setzen…", + "deleteSelected": "Löschen", + "noConversations": "Keine Konversationen in diesem Ordner.", + "noConversationsWorkspace": "Keine Konversationen im Arbeitsbereich.", + "noMatchingConversations": "Keine Konversationen entsprechen den Filtern.", + "confirmDeleteTitle": "{count} Konversation(en) löschen?", + "confirmDeleteDescription": "Diese Aktion kann nicht rückgängig gemacht werden.", + "toastDeleted": "{count} Konversation(en) gelöscht", + "toastStatusUpdated": "Status von {count} Konversation(en) aktualisiert", + "toastOpFailed": "Aktion fehlgeschlagen: {message}" + }, + "sectionPinned": "Angeheftet", + "sectionFolders": "Ordner", + "sectionChats": "Chat", + "sectionRecent": "Zuletzt", + "noChats": "Keine Chats", + "noRecent": "Keine kürzlichen Konversationen", + "showMoreRecent": "Mehr anzeigen ({count})", + "noFolders": "Keine Ordner geöffnet", + "newChatAction": "Neuer Chat", + "automations": "Automatisierungen", + "tasks": "To-dos", + "loadingSubsessions": "Unterkonversationen werden geladen…" + }, + "conversation": { + "reloadFailed": "Konversation konnte nicht neu geladen werden: {message}", + "reloaded": "Konversation neu geladen", + "reload": "Neu laden", + "activeConversationIndicator": "Aktive Konversation", + "newConversation": "Neue Konversation", + "closeConversation": "Konversation schließen", + "copyText": "Text kopieren", + "copyTextSuccess": "Kopiert", + "copyTextFailed": "Kopieren fehlgeschlagen", + "forkSession": "Sitzung forken", + "forkSessionSuccess": "Sitzung erfolgreich geforkt", + "forkSessionFailed": "Sitzung konnte nicht geforkt werden: {error}", + "exportConversation": "Konversation exportieren", + "exportImage": "Bild", + "exportMarkdown": "Markdown", + "exportHtml": "HTML", + "exportSuccess": "Konversation exportiert", + "exportFailed": "Export fehlgeschlagen", + "exportImageTooLong": "Konversation ist zu lang für den Bildexport", + "exportLabels": { + "untitledConversation": "Unbenannte Konversation", + "agent": "Agent", + "model": "Modell", + "status": "Status", + "started": "Gestartet", + "updated": "Aktualisiert", + "tokens": "Token-Statistik", + "duration": "Dauer", + "inputTokens": "Eingabe", + "outputTokens": "Ausgabe", + "cacheRead": "Cache gelesen", + "cacheWrite": "Cache geschrieben", + "user": "Benutzer", + "assistant": "Assistent", + "system": "System", + "toolResult": "Ergebnis", + "toolError": "Fehler" + }, + "moreActions": "Weitere Aktionen" + }, + "sessionDetails": { + "menuLabel": "Sitzungsdetails", + "noActiveSession": "Keine aktive Sitzung", + "title": "Sitzungsdetails", + "subtitle": "Sitzungsmetadaten und Token-Nutzung", + "fieldTitle": "Titel", + "untitled": "Unbenannte Konversation", + "sessionId": "Sitzungs-ID", + "externalId": "Erweiterungs-ID", + "agent": "Agent", + "model": "Modell", + "status": "Status", + "gitBranch": "Git-Branch", + "parentId": "Übergeordnete Sitzung", + "tokensHeading": "Token-Nutzung", + "totalTokens": "Gesamt", + "inputTokens": "Eingabe", + "outputTokens": "Ausgabe", + "cacheWrite": "Cache geschrieben", + "cacheRead": "Cache gelesen", + "contextWindow": "Kontextfenster", + "duration": "Dauer", + "loadingStats": "Token-Nutzung wird geladen…", + "loadFailed": "Token-Nutzung konnte nicht geladen werden", + "noStats": "Keine Nutzung erfasst", + "timestampsHeading": "Zeitstempel", + "createdAt": "Erstellt", + "updatedAt": "Aktualisiert", + "none": "—", + "copyField": "{field} kopieren", + "copiedField": "{field} kopiert" + }, + "conversationCard": { + "untitledConversation": "Unbenannte Konversation", + "newConversation": "Neue Konversation", + "rename": "Umbenennen", + "status": "Zustand", + "delete": "Löschen", + "importLocalSessions": "Lokale Sitzungen importieren", + "importing": "Importiere...", + "renameConversation": "Konversation umbenennen", + "deleteConversationTitle": "Konversation löschen?", + "deleteConversationDescription": "\"{title}\" wird gelöscht. Diese Aktion kann nicht rückgängig gemacht werden.", + "cancel": "Abbrechen", + "save": "Speichern", + "pin": "Anheften", + "unpin": "Loslösen", + "markCompleted": "Als abgeschlossen markieren", + "reopen": "Erneut öffnen", + "expandSubsessions": "Unterkonversationen einblenden", + "collapseSubsessions": "Unterkonversationen ausblenden" + }, + "search": { + "dialogTitle": "Suchen", + "dialogTitleWithFolder": "Suchen — {name}", + "tabConversations": "Konversationen", + "tabFiles": "Dateien", + "placeholder": "Konversationen suchen...", + "filePlaceholder": "Dateien oder Verzeichnisse suchen...", + "allAgents": "Alle", + "searching": "Suche...", + "typeToSearch": "Tippen, um Konversationen zu suchen", + "typeToSearchFiles": "Tippen, um Dateien oder Verzeichnisse zu suchen", + "noResults": "Keine Ergebnisse gefunden.", + "untitledConversation": "Unbenannte Konversation" + }, + "folderTitleBar": { + "showSidebar": "Seitenleiste anzeigen", + "hideSidebar": "Seitenleiste ausblenden", + "toggleTerminal": "Terminal umschalten", + "toggleAuxPanel": "Hilfspaneel umschalten", + "search": "Suchen", + "openSettings": "Einstellungen öffnen", + "backToConversations": "Zurück zu Konversationen", + "withShortcut": "{label} (Tastenkürzel: {shortcut})" + }, + "statusBar": { + "connection": { + "connected": "Verbunden", + "connecting": "Verbinde...", + "prompting": "Antworte...", + "error": "Verbindungsfehler", + "disconnected": "Getrennt", + "tooltip": "{agent}: {status}", + "tooltipError": "{agent}: {error}", + "title": "Agent-Verbindung", + "triggerAria": "Agent-Verbindung: {status}", + "workingDir": "Arbeitsverzeichnis", + "sessionId": "Sitzungs-ID", + "viewerNote": "Mit einer Sitzung verbunden, die einem anderen Client gehört – ein Neuverbinden hängt nur diese Ansicht erneut an.", + "reconnectInterrupts": "Neu verbinden startet den Agenten neu und unterbricht die laufende Arbeit.", + "reconnect": "Neu verbinden", + "reconnecting": "Verbinde neu...", + "reconnectUnavailable": "Noch keine Sitzung zum Neuverbinden." + }, + "tasks": { + "title": "Aufgaben" + }, + "alerts": { + "title": "Warnungen", + "empty": "Keine Warnungen", + "details": "Details" + }, + "stats": { + "conversations": "{count} Konversationen", + "openUsage": "Sitzungsstatistik und Token-Nutzung anzeigen" + }, + "tokens": { + "contextWindowUsageAria": "Kontextfenster-Nutzung", + "contextWindow": "Kontextfenster", + "usedMax": "Verwendet / Max", + "tokenUsage": "Token-Nutzung", + "input": "Eingabe", + "output": "Ausgabe", + "cacheRead": "Cache lesen", + "cacheWrite": "Cache schreiben", + "total": "Gesamt" + } + }, + "auxPanel": { + "tabs": { + "files": "Dateien", + "changes": "Änderungen", + "commits": "Einträge" + }, + "noFolderTitle": "Kein Ordner geöffnet", + "noFolderHint": "Öffnen Sie einen Ordner, um seinen Inhalt hier zu sehen" + }, + "windowControls": { + "minimizeWindow": "Fenster minimieren", + "minimize": "Minimieren", + "maximizeWindow": "Fenster maximieren", + "maximize": "Maximieren", + "restoreWindow": "Fenster wiederherstellen", + "restore": "Wiederherstellen", + "closeWindow": "Fenster schließen", + "close": "Schließen" + }, + "tabs": { + "closeConversationTab": "Konversationstab schließen", + "close": "Schließen", + "closeOthers": "Andere schließen", + "splitRight": "Nach rechts teilen", + "splitDown": "Nach unten teilen", + "splitAndMoveRight": "Teilen und nach rechts verschieben", + "splitAndMoveDown": "Teilen und nach unten verschieben", + "moveToOppositeGroup": "In gegenüberliegende Gruppe verschieben", + "moveToGroup": "In Gruppe verschieben", + "groupLabel": "Gruppe {index}", + "changeSplitterOrientation": "Teiler-Ausrichtung wechseln", + "unsplit": "Teilung aufheben", + "unsplitAll": "Alle Teilungen aufheben", + "closeAll": "Alle schließen", + "tileDisplay": "Kachelansicht", + "untileDisplay": "Kachel beenden" + }, + "fileWorkspace": { + "files": "Dateien", + "closeFileTab": "Dateitab schließen", + "close": "Schließen", + "closeOthers": "Andere schließen", + "closeAll": "Alle schließen", + "preview": "Vorschau", + "editSource": "Quelle bearbeiten", + "maximize": "Maximieren", + "restore": "Wiederherstellen", + "emptyDirectory": "Leerer Ordner" + }, + "terminal": { + "rename": "Umbenennen", + "close": "Schließen", + "closeOthers": "Andere schließen", + "closeAll": "Alle schließen", + "hideTerminal": "Terminal ausblenden ({shortcut})", + "openFolderFirst": "Öffnen Sie zuerst einen Ordner" + }, + "workspaceDialog": { + "title": "Ordner öffnen", + "manageTitle": "Verknüpfte Ordner", + "addTargetsTitle": "Ordner zum Verknüpfen hinzufügen", + "pickRootDescription": "Wähle den Hauptordner für diesen Arbeitsbereich.", + "linksDescription": "Verknüpfe weitere Ordner als Unterverzeichnisse, damit Agenten aus einem Arbeitsbereich heraus über alle hinweg arbeiten können.", + "addTargetsDescription": "Wähle einen oder mehrere Ordner. Jeder wird zu einem Unterverzeichnis des Arbeitsbereichs.", + "useSystemPicker": "Systemauswahl", + "next": "Weiter", + "back": "Zurück", + "done": "Fertig", + "change": "Ändern", + "addFolders": "Ordner hinzufügen", + "addSelected": "Hinzufügen", + "addSelectedCount": "{count} hinzufügen", + "createCount": "{count} Ordner verknüpfen", + "discardPending": "Verwerfen", + "noLinks": "Noch keine verknüpften Ordner.", + "gitExclude": "Verknüpfungen aus dem Git-Status heraushalten", + "rename": "Umbenennen", + "unlink": "Verknüpfung entfernen", + "repair": "Verknüpfung neu anlegen", + "saveName": "Speichern", + "cancelRename": "Abbrechen", + "removePending": "Entfernen", + "willAppearAs": "Erscheint im Arbeitsbereich als {name}", + "renamedForDuplicate": "Umbenannt – {base} wird bereits von einer anderen Verknüpfung genutzt", + "renamedForExistingEntry": "Umbenannt – {base} existiert in diesem Ordner bereits", + "partiallyCreated": "Nur {count} Ordner konnten verknüpft werden", + "openFailed": "Ordner konnte nicht geöffnet werden", + "previewFailed": "Ausgewählte Ordner konnten nicht geprüft werden", + "createFailed": "Ordner konnten nicht verknüpft werden", + "renameFailed": "Verknüpfung konnte nicht umbenannt werden", + "removeFailed": "Verknüpfung konnte nicht entfernt werden", + "repairFailed": "Verknüpfung konnte nicht neu angelegt werden", + "status": { + "ok": "Verknüpft", + "missing": "Die Verknüpfung ist aus diesem Ordner verschwunden", + "conflicted": "Ein anderer Eintrag nutzt jetzt diesen Namen", + "broken": "Der verknüpfte Ordner existiert nicht mehr" + }, + "nameIssue": { + "empty": "Namen eingeben", + "illegalChars": "Darf / \\ : * ? \" < > | nicht enthalten", + "tooLong": "Name ist zu lang", + "reserved": "Dieser Name ist unter Windows reserviert", + "duplicate": "Dieser Name wird bereits verwendet" + }, + "rejection": { + "not_found": "Dieser Ordner wurde nicht gefunden", + "not_a_directory": "Dieser Pfad ist kein Ordner", + "same_as_root": "Das ist der Arbeitsbereichsordner selbst", + "ancestor_of_root": "Dieser Ordner enthält den Arbeitsbereich", + "inside_root": "Liegt bereits im Arbeitsbereich", + "already_linked": "Bereits verknüpft", + "name_unavailable": "Für diesen Ordner ist kein Name mehr frei", + "alreadyLinkedAs": "Bereits als {name} verknüpft" + } + }, + "folderNameDropdown": { + "fallbackFolderName": "Ordner", + "openFolder": "Ordner öffnen", + "cloneRepository": "Repository klonen", + "projectBoot": "Projekt-Boot", + "opened": "Geöffnet", + "recentOpen": "Zuletzt geöffnet" + }, + "fileWorkspacePanel": { + "addSelectionToChat": "Auswahl zum Chat hinzufügen", + "addToChat": "Zum Chat hinzufügen", + "addSelectionToChatDone": "{label} zur Unterhaltung hinzugefügt", + "addFileToChat": "Datei zum Chat hinzufügen", + "toggleWordWrap": "Zeilenumbruch umschalten", + "addFileToChatDone": "{label} zur Unterhaltung hinzugefügt", + "viewDiff": "Diff anzeigen", + "openFile": "Datei öffnen", + "fileCount": "{count, plural, one {# Datei} other {# Dateien}}", + "openFileOrDiff": "Öffne eine Datei oder Diff im rechten Panel", + "disk": "Datenträger", + "head": "HEAD", + "unsaved": "Ungespeichert", + "workingTree": "Arbeitsverzeichnis", + "loading": "Wird geladen...", + "compareWithBranch": "{path} · vergleichen mit {branch}", + "hunkCount": "{count, plural, one {# Hunk} other {# Hunks}}", + "prev": "Zurück", + "next": "Weiter", + "jumpToLine": "Zu Zeile {line} springen", + "noParsedDiffSections": "Keine geparsten Diff-Abschnitte", + "loadingEditor": "Editor wird geladen...", + "imageZoomIn": "Vergrößern", + "imageZoomOut": "Verkleinern", + "imageZoomReset": "Zoom zurücksetzen", + "htmlPreviewTitle": "HTML-Vorschau", + "htmlPreviewTrust": "Skripte aktivieren", + "htmlPreviewTrustHint": "Skripte dieser Datei ausführen und Netzwerkzugriff erlauben. Nur für vertrauenswürdige Dateien aktivieren.", + "officePreviewTitle": "Office-Dokumentvorschau", + "officeFullRender": "Vollständige Darstellung", + "officeFullRenderHint": "Stellt Morph-Animationen, 3D und Formeln dar (führt die Skripte der Folie aus)", + "officeNotInstalled": "OfficeCLI ist nicht installiert", + "officeNotInstalledHint": "Installiere OfficeCLI unter Einstellungen → Office-Tools, um Word-, Excel- und PowerPoint-Dateien vorzuschauen.", + "officeOpenSettings": "Einstellungen öffnen", + "officeWatchFailed": "Live-Vorschau konnte nicht gestartet werden", + "officeWatchRetry": "Erneut versuchen", + "officeServerInstallHint": "OfficeCLI muss auf dem Server-Host installiert sein. Führe diesen Befehl dort aus und versuche es erneut:", + "officeRemoteDesktopUnsupported": "Die Live-Vorschau ist in einem Remote-Desktop-Fenster nicht verfügbar. Öffne diesen Arbeitsbereich in der Web-Oberfläche des Servers, um Office-Dateien anzusehen." + }, + "branchDropdown": { + "toasts": { + "commitCodeCompleted": "Code-Commit abgeschlossen", + "pushCodeCompleted": "Code-Push abgeschlossen", + "committedFiles": "{count, plural, one {# Datei committet} other {# Dateien committet}}", + "taskCompleted": "{label} abgeschlossen", + "taskFailed": "{label} fehlgeschlagen", + "mergeNoNewCommits": "{branchName} hat keine neuen Commits", + "mergedCommits": "{count, plural, one {# Commit zusammengeführt} other {# Commits zusammengeführt}}", + "allFilesUpToDate": "Alle Dateien sind aktuell", + "updatedFiles": "{count, plural, one {# Datei aktualisiert} other {# Dateien aktualisiert}}", + "openCommitWindowFailed": "Commit-Fenster konnte nicht geöffnet werden", + "openPushWindowFailed": "Push-Fenster konnte nicht geöffnet werden", + "upstreamSet": "Upstream-Branch wurde gesetzt", + "upstreamSetAndPushed": "Upstream-Branch gesetzt und {count, plural, one {# Commit} other {# Commits}} gepusht", + "noCommitsToPush": "Keine Commits zum Pushen", + "pushedCommits": "{count, plural, one {# Commit gepusht} other {# Commits gepusht}}", + "switchedToFolder": "Zu {name} gewechselt", + "switchFailed": "Branch konnte nicht gewechselt werden", + "openStashWindowFailed": "Stash-Fenster konnte nicht geöffnet werden" + }, + "tasks": { + "newBranch": "Branch {name} erstellen", + "newWorktree": "Worktree {name} erstellen", + "checkoutTo": "Zu {branchName} wechseln", + "mergeBranch": "{branchName} mergen", + "rebaseTo": "Auf {branchName} rebasen", + "deleteRemoteBranch": "Remote-Branch {branchName} löschen", + "initGitRepo": "Git-Repository initialisieren", + "pullCode": "Code pullen", + "fetchInfo": "Informationen fetchen", + "pushCode": "Code pushen", + "stashChanges": "Änderungen stashen", + "stashPop": "Stash anwenden", + "deleteBranch": "Branch {branchName} löschen", + "removeWorktree": "Worktree von {branchName} löschen", + "removeWorktreeAndBranch": "Worktree und Branch {branchName} löschen", + "updateBranch": "Branch {branchName} aktualisieren" + }, + "confirm": { + "mergeTitle": "Branch mergen", + "rebaseTitle": "Branch rebasen", + "mergeDescription": "{branchName} in den aktuellen Branch {currentBranch} mergen?", + "rebaseDescription": "Aktuellen Branch {currentBranch} auf {branchName} rebasen?", + "deleteRemoteTitle": "Remote-Branch löschen", + "deleteRemoteDescription": "Remote-Branch {branchName} löschen? Dies entfernt ihn aus dem Remote-Repository und kann nicht rückgängig gemacht werden.", + "deleteTitle": "Branch löschen", + "deleteDescription": "Branch {branchName} löschen? Diese Aktion kann nicht rückgängig gemacht werden.", + "forceDeleteTitle": "Branch erzwungen löschen", + "forceDeleteDescription": "Der Branch {branchName} ist nicht vollständig gemergt. Möchten Sie ihn wirklich erzwungen löschen? Diese Aktion kann nicht rückgängig gemacht werden.", + "deleteWorktreeTitle": "Worktree löschen", + "deleteWorktreeDescription": "Das Worktree-Verzeichnis löschen, in dem {branchName} ausgecheckt ist? Der Branch und seine Commits bleiben erhalten.", + "forceDeleteWorktreeTitle": "Worktree erzwungen löschen", + "forceDeleteWorktreeDescription": "Im Worktree von {branchName} gibt es nicht committete oder nicht verfolgte Dateien. Trotzdem löschen? Diese Änderungen lassen sich nicht wiederherstellen.", + "deleteWorktreeAndBranchTitle": "Worktree und Branch löschen", + "deleteWorktreeAndBranchDescription": "Den Worktree von {branchName}, den Branch selbst und seinen Arbeitsbereich-Ordner löschen? Seine Sitzungen wandern in den Repository-Ordner. Diese Aktion kann nicht rückgängig gemacht werden.", + "forceDeleteWorktreeAndBranchTitle": "Worktree und Branch erzwungen löschen", + "forceDeleteWorktreeAndBranchDescription": "Im Worktree von {branchName} gibt es nicht committete Dateien, oder der Branch ist nicht vollständig gemergt. Trotzdem beides löschen? Diese Aktion kann nicht rückgängig gemacht werden." + }, + "current": "Aktuell", + "switchToBranch": "Zu diesem Branch wechseln", + "mergeBranchIntoCurrent": "{branchName} in {currentBranch} mergen", + "rebaseCurrentToBranch": "{currentBranch} auf {branchName} rebasen", + "noBranch": "Kein Branch", + "detachedHead": "Losgelöster HEAD bei {sha}", + "initGitRepo": "Git-Repository initialisieren", + "pullCode": "Code pullen", + "fetchRemoteBranches": "Remote-Branches fetchen", + "openCommitWindow": "Code committen...", + "pushCode": "Hochladen...", + "pushBranch": "Hochladen", + "newBranch": "Neuer Branch...", + "newWorktree": "Neuer Worktree...", + "stashChanges": "Änderungen stashen...", + "stashPop": "Stash anwenden...", + "manageRemotes": "Remotes verwalten...", + "localBranches": "Lokale Branches ({count, plural, one {#} other {#}})", + "noLocalBranches": "Keine lokalen Branches", + "remoteBranches": "Remote-Branches ({count, plural, one {#} other {#}})", + "noRemoteBranches": "Keine Remote-Branches", + "dialogs": { + "newBranchTitle": "Neuer Branch", + "newBranchDescription": "Neuen Branch vom aktuellen Branch {branch} erstellen", + "branchNamePlaceholder": "Branch-Name", + "newWorktreeTitle": "Neuer Worktree", + "newWorktreeDescription": "Neuen Worktree vom aktuellen Branch {branch} erstellen", + "branchNameLabel": "Branch-Name", + "worktreePathLabel": "Worktree-Pfad", + "worktreePathPlaceholder": "Worktree-Pfad", + "manageRemotesTitle": "Remotes verwalten", + "manageRemotesEmpty": "Keine Remotes konfiguriert", + "remoteNamePlaceholder": "Remote-Name", + "remoteUrlPlaceholder": "Remote-URL", + "addRemote": "Hinzufügen", + "savingRemotes": "Speichern..." + }, + "conflict": { + "title": "Merge-Konflikte", + "description": "Die folgenden Dateien haben Konflikte, die gelöst werden müssen:", + "abort": "Merge abbrechen", + "openMergeTool": "Merge-Tool öffnen", + "completeMerge": "Merge abschließen", + "abortSuccess": "Merge erfolgreich abgebrochen", + "completeSuccess": "Merge erfolgreich abgeschlossen" + }, + "stashDialog": { + "title": "Änderungen stashen", + "description": "Aktuelle Änderungen im Stash speichern", + "messageLabel": "Nachricht", + "messagePlaceholder": "Stash-Nachricht (optional)", + "keepIndex": "Index beibehalten (gestagete Änderungen bleiben erhalten)", + "cancel": "Abbrechen", + "stash": "Stashen", + "success": "Änderungen wurden gestasht", + "error": "Stash fehlgeschlagen" + }, + "unstashDialog": { + "title": "Stash anwenden", + "noStashes": "Keine Stashes vorhanden", + "selectFile": "Datei auswählen um Diff anzuzeigen", + "viewDiff": "Diff anzeigen", + "original": "Original", + "modified": "Geändert", + "apply": "Anwenden", + "drop": "Löschen", + "applySuccess": "Stash angewendet", + "dropSuccess": "Stash gelöscht", + "confirmApply": "Stash {ref} auf das Arbeitsverzeichnis anwenden?", + "cancel": "Abbrechen" + }, + "deleteBranch": "Branch löschen", + "deleteWorktree": "Worktree löschen", + "deleteWorktreeAndBranch": "Worktree und Branch löschen", + "searchPlaceholder": "Branches und Aktionen suchen", + "searchAriaLabel": "Branches und Aktionen suchen", + "branchListLabel": "Branches und Aktionen", + "noMatches": "Keine Treffer" + }, + "commitDialog": { + "toasts": { + "commitCompleted": "Code-Commit abgeschlossen", + "pushFailed": "Push fehlgeschlagen", + "committedFiles": "{count, plural, one {# Datei committet} other {# Dateien committet}}", + "addedToVcs": "Zu VCS hinzugefügt", + "addToVcsFailed": "Hinzufügen zu VCS fehlgeschlagen", + "fileDeleted": "Datei gelöscht", + "deleteFailed": "Löschen fehlgeschlagen", + "fileRolledBack": "Datei zurückgesetzt", + "rollbackFailed": "Rollback fehlgeschlagen", + "dirRolledBack": "Verzeichnis zurückgesetzt", + "dirDeleted": "Verzeichnis gelöscht" + }, + "confirm": { + "deleteTitle": "Löschen bestätigen", + "deleteDescription": "Datei \"{file}\" löschen? Diese Aktion kann nicht rückgängig gemacht werden.", + "rollbackTitle": "Rollback bestätigen", + "rollbackDescription": "Datei \"{file}\" auf HEAD zurücksetzen? Ungespeicherte Änderungen gehen verloren.", + "rollbackDirDescription": "Verzeichnis \"{dir}\" auf HEAD zurücksetzen? Nicht gespeicherte Änderungen gehen verloren.", + "deleteDirDescription": "Verzeichnis \"{dir}\" löschen? Diese Aktion kann nicht rückgängig gemacht werden." + }, + "actions": { + "select": "Auswählen", + "unselect": "Auswahl aufheben", + "rollback": "Zurücksetzen", + "addToVcs": "Zu VCS hinzufügen" + }, + "aria": { + "selectFile": "{action}: {path}", + "unselectAllFiles": "Auswahl aller Dateien aufheben", + "selectAllFiles": "Alle Dateien auswählen", + "unselectTracked": "Auswahl verfolgter Änderungen aufheben", + "selectTracked": "Verfolgte Änderungen auswählen", + "unselectUntracked": "Auswahl nicht verfolgter Dateien aufheben", + "selectUntracked": "Nicht verfolgte Dateien auswählen" + }, + "loading": "Wird geladen...", + "selectionCount": "{selected} / {total} Dateien", + "emptyFiles": "Keine geänderten Dateien", + "trackedChanges": "Verfolgte Änderungen ({count})", + "untrackedFiles": "Nicht verfolgte Dateien ({count})", + "commitMessage": "Commit-Nachricht", + "commitMessagePlaceholder": "Commit-Nachricht eingeben...", + "commitButton": "Einchecken ({count})", + "commitAndPushButton": "Committen und pushen ({count})", + "head": "HEAD", + "workingTree": "Arbeitsverzeichnis", + "clickFileToDiff": "Dateinamen anklicken, um Diff zu sehen", + "loadingDiff": "Diff wird geladen..." + }, + "pushWindow": { + "title": "Code pushen", + "noUnpushedCommits": "Keine ungepushten Commits", + "noRemoteConfigured": "Kein Git-Remote konfiguriert\nFüge einen unter Remotes verwalten hinzu", + "newBranchNoPushedCommits": "Neuer Branch — pushen, um Remote-Tracking-Branch zu erstellen", + "unpushed": "Nicht gepusht", + "selectFileToViewDiff": "Datei auswählen, um Unterschiede anzuzeigen", + "before": "Vorher", + "after": "Nachher", + "push": "Pushen", + "toasts": { + "pushSuccess": "Push erfolgreich", + "pushFailed": "Push fehlgeschlagen", + "upstreamSet": "Remote-Tracking-Branch wurde eingerichtet", + "upstreamSetAndPushed": "Remote-Tracking-Branch eingerichtet und {count} Commits gepusht", + "noCommitsToPush": "Keine Commits zum Pushen", + "pushedCommits": "{count} Commits gepusht" + } + }, + "gitLogTab": { + "filesTitle": "Dateien", + "expandAllFiles": "Alle Dateien ausklappen", + "collapseAllFiles": "Alle Dateien einklappen", + "workspace": "Arbeitsbereich", + "retry": "Erneut versuchen", + "noCommitsFound": "Keine Commits gefunden", + "notAGitRepoTitle": "Kein Git-Repository", + "notAGitRepoHint": "Initialisiere Git über das Branch-Menü oben oder öffne ein bestehendes Repository.", + "hash": "Hash-Wert", + "copyHash": "Hash kopieren", + "copyMessage": "Nachricht kopieren", + "showMore": "Mehr anzeigen", + "showLess": "Weniger anzeigen", + "author": "Autor", + "noFileChangeDetails": "Keine Details zu Dateiänderungen verfügbar.", + "loadingFiles": "Dateien werden geladen...", + "branchesTitle": "Zweige", + "loadingBranches": "Branches werden geladen...", + "noContainingBranches": "Keine enthaltenen Branches gefunden.", + "newBranch": "Neuer Branch...", + "resetToHere": "Auf diesen Stand zurücksetzen", + "resetDisabledReasonNotCurrentBranchView": "Nur in der Ansicht des aktuellen Branches verfügbar", + "copyFullCommitHashAria": "Vollständigen Commit-Hash {hash} kopieren", + "pushStatus": { + "pushed": "Zum Remote gepusht", + "notPushed": "Nicht zum Remote gepusht", + "unknown": "Push-Status unbekannt (kein Upstream konfiguriert)" + }, + "time": { + "monthsAgo": "{count, plural, one {vor # Monat} other {vor # Monaten}}", + "daysAgo": "{count, plural, one {vor # Tag} other {vor # Tagen}}", + "hoursAgo": "{count, plural, one {vor # Stunde} other {vor # Stunden}}", + "minsAgo": "{count, plural, one {vor # Min} other {vor # Min}}", + "justNow": "gerade eben" + }, + "toasts": { + "createdAndSwitchedNewBranch": "Neuen Branch erstellt und gewechselt", + "newBranchFromCommit": "{name} (aus {shortHash})", + "createBranchFailed": "Branch konnte nicht erstellt werden", + "openPushWindowFailed": "Push-Fenster konnte nicht geöffnet werden", + "resetSuccess": "Zurücksetzen erfolgreich", + "resetSuccessDescription": "{branch} wurde mit {mode} auf {shortHash} zurückgesetzt", + "resetFailed": "Zurücksetzen fehlgeschlagen" + }, + "authorFilter": { + "label": "Autor", + "searchPlaceholder": "Autor suchen", + "noAuthors": "Keine Autoren gefunden", + "you": "du", + "filterByAuthorAria": "Commits nach Autor filtern", + "filterByQuery": "Nach \"{query}\" filtern", + "clearAuthorFilterAria": "Autorfilter löschen", + "recent": "Zuletzt verwendet", + "matchingAuthors": "Passende Autoren", + "removeFromRecent": "{name} aus „Zuletzt verwendet“ entfernen" + }, + "branchSelector": { + "label": "Branch", + "head": "HEAD", + "headHint": "Folgt dem aktuellen Branch", + "headHintWithBranch": "Folgt dem aktuellen Branch ({branch})", + "searchBranch": "Branch suchen...", + "noBranches": "Keine Branches", + "selectBranchPlaceholder": "Branch auswählen...", + "localBranches": "Lokale Branches", + "current": "Aktuell", + "remoteBranches": "Remote-Branches", + "refreshCommitHistory": "Commit-Verlauf aktualisieren", + "clearBranchFilterAria": "Branch-Filter löschen" + }, + "dialogs": { + "newBranchTitle": "Neuer Branch", + "newBranchDescription": "Erstelle einen neuen Branch mit Commit {shortHash} als letztem Commit.", + "branchNamePlaceholder": "Branch-Name", + "reset": { + "title": "Aktuellen Branch auf diesen Commit zurücksetzen", + "branchLabel": "Branch", + "targetLabel": "Ziel-Commit", + "messageLabel": "Nachricht", + "modeLabel": "Reset-Modus", + "confirmButton": "Zurücksetzen", + "modes": { + "soft": { + "label": "--soft", + "description": "Verschiebt HEAD und den Zeiger des aktuellen Branches auf den Ziel-Commit.\nIndex und Working Tree bleiben unverändert.\nÄnderungen aus den entfernten Commits bleiben staged." + }, + "mixed": { + "label": "--mixed (Standard)", + "description": "Verschiebt HEAD auf den Ziel-Commit.\nSetzt den Index auf den Ziel-Commit zurück und behält Änderungen im Working Tree.\nÄnderungen wechseln von staged zu unstaged." + }, + "hard": { + "label": "--hard", + "description": "Verschiebt HEAD und setzt sowohl Index als auch Working Tree auf den Ziel-Commit zurück.\nLokale verfolgte Änderungen nach dem Ziel-Commit werden verworfen.\nDies ist eine destruktive Operation." + }, + "keep": { + "label": "--keep", + "description": "Verschiebt HEAD auf den Ziel-Commit und versucht lokale Änderungen zu behalten.\nNur nicht-konfliktierende Änderungen bleiben erhalten.\nBei Konflikten wird der Reset zum Schutz der Änderungen abgebrochen." + } + } + } + }, + "moreActions": "Weitere Git-Aktionen" + }, + "gitChangesTab": { + "workspace": "Arbeitsbereich", + "noChanges": "Keine lokalen Änderungen", + "notAGitRepoTitle": "Kein Git-Repository", + "notAGitRepoHint": "Initialisiere Git über das Branch-Menü oben oder öffne ein bestehendes Repository.", + "trackedChanges": "Verfolgte Änderungen ({count})", + "untrackedFiles": "Nicht verfolgte Dateien ({count})", + "expandTracked": "Verfolgte Änderungen ausklappen", + "collapseTracked": "Verfolgte Änderungen einklappen", + "expandUntracked": "Nicht verfolgte Dateien ausklappen", + "collapseUntracked": "Nicht verfolgte Dateien einklappen", + "showRemainingItems": "{count} weitere Einträge anzeigen", + "actions": { + "commitCode": "Code committen", + "rollback": "Zurücksetzen", + "addToVcs": "Zu VCS hinzufügen", + "delete": "Löschen", + "moreActions": "Weitere Git-Aktionen", + "addAllToVcs": "Alle zur VCS hinzufügen", + "rollbackAll": "Alle zurücksetzen", + "refresh": "Aktualisieren" + }, + "toasts": { + "noAddableFilesInDir": "Keine geänderten Dateien in diesem Verzeichnis können zu VCS hinzugefügt werden", + "noRollbackFilesInDir": "Keine geänderten Dateien in diesem Verzeichnis können zurückgesetzt werden", + "addedToVcs": "{name} zu VCS hinzugefügt", + "addToVcsFailed": "Hinzufügen zu VCS fehlgeschlagen", + "openCommitWindowFailed": "Commit-Fenster konnte nicht geöffnet werden", + "rolledBack": "{name} zurückgesetzt", + "rollbackFailed": "Rollback fehlgeschlagen", + "addedFilesToVcs": "{count, plural, one {# Datei} other {# Dateien}} zu VCS hinzugefügt", + "rolledBackFiles": "{count, plural, one {# Datei zurückgesetzt} other {# Dateien zurückgesetzt}}", + "deleted": "{name} gelöscht", + "deleteFailed": "Löschen fehlgeschlagen", + "deletedFiles": "{count} Dateien gelöscht", + "noDeletableFilesInDir": "In diesem Verzeichnis gibt es keine löschbaren geänderten Dateien", + "commitFailed": "Commit fehlgeschlagen" + }, + "directoryDialog": { + "descriptionAdd": "Dateien unter Verzeichnis {path} auswählen, um sie zu VCS hinzuzufügen.", + "descriptionRollback": "Dateien unter Verzeichnis {path} auswählen, um sie zurückzusetzen.", + "descriptionDelete": "Dateien unter Verzeichnis {path} auswählen, um sie zu löschen. Diese Aktion kann nicht rückgängig gemacht werden.", + "descriptionFallback": "Dateien auswählen, um fortzufahren.", + "selectionCount": "{selected} / {total} Dateien ausgewählt", + "selectAll": "Alle auswählen", + "unselectAll": "Auswahl aller aufheben", + "loadingCandidates": "Verzeichnisänderungen werden geladen...", + "noOperableFiles": "Keine bearbeitbaren Dateien" + }, + "rollbackConfirm": { + "title": "Rollback bestätigen", + "descriptionWithTarget": "Lokale Änderungen für {kind} \"{name}\" zurücksetzen?", + "descriptionFallback": "Lokale Änderungen zurücksetzen?", + "kindDirectory": "Verzeichnis", + "kindFile": "Datei" + }, + "deleteConfirm": { + "title": "Löschen bestätigen", + "descriptionWithTarget": "{kind} \"{name}\" löschen? Diese Aktion kann nicht rückgängig gemacht werden.", + "descriptionFallback": "Diese Aktion kann nicht rückgängig gemacht werden.", + "kindDirectory": "Verzeichnis", + "kindFile": "Datei" + }, + "quickCommit": { + "placeholder": "Commit-Nachricht (Enter zum Committen)" + } + }, + "tabContext": { + "loadingConversation": "Wird geladen...", + "untitledConversation": "Unbenannte Konversation", + "newConversation": "Neue Konversation" + }, + "fileTreeTab": { + "workspace": "Arbeitsbereich", + "retry": "Erneut versuchen", + "git": "Git", + "openInFileManager": "Im Dateimanager öffnen", + "openInFinder": "In Finder öffnen", + "openInExplorer": "In Explorer öffnen", + "attachToCurrentSession": "Zur Sitzung hinzufügen", + "compareWithBranch": "Mit Branch vergleichen...", + "reloadFromDisk": "Von Datenträger neu laden", + "new": "Neu", + "newFile": "Datei", + "newDirectory": "Verzeichnis", + "openIn": "Öffnen in", + "openInTerminal": "Im Terminal öffnen", + "linkedFolder": "Verknüpfter Ordner", + "copyPath": "Pfad kopieren", + "upload": "Dateien/Ordner hochladen", + "download": "Datei herunterladen", + "downloadAsZip": "Als ZIP herunterladen", + "actions": { + "select": "Auswählen", + "unselect": "Auswahl aufheben", + "commitCode": "Code committen", + "rollback": "Zurücksetzen", + "addToVcs": "Zu VCS hinzufügen" + }, + "aria": { + "selectPath": "{action}: {path}" + }, + "toasts": { + "openDirectoryFailed": "Verzeichnis konnte nicht geöffnet werden", + "openBuiltinTerminalFailed": "Integriertes Terminal konnte nicht geöffnet werden", + "openCommitWindowFailed": "Commit-Fenster konnte nicht geöffnet werden", + "noAddableFilesInDir": "Keine geänderten Dateien in diesem Verzeichnis können zu VCS hinzugefügt werden", + "noRollbackFilesInDir": "Keine geänderten Dateien in diesem Verzeichnis können zurückgesetzt werden", + "addedToVcs": "{name} zu VCS hinzugefügt", + "addToVcsFailed": "Hinzufügen zu VCS fehlgeschlagen", + "loadBranchesFailed": "Branches konnten nicht geladen werden", + "renameFailed": "Umbenennen fehlgeschlagen", + "moveFailed": "Verschieben fehlgeschlagen", + "deleteFailed": "Löschen fehlgeschlagen", + "rolledBack": "{name} zurückgesetzt", + "rollbackFailed": "Zurücksetzen fehlgeschlagen", + "addedFilesToVcs": "{count, plural, one {# Datei zu VCS hinzugefügt} other {# Dateien zu VCS hinzugefügt}}", + "rolledBackFiles": "{count, plural, one {# Datei zurückgesetzt} other {# Dateien zurückgesetzt}}", + "savedAsCopy": "Als Kopie gespeichert", + "saveCopyFailed": "Speichern als Kopie fehlgeschlagen", + "watchStartFailed": "Dateiwatch konnte nicht gestartet werden", + "createFailed": "Erstellen fehlgeschlagen", + "downloadFailed": "Herunterladen von {name} fehlgeschlagen", + "downloadSaved": "{name} heruntergeladen", + "pathCopied": "Pfad kopiert", + "copyPathFailed": "Pfad konnte nicht kopiert werden" + }, + "createDialog": { + "newFile": "Neue Datei", + "newDirectory": "Neues Verzeichnis", + "description": "Geben Sie einen Namen für das neue {kind} ein.", + "placeholderFile": "file-name.ext", + "placeholderDirectory": "folder-name" + }, + "renameDialog": { + "renameDirectory": "Verzeichnis umbenennen", + "renameFile": "Datei umbenennen", + "description": "Geben Sie einen neuen Namen ein (nur Name, kein Pfad).", + "placeholderDirectory": "neuer-ordnername", + "placeholderFile": "neuer-dateiname.ext" + }, + "uploadDialog": { + "title": "In den Arbeitsbereich hochladen", + "description": "Passe das Ziel bei Bedarf an und füge Dateien oder Ordner hinzu.", + "workspaceRoot": "Arbeitsbereich-Stammverzeichnis", + "targetPathLabel": "Hochladen nach", + "targetPathHint": "Aufgelöster Pfad: {path}", + "dropHint": "Dateien oder Ordner hier ablegen oder die Schaltflächen unten verwenden", + "dropHintActive": "Loslassen, um zur Warteschlange hinzuzufügen", + "selectFiles": "Dateien auswählen", + "selectFolder": "Ordner auswählen", + "startUpload": "Upload starten", + "clearQueue": "Erledigte entfernen", + "removeItem": "Aus der Warteschlange entfernen", + "retry": "Wiederholen", + "dropZoneAria": "Dateien hier ablegen oder aktivieren zum Durchsuchen", + "folderEmpty": "Keine Dateien im abgelegten Ordner gefunden", + "summary": "Gesamt: {total} · Erfolgreich: {succeeded} · Fehlgeschlagen: {failed}", + "status": { + "pending": "Wartet", + "uploading": "Wird hochgeladen", + "success": "Fertig", + "error": "Fehlgeschlagen", + "cancelled": "Abgebrochen" + } + }, + "directoryDialog": { + "descriptionAdd": "Wählen Sie Dateien im Verzeichnis {path} aus, um sie zu VCS hinzuzufügen.", + "descriptionRollback": "Wählen Sie Dateien im Verzeichnis {path} aus, um sie zurückzusetzen.", + "descriptionFallback": "Wählen Sie Dateien aus, um fortzufahren.", + "selectionCount": "{selected} / {total} Dateien ausgewählt", + "selectAll": "Alle auswählen", + "unselectAll": "Auswahl aufheben", + "loadingCandidates": "Verzeichnisänderungen werden geladen...", + "noOperableFiles": "Keine bearbeitbaren Dateien" + }, + "compareDialog": { + "title": "Mit Branch vergleichen", + "descriptionWithTarget": "Wählen Sie einen Branch und vergleichen Sie mit {kind} {path}", + "descriptionFallback": "Wählen Sie einen Branch zum Vergleichen.", + "kindDirectory": "Verzeichnis", + "kindFile": "Datei", + "filterPlaceholder": "Branches filtern, z. B. main / origin/main", + "singleClickHint": "Klicken Sie auf einen Branch, um direkt zu vergleichen", + "loadingBranches": "Branches werden geladen...", + "recentBranches": "Letzte Branches ({count})", + "noCurrentBranch": "Kein aktueller Branch", + "localBranches": "Lokale Branches ({count})", + "remoteBranches": "Remote-Branches ({count})", + "noMatchingBranches": "Keine passenden Branches" + }, + "externalConflictDialog": { + "title": "Externe Dateiänderungen erkannt", + "descriptionWithPath": "Datei {path} wurde auf dem Datenträger geändert, und aktuelle Bearbeitungen sind nicht gespeichert.", + "descriptionFallback": "Aktuelle Datei wurde auf dem Datenträger geändert, und aktuelle Bearbeitungen sind nicht gespeichert.", + "compare": "Vergleichen", + "savingCopy": "Kopie wird gespeichert...", + "saveAsCopy": "Als Kopie speichern", + "reload": "Neu laden" + }, + "deleteConfirm": { + "title": "Löschen bestätigen", + "descriptionWithTarget": "{kind} \"{name}\" löschen? Diese Aktion kann nicht rückgängig gemacht werden.", + "descriptionFallback": "Diese Aktion kann nicht rückgängig gemacht werden.", + "kindDirectory": "Verzeichnis", + "kindFile": "Datei" + }, + "rollbackConfirm": { + "title": "Zurücksetzen bestätigen", + "descriptionWithTarget": "Lokale Änderungen für Datei \"{name}\" zurücksetzen?", + "descriptionFallback": "Lokale Änderungen für diese Datei zurücksetzen?" + }, + "terminalTitle": "Konsole · {name}" + }, + "commandDropdown": { + "loading": "Wird geladen...", + "addCommand": "Befehl hinzufügen", + "manageCommands": "Befehle verwalten...", + "runCommandTitle": "Ausführen: {command}", + "stopCommandTitle": "Stoppen: {command}", + "manageDialog": { + "title": "Befehle verwalten", + "empty": "Noch keine Befehle", + "noResults": "Keine passenden Befehle", + "searchPlaceholder": "Befehle suchen", + "newCommand": "Neuer Befehl", + "nameLabel": "Bezeichnung", + "commandLabel": "Befehl", + "dragSort": "Zum Sortieren ziehen", + "dragSortCommand": "{name} zum Sortieren ziehen", + "orderFailed": "Befehlsreihenfolge konnte nicht gespeichert werden", + "loadFailed": "Befehle konnten nicht geladen werden", + "saveFailed": "Befehl konnte nicht gespeichert werden", + "deleteFailed": "Befehl konnte nicht gelöscht werden", + "confirmDelete": { + "title": "Befehl löschen?", + "message": "Dadurch wird \"{name}\" entfernt. Diese Aktion kann nicht rückgängig gemacht werden." + } + } + }, + "workspaceContext": { + "confirmCloseDirtyTab": "„{title}“ ohne Speichern schließen?", + "confirmCloseOtherDirtyTabs": "Andere Tabs mit ungespeicherten Änderungen schließen?", + "confirmCloseAllDirtyTabs": "Alle Tabs mit ungespeicherten Änderungen schließen?", + "unableLoadContent": "Inhalt konnte nicht geladen werden.\n\n{message}", + "previewRequestTimedOut": "Vorschauanfrage hat das Zeitlimit überschritten", + "diffRequestTimedOut": "Diff-Anfrage hat das Zeitlimit überschritten", + "branchCompareRequestTimedOut": "Branch-Vergleichsanfrage hat das Zeitlimit überschritten", + "commitDiffRequestTimedOut": "Commit-Diff-Anfrage hat das Zeitlimit überschritten", + "saveRequestTimedOut": "Speicheranfrage hat das Zeitlimit überschritten", + "reloadRequestTimedOut": "Neuladeanfrage hat das Zeitlimit überschritten", + "noChanges": "Keine Änderungen.", + "noDiffOutput": "Keine Diff-Ausgabe.", + "diffTitleWorkspace": "Diff · Arbeitsbereich", + "diffDescriptionWorkingTree": "Working Tree (HEAD)", + "diffTitleFile": "Unterschied · {name}", + "compareTitleFile": "Vergleich · {name}", + "compareTitleBranch": "Vergleich · {branch}", + "compareDescriptionPath": "{path} · vergleichen mit {branch}", + "compareDescriptionBranch": "vergleichen mit {branch}", + "diffTitleCommitFile": "Unterschied · {name} @ {hash}", + "diffTitleCommit": "Unterschied · {hash}", + "diffDescriptionCommitPath": "{path} · Commit {commit}", + "diffDescriptionCommit": "Commit {commit}", + "diffTitleConflictFile": "Konflikt · {name}", + "diffDescriptionConflict": "{path} · Disk vs ungespeichert" + }, + "chat": { + "acpConnections": { + "actions": { + "openAgentsSettings": "Agenten-Einstellungen öffnen", + "retry": "Erneut versuchen" + }, + "agentsSetupHint": "Öffnen Sie Einstellungen > Agenten, um die Installation zu verwalten.", + "withSetupHint": "{message}\n{hint}", + "blocked": { + "missingConfig": "Aktuelle Agenten-Konfiguration kann nicht gelesen werden.", + "disabled": "{agent} ist in den Agenten-Einstellungen deaktiviert. Aktivieren Sie ihn vor dem Verbinden.", + "unavailable": "{agent} ist auf der aktuellen Plattform nicht verfügbar.", + "sdkMissing": "{agent} SDK ist nicht installiert", + "adapterMissing": "Der ACP-Adapter von {agent} ist nicht installiert" + }, + "backendErrors": { + "initializeTimeout": "Der Verbindungs-Handshake von {agent} hat nach 60 Sekunden das Zeitlimit überschritten. Öffnen Sie die Einstellungen, um Agenten- und Netzwerkkonfiguration zu prüfen.", + "mcpRejectedByAgent": "{agent} hat die Sitzung abgelehnt, während codegs MCP-Begleitprozess angehängt war: {message} Falls dieser Agent MCP nicht unterstützt, deaktivieren Sie „MCP-Unterstützung“ in den Einstellungen und verbinden Sie erneut.", + "processExited": "{agent}-Prozess wurde unerwartet beendet.", + "spawnFailed": "{agent} konnte nicht gestartet werden: {message}", + "downloadFailed": "{agent}-Download fehlgeschlagen: {message}", + "sessionLoadResourceNotFound": "{agent}-Sitzung konnte nicht geladen werden. Neu laden, um es erneut zu versuchen, oder eine neue Konversation starten.", + "sessionLoadUnavailable": "{agent} konnte diese Sitzung nicht wiederherstellen – sie wurde möglicherweise beendet oder der Agent wurde gestoppt. Neu laden, um es erneut zu versuchen, oder eine neue Konversation starten.", + "turnFailedRefusal": "{agent} hat die Fortsetzung dieser Runde abgelehnt. Häufig deutet das auf einen Backend- oder Gateway-Fehler hin. Bitte prüfen Sie die Agent-Logs.", + "turnFailedMaxTokens": "{agent} hat das Token-Limit für diese Runde erreicht.", + "turnFailedMaxTurnRequests": "{agent} hat die maximale Anzahl zulässiger Anfragen für diese Runde erreicht.", + "turnFailedUnknown": "{agent} hat die Runde mit einem unbekannten Stoppgrund beendet.", + "grokModelSwitchIncompatibleAgent": "{agent} kann in einer bestehenden Unterhaltung nicht zu diesem Modell wechseln. Starte eine neue Sitzung, um es zu verwenden.", + "turnFailedEmpty": "{agent} hat die Runde ohne jegliche Antwort beendet.", + "turnFailedEmptyProtocol": "{agent} hat eine Ausgabe erzeugt, die codeg nicht auswerten konnte — die Agent-Version passt möglicherweise nicht zum Protokoll.", + "turnFailedEmptyMetadata": "{agent} hat in dieser Runde nur Statusaktualisierungen gesendet (Plan / Modus / Verbrauch) und keine Antwort.", + "detailsInAlerts": "Öffnen Sie die Warnungen in der Statusleiste und klappen Sie die Details auf, um die Ausgabe des Agents zu sehen." + }, + "unableReadAgentConfig": "Agenten-Konfiguration kann nicht gelesen werden: {message}", + "connectFailedTitle": "{agent} Verbindung fehlgeschlagen", + "toolFallbackTitle": "Werkzeug", + "eventErrorTitle": "Agentenfehler", + "notificationTurnComplete": "{agent} hat die Antwort abgeschlossen", + "notificationError": "{agent} Fehler: {message}", + "claudeApiRetry": { + "fallbackError": "authentication_failed", + "retryingWithMax": "erneuter Versuch {attempt}/{max}", + "retryingAttempt": "erneuter Versuch {attempt}", + "retrying": "erneuter Versuch", + "nextRetryIn": "nächster in {seconds}s", + "line": "{error}{status} · {retry}", + "lineWithDelay": "{error}{status} · {retry}, {delay}", + "httpStatus": " (HTTP {status})" + }, + "configOptionAdjusted": "{agent} hat {option} auf {actual} statt {requested} gesetzt" + }, + "connectionLifecycle": { + "tasks": { + "connectingTitle": "Verbinde mit {agent}", + "connectingDescription": "Verbindung wird hergestellt", + "loadingSelectorsTitle": "{agent}-Selektoren werden geladen", + "loadingSelectorsDescription": "Modus- und Sitzungsoptionen werden abgerufen", + "initSessionTitle": "Initializing {agent} session", + "initSessionDescription": "Creating session and loading configuration" + }, + "errors": { + "connectionFailed": "Verbindung fehlgeschlagen", + "sendPromptFailed": "Nachricht konnte nicht gesendet werden: {error}" + } + }, + "shared": { + "attachedResources": "Angehängte Ressourcen", + "toolCallFailed": "Tool-Aufruf fehlgeschlagen" + }, + "messageThread": { + "emptyTitle": "Noch keine Nachrichten", + "emptyDescription": "Starten Sie eine Unterhaltung, um hier Nachrichten zu sehen" + }, + "chatInput": { + "connecting": "Verbinden...", + "agentResponding": "{agent} antwortet...", + "sendMessage": "Nachricht senden..." + }, + "messageInput": { + "askAnything": "Fragen Sie alles...", + "removeAttachmentAria": "{name} entfernen", + "attachFiles": "Dateien anhängen", + "addActions": "Hinzufügen", + "quickMessages": "Schnellnachrichten", + "quickMessagesEmpty": "Noch keine Schnellnachrichten", + "quickMessagesLoading": "Wird geladen...", + "pasteAsPlainText": "Als reinen Text einfügen", + "cut": "Ausschneiden", + "copy": "Kopieren", + "selectAll": "Alles auswählen", + "pasteUnavailable": "Zwischenablage konnte nicht gelesen werden. Mit Strg/⌘V einfügen.", + "clipboardWriteFailed": "Schreiben in die Zwischenablage fehlgeschlagen. Bitte das Tastenkürzel verwenden.", + "quickMessageUntitled": "Ohne Titel", + "liveFeedback": "Live-Feedback", + "liveFeedbackDisabledHint": "Verfügbar, während der Agent arbeitet", + "dropFilesToAttach": "Dateien zum Anhängen ablegen", + "loadingSettings": "Einstellungen werden geladen...", + "loadingMode": "Modus wird geladen...", + "modeLabel": "Modus", + "toggleOn": "Ein", + "toggleOff": "Aus", + "agentSettings": "Agent-Einstellungen", + "searchModel": "Modelle suchen...", + "searchModelAria": "Modelle suchen", + "modelListLabel": "Modelle", + "noModels": "Keine Modelle gefunden", + "cancel": "Abbrechen", + "send": "Senden", + "forkAndSend": "Fork & Senden", + "queueMessage": "In Warteschlange stellen", + "steerIntoTurn": "In laufenden Turn einfügen", + "steerQueuedInstead": "Stattdessen in die Warteschlange gestellt – wird mit dem nächsten Turn gesendet.", + "steerFailed": "Konnte nicht in den laufenden Turn eingefügt werden", + "steerAttachmentsUnsupported": "Nur Text – Entwürfe mit Anhängen laufen über die Warteschlange.", + "slashCommands": "Slash-Befehle", + "slashSearchPlaceholder": "Befehle suchen...", + "slashSearchEmpty": "Keine passenden Befehle", + "experts": "Experten", + "office": "Büroarbeit", + "research": "Forschung", + "attachLocalUpload": "Lokale Datei hochladen", + "attachServerFile": "Serverdatei auswählen", + "attachUploadTooLarge": "{names} überschreitet das Upload-Limit von {limit}MB und wurde übersprungen.", + "attachUploadFailed": "Upload fehlgeschlagen: {names}.", + "attachUploadNotAFile": "{names} ist keine reguläre Datei (Verzeichnis oder Spezialdatei) und wurde übersprungen.", + "attachUploadQuotaExceeded": "Auf dem Server ist kein Upload-Speicher mehr verfügbar; {names} konnte nicht hochgeladen werden.", + "attachUploadInProgress": "Bilder werden noch hochgeladen – versuche es gleich noch einmal.", + "mentionEmpty": "Keine Treffer", + "mentionLoading": "Suche läuft…", + "mentionListLabel": "Erwähnungen", + "mentionMore": "Weitere Ergebnisse – tippe weiter, um zu filtern", + "mentionCount": "{count, plural, one {# Ergebnis} other {# Ergebnisse}}", + "mentionGroupFile": "Dateien", + "mentionGroupAgent": "Agenten", + "mentionGroupSession": "Sitzungen", + "mentionGroupCommit": "Commits", + "mentionGroupSkill": "Fähigkeiten" + }, + "messageQueue": { + "addToQueue": "Zur Warteschlange", + "saveEdit": "Speichern", + "cancelEdit": "Bearbeitung abbrechen", + "editItem": "Bearbeiten", + "deleteItem": "Entfernen" + }, + "welcomeInputPanel": { + "agentsSettingsPath": "Einstellungen > Agenten", + "autoConnectFallback": "Klicken Sie, um {path} zu öffnen und die Installation zu verwalten.", + "autoConnectAppend": "{message}. Klicken Sie, um {path} zu öffnen und die Installation zu verwalten.", + "enableAgentFirstPlaceholder": "Aktivieren Sie mindestens einen Agenten, bevor Sie eine Sitzung starten...", + "prepareSessionFailed": "Die Chat-Sitzung konnte nicht vorbereitet werden. Bitte versuche es erneut.", + "createConversationFailed": "Die Konversation konnte nicht erstellt werden. Bitte versuche es erneut.", + "askAnythingPlaceholder": "Fragen Sie alles...", + "agentNotInstalled": "{agent} ist nicht installiert · in den Agents-Einstellungen installieren", + "agentAdapterNotInstalled": "Der ACP-Adapter von {agent} ist nicht installiert (unabhängig von deiner eigenen CLI) · in den Agents-Einstellungen installieren" + }, + "welcomePanel": { + "greeting": "Was möchtest du heute machen?", + "tips": { + "tileTabs": "Klicke mit der rechten Maustaste auf einen Konversations-Tab und wähle Kachelansicht, um mehrere Sitzungen nebeneinander zu sehen.", + "pinTab": "Doppelklicke auf einen Konversations-Tab, um ihn anzuheften – so wird er nicht von einer neuen Sitzung automatisch ersetzt.", + "shortcutsNewSearch": "{newConversation} öffnet eine neue Konversation, {searchConversations} durchsucht den Verlauf.", + "slashAtMention": "Tippe / im Eingabefeld für Slash-Befehle oder @, um eine Datei aus dem Projekt zu referenzieren.", + "pasteDropFiles": "Füge einen Screenshot ein oder ziehe eine Datei direkt ins Eingabefeld, um sie anzuhängen.", + "queueMessage": "Während der Agent antwortet, kannst du weitertippen – deine nächste Nachricht wird in die Warteschlange gestellt und automatisch gesendet.", + "draftAutoSave": "Nicht gesendete Entwürfe werden pro Konversation automatisch gespeichert und beim Zurückkehren wiederhergestellt.", + "forkSend": "Im Dropdown der Senden-Schaltfläche gibt es Verzweigen und senden – verzweige vom aktuellen Punkt in einen neuen Tab.", + "exportConversation": "Klicke mit der rechten Maustaste in die Konversation, um sie als Markdown, HTML oder Bild zu exportieren.", + "chatChannels": "Verbinde Telegram / Lark / WeChat unter Einstellungen → Chat-Kanäle, um vom Handy aus weiterzuarbeiten.", + "shortcutsAuxPanel": "{toggleAuxPanel} blendet das rechte Panel ein – mit den geänderten Dateien und Git-Änderungen dieser Sitzung.", + "shortcutsTerminalSidebar": "{toggleTerminal} öffnet das eingebaute Terminal, {toggleSidebar} schaltet die Seitenleiste um.", + "customShortcuts": "Alle Tastenkürzel lassen sich unter Einstellungen → Tastenkürzel frei belegen.", + "webService": "Aktiviere Einstellungen → Webdienst, damit Teammitglieder dasselbe codeg im Browser nutzen können.", + "fusionMode": "Öffne eine Datei oder ein Diff, um es automatisch neben der Konversation zu sehen.", + "quickMessages": "Klicke auf die +-Schaltfläche neben der Eingabe und wähle Schnellnachrichten, um ein gespeichertes Snippet einzufügen (verwaltbar unter Einstellungen → Schnellnachrichten).", + "experts": "Die +-Schaltfläche hat ein Menü Expertenfähigkeiten – lade Rollen wie Debugging oder Planung mit einem Klick.", + "taskBoard": "To-dos führen eine Aufgabe von Anfang bis Ende aus: Der Agent arbeitet in einem eigenen Worktree, du prüfst das Diff und mergest.", + "automations": "Automatisierungen führen einen gespeicherten Prompt nach Zeitplan aus – etwa ein nächtliches Review – und jeder Lauf kann einen eigenen Worktree bekommen.", + "tokenUsage": "Klicke auf die Konversationszahl in der Statusleiste, um den Token-Verbrauch zu öffnen – aufgeschlüsselt nach Tag, Agent, Modell und Ordner.", + "mentionTargets": "@ holt mehr als Dateien: Erwähne einen anderen Agenten, um eine Teilaufgabe abzugeben, oder verweise auf eine frühere Sitzung, einen Commit oder einen Skill.", + "splitGroups": "Rechtsklick auf einen Tab, dann Nach rechts teilen oder Nach unten teilen – so bleiben zwei Konversationen in eigenen Bereichen offen.", + "worktrees": "Öffne die Branch-Schaltfläche und wähle Neuer Worktree, damit mehrere Agenten dasselbe Repository bearbeiten, ohne sich gegenseitig die Dateien zu überschreiben.", + "importSessions": "Schon Sitzungen im Terminal gelaufen? Im Menü eines Ordners holt Lokale Sitzungen importieren diesen Verlauf nach codeg.", + "subSessions": "Delegiert ein Agent, erscheint die Untersitzung in der Seitenleiste verschachtelt darunter – klapp die Zeile auf, um jeder einzeln zu folgen.", + "liveFeedback": "Live-Feedback im +-Menü schiebt eine Notiz in den Zug, den der Agent gerade ausführt – ohne ihn zu unterbrechen.", + "skillPacks": "Einstellungen → Skill-Pakete bündelt Coding-Experten, wissenschaftliche Recherche und Office-Skills – pro Agent aktivierbar.", + "modelProviders": "Einstellungen → Modellanbieter nimmt deinen eigenen API-Key oder Endpunkt entgegen; das Modell wählst du danach direkt im Eingabefeld.", + "workspaceBackground": "Einstellungen → Darstellung setzt ein Hintergrundbild für den Arbeitsbereich, die Panel-Deckkraft und die Schriftarten der App." + }, + "quickActions": { + "excel": "Excel-Arbeitsmappe", + "excelDesc": "Datentabellen, Formeln & Diagramme", + "word": "Word-Dokument", + "wordDesc": "Berichte, Briefe & Memos", + "ppt": "Präsentation", + "pptDesc": "Folien mit professionellem Design", + "pitchDeck": "Pitch Deck", + "pitchDeckDesc": "Investoren-Deck mit Kennzahlen", + "morph": "Morph-Animation", + "morphDesc": "Filmreife Folienübergänge", + "morph3d": "3D-Morph", + "morph3dDesc": "3D-Modelle mit Kamerafahrten", + "academic": "Wissenschaftliche Arbeit", + "academicDesc": "Forschung mit Zitaten & Struktur", + "financial": "Finanzmodell", + "financialDesc": "Abschlüsse, DCF & Prognosen", + "dashboard": "Daten-Dashboard", + "dashboardDesc": "KPIs & Analysen aus deinen Daten", + "prompts": { + "excel": "Erstelle eine Excel-Arbeitsmappe mit den folgenden Anforderungen:\n\n[beschreibe hier deine Daten, Tabellen, Formeln und Diagramme]", + "word": "Erstelle ein Word-Dokument mit den folgenden Anforderungen:\n\n[beschreibe hier Inhalt, Struktur und Formatierung des Dokuments]", + "ppt": "Erstelle eine PowerPoint-Präsentation mit den folgenden Anforderungen:\n\n[beschreibe hier deine Folien, Inhalte und das Design]", + "pitchDeck": "Erstelle ein Investoren-Pitch-Deck mit den folgenden Anforderungen:\n\n[beschreibe hier dein Unternehmen, die Finanzierungsrunde und die wichtigsten Kennzahlen]", + "morph": "Erstelle eine Präsentation mit Morph-Übergangsanimationen:\n\n[beschreibe hier das Thema der Präsentation und die gewünschten visuellen Effekte]", + "morph3d": "Erstelle eine 3D-Morph-Präsentation mit GLB-Modellen und Kamerafahrten:\n\n[beschreibe hier dein Thema und das visuelle 3D-Konzept]", + "academic": "Schreibe eine wissenschaftliche Arbeit in Word mit den folgenden Anforderungen:\n\n[beschreibe hier dein Forschungsthema, die Methodik und die wichtigsten Ergebnisse]", + "financial": "Erstelle ein Finanzmodell in Excel mit den folgenden Anforderungen:\n\n[beschreibe hier deine Finanzabschlüsse, Prognosen und Analysen]", + "dashboard": "Erstelle ein Daten-Dashboard in Excel mit den folgenden Anforderungen:\n\n[beschreibe hier deine Datenquelle, KPIs und Diagramme]", + "scientific-brainstorming": "Hilf mir beim Brainstorming von Forschungsrichtungen — erkunde interdisziplinäre Verbindungen, hinterfrage Annahmen und finde vielversprechende Lücken. Mein Themenbereich: ", + "hypothesis-generation": "Hilf mir, diese Beobachtungen in prüfbare Hypothesen zu überführen — mit klaren Vorhersagen, plausiblen Mechanismen und Experimenten. Meine Beobachtungen: ", + "experimental-design": "Hilf mir, vor der Datenerhebung ein rigoroses Experiment zu planen — Design, Randomisierung, Kontrollen und wie man Confounding vermeidet. Was ich untersuchen möchte: ", + "statistical-power": "Hilf mir, die benötigte Stichprobengröße zu bestimmen — führe mich durch eine Poweranalyse (Effektstärke, Alpha, Power) für mein Design. Details: ", + "statistical-analysis": "Hilf mir, diese Daten korrekt zu analysieren — den richtigen Test wählen, Annahmen prüfen, Effektstärken berichten und alles aufschreiben. Meine Daten und Frage: ", + "exploratory-data-analysis": "Führe eine explorative Analyse meiner Datendatei durch — fasse Struktur, Qualität und auffällige Muster zusammen und schlage nächste Schritte vor. Die Datei ist: ", + "scientific-visualization": "Hilf mir, eine publikationsreife Abbildung zu erstellen — klares Layout, ehrliche Fehlerbalken, eine farbenblindensichere Palette und Journal-Formatierung. Was ich zeigen möchte: ", + "scientific-critical-thinking": "Hilf mir, diese Studie oder Behauptung kritisch zu bewerten — beurteile die Evidenzqualität, erkenne Verzerrungen und Confounder und wäge die Schlussfolgerungen ab. Hier ist sie: ", + "paper-lookup": "Hilf mir, relevante Artikel und Open-Access-Volltexte in wissenschaftlichen Datenbanken zu finden, mit wiederverwendbaren Zitaten. Ich suche: " + }, + "paper-lookup": "Publikationssuche", + "paper-lookupDesc": "10 wissenschaftliche APIs (PubMed, arXiv, OpenAlex, Crossref…) nach Artikeln, Zitationen und Open-Access-Volltext durchsuchen.", + "scientific-critical-thinking": "Kritisches Denken", + "scientific-critical-thinkingDesc": "Wissenschaftliche Aussagen und Evidenzqualität beurteilen — Verzerrungen und Confounder erkennen, GRADE anwenden.", + "scientific-visualization": "Wissenschaftliche Visualisierung", + "scientific-visualizationDesc": "Publikationsreife Abbildungen — Mehrfeld-Layouts, Signifikanz-Annotationen und journalspezifische Formate.", + "exploratory-data-analysis": "Explorative Datenanalyse", + "exploratory-data-analysisDesc": "Automatisierte Exploration wissenschaftlicher Datendateien in über 200 Formaten mit Qualitätsmetriken und Berichten.", + "statistical-analysis": "Statistische Analyse", + "statistical-analysisDesc": "Geführte statistische Analyse — Testauswahl, Annahmenprüfung, Effektstärken und Bericht im APA-Stil.", + "statistical-power": "Teststärke", + "statistical-powerDesc": "Stichprobengröße und Teststärke — benötigte Fallzahl, minimal nachweisbare Effekte und Powerkurven.", + "experimental-design": "Versuchsplanung", + "experimental-designDesc": "Rigorose Studien vor der Datenerhebung planen — Randomisierung, Blockbildung, Kontrollen und faktorielle/DOE-Designs.", + "hypothesis-generation": "Hypothesengenerierung", + "hypothesis-generationDesc": "Beobachtungen in prüfbare Hypothesen mit Vorhersagen, Mechanismen und Experimenten überführen.", + "scientific-brainstorming": "Wissenschaftliches Brainstorming", + "scientific-brainstormingDesc": "Offene Forschungsideen — interdisziplinäre Verbindungen erkunden, Annahmen hinterfragen, Forschungslücken finden.", + "tabs": { + "office": "Büroarbeit", + "coding": "Code-Entwicklung", + "research": "Forschung" + }, + "coding": { + "brainstormingDesc": "Absicht & Anforderungen vor dem Bauen klären", + "debuggingDesc": "Erst die Ursache finden, dann Fixes vorschlagen", + "writingSkillsDesc": "Wiederverwendbare Skills erstellen, bearbeiten & prüfen" + }, + "notEnabled": { + "title": "Skill „{skill}“ ist für {agent} noch nicht aktiviert", + "description": "Aktiviere ihn in den Einstellungen, um ihn hier zu nutzen.", + "action": "Aktivieren", + "hint": "Skill nicht aktiviert" + }, + "scrollPrev": "Vorherige Skills anzeigen", + "scrollNext": "Weitere Skills anzeigen" + } + }, + "agentSelector": { + "noEnabledAgents": "Keine aktivierten Agenten", + "openAgentsSettings": "Agenten-Einstellungen öffnen", + "notInstalled": "Nicht installiert", + "moreAgents": "Weitere Agenten ({count})" + }, + "subAgentOverlay": { + "title": "Subagenten", + "collapsedSummary": "Subagenten {count}", + "collapseAria": "Subagenten einklappen" + }, + "agentPlanOverlay": { + "title": "Agentenplan", + "collapsePlanAria": "Plan einklappen", + "collapsedSummary": "Arbeitsplan {completed}/{total}", + "status": { + "completed": "Abgeschlossen", + "inProgress": "In Bearbeitung", + "pending": "Ausstehend", + "unknown": "Unbekannt" + }, + "priority": { + "high": "Hoch", + "medium": "Mittel", + "low": "Niedrig", + "unknown": "Unbekannt" + } + }, + "permissionDialog": { + "subtitle": "Agent fordert Berechtigung an, um diesen Zug fortzusetzen.", + "queuedCount": "+{count} wartend", + "kindFallbackTool": "Tool", + "command": "Befehl", + "cwd": "Arbeitsverzeichnis: {cwd}", + "filesSummary": "Dateien: {count}", + "moreFiles": "+{count} weitere Dateien", + "plan": "Arbeitsplan", + "allowedActions": "Erlaubte Aktionen", + "targetMode": "Zielmodus: {mode}", + "optionGrants": "Was jede Option gewährt", + "changeScopeSession": "Diese Sitzung", + "changeScopeProcess": "Dieser Lauf", + "changeScopeUser": "In Benutzereinstellungen gespeichert", + "changeScopeProject": "In Projekteinstellungen gespeichert", + "changeScopeProjectLocal": "In lokalen Projekteinstellungen gespeichert", + "changeScopePersistent": "Dauerhaft gespeichert" + }, + "questionDialog": { + "title": "Agent stellt eine Frage", + "placeholder": "Antwort eingeben...", + "send": "Senden" + }, + "messageBranch": { + "previousBranchAria": "Vorheriger Branch", + "nextBranchAria": "Nächster Branch", + "pageOf": "{current} von {total}" + }, + "terminal": { + "title": "Konsole", + "running": "Läuft" + }, + "reasoning": { + "thinking": "Denkt nach…", + "thoughtForFewSeconds": "Nachgedacht", + "thoughtForSeconds": "Nachgedacht" + }, + "linkSafety": { + "errorCannotOpen": "Lokale Datei kann nicht geöffnet werden", + "errorNoWorkspace": "Es ist kein Arbeitsbereichsordner aktiv.", + "errorFailedOpen": "Lokale Datei konnte nicht geöffnet werden", + "errorFailedLink": "Link konnte nicht geöffnet werden", + "errorUnsupportedLinkProtocol": "Dieses Linkprotokoll wird nicht unterstützt." + }, + "fileActions": { + "openInFinder": "In Finder öffnen", + "openInExplorer": "In Explorer öffnen", + "openInFileManager": "Im Dateimanager öffnen", + "copyRelativePath": "Relativen Pfad kopieren", + "copyAbsolutePath": "Absoluten Pfad kopieren", + "pathCopied": "Pfad kopiert", + "copyPathFailed": "Pfad konnte nicht kopiert werden", + "openFailed": "Lokale Datei konnte nicht geöffnet werden" + }, + "messageList": { + "attachedResources": "Angehängte Ressourcen", + "loading": "Lädt...", + "loadEarlier": "Frühere Nachrichten laden", + "loadingEarlier": "Frühere Nachrichten werden geladen…", + "error": "Fehler: {message}", + "errorTitle": "Sitzung konnte nicht geladen werden", + "errorActionReload": "Neu laden", + "errorActionNewSession": "Neue Konversation", + "emptyConversation": "Keine Nachrichten in dieser Unterhaltung.", + "systemMessage": "Systemnachricht", + "copyMessage": "Kopieren", + "copied": "Kopiert", + "downloadImage": "Bild herunterladen", + "downloadFailed": "Download fehlgeschlagen: {message}", + "imageGeneration": "Bildgenerierung", + "imageGenerationPending": "Bild wird generiert…", + "imageGenerationFailed": "Bildgenerierung fehlgeschlagen", + "model": "Modell", + "tokenStats": "Token-Nutzung", + "tokenInput": "Eingabe", + "tokenOutput": "Ausgabe", + "tokenCacheRead": "Cache-Lesen", + "tokenCacheWrite": "Cache-Schreiben", + "duration": "Dauer", + "completedAt": "Abgeschlossen um", + "jumpToPreviousUserMessage": "Zur Benutzernachricht springen", + "showMore": "Mehr anzeigen", + "showLess": "Weniger anzeigen" + }, + "liveTurnStats": { + "thinking": "Denkt nach...", + "streaming": "Übertragung", + "elapsedHours": "{value} Std", + "elapsedMinutes": "{value} Min", + "elapsedSeconds": "{value} Sek", + "outputSpeedAria": "Geschätzte Ausgabegeschwindigkeit", + "outputSpeedTooltip": "Geschätzte Ausgabegeschwindigkeit (Text + Denken)" + }, + "jsonTree": { + "viewRaw": "Rohes JSON anzeigen", + "viewTree": "Baum anzeigen", + "fields": "{count, plural, one {# Feld} other {# Felder}}", + "items": "{count, plural, one {# Eintrag} other {# Einträge}}" + }, + "tool": { + "parameters": "Parameter", + "error": "Fehler", + "result": "Ergebnis", + "status": { + "approvalRequested": "Warten auf Genehmigung", + "approvalResponded": "Beantwortet", + "inputAvailable": "Läuft", + "inputStreaming": "Ausstehend", + "outputAvailable": "Abgeschlossen", + "outputDenied": "Abgelehnt", + "outputError": "Fehler" + } + }, + "toolCallBlock": { + "tool": "Werkzeug", + "error": "Fehler", + "result": "Ergebnis" + }, + "delegation": { + "subAgentRunning": "Unteragent läuft…", + "noDetail": "No detail available yet.", + "unknownAgent": "Sub-Agent", + "openDetail": "Konversation anzeigen", + "detailTitle": "Unteragent-Konversation", + "detailDescription": "Schreibgeschützte Ansicht der delegierten Unteragent-Konversation.", + "waitForResult": "Warte auf das Ergebnis von Aufgabe {task}", + "waitForResultNoTask": "Warte auf das Aufgabenergebnis", + "cancelTask": "Aufgabe {task} wird abgebrochen", + "cancelTaskNoTask": "Aufgabe wird abgebrochen", + "resultPageOf": "{current} / {total}", + "prevResult": "Vorheriges Ergebnis", + "nextResult": "Nächstes Ergebnis", + "noResultText": "Kein Ergebnis bei dieser Prüfung.", + "status": { + "starting": "startet", + "running": "läuft", + "checked": "geprüft", + "waiting": "Genehmigung ausstehend", + "ok": "fertig", + "err": { + "default": "fehlgeschlagen", + "delegation_disabled": "deaktiviert", + "depth_limit": "Tiefenlimit", + "invalid_agent_type": "ungültiger Agent", + "spawn_failed": "Start fehlgeschlagen", + "send_failed": "Senden fehlgeschlagen", + "timeout": "Zeitüberschreitung", + "canceled": "abgebrochen", + "child_refusal": "Subagent verweigerte", + "child_max_tokens": "Subagent: Token-Limit", + "child_max_turn_requests": "Subagent: Anfragelimit", + "child_empty": "Subagent ohne Ausgabe", + "child_unknown": "Subagent: Fehler", + "unknown": "unbekannte Aufgabe" + } + } + }, + "contentParts": { + "showingTailOutput": "Zur besseren Performance wird während des Streamings nur die Endausgabe angezeigt.", + "result": "Ergebnis", + "unknown": "unbekannt", + "inputTruncated": "Eingabe wurde gekürzt — Diff ist möglicherweise unvollständig.", + "replaceAll": "ALLES ERSETZEN", + "filesCount": "Dateien: {count}", + "update": "aktualisieren", + "moreFiles": "+{count} weitere Dateien", + "timeoutMs": "Zeitlimit: {timeout}ms", + "backgroundTrue": "Hintergrund: true", + "scriptToolCalls": "{count, plural, one {# Tool-Aufruf} other {# Tool-Aufrufe}}", + "offset": "Versatz: {offset}", + "limit": "Grenze: {limit}", + "pages": "Seiten: {pages}", + "mode": "Modus: {mode}", + "cell": "Zelle: {cell}", + "shellSession": "Sitzung {id}", + "pathLabel": "Pfad:", + "globLabel": "Glob-Muster:", + "typeLabel": "Typ:", + "outputLabel": "Ausgabe:", + "caseInsensitive": "Groß-/Kleinschreibung ignorieren", + "multiline": "Mehrzeilig", + "promptLabel": "Eingabe", + "subjectLabel": "Betreff", + "taskLabel": "Aufgabe", + "nameLabel": "Bezeichnung:", + "agentPromptLabel": "Eingabe", + "agentModelLabel": "Modell", + "agentRunning": "Läuft...", + "agentLiveTranscript": "Live-Aktivität", + "agentProgressTools": "{count} Tool-Aufrufe", + "agentProgressTurns": "{count} Runden", + "agentProgressContext": "Kontext {pct}%", + "agentSessionAction": "Subagent-Sitzung ansehen", + "agentSessionTitle": "Subagent-Sitzung", + "agentSessionLoading": "Protokoll des Subagenten wird geladen…", + "agentSessionEmpty": "Der Subagent hat noch nichts geschrieben.", + "agentFallbackTitle": "Sub-Agent wird gestartet…", + "agentCodexLaunchOnly": "Gestartet. Codex meldet keinen weiteren Fortschritt dieses Sub-Agenten – sein Ergebnis trifft als Nachricht in dieser Unterhaltung ein.", + "agentStatsBash": "Befehle", + "agentStatsRead": "Dateien gelesen", + "agentStatsSearch": "Suchen", + "agentStatsEdit": "Bearbeitungen", + "agentStatsOther": "Sonstige", + "goal": { + "title": "Ziel:", + "titleWithStatus": "Ziel {status}", + "objective": "Ziel", + "statusLabel": "Status", + "tokensUsed": "Verwendete tokens", + "budget": "Budget", + "remaining": "Verbleibend", + "elapsed": "Verstrichen", + "tokens": "tokens", + "pause": "Pausieren", + "clear": "Löschen", + "status": { + "active": "aktiv", + "paused": "pausiert", + "blocked": "blockiert", + "usageLimited": "Nutzung begrenzt", + "budgetLimited": "Budget begrenzt", + "complete": "abgeschlossen", + "limited": "Limit erreicht" + } + }, + "field": { + "file": "Datei", + "notebook": "Notizbuch", + "command": "Befehl", + "old": "Alt", + "new": "Neu", + "pattern": "Muster", + "path": "Pfad", + "query": "Abfrage", + "url": "URL:", + "description": "Beschreibung", + "content": "Inhalt", + "source": "Quelle", + "prompt": "Eingabe", + "subject": "Betreff", + "taskId": "Aufgaben-ID", + "status": "Zustand", + "skill": "Skill", + "args": "Argumente", + "offset": "Versatz", + "limit": "Grenze", + "glob": "Glob-Muster", + "type": "Typ", + "output": "Ausgabe", + "replaceAll": "Alles ersetzen", + "language": "Sprache", + "timeout": "Zeitlimit", + "background": "Hintergrund", + "agentType": "Agent-Typ", + "library": "Bibliothek", + "libraryId": "Bibliotheks-ID" + }, + "title": { + "edit": "Bearbeiten", + "command": "Befehl", + "script": "Skript", + "waitCommand": "Warten {command}", + "waitCell": "Sitzung {id} abwarten", + "terminateCommand": "Beenden {command}", + "terminateCell": "Sitzung {id} beenden", + "stdinChars": "Eingabe {chars}", + "todoWrite": "TodoWrite (Aufgaben aktualisieren)", + "read": "Lesen", + "write": "Schreiben", + "notebookEdit": "NotebookEdit (Notizbuch bearbeiten)", + "editFiles": "Bearbeiten ({count} Dateien)", + "editWithTarget": "{target} bearbeiten", + "readWithTarget": "{target} lesen", + "writeWithTarget": "{target} schreiben", + "notebookEditWithTarget": "NotebookEdit ({target})", + "globWithPattern": "Glob-Muster {pattern}", + "listFilesWithPath": "Dateien auflisten {path}", + "grepWithPattern": "Grep-Muster {pattern}", + "taskCreateWithSubject": "Aufgabe erstellen: {subject}", + "taskUpdateWithStatus": "Aufgabe aktualisieren #{id} -> {status}", + "taskUpdate": "Aufgabe aktualisieren #{id}", + "webFetchWithUrl": "WebFetch ({url})", + "webSearchWithQuery": "Websuche: {query}", + "todosProgress": "Aufgaben ({done}/{total})", + "skillWithName": "Skill: {name}", + "genericWithContext": "{tool} ({context})" + }, + "search": { + "noMatches": "Keine Treffer", + "matchSummary": "{matches, plural, one {# Treffer} other {# Treffer}} in {files, plural, one {# Datei} other {# Dateien}}", + "fileSummary": "{files, plural, one {# Datei} other {# Dateien}}", + "moreResults": "{count, plural, one {# weiteres Ergebnis nicht angezeigt} other {# weitere Ergebnisse nicht angezeigt}}" + }, + "toolGroup": { + "search": "{count, plural, one {# Suche durchgeführt} other {# Suchen durchgeführt}}", + "command": "{count, plural, one {# Befehl ausgeführt} other {# Befehle ausgeführt}}", + "read": "{count, plural, one {Dateien # Mal gelesen} other {Dateien # Mal gelesen}}", + "memory": "{count, plural, one {# Erinnerung abgerufen} other {# Erinnerungen abgerufen}}", + "edit": "{count, plural, one {Dateien # Mal bearbeitet} other {Dateien # Mal bearbeitet}}", + "fetch": "{count, plural, one {# Ressource abgerufen} other {# Ressourcen abgerufen}}", + "think": "{count, plural, one {# Mal nachgedacht} other {# Mal nachgedacht}}", + "todo": "{count, plural, one {# Aufgabe aktualisiert} other {# Aufgaben aktualisiert}}", + "task": "{count, plural, one {# Aufgabe ausgeführt} other {# Aufgaben ausgeführt}}", + "other": "{count, plural, one {# Werkzeug verwendet} other {# Werkzeuge verwendet}}", + "errorSuffix": "{count, plural, one {# fehlgeschlagen} other {# fehlgeschlagen}}", + "joiner": " · " + }, + "planMode": { + "entered": "Planungsmodus gestartet", + "planLabel": "Plan", + "reviewApproved": "Plan genehmigt – wird umgesetzt", + "reviewKept": "Im Planmodus geblieben", + "reviewPending": "Warte auf Planentscheidung", + "submitted": "Plan eingereicht", + "switched": "Modus gewechselt" + }, + "backgroundTask": { + "title": "Hintergrundaufgabe", + "titleWithId": "Hintergrundaufgabe · {id}", + "running": "Läuft", + "completed": "Abgeschlossen", + "failed": "Fehlgeschlagen", + "stopped": "Gestoppt", + "exitCode": "Exit {code}", + "polledTimes": "{count}-mal abgefragt", + "runningInBackground": "Hintergrund", + "launchNote": "Läuft im Hintergrund · {id}" + }, + "codexScript": { + "outputMissing": "Codex hat die Skriptausgabe gekürzt und dabei das Trennzeichen dieses Befehls entfernt, sodass ihm keine Ausgabe zugeordnet werden konnte.", + "sharedWith": "Enthält auch die Ausgabe von {commands} – codex hat deren Trennzeichen abgeschnitten.", + "truncated": "gekürzt" + } + }, + "messageNav": { + "title": "Nachrichtennavigation", + "collapse": "Nachrichtennavigation ausblenden", + "collapsedSummary": "Nachrichten {count}", + "fileCount": "{count, plural, one {# Datei} other {# Dateien}}", + "remove": "Entfernen", + "noDiffDataAvailable": "Keine Diff-Daten verfügbar für {filePath}" + }, + "replyArtifacts": { + "title": "Geänderte Dateien", + "fileCount": "{count, plural, one {# Datei} other {# Dateien}}", + "newFilesTitle": "Neue Dateien", + "revealInFolder": "Im Dateimanager anzeigen", + "openFile": "{filePath} öffnen", + "openInEditor": "Im Editor öffnen", + "remove": "Entfernen", + "noDiffDataAvailable": "Keine Diff-Daten verfügbar für {filePath}" + }, + "askQuestion": { + "title": "Der Agent benötigt deine Auswahl", + "subtitle": "Antworten und absenden. Du kannst jederzeit überspringen.", + "recommended": "Empfohlen", + "other": "Andere", + "otherPlaceholder": "Antwort eingeben…", + "singleSelect": "Einfach", + "multiSelect": "Mehrfach", + "skip": "Überspringen", + "next": "Weiter", + "submit": "Senden", + "submitError": "Senden fehlgeschlagen. Bitte versuche es erneut." + }, + "planApproval": { + "title": "Der Agent hat einen Plan – bitte prüfen", + "emptyPlan": "Der Agent hat keinen Plan geschrieben. Genehmige, um zu starten, oder fordere Änderungen an.", + "approve": "Genehmigen & starten", + "requestChanges": "Änderungen anfordern", + "abandon": "Verwerfen", + "feedbackPlaceholder": "Was soll geändert werden?", + "sendChanges": "Senden", + "cancel": "Abbrechen", + "submitError": "Senden fehlgeschlagen. Bitte erneut versuchen." + }, + "feedbackCheckResult": { + "count": "{count, plural, =1 {1 Rückmeldung} other {# Rückmeldungen}}", + "expand": "Alle Rückmeldungen anzeigen", + "collapse": "Einklappen", + "errorTitle": "Feedback-Prüfung fehlgeschlagen" + }, + "askQuestionResult": { + "title": "Frage", + "answeredLabel": "Frage & Antwort:", + "awaiting": "Warten auf deine Antwort…", + "declined": "Du hast dies verworfen – der Agent hat nach eigenem Ermessen entschieden.", + "noSelection": "Keine Auswahl" + }, + "configStale": { + "agentConfigTitle": "Agent-Einstellungen aktualisiert", + "modelProviderTitle": "Modellanbieter aktualisiert", + "description": "Diese Sitzung verwendet weiterhin die bisherige Konfiguration. Zum Anwenden neu verbinden (der Gesprächsverlauf bleibt erhalten).", + "reconnect": "Zum Anwenden neu verbinden", + "reconnecting": "Wird neu verbunden…", + "reconnectDisabledDuringTurn": "Verfügbar, sobald die aktuelle Runde abgeschlossen ist", + "dismiss": "Schließen", + "reconnectFailed": "Sitzung konnte nicht neu verbunden werden", + "applied": "Neue Konfiguration angewendet" + }, + "piProjectTrust": { + "title": "Dieses Projekt enthält pi-Ressourcen", + "description": "pi lädt die .pi-Dateien des Repositorys nicht. Prüfe sie, um zu entscheiden.", + "descriptionExecutable": "Das Repository enthält pi-Erweiterungen, die beim Start Code ausführen. pi lädt sie nicht. Prüfe sie, bevor du entscheidest.", + "review": "Prüfen…", + "dismiss": "Ausblenden", + "dialogTitle": "Den pi-Ressourcen dieses Projekts vertrauen?", + "dialogDescription": "pi lädt die .pi-Dateien eines Repositorys nur, wenn du dem Ordner vertraust. Vertraue nur, wenn du dem Inhalt dieses Repositorys vertraust.", + "executionWarning": "Erweiterungen sind Code. Wenn du diesem Ordner vertraust, führt das Repository sie beim Start von pi mit deinen Rechten aus – noch bevor du eine Nachricht sendest.", + "scopeNote": "Die Entscheidung wird in der trust.json von pi für diesen Ordner gespeichert, gilt für alle darin enthaltenen Ordner und wird auch verwendet, wenn du pi selbst im Terminal startest. Du kannst sie später unter Einstellungen → Agenten → Pi ändern.", + "trust": "Projekt vertrauen", + "decline": "Nicht laden", + "disabledDuringTurn": "Verfügbar, sobald der aktuelle Zug beendet ist", + "trustedToast": "Projekt vertraut – neu verbunden, damit pi seine Ressourcen lädt", + "declinedToast": "Projektressourcen bleiben ungeladen", + "saveFailed": "Die Vertrauensentscheidung für das Projekt konnte nicht gespeichert werden", + "grantTitle": "Diesem Projekt wird bereits vertraut", + "grantDescription": "pi lädt die .pi-Dateien dieses Repositorys. Sieh dir an, was das erlaubt.", + "grantInheritedDescription": "Einem übergeordneten Ordner wird vertraut, daher lädt pi die .pi-Dateien dieses Repositorys. Sieh dir an, was das erlaubt.", + "grantDialogTitle": "Den pi-Ressourcen dieses Projekts wird vertraut", + "grantDialogDescription": "pi darf die .pi-Dateien dieses Repositorys laden. Frühere codeg-Versionen haben das beim Öffnen eines Ordners automatisch erteilt, du wurdest also womöglich nie gefragt.", + "grantExecutionWarning": "Erweiterungen sind Code. Das Repository führt sie beim Start von pi mit deinen Rechten aus, bevor du eine Nachricht sendest.", + "inheritedFrom": "Vertraut über", + "revoke": "Vertrauen widerrufen", + "keepTrusted": "Vertrauen behalten", + "revokedToast": "Vertrauen widerrufen – neu verbunden, damit pi die Projektressourcen nicht mehr lädt", + "trustedNoReconnect": "Projekt vertraut – gilt ab dem nächsten Start von pi", + "revokedNoReconnect": "Vertrauen widerrufen – gilt ab dem nächsten Start von pi" + }, + "collabAgent": { + "title": "Subagent", + "errorTitle": "Subagent-Aufgabe fehlgeschlagen", + "statesLabel": "Subagenten", + "statusRunning": "Läuft", + "statusCompleted": "Abgeschlossen", + "statusFailed": "Fehlgeschlagen", + "statusPending": "Wird gestartet", + "statusInterrupted": "Unterbrochen", + "statusClosed": "Geschlossen", + "statusNotFound": "Nicht gefunden", + "opSpawn": "Sub-Agent wird gestartet", + "opWait": "Sub-Agent-Ergebnis wird abgerufen", + "opClose": "Sub-Agent wird geschlossen", + "opResume": "Sub-Agent wird fortgesetzt" + }, + "contextCompaction": { + "compacting": "Kontext wird komprimiert…", + "compacted": "Kontext komprimiert", + "compactedTokens": "Kontext komprimiert · {before} → {after} Tokens", + "failed": "Kontextkomprimierung fehlgeschlagen" + }, + "sessionFailure": { + "category": { + "connection": "Verbindungsproblem", + "access": "Zugriffsproblem", + "limit": "Limit erreicht", + "request": "Anfrage abgelehnt", + "service": "Dienstproblem", + "unknown": "Sitzungsproblem" + }, + "action": { + "retry": "Erneut versuchen", + "login": "Anmelden", + "newSession": "Neue Sitzung" + }, + "recovered": "Wiederhergestellt", + "retryUnavailable": "Keine vorherige Nachricht zum erneuten Senden.", + "toggleDetails": "Details umschalten" + }, + "backgroundTasks": { + "running": "{count, plural, one {# Hintergrundaufgabe läuft} other {# Hintergrundaufgaben laufen}}", + "settling": "Hintergrundergebnisse werden synchronisiert…", + "settledFallback": "Hintergrundaufgabe beendet ({status})", + "cardRunning": "Läuft im Hintergrund", + "cardLaunchedPending": "Hintergrundaufgabe gestartet", + "cardCompleted": "Hintergrundaufgabe abgeschlossen", + "cardFinishedWithStatus": "Hintergrundaufgabe beendet ({status})", + "cardResultPending": "Ergebnis steht noch aus" + }, + "proposedPlan": { + "title": "Vorgeschlagener Plan", + "planning": "Wird geplant…" + } + }, + "diffPreview": { + "mode": { + "added": "Hinzugefügt", + "deleted": "Gelöscht", + "renamed": "Umbenannt", + "modified": "Geändert" + }, + "hunkLabel": "Block {index}", + "loadingHunk": "Hunk wird geladen...", + "noDiffData": "Keine Diff-Daten", + "showRemainingLines": "{count} weitere Zeilen anzeigen" + }, + "conversationContextBar": { + "folderTitle": "Arbeitsordner", + "branchTitle": "Arbeits-Branch", + "searchFolder": "Search folder...", + "searchBranch": "Search branch...", + "noFolders": "No folders", + "noBranches": "No branches", + "noBranch": "(no branch)", + "chatModeLabel": "Chat-Modus", + "commit": "Commit", + "push": "Push", + "merge": "Merge", + "toasts": { + "folderChanged": "Switched to {name}", + "openFolderFailed": "Failed to open folder", + "switchedToChatMode": "In den Chat-Modus gewechselt", + "openStashFailed": "Failed to open stash window", + "openMergeFailed": "Failed to open merge window" + } + }, + "cloneDialog": { + "title": "Repository klonen", + "repositoryUrl": "Repository-URL", + "repositoryUrlPlaceholder": "https://github.com/user/repo.git", + "directory": "Verzeichnis", + "directoryPlaceholder": "Zielverzeichnis auswählen...", + "browseDirectory": "Verzeichnis durchsuchen", + "cancel": "Abbrechen", + "clone": "Klonen", + "clonePath": "Klonpfad: {path}" + }, + "toasts": { + "cloneFailed": "Repository konnte nicht geklont werden" + } + }, + "ProjectBoot": { + "title": "Projekt-Starter", + "tabs": { + "shadcn": "shadcn", + "hyperframes": "HyperFrames" + }, + "hyperframes": { + "title": "HyperFrames-Videoprojekt", + "subtitle": "Erstelle ein HTML-zu-Video-Projekt. Der Agent im Arbeitsbereich kann es dann schreiben und rendern.", + "resolution": "Auflösung", + "skillsTitle": "Agenten-Skills", + "skillsDesc": "Installiert die HyperFrames-Skills global (Symlink) für die ausgewählten Agenten, damit sie Videos erstellen und rendern können.", + "recheck": "Erneut prüfen", + "installedBadge": "Installiert", + "skillsInstall": "Skills installieren / aktualisieren", + "skillsInstalling": "Skills werden installiert…", + "skillsInstalled": "HyperFrames-Skills installiert", + "skillsInstallFailed": "HyperFrames-Skills konnten nicht installiert werden" + }, + "config": { + "base": "Basis", + "style": "Stil", + "baseColor": "Basisfarbe", + "theme": "Thema", + "chartColor": "Diagrammfarbe", + "iconLibrary": "Icon-Bibliothek", + "font": "Schriftart", + "fontHeading": "Überschrift-Schriftart", + "menuAccent": "Menü-Akzent", + "menuColor": "Menü-Farbe", + "radius": "Radius", + "template": "Vorlage", + "createProject": "Projekt erstellen", + "sectionStyle": "Stil", + "sectionColors": "Farben", + "sectionTypography": "Typografie", + "sectionInterface": "Oberfläche" + }, + "preview": { + "loading": "Vorschau wird geladen..." + }, + "createDialog": { + "title": "Projekt erstellen", + "projectName": "Projektname", + "projectNamePlaceholder": "my-app", + "frameworkTemplate": "Framework-Vorlage", + "packageManager": "Paketmanager", + "saveDirectory": "Speicherverzeichnis", + "saveDirectoryPlaceholder": "Verzeichnis auswählen...", + "browseDirectory": "Durchsuchen", + "projectPath": "Projekt wird erstellt in: {path}", + "advancedOptions": "Erweiterte Optionen", + "base": "Basisbibliothek", + "enableRtl": "RTL-Unterstützung aktivieren", + "enableRtlDescription": "Layout-Unterstützung für Rechts-nach-links-Sprachen (z.B. Arabisch, Hebräisch) aktivieren", + "pmChecking": "Wird überprüft...", + "pmNotInstalled": "Nicht installiert", + "cancel": "Abbrechen", + "create": "Erstellen", + "creating": "Projekt wird erstellt..." + }, + "toasts": { + "createFailed": "Projekt konnte nicht erstellt werden", + "createSuccess": "Projekt erfolgreich erstellt", + "openWorkspaceFailed": "Projekt erstellt, konnte aber nicht im Arbeitsbereich geöffnet werden" + }, + "errors": { + "directoryExists": "Zielverzeichnis existiert bereits", + "commandFailed": "Projekterstellungsbefehl fehlgeschlagen." + } + }, + "WebServiceSettings": { + "addressSwitchHint": "Das Umschalten ändert nur die hier angezeigte und geöffnete Adresse – der Dienst lauscht auf allen Schnittstellen und bleibt unter jeder Adresse erreichbar.", + "sectionTitle": "Webdienst", + "sectionDescription": "Aktivieren Sie den Fernzugriff auf Codeg über den Browser", + "port": "Port", + "status": "Status", + "autoStart": "Automatisch starten", + "autoStartHint": "Webdienst beim Start von Codeg starten", + "running": "Läuft", + "stopped": "Gestoppt", + "processing": "Verarbeitung...", + "start": "Starten", + "stop": "Stoppen", + "startFailed": "Start fehlgeschlagen", + "stopFailed": "Stopp fehlgeschlagen", + "saveConfigFailed": "Webdienst-Einstellungen konnten nicht gespeichert werden", + "open": "Öffnen", + "hide": "Ausblenden", + "show": "Einblenden", + "copy": "Kopieren", + "qrcode": "QR-Code", + "qrcodeTitle": "Zum Öffnen scannen", + "qrcodeHint": "Scanne mit deinem Handy, um Codeg im Browser zu öffnen", + "addressLabel": "Zugriffsadresse", + "tokenLabel": "Zugriffstoken", + "tokenHint": "Geben Sie dieses Token beim ersten Zugriff auf den Web-Client ein", + "tokenPlaceholder": "Leer lassen für automatische Generierung", + "regenerate": "Neu generieren", + "stalePortOccupiedTitle": "Port {port} wird von einem anderen Prozess belegt", + "stalePortUnknownTitle": "Status von Port {port} unklar", + "stalePortHint": "Codeg kann sich nicht binden, bis der Port freigegeben ist. Ändere den Port oben oder beende den Prozess, der ihn hält.", + "errors": { + "alreadyRunning": "Der Web-Dienst läuft bereits", + "invalidAddress": "Host- oder Portformat ungültig", + "portInUse": "Port {port} wird bereits verwendet. Beenden Sie den Prozess oder wählen Sie einen anderen Port.", + "permissionDenied": "Zugriff verweigert. Verwenden Sie einen Port über 1024 oder starten Sie mit höheren Rechten.", + "addressUnavailable": "Die Adresse ist auf diesem Computer nicht verfügbar", + "bindFailed": "Adresse konnte nicht gebunden werden" + } + }, + "DirectoryBrowser": { + "title": "Verzeichnis durchsuchen", + "pathPlaceholder": "Verzeichnispfad eingeben...", + "goHome": "Zum Heimverzeichnis", + "navigateUp": "Zum übergeordneten Verzeichnis", + "select": "Auswählen", + "cancel": "Abbrechen", + "loading": "Wird geladen...", + "emptyDirectory": "Dieses Verzeichnis ist leer", + "errorLoadingDir": "Verzeichnis konnte nicht geladen werden", + "permissionDenied": "Zugriff verweigert" + }, + "ChatChannelSettings": { + "loading": "Wird geladen...", + "sectionTitle": "Chat-Kanäle", + "sectionDescription": "Konfigurieren Sie IM-Bots, um Ereignisbenachrichtigungen zu empfangen und Codieraktivitäten abzufragen.", + "addChannel": "Kanal hinzufügen", + "noChannels": "Noch keine Chat-Kanäle konfiguriert.", + "channelName": "Name", + "channelNamePlaceholder": "Mein Telegram Bot", + "channelType": "Kanaltyp", + "lark": "Lark (Feishu)", + "weixin": "WeChat", + "dailyReport": "Tagesbericht", + "dailyReportTime": "Berichtszeit", + "nameRequired": "Kanalname ist erforderlich.", + "tokenRequired": "Token ist erforderlich.", + "chatIdRequired": "Chat-ID ist erforderlich.", + "topicMode": "Themengruppenmodus", + "topicModeHint": "Leitet Telegram-Forum-Themen als separate Codeg-Sitzungen weiter. Der Bot muss in einer Forum-Supergruppe sein und Themen verwalten dürfen.", + "loadFailed": "Kanäle konnten nicht geladen werden.", + "saveFailed": "Änderungen konnten nicht gespeichert werden.", + "connectSuccess": "Kanal verbunden.", + "connectFailed": "Verbindung fehlgeschlagen", + "disconnectSuccess": "Kanal getrennt.", + "disconnectFailed": "Trennung fehlgeschlagen.", + "testSuccess": "Verbindungstest bestanden.", + "testFailed": "Verbindungstest fehlgeschlagen", + "deleteSuccess": "Kanal gelöscht.", + "deleteFailed": "Kanal konnte nicht gelöscht werden.", + "deleteConfirmTitle": "Kanal löschen", + "deleteConfirmMessage": "Der Kanal und seine Nachrichtenprotokolle werden dauerhaft gelöscht. Sind Sie sicher?", + "cancel": "Abbrechen", + "delete": "Löschen", + "create": "Erstellen", + "save": "Speichern", + "channelListTitle": "Konfigurierte Kanäle", + "channelListDescription": "Aktivierte Kanäle werden beim Dienststart automatisch verbunden.", + "editChannel": "Kanal bearbeiten", + "editSuccess": "Kanal aktualisiert.", + "tokenPlaceholderKeep": "Leer lassen, um aktuellen Wert beizubehalten", + "weixinScanTitle": "QR-Code scannen", + "weixinScanDescription": "Öffnen Sie WeChat und scannen Sie den QR-Code, um eine Verbindung herzustellen.", + "weixinQrcodeExpired": "QR-Code abgelaufen.", + "weixinRefreshQrcode": "Aktualisieren", + "weixinWaitingScan": "Warten auf Scan...", + "weixinPollError": "Verbindung instabil, erneuter Versuch...", + "weixinReconnectNotice": "Aufgrund von Einschränkungen des iLink-Protokolls müssen Sie nach jeder erneuten Verbindung dem Bot eine Nachricht senden, damit Ereignisauslöser wirksam werden.", + "connect": "Verbinden", + "disconnect": "Trennen", + "test": "Verbindung testen", + "tabs": { + "channels": "Kanäle", + "commands": "Befehle", + "events": "Ereignisse", + "other": "Sonstiges" + }, + "commands": { + "title": "Integrierte Befehle", + "description": "Im Chat-Kanal verfügbare Bot-Befehle. In Gruppenchats ist @Bot erforderlich, um Nachrichten zu verarbeiten.", + "prefixLabel": "Befehlspräfix", + "prefixDescription": "1-3 nicht-alphanumerische Zeichen zum Auslösen von Bot-Befehlen (Standard /).", + "prefixSaved": "Befehlspräfix gespeichert.", + "prefixSaveFailed": "Fehler beim Speichern des Präfixes.", + "prefixInvalid": "Das Präfix muss 1-3 nicht-alphanumerische Zeichen sein.", + "save": "Speichern", + "folderDesc": "Arbeitsordner auswählen", + "agentDesc": "KI-Agent auswählen", + "taskDesc": "Sitzung erstellen und Aufgabe ausführen", + "sessionsDesc": "Aktive Sitzungen im Ordner anzeigen", + "resumeDesc": "Neueste Konversationen / Sitzung fortsetzen", + "cancelDesc": "Aktuelle Aufgabe abbrechen", + "approveDesc": "Berechtigungsanfrage des Agenten genehmigen", + "denyDesc": "Berechtigungsanfrage des Agenten ablehnen", + "searchDesc": "Konversationen nach Stichwort suchen", + "todayDesc": "Heutige Aktivitätsübersicht", + "statusDesc": "Kanal-Verbindungsstatus", + "helpDesc": "Hilfe anzeigen" + }, + "events": { + "title": "Ereignisbenachrichtigungen", + "description": "Nach Aktivierung werden ausgelöste Ereignisse an den Kanal gesendet.", + "turnComplete": "Runde abgeschlossen", + "turnCompleteDesc": "Wenn eine Agentenrunde endet", + "error": "Agentenfehler", + "errorDesc": "Wenn ein Agent einen Fehler feststellt", + "permissionRequest": "Berechtigungsanfrage", + "permissionRequestDesc": "Wenn ein Agent eine Berechtigung anfordert", + "questionRequest": "Frage des Agenten", + "questionRequestDesc": "Wenn ein Agent dir eine Frage stellt", + "userPromptSent": "Benutzernachricht", + "userPromptSentDesc": "Wenn du eine Nachricht sendest – der Nachrichtentext ist in der Benachrichtigung enthalten", + "saved": "Ereignisfilter aktualisiert.", + "saveFailed": "Fehler beim Speichern des Ereignisfilters.", + "loadFailed": "Einstellungen konnten nicht geladen werden.", + "retry": "Erneut versuchen", + "webhooksTitle": "Webhooks", + "webhooksDescription": "Sendet bei einem aktivierten Ereignis eine JSON-Nutzlast per POST an eine oder mehrere URLs. Der Ereignisfilter oben gilt auch für Webhooks.", + "webhookUrlPlaceholder": "https://example.com/webhook", + "addWebhook": "Webhook hinzufügen", + "removeWebhook": "Webhook entfernen", + "webhookSave": "Speichern", + "webhooksSaved": "Webhooks gespeichert.", + "webhooksSaveFailed": "Fehler beim Speichern der Webhooks.", + "webhookInvalidUrl": "Gültige http(s)-URLs eingeben.", + "docsTitle": "Anfrageformat", + "docsMethod": "Methode", + "docsContentType": "Content-Type", + "docsNote": "Jedes aktivierte Ereignis wird an alle URLs gesendet. Webhooks werden nicht entprellt; der Ereignisfilter oben gilt weiterhin.", + "editWebhook": "Webhook bearbeiten", + "enableWebhook": "Webhook aktivieren", + "webhookDuplicate": "Diese URL ist bereits konfiguriert.", + "cancel": "Abbrechen", + "webhooksEmpty": "Noch keine Webhooks konfiguriert.", + "deleteWebhookTitle": "Webhook löschen", + "deleteWebhookMessage": "Diesen Webhook entfernen? Ereignisse werden nicht mehr an diese URL gesendet.", + "delete": "Löschen" + }, + "language": { + "title": "Nachrichtensprache", + "description": "Sprache für Ereignisbenachrichtigungen, Befehlsantworten und tägliche Berichte, die an Chat-Kanäle gesendet werden.", + "saved": "Nachrichtensprache gespeichert.", + "saveFailed": "Fehler beim Speichern der Nachrichtensprache.", + "en": "Englisch", + "zh-cn": "Vereinfachtes Chinesisch", + "zh-tw": "Traditionelles Chinesisch", + "ja": "Japanisch", + "ko": "Koreanisch", + "es": "Spanisch", + "de": "Deutsch", + "fr": "Französisch", + "pt": "Portugiesisch", + "ar": "Arabisch" + } + }, + "ModelProviderSettings": { + "sectionTitle": "Modellanbieter", + "sectionDescription": "API-Anbieter-Zugangsdaten für Agenten verwalten.", + "filterAll": "Alle", + "providerListTitle": "Konfigurierte Anbieter", + "addProvider": "Anbieter hinzufügen", + "editProvider": "Anbieter bearbeiten", + "noProviders": "Noch keine Modellanbieter konfiguriert.", + "providerName": "Name", + "providerNamePlaceholder": "z.B. OpenAI, Anthropic", + "apiUrl": "API-URL", + "apiUrlPlaceholder": "https://api.openai.com/v1", + "apiKey": "API-Schlüssel", + "apiKeyPlaceholder": "sk-...", + "apiKeyKeepCurrent": "Leer lassen, um aktuellen Wert beizubehalten", + "agentTypes": "Agententypen", + "agentTypesRequired": "Mindestens ein Agententyp ist erforderlich.", + "agentType": "Agententyp", + "agentTypeRequired": "Agententyp ist erforderlich.", + "agentTypeImmutableHint": "Der Agententyp kann nach der Erstellung nicht mehr geändert werden.", + "model": "Modell", + "modelPlaceholderCodex": "gpt-5.6-sol / gpt-5.5", + "modelPlaceholderGemini": "gemini-3-pro-preview", + "claudeMainModel": "Hauptmodell", + "claudeReasoningModel": "Reasoning-Modell (Thinking)", + "claudeHaikuDefaultModel": "Standard Haiku-Modell", + "claudeSonnetDefaultModel": "Standard Sonnet-Modell", + "claudeOpusDefaultModel": "Standard Opus-Modell", + "claudeCustomModelOption": "Benutzerdefinierte Modell-ID", + "claudeCustomModelOptionName": "Name des benutzerdefinierten Modells", + "claudeCustomModelOptionDescription": "Beschreibung des benutzerdefinierten Modells", + "claudeCustomModelOptionHint": "Fügt der Modellauswahl von Claude einen einzelnen benutzerdefinierten Eintrag hinzu (z. B. ein Modell hinter einem benutzerdefinierten Gateway/Proxy). Name und Beschreibung sind optionale Anzeigeangaben.", + "nameRequired": "Anbietername ist erforderlich.", + "apiUrlRequired": "API-URL ist erforderlich.", + "apiKeyRequired": "API-Schlüssel ist erforderlich.", + "loadFailed": "Anbieter konnten nicht geladen werden.", + "saveFailed": "Änderungen konnten nicht gespeichert werden.", + "createSuccess": "Anbieter erstellt.", + "editSuccess": "Anbieter aktualisiert.", + "deleteSuccess": "Anbieter gelöscht.", + "deleteConfirmTitle": "Anbieter löschen", + "deleteConfirmMessage": "Der Anbieter \"{name}\" wird dauerhaft gelöscht. Sind Sie sicher?", + "deleteBlockedByAgent": "{agents} verwendet diesen Anbieter. Bitte trennen Sie die Verbindung vor dem Löschen.", + "cancel": "Abbrechen", + "delete": "Löschen", + "create": "Erstellen", + "save": "Speichern", + "affectedRunningSessions": "{count, plural, one {# laufende Sitzung muss zum Anwenden neu verbunden werden} other {# laufende Sitzungen müssen zum Anwenden neu verbunden werden}}" + }, + "SkillMatrix": { + "loading": "Wird geladen…", + "searchPlaceholder": "Nach Name, ID oder Beschreibung suchen", + "empty": "Nichts anzuzeigen.", + "emptySearch": "Keine Treffer für die aktuelle Suche.", + "skillColumn": "Skill", + "selectAll": "Alle sichtbaren auswählen", + "selectSkill": "{name} auswählen", + "everything": { + "label": "Sammelaktion", + "enable": "Alle aktivieren (sichtbar)", + "disable": "Alle deaktivieren (sichtbar)" + }, + "columnMenu": { + "enableAll": "Alle Skills aktivieren", + "disableAll": "Alle Skills deaktivieren" + }, + "rowMenu": { + "label": "Sammelaktionen für {name}", + "enableAll": "Für alle Agenten aktivieren", + "disableAll": "Für alle Agenten deaktivieren" + }, + "bulk": { + "selected": "{count} ausgewählt", + "targetAll": "Alle Agenten", + "targetSome": "{count} Agenten", + "enable": "Aktivieren", + "disable": "Deaktivieren", + "clear": "Leeren" + }, + "confirm": { + "disableTitle": "Diese Verknüpfungen deaktivieren?", + "disableBody": "Dadurch werden {count} von codeg verwaltete Skill-Verknüpfungen entfernt. Skills, die ein eigenes Verzeichnis belegen, bleiben unberührt. Du kannst sie jederzeit wieder aktivieren.", + "cancel": "Abbrechen", + "confirm": "Deaktivieren" + }, + "toasts": { + "loadFailed": "Skill-Status konnte nicht geladen werden", + "applyFailed": "Änderungen konnten nicht angewendet werden", + "enabled": "{count} Verknüpfungen aktiviert", + "disabled": "{count} Verknüpfungen deaktiviert", + "enabledPartial": "{ok} aktiviert, {failed} fehlgeschlagen", + "disabledPartial": "{ok} deaktiviert, {failed} fehlgeschlagen" + }, + "detail": { + "enableForAgents": "Für Agenten aktivieren", + "preview": "SKILL.md-Vorschau", + "loadingContent": "Inhalt wird geladen…" + }, + "copyModeHint": "Kopiert (nicht verknüpft) – nach Updates erneut aktivieren, um die neueste Version zu erhalten" + }, + "ExpertsSettings": { + "title": "Experten-Skills", + "description": "Aktivieren Sie kuratierte, praxiserprobte Skill-Workflows für Ihre KI-Coding-Agents. Jeder Experte ist ein eigenständiger Skill aus dem superpowers-Projekt — codeg verwaltet die zentrale Kopie und verknüpft sie mit den von Ihnen ausgewählten Agents.", + "loading": "Experten werden geladen…", + "loadingContent": "Inhalt wird geladen…", + "emptyExperts": "Keine Experten verfügbar. Prüfen Sie die Anwendungsprotokolle.", + "emptySelection": "Wählen Sie einen Experten aus, um seinen Inhalt anzuzeigen und die Aktivierung zu verwalten.", + "emptySearch": "Keine Experten entsprechen der aktuellen Suche.", + "searchPlaceholder": "Experten nach Name, ID oder Beschreibung suchen", + "enableForAgents": "Für Agents aktivieren", + "noAgents": "Keine ACP-Agents erkannt.", + "copyModeWarning": "Kopiert (nicht verknüpft). Nach codeg-Updates erneut aktivieren, um die neueste Version zu erhalten.", + "previewTitle": "SKILL.md-Vorschau", + "categories": { + "discovery": "Entdeckung & Design", + "planning": "Planung", + "execution": "Ausführung", + "quality": "Qualität & Tests", + "debugging": "Debugging", + "review": "Review & Integration", + "meta": "Meta" + }, + "states": { + "not_linked": "Nicht aktiviert", + "linked_to_codeg": "Aktiviert", + "linked_elsewhere": "Blockiert — ein anderer Link existiert", + "blocked_by_real_directory": "Blockiert — ein benutzerdefinierter Skill belegt diesen Namen", + "broken": "Defekter Link" + }, + "badges": { + "userModified": "Vom Benutzer geändert" + }, + "actions": { + "openCentralDir": "Zentralen Ordner öffnen", + "refresh": "Aktualisieren" + }, + "toasts": { + "loadFailed": "Laden der Expertendetails fehlgeschlagen", + "enabled": "Experte für diesen Agent aktiviert", + "disabled": "Experte für diesen Agent deaktiviert", + "enableFailed": "Aktivieren des Experten fehlgeschlagen", + "disableFailed": "Deaktivieren des Experten fehlgeschlagen", + "openFolderFailed": "Ordner konnte nicht geöffnet werden" + } + }, + "ScienceSettings": { + "title": "Wissenschaftliche Skills", + "description": "Aktiviere kuratierte wissenschaftliche Skills für deine KI-Coding-Agents — Hypothesengenerierung, Versuchsplanung, Statistik, Visualisierung, kritische Bewertung und Literatursuche. codeg verwaltet eine zentrale Kopie und verlinkt jeden Skill in die von dir gewählten Agents.", + "loading": "Wissenschaftliche Skills werden geladen…", + "emptySkills": "Keine wissenschaftlichen Skills verfügbar. Prüfe die Anwendungsprotokolle.", + "searchPlaceholder": "Wissenschaftliche Skills nach Name, ID oder Beschreibung suchen", + "categories": { + "ideation": "Ideenfindung", + "design": "Studiendesign", + "analysis": "Analyse", + "visualization": "Visualisierung", + "evaluation": "Bewertung", + "literature": "Literatur" + }, + "states": { + "not_linked": "Nicht aktiviert", + "linked_to_codeg": "Aktiviert", + "linked_elsewhere": "Blockiert — ein anderer Link existiert", + "blocked_by_real_directory": "Blockiert — ein benutzerdefinierter Skill belegt diesen Namen", + "broken": "Defekter Link" + }, + "badges": { + "userModified": "Vom Benutzer geändert", + "needsKey": "API-Schlüssel nötig", + "needsSetup": "Ggf. Einrichtung nötig" + }, + "actions": { + "openCentralDir": "Zentralen Ordner öffnen", + "refresh": "Aktualisieren" + }, + "toasts": { + "openFolderFailed": "Ordner konnte nicht geöffnet werden" + } + }, + "OfficeToolsSettings": { + "title": "Office-Tools", + "description": "Verwalten Sie OfficeCLI-Skills zum Erstellen von Excel-, Word- und PowerPoint-Dateien. Installieren Sie OfficeCLI, synchronisieren Sie Skills und aktivieren Sie sie pro Agent.", + "loadingContent": "Inhalt wird geladen…", + "emptySkills": "Keine Skills verfügbar. Installieren Sie OfficeCLI und synchronisieren Sie die Skills.", + "emptySelection": "Wählen Sie einen Skill aus, um den Inhalt anzuzeigen und die Aktivierung zu verwalten.", + "emptySearch": "Keine übereinstimmenden Skills gefunden.", + "searchPlaceholder": "Skills nach Name, ID oder Beschreibung suchen", + "enableForAgents": "Für Agenten aktivieren", + "noAgents": "Keine ACP-Agenten erkannt.", + "installFirst": "Installieren Sie zuerst OfficeCLI, um Skills zu aktivieren.", + "syncFirst": "Synchronisieren Sie zuerst die Skills, um den Inhalt zu laden.", + "noContent": "Kein Inhalt verfügbar.", + "copyModeWarning": "Kopiert (nicht verknüpft). Erneut synchronisieren, um die neueste Version zu erhalten.", + "previewTitle": "SKILL.md-Vorschau", + "detection": { + "installed": "Installiert", + "notInstalled": "Nicht installiert", + "notRunnable": "Installiert, aber nicht lauffähig", + "installHint": "Installieren Sie OfficeCLI, um Office-Dokumentenerstellungs-Skills für Ihre KI-Agenten zu aktivieren.", + "install": "Installieren", + "uninstall": "Deinstallieren", + "syncSkills": "Skills synchronisieren" + }, + "categories": { + "general": "Allgemein", + "presentations": "Präsentationen", + "documents": "Dokumente", + "spreadsheets": "Tabellenkalkulationen" + }, + "states": { + "not_linked": "Nicht aktiviert", + "linked_to_codeg": "Aktiviert", + "linked_elsewhere": "Blockiert — ein anderer Link existiert", + "blocked_by_real_directory": "Blockiert — ein benutzerdefinierter Skill belegt diesen Namen", + "broken": "Defekter Link" + }, + "badges": { + "notSynced": "Nicht synchronisiert" + }, + "actions": { + "refresh": "Aktualisieren" + }, + "toasts": { + "loadFailed": "Skill-Details konnten nicht geladen werden", + "enabled": "Skill für diesen Agenten aktiviert", + "disabled": "Skill für diesen Agenten deaktiviert", + "enableFailed": "Skill konnte nicht aktiviert werden", + "disableFailed": "Skill konnte nicht deaktiviert werden", + "installSuccess": "OfficeCLI erfolgreich installiert", + "installFailed": "OfficeCLI konnte nicht installiert werden", + "uninstallSuccess": "OfficeCLI deinstalliert", + "uninstallFailed": "OfficeCLI konnte nicht deinstalliert werden", + "syncSuccess": "{synced} Skills erfolgreich synchronisiert", + "syncPartial": "{synced} synchronisiert, {errors} fehlgeschlagen", + "syncFailed": "Skills konnten nicht synchronisiert werden" + }, + "autoPreviewLabel": "Vorschau automatisch öffnen", + "autoPreviewHint": "Wenn ein Agent eine Word-, Excel- oder PowerPoint-Datei erstellt oder bearbeitet, wird die Live-Vorschau automatisch geöffnet." + }, + "SkillPacksSettings": { + "title": "Skill-Pakete", + "description": "Kuratierte Skill-Pakete, die codeg zentral verwaltet und mit deinen KI-Agenten verknüpft – Programmierexperten, wissenschaftliche Forschung und Office-Dokumenttools. Unten pro Agent aktivierbar.", + "tabs": { + "experts": "Experten", + "science": "Wissenschaft", + "office": "Office-Tools", + "custom": "Benutzerdefiniert" + }, + "actions": { + "openCentralDir": "Zentralen Ordner öffnen", + "refresh": "Aktualisieren" + }, + "toasts": { + "openFolderFailed": "Ordner konnte nicht geöffnet werden" + } + }, + "QuickMessagesSettings": { + "title": "Schnellnachrichten", + "description": "Verwalte wiederverwendbare Nachrichtenbausteine. Ziehe zum Neuordnen.", + "loading": "Schnellnachrichten werden geladen…", + "emptyList": "Noch keine Schnellnachrichten. Klicke auf \"Neu\", um eine zu erstellen.", + "emptySelection": "Wähle eine Schnellnachricht zum Bearbeiten aus.", + "searchPlaceholder": "Nach Titel oder Inhalt suchen", + "untitled": "Ohne Titel", + "actions": { + "new": "Neu", + "save": "Speichern", + "delete": "Löschen", + "dragSort": "Zum Neuordnen ziehen", + "dragSortMessage": "Schnellnachricht neu ordnen: {name}" + }, + "fields": { + "title": "Titel", + "titlePlaceholder": "Gib dieser Nachricht einen kurzen Titel", + "content": "Inhalt", + "contentPlaceholder": "Gib hier den Nachrichteninhalt ein" + }, + "confirmDelete": { + "title": "Schnellnachricht löschen?", + "message": "Dadurch wird \"{name}\" dauerhaft gelöscht. Bist du sicher?", + "cancel": "Abbrechen", + "confirm": "Löschen" + }, + "toasts": { + "loadFailed": "Laden der Schnellnachrichten fehlgeschlagen", + "createFailed": "Erstellen der Schnellnachricht fehlgeschlagen", + "saveFailed": "Speichern der Schnellnachricht fehlgeschlagen", + "deleteFailed": "Löschen der Schnellnachricht fehlgeschlagen", + "saveOrderFailed": "Reihenfolge konnte nicht gespeichert werden", + "created": "Schnellnachricht erstellt", + "saved": "Schnellnachricht gespeichert", + "deleted": "Schnellnachricht gelöscht" + } + }, + "Pet": { + "badge": { + "running": "{count} laufend", + "waiting": "{count} warten auf Freigabe", + "error": "{count} fehlgeschlagen" + }, + "panel": { + "title": "Aktive Sitzungen", + "empty": "Keine aktiven Sitzungen", + "emptyHint": "Laufende Agenten und solche, die dich brauchen, erscheinen hier.", + "statusRunning": "Läuft", + "statusWaiting": "Wartet", + "statusError": "Fehler", + "subAgentOf": "Sub-Agent von" + }, + "menu": { + "scale": "Skalierung", + "openManager": "Pets verwalten", + "close": "Schließen" + }, + "loadError": "Pet konnte nicht geladen werden", + "missingPetIdParam": "Kein Pet ausgewählt", + "summonButton": "Pet", + "manager": { + "title": "Desktop-Pets", + "description": "Schwebende Begleiter mit Codex-kompatiblen Sprite-Sheets.", + "addPet": "Pet hinzufügen", + "importFromCodex": "Aus Codex importieren", + "noPets": "Keine Pets. Lege eines an oder importiere aus Codex.", + "setActive": "Aktivieren", + "active": "Aktiv", + "edit": "Bearbeiten", + "delete": "Löschen", + "deleteConfirm": "Pet „{name}\" löschen? Auch von der Festplatte entfernt.", + "summon": "Pet-Fenster aufrufen", + "openCodexHelp": "Codex-Pets müssen in ~/.codex/pets/ liegen. Nichts gefunden.", + "specRequirement": "Sprite-Sheet muss 1536px breit sein, mit einer Höhe als Vielfaches von 208px (z. B. 1872 oder 2288), als PNG oder WebP mit Transparenz.", + "form": { + "id": "Pet-ID", + "idHelp": "Kleinbuchstaben, Ziffern, '-' und '_'. Max 64 Zeichen.", + "displayName": "Anzeigename", + "description": "Beschreibung (optional)", + "spritesheet": "Sprite-Sheet", + "chooseFile": "Datei wählen", + "replaceFile": "Sprite ersetzen", + "saveCreate": "Pet hinzufügen", + "saveUpdate": "Änderungen speichern", + "cancel": "Abbrechen" + }, + "errors": { + "missingId": "Pet-ID erforderlich", + "missingName": "Anzeigename erforderlich", + "missingSpritesheet": "Sprite erforderlich", + "addFailed": "Hinzufügen fehlgeschlagen", + "updateFailed": "Aktualisieren fehlgeschlagen", + "deleteFailed": "Löschen fehlgeschlagen", + "loadFailed": "Pet-Liste konnte nicht geladen werden", + "setActiveFailed": "Aktivieren fehlgeschlagen", + "summonFailed": "Pet-Fenster konnte nicht geöffnet werden" + } + }, + "import": { + "title": "Aus Codex importieren", + "subtitle": "Pets unter ~/.codex/pets/.", + "selectAll": "Alle auswählen", + "alreadyImported": "Bereits importiert", + "renameOnConflict": "Konflikte mit Suffix -imported umbenennen", + "import": "Auswahl importieren", + "noneFound": "Keine importierbaren Codex-Pets gefunden.", + "imported": "Erfolgreich importiert", + "failed": "Import fehlgeschlagen", + "close": "Schließen" + }, + "marketplace": { + "openMarketplace": "Pet-Marketplace", + "title": "Pet-Marketplace", + "search": "Pets suchen", + "kindFilter": { + "all": "Alle", + "object": "Objekt", + "animal": "Tier", + "person": "Person", + "creature": "Kreatur" + }, + "sortFilter": { + "latest": "Neueste", + "popular": "Beliebt", + "views": "Aufrufe" + }, + "refresh": "Aktualisieren", + "install": "Installieren", + "installing": "Wird installiert", + "reinstall": "Neu installieren", + "reinstallConfirm": "Lokales Pet \"{name}\" überschreiben? Vorhandene Daten werden ersetzt.", + "cancel": "Abbrechen", + "stats": { + "views": "Aufrufe", + "downloads": "Downloads", + "likes": "Likes" + }, + "actions": { + "idle": "Idle", + "running_right": "Rechtslauf", + "running_left": "Linkslauf", + "waving": "Winken", + "jumping": "Springen", + "failed": "Fehler", + "waiting": "Warten", + "running": "Laufen", + "review": "Review" + }, + "page": "Seite {page} von {total}", + "prev": "Zurück", + "next": "Weiter", + "empty": "Keine Pets entsprechen dem Filter.", + "successInstalled": "\"{name}\" installiert", + "errors": { + "loadFailed": "Marketplace konnte nicht geladen werden", + "installFailed": "Installation fehlgeschlagen", + "alreadyInstalled": "Pet existiert bereits lokal" + } + } + }, + "RemoteWorkspace": { + "openRemoteWorkspace": "Open remote workspace", + "manage": "Manage remote workspace", + "manageTitle": "Remote Workspace connections", + "empty": "No remote connections", + "searchPlaceholder": "Search remote workspaces", + "orderFailed": "Failed to save remote workspace order", + "dragSort": "Drag to sort", + "dragSortConnection": "Drag to sort {name}", + "newConnection": "New connection", + "loading": "Loading", + "loadingConnection": "Loading remote connection", + "name": "Name", + "baseUrl": "Service URL", + "token": "Access token", + "save": "Save", + "delete": "Delete", + "confirmDelete": { + "title": "Delete remote connection?", + "message": "This will remove \"{name}\" from this device. This action cannot be undone.", + "cancel": "Cancel", + "confirm": "Delete" + }, + "saved": "Remote connection saved.", + "deleted": "Remote connection deleted.", + "loadFailed": "Failed to load remote connections", + "saveFailed": "Failed to save remote connection", + "deleteFailed": "Failed to delete remote connection", + "openFailed": "Failed to open remote workspace", + "connectionLoadFailed": "Failed to load remote connection: {message}", + "connectionExpired": "Remote connection \"{name}\" is expired. Update its token and reload this window." + }, + "ServerFileBrowser": { + "title": "Serverdatei auswählen", + "pathPlaceholder": "Verzeichnispfad eingeben...", + "goHome": "Zum Home-Verzeichnis", + "navigateUp": "Zum übergeordneten Verzeichnis", + "select": "Auswählen", + "cancel": "Abbrechen", + "loading": "Laden...", + "emptyDirectory": "Dieses Verzeichnis ist leer", + "errorLoadingDir": "Verzeichnis konnte nicht geladen werden", + "selectedCount": "{count} ausgewählt" + }, + "BackupSettings": { + "title": "Sicherung & Wiederherstellung", + "description": "Exportiere eine portable Sicherung deiner codeg-Daten oder stelle aus einer Sicherung wieder her.", + "tabs": { + "backup": "Sicherung", + "restore": "Wiederherstellung" + }, + "export": { + "includeExternal": "Gesprächsinhalte einschließen", + "includeExternalHint": "Archiviert auch die CLI-Transkripte (Claude, Codex, Gemini, …). Erhöht die Größe.", + "passphrase": "Passphrase (optional)", + "passphrasePlaceholder": "Leer lassen für ein unverschlüsseltes Archiv", + "passphraseConfirm": "Passphrase bestätigen", + "passphraseMismatch": "Die Passphrasen stimmen nicht überein.", + "noPassphraseWarning": "Diese Sicherung enthält Geheimnisse (API-Schlüssel, Tokens) im Klartext. Bewahre sie sicher auf.", + "passphraseLossWarning": "Mit dieser Passphrase verschlüsselt. Wenn du sie verlierst, kann die Sicherung nicht wiederhergestellt werden.", + "button": "Sicherung exportieren", + "inProgress": "Sicherung wird erstellt…", + "success": "Sicherung erstellt.", + "started": "Download der Sicherung gestartet." + }, + "restore": { + "selectFile": "Sicherungsdatei auswählen", + "passphrasePrompt": "Diese Sicherung ist verschlüsselt. Gib ihre Passphrase ein.", + "unlock": "Entsperren", + "preview": { + "title": "Sicherungsdetails", + "encrypted": "Verschlüsselt", + "compatible": "Kompatibel", + "incompatible": "Inkompatibel", + "createdAt": "Erstellt: {value}", + "appVersion": "App-Version: {value}", + "incompatibleHint": "Diese Sicherung wurde mit einer neueren Version von codeg erstellt und kann nicht wiederhergestellt werden." + }, + "replaceWarning": "Beim Wiederherstellen werden alle aktuellen codeg-Daten (Datenbank und Uploads) ersetzt. Deine aktuellen Daten werden zuvor als Snapshot gesichert.", + "keyringNote": "GitHub-/Chat-Tokens der Desktop-App liegen im Schlüsselbund des Betriebssystems und sind nicht enthalten; gib sie nach dem Wiederherstellen erneut ein.", + "button": "Wiederherstellen", + "staging": "Wiederherstellung wird vorbereitet…", + "staged": "Wiederherstellung vorbereitet. Neustart…", + "restarting": "Wiederherstellung vorbereitet. Server wird neu gestartet…", + "restartTimeout": "Der Server kam nicht rechtzeitig zurück. Lade die Seite neu, sobald er läuft.", + "externalSideLocation": "Gesprächstranskripte wurden nach {path} wiederhergestellt", + "confirmTitle": "Alle Daten ersetzen?", + "confirmBody": "Dadurch werden deine aktuelle codeg-Datenbank und Uploads durch die Sicherung ersetzt und anschließend neu gestartet. Deine aktuellen Daten werden zuvor als Snapshot gesichert.", + "cancel": "Abbrechen", + "confirmAction": "Ersetzen & neu starten", + "external": { + "title": "Gesprächsinhalte", + "hint": "Diese Sicherung enthält CLI-Transkripte. Wähle, wohin sie wiederhergestellt werden.", + "modeSkip": "Nicht wiederherstellen", + "modeSide": "In einen sicheren Nebenordner wiederherstellen", + "modeOriginal": "An den ursprünglichen CLI-Speicherorten wiederherstellen", + "forceOverwrite": "Vorhandene Dateien überschreiben", + "forceOverwriteHint": "Ersetzt Dateien, die bereits in den CLI-Ordnern vorhanden sind.", + "scanning": "Konflikte werden geprüft…", + "noConflicts": "Es werden keine vorhandenen Dateien überschrieben.", + "conflictCount": "{count} vorhandene Datei(en) wären betroffen.", + "conflictSkipNote": "Vorhandene Dateien bleiben erhalten (übersprungen), sofern du das Überschreiben nicht aktivierst." + }, + "restartFailed": "Wiederherstellung vorbereitet, aber der Server konnte nicht neu starten. Starte ihn manuell neu, um sie anzuwenden." + }, + "remoteUnsupported": "Sicherung & Wiederherstellung wirken auf die Daten des Rechners, auf dem codeg läuft. Du bist mit einem entfernten Arbeitsbereich verbunden – verwalte dessen Sicherungen direkt auf jenem Server." + }, + "backup": { + "restore": { + "error": { + "badPassphrase": "Falsche Passphrase oder beschädigte Sicherung.", + "corrupted": "Das Sicherungsarchiv ist beschädigt.", + "unknownFormat": "Diese Datei ist keine erkannte codeg-Sicherung.", + "newerVersion": "Diese Sicherung wurde mit codeg {backupVersion} erstellt, neuer als diese Version ({appVersion}).", + "alreadyPending": "Es ist bereits eine Wiederherstellung vorbereitet. Starte neu, um sie anzuwenden, bevor du eine weitere vorbereitest." + } + }, + "error": { + "diskSpace": "Nicht genügend Speicherplatz, um den Vorgang abzuschließen.", + "cancelled": "Der Vorgang wurde abgebrochen." + } + }, + "WebConnection": { + "disconnectedTitle": "Verbindung getrennt", + "reconnectingDescription": "Verbindung zum Server wird wiederhergestellt. Das geschieht normalerweise innerhalb weniger Sekunden automatisch.", + "reconnectNow": "Jetzt neu verbinden", + "sessionExpiredTitle": "Sitzung abgelaufen", + "sessionExpiredDescription": "Deine Sitzung ist nicht mehr gültig. Bitte melde dich erneut an, um fortzufahren.", + "goToLogin": "Zur Anmeldung" + }, + "LiveFeedback": { + "placeholder": "Sende {agent} eine Notiz, während er arbeitet…", + "agentFallback": "der Agent", + "ariaLabel": "Live-Feedback-Notiz", + "dialogTitle": "Live-Feedback", + "dialogDescription": "Sende dem Agenten eine Notiz, während er arbeitet. Er liest sie bei der nächsten Prüfung – ohne den aktuellen Schritt zu unterbrechen.", + "dialogDescriptionInstant": "Sende dem Agenten eine Notiz, während er arbeitet. Sie wird sofort in den laufenden Turn eingefügt – der Agent sieht sie umgehend.", + "channelDowngraded": "Sofortiges Einfügen ist in dieser Sitzung nicht verfügbar – deine Notiz wurde gespeichert; der Agent holt sie bei seinem nächsten Check ab.", + "send": "Senden", + "cancel": "Abbrechen", + "pending": "wartet", + "delivered": "erhalten", + "turnEndedUnread": "Der Agent hat die Runde beendet, bevor er dein Feedback gelesen hat.", + "sendAsMessage": "Als Nachricht senden", + "dismiss": "Verwerfen", + "turnEndedResent": "Die Runde endete – stattdessen als neue Nachricht gesendet.", + "turnEnded": "Die Runde ist bereits beendet.", + "submitFailed": "Deine Notiz konnte nicht gesendet werden" + }, + "AgentToolsSettings": { + "title": "Tools in der Unterhaltung", + "description": "Zusätzliche Tools, die codeg einem Agenten innerhalb einer Unterhaltung gibt. Sie werden beim Start des Agenten injiziert – eine Änderung gilt daher für danach gestartete Agenten.", + "feedbackLabel": "Live-Feedback", + "feedbackHint": "Sende einem Agenten Notizen und Korrekturen, während er arbeitet. Unterstützt der Agent sofortiges Einfügen, landet deine Notiz umgehend im laufenden Turn; andernfalls erhält der Agent ein Tool zum Abrufen deines Feedbacks – solche Agenten prüfen es meist nur, wenn du es im Prompt erwähnst, z. B. mit \"prüfe regelmäßig mein Live-Feedback\".", + "questionLabel": "Benutzer fragen", + "questionHint": "Erlaubt Agenten, anzuhalten und dir eine Multiple-Choice-Frage zu stellen, die über dem Eingabefeld der Unterhaltung erscheint. Der Agent wartet, bis du antwortest (oder überspringst).", + "sessionInfoLabel": "Sitzungsinformationen abrufen", + "sessionInfoHint": "Erlaubt Agenten, eine in deiner Nachricht referenzierte Sitzung (ein Sitzungs-Badge) nachzuschlagen, um Titel, Agent, Status, Arbeitsbereich, Token-Verbrauch und letzte Nachrichten zu lesen.", + "automationsLabel": "Automatisierungen erstellen", + "automationsHint": "Speichert die Unterhaltung als Automatisierung, die nach Zeitplan läuft. Standardmäßig aus – sie startet danach selbst Agenten.", + "workTasksLabel": "To-do-Aufgaben erstellen", + "workTasksHint": "Stellt aus der Unterhaltung heraus eine Karte auf das To-do-Board. Standardmäßig aus – schreibt App-Zustand.", + "save": "Speichern", + "saving": "Wird gespeichert…", + "saved": "Tool-Einstellungen gespeichert", + "saveFailed": "Tool-Einstellungen konnten nicht gespeichert werden", + "loadFailed": "Laden fehlgeschlagen: {detail}" + }, + "NotificationSoundSettings": { + "title": "Benachrichtigungstöne", + "description": "Spielt einen kurzen Ton ab, wenn ein Agent-Ereignis eintritt. Es sind dieselben Ereignisse, die an die Chat-Kanäle gesendet werden; diese Einstellung gilt nur für dieses Gerät.", + "enableHint": "Standardmäßig aus. Töne werden nur im Arbeitsbereich-Fenster dieses Browsers oder dieser App abgespielt.", + "volume": "Lautstärke", + "preview": "Anhören", + "previewEvent": "Ton für {event} anhören", + "onlyWhenUnfocused": "Nur wenn das Fenster nicht im Fokus ist", + "onlyWhenUnfocusedHint": "Bleibt stumm, solange du Codeg ansiehst.", + "eventsTitle": "Ereignisse", + "eventsHint": "Wähle pro Ereignis einen Ton oder „Stumm“, um es zu überspringen. Wiederholt sich dasselbe Ereignis innerhalb weniger Sekunden, erklingt es nur einmal.", + "toneNone": "Stumm", + "toneChime": "Glockenspiel", + "toneDing": "Klingel", + "toneBlip": "Blip", + "tonePop": "Pop", + "toneAlert": "Alarm", + "toneDescend": "Absteigend" + }, + "LogsSettings": { + "loading": "Wird geladen…", + "sectionTitle": "Laufzeitprotokolle", + "sectionDescription": "Diagnoseprotokolle der Anwendung anzeigen und konfigurieren. Protokolle werden in lokale Dateien geschrieben und für die Live-Ansicht im Speicher gehalten.", + "captureTitle": "Protokollebene", + "captureDescription": "Steuert, wie viele Details erfasst werden. Höhere Stufen (Debug, Trace) zeichnen mehr auf, erzeugen aber größere Protokolle. „Aus“ deaktiviert die Protokollierung.", + "captureLabel": "Erfassungsebene", + "levels": { + "off": "Aus", + "error": "Fehler", + "warn": "Warnung", + "info": "Info", + "debug": "Debug", + "trace": "Trace" + }, + "viewerTitle": "Aktuelle Protokolle", + "viewerDescription": "Live-Ansicht der letzten Protokolleinträge. Nach Ebene filtern oder Text suchen.", + "searchPlaceholder": "Nachricht oder Ziel suchen…", + "viewLevels": { + "all": "Alle Ebenen", + "error": "Fehler und höher", + "warn": "Warnung und höher", + "info": "Info und höher", + "debug": "Debug und höher", + "trace": "Trace und höher" + }, + "pause": "Pause", + "resume": "Live", + "refresh": "Aktualisieren", + "clear": "Leeren", + "openFolder": "Ordner öffnen", + "shownCount": "{shown} / {total} angezeigt", + "empty": "Keine Protokolle vorhanden.", + "levelSaveFailed": "Protokollebene konnte nicht gespeichert werden", + "openFolderFailed": "Protokollordner konnte nicht geöffnet werden", + "downloadFailed": "Protokolldatei konnte nicht heruntergeladen werden", + "filesTitle": "Protokolldateien", + "filesDescription": "Vollständige Protokolldateien von der Festplatte herunterladen, um den Verlauf über den Live-Puffer hinaus anzuzeigen.", + "filesEmpty": "Noch keine Protokolldateien.", + "download": "Herunterladen", + "downloadTruncated": "Die Datei ist groß; die neuesten {size} wurden heruntergeladen. Die vollständige Datei befindet sich im Log-Verzeichnis.", + "captureEnvLocked": "Die Protokollebene wird durch die Umgebungsvariable RUST_LOG / CODEG_LOG gesteuert; ändere sie dort, damit es wirksam wird.", + "targetsTitle": "Modulspezifische Überschreibungen", + "targetsDescription": "Lege für bestimmte Module (z. B. codeg_lib::acp) eine andere Stufe fest, ohne die globale Stufe zu ändern.", + "targetsAdd": "Hinzufügen", + "targetsRemove": "Überschreibung entfernen", + "toggleDetails": "Details umschalten" + }, + "Automations": { + "title": "Automatisierungen", + "new": "Neue Automatisierung", + "empty": "Noch keine Automatisierungen", + "emptyHint": "Erstelle eine, um eine Agentenaufgabe geplant oder manuell auszuführen.", + "name": "Name", + "namePlaceholder": "z. B. Nächtliche PR-Prüfung", + "prompt": "Eingabe", + "promptPlaceholder": "Was soll der Agent tun?", + "agent": "Agent", + "folder": "Arbeitsbereich-Ordner", + "folderPlaceholder": "Ordner auswählen", + "isolation": "Isolierung", + "isolationWorktree": "Neues Worktree pro Lauf", + "isolationShared": "Im Ordner ausführen", + "isolationSharedCaveat": "Ausführungen verwenden den Arbeitsbaum dieses Ordners direkt und können mit deinen nicht committeten Änderungen kollidieren. Aktiviere die Worktree-Option, um jede Ausführung zu isolieren.", + "trigger": "Auslöser", + "triggerSchedule": "Nach Zeitplan", + "triggerManual": "Nur manuell", + "cron": "Zeitplan (Cron)", + "cronPlaceholder": "0 9 * * 1-5", + "timezone": "Zeitzone", + "nextRun": "Nächster Lauf", + "branch": "Branch", + "branchOptional": "Branch (optional)", + "enabled": "Aktiviert", + "save": "Speichern", + "cancel": "Abbrechen", + "edit": "Bearbeiten", + "delete": "Löschen", + "runNow": "Jetzt ausführen", + "cancelRun": "Lauf abbrechen", + "runHistory": "Laufverlauf", + "noRuns": "Noch keine Läufe", + "allFolders": "Alle Ordner", + "filterAll": "Alle", + "noMatches": "Keine passenden Automatisierungen", + "viewConversation": "Konversation ansehen", + "lastRun": "Letzter Lauf", + "never": "Nie", + "running": "Läuft", + "deleteTitle": "Automatisierung löschen?", + "deleteDescription": "Dies entfernt die Automatisierung und ihren Zeitplan. Der Laufverlauf bleibt erhalten.", + "statusRunning": "Läuft", + "statusSucceeded": "Erfolgreich", + "statusFailed": "Fehlgeschlagen", + "statusCancelled": "Abgebrochen", + "statusSkipped": "Übersprungen", + "errorName": "Name ist erforderlich", + "errorPrompt": "Eingabe ist erforderlich", + "errorCron": "Geplante Automatisierungen benötigen einen Cron-Ausdruck", + "errorFolder": "Wähle einen Arbeitsbereich-Ordner", + "presetHourly": "Stündlich", + "presetDaily": "Täglich 9 Uhr", + "presetWeekdays": "Werktags 9 Uhr", + "presetCustom": "Benutzerdefiniert", + "probing": "Optionen werden geladen…", + "retry": "Erneut versuchen", + "configNone": "Dieser Agent hat keine konfigurierbaren Optionen", + "inherit": "Agent-Standard", + "mode": "Modus", + "config": "Konfiguration", + "branchPlaceholder": "(Standard-Branch)", + "selectHint": "Wähle eine Automatisierung, um Details zu sehen", + "refresh": "Aktualisieren", + "onboardTitle": "Routineaufgaben des Agenten automatisieren", + "onboardHint": "Plane einen Agenten, der Code überprüft, Abhängigkeiten aktualisiert oder Probleme sichtet – nach Zeitplan oder bei Bedarf.", + "headerSubtitle": "Geplante und bedarfsgesteuerte Agentenaufgaben", + "startFromTemplate": "Mit einer Vorlage beginnen", + "blankTitle": "Leere Automatisierung", + "blankDesc": "Eine Agentenaufgabe von Grund auf konfigurieren.", + "backToTemplates": "Vorlagen", + "sectionSchedule": "Zeitplan & Ziel", + "sectionTarget": "Ziel", + "sectionAction": "Aktion", + "actionLaunchSession": "Sitzung starten", + "actionEnqueueTask": "Aufgabe einreihen", + "actionEnqueueTaskHint": "Jede Auslösung fügt den To-dos des Ordners eine To-do-Aufgabe mit dem Namen dieser Automatisierung hinzu; die Task-Engine führt sie gemäß den Board-Einstellungen aus.", + "sectionPrompt": "Prompt", + "nextIn": "Nächste in {rel}", + "manual": "Manuell", + "schedEveryMinutes": "Alle {n} Minuten", + "schedHourly": "Stündlich", + "schedDaily": "Täglich um {time}", + "schedWeekdays": "Wochentags um {time}", + "schedWeekly": "Jeden {day} um {time}", + "schedMonthly": "Monatlich am {day}. um {time}", + "dow0": "Sonntag", + "dow1": "Montag", + "dow2": "Dienstag", + "dow3": "Mittwoch", + "dow4": "Donnerstag", + "dow5": "Freitag", + "dow6": "Samstag", + "tplCodeReviewTitle": "Code-Review", + "tplCodeReviewDesc": "Überprüft aktuelle Änderungen auf Fehler, Regressionen und Qualitätsprobleme.", + "tplDependencyUpdatesTitle": "Abhängigkeits-Updates", + "tplDependencyUpdatesDesc": "Findet veraltete Abhängigkeiten und schlägt sichere Upgrades vor.", + "tplTestCoverageTitle": "Testabdeckung", + "tplTestCoverageDesc": "Findet ungetestete Codepfade und ergänzt die fehlenden Tests.", + "tplTodoSweepTitle": "TODO-Durchsicht", + "tplTodoSweepDesc": "Sammelt TODO- und FIXME-Kommentare und sortiert sie nach Priorität.", + "tplCiTriageTitle": "CI-Sichtung", + "tplCiTriageDesc": "Untersucht kürzlich fehlgeschlagene Prüfungen und schlägt Korrekturen vor.", + "tplReleaseNotesTitle": "Release Notes", + "tplReleaseNotesDesc": "Fasst Änderungen seit dem letzten Release in einem Changelog zusammen.", + "tplSecurityAuditTitle": "Sicherheitsaudit", + "tplSecurityAuditDesc": "Sucht nach Schwachstellen und riskanten Mustern und meldet die Ergebnisse.", + "enable": "Aktivieren", + "disable": "Deaktivieren", + "moreActions": "Weitere Aktionen", + "statusDisabled": "Deaktiviert", + "cronBuilderTitle": "Zeitplan-Generator", + "cronFreqLabel": "Häufigkeit", + "cronFreqMinutes": "Alle N Minuten", + "cronFreqHourly": "Stündlich", + "cronFreqDaily": "Täglich", + "cronFreqWeekdays": "Wochentags", + "cronFreqWeekly": "Wöchentlich", + "cronFreqMonthly": "Monatlich", + "cronFreqCustom": "Benutzerdefiniert", + "cronEveryLabel": "Intervall (Minuten)", + "cronTimeLabel": "Uhrzeit", + "cronHourLabel": "Stunde", + "cronMinuteLabel": "Minute", + "cronDowLabel": "Wochentag", + "cronDomLabel": "Tag des Monats", + "cronApply": "Anwenden", + "cronPreviewLabel": "Vorschau", + "cronOpenBuilder": "Zeitplan-Generator öffnen", + "branchDefault": "Standard-Branch", + "branchUseCustom": "„{query}“ verwenden", + "branchLocal": "Lokal", + "branchRemote": "Remote", + "branchSearchPlaceholder": "Branches suchen…", + "branchNone": "Keine Branches" + }, + "Tasks": { + "title": "To-dos", + "new": "Neue Aufgabe", + "empty": "Noch keine Aufgaben", + "emptyHint": "Füge ein To-do hinzu und starte es — der Agent arbeitet in einem isolierten Worktree, du prüfst und mergst das Ergebnis.", + "emptyColTodo": "Noch keine To-dos", + "emptyColInProgress": "Nichts in Arbeit", + "emptyColAttention": "Nichts wartet auf dich", + "emptyColDone": "Noch nichts fertig", + "allFolders": "Alle Ordner", + "showCanceled": "Abgebrochene anzeigen", + "showArchived": "Archivierte anzeigen", + "filter": "Filter", + "viewSwitchToBoard": "Zur Board-Ansicht wechseln", + "viewSwitchToList": "Zur Listenansicht wechseln", + "statusFilter": "Status", + "statusFilterAll": "Alle Status", + "listEmpty": "Keine Aufgabe entspricht den aktuellen Filtern", + "listColStatus": "Status", + "listColTask": "Aufgabe", + "listColLocation": "Ort", + "listColChanges": "Änderungen", + "listColUpdated": "Aktualisiert", + "colTodo": "To-do", + "colInProgress": "In Arbeit", + "colAttention": "Wartet auf dich", + "colDone": "Fertig", + "statusTodo": "To-do", + "statusQueued": "In Warteschlange", + "statusPreparing": "Wird vorbereitet", + "statusRunning": "Läuft", + "statusAwaitingInput": "Wartet auf Eingabe", + "statusReview": "Zur Prüfung", + "statusMerging": "Wird gemergt", + "statusDone": "Fertig", + "statusFailed": "Fehlgeschlagen", + "statusCanceled": "Abgebrochen", + "statusInterrupted": "Unterbrochen", + "badgeCleanupFailed": "Aufräumen fehlgeschlagen", + "badgeWorktreeKept": "Worktree behalten", + "badgeWorktreeRemoved": "Worktree entfernt", + "filesChanged": "{count} Dateien", + "actionStart": "Starten", + "actionSchedule": "Planen", + "actionCancel": "Abbrechen", + "actionRetry": "Erneut versuchen", + "actionRequeue": "Erneut einreihen", + "actionViewSession": "Konversation anzeigen", + "actionEdit": "Bearbeiten", + "actionDelete": "Löschen", + "actionRetryCleanup": "Aufräumen wiederholen", + "actionMerge": "Mergen", + "actionUnqueueMerge": "Merge-Warteschlange verlassen", + "actionEditQueuedMerge": "Wartenden Merge bearbeiten", + "badgeMergeQueued": "Wartet auf Merge", + "badgeMergeQueuedRank": "Wartet auf Merge · Nr. {rank}", + "badgeMergeQueuedHint": "Wartet, bis der laufende Merge des Projekts fertig ist; dieser startet dann von selbst.", + "actionComplete": "Abschließen", + "actionAbandon": "Verwerfen", + "cancelTitle": "Aufgabe abbrechen?", + "cancelDescription": "Die Aufgabe wird auf Abgebrochen gesetzt. Ihr Worktree bleibt erhalten und du kannst sie später erneut einreihen.", + "cancelReasonLabel": "Grund (optional)", + "cancelReasonPlaceholder": "Z. B. falscher Ansatz – ich schreibe die Beschreibung neu", + "cancelKeep": "Doch nicht", + "cancelSubmit": "Aufgabe abbrechen", + "restartTitleRetry": "Aufgabe erneut versuchen", + "restartTitleRequeue": "Aufgabe erneut einreihen", + "restartDescription": "Du kannst eine Notiz ergänzen (optional) – sie landet im Prompt des nächsten Laufs.", + "scheduleTitle": "Aufgabe planen", + "scheduleDescription": "Die Aufgabe bleibt im To-do und startet zur gewählten Zeit von selbst. Das Parallelitätslimit des Ordners gilt weiterhin.", + "scheduleDateLabel": "Datum", + "schedulePickDate": "Datum wählen", + "scheduleTimeLabel": "Uhrzeit", + "schedulePreview": "Läuft am {time}", + "schedulePastHint": "Dieser Zeitpunkt liegt in der Vergangenheit – die Aufgabe startet direkt nach dem Speichern.", + "scheduleInAnHour": "In 1 Stunde", + "scheduleInThreeHours": "In 3 Stunden", + "scheduleTomorrow": "Morgen 9:00", + "scheduleClear": "Planung entfernen", + "scheduleBadge": "Geplanter Start: {time}", + "toastScheduled": "Geplant für {time}", + "toastScheduleCleared": "Planung entfernt", + "actionFollowUp": "Nachfassen", + "actionAddNote": "Hinweis ergänzen", + "followUpSubmit": "Senden", + "followUpIntentRevise": "Überarbeiten", + "followUpIntentContinue": "Weitermachen", + "followUpIntentQuestion": "Nachfragen", + "followUpIntentVerify": "Selbstprüfung", + "followUpPlaceholderRevise": "Was soll der Agent ändern? Er macht in derselben Sitzung weiter.", + "followUpPlaceholderContinue": "Was kommt als Nächstes? Das Bisherige bleibt bestehen.", + "followUpPlaceholderQuestion": "Was möchtest du wissen? Der Agent antwortet, ohne Dateien anzufassen.", + "followUpPlaceholderVerify": "Optional: Worauf soll es besonders achten?", + "followUpPlaceholderRetry": "Optional: Was soll diesmal anders laufen? Z. B. zuerst pnpm install ausführen", + "followUpPlaceholderRequeue": "Optional: Warum hast du abgebrochen, und was soll diesmal anders sein?", + "actionArchive": "Archivieren", + "actionUnarchive": "Dearchivieren", + "archiveAllDone": "Alle archivieren", + "dropToStart": "Loslassen zum Starten", + "errorView": "Ansehen", + "notifyReview": "Bereit zur Abnahme: {title}", + "notifyFailed": "Aufgabe fehlgeschlagen: {title}", + "createFromMessage": "Aufgabe aus Nachricht erstellen", + "detailTokens": "Token insgesamt", + "editorTitleNew": "Neue Aufgabe", + "editorTitleEdit": "Aufgabe bearbeiten", + "templates": "Vorlagen", + "templatesEmpty": "Noch keine Vorlagen.", + "templateSaveCurrent": "Aktuelles als Vorlage speichern", + "templateDelete": "Vorlage löschen", + "transcriptTitle": "Aufgaben-Konversation", + "transcriptDescription": "Schreibgeschützte Live-Ansicht der Agentensitzung dieser Aufgabe.", + "phaseWork": "Ausführung", + "phaseRetry": "Neuversuch", + "phaseReturn": "Nachfassen", + "phaseMerge": "Merge", + "titleLabel": "Titel", + "titlePlaceholder": "Was ist zu tun?", + "promptLabel": "Aufgabenbeschreibung", + "promptPlaceholder": "Beschreibe die Aufgabe für den Agenten — @ für Dateiverweise, / für Befehle", + "folderPlaceholder": "Ordner wählen", + "agentInheritedHint": "Aus den Aufgaben-Einstellungen geerbt — Änderungen gelten nur für diese Aufgabe", + "agentOverrideReset": "Wieder erben", + "sectionTarget": "Ziel", + "errorTitle": "Titel ist erforderlich", + "errorPrompt": "Beschreibung ist erforderlich", + "errorFolder": "Ordner wählen", + "save": "Speichern", + "cancel": "Abbrechen", + "mergeTitle": "Aufgabe mergen", + "mergeQueuedTitle": "Wartender Merge", + "mergeQueueHint": "Eine andere Aufgabe dieses Projekts wird gerade gemergt. Diese reiht sich ein und startet von selbst, sobald die andere fertig ist.", + "mergeQueueUpdateHint": "Diese Aufgabe wartet bereits auf den Merge. Beim Absenden wird sie aktualisiert und behält ihren Platz in der Warteschlange.", + "mergeDescription": "{branch} in {base} mergen. Nicht committete Änderungen im Worktree werden zuerst committet.", + "mergeMessage": "Commit-Nachricht", + "mergeMessagePlaceholder": "z. B. feat: add login validation", + "mergeAutoMessage": "Commit-Nachricht vom Agenten schreiben lassen", + "strategySquash": "Zu einem Commit zusammenfassen", + "strategySquashHint": "Alle Änderungen der Aufgabe landen als ein einzelner Eintrag im Verlauf des Hauptbranchs — der Verlauf bleibt übersichtlich.", + "strategyMerge": "Gesamten Verlauf behalten", + "strategyMergeHint": "Jeder während der Aufgabe erstellte Commit bleibt erhalten, plus ein Merge-Eintrag — jeder Schritt bleibt nachvollziehbar.", + "mergeDeleteWorktree": "Worktree nach dem Merge löschen", + "mergeSubmit": "Mergen", + "mergeSubmitQueue": "In die Warteschlange", + "mergeQueuedToast": "Zur Merge-Warteschlange hinzugefügt – startet, sobald der laufende Merge fertig ist.", + "completeTitle": "Aufgabe abschließen", + "completeDescription": "Diese Aufgabe hat keine Dateien geändert – es gibt nichts zu mergen, sie wird direkt als fertig markiert.", + "completeDescriptionNoWorktree": "Der Worktree dieser Aufgabe wurde entfernt – es kann nichts mehr gemergt werden, sie wird direkt als fertig markiert. Ein Arbeitsbranch mit noch nicht gemergten Commits bleibt erhalten.", + "completeDeleteWorktree": "Worktree nach dem Abschließen löschen", + "completeSubmit": "Abschließen", + "settingsTitle": "Aufgaben-Einstellungen", + "settingsDescription": "Standardwerte für Aufgaben in {folder}.", + "settingsScope": "Geltungsbereich", + "settingsScopeGlobal": "Alle Ordner (globale Standardwerte)", + "settingsScopeGlobalHint": "Ordner ohne eigene Einstellungen verwenden diese globalen Standardwerte.", + "settingsSource": "Konfigurationsquelle", + "settingsSourceGlobal": "Globale Standards", + "settingsSourceCustom": "Eigene", + "settingsSourceGlobalFollow": "Folgt den globalen Aufgaben-Einstellungen — Änderungen dort gelten hier automatisch.", + "settingsSourceCustomHint": "Speichert eigene Einstellungen für diesen Ordner; die globalen Standards gelten dann nicht mehr.", + "settingsAgent": "Standard-Agent", + "settingsMaxConcurrent": "Max. gleichzeitige Aufgaben", + "settingsMaxConcurrentHint": "0 = unbegrenzt", + "settingsAutoProcess": "Automatisch verarbeiten", + "settingsAutoProcessHint": "Offene Aufgaben starten von selbst, bis zum Parallelitätslimit.", + "settingsMergeStrategy": "Standard-Merge-Strategie", + "settingsMergeStrategyHint": "Wie die Änderungen der Aufgabe beim Mergen im Branch-Verlauf festgehalten werden.", + "settingsAutoMerge": "Automatisch mergen", + "settingsAutoMergeHint": "Eine Aufgabe, die mit landbaren Änderungen das Review erreicht, wird gemergt, als hättest du auf Mergen geklickt: Der Agent schreibt die Commit-Nachricht, der Worktree folgt der Voreinstellung unten. Bei rotem Preflight oder einem fehlgeschlagenen Merge wartet die Aufgabe auf dich.", + "settingsDeleteWorktree": "Worktree nach dem Mergen löschen", + "settingsDeleteWorktreeHint": "Aktiviert die Option im Merge-Dialog vor; dort lässt sie sich weiterhin ändern.", + "settingsWorktreeRoot": "Worktree-Verzeichnis", + "settingsWorktreeRootHint": "Verzeichnis, in dem neue Aufgaben-Worktrees angelegt werden – eines pro Aufgabe. Leer lassen, um sie neben dem Projektordner anzulegen; „~“ ist dein Home-Verzeichnis, ein relativer Pfad gilt relativ zum Projektordner.", + "settingsWorktreeRootPlaceholder": "~/codeg-worktrees", + "settingsWorktreeRootBrowse": "Worktree-Verzeichnis auswählen", + "settingsPreflight": "Preflight-Befehl", + "settingsPreflightHint": "Läuft im Worktree, sobald eine Aufgabe das Review erreicht.", + "settingsPreflightCustomPlaceholder": "pnpm test", + "settingsInitCommand": "Worktree-Init-Befehl", + "settingsInitCommandHint": "Läuft in einem frisch erstellten Worktree, bevor der Agent startet.", + "settingsInitCommandPlaceholder": "pnpm install", + "settingsTabGeneral": "Allgemein", + "settingsTabMerge": "Merge", + "settingsTabWorktree": "Worktree", + "settingsTabPrompts": "Prompts", + "settingsPromptsIntro": "Jede Phase sendet bereits einen eingebauten Prompt — die Aufgabe selbst, die Worktree-Regeln und beim Mergen die genauen Git-Schritte. Was du hier ergänzt, wird als zusätzliche Anweisung ans Ende gehängt: Es verfeinert den eingebauten Text, ersetzt ihn aber nie.", + "settingsPromptStageAll": "Alle Phasen", + "settingsPromptPlaceholderAll": "z. B. Halte dich an die Konventionen in AGENTS.md; fasse am Ende in zwei Sätzen zusammen", + "settingsPromptPlaceholderWork": "z. B. Lies zuerst die zugehörigen Tests; committe in kleinen Schritten", + "settingsPromptPlaceholderRetry": "z. B. Prüfe vor dem Weitermachen, was bereits committet ist; wiederhole nichts Fertiges", + "settingsPromptPlaceholderReturn": "Z. B. Arbeite jeden genannten Punkt ab; refaktoriere nichts Fremdes", + "settingsPromptPlaceholderMerge": "z. B. Schreibe die Merge-Commit-Nachricht auf Deutsch; nenne jeden manuell gelösten Konflikt", + "settingsPromptHintAll": "Wird an jeden Prompt des Agents angehängt, auch beim Merge-Lauf.", + "settingsPromptHintWork": "Wird angehängt, wenn eine Aufgabe zum ersten Mal läuft.", + "settingsPromptHintRetry": "Wird angehängt, wenn eine unterbrochene oder fehlgeschlagene Aufgabe fortgesetzt wird.", + "settingsPromptHintReturn": "Wird ergänzt, wenn du bei einer Aufgabe in Prüfung nachfasst (überarbeiten, erweitern, prüfen).", + "settingsPromptHintMerge": "Wird angehängt, wenn der Agent die Aufgabe in den Basis-Branch übernimmt.", + "preflightPassed": "{name} bestanden", + "preflightFailed": "{name} fehlgeschlagen", + "preflightRunning": "{name} läuft…", + "detailDescription": "Aufgabendetails", + "detailSummary": "Ergebnis", + "detailFiles": "Geänderte Dateien", + "detailDiffAll": "Gesamtes Diff anzeigen", + "detailDiffAllTitle": "Gesamtes Diff", + "detailNoChanges": "Noch keine Änderungen gegenüber der Basis", + "detailTimeline": "Verlauf", + "detailTimelineEmpty": "Noch keine Aktivität", + "showMore": "Mehr anzeigen", + "showLess": "Weniger anzeigen", + "detailInfo": "Details", + "detailBranch": "Branch", + "detailMergeCommit": "Merge-Commit", + "detailChanges": "Änderungen", + "detailScheduled": "Geplanter Start", + "detailCreated": "Erstellt", + "detailStarted": "Gestartet", + "detailFinished": "Abgeschlossen", + "diffLoading": "Diff wird geladen…", + "deleteConfirmTitle": "Aufgabe löschen?", + "deleteConfirmBody": "„{title}“ wird vom Board entfernt. Ein aktiver Lauf wird zuerst abgebrochen.", + "deleteWithWorktree": "Auch den Worktree löschen", + "eventCreated": "Erstellt", + "eventStatusChanged": "Statusänderung", + "eventConfigEffective": "Startkonfiguration", + "eventInitCommand": "Init-Befehl", + "eventAgentProgress": "Agent-Fortschritt", + "eventAgentVerdict": "Agent-Urteil", + "eventMergeAttempt": "Merge gestartet", + "eventMergeQueued": "In Merge-Warteschlange", + "eventMergeConflict": "Merge-Konflikt", + "eventPreflight": "Preflight", + "eventCleanupFailed": "Worktree-Aufräumen fehlgeschlagen", + "eventResumeFallback": "Sitzungsfortsetzung fehlgeschlagen, neue Sitzung", + "eventUserAction": "Benutzeraktion", + "eventDiffStat": "Änderungs-Snapshot" + }, + "CustomSkillsSettings": { + "loading": "Benutzerdefinierte Skills werden geladen…", + "category": "Benutzerdefiniert", + "searchPlaceholder": "Benutzerdefinierte Skills nach Name, ID oder Beschreibung suchen", + "states": { + "not_linked": "Nicht aktiviert", + "linked_to_codeg": "Aktiviert", + "linked_elsewhere": "Anderweitig verknüpft", + "blocked_by_real_directory": "Durch echten Ordner blockiert", + "broken": "Defekter Link" + }, + "actions": { + "new": "Neu", + "import": "Importieren", + "importFromAgent": "Von Agent importieren", + "cancel": "Abbrechen", + "save": "Speichern" + }, + "rowMenu": { + "edit": "Bearbeiten", + "duplicate": "Duplizieren", + "delete": "Löschen" + }, + "bulk": { + "delete": "Auswahl löschen" + }, + "editor": { + "createTitle": "Neuer benutzerdefinierter Skill", + "editTitle": "Benutzerdefinierten Skill bearbeiten", + "description": "Benutzerdefinierte Skills liegen im gemeinsamen Speicher (~/.codeg/skills) und können für jeden Agenten aktiviert werden.", + "idLabel": "Skill-ID", + "idPlaceholder": "z. B. my-workflow", + "contentLabel": "SKILL.md", + "contentPlaceholder": "Hier die SKILL.md des Skills schreiben…", + "preview": "Vorschau", + "edit": "Bearbeiten", + "emptyBody": "Noch kein Inhalt." + }, + "duplicate": { + "title": "Skill duplizieren", + "description": "Eine Kopie von „{id}“ mit einer neuen ID erstellen.", + "newIdPlaceholder": "Neue Skill-ID", + "confirm": "Duplizieren" + }, + "import": { + "title": "Skill-Ordner zum Importieren wählen" + }, + "importFromAgent": { + "title": "Skills von einem Agenten importieren", + "description": "Kopiere die eigenen Skills eines Agenten in den gemeinsamen Speicher, um sie für jeden Agenten zu aktivieren.", + "agentLabel": "Agent", + "agentPlaceholder": "Agent auswählen", + "selectAll": "Alle auswählen ({count})", + "loading": "Skills des Agenten werden geladen…", + "unsupported": "Dieser Agent stellt kein Skill-Verzeichnis bereit.", + "empty": "Dieser Agent hat keine importierbaren Skills.", + "alreadyInLibrary": "In Bibliothek", + "confirm": "Auswahl importieren ({count})" + }, + "delete": { + "title": "Benutzerdefinierte Skills löschen?", + "body": "Dadurch werden {count} benutzerdefinierte Skill(s) aus dem zentralen Speicher entfernt und von allen Agenten getrennt. Dies kann nicht rückgängig gemacht werden.", + "confirm": "Löschen" + }, + "toasts": { + "loadFailed": "Skill konnte nicht geladen werden", + "idRequired": "Bitte eine Skill-ID eingeben", + "created": "Benutzerdefinierter Skill erstellt", + "updated": "Benutzerdefinierter Skill aktualisiert", + "saveFailed": "Skill konnte nicht gespeichert werden", + "imported": "Skill importiert", + "importFailed": "Skill konnte nicht importiert werden", + "duplicated": "Skill dupliziert", + "duplicateFailed": "Skill konnte nicht dupliziert werden", + "deleted": "{count} Skill(s) gelöscht", + "deletedPartial": "{ok} gelöscht, {failed} fehlgeschlagen", + "deleteFailed": "Skills konnten nicht gelöscht werden", + "importedFromAgent": "{count} Skill(s) importiert", + "importedFromAgentPartial": "{ok} importiert, {failed} fehlgeschlagen", + "importFromAgentAllSkipped": "Nichts zu importieren – {count} bereits in der Bibliothek", + "importFromAgentFailed": "Import vom Agenten fehlgeschlagen" + } + }, + "CodexModelEditor": { + "customizedNotice": "Du hast die Modellliste angepasst, daher verwaltet codeg jetzt die gesamte Modelltabelle von codex. Offizielle Modelle, die codex später hinzufügt, erscheinen nicht automatisch – klicke unten auf Aktualisieren und speichere erneut, um sie zu übernehmen. Entferne alle Anpassungen, damit codex sich wieder automatisch aktualisiert.", + "officialsTitle": "Offizielle Modelle", + "officialsHint": "Automatisch aus dem gestarteten codex übernommen; nicht benötigte entfernen.", + "officialsEmpty": "Keine offiziellen Modelle verfügbar.", + "refresh": "Aus codex aktualisieren", + "readdOfficial": "Offizielles erneut hinzufügen", + "customsTitle": "Benutzerdefinierte Modelle", + "customsEmpty": "Noch keine benutzerdefinierten Modelle.", + "addCustom": "Benutzerdefiniert hinzufügen", + "slugPlaceholder": "Modell-ID (Slug)", + "displayNamePlaceholder": "Anzeigename", + "contextWindow": "Kontext", + "makeDefault": "Als Standard festlegen", + "defaultHint": "Standardmodell", + "remove": "Entfernen", + "advanced": "Erweitert", + "baseTemplate": "Basisvorlage", + "baseTemplateHint": "Offizielles Modell, von dem Pflichtfelder (System-Prompt, Tools, Limits) geklont werden.", + "groupBehavior": "Verhalten & Funktionen", + "fieldReasoningLevel": "Standard-Reasoning", + "fieldReasoningSummary": "Reasoning-Zusammenfassung", + "fieldVerbosity": "Ausführlichkeit", + "fieldShellType": "Shell-Typ", + "fieldApplyPatch": "Apply-Patch-Tool", + "fieldReasoningSummaries": "Reasoning-Zusammenfassungen", + "fieldSupportVerbosity": "Ausführlichkeitssteuerung", + "fieldParallelToolCalls": "Parallele Tool-Aufrufe", + "fieldSearchTool": "Websuche-Tool", + "optNone": "Keine", + "groupInstructions": "Beschreibung & System-Prompt", + "fieldDescription": "Beschreibung", + "baseInstructions": "System-Prompt (base_instructions)" + }, + "DiagnosticsSettings": { + "title": "Umgebungsdiagnose", + "description": "Prüft, wie diese App die Agent-CLI im eigenen Prozess auflöst – das kann sich von deinem Terminal unterscheiden.", + "loading": "Diagnose wird ausgeführt…", + "error": "Diagnose fehlgeschlagen", + "rerun": "Erneut ausführen", + "copyAll": "Alles kopieren", + "copied": "Diagnose in die Zwischenablage kopiert", + "button": "Diagnose", + "verdict": { + "ok": "Die Umgebung sieht in Ordnung aus. Wird trotzdem „nicht installiert“ angezeigt, starte die App komplett neu, um den Prefix-Cache zu aktualisieren.", + "node_missing": "Node.js wurde im PATH der App nicht gefunden.", + "npm_missing": "npm wurde im PATH der App nicht gefunden.", + "not_installed": "Dieser Agent scheint nicht installiert zu sein.", + "installed_but_unresolved": "Als installiert vermerkt, aber die App findet die ausführbare Datei nicht.", + "user_prefix_not_on_path": "In das Ausweich-Prefix (~/.codeg/npm-global) installiert, das nicht im PATH der App liegt. Starte die App komplett neu und versuche es erneut.", + "homebrew_bin_not_on_path": "Unter dem Homebrew-bin installiert, das nicht im PATH der App liegt (Apple-Silicon-Keg-Trennung).", + "terminal_only_path": "Der Befehl wird in deinem Terminal aufgelöst, aber nicht in der App – eine GUI-PATH-Lücke. Starte die App aus einem Terminal oder installiere sie in den Agent-Einstellungen neu.", + "npm_prefix_timeout": "npm prefix -g war zu langsam (über 1,5 s), daher wurde die Ausweicherkennung übersprungen. Starte die App neu und versuche es erneut.", + "node_too_old": "Dein aktives Node.js ist älter als von diesem Agenten benötigt. Aktualisiere Node.js.", + "adapter_missing_native_present": "Deine eigene {agent}-CLI ist installiert, aber Codeg startet ein separates ACP-Adapterpaket — und das fehlt noch. Installiere es in den Agenten-Einstellungen; es rührt deine CLI nicht an und teilt sich dieselbe Anmeldung.", + "adapter_missing": "Codeg startet für {agent} ein separates ACP-Adapterpaket, das noch nicht installiert ist. Installiere es in den Agenten-Einstellungen — die Hersteller-CLI allein genügt nicht." + } + }, + "TokenUsage": { + "title": "Token-Verbrauch", + "rangeLabel": "Zeitraum", + "range7d": "7 Tage", + "range30d": "30 Tage", + "range90d": "90 Tage", + "rangeThisMonth": "Dieser Monat", + "rangeThisYear": "Dieses Jahr", + "rangeAll": "Gesamt", + "rangeCustom": "Benutzerdefiniert", + "moreRanges": "Mehr", + "customRangePick": "Zeitraum wählen", + "bucketLabel": "Gruppieren nach", + "bucketDay": "Tag", + "bucketWeek": "Woche", + "bucketMonth": "Monat", + "bucketUnitDay": "Tag", + "bucketUnitWeek": "Woche", + "bucketUnitMonth": "Monat", + "folderFilter": "Ordner", + "allFolders": "Alle Ordner", + "agentFilter": "Agenten", + "allAgents": "Alle Agenten", + "modelFilter": "Modelle", + "allModels": "Alle Modelle", + "searchPlaceholder": "Suchen…", + "noMatches": "Keine Treffer", + "clearFilter": "Auswahl löschen", + "resetFilters": "Filter zurücksetzen", + "refresh": "Aktualisieren", + "rebuild": "Alles neu aufbauen", + "rebuildHint": "Verwirft die gezählten Daten und liest alle Sitzungsprotokolle neu ein. Nützlich, wenn eine Sitzung außerhalb von codeg gewachsen ist.", + "syncing": "Sitzungen werden gezählt…", + "syncProgress": "{done} / {total}", + "syncDone": "{synced} Sitzungen gezählt", + "syncFailed": "Einige Sitzungen konnten nicht gelesen werden", + "syncBusy": "Eine Aktualisierung läuft bereits", + "lastSynced": "Aktualisiert {time}", + "lastSyncedNever": "Noch nie aktualisiert", + "tileTotal": "Tokens gesamt", + "tileSessions": "Sitzungen", + "tileTurns": "Turns", + "tileActiveDays": "Aktive Tage", + "tileGenTime": "Generierungszeit", + "vsPrevious": "ggü. Vorperiode", + "deltaNew": "neu", + "trendTitle": "Verbrauch im Zeitverlauf", + "trendEmpty": "Kein Verbrauch in diesem Zeitraum", + "trendTurns": "Turns", + "trendSessions": "Sitzungen", + "compositionTitle": "Wofür die Tokens draufgingen", + "compositionHint": "Eingabe ist, was du gesendet hast, Ausgabe, was das Modell geschrieben hat, und Cache-Lesevorgänge sind Kontext, den du nicht voll bezahlt hast.", + "compositionNote": "Diese Cache-Treffer zum vollen Preis erneut zu senden hätte weitere {value} gekostet.", + "inputTokens": "Eingabe", + "outputTokens": "Ausgabe", + "cacheWrite": "Cache-Schreiben", + "cacheRead": "Cache-Lesen", + "freshTokens": "Frisch berechnet", + "cacheHitCaption": "Cache-Treffer", + "cacheHeroTitleHigh": "Der Großteil des Kontexts musste nie erneut gesendet werden", + "cacheHeroTitleLow": "Der Großteil des Kontexts wird noch voll berechnet", + "cacheHeroDesc": "{cached} des Kontexts trug der Cache — nur {fresh} wurde in diesem Zeitraum wirklich neu berechnet.", + "cacheSavedSuffix": "Das sparte erneutes Senden im Umfang von {saved}.", + "avgPerSession": "Ø pro Sitzung", + "avgTurnsPerSession": "Ø {count} Turns pro Sitzung", + "avgPerActiveDay": "Ø pro aktivem Tag", + "peakBucket": "Stärkste(r) {bucket}", + "peakHour": "Spitzenstunde", + "daysValue": "{count} Tage", + "idleDays": "Leerlauftage", + "byFolderTitle": "Nach Ordner", + "byAgentTitle": "Nach Agent", + "byModelTitle": "Nach Modell", + "distributionTitle": "Verteilung der Nutzung", + "distributionHint": "Sitzungen und Tokens nach gewählter Dimension gebündelt — Klick auf eine Zeile filtert danach.", + "otherLabel": "Sonstige", + "unknownModel": "Modell nicht erfasst", + "emptyBreakdown": "Noch nichts erfasst", + "sessionsCount": "{count} Sitzungen", + "heatmapTitle": "Wann du baust", + "heatmapHint": "Tokens nach lokalem Wochentag und Stunde.", + "heatmapPeakHint": "Am dichtesten gegen {hour}:00 Uhr.", + "less": "Weniger", + "more": "Mehr", + "heatmapCell": "{weekday} {hour}:00 — {value} Tokens", + "weekMon": "Mo", + "weekTue": "Di", + "weekWed": "Mi", + "weekThu": "Do", + "weekFri": "Fr", + "weekSat": "Sa", + "weekSun": "So", + "topSessionsTitle": "Teuerste Sitzungen", + "untitledSession": "Unbenannte Sitzung", + "topSessionsEmpty": "Keine Sitzungen in diesem Zeitraum", + "streakLongest": "Längste Serie", + "streakLongestDays": "Längste Serie: {count} Tage", + "share": "Teilen", + "moreActions": "Weitere Aktionen", + "shareDialogTitle": "Teile deine Verbrauchskarte", + "shareDialogHint": "Eine Momentaufnahme des gewählten Zeitraums und der Filter.", + "shareSave": "Bild speichern", + "shareCopy": "Bild kopieren", + "shareCopied": "In die Zwischenablage kopiert", + "shareSaved": "Bild gespeichert", + "shareFailed": "Bild konnte nicht erstellt werden", + "shareRendering": "Wird erstellt…", + "cardHeading": "Meine KI-Coding-Bilanz", + "cardRangeAll": "Gesamter Zeitraum", + "cardTotalLabel": "Verbrauchte Tokens", + "cardFooter": "Erstellt mit codeg", + "cardTopModels": "Top-Modelle", + "cardTopProjects": "Top-Projekte", + "archetypeNightOwl": "Nachteule", + "archetypeNightOwlDesc": "{percent}% deiner Tokens gehen nach Einbruch der Dunkelheit drauf.", + "archetypeEarlyBird": "Frühaufsteher", + "archetypeEarlyBirdDesc": "{percent}% deiner Tokens fallen vor 9 Uhr an.", + "archetypeWeekendWarrior": "Wochenendkrieger", + "archetypeWeekendWarriorDesc": "{percent}% deiner Tokens entstehen am Wochenende.", + "archetypeCacheMaster": "Cache-Meister", + "archetypeCacheMasterDesc": "{percent}% deines Kontexts kamen aus dem Cache.", + "archetypeMarathoner": "Marathonläufer", + "archetypeMarathonerDesc": "{days} Tage am Stück gebaut.", + "archetypePolyglot": "Allrounder", + "archetypePolyglotDesc": "{count} Agenten im ernsthaften Einsatz.", + "archetypeLaserFocus": "Laserfokus", + "archetypeLaserFocusDesc": "{percent}% deiner Tokens gingen in ein einziges Projekt.", + "archetypeDeepDiver": "Tieftaucher", + "archetypeDeepDiverDesc": "{averageK}K Tokens in einer durchschnittlichen Sitzung.", + "archetypeSteady": "Stetiger Bauer", + "archetypeSteadyDesc": "{days} Tage geliefert.", + "emptyTitle": "Noch nichts gezählt", + "emptyHint": "Codeg liest die Token-Zahlen direkt aus dem Protokoll jedes Agenten. Aktualisiere, um zu zählen, was schon auf diesem Rechner liegt.", + "emptyAction": "Meine Sitzungen zählen", + "loadFailed": "Verbrauch konnte nicht geladen werden", + "truncatedNotice": "Dieser Zeitraum ist sehr groß — die Zahlen decken nur seinen jüngsten Abschnitt ab." + } +} diff --git a/src/i18n/messages/en.json b/src/i18n/messages/en.json index 7c9c876d7..a37900ca0 100644 --- a/src/i18n/messages/en.json +++ b/src/i18n/messages/en.json @@ -1,4958 +1,4958 @@ -{ - "Language": { - "followSystem": "Follow System", - "english": "English", - "simplifiedChinese": "Simplified Chinese", - "traditionalChinese": "Traditional Chinese", - "japanese": "Japanese", - "korean": "Korean", - "spanish": "Spanish", - "german": "German", - "french": "French", - "portuguese": "Portuguese", - "arabic": "Arabic" - }, - "GitCredentialDialog": { - "title": "Authentication Required", - "description": "The remote server requires credentials. Enter your username and password (or personal access token).", - "username": "Username", - "usernamePlaceholder": "Username or email", - "password": "Password / Token", - "passwordPlaceholder": "Password or personal access token", - "passwordHint": "For non-GitHub servers, enter your username and password.", - "cancel": "Cancel", - "authenticate": "Authenticate", - "authenticating": "Authenticating...", - "invalidCredentials": "Invalid credentials. Please try again.", - "saveCredentials": "Save credentials for future operations", - "githubTitle": "GitHub Authentication", - "githubDescription": "Enter a personal access token to authenticate with GitHub. The token will be validated and saved to your accounts.", - "githubToken": "Personal Access Token", - "githubTokenPlaceholder": "ghp_xxxxxxxxxxxx", - "githubTokenHint": "Generate a token at GitHub → Settings → Developer settings → Personal access tokens.", - "githubAuthenticate": "Validate & Connect", - "generateToken": "Generate token" - }, - "SettingsShell": { - "title": "Settings", - "preferences": "Preferences", - "nav": { - "general": "General", - "appearance": "Appearance", - "agents": "Agents", - "mcp": "MCP", - "skills": "Skills", - "shortcuts": "Shortcuts", - "version_control": "Version Control", - "system": "System", - "chat_channels": "Chat Channels", - "web_service": "Web Service", - "model_providers": "Model Providers", - "experts": "Experts", - "science": "Science", - "office_tools": "Office Tools", - "skill_packs": "Skill Packs", - "quick_messages": "Quick Messages", - "logs": "Runtime Logs" - } - }, - "AppearanceSettings": { - "sectionTitle": "Theme Appearance", - "sectionDescription": "Choose light, dark, or follow system. Settings are saved automatically.", - "themeMode": "Theme mode", - "placeholder": "Select theme mode", - "system": "Follow system", - "light": "Light", - "dark": "Dark", - "currentTheme": "Current effective theme: {theme}", - "resolvedTheme": { - "light": "Light", - "dark": "Dark", - "unknown": "--" - }, - "themeColor": { - "sectionTitle": "Theme color", - "sectionDescription": "Pick a color palette for accents, buttons, and highlights.", - "current": "Current color: {color}", - "options": { - "neutral": "Neutral", - "zinc": "Zinc", - "slate": "Slate", - "stone": "Stone", - "gray": "Gray", - "red": "Red", - "rose": "Rose", - "orange": "Orange", - "green": "Green", - "blue": "Blue", - "yellow": "Yellow", - "violet": "Violet" - } - }, - "customStyle": { - "sectionTitle": "Custom Style", - "sectionDescription": "Fine-tune the current theme's colors, or inject your own CSS. Overrides sit on top of the base preset, so switching presets keeps them.", - "summarySuspended": "Suspended", - "summaryDefault": "Preset defaults", - "summaryTokens": "{count, plural, one {# override} other {# overrides}}", - "summaryCss": "Custom CSS", - "suspendedByShortcut": "Custom style is suspended. Nothing set here takes effect until you resume it.", - "suspendedBySafeParam": "This window was opened in safe appearance mode, so custom style is ignored here. Other windows are unaffected.", - "resume": "Resume custom style", - "enableTheme": "Enable custom colors", - "editingLight": "Editing light mode values. Switch the app to dark mode to set its own.", - "editingDark": "Editing dark mode values. Switch the app to light mode to set its own.", - "resetToken": "Reset to preset value", - "radius": "Corner radius", - "radiusHint": "Drives the whole radius scale from sm to 4xl, so one slider rounds the entire app.", - "advanced": "Advanced ({count} more variables)", - "enableCss": "Enable custom CSS", - "cssRisk": "Advanced feature. Custom CSS overrides every built-in style and can make the interface unusable.", - "editCss": "Edit CSS…", - "cssPresent": "{size} KB saved", - "cssEmpty": "Nothing saved yet", - "escapeHint": "Stuck with a broken interface? Press {shortcut} to suspend all custom style, or open a window with the safeStyle=1 query parameter.", - "copyTheme": "Copy theme JSON", - "importTheme": "Import theme…", - "clearTheme": "Clear overrides", - "interopHint": "Themes use shadcn's registry:theme format, so you can paste any shadcn theme here and use exported ones in any shadcn project.", - "importTitle": "Import theme", - "importDescription": "Paste a shadcn registry:theme item, a bare light/dark object, or a flat token map.", - "readClipboard": "Read clipboard", - "importConfirm": "Import", - "cancel": "Cancel", - "apply": "Apply", - "toasts": { - "copied": "Theme JSON copied", - "copyFailed": "Could not copy to the clipboard", - "clipboardReadFailed": "Could not read the clipboard, paste manually", - "importFailed": "No usable theme tokens found in that JSON", - "imported": "Theme imported" - }, - "css": { - "dialogTitle": "Custom CSS", - "dialogDescription": "Applies to every codeg window. Changes preview live; press Apply to save.", - "size": "{used} KB / {max} KB", - "ruleCount": "{count} rules", - "errorTooLarge": "Too large to save. Trim it below the limit.", - "errorImportEscaped": "An @import rule survived removal (escaped syntax). Remove it to save.", - "warnNoRules": "No rules parsed, check the syntax.", - "noticeImportsRemoved": "@import rules removed: {count}. They would fetch remote stylesheets.", - "noticeRemoteUrl": "Contains a remote url(), which makes a network request when applied.", - "noticePreviewSuspended": "Custom style is suspended, so this preview is not applied.", - "noticeDisabled": "Custom CSS is off. You can preview here, but nothing applies until you enable it.", - "hintTokens": "Tip: your color overrides are available as var(--primary), var(--background) and so on." - } - }, - "zoomLevel": { - "sectionTitle": "Window zoom", - "sectionDescription": "Scale the entire interface. Applies immediately and persists per device.", - "placeholder": "Select zoom level", - "default": "Default", - "current": "Current zoom: {zoom}%" - }, - "fonts": { - "sectionTitle": "Fonts", - "sectionDescription": "Choose fonts for the interface, code editor, and terminal. Bundled fonts load on demand; pick “Custom…” to use any font installed on your system.", - "interface": "Interface", - "editor": "Editor", - "terminal": "Terminal", - "groupSans": "Sans-serif", - "groupMono": "Monospace", - "custom": "Custom…", - "customPlaceholder": "Font family, e.g. Fira Code", - "fontSize": "Font size", - "ligatures": "Enable font ligatures", - "ligaturesUnavailable": "This font has no ligatures", - "wordWrap": "Enable word wrap", - "terminalLigaturesHint": "Terminal ligatures apply only to bundled coding fonts.", - "preview": "Preview" - }, - "welcomePanel": { - "sectionTitle": "Mode selection area", - "sectionDescription": "The Code Development / Office Work shortcut cards shown above the composer on the new conversation page.", - "showQuickActions": "Show on the new conversation page" - }, - "workspaceBackground": { - "sectionTitle": "Workspace background", - "sectionDescription": "Show a picture behind the whole workspace. Sidebar and panels turn translucent and frosted so the image shows through, and a mask keeps text readable.", - "enable": "Enable background image", - "image": "Image", - "chooseImage": "Choose image", - "replaceImage": "Replace image", - "removeImage": "Remove", - "fillMode": "Fill mode", - "fillModes": { - "cover": "Cover", - "contain": "Contain", - "center": "Center", - "tile": "Tile" - }, - "maskOpacity": "Mask opacity", - "maskOpacityHint": "Higher values fade the image toward the theme background, improving text contrast.", - "imageBlur": "Image blur", - "panelOpacity": "Panel opacity", - "panelOpacityHint": "How opaque the sidebar, panels and tab bars are. Lower lets more of the image show through.", - "errorTooLarge": "Image is too large (max 16 MB).", - "errorUploadFailed": "Failed to set the background image." - } - }, - "SystemSettings": { - "loading": "Loading...", - "sectionTitle": "System Management", - "sectionDescription": "Manage network proxy, app updates and language preferences.", - "proxyTitle": "Network Proxy", - "proxyDescription": "When enabled, subsequent network requests prefer this proxy (including ACP chat, agent installation and Git remote operations).", - "loadFailed": "Load failed: {message}", - "enableProxy": "Enable system proxy", - "proxyAddress": "Proxy address", - "proxyHint": "Supports http(s)/socks5, example: {example}. Only effective when system proxy is enabled.", - "save": "Save", - "saving": "Saving...", - "proxyRequired": "Proxy URL is required when proxy is enabled", - "saveSuccess": "System proxy settings saved", - "saveFailed": "Save failed: {message}", - "languageTitle": "Language", - "languageDescription": "Set app language. When following system locale, unsupported languages fall back to English.", - "appLanguage": "App language", - "languageSaveSuccess": "Language settings saved", - "languageSaveFailed": "Failed to save language settings: {message}", - "updateTitle": "App Update", - "versionTitle": "Software Update", - "updateDescription": "Check the configured release source for newer versions and install directly when available.", - "currentVersion": "Current version", - "upgradableVersion": "Latest version", - "none": "None", - "lastChecked": "Last checked: {time}", - "updateError": "Update error: {message}", - "checking": "Checking...", - "checkUpdate": "Check for updates", - "updating": "Installing...", - "downloading": "Downloading...", - "upgradeTo": "Upgrade to v{version}", - "viewRelease": "View v{version} release", - "foundUpdate": "New version v{version} found", - "alreadyLatest": "You're on the latest version", - "checkUpdateFailed": "Failed to check for updates: {message}", - "installSuccess": "Update installed. Relaunching app.", - "installFailed": "Update failed: {message}", - "upgradeSuccess": "Upgrade complete. Reloading...", - "restartTimeout": "The server didn't come back in time. Check the container or service logs.", - "restartingIn": "Restarting in {seconds}s...", - "waitingForServer": "Waiting for the server to come back...", - "restartToUpdate": "Restart to update", - "newVersionBadge": "New v{version}", - "updateAvailableTitle": "Update available", - "releaseNotesTitle": "What's new", - "remindLater": "Later", - "retry": "Retry", - "stepDownload": "Download", - "stepInstall": "Install", - "stepRestart": "Restart", - "updateReadyHint": "Update downloaded — restart to apply.", - "restarting": "Restarting...", - "dockerUpgradeHint": "This upgrades the running container now. It's lost if the container is recreated — to keep it, pull or build an image at the new version and recreate.", - "upgradeRolledBack": "Upgrade failed; the server rolled back to the previous version.", - "serverUnreachable": "Couldn't reach the server to start the upgrade. Check that it's running and try again.", - "rollbackButton": "Roll back", - "rollingBack": "Rolling back...", - "rollbackDescription": "Restore the version installed before the last upgrade.", - "rollbackConfirmTitle": "Roll back to the previous version?", - "rollbackConfirmDescription": "The server will restart on the version installed before the last upgrade. A newer release stays available to install again.", - "rollbackConfirm": "Roll back", - "rollbackCancel": "Cancel", - "rollbackSuccess": "Rolled back to the previous version. Reloading...", - "rollbackFailed": "Rollback failed. Check the server logs.", - "updateErrors": { - "sourceUnavailable": "Cannot reach the update source. Check your network or proxy and try again.", - "network": "Network connection failed. Check your network or proxy and try again.", - "downloadFailed": "Failed to download update package. Please try again later.", - "installFailed": "Failed to install update. Please close the app and try again.", - "unknown": "Update failed. Please try again later." - } - }, - "VersionControlSettings": { - "loading": "Loading...", - "sectionTitle": "Version Control", - "sectionDescription": "Configure Git executable and manage GitHub accounts.", - "gitTitle": "Git Configuration", - "gitDescription": "Configure the Git executable used by the application.", - "gitDetected": "Git detected", - "gitNotFound": "Git not found on this system", - "gitVersion": "Version", - "gitPath": "Path", - "customGitPath": "Custom Git Path", - "customGitPathPlaceholder": "/usr/bin/git", - "customGitPathHint": "Leave empty to use the auto-detected path.", - "test": "Test", - "testing": "Testing...", - "testSuccess": "Git executable is valid.", - "testFailed": "Git test failed: {message}", - "save": "Save", - "saving": "Saving...", - "saveSuccess": "Git settings saved.", - "saveFailed": "Failed to save: {message}", - "githubTitle": "GitHub Accounts", - "githubDescription": "Manage GitHub accounts for authentication. Tokens are stored locally.", - "noAccounts": "No GitHub accounts configured.", - "addAccount": "Add Account", - "serverUrl": "Server URL", - "serverUrlPlaceholder": "https://github.com", - "token": "Personal Access Token", - "tokenPlaceholder": "ghp_xxxxxxxxxxxx", - "generateToken": "Generate token", - "tokenHint": "Generate a token at GitHub → Settings → Developer settings → Personal access tokens.", - "validateAndAdd": "Validate & Add", - "validating": "Validating...", - "addSuccess": "Account {username} added successfully.", - "addFailed": "Failed to add account: {message}", - "testConnection": "Test", - "connectionSuccess": "Connection successful.", - "connectionFailed": "Connection failed: {message}", - "setDefault": "Set Default", - "defaultLabel": "Default", - "defaultSet": "Default account updated.", - "removeAccount": "Remove", - "removeConfirmTitle": "Remove Account", - "removeConfirmMessage": "Are you sure you want to remove the account \"{username}\"?", - "removeConfirm": "Remove", - "removeCancel": "Cancel", - "removeSuccess": "Account removed.", - "scopes": "Scopes", - "loadFailed": "Failed to load settings: {message}", - "gitAccount": { - "sectionTitle": "Git Accounts", - "sectionDescription": "Manage credentials for non-GitHub Git servers (GitLab, Bitbucket, self-hosted, etc.).", - "noAccounts": "No Git server accounts configured.", - "addAccount": "Add Account", - "addTitle": "Add Git Account", - "addDescription": "Enter the server address, username, and password or access token.", - "serverUrl": "Server URL", - "serverUrlPlaceholder": "https://gitlab.example.com", - "username": "Username", - "usernamePlaceholder": "Username or email", - "password": "Password / Token", - "passwordPlaceholder": "Password or access token", - "passwordHint": "Enter your password or a personal access token for the server.", - "add": "Add", - "serverRequired": "Server URL is required.", - "usernameRequired": "Username is required.", - "passwordRequired": "Password is required." - } - }, - "ShortcutSettings": { - "sectionTitle": "Shortcuts", - "resetDefault": "Reset defaults", - "recordInstruction": "Click the right-side button, then press a key combination. Use Ctrl/Cmd, Alt, and Shift. Press Esc to cancel recording.", - "recording": "Press shortcut...", - "toasts": { - "conflict": "Shortcut is already used by \"{title}\"", - "updated": "Shortcut updated", - "invalid": "Invalid shortcut, please try again", - "reset": "Default shortcuts restored" - }, - "actions": { - "toggle_search": { - "title": "Open Search", - "description": "Show or hide the conversation search panel" - }, - "toggle_sidebar": { - "title": "Toggle Left Sidebar", - "description": "Show or hide the conversation list sidebar" - }, - "toggle_terminal": { - "title": "Toggle Terminal", - "description": "Show or hide the bottom terminal panel" - }, - "new_terminal_tab": { - "title": "New Terminal", - "description": "Create a new terminal tab when focus is on terminal" - }, - "close_current_terminal_tab": { - "title": "Close Current Terminal", - "description": "Close the current terminal tab when focus is on terminal" - }, - "toggle_aux_panel": { - "title": "Toggle Right Panel", - "description": "Show or hide the auxiliary info panel" - }, - "new_conversation": { - "title": "New Conversation", - "description": "Create a new conversation tab in current folder" - }, - "open_folder": { - "title": "Open Folder", - "description": "Open folder picker and open in a new window" - }, - "open_settings": { - "title": "Open Settings", - "description": "Open settings window" - }, - "close_current_tab": { - "title": "Close Current Tab", - "description": "Close current conversation or file tab" - }, - "close_all_file_tabs": { - "title": "Close All File Tabs", - "description": "Close all open file tabs when the file pane is active" - }, - "next_tab": { - "title": "Next Tab", - "description": "Switch to the next conversation or file tab" - }, - "prev_tab": { - "title": "Previous Tab", - "description": "Switch to the previous conversation or file tab" - }, - "send_message": { - "title": "Send Message", - "description": "Send the current message in the input box" - }, - "newline_in_message": { - "title": "Newline in Message", - "description": "Insert a newline in the message input box" - }, - "toggle_custom_style": { - "title": "Suspend/resume custom style", - "description": "Escape hatch: turns all custom colors and CSS off, and back on" - } - } - }, - "SkillsSettings": { - "title": "Skills", - "description": "Select a skill on the left. The right side previews Markdown by default; switch to edit to modify and save.", - "loadingAgents": "Loading agents that support Skills...", - "emptyNoManageableAgents": "No agents available for Skills management.", - "managedTarget": "Managed target", - "selectAgentPlaceholder": "Select an agent", - "searchPlaceholder": "Search by name / ID / path...", - "skillsList": "Skills list", - "loadingSkills": "Loading skills...", - "agentNotSupported": "Current agent does not support Skills management.", - "emptySkills": "No skills yet. Click \"New Skill\" to create one.", - "newSkillTitle": "New Skill", - "skillInfo": "Skill Info", - "skillIdPlaceholder": "skill-id (letters/numbers/-/_/.)", - "skillsDirectoryWithPath": "Skills directory: {path}", - "skillsDirectoryNeedId": "Skills directory: enter Skill ID to generate full path", - "markdownContent": "Markdown Content", - "editingStatus": "Editing", - "previewStatus": "Previewing", - "contentPlaceholder": "Enter Skill markdown content...", - "metadataTitle": "Skills Metadata", - "onlyYamlMetadata": "This skill only contains YAML metadata.", - "emptyContentHint": "No content yet. Click \"Edit\" to start.", - "loadingSkill": "Loading skill...", - "emptyNoAgents": "No available agent.", - "noSelectionHint": "Select a skill on the left, or click \"New Skill\" to create one.", - "systemBadge": "System", - "systemHint": "Built-in CLI skill · read-only", - "scope": { - "global": "Global", - "folder": "Folder", - "selectFolderPlaceholder": "Select a folder", - "noFolders": "No folders found", - "pickFolderHint": "Select a folder to view its skills." - }, - "actions": { - "preview": "Preview", - "edit": "Edit", - "openInWindow": "Open in new window", - "delete": "Delete", - "deleting": "Deleting...", - "refresh": "Refresh", - "newSkill": "New Skill", - "reset": "Reset", - "save": "Save", - "saving": "Saving...", - "cancel": "Cancel" - }, - "deleteDialog": { - "title": "Delete Skill", - "confirm": "Delete current skill? This action cannot be undone.", - "confirmWithNamePrefix": "Delete skill", - "confirmWithNameSuffix": "? This action cannot be undone." - }, - "toasts": { - "loadFailed": "Failed to load skill", - "openFolderFailed": "Failed to open folder", - "noSkillDirectory": "No available Skills directory found for current agent", - "nameRequired": "Skill name cannot be empty", - "updated": "Skill updated", - "created": "Skill created", - "saveFailed": "Failed to save skill", - "deleted": "Skill deleted", - "deleteFailed": "Failed to delete skill" - }, - "templates": { - "gemini": "---\nname: example-skill\ndescription: Describe when this skill should be used.\n---\n\n# Skill Name\n\nInstructions for the agent when this skill is active.\n\n## Workflow\n\n1. Add actionable step one.\n2. Add actionable step two.\n", - "openCode": "---\nname: example-skill\ndescription: Describe when this skill should be used.\n---\n\n# Purpose\n\nDescribe what this skill helps with.\n\n# Steps\n\n1. Add actionable step one.\n2. Add actionable step two.\n", - "openClaw": "---\nname: example-skill\ndescription: Describe when this skill should be used.\nuser-invocable: true\ndisable-model-invocation: false\n---\n\n# Purpose\n\nDescribe what this skill helps with.\n\n# Instructions\n\n1. Add actionable instruction one.\n2. Add actionable instruction two.\n", - "default": "---\nname: example-skill\ndescription: Describe when this skill should be used.\n---\n\n# Skill: example-skill\n\n## When to use\n\n- Describe trigger conditions.\n\n## Instructions\n\n1. Add actionable instruction one.\n2. Add actionable instruction two.\n" - } - }, - "McpSettings": { - "loading": "Loading...", - "summary": { - "missingCommand": "(missing command)", - "missingUrl": "(missing url)" - }, - "protocol": { - "stdio": "Stdio" - }, - "errors": { - "selectInstallProtocol": "Please select an install protocol", - "fieldRequired": "{field} is required", - "fieldNeedsBoolean": "{field} must be true or false", - "fieldNeedsNumber": "{field} must be a number", - "fieldNeedsInteger": "{field} must be an integer", - "fieldInvalidJson": "{field} has invalid JSON: {message}", - "fieldOutOfRange": "{field} value is out of allowed range", - "jsonEmpty": "{name} cannot be empty", - "jsonInvalid": "{name} is not valid JSON: {message}", - "jsonMustBeObject": "{name} must be a JSON object", - "specMustBeObject": "MCP config must be a JSON object.", - "missingType": "MCP config is missing the type field. Use one of stdio, http (aliases: streamable-http, streamableHttp), sse.", - "unsupportedType": "Unsupported MCP type {type}. Supported: stdio, http (aliases: streamable-http, streamableHttp), sse.", - "codexEntryUnsupportedType": "Codex MCP entry {id} has unsupported type {type}. Supported: stdio, http (aliases: streamable-http, streamableHttp), sse.", - "unsupportedTransportType": "Unsupported transport type {type}. Supported: http (aliases: streamable-http, streamableHttp), sse.", - "stdioCommandRequired": "stdio MCP requires a non-empty command field.", - "remoteUrlRequired": "Remote MCP requires a non-empty url field.", - "appsRequired": "Select at least one target app." - }, - "jsonNames": { - "localConfig": "MCP Config", - "installConfig": "Install Config" - }, - "toasts": { - "uninstalled": "MCP uninstalled", - "uninstallFailed": "Uninstall failed: {message}", - "selectAtLeastOneApp": "Please select at least one target app", - "saveSuccess": "Saved", - "saveFailed": "Save failed: {message}", - "installed": "{name} installed", - "installFailed": "Install failed: {message}", - "serverIdRequired": "Server ID is required", - "serverIdExists": "Server ID \"{id}\" already exists. Edit the existing entry or pick a different name.", - "created": "MCP created" - }, - "installDialog": { - "title": "Confirm MCP Installation", - "descriptionWithName": "Install {name} to local configuration.", - "description": "Select target apps for installation.", - "protocol": "Protocol", - "selectProtocol": "Select protocol", - "parameters": "Configuration Parameters", - "booleanPlaceholder": "Please select true/false", - "selectOneValue": "Select a value", - "targetApps": "Target Apps" - }, - "actions": { - "cancel": "Cancel", - "confirmInstall": "Confirm Install", - "installing": "Installing", - "uninstall": "Uninstall", - "uninstalling": "Uninstalling", - "viewDetails": "View Details", - "save": "Save", - "saving": "Saving", - "install": "Install", - "refresh": "Refresh", - "newMcp": "New MCP", - "create": "Create", - "creating": "Creating..." - }, - "tabs": { - "local": "Local MCP", - "market": "MCP Marketplace" - }, - "local": { - "filterPlaceholder": "Filter local MCP...", - "loadFailed": "Load failed: {message}", - "empty": "No local MCP detected.", - "description": "Local MCP configuration can be edited and saved directly.", - "enabledApps": "Enabled Apps", - "configJson": "MCP Config (JSON)", - "draftTitle": "New MCP", - "draftDescription": "Provide a Server ID and configuration to create a local MCP server.", - "serverIdLabel": "Server ID", - "serverIdPlaceholder": "Server ID (e.g. my-mcp)", - "typeHint": "Supported types: stdio, http (aliases: streamable-http, streamableHttp), sse. env is only used by stdio; for remote MCPs use headers to carry auth tokens.", - "envOnRemoteWarning": "env detected on a remote MCP. Only stdio uses env; remote MCPs carry auth tokens via headers, so env will be ignored on save." - }, - "market": { - "selectMarketplace": "Select marketplace", - "searchPlaceholder": "Search MCP...", - "searchFailed": "Search failed: {message}", - "loadingList": "Loading MCP list...", - "empty": "No MCP results.", - "loadingDetail": "Loading marketplace details...", - "detailLoadFailed": "Failed to load details: {message}", - "owner": "Owner: {owner}", - "namespace": "Namespace: {namespace}", - "defaultInstallProtocol": "Default Install Protocol", - "currentOptionParameterCount": "Current option parameter count: {count}", - "installConfigDescription": "Install Config (JSON, editable before install; edits will override protocol/parameter form)", - "selectLeftToView": "Select a marketplace MCP on the left to view details." - }, - "badges": { - "verified": "Verified", - "remote": "Remote", - "hasHomepage": "Has Homepage", - "uses": "{count} uses", - "deployed": "Deployed", - "notDeployed": "Not Deployed" - }, - "selectLeftMcp": "Select an MCP on the left." - }, - "AcpAgentSettings": { - "title": "Agent SDK Management", - "description": "Manage Agent SDK connection, enabled state, environment variables, config management and version preflight info in one place.", - "loadingAgents": "Loading agent list...", - "agentList": "Agent List", - "emptyNoAgent": "No available agent.", - "configManagement": "Config Management", - "envVars": "Environment Variables", - "hostTools": { - "label": "Let the agent handle files and commands", - "description": "codeg stops serving file access and terminal commands, so the agent runs them in its own process — where its own sandbox and permission rules apply. Delegating to other agents is also turned off, since that would route the same work back through codeg. codeg adds no sandbox itself, so turn this on only if the agent has one configured." - }, - "nativeJsonConfig": "Native JSON Config", - "modelHintDefault": "Leave empty to use system default model.", - "generalConfigDescriptionClaude": "Supports quick configuration for API URL, API Key and Claude models, and syncs with native JSON config.", - "generalConfigDescriptionDefault": "Supports important config input (API URL, API Key, Model) and native JSON config management.", - "multiAgent": { - "title": "Multi-Agent Collaboration", - "description": "Allow active agents to delegate sub-tasks to other agents.", - "enable": "Enable delegation", - "enableHint": "When off, the delegate_to_agent tool is hidden from the agent's MCP catalog.", - "withheldByHostTools": "{agents} will not get the delegation tools: their per-agent “Let the agent handle files and commands” switch is on.", - "selfInitiate": "Allow spawn without @", - "selfInitiateHint": "When on, an agent may start a listed sub-agent on its own. An @ mention is still always honored. When off, only an @ mention starts a sub-agent.", - "depthLimit": "Maximum delegation depth", - "depthHint": "Allowed range: {min}–{max}. Caps how deep a chain (root → child → grandchild …) can recurse.", - "completedCacheLabel": "Completed-result cache (MB)", - "completedCacheHint": "In-memory cache of finished sub-agent results, held only while the delegating session is running and cleared automatically when it ends. Over this budget the oldest results are dropped from memory first (still viewable in the sub-agent's own session); 0 = unlimited (still cleared when the session ends).", - "save": "Save", - "saving": "Saving…", - "saved": "Delegation settings saved", - "saveFailed": "Failed to save delegation settings", - "loadFailed": "Failed to load delegation settings: {detail}", - "tabGeneral": "General", - "tabAgentDefaults": "Agent defaults", - "agentDefaultsDescription": "Per-agent overrides applied when Multi-Agent Collaboration spawns a subagent for a delegation call. Options shown here come from a live probe — what you pick is exactly what the agent will accept.", - "probing": "Loading available options from the agent…", - "probeFailed": "Failed to load options: {detail}", - "retry": "Retry", - "noConfigAvailable": "This agent has no configurable options.", - "modeLabel": "Mode", - "agentDefaultHint": "Agent default: {value}", - "defaultOptionLabel": "Default ({value})" - }, - "actions": { - "dragSort": "Drag to reorder", - "dragSortAgent": "Drag to reorder {name}", - "refreshCheck": "Refresh check", - "refreshCheckAgent": "Refresh check {name}", - "clickEnable": "Click to enable {name}", - "clickDisable": "Click to disable {name}", - "install": "Install", - "upgrade": "Upgrade", - "uninstall": "Uninstall", - "uninstalling": "Uninstalling...", - "saveEnvVars": "Save environment variables", - "saving": "Saving...", - "saveGrokConfig": "Save Grok Config", - "saveCodexConfig": "Save Codex Config", - "saveGeminiConfig": "Save Gemini Config", - "saveOpenCodeConfig": "Save OpenCode Config", - "saveOpenClawConfig": "Save OpenClaw Config", - "saveConfigManagement": "Save Config Management", - "saveCurrentProvider": "Save Current Provider", - "showApiKey": "Show API Key", - "hideApiKey": "Hide API Key", - "showKey": "Show Key", - "hideKey": "Hide Key", - "showToken": "Show Token", - "hideToken": "Hide Token", - "cancel": "Cancel", - "delete": "Delete", - "deleting": "Deleting...", - "confirmDelete": "Confirm Delete", - "confirmUninstall": "Confirm Uninstall", - "saveClineConfig": "Save Cline Config", - "saveHermesConfig": "Save Hermes Config", - "saveCodeBuddyConfig": "Save CodeBuddy Config", - "saveKimiCodeConfig": "Save Kimi Code Config", - "customInstall": "Custom install", - "saveKimiCodeRawConfig": "Save config.toml", - "saveDeepSeekConfig": "Save DeepSeek Config", - "diagnose": "Diagnose" - }, - "status": { - "enabled": "Enabled", - "disabled": "Disabled", - "unchecked": "Unchecked", - "agentEnabledAria": "{name} enabled", - "agentEnabledSwitch": "{name} enable switch" - }, - "preflight": { - "count": "Preflight items: {count}", - "notRun": "Checks have not run yet." - }, - "grok": { - "configDescription": "Configure Grok here. The controls below — permission mode, reasoning effort, an optional custom (BYO endpoint) model, and compaction — merge into ~/.grok/config.toml, preserving your other keys and comments. Sign-in uses your XAI_API_KEY or `grok login`. Other keys stay editable under Advanced.", - "permissionModeLabel": "Permission mode", - "permissionDefault": "Ask every time", - "permissionAcceptEdits": "Auto-approve edits", - "permissionAuto": "Smart auto-approve", - "permissionAlwaysApprove": "Always approve", - "reasoningEffortLabel": "Reasoning effort", - "effortLow": "Low (faster)", - "effortMedium": "Medium (balanced)", - "effortHigh": "High", - "effortXhigh": "Max", - "optionDefault": "Use default", - "authTitle": "Authentication", - "authMode": "Authentication method", - "authModeApiKey": "XAI API key", - "authModeApiKeyHint": "Authenticate with an XAI_API_KEY from the xAI console — for non-interactive or headless runs. Stored in this agent's environment.", - "authModeCustom": "Custom endpoint", - "authModeCustomHint": "Use a bring-your-own endpoint: define a custom model below with its own base URL and API key. It becomes Grok's default model.", - "subscriptionHint": "Sign in with `grok login` (SuperGrok / X Premium+). No API key is stored.", - "loginHint": "Run this in a terminal to sign in, then reopen these settings:", - "commandCopied": "Command copied to clipboard", - "copyCommand": "Copy command", - "authKeyConfigured": "XAI_API_KEY is configured.", - "authKeyMissing": "No XAI_API_KEY set.", - "advancedToggle": "Advanced (raw config.toml)", - "configTomlNative": "config.toml (native)", - "configTomlHint": "Saved verbatim as the whole ~/.grok/config.toml. Invalid TOML is rejected so a typo never truncates your file.", - "configTomlPlaceholder": "# Keys other than the controls above, e.g.\n# [mcp_servers.*], [cli], [permission] rules.", - "customModelTitle": "Custom model (BYO endpoint)", - "customModelHint": "Point Grok at a custom or self-hosted endpoint. codeg writes a per-model `[model.*]` block and makes it the default. Leave the Model ID empty to remove it.", - "customModelIdLabel": "Model ID", - "customModelIdPlaceholder": "grok-4.5", - "customModelIdHint": "Registered as a `[model.*]` block and sent to the API as the model name; also set as `[models].default`.", - "customBaseUrlLabel": "Base URL", - "customBaseUrlPlaceholder": "https://api.x.ai/v1 (default)", - "customApiBackendLabel": "API backend", - "backendResponses": "Responses", - "backendChatCompletions": "Chat Completions", - "backendMessages": "Messages (Anthropic)", - "customApiKeyLabel": "API Key", - "customApiKeyHint": "Stored inline in `[model.*].api_key`, scoped to this endpoint.", - "customContextWindowLabel": "Context window (tokens)", - "customContextWindowHint": "Optional. Drives auto-compact timing; leave empty for the endpoint default.", - "autoCompactLabel": "Auto-compact threshold (%)", - "autoCompactHint": "Compact the conversation when context usage reaches this percent (Grok default 85). Written to `[session]`." - }, - "cursor": { - "configDescription": "Configure Cursor here. Choose an authentication method — official subscription (browser sign-in) or a Cursor API key for headless/server machines — then pick a model and edit the CLI's permission rules and sandbox. codeg writes them into ~/.cursor/cli-config.json, shared with the cursor-agent CLI.", - "authTitle": "Authentication", - "authChecking": "Checking…", - "authNotInstalled": "cursor-agent is not installed", - "authLoggedIn": "Logged in", - "authNotLoggedIn": "Not logged in", - "loginHint": "Run this in a terminal to sign in with your Cursor account (a browser window opens), then hit refresh:", - "apiKeyLabel": "Cursor API key", - "apiKeyPlaceholder": "key from cursor.com/dashboard", - "apiKeyHint": "CURSOR_API_KEY — a Cursor Dashboard account key, an alternative to browser login for headless/server machines. Not a third-party or OpenAI key.", - "modelTitle": "Default model", - "loadModels": "Load models", - "modelsUnavailable": "Model list unavailable", - "modelHint": "Passed to the CLI as --model at session start. Leave on default to let Cursor choose.", - "permissionsTitle": "Permissions & sandbox", - "permissionsDescription": "Visual editor for the CLI's permission rules (cli-config.json). Allow rules run without prompting; deny rules are always blocked.", - "permissionModeLabel": "Permission mode", - "permissionModeDefault": "Ask before running (default)", - "permissionModeForce": "Run Everything (--force)", - "permissionModeHint": "Run Everything launches sessions with --force: every tool call is auto-allowed except deny rules, with no confirmation prompts (an organization policy may downgrade it to allow-rule matching). Takes effect for new sessions.", - "optionDefault": "Default (unset)", - "sandboxLabel": "Sandbox", - "sandboxEnabled": "Enabled", - "sandboxDisabled": "Disabled", - "allowRulesLabel": "Allow rules", - "denyRulesLabel": "Deny rules", - "addRule": "Add rule", - "rulesSyntaxHint": "Rule syntax: Shell(cmd), Read(path/glob), Write(path/glob), WebFetch(domain), Mcp(server:tool) — deny rules always win.", - "saveConfig": "Save configuration", - "advancedToggle": "Advanced: raw cli-config.json", - "advancedHint": "The whole ~/.cursor/cli-config.json. Saving writes the file verbatim — the structured controls above merge into it instead.", - "saveRawConfig": "Save file", - "authMode": "Authentication method", - "subscriptionHint": "Sign in with your Cursor account and use Cursor's models.", - "customApiKeyRequired": "A Cursor API key is required.", - "authModeApiKey": "Cursor API key (headless)", - "authModeApiKeyHint": "Authenticate with a Cursor account API key from the Cursor dashboard — for headless or server machines. This is a Cursor account key, not a third-party/OpenAI endpoint: cursor-agent only talks to Cursor's own backend. To use a codex/OpenAI-compatible endpoint, use the Codex agent instead.", - "modelPickerPlaceholder": "Search models…", - "modelNoMatch": "No matching model", - "modelsNeedAuth": "Sign in to load the model list.", - "modelDefaultBadge": "default" - }, - "deepseek": { - "configManagement": "DeepSeek Harness Configuration", - "configDescription": "The endpoint and key are environment variables deepseek-acp reads at launch. Model and reasoning effort are per-session selectors — pick them in the composer.", - "baseUrlLabel": "API endpoint", - "baseUrlHint": "Leave empty for the official endpoint. Applies to sessions started after the save — reconnect a running session to pick it up.", - "baseUrlInvalid": "Enter a full http(s) URL with no query string, for example https://api.deepseek.com", - "apiKeyLabel": "API key", - "apiKeyHint": "Passed to the agent as DEEPSEEK_API_KEY. An environment variable outranks the credentials file, so leave this empty if you sign in through the terminal." - }, - "codex": { - "configDescription": "Supports quick configuration for API URL, API Key, model name and reasoning effort, and syncs with `auth.json` / `config.toml`.", - "authMode": "Auth Mode", - "chatgptSubscription": "Official Subscription", - "chatgptSubscriptionHint": "Log in with ChatGPT official subscription, no API Key required", - "apiKeyHint": "Connect using API Key to OpenAI or compatible API services", - "selectProvider": "Select Provider", - "modelName": "Model Name", - "selectReasoningEffort": "Select Reasoning Effort", - "enableWebsocket": "Enable WebSocket", - "enableWebsocketAria": "Enable WebSocket for Codex Provider", - "enableSkills": "Enable Skills", - "enableSkillsAria": "Enable Skills for Codex", - "enableFast": "Enable Fast", - "enableFastAria": "Enable Fast service tier for Codex", - "sandboxGroupTitle": "Sandbox & approvals", - "sandboxGroupHint": "Written to the global ~/.codex/config.toml, so codex CLI and IDE sessions see it too. These are thread defaults: they govern the turns codex starts on its own (/goal, /review, /compact). Ordinary prompts use the composer's approval preset instead. Restart a session to pick up changes.", - "sandboxShadowedWarning": "config.toml sets default_permissions, so codex resolves permissions through that profile and ignores sandbox_mode entirely. Remove default_permissions to use the controls below.", - "sandboxPermissionsTableWarning": "config.toml defines [permissions] profiles but no default_permissions, which makes codex refuse to start. Set one in the raw editor below.", - "approvalPolicyLabel": "Approval policy", - "approvalPolicyUnset": "Not set (codex default: on request)", - "approvalPolicy_on-request": "On request — the model decides when to ask", - "approvalPolicy_untrusted": "Untrusted — only known-safe read-only commands run unattended", - "approvalPolicy_never": "Never — no approval prompts at all", - "approvalPolicy_granular": "Granular — choose per prompt type", - "approvalPolicyUntrustedAcpWarning": "Untrusted has no equivalent in the ACP adapter's three approval presets, so codeg sessions fall back to \"on request\" — the model then decides when to ask, and commands the sandbox already allows stop prompting. Tighten the sandbox mode below instead.", - "granularHint": "Off means requests of that kind are auto-rejected instead of shown to you.", - "granular_sandbox_approval": "Shell command escalations", - "granular_rules": "Execpolicy rule prompts", - "granular_skill_approval": "Skill script prompts", - "granular_request_permissions": "request_permissions tool prompts", - "granular_mcp_elicitations": "MCP elicitation prompts", - "sandboxModeLabel": "Sandbox mode", - "sandboxModeUnset": "Not set (trusted folders fall back to workspace write)", - "sandboxMode_read-only": "Read-only", - "sandboxMode_workspace-write": "Workspace write", - "sandboxMode_danger-full-access": "Full access (no sandbox)", - "sandboxModeHint": "On Windows, workspace write is downgraded to read-only unless codex's experimental Windows sandbox is enabled.", - "sandboxModeSeedsPresetHint": "codeg also maps this onto the session's starting approval preset, so unlike approval policy it does reach ordinary prompts. The composer's preset still overrides it.", - "writableRootsLabel": "Extra writable folders", - "writableRootsHint": "One absolute path per line, in addition to the working directory.", - "sandboxRootsRelativeError": "Must be an absolute path — codex resolves relative entries against ~/.codex: {path}", - "networkAccessLabel": "Allow network access", - "excludeTmpdirLabel": "Exclude TMPDIR from writable roots", - "excludeSlashTmpLabel": "Exclude /tmp from writable roots", - "authJsonNative": "auth.json (native)", - "configTomlNative": "config.toml (native)", - "loginButton": "Log in with ChatGPT", - "loginRequesting": "Requesting login code...", - "loginStep1": "Open the following URL in your browser:", - "loginStep2": "Enter the code below:", - "loginPolling": "Waiting for authorization...", - "loginCancel": "Cancel", - "loginSuccess": "Logged in successfully, config saved!", - "loginFailed": "Login failed: {message}", - "loginRetry": "Retry", - "loginCodeCopied": "Code copied", - "loggedIn": "Account logged in", - "loginRelogin": "Re-login / Switch account", - "loginTimeout": "Login timed out, please try again", - "loginSaveFailed": "Login succeeded but failed to save config" - }, - "gemini": { - "authConfig": "Gemini Auth Config", - "authConfigDescription": "Aligned with Gemini CLI authentication docs, supporting custom endpoint, Google login, Gemini API Key and Vertex AI (ADC / service account / API Key).", - "authMode": "Auth Mode", - "selectAuthMode": "Select auth mode", - "viewAuthDoc": "View auth docs", - "mode": { - "custom": "Custom Endpoint", - "loginGoogle": "Google Login (OAuth)", - "vertexServiceAccount": "Vertex AI (Service Account)" - }, - "hint": { - "custom": "Fill API URL, API Key and Model, mapped to GOOGLE_GEMINI_BASE_URL / GEMINI_API_KEY / GEMINI_MODEL.", - "loginGoogle": "Run gemini in terminal and complete Google login first; API key is not required.", - "geminiApiKey": "Fill GEMINI_API_KEY when using Gemini API.", - "vertexAdc": "Use gcloud ADC; GOOGLE_CLOUD_PROJECT and GOOGLE_CLOUD_LOCATION are recommended.", - "vertexServiceAccount": "Set service account JSON path to GOOGLE_APPLICATION_CREDENTIALS.", - "vertexApiKey": "Fill GOOGLE_API_KEY when using Vertex AI API key." - } - }, - "openCode": { - "configManagement": "OpenCode Config Management", - "configDescription": "Aligned with OpenCode `provider` schema, supports multi-provider management and two-way sync with native JSON files.", - "providerManagement": "Provider Management", - "providerCount": "{count} providers", - "addProvider": "Add Provider", - "emptyProvider": "No custom providers yet. Click Add custom provider to create one.", - "providerEnabledState": "{providerId} enabled state", - "selectProviderNpm": "Select provider.npm", - "modelManagement": "Model Management", - "modelCount": "{count} models", - "modelDescription": "Aligned with OpenCode `provider.models`. Fast management currently supports `name` / `id`; other advanced fields are preserved and can be edited in native JSON below.", - "addModel": "Add model", - "emptyModel": "No model yet. Enter model id then click \"Add model\".", - "modelId": "Model ID", - "modelName": "Model Name", - "deleteModel": "Delete model {modelId}", - "nativeJsonConfig": "OpenCode Native JSON Config", - "mainModel": "Main Model", - "smallModel": "Small Model", - "noMatchingModels": "No matching models", - "connectProvider": "Connect Provider", - "connectedProviders": "Connected providers", - "noConnectedProviders": "No catalog providers connected yet.", - "advancedProviderConfig": "Custom providers", - "customProviderConfigHint": "OpenAI-compatible endpoints you define yourself — a provider block in opencode.json, with the API key in auth.json.", - "addCustomProvider": "Add custom provider", - "disconnect": "Disconnect", - "editConfig": "Edit", - "customBadge": "Custom", - "authKindApi": "API Key", - "authKindOauth": "OAuth", - "authKindNone": "No credential", - "connect": { - "title": "Connect a provider", - "description": "Choose a provider from the models.dev catalog. Credentials are saved to the OpenCode auth.json file.", - "pick": "Provider", - "search": "Search providers…", - "loading": "Loading catalog…", - "catalogLabel": "models.dev catalog", - "modelsAvailable": "{count} models available", - "getKey": "Get API key", - "oauthApiKeyNote": "This provider also supports browser sign-in via opencode auth login. Browser sign-in is coming soon — for now, paste an API key.", - "apiKey": "API Key", - "apiKeyHint": "Stored in auth.json, never in opencode.json.", - "baseUrlOptional": "Base URL override (optional)", - "providerId": "Provider ID", - "displayName": "Display name", - "modelsList": "Models (one per line)", - "modelsHint": "Model ids the endpoint accepts.", - "action": "Connect", - "editTitle": "Edit provider", - "editDescription": "Update this provider's API key or base URL.", - "saveAction": "Save" - }, - "customProvider": { - "title": "Add a custom provider", - "description": "Define an OpenAI-compatible endpoint. The API key is saved to auth.json; the provider block goes to opencode.json.", - "action": "Add provider", - "idInCatalog": "{providerId} is a known provider — connect it via Connect Provider instead." - }, - "refreshCatalog": "Refresh catalog", - "reasoningBadge": "reasoning", - "contextWindow": "Context window", - "permissions": { - "title": "Permissions", - "description": "Decide which actions run on their own, prompt you first, or are blocked. Written to the permission block of opencode.json and applied once you save below.", - "docsLink": "Permissions docs", - "unparsableConfig": "The native JSON below is not valid, so the visual editor is paused. Fix the JSON to resume.", - "invalidBlock": "The permission block has a shape codeg does not recognize. Edit it in the native JSON below, or use Reset to start over.", - "orderingUnsafe": "A wildcard rule is written after specific tools, so OpenCode applies it to them as well — the rows below are not what is in force. Fix order moves every wildcard back to the front of its scope without changing a single value.", - "orderingUnsafeManual": "One rule is shadowed by a later, more general pattern, so OpenCode never applies it — the rows below are not what is in force. Two overlapping patterns have no single right order; reorder them in the native JSON so the general one comes first.", - "fixOrder": "Fix order", - "agentOverrides": "These agents override permissions and are applied last, so they win over everything here: {agents}. Edit them in the native JSON below, or turn on auto-accept to clear them.", - "legacyTools": "The legacy top-level tools map denies a tool. OpenCode folds it into the permissions, so it applies on top of everything shown here. Edit it in the native JSON below, or turn on auto-accept to clear it.", - "autoAcceptTitle": "Auto-accept every permission", - "autoAcceptHint": "Every tool call — shell commands, file edits, paths outside the project — runs without asking. Turning this on replaces the per-tool settings below with a single allow-all rule, and clears the per-agent permission overrides and legacy tool toggles that would otherwise still block.", - "globalLabel": "Global default", - "globalHint": "The * rule: what applies to anything the tools below do not override.", - "actionUnset": "Unset (OpenCode defaults)", - "actionInherit": "Inherit ({action})", - "actionAllow": "Allow", - "actionAsk": "Ask", - "actionDeny": "Deny", - "perToolTitle": "Per-tool permissions", - "reset": "Reset", - "ruleCount": "rules: {count}", - "rulesToggle": "Fine-grained rules for {tool}", - "rulesHint": "Matched against the tool input, last match wins — so put the broad patterns first. * matches any characters, ? matches exactly one, and a leading ~ expands to your home directory.", - "noRules": "No fine-grained rules yet.", - "addRule": "Add rule", - "deleteRule": "Delete rule {pattern}", - "duplicateRule": "That pattern already exists.", - "blankRule": "A rule needs a pattern — use the trash icon to remove it.", - "customKeys": "Other permission keys in the file", - "customKeyHint": "Not a built-in OpenCode tool — kept as written.", - "keys": { - "bash": "Run shell commands, matched by the parsed command", - "edit": "All file modifications: edit, write and patch", - "read": "Read files, matched by path", - "external_directory": "Reach paths outside the project working directory", - "task": "Launch subagents, matched by subagent type", - "skill": "Load skills, matched by skill name", - "glob": "Find files, matched by glob pattern", - "grep": "Search file contents, matched by pattern", - "list": "List directory contents", - "webfetch": "Fetch a URL", - "websearch": "Search the web", - "lsp": "Run LSP queries", - "todowrite": "Write the todo list", - "question": "Ask you a question", - "doom_loop": "Trips when the same call repeats three times with identical input" - } - } - }, - "openClaw": { - "gatewayConfig": "Gateway Config", - "gatewayDescription": "Configure OpenClaw Gateway connection. Supports local or remote gateway.", - "gatewayUrlHint": "Leave empty to use gateway.remote.url from local openclaw config.", - "gatewayTokenPlaceholder": "Gateway auth token", - "gatewayTokenHint": "Use token-file instead of plain token when possible; configure via openclaw CLI.", - "sessionKeyHint": "Optional. Specify gateway session key; leave empty to auto-assign isolated session." - }, - "hermes": { - "configManagement": "Hermes Configuration", - "configDescription": "Hermes manages its own credentials in ~/.hermes/.env and settings in ~/.hermes/config.yaml. Pick a provider, then set the API key and model — codeg writes both files for you.", - "providerLabel": "Provider", - "providerHint": "The provider selects which API key variable and model.provider Hermes uses. OAuth providers are configured through the terminal setup below.", - "groupApiKey": "API key providers", - "groupOauth": "OAuth providers", - "groupAws": "AWS", - "apiKeyHint": "Saved to ~/.hermes/.env. It is never injected into the process — Hermes reads it from its own config.", - "modelName": "Model", - "oauthHint": "This provider uses OAuth. Run the setup below to authenticate in your terminal.", - "awsHint": "Bedrock uses your AWS credentials (environment or shared config). Set the model id above and configure AWS access in your environment.", - "unsupportedProvider": "This provider isn't editable with structured fields. Use the raw config.yaml editor below or the terminal setup.", - "setupTitle": "Self-managed setup", - "setupHint": "Hermes's interactive setup needs a terminal. Launch it below, or copy the command to run it yourself.", - "runSetup": "Run Hermes setup", - "configureModel": "Configure model", - "openConfigFolder": "Open ~/.hermes", - "copyCommand": "Copy command", - "commandCopied": "Command copied to clipboard", - "advancedTitle": "Advanced: edit config.yaml", - "rawConfigHint": "Edit ~/.hermes/config.yaml directly. Saving here overwrites the file verbatim.", - "saveRawConfig": "Save config.yaml" - }, - "codebuddy": { - "configManagement": "CodeBuddy Configuration", - "configDescription": "CodeBuddy authenticates with an API key. Mainland China builds also require the environment set to “China (internal)”; iOA builds use “iOA”. The overseas build leaves it unset.", - "apiKeyLabel": "API Key", - "apiKeyHint": "Saved as CODEBUDDY_API_KEY for this agent. Alternatively, sign in with the CodeBuddy CLI in a terminal.", - "apiKeyHintSelfHosted": "Saved as CODEBUDDY_API_KEY for this agent. Use the key issued by your private deployment.", - "environmentLabel": "Environment", - "environmentHint": "Sets CODEBUDDY_INTERNET_ENVIRONMENT. Mainland China must use “China (internal)”; the overseas build leaves it unset.", - "envOverseas": "Overseas (default)", - "envChina": "China (internal)", - "envIoa": "iOA", - "envSelfHosted": "Self-hosted (private deployment)", - "baseUrlLabel": "Deployment URL", - "baseUrlPlaceholder": "https://codebuddy.your-company.com", - "baseUrlHint": "Saved as CODEBUDDY_BASE_URL and points CodeBuddy at your private endpoint. The region setting is left unset for self-hosted deployments.", - "baseUrlInvalid": "Enter a valid http(s) URL.", - "loginHint": "No API key? Run “codebuddy” in a terminal to sign in with your Tencent account instead." - }, - "kimiCode": { - "configManagement": "Kimi Code Configuration", - "configDescription": "`kimi acp` only accepts a stored login token, so codeg writes a managed provider into ~/.kimi-code/config.toml and seeds a local gate token — inference still runs on your own key.", - "statusUnconfigured": "Not configured yet", - "statusDirty": "Unsaved changes", - "summaryLabel": "In effect", - "gateReadyApiKey": "API key written to config.toml", - "gateReadyLogin": "Signed in with a Kimi account", - "revealConfig": "Show in folder", - "envOverrideWarning": "{keys} is set and takes priority over config.toml. Saving here clears it.", - "authModeLabel": "Authentication method", - "authModeApiKey": "API key", - "authModeLogin": "Kimi account login (subscription)", - "authModeApiKeyHint": "Writes a codeg-managed provider into config.toml and seeds the gate token so sessions can open.", - "loginHint": "Run `kimi login` in a terminal to sign in with a Kimi subscription account. codeg stores nothing and reuses Kimi's own login. Saving here removes codeg's API-key gate token.", - "credentialTitle": "Credential", - "interfaceTypeLabel": "Provider type", - "interfaceTypeHint": "The provider protocol Kimi speaks (config.toml `type`). Use Kimi / Moonshot for a Moonshot / platform.kimi.com key.", - "endpointLabel": "Endpoint", - "endpointCustom": "Custom (OpenAI-compatible)", - "endpointHint": "International = api.moonshot.ai; China (platform.kimi.com keys) = api.moonshot.cn. Custom points at any OpenAI-compatible endpoint.", - "regionInternational": "International (api.moonshot.ai)", - "regionChina": "China (api.moonshot.cn)", - "baseUrlLabel": "Base URL", - "baseUrlHint": "Leave blank to use the provider SDK default.", - "apiKeyLabel": "API Key", - "apiKeyHint": "Written to ~/.kimi-code/config.toml and used for inference. From platform.kimi.com or platform.kimi.ai.", - "vertexProjectLabel": "GCP project (GOOGLE_CLOUD_PROJECT)", - "vertexLocationLabel": "GCP location (GOOGLE_CLOUD_LOCATION)", - "vertexHint": "Vertex AI uses Google Application Default Credentials — run `gcloud auth application-default login` (no API key).", - "modelTitle": "Model", - "modelLabel": "Model", - "modelHint": "The model id written to config.toml. Use “Test & list models” to see what your key can actually access.", - "maxContextLabel": "Max context size", - "maxContextHint": "Required by Kimi's schema: without it Kimi discards the whole model block and every prompt comes back empty. Defaults to 262144.", - "fetchModels": "Test & list models", - "fetchModelsOk": "Key works — {count} models available", - "fetchModelsEmpty": "Key works, but no models were returned", - "fetchModelsFailed": "Test failed", - "fetchModelsNeedsKey": "Enter an API key and endpoint first", - "modelNotInList": "This model is not in the list your key can access — Kimi will fail with “model not found”.", - "reasoningTitle": "Reasoning", - "reasoningEnableLabel": "Enable", - "reasoningDescription": "Kimi only shows a Thinking picker in the composer when the model declares a reasoning capability, so codeg writes one here. Takes effect on new sessions.", - "effortsLabel": "Levels offered", - "effortsHint": "These become the rows of the composer's Thinking picker. Kimi forwards the level to the provider verbatim, so pick ones your model accepts.", - "effortsEmptyHint": "With no levels chosen the composer falls back to a plain Off / On toggle.", - "effortsCustomPlaceholder": "Add another level", - "effortsAdd": "Add", - "defaultEffortLabel": "Default level", - "defaultEffortAuto": "Let Kimi choose", - "alwaysThinkingLabel": "The model always reasons — remove the Off row from the picker", - "fixErrorsFirst": "Fix the highlighted fields first", - "errorModelRequired": "Model is required", - "errorMaxContextRequired": "Max context size is required", - "errorMaxContextInvalid": "Must be a positive integer", - "errorApiKeyRequired": "API key is required", - "errorApiKeyInvalid": "The API key must not contain line breaks", - "errorBaseUrlRequired": "Base URL is required", - "errorBaseUrlInvalid": "Must start with http:// or https://", - "errorVertexProjectRequired": "GCP project is required", - "errorDefaultEffortUnlisted": "Pick one of the levels selected above", - "advancedTitle": "Advanced", - "authTypeLabel": "Credential placement", - "authTypeApiKey": "Inline api_key", - "authTypeEnv": "Provider env sub-table", - "authTypeHint": "Where the API key is written inside config.toml.", - "rawEditorLabel": "Edit config.toml directly", - "rawEditorWarning": "Saving here overwrites the entire file verbatim, replacing the structured settings above.", - "rawEditorPlaceholder": "[providers.codeg]\ntype = \"kimi\"\nbase_url = \"https://api.moonshot.cn/v1\"\napi_key = \"sk-...\"" - }, - "authModeOfficialSubscription": "Official Subscription", - "authModeCustomEndpoint": "Custom Endpoint", - "authModeCustomEndpointHint": "Manually configure API URL and API Key for a custom endpoint.", - "authModeModelProvider": "Model Provider", - "modelProvider": "Model Provider", - "modelProviderHint": "Use API URL, API Key, and model from a configured model provider.", - "selectModelProvider": "Select Model Provider", - "noModelProviderAvailable": "No model provider configured for this agent. Go to Model Provider Settings to add one.", - "claude": { - "authMode": "Auth Mode", - "officialSubscription": "Official Subscription", - "officialSubscriptionHint": "Use official Anthropic subscription, no API Key required.", - "mainModel": "Main Model", - "reasoningModel": "Reasoning Model (thinking)", - "haikuDefaultModel": "Default Haiku Model", - "sonnetDefaultModel": "Default Sonnet Model", - "opusDefaultModel": "Default Opus Model", - "customModelOption": "Custom Model ID", - "customModelOptionName": "Custom Model Name", - "customModelOptionDescription": "Custom Model Description", - "customModelOptionHint": "Adds a single custom entry to Claude's model picker (e.g. a model behind a custom gateway/proxy). Name and description are optional display overrides.", - "effortLevel": "Reasoning Effort Level", - "effortLevelDefault": "Default Level", - "effortLevel_low": "Low", - "effortLevel_medium": "Medium", - "effortLevel_high": "High", - "effortLevel_xhigh": "Extra High", - "sendAttributionHeader": "Send attribution/billing identifier to the API", - "sendAttributionHeaderAria": "Send Claude Code attribution/billing identifier to the API", - "disableNonessentialTraffic": "Disable telemetry or redundant network requests", - "disableNonessentialTrafficAria": "Disable Claude Code telemetry or redundant network requests" - }, - "dialogs": { - "confirmDeleteProvider": "Delete Provider {providerId}?", - "confirmDeleteProviderDescription": "OpenCode config and auth JSON will be updated together. This action cannot be undone.", - "confirmUninstall": "Uninstall {name}?", - "confirmUninstallDescription": "This removes local installed version. You can reinstall later.", - "customInstallTitle": "Custom install {name}", - "customInstallDescription": "Enter the version to install. This reinstalls and replaces the currently installed version.", - "customInstallVersionLabel": "Version number", - "customInstallInvalid": "Enter a valid version number, e.g. 1.2.3.", - "customInstallSubmit": "Install" - }, - "errors": { - "windowsFileLocked": "{name}'s files are in use by a running session, so Windows can't replace them. Close all {name} sessions and try again.", - "nativeJsonMustBeObject": "Native JSON config must be an object", - "nativeJsonInvalid": "Native JSON config format error: {message}", - "openCodeAuthMustBeObject": "OpenCode auth.json must be a JSON object", - "openCodeAuthInvalid": "OpenCode auth.json format error: {message}", - "authMustBeObject": "auth.json must be a JSON object", - "authInvalid": "auth.json format error: {message}", - "providerIdPattern": "Provider ID only supports letters, numbers, underscore, dot and hyphen", - "providerExists": "Provider {providerId} already exists", - "modelIdPattern": "Model ID only supports letters, numbers, underscore, dot, colon and hyphen", - "modelExists": "Model {modelId} already exists" - }, - "warnings": { - "nativeJsonRecoveredStructured": "Native JSON config is invalid; reset to structured config", - "nativeJsonRecoveredOpenCode": "Native JSON config is invalid; reset to OpenCode structured config", - "openCodeAuthRecovered": "OpenCode auth.json is invalid; reset to default config", - "authRecoveredStructured": "auth.json is invalid; reset to structured config" - }, - "toasts": { - "agentActionCompleted": "{name} {action} completed", - "agentActionFailed": "{name} {action} failed", - "localVersion": "Local version: {version}", - "installCompletedVersionLater": "Install completed, version will update on next check", - "uninstallCompleted": "{name} uninstall completed", - "uninstallFailed": "{name} uninstall failed", - "localVersionRemoved": "Local version removed", - "saveAgentOrderFailed": "Failed to save Agent order", - "saveAgentSwitchFailed": "Failed to save Agent switch", - "saveEnvFailed": "Failed to save environment variables", - "grokSaved": "Grok config saved", - "saveGrokNativeFailed": "Failed to save Grok native config", - "saveGrokApiKeyFailed": "Settings saved, but the API key couldn't be saved", - "cursorSaved": "Cursor config saved", - "saveCursorConfigFailed": "Failed to save Cursor config", - "codexSaved": "Codex config saved", - "saveCodexNativeFailed": "Failed to save Codex native config", - "geminiSaved": "Gemini config saved", - "saveGeminiFailed": "Failed to save Gemini config", - "providerDeleted": "Provider {providerId} deleted", - "providerDeleteFailed": "Failed to delete Provider {providerId}", - "providerSaved": "Provider {providerId} saved", - "saveProviderFailed": "Failed to save Provider {providerId}", - "openCodeConfigSynced": "OpenCode config and auth JSON have been synced.", - "openCodeSaved": "OpenCode config saved", - "saveOpenCodeFailed": "Failed to save OpenCode config", - "openClawSaved": "OpenClaw config saved", - "saveOpenClawFailed": "Failed to save OpenClaw config", - "configSaved": "Config saved", - "configSavedHint": "Existing sessions need to be reopened to take effect", - "saveConfigManagementFailed": "Failed to save config management", - "clineSaved": "Cline config saved", - "saveClineFailed": "Failed to save Cline config", - "hermesSaved": "Hermes config saved", - "saveHermesFailed": "Failed to save Hermes config", - "codeBuddySaved": "CodeBuddy config saved", - "saveCodeBuddyFailed": "Failed to save CodeBuddy config", - "kimiCodeSaved": "Kimi Code config saved", - "saveKimiCodeFailed": "Failed to save Kimi Code config", - "deepseekSaved": "DeepSeek config saved", - "saveDeepSeekFailed": "Failed to save DeepSeek config", - "modelProviderRequired": "Please select a model provider before saving.", - "affectedRunningSessions": "{count, plural, one {# running session needs to reconnect to apply the change} other {# running sessions need to reconnect to apply the change}}", - "providerConnected": "Connected {providerId}", - "connectFailed": "Failed to connect {providerId}", - "providerDisconnected": "Disconnected {providerId}", - "disconnectFailed": "Failed to disconnect {providerId}", - "catalogRefreshed": "Catalog refreshed — {count} providers", - "catalogRefreshFailed": "Failed to refresh catalog", - "piSaved": "Pi config saved", - "savePiFailed": "Failed to save Pi config", - "piRuntimeSaved": "Pi runtime saved", - "savePiRuntimeFailed": "Failed to save Pi runtime", - "piBinaryInstalled": "pi installed", - "piBinaryInstallFailed": "Failed to install pi", - "piBinaryUninstalled": "pi uninstalled", - "piBinaryUninstallFailed": "Failed to uninstall pi", - "savePiTrustFailed": "Failed to save workspace trust" - }, - "version": { - "statusLabel": "Version Status", - "notInstalled": "Not installed", - "remoteLocal": "Remote: {remoteVersion} · Local: {localVersion}", - "localOnly": "Local: {localVersion}", - "localInstalled": "{versionText}. Installed.", - "platformUnsupported": "{versionText}. Current platform does not support this agent.", - "uvxNotReady": "{versionText}. The uv runtime isn't installed — install it from the uv check below to use this agent.", - "clickInstall": "{versionText}. Click Install on the right.", - "localUnrecognized": "{versionText}. Local version is not comparable; try upgrade to overwrite install.", - "upgradeAvailable": "{versionText}. Upgrade available.", - "remoteUnavailable": "{versionText}. Remote version is currently unavailable.", - "latest": "{versionText}. Already latest." - }, - "adapter": { - "label": "ACP adapter", - "badge": "ACP adapter", - "badgeHint": "For this agent Codeg installs an ACP adapter package, not the vendor CLI. The two are independent and share the same config.", - "learnMore": "Learn more", - "missingWithNative": "Found your own {nativeLabel} at {nativePath}. Codeg drives agents over ACP and that CLI does not speak ACP, so Codeg needs a separate adapter package, {adapterPackage}, maintained by the Agent Client Protocol project (originally Zed). It ships its own runtime, never modifies or replaces your {nativeCmd} command, and reads the same {configDir} — your existing sign-in and settings carry over. Install it below.", - "missing": "Codeg drives agents over ACP and the {nativeLabel} does not speak ACP, so Codeg needs a separate adapter package, {adapterPackage}, maintained by the Agent Client Protocol project (originally Zed). It ships its own runtime, so the {nativeCmd} CLI is not required first; if you do have it, the two coexist and share the same {configDir} sign-in and settings. Install it below.", - "readyWithNative": "Adapter {adapterCmd} is installed — that is what Codeg launches, not your own {nativeCmd} at {nativePath}. They are separate packages that coexist, and both read {configDir}, so sign-in and settings are shared.", - "ready": "Adapter {adapterCmd} is installed — that is what Codeg launches. It ships its own runtime, so the {nativeLabel} is not required; install it later and the two coexist, sharing {configDir}." - }, - "cline": { - "configDescription": "Configure Cline API provider and credentials. Settings are saved to ~/.cline/data/." - }, - "opencodePlugins": { - "title": "OpenCode Plugins", - "declared": "Declared Plugins", - "noPlugins": "No plugins declared.", - "status": { - "installed": "Installed", - "missing": "Missing" - }, - "installAll": "Install All Missing", - "pinVersions": "Pin @latest Versions", - "install": "Install", - "uninstall": "Uninstall", - "refresh": "Refresh", - "success": "All plugins installed successfully.", - "failed": "Installation failed" - }, - "pi": { - "configManagement": "Pi Configuration", - "configDescription": "Pi authenticates with your model provider's API key. The key is written to ~/.pi/agent/auth.json and the model selection to settings.json.", - "providerLabel": "Provider", - "modelLabel": "Model", - "thinkingLabel": "Thinking", - "thinking": { - "off": "Off", - "low": "Low", - "medium": "Medium", - "high": "High", - "minimal": "Minimal", - "xhigh": "Extra high" - }, - "apiKeyLabel": "API Key", - "apiKeyHint": "Stored in ~/.pi/agent/auth.json for the selected provider.", - "apiKeySetPlaceholder": "•••••• (saved — leave blank to keep)", - "saveConfig": "Save Pi Config", - "providerModelRequired": "Provider and model are required", - "runtimeTitle": "Runtime", - "runtimeDescription": "Choose which pi binary runs. Use the default, or point at your own pi build.", - "modeDefault": "Default pi", - "modeDefaultHint": "Use the bundled pi-acp adapter with the pi on your PATH. Install pi with: npm install -g @earendil-works/pi-coding-agent", - "modeCustom": "Custom pi", - "modeCustomHint": "Run your own pi build, install, or wrapper.", - "commandLabel": "pi command or path", - "commandHint": "An absolute path, a command name on PATH, or a wrapper script (e.g. a monorepo ./pi-test.sh).", - "commandNotFound": "Command not found", - "validate": "Validate", - "advanced": "Advanced", - "configDirLabel": "Config directory (PI_CODING_AGENT_DIR)", - "sessionDirLabel": "Sessions directory (PI_CODING_AGENT_SESSION_DIR)", - "flagsHint": "Custom pi flags (--approve, -e, …) aren't forwarded by pi-acp — wrap pi in a script and point the command at it.", - "customIncomplete": "Enter a pi command to save", - "saveRuntime": "Save Runtime", - "providerPlaceholder": "Select a provider", - "customProvider": "Custom provider…", - "providerIdLabel": "Provider ID", - "apiProtocolLabel": "API protocol", - "baseUrlLabel": "API endpoint (Base URL)", - "customProviderHint": "Defines a provider in ~/.pi/agent/models.json at your endpoint. Most self-hosted or proxy servers use openai-completions.", - "baseUrlRequired": "API endpoint (Base URL) is required", - "binaryTitle": "pi binary (pi-coding-agent)", - "binaryDescription": "pi-acp runs this pi binary. Install it here, or point pi-acp at your own build below.", - "binaryInstalled": "Installed", - "binaryMissing": "Not installed", - "binaryChecking": "Checking…", - "installBinary": "Install pi", - "installing": "Installing…", - "recheck": "Recheck", - "configDirSkillsNote": "With a custom config directory, the Skills, Experts, and Office tools managed in Settings won't apply to this pi — manage its skills in that folder directly.", - "projectTrustTitle": "Project trust", - "projectTrustDescription": "Folders you allowed pi to load project files from. A trusted folder lets that repository's .pi/extensions run code when pi starts, applies to every folder inside it, and is also used when you run pi in a terminal.", - "projectTrustLoading": "Loading…", - "projectTrustEmpty": "No folders decided yet.", - "projectTrustTrusted": "Trusted", - "projectTrustDenied": "Not trusted", - "projectTrustRevoke": "Revoke", - "reasoningTitle": "Reasoning", - "reasoningEnableLabel": "Enable", - "reasoningDescription": "pi only sends a reasoning effort for a model that declares it — an undeclared model has every level clamped to Off, so the composer's picker springs back the moment you touch it. Written to this model's entry in models.json.", - "levelsLabel": "Available levels", - "levelsHint": "These become the rows in the composer's reasoning picker. Pick the ones your endpoint accepts; pi rejects any level that isn't listed here.", - "levelsEmptyError": "Pick at least one level — with none, pi falls back to Off.", - "wireValuesTitle": "Advanced: values sent to the provider", - "wireValuesHint": "Leave blank to send the level name as-is. Set one when your endpoint expects something else — Google-style backends want LOW / HIGH.", - "defaultLevelUnlisted": "This level isn't in the available list above — pi would clamp it." - }, - "addCustomAgent": "Add custom agent", - "addCustomAgentHint": "Register any ACP-compatible agent. Pick one from the public ACP registry, or paste its registry information.", - "customAgentFromRegistry": "ACP registry", - "customAgentManual": "Manual", - "customAgentSearchPlaceholder": "Search agents…", - "customAgentLoadingCatalog": "Loading the ACP registry…", - "customAgentRetry": "Retry", - "customAgentNoResults": "No matching agents", - "customAgentAdd": "Add", - "customAgentAlreadyAdded": "Added", - "customAgentUnsupportedPlatform": "No build available for this platform", - "customAgentAdded": "Added {name}", - "customAgentIdLabel": "Registry ID", - "customAgentNameLabel": "Display name", - "customAgentVersionLabel": "Version", - "customAgentSpecLabel": "Distribution (JSON)", - "customAgentSpecHint": "Same shape as a registry entry's distribution object: npx, uvx and binary channels, or paste a whole registry entry. For npx/uvx, cmd is the executable the package installs — derived from the package name when omitted, so set it when the two differ. binary is keyed by platform (this machine: {platform}); its cmd is the launch path inside the archive, and sha256 optionally verifies the download.", - "customAgentTemplateLabel": "Templates", - "customAgentKindLabel": "Launch via", - "customAgentInvalidJson": "Not valid JSON", - "customAgentNoDistribution": "No npx, uvx, or binary distribution found", - "customAgentCancel": "Cancel", - "customAgentSave": "Add agent", - "customAgentSaveChanges": "Save changes", - "customAgentEdit": "Edit agent", - "customAgentEditHint": "Update the name, icon, distribution and skills declarations. The agent ID cannot be changed.", - "customAgentEditNotFound": "Custom agent {id} was not found", - "customAgentSaved": "Saved {name}", - "customAgentVersionProbeLabel": "Version probe command (optional)", - "customAgentVersionProbeHint": "Command that prints the locally installed version. Left empty, codeg runs the agent command with --version.", - "customAgentRemove": "Remove agent", - "customAgentRemoveHint": "Deletes the agent definition. Existing conversations keep their history; the agent just can no longer be launched.", - "customAgentIconLabel": "Icon (optional)", - "customAgentIconUpload": "Upload", - "customAgentIconReplace": "Replace", - "customAgentIconClear": "Remove icon", - "customAgentIconHint": "Stored with the agent, so it works offline. Without one, a colored initial is used.", - "customAgentSkillsLabel": "Skills (shared .agents/skills)", - "customAgentSkillsHint": "Declares that this agent reads the shared .agents/skills store — its global and project directories — and adds it to every skills matrix. Skills linked there are visible to every agent that reads the shared store.", - "customAgentSkillsDirLabel": "Dedicated skills directory", - "customAgentSkillsDirHint": "Absolute path of a directory this agent loads skills from — its own store, in addition to (or instead of) the shared one. ~ expands to your home directory; linked skills are placed here first.", - "customAgentMcpLabel": "MCP support", - "customAgentMcpHint": "Sends codeg's built-in MCP companion to this agent when a session starts — the channel behind delegation, live feedback and task tools. Turn it off for an agent that rejects MCP servers and fails to connect; the change applies to the next connection.", - "customAgentIconNotAnImage": "Pick an image file.", - "customAgentIconTooLarge": "The icon must be smaller than {limit} KB.", - "customAgentIconReadFailed": "Could not read that image.", - "customAgentRemoveConfirm": "Remove {name}? Existing conversations stay, but the agent can no longer be launched.", - "customAgentRemoveWithData": "Also delete its recorded conversation history", - "customAgentRemoved": "Removed {name}", - "customAgentBadge": "Custom", - "customAgentNotLaunchable": "This agent cannot launch here: {reason}" - }, - "SettingsPages": { - "agentsLoading": "Loading agent settings...", - "skillPacksLoading": "Loading skill packs…" - }, - "GeneralSettings": { - "loading": "Loading...", - "sectionTitle": "General", - "sectionDescription": "Centralized preferences for the default terminal, rendering acceleration, and multi-agent delegation.", - "terminalTitle": "Default Terminal", - "terminalDescription": "Choose the shell used when opening new terminal tabs from the terminal bar or file tree. Agents also use it when they ask codeg to run a whole command line for them.", - "terminalSystemDefault": "System default", - "terminalPowerShell7": "PowerShell 7 (pwsh)", - "terminalWindowsPowerShell": "Windows PowerShell", - "terminalCmd": "Command Prompt (cmd)", - "terminalSaveFailed": "Failed to save terminal settings: {message}", - "terminalShellCustom": "Custom path", - "terminalShellCustomPath": "Shell path", - "terminalShellCustomPlaceholder": "/usr/local/bin/fish", - "terminalShellCustomSave": "Save", - "terminalShellCustomHint": "Provide an absolute path or a name resolvable on PATH.", - "terminalShellNotInstalled": "not installed", - "terminalShellNotFoundWarning": "This path doesn't exist on this host.", - "terminalCurrentShell": "Currently using: {path}", - "renderingDescription": "Disable hardware acceleration if the app shows a black screen or rendering glitches (common on certain AMD GPUs or Intel integrated GPUs). Only takes effect on the Windows desktop build.", - "disableHardwareAcceleration": "Disable hardware acceleration", - "renderingSaveFailed": "Failed to save rendering settings: {message}", - "restartRequired": "Saved. Restart the app for the change to take effect.", - "restartNow": "Restart now", - "restartFailed": "Failed to restart: {message}", - "loadFailed": "Load failed: {message}" - }, - "LoginPage": { - "documentTitle": "Login - codeg", - "brand": "Codeg", - "subtitle": "Enter your access token to connect to the desktop app", - "tokenPlaceholder": "Access Token", - "connect": "Connect", - "connecting": "Connecting...", - "helpText": "Find your token in the desktop app under Settings → Web Service", - "invalidToken": "Invalid token. Please check and try again.", - "connectionFailed": "Connection failed (HTTP {status})", - "networkError": "Unable to connect to the server" - }, - "CommitPage": { - "title": "Commit", - "invalidFolderId": "Invalid folder ID", - "loadingRepo": "Loading repository..." - }, - "MergePage": { - "title": "Resolve Conflicts", - "invalidFolderId": "Invalid folder ID", - "loadingRepo": "Loading repository...", - "localVersion": "Local (Ours)", - "result": "Result", - "remoteVersion": "Remote (Theirs)", - "acceptLocal": "Accept Local", - "acceptRemote": "Accept Remote", - "markResolved": "Mark Resolved", - "abortMerge": "Abort", - "completeMerge": "Complete Merge", - "unresolvedConflicts": "There are still unresolved conflict markers in this file", - "fileResolved": "File resolved successfully", - "allResolved": "All conflicts resolved", - "conflictFiles": "Conflict Files", - "loadingFile": "Loading file...", - "preparingMerge": "Preparing merge...", - "selectFile": "Select a file to resolve", - "noConflicts": "No conflict files", - "skipFile": "Skip", - "abortSuccess": "Operation aborted", - "applyAllNonConflicting": "Apply All Non-Conflicting", - "applyLeftNonConflicting": "Apply Local", - "applyRightNonConflicting": "Apply Remote" - }, - "ImportSessions": { - "title": "Import Local Sessions", - "scanningTitle": "Scanning local agent sessions…", - "scanningHint": "Walking each agent's local session store. Large histories can take a moment. Sessions you already imported are refreshed along the way.", - "scanFailed": "Scan failed", - "retry": "Retry", - "rescan": "Rescan", - "empty": "No local sessions found", - "emptyHint": "No agent session stores were found on this machine.", - "noMatches": "No sessions match the current filters", - "searchPlaceholder": "Search title or path…", - "allAgents": "All agents", - "onlyImportable": "Importable only", - "selectAll": "Select all", - "clearSelection": "Clear", - "expandAll": "Expand all", - "collapseAll": "Collapse all", - "summaryCounts": "{total} sessions · {importable} importable · {folders} folders", - "noFolderSkipped": "{count} without a project folder skipped", - "folderNew": "New", - "folderCounts": "{importable}/{total} importable", - "toggleFolderAria": "Select all importable sessions in {name}", - "toggleSessionAria": "Select session {title}", - "statusImported": "Imported", - "statusDeleted": "Deleted", - "untitled": "Untitled session", - "messageCount": "{count} msgs", - "selectedCount": "{count} selected", - "importSelected": "Import selected", - "importing": "Importing…", - "close": "Close", - "doneTitle": "Import finished", - "doneImported": "Imported", - "doneUpdated": "Refreshed", - "doneSkipped": "Skipped", - "doneCreatedFolders": "Folders created", - "doneNotFound": "Not found", - "doneFailed": "Failed", - "continueImport": "Continue importing", - "toasts": { - "importFailed": "Import failed: {message}" - } - }, - "Folder": { - "workspaceStatus": { - "degradedTitle": "Live updates unavailable", - "degradedHint": "Watcher failed to start (e.g. permission denied). Refresh manually to see changes.", - "retry": "Retry", - "retrying": "Retrying..." - }, - "common": { - "all": "All", - "cancel": "Cancel", - "close": "Close", - "closeOthers": "Close Others", - "closeAll": "Close All", - "confirm": "Confirm", - "save": "Save", - "delete": "Delete", - "rename": "Rename", - "loading": "Loading...", - "refresh": "Refresh", - "refreshing": "Refreshing...", - "create": "Create", - "createAndSwitch": "Create and Switch", - "openFile": "Open File", - "viewDiff": "View Diff", - "push": "Push..." - }, - "statusLabels": { - "in_progress": "In Progress", - "pending_review": "Review", - "completed": "Completed", - "cancelled": "Cancelled" - }, - "sidebar": { - "title": "Conversations", - "locateActiveConversation": "Locate Active Conversation", - "expandAllGroups": "Expand All Groups", - "collapseAllGroups": "Collapse All Groups", - "newConversation": "New Conversation", - "newConversationShort": "New", - "newChat": "New chat", - "search": "Search", - "noConversationsFound": "No conversations found.", - "importLocalSessions": "Import local sessions", - "importing": "Importing...", - "error": "Error: {message}", - "completeAllSessions": "Complete all sessions", - "completeAllReviewTitle": "Complete all review sessions?", - "completeAllReviewDescription": "This will mark all {count, plural, one {# session} other {# sessions}} in Review as completed.", - "completing": "Completing...", - "toasts": { - "importedSessions": "Imported {imported, plural, one {# session} other {# sessions}}, skipped {skipped}", - "importedAndUpdated": "Imported {imported, plural, one {# session} other {# sessions}}, updated {updated, plural, one {# title} other {# titles}}, skipped {skipped}", - "updatedTitles": "Updated {updated, plural, one {# title} other {# titles}}, skipped {skipped}", - "noNewSessionsFound": "No new sessions found (skipped {skipped})", - "importFailed": "Import failed: {message}", - "reviewCompleted": "Marked {count, plural, one {# review session} other {# review sessions}} as completed", - "completeReviewFailed": "Failed to complete review sessions: {message}", - "folderOpened": "Opened folder {name}", - "folderRemoved": "Removed folder {name}", - "openFolderFailed": "Failed to open folder", - "removeFolderFailed": "Failed to remove folder: {message}", - "reorderFoldersFailed": "Failed to reorder folders: {message}", - "changeFolderColorFailed": "Failed to change folder color: {message}", - "setFolderAliasFailed": "Failed to set alias: {message}", - "changeFolderDefaultAgentFailed": "Failed to set default agent: {message}" - }, - "statsLabel": "{folders} folders · {convos} conversations", - "reorderHandle": "Drag to reorder", - "openFolder": "Open Folder", - "searchPlaceholder": "Search conversations...", - "viewOptions": "View options", - "showCompleted": "Show completed conversations", - "showWorktrees": "Show worktree folders", - "showRecent": "Show Recent group", - "moreOptions": "More options", - "sortBy": "Sort by", - "sortByCreatedAt": "Created time", - "sortByUpdatedAt": "Updated time", - "sectionOrder": "Section order", - "sectionOrderMoveUp": "Move up", - "sectionOrderMoveDown": "Move down", - "sectionOrderItemLabel": "{name} — position {position} of {total}", - "statusRunningBadge": "Running", - "runningCountBadge": "{count, plural, one {# session running} other {# sessions running}}", - "statusCancelledBadge": "Cancelled", - "worktreeRemovedBadge": "Source worktree removed", - "conversationCountUnit": "{count, plural, one {# conversation} other {# conversations}}", - "emptyFolderHint": "No conversations", - "noMatchingConversations": "No matching conversations", - "noUnfinishedConversations": "No unfinished conversations. Enable \"Show completed\" from the top-right menu.", - "removeFolderConfirmTitle": "Remove folder from workspace?", - "removeFolderConfirmDescription": "Remove \"{name}\" from the workspace? Its tabs and terminals will close.", - "folderHeaderMenu": { - "manageConversations": "Manage conversations…", - "manageLinks": "Linked folders", - "changeColor": "Change color", - "useThemeColor": "Use app theme", - "setDefaultAgent": "Set default agent", - "defaultAgentNone": "No default (use global)", - "agentUnavailableSuffix": "(unavailable)", - "loadingAgents": "Loading agents…", - "setAlias": "Set alias…", - "setAliasTitle": "Set folder alias", - "setAliasPlaceholder": "Enter an alias (leave empty to clear)", - "setAliasSave": "Save", - "setAliasCancel": "Cancel", - "removeFromWorkspace": "Remove from workspace" - }, - "manageConversations": { - "title": "Manage conversations", - "searchPlaceholder": "Search by title…", - "agentFilterAll": "All agents", - "statusFilterAll": "All statuses", - "folderFilterAll": "All folders", - "branchFilterAll": "All branches", - "branchNone": "No branch", - "branchSearchPlaceholder": "Search branches…", - "noMatchingBranches": "No matching branches", - "selectAllVisible": "Select all", - "deselectAll": "Deselect all", - "selectedCount": "{count} selected", - "matchedCount": "{count} matched", - "untitledConversation": "Untitled conversation", - "setStatus": "Set status…", - "deleteSelected": "Delete", - "noConversations": "No conversations in this folder.", - "noConversationsWorkspace": "No conversations in the workspace.", - "noMatchingConversations": "No conversations match the filters.", - "confirmDeleteTitle": "Delete {count} conversation(s)?", - "confirmDeleteDescription": "This action cannot be undone.", - "toastDeleted": "Deleted {count} conversation(s)", - "toastStatusUpdated": "Updated status for {count} conversation(s)", - "toastOpFailed": "Operation failed: {message}" - }, - "sectionPinned": "Pinned", - "sectionFolders": "Folders", - "sectionChats": "Chat", - "sectionRecent": "Recent", - "noChats": "No chats", - "noRecent": "No recent conversations", - "showMoreRecent": "Show more ({count})", - "noFolders": "No folders open", - "newChatAction": "New chat", - "automations": "Automations", - "tasks": "To-dos", - "loadingSubsessions": "Loading sub-conversations…" - }, - "conversation": { - "reloadFailed": "Failed to reload conversation: {message}", - "reloaded": "Conversation reloaded", - "reload": "Reload", - "activeConversationIndicator": "Active conversation", - "newConversation": "New Conversation", - "closeConversation": "Close Conversation", - "copyText": "Copy Text", - "copyTextSuccess": "Copied", - "copyTextFailed": "Copy failed", - "forkSession": "Fork Session", - "forkSessionSuccess": "Session forked successfully", - "forkSessionFailed": "Failed to fork session: {error}", - "exportConversation": "Export Conversation", - "exportImage": "Image", - "exportMarkdown": "Markdown", - "exportHtml": "HTML", - "exportSuccess": "Conversation exported", - "exportFailed": "Export failed", - "exportImageTooLong": "Conversation is too long to export as image", - "exportLabels": { - "untitledConversation": "Untitled Conversation", - "agent": "Agent", - "model": "Model", - "status": "Status", - "started": "Started", - "updated": "Updated", - "tokens": "Token Stats", - "duration": "Duration", - "inputTokens": "Input", - "outputTokens": "Output", - "cacheRead": "Cache Read", - "cacheWrite": "Cache Write", - "user": "User", - "assistant": "Assistant", - "system": "System", - "toolResult": "Result", - "toolError": "Error" - }, - "moreActions": "More actions" - }, - "sessionDetails": { - "menuLabel": "Session Details", - "noActiveSession": "No active session", - "title": "Session Details", - "subtitle": "Session metadata and token usage", - "fieldTitle": "Title", - "untitled": "Untitled conversation", - "sessionId": "Session ID", - "externalId": "Extension ID", - "agent": "Agent", - "model": "Model", - "status": "Status", - "gitBranch": "Git Branch", - "parentId": "Parent Session", - "tokensHeading": "Token Usage", - "totalTokens": "Total", - "inputTokens": "Input", - "outputTokens": "Output", - "cacheWrite": "Cache Write", - "cacheRead": "Cache Read", - "contextWindow": "Context Window", - "duration": "Duration", - "loadingStats": "Loading token usage…", - "loadFailed": "Failed to load token usage", - "noStats": "No usage recorded", - "timestampsHeading": "Timestamps", - "createdAt": "Created", - "updatedAt": "Updated", - "none": "—", - "copyField": "Copy {field}", - "copiedField": "Copied {field}" - }, - "conversationCard": { - "untitledConversation": "Untitled conversation", - "newConversation": "New Conversation", - "rename": "Rename", - "status": "Status", - "delete": "Delete", - "importLocalSessions": "Import local sessions", - "importing": "Importing...", - "renameConversation": "Rename conversation", - "deleteConversationTitle": "Delete conversation?", - "deleteConversationDescription": "This will delete \"{title}\". This action cannot be undone.", - "cancel": "Cancel", - "save": "Save", - "pin": "Pin", - "unpin": "Unpin", - "markCompleted": "Mark as completed", - "reopen": "Reopen", - "expandSubsessions": "Expand sub-conversations", - "collapseSubsessions": "Collapse sub-conversations" - }, - "search": { - "dialogTitle": "Search", - "dialogTitleWithFolder": "Search — {name}", - "tabConversations": "Conversations", - "tabFiles": "Files", - "placeholder": "Search conversations...", - "filePlaceholder": "Search files or directories...", - "allAgents": "All", - "searching": "Searching...", - "typeToSearch": "Type to search conversations", - "typeToSearchFiles": "Type to search files or directories", - "noResults": "No results found.", - "untitledConversation": "Untitled conversation" - }, - "folderTitleBar": { - "showSidebar": "Show Sidebar", - "hideSidebar": "Hide Sidebar", - "toggleTerminal": "Toggle Terminal", - "toggleAuxPanel": "Toggle Auxiliary Panel", - "search": "Search", - "openSettings": "Open Settings", - "backToConversations": "Back to Conversations", - "withShortcut": "{label} ({shortcut})" - }, - "statusBar": { - "connection": { - "connected": "Connected", - "connecting": "Connecting...", - "prompting": "Responding...", - "error": "Connection error", - "disconnected": "Disconnected", - "tooltip": "{agent} - {status}", - "tooltipError": "{agent} - {error}", - "title": "Agent connection", - "triggerAria": "Agent connection: {status}", - "workingDir": "Working directory", - "sessionId": "Session ID", - "viewerNote": "Attached to a session another client owns — reconnecting only re-attaches this view.", - "reconnectInterrupts": "Reconnecting restarts the agent and interrupts the work in progress.", - "reconnect": "Reconnect", - "reconnecting": "Reconnecting...", - "reconnectUnavailable": "Nothing to reconnect to yet." - }, - "tasks": { - "title": "Tasks" - }, - "alerts": { - "title": "Alerts", - "empty": "No alerts", - "details": "Details" - }, - "stats": { - "conversations": "{count} conversations", - "openUsage": "View session stats & token usage" - }, - "tokens": { - "contextWindowUsageAria": "Context window usage", - "contextWindow": "Context Window", - "usedMax": "Used / Max", - "tokenUsage": "Token Usage", - "input": "Input", - "output": "Output", - "cacheRead": "Cache Read", - "cacheWrite": "Cache Write", - "total": "Total" - } - }, - "auxPanel": { - "tabs": { - "files": "Files", - "changes": "Changes", - "commits": "Commits" - }, - "noFolderTitle": "No folder open", - "noFolderHint": "Open a folder to see its contents here" - }, - "windowControls": { - "minimizeWindow": "Minimize window", - "minimize": "Minimize", - "maximizeWindow": "Maximize window", - "maximize": "Maximize", - "restoreWindow": "Restore window", - "restore": "Restore", - "closeWindow": "Close window", - "close": "Close" - }, - "tabs": { - "closeConversationTab": "Close conversation tab", - "close": "Close", - "closeOthers": "Close Others", - "splitRight": "Split Right", - "splitDown": "Split Down", - "splitAndMoveRight": "Split and Move Right", - "splitAndMoveDown": "Split and Move Down", - "moveToOppositeGroup": "Move to Opposite Group", - "moveToGroup": "Move to Group", - "groupLabel": "Group {index}", - "changeSplitterOrientation": "Change Splitter Orientation", - "unsplit": "Unsplit", - "unsplitAll": "Unsplit All", - "closeAll": "Close All", - "tileDisplay": "Tile Display", - "untileDisplay": "Exit Tile" - }, - "fileWorkspace": { - "files": "Files", - "closeFileTab": "Close file tab", - "close": "Close", - "closeOthers": "Close Others", - "closeAll": "Close All", - "preview": "Preview", - "editSource": "Edit Source", - "maximize": "Maximize", - "restore": "Restore", - "emptyDirectory": "Empty folder" - }, - "terminal": { - "rename": "Rename", - "close": "Close", - "closeOthers": "Close Others", - "closeAll": "Close All", - "hideTerminal": "Hide Terminal ({shortcut})", - "openFolderFirst": "Open a folder first" - }, - "workspaceDialog": { - "title": "Open Folder", - "manageTitle": "Linked Folders", - "addTargetsTitle": "Add Folders to Link", - "pickRootDescription": "Pick the main folder for this workspace.", - "linksDescription": "Link other folders in as subdirectories so agents can work across all of them from this one workspace.", - "addTargetsDescription": "Select one or more folders. Each becomes a subdirectory of the workspace.", - "useSystemPicker": "System picker", - "next": "Next", - "back": "Back", - "done": "Done", - "change": "Change", - "addFolders": "Add folders", - "addSelected": "Add", - "addSelectedCount": "Add {count}", - "createCount": "Link {count} folder(s)", - "discardPending": "Discard", - "noLinks": "No linked folders yet.", - "gitExclude": "Keep links out of git status", - "rename": "Rename", - "unlink": "Remove link", - "repair": "Recreate link", - "saveName": "Save", - "cancelRename": "Cancel", - "removePending": "Remove", - "willAppearAs": "Appears as {name} in the workspace", - "renamedForDuplicate": "Renamed — {base} is already used by another link", - "renamedForExistingEntry": "Renamed — {base} already exists in this folder", - "partiallyCreated": "Only {count} folder(s) could be linked", - "openFailed": "Failed to open the folder", - "previewFailed": "Failed to check the selected folders", - "createFailed": "Failed to link the folders", - "renameFailed": "Failed to rename the link", - "removeFailed": "Failed to remove the link", - "repairFailed": "Failed to recreate the link", - "status": { - "ok": "Linked", - "missing": "The link is gone from this folder", - "conflicted": "Another entry now uses this name", - "broken": "The linked folder no longer exists" - }, - "nameIssue": { - "empty": "Enter a name", - "illegalChars": "Cannot contain / \\ : * ? \" < > |", - "tooLong": "Name is too long", - "reserved": "This name is reserved by Windows", - "duplicate": "This name is already used" - }, - "rejection": { - "not_found": "This folder could not be found", - "not_a_directory": "This path is not a folder", - "same_as_root": "This is the workspace folder itself", - "ancestor_of_root": "This folder contains the workspace", - "inside_root": "Already inside the workspace", - "already_linked": "Already linked", - "name_unavailable": "No free name is left for this folder", - "alreadyLinkedAs": "Already linked as {name}" - } - }, - "folderNameDropdown": { - "fallbackFolderName": "Folder", - "openFolder": "Open Folder", - "cloneRepository": "Clone Repository", - "projectBoot": "Project Boot", - "opened": "Opened", - "recentOpen": "Recently Opened" - }, - "fileWorkspacePanel": { - "addSelectionToChat": "Add Selection to Chat", - "addToChat": "Add to Chat", - "addSelectionToChatDone": "Added {label} to the conversation", - "addFileToChat": "Add File to Chat", - "toggleWordWrap": "Toggle Word Wrap", - "addFileToChatDone": "Added {label} to the conversation", - "viewDiff": "View Diff", - "openFile": "Open File", - "fileCount": "{count, plural, one {# file} other {# files}}", - "openFileOrDiff": "Open a file or diff from the right panel", - "disk": "Disk", - "head": "HEAD", - "unsaved": "Unsaved", - "workingTree": "Working Tree", - "loading": "Loading...", - "compareWithBranch": "{path} · compare with {branch}", - "hunkCount": "{count, plural, one {# hunk} other {# hunks}}", - "prev": "Prev", - "next": "Next", - "jumpToLine": "Jump to line {line}", - "noParsedDiffSections": "No parsed diff sections", - "loadingEditor": "Loading editor...", - "imageZoomIn": "Zoom in", - "imageZoomOut": "Zoom out", - "imageZoomReset": "Reset zoom", - "htmlPreviewTitle": "HTML preview", - "htmlPreviewTrust": "Enable scripts", - "htmlPreviewTrustHint": "Run this file's scripts and allow network access. Enable only for files you trust.", - "officePreviewTitle": "Office document preview", - "officeFullRender": "Full render", - "officeFullRenderHint": "Render Morph animations, 3D and math (runs the slide's own scripts)", - "officeNotInstalled": "OfficeCLI is not installed", - "officeNotInstalledHint": "Install OfficeCLI under Settings → Office Tools to preview Word, Excel, and PowerPoint files.", - "officeOpenSettings": "Open Settings", - "officeWatchFailed": "Couldn't start the live preview", - "officeWatchRetry": "Retry", - "officeServerInstallHint": "OfficeCLI must be installed on the server host. Run this command there, then retry:", - "officeRemoteDesktopUnsupported": "Live preview isn't available in a remote-desktop window. Open this workspace in the server's web UI to preview Office files." - }, - "branchDropdown": { - "toasts": { - "commitCodeCompleted": "Code commit completed", - "pushCodeCompleted": "Code push completed", - "committedFiles": "Committed {count, plural, one {# file} other {# files}}", - "taskCompleted": "{label} completed", - "taskFailed": "{label} failed", - "mergeNoNewCommits": "{branchName} has no new commits", - "mergedCommits": "Merged {count, plural, one {# commit} other {# commits}}", - "allFilesUpToDate": "All files are up to date", - "updatedFiles": "Updated {count, plural, one {# file} other {# files}}", - "openCommitWindowFailed": "Failed to open commit window", - "openPushWindowFailed": "Failed to open push window", - "upstreamSet": "Upstream branch has been set", - "upstreamSetAndPushed": "Upstream branch set and pushed {count, plural, one {# commit} other {# commits}}", - "noCommitsToPush": "No commits to push", - "pushedCommits": "Pushed {count, plural, one {# commit} other {# commits}}", - "switchedToFolder": "Switched to {name}", - "switchFailed": "Failed to switch branch", - "openStashWindowFailed": "Failed to open stash window" - }, - "tasks": { - "newBranch": "Create branch {name}", - "newWorktree": "Create worktree {name}", - "checkoutTo": "Checkout to {branchName}", - "mergeBranch": "Merge {branchName}", - "rebaseTo": "Rebase to {branchName}", - "deleteRemoteBranch": "Delete remote branch {branchName}", - "initGitRepo": "Initialize Git repository", - "pullCode": "Pull code", - "fetchInfo": "Fetch info", - "pushCode": "Push code", - "stashChanges": "Stash changes", - "stashPop": "Pop stash", - "deleteBranch": "Delete branch {branchName}", - "removeWorktree": "Delete worktree for {branchName}", - "removeWorktreeAndBranch": "Delete worktree and branch {branchName}", - "updateBranch": "Update branch {branchName}" - }, - "confirm": { - "mergeTitle": "Merge branch", - "rebaseTitle": "Rebase branch", - "mergeDescription": "Merge {branchName} into current branch {currentBranch}?", - "rebaseDescription": "Rebase current branch {currentBranch} onto {branchName}?", - "deleteRemoteTitle": "Delete Remote Branch", - "deleteRemoteDescription": "Delete remote branch {branchName}? This will remove it from the remote repository and cannot be undone.", - "deleteTitle": "Delete branch", - "deleteDescription": "Delete branch {branchName}? This action cannot be undone.", - "forceDeleteTitle": "Force Delete Branch", - "forceDeleteDescription": "Branch {branchName} is not fully merged. Are you sure you want to force delete it? This action cannot be undone.", - "deleteWorktreeTitle": "Delete worktree", - "deleteWorktreeDescription": "Delete the worktree directory that has {branchName} checked out? The branch and its commits are kept.", - "forceDeleteWorktreeTitle": "Force delete worktree", - "forceDeleteWorktreeDescription": "The worktree for {branchName} has uncommitted or untracked files. Delete it anyway? Those changes cannot be recovered.", - "deleteWorktreeAndBranchTitle": "Delete worktree and branch", - "deleteWorktreeAndBranchDescription": "Delete the worktree for {branchName}, the branch itself, and its workspace folder? Its sessions move to the repository folder. This action cannot be undone.", - "forceDeleteWorktreeAndBranchTitle": "Force delete worktree and branch", - "forceDeleteWorktreeAndBranchDescription": "The worktree for {branchName} has uncommitted files, or the branch is not fully merged. Delete both anyway? This action cannot be undone." - }, - "current": "Current", - "switchToBranch": "Switch to this branch", - "mergeBranchIntoCurrent": "Merge {branchName} into {currentBranch}", - "rebaseCurrentToBranch": "Rebase {currentBranch} onto {branchName}", - "noBranch": "No branch", - "detachedHead": "Detached HEAD at {sha}", - "initGitRepo": "Initialize Git repository", - "pullCode": "Pull code", - "fetchRemoteBranches": "Fetch remote branches", - "openCommitWindow": "Commit code...", - "pushCode": "Push...", - "pushBranch": "Push", - "newBranch": "New branch...", - "newWorktree": "New worktree...", - "stashChanges": "Stash changes...", - "stashPop": "Unstash...", - "manageRemotes": "Manage Remotes...", - "localBranches": "Local branches ({count, plural, one {#} other {#}})", - "noLocalBranches": "No local branches", - "remoteBranches": "Remote branches ({count, plural, one {#} other {#}})", - "noRemoteBranches": "No remote branches", - "dialogs": { - "newBranchTitle": "New branch", - "newBranchDescription": "Create a new branch from current branch {branch}", - "branchNamePlaceholder": "Branch name", - "newWorktreeTitle": "New worktree", - "newWorktreeDescription": "Create a new worktree from current branch {branch}", - "branchNameLabel": "Branch name", - "worktreePathLabel": "Worktree path", - "worktreePathPlaceholder": "Worktree path", - "manageRemotesTitle": "Manage Remotes", - "manageRemotesEmpty": "No remotes configured", - "remoteNamePlaceholder": "Remote name", - "remoteUrlPlaceholder": "Remote URL", - "addRemote": "Add", - "savingRemotes": "Saving..." - }, - "conflict": { - "title": "Merge Conflicts", - "description": "The following files have conflicts that need to be resolved:", - "abort": "Abort Merge", - "openMergeTool": "Open Merge Tool", - "completeMerge": "Complete Merge", - "abortSuccess": "Merge aborted successfully", - "completeSuccess": "Merge completed successfully" - }, - "stashDialog": { - "title": "Stash Changes", - "description": "Save your current changes to a stash", - "messageLabel": "Message", - "messagePlaceholder": "Stash message (optional)", - "keepIndex": "Keep index (staged changes remain staged)", - "cancel": "Cancel", - "stash": "Stash", - "success": "Changes stashed successfully", - "error": "Failed to stash changes" - }, - "unstashDialog": { - "title": "Unstash Changes", - "noStashes": "No stashes found", - "selectFile": "Select a file to view diff", - "viewDiff": "View Diff", - "original": "Original", - "modified": "Modified", - "apply": "Apply", - "drop": "Drop", - "applySuccess": "Stash applied successfully", - "dropSuccess": "Stash dropped", - "confirmApply": "Apply stash {ref} to working directory?", - "cancel": "Cancel" - }, - "deleteBranch": "Delete branch", - "deleteWorktree": "Delete worktree", - "deleteWorktreeAndBranch": "Delete worktree and branch", - "searchPlaceholder": "Search branches and actions", - "searchAriaLabel": "Search branches and actions", - "branchListLabel": "Branches and actions", - "noMatches": "No matches" - }, - "commitDialog": { - "toasts": { - "commitCompleted": "Code commit completed", - "pushFailed": "Push failed", - "committedFiles": "Committed {count, plural, one {# file} other {# files}}", - "addedToVcs": "Added to VCS", - "addToVcsFailed": "Failed to add to VCS", - "fileDeleted": "File deleted", - "deleteFailed": "Delete failed", - "fileRolledBack": "File rolled back", - "rollbackFailed": "Rollback failed", - "dirRolledBack": "Directory rolled back", - "dirDeleted": "Directory deleted" - }, - "confirm": { - "deleteTitle": "Confirm deletion", - "deleteDescription": "Delete file \"{file}\"? This action cannot be undone.", - "rollbackTitle": "Confirm rollback", - "rollbackDescription": "Rollback file \"{file}\" to HEAD? Unsaved changes will be lost.", - "rollbackDirDescription": "Rollback directory \"{dir}\" to HEAD? Unsaved changes will be lost.", - "deleteDirDescription": "Delete directory \"{dir}\"? This action cannot be undone." - }, - "actions": { - "select": "Select", - "unselect": "Unselect", - "rollback": "Rollback", - "addToVcs": "Add to VCS" - }, - "aria": { - "selectFile": "{action} {path}", - "unselectAllFiles": "Unselect all files", - "selectAllFiles": "Select all files", - "unselectTracked": "Unselect tracked changes", - "selectTracked": "Select tracked changes", - "unselectUntracked": "Unselect untracked files", - "selectUntracked": "Select untracked files" - }, - "loading": "Loading...", - "selectionCount": "{selected} / {total} files", - "emptyFiles": "No changed files", - "trackedChanges": "Tracked changes ({count})", - "untrackedFiles": "Untracked files ({count})", - "commitMessage": "Commit message", - "commitMessagePlaceholder": "Enter commit message...", - "commitButton": "Commit ({count})", - "commitAndPushButton": "Commit and Push ({count})", - "head": "HEAD", - "workingTree": "Working Tree", - "clickFileToDiff": "Click a file name to view diff", - "loadingDiff": "Loading diff..." - }, - "pushWindow": { - "title": "Push Code", - "noUnpushedCommits": "No unpushed commits", - "noRemoteConfigured": "No Git remote configured\nAdd a remote in Manage Remotes", - "newBranchNoPushedCommits": "New branch — push to create remote tracking branch", - "unpushed": "Unpushed", - "selectFileToViewDiff": "Select a file to view diff", - "before": "Before", - "after": "After", - "push": "Push", - "toasts": { - "pushSuccess": "Push successful", - "pushFailed": "Push failed", - "upstreamSet": "Upstream branch has been set", - "upstreamSetAndPushed": "Upstream branch set and pushed {count, plural, one {# commit} other {# commits}}", - "noCommitsToPush": "No commits to push", - "pushedCommits": "Pushed {count, plural, one {# commit} other {# commits}}" - } - }, - "gitLogTab": { - "filesTitle": "Files", - "expandAllFiles": "Expand all files", - "collapseAllFiles": "Collapse all files", - "workspace": "workspace", - "retry": "Retry", - "noCommitsFound": "No commits found", - "notAGitRepoTitle": "Not a Git repository", - "notAGitRepoHint": "Initialize Git from the branch menu above, or open a folder that is already tracked.", - "hash": "Hash", - "copyHash": "Copy hash", - "copyMessage": "Copy message", - "showMore": "Show more", - "showLess": "Show less", - "author": "Author", - "noFileChangeDetails": "No file change details available.", - "loadingFiles": "Loading files...", - "branchesTitle": "Branches", - "loadingBranches": "Loading branches...", - "noContainingBranches": "No containing branches found.", - "newBranch": "New branch...", - "resetToHere": "Reset to Here", - "resetDisabledReasonNotCurrentBranchView": "Available only when viewing current branch", - "copyFullCommitHashAria": "Copy full commit hash {hash}", - "pushStatus": { - "pushed": "Pushed to remote", - "notPushed": "Not pushed to remote", - "unknown": "Push status unknown (no upstream configured)" - }, - "time": { - "monthsAgo": "{count, plural, one {# month ago} other {# months ago}}", - "daysAgo": "{count, plural, one {# day ago} other {# days ago}}", - "hoursAgo": "{count, plural, one {# hour ago} other {# hours ago}}", - "minsAgo": "{count, plural, one {# min ago} other {# mins ago}}", - "justNow": "just now" - }, - "toasts": { - "createdAndSwitchedNewBranch": "Created and switched to new branch", - "newBranchFromCommit": "{name} (from {shortHash})", - "createBranchFailed": "Failed to create branch", - "openPushWindowFailed": "Failed to open push window", - "resetSuccess": "Reset successful", - "resetSuccessDescription": "{branch} reset to {shortHash} with {mode}", - "resetFailed": "Reset failed" - }, - "authorFilter": { - "label": "Author", - "searchPlaceholder": "Search author", - "noAuthors": "No authors found", - "you": "you", - "filterByAuthorAria": "Filter commits by author", - "filterByQuery": "Filter by \"{query}\"", - "clearAuthorFilterAria": "Clear author filter", - "recent": "Recent", - "matchingAuthors": "Matching authors", - "removeFromRecent": "Remove {name} from recent" - }, - "branchSelector": { - "label": "Branch", - "head": "HEAD", - "headHint": "Follows the current branch", - "headHintWithBranch": "Follows the current branch ({branch})", - "searchBranch": "Search branch...", - "noBranches": "No branches", - "selectBranchPlaceholder": "Select branch...", - "localBranches": "Local branches", - "current": "Current", - "remoteBranches": "Remote branches", - "refreshCommitHistory": "Refresh commit history", - "clearBranchFilterAria": "Clear branch filter" - }, - "dialogs": { - "newBranchTitle": "New branch", - "newBranchDescription": "Create a new branch with commit {shortHash} as the latest commit.", - "branchNamePlaceholder": "Branch name", - "reset": { - "title": "Reset Current Branch to Here", - "branchLabel": "Branch", - "targetLabel": "Target", - "messageLabel": "Message", - "modeLabel": "Reset mode", - "confirmButton": "Reset", - "modes": { - "soft": { - "label": "--soft", - "description": "Move HEAD and the current branch pointer to the target commit.\nKeep Index and Working Tree unchanged.\nChanges from the removed commits stay staged." - }, - "mixed": { - "label": "--mixed (default)", - "description": "Move HEAD to the target commit.\nReset Index to the target commit while keeping Working Tree changes.\nThose changes become unstaged." - }, - "hard": { - "label": "--hard", - "description": "Move HEAD and reset both Index and Working Tree to the target commit.\nLocal tracked changes after the target commit are discarded.\nThis is a destructive operation." - }, - "keep": { - "label": "--keep", - "description": "Move HEAD to the target commit and keep local changes when possible.\nOnly non-conflicting local changes are preserved.\nIf conflicts are detected, reset aborts to protect your work." - } - } - } - }, - "moreActions": "More Git actions" - }, - "gitChangesTab": { - "workspace": "workspace", - "noChanges": "No local changes", - "notAGitRepoTitle": "Not a Git repository", - "notAGitRepoHint": "Initialize Git from the branch menu above, or open a folder that is already tracked.", - "trackedChanges": "Tracked changes ({count})", - "untrackedFiles": "Untracked files ({count})", - "expandTracked": "Expand tracked changes", - "collapseTracked": "Collapse tracked changes", - "expandUntracked": "Expand untracked files", - "collapseUntracked": "Collapse untracked files", - "showRemainingItems": "Show {count} more items", - "actions": { - "commitCode": "Commit code", - "rollback": "Rollback", - "addToVcs": "Add to VCS", - "delete": "Delete", - "moreActions": "More Git actions", - "addAllToVcs": "Add all to VCS", - "rollbackAll": "Rollback all", - "refresh": "Refresh" - }, - "toasts": { - "noAddableFilesInDir": "No changed files in this directory can be added to VCS", - "noRollbackFilesInDir": "No changed files in this directory can be rolled back", - "addedToVcs": "Added {name} to VCS", - "addToVcsFailed": "Failed to add to VCS", - "openCommitWindowFailed": "Failed to open commit window", - "rolledBack": "Rolled back {name}", - "rollbackFailed": "Rollback failed", - "addedFilesToVcs": "Added {count, plural, one {# file} other {# files}} to VCS", - "rolledBackFiles": "Rolled back {count, plural, one {# file} other {# files}}", - "deleted": "Deleted {name}", - "deleteFailed": "Delete failed", - "deletedFiles": "Deleted {count, plural, one {# file} other {# files}}", - "noDeletableFilesInDir": "No changed files in this directory can be deleted", - "commitFailed": "Commit failed" - }, - "directoryDialog": { - "descriptionAdd": "Select files under directory {path} to add to VCS.", - "descriptionRollback": "Select files under directory {path} to roll back.", - "descriptionDelete": "Select files under directory {path} to delete. This action cannot be undone.", - "descriptionFallback": "Select files to proceed.", - "selectionCount": "Selected {selected} / {total} files", - "selectAll": "Select all", - "unselectAll": "Unselect all", - "loadingCandidates": "Loading directory changes...", - "noOperableFiles": "No operable files" - }, - "rollbackConfirm": { - "title": "Confirm rollback", - "descriptionWithTarget": "Roll back local changes for {kind} \"{name}\"?", - "descriptionFallback": "Roll back local changes?", - "kindDirectory": "directory", - "kindFile": "file" - }, - "deleteConfirm": { - "title": "Confirm deletion", - "descriptionWithTarget": "Delete {kind} \"{name}\"? This action cannot be undone.", - "descriptionFallback": "This action cannot be undone.", - "kindDirectory": "directory", - "kindFile": "file" - }, - "quickCommit": { - "placeholder": "Commit message (Enter to commit)" - } - }, - "tabContext": { - "loadingConversation": "Loading...", - "untitledConversation": "Untitled conversation", - "newConversation": "New Conversation" - }, - "fileTreeTab": { - "workspace": "Workspace", - "retry": "Retry", - "git": "Git", - "openInFileManager": "Open in file manager", - "openInFinder": "Open in Finder", - "openInExplorer": "Open in Explorer", - "attachToCurrentSession": "Add to session", - "compareWithBranch": "Compare with branch...", - "reloadFromDisk": "Reload from disk", - "new": "New", - "newFile": "File", - "newDirectory": "Directory", - "openIn": "Open in", - "openInTerminal": "Open in terminal", - "linkedFolder": "Linked folder", - "copyPath": "Copy path", - "upload": "Upload files/folder", - "download": "Download file", - "downloadAsZip": "Download as ZIP", - "actions": { - "select": "Select", - "unselect": "Unselect", - "commitCode": "Commit code", - "rollback": "Rollback", - "addToVcs": "Add to VCS" - }, - "aria": { - "selectPath": "{action} {path}" - }, - "toasts": { - "openDirectoryFailed": "Failed to open directory", - "openBuiltinTerminalFailed": "Unable to open built-in terminal", - "openCommitWindowFailed": "Failed to open commit window", - "noAddableFilesInDir": "No changed files in this directory can be added to VCS", - "noRollbackFilesInDir": "No changed files in this directory can be rolled back", - "addedToVcs": "Added {name} to VCS", - "addToVcsFailed": "Failed to add to VCS", - "loadBranchesFailed": "Failed to load branches", - "renameFailed": "Rename failed", - "moveFailed": "Move failed", - "deleteFailed": "Delete failed", - "rolledBack": "Rolled back {name}", - "rollbackFailed": "Rollback failed", - "addedFilesToVcs": "Added {count, plural, one {# file} other {# files}} to VCS", - "rolledBackFiles": "Rolled back {count, plural, one {# file} other {# files}}", - "savedAsCopy": "Saved as a copy", - "saveCopyFailed": "Failed to save as copy", - "watchStartFailed": "Failed to start file watch", - "createFailed": "Failed to create", - "downloadFailed": "Failed to download {name}", - "downloadSaved": "Downloaded {name}", - "pathCopied": "Path copied", - "copyPathFailed": "Failed to copy path" - }, - "createDialog": { - "newFile": "New file", - "newDirectory": "New directory", - "description": "Enter a name for the new {kind}.", - "placeholderFile": "file-name.ext", - "placeholderDirectory": "folder-name" - }, - "renameDialog": { - "renameDirectory": "Rename directory", - "renameFile": "Rename file", - "description": "Enter a new name (name only, no path).", - "placeholderDirectory": "new-folder-name", - "placeholderFile": "new-file-name.ext" - }, - "uploadDialog": { - "title": "Upload to workspace", - "description": "Adjust the destination if needed, then add files or folders.", - "workspaceRoot": "workspace root", - "targetPathLabel": "Upload to", - "targetPathHint": "Resolved path: {path}", - "dropHint": "Drag files or folders here, or use the buttons below", - "dropHintActive": "Release to add to the queue", - "selectFiles": "Select files", - "selectFolder": "Select folder", - "startUpload": "Start upload", - "clearQueue": "Clear finished", - "removeItem": "Remove from queue", - "retry": "Retry", - "dropZoneAria": "Drop files here or activate to browse", - "folderEmpty": "No files found in the dropped folder", - "summary": "Total: {total} · Succeeded: {succeeded} · Failed: {failed}", - "status": { - "pending": "Waiting", - "uploading": "Uploading", - "success": "Done", - "error": "Failed", - "cancelled": "Cancelled" - } - }, - "directoryDialog": { - "descriptionAdd": "Select files under directory {path} to add to VCS.", - "descriptionRollback": "Select files under directory {path} to roll back.", - "descriptionFallback": "Select files to proceed.", - "selectionCount": "Selected {selected} / {total} files", - "selectAll": "Select all", - "unselectAll": "Unselect all", - "loadingCandidates": "Loading directory changes...", - "noOperableFiles": "No operable files" - }, - "compareDialog": { - "title": "Compare with branch", - "descriptionWithTarget": "Select a branch and compare with {kind} {path}", - "descriptionFallback": "Select a branch to compare.", - "kindDirectory": "directory", - "kindFile": "file", - "filterPlaceholder": "Filter branches, e.g. main / origin/main", - "singleClickHint": "Click a branch to compare directly", - "loadingBranches": "Loading branches...", - "recentBranches": "Recent branches ({count})", - "noCurrentBranch": "No current branch", - "localBranches": "Local branches ({count})", - "remoteBranches": "Remote branches ({count})", - "noMatchingBranches": "No matching branches" - }, - "externalConflictDialog": { - "title": "External file changes detected", - "descriptionWithPath": "File {path} has changed on disk, and current edits are unsaved.", - "descriptionFallback": "Current file has changed on disk, and current edits are unsaved.", - "compare": "Compare", - "savingCopy": "Saving copy...", - "saveAsCopy": "Save as copy", - "reload": "Reload" - }, - "deleteConfirm": { - "title": "Confirm deletion", - "descriptionWithTarget": "Delete {kind} \"{name}\"? This action cannot be undone.", - "descriptionFallback": "This action cannot be undone.", - "kindDirectory": "directory", - "kindFile": "file" - }, - "rollbackConfirm": { - "title": "Confirm rollback", - "descriptionWithTarget": "Rollback local changes for file \"{name}\"?", - "descriptionFallback": "Rollback local changes for this file?" - }, - "terminalTitle": "Terminal · {name}" - }, - "commandDropdown": { - "loading": "Loading...", - "addCommand": "Add Command", - "manageCommands": "Manage Commands...", - "runCommandTitle": "Run: {command}", - "stopCommandTitle": "Stop: {command}", - "manageDialog": { - "title": "Manage Commands", - "empty": "No commands yet", - "noResults": "No matching commands", - "searchPlaceholder": "Search commands", - "newCommand": "New command", - "nameLabel": "Name", - "commandLabel": "Command", - "dragSort": "Drag to sort", - "dragSortCommand": "Drag to sort {name}", - "orderFailed": "Failed to save command order", - "loadFailed": "Failed to load commands", - "saveFailed": "Failed to save command", - "deleteFailed": "Failed to delete command", - "confirmDelete": { - "title": "Delete command?", - "message": "This will remove \"{name}\". This action cannot be undone." - } - } - }, - "workspaceContext": { - "confirmCloseDirtyTab": "Close \"{title}\" without saving?", - "confirmCloseOtherDirtyTabs": "Close other tabs with unsaved changes?", - "confirmCloseAllDirtyTabs": "Close all tabs with unsaved changes?", - "unableLoadContent": "Unable to load content.\n\n{message}", - "previewRequestTimedOut": "Preview request timed out", - "diffRequestTimedOut": "Diff request timed out", - "branchCompareRequestTimedOut": "Branch compare request timed out", - "commitDiffRequestTimedOut": "Commit diff request timed out", - "saveRequestTimedOut": "Save request timed out", - "reloadRequestTimedOut": "Reload request timed out", - "noChanges": "No changes.", - "noDiffOutput": "No diff output.", - "diffTitleWorkspace": "Diff · Workspace", - "diffDescriptionWorkingTree": "Working tree (HEAD)", - "diffTitleFile": "Diff · {name}", - "compareTitleFile": "Compare · {name}", - "compareTitleBranch": "Compare · {branch}", - "compareDescriptionPath": "{path} · compare with {branch}", - "compareDescriptionBranch": "compare with {branch}", - "diffTitleCommitFile": "Diff · {name} @ {hash}", - "diffTitleCommit": "Diff · {hash}", - "diffDescriptionCommitPath": "{path} · commit {commit}", - "diffDescriptionCommit": "commit {commit}", - "diffTitleConflictFile": "Conflict · {name}", - "diffDescriptionConflict": "{path} · disk vs unsaved" - }, - "chat": { - "acpConnections": { - "actions": { - "openAgentsSettings": "Open Agents settings", - "retry": "Retry" - }, - "agentsSetupHint": "Open Settings > Agents to manage installation.", - "withSetupHint": "{message}\n{hint}", - "blocked": { - "missingConfig": "Unable to read current Agent configuration.", - "disabled": "{agent} is disabled in Agents settings. Enable it before connecting.", - "unavailable": "{agent} is unavailable on the current platform.", - "sdkMissing": "{agent} SDK is not installed", - "adapterMissing": "{agent}'s ACP adapter is not installed" - }, - "backendErrors": { - "initializeTimeout": "{agent} connection handshake timed out after 60 seconds. Please open Settings to check Agent configuration and network settings.", - "mcpRejectedByAgent": "{agent} refused the session while codeg’s MCP companion was attached: {message} If this agent does not support MCP, turn off “MCP support” for it in Settings and connect again.", - "processExited": "{agent} process exited unexpectedly.", - "spawnFailed": "Failed to start {agent}: {message}", - "downloadFailed": "{agent} download failed: {message}", - "sessionLoadResourceNotFound": "{agent} session failed to load. Reload to retry, or start a new conversation.", - "sessionLoadUnavailable": "{agent} couldn't restore this session — it may have ended or the agent stopped. Reload to retry, or start a new conversation.", - "turnFailedRefusal": "{agent} refused to continue this turn. This often indicates a backend or gateway error — check the agent's logs.", - "turnFailedMaxTokens": "{agent} reached the maximum token limit for this turn.", - "turnFailedMaxTurnRequests": "{agent} reached the maximum number of allowed requests for this turn.", - "turnFailedUnknown": "{agent} ended the turn with an unrecognized stop reason.", - "grokModelSwitchIncompatibleAgent": "{agent} can't switch to that model in an existing conversation. Start a new session to use it.", - "turnFailedEmpty": "{agent} ended the turn without producing any response.", - "turnFailedEmptyProtocol": "{agent} produced output that codeg could not parse — the agent version may not match the protocol.", - "turnFailedEmptyMetadata": "{agent} sent only status updates this turn (plan / mode / usage) and no reply.", - "detailsInAlerts": "Open Alerts in the status bar and expand the details to see the agent's output." - }, - "unableReadAgentConfig": "Unable to read Agent config: {message}", - "connectFailedTitle": "{agent} connection failed", - "toolFallbackTitle": "Tool", - "eventErrorTitle": "Agent Error", - "notificationTurnComplete": "{agent} has finished responding", - "notificationError": "{agent} error: {message}", - "claudeApiRetry": { - "fallbackError": "authentication_failed", - "retryingWithMax": "retrying {attempt}/{max}", - "retryingAttempt": "retrying attempt {attempt}", - "retrying": "retrying", - "nextRetryIn": "next in {seconds}s", - "line": "{error}{status} · {retry}", - "lineWithDelay": "{error}{status} · {retry}, {delay}", - "httpStatus": " (HTTP {status})" - }, - "configOptionAdjusted": "{agent} set {option} to {actual} instead of {requested}" - }, - "connectionLifecycle": { - "tasks": { - "connectingTitle": "Connecting to {agent}", - "connectingDescription": "Establishing connection", - "loadingSelectorsTitle": "Loading {agent} selectors", - "loadingSelectorsDescription": "Fetching mode and session config options", - "initSessionTitle": "Initializing {agent} session", - "initSessionDescription": "Creating session and loading configuration" - }, - "errors": { - "connectionFailed": "Connection failed", - "sendPromptFailed": "Failed to send the message: {error}" - } - }, - "shared": { - "attachedResources": "Attached resources", - "toolCallFailed": "Tool call failed" - }, - "messageThread": { - "emptyTitle": "No messages yet", - "emptyDescription": "Start a conversation to see messages here" - }, - "chatInput": { - "connecting": "Connecting...", - "agentResponding": "{agent} is responding...", - "sendMessage": "Send a message..." - }, - "messageInput": { - "askAnything": "Ask anything...", - "removeAttachmentAria": "Remove {name}", - "attachFiles": "Attach files", - "attachLocalUpload": "Upload local file", - "attachServerFile": "Pick server file", - "addActions": "Add", - "quickMessages": "Quick messages", - "quickMessagesEmpty": "No quick messages yet", - "quickMessagesLoading": "Loading...", - "pasteAsPlainText": "Paste as plain text", - "cut": "Cut", - "copy": "Copy", - "selectAll": "Select all", - "pasteUnavailable": "Couldn't read the clipboard. Press Ctrl/⌘V to paste instead.", - "clipboardWriteFailed": "Couldn't write to the clipboard. Use the keyboard shortcut instead.", - "quickMessageUntitled": "Untitled", - "liveFeedback": "Live feedback", - "liveFeedbackDisabledHint": "Available while the agent is working", - "dropFilesToAttach": "Drop files to attach", - "loadingSettings": "Loading settings...", - "loadingMode": "Loading mode...", - "modeLabel": "Mode", - "toggleOn": "On", - "toggleOff": "Off", - "agentSettings": "Agent settings", - "searchModel": "Search models...", - "searchModelAria": "Search models", - "modelListLabel": "Models", - "noModels": "No models found", - "cancel": "Cancel", - "send": "Send", - "forkAndSend": "Fork & Send", - "queueMessage": "Queue message", - "steerIntoTurn": "Insert into current turn", - "steerQueuedInstead": "Queued instead — it will be sent with the next turn.", - "steerFailed": "Couldn't insert into the current turn", - "steerAttachmentsUnsupported": "Text only — drafts with attachments go through the queue.", - "slashCommands": "Slash commands", - "slashSearchPlaceholder": "Search commands...", - "slashSearchEmpty": "No matching commands", - "experts": "Experts", - "office": "Office Work", - "research": "Scientific Research", - "attachUploadTooLarge": "{names} exceeds the {limit}MB upload limit and was skipped.", - "attachUploadFailed": "Failed to upload {names}.", - "attachUploadNotAFile": "{names} isn't a regular file (directory or special file) and was skipped.", - "attachUploadQuotaExceeded": "The server is out of upload storage; {names} couldn't be uploaded.", - "attachUploadInProgress": "Images are still uploading — try again in a moment.", - "mentionEmpty": "No matches", - "mentionLoading": "Searching…", - "mentionListLabel": "Mentions", - "mentionMore": "More results — keep typing to filter", - "mentionCount": "{count, plural, one {# result} other {# results}}", - "mentionGroupFile": "Files", - "mentionGroupAgent": "Agents", - "mentionGroupSession": "Sessions", - "mentionGroupCommit": "Commits", - "mentionGroupSkill": "Skills" - }, - "messageQueue": { - "addToQueue": "Queue message", - "saveEdit": "Save", - "cancelEdit": "Cancel edit", - "editItem": "Edit", - "deleteItem": "Remove" - }, - "welcomeInputPanel": { - "agentsSettingsPath": "Settings > Agents", - "autoConnectFallback": "Click to open {path} and manage installation.", - "autoConnectAppend": "{message}. Click to open {path} and manage installation.", - "enableAgentFirstPlaceholder": "Enable at least one agent before starting a session...", - "prepareSessionFailed": "Couldn't prepare the chat session. Please try again.", - "createConversationFailed": "Couldn't create the conversation. Please try again.", - "askAnythingPlaceholder": "Ask anything...", - "agentNotInstalled": "{agent} is not installed — open Agents settings to install it", - "agentAdapterNotInstalled": "{agent}'s ACP adapter is not installed (separate from your own CLI) · open Agents settings to install it" - }, - "welcomePanel": { - "greeting": "What would you like to do today?", - "tips": { - "tileTabs": "Right-click any conversation tab and choose Tile Display to see multiple sessions side by side.", - "pinTab": "Double-click a conversation tab to pin it, so a newly opened session won't auto-replace it.", - "shortcutsNewSearch": "{newConversation} opens a new conversation, {searchConversations} searches your history.", - "slashAtMention": "Type / in the input to trigger slash commands, or @ to reference a file from the project.", - "pasteDropFiles": "Paste a screenshot or drop a file directly onto the input to attach it.", - "queueMessage": "While the agent is replying, keep typing — your next message gets queued and auto-sent when it finishes.", - "draftAutoSave": "Unsent drafts are auto-saved per conversation and restored when you come back.", - "forkSend": "The send button's dropdown has Fork and Send — branch from the current turn into a new tab.", - "exportConversation": "Right-click inside the conversation to export it as Markdown, HTML, or an image.", - "chatChannels": "Connect Telegram / Lark / WeChat under Settings → Chat Channels to continue from your phone.", - "shortcutsAuxPanel": "{toggleAuxPanel} toggles the right panel to view this session's touched files and Git changes.", - "shortcutsTerminalSidebar": "{toggleTerminal} opens the built-in terminal, {toggleSidebar} toggles the sidebar.", - "customShortcuts": "Every shortcut is fully remappable under Settings → Shortcuts.", - "webService": "Enable Settings → Web Service so teammates can reach the same codeg from a browser.", - "fusionMode": "Open a file or diff to automatically show it alongside the conversation.", - "quickMessages": "Open the + button next to the input and pick Quick Messages to insert a saved snippet (manage them under Settings → Quick Messages).", - "experts": "The + button has an Expert Skills menu — preload roles like Debug or Planning with one click.", - "taskBoard": "To-dos run a task end to end — the agent works in its own worktree, then you review the diff and merge.", - "automations": "Automations run a saved prompt on a schedule — a nightly review, a recurring report — and each run can get its own worktree.", - "tokenUsage": "Click the conversation count in the status bar to open Token Usage — spend broken down by day, agent, model, and folder.", - "mentionTargets": "@ pulls in more than files — mention another agent to hand off a subtask, or reference a past session, a commit, or a skill.", - "splitGroups": "Right-click a tab and pick Split Right or Split Down to keep two conversations open in their own panes.", - "worktrees": "Open the branch button and pick New worktree so several agents can work the same repo without overwriting each other's files.", - "importSessions": "Already ran sessions in the terminal? A folder's menu has Import local sessions — bring that history into codeg.", - "subSessions": "When an agent delegates, the sub-session appears nested under it in the sidebar — expand the row to follow what each one did.", - "liveFeedback": "Live feedback in the + menu drops a note into the turn the agent is already running, without interrupting it.", - "skillPacks": "Settings → Skill Packs bundles coding experts, scientific research, and office skills — switch them on per agent.", - "modelProviders": "Settings → Model Providers takes your own API key or endpoint, and you pick the model right in the composer.", - "workspaceBackground": "Settings → Appearance sets a workspace background image, panel opacity, and the app's fonts." - }, - "quickActions": { - "excel": "Excel Workbook", - "excelDesc": "Data tables, formulas & charts", - "word": "Word Document", - "wordDesc": "Reports, letters & memos", - "ppt": "Presentation", - "pptDesc": "Slides with professional design", - "pitchDeck": "Pitch Deck", - "pitchDeckDesc": "Fundraising deck with key metrics", - "morph": "Morph Animation", - "morphDesc": "Cinematic slide transitions", - "morph3d": "3D Morph", - "morph3dDesc": "3D models with camera moves", - "academic": "Academic Paper", - "academicDesc": "Research with citations & structure", - "financial": "Financial Model", - "financialDesc": "Statements, DCF & projections", - "dashboard": "Data Dashboard", - "dashboardDesc": "KPIs & analytics from your data", - "prompts": { - "excel": "Create an Excel workbook with the following requirements:\n\n[describe your data, tables, formulas, and charts here]", - "word": "Create a Word document with the following requirements:\n\n[describe your document content, structure, and formatting here]", - "ppt": "Create a PowerPoint presentation with the following requirements:\n\n[describe your slides, content, and design here]", - "pitchDeck": "Create a fundraising pitch deck with the following requirements:\n\n[describe your company, funding round, and key metrics here]", - "morph": "Create a presentation with Morph transition animations:\n\n[describe your presentation topic and desired visual effects here]", - "morph3d": "Create a 3D Morph presentation with GLB models and camera moves:\n\n[describe your topic and 3D visual concept here]", - "academic": "Write an academic paper in Word with the following requirements:\n\n[describe your research topic, methodology, and key findings here]", - "financial": "Create a financial model in Excel with the following requirements:\n\n[describe your financial statements, projections, and analysis here]", - "dashboard": "Create a data dashboard in Excel with the following requirements:\n\n[describe your data source, KPIs, and charts here]", - "scientific-brainstorming": "Help me brainstorm research directions — explore interdisciplinary connections, challenge assumptions, and surface promising gaps. The area I'm exploring: ", - "hypothesis-generation": "Help me turn these observations into testable hypotheses — with clear predictions, plausible mechanisms, and experiments to test them. My observations: ", - "experimental-design": "Help me design a rigorous experiment before I collect data — the design, randomization, controls, and how to avoid confounding. What I want to study: ", - "statistical-power": "Help me determine the sample size I need — walk me through a power analysis (effect size, alpha, power) for my design. Details: ", - "statistical-analysis": "Help me analyze this data properly — choose the right test, check assumptions, report effect sizes, and write it up. My data and question: ", - "exploratory-data-analysis": "Do an exploratory analysis of my data file — summarize its structure, quality, and notable patterns, then suggest next steps. The file is: ", - "scientific-visualization": "Help me make a publication-quality figure — clear layout, honest error bars, a colorblind-safe palette, and journal formatting. What I want to show: ", - "scientific-critical-thinking": "Help me critically appraise this study or claim — assess the evidence quality, spot biases and confounders, and weigh the conclusions. Here it is: ", - "paper-lookup": "Help me find relevant papers and open-access full text across scholarly databases, with citations I can reuse. I'm looking for: " - }, - "paper-lookup": "Paper Lookup", - "paper-lookupDesc": "Search 10 scholarly APIs (PubMed, arXiv, OpenAlex, Crossref…) for papers, citations, and open-access full text.", - "scientific-critical-thinking": "Critical Thinking", - "scientific-critical-thinkingDesc": "Appraise scientific claims and evidence quality — spot biases and confounders, apply GRADE and risk-of-bias frameworks.", - "scientific-visualization": "Scientific Visualization", - "scientific-visualizationDesc": "Publication-ready figures — multi-panel layouts, significance annotations, and journal-specific formatting.", - "exploratory-data-analysis": "Exploratory Data Analysis", - "exploratory-data-analysisDesc": "Automated exploration of scientific data files across 200+ formats with quality metrics and reports.", - "statistical-analysis": "Statistical Analysis", - "statistical-analysisDesc": "Guided statistical analysis — test selection, assumption checks, effect sizes, and APA-style reporting.", - "statistical-power": "Statistical Power", - "statistical-powerDesc": "Sample-size and power analysis — how many subjects you need, minimum detectable effects, and power curves.", - "experimental-design": "Experimental Design", - "experimental-designDesc": "Design rigorous studies before collecting data — randomization, blocking, controls, and factorial/DOE layouts.", - "hypothesis-generation": "Hypothesis Generation", - "hypothesis-generationDesc": "Turn observations into testable hypotheses with predictions, mechanisms, and experiments to test them.", - "scientific-brainstorming": "Scientific Brainstorming", - "scientific-brainstormingDesc": "Open-ended research ideation — explore interdisciplinary links, challenge assumptions, and surface research gaps.", - "tabs": { - "office": "Office Work", - "coding": "Code Development", - "research": "Scientific Research" - }, - "coding": { - "brainstormingDesc": "Explore intent & requirements before building", - "debuggingDesc": "Find the root cause before proposing fixes", - "writingSkillsDesc": "Create, edit & verify reusable skills" - }, - "notEnabled": { - "title": "“{skill}” isn’t enabled for {agent} yet", - "description": "Enable it in Settings to use it here.", - "action": "Enable", - "hint": "Skill not enabled" - }, - "scrollPrev": "Show previous skills", - "scrollNext": "Show more skills" - } - }, - "agentSelector": { - "noEnabledAgents": "No enabled agents", - "openAgentsSettings": "Open Agents settings", - "notInstalled": "Not installed", - "moreAgents": "More agents ({count})" - }, - "subAgentOverlay": { - "title": "Sub-agents", - "collapsedSummary": "Sub-agents {count}", - "collapseAria": "Collapse sub-agents" - }, - "agentPlanOverlay": { - "title": "Agent Plan", - "collapsePlanAria": "Collapse plan", - "collapsedSummary": "Plan {completed}/{total}", - "status": { - "completed": "Completed", - "inProgress": "In Progress", - "pending": "Pending", - "unknown": "Unknown" - }, - "priority": { - "high": "High", - "medium": "Medium", - "low": "Low", - "unknown": "Unknown" - } - }, - "permissionDialog": { - "subtitle": "Agent requests permission to continue this turn.", - "queuedCount": "+{count} waiting", - "kindFallbackTool": "tool", - "command": "Command", - "cwd": "CWD: {cwd}", - "filesSummary": "Files: {count}", - "moreFiles": "+{count} more files", - "plan": "Plan", - "allowedActions": "Allowed actions", - "targetMode": "Target mode: {mode}", - "optionGrants": "What each option grants", - "changeScopeSession": "This session", - "changeScopeProcess": "This run", - "changeScopeUser": "Saved to user settings", - "changeScopeProject": "Saved to project settings", - "changeScopeProjectLocal": "Saved to local project settings", - "changeScopePersistent": "Saved permanently" - }, - "questionDialog": { - "title": "Agent is asking a question", - "placeholder": "Type your answer...", - "send": "Send" - }, - "messageBranch": { - "previousBranchAria": "Previous branch", - "nextBranchAria": "Next branch", - "pageOf": "{current} of {total}" - }, - "terminal": { - "title": "Terminal", - "running": "Running" - }, - "reasoning": { - "thinking": "Thinking…", - "thoughtForFewSeconds": "Thought", - "thoughtForSeconds": "Thought" - }, - "linkSafety": { - "errorCannotOpen": "Cannot open local file", - "errorNoWorkspace": "No workspace folder is currently active.", - "errorFailedOpen": "Failed to open local file", - "errorFailedLink": "Failed to open link", - "errorUnsupportedLinkProtocol": "This link protocol is not supported." - }, - "fileActions": { - "openInFinder": "Open in Finder", - "openInExplorer": "Open in Explorer", - "openInFileManager": "Open in file manager", - "copyRelativePath": "Copy relative path", - "copyAbsolutePath": "Copy absolute path", - "pathCopied": "Path copied", - "copyPathFailed": "Failed to copy path", - "openFailed": "Failed to open local file" - }, - "messageList": { - "attachedResources": "Attached resources", - "loading": "Loading...", - "loadEarlier": "Load earlier messages", - "loadingEarlier": "Loading earlier messages…", - "error": "Error: {message}", - "errorTitle": "Session load failed", - "errorActionReload": "Reload", - "errorActionNewSession": "New conversation", - "emptyConversation": "No messages in this conversation.", - "systemMessage": "System message", - "copyMessage": "Copy", - "copied": "Copied", - "downloadImage": "Download image", - "downloadFailed": "Download failed: {message}", - "imageGeneration": "Image generation", - "imageGenerationPending": "Generating image…", - "imageGenerationFailed": "Image generation failed", - "model": "Model", - "tokenStats": "Token usage", - "tokenInput": "Input", - "tokenOutput": "Output", - "tokenCacheRead": "Cache read", - "tokenCacheWrite": "Cache write", - "duration": "Duration", - "completedAt": "Completed at", - "jumpToPreviousUserMessage": "Jump to user message", - "showMore": "Show more", - "showLess": "Show less" - }, - "liveTurnStats": { - "thinking": "Thinking...", - "streaming": "Streaming", - "elapsedHours": "{value}h", - "elapsedMinutes": "{value}m", - "elapsedSeconds": "{value}s", - "outputSpeedAria": "Estimated output speed", - "outputSpeedTooltip": "Estimated output speed (text + thinking)" - }, - "jsonTree": { - "viewRaw": "Show raw JSON", - "viewTree": "Show tree", - "fields": "{count, plural, one {# field} other {# fields}}", - "items": "{count, plural, one {# item} other {# items}}" - }, - "tool": { - "parameters": "Parameters", - "error": "Error", - "result": "Result", - "status": { - "approvalRequested": "Awaiting Approval", - "approvalResponded": "Responded", - "inputAvailable": "Running", - "inputStreaming": "Pending", - "outputAvailable": "Completed", - "outputDenied": "Denied", - "outputError": "Error" - } - }, - "toolCallBlock": { - "tool": "Tool", - "error": "Error", - "result": "Result" - }, - "delegation": { - "subAgentRunning": "Sub-agent running…", - "noDetail": "No detail available yet.", - "unknownAgent": "Sub-agent", - "openDetail": "Open conversation", - "detailTitle": "Sub-agent conversation", - "detailDescription": "Read-only view of the delegated sub-agent's conversation.", - "waitForResult": "Waiting for task {task} result", - "waitForResultNoTask": "Waiting for task result", - "cancelTask": "Canceling task {task}", - "cancelTaskNoTask": "Canceling task", - "resultPageOf": "{current} / {total}", - "prevResult": "Previous result", - "nextResult": "Next result", - "noResultText": "No result captured for this check.", - "status": { - "starting": "starting", - "running": "running", - "checked": "checked", - "waiting": "awaiting approval", - "ok": "done", - "err": { - "default": "failed", - "delegation_disabled": "disabled", - "depth_limit": "depth limit", - "invalid_agent_type": "bad agent", - "spawn_failed": "spawn failed", - "send_failed": "send failed", - "timeout": "timeout", - "canceled": "canceled", - "child_refusal": "subagent refused", - "child_max_tokens": "subagent token limit", - "child_max_turn_requests": "subagent request limit", - "child_empty": "subagent no output", - "child_unknown": "subagent unknown error", - "unknown": "unknown task" - } - } - }, - "contentParts": { - "showingTailOutput": "Showing tail output while streaming for performance.", - "result": "Result", - "unknown": "unknown", - "inputTruncated": "Input was truncated — diff may be incomplete.", - "replaceAll": "REPLACE ALL", - "filesCount": "Files: {count}", - "update": "update", - "moreFiles": "+{count} more files", - "timeoutMs": "Timeout: {timeout}ms", - "backgroundTrue": "Background: true", - "scriptToolCalls": "{count, plural, one {# tool call} other {# tool calls}}", - "offset": "Offset: {offset}", - "limit": "Limit: {limit}", - "pages": "Pages: {pages}", - "mode": "Mode: {mode}", - "cell": "Cell: {cell}", - "shellSession": "Session {id}", - "pathLabel": "Path:", - "globLabel": "Glob:", - "typeLabel": "Type:", - "outputLabel": "Output:", - "caseInsensitive": "Case insensitive", - "multiline": "Multiline", - "promptLabel": "Prompt", - "subjectLabel": "Subject", - "taskLabel": "Task", - "nameLabel": "Name:", - "agentPromptLabel": "Prompt", - "agentModelLabel": "Model", - "agentRunning": "Running...", - "agentLiveTranscript": "Live activity", - "agentProgressTools": "{count} tool calls", - "agentProgressTurns": "{count} turns", - "agentProgressContext": "context {pct}%", - "agentSessionAction": "View sub-agent session", - "agentSessionTitle": "Sub-agent session", - "agentSessionLoading": "Loading the sub-agent's transcript…", - "agentSessionEmpty": "The sub-agent hasn't written anything yet.", - "agentFallbackTitle": "Sub-agent starting…", - "agentCodexLaunchOnly": "Launched. Codex reports no further progress for this sub-agent — its result arrives as a message in this conversation.", - "agentStatsBash": "Commands", - "agentStatsRead": "Files read", - "agentStatsSearch": "Searches", - "agentStatsEdit": "Edits", - "agentStatsOther": "Other", - "goal": { - "title": "Goal:", - "titleWithStatus": "Goal {status}", - "objective": "Objective", - "statusLabel": "Status", - "tokensUsed": "Tokens used", - "budget": "Budget", - "remaining": "Remaining", - "elapsed": "Elapsed", - "tokens": "tokens", - "pause": "Pause", - "clear": "Clear", - "status": { - "active": "active", - "paused": "paused", - "blocked": "blocked", - "usageLimited": "usage limited", - "budgetLimited": "budget limited", - "complete": "complete", - "limited": "limit reached" - } - }, - "field": { - "file": "File", - "notebook": "Notebook", - "command": "Command", - "old": "Old", - "new": "New", - "pattern": "Pattern", - "path": "Path", - "query": "Query", - "url": "URL", - "description": "Description", - "content": "Content", - "source": "Source", - "prompt": "Prompt", - "subject": "Subject", - "taskId": "Task ID", - "status": "Status", - "skill": "Skill", - "args": "Args", - "offset": "Offset", - "limit": "Limit", - "glob": "Glob", - "type": "Type", - "output": "Output", - "replaceAll": "Replace All", - "language": "Language", - "timeout": "Timeout", - "background": "Background", - "agentType": "Agent Type", - "library": "Library", - "libraryId": "Library ID" - }, - "title": { - "edit": "Edit", - "command": "Command", - "script": "Script", - "waitCommand": "Wait {command}", - "waitCell": "Wait cell {id}", - "terminateCommand": "Terminate {command}", - "terminateCell": "Terminate cell {id}", - "stdinChars": "Stdin {chars}", - "todoWrite": "TodoWrite", - "read": "Read", - "write": "Write", - "notebookEdit": "NotebookEdit", - "editFiles": "Edit ({count} files)", - "editWithTarget": "Edit {target}", - "readWithTarget": "Read {target}", - "writeWithTarget": "Write {target}", - "notebookEditWithTarget": "NotebookEdit {target}", - "globWithPattern": "Glob {pattern}", - "listFilesWithPath": "List files {path}", - "grepWithPattern": "Grep {pattern}", - "taskCreateWithSubject": "TaskCreate: {subject}", - "taskUpdateWithStatus": "TaskUpdate #{id} -> {status}", - "taskUpdate": "TaskUpdate #{id}", - "webFetchWithUrl": "WebFetch {url}", - "webSearchWithQuery": "WebSearch: {query}", - "todosProgress": "Todos ({done}/{total})", - "skillWithName": "Skill: {name}", - "genericWithContext": "{tool}: {context}" - }, - "search": { - "noMatches": "No matches", - "matchSummary": "{matches, plural, one {# match} other {# matches}} in {files, plural, one {# file} other {# files}}", - "fileSummary": "{files, plural, one {# file} other {# files}}", - "moreResults": "{count, plural, one {# more result not shown} other {# more results not shown}}" - }, - "toolGroup": { - "search": "{count, plural, one {Explored # search} other {Explored # searches}}", - "command": "{count, plural, one {Ran # command} other {Ran # commands}}", - "read": "{count, plural, one {Read files # time} other {Read files # times}}", - "memory": "{count, plural, one {Recalled # memory} other {Recalled # memories}}", - "edit": "{count, plural, one {Edited files # time} other {Edited files # times}}", - "fetch": "{count, plural, one {Fetched # resource} other {Fetched # resources}}", - "think": "{count, plural, one {Thought # time} other {Thought # times}}", - "todo": "{count, plural, one {Updated # todo} other {Updated # todos}}", - "task": "{count, plural, one {Ran # task} other {Ran # tasks}}", - "other": "{count, plural, one {Used # tool} other {Used # tools}}", - "errorSuffix": "{count, plural, one {# failed} other {# failed}}", - "joiner": " · " - }, - "planMode": { - "entered": "Entered plan mode", - "planLabel": "Plan", - "reviewApproved": "Plan approved — implementing", - "reviewKept": "Kept in plan mode", - "reviewPending": "Awaiting plan decision", - "submitted": "Plan submitted", - "switched": "Switched mode" - }, - "backgroundTask": { - "title": "Background task", - "titleWithId": "Background task · {id}", - "running": "Running", - "completed": "Completed", - "failed": "Failed", - "stopped": "Stopped", - "exitCode": "exit {code}", - "polledTimes": "Polled {count} times", - "runningInBackground": "Background", - "launchNote": "Running in background · {id}" - }, - "codexScript": { - "outputMissing": "Codex truncated the script output and dropped this command's separator, so none of the output could be attributed to it.", - "sharedWith": "Also contains the output of {commands} — codex truncated their separators away.", - "truncated": "truncated" - } - }, - "messageNav": { - "title": "Message navigation", - "collapse": "Collapse message navigation", - "collapsedSummary": "Messages {count}", - "fileCount": "{count, plural, one {# file} other {# files}}", - "remove": "Remove", - "noDiffDataAvailable": "No diff data available for {filePath}" - }, - "replyArtifacts": { - "title": "Files changed", - "fileCount": "{count, plural, one {# file} other {# files}}", - "newFilesTitle": "New files", - "revealInFolder": "Show in file manager", - "openFile": "Open {filePath}", - "openInEditor": "Open in editor", - "remove": "Remove", - "noDiffDataAvailable": "No diff data available for {filePath}" - }, - "askQuestion": { - "title": "The agent needs your input", - "subtitle": "Answer below, then submit. You can skip anytime.", - "recommended": "Recommended", - "other": "Other", - "otherPlaceholder": "Type your answer…", - "singleSelect": "Single", - "multiSelect": "Multiple", - "skip": "Skip", - "next": "Next", - "submit": "Submit", - "submitError": "Couldn't submit. Please try again." - }, - "planApproval": { - "title": "The agent has a plan — review it", - "emptyPlan": "The agent didn't write a plan. Approve to start building, or request changes.", - "approve": "Approve & build", - "requestChanges": "Request changes", - "abandon": "Abandon", - "feedbackPlaceholder": "What should change?", - "sendChanges": "Send", - "cancel": "Cancel", - "submitError": "Couldn't submit. Please try again." - }, - "feedbackCheckResult": { - "count": "{count, plural, =1 {1 feedback note} other {# feedback notes}}", - "expand": "Show all feedback", - "collapse": "Collapse", - "errorTitle": "Feedback check failed" - }, - "askQuestionResult": { - "title": "Question", - "answeredLabel": "Q&A:", - "awaiting": "Waiting for your answer…", - "declined": "You dismissed this — the agent used its own judgment.", - "noSelection": "No selection" - }, - "configStale": { - "agentConfigTitle": "Agent settings updated", - "modelProviderTitle": "Model provider updated", - "description": "This session is still using its previous configuration. Reconnect to apply — your conversation history is kept.", - "reconnect": "Reconnect to apply", - "reconnecting": "Reconnecting…", - "reconnectDisabledDuringTurn": "Available once the current turn finishes", - "dismiss": "Dismiss", - "reconnectFailed": "Failed to reconnect session", - "applied": "New configuration applied" - }, - "piProjectTrust": { - "title": "This project ships pi resources", - "description": "pi is not loading the repository's own .pi files. Review them to decide.", - "descriptionExecutable": "The repository ships pi extensions, which run code at startup. pi is not loading them. Review before you decide.", - "review": "Review…", - "dismiss": "Dismiss", - "dialogTitle": "Trust this project's pi resources?", - "dialogDescription": "pi only loads a repository's own .pi files once you trust the folder. Trust it only if you trust this repository's contents.", - "executionWarning": "Extensions are code. Trusting this folder lets the repository run them at pi startup with your permissions, before you send any message.", - "scopeNote": "The decision is saved in pi's trust.json for this folder, applies to every folder inside it, and is also used when you run pi yourself in a terminal. You can change it later in Settings → Agents → Pi.", - "trust": "Trust project", - "decline": "Keep unloaded", - "disabledDuringTurn": "Available once the current turn finishes", - "trustedToast": "Project trusted — reconnected so pi loads its resources", - "declinedToast": "Project resources stay unloaded", - "saveFailed": "Failed to save the project trust decision", - "grantTitle": "This project is already trusted", - "grantDescription": "pi loads this repository's own .pi files. Review what that allows.", - "grantInheritedDescription": "A parent folder is trusted, so pi loads this repository's own .pi files. Review what that allows.", - "grantDialogTitle": "This project's pi resources are trusted", - "grantDialogDescription": "pi is allowed to load this repository's own .pi files. Earlier codeg versions granted this automatically when you opened a folder, so you may not have been asked.", - "grantExecutionWarning": "Extensions are code. The repository runs them at pi startup with your permissions, before you send any message.", - "inheritedFrom": "Trusted via", - "revoke": "Revoke trust", - "keepTrusted": "Keep trusted", - "revokedToast": "Trust revoked — reconnected so pi stops loading the project's resources", - "trustedNoReconnect": "Project trusted — it applies the next time pi starts", - "revokedNoReconnect": "Trust revoked — it applies the next time pi starts" - }, - "collabAgent": { - "title": "Sub-agent", - "errorTitle": "Sub-agent task failed", - "statesLabel": "Sub-agents", - "statusRunning": "Running", - "statusCompleted": "Completed", - "statusFailed": "Failed", - "statusPending": "Starting", - "statusInterrupted": "Interrupted", - "statusClosed": "Closed", - "statusNotFound": "Not found", - "opSpawn": "Starting sub-agent", - "opWait": "Fetching sub-agent result", - "opClose": "Closing sub-agent", - "opResume": "Resuming sub-agent" - }, - "contextCompaction": { - "compacting": "Compacting context…", - "compacted": "Context compacted", - "compactedTokens": "Context compacted · {before} → {after} tokens", - "failed": "Context compaction failed" - }, - "sessionFailure": { - "category": { - "connection": "Connection issue", - "access": "Access issue", - "limit": "Limit reached", - "request": "Request rejected", - "service": "Service issue", - "unknown": "Session issue" - }, - "action": { - "retry": "Retry", - "login": "Sign in", - "newSession": "New session" - }, - "recovered": "Recovered", - "retryUnavailable": "No previous message to resend.", - "toggleDetails": "Toggle details" - }, - "backgroundTasks": { - "running": "{count, plural, one {# background task running} other {# background tasks running}}", - "settling": "Syncing background results…", - "settledFallback": "Background task finished ({status})", - "cardRunning": "Running in background", - "cardLaunchedPending": "Launched in background", - "cardCompleted": "Background task completed", - "cardFinishedWithStatus": "Background task finished ({status})", - "cardResultPending": "Result not returned yet" - }, - "proposedPlan": { - "title": "Proposed plan", - "planning": "Planning…" - } - }, - "diffPreview": { - "mode": { - "added": "Added", - "deleted": "Deleted", - "renamed": "Renamed", - "modified": "Modified" - }, - "hunkLabel": "Hunk {index}", - "loadingHunk": "Loading hunk...", - "noDiffData": "No diff data", - "showRemainingLines": "Show {count} more lines" - }, - "conversationContextBar": { - "folderTitle": "Working folder", - "branchTitle": "Working branch", - "searchFolder": "Search folder...", - "searchBranch": "Search branch...", - "noFolders": "No folders", - "noBranches": "No branches", - "noBranch": "(no branch)", - "chatModeLabel": "Chat mode", - "commit": "Commit", - "push": "Push", - "merge": "Merge", - "toasts": { - "folderChanged": "Switched to {name}", - "openFolderFailed": "Failed to open folder", - "switchedToChatMode": "Switched to chat mode", - "openStashFailed": "Failed to open stash window", - "openMergeFailed": "Failed to open merge window" - } - }, - "cloneDialog": { - "title": "Clone Repository", - "repositoryUrl": "Repository URL", - "repositoryUrlPlaceholder": "https://github.com/user/repo.git", - "directory": "Directory", - "directoryPlaceholder": "Select target directory...", - "browseDirectory": "Browse directory", - "cancel": "Cancel", - "clone": "Clone", - "clonePath": "Clone path: {path}" - }, - "toasts": { - "cloneFailed": "Failed to clone repository" - } - }, - "ProjectBoot": { - "title": "Project Boot", - "tabs": { - "shadcn": "shadcn", - "hyperframes": "HyperFrames" - }, - "hyperframes": { - "title": "HyperFrames Video Project", - "subtitle": "Scaffold an HTML-to-video project. Your workspace agent can then write and render it.", - "resolution": "Resolution", - "skillsTitle": "Agent Skills", - "skillsDesc": "Globally install the HyperFrames skills (symlinked) for the selected agents so they can author and render video.", - "recheck": "Re-check", - "installedBadge": "Installed", - "skillsInstall": "Install / update skills", - "skillsInstalling": "Installing skills…", - "skillsInstalled": "HyperFrames skills installed", - "skillsInstallFailed": "Couldn't install HyperFrames skills" - }, - "config": { - "base": "Base", - "style": "Style", - "baseColor": "Base Color", - "theme": "Theme", - "chartColor": "Chart Color", - "iconLibrary": "Icon Library", - "font": "Font", - "fontHeading": "Heading Font", - "menuAccent": "Menu Accent", - "menuColor": "Menu Color", - "radius": "Radius", - "template": "Template", - "createProject": "Create Project", - "sectionStyle": "Style", - "sectionColors": "Colors", - "sectionTypography": "Typography", - "sectionInterface": "Interface" - }, - "preview": { - "loading": "Loading preview..." - }, - "createDialog": { - "title": "Create Project", - "projectName": "Project Name", - "projectNamePlaceholder": "my-app", - "frameworkTemplate": "Framework Template", - "packageManager": "Package Manager", - "saveDirectory": "Save Directory", - "saveDirectoryPlaceholder": "Select directory...", - "browseDirectory": "Browse", - "projectPath": "Project will be created at: {path}", - "advancedOptions": "Advanced Options", - "base": "Base Library", - "enableRtl": "Enable RTL Support", - "enableRtlDescription": "Enable layout support for right-to-left languages (e.g. Arabic, Hebrew)", - "pmChecking": "Checking...", - "pmNotInstalled": "Not installed", - "cancel": "Cancel", - "create": "Create", - "creating": "Creating project..." - }, - "toasts": { - "createFailed": "Failed to create project", - "createSuccess": "Project created successfully", - "openWorkspaceFailed": "Project created, but couldn't open it in the workspace" - }, - "errors": { - "directoryExists": "Target directory already exists", - "commandFailed": "Project creation command failed." - } - }, - "WebServiceSettings": { - "addressSwitchHint": "Switching only changes the address shown and opened here — the service listens on all interfaces and stays reachable at every address.", - "sectionTitle": "Web Service", - "sectionDescription": "Enable to access Codeg remotely via browser", - "port": "Port", - "status": "Status", - "autoStart": "Auto-start", - "autoStartHint": "Start the Web service when Codeg launches", - "running": "Running", - "stopped": "Stopped", - "processing": "Processing...", - "start": "Start", - "stop": "Stop", - "startFailed": "Failed to start", - "stopFailed": "Failed to stop", - "saveConfigFailed": "Failed to save Web service settings", - "open": "Open", - "hide": "Hide", - "show": "Show", - "copy": "Copy", - "qrcode": "QR Code", - "qrcodeTitle": "Scan to Open", - "qrcodeHint": "Scan with your phone to open Codeg in a browser", - "addressLabel": "Access Address", - "tokenLabel": "Access Token", - "tokenHint": "Enter this token when accessing the Web client for the first time", - "tokenPlaceholder": "Leave empty to auto-generate", - "regenerate": "Regenerate", - "stalePortOccupiedTitle": "Port {port} is held by another process", - "stalePortUnknownTitle": "Port {port} status is unclear", - "stalePortHint": "Codeg can't bind here until the port is released. Change the port above, or close the process holding it.", - "errors": { - "alreadyRunning": "Web service is already running", - "invalidAddress": "Invalid host or port format", - "portInUse": "Port {port} is already in use. Close the process using it or choose another port.", - "permissionDenied": "Permission denied. Try a port above 1024 or run with higher privileges.", - "addressUnavailable": "The address is not available on this machine", - "bindFailed": "Failed to bind address" - } - }, - "DirectoryBrowser": { - "title": "Browse Directory", - "pathPlaceholder": "Enter directory path...", - "goHome": "Go to home directory", - "navigateUp": "Go to parent directory", - "select": "Select", - "cancel": "Cancel", - "loading": "Loading...", - "emptyDirectory": "This directory is empty", - "errorLoadingDir": "Failed to load directory", - "permissionDenied": "Permission denied" - }, - "ServerFileBrowser": { - "title": "Pick server file", - "pathPlaceholder": "Enter directory path...", - "goHome": "Go to home directory", - "navigateUp": "Go to parent directory", - "select": "Select", - "cancel": "Cancel", - "loading": "Loading...", - "emptyDirectory": "This directory is empty", - "errorLoadingDir": "Failed to load directory", - "selectedCount": "{count} selected" - }, - "ChatChannelSettings": { - "loading": "Loading...", - "sectionTitle": "Chat Channels", - "sectionDescription": "Configure IM bots to receive event notifications and query coding activity.", - "addChannel": "Add Channel", - "noChannels": "No chat channels configured yet.", - "channelName": "Name", - "channelNamePlaceholder": "My Telegram Bot", - "channelType": "Channel Type", - "lark": "Lark (Feishu)", - "weixin": "WeChat", - "dailyReport": "Daily Report", - "dailyReportTime": "Report Time", - "nameRequired": "Channel name is required.", - "tokenRequired": "Token is required.", - "chatIdRequired": "Chat ID is required.", - "topicMode": "Topic group mode", - "topicModeHint": "Route Telegram forum topics as separate Codeg sessions. The bot must be in a forum supergroup and be allowed to manage topics.", - "loadFailed": "Failed to load channels.", - "saveFailed": "Failed to save changes.", - "connectSuccess": "Channel connected.", - "connectFailed": "Failed to connect", - "disconnectSuccess": "Channel disconnected.", - "disconnectFailed": "Failed to disconnect.", - "testSuccess": "Connection test passed.", - "testFailed": "Connection test failed", - "deleteSuccess": "Channel deleted.", - "deleteFailed": "Failed to delete channel.", - "deleteConfirmTitle": "Delete Channel", - "deleteConfirmMessage": "This will permanently delete the channel and its message logs. Are you sure?", - "cancel": "Cancel", - "delete": "Delete", - "create": "Create", - "save": "Save", - "channelListTitle": "Configured Channels", - "channelListDescription": "Enabled channels will auto-connect when the service starts.", - "editChannel": "Edit Channel", - "editSuccess": "Channel updated.", - "tokenPlaceholderKeep": "Leave blank to keep current", - "weixinScanTitle": "Scan QR Code", - "weixinScanDescription": "Open WeChat and scan the QR code to connect.", - "weixinQrcodeExpired": "QR code expired.", - "weixinRefreshQrcode": "Refresh", - "weixinWaitingScan": "Waiting for scan...", - "weixinPollError": "Connection unstable, retrying...", - "weixinReconnectNotice": "Due to iLink protocol limitations, after each reconnection you must send a message to the bot before event triggers take effect.", - "connect": "Connect", - "disconnect": "Disconnect", - "test": "Test Connection", - "tabs": { - "channels": "Channels", - "commands": "Commands", - "events": "Events", - "other": "Other" - }, - "commands": { - "title": "Built-in Commands", - "description": "Bot commands available in chat channels. In group chats, @Bot is required to process messages.", - "prefixLabel": "Command Prefix", - "prefixDescription": "1-3 non-alphanumeric characters used to trigger bot commands (default /).", - "prefixSaved": "Command prefix saved.", - "prefixSaveFailed": "Failed to save command prefix.", - "prefixInvalid": "Prefix must be 1-3 non-alphanumeric characters.", - "save": "Save", - "folderDesc": "Select working folder", - "agentDesc": "Select AI agent", - "taskDesc": "Create session and run task", - "sessionsDesc": "List active sessions in folder", - "resumeDesc": "Recent conversations / resume a session", - "cancelDesc": "Cancel current task", - "approveDesc": "Approve agent permission request", - "denyDesc": "Deny agent permission request", - "searchDesc": "Search conversations by keyword", - "todayDesc": "Today's activity summary", - "statusDesc": "Channel connection status", - "helpDesc": "Show help message" - }, - "events": { - "title": "Event Notifications", - "description": "When enabled, triggered events will be pushed to the channel.", - "turnComplete": "Turn Complete", - "turnCompleteDesc": "When an agent turn ends", - "error": "Agent Error", - "errorDesc": "When an agent encounters an error", - "permissionRequest": "Permission Request", - "permissionRequestDesc": "When an agent requests permission to act", - "questionRequest": "Agent Question", - "questionRequestDesc": "When an agent asks you a question", - "userPromptSent": "User Message", - "userPromptSentDesc": "When you send a message — the message text is included in the notification", - "saved": "Event filter updated.", - "saveFailed": "Failed to save event filter.", - "loadFailed": "Failed to load settings.", - "retry": "Retry", - "webhooksTitle": "Webhooks", - "webhooksDescription": "POST a JSON payload to one or more URLs when an enabled event fires. The event filter above also applies to webhooks.", - "webhookUrlPlaceholder": "https://example.com/webhook", - "addWebhook": "Add Webhook", - "removeWebhook": "Remove webhook", - "webhookSave": "Save", - "webhooksSaved": "Webhooks saved.", - "webhooksSaveFailed": "Failed to save webhooks.", - "webhookInvalidUrl": "Enter valid http(s) URLs.", - "docsTitle": "Request Format", - "docsMethod": "Method", - "docsContentType": "Content-Type", - "docsNote": "Each enabled event is delivered to every URL. Webhooks are not debounced; the event filter above still applies.", - "editWebhook": "Edit Webhook", - "enableWebhook": "Enable webhook", - "webhookDuplicate": "This URL is already configured.", - "cancel": "Cancel", - "webhooksEmpty": "No webhooks configured yet.", - "deleteWebhookTitle": "Delete Webhook", - "deleteWebhookMessage": "Remove this webhook? Events will no longer be delivered to this URL.", - "delete": "Delete" - }, - "language": { - "title": "Message Language", - "description": "Language used for event notifications, command responses, and daily reports sent to chat channels.", - "saved": "Message language saved.", - "saveFailed": "Failed to save message language.", - "en": "English", - "zh-cn": "Simplified Chinese", - "zh-tw": "Traditional Chinese", - "ja": "Japanese", - "ko": "Korean", - "es": "Spanish", - "de": "German", - "fr": "French", - "pt": "Portuguese", - "ar": "Arabic" - } - }, - "ModelProviderSettings": { - "sectionTitle": "Model Providers", - "sectionDescription": "Manage API provider credentials for agents.", - "filterAll": "All", - "providerListTitle": "Configured Providers", - "addProvider": "Add Provider", - "editProvider": "Edit Provider", - "noProviders": "No model providers configured yet.", - "providerName": "Name", - "providerNamePlaceholder": "e.g. OpenAI, Anthropic", - "apiUrl": "API URL", - "apiUrlPlaceholder": "https://api.openai.com/v1", - "apiKey": "API Key", - "apiKeyPlaceholder": "sk-...", - "apiKeyKeepCurrent": "Leave blank to keep current", - "agentTypes": "Agent Types", - "agentTypesRequired": "At least one agent type is required.", - "agentType": "Agent Type", - "agentTypeRequired": "Agent type is required.", - "agentTypeImmutableHint": "Agent type cannot be changed after creation.", - "model": "Model", - "modelPlaceholderCodex": "gpt-5.6-sol / gpt-5.5", - "modelPlaceholderGemini": "gemini-3-pro-preview", - "claudeMainModel": "Main Model", - "claudeReasoningModel": "Reasoning Model (thinking)", - "claudeHaikuDefaultModel": "Default Haiku Model", - "claudeSonnetDefaultModel": "Default Sonnet Model", - "claudeOpusDefaultModel": "Default Opus Model", - "claudeCustomModelOption": "Custom Model ID", - "claudeCustomModelOptionName": "Custom Model Name", - "claudeCustomModelOptionDescription": "Custom Model Description", - "claudeCustomModelOptionHint": "Adds a single custom entry to Claude's model picker (e.g. a model behind a custom gateway/proxy). Name and description are optional display overrides.", - "nameRequired": "Provider name is required.", - "apiUrlRequired": "API URL is required.", - "apiKeyRequired": "API Key is required.", - "loadFailed": "Failed to load providers.", - "saveFailed": "Failed to save changes.", - "createSuccess": "Provider created.", - "editSuccess": "Provider updated.", - "deleteSuccess": "Provider deleted.", - "deleteConfirmTitle": "Delete Provider", - "deleteConfirmMessage": "This will permanently delete the provider \"{name}\". Are you sure?", - "deleteBlockedByAgent": "{agents} is currently using this provider. Please unlink before deleting.", - "cancel": "Cancel", - "delete": "Delete", - "create": "Create", - "save": "Save", - "affectedRunningSessions": "{count, plural, one {# running session needs to reconnect to apply the change} other {# running sessions need to reconnect to apply the change}}" - }, - "SkillMatrix": { - "loading": "Loading…", - "searchPlaceholder": "Search by name, id, or description", - "empty": "Nothing to show.", - "emptySearch": "No matches for the current search.", - "skillColumn": "Skill", - "selectAll": "Select all visible", - "selectSkill": "Select {name}", - "everything": { - "label": "Bulk", - "enable": "Enable everything (visible)", - "disable": "Disable everything (visible)" - }, - "columnMenu": { - "enableAll": "Enable all skills", - "disableAll": "Disable all skills" - }, - "rowMenu": { - "label": "Batch actions for {name}", - "enableAll": "Enable for all agents", - "disableAll": "Disable for all agents" - }, - "bulk": { - "selected": "{count} selected", - "targetAll": "All agents", - "targetSome": "{count} agents", - "enable": "Enable", - "disable": "Disable", - "clear": "Clear" - }, - "confirm": { - "disableTitle": "Disable these links?", - "disableBody": "This removes {count} codeg-managed skill link(s). Skills occupying a custom directory are left untouched. You can re-enable them anytime.", - "cancel": "Cancel", - "confirm": "Disable" - }, - "toasts": { - "loadFailed": "Failed to load skill statuses", - "applyFailed": "Failed to apply changes", - "enabled": "Enabled {count} link(s)", - "disabled": "Disabled {count} link(s)", - "enabledPartial": "Enabled {ok}, {failed} failed", - "disabledPartial": "Disabled {ok}, {failed} failed" - }, - "detail": { - "enableForAgents": "Enable for agents", - "preview": "SKILL.md preview", - "loadingContent": "Loading content…" - }, - "copyModeHint": "Copied (not linked) — re-enable after updates for the latest version" - }, - "ExpertsSettings": { - "title": "Expert Skills", - "description": "Enable curated, battle-tested skill workflows for your AI coding agents. Each expert is a standalone skill from the superpowers project — codeg manages the central copy and links it into the agents you choose.", - "loading": "Loading experts…", - "loadingContent": "Loading content…", - "emptyExperts": "No experts available. Check the application logs.", - "emptySelection": "Select an expert to see its content and manage activation.", - "emptySearch": "No experts match the current search.", - "searchPlaceholder": "Search experts by name, id, or description", - "enableForAgents": "Enable for agents", - "noAgents": "No ACP agents detected.", - "copyModeWarning": "Copied (not linked). Re-enable after codeg updates to get the latest version.", - "previewTitle": "SKILL.md preview", - "categories": { - "discovery": "Discovery & Design", - "planning": "Planning", - "execution": "Execution", - "quality": "Quality & Testing", - "debugging": "Debugging", - "review": "Review & Integration", - "meta": "Meta" - }, - "states": { - "not_linked": "Not enabled", - "linked_to_codeg": "Enabled", - "linked_elsewhere": "Blocked — another link exists", - "blocked_by_real_directory": "Blocked — a custom skill occupies this name", - "broken": "Broken link" - }, - "badges": { - "userModified": "User modified" - }, - "actions": { - "openCentralDir": "Open central folder", - "refresh": "Refresh" - }, - "toasts": { - "loadFailed": "Failed to load expert details", - "enabled": "Expert enabled for this agent", - "disabled": "Expert disabled for this agent", - "enableFailed": "Failed to enable expert", - "disableFailed": "Failed to disable expert", - "openFolderFailed": "Failed to open folder" - } - }, - "ScienceSettings": { - "title": "Scientific Research Skills", - "description": "Enable curated scientific-research skills for your AI coding agents — hypothesis generation, experimental design, statistics, visualization, critical appraisal, and literature search. codeg manages a central copy and links each skill into the agents you choose.", - "loading": "Loading science skills…", - "emptySkills": "No science skills available. Check the application logs.", - "searchPlaceholder": "Search science skills by name, id, or description", - "categories": { - "ideation": "Ideation", - "design": "Study Design", - "analysis": "Analysis", - "visualization": "Visualization", - "evaluation": "Evaluation", - "literature": "Literature" - }, - "states": { - "not_linked": "Not enabled", - "linked_to_codeg": "Enabled", - "linked_elsewhere": "Blocked — another link exists", - "blocked_by_real_directory": "Blocked — a custom skill occupies this name", - "broken": "Broken link" - }, - "badges": { - "userModified": "User modified", - "needsKey": "Needs API key", - "needsSetup": "May need setup" - }, - "actions": { - "openCentralDir": "Open central folder", - "refresh": "Refresh" - }, - "toasts": { - "openFolderFailed": "Failed to open folder" - } - }, - "OfficeToolsSettings": { - "title": "Office Tools", - "description": "Manage OfficeCLI skills for creating Excel, Word, and PowerPoint files. Install OfficeCLI, sync skills, and enable them per agent.", - "loadingContent": "Loading content…", - "emptySkills": "No skills available. Install OfficeCLI and sync skills to get started.", - "emptySelection": "Select a skill to see its content and manage activation.", - "emptySearch": "No skills match the current search.", - "searchPlaceholder": "Search skills by name, id, or description", - "enableForAgents": "Enable for agents", - "noAgents": "No ACP agents detected.", - "installFirst": "Install OfficeCLI first to enable skills for agents.", - "syncFirst": "Sync skills first to load this skill's content.", - "noContent": "No content available.", - "copyModeWarning": "Copied (not linked). Re-sync to get the latest version.", - "previewTitle": "SKILL.md preview", - "detection": { - "installed": "Installed", - "notInstalled": "Not installed", - "notRunnable": "Installed but not runnable", - "installHint": "Install OfficeCLI to enable office document generation skills for your AI agents.", - "install": "Install", - "uninstall": "Uninstall", - "syncSkills": "Sync Skills" - }, - "categories": { - "general": "General", - "presentations": "Presentations", - "documents": "Documents", - "spreadsheets": "Spreadsheets" - }, - "states": { - "not_linked": "Not enabled", - "linked_to_codeg": "Enabled", - "linked_elsewhere": "Blocked — another link exists", - "blocked_by_real_directory": "Blocked — a custom skill occupies this name", - "broken": "Broken link" - }, - "badges": { - "notSynced": "Not synced" - }, - "actions": { - "refresh": "Refresh" - }, - "toasts": { - "loadFailed": "Failed to load skill details", - "enabled": "Skill enabled for this agent", - "disabled": "Skill disabled for this agent", - "enableFailed": "Failed to enable skill", - "disableFailed": "Failed to disable skill", - "installSuccess": "OfficeCLI installed successfully", - "installFailed": "Failed to install OfficeCLI", - "uninstallSuccess": "OfficeCLI uninstalled", - "uninstallFailed": "Failed to uninstall OfficeCLI", - "syncSuccess": "{synced} skills synced successfully", - "syncPartial": "{synced} skills synced, {errors} failed", - "syncFailed": "Failed to sync skills" - }, - "autoPreviewLabel": "Auto-open preview", - "autoPreviewHint": "When an agent creates or edits a Word, Excel, or PowerPoint file, open its live preview automatically." - }, - "SkillPacksSettings": { - "title": "Skill Packs", - "description": "Curated skill bundles that codeg manages centrally and links into your AI agents — coding experts, scientific research, and office document tools. Enable them per agent below.", - "tabs": { - "experts": "Experts", - "science": "Science", - "office": "Office Tools", - "custom": "Custom" - }, - "actions": { - "openCentralDir": "Open central folder", - "refresh": "Refresh" - }, - "toasts": { - "openFolderFailed": "Failed to open folder" - } - }, - "QuickMessagesSettings": { - "title": "Quick Messages", - "description": "Manage reusable message snippets. Drag to reorder.", - "loading": "Loading quick messages…", - "emptyList": "No quick messages yet. Click \"New\" to create one.", - "emptySelection": "Select a quick message to edit.", - "searchPlaceholder": "Search by title or content", - "untitled": "Untitled", - "actions": { - "new": "New", - "save": "Save", - "delete": "Delete", - "dragSort": "Drag to reorder", - "dragSortMessage": "Drag to reorder quick message: {name}" - }, - "fields": { - "title": "Title", - "titlePlaceholder": "Give this message a short title", - "content": "Content", - "contentPlaceholder": "Write the message content here" - }, - "confirmDelete": { - "title": "Delete quick message?", - "message": "This will permanently delete \"{name}\". Are you sure?", - "cancel": "Cancel", - "confirm": "Delete" - }, - "toasts": { - "loadFailed": "Failed to load quick messages", - "createFailed": "Failed to create quick message", - "saveFailed": "Failed to save quick message", - "deleteFailed": "Failed to delete quick message", - "saveOrderFailed": "Failed to save order", - "created": "Quick message created", - "saved": "Quick message saved", - "deleted": "Quick message deleted" - } - }, - "Pet": { - "badge": { - "running": "{count} running", - "waiting": "{count} awaiting approval", - "error": "{count} errored" - }, - "panel": { - "title": "Active sessions", - "empty": "No active sessions", - "emptyHint": "Running agents and ones that need you appear here.", - "statusRunning": "Running", - "statusWaiting": "Waiting", - "statusError": "Error", - "subAgentOf": "Sub-agent of" - }, - "menu": { - "scale": "Scale", - "openManager": "Manage pets", - "close": "Close" - }, - "loadError": "Failed to load pet", - "missingPetIdParam": "No pet selected", - "summonButton": "Pet", - "manager": { - "title": "Pets", - "description": "Floating desktop companions powered by Codex-compatible sprite sheets.", - "addPet": "Add pet", - "importFromCodex": "Import from Codex", - "noPets": "No pets yet. Add one or import from Codex.", - "setActive": "Set active", - "active": "Active", - "edit": "Edit", - "delete": "Delete", - "deleteConfirm": "Delete pet \"{name}\"? It will be removed from disk.", - "summon": "Summon pet window", - "openCodexHelp": "Codex pets must be installed under ~/.codex/pets/. None found.", - "specRequirement": "Spritesheet must be 1536px wide with a height in 208px rows (e.g. 1872 or 2288), PNG or WebP with transparency.", - "form": { - "id": "Pet ID", - "idHelp": "Lowercase letters, digits, '-' and '_'. Max 64 chars.", - "displayName": "Display name", - "description": "Description (optional)", - "spritesheet": "Spritesheet", - "chooseFile": "Choose file", - "replaceFile": "Replace spritesheet", - "saveCreate": "Add pet", - "saveUpdate": "Save changes", - "cancel": "Cancel" - }, - "errors": { - "missingId": "Pet id is required", - "missingName": "Display name is required", - "missingSpritesheet": "Spritesheet is required", - "addFailed": "Failed to add pet", - "updateFailed": "Failed to update pet", - "deleteFailed": "Failed to delete pet", - "loadFailed": "Failed to load pets", - "setActiveFailed": "Failed to set active pet", - "summonFailed": "Failed to summon pet window" - } - }, - "import": { - "title": "Import from Codex", - "subtitle": "These pets are available under ~/.codex/pets/.", - "selectAll": "Select all", - "alreadyImported": "Already imported", - "renameOnConflict": "Rename conflicts with -imported suffix", - "import": "Import selected", - "noneFound": "No importable Codex pets found.", - "imported": "Imported successfully", - "failed": "Import failed", - "close": "Close" - }, - "marketplace": { - "openMarketplace": "Pet marketplace", - "title": "Pet marketplace", - "search": "Search pets", - "kindFilter": { - "all": "All", - "object": "Object", - "animal": "Animal", - "person": "Person", - "creature": "Creature" - }, - "sortFilter": { - "latest": "Latest", - "popular": "Popular", - "views": "Most viewed" - }, - "refresh": "Refresh", - "install": "Install", - "installing": "Installing", - "reinstall": "Reinstall", - "reinstallConfirm": "Replace local pet \"{name}\"? Existing data will be overwritten.", - "cancel": "Cancel", - "stats": { - "views": "Views", - "downloads": "Downloads", - "likes": "Likes" - }, - "actions": { - "idle": "Idle", - "running_right": "Run right", - "running_left": "Run left", - "waving": "Wave", - "jumping": "Jump", - "failed": "Fail", - "waiting": "Wait", - "running": "Run", - "review": "Review" - }, - "page": "Page {page} of {total}", - "prev": "Previous", - "next": "Next", - "empty": "No pets match this filter.", - "successInstalled": "Installed \"{name}\"", - "errors": { - "loadFailed": "Failed to load marketplace", - "installFailed": "Failed to install pet", - "alreadyInstalled": "Pet already exists locally" - } - } - }, - "RemoteWorkspace": { - "openRemoteWorkspace": "Open remote workspace", - "manage": "Manage remote workspace", - "manageTitle": "Remote Workspace connections", - "empty": "No remote connections", - "searchPlaceholder": "Search remote workspaces", - "orderFailed": "Failed to save remote workspace order", - "dragSort": "Drag to sort", - "dragSortConnection": "Drag to sort {name}", - "newConnection": "New connection", - "loading": "Loading", - "loadingConnection": "Loading remote connection", - "name": "Name", - "baseUrl": "Service URL", - "token": "Access token", - "save": "Save", - "delete": "Delete", - "confirmDelete": { - "title": "Delete remote connection?", - "message": "This will remove \"{name}\" from this device. This action cannot be undone.", - "cancel": "Cancel", - "confirm": "Delete" - }, - "saved": "Remote connection saved.", - "deleted": "Remote connection deleted.", - "loadFailed": "Failed to load remote connections", - "saveFailed": "Failed to save remote connection", - "deleteFailed": "Failed to delete remote connection", - "openFailed": "Failed to open remote workspace", - "connectionLoadFailed": "Failed to load remote connection: {message}", - "connectionExpired": "Remote connection \"{name}\" is expired. Update its token and reload this window." - }, - "BackupSettings": { - "title": "Backup & Restore", - "description": "Export a portable backup of your codeg data, or restore from one.", - "tabs": { - "backup": "Backup", - "restore": "Restore" - }, - "export": { - "includeExternal": "Include conversation content", - "includeExternalHint": "Also archive agent CLI transcripts (Claude, Codex, Gemini, …). Increases size.", - "passphrase": "Passphrase (optional)", - "passphrasePlaceholder": "Leave empty for an unencrypted archive", - "passphraseConfirm": "Confirm passphrase", - "passphraseMismatch": "Passphrases do not match.", - "noPassphraseWarning": "This backup will contain secrets (API keys, tokens) in plaintext. Store it somewhere safe.", - "passphraseLossWarning": "Encrypted with this passphrase. If you lose it, the backup cannot be recovered.", - "button": "Export backup", - "inProgress": "Creating backup…", - "success": "Backup created.", - "started": "Backup download started." - }, - "restore": { - "selectFile": "Select backup file", - "passphrasePrompt": "This backup is encrypted. Enter its passphrase.", - "unlock": "Unlock", - "preview": { - "title": "Backup details", - "encrypted": "Encrypted", - "compatible": "Compatible", - "incompatible": "Incompatible", - "createdAt": "Created: {value}", - "appVersion": "App version: {value}", - "incompatibleHint": "This backup was created by a newer version of codeg and cannot be restored." - }, - "replaceWarning": "Restoring replaces all current codeg data (database and uploads). Your current data is snapshotted first so it can be recovered.", - "keyringNote": "Desktop GitHub/chat tokens live in your OS keychain and are not included; re-enter them after restoring.", - "button": "Restore", - "staging": "Preparing restore…", - "staged": "Restore staged. Restarting…", - "restarting": "Restore staged. Restarting the server…", - "restartTimeout": "The server did not come back in time. Reload the page once it is up.", - "externalSideLocation": "Conversation transcripts were restored to {path}", - "confirmTitle": "Replace all data?", - "confirmBody": "This will replace your current codeg database and uploads with the backup, then restart. Your current data is snapshotted first.", - "cancel": "Cancel", - "confirmAction": "Replace & restart", - "external": { - "title": "Conversation content", - "hint": "This backup includes agent CLI transcripts. Choose where to restore them.", - "modeSkip": "Don't restore", - "modeSide": "Restore to a safe side folder", - "modeOriginal": "Restore to original CLI locations", - "forceOverwrite": "Overwrite existing files", - "forceOverwriteHint": "Replace files that already exist in the agent CLI folders.", - "scanning": "Checking for conflicts…", - "noConflicts": "No existing files would be overwritten.", - "conflictCount": "{count} existing file(s) would be affected.", - "conflictSkipNote": "Existing files are kept (skipped) unless you enable overwrite." - }, - "restartFailed": "Restore staged, but the server couldn't restart. Restart it manually to apply the restore." - }, - "remoteUnsupported": "Backup & restore acts on the data of the machine running codeg. You're connected to a remote workspace — manage its backups from that server directly." - }, - "backup": { - "restore": { - "error": { - "badPassphrase": "Incorrect passphrase or corrupted backup.", - "corrupted": "The backup archive is corrupted.", - "unknownFormat": "This file is not a recognized codeg backup.", - "newerVersion": "This backup was created by codeg {backupVersion}, newer than this version ({appVersion}).", - "alreadyPending": "A restore is already staged. Restart to apply it before staging another." - } - }, - "error": { - "diskSpace": "Not enough disk space to complete the operation.", - "cancelled": "The operation was cancelled." - } - }, - "WebConnection": { - "disconnectedTitle": "Connection lost", - "reconnectingDescription": "Trying to reconnect to the server. This usually recovers on its own within a few seconds.", - "reconnectNow": "Reconnect now", - "sessionExpiredTitle": "Session expired", - "sessionExpiredDescription": "Your session is no longer valid. Please sign in again to continue.", - "goToLogin": "Go to login" - }, - "LiveFeedback": { - "placeholder": "Send a note to {agent} while it works…", - "agentFallback": "the agent", - "ariaLabel": "Live feedback note", - "dialogTitle": "Live feedback", - "dialogDescription": "Send a note to the agent while it works. It reads your note the next time it checks — without interrupting the current step.", - "dialogDescriptionInstant": "Send a note to the agent while it works. It lands in the current turn immediately — the agent sees it right away.", - "channelDowngraded": "Instant insert isn't available in this session — your note was saved for the agent to pick up on its next check.", - "send": "Send", - "cancel": "Cancel", - "pending": "waiting", - "delivered": "received", - "turnEndedUnread": "The agent finished before reading your feedback.", - "sendAsMessage": "Send as message", - "dismiss": "Dismiss", - "turnEndedResent": "The turn ended — sent as a new message instead.", - "turnEnded": "The turn already ended.", - "submitFailed": "Couldn't send your note" - }, - "AgentToolsSettings": { - "title": "In-conversation tools", - "description": "Extra tools codeg gives an agent inside a conversation. Each is injected when the agent starts, so a change applies to agents started afterwards.", - "feedbackLabel": "Live Feedback", - "feedbackHint": "Send notes and corrections to an agent while it's working. When the agent supports instant steering, your note is inserted into the running turn immediately; otherwise the agent gets a tool to check for your feedback — those agents typically only check when you mention it in your prompt, for example add \"check my live feedback regularly\" to your message.", - "questionLabel": "Ask user question", - "questionHint": "Let agents pause and ask you a multiple-choice question that appears above the conversation input box. The agent waits until you answer (or skip).", - "sessionInfoLabel": "Get session info", - "sessionInfoHint": "Let agents look up a session you reference in your message (a session badge) to read its title, agent, status, workspace, token usage, and recent messages.", - "automationsLabel": "Create automations", - "automationsHint": "Save the conversation as an automation that runs on a schedule. Off by default — it goes on to start agents on its own.", - "workTasksLabel": "Create to-do tasks", - "workTasksHint": "Queue a card on the to-do board from the conversation. Off by default — it writes app state.", - "save": "Save", - "saving": "Saving…", - "saved": "Tool settings saved", - "saveFailed": "Failed to save tool settings", - "loadFailed": "Failed to load: {detail}" - }, - "NotificationSoundSettings": { - "title": "Notification sounds", - "description": "Play a short sound when an agent event fires. These are the same events the chat channels push — configured here for this device only.", - "enableHint": "Off by default. Sounds play in the workspace window of this browser or app only.", - "volume": "Volume", - "preview": "Preview", - "previewEvent": "Preview the {event} sound", - "onlyWhenUnfocused": "Only when the window is not focused", - "onlyWhenUnfocusedHint": "Stay silent while you are looking at Codeg.", - "eventsTitle": "Events", - "eventsHint": "Pick a tone per event, or “Silent” to skip it. Repeats of the same event within a couple of seconds play once.", - "toneNone": "Silent", - "toneChime": "Chime", - "toneDing": "Ding", - "toneBlip": "Blip", - "tonePop": "Pop", - "toneAlert": "Alert", - "toneDescend": "Descending" - }, - "LogsSettings": { - "loading": "Loading…", - "sectionTitle": "Runtime Logs", - "sectionDescription": "View and configure application diagnostic logs. Logs are written to local files and kept in memory for live viewing.", - "captureTitle": "Log level", - "captureDescription": "Controls how much detail is captured. Higher levels (Debug, Trace) record more but produce larger logs. Off disables logging.", - "captureLabel": "Capture level", - "levels": { - "off": "Off", - "error": "Error", - "warn": "Warning", - "info": "Info", - "debug": "Debug", - "trace": "Trace" - }, - "viewerTitle": "Recent logs", - "viewerDescription": "Live view of recent log records. Filter by level or search text.", - "searchPlaceholder": "Search message or target…", - "viewLevels": { - "all": "All levels", - "error": "Error+", - "warn": "Warning+", - "info": "Info+", - "debug": "Debug+", - "trace": "Trace+" - }, - "pause": "Pause", - "resume": "Live", - "refresh": "Refresh", - "clear": "Clear", - "openFolder": "Open folder", - "shownCount": "{shown} / {total} shown", - "empty": "No logs to display.", - "levelSaveFailed": "Failed to save log level", - "openFolderFailed": "Failed to open log folder", - "downloadFailed": "Failed to download log file", - "filesTitle": "Log files", - "filesDescription": "Download full log files from disk for history beyond the live buffer.", - "filesEmpty": "No log files yet.", - "download": "Download", - "downloadTruncated": "File is large; downloaded the latest {size}. The full file is in the logs directory.", - "captureEnvLocked": "Log level is controlled by the RUST_LOG / CODEG_LOG environment variable; change it there to take effect.", - "targetsTitle": "Per-module overrides", - "targetsDescription": "Set a different level for specific modules (e.g. codeg_lib::acp) without changing the global level.", - "targetsAdd": "Add", - "targetsRemove": "Remove override", - "toggleDetails": "Toggle details" - }, - "Automations": { - "title": "Automations", - "new": "New automation", - "empty": "No automations yet", - "emptyHint": "Create one to run an agent task on a schedule or on demand.", - "name": "Name", - "namePlaceholder": "e.g. Nightly PR review", - "prompt": "Prompt", - "promptPlaceholder": "What should the agent do?", - "agent": "Agent", - "folder": "Workspace folder", - "folderPlaceholder": "Select a folder", - "isolation": "Isolation", - "isolationWorktree": "New worktree per run", - "isolationShared": "Run in the folder", - "isolationSharedCaveat": "Runs use this folder's working tree directly — they can collide with your uncommitted changes. Enable the worktree option to isolate each run.", - "trigger": "Trigger", - "triggerSchedule": "On a schedule", - "triggerManual": "Manual only", - "cron": "Schedule (cron)", - "cronPlaceholder": "0 9 * * 1-5", - "timezone": "Timezone", - "nextRun": "Next run", - "branch": "Branch", - "branchOptional": "Branch (optional)", - "enabled": "Enabled", - "save": "Save", - "cancel": "Cancel", - "edit": "Edit", - "delete": "Delete", - "runNow": "Run now", - "cancelRun": "Cancel run", - "runHistory": "Run history", - "noRuns": "No runs yet", - "allFolders": "All folders", - "filterAll": "All", - "noMatches": "No matching automations", - "viewConversation": "View conversation", - "lastRun": "Last run", - "never": "Never", - "running": "Running", - "deleteTitle": "Delete automation?", - "deleteDescription": "This removes the automation and its schedule. Run history is kept.", - "statusRunning": "Running", - "statusSucceeded": "Succeeded", - "statusFailed": "Failed", - "statusCancelled": "Cancelled", - "statusSkipped": "Skipped", - "errorName": "Name is required", - "errorPrompt": "Prompt is required", - "errorCron": "A cron expression is required for scheduled automations", - "errorFolder": "Select a workspace folder", - "presetHourly": "Hourly", - "presetDaily": "Daily 9am", - "presetWeekdays": "Weekdays 9am", - "presetCustom": "Custom", - "probing": "Loading options…", - "retry": "Retry", - "configNone": "This agent has no configurable options", - "inherit": "Agent default", - "mode": "Mode", - "config": "Configuration", - "branchPlaceholder": "(default branch)", - "selectHint": "Select an automation to see details", - "refresh": "Refresh", - "onboardTitle": "Automate routine agent tasks", - "onboardHint": "Schedule an agent to review code, update dependencies, or triage issues — on a cadence or on demand.", - "headerSubtitle": "Scheduled and on-demand agent tasks", - "startFromTemplate": "Start from a template", - "blankTitle": "Blank automation", - "blankDesc": "Configure an agent task from scratch.", - "backToTemplates": "Templates", - "sectionSchedule": "Schedule & target", - "sectionTarget": "Target", - "sectionAction": "Action", - "actionLaunchSession": "Launch session", - "actionEnqueueTask": "Enqueue task", - "actionEnqueueTaskHint": "Each fire adds a to-do task titled after this automation to the folder's to-dos; the task engine runs it per the board's settings.", - "sectionPrompt": "Prompt", - "nextIn": "Next in {rel}", - "manual": "Manual", - "schedEveryMinutes": "Every {n} minutes", - "schedHourly": "Hourly", - "schedDaily": "Daily at {time}", - "schedWeekdays": "Weekdays at {time}", - "schedWeekly": "Every {day} at {time}", - "schedMonthly": "Monthly on day {day} at {time}", - "dow0": "Sunday", - "dow1": "Monday", - "dow2": "Tuesday", - "dow3": "Wednesday", - "dow4": "Thursday", - "dow5": "Friday", - "dow6": "Saturday", - "tplCodeReviewTitle": "Code review", - "tplCodeReviewDesc": "Review recent changes for bugs, regressions, and quality issues.", - "tplDependencyUpdatesTitle": "Dependency updates", - "tplDependencyUpdatesDesc": "Find outdated dependencies and propose safe upgrades.", - "tplTestCoverageTitle": "Test coverage", - "tplTestCoverageDesc": "Find untested code paths and add the missing tests.", - "tplTodoSweepTitle": "TODO sweep", - "tplTodoSweepDesc": "Collect TODO and FIXME comments and triage them by priority.", - "tplCiTriageTitle": "CI triage", - "tplCiTriageDesc": "Investigate recent failing checks and propose fixes.", - "tplReleaseNotesTitle": "Release notes", - "tplReleaseNotesDesc": "Summarize changes since the last release into a changelog.", - "tplSecurityAuditTitle": "Security audit", - "tplSecurityAuditDesc": "Scan for vulnerabilities and risky patterns, then report findings.", - "enable": "Enable", - "disable": "Disable", - "moreActions": "More actions", - "statusDisabled": "Disabled", - "cronBuilderTitle": "Schedule builder", - "cronFreqLabel": "Frequency", - "cronFreqMinutes": "Every N minutes", - "cronFreqHourly": "Hourly", - "cronFreqDaily": "Daily", - "cronFreqWeekdays": "Weekdays", - "cronFreqWeekly": "Weekly", - "cronFreqMonthly": "Monthly", - "cronFreqCustom": "Custom", - "cronEveryLabel": "Interval (minutes)", - "cronTimeLabel": "Time", - "cronHourLabel": "Hour", - "cronMinuteLabel": "Minute", - "cronDowLabel": "Day of week", - "cronDomLabel": "Day of month", - "cronApply": "Apply", - "cronPreviewLabel": "Preview", - "cronOpenBuilder": "Open schedule builder", - "branchDefault": "Default branch", - "branchUseCustom": "Use \"{query}\"", - "branchLocal": "Local", - "branchRemote": "Remote", - "branchSearchPlaceholder": "Search branches…", - "branchNone": "No branches" - }, - "Tasks": { - "title": "To-dos", - "new": "New task", - "empty": "No tasks yet", - "emptyHint": "Add a to-do, then run it — the agent works in an isolated worktree and you review and merge the result.", - "emptyColTodo": "No to-dos yet", - "emptyColInProgress": "Nothing in progress", - "emptyColAttention": "Nothing needs you right now", - "emptyColDone": "Nothing done yet", - "allFolders": "All folders", - "showCanceled": "Show canceled", - "showArchived": "Show archived", - "filter": "Filter", - "viewSwitchToBoard": "Switch to board view", - "viewSwitchToList": "Switch to list view", - "statusFilter": "Status", - "statusFilterAll": "All statuses", - "listEmpty": "No tasks match the current filters", - "listColStatus": "Status", - "listColTask": "Task", - "listColLocation": "Location", - "listColChanges": "Changes", - "listColUpdated": "Updated", - "colTodo": "To do", - "colInProgress": "In progress", - "colAttention": "Needs you", - "colDone": "Done", - "statusTodo": "To do", - "statusQueued": "Queued", - "statusPreparing": "Setting up", - "statusRunning": "Running", - "statusAwaitingInput": "Awaiting input", - "statusReview": "To review", - "statusMerging": "Merging", - "statusDone": "Done", - "statusFailed": "Failed", - "statusCanceled": "Canceled", - "statusInterrupted": "Interrupted", - "badgeCleanupFailed": "Cleanup failed", - "badgeWorktreeKept": "Worktree kept", - "badgeWorktreeRemoved": "Worktree removed", - "filesChanged": "{count} files", - "actionStart": "Start", - "actionSchedule": "Schedule", - "actionCancel": "Cancel", - "actionRetry": "Retry", - "actionRequeue": "Requeue", - "actionViewSession": "View session", - "actionEdit": "Edit", - "actionDelete": "Delete", - "actionRetryCleanup": "Retry cleanup", - "actionMerge": "Merge", - "actionUnqueueMerge": "Leave merge queue", - "actionEditQueuedMerge": "Edit queued merge", - "badgeMergeQueued": "Queued to merge", - "badgeMergeQueuedRank": "Queued to merge · #{rank}", - "badgeMergeQueuedHint": "Waiting for the project's current merge to finish; this one starts on its own.", - "actionComplete": "Complete", - "actionAbandon": "Abandon", - "cancelTitle": "Cancel task?", - "cancelDescription": "The task moves to Canceled. Its worktree is kept, and you can requeue it later.", - "cancelReasonLabel": "Reason (optional)", - "cancelReasonPlaceholder": "e.g. wrong approach — I'll rewrite the description", - "cancelKeep": "Never mind", - "cancelSubmit": "Cancel task", - "restartTitleRetry": "Retry task", - "restartTitleRequeue": "Requeue task", - "restartDescription": "Add a note for the agent (optional) — it reaches the prompt of the next run.", - "scheduleTitle": "Schedule task", - "scheduleDescription": "The task stays in To do and starts on its own at the time you pick. The folder's concurrency limit still applies.", - "scheduleDateLabel": "Date", - "schedulePickDate": "Select date", - "scheduleTimeLabel": "Time", - "schedulePreview": "Runs at {time}", - "schedulePastHint": "That time has passed — the task starts as soon as you save.", - "scheduleInAnHour": "In 1 hour", - "scheduleInThreeHours": "In 3 hours", - "scheduleTomorrow": "Tomorrow 9:00", - "scheduleClear": "Clear schedule", - "scheduleBadge": "Scheduled to start at {time}", - "toastScheduled": "Scheduled for {time}", - "toastScheduleCleared": "Schedule cleared", - "actionFollowUp": "Follow up", - "actionAddNote": "Add a note", - "followUpSubmit": "Send", - "followUpIntentRevise": "Rework", - "followUpIntentContinue": "Keep going", - "followUpIntentQuestion": "Ask", - "followUpIntentVerify": "Double-check", - "followUpPlaceholderRevise": "What should the agent change? It continues in the same session.", - "followUpPlaceholderContinue": "What's next? The work so far stays as it is.", - "followUpPlaceholderQuestion": "What do you want to know? The agent answers without touching any file.", - "followUpPlaceholderVerify": "Optional: anything it should look at closely?", - "followUpPlaceholderRetry": "Optional: what should it do differently? e.g. run pnpm install first", - "followUpPlaceholderRequeue": "Optional: why did you cancel it, and what should change this time?", - "actionArchive": "Archive", - "actionUnarchive": "Unarchive", - "archiveAllDone": "Archive all", - "dropToStart": "Release to start", - "errorView": "View", - "notifyReview": "Ready for review: {title}", - "notifyFailed": "Task failed: {title}", - "createFromMessage": "Create task from message", - "detailTokens": "Total tokens", - "editorTitleNew": "New task", - "editorTitleEdit": "Edit task", - "templates": "Templates", - "templatesEmpty": "No templates yet.", - "templateSaveCurrent": "Save current as template", - "templateDelete": "Delete template", - "transcriptTitle": "Task session", - "transcriptDescription": "Read-only live view of the task's agent session.", - "phaseWork": "Task run", - "phaseRetry": "Retry run", - "phaseReturn": "Follow-up", - "phaseMerge": "Merge", - "titleLabel": "Title", - "titlePlaceholder": "What needs to be done?", - "promptLabel": "Task description", - "promptPlaceholder": "Describe the task for the agent — @ to reference files, / for commands", - "folderPlaceholder": "Select a folder", - "agentInheritedHint": "Inherited from task settings — change it to override for this task", - "agentOverrideReset": "Reset to inherited", - "sectionTarget": "Target", - "errorTitle": "Title is required", - "errorPrompt": "Task description is required", - "errorFolder": "Select a folder", - "save": "Save", - "cancel": "Cancel", - "mergeTitle": "Merge task", - "mergeQueuedTitle": "Queued merge", - "mergeQueueHint": "Another task of this project is merging right now. This one joins the queue and starts on its own as soon as that one finishes.", - "mergeQueueUpdateHint": "This task is already waiting to merge. Submitting updates it and keeps its place in the queue.", - "mergeDescription": "Merge {branch} into {base}. Uncommitted changes in the worktree are committed first.", - "mergeMessage": "Commit message", - "mergeMessagePlaceholder": "e.g. feat: add login validation", - "mergeAutoMessage": "Let the agent write the commit message", - "strategySquash": "Combine into one commit", - "strategySquashHint": "All the task's changes land in the main branch as a single history entry — a tidier history.", - "strategyMerge": "Keep full history", - "strategyMergeHint": "Every commit made during the task is kept, plus one merge entry — each step stays traceable.", - "mergeDeleteWorktree": "Delete worktree after merge", - "mergeSubmit": "Merge", - "mergeSubmitQueue": "Add to merge queue", - "mergeQueuedToast": "Added to the merge queue — it starts as soon as the current merge finishes.", - "completeTitle": "Complete task", - "completeDescription": "This task changed no files, so there is nothing to merge — it is marked as done directly.", - "completeDescriptionNoWorktree": "This task's worktree has been removed, so there is no merge to run — it is marked as done directly. A work branch that still holds unmerged commits is kept.", - "completeDeleteWorktree": "Delete the worktree after completing", - "completeSubmit": "Complete", - "settingsTitle": "Task settings", - "settingsDescription": "Defaults for tasks in {folder}.", - "settingsScope": "Scope", - "settingsScopeGlobal": "All folders (global defaults)", - "settingsScopeGlobalHint": "Folders without their own settings use these global defaults.", - "settingsSource": "Configuration", - "settingsSourceGlobal": "Global defaults", - "settingsSourceCustom": "Custom", - "settingsSourceGlobalFollow": "Follows the global task settings — changes there apply here automatically.", - "settingsSourceCustomHint": "Saves this folder's own settings; it stops following the global defaults.", - "settingsAgent": "Default agent", - "settingsMaxConcurrent": "Max concurrent tasks", - "settingsMaxConcurrentHint": "0 = unlimited", - "settingsAutoProcess": "Process automatically", - "settingsAutoProcessHint": "To-dos start on their own, up to the concurrency limit.", - "settingsMergeStrategy": "Default merge strategy", - "settingsMergeStrategyHint": "How the task's changes are recorded in the branch history when merged.", - "settingsAutoMerge": "Merge automatically", - "settingsAutoMergeHint": "A task that reaches review with something to land merges as if you clicked Merge: the agent writes the commit message, and the worktree follows the default below. A red preflight or a failed merge leaves the task waiting for you.", - "settingsDeleteWorktree": "Delete the worktree after merging", - "settingsDeleteWorktreeHint": "Pre-selects the option in the merge dialog; you can still change it there.", - "settingsWorktreeRoot": "Worktree location", - "settingsWorktreeRootHint": "Directory new task worktrees are created in — one per task. Leave it empty to keep them next to the project folder; \"~\" is your home directory, and a relative path resolves against the project folder.", - "settingsWorktreeRootPlaceholder": "~/codeg-worktrees", - "settingsWorktreeRootBrowse": "Choose the worktree directory", - "settingsPreflight": "Preflight command", - "settingsPreflightHint": "Runs in the worktree when a task reaches review.", - "settingsPreflightCustomPlaceholder": "pnpm test", - "settingsInitCommand": "Worktree init command", - "settingsInitCommandHint": "Runs inside a freshly created worktree before the agent starts.", - "settingsInitCommandPlaceholder": "pnpm install", - "settingsTabGeneral": "General", - "settingsTabMerge": "Merge", - "settingsTabWorktree": "Worktree", - "settingsTabPrompts": "Prompts", - "settingsPromptsIntro": "Each stage already sends a built-in prompt — the task itself, the worktree rules, and for merging the exact git steps. Text you add here is appended at the end as extra instructions: it refines those built-ins, it never replaces them.", - "settingsPromptStageAll": "All stages", - "settingsPromptPlaceholderAll": "e.g. Follow the conventions in AGENTS.md; keep the final summary to two sentences", - "settingsPromptPlaceholderWork": "e.g. Read the related tests first; commit in small steps as you go", - "settingsPromptPlaceholderRetry": "e.g. Check what is already committed before continuing; don't redo finished work", - "settingsPromptPlaceholderReturn": "e.g. Address every point raised; don't refactor anything unrelated", - "settingsPromptPlaceholderMerge": "e.g. Write the landing commit message in English; call out any conflict you resolved by hand", - "settingsPromptHintAll": "Appended to every prompt the agent receives, the merge run included.", - "settingsPromptHintWork": "Appended when a task runs for the first time.", - "settingsPromptHintRetry": "Appended when an interrupted or failed task is picked up again.", - "settingsPromptHintReturn": "Appended when you follow up on a reviewed task (rework, extra work, self-check).", - "settingsPromptHintMerge": "Appended when the agent lands the task onto the base branch.", - "preflightPassed": "{name} passed", - "preflightFailed": "{name} failed", - "preflightRunning": "{name} running…", - "detailDescription": "Task detail", - "detailSummary": "Result", - "detailFiles": "Changed files", - "detailDiffAll": "View full diff", - "detailDiffAllTitle": "Full diff", - "detailNoChanges": "No changes vs the base yet", - "detailTimeline": "Progress", - "detailTimelineEmpty": "No activity yet", - "showMore": "Show more", - "showLess": "Show less", - "detailInfo": "Details", - "detailBranch": "Branch", - "detailMergeCommit": "Merge commit", - "detailChanges": "Changes", - "detailScheduled": "Scheduled start", - "detailCreated": "Created", - "detailStarted": "Started", - "detailFinished": "Finished", - "diffLoading": "Loading diff…", - "deleteConfirmTitle": "Delete task?", - "deleteConfirmBody": "“{title}” will be removed from the board. An active run is canceled first.", - "deleteWithWorktree": "Also delete its worktree", - "eventCreated": "Created", - "eventStatusChanged": "Status changed", - "eventConfigEffective": "Launch config", - "eventInitCommand": "Init command", - "eventAgentProgress": "Agent progress", - "eventAgentVerdict": "Agent verdict", - "eventMergeAttempt": "Merge started", - "eventMergeQueued": "Queued to merge", - "eventMergeConflict": "Merge conflict", - "eventPreflight": "Preflight", - "eventCleanupFailed": "Worktree cleanup failed", - "eventResumeFallback": "Session resume fell back to a new session", - "eventUserAction": "User action", - "eventDiffStat": "Change snapshot" - }, - "CustomSkillsSettings": { - "loading": "Loading custom skills…", - "category": "Custom", - "searchPlaceholder": "Search custom skills by name, id, or description", - "states": { - "not_linked": "Not enabled", - "linked_to_codeg": "Enabled", - "linked_elsewhere": "Linked elsewhere", - "blocked_by_real_directory": "Blocked by a real folder", - "broken": "Broken link" - }, - "actions": { - "new": "New", - "import": "Import", - "importFromAgent": "Import from agent", - "cancel": "Cancel", - "save": "Save" - }, - "rowMenu": { - "edit": "Edit", - "duplicate": "Duplicate", - "delete": "Delete" - }, - "bulk": { - "delete": "Delete selected" - }, - "editor": { - "createTitle": "New custom skill", - "editTitle": "Edit custom skill", - "description": "Custom skills live in the shared store (~/.codeg/skills) and can be enabled for any agent.", - "idLabel": "Skill id", - "idPlaceholder": "e.g. my-workflow", - "contentLabel": "SKILL.md", - "contentPlaceholder": "Write the skill's SKILL.md here…", - "preview": "Preview", - "edit": "Edit", - "emptyBody": "No content yet." - }, - "duplicate": { - "title": "Duplicate skill", - "description": "Create a copy of \"{id}\" with a new id.", - "newIdPlaceholder": "New skill id", - "confirm": "Duplicate" - }, - "import": { - "title": "Choose a skill folder to import" - }, - "importFromAgent": { - "title": "Import skills from an agent", - "description": "Copy an agent's own skills into the shared store so you can enable them for any agent.", - "agentLabel": "Agent", - "agentPlaceholder": "Select an agent", - "selectAll": "Select all ({count})", - "loading": "Loading the agent's skills…", - "unsupported": "This agent doesn't expose a skills directory.", - "empty": "This agent has no importable skills.", - "alreadyInLibrary": "In library", - "confirm": "Import selected ({count})" - }, - "delete": { - "title": "Delete custom skills?", - "body": "This removes {count} custom skill(s) from the central store and unlinks them from every agent. This can't be undone.", - "confirm": "Delete" - }, - "toasts": { - "loadFailed": "Failed to load skill", - "idRequired": "Please enter a skill id", - "created": "Custom skill created", - "updated": "Custom skill updated", - "saveFailed": "Failed to save skill", - "imported": "Skill imported", - "importFailed": "Failed to import skill", - "duplicated": "Skill duplicated", - "duplicateFailed": "Failed to duplicate skill", - "deleted": "Deleted {count} skill(s)", - "deletedPartial": "Deleted {ok}, {failed} failed", - "deleteFailed": "Failed to delete skills", - "importedFromAgent": "Imported {count} skill(s)", - "importedFromAgentPartial": "Imported {ok}, {failed} failed", - "importFromAgentAllSkipped": "Nothing to import — {count} already in the library", - "importFromAgentFailed": "Failed to import from agent" - } - }, - "CodexModelEditor": { - "customizedNotice": "You've customized the model list, so codeg now manages codex's full model table. Official models codex ships later won't appear automatically — click the refresh button below and save again to sync them. Clear your customizations to let codex update automatically.", - "officialsTitle": "Official models", - "officialsHint": "Auto-included from the codex you launch; remove any you don't want.", - "officialsEmpty": "No official models available.", - "refresh": "Refresh from codex", - "readdOfficial": "Re-add official", - "customsTitle": "Custom models", - "customsEmpty": "No custom models yet.", - "addCustom": "Add custom", - "slugPlaceholder": "Model id (slug)", - "displayNamePlaceholder": "Display name", - "contextWindow": "Context", - "makeDefault": "Set as default", - "defaultHint": "Default model", - "remove": "Remove", - "advanced": "Advanced", - "baseTemplate": "Base template", - "baseTemplateHint": "Official model to clone required fields (system prompt, tools, limits) from.", - "groupBehavior": "Behavior & capabilities", - "fieldReasoningLevel": "Default reasoning", - "fieldReasoningSummary": "Reasoning summary", - "fieldVerbosity": "Verbosity", - "fieldShellType": "Shell type", - "fieldApplyPatch": "Apply-patch tool", - "fieldReasoningSummaries": "Reasoning summaries", - "fieldSupportVerbosity": "Verbosity control", - "fieldParallelToolCalls": "Parallel tool calls", - "fieldSearchTool": "Web search tool", - "optNone": "None", - "groupInstructions": "Description & system prompt", - "fieldDescription": "Description", - "baseInstructions": "System prompt (base_instructions)" - }, - "DiagnosticsSettings": { - "title": "Environment diagnostics", - "description": "Checks how this app resolves the agent CLI inside its own process, which can differ from your terminal.", - "loading": "Running diagnostics…", - "error": "Diagnostics failed", - "rerun": "Re-run", - "copyAll": "Copy all", - "copied": "Diagnostics copied to clipboard", - "button": "Diagnose", - "verdict": { - "ok": "Environment looks healthy. If it still shows as not installed, fully restart the app so the prefix cache refreshes.", - "node_missing": "Node.js was not found on the app PATH.", - "npm_missing": "npm was not found on the app PATH.", - "not_installed": "This agent does not appear to be installed.", - "installed_but_unresolved": "The agent is recorded as installed, but the app cannot locate its executable.", - "user_prefix_not_on_path": "Installed into the fallback prefix (~/.codeg/npm-global), which is not on the app PATH. Fully restart the app and try again.", - "homebrew_bin_not_on_path": "Installed under the Homebrew bin, which is not on the app PATH (Apple Silicon keg split).", - "terminal_only_path": "The command resolves in your terminal but not in the app — a GUI PATH gap. Launch the app from a terminal, or reinstall from Agent Settings.", - "npm_prefix_timeout": "npm prefix -g was too slow (over 1.5s), so fallback detection was skipped. Restart the app and try again.", - "node_too_old": "Your active Node.js is older than this agent requires. Upgrade Node.js.", - "adapter_missing_native_present": "Your own {agent} CLI is installed, but Codeg launches a separate ACP adapter package — and that one isn't installed yet. Install it from Agent Settings; it won't touch your CLI and shares the same sign-in.", - "adapter_missing": "Codeg launches a separate ACP adapter package for {agent}, and it isn't installed yet. Install it from Agent Settings — installing the vendor CLI alone is not enough." - } - }, - "TokenUsage": { - "title": "Token Usage", - "rangeLabel": "Time range", - "range7d": "7 days", - "range30d": "30 days", - "range90d": "90 days", - "rangeThisMonth": "This month", - "rangeThisYear": "This year", - "rangeAll": "All time", - "rangeCustom": "Custom", - "moreRanges": "More", - "customRangePick": "Pick a date range", - "bucketLabel": "Group by", - "bucketDay": "Day", - "bucketWeek": "Week", - "bucketMonth": "Month", - "bucketUnitDay": "day", - "bucketUnitWeek": "week", - "bucketUnitMonth": "month", - "folderFilter": "Folders", - "allFolders": "All folders", - "agentFilter": "Agents", - "allAgents": "All agents", - "modelFilter": "Models", - "allModels": "All models", - "searchPlaceholder": "Search…", - "noMatches": "No matches", - "clearFilter": "Clear selection", - "resetFilters": "Reset filters", - "refresh": "Refresh", - "rebuild": "Rebuild all", - "rebuildHint": "Re-reads every transcript from scratch. Use this if a session grew outside codeg.", - "syncing": "Counting sessions…", - "syncProgress": "{done} / {total}", - "syncDone": "Counted {synced} sessions", - "syncFailed": "Could not read some sessions", - "syncBusy": "A refresh is already running", - "lastSynced": "Updated {time}", - "lastSyncedNever": "Never updated", - "tileTotal": "Total tokens", - "tileSessions": "Sessions", - "tileTurns": "Turns", - "tileActiveDays": "Active days", - "tileGenTime": "Generation time", - "vsPrevious": "vs. previous period", - "deltaNew": "new", - "trendTitle": "Usage over time", - "trendEmpty": "No usage in this range", - "trendTurns": "Turns", - "trendSessions": "Sessions", - "compositionTitle": "What the tokens were", - "compositionHint": "Input is what you sent, output is what the model wrote, and cache reads are context you didn't pay full price for.", - "compositionNote": "Re-sending those cache hits at full price would have cost another {value}.", - "inputTokens": "Input", - "outputTokens": "Output", - "cacheWrite": "Cache write", - "cacheRead": "Cache read", - "freshTokens": "Fresh compute", - "cacheHitCaption": "Cache hit", - "cacheHeroTitleHigh": "Most context never got re-sent", - "cacheHeroTitleLow": "Most context still bills at full price", - "cacheHeroDesc": "The cache carried {cached} of context — only {fresh} was freshly computed in this period.", - "cacheSavedSuffix": "That saved re-sending the equivalent of {saved}.", - "avgPerSession": "Avg. per session", - "avgTurnsPerSession": "{count} turns per session", - "avgPerActiveDay": "Avg. per active day", - "peakBucket": "Busiest {bucket}", - "peakHour": "Peak hour", - "daysValue": "{count} days", - "idleDays": "Idle days", - "byFolderTitle": "By folder", - "byAgentTitle": "By agent", - "byModelTitle": "By model", - "distributionTitle": "Usage distribution", - "distributionHint": "Sessions and tokens grouped by the selected dimension — click a row to filter by it.", - "otherLabel": "Other", - "unknownModel": "Unspecified model", - "emptyBreakdown": "Nothing recorded yet", - "sessionsCount": "{count} sessions", - "heatmapTitle": "When you build", - "heatmapHint": "Tokens by local weekday and hour.", - "heatmapPeakHint": "Densest around {hour}:00.", - "less": "Less", - "more": "More", - "heatmapCell": "{weekday} {hour}:00 — {value} tokens", - "weekMon": "Mon", - "weekTue": "Tue", - "weekWed": "Wed", - "weekThu": "Thu", - "weekFri": "Fri", - "weekSat": "Sat", - "weekSun": "Sun", - "topSessionsTitle": "Heaviest sessions", - "untitledSession": "Untitled session", - "topSessionsEmpty": "No sessions in this range", - "streakLongest": "Longest streak", - "streakLongestDays": "Longest streak {count} days", - "share": "Share", - "moreActions": "More actions", - "shareDialogTitle": "Share your usage card", - "shareDialogHint": "A snapshot of the range and filters you're looking at.", - "shareSave": "Save image", - "shareCopy": "Copy image", - "shareCopied": "Copied to clipboard", - "shareSaved": "Image saved", - "shareFailed": "Could not create the image", - "shareRendering": "Rendering…", - "cardHeading": "My AI coding stats", - "cardRangeAll": "All time", - "cardTotalLabel": "Tokens used", - "cardFooter": "Made with codeg", - "cardTopModels": "Top models", - "cardTopProjects": "Top projects", - "archetypeNightOwl": "Night Owl", - "archetypeNightOwlDesc": "{percent}% of your tokens burn after dark.", - "archetypeEarlyBird": "Early Bird", - "archetypeEarlyBirdDesc": "{percent}% of your tokens land before 9am.", - "archetypeWeekendWarrior": "Weekend Warrior", - "archetypeWeekendWarriorDesc": "{percent}% of your tokens happen on the weekend.", - "archetypeCacheMaster": "Cache Master", - "archetypeCacheMasterDesc": "{percent}% of your context came from cache.", - "archetypeMarathoner": "Marathoner", - "archetypeMarathonerDesc": "{days} days building without a break.", - "archetypePolyglot": "Polyglot", - "archetypePolyglotDesc": "{count} agents in serious rotation.", - "archetypeLaserFocus": "Laser Focus", - "archetypeLaserFocusDesc": "{percent}% of your tokens went to one project.", - "archetypeDeepDiver": "Deep Diver", - "archetypeDeepDiverDesc": "{averageK}K tokens in an average session.", - "archetypeSteady": "Steady Builder", - "archetypeSteadyDesc": "{days} days of shipping.", - "emptyTitle": "Nothing counted yet", - "emptyHint": "Codeg reads token counts straight from each agent's own transcript. Run a refresh to count what's already on this machine.", - "emptyAction": "Count my sessions", - "loadFailed": "Could not load usage", - "truncatedNotice": "This range is very large — the numbers cover only the most recent slice of it." - } -} +{ + "Language": { + "followSystem": "Follow System", + "english": "English", + "simplifiedChinese": "Simplified Chinese", + "traditionalChinese": "Traditional Chinese", + "japanese": "Japanese", + "korean": "Korean", + "spanish": "Spanish", + "german": "German", + "french": "French", + "portuguese": "Portuguese", + "arabic": "Arabic" + }, + "GitCredentialDialog": { + "title": "Authentication Required", + "description": "The remote server requires credentials. Enter your username and password (or personal access token).", + "username": "Username", + "usernamePlaceholder": "Username or email", + "password": "Password / Token", + "passwordPlaceholder": "Password or personal access token", + "passwordHint": "For non-GitHub servers, enter your username and password.", + "cancel": "Cancel", + "authenticate": "Authenticate", + "authenticating": "Authenticating...", + "invalidCredentials": "Invalid credentials. Please try again.", + "saveCredentials": "Save credentials for future operations", + "githubTitle": "GitHub Authentication", + "githubDescription": "Enter a personal access token to authenticate with GitHub. The token will be validated and saved to your accounts.", + "githubToken": "Personal Access Token", + "githubTokenPlaceholder": "ghp_xxxxxxxxxxxx", + "githubTokenHint": "Generate a token at GitHub → Settings → Developer settings → Personal access tokens.", + "githubAuthenticate": "Validate & Connect", + "generateToken": "Generate token" + }, + "SettingsShell": { + "title": "Settings", + "preferences": "Preferences", + "nav": { + "general": "General", + "appearance": "Appearance", + "agents": "Agents", + "mcp": "MCP", + "skills": "Skills", + "shortcuts": "Shortcuts", + "version_control": "Version Control", + "system": "System", + "chat_channels": "Chat Channels", + "web_service": "Web Service", + "model_providers": "Model Providers", + "experts": "Experts", + "science": "Science", + "office_tools": "Office Tools", + "skill_packs": "Skill Packs", + "quick_messages": "Quick Messages", + "logs": "Runtime Logs" + } + }, + "AppearanceSettings": { + "sectionTitle": "Theme Appearance", + "sectionDescription": "Choose light, dark, or follow system. Settings are saved automatically.", + "themeMode": "Theme mode", + "placeholder": "Select theme mode", + "system": "Follow system", + "light": "Light", + "dark": "Dark", + "currentTheme": "Current effective theme: {theme}", + "resolvedTheme": { + "light": "Light", + "dark": "Dark", + "unknown": "--" + }, + "themeColor": { + "sectionTitle": "Theme color", + "sectionDescription": "Pick a color palette for accents, buttons, and highlights.", + "current": "Current color: {color}", + "options": { + "neutral": "Neutral", + "zinc": "Zinc", + "slate": "Slate", + "stone": "Stone", + "gray": "Gray", + "red": "Red", + "rose": "Rose", + "orange": "Orange", + "green": "Green", + "blue": "Blue", + "yellow": "Yellow", + "violet": "Violet" + } + }, + "customStyle": { + "sectionTitle": "Custom Style", + "sectionDescription": "Fine-tune the current theme's colors, or inject your own CSS. Overrides sit on top of the base preset, so switching presets keeps them.", + "summarySuspended": "Suspended", + "summaryDefault": "Preset defaults", + "summaryTokens": "{count, plural, one {# override} other {# overrides}}", + "summaryCss": "Custom CSS", + "suspendedByShortcut": "Custom style is suspended. Nothing set here takes effect until you resume it.", + "suspendedBySafeParam": "This window was opened in safe appearance mode, so custom style is ignored here. Other windows are unaffected.", + "resume": "Resume custom style", + "enableTheme": "Enable custom colors", + "editingLight": "Editing light mode values. Switch the app to dark mode to set its own.", + "editingDark": "Editing dark mode values. Switch the app to light mode to set its own.", + "resetToken": "Reset to preset value", + "radius": "Corner radius", + "radiusHint": "Drives the whole radius scale from sm to 4xl, so one slider rounds the entire app.", + "advanced": "Advanced ({count} more variables)", + "enableCss": "Enable custom CSS", + "cssRisk": "Advanced feature. Custom CSS overrides every built-in style and can make the interface unusable.", + "editCss": "Edit CSS…", + "cssPresent": "{size} KB saved", + "cssEmpty": "Nothing saved yet", + "escapeHint": "Stuck with a broken interface? Press {shortcut} to suspend all custom style, or open a window with the safeStyle=1 query parameter.", + "copyTheme": "Copy theme JSON", + "importTheme": "Import theme…", + "clearTheme": "Clear overrides", + "interopHint": "Themes use shadcn's registry:theme format, so you can paste any shadcn theme here and use exported ones in any shadcn project.", + "importTitle": "Import theme", + "importDescription": "Paste a shadcn registry:theme item, a bare light/dark object, or a flat token map.", + "readClipboard": "Read clipboard", + "importConfirm": "Import", + "cancel": "Cancel", + "apply": "Apply", + "toasts": { + "copied": "Theme JSON copied", + "copyFailed": "Could not copy to the clipboard", + "clipboardReadFailed": "Could not read the clipboard, paste manually", + "importFailed": "No usable theme tokens found in that JSON", + "imported": "Theme imported" + }, + "css": { + "dialogTitle": "Custom CSS", + "dialogDescription": "Applies to every codeg window. Changes preview live; press Apply to save.", + "size": "{used} KB / {max} KB", + "ruleCount": "{count} rules", + "errorTooLarge": "Too large to save. Trim it below the limit.", + "errorImportEscaped": "An @import rule survived removal (escaped syntax). Remove it to save.", + "warnNoRules": "No rules parsed, check the syntax.", + "noticeImportsRemoved": "@import rules removed: {count}. They would fetch remote stylesheets.", + "noticeRemoteUrl": "Contains a remote url(), which makes a network request when applied.", + "noticePreviewSuspended": "Custom style is suspended, so this preview is not applied.", + "noticeDisabled": "Custom CSS is off. You can preview here, but nothing applies until you enable it.", + "hintTokens": "Tip: your color overrides are available as var(--primary), var(--background) and so on." + } + }, + "zoomLevel": { + "sectionTitle": "Window zoom", + "sectionDescription": "Scale the entire interface. Applies immediately and persists per device.", + "placeholder": "Select zoom level", + "default": "Default", + "current": "Current zoom: {zoom}%" + }, + "fonts": { + "sectionTitle": "Fonts", + "sectionDescription": "Choose fonts for the interface, code editor, and terminal. Bundled fonts load on demand; pick “Custom…” to use any font installed on your system.", + "interface": "Interface", + "editor": "Editor", + "terminal": "Terminal", + "groupSans": "Sans-serif", + "groupMono": "Monospace", + "custom": "Custom…", + "customPlaceholder": "Font family, e.g. Fira Code", + "fontSize": "Font size", + "ligatures": "Enable font ligatures", + "ligaturesUnavailable": "This font has no ligatures", + "wordWrap": "Enable word wrap", + "terminalLigaturesHint": "Terminal ligatures apply only to bundled coding fonts.", + "preview": "Preview" + }, + "welcomePanel": { + "sectionTitle": "Mode selection area", + "sectionDescription": "The Code Development / Office Work shortcut cards shown above the composer on the new conversation page.", + "showQuickActions": "Show on the new conversation page" + }, + "workspaceBackground": { + "sectionTitle": "Workspace background", + "sectionDescription": "Show a picture behind the whole workspace. Sidebar and panels turn translucent and frosted so the image shows through, and a mask keeps text readable.", + "enable": "Enable background image", + "image": "Image", + "chooseImage": "Choose image", + "replaceImage": "Replace image", + "removeImage": "Remove", + "fillMode": "Fill mode", + "fillModes": { + "cover": "Cover", + "contain": "Contain", + "center": "Center", + "tile": "Tile" + }, + "maskOpacity": "Mask opacity", + "maskOpacityHint": "Higher values fade the image toward the theme background, improving text contrast.", + "imageBlur": "Image blur", + "panelOpacity": "Panel opacity", + "panelOpacityHint": "How opaque the sidebar, panels and tab bars are. Lower lets more of the image show through.", + "errorTooLarge": "Image is too large (max 16 MB).", + "errorUploadFailed": "Failed to set the background image." + } + }, + "SystemSettings": { + "loading": "Loading...", + "sectionTitle": "System Management", + "sectionDescription": "Manage network proxy, app updates and language preferences.", + "proxyTitle": "Network Proxy", + "proxyDescription": "When enabled, subsequent network requests prefer this proxy (including ACP chat, agent installation and Git remote operations).", + "loadFailed": "Load failed: {message}", + "enableProxy": "Enable system proxy", + "proxyAddress": "Proxy address", + "proxyHint": "Supports http(s)/socks5, example: {example}. Only effective when system proxy is enabled.", + "save": "Save", + "saving": "Saving...", + "proxyRequired": "Proxy URL is required when proxy is enabled", + "saveSuccess": "System proxy settings saved", + "saveFailed": "Save failed: {message}", + "languageTitle": "Language", + "languageDescription": "Set app language. When following system locale, unsupported languages fall back to English.", + "appLanguage": "App language", + "languageSaveSuccess": "Language settings saved", + "languageSaveFailed": "Failed to save language settings: {message}", + "updateTitle": "App Update", + "versionTitle": "Software Update", + "updateDescription": "Check the configured release source for newer versions and install directly when available.", + "currentVersion": "Current version", + "upgradableVersion": "Latest version", + "none": "None", + "lastChecked": "Last checked: {time}", + "updateError": "Update error: {message}", + "checking": "Checking...", + "checkUpdate": "Check for updates", + "updating": "Installing...", + "downloading": "Downloading...", + "upgradeTo": "Upgrade to v{version}", + "viewRelease": "View v{version} release", + "foundUpdate": "New version v{version} found", + "alreadyLatest": "You're on the latest version", + "checkUpdateFailed": "Failed to check for updates: {message}", + "installSuccess": "Update installed. Relaunching app.", + "installFailed": "Update failed: {message}", + "upgradeSuccess": "Upgrade complete. Reloading...", + "restartTimeout": "The server didn't come back in time. Check the container or service logs.", + "restartingIn": "Restarting in {seconds}s...", + "waitingForServer": "Waiting for the server to come back...", + "restartToUpdate": "Restart to update", + "newVersionBadge": "New v{version}", + "updateAvailableTitle": "Update available", + "releaseNotesTitle": "What's new", + "remindLater": "Later", + "retry": "Retry", + "stepDownload": "Download", + "stepInstall": "Install", + "stepRestart": "Restart", + "updateReadyHint": "Update downloaded — restart to apply.", + "restarting": "Restarting...", + "dockerUpgradeHint": "This upgrades the running container now. It's lost if the container is recreated — to keep it, pull or build an image at the new version and recreate.", + "upgradeRolledBack": "Upgrade failed; the server rolled back to the previous version.", + "serverUnreachable": "Couldn't reach the server to start the upgrade. Check that it's running and try again.", + "rollbackButton": "Roll back", + "rollingBack": "Rolling back...", + "rollbackDescription": "Restore the version installed before the last upgrade.", + "rollbackConfirmTitle": "Roll back to the previous version?", + "rollbackConfirmDescription": "The server will restart on the version installed before the last upgrade. A newer release stays available to install again.", + "rollbackConfirm": "Roll back", + "rollbackCancel": "Cancel", + "rollbackSuccess": "Rolled back to the previous version. Reloading...", + "rollbackFailed": "Rollback failed. Check the server logs.", + "updateErrors": { + "sourceUnavailable": "Cannot reach the update source. Check your network or proxy and try again.", + "network": "Network connection failed. Check your network or proxy and try again.", + "downloadFailed": "Failed to download update package. Please try again later.", + "installFailed": "Failed to install update. Please close the app and try again.", + "unknown": "Update failed. Please try again later." + } + }, + "VersionControlSettings": { + "loading": "Loading...", + "sectionTitle": "Version Control", + "sectionDescription": "Configure Git executable and manage GitHub accounts.", + "gitTitle": "Git Configuration", + "gitDescription": "Configure the Git executable used by the application.", + "gitDetected": "Git detected", + "gitNotFound": "Git not found on this system", + "gitVersion": "Version", + "gitPath": "Path", + "customGitPath": "Custom Git Path", + "customGitPathPlaceholder": "/usr/bin/git", + "customGitPathHint": "Leave empty to use the auto-detected path.", + "test": "Test", + "testing": "Testing...", + "testSuccess": "Git executable is valid.", + "testFailed": "Git test failed: {message}", + "save": "Save", + "saving": "Saving...", + "saveSuccess": "Git settings saved.", + "saveFailed": "Failed to save: {message}", + "githubTitle": "GitHub Accounts", + "githubDescription": "Manage GitHub accounts for authentication. Tokens are stored locally.", + "noAccounts": "No GitHub accounts configured.", + "addAccount": "Add Account", + "serverUrl": "Server URL", + "serverUrlPlaceholder": "https://github.com", + "token": "Personal Access Token", + "tokenPlaceholder": "ghp_xxxxxxxxxxxx", + "generateToken": "Generate token", + "tokenHint": "Generate a token at GitHub → Settings → Developer settings → Personal access tokens.", + "validateAndAdd": "Validate & Add", + "validating": "Validating...", + "addSuccess": "Account {username} added successfully.", + "addFailed": "Failed to add account: {message}", + "testConnection": "Test", + "connectionSuccess": "Connection successful.", + "connectionFailed": "Connection failed: {message}", + "setDefault": "Set Default", + "defaultLabel": "Default", + "defaultSet": "Default account updated.", + "removeAccount": "Remove", + "removeConfirmTitle": "Remove Account", + "removeConfirmMessage": "Are you sure you want to remove the account \"{username}\"?", + "removeConfirm": "Remove", + "removeCancel": "Cancel", + "removeSuccess": "Account removed.", + "scopes": "Scopes", + "loadFailed": "Failed to load settings: {message}", + "gitAccount": { + "sectionTitle": "Git Accounts", + "sectionDescription": "Manage credentials for non-GitHub Git servers (GitLab, Bitbucket, self-hosted, etc.).", + "noAccounts": "No Git server accounts configured.", + "addAccount": "Add Account", + "addTitle": "Add Git Account", + "addDescription": "Enter the server address, username, and password or access token.", + "serverUrl": "Server URL", + "serverUrlPlaceholder": "https://gitlab.example.com", + "username": "Username", + "usernamePlaceholder": "Username or email", + "password": "Password / Token", + "passwordPlaceholder": "Password or access token", + "passwordHint": "Enter your password or a personal access token for the server.", + "add": "Add", + "serverRequired": "Server URL is required.", + "usernameRequired": "Username is required.", + "passwordRequired": "Password is required." + } + }, + "ShortcutSettings": { + "sectionTitle": "Shortcuts", + "resetDefault": "Reset defaults", + "recordInstruction": "Click the right-side button, then press a key combination. Use Ctrl/Cmd, Alt, and Shift. Press Esc to cancel recording.", + "recording": "Press shortcut...", + "toasts": { + "conflict": "Shortcut is already used by \"{title}\"", + "updated": "Shortcut updated", + "invalid": "Invalid shortcut, please try again", + "reset": "Default shortcuts restored" + }, + "actions": { + "toggle_search": { + "title": "Open Search", + "description": "Show or hide the conversation search panel" + }, + "toggle_sidebar": { + "title": "Toggle Left Sidebar", + "description": "Show or hide the conversation list sidebar" + }, + "toggle_terminal": { + "title": "Toggle Terminal", + "description": "Show or hide the bottom terminal panel" + }, + "new_terminal_tab": { + "title": "New Terminal", + "description": "Create a new terminal tab when focus is on terminal" + }, + "close_current_terminal_tab": { + "title": "Close Current Terminal", + "description": "Close the current terminal tab when focus is on terminal" + }, + "toggle_aux_panel": { + "title": "Toggle Right Panel", + "description": "Show or hide the auxiliary info panel" + }, + "new_conversation": { + "title": "New Conversation", + "description": "Create a new conversation tab in current folder" + }, + "open_folder": { + "title": "Open Folder", + "description": "Open folder picker and open in a new window" + }, + "open_settings": { + "title": "Open Settings", + "description": "Open settings window" + }, + "close_current_tab": { + "title": "Close Current Tab", + "description": "Close current conversation or file tab" + }, + "close_all_file_tabs": { + "title": "Close All File Tabs", + "description": "Close all open file tabs when the file pane is active" + }, + "next_tab": { + "title": "Next Tab", + "description": "Switch to the next conversation or file tab" + }, + "prev_tab": { + "title": "Previous Tab", + "description": "Switch to the previous conversation or file tab" + }, + "send_message": { + "title": "Send Message", + "description": "Send the current message in the input box" + }, + "newline_in_message": { + "title": "Newline in Message", + "description": "Insert a newline in the message input box" + }, + "toggle_custom_style": { + "title": "Suspend/resume custom style", + "description": "Escape hatch: turns all custom colors and CSS off, and back on" + } + } + }, + "SkillsSettings": { + "title": "Skills", + "description": "Select a skill on the left. The right side previews Markdown by default; switch to edit to modify and save.", + "loadingAgents": "Loading agents that support Skills...", + "emptyNoManageableAgents": "No agents available for Skills management.", + "managedTarget": "Managed target", + "selectAgentPlaceholder": "Select an agent", + "searchPlaceholder": "Search by name / ID / path...", + "skillsList": "Skills list", + "loadingSkills": "Loading skills...", + "agentNotSupported": "Current agent does not support Skills management.", + "emptySkills": "No skills yet. Click \"New Skill\" to create one.", + "newSkillTitle": "New Skill", + "skillInfo": "Skill Info", + "skillIdPlaceholder": "skill-id (letters/numbers/-/_/.)", + "skillsDirectoryWithPath": "Skills directory: {path}", + "skillsDirectoryNeedId": "Skills directory: enter Skill ID to generate full path", + "markdownContent": "Markdown Content", + "editingStatus": "Editing", + "previewStatus": "Previewing", + "contentPlaceholder": "Enter Skill markdown content...", + "metadataTitle": "Skills Metadata", + "onlyYamlMetadata": "This skill only contains YAML metadata.", + "emptyContentHint": "No content yet. Click \"Edit\" to start.", + "loadingSkill": "Loading skill...", + "emptyNoAgents": "No available agent.", + "noSelectionHint": "Select a skill on the left, or click \"New Skill\" to create one.", + "systemBadge": "System", + "systemHint": "Built-in CLI skill · read-only", + "scope": { + "global": "Global", + "folder": "Folder", + "selectFolderPlaceholder": "Select a folder", + "noFolders": "No folders found", + "pickFolderHint": "Select a folder to view its skills." + }, + "actions": { + "preview": "Preview", + "edit": "Edit", + "openInWindow": "Open in new window", + "delete": "Delete", + "deleting": "Deleting...", + "refresh": "Refresh", + "newSkill": "New Skill", + "reset": "Reset", + "save": "Save", + "saving": "Saving...", + "cancel": "Cancel" + }, + "deleteDialog": { + "title": "Delete Skill", + "confirm": "Delete current skill? This action cannot be undone.", + "confirmWithNamePrefix": "Delete skill", + "confirmWithNameSuffix": "? This action cannot be undone." + }, + "toasts": { + "loadFailed": "Failed to load skill", + "openFolderFailed": "Failed to open folder", + "noSkillDirectory": "No available Skills directory found for current agent", + "nameRequired": "Skill name cannot be empty", + "updated": "Skill updated", + "created": "Skill created", + "saveFailed": "Failed to save skill", + "deleted": "Skill deleted", + "deleteFailed": "Failed to delete skill" + }, + "templates": { + "gemini": "---\nname: example-skill\ndescription: Describe when this skill should be used.\n---\n\n# Skill Name\n\nInstructions for the agent when this skill is active.\n\n## Workflow\n\n1. Add actionable step one.\n2. Add actionable step two.\n", + "openCode": "---\nname: example-skill\ndescription: Describe when this skill should be used.\n---\n\n# Purpose\n\nDescribe what this skill helps with.\n\n# Steps\n\n1. Add actionable step one.\n2. Add actionable step two.\n", + "openClaw": "---\nname: example-skill\ndescription: Describe when this skill should be used.\nuser-invocable: true\ndisable-model-invocation: false\n---\n\n# Purpose\n\nDescribe what this skill helps with.\n\n# Instructions\n\n1. Add actionable instruction one.\n2. Add actionable instruction two.\n", + "default": "---\nname: example-skill\ndescription: Describe when this skill should be used.\n---\n\n# Skill: example-skill\n\n## When to use\n\n- Describe trigger conditions.\n\n## Instructions\n\n1. Add actionable instruction one.\n2. Add actionable instruction two.\n" + } + }, + "McpSettings": { + "loading": "Loading...", + "summary": { + "missingCommand": "(missing command)", + "missingUrl": "(missing url)" + }, + "protocol": { + "stdio": "Stdio" + }, + "errors": { + "selectInstallProtocol": "Please select an install protocol", + "fieldRequired": "{field} is required", + "fieldNeedsBoolean": "{field} must be true or false", + "fieldNeedsNumber": "{field} must be a number", + "fieldNeedsInteger": "{field} must be an integer", + "fieldInvalidJson": "{field} has invalid JSON: {message}", + "fieldOutOfRange": "{field} value is out of allowed range", + "jsonEmpty": "{name} cannot be empty", + "jsonInvalid": "{name} is not valid JSON: {message}", + "jsonMustBeObject": "{name} must be a JSON object", + "specMustBeObject": "MCP config must be a JSON object.", + "missingType": "MCP config is missing the type field. Use one of stdio, http (aliases: streamable-http, streamableHttp), sse.", + "unsupportedType": "Unsupported MCP type {type}. Supported: stdio, http (aliases: streamable-http, streamableHttp), sse.", + "codexEntryUnsupportedType": "Codex MCP entry {id} has unsupported type {type}. Supported: stdio, http (aliases: streamable-http, streamableHttp), sse.", + "unsupportedTransportType": "Unsupported transport type {type}. Supported: http (aliases: streamable-http, streamableHttp), sse.", + "stdioCommandRequired": "stdio MCP requires a non-empty command field.", + "remoteUrlRequired": "Remote MCP requires a non-empty url field.", + "appsRequired": "Select at least one target app." + }, + "jsonNames": { + "localConfig": "MCP Config", + "installConfig": "Install Config" + }, + "toasts": { + "uninstalled": "MCP uninstalled", + "uninstallFailed": "Uninstall failed: {message}", + "selectAtLeastOneApp": "Please select at least one target app", + "saveSuccess": "Saved", + "saveFailed": "Save failed: {message}", + "installed": "{name} installed", + "installFailed": "Install failed: {message}", + "serverIdRequired": "Server ID is required", + "serverIdExists": "Server ID \"{id}\" already exists. Edit the existing entry or pick a different name.", + "created": "MCP created" + }, + "installDialog": { + "title": "Confirm MCP Installation", + "descriptionWithName": "Install {name} to local configuration.", + "description": "Select target apps for installation.", + "protocol": "Protocol", + "selectProtocol": "Select protocol", + "parameters": "Configuration Parameters", + "booleanPlaceholder": "Please select true/false", + "selectOneValue": "Select a value", + "targetApps": "Target Apps" + }, + "actions": { + "cancel": "Cancel", + "confirmInstall": "Confirm Install", + "installing": "Installing", + "uninstall": "Uninstall", + "uninstalling": "Uninstalling", + "viewDetails": "View Details", + "save": "Save", + "saving": "Saving", + "install": "Install", + "refresh": "Refresh", + "newMcp": "New MCP", + "create": "Create", + "creating": "Creating..." + }, + "tabs": { + "local": "Local MCP", + "market": "MCP Marketplace" + }, + "local": { + "filterPlaceholder": "Filter local MCP...", + "loadFailed": "Load failed: {message}", + "empty": "No local MCP detected.", + "description": "Local MCP configuration can be edited and saved directly.", + "enabledApps": "Enabled Apps", + "configJson": "MCP Config (JSON)", + "draftTitle": "New MCP", + "draftDescription": "Provide a Server ID and configuration to create a local MCP server.", + "serverIdLabel": "Server ID", + "serverIdPlaceholder": "Server ID (e.g. my-mcp)", + "typeHint": "Supported types: stdio, http (aliases: streamable-http, streamableHttp), sse. env is only used by stdio; for remote MCPs use headers to carry auth tokens.", + "envOnRemoteWarning": "env detected on a remote MCP. Only stdio uses env; remote MCPs carry auth tokens via headers, so env will be ignored on save." + }, + "market": { + "selectMarketplace": "Select marketplace", + "searchPlaceholder": "Search MCP...", + "searchFailed": "Search failed: {message}", + "loadingList": "Loading MCP list...", + "empty": "No MCP results.", + "loadingDetail": "Loading marketplace details...", + "detailLoadFailed": "Failed to load details: {message}", + "owner": "Owner: {owner}", + "namespace": "Namespace: {namespace}", + "defaultInstallProtocol": "Default Install Protocol", + "currentOptionParameterCount": "Current option parameter count: {count}", + "installConfigDescription": "Install Config (JSON, editable before install; edits will override protocol/parameter form)", + "selectLeftToView": "Select a marketplace MCP on the left to view details." + }, + "badges": { + "verified": "Verified", + "remote": "Remote", + "hasHomepage": "Has Homepage", + "uses": "{count} uses", + "deployed": "Deployed", + "notDeployed": "Not Deployed" + }, + "selectLeftMcp": "Select an MCP on the left." + }, + "AcpAgentSettings": { + "title": "Agent SDK Management", + "description": "Manage Agent SDK connection, enabled state, environment variables, config management and version preflight info in one place.", + "loadingAgents": "Loading agent list...", + "agentList": "Agent List", + "emptyNoAgent": "No available agent.", + "configManagement": "Config Management", + "envVars": "Environment Variables", + "hostTools": { + "label": "Let the agent handle files and commands", + "description": "codeg stops serving file access and terminal commands, so the agent runs them in its own process — where its own sandbox and permission rules apply. Delegating to other agents is also turned off, since that would route the same work back through codeg. codeg adds no sandbox itself, so turn this on only if the agent has one configured." + }, + "nativeJsonConfig": "Native JSON Config", + "modelHintDefault": "Leave empty to use system default model.", + "generalConfigDescriptionClaude": "Supports quick configuration for API URL, API Key and Claude models, and syncs with native JSON config.", + "generalConfigDescriptionDefault": "Supports important config input (API URL, API Key, Model) and native JSON config management.", + "multiAgent": { + "title": "Multi-Agent Collaboration", + "description": "Allow active agents to delegate sub-tasks to other agents.", + "enable": "Enable delegation", + "enableHint": "When off, the delegate_to_agent tool is hidden from the agent's MCP catalog.", + "withheldByHostTools": "{agents} will not get the delegation tools: their per-agent “Let the agent handle files and commands” switch is on.", + "selfInitiate": "Allow spawn without @", + "selfInitiateHint": "When on, an agent may start a listed sub-agent on its own. An @ mention is still always honored. When off, only an @ mention starts a sub-agent.", + "depthLimit": "Maximum delegation depth", + "depthHint": "Allowed range: {min}–{max}. Caps how deep a chain (root → child → grandchild …) can recurse.", + "completedCacheLabel": "Completed-result cache (MB)", + "completedCacheHint": "In-memory cache of finished sub-agent results, held only while the delegating session is running and cleared automatically when it ends. Over this budget the oldest results are dropped from memory first (still viewable in the sub-agent's own session); 0 = unlimited (still cleared when the session ends).", + "save": "Save", + "saving": "Saving…", + "saved": "Delegation settings saved", + "saveFailed": "Failed to save delegation settings", + "loadFailed": "Failed to load delegation settings: {detail}", + "tabGeneral": "General", + "tabAgentDefaults": "Agent defaults", + "agentDefaultsDescription": "Per-agent overrides applied when Multi-Agent Collaboration spawns a subagent for a delegation call. Options shown here come from a live probe — what you pick is exactly what the agent will accept.", + "probing": "Loading available options from the agent…", + "probeFailed": "Failed to load options: {detail}", + "retry": "Retry", + "noConfigAvailable": "This agent has no configurable options.", + "modeLabel": "Mode", + "agentDefaultHint": "Agent default: {value}", + "defaultOptionLabel": "Default ({value})" + }, + "actions": { + "dragSort": "Drag to reorder", + "dragSortAgent": "Drag to reorder {name}", + "refreshCheck": "Refresh check", + "refreshCheckAgent": "Refresh check {name}", + "clickEnable": "Click to enable {name}", + "clickDisable": "Click to disable {name}", + "install": "Install", + "upgrade": "Upgrade", + "uninstall": "Uninstall", + "uninstalling": "Uninstalling...", + "saveEnvVars": "Save environment variables", + "saving": "Saving...", + "saveGrokConfig": "Save Grok Config", + "saveCodexConfig": "Save Codex Config", + "saveGeminiConfig": "Save Gemini Config", + "saveOpenCodeConfig": "Save OpenCode Config", + "saveOpenClawConfig": "Save OpenClaw Config", + "saveConfigManagement": "Save Config Management", + "saveCurrentProvider": "Save Current Provider", + "showApiKey": "Show API Key", + "hideApiKey": "Hide API Key", + "showKey": "Show Key", + "hideKey": "Hide Key", + "showToken": "Show Token", + "hideToken": "Hide Token", + "cancel": "Cancel", + "delete": "Delete", + "deleting": "Deleting...", + "confirmDelete": "Confirm Delete", + "confirmUninstall": "Confirm Uninstall", + "saveClineConfig": "Save Cline Config", + "saveHermesConfig": "Save Hermes Config", + "saveCodeBuddyConfig": "Save CodeBuddy Config", + "saveKimiCodeConfig": "Save Kimi Code Config", + "customInstall": "Custom install", + "saveKimiCodeRawConfig": "Save config.toml", + "saveDeepSeekConfig": "Save DeepSeek Config", + "diagnose": "Diagnose" + }, + "status": { + "enabled": "Enabled", + "disabled": "Disabled", + "unchecked": "Unchecked", + "agentEnabledAria": "{name} enabled", + "agentEnabledSwitch": "{name} enable switch" + }, + "preflight": { + "count": "Preflight items: {count}", + "notRun": "Checks have not run yet." + }, + "grok": { + "configDescription": "Configure Grok here. The controls below — permission mode, reasoning effort, an optional custom (BYO endpoint) model, and compaction — merge into ~/.grok/config.toml, preserving your other keys and comments. Sign-in uses your XAI_API_KEY or `grok login`. Other keys stay editable under Advanced.", + "permissionModeLabel": "Permission mode", + "permissionDefault": "Ask every time", + "permissionAcceptEdits": "Auto-approve edits", + "permissionAuto": "Smart auto-approve", + "permissionAlwaysApprove": "Always approve", + "reasoningEffortLabel": "Reasoning effort", + "effortLow": "Low (faster)", + "effortMedium": "Medium (balanced)", + "effortHigh": "High", + "effortXhigh": "Max", + "optionDefault": "Use default", + "authTitle": "Authentication", + "authMode": "Authentication method", + "authModeApiKey": "XAI API key", + "authModeApiKeyHint": "Authenticate with an XAI_API_KEY from the xAI console — for non-interactive or headless runs. Stored in this agent's environment.", + "authModeCustom": "Custom endpoint", + "authModeCustomHint": "Use a bring-your-own endpoint: define a custom model below with its own base URL and API key. It becomes Grok's default model.", + "subscriptionHint": "Sign in with `grok login` (SuperGrok / X Premium+). No API key is stored.", + "loginHint": "Run this in a terminal to sign in, then reopen these settings:", + "commandCopied": "Command copied to clipboard", + "copyCommand": "Copy command", + "authKeyConfigured": "XAI_API_KEY is configured.", + "authKeyMissing": "No XAI_API_KEY set.", + "advancedToggle": "Advanced (raw config.toml)", + "configTomlNative": "config.toml (native)", + "configTomlHint": "Saved verbatim as the whole ~/.grok/config.toml. Invalid TOML is rejected so a typo never truncates your file.", + "configTomlPlaceholder": "# Keys other than the controls above, e.g.\n# [mcp_servers.*], [cli], [permission] rules.", + "customModelTitle": "Custom model (BYO endpoint)", + "customModelHint": "Point Grok at a custom or self-hosted endpoint. codeg writes a per-model `[model.*]` block and makes it the default. Leave the Model ID empty to remove it.", + "customModelIdLabel": "Model ID", + "customModelIdPlaceholder": "grok-4.5", + "customModelIdHint": "Registered as a `[model.*]` block and sent to the API as the model name; also set as `[models].default`.", + "customBaseUrlLabel": "Base URL", + "customBaseUrlPlaceholder": "https://api.x.ai/v1 (default)", + "customApiBackendLabel": "API backend", + "backendResponses": "Responses", + "backendChatCompletions": "Chat Completions", + "backendMessages": "Messages (Anthropic)", + "customApiKeyLabel": "API Key", + "customApiKeyHint": "Stored inline in `[model.*].api_key`, scoped to this endpoint.", + "customContextWindowLabel": "Context window (tokens)", + "customContextWindowHint": "Optional. Drives auto-compact timing; leave empty for the endpoint default.", + "autoCompactLabel": "Auto-compact threshold (%)", + "autoCompactHint": "Compact the conversation when context usage reaches this percent (Grok default 85). Written to `[session]`." + }, + "cursor": { + "configDescription": "Configure Cursor here. Choose an authentication method — official subscription (browser sign-in) or a Cursor API key for headless/server machines — then pick a model and edit the CLI's permission rules and sandbox. codeg writes them into ~/.cursor/cli-config.json, shared with the cursor-agent CLI.", + "authTitle": "Authentication", + "authChecking": "Checking…", + "authNotInstalled": "cursor-agent is not installed", + "authLoggedIn": "Logged in", + "authNotLoggedIn": "Not logged in", + "loginHint": "Run this in a terminal to sign in with your Cursor account (a browser window opens), then hit refresh:", + "apiKeyLabel": "Cursor API key", + "apiKeyPlaceholder": "key from cursor.com/dashboard", + "apiKeyHint": "CURSOR_API_KEY — a Cursor Dashboard account key, an alternative to browser login for headless/server machines. Not a third-party or OpenAI key.", + "modelTitle": "Default model", + "loadModels": "Load models", + "modelsUnavailable": "Model list unavailable", + "modelHint": "Passed to the CLI as --model at session start. Leave on default to let Cursor choose.", + "permissionsTitle": "Permissions & sandbox", + "permissionsDescription": "Visual editor for the CLI's permission rules (cli-config.json). Allow rules run without prompting; deny rules are always blocked.", + "permissionModeLabel": "Permission mode", + "permissionModeDefault": "Ask before running (default)", + "permissionModeForce": "Run Everything (--force)", + "permissionModeHint": "Run Everything launches sessions with --force: every tool call is auto-allowed except deny rules, with no confirmation prompts (an organization policy may downgrade it to allow-rule matching). Takes effect for new sessions.", + "optionDefault": "Default (unset)", + "sandboxLabel": "Sandbox", + "sandboxEnabled": "Enabled", + "sandboxDisabled": "Disabled", + "allowRulesLabel": "Allow rules", + "denyRulesLabel": "Deny rules", + "addRule": "Add rule", + "rulesSyntaxHint": "Rule syntax: Shell(cmd), Read(path/glob), Write(path/glob), WebFetch(domain), Mcp(server:tool) — deny rules always win.", + "saveConfig": "Save configuration", + "advancedToggle": "Advanced: raw cli-config.json", + "advancedHint": "The whole ~/.cursor/cli-config.json. Saving writes the file verbatim — the structured controls above merge into it instead.", + "saveRawConfig": "Save file", + "authMode": "Authentication method", + "subscriptionHint": "Sign in with your Cursor account and use Cursor's models.", + "customApiKeyRequired": "A Cursor API key is required.", + "authModeApiKey": "Cursor API key (headless)", + "authModeApiKeyHint": "Authenticate with a Cursor account API key from the Cursor dashboard — for headless or server machines. This is a Cursor account key, not a third-party/OpenAI endpoint: cursor-agent only talks to Cursor's own backend. To use a codex/OpenAI-compatible endpoint, use the Codex agent instead.", + "modelPickerPlaceholder": "Search models…", + "modelNoMatch": "No matching model", + "modelsNeedAuth": "Sign in to load the model list.", + "modelDefaultBadge": "default" + }, + "deepseek": { + "configManagement": "DeepSeek Harness Configuration", + "configDescription": "The endpoint and key are environment variables deepseek-acp reads at launch. Model and reasoning effort are per-session selectors — pick them in the composer.", + "baseUrlLabel": "API endpoint", + "baseUrlHint": "Leave empty for the official endpoint. Applies to sessions started after the save — reconnect a running session to pick it up.", + "baseUrlInvalid": "Enter a full http(s) URL with no query string, for example https://api.deepseek.com", + "apiKeyLabel": "API key", + "apiKeyHint": "Passed to the agent as DEEPSEEK_API_KEY. An environment variable outranks the credentials file, so leave this empty if you sign in through the terminal." + }, + "codex": { + "configDescription": "Supports quick configuration for API URL, API Key, model name and reasoning effort, and syncs with `auth.json` / `config.toml`.", + "authMode": "Auth Mode", + "chatgptSubscription": "Official Subscription", + "chatgptSubscriptionHint": "Log in with ChatGPT official subscription, no API Key required", + "apiKeyHint": "Connect using API Key to OpenAI or compatible API services", + "selectProvider": "Select Provider", + "modelName": "Model Name", + "selectReasoningEffort": "Select Reasoning Effort", + "enableWebsocket": "Enable WebSocket", + "enableWebsocketAria": "Enable WebSocket for Codex Provider", + "enableSkills": "Enable Skills", + "enableSkillsAria": "Enable Skills for Codex", + "enableFast": "Enable Fast", + "enableFastAria": "Enable Fast service tier for Codex", + "sandboxGroupTitle": "Sandbox & approvals", + "sandboxGroupHint": "Written to the global ~/.codex/config.toml, so codex CLI and IDE sessions see it too. These are thread defaults: they govern the turns codex starts on its own (/goal, /review, /compact). Ordinary prompts use the composer's approval preset instead. Restart a session to pick up changes.", + "sandboxShadowedWarning": "config.toml sets default_permissions, so codex resolves permissions through that profile and ignores sandbox_mode entirely. Remove default_permissions to use the controls below.", + "sandboxPermissionsTableWarning": "config.toml defines [permissions] profiles but no default_permissions, which makes codex refuse to start. Set one in the raw editor below.", + "approvalPolicyLabel": "Approval policy", + "approvalPolicyUnset": "Not set (codex default: on request)", + "approvalPolicy_on-request": "On request — the model decides when to ask", + "approvalPolicy_untrusted": "Untrusted — only known-safe read-only commands run unattended", + "approvalPolicy_never": "Never — no approval prompts at all", + "approvalPolicy_granular": "Granular — choose per prompt type", + "approvalPolicyUntrustedAcpWarning": "Untrusted has no equivalent in the ACP adapter's three approval presets, so codeg sessions fall back to \"on request\" — the model then decides when to ask, and commands the sandbox already allows stop prompting. Tighten the sandbox mode below instead.", + "granularHint": "Off means requests of that kind are auto-rejected instead of shown to you.", + "granular_sandbox_approval": "Shell command escalations", + "granular_rules": "Execpolicy rule prompts", + "granular_skill_approval": "Skill script prompts", + "granular_request_permissions": "request_permissions tool prompts", + "granular_mcp_elicitations": "MCP elicitation prompts", + "sandboxModeLabel": "Sandbox mode", + "sandboxModeUnset": "Not set (trusted folders fall back to workspace write)", + "sandboxMode_read-only": "Read-only", + "sandboxMode_workspace-write": "Workspace write", + "sandboxMode_danger-full-access": "Full access (no sandbox)", + "sandboxModeHint": "On Windows, workspace write is downgraded to read-only unless codex's experimental Windows sandbox is enabled.", + "sandboxModeSeedsPresetHint": "codeg also maps this onto the session's starting approval preset, so unlike approval policy it does reach ordinary prompts. The composer's preset still overrides it.", + "writableRootsLabel": "Extra writable folders", + "writableRootsHint": "One absolute path per line, in addition to the working directory.", + "sandboxRootsRelativeError": "Must be an absolute path — codex resolves relative entries against ~/.codex: {path}", + "networkAccessLabel": "Allow network access", + "excludeTmpdirLabel": "Exclude TMPDIR from writable roots", + "excludeSlashTmpLabel": "Exclude /tmp from writable roots", + "authJsonNative": "auth.json (native)", + "configTomlNative": "config.toml (native)", + "loginButton": "Log in with ChatGPT", + "loginRequesting": "Requesting login code...", + "loginStep1": "Open the following URL in your browser:", + "loginStep2": "Enter the code below:", + "loginPolling": "Waiting for authorization...", + "loginCancel": "Cancel", + "loginSuccess": "Logged in successfully, config saved!", + "loginFailed": "Login failed: {message}", + "loginRetry": "Retry", + "loginCodeCopied": "Code copied", + "loggedIn": "Account logged in", + "loginRelogin": "Re-login / Switch account", + "loginTimeout": "Login timed out, please try again", + "loginSaveFailed": "Login succeeded but failed to save config" + }, + "gemini": { + "authConfig": "Gemini Auth Config", + "authConfigDescription": "Aligned with Gemini CLI authentication docs, supporting custom endpoint, Google login, Gemini API Key and Vertex AI (ADC / service account / API Key).", + "authMode": "Auth Mode", + "selectAuthMode": "Select auth mode", + "viewAuthDoc": "View auth docs", + "mode": { + "custom": "Custom Endpoint", + "loginGoogle": "Google Login (OAuth)", + "vertexServiceAccount": "Vertex AI (Service Account)" + }, + "hint": { + "custom": "Fill API URL, API Key and Model, mapped to GOOGLE_GEMINI_BASE_URL / GEMINI_API_KEY / GEMINI_MODEL.", + "loginGoogle": "Run gemini in terminal and complete Google login first; API key is not required.", + "geminiApiKey": "Fill GEMINI_API_KEY when using Gemini API.", + "vertexAdc": "Use gcloud ADC; GOOGLE_CLOUD_PROJECT and GOOGLE_CLOUD_LOCATION are recommended.", + "vertexServiceAccount": "Set service account JSON path to GOOGLE_APPLICATION_CREDENTIALS.", + "vertexApiKey": "Fill GOOGLE_API_KEY when using Vertex AI API key." + } + }, + "openCode": { + "configManagement": "OpenCode Config Management", + "configDescription": "Aligned with OpenCode `provider` schema, supports multi-provider management and two-way sync with native JSON files.", + "providerManagement": "Provider Management", + "providerCount": "{count} providers", + "addProvider": "Add Provider", + "emptyProvider": "No custom providers yet. Click Add custom provider to create one.", + "providerEnabledState": "{providerId} enabled state", + "selectProviderNpm": "Select provider.npm", + "modelManagement": "Model Management", + "modelCount": "{count} models", + "modelDescription": "Aligned with OpenCode `provider.models`. Fast management currently supports `name` / `id`; other advanced fields are preserved and can be edited in native JSON below.", + "addModel": "Add model", + "emptyModel": "No model yet. Enter model id then click \"Add model\".", + "modelId": "Model ID", + "modelName": "Model Name", + "deleteModel": "Delete model {modelId}", + "nativeJsonConfig": "OpenCode Native JSON Config", + "mainModel": "Main Model", + "smallModel": "Small Model", + "noMatchingModels": "No matching models", + "connectProvider": "Connect Provider", + "connectedProviders": "Connected providers", + "noConnectedProviders": "No catalog providers connected yet.", + "advancedProviderConfig": "Custom providers", + "customProviderConfigHint": "OpenAI-compatible endpoints you define yourself — a provider block in opencode.json, with the API key in auth.json.", + "addCustomProvider": "Add custom provider", + "disconnect": "Disconnect", + "editConfig": "Edit", + "customBadge": "Custom", + "authKindApi": "API Key", + "authKindOauth": "OAuth", + "authKindNone": "No credential", + "connect": { + "title": "Connect a provider", + "description": "Choose a provider from the models.dev catalog. Credentials are saved to the OpenCode auth.json file.", + "pick": "Provider", + "search": "Search providers…", + "loading": "Loading catalog…", + "catalogLabel": "models.dev catalog", + "modelsAvailable": "{count} models available", + "getKey": "Get API key", + "oauthApiKeyNote": "This provider also supports browser sign-in via opencode auth login. Browser sign-in is coming soon — for now, paste an API key.", + "apiKey": "API Key", + "apiKeyHint": "Stored in auth.json, never in opencode.json.", + "baseUrlOptional": "Base URL override (optional)", + "providerId": "Provider ID", + "displayName": "Display name", + "modelsList": "Models (one per line)", + "modelsHint": "Model ids the endpoint accepts.", + "action": "Connect", + "editTitle": "Edit provider", + "editDescription": "Update this provider's API key or base URL.", + "saveAction": "Save" + }, + "customProvider": { + "title": "Add a custom provider", + "description": "Define an OpenAI-compatible endpoint. The API key is saved to auth.json; the provider block goes to opencode.json.", + "action": "Add provider", + "idInCatalog": "{providerId} is a known provider — connect it via Connect Provider instead." + }, + "refreshCatalog": "Refresh catalog", + "reasoningBadge": "reasoning", + "contextWindow": "Context window", + "permissions": { + "title": "Permissions", + "description": "Decide which actions run on their own, prompt you first, or are blocked. Written to the permission block of opencode.json and applied once you save below.", + "docsLink": "Permissions docs", + "unparsableConfig": "The native JSON below is not valid, so the visual editor is paused. Fix the JSON to resume.", + "invalidBlock": "The permission block has a shape codeg does not recognize. Edit it in the native JSON below, or use Reset to start over.", + "orderingUnsafe": "A wildcard rule is written after specific tools, so OpenCode applies it to them as well — the rows below are not what is in force. Fix order moves every wildcard back to the front of its scope without changing a single value.", + "orderingUnsafeManual": "One rule is shadowed by a later, more general pattern, so OpenCode never applies it — the rows below are not what is in force. Two overlapping patterns have no single right order; reorder them in the native JSON so the general one comes first.", + "fixOrder": "Fix order", + "agentOverrides": "These agents override permissions and are applied last, so they win over everything here: {agents}. Edit them in the native JSON below, or turn on auto-accept to clear them.", + "legacyTools": "The legacy top-level tools map denies a tool. OpenCode folds it into the permissions, so it applies on top of everything shown here. Edit it in the native JSON below, or turn on auto-accept to clear it.", + "autoAcceptTitle": "Auto-accept every permission", + "autoAcceptHint": "Every tool call — shell commands, file edits, paths outside the project — runs without asking. Turning this on replaces the per-tool settings below with a single allow-all rule, and clears the per-agent permission overrides and legacy tool toggles that would otherwise still block.", + "globalLabel": "Global default", + "globalHint": "The * rule: what applies to anything the tools below do not override.", + "actionUnset": "Unset (OpenCode defaults)", + "actionInherit": "Inherit ({action})", + "actionAllow": "Allow", + "actionAsk": "Ask", + "actionDeny": "Deny", + "perToolTitle": "Per-tool permissions", + "reset": "Reset", + "ruleCount": "rules: {count}", + "rulesToggle": "Fine-grained rules for {tool}", + "rulesHint": "Matched against the tool input, last match wins — so put the broad patterns first. * matches any characters, ? matches exactly one, and a leading ~ expands to your home directory.", + "noRules": "No fine-grained rules yet.", + "addRule": "Add rule", + "deleteRule": "Delete rule {pattern}", + "duplicateRule": "That pattern already exists.", + "blankRule": "A rule needs a pattern — use the trash icon to remove it.", + "customKeys": "Other permission keys in the file", + "customKeyHint": "Not a built-in OpenCode tool — kept as written.", + "keys": { + "bash": "Run shell commands, matched by the parsed command", + "edit": "All file modifications: edit, write and patch", + "read": "Read files, matched by path", + "external_directory": "Reach paths outside the project working directory", + "task": "Launch subagents, matched by subagent type", + "skill": "Load skills, matched by skill name", + "glob": "Find files, matched by glob pattern", + "grep": "Search file contents, matched by pattern", + "list": "List directory contents", + "webfetch": "Fetch a URL", + "websearch": "Search the web", + "lsp": "Run LSP queries", + "todowrite": "Write the todo list", + "question": "Ask you a question", + "doom_loop": "Trips when the same call repeats three times with identical input" + } + } + }, + "openClaw": { + "gatewayConfig": "Gateway Config", + "gatewayDescription": "Configure OpenClaw Gateway connection. Supports local or remote gateway.", + "gatewayUrlHint": "Leave empty to use gateway.remote.url from local openclaw config.", + "gatewayTokenPlaceholder": "Gateway auth token", + "gatewayTokenHint": "Use token-file instead of plain token when possible; configure via openclaw CLI.", + "sessionKeyHint": "Optional. Specify gateway session key; leave empty to auto-assign isolated session." + }, + "hermes": { + "configManagement": "Hermes Configuration", + "configDescription": "Hermes manages its own credentials in ~/.hermes/.env and settings in ~/.hermes/config.yaml. Pick a provider, then set the API key and model — codeg writes both files for you.", + "providerLabel": "Provider", + "providerHint": "The provider selects which API key variable and model.provider Hermes uses. OAuth providers are configured through the terminal setup below.", + "groupApiKey": "API key providers", + "groupOauth": "OAuth providers", + "groupAws": "AWS", + "apiKeyHint": "Saved to ~/.hermes/.env. It is never injected into the process — Hermes reads it from its own config.", + "modelName": "Model", + "oauthHint": "This provider uses OAuth. Run the setup below to authenticate in your terminal.", + "awsHint": "Bedrock uses your AWS credentials (environment or shared config). Set the model id above and configure AWS access in your environment.", + "unsupportedProvider": "This provider isn't editable with structured fields. Use the raw config.yaml editor below or the terminal setup.", + "setupTitle": "Self-managed setup", + "setupHint": "Hermes's interactive setup needs a terminal. Launch it below, or copy the command to run it yourself.", + "runSetup": "Run Hermes setup", + "configureModel": "Configure model", + "openConfigFolder": "Open ~/.hermes", + "copyCommand": "Copy command", + "commandCopied": "Command copied to clipboard", + "advancedTitle": "Advanced: edit config.yaml", + "rawConfigHint": "Edit ~/.hermes/config.yaml directly. Saving here overwrites the file verbatim.", + "saveRawConfig": "Save config.yaml" + }, + "codebuddy": { + "configManagement": "CodeBuddy Configuration", + "configDescription": "CodeBuddy authenticates with an API key. Mainland China builds also require the environment set to “China (internal)”; iOA builds use “iOA”. The overseas build leaves it unset.", + "apiKeyLabel": "API Key", + "apiKeyHint": "Saved as CODEBUDDY_API_KEY for this agent. Alternatively, sign in with the CodeBuddy CLI in a terminal.", + "apiKeyHintSelfHosted": "Saved as CODEBUDDY_API_KEY for this agent. Use the key issued by your private deployment.", + "environmentLabel": "Environment", + "environmentHint": "Sets CODEBUDDY_INTERNET_ENVIRONMENT. Mainland China must use “China (internal)”; the overseas build leaves it unset.", + "envOverseas": "Overseas (default)", + "envChina": "China (internal)", + "envIoa": "iOA", + "envSelfHosted": "Self-hosted (private deployment)", + "baseUrlLabel": "Deployment URL", + "baseUrlPlaceholder": "https://codebuddy.your-company.com", + "baseUrlHint": "Saved as CODEBUDDY_BASE_URL and points CodeBuddy at your private endpoint. The region setting is left unset for self-hosted deployments.", + "baseUrlInvalid": "Enter a valid http(s) URL.", + "loginHint": "No API key? Run “codebuddy” in a terminal to sign in with your Tencent account instead." + }, + "kimiCode": { + "configManagement": "Kimi Code Configuration", + "configDescription": "`kimi acp` only accepts a stored login token, so codeg writes a managed provider into ~/.kimi-code/config.toml and seeds a local gate token — inference still runs on your own key.", + "statusUnconfigured": "Not configured yet", + "statusDirty": "Unsaved changes", + "summaryLabel": "In effect", + "gateReadyApiKey": "API key written to config.toml", + "gateReadyLogin": "Signed in with a Kimi account", + "revealConfig": "Show in folder", + "envOverrideWarning": "{keys} is set and takes priority over config.toml. Saving here clears it.", + "authModeLabel": "Authentication method", + "authModeApiKey": "API key", + "authModeLogin": "Kimi account login (subscription)", + "authModeApiKeyHint": "Writes a codeg-managed provider into config.toml and seeds the gate token so sessions can open.", + "loginHint": "Run `kimi login` in a terminal to sign in with a Kimi subscription account. codeg stores nothing and reuses Kimi's own login. Saving here removes codeg's API-key gate token.", + "credentialTitle": "Credential", + "interfaceTypeLabel": "Provider type", + "interfaceTypeHint": "The provider protocol Kimi speaks (config.toml `type`). Use Kimi / Moonshot for a Moonshot / platform.kimi.com key.", + "endpointLabel": "Endpoint", + "endpointCustom": "Custom (OpenAI-compatible)", + "endpointHint": "International = api.moonshot.ai; China (platform.kimi.com keys) = api.moonshot.cn. Custom points at any OpenAI-compatible endpoint.", + "regionInternational": "International (api.moonshot.ai)", + "regionChina": "China (api.moonshot.cn)", + "baseUrlLabel": "Base URL", + "baseUrlHint": "Leave blank to use the provider SDK default.", + "apiKeyLabel": "API Key", + "apiKeyHint": "Written to ~/.kimi-code/config.toml and used for inference. From platform.kimi.com or platform.kimi.ai.", + "vertexProjectLabel": "GCP project (GOOGLE_CLOUD_PROJECT)", + "vertexLocationLabel": "GCP location (GOOGLE_CLOUD_LOCATION)", + "vertexHint": "Vertex AI uses Google Application Default Credentials — run `gcloud auth application-default login` (no API key).", + "modelTitle": "Model", + "modelLabel": "Model", + "modelHint": "The model id written to config.toml. Use “Test & list models” to see what your key can actually access.", + "maxContextLabel": "Max context size", + "maxContextHint": "Required by Kimi's schema: without it Kimi discards the whole model block and every prompt comes back empty. Defaults to 262144.", + "fetchModels": "Test & list models", + "fetchModelsOk": "Key works — {count} models available", + "fetchModelsEmpty": "Key works, but no models were returned", + "fetchModelsFailed": "Test failed", + "fetchModelsNeedsKey": "Enter an API key and endpoint first", + "modelNotInList": "This model is not in the list your key can access — Kimi will fail with “model not found”.", + "reasoningTitle": "Reasoning", + "reasoningEnableLabel": "Enable", + "reasoningDescription": "Kimi only shows a Thinking picker in the composer when the model declares a reasoning capability, so codeg writes one here. Takes effect on new sessions.", + "effortsLabel": "Levels offered", + "effortsHint": "These become the rows of the composer's Thinking picker. Kimi forwards the level to the provider verbatim, so pick ones your model accepts.", + "effortsEmptyHint": "With no levels chosen the composer falls back to a plain Off / On toggle.", + "effortsCustomPlaceholder": "Add another level", + "effortsAdd": "Add", + "defaultEffortLabel": "Default level", + "defaultEffortAuto": "Let Kimi choose", + "alwaysThinkingLabel": "The model always reasons — remove the Off row from the picker", + "fixErrorsFirst": "Fix the highlighted fields first", + "errorModelRequired": "Model is required", + "errorMaxContextRequired": "Max context size is required", + "errorMaxContextInvalid": "Must be a positive integer", + "errorApiKeyRequired": "API key is required", + "errorApiKeyInvalid": "The API key must not contain line breaks", + "errorBaseUrlRequired": "Base URL is required", + "errorBaseUrlInvalid": "Must start with http:// or https://", + "errorVertexProjectRequired": "GCP project is required", + "errorDefaultEffortUnlisted": "Pick one of the levels selected above", + "advancedTitle": "Advanced", + "authTypeLabel": "Credential placement", + "authTypeApiKey": "Inline api_key", + "authTypeEnv": "Provider env sub-table", + "authTypeHint": "Where the API key is written inside config.toml.", + "rawEditorLabel": "Edit config.toml directly", + "rawEditorWarning": "Saving here overwrites the entire file verbatim, replacing the structured settings above.", + "rawEditorPlaceholder": "[providers.codeg]\ntype = \"kimi\"\nbase_url = \"https://api.moonshot.cn/v1\"\napi_key = \"sk-...\"" + }, + "authModeOfficialSubscription": "Official Subscription", + "authModeCustomEndpoint": "Custom Endpoint", + "authModeCustomEndpointHint": "Manually configure API URL and API Key for a custom endpoint.", + "authModeModelProvider": "Model Provider", + "modelProvider": "Model Provider", + "modelProviderHint": "Use API URL, API Key, and model from a configured model provider.", + "selectModelProvider": "Select Model Provider", + "noModelProviderAvailable": "No model provider configured for this agent. Go to Model Provider Settings to add one.", + "claude": { + "authMode": "Auth Mode", + "officialSubscription": "Official Subscription", + "officialSubscriptionHint": "Use official Anthropic subscription, no API Key required.", + "mainModel": "Main Model", + "reasoningModel": "Reasoning Model (thinking)", + "haikuDefaultModel": "Default Haiku Model", + "sonnetDefaultModel": "Default Sonnet Model", + "opusDefaultModel": "Default Opus Model", + "customModelOption": "Custom Model ID", + "customModelOptionName": "Custom Model Name", + "customModelOptionDescription": "Custom Model Description", + "customModelOptionHint": "Adds a single custom entry to Claude's model picker (e.g. a model behind a custom gateway/proxy). Name and description are optional display overrides.", + "effortLevel": "Reasoning Effort Level", + "effortLevelDefault": "Default Level", + "effortLevel_low": "Low", + "effortLevel_medium": "Medium", + "effortLevel_high": "High", + "effortLevel_xhigh": "Extra High", + "sendAttributionHeader": "Send attribution/billing identifier to the API", + "sendAttributionHeaderAria": "Send Claude Code attribution/billing identifier to the API", + "disableNonessentialTraffic": "Disable telemetry or redundant network requests", + "disableNonessentialTrafficAria": "Disable Claude Code telemetry or redundant network requests" + }, + "dialogs": { + "confirmDeleteProvider": "Delete Provider {providerId}?", + "confirmDeleteProviderDescription": "OpenCode config and auth JSON will be updated together. This action cannot be undone.", + "confirmUninstall": "Uninstall {name}?", + "confirmUninstallDescription": "This removes local installed version. You can reinstall later.", + "customInstallTitle": "Custom install {name}", + "customInstallDescription": "Enter the version to install. This reinstalls and replaces the currently installed version.", + "customInstallVersionLabel": "Version number", + "customInstallInvalid": "Enter a valid version number, e.g. 1.2.3.", + "customInstallSubmit": "Install" + }, + "errors": { + "windowsFileLocked": "{name}'s files are in use by a running session, so Windows can't replace them. Close all {name} sessions and try again.", + "nativeJsonMustBeObject": "Native JSON config must be an object", + "nativeJsonInvalid": "Native JSON config format error: {message}", + "openCodeAuthMustBeObject": "OpenCode auth.json must be a JSON object", + "openCodeAuthInvalid": "OpenCode auth.json format error: {message}", + "authMustBeObject": "auth.json must be a JSON object", + "authInvalid": "auth.json format error: {message}", + "providerIdPattern": "Provider ID only supports letters, numbers, underscore, dot and hyphen", + "providerExists": "Provider {providerId} already exists", + "modelIdPattern": "Model ID only supports letters, numbers, underscore, dot, colon and hyphen", + "modelExists": "Model {modelId} already exists" + }, + "warnings": { + "nativeJsonRecoveredStructured": "Native JSON config is invalid; reset to structured config", + "nativeJsonRecoveredOpenCode": "Native JSON config is invalid; reset to OpenCode structured config", + "openCodeAuthRecovered": "OpenCode auth.json is invalid; reset to default config", + "authRecoveredStructured": "auth.json is invalid; reset to structured config" + }, + "toasts": { + "agentActionCompleted": "{name} {action} completed", + "agentActionFailed": "{name} {action} failed", + "localVersion": "Local version: {version}", + "installCompletedVersionLater": "Install completed, version will update on next check", + "uninstallCompleted": "{name} uninstall completed", + "uninstallFailed": "{name} uninstall failed", + "localVersionRemoved": "Local version removed", + "saveAgentOrderFailed": "Failed to save Agent order", + "saveAgentSwitchFailed": "Failed to save Agent switch", + "saveEnvFailed": "Failed to save environment variables", + "grokSaved": "Grok config saved", + "saveGrokNativeFailed": "Failed to save Grok native config", + "saveGrokApiKeyFailed": "Settings saved, but the API key couldn't be saved", + "cursorSaved": "Cursor config saved", + "saveCursorConfigFailed": "Failed to save Cursor config", + "codexSaved": "Codex config saved", + "saveCodexNativeFailed": "Failed to save Codex native config", + "geminiSaved": "Gemini config saved", + "saveGeminiFailed": "Failed to save Gemini config", + "providerDeleted": "Provider {providerId} deleted", + "providerDeleteFailed": "Failed to delete Provider {providerId}", + "providerSaved": "Provider {providerId} saved", + "saveProviderFailed": "Failed to save Provider {providerId}", + "openCodeConfigSynced": "OpenCode config and auth JSON have been synced.", + "openCodeSaved": "OpenCode config saved", + "saveOpenCodeFailed": "Failed to save OpenCode config", + "openClawSaved": "OpenClaw config saved", + "saveOpenClawFailed": "Failed to save OpenClaw config", + "configSaved": "Config saved", + "configSavedHint": "Existing sessions need to be reopened to take effect", + "saveConfigManagementFailed": "Failed to save config management", + "clineSaved": "Cline config saved", + "saveClineFailed": "Failed to save Cline config", + "hermesSaved": "Hermes config saved", + "saveHermesFailed": "Failed to save Hermes config", + "codeBuddySaved": "CodeBuddy config saved", + "saveCodeBuddyFailed": "Failed to save CodeBuddy config", + "kimiCodeSaved": "Kimi Code config saved", + "saveKimiCodeFailed": "Failed to save Kimi Code config", + "deepseekSaved": "DeepSeek config saved", + "saveDeepSeekFailed": "Failed to save DeepSeek config", + "modelProviderRequired": "Please select a model provider before saving.", + "affectedRunningSessions": "{count, plural, one {# running session needs to reconnect to apply the change} other {# running sessions need to reconnect to apply the change}}", + "providerConnected": "Connected {providerId}", + "connectFailed": "Failed to connect {providerId}", + "providerDisconnected": "Disconnected {providerId}", + "disconnectFailed": "Failed to disconnect {providerId}", + "catalogRefreshed": "Catalog refreshed — {count} providers", + "catalogRefreshFailed": "Failed to refresh catalog", + "piSaved": "Pi config saved", + "savePiFailed": "Failed to save Pi config", + "piRuntimeSaved": "Pi runtime saved", + "savePiRuntimeFailed": "Failed to save Pi runtime", + "piBinaryInstalled": "pi installed", + "piBinaryInstallFailed": "Failed to install pi", + "piBinaryUninstalled": "pi uninstalled", + "piBinaryUninstallFailed": "Failed to uninstall pi", + "savePiTrustFailed": "Failed to save workspace trust" + }, + "version": { + "statusLabel": "Version Status", + "notInstalled": "Not installed", + "remoteLocal": "Remote: {remoteVersion} · Local: {localVersion}", + "localOnly": "Local: {localVersion}", + "localInstalled": "{versionText}. Installed.", + "platformUnsupported": "{versionText}. Current platform does not support this agent.", + "uvxNotReady": "{versionText}. The uv runtime isn't installed — install it from the uv check below to use this agent.", + "clickInstall": "{versionText}. Click Install on the right.", + "localUnrecognized": "{versionText}. Local version is not comparable; try upgrade to overwrite install.", + "upgradeAvailable": "{versionText}. Upgrade available.", + "remoteUnavailable": "{versionText}. Remote version is currently unavailable.", + "latest": "{versionText}. Already latest." + }, + "adapter": { + "label": "ACP adapter", + "badge": "ACP adapter", + "badgeHint": "For this agent Codeg installs an ACP adapter package, not the vendor CLI. The two are independent and share the same config.", + "learnMore": "Learn more", + "missingWithNative": "Found your own {nativeLabel} at {nativePath}. Codeg drives agents over ACP and that CLI does not speak ACP, so Codeg needs a separate adapter package, {adapterPackage}, maintained by the Agent Client Protocol project (originally Zed). It ships its own runtime, never modifies or replaces your {nativeCmd} command, and reads the same {configDir} — your existing sign-in and settings carry over. Install it below.", + "missing": "Codeg drives agents over ACP and the {nativeLabel} does not speak ACP, so Codeg needs a separate adapter package, {adapterPackage}, maintained by the Agent Client Protocol project (originally Zed). It ships its own runtime, so the {nativeCmd} CLI is not required first; if you do have it, the two coexist and share the same {configDir} sign-in and settings. Install it below.", + "readyWithNative": "Adapter {adapterCmd} is installed — that is what Codeg launches, not your own {nativeCmd} at {nativePath}. They are separate packages that coexist, and both read {configDir}, so sign-in and settings are shared.", + "ready": "Adapter {adapterCmd} is installed — that is what Codeg launches. It ships its own runtime, so the {nativeLabel} is not required; install it later and the two coexist, sharing {configDir}." + }, + "cline": { + "configDescription": "Configure Cline API provider and credentials. Settings are saved to ~/.cline/data/." + }, + "opencodePlugins": { + "title": "OpenCode Plugins", + "declared": "Declared Plugins", + "noPlugins": "No plugins declared.", + "status": { + "installed": "Installed", + "missing": "Missing" + }, + "installAll": "Install All Missing", + "pinVersions": "Pin @latest Versions", + "install": "Install", + "uninstall": "Uninstall", + "refresh": "Refresh", + "success": "All plugins installed successfully.", + "failed": "Installation failed" + }, + "pi": { + "configManagement": "Pi Configuration", + "configDescription": "Pi authenticates with your model provider's API key. The key is written to ~/.pi/agent/auth.json and the model selection to settings.json.", + "providerLabel": "Provider", + "modelLabel": "Model", + "thinkingLabel": "Thinking", + "thinking": { + "off": "Off", + "low": "Low", + "medium": "Medium", + "high": "High", + "minimal": "Minimal", + "xhigh": "Extra high" + }, + "apiKeyLabel": "API Key", + "apiKeyHint": "Stored in ~/.pi/agent/auth.json for the selected provider.", + "apiKeySetPlaceholder": "•••••• (saved — leave blank to keep)", + "saveConfig": "Save Pi Config", + "providerModelRequired": "Provider and model are required", + "runtimeTitle": "Runtime", + "runtimeDescription": "Choose which pi binary runs. Use the default, or point at your own pi build.", + "modeDefault": "Default pi", + "modeDefaultHint": "Use the bundled pi-acp adapter with the pi on your PATH. Install pi with: npm install -g @earendil-works/pi-coding-agent", + "modeCustom": "Custom pi", + "modeCustomHint": "Run your own pi build, install, or wrapper.", + "commandLabel": "pi command or path", + "commandHint": "An absolute path, a command name on PATH, or a wrapper script (e.g. a monorepo ./pi-test.sh).", + "commandNotFound": "Command not found", + "validate": "Validate", + "advanced": "Advanced", + "configDirLabel": "Config directory (PI_CODING_AGENT_DIR)", + "sessionDirLabel": "Sessions directory (PI_CODING_AGENT_SESSION_DIR)", + "flagsHint": "Custom pi flags (--approve, -e, …) aren't forwarded by pi-acp — wrap pi in a script and point the command at it.", + "customIncomplete": "Enter a pi command to save", + "saveRuntime": "Save Runtime", + "providerPlaceholder": "Select a provider", + "customProvider": "Custom provider…", + "providerIdLabel": "Provider ID", + "apiProtocolLabel": "API protocol", + "baseUrlLabel": "API endpoint (Base URL)", + "customProviderHint": "Defines a provider in ~/.pi/agent/models.json at your endpoint. Most self-hosted or proxy servers use openai-completions.", + "baseUrlRequired": "API endpoint (Base URL) is required", + "binaryTitle": "pi binary (pi-coding-agent)", + "binaryDescription": "pi-acp runs this pi binary. Install it here, or point pi-acp at your own build below.", + "binaryInstalled": "Installed", + "binaryMissing": "Not installed", + "binaryChecking": "Checking…", + "installBinary": "Install pi", + "installing": "Installing…", + "recheck": "Recheck", + "configDirSkillsNote": "With a custom config directory, the Skills, Experts, and Office tools managed in Settings won't apply to this pi — manage its skills in that folder directly.", + "projectTrustTitle": "Project trust", + "projectTrustDescription": "Folders you allowed pi to load project files from. A trusted folder lets that repository's .pi/extensions run code when pi starts, applies to every folder inside it, and is also used when you run pi in a terminal.", + "projectTrustLoading": "Loading…", + "projectTrustEmpty": "No folders decided yet.", + "projectTrustTrusted": "Trusted", + "projectTrustDenied": "Not trusted", + "projectTrustRevoke": "Revoke", + "reasoningTitle": "Reasoning", + "reasoningEnableLabel": "Enable", + "reasoningDescription": "pi only sends a reasoning effort for a model that declares it — an undeclared model has every level clamped to Off, so the composer's picker springs back the moment you touch it. Written to this model's entry in models.json.", + "levelsLabel": "Available levels", + "levelsHint": "These become the rows in the composer's reasoning picker. Pick the ones your endpoint accepts; pi rejects any level that isn't listed here.", + "levelsEmptyError": "Pick at least one level — with none, pi falls back to Off.", + "wireValuesTitle": "Advanced: values sent to the provider", + "wireValuesHint": "Leave blank to send the level name as-is. Set one when your endpoint expects something else — Google-style backends want LOW / HIGH.", + "defaultLevelUnlisted": "This level isn't in the available list above — pi would clamp it." + }, + "addCustomAgent": "Add custom agent", + "addCustomAgentHint": "Register any ACP-compatible agent. Pick one from the public ACP registry, or paste its registry information.", + "customAgentFromRegistry": "ACP registry", + "customAgentManual": "Manual", + "customAgentSearchPlaceholder": "Search agents…", + "customAgentLoadingCatalog": "Loading the ACP registry…", + "customAgentRetry": "Retry", + "customAgentNoResults": "No matching agents", + "customAgentAdd": "Add", + "customAgentAlreadyAdded": "Added", + "customAgentUnsupportedPlatform": "No build available for this platform", + "customAgentAdded": "Added {name}", + "customAgentIdLabel": "Registry ID", + "customAgentNameLabel": "Display name", + "customAgentVersionLabel": "Version", + "customAgentSpecLabel": "Distribution (JSON)", + "customAgentSpecHint": "Same shape as a registry entry's distribution object: npx, uvx and binary channels, or paste a whole registry entry. For npx/uvx, cmd is the executable the package installs — derived from the package name when omitted, so set it when the two differ. binary is keyed by platform (this machine: {platform}); its cmd is the launch path inside the archive, and sha256 optionally verifies the download.", + "customAgentTemplateLabel": "Templates", + "customAgentKindLabel": "Launch via", + "customAgentInvalidJson": "Not valid JSON", + "customAgentNoDistribution": "No npx, uvx, or binary distribution found", + "customAgentCancel": "Cancel", + "customAgentSave": "Add agent", + "customAgentSaveChanges": "Save changes", + "customAgentEdit": "Edit agent", + "customAgentEditHint": "Update the name, icon, distribution and skills declarations. The agent ID cannot be changed.", + "customAgentEditNotFound": "Custom agent {id} was not found", + "customAgentSaved": "Saved {name}", + "customAgentVersionProbeLabel": "Version probe command (optional)", + "customAgentVersionProbeHint": "Command that prints the locally installed version. Left empty, codeg runs the agent command with --version.", + "customAgentRemove": "Remove agent", + "customAgentRemoveHint": "Deletes the agent definition. Existing conversations keep their history; the agent just can no longer be launched.", + "customAgentIconLabel": "Icon (optional)", + "customAgentIconUpload": "Upload", + "customAgentIconReplace": "Replace", + "customAgentIconClear": "Remove icon", + "customAgentIconHint": "Stored with the agent, so it works offline. Without one, a colored initial is used.", + "customAgentSkillsLabel": "Skills (shared .agents/skills)", + "customAgentSkillsHint": "Declares that this agent reads the shared .agents/skills store — its global and project directories — and adds it to every skills matrix. Skills linked there are visible to every agent that reads the shared store.", + "customAgentSkillsDirLabel": "Dedicated skills directory", + "customAgentSkillsDirHint": "Absolute path of a directory this agent loads skills from — its own store, in addition to (or instead of) the shared one. ~ expands to your home directory; linked skills are placed here first.", + "customAgentMcpLabel": "MCP support", + "customAgentMcpHint": "Sends codeg's built-in MCP companion to this agent when a session starts — the channel behind delegation, live feedback and task tools. Turn it off for an agent that rejects MCP servers and fails to connect; the change applies to the next connection.", + "customAgentIconNotAnImage": "Pick an image file.", + "customAgentIconTooLarge": "The icon must be smaller than {limit} KB.", + "customAgentIconReadFailed": "Could not read that image.", + "customAgentRemoveConfirm": "Remove {name}? Existing conversations stay, but the agent can no longer be launched.", + "customAgentRemoveWithData": "Also delete its recorded conversation history", + "customAgentRemoved": "Removed {name}", + "customAgentBadge": "Custom", + "customAgentNotLaunchable": "This agent cannot launch here: {reason}" + }, + "SettingsPages": { + "agentsLoading": "Loading agent settings...", + "skillPacksLoading": "Loading skill packs…" + }, + "GeneralSettings": { + "loading": "Loading...", + "sectionTitle": "General", + "sectionDescription": "Centralized preferences for the default terminal, rendering acceleration, and multi-agent delegation.", + "terminalTitle": "Default Terminal", + "terminalDescription": "Choose the shell used when opening new terminal tabs from the terminal bar or file tree. Agents also use it when they ask codeg to run a whole command line for them.", + "terminalSystemDefault": "System default", + "terminalPowerShell7": "PowerShell 7 (pwsh)", + "terminalWindowsPowerShell": "Windows PowerShell", + "terminalCmd": "Command Prompt (cmd)", + "terminalSaveFailed": "Failed to save terminal settings: {message}", + "terminalShellCustom": "Custom path", + "terminalShellCustomPath": "Shell path", + "terminalShellCustomPlaceholder": "/usr/local/bin/fish", + "terminalShellCustomSave": "Save", + "terminalShellCustomHint": "Provide an absolute path or a name resolvable on PATH.", + "terminalShellNotInstalled": "not installed", + "terminalShellNotFoundWarning": "This path doesn't exist on this host.", + "terminalCurrentShell": "Currently using: {path}", + "renderingDescription": "Disable hardware acceleration if the app shows a black screen or rendering glitches (common on certain AMD GPUs or Intel integrated GPUs). Only takes effect on the Windows desktop build.", + "disableHardwareAcceleration": "Disable hardware acceleration", + "renderingSaveFailed": "Failed to save rendering settings: {message}", + "restartRequired": "Saved. Restart the app for the change to take effect.", + "restartNow": "Restart now", + "restartFailed": "Failed to restart: {message}", + "loadFailed": "Load failed: {message}" + }, + "LoginPage": { + "documentTitle": "Login - codeg", + "brand": "Codeg", + "subtitle": "Enter your access token to connect to the desktop app", + "tokenPlaceholder": "Access Token", + "connect": "Connect", + "connecting": "Connecting...", + "helpText": "Find your token in the desktop app under Settings → Web Service", + "invalidToken": "Invalid token. Please check and try again.", + "connectionFailed": "Connection failed (HTTP {status})", + "networkError": "Unable to connect to the server" + }, + "CommitPage": { + "title": "Commit", + "invalidFolderId": "Invalid folder ID", + "loadingRepo": "Loading repository..." + }, + "MergePage": { + "title": "Resolve Conflicts", + "invalidFolderId": "Invalid folder ID", + "loadingRepo": "Loading repository...", + "localVersion": "Local (Ours)", + "result": "Result", + "remoteVersion": "Remote (Theirs)", + "acceptLocal": "Accept Local", + "acceptRemote": "Accept Remote", + "markResolved": "Mark Resolved", + "abortMerge": "Abort", + "completeMerge": "Complete Merge", + "unresolvedConflicts": "There are still unresolved conflict markers in this file", + "fileResolved": "File resolved successfully", + "allResolved": "All conflicts resolved", + "conflictFiles": "Conflict Files", + "loadingFile": "Loading file...", + "preparingMerge": "Preparing merge...", + "selectFile": "Select a file to resolve", + "noConflicts": "No conflict files", + "skipFile": "Skip", + "abortSuccess": "Operation aborted", + "applyAllNonConflicting": "Apply All Non-Conflicting", + "applyLeftNonConflicting": "Apply Local", + "applyRightNonConflicting": "Apply Remote" + }, + "ImportSessions": { + "title": "Import Local Sessions", + "scanningTitle": "Scanning local agent sessions…", + "scanningHint": "Walking each agent's local session store. Large histories can take a moment. Sessions you already imported are refreshed along the way.", + "scanFailed": "Scan failed", + "retry": "Retry", + "rescan": "Rescan", + "empty": "No local sessions found", + "emptyHint": "No agent session stores were found on this machine.", + "noMatches": "No sessions match the current filters", + "searchPlaceholder": "Search title or path…", + "allAgents": "All agents", + "onlyImportable": "Importable only", + "selectAll": "Select all", + "clearSelection": "Clear", + "expandAll": "Expand all", + "collapseAll": "Collapse all", + "summaryCounts": "{total} sessions · {importable} importable · {folders} folders", + "noFolderSkipped": "{count} without a project folder skipped", + "folderNew": "New", + "folderCounts": "{importable}/{total} importable", + "toggleFolderAria": "Select all importable sessions in {name}", + "toggleSessionAria": "Select session {title}", + "statusImported": "Imported", + "statusDeleted": "Deleted", + "untitled": "Untitled session", + "messageCount": "{count} msgs", + "selectedCount": "{count} selected", + "importSelected": "Import selected", + "importing": "Importing…", + "close": "Close", + "doneTitle": "Import finished", + "doneImported": "Imported", + "doneUpdated": "Refreshed", + "doneSkipped": "Skipped", + "doneCreatedFolders": "Folders created", + "doneNotFound": "Not found", + "doneFailed": "Failed", + "continueImport": "Continue importing", + "toasts": { + "importFailed": "Import failed: {message}" + } + }, + "Folder": { + "workspaceStatus": { + "degradedTitle": "Live updates unavailable", + "degradedHint": "Watcher failed to start (e.g. permission denied). Refresh manually to see changes.", + "retry": "Retry", + "retrying": "Retrying..." + }, + "common": { + "all": "All", + "cancel": "Cancel", + "close": "Close", + "closeOthers": "Close Others", + "closeAll": "Close All", + "confirm": "Confirm", + "save": "Save", + "delete": "Delete", + "rename": "Rename", + "loading": "Loading...", + "refresh": "Refresh", + "refreshing": "Refreshing...", + "create": "Create", + "createAndSwitch": "Create and Switch", + "openFile": "Open File", + "viewDiff": "View Diff", + "push": "Push..." + }, + "statusLabels": { + "in_progress": "In Progress", + "pending_review": "Review", + "completed": "Completed", + "cancelled": "Cancelled" + }, + "sidebar": { + "title": "Conversations", + "locateActiveConversation": "Locate Active Conversation", + "expandAllGroups": "Expand All Groups", + "collapseAllGroups": "Collapse All Groups", + "newConversation": "New Conversation", + "newConversationShort": "New", + "newChat": "New chat", + "search": "Search", + "noConversationsFound": "No conversations found.", + "importLocalSessions": "Import local sessions", + "importing": "Importing...", + "error": "Error: {message}", + "completeAllSessions": "Complete all sessions", + "completeAllReviewTitle": "Complete all review sessions?", + "completeAllReviewDescription": "This will mark all {count, plural, one {# session} other {# sessions}} in Review as completed.", + "completing": "Completing...", + "toasts": { + "importedSessions": "Imported {imported, plural, one {# session} other {# sessions}}, skipped {skipped}", + "importedAndUpdated": "Imported {imported, plural, one {# session} other {# sessions}}, updated {updated, plural, one {# title} other {# titles}}, skipped {skipped}", + "updatedTitles": "Updated {updated, plural, one {# title} other {# titles}}, skipped {skipped}", + "noNewSessionsFound": "No new sessions found (skipped {skipped})", + "importFailed": "Import failed: {message}", + "reviewCompleted": "Marked {count, plural, one {# review session} other {# review sessions}} as completed", + "completeReviewFailed": "Failed to complete review sessions: {message}", + "folderOpened": "Opened folder {name}", + "folderRemoved": "Removed folder {name}", + "openFolderFailed": "Failed to open folder", + "removeFolderFailed": "Failed to remove folder: {message}", + "reorderFoldersFailed": "Failed to reorder folders: {message}", + "changeFolderColorFailed": "Failed to change folder color: {message}", + "setFolderAliasFailed": "Failed to set alias: {message}", + "changeFolderDefaultAgentFailed": "Failed to set default agent: {message}" + }, + "statsLabel": "{folders} folders · {convos} conversations", + "reorderHandle": "Drag to reorder", + "openFolder": "Open Folder", + "searchPlaceholder": "Search conversations...", + "viewOptions": "View options", + "showCompleted": "Show completed conversations", + "showWorktrees": "Show worktree folders", + "showRecent": "Show Recent group", + "moreOptions": "More options", + "sortBy": "Sort by", + "sortByCreatedAt": "Created time", + "sortByUpdatedAt": "Updated time", + "sectionOrder": "Section order", + "sectionOrderMoveUp": "Move up", + "sectionOrderMoveDown": "Move down", + "sectionOrderItemLabel": "{name} — position {position} of {total}", + "statusRunningBadge": "Running", + "runningCountBadge": "{count, plural, one {# session running} other {# sessions running}}", + "statusCancelledBadge": "Cancelled", + "worktreeRemovedBadge": "Source worktree removed", + "conversationCountUnit": "{count, plural, one {# conversation} other {# conversations}}", + "emptyFolderHint": "No conversations", + "noMatchingConversations": "No matching conversations", + "noUnfinishedConversations": "No unfinished conversations. Enable \"Show completed\" from the top-right menu.", + "removeFolderConfirmTitle": "Remove folder from workspace?", + "removeFolderConfirmDescription": "Remove \"{name}\" from the workspace? Its tabs and terminals will close.", + "folderHeaderMenu": { + "manageConversations": "Manage conversations…", + "manageLinks": "Linked folders", + "changeColor": "Change color", + "useThemeColor": "Use app theme", + "setDefaultAgent": "Set default agent", + "defaultAgentNone": "No default (use global)", + "agentUnavailableSuffix": "(unavailable)", + "loadingAgents": "Loading agents…", + "setAlias": "Set alias…", + "setAliasTitle": "Set folder alias", + "setAliasPlaceholder": "Enter an alias (leave empty to clear)", + "setAliasSave": "Save", + "setAliasCancel": "Cancel", + "removeFromWorkspace": "Remove from workspace" + }, + "manageConversations": { + "title": "Manage conversations", + "searchPlaceholder": "Search by title…", + "agentFilterAll": "All agents", + "statusFilterAll": "All statuses", + "folderFilterAll": "All folders", + "branchFilterAll": "All branches", + "branchNone": "No branch", + "branchSearchPlaceholder": "Search branches…", + "noMatchingBranches": "No matching branches", + "selectAllVisible": "Select all", + "deselectAll": "Deselect all", + "selectedCount": "{count} selected", + "matchedCount": "{count} matched", + "untitledConversation": "Untitled conversation", + "setStatus": "Set status…", + "deleteSelected": "Delete", + "noConversations": "No conversations in this folder.", + "noConversationsWorkspace": "No conversations in the workspace.", + "noMatchingConversations": "No conversations match the filters.", + "confirmDeleteTitle": "Delete {count} conversation(s)?", + "confirmDeleteDescription": "This action cannot be undone.", + "toastDeleted": "Deleted {count} conversation(s)", + "toastStatusUpdated": "Updated status for {count} conversation(s)", + "toastOpFailed": "Operation failed: {message}" + }, + "sectionPinned": "Pinned", + "sectionFolders": "Folders", + "sectionChats": "Chat", + "sectionRecent": "Recent", + "noChats": "No chats", + "noRecent": "No recent conversations", + "showMoreRecent": "Show more ({count})", + "noFolders": "No folders open", + "newChatAction": "New chat", + "automations": "Automations", + "tasks": "To-dos", + "loadingSubsessions": "Loading sub-conversations…" + }, + "conversation": { + "reloadFailed": "Failed to reload conversation: {message}", + "reloaded": "Conversation reloaded", + "reload": "Reload", + "activeConversationIndicator": "Active conversation", + "newConversation": "New Conversation", + "closeConversation": "Close Conversation", + "copyText": "Copy Text", + "copyTextSuccess": "Copied", + "copyTextFailed": "Copy failed", + "forkSession": "Fork Session", + "forkSessionSuccess": "Session forked successfully", + "forkSessionFailed": "Failed to fork session: {error}", + "exportConversation": "Export Conversation", + "exportImage": "Image", + "exportMarkdown": "Markdown", + "exportHtml": "HTML", + "exportSuccess": "Conversation exported", + "exportFailed": "Export failed", + "exportImageTooLong": "Conversation is too long to export as image", + "exportLabels": { + "untitledConversation": "Untitled Conversation", + "agent": "Agent", + "model": "Model", + "status": "Status", + "started": "Started", + "updated": "Updated", + "tokens": "Token Stats", + "duration": "Duration", + "inputTokens": "Input", + "outputTokens": "Output", + "cacheRead": "Cache Read", + "cacheWrite": "Cache Write", + "user": "User", + "assistant": "Assistant", + "system": "System", + "toolResult": "Result", + "toolError": "Error" + }, + "moreActions": "More actions" + }, + "sessionDetails": { + "menuLabel": "Session Details", + "noActiveSession": "No active session", + "title": "Session Details", + "subtitle": "Session metadata and token usage", + "fieldTitle": "Title", + "untitled": "Untitled conversation", + "sessionId": "Session ID", + "externalId": "Extension ID", + "agent": "Agent", + "model": "Model", + "status": "Status", + "gitBranch": "Git Branch", + "parentId": "Parent Session", + "tokensHeading": "Token Usage", + "totalTokens": "Total", + "inputTokens": "Input", + "outputTokens": "Output", + "cacheWrite": "Cache Write", + "cacheRead": "Cache Read", + "contextWindow": "Context Window", + "duration": "Duration", + "loadingStats": "Loading token usage…", + "loadFailed": "Failed to load token usage", + "noStats": "No usage recorded", + "timestampsHeading": "Timestamps", + "createdAt": "Created", + "updatedAt": "Updated", + "none": "—", + "copyField": "Copy {field}", + "copiedField": "Copied {field}" + }, + "conversationCard": { + "untitledConversation": "Untitled conversation", + "newConversation": "New Conversation", + "rename": "Rename", + "status": "Status", + "delete": "Delete", + "importLocalSessions": "Import local sessions", + "importing": "Importing...", + "renameConversation": "Rename conversation", + "deleteConversationTitle": "Delete conversation?", + "deleteConversationDescription": "This will delete \"{title}\". This action cannot be undone.", + "cancel": "Cancel", + "save": "Save", + "pin": "Pin", + "unpin": "Unpin", + "markCompleted": "Mark as completed", + "reopen": "Reopen", + "expandSubsessions": "Expand sub-conversations", + "collapseSubsessions": "Collapse sub-conversations" + }, + "search": { + "dialogTitle": "Search", + "dialogTitleWithFolder": "Search — {name}", + "tabConversations": "Conversations", + "tabFiles": "Files", + "placeholder": "Search conversations...", + "filePlaceholder": "Search files or directories...", + "allAgents": "All", + "searching": "Searching...", + "typeToSearch": "Type to search conversations", + "typeToSearchFiles": "Type to search files or directories", + "noResults": "No results found.", + "untitledConversation": "Untitled conversation" + }, + "folderTitleBar": { + "showSidebar": "Show Sidebar", + "hideSidebar": "Hide Sidebar", + "toggleTerminal": "Toggle Terminal", + "toggleAuxPanel": "Toggle Auxiliary Panel", + "search": "Search", + "openSettings": "Open Settings", + "backToConversations": "Back to Conversations", + "withShortcut": "{label} ({shortcut})" + }, + "statusBar": { + "connection": { + "connected": "Connected", + "connecting": "Connecting...", + "prompting": "Responding...", + "error": "Connection error", + "disconnected": "Disconnected", + "tooltip": "{agent} - {status}", + "tooltipError": "{agent} - {error}", + "title": "Agent connection", + "triggerAria": "Agent connection: {status}", + "workingDir": "Working directory", + "sessionId": "Session ID", + "viewerNote": "Attached to a session another client owns — reconnecting only re-attaches this view.", + "reconnectInterrupts": "Reconnecting restarts the agent and interrupts the work in progress.", + "reconnect": "Reconnect", + "reconnecting": "Reconnecting...", + "reconnectUnavailable": "Nothing to reconnect to yet." + }, + "tasks": { + "title": "Tasks" + }, + "alerts": { + "title": "Alerts", + "empty": "No alerts", + "details": "Details" + }, + "stats": { + "conversations": "{count} conversations", + "openUsage": "View session stats & token usage" + }, + "tokens": { + "contextWindowUsageAria": "Context window usage", + "contextWindow": "Context Window", + "usedMax": "Used / Max", + "tokenUsage": "Token Usage", + "input": "Input", + "output": "Output", + "cacheRead": "Cache Read", + "cacheWrite": "Cache Write", + "total": "Total" + } + }, + "auxPanel": { + "tabs": { + "files": "Files", + "changes": "Changes", + "commits": "Commits" + }, + "noFolderTitle": "No folder open", + "noFolderHint": "Open a folder to see its contents here" + }, + "windowControls": { + "minimizeWindow": "Minimize window", + "minimize": "Minimize", + "maximizeWindow": "Maximize window", + "maximize": "Maximize", + "restoreWindow": "Restore window", + "restore": "Restore", + "closeWindow": "Close window", + "close": "Close" + }, + "tabs": { + "closeConversationTab": "Close conversation tab", + "close": "Close", + "closeOthers": "Close Others", + "splitRight": "Split Right", + "splitDown": "Split Down", + "splitAndMoveRight": "Split and Move Right", + "splitAndMoveDown": "Split and Move Down", + "moveToOppositeGroup": "Move to Opposite Group", + "moveToGroup": "Move to Group", + "groupLabel": "Group {index}", + "changeSplitterOrientation": "Change Splitter Orientation", + "unsplit": "Unsplit", + "unsplitAll": "Unsplit All", + "closeAll": "Close All", + "tileDisplay": "Tile Display", + "untileDisplay": "Exit Tile" + }, + "fileWorkspace": { + "files": "Files", + "closeFileTab": "Close file tab", + "close": "Close", + "closeOthers": "Close Others", + "closeAll": "Close All", + "preview": "Preview", + "editSource": "Edit Source", + "maximize": "Maximize", + "restore": "Restore", + "emptyDirectory": "Empty folder" + }, + "terminal": { + "rename": "Rename", + "close": "Close", + "closeOthers": "Close Others", + "closeAll": "Close All", + "hideTerminal": "Hide Terminal ({shortcut})", + "openFolderFirst": "Open a folder first" + }, + "workspaceDialog": { + "title": "Open Folder", + "manageTitle": "Linked Folders", + "addTargetsTitle": "Add Folders to Link", + "pickRootDescription": "Pick the main folder for this workspace.", + "linksDescription": "Link other folders in as subdirectories so agents can work across all of them from this one workspace.", + "addTargetsDescription": "Select one or more folders. Each becomes a subdirectory of the workspace.", + "useSystemPicker": "System picker", + "next": "Next", + "back": "Back", + "done": "Done", + "change": "Change", + "addFolders": "Add folders", + "addSelected": "Add", + "addSelectedCount": "Add {count}", + "createCount": "Link {count} folder(s)", + "discardPending": "Discard", + "noLinks": "No linked folders yet.", + "gitExclude": "Keep links out of git status", + "rename": "Rename", + "unlink": "Remove link", + "repair": "Recreate link", + "saveName": "Save", + "cancelRename": "Cancel", + "removePending": "Remove", + "willAppearAs": "Appears as {name} in the workspace", + "renamedForDuplicate": "Renamed — {base} is already used by another link", + "renamedForExistingEntry": "Renamed — {base} already exists in this folder", + "partiallyCreated": "Only {count} folder(s) could be linked", + "openFailed": "Failed to open the folder", + "previewFailed": "Failed to check the selected folders", + "createFailed": "Failed to link the folders", + "renameFailed": "Failed to rename the link", + "removeFailed": "Failed to remove the link", + "repairFailed": "Failed to recreate the link", + "status": { + "ok": "Linked", + "missing": "The link is gone from this folder", + "conflicted": "Another entry now uses this name", + "broken": "The linked folder no longer exists" + }, + "nameIssue": { + "empty": "Enter a name", + "illegalChars": "Cannot contain / \\ : * ? \" < > |", + "tooLong": "Name is too long", + "reserved": "This name is reserved by Windows", + "duplicate": "This name is already used" + }, + "rejection": { + "not_found": "This folder could not be found", + "not_a_directory": "This path is not a folder", + "same_as_root": "This is the workspace folder itself", + "ancestor_of_root": "This folder contains the workspace", + "inside_root": "Already inside the workspace", + "already_linked": "Already linked", + "name_unavailable": "No free name is left for this folder", + "alreadyLinkedAs": "Already linked as {name}" + } + }, + "folderNameDropdown": { + "fallbackFolderName": "Folder", + "openFolder": "Open Folder", + "cloneRepository": "Clone Repository", + "projectBoot": "Project Boot", + "opened": "Opened", + "recentOpen": "Recently Opened" + }, + "fileWorkspacePanel": { + "addSelectionToChat": "Add Selection to Chat", + "addToChat": "Add to Chat", + "addSelectionToChatDone": "Added {label} to the conversation", + "addFileToChat": "Add File to Chat", + "toggleWordWrap": "Toggle Word Wrap", + "addFileToChatDone": "Added {label} to the conversation", + "viewDiff": "View Diff", + "openFile": "Open File", + "fileCount": "{count, plural, one {# file} other {# files}}", + "openFileOrDiff": "Open a file or diff from the right panel", + "disk": "Disk", + "head": "HEAD", + "unsaved": "Unsaved", + "workingTree": "Working Tree", + "loading": "Loading...", + "compareWithBranch": "{path} · compare with {branch}", + "hunkCount": "{count, plural, one {# hunk} other {# hunks}}", + "prev": "Prev", + "next": "Next", + "jumpToLine": "Jump to line {line}", + "noParsedDiffSections": "No parsed diff sections", + "loadingEditor": "Loading editor...", + "imageZoomIn": "Zoom in", + "imageZoomOut": "Zoom out", + "imageZoomReset": "Reset zoom", + "htmlPreviewTitle": "HTML preview", + "htmlPreviewTrust": "Enable scripts", + "htmlPreviewTrustHint": "Run this file's scripts and allow network access. Enable only for files you trust.", + "officePreviewTitle": "Office document preview", + "officeFullRender": "Full render", + "officeFullRenderHint": "Render Morph animations, 3D and math (runs the slide's own scripts)", + "officeNotInstalled": "OfficeCLI is not installed", + "officeNotInstalledHint": "Install OfficeCLI under Settings → Office Tools to preview Word, Excel, and PowerPoint files.", + "officeOpenSettings": "Open Settings", + "officeWatchFailed": "Couldn't start the live preview", + "officeWatchRetry": "Retry", + "officeServerInstallHint": "OfficeCLI must be installed on the server host. Run this command there, then retry:", + "officeRemoteDesktopUnsupported": "Live preview isn't available in a remote-desktop window. Open this workspace in the server's web UI to preview Office files." + }, + "branchDropdown": { + "toasts": { + "commitCodeCompleted": "Code commit completed", + "pushCodeCompleted": "Code push completed", + "committedFiles": "Committed {count, plural, one {# file} other {# files}}", + "taskCompleted": "{label} completed", + "taskFailed": "{label} failed", + "mergeNoNewCommits": "{branchName} has no new commits", + "mergedCommits": "Merged {count, plural, one {# commit} other {# commits}}", + "allFilesUpToDate": "All files are up to date", + "updatedFiles": "Updated {count, plural, one {# file} other {# files}}", + "openCommitWindowFailed": "Failed to open commit window", + "openPushWindowFailed": "Failed to open push window", + "upstreamSet": "Upstream branch has been set", + "upstreamSetAndPushed": "Upstream branch set and pushed {count, plural, one {# commit} other {# commits}}", + "noCommitsToPush": "No commits to push", + "pushedCommits": "Pushed {count, plural, one {# commit} other {# commits}}", + "switchedToFolder": "Switched to {name}", + "switchFailed": "Failed to switch branch", + "openStashWindowFailed": "Failed to open stash window" + }, + "tasks": { + "newBranch": "Create branch {name}", + "newWorktree": "Create worktree {name}", + "checkoutTo": "Checkout to {branchName}", + "mergeBranch": "Merge {branchName}", + "rebaseTo": "Rebase to {branchName}", + "deleteRemoteBranch": "Delete remote branch {branchName}", + "initGitRepo": "Initialize Git repository", + "pullCode": "Pull code", + "fetchInfo": "Fetch info", + "pushCode": "Push code", + "stashChanges": "Stash changes", + "stashPop": "Pop stash", + "deleteBranch": "Delete branch {branchName}", + "removeWorktree": "Delete worktree for {branchName}", + "removeWorktreeAndBranch": "Delete worktree and branch {branchName}", + "updateBranch": "Update branch {branchName}" + }, + "confirm": { + "mergeTitle": "Merge branch", + "rebaseTitle": "Rebase branch", + "mergeDescription": "Merge {branchName} into current branch {currentBranch}?", + "rebaseDescription": "Rebase current branch {currentBranch} onto {branchName}?", + "deleteRemoteTitle": "Delete Remote Branch", + "deleteRemoteDescription": "Delete remote branch {branchName}? This will remove it from the remote repository and cannot be undone.", + "deleteTitle": "Delete branch", + "deleteDescription": "Delete branch {branchName}? This action cannot be undone.", + "forceDeleteTitle": "Force Delete Branch", + "forceDeleteDescription": "Branch {branchName} is not fully merged. Are you sure you want to force delete it? This action cannot be undone.", + "deleteWorktreeTitle": "Delete worktree", + "deleteWorktreeDescription": "Delete the worktree directory that has {branchName} checked out? The branch and its commits are kept.", + "forceDeleteWorktreeTitle": "Force delete worktree", + "forceDeleteWorktreeDescription": "The worktree for {branchName} has uncommitted or untracked files. Delete it anyway? Those changes cannot be recovered.", + "deleteWorktreeAndBranchTitle": "Delete worktree and branch", + "deleteWorktreeAndBranchDescription": "Delete the worktree for {branchName}, the branch itself, and its workspace folder? Its sessions move to the repository folder. This action cannot be undone.", + "forceDeleteWorktreeAndBranchTitle": "Force delete worktree and branch", + "forceDeleteWorktreeAndBranchDescription": "The worktree for {branchName} has uncommitted files, or the branch is not fully merged. Delete both anyway? This action cannot be undone." + }, + "current": "Current", + "switchToBranch": "Switch to this branch", + "mergeBranchIntoCurrent": "Merge {branchName} into {currentBranch}", + "rebaseCurrentToBranch": "Rebase {currentBranch} onto {branchName}", + "noBranch": "No branch", + "detachedHead": "Detached HEAD at {sha}", + "initGitRepo": "Initialize Git repository", + "pullCode": "Pull code", + "fetchRemoteBranches": "Fetch remote branches", + "openCommitWindow": "Commit code...", + "pushCode": "Push...", + "pushBranch": "Push", + "newBranch": "New branch...", + "newWorktree": "New worktree...", + "stashChanges": "Stash changes...", + "stashPop": "Unstash...", + "manageRemotes": "Manage Remotes...", + "localBranches": "Local branches ({count, plural, one {#} other {#}})", + "noLocalBranches": "No local branches", + "remoteBranches": "Remote branches ({count, plural, one {#} other {#}})", + "noRemoteBranches": "No remote branches", + "dialogs": { + "newBranchTitle": "New branch", + "newBranchDescription": "Create a new branch from current branch {branch}", + "branchNamePlaceholder": "Branch name", + "newWorktreeTitle": "New worktree", + "newWorktreeDescription": "Create a new worktree from current branch {branch}", + "branchNameLabel": "Branch name", + "worktreePathLabel": "Worktree path", + "worktreePathPlaceholder": "Worktree path", + "manageRemotesTitle": "Manage Remotes", + "manageRemotesEmpty": "No remotes configured", + "remoteNamePlaceholder": "Remote name", + "remoteUrlPlaceholder": "Remote URL", + "addRemote": "Add", + "savingRemotes": "Saving..." + }, + "conflict": { + "title": "Merge Conflicts", + "description": "The following files have conflicts that need to be resolved:", + "abort": "Abort Merge", + "openMergeTool": "Open Merge Tool", + "completeMerge": "Complete Merge", + "abortSuccess": "Merge aborted successfully", + "completeSuccess": "Merge completed successfully" + }, + "stashDialog": { + "title": "Stash Changes", + "description": "Save your current changes to a stash", + "messageLabel": "Message", + "messagePlaceholder": "Stash message (optional)", + "keepIndex": "Keep index (staged changes remain staged)", + "cancel": "Cancel", + "stash": "Stash", + "success": "Changes stashed successfully", + "error": "Failed to stash changes" + }, + "unstashDialog": { + "title": "Unstash Changes", + "noStashes": "No stashes found", + "selectFile": "Select a file to view diff", + "viewDiff": "View Diff", + "original": "Original", + "modified": "Modified", + "apply": "Apply", + "drop": "Drop", + "applySuccess": "Stash applied successfully", + "dropSuccess": "Stash dropped", + "confirmApply": "Apply stash {ref} to working directory?", + "cancel": "Cancel" + }, + "deleteBranch": "Delete branch", + "deleteWorktree": "Delete worktree", + "deleteWorktreeAndBranch": "Delete worktree and branch", + "searchPlaceholder": "Search branches and actions", + "searchAriaLabel": "Search branches and actions", + "branchListLabel": "Branches and actions", + "noMatches": "No matches" + }, + "commitDialog": { + "toasts": { + "commitCompleted": "Code commit completed", + "pushFailed": "Push failed", + "committedFiles": "Committed {count, plural, one {# file} other {# files}}", + "addedToVcs": "Added to VCS", + "addToVcsFailed": "Failed to add to VCS", + "fileDeleted": "File deleted", + "deleteFailed": "Delete failed", + "fileRolledBack": "File rolled back", + "rollbackFailed": "Rollback failed", + "dirRolledBack": "Directory rolled back", + "dirDeleted": "Directory deleted" + }, + "confirm": { + "deleteTitle": "Confirm deletion", + "deleteDescription": "Delete file \"{file}\"? This action cannot be undone.", + "rollbackTitle": "Confirm rollback", + "rollbackDescription": "Rollback file \"{file}\" to HEAD? Unsaved changes will be lost.", + "rollbackDirDescription": "Rollback directory \"{dir}\" to HEAD? Unsaved changes will be lost.", + "deleteDirDescription": "Delete directory \"{dir}\"? This action cannot be undone." + }, + "actions": { + "select": "Select", + "unselect": "Unselect", + "rollback": "Rollback", + "addToVcs": "Add to VCS" + }, + "aria": { + "selectFile": "{action} {path}", + "unselectAllFiles": "Unselect all files", + "selectAllFiles": "Select all files", + "unselectTracked": "Unselect tracked changes", + "selectTracked": "Select tracked changes", + "unselectUntracked": "Unselect untracked files", + "selectUntracked": "Select untracked files" + }, + "loading": "Loading...", + "selectionCount": "{selected} / {total} files", + "emptyFiles": "No changed files", + "trackedChanges": "Tracked changes ({count})", + "untrackedFiles": "Untracked files ({count})", + "commitMessage": "Commit message", + "commitMessagePlaceholder": "Enter commit message...", + "commitButton": "Commit ({count})", + "commitAndPushButton": "Commit and Push ({count})", + "head": "HEAD", + "workingTree": "Working Tree", + "clickFileToDiff": "Click a file name to view diff", + "loadingDiff": "Loading diff..." + }, + "pushWindow": { + "title": "Push Code", + "noUnpushedCommits": "No unpushed commits", + "noRemoteConfigured": "No Git remote configured\nAdd a remote in Manage Remotes", + "newBranchNoPushedCommits": "New branch — push to create remote tracking branch", + "unpushed": "Unpushed", + "selectFileToViewDiff": "Select a file to view diff", + "before": "Before", + "after": "After", + "push": "Push", + "toasts": { + "pushSuccess": "Push successful", + "pushFailed": "Push failed", + "upstreamSet": "Upstream branch has been set", + "upstreamSetAndPushed": "Upstream branch set and pushed {count, plural, one {# commit} other {# commits}}", + "noCommitsToPush": "No commits to push", + "pushedCommits": "Pushed {count, plural, one {# commit} other {# commits}}" + } + }, + "gitLogTab": { + "filesTitle": "Files", + "expandAllFiles": "Expand all files", + "collapseAllFiles": "Collapse all files", + "workspace": "workspace", + "retry": "Retry", + "noCommitsFound": "No commits found", + "notAGitRepoTitle": "Not a Git repository", + "notAGitRepoHint": "Initialize Git from the branch menu above, or open a folder that is already tracked.", + "hash": "Hash", + "copyHash": "Copy hash", + "copyMessage": "Copy message", + "showMore": "Show more", + "showLess": "Show less", + "author": "Author", + "noFileChangeDetails": "No file change details available.", + "loadingFiles": "Loading files...", + "branchesTitle": "Branches", + "loadingBranches": "Loading branches...", + "noContainingBranches": "No containing branches found.", + "newBranch": "New branch...", + "resetToHere": "Reset to Here", + "resetDisabledReasonNotCurrentBranchView": "Available only when viewing current branch", + "copyFullCommitHashAria": "Copy full commit hash {hash}", + "pushStatus": { + "pushed": "Pushed to remote", + "notPushed": "Not pushed to remote", + "unknown": "Push status unknown (no upstream configured)" + }, + "time": { + "monthsAgo": "{count, plural, one {# month ago} other {# months ago}}", + "daysAgo": "{count, plural, one {# day ago} other {# days ago}}", + "hoursAgo": "{count, plural, one {# hour ago} other {# hours ago}}", + "minsAgo": "{count, plural, one {# min ago} other {# mins ago}}", + "justNow": "just now" + }, + "toasts": { + "createdAndSwitchedNewBranch": "Created and switched to new branch", + "newBranchFromCommit": "{name} (from {shortHash})", + "createBranchFailed": "Failed to create branch", + "openPushWindowFailed": "Failed to open push window", + "resetSuccess": "Reset successful", + "resetSuccessDescription": "{branch} reset to {shortHash} with {mode}", + "resetFailed": "Reset failed" + }, + "authorFilter": { + "label": "Author", + "searchPlaceholder": "Search author", + "noAuthors": "No authors found", + "you": "you", + "filterByAuthorAria": "Filter commits by author", + "filterByQuery": "Filter by \"{query}\"", + "clearAuthorFilterAria": "Clear author filter", + "recent": "Recent", + "matchingAuthors": "Matching authors", + "removeFromRecent": "Remove {name} from recent" + }, + "branchSelector": { + "label": "Branch", + "head": "HEAD", + "headHint": "Follows the current branch", + "headHintWithBranch": "Follows the current branch ({branch})", + "searchBranch": "Search branch...", + "noBranches": "No branches", + "selectBranchPlaceholder": "Select branch...", + "localBranches": "Local branches", + "current": "Current", + "remoteBranches": "Remote branches", + "refreshCommitHistory": "Refresh commit history", + "clearBranchFilterAria": "Clear branch filter" + }, + "dialogs": { + "newBranchTitle": "New branch", + "newBranchDescription": "Create a new branch with commit {shortHash} as the latest commit.", + "branchNamePlaceholder": "Branch name", + "reset": { + "title": "Reset Current Branch to Here", + "branchLabel": "Branch", + "targetLabel": "Target", + "messageLabel": "Message", + "modeLabel": "Reset mode", + "confirmButton": "Reset", + "modes": { + "soft": { + "label": "--soft", + "description": "Move HEAD and the current branch pointer to the target commit.\nKeep Index and Working Tree unchanged.\nChanges from the removed commits stay staged." + }, + "mixed": { + "label": "--mixed (default)", + "description": "Move HEAD to the target commit.\nReset Index to the target commit while keeping Working Tree changes.\nThose changes become unstaged." + }, + "hard": { + "label": "--hard", + "description": "Move HEAD and reset both Index and Working Tree to the target commit.\nLocal tracked changes after the target commit are discarded.\nThis is a destructive operation." + }, + "keep": { + "label": "--keep", + "description": "Move HEAD to the target commit and keep local changes when possible.\nOnly non-conflicting local changes are preserved.\nIf conflicts are detected, reset aborts to protect your work." + } + } + } + }, + "moreActions": "More Git actions" + }, + "gitChangesTab": { + "workspace": "workspace", + "noChanges": "No local changes", + "notAGitRepoTitle": "Not a Git repository", + "notAGitRepoHint": "Initialize Git from the branch menu above, or open a folder that is already tracked.", + "trackedChanges": "Tracked changes ({count})", + "untrackedFiles": "Untracked files ({count})", + "expandTracked": "Expand tracked changes", + "collapseTracked": "Collapse tracked changes", + "expandUntracked": "Expand untracked files", + "collapseUntracked": "Collapse untracked files", + "showRemainingItems": "Show {count} more items", + "actions": { + "commitCode": "Commit code", + "rollback": "Rollback", + "addToVcs": "Add to VCS", + "delete": "Delete", + "moreActions": "More Git actions", + "addAllToVcs": "Add all to VCS", + "rollbackAll": "Rollback all", + "refresh": "Refresh" + }, + "toasts": { + "noAddableFilesInDir": "No changed files in this directory can be added to VCS", + "noRollbackFilesInDir": "No changed files in this directory can be rolled back", + "addedToVcs": "Added {name} to VCS", + "addToVcsFailed": "Failed to add to VCS", + "openCommitWindowFailed": "Failed to open commit window", + "rolledBack": "Rolled back {name}", + "rollbackFailed": "Rollback failed", + "addedFilesToVcs": "Added {count, plural, one {# file} other {# files}} to VCS", + "rolledBackFiles": "Rolled back {count, plural, one {# file} other {# files}}", + "deleted": "Deleted {name}", + "deleteFailed": "Delete failed", + "deletedFiles": "Deleted {count, plural, one {# file} other {# files}}", + "noDeletableFilesInDir": "No changed files in this directory can be deleted", + "commitFailed": "Commit failed" + }, + "directoryDialog": { + "descriptionAdd": "Select files under directory {path} to add to VCS.", + "descriptionRollback": "Select files under directory {path} to roll back.", + "descriptionDelete": "Select files under directory {path} to delete. This action cannot be undone.", + "descriptionFallback": "Select files to proceed.", + "selectionCount": "Selected {selected} / {total} files", + "selectAll": "Select all", + "unselectAll": "Unselect all", + "loadingCandidates": "Loading directory changes...", + "noOperableFiles": "No operable files" + }, + "rollbackConfirm": { + "title": "Confirm rollback", + "descriptionWithTarget": "Roll back local changes for {kind} \"{name}\"?", + "descriptionFallback": "Roll back local changes?", + "kindDirectory": "directory", + "kindFile": "file" + }, + "deleteConfirm": { + "title": "Confirm deletion", + "descriptionWithTarget": "Delete {kind} \"{name}\"? This action cannot be undone.", + "descriptionFallback": "This action cannot be undone.", + "kindDirectory": "directory", + "kindFile": "file" + }, + "quickCommit": { + "placeholder": "Commit message (Enter to commit)" + } + }, + "tabContext": { + "loadingConversation": "Loading...", + "untitledConversation": "Untitled conversation", + "newConversation": "New Conversation" + }, + "fileTreeTab": { + "workspace": "Workspace", + "retry": "Retry", + "git": "Git", + "openInFileManager": "Open in file manager", + "openInFinder": "Open in Finder", + "openInExplorer": "Open in Explorer", + "attachToCurrentSession": "Add to session", + "compareWithBranch": "Compare with branch...", + "reloadFromDisk": "Reload from disk", + "new": "New", + "newFile": "File", + "newDirectory": "Directory", + "openIn": "Open in", + "openInTerminal": "Open in terminal", + "linkedFolder": "Linked folder", + "copyPath": "Copy path", + "upload": "Upload files/folder", + "download": "Download file", + "downloadAsZip": "Download as ZIP", + "actions": { + "select": "Select", + "unselect": "Unselect", + "commitCode": "Commit code", + "rollback": "Rollback", + "addToVcs": "Add to VCS" + }, + "aria": { + "selectPath": "{action} {path}" + }, + "toasts": { + "openDirectoryFailed": "Failed to open directory", + "openBuiltinTerminalFailed": "Unable to open built-in terminal", + "openCommitWindowFailed": "Failed to open commit window", + "noAddableFilesInDir": "No changed files in this directory can be added to VCS", + "noRollbackFilesInDir": "No changed files in this directory can be rolled back", + "addedToVcs": "Added {name} to VCS", + "addToVcsFailed": "Failed to add to VCS", + "loadBranchesFailed": "Failed to load branches", + "renameFailed": "Rename failed", + "moveFailed": "Move failed", + "deleteFailed": "Delete failed", + "rolledBack": "Rolled back {name}", + "rollbackFailed": "Rollback failed", + "addedFilesToVcs": "Added {count, plural, one {# file} other {# files}} to VCS", + "rolledBackFiles": "Rolled back {count, plural, one {# file} other {# files}}", + "savedAsCopy": "Saved as a copy", + "saveCopyFailed": "Failed to save as copy", + "watchStartFailed": "Failed to start file watch", + "createFailed": "Failed to create", + "downloadFailed": "Failed to download {name}", + "downloadSaved": "Downloaded {name}", + "pathCopied": "Path copied", + "copyPathFailed": "Failed to copy path" + }, + "createDialog": { + "newFile": "New file", + "newDirectory": "New directory", + "description": "Enter a name for the new {kind}.", + "placeholderFile": "file-name.ext", + "placeholderDirectory": "folder-name" + }, + "renameDialog": { + "renameDirectory": "Rename directory", + "renameFile": "Rename file", + "description": "Enter a new name (name only, no path).", + "placeholderDirectory": "new-folder-name", + "placeholderFile": "new-file-name.ext" + }, + "uploadDialog": { + "title": "Upload to workspace", + "description": "Adjust the destination if needed, then add files or folders.", + "workspaceRoot": "workspace root", + "targetPathLabel": "Upload to", + "targetPathHint": "Resolved path: {path}", + "dropHint": "Drag files or folders here, or use the buttons below", + "dropHintActive": "Release to add to the queue", + "selectFiles": "Select files", + "selectFolder": "Select folder", + "startUpload": "Start upload", + "clearQueue": "Clear finished", + "removeItem": "Remove from queue", + "retry": "Retry", + "dropZoneAria": "Drop files here or activate to browse", + "folderEmpty": "No files found in the dropped folder", + "summary": "Total: {total} · Succeeded: {succeeded} · Failed: {failed}", + "status": { + "pending": "Waiting", + "uploading": "Uploading", + "success": "Done", + "error": "Failed", + "cancelled": "Cancelled" + } + }, + "directoryDialog": { + "descriptionAdd": "Select files under directory {path} to add to VCS.", + "descriptionRollback": "Select files under directory {path} to roll back.", + "descriptionFallback": "Select files to proceed.", + "selectionCount": "Selected {selected} / {total} files", + "selectAll": "Select all", + "unselectAll": "Unselect all", + "loadingCandidates": "Loading directory changes...", + "noOperableFiles": "No operable files" + }, + "compareDialog": { + "title": "Compare with branch", + "descriptionWithTarget": "Select a branch and compare with {kind} {path}", + "descriptionFallback": "Select a branch to compare.", + "kindDirectory": "directory", + "kindFile": "file", + "filterPlaceholder": "Filter branches, e.g. main / origin/main", + "singleClickHint": "Click a branch to compare directly", + "loadingBranches": "Loading branches...", + "recentBranches": "Recent branches ({count})", + "noCurrentBranch": "No current branch", + "localBranches": "Local branches ({count})", + "remoteBranches": "Remote branches ({count})", + "noMatchingBranches": "No matching branches" + }, + "externalConflictDialog": { + "title": "External file changes detected", + "descriptionWithPath": "File {path} has changed on disk, and current edits are unsaved.", + "descriptionFallback": "Current file has changed on disk, and current edits are unsaved.", + "compare": "Compare", + "savingCopy": "Saving copy...", + "saveAsCopy": "Save as copy", + "reload": "Reload" + }, + "deleteConfirm": { + "title": "Confirm deletion", + "descriptionWithTarget": "Delete {kind} \"{name}\"? This action cannot be undone.", + "descriptionFallback": "This action cannot be undone.", + "kindDirectory": "directory", + "kindFile": "file" + }, + "rollbackConfirm": { + "title": "Confirm rollback", + "descriptionWithTarget": "Rollback local changes for file \"{name}\"?", + "descriptionFallback": "Rollback local changes for this file?" + }, + "terminalTitle": "Terminal · {name}" + }, + "commandDropdown": { + "loading": "Loading...", + "addCommand": "Add Command", + "manageCommands": "Manage Commands...", + "runCommandTitle": "Run: {command}", + "stopCommandTitle": "Stop: {command}", + "manageDialog": { + "title": "Manage Commands", + "empty": "No commands yet", + "noResults": "No matching commands", + "searchPlaceholder": "Search commands", + "newCommand": "New command", + "nameLabel": "Name", + "commandLabel": "Command", + "dragSort": "Drag to sort", + "dragSortCommand": "Drag to sort {name}", + "orderFailed": "Failed to save command order", + "loadFailed": "Failed to load commands", + "saveFailed": "Failed to save command", + "deleteFailed": "Failed to delete command", + "confirmDelete": { + "title": "Delete command?", + "message": "This will remove \"{name}\". This action cannot be undone." + } + } + }, + "workspaceContext": { + "confirmCloseDirtyTab": "Close \"{title}\" without saving?", + "confirmCloseOtherDirtyTabs": "Close other tabs with unsaved changes?", + "confirmCloseAllDirtyTabs": "Close all tabs with unsaved changes?", + "unableLoadContent": "Unable to load content.\n\n{message}", + "previewRequestTimedOut": "Preview request timed out", + "diffRequestTimedOut": "Diff request timed out", + "branchCompareRequestTimedOut": "Branch compare request timed out", + "commitDiffRequestTimedOut": "Commit diff request timed out", + "saveRequestTimedOut": "Save request timed out", + "reloadRequestTimedOut": "Reload request timed out", + "noChanges": "No changes.", + "noDiffOutput": "No diff output.", + "diffTitleWorkspace": "Diff · Workspace", + "diffDescriptionWorkingTree": "Working tree (HEAD)", + "diffTitleFile": "Diff · {name}", + "compareTitleFile": "Compare · {name}", + "compareTitleBranch": "Compare · {branch}", + "compareDescriptionPath": "{path} · compare with {branch}", + "compareDescriptionBranch": "compare with {branch}", + "diffTitleCommitFile": "Diff · {name} @ {hash}", + "diffTitleCommit": "Diff · {hash}", + "diffDescriptionCommitPath": "{path} · commit {commit}", + "diffDescriptionCommit": "commit {commit}", + "diffTitleConflictFile": "Conflict · {name}", + "diffDescriptionConflict": "{path} · disk vs unsaved" + }, + "chat": { + "acpConnections": { + "actions": { + "openAgentsSettings": "Open Agents settings", + "retry": "Retry" + }, + "agentsSetupHint": "Open Settings > Agents to manage installation.", + "withSetupHint": "{message}\n{hint}", + "blocked": { + "missingConfig": "Unable to read current Agent configuration.", + "disabled": "{agent} is disabled in Agents settings. Enable it before connecting.", + "unavailable": "{agent} is unavailable on the current platform.", + "sdkMissing": "{agent} SDK is not installed", + "adapterMissing": "{agent}'s ACP adapter is not installed" + }, + "backendErrors": { + "initializeTimeout": "{agent} connection handshake timed out after 60 seconds. Please open Settings to check Agent configuration and network settings.", + "mcpRejectedByAgent": "{agent} refused the session while codeg’s MCP companion was attached: {message} If this agent does not support MCP, turn off “MCP support” for it in Settings and connect again.", + "processExited": "{agent} process exited unexpectedly.", + "spawnFailed": "Failed to start {agent}: {message}", + "downloadFailed": "{agent} download failed: {message}", + "sessionLoadResourceNotFound": "{agent} session failed to load. Reload to retry, or start a new conversation.", + "sessionLoadUnavailable": "{agent} couldn't restore this session — it may have ended or the agent stopped. Reload to retry, or start a new conversation.", + "turnFailedRefusal": "{agent} refused to continue this turn. This often indicates a backend or gateway error — check the agent's logs.", + "turnFailedMaxTokens": "{agent} reached the maximum token limit for this turn.", + "turnFailedMaxTurnRequests": "{agent} reached the maximum number of allowed requests for this turn.", + "turnFailedUnknown": "{agent} ended the turn with an unrecognized stop reason.", + "grokModelSwitchIncompatibleAgent": "{agent} can't switch to that model in an existing conversation. Start a new session to use it.", + "turnFailedEmpty": "{agent} ended the turn without producing any response.", + "turnFailedEmptyProtocol": "{agent} produced output that codeg could not parse — the agent version may not match the protocol.", + "turnFailedEmptyMetadata": "{agent} sent only status updates this turn (plan / mode / usage) and no reply.", + "detailsInAlerts": "Open Alerts in the status bar and expand the details to see the agent's output." + }, + "unableReadAgentConfig": "Unable to read Agent config: {message}", + "connectFailedTitle": "{agent} connection failed", + "toolFallbackTitle": "Tool", + "eventErrorTitle": "Agent Error", + "notificationTurnComplete": "{agent} has finished responding", + "notificationError": "{agent} error: {message}", + "claudeApiRetry": { + "fallbackError": "authentication_failed", + "retryingWithMax": "retrying {attempt}/{max}", + "retryingAttempt": "retrying attempt {attempt}", + "retrying": "retrying", + "nextRetryIn": "next in {seconds}s", + "line": "{error}{status} · {retry}", + "lineWithDelay": "{error}{status} · {retry}, {delay}", + "httpStatus": " (HTTP {status})" + }, + "configOptionAdjusted": "{agent} set {option} to {actual} instead of {requested}" + }, + "connectionLifecycle": { + "tasks": { + "connectingTitle": "Connecting to {agent}", + "connectingDescription": "Establishing connection", + "loadingSelectorsTitle": "Loading {agent} selectors", + "loadingSelectorsDescription": "Fetching mode and session config options", + "initSessionTitle": "Initializing {agent} session", + "initSessionDescription": "Creating session and loading configuration" + }, + "errors": { + "connectionFailed": "Connection failed", + "sendPromptFailed": "Failed to send the message: {error}" + } + }, + "shared": { + "attachedResources": "Attached resources", + "toolCallFailed": "Tool call failed" + }, + "messageThread": { + "emptyTitle": "No messages yet", + "emptyDescription": "Start a conversation to see messages here" + }, + "chatInput": { + "connecting": "Connecting...", + "agentResponding": "{agent} is responding...", + "sendMessage": "Send a message..." + }, + "messageInput": { + "askAnything": "Ask anything...", + "removeAttachmentAria": "Remove {name}", + "attachFiles": "Attach files", + "attachLocalUpload": "Upload local file", + "attachServerFile": "Pick server file", + "addActions": "Add", + "quickMessages": "Quick messages", + "quickMessagesEmpty": "No quick messages yet", + "quickMessagesLoading": "Loading...", + "pasteAsPlainText": "Paste as plain text", + "cut": "Cut", + "copy": "Copy", + "selectAll": "Select all", + "pasteUnavailable": "Couldn't read the clipboard. Press Ctrl/⌘V to paste instead.", + "clipboardWriteFailed": "Couldn't write to the clipboard. Use the keyboard shortcut instead.", + "quickMessageUntitled": "Untitled", + "liveFeedback": "Live feedback", + "liveFeedbackDisabledHint": "Available while the agent is working", + "dropFilesToAttach": "Drop files to attach", + "loadingSettings": "Loading settings...", + "loadingMode": "Loading mode...", + "modeLabel": "Mode", + "toggleOn": "On", + "toggleOff": "Off", + "agentSettings": "Agent settings", + "searchModel": "Search models...", + "searchModelAria": "Search models", + "modelListLabel": "Models", + "noModels": "No models found", + "cancel": "Cancel", + "send": "Send", + "forkAndSend": "Fork & Send", + "queueMessage": "Queue message", + "steerIntoTurn": "Insert into current turn", + "steerQueuedInstead": "Queued instead — it will be sent with the next turn.", + "steerFailed": "Couldn't insert into the current turn", + "steerAttachmentsUnsupported": "Text only — drafts with attachments go through the queue.", + "slashCommands": "Slash commands", + "slashSearchPlaceholder": "Search commands...", + "slashSearchEmpty": "No matching commands", + "experts": "Experts", + "office": "Office Work", + "research": "Scientific Research", + "attachUploadTooLarge": "{names} exceeds the {limit}MB upload limit and was skipped.", + "attachUploadFailed": "Failed to upload {names}.", + "attachUploadNotAFile": "{names} isn't a regular file (directory or special file) and was skipped.", + "attachUploadQuotaExceeded": "The server is out of upload storage; {names} couldn't be uploaded.", + "attachUploadInProgress": "Images are still uploading — try again in a moment.", + "mentionEmpty": "No matches", + "mentionLoading": "Searching…", + "mentionListLabel": "Mentions", + "mentionMore": "More results — keep typing to filter", + "mentionCount": "{count, plural, one {# result} other {# results}}", + "mentionGroupFile": "Files", + "mentionGroupAgent": "Agents", + "mentionGroupSession": "Sessions", + "mentionGroupCommit": "Commits", + "mentionGroupSkill": "Skills" + }, + "messageQueue": { + "addToQueue": "Queue message", + "saveEdit": "Save", + "cancelEdit": "Cancel edit", + "editItem": "Edit", + "deleteItem": "Remove" + }, + "welcomeInputPanel": { + "agentsSettingsPath": "Settings > Agents", + "autoConnectFallback": "Click to open {path} and manage installation.", + "autoConnectAppend": "{message}. Click to open {path} and manage installation.", + "enableAgentFirstPlaceholder": "Enable at least one agent before starting a session...", + "prepareSessionFailed": "Couldn't prepare the chat session. Please try again.", + "createConversationFailed": "Couldn't create the conversation. Please try again.", + "askAnythingPlaceholder": "Ask anything...", + "agentNotInstalled": "{agent} is not installed — open Agents settings to install it", + "agentAdapterNotInstalled": "{agent}'s ACP adapter is not installed (separate from your own CLI) · open Agents settings to install it" + }, + "welcomePanel": { + "greeting": "What would you like to do today?", + "tips": { + "tileTabs": "Right-click any conversation tab and choose Tile Display to see multiple sessions side by side.", + "pinTab": "Double-click a conversation tab to pin it, so a newly opened session won't auto-replace it.", + "shortcutsNewSearch": "{newConversation} opens a new conversation, {searchConversations} searches your history.", + "slashAtMention": "Type / in the input to trigger slash commands, or @ to reference a file from the project.", + "pasteDropFiles": "Paste a screenshot or drop a file directly onto the input to attach it.", + "queueMessage": "While the agent is replying, keep typing — your next message gets queued and auto-sent when it finishes.", + "draftAutoSave": "Unsent drafts are auto-saved per conversation and restored when you come back.", + "forkSend": "The send button's dropdown has Fork and Send — branch from the current turn into a new tab.", + "exportConversation": "Right-click inside the conversation to export it as Markdown, HTML, or an image.", + "chatChannels": "Connect Telegram / Lark / WeChat under Settings → Chat Channels to continue from your phone.", + "shortcutsAuxPanel": "{toggleAuxPanel} toggles the right panel to view this session's touched files and Git changes.", + "shortcutsTerminalSidebar": "{toggleTerminal} opens the built-in terminal, {toggleSidebar} toggles the sidebar.", + "customShortcuts": "Every shortcut is fully remappable under Settings → Shortcuts.", + "webService": "Enable Settings → Web Service so teammates can reach the same codeg from a browser.", + "fusionMode": "Open a file or diff to automatically show it alongside the conversation.", + "quickMessages": "Open the + button next to the input and pick Quick Messages to insert a saved snippet (manage them under Settings → Quick Messages).", + "experts": "The + button has an Expert Skills menu — preload roles like Debug or Planning with one click.", + "taskBoard": "To-dos run a task end to end — the agent works in its own worktree, then you review the diff and merge.", + "automations": "Automations run a saved prompt on a schedule — a nightly review, a recurring report — and each run can get its own worktree.", + "tokenUsage": "Click the conversation count in the status bar to open Token Usage — spend broken down by day, agent, model, and folder.", + "mentionTargets": "@ pulls in more than files — mention another agent to hand off a subtask, or reference a past session, a commit, or a skill.", + "splitGroups": "Right-click a tab and pick Split Right or Split Down to keep two conversations open in their own panes.", + "worktrees": "Open the branch button and pick New worktree so several agents can work the same repo without overwriting each other's files.", + "importSessions": "Already ran sessions in the terminal? A folder's menu has Import local sessions — bring that history into codeg.", + "subSessions": "When an agent delegates, the sub-session appears nested under it in the sidebar — expand the row to follow what each one did.", + "liveFeedback": "Live feedback in the + menu drops a note into the turn the agent is already running, without interrupting it.", + "skillPacks": "Settings → Skill Packs bundles coding experts, scientific research, and office skills — switch them on per agent.", + "modelProviders": "Settings → Model Providers takes your own API key or endpoint, and you pick the model right in the composer.", + "workspaceBackground": "Settings → Appearance sets a workspace background image, panel opacity, and the app's fonts." + }, + "quickActions": { + "excel": "Excel Workbook", + "excelDesc": "Data tables, formulas & charts", + "word": "Word Document", + "wordDesc": "Reports, letters & memos", + "ppt": "Presentation", + "pptDesc": "Slides with professional design", + "pitchDeck": "Pitch Deck", + "pitchDeckDesc": "Fundraising deck with key metrics", + "morph": "Morph Animation", + "morphDesc": "Cinematic slide transitions", + "morph3d": "3D Morph", + "morph3dDesc": "3D models with camera moves", + "academic": "Academic Paper", + "academicDesc": "Research with citations & structure", + "financial": "Financial Model", + "financialDesc": "Statements, DCF & projections", + "dashboard": "Data Dashboard", + "dashboardDesc": "KPIs & analytics from your data", + "prompts": { + "excel": "Create an Excel workbook with the following requirements:\n\n[describe your data, tables, formulas, and charts here]", + "word": "Create a Word document with the following requirements:\n\n[describe your document content, structure, and formatting here]", + "ppt": "Create a PowerPoint presentation with the following requirements:\n\n[describe your slides, content, and design here]", + "pitchDeck": "Create a fundraising pitch deck with the following requirements:\n\n[describe your company, funding round, and key metrics here]", + "morph": "Create a presentation with Morph transition animations:\n\n[describe your presentation topic and desired visual effects here]", + "morph3d": "Create a 3D Morph presentation with GLB models and camera moves:\n\n[describe your topic and 3D visual concept here]", + "academic": "Write an academic paper in Word with the following requirements:\n\n[describe your research topic, methodology, and key findings here]", + "financial": "Create a financial model in Excel with the following requirements:\n\n[describe your financial statements, projections, and analysis here]", + "dashboard": "Create a data dashboard in Excel with the following requirements:\n\n[describe your data source, KPIs, and charts here]", + "scientific-brainstorming": "Help me brainstorm research directions — explore interdisciplinary connections, challenge assumptions, and surface promising gaps. The area I'm exploring: ", + "hypothesis-generation": "Help me turn these observations into testable hypotheses — with clear predictions, plausible mechanisms, and experiments to test them. My observations: ", + "experimental-design": "Help me design a rigorous experiment before I collect data — the design, randomization, controls, and how to avoid confounding. What I want to study: ", + "statistical-power": "Help me determine the sample size I need — walk me through a power analysis (effect size, alpha, power) for my design. Details: ", + "statistical-analysis": "Help me analyze this data properly — choose the right test, check assumptions, report effect sizes, and write it up. My data and question: ", + "exploratory-data-analysis": "Do an exploratory analysis of my data file — summarize its structure, quality, and notable patterns, then suggest next steps. The file is: ", + "scientific-visualization": "Help me make a publication-quality figure — clear layout, honest error bars, a colorblind-safe palette, and journal formatting. What I want to show: ", + "scientific-critical-thinking": "Help me critically appraise this study or claim — assess the evidence quality, spot biases and confounders, and weigh the conclusions. Here it is: ", + "paper-lookup": "Help me find relevant papers and open-access full text across scholarly databases, with citations I can reuse. I'm looking for: " + }, + "paper-lookup": "Paper Lookup", + "paper-lookupDesc": "Search 10 scholarly APIs (PubMed, arXiv, OpenAlex, Crossref…) for papers, citations, and open-access full text.", + "scientific-critical-thinking": "Critical Thinking", + "scientific-critical-thinkingDesc": "Appraise scientific claims and evidence quality — spot biases and confounders, apply GRADE and risk-of-bias frameworks.", + "scientific-visualization": "Scientific Visualization", + "scientific-visualizationDesc": "Publication-ready figures — multi-panel layouts, significance annotations, and journal-specific formatting.", + "exploratory-data-analysis": "Exploratory Data Analysis", + "exploratory-data-analysisDesc": "Automated exploration of scientific data files across 200+ formats with quality metrics and reports.", + "statistical-analysis": "Statistical Analysis", + "statistical-analysisDesc": "Guided statistical analysis — test selection, assumption checks, effect sizes, and APA-style reporting.", + "statistical-power": "Statistical Power", + "statistical-powerDesc": "Sample-size and power analysis — how many subjects you need, minimum detectable effects, and power curves.", + "experimental-design": "Experimental Design", + "experimental-designDesc": "Design rigorous studies before collecting data — randomization, blocking, controls, and factorial/DOE layouts.", + "hypothesis-generation": "Hypothesis Generation", + "hypothesis-generationDesc": "Turn observations into testable hypotheses with predictions, mechanisms, and experiments to test them.", + "scientific-brainstorming": "Scientific Brainstorming", + "scientific-brainstormingDesc": "Open-ended research ideation — explore interdisciplinary links, challenge assumptions, and surface research gaps.", + "tabs": { + "office": "Office Work", + "coding": "Code Development", + "research": "Scientific Research" + }, + "coding": { + "brainstormingDesc": "Explore intent & requirements before building", + "debuggingDesc": "Find the root cause before proposing fixes", + "writingSkillsDesc": "Create, edit & verify reusable skills" + }, + "notEnabled": { + "title": "“{skill}” isn’t enabled for {agent} yet", + "description": "Enable it in Settings to use it here.", + "action": "Enable", + "hint": "Skill not enabled" + }, + "scrollPrev": "Show previous skills", + "scrollNext": "Show more skills" + } + }, + "agentSelector": { + "noEnabledAgents": "No enabled agents", + "openAgentsSettings": "Open Agents settings", + "notInstalled": "Not installed", + "moreAgents": "More agents ({count})" + }, + "subAgentOverlay": { + "title": "Sub-agents", + "collapsedSummary": "Sub-agents {count}", + "collapseAria": "Collapse sub-agents" + }, + "agentPlanOverlay": { + "title": "Agent Plan", + "collapsePlanAria": "Collapse plan", + "collapsedSummary": "Plan {completed}/{total}", + "status": { + "completed": "Completed", + "inProgress": "In Progress", + "pending": "Pending", + "unknown": "Unknown" + }, + "priority": { + "high": "High", + "medium": "Medium", + "low": "Low", + "unknown": "Unknown" + } + }, + "permissionDialog": { + "subtitle": "Agent requests permission to continue this turn.", + "queuedCount": "+{count} waiting", + "kindFallbackTool": "tool", + "command": "Command", + "cwd": "CWD: {cwd}", + "filesSummary": "Files: {count}", + "moreFiles": "+{count} more files", + "plan": "Plan", + "allowedActions": "Allowed actions", + "targetMode": "Target mode: {mode}", + "optionGrants": "What each option grants", + "changeScopeSession": "This session", + "changeScopeProcess": "This run", + "changeScopeUser": "Saved to user settings", + "changeScopeProject": "Saved to project settings", + "changeScopeProjectLocal": "Saved to local project settings", + "changeScopePersistent": "Saved permanently" + }, + "questionDialog": { + "title": "Agent is asking a question", + "placeholder": "Type your answer...", + "send": "Send" + }, + "messageBranch": { + "previousBranchAria": "Previous branch", + "nextBranchAria": "Next branch", + "pageOf": "{current} of {total}" + }, + "terminal": { + "title": "Terminal", + "running": "Running" + }, + "reasoning": { + "thinking": "Thinking…", + "thoughtForFewSeconds": "Thought", + "thoughtForSeconds": "Thought" + }, + "linkSafety": { + "errorCannotOpen": "Cannot open local file", + "errorNoWorkspace": "No workspace folder is currently active.", + "errorFailedOpen": "Failed to open local file", + "errorFailedLink": "Failed to open link", + "errorUnsupportedLinkProtocol": "This link protocol is not supported." + }, + "fileActions": { + "openInFinder": "Open in Finder", + "openInExplorer": "Open in Explorer", + "openInFileManager": "Open in file manager", + "copyRelativePath": "Copy relative path", + "copyAbsolutePath": "Copy absolute path", + "pathCopied": "Path copied", + "copyPathFailed": "Failed to copy path", + "openFailed": "Failed to open local file" + }, + "messageList": { + "attachedResources": "Attached resources", + "loading": "Loading...", + "loadEarlier": "Load earlier messages", + "loadingEarlier": "Loading earlier messages…", + "error": "Error: {message}", + "errorTitle": "Session load failed", + "errorActionReload": "Reload", + "errorActionNewSession": "New conversation", + "emptyConversation": "No messages in this conversation.", + "systemMessage": "System message", + "copyMessage": "Copy", + "copied": "Copied", + "downloadImage": "Download image", + "downloadFailed": "Download failed: {message}", + "imageGeneration": "Image generation", + "imageGenerationPending": "Generating image…", + "imageGenerationFailed": "Image generation failed", + "model": "Model", + "tokenStats": "Token usage", + "tokenInput": "Input", + "tokenOutput": "Output", + "tokenCacheRead": "Cache read", + "tokenCacheWrite": "Cache write", + "duration": "Duration", + "completedAt": "Completed at", + "jumpToPreviousUserMessage": "Jump to user message", + "showMore": "Show more", + "showLess": "Show less" + }, + "liveTurnStats": { + "thinking": "Thinking...", + "streaming": "Streaming", + "elapsedHours": "{value}h", + "elapsedMinutes": "{value}m", + "elapsedSeconds": "{value}s", + "outputSpeedAria": "Estimated output speed", + "outputSpeedTooltip": "Estimated output speed (text + thinking)" + }, + "jsonTree": { + "viewRaw": "Show raw JSON", + "viewTree": "Show tree", + "fields": "{count, plural, one {# field} other {# fields}}", + "items": "{count, plural, one {# item} other {# items}}" + }, + "tool": { + "parameters": "Parameters", + "error": "Error", + "result": "Result", + "status": { + "approvalRequested": "Awaiting Approval", + "approvalResponded": "Responded", + "inputAvailable": "Running", + "inputStreaming": "Pending", + "outputAvailable": "Completed", + "outputDenied": "Denied", + "outputError": "Error" + } + }, + "toolCallBlock": { + "tool": "Tool", + "error": "Error", + "result": "Result" + }, + "delegation": { + "subAgentRunning": "Sub-agent running…", + "noDetail": "No detail available yet.", + "unknownAgent": "Sub-agent", + "openDetail": "Open conversation", + "detailTitle": "Sub-agent conversation", + "detailDescription": "Read-only view of the delegated sub-agent's conversation.", + "waitForResult": "Waiting for task {task} result", + "waitForResultNoTask": "Waiting for task result", + "cancelTask": "Canceling task {task}", + "cancelTaskNoTask": "Canceling task", + "resultPageOf": "{current} / {total}", + "prevResult": "Previous result", + "nextResult": "Next result", + "noResultText": "No result captured for this check.", + "status": { + "starting": "starting", + "running": "running", + "checked": "checked", + "waiting": "awaiting approval", + "ok": "done", + "err": { + "default": "failed", + "delegation_disabled": "disabled", + "depth_limit": "depth limit", + "invalid_agent_type": "bad agent", + "spawn_failed": "spawn failed", + "send_failed": "send failed", + "timeout": "timeout", + "canceled": "canceled", + "child_refusal": "subagent refused", + "child_max_tokens": "subagent token limit", + "child_max_turn_requests": "subagent request limit", + "child_empty": "subagent no output", + "child_unknown": "subagent unknown error", + "unknown": "unknown task" + } + } + }, + "contentParts": { + "showingTailOutput": "Showing tail output while streaming for performance.", + "result": "Result", + "unknown": "unknown", + "inputTruncated": "Input was truncated — diff may be incomplete.", + "replaceAll": "REPLACE ALL", + "filesCount": "Files: {count}", + "update": "update", + "moreFiles": "+{count} more files", + "timeoutMs": "Timeout: {timeout}ms", + "backgroundTrue": "Background: true", + "scriptToolCalls": "{count, plural, one {# tool call} other {# tool calls}}", + "offset": "Offset: {offset}", + "limit": "Limit: {limit}", + "pages": "Pages: {pages}", + "mode": "Mode: {mode}", + "cell": "Cell: {cell}", + "shellSession": "Session {id}", + "pathLabel": "Path:", + "globLabel": "Glob:", + "typeLabel": "Type:", + "outputLabel": "Output:", + "caseInsensitive": "Case insensitive", + "multiline": "Multiline", + "promptLabel": "Prompt", + "subjectLabel": "Subject", + "taskLabel": "Task", + "nameLabel": "Name:", + "agentPromptLabel": "Prompt", + "agentModelLabel": "Model", + "agentRunning": "Running...", + "agentLiveTranscript": "Live activity", + "agentProgressTools": "{count} tool calls", + "agentProgressTurns": "{count} turns", + "agentProgressContext": "context {pct}%", + "agentSessionAction": "View sub-agent session", + "agentSessionTitle": "Sub-agent session", + "agentSessionLoading": "Loading the sub-agent's transcript…", + "agentSessionEmpty": "The sub-agent hasn't written anything yet.", + "agentFallbackTitle": "Sub-agent starting…", + "agentCodexLaunchOnly": "Launched. Codex reports no further progress for this sub-agent — its result arrives as a message in this conversation.", + "agentStatsBash": "Commands", + "agentStatsRead": "Files read", + "agentStatsSearch": "Searches", + "agentStatsEdit": "Edits", + "agentStatsOther": "Other", + "goal": { + "title": "Goal:", + "titleWithStatus": "Goal {status}", + "objective": "Objective", + "statusLabel": "Status", + "tokensUsed": "Tokens used", + "budget": "Budget", + "remaining": "Remaining", + "elapsed": "Elapsed", + "tokens": "tokens", + "pause": "Pause", + "clear": "Clear", + "status": { + "active": "active", + "paused": "paused", + "blocked": "blocked", + "usageLimited": "usage limited", + "budgetLimited": "budget limited", + "complete": "complete", + "limited": "limit reached" + } + }, + "field": { + "file": "File", + "notebook": "Notebook", + "command": "Command", + "old": "Old", + "new": "New", + "pattern": "Pattern", + "path": "Path", + "query": "Query", + "url": "URL", + "description": "Description", + "content": "Content", + "source": "Source", + "prompt": "Prompt", + "subject": "Subject", + "taskId": "Task ID", + "status": "Status", + "skill": "Skill", + "args": "Args", + "offset": "Offset", + "limit": "Limit", + "glob": "Glob", + "type": "Type", + "output": "Output", + "replaceAll": "Replace All", + "language": "Language", + "timeout": "Timeout", + "background": "Background", + "agentType": "Agent Type", + "library": "Library", + "libraryId": "Library ID" + }, + "title": { + "edit": "Edit", + "command": "Command", + "script": "Script", + "waitCommand": "Wait {command}", + "waitCell": "Wait cell {id}", + "terminateCommand": "Terminate {command}", + "terminateCell": "Terminate cell {id}", + "stdinChars": "Stdin {chars}", + "todoWrite": "TodoWrite", + "read": "Read", + "write": "Write", + "notebookEdit": "NotebookEdit", + "editFiles": "Edit ({count} files)", + "editWithTarget": "Edit {target}", + "readWithTarget": "Read {target}", + "writeWithTarget": "Write {target}", + "notebookEditWithTarget": "NotebookEdit {target}", + "globWithPattern": "Glob {pattern}", + "listFilesWithPath": "List files {path}", + "grepWithPattern": "Grep {pattern}", + "taskCreateWithSubject": "TaskCreate: {subject}", + "taskUpdateWithStatus": "TaskUpdate #{id} -> {status}", + "taskUpdate": "TaskUpdate #{id}", + "webFetchWithUrl": "WebFetch {url}", + "webSearchWithQuery": "WebSearch: {query}", + "todosProgress": "Todos ({done}/{total})", + "skillWithName": "Skill: {name}", + "genericWithContext": "{tool}: {context}" + }, + "search": { + "noMatches": "No matches", + "matchSummary": "{matches, plural, one {# match} other {# matches}} in {files, plural, one {# file} other {# files}}", + "fileSummary": "{files, plural, one {# file} other {# files}}", + "moreResults": "{count, plural, one {# more result not shown} other {# more results not shown}}" + }, + "toolGroup": { + "search": "{count, plural, one {Explored # search} other {Explored # searches}}", + "command": "{count, plural, one {Ran # command} other {Ran # commands}}", + "read": "{count, plural, one {Read files # time} other {Read files # times}}", + "memory": "{count, plural, one {Recalled # memory} other {Recalled # memories}}", + "edit": "{count, plural, one {Edited files # time} other {Edited files # times}}", + "fetch": "{count, plural, one {Fetched # resource} other {Fetched # resources}}", + "think": "{count, plural, one {Thought # time} other {Thought # times}}", + "todo": "{count, plural, one {Updated # todo} other {Updated # todos}}", + "task": "{count, plural, one {Ran # task} other {Ran # tasks}}", + "other": "{count, plural, one {Used # tool} other {Used # tools}}", + "errorSuffix": "{count, plural, one {# failed} other {# failed}}", + "joiner": " · " + }, + "planMode": { + "entered": "Entered plan mode", + "planLabel": "Plan", + "reviewApproved": "Plan approved — implementing", + "reviewKept": "Kept in plan mode", + "reviewPending": "Awaiting plan decision", + "submitted": "Plan submitted", + "switched": "Switched mode" + }, + "backgroundTask": { + "title": "Background task", + "titleWithId": "Background task · {id}", + "running": "Running", + "completed": "Completed", + "failed": "Failed", + "stopped": "Stopped", + "exitCode": "exit {code}", + "polledTimes": "Polled {count} times", + "runningInBackground": "Background", + "launchNote": "Running in background · {id}" + }, + "codexScript": { + "outputMissing": "Codex truncated the script output and dropped this command's separator, so none of the output could be attributed to it.", + "sharedWith": "Also contains the output of {commands} — codex truncated their separators away.", + "truncated": "truncated" + } + }, + "messageNav": { + "title": "Message navigation", + "collapse": "Collapse message navigation", + "collapsedSummary": "Messages {count}", + "fileCount": "{count, plural, one {# file} other {# files}}", + "remove": "Remove", + "noDiffDataAvailable": "No diff data available for {filePath}" + }, + "replyArtifacts": { + "title": "Files changed", + "fileCount": "{count, plural, one {# file} other {# files}}", + "newFilesTitle": "New files", + "revealInFolder": "Show in file manager", + "openFile": "Open {filePath}", + "openInEditor": "Open in editor", + "remove": "Remove", + "noDiffDataAvailable": "No diff data available for {filePath}" + }, + "askQuestion": { + "title": "The agent needs your input", + "subtitle": "Answer below, then submit. You can skip anytime.", + "recommended": "Recommended", + "other": "Other", + "otherPlaceholder": "Type your answer…", + "singleSelect": "Single", + "multiSelect": "Multiple", + "skip": "Skip", + "next": "Next", + "submit": "Submit", + "submitError": "Couldn't submit. Please try again." + }, + "planApproval": { + "title": "The agent has a plan — review it", + "emptyPlan": "The agent didn't write a plan. Approve to start building, or request changes.", + "approve": "Approve & build", + "requestChanges": "Request changes", + "abandon": "Abandon", + "feedbackPlaceholder": "What should change?", + "sendChanges": "Send", + "cancel": "Cancel", + "submitError": "Couldn't submit. Please try again." + }, + "feedbackCheckResult": { + "count": "{count, plural, =1 {1 feedback note} other {# feedback notes}}", + "expand": "Show all feedback", + "collapse": "Collapse", + "errorTitle": "Feedback check failed" + }, + "askQuestionResult": { + "title": "Question", + "answeredLabel": "Q&A:", + "awaiting": "Waiting for your answer…", + "declined": "You dismissed this — the agent used its own judgment.", + "noSelection": "No selection" + }, + "configStale": { + "agentConfigTitle": "Agent settings updated", + "modelProviderTitle": "Model provider updated", + "description": "This session is still using its previous configuration. Reconnect to apply — your conversation history is kept.", + "reconnect": "Reconnect to apply", + "reconnecting": "Reconnecting…", + "reconnectDisabledDuringTurn": "Available once the current turn finishes", + "dismiss": "Dismiss", + "reconnectFailed": "Failed to reconnect session", + "applied": "New configuration applied" + }, + "piProjectTrust": { + "title": "This project ships pi resources", + "description": "pi is not loading the repository's own .pi files. Review them to decide.", + "descriptionExecutable": "The repository ships pi extensions, which run code at startup. pi is not loading them. Review before you decide.", + "review": "Review…", + "dismiss": "Dismiss", + "dialogTitle": "Trust this project's pi resources?", + "dialogDescription": "pi only loads a repository's own .pi files once you trust the folder. Trust it only if you trust this repository's contents.", + "executionWarning": "Extensions are code. Trusting this folder lets the repository run them at pi startup with your permissions, before you send any message.", + "scopeNote": "The decision is saved in pi's trust.json for this folder, applies to every folder inside it, and is also used when you run pi yourself in a terminal. You can change it later in Settings → Agents → Pi.", + "trust": "Trust project", + "decline": "Keep unloaded", + "disabledDuringTurn": "Available once the current turn finishes", + "trustedToast": "Project trusted — reconnected so pi loads its resources", + "declinedToast": "Project resources stay unloaded", + "saveFailed": "Failed to save the project trust decision", + "grantTitle": "This project is already trusted", + "grantDescription": "pi loads this repository's own .pi files. Review what that allows.", + "grantInheritedDescription": "A parent folder is trusted, so pi loads this repository's own .pi files. Review what that allows.", + "grantDialogTitle": "This project's pi resources are trusted", + "grantDialogDescription": "pi is allowed to load this repository's own .pi files. Earlier codeg versions granted this automatically when you opened a folder, so you may not have been asked.", + "grantExecutionWarning": "Extensions are code. The repository runs them at pi startup with your permissions, before you send any message.", + "inheritedFrom": "Trusted via", + "revoke": "Revoke trust", + "keepTrusted": "Keep trusted", + "revokedToast": "Trust revoked — reconnected so pi stops loading the project's resources", + "trustedNoReconnect": "Project trusted — it applies the next time pi starts", + "revokedNoReconnect": "Trust revoked — it applies the next time pi starts" + }, + "collabAgent": { + "title": "Sub-agent", + "errorTitle": "Sub-agent task failed", + "statesLabel": "Sub-agents", + "statusRunning": "Running", + "statusCompleted": "Completed", + "statusFailed": "Failed", + "statusPending": "Starting", + "statusInterrupted": "Interrupted", + "statusClosed": "Closed", + "statusNotFound": "Not found", + "opSpawn": "Starting sub-agent", + "opWait": "Fetching sub-agent result", + "opClose": "Closing sub-agent", + "opResume": "Resuming sub-agent" + }, + "contextCompaction": { + "compacting": "Compacting context…", + "compacted": "Context compacted", + "compactedTokens": "Context compacted · {before} → {after} tokens", + "failed": "Context compaction failed" + }, + "sessionFailure": { + "category": { + "connection": "Connection issue", + "access": "Access issue", + "limit": "Limit reached", + "request": "Request rejected", + "service": "Service issue", + "unknown": "Session issue" + }, + "action": { + "retry": "Retry", + "login": "Sign in", + "newSession": "New session" + }, + "recovered": "Recovered", + "retryUnavailable": "No previous message to resend.", + "toggleDetails": "Toggle details" + }, + "backgroundTasks": { + "running": "{count, plural, one {# background task running} other {# background tasks running}}", + "settling": "Syncing background results…", + "settledFallback": "Background task finished ({status})", + "cardRunning": "Running in background", + "cardLaunchedPending": "Launched in background", + "cardCompleted": "Background task completed", + "cardFinishedWithStatus": "Background task finished ({status})", + "cardResultPending": "Result not returned yet" + }, + "proposedPlan": { + "title": "Proposed plan", + "planning": "Planning…" + } + }, + "diffPreview": { + "mode": { + "added": "Added", + "deleted": "Deleted", + "renamed": "Renamed", + "modified": "Modified" + }, + "hunkLabel": "Hunk {index}", + "loadingHunk": "Loading hunk...", + "noDiffData": "No diff data", + "showRemainingLines": "Show {count} more lines" + }, + "conversationContextBar": { + "folderTitle": "Working folder", + "branchTitle": "Working branch", + "searchFolder": "Search folder...", + "searchBranch": "Search branch...", + "noFolders": "No folders", + "noBranches": "No branches", + "noBranch": "(no branch)", + "chatModeLabel": "Chat mode", + "commit": "Commit", + "push": "Push", + "merge": "Merge", + "toasts": { + "folderChanged": "Switched to {name}", + "openFolderFailed": "Failed to open folder", + "switchedToChatMode": "Switched to chat mode", + "openStashFailed": "Failed to open stash window", + "openMergeFailed": "Failed to open merge window" + } + }, + "cloneDialog": { + "title": "Clone Repository", + "repositoryUrl": "Repository URL", + "repositoryUrlPlaceholder": "https://github.com/user/repo.git", + "directory": "Directory", + "directoryPlaceholder": "Select target directory...", + "browseDirectory": "Browse directory", + "cancel": "Cancel", + "clone": "Clone", + "clonePath": "Clone path: {path}" + }, + "toasts": { + "cloneFailed": "Failed to clone repository" + } + }, + "ProjectBoot": { + "title": "Project Boot", + "tabs": { + "shadcn": "shadcn", + "hyperframes": "HyperFrames" + }, + "hyperframes": { + "title": "HyperFrames Video Project", + "subtitle": "Scaffold an HTML-to-video project. Your workspace agent can then write and render it.", + "resolution": "Resolution", + "skillsTitle": "Agent Skills", + "skillsDesc": "Globally install the HyperFrames skills (symlinked) for the selected agents so they can author and render video.", + "recheck": "Re-check", + "installedBadge": "Installed", + "skillsInstall": "Install / update skills", + "skillsInstalling": "Installing skills…", + "skillsInstalled": "HyperFrames skills installed", + "skillsInstallFailed": "Couldn't install HyperFrames skills" + }, + "config": { + "base": "Base", + "style": "Style", + "baseColor": "Base Color", + "theme": "Theme", + "chartColor": "Chart Color", + "iconLibrary": "Icon Library", + "font": "Font", + "fontHeading": "Heading Font", + "menuAccent": "Menu Accent", + "menuColor": "Menu Color", + "radius": "Radius", + "template": "Template", + "createProject": "Create Project", + "sectionStyle": "Style", + "sectionColors": "Colors", + "sectionTypography": "Typography", + "sectionInterface": "Interface" + }, + "preview": { + "loading": "Loading preview..." + }, + "createDialog": { + "title": "Create Project", + "projectName": "Project Name", + "projectNamePlaceholder": "my-app", + "frameworkTemplate": "Framework Template", + "packageManager": "Package Manager", + "saveDirectory": "Save Directory", + "saveDirectoryPlaceholder": "Select directory...", + "browseDirectory": "Browse", + "projectPath": "Project will be created at: {path}", + "advancedOptions": "Advanced Options", + "base": "Base Library", + "enableRtl": "Enable RTL Support", + "enableRtlDescription": "Enable layout support for right-to-left languages (e.g. Arabic, Hebrew)", + "pmChecking": "Checking...", + "pmNotInstalled": "Not installed", + "cancel": "Cancel", + "create": "Create", + "creating": "Creating project..." + }, + "toasts": { + "createFailed": "Failed to create project", + "createSuccess": "Project created successfully", + "openWorkspaceFailed": "Project created, but couldn't open it in the workspace" + }, + "errors": { + "directoryExists": "Target directory already exists", + "commandFailed": "Project creation command failed." + } + }, + "WebServiceSettings": { + "addressSwitchHint": "Switching only changes the address shown and opened here — the service listens on all interfaces and stays reachable at every address.", + "sectionTitle": "Web Service", + "sectionDescription": "Enable to access Codeg remotely via browser", + "port": "Port", + "status": "Status", + "autoStart": "Auto-start", + "autoStartHint": "Start the Web service when Codeg launches", + "running": "Running", + "stopped": "Stopped", + "processing": "Processing...", + "start": "Start", + "stop": "Stop", + "startFailed": "Failed to start", + "stopFailed": "Failed to stop", + "saveConfigFailed": "Failed to save Web service settings", + "open": "Open", + "hide": "Hide", + "show": "Show", + "copy": "Copy", + "qrcode": "QR Code", + "qrcodeTitle": "Scan to Open", + "qrcodeHint": "Scan with your phone to open Codeg in a browser", + "addressLabel": "Access Address", + "tokenLabel": "Access Token", + "tokenHint": "Enter this token when accessing the Web client for the first time", + "tokenPlaceholder": "Leave empty to auto-generate", + "regenerate": "Regenerate", + "stalePortOccupiedTitle": "Port {port} is held by another process", + "stalePortUnknownTitle": "Port {port} status is unclear", + "stalePortHint": "Codeg can't bind here until the port is released. Change the port above, or close the process holding it.", + "errors": { + "alreadyRunning": "Web service is already running", + "invalidAddress": "Invalid host or port format", + "portInUse": "Port {port} is already in use. Close the process using it or choose another port.", + "permissionDenied": "Permission denied. Try a port above 1024 or run with higher privileges.", + "addressUnavailable": "The address is not available on this machine", + "bindFailed": "Failed to bind address" + } + }, + "DirectoryBrowser": { + "title": "Browse Directory", + "pathPlaceholder": "Enter directory path...", + "goHome": "Go to home directory", + "navigateUp": "Go to parent directory", + "select": "Select", + "cancel": "Cancel", + "loading": "Loading...", + "emptyDirectory": "This directory is empty", + "errorLoadingDir": "Failed to load directory", + "permissionDenied": "Permission denied" + }, + "ServerFileBrowser": { + "title": "Pick server file", + "pathPlaceholder": "Enter directory path...", + "goHome": "Go to home directory", + "navigateUp": "Go to parent directory", + "select": "Select", + "cancel": "Cancel", + "loading": "Loading...", + "emptyDirectory": "This directory is empty", + "errorLoadingDir": "Failed to load directory", + "selectedCount": "{count} selected" + }, + "ChatChannelSettings": { + "loading": "Loading...", + "sectionTitle": "Chat Channels", + "sectionDescription": "Configure IM bots to receive event notifications and query coding activity.", + "addChannel": "Add Channel", + "noChannels": "No chat channels configured yet.", + "channelName": "Name", + "channelNamePlaceholder": "My Telegram Bot", + "channelType": "Channel Type", + "lark": "Lark (Feishu)", + "weixin": "WeChat", + "dailyReport": "Daily Report", + "dailyReportTime": "Report Time", + "nameRequired": "Channel name is required.", + "tokenRequired": "Token is required.", + "chatIdRequired": "Chat ID is required.", + "topicMode": "Topic group mode", + "topicModeHint": "Route Telegram forum topics as separate Codeg sessions. The bot must be in a forum supergroup and be allowed to manage topics.", + "loadFailed": "Failed to load channels.", + "saveFailed": "Failed to save changes.", + "connectSuccess": "Channel connected.", + "connectFailed": "Failed to connect", + "disconnectSuccess": "Channel disconnected.", + "disconnectFailed": "Failed to disconnect.", + "testSuccess": "Connection test passed.", + "testFailed": "Connection test failed", + "deleteSuccess": "Channel deleted.", + "deleteFailed": "Failed to delete channel.", + "deleteConfirmTitle": "Delete Channel", + "deleteConfirmMessage": "This will permanently delete the channel and its message logs. Are you sure?", + "cancel": "Cancel", + "delete": "Delete", + "create": "Create", + "save": "Save", + "channelListTitle": "Configured Channels", + "channelListDescription": "Enabled channels will auto-connect when the service starts.", + "editChannel": "Edit Channel", + "editSuccess": "Channel updated.", + "tokenPlaceholderKeep": "Leave blank to keep current", + "weixinScanTitle": "Scan QR Code", + "weixinScanDescription": "Open WeChat and scan the QR code to connect.", + "weixinQrcodeExpired": "QR code expired.", + "weixinRefreshQrcode": "Refresh", + "weixinWaitingScan": "Waiting for scan...", + "weixinPollError": "Connection unstable, retrying...", + "weixinReconnectNotice": "Due to iLink protocol limitations, after each reconnection you must send a message to the bot before event triggers take effect.", + "connect": "Connect", + "disconnect": "Disconnect", + "test": "Test Connection", + "tabs": { + "channels": "Channels", + "commands": "Commands", + "events": "Events", + "other": "Other" + }, + "commands": { + "title": "Built-in Commands", + "description": "Bot commands available in chat channels. In group chats, @Bot is required to process messages.", + "prefixLabel": "Command Prefix", + "prefixDescription": "1-3 non-alphanumeric characters used to trigger bot commands (default /).", + "prefixSaved": "Command prefix saved.", + "prefixSaveFailed": "Failed to save command prefix.", + "prefixInvalid": "Prefix must be 1-3 non-alphanumeric characters.", + "save": "Save", + "folderDesc": "Select working folder", + "agentDesc": "Select AI agent", + "taskDesc": "Create session and run task", + "sessionsDesc": "List active sessions in folder", + "resumeDesc": "Recent conversations / resume a session", + "cancelDesc": "Cancel current task", + "approveDesc": "Approve agent permission request", + "denyDesc": "Deny agent permission request", + "searchDesc": "Search conversations by keyword", + "todayDesc": "Today's activity summary", + "statusDesc": "Channel connection status", + "helpDesc": "Show help message" + }, + "events": { + "title": "Event Notifications", + "description": "When enabled, triggered events will be pushed to the channel.", + "turnComplete": "Turn Complete", + "turnCompleteDesc": "When an agent turn ends", + "error": "Agent Error", + "errorDesc": "When an agent encounters an error", + "permissionRequest": "Permission Request", + "permissionRequestDesc": "When an agent requests permission to act", + "questionRequest": "Agent Question", + "questionRequestDesc": "When an agent asks you a question", + "userPromptSent": "User Message", + "userPromptSentDesc": "When you send a message — the message text is included in the notification", + "saved": "Event filter updated.", + "saveFailed": "Failed to save event filter.", + "loadFailed": "Failed to load settings.", + "retry": "Retry", + "webhooksTitle": "Webhooks", + "webhooksDescription": "POST a JSON payload to one or more URLs when an enabled event fires. The event filter above also applies to webhooks.", + "webhookUrlPlaceholder": "https://example.com/webhook", + "addWebhook": "Add Webhook", + "removeWebhook": "Remove webhook", + "webhookSave": "Save", + "webhooksSaved": "Webhooks saved.", + "webhooksSaveFailed": "Failed to save webhooks.", + "webhookInvalidUrl": "Enter valid http(s) URLs.", + "docsTitle": "Request Format", + "docsMethod": "Method", + "docsContentType": "Content-Type", + "docsNote": "Each enabled event is delivered to every URL. Webhooks are not debounced; the event filter above still applies.", + "editWebhook": "Edit Webhook", + "enableWebhook": "Enable webhook", + "webhookDuplicate": "This URL is already configured.", + "cancel": "Cancel", + "webhooksEmpty": "No webhooks configured yet.", + "deleteWebhookTitle": "Delete Webhook", + "deleteWebhookMessage": "Remove this webhook? Events will no longer be delivered to this URL.", + "delete": "Delete" + }, + "language": { + "title": "Message Language", + "description": "Language used for event notifications, command responses, and daily reports sent to chat channels.", + "saved": "Message language saved.", + "saveFailed": "Failed to save message language.", + "en": "English", + "zh-cn": "Simplified Chinese", + "zh-tw": "Traditional Chinese", + "ja": "Japanese", + "ko": "Korean", + "es": "Spanish", + "de": "German", + "fr": "French", + "pt": "Portuguese", + "ar": "Arabic" + } + }, + "ModelProviderSettings": { + "sectionTitle": "Model Providers", + "sectionDescription": "Manage API provider credentials for agents.", + "filterAll": "All", + "providerListTitle": "Configured Providers", + "addProvider": "Add Provider", + "editProvider": "Edit Provider", + "noProviders": "No model providers configured yet.", + "providerName": "Name", + "providerNamePlaceholder": "e.g. OpenAI, Anthropic", + "apiUrl": "API URL", + "apiUrlPlaceholder": "https://api.openai.com/v1", + "apiKey": "API Key", + "apiKeyPlaceholder": "sk-...", + "apiKeyKeepCurrent": "Leave blank to keep current", + "agentTypes": "Agent Types", + "agentTypesRequired": "At least one agent type is required.", + "agentType": "Agent Type", + "agentTypeRequired": "Agent type is required.", + "agentTypeImmutableHint": "Agent type cannot be changed after creation.", + "model": "Model", + "modelPlaceholderCodex": "gpt-5.6-sol / gpt-5.5", + "modelPlaceholderGemini": "gemini-3-pro-preview", + "claudeMainModel": "Main Model", + "claudeReasoningModel": "Reasoning Model (thinking)", + "claudeHaikuDefaultModel": "Default Haiku Model", + "claudeSonnetDefaultModel": "Default Sonnet Model", + "claudeOpusDefaultModel": "Default Opus Model", + "claudeCustomModelOption": "Custom Model ID", + "claudeCustomModelOptionName": "Custom Model Name", + "claudeCustomModelOptionDescription": "Custom Model Description", + "claudeCustomModelOptionHint": "Adds a single custom entry to Claude's model picker (e.g. a model behind a custom gateway/proxy). Name and description are optional display overrides.", + "nameRequired": "Provider name is required.", + "apiUrlRequired": "API URL is required.", + "apiKeyRequired": "API Key is required.", + "loadFailed": "Failed to load providers.", + "saveFailed": "Failed to save changes.", + "createSuccess": "Provider created.", + "editSuccess": "Provider updated.", + "deleteSuccess": "Provider deleted.", + "deleteConfirmTitle": "Delete Provider", + "deleteConfirmMessage": "This will permanently delete the provider \"{name}\". Are you sure?", + "deleteBlockedByAgent": "{agents} is currently using this provider. Please unlink before deleting.", + "cancel": "Cancel", + "delete": "Delete", + "create": "Create", + "save": "Save", + "affectedRunningSessions": "{count, plural, one {# running session needs to reconnect to apply the change} other {# running sessions need to reconnect to apply the change}}" + }, + "SkillMatrix": { + "loading": "Loading…", + "searchPlaceholder": "Search by name, id, or description", + "empty": "Nothing to show.", + "emptySearch": "No matches for the current search.", + "skillColumn": "Skill", + "selectAll": "Select all visible", + "selectSkill": "Select {name}", + "everything": { + "label": "Bulk", + "enable": "Enable everything (visible)", + "disable": "Disable everything (visible)" + }, + "columnMenu": { + "enableAll": "Enable all skills", + "disableAll": "Disable all skills" + }, + "rowMenu": { + "label": "Batch actions for {name}", + "enableAll": "Enable for all agents", + "disableAll": "Disable for all agents" + }, + "bulk": { + "selected": "{count} selected", + "targetAll": "All agents", + "targetSome": "{count} agents", + "enable": "Enable", + "disable": "Disable", + "clear": "Clear" + }, + "confirm": { + "disableTitle": "Disable these links?", + "disableBody": "This removes {count} codeg-managed skill link(s). Skills occupying a custom directory are left untouched. You can re-enable them anytime.", + "cancel": "Cancel", + "confirm": "Disable" + }, + "toasts": { + "loadFailed": "Failed to load skill statuses", + "applyFailed": "Failed to apply changes", + "enabled": "Enabled {count} link(s)", + "disabled": "Disabled {count} link(s)", + "enabledPartial": "Enabled {ok}, {failed} failed", + "disabledPartial": "Disabled {ok}, {failed} failed" + }, + "detail": { + "enableForAgents": "Enable for agents", + "preview": "SKILL.md preview", + "loadingContent": "Loading content…" + }, + "copyModeHint": "Copied (not linked) — re-enable after updates for the latest version" + }, + "ExpertsSettings": { + "title": "Expert Skills", + "description": "Enable curated, battle-tested skill workflows for your AI coding agents. Each expert is a standalone skill from the superpowers project — codeg manages the central copy and links it into the agents you choose.", + "loading": "Loading experts…", + "loadingContent": "Loading content…", + "emptyExperts": "No experts available. Check the application logs.", + "emptySelection": "Select an expert to see its content and manage activation.", + "emptySearch": "No experts match the current search.", + "searchPlaceholder": "Search experts by name, id, or description", + "enableForAgents": "Enable for agents", + "noAgents": "No ACP agents detected.", + "copyModeWarning": "Copied (not linked). Re-enable after codeg updates to get the latest version.", + "previewTitle": "SKILL.md preview", + "categories": { + "discovery": "Discovery & Design", + "planning": "Planning", + "execution": "Execution", + "quality": "Quality & Testing", + "debugging": "Debugging", + "review": "Review & Integration", + "meta": "Meta" + }, + "states": { + "not_linked": "Not enabled", + "linked_to_codeg": "Enabled", + "linked_elsewhere": "Blocked — another link exists", + "blocked_by_real_directory": "Blocked — a custom skill occupies this name", + "broken": "Broken link" + }, + "badges": { + "userModified": "User modified" + }, + "actions": { + "openCentralDir": "Open central folder", + "refresh": "Refresh" + }, + "toasts": { + "loadFailed": "Failed to load expert details", + "enabled": "Expert enabled for this agent", + "disabled": "Expert disabled for this agent", + "enableFailed": "Failed to enable expert", + "disableFailed": "Failed to disable expert", + "openFolderFailed": "Failed to open folder" + } + }, + "ScienceSettings": { + "title": "Scientific Research Skills", + "description": "Enable curated scientific-research skills for your AI coding agents — hypothesis generation, experimental design, statistics, visualization, critical appraisal, and literature search. codeg manages a central copy and links each skill into the agents you choose.", + "loading": "Loading science skills…", + "emptySkills": "No science skills available. Check the application logs.", + "searchPlaceholder": "Search science skills by name, id, or description", + "categories": { + "ideation": "Ideation", + "design": "Study Design", + "analysis": "Analysis", + "visualization": "Visualization", + "evaluation": "Evaluation", + "literature": "Literature" + }, + "states": { + "not_linked": "Not enabled", + "linked_to_codeg": "Enabled", + "linked_elsewhere": "Blocked — another link exists", + "blocked_by_real_directory": "Blocked — a custom skill occupies this name", + "broken": "Broken link" + }, + "badges": { + "userModified": "User modified", + "needsKey": "Needs API key", + "needsSetup": "May need setup" + }, + "actions": { + "openCentralDir": "Open central folder", + "refresh": "Refresh" + }, + "toasts": { + "openFolderFailed": "Failed to open folder" + } + }, + "OfficeToolsSettings": { + "title": "Office Tools", + "description": "Manage OfficeCLI skills for creating Excel, Word, and PowerPoint files. Install OfficeCLI, sync skills, and enable them per agent.", + "loadingContent": "Loading content…", + "emptySkills": "No skills available. Install OfficeCLI and sync skills to get started.", + "emptySelection": "Select a skill to see its content and manage activation.", + "emptySearch": "No skills match the current search.", + "searchPlaceholder": "Search skills by name, id, or description", + "enableForAgents": "Enable for agents", + "noAgents": "No ACP agents detected.", + "installFirst": "Install OfficeCLI first to enable skills for agents.", + "syncFirst": "Sync skills first to load this skill's content.", + "noContent": "No content available.", + "copyModeWarning": "Copied (not linked). Re-sync to get the latest version.", + "previewTitle": "SKILL.md preview", + "detection": { + "installed": "Installed", + "notInstalled": "Not installed", + "notRunnable": "Installed but not runnable", + "installHint": "Install OfficeCLI to enable office document generation skills for your AI agents.", + "install": "Install", + "uninstall": "Uninstall", + "syncSkills": "Sync Skills" + }, + "categories": { + "general": "General", + "presentations": "Presentations", + "documents": "Documents", + "spreadsheets": "Spreadsheets" + }, + "states": { + "not_linked": "Not enabled", + "linked_to_codeg": "Enabled", + "linked_elsewhere": "Blocked — another link exists", + "blocked_by_real_directory": "Blocked — a custom skill occupies this name", + "broken": "Broken link" + }, + "badges": { + "notSynced": "Not synced" + }, + "actions": { + "refresh": "Refresh" + }, + "toasts": { + "loadFailed": "Failed to load skill details", + "enabled": "Skill enabled for this agent", + "disabled": "Skill disabled for this agent", + "enableFailed": "Failed to enable skill", + "disableFailed": "Failed to disable skill", + "installSuccess": "OfficeCLI installed successfully", + "installFailed": "Failed to install OfficeCLI", + "uninstallSuccess": "OfficeCLI uninstalled", + "uninstallFailed": "Failed to uninstall OfficeCLI", + "syncSuccess": "{synced} skills synced successfully", + "syncPartial": "{synced} skills synced, {errors} failed", + "syncFailed": "Failed to sync skills" + }, + "autoPreviewLabel": "Auto-open preview", + "autoPreviewHint": "When an agent creates or edits a Word, Excel, or PowerPoint file, open its live preview automatically." + }, + "SkillPacksSettings": { + "title": "Skill Packs", + "description": "Curated skill bundles that codeg manages centrally and links into your AI agents — coding experts, scientific research, and office document tools. Enable them per agent below.", + "tabs": { + "experts": "Experts", + "science": "Science", + "office": "Office Tools", + "custom": "Custom" + }, + "actions": { + "openCentralDir": "Open central folder", + "refresh": "Refresh" + }, + "toasts": { + "openFolderFailed": "Failed to open folder" + } + }, + "QuickMessagesSettings": { + "title": "Quick Messages", + "description": "Manage reusable message snippets. Drag to reorder.", + "loading": "Loading quick messages…", + "emptyList": "No quick messages yet. Click \"New\" to create one.", + "emptySelection": "Select a quick message to edit.", + "searchPlaceholder": "Search by title or content", + "untitled": "Untitled", + "actions": { + "new": "New", + "save": "Save", + "delete": "Delete", + "dragSort": "Drag to reorder", + "dragSortMessage": "Drag to reorder quick message: {name}" + }, + "fields": { + "title": "Title", + "titlePlaceholder": "Give this message a short title", + "content": "Content", + "contentPlaceholder": "Write the message content here" + }, + "confirmDelete": { + "title": "Delete quick message?", + "message": "This will permanently delete \"{name}\". Are you sure?", + "cancel": "Cancel", + "confirm": "Delete" + }, + "toasts": { + "loadFailed": "Failed to load quick messages", + "createFailed": "Failed to create quick message", + "saveFailed": "Failed to save quick message", + "deleteFailed": "Failed to delete quick message", + "saveOrderFailed": "Failed to save order", + "created": "Quick message created", + "saved": "Quick message saved", + "deleted": "Quick message deleted" + } + }, + "Pet": { + "badge": { + "running": "{count} running", + "waiting": "{count} awaiting approval", + "error": "{count} errored" + }, + "panel": { + "title": "Active sessions", + "empty": "No active sessions", + "emptyHint": "Running agents and ones that need you appear here.", + "statusRunning": "Running", + "statusWaiting": "Waiting", + "statusError": "Error", + "subAgentOf": "Sub-agent of" + }, + "menu": { + "scale": "Scale", + "openManager": "Manage pets", + "close": "Close" + }, + "loadError": "Failed to load pet", + "missingPetIdParam": "No pet selected", + "summonButton": "Pet", + "manager": { + "title": "Pets", + "description": "Floating desktop companions powered by Codex-compatible sprite sheets.", + "addPet": "Add pet", + "importFromCodex": "Import from Codex", + "noPets": "No pets yet. Add one or import from Codex.", + "setActive": "Set active", + "active": "Active", + "edit": "Edit", + "delete": "Delete", + "deleteConfirm": "Delete pet \"{name}\"? It will be removed from disk.", + "summon": "Summon pet window", + "openCodexHelp": "Codex pets must be installed under ~/.codex/pets/. None found.", + "specRequirement": "Spritesheet must be 1536px wide with a height in 208px rows (e.g. 1872 or 2288), PNG or WebP with transparency.", + "form": { + "id": "Pet ID", + "idHelp": "Lowercase letters, digits, '-' and '_'. Max 64 chars.", + "displayName": "Display name", + "description": "Description (optional)", + "spritesheet": "Spritesheet", + "chooseFile": "Choose file", + "replaceFile": "Replace spritesheet", + "saveCreate": "Add pet", + "saveUpdate": "Save changes", + "cancel": "Cancel" + }, + "errors": { + "missingId": "Pet id is required", + "missingName": "Display name is required", + "missingSpritesheet": "Spritesheet is required", + "addFailed": "Failed to add pet", + "updateFailed": "Failed to update pet", + "deleteFailed": "Failed to delete pet", + "loadFailed": "Failed to load pets", + "setActiveFailed": "Failed to set active pet", + "summonFailed": "Failed to summon pet window" + } + }, + "import": { + "title": "Import from Codex", + "subtitle": "These pets are available under ~/.codex/pets/.", + "selectAll": "Select all", + "alreadyImported": "Already imported", + "renameOnConflict": "Rename conflicts with -imported suffix", + "import": "Import selected", + "noneFound": "No importable Codex pets found.", + "imported": "Imported successfully", + "failed": "Import failed", + "close": "Close" + }, + "marketplace": { + "openMarketplace": "Pet marketplace", + "title": "Pet marketplace", + "search": "Search pets", + "kindFilter": { + "all": "All", + "object": "Object", + "animal": "Animal", + "person": "Person", + "creature": "Creature" + }, + "sortFilter": { + "latest": "Latest", + "popular": "Popular", + "views": "Most viewed" + }, + "refresh": "Refresh", + "install": "Install", + "installing": "Installing", + "reinstall": "Reinstall", + "reinstallConfirm": "Replace local pet \"{name}\"? Existing data will be overwritten.", + "cancel": "Cancel", + "stats": { + "views": "Views", + "downloads": "Downloads", + "likes": "Likes" + }, + "actions": { + "idle": "Idle", + "running_right": "Run right", + "running_left": "Run left", + "waving": "Wave", + "jumping": "Jump", + "failed": "Fail", + "waiting": "Wait", + "running": "Run", + "review": "Review" + }, + "page": "Page {page} of {total}", + "prev": "Previous", + "next": "Next", + "empty": "No pets match this filter.", + "successInstalled": "Installed \"{name}\"", + "errors": { + "loadFailed": "Failed to load marketplace", + "installFailed": "Failed to install pet", + "alreadyInstalled": "Pet already exists locally" + } + } + }, + "RemoteWorkspace": { + "openRemoteWorkspace": "Open remote workspace", + "manage": "Manage remote workspace", + "manageTitle": "Remote Workspace connections", + "empty": "No remote connections", + "searchPlaceholder": "Search remote workspaces", + "orderFailed": "Failed to save remote workspace order", + "dragSort": "Drag to sort", + "dragSortConnection": "Drag to sort {name}", + "newConnection": "New connection", + "loading": "Loading", + "loadingConnection": "Loading remote connection", + "name": "Name", + "baseUrl": "Service URL", + "token": "Access token", + "save": "Save", + "delete": "Delete", + "confirmDelete": { + "title": "Delete remote connection?", + "message": "This will remove \"{name}\" from this device. This action cannot be undone.", + "cancel": "Cancel", + "confirm": "Delete" + }, + "saved": "Remote connection saved.", + "deleted": "Remote connection deleted.", + "loadFailed": "Failed to load remote connections", + "saveFailed": "Failed to save remote connection", + "deleteFailed": "Failed to delete remote connection", + "openFailed": "Failed to open remote workspace", + "connectionLoadFailed": "Failed to load remote connection: {message}", + "connectionExpired": "Remote connection \"{name}\" is expired. Update its token and reload this window." + }, + "BackupSettings": { + "title": "Backup & Restore", + "description": "Export a portable backup of your codeg data, or restore from one.", + "tabs": { + "backup": "Backup", + "restore": "Restore" + }, + "export": { + "includeExternal": "Include conversation content", + "includeExternalHint": "Also archive agent CLI transcripts (Claude, Codex, Gemini, …). Increases size.", + "passphrase": "Passphrase (optional)", + "passphrasePlaceholder": "Leave empty for an unencrypted archive", + "passphraseConfirm": "Confirm passphrase", + "passphraseMismatch": "Passphrases do not match.", + "noPassphraseWarning": "This backup will contain secrets (API keys, tokens) in plaintext. Store it somewhere safe.", + "passphraseLossWarning": "Encrypted with this passphrase. If you lose it, the backup cannot be recovered.", + "button": "Export backup", + "inProgress": "Creating backup…", + "success": "Backup created.", + "started": "Backup download started." + }, + "restore": { + "selectFile": "Select backup file", + "passphrasePrompt": "This backup is encrypted. Enter its passphrase.", + "unlock": "Unlock", + "preview": { + "title": "Backup details", + "encrypted": "Encrypted", + "compatible": "Compatible", + "incompatible": "Incompatible", + "createdAt": "Created: {value}", + "appVersion": "App version: {value}", + "incompatibleHint": "This backup was created by a newer version of codeg and cannot be restored." + }, + "replaceWarning": "Restoring replaces all current codeg data (database and uploads). Your current data is snapshotted first so it can be recovered.", + "keyringNote": "Desktop GitHub/chat tokens live in your OS keychain and are not included; re-enter them after restoring.", + "button": "Restore", + "staging": "Preparing restore…", + "staged": "Restore staged. Restarting…", + "restarting": "Restore staged. Restarting the server…", + "restartTimeout": "The server did not come back in time. Reload the page once it is up.", + "externalSideLocation": "Conversation transcripts were restored to {path}", + "confirmTitle": "Replace all data?", + "confirmBody": "This will replace your current codeg database and uploads with the backup, then restart. Your current data is snapshotted first.", + "cancel": "Cancel", + "confirmAction": "Replace & restart", + "external": { + "title": "Conversation content", + "hint": "This backup includes agent CLI transcripts. Choose where to restore them.", + "modeSkip": "Don't restore", + "modeSide": "Restore to a safe side folder", + "modeOriginal": "Restore to original CLI locations", + "forceOverwrite": "Overwrite existing files", + "forceOverwriteHint": "Replace files that already exist in the agent CLI folders.", + "scanning": "Checking for conflicts…", + "noConflicts": "No existing files would be overwritten.", + "conflictCount": "{count} existing file(s) would be affected.", + "conflictSkipNote": "Existing files are kept (skipped) unless you enable overwrite." + }, + "restartFailed": "Restore staged, but the server couldn't restart. Restart it manually to apply the restore." + }, + "remoteUnsupported": "Backup & restore acts on the data of the machine running codeg. You're connected to a remote workspace — manage its backups from that server directly." + }, + "backup": { + "restore": { + "error": { + "badPassphrase": "Incorrect passphrase or corrupted backup.", + "corrupted": "The backup archive is corrupted.", + "unknownFormat": "This file is not a recognized codeg backup.", + "newerVersion": "This backup was created by codeg {backupVersion}, newer than this version ({appVersion}).", + "alreadyPending": "A restore is already staged. Restart to apply it before staging another." + } + }, + "error": { + "diskSpace": "Not enough disk space to complete the operation.", + "cancelled": "The operation was cancelled." + } + }, + "WebConnection": { + "disconnectedTitle": "Connection lost", + "reconnectingDescription": "Trying to reconnect to the server. This usually recovers on its own within a few seconds.", + "reconnectNow": "Reconnect now", + "sessionExpiredTitle": "Session expired", + "sessionExpiredDescription": "Your session is no longer valid. Please sign in again to continue.", + "goToLogin": "Go to login" + }, + "LiveFeedback": { + "placeholder": "Send a note to {agent} while it works…", + "agentFallback": "the agent", + "ariaLabel": "Live feedback note", + "dialogTitle": "Live feedback", + "dialogDescription": "Send a note to the agent while it works. It reads your note the next time it checks — without interrupting the current step.", + "dialogDescriptionInstant": "Send a note to the agent while it works. It lands in the current turn immediately — the agent sees it right away.", + "channelDowngraded": "Instant insert isn't available in this session — your note was saved for the agent to pick up on its next check.", + "send": "Send", + "cancel": "Cancel", + "pending": "waiting", + "delivered": "received", + "turnEndedUnread": "The agent finished before reading your feedback.", + "sendAsMessage": "Send as message", + "dismiss": "Dismiss", + "turnEndedResent": "The turn ended — sent as a new message instead.", + "turnEnded": "The turn already ended.", + "submitFailed": "Couldn't send your note" + }, + "AgentToolsSettings": { + "title": "In-conversation tools", + "description": "Extra tools codeg gives an agent inside a conversation. Each is injected when the agent starts, so a change applies to agents started afterwards.", + "feedbackLabel": "Live Feedback", + "feedbackHint": "Send notes and corrections to an agent while it's working. When the agent supports instant steering, your note is inserted into the running turn immediately; otherwise the agent gets a tool to check for your feedback — those agents typically only check when you mention it in your prompt, for example add \"check my live feedback regularly\" to your message.", + "questionLabel": "Ask user question", + "questionHint": "Let agents pause and ask you a multiple-choice question that appears above the conversation input box. The agent waits until you answer (or skip).", + "sessionInfoLabel": "Get session info", + "sessionInfoHint": "Let agents look up a session you reference in your message (a session badge) to read its title, agent, status, workspace, token usage, and recent messages.", + "automationsLabel": "Create automations", + "automationsHint": "Save the conversation as an automation that runs on a schedule. Off by default — it goes on to start agents on its own.", + "workTasksLabel": "Create to-do tasks", + "workTasksHint": "Queue a card on the to-do board from the conversation. Off by default — it writes app state.", + "save": "Save", + "saving": "Saving…", + "saved": "Tool settings saved", + "saveFailed": "Failed to save tool settings", + "loadFailed": "Failed to load: {detail}" + }, + "NotificationSoundSettings": { + "title": "Notification sounds", + "description": "Play a short sound when an agent event fires. These are the same events the chat channels push — configured here for this device only.", + "enableHint": "Off by default. Sounds play in the workspace window of this browser or app only.", + "volume": "Volume", + "preview": "Preview", + "previewEvent": "Preview the {event} sound", + "onlyWhenUnfocused": "Only when the window is not focused", + "onlyWhenUnfocusedHint": "Stay silent while you are looking at Codeg.", + "eventsTitle": "Events", + "eventsHint": "Pick a tone per event, or “Silent” to skip it. Repeats of the same event within a couple of seconds play once.", + "toneNone": "Silent", + "toneChime": "Chime", + "toneDing": "Ding", + "toneBlip": "Blip", + "tonePop": "Pop", + "toneAlert": "Alert", + "toneDescend": "Descending" + }, + "LogsSettings": { + "loading": "Loading…", + "sectionTitle": "Runtime Logs", + "sectionDescription": "View and configure application diagnostic logs. Logs are written to local files and kept in memory for live viewing.", + "captureTitle": "Log level", + "captureDescription": "Controls how much detail is captured. Higher levels (Debug, Trace) record more but produce larger logs. Off disables logging.", + "captureLabel": "Capture level", + "levels": { + "off": "Off", + "error": "Error", + "warn": "Warning", + "info": "Info", + "debug": "Debug", + "trace": "Trace" + }, + "viewerTitle": "Recent logs", + "viewerDescription": "Live view of recent log records. Filter by level or search text.", + "searchPlaceholder": "Search message or target…", + "viewLevels": { + "all": "All levels", + "error": "Error+", + "warn": "Warning+", + "info": "Info+", + "debug": "Debug+", + "trace": "Trace+" + }, + "pause": "Pause", + "resume": "Live", + "refresh": "Refresh", + "clear": "Clear", + "openFolder": "Open folder", + "shownCount": "{shown} / {total} shown", + "empty": "No logs to display.", + "levelSaveFailed": "Failed to save log level", + "openFolderFailed": "Failed to open log folder", + "downloadFailed": "Failed to download log file", + "filesTitle": "Log files", + "filesDescription": "Download full log files from disk for history beyond the live buffer.", + "filesEmpty": "No log files yet.", + "download": "Download", + "downloadTruncated": "File is large; downloaded the latest {size}. The full file is in the logs directory.", + "captureEnvLocked": "Log level is controlled by the RUST_LOG / CODEG_LOG environment variable; change it there to take effect.", + "targetsTitle": "Per-module overrides", + "targetsDescription": "Set a different level for specific modules (e.g. codeg_lib::acp) without changing the global level.", + "targetsAdd": "Add", + "targetsRemove": "Remove override", + "toggleDetails": "Toggle details" + }, + "Automations": { + "title": "Automations", + "new": "New automation", + "empty": "No automations yet", + "emptyHint": "Create one to run an agent task on a schedule or on demand.", + "name": "Name", + "namePlaceholder": "e.g. Nightly PR review", + "prompt": "Prompt", + "promptPlaceholder": "What should the agent do?", + "agent": "Agent", + "folder": "Workspace folder", + "folderPlaceholder": "Select a folder", + "isolation": "Isolation", + "isolationWorktree": "New worktree per run", + "isolationShared": "Run in the folder", + "isolationSharedCaveat": "Runs use this folder's working tree directly — they can collide with your uncommitted changes. Enable the worktree option to isolate each run.", + "trigger": "Trigger", + "triggerSchedule": "On a schedule", + "triggerManual": "Manual only", + "cron": "Schedule (cron)", + "cronPlaceholder": "0 9 * * 1-5", + "timezone": "Timezone", + "nextRun": "Next run", + "branch": "Branch", + "branchOptional": "Branch (optional)", + "enabled": "Enabled", + "save": "Save", + "cancel": "Cancel", + "edit": "Edit", + "delete": "Delete", + "runNow": "Run now", + "cancelRun": "Cancel run", + "runHistory": "Run history", + "noRuns": "No runs yet", + "allFolders": "All folders", + "filterAll": "All", + "noMatches": "No matching automations", + "viewConversation": "View conversation", + "lastRun": "Last run", + "never": "Never", + "running": "Running", + "deleteTitle": "Delete automation?", + "deleteDescription": "This removes the automation and its schedule. Run history is kept.", + "statusRunning": "Running", + "statusSucceeded": "Succeeded", + "statusFailed": "Failed", + "statusCancelled": "Cancelled", + "statusSkipped": "Skipped", + "errorName": "Name is required", + "errorPrompt": "Prompt is required", + "errorCron": "A cron expression is required for scheduled automations", + "errorFolder": "Select a workspace folder", + "presetHourly": "Hourly", + "presetDaily": "Daily 9am", + "presetWeekdays": "Weekdays 9am", + "presetCustom": "Custom", + "probing": "Loading options…", + "retry": "Retry", + "configNone": "This agent has no configurable options", + "inherit": "Agent default", + "mode": "Mode", + "config": "Configuration", + "branchPlaceholder": "(default branch)", + "selectHint": "Select an automation to see details", + "refresh": "Refresh", + "onboardTitle": "Automate routine agent tasks", + "onboardHint": "Schedule an agent to review code, update dependencies, or triage issues — on a cadence or on demand.", + "headerSubtitle": "Scheduled and on-demand agent tasks", + "startFromTemplate": "Start from a template", + "blankTitle": "Blank automation", + "blankDesc": "Configure an agent task from scratch.", + "backToTemplates": "Templates", + "sectionSchedule": "Schedule & target", + "sectionTarget": "Target", + "sectionAction": "Action", + "actionLaunchSession": "Launch session", + "actionEnqueueTask": "Enqueue task", + "actionEnqueueTaskHint": "Each fire adds a to-do task titled after this automation to the folder's to-dos; the task engine runs it per the board's settings.", + "sectionPrompt": "Prompt", + "nextIn": "Next in {rel}", + "manual": "Manual", + "schedEveryMinutes": "Every {n} minutes", + "schedHourly": "Hourly", + "schedDaily": "Daily at {time}", + "schedWeekdays": "Weekdays at {time}", + "schedWeekly": "Every {day} at {time}", + "schedMonthly": "Monthly on day {day} at {time}", + "dow0": "Sunday", + "dow1": "Monday", + "dow2": "Tuesday", + "dow3": "Wednesday", + "dow4": "Thursday", + "dow5": "Friday", + "dow6": "Saturday", + "tplCodeReviewTitle": "Code review", + "tplCodeReviewDesc": "Review recent changes for bugs, regressions, and quality issues.", + "tplDependencyUpdatesTitle": "Dependency updates", + "tplDependencyUpdatesDesc": "Find outdated dependencies and propose safe upgrades.", + "tplTestCoverageTitle": "Test coverage", + "tplTestCoverageDesc": "Find untested code paths and add the missing tests.", + "tplTodoSweepTitle": "TODO sweep", + "tplTodoSweepDesc": "Collect TODO and FIXME comments and triage them by priority.", + "tplCiTriageTitle": "CI triage", + "tplCiTriageDesc": "Investigate recent failing checks and propose fixes.", + "tplReleaseNotesTitle": "Release notes", + "tplReleaseNotesDesc": "Summarize changes since the last release into a changelog.", + "tplSecurityAuditTitle": "Security audit", + "tplSecurityAuditDesc": "Scan for vulnerabilities and risky patterns, then report findings.", + "enable": "Enable", + "disable": "Disable", + "moreActions": "More actions", + "statusDisabled": "Disabled", + "cronBuilderTitle": "Schedule builder", + "cronFreqLabel": "Frequency", + "cronFreqMinutes": "Every N minutes", + "cronFreqHourly": "Hourly", + "cronFreqDaily": "Daily", + "cronFreqWeekdays": "Weekdays", + "cronFreqWeekly": "Weekly", + "cronFreqMonthly": "Monthly", + "cronFreqCustom": "Custom", + "cronEveryLabel": "Interval (minutes)", + "cronTimeLabel": "Time", + "cronHourLabel": "Hour", + "cronMinuteLabel": "Minute", + "cronDowLabel": "Day of week", + "cronDomLabel": "Day of month", + "cronApply": "Apply", + "cronPreviewLabel": "Preview", + "cronOpenBuilder": "Open schedule builder", + "branchDefault": "Default branch", + "branchUseCustom": "Use \"{query}\"", + "branchLocal": "Local", + "branchRemote": "Remote", + "branchSearchPlaceholder": "Search branches…", + "branchNone": "No branches" + }, + "Tasks": { + "title": "To-dos", + "new": "New task", + "empty": "No tasks yet", + "emptyHint": "Add a to-do, then run it — the agent works in an isolated worktree and you review and merge the result.", + "emptyColTodo": "No to-dos yet", + "emptyColInProgress": "Nothing in progress", + "emptyColAttention": "Nothing needs you right now", + "emptyColDone": "Nothing done yet", + "allFolders": "All folders", + "showCanceled": "Show canceled", + "showArchived": "Show archived", + "filter": "Filter", + "viewSwitchToBoard": "Switch to board view", + "viewSwitchToList": "Switch to list view", + "statusFilter": "Status", + "statusFilterAll": "All statuses", + "listEmpty": "No tasks match the current filters", + "listColStatus": "Status", + "listColTask": "Task", + "listColLocation": "Location", + "listColChanges": "Changes", + "listColUpdated": "Updated", + "colTodo": "To do", + "colInProgress": "In progress", + "colAttention": "Needs you", + "colDone": "Done", + "statusTodo": "To do", + "statusQueued": "Queued", + "statusPreparing": "Setting up", + "statusRunning": "Running", + "statusAwaitingInput": "Awaiting input", + "statusReview": "To review", + "statusMerging": "Merging", + "statusDone": "Done", + "statusFailed": "Failed", + "statusCanceled": "Canceled", + "statusInterrupted": "Interrupted", + "badgeCleanupFailed": "Cleanup failed", + "badgeWorktreeKept": "Worktree kept", + "badgeWorktreeRemoved": "Worktree removed", + "filesChanged": "{count} files", + "actionStart": "Start", + "actionSchedule": "Schedule", + "actionCancel": "Cancel", + "actionRetry": "Retry", + "actionRequeue": "Requeue", + "actionViewSession": "View session", + "actionEdit": "Edit", + "actionDelete": "Delete", + "actionRetryCleanup": "Retry cleanup", + "actionMerge": "Merge", + "actionUnqueueMerge": "Leave merge queue", + "actionEditQueuedMerge": "Edit queued merge", + "badgeMergeQueued": "Queued to merge", + "badgeMergeQueuedRank": "Queued to merge · #{rank}", + "badgeMergeQueuedHint": "Waiting for the project's current merge to finish; this one starts on its own.", + "actionComplete": "Complete", + "actionAbandon": "Abandon", + "cancelTitle": "Cancel task?", + "cancelDescription": "The task moves to Canceled. Its worktree is kept, and you can requeue it later.", + "cancelReasonLabel": "Reason (optional)", + "cancelReasonPlaceholder": "e.g. wrong approach — I'll rewrite the description", + "cancelKeep": "Never mind", + "cancelSubmit": "Cancel task", + "restartTitleRetry": "Retry task", + "restartTitleRequeue": "Requeue task", + "restartDescription": "Add a note for the agent (optional) — it reaches the prompt of the next run.", + "scheduleTitle": "Schedule task", + "scheduleDescription": "The task stays in To do and starts on its own at the time you pick. The folder's concurrency limit still applies.", + "scheduleDateLabel": "Date", + "schedulePickDate": "Select date", + "scheduleTimeLabel": "Time", + "schedulePreview": "Runs at {time}", + "schedulePastHint": "That time has passed — the task starts as soon as you save.", + "scheduleInAnHour": "In 1 hour", + "scheduleInThreeHours": "In 3 hours", + "scheduleTomorrow": "Tomorrow 9:00", + "scheduleClear": "Clear schedule", + "scheduleBadge": "Scheduled to start at {time}", + "toastScheduled": "Scheduled for {time}", + "toastScheduleCleared": "Schedule cleared", + "actionFollowUp": "Follow up", + "actionAddNote": "Add a note", + "followUpSubmit": "Send", + "followUpIntentRevise": "Rework", + "followUpIntentContinue": "Keep going", + "followUpIntentQuestion": "Ask", + "followUpIntentVerify": "Double-check", + "followUpPlaceholderRevise": "What should the agent change? It continues in the same session.", + "followUpPlaceholderContinue": "What's next? The work so far stays as it is.", + "followUpPlaceholderQuestion": "What do you want to know? The agent answers without touching any file.", + "followUpPlaceholderVerify": "Optional: anything it should look at closely?", + "followUpPlaceholderRetry": "Optional: what should it do differently? e.g. run pnpm install first", + "followUpPlaceholderRequeue": "Optional: why did you cancel it, and what should change this time?", + "actionArchive": "Archive", + "actionUnarchive": "Unarchive", + "archiveAllDone": "Archive all", + "dropToStart": "Release to start", + "errorView": "View", + "notifyReview": "Ready for review: {title}", + "notifyFailed": "Task failed: {title}", + "createFromMessage": "Create task from message", + "detailTokens": "Total tokens", + "editorTitleNew": "New task", + "editorTitleEdit": "Edit task", + "templates": "Templates", + "templatesEmpty": "No templates yet.", + "templateSaveCurrent": "Save current as template", + "templateDelete": "Delete template", + "transcriptTitle": "Task session", + "transcriptDescription": "Read-only live view of the task's agent session.", + "phaseWork": "Task run", + "phaseRetry": "Retry run", + "phaseReturn": "Follow-up", + "phaseMerge": "Merge", + "titleLabel": "Title", + "titlePlaceholder": "What needs to be done?", + "promptLabel": "Task description", + "promptPlaceholder": "Describe the task for the agent — @ to reference files, / for commands", + "folderPlaceholder": "Select a folder", + "agentInheritedHint": "Inherited from task settings — change it to override for this task", + "agentOverrideReset": "Reset to inherited", + "sectionTarget": "Target", + "errorTitle": "Title is required", + "errorPrompt": "Task description is required", + "errorFolder": "Select a folder", + "save": "Save", + "cancel": "Cancel", + "mergeTitle": "Merge task", + "mergeQueuedTitle": "Queued merge", + "mergeQueueHint": "Another task of this project is merging right now. This one joins the queue and starts on its own as soon as that one finishes.", + "mergeQueueUpdateHint": "This task is already waiting to merge. Submitting updates it and keeps its place in the queue.", + "mergeDescription": "Merge {branch} into {base}. Uncommitted changes in the worktree are committed first.", + "mergeMessage": "Commit message", + "mergeMessagePlaceholder": "e.g. feat: add login validation", + "mergeAutoMessage": "Let the agent write the commit message", + "strategySquash": "Combine into one commit", + "strategySquashHint": "All the task's changes land in the main branch as a single history entry — a tidier history.", + "strategyMerge": "Keep full history", + "strategyMergeHint": "Every commit made during the task is kept, plus one merge entry — each step stays traceable.", + "mergeDeleteWorktree": "Delete worktree after merge", + "mergeSubmit": "Merge", + "mergeSubmitQueue": "Add to merge queue", + "mergeQueuedToast": "Added to the merge queue — it starts as soon as the current merge finishes.", + "completeTitle": "Complete task", + "completeDescription": "This task changed no files, so there is nothing to merge — it is marked as done directly.", + "completeDescriptionNoWorktree": "This task's worktree has been removed, so there is no merge to run — it is marked as done directly. A work branch that still holds unmerged commits is kept.", + "completeDeleteWorktree": "Delete the worktree after completing", + "completeSubmit": "Complete", + "settingsTitle": "Task settings", + "settingsDescription": "Defaults for tasks in {folder}.", + "settingsScope": "Scope", + "settingsScopeGlobal": "All folders (global defaults)", + "settingsScopeGlobalHint": "Folders without their own settings use these global defaults.", + "settingsSource": "Configuration", + "settingsSourceGlobal": "Global defaults", + "settingsSourceCustom": "Custom", + "settingsSourceGlobalFollow": "Follows the global task settings — changes there apply here automatically.", + "settingsSourceCustomHint": "Saves this folder's own settings; it stops following the global defaults.", + "settingsAgent": "Default agent", + "settingsMaxConcurrent": "Max concurrent tasks", + "settingsMaxConcurrentHint": "0 = unlimited", + "settingsAutoProcess": "Process automatically", + "settingsAutoProcessHint": "To-dos start on their own, up to the concurrency limit.", + "settingsMergeStrategy": "Default merge strategy", + "settingsMergeStrategyHint": "How the task's changes are recorded in the branch history when merged.", + "settingsAutoMerge": "Merge automatically", + "settingsAutoMergeHint": "A task that reaches review with something to land merges as if you clicked Merge: the agent writes the commit message, and the worktree follows the default below. A red preflight or a failed merge leaves the task waiting for you.", + "settingsDeleteWorktree": "Delete the worktree after merging", + "settingsDeleteWorktreeHint": "Pre-selects the option in the merge dialog; you can still change it there.", + "settingsWorktreeRoot": "Worktree location", + "settingsWorktreeRootHint": "Directory new task worktrees are created in — one per task. Leave it empty to keep them next to the project folder; \"~\" is your home directory, and a relative path resolves against the project folder.", + "settingsWorktreeRootPlaceholder": "~/codeg-worktrees", + "settingsWorktreeRootBrowse": "Choose the worktree directory", + "settingsPreflight": "Preflight command", + "settingsPreflightHint": "Runs in the worktree when a task reaches review.", + "settingsPreflightCustomPlaceholder": "pnpm test", + "settingsInitCommand": "Worktree init command", + "settingsInitCommandHint": "Runs inside a freshly created worktree before the agent starts.", + "settingsInitCommandPlaceholder": "pnpm install", + "settingsTabGeneral": "General", + "settingsTabMerge": "Merge", + "settingsTabWorktree": "Worktree", + "settingsTabPrompts": "Prompts", + "settingsPromptsIntro": "Each stage already sends a built-in prompt — the task itself, the worktree rules, and for merging the exact git steps. Text you add here is appended at the end as extra instructions: it refines those built-ins, it never replaces them.", + "settingsPromptStageAll": "All stages", + "settingsPromptPlaceholderAll": "e.g. Follow the conventions in AGENTS.md; keep the final summary to two sentences", + "settingsPromptPlaceholderWork": "e.g. Read the related tests first; commit in small steps as you go", + "settingsPromptPlaceholderRetry": "e.g. Check what is already committed before continuing; don't redo finished work", + "settingsPromptPlaceholderReturn": "e.g. Address every point raised; don't refactor anything unrelated", + "settingsPromptPlaceholderMerge": "e.g. Write the landing commit message in English; call out any conflict you resolved by hand", + "settingsPromptHintAll": "Appended to every prompt the agent receives, the merge run included.", + "settingsPromptHintWork": "Appended when a task runs for the first time.", + "settingsPromptHintRetry": "Appended when an interrupted or failed task is picked up again.", + "settingsPromptHintReturn": "Appended when you follow up on a reviewed task (rework, extra work, self-check).", + "settingsPromptHintMerge": "Appended when the agent lands the task onto the base branch.", + "preflightPassed": "{name} passed", + "preflightFailed": "{name} failed", + "preflightRunning": "{name} running…", + "detailDescription": "Task detail", + "detailSummary": "Result", + "detailFiles": "Changed files", + "detailDiffAll": "View full diff", + "detailDiffAllTitle": "Full diff", + "detailNoChanges": "No changes vs the base yet", + "detailTimeline": "Progress", + "detailTimelineEmpty": "No activity yet", + "showMore": "Show more", + "showLess": "Show less", + "detailInfo": "Details", + "detailBranch": "Branch", + "detailMergeCommit": "Merge commit", + "detailChanges": "Changes", + "detailScheduled": "Scheduled start", + "detailCreated": "Created", + "detailStarted": "Started", + "detailFinished": "Finished", + "diffLoading": "Loading diff…", + "deleteConfirmTitle": "Delete task?", + "deleteConfirmBody": "“{title}” will be removed from the board. An active run is canceled first.", + "deleteWithWorktree": "Also delete its worktree", + "eventCreated": "Created", + "eventStatusChanged": "Status changed", + "eventConfigEffective": "Launch config", + "eventInitCommand": "Init command", + "eventAgentProgress": "Agent progress", + "eventAgentVerdict": "Agent verdict", + "eventMergeAttempt": "Merge started", + "eventMergeQueued": "Queued to merge", + "eventMergeConflict": "Merge conflict", + "eventPreflight": "Preflight", + "eventCleanupFailed": "Worktree cleanup failed", + "eventResumeFallback": "Session resume fell back to a new session", + "eventUserAction": "User action", + "eventDiffStat": "Change snapshot" + }, + "CustomSkillsSettings": { + "loading": "Loading custom skills…", + "category": "Custom", + "searchPlaceholder": "Search custom skills by name, id, or description", + "states": { + "not_linked": "Not enabled", + "linked_to_codeg": "Enabled", + "linked_elsewhere": "Linked elsewhere", + "blocked_by_real_directory": "Blocked by a real folder", + "broken": "Broken link" + }, + "actions": { + "new": "New", + "import": "Import", + "importFromAgent": "Import from agent", + "cancel": "Cancel", + "save": "Save" + }, + "rowMenu": { + "edit": "Edit", + "duplicate": "Duplicate", + "delete": "Delete" + }, + "bulk": { + "delete": "Delete selected" + }, + "editor": { + "createTitle": "New custom skill", + "editTitle": "Edit custom skill", + "description": "Custom skills live in the shared store (~/.codeg/skills) and can be enabled for any agent.", + "idLabel": "Skill id", + "idPlaceholder": "e.g. my-workflow", + "contentLabel": "SKILL.md", + "contentPlaceholder": "Write the skill's SKILL.md here…", + "preview": "Preview", + "edit": "Edit", + "emptyBody": "No content yet." + }, + "duplicate": { + "title": "Duplicate skill", + "description": "Create a copy of \"{id}\" with a new id.", + "newIdPlaceholder": "New skill id", + "confirm": "Duplicate" + }, + "import": { + "title": "Choose a skill folder to import" + }, + "importFromAgent": { + "title": "Import skills from an agent", + "description": "Copy an agent's own skills into the shared store so you can enable them for any agent.", + "agentLabel": "Agent", + "agentPlaceholder": "Select an agent", + "selectAll": "Select all ({count})", + "loading": "Loading the agent's skills…", + "unsupported": "This agent doesn't expose a skills directory.", + "empty": "This agent has no importable skills.", + "alreadyInLibrary": "In library", + "confirm": "Import selected ({count})" + }, + "delete": { + "title": "Delete custom skills?", + "body": "This removes {count} custom skill(s) from the central store and unlinks them from every agent. This can't be undone.", + "confirm": "Delete" + }, + "toasts": { + "loadFailed": "Failed to load skill", + "idRequired": "Please enter a skill id", + "created": "Custom skill created", + "updated": "Custom skill updated", + "saveFailed": "Failed to save skill", + "imported": "Skill imported", + "importFailed": "Failed to import skill", + "duplicated": "Skill duplicated", + "duplicateFailed": "Failed to duplicate skill", + "deleted": "Deleted {count} skill(s)", + "deletedPartial": "Deleted {ok}, {failed} failed", + "deleteFailed": "Failed to delete skills", + "importedFromAgent": "Imported {count} skill(s)", + "importedFromAgentPartial": "Imported {ok}, {failed} failed", + "importFromAgentAllSkipped": "Nothing to import — {count} already in the library", + "importFromAgentFailed": "Failed to import from agent" + } + }, + "CodexModelEditor": { + "customizedNotice": "You've customized the model list, so codeg now manages codex's full model table. Official models codex ships later won't appear automatically — click the refresh button below and save again to sync them. Clear your customizations to let codex update automatically.", + "officialsTitle": "Official models", + "officialsHint": "Auto-included from the codex you launch; remove any you don't want.", + "officialsEmpty": "No official models available.", + "refresh": "Refresh from codex", + "readdOfficial": "Re-add official", + "customsTitle": "Custom models", + "customsEmpty": "No custom models yet.", + "addCustom": "Add custom", + "slugPlaceholder": "Model id (slug)", + "displayNamePlaceholder": "Display name", + "contextWindow": "Context", + "makeDefault": "Set as default", + "defaultHint": "Default model", + "remove": "Remove", + "advanced": "Advanced", + "baseTemplate": "Base template", + "baseTemplateHint": "Official model to clone required fields (system prompt, tools, limits) from.", + "groupBehavior": "Behavior & capabilities", + "fieldReasoningLevel": "Default reasoning", + "fieldReasoningSummary": "Reasoning summary", + "fieldVerbosity": "Verbosity", + "fieldShellType": "Shell type", + "fieldApplyPatch": "Apply-patch tool", + "fieldReasoningSummaries": "Reasoning summaries", + "fieldSupportVerbosity": "Verbosity control", + "fieldParallelToolCalls": "Parallel tool calls", + "fieldSearchTool": "Web search tool", + "optNone": "None", + "groupInstructions": "Description & system prompt", + "fieldDescription": "Description", + "baseInstructions": "System prompt (base_instructions)" + }, + "DiagnosticsSettings": { + "title": "Environment diagnostics", + "description": "Checks how this app resolves the agent CLI inside its own process, which can differ from your terminal.", + "loading": "Running diagnostics…", + "error": "Diagnostics failed", + "rerun": "Re-run", + "copyAll": "Copy all", + "copied": "Diagnostics copied to clipboard", + "button": "Diagnose", + "verdict": { + "ok": "Environment looks healthy. If it still shows as not installed, fully restart the app so the prefix cache refreshes.", + "node_missing": "Node.js was not found on the app PATH.", + "npm_missing": "npm was not found on the app PATH.", + "not_installed": "This agent does not appear to be installed.", + "installed_but_unresolved": "The agent is recorded as installed, but the app cannot locate its executable.", + "user_prefix_not_on_path": "Installed into the fallback prefix (~/.codeg/npm-global), which is not on the app PATH. Fully restart the app and try again.", + "homebrew_bin_not_on_path": "Installed under the Homebrew bin, which is not on the app PATH (Apple Silicon keg split).", + "terminal_only_path": "The command resolves in your terminal but not in the app — a GUI PATH gap. Launch the app from a terminal, or reinstall from Agent Settings.", + "npm_prefix_timeout": "npm prefix -g was too slow (over 1.5s), so fallback detection was skipped. Restart the app and try again.", + "node_too_old": "Your active Node.js is older than this agent requires. Upgrade Node.js.", + "adapter_missing_native_present": "Your own {agent} CLI is installed, but Codeg launches a separate ACP adapter package — and that one isn't installed yet. Install it from Agent Settings; it won't touch your CLI and shares the same sign-in.", + "adapter_missing": "Codeg launches a separate ACP adapter package for {agent}, and it isn't installed yet. Install it from Agent Settings — installing the vendor CLI alone is not enough." + } + }, + "TokenUsage": { + "title": "Token Usage", + "rangeLabel": "Time range", + "range7d": "7 days", + "range30d": "30 days", + "range90d": "90 days", + "rangeThisMonth": "This month", + "rangeThisYear": "This year", + "rangeAll": "All time", + "rangeCustom": "Custom", + "moreRanges": "More", + "customRangePick": "Pick a date range", + "bucketLabel": "Group by", + "bucketDay": "Day", + "bucketWeek": "Week", + "bucketMonth": "Month", + "bucketUnitDay": "day", + "bucketUnitWeek": "week", + "bucketUnitMonth": "month", + "folderFilter": "Folders", + "allFolders": "All folders", + "agentFilter": "Agents", + "allAgents": "All agents", + "modelFilter": "Models", + "allModels": "All models", + "searchPlaceholder": "Search…", + "noMatches": "No matches", + "clearFilter": "Clear selection", + "resetFilters": "Reset filters", + "refresh": "Refresh", + "rebuild": "Rebuild all", + "rebuildHint": "Re-reads every transcript from scratch. Use this if a session grew outside codeg.", + "syncing": "Counting sessions…", + "syncProgress": "{done} / {total}", + "syncDone": "Counted {synced} sessions", + "syncFailed": "Could not read some sessions", + "syncBusy": "A refresh is already running", + "lastSynced": "Updated {time}", + "lastSyncedNever": "Never updated", + "tileTotal": "Total tokens", + "tileSessions": "Sessions", + "tileTurns": "Turns", + "tileActiveDays": "Active days", + "tileGenTime": "Generation time", + "vsPrevious": "vs. previous period", + "deltaNew": "new", + "trendTitle": "Usage over time", + "trendEmpty": "No usage in this range", + "trendTurns": "Turns", + "trendSessions": "Sessions", + "compositionTitle": "What the tokens were", + "compositionHint": "Input is what you sent, output is what the model wrote, and cache reads are context you didn't pay full price for.", + "compositionNote": "Re-sending those cache hits at full price would have cost another {value}.", + "inputTokens": "Input", + "outputTokens": "Output", + "cacheWrite": "Cache write", + "cacheRead": "Cache read", + "freshTokens": "Fresh compute", + "cacheHitCaption": "Cache hit", + "cacheHeroTitleHigh": "Most context never got re-sent", + "cacheHeroTitleLow": "Most context still bills at full price", + "cacheHeroDesc": "The cache carried {cached} of context — only {fresh} was freshly computed in this period.", + "cacheSavedSuffix": "That saved re-sending the equivalent of {saved}.", + "avgPerSession": "Avg. per session", + "avgTurnsPerSession": "{count} turns per session", + "avgPerActiveDay": "Avg. per active day", + "peakBucket": "Busiest {bucket}", + "peakHour": "Peak hour", + "daysValue": "{count} days", + "idleDays": "Idle days", + "byFolderTitle": "By folder", + "byAgentTitle": "By agent", + "byModelTitle": "By model", + "distributionTitle": "Usage distribution", + "distributionHint": "Sessions and tokens grouped by the selected dimension — click a row to filter by it.", + "otherLabel": "Other", + "unknownModel": "Unspecified model", + "emptyBreakdown": "Nothing recorded yet", + "sessionsCount": "{count} sessions", + "heatmapTitle": "When you build", + "heatmapHint": "Tokens by local weekday and hour.", + "heatmapPeakHint": "Densest around {hour}:00.", + "less": "Less", + "more": "More", + "heatmapCell": "{weekday} {hour}:00 — {value} tokens", + "weekMon": "Mon", + "weekTue": "Tue", + "weekWed": "Wed", + "weekThu": "Thu", + "weekFri": "Fri", + "weekSat": "Sat", + "weekSun": "Sun", + "topSessionsTitle": "Heaviest sessions", + "untitledSession": "Untitled session", + "topSessionsEmpty": "No sessions in this range", + "streakLongest": "Longest streak", + "streakLongestDays": "Longest streak {count} days", + "share": "Share", + "moreActions": "More actions", + "shareDialogTitle": "Share your usage card", + "shareDialogHint": "A snapshot of the range and filters you're looking at.", + "shareSave": "Save image", + "shareCopy": "Copy image", + "shareCopied": "Copied to clipboard", + "shareSaved": "Image saved", + "shareFailed": "Could not create the image", + "shareRendering": "Rendering…", + "cardHeading": "My AI coding stats", + "cardRangeAll": "All time", + "cardTotalLabel": "Tokens used", + "cardFooter": "Made with codeg", + "cardTopModels": "Top models", + "cardTopProjects": "Top projects", + "archetypeNightOwl": "Night Owl", + "archetypeNightOwlDesc": "{percent}% of your tokens burn after dark.", + "archetypeEarlyBird": "Early Bird", + "archetypeEarlyBirdDesc": "{percent}% of your tokens land before 9am.", + "archetypeWeekendWarrior": "Weekend Warrior", + "archetypeWeekendWarriorDesc": "{percent}% of your tokens happen on the weekend.", + "archetypeCacheMaster": "Cache Master", + "archetypeCacheMasterDesc": "{percent}% of your context came from cache.", + "archetypeMarathoner": "Marathoner", + "archetypeMarathonerDesc": "{days} days building without a break.", + "archetypePolyglot": "Polyglot", + "archetypePolyglotDesc": "{count} agents in serious rotation.", + "archetypeLaserFocus": "Laser Focus", + "archetypeLaserFocusDesc": "{percent}% of your tokens went to one project.", + "archetypeDeepDiver": "Deep Diver", + "archetypeDeepDiverDesc": "{averageK}K tokens in an average session.", + "archetypeSteady": "Steady Builder", + "archetypeSteadyDesc": "{days} days of shipping.", + "emptyTitle": "Nothing counted yet", + "emptyHint": "Codeg reads token counts straight from each agent's own transcript. Run a refresh to count what's already on this machine.", + "emptyAction": "Count my sessions", + "loadFailed": "Could not load usage", + "truncatedNotice": "This range is very large — the numbers cover only the most recent slice of it." + } +} diff --git a/src/i18n/messages/es.json b/src/i18n/messages/es.json index 663f1b60b..891543642 100644 --- a/src/i18n/messages/es.json +++ b/src/i18n/messages/es.json @@ -1,4958 +1,4958 @@ -{ - "Language": { - "followSystem": "Seguir el sistema", - "english": "Inglés", - "simplifiedChinese": "Chino simplificado", - "traditionalChinese": "Chino tradicional", - "japanese": "Japonés", - "korean": "Coreano", - "spanish": "Español", - "german": "Alemán", - "french": "Francés", - "portuguese": "Portugués", - "arabic": "Árabe" - }, - "GitCredentialDialog": { - "title": "Autenticación requerida", - "description": "El servidor remoto requiere credenciales. Introduce tu nombre de usuario y contraseña (o token de acceso personal).", - "username": "Nombre de usuario", - "usernamePlaceholder": "Usuario o correo electrónico", - "password": "Contraseña / Token", - "passwordPlaceholder": "Contraseña o token de acceso personal", - "passwordHint": "Introduce el nombre de usuario y contraseña del servidor.", - "cancel": "Cancelar", - "authenticate": "Autenticar", - "authenticating": "Autenticando...", - "invalidCredentials": "Credenciales inválidas. Inténtalo de nuevo.", - "saveCredentials": "Guardar credenciales para futuras operaciones", - "githubTitle": "Autenticación de GitHub", - "githubDescription": "Introduce un token de acceso personal para conectarte a GitHub. El token se validará y guardará automáticamente.", - "githubToken": "Token de acceso personal", - "githubTokenPlaceholder": "ghp_xxxxxxxxxxxx", - "githubTokenHint": "Genera un token en GitHub → Settings → Developer settings → Personal access tokens.", - "githubAuthenticate": "Validar y conectar", - "generateToken": "Generar token" - }, - "SettingsShell": { - "title": "Configuración", - "preferences": "Preferencias", - "nav": { - "general": "General", - "appearance": "Apariencia", - "agents": "Agentes", - "mcp": "MCP", - "skills": "Skills", - "shortcuts": "Atajos", - "version_control": "Control de versiones", - "system": "Sistema", - "chat_channels": "Canales de chat", - "web_service": "Servicio Web", - "model_providers": "Proveedores de Modelos", - "experts": "Expertos", - "science": "Ciencia", - "office_tools": "Herramientas de oficina", - "skill_packs": "Paquetes de habilidades", - "quick_messages": "Mensajes rápidos", - "logs": "Registros de ejecución" - } - }, - "AppearanceSettings": { - "sectionTitle": "Apariencia del tema", - "sectionDescription": "Elige claro, oscuro o seguir el sistema. La configuración se guarda automáticamente.", - "themeMode": "Modo de tema", - "placeholder": "Selecciona el modo de tema", - "system": "Seguir el sistema", - "light": "Claro", - "dark": "Oscuro", - "currentTheme": "Tema efectivo actual: {theme}", - "resolvedTheme": { - "light": "Claro", - "dark": "Oscuro", - "unknown": "--" - }, - "themeColor": { - "sectionTitle": "Color del tema", - "sectionDescription": "Elige una paleta de colores para acentos, botones y resaltados.", - "current": "Color actual: {color}", - "options": { - "neutral": "Neutral", - "zinc": "Zinc", - "slate": "Slate", - "stone": "Stone", - "gray": "Gray", - "red": "Red", - "rose": "Rose", - "orange": "Orange", - "green": "Green", - "blue": "Blue", - "yellow": "Yellow", - "violet": "Violet" - } - }, - "customStyle": { - "sectionTitle": "Estilo personalizado", - "sectionDescription": "Ajusta los colores del tema actual o inyecta tu propio CSS. Las anulaciones se aplican sobre el preajuste base, así que se conservan al cambiar de preajuste.", - "summarySuspended": "Suspendido", - "summaryDefault": "Preajuste sin cambios", - "summaryTokens": "{count, plural, one {# anulación} other {# anulaciones}}", - "summaryCss": "CSS personalizado", - "suspendedByShortcut": "El estilo personalizado está suspendido. Nada de lo que configures aquí surtirá efecto hasta que lo reanudes.", - "suspendedBySafeParam": "Esta ventana se abrió en modo de apariencia segura, por lo que el estilo personalizado se ignora aquí. Las demás ventanas no se ven afectadas.", - "resume": "Reanudar estilo personalizado", - "enableTheme": "Activar colores personalizados", - "editingLight": "Editando los valores del modo claro. Cambia la aplicación al modo oscuro para configurarlo por separado.", - "editingDark": "Editando los valores del modo oscuro. Cambia la aplicación al modo claro para configurarlo por separado.", - "resetToken": "Restablecer al valor del preajuste", - "radius": "Radio de esquina", - "radiusHint": "De él deriva toda la escala de radios, de sm a 4xl, así que un único control redondea toda la aplicación.", - "advanced": "Avanzado ({count} variables más)", - "enableCss": "Activar CSS personalizado", - "cssRisk": "Función avanzada. El CSS personalizado anula todos los estilos integrados y puede dejar la interfaz inutilizable.", - "editCss": "Editar CSS…", - "cssPresent": "{size} KB guardados", - "cssEmpty": "Todavía no hay nada guardado", - "escapeHint": "¿Interfaz rota? Pulsa {shortcut} para suspender todo el estilo personalizado, o abre una ventana con el parámetro de consulta safeStyle=1.", - "copyTheme": "Copiar JSON del tema", - "importTheme": "Importar tema…", - "clearTheme": "Borrar anulaciones", - "interopHint": "Los temas usan el formato registry:theme de shadcn, así que puedes pegar aquí cualquier tema de shadcn y usar los exportados en cualquier proyecto shadcn.", - "importTitle": "Importar tema", - "importDescription": "Pega un elemento registry:theme de shadcn, un objeto light/dark simple o un mapa plano de tokens.", - "readClipboard": "Leer portapapeles", - "importConfirm": "Importar", - "cancel": "Cancelar", - "apply": "Aplicar", - "toasts": { - "copied": "JSON del tema copiado", - "copyFailed": "No se pudo copiar al portapapeles", - "clipboardReadFailed": "No se pudo leer el portapapeles, pégalo manualmente", - "importFailed": "Ese JSON no contiene variables de tema utilizables", - "imported": "Tema importado" - }, - "css": { - "dialogTitle": "CSS personalizado", - "dialogDescription": "Se aplica a todas las ventanas de codeg. Los cambios se previsualizan en vivo; pulsa Aplicar para guardar.", - "size": "{used} KB / {max} KB", - "ruleCount": "{count} reglas", - "errorTooLarge": "Demasiado grande para guardar. Redúcelo por debajo del límite.", - "errorImportEscaped": "Una regla @import sobrevivió a la eliminación (sintaxis con escapes). Quítala para guardar.", - "warnNoRules": "No se analizó ninguna regla; revisa la sintaxis.", - "noticeImportsRemoved": "Reglas @import eliminadas: {count}. Descargarían hojas de estilo remotas.", - "noticeRemoteUrl": "Contiene una url() remota, que hará una petición de red al aplicarse.", - "noticePreviewSuspended": "El estilo personalizado está suspendido, así que esta vista previa no se aplica.", - "noticeDisabled": "El CSS personalizado está desactivado. Puedes previsualizar aquí, pero no se aplicará hasta que lo actives.", - "hintTokens": "Consejo: tus colores anulados están disponibles como var(--primary), var(--background), etc." - } - }, - "zoomLevel": { - "sectionTitle": "Zoom de ventana", - "sectionDescription": "Escala toda la interfaz. Se aplica al instante y se guarda por dispositivo.", - "placeholder": "Selecciona el nivel de zoom", - "default": "Predeterminado", - "current": "Zoom actual: {zoom}%" - }, - "fonts": { - "sectionTitle": "Fuentes", - "sectionDescription": "Elige las fuentes para la interfaz, el editor de código y el terminal. Las fuentes incluidas se cargan cuando se necesitan; selecciona «Personalizada…» para usar cualquier fuente instalada en tu sistema.", - "interface": "Interfaz", - "editor": "Editor", - "terminal": "Terminal", - "groupSans": "Sans-serif", - "groupMono": "Monoespaciada", - "custom": "Personalizada…", - "customPlaceholder": "Nombre de la fuente, p. ej. Fira Code", - "fontSize": "Tamaño de fuente", - "ligatures": "Activar ligaduras", - "ligaturesUnavailable": "Esta fuente no tiene ligaduras", - "wordWrap": "Activar ajuste de línea", - "terminalLigaturesHint": "Las ligaduras del terminal solo se aplican a las fuentes de programación incluidas.", - "preview": "Vista previa" - }, - "welcomePanel": { - "sectionTitle": "Área de selección de modo", - "sectionDescription": "Las tarjetas de acceso rápido «Desarrollo de código / Ofimática» que se muestran sobre el editor en la página de nueva conversación.", - "showQuickActions": "Mostrar en la página de nueva conversación" - }, - "workspaceBackground": { - "sectionTitle": "Fondo del espacio de trabajo", - "sectionDescription": "Muestra una imagen detrás de todo el espacio de trabajo. La barra lateral y los paneles se vuelven translúcidos y esmerilados para dejar ver la imagen, y una máscara mantiene el texto legible.", - "enable": "Activar imagen de fondo", - "image": "Imagen", - "chooseImage": "Elegir imagen", - "replaceImage": "Reemplazar imagen", - "removeImage": "Quitar", - "fillMode": "Modo de relleno", - "fillModes": { - "cover": "Cubrir", - "contain": "Ajustar", - "center": "Centrar", - "tile": "Mosaico" - }, - "maskOpacity": "Opacidad de la máscara", - "maskOpacityHint": "Los valores más altos difuminan la imagen hacia el color de fondo del tema, mejorando el contraste del texto.", - "imageBlur": "Desenfoque de la imagen", - "panelOpacity": "Opacidad de los paneles", - "panelOpacityHint": "Cuán opacos son la barra lateral, los paneles y las barras de pestañas. Más bajo deja ver más la imagen.", - "errorTooLarge": "La imagen es demasiado grande (máx. 16 MB).", - "errorUploadFailed": "No se pudo establecer la imagen de fondo." - } - }, - "SystemSettings": { - "loading": "Cargando...", - "sectionTitle": "Administración del sistema", - "sectionDescription": "Administra el proxy de red, las actualizaciones de la app y las preferencias de idioma.", - "proxyTitle": "Proxy de red", - "proxyDescription": "Cuando está activado, las solicitudes de red posteriores usarán este proxy preferentemente (incluyendo chat ACP, instalación de agentes y operaciones remotas de Git).", - "loadFailed": "Error al cargar: {message}", - "enableProxy": "Activar proxy del sistema", - "proxyAddress": "Dirección del proxy", - "proxyHint": "Compatible con http(s)/socks5, ejemplo: {example}. Solo funciona cuando el proxy del sistema está activado.", - "save": "Guardar", - "saving": "Guardando...", - "proxyRequired": "Se requiere URL del proxy cuando el proxy está activado", - "saveSuccess": "La configuración del proxy del sistema se guardó", - "saveFailed": "Error al guardar: {message}", - "languageTitle": "Idioma", - "languageDescription": "Configura el idioma de la app. Al seguir el idioma del sistema, los no compatibles vuelven a inglés.", - "appLanguage": "Idioma de la app", - "languageSaveSuccess": "La configuración de idioma se guardó", - "languageSaveFailed": "No se pudo guardar la configuración de idioma: {message}", - "updateTitle": "Actualización de la app", - "versionTitle": "Actualización de software", - "updateDescription": "Comprueba versiones más nuevas en la fuente de versiones configurada e instálalas directamente cuando estén disponibles.", - "currentVersion": "Versión actual", - "upgradableVersion": "Última versión", - "none": "Ninguna", - "lastChecked": "Última comprobación: {time}", - "updateError": "Error de actualización: {message}", - "checking": "Comprobando...", - "checkUpdate": "Buscar actualizaciones", - "updating": "Instalando...", - "downloading": "Descargando...", - "upgradeTo": "Actualizar a v{version}", - "viewRelease": "Ver lanzamiento v{version}", - "foundUpdate": "Nueva versión v{version} encontrada", - "alreadyLatest": "Ya tienes la versión más reciente", - "checkUpdateFailed": "No se pudo buscar actualizaciones: {message}", - "installSuccess": "Actualización instalada. Reiniciando la app.", - "installFailed": "La actualización falló: {message}", - "upgradeSuccess": "Actualización completada. Recargando...", - "restartTimeout": "El servidor no volvió a tiempo. Revisa los registros del contenedor o del servicio.", - "restartingIn": "Reiniciando en {seconds} s...", - "waitingForServer": "Esperando a que el servidor vuelva...", - "restartToUpdate": "Reiniciar para actualizar", - "newVersionBadge": "Nueva v{version}", - "updateAvailableTitle": "Actualización disponible", - "releaseNotesTitle": "Novedades", - "remindLater": "Más tarde", - "retry": "Reintentar", - "stepDownload": "Descarga", - "stepInstall": "Instalación", - "stepRestart": "Reinicio", - "updateReadyHint": "Actualización descargada: reinicia para aplicarla.", - "restarting": "Reiniciando...", - "dockerUpgradeHint": "Esto actualiza el contenedor en ejecución ahora. Se pierde si se recrea el contenedor: para conservarlo, descarga o crea una imagen con la nueva versión y recrea el contenedor.", - "upgradeRolledBack": "La actualización falló; el servidor volvió a la versión anterior.", - "serverUnreachable": "No se pudo conectar con el servidor para iniciar la actualización. Comprueba que esté en ejecución e inténtalo de nuevo.", - "rollbackButton": "Revertir", - "rollingBack": "Revirtiendo...", - "rollbackDescription": "Restaura la versión instalada antes de la última actualización.", - "rollbackConfirmTitle": "¿Revertir a la versión anterior?", - "rollbackConfirmDescription": "El servidor se reiniciará con la versión instalada antes de la última actualización. Una versión más reciente seguirá disponible para instalar de nuevo.", - "rollbackConfirm": "Revertir", - "rollbackCancel": "Cancelar", - "rollbackSuccess": "Se revirtió a la versión anterior. Recargando...", - "rollbackFailed": "Error al revertir. Revisa los registros del servidor.", - "updateErrors": { - "sourceUnavailable": "No se puede acceder al origen de actualización. Revisa tu red o proxy e inténtalo de nuevo.", - "network": "Falló la conexión de red. Revisa tu red o proxy e inténtalo de nuevo.", - "downloadFailed": "No se pudo descargar el paquete de actualización. Inténtalo más tarde.", - "installFailed": "No se pudo instalar la actualización. Cierra la app e inténtalo de nuevo.", - "unknown": "La actualización falló. Inténtalo más tarde." - } - }, - "VersionControlSettings": { - "loading": "Cargando...", - "sectionTitle": "Control de versiones", - "sectionDescription": "Configura el ejecutable de Git y gestiona las cuentas de GitHub.", - "gitTitle": "Configuración de Git", - "gitDescription": "Configura el ejecutable de Git utilizado por la aplicación.", - "gitDetected": "Git detectado", - "gitNotFound": "Git no encontrado en el sistema", - "gitVersion": "Versión", - "gitPath": "Ruta", - "customGitPath": "Ruta personalizada de Git", - "customGitPathPlaceholder": "/usr/bin/git", - "customGitPathHint": "Dejar vacío para usar la ruta detectada automáticamente.", - "test": "Probar", - "testing": "Probando...", - "testSuccess": "El ejecutable de Git es válido.", - "testFailed": "Prueba de Git fallida: {message}", - "save": "Guardar", - "saving": "Guardando...", - "saveSuccess": "Configuración de Git guardada.", - "saveFailed": "Error al guardar: {message}", - "githubTitle": "Cuentas de GitHub", - "githubDescription": "Gestiona las cuentas de GitHub para autenticación. Los tokens se almacenan localmente.", - "noAccounts": "No hay cuentas de GitHub configuradas.", - "addAccount": "Añadir cuenta", - "serverUrl": "URL del servidor", - "serverUrlPlaceholder": "https://github.com", - "token": "Token de acceso personal", - "tokenPlaceholder": "ghp_xxxxxxxxxxxx", - "generateToken": "Generar token", - "tokenHint": "Genera un token en GitHub → Settings → Developer settings → Personal access tokens.", - "validateAndAdd": "Validar y añadir", - "validating": "Validando...", - "addSuccess": "Cuenta {username} añadida correctamente.", - "addFailed": "Error al añadir cuenta: {message}", - "testConnection": "Probar", - "connectionSuccess": "Conexión exitosa.", - "connectionFailed": "Conexión fallida: {message}", - "setDefault": "Establecer como predeterminada", - "defaultLabel": "Predeterminada", - "defaultSet": "Cuenta predeterminada actualizada.", - "removeAccount": "Eliminar", - "removeConfirmTitle": "Eliminar cuenta", - "removeConfirmMessage": "¿Estás seguro de que deseas eliminar la cuenta \"{username}\"?", - "removeConfirm": "Eliminar", - "removeCancel": "Cancelar", - "removeSuccess": "Cuenta eliminada.", - "scopes": "Alcances", - "loadFailed": "Error al cargar configuración: {message}", - "gitAccount": { - "sectionTitle": "Cuentas de servidor Git", - "sectionDescription": "Gestiona credenciales para servidores Git que no son GitHub (GitLab, Bitbucket, autoalojados, etc.).", - "noAccounts": "No hay cuentas de servidor Git configuradas.", - "addAccount": "Añadir cuenta", - "addTitle": "Añadir cuenta Git", - "addDescription": "Introduce la dirección del servidor, nombre de usuario y contraseña o token de acceso.", - "serverUrl": "URL del servidor", - "serverUrlPlaceholder": "https://gitlab.example.com", - "username": "Nombre de usuario", - "usernamePlaceholder": "Usuario o correo electrónico", - "password": "Contraseña / Token", - "passwordPlaceholder": "Contraseña o token de acceso", - "passwordHint": "Introduce tu contraseña o token de acceso del servidor.", - "add": "Añadir", - "serverRequired": "La URL del servidor es obligatoria.", - "usernameRequired": "El nombre de usuario es obligatorio.", - "passwordRequired": "La contraseña es obligatoria." - } - }, - "ShortcutSettings": { - "sectionTitle": "Atajos", - "resetDefault": "Restablecer valores predeterminados", - "recordInstruction": "Haz clic en el botón derecho y luego pulsa una combinación de teclas. Usa Ctrl/Cmd, Alt y Shift. Pulsa Esc para cancelar la grabación.", - "recording": "Pulsa un atajo...", - "toasts": { - "conflict": "El atajo ya está en uso por \"{title}\"", - "updated": "Atajo actualizado", - "invalid": "Atajo no válido, inténtalo de nuevo", - "reset": "Se restauraron los atajos predeterminados" - }, - "actions": { - "toggle_search": { - "title": "Abrir búsqueda", - "description": "Muestra u oculta el panel de búsqueda de conversaciones" - }, - "toggle_sidebar": { - "title": "Alternar barra lateral izquierda", - "description": "Muestra u oculta la barra lateral de lista de conversaciones" - }, - "toggle_terminal": { - "title": "Alternar terminal", - "description": "Muestra u oculta el panel de terminal inferior" - }, - "new_terminal_tab": { - "title": "Nueva terminal", - "description": "Crea una nueva pestaña de terminal cuando el foco está en la terminal" - }, - "close_current_terminal_tab": { - "title": "Cerrar terminal actual", - "description": "Cierra la pestaña de terminal actual cuando el foco está en la terminal" - }, - "toggle_aux_panel": { - "title": "Alternar panel derecho", - "description": "Muestra u oculta el panel de información auxiliar" - }, - "new_conversation": { - "title": "Nueva conversación", - "description": "Crea una nueva pestaña de conversación en la carpeta actual" - }, - "open_folder": { - "title": "Abrir carpeta", - "description": "Abre el selector de carpetas y la carpeta en una nueva ventana" - }, - "open_settings": { - "title": "Abrir configuración", - "description": "Abre la ventana de configuración" - }, - "close_current_tab": { - "title": "Cerrar pestaña actual", - "description": "Cierra la conversación o pestaña de archivo actual" - }, - "close_all_file_tabs": { - "title": "Cerrar todas las pestañas de archivos", - "description": "Cierra todas las pestañas de archivos abiertas cuando el panel de archivos está activo" - }, - "next_tab": { - "title": "Pestaña siguiente", - "description": "Cambiar a la siguiente pestaña de conversación o archivo" - }, - "prev_tab": { - "title": "Pestaña anterior", - "description": "Cambiar a la pestaña anterior de conversación o archivo" - }, - "send_message": { - "title": "Enviar mensaje", - "description": "Enviar el mensaje actual en el cuadro de entrada" - }, - "newline_in_message": { - "title": "Nueva línea en mensaje", - "description": "Insertar una nueva línea en el cuadro de entrada" - }, - "toggle_custom_style": { - "title": "Suspender/reanudar estilo personalizado", - "description": "Vía de escape: desactiva todos los colores y el CSS personalizados, y los vuelve a activar" - } - } - }, - "SkillsSettings": { - "title": "Skills", - "description": "Selecciona una Skill a la izquierda. A la derecha se muestra una vista previa de Markdown por defecto; cambia a edición para modificar y guardar.", - "loadingAgents": "Cargando agentes compatibles con Skills...", - "emptyNoManageableAgents": "No hay agentes disponibles para gestionar Skills.", - "managedTarget": "Objetivo gestionado", - "selectAgentPlaceholder": "Selecciona un agente", - "searchPlaceholder": "Buscar por nombre / ID / ruta...", - "skillsList": "Lista de Skills", - "loadingSkills": "Cargando Skills...", - "agentNotSupported": "El agente actual no admite gestión de Skills.", - "emptySkills": "Aún no hay Skills. Haz clic en \"Nueva Skill\" para crear una.", - "newSkillTitle": "Nueva Skill", - "skillInfo": "Información de la Skill", - "skillIdPlaceholder": "skill-id (letras/números/-/_/.)", - "skillsDirectoryWithPath": "Directorio de Skills: {path}", - "skillsDirectoryNeedId": "Directorio de Skills: introduce el ID de Skill para generar la ruta completa", - "markdownContent": "Contenido Markdown", - "editingStatus": "Editando", - "previewStatus": "Vista previa", - "contentPlaceholder": "Introduce el contenido Markdown de la Skill...", - "metadataTitle": "Metadatos de Skills", - "onlyYamlMetadata": "Esta Skill solo contiene metadatos YAML.", - "emptyContentHint": "Aún no hay contenido. Haz clic en \"Editar\" para empezar.", - "loadingSkill": "Cargando Skill...", - "emptyNoAgents": "No hay agentes disponibles.", - "noSelectionHint": "Selecciona un Skill a la izquierda o haz clic en \"Nuevo Skill\" para crear uno.", - "systemBadge": "Sistema", - "systemHint": "Skill integrado del CLI · solo lectura", - "scope": { - "global": "Global", - "folder": "Carpeta", - "selectFolderPlaceholder": "Seleccionar una carpeta", - "noFolders": "No se encontraron carpetas", - "pickFolderHint": "Selecciona una carpeta para ver sus Skills." - }, - "actions": { - "preview": "Vista previa", - "edit": "Editar", - "openInWindow": "Abrir en nueva ventana", - "delete": "Eliminar", - "deleting": "Eliminando...", - "refresh": "Actualizar", - "newSkill": "Nueva Skill", - "reset": "Restablecer", - "save": "Guardar", - "saving": "Guardando...", - "cancel": "Cancelar" - }, - "deleteDialog": { - "title": "Eliminar Skill", - "confirm": "¿Eliminar la Skill actual? Esta acción no se puede deshacer.", - "confirmWithNamePrefix": "¿Eliminar la Skill", - "confirmWithNameSuffix": "? Esta acción no se puede deshacer." - }, - "toasts": { - "loadFailed": "No se pudo cargar la Skill", - "openFolderFailed": "No se pudo abrir la carpeta", - "noSkillDirectory": "No se encontró un directorio de Skills disponible para el agente actual", - "nameRequired": "El nombre de la Skill no puede estar vacío", - "updated": "Skill actualizada", - "created": "Skill creada", - "saveFailed": "No se pudo guardar la Skill", - "deleted": "Skill eliminada", - "deleteFailed": "No se pudo eliminar la Skill" - }, - "templates": { - "gemini": "---\nname: example-skill\ndescription: Describe when this skill should be used.\n---\n\n# Skill Name\n\nInstructions for the agent when this skill is active.\n\n## Workflow\n\n1. Add actionable step one.\n2. Add actionable step two.\n", - "openCode": "---\nname: example-skill\ndescription: Describe when this skill should be used.\n---\n\n# Purpose\n\nDescribe what this skill helps with.\n\n# Steps\n\n1. Add actionable step one.\n2. Add actionable step two.\n", - "openClaw": "---\nname: example-skill\ndescription: Describe when this skill should be used.\nuser-invocable: true\ndisable-model-invocation: false\n---\n\n# Purpose\n\nDescribe what this skill helps with.\n\n# Instructions\n\n1. Add actionable instruction one.\n2. Add actionable instruction two.\n", - "default": "---\nname: example-skill\ndescription: Describe when this skill should be used.\n---\n\n# Skill: example-skill\n\n## When to use\n\n- Describe trigger conditions.\n\n## Instructions\n\n1. Add actionable instruction one.\n2. Add actionable instruction two.\n" - } - }, - "McpSettings": { - "loading": "Cargando...", - "summary": { - "missingCommand": "(comando faltante)", - "missingUrl": "(URL faltante)" - }, - "protocol": { - "stdio": "Stdio" - }, - "errors": { - "selectInstallProtocol": "Selecciona un protocolo de instalación", - "fieldRequired": "{field} es obligatorio", - "fieldNeedsBoolean": "{field} debe ser true o false", - "fieldNeedsNumber": "{field} debe ser un número", - "fieldNeedsInteger": "{field} debe ser un entero", - "fieldInvalidJson": "{field} tiene JSON inválido: {message}", - "fieldOutOfRange": "El valor de {field} está fuera del rango permitido", - "jsonEmpty": "{name} no puede estar vacío", - "jsonInvalid": "{name} no es un JSON válido: {message}", - "jsonMustBeObject": "{name} debe ser un objeto JSON", - "specMustBeObject": "La configuración de MCP debe ser un objeto JSON.", - "missingType": "Falta el campo type en la configuración de MCP. Indica uno de stdio, http (alias: streamable-http, streamableHttp), sse.", - "unsupportedType": "Tipo de MCP no admitido {type}. Compatibles: stdio, http (alias: streamable-http, streamableHttp), sse.", - "codexEntryUnsupportedType": "La entrada Codex MCP {id} tiene un tipo no admitido {type}. Compatibles: stdio, http (alias: streamable-http, streamableHttp), sse.", - "unsupportedTransportType": "Tipo de transport no admitido {type}. Compatibles: http (alias: streamable-http, streamableHttp), sse.", - "stdioCommandRequired": "Los MCP stdio requieren un campo command no vacío.", - "remoteUrlRequired": "Los MCP remotos requieren un campo url no vacío.", - "appsRequired": "Selecciona al menos una aplicación de destino." - }, - "jsonNames": { - "localConfig": "Configuración MCP", - "installConfig": "Configuración de instalación" - }, - "toasts": { - "uninstalled": "MCP desinstalado", - "uninstallFailed": "Error al desinstalar: {message}", - "selectAtLeastOneApp": "Selecciona al menos una app de destino", - "saveSuccess": "Guardado", - "saveFailed": "Error al guardar: {message}", - "installed": "{name} instalado", - "installFailed": "Error al instalar: {message}", - "serverIdRequired": "Server ID es obligatorio", - "serverIdExists": "El Server ID \"{id}\" ya existe. Edita la entrada existente o usa un nombre diferente.", - "created": "MCP creado" - }, - "installDialog": { - "title": "Confirmar instalación de MCP", - "descriptionWithName": "Instalar {name} en la configuración local.", - "description": "Selecciona las apps de destino para la instalación.", - "protocol": "Protocolo", - "selectProtocol": "Seleccionar protocolo", - "parameters": "Parámetros de configuración", - "booleanPlaceholder": "Selecciona true/false", - "selectOneValue": "Selecciona un valor", - "targetApps": "Apps de destino" - }, - "actions": { - "cancel": "Cancelar", - "confirmInstall": "Confirmar instalación", - "installing": "Instalando", - "uninstall": "Desinstalar", - "uninstalling": "Desinstalando", - "viewDetails": "Ver detalles", - "save": "Guardar", - "saving": "Guardando", - "install": "Instalar", - "refresh": "Actualizar", - "newMcp": "Nuevo MCP", - "create": "Crear", - "creating": "Creando..." - }, - "tabs": { - "local": "MCP local", - "market": "Marketplace MCP" - }, - "local": { - "filterPlaceholder": "Filtrar MCP local...", - "loadFailed": "Error de carga: {message}", - "empty": "No se detectó MCP local.", - "description": "La configuración de MCP local se puede editar y guardar directamente.", - "enabledApps": "Apps habilitadas", - "configJson": "Configuración MCP (JSON)", - "draftTitle": "Nuevo MCP", - "draftDescription": "Indica un Server ID y la configuración para crear un servidor MCP local.", - "serverIdLabel": "Server ID", - "serverIdPlaceholder": "Server ID (p. ej. my-mcp)", - "typeHint": "Tipos admitidos: stdio, http (alias: streamable-http, streamableHttp), sse. env solo se usa con stdio; para MCP remotos usa headers para llevar tokens de autenticación.", - "envOnRemoteWarning": "Se detectó env en un MCP remoto. Solo stdio usa env; los MCP remotos llevan los tokens de autenticación en headers, así que env se ignorará al guardar." - }, - "market": { - "selectMarketplace": "Seleccionar marketplace", - "searchPlaceholder": "Buscar MCP...", - "searchFailed": "Error de búsqueda: {message}", - "loadingList": "Cargando lista de MCP...", - "empty": "Sin resultados de MCP.", - "loadingDetail": "Cargando detalles del marketplace...", - "detailLoadFailed": "No se pudieron cargar los detalles: {message}", - "owner": "Propietario: {owner}", - "namespace": "Espacio de nombres: {namespace}", - "defaultInstallProtocol": "Protocolo de instalación predeterminado", - "currentOptionParameterCount": "Cantidad de parámetros de la opción actual: {count}", - "installConfigDescription": "Configuración de instalación (JSON, editable antes de instalar; las ediciones sobrescribirán el formulario de protocolo/parámetros)", - "selectLeftToView": "Selecciona un MCP del marketplace a la izquierda para ver detalles." - }, - "badges": { - "verified": "Verificado", - "remote": "Remoto", - "hasHomepage": "Tiene página web", - "uses": "{count} usos", - "deployed": "Desplegado", - "notDeployed": "No desplegado" - }, - "selectLeftMcp": "Selecciona un MCP a la izquierda." - }, - "AcpAgentSettings": { - "title": "Gestión del SDK de agentes", - "description": "Gestiona en un solo lugar la conexión del SDK de agentes, estado habilitado, variables de entorno, gestión de configuración e información de preflight de versión.", - "loadingAgents": "Cargando lista de agentes...", - "agentList": "Lista de agentes", - "emptyNoAgent": "No hay agentes disponibles.", - "configManagement": "Gestión de configuración", - "envVars": "Variables de entorno", - "hostTools": { - "label": "Dejar que el agente gestione archivos y comandos", - "description": "codeg deja de atender el acceso a archivos y los comandos de terminal, de modo que el agente los ejecuta en su propio proceso, donde sí se aplican su sandbox y sus reglas de permisos. También se desactiva la delegación a otros agentes, ya que devolvería ese mismo trabajo a codeg. codeg no añade ningún sandbox propio, así que actívalo solo si el agente tiene uno configurado." - }, - "nativeJsonConfig": "Configuración JSON nativa", - "modelHintDefault": "Déjalo vacío para usar el modelo predeterminado del sistema.", - "generalConfigDescriptionClaude": "Admite configuración rápida de API URL, API Key y modelos de Claude, y sincroniza con la configuración JSON nativa.", - "generalConfigDescriptionDefault": "Admite entrada de configuración importante (API URL, API Key, Model) y gestión de configuración JSON nativa.", - "multiAgent": { - "title": "Colaboración multiagente", - "description": "Permite que los agentes activos deleguen subtareas a otros agentes.", - "enable": "Activar delegación", - "enableHint": "Cuando está desactivado, la herramienta delegate_to_agent se oculta del catálogo de herramientas MCP del agente.", - "withheldByHostTools": "{agents} no recibirán las herramientas de delegación: su interruptor por agente «Deja que el agente gestione archivos y comandos» está activado.", - "selfInitiate": "Allow spawn without @", - "selfInitiateHint": "When on, an agent may start a listed sub-agent on its own. An @ mention is still always honored. When off, only an @ mention starts a sub-agent.", - "depthLimit": "Profundidad máxima de delegación", - "depthHint": "Rango permitido: {min}–{max}. Limita la profundidad de recursión de una cadena de delegación (raíz → hijo → nieto …).", - "completedCacheLabel": "Caché de resultados completados (MB)", - "completedCacheHint": "Caché en memoria de los resultados completados de subagentes, que se conserva solo mientras la sesión de delegación está en ejecución y se libera automáticamente cuando esa sesión termina. Al superar este presupuesto, los resultados más antiguos se descartan primero de la memoria (aún visibles en la sesión propia del subagente); 0 = sin límite (igualmente se libera al terminar la sesión).", - "save": "Guardar", - "saving": "Guardando…", - "saved": "Configuración de delegación guardada", - "saveFailed": "Error al guardar la configuración de delegación", - "loadFailed": "Error al cargar la configuración de delegación: {detail}", - "tabGeneral": "General", - "tabAgentDefaults": "Valores por defecto del agente", - "agentDefaultsDescription": "Anulaciones por agente que se aplican cuando Colaboración multiagente inicia un subagente para una llamada de delegación. Las opciones mostradas provienen de un sondeo en vivo: lo que selecciones es exactamente lo que el agente aceptará.", - "probing": "Cargando las opciones disponibles del agente…", - "probeFailed": "Error al cargar las opciones: {detail}", - "retry": "Reintentar", - "noConfigAvailable": "Este agente no tiene opciones configurables.", - "modeLabel": "Modo", - "agentDefaultHint": "Predeterminado del agente: {value}", - "defaultOptionLabel": "Predeterminado ({value})" - }, - "actions": { - "dragSort": "Arrastrar para reordenar", - "dragSortAgent": "Arrastrar para reordenar {name}", - "refreshCheck": "Actualizar comprobación", - "refreshCheckAgent": "Actualizar comprobación de {name}", - "clickEnable": "Haz clic para habilitar {name}", - "clickDisable": "Haz clic para deshabilitar {name}", - "install": "Instalar", - "upgrade": "Actualizar", - "uninstall": "Desinstalar", - "uninstalling": "Desinstalando...", - "saveEnvVars": "Guardar variables de entorno", - "saving": "Guardando...", - "saveGrokConfig": "Guardar configuración de Grok", - "saveCodexConfig": "Guardar configuración de Codex", - "saveGeminiConfig": "Guardar configuración de Gemini", - "saveOpenCodeConfig": "Guardar configuración de OpenCode", - "saveOpenClawConfig": "Guardar configuración de OpenClaw", - "saveConfigManagement": "Guardar gestión de configuración", - "saveCurrentProvider": "Guardar proveedor actual", - "showApiKey": "Mostrar API Key", - "hideApiKey": "Ocultar API Key", - "showKey": "Mostrar clave", - "hideKey": "Ocultar clave", - "showToken": "Mostrar token", - "hideToken": "Ocultar token", - "cancel": "Cancelar", - "delete": "Eliminar", - "deleting": "Eliminando...", - "confirmDelete": "Confirmar eliminación", - "confirmUninstall": "Confirmar desinstalación", - "saveClineConfig": "Guardar configuración de Cline", - "saveHermesConfig": "Guardar configuración de Hermes", - "saveCodeBuddyConfig": "Guardar configuración de CodeBuddy", - "saveKimiCodeConfig": "Guardar configuración de Kimi Code", - "customInstall": "Instalación personalizada", - "saveKimiCodeRawConfig": "Save config.toml", - "saveDeepSeekConfig": "Guardar configuración de DeepSeek", - "diagnose": "Diagnosticar" - }, - "status": { - "enabled": "Habilitado", - "disabled": "Deshabilitado", - "unchecked": "Sin comprobar", - "agentEnabledAria": "{name} habilitado", - "agentEnabledSwitch": "Interruptor de habilitación de {name}" - }, - "preflight": { - "count": "Elementos de preflight: {count}", - "notRun": "Las comprobaciones aún no se han ejecutado." - }, - "grok": { - "configDescription": "Configura Grok aquí. Los controles siguientes —modo de permisos, esfuerzo de razonamiento, un modelo personalizado opcional (endpoint propio) y la compactación— se combinan en ~/.grok/config.toml, conservando tus otras claves y comentarios. El inicio de sesión usa tu XAI_API_KEY o `grok login`. Las demás claves siguen siendo editables en Avanzado.", - "permissionModeLabel": "Modo de permisos", - "permissionDefault": "Preguntar siempre", - "permissionAcceptEdits": "Aprobar ediciones automáticamente", - "permissionAuto": "Aprobación automática inteligente", - "permissionAlwaysApprove": "Aprobar siempre", - "reasoningEffortLabel": "Esfuerzo de razonamiento", - "effortLow": "Bajo (más rápido)", - "effortMedium": "Medio (equilibrado)", - "effortHigh": "Alto", - "effortXhigh": "Máximo", - "optionDefault": "Usar predeterminado", - "authTitle": "Autenticación", - "authMode": "Método de autenticación", - "authModeApiKey": "Clave de API de XAI", - "authModeApiKeyHint": "Autentícate con una XAI_API_KEY de la consola de xAI, para ejecuciones no interactivas o headless. Se guarda en el entorno de este agente.", - "authModeCustom": "Endpoint personalizado", - "authModeCustomHint": "Usa un endpoint propio (BYO): define abajo un modelo personalizado con su propia base URL y clave de API. Se convierte en el modelo predeterminado de Grok.", - "subscriptionHint": "Inicia sesión con `grok login` (SuperGrok / X Premium+). No se guarda ninguna clave de API.", - "loginHint": "Ejecuta esto en una terminal para iniciar sesión y luego vuelve a abrir esta configuración:", - "commandCopied": "Comando copiado al portapapeles", - "copyCommand": "Copiar comando", - "authKeyConfigured": "XAI_API_KEY está configurada.", - "authKeyMissing": "No hay XAI_API_KEY configurada.", - "advancedToggle": "Avanzado (config.toml sin procesar)", - "configTomlNative": "config.toml (nativo)", - "configTomlHint": "Se guarda literalmente como todo el ~/.grok/config.toml. El TOML no válido se rechaza para que una errata no trunque tu archivo.", - "configTomlPlaceholder": "# Claves distintas de los controles de arriba, p. ej.\n# [mcp_servers.*], [cli], reglas [permission].", - "customModelTitle": "Modelo personalizado (endpoint propio)", - "customModelHint": "Apunta Grok a un endpoint personalizado o autoalojado. codeg escribe un bloque `[model.*]` por modelo y lo establece como predeterminado. Deja el ID de modelo vacío para eliminarlo.", - "customModelIdLabel": "ID del modelo", - "customModelIdPlaceholder": "grok-4.5", - "customModelIdHint": "Se registra como un bloque `[model.*]` y se envía a la API como nombre del modelo; también se establece como `[models].default`.", - "customBaseUrlLabel": "URL base", - "customBaseUrlPlaceholder": "https://api.x.ai/v1 (predeterminado)", - "customApiBackendLabel": "Backend de la API", - "backendResponses": "Responses", - "backendChatCompletions": "Chat Completions", - "backendMessages": "Messages (Anthropic)", - "customApiKeyLabel": "Clave de API", - "customApiKeyHint": "Se guarda en línea en `[model.*].api_key`, limitada a este endpoint.", - "customContextWindowLabel": "Ventana de contexto (tokens)", - "customContextWindowHint": "Opcional. Determina el momento de la autocompactación; déjalo vacío para el valor predeterminado del endpoint.", - "autoCompactLabel": "Umbral de autocompactación (%)", - "autoCompactHint": "Compacta la conversación cuando el uso del contexto alcanza este porcentaje (predeterminado de Grok: 85). Se escribe en `[session]`." - }, - "cursor": { - "configDescription": "Configura Cursor aquí. Elige un método de autenticación —suscripción oficial (inicio de sesión en el navegador) o una clave API de Cursor para equipos sin interfaz o servidores— y luego elige un modelo y edita las reglas de permisos y el sandbox del CLI. codeg los escribe en ~/.cursor/cli-config.json, compartido con el CLI cursor-agent.", - "authTitle": "Autenticación", - "authChecking": "Comprobando…", - "authNotInstalled": "cursor-agent no está instalado", - "authLoggedIn": "Sesión iniciada", - "authNotLoggedIn": "Sin sesión", - "loginHint": "Ejecuta esto en una terminal para iniciar sesión con tu cuenta de Cursor (se abre el navegador) y luego pulsa actualizar:", - "apiKeyLabel": "Clave API de Cursor", - "apiKeyPlaceholder": "clave de cursor.com/dashboard", - "apiKeyHint": "CURSOR_API_KEY: una clave de cuenta del panel de Cursor, alternativa al inicio de sesión en el navegador para equipos sin interfaz o servidores. No es una clave de terceros ni de OpenAI.", - "modelTitle": "Modelo predeterminado", - "loadModels": "Cargar modelos", - "modelsUnavailable": "Lista de modelos no disponible", - "modelHint": "Se pasa a la CLI como --model al iniciar la sesión. Déjalo en predeterminado para que Cursor elija.", - "permissionsTitle": "Permisos y sandbox", - "permissionsDescription": "Editor visual de las reglas de permisos de la CLI (cli-config.json). Las reglas permitidas se ejecutan sin confirmación; las denegadas se bloquean siempre.", - "permissionModeLabel": "Modo de permisos", - "permissionModeDefault": "Preguntar antes de ejecutar (predeterminado)", - "permissionModeForce": "Run Everything (--force)", - "permissionModeHint": "Run Everything inicia las sesiones con --force: todas las llamadas de herramientas se permiten automáticamente salvo las reglas de denegación, sin confirmaciones (una política de la organización puede limitarlo a las reglas de permiso). Se aplica a las sesiones nuevas.", - "optionDefault": "Predeterminado (sin definir)", - "sandboxLabel": "Sandbox", - "sandboxEnabled": "Activado", - "sandboxDisabled": "Desactivado", - "allowRulesLabel": "Reglas permitidas", - "denyRulesLabel": "Reglas denegadas", - "addRule": "Añadir regla", - "rulesSyntaxHint": "Sintaxis de reglas: Shell(cmd), Read(ruta/glob), Write(ruta/glob), WebFetch(dominio), Mcp(servidor:herramienta) — las reglas de denegación siempre prevalecen.", - "saveConfig": "Guardar configuración", - "advancedToggle": "Avanzado: cli-config.json sin procesar", - "advancedHint": "El ~/.cursor/cli-config.json completo. Guardar escribe el archivo tal cual; los controles estructurados de arriba se fusionan en él.", - "saveRawConfig": "Guardar archivo", - "authMode": "Método de autenticación", - "subscriptionHint": "Inicia sesión con tu cuenta de Cursor y usa los modelos de Cursor.", - "customApiKeyRequired": "Se requiere una clave API de Cursor.", - "authModeApiKey": "Clave API de Cursor (sin interfaz)", - "authModeApiKeyHint": "Autentícate con una clave API de cuenta de Cursor generada en el panel de Cursor (para equipos sin interfaz o servidores). Es una clave de cuenta de Cursor, no un endpoint de terceros/OpenAI: cursor-agent solo se comunica con el backend de Cursor. Para usar un endpoint compatible con codex/OpenAI, usa el agente Codex en su lugar.", - "modelPickerPlaceholder": "Buscar modelos…", - "modelNoMatch": "Ningún modelo coincide", - "modelsNeedAuth": "Inicia sesión para cargar la lista de modelos.", - "modelDefaultBadge": "predeterminado" - }, - "deepseek": { - "configManagement": "Configuración de DeepSeek Harness", - "configDescription": "El endpoint y la clave son variables de entorno que deepseek-acp lee al arrancar. El modelo y el esfuerzo de razonamiento son selectores por sesión: se eligen en el campo de mensaje.", - "baseUrlLabel": "Endpoint de la API", - "baseUrlHint": "Déjalo vacío para el endpoint oficial. Se aplica a las sesiones iniciadas tras guardar; vuelve a conectar una sesión en curso para que lo tome.", - "baseUrlInvalid": "Introduce una URL http(s) completa y sin cadena de consulta, por ejemplo https://api.deepseek.com", - "apiKeyLabel": "Clave de API", - "apiKeyHint": "Se pasa al agente como DEEPSEEK_API_KEY. Una variable de entorno tiene prioridad sobre el archivo de credenciales, así que déjala vacía si inicias sesión desde la terminal." - }, - "codex": { - "configDescription": "Admite configuración rápida de URL de API, API Key, nombre del modelo y reasoning effort, y sincroniza con `auth.json` / `config.toml`.", - "authMode": "Modo de Autenticación", - "chatgptSubscription": "Suscripción oficial", - "chatgptSubscriptionHint": "Iniciar sesión con suscripción oficial de ChatGPT, sin necesidad de API Key", - "apiKeyHint": "Conectar usando API Key a OpenAI o servicios API compatibles", - "selectProvider": "Seleccionar proveedor", - "modelName": "Nombre del modelo", - "selectReasoningEffort": "Seleccionar Reasoning Effort", - "enableWebsocket": "Habilitar WebSocket", - "enableWebsocketAria": "Habilitar WebSocket para Codex Provider", - "enableSkills": "Habilitar Skills", - "enableSkillsAria": "Habilitar Skills para Codex", - "enableFast": "Habilitar Fast", - "enableFastAria": "Habilitar nivel de servicio Fast para Codex", - "sandboxGroupTitle": "Sandbox y aprobaciones", - "sandboxGroupHint": "Se escribe en el ~/.codex/config.toml global, por lo que también lo ven las sesiones de codex CLI e IDE. Son valores predeterminados del hilo: rigen los turnos que codex inicia por su cuenta (/goal, /review, /compact). Los mensajes normales usan el preajuste de aprobación del compositor. Reinicia una sesión para aplicar los cambios.", - "sandboxShadowedWarning": "config.toml define default_permissions, así que codex resuelve los permisos con ese perfil e ignora sandbox_mode por completo. Elimina default_permissions para usar los controles de abajo.", - "sandboxPermissionsTableWarning": "config.toml define perfiles [permissions] pero no default_permissions, lo que impide que codex arranque. Configúralo en el editor sin formato de abajo.", - "approvalPolicyLabel": "Política de aprobación", - "approvalPolicyUnset": "Sin definir (predeterminado de codex: a petición)", - "approvalPolicy_on-request": "A petición: el modelo decide cuándo preguntar", - "approvalPolicy_untrusted": "No confiable: solo se ejecutan sin supervisión los comandos de solo lectura seguros", - "approvalPolicy_never": "Nunca: sin ninguna solicitud de aprobación", - "approvalPolicy_granular": "Granular: elige por tipo de solicitud", - "approvalPolicyUntrustedAcpWarning": "Untrusted no tiene equivalente entre los tres ajustes de aprobación del adaptador ACP, así que las sesiones de codeg recurren a «a petición»: el modelo decide entonces cuándo preguntar y los comandos que la zona aislada ya permite dejan de pedir confirmación. Restringe mejor el modo de aislamiento de abajo.", - "granularHint": "Desactivado significa que ese tipo de solicitud se rechaza automáticamente en vez de mostrártela.", - "granular_sandbox_approval": "Escalados de comandos de shell", - "granular_rules": "Avisos de reglas de execpolicy", - "granular_skill_approval": "Avisos de scripts de habilidades", - "granular_request_permissions": "Avisos de la herramienta request_permissions", - "granular_mcp_elicitations": "Avisos de elicitación MCP", - "sandboxModeLabel": "Modo de sandbox", - "sandboxModeUnset": "Sin definir (las carpetas de confianza usan escritura en el espacio de trabajo)", - "sandboxMode_read-only": "Solo lectura", - "sandboxMode_workspace-write": "Escritura en el espacio de trabajo", - "sandboxMode_danger-full-access": "Acceso total (sin sandbox)", - "sandboxModeHint": "En Windows, la escritura en el espacio de trabajo baja a solo lectura salvo que actives el sandbox experimental de Windows de codex.", - "sandboxModeSeedsPresetHint": "codeg también lo traduce al ajuste de aprobación inicial de la sesión, así que —a diferencia de la política de aprobación— sí afecta a las peticiones normales. El ajuste elegido en el editor sigue teniendo prioridad.", - "writableRootsLabel": "Carpetas adicionales con escritura", - "writableRootsHint": "Una ruta absoluta por línea, además del directorio de trabajo.", - "sandboxRootsRelativeError": "Debe ser una ruta absoluta: codex resuelve las rutas relativas dentro de ~/.codex: {path}", - "networkAccessLabel": "Permitir acceso a la red", - "excludeTmpdirLabel": "Excluir TMPDIR de las raíces con escritura", - "excludeSlashTmpLabel": "Excluir /tmp de las raíces con escritura", - "authJsonNative": "auth.json (nativo)", - "configTomlNative": "config.toml (nativo)", - "loginButton": "Iniciar sesión con ChatGPT", - "loginRequesting": "Solicitando código de inicio de sesión...", - "loginStep1": "Abre la siguiente URL en tu navegador:", - "loginStep2": "Introduce el siguiente código:", - "loginPolling": "Esperando autorización...", - "loginCancel": "Cancelar", - "loginSuccess": "¡Inicio de sesión exitoso, configuración guardada!", - "loginFailed": "Error de inicio de sesión: {message}", - "loginRetry": "Reintentar", - "loginCodeCopied": "Código copiado", - "loggedIn": "Cuenta conectada", - "loginRelogin": "Reconectar / Cambiar cuenta", - "loginTimeout": "Tiempo de inicio de sesión agotado, inténtalo de nuevo", - "loginSaveFailed": "Inicio de sesión exitoso pero falló al guardar la configuración" - }, - "gemini": { - "authConfig": "Configuración de autenticación de Gemini", - "authConfigDescription": "Alineado con la documentación de autenticación de Gemini CLI, con soporte para endpoint personalizado, inicio de sesión de Google, Gemini API Key y Vertex AI (ADC / cuenta de servicio / API Key).", - "authMode": "Modo de autenticación", - "selectAuthMode": "Seleccionar modo de autenticación", - "viewAuthDoc": "Ver documentación de autenticación", - "mode": { - "custom": "Endpoint personalizado", - "loginGoogle": "Inicio de sesión de Google (OAuth)", - "vertexServiceAccount": "Vertex AI (Cuenta de servicio)" - }, - "hint": { - "custom": "Completa API URL, API Key y Modelo; se mapean a GOOGLE_GEMINI_BASE_URL / GEMINI_API_KEY / GEMINI_MODEL.", - "loginGoogle": "Ejecuta gemini en terminal y completa primero el inicio de sesión de Google; no se requiere API key.", - "geminiApiKey": "Completa GEMINI_API_KEY cuando uses la API de Gemini.", - "vertexAdc": "Usa gcloud ADC; se recomienda configurar GOOGLE_CLOUD_PROJECT y GOOGLE_CLOUD_LOCATION.", - "vertexServiceAccount": "Establece la ruta del JSON de la cuenta de servicio en GOOGLE_APPLICATION_CREDENTIALS.", - "vertexApiKey": "Completa GOOGLE_API_KEY cuando uses API key de Vertex AI." - } - }, - "openCode": { - "configManagement": "Gestión de configuración de OpenCode", - "configDescription": "Alineado con el esquema `provider` de OpenCode, admite gestión de múltiples proveedores y sincronización bidireccional con archivos JSON nativos.", - "providerManagement": "Gestión de proveedores", - "providerCount": "{count} proveedores", - "addProvider": "Agregar proveedor", - "emptyProvider": "Aún no hay proveedores personalizados. Haz clic en Agregar proveedor personalizado para crear uno.", - "providerEnabledState": "Estado habilitado de {providerId}", - "selectProviderNpm": "Seleccionar provider.npm", - "modelManagement": "Gestión de modelos", - "modelCount": "{count} modelos", - "modelDescription": "Alineado con `provider.models` de OpenCode. La gestión rápida actualmente soporta `name` / `id`; otros campos avanzados se conservan y se pueden editar en el JSON nativo de abajo.", - "addModel": "Agregar modelo", - "emptyModel": "Aún no hay modelo. Introduce model id y haz clic en \"Agregar modelo\".", - "modelId": "ID de modelo", - "modelName": "Nombre del modelo", - "deleteModel": "Eliminar modelo {modelId}", - "nativeJsonConfig": "Configuración JSON nativa de OpenCode", - "mainModel": "Modelo principal", - "smallModel": "Modelo pequeño", - "noMatchingModels": "No hay modelos coincidentes", - "connectProvider": "Conectar proveedor", - "connectedProviders": "Proveedores conectados", - "noConnectedProviders": "Aún no hay proveedores del catálogo conectados.", - "advancedProviderConfig": "Proveedores personalizados", - "customProviderConfigHint": "Endpoints compatibles con OpenAI que defines tú mismo: un bloque de provider en opencode.json, con la API key en auth.json.", - "addCustomProvider": "Agregar proveedor personalizado", - "disconnect": "Desconectar", - "editConfig": "Editar", - "customBadge": "Personalizado", - "authKindApi": "Clave API", - "authKindOauth": "OAuth", - "authKindNone": "Sin credencial", - "connect": { - "title": "Conectar un proveedor", - "description": "Elige un proveedor del catálogo de models.dev. Las credenciales se guardan en el archivo auth.json de OpenCode.", - "pick": "Proveedor", - "search": "Buscar proveedores…", - "loading": "Cargando catálogo…", - "catalogLabel": "Catálogo de models.dev", - "modelsAvailable": "{count} modelos disponibles", - "getKey": "Obtener clave API", - "oauthApiKeyNote": "Este proveedor también admite el inicio de sesión por navegador con opencode auth login. El inicio por navegador llegará pronto; por ahora, pega una clave API.", - "apiKey": "Clave API", - "apiKeyHint": "Se guarda en auth.json, nunca en opencode.json.", - "baseUrlOptional": "Anular Base URL (opcional)", - "providerId": "ID del proveedor", - "displayName": "Nombre visible", - "modelsList": "Modelos (uno por línea)", - "modelsHint": "IDs de modelo que acepta el endpoint.", - "action": "Conectar", - "editTitle": "Editar proveedor", - "editDescription": "Actualiza la clave API o la Base URL de este proveedor.", - "saveAction": "Guardar" - }, - "customProvider": { - "title": "Agregar un proveedor personalizado", - "description": "Define un endpoint compatible con OpenAI. La API key se guarda en auth.json; el bloque de provider va a opencode.json.", - "action": "Agregar proveedor", - "idInCatalog": "{providerId} es un proveedor conocido: conéctalo mediante Conectar proveedor." - }, - "refreshCatalog": "Actualizar catálogo", - "reasoningBadge": "razonamiento", - "contextWindow": "Ventana de contexto", - "permissions": { - "title": "Permisos", - "description": "Decide qué acciones se ejecutan solas, cuáles te preguntan primero y cuáles se bloquean. Se escribe en el bloque permission de opencode.json y se aplica al guardar abajo.", - "docsLink": "Documentación de permisos", - "unparsableConfig": "El JSON nativo de abajo no es válido, así que el editor visual está pausado. Corrige el JSON para continuar.", - "invalidBlock": "El bloque permission tiene una forma que codeg no reconoce. Edítalo en el JSON nativo de abajo o usa Restablecer para empezar de nuevo.", - "orderingUnsafe": "Hay una regla comodín escrita después de herramientas concretas, así que OpenCode también se la aplica a ellas: las filas de abajo no son lo que está en vigor. Corregir orden solo devuelve cada comodín al principio de su ámbito, sin cambiar ningún valor.", - "orderingUnsafeManual": "Una regla queda tapada por un patrón posterior más general, así que OpenCode nunca la aplica: las filas de abajo no son lo que está en vigor. Dos patrones que se solapan no tienen un único orden correcto; reordénalos en el JSON nativo para que el más general vaya primero.", - "fixOrder": "Corregir orden", - "agentOverrides": "Estos agentes anulan los permisos y se aplican al final, así que ganan sobre todo lo de aquí: {agents}. Edítalos en el JSON nativo de abajo o activa el aceptar automático para borrarlos.", - "legacyTools": "El mapa tools heredado del nivel superior deniega una herramienta. OpenCode lo fusiona con los permisos, así que se aplica por encima de todo lo que se ve aquí. Edítalo en el JSON nativo de abajo o activa el aceptar automático para borrarlo.", - "autoAcceptTitle": "Aceptar todos los permisos automáticamente", - "autoAcceptHint": "Toda llamada a herramientas —comandos de shell, ediciones de archivos, rutas fuera del proyecto— se ejecuta sin preguntar. Al activarlo, los ajustes por herramienta de abajo se sustituyen por una única regla que lo permite todo, y se borran las anulaciones por agente y los conmutadores tools heredados que si no seguirían bloqueando.", - "globalLabel": "Valor global por defecto", - "globalHint": "La regla *: se aplica a todo lo que las herramientas de abajo no anulen.", - "actionUnset": "Sin definir (valores de OpenCode)", - "actionInherit": "Heredar ({action})", - "actionAllow": "Permitir", - "actionAsk": "Preguntar", - "actionDeny": "Denegar", - "perToolTitle": "Permisos por herramienta", - "reset": "Restablecer", - "ruleCount": "reglas: {count}", - "rulesToggle": "Reglas detalladas de {tool}", - "rulesHint": "Se comparan con la entrada de la herramienta y gana la última coincidencia, así que pon primero los patrones amplios. * coincide con cualquier cantidad de caracteres, ? con exactamente uno, y un ~ inicial se expande a tu carpeta personal.", - "noRules": "Todavía no hay reglas detalladas.", - "addRule": "Añadir regla", - "deleteRule": "Eliminar la regla {pattern}", - "duplicateRule": "Ese patrón ya existe.", - "blankRule": "Una regla necesita un patrón; usa el icono de papelera para eliminarla.", - "customKeys": "Otras claves de permiso del archivo", - "customKeyHint": "No es una herramienta integrada de OpenCode; se conserva tal cual.", - "keys": { - "bash": "Ejecutar comandos de shell, según el comando analizado", - "edit": "Todas las modificaciones de archivos: edit, write y patch", - "read": "Leer archivos, según la ruta", - "external_directory": "Acceder a rutas fuera del directorio de trabajo del proyecto", - "task": "Lanzar subagentes, según el tipo de subagente", - "skill": "Cargar habilidades, según su nombre", - "glob": "Buscar archivos, según el patrón glob", - "grep": "Buscar en el contenido de los archivos, según el patrón", - "list": "Listar el contenido de un directorio", - "webfetch": "Descargar una URL", - "websearch": "Buscar en la web", - "lsp": "Ejecutar consultas LSP", - "todowrite": "Escribir la lista de tareas", - "question": "Hacerte una pregunta", - "doom_loop": "Se activa cuando la misma llamada se repite tres veces con la misma entrada" - } - } - }, - "openClaw": { - "gatewayConfig": "Configuración de Gateway", - "gatewayDescription": "Configura la conexión de OpenClaw Gateway. Admite gateway local o remoto.", - "gatewayUrlHint": "Déjalo vacío para usar gateway.remote.url desde la configuración local de openclaw.", - "gatewayTokenPlaceholder": "Token de autenticación de Gateway", - "gatewayTokenHint": "Usa token-file en lugar de token en texto plano cuando sea posible; configúralo con el CLI de openclaw.", - "sessionKeyHint": "Opcional. Especifica la session key del gateway; si se deja vacío se asigna automáticamente una sesión aislada." - }, - "hermes": { - "configManagement": "Configuración de Hermes", - "configDescription": "Hermes gestiona sus propias credenciales en ~/.hermes/.env y los ajustes en ~/.hermes/config.yaml. Elige un proveedor y luego establece la clave de API y el modelo: codeg escribe ambos archivos por ti.", - "providerLabel": "Proveedor", - "providerHint": "El proveedor determina qué variable de clave de API y qué model.provider usa Hermes. Los proveedores de OAuth se configuran mediante la configuración del terminal que aparece a continuación.", - "groupApiKey": "Proveedores con clave API", - "groupOauth": "Proveedores OAuth", - "groupAws": "AWS", - "apiKeyHint": "Se guarda en ~/.hermes/.env. Nunca se inyecta en el proceso: Hermes la lee de su propia configuración.", - "modelName": "Modelo", - "oauthHint": "Este proveedor usa OAuth. Ejecuta la configuración de abajo para autenticarte en tu terminal.", - "awsHint": "Bedrock usa tus credenciales de AWS (entorno o configuración compartida). Define el ID del modelo arriba y configura el acceso a AWS en tu entorno.", - "unsupportedProvider": "Este proveedor no se puede editar con campos estructurados. Usa el editor de config.yaml de abajo o la configuración por terminal.", - "setupTitle": "Configuración autogestionada", - "setupHint": "La configuración interactiva de Hermes necesita un terminal. Iníciala abajo o copia el comando para ejecutarlo tú mismo.", - "runSetup": "Ejecutar configuración de Hermes", - "configureModel": "Configurar modelo", - "openConfigFolder": "Abrir ~/.hermes", - "copyCommand": "Copiar comando", - "commandCopied": "Comando copiado al portapapeles", - "advancedTitle": "Avanzado: editar config.yaml", - "rawConfigHint": "Edita ~/.hermes/config.yaml directamente. Guardar aquí sobrescribe el archivo tal cual.", - "saveRawConfig": "Guardar config.yaml" - }, - "codebuddy": { - "configManagement": "Configuración de CodeBuddy", - "configDescription": "CodeBuddy se autentica con una clave de API. Las versiones para China continental también requieren establecer el entorno en «China (internal)»; las versiones iOA usan «iOA». La versión internacional lo deja sin definir.", - "apiKeyLabel": "Clave de API", - "apiKeyHint": "Se guarda como CODEBUDDY_API_KEY para este agente. También puedes iniciar sesión con la CLI de CodeBuddy en una terminal.", - "apiKeyHintSelfHosted": "Se guarda como CODEBUDDY_API_KEY para este agente. Usa la clave emitida por tu implementación privada.", - "environmentLabel": "Entorno", - "environmentHint": "Establece CODEBUDDY_INTERNET_ENVIRONMENT. China continental debe usar «China (internal)»; la versión internacional lo deja sin definir.", - "envOverseas": "Internacional (predeterminado)", - "envChina": "China (internal)", - "envIoa": "iOA", - "envSelfHosted": "Autoalojado (implementación privada)", - "baseUrlLabel": "URL de implementación", - "baseUrlPlaceholder": "https://codebuddy.your-company.com", - "baseUrlHint": "Se guarda como CODEBUDDY_BASE_URL y dirige CodeBuddy a tu endpoint privado. En autoalojado, el entorno de red (CODEBUDDY_INTERNET_ENVIRONMENT) queda sin configurar.", - "baseUrlInvalid": "Introduce una URL http(s) válida.", - "loginHint": "¿No tienes clave de API? Ejecuta «codebuddy» en una terminal para iniciar sesión con tu cuenta de Tencent." - }, - "kimiCode": { - "configManagement": "Configuración de Kimi Code", - "configDescription": "`kimi acp` solo acepta un token de sesión almacenado, así que codeg escribe un proveedor gestionado en ~/.kimi-code/config.toml y siembra un token de acceso local: la inferencia sigue usando tu propia clave.", - "statusUnconfigured": "Sin configurar", - "statusDirty": "Cambios sin guardar", - "summaryLabel": "En vigor", - "gateReadyApiKey": "Clave de API escrita en config.toml", - "gateReadyLogin": "Sesión iniciada con una cuenta de Kimi", - "revealConfig": "Mostrar en la carpeta", - "envOverrideWarning": "{keys} está definido y tiene prioridad sobre config.toml. Al guardar aquí se elimina.", - "authModeLabel": "Método de autenticación", - "authModeApiKey": "Clave de API", - "authModeLogin": "Inicio de sesión de Kimi (suscripción)", - "authModeApiKeyHint": "Escribe un proveedor gestionado en config.toml y siembra el token de acceso para que las sesiones puedan abrirse.", - "loginHint": "Ejecuta `kimi login` en una terminal para iniciar sesión con una cuenta de suscripción de Kimi. codeg no guarda nada y reutiliza el inicio de sesión de Kimi. Guardar aquí elimina el token de acceso por clave de API de codeg.", - "credentialTitle": "Credencial", - "interfaceTypeLabel": "Tipo de proveedor", - "interfaceTypeHint": "El protocolo de proveedor que habla Kimi (el `type` de config.toml). Usa Kimi / Moonshot para una clave de Moonshot / platform.kimi.com.", - "endpointLabel": "Endpoint", - "endpointCustom": "Personalizado (compatible con OpenAI)", - "endpointHint": "Internacional = api.moonshot.ai; China (claves de platform.kimi.com) = api.moonshot.cn. Personalizado apunta a cualquier endpoint compatible con OpenAI.", - "regionInternational": "Internacional (api.moonshot.ai)", - "regionChina": "China (api.moonshot.cn)", - "baseUrlLabel": "URL base", - "baseUrlHint": "Déjalo en blanco para usar el valor por defecto del SDK del proveedor.", - "apiKeyLabel": "Clave de API", - "apiKeyHint": "Se escribe en ~/.kimi-code/config.toml y se usa para la inferencia. De platform.kimi.com o platform.kimi.ai.", - "vertexProjectLabel": "Proyecto de GCP (GOOGLE_CLOUD_PROJECT)", - "vertexLocationLabel": "Región de GCP (GOOGLE_CLOUD_LOCATION)", - "vertexHint": "Vertex AI usa las credenciales predeterminadas de aplicación de Google: ejecuta `gcloud auth application-default login` (sin clave de API).", - "modelTitle": "Modelo", - "modelLabel": "Modelo", - "modelHint": "El id de modelo que se escribe en config.toml. Usa «Probar y listar modelos» para ver a cuáles puede acceder tu clave.", - "maxContextLabel": "Tamaño máximo de contexto", - "maxContextHint": "Obligatorio según el esquema de Kimi: sin él, Kimi descarta todo el bloque del modelo y ninguna consulta devuelve respuesta. Por defecto 262144.", - "fetchModels": "Probar y listar modelos", - "fetchModelsOk": "La clave funciona: {count} modelos disponibles", - "fetchModelsEmpty": "La clave funciona, pero no se devolvió ningún modelo", - "fetchModelsFailed": "La prueba falló", - "fetchModelsNeedsKey": "Introduce primero una clave de API y un endpoint", - "modelNotInList": "Este modelo no está en la lista a la que tu clave puede acceder: Kimi fallará con «modelo no encontrado».", - "reasoningTitle": "Razonamiento", - "reasoningEnableLabel": "Activar", - "reasoningDescription": "Kimi solo muestra el selector «Thinking» en el cuadro de mensaje cuando el modelo declara una capacidad de razonamiento, así que codeg la escribe aquí. Se aplica a las sesiones nuevas.", - "effortsLabel": "Niveles ofrecidos", - "effortsHint": "Estos son los niveles que aparecerán en el selector «Thinking». Kimi los reenvía al proveedor tal cual, así que elige los que acepte tu modelo.", - "effortsEmptyHint": "Sin ningún nivel elegido, el cuadro de mensaje se reduce a un simple interruptor Off / On.", - "effortsCustomPlaceholder": "Añadir otro nivel", - "effortsAdd": "Añadir", - "defaultEffortLabel": "Nivel por defecto", - "defaultEffortAuto": "Que elija Kimi", - "alwaysThinkingLabel": "El modelo siempre razona: quitar la opción Off del selector", - "fixErrorsFirst": "Corrige primero los campos marcados", - "errorModelRequired": "El modelo es obligatorio", - "errorMaxContextRequired": "El tamaño máximo de contexto es obligatorio", - "errorMaxContextInvalid": "Debe ser un entero positivo", - "errorApiKeyRequired": "La clave de API es obligatoria", - "errorApiKeyInvalid": "La clave de API no puede contener saltos de línea", - "errorBaseUrlRequired": "La URL base es obligatoria", - "errorBaseUrlInvalid": "Debe empezar por http:// o https://", - "errorVertexProjectRequired": "El proyecto de GCP es obligatorio", - "errorDefaultEffortUnlisted": "Elige uno de los niveles seleccionados arriba", - "advancedTitle": "Avanzado", - "authTypeLabel": "Ubicación de la credencial", - "authTypeApiKey": "api_key en línea", - "authTypeEnv": "Subtabla env del proveedor", - "authTypeHint": "Dónde se escribe la clave de API dentro de config.toml.", - "rawEditorLabel": "Editar config.toml directamente", - "rawEditorWarning": "Guardar aquí sobrescribe el archivo completo tal cual y reemplaza la configuración estructurada de arriba.", - "rawEditorPlaceholder": "[providers.codeg]\ntype = \"kimi\"\nbase_url = \"https://api.moonshot.cn/v1\"\napi_key = \"sk-...\"" - }, - "authModeOfficialSubscription": "Suscripción oficial", - "authModeCustomEndpoint": "Endpoint personalizado", - "authModeCustomEndpointHint": "Configurar manualmente la URL de API y la clave API para un endpoint personalizado.", - "authModeModelProvider": "Proveedor de modelo", - "modelProvider": "Proveedor de modelo", - "modelProviderHint": "Usar la URL de API, la clave API y el modelo de un proveedor de modelo configurado.", - "selectModelProvider": "Seleccionar proveedor de modelo", - "noModelProviderAvailable": "No hay proveedor de modelo configurado para este agente. Vaya a la configuración de proveedores de modelo para agregar uno.", - "claude": { - "authMode": "Modo de autenticación", - "officialSubscription": "Suscripción oficial", - "officialSubscriptionHint": "Usar la suscripción oficial de Anthropic, no se requiere API Key.", - "mainModel": "Modelo principal", - "reasoningModel": "Modelo de razonamiento (thinking)", - "haikuDefaultModel": "Modelo Haiku predeterminado", - "sonnetDefaultModel": "Modelo Sonnet predeterminado", - "opusDefaultModel": "Modelo Opus predeterminado", - "customModelOption": "ID de modelo personalizado", - "customModelOptionName": "Nombre del modelo personalizado", - "customModelOptionDescription": "Descripción del modelo personalizado", - "customModelOptionHint": "Añade una única entrada personalizada al selector de modelos de Claude (por ejemplo, un modelo detrás de una pasarela/proxy personalizado). El nombre y la descripción son opcionales y solo afectan a la visualización.", - "effortLevel": "Nivel de razonamiento", - "effortLevelDefault": "Nivel predeterminado", - "effortLevel_low": "Bajo", - "effortLevel_medium": "Medio", - "effortLevel_high": "Alto", - "effortLevel_xhigh": "Extra Alto", - "sendAttributionHeader": "Enviar identificador de atribución/facturación a la API", - "sendAttributionHeaderAria": "Enviar el identificador de atribución/facturación de Claude Code a la API", - "disableNonessentialTraffic": "Desactivar la telemetría o las solicitudes de red innecesarias", - "disableNonessentialTrafficAria": "Desactivar la telemetría o las solicitudes de red innecesarias de Claude Code" - }, - "dialogs": { - "confirmDeleteProvider": "¿Eliminar proveedor {providerId}?", - "confirmDeleteProviderDescription": "La configuración de OpenCode y auth JSON se actualizarán juntos. Esta acción no se puede deshacer.", - "confirmUninstall": "¿Desinstalar {name}?", - "confirmUninstallDescription": "Esto elimina la versión instalada localmente. Puedes reinstalar más tarde.", - "customInstallTitle": "Instalación personalizada de {name}", - "customInstallDescription": "Introduce la versión que quieres instalar. Se reinstalará y reemplazará la versión instalada actualmente.", - "customInstallVersionLabel": "Número de versión", - "customInstallInvalid": "Introduce un número de versión válido, p. ej. 1.2.3.", - "customInstallSubmit": "Instalar" - }, - "errors": { - "windowsFileLocked": "Los archivos de {name} están en uso por una sesión activa, por lo que Windows no puede reemplazarlos. Cierra todas las sesiones de {name} e inténtalo de nuevo.", - "nativeJsonMustBeObject": "La configuración JSON nativa debe ser un objeto", - "nativeJsonInvalid": "Error de formato en JSON nativo: {message}", - "openCodeAuthMustBeObject": "OpenCode auth.json debe ser un objeto JSON", - "openCodeAuthInvalid": "Error de formato en OpenCode auth.json: {message}", - "authMustBeObject": "auth.json debe ser un objeto JSON", - "authInvalid": "Error de formato en auth.json: {message}", - "providerIdPattern": "El ID de proveedor solo admite letras, números, guion bajo, punto y guion", - "providerExists": "El proveedor {providerId} ya existe", - "modelIdPattern": "El ID de modelo solo admite letras, números, guion bajo, punto, dos puntos y guion", - "modelExists": "El modelo {modelId} ya existe" - }, - "warnings": { - "nativeJsonRecoveredStructured": "La configuración JSON nativa es inválida; se restableció a configuración estructurada", - "nativeJsonRecoveredOpenCode": "La configuración JSON nativa es inválida; se restableció a configuración estructurada de OpenCode", - "openCodeAuthRecovered": "OpenCode auth.json es inválido; se restableció a configuración predeterminada", - "authRecoveredStructured": "auth.json es inválido; se restableció a configuración estructurada" - }, - "toasts": { - "agentActionCompleted": "{name} {action} completado", - "agentActionFailed": "{name} {action} falló", - "localVersion": "Versión local: {version}", - "installCompletedVersionLater": "Instalación completada, la versión se actualizará en la próxima comprobación", - "uninstallCompleted": "Desinstalación de {name} completada", - "uninstallFailed": "Desinstalación de {name} fallida", - "localVersionRemoved": "Versión local eliminada", - "saveAgentOrderFailed": "No se pudo guardar el orden de Agent", - "saveAgentSwitchFailed": "No se pudo guardar el switch de Agent", - "saveEnvFailed": "No se pudieron guardar las variables de entorno", - "grokSaved": "Configuración de Grok guardada", - "saveGrokNativeFailed": "No se pudo guardar la configuración nativa de Grok", - "saveGrokApiKeyFailed": "Ajustes guardados, pero no se pudo guardar la clave API", - "cursorSaved": "Configuración de Cursor guardada", - "saveCursorConfigFailed": "Error al guardar la configuración de Cursor", - "codexSaved": "Configuración de Codex guardada", - "saveCodexNativeFailed": "No se pudo guardar la configuración nativa de Codex", - "geminiSaved": "Configuración de Gemini guardada", - "saveGeminiFailed": "No se pudo guardar la configuración de Gemini", - "providerDeleted": "Proveedor {providerId} eliminado", - "providerDeleteFailed": "No se pudo eliminar el proveedor {providerId}", - "providerSaved": "Proveedor {providerId} guardado", - "saveProviderFailed": "No se pudo guardar el proveedor {providerId}", - "openCodeConfigSynced": "La configuración de OpenCode y auth JSON se sincronizaron.", - "openCodeSaved": "Configuración de OpenCode guardada", - "saveOpenCodeFailed": "No se pudo guardar la configuración de OpenCode", - "openClawSaved": "Configuración de OpenClaw guardada", - "saveOpenClawFailed": "No se pudo guardar la configuración de OpenClaw", - "configSaved": "Configuración guardada", - "configSavedHint": "Las sesiones existentes deben reabrirse para que surta efecto", - "saveConfigManagementFailed": "No se pudo guardar la gestión de configuración", - "clineSaved": "Configuración de Cline guardada", - "saveClineFailed": "Error al guardar la configuración de Cline", - "hermesSaved": "Configuración de Hermes guardada", - "saveHermesFailed": "Error al guardar la configuración de Hermes", - "codeBuddySaved": "Configuración de CodeBuddy guardada", - "saveCodeBuddyFailed": "No se pudo guardar la configuración de CodeBuddy", - "kimiCodeSaved": "Configuración de Kimi Code guardada", - "saveKimiCodeFailed": "Error al guardar la configuración de Kimi Code", - "deepseekSaved": "Configuración de DeepSeek guardada", - "saveDeepSeekFailed": "No se pudo guardar la configuración de DeepSeek", - "modelProviderRequired": "Seleccione un proveedor de modelo antes de guardar.", - "affectedRunningSessions": "{count, plural, one {# sesión activa necesita reconectarse para aplicar el cambio} other {# sesiones activas necesitan reconectarse para aplicar el cambio}}", - "providerConnected": "Conectado {providerId}", - "connectFailed": "Error al conectar {providerId}", - "providerDisconnected": "Desconectado {providerId}", - "disconnectFailed": "Error al desconectar {providerId}", - "catalogRefreshed": "Catálogo actualizado: {count} proveedores", - "catalogRefreshFailed": "Error al actualizar el catálogo", - "piSaved": "Configuración de Pi guardada", - "savePiFailed": "No se pudo guardar la configuración de Pi", - "piRuntimeSaved": "Entorno de Pi guardado", - "savePiRuntimeFailed": "No se pudo guardar el entorno de Pi", - "piBinaryInstalled": "pi instalado", - "piBinaryInstallFailed": "Error al instalar pi", - "piBinaryUninstalled": "pi desinstalado", - "piBinaryUninstallFailed": "Error al desinstalar pi", - "savePiTrustFailed": "Error al guardar la confianza del espacio de trabajo" - }, - "version": { - "statusLabel": "Estado de versión", - "notInstalled": "No instalado", - "remoteLocal": "Remota: {remoteVersion} · Local: {localVersion}", - "localOnly": "Local: {localVersion}", - "localInstalled": "{versionText}. Instalado.", - "platformUnsupported": "{versionText}. La plataforma actual no soporta este agente.", - "uvxNotReady": "{versionText}. El runtime de uv no está instalado: instálalo desde la comprobación de uv de abajo para usar este agente.", - "clickInstall": "{versionText}. Haz clic en Instalar a la derecha.", - "localUnrecognized": "{versionText}. La versión local no es comparable; intenta actualizar para sobrescribir la instalación.", - "upgradeAvailable": "{versionText}. Hay actualización disponible.", - "remoteUnavailable": "{versionText}. La versión remota no está disponible por ahora.", - "latest": "{versionText}. Ya está en la última versión." - }, - "adapter": { - "label": "Adaptador ACP", - "badge": "Adaptador ACP", - "badgeHint": "Para este agente Codeg instala un paquete adaptador ACP, no la CLI del proveedor. Son independientes y comparten la misma configuración.", - "learnMore": "Más información", - "missingWithNative": "Se encontró tu {nativeLabel} en {nativePath}. Codeg habla con los agentes mediante ACP y esa CLI no habla ACP, así que Codeg necesita un paquete adaptador aparte, {adapterPackage}, mantenido por el proyecto Agent Client Protocol (originalmente Zed). Incluye su propio runtime, nunca modifica ni reemplaza tu comando {nativeCmd} y lee el mismo {configDir}: tu sesión y tus ajustes actuales se conservan. Instálalo abajo.", - "missing": "Codeg habla con los agentes mediante ACP y la {nativeLabel} no habla ACP, así que Codeg necesita un paquete adaptador aparte, {adapterPackage}, mantenido por el proyecto Agent Client Protocol (originalmente Zed). Incluye su propio runtime, por lo que no hace falta instalar antes la CLI {nativeCmd}; si ya la tienes, ambas conviven y comparten la sesión y los ajustes de {configDir}. Instálalo abajo.", - "readyWithNative": "El adaptador {adapterCmd} está instalado: es lo que Codeg ejecuta, no tu propio {nativeCmd} en {nativePath}. Son paquetes distintos que conviven y ambos leen {configDir}, así que la sesión y los ajustes son compartidos.", - "ready": "El adaptador {adapterCmd} está instalado: es lo que Codeg ejecuta. Incluye su propio runtime, así que la {nativeLabel} no es necesaria; si la instalas después, ambas conviven y comparten {configDir}." - }, - "cline": { - "configDescription": "Configure el proveedor de API y las credenciales de Cline. La configuración se guarda en ~/.cline/data/." - }, - "opencodePlugins": { - "title": "Plugins de OpenCode", - "declared": "Plugins declarados", - "noPlugins": "No hay plugins declarados en opencode.json", - "status": { - "installed": "Instalado", - "missing": "No instalado" - }, - "installAll": "Instalar todos los faltantes", - "pinVersions": "Fijar versiones @latest", - "install": "Instalar", - "uninstall": "Desinstalar", - "refresh": "Actualizar", - "success": "Todos los plugins se instalaron correctamente", - "failed": "La operación del plugin falló" - }, - "pi": { - "configManagement": "Configuración de Pi", - "configDescription": "Pi se autentica con la clave API de tu proveedor de modelos. La clave se escribe en ~/.pi/agent/auth.json y la selección de modelo en settings.json.", - "providerLabel": "Proveedor", - "modelLabel": "Modelo", - "thinkingLabel": "Razonamiento", - "thinking": { - "off": "Desactivado", - "low": "Bajo", - "medium": "Medio", - "high": "Alto", - "minimal": "Mínimo", - "xhigh": "Muy alto" - }, - "apiKeyLabel": "Clave API", - "apiKeyHint": "Se guarda en ~/.pi/agent/auth.json para el proveedor seleccionado.", - "apiKeySetPlaceholder": "•••••• (guardada — déjalo vacío para mantener)", - "saveConfig": "Guardar configuración de Pi", - "providerModelRequired": "El proveedor y el modelo son obligatorios", - "runtimeTitle": "Entorno de ejecución", - "runtimeDescription": "Elige qué binario de pi se ejecuta. Usa el predeterminado o apunta a tu propia compilación de pi.", - "modeDefault": "pi predeterminado", - "modeDefaultHint": "Usa el adaptador pi-acp integrado con el pi de tu PATH. Instala pi con: npm install -g @earendil-works/pi-coding-agent", - "modeCustom": "pi personalizado", - "modeCustomHint": "Ejecuta tu propia compilación, instalación o envoltorio de pi.", - "commandLabel": "Comando o ruta de pi", - "commandHint": "Una ruta absoluta, un nombre de comando en el PATH o un script envoltorio (p. ej. ./pi-test.sh de un monorepo).", - "commandNotFound": "Comando no encontrado", - "validate": "Validar", - "advanced": "Avanzado", - "configDirLabel": "Directorio de configuración (PI_CODING_AGENT_DIR)", - "sessionDirLabel": "Directorio de sesiones (PI_CODING_AGENT_SESSION_DIR)", - "flagsHint": "pi-acp no reenvía flags personalizados de pi (--approve, -e, …); envuelve pi en un script y apunta el comando a él.", - "customIncomplete": "Introduce un comando de pi para guardar", - "saveRuntime": "Guardar entorno", - "providerPlaceholder": "Seleccionar un proveedor", - "customProvider": "Proveedor personalizado…", - "providerIdLabel": "ID del proveedor", - "apiProtocolLabel": "Protocolo de API", - "baseUrlLabel": "Endpoint de API (Base URL)", - "customProviderHint": "Define un proveedor en ~/.pi/agent/models.json hacia tu endpoint. La mayoría de los servidores autoalojados o proxy usan openai-completions.", - "baseUrlRequired": "El endpoint de API (Base URL) es obligatorio", - "binaryTitle": "binario pi (pi-coding-agent)", - "binaryDescription": "pi-acp ejecuta este binario pi. Instálalo aquí o apunta pi-acp a tu propia compilación más abajo.", - "binaryInstalled": "Instalado", - "binaryMissing": "No instalado", - "binaryChecking": "Comprobando…", - "installBinary": "Instalar pi", - "installing": "Instalando…", - "recheck": "Volver a comprobar", - "configDirSkillsNote": "Con un directorio de configuración personalizado, las habilidades, los expertos y las herramientas de oficina gestionados en Ajustes no se aplican a este pi; gestiona sus habilidades directamente en esa carpeta.", - "projectTrustTitle": "Confianza del proyecto", - "projectTrustDescription": "Carpetas desde las que permitiste que pi cargue archivos del proyecto. Una carpeta de confianza permite que las .pi/extensions de ese repositorio ejecuten código al iniciar pi, se aplica a todas las carpetas que contiene y también se usa cuando ejecutas pi en una terminal.", - "projectTrustLoading": "Cargando…", - "projectTrustEmpty": "Aún no hay carpetas decididas.", - "projectTrustTrusted": "De confianza", - "projectTrustDenied": "Sin confianza", - "projectTrustRevoke": "Revocar", - "reasoningTitle": "Razonamiento", - "reasoningEnableLabel": "Activar", - "reasoningDescription": "pi solo envía un esfuerzo de razonamiento para un modelo que lo declara: en un modelo sin declarar, todos los niveles se reducen a Off, así que el selector del compositor vuelve atrás en cuanto lo tocas. Se escribe en la entrada de este modelo en models.json.", - "levelsLabel": "Niveles disponibles", - "levelsHint": "Serán las filas del selector de razonamiento del compositor. Elige los que acepte tu endpoint; pi rechaza cualquier nivel que no esté aquí.", - "levelsEmptyError": "Elige al menos un nivel: sin ninguno, pi vuelve a Off.", - "wireValuesTitle": "Avanzado: valores enviados al proveedor", - "wireValuesHint": "Déjalo vacío para enviar el nombre del nivel tal cual. Defínelo cuando tu endpoint espere otra cosa: los backends al estilo de Google quieren LOW / HIGH.", - "defaultLevelUnlisted": "Este nivel no está en la lista de arriba: pi lo reduciría." - }, - "addCustomAgent": "Añadir agente personalizado", - "addCustomAgentHint": "Registra cualquier agente compatible con ACP. Elige uno del registro público de ACP o pega su información de registro.", - "customAgentFromRegistry": "Registro ACP", - "customAgentManual": "Manual", - "customAgentSearchPlaceholder": "Buscar agentes…", - "customAgentLoadingCatalog": "Cargando el registro ACP…", - "customAgentRetry": "Reintentar", - "customAgentNoResults": "No hay agentes coincidentes", - "customAgentAdd": "Añadir", - "customAgentAlreadyAdded": "Añadido", - "customAgentUnsupportedPlatform": "No hay compilación disponible para esta plataforma", - "customAgentAdded": "{name} añadido", - "customAgentIdLabel": "ID del registro", - "customAgentNameLabel": "Nombre visible", - "customAgentVersionLabel": "Versión", - "customAgentSpecLabel": "Distribución (JSON)", - "customAgentSpecHint": "Misma forma que el objeto distribution del registro ACP: canales npx, uvx y binary, o pega una entrada completa del registro. En npx/uvx, cmd es el ejecutable que instala el paquete; se deriva del nombre del paquete si se omite, así que indícalo cuando difieran. binary se organiza por clave de plataforma (esta máquina: {platform}); su cmd es la ruta de arranque dentro del archivo y sha256 verifica opcionalmente la descarga.", - "customAgentTemplateLabel": "Plantillas", - "customAgentKindLabel": "Iniciar mediante", - "customAgentInvalidJson": "JSON no válido", - "customAgentNoDistribution": "No se encontró distribución npx, uvx ni binary", - "customAgentCancel": "Cancelar", - "customAgentSave": "Añadir agente", - "customAgentSaveChanges": "Guardar cambios", - "customAgentEdit": "Editar agente", - "customAgentEditHint": "Actualiza el nombre, el icono, la distribución y las declaraciones de skills. El ID del agente no puede cambiarse.", - "customAgentEditNotFound": "No se encontró el agente personalizado {id}", - "customAgentSaved": "{name} guardado", - "customAgentVersionProbeLabel": "Comando de consulta de versión (opcional)", - "customAgentVersionProbeHint": "Comando que imprime la versión instalada localmente. Si se deja vacío, codeg ejecuta el comando del agente con --version.", - "customAgentRemove": "Eliminar agente", - "customAgentRemoveHint": "Elimina la definición del agente. Las conversaciones existentes conservan su historial; el agente simplemente ya no se puede iniciar.", - "customAgentIconLabel": "Icono (opcional)", - "customAgentIconUpload": "Subir", - "customAgentIconReplace": "Reemplazar", - "customAgentIconClear": "Quitar icono", - "customAgentIconHint": "Se guarda junto al agente, así funciona sin conexión. Si no indicas ninguno, se usa una inicial de color.", - "customAgentSkillsLabel": "Skills (.agents/skills compartido)", - "customAgentSkillsHint": "Declara que este agente lee el almacén compartido .agents/skills (directorios global y de proyecto) y lo añade a todas las matrices de habilidades. Las habilidades vinculadas allí son visibles para todos los agentes que leen ese almacén compartido.", - "customAgentSkillsDirLabel": "Directorio de skills dedicado", - "customAgentSkillsDirHint": "Ruta absoluta del directorio desde el que este agente carga skills: su propio almacén, además del compartido o en su lugar. ~ se expande al directorio personal; las skills vinculadas se colocan aquí primero.", - "customAgentMcpLabel": "Compatibilidad con MCP", - "customAgentMcpHint": "Envía el complemento MCP integrado de codeg a este agente al iniciar la sesión: es el canal de la delegación, los comentarios en vivo y las herramientas de tareas. Desactívalo para un agente que rechaza servidores MCP y no llega a conectarse; el cambio se aplica en la próxima conexión.", - "customAgentIconNotAnImage": "Selecciona un archivo de imagen.", - "customAgentIconTooLarge": "El icono debe pesar menos de {limit} KB.", - "customAgentIconReadFailed": "No se pudo leer esa imagen.", - "customAgentRemoveConfirm": "¿Eliminar {name}? Las conversaciones existentes se conservan, pero el agente ya no podrá iniciarse.", - "customAgentRemoveWithData": "Eliminar también su historial de conversaciones registrado", - "customAgentRemoved": "{name} eliminado", - "customAgentBadge": "Personalizado", - "customAgentNotLaunchable": "Este agente no puede iniciarse aquí: {reason}" - }, - "SettingsPages": { - "agentsLoading": "Cargando configuración de agentes...", - "skillPacksLoading": "Cargando paquetes de habilidades…" - }, - "GeneralSettings": { - "loading": "Cargando...", - "sectionTitle": "General", - "sectionDescription": "Preferencias centralizadas para el terminal predeterminado, la aceleración de renderizado y la delegación entre agentes.", - "terminalTitle": "Terminal predeterminada", - "terminalDescription": "Elige el shell que se usa al abrir nuevas pestañas de terminal desde la barra de terminal o el árbol de archivos. Los agentes también lo usan cuando piden a codeg que ejecute una línea de comandos completa.", - "terminalSystemDefault": "Predeterminado del sistema", - "terminalPowerShell7": "PowerShell 7 (pwsh)", - "terminalWindowsPowerShell": "Windows PowerShell", - "terminalCmd": "Símbolo del sistema (cmd)", - "terminalSaveFailed": "Error al guardar la configuración del terminal: {message}", - "terminalShellCustom": "Ruta personalizada", - "terminalShellCustomPath": "Ruta del shell", - "terminalShellCustomPlaceholder": "/usr/local/bin/fish", - "terminalShellCustomSave": "Guardar", - "terminalShellCustomHint": "Indica una ruta absoluta o un nombre resoluble en PATH.", - "terminalShellNotInstalled": "no instalado", - "terminalShellNotFoundWarning": "Esta ruta no existe en este host.", - "terminalCurrentShell": "En uso actualmente: {path}", - "renderingDescription": "Desactiva la aceleración por hardware si la aplicación muestra pantalla negra o fallos de renderizado (común en algunas GPU AMD o Intel integradas). Solo afecta a la versión de escritorio en Windows.", - "disableHardwareAcceleration": "Desactivar aceleración por hardware", - "renderingSaveFailed": "No se pudo guardar la configuración de renderizado: {message}", - "restartRequired": "Guardado. Reinicia la aplicación para aplicar el cambio.", - "restartNow": "Reiniciar ahora", - "restartFailed": "No se pudo reiniciar: {message}", - "loadFailed": "Error al cargar: {message}" - }, - "LoginPage": { - "documentTitle": "Iniciar sesión - codeg", - "brand": "Codeg", - "subtitle": "Introduce tu token de acceso para conectarte a la aplicación de escritorio", - "tokenPlaceholder": "Token de acceso", - "connect": "Conectar", - "connecting": "Conectando...", - "helpText": "Encuentra tu token en la aplicación de escritorio en Configuración → Servicio web", - "invalidToken": "Token no válido. Por favor, comprueba e inténtalo de nuevo.", - "connectionFailed": "Error de conexión (HTTP {status})", - "networkError": "No se puede conectar al servidor" - }, - "CommitPage": { - "title": "Confirmación", - "invalidFolderId": "ID de carpeta no válido", - "loadingRepo": "Cargando repositorio..." - }, - "MergePage": { - "title": "Resolver conflictos", - "invalidFolderId": "ID de carpeta no válido", - "loadingRepo": "Cargando repositorio...", - "localVersion": "Local (Nuestro)", - "result": "Resultado", - "remoteVersion": "Remoto (Suyo)", - "acceptLocal": "Aceptar local", - "acceptRemote": "Aceptar remoto", - "markResolved": "Marcar como resuelto", - "abortMerge": "Abortar", - "completeMerge": "Completar fusión", - "unresolvedConflicts": "Todavía hay marcadores de conflicto sin resolver en este archivo", - "fileResolved": "Archivo resuelto correctamente", - "allResolved": "Todos los conflictos resueltos", - "conflictFiles": "Archivos en conflicto", - "loadingFile": "Cargando archivo...", - "preparingMerge": "Preparando fusión...", - "selectFile": "Seleccionar un archivo para resolver", - "noConflicts": "No hay archivos en conflicto", - "skipFile": "Omitir", - "abortSuccess": "Operación abortada", - "applyAllNonConflicting": "Aplicar todos los cambios sin conflicto", - "applyLeftNonConflicting": "Aplicar local", - "applyRightNonConflicting": "Aplicar remoto" - }, - "ImportSessions": { - "title": "Importar sesiones locales", - "scanningTitle": "Escaneando sesiones locales de los agentes…", - "scanningHint": "Recorriendo el almacén local de sesiones de cada agente. Con historiales grandes puede tardar un momento. Las sesiones ya importadas se actualizan por el camino.", - "scanFailed": "Error al escanear", - "retry": "Reintentar", - "rescan": "Reescanear", - "empty": "No se encontraron sesiones locales", - "emptyHint": "No se encontraron almacenes de sesiones de agentes en este equipo.", - "noMatches": "Ninguna sesión coincide con los filtros actuales", - "searchPlaceholder": "Buscar título o ruta…", - "allAgents": "Todos los agentes", - "onlyImportable": "Solo importables", - "selectAll": "Seleccionar todo", - "clearSelection": "Limpiar", - "expandAll": "Expandir todo", - "collapseAll": "Contraer todo", - "summaryCounts": "{total} sesiones · {importable} importables · {folders} carpetas", - "noFolderSkipped": "{count} sin carpeta de proyecto omitidas", - "folderNew": "Nueva", - "folderCounts": "{importable}/{total} importables", - "toggleFolderAria": "Seleccionar todas las sesiones importables de {name}", - "toggleSessionAria": "Seleccionar la sesión {title}", - "statusImported": "Importada", - "statusDeleted": "Eliminada", - "untitled": "Sesión sin título", - "messageCount": "{count} mensajes", - "selectedCount": "{count} seleccionadas", - "importSelected": "Importar selección", - "importing": "Importando…", - "close": "Cerrar", - "doneTitle": "Importación finalizada", - "doneImported": "Importadas", - "doneUpdated": "Actualizadas", - "doneSkipped": "Omitidas", - "doneCreatedFolders": "Carpetas creadas", - "doneNotFound": "No encontradas", - "doneFailed": "Fallidas", - "continueImport": "Seguir importando", - "toasts": { - "importFailed": "Error al importar: {message}" - } - }, - "Folder": { - "workspaceStatus": { - "degradedTitle": "Actualizaciones en vivo no disponibles", - "degradedHint": "El observador no pudo iniciarse (por ejemplo, permiso denegado). Actualiza manualmente para ver los cambios.", - "retry": "Reintentar", - "retrying": "Reintentando..." - }, - "common": { - "all": "Todo", - "cancel": "Cancelar", - "close": "Cerrar", - "closeOthers": "Cerrar otros", - "closeAll": "Cerrar todo", - "confirm": "Confirmar", - "save": "Guardar", - "delete": "Eliminar", - "rename": "Renombrar", - "loading": "Cargando...", - "refresh": "Actualizar", - "refreshing": "Actualizando...", - "create": "Crear", - "createAndSwitch": "Crear y cambiar", - "openFile": "Abrir archivo", - "viewDiff": "Ver Diff", - "push": "Enviar..." - }, - "statusLabels": { - "in_progress": "En progreso", - "pending_review": "Revisión", - "completed": "Completado", - "cancelled": "Cancelado" - }, - "sidebar": { - "title": "Conversaciones", - "locateActiveConversation": "Ubicar conversación activa", - "expandAllGroups": "Expandir todos los grupos", - "collapseAllGroups": "Colapsar todos los grupos", - "newConversation": "Nueva conversación", - "newConversationShort": "Nueva", - "newChat": "Nueva conversación", - "search": "Buscar", - "noConversationsFound": "No se encontraron conversaciones.", - "importLocalSessions": "Importar sesiones locales", - "importing": "Importando...", - "error": "Error del sistema: {message}", - "completeAllSessions": "Completar todas las sesiones", - "completeAllReviewTitle": "¿Completar todas las sesiones en revisión?", - "completeAllReviewDescription": "Esto marcará como completadas todas las {count, plural, one {# sesión} other {# sesiones}} en Revisión.", - "completing": "Completando...", - "toasts": { - "importedSessions": "Se importaron {imported, plural, one {# sesión} other {# sesiones}}, se omitieron {skipped}", - "importedAndUpdated": "Se importaron {imported, plural, one {# sesión} other {# sesiones}}, se actualizaron {updated, plural, one {# título} other {# títulos}}, se omitieron {skipped}", - "updatedTitles": "Se actualizaron {updated, plural, one {# título} other {# títulos}}, se omitieron {skipped}", - "noNewSessionsFound": "No se encontraron sesiones nuevas (omitidas {skipped})", - "importFailed": "Error al importar: {message}", - "reviewCompleted": "Se marcaron como completadas {count, plural, one {# sesión en revisión} other {# sesiones en revisión}}", - "completeReviewFailed": "Error al completar sesiones en revisión: {message}", - "folderOpened": "Carpeta {name} abierta", - "folderRemoved": "Carpeta {name} eliminada", - "openFolderFailed": "Error al abrir carpeta", - "removeFolderFailed": "Error al eliminar carpeta: {message}", - "reorderFoldersFailed": "Error al reordenar carpetas: {message}", - "changeFolderColorFailed": "Error al cambiar el color: {message}", - "setFolderAliasFailed": "Error al establecer el alias: {message}", - "changeFolderDefaultAgentFailed": "Error al establecer agente predeterminado: {message}" - }, - "statsLabel": "{folders} carpetas · {convos} conversaciones", - "reorderHandle": "Arrastrar para reordenar", - "openFolder": "Abrir carpeta", - "searchPlaceholder": "Buscar conversaciones...", - "viewOptions": "Opciones de visualización", - "showCompleted": "Mostrar conversaciones completadas", - "showWorktrees": "Mostrar carpetas de worktree", - "showRecent": "Mostrar grupo Recientes", - "moreOptions": "Más opciones", - "sortBy": "Ordenar por", - "sortByCreatedAt": "Fecha de creación", - "sortByUpdatedAt": "Fecha de actualización", - "sectionOrder": "Orden de secciones", - "sectionOrderMoveUp": "Subir", - "sectionOrderMoveDown": "Bajar", - "sectionOrderItemLabel": "{name} — posición {position} de {total}", - "statusRunningBadge": "Ejecutando", - "runningCountBadge": "{count, plural, one {# sesión en ejecución} other {# sesiones en ejecución}}", - "statusCancelledBadge": "Cancelado", - "worktreeRemovedBadge": "Worktree de origen eliminado", - "conversationCountUnit": "{count, plural, one {# conversación} other {# conversaciones}}", - "emptyFolderHint": "Sin conversaciones", - "noMatchingConversations": "No hay conversaciones coincidentes", - "noUnfinishedConversations": "No hay conversaciones pendientes. Activa \"Mostrar completadas\" desde el menú superior derecho.", - "removeFolderConfirmTitle": "¿Eliminar carpeta del espacio de trabajo?", - "removeFolderConfirmDescription": "¿Eliminar \"{name}\" del espacio de trabajo? Sus pestañas y terminales se cerrarán.", - "folderHeaderMenu": { - "manageConversations": "Gestionar conversaciones…", - "manageLinks": "Carpetas vinculadas", - "changeColor": "Cambiar color", - "useThemeColor": "Usar tema de la app", - "setDefaultAgent": "Establecer agente predeterminado", - "defaultAgentNone": "Sin valor (usar predeterminado global)", - "agentUnavailableSuffix": "(no disponible)", - "loadingAgents": "Cargando agentes…", - "setAlias": "Establecer alias…", - "setAliasTitle": "Establecer alias de la carpeta", - "setAliasPlaceholder": "Introduce un alias (déjalo vacío para borrarlo)", - "setAliasSave": "Guardar", - "setAliasCancel": "Cancelar", - "removeFromWorkspace": "Quitar del espacio de trabajo" - }, - "manageConversations": { - "title": "Gestionar conversaciones", - "searchPlaceholder": "Buscar por título…", - "agentFilterAll": "Todos los agentes", - "statusFilterAll": "Todos los estados", - "folderFilterAll": "Todas las carpetas", - "branchFilterAll": "Todas las ramas", - "branchNone": "Sin rama", - "branchSearchPlaceholder": "Buscar ramas…", - "noMatchingBranches": "No hay ramas coincidentes", - "selectAllVisible": "Seleccionar todo", - "deselectAll": "Deseleccionar todo", - "selectedCount": "{count} seleccionada(s)", - "matchedCount": "{count} coincidencia(s)", - "untitledConversation": "Conversación sin título", - "setStatus": "Cambiar estado…", - "deleteSelected": "Eliminar", - "noConversations": "No hay conversaciones en esta carpeta.", - "noConversationsWorkspace": "No hay conversaciones en el espacio de trabajo.", - "noMatchingConversations": "Ninguna conversación coincide con los filtros.", - "confirmDeleteTitle": "¿Eliminar {count} conversación(es)?", - "confirmDeleteDescription": "Esta acción no se puede deshacer.", - "toastDeleted": "Se eliminaron {count} conversación(es)", - "toastStatusUpdated": "Estado actualizado para {count} conversación(es)", - "toastOpFailed": "Error en la operación: {message}" - }, - "sectionPinned": "Fijadas", - "sectionFolders": "Carpetas", - "sectionChats": "Chat", - "sectionRecent": "Recientes", - "noChats": "Sin chats", - "noRecent": "Sin conversaciones recientes", - "showMoreRecent": "Mostrar más ({count})", - "noFolders": "No hay carpetas abiertas", - "newChatAction": "Nuevo chat", - "automations": "Automatizaciones", - "tasks": "Tareas pendientes", - "loadingSubsessions": "Cargando subconversaciones…" - }, - "conversation": { - "reloadFailed": "No se pudo recargar la conversación: {message}", - "reloaded": "Conversación recargada", - "reload": "Recargar", - "activeConversationIndicator": "Conversación activa", - "newConversation": "Nueva conversación", - "closeConversation": "Cerrar conversación", - "copyText": "Copiar texto", - "copyTextSuccess": "Copiado", - "copyTextFailed": "Error al copiar", - "forkSession": "Bifurcar sesión", - "forkSessionSuccess": "Sesión bifurcada exitosamente", - "forkSessionFailed": "Error al bifurcar la sesión: {error}", - "exportConversation": "Exportar conversación", - "exportImage": "Imagen", - "exportMarkdown": "Markdown", - "exportHtml": "HTML", - "exportSuccess": "Conversación exportada", - "exportFailed": "Error al exportar", - "exportImageTooLong": "La conversación es demasiado larga para exportar como imagen", - "exportLabels": { - "untitledConversation": "Conversación sin título", - "agent": "Agente", - "model": "Modelo", - "status": "Estado", - "started": "Inicio", - "updated": "Actualizado", - "tokens": "Estadísticas de tokens", - "duration": "Duración", - "inputTokens": "Entrada", - "outputTokens": "Salida", - "cacheRead": "Caché leída", - "cacheWrite": "Caché escrita", - "user": "Usuario", - "assistant": "Asistente", - "system": "Sistema", - "toolResult": "Resultado", - "toolError": "Error" - }, - "moreActions": "Más acciones" - }, - "sessionDetails": { - "menuLabel": "Detalles de la sesión", - "noActiveSession": "No hay ninguna sesión activa", - "title": "Detalles de la sesión", - "subtitle": "Metadatos de la sesión y uso de tokens", - "fieldTitle": "Título", - "untitled": "Conversación sin título", - "sessionId": "ID de sesión", - "externalId": "ID de extensión", - "agent": "Agente", - "model": "Modelo", - "status": "Estado", - "gitBranch": "Rama de Git", - "parentId": "Sesión principal", - "tokensHeading": "Uso de tokens", - "totalTokens": "Total", - "inputTokens": "Entrada", - "outputTokens": "Salida", - "cacheWrite": "Caché escrita", - "cacheRead": "Caché leída", - "contextWindow": "Ventana de contexto", - "duration": "Duración", - "loadingStats": "Cargando uso de tokens…", - "loadFailed": "Error al cargar el uso de tokens", - "noStats": "Sin uso registrado", - "timestampsHeading": "Marcas de tiempo", - "createdAt": "Creado", - "updatedAt": "Actualizado", - "none": "—", - "copyField": "Copiar {field}", - "copiedField": "{field} copiado" - }, - "conversationCard": { - "untitledConversation": "Conversación sin título", - "newConversation": "Nueva conversación", - "rename": "Renombrar", - "status": "Estado", - "delete": "Eliminar", - "importLocalSessions": "Importar sesiones locales", - "importing": "Importando...", - "renameConversation": "Renombrar conversación", - "deleteConversationTitle": "¿Eliminar conversación?", - "deleteConversationDescription": "Esto eliminará \"{title}\". Esta acción no se puede deshacer.", - "cancel": "Cancelar", - "save": "Guardar", - "pin": "Fijar", - "unpin": "Dejar de fijar", - "markCompleted": "Marcar como completada", - "reopen": "Reabrir", - "expandSubsessions": "Expandir subconversaciones", - "collapseSubsessions": "Contraer subconversaciones" - }, - "search": { - "dialogTitle": "Buscar", - "dialogTitleWithFolder": "Buscar — {name}", - "tabConversations": "Conversaciones", - "tabFiles": "Archivos", - "placeholder": "Buscar conversaciones...", - "filePlaceholder": "Buscar archivos o directorios...", - "allAgents": "Todo", - "searching": "Buscando...", - "typeToSearch": "Escribe para buscar conversaciones", - "typeToSearchFiles": "Escribe para buscar archivos o directorios", - "noResults": "No se encontraron resultados.", - "untitledConversation": "Conversación sin título" - }, - "folderTitleBar": { - "showSidebar": "Mostrar barra lateral", - "hideSidebar": "Ocultar barra lateral", - "toggleTerminal": "Alternar terminal", - "toggleAuxPanel": "Alternar panel auxiliar", - "search": "Buscar", - "openSettings": "Abrir configuración", - "backToConversations": "Volver a conversaciones", - "withShortcut": "{label} (atajo: {shortcut})" - }, - "statusBar": { - "connection": { - "connected": "Conectado", - "connecting": "Conectando...", - "prompting": "Respondiendo...", - "error": "Error de conexión", - "disconnected": "Desconectado", - "tooltip": "{agent}: {status}", - "tooltipError": "{agent}: {error}", - "title": "Conexión del agente", - "triggerAria": "Conexión del agente: {status}", - "workingDir": "Directorio de trabajo", - "sessionId": "ID de sesión", - "viewerNote": "Conectado a una sesión que pertenece a otro cliente: reconectar solo vuelve a adjuntar esta vista.", - "reconnectInterrupts": "Reconectar reinicia el agente e interrumpe el trabajo en curso.", - "reconnect": "Reconectar", - "reconnecting": "Reconectando...", - "reconnectUnavailable": "Aún no hay ninguna sesión a la que reconectar." - }, - "tasks": { - "title": "Tareas" - }, - "alerts": { - "title": "Alertas", - "empty": "Sin alertas", - "details": "Detalles" - }, - "stats": { - "conversations": "{count} conversaciones", - "openUsage": "Ver estadísticas de sesiones y uso de tokens" - }, - "tokens": { - "contextWindowUsageAria": "Uso de la ventana de contexto", - "contextWindow": "Ventana de contexto", - "usedMax": "Usado / Máx", - "tokenUsage": "Uso de tokens", - "input": "Entrada", - "output": "Salida", - "cacheRead": "Lectura de caché", - "cacheWrite": "Escritura de caché", - "total": "Total de tokens" - } - }, - "auxPanel": { - "tabs": { - "files": "Archivos", - "changes": "Cambios", - "commits": "Confirmaciones" - }, - "noFolderTitle": "No hay carpeta abierta", - "noFolderHint": "Abre una carpeta para ver su contenido aquí" - }, - "windowControls": { - "minimizeWindow": "Minimizar ventana", - "minimize": "Minimizar", - "maximizeWindow": "Maximizar ventana", - "maximize": "Maximizar", - "restoreWindow": "Restaurar ventana", - "restore": "Restaurar", - "closeWindow": "Cerrar ventana", - "close": "Cerrar" - }, - "tabs": { - "closeConversationTab": "Cerrar pestaña de conversación", - "close": "Cerrar", - "closeOthers": "Cerrar otros", - "splitRight": "Dividir a la derecha", - "splitDown": "Dividir abajo", - "splitAndMoveRight": "Dividir y mover a la derecha", - "splitAndMoveDown": "Dividir y mover abajo", - "moveToOppositeGroup": "Mover al grupo opuesto", - "moveToGroup": "Mover al grupo", - "groupLabel": "Grupo {index}", - "changeSplitterOrientation": "Cambiar orientación del divisor", - "unsplit": "Deshacer división", - "unsplitAll": "Deshacer todas las divisiones", - "closeAll": "Cerrar todo", - "tileDisplay": "Vista en mosaico", - "untileDisplay": "Salir de mosaico" - }, - "fileWorkspace": { - "files": "Archivos", - "closeFileTab": "Cerrar pestaña de archivo", - "close": "Cerrar", - "closeOthers": "Cerrar otros", - "closeAll": "Cerrar todo", - "preview": "Vista previa", - "editSource": "Editar fuente", - "maximize": "Maximizar", - "restore": "Restaurar", - "emptyDirectory": "Carpeta vacía" - }, - "terminal": { - "rename": "Renombrar", - "close": "Cerrar", - "closeOthers": "Cerrar otros", - "closeAll": "Cerrar todo", - "hideTerminal": "Ocultar terminal ({shortcut})", - "openFolderFirst": "Abre primero una carpeta" - }, - "workspaceDialog": { - "title": "Abrir carpeta", - "manageTitle": "Carpetas vinculadas", - "addTargetsTitle": "Añadir carpetas para vincular", - "pickRootDescription": "Elige la carpeta principal de este espacio de trabajo.", - "linksDescription": "Vincula otras carpetas como subdirectorios para que los agentes trabajen en todas ellas desde un solo espacio de trabajo.", - "addTargetsDescription": "Selecciona una o más carpetas. Cada una será un subdirectorio del espacio de trabajo.", - "useSystemPicker": "Selector del sistema", - "next": "Siguiente", - "back": "Atrás", - "done": "Listo", - "change": "Cambiar", - "addFolders": "Añadir carpetas", - "addSelected": "Añadir", - "addSelectedCount": "Añadir {count}", - "createCount": "Vincular {count} carpeta(s)", - "discardPending": "Descartar", - "noLinks": "Todavía no hay carpetas vinculadas.", - "gitExclude": "Mantener los enlaces fuera del estado de git", - "rename": "Renombrar", - "unlink": "Quitar enlace", - "repair": "Recrear enlace", - "saveName": "Guardar", - "cancelRename": "Cancelar", - "removePending": "Quitar", - "willAppearAs": "Aparece como {name} en el espacio de trabajo", - "renamedForDuplicate": "Renombrada: {base} ya lo usa otro enlace", - "renamedForExistingEntry": "Renombrada: {base} ya existe en esta carpeta", - "partiallyCreated": "Solo se pudieron vincular {count} carpeta(s)", - "openFailed": "No se pudo abrir la carpeta", - "previewFailed": "No se pudieron comprobar las carpetas seleccionadas", - "createFailed": "No se pudieron vincular las carpetas", - "renameFailed": "No se pudo renombrar el enlace", - "removeFailed": "No se pudo quitar el enlace", - "repairFailed": "No se pudo recrear el enlace", - "status": { - "ok": "Vinculada", - "missing": "El enlace ya no está en esta carpeta", - "conflicted": "Otra entrada usa ahora este nombre", - "broken": "La carpeta vinculada ya no existe" - }, - "nameIssue": { - "empty": "Escribe un nombre", - "illegalChars": "No puede contener / \\ : * ? \" < > |", - "tooLong": "El nombre es demasiado largo", - "reserved": "Windows reserva este nombre", - "duplicate": "Este nombre ya está en uso" - }, - "rejection": { - "not_found": "No se encontró esta carpeta", - "not_a_directory": "Esta ruta no es una carpeta", - "same_as_root": "Es la propia carpeta del espacio de trabajo", - "ancestor_of_root": "Esta carpeta contiene el espacio de trabajo", - "inside_root": "Ya está dentro del espacio de trabajo", - "already_linked": "Ya está vinculada", - "name_unavailable": "No queda ningún nombre libre para esta carpeta", - "alreadyLinkedAs": "Ya vinculada como {name}" - } - }, - "folderNameDropdown": { - "fallbackFolderName": "Carpeta", - "openFolder": "Abrir carpeta", - "cloneRepository": "Clonar repositorio", - "projectBoot": "Inicializador de proyecto", - "opened": "Abierto", - "recentOpen": "Abiertos recientemente" - }, - "fileWorkspacePanel": { - "addSelectionToChat": "Añadir selección al chat", - "addToChat": "Añadir al chat", - "addSelectionToChatDone": "Se añadió {label} a la conversación", - "addFileToChat": "Añadir archivo al chat", - "toggleWordWrap": "Alternar ajuste de línea", - "addFileToChatDone": "Se añadió {label} a la conversación", - "viewDiff": "Ver Diff", - "openFile": "Abrir archivo", - "fileCount": "{count, plural, one {# archivo} other {# archivos}}", - "openFileOrDiff": "Abre un archivo o diff desde el panel derecho", - "disk": "Disco", - "head": "HEAD (referencia)", - "unsaved": "Sin guardar", - "workingTree": "Árbol de trabajo", - "loading": "Cargando...", - "compareWithBranch": "{path} · comparar con {branch}", - "hunkCount": "{count, plural, one {# bloque} other {# bloques}}", - "prev": "Anterior", - "next": "Siguiente", - "jumpToLine": "Ir a la línea {line}", - "noParsedDiffSections": "No hay secciones de diff analizadas", - "loadingEditor": "Cargando editor...", - "imageZoomIn": "Ampliar", - "imageZoomOut": "Reducir", - "imageZoomReset": "Restablecer zoom", - "htmlPreviewTitle": "Vista previa HTML", - "htmlPreviewTrust": "Habilitar scripts", - "htmlPreviewTrustHint": "Ejecuta los scripts de este archivo y permite el acceso a la red. Actívalo solo para archivos de confianza.", - "officePreviewTitle": "Vista previa de documento de Office", - "officeFullRender": "Renderizado completo", - "officeFullRenderHint": "Renderiza animaciones Morph, 3D y fórmulas (ejecuta los scripts de la diapositiva)", - "officeNotInstalled": "OfficeCLI no está instalado", - "officeNotInstalledHint": "Instala OfficeCLI en Ajustes → Herramientas de Office para previsualizar archivos de Word, Excel y PowerPoint.", - "officeOpenSettings": "Abrir ajustes", - "officeWatchFailed": "No se pudo iniciar la vista previa en vivo", - "officeWatchRetry": "Reintentar", - "officeServerInstallHint": "OfficeCLI debe instalarse en el host del servidor. Ejecuta este comando allí y vuelve a intentarlo:", - "officeRemoteDesktopUnsupported": "La vista previa en vivo no está disponible en una ventana de escritorio remoto. Abre este espacio de trabajo en la interfaz web del servidor para previsualizar archivos de Office." - }, - "branchDropdown": { - "toasts": { - "commitCodeCompleted": "Commit de código completado", - "pushCodeCompleted": "Push de código completado", - "committedFiles": "{count, plural, one {# archivo confirmado} other {# archivos confirmados}}", - "taskCompleted": "{label} completado", - "taskFailed": "{label} falló", - "mergeNoNewCommits": "{branchName} no tiene commits nuevos", - "mergedCommits": "{count, plural, one {# commit fusionado} other {# commits fusionados}}", - "allFilesUpToDate": "Todos los archivos están actualizados", - "updatedFiles": "{count, plural, one {# archivo actualizado} other {# archivos actualizados}}", - "openCommitWindowFailed": "No se pudo abrir la ventana de commit", - "openPushWindowFailed": "Error al abrir la ventana de envío", - "upstreamSet": "La rama upstream se ha configurado", - "upstreamSetAndPushed": "Rama upstream configurada y se enviaron {count, plural, one {# commit} other {# commits}}", - "noCommitsToPush": "No hay commits para enviar", - "pushedCommits": "Se enviaron {count, plural, one {# commit} other {# commits}}", - "switchedToFolder": "Cambiado a {name}", - "switchFailed": "No se pudo cambiar de rama", - "openStashWindowFailed": "No se pudo abrir la ventana de stash" - }, - "tasks": { - "newBranch": "Crear rama {name}", - "newWorktree": "Crear worktree {name}", - "checkoutTo": "Cambiar a {branchName}", - "mergeBranch": "Fusionar {branchName}", - "rebaseTo": "Rebase a {branchName}", - "deleteRemoteBranch": "Eliminar rama remota {branchName}", - "initGitRepo": "Inicializar repositorio Git", - "pullCode": "Hacer pull del código", - "fetchInfo": "Obtener información", - "pushCode": "Enviar código", - "stashChanges": "Guardar cambios en stash", - "stashPop": "Aplicar stash", - "deleteBranch": "Eliminar rama {branchName}", - "removeWorktree": "Eliminar el worktree de {branchName}", - "removeWorktreeAndBranch": "Eliminar el worktree y la rama {branchName}", - "updateBranch": "Actualizar la rama {branchName}" - }, - "confirm": { - "mergeTitle": "Fusionar rama", - "rebaseTitle": "Rebase de rama", - "mergeDescription": "¿Fusionar {branchName} en la rama actual {currentBranch}?", - "rebaseDescription": "¿Hacer rebase de la rama actual {currentBranch} sobre {branchName}?", - "deleteRemoteTitle": "Eliminar rama remota", - "deleteRemoteDescription": "¿Eliminar la rama remota {branchName}? Esto la eliminará del repositorio remoto y no se puede deshacer.", - "deleteTitle": "Eliminar rama", - "deleteDescription": "¿Eliminar la rama {branchName}? Esta acción no se puede deshacer.", - "forceDeleteTitle": "Forzar eliminación de rama", - "forceDeleteDescription": "La rama {branchName} no está completamente fusionada. ¿Estás seguro de que quieres forzar su eliminación? Esta acción no se puede deshacer.", - "deleteWorktreeTitle": "Eliminar worktree", - "deleteWorktreeDescription": "¿Eliminar el directorio del worktree que tiene {branchName} activa? La rama y sus commits se conservan.", - "forceDeleteWorktreeTitle": "Forzar la eliminación del worktree", - "forceDeleteWorktreeDescription": "El worktree de {branchName} tiene archivos sin confirmar o sin seguimiento. ¿Eliminarlo de todos modos? Esos cambios no se podrán recuperar.", - "deleteWorktreeAndBranchTitle": "Eliminar worktree y rama", - "deleteWorktreeAndBranchDescription": "¿Eliminar el worktree de {branchName}, la rama y su carpeta del espacio de trabajo? Sus sesiones pasan a la carpeta del repositorio. Esta acción no se puede deshacer.", - "forceDeleteWorktreeAndBranchTitle": "Forzar la eliminación del worktree y la rama", - "forceDeleteWorktreeAndBranchDescription": "El worktree de {branchName} tiene archivos sin confirmar, o la rama no está totalmente fusionada. ¿Eliminar ambos de todos modos? Esta acción no se puede deshacer." - }, - "current": "Actual", - "switchToBranch": "Cambiar a esta rama", - "mergeBranchIntoCurrent": "Fusionar {branchName} en {currentBranch}", - "rebaseCurrentToBranch": "Rebase de {currentBranch} sobre {branchName}", - "noBranch": "Sin rama", - "detachedHead": "HEAD desacoplado en {sha}", - "initGitRepo": "Inicializar repositorio Git", - "pullCode": "Hacer pull del código", - "fetchRemoteBranches": "Obtener ramas remotas", - "openCommitWindow": "Commit de código...", - "pushCode": "Enviar...", - "pushBranch": "Enviar", - "newBranch": "Nueva rama...", - "newWorktree": "Nuevo worktree...", - "stashChanges": "Guardar cambios...", - "stashPop": "Aplicar stash...", - "manageRemotes": "Gestionar remotos...", - "localBranches": "Ramas locales ({count, plural, one {#} other {#}})", - "noLocalBranches": "Sin ramas locales", - "remoteBranches": "Ramas remotas ({count, plural, one {#} other {#}})", - "noRemoteBranches": "Sin ramas remotas", - "dialogs": { - "newBranchTitle": "Nueva rama", - "newBranchDescription": "Crear una nueva rama desde la rama actual {branch}", - "branchNamePlaceholder": "Nombre de la rama", - "newWorktreeTitle": "Nuevo worktree", - "newWorktreeDescription": "Crear un nuevo worktree desde la rama actual {branch}", - "branchNameLabel": "Nombre de la rama", - "worktreePathLabel": "Ruta del worktree", - "worktreePathPlaceholder": "Ruta del worktree", - "manageRemotesTitle": "Gestionar remotos", - "manageRemotesEmpty": "No hay remotos configurados", - "remoteNamePlaceholder": "Nombre del remoto", - "remoteUrlPlaceholder": "URL del remoto", - "addRemote": "Añadir", - "savingRemotes": "Guardando..." - }, - "conflict": { - "title": "Conflictos de fusión", - "description": "Los siguientes archivos tienen conflictos que necesitan ser resueltos:", - "abort": "Abortar fusión", - "openMergeTool": "Abrir herramienta de fusión", - "completeMerge": "Completar fusión", - "abortSuccess": "Fusión abortada correctamente", - "completeSuccess": "Fusión completada correctamente" - }, - "stashDialog": { - "title": "Guardar cambios en stash", - "description": "Guardar los cambios actuales en el stash", - "messageLabel": "Mensaje", - "messagePlaceholder": "Mensaje del stash (opcional)", - "keepIndex": "Mantener índice (los cambios preparados permanecen preparados)", - "cancel": "Cancelar", - "stash": "Guardar", - "success": "Cambios guardados en stash", - "error": "Error al guardar en stash" - }, - "unstashDialog": { - "title": "Aplicar stash", - "noStashes": "No hay stashes", - "selectFile": "Selecciona un archivo para ver diferencias", - "viewDiff": "Ver diferencias", - "original": "Original", - "modified": "Modificado", - "apply": "Aplicar", - "drop": "Eliminar", - "applySuccess": "Stash aplicado", - "dropSuccess": "Stash eliminado", - "confirmApply": "¿Aplicar stash {ref} al directorio de trabajo?", - "cancel": "Cancelar" - }, - "deleteBranch": "Eliminar rama", - "deleteWorktree": "Eliminar worktree", - "deleteWorktreeAndBranch": "Eliminar worktree y rama", - "searchPlaceholder": "Buscar ramas y acciones", - "searchAriaLabel": "Buscar ramas y acciones", - "branchListLabel": "Ramas y acciones", - "noMatches": "Sin coincidencias" - }, - "commitDialog": { - "toasts": { - "commitCompleted": "Commit de código completado", - "pushFailed": "Error al enviar", - "committedFiles": "{count, plural, one {# archivo confirmado} other {# archivos confirmados}}", - "addedToVcs": "Añadido a VCS", - "addToVcsFailed": "No se pudo añadir a VCS", - "fileDeleted": "Archivo eliminado", - "deleteFailed": "Error al eliminar", - "fileRolledBack": "Archivo revertido", - "rollbackFailed": "Error al revertir", - "dirRolledBack": "Directorio revertido", - "dirDeleted": "Directorio eliminado" - }, - "confirm": { - "deleteTitle": "Confirmar eliminación", - "deleteDescription": "¿Eliminar el archivo \"{file}\"? Esta acción no se puede deshacer.", - "rollbackTitle": "Confirmar reversión", - "rollbackDescription": "¿Revertir el archivo \"{file}\" a HEAD? Se perderán los cambios sin guardar.", - "rollbackDirDescription": "¿Revertir el directorio \"{dir}\" a HEAD? Los cambios no guardados se perderán.", - "deleteDirDescription": "¿Eliminar el directorio \"{dir}\"? Esta acción no se puede deshacer." - }, - "actions": { - "select": "Seleccionar", - "unselect": "Deseleccionar", - "rollback": "Revertir", - "addToVcs": "Añadir a VCS" - }, - "aria": { - "selectFile": "{action}: {path}", - "unselectAllFiles": "Deseleccionar todos los archivos", - "selectAllFiles": "Seleccionar todos los archivos", - "unselectTracked": "Deseleccionar cambios rastreados", - "selectTracked": "Seleccionar cambios rastreados", - "unselectUntracked": "Deseleccionar archivos no rastreados", - "selectUntracked": "Seleccionar archivos no rastreados" - }, - "loading": "Cargando...", - "selectionCount": "{selected} / {total} archivos", - "emptyFiles": "No hay archivos cambiados", - "trackedChanges": "Cambios rastreados ({count})", - "untrackedFiles": "Archivos no rastreados ({count})", - "commitMessage": "Mensaje de commit", - "commitMessagePlaceholder": "Introduce el mensaje de commit...", - "commitButton": "Confirmar ({count})", - "commitAndPushButton": "Confirmar y enviar ({count})", - "head": "HEAD", - "workingTree": "Árbol de trabajo", - "clickFileToDiff": "Haz clic en un nombre de archivo para ver diff", - "loadingDiff": "Cargando diff..." - }, - "pushWindow": { - "title": "Enviar código", - "noUnpushedCommits": "No hay commits sin enviar", - "noRemoteConfigured": "No hay remoto Git configurado\nAñade uno en «Gestionar remotos»", - "newBranchNoPushedCommits": "Nueva rama — enviar para crear rama de seguimiento remota", - "unpushed": "Sin enviar", - "selectFileToViewDiff": "Selecciona un archivo para ver las diferencias", - "before": "Antes", - "after": "Después", - "push": "Enviar", - "toasts": { - "pushSuccess": "Envío exitoso", - "pushFailed": "Error al enviar", - "upstreamSet": "Se ha configurado la rama remota", - "upstreamSetAndPushed": "Rama remota configurada y enviados {count} commits", - "noCommitsToPush": "No hay commits para enviar", - "pushedCommits": "Enviados {count} commits" - } - }, - "gitLogTab": { - "filesTitle": "Archivos", - "expandAllFiles": "Expandir todos los archivos", - "collapseAllFiles": "Colapsar todos los archivos", - "workspace": "espacio de trabajo", - "retry": "Reintentar", - "noCommitsFound": "No se encontraron commits", - "notAGitRepoTitle": "No es un repositorio Git", - "notAGitRepoHint": "Inicializa Git desde el menú de ramas superior, o abre un repositorio existente.", - "hash": "Hash del commit", - "copyHash": "Copiar hash", - "copyMessage": "Copiar mensaje", - "showMore": "Mostrar más", - "showLess": "Mostrar menos", - "author": "Autor", - "noFileChangeDetails": "No hay detalles de cambios de archivo disponibles.", - "loadingFiles": "Cargando archivos...", - "branchesTitle": "Ramas", - "loadingBranches": "Cargando ramas...", - "noContainingBranches": "No se encontraron ramas contenedoras.", - "newBranch": "Nueva rama...", - "resetToHere": "Resetear aquí", - "resetDisabledReasonNotCurrentBranchView": "Disponible solo al ver la rama actual", - "copyFullCommitHashAria": "Copiar hash completo del commit {hash}", - "pushStatus": { - "pushed": "Enviado al remoto", - "notPushed": "No enviado al remoto", - "unknown": "Estado de push desconocido (sin upstream configurado)" - }, - "time": { - "monthsAgo": "{count, plural, one {hace # mes} other {hace # meses}}", - "daysAgo": "{count, plural, one {hace # día} other {hace # días}}", - "hoursAgo": "{count, plural, one {hace # hora} other {hace # horas}}", - "minsAgo": "{count, plural, one {hace # min} other {hace # mins}}", - "justNow": "justo ahora" - }, - "toasts": { - "createdAndSwitchedNewBranch": "Nueva rama creada y activada", - "newBranchFromCommit": "{name} (desde {shortHash})", - "createBranchFailed": "No se pudo crear la rama", - "openPushWindowFailed": "No se pudo abrir la ventana de envío", - "resetSuccess": "Reset completado", - "resetSuccessDescription": "{branch} se reseteó a {shortHash} con {mode}", - "resetFailed": "Falló el reset" - }, - "authorFilter": { - "label": "Autor", - "searchPlaceholder": "Buscar autor", - "noAuthors": "No se encontraron autores", - "you": "tú", - "filterByAuthorAria": "Filtrar commits por autor", - "filterByQuery": "Filtrar por \"{query}\"", - "clearAuthorFilterAria": "Borrar filtro de autor", - "recent": "Recientes", - "matchingAuthors": "Autores coincidentes", - "removeFromRecent": "Quitar {name} de recientes" - }, - "branchSelector": { - "label": "Rama", - "head": "HEAD", - "headHint": "Sigue la rama actual", - "headHintWithBranch": "Sigue la rama actual ({branch})", - "searchBranch": "Buscar rama...", - "noBranches": "Sin ramas", - "selectBranchPlaceholder": "Seleccionar rama...", - "localBranches": "Ramas locales", - "current": "Actual", - "remoteBranches": "Ramas remotas", - "refreshCommitHistory": "Actualizar historial de commits", - "clearBranchFilterAria": "Borrar filtro de rama" - }, - "dialogs": { - "newBranchTitle": "Nueva rama", - "newBranchDescription": "Crea una nueva rama con el commit {shortHash} como último commit.", - "branchNamePlaceholder": "Nombre de la rama", - "reset": { - "title": "Resetear la rama actual hasta aquí", - "branchLabel": "Rama", - "targetLabel": "Commit objetivo", - "messageLabel": "Mensaje", - "modeLabel": "Modo de reset", - "confirmButton": "Resetear", - "modes": { - "soft": { - "label": "--soft", - "description": "Mueve HEAD y el puntero de la rama actual al commit objetivo.\nMantiene Index y Working Tree sin cambios.\nLos cambios de los commits retirados permanecen en estado staged." - }, - "mixed": { - "label": "--mixed (predeterminado)", - "description": "Mueve HEAD al commit objetivo.\nResetea Index al commit objetivo y mantiene los cambios en Working Tree.\nLos cambios pasan de staged a unstaged." - }, - "hard": { - "label": "--hard", - "description": "Mueve HEAD y resetea tanto Index como Working Tree al commit objetivo.\nSe descartan los cambios locales rastreados posteriores al commit objetivo.\nEs una operación destructiva." - }, - "keep": { - "label": "--keep", - "description": "Mueve HEAD al commit objetivo e intenta conservar los cambios locales.\nSolo se conservan cambios que no entren en conflicto.\nSi hay conflictos, el reset se aborta para proteger tu trabajo." - } - } - } - }, - "moreActions": "Más acciones de Git" - }, - "gitChangesTab": { - "workspace": "espacio de trabajo", - "noChanges": "No hay cambios locales", - "notAGitRepoTitle": "No es un repositorio Git", - "notAGitRepoHint": "Inicializa Git desde el menú de ramas superior, o abre un repositorio existente.", - "trackedChanges": "Cambios rastreados ({count})", - "untrackedFiles": "Archivos no rastreados ({count})", - "expandTracked": "Expandir cambios rastreados", - "collapseTracked": "Colapsar cambios rastreados", - "expandUntracked": "Expandir archivos no rastreados", - "collapseUntracked": "Colapsar archivos no rastreados", - "showRemainingItems": "Mostrar {count} elementos más", - "actions": { - "commitCode": "Hacer commit del código", - "rollback": "Revertir", - "addToVcs": "Añadir a VCS", - "delete": "Eliminar", - "moreActions": "Más acciones de Git", - "addAllToVcs": "Añadir todo al VCS", - "rollbackAll": "Revertir todo", - "refresh": "Actualizar" - }, - "toasts": { - "noAddableFilesInDir": "No hay archivos cambiados en este directorio para añadir a VCS", - "noRollbackFilesInDir": "No hay archivos cambiados en este directorio para revertir", - "addedToVcs": "Se añadió {name} a VCS", - "addToVcsFailed": "No se pudo añadir a VCS", - "openCommitWindowFailed": "No se pudo abrir la ventana de commit", - "rolledBack": "Se revirtió {name}", - "rollbackFailed": "Error al revertir", - "addedFilesToVcs": "Se añadieron {count, plural, one {# archivo} other {# archivos}} a VCS", - "rolledBackFiles": "Se revirtieron {count, plural, one {# archivo} other {# archivos}}", - "deleted": "Se eliminó {name}", - "deleteFailed": "Error al eliminar", - "deletedFiles": "Se eliminaron {count} archivos", - "noDeletableFilesInDir": "No hay archivos modificados en este directorio que se puedan eliminar", - "commitFailed": "Error al confirmar" - }, - "directoryDialog": { - "descriptionAdd": "Selecciona archivos bajo el directorio {path} para añadir a VCS.", - "descriptionRollback": "Selecciona archivos bajo el directorio {path} para revertir.", - "descriptionDelete": "Selecciona archivos bajo el directorio {path} para eliminar. Esta acción no se puede deshacer.", - "descriptionFallback": "Selecciona archivos para continuar.", - "selectionCount": "Seleccionados {selected} / {total} archivos", - "selectAll": "Seleccionar todo", - "unselectAll": "Deseleccionar todo", - "loadingCandidates": "Cargando cambios del directorio...", - "noOperableFiles": "No hay archivos operables" - }, - "rollbackConfirm": { - "title": "Confirmar reversión", - "descriptionWithTarget": "¿Revertir cambios locales de {kind} \"{name}\"?", - "descriptionFallback": "¿Revertir cambios locales?", - "kindDirectory": "directorio", - "kindFile": "archivo" - }, - "deleteConfirm": { - "title": "Confirmar eliminación", - "descriptionWithTarget": "¿Eliminar {kind} \"{name}\"? Esta acción no se puede deshacer.", - "descriptionFallback": "Esta acción no se puede deshacer.", - "kindDirectory": "directorio", - "kindFile": "archivo" - }, - "quickCommit": { - "placeholder": "Mensaje del commit (Intro para confirmar)" - } - }, - "tabContext": { - "loadingConversation": "Cargando...", - "untitledConversation": "Conversación sin título", - "newConversation": "Nueva conversación" - }, - "fileTreeTab": { - "workspace": "Espacio de trabajo", - "retry": "Reintentar", - "git": "Git", - "openInFileManager": "Abrir en el gestor de archivos", - "openInFinder": "Abrir en Finder", - "openInExplorer": "Abrir en Explorer", - "attachToCurrentSession": "Agregar a la sesión", - "compareWithBranch": "Comparar con rama...", - "reloadFromDisk": "Recargar desde disco", - "new": "Nuevo", - "newFile": "Archivo", - "newDirectory": "Directorio", - "openIn": "Abrir en", - "openInTerminal": "Abrir en terminal", - "linkedFolder": "Carpeta vinculada", - "copyPath": "Copiar ruta", - "upload": "Subir archivos/carpeta", - "download": "Descargar archivo", - "downloadAsZip": "Descargar como ZIP", - "actions": { - "select": "Seleccionar", - "unselect": "Deseleccionar", - "commitCode": "Confirmar código", - "rollback": "Revertir", - "addToVcs": "Añadir a VCS" - }, - "aria": { - "selectPath": "{action}: {path}" - }, - "toasts": { - "openDirectoryFailed": "No se pudo abrir el directorio", - "openBuiltinTerminalFailed": "No se pudo abrir la terminal integrada", - "openCommitWindowFailed": "No se pudo abrir la ventana de commit", - "noAddableFilesInDir": "No hay archivos modificados en este directorio que se puedan añadir a VCS", - "noRollbackFilesInDir": "No hay archivos modificados en este directorio que se puedan revertir", - "addedToVcs": "Se añadió {name} a VCS", - "addToVcsFailed": "No se pudo añadir a VCS", - "loadBranchesFailed": "No se pudieron cargar las ramas", - "renameFailed": "Error al renombrar", - "moveFailed": "Error al mover", - "deleteFailed": "Error al eliminar", - "rolledBack": "Se revirtió {name}", - "rollbackFailed": "Error al revertir", - "addedFilesToVcs": "{count, plural, one {Se añadió # archivo a VCS} other {Se añadieron # archivos a VCS}}", - "rolledBackFiles": "{count, plural, one {Se revirtió # archivo} other {Se revirtieron # archivos}}", - "savedAsCopy": "Guardado como copia", - "saveCopyFailed": "No se pudo guardar como copia", - "watchStartFailed": "No se pudo iniciar la vigilancia de archivos", - "createFailed": "Error al crear", - "downloadFailed": "No se pudo descargar {name}", - "downloadSaved": "{name} descargado", - "pathCopied": "Ruta copiada", - "copyPathFailed": "No se pudo copiar la ruta" - }, - "createDialog": { - "newFile": "Nuevo archivo", - "newDirectory": "Nuevo directorio", - "description": "Ingrese un nombre para el nuevo {kind}.", - "placeholderFile": "file-name.ext", - "placeholderDirectory": "folder-name" - }, - "renameDialog": { - "renameDirectory": "Renombrar directorio", - "renameFile": "Renombrar archivo", - "description": "Introduce un nuevo nombre (solo nombre, sin ruta).", - "placeholderDirectory": "nuevo-nombre-carpeta", - "placeholderFile": "nuevo-nombre-archivo.ext" - }, - "uploadDialog": { - "title": "Subir al área de trabajo", - "description": "Ajusta el destino si es necesario y añade archivos o carpetas.", - "workspaceRoot": "raíz del área de trabajo", - "targetPathLabel": "Subir a", - "targetPathHint": "Ruta resuelta: {path}", - "dropHint": "Arrastra archivos o carpetas aquí, o usa los botones de abajo", - "dropHintActive": "Suelta para añadir a la cola", - "selectFiles": "Seleccionar archivos", - "selectFolder": "Seleccionar carpeta", - "startUpload": "Iniciar subida", - "clearQueue": "Limpiar finalizados", - "removeItem": "Quitar de la cola", - "retry": "Reintentar", - "dropZoneAria": "Suelta archivos aquí o activa para examinar", - "folderEmpty": "No se encontraron archivos en la carpeta soltada", - "summary": "Total: {total} · Con éxito: {succeeded} · Con error: {failed}", - "status": { - "pending": "En espera", - "uploading": "Subiendo", - "success": "Completado", - "error": "Falló", - "cancelled": "Cancelado" - } - }, - "directoryDialog": { - "descriptionAdd": "Selecciona archivos del directorio {path} para añadir a VCS.", - "descriptionRollback": "Selecciona archivos del directorio {path} para revertir.", - "descriptionFallback": "Selecciona archivos para continuar.", - "selectionCount": "Seleccionados {selected} / {total} archivos", - "selectAll": "Seleccionar todo", - "unselectAll": "Deseleccionar todo", - "loadingCandidates": "Cargando cambios del directorio...", - "noOperableFiles": "No hay archivos operables" - }, - "compareDialog": { - "title": "Comparar con rama", - "descriptionWithTarget": "Selecciona una rama y compara con {kind} {path}", - "descriptionFallback": "Selecciona una rama para comparar.", - "kindDirectory": "directorio", - "kindFile": "archivo", - "filterPlaceholder": "Filtra ramas, p. ej. main / origin/main", - "singleClickHint": "Haz clic en una rama para comparar directamente", - "loadingBranches": "Cargando ramas...", - "recentBranches": "Ramas recientes ({count})", - "noCurrentBranch": "Sin rama actual", - "localBranches": "Ramas locales ({count})", - "remoteBranches": "Ramas remotas ({count})", - "noMatchingBranches": "No hay ramas coincidentes" - }, - "externalConflictDialog": { - "title": "Se detectaron cambios externos en archivos", - "descriptionWithPath": "El archivo {path} cambió en disco y las ediciones actuales no están guardadas.", - "descriptionFallback": "El archivo actual cambió en disco y las ediciones actuales no están guardadas.", - "compare": "Comparar", - "savingCopy": "Guardando copia...", - "saveAsCopy": "Guardar como copia", - "reload": "Recargar" - }, - "deleteConfirm": { - "title": "Confirmar eliminación", - "descriptionWithTarget": "¿Eliminar {kind} \"{name}\"? Esta acción no se puede deshacer.", - "descriptionFallback": "Esta acción no se puede deshacer.", - "kindDirectory": "directorio", - "kindFile": "archivo" - }, - "rollbackConfirm": { - "title": "Confirmar reversión", - "descriptionWithTarget": "¿Revertir cambios locales del archivo \"{name}\"?", - "descriptionFallback": "¿Revertir cambios locales de este archivo?" - }, - "terminalTitle": "Consola · {name}" - }, - "commandDropdown": { - "loading": "Cargando...", - "addCommand": "Agregar comando", - "manageCommands": "Gestionar comandos...", - "runCommandTitle": "Ejecutar: {command}", - "stopCommandTitle": "Detener: {command}", - "manageDialog": { - "title": "Gestionar comandos", - "empty": "Aún no hay comandos", - "noResults": "No hay comandos coincidentes", - "searchPlaceholder": "Buscar comandos", - "newCommand": "Nuevo comando", - "nameLabel": "Nombre", - "commandLabel": "Comando", - "dragSort": "Arrastra para ordenar", - "dragSortCommand": "Arrastra para ordenar {name}", - "orderFailed": "No se pudo guardar el orden de los comandos", - "loadFailed": "No se pudieron cargar los comandos", - "saveFailed": "No se pudo guardar el comando", - "deleteFailed": "No se pudo eliminar el comando", - "confirmDelete": { - "title": "¿Eliminar comando?", - "message": "Esto eliminará \"{name}\". Esta acción no se puede deshacer." - } - } - }, - "workspaceContext": { - "confirmCloseDirtyTab": "¿Cerrar \"{title}\" sin guardar?", - "confirmCloseOtherDirtyTabs": "¿Cerrar otras pestañas con cambios sin guardar?", - "confirmCloseAllDirtyTabs": "¿Cerrar todas las pestañas con cambios sin guardar?", - "unableLoadContent": "No se puede cargar el contenido.\n\n{message}", - "previewRequestTimedOut": "La solicitud de vista previa agotó el tiempo", - "diffRequestTimedOut": "La solicitud de Diff agotó el tiempo", - "branchCompareRequestTimedOut": "La solicitud de comparación de ramas agotó el tiempo", - "commitDiffRequestTimedOut": "La solicitud de Diff de commit agotó el tiempo", - "saveRequestTimedOut": "La solicitud de guardado agotó el tiempo", - "reloadRequestTimedOut": "La solicitud de recarga agotó el tiempo", - "noChanges": "Sin cambios.", - "noDiffOutput": "Sin salida de diff.", - "diffTitleWorkspace": "Diferencias · Espacio de trabajo", - "diffDescriptionWorkingTree": "Árbol de trabajo (HEAD)", - "diffTitleFile": "Diferencias · {name}", - "compareTitleFile": "Comparar · {name}", - "compareTitleBranch": "Comparar · {branch}", - "compareDescriptionPath": "{path} · comparar con {branch}", - "compareDescriptionBranch": "comparar con {branch}", - "diffTitleCommitFile": "Diferencias · {name} @ {hash}", - "diffTitleCommit": "Diferencias · {hash}", - "diffDescriptionCommitPath": "{path} · confirmación {commit}", - "diffDescriptionCommit": "confirmación {commit}", - "diffTitleConflictFile": "Conflicto · {name}", - "diffDescriptionConflict": "{path} · disco vs sin guardar" - }, - "chat": { - "acpConnections": { - "actions": { - "openAgentsSettings": "Abrir ajustes de agentes", - "retry": "Reintentar" - }, - "agentsSetupHint": "Abre Ajustes > Agentes para gestionar la instalación.", - "withSetupHint": "{message}\n{hint}", - "blocked": { - "missingConfig": "No se puede leer la configuración actual del agente.", - "disabled": "{agent} está deshabilitado en Ajustes de agentes. Actívalo antes de conectar.", - "unavailable": "{agent} no está disponible en la plataforma actual.", - "sdkMissing": "El SDK de {agent} no está instalado", - "adapterMissing": "El adaptador ACP de {agent} no está instalado" - }, - "backendErrors": { - "initializeTimeout": "Se agotó el tiempo del handshake de conexión de {agent} (sin respuesta tras 60 segundos). Abre Ajustes para revisar la configuración del agente y de la red.", - "mcpRejectedByAgent": "{agent} rechazó la sesión con el complemento MCP de codeg adjunto: {message} Si este agente no admite MCP, desactiva «Compatibilidad con MCP» en Ajustes y vuelve a conectar.", - "processExited": "El proceso de {agent} terminó inesperadamente.", - "spawnFailed": "No se pudo iniciar {agent}: {message}", - "downloadFailed": "La descarga de {agent} falló: {message}", - "sessionLoadResourceNotFound": "Error al cargar la sesión de {agent}. Recarga para reintentar o inicia una nueva conversación.", - "sessionLoadUnavailable": "{agent} no pudo restaurar esta sesión; es posible que haya finalizado o que el agente se haya detenido. Recarga para reintentar o inicia una nueva conversación.", - "turnFailedRefusal": "{agent} rechazó continuar este turno. Suele indicar un error de backend o pasarela. Revisa los registros del agente.", - "turnFailedMaxTokens": "{agent} alcanzó el límite máximo de tokens para este turno.", - "turnFailedMaxTurnRequests": "{agent} alcanzó el número máximo de solicitudes permitidas para este turno.", - "turnFailedUnknown": "{agent} finalizó el turno con un motivo de parada no reconocido.", - "grokModelSwitchIncompatibleAgent": "{agent} no puede cambiar a ese modelo en una conversación existente. Inicia una nueva sesión para usarlo.", - "turnFailedEmpty": "{agent} finalizó el turno sin producir ninguna respuesta.", - "turnFailedEmptyProtocol": "{agent} produjo una salida que codeg no pudo analizar; la versión del agente podría no coincidir con el protocolo.", - "turnFailedEmptyMetadata": "{agent} solo envió actualizaciones de estado en este turno (plan / modo / uso) y ninguna respuesta.", - "detailsInAlerts": "Abre Alertas en la barra de estado y despliega los detalles para ver la salida del agente." - }, - "unableReadAgentConfig": "No se puede leer la configuración del agente: {message}", - "connectFailedTitle": "Falló la conexión de {agent}", - "toolFallbackTitle": "Herramienta", - "eventErrorTitle": "Error del agente", - "notificationTurnComplete": "{agent} ha terminado de responder", - "notificationError": "{agent} error: {message}", - "claudeApiRetry": { - "fallbackError": "authentication_failed", - "retryingWithMax": "reintentando {attempt}/{max}", - "retryingAttempt": "reintentando intento {attempt}", - "retrying": "reintentando", - "nextRetryIn": "siguiente en {seconds}s", - "line": "{error}{status} · {retry}", - "lineWithDelay": "{error}{status} · {retry}, {delay}", - "httpStatus": " (HTTP {status})" - }, - "configOptionAdjusted": "{agent} estableció {option} en {actual} en lugar de {requested}" - }, - "connectionLifecycle": { - "tasks": { - "connectingTitle": "Conectando con {agent}", - "connectingDescription": "Estableciendo conexión", - "loadingSelectorsTitle": "Cargando selectores de {agent}", - "loadingSelectorsDescription": "Obteniendo opciones de modo y configuración de sesión", - "initSessionTitle": "Initializing {agent} session", - "initSessionDescription": "Creating session and loading configuration" - }, - "errors": { - "connectionFailed": "Conexión fallida", - "sendPromptFailed": "No se pudo enviar el mensaje: {error}" - } - }, - "shared": { - "attachedResources": "Recursos adjuntos", - "toolCallFailed": "Falló la llamada de herramienta" - }, - "messageThread": { - "emptyTitle": "Aún no hay mensajes", - "emptyDescription": "Inicia una conversación para ver mensajes aquí" - }, - "chatInput": { - "connecting": "Conectando...", - "agentResponding": "{agent} está respondiendo...", - "sendMessage": "Enviar un mensaje..." - }, - "messageInput": { - "askAnything": "Pregunta lo que sea...", - "removeAttachmentAria": "Quitar {name}", - "attachFiles": "Adjuntar archivos", - "addActions": "Añadir", - "quickMessages": "Mensajes rápidos", - "quickMessagesEmpty": "Aún no hay mensajes rápidos", - "quickMessagesLoading": "Cargando...", - "pasteAsPlainText": "Pegar como texto sin formato", - "cut": "Cortar", - "copy": "Copiar", - "selectAll": "Seleccionar todo", - "pasteUnavailable": "No se pudo leer el portapapeles. Pulsa Ctrl/⌘V para pegar.", - "clipboardWriteFailed": "No se pudo escribir en el portapapeles. Usa el atajo de teclado.", - "quickMessageUntitled": "Sin título", - "liveFeedback": "Comentarios en vivo", - "liveFeedbackDisabledHint": "Disponible mientras el agente trabaja", - "dropFilesToAttach": "Suelta archivos para adjuntar", - "loadingSettings": "Cargando ajustes...", - "loadingMode": "Cargando modo...", - "modeLabel": "Modo", - "toggleOn": "Activado", - "toggleOff": "Desactivado", - "agentSettings": "Ajustes del agente", - "searchModel": "Buscar modelos...", - "searchModelAria": "Buscar modelos", - "modelListLabel": "Modelos", - "noModels": "No se encontraron modelos", - "cancel": "Cancelar", - "send": "Enviar", - "forkAndSend": "Fork y Enviar", - "queueMessage": "Poner en cola", - "steerIntoTurn": "Insertar en el turno actual", - "steerQueuedInstead": "Se puso en cola: se enviará con el siguiente turno.", - "steerFailed": "No se pudo insertar en el turno actual", - "steerAttachmentsUnsupported": "Solo texto: los borradores con adjuntos pasan por la cola.", - "slashCommands": "Comandos de barra", - "slashSearchPlaceholder": "Buscar comandos...", - "slashSearchEmpty": "Sin comandos coincidentes", - "experts": "Expertos", - "office": "Ofimática", - "research": "Investigación", - "attachLocalUpload": "Subir archivo local", - "attachServerFile": "Seleccionar archivo del servidor", - "attachUploadTooLarge": "{names} supera el límite de carga de {limit}MB y se omitió.", - "attachUploadFailed": "Error al subir {names}.", - "attachUploadNotAFile": "{names} no es un archivo regular (directorio o archivo especial) y se omitió.", - "attachUploadQuotaExceeded": "El servidor se quedó sin espacio para subidas; no se pudo cargar {names}.", - "attachUploadInProgress": "Las imágenes aún se están subiendo; inténtalo de nuevo en un momento.", - "mentionEmpty": "Sin coincidencias", - "mentionLoading": "Buscando…", - "mentionListLabel": "Menciones", - "mentionMore": "Más resultados: sigue escribiendo para filtrar", - "mentionCount": "{count, plural, one {# resultado} other {# resultados}}", - "mentionGroupFile": "Archivos", - "mentionGroupAgent": "Agentes", - "mentionGroupSession": "Sesiones", - "mentionGroupCommit": "Commits", - "mentionGroupSkill": "Habilidades" - }, - "messageQueue": { - "addToQueue": "Agregar a la cola", - "saveEdit": "Guardar", - "cancelEdit": "Cancelar edición", - "editItem": "Editar", - "deleteItem": "Eliminar" - }, - "welcomeInputPanel": { - "agentsSettingsPath": "Ajustes > Agentes", - "autoConnectFallback": "Haz clic para abrir {path} y gestionar la instalación.", - "autoConnectAppend": "{message}. Haz clic para abrir {path} y gestionar la instalación.", - "enableAgentFirstPlaceholder": "Habilita al menos un agente antes de iniciar una sesión...", - "prepareSessionFailed": "No se pudo preparar la sesión de chat. Inténtalo de nuevo.", - "createConversationFailed": "No se pudo crear la conversación. Inténtalo de nuevo.", - "askAnythingPlaceholder": "Pregunta lo que sea...", - "agentNotInstalled": "{agent} no está instalado · abre la configuración de Agents para instalarlo", - "agentAdapterNotInstalled": "El adaptador ACP de {agent} no está instalado (es aparte de tu propia CLI) · abre la configuración de Agents para instalarlo" - }, - "welcomePanel": { - "greeting": "¿Qué te gustaría hacer hoy?", - "tips": { - "tileTabs": "Haz clic derecho en una pestaña de conversación y elige Vista en mosaico para comparar varias sesiones lado a lado.", - "pinTab": "Haz doble clic en una pestaña de conversación para fijarla y que una sesión nueva no la reemplace automáticamente.", - "shortcutsNewSearch": "{newConversation} abre una conversación nueva, {searchConversations} busca en el historial.", - "slashAtMention": "Escribe / en la entrada para activar comandos slash, o @ para referenciar un archivo del proyecto.", - "pasteDropFiles": "Pega una captura de pantalla o arrastra un archivo a la entrada para adjuntarlo.", - "queueMessage": "Mientras el agente responde, sigue escribiendo: tu próximo mensaje se pone en cola y se envía al terminar.", - "draftAutoSave": "Los borradores sin enviar se guardan automáticamente por conversación y se restauran al volver.", - "forkSend": "El desplegable del botón de enviar incluye Bifurcar y enviar, que ramifica desde el punto actual a una pestaña nueva.", - "exportConversation": "Haz clic derecho dentro de la conversación para exportarla como Markdown, HTML o imagen.", - "chatChannels": "Conecta Telegram / Lark / WeChat en Ajustes → Canales de chat para continuar desde el móvil.", - "shortcutsAuxPanel": "{toggleAuxPanel} alterna el panel derecho para ver los archivos tocados y los cambios de Git de esta sesión.", - "shortcutsTerminalSidebar": "{toggleTerminal} abre la terminal integrada, {toggleSidebar} alterna la barra lateral.", - "customShortcuts": "Todos los atajos se pueden reasignar en Ajustes → Atajos.", - "webService": "Activa Ajustes → Servicio web para que tu equipo acceda al mismo codeg desde un navegador.", - "fusionMode": "Abre un archivo o diff para mostrarlo automáticamente junto a la conversación.", - "quickMessages": "Abre el botón + junto a la entrada y elige Mensajes rápidos para insertar un fragmento guardado (gestiónalos en Ajustes → Mensajes rápidos).", - "experts": "El botón + tiene un menú Habilidades expertas: carga roles como Depuración o Planificación con un clic.", - "taskBoard": "Las tareas pendientes ejecutan un trabajo de principio a fin: el agente trabaja en su propio worktree y tú revisas el diff antes de fusionar.", - "automations": "Las Automatizaciones ejecutan un prompt guardado según un horario —una revisión nocturna, un informe recurrente— y cada ejecución puede tener su propio worktree.", - "tokenUsage": "Haz clic en el número de conversaciones de la barra de estado para abrir Uso de tokens, desglosado por día, agente, modelo y carpeta.", - "mentionTargets": "@ no solo trae archivos: menciona a otro agente para delegarle una subtarea, o referencia una sesión anterior, un commit o una habilidad.", - "splitGroups": "Haz clic derecho en una pestaña y elige Dividir a la derecha o Dividir abajo para mantener dos conversaciones en paneles propios.", - "worktrees": "Abre el botón de rama y elige Nuevo worktree para que varios agentes trabajen en el mismo repositorio sin pisarse los archivos.", - "importSessions": "¿Ya ejecutaste sesiones en la terminal? El menú de una carpeta tiene Importar sesiones locales para traer ese historial a codeg.", - "subSessions": "Cuando un agente delega, la subsesión aparece anidada bajo él en la barra lateral: despliega la fila para seguir lo que hizo cada una.", - "liveFeedback": "Comentarios en vivo, en el menú +, inserta una nota en el turno que el agente ya está ejecutando, sin interrumpirlo.", - "skillPacks": "Configuración → Paquetes de habilidades reúne expertos de programación, investigación científica y ofimática; actívalos por agente.", - "modelProviders": "Configuración → Proveedores de Modelos acepta tu propia clave de API o endpoint, y el modelo lo eliges desde el cuadro de entrada.", - "workspaceBackground": "Configuración → Apariencia define una imagen de fondo del espacio de trabajo, la opacidad de los paneles y las fuentes de la app." - }, - "quickActions": { - "excel": "Libro de Excel", - "excelDesc": "Tablas, fórmulas y gráficos", - "word": "Documento de Word", - "wordDesc": "Informes, cartas y notas", - "ppt": "Presentación", - "pptDesc": "Diapositivas con diseño profesional", - "pitchDeck": "Pitch Deck", - "pitchDeckDesc": "Presentación de inversión con métricas", - "morph": "Animación Morph", - "morphDesc": "Transiciones de diapositiva cinematográficas", - "morph3d": "Morph 3D", - "morph3dDesc": "Modelos 3D con movimientos de cámara", - "academic": "Artículo académico", - "academicDesc": "Investigación con citas y estructura", - "financial": "Modelo financiero", - "financialDesc": "Estados, DCF y proyecciones", - "dashboard": "Panel de datos", - "dashboardDesc": "KPIs y análisis a partir de tus datos", - "prompts": { - "excel": "Crea un libro de Excel con los siguientes requisitos:\n\n[describe aquí tus datos, tablas, fórmulas y gráficos]", - "word": "Crea un documento de Word con los siguientes requisitos:\n\n[describe aquí el contenido, la estructura y el formato del documento]", - "ppt": "Crea una presentación de PowerPoint con los siguientes requisitos:\n\n[describe aquí tus diapositivas, contenido y diseño]", - "pitchDeck": "Crea un pitch deck de inversión con los siguientes requisitos:\n\n[describe aquí tu empresa, ronda de financiación y métricas clave]", - "morph": "Crea una presentación con animaciones de transición Morph:\n\n[describe aquí el tema de la presentación y los efectos visuales deseados]", - "morph3d": "Crea una presentación Morph 3D con modelos GLB y movimientos de cámara:\n\n[describe aquí tu tema y concepto visual en 3D]", - "academic": "Escribe un artículo académico en Word con los siguientes requisitos:\n\n[describe aquí tu tema de investigación, metodología y hallazgos clave]", - "financial": "Crea un modelo financiero en Excel con los siguientes requisitos:\n\n[describe aquí tus estados financieros, proyecciones y análisis]", - "dashboard": "Crea un panel de datos en Excel con los siguientes requisitos:\n\n[describe aquí tu fuente de datos, KPIs y gráficos]", - "scientific-brainstorming": "Ayúdame a generar ideas de investigación: explora conexiones interdisciplinares, cuestiona supuestos y detecta vacíos prometedores. El área que exploro: ", - "hypothesis-generation": "Ayúdame a convertir estas observaciones en hipótesis comprobables, con predicciones claras, mecanismos plausibles y experimentos para probarlas. Mis observaciones: ", - "experimental-design": "Ayúdame a diseñar un experimento riguroso antes de recolectar datos: el diseño, la aleatorización, los controles y cómo evitar la confusión. Lo que quiero estudiar: ", - "statistical-power": "Ayúdame a determinar el tamaño muestral que necesito: guíame en un análisis de potencia (tamaño del efecto, alfa, potencia) para mi diseño. Detalles: ", - "statistical-analysis": "Ayúdame a analizar estos datos correctamente: elige la prueba adecuada, verifica los supuestos, informa los tamaños de efecto y redáctalo. Mis datos y pregunta: ", - "exploratory-data-analysis": "Haz un análisis exploratorio de mi archivo de datos: resume su estructura, calidad y patrones destacados, y sugiere próximos pasos. El archivo es: ", - "scientific-visualization": "Ayúdame a crear una figura de calidad de publicación: diseño claro, barras de error honestas, una paleta apta para daltónicos y formato de revista. Lo que quiero mostrar: ", - "scientific-critical-thinking": "Ayúdame a evaluar críticamente este estudio o afirmación: valora la calidad de la evidencia, detecta sesgos y confusores, y pondera las conclusiones. Aquí está: ", - "paper-lookup": "Ayúdame a encontrar artículos relevantes y texto completo de acceso abierto en bases de datos académicas, con citas que pueda reutilizar. Busco: " - }, - "paper-lookup": "Búsqueda de artículos", - "paper-lookupDesc": "Busca en 10 API académicas (PubMed, arXiv, OpenAlex, Crossref…) artículos, citas y texto completo de acceso abierto.", - "scientific-critical-thinking": "Pensamiento crítico", - "scientific-critical-thinkingDesc": "Evalúa afirmaciones científicas y calidad de la evidencia: detecta sesgos y confusores, aplica GRADE y riesgo de sesgo.", - "scientific-visualization": "Visualización científica", - "scientific-visualizationDesc": "Figuras listas para publicar: diseños multipanel, anotaciones de significancia y formato específico de revista.", - "exploratory-data-analysis": "Análisis exploratorio de datos", - "exploratory-data-analysisDesc": "Exploración automatizada de archivos de datos científicos en más de 200 formatos con métricas de calidad e informes.", - "statistical-analysis": "Análisis estadístico", - "statistical-analysisDesc": "Análisis estadístico guiado: selección de pruebas, verificación de supuestos, tamaños de efecto e informe estilo APA.", - "statistical-power": "Potencia estadística", - "statistical-powerDesc": "Análisis de tamaño muestral y potencia: cuántos sujetos necesitas, efectos mínimos detectables y curvas de potencia.", - "experimental-design": "Diseño experimental", - "experimental-designDesc": "Diseña estudios rigurosos antes de recolectar datos: aleatorización, bloqueo, controles y diseños factoriales/DOE.", - "hypothesis-generation": "Generación de hipótesis", - "hypothesis-generationDesc": "Convierte observaciones en hipótesis comprobables con predicciones, mecanismos y experimentos para probarlas.", - "scientific-brainstorming": "Lluvia de ideas científica", - "scientific-brainstormingDesc": "Ideación abierta de investigación: explora conexiones interdisciplinares, cuestiona supuestos y detecta vacíos.", - "tabs": { - "office": "Ofimática", - "coding": "Desarrollo de código", - "research": "Investigación" - }, - "coding": { - "brainstormingDesc": "Explora intención y requisitos antes de construir", - "debuggingDesc": "Encuentra la causa raíz antes de proponer arreglos", - "writingSkillsDesc": "Crea, edita y verifica habilidades reutilizables" - }, - "notEnabled": { - "title": "La habilidad «{skill}» aún no está activada para {agent}", - "description": "Actívala en Ajustes para usarla aquí.", - "action": "Activar", - "hint": "Habilidad no activada" - }, - "scrollPrev": "Mostrar habilidades anteriores", - "scrollNext": "Mostrar más habilidades" - } - }, - "agentSelector": { - "noEnabledAgents": "No hay agentes habilitados", - "openAgentsSettings": "Abrir ajustes de agentes", - "notInstalled": "No instalado", - "moreAgents": "Más agentes ({count})" - }, - "subAgentOverlay": { - "title": "Subagentes", - "collapsedSummary": "Subagentes {count}", - "collapseAria": "Contraer subagentes" - }, - "agentPlanOverlay": { - "title": "Plan del agente", - "collapsePlanAria": "Contraer plan", - "collapsedSummary": "Plan de trabajo {completed}/{total}", - "status": { - "completed": "Completado", - "inProgress": "En progreso", - "pending": "Pendiente", - "unknown": "Desconocido" - }, - "priority": { - "high": "Alta", - "medium": "Media", - "low": "Baja", - "unknown": "Desconocida" - } - }, - "permissionDialog": { - "subtitle": "El agente solicita permiso para continuar este turno.", - "queuedCount": "+{count} en espera", - "kindFallbackTool": "herramienta", - "command": "Comando", - "cwd": "Directorio de trabajo: {cwd}", - "filesSummary": "Archivos: {count}", - "moreFiles": "+{count} archivos más", - "plan": "Plan de trabajo", - "allowedActions": "Acciones permitidas", - "targetMode": "Modo objetivo: {mode}", - "optionGrants": "Lo que concede cada opción", - "changeScopeSession": "Esta sesión", - "changeScopeProcess": "Esta ejecución", - "changeScopeUser": "Guardado en la configuración del usuario", - "changeScopeProject": "Guardado en la configuración del proyecto", - "changeScopeProjectLocal": "Guardado en la configuración local del proyecto", - "changeScopePersistent": "Guardado permanentemente" - }, - "questionDialog": { - "title": "El agente está haciendo una pregunta", - "placeholder": "Escribe tu respuesta...", - "send": "Enviar" - }, - "messageBranch": { - "previousBranchAria": "Rama anterior", - "nextBranchAria": "Rama siguiente", - "pageOf": "{current} de {total}" - }, - "terminal": { - "title": "Consola", - "running": "En ejecución" - }, - "reasoning": { - "thinking": "Pensando…", - "thoughtForFewSeconds": "Pensamiento", - "thoughtForSeconds": "Pensamiento" - }, - "linkSafety": { - "errorCannotOpen": "No se puede abrir el archivo local", - "errorNoWorkspace": "No hay ninguna carpeta de espacio de trabajo activa.", - "errorFailedOpen": "Error al abrir el archivo local", - "errorFailedLink": "Error al abrir el enlace", - "errorUnsupportedLinkProtocol": "Este protocolo de enlace no es compatible." - }, - "fileActions": { - "openInFinder": "Abrir en Finder", - "openInExplorer": "Abrir en Explorer", - "openInFileManager": "Abrir en el gestor de archivos", - "copyRelativePath": "Copiar ruta relativa", - "copyAbsolutePath": "Copiar ruta absoluta", - "pathCopied": "Ruta copiada", - "copyPathFailed": "No se pudo copiar la ruta", - "openFailed": "Error al abrir el archivo local" - }, - "messageList": { - "attachedResources": "Recursos adjuntos", - "loading": "Cargando...", - "loadEarlier": "Cargar mensajes anteriores", - "loadingEarlier": "Cargando mensajes anteriores…", - "error": "Error del chat: {message}", - "errorTitle": "Error al cargar la sesión", - "errorActionReload": "Recargar", - "errorActionNewSession": "Nueva conversación", - "emptyConversation": "No hay mensajes en esta conversación.", - "systemMessage": "Mensaje del sistema", - "copyMessage": "Copiar", - "copied": "Copiado", - "downloadImage": "Descargar imagen", - "downloadFailed": "Descarga fallida: {message}", - "imageGeneration": "Generación de imágenes", - "imageGenerationPending": "Generando imagen…", - "imageGenerationFailed": "Error al generar la imagen", - "model": "Modelo", - "tokenStats": "Uso de tokens", - "tokenInput": "Entrada", - "tokenOutput": "Salida", - "tokenCacheRead": "Lectura de caché", - "tokenCacheWrite": "Escritura de caché", - "duration": "Duración", - "completedAt": "Completado a las", - "jumpToPreviousUserMessage": "Ir al mensaje del usuario", - "showMore": "Mostrar más", - "showLess": "Mostrar menos" - }, - "liveTurnStats": { - "thinking": "Pensando...", - "streaming": "Transmitiendo", - "elapsedHours": "{value} h", - "elapsedMinutes": "{value} min", - "elapsedSeconds": "{value} s", - "outputSpeedAria": "Velocidad de salida estimada", - "outputSpeedTooltip": "Velocidad de salida estimada (texto + razonamiento)" - }, - "jsonTree": { - "viewRaw": "Ver JSON sin formato", - "viewTree": "Ver árbol", - "fields": "{count, plural, one {# campo} other {# campos}}", - "items": "{count, plural, one {# elemento} other {# elementos}}" - }, - "tool": { - "parameters": "Parámetros", - "error": "Error de herramienta", - "result": "Resultado", - "status": { - "approvalRequested": "Esperando aprobación", - "approvalResponded": "Respondido", - "inputAvailable": "En ejecución", - "inputStreaming": "Pendiente", - "outputAvailable": "Completado", - "outputDenied": "Denegado", - "outputError": "Error de salida" - } - }, - "toolCallBlock": { - "tool": "Herramienta", - "error": "Error de ejecución", - "result": "Resultado" - }, - "delegation": { - "subAgentRunning": "Subagente en ejecución…", - "noDetail": "No detail available yet.", - "unknownAgent": "Sub-agente", - "openDetail": "Ver conversación", - "detailTitle": "Conversación del subagente", - "detailDescription": "Vista de solo lectura de la conversación del subagente delegado.", - "waitForResult": "Esperando el resultado de la tarea {task}", - "waitForResultNoTask": "Esperando el resultado de la tarea", - "cancelTask": "Cancelando la tarea {task}", - "cancelTaskNoTask": "Cancelando la tarea", - "resultPageOf": "{current} / {total}", - "prevResult": "Resultado anterior", - "nextResult": "Resultado siguiente", - "noResultText": "Sin resultado en esta comprobación.", - "status": { - "starting": "iniciando", - "running": "en curso", - "checked": "consultado", - "waiting": "esperando aprobación", - "ok": "completado", - "err": { - "default": "fallido", - "delegation_disabled": "deshabilitado", - "depth_limit": "límite de profundidad", - "invalid_agent_type": "agente inválido", - "spawn_failed": "fallo al iniciar", - "send_failed": "fallo al enviar", - "timeout": "tiempo agotado", - "canceled": "cancelado", - "child_refusal": "subagente rechazó", - "child_max_tokens": "subagente: límite de tokens", - "child_max_turn_requests": "subagente: límite de solicitudes", - "child_empty": "subagente sin salida", - "child_unknown": "subagente: error", - "unknown": "tarea desconocida" - } - } - }, - "contentParts": { - "showingTailOutput": "Mostrando la salida final durante el streaming para mejorar el rendimiento.", - "result": "Resultado", - "unknown": "desconocido", - "inputTruncated": "La entrada fue truncada — el diff puede estar incompleto.", - "replaceAll": "REEMPLAZAR TODO", - "filesCount": "Archivos: {count}", - "update": "actualizar", - "moreFiles": "+{count} archivos más", - "timeoutMs": "Tiempo de espera: {timeout}ms", - "backgroundTrue": "Segundo plano: true", - "scriptToolCalls": "{count, plural, one {# llamada a herramienta} other {# llamadas a herramientas}}", - "offset": "Desplazamiento: {offset}", - "limit": "Límite: {limit}", - "pages": "Páginas: {pages}", - "mode": "Modo: {mode}", - "cell": "Celda: {cell}", - "shellSession": "Sesión {id}", - "pathLabel": "Ruta:", - "globLabel": "Patrón glob:", - "typeLabel": "Tipo:", - "outputLabel": "Salida:", - "caseInsensitive": "Sin distinguir mayúsculas/minúsculas", - "multiline": "Multilínea", - "promptLabel": "Instrucción", - "subjectLabel": "Asunto", - "taskLabel": "Tarea", - "nameLabel": "Nombre:", - "agentPromptLabel": "Instrucción", - "agentModelLabel": "Modelo", - "agentRunning": "Ejecutando...", - "agentLiveTranscript": "Actividad en vivo", - "agentProgressTools": "{count} llamadas a herramientas", - "agentProgressTurns": "{count} turnos", - "agentProgressContext": "contexto {pct}%", - "agentSessionAction": "Ver la sesión del subagente", - "agentSessionTitle": "Sesión del subagente", - "agentSessionLoading": "Cargando la transcripción del subagente…", - "agentSessionEmpty": "El subagente aún no ha escrito nada.", - "agentFallbackTitle": "Iniciando subagente…", - "agentCodexLaunchOnly": "Lanzado. Codex no informa de más progreso sobre este subagente: su resultado llega como un mensaje en esta conversación.", - "agentStatsBash": "Comandos", - "agentStatsRead": "Archivos leídos", - "agentStatsSearch": "Búsquedas", - "agentStatsEdit": "Ediciones", - "agentStatsOther": "Otros", - "goal": { - "title": "Objetivo:", - "titleWithStatus": "Objetivo {status}", - "objective": "Objetivo", - "statusLabel": "Estado", - "tokensUsed": "Tokens usados", - "budget": "Presupuesto", - "remaining": "Restante", - "elapsed": "Transcurrido", - "tokens": "tokens", - "pause": "Pausar", - "clear": "Borrar", - "status": { - "active": "activo", - "paused": "pausado", - "blocked": "bloqueado", - "usageLimited": "uso limitado", - "budgetLimited": "presupuesto limitado", - "complete": "completo", - "limited": "límite alcanzado" - } - }, - "field": { - "file": "Archivo", - "notebook": "Cuaderno", - "command": "Comando", - "old": "Anterior", - "new": "Nuevo", - "pattern": "Patrón", - "path": "Ruta", - "query": "Consulta", - "url": "URL:", - "description": "Descripción", - "content": "Contenido", - "source": "Fuente", - "prompt": "Instrucción", - "subject": "Asunto", - "taskId": "ID de tarea", - "status": "Estado", - "skill": "Skill", - "args": "Argumentos", - "offset": "Desplazamiento", - "limit": "Límite", - "glob": "Patrón glob", - "type": "Tipo", - "output": "Salida", - "replaceAll": "Reemplazar todo", - "language": "Idioma", - "timeout": "Tiempo de espera", - "background": "Segundo plano", - "agentType": "Tipo de agente", - "library": "Biblioteca", - "libraryId": "ID de biblioteca" - }, - "title": { - "edit": "Editar", - "command": "Comando", - "script": "Script", - "waitCommand": "Esperar {command}", - "waitCell": "Esperar sesión {id}", - "terminateCommand": "Terminar {command}", - "terminateCell": "Terminar sesión {id}", - "stdinChars": "Entrada {chars}", - "todoWrite": "TodoWrite (actualización de tareas)", - "read": "Leer", - "write": "Escribir", - "notebookEdit": "NotebookEdit (edición de cuaderno)", - "editFiles": "Editar ({count} archivos)", - "editWithTarget": "Editar {target}", - "readWithTarget": "Leer {target}", - "writeWithTarget": "Escribir {target}", - "notebookEditWithTarget": "NotebookEdit ({target})", - "globWithPattern": "Patrón glob {pattern}", - "listFilesWithPath": "Listar archivos {path}", - "grepWithPattern": "Patrón grep {pattern}", - "taskCreateWithSubject": "Crear tarea: {subject}", - "taskUpdateWithStatus": "Actualizar tarea #{id} -> {status}", - "taskUpdate": "Actualizar tarea #{id}", - "webFetchWithUrl": "WebFetch ({url})", - "webSearchWithQuery": "Búsqueda web: {query}", - "todosProgress": "Tareas ({done}/{total})", - "skillWithName": "Skill: {name}", - "genericWithContext": "{tool} ({context})" - }, - "search": { - "noMatches": "Sin coincidencias", - "matchSummary": "{matches, plural, one {# coincidencia} other {# coincidencias}} en {files, plural, one {# archivo} other {# archivos}}", - "fileSummary": "{files, plural, one {# archivo} other {# archivos}}", - "moreResults": "{count, plural, one {# resultado más no mostrado} other {# resultados más no mostrados}}" - }, - "toolGroup": { - "search": "{count, plural, one {Exploró # búsqueda} other {Exploró # búsquedas}}", - "command": "{count, plural, one {Ejecutó # comando} other {Ejecutó # comandos}}", - "read": "{count, plural, one {Leyó archivos # vez} other {Leyó archivos # veces}}", - "memory": "{count, plural, one {Recordó # memoria} other {Recordó # memorias}}", - "edit": "{count, plural, one {Editó archivos # vez} other {Editó archivos # veces}}", - "fetch": "{count, plural, one {Recuperó # recurso} other {Recuperó # recursos}}", - "think": "{count, plural, one {Pensó # vez} other {Pensó # veces}}", - "todo": "{count, plural, one {Actualizó # tarea} other {Actualizó # tareas}}", - "task": "{count, plural, one {Ejecutó # tarea} other {Ejecutó # tareas}}", - "other": "{count, plural, one {Usó # herramienta} other {Usó # herramientas}}", - "errorSuffix": "{count, plural, one {# falló} other {# fallaron}}", - "joiner": " · " - }, - "planMode": { - "entered": "Modo de planificación iniciado", - "planLabel": "Plan", - "reviewApproved": "Plan aprobado: implementando", - "reviewKept": "Se mantuvo en modo plan", - "reviewPending": "Esperando la decisión sobre el plan", - "submitted": "Plan enviado", - "switched": "Modo cambiado" - }, - "backgroundTask": { - "title": "Tarea en segundo plano", - "titleWithId": "Tarea en segundo plano · {id}", - "running": "En ejecución", - "completed": "Completada", - "failed": "Fallida", - "stopped": "Detenida", - "exitCode": "salida {code}", - "polledTimes": "Consultada {count} veces", - "runningInBackground": "Segundo plano", - "launchNote": "Ejecutándose en segundo plano · {id}" - }, - "codexScript": { - "outputMissing": "Codex truncó la salida del script y eliminó el separador de este comando, por lo que no se le pudo atribuir ninguna salida.", - "sharedWith": "También contiene la salida de {commands}: codex truncó sus separadores.", - "truncated": "truncado" - } - }, - "messageNav": { - "title": "Navegación de mensajes", - "collapse": "Contraer navegación de mensajes", - "collapsedSummary": "Mensajes {count}", - "fileCount": "{count, plural, one {# archivo} other {# archivos}}", - "remove": "Quitar", - "noDiffDataAvailable": "No hay datos de diff disponibles para {filePath}" - }, - "replyArtifacts": { - "title": "Archivos modificados", - "fileCount": "{count, plural, one {# archivo} other {# archivos}}", - "newFilesTitle": "Archivos nuevos", - "revealInFolder": "Mostrar en el gestor de archivos", - "openFile": "Abrir {filePath}", - "openInEditor": "Abrir en el editor", - "remove": "Quitar", - "noDiffDataAvailable": "No hay datos de diff disponibles para {filePath}" - }, - "askQuestion": { - "title": "El agente necesita tu elección", - "subtitle": "Responde y luego envía. Puedes omitir en cualquier momento.", - "recommended": "Recomendado", - "other": "Otro", - "otherPlaceholder": "Escribe tu respuesta…", - "singleSelect": "Única", - "multiSelect": "Múltiple", - "skip": "Omitir", - "next": "Siguiente", - "submit": "Enviar", - "submitError": "No se pudo enviar. Inténtalo de nuevo." - }, - "planApproval": { - "title": "El agente tiene un plan: revísalo", - "emptyPlan": "El agente no escribió un plan. Aprueba para empezar a construir o solicita cambios.", - "approve": "Aprobar y construir", - "requestChanges": "Solicitar cambios", - "abandon": "Descartar", - "feedbackPlaceholder": "¿Qué debería cambiar?", - "sendChanges": "Enviar", - "cancel": "Cancelar", - "submitError": "No se pudo enviar. Inténtalo de nuevo." - }, - "feedbackCheckResult": { - "count": "{count, plural, =1 {1 comentario} other {# comentarios}}", - "expand": "Mostrar todos los comentarios", - "collapse": "Contraer", - "errorTitle": "Error al comprobar los comentarios" - }, - "askQuestionResult": { - "title": "Pregunta", - "answeredLabel": "Pregunta y respuesta:", - "awaiting": "Esperando tu respuesta…", - "declined": "Descartaste esto: el agente usó su propio criterio.", - "noSelection": "Sin selección" - }, - "configStale": { - "agentConfigTitle": "Configuración del agente actualizada", - "modelProviderTitle": "Proveedor de modelo actualizado", - "description": "Esta sesión sigue usando su configuración anterior. Vuelve a conectarte para aplicarla (se conserva el historial de la conversación).", - "reconnect": "Reconectar para aplicar", - "reconnecting": "Reconectando…", - "reconnectDisabledDuringTurn": "Disponible cuando termine el turno actual", - "dismiss": "Descartar", - "reconnectFailed": "No se pudo reconectar la sesión", - "applied": "Nueva configuración aplicada" - }, - "piProjectTrust": { - "title": "Este proyecto incluye recursos de pi", - "description": "pi no está cargando los archivos .pi del propio repositorio. Revísalos para decidir.", - "descriptionExecutable": "El repositorio incluye extensiones de pi, que ejecutan código al iniciar. pi no las está cargando. Revísalas antes de decidir.", - "review": "Revisar…", - "dismiss": "Descartar", - "dialogTitle": "¿Confiar en los recursos de pi de este proyecto?", - "dialogDescription": "pi solo carga los archivos .pi del propio repositorio si confías en la carpeta. Confía solo si confías en el contenido de este repositorio.", - "executionWarning": "Las extensiones son código. Al confiar en esta carpeta, el repositorio podrá ejecutarlas al iniciar pi con tus permisos, antes de que envíes ningún mensaje.", - "scopeNote": "La decisión se guarda en el trust.json de pi para esta carpeta, se aplica a todas las carpetas que contiene y también se usa cuando ejecutas pi por tu cuenta en una terminal. Puedes cambiarla en Ajustes → Agentes → Pi.", - "trust": "Confiar en el proyecto", - "decline": "Mantener sin cargar", - "disabledDuringTurn": "Disponible cuando termine el turno actual", - "trustedToast": "Proyecto de confianza: se reconectó para que pi cargue sus recursos", - "declinedToast": "Los recursos del proyecto siguen sin cargarse", - "saveFailed": "No se pudo guardar la decisión de confianza del proyecto", - "grantTitle": "Este proyecto ya es de confianza", - "grantDescription": "pi carga los archivos .pi del propio repositorio. Revisa lo que eso permite.", - "grantInheritedDescription": "Una carpeta superior es de confianza, así que pi carga los archivos .pi del propio repositorio. Revisa lo que eso permite.", - "grantDialogTitle": "Los recursos de pi de este proyecto son de confianza", - "grantDialogDescription": "pi tiene permiso para cargar los archivos .pi del propio repositorio. Versiones anteriores de codeg lo concedían automáticamente al abrir una carpeta, así que puede que nunca te lo preguntaran.", - "grantExecutionWarning": "Las extensiones son código. El repositorio las ejecuta al iniciar pi con tus permisos, antes de que envíes ningún mensaje.", - "inheritedFrom": "Confianza heredada de", - "revoke": "Revocar confianza", - "keepTrusted": "Mantener la confianza", - "revokedToast": "Confianza revocada: se reconectó para que pi deje de cargar los recursos del proyecto", - "trustedNoReconnect": "Proyecto de confianza: se aplicará la próxima vez que se inicie pi", - "revokedNoReconnect": "Confianza revocada: se aplicará la próxima vez que se inicie pi" - }, - "collabAgent": { - "title": "Subagente", - "errorTitle": "La tarea del subagente falló", - "statesLabel": "Subagentes", - "statusRunning": "En ejecución", - "statusCompleted": "Completado", - "statusFailed": "Fallido", - "statusPending": "Iniciando", - "statusInterrupted": "Interrumpido", - "statusClosed": "Cerrado", - "statusNotFound": "No encontrado", - "opSpawn": "Iniciando subagente", - "opWait": "Obteniendo resultado del subagente", - "opClose": "Cerrando subagente", - "opResume": "Reanudando subagente" - }, - "contextCompaction": { - "compacting": "Compactando el contexto…", - "compacted": "Contexto compactado", - "compactedTokens": "Contexto compactado · {before} → {after} tokens", - "failed": "Error al compactar el contexto" - }, - "sessionFailure": { - "category": { - "connection": "Problema de conexión", - "access": "Problema de acceso", - "limit": "Límite alcanzado", - "request": "Solicitud rechazada", - "service": "Problema del servicio", - "unknown": "Problema de sesión" - }, - "action": { - "retry": "Reintentar", - "login": "Iniciar sesión", - "newSession": "Nueva sesión" - }, - "recovered": "Recuperado", - "retryUnavailable": "No hay ningún mensaje anterior para reenviar.", - "toggleDetails": "Mostrar u ocultar detalles" - }, - "backgroundTasks": { - "running": "{count, plural, one {# tarea en segundo plano en ejecución} other {# tareas en segundo plano en ejecución}}", - "settling": "Sincronizando resultados en segundo plano…", - "settledFallback": "Tarea en segundo plano finalizada ({status})", - "cardRunning": "Ejecutándose en segundo plano", - "cardLaunchedPending": "Tarea lanzada en segundo plano", - "cardCompleted": "Tarea en segundo plano completada", - "cardFinishedWithStatus": "Tarea en segundo plano finalizada ({status})", - "cardResultPending": "El resultado aún no ha llegado" - }, - "proposedPlan": { - "title": "Plan propuesto", - "planning": "Planificando…" - } - }, - "diffPreview": { - "mode": { - "added": "Añadido", - "deleted": "Eliminado", - "renamed": "Renombrado", - "modified": "Modificado" - }, - "hunkLabel": "Bloque {index}", - "loadingHunk": "Cargando hunk...", - "noDiffData": "Sin datos de diff", - "showRemainingLines": "Mostrar {count} líneas más" - }, - "conversationContextBar": { - "folderTitle": "Carpeta de trabajo", - "branchTitle": "Rama de trabajo", - "searchFolder": "Search folder...", - "searchBranch": "Search branch...", - "noFolders": "No folders", - "noBranches": "No branches", - "noBranch": "(no branch)", - "chatModeLabel": "Modo de chat", - "commit": "Commit", - "push": "Push", - "merge": "Merge", - "toasts": { - "folderChanged": "Switched to {name}", - "openFolderFailed": "Failed to open folder", - "switchedToChatMode": "Cambiado al modo de chat", - "openStashFailed": "Failed to open stash window", - "openMergeFailed": "Failed to open merge window" - } - }, - "cloneDialog": { - "title": "Clonar repositorio", - "repositoryUrl": "URL del repositorio", - "repositoryUrlPlaceholder": "https://github.com/user/repo.git", - "directory": "Directorio", - "directoryPlaceholder": "Selecciona el directorio de destino...", - "browseDirectory": "Explorar directorio", - "cancel": "Cancelar", - "clone": "Clonar", - "clonePath": "Ruta de clonación: {path}" - }, - "toasts": { - "cloneFailed": "No se pudo clonar el repositorio" - } - }, - "ProjectBoot": { - "title": "Inicio de Proyecto", - "tabs": { - "shadcn": "shadcn", - "hyperframes": "HyperFrames" - }, - "hyperframes": { - "title": "Proyecto de vídeo HyperFrames", - "subtitle": "Genera un proyecto de HTML a vídeo. Luego, el agente del espacio de trabajo puede escribirlo y renderizarlo.", - "resolution": "Resolución", - "skillsTitle": "Skills de agentes", - "skillsDesc": "Instala globalmente las skills de HyperFrames (enlace simbólico) para los agentes seleccionados, para que puedan crear y renderizar vídeo.", - "recheck": "Volver a comprobar", - "installedBadge": "Instalado", - "skillsInstall": "Instalar / actualizar skills", - "skillsInstalling": "Instalando skills…", - "skillsInstalled": "Skills de HyperFrames instaladas", - "skillsInstallFailed": "No se pudieron instalar las skills de HyperFrames" - }, - "config": { - "base": "Base", - "style": "Estilo", - "baseColor": "Color base", - "theme": "Tema", - "chartColor": "Color del gráfico", - "iconLibrary": "Biblioteca de iconos", - "font": "Fuente", - "fontHeading": "Fuente de título", - "menuAccent": "Acento del menú", - "menuColor": "Color del menú", - "radius": "Radio", - "template": "Plantilla", - "createProject": "Crear proyecto", - "sectionStyle": "Estilo", - "sectionColors": "Colores", - "sectionTypography": "Tipografía", - "sectionInterface": "Interfaz" - }, - "preview": { - "loading": "Cargando vista previa..." - }, - "createDialog": { - "title": "Crear proyecto", - "projectName": "Nombre del proyecto", - "projectNamePlaceholder": "my-app", - "frameworkTemplate": "Plantilla del framework", - "packageManager": "Gestor de paquetes", - "saveDirectory": "Directorio de guardado", - "saveDirectoryPlaceholder": "Seleccionar directorio...", - "browseDirectory": "Explorar", - "projectPath": "El proyecto se creará en: {path}", - "advancedOptions": "Opciones Avanzadas", - "base": "Biblioteca Base", - "enableRtl": "Habilitar Soporte RTL", - "enableRtlDescription": "Habilitar soporte de diseño para idiomas de derecha a izquierda (ej. árabe, hebreo)", - "pmChecking": "Verificando...", - "pmNotInstalled": "No instalado", - "cancel": "Cancelar", - "create": "Crear", - "creating": "Creando proyecto..." - }, - "toasts": { - "createFailed": "Error al crear el proyecto", - "createSuccess": "Proyecto creado exitosamente", - "openWorkspaceFailed": "Proyecto creado, pero no se pudo abrir en el espacio de trabajo" - }, - "errors": { - "directoryExists": "El directorio de destino ya existe", - "commandFailed": "El comando de creación del proyecto falló." - } - }, - "WebServiceSettings": { - "addressSwitchHint": "Cambiar solo modifica la dirección que se muestra y se abre aquí; el servicio escucha en todas las interfaces y sigue accesible en cada dirección.", - "sectionTitle": "Servicio Web", - "sectionDescription": "Habilitar para acceder a Codeg de forma remota a través del navegador", - "port": "Puerto", - "status": "Estado", - "autoStart": "Inicio automático", - "autoStartHint": "Iniciar el servicio web al abrir Codeg", - "running": "En ejecución", - "stopped": "Detenido", - "processing": "Procesando...", - "start": "Iniciar", - "stop": "Detener", - "startFailed": "Error al iniciar", - "stopFailed": "Error al detener", - "saveConfigFailed": "No se pudo guardar la configuración del servicio web", - "open": "Abrir", - "hide": "Ocultar", - "show": "Mostrar", - "copy": "Copiar", - "qrcode": "Código QR", - "qrcodeTitle": "Escanear para abrir", - "qrcodeHint": "Escanea con tu teléfono para abrir Codeg en el navegador", - "addressLabel": "Dirección de acceso", - "tokenLabel": "Token de acceso", - "tokenHint": "Ingrese este token al acceder al cliente Web por primera vez", - "tokenPlaceholder": "Dejar vacío para generar automáticamente", - "regenerate": "Regenerar", - "stalePortOccupiedTitle": "El puerto {port} está en uso por otro proceso", - "stalePortUnknownTitle": "Estado del puerto {port} indeterminado", - "stalePortHint": "Codeg no puede vincularse hasta que se libere el puerto. Cambia el puerto arriba o cierra el proceso que lo retiene.", - "errors": { - "alreadyRunning": "El servicio Web ya está en ejecución", - "invalidAddress": "Formato de host o puerto no válido", - "portInUse": "El puerto {port} ya está en uso. Cierre el proceso que lo usa o elija otro puerto.", - "permissionDenied": "Permiso denegado. Utilice un puerto superior a 1024 o ejecute con mayores privilegios.", - "addressUnavailable": "La dirección no está disponible en este equipo", - "bindFailed": "No se pudo enlazar la dirección" - } - }, - "DirectoryBrowser": { - "title": "Explorar directorio", - "pathPlaceholder": "Ingrese la ruta del directorio...", - "goHome": "Ir al directorio principal", - "navigateUp": "Ir al directorio superior", - "select": "Seleccionar", - "cancel": "Cancelar", - "loading": "Cargando...", - "emptyDirectory": "Este directorio está vacío", - "errorLoadingDir": "Error al cargar el directorio", - "permissionDenied": "Permiso denegado" - }, - "ChatChannelSettings": { - "loading": "Cargando...", - "sectionTitle": "Canales de chat", - "sectionDescription": "Configure bots de IM para recibir notificaciones de eventos y consultar actividad de codificación.", - "addChannel": "Agregar canal", - "noChannels": "Aún no se han configurado canales de chat.", - "channelName": "Nombre", - "channelNamePlaceholder": "Mi bot de Telegram", - "channelType": "Tipo de canal", - "lark": "Lark (Feishu)", - "weixin": "WeChat", - "dailyReport": "Informe diario", - "dailyReportTime": "Hora del informe", - "nameRequired": "El nombre del canal es obligatorio.", - "tokenRequired": "El token es obligatorio.", - "chatIdRequired": "El Chat ID es obligatorio.", - "topicMode": "Modo de grupo por temas", - "topicModeHint": "Enruta los temas de foros de Telegram como sesiones Codeg separadas. El bot debe estar en un supergrupo de foro y poder administrar temas.", - "loadFailed": "Error al cargar los canales.", - "saveFailed": "Error al guardar los cambios.", - "connectSuccess": "Canal conectado.", - "connectFailed": "Error al conectar", - "disconnectSuccess": "Canal desconectado.", - "disconnectFailed": "Error al desconectar.", - "testSuccess": "Prueba de conexión exitosa.", - "testFailed": "Prueba de conexión fallida", - "deleteSuccess": "Canal eliminado.", - "deleteFailed": "Error al eliminar el canal.", - "deleteConfirmTitle": "Eliminar canal", - "deleteConfirmMessage": "Se eliminará permanentemente el canal y sus registros de mensajes. ¿Está seguro?", - "cancel": "Cancelar", - "delete": "Eliminar", - "create": "Crear", - "save": "Guardar", - "channelListTitle": "Canales configurados", - "channelListDescription": "Los canales habilitados se conectarán automáticamente al iniciar el servicio.", - "editChannel": "Editar canal", - "editSuccess": "Canal actualizado.", - "tokenPlaceholderKeep": "Dejar vacío para mantener actual", - "weixinScanTitle": "Escanear código QR", - "weixinScanDescription": "Abra WeChat y escanee el código QR para conectarse.", - "weixinQrcodeExpired": "El código QR ha expirado.", - "weixinRefreshQrcode": "Actualizar", - "weixinWaitingScan": "Esperando escaneo...", - "weixinPollError": "Conexión inestable, reintentando...", - "weixinReconnectNotice": "Debido a limitaciones del protocolo iLink, después de cada reconexión debes enviar un mensaje al bot para que los activadores de eventos surtan efecto.", - "connect": "Conectar", - "disconnect": "Desconectar", - "test": "Probar conexión", - "tabs": { - "channels": "Canales", - "commands": "Comandos", - "events": "Eventos", - "other": "Otros" - }, - "commands": { - "title": "Comandos integrados", - "description": "Comandos de bot disponibles en los canales de chat. En chats grupales, se requiere @Bot para procesar mensajes.", - "prefixLabel": "Prefijo de comando", - "prefixDescription": "1-3 caracteres no alfanuméricos para activar comandos del bot (por defecto /).", - "prefixSaved": "Prefijo de comando guardado.", - "prefixSaveFailed": "Error al guardar el prefijo.", - "prefixInvalid": "El prefijo debe ser de 1-3 caracteres no alfanuméricos.", - "save": "Guardar", - "folderDesc": "Seleccionar carpeta de trabajo", - "agentDesc": "Seleccionar agente de IA", - "taskDesc": "Crear sesión y ejecutar tarea", - "sessionsDesc": "Listar sesiones activas en la carpeta", - "resumeDesc": "Conversaciones recientes / reanudar una sesión", - "cancelDesc": "Cancelar tarea actual", - "approveDesc": "Aprobar solicitud de permiso del agente", - "denyDesc": "Denegar solicitud de permiso del agente", - "searchDesc": "Buscar conversaciones por palabra clave", - "todayDesc": "Resumen de actividad de hoy", - "statusDesc": "Estado de conexión del canal", - "helpDesc": "Mostrar ayuda" - }, - "events": { - "title": "Notificaciones de eventos", - "description": "Al habilitar eventos, se enviarán al canal cuando se activen.", - "turnComplete": "Turno completado", - "turnCompleteDesc": "Cuando finaliza un turno del agente", - "error": "Error del agente", - "errorDesc": "Cuando un agente encuentra un error", - "permissionRequest": "Solicitud de permiso", - "permissionRequestDesc": "Cuando un agente solicita permiso para actuar", - "questionRequest": "Pregunta del agente", - "questionRequestDesc": "Cuando un agente te hace una pregunta", - "userPromptSent": "Mensaje del usuario", - "userPromptSentDesc": "Cuando envías un mensaje (el texto del mensaje se incluye en la notificación)", - "saved": "Filtro de eventos actualizado.", - "saveFailed": "Error al guardar el filtro de eventos.", - "loadFailed": "No se pudo cargar la configuración.", - "retry": "Reintentar", - "webhooksTitle": "Webhooks", - "webhooksDescription": "Envía una carga JSON por POST a una o varias URL cuando se activa un evento habilitado. El filtro de eventos anterior también se aplica a los webhooks.", - "webhookUrlPlaceholder": "https://example.com/webhook", - "addWebhook": "Agregar webhook", - "removeWebhook": "Eliminar webhook", - "webhookSave": "Guardar", - "webhooksSaved": "Webhooks guardados.", - "webhooksSaveFailed": "Error al guardar los webhooks.", - "webhookInvalidUrl": "Introduce URL http(s) válidas.", - "docsTitle": "Formato de solicitud", - "docsMethod": "Método", - "docsContentType": "Content-Type", - "docsNote": "Cada evento habilitado se entrega a todas las URL. Los webhooks no tienen antirrebote; el filtro de eventos anterior sigue aplicándose.", - "editWebhook": "Editar webhook", - "enableWebhook": "Activar webhook", - "webhookDuplicate": "Esta URL ya está configurada.", - "cancel": "Cancelar", - "webhooksEmpty": "Aún no hay webhooks configurados.", - "deleteWebhookTitle": "Eliminar webhook", - "deleteWebhookMessage": "¿Eliminar este webhook? Los eventos ya no se enviarán a esta URL.", - "delete": "Eliminar" - }, - "language": { - "title": "Idioma de mensajes", - "description": "Idioma utilizado para las notificaciones de eventos, respuestas de comandos e informes diarios enviados a los canales de chat.", - "saved": "Idioma de mensajes guardado.", - "saveFailed": "Error al guardar el idioma de mensajes.", - "en": "Inglés", - "zh-cn": "Chino simplificado", - "zh-tw": "Chino tradicional", - "ja": "Japonés", - "ko": "Coreano", - "es": "Español", - "de": "Alemán", - "fr": "Francés", - "pt": "Portugués", - "ar": "Árabe" - } - }, - "ModelProviderSettings": { - "sectionTitle": "Proveedores de Modelos", - "sectionDescription": "Gestionar las credenciales de proveedores API para agentes.", - "filterAll": "Todos", - "providerListTitle": "Proveedores Configurados", - "addProvider": "Agregar Proveedor", - "editProvider": "Editar Proveedor", - "noProviders": "Aún no se han configurado proveedores de modelos.", - "providerName": "Nombre", - "providerNamePlaceholder": "Ej. OpenAI, Anthropic", - "apiUrl": "URL de API", - "apiUrlPlaceholder": "https://api.openai.com/v1", - "apiKey": "Clave API", - "apiKeyPlaceholder": "sk-...", - "apiKeyKeepCurrent": "Dejar vacío para mantener actual", - "agentTypes": "Tipos de Agente", - "agentTypesRequired": "Se requiere al menos un tipo de agente.", - "agentType": "Tipo de Agente", - "agentTypeRequired": "El tipo de agente es obligatorio.", - "agentTypeImmutableHint": "El tipo de agente no se puede cambiar después de la creación.", - "model": "Modelo", - "modelPlaceholderCodex": "gpt-5.6-sol / gpt-5.5", - "modelPlaceholderGemini": "gemini-3-pro-preview", - "claudeMainModel": "Modelo Principal", - "claudeReasoningModel": "Modelo de Razonamiento (pensamiento)", - "claudeHaikuDefaultModel": "Modelo Haiku Predeterminado", - "claudeSonnetDefaultModel": "Modelo Sonnet Predeterminado", - "claudeOpusDefaultModel": "Modelo Opus Predeterminado", - "claudeCustomModelOption": "ID de modelo personalizado", - "claudeCustomModelOptionName": "Nombre del modelo personalizado", - "claudeCustomModelOptionDescription": "Descripción del modelo personalizado", - "claudeCustomModelOptionHint": "Añade una única entrada personalizada al selector de modelos de Claude (por ejemplo, un modelo detrás de una pasarela/proxy personalizado). El nombre y la descripción son opcionales y solo afectan a la visualización.", - "nameRequired": "El nombre del proveedor es obligatorio.", - "apiUrlRequired": "La URL de API es obligatoria.", - "apiKeyRequired": "La clave API es obligatoria.", - "loadFailed": "Error al cargar proveedores.", - "saveFailed": "Error al guardar cambios.", - "createSuccess": "Proveedor creado.", - "editSuccess": "Proveedor actualizado.", - "deleteSuccess": "Proveedor eliminado.", - "deleteConfirmTitle": "Eliminar Proveedor", - "deleteConfirmMessage": "Esto eliminará permanentemente el proveedor \"{name}\". ¿Está seguro?", - "deleteBlockedByAgent": "{agents} está usando este proveedor. Desvincúlelo antes de eliminarlo.", - "cancel": "Cancelar", - "delete": "Eliminar", - "create": "Crear", - "save": "Guardar", - "affectedRunningSessions": "{count, plural, one {# sesión activa necesita reconectarse para aplicar el cambio} other {# sesiones activas necesitan reconectarse para aplicar el cambio}}" - }, - "SkillMatrix": { - "loading": "Cargando…", - "searchPlaceholder": "Buscar por nombre, id o descripción", - "empty": "Nada que mostrar.", - "emptySearch": "No hay coincidencias para la búsqueda actual.", - "skillColumn": "Habilidad", - "selectAll": "Seleccionar todo lo visible", - "selectSkill": "Seleccionar {name}", - "everything": { - "label": "En bloque", - "enable": "Activar todo (visible)", - "disable": "Desactivar todo (visible)" - }, - "columnMenu": { - "enableAll": "Activar todas las habilidades", - "disableAll": "Desactivar todas las habilidades" - }, - "rowMenu": { - "label": "Acciones en bloque para {name}", - "enableAll": "Activar para todos los agentes", - "disableAll": "Desactivar para todos los agentes" - }, - "bulk": { - "selected": "{count} seleccionados", - "targetAll": "Todos los agentes", - "targetSome": "{count} agentes", - "enable": "Activar", - "disable": "Desactivar", - "clear": "Limpiar" - }, - "confirm": { - "disableTitle": "¿Desactivar estos enlaces?", - "disableBody": "Esto eliminará {count} enlaces de habilidades gestionados por codeg. Las habilidades que ocupan un directorio personalizado no se modifican. Puedes reactivarlas cuando quieras.", - "cancel": "Cancelar", - "confirm": "Desactivar" - }, - "toasts": { - "loadFailed": "No se pudieron cargar los estados de las habilidades", - "applyFailed": "No se pudieron aplicar los cambios", - "enabled": "{count} enlaces activados", - "disabled": "{count} enlaces desactivados", - "enabledPartial": "{ok} activados, {failed} fallidos", - "disabledPartial": "{ok} desactivados, {failed} fallidos" - }, - "detail": { - "enableForAgents": "Activar para agentes", - "preview": "Vista previa de SKILL.md", - "loadingContent": "Cargando contenido…" - }, - "copyModeHint": "Copiado (no enlazado): vuelve a activarlo tras las actualizaciones para la última versión" - }, - "ExpertsSettings": { - "title": "Habilidades de expertos", - "description": "Habilita flujos de trabajo de habilidades cuidadosamente seleccionadas y probadas en la práctica para tus agentes de codificación de IA. Cada experto es una habilidad independiente del proyecto superpowers — codeg gestiona la copia central y la vincula a los agentes que elijas.", - "loading": "Cargando expertos…", - "loadingContent": "Cargando contenido…", - "emptyExperts": "No hay expertos disponibles. Revisa los registros de la aplicación.", - "emptySelection": "Selecciona un experto para ver su contenido y gestionar la activación.", - "emptySearch": "Ningún experto coincide con la búsqueda actual.", - "searchPlaceholder": "Buscar expertos por nombre, ID o descripción", - "enableForAgents": "Habilitar para agentes", - "noAgents": "No se detectaron agentes ACP.", - "copyModeWarning": "Copiado (no vinculado). Vuelve a habilitarlo después de actualizar codeg para obtener la última versión.", - "previewTitle": "Vista previa de SKILL.md", - "categories": { - "discovery": "Descubrimiento y diseño", - "planning": "Planificación", - "execution": "Ejecución", - "quality": "Calidad y pruebas", - "debugging": "Depuración", - "review": "Revisión e integración", - "meta": "Meta" - }, - "states": { - "not_linked": "No habilitado", - "linked_to_codeg": "Habilitado", - "linked_elsewhere": "Bloqueado — existe otro vínculo", - "blocked_by_real_directory": "Bloqueado — una habilidad personalizada ocupa este nombre", - "broken": "Vínculo roto" - }, - "badges": { - "userModified": "Modificado por el usuario" - }, - "actions": { - "openCentralDir": "Abrir carpeta central", - "refresh": "Actualizar" - }, - "toasts": { - "loadFailed": "Error al cargar los detalles del experto", - "enabled": "Experto habilitado para este agente", - "disabled": "Experto deshabilitado para este agente", - "enableFailed": "Error al habilitar el experto", - "disableFailed": "Error al deshabilitar el experto", - "openFolderFailed": "Error al abrir la carpeta" - } - }, - "ScienceSettings": { - "title": "Habilidades de investigación científica", - "description": "Habilita habilidades de investigación científica seleccionadas para tus agentes de código con IA: generación de hipótesis, diseño experimental, estadística, visualización, evaluación crítica y búsqueda bibliográfica. codeg gestiona una copia central y enlaza cada habilidad a los agentes que elijas.", - "loading": "Cargando habilidades científicas…", - "emptySkills": "No hay habilidades científicas disponibles. Revisa los registros de la aplicación.", - "searchPlaceholder": "Buscar habilidades científicas por nombre, id o descripción", - "categories": { - "ideation": "Ideación", - "design": "Diseño de estudios", - "analysis": "Análisis", - "visualization": "Visualización", - "evaluation": "Evaluación", - "literature": "Literatura" - }, - "states": { - "not_linked": "No habilitado", - "linked_to_codeg": "Habilitado", - "linked_elsewhere": "Bloqueado — existe otro vínculo", - "blocked_by_real_directory": "Bloqueado — una habilidad personalizada ocupa este nombre", - "broken": "Vínculo roto" - }, - "badges": { - "userModified": "Modificado por el usuario", - "needsKey": "Requiere clave", - "needsSetup": "Puede requerir configuración" - }, - "actions": { - "openCentralDir": "Abrir carpeta central", - "refresh": "Actualizar" - }, - "toasts": { - "openFolderFailed": "Error al abrir la carpeta" - } - }, - "OfficeToolsSettings": { - "title": "Herramientas Office", - "description": "Gestiona las habilidades de OfficeCLI para crear archivos Excel, Word y PowerPoint. Instala OfficeCLI, sincroniza habilidades y actívalas por agente.", - "loadingContent": "Cargando contenido…", - "emptySkills": "No hay habilidades disponibles. Instala OfficeCLI y sincroniza las habilidades.", - "emptySelection": "Selecciona una habilidad para ver su contenido y gestionar la activación.", - "emptySearch": "No se encontraron habilidades.", - "searchPlaceholder": "Buscar habilidades por nombre, ID o descripción", - "enableForAgents": "Activar para agentes", - "noAgents": "No se detectaron agentes ACP.", - "installFirst": "Instala OfficeCLI primero para activar habilidades.", - "syncFirst": "Sincroniza las habilidades primero para cargar el contenido.", - "noContent": "Sin contenido disponible.", - "copyModeWarning": "Copiado (no vinculado). Vuelve a sincronizar para obtener la última versión.", - "previewTitle": "Vista previa de SKILL.md", - "detection": { - "installed": "Instalado", - "notInstalled": "No instalado", - "notRunnable": "Instalado pero no ejecutable", - "installHint": "Instala OfficeCLI para habilitar las habilidades de generación de documentos de oficina en tus agentes de IA.", - "install": "Instalar", - "uninstall": "Desinstalar", - "syncSkills": "Sincronizar habilidades" - }, - "categories": { - "general": "General", - "presentations": "Presentaciones", - "documents": "Documentos", - "spreadsheets": "Hojas de cálculo" - }, - "states": { - "not_linked": "No activado", - "linked_to_codeg": "Activado", - "linked_elsewhere": "Bloqueado — existe otro enlace", - "blocked_by_real_directory": "Bloqueado — una habilidad personalizada ocupa este nombre", - "broken": "Enlace roto" - }, - "badges": { - "notSynced": "No sincronizado" - }, - "actions": { - "refresh": "Actualizar" - }, - "toasts": { - "loadFailed": "Error al cargar los detalles de la habilidad", - "enabled": "Habilidad activada para este agente", - "disabled": "Habilidad desactivada para este agente", - "enableFailed": "Error al activar la habilidad", - "disableFailed": "Error al desactivar la habilidad", - "installSuccess": "OfficeCLI instalado correctamente", - "installFailed": "Error al instalar OfficeCLI", - "uninstallSuccess": "OfficeCLI desinstalado", - "uninstallFailed": "Error al desinstalar OfficeCLI", - "syncSuccess": "{synced} habilidades sincronizadas", - "syncPartial": "{synced} sincronizadas, {errors} fallidas", - "syncFailed": "Error al sincronizar habilidades" - }, - "autoPreviewLabel": "Abrir vista previa automáticamente", - "autoPreviewHint": "Cuando un agente crea o edita un archivo de Word, Excel o PowerPoint, abre su vista previa en vivo automáticamente." - }, - "SkillPacksSettings": { - "title": "Paquetes de habilidades", - "description": "Paquetes de habilidades seleccionados que codeg gestiona de forma centralizada y vincula a tus agentes de IA: expertos en programación, investigación científica y herramientas de documentos de oficina. Actívalos por agente abajo.", - "tabs": { - "experts": "Expertos", - "science": "Ciencia", - "office": "Herramientas de oficina", - "custom": "Personalizadas" - }, - "actions": { - "openCentralDir": "Abrir carpeta central", - "refresh": "Actualizar" - }, - "toasts": { - "openFolderFailed": "Error al abrir la carpeta" - } - }, - "QuickMessagesSettings": { - "title": "Mensajes rápidos", - "description": "Gestiona fragmentos de mensajes reutilizables. Arrastra para reordenar.", - "loading": "Cargando mensajes rápidos…", - "emptyList": "Aún no hay mensajes rápidos. Haz clic en \"Nuevo\" para crear uno.", - "emptySelection": "Selecciona un mensaje rápido para editar.", - "searchPlaceholder": "Buscar por título o contenido", - "untitled": "Sin título", - "actions": { - "new": "Nuevo", - "save": "Guardar", - "delete": "Eliminar", - "dragSort": "Arrastra para reordenar", - "dragSortMessage": "Arrastra para reordenar mensaje rápido: {name}" - }, - "fields": { - "title": "Título", - "titlePlaceholder": "Asigna un título corto a este mensaje", - "content": "Contenido", - "contentPlaceholder": "Escribe aquí el contenido del mensaje" - }, - "confirmDelete": { - "title": "¿Eliminar mensaje rápido?", - "message": "Esto eliminará permanentemente \"{name}\". ¿Estás seguro?", - "cancel": "Cancelar", - "confirm": "Eliminar" - }, - "toasts": { - "loadFailed": "Error al cargar mensajes rápidos", - "createFailed": "Error al crear el mensaje rápido", - "saveFailed": "Error al guardar el mensaje rápido", - "deleteFailed": "Error al eliminar el mensaje rápido", - "saveOrderFailed": "Error al guardar el orden", - "created": "Mensaje rápido creado", - "saved": "Mensaje rápido guardado", - "deleted": "Mensaje rápido eliminado" - } - }, - "Pet": { - "badge": { - "running": "{count} en ejecución", - "waiting": "{count} esperando aprobación", - "error": "{count} con error" - }, - "panel": { - "title": "Sesiones activas", - "empty": "No hay sesiones activas", - "emptyHint": "Aquí aparecen los agentes en ejecución y los que te necesitan.", - "statusRunning": "En ejecución", - "statusWaiting": "En espera", - "statusError": "Error", - "subAgentOf": "Subagente de" - }, - "menu": { - "scale": "Escala", - "openManager": "Gestionar mascotas", - "close": "Cerrar" - }, - "loadError": "No se pudo cargar la mascota", - "missingPetIdParam": "No hay mascota seleccionada", - "summonButton": "Mascota", - "manager": { - "title": "Mascotas", - "description": "Compañeros flotantes de escritorio con sprites compatibles con Codex.", - "addPet": "Añadir mascota", - "importFromCodex": "Importar desde Codex", - "noPets": "No hay mascotas. Añade una o impórtala desde Codex.", - "setActive": "Activar", - "active": "Activa", - "edit": "Editar", - "delete": "Eliminar", - "deleteConfirm": "¿Eliminar la mascota «{name}»? Se borrará del disco.", - "summon": "Invocar ventana de la mascota", - "openCodexHelp": "Las mascotas de Codex deben estar en ~/.codex/pets/. No se encontraron.", - "specRequirement": "El sprite debe tener 1536px de ancho y una altura múltiplo de 208px (p. ej. 1872 o 2288), en PNG o WebP con transparencia.", - "form": { - "id": "ID de mascota", - "idHelp": "Letras minúsculas, dígitos, '-' y '_'. Máx 64 chars.", - "displayName": "Nombre", - "description": "Descripción (opcional)", - "spritesheet": "Sprite", - "chooseFile": "Elegir archivo", - "replaceFile": "Reemplazar sprite", - "saveCreate": "Añadir mascota", - "saveUpdate": "Guardar cambios", - "cancel": "Cancelar" - }, - "errors": { - "missingId": "Se requiere ID de mascota", - "missingName": "Se requiere nombre", - "missingSpritesheet": "Se requiere sprite", - "addFailed": "Error al añadir la mascota", - "updateFailed": "Error al actualizar", - "deleteFailed": "Error al eliminar", - "loadFailed": "Error al cargar mascotas", - "setActiveFailed": "Error al activar mascota", - "summonFailed": "Error al invocar la ventana de mascota" - } - }, - "import": { - "title": "Importar desde Codex", - "subtitle": "Mascotas disponibles bajo ~/.codex/pets/.", - "selectAll": "Seleccionar todo", - "alreadyImported": "Ya importada", - "renameOnConflict": "Renombrar conflictos con sufijo -imported", - "import": "Importar selección", - "noneFound": "No hay mascotas Codex importables.", - "imported": "Importación correcta", - "failed": "Importación fallida", - "close": "Cerrar" - }, - "marketplace": { - "openMarketplace": "Mercado de mascotas", - "title": "Mercado de mascotas", - "search": "Buscar mascotas", - "kindFilter": { - "all": "Todas", - "object": "Objeto", - "animal": "Animal", - "person": "Persona", - "creature": "Criatura" - }, - "sortFilter": { - "latest": "Recientes", - "popular": "Populares", - "views": "Más vistas" - }, - "refresh": "Actualizar", - "install": "Instalar", - "installing": "Instalando", - "reinstall": "Reinstalar", - "reinstallConfirm": "¿Sobrescribir la mascota local \"{name}\"? Los datos existentes serán reemplazados.", - "cancel": "Cancelar", - "stats": { - "views": "Vistas", - "downloads": "Descargas", - "likes": "Me gusta" - }, - "actions": { - "idle": "Reposo", - "running_right": "Corre der.", - "running_left": "Corre izq.", - "waving": "Saluda", - "jumping": "Salta", - "failed": "Fallo", - "waiting": "Espera", - "running": "Corre", - "review": "Revisa" - }, - "page": "Página {page} de {total}", - "prev": "Anterior", - "next": "Siguiente", - "empty": "No hay mascotas que coincidan.", - "successInstalled": "\"{name}\" instalada", - "errors": { - "loadFailed": "No se pudo cargar el mercado", - "installFailed": "No se pudo instalar la mascota", - "alreadyInstalled": "La mascota ya existe localmente" - } - } - }, - "RemoteWorkspace": { - "openRemoteWorkspace": "Open remote workspace", - "manage": "Manage remote workspace", - "manageTitle": "Remote Workspace connections", - "empty": "No remote connections", - "searchPlaceholder": "Search remote workspaces", - "orderFailed": "Failed to save remote workspace order", - "dragSort": "Drag to sort", - "dragSortConnection": "Drag to sort {name}", - "newConnection": "New connection", - "loading": "Loading", - "loadingConnection": "Loading remote connection", - "name": "Name", - "baseUrl": "Service URL", - "token": "Access token", - "save": "Save", - "delete": "Delete", - "confirmDelete": { - "title": "Delete remote connection?", - "message": "This will remove \"{name}\" from this device. This action cannot be undone.", - "cancel": "Cancel", - "confirm": "Delete" - }, - "saved": "Remote connection saved.", - "deleted": "Remote connection deleted.", - "loadFailed": "Failed to load remote connections", - "saveFailed": "Failed to save remote connection", - "deleteFailed": "Failed to delete remote connection", - "openFailed": "Failed to open remote workspace", - "connectionLoadFailed": "Failed to load remote connection: {message}", - "connectionExpired": "Remote connection \"{name}\" is expired. Update its token and reload this window." - }, - "ServerFileBrowser": { - "title": "Seleccionar archivo del servidor", - "pathPlaceholder": "Introducir ruta de directorio...", - "goHome": "Ir al directorio personal", - "navigateUp": "Ir al directorio superior", - "select": "Seleccionar", - "cancel": "Cancelar", - "loading": "Cargando...", - "emptyDirectory": "Este directorio está vacío", - "errorLoadingDir": "Error al cargar el directorio", - "selectedCount": "{count} seleccionado(s)" - }, - "BackupSettings": { - "title": "Copia de seguridad y restauración", - "description": "Exporta una copia de seguridad portátil de tus datos de codeg, o restaura desde una.", - "tabs": { - "backup": "Copia de seguridad", - "restore": "Restaurar" - }, - "export": { - "includeExternal": "Incluir el contenido de las conversaciones", - "includeExternalHint": "También archiva las transcripciones de las CLI (Claude, Codex, Gemini, …). Aumenta el tamaño.", - "passphrase": "Frase de contraseña (opcional)", - "passphrasePlaceholder": "Déjala vacía para un archivo sin cifrar", - "passphraseConfirm": "Confirmar la frase de contraseña", - "passphraseMismatch": "Las frases de contraseña no coinciden.", - "noPassphraseWarning": "Esta copia contendrá secretos (claves de API, tokens) en texto plano. Guárdala en un lugar seguro.", - "passphraseLossWarning": "Cifrada con esta frase de contraseña. Si la pierdes, la copia no se podrá recuperar.", - "button": "Exportar copia", - "inProgress": "Creando copia de seguridad…", - "success": "Copia de seguridad creada.", - "started": "Descarga de la copia iniciada." - }, - "restore": { - "selectFile": "Seleccionar archivo de copia", - "passphrasePrompt": "Esta copia está cifrada. Introduce su frase de contraseña.", - "unlock": "Desbloquear", - "preview": { - "title": "Detalles de la copia", - "encrypted": "Cifrada", - "compatible": "Compatible", - "incompatible": "Incompatible", - "createdAt": "Creada: {value}", - "appVersion": "Versión de la app: {value}", - "incompatibleHint": "Esta copia fue creada por una versión más reciente de codeg y no se puede restaurar." - }, - "replaceWarning": "Restaurar reemplaza todos los datos actuales de codeg (base de datos y subidas). Tus datos actuales se guardan primero en una instantánea para poder recuperarlos.", - "keyringNote": "Los tokens de GitHub/chat del escritorio están en el llavero del sistema y no se incluyen; vuelve a introducirlos tras restaurar.", - "button": "Restaurar", - "staging": "Preparando la restauración…", - "staged": "Restauración preparada. Reiniciando…", - "restarting": "Restauración preparada. Reiniciando el servidor…", - "restartTimeout": "El servidor no volvió a tiempo. Recarga la página cuando esté activo.", - "externalSideLocation": "Las transcripciones de conversaciones se restauraron en {path}", - "confirmTitle": "¿Reemplazar todos los datos?", - "confirmBody": "Esto reemplazará tu base de datos y subidas actuales de codeg con la copia y luego reiniciará. Tus datos actuales se guardan primero en una instantánea.", - "cancel": "Cancelar", - "confirmAction": "Reemplazar y reiniciar", - "external": { - "title": "Contenido de las conversaciones", - "hint": "Esta copia incluye transcripciones de las CLI. Elige dónde restaurarlas.", - "modeSkip": "No restaurar", - "modeSide": "Restaurar en una carpeta aparte segura", - "modeOriginal": "Restaurar en las ubicaciones originales de las CLI", - "forceOverwrite": "Sobrescribir archivos existentes", - "forceOverwriteHint": "Reemplaza los archivos que ya existen en las carpetas de las CLI.", - "scanning": "Comprobando conflictos…", - "noConflicts": "No se sobrescribirá ningún archivo existente.", - "conflictCount": "Se verían afectados {count} archivo(s) existente(s).", - "conflictSkipNote": "Los archivos existentes se conservan (se omiten) salvo que actives la sobrescritura." - }, - "restartFailed": "La restauración quedó preparada, pero el servidor no pudo reiniciarse. Reinícialo manualmente para aplicarla." - }, - "remoteUnsupported": "La copia de seguridad y la restauración actúan sobre los datos de la máquina que ejecuta codeg. Estás conectado a un espacio de trabajo remoto: gestiona sus copias desde ese servidor directamente." - }, - "backup": { - "restore": { - "error": { - "badPassphrase": "Frase de contraseña incorrecta o copia dañada.", - "corrupted": "El archivo de copia de seguridad está dañado.", - "unknownFormat": "Este archivo no es una copia de seguridad de codeg reconocida.", - "newerVersion": "Esta copia fue creada por codeg {backupVersion}, más reciente que esta versión ({appVersion}).", - "alreadyPending": "Ya hay una restauración preparada. Reinicia para aplicarla antes de preparar otra." - } - }, - "error": { - "diskSpace": "No hay espacio en disco suficiente para completar la operación.", - "cancelled": "La operación fue cancelada." - } - }, - "WebConnection": { - "disconnectedTitle": "Conexión perdida", - "reconnectingDescription": "Intentando volver a conectar con el servidor. Normalmente se recupera solo en unos segundos.", - "reconnectNow": "Volver a conectar ahora", - "sessionExpiredTitle": "Sesión caducada", - "sessionExpiredDescription": "Tu sesión ya no es válida. Inicia sesión de nuevo para continuar.", - "goToLogin": "Ir al inicio de sesión" - }, - "LiveFeedback": { - "placeholder": "Envía una nota a {agent} mientras trabaja…", - "agentFallback": "el agente", - "ariaLabel": "Nota de comentarios en vivo", - "dialogTitle": "Comentarios en vivo", - "dialogDescription": "Envía una nota al agente mientras trabaja. La leerá en su próxima comprobación, sin interrumpir el paso actual.", - "dialogDescriptionInstant": "Envía una nota al agente mientras trabaja. Se inserta de inmediato en el turno actual: el agente la ve al instante.", - "channelDowngraded": "La inserción instantánea no está disponible en esta sesión: tu nota quedó guardada para que el agente la recoja en su próxima consulta.", - "send": "Enviar", - "cancel": "Cancelar", - "pending": "esperando", - "delivered": "recibida", - "turnEndedUnread": "El agente terminó antes de leer tus comentarios.", - "sendAsMessage": "Enviar como mensaje", - "dismiss": "Descartar", - "turnEndedResent": "El turno terminó: se envió como un mensaje nuevo.", - "turnEnded": "El turno ya terminó.", - "submitFailed": "No se pudo enviar tu nota" - }, - "AgentToolsSettings": { - "title": "Herramientas en la conversación", - "description": "Herramientas adicionales que codeg entrega a un agente dentro de una conversación. Se inyectan al iniciar el agente, así que los cambios se aplican a los agentes iniciados después.", - "feedbackLabel": "Comentarios en vivo", - "feedbackHint": "Envía notas y correcciones a un agente mientras trabaja. Si el agente admite la inserción instantánea, tu nota se inserta de inmediato en el turno en curso; de lo contrario, el agente recibe una herramienta para consultar tus comentarios — esos agentes suelen consultarla solo si lo mencionas en tu prompt, por ejemplo añade \"revisa mi feedback en vivo con regularidad\" a tu mensaje.", - "questionLabel": "Preguntar al usuario", - "questionHint": "Permite que los agentes se detengan y te hagan una pregunta de opción múltiple que aparece encima del cuadro de entrada de la conversación. El agente espera hasta que respondas (u omitas).", - "sessionInfoLabel": "Obtener información de sesión", - "sessionInfoHint": "Permite que los agentes consulten una sesión que mencionas en tu mensaje (una insignia de sesión) para leer su título, agente, estado, espacio de trabajo, uso de tokens y mensajes recientes.", - "automationsLabel": "Crear automatizaciones", - "automationsHint": "Guarda la conversación como una automatización que se ejecuta según un horario. Desactivado por defecto: luego inicia agentes por su cuenta.", - "workTasksLabel": "Crear tareas pendientes", - "workTasksHint": "Añade una tarjeta al tablero de pendientes desde la conversación. Desactivado por defecto: escribe estado de la aplicación.", - "save": "Guardar", - "saving": "Guardando…", - "saved": "Ajustes de herramientas guardados", - "saveFailed": "No se pudieron guardar los ajustes de herramientas", - "loadFailed": "Error al cargar: {detail}" - }, - "NotificationSoundSettings": { - "title": "Sonidos de notificación", - "description": "Reproduce un sonido breve cuando se produce un evento del agente. Son los mismos eventos que se envían a los canales de chat; esta configuración solo se aplica a este dispositivo.", - "enableHint": "Desactivado por defecto. Los sonidos solo suenan en la ventana del espacio de trabajo de este navegador o aplicación.", - "volume": "Volumen", - "preview": "Escuchar", - "previewEvent": "Escuchar el sonido de {event}", - "onlyWhenUnfocused": "Solo cuando la ventana no está enfocada", - "onlyWhenUnfocusedHint": "Permanece en silencio mientras estás mirando Codeg.", - "eventsTitle": "Eventos", - "eventsHint": "Elige un tono para cada evento o «Silencio» para omitirlo. Si el mismo evento se repite en pocos segundos, solo suena una vez.", - "toneNone": "Silencio", - "toneChime": "Campanilla", - "toneDing": "Timbre", - "toneBlip": "Pitido", - "tonePop": "Pop", - "toneAlert": "Alerta", - "toneDescend": "Descendente" - }, - "LogsSettings": { - "loading": "Cargando…", - "sectionTitle": "Registros de ejecución", - "sectionDescription": "Visualiza y configura los registros de diagnóstico de la aplicación. Los registros se escriben en archivos locales y se mantienen en memoria para la vista en vivo.", - "captureTitle": "Nivel de registro", - "captureDescription": "Controla cuánto detalle se captura. Los niveles más altos (Debug, Trace) registran más, pero generan registros más grandes. «Desactivado» deshabilita el registro.", - "captureLabel": "Nivel de captura", - "levels": { - "off": "Desactivado", - "error": "Error", - "warn": "Advertencia", - "info": "Información", - "debug": "Depuración", - "trace": "Rastreo" - }, - "viewerTitle": "Registros recientes", - "viewerDescription": "Vista en vivo de los registros recientes. Filtra por nivel o busca texto.", - "searchPlaceholder": "Buscar mensaje u origen…", - "viewLevels": { - "all": "Todos los niveles", - "error": "Error y superior", - "warn": "Advertencia y superior", - "info": "Información y superior", - "debug": "Depuración y superior", - "trace": "Rastreo y superior" - }, - "pause": "Pausar", - "resume": "En vivo", - "refresh": "Actualizar", - "clear": "Limpiar", - "openFolder": "Abrir carpeta", - "shownCount": "{shown} / {total} mostrados", - "empty": "No hay registros para mostrar.", - "levelSaveFailed": "No se pudo guardar el nivel de registro", - "openFolderFailed": "No se pudo abrir la carpeta de registros", - "downloadFailed": "No se pudo descargar el archivo de registro", - "filesTitle": "Archivos de registro", - "filesDescription": "Descarga archivos de registro completos del disco para ver el historial más allá del búfer en vivo.", - "filesEmpty": "Aún no hay archivos de registro.", - "download": "Descargar", - "downloadTruncated": "El archivo es grande; se descargaron los {size} más recientes. El archivo completo está en el directorio de registros.", - "captureEnvLocked": "El nivel de registro está controlado por la variable de entorno RUST_LOG / CODEG_LOG; cámbialo ahí para que surta efecto.", - "targetsTitle": "Anulaciones por módulo", - "targetsDescription": "Establece un nivel distinto para módulos específicos (p. ej. codeg_lib::acp) sin cambiar el nivel global.", - "targetsAdd": "Añadir", - "targetsRemove": "Quitar anulación", - "toggleDetails": "Mostrar detalles" - }, - "Automations": { - "title": "Automatizaciones", - "new": "Nueva automatización", - "empty": "Aún no hay automatizaciones", - "emptyHint": "Crea una para ejecutar una tarea del agente de forma programada o manual.", - "name": "Nombre", - "namePlaceholder": "p. ej. Revisión nocturna de PR", - "prompt": "Instrucción", - "promptPlaceholder": "¿Qué debe hacer el agente?", - "agent": "Agente", - "folder": "Carpeta del espacio de trabajo", - "folderPlaceholder": "Selecciona una carpeta", - "isolation": "Aislamiento", - "isolationWorktree": "Nuevo worktree por ejecución", - "isolationShared": "Ejecutar en la carpeta", - "isolationSharedCaveat": "Las ejecuciones usan directamente el árbol de trabajo de esta carpeta y pueden entrar en conflicto con tus cambios sin confirmar. Activa la opción de árbol de trabajo para aislar cada ejecución.", - "trigger": "Activador", - "triggerSchedule": "Programado", - "triggerManual": "Solo manual", - "cron": "Programación (cron)", - "cronPlaceholder": "0 9 * * 1-5", - "timezone": "Zona horaria", - "nextRun": "Próxima ejecución", - "branch": "Rama", - "branchOptional": "Rama (opcional)", - "enabled": "Activado", - "save": "Guardar", - "cancel": "Cancelar", - "edit": "Editar", - "delete": "Eliminar", - "runNow": "Ejecutar ahora", - "cancelRun": "Cancelar ejecución", - "runHistory": "Historial de ejecuciones", - "noRuns": "Aún no hay ejecuciones", - "allFolders": "Todas las carpetas", - "filterAll": "Todos", - "noMatches": "No hay automatizaciones que coincidan", - "viewConversation": "Ver conversación", - "lastRun": "Última ejecución", - "never": "Nunca", - "running": "En ejecución", - "deleteTitle": "¿Eliminar la automatización?", - "deleteDescription": "Esto elimina la automatización y su programación. Se conserva el historial.", - "statusRunning": "En ejecución", - "statusSucceeded": "Correcta", - "statusFailed": "Fallida", - "statusCancelled": "Cancelada", - "statusSkipped": "Omitida", - "errorName": "El nombre es obligatorio", - "errorPrompt": "La instrucción es obligatoria", - "errorCron": "Las automatizaciones programadas requieren una expresión cron", - "errorFolder": "Selecciona una carpeta del espacio de trabajo", - "presetHourly": "Cada hora", - "presetDaily": "Diario 9:00", - "presetWeekdays": "Días laborables 9:00", - "presetCustom": "Personalizado", - "probing": "Cargando opciones…", - "retry": "Reintentar", - "configNone": "Este agente no tiene opciones configurables", - "inherit": "Predeterminado del agente", - "mode": "Modo", - "config": "Configuración", - "branchPlaceholder": "(rama predeterminada)", - "selectHint": "Selecciona una automatización para ver los detalles", - "refresh": "Actualizar", - "onboardTitle": "Automatiza tareas rutinarias del agente", - "onboardHint": "Programa un agente para revisar código, actualizar dependencias o clasificar incidencias, de forma periódica o bajo demanda.", - "headerSubtitle": "Tareas del agente programadas y bajo demanda", - "startFromTemplate": "Empezar con una plantilla", - "blankTitle": "Automatización en blanco", - "blankDesc": "Configura una tarea del agente desde cero.", - "backToTemplates": "Plantillas", - "sectionSchedule": "Programación y destino", - "sectionTarget": "Destino", - "sectionAction": "Acción", - "actionLaunchSession": "Ejecutar sesión", - "actionEnqueueTask": "Encolar tarea", - "actionEnqueueTaskHint": "Cada disparo añade una tarea pendiente, titulada como esta automatización, a las tareas pendientes de la carpeta; el motor de tareas la ejecuta según la configuración del tablero.", - "sectionPrompt": "Prompt", - "nextIn": "Próxima en {rel}", - "manual": "Manual", - "schedEveryMinutes": "Cada {n} minutos", - "schedHourly": "Cada hora", - "schedDaily": "Cada día a las {time}", - "schedWeekdays": "Días laborables a las {time}", - "schedWeekly": "Cada {day} a las {time}", - "schedMonthly": "Cada mes el día {day} a las {time}", - "dow0": "domingo", - "dow1": "lunes", - "dow2": "martes", - "dow3": "miércoles", - "dow4": "jueves", - "dow5": "viernes", - "dow6": "sábado", - "tplCodeReviewTitle": "Revisión de código", - "tplCodeReviewDesc": "Revisa los cambios recientes en busca de errores, regresiones y problemas de calidad.", - "tplDependencyUpdatesTitle": "Actualización de dependencias", - "tplDependencyUpdatesDesc": "Encuentra dependencias desactualizadas y propón actualizaciones seguras.", - "tplTestCoverageTitle": "Cobertura de pruebas", - "tplTestCoverageDesc": "Encuentra rutas de código sin probar y añade las pruebas que faltan.", - "tplTodoSweepTitle": "Revisión de TODO", - "tplTodoSweepDesc": "Recopila los comentarios TODO y FIXME y clasifícalos por prioridad.", - "tplCiTriageTitle": "Clasificación de CI", - "tplCiTriageDesc": "Investiga las comprobaciones fallidas recientes y propón soluciones.", - "tplReleaseNotesTitle": "Notas de la versión", - "tplReleaseNotesDesc": "Resume los cambios desde la última versión en un registro de cambios.", - "tplSecurityAuditTitle": "Auditoría de seguridad", - "tplSecurityAuditDesc": "Busca vulnerabilidades y patrones de riesgo, y reporta los hallazgos.", - "enable": "Activar", - "disable": "Desactivar", - "moreActions": "Más acciones", - "statusDisabled": "Desactivada", - "cronBuilderTitle": "Generador de programación", - "cronFreqLabel": "Frecuencia", - "cronFreqMinutes": "Cada N minutos", - "cronFreqHourly": "Cada hora", - "cronFreqDaily": "Diario", - "cronFreqWeekdays": "Días laborables", - "cronFreqWeekly": "Semanal", - "cronFreqMonthly": "Mensual", - "cronFreqCustom": "Personalizado", - "cronEveryLabel": "Intervalo (minutos)", - "cronTimeLabel": "Hora", - "cronHourLabel": "Hora", - "cronMinuteLabel": "Minuto", - "cronDowLabel": "Día de la semana", - "cronDomLabel": "Día del mes", - "cronApply": "Aplicar", - "cronPreviewLabel": "Vista previa", - "cronOpenBuilder": "Abrir el generador de programación", - "branchDefault": "Rama predeterminada", - "branchUseCustom": "Usar «{query}»", - "branchLocal": "Local", - "branchRemote": "Remota", - "branchSearchPlaceholder": "Buscar ramas…", - "branchNone": "Sin ramas" - }, - "Tasks": { - "title": "Tareas pendientes", - "new": "Nueva tarea", - "empty": "Aún no hay tareas", - "emptyHint": "Añade un pendiente y ejecútalo: el agente trabaja en un worktree aislado y tú revisas y fusionas el resultado.", - "emptyColTodo": "Aún no hay pendientes", - "emptyColInProgress": "Nada en curso", - "emptyColAttention": "Nada requiere tu acción", - "emptyColDone": "Aún no hay completadas", - "allFolders": "Todas las carpetas", - "showCanceled": "Mostrar canceladas", - "showArchived": "Mostrar archivadas", - "filter": "Filtrar", - "viewSwitchToBoard": "Cambiar a vista de tablero", - "viewSwitchToList": "Cambiar a vista de lista", - "statusFilter": "Estado", - "statusFilterAll": "Todos los estados", - "listEmpty": "Ninguna tarea coincide con los filtros actuales", - "listColStatus": "Estado", - "listColTask": "Tarea", - "listColLocation": "Ubicación", - "listColChanges": "Cambios", - "listColUpdated": "Actualizado", - "colTodo": "Pendientes", - "colInProgress": "En curso", - "colAttention": "Requiere tu acción", - "colDone": "Completadas", - "statusTodo": "Pendiente", - "statusQueued": "En cola", - "statusPreparing": "Preparando", - "statusRunning": "En ejecución", - "statusAwaitingInput": "Esperando entrada", - "statusReview": "Por revisar", - "statusMerging": "Fusionando", - "statusDone": "Completada", - "statusFailed": "Fallida", - "statusCanceled": "Cancelada", - "statusInterrupted": "Interrumpida", - "badgeCleanupFailed": "Limpieza fallida", - "badgeWorktreeKept": "Worktree conservado", - "badgeWorktreeRemoved": "Worktree eliminado", - "filesChanged": "{count} archivos", - "actionStart": "Iniciar", - "actionSchedule": "Programar", - "actionCancel": "Cancelar", - "actionRetry": "Reintentar", - "actionRequeue": "Reencolar", - "actionViewSession": "Ver conversación", - "actionEdit": "Editar", - "actionDelete": "Eliminar", - "actionRetryCleanup": "Reintentar limpieza", - "actionMerge": "Fusionar", - "actionUnqueueMerge": "Salir de la cola de fusión", - "actionEditQueuedMerge": "Editar la fusión en cola", - "badgeMergeQueued": "En cola para fusionar", - "badgeMergeQueuedRank": "En cola para fusionar · n.º {rank}", - "badgeMergeQueuedHint": "Esperando a que termine la fusión en curso del proyecto; esta empezará sola.", - "actionComplete": "Completar", - "actionAbandon": "Abandonar", - "cancelTitle": "¿Cancelar la tarea?", - "cancelDescription": "La tarea pasa a Cancelada. Su worktree se conserva y podrás reencolarla más tarde.", - "cancelReasonLabel": "Motivo (opcional)", - "cancelReasonPlaceholder": "P. ej. enfoque equivocado: voy a reescribir la descripción", - "cancelKeep": "Mejor no", - "cancelSubmit": "Cancelar tarea", - "restartTitleRetry": "Reintentar la tarea", - "restartTitleRequeue": "Reencolar la tarea", - "restartDescription": "Puedes añadir una nota (opcional): llega al prompt de la próxima ejecución.", - "scheduleTitle": "Programar tarea", - "scheduleDescription": "La tarea sigue en Pendientes y se inicia sola a la hora que elijas. El límite de concurrencia de la carpeta se sigue aplicando.", - "scheduleDateLabel": "Fecha", - "schedulePickDate": "Elegir fecha", - "scheduleTimeLabel": "Hora", - "schedulePreview": "Se ejecuta el {time}", - "schedulePastHint": "Esa hora ya pasó: la tarea empezará en cuanto guardes.", - "scheduleInAnHour": "En 1 hora", - "scheduleInThreeHours": "En 3 horas", - "scheduleTomorrow": "Mañana 9:00", - "scheduleClear": "Quitar programación", - "scheduleBadge": "Inicio programado para el {time}", - "toastScheduled": "Programada para el {time}", - "toastScheduleCleared": "Programación eliminada", - "actionFollowUp": "Continuar", - "actionAddNote": "Añadir una nota", - "followUpSubmit": "Enviar", - "followUpIntentRevise": "Corregir", - "followUpIntentContinue": "Seguir", - "followUpIntentQuestion": "Preguntar", - "followUpIntentVerify": "Revisar", - "followUpPlaceholderRevise": "¿Qué debe cambiar el agente? Continúa en la misma sesión.", - "followUpPlaceholderContinue": "¿Qué sigue? Lo hecho hasta ahora se mantiene.", - "followUpPlaceholderQuestion": "¿Qué quieres saber? El agente responde sin tocar ningún archivo.", - "followUpPlaceholderVerify": "Opcional: ¿algo que deba revisar con atención?", - "followUpPlaceholderRetry": "Opcional: ¿qué debe hacer distinto? P. ej. ejecutar pnpm install primero", - "followUpPlaceholderRequeue": "Opcional: ¿por qué lo cancelaste y qué debe cambiar esta vez?", - "actionArchive": "Archivar", - "actionUnarchive": "Desarchivar", - "archiveAllDone": "Archivar todo", - "dropToStart": "Suelta para iniciar", - "errorView": "Ver", - "notifyReview": "Listo para revisar: {title}", - "notifyFailed": "La tarea falló: {title}", - "createFromMessage": "Crear tarea desde el mensaje", - "detailTokens": "Tokens totales", - "editorTitleNew": "Nueva tarea", - "editorTitleEdit": "Editar tarea", - "templates": "Plantillas", - "templatesEmpty": "Aún no hay plantillas.", - "templateSaveCurrent": "Guardar como plantilla", - "templateDelete": "Eliminar plantilla", - "transcriptTitle": "Conversación de la tarea", - "transcriptDescription": "Vista en vivo de solo lectura de la sesión del agente de la tarea.", - "phaseWork": "Ejecución", - "phaseRetry": "Reintento", - "phaseReturn": "Continuación", - "phaseMerge": "Fusión", - "titleLabel": "Título", - "titlePlaceholder": "¿Qué hay que hacer?", - "promptLabel": "Descripción de la tarea", - "promptPlaceholder": "Describe la tarea para el agente — @ para referenciar archivos, / para comandos", - "folderPlaceholder": "Selecciona una carpeta", - "agentInheritedHint": "Heredado de la configuración de tareas; cámbialo para personalizar esta tarea", - "agentOverrideReset": "Volver a heredar", - "sectionTarget": "Destino", - "errorTitle": "El título es obligatorio", - "errorPrompt": "La descripción es obligatoria", - "errorFolder": "Selecciona una carpeta", - "save": "Guardar", - "cancel": "Cancelar", - "mergeTitle": "Fusionar tarea", - "mergeQueuedTitle": "Fusión en cola", - "mergeQueueHint": "Otra tarea de este proyecto se está fusionando ahora. Esta entra en la cola y empezará sola en cuanto la otra termine.", - "mergeQueueUpdateHint": "Esta tarea ya está esperando para fusionarse. Al enviar se actualiza y conserva su lugar en la cola.", - "mergeDescription": "Fusionar {branch} en {base}. Los cambios sin confirmar del worktree se confirman primero.", - "mergeMessage": "Mensaje de commit", - "mergeMessagePlaceholder": "p. ej. feat: add login validation", - "mergeAutoMessage": "Dejar que el agente escriba el mensaje de commit", - "strategySquash": "Combinar en un solo commit", - "strategySquashHint": "Todos los cambios de la tarea llegan a la rama principal como una sola entrada del historial: un historial más limpio.", - "strategyMerge": "Conservar todo el historial", - "strategyMergeHint": "Se conserva cada commit hecho durante la tarea, más una entrada de fusión: cada paso queda rastreable.", - "mergeDeleteWorktree": "Eliminar el worktree tras fusionar", - "mergeSubmit": "Fusionar", - "mergeSubmitQueue": "Añadir a la cola", - "mergeQueuedToast": "Añadida a la cola de fusión: empezará en cuanto termine la fusión actual.", - "completeTitle": "Completar tarea", - "completeDescription": "Esta tarea no cambió ningún archivo, así que no hay nada que fusionar: se marca como completada directamente.", - "completeDescriptionNoWorktree": "El worktree de esta tarea fue eliminado, así que ya no se puede fusionar: se marca como completada directamente. Una rama de trabajo que aún tenga commits sin fusionar se conserva.", - "completeDeleteWorktree": "Eliminar el worktree al completar", - "completeSubmit": "Completar", - "settingsTitle": "Ajustes de tareas", - "settingsDescription": "Valores por defecto para las tareas de {folder}.", - "settingsScope": "Ámbito", - "settingsScopeGlobal": "Todas las carpetas (valores globales)", - "settingsScopeGlobalHint": "Las carpetas sin configuración propia usan estos valores globales.", - "settingsSource": "Origen de configuración", - "settingsSourceGlobal": "Valores globales", - "settingsSourceCustom": "Personalizada", - "settingsSourceGlobalFollow": "Sigue la configuración global de tareas; los cambios allí se aplican aquí automáticamente.", - "settingsSourceCustomHint": "Guarda configuración propia para esta carpeta y deja de seguir los valores globales.", - "settingsAgent": "Agente por defecto", - "settingsMaxConcurrent": "Tareas concurrentes máx.", - "settingsMaxConcurrentHint": "0 = sin límite", - "settingsAutoProcess": "Procesar automáticamente", - "settingsAutoProcessHint": "Las tareas pendientes se inician solas, hasta el límite de concurrencia.", - "settingsMergeStrategy": "Estrategia de fusión por defecto", - "settingsMergeStrategyHint": "Cómo se registran los cambios de la tarea en el historial de la rama al fusionar.", - "settingsAutoMerge": "Fusionar automáticamente", - "settingsAutoMergeHint": "Una tarea que llega a revisión con cambios que integrar se fusiona como si pulsaras Fusionar: el agente escribe el mensaje de commit y el worktree sigue el valor por defecto de abajo. Si la verificación falla o una fusión falló, la tarea queda esperándote.", - "settingsDeleteWorktree": "Eliminar el worktree tras fusionar", - "settingsDeleteWorktreeHint": "Marca la opción por defecto en el diálogo de fusión; aún puedes cambiarla allí.", - "settingsWorktreeRoot": "Ubicación del worktree", - "settingsWorktreeRootHint": "Directorio donde se crean los worktrees de las tareas nuevas, uno por tarea. Déjalo vacío para crearlos junto a la carpeta del proyecto; «~» es tu carpeta personal y una ruta relativa se resuelve respecto a la carpeta del proyecto.", - "settingsWorktreeRootPlaceholder": "~/codeg-worktrees", - "settingsWorktreeRootBrowse": "Elegir el directorio de worktrees", - "settingsPreflight": "Comando de verificación", - "settingsPreflightHint": "Se ejecuta en el worktree cuando una tarea llega a revisión.", - "settingsPreflightCustomPlaceholder": "pnpm test", - "settingsInitCommand": "Comando de inicialización del worktree", - "settingsInitCommandHint": "Se ejecuta en un worktree recién creado antes de iniciar el agente.", - "settingsInitCommandPlaceholder": "pnpm install", - "settingsTabGeneral": "General", - "settingsTabMerge": "Fusión", - "settingsTabWorktree": "Worktree", - "settingsTabPrompts": "Prompts", - "settingsPromptsIntro": "Cada etapa ya envía su propio prompt integrado: la tarea, las reglas del worktree y, al fusionar, los pasos exactos de git. Lo que añadas aquí se agrega al final como instrucciones extra: matiza esos textos integrados, nunca los sustituye.", - "settingsPromptStageAll": "Todas las fases", - "settingsPromptPlaceholderAll": "p. ej. Sigue las convenciones de AGENTS.md; que el resumen final no pase de dos frases", - "settingsPromptPlaceholderWork": "p. ej. Lee primero las pruebas relacionadas; haz commits pequeños sobre la marcha", - "settingsPromptPlaceholderRetry": "p. ej. Revisa qué hay ya commiteado antes de continuar; no rehagas lo terminado", - "settingsPromptPlaceholderReturn": "P. ej. Atiende cada punto planteado; no refactorices nada ajeno", - "settingsPromptPlaceholderMerge": "p. ej. Escribe el mensaje del commit de integración en español; señala los conflictos que resolviste a mano", - "settingsPromptHintAll": "Se añade a todos los prompts que recibe el agente, incluida la fusión.", - "settingsPromptHintWork": "Se añade cuando una tarea se ejecuta por primera vez.", - "settingsPromptHintRetry": "Se añade al retomar una tarea interrumpida o fallida.", - "settingsPromptHintReturn": "Se añade cuando continúas una tarea en revisión (corregir, ampliar, revisar).", - "settingsPromptHintMerge": "Se añade cuando el agente integra la tarea en la rama base.", - "preflightPassed": "{name} superado", - "preflightFailed": "{name} falló", - "preflightRunning": "{name} en ejecución…", - "detailDescription": "Detalle de la tarea", - "detailSummary": "Resultado", - "detailFiles": "Archivos modificados", - "detailDiffAll": "Ver diff completo", - "detailDiffAllTitle": "Diff completo", - "detailNoChanges": "Aún no hay cambios respecto a la base", - "detailTimeline": "Progreso", - "detailTimelineEmpty": "Sin actividad todavía", - "showMore": "Ver más", - "showLess": "Ver menos", - "detailInfo": "Detalles", - "detailBranch": "Rama", - "detailMergeCommit": "Commit de fusión", - "detailChanges": "Cambios", - "detailScheduled": "Inicio programado", - "detailCreated": "Creada", - "detailStarted": "Iniciada", - "detailFinished": "Finalizada", - "diffLoading": "Cargando diff…", - "deleteConfirmTitle": "¿Eliminar la tarea?", - "deleteConfirmBody": "“{title}” se quitará del tablero. Una ejecución activa se cancela primero.", - "deleteWithWorktree": "Eliminar también su worktree", - "eventCreated": "Creada", - "eventStatusChanged": "Cambio de estado", - "eventConfigEffective": "Configuración de arranque", - "eventInitCommand": "Comando de inicialización", - "eventAgentProgress": "Progreso del agente", - "eventAgentVerdict": "Veredicto del agente", - "eventMergeAttempt": "Fusión iniciada", - "eventMergeQueued": "En cola para fusionar", - "eventMergeConflict": "Conflicto de fusión", - "eventPreflight": "Verificación", - "eventCleanupFailed": "Fallo al limpiar el worktree", - "eventResumeFallback": "La reanudación falló; se usó una sesión nueva", - "eventUserAction": "Acción del usuario", - "eventDiffStat": "Instantánea de cambios" - }, - "CustomSkillsSettings": { - "loading": "Cargando habilidades personalizadas…", - "category": "Personalizadas", - "searchPlaceholder": "Buscar habilidades personalizadas por nombre, ID o descripción", - "states": { - "not_linked": "No habilitada", - "linked_to_codeg": "Habilitada", - "linked_elsewhere": "Vinculada en otro lugar", - "blocked_by_real_directory": "Bloqueada por una carpeta real", - "broken": "Enlace roto" - }, - "actions": { - "new": "Nueva", - "import": "Importar", - "importFromAgent": "Importar de un agente", - "cancel": "Cancelar", - "save": "Guardar" - }, - "rowMenu": { - "edit": "Editar", - "duplicate": "Duplicar", - "delete": "Eliminar" - }, - "bulk": { - "delete": "Eliminar seleccionadas" - }, - "editor": { - "createTitle": "Nueva habilidad personalizada", - "editTitle": "Editar habilidad personalizada", - "description": "Las habilidades personalizadas se guardan en el almacén compartido (~/.codeg/skills) y pueden habilitarse para cualquier agente.", - "idLabel": "ID de habilidad", - "idPlaceholder": "p. ej. my-workflow", - "contentLabel": "SKILL.md", - "contentPlaceholder": "Escribe aquí el SKILL.md de la habilidad…", - "preview": "Vista previa", - "edit": "Editar", - "emptyBody": "Aún no hay contenido." - }, - "duplicate": { - "title": "Duplicar habilidad", - "description": "Crea una copia de «{id}» con un nuevo ID.", - "newIdPlaceholder": "Nuevo ID de habilidad", - "confirm": "Duplicar" - }, - "import": { - "title": "Elige una carpeta de habilidad para importar" - }, - "importFromAgent": { - "title": "Importar habilidades de un agente", - "description": "Copia las habilidades propias de un agente al almacén compartido para poder activarlas en cualquier agente.", - "agentLabel": "Agente", - "agentPlaceholder": "Selecciona un agente", - "selectAll": "Seleccionar todo ({count})", - "loading": "Cargando las habilidades del agente…", - "unsupported": "Este agente no expone un directorio de habilidades.", - "empty": "Este agente no tiene habilidades que importar.", - "alreadyInLibrary": "En la biblioteca", - "confirm": "Importar seleccionadas ({count})" - }, - "delete": { - "title": "¿Eliminar habilidades personalizadas?", - "body": "Se eliminarán {count} habilidad(es) personalizada(s) del almacén central y se desvincularán de todos los agentes. Esta acción no se puede deshacer.", - "confirm": "Eliminar" - }, - "toasts": { - "loadFailed": "No se pudo cargar la habilidad", - "idRequired": "Introduce un ID de habilidad", - "created": "Habilidad personalizada creada", - "updated": "Habilidad personalizada actualizada", - "saveFailed": "No se pudo guardar la habilidad", - "imported": "Habilidad importada", - "importFailed": "No se pudo importar la habilidad", - "duplicated": "Habilidad duplicada", - "duplicateFailed": "No se pudo duplicar la habilidad", - "deleted": "Se eliminaron {count} habilidad(es)", - "deletedPartial": "{ok} eliminadas, {failed} fallidas", - "deleteFailed": "No se pudieron eliminar las habilidades", - "importedFromAgent": "Se importaron {count} habilidad(es)", - "importedFromAgentPartial": "Importadas {ok}, {failed} con error", - "importFromAgentAllSkipped": "Nada que importar: {count} ya están en la biblioteca", - "importFromAgentFailed": "No se pudo importar del agente" - } - }, - "CodexModelEditor": { - "customizedNotice": "Has personalizado la lista de modelos, así que ahora codeg gestiona toda la tabla de modelos de codex. Los modelos oficiales que codex añada después no aparecerán automáticamente: haz clic en el botón actualizar de abajo y guarda de nuevo para sincronizarlos. Borra tus personalizaciones para que codex vuelva a actualizarse automáticamente.", - "officialsTitle": "Modelos oficiales", - "officialsHint": "Se incluyen automáticamente del codex que ejecutas; elimina los que no quieras.", - "officialsEmpty": "No hay modelos oficiales disponibles.", - "refresh": "Actualizar desde codex", - "readdOfficial": "Volver a añadir oficial", - "customsTitle": "Modelos personalizados", - "customsEmpty": "Aún no hay modelos personalizados.", - "addCustom": "Agregar personalizado", - "slugPlaceholder": "id del modelo (slug)", - "displayNamePlaceholder": "Nombre visible", - "contextWindow": "Contexto", - "makeDefault": "Establecer como predeterminado", - "defaultHint": "Modelo predeterminado", - "remove": "Eliminar", - "advanced": "Avanzado", - "baseTemplate": "Plantilla base", - "baseTemplateHint": "Modelo oficial del que clonar los campos obligatorios (prompt del sistema, herramientas, límites).", - "groupBehavior": "Comportamiento y capacidades", - "fieldReasoningLevel": "Razonamiento predeterminado", - "fieldReasoningSummary": "Resumen de razonamiento", - "fieldVerbosity": "Nivel de detalle", - "fieldShellType": "Tipo de shell", - "fieldApplyPatch": "Herramienta apply-patch", - "fieldReasoningSummaries": "Resúmenes de razonamiento", - "fieldSupportVerbosity": "Control de detalle", - "fieldParallelToolCalls": "Llamadas a herramientas en paralelo", - "fieldSearchTool": "Herramienta de búsqueda web", - "optNone": "Ninguno", - "groupInstructions": "Descripción y prompt del sistema", - "fieldDescription": "Descripción", - "baseInstructions": "Prompt del sistema (base_instructions)" - }, - "DiagnosticsSettings": { - "title": "Diagnóstico del entorno", - "description": "Comprueba cómo esta app resuelve la CLI del agente en su propio proceso, que puede diferir de tu terminal.", - "loading": "Ejecutando diagnóstico…", - "error": "El diagnóstico falló", - "rerun": "Volver a ejecutar", - "copyAll": "Copiar todo", - "copied": "Diagnóstico copiado al portapapeles", - "button": "Diagnosticar", - "verdict": { - "ok": "El entorno parece correcto. Si aún aparece como no instalado, reinicia por completo la app para actualizar la caché del prefijo.", - "node_missing": "No se encontró Node.js en el PATH de la app.", - "npm_missing": "No se encontró npm en el PATH de la app.", - "not_installed": "Este agente no parece estar instalado.", - "installed_but_unresolved": "Consta como instalado, pero la app no puede localizar su ejecutable.", - "user_prefix_not_on_path": "Se instaló en el prefijo de reserva (~/.codeg/npm-global), que no está en el PATH de la app. Reinicia por completo la app e inténtalo de nuevo.", - "homebrew_bin_not_on_path": "Se instaló en el bin de Homebrew, que no está en el PATH de la app (división de keg en Apple Silicon).", - "terminal_only_path": "El comando se resuelve en tu terminal pero no en la app: una diferencia de PATH de la GUI. Inicia la app desde una terminal o reinstala desde Ajustes de agentes.", - "npm_prefix_timeout": "npm prefix -g fue demasiado lento (más de 1,5 s), por lo que se omitió la detección de reserva. Reinicia la app e inténtalo de nuevo.", - "node_too_old": "Tu Node.js activo es más antiguo de lo que requiere este agente. Actualiza Node.js.", - "adapter_missing_native_present": "Tu CLI de {agent} sí está instalada, pero Codeg ejecuta un paquete adaptador ACP aparte, y ese todavía no lo está. Instálalo desde la configuración de agentes: no toca tu CLI y comparte la misma sesión.", - "adapter_missing": "Codeg ejecuta un paquete adaptador ACP aparte para {agent} y aún no está instalado. Instálalo desde la configuración de agentes: instalar solo la CLI del proveedor no basta." - } - }, - "TokenUsage": { - "title": "Uso de tokens", - "rangeLabel": "Periodo", - "range7d": "7 días", - "range30d": "30 días", - "range90d": "90 días", - "rangeThisMonth": "Este mes", - "rangeThisYear": "Este año", - "rangeAll": "Todo", - "rangeCustom": "Personalizado", - "moreRanges": "Más", - "customRangePick": "Elegir un intervalo", - "bucketLabel": "Agrupar por", - "bucketDay": "Día", - "bucketWeek": "Semana", - "bucketMonth": "Mes", - "bucketUnitDay": "Día", - "bucketUnitWeek": "Semana", - "bucketUnitMonth": "Mes", - "folderFilter": "Carpetas", - "allFolders": "Todas las carpetas", - "agentFilter": "Agentes", - "allAgents": "Todos los agentes", - "modelFilter": "Modelos", - "allModels": "Todos los modelos", - "searchPlaceholder": "Buscar…", - "noMatches": "Sin coincidencias", - "clearFilter": "Borrar selección", - "resetFilters": "Restablecer filtros", - "refresh": "Actualizar", - "rebuild": "Reconstruir todo", - "rebuildHint": "Descarta lo contabilizado y vuelve a leer todas las transcripciones. Útil si una sesión creció fuera de codeg.", - "syncing": "Contando sesiones…", - "syncProgress": "{done} / {total}", - "syncDone": "{synced} sesiones contabilizadas", - "syncFailed": "No se pudieron leer algunas sesiones", - "syncBusy": "Ya hay una actualización en curso", - "lastSynced": "Actualizado {time}", - "lastSyncedNever": "Nunca actualizado", - "tileTotal": "Tokens totales", - "tileSessions": "Sesiones", - "tileTurns": "Turnos", - "tileActiveDays": "Días activos", - "tileGenTime": "Tiempo de generación", - "vsPrevious": "frente al periodo anterior", - "deltaNew": "nuevo", - "trendTitle": "Uso en el tiempo", - "trendEmpty": "Sin uso en este periodo", - "trendTurns": "Turnos", - "trendSessions": "Sesiones", - "compositionTitle": "En qué se fueron los tokens", - "compositionHint": "La entrada es lo que enviaste, la salida lo que escribió el modelo y las lecturas de caché son contexto que no pagaste a precio completo.", - "compositionNote": "Reenviar esos aciertos de caché a precio completo habría costado otros {value}.", - "inputTokens": "Entrada", - "outputTokens": "Salida", - "cacheWrite": "Escritura de caché", - "cacheRead": "Lectura de caché", - "freshTokens": "Cómputo nuevo", - "cacheHitCaption": "Acierto de caché", - "cacheHeroTitleHigh": "La mayoría del contexto no se reenvió", - "cacheHeroTitleLow": "La mayoría del contexto aún se calcula a precio completo", - "cacheHeroDesc": "La caché cargó con {cached} de contexto; solo {fresh} se calculó de nuevo en este periodo.", - "cacheSavedSuffix": "Eso ahorró reenviar el equivalente a {saved}.", - "avgPerSession": "Media por sesión", - "avgTurnsPerSession": "{count} turnos por sesión de media", - "avgPerActiveDay": "Media por día activo", - "peakBucket": "{bucket} con más uso", - "peakHour": "Hora punta", - "daysValue": "{count} días", - "idleDays": "Días sin actividad", - "byFolderTitle": "Por carpeta", - "byAgentTitle": "Por agente", - "byModelTitle": "Por modelo", - "distributionTitle": "Distribución del uso", - "distributionHint": "Sesiones y tokens agrupados por la dimensión elegida; haz clic en una fila para filtrar por ella.", - "otherLabel": "Otros", - "unknownModel": "Modelo sin registrar", - "emptyBreakdown": "Todavía sin registros", - "sessionsCount": "{count} sesiones", - "heatmapTitle": "Cuándo programas", - "heatmapHint": "Tokens por día de la semana y hora local.", - "heatmapPeakHint": "La franja más densa ronda las {hour}:00.", - "less": "Menos", - "more": "Más", - "heatmapCell": "{weekday} {hour}:00 — {value} tokens", - "weekMon": "Lun", - "weekTue": "Mar", - "weekWed": "Mié", - "weekThu": "Jue", - "weekFri": "Vie", - "weekSat": "Sáb", - "weekSun": "Dom", - "topSessionsTitle": "Sesiones más costosas", - "untitledSession": "Sesión sin título", - "topSessionsEmpty": "Sin sesiones en este periodo", - "streakLongest": "Racha más larga", - "streakLongestDays": "Racha más larga: {count} días", - "share": "Compartir", - "moreActions": "Más acciones", - "shareDialogTitle": "Comparte tu tarjeta de uso", - "shareDialogHint": "Una instantánea del periodo y los filtros que estás viendo.", - "shareSave": "Guardar imagen", - "shareCopy": "Copiar imagen", - "shareCopied": "Copiado al portapapeles", - "shareSaved": "Imagen guardada", - "shareFailed": "No se pudo crear la imagen", - "shareRendering": "Generando…", - "cardHeading": "Mis estadísticas de código con IA", - "cardRangeAll": "Todo el tiempo", - "cardTotalLabel": "Tokens usados", - "cardFooter": "Hecho con codeg", - "cardTopModels": "Modelos principales", - "cardTopProjects": "Proyectos principales", - "archetypeNightOwl": "Ave nocturna", - "archetypeNightOwlDesc": "El {percent}% de tus tokens se quema de noche.", - "archetypeEarlyBird": "Madrugador", - "archetypeEarlyBirdDesc": "El {percent}% de tus tokens cae antes de las 9.", - "archetypeWeekendWarrior": "Guerrero de fin de semana", - "archetypeWeekendWarriorDesc": "El {percent}% de tus tokens ocurre el fin de semana.", - "archetypeCacheMaster": "Maestro de la caché", - "archetypeCacheMasterDesc": "El {percent}% de tu contexto vino de la caché.", - "archetypeMarathoner": "Maratoniano", - "archetypeMarathonerDesc": "{days} días programando sin parar.", - "archetypePolyglot": "Polivalente", - "archetypePolyglotDesc": "{count} agentes en rotación seria.", - "archetypeLaserFocus": "Foco láser", - "archetypeLaserFocusDesc": "El {percent}% de tus tokens fue a un solo proyecto.", - "archetypeDeepDiver": "Buceador", - "archetypeDeepDiverDesc": "{averageK}K tokens en una sesión media.", - "archetypeSteady": "Constructor constante", - "archetypeSteadyDesc": "{days} días entregando.", - "emptyTitle": "Todavía no hay nada contabilizado", - "emptyHint": "Codeg lee los tokens directamente de la transcripción de cada agente. Actualiza para contabilizar lo que ya hay en esta máquina.", - "emptyAction": "Contabilizar mis sesiones", - "loadFailed": "No se pudo cargar el uso", - "truncatedNotice": "Este periodo es muy amplio: las cifras cubren solo su tramo más reciente." - } -} +{ + "Language": { + "followSystem": "Seguir el sistema", + "english": "Inglés", + "simplifiedChinese": "Chino simplificado", + "traditionalChinese": "Chino tradicional", + "japanese": "Japonés", + "korean": "Coreano", + "spanish": "Español", + "german": "Alemán", + "french": "Francés", + "portuguese": "Portugués", + "arabic": "Árabe" + }, + "GitCredentialDialog": { + "title": "Autenticación requerida", + "description": "El servidor remoto requiere credenciales. Introduce tu nombre de usuario y contraseña (o token de acceso personal).", + "username": "Nombre de usuario", + "usernamePlaceholder": "Usuario o correo electrónico", + "password": "Contraseña / Token", + "passwordPlaceholder": "Contraseña o token de acceso personal", + "passwordHint": "Introduce el nombre de usuario y contraseña del servidor.", + "cancel": "Cancelar", + "authenticate": "Autenticar", + "authenticating": "Autenticando...", + "invalidCredentials": "Credenciales inválidas. Inténtalo de nuevo.", + "saveCredentials": "Guardar credenciales para futuras operaciones", + "githubTitle": "Autenticación de GitHub", + "githubDescription": "Introduce un token de acceso personal para conectarte a GitHub. El token se validará y guardará automáticamente.", + "githubToken": "Token de acceso personal", + "githubTokenPlaceholder": "ghp_xxxxxxxxxxxx", + "githubTokenHint": "Genera un token en GitHub → Settings → Developer settings → Personal access tokens.", + "githubAuthenticate": "Validar y conectar", + "generateToken": "Generar token" + }, + "SettingsShell": { + "title": "Configuración", + "preferences": "Preferencias", + "nav": { + "general": "General", + "appearance": "Apariencia", + "agents": "Agentes", + "mcp": "MCP", + "skills": "Skills", + "shortcuts": "Atajos", + "version_control": "Control de versiones", + "system": "Sistema", + "chat_channels": "Canales de chat", + "web_service": "Servicio Web", + "model_providers": "Proveedores de Modelos", + "experts": "Expertos", + "science": "Ciencia", + "office_tools": "Herramientas de oficina", + "skill_packs": "Paquetes de habilidades", + "quick_messages": "Mensajes rápidos", + "logs": "Registros de ejecución" + } + }, + "AppearanceSettings": { + "sectionTitle": "Apariencia del tema", + "sectionDescription": "Elige claro, oscuro o seguir el sistema. La configuración se guarda automáticamente.", + "themeMode": "Modo de tema", + "placeholder": "Selecciona el modo de tema", + "system": "Seguir el sistema", + "light": "Claro", + "dark": "Oscuro", + "currentTheme": "Tema efectivo actual: {theme}", + "resolvedTheme": { + "light": "Claro", + "dark": "Oscuro", + "unknown": "--" + }, + "themeColor": { + "sectionTitle": "Color del tema", + "sectionDescription": "Elige una paleta de colores para acentos, botones y resaltados.", + "current": "Color actual: {color}", + "options": { + "neutral": "Neutral", + "zinc": "Zinc", + "slate": "Slate", + "stone": "Stone", + "gray": "Gray", + "red": "Red", + "rose": "Rose", + "orange": "Orange", + "green": "Green", + "blue": "Blue", + "yellow": "Yellow", + "violet": "Violet" + } + }, + "customStyle": { + "sectionTitle": "Estilo personalizado", + "sectionDescription": "Ajusta los colores del tema actual o inyecta tu propio CSS. Las anulaciones se aplican sobre el preajuste base, así que se conservan al cambiar de preajuste.", + "summarySuspended": "Suspendido", + "summaryDefault": "Preajuste sin cambios", + "summaryTokens": "{count, plural, one {# anulación} other {# anulaciones}}", + "summaryCss": "CSS personalizado", + "suspendedByShortcut": "El estilo personalizado está suspendido. Nada de lo que configures aquí surtirá efecto hasta que lo reanudes.", + "suspendedBySafeParam": "Esta ventana se abrió en modo de apariencia segura, por lo que el estilo personalizado se ignora aquí. Las demás ventanas no se ven afectadas.", + "resume": "Reanudar estilo personalizado", + "enableTheme": "Activar colores personalizados", + "editingLight": "Editando los valores del modo claro. Cambia la aplicación al modo oscuro para configurarlo por separado.", + "editingDark": "Editando los valores del modo oscuro. Cambia la aplicación al modo claro para configurarlo por separado.", + "resetToken": "Restablecer al valor del preajuste", + "radius": "Radio de esquina", + "radiusHint": "De él deriva toda la escala de radios, de sm a 4xl, así que un único control redondea toda la aplicación.", + "advanced": "Avanzado ({count} variables más)", + "enableCss": "Activar CSS personalizado", + "cssRisk": "Función avanzada. El CSS personalizado anula todos los estilos integrados y puede dejar la interfaz inutilizable.", + "editCss": "Editar CSS…", + "cssPresent": "{size} KB guardados", + "cssEmpty": "Todavía no hay nada guardado", + "escapeHint": "¿Interfaz rota? Pulsa {shortcut} para suspender todo el estilo personalizado, o abre una ventana con el parámetro de consulta safeStyle=1.", + "copyTheme": "Copiar JSON del tema", + "importTheme": "Importar tema…", + "clearTheme": "Borrar anulaciones", + "interopHint": "Los temas usan el formato registry:theme de shadcn, así que puedes pegar aquí cualquier tema de shadcn y usar los exportados en cualquier proyecto shadcn.", + "importTitle": "Importar tema", + "importDescription": "Pega un elemento registry:theme de shadcn, un objeto light/dark simple o un mapa plano de tokens.", + "readClipboard": "Leer portapapeles", + "importConfirm": "Importar", + "cancel": "Cancelar", + "apply": "Aplicar", + "toasts": { + "copied": "JSON del tema copiado", + "copyFailed": "No se pudo copiar al portapapeles", + "clipboardReadFailed": "No se pudo leer el portapapeles, pégalo manualmente", + "importFailed": "Ese JSON no contiene variables de tema utilizables", + "imported": "Tema importado" + }, + "css": { + "dialogTitle": "CSS personalizado", + "dialogDescription": "Se aplica a todas las ventanas de codeg. Los cambios se previsualizan en vivo; pulsa Aplicar para guardar.", + "size": "{used} KB / {max} KB", + "ruleCount": "{count} reglas", + "errorTooLarge": "Demasiado grande para guardar. Redúcelo por debajo del límite.", + "errorImportEscaped": "Una regla @import sobrevivió a la eliminación (sintaxis con escapes). Quítala para guardar.", + "warnNoRules": "No se analizó ninguna regla; revisa la sintaxis.", + "noticeImportsRemoved": "Reglas @import eliminadas: {count}. Descargarían hojas de estilo remotas.", + "noticeRemoteUrl": "Contiene una url() remota, que hará una petición de red al aplicarse.", + "noticePreviewSuspended": "El estilo personalizado está suspendido, así que esta vista previa no se aplica.", + "noticeDisabled": "El CSS personalizado está desactivado. Puedes previsualizar aquí, pero no se aplicará hasta que lo actives.", + "hintTokens": "Consejo: tus colores anulados están disponibles como var(--primary), var(--background), etc." + } + }, + "zoomLevel": { + "sectionTitle": "Zoom de ventana", + "sectionDescription": "Escala toda la interfaz. Se aplica al instante y se guarda por dispositivo.", + "placeholder": "Selecciona el nivel de zoom", + "default": "Predeterminado", + "current": "Zoom actual: {zoom}%" + }, + "fonts": { + "sectionTitle": "Fuentes", + "sectionDescription": "Elige las fuentes para la interfaz, el editor de código y el terminal. Las fuentes incluidas se cargan cuando se necesitan; selecciona «Personalizada…» para usar cualquier fuente instalada en tu sistema.", + "interface": "Interfaz", + "editor": "Editor", + "terminal": "Terminal", + "groupSans": "Sans-serif", + "groupMono": "Monoespaciada", + "custom": "Personalizada…", + "customPlaceholder": "Nombre de la fuente, p. ej. Fira Code", + "fontSize": "Tamaño de fuente", + "ligatures": "Activar ligaduras", + "ligaturesUnavailable": "Esta fuente no tiene ligaduras", + "wordWrap": "Activar ajuste de línea", + "terminalLigaturesHint": "Las ligaduras del terminal solo se aplican a las fuentes de programación incluidas.", + "preview": "Vista previa" + }, + "welcomePanel": { + "sectionTitle": "Área de selección de modo", + "sectionDescription": "Las tarjetas de acceso rápido «Desarrollo de código / Ofimática» que se muestran sobre el editor en la página de nueva conversación.", + "showQuickActions": "Mostrar en la página de nueva conversación" + }, + "workspaceBackground": { + "sectionTitle": "Fondo del espacio de trabajo", + "sectionDescription": "Muestra una imagen detrás de todo el espacio de trabajo. La barra lateral y los paneles se vuelven translúcidos y esmerilados para dejar ver la imagen, y una máscara mantiene el texto legible.", + "enable": "Activar imagen de fondo", + "image": "Imagen", + "chooseImage": "Elegir imagen", + "replaceImage": "Reemplazar imagen", + "removeImage": "Quitar", + "fillMode": "Modo de relleno", + "fillModes": { + "cover": "Cubrir", + "contain": "Ajustar", + "center": "Centrar", + "tile": "Mosaico" + }, + "maskOpacity": "Opacidad de la máscara", + "maskOpacityHint": "Los valores más altos difuminan la imagen hacia el color de fondo del tema, mejorando el contraste del texto.", + "imageBlur": "Desenfoque de la imagen", + "panelOpacity": "Opacidad de los paneles", + "panelOpacityHint": "Cuán opacos son la barra lateral, los paneles y las barras de pestañas. Más bajo deja ver más la imagen.", + "errorTooLarge": "La imagen es demasiado grande (máx. 16 MB).", + "errorUploadFailed": "No se pudo establecer la imagen de fondo." + } + }, + "SystemSettings": { + "loading": "Cargando...", + "sectionTitle": "Administración del sistema", + "sectionDescription": "Administra el proxy de red, las actualizaciones de la app y las preferencias de idioma.", + "proxyTitle": "Proxy de red", + "proxyDescription": "Cuando está activado, las solicitudes de red posteriores usarán este proxy preferentemente (incluyendo chat ACP, instalación de agentes y operaciones remotas de Git).", + "loadFailed": "Error al cargar: {message}", + "enableProxy": "Activar proxy del sistema", + "proxyAddress": "Dirección del proxy", + "proxyHint": "Compatible con http(s)/socks5, ejemplo: {example}. Solo funciona cuando el proxy del sistema está activado.", + "save": "Guardar", + "saving": "Guardando...", + "proxyRequired": "Se requiere URL del proxy cuando el proxy está activado", + "saveSuccess": "La configuración del proxy del sistema se guardó", + "saveFailed": "Error al guardar: {message}", + "languageTitle": "Idioma", + "languageDescription": "Configura el idioma de la app. Al seguir el idioma del sistema, los no compatibles vuelven a inglés.", + "appLanguage": "Idioma de la app", + "languageSaveSuccess": "La configuración de idioma se guardó", + "languageSaveFailed": "No se pudo guardar la configuración de idioma: {message}", + "updateTitle": "Actualización de la app", + "versionTitle": "Actualización de software", + "updateDescription": "Comprueba versiones más nuevas en la fuente de versiones configurada e instálalas directamente cuando estén disponibles.", + "currentVersion": "Versión actual", + "upgradableVersion": "Última versión", + "none": "Ninguna", + "lastChecked": "Última comprobación: {time}", + "updateError": "Error de actualización: {message}", + "checking": "Comprobando...", + "checkUpdate": "Buscar actualizaciones", + "updating": "Instalando...", + "downloading": "Descargando...", + "upgradeTo": "Actualizar a v{version}", + "viewRelease": "Ver lanzamiento v{version}", + "foundUpdate": "Nueva versión v{version} encontrada", + "alreadyLatest": "Ya tienes la versión más reciente", + "checkUpdateFailed": "No se pudo buscar actualizaciones: {message}", + "installSuccess": "Actualización instalada. Reiniciando la app.", + "installFailed": "La actualización falló: {message}", + "upgradeSuccess": "Actualización completada. Recargando...", + "restartTimeout": "El servidor no volvió a tiempo. Revisa los registros del contenedor o del servicio.", + "restartingIn": "Reiniciando en {seconds} s...", + "waitingForServer": "Esperando a que el servidor vuelva...", + "restartToUpdate": "Reiniciar para actualizar", + "newVersionBadge": "Nueva v{version}", + "updateAvailableTitle": "Actualización disponible", + "releaseNotesTitle": "Novedades", + "remindLater": "Más tarde", + "retry": "Reintentar", + "stepDownload": "Descarga", + "stepInstall": "Instalación", + "stepRestart": "Reinicio", + "updateReadyHint": "Actualización descargada: reinicia para aplicarla.", + "restarting": "Reiniciando...", + "dockerUpgradeHint": "Esto actualiza el contenedor en ejecución ahora. Se pierde si se recrea el contenedor: para conservarlo, descarga o crea una imagen con la nueva versión y recrea el contenedor.", + "upgradeRolledBack": "La actualización falló; el servidor volvió a la versión anterior.", + "serverUnreachable": "No se pudo conectar con el servidor para iniciar la actualización. Comprueba que esté en ejecución e inténtalo de nuevo.", + "rollbackButton": "Revertir", + "rollingBack": "Revirtiendo...", + "rollbackDescription": "Restaura la versión instalada antes de la última actualización.", + "rollbackConfirmTitle": "¿Revertir a la versión anterior?", + "rollbackConfirmDescription": "El servidor se reiniciará con la versión instalada antes de la última actualización. Una versión más reciente seguirá disponible para instalar de nuevo.", + "rollbackConfirm": "Revertir", + "rollbackCancel": "Cancelar", + "rollbackSuccess": "Se revirtió a la versión anterior. Recargando...", + "rollbackFailed": "Error al revertir. Revisa los registros del servidor.", + "updateErrors": { + "sourceUnavailable": "No se puede acceder al origen de actualización. Revisa tu red o proxy e inténtalo de nuevo.", + "network": "Falló la conexión de red. Revisa tu red o proxy e inténtalo de nuevo.", + "downloadFailed": "No se pudo descargar el paquete de actualización. Inténtalo más tarde.", + "installFailed": "No se pudo instalar la actualización. Cierra la app e inténtalo de nuevo.", + "unknown": "La actualización falló. Inténtalo más tarde." + } + }, + "VersionControlSettings": { + "loading": "Cargando...", + "sectionTitle": "Control de versiones", + "sectionDescription": "Configura el ejecutable de Git y gestiona las cuentas de GitHub.", + "gitTitle": "Configuración de Git", + "gitDescription": "Configura el ejecutable de Git utilizado por la aplicación.", + "gitDetected": "Git detectado", + "gitNotFound": "Git no encontrado en el sistema", + "gitVersion": "Versión", + "gitPath": "Ruta", + "customGitPath": "Ruta personalizada de Git", + "customGitPathPlaceholder": "/usr/bin/git", + "customGitPathHint": "Dejar vacío para usar la ruta detectada automáticamente.", + "test": "Probar", + "testing": "Probando...", + "testSuccess": "El ejecutable de Git es válido.", + "testFailed": "Prueba de Git fallida: {message}", + "save": "Guardar", + "saving": "Guardando...", + "saveSuccess": "Configuración de Git guardada.", + "saveFailed": "Error al guardar: {message}", + "githubTitle": "Cuentas de GitHub", + "githubDescription": "Gestiona las cuentas de GitHub para autenticación. Los tokens se almacenan localmente.", + "noAccounts": "No hay cuentas de GitHub configuradas.", + "addAccount": "Añadir cuenta", + "serverUrl": "URL del servidor", + "serverUrlPlaceholder": "https://github.com", + "token": "Token de acceso personal", + "tokenPlaceholder": "ghp_xxxxxxxxxxxx", + "generateToken": "Generar token", + "tokenHint": "Genera un token en GitHub → Settings → Developer settings → Personal access tokens.", + "validateAndAdd": "Validar y añadir", + "validating": "Validando...", + "addSuccess": "Cuenta {username} añadida correctamente.", + "addFailed": "Error al añadir cuenta: {message}", + "testConnection": "Probar", + "connectionSuccess": "Conexión exitosa.", + "connectionFailed": "Conexión fallida: {message}", + "setDefault": "Establecer como predeterminada", + "defaultLabel": "Predeterminada", + "defaultSet": "Cuenta predeterminada actualizada.", + "removeAccount": "Eliminar", + "removeConfirmTitle": "Eliminar cuenta", + "removeConfirmMessage": "¿Estás seguro de que deseas eliminar la cuenta \"{username}\"?", + "removeConfirm": "Eliminar", + "removeCancel": "Cancelar", + "removeSuccess": "Cuenta eliminada.", + "scopes": "Alcances", + "loadFailed": "Error al cargar configuración: {message}", + "gitAccount": { + "sectionTitle": "Cuentas de servidor Git", + "sectionDescription": "Gestiona credenciales para servidores Git que no son GitHub (GitLab, Bitbucket, autoalojados, etc.).", + "noAccounts": "No hay cuentas de servidor Git configuradas.", + "addAccount": "Añadir cuenta", + "addTitle": "Añadir cuenta Git", + "addDescription": "Introduce la dirección del servidor, nombre de usuario y contraseña o token de acceso.", + "serverUrl": "URL del servidor", + "serverUrlPlaceholder": "https://gitlab.example.com", + "username": "Nombre de usuario", + "usernamePlaceholder": "Usuario o correo electrónico", + "password": "Contraseña / Token", + "passwordPlaceholder": "Contraseña o token de acceso", + "passwordHint": "Introduce tu contraseña o token de acceso del servidor.", + "add": "Añadir", + "serverRequired": "La URL del servidor es obligatoria.", + "usernameRequired": "El nombre de usuario es obligatorio.", + "passwordRequired": "La contraseña es obligatoria." + } + }, + "ShortcutSettings": { + "sectionTitle": "Atajos", + "resetDefault": "Restablecer valores predeterminados", + "recordInstruction": "Haz clic en el botón derecho y luego pulsa una combinación de teclas. Usa Ctrl/Cmd, Alt y Shift. Pulsa Esc para cancelar la grabación.", + "recording": "Pulsa un atajo...", + "toasts": { + "conflict": "El atajo ya está en uso por \"{title}\"", + "updated": "Atajo actualizado", + "invalid": "Atajo no válido, inténtalo de nuevo", + "reset": "Se restauraron los atajos predeterminados" + }, + "actions": { + "toggle_search": { + "title": "Abrir búsqueda", + "description": "Muestra u oculta el panel de búsqueda de conversaciones" + }, + "toggle_sidebar": { + "title": "Alternar barra lateral izquierda", + "description": "Muestra u oculta la barra lateral de lista de conversaciones" + }, + "toggle_terminal": { + "title": "Alternar terminal", + "description": "Muestra u oculta el panel de terminal inferior" + }, + "new_terminal_tab": { + "title": "Nueva terminal", + "description": "Crea una nueva pestaña de terminal cuando el foco está en la terminal" + }, + "close_current_terminal_tab": { + "title": "Cerrar terminal actual", + "description": "Cierra la pestaña de terminal actual cuando el foco está en la terminal" + }, + "toggle_aux_panel": { + "title": "Alternar panel derecho", + "description": "Muestra u oculta el panel de información auxiliar" + }, + "new_conversation": { + "title": "Nueva conversación", + "description": "Crea una nueva pestaña de conversación en la carpeta actual" + }, + "open_folder": { + "title": "Abrir carpeta", + "description": "Abre el selector de carpetas y la carpeta en una nueva ventana" + }, + "open_settings": { + "title": "Abrir configuración", + "description": "Abre la ventana de configuración" + }, + "close_current_tab": { + "title": "Cerrar pestaña actual", + "description": "Cierra la conversación o pestaña de archivo actual" + }, + "close_all_file_tabs": { + "title": "Cerrar todas las pestañas de archivos", + "description": "Cierra todas las pestañas de archivos abiertas cuando el panel de archivos está activo" + }, + "next_tab": { + "title": "Pestaña siguiente", + "description": "Cambiar a la siguiente pestaña de conversación o archivo" + }, + "prev_tab": { + "title": "Pestaña anterior", + "description": "Cambiar a la pestaña anterior de conversación o archivo" + }, + "send_message": { + "title": "Enviar mensaje", + "description": "Enviar el mensaje actual en el cuadro de entrada" + }, + "newline_in_message": { + "title": "Nueva línea en mensaje", + "description": "Insertar una nueva línea en el cuadro de entrada" + }, + "toggle_custom_style": { + "title": "Suspender/reanudar estilo personalizado", + "description": "Vía de escape: desactiva todos los colores y el CSS personalizados, y los vuelve a activar" + } + } + }, + "SkillsSettings": { + "title": "Skills", + "description": "Selecciona una Skill a la izquierda. A la derecha se muestra una vista previa de Markdown por defecto; cambia a edición para modificar y guardar.", + "loadingAgents": "Cargando agentes compatibles con Skills...", + "emptyNoManageableAgents": "No hay agentes disponibles para gestionar Skills.", + "managedTarget": "Objetivo gestionado", + "selectAgentPlaceholder": "Selecciona un agente", + "searchPlaceholder": "Buscar por nombre / ID / ruta...", + "skillsList": "Lista de Skills", + "loadingSkills": "Cargando Skills...", + "agentNotSupported": "El agente actual no admite gestión de Skills.", + "emptySkills": "Aún no hay Skills. Haz clic en \"Nueva Skill\" para crear una.", + "newSkillTitle": "Nueva Skill", + "skillInfo": "Información de la Skill", + "skillIdPlaceholder": "skill-id (letras/números/-/_/.)", + "skillsDirectoryWithPath": "Directorio de Skills: {path}", + "skillsDirectoryNeedId": "Directorio de Skills: introduce el ID de Skill para generar la ruta completa", + "markdownContent": "Contenido Markdown", + "editingStatus": "Editando", + "previewStatus": "Vista previa", + "contentPlaceholder": "Introduce el contenido Markdown de la Skill...", + "metadataTitle": "Metadatos de Skills", + "onlyYamlMetadata": "Esta Skill solo contiene metadatos YAML.", + "emptyContentHint": "Aún no hay contenido. Haz clic en \"Editar\" para empezar.", + "loadingSkill": "Cargando Skill...", + "emptyNoAgents": "No hay agentes disponibles.", + "noSelectionHint": "Selecciona un Skill a la izquierda o haz clic en \"Nuevo Skill\" para crear uno.", + "systemBadge": "Sistema", + "systemHint": "Skill integrado del CLI · solo lectura", + "scope": { + "global": "Global", + "folder": "Carpeta", + "selectFolderPlaceholder": "Seleccionar una carpeta", + "noFolders": "No se encontraron carpetas", + "pickFolderHint": "Selecciona una carpeta para ver sus Skills." + }, + "actions": { + "preview": "Vista previa", + "edit": "Editar", + "openInWindow": "Abrir en nueva ventana", + "delete": "Eliminar", + "deleting": "Eliminando...", + "refresh": "Actualizar", + "newSkill": "Nueva Skill", + "reset": "Restablecer", + "save": "Guardar", + "saving": "Guardando...", + "cancel": "Cancelar" + }, + "deleteDialog": { + "title": "Eliminar Skill", + "confirm": "¿Eliminar la Skill actual? Esta acción no se puede deshacer.", + "confirmWithNamePrefix": "¿Eliminar la Skill", + "confirmWithNameSuffix": "? Esta acción no se puede deshacer." + }, + "toasts": { + "loadFailed": "No se pudo cargar la Skill", + "openFolderFailed": "No se pudo abrir la carpeta", + "noSkillDirectory": "No se encontró un directorio de Skills disponible para el agente actual", + "nameRequired": "El nombre de la Skill no puede estar vacío", + "updated": "Skill actualizada", + "created": "Skill creada", + "saveFailed": "No se pudo guardar la Skill", + "deleted": "Skill eliminada", + "deleteFailed": "No se pudo eliminar la Skill" + }, + "templates": { + "gemini": "---\nname: example-skill\ndescription: Describe when this skill should be used.\n---\n\n# Skill Name\n\nInstructions for the agent when this skill is active.\n\n## Workflow\n\n1. Add actionable step one.\n2. Add actionable step two.\n", + "openCode": "---\nname: example-skill\ndescription: Describe when this skill should be used.\n---\n\n# Purpose\n\nDescribe what this skill helps with.\n\n# Steps\n\n1. Add actionable step one.\n2. Add actionable step two.\n", + "openClaw": "---\nname: example-skill\ndescription: Describe when this skill should be used.\nuser-invocable: true\ndisable-model-invocation: false\n---\n\n# Purpose\n\nDescribe what this skill helps with.\n\n# Instructions\n\n1. Add actionable instruction one.\n2. Add actionable instruction two.\n", + "default": "---\nname: example-skill\ndescription: Describe when this skill should be used.\n---\n\n# Skill: example-skill\n\n## When to use\n\n- Describe trigger conditions.\n\n## Instructions\n\n1. Add actionable instruction one.\n2. Add actionable instruction two.\n" + } + }, + "McpSettings": { + "loading": "Cargando...", + "summary": { + "missingCommand": "(comando faltante)", + "missingUrl": "(URL faltante)" + }, + "protocol": { + "stdio": "Stdio" + }, + "errors": { + "selectInstallProtocol": "Selecciona un protocolo de instalación", + "fieldRequired": "{field} es obligatorio", + "fieldNeedsBoolean": "{field} debe ser true o false", + "fieldNeedsNumber": "{field} debe ser un número", + "fieldNeedsInteger": "{field} debe ser un entero", + "fieldInvalidJson": "{field} tiene JSON inválido: {message}", + "fieldOutOfRange": "El valor de {field} está fuera del rango permitido", + "jsonEmpty": "{name} no puede estar vacío", + "jsonInvalid": "{name} no es un JSON válido: {message}", + "jsonMustBeObject": "{name} debe ser un objeto JSON", + "specMustBeObject": "La configuración de MCP debe ser un objeto JSON.", + "missingType": "Falta el campo type en la configuración de MCP. Indica uno de stdio, http (alias: streamable-http, streamableHttp), sse.", + "unsupportedType": "Tipo de MCP no admitido {type}. Compatibles: stdio, http (alias: streamable-http, streamableHttp), sse.", + "codexEntryUnsupportedType": "La entrada Codex MCP {id} tiene un tipo no admitido {type}. Compatibles: stdio, http (alias: streamable-http, streamableHttp), sse.", + "unsupportedTransportType": "Tipo de transport no admitido {type}. Compatibles: http (alias: streamable-http, streamableHttp), sse.", + "stdioCommandRequired": "Los MCP stdio requieren un campo command no vacío.", + "remoteUrlRequired": "Los MCP remotos requieren un campo url no vacío.", + "appsRequired": "Selecciona al menos una aplicación de destino." + }, + "jsonNames": { + "localConfig": "Configuración MCP", + "installConfig": "Configuración de instalación" + }, + "toasts": { + "uninstalled": "MCP desinstalado", + "uninstallFailed": "Error al desinstalar: {message}", + "selectAtLeastOneApp": "Selecciona al menos una app de destino", + "saveSuccess": "Guardado", + "saveFailed": "Error al guardar: {message}", + "installed": "{name} instalado", + "installFailed": "Error al instalar: {message}", + "serverIdRequired": "Server ID es obligatorio", + "serverIdExists": "El Server ID \"{id}\" ya existe. Edita la entrada existente o usa un nombre diferente.", + "created": "MCP creado" + }, + "installDialog": { + "title": "Confirmar instalación de MCP", + "descriptionWithName": "Instalar {name} en la configuración local.", + "description": "Selecciona las apps de destino para la instalación.", + "protocol": "Protocolo", + "selectProtocol": "Seleccionar protocolo", + "parameters": "Parámetros de configuración", + "booleanPlaceholder": "Selecciona true/false", + "selectOneValue": "Selecciona un valor", + "targetApps": "Apps de destino" + }, + "actions": { + "cancel": "Cancelar", + "confirmInstall": "Confirmar instalación", + "installing": "Instalando", + "uninstall": "Desinstalar", + "uninstalling": "Desinstalando", + "viewDetails": "Ver detalles", + "save": "Guardar", + "saving": "Guardando", + "install": "Instalar", + "refresh": "Actualizar", + "newMcp": "Nuevo MCP", + "create": "Crear", + "creating": "Creando..." + }, + "tabs": { + "local": "MCP local", + "market": "Marketplace MCP" + }, + "local": { + "filterPlaceholder": "Filtrar MCP local...", + "loadFailed": "Error de carga: {message}", + "empty": "No se detectó MCP local.", + "description": "La configuración de MCP local se puede editar y guardar directamente.", + "enabledApps": "Apps habilitadas", + "configJson": "Configuración MCP (JSON)", + "draftTitle": "Nuevo MCP", + "draftDescription": "Indica un Server ID y la configuración para crear un servidor MCP local.", + "serverIdLabel": "Server ID", + "serverIdPlaceholder": "Server ID (p. ej. my-mcp)", + "typeHint": "Tipos admitidos: stdio, http (alias: streamable-http, streamableHttp), sse. env solo se usa con stdio; para MCP remotos usa headers para llevar tokens de autenticación.", + "envOnRemoteWarning": "Se detectó env en un MCP remoto. Solo stdio usa env; los MCP remotos llevan los tokens de autenticación en headers, así que env se ignorará al guardar." + }, + "market": { + "selectMarketplace": "Seleccionar marketplace", + "searchPlaceholder": "Buscar MCP...", + "searchFailed": "Error de búsqueda: {message}", + "loadingList": "Cargando lista de MCP...", + "empty": "Sin resultados de MCP.", + "loadingDetail": "Cargando detalles del marketplace...", + "detailLoadFailed": "No se pudieron cargar los detalles: {message}", + "owner": "Propietario: {owner}", + "namespace": "Espacio de nombres: {namespace}", + "defaultInstallProtocol": "Protocolo de instalación predeterminado", + "currentOptionParameterCount": "Cantidad de parámetros de la opción actual: {count}", + "installConfigDescription": "Configuración de instalación (JSON, editable antes de instalar; las ediciones sobrescribirán el formulario de protocolo/parámetros)", + "selectLeftToView": "Selecciona un MCP del marketplace a la izquierda para ver detalles." + }, + "badges": { + "verified": "Verificado", + "remote": "Remoto", + "hasHomepage": "Tiene página web", + "uses": "{count} usos", + "deployed": "Desplegado", + "notDeployed": "No desplegado" + }, + "selectLeftMcp": "Selecciona un MCP a la izquierda." + }, + "AcpAgentSettings": { + "title": "Gestión del SDK de agentes", + "description": "Gestiona en un solo lugar la conexión del SDK de agentes, estado habilitado, variables de entorno, gestión de configuración e información de preflight de versión.", + "loadingAgents": "Cargando lista de agentes...", + "agentList": "Lista de agentes", + "emptyNoAgent": "No hay agentes disponibles.", + "configManagement": "Gestión de configuración", + "envVars": "Variables de entorno", + "hostTools": { + "label": "Dejar que el agente gestione archivos y comandos", + "description": "codeg deja de atender el acceso a archivos y los comandos de terminal, de modo que el agente los ejecuta en su propio proceso, donde sí se aplican su sandbox y sus reglas de permisos. También se desactiva la delegación a otros agentes, ya que devolvería ese mismo trabajo a codeg. codeg no añade ningún sandbox propio, así que actívalo solo si el agente tiene uno configurado." + }, + "nativeJsonConfig": "Configuración JSON nativa", + "modelHintDefault": "Déjalo vacío para usar el modelo predeterminado del sistema.", + "generalConfigDescriptionClaude": "Admite configuración rápida de API URL, API Key y modelos de Claude, y sincroniza con la configuración JSON nativa.", + "generalConfigDescriptionDefault": "Admite entrada de configuración importante (API URL, API Key, Model) y gestión de configuración JSON nativa.", + "multiAgent": { + "title": "Colaboración multiagente", + "description": "Permite que los agentes activos deleguen subtareas a otros agentes.", + "enable": "Activar delegación", + "enableHint": "Cuando está desactivado, la herramienta delegate_to_agent se oculta del catálogo de herramientas MCP del agente.", + "withheldByHostTools": "{agents} no recibirán las herramientas de delegación: su interruptor por agente «Deja que el agente gestione archivos y comandos» está activado.", + "selfInitiate": "Allow spawn without @", + "selfInitiateHint": "When on, an agent may start a listed sub-agent on its own. An @ mention is still always honored. When off, only an @ mention starts a sub-agent.", + "depthLimit": "Profundidad máxima de delegación", + "depthHint": "Rango permitido: {min}–{max}. Limita la profundidad de recursión de una cadena de delegación (raíz → hijo → nieto …).", + "completedCacheLabel": "Caché de resultados completados (MB)", + "completedCacheHint": "Caché en memoria de los resultados completados de subagentes, que se conserva solo mientras la sesión de delegación está en ejecución y se libera automáticamente cuando esa sesión termina. Al superar este presupuesto, los resultados más antiguos se descartan primero de la memoria (aún visibles en la sesión propia del subagente); 0 = sin límite (igualmente se libera al terminar la sesión).", + "save": "Guardar", + "saving": "Guardando…", + "saved": "Configuración de delegación guardada", + "saveFailed": "Error al guardar la configuración de delegación", + "loadFailed": "Error al cargar la configuración de delegación: {detail}", + "tabGeneral": "General", + "tabAgentDefaults": "Valores por defecto del agente", + "agentDefaultsDescription": "Anulaciones por agente que se aplican cuando Colaboración multiagente inicia un subagente para una llamada de delegación. Las opciones mostradas provienen de un sondeo en vivo: lo que selecciones es exactamente lo que el agente aceptará.", + "probing": "Cargando las opciones disponibles del agente…", + "probeFailed": "Error al cargar las opciones: {detail}", + "retry": "Reintentar", + "noConfigAvailable": "Este agente no tiene opciones configurables.", + "modeLabel": "Modo", + "agentDefaultHint": "Predeterminado del agente: {value}", + "defaultOptionLabel": "Predeterminado ({value})" + }, + "actions": { + "dragSort": "Arrastrar para reordenar", + "dragSortAgent": "Arrastrar para reordenar {name}", + "refreshCheck": "Actualizar comprobación", + "refreshCheckAgent": "Actualizar comprobación de {name}", + "clickEnable": "Haz clic para habilitar {name}", + "clickDisable": "Haz clic para deshabilitar {name}", + "install": "Instalar", + "upgrade": "Actualizar", + "uninstall": "Desinstalar", + "uninstalling": "Desinstalando...", + "saveEnvVars": "Guardar variables de entorno", + "saving": "Guardando...", + "saveGrokConfig": "Guardar configuración de Grok", + "saveCodexConfig": "Guardar configuración de Codex", + "saveGeminiConfig": "Guardar configuración de Gemini", + "saveOpenCodeConfig": "Guardar configuración de OpenCode", + "saveOpenClawConfig": "Guardar configuración de OpenClaw", + "saveConfigManagement": "Guardar gestión de configuración", + "saveCurrentProvider": "Guardar proveedor actual", + "showApiKey": "Mostrar API Key", + "hideApiKey": "Ocultar API Key", + "showKey": "Mostrar clave", + "hideKey": "Ocultar clave", + "showToken": "Mostrar token", + "hideToken": "Ocultar token", + "cancel": "Cancelar", + "delete": "Eliminar", + "deleting": "Eliminando...", + "confirmDelete": "Confirmar eliminación", + "confirmUninstall": "Confirmar desinstalación", + "saveClineConfig": "Guardar configuración de Cline", + "saveHermesConfig": "Guardar configuración de Hermes", + "saveCodeBuddyConfig": "Guardar configuración de CodeBuddy", + "saveKimiCodeConfig": "Guardar configuración de Kimi Code", + "customInstall": "Instalación personalizada", + "saveKimiCodeRawConfig": "Save config.toml", + "saveDeepSeekConfig": "Guardar configuración de DeepSeek", + "diagnose": "Diagnosticar" + }, + "status": { + "enabled": "Habilitado", + "disabled": "Deshabilitado", + "unchecked": "Sin comprobar", + "agentEnabledAria": "{name} habilitado", + "agentEnabledSwitch": "Interruptor de habilitación de {name}" + }, + "preflight": { + "count": "Elementos de preflight: {count}", + "notRun": "Las comprobaciones aún no se han ejecutado." + }, + "grok": { + "configDescription": "Configura Grok aquí. Los controles siguientes —modo de permisos, esfuerzo de razonamiento, un modelo personalizado opcional (endpoint propio) y la compactación— se combinan en ~/.grok/config.toml, conservando tus otras claves y comentarios. El inicio de sesión usa tu XAI_API_KEY o `grok login`. Las demás claves siguen siendo editables en Avanzado.", + "permissionModeLabel": "Modo de permisos", + "permissionDefault": "Preguntar siempre", + "permissionAcceptEdits": "Aprobar ediciones automáticamente", + "permissionAuto": "Aprobación automática inteligente", + "permissionAlwaysApprove": "Aprobar siempre", + "reasoningEffortLabel": "Esfuerzo de razonamiento", + "effortLow": "Bajo (más rápido)", + "effortMedium": "Medio (equilibrado)", + "effortHigh": "Alto", + "effortXhigh": "Máximo", + "optionDefault": "Usar predeterminado", + "authTitle": "Autenticación", + "authMode": "Método de autenticación", + "authModeApiKey": "Clave de API de XAI", + "authModeApiKeyHint": "Autentícate con una XAI_API_KEY de la consola de xAI, para ejecuciones no interactivas o headless. Se guarda en el entorno de este agente.", + "authModeCustom": "Endpoint personalizado", + "authModeCustomHint": "Usa un endpoint propio (BYO): define abajo un modelo personalizado con su propia base URL y clave de API. Se convierte en el modelo predeterminado de Grok.", + "subscriptionHint": "Inicia sesión con `grok login` (SuperGrok / X Premium+). No se guarda ninguna clave de API.", + "loginHint": "Ejecuta esto en una terminal para iniciar sesión y luego vuelve a abrir esta configuración:", + "commandCopied": "Comando copiado al portapapeles", + "copyCommand": "Copiar comando", + "authKeyConfigured": "XAI_API_KEY está configurada.", + "authKeyMissing": "No hay XAI_API_KEY configurada.", + "advancedToggle": "Avanzado (config.toml sin procesar)", + "configTomlNative": "config.toml (nativo)", + "configTomlHint": "Se guarda literalmente como todo el ~/.grok/config.toml. El TOML no válido se rechaza para que una errata no trunque tu archivo.", + "configTomlPlaceholder": "# Claves distintas de los controles de arriba, p. ej.\n# [mcp_servers.*], [cli], reglas [permission].", + "customModelTitle": "Modelo personalizado (endpoint propio)", + "customModelHint": "Apunta Grok a un endpoint personalizado o autoalojado. codeg escribe un bloque `[model.*]` por modelo y lo establece como predeterminado. Deja el ID de modelo vacío para eliminarlo.", + "customModelIdLabel": "ID del modelo", + "customModelIdPlaceholder": "grok-4.5", + "customModelIdHint": "Se registra como un bloque `[model.*]` y se envía a la API como nombre del modelo; también se establece como `[models].default`.", + "customBaseUrlLabel": "URL base", + "customBaseUrlPlaceholder": "https://api.x.ai/v1 (predeterminado)", + "customApiBackendLabel": "Backend de la API", + "backendResponses": "Responses", + "backendChatCompletions": "Chat Completions", + "backendMessages": "Messages (Anthropic)", + "customApiKeyLabel": "Clave de API", + "customApiKeyHint": "Se guarda en línea en `[model.*].api_key`, limitada a este endpoint.", + "customContextWindowLabel": "Ventana de contexto (tokens)", + "customContextWindowHint": "Opcional. Determina el momento de la autocompactación; déjalo vacío para el valor predeterminado del endpoint.", + "autoCompactLabel": "Umbral de autocompactación (%)", + "autoCompactHint": "Compacta la conversación cuando el uso del contexto alcanza este porcentaje (predeterminado de Grok: 85). Se escribe en `[session]`." + }, + "cursor": { + "configDescription": "Configura Cursor aquí. Elige un método de autenticación —suscripción oficial (inicio de sesión en el navegador) o una clave API de Cursor para equipos sin interfaz o servidores— y luego elige un modelo y edita las reglas de permisos y el sandbox del CLI. codeg los escribe en ~/.cursor/cli-config.json, compartido con el CLI cursor-agent.", + "authTitle": "Autenticación", + "authChecking": "Comprobando…", + "authNotInstalled": "cursor-agent no está instalado", + "authLoggedIn": "Sesión iniciada", + "authNotLoggedIn": "Sin sesión", + "loginHint": "Ejecuta esto en una terminal para iniciar sesión con tu cuenta de Cursor (se abre el navegador) y luego pulsa actualizar:", + "apiKeyLabel": "Clave API de Cursor", + "apiKeyPlaceholder": "clave de cursor.com/dashboard", + "apiKeyHint": "CURSOR_API_KEY: una clave de cuenta del panel de Cursor, alternativa al inicio de sesión en el navegador para equipos sin interfaz o servidores. No es una clave de terceros ni de OpenAI.", + "modelTitle": "Modelo predeterminado", + "loadModels": "Cargar modelos", + "modelsUnavailable": "Lista de modelos no disponible", + "modelHint": "Se pasa a la CLI como --model al iniciar la sesión. Déjalo en predeterminado para que Cursor elija.", + "permissionsTitle": "Permisos y sandbox", + "permissionsDescription": "Editor visual de las reglas de permisos de la CLI (cli-config.json). Las reglas permitidas se ejecutan sin confirmación; las denegadas se bloquean siempre.", + "permissionModeLabel": "Modo de permisos", + "permissionModeDefault": "Preguntar antes de ejecutar (predeterminado)", + "permissionModeForce": "Run Everything (--force)", + "permissionModeHint": "Run Everything inicia las sesiones con --force: todas las llamadas de herramientas se permiten automáticamente salvo las reglas de denegación, sin confirmaciones (una política de la organización puede limitarlo a las reglas de permiso). Se aplica a las sesiones nuevas.", + "optionDefault": "Predeterminado (sin definir)", + "sandboxLabel": "Sandbox", + "sandboxEnabled": "Activado", + "sandboxDisabled": "Desactivado", + "allowRulesLabel": "Reglas permitidas", + "denyRulesLabel": "Reglas denegadas", + "addRule": "Añadir regla", + "rulesSyntaxHint": "Sintaxis de reglas: Shell(cmd), Read(ruta/glob), Write(ruta/glob), WebFetch(dominio), Mcp(servidor:herramienta) — las reglas de denegación siempre prevalecen.", + "saveConfig": "Guardar configuración", + "advancedToggle": "Avanzado: cli-config.json sin procesar", + "advancedHint": "El ~/.cursor/cli-config.json completo. Guardar escribe el archivo tal cual; los controles estructurados de arriba se fusionan en él.", + "saveRawConfig": "Guardar archivo", + "authMode": "Método de autenticación", + "subscriptionHint": "Inicia sesión con tu cuenta de Cursor y usa los modelos de Cursor.", + "customApiKeyRequired": "Se requiere una clave API de Cursor.", + "authModeApiKey": "Clave API de Cursor (sin interfaz)", + "authModeApiKeyHint": "Autentícate con una clave API de cuenta de Cursor generada en el panel de Cursor (para equipos sin interfaz o servidores). Es una clave de cuenta de Cursor, no un endpoint de terceros/OpenAI: cursor-agent solo se comunica con el backend de Cursor. Para usar un endpoint compatible con codex/OpenAI, usa el agente Codex en su lugar.", + "modelPickerPlaceholder": "Buscar modelos…", + "modelNoMatch": "Ningún modelo coincide", + "modelsNeedAuth": "Inicia sesión para cargar la lista de modelos.", + "modelDefaultBadge": "predeterminado" + }, + "deepseek": { + "configManagement": "Configuración de DeepSeek Harness", + "configDescription": "El endpoint y la clave son variables de entorno que deepseek-acp lee al arrancar. El modelo y el esfuerzo de razonamiento son selectores por sesión: se eligen en el campo de mensaje.", + "baseUrlLabel": "Endpoint de la API", + "baseUrlHint": "Déjalo vacío para el endpoint oficial. Se aplica a las sesiones iniciadas tras guardar; vuelve a conectar una sesión en curso para que lo tome.", + "baseUrlInvalid": "Introduce una URL http(s) completa y sin cadena de consulta, por ejemplo https://api.deepseek.com", + "apiKeyLabel": "Clave de API", + "apiKeyHint": "Se pasa al agente como DEEPSEEK_API_KEY. Una variable de entorno tiene prioridad sobre el archivo de credenciales, así que déjala vacía si inicias sesión desde la terminal." + }, + "codex": { + "configDescription": "Admite configuración rápida de URL de API, API Key, nombre del modelo y reasoning effort, y sincroniza con `auth.json` / `config.toml`.", + "authMode": "Modo de Autenticación", + "chatgptSubscription": "Suscripción oficial", + "chatgptSubscriptionHint": "Iniciar sesión con suscripción oficial de ChatGPT, sin necesidad de API Key", + "apiKeyHint": "Conectar usando API Key a OpenAI o servicios API compatibles", + "selectProvider": "Seleccionar proveedor", + "modelName": "Nombre del modelo", + "selectReasoningEffort": "Seleccionar Reasoning Effort", + "enableWebsocket": "Habilitar WebSocket", + "enableWebsocketAria": "Habilitar WebSocket para Codex Provider", + "enableSkills": "Habilitar Skills", + "enableSkillsAria": "Habilitar Skills para Codex", + "enableFast": "Habilitar Fast", + "enableFastAria": "Habilitar nivel de servicio Fast para Codex", + "sandboxGroupTitle": "Sandbox y aprobaciones", + "sandboxGroupHint": "Se escribe en el ~/.codex/config.toml global, por lo que también lo ven las sesiones de codex CLI e IDE. Son valores predeterminados del hilo: rigen los turnos que codex inicia por su cuenta (/goal, /review, /compact). Los mensajes normales usan el preajuste de aprobación del compositor. Reinicia una sesión para aplicar los cambios.", + "sandboxShadowedWarning": "config.toml define default_permissions, así que codex resuelve los permisos con ese perfil e ignora sandbox_mode por completo. Elimina default_permissions para usar los controles de abajo.", + "sandboxPermissionsTableWarning": "config.toml define perfiles [permissions] pero no default_permissions, lo que impide que codex arranque. Configúralo en el editor sin formato de abajo.", + "approvalPolicyLabel": "Política de aprobación", + "approvalPolicyUnset": "Sin definir (predeterminado de codex: a petición)", + "approvalPolicy_on-request": "A petición: el modelo decide cuándo preguntar", + "approvalPolicy_untrusted": "No confiable: solo se ejecutan sin supervisión los comandos de solo lectura seguros", + "approvalPolicy_never": "Nunca: sin ninguna solicitud de aprobación", + "approvalPolicy_granular": "Granular: elige por tipo de solicitud", + "approvalPolicyUntrustedAcpWarning": "Untrusted no tiene equivalente entre los tres ajustes de aprobación del adaptador ACP, así que las sesiones de codeg recurren a «a petición»: el modelo decide entonces cuándo preguntar y los comandos que la zona aislada ya permite dejan de pedir confirmación. Restringe mejor el modo de aislamiento de abajo.", + "granularHint": "Desactivado significa que ese tipo de solicitud se rechaza automáticamente en vez de mostrártela.", + "granular_sandbox_approval": "Escalados de comandos de shell", + "granular_rules": "Avisos de reglas de execpolicy", + "granular_skill_approval": "Avisos de scripts de habilidades", + "granular_request_permissions": "Avisos de la herramienta request_permissions", + "granular_mcp_elicitations": "Avisos de elicitación MCP", + "sandboxModeLabel": "Modo de sandbox", + "sandboxModeUnset": "Sin definir (las carpetas de confianza usan escritura en el espacio de trabajo)", + "sandboxMode_read-only": "Solo lectura", + "sandboxMode_workspace-write": "Escritura en el espacio de trabajo", + "sandboxMode_danger-full-access": "Acceso total (sin sandbox)", + "sandboxModeHint": "En Windows, la escritura en el espacio de trabajo baja a solo lectura salvo que actives el sandbox experimental de Windows de codex.", + "sandboxModeSeedsPresetHint": "codeg también lo traduce al ajuste de aprobación inicial de la sesión, así que —a diferencia de la política de aprobación— sí afecta a las peticiones normales. El ajuste elegido en el editor sigue teniendo prioridad.", + "writableRootsLabel": "Carpetas adicionales con escritura", + "writableRootsHint": "Una ruta absoluta por línea, además del directorio de trabajo.", + "sandboxRootsRelativeError": "Debe ser una ruta absoluta: codex resuelve las rutas relativas dentro de ~/.codex: {path}", + "networkAccessLabel": "Permitir acceso a la red", + "excludeTmpdirLabel": "Excluir TMPDIR de las raíces con escritura", + "excludeSlashTmpLabel": "Excluir /tmp de las raíces con escritura", + "authJsonNative": "auth.json (nativo)", + "configTomlNative": "config.toml (nativo)", + "loginButton": "Iniciar sesión con ChatGPT", + "loginRequesting": "Solicitando código de inicio de sesión...", + "loginStep1": "Abre la siguiente URL en tu navegador:", + "loginStep2": "Introduce el siguiente código:", + "loginPolling": "Esperando autorización...", + "loginCancel": "Cancelar", + "loginSuccess": "¡Inicio de sesión exitoso, configuración guardada!", + "loginFailed": "Error de inicio de sesión: {message}", + "loginRetry": "Reintentar", + "loginCodeCopied": "Código copiado", + "loggedIn": "Cuenta conectada", + "loginRelogin": "Reconectar / Cambiar cuenta", + "loginTimeout": "Tiempo de inicio de sesión agotado, inténtalo de nuevo", + "loginSaveFailed": "Inicio de sesión exitoso pero falló al guardar la configuración" + }, + "gemini": { + "authConfig": "Configuración de autenticación de Gemini", + "authConfigDescription": "Alineado con la documentación de autenticación de Gemini CLI, con soporte para endpoint personalizado, inicio de sesión de Google, Gemini API Key y Vertex AI (ADC / cuenta de servicio / API Key).", + "authMode": "Modo de autenticación", + "selectAuthMode": "Seleccionar modo de autenticación", + "viewAuthDoc": "Ver documentación de autenticación", + "mode": { + "custom": "Endpoint personalizado", + "loginGoogle": "Inicio de sesión de Google (OAuth)", + "vertexServiceAccount": "Vertex AI (Cuenta de servicio)" + }, + "hint": { + "custom": "Completa API URL, API Key y Modelo; se mapean a GOOGLE_GEMINI_BASE_URL / GEMINI_API_KEY / GEMINI_MODEL.", + "loginGoogle": "Ejecuta gemini en terminal y completa primero el inicio de sesión de Google; no se requiere API key.", + "geminiApiKey": "Completa GEMINI_API_KEY cuando uses la API de Gemini.", + "vertexAdc": "Usa gcloud ADC; se recomienda configurar GOOGLE_CLOUD_PROJECT y GOOGLE_CLOUD_LOCATION.", + "vertexServiceAccount": "Establece la ruta del JSON de la cuenta de servicio en GOOGLE_APPLICATION_CREDENTIALS.", + "vertexApiKey": "Completa GOOGLE_API_KEY cuando uses API key de Vertex AI." + } + }, + "openCode": { + "configManagement": "Gestión de configuración de OpenCode", + "configDescription": "Alineado con el esquema `provider` de OpenCode, admite gestión de múltiples proveedores y sincronización bidireccional con archivos JSON nativos.", + "providerManagement": "Gestión de proveedores", + "providerCount": "{count} proveedores", + "addProvider": "Agregar proveedor", + "emptyProvider": "Aún no hay proveedores personalizados. Haz clic en Agregar proveedor personalizado para crear uno.", + "providerEnabledState": "Estado habilitado de {providerId}", + "selectProviderNpm": "Seleccionar provider.npm", + "modelManagement": "Gestión de modelos", + "modelCount": "{count} modelos", + "modelDescription": "Alineado con `provider.models` de OpenCode. La gestión rápida actualmente soporta `name` / `id`; otros campos avanzados se conservan y se pueden editar en el JSON nativo de abajo.", + "addModel": "Agregar modelo", + "emptyModel": "Aún no hay modelo. Introduce model id y haz clic en \"Agregar modelo\".", + "modelId": "ID de modelo", + "modelName": "Nombre del modelo", + "deleteModel": "Eliminar modelo {modelId}", + "nativeJsonConfig": "Configuración JSON nativa de OpenCode", + "mainModel": "Modelo principal", + "smallModel": "Modelo pequeño", + "noMatchingModels": "No hay modelos coincidentes", + "connectProvider": "Conectar proveedor", + "connectedProviders": "Proveedores conectados", + "noConnectedProviders": "Aún no hay proveedores del catálogo conectados.", + "advancedProviderConfig": "Proveedores personalizados", + "customProviderConfigHint": "Endpoints compatibles con OpenAI que defines tú mismo: un bloque de provider en opencode.json, con la API key en auth.json.", + "addCustomProvider": "Agregar proveedor personalizado", + "disconnect": "Desconectar", + "editConfig": "Editar", + "customBadge": "Personalizado", + "authKindApi": "Clave API", + "authKindOauth": "OAuth", + "authKindNone": "Sin credencial", + "connect": { + "title": "Conectar un proveedor", + "description": "Elige un proveedor del catálogo de models.dev. Las credenciales se guardan en el archivo auth.json de OpenCode.", + "pick": "Proveedor", + "search": "Buscar proveedores…", + "loading": "Cargando catálogo…", + "catalogLabel": "Catálogo de models.dev", + "modelsAvailable": "{count} modelos disponibles", + "getKey": "Obtener clave API", + "oauthApiKeyNote": "Este proveedor también admite el inicio de sesión por navegador con opencode auth login. El inicio por navegador llegará pronto; por ahora, pega una clave API.", + "apiKey": "Clave API", + "apiKeyHint": "Se guarda en auth.json, nunca en opencode.json.", + "baseUrlOptional": "Anular Base URL (opcional)", + "providerId": "ID del proveedor", + "displayName": "Nombre visible", + "modelsList": "Modelos (uno por línea)", + "modelsHint": "IDs de modelo que acepta el endpoint.", + "action": "Conectar", + "editTitle": "Editar proveedor", + "editDescription": "Actualiza la clave API o la Base URL de este proveedor.", + "saveAction": "Guardar" + }, + "customProvider": { + "title": "Agregar un proveedor personalizado", + "description": "Define un endpoint compatible con OpenAI. La API key se guarda en auth.json; el bloque de provider va a opencode.json.", + "action": "Agregar proveedor", + "idInCatalog": "{providerId} es un proveedor conocido: conéctalo mediante Conectar proveedor." + }, + "refreshCatalog": "Actualizar catálogo", + "reasoningBadge": "razonamiento", + "contextWindow": "Ventana de contexto", + "permissions": { + "title": "Permisos", + "description": "Decide qué acciones se ejecutan solas, cuáles te preguntan primero y cuáles se bloquean. Se escribe en el bloque permission de opencode.json y se aplica al guardar abajo.", + "docsLink": "Documentación de permisos", + "unparsableConfig": "El JSON nativo de abajo no es válido, así que el editor visual está pausado. Corrige el JSON para continuar.", + "invalidBlock": "El bloque permission tiene una forma que codeg no reconoce. Edítalo en el JSON nativo de abajo o usa Restablecer para empezar de nuevo.", + "orderingUnsafe": "Hay una regla comodín escrita después de herramientas concretas, así que OpenCode también se la aplica a ellas: las filas de abajo no son lo que está en vigor. Corregir orden solo devuelve cada comodín al principio de su ámbito, sin cambiar ningún valor.", + "orderingUnsafeManual": "Una regla queda tapada por un patrón posterior más general, así que OpenCode nunca la aplica: las filas de abajo no son lo que está en vigor. Dos patrones que se solapan no tienen un único orden correcto; reordénalos en el JSON nativo para que el más general vaya primero.", + "fixOrder": "Corregir orden", + "agentOverrides": "Estos agentes anulan los permisos y se aplican al final, así que ganan sobre todo lo de aquí: {agents}. Edítalos en el JSON nativo de abajo o activa el aceptar automático para borrarlos.", + "legacyTools": "El mapa tools heredado del nivel superior deniega una herramienta. OpenCode lo fusiona con los permisos, así que se aplica por encima de todo lo que se ve aquí. Edítalo en el JSON nativo de abajo o activa el aceptar automático para borrarlo.", + "autoAcceptTitle": "Aceptar todos los permisos automáticamente", + "autoAcceptHint": "Toda llamada a herramientas —comandos de shell, ediciones de archivos, rutas fuera del proyecto— se ejecuta sin preguntar. Al activarlo, los ajustes por herramienta de abajo se sustituyen por una única regla que lo permite todo, y se borran las anulaciones por agente y los conmutadores tools heredados que si no seguirían bloqueando.", + "globalLabel": "Valor global por defecto", + "globalHint": "La regla *: se aplica a todo lo que las herramientas de abajo no anulen.", + "actionUnset": "Sin definir (valores de OpenCode)", + "actionInherit": "Heredar ({action})", + "actionAllow": "Permitir", + "actionAsk": "Preguntar", + "actionDeny": "Denegar", + "perToolTitle": "Permisos por herramienta", + "reset": "Restablecer", + "ruleCount": "reglas: {count}", + "rulesToggle": "Reglas detalladas de {tool}", + "rulesHint": "Se comparan con la entrada de la herramienta y gana la última coincidencia, así que pon primero los patrones amplios. * coincide con cualquier cantidad de caracteres, ? con exactamente uno, y un ~ inicial se expande a tu carpeta personal.", + "noRules": "Todavía no hay reglas detalladas.", + "addRule": "Añadir regla", + "deleteRule": "Eliminar la regla {pattern}", + "duplicateRule": "Ese patrón ya existe.", + "blankRule": "Una regla necesita un patrón; usa el icono de papelera para eliminarla.", + "customKeys": "Otras claves de permiso del archivo", + "customKeyHint": "No es una herramienta integrada de OpenCode; se conserva tal cual.", + "keys": { + "bash": "Ejecutar comandos de shell, según el comando analizado", + "edit": "Todas las modificaciones de archivos: edit, write y patch", + "read": "Leer archivos, según la ruta", + "external_directory": "Acceder a rutas fuera del directorio de trabajo del proyecto", + "task": "Lanzar subagentes, según el tipo de subagente", + "skill": "Cargar habilidades, según su nombre", + "glob": "Buscar archivos, según el patrón glob", + "grep": "Buscar en el contenido de los archivos, según el patrón", + "list": "Listar el contenido de un directorio", + "webfetch": "Descargar una URL", + "websearch": "Buscar en la web", + "lsp": "Ejecutar consultas LSP", + "todowrite": "Escribir la lista de tareas", + "question": "Hacerte una pregunta", + "doom_loop": "Se activa cuando la misma llamada se repite tres veces con la misma entrada" + } + } + }, + "openClaw": { + "gatewayConfig": "Configuración de Gateway", + "gatewayDescription": "Configura la conexión de OpenClaw Gateway. Admite gateway local o remoto.", + "gatewayUrlHint": "Déjalo vacío para usar gateway.remote.url desde la configuración local de openclaw.", + "gatewayTokenPlaceholder": "Token de autenticación de Gateway", + "gatewayTokenHint": "Usa token-file en lugar de token en texto plano cuando sea posible; configúralo con el CLI de openclaw.", + "sessionKeyHint": "Opcional. Especifica la session key del gateway; si se deja vacío se asigna automáticamente una sesión aislada." + }, + "hermes": { + "configManagement": "Configuración de Hermes", + "configDescription": "Hermes gestiona sus propias credenciales en ~/.hermes/.env y los ajustes en ~/.hermes/config.yaml. Elige un proveedor y luego establece la clave de API y el modelo: codeg escribe ambos archivos por ti.", + "providerLabel": "Proveedor", + "providerHint": "El proveedor determina qué variable de clave de API y qué model.provider usa Hermes. Los proveedores de OAuth se configuran mediante la configuración del terminal que aparece a continuación.", + "groupApiKey": "Proveedores con clave API", + "groupOauth": "Proveedores OAuth", + "groupAws": "AWS", + "apiKeyHint": "Se guarda en ~/.hermes/.env. Nunca se inyecta en el proceso: Hermes la lee de su propia configuración.", + "modelName": "Modelo", + "oauthHint": "Este proveedor usa OAuth. Ejecuta la configuración de abajo para autenticarte en tu terminal.", + "awsHint": "Bedrock usa tus credenciales de AWS (entorno o configuración compartida). Define el ID del modelo arriba y configura el acceso a AWS en tu entorno.", + "unsupportedProvider": "Este proveedor no se puede editar con campos estructurados. Usa el editor de config.yaml de abajo o la configuración por terminal.", + "setupTitle": "Configuración autogestionada", + "setupHint": "La configuración interactiva de Hermes necesita un terminal. Iníciala abajo o copia el comando para ejecutarlo tú mismo.", + "runSetup": "Ejecutar configuración de Hermes", + "configureModel": "Configurar modelo", + "openConfigFolder": "Abrir ~/.hermes", + "copyCommand": "Copiar comando", + "commandCopied": "Comando copiado al portapapeles", + "advancedTitle": "Avanzado: editar config.yaml", + "rawConfigHint": "Edita ~/.hermes/config.yaml directamente. Guardar aquí sobrescribe el archivo tal cual.", + "saveRawConfig": "Guardar config.yaml" + }, + "codebuddy": { + "configManagement": "Configuración de CodeBuddy", + "configDescription": "CodeBuddy se autentica con una clave de API. Las versiones para China continental también requieren establecer el entorno en «China (internal)»; las versiones iOA usan «iOA». La versión internacional lo deja sin definir.", + "apiKeyLabel": "Clave de API", + "apiKeyHint": "Se guarda como CODEBUDDY_API_KEY para este agente. También puedes iniciar sesión con la CLI de CodeBuddy en una terminal.", + "apiKeyHintSelfHosted": "Se guarda como CODEBUDDY_API_KEY para este agente. Usa la clave emitida por tu implementación privada.", + "environmentLabel": "Entorno", + "environmentHint": "Establece CODEBUDDY_INTERNET_ENVIRONMENT. China continental debe usar «China (internal)»; la versión internacional lo deja sin definir.", + "envOverseas": "Internacional (predeterminado)", + "envChina": "China (internal)", + "envIoa": "iOA", + "envSelfHosted": "Autoalojado (implementación privada)", + "baseUrlLabel": "URL de implementación", + "baseUrlPlaceholder": "https://codebuddy.your-company.com", + "baseUrlHint": "Se guarda como CODEBUDDY_BASE_URL y dirige CodeBuddy a tu endpoint privado. En autoalojado, el entorno de red (CODEBUDDY_INTERNET_ENVIRONMENT) queda sin configurar.", + "baseUrlInvalid": "Introduce una URL http(s) válida.", + "loginHint": "¿No tienes clave de API? Ejecuta «codebuddy» en una terminal para iniciar sesión con tu cuenta de Tencent." + }, + "kimiCode": { + "configManagement": "Configuración de Kimi Code", + "configDescription": "`kimi acp` solo acepta un token de sesión almacenado, así que codeg escribe un proveedor gestionado en ~/.kimi-code/config.toml y siembra un token de acceso local: la inferencia sigue usando tu propia clave.", + "statusUnconfigured": "Sin configurar", + "statusDirty": "Cambios sin guardar", + "summaryLabel": "En vigor", + "gateReadyApiKey": "Clave de API escrita en config.toml", + "gateReadyLogin": "Sesión iniciada con una cuenta de Kimi", + "revealConfig": "Mostrar en la carpeta", + "envOverrideWarning": "{keys} está definido y tiene prioridad sobre config.toml. Al guardar aquí se elimina.", + "authModeLabel": "Método de autenticación", + "authModeApiKey": "Clave de API", + "authModeLogin": "Inicio de sesión de Kimi (suscripción)", + "authModeApiKeyHint": "Escribe un proveedor gestionado en config.toml y siembra el token de acceso para que las sesiones puedan abrirse.", + "loginHint": "Ejecuta `kimi login` en una terminal para iniciar sesión con una cuenta de suscripción de Kimi. codeg no guarda nada y reutiliza el inicio de sesión de Kimi. Guardar aquí elimina el token de acceso por clave de API de codeg.", + "credentialTitle": "Credencial", + "interfaceTypeLabel": "Tipo de proveedor", + "interfaceTypeHint": "El protocolo de proveedor que habla Kimi (el `type` de config.toml). Usa Kimi / Moonshot para una clave de Moonshot / platform.kimi.com.", + "endpointLabel": "Endpoint", + "endpointCustom": "Personalizado (compatible con OpenAI)", + "endpointHint": "Internacional = api.moonshot.ai; China (claves de platform.kimi.com) = api.moonshot.cn. Personalizado apunta a cualquier endpoint compatible con OpenAI.", + "regionInternational": "Internacional (api.moonshot.ai)", + "regionChina": "China (api.moonshot.cn)", + "baseUrlLabel": "URL base", + "baseUrlHint": "Déjalo en blanco para usar el valor por defecto del SDK del proveedor.", + "apiKeyLabel": "Clave de API", + "apiKeyHint": "Se escribe en ~/.kimi-code/config.toml y se usa para la inferencia. De platform.kimi.com o platform.kimi.ai.", + "vertexProjectLabel": "Proyecto de GCP (GOOGLE_CLOUD_PROJECT)", + "vertexLocationLabel": "Región de GCP (GOOGLE_CLOUD_LOCATION)", + "vertexHint": "Vertex AI usa las credenciales predeterminadas de aplicación de Google: ejecuta `gcloud auth application-default login` (sin clave de API).", + "modelTitle": "Modelo", + "modelLabel": "Modelo", + "modelHint": "El id de modelo que se escribe en config.toml. Usa «Probar y listar modelos» para ver a cuáles puede acceder tu clave.", + "maxContextLabel": "Tamaño máximo de contexto", + "maxContextHint": "Obligatorio según el esquema de Kimi: sin él, Kimi descarta todo el bloque del modelo y ninguna consulta devuelve respuesta. Por defecto 262144.", + "fetchModels": "Probar y listar modelos", + "fetchModelsOk": "La clave funciona: {count} modelos disponibles", + "fetchModelsEmpty": "La clave funciona, pero no se devolvió ningún modelo", + "fetchModelsFailed": "La prueba falló", + "fetchModelsNeedsKey": "Introduce primero una clave de API y un endpoint", + "modelNotInList": "Este modelo no está en la lista a la que tu clave puede acceder: Kimi fallará con «modelo no encontrado».", + "reasoningTitle": "Razonamiento", + "reasoningEnableLabel": "Activar", + "reasoningDescription": "Kimi solo muestra el selector «Thinking» en el cuadro de mensaje cuando el modelo declara una capacidad de razonamiento, así que codeg la escribe aquí. Se aplica a las sesiones nuevas.", + "effortsLabel": "Niveles ofrecidos", + "effortsHint": "Estos son los niveles que aparecerán en el selector «Thinking». Kimi los reenvía al proveedor tal cual, así que elige los que acepte tu modelo.", + "effortsEmptyHint": "Sin ningún nivel elegido, el cuadro de mensaje se reduce a un simple interruptor Off / On.", + "effortsCustomPlaceholder": "Añadir otro nivel", + "effortsAdd": "Añadir", + "defaultEffortLabel": "Nivel por defecto", + "defaultEffortAuto": "Que elija Kimi", + "alwaysThinkingLabel": "El modelo siempre razona: quitar la opción Off del selector", + "fixErrorsFirst": "Corrige primero los campos marcados", + "errorModelRequired": "El modelo es obligatorio", + "errorMaxContextRequired": "El tamaño máximo de contexto es obligatorio", + "errorMaxContextInvalid": "Debe ser un entero positivo", + "errorApiKeyRequired": "La clave de API es obligatoria", + "errorApiKeyInvalid": "La clave de API no puede contener saltos de línea", + "errorBaseUrlRequired": "La URL base es obligatoria", + "errorBaseUrlInvalid": "Debe empezar por http:// o https://", + "errorVertexProjectRequired": "El proyecto de GCP es obligatorio", + "errorDefaultEffortUnlisted": "Elige uno de los niveles seleccionados arriba", + "advancedTitle": "Avanzado", + "authTypeLabel": "Ubicación de la credencial", + "authTypeApiKey": "api_key en línea", + "authTypeEnv": "Subtabla env del proveedor", + "authTypeHint": "Dónde se escribe la clave de API dentro de config.toml.", + "rawEditorLabel": "Editar config.toml directamente", + "rawEditorWarning": "Guardar aquí sobrescribe el archivo completo tal cual y reemplaza la configuración estructurada de arriba.", + "rawEditorPlaceholder": "[providers.codeg]\ntype = \"kimi\"\nbase_url = \"https://api.moonshot.cn/v1\"\napi_key = \"sk-...\"" + }, + "authModeOfficialSubscription": "Suscripción oficial", + "authModeCustomEndpoint": "Endpoint personalizado", + "authModeCustomEndpointHint": "Configurar manualmente la URL de API y la clave API para un endpoint personalizado.", + "authModeModelProvider": "Proveedor de modelo", + "modelProvider": "Proveedor de modelo", + "modelProviderHint": "Usar la URL de API, la clave API y el modelo de un proveedor de modelo configurado.", + "selectModelProvider": "Seleccionar proveedor de modelo", + "noModelProviderAvailable": "No hay proveedor de modelo configurado para este agente. Vaya a la configuración de proveedores de modelo para agregar uno.", + "claude": { + "authMode": "Modo de autenticación", + "officialSubscription": "Suscripción oficial", + "officialSubscriptionHint": "Usar la suscripción oficial de Anthropic, no se requiere API Key.", + "mainModel": "Modelo principal", + "reasoningModel": "Modelo de razonamiento (thinking)", + "haikuDefaultModel": "Modelo Haiku predeterminado", + "sonnetDefaultModel": "Modelo Sonnet predeterminado", + "opusDefaultModel": "Modelo Opus predeterminado", + "customModelOption": "ID de modelo personalizado", + "customModelOptionName": "Nombre del modelo personalizado", + "customModelOptionDescription": "Descripción del modelo personalizado", + "customModelOptionHint": "Añade una única entrada personalizada al selector de modelos de Claude (por ejemplo, un modelo detrás de una pasarela/proxy personalizado). El nombre y la descripción son opcionales y solo afectan a la visualización.", + "effortLevel": "Nivel de razonamiento", + "effortLevelDefault": "Nivel predeterminado", + "effortLevel_low": "Bajo", + "effortLevel_medium": "Medio", + "effortLevel_high": "Alto", + "effortLevel_xhigh": "Extra Alto", + "sendAttributionHeader": "Enviar identificador de atribución/facturación a la API", + "sendAttributionHeaderAria": "Enviar el identificador de atribución/facturación de Claude Code a la API", + "disableNonessentialTraffic": "Desactivar la telemetría o las solicitudes de red innecesarias", + "disableNonessentialTrafficAria": "Desactivar la telemetría o las solicitudes de red innecesarias de Claude Code" + }, + "dialogs": { + "confirmDeleteProvider": "¿Eliminar proveedor {providerId}?", + "confirmDeleteProviderDescription": "La configuración de OpenCode y auth JSON se actualizarán juntos. Esta acción no se puede deshacer.", + "confirmUninstall": "¿Desinstalar {name}?", + "confirmUninstallDescription": "Esto elimina la versión instalada localmente. Puedes reinstalar más tarde.", + "customInstallTitle": "Instalación personalizada de {name}", + "customInstallDescription": "Introduce la versión que quieres instalar. Se reinstalará y reemplazará la versión instalada actualmente.", + "customInstallVersionLabel": "Número de versión", + "customInstallInvalid": "Introduce un número de versión válido, p. ej. 1.2.3.", + "customInstallSubmit": "Instalar" + }, + "errors": { + "windowsFileLocked": "Los archivos de {name} están en uso por una sesión activa, por lo que Windows no puede reemplazarlos. Cierra todas las sesiones de {name} e inténtalo de nuevo.", + "nativeJsonMustBeObject": "La configuración JSON nativa debe ser un objeto", + "nativeJsonInvalid": "Error de formato en JSON nativo: {message}", + "openCodeAuthMustBeObject": "OpenCode auth.json debe ser un objeto JSON", + "openCodeAuthInvalid": "Error de formato en OpenCode auth.json: {message}", + "authMustBeObject": "auth.json debe ser un objeto JSON", + "authInvalid": "Error de formato en auth.json: {message}", + "providerIdPattern": "El ID de proveedor solo admite letras, números, guion bajo, punto y guion", + "providerExists": "El proveedor {providerId} ya existe", + "modelIdPattern": "El ID de modelo solo admite letras, números, guion bajo, punto, dos puntos y guion", + "modelExists": "El modelo {modelId} ya existe" + }, + "warnings": { + "nativeJsonRecoveredStructured": "La configuración JSON nativa es inválida; se restableció a configuración estructurada", + "nativeJsonRecoveredOpenCode": "La configuración JSON nativa es inválida; se restableció a configuración estructurada de OpenCode", + "openCodeAuthRecovered": "OpenCode auth.json es inválido; se restableció a configuración predeterminada", + "authRecoveredStructured": "auth.json es inválido; se restableció a configuración estructurada" + }, + "toasts": { + "agentActionCompleted": "{name} {action} completado", + "agentActionFailed": "{name} {action} falló", + "localVersion": "Versión local: {version}", + "installCompletedVersionLater": "Instalación completada, la versión se actualizará en la próxima comprobación", + "uninstallCompleted": "Desinstalación de {name} completada", + "uninstallFailed": "Desinstalación de {name} fallida", + "localVersionRemoved": "Versión local eliminada", + "saveAgentOrderFailed": "No se pudo guardar el orden de Agent", + "saveAgentSwitchFailed": "No se pudo guardar el switch de Agent", + "saveEnvFailed": "No se pudieron guardar las variables de entorno", + "grokSaved": "Configuración de Grok guardada", + "saveGrokNativeFailed": "No se pudo guardar la configuración nativa de Grok", + "saveGrokApiKeyFailed": "Ajustes guardados, pero no se pudo guardar la clave API", + "cursorSaved": "Configuración de Cursor guardada", + "saveCursorConfigFailed": "Error al guardar la configuración de Cursor", + "codexSaved": "Configuración de Codex guardada", + "saveCodexNativeFailed": "No se pudo guardar la configuración nativa de Codex", + "geminiSaved": "Configuración de Gemini guardada", + "saveGeminiFailed": "No se pudo guardar la configuración de Gemini", + "providerDeleted": "Proveedor {providerId} eliminado", + "providerDeleteFailed": "No se pudo eliminar el proveedor {providerId}", + "providerSaved": "Proveedor {providerId} guardado", + "saveProviderFailed": "No se pudo guardar el proveedor {providerId}", + "openCodeConfigSynced": "La configuración de OpenCode y auth JSON se sincronizaron.", + "openCodeSaved": "Configuración de OpenCode guardada", + "saveOpenCodeFailed": "No se pudo guardar la configuración de OpenCode", + "openClawSaved": "Configuración de OpenClaw guardada", + "saveOpenClawFailed": "No se pudo guardar la configuración de OpenClaw", + "configSaved": "Configuración guardada", + "configSavedHint": "Las sesiones existentes deben reabrirse para que surta efecto", + "saveConfigManagementFailed": "No se pudo guardar la gestión de configuración", + "clineSaved": "Configuración de Cline guardada", + "saveClineFailed": "Error al guardar la configuración de Cline", + "hermesSaved": "Configuración de Hermes guardada", + "saveHermesFailed": "Error al guardar la configuración de Hermes", + "codeBuddySaved": "Configuración de CodeBuddy guardada", + "saveCodeBuddyFailed": "No se pudo guardar la configuración de CodeBuddy", + "kimiCodeSaved": "Configuración de Kimi Code guardada", + "saveKimiCodeFailed": "Error al guardar la configuración de Kimi Code", + "deepseekSaved": "Configuración de DeepSeek guardada", + "saveDeepSeekFailed": "No se pudo guardar la configuración de DeepSeek", + "modelProviderRequired": "Seleccione un proveedor de modelo antes de guardar.", + "affectedRunningSessions": "{count, plural, one {# sesión activa necesita reconectarse para aplicar el cambio} other {# sesiones activas necesitan reconectarse para aplicar el cambio}}", + "providerConnected": "Conectado {providerId}", + "connectFailed": "Error al conectar {providerId}", + "providerDisconnected": "Desconectado {providerId}", + "disconnectFailed": "Error al desconectar {providerId}", + "catalogRefreshed": "Catálogo actualizado: {count} proveedores", + "catalogRefreshFailed": "Error al actualizar el catálogo", + "piSaved": "Configuración de Pi guardada", + "savePiFailed": "No se pudo guardar la configuración de Pi", + "piRuntimeSaved": "Entorno de Pi guardado", + "savePiRuntimeFailed": "No se pudo guardar el entorno de Pi", + "piBinaryInstalled": "pi instalado", + "piBinaryInstallFailed": "Error al instalar pi", + "piBinaryUninstalled": "pi desinstalado", + "piBinaryUninstallFailed": "Error al desinstalar pi", + "savePiTrustFailed": "Error al guardar la confianza del espacio de trabajo" + }, + "version": { + "statusLabel": "Estado de versión", + "notInstalled": "No instalado", + "remoteLocal": "Remota: {remoteVersion} · Local: {localVersion}", + "localOnly": "Local: {localVersion}", + "localInstalled": "{versionText}. Instalado.", + "platformUnsupported": "{versionText}. La plataforma actual no soporta este agente.", + "uvxNotReady": "{versionText}. El runtime de uv no está instalado: instálalo desde la comprobación de uv de abajo para usar este agente.", + "clickInstall": "{versionText}. Haz clic en Instalar a la derecha.", + "localUnrecognized": "{versionText}. La versión local no es comparable; intenta actualizar para sobrescribir la instalación.", + "upgradeAvailable": "{versionText}. Hay actualización disponible.", + "remoteUnavailable": "{versionText}. La versión remota no está disponible por ahora.", + "latest": "{versionText}. Ya está en la última versión." + }, + "adapter": { + "label": "Adaptador ACP", + "badge": "Adaptador ACP", + "badgeHint": "Para este agente Codeg instala un paquete adaptador ACP, no la CLI del proveedor. Son independientes y comparten la misma configuración.", + "learnMore": "Más información", + "missingWithNative": "Se encontró tu {nativeLabel} en {nativePath}. Codeg habla con los agentes mediante ACP y esa CLI no habla ACP, así que Codeg necesita un paquete adaptador aparte, {adapterPackage}, mantenido por el proyecto Agent Client Protocol (originalmente Zed). Incluye su propio runtime, nunca modifica ni reemplaza tu comando {nativeCmd} y lee el mismo {configDir}: tu sesión y tus ajustes actuales se conservan. Instálalo abajo.", + "missing": "Codeg habla con los agentes mediante ACP y la {nativeLabel} no habla ACP, así que Codeg necesita un paquete adaptador aparte, {adapterPackage}, mantenido por el proyecto Agent Client Protocol (originalmente Zed). Incluye su propio runtime, por lo que no hace falta instalar antes la CLI {nativeCmd}; si ya la tienes, ambas conviven y comparten la sesión y los ajustes de {configDir}. Instálalo abajo.", + "readyWithNative": "El adaptador {adapterCmd} está instalado: es lo que Codeg ejecuta, no tu propio {nativeCmd} en {nativePath}. Son paquetes distintos que conviven y ambos leen {configDir}, así que la sesión y los ajustes son compartidos.", + "ready": "El adaptador {adapterCmd} está instalado: es lo que Codeg ejecuta. Incluye su propio runtime, así que la {nativeLabel} no es necesaria; si la instalas después, ambas conviven y comparten {configDir}." + }, + "cline": { + "configDescription": "Configure el proveedor de API y las credenciales de Cline. La configuración se guarda en ~/.cline/data/." + }, + "opencodePlugins": { + "title": "Plugins de OpenCode", + "declared": "Plugins declarados", + "noPlugins": "No hay plugins declarados en opencode.json", + "status": { + "installed": "Instalado", + "missing": "No instalado" + }, + "installAll": "Instalar todos los faltantes", + "pinVersions": "Fijar versiones @latest", + "install": "Instalar", + "uninstall": "Desinstalar", + "refresh": "Actualizar", + "success": "Todos los plugins se instalaron correctamente", + "failed": "La operación del plugin falló" + }, + "pi": { + "configManagement": "Configuración de Pi", + "configDescription": "Pi se autentica con la clave API de tu proveedor de modelos. La clave se escribe en ~/.pi/agent/auth.json y la selección de modelo en settings.json.", + "providerLabel": "Proveedor", + "modelLabel": "Modelo", + "thinkingLabel": "Razonamiento", + "thinking": { + "off": "Desactivado", + "low": "Bajo", + "medium": "Medio", + "high": "Alto", + "minimal": "Mínimo", + "xhigh": "Muy alto" + }, + "apiKeyLabel": "Clave API", + "apiKeyHint": "Se guarda en ~/.pi/agent/auth.json para el proveedor seleccionado.", + "apiKeySetPlaceholder": "•••••• (guardada — déjalo vacío para mantener)", + "saveConfig": "Guardar configuración de Pi", + "providerModelRequired": "El proveedor y el modelo son obligatorios", + "runtimeTitle": "Entorno de ejecución", + "runtimeDescription": "Elige qué binario de pi se ejecuta. Usa el predeterminado o apunta a tu propia compilación de pi.", + "modeDefault": "pi predeterminado", + "modeDefaultHint": "Usa el adaptador pi-acp integrado con el pi de tu PATH. Instala pi con: npm install -g @earendil-works/pi-coding-agent", + "modeCustom": "pi personalizado", + "modeCustomHint": "Ejecuta tu propia compilación, instalación o envoltorio de pi.", + "commandLabel": "Comando o ruta de pi", + "commandHint": "Una ruta absoluta, un nombre de comando en el PATH o un script envoltorio (p. ej. ./pi-test.sh de un monorepo).", + "commandNotFound": "Comando no encontrado", + "validate": "Validar", + "advanced": "Avanzado", + "configDirLabel": "Directorio de configuración (PI_CODING_AGENT_DIR)", + "sessionDirLabel": "Directorio de sesiones (PI_CODING_AGENT_SESSION_DIR)", + "flagsHint": "pi-acp no reenvía flags personalizados de pi (--approve, -e, …); envuelve pi en un script y apunta el comando a él.", + "customIncomplete": "Introduce un comando de pi para guardar", + "saveRuntime": "Guardar entorno", + "providerPlaceholder": "Seleccionar un proveedor", + "customProvider": "Proveedor personalizado…", + "providerIdLabel": "ID del proveedor", + "apiProtocolLabel": "Protocolo de API", + "baseUrlLabel": "Endpoint de API (Base URL)", + "customProviderHint": "Define un proveedor en ~/.pi/agent/models.json hacia tu endpoint. La mayoría de los servidores autoalojados o proxy usan openai-completions.", + "baseUrlRequired": "El endpoint de API (Base URL) es obligatorio", + "binaryTitle": "binario pi (pi-coding-agent)", + "binaryDescription": "pi-acp ejecuta este binario pi. Instálalo aquí o apunta pi-acp a tu propia compilación más abajo.", + "binaryInstalled": "Instalado", + "binaryMissing": "No instalado", + "binaryChecking": "Comprobando…", + "installBinary": "Instalar pi", + "installing": "Instalando…", + "recheck": "Volver a comprobar", + "configDirSkillsNote": "Con un directorio de configuración personalizado, las habilidades, los expertos y las herramientas de oficina gestionados en Ajustes no se aplican a este pi; gestiona sus habilidades directamente en esa carpeta.", + "projectTrustTitle": "Confianza del proyecto", + "projectTrustDescription": "Carpetas desde las que permitiste que pi cargue archivos del proyecto. Una carpeta de confianza permite que las .pi/extensions de ese repositorio ejecuten código al iniciar pi, se aplica a todas las carpetas que contiene y también se usa cuando ejecutas pi en una terminal.", + "projectTrustLoading": "Cargando…", + "projectTrustEmpty": "Aún no hay carpetas decididas.", + "projectTrustTrusted": "De confianza", + "projectTrustDenied": "Sin confianza", + "projectTrustRevoke": "Revocar", + "reasoningTitle": "Razonamiento", + "reasoningEnableLabel": "Activar", + "reasoningDescription": "pi solo envía un esfuerzo de razonamiento para un modelo que lo declara: en un modelo sin declarar, todos los niveles se reducen a Off, así que el selector del compositor vuelve atrás en cuanto lo tocas. Se escribe en la entrada de este modelo en models.json.", + "levelsLabel": "Niveles disponibles", + "levelsHint": "Serán las filas del selector de razonamiento del compositor. Elige los que acepte tu endpoint; pi rechaza cualquier nivel que no esté aquí.", + "levelsEmptyError": "Elige al menos un nivel: sin ninguno, pi vuelve a Off.", + "wireValuesTitle": "Avanzado: valores enviados al proveedor", + "wireValuesHint": "Déjalo vacío para enviar el nombre del nivel tal cual. Defínelo cuando tu endpoint espere otra cosa: los backends al estilo de Google quieren LOW / HIGH.", + "defaultLevelUnlisted": "Este nivel no está en la lista de arriba: pi lo reduciría." + }, + "addCustomAgent": "Añadir agente personalizado", + "addCustomAgentHint": "Registra cualquier agente compatible con ACP. Elige uno del registro público de ACP o pega su información de registro.", + "customAgentFromRegistry": "Registro ACP", + "customAgentManual": "Manual", + "customAgentSearchPlaceholder": "Buscar agentes…", + "customAgentLoadingCatalog": "Cargando el registro ACP…", + "customAgentRetry": "Reintentar", + "customAgentNoResults": "No hay agentes coincidentes", + "customAgentAdd": "Añadir", + "customAgentAlreadyAdded": "Añadido", + "customAgentUnsupportedPlatform": "No hay compilación disponible para esta plataforma", + "customAgentAdded": "{name} añadido", + "customAgentIdLabel": "ID del registro", + "customAgentNameLabel": "Nombre visible", + "customAgentVersionLabel": "Versión", + "customAgentSpecLabel": "Distribución (JSON)", + "customAgentSpecHint": "Misma forma que el objeto distribution del registro ACP: canales npx, uvx y binary, o pega una entrada completa del registro. En npx/uvx, cmd es el ejecutable que instala el paquete; se deriva del nombre del paquete si se omite, así que indícalo cuando difieran. binary se organiza por clave de plataforma (esta máquina: {platform}); su cmd es la ruta de arranque dentro del archivo y sha256 verifica opcionalmente la descarga.", + "customAgentTemplateLabel": "Plantillas", + "customAgentKindLabel": "Iniciar mediante", + "customAgentInvalidJson": "JSON no válido", + "customAgentNoDistribution": "No se encontró distribución npx, uvx ni binary", + "customAgentCancel": "Cancelar", + "customAgentSave": "Añadir agente", + "customAgentSaveChanges": "Guardar cambios", + "customAgentEdit": "Editar agente", + "customAgentEditHint": "Actualiza el nombre, el icono, la distribución y las declaraciones de skills. El ID del agente no puede cambiarse.", + "customAgentEditNotFound": "No se encontró el agente personalizado {id}", + "customAgentSaved": "{name} guardado", + "customAgentVersionProbeLabel": "Comando de consulta de versión (opcional)", + "customAgentVersionProbeHint": "Comando que imprime la versión instalada localmente. Si se deja vacío, codeg ejecuta el comando del agente con --version.", + "customAgentRemove": "Eliminar agente", + "customAgentRemoveHint": "Elimina la definición del agente. Las conversaciones existentes conservan su historial; el agente simplemente ya no se puede iniciar.", + "customAgentIconLabel": "Icono (opcional)", + "customAgentIconUpload": "Subir", + "customAgentIconReplace": "Reemplazar", + "customAgentIconClear": "Quitar icono", + "customAgentIconHint": "Se guarda junto al agente, así funciona sin conexión. Si no indicas ninguno, se usa una inicial de color.", + "customAgentSkillsLabel": "Skills (.agents/skills compartido)", + "customAgentSkillsHint": "Declara que este agente lee el almacén compartido .agents/skills (directorios global y de proyecto) y lo añade a todas las matrices de habilidades. Las habilidades vinculadas allí son visibles para todos los agentes que leen ese almacén compartido.", + "customAgentSkillsDirLabel": "Directorio de skills dedicado", + "customAgentSkillsDirHint": "Ruta absoluta del directorio desde el que este agente carga skills: su propio almacén, además del compartido o en su lugar. ~ se expande al directorio personal; las skills vinculadas se colocan aquí primero.", + "customAgentMcpLabel": "Compatibilidad con MCP", + "customAgentMcpHint": "Envía el complemento MCP integrado de codeg a este agente al iniciar la sesión: es el canal de la delegación, los comentarios en vivo y las herramientas de tareas. Desactívalo para un agente que rechaza servidores MCP y no llega a conectarse; el cambio se aplica en la próxima conexión.", + "customAgentIconNotAnImage": "Selecciona un archivo de imagen.", + "customAgentIconTooLarge": "El icono debe pesar menos de {limit} KB.", + "customAgentIconReadFailed": "No se pudo leer esa imagen.", + "customAgentRemoveConfirm": "¿Eliminar {name}? Las conversaciones existentes se conservan, pero el agente ya no podrá iniciarse.", + "customAgentRemoveWithData": "Eliminar también su historial de conversaciones registrado", + "customAgentRemoved": "{name} eliminado", + "customAgentBadge": "Personalizado", + "customAgentNotLaunchable": "Este agente no puede iniciarse aquí: {reason}" + }, + "SettingsPages": { + "agentsLoading": "Cargando configuración de agentes...", + "skillPacksLoading": "Cargando paquetes de habilidades…" + }, + "GeneralSettings": { + "loading": "Cargando...", + "sectionTitle": "General", + "sectionDescription": "Preferencias centralizadas para el terminal predeterminado, la aceleración de renderizado y la delegación entre agentes.", + "terminalTitle": "Terminal predeterminada", + "terminalDescription": "Elige el shell que se usa al abrir nuevas pestañas de terminal desde la barra de terminal o el árbol de archivos. Los agentes también lo usan cuando piden a codeg que ejecute una línea de comandos completa.", + "terminalSystemDefault": "Predeterminado del sistema", + "terminalPowerShell7": "PowerShell 7 (pwsh)", + "terminalWindowsPowerShell": "Windows PowerShell", + "terminalCmd": "Símbolo del sistema (cmd)", + "terminalSaveFailed": "Error al guardar la configuración del terminal: {message}", + "terminalShellCustom": "Ruta personalizada", + "terminalShellCustomPath": "Ruta del shell", + "terminalShellCustomPlaceholder": "/usr/local/bin/fish", + "terminalShellCustomSave": "Guardar", + "terminalShellCustomHint": "Indica una ruta absoluta o un nombre resoluble en PATH.", + "terminalShellNotInstalled": "no instalado", + "terminalShellNotFoundWarning": "Esta ruta no existe en este host.", + "terminalCurrentShell": "En uso actualmente: {path}", + "renderingDescription": "Desactiva la aceleración por hardware si la aplicación muestra pantalla negra o fallos de renderizado (común en algunas GPU AMD o Intel integradas). Solo afecta a la versión de escritorio en Windows.", + "disableHardwareAcceleration": "Desactivar aceleración por hardware", + "renderingSaveFailed": "No se pudo guardar la configuración de renderizado: {message}", + "restartRequired": "Guardado. Reinicia la aplicación para aplicar el cambio.", + "restartNow": "Reiniciar ahora", + "restartFailed": "No se pudo reiniciar: {message}", + "loadFailed": "Error al cargar: {message}" + }, + "LoginPage": { + "documentTitle": "Iniciar sesión - codeg", + "brand": "Codeg", + "subtitle": "Introduce tu token de acceso para conectarte a la aplicación de escritorio", + "tokenPlaceholder": "Token de acceso", + "connect": "Conectar", + "connecting": "Conectando...", + "helpText": "Encuentra tu token en la aplicación de escritorio en Configuración → Servicio web", + "invalidToken": "Token no válido. Por favor, comprueba e inténtalo de nuevo.", + "connectionFailed": "Error de conexión (HTTP {status})", + "networkError": "No se puede conectar al servidor" + }, + "CommitPage": { + "title": "Confirmación", + "invalidFolderId": "ID de carpeta no válido", + "loadingRepo": "Cargando repositorio..." + }, + "MergePage": { + "title": "Resolver conflictos", + "invalidFolderId": "ID de carpeta no válido", + "loadingRepo": "Cargando repositorio...", + "localVersion": "Local (Nuestro)", + "result": "Resultado", + "remoteVersion": "Remoto (Suyo)", + "acceptLocal": "Aceptar local", + "acceptRemote": "Aceptar remoto", + "markResolved": "Marcar como resuelto", + "abortMerge": "Abortar", + "completeMerge": "Completar fusión", + "unresolvedConflicts": "Todavía hay marcadores de conflicto sin resolver en este archivo", + "fileResolved": "Archivo resuelto correctamente", + "allResolved": "Todos los conflictos resueltos", + "conflictFiles": "Archivos en conflicto", + "loadingFile": "Cargando archivo...", + "preparingMerge": "Preparando fusión...", + "selectFile": "Seleccionar un archivo para resolver", + "noConflicts": "No hay archivos en conflicto", + "skipFile": "Omitir", + "abortSuccess": "Operación abortada", + "applyAllNonConflicting": "Aplicar todos los cambios sin conflicto", + "applyLeftNonConflicting": "Aplicar local", + "applyRightNonConflicting": "Aplicar remoto" + }, + "ImportSessions": { + "title": "Importar sesiones locales", + "scanningTitle": "Escaneando sesiones locales de los agentes…", + "scanningHint": "Recorriendo el almacén local de sesiones de cada agente. Con historiales grandes puede tardar un momento. Las sesiones ya importadas se actualizan por el camino.", + "scanFailed": "Error al escanear", + "retry": "Reintentar", + "rescan": "Reescanear", + "empty": "No se encontraron sesiones locales", + "emptyHint": "No se encontraron almacenes de sesiones de agentes en este equipo.", + "noMatches": "Ninguna sesión coincide con los filtros actuales", + "searchPlaceholder": "Buscar título o ruta…", + "allAgents": "Todos los agentes", + "onlyImportable": "Solo importables", + "selectAll": "Seleccionar todo", + "clearSelection": "Limpiar", + "expandAll": "Expandir todo", + "collapseAll": "Contraer todo", + "summaryCounts": "{total} sesiones · {importable} importables · {folders} carpetas", + "noFolderSkipped": "{count} sin carpeta de proyecto omitidas", + "folderNew": "Nueva", + "folderCounts": "{importable}/{total} importables", + "toggleFolderAria": "Seleccionar todas las sesiones importables de {name}", + "toggleSessionAria": "Seleccionar la sesión {title}", + "statusImported": "Importada", + "statusDeleted": "Eliminada", + "untitled": "Sesión sin título", + "messageCount": "{count} mensajes", + "selectedCount": "{count} seleccionadas", + "importSelected": "Importar selección", + "importing": "Importando…", + "close": "Cerrar", + "doneTitle": "Importación finalizada", + "doneImported": "Importadas", + "doneUpdated": "Actualizadas", + "doneSkipped": "Omitidas", + "doneCreatedFolders": "Carpetas creadas", + "doneNotFound": "No encontradas", + "doneFailed": "Fallidas", + "continueImport": "Seguir importando", + "toasts": { + "importFailed": "Error al importar: {message}" + } + }, + "Folder": { + "workspaceStatus": { + "degradedTitle": "Actualizaciones en vivo no disponibles", + "degradedHint": "El observador no pudo iniciarse (por ejemplo, permiso denegado). Actualiza manualmente para ver los cambios.", + "retry": "Reintentar", + "retrying": "Reintentando..." + }, + "common": { + "all": "Todo", + "cancel": "Cancelar", + "close": "Cerrar", + "closeOthers": "Cerrar otros", + "closeAll": "Cerrar todo", + "confirm": "Confirmar", + "save": "Guardar", + "delete": "Eliminar", + "rename": "Renombrar", + "loading": "Cargando...", + "refresh": "Actualizar", + "refreshing": "Actualizando...", + "create": "Crear", + "createAndSwitch": "Crear y cambiar", + "openFile": "Abrir archivo", + "viewDiff": "Ver Diff", + "push": "Enviar..." + }, + "statusLabels": { + "in_progress": "En progreso", + "pending_review": "Revisión", + "completed": "Completado", + "cancelled": "Cancelado" + }, + "sidebar": { + "title": "Conversaciones", + "locateActiveConversation": "Ubicar conversación activa", + "expandAllGroups": "Expandir todos los grupos", + "collapseAllGroups": "Colapsar todos los grupos", + "newConversation": "Nueva conversación", + "newConversationShort": "Nueva", + "newChat": "Nueva conversación", + "search": "Buscar", + "noConversationsFound": "No se encontraron conversaciones.", + "importLocalSessions": "Importar sesiones locales", + "importing": "Importando...", + "error": "Error del sistema: {message}", + "completeAllSessions": "Completar todas las sesiones", + "completeAllReviewTitle": "¿Completar todas las sesiones en revisión?", + "completeAllReviewDescription": "Esto marcará como completadas todas las {count, plural, one {# sesión} other {# sesiones}} en Revisión.", + "completing": "Completando...", + "toasts": { + "importedSessions": "Se importaron {imported, plural, one {# sesión} other {# sesiones}}, se omitieron {skipped}", + "importedAndUpdated": "Se importaron {imported, plural, one {# sesión} other {# sesiones}}, se actualizaron {updated, plural, one {# título} other {# títulos}}, se omitieron {skipped}", + "updatedTitles": "Se actualizaron {updated, plural, one {# título} other {# títulos}}, se omitieron {skipped}", + "noNewSessionsFound": "No se encontraron sesiones nuevas (omitidas {skipped})", + "importFailed": "Error al importar: {message}", + "reviewCompleted": "Se marcaron como completadas {count, plural, one {# sesión en revisión} other {# sesiones en revisión}}", + "completeReviewFailed": "Error al completar sesiones en revisión: {message}", + "folderOpened": "Carpeta {name} abierta", + "folderRemoved": "Carpeta {name} eliminada", + "openFolderFailed": "Error al abrir carpeta", + "removeFolderFailed": "Error al eliminar carpeta: {message}", + "reorderFoldersFailed": "Error al reordenar carpetas: {message}", + "changeFolderColorFailed": "Error al cambiar el color: {message}", + "setFolderAliasFailed": "Error al establecer el alias: {message}", + "changeFolderDefaultAgentFailed": "Error al establecer agente predeterminado: {message}" + }, + "statsLabel": "{folders} carpetas · {convos} conversaciones", + "reorderHandle": "Arrastrar para reordenar", + "openFolder": "Abrir carpeta", + "searchPlaceholder": "Buscar conversaciones...", + "viewOptions": "Opciones de visualización", + "showCompleted": "Mostrar conversaciones completadas", + "showWorktrees": "Mostrar carpetas de worktree", + "showRecent": "Mostrar grupo Recientes", + "moreOptions": "Más opciones", + "sortBy": "Ordenar por", + "sortByCreatedAt": "Fecha de creación", + "sortByUpdatedAt": "Fecha de actualización", + "sectionOrder": "Orden de secciones", + "sectionOrderMoveUp": "Subir", + "sectionOrderMoveDown": "Bajar", + "sectionOrderItemLabel": "{name} — posición {position} de {total}", + "statusRunningBadge": "Ejecutando", + "runningCountBadge": "{count, plural, one {# sesión en ejecución} other {# sesiones en ejecución}}", + "statusCancelledBadge": "Cancelado", + "worktreeRemovedBadge": "Worktree de origen eliminado", + "conversationCountUnit": "{count, plural, one {# conversación} other {# conversaciones}}", + "emptyFolderHint": "Sin conversaciones", + "noMatchingConversations": "No hay conversaciones coincidentes", + "noUnfinishedConversations": "No hay conversaciones pendientes. Activa \"Mostrar completadas\" desde el menú superior derecho.", + "removeFolderConfirmTitle": "¿Eliminar carpeta del espacio de trabajo?", + "removeFolderConfirmDescription": "¿Eliminar \"{name}\" del espacio de trabajo? Sus pestañas y terminales se cerrarán.", + "folderHeaderMenu": { + "manageConversations": "Gestionar conversaciones…", + "manageLinks": "Carpetas vinculadas", + "changeColor": "Cambiar color", + "useThemeColor": "Usar tema de la app", + "setDefaultAgent": "Establecer agente predeterminado", + "defaultAgentNone": "Sin valor (usar predeterminado global)", + "agentUnavailableSuffix": "(no disponible)", + "loadingAgents": "Cargando agentes…", + "setAlias": "Establecer alias…", + "setAliasTitle": "Establecer alias de la carpeta", + "setAliasPlaceholder": "Introduce un alias (déjalo vacío para borrarlo)", + "setAliasSave": "Guardar", + "setAliasCancel": "Cancelar", + "removeFromWorkspace": "Quitar del espacio de trabajo" + }, + "manageConversations": { + "title": "Gestionar conversaciones", + "searchPlaceholder": "Buscar por título…", + "agentFilterAll": "Todos los agentes", + "statusFilterAll": "Todos los estados", + "folderFilterAll": "Todas las carpetas", + "branchFilterAll": "Todas las ramas", + "branchNone": "Sin rama", + "branchSearchPlaceholder": "Buscar ramas…", + "noMatchingBranches": "No hay ramas coincidentes", + "selectAllVisible": "Seleccionar todo", + "deselectAll": "Deseleccionar todo", + "selectedCount": "{count} seleccionada(s)", + "matchedCount": "{count} coincidencia(s)", + "untitledConversation": "Conversación sin título", + "setStatus": "Cambiar estado…", + "deleteSelected": "Eliminar", + "noConversations": "No hay conversaciones en esta carpeta.", + "noConversationsWorkspace": "No hay conversaciones en el espacio de trabajo.", + "noMatchingConversations": "Ninguna conversación coincide con los filtros.", + "confirmDeleteTitle": "¿Eliminar {count} conversación(es)?", + "confirmDeleteDescription": "Esta acción no se puede deshacer.", + "toastDeleted": "Se eliminaron {count} conversación(es)", + "toastStatusUpdated": "Estado actualizado para {count} conversación(es)", + "toastOpFailed": "Error en la operación: {message}" + }, + "sectionPinned": "Fijadas", + "sectionFolders": "Carpetas", + "sectionChats": "Chat", + "sectionRecent": "Recientes", + "noChats": "Sin chats", + "noRecent": "Sin conversaciones recientes", + "showMoreRecent": "Mostrar más ({count})", + "noFolders": "No hay carpetas abiertas", + "newChatAction": "Nuevo chat", + "automations": "Automatizaciones", + "tasks": "Tareas pendientes", + "loadingSubsessions": "Cargando subconversaciones…" + }, + "conversation": { + "reloadFailed": "No se pudo recargar la conversación: {message}", + "reloaded": "Conversación recargada", + "reload": "Recargar", + "activeConversationIndicator": "Conversación activa", + "newConversation": "Nueva conversación", + "closeConversation": "Cerrar conversación", + "copyText": "Copiar texto", + "copyTextSuccess": "Copiado", + "copyTextFailed": "Error al copiar", + "forkSession": "Bifurcar sesión", + "forkSessionSuccess": "Sesión bifurcada exitosamente", + "forkSessionFailed": "Error al bifurcar la sesión: {error}", + "exportConversation": "Exportar conversación", + "exportImage": "Imagen", + "exportMarkdown": "Markdown", + "exportHtml": "HTML", + "exportSuccess": "Conversación exportada", + "exportFailed": "Error al exportar", + "exportImageTooLong": "La conversación es demasiado larga para exportar como imagen", + "exportLabels": { + "untitledConversation": "Conversación sin título", + "agent": "Agente", + "model": "Modelo", + "status": "Estado", + "started": "Inicio", + "updated": "Actualizado", + "tokens": "Estadísticas de tokens", + "duration": "Duración", + "inputTokens": "Entrada", + "outputTokens": "Salida", + "cacheRead": "Caché leída", + "cacheWrite": "Caché escrita", + "user": "Usuario", + "assistant": "Asistente", + "system": "Sistema", + "toolResult": "Resultado", + "toolError": "Error" + }, + "moreActions": "Más acciones" + }, + "sessionDetails": { + "menuLabel": "Detalles de la sesión", + "noActiveSession": "No hay ninguna sesión activa", + "title": "Detalles de la sesión", + "subtitle": "Metadatos de la sesión y uso de tokens", + "fieldTitle": "Título", + "untitled": "Conversación sin título", + "sessionId": "ID de sesión", + "externalId": "ID de extensión", + "agent": "Agente", + "model": "Modelo", + "status": "Estado", + "gitBranch": "Rama de Git", + "parentId": "Sesión principal", + "tokensHeading": "Uso de tokens", + "totalTokens": "Total", + "inputTokens": "Entrada", + "outputTokens": "Salida", + "cacheWrite": "Caché escrita", + "cacheRead": "Caché leída", + "contextWindow": "Ventana de contexto", + "duration": "Duración", + "loadingStats": "Cargando uso de tokens…", + "loadFailed": "Error al cargar el uso de tokens", + "noStats": "Sin uso registrado", + "timestampsHeading": "Marcas de tiempo", + "createdAt": "Creado", + "updatedAt": "Actualizado", + "none": "—", + "copyField": "Copiar {field}", + "copiedField": "{field} copiado" + }, + "conversationCard": { + "untitledConversation": "Conversación sin título", + "newConversation": "Nueva conversación", + "rename": "Renombrar", + "status": "Estado", + "delete": "Eliminar", + "importLocalSessions": "Importar sesiones locales", + "importing": "Importando...", + "renameConversation": "Renombrar conversación", + "deleteConversationTitle": "¿Eliminar conversación?", + "deleteConversationDescription": "Esto eliminará \"{title}\". Esta acción no se puede deshacer.", + "cancel": "Cancelar", + "save": "Guardar", + "pin": "Fijar", + "unpin": "Dejar de fijar", + "markCompleted": "Marcar como completada", + "reopen": "Reabrir", + "expandSubsessions": "Expandir subconversaciones", + "collapseSubsessions": "Contraer subconversaciones" + }, + "search": { + "dialogTitle": "Buscar", + "dialogTitleWithFolder": "Buscar — {name}", + "tabConversations": "Conversaciones", + "tabFiles": "Archivos", + "placeholder": "Buscar conversaciones...", + "filePlaceholder": "Buscar archivos o directorios...", + "allAgents": "Todo", + "searching": "Buscando...", + "typeToSearch": "Escribe para buscar conversaciones", + "typeToSearchFiles": "Escribe para buscar archivos o directorios", + "noResults": "No se encontraron resultados.", + "untitledConversation": "Conversación sin título" + }, + "folderTitleBar": { + "showSidebar": "Mostrar barra lateral", + "hideSidebar": "Ocultar barra lateral", + "toggleTerminal": "Alternar terminal", + "toggleAuxPanel": "Alternar panel auxiliar", + "search": "Buscar", + "openSettings": "Abrir configuración", + "backToConversations": "Volver a conversaciones", + "withShortcut": "{label} (atajo: {shortcut})" + }, + "statusBar": { + "connection": { + "connected": "Conectado", + "connecting": "Conectando...", + "prompting": "Respondiendo...", + "error": "Error de conexión", + "disconnected": "Desconectado", + "tooltip": "{agent}: {status}", + "tooltipError": "{agent}: {error}", + "title": "Conexión del agente", + "triggerAria": "Conexión del agente: {status}", + "workingDir": "Directorio de trabajo", + "sessionId": "ID de sesión", + "viewerNote": "Conectado a una sesión que pertenece a otro cliente: reconectar solo vuelve a adjuntar esta vista.", + "reconnectInterrupts": "Reconectar reinicia el agente e interrumpe el trabajo en curso.", + "reconnect": "Reconectar", + "reconnecting": "Reconectando...", + "reconnectUnavailable": "Aún no hay ninguna sesión a la que reconectar." + }, + "tasks": { + "title": "Tareas" + }, + "alerts": { + "title": "Alertas", + "empty": "Sin alertas", + "details": "Detalles" + }, + "stats": { + "conversations": "{count} conversaciones", + "openUsage": "Ver estadísticas de sesiones y uso de tokens" + }, + "tokens": { + "contextWindowUsageAria": "Uso de la ventana de contexto", + "contextWindow": "Ventana de contexto", + "usedMax": "Usado / Máx", + "tokenUsage": "Uso de tokens", + "input": "Entrada", + "output": "Salida", + "cacheRead": "Lectura de caché", + "cacheWrite": "Escritura de caché", + "total": "Total de tokens" + } + }, + "auxPanel": { + "tabs": { + "files": "Archivos", + "changes": "Cambios", + "commits": "Confirmaciones" + }, + "noFolderTitle": "No hay carpeta abierta", + "noFolderHint": "Abre una carpeta para ver su contenido aquí" + }, + "windowControls": { + "minimizeWindow": "Minimizar ventana", + "minimize": "Minimizar", + "maximizeWindow": "Maximizar ventana", + "maximize": "Maximizar", + "restoreWindow": "Restaurar ventana", + "restore": "Restaurar", + "closeWindow": "Cerrar ventana", + "close": "Cerrar" + }, + "tabs": { + "closeConversationTab": "Cerrar pestaña de conversación", + "close": "Cerrar", + "closeOthers": "Cerrar otros", + "splitRight": "Dividir a la derecha", + "splitDown": "Dividir abajo", + "splitAndMoveRight": "Dividir y mover a la derecha", + "splitAndMoveDown": "Dividir y mover abajo", + "moveToOppositeGroup": "Mover al grupo opuesto", + "moveToGroup": "Mover al grupo", + "groupLabel": "Grupo {index}", + "changeSplitterOrientation": "Cambiar orientación del divisor", + "unsplit": "Deshacer división", + "unsplitAll": "Deshacer todas las divisiones", + "closeAll": "Cerrar todo", + "tileDisplay": "Vista en mosaico", + "untileDisplay": "Salir de mosaico" + }, + "fileWorkspace": { + "files": "Archivos", + "closeFileTab": "Cerrar pestaña de archivo", + "close": "Cerrar", + "closeOthers": "Cerrar otros", + "closeAll": "Cerrar todo", + "preview": "Vista previa", + "editSource": "Editar fuente", + "maximize": "Maximizar", + "restore": "Restaurar", + "emptyDirectory": "Carpeta vacía" + }, + "terminal": { + "rename": "Renombrar", + "close": "Cerrar", + "closeOthers": "Cerrar otros", + "closeAll": "Cerrar todo", + "hideTerminal": "Ocultar terminal ({shortcut})", + "openFolderFirst": "Abre primero una carpeta" + }, + "workspaceDialog": { + "title": "Abrir carpeta", + "manageTitle": "Carpetas vinculadas", + "addTargetsTitle": "Añadir carpetas para vincular", + "pickRootDescription": "Elige la carpeta principal de este espacio de trabajo.", + "linksDescription": "Vincula otras carpetas como subdirectorios para que los agentes trabajen en todas ellas desde un solo espacio de trabajo.", + "addTargetsDescription": "Selecciona una o más carpetas. Cada una será un subdirectorio del espacio de trabajo.", + "useSystemPicker": "Selector del sistema", + "next": "Siguiente", + "back": "Atrás", + "done": "Listo", + "change": "Cambiar", + "addFolders": "Añadir carpetas", + "addSelected": "Añadir", + "addSelectedCount": "Añadir {count}", + "createCount": "Vincular {count} carpeta(s)", + "discardPending": "Descartar", + "noLinks": "Todavía no hay carpetas vinculadas.", + "gitExclude": "Mantener los enlaces fuera del estado de git", + "rename": "Renombrar", + "unlink": "Quitar enlace", + "repair": "Recrear enlace", + "saveName": "Guardar", + "cancelRename": "Cancelar", + "removePending": "Quitar", + "willAppearAs": "Aparece como {name} en el espacio de trabajo", + "renamedForDuplicate": "Renombrada: {base} ya lo usa otro enlace", + "renamedForExistingEntry": "Renombrada: {base} ya existe en esta carpeta", + "partiallyCreated": "Solo se pudieron vincular {count} carpeta(s)", + "openFailed": "No se pudo abrir la carpeta", + "previewFailed": "No se pudieron comprobar las carpetas seleccionadas", + "createFailed": "No se pudieron vincular las carpetas", + "renameFailed": "No se pudo renombrar el enlace", + "removeFailed": "No se pudo quitar el enlace", + "repairFailed": "No se pudo recrear el enlace", + "status": { + "ok": "Vinculada", + "missing": "El enlace ya no está en esta carpeta", + "conflicted": "Otra entrada usa ahora este nombre", + "broken": "La carpeta vinculada ya no existe" + }, + "nameIssue": { + "empty": "Escribe un nombre", + "illegalChars": "No puede contener / \\ : * ? \" < > |", + "tooLong": "El nombre es demasiado largo", + "reserved": "Windows reserva este nombre", + "duplicate": "Este nombre ya está en uso" + }, + "rejection": { + "not_found": "No se encontró esta carpeta", + "not_a_directory": "Esta ruta no es una carpeta", + "same_as_root": "Es la propia carpeta del espacio de trabajo", + "ancestor_of_root": "Esta carpeta contiene el espacio de trabajo", + "inside_root": "Ya está dentro del espacio de trabajo", + "already_linked": "Ya está vinculada", + "name_unavailable": "No queda ningún nombre libre para esta carpeta", + "alreadyLinkedAs": "Ya vinculada como {name}" + } + }, + "folderNameDropdown": { + "fallbackFolderName": "Carpeta", + "openFolder": "Abrir carpeta", + "cloneRepository": "Clonar repositorio", + "projectBoot": "Inicializador de proyecto", + "opened": "Abierto", + "recentOpen": "Abiertos recientemente" + }, + "fileWorkspacePanel": { + "addSelectionToChat": "Añadir selección al chat", + "addToChat": "Añadir al chat", + "addSelectionToChatDone": "Se añadió {label} a la conversación", + "addFileToChat": "Añadir archivo al chat", + "toggleWordWrap": "Alternar ajuste de línea", + "addFileToChatDone": "Se añadió {label} a la conversación", + "viewDiff": "Ver Diff", + "openFile": "Abrir archivo", + "fileCount": "{count, plural, one {# archivo} other {# archivos}}", + "openFileOrDiff": "Abre un archivo o diff desde el panel derecho", + "disk": "Disco", + "head": "HEAD (referencia)", + "unsaved": "Sin guardar", + "workingTree": "Árbol de trabajo", + "loading": "Cargando...", + "compareWithBranch": "{path} · comparar con {branch}", + "hunkCount": "{count, plural, one {# bloque} other {# bloques}}", + "prev": "Anterior", + "next": "Siguiente", + "jumpToLine": "Ir a la línea {line}", + "noParsedDiffSections": "No hay secciones de diff analizadas", + "loadingEditor": "Cargando editor...", + "imageZoomIn": "Ampliar", + "imageZoomOut": "Reducir", + "imageZoomReset": "Restablecer zoom", + "htmlPreviewTitle": "Vista previa HTML", + "htmlPreviewTrust": "Habilitar scripts", + "htmlPreviewTrustHint": "Ejecuta los scripts de este archivo y permite el acceso a la red. Actívalo solo para archivos de confianza.", + "officePreviewTitle": "Vista previa de documento de Office", + "officeFullRender": "Renderizado completo", + "officeFullRenderHint": "Renderiza animaciones Morph, 3D y fórmulas (ejecuta los scripts de la diapositiva)", + "officeNotInstalled": "OfficeCLI no está instalado", + "officeNotInstalledHint": "Instala OfficeCLI en Ajustes → Herramientas de Office para previsualizar archivos de Word, Excel y PowerPoint.", + "officeOpenSettings": "Abrir ajustes", + "officeWatchFailed": "No se pudo iniciar la vista previa en vivo", + "officeWatchRetry": "Reintentar", + "officeServerInstallHint": "OfficeCLI debe instalarse en el host del servidor. Ejecuta este comando allí y vuelve a intentarlo:", + "officeRemoteDesktopUnsupported": "La vista previa en vivo no está disponible en una ventana de escritorio remoto. Abre este espacio de trabajo en la interfaz web del servidor para previsualizar archivos de Office." + }, + "branchDropdown": { + "toasts": { + "commitCodeCompleted": "Commit de código completado", + "pushCodeCompleted": "Push de código completado", + "committedFiles": "{count, plural, one {# archivo confirmado} other {# archivos confirmados}}", + "taskCompleted": "{label} completado", + "taskFailed": "{label} falló", + "mergeNoNewCommits": "{branchName} no tiene commits nuevos", + "mergedCommits": "{count, plural, one {# commit fusionado} other {# commits fusionados}}", + "allFilesUpToDate": "Todos los archivos están actualizados", + "updatedFiles": "{count, plural, one {# archivo actualizado} other {# archivos actualizados}}", + "openCommitWindowFailed": "No se pudo abrir la ventana de commit", + "openPushWindowFailed": "Error al abrir la ventana de envío", + "upstreamSet": "La rama upstream se ha configurado", + "upstreamSetAndPushed": "Rama upstream configurada y se enviaron {count, plural, one {# commit} other {# commits}}", + "noCommitsToPush": "No hay commits para enviar", + "pushedCommits": "Se enviaron {count, plural, one {# commit} other {# commits}}", + "switchedToFolder": "Cambiado a {name}", + "switchFailed": "No se pudo cambiar de rama", + "openStashWindowFailed": "No se pudo abrir la ventana de stash" + }, + "tasks": { + "newBranch": "Crear rama {name}", + "newWorktree": "Crear worktree {name}", + "checkoutTo": "Cambiar a {branchName}", + "mergeBranch": "Fusionar {branchName}", + "rebaseTo": "Rebase a {branchName}", + "deleteRemoteBranch": "Eliminar rama remota {branchName}", + "initGitRepo": "Inicializar repositorio Git", + "pullCode": "Hacer pull del código", + "fetchInfo": "Obtener información", + "pushCode": "Enviar código", + "stashChanges": "Guardar cambios en stash", + "stashPop": "Aplicar stash", + "deleteBranch": "Eliminar rama {branchName}", + "removeWorktree": "Eliminar el worktree de {branchName}", + "removeWorktreeAndBranch": "Eliminar el worktree y la rama {branchName}", + "updateBranch": "Actualizar la rama {branchName}" + }, + "confirm": { + "mergeTitle": "Fusionar rama", + "rebaseTitle": "Rebase de rama", + "mergeDescription": "¿Fusionar {branchName} en la rama actual {currentBranch}?", + "rebaseDescription": "¿Hacer rebase de la rama actual {currentBranch} sobre {branchName}?", + "deleteRemoteTitle": "Eliminar rama remota", + "deleteRemoteDescription": "¿Eliminar la rama remota {branchName}? Esto la eliminará del repositorio remoto y no se puede deshacer.", + "deleteTitle": "Eliminar rama", + "deleteDescription": "¿Eliminar la rama {branchName}? Esta acción no se puede deshacer.", + "forceDeleteTitle": "Forzar eliminación de rama", + "forceDeleteDescription": "La rama {branchName} no está completamente fusionada. ¿Estás seguro de que quieres forzar su eliminación? Esta acción no se puede deshacer.", + "deleteWorktreeTitle": "Eliminar worktree", + "deleteWorktreeDescription": "¿Eliminar el directorio del worktree que tiene {branchName} activa? La rama y sus commits se conservan.", + "forceDeleteWorktreeTitle": "Forzar la eliminación del worktree", + "forceDeleteWorktreeDescription": "El worktree de {branchName} tiene archivos sin confirmar o sin seguimiento. ¿Eliminarlo de todos modos? Esos cambios no se podrán recuperar.", + "deleteWorktreeAndBranchTitle": "Eliminar worktree y rama", + "deleteWorktreeAndBranchDescription": "¿Eliminar el worktree de {branchName}, la rama y su carpeta del espacio de trabajo? Sus sesiones pasan a la carpeta del repositorio. Esta acción no se puede deshacer.", + "forceDeleteWorktreeAndBranchTitle": "Forzar la eliminación del worktree y la rama", + "forceDeleteWorktreeAndBranchDescription": "El worktree de {branchName} tiene archivos sin confirmar, o la rama no está totalmente fusionada. ¿Eliminar ambos de todos modos? Esta acción no se puede deshacer." + }, + "current": "Actual", + "switchToBranch": "Cambiar a esta rama", + "mergeBranchIntoCurrent": "Fusionar {branchName} en {currentBranch}", + "rebaseCurrentToBranch": "Rebase de {currentBranch} sobre {branchName}", + "noBranch": "Sin rama", + "detachedHead": "HEAD desacoplado en {sha}", + "initGitRepo": "Inicializar repositorio Git", + "pullCode": "Hacer pull del código", + "fetchRemoteBranches": "Obtener ramas remotas", + "openCommitWindow": "Commit de código...", + "pushCode": "Enviar...", + "pushBranch": "Enviar", + "newBranch": "Nueva rama...", + "newWorktree": "Nuevo worktree...", + "stashChanges": "Guardar cambios...", + "stashPop": "Aplicar stash...", + "manageRemotes": "Gestionar remotos...", + "localBranches": "Ramas locales ({count, plural, one {#} other {#}})", + "noLocalBranches": "Sin ramas locales", + "remoteBranches": "Ramas remotas ({count, plural, one {#} other {#}})", + "noRemoteBranches": "Sin ramas remotas", + "dialogs": { + "newBranchTitle": "Nueva rama", + "newBranchDescription": "Crear una nueva rama desde la rama actual {branch}", + "branchNamePlaceholder": "Nombre de la rama", + "newWorktreeTitle": "Nuevo worktree", + "newWorktreeDescription": "Crear un nuevo worktree desde la rama actual {branch}", + "branchNameLabel": "Nombre de la rama", + "worktreePathLabel": "Ruta del worktree", + "worktreePathPlaceholder": "Ruta del worktree", + "manageRemotesTitle": "Gestionar remotos", + "manageRemotesEmpty": "No hay remotos configurados", + "remoteNamePlaceholder": "Nombre del remoto", + "remoteUrlPlaceholder": "URL del remoto", + "addRemote": "Añadir", + "savingRemotes": "Guardando..." + }, + "conflict": { + "title": "Conflictos de fusión", + "description": "Los siguientes archivos tienen conflictos que necesitan ser resueltos:", + "abort": "Abortar fusión", + "openMergeTool": "Abrir herramienta de fusión", + "completeMerge": "Completar fusión", + "abortSuccess": "Fusión abortada correctamente", + "completeSuccess": "Fusión completada correctamente" + }, + "stashDialog": { + "title": "Guardar cambios en stash", + "description": "Guardar los cambios actuales en el stash", + "messageLabel": "Mensaje", + "messagePlaceholder": "Mensaje del stash (opcional)", + "keepIndex": "Mantener índice (los cambios preparados permanecen preparados)", + "cancel": "Cancelar", + "stash": "Guardar", + "success": "Cambios guardados en stash", + "error": "Error al guardar en stash" + }, + "unstashDialog": { + "title": "Aplicar stash", + "noStashes": "No hay stashes", + "selectFile": "Selecciona un archivo para ver diferencias", + "viewDiff": "Ver diferencias", + "original": "Original", + "modified": "Modificado", + "apply": "Aplicar", + "drop": "Eliminar", + "applySuccess": "Stash aplicado", + "dropSuccess": "Stash eliminado", + "confirmApply": "¿Aplicar stash {ref} al directorio de trabajo?", + "cancel": "Cancelar" + }, + "deleteBranch": "Eliminar rama", + "deleteWorktree": "Eliminar worktree", + "deleteWorktreeAndBranch": "Eliminar worktree y rama", + "searchPlaceholder": "Buscar ramas y acciones", + "searchAriaLabel": "Buscar ramas y acciones", + "branchListLabel": "Ramas y acciones", + "noMatches": "Sin coincidencias" + }, + "commitDialog": { + "toasts": { + "commitCompleted": "Commit de código completado", + "pushFailed": "Error al enviar", + "committedFiles": "{count, plural, one {# archivo confirmado} other {# archivos confirmados}}", + "addedToVcs": "Añadido a VCS", + "addToVcsFailed": "No se pudo añadir a VCS", + "fileDeleted": "Archivo eliminado", + "deleteFailed": "Error al eliminar", + "fileRolledBack": "Archivo revertido", + "rollbackFailed": "Error al revertir", + "dirRolledBack": "Directorio revertido", + "dirDeleted": "Directorio eliminado" + }, + "confirm": { + "deleteTitle": "Confirmar eliminación", + "deleteDescription": "¿Eliminar el archivo \"{file}\"? Esta acción no se puede deshacer.", + "rollbackTitle": "Confirmar reversión", + "rollbackDescription": "¿Revertir el archivo \"{file}\" a HEAD? Se perderán los cambios sin guardar.", + "rollbackDirDescription": "¿Revertir el directorio \"{dir}\" a HEAD? Los cambios no guardados se perderán.", + "deleteDirDescription": "¿Eliminar el directorio \"{dir}\"? Esta acción no se puede deshacer." + }, + "actions": { + "select": "Seleccionar", + "unselect": "Deseleccionar", + "rollback": "Revertir", + "addToVcs": "Añadir a VCS" + }, + "aria": { + "selectFile": "{action}: {path}", + "unselectAllFiles": "Deseleccionar todos los archivos", + "selectAllFiles": "Seleccionar todos los archivos", + "unselectTracked": "Deseleccionar cambios rastreados", + "selectTracked": "Seleccionar cambios rastreados", + "unselectUntracked": "Deseleccionar archivos no rastreados", + "selectUntracked": "Seleccionar archivos no rastreados" + }, + "loading": "Cargando...", + "selectionCount": "{selected} / {total} archivos", + "emptyFiles": "No hay archivos cambiados", + "trackedChanges": "Cambios rastreados ({count})", + "untrackedFiles": "Archivos no rastreados ({count})", + "commitMessage": "Mensaje de commit", + "commitMessagePlaceholder": "Introduce el mensaje de commit...", + "commitButton": "Confirmar ({count})", + "commitAndPushButton": "Confirmar y enviar ({count})", + "head": "HEAD", + "workingTree": "Árbol de trabajo", + "clickFileToDiff": "Haz clic en un nombre de archivo para ver diff", + "loadingDiff": "Cargando diff..." + }, + "pushWindow": { + "title": "Enviar código", + "noUnpushedCommits": "No hay commits sin enviar", + "noRemoteConfigured": "No hay remoto Git configurado\nAñade uno en «Gestionar remotos»", + "newBranchNoPushedCommits": "Nueva rama — enviar para crear rama de seguimiento remota", + "unpushed": "Sin enviar", + "selectFileToViewDiff": "Selecciona un archivo para ver las diferencias", + "before": "Antes", + "after": "Después", + "push": "Enviar", + "toasts": { + "pushSuccess": "Envío exitoso", + "pushFailed": "Error al enviar", + "upstreamSet": "Se ha configurado la rama remota", + "upstreamSetAndPushed": "Rama remota configurada y enviados {count} commits", + "noCommitsToPush": "No hay commits para enviar", + "pushedCommits": "Enviados {count} commits" + } + }, + "gitLogTab": { + "filesTitle": "Archivos", + "expandAllFiles": "Expandir todos los archivos", + "collapseAllFiles": "Colapsar todos los archivos", + "workspace": "espacio de trabajo", + "retry": "Reintentar", + "noCommitsFound": "No se encontraron commits", + "notAGitRepoTitle": "No es un repositorio Git", + "notAGitRepoHint": "Inicializa Git desde el menú de ramas superior, o abre un repositorio existente.", + "hash": "Hash del commit", + "copyHash": "Copiar hash", + "copyMessage": "Copiar mensaje", + "showMore": "Mostrar más", + "showLess": "Mostrar menos", + "author": "Autor", + "noFileChangeDetails": "No hay detalles de cambios de archivo disponibles.", + "loadingFiles": "Cargando archivos...", + "branchesTitle": "Ramas", + "loadingBranches": "Cargando ramas...", + "noContainingBranches": "No se encontraron ramas contenedoras.", + "newBranch": "Nueva rama...", + "resetToHere": "Resetear aquí", + "resetDisabledReasonNotCurrentBranchView": "Disponible solo al ver la rama actual", + "copyFullCommitHashAria": "Copiar hash completo del commit {hash}", + "pushStatus": { + "pushed": "Enviado al remoto", + "notPushed": "No enviado al remoto", + "unknown": "Estado de push desconocido (sin upstream configurado)" + }, + "time": { + "monthsAgo": "{count, plural, one {hace # mes} other {hace # meses}}", + "daysAgo": "{count, plural, one {hace # día} other {hace # días}}", + "hoursAgo": "{count, plural, one {hace # hora} other {hace # horas}}", + "minsAgo": "{count, plural, one {hace # min} other {hace # mins}}", + "justNow": "justo ahora" + }, + "toasts": { + "createdAndSwitchedNewBranch": "Nueva rama creada y activada", + "newBranchFromCommit": "{name} (desde {shortHash})", + "createBranchFailed": "No se pudo crear la rama", + "openPushWindowFailed": "No se pudo abrir la ventana de envío", + "resetSuccess": "Reset completado", + "resetSuccessDescription": "{branch} se reseteó a {shortHash} con {mode}", + "resetFailed": "Falló el reset" + }, + "authorFilter": { + "label": "Autor", + "searchPlaceholder": "Buscar autor", + "noAuthors": "No se encontraron autores", + "you": "tú", + "filterByAuthorAria": "Filtrar commits por autor", + "filterByQuery": "Filtrar por \"{query}\"", + "clearAuthorFilterAria": "Borrar filtro de autor", + "recent": "Recientes", + "matchingAuthors": "Autores coincidentes", + "removeFromRecent": "Quitar {name} de recientes" + }, + "branchSelector": { + "label": "Rama", + "head": "HEAD", + "headHint": "Sigue la rama actual", + "headHintWithBranch": "Sigue la rama actual ({branch})", + "searchBranch": "Buscar rama...", + "noBranches": "Sin ramas", + "selectBranchPlaceholder": "Seleccionar rama...", + "localBranches": "Ramas locales", + "current": "Actual", + "remoteBranches": "Ramas remotas", + "refreshCommitHistory": "Actualizar historial de commits", + "clearBranchFilterAria": "Borrar filtro de rama" + }, + "dialogs": { + "newBranchTitle": "Nueva rama", + "newBranchDescription": "Crea una nueva rama con el commit {shortHash} como último commit.", + "branchNamePlaceholder": "Nombre de la rama", + "reset": { + "title": "Resetear la rama actual hasta aquí", + "branchLabel": "Rama", + "targetLabel": "Commit objetivo", + "messageLabel": "Mensaje", + "modeLabel": "Modo de reset", + "confirmButton": "Resetear", + "modes": { + "soft": { + "label": "--soft", + "description": "Mueve HEAD y el puntero de la rama actual al commit objetivo.\nMantiene Index y Working Tree sin cambios.\nLos cambios de los commits retirados permanecen en estado staged." + }, + "mixed": { + "label": "--mixed (predeterminado)", + "description": "Mueve HEAD al commit objetivo.\nResetea Index al commit objetivo y mantiene los cambios en Working Tree.\nLos cambios pasan de staged a unstaged." + }, + "hard": { + "label": "--hard", + "description": "Mueve HEAD y resetea tanto Index como Working Tree al commit objetivo.\nSe descartan los cambios locales rastreados posteriores al commit objetivo.\nEs una operación destructiva." + }, + "keep": { + "label": "--keep", + "description": "Mueve HEAD al commit objetivo e intenta conservar los cambios locales.\nSolo se conservan cambios que no entren en conflicto.\nSi hay conflictos, el reset se aborta para proteger tu trabajo." + } + } + } + }, + "moreActions": "Más acciones de Git" + }, + "gitChangesTab": { + "workspace": "espacio de trabajo", + "noChanges": "No hay cambios locales", + "notAGitRepoTitle": "No es un repositorio Git", + "notAGitRepoHint": "Inicializa Git desde el menú de ramas superior, o abre un repositorio existente.", + "trackedChanges": "Cambios rastreados ({count})", + "untrackedFiles": "Archivos no rastreados ({count})", + "expandTracked": "Expandir cambios rastreados", + "collapseTracked": "Colapsar cambios rastreados", + "expandUntracked": "Expandir archivos no rastreados", + "collapseUntracked": "Colapsar archivos no rastreados", + "showRemainingItems": "Mostrar {count} elementos más", + "actions": { + "commitCode": "Hacer commit del código", + "rollback": "Revertir", + "addToVcs": "Añadir a VCS", + "delete": "Eliminar", + "moreActions": "Más acciones de Git", + "addAllToVcs": "Añadir todo al VCS", + "rollbackAll": "Revertir todo", + "refresh": "Actualizar" + }, + "toasts": { + "noAddableFilesInDir": "No hay archivos cambiados en este directorio para añadir a VCS", + "noRollbackFilesInDir": "No hay archivos cambiados en este directorio para revertir", + "addedToVcs": "Se añadió {name} a VCS", + "addToVcsFailed": "No se pudo añadir a VCS", + "openCommitWindowFailed": "No se pudo abrir la ventana de commit", + "rolledBack": "Se revirtió {name}", + "rollbackFailed": "Error al revertir", + "addedFilesToVcs": "Se añadieron {count, plural, one {# archivo} other {# archivos}} a VCS", + "rolledBackFiles": "Se revirtieron {count, plural, one {# archivo} other {# archivos}}", + "deleted": "Se eliminó {name}", + "deleteFailed": "Error al eliminar", + "deletedFiles": "Se eliminaron {count} archivos", + "noDeletableFilesInDir": "No hay archivos modificados en este directorio que se puedan eliminar", + "commitFailed": "Error al confirmar" + }, + "directoryDialog": { + "descriptionAdd": "Selecciona archivos bajo el directorio {path} para añadir a VCS.", + "descriptionRollback": "Selecciona archivos bajo el directorio {path} para revertir.", + "descriptionDelete": "Selecciona archivos bajo el directorio {path} para eliminar. Esta acción no se puede deshacer.", + "descriptionFallback": "Selecciona archivos para continuar.", + "selectionCount": "Seleccionados {selected} / {total} archivos", + "selectAll": "Seleccionar todo", + "unselectAll": "Deseleccionar todo", + "loadingCandidates": "Cargando cambios del directorio...", + "noOperableFiles": "No hay archivos operables" + }, + "rollbackConfirm": { + "title": "Confirmar reversión", + "descriptionWithTarget": "¿Revertir cambios locales de {kind} \"{name}\"?", + "descriptionFallback": "¿Revertir cambios locales?", + "kindDirectory": "directorio", + "kindFile": "archivo" + }, + "deleteConfirm": { + "title": "Confirmar eliminación", + "descriptionWithTarget": "¿Eliminar {kind} \"{name}\"? Esta acción no se puede deshacer.", + "descriptionFallback": "Esta acción no se puede deshacer.", + "kindDirectory": "directorio", + "kindFile": "archivo" + }, + "quickCommit": { + "placeholder": "Mensaje del commit (Intro para confirmar)" + } + }, + "tabContext": { + "loadingConversation": "Cargando...", + "untitledConversation": "Conversación sin título", + "newConversation": "Nueva conversación" + }, + "fileTreeTab": { + "workspace": "Espacio de trabajo", + "retry": "Reintentar", + "git": "Git", + "openInFileManager": "Abrir en el gestor de archivos", + "openInFinder": "Abrir en Finder", + "openInExplorer": "Abrir en Explorer", + "attachToCurrentSession": "Agregar a la sesión", + "compareWithBranch": "Comparar con rama...", + "reloadFromDisk": "Recargar desde disco", + "new": "Nuevo", + "newFile": "Archivo", + "newDirectory": "Directorio", + "openIn": "Abrir en", + "openInTerminal": "Abrir en terminal", + "linkedFolder": "Carpeta vinculada", + "copyPath": "Copiar ruta", + "upload": "Subir archivos/carpeta", + "download": "Descargar archivo", + "downloadAsZip": "Descargar como ZIP", + "actions": { + "select": "Seleccionar", + "unselect": "Deseleccionar", + "commitCode": "Confirmar código", + "rollback": "Revertir", + "addToVcs": "Añadir a VCS" + }, + "aria": { + "selectPath": "{action}: {path}" + }, + "toasts": { + "openDirectoryFailed": "No se pudo abrir el directorio", + "openBuiltinTerminalFailed": "No se pudo abrir la terminal integrada", + "openCommitWindowFailed": "No se pudo abrir la ventana de commit", + "noAddableFilesInDir": "No hay archivos modificados en este directorio que se puedan añadir a VCS", + "noRollbackFilesInDir": "No hay archivos modificados en este directorio que se puedan revertir", + "addedToVcs": "Se añadió {name} a VCS", + "addToVcsFailed": "No se pudo añadir a VCS", + "loadBranchesFailed": "No se pudieron cargar las ramas", + "renameFailed": "Error al renombrar", + "moveFailed": "Error al mover", + "deleteFailed": "Error al eliminar", + "rolledBack": "Se revirtió {name}", + "rollbackFailed": "Error al revertir", + "addedFilesToVcs": "{count, plural, one {Se añadió # archivo a VCS} other {Se añadieron # archivos a VCS}}", + "rolledBackFiles": "{count, plural, one {Se revirtió # archivo} other {Se revirtieron # archivos}}", + "savedAsCopy": "Guardado como copia", + "saveCopyFailed": "No se pudo guardar como copia", + "watchStartFailed": "No se pudo iniciar la vigilancia de archivos", + "createFailed": "Error al crear", + "downloadFailed": "No se pudo descargar {name}", + "downloadSaved": "{name} descargado", + "pathCopied": "Ruta copiada", + "copyPathFailed": "No se pudo copiar la ruta" + }, + "createDialog": { + "newFile": "Nuevo archivo", + "newDirectory": "Nuevo directorio", + "description": "Ingrese un nombre para el nuevo {kind}.", + "placeholderFile": "file-name.ext", + "placeholderDirectory": "folder-name" + }, + "renameDialog": { + "renameDirectory": "Renombrar directorio", + "renameFile": "Renombrar archivo", + "description": "Introduce un nuevo nombre (solo nombre, sin ruta).", + "placeholderDirectory": "nuevo-nombre-carpeta", + "placeholderFile": "nuevo-nombre-archivo.ext" + }, + "uploadDialog": { + "title": "Subir al área de trabajo", + "description": "Ajusta el destino si es necesario y añade archivos o carpetas.", + "workspaceRoot": "raíz del área de trabajo", + "targetPathLabel": "Subir a", + "targetPathHint": "Ruta resuelta: {path}", + "dropHint": "Arrastra archivos o carpetas aquí, o usa los botones de abajo", + "dropHintActive": "Suelta para añadir a la cola", + "selectFiles": "Seleccionar archivos", + "selectFolder": "Seleccionar carpeta", + "startUpload": "Iniciar subida", + "clearQueue": "Limpiar finalizados", + "removeItem": "Quitar de la cola", + "retry": "Reintentar", + "dropZoneAria": "Suelta archivos aquí o activa para examinar", + "folderEmpty": "No se encontraron archivos en la carpeta soltada", + "summary": "Total: {total} · Con éxito: {succeeded} · Con error: {failed}", + "status": { + "pending": "En espera", + "uploading": "Subiendo", + "success": "Completado", + "error": "Falló", + "cancelled": "Cancelado" + } + }, + "directoryDialog": { + "descriptionAdd": "Selecciona archivos del directorio {path} para añadir a VCS.", + "descriptionRollback": "Selecciona archivos del directorio {path} para revertir.", + "descriptionFallback": "Selecciona archivos para continuar.", + "selectionCount": "Seleccionados {selected} / {total} archivos", + "selectAll": "Seleccionar todo", + "unselectAll": "Deseleccionar todo", + "loadingCandidates": "Cargando cambios del directorio...", + "noOperableFiles": "No hay archivos operables" + }, + "compareDialog": { + "title": "Comparar con rama", + "descriptionWithTarget": "Selecciona una rama y compara con {kind} {path}", + "descriptionFallback": "Selecciona una rama para comparar.", + "kindDirectory": "directorio", + "kindFile": "archivo", + "filterPlaceholder": "Filtra ramas, p. ej. main / origin/main", + "singleClickHint": "Haz clic en una rama para comparar directamente", + "loadingBranches": "Cargando ramas...", + "recentBranches": "Ramas recientes ({count})", + "noCurrentBranch": "Sin rama actual", + "localBranches": "Ramas locales ({count})", + "remoteBranches": "Ramas remotas ({count})", + "noMatchingBranches": "No hay ramas coincidentes" + }, + "externalConflictDialog": { + "title": "Se detectaron cambios externos en archivos", + "descriptionWithPath": "El archivo {path} cambió en disco y las ediciones actuales no están guardadas.", + "descriptionFallback": "El archivo actual cambió en disco y las ediciones actuales no están guardadas.", + "compare": "Comparar", + "savingCopy": "Guardando copia...", + "saveAsCopy": "Guardar como copia", + "reload": "Recargar" + }, + "deleteConfirm": { + "title": "Confirmar eliminación", + "descriptionWithTarget": "¿Eliminar {kind} \"{name}\"? Esta acción no se puede deshacer.", + "descriptionFallback": "Esta acción no se puede deshacer.", + "kindDirectory": "directorio", + "kindFile": "archivo" + }, + "rollbackConfirm": { + "title": "Confirmar reversión", + "descriptionWithTarget": "¿Revertir cambios locales del archivo \"{name}\"?", + "descriptionFallback": "¿Revertir cambios locales de este archivo?" + }, + "terminalTitle": "Consola · {name}" + }, + "commandDropdown": { + "loading": "Cargando...", + "addCommand": "Agregar comando", + "manageCommands": "Gestionar comandos...", + "runCommandTitle": "Ejecutar: {command}", + "stopCommandTitle": "Detener: {command}", + "manageDialog": { + "title": "Gestionar comandos", + "empty": "Aún no hay comandos", + "noResults": "No hay comandos coincidentes", + "searchPlaceholder": "Buscar comandos", + "newCommand": "Nuevo comando", + "nameLabel": "Nombre", + "commandLabel": "Comando", + "dragSort": "Arrastra para ordenar", + "dragSortCommand": "Arrastra para ordenar {name}", + "orderFailed": "No se pudo guardar el orden de los comandos", + "loadFailed": "No se pudieron cargar los comandos", + "saveFailed": "No se pudo guardar el comando", + "deleteFailed": "No se pudo eliminar el comando", + "confirmDelete": { + "title": "¿Eliminar comando?", + "message": "Esto eliminará \"{name}\". Esta acción no se puede deshacer." + } + } + }, + "workspaceContext": { + "confirmCloseDirtyTab": "¿Cerrar \"{title}\" sin guardar?", + "confirmCloseOtherDirtyTabs": "¿Cerrar otras pestañas con cambios sin guardar?", + "confirmCloseAllDirtyTabs": "¿Cerrar todas las pestañas con cambios sin guardar?", + "unableLoadContent": "No se puede cargar el contenido.\n\n{message}", + "previewRequestTimedOut": "La solicitud de vista previa agotó el tiempo", + "diffRequestTimedOut": "La solicitud de Diff agotó el tiempo", + "branchCompareRequestTimedOut": "La solicitud de comparación de ramas agotó el tiempo", + "commitDiffRequestTimedOut": "La solicitud de Diff de commit agotó el tiempo", + "saveRequestTimedOut": "La solicitud de guardado agotó el tiempo", + "reloadRequestTimedOut": "La solicitud de recarga agotó el tiempo", + "noChanges": "Sin cambios.", + "noDiffOutput": "Sin salida de diff.", + "diffTitleWorkspace": "Diferencias · Espacio de trabajo", + "diffDescriptionWorkingTree": "Árbol de trabajo (HEAD)", + "diffTitleFile": "Diferencias · {name}", + "compareTitleFile": "Comparar · {name}", + "compareTitleBranch": "Comparar · {branch}", + "compareDescriptionPath": "{path} · comparar con {branch}", + "compareDescriptionBranch": "comparar con {branch}", + "diffTitleCommitFile": "Diferencias · {name} @ {hash}", + "diffTitleCommit": "Diferencias · {hash}", + "diffDescriptionCommitPath": "{path} · confirmación {commit}", + "diffDescriptionCommit": "confirmación {commit}", + "diffTitleConflictFile": "Conflicto · {name}", + "diffDescriptionConflict": "{path} · disco vs sin guardar" + }, + "chat": { + "acpConnections": { + "actions": { + "openAgentsSettings": "Abrir ajustes de agentes", + "retry": "Reintentar" + }, + "agentsSetupHint": "Abre Ajustes > Agentes para gestionar la instalación.", + "withSetupHint": "{message}\n{hint}", + "blocked": { + "missingConfig": "No se puede leer la configuración actual del agente.", + "disabled": "{agent} está deshabilitado en Ajustes de agentes. Actívalo antes de conectar.", + "unavailable": "{agent} no está disponible en la plataforma actual.", + "sdkMissing": "El SDK de {agent} no está instalado", + "adapterMissing": "El adaptador ACP de {agent} no está instalado" + }, + "backendErrors": { + "initializeTimeout": "Se agotó el tiempo del handshake de conexión de {agent} (sin respuesta tras 60 segundos). Abre Ajustes para revisar la configuración del agente y de la red.", + "mcpRejectedByAgent": "{agent} rechazó la sesión con el complemento MCP de codeg adjunto: {message} Si este agente no admite MCP, desactiva «Compatibilidad con MCP» en Ajustes y vuelve a conectar.", + "processExited": "El proceso de {agent} terminó inesperadamente.", + "spawnFailed": "No se pudo iniciar {agent}: {message}", + "downloadFailed": "La descarga de {agent} falló: {message}", + "sessionLoadResourceNotFound": "Error al cargar la sesión de {agent}. Recarga para reintentar o inicia una nueva conversación.", + "sessionLoadUnavailable": "{agent} no pudo restaurar esta sesión; es posible que haya finalizado o que el agente se haya detenido. Recarga para reintentar o inicia una nueva conversación.", + "turnFailedRefusal": "{agent} rechazó continuar este turno. Suele indicar un error de backend o pasarela. Revisa los registros del agente.", + "turnFailedMaxTokens": "{agent} alcanzó el límite máximo de tokens para este turno.", + "turnFailedMaxTurnRequests": "{agent} alcanzó el número máximo de solicitudes permitidas para este turno.", + "turnFailedUnknown": "{agent} finalizó el turno con un motivo de parada no reconocido.", + "grokModelSwitchIncompatibleAgent": "{agent} no puede cambiar a ese modelo en una conversación existente. Inicia una nueva sesión para usarlo.", + "turnFailedEmpty": "{agent} finalizó el turno sin producir ninguna respuesta.", + "turnFailedEmptyProtocol": "{agent} produjo una salida que codeg no pudo analizar; la versión del agente podría no coincidir con el protocolo.", + "turnFailedEmptyMetadata": "{agent} solo envió actualizaciones de estado en este turno (plan / modo / uso) y ninguna respuesta.", + "detailsInAlerts": "Abre Alertas en la barra de estado y despliega los detalles para ver la salida del agente." + }, + "unableReadAgentConfig": "No se puede leer la configuración del agente: {message}", + "connectFailedTitle": "Falló la conexión de {agent}", + "toolFallbackTitle": "Herramienta", + "eventErrorTitle": "Error del agente", + "notificationTurnComplete": "{agent} ha terminado de responder", + "notificationError": "{agent} error: {message}", + "claudeApiRetry": { + "fallbackError": "authentication_failed", + "retryingWithMax": "reintentando {attempt}/{max}", + "retryingAttempt": "reintentando intento {attempt}", + "retrying": "reintentando", + "nextRetryIn": "siguiente en {seconds}s", + "line": "{error}{status} · {retry}", + "lineWithDelay": "{error}{status} · {retry}, {delay}", + "httpStatus": " (HTTP {status})" + }, + "configOptionAdjusted": "{agent} estableció {option} en {actual} en lugar de {requested}" + }, + "connectionLifecycle": { + "tasks": { + "connectingTitle": "Conectando con {agent}", + "connectingDescription": "Estableciendo conexión", + "loadingSelectorsTitle": "Cargando selectores de {agent}", + "loadingSelectorsDescription": "Obteniendo opciones de modo y configuración de sesión", + "initSessionTitle": "Initializing {agent} session", + "initSessionDescription": "Creating session and loading configuration" + }, + "errors": { + "connectionFailed": "Conexión fallida", + "sendPromptFailed": "No se pudo enviar el mensaje: {error}" + } + }, + "shared": { + "attachedResources": "Recursos adjuntos", + "toolCallFailed": "Falló la llamada de herramienta" + }, + "messageThread": { + "emptyTitle": "Aún no hay mensajes", + "emptyDescription": "Inicia una conversación para ver mensajes aquí" + }, + "chatInput": { + "connecting": "Conectando...", + "agentResponding": "{agent} está respondiendo...", + "sendMessage": "Enviar un mensaje..." + }, + "messageInput": { + "askAnything": "Pregunta lo que sea...", + "removeAttachmentAria": "Quitar {name}", + "attachFiles": "Adjuntar archivos", + "addActions": "Añadir", + "quickMessages": "Mensajes rápidos", + "quickMessagesEmpty": "Aún no hay mensajes rápidos", + "quickMessagesLoading": "Cargando...", + "pasteAsPlainText": "Pegar como texto sin formato", + "cut": "Cortar", + "copy": "Copiar", + "selectAll": "Seleccionar todo", + "pasteUnavailable": "No se pudo leer el portapapeles. Pulsa Ctrl/⌘V para pegar.", + "clipboardWriteFailed": "No se pudo escribir en el portapapeles. Usa el atajo de teclado.", + "quickMessageUntitled": "Sin título", + "liveFeedback": "Comentarios en vivo", + "liveFeedbackDisabledHint": "Disponible mientras el agente trabaja", + "dropFilesToAttach": "Suelta archivos para adjuntar", + "loadingSettings": "Cargando ajustes...", + "loadingMode": "Cargando modo...", + "modeLabel": "Modo", + "toggleOn": "Activado", + "toggleOff": "Desactivado", + "agentSettings": "Ajustes del agente", + "searchModel": "Buscar modelos...", + "searchModelAria": "Buscar modelos", + "modelListLabel": "Modelos", + "noModels": "No se encontraron modelos", + "cancel": "Cancelar", + "send": "Enviar", + "forkAndSend": "Fork y Enviar", + "queueMessage": "Poner en cola", + "steerIntoTurn": "Insertar en el turno actual", + "steerQueuedInstead": "Se puso en cola: se enviará con el siguiente turno.", + "steerFailed": "No se pudo insertar en el turno actual", + "steerAttachmentsUnsupported": "Solo texto: los borradores con adjuntos pasan por la cola.", + "slashCommands": "Comandos de barra", + "slashSearchPlaceholder": "Buscar comandos...", + "slashSearchEmpty": "Sin comandos coincidentes", + "experts": "Expertos", + "office": "Ofimática", + "research": "Investigación", + "attachLocalUpload": "Subir archivo local", + "attachServerFile": "Seleccionar archivo del servidor", + "attachUploadTooLarge": "{names} supera el límite de carga de {limit}MB y se omitió.", + "attachUploadFailed": "Error al subir {names}.", + "attachUploadNotAFile": "{names} no es un archivo regular (directorio o archivo especial) y se omitió.", + "attachUploadQuotaExceeded": "El servidor se quedó sin espacio para subidas; no se pudo cargar {names}.", + "attachUploadInProgress": "Las imágenes aún se están subiendo; inténtalo de nuevo en un momento.", + "mentionEmpty": "Sin coincidencias", + "mentionLoading": "Buscando…", + "mentionListLabel": "Menciones", + "mentionMore": "Más resultados: sigue escribiendo para filtrar", + "mentionCount": "{count, plural, one {# resultado} other {# resultados}}", + "mentionGroupFile": "Archivos", + "mentionGroupAgent": "Agentes", + "mentionGroupSession": "Sesiones", + "mentionGroupCommit": "Commits", + "mentionGroupSkill": "Habilidades" + }, + "messageQueue": { + "addToQueue": "Agregar a la cola", + "saveEdit": "Guardar", + "cancelEdit": "Cancelar edición", + "editItem": "Editar", + "deleteItem": "Eliminar" + }, + "welcomeInputPanel": { + "agentsSettingsPath": "Ajustes > Agentes", + "autoConnectFallback": "Haz clic para abrir {path} y gestionar la instalación.", + "autoConnectAppend": "{message}. Haz clic para abrir {path} y gestionar la instalación.", + "enableAgentFirstPlaceholder": "Habilita al menos un agente antes de iniciar una sesión...", + "prepareSessionFailed": "No se pudo preparar la sesión de chat. Inténtalo de nuevo.", + "createConversationFailed": "No se pudo crear la conversación. Inténtalo de nuevo.", + "askAnythingPlaceholder": "Pregunta lo que sea...", + "agentNotInstalled": "{agent} no está instalado · abre la configuración de Agents para instalarlo", + "agentAdapterNotInstalled": "El adaptador ACP de {agent} no está instalado (es aparte de tu propia CLI) · abre la configuración de Agents para instalarlo" + }, + "welcomePanel": { + "greeting": "¿Qué te gustaría hacer hoy?", + "tips": { + "tileTabs": "Haz clic derecho en una pestaña de conversación y elige Vista en mosaico para comparar varias sesiones lado a lado.", + "pinTab": "Haz doble clic en una pestaña de conversación para fijarla y que una sesión nueva no la reemplace automáticamente.", + "shortcutsNewSearch": "{newConversation} abre una conversación nueva, {searchConversations} busca en el historial.", + "slashAtMention": "Escribe / en la entrada para activar comandos slash, o @ para referenciar un archivo del proyecto.", + "pasteDropFiles": "Pega una captura de pantalla o arrastra un archivo a la entrada para adjuntarlo.", + "queueMessage": "Mientras el agente responde, sigue escribiendo: tu próximo mensaje se pone en cola y se envía al terminar.", + "draftAutoSave": "Los borradores sin enviar se guardan automáticamente por conversación y se restauran al volver.", + "forkSend": "El desplegable del botón de enviar incluye Bifurcar y enviar, que ramifica desde el punto actual a una pestaña nueva.", + "exportConversation": "Haz clic derecho dentro de la conversación para exportarla como Markdown, HTML o imagen.", + "chatChannels": "Conecta Telegram / Lark / WeChat en Ajustes → Canales de chat para continuar desde el móvil.", + "shortcutsAuxPanel": "{toggleAuxPanel} alterna el panel derecho para ver los archivos tocados y los cambios de Git de esta sesión.", + "shortcutsTerminalSidebar": "{toggleTerminal} abre la terminal integrada, {toggleSidebar} alterna la barra lateral.", + "customShortcuts": "Todos los atajos se pueden reasignar en Ajustes → Atajos.", + "webService": "Activa Ajustes → Servicio web para que tu equipo acceda al mismo codeg desde un navegador.", + "fusionMode": "Abre un archivo o diff para mostrarlo automáticamente junto a la conversación.", + "quickMessages": "Abre el botón + junto a la entrada y elige Mensajes rápidos para insertar un fragmento guardado (gestiónalos en Ajustes → Mensajes rápidos).", + "experts": "El botón + tiene un menú Habilidades expertas: carga roles como Depuración o Planificación con un clic.", + "taskBoard": "Las tareas pendientes ejecutan un trabajo de principio a fin: el agente trabaja en su propio worktree y tú revisas el diff antes de fusionar.", + "automations": "Las Automatizaciones ejecutan un prompt guardado según un horario —una revisión nocturna, un informe recurrente— y cada ejecución puede tener su propio worktree.", + "tokenUsage": "Haz clic en el número de conversaciones de la barra de estado para abrir Uso de tokens, desglosado por día, agente, modelo y carpeta.", + "mentionTargets": "@ no solo trae archivos: menciona a otro agente para delegarle una subtarea, o referencia una sesión anterior, un commit o una habilidad.", + "splitGroups": "Haz clic derecho en una pestaña y elige Dividir a la derecha o Dividir abajo para mantener dos conversaciones en paneles propios.", + "worktrees": "Abre el botón de rama y elige Nuevo worktree para que varios agentes trabajen en el mismo repositorio sin pisarse los archivos.", + "importSessions": "¿Ya ejecutaste sesiones en la terminal? El menú de una carpeta tiene Importar sesiones locales para traer ese historial a codeg.", + "subSessions": "Cuando un agente delega, la subsesión aparece anidada bajo él en la barra lateral: despliega la fila para seguir lo que hizo cada una.", + "liveFeedback": "Comentarios en vivo, en el menú +, inserta una nota en el turno que el agente ya está ejecutando, sin interrumpirlo.", + "skillPacks": "Configuración → Paquetes de habilidades reúne expertos de programación, investigación científica y ofimática; actívalos por agente.", + "modelProviders": "Configuración → Proveedores de Modelos acepta tu propia clave de API o endpoint, y el modelo lo eliges desde el cuadro de entrada.", + "workspaceBackground": "Configuración → Apariencia define una imagen de fondo del espacio de trabajo, la opacidad de los paneles y las fuentes de la app." + }, + "quickActions": { + "excel": "Libro de Excel", + "excelDesc": "Tablas, fórmulas y gráficos", + "word": "Documento de Word", + "wordDesc": "Informes, cartas y notas", + "ppt": "Presentación", + "pptDesc": "Diapositivas con diseño profesional", + "pitchDeck": "Pitch Deck", + "pitchDeckDesc": "Presentación de inversión con métricas", + "morph": "Animación Morph", + "morphDesc": "Transiciones de diapositiva cinematográficas", + "morph3d": "Morph 3D", + "morph3dDesc": "Modelos 3D con movimientos de cámara", + "academic": "Artículo académico", + "academicDesc": "Investigación con citas y estructura", + "financial": "Modelo financiero", + "financialDesc": "Estados, DCF y proyecciones", + "dashboard": "Panel de datos", + "dashboardDesc": "KPIs y análisis a partir de tus datos", + "prompts": { + "excel": "Crea un libro de Excel con los siguientes requisitos:\n\n[describe aquí tus datos, tablas, fórmulas y gráficos]", + "word": "Crea un documento de Word con los siguientes requisitos:\n\n[describe aquí el contenido, la estructura y el formato del documento]", + "ppt": "Crea una presentación de PowerPoint con los siguientes requisitos:\n\n[describe aquí tus diapositivas, contenido y diseño]", + "pitchDeck": "Crea un pitch deck de inversión con los siguientes requisitos:\n\n[describe aquí tu empresa, ronda de financiación y métricas clave]", + "morph": "Crea una presentación con animaciones de transición Morph:\n\n[describe aquí el tema de la presentación y los efectos visuales deseados]", + "morph3d": "Crea una presentación Morph 3D con modelos GLB y movimientos de cámara:\n\n[describe aquí tu tema y concepto visual en 3D]", + "academic": "Escribe un artículo académico en Word con los siguientes requisitos:\n\n[describe aquí tu tema de investigación, metodología y hallazgos clave]", + "financial": "Crea un modelo financiero en Excel con los siguientes requisitos:\n\n[describe aquí tus estados financieros, proyecciones y análisis]", + "dashboard": "Crea un panel de datos en Excel con los siguientes requisitos:\n\n[describe aquí tu fuente de datos, KPIs y gráficos]", + "scientific-brainstorming": "Ayúdame a generar ideas de investigación: explora conexiones interdisciplinares, cuestiona supuestos y detecta vacíos prometedores. El área que exploro: ", + "hypothesis-generation": "Ayúdame a convertir estas observaciones en hipótesis comprobables, con predicciones claras, mecanismos plausibles y experimentos para probarlas. Mis observaciones: ", + "experimental-design": "Ayúdame a diseñar un experimento riguroso antes de recolectar datos: el diseño, la aleatorización, los controles y cómo evitar la confusión. Lo que quiero estudiar: ", + "statistical-power": "Ayúdame a determinar el tamaño muestral que necesito: guíame en un análisis de potencia (tamaño del efecto, alfa, potencia) para mi diseño. Detalles: ", + "statistical-analysis": "Ayúdame a analizar estos datos correctamente: elige la prueba adecuada, verifica los supuestos, informa los tamaños de efecto y redáctalo. Mis datos y pregunta: ", + "exploratory-data-analysis": "Haz un análisis exploratorio de mi archivo de datos: resume su estructura, calidad y patrones destacados, y sugiere próximos pasos. El archivo es: ", + "scientific-visualization": "Ayúdame a crear una figura de calidad de publicación: diseño claro, barras de error honestas, una paleta apta para daltónicos y formato de revista. Lo que quiero mostrar: ", + "scientific-critical-thinking": "Ayúdame a evaluar críticamente este estudio o afirmación: valora la calidad de la evidencia, detecta sesgos y confusores, y pondera las conclusiones. Aquí está: ", + "paper-lookup": "Ayúdame a encontrar artículos relevantes y texto completo de acceso abierto en bases de datos académicas, con citas que pueda reutilizar. Busco: " + }, + "paper-lookup": "Búsqueda de artículos", + "paper-lookupDesc": "Busca en 10 API académicas (PubMed, arXiv, OpenAlex, Crossref…) artículos, citas y texto completo de acceso abierto.", + "scientific-critical-thinking": "Pensamiento crítico", + "scientific-critical-thinkingDesc": "Evalúa afirmaciones científicas y calidad de la evidencia: detecta sesgos y confusores, aplica GRADE y riesgo de sesgo.", + "scientific-visualization": "Visualización científica", + "scientific-visualizationDesc": "Figuras listas para publicar: diseños multipanel, anotaciones de significancia y formato específico de revista.", + "exploratory-data-analysis": "Análisis exploratorio de datos", + "exploratory-data-analysisDesc": "Exploración automatizada de archivos de datos científicos en más de 200 formatos con métricas de calidad e informes.", + "statistical-analysis": "Análisis estadístico", + "statistical-analysisDesc": "Análisis estadístico guiado: selección de pruebas, verificación de supuestos, tamaños de efecto e informe estilo APA.", + "statistical-power": "Potencia estadística", + "statistical-powerDesc": "Análisis de tamaño muestral y potencia: cuántos sujetos necesitas, efectos mínimos detectables y curvas de potencia.", + "experimental-design": "Diseño experimental", + "experimental-designDesc": "Diseña estudios rigurosos antes de recolectar datos: aleatorización, bloqueo, controles y diseños factoriales/DOE.", + "hypothesis-generation": "Generación de hipótesis", + "hypothesis-generationDesc": "Convierte observaciones en hipótesis comprobables con predicciones, mecanismos y experimentos para probarlas.", + "scientific-brainstorming": "Lluvia de ideas científica", + "scientific-brainstormingDesc": "Ideación abierta de investigación: explora conexiones interdisciplinares, cuestiona supuestos y detecta vacíos.", + "tabs": { + "office": "Ofimática", + "coding": "Desarrollo de código", + "research": "Investigación" + }, + "coding": { + "brainstormingDesc": "Explora intención y requisitos antes de construir", + "debuggingDesc": "Encuentra la causa raíz antes de proponer arreglos", + "writingSkillsDesc": "Crea, edita y verifica habilidades reutilizables" + }, + "notEnabled": { + "title": "La habilidad «{skill}» aún no está activada para {agent}", + "description": "Actívala en Ajustes para usarla aquí.", + "action": "Activar", + "hint": "Habilidad no activada" + }, + "scrollPrev": "Mostrar habilidades anteriores", + "scrollNext": "Mostrar más habilidades" + } + }, + "agentSelector": { + "noEnabledAgents": "No hay agentes habilitados", + "openAgentsSettings": "Abrir ajustes de agentes", + "notInstalled": "No instalado", + "moreAgents": "Más agentes ({count})" + }, + "subAgentOverlay": { + "title": "Subagentes", + "collapsedSummary": "Subagentes {count}", + "collapseAria": "Contraer subagentes" + }, + "agentPlanOverlay": { + "title": "Plan del agente", + "collapsePlanAria": "Contraer plan", + "collapsedSummary": "Plan de trabajo {completed}/{total}", + "status": { + "completed": "Completado", + "inProgress": "En progreso", + "pending": "Pendiente", + "unknown": "Desconocido" + }, + "priority": { + "high": "Alta", + "medium": "Media", + "low": "Baja", + "unknown": "Desconocida" + } + }, + "permissionDialog": { + "subtitle": "El agente solicita permiso para continuar este turno.", + "queuedCount": "+{count} en espera", + "kindFallbackTool": "herramienta", + "command": "Comando", + "cwd": "Directorio de trabajo: {cwd}", + "filesSummary": "Archivos: {count}", + "moreFiles": "+{count} archivos más", + "plan": "Plan de trabajo", + "allowedActions": "Acciones permitidas", + "targetMode": "Modo objetivo: {mode}", + "optionGrants": "Lo que concede cada opción", + "changeScopeSession": "Esta sesión", + "changeScopeProcess": "Esta ejecución", + "changeScopeUser": "Guardado en la configuración del usuario", + "changeScopeProject": "Guardado en la configuración del proyecto", + "changeScopeProjectLocal": "Guardado en la configuración local del proyecto", + "changeScopePersistent": "Guardado permanentemente" + }, + "questionDialog": { + "title": "El agente está haciendo una pregunta", + "placeholder": "Escribe tu respuesta...", + "send": "Enviar" + }, + "messageBranch": { + "previousBranchAria": "Rama anterior", + "nextBranchAria": "Rama siguiente", + "pageOf": "{current} de {total}" + }, + "terminal": { + "title": "Consola", + "running": "En ejecución" + }, + "reasoning": { + "thinking": "Pensando…", + "thoughtForFewSeconds": "Pensamiento", + "thoughtForSeconds": "Pensamiento" + }, + "linkSafety": { + "errorCannotOpen": "No se puede abrir el archivo local", + "errorNoWorkspace": "No hay ninguna carpeta de espacio de trabajo activa.", + "errorFailedOpen": "Error al abrir el archivo local", + "errorFailedLink": "Error al abrir el enlace", + "errorUnsupportedLinkProtocol": "Este protocolo de enlace no es compatible." + }, + "fileActions": { + "openInFinder": "Abrir en Finder", + "openInExplorer": "Abrir en Explorer", + "openInFileManager": "Abrir en el gestor de archivos", + "copyRelativePath": "Copiar ruta relativa", + "copyAbsolutePath": "Copiar ruta absoluta", + "pathCopied": "Ruta copiada", + "copyPathFailed": "No se pudo copiar la ruta", + "openFailed": "Error al abrir el archivo local" + }, + "messageList": { + "attachedResources": "Recursos adjuntos", + "loading": "Cargando...", + "loadEarlier": "Cargar mensajes anteriores", + "loadingEarlier": "Cargando mensajes anteriores…", + "error": "Error del chat: {message}", + "errorTitle": "Error al cargar la sesión", + "errorActionReload": "Recargar", + "errorActionNewSession": "Nueva conversación", + "emptyConversation": "No hay mensajes en esta conversación.", + "systemMessage": "Mensaje del sistema", + "copyMessage": "Copiar", + "copied": "Copiado", + "downloadImage": "Descargar imagen", + "downloadFailed": "Descarga fallida: {message}", + "imageGeneration": "Generación de imágenes", + "imageGenerationPending": "Generando imagen…", + "imageGenerationFailed": "Error al generar la imagen", + "model": "Modelo", + "tokenStats": "Uso de tokens", + "tokenInput": "Entrada", + "tokenOutput": "Salida", + "tokenCacheRead": "Lectura de caché", + "tokenCacheWrite": "Escritura de caché", + "duration": "Duración", + "completedAt": "Completado a las", + "jumpToPreviousUserMessage": "Ir al mensaje del usuario", + "showMore": "Mostrar más", + "showLess": "Mostrar menos" + }, + "liveTurnStats": { + "thinking": "Pensando...", + "streaming": "Transmitiendo", + "elapsedHours": "{value} h", + "elapsedMinutes": "{value} min", + "elapsedSeconds": "{value} s", + "outputSpeedAria": "Velocidad de salida estimada", + "outputSpeedTooltip": "Velocidad de salida estimada (texto + razonamiento)" + }, + "jsonTree": { + "viewRaw": "Ver JSON sin formato", + "viewTree": "Ver árbol", + "fields": "{count, plural, one {# campo} other {# campos}}", + "items": "{count, plural, one {# elemento} other {# elementos}}" + }, + "tool": { + "parameters": "Parámetros", + "error": "Error de herramienta", + "result": "Resultado", + "status": { + "approvalRequested": "Esperando aprobación", + "approvalResponded": "Respondido", + "inputAvailable": "En ejecución", + "inputStreaming": "Pendiente", + "outputAvailable": "Completado", + "outputDenied": "Denegado", + "outputError": "Error de salida" + } + }, + "toolCallBlock": { + "tool": "Herramienta", + "error": "Error de ejecución", + "result": "Resultado" + }, + "delegation": { + "subAgentRunning": "Subagente en ejecución…", + "noDetail": "No detail available yet.", + "unknownAgent": "Sub-agente", + "openDetail": "Ver conversación", + "detailTitle": "Conversación del subagente", + "detailDescription": "Vista de solo lectura de la conversación del subagente delegado.", + "waitForResult": "Esperando el resultado de la tarea {task}", + "waitForResultNoTask": "Esperando el resultado de la tarea", + "cancelTask": "Cancelando la tarea {task}", + "cancelTaskNoTask": "Cancelando la tarea", + "resultPageOf": "{current} / {total}", + "prevResult": "Resultado anterior", + "nextResult": "Resultado siguiente", + "noResultText": "Sin resultado en esta comprobación.", + "status": { + "starting": "iniciando", + "running": "en curso", + "checked": "consultado", + "waiting": "esperando aprobación", + "ok": "completado", + "err": { + "default": "fallido", + "delegation_disabled": "deshabilitado", + "depth_limit": "límite de profundidad", + "invalid_agent_type": "agente inválido", + "spawn_failed": "fallo al iniciar", + "send_failed": "fallo al enviar", + "timeout": "tiempo agotado", + "canceled": "cancelado", + "child_refusal": "subagente rechazó", + "child_max_tokens": "subagente: límite de tokens", + "child_max_turn_requests": "subagente: límite de solicitudes", + "child_empty": "subagente sin salida", + "child_unknown": "subagente: error", + "unknown": "tarea desconocida" + } + } + }, + "contentParts": { + "showingTailOutput": "Mostrando la salida final durante el streaming para mejorar el rendimiento.", + "result": "Resultado", + "unknown": "desconocido", + "inputTruncated": "La entrada fue truncada — el diff puede estar incompleto.", + "replaceAll": "REEMPLAZAR TODO", + "filesCount": "Archivos: {count}", + "update": "actualizar", + "moreFiles": "+{count} archivos más", + "timeoutMs": "Tiempo de espera: {timeout}ms", + "backgroundTrue": "Segundo plano: true", + "scriptToolCalls": "{count, plural, one {# llamada a herramienta} other {# llamadas a herramientas}}", + "offset": "Desplazamiento: {offset}", + "limit": "Límite: {limit}", + "pages": "Páginas: {pages}", + "mode": "Modo: {mode}", + "cell": "Celda: {cell}", + "shellSession": "Sesión {id}", + "pathLabel": "Ruta:", + "globLabel": "Patrón glob:", + "typeLabel": "Tipo:", + "outputLabel": "Salida:", + "caseInsensitive": "Sin distinguir mayúsculas/minúsculas", + "multiline": "Multilínea", + "promptLabel": "Instrucción", + "subjectLabel": "Asunto", + "taskLabel": "Tarea", + "nameLabel": "Nombre:", + "agentPromptLabel": "Instrucción", + "agentModelLabel": "Modelo", + "agentRunning": "Ejecutando...", + "agentLiveTranscript": "Actividad en vivo", + "agentProgressTools": "{count} llamadas a herramientas", + "agentProgressTurns": "{count} turnos", + "agentProgressContext": "contexto {pct}%", + "agentSessionAction": "Ver la sesión del subagente", + "agentSessionTitle": "Sesión del subagente", + "agentSessionLoading": "Cargando la transcripción del subagente…", + "agentSessionEmpty": "El subagente aún no ha escrito nada.", + "agentFallbackTitle": "Iniciando subagente…", + "agentCodexLaunchOnly": "Lanzado. Codex no informa de más progreso sobre este subagente: su resultado llega como un mensaje en esta conversación.", + "agentStatsBash": "Comandos", + "agentStatsRead": "Archivos leídos", + "agentStatsSearch": "Búsquedas", + "agentStatsEdit": "Ediciones", + "agentStatsOther": "Otros", + "goal": { + "title": "Objetivo:", + "titleWithStatus": "Objetivo {status}", + "objective": "Objetivo", + "statusLabel": "Estado", + "tokensUsed": "Tokens usados", + "budget": "Presupuesto", + "remaining": "Restante", + "elapsed": "Transcurrido", + "tokens": "tokens", + "pause": "Pausar", + "clear": "Borrar", + "status": { + "active": "activo", + "paused": "pausado", + "blocked": "bloqueado", + "usageLimited": "uso limitado", + "budgetLimited": "presupuesto limitado", + "complete": "completo", + "limited": "límite alcanzado" + } + }, + "field": { + "file": "Archivo", + "notebook": "Cuaderno", + "command": "Comando", + "old": "Anterior", + "new": "Nuevo", + "pattern": "Patrón", + "path": "Ruta", + "query": "Consulta", + "url": "URL:", + "description": "Descripción", + "content": "Contenido", + "source": "Fuente", + "prompt": "Instrucción", + "subject": "Asunto", + "taskId": "ID de tarea", + "status": "Estado", + "skill": "Skill", + "args": "Argumentos", + "offset": "Desplazamiento", + "limit": "Límite", + "glob": "Patrón glob", + "type": "Tipo", + "output": "Salida", + "replaceAll": "Reemplazar todo", + "language": "Idioma", + "timeout": "Tiempo de espera", + "background": "Segundo plano", + "agentType": "Tipo de agente", + "library": "Biblioteca", + "libraryId": "ID de biblioteca" + }, + "title": { + "edit": "Editar", + "command": "Comando", + "script": "Script", + "waitCommand": "Esperar {command}", + "waitCell": "Esperar sesión {id}", + "terminateCommand": "Terminar {command}", + "terminateCell": "Terminar sesión {id}", + "stdinChars": "Entrada {chars}", + "todoWrite": "TodoWrite (actualización de tareas)", + "read": "Leer", + "write": "Escribir", + "notebookEdit": "NotebookEdit (edición de cuaderno)", + "editFiles": "Editar ({count} archivos)", + "editWithTarget": "Editar {target}", + "readWithTarget": "Leer {target}", + "writeWithTarget": "Escribir {target}", + "notebookEditWithTarget": "NotebookEdit ({target})", + "globWithPattern": "Patrón glob {pattern}", + "listFilesWithPath": "Listar archivos {path}", + "grepWithPattern": "Patrón grep {pattern}", + "taskCreateWithSubject": "Crear tarea: {subject}", + "taskUpdateWithStatus": "Actualizar tarea #{id} -> {status}", + "taskUpdate": "Actualizar tarea #{id}", + "webFetchWithUrl": "WebFetch ({url})", + "webSearchWithQuery": "Búsqueda web: {query}", + "todosProgress": "Tareas ({done}/{total})", + "skillWithName": "Skill: {name}", + "genericWithContext": "{tool} ({context})" + }, + "search": { + "noMatches": "Sin coincidencias", + "matchSummary": "{matches, plural, one {# coincidencia} other {# coincidencias}} en {files, plural, one {# archivo} other {# archivos}}", + "fileSummary": "{files, plural, one {# archivo} other {# archivos}}", + "moreResults": "{count, plural, one {# resultado más no mostrado} other {# resultados más no mostrados}}" + }, + "toolGroup": { + "search": "{count, plural, one {Exploró # búsqueda} other {Exploró # búsquedas}}", + "command": "{count, plural, one {Ejecutó # comando} other {Ejecutó # comandos}}", + "read": "{count, plural, one {Leyó archivos # vez} other {Leyó archivos # veces}}", + "memory": "{count, plural, one {Recordó # memoria} other {Recordó # memorias}}", + "edit": "{count, plural, one {Editó archivos # vez} other {Editó archivos # veces}}", + "fetch": "{count, plural, one {Recuperó # recurso} other {Recuperó # recursos}}", + "think": "{count, plural, one {Pensó # vez} other {Pensó # veces}}", + "todo": "{count, plural, one {Actualizó # tarea} other {Actualizó # tareas}}", + "task": "{count, plural, one {Ejecutó # tarea} other {Ejecutó # tareas}}", + "other": "{count, plural, one {Usó # herramienta} other {Usó # herramientas}}", + "errorSuffix": "{count, plural, one {# falló} other {# fallaron}}", + "joiner": " · " + }, + "planMode": { + "entered": "Modo de planificación iniciado", + "planLabel": "Plan", + "reviewApproved": "Plan aprobado: implementando", + "reviewKept": "Se mantuvo en modo plan", + "reviewPending": "Esperando la decisión sobre el plan", + "submitted": "Plan enviado", + "switched": "Modo cambiado" + }, + "backgroundTask": { + "title": "Tarea en segundo plano", + "titleWithId": "Tarea en segundo plano · {id}", + "running": "En ejecución", + "completed": "Completada", + "failed": "Fallida", + "stopped": "Detenida", + "exitCode": "salida {code}", + "polledTimes": "Consultada {count} veces", + "runningInBackground": "Segundo plano", + "launchNote": "Ejecutándose en segundo plano · {id}" + }, + "codexScript": { + "outputMissing": "Codex truncó la salida del script y eliminó el separador de este comando, por lo que no se le pudo atribuir ninguna salida.", + "sharedWith": "También contiene la salida de {commands}: codex truncó sus separadores.", + "truncated": "truncado" + } + }, + "messageNav": { + "title": "Navegación de mensajes", + "collapse": "Contraer navegación de mensajes", + "collapsedSummary": "Mensajes {count}", + "fileCount": "{count, plural, one {# archivo} other {# archivos}}", + "remove": "Quitar", + "noDiffDataAvailable": "No hay datos de diff disponibles para {filePath}" + }, + "replyArtifacts": { + "title": "Archivos modificados", + "fileCount": "{count, plural, one {# archivo} other {# archivos}}", + "newFilesTitle": "Archivos nuevos", + "revealInFolder": "Mostrar en el gestor de archivos", + "openFile": "Abrir {filePath}", + "openInEditor": "Abrir en el editor", + "remove": "Quitar", + "noDiffDataAvailable": "No hay datos de diff disponibles para {filePath}" + }, + "askQuestion": { + "title": "El agente necesita tu elección", + "subtitle": "Responde y luego envía. Puedes omitir en cualquier momento.", + "recommended": "Recomendado", + "other": "Otro", + "otherPlaceholder": "Escribe tu respuesta…", + "singleSelect": "Única", + "multiSelect": "Múltiple", + "skip": "Omitir", + "next": "Siguiente", + "submit": "Enviar", + "submitError": "No se pudo enviar. Inténtalo de nuevo." + }, + "planApproval": { + "title": "El agente tiene un plan: revísalo", + "emptyPlan": "El agente no escribió un plan. Aprueba para empezar a construir o solicita cambios.", + "approve": "Aprobar y construir", + "requestChanges": "Solicitar cambios", + "abandon": "Descartar", + "feedbackPlaceholder": "¿Qué debería cambiar?", + "sendChanges": "Enviar", + "cancel": "Cancelar", + "submitError": "No se pudo enviar. Inténtalo de nuevo." + }, + "feedbackCheckResult": { + "count": "{count, plural, =1 {1 comentario} other {# comentarios}}", + "expand": "Mostrar todos los comentarios", + "collapse": "Contraer", + "errorTitle": "Error al comprobar los comentarios" + }, + "askQuestionResult": { + "title": "Pregunta", + "answeredLabel": "Pregunta y respuesta:", + "awaiting": "Esperando tu respuesta…", + "declined": "Descartaste esto: el agente usó su propio criterio.", + "noSelection": "Sin selección" + }, + "configStale": { + "agentConfigTitle": "Configuración del agente actualizada", + "modelProviderTitle": "Proveedor de modelo actualizado", + "description": "Esta sesión sigue usando su configuración anterior. Vuelve a conectarte para aplicarla (se conserva el historial de la conversación).", + "reconnect": "Reconectar para aplicar", + "reconnecting": "Reconectando…", + "reconnectDisabledDuringTurn": "Disponible cuando termine el turno actual", + "dismiss": "Descartar", + "reconnectFailed": "No se pudo reconectar la sesión", + "applied": "Nueva configuración aplicada" + }, + "piProjectTrust": { + "title": "Este proyecto incluye recursos de pi", + "description": "pi no está cargando los archivos .pi del propio repositorio. Revísalos para decidir.", + "descriptionExecutable": "El repositorio incluye extensiones de pi, que ejecutan código al iniciar. pi no las está cargando. Revísalas antes de decidir.", + "review": "Revisar…", + "dismiss": "Descartar", + "dialogTitle": "¿Confiar en los recursos de pi de este proyecto?", + "dialogDescription": "pi solo carga los archivos .pi del propio repositorio si confías en la carpeta. Confía solo si confías en el contenido de este repositorio.", + "executionWarning": "Las extensiones son código. Al confiar en esta carpeta, el repositorio podrá ejecutarlas al iniciar pi con tus permisos, antes de que envíes ningún mensaje.", + "scopeNote": "La decisión se guarda en el trust.json de pi para esta carpeta, se aplica a todas las carpetas que contiene y también se usa cuando ejecutas pi por tu cuenta en una terminal. Puedes cambiarla en Ajustes → Agentes → Pi.", + "trust": "Confiar en el proyecto", + "decline": "Mantener sin cargar", + "disabledDuringTurn": "Disponible cuando termine el turno actual", + "trustedToast": "Proyecto de confianza: se reconectó para que pi cargue sus recursos", + "declinedToast": "Los recursos del proyecto siguen sin cargarse", + "saveFailed": "No se pudo guardar la decisión de confianza del proyecto", + "grantTitle": "Este proyecto ya es de confianza", + "grantDescription": "pi carga los archivos .pi del propio repositorio. Revisa lo que eso permite.", + "grantInheritedDescription": "Una carpeta superior es de confianza, así que pi carga los archivos .pi del propio repositorio. Revisa lo que eso permite.", + "grantDialogTitle": "Los recursos de pi de este proyecto son de confianza", + "grantDialogDescription": "pi tiene permiso para cargar los archivos .pi del propio repositorio. Versiones anteriores de codeg lo concedían automáticamente al abrir una carpeta, así que puede que nunca te lo preguntaran.", + "grantExecutionWarning": "Las extensiones son código. El repositorio las ejecuta al iniciar pi con tus permisos, antes de que envíes ningún mensaje.", + "inheritedFrom": "Confianza heredada de", + "revoke": "Revocar confianza", + "keepTrusted": "Mantener la confianza", + "revokedToast": "Confianza revocada: se reconectó para que pi deje de cargar los recursos del proyecto", + "trustedNoReconnect": "Proyecto de confianza: se aplicará la próxima vez que se inicie pi", + "revokedNoReconnect": "Confianza revocada: se aplicará la próxima vez que se inicie pi" + }, + "collabAgent": { + "title": "Subagente", + "errorTitle": "La tarea del subagente falló", + "statesLabel": "Subagentes", + "statusRunning": "En ejecución", + "statusCompleted": "Completado", + "statusFailed": "Fallido", + "statusPending": "Iniciando", + "statusInterrupted": "Interrumpido", + "statusClosed": "Cerrado", + "statusNotFound": "No encontrado", + "opSpawn": "Iniciando subagente", + "opWait": "Obteniendo resultado del subagente", + "opClose": "Cerrando subagente", + "opResume": "Reanudando subagente" + }, + "contextCompaction": { + "compacting": "Compactando el contexto…", + "compacted": "Contexto compactado", + "compactedTokens": "Contexto compactado · {before} → {after} tokens", + "failed": "Error al compactar el contexto" + }, + "sessionFailure": { + "category": { + "connection": "Problema de conexión", + "access": "Problema de acceso", + "limit": "Límite alcanzado", + "request": "Solicitud rechazada", + "service": "Problema del servicio", + "unknown": "Problema de sesión" + }, + "action": { + "retry": "Reintentar", + "login": "Iniciar sesión", + "newSession": "Nueva sesión" + }, + "recovered": "Recuperado", + "retryUnavailable": "No hay ningún mensaje anterior para reenviar.", + "toggleDetails": "Mostrar u ocultar detalles" + }, + "backgroundTasks": { + "running": "{count, plural, one {# tarea en segundo plano en ejecución} other {# tareas en segundo plano en ejecución}}", + "settling": "Sincronizando resultados en segundo plano…", + "settledFallback": "Tarea en segundo plano finalizada ({status})", + "cardRunning": "Ejecutándose en segundo plano", + "cardLaunchedPending": "Tarea lanzada en segundo plano", + "cardCompleted": "Tarea en segundo plano completada", + "cardFinishedWithStatus": "Tarea en segundo plano finalizada ({status})", + "cardResultPending": "El resultado aún no ha llegado" + }, + "proposedPlan": { + "title": "Plan propuesto", + "planning": "Planificando…" + } + }, + "diffPreview": { + "mode": { + "added": "Añadido", + "deleted": "Eliminado", + "renamed": "Renombrado", + "modified": "Modificado" + }, + "hunkLabel": "Bloque {index}", + "loadingHunk": "Cargando hunk...", + "noDiffData": "Sin datos de diff", + "showRemainingLines": "Mostrar {count} líneas más" + }, + "conversationContextBar": { + "folderTitle": "Carpeta de trabajo", + "branchTitle": "Rama de trabajo", + "searchFolder": "Search folder...", + "searchBranch": "Search branch...", + "noFolders": "No folders", + "noBranches": "No branches", + "noBranch": "(no branch)", + "chatModeLabel": "Modo de chat", + "commit": "Commit", + "push": "Push", + "merge": "Merge", + "toasts": { + "folderChanged": "Switched to {name}", + "openFolderFailed": "Failed to open folder", + "switchedToChatMode": "Cambiado al modo de chat", + "openStashFailed": "Failed to open stash window", + "openMergeFailed": "Failed to open merge window" + } + }, + "cloneDialog": { + "title": "Clonar repositorio", + "repositoryUrl": "URL del repositorio", + "repositoryUrlPlaceholder": "https://github.com/user/repo.git", + "directory": "Directorio", + "directoryPlaceholder": "Selecciona el directorio de destino...", + "browseDirectory": "Explorar directorio", + "cancel": "Cancelar", + "clone": "Clonar", + "clonePath": "Ruta de clonación: {path}" + }, + "toasts": { + "cloneFailed": "No se pudo clonar el repositorio" + } + }, + "ProjectBoot": { + "title": "Inicio de Proyecto", + "tabs": { + "shadcn": "shadcn", + "hyperframes": "HyperFrames" + }, + "hyperframes": { + "title": "Proyecto de vídeo HyperFrames", + "subtitle": "Genera un proyecto de HTML a vídeo. Luego, el agente del espacio de trabajo puede escribirlo y renderizarlo.", + "resolution": "Resolución", + "skillsTitle": "Skills de agentes", + "skillsDesc": "Instala globalmente las skills de HyperFrames (enlace simbólico) para los agentes seleccionados, para que puedan crear y renderizar vídeo.", + "recheck": "Volver a comprobar", + "installedBadge": "Instalado", + "skillsInstall": "Instalar / actualizar skills", + "skillsInstalling": "Instalando skills…", + "skillsInstalled": "Skills de HyperFrames instaladas", + "skillsInstallFailed": "No se pudieron instalar las skills de HyperFrames" + }, + "config": { + "base": "Base", + "style": "Estilo", + "baseColor": "Color base", + "theme": "Tema", + "chartColor": "Color del gráfico", + "iconLibrary": "Biblioteca de iconos", + "font": "Fuente", + "fontHeading": "Fuente de título", + "menuAccent": "Acento del menú", + "menuColor": "Color del menú", + "radius": "Radio", + "template": "Plantilla", + "createProject": "Crear proyecto", + "sectionStyle": "Estilo", + "sectionColors": "Colores", + "sectionTypography": "Tipografía", + "sectionInterface": "Interfaz" + }, + "preview": { + "loading": "Cargando vista previa..." + }, + "createDialog": { + "title": "Crear proyecto", + "projectName": "Nombre del proyecto", + "projectNamePlaceholder": "my-app", + "frameworkTemplate": "Plantilla del framework", + "packageManager": "Gestor de paquetes", + "saveDirectory": "Directorio de guardado", + "saveDirectoryPlaceholder": "Seleccionar directorio...", + "browseDirectory": "Explorar", + "projectPath": "El proyecto se creará en: {path}", + "advancedOptions": "Opciones Avanzadas", + "base": "Biblioteca Base", + "enableRtl": "Habilitar Soporte RTL", + "enableRtlDescription": "Habilitar soporte de diseño para idiomas de derecha a izquierda (ej. árabe, hebreo)", + "pmChecking": "Verificando...", + "pmNotInstalled": "No instalado", + "cancel": "Cancelar", + "create": "Crear", + "creating": "Creando proyecto..." + }, + "toasts": { + "createFailed": "Error al crear el proyecto", + "createSuccess": "Proyecto creado exitosamente", + "openWorkspaceFailed": "Proyecto creado, pero no se pudo abrir en el espacio de trabajo" + }, + "errors": { + "directoryExists": "El directorio de destino ya existe", + "commandFailed": "El comando de creación del proyecto falló." + } + }, + "WebServiceSettings": { + "addressSwitchHint": "Cambiar solo modifica la dirección que se muestra y se abre aquí; el servicio escucha en todas las interfaces y sigue accesible en cada dirección.", + "sectionTitle": "Servicio Web", + "sectionDescription": "Habilitar para acceder a Codeg de forma remota a través del navegador", + "port": "Puerto", + "status": "Estado", + "autoStart": "Inicio automático", + "autoStartHint": "Iniciar el servicio web al abrir Codeg", + "running": "En ejecución", + "stopped": "Detenido", + "processing": "Procesando...", + "start": "Iniciar", + "stop": "Detener", + "startFailed": "Error al iniciar", + "stopFailed": "Error al detener", + "saveConfigFailed": "No se pudo guardar la configuración del servicio web", + "open": "Abrir", + "hide": "Ocultar", + "show": "Mostrar", + "copy": "Copiar", + "qrcode": "Código QR", + "qrcodeTitle": "Escanear para abrir", + "qrcodeHint": "Escanea con tu teléfono para abrir Codeg en el navegador", + "addressLabel": "Dirección de acceso", + "tokenLabel": "Token de acceso", + "tokenHint": "Ingrese este token al acceder al cliente Web por primera vez", + "tokenPlaceholder": "Dejar vacío para generar automáticamente", + "regenerate": "Regenerar", + "stalePortOccupiedTitle": "El puerto {port} está en uso por otro proceso", + "stalePortUnknownTitle": "Estado del puerto {port} indeterminado", + "stalePortHint": "Codeg no puede vincularse hasta que se libere el puerto. Cambia el puerto arriba o cierra el proceso que lo retiene.", + "errors": { + "alreadyRunning": "El servicio Web ya está en ejecución", + "invalidAddress": "Formato de host o puerto no válido", + "portInUse": "El puerto {port} ya está en uso. Cierre el proceso que lo usa o elija otro puerto.", + "permissionDenied": "Permiso denegado. Utilice un puerto superior a 1024 o ejecute con mayores privilegios.", + "addressUnavailable": "La dirección no está disponible en este equipo", + "bindFailed": "No se pudo enlazar la dirección" + } + }, + "DirectoryBrowser": { + "title": "Explorar directorio", + "pathPlaceholder": "Ingrese la ruta del directorio...", + "goHome": "Ir al directorio principal", + "navigateUp": "Ir al directorio superior", + "select": "Seleccionar", + "cancel": "Cancelar", + "loading": "Cargando...", + "emptyDirectory": "Este directorio está vacío", + "errorLoadingDir": "Error al cargar el directorio", + "permissionDenied": "Permiso denegado" + }, + "ChatChannelSettings": { + "loading": "Cargando...", + "sectionTitle": "Canales de chat", + "sectionDescription": "Configure bots de IM para recibir notificaciones de eventos y consultar actividad de codificación.", + "addChannel": "Agregar canal", + "noChannels": "Aún no se han configurado canales de chat.", + "channelName": "Nombre", + "channelNamePlaceholder": "Mi bot de Telegram", + "channelType": "Tipo de canal", + "lark": "Lark (Feishu)", + "weixin": "WeChat", + "dailyReport": "Informe diario", + "dailyReportTime": "Hora del informe", + "nameRequired": "El nombre del canal es obligatorio.", + "tokenRequired": "El token es obligatorio.", + "chatIdRequired": "El Chat ID es obligatorio.", + "topicMode": "Modo de grupo por temas", + "topicModeHint": "Enruta los temas de foros de Telegram como sesiones Codeg separadas. El bot debe estar en un supergrupo de foro y poder administrar temas.", + "loadFailed": "Error al cargar los canales.", + "saveFailed": "Error al guardar los cambios.", + "connectSuccess": "Canal conectado.", + "connectFailed": "Error al conectar", + "disconnectSuccess": "Canal desconectado.", + "disconnectFailed": "Error al desconectar.", + "testSuccess": "Prueba de conexión exitosa.", + "testFailed": "Prueba de conexión fallida", + "deleteSuccess": "Canal eliminado.", + "deleteFailed": "Error al eliminar el canal.", + "deleteConfirmTitle": "Eliminar canal", + "deleteConfirmMessage": "Se eliminará permanentemente el canal y sus registros de mensajes. ¿Está seguro?", + "cancel": "Cancelar", + "delete": "Eliminar", + "create": "Crear", + "save": "Guardar", + "channelListTitle": "Canales configurados", + "channelListDescription": "Los canales habilitados se conectarán automáticamente al iniciar el servicio.", + "editChannel": "Editar canal", + "editSuccess": "Canal actualizado.", + "tokenPlaceholderKeep": "Dejar vacío para mantener actual", + "weixinScanTitle": "Escanear código QR", + "weixinScanDescription": "Abra WeChat y escanee el código QR para conectarse.", + "weixinQrcodeExpired": "El código QR ha expirado.", + "weixinRefreshQrcode": "Actualizar", + "weixinWaitingScan": "Esperando escaneo...", + "weixinPollError": "Conexión inestable, reintentando...", + "weixinReconnectNotice": "Debido a limitaciones del protocolo iLink, después de cada reconexión debes enviar un mensaje al bot para que los activadores de eventos surtan efecto.", + "connect": "Conectar", + "disconnect": "Desconectar", + "test": "Probar conexión", + "tabs": { + "channels": "Canales", + "commands": "Comandos", + "events": "Eventos", + "other": "Otros" + }, + "commands": { + "title": "Comandos integrados", + "description": "Comandos de bot disponibles en los canales de chat. En chats grupales, se requiere @Bot para procesar mensajes.", + "prefixLabel": "Prefijo de comando", + "prefixDescription": "1-3 caracteres no alfanuméricos para activar comandos del bot (por defecto /).", + "prefixSaved": "Prefijo de comando guardado.", + "prefixSaveFailed": "Error al guardar el prefijo.", + "prefixInvalid": "El prefijo debe ser de 1-3 caracteres no alfanuméricos.", + "save": "Guardar", + "folderDesc": "Seleccionar carpeta de trabajo", + "agentDesc": "Seleccionar agente de IA", + "taskDesc": "Crear sesión y ejecutar tarea", + "sessionsDesc": "Listar sesiones activas en la carpeta", + "resumeDesc": "Conversaciones recientes / reanudar una sesión", + "cancelDesc": "Cancelar tarea actual", + "approveDesc": "Aprobar solicitud de permiso del agente", + "denyDesc": "Denegar solicitud de permiso del agente", + "searchDesc": "Buscar conversaciones por palabra clave", + "todayDesc": "Resumen de actividad de hoy", + "statusDesc": "Estado de conexión del canal", + "helpDesc": "Mostrar ayuda" + }, + "events": { + "title": "Notificaciones de eventos", + "description": "Al habilitar eventos, se enviarán al canal cuando se activen.", + "turnComplete": "Turno completado", + "turnCompleteDesc": "Cuando finaliza un turno del agente", + "error": "Error del agente", + "errorDesc": "Cuando un agente encuentra un error", + "permissionRequest": "Solicitud de permiso", + "permissionRequestDesc": "Cuando un agente solicita permiso para actuar", + "questionRequest": "Pregunta del agente", + "questionRequestDesc": "Cuando un agente te hace una pregunta", + "userPromptSent": "Mensaje del usuario", + "userPromptSentDesc": "Cuando envías un mensaje (el texto del mensaje se incluye en la notificación)", + "saved": "Filtro de eventos actualizado.", + "saveFailed": "Error al guardar el filtro de eventos.", + "loadFailed": "No se pudo cargar la configuración.", + "retry": "Reintentar", + "webhooksTitle": "Webhooks", + "webhooksDescription": "Envía una carga JSON por POST a una o varias URL cuando se activa un evento habilitado. El filtro de eventos anterior también se aplica a los webhooks.", + "webhookUrlPlaceholder": "https://example.com/webhook", + "addWebhook": "Agregar webhook", + "removeWebhook": "Eliminar webhook", + "webhookSave": "Guardar", + "webhooksSaved": "Webhooks guardados.", + "webhooksSaveFailed": "Error al guardar los webhooks.", + "webhookInvalidUrl": "Introduce URL http(s) válidas.", + "docsTitle": "Formato de solicitud", + "docsMethod": "Método", + "docsContentType": "Content-Type", + "docsNote": "Cada evento habilitado se entrega a todas las URL. Los webhooks no tienen antirrebote; el filtro de eventos anterior sigue aplicándose.", + "editWebhook": "Editar webhook", + "enableWebhook": "Activar webhook", + "webhookDuplicate": "Esta URL ya está configurada.", + "cancel": "Cancelar", + "webhooksEmpty": "Aún no hay webhooks configurados.", + "deleteWebhookTitle": "Eliminar webhook", + "deleteWebhookMessage": "¿Eliminar este webhook? Los eventos ya no se enviarán a esta URL.", + "delete": "Eliminar" + }, + "language": { + "title": "Idioma de mensajes", + "description": "Idioma utilizado para las notificaciones de eventos, respuestas de comandos e informes diarios enviados a los canales de chat.", + "saved": "Idioma de mensajes guardado.", + "saveFailed": "Error al guardar el idioma de mensajes.", + "en": "Inglés", + "zh-cn": "Chino simplificado", + "zh-tw": "Chino tradicional", + "ja": "Japonés", + "ko": "Coreano", + "es": "Español", + "de": "Alemán", + "fr": "Francés", + "pt": "Portugués", + "ar": "Árabe" + } + }, + "ModelProviderSettings": { + "sectionTitle": "Proveedores de Modelos", + "sectionDescription": "Gestionar las credenciales de proveedores API para agentes.", + "filterAll": "Todos", + "providerListTitle": "Proveedores Configurados", + "addProvider": "Agregar Proveedor", + "editProvider": "Editar Proveedor", + "noProviders": "Aún no se han configurado proveedores de modelos.", + "providerName": "Nombre", + "providerNamePlaceholder": "Ej. OpenAI, Anthropic", + "apiUrl": "URL de API", + "apiUrlPlaceholder": "https://api.openai.com/v1", + "apiKey": "Clave API", + "apiKeyPlaceholder": "sk-...", + "apiKeyKeepCurrent": "Dejar vacío para mantener actual", + "agentTypes": "Tipos de Agente", + "agentTypesRequired": "Se requiere al menos un tipo de agente.", + "agentType": "Tipo de Agente", + "agentTypeRequired": "El tipo de agente es obligatorio.", + "agentTypeImmutableHint": "El tipo de agente no se puede cambiar después de la creación.", + "model": "Modelo", + "modelPlaceholderCodex": "gpt-5.6-sol / gpt-5.5", + "modelPlaceholderGemini": "gemini-3-pro-preview", + "claudeMainModel": "Modelo Principal", + "claudeReasoningModel": "Modelo de Razonamiento (pensamiento)", + "claudeHaikuDefaultModel": "Modelo Haiku Predeterminado", + "claudeSonnetDefaultModel": "Modelo Sonnet Predeterminado", + "claudeOpusDefaultModel": "Modelo Opus Predeterminado", + "claudeCustomModelOption": "ID de modelo personalizado", + "claudeCustomModelOptionName": "Nombre del modelo personalizado", + "claudeCustomModelOptionDescription": "Descripción del modelo personalizado", + "claudeCustomModelOptionHint": "Añade una única entrada personalizada al selector de modelos de Claude (por ejemplo, un modelo detrás de una pasarela/proxy personalizado). El nombre y la descripción son opcionales y solo afectan a la visualización.", + "nameRequired": "El nombre del proveedor es obligatorio.", + "apiUrlRequired": "La URL de API es obligatoria.", + "apiKeyRequired": "La clave API es obligatoria.", + "loadFailed": "Error al cargar proveedores.", + "saveFailed": "Error al guardar cambios.", + "createSuccess": "Proveedor creado.", + "editSuccess": "Proveedor actualizado.", + "deleteSuccess": "Proveedor eliminado.", + "deleteConfirmTitle": "Eliminar Proveedor", + "deleteConfirmMessage": "Esto eliminará permanentemente el proveedor \"{name}\". ¿Está seguro?", + "deleteBlockedByAgent": "{agents} está usando este proveedor. Desvincúlelo antes de eliminarlo.", + "cancel": "Cancelar", + "delete": "Eliminar", + "create": "Crear", + "save": "Guardar", + "affectedRunningSessions": "{count, plural, one {# sesión activa necesita reconectarse para aplicar el cambio} other {# sesiones activas necesitan reconectarse para aplicar el cambio}}" + }, + "SkillMatrix": { + "loading": "Cargando…", + "searchPlaceholder": "Buscar por nombre, id o descripción", + "empty": "Nada que mostrar.", + "emptySearch": "No hay coincidencias para la búsqueda actual.", + "skillColumn": "Habilidad", + "selectAll": "Seleccionar todo lo visible", + "selectSkill": "Seleccionar {name}", + "everything": { + "label": "En bloque", + "enable": "Activar todo (visible)", + "disable": "Desactivar todo (visible)" + }, + "columnMenu": { + "enableAll": "Activar todas las habilidades", + "disableAll": "Desactivar todas las habilidades" + }, + "rowMenu": { + "label": "Acciones en bloque para {name}", + "enableAll": "Activar para todos los agentes", + "disableAll": "Desactivar para todos los agentes" + }, + "bulk": { + "selected": "{count} seleccionados", + "targetAll": "Todos los agentes", + "targetSome": "{count} agentes", + "enable": "Activar", + "disable": "Desactivar", + "clear": "Limpiar" + }, + "confirm": { + "disableTitle": "¿Desactivar estos enlaces?", + "disableBody": "Esto eliminará {count} enlaces de habilidades gestionados por codeg. Las habilidades que ocupan un directorio personalizado no se modifican. Puedes reactivarlas cuando quieras.", + "cancel": "Cancelar", + "confirm": "Desactivar" + }, + "toasts": { + "loadFailed": "No se pudieron cargar los estados de las habilidades", + "applyFailed": "No se pudieron aplicar los cambios", + "enabled": "{count} enlaces activados", + "disabled": "{count} enlaces desactivados", + "enabledPartial": "{ok} activados, {failed} fallidos", + "disabledPartial": "{ok} desactivados, {failed} fallidos" + }, + "detail": { + "enableForAgents": "Activar para agentes", + "preview": "Vista previa de SKILL.md", + "loadingContent": "Cargando contenido…" + }, + "copyModeHint": "Copiado (no enlazado): vuelve a activarlo tras las actualizaciones para la última versión" + }, + "ExpertsSettings": { + "title": "Habilidades de expertos", + "description": "Habilita flujos de trabajo de habilidades cuidadosamente seleccionadas y probadas en la práctica para tus agentes de codificación de IA. Cada experto es una habilidad independiente del proyecto superpowers — codeg gestiona la copia central y la vincula a los agentes que elijas.", + "loading": "Cargando expertos…", + "loadingContent": "Cargando contenido…", + "emptyExperts": "No hay expertos disponibles. Revisa los registros de la aplicación.", + "emptySelection": "Selecciona un experto para ver su contenido y gestionar la activación.", + "emptySearch": "Ningún experto coincide con la búsqueda actual.", + "searchPlaceholder": "Buscar expertos por nombre, ID o descripción", + "enableForAgents": "Habilitar para agentes", + "noAgents": "No se detectaron agentes ACP.", + "copyModeWarning": "Copiado (no vinculado). Vuelve a habilitarlo después de actualizar codeg para obtener la última versión.", + "previewTitle": "Vista previa de SKILL.md", + "categories": { + "discovery": "Descubrimiento y diseño", + "planning": "Planificación", + "execution": "Ejecución", + "quality": "Calidad y pruebas", + "debugging": "Depuración", + "review": "Revisión e integración", + "meta": "Meta" + }, + "states": { + "not_linked": "No habilitado", + "linked_to_codeg": "Habilitado", + "linked_elsewhere": "Bloqueado — existe otro vínculo", + "blocked_by_real_directory": "Bloqueado — una habilidad personalizada ocupa este nombre", + "broken": "Vínculo roto" + }, + "badges": { + "userModified": "Modificado por el usuario" + }, + "actions": { + "openCentralDir": "Abrir carpeta central", + "refresh": "Actualizar" + }, + "toasts": { + "loadFailed": "Error al cargar los detalles del experto", + "enabled": "Experto habilitado para este agente", + "disabled": "Experto deshabilitado para este agente", + "enableFailed": "Error al habilitar el experto", + "disableFailed": "Error al deshabilitar el experto", + "openFolderFailed": "Error al abrir la carpeta" + } + }, + "ScienceSettings": { + "title": "Habilidades de investigación científica", + "description": "Habilita habilidades de investigación científica seleccionadas para tus agentes de código con IA: generación de hipótesis, diseño experimental, estadística, visualización, evaluación crítica y búsqueda bibliográfica. codeg gestiona una copia central y enlaza cada habilidad a los agentes que elijas.", + "loading": "Cargando habilidades científicas…", + "emptySkills": "No hay habilidades científicas disponibles. Revisa los registros de la aplicación.", + "searchPlaceholder": "Buscar habilidades científicas por nombre, id o descripción", + "categories": { + "ideation": "Ideación", + "design": "Diseño de estudios", + "analysis": "Análisis", + "visualization": "Visualización", + "evaluation": "Evaluación", + "literature": "Literatura" + }, + "states": { + "not_linked": "No habilitado", + "linked_to_codeg": "Habilitado", + "linked_elsewhere": "Bloqueado — existe otro vínculo", + "blocked_by_real_directory": "Bloqueado — una habilidad personalizada ocupa este nombre", + "broken": "Vínculo roto" + }, + "badges": { + "userModified": "Modificado por el usuario", + "needsKey": "Requiere clave", + "needsSetup": "Puede requerir configuración" + }, + "actions": { + "openCentralDir": "Abrir carpeta central", + "refresh": "Actualizar" + }, + "toasts": { + "openFolderFailed": "Error al abrir la carpeta" + } + }, + "OfficeToolsSettings": { + "title": "Herramientas Office", + "description": "Gestiona las habilidades de OfficeCLI para crear archivos Excel, Word y PowerPoint. Instala OfficeCLI, sincroniza habilidades y actívalas por agente.", + "loadingContent": "Cargando contenido…", + "emptySkills": "No hay habilidades disponibles. Instala OfficeCLI y sincroniza las habilidades.", + "emptySelection": "Selecciona una habilidad para ver su contenido y gestionar la activación.", + "emptySearch": "No se encontraron habilidades.", + "searchPlaceholder": "Buscar habilidades por nombre, ID o descripción", + "enableForAgents": "Activar para agentes", + "noAgents": "No se detectaron agentes ACP.", + "installFirst": "Instala OfficeCLI primero para activar habilidades.", + "syncFirst": "Sincroniza las habilidades primero para cargar el contenido.", + "noContent": "Sin contenido disponible.", + "copyModeWarning": "Copiado (no vinculado). Vuelve a sincronizar para obtener la última versión.", + "previewTitle": "Vista previa de SKILL.md", + "detection": { + "installed": "Instalado", + "notInstalled": "No instalado", + "notRunnable": "Instalado pero no ejecutable", + "installHint": "Instala OfficeCLI para habilitar las habilidades de generación de documentos de oficina en tus agentes de IA.", + "install": "Instalar", + "uninstall": "Desinstalar", + "syncSkills": "Sincronizar habilidades" + }, + "categories": { + "general": "General", + "presentations": "Presentaciones", + "documents": "Documentos", + "spreadsheets": "Hojas de cálculo" + }, + "states": { + "not_linked": "No activado", + "linked_to_codeg": "Activado", + "linked_elsewhere": "Bloqueado — existe otro enlace", + "blocked_by_real_directory": "Bloqueado — una habilidad personalizada ocupa este nombre", + "broken": "Enlace roto" + }, + "badges": { + "notSynced": "No sincronizado" + }, + "actions": { + "refresh": "Actualizar" + }, + "toasts": { + "loadFailed": "Error al cargar los detalles de la habilidad", + "enabled": "Habilidad activada para este agente", + "disabled": "Habilidad desactivada para este agente", + "enableFailed": "Error al activar la habilidad", + "disableFailed": "Error al desactivar la habilidad", + "installSuccess": "OfficeCLI instalado correctamente", + "installFailed": "Error al instalar OfficeCLI", + "uninstallSuccess": "OfficeCLI desinstalado", + "uninstallFailed": "Error al desinstalar OfficeCLI", + "syncSuccess": "{synced} habilidades sincronizadas", + "syncPartial": "{synced} sincronizadas, {errors} fallidas", + "syncFailed": "Error al sincronizar habilidades" + }, + "autoPreviewLabel": "Abrir vista previa automáticamente", + "autoPreviewHint": "Cuando un agente crea o edita un archivo de Word, Excel o PowerPoint, abre su vista previa en vivo automáticamente." + }, + "SkillPacksSettings": { + "title": "Paquetes de habilidades", + "description": "Paquetes de habilidades seleccionados que codeg gestiona de forma centralizada y vincula a tus agentes de IA: expertos en programación, investigación científica y herramientas de documentos de oficina. Actívalos por agente abajo.", + "tabs": { + "experts": "Expertos", + "science": "Ciencia", + "office": "Herramientas de oficina", + "custom": "Personalizadas" + }, + "actions": { + "openCentralDir": "Abrir carpeta central", + "refresh": "Actualizar" + }, + "toasts": { + "openFolderFailed": "Error al abrir la carpeta" + } + }, + "QuickMessagesSettings": { + "title": "Mensajes rápidos", + "description": "Gestiona fragmentos de mensajes reutilizables. Arrastra para reordenar.", + "loading": "Cargando mensajes rápidos…", + "emptyList": "Aún no hay mensajes rápidos. Haz clic en \"Nuevo\" para crear uno.", + "emptySelection": "Selecciona un mensaje rápido para editar.", + "searchPlaceholder": "Buscar por título o contenido", + "untitled": "Sin título", + "actions": { + "new": "Nuevo", + "save": "Guardar", + "delete": "Eliminar", + "dragSort": "Arrastra para reordenar", + "dragSortMessage": "Arrastra para reordenar mensaje rápido: {name}" + }, + "fields": { + "title": "Título", + "titlePlaceholder": "Asigna un título corto a este mensaje", + "content": "Contenido", + "contentPlaceholder": "Escribe aquí el contenido del mensaje" + }, + "confirmDelete": { + "title": "¿Eliminar mensaje rápido?", + "message": "Esto eliminará permanentemente \"{name}\". ¿Estás seguro?", + "cancel": "Cancelar", + "confirm": "Eliminar" + }, + "toasts": { + "loadFailed": "Error al cargar mensajes rápidos", + "createFailed": "Error al crear el mensaje rápido", + "saveFailed": "Error al guardar el mensaje rápido", + "deleteFailed": "Error al eliminar el mensaje rápido", + "saveOrderFailed": "Error al guardar el orden", + "created": "Mensaje rápido creado", + "saved": "Mensaje rápido guardado", + "deleted": "Mensaje rápido eliminado" + } + }, + "Pet": { + "badge": { + "running": "{count} en ejecución", + "waiting": "{count} esperando aprobación", + "error": "{count} con error" + }, + "panel": { + "title": "Sesiones activas", + "empty": "No hay sesiones activas", + "emptyHint": "Aquí aparecen los agentes en ejecución y los que te necesitan.", + "statusRunning": "En ejecución", + "statusWaiting": "En espera", + "statusError": "Error", + "subAgentOf": "Subagente de" + }, + "menu": { + "scale": "Escala", + "openManager": "Gestionar mascotas", + "close": "Cerrar" + }, + "loadError": "No se pudo cargar la mascota", + "missingPetIdParam": "No hay mascota seleccionada", + "summonButton": "Mascota", + "manager": { + "title": "Mascotas", + "description": "Compañeros flotantes de escritorio con sprites compatibles con Codex.", + "addPet": "Añadir mascota", + "importFromCodex": "Importar desde Codex", + "noPets": "No hay mascotas. Añade una o impórtala desde Codex.", + "setActive": "Activar", + "active": "Activa", + "edit": "Editar", + "delete": "Eliminar", + "deleteConfirm": "¿Eliminar la mascota «{name}»? Se borrará del disco.", + "summon": "Invocar ventana de la mascota", + "openCodexHelp": "Las mascotas de Codex deben estar en ~/.codex/pets/. No se encontraron.", + "specRequirement": "El sprite debe tener 1536px de ancho y una altura múltiplo de 208px (p. ej. 1872 o 2288), en PNG o WebP con transparencia.", + "form": { + "id": "ID de mascota", + "idHelp": "Letras minúsculas, dígitos, '-' y '_'. Máx 64 chars.", + "displayName": "Nombre", + "description": "Descripción (opcional)", + "spritesheet": "Sprite", + "chooseFile": "Elegir archivo", + "replaceFile": "Reemplazar sprite", + "saveCreate": "Añadir mascota", + "saveUpdate": "Guardar cambios", + "cancel": "Cancelar" + }, + "errors": { + "missingId": "Se requiere ID de mascota", + "missingName": "Se requiere nombre", + "missingSpritesheet": "Se requiere sprite", + "addFailed": "Error al añadir la mascota", + "updateFailed": "Error al actualizar", + "deleteFailed": "Error al eliminar", + "loadFailed": "Error al cargar mascotas", + "setActiveFailed": "Error al activar mascota", + "summonFailed": "Error al invocar la ventana de mascota" + } + }, + "import": { + "title": "Importar desde Codex", + "subtitle": "Mascotas disponibles bajo ~/.codex/pets/.", + "selectAll": "Seleccionar todo", + "alreadyImported": "Ya importada", + "renameOnConflict": "Renombrar conflictos con sufijo -imported", + "import": "Importar selección", + "noneFound": "No hay mascotas Codex importables.", + "imported": "Importación correcta", + "failed": "Importación fallida", + "close": "Cerrar" + }, + "marketplace": { + "openMarketplace": "Mercado de mascotas", + "title": "Mercado de mascotas", + "search": "Buscar mascotas", + "kindFilter": { + "all": "Todas", + "object": "Objeto", + "animal": "Animal", + "person": "Persona", + "creature": "Criatura" + }, + "sortFilter": { + "latest": "Recientes", + "popular": "Populares", + "views": "Más vistas" + }, + "refresh": "Actualizar", + "install": "Instalar", + "installing": "Instalando", + "reinstall": "Reinstalar", + "reinstallConfirm": "¿Sobrescribir la mascota local \"{name}\"? Los datos existentes serán reemplazados.", + "cancel": "Cancelar", + "stats": { + "views": "Vistas", + "downloads": "Descargas", + "likes": "Me gusta" + }, + "actions": { + "idle": "Reposo", + "running_right": "Corre der.", + "running_left": "Corre izq.", + "waving": "Saluda", + "jumping": "Salta", + "failed": "Fallo", + "waiting": "Espera", + "running": "Corre", + "review": "Revisa" + }, + "page": "Página {page} de {total}", + "prev": "Anterior", + "next": "Siguiente", + "empty": "No hay mascotas que coincidan.", + "successInstalled": "\"{name}\" instalada", + "errors": { + "loadFailed": "No se pudo cargar el mercado", + "installFailed": "No se pudo instalar la mascota", + "alreadyInstalled": "La mascota ya existe localmente" + } + } + }, + "RemoteWorkspace": { + "openRemoteWorkspace": "Open remote workspace", + "manage": "Manage remote workspace", + "manageTitle": "Remote Workspace connections", + "empty": "No remote connections", + "searchPlaceholder": "Search remote workspaces", + "orderFailed": "Failed to save remote workspace order", + "dragSort": "Drag to sort", + "dragSortConnection": "Drag to sort {name}", + "newConnection": "New connection", + "loading": "Loading", + "loadingConnection": "Loading remote connection", + "name": "Name", + "baseUrl": "Service URL", + "token": "Access token", + "save": "Save", + "delete": "Delete", + "confirmDelete": { + "title": "Delete remote connection?", + "message": "This will remove \"{name}\" from this device. This action cannot be undone.", + "cancel": "Cancel", + "confirm": "Delete" + }, + "saved": "Remote connection saved.", + "deleted": "Remote connection deleted.", + "loadFailed": "Failed to load remote connections", + "saveFailed": "Failed to save remote connection", + "deleteFailed": "Failed to delete remote connection", + "openFailed": "Failed to open remote workspace", + "connectionLoadFailed": "Failed to load remote connection: {message}", + "connectionExpired": "Remote connection \"{name}\" is expired. Update its token and reload this window." + }, + "ServerFileBrowser": { + "title": "Seleccionar archivo del servidor", + "pathPlaceholder": "Introducir ruta de directorio...", + "goHome": "Ir al directorio personal", + "navigateUp": "Ir al directorio superior", + "select": "Seleccionar", + "cancel": "Cancelar", + "loading": "Cargando...", + "emptyDirectory": "Este directorio está vacío", + "errorLoadingDir": "Error al cargar el directorio", + "selectedCount": "{count} seleccionado(s)" + }, + "BackupSettings": { + "title": "Copia de seguridad y restauración", + "description": "Exporta una copia de seguridad portátil de tus datos de codeg, o restaura desde una.", + "tabs": { + "backup": "Copia de seguridad", + "restore": "Restaurar" + }, + "export": { + "includeExternal": "Incluir el contenido de las conversaciones", + "includeExternalHint": "También archiva las transcripciones de las CLI (Claude, Codex, Gemini, …). Aumenta el tamaño.", + "passphrase": "Frase de contraseña (opcional)", + "passphrasePlaceholder": "Déjala vacía para un archivo sin cifrar", + "passphraseConfirm": "Confirmar la frase de contraseña", + "passphraseMismatch": "Las frases de contraseña no coinciden.", + "noPassphraseWarning": "Esta copia contendrá secretos (claves de API, tokens) en texto plano. Guárdala en un lugar seguro.", + "passphraseLossWarning": "Cifrada con esta frase de contraseña. Si la pierdes, la copia no se podrá recuperar.", + "button": "Exportar copia", + "inProgress": "Creando copia de seguridad…", + "success": "Copia de seguridad creada.", + "started": "Descarga de la copia iniciada." + }, + "restore": { + "selectFile": "Seleccionar archivo de copia", + "passphrasePrompt": "Esta copia está cifrada. Introduce su frase de contraseña.", + "unlock": "Desbloquear", + "preview": { + "title": "Detalles de la copia", + "encrypted": "Cifrada", + "compatible": "Compatible", + "incompatible": "Incompatible", + "createdAt": "Creada: {value}", + "appVersion": "Versión de la app: {value}", + "incompatibleHint": "Esta copia fue creada por una versión más reciente de codeg y no se puede restaurar." + }, + "replaceWarning": "Restaurar reemplaza todos los datos actuales de codeg (base de datos y subidas). Tus datos actuales se guardan primero en una instantánea para poder recuperarlos.", + "keyringNote": "Los tokens de GitHub/chat del escritorio están en el llavero del sistema y no se incluyen; vuelve a introducirlos tras restaurar.", + "button": "Restaurar", + "staging": "Preparando la restauración…", + "staged": "Restauración preparada. Reiniciando…", + "restarting": "Restauración preparada. Reiniciando el servidor…", + "restartTimeout": "El servidor no volvió a tiempo. Recarga la página cuando esté activo.", + "externalSideLocation": "Las transcripciones de conversaciones se restauraron en {path}", + "confirmTitle": "¿Reemplazar todos los datos?", + "confirmBody": "Esto reemplazará tu base de datos y subidas actuales de codeg con la copia y luego reiniciará. Tus datos actuales se guardan primero en una instantánea.", + "cancel": "Cancelar", + "confirmAction": "Reemplazar y reiniciar", + "external": { + "title": "Contenido de las conversaciones", + "hint": "Esta copia incluye transcripciones de las CLI. Elige dónde restaurarlas.", + "modeSkip": "No restaurar", + "modeSide": "Restaurar en una carpeta aparte segura", + "modeOriginal": "Restaurar en las ubicaciones originales de las CLI", + "forceOverwrite": "Sobrescribir archivos existentes", + "forceOverwriteHint": "Reemplaza los archivos que ya existen en las carpetas de las CLI.", + "scanning": "Comprobando conflictos…", + "noConflicts": "No se sobrescribirá ningún archivo existente.", + "conflictCount": "Se verían afectados {count} archivo(s) existente(s).", + "conflictSkipNote": "Los archivos existentes se conservan (se omiten) salvo que actives la sobrescritura." + }, + "restartFailed": "La restauración quedó preparada, pero el servidor no pudo reiniciarse. Reinícialo manualmente para aplicarla." + }, + "remoteUnsupported": "La copia de seguridad y la restauración actúan sobre los datos de la máquina que ejecuta codeg. Estás conectado a un espacio de trabajo remoto: gestiona sus copias desde ese servidor directamente." + }, + "backup": { + "restore": { + "error": { + "badPassphrase": "Frase de contraseña incorrecta o copia dañada.", + "corrupted": "El archivo de copia de seguridad está dañado.", + "unknownFormat": "Este archivo no es una copia de seguridad de codeg reconocida.", + "newerVersion": "Esta copia fue creada por codeg {backupVersion}, más reciente que esta versión ({appVersion}).", + "alreadyPending": "Ya hay una restauración preparada. Reinicia para aplicarla antes de preparar otra." + } + }, + "error": { + "diskSpace": "No hay espacio en disco suficiente para completar la operación.", + "cancelled": "La operación fue cancelada." + } + }, + "WebConnection": { + "disconnectedTitle": "Conexión perdida", + "reconnectingDescription": "Intentando volver a conectar con el servidor. Normalmente se recupera solo en unos segundos.", + "reconnectNow": "Volver a conectar ahora", + "sessionExpiredTitle": "Sesión caducada", + "sessionExpiredDescription": "Tu sesión ya no es válida. Inicia sesión de nuevo para continuar.", + "goToLogin": "Ir al inicio de sesión" + }, + "LiveFeedback": { + "placeholder": "Envía una nota a {agent} mientras trabaja…", + "agentFallback": "el agente", + "ariaLabel": "Nota de comentarios en vivo", + "dialogTitle": "Comentarios en vivo", + "dialogDescription": "Envía una nota al agente mientras trabaja. La leerá en su próxima comprobación, sin interrumpir el paso actual.", + "dialogDescriptionInstant": "Envía una nota al agente mientras trabaja. Se inserta de inmediato en el turno actual: el agente la ve al instante.", + "channelDowngraded": "La inserción instantánea no está disponible en esta sesión: tu nota quedó guardada para que el agente la recoja en su próxima consulta.", + "send": "Enviar", + "cancel": "Cancelar", + "pending": "esperando", + "delivered": "recibida", + "turnEndedUnread": "El agente terminó antes de leer tus comentarios.", + "sendAsMessage": "Enviar como mensaje", + "dismiss": "Descartar", + "turnEndedResent": "El turno terminó: se envió como un mensaje nuevo.", + "turnEnded": "El turno ya terminó.", + "submitFailed": "No se pudo enviar tu nota" + }, + "AgentToolsSettings": { + "title": "Herramientas en la conversación", + "description": "Herramientas adicionales que codeg entrega a un agente dentro de una conversación. Se inyectan al iniciar el agente, así que los cambios se aplican a los agentes iniciados después.", + "feedbackLabel": "Comentarios en vivo", + "feedbackHint": "Envía notas y correcciones a un agente mientras trabaja. Si el agente admite la inserción instantánea, tu nota se inserta de inmediato en el turno en curso; de lo contrario, el agente recibe una herramienta para consultar tus comentarios — esos agentes suelen consultarla solo si lo mencionas en tu prompt, por ejemplo añade \"revisa mi feedback en vivo con regularidad\" a tu mensaje.", + "questionLabel": "Preguntar al usuario", + "questionHint": "Permite que los agentes se detengan y te hagan una pregunta de opción múltiple que aparece encima del cuadro de entrada de la conversación. El agente espera hasta que respondas (u omitas).", + "sessionInfoLabel": "Obtener información de sesión", + "sessionInfoHint": "Permite que los agentes consulten una sesión que mencionas en tu mensaje (una insignia de sesión) para leer su título, agente, estado, espacio de trabajo, uso de tokens y mensajes recientes.", + "automationsLabel": "Crear automatizaciones", + "automationsHint": "Guarda la conversación como una automatización que se ejecuta según un horario. Desactivado por defecto: luego inicia agentes por su cuenta.", + "workTasksLabel": "Crear tareas pendientes", + "workTasksHint": "Añade una tarjeta al tablero de pendientes desde la conversación. Desactivado por defecto: escribe estado de la aplicación.", + "save": "Guardar", + "saving": "Guardando…", + "saved": "Ajustes de herramientas guardados", + "saveFailed": "No se pudieron guardar los ajustes de herramientas", + "loadFailed": "Error al cargar: {detail}" + }, + "NotificationSoundSettings": { + "title": "Sonidos de notificación", + "description": "Reproduce un sonido breve cuando se produce un evento del agente. Son los mismos eventos que se envían a los canales de chat; esta configuración solo se aplica a este dispositivo.", + "enableHint": "Desactivado por defecto. Los sonidos solo suenan en la ventana del espacio de trabajo de este navegador o aplicación.", + "volume": "Volumen", + "preview": "Escuchar", + "previewEvent": "Escuchar el sonido de {event}", + "onlyWhenUnfocused": "Solo cuando la ventana no está enfocada", + "onlyWhenUnfocusedHint": "Permanece en silencio mientras estás mirando Codeg.", + "eventsTitle": "Eventos", + "eventsHint": "Elige un tono para cada evento o «Silencio» para omitirlo. Si el mismo evento se repite en pocos segundos, solo suena una vez.", + "toneNone": "Silencio", + "toneChime": "Campanilla", + "toneDing": "Timbre", + "toneBlip": "Pitido", + "tonePop": "Pop", + "toneAlert": "Alerta", + "toneDescend": "Descendente" + }, + "LogsSettings": { + "loading": "Cargando…", + "sectionTitle": "Registros de ejecución", + "sectionDescription": "Visualiza y configura los registros de diagnóstico de la aplicación. Los registros se escriben en archivos locales y se mantienen en memoria para la vista en vivo.", + "captureTitle": "Nivel de registro", + "captureDescription": "Controla cuánto detalle se captura. Los niveles más altos (Debug, Trace) registran más, pero generan registros más grandes. «Desactivado» deshabilita el registro.", + "captureLabel": "Nivel de captura", + "levels": { + "off": "Desactivado", + "error": "Error", + "warn": "Advertencia", + "info": "Información", + "debug": "Depuración", + "trace": "Rastreo" + }, + "viewerTitle": "Registros recientes", + "viewerDescription": "Vista en vivo de los registros recientes. Filtra por nivel o busca texto.", + "searchPlaceholder": "Buscar mensaje u origen…", + "viewLevels": { + "all": "Todos los niveles", + "error": "Error y superior", + "warn": "Advertencia y superior", + "info": "Información y superior", + "debug": "Depuración y superior", + "trace": "Rastreo y superior" + }, + "pause": "Pausar", + "resume": "En vivo", + "refresh": "Actualizar", + "clear": "Limpiar", + "openFolder": "Abrir carpeta", + "shownCount": "{shown} / {total} mostrados", + "empty": "No hay registros para mostrar.", + "levelSaveFailed": "No se pudo guardar el nivel de registro", + "openFolderFailed": "No se pudo abrir la carpeta de registros", + "downloadFailed": "No se pudo descargar el archivo de registro", + "filesTitle": "Archivos de registro", + "filesDescription": "Descarga archivos de registro completos del disco para ver el historial más allá del búfer en vivo.", + "filesEmpty": "Aún no hay archivos de registro.", + "download": "Descargar", + "downloadTruncated": "El archivo es grande; se descargaron los {size} más recientes. El archivo completo está en el directorio de registros.", + "captureEnvLocked": "El nivel de registro está controlado por la variable de entorno RUST_LOG / CODEG_LOG; cámbialo ahí para que surta efecto.", + "targetsTitle": "Anulaciones por módulo", + "targetsDescription": "Establece un nivel distinto para módulos específicos (p. ej. codeg_lib::acp) sin cambiar el nivel global.", + "targetsAdd": "Añadir", + "targetsRemove": "Quitar anulación", + "toggleDetails": "Mostrar detalles" + }, + "Automations": { + "title": "Automatizaciones", + "new": "Nueva automatización", + "empty": "Aún no hay automatizaciones", + "emptyHint": "Crea una para ejecutar una tarea del agente de forma programada o manual.", + "name": "Nombre", + "namePlaceholder": "p. ej. Revisión nocturna de PR", + "prompt": "Instrucción", + "promptPlaceholder": "¿Qué debe hacer el agente?", + "agent": "Agente", + "folder": "Carpeta del espacio de trabajo", + "folderPlaceholder": "Selecciona una carpeta", + "isolation": "Aislamiento", + "isolationWorktree": "Nuevo worktree por ejecución", + "isolationShared": "Ejecutar en la carpeta", + "isolationSharedCaveat": "Las ejecuciones usan directamente el árbol de trabajo de esta carpeta y pueden entrar en conflicto con tus cambios sin confirmar. Activa la opción de árbol de trabajo para aislar cada ejecución.", + "trigger": "Activador", + "triggerSchedule": "Programado", + "triggerManual": "Solo manual", + "cron": "Programación (cron)", + "cronPlaceholder": "0 9 * * 1-5", + "timezone": "Zona horaria", + "nextRun": "Próxima ejecución", + "branch": "Rama", + "branchOptional": "Rama (opcional)", + "enabled": "Activado", + "save": "Guardar", + "cancel": "Cancelar", + "edit": "Editar", + "delete": "Eliminar", + "runNow": "Ejecutar ahora", + "cancelRun": "Cancelar ejecución", + "runHistory": "Historial de ejecuciones", + "noRuns": "Aún no hay ejecuciones", + "allFolders": "Todas las carpetas", + "filterAll": "Todos", + "noMatches": "No hay automatizaciones que coincidan", + "viewConversation": "Ver conversación", + "lastRun": "Última ejecución", + "never": "Nunca", + "running": "En ejecución", + "deleteTitle": "¿Eliminar la automatización?", + "deleteDescription": "Esto elimina la automatización y su programación. Se conserva el historial.", + "statusRunning": "En ejecución", + "statusSucceeded": "Correcta", + "statusFailed": "Fallida", + "statusCancelled": "Cancelada", + "statusSkipped": "Omitida", + "errorName": "El nombre es obligatorio", + "errorPrompt": "La instrucción es obligatoria", + "errorCron": "Las automatizaciones programadas requieren una expresión cron", + "errorFolder": "Selecciona una carpeta del espacio de trabajo", + "presetHourly": "Cada hora", + "presetDaily": "Diario 9:00", + "presetWeekdays": "Días laborables 9:00", + "presetCustom": "Personalizado", + "probing": "Cargando opciones…", + "retry": "Reintentar", + "configNone": "Este agente no tiene opciones configurables", + "inherit": "Predeterminado del agente", + "mode": "Modo", + "config": "Configuración", + "branchPlaceholder": "(rama predeterminada)", + "selectHint": "Selecciona una automatización para ver los detalles", + "refresh": "Actualizar", + "onboardTitle": "Automatiza tareas rutinarias del agente", + "onboardHint": "Programa un agente para revisar código, actualizar dependencias o clasificar incidencias, de forma periódica o bajo demanda.", + "headerSubtitle": "Tareas del agente programadas y bajo demanda", + "startFromTemplate": "Empezar con una plantilla", + "blankTitle": "Automatización en blanco", + "blankDesc": "Configura una tarea del agente desde cero.", + "backToTemplates": "Plantillas", + "sectionSchedule": "Programación y destino", + "sectionTarget": "Destino", + "sectionAction": "Acción", + "actionLaunchSession": "Ejecutar sesión", + "actionEnqueueTask": "Encolar tarea", + "actionEnqueueTaskHint": "Cada disparo añade una tarea pendiente, titulada como esta automatización, a las tareas pendientes de la carpeta; el motor de tareas la ejecuta según la configuración del tablero.", + "sectionPrompt": "Prompt", + "nextIn": "Próxima en {rel}", + "manual": "Manual", + "schedEveryMinutes": "Cada {n} minutos", + "schedHourly": "Cada hora", + "schedDaily": "Cada día a las {time}", + "schedWeekdays": "Días laborables a las {time}", + "schedWeekly": "Cada {day} a las {time}", + "schedMonthly": "Cada mes el día {day} a las {time}", + "dow0": "domingo", + "dow1": "lunes", + "dow2": "martes", + "dow3": "miércoles", + "dow4": "jueves", + "dow5": "viernes", + "dow6": "sábado", + "tplCodeReviewTitle": "Revisión de código", + "tplCodeReviewDesc": "Revisa los cambios recientes en busca de errores, regresiones y problemas de calidad.", + "tplDependencyUpdatesTitle": "Actualización de dependencias", + "tplDependencyUpdatesDesc": "Encuentra dependencias desactualizadas y propón actualizaciones seguras.", + "tplTestCoverageTitle": "Cobertura de pruebas", + "tplTestCoverageDesc": "Encuentra rutas de código sin probar y añade las pruebas que faltan.", + "tplTodoSweepTitle": "Revisión de TODO", + "tplTodoSweepDesc": "Recopila los comentarios TODO y FIXME y clasifícalos por prioridad.", + "tplCiTriageTitle": "Clasificación de CI", + "tplCiTriageDesc": "Investiga las comprobaciones fallidas recientes y propón soluciones.", + "tplReleaseNotesTitle": "Notas de la versión", + "tplReleaseNotesDesc": "Resume los cambios desde la última versión en un registro de cambios.", + "tplSecurityAuditTitle": "Auditoría de seguridad", + "tplSecurityAuditDesc": "Busca vulnerabilidades y patrones de riesgo, y reporta los hallazgos.", + "enable": "Activar", + "disable": "Desactivar", + "moreActions": "Más acciones", + "statusDisabled": "Desactivada", + "cronBuilderTitle": "Generador de programación", + "cronFreqLabel": "Frecuencia", + "cronFreqMinutes": "Cada N minutos", + "cronFreqHourly": "Cada hora", + "cronFreqDaily": "Diario", + "cronFreqWeekdays": "Días laborables", + "cronFreqWeekly": "Semanal", + "cronFreqMonthly": "Mensual", + "cronFreqCustom": "Personalizado", + "cronEveryLabel": "Intervalo (minutos)", + "cronTimeLabel": "Hora", + "cronHourLabel": "Hora", + "cronMinuteLabel": "Minuto", + "cronDowLabel": "Día de la semana", + "cronDomLabel": "Día del mes", + "cronApply": "Aplicar", + "cronPreviewLabel": "Vista previa", + "cronOpenBuilder": "Abrir el generador de programación", + "branchDefault": "Rama predeterminada", + "branchUseCustom": "Usar «{query}»", + "branchLocal": "Local", + "branchRemote": "Remota", + "branchSearchPlaceholder": "Buscar ramas…", + "branchNone": "Sin ramas" + }, + "Tasks": { + "title": "Tareas pendientes", + "new": "Nueva tarea", + "empty": "Aún no hay tareas", + "emptyHint": "Añade un pendiente y ejecútalo: el agente trabaja en un worktree aislado y tú revisas y fusionas el resultado.", + "emptyColTodo": "Aún no hay pendientes", + "emptyColInProgress": "Nada en curso", + "emptyColAttention": "Nada requiere tu acción", + "emptyColDone": "Aún no hay completadas", + "allFolders": "Todas las carpetas", + "showCanceled": "Mostrar canceladas", + "showArchived": "Mostrar archivadas", + "filter": "Filtrar", + "viewSwitchToBoard": "Cambiar a vista de tablero", + "viewSwitchToList": "Cambiar a vista de lista", + "statusFilter": "Estado", + "statusFilterAll": "Todos los estados", + "listEmpty": "Ninguna tarea coincide con los filtros actuales", + "listColStatus": "Estado", + "listColTask": "Tarea", + "listColLocation": "Ubicación", + "listColChanges": "Cambios", + "listColUpdated": "Actualizado", + "colTodo": "Pendientes", + "colInProgress": "En curso", + "colAttention": "Requiere tu acción", + "colDone": "Completadas", + "statusTodo": "Pendiente", + "statusQueued": "En cola", + "statusPreparing": "Preparando", + "statusRunning": "En ejecución", + "statusAwaitingInput": "Esperando entrada", + "statusReview": "Por revisar", + "statusMerging": "Fusionando", + "statusDone": "Completada", + "statusFailed": "Fallida", + "statusCanceled": "Cancelada", + "statusInterrupted": "Interrumpida", + "badgeCleanupFailed": "Limpieza fallida", + "badgeWorktreeKept": "Worktree conservado", + "badgeWorktreeRemoved": "Worktree eliminado", + "filesChanged": "{count} archivos", + "actionStart": "Iniciar", + "actionSchedule": "Programar", + "actionCancel": "Cancelar", + "actionRetry": "Reintentar", + "actionRequeue": "Reencolar", + "actionViewSession": "Ver conversación", + "actionEdit": "Editar", + "actionDelete": "Eliminar", + "actionRetryCleanup": "Reintentar limpieza", + "actionMerge": "Fusionar", + "actionUnqueueMerge": "Salir de la cola de fusión", + "actionEditQueuedMerge": "Editar la fusión en cola", + "badgeMergeQueued": "En cola para fusionar", + "badgeMergeQueuedRank": "En cola para fusionar · n.º {rank}", + "badgeMergeQueuedHint": "Esperando a que termine la fusión en curso del proyecto; esta empezará sola.", + "actionComplete": "Completar", + "actionAbandon": "Abandonar", + "cancelTitle": "¿Cancelar la tarea?", + "cancelDescription": "La tarea pasa a Cancelada. Su worktree se conserva y podrás reencolarla más tarde.", + "cancelReasonLabel": "Motivo (opcional)", + "cancelReasonPlaceholder": "P. ej. enfoque equivocado: voy a reescribir la descripción", + "cancelKeep": "Mejor no", + "cancelSubmit": "Cancelar tarea", + "restartTitleRetry": "Reintentar la tarea", + "restartTitleRequeue": "Reencolar la tarea", + "restartDescription": "Puedes añadir una nota (opcional): llega al prompt de la próxima ejecución.", + "scheduleTitle": "Programar tarea", + "scheduleDescription": "La tarea sigue en Pendientes y se inicia sola a la hora que elijas. El límite de concurrencia de la carpeta se sigue aplicando.", + "scheduleDateLabel": "Fecha", + "schedulePickDate": "Elegir fecha", + "scheduleTimeLabel": "Hora", + "schedulePreview": "Se ejecuta el {time}", + "schedulePastHint": "Esa hora ya pasó: la tarea empezará en cuanto guardes.", + "scheduleInAnHour": "En 1 hora", + "scheduleInThreeHours": "En 3 horas", + "scheduleTomorrow": "Mañana 9:00", + "scheduleClear": "Quitar programación", + "scheduleBadge": "Inicio programado para el {time}", + "toastScheduled": "Programada para el {time}", + "toastScheduleCleared": "Programación eliminada", + "actionFollowUp": "Continuar", + "actionAddNote": "Añadir una nota", + "followUpSubmit": "Enviar", + "followUpIntentRevise": "Corregir", + "followUpIntentContinue": "Seguir", + "followUpIntentQuestion": "Preguntar", + "followUpIntentVerify": "Revisar", + "followUpPlaceholderRevise": "¿Qué debe cambiar el agente? Continúa en la misma sesión.", + "followUpPlaceholderContinue": "¿Qué sigue? Lo hecho hasta ahora se mantiene.", + "followUpPlaceholderQuestion": "¿Qué quieres saber? El agente responde sin tocar ningún archivo.", + "followUpPlaceholderVerify": "Opcional: ¿algo que deba revisar con atención?", + "followUpPlaceholderRetry": "Opcional: ¿qué debe hacer distinto? P. ej. ejecutar pnpm install primero", + "followUpPlaceholderRequeue": "Opcional: ¿por qué lo cancelaste y qué debe cambiar esta vez?", + "actionArchive": "Archivar", + "actionUnarchive": "Desarchivar", + "archiveAllDone": "Archivar todo", + "dropToStart": "Suelta para iniciar", + "errorView": "Ver", + "notifyReview": "Listo para revisar: {title}", + "notifyFailed": "La tarea falló: {title}", + "createFromMessage": "Crear tarea desde el mensaje", + "detailTokens": "Tokens totales", + "editorTitleNew": "Nueva tarea", + "editorTitleEdit": "Editar tarea", + "templates": "Plantillas", + "templatesEmpty": "Aún no hay plantillas.", + "templateSaveCurrent": "Guardar como plantilla", + "templateDelete": "Eliminar plantilla", + "transcriptTitle": "Conversación de la tarea", + "transcriptDescription": "Vista en vivo de solo lectura de la sesión del agente de la tarea.", + "phaseWork": "Ejecución", + "phaseRetry": "Reintento", + "phaseReturn": "Continuación", + "phaseMerge": "Fusión", + "titleLabel": "Título", + "titlePlaceholder": "¿Qué hay que hacer?", + "promptLabel": "Descripción de la tarea", + "promptPlaceholder": "Describe la tarea para el agente — @ para referenciar archivos, / para comandos", + "folderPlaceholder": "Selecciona una carpeta", + "agentInheritedHint": "Heredado de la configuración de tareas; cámbialo para personalizar esta tarea", + "agentOverrideReset": "Volver a heredar", + "sectionTarget": "Destino", + "errorTitle": "El título es obligatorio", + "errorPrompt": "La descripción es obligatoria", + "errorFolder": "Selecciona una carpeta", + "save": "Guardar", + "cancel": "Cancelar", + "mergeTitle": "Fusionar tarea", + "mergeQueuedTitle": "Fusión en cola", + "mergeQueueHint": "Otra tarea de este proyecto se está fusionando ahora. Esta entra en la cola y empezará sola en cuanto la otra termine.", + "mergeQueueUpdateHint": "Esta tarea ya está esperando para fusionarse. Al enviar se actualiza y conserva su lugar en la cola.", + "mergeDescription": "Fusionar {branch} en {base}. Los cambios sin confirmar del worktree se confirman primero.", + "mergeMessage": "Mensaje de commit", + "mergeMessagePlaceholder": "p. ej. feat: add login validation", + "mergeAutoMessage": "Dejar que el agente escriba el mensaje de commit", + "strategySquash": "Combinar en un solo commit", + "strategySquashHint": "Todos los cambios de la tarea llegan a la rama principal como una sola entrada del historial: un historial más limpio.", + "strategyMerge": "Conservar todo el historial", + "strategyMergeHint": "Se conserva cada commit hecho durante la tarea, más una entrada de fusión: cada paso queda rastreable.", + "mergeDeleteWorktree": "Eliminar el worktree tras fusionar", + "mergeSubmit": "Fusionar", + "mergeSubmitQueue": "Añadir a la cola", + "mergeQueuedToast": "Añadida a la cola de fusión: empezará en cuanto termine la fusión actual.", + "completeTitle": "Completar tarea", + "completeDescription": "Esta tarea no cambió ningún archivo, así que no hay nada que fusionar: se marca como completada directamente.", + "completeDescriptionNoWorktree": "El worktree de esta tarea fue eliminado, así que ya no se puede fusionar: se marca como completada directamente. Una rama de trabajo que aún tenga commits sin fusionar se conserva.", + "completeDeleteWorktree": "Eliminar el worktree al completar", + "completeSubmit": "Completar", + "settingsTitle": "Ajustes de tareas", + "settingsDescription": "Valores por defecto para las tareas de {folder}.", + "settingsScope": "Ámbito", + "settingsScopeGlobal": "Todas las carpetas (valores globales)", + "settingsScopeGlobalHint": "Las carpetas sin configuración propia usan estos valores globales.", + "settingsSource": "Origen de configuración", + "settingsSourceGlobal": "Valores globales", + "settingsSourceCustom": "Personalizada", + "settingsSourceGlobalFollow": "Sigue la configuración global de tareas; los cambios allí se aplican aquí automáticamente.", + "settingsSourceCustomHint": "Guarda configuración propia para esta carpeta y deja de seguir los valores globales.", + "settingsAgent": "Agente por defecto", + "settingsMaxConcurrent": "Tareas concurrentes máx.", + "settingsMaxConcurrentHint": "0 = sin límite", + "settingsAutoProcess": "Procesar automáticamente", + "settingsAutoProcessHint": "Las tareas pendientes se inician solas, hasta el límite de concurrencia.", + "settingsMergeStrategy": "Estrategia de fusión por defecto", + "settingsMergeStrategyHint": "Cómo se registran los cambios de la tarea en el historial de la rama al fusionar.", + "settingsAutoMerge": "Fusionar automáticamente", + "settingsAutoMergeHint": "Una tarea que llega a revisión con cambios que integrar se fusiona como si pulsaras Fusionar: el agente escribe el mensaje de commit y el worktree sigue el valor por defecto de abajo. Si la verificación falla o una fusión falló, la tarea queda esperándote.", + "settingsDeleteWorktree": "Eliminar el worktree tras fusionar", + "settingsDeleteWorktreeHint": "Marca la opción por defecto en el diálogo de fusión; aún puedes cambiarla allí.", + "settingsWorktreeRoot": "Ubicación del worktree", + "settingsWorktreeRootHint": "Directorio donde se crean los worktrees de las tareas nuevas, uno por tarea. Déjalo vacío para crearlos junto a la carpeta del proyecto; «~» es tu carpeta personal y una ruta relativa se resuelve respecto a la carpeta del proyecto.", + "settingsWorktreeRootPlaceholder": "~/codeg-worktrees", + "settingsWorktreeRootBrowse": "Elegir el directorio de worktrees", + "settingsPreflight": "Comando de verificación", + "settingsPreflightHint": "Se ejecuta en el worktree cuando una tarea llega a revisión.", + "settingsPreflightCustomPlaceholder": "pnpm test", + "settingsInitCommand": "Comando de inicialización del worktree", + "settingsInitCommandHint": "Se ejecuta en un worktree recién creado antes de iniciar el agente.", + "settingsInitCommandPlaceholder": "pnpm install", + "settingsTabGeneral": "General", + "settingsTabMerge": "Fusión", + "settingsTabWorktree": "Worktree", + "settingsTabPrompts": "Prompts", + "settingsPromptsIntro": "Cada etapa ya envía su propio prompt integrado: la tarea, las reglas del worktree y, al fusionar, los pasos exactos de git. Lo que añadas aquí se agrega al final como instrucciones extra: matiza esos textos integrados, nunca los sustituye.", + "settingsPromptStageAll": "Todas las fases", + "settingsPromptPlaceholderAll": "p. ej. Sigue las convenciones de AGENTS.md; que el resumen final no pase de dos frases", + "settingsPromptPlaceholderWork": "p. ej. Lee primero las pruebas relacionadas; haz commits pequeños sobre la marcha", + "settingsPromptPlaceholderRetry": "p. ej. Revisa qué hay ya commiteado antes de continuar; no rehagas lo terminado", + "settingsPromptPlaceholderReturn": "P. ej. Atiende cada punto planteado; no refactorices nada ajeno", + "settingsPromptPlaceholderMerge": "p. ej. Escribe el mensaje del commit de integración en español; señala los conflictos que resolviste a mano", + "settingsPromptHintAll": "Se añade a todos los prompts que recibe el agente, incluida la fusión.", + "settingsPromptHintWork": "Se añade cuando una tarea se ejecuta por primera vez.", + "settingsPromptHintRetry": "Se añade al retomar una tarea interrumpida o fallida.", + "settingsPromptHintReturn": "Se añade cuando continúas una tarea en revisión (corregir, ampliar, revisar).", + "settingsPromptHintMerge": "Se añade cuando el agente integra la tarea en la rama base.", + "preflightPassed": "{name} superado", + "preflightFailed": "{name} falló", + "preflightRunning": "{name} en ejecución…", + "detailDescription": "Detalle de la tarea", + "detailSummary": "Resultado", + "detailFiles": "Archivos modificados", + "detailDiffAll": "Ver diff completo", + "detailDiffAllTitle": "Diff completo", + "detailNoChanges": "Aún no hay cambios respecto a la base", + "detailTimeline": "Progreso", + "detailTimelineEmpty": "Sin actividad todavía", + "showMore": "Ver más", + "showLess": "Ver menos", + "detailInfo": "Detalles", + "detailBranch": "Rama", + "detailMergeCommit": "Commit de fusión", + "detailChanges": "Cambios", + "detailScheduled": "Inicio programado", + "detailCreated": "Creada", + "detailStarted": "Iniciada", + "detailFinished": "Finalizada", + "diffLoading": "Cargando diff…", + "deleteConfirmTitle": "¿Eliminar la tarea?", + "deleteConfirmBody": "“{title}” se quitará del tablero. Una ejecución activa se cancela primero.", + "deleteWithWorktree": "Eliminar también su worktree", + "eventCreated": "Creada", + "eventStatusChanged": "Cambio de estado", + "eventConfigEffective": "Configuración de arranque", + "eventInitCommand": "Comando de inicialización", + "eventAgentProgress": "Progreso del agente", + "eventAgentVerdict": "Veredicto del agente", + "eventMergeAttempt": "Fusión iniciada", + "eventMergeQueued": "En cola para fusionar", + "eventMergeConflict": "Conflicto de fusión", + "eventPreflight": "Verificación", + "eventCleanupFailed": "Fallo al limpiar el worktree", + "eventResumeFallback": "La reanudación falló; se usó una sesión nueva", + "eventUserAction": "Acción del usuario", + "eventDiffStat": "Instantánea de cambios" + }, + "CustomSkillsSettings": { + "loading": "Cargando habilidades personalizadas…", + "category": "Personalizadas", + "searchPlaceholder": "Buscar habilidades personalizadas por nombre, ID o descripción", + "states": { + "not_linked": "No habilitada", + "linked_to_codeg": "Habilitada", + "linked_elsewhere": "Vinculada en otro lugar", + "blocked_by_real_directory": "Bloqueada por una carpeta real", + "broken": "Enlace roto" + }, + "actions": { + "new": "Nueva", + "import": "Importar", + "importFromAgent": "Importar de un agente", + "cancel": "Cancelar", + "save": "Guardar" + }, + "rowMenu": { + "edit": "Editar", + "duplicate": "Duplicar", + "delete": "Eliminar" + }, + "bulk": { + "delete": "Eliminar seleccionadas" + }, + "editor": { + "createTitle": "Nueva habilidad personalizada", + "editTitle": "Editar habilidad personalizada", + "description": "Las habilidades personalizadas se guardan en el almacén compartido (~/.codeg/skills) y pueden habilitarse para cualquier agente.", + "idLabel": "ID de habilidad", + "idPlaceholder": "p. ej. my-workflow", + "contentLabel": "SKILL.md", + "contentPlaceholder": "Escribe aquí el SKILL.md de la habilidad…", + "preview": "Vista previa", + "edit": "Editar", + "emptyBody": "Aún no hay contenido." + }, + "duplicate": { + "title": "Duplicar habilidad", + "description": "Crea una copia de «{id}» con un nuevo ID.", + "newIdPlaceholder": "Nuevo ID de habilidad", + "confirm": "Duplicar" + }, + "import": { + "title": "Elige una carpeta de habilidad para importar" + }, + "importFromAgent": { + "title": "Importar habilidades de un agente", + "description": "Copia las habilidades propias de un agente al almacén compartido para poder activarlas en cualquier agente.", + "agentLabel": "Agente", + "agentPlaceholder": "Selecciona un agente", + "selectAll": "Seleccionar todo ({count})", + "loading": "Cargando las habilidades del agente…", + "unsupported": "Este agente no expone un directorio de habilidades.", + "empty": "Este agente no tiene habilidades que importar.", + "alreadyInLibrary": "En la biblioteca", + "confirm": "Importar seleccionadas ({count})" + }, + "delete": { + "title": "¿Eliminar habilidades personalizadas?", + "body": "Se eliminarán {count} habilidad(es) personalizada(s) del almacén central y se desvincularán de todos los agentes. Esta acción no se puede deshacer.", + "confirm": "Eliminar" + }, + "toasts": { + "loadFailed": "No se pudo cargar la habilidad", + "idRequired": "Introduce un ID de habilidad", + "created": "Habilidad personalizada creada", + "updated": "Habilidad personalizada actualizada", + "saveFailed": "No se pudo guardar la habilidad", + "imported": "Habilidad importada", + "importFailed": "No se pudo importar la habilidad", + "duplicated": "Habilidad duplicada", + "duplicateFailed": "No se pudo duplicar la habilidad", + "deleted": "Se eliminaron {count} habilidad(es)", + "deletedPartial": "{ok} eliminadas, {failed} fallidas", + "deleteFailed": "No se pudieron eliminar las habilidades", + "importedFromAgent": "Se importaron {count} habilidad(es)", + "importedFromAgentPartial": "Importadas {ok}, {failed} con error", + "importFromAgentAllSkipped": "Nada que importar: {count} ya están en la biblioteca", + "importFromAgentFailed": "No se pudo importar del agente" + } + }, + "CodexModelEditor": { + "customizedNotice": "Has personalizado la lista de modelos, así que ahora codeg gestiona toda la tabla de modelos de codex. Los modelos oficiales que codex añada después no aparecerán automáticamente: haz clic en el botón actualizar de abajo y guarda de nuevo para sincronizarlos. Borra tus personalizaciones para que codex vuelva a actualizarse automáticamente.", + "officialsTitle": "Modelos oficiales", + "officialsHint": "Se incluyen automáticamente del codex que ejecutas; elimina los que no quieras.", + "officialsEmpty": "No hay modelos oficiales disponibles.", + "refresh": "Actualizar desde codex", + "readdOfficial": "Volver a añadir oficial", + "customsTitle": "Modelos personalizados", + "customsEmpty": "Aún no hay modelos personalizados.", + "addCustom": "Agregar personalizado", + "slugPlaceholder": "id del modelo (slug)", + "displayNamePlaceholder": "Nombre visible", + "contextWindow": "Contexto", + "makeDefault": "Establecer como predeterminado", + "defaultHint": "Modelo predeterminado", + "remove": "Eliminar", + "advanced": "Avanzado", + "baseTemplate": "Plantilla base", + "baseTemplateHint": "Modelo oficial del que clonar los campos obligatorios (prompt del sistema, herramientas, límites).", + "groupBehavior": "Comportamiento y capacidades", + "fieldReasoningLevel": "Razonamiento predeterminado", + "fieldReasoningSummary": "Resumen de razonamiento", + "fieldVerbosity": "Nivel de detalle", + "fieldShellType": "Tipo de shell", + "fieldApplyPatch": "Herramienta apply-patch", + "fieldReasoningSummaries": "Resúmenes de razonamiento", + "fieldSupportVerbosity": "Control de detalle", + "fieldParallelToolCalls": "Llamadas a herramientas en paralelo", + "fieldSearchTool": "Herramienta de búsqueda web", + "optNone": "Ninguno", + "groupInstructions": "Descripción y prompt del sistema", + "fieldDescription": "Descripción", + "baseInstructions": "Prompt del sistema (base_instructions)" + }, + "DiagnosticsSettings": { + "title": "Diagnóstico del entorno", + "description": "Comprueba cómo esta app resuelve la CLI del agente en su propio proceso, que puede diferir de tu terminal.", + "loading": "Ejecutando diagnóstico…", + "error": "El diagnóstico falló", + "rerun": "Volver a ejecutar", + "copyAll": "Copiar todo", + "copied": "Diagnóstico copiado al portapapeles", + "button": "Diagnosticar", + "verdict": { + "ok": "El entorno parece correcto. Si aún aparece como no instalado, reinicia por completo la app para actualizar la caché del prefijo.", + "node_missing": "No se encontró Node.js en el PATH de la app.", + "npm_missing": "No se encontró npm en el PATH de la app.", + "not_installed": "Este agente no parece estar instalado.", + "installed_but_unresolved": "Consta como instalado, pero la app no puede localizar su ejecutable.", + "user_prefix_not_on_path": "Se instaló en el prefijo de reserva (~/.codeg/npm-global), que no está en el PATH de la app. Reinicia por completo la app e inténtalo de nuevo.", + "homebrew_bin_not_on_path": "Se instaló en el bin de Homebrew, que no está en el PATH de la app (división de keg en Apple Silicon).", + "terminal_only_path": "El comando se resuelve en tu terminal pero no en la app: una diferencia de PATH de la GUI. Inicia la app desde una terminal o reinstala desde Ajustes de agentes.", + "npm_prefix_timeout": "npm prefix -g fue demasiado lento (más de 1,5 s), por lo que se omitió la detección de reserva. Reinicia la app e inténtalo de nuevo.", + "node_too_old": "Tu Node.js activo es más antiguo de lo que requiere este agente. Actualiza Node.js.", + "adapter_missing_native_present": "Tu CLI de {agent} sí está instalada, pero Codeg ejecuta un paquete adaptador ACP aparte, y ese todavía no lo está. Instálalo desde la configuración de agentes: no toca tu CLI y comparte la misma sesión.", + "adapter_missing": "Codeg ejecuta un paquete adaptador ACP aparte para {agent} y aún no está instalado. Instálalo desde la configuración de agentes: instalar solo la CLI del proveedor no basta." + } + }, + "TokenUsage": { + "title": "Uso de tokens", + "rangeLabel": "Periodo", + "range7d": "7 días", + "range30d": "30 días", + "range90d": "90 días", + "rangeThisMonth": "Este mes", + "rangeThisYear": "Este año", + "rangeAll": "Todo", + "rangeCustom": "Personalizado", + "moreRanges": "Más", + "customRangePick": "Elegir un intervalo", + "bucketLabel": "Agrupar por", + "bucketDay": "Día", + "bucketWeek": "Semana", + "bucketMonth": "Mes", + "bucketUnitDay": "Día", + "bucketUnitWeek": "Semana", + "bucketUnitMonth": "Mes", + "folderFilter": "Carpetas", + "allFolders": "Todas las carpetas", + "agentFilter": "Agentes", + "allAgents": "Todos los agentes", + "modelFilter": "Modelos", + "allModels": "Todos los modelos", + "searchPlaceholder": "Buscar…", + "noMatches": "Sin coincidencias", + "clearFilter": "Borrar selección", + "resetFilters": "Restablecer filtros", + "refresh": "Actualizar", + "rebuild": "Reconstruir todo", + "rebuildHint": "Descarta lo contabilizado y vuelve a leer todas las transcripciones. Útil si una sesión creció fuera de codeg.", + "syncing": "Contando sesiones…", + "syncProgress": "{done} / {total}", + "syncDone": "{synced} sesiones contabilizadas", + "syncFailed": "No se pudieron leer algunas sesiones", + "syncBusy": "Ya hay una actualización en curso", + "lastSynced": "Actualizado {time}", + "lastSyncedNever": "Nunca actualizado", + "tileTotal": "Tokens totales", + "tileSessions": "Sesiones", + "tileTurns": "Turnos", + "tileActiveDays": "Días activos", + "tileGenTime": "Tiempo de generación", + "vsPrevious": "frente al periodo anterior", + "deltaNew": "nuevo", + "trendTitle": "Uso en el tiempo", + "trendEmpty": "Sin uso en este periodo", + "trendTurns": "Turnos", + "trendSessions": "Sesiones", + "compositionTitle": "En qué se fueron los tokens", + "compositionHint": "La entrada es lo que enviaste, la salida lo que escribió el modelo y las lecturas de caché son contexto que no pagaste a precio completo.", + "compositionNote": "Reenviar esos aciertos de caché a precio completo habría costado otros {value}.", + "inputTokens": "Entrada", + "outputTokens": "Salida", + "cacheWrite": "Escritura de caché", + "cacheRead": "Lectura de caché", + "freshTokens": "Cómputo nuevo", + "cacheHitCaption": "Acierto de caché", + "cacheHeroTitleHigh": "La mayoría del contexto no se reenvió", + "cacheHeroTitleLow": "La mayoría del contexto aún se calcula a precio completo", + "cacheHeroDesc": "La caché cargó con {cached} de contexto; solo {fresh} se calculó de nuevo en este periodo.", + "cacheSavedSuffix": "Eso ahorró reenviar el equivalente a {saved}.", + "avgPerSession": "Media por sesión", + "avgTurnsPerSession": "{count} turnos por sesión de media", + "avgPerActiveDay": "Media por día activo", + "peakBucket": "{bucket} con más uso", + "peakHour": "Hora punta", + "daysValue": "{count} días", + "idleDays": "Días sin actividad", + "byFolderTitle": "Por carpeta", + "byAgentTitle": "Por agente", + "byModelTitle": "Por modelo", + "distributionTitle": "Distribución del uso", + "distributionHint": "Sesiones y tokens agrupados por la dimensión elegida; haz clic en una fila para filtrar por ella.", + "otherLabel": "Otros", + "unknownModel": "Modelo sin registrar", + "emptyBreakdown": "Todavía sin registros", + "sessionsCount": "{count} sesiones", + "heatmapTitle": "Cuándo programas", + "heatmapHint": "Tokens por día de la semana y hora local.", + "heatmapPeakHint": "La franja más densa ronda las {hour}:00.", + "less": "Menos", + "more": "Más", + "heatmapCell": "{weekday} {hour}:00 — {value} tokens", + "weekMon": "Lun", + "weekTue": "Mar", + "weekWed": "Mié", + "weekThu": "Jue", + "weekFri": "Vie", + "weekSat": "Sáb", + "weekSun": "Dom", + "topSessionsTitle": "Sesiones más costosas", + "untitledSession": "Sesión sin título", + "topSessionsEmpty": "Sin sesiones en este periodo", + "streakLongest": "Racha más larga", + "streakLongestDays": "Racha más larga: {count} días", + "share": "Compartir", + "moreActions": "Más acciones", + "shareDialogTitle": "Comparte tu tarjeta de uso", + "shareDialogHint": "Una instantánea del periodo y los filtros que estás viendo.", + "shareSave": "Guardar imagen", + "shareCopy": "Copiar imagen", + "shareCopied": "Copiado al portapapeles", + "shareSaved": "Imagen guardada", + "shareFailed": "No se pudo crear la imagen", + "shareRendering": "Generando…", + "cardHeading": "Mis estadísticas de código con IA", + "cardRangeAll": "Todo el tiempo", + "cardTotalLabel": "Tokens usados", + "cardFooter": "Hecho con codeg", + "cardTopModels": "Modelos principales", + "cardTopProjects": "Proyectos principales", + "archetypeNightOwl": "Ave nocturna", + "archetypeNightOwlDesc": "El {percent}% de tus tokens se quema de noche.", + "archetypeEarlyBird": "Madrugador", + "archetypeEarlyBirdDesc": "El {percent}% de tus tokens cae antes de las 9.", + "archetypeWeekendWarrior": "Guerrero de fin de semana", + "archetypeWeekendWarriorDesc": "El {percent}% de tus tokens ocurre el fin de semana.", + "archetypeCacheMaster": "Maestro de la caché", + "archetypeCacheMasterDesc": "El {percent}% de tu contexto vino de la caché.", + "archetypeMarathoner": "Maratoniano", + "archetypeMarathonerDesc": "{days} días programando sin parar.", + "archetypePolyglot": "Polivalente", + "archetypePolyglotDesc": "{count} agentes en rotación seria.", + "archetypeLaserFocus": "Foco láser", + "archetypeLaserFocusDesc": "El {percent}% de tus tokens fue a un solo proyecto.", + "archetypeDeepDiver": "Buceador", + "archetypeDeepDiverDesc": "{averageK}K tokens en una sesión media.", + "archetypeSteady": "Constructor constante", + "archetypeSteadyDesc": "{days} días entregando.", + "emptyTitle": "Todavía no hay nada contabilizado", + "emptyHint": "Codeg lee los tokens directamente de la transcripción de cada agente. Actualiza para contabilizar lo que ya hay en esta máquina.", + "emptyAction": "Contabilizar mis sesiones", + "loadFailed": "No se pudo cargar el uso", + "truncatedNotice": "Este periodo es muy amplio: las cifras cubren solo su tramo más reciente." + } +} diff --git a/src/i18n/messages/fr.json b/src/i18n/messages/fr.json index 7b0d92303..4d73c8849 100644 --- a/src/i18n/messages/fr.json +++ b/src/i18n/messages/fr.json @@ -1,4958 +1,4958 @@ -{ - "Language": { - "followSystem": "Suivre le système", - "english": "Anglais", - "simplifiedChinese": "Chinois simplifié", - "traditionalChinese": "Chinois traditionnel", - "japanese": "Japonais", - "korean": "Coréen", - "spanish": "Espagnol", - "german": "Allemand", - "french": "Français", - "portuguese": "Portugais", - "arabic": "Arabe" - }, - "GitCredentialDialog": { - "title": "Authentification requise", - "description": "Le serveur distant nécessite des identifiants. Entrez votre nom d'utilisateur et votre mot de passe (ou jeton d'accès personnel).", - "username": "Nom d'utilisateur", - "usernamePlaceholder": "Nom d'utilisateur ou e-mail", - "password": "Mot de passe / Jeton", - "passwordPlaceholder": "Mot de passe ou jeton d'accès personnel", - "passwordHint": "Entrez le nom d'utilisateur et le mot de passe du serveur.", - "cancel": "Annuler", - "authenticate": "Authentifier", - "authenticating": "Authentification...", - "invalidCredentials": "Identifiants invalides. Veuillez réessayer.", - "saveCredentials": "Enregistrer les identifiants pour les opérations futures", - "githubTitle": "Authentification GitHub", - "githubDescription": "Entrez un jeton d'accès personnel pour vous connecter à GitHub. Le jeton sera validé et enregistré automatiquement.", - "githubToken": "Jeton d'accès personnel", - "githubTokenPlaceholder": "ghp_xxxxxxxxxxxx", - "githubTokenHint": "Générez un jeton dans GitHub → Settings → Developer settings → Personal access tokens.", - "githubAuthenticate": "Valider et connecter", - "generateToken": "Générer un jeton" - }, - "SettingsShell": { - "title": "Paramètres", - "preferences": "Préférences", - "nav": { - "general": "Général", - "appearance": "Apparence", - "agents": "Agents IA", - "mcp": "MCP", - "skills": "Skills", - "shortcuts": "Raccourcis", - "version_control": "Contrôle de version", - "system": "Système", - "chat_channels": "Canaux de chat", - "web_service": "Service Web", - "model_providers": "Fournisseurs de Modèles", - "experts": "Experts", - "science": "Science", - "office_tools": "Outils bureautiques", - "skill_packs": "Packs de compétences", - "quick_messages": "Messages rapides", - "logs": "Journaux d'exécution" - } - }, - "AppearanceSettings": { - "sectionTitle": "Apparence du thème", - "sectionDescription": "Choisissez clair, sombre ou suivre le système. Les paramètres sont enregistrés automatiquement.", - "themeMode": "Mode du thème", - "placeholder": "Sélectionner le mode du thème", - "system": "Suivre le système", - "light": "Clair", - "dark": "Sombre", - "currentTheme": "Thème effectif actuel : {theme}", - "resolvedTheme": { - "light": "Clair", - "dark": "Sombre", - "unknown": "--" - }, - "themeColor": { - "sectionTitle": "Couleur du thème", - "sectionDescription": "Choisissez une palette pour les accents, les boutons et les surlignages.", - "current": "Couleur actuelle : {color}", - "options": { - "neutral": "Neutre", - "zinc": "Zinc", - "slate": "Ardoise", - "stone": "Pierre", - "gray": "Gris", - "red": "Rouge", - "rose": "Rose", - "orange": "Orange", - "green": "Vert", - "blue": "Bleu", - "yellow": "Jaune", - "violet": "Violet" - } - }, - "customStyle": { - "sectionTitle": "Style personnalisé", - "sectionDescription": "Ajustez les couleurs du thème actuel ou injectez votre propre CSS. Les remplacements se superposent au préréglage de base et sont conservés lorsque vous en changez.", - "summarySuspended": "Suspendu", - "summaryDefault": "Préréglage inchangé", - "summaryTokens": "{count, plural, one {# remplacement} other {# remplacements}}", - "summaryCss": "CSS personnalisé", - "suspendedByShortcut": "Le style personnalisé est suspendu. Rien de ce que vous réglez ici ne s'appliquera tant que vous ne l'aurez pas réactivé.", - "suspendedBySafeParam": "Cette fenêtre a été ouverte en mode d'apparence sûre : le style personnalisé y est ignoré. Les autres fenêtres ne sont pas affectées.", - "resume": "Réactiver le style personnalisé", - "enableTheme": "Activer les couleurs personnalisées", - "editingLight": "Vous modifiez les valeurs du mode clair. Passez l'application en mode sombre pour le régler séparément.", - "editingDark": "Vous modifiez les valeurs du mode sombre. Passez l'application en mode clair pour le régler séparément.", - "resetToken": "Rétablir la valeur du préréglage", - "radius": "Rayon des coins", - "radiusHint": "Toute l'échelle de rayons, de sm à 4xl, en découle : un seul curseur arrondit l'application entière.", - "advanced": "Avancé ({count} variables de plus)", - "enableCss": "Activer le CSS personnalisé", - "cssRisk": "Fonction avancée. Le CSS personnalisé remplace tous les styles intégrés et peut rendre l'interface inutilisable.", - "editCss": "Modifier le CSS…", - "cssPresent": "{size} Ko enregistrés", - "cssEmpty": "Rien d'enregistré pour l'instant", - "escapeHint": "Interface cassée ? Appuyez sur {shortcut} pour suspendre tout le style personnalisé, ou ouvrez une fenêtre avec le paramètre safeStyle=1.", - "copyTheme": "Copier le JSON du thème", - "importTheme": "Importer un thème…", - "clearTheme": "Effacer les remplacements", - "interopHint": "Les thèmes utilisent le format registry:theme de shadcn : collez ici n'importe quel thème shadcn, et réutilisez les vôtres dans n'importe quel projet shadcn.", - "importTitle": "Importer un thème", - "importDescription": "Collez un élément registry:theme de shadcn, un simple objet light/dark, ou une table de tokens à plat.", - "readClipboard": "Lire le presse-papiers", - "importConfirm": "Importer", - "cancel": "Annuler", - "apply": "Appliquer", - "toasts": { - "copied": "JSON du thème copié", - "copyFailed": "Impossible de copier dans le presse-papiers", - "clipboardReadFailed": "Impossible de lire le presse-papiers, collez manuellement", - "importFailed": "Ce JSON ne contient aucune variable de thème utilisable", - "imported": "Thème importé" - }, - "css": { - "dialogTitle": "CSS personnalisé", - "dialogDescription": "S'applique à toutes les fenêtres codeg. Les modifications sont prévisualisées en direct ; cliquez sur Appliquer pour enregistrer.", - "size": "{used} Ko / {max} Ko", - "ruleCount": "{count} règles", - "errorTooLarge": "Trop volumineux pour être enregistré. Réduisez-le sous la limite.", - "errorImportEscaped": "Une règle @import a survécu au retrait (syntaxe échappée). Supprimez-la pour enregistrer.", - "warnNoRules": "Aucune règle analysée, vérifiez la syntaxe.", - "noticeImportsRemoved": "Règles @import supprimées : {count}. Elles chargeraient des feuilles de style distantes.", - "noticeRemoteUrl": "Contient une url() distante, qui déclenchera une requête réseau une fois appliquée.", - "noticePreviewSuspended": "Le style personnalisé est suspendu, cet aperçu n'est donc pas appliqué.", - "noticeDisabled": "Le CSS personnalisé est désactivé. Vous pouvez prévisualiser ici, mais rien ne s'appliquera avant activation.", - "hintTokens": "Astuce : vos couleurs remplacées sont accessibles via var(--primary), var(--background), etc." - } - }, - "zoomLevel": { - "sectionTitle": "Zoom de la fenêtre", - "sectionDescription": "Met à l'échelle toute l'interface. S'applique immédiatement et est enregistré par appareil.", - "placeholder": "Sélectionnez le niveau de zoom", - "default": "Par défaut", - "current": "Zoom actuel : {zoom}%" - }, - "fonts": { - "sectionTitle": "Polices", - "sectionDescription": "Choisissez les polices pour l’interface, l’éditeur de code et le terminal. Les polices intégrées sont chargées à la demande ; sélectionnez « Personnalisée… » pour utiliser n’importe quelle police installée sur votre système.", - "interface": "Interface", - "editor": "Éditeur", - "terminal": "Terminal", - "groupSans": "Sans empattement", - "groupMono": "Monospace", - "custom": "Personnalisée…", - "customPlaceholder": "Nom de la police, par ex. Fira Code", - "fontSize": "Taille de police", - "ligatures": "Activer les ligatures", - "ligaturesUnavailable": "Cette police n’a pas de ligatures", - "wordWrap": "Activer le retour à la ligne", - "terminalLigaturesHint": "Les ligatures du terminal ne s’appliquent qu’aux polices de programmation intégrées.", - "preview": "Aperçu" - }, - "welcomePanel": { - "sectionTitle": "Zone de sélection du mode", - "sectionDescription": "Les cartes de raccourci « Développement / Bureautique » affichées au-dessus du champ de saisie sur la page de nouvelle conversation.", - "showQuickActions": "Afficher sur la page de nouvelle conversation" - }, - "workspaceBackground": { - "sectionTitle": "Arrière-plan de l'espace de travail", - "sectionDescription": "Affiche une image derrière tout l'espace de travail. La barre latérale et les panneaux deviennent translucides et dépolis pour laisser transparaître l'image, et un masque préserve la lisibilité du texte.", - "enable": "Activer l'image d'arrière-plan", - "image": "Image", - "chooseImage": "Choisir une image", - "replaceImage": "Remplacer l'image", - "removeImage": "Supprimer", - "fillMode": "Mode de remplissage", - "fillModes": { - "cover": "Remplir", - "contain": "Ajuster", - "center": "Centrer", - "tile": "Mosaïque" - }, - "maskOpacity": "Opacité du masque", - "maskOpacityHint": "Des valeurs élevées fondent l'image vers la couleur d'arrière-plan du thème, améliorant le contraste du texte.", - "imageBlur": "Flou de l'image", - "panelOpacity": "Opacité des panneaux", - "panelOpacityHint": "Opacité de la barre latérale, des panneaux et des barres d'onglets. Plus c'est bas, plus l'image transparaît.", - "errorTooLarge": "L'image est trop volumineuse (16 Mo maximum).", - "errorUploadFailed": "Échec de la définition de l'image d'arrière-plan." - } - }, - "SystemSettings": { - "loading": "Chargement...", - "sectionTitle": "Gestion du système", - "sectionDescription": "Gérez le proxy réseau, les mises à jour de l’app et les préférences de langue.", - "proxyTitle": "Proxy réseau", - "proxyDescription": "Lorsqu’il est activé, les requêtes réseau suivantes utilisent ce proxy en priorité (y compris le chat ACP, l’installation d’agents et les opérations Git distantes).", - "loadFailed": "Échec du chargement : {message}", - "enableProxy": "Activer le proxy système", - "proxyAddress": "Adresse du proxy", - "proxyHint": "Prend en charge http(s)/socks5, exemple : {example}. Actif uniquement lorsque le proxy système est activé.", - "save": "Enregistrer", - "saving": "Enregistrement...", - "proxyRequired": "L’URL du proxy est requise lorsque le proxy est activé", - "saveSuccess": "Les paramètres du proxy système ont été enregistrés", - "saveFailed": "Échec de l’enregistrement : {message}", - "languageTitle": "Langue", - "languageDescription": "Définissez la langue de l’app. En mode système, les langues non prises en charge reviennent à l’anglais.", - "appLanguage": "Langue de l’app", - "languageSaveSuccess": "Les paramètres de langue ont été enregistrés", - "languageSaveFailed": "Échec de l’enregistrement des paramètres de langue : {message}", - "updateTitle": "Mise à jour de l’app", - "versionTitle": "Mise à jour logicielle", - "updateDescription": "Vérifiez les nouvelles versions depuis la source de publication configurée et installez-les directement si disponibles.", - "currentVersion": "Version actuelle", - "upgradableVersion": "Dernière version", - "none": "Aucune", - "lastChecked": "Dernière vérification : {time}", - "updateError": "Erreur de mise à jour : {message}", - "checking": "Vérification...", - "checkUpdate": "Rechercher les mises à jour", - "updating": "Installation...", - "downloading": "Téléchargement...", - "upgradeTo": "Mettre à jour vers v{version}", - "viewRelease": "Voir la version v{version}", - "foundUpdate": "Nouvelle version v{version} trouvée", - "alreadyLatest": "Vous utilisez déjà la dernière version", - "checkUpdateFailed": "Échec de la recherche de mises à jour : {message}", - "installSuccess": "Mise à jour installée. Redémarrage de l’app.", - "installFailed": "Échec de la mise à jour : {message}", - "upgradeSuccess": "Mise à niveau terminée. Rechargement...", - "restartTimeout": "Le serveur n'est pas revenu à temps. Consultez les journaux du conteneur ou du service.", - "restartingIn": "Redémarrage dans {seconds} s...", - "waitingForServer": "En attente du retour du serveur...", - "restartToUpdate": "Redémarrer pour mettre à jour", - "newVersionBadge": "Nouveau v{version}", - "updateAvailableTitle": "Mise à jour disponible", - "releaseNotesTitle": "Nouveautés", - "remindLater": "Plus tard", - "retry": "Réessayer", - "stepDownload": "Téléchargement", - "stepInstall": "Installation", - "stepRestart": "Redémarrage", - "updateReadyHint": "Mise à jour téléchargée — redémarrez pour l'appliquer.", - "restarting": "Redémarrage...", - "dockerUpgradeHint": "Cela met à jour le conteneur en cours d'exécution. La mise à jour est perdue si le conteneur est recréé — pour la conserver, récupérez ou créez une image à la nouvelle version puis recréez le conteneur.", - "upgradeRolledBack": "Échec de la mise à niveau ; le serveur est revenu à la version précédente.", - "serverUnreachable": "Impossible de joindre le serveur pour démarrer la mise à niveau. Vérifiez qu'il fonctionne et réessayez.", - "rollbackButton": "Revenir en arrière", - "rollingBack": "Restauration...", - "rollbackDescription": "Restaure la version installée avant la dernière mise à niveau.", - "rollbackConfirmTitle": "Revenir à la version précédente ?", - "rollbackConfirmDescription": "Le serveur redémarrera sur la version installée avant la dernière mise à niveau. Une version plus récente reste disponible à la réinstallation.", - "rollbackConfirm": "Revenir en arrière", - "rollbackCancel": "Annuler", - "rollbackSuccess": "Retour à la version précédente. Rechargement...", - "rollbackFailed": "Échec du retour en arrière. Consultez les journaux du serveur.", - "updateErrors": { - "sourceUnavailable": "Impossible d’atteindre la source de mise à jour. Vérifiez votre réseau ou proxy et réessayez.", - "network": "La connexion réseau a échoué. Vérifiez votre réseau ou proxy et réessayez.", - "downloadFailed": "Impossible de télécharger le paquet de mise à jour. Veuillez réessayer plus tard.", - "installFailed": "Impossible d’installer la mise à jour. Fermez l’app puis réessayez.", - "unknown": "La mise à jour a échoué. Veuillez réessayer plus tard." - } - }, - "VersionControlSettings": { - "loading": "Chargement...", - "sectionTitle": "Contrôle de version", - "sectionDescription": "Configurez l'exécutable Git et gérez les comptes GitHub.", - "gitTitle": "Configuration Git", - "gitDescription": "Configurez l'exécutable Git utilisé par l'application.", - "gitDetected": "Git détecté", - "gitNotFound": "Git introuvable sur le système", - "gitVersion": "Version", - "gitPath": "Chemin", - "customGitPath": "Chemin Git personnalisé", - "customGitPathPlaceholder": "/usr/bin/git", - "customGitPathHint": "Laissez vide pour utiliser le chemin détecté automatiquement.", - "test": "Tester", - "testing": "Test en cours...", - "testSuccess": "L'exécutable Git est valide.", - "testFailed": "Test Git échoué : {message}", - "save": "Enregistrer", - "saving": "Enregistrement...", - "saveSuccess": "Paramètres Git enregistrés.", - "saveFailed": "Échec de l'enregistrement : {message}", - "githubTitle": "Comptes GitHub", - "githubDescription": "Gérez les comptes GitHub pour l'authentification. Les jetons sont stockés localement.", - "noAccounts": "Aucun compte GitHub configuré.", - "addAccount": "Ajouter un compte", - "serverUrl": "URL du serveur", - "serverUrlPlaceholder": "https://github.com", - "token": "Jeton d'accès personnel", - "tokenPlaceholder": "ghp_xxxxxxxxxxxx", - "generateToken": "Générer un jeton", - "tokenHint": "Générez un jeton dans GitHub → Settings → Developer settings → Personal access tokens.", - "validateAndAdd": "Valider et ajouter", - "validating": "Validation...", - "addSuccess": "Compte {username} ajouté avec succès.", - "addFailed": "Échec de l'ajout du compte : {message}", - "testConnection": "Tester", - "connectionSuccess": "Connexion réussie.", - "connectionFailed": "Échec de la connexion : {message}", - "setDefault": "Définir par défaut", - "defaultLabel": "Par défaut", - "defaultSet": "Compte par défaut mis à jour.", - "removeAccount": "Supprimer", - "removeConfirmTitle": "Supprimer le compte", - "removeConfirmMessage": "Êtes-vous sûr de vouloir supprimer le compte « {username} » ?", - "removeConfirm": "Supprimer", - "removeCancel": "Annuler", - "removeSuccess": "Compte supprimé.", - "scopes": "Portées", - "loadFailed": "Échec du chargement des paramètres : {message}", - "gitAccount": { - "sectionTitle": "Comptes serveur Git", - "sectionDescription": "Gérez les identifiants pour les serveurs Git non GitHub (GitLab, Bitbucket, auto-hébergé, etc.).", - "noAccounts": "Aucun compte de serveur Git configuré.", - "addAccount": "Ajouter un compte", - "addTitle": "Ajouter un compte Git", - "addDescription": "Entrez l'adresse du serveur, le nom d'utilisateur et le mot de passe ou jeton d'accès.", - "serverUrl": "URL du serveur", - "serverUrlPlaceholder": "https://gitlab.example.com", - "username": "Nom d'utilisateur", - "usernamePlaceholder": "Nom d'utilisateur ou e-mail", - "password": "Mot de passe / Jeton", - "passwordPlaceholder": "Mot de passe ou jeton d'accès", - "passwordHint": "Entrez le mot de passe ou le jeton d'accès du serveur.", - "add": "Ajouter", - "serverRequired": "L'URL du serveur est requise.", - "usernameRequired": "Le nom d'utilisateur est requis.", - "passwordRequired": "Le mot de passe est requis." - } - }, - "ShortcutSettings": { - "sectionTitle": "Raccourcis", - "resetDefault": "Rétablir les valeurs par défaut", - "recordInstruction": "Cliquez sur le bouton à droite, puis appuyez sur une combinaison de touches. Utilisez Ctrl/Cmd, Alt et Shift. Appuyez sur Échap pour annuler l’enregistrement.", - "recording": "Appuyez sur un raccourci...", - "toasts": { - "conflict": "Le raccourci est déjà utilisé par \"{title}\"", - "updated": "Raccourci mis à jour", - "invalid": "Raccourci invalide, veuillez réessayer", - "reset": "Les raccourcis par défaut ont été restaurés" - }, - "actions": { - "toggle_search": { - "title": "Ouvrir la recherche", - "description": "Afficher ou masquer le panneau de recherche de conversations" - }, - "toggle_sidebar": { - "title": "Basculer la barre latérale gauche", - "description": "Afficher ou masquer la barre latérale de liste des conversations" - }, - "toggle_terminal": { - "title": "Basculer le terminal", - "description": "Afficher ou masquer le panneau terminal inférieur" - }, - "new_terminal_tab": { - "title": "Nouveau terminal", - "description": "Créer un nouvel onglet terminal lorsque le terminal a le focus" - }, - "close_current_terminal_tab": { - "title": "Fermer le terminal actuel", - "description": "Fermer l’onglet terminal actuel lorsque le terminal a le focus" - }, - "toggle_aux_panel": { - "title": "Basculer le panneau droit", - "description": "Afficher ou masquer le panneau d’informations auxiliaires" - }, - "new_conversation": { - "title": "Nouvelle conversation", - "description": "Créer un nouvel onglet de conversation dans le dossier actuel" - }, - "open_folder": { - "title": "Ouvrir un dossier", - "description": "Ouvrir le sélecteur de dossier et ouvrir dans une nouvelle fenêtre" - }, - "open_settings": { - "title": "Ouvrir les paramètres", - "description": "Ouvrir la fenêtre des paramètres" - }, - "close_current_tab": { - "title": "Fermer l’onglet actuel", - "description": "Fermer la conversation actuelle ou l’onglet de fichier" - }, - "close_all_file_tabs": { - "title": "Fermer tous les onglets de fichiers", - "description": "Fermer tous les onglets de fichiers ouverts lorsque le panneau de fichiers est actif" - }, - "next_tab": { - "title": "Onglet suivant", - "description": "Passer à l'onglet de conversation ou de fichier suivant" - }, - "prev_tab": { - "title": "Onglet précédent", - "description": "Passer à l'onglet de conversation ou de fichier précédent" - }, - "send_message": { - "title": "Envoyer le message", - "description": "Envoyer le message actuel dans la zone de saisie" - }, - "newline_in_message": { - "title": "Retour à la ligne", - "description": "Insérer un retour à la ligne dans la zone de saisie" - }, - "toggle_custom_style": { - "title": "Suspendre/réactiver le style personnalisé", - "description": "Issue de secours : désactive toutes les couleurs et le CSS personnalisés, puis les réactive" - } - } - }, - "SkillsSettings": { - "title": "Skills", - "description": "Sélectionnez une Skill à gauche. À droite, un aperçu Markdown s’affiche par défaut ; passez en édition pour modifier et enregistrer.", - "loadingAgents": "Chargement des agents qui prennent en charge les Skills...", - "emptyNoManageableAgents": "Aucun agent disponible pour la gestion des Skills.", - "managedTarget": "Cible gérée", - "selectAgentPlaceholder": "Sélectionnez un agent", - "searchPlaceholder": "Rechercher par nom / ID / chemin...", - "skillsList": "Liste des Skills", - "loadingSkills": "Chargement des Skills...", - "agentNotSupported": "L’agent actuel ne prend pas en charge la gestion des Skills.", - "emptySkills": "Aucune Skill pour le moment. Cliquez sur « Nouvelle Skill » pour en créer une.", - "newSkillTitle": "Nouvelle Skill", - "skillInfo": "Infos de la Skill", - "skillIdPlaceholder": "skill-id (lettres/chiffres/-/_/.)", - "skillsDirectoryWithPath": "Répertoire des Skills : {path}", - "skillsDirectoryNeedId": "Répertoire des Skills : saisissez l’ID de Skill pour générer le chemin complet", - "markdownContent": "Contenu Markdown", - "editingStatus": "Édition", - "previewStatus": "Aperçu", - "contentPlaceholder": "Saisissez le contenu Markdown de la Skill...", - "metadataTitle": "Métadonnées des Skills", - "onlyYamlMetadata": "Cette Skill contient uniquement des métadonnées YAML.", - "emptyContentHint": "Aucun contenu pour le moment. Cliquez sur « Éditer » pour commencer.", - "loadingSkill": "Chargement de la Skill...", - "emptyNoAgents": "Aucun agent disponible.", - "noSelectionHint": "Sélectionnez un Skill à gauche ou cliquez sur « Nouveau Skill » pour en créer un.", - "systemBadge": "Système", - "systemHint": "Skill intégré du CLI · lecture seule", - "scope": { - "global": "Global", - "folder": "Dossier", - "selectFolderPlaceholder": "Sélectionner un dossier", - "noFolders": "Aucun dossier trouvé", - "pickFolderHint": "Sélectionnez un dossier pour afficher ses Skills." - }, - "actions": { - "preview": "Aperçu", - "edit": "Éditer", - "openInWindow": "Ouvrir dans une nouvelle fenêtre", - "delete": "Supprimer", - "deleting": "Suppression...", - "refresh": "Actualiser", - "newSkill": "Nouvelle Skill", - "reset": "Réinitialiser", - "save": "Enregistrer", - "saving": "Enregistrement...", - "cancel": "Annuler" - }, - "deleteDialog": { - "title": "Supprimer la Skill", - "confirm": "Supprimer la Skill actuelle ? Cette action est irréversible.", - "confirmWithNamePrefix": "Supprimer la Skill", - "confirmWithNameSuffix": "? Cette action est irréversible." - }, - "toasts": { - "loadFailed": "Échec du chargement de la Skill", - "openFolderFailed": "Échec de l'ouverture du dossier", - "noSkillDirectory": "Aucun répertoire de Skills disponible pour l’agent actuel", - "nameRequired": "Le nom de la Skill ne peut pas être vide", - "updated": "Skill mise à jour", - "created": "Skill créée", - "saveFailed": "Échec de l’enregistrement de la Skill", - "deleted": "Skill supprimée", - "deleteFailed": "Échec de la suppression de la Skill" - }, - "templates": { - "gemini": "---\nname: example-skill\ndescription: Describe when this skill should be used.\n---\n\n# Skill Name\n\nInstructions for the agent when this skill is active.\n\n## Workflow\n\n1. Add actionable step one.\n2. Add actionable step two.\n", - "openCode": "---\nname: example-skill\ndescription: Describe when this skill should be used.\n---\n\n# Purpose\n\nDescribe what this skill helps with.\n\n# Steps\n\n1. Add actionable step one.\n2. Add actionable step two.\n", - "openClaw": "---\nname: example-skill\ndescription: Describe when this skill should be used.\nuser-invocable: true\ndisable-model-invocation: false\n---\n\n# Purpose\n\nDescribe what this skill helps with.\n\n# Instructions\n\n1. Add actionable instruction one.\n2. Add actionable instruction two.\n", - "default": "---\nname: example-skill\ndescription: Describe when this skill should be used.\n---\n\n# Skill: example-skill\n\n## When to use\n\n- Describe trigger conditions.\n\n## Instructions\n\n1. Add actionable instruction one.\n2. Add actionable instruction two.\n" - } - }, - "McpSettings": { - "loading": "Chargement...", - "summary": { - "missingCommand": "(commande manquante)", - "missingUrl": "(URL manquante)" - }, - "protocol": { - "stdio": "Stdio" - }, - "errors": { - "selectInstallProtocol": "Veuillez sélectionner un protocole d’installation", - "fieldRequired": "{field} est requis", - "fieldNeedsBoolean": "{field} doit être true ou false", - "fieldNeedsNumber": "{field} doit être un nombre", - "fieldNeedsInteger": "{field} doit être un entier", - "fieldInvalidJson": "{field} contient un JSON invalide : {message}", - "fieldOutOfRange": "La valeur de {field} est hors de la plage autorisée", - "jsonEmpty": "{name} ne peut pas être vide", - "jsonInvalid": "{name} n’est pas un JSON valide : {message}", - "jsonMustBeObject": "{name} doit être un objet JSON", - "specMustBeObject": "La configuration MCP doit être un objet JSON.", - "missingType": "Le champ type est manquant dans la configuration MCP. Indiquez stdio, http (alias : streamable-http, streamableHttp) ou sse.", - "unsupportedType": "Type MCP non pris en charge {type}. Pris en charge : stdio, http (alias : streamable-http, streamableHttp), sse.", - "codexEntryUnsupportedType": "L’entrée MCP Codex {id} a un type non pris en charge {type}. Pris en charge : stdio, http (alias : streamable-http, streamableHttp), sse.", - "unsupportedTransportType": "Type de transport non pris en charge {type}. Pris en charge : http (alias : streamable-http, streamableHttp), sse.", - "stdioCommandRequired": "Un MCP stdio nécessite un champ command non vide.", - "remoteUrlRequired": "Un MCP distant nécessite un champ url non vide.", - "appsRequired": "Sélectionnez au moins une application cible." - }, - "jsonNames": { - "localConfig": "Configuration MCP", - "installConfig": "Configuration d’installation" - }, - "toasts": { - "uninstalled": "MCP désinstallé", - "uninstallFailed": "Échec de la désinstallation : {message}", - "selectAtLeastOneApp": "Veuillez sélectionner au moins une application cible", - "saveSuccess": "Enregistré", - "saveFailed": "Échec de l’enregistrement : {message}", - "installed": "{name} installé", - "installFailed": "Échec de l’installation : {message}", - "serverIdRequired": "L'ID du serveur est requis", - "serverIdExists": "Le Server ID \"{id}\" existe déjà. Modifiez l'entrée existante ou choisissez un autre nom.", - "created": "MCP créé" - }, - "installDialog": { - "title": "Confirmer l’installation MCP", - "descriptionWithName": "Installer {name} dans la configuration locale.", - "description": "Sélectionnez les applications cibles pour l’installation.", - "protocol": "Protocole", - "selectProtocol": "Sélectionner un protocole", - "parameters": "Paramètres de configuration", - "booleanPlaceholder": "Veuillez sélectionner true/false", - "selectOneValue": "Sélectionner une valeur", - "targetApps": "Applications cibles" - }, - "actions": { - "cancel": "Annuler", - "confirmInstall": "Confirmer l’installation", - "installing": "Installation", - "uninstall": "Désinstaller", - "uninstalling": "Désinstallation", - "viewDetails": "Voir les détails", - "save": "Enregistrer", - "saving": "Enregistrement", - "install": "Installer", - "refresh": "Actualiser", - "newMcp": "Nouveau MCP", - "create": "Créer", - "creating": "Création..." - }, - "tabs": { - "local": "MCP local", - "market": "Marketplace MCP" - }, - "local": { - "filterPlaceholder": "Filtrer les MCP locaux...", - "loadFailed": "Échec du chargement : {message}", - "empty": "Aucun MCP local détecté.", - "description": "La configuration MCP locale peut être modifiée et enregistrée directement.", - "enabledApps": "Applications activées", - "configJson": "Configuration MCP (JSON)", - "draftTitle": "Nouveau MCP", - "draftDescription": "Renseignez un Server ID et une configuration pour créer un serveur MCP local.", - "serverIdLabel": "ID du serveur", - "serverIdPlaceholder": "ID du serveur (ex. my-mcp)", - "typeHint": "Types pris en charge : stdio, http (alias : streamable-http, streamableHttp), sse. env n'est utilisé que par stdio ; pour les MCP distants, utilisez headers pour transporter les jetons d'authentification.", - "envOnRemoteWarning": "env détecté sur un MCP distant. Seul stdio utilise env ; les MCP distants transportent les jetons d'authentification via headers, donc env sera ignoré à l'enregistrement." - }, - "market": { - "selectMarketplace": "Sélectionner un marketplace", - "searchPlaceholder": "Rechercher MCP...", - "searchFailed": "Échec de la recherche : {message}", - "loadingList": "Chargement de la liste MCP...", - "empty": "Aucun résultat MCP.", - "loadingDetail": "Chargement des détails du marketplace...", - "detailLoadFailed": "Échec du chargement des détails : {message}", - "owner": "Propriétaire : {owner}", - "namespace": "Espace de noms : {namespace}", - "defaultInstallProtocol": "Protocole d’installation par défaut", - "currentOptionParameterCount": "Nombre de paramètres de l’option actuelle : {count}", - "installConfigDescription": "Configuration d’installation (JSON, modifiable avant installation ; les modifications remplaceront le formulaire protocole/paramètres)", - "selectLeftToView": "Sélectionnez un MCP du marketplace à gauche pour voir les détails." - }, - "badges": { - "verified": "Vérifié", - "remote": "Distant", - "hasHomepage": "A une page d’accueil", - "uses": "{count} utilisations", - "deployed": "Déployé", - "notDeployed": "Non déployé" - }, - "selectLeftMcp": "Sélectionnez un MCP à gauche." - }, - "AcpAgentSettings": { - "title": "Gestion du SDK des agents", - "description": "Gérez en un seul endroit la connexion SDK des agents, l'état activé, les variables d'environnement, la gestion de configuration et les informations de préflight de version.", - "loadingAgents": "Chargement de la liste des agents...", - "agentList": "Liste des agents", - "emptyNoAgent": "Aucun agent disponible.", - "configManagement": "Gestion de configuration", - "envVars": "Variables d'environnement", - "hostTools": { - "label": "Laisser l'agent gérer les fichiers et les commandes", - "description": "codeg cesse d'assurer l'accès aux fichiers et les commandes de terminal : l'agent les exécute dans son propre processus, là où son bac à sable et ses règles d'autorisation s'appliquent réellement. La délégation à d'autres agents est également désactivée, car elle ferait repasser le même travail par codeg. codeg n'ajoute aucun bac à sable, n'activez donc ceci que si l'agent en a un configuré." - }, - "nativeJsonConfig": "Configuration JSON native", - "modelHintDefault": "Laissez vide pour utiliser le modèle système par défaut.", - "generalConfigDescriptionClaude": "Prend en charge la configuration rapide de l'API URL, API Key et des modèles Claude, et synchronise avec la configuration JSON native.", - "generalConfigDescriptionDefault": "Prend en charge les entrées de configuration importantes (API URL, API Key, Model) et la gestion de la configuration JSON native.", - "multiAgent": { - "title": "Collaboration multi-agent", - "description": "Permet aux agents actifs de déléguer des sous-tâches à d’autres agents.", - "enable": "Activer la délégation", - "enableHint": "Lorsque cette option est désactivée, l’outil delegate_to_agent est masqué du catalogue d’outils MCP de l’agent.", - "withheldByHostTools": "{agents} ne recevront pas les outils de délégation : leur interrupteur par agent « Laisser l’agent gérer les fichiers et les commandes » est activé.", - "selfInitiate": "Allow spawn without @", - "selfInitiateHint": "When on, an agent may start a listed sub-agent on its own. An @ mention is still always honored. When off, only an @ mention starts a sub-agent.", - "depthLimit": "Profondeur maximale de délégation", - "depthHint": "Plage autorisée : {min}–{max}. Limite la profondeur de récursion d’une chaîne de délégation (racine → enfant → petit-enfant …).", - "completedCacheLabel": "Cache des résultats terminés (MB)", - "completedCacheHint": "Cache en mémoire des résultats terminés des sous-agents, conservé uniquement tant que la session de délégation est en cours et libéré automatiquement à la fin de cette session. Au-delà de ce budget, les résultats les plus anciens sont supprimés de la mémoire en premier (toujours consultables dans la session du sous-agent) ; 0 = illimité (libéré quand même à la fin de la session).", - "save": "Enregistrer", - "saving": "Enregistrement…", - "saved": "Paramètres de délégation enregistrés", - "saveFailed": "Échec de l’enregistrement des paramètres de délégation", - "loadFailed": "Échec du chargement des paramètres de délégation : {detail}", - "tabGeneral": "Général", - "tabAgentDefaults": "Valeurs par défaut du sous-agent", - "agentDefaultsDescription": "Remplacements par agent appliqués lorsque la Collaboration multi-agent démarre un sous-agent pour un appel de délégation. Les options affichées proviennent d’une sonde en direct : votre sélection correspond exactement à ce que l’agent acceptera.", - "probing": "Chargement des options disponibles depuis l’agent…", - "probeFailed": "Échec du chargement des options : {detail}", - "retry": "Réessayer", - "noConfigAvailable": "Cet agent n’a aucune option configurable.", - "modeLabel": "Mode", - "agentDefaultHint": "Valeur par défaut de l’agent : {value}", - "defaultOptionLabel": "Par défaut ({value})" - }, - "actions": { - "dragSort": "Glisser pour réordonner", - "dragSortAgent": "Glisser pour réordonner {name}", - "refreshCheck": "Actualiser la vérification", - "refreshCheckAgent": "Actualiser la vérification de {name}", - "clickEnable": "Cliquer pour activer {name}", - "clickDisable": "Cliquer pour désactiver {name}", - "install": "Installer", - "upgrade": "Mettre à niveau", - "uninstall": "Désinstaller", - "uninstalling": "Désinstallation...", - "saveEnvVars": "Enregistrer les variables d’environnement", - "saving": "Enregistrement...", - "saveGrokConfig": "Enregistrer la configuration Grok", - "saveCodexConfig": "Enregistrer la config Codex", - "saveGeminiConfig": "Enregistrer la config Gemini", - "saveOpenCodeConfig": "Enregistrer la config OpenCode", - "saveOpenClawConfig": "Enregistrer la config OpenClaw", - "saveConfigManagement": "Enregistrer la gestion de config", - "saveCurrentProvider": "Enregistrer le provider actuel", - "showApiKey": "Afficher la clé API", - "hideApiKey": "Masquer la clé API", - "showKey": "Afficher la clé", - "hideKey": "Masquer la clé", - "showToken": "Afficher le token", - "hideToken": "Masquer le token", - "cancel": "Annuler", - "delete": "Supprimer", - "deleting": "Suppression...", - "confirmDelete": "Confirmer la suppression", - "confirmUninstall": "Confirmer la désinstallation", - "saveClineConfig": "Enregistrer la configuration Cline", - "saveHermesConfig": "Enregistrer la configuration Hermes", - "saveCodeBuddyConfig": "Enregistrer la configuration CodeBuddy", - "saveKimiCodeConfig": "Enregistrer la configuration de Kimi Code", - "customInstall": "Installation personnalisée", - "saveKimiCodeRawConfig": "Enregistrer config.toml", - "saveDeepSeekConfig": "Enregistrer la configuration DeepSeek", - "diagnose": "Diagnostiquer" - }, - "status": { - "enabled": "Activé", - "disabled": "Désactivé", - "unchecked": "Non vérifié", - "agentEnabledAria": "{name} activé", - "agentEnabledSwitch": "Interrupteur d’activation {name}" - }, - "preflight": { - "count": "Éléments de pré-vérification : {count}", - "notRun": "Les vérifications n’ont pas encore été exécutées." - }, - "grok": { - "configDescription": "Configurez Grok ici. Les contrôles ci-dessous — mode d'autorisation, effort de raisonnement, un modèle personnalisé optionnel (point de terminaison dédié) et le compactage — sont fusionnés dans ~/.grok/config.toml, en préservant vos autres clés et commentaires. La connexion utilise votre XAI_API_KEY ou `grok login`. Les autres clés restent modifiables sous Avancé.", - "permissionModeLabel": "Mode d'autorisation", - "permissionDefault": "Demander à chaque fois", - "permissionAcceptEdits": "Approuver les modifications automatiquement", - "permissionAuto": "Approbation automatique intelligente", - "permissionAlwaysApprove": "Toujours approuver", - "reasoningEffortLabel": "Effort de raisonnement", - "effortLow": "Faible (plus rapide)", - "effortMedium": "Moyen (équilibré)", - "effortHigh": "Élevé", - "effortXhigh": "Maximum", - "optionDefault": "Utiliser la valeur par défaut", - "authTitle": "Authentification", - "authMode": "Méthode d'authentification", - "authModeApiKey": "Clé API XAI", - "authModeApiKeyHint": "Authentifiez-vous avec une XAI_API_KEY de la console xAI, pour les exécutions non interactives ou headless. Enregistrée dans l'environnement de cet agent.", - "authModeCustom": "Point de terminaison personnalisé", - "authModeCustomHint": "Utilisez votre propre point de terminaison (BYO) : définissez ci-dessous un modèle personnalisé avec sa propre URL de base et sa clé API. Il devient le modèle par défaut de Grok.", - "subscriptionHint": "Connectez-vous avec `grok login` (SuperGrok / X Premium+). Aucune clé API n'est enregistrée.", - "loginHint": "Exécutez ceci dans un terminal pour vous connecter, puis rouvrez ces paramètres :", - "commandCopied": "Commande copiée dans le presse-papiers", - "copyCommand": "Copier la commande", - "authKeyConfigured": "XAI_API_KEY est configurée.", - "authKeyMissing": "Aucune XAI_API_KEY définie.", - "advancedToggle": "Avancé (config.toml brut)", - "configTomlNative": "config.toml (natif)", - "configTomlHint": "Enregistré tel quel comme l'intégralité de ~/.grok/config.toml. Le TOML invalide est rejeté afin qu'une faute de frappe ne tronque jamais votre fichier.", - "configTomlPlaceholder": "# Clés autres que les contrôles ci-dessus, p. ex.\n# [mcp_servers.*], [cli], règles [permission].", - "customModelTitle": "Modèle personnalisé (point de terminaison dédié)", - "customModelHint": "Dirigez Grok vers un point de terminaison personnalisé ou auto-hébergé. codeg écrit un bloc `[model.*]` par modèle et le définit comme modèle par défaut. Laissez l'ID de modèle vide pour le supprimer.", - "customModelIdLabel": "ID du modèle", - "customModelIdPlaceholder": "grok-4.5", - "customModelIdHint": "Enregistré comme bloc `[model.*]` et envoyé à l'API comme nom de modèle ; également défini comme `[models].default`.", - "customBaseUrlLabel": "URL de base", - "customBaseUrlPlaceholder": "https://api.x.ai/v1 (par défaut)", - "customApiBackendLabel": "Backend de l'API", - "backendResponses": "Responses", - "backendChatCompletions": "Chat Completions", - "backendMessages": "Messages (Anthropic)", - "customApiKeyLabel": "Clé API", - "customApiKeyHint": "Stockée en ligne dans `[model.*].api_key`, limitée à ce point de terminaison.", - "customContextWindowLabel": "Fenêtre de contexte (tokens)", - "customContextWindowHint": "Facultatif. Détermine le moment du compactage automatique ; laissez vide pour la valeur par défaut du point de terminaison.", - "autoCompactLabel": "Seuil de compactage automatique (%)", - "autoCompactHint": "Compacte la conversation lorsque l'utilisation du contexte atteint ce pourcentage (85 par défaut pour Grok). Écrit dans `[session]`." - }, - "cursor": { - "configDescription": "Configurez Cursor ici. Choisissez une méthode d'authentification — abonnement officiel (connexion par navigateur) ou une clé API Cursor pour les machines sans interface ou serveurs — puis choisissez un modèle et modifiez les règles d'autorisation et le bac à sable du CLI. codeg les écrit dans ~/.cursor/cli-config.json, partagé avec le CLI cursor-agent.", - "authTitle": "Authentification", - "authChecking": "Vérification…", - "authNotInstalled": "cursor-agent n'est pas installé", - "authLoggedIn": "Connecté", - "authNotLoggedIn": "Non connecté", - "loginHint": "Exécutez ceci dans un terminal pour vous connecter à votre compte Cursor (une fenêtre de navigateur s'ouvre), puis cliquez sur actualiser :", - "apiKeyLabel": "Clé API Cursor", - "apiKeyPlaceholder": "clé depuis cursor.com/dashboard", - "apiKeyHint": "CURSOR_API_KEY — une clé de compte du tableau de bord Cursor, alternative à la connexion par navigateur pour les machines sans interface ou serveurs. Ce n'est pas une clé tierce ni OpenAI.", - "modelTitle": "Modèle par défaut", - "loadModels": "Charger les modèles", - "modelsUnavailable": "Liste de modèles indisponible", - "modelHint": "Transmis à la CLI via --model au démarrage de la session. Laissez par défaut pour laisser Cursor choisir.", - "permissionsTitle": "Permissions & bac à sable", - "permissionsDescription": "Éditeur visuel des règles de permissions de la CLI (cli-config.json). Les règles autorisées s'exécutent sans confirmation ; les règles refusées sont toujours bloquées.", - "permissionModeLabel": "Mode d'autorisation", - "permissionModeDefault": "Demander avant d'exécuter (par défaut)", - "permissionModeForce": "Tout exécuter (--force)", - "permissionModeHint": "Tout exécuter lance les sessions avec --force : tous les appels d'outils sont autorisés automatiquement sauf les règles de refus, sans confirmation (une politique d'organisation peut le limiter aux règles d'autorisation). S'applique aux nouvelles sessions.", - "optionDefault": "Défaut (non défini)", - "sandboxLabel": "Bac à sable", - "sandboxEnabled": "Activé", - "sandboxDisabled": "Désactivé", - "allowRulesLabel": "Règles autorisées", - "denyRulesLabel": "Règles refusées", - "addRule": "Ajouter une règle", - "rulesSyntaxHint": "Syntaxe des règles : Shell(cmd), Read(chemin/glob), Write(chemin/glob), WebFetch(domaine), Mcp(serveur:outil) — les règles de refus priment toujours.", - "saveConfig": "Enregistrer la configuration", - "advancedToggle": "Avancé : cli-config.json brut", - "advancedHint": "Le ~/.cursor/cli-config.json complet. Enregistrer écrit le fichier tel quel ; les contrôles structurés ci-dessus y sont fusionnés.", - "saveRawConfig": "Enregistrer le fichier", - "authMode": "Méthode d'authentification", - "subscriptionHint": "Connectez-vous avec votre compte Cursor et utilisez les modèles de Cursor.", - "customApiKeyRequired": "Une clé API Cursor est requise.", - "authModeApiKey": "Clé API Cursor (sans interface)", - "authModeApiKeyHint": "Authentifiez-vous avec une clé API de compte Cursor générée dans le tableau de bord Cursor (pour les machines sans interface ou serveurs). C'est une clé de compte Cursor, pas un point de terminaison tiers/OpenAI : cursor-agent ne communique qu'avec le backend de Cursor. Pour utiliser un point de terminaison compatible codex/OpenAI, utilisez plutôt l'agent Codex.", - "modelPickerPlaceholder": "Rechercher des modèles…", - "modelNoMatch": "Aucun modèle correspondant", - "modelsNeedAuth": "Connectez-vous pour charger la liste des modèles.", - "modelDefaultBadge": "par défaut" - }, - "deepseek": { - "configManagement": "Configuration de DeepSeek Harness", - "configDescription": "Le point de terminaison et la clé sont des variables d'environnement que deepseek-acp lit au démarrage. Le modèle et le niveau de raisonnement sont des sélecteurs par session : ils se choisissent dans le champ de saisie.", - "baseUrlLabel": "Point de terminaison de l'API", - "baseUrlHint": "Laissez vide pour le point de terminaison officiel. S'applique aux sessions démarrées après l'enregistrement ; reconnectez une session en cours pour qu'elle le prenne en compte.", - "baseUrlInvalid": "Saisissez une URL http(s) complète et sans chaîne de requête, par exemple https://api.deepseek.com", - "apiKeyLabel": "Clé d'API", - "apiKeyHint": "Transmise à l'agent via DEEPSEEK_API_KEY. Une variable d'environnement l'emporte sur le fichier d'identifiants : laissez ce champ vide si vous vous connectez depuis le terminal." - }, - "codex": { - "configDescription": "Prend en charge la configuration rapide de l’URL API, de la clé API, du nom du modèle et du reasoning effort, avec synchronisation vers `auth.json` / `config.toml`.", - "authMode": "Mode d’authentification", - "chatgptSubscription": "Abonnement officiel", - "chatgptSubscriptionHint": "Connectez-vous avec l’abonnement officiel ChatGPT, pas besoin d’API Key", - "apiKeyHint": "Connectez-vous avec une API Key à OpenAI ou aux services API compatibles", - "selectProvider": "Sélectionner un provider", - "modelName": "Nom du modèle", - "selectReasoningEffort": "Sélectionner Reasoning Effort", - "enableWebsocket": "Activer WebSocket", - "enableWebsocketAria": "Activer WebSocket pour Codex Provider", - "enableSkills": "Activer Skills", - "enableSkillsAria": "Activer Skills pour Codex", - "enableFast": "Activer Fast", - "enableFastAria": "Activer le niveau de service Fast pour Codex", - "sandboxGroupTitle": "Bac à sable et approbations", - "sandboxGroupHint": "Écrit dans le ~/.codex/config.toml global, donc les sessions codex CLI et IDE en héritent aussi. Ce sont des valeurs par défaut du fil : elles régissent les tours que codex démarre lui-même (/goal, /review, /compact). Les messages ordinaires utilisent le préréglage d'approbation de la zone de saisie. Redémarrez une session pour appliquer les changements.", - "sandboxShadowedWarning": "config.toml définit default_permissions : codex résout les permissions via ce profil et ignore totalement sandbox_mode. Supprimez default_permissions pour utiliser les réglages ci-dessous.", - "sandboxPermissionsTableWarning": "config.toml définit des profils [permissions] sans default_permissions, ce qui empêche codex de démarrer. Renseignez-le dans l'éditeur brut ci-dessous.", - "approvalPolicyLabel": "Politique d'approbation", - "approvalPolicyUnset": "Non définie (défaut codex : à la demande)", - "approvalPolicy_on-request": "À la demande — le modèle décide quand demander", - "approvalPolicy_untrusted": "Non fiable — seules les commandes en lecture seule reconnues sûres s'exécutent sans validation", - "approvalPolicy_never": "Jamais — aucune demande d'approbation", - "approvalPolicy_granular": "Granulaire — au cas par cas selon le type", - "approvalPolicyUntrustedAcpWarning": "« Untrusted » n'a pas d'équivalent parmi les trois préréglages d'approbation de l'adaptateur ACP ; les sessions codeg retombent donc sur « à la demande » : le modèle décide alors quand demander, et les commandes que le bac à sable autorise déjà ne demandent plus rien. Restreignez plutôt le mode de bac à sable ci-dessous.", - "granularHint": "Désactivé signifie que ce type de demande est refusé automatiquement au lieu de vous être présenté.", - "granular_sandbox_approval": "Élévations pour commandes shell", - "granular_rules": "Invites des règles execpolicy", - "granular_skill_approval": "Invites des scripts de compétences", - "granular_request_permissions": "Invites de l'outil request_permissions", - "granular_mcp_elicitations": "Invites d'elicitation MCP", - "sandboxModeLabel": "Mode bac à sable", - "sandboxModeUnset": "Non défini (les dossiers de confiance retombent sur l'écriture dans l'espace de travail)", - "sandboxMode_read-only": "Lecture seule", - "sandboxMode_workspace-write": "Écriture dans l'espace de travail", - "sandboxMode_danger-full-access": "Accès complet (sans bac à sable)", - "sandboxModeHint": "Sous Windows, l'écriture dans l'espace de travail est rétrogradée en lecture seule sauf si le bac à sable Windows expérimental de codex est activé.", - "sandboxModeSeedsPresetHint": "codeg s'en sert aussi pour le préréglage d'approbation initial de la session : contrairement à la politique d'approbation, il agit donc sur les requêtes ordinaires. Le préréglage choisi dans la zone de saisie reste prioritaire.", - "writableRootsLabel": "Dossiers inscriptibles supplémentaires", - "writableRootsHint": "Un chemin absolu par ligne, en plus du répertoire de travail.", - "sandboxRootsRelativeError": "Doit être un chemin absolu — codex résout les chemins relatifs sous ~/.codex : {path}", - "networkAccessLabel": "Autoriser l'accès réseau", - "excludeTmpdirLabel": "Exclure TMPDIR des racines inscriptibles", - "excludeSlashTmpLabel": "Exclure /tmp des racines inscriptibles", - "authJsonNative": "auth.json (natif)", - "configTomlNative": "config.toml (natif)", - "loginButton": "Se connecter avec ChatGPT", - "loginRequesting": "Demande du code de connexion...", - "loginStep1": "Ouvrez l'URL suivante dans votre navigateur :", - "loginStep2": "Entrez le code ci-dessous :", - "loginPolling": "En attente d'autorisation...", - "loginCancel": "Annuler", - "loginSuccess": "Connexion réussie, configuration enregistrée !", - "loginFailed": "Échec de la connexion : {message}", - "loginRetry": "Réessayer", - "loginCodeCopied": "Code copié", - "loggedIn": "Compte connecté", - "loginRelogin": "Reconnecter / Changer de compte", - "loginTimeout": "Connexion expirée, veuillez réessayer", - "loginSaveFailed": "Connexion réussie mais échec de la sauvegarde de la configuration" - }, - "gemini": { - "authConfig": "Configuration d’authentification Gemini", - "authConfigDescription": "Alignée sur la documentation d’authentification Gemini CLI, avec prise en charge d’un endpoint personnalisé, connexion Google, Gemini API Key et Vertex AI (ADC / compte de service / API Key).", - "authMode": "Mode d’authentification", - "selectAuthMode": "Sélectionner un mode d’authentification", - "viewAuthDoc": "Voir la documentation d’authentification", - "mode": { - "custom": "Endpoint personnalisé", - "loginGoogle": "Connexion Google (OAuth)", - "vertexServiceAccount": "Vertex AI (Compte de service)" - }, - "hint": { - "custom": "Renseignez API URL, API Key et Model, mappés sur GOOGLE_GEMINI_BASE_URL / GEMINI_API_KEY / GEMINI_MODEL.", - "loginGoogle": "Exécutez d’abord gemini dans le terminal et terminez la connexion Google ; la clé API n’est pas requise.", - "geminiApiKey": "Renseignez GEMINI_API_KEY lors de l’utilisation de l’API Gemini.", - "vertexAdc": "Utilisez gcloud ADC ; GOOGLE_CLOUD_PROJECT et GOOGLE_CLOUD_LOCATION sont recommandés.", - "vertexServiceAccount": "Définissez le chemin JSON du compte de service dans GOOGLE_APPLICATION_CREDENTIALS.", - "vertexApiKey": "Renseignez GOOGLE_API_KEY lors de l’utilisation d’une clé API Vertex AI." - } - }, - "openCode": { - "configManagement": "Gestion de configuration OpenCode", - "configDescription": "Alignée sur le schéma `provider` d’OpenCode, prend en charge la gestion multi-provider et la synchronisation bidirectionnelle avec les fichiers JSON natifs.", - "providerManagement": "Gestion des providers", - "providerCount": "{count} fournisseurs", - "addProvider": "Ajouter un provider", - "emptyProvider": "Aucun fournisseur personnalisé pour le moment. Cliquez sur Ajouter un fournisseur personnalisé pour en créer un.", - "providerEnabledState": "État activé de {providerId}", - "selectProviderNpm": "Sélectionner provider.npm", - "modelManagement": "Gestion des modèles", - "modelCount": "{count} modèles", - "modelDescription": "Aligné sur `provider.models` d’OpenCode. La gestion rapide prend actuellement en charge `name` / `id` ; les autres champs avancés sont conservés et peuvent être modifiés dans le JSON natif ci-dessous.", - "addModel": "Ajouter un modèle", - "emptyModel": "Aucun modèle pour le moment. Saisissez model id puis cliquez sur « Ajouter un modèle ».", - "modelId": "ID du modèle", - "modelName": "Nom du modèle", - "deleteModel": "Supprimer le modèle {modelId}", - "nativeJsonConfig": "Configuration JSON native OpenCode", - "mainModel": "Modèle principal", - "smallModel": "Petit modèle", - "noMatchingModels": "Aucun modèle correspondant", - "connectProvider": "Connecter un fournisseur", - "connectedProviders": "Fournisseurs connectés", - "noConnectedProviders": "Aucun fournisseur du catalogue connecté pour le moment.", - "advancedProviderConfig": "Fournisseurs personnalisés", - "customProviderConfigHint": "Points de terminaison compatibles OpenAI que vous définissez vous-même — un bloc provider dans opencode.json, avec la clé API dans auth.json.", - "addCustomProvider": "Ajouter un fournisseur personnalisé", - "disconnect": "Déconnecter", - "editConfig": "Modifier", - "customBadge": "Personnalisé", - "authKindApi": "Clé API", - "authKindOauth": "OAuth", - "authKindNone": "Aucun identifiant", - "connect": { - "title": "Connecter un fournisseur", - "description": "Choisissez un fournisseur dans le catalogue models.dev. Les identifiants sont enregistrés dans le fichier auth.json d'OpenCode.", - "pick": "Fournisseur", - "search": "Rechercher des fournisseurs…", - "loading": "Chargement du catalogue…", - "catalogLabel": "Catalogue models.dev", - "modelsAvailable": "{count} modèles disponibles", - "getKey": "Obtenir la clé API", - "oauthApiKeyNote": "Ce fournisseur prend aussi en charge la connexion via navigateur avec opencode auth login. La connexion par navigateur arrive bientôt ; pour le moment, collez une clé API.", - "apiKey": "Clé API", - "apiKeyHint": "Enregistrée dans auth.json, jamais dans opencode.json.", - "baseUrlOptional": "Remplacer l''URL de base (facultatif)", - "providerId": "ID du fournisseur", - "displayName": "Nom affiché", - "modelsList": "Modèles (un par ligne)", - "modelsHint": "Identifiants de modèle acceptés par le point de terminaison.", - "action": "Connecter", - "editTitle": "Modifier le fournisseur", - "editDescription": "Mettez à jour la clé API ou l''URL de base de ce fournisseur.", - "saveAction": "Enregistrer" - }, - "customProvider": { - "title": "Ajouter un fournisseur personnalisé", - "description": "Définissez un point de terminaison compatible OpenAI. La clé API est enregistrée dans auth.json ; le bloc provider va dans opencode.json.", - "action": "Ajouter le fournisseur", - "idInCatalog": "{providerId} est un fournisseur connu — connectez-le plutôt via Connecter un fournisseur." - }, - "refreshCatalog": "Actualiser le catalogue", - "reasoningBadge": "raisonnement", - "contextWindow": "Fenêtre de contexte", - "permissions": { - "title": "Permissions", - "description": "Décidez quelles actions s’exécutent seules, lesquelles demandent votre accord et lesquelles sont bloquées. Écrit dans le bloc permission de opencode.json et appliqué à l’enregistrement ci-dessous.", - "docsLink": "Documentation des permissions", - "unparsableConfig": "Le JSON natif ci-dessous est invalide, l’éditeur visuel est donc en pause. Corrigez le JSON pour reprendre.", - "invalidBlock": "Le bloc permission a une forme que codeg ne reconnaît pas. Modifiez-le dans le JSON natif ci-dessous ou utilisez Réinitialiser pour repartir de zéro.", - "orderingUnsafe": "Une règle joker est écrite après des outils précis, donc OpenCode l’applique aussi à ceux-ci : les lignes ci-dessous ne sont pas ce qui s’applique réellement. Corriger l’ordre ramène simplement chaque joker en tête de sa portée, sans modifier la moindre valeur.", - "orderingUnsafeManual": "Une règle est masquée par un motif plus général placé après elle, donc OpenCode ne l’applique jamais : les lignes ci-dessous ne sont pas ce qui s’applique réellement. Deux motifs qui se chevauchent n’ont pas d’ordre unique correct ; réordonnez-les dans le JSON natif pour que le plus général vienne en premier.", - "fixOrder": "Corriger l’ordre", - "agentOverrides": "Ces agents redéfinissent les permissions et sont appliqués en dernier, ils l’emportent donc sur tout ce qui est ici : {agents}. Modifiez-les dans le JSON natif ci-dessous, ou activez l’acceptation automatique pour les effacer.", - "legacyTools": "L’ancienne table tools de premier niveau refuse un outil. OpenCode la fusionne avec les permissions, elle s’applique donc par-dessus tout ce qui est affiché ici. Modifiez-la dans le JSON natif ci-dessous, ou activez l’acceptation automatique pour l’effacer.", - "autoAcceptTitle": "Accepter automatiquement toutes les permissions", - "autoAcceptHint": "Chaque appel d’outil — commandes shell, modifications de fichiers, chemins hors du projet — s’exécute sans demander. L’activer remplace les réglages par outil ci-dessous par une seule règle tout-autoriser et efface les surcharges par agent ainsi que les anciens interrupteurs tools qui bloqueraient encore.", - "globalLabel": "Valeur globale par défaut", - "globalHint": "La règle * : elle s’applique à tout ce que les outils ci-dessous ne redéfinissent pas.", - "actionUnset": "Non défini (valeurs OpenCode)", - "actionInherit": "Hériter ({action})", - "actionAllow": "Autoriser", - "actionAsk": "Demander", - "actionDeny": "Refuser", - "perToolTitle": "Permissions par outil", - "reset": "Réinitialiser", - "ruleCount": "règles : {count}", - "rulesToggle": "Règles fines de {tool}", - "rulesHint": "Comparées à l’entrée de l’outil, la dernière correspondance l’emporte : placez donc les motifs larges en premier. * correspond à n’importe quels caractères, ? à exactement un, et un ~ initial désigne votre dossier personnel.", - "noRules": "Aucune règle fine pour l’instant.", - "addRule": "Ajouter une règle", - "deleteRule": "Supprimer la règle {pattern}", - "duplicateRule": "Ce motif existe déjà.", - "blankRule": "Une règle a besoin d’un motif — utilisez l’icône corbeille pour la supprimer.", - "customKeys": "Autres clés de permission du fichier", - "customKeyHint": "Ce n’est pas un outil intégré d’OpenCode — conservé tel quel.", - "keys": { - "bash": "Exécuter des commandes shell, selon la commande analysée", - "edit": "Toutes les modifications de fichiers : edit, write et patch", - "read": "Lire des fichiers, selon le chemin", - "external_directory": "Atteindre des chemins hors du répertoire de travail du projet", - "task": "Lancer des sous-agents, selon le type de sous-agent", - "skill": "Charger des skills, selon leur nom", - "glob": "Trouver des fichiers, selon le motif glob", - "grep": "Rechercher dans le contenu des fichiers, selon le motif", - "list": "Lister le contenu d’un répertoire", - "webfetch": "Récupérer une URL", - "websearch": "Rechercher sur le web", - "lsp": "Exécuter des requêtes LSP", - "todowrite": "Écrire la liste de tâches", - "question": "Vous poser une question", - "doom_loop": "Se déclenche quand le même appel se répète trois fois avec la même entrée" - } - } - }, - "openClaw": { - "gatewayConfig": "Configuration Gateway", - "gatewayDescription": "Configure la connexion OpenClaw Gateway. Prend en charge une gateway locale ou distante.", - "gatewayUrlHint": "Laisser vide pour utiliser gateway.remote.url depuis la configuration locale openclaw.", - "gatewayTokenPlaceholder": "Token d’authentification Gateway", - "gatewayTokenHint": "Utilisez token-file plutôt qu’un token en clair si possible ; configurez-le via le CLI openclaw.", - "sessionKeyHint": "Optionnel. Spécifie la session key de la gateway ; laisser vide pour auto-attribuer une session isolée." - }, - "hermes": { - "configManagement": "Configuration de Hermes", - "configDescription": "Hermes gère ses propres identifiants dans ~/.hermes/.env et ses paramètres dans ~/.hermes/config.yaml. Choisissez un fournisseur, puis définissez la clé d'API et le modèle — codeg écrit les deux fichiers pour vous.", - "providerLabel": "Fournisseur", - "providerHint": "Le fournisseur détermine quelle variable de clé d'API et quel model.provider Hermes utilise. Les fournisseurs OAuth se configurent via la configuration du terminal ci-dessous.", - "groupApiKey": "Fournisseurs avec clé API", - "groupOauth": "Fournisseurs OAuth", - "groupAws": "AWS", - "apiKeyHint": "Enregistrée dans ~/.hermes/.env. Elle n'est jamais injectée dans le processus — Hermes la lit depuis sa propre configuration.", - "modelName": "Modèle", - "oauthHint": "Ce fournisseur utilise OAuth. Exécutez la configuration ci-dessous pour vous authentifier dans votre terminal.", - "awsHint": "Bedrock utilise vos identifiants AWS (environnement ou configuration partagée). Définissez l'ID du modèle ci-dessus et configurez l'accès AWS dans votre environnement.", - "unsupportedProvider": "Ce fournisseur n'est pas modifiable via les champs structurés. Utilisez l'éditeur config.yaml ci-dessous ou la configuration par terminal.", - "setupTitle": "Configuration autogérée", - "setupHint": "La configuration interactive de Hermes nécessite un terminal. Lancez-la ci-dessous ou copiez la commande pour l'exécuter vous-même.", - "runSetup": "Exécuter la configuration de Hermes", - "configureModel": "Configurer le modèle", - "openConfigFolder": "Ouvrir ~/.hermes", - "copyCommand": "Copier la commande", - "commandCopied": "Commande copiée dans le presse-papiers", - "advancedTitle": "Avancé : modifier config.yaml", - "rawConfigHint": "Modifiez directement ~/.hermes/config.yaml. Enregistrer ici écrase le fichier tel quel.", - "saveRawConfig": "Enregistrer config.yaml" - }, - "codebuddy": { - "configManagement": "Configuration de CodeBuddy", - "configDescription": "CodeBuddy s'authentifie avec une clé API. Les versions pour la Chine continentale nécessitent aussi de définir l'environnement sur « Chine (internal) » ; les versions iOA utilisent « iOA ». La version internationale la laisse non définie.", - "apiKeyLabel": "Clé API", - "apiKeyHint": "Enregistré en tant que CODEBUDDY_API_KEY pour cet agent. Vous pouvez aussi vous connecter avec la CLI CodeBuddy dans un terminal.", - "apiKeyHintSelfHosted": "Enregistré en tant que CODEBUDDY_API_KEY pour cet agent. Utilisez la clé émise par votre déploiement privé.", - "environmentLabel": "Environnement", - "environmentHint": "Définit CODEBUDDY_INTERNET_ENVIRONMENT. La Chine continentale doit utiliser « Chine (internal) » ; la version internationale la laisse non définie.", - "envOverseas": "International (par défaut)", - "envChina": "Chine (internal)", - "envIoa": "iOA", - "envSelfHosted": "Auto-hébergé (déploiement privé)", - "baseUrlLabel": "URL de déploiement", - "baseUrlPlaceholder": "https://codebuddy.your-company.com", - "baseUrlHint": "Enregistré comme CODEBUDDY_BASE_URL et dirige CodeBuddy vers votre point de terminaison privé. En auto-hébergement, l’environnement réseau (CODEBUDDY_INTERNET_ENVIRONMENT) reste non défini.", - "baseUrlInvalid": "Saisissez une URL http(s) valide.", - "loginHint": "Pas de clé API ? Exécutez « codebuddy » dans un terminal pour vous connecter avec votre compte Tencent." - }, - "kimiCode": { - "configManagement": "Configuration de Kimi Code", - "configDescription": "`kimi acp` n'accepte qu'un jeton de connexion enregistré ; codeg écrit donc un fournisseur géré dans ~/.kimi-code/config.toml et dépose un jeton d'accès local — l'inférence utilise toujours votre propre clé.", - "statusUnconfigured": "Pas encore configuré", - "statusDirty": "Modifications non enregistrées", - "summaryLabel": "En vigueur", - "gateReadyApiKey": "Clé API écrite dans config.toml", - "gateReadyLogin": "Connecté avec un compte Kimi", - "revealConfig": "Afficher dans le dossier", - "envOverrideWarning": "{keys} est défini et prime sur config.toml. Enregistrer ici la supprime.", - "authModeLabel": "Méthode d'authentification", - "authModeApiKey": "Clé API", - "authModeLogin": "Connexion au compte Kimi (abonnement)", - "authModeApiKeyHint": "Écrit un fournisseur géré dans config.toml et dépose le jeton d'accès pour que les sessions puissent s'ouvrir.", - "loginHint": "Exécutez `kimi login` dans un terminal pour vous connecter avec un compte Kimi par abonnement. codeg ne stocke rien et réutilise la connexion de Kimi. Enregistrer ici supprime le jeton d'accès par clé API de codeg.", - "credentialTitle": "Identifiant", - "interfaceTypeLabel": "Type de fournisseur", - "interfaceTypeHint": "Le protocole de fournisseur que parle Kimi (le `type` de config.toml). Choisissez Kimi / Moonshot pour une clé Moonshot / platform.kimi.com.", - "endpointLabel": "Point de terminaison", - "endpointCustom": "Personnalisé (compatible OpenAI)", - "endpointHint": "International = api.moonshot.ai ; Chine (clés platform.kimi.com) = api.moonshot.cn. Personnalisé pointe vers n'importe quel point de terminaison compatible OpenAI.", - "regionInternational": "International (api.moonshot.ai)", - "regionChina": "Chine (api.moonshot.cn)", - "baseUrlLabel": "URL de base", - "baseUrlHint": "Laissez vide pour utiliser la valeur par défaut du SDK du fournisseur.", - "apiKeyLabel": "Clé API", - "apiKeyHint": "Écrite dans ~/.kimi-code/config.toml et utilisée pour l'inférence. Depuis platform.kimi.com ou platform.kimi.ai.", - "vertexProjectLabel": "Projet GCP (GOOGLE_CLOUD_PROJECT)", - "vertexLocationLabel": "Région GCP (GOOGLE_CLOUD_LOCATION)", - "vertexHint": "Vertex AI utilise les identifiants par défaut de l'application Google — exécutez `gcloud auth application-default login` (aucune clé API).", - "modelTitle": "Modèle", - "modelLabel": "Modèle", - "modelHint": "L'id du modèle écrit dans config.toml. Utilisez « Tester et lister les modèles » pour voir ce à quoi votre clé accède réellement.", - "maxContextLabel": "Taille de contexte maximale", - "maxContextHint": "Obligatoire selon le schéma de Kimi : sans elle, Kimi rejette tout le bloc du modèle et chaque requête reste sans réponse. Par défaut 262144.", - "fetchModels": "Tester et lister les modèles", - "fetchModelsOk": "La clé fonctionne — {count} modèles disponibles", - "fetchModelsEmpty": "La clé fonctionne, mais aucun modèle n'a été renvoyé", - "fetchModelsFailed": "Échec du test", - "fetchModelsNeedsKey": "Saisissez d'abord une clé API et un point de terminaison", - "modelNotInList": "Ce modèle ne figure pas dans la liste accessible à votre clé — Kimi échouera avec « modèle introuvable ».", - "reasoningTitle": "Raisonnement", - "reasoningEnableLabel": "Activer", - "reasoningDescription": "Kimi n'affiche le sélecteur « Thinking » dans la zone de saisie que si le modèle déclare une capacité de raisonnement ; codeg l'écrit donc ici. S'applique aux nouvelles sessions.", - "effortsLabel": "Niveaux proposés", - "effortsHint": "Ces niveaux deviennent les entrées du sélecteur « Thinking ». Kimi transmet le niveau au fournisseur tel quel : choisissez ceux que votre modèle accepte.", - "effortsEmptyHint": "Sans aucun niveau sélectionné, la zone de saisie se limite à un simple interrupteur Off / On.", - "effortsCustomPlaceholder": "Ajouter un autre niveau", - "effortsAdd": "Ajouter", - "defaultEffortLabel": "Niveau par défaut", - "defaultEffortAuto": "Laisser Kimi choisir", - "alwaysThinkingLabel": "Le modèle raisonne toujours — retirer l'entrée Off du sélecteur", - "fixErrorsFirst": "Corrigez d'abord les champs signalés", - "errorModelRequired": "Le modèle est obligatoire", - "errorMaxContextRequired": "La taille de contexte maximale est obligatoire", - "errorMaxContextInvalid": "Doit être un entier positif", - "errorApiKeyRequired": "La clé API est obligatoire", - "errorApiKeyInvalid": "La clé API ne doit pas contenir de sauts de ligne", - "errorBaseUrlRequired": "L'URL de base est obligatoire", - "errorBaseUrlInvalid": "Doit commencer par http:// ou https://", - "errorVertexProjectRequired": "Le projet GCP est obligatoire", - "errorDefaultEffortUnlisted": "Choisissez l'un des niveaux sélectionnés ci-dessus", - "advancedTitle": "Avancé", - "authTypeLabel": "Emplacement de l'identifiant", - "authTypeApiKey": "api_key en ligne", - "authTypeEnv": "Sous-table env du fournisseur", - "authTypeHint": "Où la clé API est écrite à l'intérieur de config.toml.", - "rawEditorLabel": "Modifier config.toml directement", - "rawEditorWarning": "Enregistrer ici écrase tout le fichier tel quel et remplace les réglages structurés ci-dessus.", - "rawEditorPlaceholder": "[providers.codeg]\ntype = \"kimi\"\nbase_url = \"https://api.moonshot.cn/v1\"\napi_key = \"sk-...\"" - }, - "authModeOfficialSubscription": "Abonnement officiel", - "authModeCustomEndpoint": "Endpoint personnalisé", - "authModeCustomEndpointHint": "Configurer manuellement l'URL API et la clé API pour un endpoint personnalisé.", - "authModeModelProvider": "Fournisseur de modèle", - "modelProvider": "Fournisseur de modèle", - "modelProviderHint": "Utiliser l'URL API, la clé API et le modèle d'un fournisseur de modèle configuré.", - "selectModelProvider": "Sélectionner un fournisseur de modèle", - "noModelProviderAvailable": "Aucun fournisseur de modèle configuré pour cet agent. Allez dans les paramètres des fournisseurs de modèle pour en ajouter un.", - "claude": { - "authMode": "Mode d’authentification", - "officialSubscription": "Abonnement officiel", - "officialSubscriptionHint": "Utiliser l'abonnement officiel Anthropic, pas de clé API requise.", - "mainModel": "Modèle principal", - "reasoningModel": "Modèle de raisonnement (thinking)", - "haikuDefaultModel": "Modèle Haiku par défaut", - "sonnetDefaultModel": "Modèle Sonnet par défaut", - "opusDefaultModel": "Modèle Opus par défaut", - "customModelOption": "ID de modèle personnalisé", - "customModelOptionName": "Nom du modèle personnalisé", - "customModelOptionDescription": "Description du modèle personnalisé", - "customModelOptionHint": "Ajoute une entrée personnalisée au sélecteur de modèles de Claude (par exemple un modèle derrière une passerelle/un proxy personnalisé). Le nom et la description sont des informations d'affichage facultatives.", - "effortLevel": "Niveau de raisonnement", - "effortLevelDefault": "Niveau par défaut", - "effortLevel_low": "Bas", - "effortLevel_medium": "Moyen", - "effortLevel_high": "Élevé", - "effortLevel_xhigh": "Très Élevé", - "sendAttributionHeader": "Envoyer l'identifiant d'attribution/facturation à l'API", - "sendAttributionHeaderAria": "Envoyer l'identifiant d'attribution/facturation de Claude Code à l'API", - "disableNonessentialTraffic": "Désactiver la télémétrie ou les requêtes réseau superflues", - "disableNonessentialTrafficAria": "Désactiver la télémétrie ou les requêtes réseau superflues de Claude Code" - }, - "dialogs": { - "confirmDeleteProvider": "Supprimer le provider {providerId} ?", - "confirmDeleteProviderDescription": "La configuration OpenCode et auth JSON seront mises à jour ensemble. Cette action est irréversible.", - "confirmUninstall": "Désinstaller {name} ?", - "confirmUninstallDescription": "Cela supprime la version installée localement. Vous pouvez réinstaller plus tard.", - "customInstallTitle": "Installation personnalisée de {name}", - "customInstallDescription": "Saisissez la version à installer. Cela réinstalle et remplace la version actuellement installée.", - "customInstallVersionLabel": "Numéro de version", - "customInstallInvalid": "Saisissez un numéro de version valide, par ex. 1.2.3.", - "customInstallSubmit": "Installer" - }, - "errors": { - "windowsFileLocked": "Les fichiers de {name} sont utilisés par une session en cours, Windows ne peut donc pas les remplacer. Fermez toutes les sessions {name}, puis réessayez.", - "nativeJsonMustBeObject": "La configuration JSON native doit être un objet", - "nativeJsonInvalid": "Erreur de format de configuration JSON native : {message}", - "openCodeAuthMustBeObject": "OpenCode auth.json doit être un objet JSON", - "openCodeAuthInvalid": "Erreur de format OpenCode auth.json : {message}", - "authMustBeObject": "auth.json doit être un objet JSON", - "authInvalid": "Erreur de format auth.json : {message}", - "providerIdPattern": "L’ID du provider n’accepte que lettres, chiffres, underscore, point et tiret", - "providerExists": "Le provider {providerId} existe déjà", - "modelIdPattern": "L’ID du modèle n’accepte que lettres, chiffres, underscore, point, deux-points et tiret", - "modelExists": "Le modèle {modelId} existe déjà" - }, - "warnings": { - "nativeJsonRecoveredStructured": "La configuration JSON native est invalide ; réinitialisée en configuration structurée", - "nativeJsonRecoveredOpenCode": "La configuration JSON native est invalide ; réinitialisée en configuration structurée OpenCode", - "openCodeAuthRecovered": "OpenCode auth.json est invalide ; réinitialisé en configuration par défaut", - "authRecoveredStructured": "auth.json est invalide ; réinitialisé en configuration structurée" - }, - "toasts": { - "agentActionCompleted": "{name} {action} terminé", - "agentActionFailed": "{name} {action} échoué", - "localVersion": "Version locale : {version}", - "installCompletedVersionLater": "Installation terminée, la version sera mise à jour à la prochaine vérification", - "uninstallCompleted": "Désinstallation de {name} terminée", - "uninstallFailed": "Échec de la désinstallation de {name}", - "localVersionRemoved": "Version locale supprimée", - "saveAgentOrderFailed": "Échec de l’enregistrement de l’ordre des agents", - "saveAgentSwitchFailed": "Échec de l’enregistrement du switch agent", - "saveEnvFailed": "Échec de l’enregistrement des variables d’environnement", - "grokSaved": "Configuration Grok enregistrée", - "saveGrokNativeFailed": "Échec de l'enregistrement de la configuration native Grok", - "saveGrokApiKeyFailed": "Paramètres enregistrés, mais la clé API n'a pas pu être enregistrée", - "cursorSaved": "Configuration Cursor enregistrée", - "saveCursorConfigFailed": "Échec de l'enregistrement de la configuration Cursor", - "codexSaved": "Configuration Codex enregistrée", - "saveCodexNativeFailed": "Échec de l’enregistrement de la configuration native Codex", - "geminiSaved": "Configuration Gemini enregistrée", - "saveGeminiFailed": "Échec de l’enregistrement de la configuration Gemini", - "providerDeleted": "Provider {providerId} supprimé", - "providerDeleteFailed": "Échec de suppression du provider {providerId}", - "providerSaved": "Provider {providerId} enregistré", - "saveProviderFailed": "Échec d’enregistrement du provider {providerId}", - "openCodeConfigSynced": "La configuration OpenCode et auth JSON ont été synchronisés.", - "openCodeSaved": "Configuration OpenCode enregistrée", - "saveOpenCodeFailed": "Échec de l’enregistrement de la configuration OpenCode", - "openClawSaved": "Configuration OpenClaw enregistrée", - "saveOpenClawFailed": "Échec de l’enregistrement de la configuration OpenClaw", - "configSaved": "Configuration enregistrée", - "configSavedHint": "Les sessions existantes doivent être rouvertes pour prendre effet", - "saveConfigManagementFailed": "Échec de l’enregistrement de la gestion de configuration", - "clineSaved": "Configuration Cline enregistrée", - "saveClineFailed": "Échec de l'enregistrement de la configuration Cline", - "hermesSaved": "Configuration Hermes enregistrée", - "saveHermesFailed": "Échec de l'enregistrement de la configuration Hermes", - "codeBuddySaved": "Configuration CodeBuddy enregistrée", - "saveCodeBuddyFailed": "Échec de l'enregistrement de la configuration CodeBuddy", - "kimiCodeSaved": "Configuration de Kimi Code enregistrée", - "saveKimiCodeFailed": "Échec de l'enregistrement de la configuration de Kimi Code", - "deepseekSaved": "Configuration DeepSeek enregistrée", - "saveDeepSeekFailed": "Échec de l'enregistrement de la configuration DeepSeek", - "modelProviderRequired": "Veuillez sélectionner un fournisseur de modèle avant d'enregistrer.", - "affectedRunningSessions": "{count, plural, one {# session active doit se reconnecter pour appliquer la modification} other {# sessions actives doivent se reconnecter pour appliquer la modification}}", - "providerConnected": "{providerId} connecté", - "connectFailed": "Échec de la connexion de {providerId}", - "providerDisconnected": "{providerId} déconnecté", - "disconnectFailed": "Échec de la déconnexion de {providerId}", - "catalogRefreshed": "Catalogue actualisé — {count} fournisseurs", - "catalogRefreshFailed": "Échec de l''actualisation du catalogue", - "piSaved": "Configuration Pi enregistrée", - "savePiFailed": "Échec de l'enregistrement de la config Pi", - "piRuntimeSaved": "Exécution Pi enregistrée", - "savePiRuntimeFailed": "Échec de l'enregistrement de l'exécution Pi", - "piBinaryInstalled": "pi installé", - "piBinaryInstallFailed": "Échec de l'installation de pi", - "piBinaryUninstalled": "pi désinstallé", - "piBinaryUninstallFailed": "Échec de la désinstallation de pi", - "savePiTrustFailed": "Échec de l'enregistrement de la confiance de l'espace de travail" - }, - "version": { - "statusLabel": "Statut de version", - "notInstalled": "Non installé", - "remoteLocal": "Distant : {remoteVersion} · Local : {localVersion}", - "localOnly": "Local : {localVersion}", - "localInstalled": "{versionText}. Installé.", - "platformUnsupported": "{versionText}. La plateforme actuelle ne prend pas en charge cet agent.", - "uvxNotReady": "{versionText}. Le runtime uv n'est pas installé — installez-le depuis la vérification uv ci-dessous pour utiliser cet agent.", - "clickInstall": "{versionText}. Cliquez sur Installer à droite.", - "localUnrecognized": "{versionText}. La version locale n’est pas comparable ; essayez une mise à niveau pour écraser l’installation.", - "upgradeAvailable": "{versionText}. Mise à niveau disponible.", - "remoteUnavailable": "{versionText}. La version distante est actuellement indisponible.", - "latest": "{versionText}. Déjà à jour." - }, - "adapter": { - "label": "Adaptateur ACP", - "badge": "Adaptateur ACP", - "badgeHint": "Pour cet agent, Codeg installe un paquet adaptateur ACP, pas la CLI de l'éditeur. Les deux sont indépendants et partagent la même configuration.", - "learnMore": "En savoir plus", - "missingWithNative": "Votre {nativeLabel} a été trouvée dans {nativePath}. Codeg pilote les agents via ACP, or cette CLI ne parle pas ACP : Codeg a donc besoin d'un paquet adaptateur distinct, {adapterPackage}, maintenu par le projet Agent Client Protocol (à l'origine Zed). Il embarque son propre runtime, ne modifie ni ne remplace jamais votre commande {nativeCmd}, et lit le même {configDir} — votre connexion et vos réglages sont conservés. Installez-le ci-dessous.", - "missing": "Codeg pilote les agents via ACP, or la {nativeLabel} ne parle pas ACP : Codeg a donc besoin d'un paquet adaptateur distinct, {adapterPackage}, maintenu par le projet Agent Client Protocol (à l'origine Zed). Il embarque son propre runtime, la CLI {nativeCmd} n'est donc pas un prérequis ; si vous l'avez déjà, les deux coexistent et partagent la connexion et les réglages de {configDir}. Installez-le ci-dessous.", - "readyWithNative": "L'adaptateur {adapterCmd} est installé : c'est lui que Codeg lance, pas votre {nativeCmd} situé dans {nativePath}. Ce sont des paquets distincts qui coexistent, et tous deux lisent {configDir} : connexion et réglages sont partagés.", - "ready": "L'adaptateur {adapterCmd} est installé : c'est lui que Codeg lance. Il embarque son propre runtime, la {nativeLabel} n'est donc pas nécessaire ; si vous l'installez plus tard, les deux coexistent et partagent {configDir}." - }, - "cline": { - "configDescription": "Configurez le fournisseur API et les identifiants Cline. Les paramètres sont enregistrés dans ~/.cline/data/." - }, - "opencodePlugins": { - "title": "Plugins OpenCode", - "declared": "Plugins déclarés", - "noPlugins": "Aucun plugin déclaré dans opencode.json", - "status": { - "installed": "Installé", - "missing": "Non installé" - }, - "installAll": "Installer tous les manquants", - "pinVersions": "Fixer les versions @latest", - "install": "Installer", - "uninstall": "Désinstaller", - "refresh": "Actualiser", - "success": "Tous les plugins ont été installés avec succès", - "failed": "L'opération du plugin a échoué" - }, - "pi": { - "configManagement": "Configuration de Pi", - "configDescription": "Pi s'authentifie via la clé API de votre fournisseur de modèle. La clé est écrite dans ~/.pi/agent/auth.json et le choix du modèle dans settings.json.", - "providerLabel": "Fournisseur", - "modelLabel": "Modèle", - "thinkingLabel": "Réflexion", - "thinking": { - "off": "Désactivé", - "low": "Faible", - "medium": "Moyen", - "high": "Élevé", - "minimal": "Minimal", - "xhigh": "Très élevé" - }, - "apiKeyLabel": "Clé API", - "apiKeyHint": "Enregistrée dans ~/.pi/agent/auth.json pour le fournisseur sélectionné.", - "apiKeySetPlaceholder": "•••••• (enregistrée — laisser vide pour conserver)", - "saveConfig": "Enregistrer la config Pi", - "providerModelRequired": "Le fournisseur et le modèle sont requis", - "runtimeTitle": "Exécution", - "runtimeDescription": "Choisissez quel binaire pi s'exécute. Utilisez celui par défaut ou pointez vers votre propre build de pi.", - "modeDefault": "pi par défaut", - "modeDefaultHint": "Utilise l'adaptateur pi-acp intégré avec le pi de votre PATH. Installer pi : npm install -g @earendil-works/pi-coding-agent", - "modeCustom": "pi personnalisé", - "modeCustomHint": "Exécutez votre propre build, installation ou wrapper de pi.", - "commandLabel": "Commande ou chemin pi", - "commandHint": "Un chemin absolu, un nom de commande dans le PATH, ou un script wrapper (par ex. ./pi-test.sh d'un monorepo).", - "commandNotFound": "Commande introuvable", - "validate": "Valider", - "advanced": "Avancé", - "configDirLabel": "Répertoire de config (PI_CODING_AGENT_DIR)", - "sessionDirLabel": "Répertoire des sessions (PI_CODING_AGENT_SESSION_DIR)", - "flagsHint": "pi-acp ne transmet pas les options pi personnalisées (--approve, -e, …) — encapsulez pi dans un script et pointez-y la commande.", - "customIncomplete": "Saisissez une commande pi pour enregistrer", - "saveRuntime": "Enregistrer l'exécution", - "providerPlaceholder": "Sélectionner un fournisseur", - "customProvider": "Fournisseur personnalisé…", - "providerIdLabel": "ID du fournisseur", - "apiProtocolLabel": "Protocole API", - "baseUrlLabel": "Point de terminaison API (Base URL)", - "customProviderHint": "Définit un fournisseur dans ~/.pi/agent/models.json vers votre point de terminaison. La plupart des serveurs auto-hébergés ou proxy utilisent openai-completions.", - "baseUrlRequired": "Le point de terminaison API (Base URL) est requis", - "binaryTitle": "binaire pi (pi-coding-agent)", - "binaryDescription": "pi-acp exécute ce binaire pi. Installez-le ici, ou faites pointer pi-acp vers votre propre build ci-dessous.", - "binaryInstalled": "Installé", - "binaryMissing": "Non installé", - "binaryChecking": "Vérification…", - "installBinary": "Installer pi", - "installing": "Installation…", - "recheck": "Revérifier", - "configDirSkillsNote": "Avec un répertoire de configuration personnalisé, les compétences, experts et outils bureautiques gérés dans les Paramètres ne s'appliquent pas à ce pi — gérez ses compétences directement dans ce dossier.", - "projectTrustTitle": "Confiance du projet", - "projectTrustDescription": "Dossiers depuis lesquels vous avez autorisé pi à charger des fichiers de projet. Un dossier de confiance permet aux .pi/extensions de ce dépôt d'exécuter du code au démarrage de pi, s'applique à tous les dossiers qu'il contient et sert aussi lorsque vous lancez pi dans un terminal.", - "projectTrustLoading": "Chargement…", - "projectTrustEmpty": "Aucun dossier n'a encore été décidé.", - "projectTrustTrusted": "Approuvé", - "projectTrustDenied": "Non approuvé", - "projectTrustRevoke": "Révoquer", - "reasoningTitle": "Raisonnement", - "reasoningEnableLabel": "Activer", - "reasoningDescription": "pi n'envoie un effort de raisonnement que pour un modèle qui le déclare — sur un modèle non déclaré, tous les niveaux sont ramenés à Off, si bien que le sélecteur du composeur revient en arrière dès qu'on y touche. Écrit dans l'entrée de ce modèle dans models.json.", - "levelsLabel": "Niveaux disponibles", - "levelsHint": "Ils deviennent les lignes du sélecteur de raisonnement du composeur. Choisissez ceux que votre endpoint accepte ; pi refuse tout niveau absent d'ici.", - "levelsEmptyError": "Choisissez au moins un niveau — sans aucun, pi retombe sur Off.", - "wireValuesTitle": "Avancé : valeurs envoyées au fournisseur", - "wireValuesHint": "Laissez vide pour envoyer le nom du niveau tel quel. Renseignez-le si votre endpoint attend autre chose — les backends façon Google veulent LOW / HIGH.", - "defaultLevelUnlisted": "Ce niveau n'est pas dans la liste ci-dessus — pi le ramènerait plus bas." - }, - "addCustomAgent": "Ajouter un agent personnalisé", - "addCustomAgentHint": "Enregistrez n'importe quel agent compatible ACP. Choisissez-en un dans le registre ACP public ou collez ses informations de registre.", - "customAgentFromRegistry": "Registre ACP", - "customAgentManual": "Manuel", - "customAgentSearchPlaceholder": "Rechercher des agents…", - "customAgentLoadingCatalog": "Chargement du registre ACP…", - "customAgentRetry": "Réessayer", - "customAgentNoResults": "Aucun agent correspondant", - "customAgentAdd": "Ajouter", - "customAgentAlreadyAdded": "Ajouté", - "customAgentUnsupportedPlatform": "Aucune version disponible pour cette plateforme", - "customAgentAdded": "{name} ajouté", - "customAgentIdLabel": "ID du registre", - "customAgentNameLabel": "Nom affiché", - "customAgentVersionLabel": "Version", - "customAgentSpecLabel": "Distribution (JSON)", - "customAgentSpecHint": "Même forme que l’objet distribution du registre ACP : canaux npx, uvx et binary, ou collez une entrée de registre complète. Pour npx/uvx, cmd est l’exécutable installé par le paquet — déduit du nom du paquet s’il est omis, à préciser donc quand ils diffèrent. binary est organisé par clé de plateforme (cette machine : {platform}) ; son cmd est le chemin de lancement dans l’archive et sha256 vérifie éventuellement le téléchargement.", - "customAgentTemplateLabel": "Modèles", - "customAgentKindLabel": "Lancer via", - "customAgentInvalidJson": "JSON invalide", - "customAgentNoDistribution": "Aucune distribution npx, uvx ou binary trouvée", - "customAgentCancel": "Annuler", - "customAgentSave": "Ajouter l'agent", - "customAgentSaveChanges": "Enregistrer les modifications", - "customAgentEdit": "Modifier l’agent", - "customAgentEditHint": "Modifiez le nom, l’icône, la distribution et les déclarations de skills. L’ID de l’agent ne peut pas être modifié.", - "customAgentEditNotFound": "Agent personnalisé {id} introuvable", - "customAgentSaved": "{name} enregistré", - "customAgentVersionProbeLabel": "Commande de version (facultatif)", - "customAgentVersionProbeHint": "Commande qui affiche la version installée localement. Laissée vide, codeg exécute la commande de l’agent avec --version.", - "customAgentRemove": "Supprimer l'agent", - "customAgentRemoveHint": "Supprime la définition de l'agent. Les conversations existantes conservent leur historique ; l'agent ne peut simplement plus être lancé.", - "customAgentIconLabel": "Icône (facultatif)", - "customAgentIconUpload": "Téléverser", - "customAgentIconReplace": "Remplacer", - "customAgentIconClear": "Retirer l'icône", - "customAgentIconHint": "Enregistrée avec l'agent, elle fonctionne donc hors ligne. Sans icône, une initiale colorée est utilisée.", - "customAgentSkillsLabel": "Skills (.agents/skills partagé)", - "customAgentSkillsHint": "Déclare que cet agent lit le magasin partagé .agents/skills (répertoires global et projet) et l'ajoute à toutes les matrices de compétences. Les compétences qui y sont liées sont visibles par tous les agents qui lisent ce magasin partagé.", - "customAgentSkillsDirLabel": "Répertoire de skills dédié", - "customAgentSkillsDirHint": "Chemin absolu du répertoire depuis lequel cet agent charge ses skills — son propre magasin, en plus du magasin partagé ou à sa place. ~ est remplacé par le répertoire personnel ; les skills liées y sont placées en premier.", - "customAgentMcpLabel": "Prise en charge de MCP", - "customAgentMcpHint": "Transmet le compagnon MCP intégré de codeg à cet agent au démarrage de la session — le canal derrière la délégation, le retour en direct et les outils de tâches. Désactivez-le pour un agent qui refuse les serveurs MCP et ne parvient pas à se connecter ; le changement s'applique à la prochaine connexion.", - "customAgentIconNotAnImage": "Choisissez un fichier image.", - "customAgentIconTooLarge": "L'icône doit faire moins de {limit} Ko.", - "customAgentIconReadFailed": "Impossible de lire cette image.", - "customAgentRemoveConfirm": "Supprimer {name} ? Les conversations existantes sont conservées, mais l'agent ne pourra plus être lancé.", - "customAgentRemoveWithData": "Supprimer aussi l'historique de conversation enregistré", - "customAgentRemoved": "{name} supprimé", - "customAgentBadge": "Personnalisé", - "customAgentNotLaunchable": "Cet agent ne peut pas démarrer ici : {reason}" - }, - "SettingsPages": { - "agentsLoading": "Chargement des paramètres des agents...", - "skillPacksLoading": "Chargement des packs de compétences…" - }, - "GeneralSettings": { - "loading": "Chargement...", - "sectionTitle": "Général", - "sectionDescription": "Préférences centralisées pour le terminal par défaut, l'accélération du rendu et la délégation multi-agents.", - "terminalTitle": "Terminal par défaut", - "terminalDescription": "Choisissez le shell utilisé à l'ouverture de nouveaux onglets de terminal depuis la barre de terminal ou l'arborescence des fichiers. Les agents l'utilisent aussi lorsqu'ils demandent à codeg d'exécuter une ligne de commande complète.", - "terminalSystemDefault": "Par défaut système", - "terminalPowerShell7": "PowerShell 7 (pwsh)", - "terminalWindowsPowerShell": "Windows PowerShell", - "terminalCmd": "Invite de commandes (cmd)", - "terminalSaveFailed": "Échec de l’enregistrement des paramètres du terminal : {message}", - "terminalShellCustom": "Chemin personnalisé", - "terminalShellCustomPath": "Chemin du shell", - "terminalShellCustomPlaceholder": "/usr/local/bin/fish", - "terminalShellCustomSave": "Enregistrer", - "terminalShellCustomHint": "Indiquez un chemin absolu ou un nom résolvable via PATH.", - "terminalShellNotInstalled": "non installé", - "terminalShellNotFoundWarning": "Ce chemin n’existe pas sur cet hôte.", - "terminalCurrentShell": "Actuellement utilisé : {path}", - "renderingDescription": "Désactivez l’accélération matérielle si l’application affiche un écran noir ou des défauts de rendu (fréquent sur certaines GPU AMD ou GPU Intel intégrées). N’a d’effet que sur la version Windows de bureau.", - "disableHardwareAcceleration": "Désactiver l’accélération matérielle", - "renderingSaveFailed": "Échec de l’enregistrement des paramètres de rendu : {message}", - "restartRequired": "Enregistré. Redémarrez l’application pour appliquer la modification.", - "restartNow": "Redémarrer maintenant", - "restartFailed": "Échec du redémarrage : {message}", - "loadFailed": "Échec du chargement : {message}" - }, - "LoginPage": { - "documentTitle": "Connexion - codeg", - "brand": "Codeg", - "subtitle": "Saisissez votre jeton d'accès pour vous connecter à l'application de bureau", - "tokenPlaceholder": "Jeton d'accès", - "connect": "Se connecter", - "connecting": "Connexion...", - "helpText": "Vous trouverez votre jeton dans l'application de bureau sous Paramètres → Service Web", - "invalidToken": "Jeton invalide. Veuillez vérifier et réessayer.", - "connectionFailed": "Échec de la connexion (HTTP {status})", - "networkError": "Impossible de se connecter au serveur" - }, - "CommitPage": { - "title": "Valider", - "invalidFolderId": "ID de dossier invalide", - "loadingRepo": "Chargement du dépôt..." - }, - "MergePage": { - "title": "Résoudre les conflits", - "invalidFolderId": "ID de dossier invalide", - "loadingRepo": "Chargement du dépôt...", - "localVersion": "Local (Le nôtre)", - "result": "Résultat", - "remoteVersion": "Distant (Le leur)", - "acceptLocal": "Accepter le local", - "acceptRemote": "Accepter le distant", - "markResolved": "Marquer comme résolu", - "abortMerge": "Abandonner", - "completeMerge": "Terminer la fusion", - "unresolvedConflicts": "Il reste des marqueurs de conflit non résolus dans ce fichier", - "fileResolved": "Fichier résolu avec succès", - "allResolved": "Tous les conflits sont résolus", - "conflictFiles": "Fichiers en conflit", - "loadingFile": "Chargement du fichier...", - "preparingMerge": "Préparation de la fusion...", - "selectFile": "Sélectionner un fichier à résoudre", - "noConflicts": "Aucun fichier en conflit", - "skipFile": "Passer", - "abortSuccess": "Opération abandonnée", - "applyAllNonConflicting": "Appliquer tous les changements non conflictuels", - "applyLeftNonConflicting": "Appliquer local", - "applyRightNonConflicting": "Appliquer distant" - }, - "ImportSessions": { - "title": "Importer les sessions locales", - "scanningTitle": "Analyse des sessions locales des agents…", - "scanningHint": "Parcours du stockage local des sessions de chaque agent. Cela peut prendre un moment avec de gros historiques. Les sessions déjà importées sont actualisées au passage.", - "scanFailed": "Échec de l'analyse", - "retry": "Réessayer", - "rescan": "Réanalyser", - "empty": "Aucune session locale trouvée", - "emptyHint": "Aucun stockage de sessions d'agent n'a été trouvé sur cette machine.", - "noMatches": "Aucune session ne correspond aux filtres actuels", - "searchPlaceholder": "Rechercher un titre ou un chemin…", - "allAgents": "Tous les agents", - "onlyImportable": "Importables uniquement", - "selectAll": "Tout sélectionner", - "clearSelection": "Effacer", - "expandAll": "Tout développer", - "collapseAll": "Tout réduire", - "summaryCounts": "{total} sessions · {importable} importables · {folders} dossiers", - "noFolderSkipped": "{count} sans dossier de projet ignorées", - "folderNew": "Nouveau", - "folderCounts": "{importable}/{total} importables", - "toggleFolderAria": "Sélectionner toutes les sessions importables de {name}", - "toggleSessionAria": "Sélectionner la session {title}", - "statusImported": "Importée", - "statusDeleted": "Supprimée", - "untitled": "Session sans titre", - "messageCount": "{count} messages", - "selectedCount": "{count} sélectionnées", - "importSelected": "Importer la sélection", - "importing": "Importation…", - "close": "Fermer", - "doneTitle": "Importation terminée", - "doneImported": "Importées", - "doneUpdated": "Actualisées", - "doneSkipped": "Ignorées", - "doneCreatedFolders": "Dossiers créés", - "doneNotFound": "Introuvables", - "doneFailed": "Échouées", - "continueImport": "Continuer l'import", - "toasts": { - "importFailed": "Échec de l'import : {message}" - } - }, - "Folder": { - "workspaceStatus": { - "degradedTitle": "Mises à jour en temps réel indisponibles", - "degradedHint": "L’observateur n’a pas pu démarrer (par ex. permission refusée). Actualisez manuellement pour voir les modifications.", - "retry": "Réessayer", - "retrying": "Nouvelle tentative..." - }, - "common": { - "all": "Tout", - "cancel": "Annuler", - "close": "Fermer", - "closeOthers": "Fermer les autres", - "closeAll": "Tout fermer", - "confirm": "Confirmer", - "save": "Enregistrer", - "delete": "Supprimer", - "rename": "Renommer", - "loading": "Chargement...", - "refresh": "Actualiser", - "refreshing": "Actualisation...", - "create": "Créer", - "createAndSwitch": "Créer et basculer", - "openFile": "Ouvrir le fichier", - "viewDiff": "Voir le Diff", - "push": "Pousser..." - }, - "statusLabels": { - "in_progress": "En cours", - "pending_review": "Revue", - "completed": "Terminé", - "cancelled": "Annulé" - }, - "sidebar": { - "title": "Discussions", - "locateActiveConversation": "Localiser la conversation active", - "expandAllGroups": "Développer tous les groupes", - "collapseAllGroups": "Réduire tous les groupes", - "newConversation": "Nouvelle conversation", - "newConversationShort": "Nouvelle", - "newChat": "Nouvelle conversation", - "search": "Rechercher", - "noConversationsFound": "Aucune conversation trouvée.", - "importLocalSessions": "Importer les sessions locales", - "importing": "Import en cours...", - "error": "Erreur : {message}", - "completeAllSessions": "Terminer toutes les sessions", - "completeAllReviewTitle": "Terminer toutes les sessions en revue ?", - "completeAllReviewDescription": "Cela marquera comme terminées toutes les {count, plural, one {# session} other {# sessions}} en Revue.", - "completing": "Finalisation...", - "toasts": { - "importedSessions": "{imported, plural, one {# session} other {# sessions}} importée(s), {skipped} ignorée(s)", - "importedAndUpdated": "{imported, plural, one {# session} other {# sessions}} importée(s), {updated, plural, one {# titre} other {# titres}} mis à jour, {skipped} ignorée(s)", - "updatedTitles": "{updated, plural, one {# titre} other {# titres}} mis à jour, {skipped} ignorée(s)", - "noNewSessionsFound": "Aucune nouvelle session trouvée ({skipped} ignorée(s))", - "importFailed": "Échec de l'import : {message}", - "reviewCompleted": "{count, plural, one {# session en revue} other {# sessions en revue}} marquée(s) comme terminée(s)", - "completeReviewFailed": "Échec de la finalisation des sessions en revue : {message}", - "folderOpened": "Dossier {name} ouvert", - "folderRemoved": "Dossier {name} retiré", - "openFolderFailed": "Échec de l'ouverture du dossier", - "removeFolderFailed": "Échec de la suppression du dossier : {message}", - "reorderFoldersFailed": "Échec du réordonnancement des dossiers : {message}", - "changeFolderColorFailed": "Échec du changement de couleur : {message}", - "setFolderAliasFailed": "Échec de la définition de l'alias : {message}", - "changeFolderDefaultAgentFailed": "Échec de la définition de l'agent par défaut : {message}" - }, - "statsLabel": "{folders} dossiers · {convos} conversations", - "reorderHandle": "Glisser pour réorganiser", - "openFolder": "Ouvrir le dossier", - "searchPlaceholder": "Rechercher des conversations...", - "viewOptions": "Options d'affichage", - "showCompleted": "Afficher les conversations terminées", - "showWorktrees": "Afficher les dossiers de worktree", - "showRecent": "Afficher le groupe Récents", - "moreOptions": "Plus d'options", - "sortBy": "Trier par", - "sortByCreatedAt": "Date de création", - "sortByUpdatedAt": "Date de mise à jour", - "sectionOrder": "Ordre des sections", - "sectionOrderMoveUp": "Monter", - "sectionOrderMoveDown": "Descendre", - "sectionOrderItemLabel": "{name} — position {position} sur {total}", - "statusRunningBadge": "En cours", - "runningCountBadge": "{count, plural, one {# session en cours} other {# sessions en cours}}", - "statusCancelledBadge": "Annulé", - "worktreeRemovedBadge": "Worktree d'origine supprimé", - "conversationCountUnit": "{count, plural, one {# conversation} other {# conversations}}", - "emptyFolderHint": "Aucune conversation", - "noMatchingConversations": "Aucune conversation correspondante", - "noUnfinishedConversations": "Aucune conversation en cours. Activez « Afficher les terminées » dans le menu en haut à droite.", - "removeFolderConfirmTitle": "Retirer le dossier de l'espace de travail ?", - "removeFolderConfirmDescription": "Retirer \"{name}\" de l'espace de travail ? Les onglets et terminaux associés seront fermés.", - "folderHeaderMenu": { - "manageConversations": "Gérer les conversations…", - "manageLinks": "Dossiers liés", - "changeColor": "Changer la couleur", - "useThemeColor": "Utiliser le thème de l'app", - "setDefaultAgent": "Définir l'agent par défaut", - "defaultAgentNone": "Aucun (utiliser la valeur globale)", - "agentUnavailableSuffix": "(indisponible)", - "loadingAgents": "Chargement des agents…", - "setAlias": "Définir un alias…", - "setAliasTitle": "Définir l'alias du dossier", - "setAliasPlaceholder": "Saisir un alias (laisser vide pour effacer)", - "setAliasSave": "Enregistrer", - "setAliasCancel": "Annuler", - "removeFromWorkspace": "Retirer de l'espace de travail" - }, - "manageConversations": { - "title": "Gérer les conversations", - "searchPlaceholder": "Rechercher par titre…", - "agentFilterAll": "Tous les agents", - "statusFilterAll": "Tous les statuts", - "folderFilterAll": "Tous les dossiers", - "branchFilterAll": "Toutes les branches", - "branchNone": "Aucune branche", - "branchSearchPlaceholder": "Rechercher des branches…", - "noMatchingBranches": "Aucune branche correspondante", - "selectAllVisible": "Tout sélectionner", - "deselectAll": "Tout désélectionner", - "selectedCount": "{count} sélectionnée(s)", - "matchedCount": "{count} correspondance(s)", - "untitledConversation": "Conversation sans titre", - "setStatus": "Définir le statut…", - "deleteSelected": "Supprimer", - "noConversations": "Aucune conversation dans ce dossier.", - "noConversationsWorkspace": "Aucune conversation dans l'espace de travail.", - "noMatchingConversations": "Aucune conversation ne correspond aux filtres.", - "confirmDeleteTitle": "Supprimer {count} conversation(s) ?", - "confirmDeleteDescription": "Cette action est irréversible.", - "toastDeleted": "{count} conversation(s) supprimée(s)", - "toastStatusUpdated": "Statut mis à jour pour {count} conversation(s)", - "toastOpFailed": "Échec de l'opération : {message}" - }, - "sectionPinned": "Épinglées", - "sectionFolders": "Dossiers", - "sectionChats": "Discussion", - "sectionRecent": "Récents", - "noChats": "Aucune discussion", - "noRecent": "Aucune conversation récente", - "showMoreRecent": "Afficher plus ({count})", - "noFolders": "Aucun dossier ouvert", - "newChatAction": "Nouvelle discussion", - "automations": "Automatisations", - "tasks": "Tâches à faire", - "loadingSubsessions": "Chargement des sous-conversations…" - }, - "conversation": { - "reloadFailed": "Échec du rechargement de la conversation : {message}", - "reloaded": "Conversation rechargée", - "reload": "Recharger", - "activeConversationIndicator": "Conversation active", - "newConversation": "Nouvelle conversation", - "closeConversation": "Fermer la conversation", - "copyText": "Copier le texte", - "copyTextSuccess": "Copié", - "copyTextFailed": "Échec de la copie", - "forkSession": "Dupliquer la session", - "forkSessionSuccess": "Session dupliquée avec succès", - "forkSessionFailed": "Échec de la duplication de la session : {error}", - "exportConversation": "Exporter la conversation", - "exportImage": "Image", - "exportMarkdown": "Markdown", - "exportHtml": "HTML", - "exportSuccess": "Conversation exportée", - "exportFailed": "Échec de l'exportation", - "exportImageTooLong": "La conversation est trop longue pour être exportée en image", - "exportLabels": { - "untitledConversation": "Conversation sans titre", - "agent": "Agent", - "model": "Modèle", - "status": "Statut", - "started": "Début", - "updated": "Mis à jour", - "tokens": "Statistiques de tokens", - "duration": "Durée", - "inputTokens": "Entrée", - "outputTokens": "Sortie", - "cacheRead": "Cache lu", - "cacheWrite": "Cache écrit", - "user": "Utilisateur", - "assistant": "Assistant", - "system": "Système", - "toolResult": "Résultat", - "toolError": "Erreur" - }, - "moreActions": "Plus d’actions" - }, - "sessionDetails": { - "menuLabel": "Détails de la session", - "noActiveSession": "Aucune session active", - "title": "Détails de la session", - "subtitle": "Métadonnées de la session et utilisation des tokens", - "fieldTitle": "Titre", - "untitled": "Conversation sans titre", - "sessionId": "ID de session", - "externalId": "ID d'extension", - "agent": "Agent", - "model": "Modèle", - "status": "Statut", - "gitBranch": "Branche Git", - "parentId": "Session parente", - "tokensHeading": "Utilisation des tokens", - "totalTokens": "Total", - "inputTokens": "Entrée", - "outputTokens": "Sortie", - "cacheWrite": "Cache écrit", - "cacheRead": "Cache lu", - "contextWindow": "Fenêtre de contexte", - "duration": "Durée", - "loadingStats": "Chargement de l'utilisation des tokens…", - "loadFailed": "Échec du chargement de l'utilisation des tokens", - "noStats": "Aucune utilisation enregistrée", - "timestampsHeading": "Horodatage", - "createdAt": "Créé", - "updatedAt": "Mis à jour", - "none": "—", - "copyField": "Copier {field}", - "copiedField": "{field} copié" - }, - "conversationCard": { - "untitledConversation": "Conversation sans titre", - "newConversation": "Nouvelle conversation", - "rename": "Renommer", - "status": "Statut", - "delete": "Supprimer", - "importLocalSessions": "Importer les sessions locales", - "importing": "Import en cours...", - "renameConversation": "Renommer la conversation", - "deleteConversationTitle": "Supprimer la conversation ?", - "deleteConversationDescription": "Cela supprimera \"{title}\". Cette action est irréversible.", - "cancel": "Annuler", - "save": "Enregistrer", - "pin": "Épingler", - "unpin": "Désépingler", - "markCompleted": "Marquer comme terminé", - "reopen": "Rouvrir", - "expandSubsessions": "Développer les sous-conversations", - "collapseSubsessions": "Réduire les sous-conversations" - }, - "search": { - "dialogTitle": "Rechercher", - "dialogTitleWithFolder": "Rechercher — {name}", - "tabConversations": "Conversations", - "tabFiles": "Fichiers", - "placeholder": "Rechercher des conversations...", - "filePlaceholder": "Rechercher des fichiers ou répertoires...", - "allAgents": "Tout", - "searching": "Recherche...", - "typeToSearch": "Tapez pour rechercher des conversations", - "typeToSearchFiles": "Tapez pour rechercher des fichiers ou répertoires", - "noResults": "Aucun résultat trouvé.", - "untitledConversation": "Conversation sans titre" - }, - "folderTitleBar": { - "showSidebar": "Afficher la barre latérale", - "hideSidebar": "Masquer la barre latérale", - "toggleTerminal": "Basculer le terminal", - "toggleAuxPanel": "Basculer le panneau auxiliaire", - "search": "Rechercher", - "openSettings": "Ouvrir les paramètres", - "backToConversations": "Retour aux conversations", - "withShortcut": "{label} (raccourci : {shortcut})" - }, - "statusBar": { - "connection": { - "connected": "Connecté", - "connecting": "Connexion...", - "prompting": "Réponse...", - "error": "Erreur de connexion", - "disconnected": "Déconnecté", - "tooltip": "{agent} : {status}", - "tooltipError": "{agent} : {error}", - "title": "Connexion de l'agent", - "triggerAria": "Connexion de l'agent : {status}", - "workingDir": "Répertoire de travail", - "sessionId": "ID de session", - "viewerNote": "Rattaché à une session appartenant à un autre client : la reconnexion ne rattache que cette vue.", - "reconnectInterrupts": "La reconnexion redémarre l'agent et interrompt le travail en cours.", - "reconnect": "Reconnecter", - "reconnecting": "Reconnexion...", - "reconnectUnavailable": "Aucune session à laquelle se reconnecter pour l'instant." - }, - "tasks": { - "title": "Tâches" - }, - "alerts": { - "title": "Alertes", - "empty": "Aucune alerte", - "details": "Détails" - }, - "stats": { - "conversations": "{count} discussions", - "openUsage": "Voir les statistiques de sessions et l'usage de tokens" - }, - "tokens": { - "contextWindowUsageAria": "Utilisation de la fenêtre de contexte", - "contextWindow": "Fenêtre de contexte", - "usedMax": "Utilisé / Max", - "tokenUsage": "Utilisation des tokens", - "input": "Entrée", - "output": "Sortie", - "cacheRead": "Lecture cache", - "cacheWrite": "Écriture cache", - "total": "Total des tokens" - } - }, - "auxPanel": { - "tabs": { - "files": "Fichiers", - "changes": "Changements", - "commits": "Validations" - }, - "noFolderTitle": "Aucun dossier ouvert", - "noFolderHint": "Ouvrez un dossier pour voir son contenu ici" - }, - "windowControls": { - "minimizeWindow": "Minimiser la fenêtre", - "minimize": "Minimiser", - "maximizeWindow": "Maximiser la fenêtre", - "maximize": "Maximiser", - "restoreWindow": "Restaurer la fenêtre", - "restore": "Restaurer", - "closeWindow": "Fermer la fenêtre", - "close": "Fermer" - }, - "tabs": { - "closeConversationTab": "Fermer l’onglet de conversation", - "close": "Fermer", - "closeOthers": "Fermer les autres", - "splitRight": "Diviser à droite", - "splitDown": "Diviser en bas", - "splitAndMoveRight": "Diviser et déplacer à droite", - "splitAndMoveDown": "Diviser et déplacer en bas", - "moveToOppositeGroup": "Déplacer vers le groupe opposé", - "moveToGroup": "Déplacer vers le groupe", - "groupLabel": "Groupe {index}", - "changeSplitterOrientation": "Changer l'orientation du séparateur", - "unsplit": "Annuler la division", - "unsplitAll": "Annuler toutes les divisions", - "closeAll": "Tout fermer", - "tileDisplay": "Affichage en mosaïque", - "untileDisplay": "Quitter la mosaïque" - }, - "fileWorkspace": { - "files": "Fichiers", - "closeFileTab": "Fermer l’onglet fichier", - "close": "Fermer", - "closeOthers": "Fermer les autres", - "closeAll": "Tout fermer", - "preview": "Aperçu", - "editSource": "Modifier la source", - "maximize": "Agrandir", - "restore": "Restaurer", - "emptyDirectory": "Dossier vide" - }, - "terminal": { - "rename": "Renommer", - "close": "Fermer", - "closeOthers": "Fermer les autres", - "closeAll": "Tout fermer", - "hideTerminal": "Masquer le terminal ({shortcut})", - "openFolderFirst": "Ouvrez d'abord un dossier" - }, - "workspaceDialog": { - "title": "Ouvrir un dossier", - "manageTitle": "Dossiers liés", - "addTargetsTitle": "Ajouter des dossiers à lier", - "pickRootDescription": "Choisissez le dossier principal de cet espace de travail.", - "linksDescription": "Liez d'autres dossiers en sous-répertoires pour que les agents travaillent sur tous depuis un seul espace de travail.", - "addTargetsDescription": "Sélectionnez un ou plusieurs dossiers. Chacun devient un sous-répertoire de l'espace de travail.", - "useSystemPicker": "Sélecteur système", - "next": "Suivant", - "back": "Retour", - "done": "Terminé", - "change": "Modifier", - "addFolders": "Ajouter des dossiers", - "addSelected": "Ajouter", - "addSelectedCount": "Ajouter {count}", - "createCount": "Lier {count} dossier(s)", - "discardPending": "Abandonner", - "noLinks": "Aucun dossier lié pour l'instant.", - "gitExclude": "Garder les liens hors du statut git", - "rename": "Renommer", - "unlink": "Supprimer le lien", - "repair": "Recréer le lien", - "saveName": "Enregistrer", - "cancelRename": "Annuler", - "removePending": "Retirer", - "willAppearAs": "Apparaît sous le nom {name} dans l'espace de travail", - "renamedForDuplicate": "Renommé — {base} est déjà utilisé par un autre lien", - "renamedForExistingEntry": "Renommé — {base} existe déjà dans ce dossier", - "partiallyCreated": "Seuls {count} dossier(s) ont pu être liés", - "openFailed": "Impossible d'ouvrir le dossier", - "previewFailed": "Impossible de vérifier les dossiers sélectionnés", - "createFailed": "Impossible de lier les dossiers", - "renameFailed": "Impossible de renommer le lien", - "removeFailed": "Impossible de supprimer le lien", - "repairFailed": "Impossible de recréer le lien", - "status": { - "ok": "Lié", - "missing": "Le lien a disparu de ce dossier", - "conflicted": "Une autre entrée utilise désormais ce nom", - "broken": "Le dossier lié n'existe plus" - }, - "nameIssue": { - "empty": "Saisissez un nom", - "illegalChars": "Ne peut pas contenir / \\ : * ? \" < > |", - "tooLong": "Nom trop long", - "reserved": "Ce nom est réservé par Windows", - "duplicate": "Ce nom est déjà utilisé" - }, - "rejection": { - "not_found": "Dossier introuvable", - "not_a_directory": "Ce chemin n'est pas un dossier", - "same_as_root": "C'est le dossier de l'espace de travail lui-même", - "ancestor_of_root": "Ce dossier contient l'espace de travail", - "inside_root": "Déjà dans l'espace de travail", - "already_linked": "Déjà lié", - "name_unavailable": "Plus aucun nom disponible pour ce dossier", - "alreadyLinkedAs": "Déjà lié sous le nom {name}" - } - }, - "folderNameDropdown": { - "fallbackFolderName": "Dossier", - "openFolder": "Ouvrir le dossier", - "cloneRepository": "Cloner le dépôt", - "projectBoot": "Lanceur de projet", - "opened": "Ouvert", - "recentOpen": "Ouvert récemment" - }, - "fileWorkspacePanel": { - "addSelectionToChat": "Ajouter la sélection au chat", - "addToChat": "Ajouter au chat", - "addSelectionToChatDone": "{label} ajouté à la conversation", - "addFileToChat": "Ajouter le fichier au chat", - "toggleWordWrap": "Basculer le retour à la ligne", - "addFileToChatDone": "{label} ajouté à la conversation", - "viewDiff": "Voir le Diff", - "openFile": "Ouvrir le fichier", - "fileCount": "{count, plural, one {# fichier} other {# fichiers}}", - "openFileOrDiff": "Ouvrez un fichier ou un diff depuis le panneau de droite", - "disk": "Disque", - "head": "HEAD", - "unsaved": "Non enregistré", - "workingTree": "Arbre de travail", - "loading": "Chargement...", - "compareWithBranch": "{path} · comparer avec {branch}", - "hunkCount": "{count, plural, one {# bloc} other {# blocs}}", - "prev": "Précédent", - "next": "Suivant", - "jumpToLine": "Aller à la ligne {line}", - "noParsedDiffSections": "Aucune section de diff analysée", - "loadingEditor": "Chargement de l’éditeur...", - "imageZoomIn": "Agrandir", - "imageZoomOut": "Réduire", - "imageZoomReset": "Réinitialiser le zoom", - "htmlPreviewTitle": "Aperçu HTML", - "htmlPreviewTrust": "Activer les scripts", - "htmlPreviewTrustHint": "Exécuter les scripts de ce fichier et autoriser l'accès réseau. À activer uniquement pour les fichiers de confiance.", - "officePreviewTitle": "Aperçu du document Office", - "officeFullRender": "Rendu complet", - "officeFullRenderHint": "Affiche les animations Morph, la 3D et les formules (exécute les scripts de la diapositive)", - "officeNotInstalled": "OfficeCLI n'est pas installé", - "officeNotInstalledHint": "Installe OfficeCLI dans Paramètres → Outils Office pour prévisualiser les fichiers Word, Excel et PowerPoint.", - "officeOpenSettings": "Ouvrir les paramètres", - "officeWatchFailed": "Impossible de démarrer l'aperçu en direct", - "officeWatchRetry": "Réessayer", - "officeServerInstallHint": "OfficeCLI doit être installé sur l'hôte du serveur. Exécutez cette commande là-bas, puis réessayez :", - "officeRemoteDesktopUnsupported": "L'aperçu en direct n'est pas disponible dans une fenêtre de bureau à distance. Ouvrez cet espace de travail dans l'interface web du serveur pour prévisualiser les fichiers Office." - }, - "branchDropdown": { - "toasts": { - "commitCodeCompleted": "Commit de code terminé", - "pushCodeCompleted": "Push de code terminé", - "committedFiles": "{count, plural, one {# fichier commit} other {# fichiers commit}}", - "taskCompleted": "{label} terminé", - "taskFailed": "{label} échoué", - "mergeNoNewCommits": "{branchName} n’a pas de nouveaux commits", - "mergedCommits": "{count, plural, one {# commit fusionné} other {# commits fusionnés}}", - "allFilesUpToDate": "Tous les fichiers sont à jour", - "updatedFiles": "{count, plural, one {# fichier mis à jour} other {# fichiers mis à jour}}", - "openCommitWindowFailed": "Impossible d’ouvrir la fenêtre de commit", - "openPushWindowFailed": "Impossible d’ouvrir la fenêtre de push", - "upstreamSet": "La branche upstream a été définie", - "upstreamSetAndPushed": "Branche upstream définie et {count, plural, one {# commit} other {# commits}} poussé(s)", - "noCommitsToPush": "Aucun commit à pousser", - "pushedCommits": "{count, plural, one {# commit poussé} other {# commits poussés}}", - "switchedToFolder": "Basculé vers {name}", - "switchFailed": "Échec du changement de branche", - "openStashWindowFailed": "Échec de l'ouverture de la fenêtre de remisage" - }, - "tasks": { - "newBranch": "Créer la branche {name}", - "newWorktree": "Créer le worktree {name}", - "checkoutTo": "Basculer vers {branchName}", - "mergeBranch": "Fusionner {branchName}", - "rebaseTo": "Rebase vers {branchName}", - "deleteRemoteBranch": "Supprimer la branche distante {branchName}", - "initGitRepo": "Initialiser le dépôt Git", - "pullCode": "Pull du code", - "fetchInfo": "Récupérer les infos", - "pushCode": "Push du code", - "stashChanges": "Stash des changements", - "stashPop": "Appliquer le stash", - "deleteBranch": "Supprimer la branche {branchName}", - "removeWorktree": "Supprimer le worktree de {branchName}", - "removeWorktreeAndBranch": "Supprimer le worktree et la branche {branchName}", - "updateBranch": "Mettre à jour la branche {branchName}" - }, - "confirm": { - "mergeTitle": "Fusionner la branche", - "rebaseTitle": "Rebase de la branche", - "mergeDescription": "Fusionner {branchName} dans la branche actuelle {currentBranch} ?", - "rebaseDescription": "Rebaser la branche actuelle {currentBranch} sur {branchName} ?", - "deleteRemoteTitle": "Supprimer la branche distante", - "deleteRemoteDescription": "Supprimer la branche distante {branchName} ? Cette action la supprimera du dépôt distant et ne pourra pas être annulée.", - "deleteTitle": "Supprimer la branche", - "deleteDescription": "Supprimer la branche {branchName} ? Cette action est irréversible.", - "forceDeleteTitle": "Forcer la suppression de la branche", - "forceDeleteDescription": "La branche {branchName} n'est pas entièrement fusionnée. Êtes-vous sûr de vouloir la supprimer de force ? Cette action est irréversible.", - "deleteWorktreeTitle": "Supprimer le worktree", - "deleteWorktreeDescription": "Supprimer le répertoire du worktree où {branchName} est extraite ? La branche et ses commits sont conservés.", - "forceDeleteWorktreeTitle": "Forcer la suppression du worktree", - "forceDeleteWorktreeDescription": "Le worktree de {branchName} contient des fichiers non validés ou non suivis. Le supprimer quand même ? Ces modifications seront irrécupérables.", - "deleteWorktreeAndBranchTitle": "Supprimer le worktree et la branche", - "deleteWorktreeAndBranchDescription": "Supprimer le worktree de {branchName}, la branche elle-même et son dossier d'espace de travail ? Ses sessions sont déplacées vers le dossier du dépôt. Cette action est irréversible.", - "forceDeleteWorktreeAndBranchTitle": "Forcer la suppression du worktree et de la branche", - "forceDeleteWorktreeAndBranchDescription": "Le worktree de {branchName} contient des fichiers non validés, ou la branche n'est pas entièrement fusionnée. Tout supprimer quand même ? Cette action est irréversible." - }, - "current": "Actuelle", - "switchToBranch": "Basculer vers cette branche", - "mergeBranchIntoCurrent": "Fusionner {branchName} dans {currentBranch}", - "rebaseCurrentToBranch": "Rebaser {currentBranch} sur {branchName}", - "noBranch": "Aucune branche", - "detachedHead": "HEAD détaché sur {sha}", - "initGitRepo": "Initialiser le dépôt Git", - "pullCode": "Pull du code", - "fetchRemoteBranches": "Récupérer les branches distantes", - "openCommitWindow": "Commit du code...", - "pushCode": "Pousser...", - "pushBranch": "Pousser", - "newBranch": "Nouvelle branche...", - "newWorktree": "Nouveau worktree...", - "stashChanges": "Remiser les changements...", - "stashPop": "Appliquer le stash...", - "manageRemotes": "Gérer les dépôts distants...", - "localBranches": "Branches locales ({count, plural, one {#} other {#}})", - "noLocalBranches": "Aucune branche locale", - "remoteBranches": "Branches distantes ({count, plural, one {#} other {#}})", - "noRemoteBranches": "Aucune branche distante", - "dialogs": { - "newBranchTitle": "Nouvelle branche", - "newBranchDescription": "Créer une nouvelle branche depuis la branche actuelle {branch}", - "branchNamePlaceholder": "Nom de la branche", - "newWorktreeTitle": "Nouveau worktree", - "newWorktreeDescription": "Créer un nouveau worktree depuis la branche actuelle {branch}", - "branchNameLabel": "Nom de la branche", - "worktreePathLabel": "Chemin du worktree", - "worktreePathPlaceholder": "Chemin du worktree", - "manageRemotesTitle": "Gérer les dépôts distants", - "manageRemotesEmpty": "Aucun dépôt distant configuré", - "remoteNamePlaceholder": "Nom du dépôt distant", - "remoteUrlPlaceholder": "URL du dépôt distant", - "addRemote": "Ajouter", - "savingRemotes": "Enregistrement..." - }, - "conflict": { - "title": "Conflits de fusion", - "description": "Les fichiers suivants ont des conflits qui doivent être résolus :", - "abort": "Abandonner la fusion", - "openMergeTool": "Ouvrir l'outil de fusion", - "completeMerge": "Terminer la fusion", - "abortSuccess": "Fusion abandonnée avec succès", - "completeSuccess": "Fusion terminée avec succès" - }, - "stashDialog": { - "title": "Remiser les changements", - "description": "Sauvegarder les changements actuels dans la remise", - "messageLabel": "Message", - "messagePlaceholder": "Message de remise (optionnel)", - "keepIndex": "Conserver l'index (les changements indexés restent indexés)", - "cancel": "Annuler", - "stash": "Remiser", - "success": "Changements remisés", - "error": "Échec de la remise" - }, - "unstashDialog": { - "title": "Appliquer la remise", - "noStashes": "Aucune remise trouvée", - "selectFile": "Sélectionner un fichier pour voir le diff", - "viewDiff": "Voir le diff", - "original": "Original", - "modified": "Modifié", - "apply": "Appliquer", - "drop": "Supprimer", - "applySuccess": "Remise appliquée", - "dropSuccess": "Remise supprimée", - "confirmApply": "Appliquer la remise {ref} au répertoire de travail ?", - "cancel": "Annuler" - }, - "deleteBranch": "Supprimer la branche", - "deleteWorktree": "Supprimer le worktree", - "deleteWorktreeAndBranch": "Supprimer le worktree et la branche", - "searchPlaceholder": "Rechercher des branches et actions", - "searchAriaLabel": "Rechercher des branches et actions", - "branchListLabel": "Branches et actions", - "noMatches": "Aucune correspondance" - }, - "commitDialog": { - "toasts": { - "commitCompleted": "Commit de code terminé", - "pushFailed": "Échec du push", - "committedFiles": "{count, plural, one {# fichier commit} other {# fichiers commit}}", - "addedToVcs": "Ajouté à VCS", - "addToVcsFailed": "Échec de l’ajout à VCS", - "fileDeleted": "Fichier supprimé", - "deleteFailed": "Échec de la suppression", - "fileRolledBack": "Fichier restauré", - "rollbackFailed": "Échec du rollback", - "dirRolledBack": "Répertoire restauré", - "dirDeleted": "Répertoire supprimé" - }, - "confirm": { - "deleteTitle": "Confirmer la suppression", - "deleteDescription": "Supprimer le fichier \"{file}\" ? Cette action est irréversible.", - "rollbackTitle": "Confirmer le rollback", - "rollbackDescription": "Restaurer le fichier \"{file}\" vers HEAD ? Les modifications non enregistrées seront perdues.", - "rollbackDirDescription": "Restaurer le répertoire \"{dir}\" vers HEAD ? Les modifications non enregistrées seront perdues.", - "deleteDirDescription": "Supprimer le répertoire \"{dir}\" ? Cette action est irréversible." - }, - "actions": { - "select": "Sélectionner", - "unselect": "Désélectionner", - "rollback": "Annuler", - "addToVcs": "Ajouter à VCS" - }, - "aria": { - "selectFile": "{action} : {path}", - "unselectAllFiles": "Désélectionner tous les fichiers", - "selectAllFiles": "Sélectionner tous les fichiers", - "unselectTracked": "Désélectionner les changements suivis", - "selectTracked": "Sélectionner les changements suivis", - "unselectUntracked": "Désélectionner les fichiers non suivis", - "selectUntracked": "Sélectionner les fichiers non suivis" - }, - "loading": "Chargement...", - "selectionCount": "{selected} / {total} fichiers", - "emptyFiles": "Aucun fichier modifié", - "trackedChanges": "Changements suivis ({count})", - "untrackedFiles": "Fichiers non suivis ({count})", - "commitMessage": "Message de commit", - "commitMessagePlaceholder": "Saisissez le message de commit...", - "commitButton": "Valider ({count})", - "commitAndPushButton": "Valider et pousser ({count})", - "head": "HEAD", - "workingTree": "Arbre de travail", - "clickFileToDiff": "Cliquez sur un nom de fichier pour voir le diff", - "loadingDiff": "Chargement du diff..." - }, - "pushWindow": { - "title": "Pousser le code", - "noUnpushedCommits": "Aucun commit non poussé", - "noRemoteConfigured": "Aucun dépôt distant Git configuré\nAjoutez-en un dans « Gérer les dépôts distants »", - "newBranchNoPushedCommits": "Nouvelle branche — pousser pour créer la branche de suivi distante", - "unpushed": "Non poussé", - "selectFileToViewDiff": "Sélectionnez un fichier pour voir les différences", - "before": "Avant", - "after": "Après", - "push": "Pousser", - "toasts": { - "pushSuccess": "Push réussi", - "pushFailed": "Échec du push", - "upstreamSet": "La branche distante a été configurée", - "upstreamSetAndPushed": "Branche distante configurée et {count} commits poussés", - "noCommitsToPush": "Aucun commit à pousser", - "pushedCommits": "{count} commits poussés" - } - }, - "gitLogTab": { - "filesTitle": "Fichiers", - "expandAllFiles": "Développer tous les fichiers", - "collapseAllFiles": "Réduire tous les fichiers", - "workspace": "espace de travail", - "retry": "Réessayer", - "noCommitsFound": "Aucun commit trouvé", - "notAGitRepoTitle": "Pas un dépôt Git", - "notAGitRepoHint": "Initialisez Git depuis le menu des branches ci-dessus, ou ouvrez un dépôt existant.", - "hash": "Empreinte", - "copyHash": "Copier le hash", - "copyMessage": "Copier le message", - "showMore": "Afficher plus", - "showLess": "Afficher moins", - "author": "Auteur", - "noFileChangeDetails": "Aucun détail de changement de fichier disponible.", - "loadingFiles": "Chargement des fichiers...", - "branchesTitle": "Branches Git", - "loadingBranches": "Chargement des branches...", - "noContainingBranches": "Aucune branche contenant ce commit.", - "newBranch": "Nouvelle branche...", - "resetToHere": "Réinitialiser ici", - "resetDisabledReasonNotCurrentBranchView": "Disponible uniquement en affichant la branche actuelle", - "copyFullCommitHashAria": "Copier le hash complet du commit {hash}", - "pushStatus": { - "pushed": "Poussé vers le remote", - "notPushed": "Non poussé vers le remote", - "unknown": "Statut de push inconnu (aucun upstream configuré)" - }, - "time": { - "monthsAgo": "{count, plural, one {il y a # mois} other {il y a # mois}}", - "daysAgo": "{count, plural, one {il y a # jour} other {il y a # jours}}", - "hoursAgo": "{count, plural, one {il y a # heure} other {il y a # heures}}", - "minsAgo": "{count, plural, one {il y a # min} other {il y a # mins}}", - "justNow": "à l’instant" - }, - "toasts": { - "createdAndSwitchedNewBranch": "Nouvelle branche créée et activée", - "newBranchFromCommit": "{name} (depuis {shortHash})", - "createBranchFailed": "Échec de la création de la branche", - "openPushWindowFailed": "Échec de l'ouverture de la fenêtre de push", - "resetSuccess": "Réinitialisation réussie", - "resetSuccessDescription": "{branch} a été réinitialisée sur {shortHash} avec {mode}", - "resetFailed": "Échec de la réinitialisation" - }, - "authorFilter": { - "label": "Auteur", - "searchPlaceholder": "Rechercher un auteur", - "noAuthors": "Aucun auteur trouvé", - "you": "vous", - "filterByAuthorAria": "Filtrer les commits par auteur", - "filterByQuery": "Filtrer par « {query} »", - "clearAuthorFilterAria": "Effacer le filtre par auteur", - "recent": "Récents", - "matchingAuthors": "Auteurs correspondants", - "removeFromRecent": "Retirer {name} des récents" - }, - "branchSelector": { - "label": "Branche", - "head": "HEAD", - "headHint": "Suit la branche actuelle", - "headHintWithBranch": "Suit la branche actuelle ({branch})", - "searchBranch": "Rechercher une branche...", - "noBranches": "Aucune branche", - "selectBranchPlaceholder": "Sélectionner une branche...", - "localBranches": "Branches locales", - "current": "Actuelle", - "remoteBranches": "Branches distantes", - "refreshCommitHistory": "Actualiser l’historique des commits", - "clearBranchFilterAria": "Effacer le filtre par branche" - }, - "dialogs": { - "newBranchTitle": "Nouvelle branche", - "newBranchDescription": "Créer une nouvelle branche avec le commit {shortHash} comme dernier commit.", - "branchNamePlaceholder": "Nom de la branche", - "reset": { - "title": "Réinitialiser la branche actuelle jusqu’ici", - "branchLabel": "Branche", - "targetLabel": "Commit cible", - "messageLabel": "Message", - "modeLabel": "Mode de réinitialisation", - "confirmButton": "Réinitialiser", - "modes": { - "soft": { - "label": "--soft", - "description": "Déplace HEAD et le pointeur de la branche actuelle vers le commit cible.\nConserve Index et Working Tree inchangés.\nLes changements des commits retirés restent staged." - }, - "mixed": { - "label": "--mixed (par défaut)", - "description": "Déplace HEAD vers le commit cible.\nRéinitialise Index au commit cible tout en conservant les changements du Working Tree.\nLes changements passent de staged à unstaged." - }, - "hard": { - "label": "--hard", - "description": "Déplace HEAD et réinitialise à la fois Index et Working Tree au commit cible.\nLes changements locaux suivis après le commit cible sont supprimés.\nC’est une opération destructive." - }, - "keep": { - "label": "--keep", - "description": "Déplace HEAD vers le commit cible en conservant les changements locaux quand c’est possible.\nSeuls les changements sans conflit sont conservés.\nEn cas de conflit, la réinitialisation est annulée pour protéger votre travail." - } - } - } - }, - "moreActions": "Autres actions Git" - }, - "gitChangesTab": { - "workspace": "espace de travail", - "noChanges": "Aucun changement local", - "notAGitRepoTitle": "Pas un dépôt Git", - "notAGitRepoHint": "Initialisez Git depuis le menu des branches ci-dessus, ou ouvrez un dépôt existant.", - "trackedChanges": "Changements suivis ({count})", - "untrackedFiles": "Fichiers non suivis ({count})", - "expandTracked": "Développer les changements suivis", - "collapseTracked": "Réduire les changements suivis", - "expandUntracked": "Développer les fichiers non suivis", - "collapseUntracked": "Réduire les fichiers non suivis", - "showRemainingItems": "Afficher {count} éléments de plus", - "actions": { - "commitCode": "Commit du code", - "rollback": "Annuler", - "addToVcs": "Ajouter à VCS", - "delete": "Supprimer", - "moreActions": "Autres actions Git", - "addAllToVcs": "Tout ajouter au VCS", - "rollbackAll": "Tout annuler", - "refresh": "Actualiser" - }, - "toasts": { - "noAddableFilesInDir": "Aucun fichier modifié de ce répertoire ne peut être ajouté à VCS", - "noRollbackFilesInDir": "Aucun fichier modifié de ce répertoire ne peut être rollback", - "addedToVcs": "{name} ajouté à VCS", - "addToVcsFailed": "Échec de l’ajout à VCS", - "openCommitWindowFailed": "Impossible d’ouvrir la fenêtre de commit", - "rolledBack": "{name} restauré", - "rollbackFailed": "Échec du rollback", - "addedFilesToVcs": "{count, plural, one {# fichier} other {# fichiers}} ajouté(s) à VCS", - "rolledBackFiles": "{count, plural, one {# fichier restauré} other {# fichiers restaurés}}", - "deleted": "{name} supprimé", - "deleteFailed": "Échec de la suppression", - "deletedFiles": "{count} fichiers supprimés", - "noDeletableFilesInDir": "Aucun fichier modifié dans ce répertoire ne peut être supprimé", - "commitFailed": "Échec du commit" - }, - "directoryDialog": { - "descriptionAdd": "Sélectionnez les fichiers du répertoire {path} à ajouter à VCS.", - "descriptionRollback": "Sélectionnez les fichiers du répertoire {path} à rollback.", - "descriptionDelete": "Sélectionnez les fichiers du répertoire {path} à supprimer. Cette action est irréversible.", - "descriptionFallback": "Sélectionnez les fichiers pour continuer.", - "selectionCount": "{selected} / {total} fichiers sélectionnés", - "selectAll": "Tout sélectionner", - "unselectAll": "Tout désélectionner", - "loadingCandidates": "Chargement des changements du répertoire...", - "noOperableFiles": "Aucun fichier opérable" - }, - "rollbackConfirm": { - "title": "Confirmer le rollback", - "descriptionWithTarget": "Rollback des changements locaux pour {kind} \"{name}\" ?", - "descriptionFallback": "Rollback des changements locaux ?", - "kindDirectory": "répertoire", - "kindFile": "fichier" - }, - "deleteConfirm": { - "title": "Confirmer la suppression", - "descriptionWithTarget": "Supprimer {kind} \"{name}\" ? Cette action est irréversible.", - "descriptionFallback": "Cette action est irréversible.", - "kindDirectory": "répertoire", - "kindFile": "fichier" - }, - "quickCommit": { - "placeholder": "Message du commit (Entrée pour valider)" - } - }, - "tabContext": { - "loadingConversation": "Chargement...", - "untitledConversation": "Conversation sans titre", - "newConversation": "Nouvelle conversation" - }, - "fileTreeTab": { - "workspace": "Espace de travail", - "retry": "Réessayer", - "git": "Git", - "openInFileManager": "Ouvrir dans le gestionnaire de fichiers", - "openInFinder": "Ouvrir dans Finder", - "openInExplorer": "Ouvrir dans Explorer", - "attachToCurrentSession": "Ajouter à la session", - "compareWithBranch": "Comparer avec la branche...", - "reloadFromDisk": "Recharger depuis le disque", - "new": "Nouveau", - "newFile": "Fichier", - "newDirectory": "Répertoire", - "openIn": "Ouvrir dans", - "openInTerminal": "Ouvrir dans le terminal", - "linkedFolder": "Dossier lié", - "copyPath": "Copier le chemin", - "upload": "Téléverser fichiers/dossier", - "download": "Télécharger le fichier", - "downloadAsZip": "Télécharger en ZIP", - "actions": { - "select": "Sélectionner", - "unselect": "Désélectionner", - "commitCode": "Committer le code", - "rollback": "Annuler", - "addToVcs": "Ajouter au VCS" - }, - "aria": { - "selectPath": "{action} : {path}" - }, - "toasts": { - "openDirectoryFailed": "Échec de l'ouverture du dossier", - "openBuiltinTerminalFailed": "Impossible d'ouvrir le terminal intégré", - "openCommitWindowFailed": "Échec de l'ouverture de la fenêtre de commit", - "noAddableFilesInDir": "Aucun fichier modifié de ce dossier ne peut être ajouté au VCS", - "noRollbackFilesInDir": "Aucun fichier modifié de ce dossier ne peut être annulé", - "addedToVcs": "{name} ajouté au VCS", - "addToVcsFailed": "Échec de l'ajout au VCS", - "loadBranchesFailed": "Échec du chargement des branches", - "renameFailed": "Échec du renommage", - "moveFailed": "Échec du déplacement", - "deleteFailed": "Échec de la suppression", - "rolledBack": "{name} annulé", - "rollbackFailed": "Échec de l'annulation", - "addedFilesToVcs": "{count, plural, one {# fichier ajouté au VCS} other {# fichiers ajoutés au VCS}}", - "rolledBackFiles": "{count, plural, one {# fichier annulé} other {# fichiers annulés}}", - "savedAsCopy": "Enregistré en copie", - "saveCopyFailed": "Échec de l'enregistrement en copie", - "watchStartFailed": "Échec du démarrage de la surveillance de fichiers", - "createFailed": "Échec de la création", - "downloadFailed": "Échec du téléchargement de {name}", - "downloadSaved": "{name} téléchargé", - "pathCopied": "Chemin copié", - "copyPathFailed": "Échec de la copie du chemin" - }, - "createDialog": { - "newFile": "Nouveau fichier", - "newDirectory": "Nouveau répertoire", - "description": "Entrez un nom pour le nouveau {kind}.", - "placeholderFile": "nom-du-fichier.ext", - "placeholderDirectory": "nom-du-dossier" - }, - "renameDialog": { - "renameDirectory": "Renommer le dossier", - "renameFile": "Renommer le fichier", - "description": "Saisissez un nouveau nom (nom uniquement, sans chemin).", - "placeholderDirectory": "nouveau-nom-dossier", - "placeholderFile": "nouveau-nom-fichier.ext" - }, - "uploadDialog": { - "title": "Téléverser vers l'espace de travail", - "description": "Ajustez la destination si besoin, puis ajoutez des fichiers ou dossiers.", - "workspaceRoot": "racine de l'espace de travail", - "targetPathLabel": "Téléverser vers", - "targetPathHint": "Chemin résolu : {path}", - "dropHint": "Déposez des fichiers ou dossiers ici, ou utilisez les boutons ci-dessous", - "dropHintActive": "Relâchez pour ajouter à la file d'attente", - "selectFiles": "Sélectionner des fichiers", - "selectFolder": "Sélectionner un dossier", - "startUpload": "Lancer le téléversement", - "clearQueue": "Effacer terminés", - "removeItem": "Retirer de la file", - "retry": "Réessayer", - "dropZoneAria": "Déposez ici ou activez pour parcourir", - "folderEmpty": "Aucun fichier trouvé dans le dossier déposé", - "summary": "Total : {total} · Réussis : {succeeded} · Échoués : {failed}", - "status": { - "pending": "En attente", - "uploading": "Téléversement", - "success": "Terminé", - "error": "Échec", - "cancelled": "Annulé" - } - }, - "directoryDialog": { - "descriptionAdd": "Sélectionnez des fichiers sous le dossier {path} à ajouter au VCS.", - "descriptionRollback": "Sélectionnez des fichiers sous le dossier {path} à annuler.", - "descriptionFallback": "Sélectionnez des fichiers pour continuer.", - "selectionCount": "{selected} / {total} fichiers sélectionnés", - "selectAll": "Tout sélectionner", - "unselectAll": "Tout désélectionner", - "loadingCandidates": "Chargement des changements du dossier...", - "noOperableFiles": "Aucun fichier exploitable" - }, - "compareDialog": { - "title": "Comparer avec la branche", - "descriptionWithTarget": "Sélectionnez une branche et comparez avec {kind} {path}", - "descriptionFallback": "Sélectionnez une branche à comparer.", - "kindDirectory": "dossier", - "kindFile": "fichier", - "filterPlaceholder": "Filtrer les branches, ex. main / origin/main", - "singleClickHint": "Cliquez sur une branche pour comparer directement", - "loadingBranches": "Chargement des branches...", - "recentBranches": "Branches récentes ({count})", - "noCurrentBranch": "Aucune branche courante", - "localBranches": "Branches locales ({count})", - "remoteBranches": "Branches distantes ({count})", - "noMatchingBranches": "Aucune branche correspondante" - }, - "externalConflictDialog": { - "title": "Modifications externes de fichiers détectées", - "descriptionWithPath": "Le fichier {path} a changé sur le disque et les modifications actuelles ne sont pas enregistrées.", - "descriptionFallback": "Le fichier actuel a changé sur le disque et les modifications actuelles ne sont pas enregistrées.", - "compare": "Comparer", - "savingCopy": "Enregistrement de la copie...", - "saveAsCopy": "Enregistrer en copie", - "reload": "Recharger" - }, - "deleteConfirm": { - "title": "Confirmer la suppression", - "descriptionWithTarget": "Supprimer {kind} \"{name}\" ? Cette action est irréversible.", - "descriptionFallback": "Cette action est irréversible.", - "kindDirectory": "dossier", - "kindFile": "fichier" - }, - "rollbackConfirm": { - "title": "Confirmer l'annulation", - "descriptionWithTarget": "Annuler les modifications locales du fichier \"{name}\" ?", - "descriptionFallback": "Annuler les modifications locales de ce fichier ?" - }, - "terminalTitle": "Console · {name}" - }, - "commandDropdown": { - "loading": "Chargement...", - "addCommand": "Ajouter une commande", - "manageCommands": "Gérer les commandes...", - "runCommandTitle": "Exécuter : {command}", - "stopCommandTitle": "Arrêter : {command}", - "manageDialog": { - "title": "Gérer les commandes", - "empty": "Aucune commande pour le moment", - "noResults": "Aucune commande correspondante", - "searchPlaceholder": "Rechercher des commandes", - "newCommand": "Nouvelle commande", - "nameLabel": "Nom", - "commandLabel": "Commande", - "dragSort": "Glisser pour trier", - "dragSortCommand": "Glisser pour trier {name}", - "orderFailed": "Échec de l'enregistrement de l'ordre des commandes", - "loadFailed": "Échec du chargement des commandes", - "saveFailed": "Échec de l'enregistrement de la commande", - "deleteFailed": "Échec de la suppression de la commande", - "confirmDelete": { - "title": "Supprimer la commande ?", - "message": "Cela supprimera \"{name}\". Cette action est irréversible." - } - } - }, - "workspaceContext": { - "confirmCloseDirtyTab": "Fermer « {title} » sans enregistrer ?", - "confirmCloseOtherDirtyTabs": "Fermer les autres onglets avec des modifications non enregistrées ?", - "confirmCloseAllDirtyTabs": "Fermer tous les onglets avec des modifications non enregistrées ?", - "unableLoadContent": "Impossible de charger le contenu.\n\n{message}", - "previewRequestTimedOut": "La requête de prévisualisation a expiré", - "diffRequestTimedOut": "La requête Diff a expiré", - "branchCompareRequestTimedOut": "La requête de comparaison de branches a expiré", - "commitDiffRequestTimedOut": "La requête de Diff de commit a expiré", - "saveRequestTimedOut": "La requête d’enregistrement a expiré", - "reloadRequestTimedOut": "La requête de rechargement a expiré", - "noChanges": "Aucun changement.", - "noDiffOutput": "Aucune sortie diff.", - "diffTitleWorkspace": "Diff · Espace de travail", - "diffDescriptionWorkingTree": "Arbre de travail (HEAD)", - "diffTitleFile": "Différence · {name}", - "compareTitleFile": "Comparer · {name}", - "compareTitleBranch": "Comparer · {branch}", - "compareDescriptionPath": "{path} · comparer avec {branch}", - "compareDescriptionBranch": "comparer avec {branch}", - "diffTitleCommitFile": "Différence · {name} @ {hash}", - "diffTitleCommit": "Différence · {hash}", - "diffDescriptionCommitPath": "{path} · validation {commit}", - "diffDescriptionCommit": "validation {commit}", - "diffTitleConflictFile": "Conflit · {name}", - "diffDescriptionConflict": "{path} · disque vs non enregistré" - }, - "chat": { - "acpConnections": { - "actions": { - "openAgentsSettings": "Ouvrir les paramètres des agents", - "retry": "Réessayer" - }, - "agentsSetupHint": "Ouvrez Paramètres > Agents pour gérer l'installation.", - "withSetupHint": "{message}\n{hint}", - "blocked": { - "missingConfig": "Impossible de lire la configuration actuelle de l'agent.", - "disabled": "{agent} est désactivé dans les paramètres des agents. Activez-le avant de vous connecter.", - "unavailable": "{agent} n'est pas disponible sur la plateforme actuelle.", - "sdkMissing": "Le SDK de {agent} n'est pas installé", - "adapterMissing": "L'adaptateur ACP de {agent} n'est pas installé" - }, - "backendErrors": { - "initializeTimeout": "Le handshake de connexion de {agent} a expiré (aucune réponse après 60 secondes). Ouvrez Paramètres pour vérifier la configuration de l'agent et du réseau.", - "mcpRejectedByAgent": "{agent} a refusé la session alors que le compagnon MCP de codeg était joint : {message} Si cet agent ne prend pas en charge MCP, désactivez « Prise en charge de MCP » dans les Paramètres puis reconnectez-vous.", - "processExited": "Le processus {agent} s'est arrêté de manière inattendue.", - "spawnFailed": "Impossible de démarrer {agent} : {message}", - "downloadFailed": "Échec du téléchargement de {agent} : {message}", - "sessionLoadResourceNotFound": "Échec du chargement de la session de {agent}. Rechargez pour réessayer ou démarrez une nouvelle conversation.", - "sessionLoadUnavailable": "{agent} n'a pas pu restaurer cette session ; elle a peut-être pris fin ou l'agent s'est arrêté. Rechargez pour réessayer ou démarrez une nouvelle conversation.", - "turnFailedRefusal": "{agent} a refusé de poursuivre ce tour. Cela indique souvent une erreur de backend ou de passerelle. Vérifiez les journaux de l'agent.", - "turnFailedMaxTokens": "{agent} a atteint la limite maximale de jetons pour ce tour.", - "turnFailedMaxTurnRequests": "{agent} a atteint le nombre maximal de requêtes autorisées pour ce tour.", - "turnFailedUnknown": "{agent} a terminé le tour avec une raison d'arrêt inconnue.", - "grokModelSwitchIncompatibleAgent": "{agent} ne peut pas basculer vers ce modèle dans une conversation existante. Démarrez une nouvelle session pour l'utiliser.", - "turnFailedEmpty": "{agent} a terminé le tour sans produire de réponse.", - "turnFailedEmptyProtocol": "{agent} a produit une sortie que codeg n'a pas pu analyser — la version de l'agent ne correspond peut-être pas au protocole.", - "turnFailedEmptyMetadata": "{agent} n'a envoyé que des mises à jour d'état ce tour-ci (plan / mode / utilisation) et aucune réponse.", - "detailsInAlerts": "Ouvrez les alertes de la barre d'état et développez les détails pour voir la sortie de l'agent." - }, - "unableReadAgentConfig": "Impossible de lire la configuration de l'agent : {message}", - "connectFailedTitle": "Échec de la connexion de {agent}", - "toolFallbackTitle": "Outil", - "eventErrorTitle": "Erreur de l'agent", - "notificationTurnComplete": "{agent} a terminé de répondre", - "notificationError": "{agent} erreur : {message}", - "claudeApiRetry": { - "fallbackError": "authentication_failed", - "retryingWithMax": "nouvelle tentative {attempt}/{max}", - "retryingAttempt": "nouvelle tentative {attempt}", - "retrying": "nouvelle tentative", - "nextRetryIn": "prochaine dans {seconds}s", - "line": "{error}{status} · {retry}", - "lineWithDelay": "{error}{status} · {retry}, {delay}", - "httpStatus": " (HTTP {status})" - }, - "configOptionAdjusted": "{agent} a réglé {option} sur {actual} au lieu de {requested}" - }, - "connectionLifecycle": { - "tasks": { - "connectingTitle": "Connexion à {agent}", - "connectingDescription": "Établissement de la connexion", - "loadingSelectorsTitle": "Chargement des sélecteurs de {agent}", - "loadingSelectorsDescription": "Récupération des options de mode et de configuration de session", - "initSessionTitle": "Initialisation de la session {agent}", - "initSessionDescription": "Création de la session et chargement de la configuration" - }, - "errors": { - "connectionFailed": "Échec de la connexion", - "sendPromptFailed": "Échec de l'envoi du message : {error}" - } - }, - "shared": { - "attachedResources": "Ressources jointes", - "toolCallFailed": "Échec de l'appel d'outil" - }, - "messageThread": { - "emptyTitle": "Aucun message pour le moment", - "emptyDescription": "Commencez une conversation pour voir les messages ici" - }, - "chatInput": { - "connecting": "Connexion...", - "agentResponding": "{agent} répond...", - "sendMessage": "Envoyer un message..." - }, - "messageInput": { - "askAnything": "Posez n'importe quelle question...", - "removeAttachmentAria": "Retirer {name}", - "attachFiles": "Joindre des fichiers", - "addActions": "Ajouter", - "quickMessages": "Messages rapides", - "quickMessagesEmpty": "Aucun message rapide pour l'instant", - "quickMessagesLoading": "Chargement...", - "pasteAsPlainText": "Coller en texte brut", - "cut": "Couper", - "copy": "Copier", - "selectAll": "Tout sélectionner", - "pasteUnavailable": "Impossible de lire le presse-papiers. Utilisez Ctrl/⌘V pour coller.", - "clipboardWriteFailed": "Impossible d'écrire dans le presse-papiers. Utilisez le raccourci clavier.", - "quickMessageUntitled": "Sans titre", - "liveFeedback": "Retour en direct", - "liveFeedbackDisabledHint": "Disponible pendant que l'agent travaille", - "dropFilesToAttach": "Déposez des fichiers à joindre", - "loadingSettings": "Chargement des paramètres...", - "loadingMode": "Chargement du mode...", - "modeLabel": "Mode", - "toggleOn": "Activé", - "toggleOff": "Désactivé", - "agentSettings": "Paramètres de l'agent", - "searchModel": "Rechercher des modèles...", - "searchModelAria": "Rechercher des modèles", - "modelListLabel": "Modèles", - "noModels": "Aucun modèle trouvé", - "cancel": "Annuler", - "send": "Envoyer", - "forkAndSend": "Fork & Envoyer", - "queueMessage": "Mettre en file d'attente", - "steerIntoTurn": "Insérer dans le tour en cours", - "steerQueuedInstead": "Mis en file d'attente — il sera envoyé au tour suivant.", - "steerFailed": "Impossible d'insérer dans le tour en cours", - "steerAttachmentsUnsupported": "Texte uniquement — les brouillons avec pièces jointes passent par la file d'attente.", - "slashCommands": "Commandes slash", - "slashSearchPlaceholder": "Rechercher des commandes...", - "slashSearchEmpty": "Aucune commande correspondante", - "experts": "Experts", - "office": "Bureautique", - "research": "Recherche", - "attachLocalUpload": "Téléverser un fichier local", - "attachServerFile": "Sélectionner un fichier serveur", - "attachUploadTooLarge": "{names} dépasse la limite de téléversement de {limit} Mo et a été ignoré.", - "attachUploadFailed": "Échec du téléversement de {names}.", - "attachUploadNotAFile": "{names} n'est pas un fichier régulier (répertoire ou fichier spécial) et a été ignoré.", - "attachUploadQuotaExceeded": "Le serveur n'a plus d'espace pour les téléversements ; {names} n'a pas pu être envoyé.", - "attachUploadInProgress": "Les images sont encore en cours d'envoi — réessayez dans un instant.", - "mentionEmpty": "Aucune correspondance", - "mentionLoading": "Recherche…", - "mentionListLabel": "Mentions", - "mentionMore": "Plus de résultats — continuez à taper pour filtrer", - "mentionCount": "{count, plural, one {# résultat} other {# résultats}}", - "mentionGroupFile": "Fichiers", - "mentionGroupAgent": "Agents", - "mentionGroupSession": "Sessions", - "mentionGroupCommit": "Commits", - "mentionGroupSkill": "Compétences" - }, - "messageQueue": { - "addToQueue": "Mettre en file", - "saveEdit": "Enregistrer", - "cancelEdit": "Annuler la modification", - "editItem": "Modifier", - "deleteItem": "Supprimer" - }, - "welcomeInputPanel": { - "agentsSettingsPath": "Paramètres > Agents", - "autoConnectFallback": "Cliquez pour ouvrir {path} et gérer l'installation.", - "autoConnectAppend": "{message}. Cliquez pour ouvrir {path} et gérer l'installation.", - "enableAgentFirstPlaceholder": "Activez au moins un agent avant de démarrer une session...", - "prepareSessionFailed": "Impossible de préparer la session de chat. Veuillez réessayer.", - "createConversationFailed": "Impossible de créer la conversation. Veuillez réessayer.", - "askAnythingPlaceholder": "Posez n'importe quelle question...", - "agentNotInstalled": "{agent} n'est pas installé · ouvrez les paramètres Agents pour l'installer", - "agentAdapterNotInstalled": "L'adaptateur ACP de {agent} n'est pas installé (distinct de votre propre CLI) · ouvrez les paramètres Agents pour l'installer" - }, - "welcomePanel": { - "greeting": "Que souhaites-tu faire aujourd'hui ?", - "tips": { - "tileTabs": "Faites un clic droit sur un onglet de conversation et choisissez Affichage en mosaïque pour comparer plusieurs sessions côte à côte.", - "pinTab": "Double-cliquez sur un onglet de conversation pour l'épingler : une nouvelle session ne le remplacera plus automatiquement.", - "shortcutsNewSearch": "{newConversation} ouvre une nouvelle conversation, {searchConversations} recherche dans l'historique.", - "slashAtMention": "Saisissez / dans la zone de saisie pour les commandes slash, ou @ pour référencer un fichier du projet.", - "pasteDropFiles": "Collez une capture d'écran ou déposez un fichier directement dans la zone de saisie pour le joindre.", - "queueMessage": "Pendant que l'agent répond, continuez à écrire : votre message suivant est mis en file et envoyé automatiquement à la fin.", - "draftAutoSave": "Les brouillons non envoyés sont sauvegardés automatiquement par conversation et restaurés à votre retour.", - "forkSend": "Le menu déroulant du bouton d'envoi propose Bifurquer et envoyer pour ouvrir une branche dans un nouvel onglet à partir du point actuel.", - "exportConversation": "Faites un clic droit dans la conversation pour l'exporter en Markdown, HTML ou image.", - "chatChannels": "Connectez Telegram / Lark / WeChat dans Paramètres → Canaux de discussion pour continuer depuis votre téléphone.", - "shortcutsAuxPanel": "{toggleAuxPanel} bascule le panneau droit pour voir les fichiers modifiés et les changements Git de cette session.", - "shortcutsTerminalSidebar": "{toggleTerminal} ouvre le terminal intégré, {toggleSidebar} bascule la barre latérale.", - "customShortcuts": "Tous les raccourcis peuvent être réassignés dans Paramètres → Raccourcis.", - "webService": "Activez Paramètres → Service Web pour que votre équipe accède au même codeg depuis un navigateur.", - "fusionMode": "Ouvrez un fichier ou un diff pour l'afficher automatiquement à côté de la conversation.", - "quickMessages": "Ouvrez le bouton + à côté de la saisie et choisissez Messages rapides pour insérer un extrait enregistré (à gérer dans Paramètres → Messages rapides).", - "experts": "Le bouton + propose un menu Compétences expertes — chargez en un clic des rôles comme Débogage ou Planification.", - "taskBoard": "Les tâches à faire exécutent un travail de bout en bout : l'agent travaille dans son propre worktree, vous relisez le diff puis fusionnez.", - "automations": "Les Automatisations exécutent un prompt enregistré selon un planning — une revue nocturne, un rapport récurrent — et chaque exécution peut avoir son propre worktree.", - "tokenUsage": "Cliquez sur le nombre de conversations dans la barre d'état pour ouvrir la Consommation de tokens, détaillée par jour, agent, modèle et dossier.", - "mentionTargets": "@ ne sert pas qu'aux fichiers : mentionnez un autre agent pour lui confier une sous-tâche, ou référencez une session passée, un commit ou une compétence.", - "splitGroups": "Faites un clic droit sur un onglet et choisissez Diviser à droite ou Diviser en bas pour garder deux conversations dans leurs propres volets.", - "worktrees": "Ouvrez le bouton de branche et choisissez Nouveau worktree pour que plusieurs agents travaillent sur le même dépôt sans écraser les fichiers des autres.", - "importSessions": "Vous avez déjà lancé des sessions dans le terminal ? Le menu d'un dossier propose Importer les sessions locales pour récupérer cet historique dans codeg.", - "subSessions": "Quand un agent délègue, la sous-session apparaît imbriquée sous lui dans la barre latérale : dépliez la ligne pour suivre ce que chacune a fait.", - "liveFeedback": "Retour en direct, dans le menu +, glisse une note dans le tour que l'agent exécute déjà, sans l'interrompre.", - "skillPacks": "Paramètres → Packs de compétences regroupe experts du code, recherche scientifique et bureautique ; activez-les agent par agent.", - "modelProviders": "Paramètres → Fournisseurs de Modèles accepte votre propre clé d'API ou endpoint, puis vous choisissez le modèle dans la zone de saisie.", - "workspaceBackground": "Paramètres → Apparence définit une image de fond pour l'espace de travail, l'opacité des panneaux et les polices de l'application." - }, - "quickActions": { - "excel": "Classeur Excel", - "excelDesc": "Tableaux, formules et graphiques", - "word": "Document Word", - "wordDesc": "Rapports, lettres et notes", - "ppt": "Présentation", - "pptDesc": "Diapositives au design professionnel", - "pitchDeck": "Pitch Deck", - "pitchDeckDesc": "Présentation de levée avec indicateurs", - "morph": "Animation Morph", - "morphDesc": "Transitions de diapositive cinématographiques", - "morph3d": "Morph 3D", - "morph3dDesc": "Modèles 3D avec mouvements de caméra", - "academic": "Article académique", - "academicDesc": "Recherche avec citations et structure", - "financial": "Modèle financier", - "financialDesc": "États, DCF et projections", - "dashboard": "Tableau de bord", - "dashboardDesc": "KPI et analyses à partir de vos données", - "prompts": { - "excel": "Crée un classeur Excel avec les exigences suivantes :\n\n[décris ici tes données, tableaux, formules et graphiques]", - "word": "Crée un document Word avec les exigences suivantes :\n\n[décris ici le contenu, la structure et la mise en forme du document]", - "ppt": "Crée une présentation PowerPoint avec les exigences suivantes :\n\n[décris ici tes diapositives, le contenu et le design]", - "pitchDeck": "Crée un pitch deck de levée de fonds avec les exigences suivantes :\n\n[décris ici ton entreprise, le tour de financement et les indicateurs clés]", - "morph": "Crée une présentation avec des animations de transition Morph :\n\n[décris ici le sujet de la présentation et les effets visuels souhaités]", - "morph3d": "Crée une présentation Morph 3D avec des modèles GLB et des mouvements de caméra :\n\n[décris ici ton sujet et le concept visuel en 3D]", - "academic": "Rédige un article académique dans Word avec les exigences suivantes :\n\n[décris ici ton sujet de recherche, la méthodologie et les principaux résultats]", - "financial": "Crée un modèle financier dans Excel avec les exigences suivantes :\n\n[décris ici tes états financiers, projections et analyses]", - "dashboard": "Crée un tableau de bord de données dans Excel avec les exigences suivantes :\n\n[décris ici ta source de données, les KPI et les graphiques]", - "scientific-brainstorming": "Aide-moi à imaginer des pistes de recherche : explore les liens interdisciplinaires, questionne les hypothèses et repère les lacunes prometteuses. Le domaine que j'explore : ", - "hypothesis-generation": "Aide-moi à transformer ces observations en hypothèses testables, avec des prédictions claires, des mécanismes plausibles et des expériences. Mes observations : ", - "experimental-design": "Aide-moi à concevoir une expérience rigoureuse avant de collecter des données : le plan, la randomisation, les contrôles et comment éviter les facteurs de confusion. Ce que je veux étudier : ", - "statistical-power": "Aide-moi à déterminer la taille d'échantillon nécessaire : guide-moi dans une analyse de puissance (taille d'effet, alpha, puissance) pour mon plan. Détails : ", - "statistical-analysis": "Aide-moi à analyser ces données correctement : choisir le bon test, vérifier les hypothèses, rapporter les tailles d'effet et rédiger. Mes données et ma question : ", - "exploratory-data-analysis": "Fais une analyse exploratoire de mon fichier de données : résume sa structure, sa qualité et les motifs notables, puis propose les prochaines étapes. Le fichier est : ", - "scientific-visualization": "Aide-moi à créer une figure de qualité publication : mise en page claire, barres d'erreur honnêtes, palette adaptée au daltonisme et mise en forme de revue. Ce que je veux montrer : ", - "scientific-critical-thinking": "Aide-moi à évaluer de façon critique cette étude ou affirmation : apprécie la qualité des preuves, repère les biais et facteurs de confusion, et pèse les conclusions. La voici : ", - "paper-lookup": "Aide-moi à trouver des articles pertinents et du texte intégral en libre accès dans les bases de données savantes, avec des citations réutilisables. Je cherche : " - }, - "paper-lookup": "Recherche d'articles", - "paper-lookupDesc": "Rechercher dans 10 API savantes (PubMed, arXiv, OpenAlex, Crossref…) articles, citations et texte intégral en libre accès.", - "scientific-critical-thinking": "Pensée critique", - "scientific-critical-thinkingDesc": "Évaluer les affirmations scientifiques et la qualité des preuves : repérer biais et facteurs de confusion, appliquer GRADE.", - "scientific-visualization": "Visualisation scientifique", - "scientific-visualizationDesc": "Figures prêtes à publier : dispositions multipanneaux, annotations de significativité et mise en forme par revue.", - "exploratory-data-analysis": "Analyse exploratoire des données", - "exploratory-data-analysisDesc": "Exploration automatisée de fichiers de données scientifiques (200+ formats) avec métriques de qualité et rapports.", - "statistical-analysis": "Analyse statistique", - "statistical-analysisDesc": "Analyse statistique guidée : choix du test, vérification des hypothèses, tailles d'effet et rapport au format APA.", - "statistical-power": "Puissance statistique", - "statistical-powerDesc": "Analyse de la taille d'échantillon et de la puissance : effectifs nécessaires, effets minimaux détectables, courbes de puissance.", - "experimental-design": "Plan d'expérience", - "experimental-designDesc": "Concevoir des études rigoureuses avant la collecte : randomisation, blocs, contrôles et plans factoriels/DOE.", - "hypothesis-generation": "Génération d'hypothèses", - "hypothesis-generationDesc": "Transformer des observations en hypothèses testables avec prédictions, mécanismes et expériences de test.", - "scientific-brainstorming": "Brainstorming scientifique", - "scientific-brainstormingDesc": "Idéation de recherche ouverte : explorer les liens interdisciplinaires, questionner les hypothèses, repérer les lacunes.", - "tabs": { - "office": "Bureautique", - "coding": "Développement", - "research": "Recherche" - }, - "coding": { - "brainstormingDesc": "Explorer intention et besoins avant de coder", - "debuggingDesc": "Trouver la cause racine avant de corriger", - "writingSkillsDesc": "Créer, modifier et vérifier des skills réutilisables" - }, - "notEnabled": { - "title": "La compétence « {skill} » n’est pas encore activée pour {agent}", - "description": "Activez-la dans les Paramètres pour l’utiliser ici.", - "action": "Activer", - "hint": "Compétence non activée" - }, - "scrollPrev": "Afficher les compétences précédentes", - "scrollNext": "Afficher plus de compétences" - } - }, - "agentSelector": { - "noEnabledAgents": "Aucun agent activé", - "openAgentsSettings": "Ouvrir les paramètres des agents", - "notInstalled": "Non installé", - "moreAgents": "Plus d'agents ({count})" - }, - "subAgentOverlay": { - "title": "Sous-agents", - "collapsedSummary": "Sous-agents {count}", - "collapseAria": "Réduire les sous-agents" - }, - "agentPlanOverlay": { - "title": "Plan de l'agent", - "collapsePlanAria": "Réduire le plan", - "collapsedSummary": "Plan de travail {completed}/{total}", - "status": { - "completed": "Terminé", - "inProgress": "En cours", - "pending": "En attente", - "unknown": "Inconnu" - }, - "priority": { - "high": "Haute", - "medium": "Moyenne", - "low": "Basse", - "unknown": "Inconnue" - } - }, - "permissionDialog": { - "subtitle": "L'agent demande une autorisation pour continuer ce tour.", - "queuedCount": "+{count} en attente", - "kindFallbackTool": "outil", - "command": "Commande", - "cwd": "Répertoire de travail : {cwd}", - "filesSummary": "Fichiers : {count}", - "moreFiles": "+{count} fichiers supplémentaires", - "plan": "Plan de travail", - "allowedActions": "Actions autorisées", - "targetMode": "Mode cible : {mode}", - "optionGrants": "Ce que chaque option accorde", - "changeScopeSession": "Cette session", - "changeScopeProcess": "Cette exécution", - "changeScopeUser": "Enregistré dans les paramètres utilisateur", - "changeScopeProject": "Enregistré dans les paramètres du projet", - "changeScopeProjectLocal": "Enregistré dans les paramètres locaux du projet", - "changeScopePersistent": "Enregistré définitivement" - }, - "questionDialog": { - "title": "L'agent pose une question", - "placeholder": "Tapez votre réponse...", - "send": "Envoyer" - }, - "messageBranch": { - "previousBranchAria": "Branche précédente", - "nextBranchAria": "Branche suivante", - "pageOf": "{current} sur {total}" - }, - "terminal": { - "title": "Console", - "running": "En cours" - }, - "reasoning": { - "thinking": "Réflexion…", - "thoughtForFewSeconds": "Réflexion", - "thoughtForSeconds": "Réflexion" - }, - "linkSafety": { - "errorCannotOpen": "Impossible d'ouvrir le fichier local", - "errorNoWorkspace": "Aucun dossier d'espace de travail n'est actuellement actif.", - "errorFailedOpen": "Échec de l'ouverture du fichier local", - "errorFailedLink": "Échec de l'ouverture du lien", - "errorUnsupportedLinkProtocol": "Ce protocole de lien n’est pas pris en charge." - }, - "fileActions": { - "openInFinder": "Ouvrir dans Finder", - "openInExplorer": "Ouvrir dans Explorer", - "openInFileManager": "Ouvrir dans le gestionnaire de fichiers", - "copyRelativePath": "Copier le chemin relatif", - "copyAbsolutePath": "Copier le chemin absolu", - "pathCopied": "Chemin copié", - "copyPathFailed": "Échec de la copie du chemin", - "openFailed": "Échec de l'ouverture du fichier local" - }, - "messageList": { - "attachedResources": "Ressources jointes", - "loading": "Chargement...", - "loadEarlier": "Charger les messages précédents", - "loadingEarlier": "Chargement des messages précédents…", - "error": "Erreur : {message}", - "errorTitle": "Échec du chargement de la session", - "errorActionReload": "Recharger", - "errorActionNewSession": "Nouvelle conversation", - "emptyConversation": "Aucun message dans cette conversation.", - "systemMessage": "Message système", - "copyMessage": "Copier", - "copied": "Copié", - "downloadImage": "Télécharger l'image", - "downloadFailed": "Échec du téléchargement : {message}", - "imageGeneration": "Génération d'image", - "imageGenerationPending": "Génération de l'image…", - "imageGenerationFailed": "Échec de la génération d'image", - "model": "Modèle", - "tokenStats": "Utilisation des tokens", - "tokenInput": "Entrée", - "tokenOutput": "Sortie", - "tokenCacheRead": "Lecture du cache", - "tokenCacheWrite": "Écriture du cache", - "duration": "Durée", - "completedAt": "Terminé à", - "jumpToPreviousUserMessage": "Aller au message utilisateur", - "showMore": "Afficher plus", - "showLess": "Afficher moins" - }, - "liveTurnStats": { - "thinking": "Réflexion...", - "streaming": "Diffusion", - "elapsedHours": "{value} h", - "elapsedMinutes": "{value} min", - "elapsedSeconds": "{value} s", - "outputSpeedAria": "Vitesse de sortie estimée", - "outputSpeedTooltip": "Vitesse de sortie estimée (texte + raisonnement)" - }, - "jsonTree": { - "viewRaw": "Afficher le JSON brut", - "viewTree": "Afficher l'arborescence", - "fields": "{count, plural, one {# champ} other {# champs}}", - "items": "{count, plural, one {# élément} other {# éléments}}" - }, - "tool": { - "parameters": "Paramètres", - "error": "Erreur", - "result": "Résultat", - "status": { - "approvalRequested": "En attente d'approbation", - "approvalResponded": "Répondu", - "inputAvailable": "En cours", - "inputStreaming": "En attente", - "outputAvailable": "Terminé", - "outputDenied": "Refusé", - "outputError": "Erreur" - } - }, - "toolCallBlock": { - "tool": "Outil", - "error": "Erreur", - "result": "Résultat" - }, - "delegation": { - "subAgentRunning": "Sous-agent en cours…", - "noDetail": "Aucun détail disponible pour le moment.", - "unknownAgent": "Sous-agent", - "openDetail": "Voir la conversation", - "detailTitle": "Conversation du sous-agent", - "detailDescription": "Vue en lecture seule de la conversation du sous-agent délégué.", - "waitForResult": "En attente du résultat de la tâche {task}", - "waitForResultNoTask": "En attente du résultat de la tâche", - "cancelTask": "Annulation de la tâche {task}", - "cancelTaskNoTask": "Annulation de la tâche", - "resultPageOf": "{current} / {total}", - "prevResult": "Résultat précédent", - "nextResult": "Résultat suivant", - "noResultText": "Aucun résultat pour cette vérification.", - "status": { - "starting": "démarrage", - "running": "en cours", - "checked": "vérifié", - "waiting": "en attente d'approbation", - "ok": "terminé", - "err": { - "default": "échec", - "delegation_disabled": "désactivé", - "depth_limit": "limite de profondeur", - "invalid_agent_type": "agent invalide", - "spawn_failed": "échec du démarrage", - "send_failed": "échec de l'envoi", - "timeout": "délai dépassé", - "canceled": "annulé", - "child_refusal": "sous-agent refusé", - "child_max_tokens": "sous-agent : limite de jetons", - "child_max_turn_requests": "sous-agent : limite de requêtes", - "child_empty": "sous-agent sans sortie", - "child_unknown": "sous-agent : erreur", - "unknown": "tâche inconnue" - } - } - }, - "contentParts": { - "showingTailOutput": "Affichage de la fin de la sortie pendant le streaming pour de meilleures performances.", - "result": "Résultat", - "unknown": "inconnu", - "inputTruncated": "L'entrée a été tronquée — le diff peut être incomplet.", - "replaceAll": "TOUT REMPLACER", - "filesCount": "Fichiers : {count}", - "update": "mettre à jour", - "moreFiles": "+{count} fichiers supplémentaires", - "timeoutMs": "Délai d'expiration : {timeout}ms", - "backgroundTrue": "Arrière-plan : true", - "scriptToolCalls": "{count, plural, one {# appel d'outil} other {# appels d'outil}}", - "offset": "Décalage : {offset}", - "limit": "Limite : {limit}", - "pages": "Pages : {pages}", - "mode": "Mode : {mode}", - "cell": "Cellule : {cell}", - "shellSession": "Session {id}", - "pathLabel": "Chemin :", - "globLabel": "Glob :", - "typeLabel": "Type :", - "outputLabel": "Sortie :", - "caseInsensitive": "Insensible à la casse", - "multiline": "Multiligne", - "promptLabel": "Instruction", - "subjectLabel": "Sujet", - "taskLabel": "Tâche", - "nameLabel": "Nom :", - "agentPromptLabel": "Instruction", - "agentModelLabel": "Modèle", - "agentRunning": "En cours...", - "agentLiveTranscript": "Activité en direct", - "agentProgressTools": "{count} appels d'outils", - "agentProgressTurns": "{count} tours", - "agentProgressContext": "contexte {pct}%", - "agentSessionAction": "Voir la session du sous-agent", - "agentSessionTitle": "Session du sous-agent", - "agentSessionLoading": "Chargement de la transcription du sous-agent…", - "agentSessionEmpty": "Le sous-agent n'a encore rien écrit.", - "agentFallbackTitle": "Démarrage du sous-agent…", - "agentCodexLaunchOnly": "Lancé. Codex ne signale plus la progression de ce sous-agent : son résultat arrivera sous forme de message dans cette conversation.", - "agentStatsBash": "Commandes", - "agentStatsRead": "Fichiers lus", - "agentStatsSearch": "Recherches", - "agentStatsEdit": "Modifications", - "agentStatsOther": "Autres", - "goal": { - "title": "Objectif :", - "titleWithStatus": "Objectif {status}", - "objective": "Objectif", - "statusLabel": "Statut", - "tokensUsed": "Tokens utilisés", - "budget": "Budget", - "remaining": "Restant", - "elapsed": "Écoulé", - "tokens": "tokens", - "pause": "Pause", - "clear": "Effacer", - "status": { - "active": "actif", - "paused": "en pause", - "blocked": "bloqué", - "usageLimited": "utilisation limitée", - "budgetLimited": "budget limité", - "complete": "terminé", - "limited": "limite atteinte" - } - }, - "field": { - "file": "Fichier", - "notebook": "Carnet", - "command": "Commande", - "old": "Ancien", - "new": "Nouveau", - "pattern": "Motif", - "path": "Chemin", - "query": "Requête", - "url": "URL :", - "description": "Détails", - "content": "Contenu", - "source": "Origine", - "prompt": "Instruction", - "subject": "Sujet", - "taskId": "ID de tâche", - "status": "Statut", - "skill": "Skill", - "args": "Arguments", - "offset": "Décalage", - "limit": "Limite", - "glob": "Motif glob", - "type": "Type de donnée", - "output": "Sortie", - "replaceAll": "Tout remplacer", - "language": "Langue", - "timeout": "Délai", - "background": "Arrière-plan", - "agentType": "Type d'agent", - "library": "Bibliothèque", - "libraryId": "ID de bibliothèque" - }, - "title": { - "edit": "Modifier", - "command": "Commande", - "script": "Script", - "waitCommand": "Attendre {command}", - "waitCell": "Attendre la session {id}", - "terminateCommand": "Terminer {command}", - "terminateCell": "Terminer la session {id}", - "stdinChars": "Entrée {chars}", - "todoWrite": "TodoWrite (mise à jour des tâches)", - "read": "Lire", - "write": "Écrire", - "notebookEdit": "NotebookEdit (édition du carnet)", - "editFiles": "Modifier ({count} fichiers)", - "editWithTarget": "Modifier {target}", - "readWithTarget": "Lire {target}", - "writeWithTarget": "Écrire {target}", - "notebookEditWithTarget": "NotebookEdit ({target})", - "globWithPattern": "Motif glob {pattern}", - "listFilesWithPath": "Lister les fichiers {path}", - "grepWithPattern": "Motif grep {pattern}", - "taskCreateWithSubject": "Créer une tâche : {subject}", - "taskUpdateWithStatus": "Mettre à jour la tâche #{id} -> {status}", - "taskUpdate": "Mettre à jour la tâche #{id}", - "webFetchWithUrl": "WebFetch ({url})", - "webSearchWithQuery": "Recherche web : {query}", - "todosProgress": "Tâches ({done}/{total})", - "skillWithName": "Skill : {name}", - "genericWithContext": "{tool} ({context})" - }, - "search": { - "noMatches": "Aucune correspondance", - "matchSummary": "{matches, plural, one {# correspondance} other {# correspondances}} dans {files, plural, one {# fichier} other {# fichiers}}", - "fileSummary": "{files, plural, one {# fichier} other {# fichiers}}", - "moreResults": "{count, plural, one {# résultat supplémentaire non affiché} other {# résultats supplémentaires non affichés}}" - }, - "toolGroup": { - "search": "{count, plural, one {A exploré # recherche} other {A exploré # recherches}}", - "command": "{count, plural, one {A exécuté # commande} other {A exécuté # commandes}}", - "read": "{count, plural, one {A lu des fichiers # fois} other {A lu des fichiers # fois}}", - "memory": "{count, plural, one {A rappelé # souvenir} other {A rappelé # souvenirs}}", - "edit": "{count, plural, one {A modifié des fichiers # fois} other {A modifié des fichiers # fois}}", - "fetch": "{count, plural, one {A récupéré # ressource} other {A récupéré # ressources}}", - "think": "{count, plural, one {A réfléchi # fois} other {A réfléchi # fois}}", - "todo": "{count, plural, one {A mis à jour # tâche} other {A mis à jour # tâches}}", - "task": "{count, plural, one {A lancé # tâche} other {A lancé # tâches}}", - "other": "{count, plural, one {A utilisé # outil} other {A utilisé # outils}}", - "errorSuffix": "{count, plural, one {# échec} other {# échecs}}", - "joiner": " · " - }, - "planMode": { - "entered": "Mode planification activé", - "planLabel": "Plan", - "reviewApproved": "Plan approuvé — mise en œuvre", - "reviewKept": "Reste en mode plan", - "reviewPending": "En attente de la décision sur le plan", - "submitted": "Plan soumis", - "switched": "Mode changé" - }, - "backgroundTask": { - "title": "Tâche en arrière-plan", - "titleWithId": "Tâche en arrière-plan · {id}", - "running": "En cours", - "completed": "Terminée", - "failed": "Échouée", - "stopped": "Arrêtée", - "exitCode": "sortie {code}", - "polledTimes": "Interrogée {count} fois", - "runningInBackground": "Arrière-plan", - "launchNote": "En cours d'exécution en arrière-plan · {id}" - }, - "codexScript": { - "outputMissing": "Codex a tronqué la sortie du script et supprimé le séparateur de cette commande ; aucune sortie n'a donc pu lui être attribuée.", - "sharedWith": "Contient aussi la sortie de {commands} — codex en a tronqué les séparateurs.", - "truncated": "tronqué" - } - }, - "messageNav": { - "title": "Navigation des messages", - "collapse": "Réduire la navigation des messages", - "collapsedSummary": "Messages {count}", - "fileCount": "{count, plural, one {# fichier} other {# fichiers}}", - "remove": "Retirer", - "noDiffDataAvailable": "Aucune donnée de diff disponible pour {filePath}" - }, - "replyArtifacts": { - "title": "Fichiers modifiés", - "fileCount": "{count, plural, one {# fichier} other {# fichiers}}", - "newFilesTitle": "Nouveaux fichiers", - "revealInFolder": "Afficher dans le gestionnaire de fichiers", - "openFile": "Ouvrir {filePath}", - "openInEditor": "Ouvrir dans l'éditeur", - "remove": "Retirer", - "noDiffDataAvailable": "Aucune donnée de diff disponible pour {filePath}" - }, - "askQuestion": { - "title": "L'agent attend votre choix", - "subtitle": "Répondez puis envoyez. Vous pouvez ignorer à tout moment.", - "recommended": "Recommandé", - "other": "Autre", - "otherPlaceholder": "Saisissez votre réponse…", - "singleSelect": "Unique", - "multiSelect": "Multiple", - "skip": "Ignorer", - "next": "Suivant", - "submit": "Envoyer", - "submitError": "Échec de l'envoi. Veuillez réessayer." - }, - "planApproval": { - "title": "L'agent a un plan — à vérifier", - "emptyPlan": "L'agent n'a pas rédigé de plan. Approuvez pour commencer ou demandez des modifications.", - "approve": "Approuver et lancer", - "requestChanges": "Demander des modifications", - "abandon": "Abandonner", - "feedbackPlaceholder": "Que faut-il changer ?", - "sendChanges": "Envoyer", - "cancel": "Annuler", - "submitError": "Échec de l'envoi. Veuillez réessayer." - }, - "feedbackCheckResult": { - "count": "{count, plural, =1 {1 retour} other {# retours}}", - "expand": "Afficher tous les retours", - "collapse": "Réduire", - "errorTitle": "Échec de la vérification des retours" - }, - "askQuestionResult": { - "title": "Question", - "answeredLabel": "Question et réponse :", - "awaiting": "En attente de ta réponse…", - "declined": "Tu as ignoré cette question — l’agent a utilisé son propre jugement.", - "noSelection": "Aucune sélection" - }, - "configStale": { - "agentConfigTitle": "Paramètres de l'agent mis à jour", - "modelProviderTitle": "Fournisseur de modèle mis à jour", - "description": "Cette session utilise encore son ancienne configuration. Reconnectez-vous pour l'appliquer (l'historique de conversation est conservé).", - "reconnect": "Reconnecter pour appliquer", - "reconnecting": "Reconnexion…", - "reconnectDisabledDuringTurn": "Disponible une fois le tour en cours terminé", - "dismiss": "Ignorer", - "reconnectFailed": "Échec de la reconnexion de la session", - "applied": "Nouvelle configuration appliquée" - }, - "piProjectTrust": { - "title": "Ce projet fournit des ressources pi", - "description": "pi ne charge pas les fichiers .pi du dépôt. Examinez-les pour décider.", - "descriptionExecutable": "Le dépôt fournit des extensions pi, qui exécutent du code au démarrage. pi ne les charge pas. Examinez-les avant de décider.", - "review": "Examiner…", - "dismiss": "Ignorer", - "dialogTitle": "Faire confiance aux ressources pi de ce projet ?", - "dialogDescription": "pi ne charge les fichiers .pi d'un dépôt que si vous faites confiance au dossier. N'accordez votre confiance que si vous avez confiance dans le contenu de ce dépôt.", - "executionWarning": "Les extensions sont du code. En faisant confiance à ce dossier, vous autorisez le dépôt à les exécuter au démarrage de pi avec vos permissions, avant même l'envoi d'un message.", - "scopeNote": "La décision est enregistrée dans le trust.json de pi pour ce dossier, s'applique à tous les dossiers qu'il contient et sert aussi lorsque vous lancez pi vous-même dans un terminal. Vous pourrez la modifier dans Paramètres → Agents → Pi.", - "trust": "Faire confiance au projet", - "decline": "Ne pas charger", - "disabledDuringTurn": "Disponible une fois le tour en cours terminé", - "trustedToast": "Projet approuvé — reconnexion effectuée pour que pi charge ses ressources", - "declinedToast": "Les ressources du projet restent non chargées", - "saveFailed": "Échec de l'enregistrement de la décision de confiance du projet", - "grantTitle": "Ce projet est déjà approuvé", - "grantDescription": "pi charge les fichiers .pi du dépôt. Examinez ce que cela autorise.", - "grantInheritedDescription": "Un dossier parent est approuvé, donc pi charge les fichiers .pi du dépôt. Examinez ce que cela autorise.", - "grantDialogTitle": "Les ressources pi de ce projet sont approuvées", - "grantDialogDescription": "pi est autorisé à charger les fichiers .pi du dépôt. Les versions précédentes de codeg accordaient cela automatiquement à l'ouverture d'un dossier, la question ne vous a donc peut-être jamais été posée.", - "grantExecutionWarning": "Les extensions sont du code. Le dépôt les exécute au démarrage de pi avec vos permissions, avant même l'envoi d'un message.", - "inheritedFrom": "Approuvé via", - "revoke": "Révoquer la confiance", - "keepTrusted": "Conserver la confiance", - "revokedToast": "Confiance révoquée — reconnexion effectuée pour que pi cesse de charger les ressources du projet", - "trustedNoReconnect": "Projet approuvé — effectif au prochain démarrage de pi", - "revokedNoReconnect": "Confiance révoquée — effectif au prochain démarrage de pi" - }, - "collabAgent": { - "title": "Sous-agent", - "errorTitle": "Échec de la tâche du sous-agent", - "statesLabel": "Sous-agents", - "statusRunning": "En cours", - "statusCompleted": "Terminé", - "statusFailed": "Échec", - "statusPending": "Démarrage", - "statusInterrupted": "Interrompu", - "statusClosed": "Fermé", - "statusNotFound": "Introuvable", - "opSpawn": "Démarrage du sous-agent", - "opWait": "Récupération du résultat du sous-agent", - "opClose": "Fermeture du sous-agent", - "opResume": "Reprise du sous-agent" - }, - "contextCompaction": { - "compacting": "Compactage du contexte…", - "compacted": "Contexte compacté", - "compactedTokens": "Contexte compacté · {before} → {after} tokens", - "failed": "Échec de la compaction du contexte" - }, - "sessionFailure": { - "category": { - "connection": "Problème de connexion", - "access": "Problème d'accès", - "limit": "Limite atteinte", - "request": "Requête rejetée", - "service": "Problème de service", - "unknown": "Problème de session" - }, - "action": { - "retry": "Réessayer", - "login": "Se connecter", - "newSession": "Nouvelle session" - }, - "recovered": "Rétabli", - "retryUnavailable": "Aucun message précédent à renvoyer.", - "toggleDetails": "Afficher/masquer les détails" - }, - "backgroundTasks": { - "running": "{count, plural, one {# tâche en arrière-plan en cours} other {# tâches en arrière-plan en cours}}", - "settling": "Synchronisation des résultats d'arrière-plan…", - "settledFallback": "Tâche en arrière-plan terminée ({status})", - "cardRunning": "En cours d'exécution en arrière-plan", - "cardLaunchedPending": "Tâche lancée en arrière-plan", - "cardCompleted": "Tâche en arrière-plan terminée", - "cardFinishedWithStatus": "Tâche en arrière-plan terminée ({status})", - "cardResultPending": "Résultat pas encore reçu" - }, - "proposedPlan": { - "title": "Plan proposé", - "planning": "Planification…" - } - }, - "diffPreview": { - "mode": { - "added": "Ajouté", - "deleted": "Supprimé", - "renamed": "Renommé", - "modified": "Modifié" - }, - "hunkLabel": "Bloc {index}", - "loadingHunk": "Chargement du hunk...", - "noDiffData": "Aucune donnée diff", - "showRemainingLines": "Afficher {count} lignes de plus" - }, - "conversationContextBar": { - "folderTitle": "Dossier de travail", - "branchTitle": "Branche de travail", - "searchFolder": "Rechercher un dossier...", - "searchBranch": "Rechercher une branche...", - "noFolders": "Aucun dossier", - "noBranches": "Aucune branche", - "noBranch": "(aucune branche)", - "chatModeLabel": "Mode chat", - "commit": "Valider", - "push": "Pousser", - "merge": "Fusionner", - "toasts": { - "folderChanged": "Basculé vers {name}", - "openFolderFailed": "Échec de l'ouverture du dossier", - "switchedToChatMode": "Basculé en mode discussion", - "openStashFailed": "Échec de l'ouverture de la fenêtre de remisage", - "openMergeFailed": "Échec de l'ouverture de la fenêtre de fusion" - } - }, - "cloneDialog": { - "title": "Cloner un dépôt", - "repositoryUrl": "URL du dépôt", - "repositoryUrlPlaceholder": "https://github.com/user/repo.git", - "directory": "Répertoire", - "directoryPlaceholder": "Sélectionnez le répertoire cible...", - "browseDirectory": "Parcourir le répertoire", - "cancel": "Annuler", - "clone": "Cloner", - "clonePath": "Chemin de clonage : {path}" - }, - "toasts": { - "cloneFailed": "Échec du clonage du dépôt" - } - }, - "ProjectBoot": { - "title": "Lanceur de projet", - "tabs": { - "shadcn": "shadcn", - "hyperframes": "HyperFrames" - }, - "hyperframes": { - "title": "Projet vidéo HyperFrames", - "subtitle": "Générez un projet HTML-vers-vidéo. L'agent de l'espace de travail peut ensuite l'écrire et le rendre.", - "resolution": "Résolution", - "skillsTitle": "Skills des agents", - "skillsDesc": "Installe globalement les skills HyperFrames (lien symbolique) pour les agents sélectionnés, afin qu'ils puissent créer et rendre des vidéos.", - "recheck": "Revérifier", - "installedBadge": "Installé", - "skillsInstall": "Installer / mettre à jour les skills", - "skillsInstalling": "Installation des skills…", - "skillsInstalled": "Skills HyperFrames installées", - "skillsInstallFailed": "Impossible d'installer les skills HyperFrames" - }, - "config": { - "base": "Base", - "style": "Style", - "baseColor": "Couleur de base", - "theme": "Thème", - "chartColor": "Couleur du graphique", - "iconLibrary": "Bibliothèque d'icônes", - "font": "Police", - "fontHeading": "Police de titre", - "menuAccent": "Accent du menu", - "menuColor": "Couleur du menu", - "radius": "Rayon", - "template": "Modèle", - "createProject": "Créer un projet", - "sectionStyle": "Style", - "sectionColors": "Couleurs", - "sectionTypography": "Typographie", - "sectionInterface": "Interface" - }, - "preview": { - "loading": "Chargement de l'aperçu..." - }, - "createDialog": { - "title": "Créer un projet", - "projectName": "Nom du projet", - "projectNamePlaceholder": "mon-app", - "frameworkTemplate": "Modèle de framework", - "packageManager": "Gestionnaire de paquets", - "saveDirectory": "Répertoire de sauvegarde", - "saveDirectoryPlaceholder": "Sélectionner un répertoire...", - "browseDirectory": "Parcourir", - "projectPath": "Le projet sera créé dans : {path}", - "advancedOptions": "Options avancées", - "base": "Bibliothèque de base", - "enableRtl": "Activer le support RTL", - "enableRtlDescription": "Activer la prise en charge de la mise en page pour les langues de droite à gauche (ex. arabe, hébreu)", - "pmChecking": "Vérification...", - "pmNotInstalled": "Non installé", - "cancel": "Annuler", - "create": "Créer", - "creating": "Création du projet..." - }, - "toasts": { - "createFailed": "Échec de la création du projet", - "createSuccess": "Projet créé avec succès", - "openWorkspaceFailed": "Projet créé, mais impossible de l'ouvrir dans l'espace de travail" - }, - "errors": { - "directoryExists": "Le répertoire cible existe déjà", - "commandFailed": "La commande de création du projet a échoué." - } - }, - "WebServiceSettings": { - "addressSwitchHint": "Changer ne modifie que l'adresse affichée et ouverte ici ; le service écoute sur toutes les interfaces et reste accessible à chaque adresse.", - "sectionTitle": "Service Web", - "sectionDescription": "Activer pour accéder à Codeg à distance via le navigateur", - "port": "Port", - "status": "Statut", - "autoStart": "Démarrage auto", - "autoStartHint": "Démarrer le service Web au lancement de Codeg", - "running": "En cours", - "stopped": "Arrêté", - "processing": "Traitement...", - "start": "Démarrer", - "stop": "Arrêter", - "startFailed": "Échec du démarrage", - "stopFailed": "Échec de l'arrêt", - "saveConfigFailed": "Échec de l'enregistrement des paramètres du service Web", - "open": "Ouvrir", - "hide": "Masquer", - "show": "Afficher", - "copy": "Copier", - "qrcode": "Code QR", - "qrcodeTitle": "Scanner pour ouvrir", - "qrcodeHint": "Scannez avec votre téléphone pour ouvrir Codeg dans un navigateur", - "addressLabel": "Adresse d'accès", - "tokenLabel": "Token d'accès", - "tokenHint": "Entrez ce token lors du premier accès au client Web", - "tokenPlaceholder": "Laisser vide pour générer automatiquement", - "regenerate": "Régénérer", - "stalePortOccupiedTitle": "Le port {port} est utilisé par un autre processus", - "stalePortUnknownTitle": "L'état du port {port} est indéterminé", - "stalePortHint": "Codeg ne peut pas s'attacher tant que le port n'est pas libéré. Changez de port ci-dessus, ou fermez le processus qui le retient.", - "errors": { - "alreadyRunning": "Le service Web est déjà en cours d'exécution", - "invalidAddress": "Format d'hôte ou de port non valide", - "portInUse": "Le port {port} est déjà utilisé. Fermez le processus qui l'utilise ou choisissez un autre port.", - "permissionDenied": "Permission refusée. Utilisez un port supérieur à 1024 ou exécutez avec des privilèges plus élevés.", - "addressUnavailable": "Cette adresse n'est pas disponible sur cette machine", - "bindFailed": "Échec de la liaison à l'adresse" - } - }, - "DirectoryBrowser": { - "title": "Parcourir le répertoire", - "pathPlaceholder": "Entrez le chemin du répertoire...", - "goHome": "Aller au répertoire personnel", - "navigateUp": "Aller au répertoire parent", - "select": "Sélectionner", - "cancel": "Annuler", - "loading": "Chargement...", - "emptyDirectory": "Ce répertoire est vide", - "errorLoadingDir": "Échec du chargement du répertoire", - "permissionDenied": "Permission refusée" - }, - "ChatChannelSettings": { - "loading": "Chargement...", - "sectionTitle": "Canaux de chat", - "sectionDescription": "Configurez des bots IM pour recevoir des notifications d'événements et interroger l'activité de codage.", - "addChannel": "Ajouter un canal", - "noChannels": "Aucun canal de chat configuré pour le moment.", - "channelName": "Nom", - "channelNamePlaceholder": "Mon bot Telegram", - "channelType": "Type de canal", - "lark": "Lark (Feishu)", - "weixin": "WeChat", - "dailyReport": "Rapport quotidien", - "dailyReportTime": "Heure du rapport", - "nameRequired": "Le nom du canal est requis.", - "tokenRequired": "Le token est requis.", - "chatIdRequired": "Le Chat ID est requis.", - "topicMode": "Mode groupe de sujets", - "topicModeHint": "Route les sujets de forum Telegram comme des sessions Codeg séparées. Le bot doit être dans un supergroupe forum et pouvoir gérer les sujets.", - "loadFailed": "Échec du chargement des canaux.", - "saveFailed": "Échec de l'enregistrement.", - "connectSuccess": "Canal connecté.", - "connectFailed": "Échec de la connexion", - "disconnectSuccess": "Canal déconnecté.", - "disconnectFailed": "Échec de la déconnexion.", - "testSuccess": "Test de connexion réussi.", - "testFailed": "Test de connexion échoué", - "deleteSuccess": "Canal supprimé.", - "deleteFailed": "Échec de la suppression du canal.", - "deleteConfirmTitle": "Supprimer le canal", - "deleteConfirmMessage": "Le canal et ses journaux de messages seront définitivement supprimés. Êtes-vous sûr ?", - "cancel": "Annuler", - "delete": "Supprimer", - "create": "Créer", - "save": "Enregistrer", - "channelListTitle": "Canaux configurés", - "channelListDescription": "Les canaux activés se connectent automatiquement au démarrage du service.", - "editChannel": "Modifier le canal", - "editSuccess": "Canal mis à jour.", - "tokenPlaceholderKeep": "Laisser vide pour conserver l'actuel", - "weixinScanTitle": "Scanner le QR code", - "weixinScanDescription": "Ouvrez WeChat et scannez le QR code pour vous connecter.", - "weixinQrcodeExpired": "QR code expiré.", - "weixinRefreshQrcode": "Actualiser", - "weixinWaitingScan": "En attente du scan...", - "weixinPollError": "Connexion instable, nouvelle tentative...", - "weixinReconnectNotice": "En raison des limitations du protocole iLink, après chaque reconnexion vous devez envoyer un message au bot pour que les déclencheurs d'événements prennent effet.", - "connect": "Connecter", - "disconnect": "Déconnecter", - "test": "Tester la connexion", - "tabs": { - "channels": "Canaux", - "commands": "Commandes", - "events": "Événements", - "other": "Autres" - }, - "commands": { - "title": "Commandes intégrées", - "description": "Commandes bot disponibles dans les canaux de chat. Dans les chats de groupe, @Bot est requis pour traiter les messages.", - "prefixLabel": "Préfixe de commande", - "prefixDescription": "1-3 caractères non alphanumériques pour déclencher les commandes du bot (par défaut /).", - "prefixSaved": "Préfixe de commande enregistré.", - "prefixSaveFailed": "Échec de l'enregistrement du préfixe.", - "prefixInvalid": "Le préfixe doit être de 1-3 caractères non alphanumériques.", - "save": "Enregistrer", - "folderDesc": "Sélectionner le dossier de travail", - "agentDesc": "Sélectionner l'agent IA", - "taskDesc": "Créer une session et exécuter la tâche", - "sessionsDesc": "Lister les sessions actives du dossier", - "resumeDesc": "Conversations récentes / reprendre une session", - "cancelDesc": "Annuler la tâche en cours", - "approveDesc": "Approuver la demande de permission de l'agent", - "denyDesc": "Refuser la demande de permission de l'agent", - "searchDesc": "Rechercher des conversations par mot-clé", - "todayDesc": "Résumé de l'activité du jour", - "statusDesc": "État de connexion du canal", - "helpDesc": "Afficher l'aide" - }, - "events": { - "title": "Notifications d'événements", - "description": "Une fois activés, les événements déclenchés seront envoyés au canal.", - "turnComplete": "Tour terminé", - "turnCompleteDesc": "Lorsqu'un tour d'agent se termine", - "error": "Erreur de l'agent", - "errorDesc": "Lorsqu'un agent rencontre une erreur", - "permissionRequest": "Demande d'autorisation", - "permissionRequestDesc": "Lorsqu'un agent demande une autorisation", - "questionRequest": "Question de l'agent", - "questionRequestDesc": "Quand un agent vous pose une question", - "userPromptSent": "Message de l'utilisateur", - "userPromptSentDesc": "Lorsque vous envoyez un message (le texte du message est inclus dans la notification)", - "saved": "Filtre d'événements mis à jour.", - "saveFailed": "Échec de l'enregistrement du filtre d'événements.", - "loadFailed": "Échec du chargement des paramètres.", - "retry": "Réessayer", - "webhooksTitle": "Webhooks", - "webhooksDescription": "Envoie une charge JSON via POST vers une ou plusieurs URL lorsqu'un événement activé se déclenche. Le filtre d'événements ci-dessus s'applique aussi aux webhooks.", - "webhookUrlPlaceholder": "https://example.com/webhook", - "addWebhook": "Ajouter un webhook", - "removeWebhook": "Supprimer le webhook", - "webhookSave": "Enregistrer", - "webhooksSaved": "Webhooks enregistrés.", - "webhooksSaveFailed": "Échec de l'enregistrement des webhooks.", - "webhookInvalidUrl": "Saisissez des URL http(s) valides.", - "docsTitle": "Format de la requête", - "docsMethod": "Méthode", - "docsContentType": "Content-Type", - "docsNote": "Chaque événement activé est envoyé à toutes les URL. Les webhooks ne sont pas anti-rebond ; le filtre d'événements ci-dessus s'applique toujours.", - "editWebhook": "Modifier le webhook", - "enableWebhook": "Activer le webhook", - "webhookDuplicate": "Cette URL est déjà configurée.", - "cancel": "Annuler", - "webhooksEmpty": "Aucun webhook configuré pour le moment.", - "deleteWebhookTitle": "Supprimer le webhook", - "deleteWebhookMessage": "Supprimer ce webhook ? Les événements ne seront plus envoyés à cette URL.", - "delete": "Supprimer" - }, - "language": { - "title": "Langue des messages", - "description": "Langue utilisée pour les notifications d'événements, les réponses aux commandes et les rapports quotidiens envoyés aux canaux de chat.", - "saved": "Langue des messages enregistrée.", - "saveFailed": "Échec de l'enregistrement de la langue des messages.", - "en": "Anglais", - "zh-cn": "Chinois simplifié", - "zh-tw": "Chinois traditionnel", - "ja": "Japonais", - "ko": "Coréen", - "es": "Espagnol", - "de": "Allemand", - "fr": "Français", - "pt": "Portugais", - "ar": "Arabe" - } - }, - "ModelProviderSettings": { - "sectionTitle": "Fournisseurs de Modèles", - "sectionDescription": "Gérer les identifiants des fournisseurs d'API pour les agents.", - "filterAll": "Tous", - "providerListTitle": "Fournisseurs Configurés", - "addProvider": "Ajouter un Fournisseur", - "editProvider": "Modifier le Fournisseur", - "noProviders": "Aucun fournisseur de modèle configuré.", - "providerName": "Nom", - "providerNamePlaceholder": "Ex. OpenAI, Anthropic", - "apiUrl": "URL de l'API", - "apiUrlPlaceholder": "https://api.openai.com/v1", - "apiKey": "Clé API", - "apiKeyPlaceholder": "sk-...", - "apiKeyKeepCurrent": "Laisser vide pour conserver l'actuelle", - "agentTypes": "Types d'Agent", - "agentTypesRequired": "Au moins un type d'agent est requis.", - "agentType": "Type d'Agent", - "agentTypeRequired": "Le type d'agent est requis.", - "agentTypeImmutableHint": "Le type d'agent ne peut pas être modifié après la création.", - "model": "Modèle", - "modelPlaceholderCodex": "gpt-5.6-sol / gpt-5.5", - "modelPlaceholderGemini": "gemini-3-pro-preview", - "claudeMainModel": "Modèle Principal", - "claudeReasoningModel": "Modèle de Raisonnement (réflexion)", - "claudeHaikuDefaultModel": "Modèle Haiku par Défaut", - "claudeSonnetDefaultModel": "Modèle Sonnet par Défaut", - "claudeOpusDefaultModel": "Modèle Opus par Défaut", - "claudeCustomModelOption": "ID de modèle personnalisé", - "claudeCustomModelOptionName": "Nom du modèle personnalisé", - "claudeCustomModelOptionDescription": "Description du modèle personnalisé", - "claudeCustomModelOptionHint": "Ajoute une entrée personnalisée au sélecteur de modèles de Claude (par exemple un modèle derrière une passerelle/un proxy personnalisé). Le nom et la description sont des informations d'affichage facultatives.", - "nameRequired": "Le nom du fournisseur est requis.", - "apiUrlRequired": "L'URL de l'API est requise.", - "apiKeyRequired": "La clé API est requise.", - "loadFailed": "Échec du chargement des fournisseurs.", - "saveFailed": "Échec de la sauvegarde.", - "createSuccess": "Fournisseur créé.", - "editSuccess": "Fournisseur mis à jour.", - "deleteSuccess": "Fournisseur supprimé.", - "deleteConfirmTitle": "Supprimer le Fournisseur", - "deleteConfirmMessage": "Le fournisseur \"{name}\" sera définitivement supprimé. Êtes-vous sûr ?", - "deleteBlockedByAgent": "{agents} utilise ce fournisseur. Veuillez le dissocier avant de supprimer.", - "cancel": "Annuler", - "delete": "Supprimer", - "create": "Créer", - "save": "Enregistrer", - "affectedRunningSessions": "{count, plural, one {# session active doit se reconnecter pour appliquer la modification} other {# sessions actives doivent se reconnecter pour appliquer la modification}}" - }, - "SkillMatrix": { - "loading": "Chargement…", - "searchPlaceholder": "Rechercher par nom, id ou description", - "empty": "Rien à afficher.", - "emptySearch": "Aucun résultat pour la recherche actuelle.", - "skillColumn": "Compétence", - "selectAll": "Tout sélectionner (visible)", - "selectSkill": "Sélectionner {name}", - "everything": { - "label": "En masse", - "enable": "Tout activer (visible)", - "disable": "Tout désactiver (visible)" - }, - "columnMenu": { - "enableAll": "Activer toutes les compétences", - "disableAll": "Désactiver toutes les compétences" - }, - "rowMenu": { - "label": "Actions groupées pour {name}", - "enableAll": "Activer pour tous les agents", - "disableAll": "Désactiver pour tous les agents" - }, - "bulk": { - "selected": "{count} sélectionné(s)", - "targetAll": "Tous les agents", - "targetSome": "{count} agents", - "enable": "Activer", - "disable": "Désactiver", - "clear": "Effacer" - }, - "confirm": { - "disableTitle": "Désactiver ces liens ?", - "disableBody": "Cela supprimera {count} liens de compétences gérés par codeg. Les compétences occupant un répertoire personnalisé ne sont pas touchées. Vous pouvez les réactiver à tout moment.", - "cancel": "Annuler", - "confirm": "Désactiver" - }, - "toasts": { - "loadFailed": "Échec du chargement des états des compétences", - "applyFailed": "Échec de l'application des modifications", - "enabled": "{count} liens activés", - "disabled": "{count} liens désactivés", - "enabledPartial": "{ok} activés, {failed} échoués", - "disabledPartial": "{ok} désactivés, {failed} échoués" - }, - "detail": { - "enableForAgents": "Activer pour les agents", - "preview": "Aperçu de SKILL.md", - "loadingContent": "Chargement du contenu…" - }, - "copyModeHint": "Copié (non lié) — réactivez après les mises à jour pour obtenir la dernière version" - }, - "ExpertsSettings": { - "title": "Compétences d'experts", - "description": "Activez des workflows de compétences soigneusement sélectionnés et éprouvés pour vos agents de codage IA. Chaque expert est une compétence autonome du projet superpowers — codeg gère la copie centrale et la lie aux agents que vous choisissez.", - "loading": "Chargement des experts…", - "loadingContent": "Chargement du contenu…", - "emptyExperts": "Aucun expert disponible. Vérifiez les journaux de l'application.", - "emptySelection": "Sélectionnez un expert pour voir son contenu et gérer son activation.", - "emptySearch": "Aucun expert ne correspond à la recherche actuelle.", - "searchPlaceholder": "Rechercher des experts par nom, ID ou description", - "enableForAgents": "Activer pour les agents", - "noAgents": "Aucun agent ACP détecté.", - "copyModeWarning": "Copié (non lié). Réactivez après les mises à jour de codeg pour obtenir la dernière version.", - "previewTitle": "Aperçu de SKILL.md", - "categories": { - "discovery": "Découverte et conception", - "planning": "Planification", - "execution": "Exécution", - "quality": "Qualité et tests", - "debugging": "Débogage", - "review": "Révision et intégration", - "meta": "Méta" - }, - "states": { - "not_linked": "Non activé", - "linked_to_codeg": "Activé", - "linked_elsewhere": "Bloqué — un autre lien existe", - "blocked_by_real_directory": "Bloqué — une compétence personnalisée occupe ce nom", - "broken": "Lien cassé" - }, - "badges": { - "userModified": "Modifié par l'utilisateur" - }, - "actions": { - "openCentralDir": "Ouvrir le dossier central", - "refresh": "Actualiser" - }, - "toasts": { - "loadFailed": "Échec du chargement des détails de l'expert", - "enabled": "Expert activé pour cet agent", - "disabled": "Expert désactivé pour cet agent", - "enableFailed": "Échec de l'activation de l'expert", - "disableFailed": "Échec de la désactivation de l'expert", - "openFolderFailed": "Échec de l'ouverture du dossier" - } - }, - "ScienceSettings": { - "title": "Compétences de recherche scientifique", - "description": "Activez des compétences de recherche scientifique sélectionnées pour vos agents de codage IA : génération d'hypothèses, plan d'expérience, statistiques, visualisation, évaluation critique et recherche bibliographique. codeg gère une copie centrale et relie chaque compétence aux agents que vous choisissez.", - "loading": "Chargement des compétences scientifiques…", - "emptySkills": "Aucune compétence scientifique disponible. Consultez les journaux de l'application.", - "searchPlaceholder": "Rechercher des compétences scientifiques par nom, id ou description", - "categories": { - "ideation": "Idéation", - "design": "Plan d'étude", - "analysis": "Analyse", - "visualization": "Visualisation", - "evaluation": "Évaluation", - "literature": "Littérature" - }, - "states": { - "not_linked": "Non activé", - "linked_to_codeg": "Activé", - "linked_elsewhere": "Bloqué — un autre lien existe", - "blocked_by_real_directory": "Bloqué — une compétence personnalisée occupe ce nom", - "broken": "Lien cassé" - }, - "badges": { - "userModified": "Modifié par l'utilisateur", - "needsKey": "Clé API requise", - "needsSetup": "Configuration possible" - }, - "actions": { - "openCentralDir": "Ouvrir le dossier central", - "refresh": "Actualiser" - }, - "toasts": { - "openFolderFailed": "Échec de l'ouverture du dossier" - } - }, - "OfficeToolsSettings": { - "title": "Outils Office", - "description": "Gérez les compétences OfficeCLI pour créer des fichiers Excel, Word et PowerPoint. Installez OfficeCLI, synchronisez les compétences et activez-les par agent.", - "loadingContent": "Chargement du contenu…", - "emptySkills": "Aucune compétence disponible. Installez OfficeCLI et synchronisez les compétences.", - "emptySelection": "Sélectionnez une compétence pour voir son contenu et gérer l'activation.", - "emptySearch": "Aucune compétence correspondante.", - "searchPlaceholder": "Rechercher par nom, ID ou description", - "enableForAgents": "Activer pour les agents", - "noAgents": "Aucun agent ACP détecté.", - "installFirst": "Installez d'abord OfficeCLI pour activer les compétences.", - "syncFirst": "Synchronisez d'abord les compétences pour charger le contenu.", - "noContent": "Aucun contenu disponible.", - "copyModeWarning": "Copié (non lié). Resynchronisez pour obtenir la dernière version.", - "previewTitle": "Aperçu SKILL.md", - "detection": { - "installed": "Installé", - "notInstalled": "Non installé", - "notRunnable": "Installé mais non exécutable", - "installHint": "Installez OfficeCLI pour activer les compétences de génération de documents Office pour vos agents IA.", - "install": "Installer", - "uninstall": "Désinstaller", - "syncSkills": "Synchroniser les compétences" - }, - "categories": { - "general": "Général", - "presentations": "Présentations", - "documents": "Documents", - "spreadsheets": "Tableurs" - }, - "states": { - "not_linked": "Non activé", - "linked_to_codeg": "Activé", - "linked_elsewhere": "Bloqué — un autre lien existe", - "blocked_by_real_directory": "Bloqué — une compétence personnalisée occupe ce nom", - "broken": "Lien cassé" - }, - "badges": { - "notSynced": "Non synchronisé" - }, - "actions": { - "refresh": "Actualiser" - }, - "toasts": { - "loadFailed": "Échec du chargement des détails de la compétence", - "enabled": "Compétence activée pour cet agent", - "disabled": "Compétence désactivée pour cet agent", - "enableFailed": "Échec de l'activation de la compétence", - "disableFailed": "Échec de la désactivation de la compétence", - "installSuccess": "OfficeCLI installé avec succès", - "installFailed": "Échec de l'installation d'OfficeCLI", - "uninstallSuccess": "OfficeCLI désinstallé", - "uninstallFailed": "Échec de la désinstallation d'OfficeCLI", - "syncSuccess": "{synced} compétences synchronisées", - "syncPartial": "{synced} synchronisées, {errors} échouées", - "syncFailed": "Échec de la synchronisation des compétences" - }, - "autoPreviewLabel": "Ouvrir l'aperçu automatiquement", - "autoPreviewHint": "Lorsqu'un agent crée ou modifie un fichier Word, Excel ou PowerPoint, ouvrir automatiquement son aperçu en direct." - }, - "SkillPacksSettings": { - "title": "Packs de compétences", - "description": "Ensembles de compétences sélectionnés que codeg gère de manière centralisée et relie à vos agents IA : experts en programmation, recherche scientifique et outils de documents bureautiques. Activez-les par agent ci-dessous.", - "tabs": { - "experts": "Experts", - "science": "Science", - "office": "Outils bureautiques", - "custom": "Personnalisées" - }, - "actions": { - "openCentralDir": "Ouvrir le dossier central", - "refresh": "Actualiser" - }, - "toasts": { - "openFolderFailed": "Échec de l'ouverture du dossier" - } - }, - "QuickMessagesSettings": { - "title": "Messages rapides", - "description": "Gérez des extraits de messages réutilisables. Glissez pour réorganiser.", - "loading": "Chargement des messages rapides…", - "emptyList": "Aucun message rapide. Cliquez sur « Nouveau » pour en créer un.", - "emptySelection": "Sélectionnez un message rapide à modifier.", - "searchPlaceholder": "Rechercher par titre ou contenu", - "untitled": "Sans titre", - "actions": { - "new": "Nouveau", - "save": "Enregistrer", - "delete": "Supprimer", - "dragSort": "Glisser pour réorganiser", - "dragSortMessage": "Réorganiser le message rapide : {name}" - }, - "fields": { - "title": "Titre", - "titlePlaceholder": "Donnez un titre court à ce message", - "content": "Contenu", - "contentPlaceholder": "Saisissez ici le contenu du message" - }, - "confirmDelete": { - "title": "Supprimer le message rapide ?", - "message": "Cela supprimera définitivement « {name} ». Êtes-vous sûr ?", - "cancel": "Annuler", - "confirm": "Supprimer" - }, - "toasts": { - "loadFailed": "Échec du chargement des messages rapides", - "createFailed": "Échec de la création du message rapide", - "saveFailed": "Échec de l'enregistrement du message rapide", - "deleteFailed": "Échec de la suppression du message rapide", - "saveOrderFailed": "Échec de l'enregistrement de l'ordre", - "created": "Message rapide créé", - "saved": "Message rapide enregistré", - "deleted": "Message rapide supprimé" - } - }, - "Pet": { - "badge": { - "running": "{count} en cours", - "waiting": "{count} en attente d'approbation", - "error": "{count} en erreur" - }, - "panel": { - "title": "Sessions actives", - "empty": "Aucune session active", - "emptyHint": "Les agents en cours et ceux qui vous attendent apparaissent ici.", - "statusRunning": "En cours", - "statusWaiting": "En attente", - "statusError": "Erreur", - "subAgentOf": "Sous-agent de" - }, - "menu": { - "scale": "Échelle", - "openManager": "Gérer les mascottes", - "close": "Fermer" - }, - "loadError": "Échec du chargement de la mascotte", - "missingPetIdParam": "Aucune mascotte sélectionnée", - "summonButton": "Mascotte", - "manager": { - "title": "Mascottes", - "description": "Compagnons flottants de bureau avec des sprites compatibles Codex.", - "addPet": "Ajouter une mascotte", - "importFromCodex": "Importer depuis Codex", - "noPets": "Aucune mascotte. Ajoutez-en ou importez depuis Codex.", - "setActive": "Activer", - "active": "Active", - "edit": "Modifier", - "delete": "Supprimer", - "deleteConfirm": "Supprimer la mascotte « {name} » ? Elle sera retirée du disque.", - "summon": "Invoquer la fenêtre de la mascotte", - "openCodexHelp": "Les mascottes Codex doivent être dans ~/.codex/pets/. Aucune trouvée.", - "specRequirement": "Le sprite doit faire 1536px de large avec une hauteur multiple de 208px (par ex. 1872 ou 2288), en PNG/WebP avec transparence.", - "form": { - "id": "ID mascotte", - "idHelp": "Lettres minuscules, chiffres, '-' et '_'. Max 64 caractères.", - "displayName": "Nom affiché", - "description": "Description (facultative)", - "spritesheet": "Sprite", - "chooseFile": "Choisir un fichier", - "replaceFile": "Remplacer le sprite", - "saveCreate": "Ajouter la mascotte", - "saveUpdate": "Enregistrer", - "cancel": "Annuler" - }, - "errors": { - "missingId": "ID requis", - "missingName": "Nom requis", - "missingSpritesheet": "Sprite requis", - "addFailed": "Ajout impossible", - "updateFailed": "Mise à jour impossible", - "deleteFailed": "Suppression impossible", - "loadFailed": "Chargement impossible", - "setActiveFailed": "Activation impossible", - "summonFailed": "Ouverture de la fenêtre impossible" - } - }, - "import": { - "title": "Importer depuis Codex", - "subtitle": "Mascottes disponibles sous ~/.codex/pets/.", - "selectAll": "Tout sélectionner", - "alreadyImported": "Déjà importée", - "renameOnConflict": "Renommer en -imported en cas de conflit", - "import": "Importer la sélection", - "noneFound": "Aucune mascotte Codex importable.", - "imported": "Import réussi", - "failed": "Import échoué", - "close": "Fermer" - }, - "marketplace": { - "openMarketplace": "Marketplace de mascottes", - "title": "Marketplace de mascottes", - "search": "Rechercher des mascottes", - "kindFilter": { - "all": "Toutes", - "object": "Objet", - "animal": "Animal", - "person": "Personne", - "creature": "Créature" - }, - "sortFilter": { - "latest": "Récents", - "popular": "Populaires", - "views": "Vues" - }, - "refresh": "Actualiser", - "install": "Installer", - "installing": "Installation", - "reinstall": "Réinstaller", - "reinstallConfirm": "Remplacer la mascotte locale « {name} » ? Les données existantes seront écrasées.", - "cancel": "Annuler", - "stats": { - "views": "Vues", - "downloads": "Téléchargements", - "likes": "J’aime" - }, - "actions": { - "idle": "Repos", - "running_right": "Course dr.", - "running_left": "Course g.", - "waving": "Salut", - "jumping": "Saut", - "failed": "Échec", - "waiting": "Attente", - "running": "Course", - "review": "Revue" - }, - "page": "Page {page} sur {total}", - "prev": "Précédent", - "next": "Suivant", - "empty": "Aucune mascotte ne correspond.", - "successInstalled": "« {name} » installée", - "errors": { - "loadFailed": "Impossible de charger le marketplace", - "installFailed": "Échec de l’installation", - "alreadyInstalled": "La mascotte existe déjà localement" - } - } - }, - "RemoteWorkspace": { - "openRemoteWorkspace": "Ouvrir l’espace de travail distant", - "manage": "Gérer l’espace de travail distant", - "manageTitle": "Connexions à l’espace de travail distant", - "empty": "Aucune connexion distante", - "searchPlaceholder": "Rechercher un espace de travail distant", - "orderFailed": "Échec de l’enregistrement de l’ordre des espaces de travail distants", - "dragSort": "Glisser pour trier", - "dragSortConnection": "Glisser pour trier {name}", - "newConnection": "Nouvelle connexion", - "loading": "Chargement", - "loadingConnection": "Chargement de la connexion distante", - "name": "Nom", - "baseUrl": "URL du service", - "token": "Jeton d’accès", - "save": "Enregistrer", - "delete": "Supprimer", - "confirmDelete": { - "title": "Supprimer la connexion distante ?", - "message": "Cela retirera « {name} » de cet appareil. Cette action est irréversible.", - "cancel": "Annuler", - "confirm": "Supprimer" - }, - "saved": "Connexion distante enregistrée.", - "deleted": "Connexion distante supprimée.", - "loadFailed": "Échec du chargement des connexions distantes", - "saveFailed": "Échec de l’enregistrement de la connexion distante", - "deleteFailed": "Échec de la suppression de la connexion distante", - "openFailed": "Échec de l’ouverture de l’espace de travail distant", - "connectionLoadFailed": "Échec du chargement de la connexion distante : {message}", - "connectionExpired": "La connexion distante « {name} » a expiré. Mettez son jeton à jour, puis rechargez cette fenêtre." - }, - "ServerFileBrowser": { - "title": "Sélectionner un fichier serveur", - "pathPlaceholder": "Saisir le chemin du dossier...", - "goHome": "Aller au dossier personnel", - "navigateUp": "Aller au dossier parent", - "select": "Sélectionner", - "cancel": "Annuler", - "loading": "Chargement...", - "emptyDirectory": "Ce dossier est vide", - "errorLoadingDir": "Échec du chargement du dossier", - "selectedCount": "{count} sélectionné(s)" - }, - "BackupSettings": { - "title": "Sauvegarde et restauration", - "description": "Exportez une sauvegarde portable de vos données codeg, ou restaurez à partir d'une sauvegarde.", - "tabs": { - "backup": "Sauvegarde", - "restore": "Restauration" - }, - "export": { - "includeExternal": "Inclure le contenu des conversations", - "includeExternalHint": "Archive aussi les transcriptions des CLI (Claude, Codex, Gemini, …). Augmente la taille.", - "passphrase": "Phrase secrète (facultatif)", - "passphrasePlaceholder": "Laissez vide pour une archive non chiffrée", - "passphraseConfirm": "Confirmer la phrase secrète", - "passphraseMismatch": "Les phrases secrètes ne correspondent pas.", - "noPassphraseWarning": "Cette sauvegarde contiendra des secrets (clés d'API, jetons) en clair. Conservez-la en lieu sûr.", - "passphraseLossWarning": "Chiffrée avec cette phrase secrète. Si vous la perdez, la sauvegarde ne pourra pas être récupérée.", - "button": "Exporter la sauvegarde", - "inProgress": "Création de la sauvegarde…", - "success": "Sauvegarde créée.", - "started": "Téléchargement de la sauvegarde lancé." - }, - "restore": { - "selectFile": "Sélectionner le fichier de sauvegarde", - "passphrasePrompt": "Cette sauvegarde est chiffrée. Saisissez sa phrase secrète.", - "unlock": "Déverrouiller", - "preview": { - "title": "Détails de la sauvegarde", - "encrypted": "Chiffrée", - "compatible": "Compatible", - "incompatible": "Incompatible", - "createdAt": "Créée : {value}", - "appVersion": "Version de l'app : {value}", - "incompatibleHint": "Cette sauvegarde a été créée par une version plus récente de codeg et ne peut pas être restaurée." - }, - "replaceWarning": "La restauration remplace toutes les données codeg actuelles (base de données et téléversements). Vos données actuelles sont d'abord sauvegardées en instantané pour pouvoir être récupérées.", - "keyringNote": "Les jetons GitHub/chat du bureau sont dans le trousseau du système et ne sont pas inclus ; ressaisissez-les après la restauration.", - "button": "Restaurer", - "staging": "Préparation de la restauration…", - "staged": "Restauration préparée. Redémarrage…", - "restarting": "Restauration préparée. Redémarrage du serveur…", - "restartTimeout": "Le serveur n'est pas revenu à temps. Rechargez la page une fois qu'il est actif.", - "externalSideLocation": "Les transcriptions de conversations ont été restaurées dans {path}", - "confirmTitle": "Remplacer toutes les données ?", - "confirmBody": "Cela remplacera votre base de données et vos téléversements codeg actuels par la sauvegarde, puis redémarrera. Vos données actuelles sont d'abord sauvegardées en instantané.", - "cancel": "Annuler", - "confirmAction": "Remplacer et redémarrer", - "external": { - "title": "Contenu des conversations", - "hint": "Cette sauvegarde inclut des transcriptions des CLI. Choisissez où les restaurer.", - "modeSkip": "Ne pas restaurer", - "modeSide": "Restaurer dans un dossier annexe sûr", - "modeOriginal": "Restaurer aux emplacements d'origine des CLI", - "forceOverwrite": "Écraser les fichiers existants", - "forceOverwriteHint": "Remplace les fichiers déjà présents dans les dossiers des CLI.", - "scanning": "Vérification des conflits…", - "noConflicts": "Aucun fichier existant ne sera écrasé.", - "conflictCount": "{count} fichier(s) existant(s) seraient concerné(s).", - "conflictSkipNote": "Les fichiers existants sont conservés (ignorés) sauf si vous activez l'écrasement." - }, - "restartFailed": "Restauration préparée, mais le serveur n'a pas pu redémarrer. Redémarrez-le manuellement pour l'appliquer." - }, - "remoteUnsupported": "La sauvegarde et la restauration agissent sur les données de la machine qui exécute codeg. Vous êtes connecté à un espace de travail distant : gérez ses sauvegardes directement depuis ce serveur." - }, - "backup": { - "restore": { - "error": { - "badPassphrase": "Phrase secrète incorrecte ou sauvegarde corrompue.", - "corrupted": "L'archive de sauvegarde est corrompue.", - "unknownFormat": "Ce fichier n'est pas une sauvegarde codeg reconnue.", - "newerVersion": "Cette sauvegarde a été créée par codeg {backupVersion}, plus récent que cette version ({appVersion}).", - "alreadyPending": "Une restauration est déjà préparée. Redémarrez pour l'appliquer avant d'en préparer une autre." - } - }, - "error": { - "diskSpace": "Espace disque insuffisant pour terminer l'opération.", - "cancelled": "L'opération a été annulée." - } - }, - "WebConnection": { - "disconnectedTitle": "Connexion perdue", - "reconnectingDescription": "Tentative de reconnexion au serveur. Cela se rétablit généralement tout seul en quelques secondes.", - "reconnectNow": "Se reconnecter maintenant", - "sessionExpiredTitle": "Session expirée", - "sessionExpiredDescription": "Votre session n'est plus valide. Veuillez vous reconnecter pour continuer.", - "goToLogin": "Aller à la connexion" - }, - "LiveFeedback": { - "placeholder": "Envoyez une note à {agent} pendant qu'il travaille…", - "agentFallback": "l'agent", - "ariaLabel": "Note de retour en direct", - "dialogTitle": "Retour en direct", - "dialogDescription": "Envoyez une note à l'agent pendant qu'il travaille. Il la lira lors de sa prochaine vérification, sans interrompre l'étape en cours.", - "dialogDescriptionInstant": "Envoyez une note à l'agent pendant qu'il travaille. Elle est insérée immédiatement dans le tour en cours — l'agent la voit aussitôt.", - "channelDowngraded": "L'insertion instantanée n'est pas disponible dans cette session — votre note a été enregistrée et sera récupérée au prochain contrôle de l'agent.", - "send": "Envoyer", - "cancel": "Annuler", - "pending": "en attente", - "delivered": "reçue", - "turnEndedUnread": "L'agent a terminé avant de lire votre retour.", - "sendAsMessage": "Envoyer comme message", - "dismiss": "Ignorer", - "turnEndedResent": "Le tour est terminé : envoyé comme nouveau message.", - "turnEnded": "Le tour est déjà terminé.", - "submitFailed": "Impossible d'envoyer votre note" - }, - "AgentToolsSettings": { - "title": "Outils dans la conversation", - "description": "Outils supplémentaires que codeg fournit à un agent au sein d'une conversation. Ils sont injectés au démarrage de l'agent : une modification s'applique donc aux agents démarrés ensuite.", - "feedbackLabel": "Retour en direct", - "feedbackHint": "Envoyez des notes et corrections à un agent pendant qu'il travaille. Si l'agent prend en charge l'insertion instantanée, votre note est insérée immédiatement dans le tour en cours ; sinon, l'agent reçoit un outil pour consulter vos retours — ces agents ne le consultent généralement que si vous le mentionnez dans votre prompt, par exemple ajoutez « vérifie régulièrement mon feedback en direct » à votre message.", - "questionLabel": "Poser une question à l'utilisateur", - "questionHint": "Permet aux agents de s'interrompre et de vous poser une question à choix multiples affichée au-dessus de la zone de saisie de la conversation. L'agent attend votre réponse (ou que vous ignoriez).", - "sessionInfoLabel": "Obtenir les infos de session", - "sessionInfoHint": "Permet aux agents de consulter une session que vous mentionnez dans votre message (un badge de session) pour lire son titre, son agent, son statut, son espace de travail, sa consommation de jetons et ses messages récents.", - "automationsLabel": "Créer des automatisations", - "automationsHint": "Enregistre la conversation comme une automatisation qui s'exécute selon un planning. Désactivé par défaut : elle démarre ensuite des agents d'elle-même.", - "workTasksLabel": "Créer des tâches à faire", - "workTasksHint": "Ajoute une carte au tableau des tâches depuis la conversation. Désactivé par défaut : écrit l'état de l'application.", - "save": "Enregistrer", - "saving": "Enregistrement…", - "saved": "Paramètres des outils enregistrés", - "saveFailed": "Échec de l'enregistrement des paramètres des outils", - "loadFailed": "Échec du chargement : {detail}" - }, - "NotificationSoundSettings": { - "title": "Sons de notification", - "description": "Joue un son bref lorsqu’un événement d’agent se produit. Ce sont les mêmes événements que ceux envoyés aux canaux de discussion ; ce réglage ne s’applique qu’à cet appareil.", - "enableHint": "Désactivé par défaut. Les sons ne sont joués que dans la fenêtre de l’espace de travail de ce navigateur ou de cette application.", - "volume": "Volume", - "preview": "Écouter", - "previewEvent": "Écouter le son de {event}", - "onlyWhenUnfocused": "Uniquement lorsque la fenêtre n’est pas au premier plan", - "onlyWhenUnfocusedHint": "Reste silencieux tant que Codeg est affiché.", - "eventsTitle": "Événements", - "eventsHint": "Choisissez un son par événement, ou « Silencieux » pour l’ignorer. Si le même événement se répète en quelques secondes, il ne sonne qu’une fois.", - "toneNone": "Silencieux", - "toneChime": "Carillon", - "toneDing": "Clochette", - "toneBlip": "Bip", - "tonePop": "Pop", - "toneAlert": "Alerte", - "toneDescend": "Descendant" - }, - "LogsSettings": { - "loading": "Chargement…", - "sectionTitle": "Journaux d'exécution", - "sectionDescription": "Consultez et configurez les journaux de diagnostic de l'application. Les journaux sont écrits dans des fichiers locaux et conservés en mémoire pour l'affichage en direct.", - "captureTitle": "Niveau de journalisation", - "captureDescription": "Contrôle le niveau de détail capturé. Les niveaux plus élevés (Debug, Trace) enregistrent davantage mais produisent des journaux plus volumineux. « Désactivé » désactive la journalisation.", - "captureLabel": "Niveau de capture", - "levels": { - "off": "Désactivé", - "error": "Erreur", - "warn": "Avertissement", - "info": "Info", - "debug": "Débogage", - "trace": "Trace" - }, - "viewerTitle": "Journaux récents", - "viewerDescription": "Affichage en direct des journaux récents. Filtrez par niveau ou recherchez du texte.", - "searchPlaceholder": "Rechercher un message ou une cible…", - "viewLevels": { - "all": "Tous les niveaux", - "error": "Erreur et plus", - "warn": "Avertissement et plus", - "info": "Info et plus", - "debug": "Débogage et plus", - "trace": "Trace et plus" - }, - "pause": "Pause", - "resume": "Direct", - "refresh": "Actualiser", - "clear": "Effacer", - "openFolder": "Ouvrir le dossier", - "shownCount": "{shown} / {total} affichés", - "empty": "Aucun journal à afficher.", - "levelSaveFailed": "Échec de l'enregistrement du niveau de journalisation", - "openFolderFailed": "Échec de l'ouverture du dossier des journaux", - "downloadFailed": "Échec du téléchargement du fichier journal", - "filesTitle": "Fichiers journaux", - "filesDescription": "Téléchargez les fichiers journaux complets depuis le disque pour l'historique au-delà du tampon en direct.", - "filesEmpty": "Aucun fichier journal pour l'instant.", - "download": "Télécharger", - "downloadTruncated": "Le fichier est volumineux ; les {size} les plus récents ont été téléchargés. Le fichier complet se trouve dans le répertoire des journaux.", - "captureEnvLocked": "Le niveau de journalisation est contrôlé par la variable d'environnement RUST_LOG / CODEG_LOG ; modifiez-la là pour qu'elle prenne effet.", - "targetsTitle": "Remplacements par module", - "targetsDescription": "Définissez un niveau différent pour des modules spécifiques (p. ex. codeg_lib::acp) sans changer le niveau global.", - "targetsAdd": "Ajouter", - "targetsRemove": "Supprimer le remplacement", - "toggleDetails": "Afficher les détails" - }, - "Automations": { - "title": "Automatisations", - "new": "Nouvelle automatisation", - "empty": "Aucune automatisation pour l'instant", - "emptyHint": "Créez-en une pour exécuter une tâche d'agent planifiée ou à la demande.", - "name": "Nom", - "namePlaceholder": "ex. Revue de PR nocturne", - "prompt": "Instruction", - "promptPlaceholder": "Que doit faire l'agent ?", - "agent": "Agent", - "folder": "Dossier de l'espace de travail", - "folderPlaceholder": "Sélectionner un dossier", - "isolation": "Isolation", - "isolationWorktree": "Nouveau worktree par exécution", - "isolationShared": "Exécuter dans le dossier", - "isolationSharedCaveat": "Les exécutions utilisent directement l'arbre de travail de ce dossier et peuvent entrer en conflit avec vos modifications non validées. Activez l'option worktree pour isoler chaque exécution.", - "trigger": "Déclencheur", - "triggerSchedule": "Planifié", - "triggerManual": "Manuel uniquement", - "cron": "Planification (cron)", - "cronPlaceholder": "0 9 * * 1-5", - "timezone": "Fuseau horaire", - "nextRun": "Prochaine exécution", - "branch": "Branche", - "branchOptional": "Branche (facultatif)", - "enabled": "Activé", - "save": "Enregistrer", - "cancel": "Annuler", - "edit": "Modifier", - "delete": "Supprimer", - "runNow": "Exécuter maintenant", - "cancelRun": "Annuler l'exécution", - "runHistory": "Historique d'exécution", - "noRuns": "Aucune exécution pour l'instant", - "allFolders": "Tous les dossiers", - "filterAll": "Tous", - "noMatches": "Aucune automatisation correspondante", - "viewConversation": "Voir la conversation", - "lastRun": "Dernière exécution", - "never": "Jamais", - "running": "En cours", - "deleteTitle": "Supprimer l'automatisation ?", - "deleteDescription": "Cela supprime l'automatisation et sa planification. L'historique est conservé.", - "statusRunning": "En cours", - "statusSucceeded": "Réussie", - "statusFailed": "Échouée", - "statusCancelled": "Annulée", - "statusSkipped": "Ignorée", - "errorName": "Le nom est requis", - "errorPrompt": "L'instruction est requise", - "errorCron": "Les automatisations planifiées nécessitent une expression cron", - "errorFolder": "Sélectionnez un dossier d'espace de travail", - "presetHourly": "Toutes les heures", - "presetDaily": "Tous les jours 9 h", - "presetWeekdays": "En semaine 9 h", - "presetCustom": "Personnalisé", - "probing": "Chargement des options…", - "retry": "Réessayer", - "configNone": "Cet agent n'a aucune option configurable", - "inherit": "Par défaut de l'agent", - "mode": "Mode", - "config": "Configuration", - "branchPlaceholder": "(branche par défaut)", - "selectHint": "Sélectionnez une automatisation pour voir les détails", - "refresh": "Actualiser", - "onboardTitle": "Automatisez les tâches récurrentes de l'agent", - "onboardHint": "Planifiez un agent pour relire le code, mettre à jour les dépendances ou trier les problèmes, de façon périodique ou à la demande.", - "headerSubtitle": "Tâches d'agent planifiées et à la demande", - "startFromTemplate": "Partir d'un modèle", - "blankTitle": "Automatisation vierge", - "blankDesc": "Configurez une tâche d'agent à partir de zéro.", - "backToTemplates": "Modèles", - "sectionSchedule": "Planification et cible", - "sectionTarget": "Cible", - "sectionAction": "Action", - "actionLaunchSession": "Lancer une session", - "actionEnqueueTask": "Mettre une tâche en file", - "actionEnqueueTaskHint": "Chaque déclenchement ajoute une tâche à faire, nommée d'après cette automatisation, aux tâches à faire du dossier ; le moteur de tâches l'exécute selon les réglages du tableau.", - "sectionPrompt": "Instruction", - "nextIn": "Prochaine dans {rel}", - "manual": "Manuel", - "schedEveryMinutes": "Toutes les {n} minutes", - "schedHourly": "Toutes les heures", - "schedDaily": "Tous les jours à {time}", - "schedWeekdays": "En semaine à {time}", - "schedWeekly": "Chaque {day} à {time}", - "schedMonthly": "Le {day} de chaque mois à {time}", - "dow0": "dimanche", - "dow1": "lundi", - "dow2": "mardi", - "dow3": "mercredi", - "dow4": "jeudi", - "dow5": "vendredi", - "dow6": "samedi", - "tplCodeReviewTitle": "Revue de code", - "tplCodeReviewDesc": "Examine les modifications récentes à la recherche de bugs, de régressions et de problèmes de qualité.", - "tplDependencyUpdatesTitle": "Mise à jour des dépendances", - "tplDependencyUpdatesDesc": "Repère les dépendances obsolètes et propose des mises à niveau sûres.", - "tplTestCoverageTitle": "Couverture de tests", - "tplTestCoverageDesc": "Repère les chemins de code non testés et ajoute les tests manquants.", - "tplTodoSweepTitle": "Revue des TODO", - "tplTodoSweepDesc": "Rassemble les commentaires TODO et FIXME et les trie par priorité.", - "tplCiTriageTitle": "Tri CI", - "tplCiTriageDesc": "Enquête sur les vérifications récemment en échec et propose des correctifs.", - "tplReleaseNotesTitle": "Notes de version", - "tplReleaseNotesDesc": "Résume les changements depuis la dernière version dans un journal des modifications.", - "tplSecurityAuditTitle": "Audit de sécurité", - "tplSecurityAuditDesc": "Recherche les vulnérabilités et les schémas à risque, puis signale les constats.", - "enable": "Activer", - "disable": "Désactiver", - "moreActions": "Plus d'actions", - "statusDisabled": "Désactivée", - "cronBuilderTitle": "Générateur de planification", - "cronFreqLabel": "Fréquence", - "cronFreqMinutes": "Toutes les N minutes", - "cronFreqHourly": "Toutes les heures", - "cronFreqDaily": "Quotidien", - "cronFreqWeekdays": "Jours ouvrés", - "cronFreqWeekly": "Hebdomadaire", - "cronFreqMonthly": "Mensuel", - "cronFreqCustom": "Personnalisé", - "cronEveryLabel": "Intervalle (minutes)", - "cronTimeLabel": "Heure", - "cronHourLabel": "Heure", - "cronMinuteLabel": "Minute", - "cronDowLabel": "Jour de la semaine", - "cronDomLabel": "Jour du mois", - "cronApply": "Appliquer", - "cronPreviewLabel": "Aperçu", - "cronOpenBuilder": "Ouvrir le générateur de planification", - "branchDefault": "Branche par défaut", - "branchUseCustom": "Utiliser « {query} »", - "branchLocal": "Locale", - "branchRemote": "Distante", - "branchSearchPlaceholder": "Rechercher des branches…", - "branchNone": "Aucune branche" - }, - "Tasks": { - "title": "Tâches à faire", - "new": "Nouvelle tâche", - "empty": "Aucune tâche pour l’instant", - "emptyHint": "Ajoutez une tâche puis lancez-la : l’agent travaille dans un worktree isolé, vous relisez et fusionnez le résultat.", - "emptyColTodo": "Aucune tâche à faire pour l’instant", - "emptyColInProgress": "Rien en cours", - "emptyColAttention": "Rien à traiter", - "emptyColDone": "Rien de terminé pour l’instant", - "allFolders": "Tous les dossiers", - "showCanceled": "Afficher les annulées", - "showArchived": "Afficher les archivées", - "filter": "Filtrer", - "viewSwitchToBoard": "Passer à la vue tableau", - "viewSwitchToList": "Passer à la vue liste", - "statusFilter": "Statut", - "statusFilterAll": "Tous les statuts", - "listEmpty": "Aucune tâche ne correspond aux filtres actuels", - "listColStatus": "Statut", - "listColTask": "Tâche", - "listColLocation": "Emplacement", - "listColChanges": "Modifications", - "listColUpdated": "Mis à jour", - "colTodo": "À faire", - "colInProgress": "En cours", - "colAttention": "À traiter", - "colDone": "Terminées", - "statusTodo": "À faire", - "statusQueued": "En file", - "statusPreparing": "Préparation", - "statusRunning": "En cours", - "statusAwaitingInput": "En attente de saisie", - "statusReview": "À valider", - "statusMerging": "Fusion en cours", - "statusDone": "Terminée", - "statusFailed": "Échouée", - "statusCanceled": "Annulée", - "statusInterrupted": "Interrompue", - "badgeCleanupFailed": "Nettoyage échoué", - "badgeWorktreeKept": "Worktree conservé", - "badgeWorktreeRemoved": "Worktree supprimé", - "filesChanged": "{count} fichiers", - "actionStart": "Démarrer", - "actionSchedule": "Planifier", - "actionCancel": "Annuler", - "actionRetry": "Réessayer", - "actionRequeue": "Remettre en file", - "actionViewSession": "Voir la conversation", - "actionEdit": "Modifier", - "actionDelete": "Supprimer", - "actionRetryCleanup": "Réessayer le nettoyage", - "actionMerge": "Fusionner", - "actionUnqueueMerge": "Quitter la file de fusion", - "actionEditQueuedMerge": "Modifier la fusion en attente", - "badgeMergeQueued": "En attente de fusion", - "badgeMergeQueuedRank": "En attente de fusion · n° {rank}", - "badgeMergeQueuedHint": "En attente de la fin de la fusion en cours du projet ; celle-ci démarrera toute seule.", - "actionComplete": "Terminer", - "actionAbandon": "Abandonner", - "cancelTitle": "Annuler la tâche ?", - "cancelDescription": "La tâche passe à Annulée. Son worktree est conservé et vous pourrez la remettre en file plus tard.", - "cancelReasonLabel": "Raison (facultatif)", - "cancelReasonPlaceholder": "Ex. : mauvaise approche, je vais réécrire la description", - "cancelKeep": "Finalement non", - "cancelSubmit": "Annuler la tâche", - "restartTitleRetry": "Réessayer la tâche", - "restartTitleRequeue": "Remettre la tâche en file", - "restartDescription": "Vous pouvez ajouter une note (facultatif) : elle arrive dans le prompt de la prochaine exécution.", - "scheduleTitle": "Planifier la tâche", - "scheduleDescription": "La tâche reste dans À faire et démarre d'elle-même à l'heure choisie. La limite de concurrence du dossier s'applique toujours.", - "scheduleDateLabel": "Date", - "schedulePickDate": "Choisir une date", - "scheduleTimeLabel": "Heure", - "schedulePreview": "S'exécute le {time}", - "schedulePastHint": "Cette heure est déjà passée : la tâche démarrera dès l'enregistrement.", - "scheduleInAnHour": "Dans 1 heure", - "scheduleInThreeHours": "Dans 3 heures", - "scheduleTomorrow": "Demain 9:00", - "scheduleClear": "Annuler la planification", - "scheduleBadge": "Démarrage prévu le {time}", - "toastScheduled": "Planifiée pour le {time}", - "toastScheduleCleared": "Planification annulée", - "actionFollowUp": "Poursuivre", - "actionAddNote": "Ajouter une note", - "followUpSubmit": "Envoyer", - "followUpIntentRevise": "Corriger", - "followUpIntentContinue": "Continuer", - "followUpIntentQuestion": "Demander", - "followUpIntentVerify": "Vérifier", - "followUpPlaceholderRevise": "Que doit changer l'agent ? Il poursuit dans la même session.", - "followUpPlaceholderContinue": "Et ensuite ? Le travail déjà fait reste en place.", - "followUpPlaceholderQuestion": "Que voulez-vous savoir ? L'agent répond sans toucher aux fichiers.", - "followUpPlaceholderVerify": "Facultatif : quelque chose à examiner de près ?", - "followUpPlaceholderRetry": "Facultatif : que faire différemment ? Ex. : lancer pnpm install d'abord", - "followUpPlaceholderRequeue": "Facultatif : pourquoi l'avoir annulée, et qu'est-ce qui doit changer ?", - "actionArchive": "Archiver", - "actionUnarchive": "Désarchiver", - "archiveAllDone": "Tout archiver", - "dropToStart": "Relâchez pour lancer", - "errorView": "Voir", - "notifyReview": "Prêt pour révision : {title}", - "notifyFailed": "La tâche a échoué : {title}", - "createFromMessage": "Créer une tâche depuis le message", - "detailTokens": "Total de tokens", - "editorTitleNew": "Nouvelle tâche", - "editorTitleEdit": "Modifier la tâche", - "templates": "Modèles", - "templatesEmpty": "Aucun modèle pour l'instant.", - "templateSaveCurrent": "Enregistrer comme modèle", - "templateDelete": "Supprimer le modèle", - "transcriptTitle": "Conversation de la tâche", - "transcriptDescription": "Vue en direct, en lecture seule, de la session de l'agent de la tâche.", - "phaseWork": "Exécution", - "phaseRetry": "Nouvel essai", - "phaseReturn": "Relance", - "phaseMerge": "Fusion", - "titleLabel": "Titre", - "titlePlaceholder": "Que faut-il faire ?", - "promptLabel": "Description de la tâche", - "promptPlaceholder": "Décrivez la tâche pour l’agent — @ pour référencer des fichiers, / pour les commandes", - "folderPlaceholder": "Choisir un dossier", - "agentInheritedHint": "Hérité des réglages des tâches — modifiez-le pour personnaliser cette tâche", - "agentOverrideReset": "Revenir à l'héritage", - "sectionTarget": "Cible", - "errorTitle": "Le titre est requis", - "errorPrompt": "La description est requise", - "errorFolder": "Choisissez un dossier", - "save": "Enregistrer", - "cancel": "Annuler", - "mergeTitle": "Fusionner la tâche", - "mergeQueuedTitle": "Fusion en attente", - "mergeQueueHint": "Une autre tâche de ce projet est en cours de fusion. Celle-ci rejoint la file et démarrera d'elle-même dès que l'autre sera terminée.", - "mergeQueueUpdateHint": "Cette tâche attend déjà de fusionner. L'envoi la met à jour et conserve sa place dans la file.", - "mergeDescription": "Fusionner {branch} dans {base}. Les changements non commités du worktree sont d’abord commités.", - "mergeMessage": "Message de commit", - "mergeMessagePlaceholder": "ex. feat: add login validation", - "mergeAutoMessage": "Laisser l'agent rédiger le message de commit", - "strategySquash": "Regrouper en un seul commit", - "strategySquashHint": "Toutes les modifications de la tâche arrivent dans la branche principale comme une seule entrée d'historique — un historique plus net.", - "strategyMerge": "Conserver tout l'historique", - "strategyMergeHint": "Chaque commit réalisé pendant la tâche est conservé, plus une entrée de fusion — chaque étape reste traçable.", - "mergeDeleteWorktree": "Supprimer le worktree après la fusion", - "mergeSubmit": "Fusionner", - "mergeSubmitQueue": "Ajouter à la file", - "mergeQueuedToast": "Ajoutée à la file de fusion — elle démarrera dès la fin de la fusion en cours.", - "completeTitle": "Terminer la tâche", - "completeDescription": "Cette tâche n'a modifié aucun fichier : il n'y a rien à fusionner, elle est marquée comme terminée directement.", - "completeDescriptionNoWorktree": "Le worktree de cette tâche a été supprimé : plus rien ne peut être fusionné, elle est marquée comme terminée directement. Une branche de travail contenant encore des commits non fusionnés est conservée.", - "completeDeleteWorktree": "Supprimer le worktree après avoir terminé", - "completeSubmit": "Terminer", - "settingsTitle": "Réglages des tâches", - "settingsDescription": "Valeurs par défaut des tâches de {folder}.", - "settingsScope": "Portée", - "settingsScopeGlobal": "Tous les dossiers (valeurs globales)", - "settingsScopeGlobalHint": "Les dossiers sans réglages propres utilisent ces valeurs globales.", - "settingsSource": "Source de configuration", - "settingsSourceGlobal": "Valeurs globales", - "settingsSourceCustom": "Personnalisée", - "settingsSourceGlobalFollow": "Suit les réglages globaux des tâches — les changements globaux s'appliquent ici automatiquement.", - "settingsSourceCustomHint": "Enregistre des réglages propres à ce dossier, qui ne suit plus les valeurs globales.", - "settingsAgent": "Agent par défaut", - "settingsMaxConcurrent": "Tâches simultanées max.", - "settingsMaxConcurrentHint": "0 = illimité", - "settingsAutoProcess": "Traiter automatiquement", - "settingsAutoProcessHint": "Les tâches à faire démarrent seules, dans la limite de concurrence.", - "settingsMergeStrategy": "Stratégie de fusion par défaut", - "settingsMergeStrategyHint": "Comment les modifications de la tâche sont consignées dans l'historique de la branche lors de la fusion.", - "settingsAutoMerge": "Fusionner automatiquement", - "settingsAutoMergeHint": "Une tâche qui arrive en revue avec des changements à intégrer est fusionnée comme si vous cliquiez sur Fusionner : l'agent rédige le message de commit et le worktree suit le réglage par défaut ci-dessous. Si la pré-vérification échoue ou qu'une fusion a échoué, la tâche vous attend.", - "settingsDeleteWorktree": "Supprimer le worktree après la fusion", - "settingsDeleteWorktreeHint": "Coche l’option par défaut dans la boîte de dialogue de fusion ; elle reste modifiable.", - "settingsWorktreeRoot": "Emplacement du worktree", - "settingsWorktreeRootHint": "Répertoire dans lequel les worktrees des nouvelles tâches sont créés, un par tâche. Laissez vide pour les créer à côté du dossier du projet ; « ~ » désigne votre dossier personnel et un chemin relatif est résolu depuis le dossier du projet.", - "settingsWorktreeRootPlaceholder": "~/codeg-worktrees", - "settingsWorktreeRootBrowse": "Choisir le répertoire des worktrees", - "settingsPreflight": "Commande de pré-vérification", - "settingsPreflightHint": "S'exécute dans le worktree quand une tâche passe en revue.", - "settingsPreflightCustomPlaceholder": "pnpm test", - "settingsInitCommand": "Commande d'initialisation du worktree", - "settingsInitCommandHint": "Exécutée dans un worktree fraîchement créé avant le démarrage de l'agent.", - "settingsInitCommandPlaceholder": "pnpm install", - "settingsTabGeneral": "Général", - "settingsTabMerge": "Fusion", - "settingsTabWorktree": "Worktree", - "settingsTabPrompts": "Instructions", - "settingsPromptsIntro": "Chaque étape envoie déjà son propre prompt intégré : la tâche, les règles du worktree et, pour la fusion, les étapes git exactes. Ce que vous ajoutez ici est apposé à la fin comme instructions supplémentaires : cela affine ces textes intégrés, sans jamais les remplacer.", - "settingsPromptStageAll": "Toutes les phases", - "settingsPromptPlaceholderAll": "ex. Respecte les conventions d’AGENTS.md ; limite le résumé final à deux phrases", - "settingsPromptPlaceholderWork": "ex. Lis d’abord les tests concernés ; fais des commits petits et fréquents", - "settingsPromptPlaceholderRetry": "ex. Vérifie ce qui est déjà commité avant de continuer ; ne refais pas le travail terminé", - "settingsPromptPlaceholderReturn": "Ex. : Traitez chaque point soulevé ; ne refactorisez rien d'autre", - "settingsPromptPlaceholderMerge": "ex. Rédige le message du commit d’intégration en français ; signale les conflits résolus à la main", - "settingsPromptHintAll": "Ajouté à chaque prompt reçu par l'agent, fusion comprise.", - "settingsPromptHintWork": "Ajouté lors de la première exécution d'une tâche.", - "settingsPromptHintRetry": "Ajouté lorsqu'une tâche interrompue ou en échec est reprise.", - "settingsPromptHintReturn": "Ajouté quand vous relancez une tâche en revue (correction, ajout, vérification).", - "settingsPromptHintMerge": "Ajouté lorsque l'agent intègre la tâche dans la branche de base.", - "preflightPassed": "{name} réussie", - "preflightFailed": "{name} échouée", - "preflightRunning": "{name} en cours…", - "detailDescription": "Détail de la tâche", - "detailSummary": "Résultat", - "detailFiles": "Fichiers modifiés", - "detailDiffAll": "Voir tout le diff", - "detailDiffAllTitle": "Diff complet", - "detailNoChanges": "Aucun changement par rapport à la base", - "detailTimeline": "Progression", - "detailTimelineEmpty": "Aucune activité pour l’instant", - "showMore": "Afficher plus", - "showLess": "Afficher moins", - "detailInfo": "Détails", - "detailBranch": "Branche", - "detailMergeCommit": "Commit de fusion", - "detailChanges": "Modifications", - "detailScheduled": "Démarrage prévu", - "detailCreated": "Créée", - "detailStarted": "Démarrée", - "detailFinished": "Terminée", - "diffLoading": "Chargement du diff…", - "deleteConfirmTitle": "Supprimer la tâche ?", - "deleteConfirmBody": "« {title} » sera retirée du tableau. Une exécution active est d’abord annulée.", - "deleteWithWorktree": "Supprimer aussi son worktree", - "eventCreated": "Créée", - "eventStatusChanged": "Changement d’état", - "eventConfigEffective": "Configuration de lancement", - "eventInitCommand": "Commande d'initialisation", - "eventAgentProgress": "Progression de l’agent", - "eventAgentVerdict": "Verdict de l’agent", - "eventMergeAttempt": "Fusion démarrée", - "eventMergeQueued": "Mise en file de fusion", - "eventMergeConflict": "Conflit de fusion", - "eventPreflight": "Pré-vérification", - "eventCleanupFailed": "Échec du nettoyage du worktree", - "eventResumeFallback": "Reprise échouée, nouvelle session utilisée", - "eventUserAction": "Action utilisateur", - "eventDiffStat": "Instantané des changements" - }, - "CustomSkillsSettings": { - "loading": "Chargement des compétences personnalisées…", - "category": "Personnalisées", - "searchPlaceholder": "Rechercher des compétences personnalisées par nom, ID ou description", - "states": { - "not_linked": "Non activée", - "linked_to_codeg": "Activée", - "linked_elsewhere": "Liée ailleurs", - "blocked_by_real_directory": "Bloquée par un dossier réel", - "broken": "Lien rompu" - }, - "actions": { - "new": "Nouvelle", - "import": "Importer", - "importFromAgent": "Importer depuis un agent", - "cancel": "Annuler", - "save": "Enregistrer" - }, - "rowMenu": { - "edit": "Modifier", - "duplicate": "Dupliquer", - "delete": "Supprimer" - }, - "bulk": { - "delete": "Supprimer la sélection" - }, - "editor": { - "createTitle": "Nouvelle compétence personnalisée", - "editTitle": "Modifier la compétence personnalisée", - "description": "Les compétences personnalisées sont stockées dans le magasin partagé (~/.codeg/skills) et peuvent être activées pour n'importe quel agent.", - "idLabel": "ID de la compétence", - "idPlaceholder": "ex. my-workflow", - "contentLabel": "SKILL.md", - "contentPlaceholder": "Rédigez ici le SKILL.md de la compétence…", - "preview": "Aperçu", - "edit": "Modifier", - "emptyBody": "Aucun contenu pour le moment." - }, - "duplicate": { - "title": "Dupliquer la compétence", - "description": "Créer une copie de « {id} » avec un nouvel ID.", - "newIdPlaceholder": "Nouvel ID de compétence", - "confirm": "Dupliquer" - }, - "import": { - "title": "Choisir un dossier de compétence à importer" - }, - "importFromAgent": { - "title": "Importer des compétences depuis un agent", - "description": "Copiez les compétences propres à un agent dans le magasin partagé pour les activer sur n'importe quel agent.", - "agentLabel": "Agent", - "agentPlaceholder": "Sélectionner un agent", - "selectAll": "Tout sélectionner ({count})", - "loading": "Chargement des compétences de l'agent…", - "unsupported": "Cet agent n'expose pas de répertoire de compétences.", - "empty": "Cet agent n'a aucune compétence à importer.", - "alreadyInLibrary": "Dans la bibliothèque", - "confirm": "Importer la sélection ({count})" - }, - "delete": { - "title": "Supprimer les compétences personnalisées ?", - "body": "Cela retire {count} compétence(s) personnalisée(s) du magasin central et les dissocie de tous les agents. Action irréversible.", - "confirm": "Supprimer" - }, - "toasts": { - "loadFailed": "Échec du chargement de la compétence", - "idRequired": "Veuillez saisir un ID de compétence", - "created": "Compétence personnalisée créée", - "updated": "Compétence personnalisée mise à jour", - "saveFailed": "Échec de l'enregistrement de la compétence", - "imported": "Compétence importée", - "importFailed": "Échec de l'importation de la compétence", - "duplicated": "Compétence dupliquée", - "duplicateFailed": "Échec de la duplication de la compétence", - "deleted": "{count} compétence(s) supprimée(s)", - "deletedPartial": "{ok} supprimée(s), {failed} en échec", - "deleteFailed": "Échec de la suppression des compétences", - "importedFromAgent": "{count} compétence(s) importée(s)", - "importedFromAgentPartial": "{ok} importée(s), {failed} en échec", - "importFromAgentAllSkipped": "Rien à importer — {count} déjà dans la bibliothèque", - "importFromAgentFailed": "Échec de l'import depuis l'agent" - } - }, - "CodexModelEditor": { - "customizedNotice": "Vous avez personnalisé la liste des modèles, codeg gère donc désormais toute la table des modèles de codex. Les modèles officiels que codex ajoutera plus tard n'apparaîtront pas automatiquement : cliquez sur le bouton actualiser ci-dessous puis enregistrez à nouveau pour les synchroniser. Effacez vos personnalisations pour laisser codex se mettre à jour automatiquement.", - "officialsTitle": "Modèles officiels", - "officialsHint": "Inclus automatiquement depuis le codex que vous lancez ; supprimez ceux dont vous ne voulez pas.", - "officialsEmpty": "Aucun modèle officiel disponible.", - "refresh": "Actualiser depuis codex", - "readdOfficial": "Rajouter un officiel", - "customsTitle": "Modèles personnalisés", - "customsEmpty": "Aucun modèle personnalisé pour l'instant.", - "addCustom": "Ajouter personnalisé", - "slugPlaceholder": "id du modèle (slug)", - "displayNamePlaceholder": "Nom affiché", - "contextWindow": "Contexte", - "makeDefault": "Définir par défaut", - "defaultHint": "Modèle par défaut", - "remove": "Supprimer", - "advanced": "Avancé", - "baseTemplate": "Modèle de base", - "baseTemplateHint": "Modèle officiel à partir duquel cloner les champs requis (invite système, outils, limites).", - "groupBehavior": "Comportement et capacités", - "fieldReasoningLevel": "Raisonnement par défaut", - "fieldReasoningSummary": "Résumé du raisonnement", - "fieldVerbosity": "Verbosité", - "fieldShellType": "Type de shell", - "fieldApplyPatch": "Outil apply-patch", - "fieldReasoningSummaries": "Résumés de raisonnement", - "fieldSupportVerbosity": "Contrôle de la verbosité", - "fieldParallelToolCalls": "Appels d'outils en parallèle", - "fieldSearchTool": "Outil de recherche web", - "optNone": "Aucun", - "groupInstructions": "Description et prompt système", - "fieldDescription": "Description", - "baseInstructions": "Invite système (base_instructions)" - }, - "DiagnosticsSettings": { - "title": "Diagnostic de l'environnement", - "description": "Vérifie comment cette app résout la CLI de l'agent dans son propre processus, ce qui peut différer de votre terminal.", - "loading": "Diagnostic en cours…", - "error": "Échec du diagnostic", - "rerun": "Relancer", - "copyAll": "Tout copier", - "copied": "Diagnostic copié dans le presse-papiers", - "button": "Diagnostiquer", - "verdict": { - "ok": "L'environnement semble sain. S'il indique toujours non installé, redémarrez complètement l'app pour actualiser le cache du préfixe.", - "node_missing": "Node.js est introuvable dans le PATH de l'app.", - "npm_missing": "npm est introuvable dans le PATH de l'app.", - "not_installed": "Cet agent ne semble pas installé.", - "installed_but_unresolved": "Enregistré comme installé, mais l'app ne trouve pas son exécutable.", - "user_prefix_not_on_path": "Installé dans le préfixe de secours (~/.codeg/npm-global), qui n'est pas dans le PATH de l'app. Redémarrez complètement l'app et réessayez.", - "homebrew_bin_not_on_path": "Installé sous le bin de Homebrew, qui n'est pas dans le PATH de l'app (séparation keg Apple Silicon).", - "terminal_only_path": "La commande se résout dans votre terminal mais pas dans l'app : un écart de PATH GUI. Lancez l'app depuis un terminal ou réinstallez depuis les Paramètres des agents.", - "npm_prefix_timeout": "npm prefix -g était trop lent (plus de 1,5 s), la détection de secours a été ignorée. Redémarrez l'app et réessayez.", - "node_too_old": "Votre Node.js actif est plus ancien que ce que cet agent requiert. Mettez à niveau Node.js.", - "adapter_missing_native_present": "Votre CLI {agent} est bien installée, mais Codeg lance un paquet adaptateur ACP distinct, et celui-ci ne l'est pas encore. Installez-le depuis les paramètres des agents : il ne touche pas à votre CLI et partage la même connexion.", - "adapter_missing": "Codeg lance un paquet adaptateur ACP distinct pour {agent}, et il n'est pas encore installé. Installez-le depuis les paramètres des agents — installer seulement la CLI de l'éditeur ne suffit pas." - } - }, - "TokenUsage": { - "title": "Consommation de tokens", - "rangeLabel": "Période", - "range7d": "7 jours", - "range30d": "30 jours", - "range90d": "90 jours", - "rangeThisMonth": "Ce mois-ci", - "rangeThisYear": "Cette année", - "rangeAll": "Tout", - "rangeCustom": "Personnalisée", - "moreRanges": "Plus", - "customRangePick": "Choisir une période", - "bucketLabel": "Regrouper par", - "bucketDay": "Jour", - "bucketWeek": "Semaine", - "bucketMonth": "Mois", - "bucketUnitDay": "Jour", - "bucketUnitWeek": "Semaine", - "bucketUnitMonth": "Mois", - "folderFilter": "Dossiers", - "allFolders": "Tous les dossiers", - "agentFilter": "Agents", - "allAgents": "Tous les agents", - "modelFilter": "Modèles", - "allModels": "Tous les modèles", - "searchPlaceholder": "Rechercher…", - "noMatches": "Aucun résultat", - "clearFilter": "Effacer la sélection", - "resetFilters": "Réinitialiser les filtres", - "refresh": "Actualiser", - "rebuild": "Tout reconstruire", - "rebuildHint": "Efface les données comptées et relit toutes les transcriptions. Utile si une session a grandi hors de codeg.", - "syncing": "Comptage des sessions…", - "syncProgress": "{done} / {total}", - "syncDone": "{synced} sessions comptées", - "syncFailed": "Certaines sessions n'ont pas pu être lues", - "syncBusy": "Une actualisation est déjà en cours", - "lastSynced": "Mis à jour {time}", - "lastSyncedNever": "Jamais mis à jour", - "tileTotal": "Tokens au total", - "tileSessions": "Sessions", - "tileTurns": "Tours", - "tileActiveDays": "Jours actifs", - "tileGenTime": "Temps de génération", - "vsPrevious": "vs période précédente", - "deltaNew": "nouveau", - "trendTitle": "Consommation dans le temps", - "trendEmpty": "Aucune consommation sur cette période", - "trendTurns": "Tours", - "trendSessions": "Sessions", - "compositionTitle": "À quoi sont partis les tokens", - "compositionHint": "L'entrée est ce que vous avez envoyé, la sortie ce que le modèle a écrit, et les lectures de cache du contexte non refacturé au prix fort.", - "compositionNote": "Renvoyer ces lectures de cache au prix fort aurait coûté {value} de plus.", - "inputTokens": "Entrée", - "outputTokens": "Sortie", - "cacheWrite": "Écriture cache", - "cacheRead": "Lecture cache", - "freshTokens": "Calcul frais", - "cacheHitCaption": "Taux de cache", - "cacheHeroTitleHigh": "L'essentiel du contexte n'a pas été renvoyé", - "cacheHeroTitleLow": "L'essentiel du contexte se calcule encore au prix fort", - "cacheHeroDesc": "Le cache a porté {cached} de contexte ; seuls {fresh} ont été réellement recalculés sur la période.", - "cacheSavedSuffix": "Soit l'équivalent de {saved} de renvois économisés.", - "avgPerSession": "Moy. par session", - "avgTurnsPerSession": "{count} tours par session en moyenne", - "avgPerActiveDay": "Moy. par jour actif", - "peakBucket": "{bucket} le plus chargé", - "peakHour": "Heure de pointe", - "daysValue": "{count} jours", - "idleDays": "Jours sans activité", - "byFolderTitle": "Par dossier", - "byAgentTitle": "Par agent", - "byModelTitle": "Par modèle", - "distributionTitle": "Répartition de l'usage", - "distributionHint": "Sessions et tokens regroupés selon la dimension choisie — cliquez sur une ligne pour filtrer.", - "otherLabel": "Autres", - "unknownModel": "Modèle non renseigné", - "emptyBreakdown": "Rien d'enregistré", - "sessionsCount": "{count} sessions", - "heatmapTitle": "Quand vous codez", - "heatmapHint": "Tokens par jour de la semaine et heure locale.", - "heatmapPeakHint": "Le plus dense autour de {hour}:00.", - "less": "Moins", - "more": "Plus", - "heatmapCell": "{weekday} {hour}:00 — {value} tokens", - "weekMon": "Lun", - "weekTue": "Mar", - "weekWed": "Mer", - "weekThu": "Jeu", - "weekFri": "Ven", - "weekSat": "Sam", - "weekSun": "Dim", - "topSessionsTitle": "Sessions les plus gourmandes", - "untitledSession": "Session sans titre", - "topSessionsEmpty": "Aucune session sur cette période", - "streakLongest": "Plus longue série", - "streakLongestDays": "Plus longue série : {count} jours", - "share": "Partager", - "moreActions": "Autres actions", - "shareDialogTitle": "Partagez votre carte de consommation", - "shareDialogHint": "Un instantané de la période et des filtres affichés.", - "shareSave": "Enregistrer l'image", - "shareCopy": "Copier l'image", - "shareCopied": "Copié dans le presse-papiers", - "shareSaved": "Image enregistrée", - "shareFailed": "Impossible de créer l'image", - "shareRendering": "Génération…", - "cardHeading": "Mon bilan de code assisté par IA", - "cardRangeAll": "Depuis le début", - "cardTotalLabel": "Tokens consommés", - "cardFooter": "Réalisé avec codeg", - "cardTopModels": "Modèles principaux", - "cardTopProjects": "Projets principaux", - "archetypeNightOwl": "Oiseau de nuit", - "archetypeNightOwlDesc": "{percent}% de vos tokens brûlent après la tombée de la nuit.", - "archetypeEarlyBird": "Lève-tôt", - "archetypeEarlyBirdDesc": "{percent}% de vos tokens tombent avant 9 h.", - "archetypeWeekendWarrior": "Guerrier du week-end", - "archetypeWeekendWarriorDesc": "{percent}% de vos tokens arrivent le week-end.", - "archetypeCacheMaster": "Maître du cache", - "archetypeCacheMasterDesc": "{percent}% de votre contexte venait du cache.", - "archetypeMarathoner": "Marathonien", - "archetypeMarathonerDesc": "{days} jours de code sans interruption.", - "archetypePolyglot": "Polyvalent", - "archetypePolyglotDesc": "{count} agents utilisés sérieusement.", - "archetypeLaserFocus": "Focus laser", - "archetypeLaserFocusDesc": "{percent}% de vos tokens sur un seul projet.", - "archetypeDeepDiver": "Plongeur", - "archetypeDeepDiverDesc": "{averageK}K tokens par session en moyenne.", - "archetypeSteady": "Bâtisseur régulier", - "archetypeSteadyDesc": "{days} jours de livraison.", - "emptyTitle": "Rien de compté pour l'instant", - "emptyHint": "Codeg lit les tokens directement dans la transcription de chaque agent. Actualisez pour compter ce qui est déjà sur cette machine.", - "emptyAction": "Compter mes sessions", - "loadFailed": "Impossible de charger la consommation", - "truncatedNotice": "Cette période est très large — les chiffres ne couvrent que sa portion la plus récente." - } -} +{ + "Language": { + "followSystem": "Suivre le système", + "english": "Anglais", + "simplifiedChinese": "Chinois simplifié", + "traditionalChinese": "Chinois traditionnel", + "japanese": "Japonais", + "korean": "Coréen", + "spanish": "Espagnol", + "german": "Allemand", + "french": "Français", + "portuguese": "Portugais", + "arabic": "Arabe" + }, + "GitCredentialDialog": { + "title": "Authentification requise", + "description": "Le serveur distant nécessite des identifiants. Entrez votre nom d'utilisateur et votre mot de passe (ou jeton d'accès personnel).", + "username": "Nom d'utilisateur", + "usernamePlaceholder": "Nom d'utilisateur ou e-mail", + "password": "Mot de passe / Jeton", + "passwordPlaceholder": "Mot de passe ou jeton d'accès personnel", + "passwordHint": "Entrez le nom d'utilisateur et le mot de passe du serveur.", + "cancel": "Annuler", + "authenticate": "Authentifier", + "authenticating": "Authentification...", + "invalidCredentials": "Identifiants invalides. Veuillez réessayer.", + "saveCredentials": "Enregistrer les identifiants pour les opérations futures", + "githubTitle": "Authentification GitHub", + "githubDescription": "Entrez un jeton d'accès personnel pour vous connecter à GitHub. Le jeton sera validé et enregistré automatiquement.", + "githubToken": "Jeton d'accès personnel", + "githubTokenPlaceholder": "ghp_xxxxxxxxxxxx", + "githubTokenHint": "Générez un jeton dans GitHub → Settings → Developer settings → Personal access tokens.", + "githubAuthenticate": "Valider et connecter", + "generateToken": "Générer un jeton" + }, + "SettingsShell": { + "title": "Paramètres", + "preferences": "Préférences", + "nav": { + "general": "Général", + "appearance": "Apparence", + "agents": "Agents IA", + "mcp": "MCP", + "skills": "Skills", + "shortcuts": "Raccourcis", + "version_control": "Contrôle de version", + "system": "Système", + "chat_channels": "Canaux de chat", + "web_service": "Service Web", + "model_providers": "Fournisseurs de Modèles", + "experts": "Experts", + "science": "Science", + "office_tools": "Outils bureautiques", + "skill_packs": "Packs de compétences", + "quick_messages": "Messages rapides", + "logs": "Journaux d'exécution" + } + }, + "AppearanceSettings": { + "sectionTitle": "Apparence du thème", + "sectionDescription": "Choisissez clair, sombre ou suivre le système. Les paramètres sont enregistrés automatiquement.", + "themeMode": "Mode du thème", + "placeholder": "Sélectionner le mode du thème", + "system": "Suivre le système", + "light": "Clair", + "dark": "Sombre", + "currentTheme": "Thème effectif actuel : {theme}", + "resolvedTheme": { + "light": "Clair", + "dark": "Sombre", + "unknown": "--" + }, + "themeColor": { + "sectionTitle": "Couleur du thème", + "sectionDescription": "Choisissez une palette pour les accents, les boutons et les surlignages.", + "current": "Couleur actuelle : {color}", + "options": { + "neutral": "Neutre", + "zinc": "Zinc", + "slate": "Ardoise", + "stone": "Pierre", + "gray": "Gris", + "red": "Rouge", + "rose": "Rose", + "orange": "Orange", + "green": "Vert", + "blue": "Bleu", + "yellow": "Jaune", + "violet": "Violet" + } + }, + "customStyle": { + "sectionTitle": "Style personnalisé", + "sectionDescription": "Ajustez les couleurs du thème actuel ou injectez votre propre CSS. Les remplacements se superposent au préréglage de base et sont conservés lorsque vous en changez.", + "summarySuspended": "Suspendu", + "summaryDefault": "Préréglage inchangé", + "summaryTokens": "{count, plural, one {# remplacement} other {# remplacements}}", + "summaryCss": "CSS personnalisé", + "suspendedByShortcut": "Le style personnalisé est suspendu. Rien de ce que vous réglez ici ne s'appliquera tant que vous ne l'aurez pas réactivé.", + "suspendedBySafeParam": "Cette fenêtre a été ouverte en mode d'apparence sûre : le style personnalisé y est ignoré. Les autres fenêtres ne sont pas affectées.", + "resume": "Réactiver le style personnalisé", + "enableTheme": "Activer les couleurs personnalisées", + "editingLight": "Vous modifiez les valeurs du mode clair. Passez l'application en mode sombre pour le régler séparément.", + "editingDark": "Vous modifiez les valeurs du mode sombre. Passez l'application en mode clair pour le régler séparément.", + "resetToken": "Rétablir la valeur du préréglage", + "radius": "Rayon des coins", + "radiusHint": "Toute l'échelle de rayons, de sm à 4xl, en découle : un seul curseur arrondit l'application entière.", + "advanced": "Avancé ({count} variables de plus)", + "enableCss": "Activer le CSS personnalisé", + "cssRisk": "Fonction avancée. Le CSS personnalisé remplace tous les styles intégrés et peut rendre l'interface inutilisable.", + "editCss": "Modifier le CSS…", + "cssPresent": "{size} Ko enregistrés", + "cssEmpty": "Rien d'enregistré pour l'instant", + "escapeHint": "Interface cassée ? Appuyez sur {shortcut} pour suspendre tout le style personnalisé, ou ouvrez une fenêtre avec le paramètre safeStyle=1.", + "copyTheme": "Copier le JSON du thème", + "importTheme": "Importer un thème…", + "clearTheme": "Effacer les remplacements", + "interopHint": "Les thèmes utilisent le format registry:theme de shadcn : collez ici n'importe quel thème shadcn, et réutilisez les vôtres dans n'importe quel projet shadcn.", + "importTitle": "Importer un thème", + "importDescription": "Collez un élément registry:theme de shadcn, un simple objet light/dark, ou une table de tokens à plat.", + "readClipboard": "Lire le presse-papiers", + "importConfirm": "Importer", + "cancel": "Annuler", + "apply": "Appliquer", + "toasts": { + "copied": "JSON du thème copié", + "copyFailed": "Impossible de copier dans le presse-papiers", + "clipboardReadFailed": "Impossible de lire le presse-papiers, collez manuellement", + "importFailed": "Ce JSON ne contient aucune variable de thème utilisable", + "imported": "Thème importé" + }, + "css": { + "dialogTitle": "CSS personnalisé", + "dialogDescription": "S'applique à toutes les fenêtres codeg. Les modifications sont prévisualisées en direct ; cliquez sur Appliquer pour enregistrer.", + "size": "{used} Ko / {max} Ko", + "ruleCount": "{count} règles", + "errorTooLarge": "Trop volumineux pour être enregistré. Réduisez-le sous la limite.", + "errorImportEscaped": "Une règle @import a survécu au retrait (syntaxe échappée). Supprimez-la pour enregistrer.", + "warnNoRules": "Aucune règle analysée, vérifiez la syntaxe.", + "noticeImportsRemoved": "Règles @import supprimées : {count}. Elles chargeraient des feuilles de style distantes.", + "noticeRemoteUrl": "Contient une url() distante, qui déclenchera une requête réseau une fois appliquée.", + "noticePreviewSuspended": "Le style personnalisé est suspendu, cet aperçu n'est donc pas appliqué.", + "noticeDisabled": "Le CSS personnalisé est désactivé. Vous pouvez prévisualiser ici, mais rien ne s'appliquera avant activation.", + "hintTokens": "Astuce : vos couleurs remplacées sont accessibles via var(--primary), var(--background), etc." + } + }, + "zoomLevel": { + "sectionTitle": "Zoom de la fenêtre", + "sectionDescription": "Met à l'échelle toute l'interface. S'applique immédiatement et est enregistré par appareil.", + "placeholder": "Sélectionnez le niveau de zoom", + "default": "Par défaut", + "current": "Zoom actuel : {zoom}%" + }, + "fonts": { + "sectionTitle": "Polices", + "sectionDescription": "Choisissez les polices pour l’interface, l’éditeur de code et le terminal. Les polices intégrées sont chargées à la demande ; sélectionnez « Personnalisée… » pour utiliser n’importe quelle police installée sur votre système.", + "interface": "Interface", + "editor": "Éditeur", + "terminal": "Terminal", + "groupSans": "Sans empattement", + "groupMono": "Monospace", + "custom": "Personnalisée…", + "customPlaceholder": "Nom de la police, par ex. Fira Code", + "fontSize": "Taille de police", + "ligatures": "Activer les ligatures", + "ligaturesUnavailable": "Cette police n’a pas de ligatures", + "wordWrap": "Activer le retour à la ligne", + "terminalLigaturesHint": "Les ligatures du terminal ne s’appliquent qu’aux polices de programmation intégrées.", + "preview": "Aperçu" + }, + "welcomePanel": { + "sectionTitle": "Zone de sélection du mode", + "sectionDescription": "Les cartes de raccourci « Développement / Bureautique » affichées au-dessus du champ de saisie sur la page de nouvelle conversation.", + "showQuickActions": "Afficher sur la page de nouvelle conversation" + }, + "workspaceBackground": { + "sectionTitle": "Arrière-plan de l'espace de travail", + "sectionDescription": "Affiche une image derrière tout l'espace de travail. La barre latérale et les panneaux deviennent translucides et dépolis pour laisser transparaître l'image, et un masque préserve la lisibilité du texte.", + "enable": "Activer l'image d'arrière-plan", + "image": "Image", + "chooseImage": "Choisir une image", + "replaceImage": "Remplacer l'image", + "removeImage": "Supprimer", + "fillMode": "Mode de remplissage", + "fillModes": { + "cover": "Remplir", + "contain": "Ajuster", + "center": "Centrer", + "tile": "Mosaïque" + }, + "maskOpacity": "Opacité du masque", + "maskOpacityHint": "Des valeurs élevées fondent l'image vers la couleur d'arrière-plan du thème, améliorant le contraste du texte.", + "imageBlur": "Flou de l'image", + "panelOpacity": "Opacité des panneaux", + "panelOpacityHint": "Opacité de la barre latérale, des panneaux et des barres d'onglets. Plus c'est bas, plus l'image transparaît.", + "errorTooLarge": "L'image est trop volumineuse (16 Mo maximum).", + "errorUploadFailed": "Échec de la définition de l'image d'arrière-plan." + } + }, + "SystemSettings": { + "loading": "Chargement...", + "sectionTitle": "Gestion du système", + "sectionDescription": "Gérez le proxy réseau, les mises à jour de l’app et les préférences de langue.", + "proxyTitle": "Proxy réseau", + "proxyDescription": "Lorsqu’il est activé, les requêtes réseau suivantes utilisent ce proxy en priorité (y compris le chat ACP, l’installation d’agents et les opérations Git distantes).", + "loadFailed": "Échec du chargement : {message}", + "enableProxy": "Activer le proxy système", + "proxyAddress": "Adresse du proxy", + "proxyHint": "Prend en charge http(s)/socks5, exemple : {example}. Actif uniquement lorsque le proxy système est activé.", + "save": "Enregistrer", + "saving": "Enregistrement...", + "proxyRequired": "L’URL du proxy est requise lorsque le proxy est activé", + "saveSuccess": "Les paramètres du proxy système ont été enregistrés", + "saveFailed": "Échec de l’enregistrement : {message}", + "languageTitle": "Langue", + "languageDescription": "Définissez la langue de l’app. En mode système, les langues non prises en charge reviennent à l’anglais.", + "appLanguage": "Langue de l’app", + "languageSaveSuccess": "Les paramètres de langue ont été enregistrés", + "languageSaveFailed": "Échec de l’enregistrement des paramètres de langue : {message}", + "updateTitle": "Mise à jour de l’app", + "versionTitle": "Mise à jour logicielle", + "updateDescription": "Vérifiez les nouvelles versions depuis la source de publication configurée et installez-les directement si disponibles.", + "currentVersion": "Version actuelle", + "upgradableVersion": "Dernière version", + "none": "Aucune", + "lastChecked": "Dernière vérification : {time}", + "updateError": "Erreur de mise à jour : {message}", + "checking": "Vérification...", + "checkUpdate": "Rechercher les mises à jour", + "updating": "Installation...", + "downloading": "Téléchargement...", + "upgradeTo": "Mettre à jour vers v{version}", + "viewRelease": "Voir la version v{version}", + "foundUpdate": "Nouvelle version v{version} trouvée", + "alreadyLatest": "Vous utilisez déjà la dernière version", + "checkUpdateFailed": "Échec de la recherche de mises à jour : {message}", + "installSuccess": "Mise à jour installée. Redémarrage de l’app.", + "installFailed": "Échec de la mise à jour : {message}", + "upgradeSuccess": "Mise à niveau terminée. Rechargement...", + "restartTimeout": "Le serveur n'est pas revenu à temps. Consultez les journaux du conteneur ou du service.", + "restartingIn": "Redémarrage dans {seconds} s...", + "waitingForServer": "En attente du retour du serveur...", + "restartToUpdate": "Redémarrer pour mettre à jour", + "newVersionBadge": "Nouveau v{version}", + "updateAvailableTitle": "Mise à jour disponible", + "releaseNotesTitle": "Nouveautés", + "remindLater": "Plus tard", + "retry": "Réessayer", + "stepDownload": "Téléchargement", + "stepInstall": "Installation", + "stepRestart": "Redémarrage", + "updateReadyHint": "Mise à jour téléchargée — redémarrez pour l'appliquer.", + "restarting": "Redémarrage...", + "dockerUpgradeHint": "Cela met à jour le conteneur en cours d'exécution. La mise à jour est perdue si le conteneur est recréé — pour la conserver, récupérez ou créez une image à la nouvelle version puis recréez le conteneur.", + "upgradeRolledBack": "Échec de la mise à niveau ; le serveur est revenu à la version précédente.", + "serverUnreachable": "Impossible de joindre le serveur pour démarrer la mise à niveau. Vérifiez qu'il fonctionne et réessayez.", + "rollbackButton": "Revenir en arrière", + "rollingBack": "Restauration...", + "rollbackDescription": "Restaure la version installée avant la dernière mise à niveau.", + "rollbackConfirmTitle": "Revenir à la version précédente ?", + "rollbackConfirmDescription": "Le serveur redémarrera sur la version installée avant la dernière mise à niveau. Une version plus récente reste disponible à la réinstallation.", + "rollbackConfirm": "Revenir en arrière", + "rollbackCancel": "Annuler", + "rollbackSuccess": "Retour à la version précédente. Rechargement...", + "rollbackFailed": "Échec du retour en arrière. Consultez les journaux du serveur.", + "updateErrors": { + "sourceUnavailable": "Impossible d’atteindre la source de mise à jour. Vérifiez votre réseau ou proxy et réessayez.", + "network": "La connexion réseau a échoué. Vérifiez votre réseau ou proxy et réessayez.", + "downloadFailed": "Impossible de télécharger le paquet de mise à jour. Veuillez réessayer plus tard.", + "installFailed": "Impossible d’installer la mise à jour. Fermez l’app puis réessayez.", + "unknown": "La mise à jour a échoué. Veuillez réessayer plus tard." + } + }, + "VersionControlSettings": { + "loading": "Chargement...", + "sectionTitle": "Contrôle de version", + "sectionDescription": "Configurez l'exécutable Git et gérez les comptes GitHub.", + "gitTitle": "Configuration Git", + "gitDescription": "Configurez l'exécutable Git utilisé par l'application.", + "gitDetected": "Git détecté", + "gitNotFound": "Git introuvable sur le système", + "gitVersion": "Version", + "gitPath": "Chemin", + "customGitPath": "Chemin Git personnalisé", + "customGitPathPlaceholder": "/usr/bin/git", + "customGitPathHint": "Laissez vide pour utiliser le chemin détecté automatiquement.", + "test": "Tester", + "testing": "Test en cours...", + "testSuccess": "L'exécutable Git est valide.", + "testFailed": "Test Git échoué : {message}", + "save": "Enregistrer", + "saving": "Enregistrement...", + "saveSuccess": "Paramètres Git enregistrés.", + "saveFailed": "Échec de l'enregistrement : {message}", + "githubTitle": "Comptes GitHub", + "githubDescription": "Gérez les comptes GitHub pour l'authentification. Les jetons sont stockés localement.", + "noAccounts": "Aucun compte GitHub configuré.", + "addAccount": "Ajouter un compte", + "serverUrl": "URL du serveur", + "serverUrlPlaceholder": "https://github.com", + "token": "Jeton d'accès personnel", + "tokenPlaceholder": "ghp_xxxxxxxxxxxx", + "generateToken": "Générer un jeton", + "tokenHint": "Générez un jeton dans GitHub → Settings → Developer settings → Personal access tokens.", + "validateAndAdd": "Valider et ajouter", + "validating": "Validation...", + "addSuccess": "Compte {username} ajouté avec succès.", + "addFailed": "Échec de l'ajout du compte : {message}", + "testConnection": "Tester", + "connectionSuccess": "Connexion réussie.", + "connectionFailed": "Échec de la connexion : {message}", + "setDefault": "Définir par défaut", + "defaultLabel": "Par défaut", + "defaultSet": "Compte par défaut mis à jour.", + "removeAccount": "Supprimer", + "removeConfirmTitle": "Supprimer le compte", + "removeConfirmMessage": "Êtes-vous sûr de vouloir supprimer le compte « {username} » ?", + "removeConfirm": "Supprimer", + "removeCancel": "Annuler", + "removeSuccess": "Compte supprimé.", + "scopes": "Portées", + "loadFailed": "Échec du chargement des paramètres : {message}", + "gitAccount": { + "sectionTitle": "Comptes serveur Git", + "sectionDescription": "Gérez les identifiants pour les serveurs Git non GitHub (GitLab, Bitbucket, auto-hébergé, etc.).", + "noAccounts": "Aucun compte de serveur Git configuré.", + "addAccount": "Ajouter un compte", + "addTitle": "Ajouter un compte Git", + "addDescription": "Entrez l'adresse du serveur, le nom d'utilisateur et le mot de passe ou jeton d'accès.", + "serverUrl": "URL du serveur", + "serverUrlPlaceholder": "https://gitlab.example.com", + "username": "Nom d'utilisateur", + "usernamePlaceholder": "Nom d'utilisateur ou e-mail", + "password": "Mot de passe / Jeton", + "passwordPlaceholder": "Mot de passe ou jeton d'accès", + "passwordHint": "Entrez le mot de passe ou le jeton d'accès du serveur.", + "add": "Ajouter", + "serverRequired": "L'URL du serveur est requise.", + "usernameRequired": "Le nom d'utilisateur est requis.", + "passwordRequired": "Le mot de passe est requis." + } + }, + "ShortcutSettings": { + "sectionTitle": "Raccourcis", + "resetDefault": "Rétablir les valeurs par défaut", + "recordInstruction": "Cliquez sur le bouton à droite, puis appuyez sur une combinaison de touches. Utilisez Ctrl/Cmd, Alt et Shift. Appuyez sur Échap pour annuler l’enregistrement.", + "recording": "Appuyez sur un raccourci...", + "toasts": { + "conflict": "Le raccourci est déjà utilisé par \"{title}\"", + "updated": "Raccourci mis à jour", + "invalid": "Raccourci invalide, veuillez réessayer", + "reset": "Les raccourcis par défaut ont été restaurés" + }, + "actions": { + "toggle_search": { + "title": "Ouvrir la recherche", + "description": "Afficher ou masquer le panneau de recherche de conversations" + }, + "toggle_sidebar": { + "title": "Basculer la barre latérale gauche", + "description": "Afficher ou masquer la barre latérale de liste des conversations" + }, + "toggle_terminal": { + "title": "Basculer le terminal", + "description": "Afficher ou masquer le panneau terminal inférieur" + }, + "new_terminal_tab": { + "title": "Nouveau terminal", + "description": "Créer un nouvel onglet terminal lorsque le terminal a le focus" + }, + "close_current_terminal_tab": { + "title": "Fermer le terminal actuel", + "description": "Fermer l’onglet terminal actuel lorsque le terminal a le focus" + }, + "toggle_aux_panel": { + "title": "Basculer le panneau droit", + "description": "Afficher ou masquer le panneau d’informations auxiliaires" + }, + "new_conversation": { + "title": "Nouvelle conversation", + "description": "Créer un nouvel onglet de conversation dans le dossier actuel" + }, + "open_folder": { + "title": "Ouvrir un dossier", + "description": "Ouvrir le sélecteur de dossier et ouvrir dans une nouvelle fenêtre" + }, + "open_settings": { + "title": "Ouvrir les paramètres", + "description": "Ouvrir la fenêtre des paramètres" + }, + "close_current_tab": { + "title": "Fermer l’onglet actuel", + "description": "Fermer la conversation actuelle ou l’onglet de fichier" + }, + "close_all_file_tabs": { + "title": "Fermer tous les onglets de fichiers", + "description": "Fermer tous les onglets de fichiers ouverts lorsque le panneau de fichiers est actif" + }, + "next_tab": { + "title": "Onglet suivant", + "description": "Passer à l'onglet de conversation ou de fichier suivant" + }, + "prev_tab": { + "title": "Onglet précédent", + "description": "Passer à l'onglet de conversation ou de fichier précédent" + }, + "send_message": { + "title": "Envoyer le message", + "description": "Envoyer le message actuel dans la zone de saisie" + }, + "newline_in_message": { + "title": "Retour à la ligne", + "description": "Insérer un retour à la ligne dans la zone de saisie" + }, + "toggle_custom_style": { + "title": "Suspendre/réactiver le style personnalisé", + "description": "Issue de secours : désactive toutes les couleurs et le CSS personnalisés, puis les réactive" + } + } + }, + "SkillsSettings": { + "title": "Skills", + "description": "Sélectionnez une Skill à gauche. À droite, un aperçu Markdown s’affiche par défaut ; passez en édition pour modifier et enregistrer.", + "loadingAgents": "Chargement des agents qui prennent en charge les Skills...", + "emptyNoManageableAgents": "Aucun agent disponible pour la gestion des Skills.", + "managedTarget": "Cible gérée", + "selectAgentPlaceholder": "Sélectionnez un agent", + "searchPlaceholder": "Rechercher par nom / ID / chemin...", + "skillsList": "Liste des Skills", + "loadingSkills": "Chargement des Skills...", + "agentNotSupported": "L’agent actuel ne prend pas en charge la gestion des Skills.", + "emptySkills": "Aucune Skill pour le moment. Cliquez sur « Nouvelle Skill » pour en créer une.", + "newSkillTitle": "Nouvelle Skill", + "skillInfo": "Infos de la Skill", + "skillIdPlaceholder": "skill-id (lettres/chiffres/-/_/.)", + "skillsDirectoryWithPath": "Répertoire des Skills : {path}", + "skillsDirectoryNeedId": "Répertoire des Skills : saisissez l’ID de Skill pour générer le chemin complet", + "markdownContent": "Contenu Markdown", + "editingStatus": "Édition", + "previewStatus": "Aperçu", + "contentPlaceholder": "Saisissez le contenu Markdown de la Skill...", + "metadataTitle": "Métadonnées des Skills", + "onlyYamlMetadata": "Cette Skill contient uniquement des métadonnées YAML.", + "emptyContentHint": "Aucun contenu pour le moment. Cliquez sur « Éditer » pour commencer.", + "loadingSkill": "Chargement de la Skill...", + "emptyNoAgents": "Aucun agent disponible.", + "noSelectionHint": "Sélectionnez un Skill à gauche ou cliquez sur « Nouveau Skill » pour en créer un.", + "systemBadge": "Système", + "systemHint": "Skill intégré du CLI · lecture seule", + "scope": { + "global": "Global", + "folder": "Dossier", + "selectFolderPlaceholder": "Sélectionner un dossier", + "noFolders": "Aucun dossier trouvé", + "pickFolderHint": "Sélectionnez un dossier pour afficher ses Skills." + }, + "actions": { + "preview": "Aperçu", + "edit": "Éditer", + "openInWindow": "Ouvrir dans une nouvelle fenêtre", + "delete": "Supprimer", + "deleting": "Suppression...", + "refresh": "Actualiser", + "newSkill": "Nouvelle Skill", + "reset": "Réinitialiser", + "save": "Enregistrer", + "saving": "Enregistrement...", + "cancel": "Annuler" + }, + "deleteDialog": { + "title": "Supprimer la Skill", + "confirm": "Supprimer la Skill actuelle ? Cette action est irréversible.", + "confirmWithNamePrefix": "Supprimer la Skill", + "confirmWithNameSuffix": "? Cette action est irréversible." + }, + "toasts": { + "loadFailed": "Échec du chargement de la Skill", + "openFolderFailed": "Échec de l'ouverture du dossier", + "noSkillDirectory": "Aucun répertoire de Skills disponible pour l’agent actuel", + "nameRequired": "Le nom de la Skill ne peut pas être vide", + "updated": "Skill mise à jour", + "created": "Skill créée", + "saveFailed": "Échec de l’enregistrement de la Skill", + "deleted": "Skill supprimée", + "deleteFailed": "Échec de la suppression de la Skill" + }, + "templates": { + "gemini": "---\nname: example-skill\ndescription: Describe when this skill should be used.\n---\n\n# Skill Name\n\nInstructions for the agent when this skill is active.\n\n## Workflow\n\n1. Add actionable step one.\n2. Add actionable step two.\n", + "openCode": "---\nname: example-skill\ndescription: Describe when this skill should be used.\n---\n\n# Purpose\n\nDescribe what this skill helps with.\n\n# Steps\n\n1. Add actionable step one.\n2. Add actionable step two.\n", + "openClaw": "---\nname: example-skill\ndescription: Describe when this skill should be used.\nuser-invocable: true\ndisable-model-invocation: false\n---\n\n# Purpose\n\nDescribe what this skill helps with.\n\n# Instructions\n\n1. Add actionable instruction one.\n2. Add actionable instruction two.\n", + "default": "---\nname: example-skill\ndescription: Describe when this skill should be used.\n---\n\n# Skill: example-skill\n\n## When to use\n\n- Describe trigger conditions.\n\n## Instructions\n\n1. Add actionable instruction one.\n2. Add actionable instruction two.\n" + } + }, + "McpSettings": { + "loading": "Chargement...", + "summary": { + "missingCommand": "(commande manquante)", + "missingUrl": "(URL manquante)" + }, + "protocol": { + "stdio": "Stdio" + }, + "errors": { + "selectInstallProtocol": "Veuillez sélectionner un protocole d’installation", + "fieldRequired": "{field} est requis", + "fieldNeedsBoolean": "{field} doit être true ou false", + "fieldNeedsNumber": "{field} doit être un nombre", + "fieldNeedsInteger": "{field} doit être un entier", + "fieldInvalidJson": "{field} contient un JSON invalide : {message}", + "fieldOutOfRange": "La valeur de {field} est hors de la plage autorisée", + "jsonEmpty": "{name} ne peut pas être vide", + "jsonInvalid": "{name} n’est pas un JSON valide : {message}", + "jsonMustBeObject": "{name} doit être un objet JSON", + "specMustBeObject": "La configuration MCP doit être un objet JSON.", + "missingType": "Le champ type est manquant dans la configuration MCP. Indiquez stdio, http (alias : streamable-http, streamableHttp) ou sse.", + "unsupportedType": "Type MCP non pris en charge {type}. Pris en charge : stdio, http (alias : streamable-http, streamableHttp), sse.", + "codexEntryUnsupportedType": "L’entrée MCP Codex {id} a un type non pris en charge {type}. Pris en charge : stdio, http (alias : streamable-http, streamableHttp), sse.", + "unsupportedTransportType": "Type de transport non pris en charge {type}. Pris en charge : http (alias : streamable-http, streamableHttp), sse.", + "stdioCommandRequired": "Un MCP stdio nécessite un champ command non vide.", + "remoteUrlRequired": "Un MCP distant nécessite un champ url non vide.", + "appsRequired": "Sélectionnez au moins une application cible." + }, + "jsonNames": { + "localConfig": "Configuration MCP", + "installConfig": "Configuration d’installation" + }, + "toasts": { + "uninstalled": "MCP désinstallé", + "uninstallFailed": "Échec de la désinstallation : {message}", + "selectAtLeastOneApp": "Veuillez sélectionner au moins une application cible", + "saveSuccess": "Enregistré", + "saveFailed": "Échec de l’enregistrement : {message}", + "installed": "{name} installé", + "installFailed": "Échec de l’installation : {message}", + "serverIdRequired": "L'ID du serveur est requis", + "serverIdExists": "Le Server ID \"{id}\" existe déjà. Modifiez l'entrée existante ou choisissez un autre nom.", + "created": "MCP créé" + }, + "installDialog": { + "title": "Confirmer l’installation MCP", + "descriptionWithName": "Installer {name} dans la configuration locale.", + "description": "Sélectionnez les applications cibles pour l’installation.", + "protocol": "Protocole", + "selectProtocol": "Sélectionner un protocole", + "parameters": "Paramètres de configuration", + "booleanPlaceholder": "Veuillez sélectionner true/false", + "selectOneValue": "Sélectionner une valeur", + "targetApps": "Applications cibles" + }, + "actions": { + "cancel": "Annuler", + "confirmInstall": "Confirmer l’installation", + "installing": "Installation", + "uninstall": "Désinstaller", + "uninstalling": "Désinstallation", + "viewDetails": "Voir les détails", + "save": "Enregistrer", + "saving": "Enregistrement", + "install": "Installer", + "refresh": "Actualiser", + "newMcp": "Nouveau MCP", + "create": "Créer", + "creating": "Création..." + }, + "tabs": { + "local": "MCP local", + "market": "Marketplace MCP" + }, + "local": { + "filterPlaceholder": "Filtrer les MCP locaux...", + "loadFailed": "Échec du chargement : {message}", + "empty": "Aucun MCP local détecté.", + "description": "La configuration MCP locale peut être modifiée et enregistrée directement.", + "enabledApps": "Applications activées", + "configJson": "Configuration MCP (JSON)", + "draftTitle": "Nouveau MCP", + "draftDescription": "Renseignez un Server ID et une configuration pour créer un serveur MCP local.", + "serverIdLabel": "ID du serveur", + "serverIdPlaceholder": "ID du serveur (ex. my-mcp)", + "typeHint": "Types pris en charge : stdio, http (alias : streamable-http, streamableHttp), sse. env n'est utilisé que par stdio ; pour les MCP distants, utilisez headers pour transporter les jetons d'authentification.", + "envOnRemoteWarning": "env détecté sur un MCP distant. Seul stdio utilise env ; les MCP distants transportent les jetons d'authentification via headers, donc env sera ignoré à l'enregistrement." + }, + "market": { + "selectMarketplace": "Sélectionner un marketplace", + "searchPlaceholder": "Rechercher MCP...", + "searchFailed": "Échec de la recherche : {message}", + "loadingList": "Chargement de la liste MCP...", + "empty": "Aucun résultat MCP.", + "loadingDetail": "Chargement des détails du marketplace...", + "detailLoadFailed": "Échec du chargement des détails : {message}", + "owner": "Propriétaire : {owner}", + "namespace": "Espace de noms : {namespace}", + "defaultInstallProtocol": "Protocole d’installation par défaut", + "currentOptionParameterCount": "Nombre de paramètres de l’option actuelle : {count}", + "installConfigDescription": "Configuration d’installation (JSON, modifiable avant installation ; les modifications remplaceront le formulaire protocole/paramètres)", + "selectLeftToView": "Sélectionnez un MCP du marketplace à gauche pour voir les détails." + }, + "badges": { + "verified": "Vérifié", + "remote": "Distant", + "hasHomepage": "A une page d’accueil", + "uses": "{count} utilisations", + "deployed": "Déployé", + "notDeployed": "Non déployé" + }, + "selectLeftMcp": "Sélectionnez un MCP à gauche." + }, + "AcpAgentSettings": { + "title": "Gestion du SDK des agents", + "description": "Gérez en un seul endroit la connexion SDK des agents, l'état activé, les variables d'environnement, la gestion de configuration et les informations de préflight de version.", + "loadingAgents": "Chargement de la liste des agents...", + "agentList": "Liste des agents", + "emptyNoAgent": "Aucun agent disponible.", + "configManagement": "Gestion de configuration", + "envVars": "Variables d'environnement", + "hostTools": { + "label": "Laisser l'agent gérer les fichiers et les commandes", + "description": "codeg cesse d'assurer l'accès aux fichiers et les commandes de terminal : l'agent les exécute dans son propre processus, là où son bac à sable et ses règles d'autorisation s'appliquent réellement. La délégation à d'autres agents est également désactivée, car elle ferait repasser le même travail par codeg. codeg n'ajoute aucun bac à sable, n'activez donc ceci que si l'agent en a un configuré." + }, + "nativeJsonConfig": "Configuration JSON native", + "modelHintDefault": "Laissez vide pour utiliser le modèle système par défaut.", + "generalConfigDescriptionClaude": "Prend en charge la configuration rapide de l'API URL, API Key et des modèles Claude, et synchronise avec la configuration JSON native.", + "generalConfigDescriptionDefault": "Prend en charge les entrées de configuration importantes (API URL, API Key, Model) et la gestion de la configuration JSON native.", + "multiAgent": { + "title": "Collaboration multi-agent", + "description": "Permet aux agents actifs de déléguer des sous-tâches à d’autres agents.", + "enable": "Activer la délégation", + "enableHint": "Lorsque cette option est désactivée, l’outil delegate_to_agent est masqué du catalogue d’outils MCP de l’agent.", + "withheldByHostTools": "{agents} ne recevront pas les outils de délégation : leur interrupteur par agent « Laisser l’agent gérer les fichiers et les commandes » est activé.", + "selfInitiate": "Allow spawn without @", + "selfInitiateHint": "When on, an agent may start a listed sub-agent on its own. An @ mention is still always honored. When off, only an @ mention starts a sub-agent.", + "depthLimit": "Profondeur maximale de délégation", + "depthHint": "Plage autorisée : {min}–{max}. Limite la profondeur de récursion d’une chaîne de délégation (racine → enfant → petit-enfant …).", + "completedCacheLabel": "Cache des résultats terminés (MB)", + "completedCacheHint": "Cache en mémoire des résultats terminés des sous-agents, conservé uniquement tant que la session de délégation est en cours et libéré automatiquement à la fin de cette session. Au-delà de ce budget, les résultats les plus anciens sont supprimés de la mémoire en premier (toujours consultables dans la session du sous-agent) ; 0 = illimité (libéré quand même à la fin de la session).", + "save": "Enregistrer", + "saving": "Enregistrement…", + "saved": "Paramètres de délégation enregistrés", + "saveFailed": "Échec de l’enregistrement des paramètres de délégation", + "loadFailed": "Échec du chargement des paramètres de délégation : {detail}", + "tabGeneral": "Général", + "tabAgentDefaults": "Valeurs par défaut du sous-agent", + "agentDefaultsDescription": "Remplacements par agent appliqués lorsque la Collaboration multi-agent démarre un sous-agent pour un appel de délégation. Les options affichées proviennent d’une sonde en direct : votre sélection correspond exactement à ce que l’agent acceptera.", + "probing": "Chargement des options disponibles depuis l’agent…", + "probeFailed": "Échec du chargement des options : {detail}", + "retry": "Réessayer", + "noConfigAvailable": "Cet agent n’a aucune option configurable.", + "modeLabel": "Mode", + "agentDefaultHint": "Valeur par défaut de l’agent : {value}", + "defaultOptionLabel": "Par défaut ({value})" + }, + "actions": { + "dragSort": "Glisser pour réordonner", + "dragSortAgent": "Glisser pour réordonner {name}", + "refreshCheck": "Actualiser la vérification", + "refreshCheckAgent": "Actualiser la vérification de {name}", + "clickEnable": "Cliquer pour activer {name}", + "clickDisable": "Cliquer pour désactiver {name}", + "install": "Installer", + "upgrade": "Mettre à niveau", + "uninstall": "Désinstaller", + "uninstalling": "Désinstallation...", + "saveEnvVars": "Enregistrer les variables d’environnement", + "saving": "Enregistrement...", + "saveGrokConfig": "Enregistrer la configuration Grok", + "saveCodexConfig": "Enregistrer la config Codex", + "saveGeminiConfig": "Enregistrer la config Gemini", + "saveOpenCodeConfig": "Enregistrer la config OpenCode", + "saveOpenClawConfig": "Enregistrer la config OpenClaw", + "saveConfigManagement": "Enregistrer la gestion de config", + "saveCurrentProvider": "Enregistrer le provider actuel", + "showApiKey": "Afficher la clé API", + "hideApiKey": "Masquer la clé API", + "showKey": "Afficher la clé", + "hideKey": "Masquer la clé", + "showToken": "Afficher le token", + "hideToken": "Masquer le token", + "cancel": "Annuler", + "delete": "Supprimer", + "deleting": "Suppression...", + "confirmDelete": "Confirmer la suppression", + "confirmUninstall": "Confirmer la désinstallation", + "saveClineConfig": "Enregistrer la configuration Cline", + "saveHermesConfig": "Enregistrer la configuration Hermes", + "saveCodeBuddyConfig": "Enregistrer la configuration CodeBuddy", + "saveKimiCodeConfig": "Enregistrer la configuration de Kimi Code", + "customInstall": "Installation personnalisée", + "saveKimiCodeRawConfig": "Enregistrer config.toml", + "saveDeepSeekConfig": "Enregistrer la configuration DeepSeek", + "diagnose": "Diagnostiquer" + }, + "status": { + "enabled": "Activé", + "disabled": "Désactivé", + "unchecked": "Non vérifié", + "agentEnabledAria": "{name} activé", + "agentEnabledSwitch": "Interrupteur d’activation {name}" + }, + "preflight": { + "count": "Éléments de pré-vérification : {count}", + "notRun": "Les vérifications n’ont pas encore été exécutées." + }, + "grok": { + "configDescription": "Configurez Grok ici. Les contrôles ci-dessous — mode d'autorisation, effort de raisonnement, un modèle personnalisé optionnel (point de terminaison dédié) et le compactage — sont fusionnés dans ~/.grok/config.toml, en préservant vos autres clés et commentaires. La connexion utilise votre XAI_API_KEY ou `grok login`. Les autres clés restent modifiables sous Avancé.", + "permissionModeLabel": "Mode d'autorisation", + "permissionDefault": "Demander à chaque fois", + "permissionAcceptEdits": "Approuver les modifications automatiquement", + "permissionAuto": "Approbation automatique intelligente", + "permissionAlwaysApprove": "Toujours approuver", + "reasoningEffortLabel": "Effort de raisonnement", + "effortLow": "Faible (plus rapide)", + "effortMedium": "Moyen (équilibré)", + "effortHigh": "Élevé", + "effortXhigh": "Maximum", + "optionDefault": "Utiliser la valeur par défaut", + "authTitle": "Authentification", + "authMode": "Méthode d'authentification", + "authModeApiKey": "Clé API XAI", + "authModeApiKeyHint": "Authentifiez-vous avec une XAI_API_KEY de la console xAI, pour les exécutions non interactives ou headless. Enregistrée dans l'environnement de cet agent.", + "authModeCustom": "Point de terminaison personnalisé", + "authModeCustomHint": "Utilisez votre propre point de terminaison (BYO) : définissez ci-dessous un modèle personnalisé avec sa propre URL de base et sa clé API. Il devient le modèle par défaut de Grok.", + "subscriptionHint": "Connectez-vous avec `grok login` (SuperGrok / X Premium+). Aucune clé API n'est enregistrée.", + "loginHint": "Exécutez ceci dans un terminal pour vous connecter, puis rouvrez ces paramètres :", + "commandCopied": "Commande copiée dans le presse-papiers", + "copyCommand": "Copier la commande", + "authKeyConfigured": "XAI_API_KEY est configurée.", + "authKeyMissing": "Aucune XAI_API_KEY définie.", + "advancedToggle": "Avancé (config.toml brut)", + "configTomlNative": "config.toml (natif)", + "configTomlHint": "Enregistré tel quel comme l'intégralité de ~/.grok/config.toml. Le TOML invalide est rejeté afin qu'une faute de frappe ne tronque jamais votre fichier.", + "configTomlPlaceholder": "# Clés autres que les contrôles ci-dessus, p. ex.\n# [mcp_servers.*], [cli], règles [permission].", + "customModelTitle": "Modèle personnalisé (point de terminaison dédié)", + "customModelHint": "Dirigez Grok vers un point de terminaison personnalisé ou auto-hébergé. codeg écrit un bloc `[model.*]` par modèle et le définit comme modèle par défaut. Laissez l'ID de modèle vide pour le supprimer.", + "customModelIdLabel": "ID du modèle", + "customModelIdPlaceholder": "grok-4.5", + "customModelIdHint": "Enregistré comme bloc `[model.*]` et envoyé à l'API comme nom de modèle ; également défini comme `[models].default`.", + "customBaseUrlLabel": "URL de base", + "customBaseUrlPlaceholder": "https://api.x.ai/v1 (par défaut)", + "customApiBackendLabel": "Backend de l'API", + "backendResponses": "Responses", + "backendChatCompletions": "Chat Completions", + "backendMessages": "Messages (Anthropic)", + "customApiKeyLabel": "Clé API", + "customApiKeyHint": "Stockée en ligne dans `[model.*].api_key`, limitée à ce point de terminaison.", + "customContextWindowLabel": "Fenêtre de contexte (tokens)", + "customContextWindowHint": "Facultatif. Détermine le moment du compactage automatique ; laissez vide pour la valeur par défaut du point de terminaison.", + "autoCompactLabel": "Seuil de compactage automatique (%)", + "autoCompactHint": "Compacte la conversation lorsque l'utilisation du contexte atteint ce pourcentage (85 par défaut pour Grok). Écrit dans `[session]`." + }, + "cursor": { + "configDescription": "Configurez Cursor ici. Choisissez une méthode d'authentification — abonnement officiel (connexion par navigateur) ou une clé API Cursor pour les machines sans interface ou serveurs — puis choisissez un modèle et modifiez les règles d'autorisation et le bac à sable du CLI. codeg les écrit dans ~/.cursor/cli-config.json, partagé avec le CLI cursor-agent.", + "authTitle": "Authentification", + "authChecking": "Vérification…", + "authNotInstalled": "cursor-agent n'est pas installé", + "authLoggedIn": "Connecté", + "authNotLoggedIn": "Non connecté", + "loginHint": "Exécutez ceci dans un terminal pour vous connecter à votre compte Cursor (une fenêtre de navigateur s'ouvre), puis cliquez sur actualiser :", + "apiKeyLabel": "Clé API Cursor", + "apiKeyPlaceholder": "clé depuis cursor.com/dashboard", + "apiKeyHint": "CURSOR_API_KEY — une clé de compte du tableau de bord Cursor, alternative à la connexion par navigateur pour les machines sans interface ou serveurs. Ce n'est pas une clé tierce ni OpenAI.", + "modelTitle": "Modèle par défaut", + "loadModels": "Charger les modèles", + "modelsUnavailable": "Liste de modèles indisponible", + "modelHint": "Transmis à la CLI via --model au démarrage de la session. Laissez par défaut pour laisser Cursor choisir.", + "permissionsTitle": "Permissions & bac à sable", + "permissionsDescription": "Éditeur visuel des règles de permissions de la CLI (cli-config.json). Les règles autorisées s'exécutent sans confirmation ; les règles refusées sont toujours bloquées.", + "permissionModeLabel": "Mode d'autorisation", + "permissionModeDefault": "Demander avant d'exécuter (par défaut)", + "permissionModeForce": "Tout exécuter (--force)", + "permissionModeHint": "Tout exécuter lance les sessions avec --force : tous les appels d'outils sont autorisés automatiquement sauf les règles de refus, sans confirmation (une politique d'organisation peut le limiter aux règles d'autorisation). S'applique aux nouvelles sessions.", + "optionDefault": "Défaut (non défini)", + "sandboxLabel": "Bac à sable", + "sandboxEnabled": "Activé", + "sandboxDisabled": "Désactivé", + "allowRulesLabel": "Règles autorisées", + "denyRulesLabel": "Règles refusées", + "addRule": "Ajouter une règle", + "rulesSyntaxHint": "Syntaxe des règles : Shell(cmd), Read(chemin/glob), Write(chemin/glob), WebFetch(domaine), Mcp(serveur:outil) — les règles de refus priment toujours.", + "saveConfig": "Enregistrer la configuration", + "advancedToggle": "Avancé : cli-config.json brut", + "advancedHint": "Le ~/.cursor/cli-config.json complet. Enregistrer écrit le fichier tel quel ; les contrôles structurés ci-dessus y sont fusionnés.", + "saveRawConfig": "Enregistrer le fichier", + "authMode": "Méthode d'authentification", + "subscriptionHint": "Connectez-vous avec votre compte Cursor et utilisez les modèles de Cursor.", + "customApiKeyRequired": "Une clé API Cursor est requise.", + "authModeApiKey": "Clé API Cursor (sans interface)", + "authModeApiKeyHint": "Authentifiez-vous avec une clé API de compte Cursor générée dans le tableau de bord Cursor (pour les machines sans interface ou serveurs). C'est une clé de compte Cursor, pas un point de terminaison tiers/OpenAI : cursor-agent ne communique qu'avec le backend de Cursor. Pour utiliser un point de terminaison compatible codex/OpenAI, utilisez plutôt l'agent Codex.", + "modelPickerPlaceholder": "Rechercher des modèles…", + "modelNoMatch": "Aucun modèle correspondant", + "modelsNeedAuth": "Connectez-vous pour charger la liste des modèles.", + "modelDefaultBadge": "par défaut" + }, + "deepseek": { + "configManagement": "Configuration de DeepSeek Harness", + "configDescription": "Le point de terminaison et la clé sont des variables d'environnement que deepseek-acp lit au démarrage. Le modèle et le niveau de raisonnement sont des sélecteurs par session : ils se choisissent dans le champ de saisie.", + "baseUrlLabel": "Point de terminaison de l'API", + "baseUrlHint": "Laissez vide pour le point de terminaison officiel. S'applique aux sessions démarrées après l'enregistrement ; reconnectez une session en cours pour qu'elle le prenne en compte.", + "baseUrlInvalid": "Saisissez une URL http(s) complète et sans chaîne de requête, par exemple https://api.deepseek.com", + "apiKeyLabel": "Clé d'API", + "apiKeyHint": "Transmise à l'agent via DEEPSEEK_API_KEY. Une variable d'environnement l'emporte sur le fichier d'identifiants : laissez ce champ vide si vous vous connectez depuis le terminal." + }, + "codex": { + "configDescription": "Prend en charge la configuration rapide de l’URL API, de la clé API, du nom du modèle et du reasoning effort, avec synchronisation vers `auth.json` / `config.toml`.", + "authMode": "Mode d’authentification", + "chatgptSubscription": "Abonnement officiel", + "chatgptSubscriptionHint": "Connectez-vous avec l’abonnement officiel ChatGPT, pas besoin d’API Key", + "apiKeyHint": "Connectez-vous avec une API Key à OpenAI ou aux services API compatibles", + "selectProvider": "Sélectionner un provider", + "modelName": "Nom du modèle", + "selectReasoningEffort": "Sélectionner Reasoning Effort", + "enableWebsocket": "Activer WebSocket", + "enableWebsocketAria": "Activer WebSocket pour Codex Provider", + "enableSkills": "Activer Skills", + "enableSkillsAria": "Activer Skills pour Codex", + "enableFast": "Activer Fast", + "enableFastAria": "Activer le niveau de service Fast pour Codex", + "sandboxGroupTitle": "Bac à sable et approbations", + "sandboxGroupHint": "Écrit dans le ~/.codex/config.toml global, donc les sessions codex CLI et IDE en héritent aussi. Ce sont des valeurs par défaut du fil : elles régissent les tours que codex démarre lui-même (/goal, /review, /compact). Les messages ordinaires utilisent le préréglage d'approbation de la zone de saisie. Redémarrez une session pour appliquer les changements.", + "sandboxShadowedWarning": "config.toml définit default_permissions : codex résout les permissions via ce profil et ignore totalement sandbox_mode. Supprimez default_permissions pour utiliser les réglages ci-dessous.", + "sandboxPermissionsTableWarning": "config.toml définit des profils [permissions] sans default_permissions, ce qui empêche codex de démarrer. Renseignez-le dans l'éditeur brut ci-dessous.", + "approvalPolicyLabel": "Politique d'approbation", + "approvalPolicyUnset": "Non définie (défaut codex : à la demande)", + "approvalPolicy_on-request": "À la demande — le modèle décide quand demander", + "approvalPolicy_untrusted": "Non fiable — seules les commandes en lecture seule reconnues sûres s'exécutent sans validation", + "approvalPolicy_never": "Jamais — aucune demande d'approbation", + "approvalPolicy_granular": "Granulaire — au cas par cas selon le type", + "approvalPolicyUntrustedAcpWarning": "« Untrusted » n'a pas d'équivalent parmi les trois préréglages d'approbation de l'adaptateur ACP ; les sessions codeg retombent donc sur « à la demande » : le modèle décide alors quand demander, et les commandes que le bac à sable autorise déjà ne demandent plus rien. Restreignez plutôt le mode de bac à sable ci-dessous.", + "granularHint": "Désactivé signifie que ce type de demande est refusé automatiquement au lieu de vous être présenté.", + "granular_sandbox_approval": "Élévations pour commandes shell", + "granular_rules": "Invites des règles execpolicy", + "granular_skill_approval": "Invites des scripts de compétences", + "granular_request_permissions": "Invites de l'outil request_permissions", + "granular_mcp_elicitations": "Invites d'elicitation MCP", + "sandboxModeLabel": "Mode bac à sable", + "sandboxModeUnset": "Non défini (les dossiers de confiance retombent sur l'écriture dans l'espace de travail)", + "sandboxMode_read-only": "Lecture seule", + "sandboxMode_workspace-write": "Écriture dans l'espace de travail", + "sandboxMode_danger-full-access": "Accès complet (sans bac à sable)", + "sandboxModeHint": "Sous Windows, l'écriture dans l'espace de travail est rétrogradée en lecture seule sauf si le bac à sable Windows expérimental de codex est activé.", + "sandboxModeSeedsPresetHint": "codeg s'en sert aussi pour le préréglage d'approbation initial de la session : contrairement à la politique d'approbation, il agit donc sur les requêtes ordinaires. Le préréglage choisi dans la zone de saisie reste prioritaire.", + "writableRootsLabel": "Dossiers inscriptibles supplémentaires", + "writableRootsHint": "Un chemin absolu par ligne, en plus du répertoire de travail.", + "sandboxRootsRelativeError": "Doit être un chemin absolu — codex résout les chemins relatifs sous ~/.codex : {path}", + "networkAccessLabel": "Autoriser l'accès réseau", + "excludeTmpdirLabel": "Exclure TMPDIR des racines inscriptibles", + "excludeSlashTmpLabel": "Exclure /tmp des racines inscriptibles", + "authJsonNative": "auth.json (natif)", + "configTomlNative": "config.toml (natif)", + "loginButton": "Se connecter avec ChatGPT", + "loginRequesting": "Demande du code de connexion...", + "loginStep1": "Ouvrez l'URL suivante dans votre navigateur :", + "loginStep2": "Entrez le code ci-dessous :", + "loginPolling": "En attente d'autorisation...", + "loginCancel": "Annuler", + "loginSuccess": "Connexion réussie, configuration enregistrée !", + "loginFailed": "Échec de la connexion : {message}", + "loginRetry": "Réessayer", + "loginCodeCopied": "Code copié", + "loggedIn": "Compte connecté", + "loginRelogin": "Reconnecter / Changer de compte", + "loginTimeout": "Connexion expirée, veuillez réessayer", + "loginSaveFailed": "Connexion réussie mais échec de la sauvegarde de la configuration" + }, + "gemini": { + "authConfig": "Configuration d’authentification Gemini", + "authConfigDescription": "Alignée sur la documentation d’authentification Gemini CLI, avec prise en charge d’un endpoint personnalisé, connexion Google, Gemini API Key et Vertex AI (ADC / compte de service / API Key).", + "authMode": "Mode d’authentification", + "selectAuthMode": "Sélectionner un mode d’authentification", + "viewAuthDoc": "Voir la documentation d’authentification", + "mode": { + "custom": "Endpoint personnalisé", + "loginGoogle": "Connexion Google (OAuth)", + "vertexServiceAccount": "Vertex AI (Compte de service)" + }, + "hint": { + "custom": "Renseignez API URL, API Key et Model, mappés sur GOOGLE_GEMINI_BASE_URL / GEMINI_API_KEY / GEMINI_MODEL.", + "loginGoogle": "Exécutez d’abord gemini dans le terminal et terminez la connexion Google ; la clé API n’est pas requise.", + "geminiApiKey": "Renseignez GEMINI_API_KEY lors de l’utilisation de l’API Gemini.", + "vertexAdc": "Utilisez gcloud ADC ; GOOGLE_CLOUD_PROJECT et GOOGLE_CLOUD_LOCATION sont recommandés.", + "vertexServiceAccount": "Définissez le chemin JSON du compte de service dans GOOGLE_APPLICATION_CREDENTIALS.", + "vertexApiKey": "Renseignez GOOGLE_API_KEY lors de l’utilisation d’une clé API Vertex AI." + } + }, + "openCode": { + "configManagement": "Gestion de configuration OpenCode", + "configDescription": "Alignée sur le schéma `provider` d’OpenCode, prend en charge la gestion multi-provider et la synchronisation bidirectionnelle avec les fichiers JSON natifs.", + "providerManagement": "Gestion des providers", + "providerCount": "{count} fournisseurs", + "addProvider": "Ajouter un provider", + "emptyProvider": "Aucun fournisseur personnalisé pour le moment. Cliquez sur Ajouter un fournisseur personnalisé pour en créer un.", + "providerEnabledState": "État activé de {providerId}", + "selectProviderNpm": "Sélectionner provider.npm", + "modelManagement": "Gestion des modèles", + "modelCount": "{count} modèles", + "modelDescription": "Aligné sur `provider.models` d’OpenCode. La gestion rapide prend actuellement en charge `name` / `id` ; les autres champs avancés sont conservés et peuvent être modifiés dans le JSON natif ci-dessous.", + "addModel": "Ajouter un modèle", + "emptyModel": "Aucun modèle pour le moment. Saisissez model id puis cliquez sur « Ajouter un modèle ».", + "modelId": "ID du modèle", + "modelName": "Nom du modèle", + "deleteModel": "Supprimer le modèle {modelId}", + "nativeJsonConfig": "Configuration JSON native OpenCode", + "mainModel": "Modèle principal", + "smallModel": "Petit modèle", + "noMatchingModels": "Aucun modèle correspondant", + "connectProvider": "Connecter un fournisseur", + "connectedProviders": "Fournisseurs connectés", + "noConnectedProviders": "Aucun fournisseur du catalogue connecté pour le moment.", + "advancedProviderConfig": "Fournisseurs personnalisés", + "customProviderConfigHint": "Points de terminaison compatibles OpenAI que vous définissez vous-même — un bloc provider dans opencode.json, avec la clé API dans auth.json.", + "addCustomProvider": "Ajouter un fournisseur personnalisé", + "disconnect": "Déconnecter", + "editConfig": "Modifier", + "customBadge": "Personnalisé", + "authKindApi": "Clé API", + "authKindOauth": "OAuth", + "authKindNone": "Aucun identifiant", + "connect": { + "title": "Connecter un fournisseur", + "description": "Choisissez un fournisseur dans le catalogue models.dev. Les identifiants sont enregistrés dans le fichier auth.json d'OpenCode.", + "pick": "Fournisseur", + "search": "Rechercher des fournisseurs…", + "loading": "Chargement du catalogue…", + "catalogLabel": "Catalogue models.dev", + "modelsAvailable": "{count} modèles disponibles", + "getKey": "Obtenir la clé API", + "oauthApiKeyNote": "Ce fournisseur prend aussi en charge la connexion via navigateur avec opencode auth login. La connexion par navigateur arrive bientôt ; pour le moment, collez une clé API.", + "apiKey": "Clé API", + "apiKeyHint": "Enregistrée dans auth.json, jamais dans opencode.json.", + "baseUrlOptional": "Remplacer l''URL de base (facultatif)", + "providerId": "ID du fournisseur", + "displayName": "Nom affiché", + "modelsList": "Modèles (un par ligne)", + "modelsHint": "Identifiants de modèle acceptés par le point de terminaison.", + "action": "Connecter", + "editTitle": "Modifier le fournisseur", + "editDescription": "Mettez à jour la clé API ou l''URL de base de ce fournisseur.", + "saveAction": "Enregistrer" + }, + "customProvider": { + "title": "Ajouter un fournisseur personnalisé", + "description": "Définissez un point de terminaison compatible OpenAI. La clé API est enregistrée dans auth.json ; le bloc provider va dans opencode.json.", + "action": "Ajouter le fournisseur", + "idInCatalog": "{providerId} est un fournisseur connu — connectez-le plutôt via Connecter un fournisseur." + }, + "refreshCatalog": "Actualiser le catalogue", + "reasoningBadge": "raisonnement", + "contextWindow": "Fenêtre de contexte", + "permissions": { + "title": "Permissions", + "description": "Décidez quelles actions s’exécutent seules, lesquelles demandent votre accord et lesquelles sont bloquées. Écrit dans le bloc permission de opencode.json et appliqué à l’enregistrement ci-dessous.", + "docsLink": "Documentation des permissions", + "unparsableConfig": "Le JSON natif ci-dessous est invalide, l’éditeur visuel est donc en pause. Corrigez le JSON pour reprendre.", + "invalidBlock": "Le bloc permission a une forme que codeg ne reconnaît pas. Modifiez-le dans le JSON natif ci-dessous ou utilisez Réinitialiser pour repartir de zéro.", + "orderingUnsafe": "Une règle joker est écrite après des outils précis, donc OpenCode l’applique aussi à ceux-ci : les lignes ci-dessous ne sont pas ce qui s’applique réellement. Corriger l’ordre ramène simplement chaque joker en tête de sa portée, sans modifier la moindre valeur.", + "orderingUnsafeManual": "Une règle est masquée par un motif plus général placé après elle, donc OpenCode ne l’applique jamais : les lignes ci-dessous ne sont pas ce qui s’applique réellement. Deux motifs qui se chevauchent n’ont pas d’ordre unique correct ; réordonnez-les dans le JSON natif pour que le plus général vienne en premier.", + "fixOrder": "Corriger l’ordre", + "agentOverrides": "Ces agents redéfinissent les permissions et sont appliqués en dernier, ils l’emportent donc sur tout ce qui est ici : {agents}. Modifiez-les dans le JSON natif ci-dessous, ou activez l’acceptation automatique pour les effacer.", + "legacyTools": "L’ancienne table tools de premier niveau refuse un outil. OpenCode la fusionne avec les permissions, elle s’applique donc par-dessus tout ce qui est affiché ici. Modifiez-la dans le JSON natif ci-dessous, ou activez l’acceptation automatique pour l’effacer.", + "autoAcceptTitle": "Accepter automatiquement toutes les permissions", + "autoAcceptHint": "Chaque appel d’outil — commandes shell, modifications de fichiers, chemins hors du projet — s’exécute sans demander. L’activer remplace les réglages par outil ci-dessous par une seule règle tout-autoriser et efface les surcharges par agent ainsi que les anciens interrupteurs tools qui bloqueraient encore.", + "globalLabel": "Valeur globale par défaut", + "globalHint": "La règle * : elle s’applique à tout ce que les outils ci-dessous ne redéfinissent pas.", + "actionUnset": "Non défini (valeurs OpenCode)", + "actionInherit": "Hériter ({action})", + "actionAllow": "Autoriser", + "actionAsk": "Demander", + "actionDeny": "Refuser", + "perToolTitle": "Permissions par outil", + "reset": "Réinitialiser", + "ruleCount": "règles : {count}", + "rulesToggle": "Règles fines de {tool}", + "rulesHint": "Comparées à l’entrée de l’outil, la dernière correspondance l’emporte : placez donc les motifs larges en premier. * correspond à n’importe quels caractères, ? à exactement un, et un ~ initial désigne votre dossier personnel.", + "noRules": "Aucune règle fine pour l’instant.", + "addRule": "Ajouter une règle", + "deleteRule": "Supprimer la règle {pattern}", + "duplicateRule": "Ce motif existe déjà.", + "blankRule": "Une règle a besoin d’un motif — utilisez l’icône corbeille pour la supprimer.", + "customKeys": "Autres clés de permission du fichier", + "customKeyHint": "Ce n’est pas un outil intégré d’OpenCode — conservé tel quel.", + "keys": { + "bash": "Exécuter des commandes shell, selon la commande analysée", + "edit": "Toutes les modifications de fichiers : edit, write et patch", + "read": "Lire des fichiers, selon le chemin", + "external_directory": "Atteindre des chemins hors du répertoire de travail du projet", + "task": "Lancer des sous-agents, selon le type de sous-agent", + "skill": "Charger des skills, selon leur nom", + "glob": "Trouver des fichiers, selon le motif glob", + "grep": "Rechercher dans le contenu des fichiers, selon le motif", + "list": "Lister le contenu d’un répertoire", + "webfetch": "Récupérer une URL", + "websearch": "Rechercher sur le web", + "lsp": "Exécuter des requêtes LSP", + "todowrite": "Écrire la liste de tâches", + "question": "Vous poser une question", + "doom_loop": "Se déclenche quand le même appel se répète trois fois avec la même entrée" + } + } + }, + "openClaw": { + "gatewayConfig": "Configuration Gateway", + "gatewayDescription": "Configure la connexion OpenClaw Gateway. Prend en charge une gateway locale ou distante.", + "gatewayUrlHint": "Laisser vide pour utiliser gateway.remote.url depuis la configuration locale openclaw.", + "gatewayTokenPlaceholder": "Token d’authentification Gateway", + "gatewayTokenHint": "Utilisez token-file plutôt qu’un token en clair si possible ; configurez-le via le CLI openclaw.", + "sessionKeyHint": "Optionnel. Spécifie la session key de la gateway ; laisser vide pour auto-attribuer une session isolée." + }, + "hermes": { + "configManagement": "Configuration de Hermes", + "configDescription": "Hermes gère ses propres identifiants dans ~/.hermes/.env et ses paramètres dans ~/.hermes/config.yaml. Choisissez un fournisseur, puis définissez la clé d'API et le modèle — codeg écrit les deux fichiers pour vous.", + "providerLabel": "Fournisseur", + "providerHint": "Le fournisseur détermine quelle variable de clé d'API et quel model.provider Hermes utilise. Les fournisseurs OAuth se configurent via la configuration du terminal ci-dessous.", + "groupApiKey": "Fournisseurs avec clé API", + "groupOauth": "Fournisseurs OAuth", + "groupAws": "AWS", + "apiKeyHint": "Enregistrée dans ~/.hermes/.env. Elle n'est jamais injectée dans le processus — Hermes la lit depuis sa propre configuration.", + "modelName": "Modèle", + "oauthHint": "Ce fournisseur utilise OAuth. Exécutez la configuration ci-dessous pour vous authentifier dans votre terminal.", + "awsHint": "Bedrock utilise vos identifiants AWS (environnement ou configuration partagée). Définissez l'ID du modèle ci-dessus et configurez l'accès AWS dans votre environnement.", + "unsupportedProvider": "Ce fournisseur n'est pas modifiable via les champs structurés. Utilisez l'éditeur config.yaml ci-dessous ou la configuration par terminal.", + "setupTitle": "Configuration autogérée", + "setupHint": "La configuration interactive de Hermes nécessite un terminal. Lancez-la ci-dessous ou copiez la commande pour l'exécuter vous-même.", + "runSetup": "Exécuter la configuration de Hermes", + "configureModel": "Configurer le modèle", + "openConfigFolder": "Ouvrir ~/.hermes", + "copyCommand": "Copier la commande", + "commandCopied": "Commande copiée dans le presse-papiers", + "advancedTitle": "Avancé : modifier config.yaml", + "rawConfigHint": "Modifiez directement ~/.hermes/config.yaml. Enregistrer ici écrase le fichier tel quel.", + "saveRawConfig": "Enregistrer config.yaml" + }, + "codebuddy": { + "configManagement": "Configuration de CodeBuddy", + "configDescription": "CodeBuddy s'authentifie avec une clé API. Les versions pour la Chine continentale nécessitent aussi de définir l'environnement sur « Chine (internal) » ; les versions iOA utilisent « iOA ». La version internationale la laisse non définie.", + "apiKeyLabel": "Clé API", + "apiKeyHint": "Enregistré en tant que CODEBUDDY_API_KEY pour cet agent. Vous pouvez aussi vous connecter avec la CLI CodeBuddy dans un terminal.", + "apiKeyHintSelfHosted": "Enregistré en tant que CODEBUDDY_API_KEY pour cet agent. Utilisez la clé émise par votre déploiement privé.", + "environmentLabel": "Environnement", + "environmentHint": "Définit CODEBUDDY_INTERNET_ENVIRONMENT. La Chine continentale doit utiliser « Chine (internal) » ; la version internationale la laisse non définie.", + "envOverseas": "International (par défaut)", + "envChina": "Chine (internal)", + "envIoa": "iOA", + "envSelfHosted": "Auto-hébergé (déploiement privé)", + "baseUrlLabel": "URL de déploiement", + "baseUrlPlaceholder": "https://codebuddy.your-company.com", + "baseUrlHint": "Enregistré comme CODEBUDDY_BASE_URL et dirige CodeBuddy vers votre point de terminaison privé. En auto-hébergement, l’environnement réseau (CODEBUDDY_INTERNET_ENVIRONMENT) reste non défini.", + "baseUrlInvalid": "Saisissez une URL http(s) valide.", + "loginHint": "Pas de clé API ? Exécutez « codebuddy » dans un terminal pour vous connecter avec votre compte Tencent." + }, + "kimiCode": { + "configManagement": "Configuration de Kimi Code", + "configDescription": "`kimi acp` n'accepte qu'un jeton de connexion enregistré ; codeg écrit donc un fournisseur géré dans ~/.kimi-code/config.toml et dépose un jeton d'accès local — l'inférence utilise toujours votre propre clé.", + "statusUnconfigured": "Pas encore configuré", + "statusDirty": "Modifications non enregistrées", + "summaryLabel": "En vigueur", + "gateReadyApiKey": "Clé API écrite dans config.toml", + "gateReadyLogin": "Connecté avec un compte Kimi", + "revealConfig": "Afficher dans le dossier", + "envOverrideWarning": "{keys} est défini et prime sur config.toml. Enregistrer ici la supprime.", + "authModeLabel": "Méthode d'authentification", + "authModeApiKey": "Clé API", + "authModeLogin": "Connexion au compte Kimi (abonnement)", + "authModeApiKeyHint": "Écrit un fournisseur géré dans config.toml et dépose le jeton d'accès pour que les sessions puissent s'ouvrir.", + "loginHint": "Exécutez `kimi login` dans un terminal pour vous connecter avec un compte Kimi par abonnement. codeg ne stocke rien et réutilise la connexion de Kimi. Enregistrer ici supprime le jeton d'accès par clé API de codeg.", + "credentialTitle": "Identifiant", + "interfaceTypeLabel": "Type de fournisseur", + "interfaceTypeHint": "Le protocole de fournisseur que parle Kimi (le `type` de config.toml). Choisissez Kimi / Moonshot pour une clé Moonshot / platform.kimi.com.", + "endpointLabel": "Point de terminaison", + "endpointCustom": "Personnalisé (compatible OpenAI)", + "endpointHint": "International = api.moonshot.ai ; Chine (clés platform.kimi.com) = api.moonshot.cn. Personnalisé pointe vers n'importe quel point de terminaison compatible OpenAI.", + "regionInternational": "International (api.moonshot.ai)", + "regionChina": "Chine (api.moonshot.cn)", + "baseUrlLabel": "URL de base", + "baseUrlHint": "Laissez vide pour utiliser la valeur par défaut du SDK du fournisseur.", + "apiKeyLabel": "Clé API", + "apiKeyHint": "Écrite dans ~/.kimi-code/config.toml et utilisée pour l'inférence. Depuis platform.kimi.com ou platform.kimi.ai.", + "vertexProjectLabel": "Projet GCP (GOOGLE_CLOUD_PROJECT)", + "vertexLocationLabel": "Région GCP (GOOGLE_CLOUD_LOCATION)", + "vertexHint": "Vertex AI utilise les identifiants par défaut de l'application Google — exécutez `gcloud auth application-default login` (aucune clé API).", + "modelTitle": "Modèle", + "modelLabel": "Modèle", + "modelHint": "L'id du modèle écrit dans config.toml. Utilisez « Tester et lister les modèles » pour voir ce à quoi votre clé accède réellement.", + "maxContextLabel": "Taille de contexte maximale", + "maxContextHint": "Obligatoire selon le schéma de Kimi : sans elle, Kimi rejette tout le bloc du modèle et chaque requête reste sans réponse. Par défaut 262144.", + "fetchModels": "Tester et lister les modèles", + "fetchModelsOk": "La clé fonctionne — {count} modèles disponibles", + "fetchModelsEmpty": "La clé fonctionne, mais aucun modèle n'a été renvoyé", + "fetchModelsFailed": "Échec du test", + "fetchModelsNeedsKey": "Saisissez d'abord une clé API et un point de terminaison", + "modelNotInList": "Ce modèle ne figure pas dans la liste accessible à votre clé — Kimi échouera avec « modèle introuvable ».", + "reasoningTitle": "Raisonnement", + "reasoningEnableLabel": "Activer", + "reasoningDescription": "Kimi n'affiche le sélecteur « Thinking » dans la zone de saisie que si le modèle déclare une capacité de raisonnement ; codeg l'écrit donc ici. S'applique aux nouvelles sessions.", + "effortsLabel": "Niveaux proposés", + "effortsHint": "Ces niveaux deviennent les entrées du sélecteur « Thinking ». Kimi transmet le niveau au fournisseur tel quel : choisissez ceux que votre modèle accepte.", + "effortsEmptyHint": "Sans aucun niveau sélectionné, la zone de saisie se limite à un simple interrupteur Off / On.", + "effortsCustomPlaceholder": "Ajouter un autre niveau", + "effortsAdd": "Ajouter", + "defaultEffortLabel": "Niveau par défaut", + "defaultEffortAuto": "Laisser Kimi choisir", + "alwaysThinkingLabel": "Le modèle raisonne toujours — retirer l'entrée Off du sélecteur", + "fixErrorsFirst": "Corrigez d'abord les champs signalés", + "errorModelRequired": "Le modèle est obligatoire", + "errorMaxContextRequired": "La taille de contexte maximale est obligatoire", + "errorMaxContextInvalid": "Doit être un entier positif", + "errorApiKeyRequired": "La clé API est obligatoire", + "errorApiKeyInvalid": "La clé API ne doit pas contenir de sauts de ligne", + "errorBaseUrlRequired": "L'URL de base est obligatoire", + "errorBaseUrlInvalid": "Doit commencer par http:// ou https://", + "errorVertexProjectRequired": "Le projet GCP est obligatoire", + "errorDefaultEffortUnlisted": "Choisissez l'un des niveaux sélectionnés ci-dessus", + "advancedTitle": "Avancé", + "authTypeLabel": "Emplacement de l'identifiant", + "authTypeApiKey": "api_key en ligne", + "authTypeEnv": "Sous-table env du fournisseur", + "authTypeHint": "Où la clé API est écrite à l'intérieur de config.toml.", + "rawEditorLabel": "Modifier config.toml directement", + "rawEditorWarning": "Enregistrer ici écrase tout le fichier tel quel et remplace les réglages structurés ci-dessus.", + "rawEditorPlaceholder": "[providers.codeg]\ntype = \"kimi\"\nbase_url = \"https://api.moonshot.cn/v1\"\napi_key = \"sk-...\"" + }, + "authModeOfficialSubscription": "Abonnement officiel", + "authModeCustomEndpoint": "Endpoint personnalisé", + "authModeCustomEndpointHint": "Configurer manuellement l'URL API et la clé API pour un endpoint personnalisé.", + "authModeModelProvider": "Fournisseur de modèle", + "modelProvider": "Fournisseur de modèle", + "modelProviderHint": "Utiliser l'URL API, la clé API et le modèle d'un fournisseur de modèle configuré.", + "selectModelProvider": "Sélectionner un fournisseur de modèle", + "noModelProviderAvailable": "Aucun fournisseur de modèle configuré pour cet agent. Allez dans les paramètres des fournisseurs de modèle pour en ajouter un.", + "claude": { + "authMode": "Mode d’authentification", + "officialSubscription": "Abonnement officiel", + "officialSubscriptionHint": "Utiliser l'abonnement officiel Anthropic, pas de clé API requise.", + "mainModel": "Modèle principal", + "reasoningModel": "Modèle de raisonnement (thinking)", + "haikuDefaultModel": "Modèle Haiku par défaut", + "sonnetDefaultModel": "Modèle Sonnet par défaut", + "opusDefaultModel": "Modèle Opus par défaut", + "customModelOption": "ID de modèle personnalisé", + "customModelOptionName": "Nom du modèle personnalisé", + "customModelOptionDescription": "Description du modèle personnalisé", + "customModelOptionHint": "Ajoute une entrée personnalisée au sélecteur de modèles de Claude (par exemple un modèle derrière une passerelle/un proxy personnalisé). Le nom et la description sont des informations d'affichage facultatives.", + "effortLevel": "Niveau de raisonnement", + "effortLevelDefault": "Niveau par défaut", + "effortLevel_low": "Bas", + "effortLevel_medium": "Moyen", + "effortLevel_high": "Élevé", + "effortLevel_xhigh": "Très Élevé", + "sendAttributionHeader": "Envoyer l'identifiant d'attribution/facturation à l'API", + "sendAttributionHeaderAria": "Envoyer l'identifiant d'attribution/facturation de Claude Code à l'API", + "disableNonessentialTraffic": "Désactiver la télémétrie ou les requêtes réseau superflues", + "disableNonessentialTrafficAria": "Désactiver la télémétrie ou les requêtes réseau superflues de Claude Code" + }, + "dialogs": { + "confirmDeleteProvider": "Supprimer le provider {providerId} ?", + "confirmDeleteProviderDescription": "La configuration OpenCode et auth JSON seront mises à jour ensemble. Cette action est irréversible.", + "confirmUninstall": "Désinstaller {name} ?", + "confirmUninstallDescription": "Cela supprime la version installée localement. Vous pouvez réinstaller plus tard.", + "customInstallTitle": "Installation personnalisée de {name}", + "customInstallDescription": "Saisissez la version à installer. Cela réinstalle et remplace la version actuellement installée.", + "customInstallVersionLabel": "Numéro de version", + "customInstallInvalid": "Saisissez un numéro de version valide, par ex. 1.2.3.", + "customInstallSubmit": "Installer" + }, + "errors": { + "windowsFileLocked": "Les fichiers de {name} sont utilisés par une session en cours, Windows ne peut donc pas les remplacer. Fermez toutes les sessions {name}, puis réessayez.", + "nativeJsonMustBeObject": "La configuration JSON native doit être un objet", + "nativeJsonInvalid": "Erreur de format de configuration JSON native : {message}", + "openCodeAuthMustBeObject": "OpenCode auth.json doit être un objet JSON", + "openCodeAuthInvalid": "Erreur de format OpenCode auth.json : {message}", + "authMustBeObject": "auth.json doit être un objet JSON", + "authInvalid": "Erreur de format auth.json : {message}", + "providerIdPattern": "L’ID du provider n’accepte que lettres, chiffres, underscore, point et tiret", + "providerExists": "Le provider {providerId} existe déjà", + "modelIdPattern": "L’ID du modèle n’accepte que lettres, chiffres, underscore, point, deux-points et tiret", + "modelExists": "Le modèle {modelId} existe déjà" + }, + "warnings": { + "nativeJsonRecoveredStructured": "La configuration JSON native est invalide ; réinitialisée en configuration structurée", + "nativeJsonRecoveredOpenCode": "La configuration JSON native est invalide ; réinitialisée en configuration structurée OpenCode", + "openCodeAuthRecovered": "OpenCode auth.json est invalide ; réinitialisé en configuration par défaut", + "authRecoveredStructured": "auth.json est invalide ; réinitialisé en configuration structurée" + }, + "toasts": { + "agentActionCompleted": "{name} {action} terminé", + "agentActionFailed": "{name} {action} échoué", + "localVersion": "Version locale : {version}", + "installCompletedVersionLater": "Installation terminée, la version sera mise à jour à la prochaine vérification", + "uninstallCompleted": "Désinstallation de {name} terminée", + "uninstallFailed": "Échec de la désinstallation de {name}", + "localVersionRemoved": "Version locale supprimée", + "saveAgentOrderFailed": "Échec de l’enregistrement de l’ordre des agents", + "saveAgentSwitchFailed": "Échec de l’enregistrement du switch agent", + "saveEnvFailed": "Échec de l’enregistrement des variables d’environnement", + "grokSaved": "Configuration Grok enregistrée", + "saveGrokNativeFailed": "Échec de l'enregistrement de la configuration native Grok", + "saveGrokApiKeyFailed": "Paramètres enregistrés, mais la clé API n'a pas pu être enregistrée", + "cursorSaved": "Configuration Cursor enregistrée", + "saveCursorConfigFailed": "Échec de l'enregistrement de la configuration Cursor", + "codexSaved": "Configuration Codex enregistrée", + "saveCodexNativeFailed": "Échec de l’enregistrement de la configuration native Codex", + "geminiSaved": "Configuration Gemini enregistrée", + "saveGeminiFailed": "Échec de l’enregistrement de la configuration Gemini", + "providerDeleted": "Provider {providerId} supprimé", + "providerDeleteFailed": "Échec de suppression du provider {providerId}", + "providerSaved": "Provider {providerId} enregistré", + "saveProviderFailed": "Échec d’enregistrement du provider {providerId}", + "openCodeConfigSynced": "La configuration OpenCode et auth JSON ont été synchronisés.", + "openCodeSaved": "Configuration OpenCode enregistrée", + "saveOpenCodeFailed": "Échec de l’enregistrement de la configuration OpenCode", + "openClawSaved": "Configuration OpenClaw enregistrée", + "saveOpenClawFailed": "Échec de l’enregistrement de la configuration OpenClaw", + "configSaved": "Configuration enregistrée", + "configSavedHint": "Les sessions existantes doivent être rouvertes pour prendre effet", + "saveConfigManagementFailed": "Échec de l’enregistrement de la gestion de configuration", + "clineSaved": "Configuration Cline enregistrée", + "saveClineFailed": "Échec de l'enregistrement de la configuration Cline", + "hermesSaved": "Configuration Hermes enregistrée", + "saveHermesFailed": "Échec de l'enregistrement de la configuration Hermes", + "codeBuddySaved": "Configuration CodeBuddy enregistrée", + "saveCodeBuddyFailed": "Échec de l'enregistrement de la configuration CodeBuddy", + "kimiCodeSaved": "Configuration de Kimi Code enregistrée", + "saveKimiCodeFailed": "Échec de l'enregistrement de la configuration de Kimi Code", + "deepseekSaved": "Configuration DeepSeek enregistrée", + "saveDeepSeekFailed": "Échec de l'enregistrement de la configuration DeepSeek", + "modelProviderRequired": "Veuillez sélectionner un fournisseur de modèle avant d'enregistrer.", + "affectedRunningSessions": "{count, plural, one {# session active doit se reconnecter pour appliquer la modification} other {# sessions actives doivent se reconnecter pour appliquer la modification}}", + "providerConnected": "{providerId} connecté", + "connectFailed": "Échec de la connexion de {providerId}", + "providerDisconnected": "{providerId} déconnecté", + "disconnectFailed": "Échec de la déconnexion de {providerId}", + "catalogRefreshed": "Catalogue actualisé — {count} fournisseurs", + "catalogRefreshFailed": "Échec de l''actualisation du catalogue", + "piSaved": "Configuration Pi enregistrée", + "savePiFailed": "Échec de l'enregistrement de la config Pi", + "piRuntimeSaved": "Exécution Pi enregistrée", + "savePiRuntimeFailed": "Échec de l'enregistrement de l'exécution Pi", + "piBinaryInstalled": "pi installé", + "piBinaryInstallFailed": "Échec de l'installation de pi", + "piBinaryUninstalled": "pi désinstallé", + "piBinaryUninstallFailed": "Échec de la désinstallation de pi", + "savePiTrustFailed": "Échec de l'enregistrement de la confiance de l'espace de travail" + }, + "version": { + "statusLabel": "Statut de version", + "notInstalled": "Non installé", + "remoteLocal": "Distant : {remoteVersion} · Local : {localVersion}", + "localOnly": "Local : {localVersion}", + "localInstalled": "{versionText}. Installé.", + "platformUnsupported": "{versionText}. La plateforme actuelle ne prend pas en charge cet agent.", + "uvxNotReady": "{versionText}. Le runtime uv n'est pas installé — installez-le depuis la vérification uv ci-dessous pour utiliser cet agent.", + "clickInstall": "{versionText}. Cliquez sur Installer à droite.", + "localUnrecognized": "{versionText}. La version locale n’est pas comparable ; essayez une mise à niveau pour écraser l’installation.", + "upgradeAvailable": "{versionText}. Mise à niveau disponible.", + "remoteUnavailable": "{versionText}. La version distante est actuellement indisponible.", + "latest": "{versionText}. Déjà à jour." + }, + "adapter": { + "label": "Adaptateur ACP", + "badge": "Adaptateur ACP", + "badgeHint": "Pour cet agent, Codeg installe un paquet adaptateur ACP, pas la CLI de l'éditeur. Les deux sont indépendants et partagent la même configuration.", + "learnMore": "En savoir plus", + "missingWithNative": "Votre {nativeLabel} a été trouvée dans {nativePath}. Codeg pilote les agents via ACP, or cette CLI ne parle pas ACP : Codeg a donc besoin d'un paquet adaptateur distinct, {adapterPackage}, maintenu par le projet Agent Client Protocol (à l'origine Zed). Il embarque son propre runtime, ne modifie ni ne remplace jamais votre commande {nativeCmd}, et lit le même {configDir} — votre connexion et vos réglages sont conservés. Installez-le ci-dessous.", + "missing": "Codeg pilote les agents via ACP, or la {nativeLabel} ne parle pas ACP : Codeg a donc besoin d'un paquet adaptateur distinct, {adapterPackage}, maintenu par le projet Agent Client Protocol (à l'origine Zed). Il embarque son propre runtime, la CLI {nativeCmd} n'est donc pas un prérequis ; si vous l'avez déjà, les deux coexistent et partagent la connexion et les réglages de {configDir}. Installez-le ci-dessous.", + "readyWithNative": "L'adaptateur {adapterCmd} est installé : c'est lui que Codeg lance, pas votre {nativeCmd} situé dans {nativePath}. Ce sont des paquets distincts qui coexistent, et tous deux lisent {configDir} : connexion et réglages sont partagés.", + "ready": "L'adaptateur {adapterCmd} est installé : c'est lui que Codeg lance. Il embarque son propre runtime, la {nativeLabel} n'est donc pas nécessaire ; si vous l'installez plus tard, les deux coexistent et partagent {configDir}." + }, + "cline": { + "configDescription": "Configurez le fournisseur API et les identifiants Cline. Les paramètres sont enregistrés dans ~/.cline/data/." + }, + "opencodePlugins": { + "title": "Plugins OpenCode", + "declared": "Plugins déclarés", + "noPlugins": "Aucun plugin déclaré dans opencode.json", + "status": { + "installed": "Installé", + "missing": "Non installé" + }, + "installAll": "Installer tous les manquants", + "pinVersions": "Fixer les versions @latest", + "install": "Installer", + "uninstall": "Désinstaller", + "refresh": "Actualiser", + "success": "Tous les plugins ont été installés avec succès", + "failed": "L'opération du plugin a échoué" + }, + "pi": { + "configManagement": "Configuration de Pi", + "configDescription": "Pi s'authentifie via la clé API de votre fournisseur de modèle. La clé est écrite dans ~/.pi/agent/auth.json et le choix du modèle dans settings.json.", + "providerLabel": "Fournisseur", + "modelLabel": "Modèle", + "thinkingLabel": "Réflexion", + "thinking": { + "off": "Désactivé", + "low": "Faible", + "medium": "Moyen", + "high": "Élevé", + "minimal": "Minimal", + "xhigh": "Très élevé" + }, + "apiKeyLabel": "Clé API", + "apiKeyHint": "Enregistrée dans ~/.pi/agent/auth.json pour le fournisseur sélectionné.", + "apiKeySetPlaceholder": "•••••• (enregistrée — laisser vide pour conserver)", + "saveConfig": "Enregistrer la config Pi", + "providerModelRequired": "Le fournisseur et le modèle sont requis", + "runtimeTitle": "Exécution", + "runtimeDescription": "Choisissez quel binaire pi s'exécute. Utilisez celui par défaut ou pointez vers votre propre build de pi.", + "modeDefault": "pi par défaut", + "modeDefaultHint": "Utilise l'adaptateur pi-acp intégré avec le pi de votre PATH. Installer pi : npm install -g @earendil-works/pi-coding-agent", + "modeCustom": "pi personnalisé", + "modeCustomHint": "Exécutez votre propre build, installation ou wrapper de pi.", + "commandLabel": "Commande ou chemin pi", + "commandHint": "Un chemin absolu, un nom de commande dans le PATH, ou un script wrapper (par ex. ./pi-test.sh d'un monorepo).", + "commandNotFound": "Commande introuvable", + "validate": "Valider", + "advanced": "Avancé", + "configDirLabel": "Répertoire de config (PI_CODING_AGENT_DIR)", + "sessionDirLabel": "Répertoire des sessions (PI_CODING_AGENT_SESSION_DIR)", + "flagsHint": "pi-acp ne transmet pas les options pi personnalisées (--approve, -e, …) — encapsulez pi dans un script et pointez-y la commande.", + "customIncomplete": "Saisissez une commande pi pour enregistrer", + "saveRuntime": "Enregistrer l'exécution", + "providerPlaceholder": "Sélectionner un fournisseur", + "customProvider": "Fournisseur personnalisé…", + "providerIdLabel": "ID du fournisseur", + "apiProtocolLabel": "Protocole API", + "baseUrlLabel": "Point de terminaison API (Base URL)", + "customProviderHint": "Définit un fournisseur dans ~/.pi/agent/models.json vers votre point de terminaison. La plupart des serveurs auto-hébergés ou proxy utilisent openai-completions.", + "baseUrlRequired": "Le point de terminaison API (Base URL) est requis", + "binaryTitle": "binaire pi (pi-coding-agent)", + "binaryDescription": "pi-acp exécute ce binaire pi. Installez-le ici, ou faites pointer pi-acp vers votre propre build ci-dessous.", + "binaryInstalled": "Installé", + "binaryMissing": "Non installé", + "binaryChecking": "Vérification…", + "installBinary": "Installer pi", + "installing": "Installation…", + "recheck": "Revérifier", + "configDirSkillsNote": "Avec un répertoire de configuration personnalisé, les compétences, experts et outils bureautiques gérés dans les Paramètres ne s'appliquent pas à ce pi — gérez ses compétences directement dans ce dossier.", + "projectTrustTitle": "Confiance du projet", + "projectTrustDescription": "Dossiers depuis lesquels vous avez autorisé pi à charger des fichiers de projet. Un dossier de confiance permet aux .pi/extensions de ce dépôt d'exécuter du code au démarrage de pi, s'applique à tous les dossiers qu'il contient et sert aussi lorsque vous lancez pi dans un terminal.", + "projectTrustLoading": "Chargement…", + "projectTrustEmpty": "Aucun dossier n'a encore été décidé.", + "projectTrustTrusted": "Approuvé", + "projectTrustDenied": "Non approuvé", + "projectTrustRevoke": "Révoquer", + "reasoningTitle": "Raisonnement", + "reasoningEnableLabel": "Activer", + "reasoningDescription": "pi n'envoie un effort de raisonnement que pour un modèle qui le déclare — sur un modèle non déclaré, tous les niveaux sont ramenés à Off, si bien que le sélecteur du composeur revient en arrière dès qu'on y touche. Écrit dans l'entrée de ce modèle dans models.json.", + "levelsLabel": "Niveaux disponibles", + "levelsHint": "Ils deviennent les lignes du sélecteur de raisonnement du composeur. Choisissez ceux que votre endpoint accepte ; pi refuse tout niveau absent d'ici.", + "levelsEmptyError": "Choisissez au moins un niveau — sans aucun, pi retombe sur Off.", + "wireValuesTitle": "Avancé : valeurs envoyées au fournisseur", + "wireValuesHint": "Laissez vide pour envoyer le nom du niveau tel quel. Renseignez-le si votre endpoint attend autre chose — les backends façon Google veulent LOW / HIGH.", + "defaultLevelUnlisted": "Ce niveau n'est pas dans la liste ci-dessus — pi le ramènerait plus bas." + }, + "addCustomAgent": "Ajouter un agent personnalisé", + "addCustomAgentHint": "Enregistrez n'importe quel agent compatible ACP. Choisissez-en un dans le registre ACP public ou collez ses informations de registre.", + "customAgentFromRegistry": "Registre ACP", + "customAgentManual": "Manuel", + "customAgentSearchPlaceholder": "Rechercher des agents…", + "customAgentLoadingCatalog": "Chargement du registre ACP…", + "customAgentRetry": "Réessayer", + "customAgentNoResults": "Aucun agent correspondant", + "customAgentAdd": "Ajouter", + "customAgentAlreadyAdded": "Ajouté", + "customAgentUnsupportedPlatform": "Aucune version disponible pour cette plateforme", + "customAgentAdded": "{name} ajouté", + "customAgentIdLabel": "ID du registre", + "customAgentNameLabel": "Nom affiché", + "customAgentVersionLabel": "Version", + "customAgentSpecLabel": "Distribution (JSON)", + "customAgentSpecHint": "Même forme que l’objet distribution du registre ACP : canaux npx, uvx et binary, ou collez une entrée de registre complète. Pour npx/uvx, cmd est l’exécutable installé par le paquet — déduit du nom du paquet s’il est omis, à préciser donc quand ils diffèrent. binary est organisé par clé de plateforme (cette machine : {platform}) ; son cmd est le chemin de lancement dans l’archive et sha256 vérifie éventuellement le téléchargement.", + "customAgentTemplateLabel": "Modèles", + "customAgentKindLabel": "Lancer via", + "customAgentInvalidJson": "JSON invalide", + "customAgentNoDistribution": "Aucune distribution npx, uvx ou binary trouvée", + "customAgentCancel": "Annuler", + "customAgentSave": "Ajouter l'agent", + "customAgentSaveChanges": "Enregistrer les modifications", + "customAgentEdit": "Modifier l’agent", + "customAgentEditHint": "Modifiez le nom, l’icône, la distribution et les déclarations de skills. L’ID de l’agent ne peut pas être modifié.", + "customAgentEditNotFound": "Agent personnalisé {id} introuvable", + "customAgentSaved": "{name} enregistré", + "customAgentVersionProbeLabel": "Commande de version (facultatif)", + "customAgentVersionProbeHint": "Commande qui affiche la version installée localement. Laissée vide, codeg exécute la commande de l’agent avec --version.", + "customAgentRemove": "Supprimer l'agent", + "customAgentRemoveHint": "Supprime la définition de l'agent. Les conversations existantes conservent leur historique ; l'agent ne peut simplement plus être lancé.", + "customAgentIconLabel": "Icône (facultatif)", + "customAgentIconUpload": "Téléverser", + "customAgentIconReplace": "Remplacer", + "customAgentIconClear": "Retirer l'icône", + "customAgentIconHint": "Enregistrée avec l'agent, elle fonctionne donc hors ligne. Sans icône, une initiale colorée est utilisée.", + "customAgentSkillsLabel": "Skills (.agents/skills partagé)", + "customAgentSkillsHint": "Déclare que cet agent lit le magasin partagé .agents/skills (répertoires global et projet) et l'ajoute à toutes les matrices de compétences. Les compétences qui y sont liées sont visibles par tous les agents qui lisent ce magasin partagé.", + "customAgentSkillsDirLabel": "Répertoire de skills dédié", + "customAgentSkillsDirHint": "Chemin absolu du répertoire depuis lequel cet agent charge ses skills — son propre magasin, en plus du magasin partagé ou à sa place. ~ est remplacé par le répertoire personnel ; les skills liées y sont placées en premier.", + "customAgentMcpLabel": "Prise en charge de MCP", + "customAgentMcpHint": "Transmet le compagnon MCP intégré de codeg à cet agent au démarrage de la session — le canal derrière la délégation, le retour en direct et les outils de tâches. Désactivez-le pour un agent qui refuse les serveurs MCP et ne parvient pas à se connecter ; le changement s'applique à la prochaine connexion.", + "customAgentIconNotAnImage": "Choisissez un fichier image.", + "customAgentIconTooLarge": "L'icône doit faire moins de {limit} Ko.", + "customAgentIconReadFailed": "Impossible de lire cette image.", + "customAgentRemoveConfirm": "Supprimer {name} ? Les conversations existantes sont conservées, mais l'agent ne pourra plus être lancé.", + "customAgentRemoveWithData": "Supprimer aussi l'historique de conversation enregistré", + "customAgentRemoved": "{name} supprimé", + "customAgentBadge": "Personnalisé", + "customAgentNotLaunchable": "Cet agent ne peut pas démarrer ici : {reason}" + }, + "SettingsPages": { + "agentsLoading": "Chargement des paramètres des agents...", + "skillPacksLoading": "Chargement des packs de compétences…" + }, + "GeneralSettings": { + "loading": "Chargement...", + "sectionTitle": "Général", + "sectionDescription": "Préférences centralisées pour le terminal par défaut, l'accélération du rendu et la délégation multi-agents.", + "terminalTitle": "Terminal par défaut", + "terminalDescription": "Choisissez le shell utilisé à l'ouverture de nouveaux onglets de terminal depuis la barre de terminal ou l'arborescence des fichiers. Les agents l'utilisent aussi lorsqu'ils demandent à codeg d'exécuter une ligne de commande complète.", + "terminalSystemDefault": "Par défaut système", + "terminalPowerShell7": "PowerShell 7 (pwsh)", + "terminalWindowsPowerShell": "Windows PowerShell", + "terminalCmd": "Invite de commandes (cmd)", + "terminalSaveFailed": "Échec de l’enregistrement des paramètres du terminal : {message}", + "terminalShellCustom": "Chemin personnalisé", + "terminalShellCustomPath": "Chemin du shell", + "terminalShellCustomPlaceholder": "/usr/local/bin/fish", + "terminalShellCustomSave": "Enregistrer", + "terminalShellCustomHint": "Indiquez un chemin absolu ou un nom résolvable via PATH.", + "terminalShellNotInstalled": "non installé", + "terminalShellNotFoundWarning": "Ce chemin n’existe pas sur cet hôte.", + "terminalCurrentShell": "Actuellement utilisé : {path}", + "renderingDescription": "Désactivez l’accélération matérielle si l’application affiche un écran noir ou des défauts de rendu (fréquent sur certaines GPU AMD ou GPU Intel intégrées). N’a d’effet que sur la version Windows de bureau.", + "disableHardwareAcceleration": "Désactiver l’accélération matérielle", + "renderingSaveFailed": "Échec de l’enregistrement des paramètres de rendu : {message}", + "restartRequired": "Enregistré. Redémarrez l’application pour appliquer la modification.", + "restartNow": "Redémarrer maintenant", + "restartFailed": "Échec du redémarrage : {message}", + "loadFailed": "Échec du chargement : {message}" + }, + "LoginPage": { + "documentTitle": "Connexion - codeg", + "brand": "Codeg", + "subtitle": "Saisissez votre jeton d'accès pour vous connecter à l'application de bureau", + "tokenPlaceholder": "Jeton d'accès", + "connect": "Se connecter", + "connecting": "Connexion...", + "helpText": "Vous trouverez votre jeton dans l'application de bureau sous Paramètres → Service Web", + "invalidToken": "Jeton invalide. Veuillez vérifier et réessayer.", + "connectionFailed": "Échec de la connexion (HTTP {status})", + "networkError": "Impossible de se connecter au serveur" + }, + "CommitPage": { + "title": "Valider", + "invalidFolderId": "ID de dossier invalide", + "loadingRepo": "Chargement du dépôt..." + }, + "MergePage": { + "title": "Résoudre les conflits", + "invalidFolderId": "ID de dossier invalide", + "loadingRepo": "Chargement du dépôt...", + "localVersion": "Local (Le nôtre)", + "result": "Résultat", + "remoteVersion": "Distant (Le leur)", + "acceptLocal": "Accepter le local", + "acceptRemote": "Accepter le distant", + "markResolved": "Marquer comme résolu", + "abortMerge": "Abandonner", + "completeMerge": "Terminer la fusion", + "unresolvedConflicts": "Il reste des marqueurs de conflit non résolus dans ce fichier", + "fileResolved": "Fichier résolu avec succès", + "allResolved": "Tous les conflits sont résolus", + "conflictFiles": "Fichiers en conflit", + "loadingFile": "Chargement du fichier...", + "preparingMerge": "Préparation de la fusion...", + "selectFile": "Sélectionner un fichier à résoudre", + "noConflicts": "Aucun fichier en conflit", + "skipFile": "Passer", + "abortSuccess": "Opération abandonnée", + "applyAllNonConflicting": "Appliquer tous les changements non conflictuels", + "applyLeftNonConflicting": "Appliquer local", + "applyRightNonConflicting": "Appliquer distant" + }, + "ImportSessions": { + "title": "Importer les sessions locales", + "scanningTitle": "Analyse des sessions locales des agents…", + "scanningHint": "Parcours du stockage local des sessions de chaque agent. Cela peut prendre un moment avec de gros historiques. Les sessions déjà importées sont actualisées au passage.", + "scanFailed": "Échec de l'analyse", + "retry": "Réessayer", + "rescan": "Réanalyser", + "empty": "Aucune session locale trouvée", + "emptyHint": "Aucun stockage de sessions d'agent n'a été trouvé sur cette machine.", + "noMatches": "Aucune session ne correspond aux filtres actuels", + "searchPlaceholder": "Rechercher un titre ou un chemin…", + "allAgents": "Tous les agents", + "onlyImportable": "Importables uniquement", + "selectAll": "Tout sélectionner", + "clearSelection": "Effacer", + "expandAll": "Tout développer", + "collapseAll": "Tout réduire", + "summaryCounts": "{total} sessions · {importable} importables · {folders} dossiers", + "noFolderSkipped": "{count} sans dossier de projet ignorées", + "folderNew": "Nouveau", + "folderCounts": "{importable}/{total} importables", + "toggleFolderAria": "Sélectionner toutes les sessions importables de {name}", + "toggleSessionAria": "Sélectionner la session {title}", + "statusImported": "Importée", + "statusDeleted": "Supprimée", + "untitled": "Session sans titre", + "messageCount": "{count} messages", + "selectedCount": "{count} sélectionnées", + "importSelected": "Importer la sélection", + "importing": "Importation…", + "close": "Fermer", + "doneTitle": "Importation terminée", + "doneImported": "Importées", + "doneUpdated": "Actualisées", + "doneSkipped": "Ignorées", + "doneCreatedFolders": "Dossiers créés", + "doneNotFound": "Introuvables", + "doneFailed": "Échouées", + "continueImport": "Continuer l'import", + "toasts": { + "importFailed": "Échec de l'import : {message}" + } + }, + "Folder": { + "workspaceStatus": { + "degradedTitle": "Mises à jour en temps réel indisponibles", + "degradedHint": "L’observateur n’a pas pu démarrer (par ex. permission refusée). Actualisez manuellement pour voir les modifications.", + "retry": "Réessayer", + "retrying": "Nouvelle tentative..." + }, + "common": { + "all": "Tout", + "cancel": "Annuler", + "close": "Fermer", + "closeOthers": "Fermer les autres", + "closeAll": "Tout fermer", + "confirm": "Confirmer", + "save": "Enregistrer", + "delete": "Supprimer", + "rename": "Renommer", + "loading": "Chargement...", + "refresh": "Actualiser", + "refreshing": "Actualisation...", + "create": "Créer", + "createAndSwitch": "Créer et basculer", + "openFile": "Ouvrir le fichier", + "viewDiff": "Voir le Diff", + "push": "Pousser..." + }, + "statusLabels": { + "in_progress": "En cours", + "pending_review": "Revue", + "completed": "Terminé", + "cancelled": "Annulé" + }, + "sidebar": { + "title": "Discussions", + "locateActiveConversation": "Localiser la conversation active", + "expandAllGroups": "Développer tous les groupes", + "collapseAllGroups": "Réduire tous les groupes", + "newConversation": "Nouvelle conversation", + "newConversationShort": "Nouvelle", + "newChat": "Nouvelle conversation", + "search": "Rechercher", + "noConversationsFound": "Aucune conversation trouvée.", + "importLocalSessions": "Importer les sessions locales", + "importing": "Import en cours...", + "error": "Erreur : {message}", + "completeAllSessions": "Terminer toutes les sessions", + "completeAllReviewTitle": "Terminer toutes les sessions en revue ?", + "completeAllReviewDescription": "Cela marquera comme terminées toutes les {count, plural, one {# session} other {# sessions}} en Revue.", + "completing": "Finalisation...", + "toasts": { + "importedSessions": "{imported, plural, one {# session} other {# sessions}} importée(s), {skipped} ignorée(s)", + "importedAndUpdated": "{imported, plural, one {# session} other {# sessions}} importée(s), {updated, plural, one {# titre} other {# titres}} mis à jour, {skipped} ignorée(s)", + "updatedTitles": "{updated, plural, one {# titre} other {# titres}} mis à jour, {skipped} ignorée(s)", + "noNewSessionsFound": "Aucune nouvelle session trouvée ({skipped} ignorée(s))", + "importFailed": "Échec de l'import : {message}", + "reviewCompleted": "{count, plural, one {# session en revue} other {# sessions en revue}} marquée(s) comme terminée(s)", + "completeReviewFailed": "Échec de la finalisation des sessions en revue : {message}", + "folderOpened": "Dossier {name} ouvert", + "folderRemoved": "Dossier {name} retiré", + "openFolderFailed": "Échec de l'ouverture du dossier", + "removeFolderFailed": "Échec de la suppression du dossier : {message}", + "reorderFoldersFailed": "Échec du réordonnancement des dossiers : {message}", + "changeFolderColorFailed": "Échec du changement de couleur : {message}", + "setFolderAliasFailed": "Échec de la définition de l'alias : {message}", + "changeFolderDefaultAgentFailed": "Échec de la définition de l'agent par défaut : {message}" + }, + "statsLabel": "{folders} dossiers · {convos} conversations", + "reorderHandle": "Glisser pour réorganiser", + "openFolder": "Ouvrir le dossier", + "searchPlaceholder": "Rechercher des conversations...", + "viewOptions": "Options d'affichage", + "showCompleted": "Afficher les conversations terminées", + "showWorktrees": "Afficher les dossiers de worktree", + "showRecent": "Afficher le groupe Récents", + "moreOptions": "Plus d'options", + "sortBy": "Trier par", + "sortByCreatedAt": "Date de création", + "sortByUpdatedAt": "Date de mise à jour", + "sectionOrder": "Ordre des sections", + "sectionOrderMoveUp": "Monter", + "sectionOrderMoveDown": "Descendre", + "sectionOrderItemLabel": "{name} — position {position} sur {total}", + "statusRunningBadge": "En cours", + "runningCountBadge": "{count, plural, one {# session en cours} other {# sessions en cours}}", + "statusCancelledBadge": "Annulé", + "worktreeRemovedBadge": "Worktree d'origine supprimé", + "conversationCountUnit": "{count, plural, one {# conversation} other {# conversations}}", + "emptyFolderHint": "Aucune conversation", + "noMatchingConversations": "Aucune conversation correspondante", + "noUnfinishedConversations": "Aucune conversation en cours. Activez « Afficher les terminées » dans le menu en haut à droite.", + "removeFolderConfirmTitle": "Retirer le dossier de l'espace de travail ?", + "removeFolderConfirmDescription": "Retirer \"{name}\" de l'espace de travail ? Les onglets et terminaux associés seront fermés.", + "folderHeaderMenu": { + "manageConversations": "Gérer les conversations…", + "manageLinks": "Dossiers liés", + "changeColor": "Changer la couleur", + "useThemeColor": "Utiliser le thème de l'app", + "setDefaultAgent": "Définir l'agent par défaut", + "defaultAgentNone": "Aucun (utiliser la valeur globale)", + "agentUnavailableSuffix": "(indisponible)", + "loadingAgents": "Chargement des agents…", + "setAlias": "Définir un alias…", + "setAliasTitle": "Définir l'alias du dossier", + "setAliasPlaceholder": "Saisir un alias (laisser vide pour effacer)", + "setAliasSave": "Enregistrer", + "setAliasCancel": "Annuler", + "removeFromWorkspace": "Retirer de l'espace de travail" + }, + "manageConversations": { + "title": "Gérer les conversations", + "searchPlaceholder": "Rechercher par titre…", + "agentFilterAll": "Tous les agents", + "statusFilterAll": "Tous les statuts", + "folderFilterAll": "Tous les dossiers", + "branchFilterAll": "Toutes les branches", + "branchNone": "Aucune branche", + "branchSearchPlaceholder": "Rechercher des branches…", + "noMatchingBranches": "Aucune branche correspondante", + "selectAllVisible": "Tout sélectionner", + "deselectAll": "Tout désélectionner", + "selectedCount": "{count} sélectionnée(s)", + "matchedCount": "{count} correspondance(s)", + "untitledConversation": "Conversation sans titre", + "setStatus": "Définir le statut…", + "deleteSelected": "Supprimer", + "noConversations": "Aucune conversation dans ce dossier.", + "noConversationsWorkspace": "Aucune conversation dans l'espace de travail.", + "noMatchingConversations": "Aucune conversation ne correspond aux filtres.", + "confirmDeleteTitle": "Supprimer {count} conversation(s) ?", + "confirmDeleteDescription": "Cette action est irréversible.", + "toastDeleted": "{count} conversation(s) supprimée(s)", + "toastStatusUpdated": "Statut mis à jour pour {count} conversation(s)", + "toastOpFailed": "Échec de l'opération : {message}" + }, + "sectionPinned": "Épinglées", + "sectionFolders": "Dossiers", + "sectionChats": "Discussion", + "sectionRecent": "Récents", + "noChats": "Aucune discussion", + "noRecent": "Aucune conversation récente", + "showMoreRecent": "Afficher plus ({count})", + "noFolders": "Aucun dossier ouvert", + "newChatAction": "Nouvelle discussion", + "automations": "Automatisations", + "tasks": "Tâches à faire", + "loadingSubsessions": "Chargement des sous-conversations…" + }, + "conversation": { + "reloadFailed": "Échec du rechargement de la conversation : {message}", + "reloaded": "Conversation rechargée", + "reload": "Recharger", + "activeConversationIndicator": "Conversation active", + "newConversation": "Nouvelle conversation", + "closeConversation": "Fermer la conversation", + "copyText": "Copier le texte", + "copyTextSuccess": "Copié", + "copyTextFailed": "Échec de la copie", + "forkSession": "Dupliquer la session", + "forkSessionSuccess": "Session dupliquée avec succès", + "forkSessionFailed": "Échec de la duplication de la session : {error}", + "exportConversation": "Exporter la conversation", + "exportImage": "Image", + "exportMarkdown": "Markdown", + "exportHtml": "HTML", + "exportSuccess": "Conversation exportée", + "exportFailed": "Échec de l'exportation", + "exportImageTooLong": "La conversation est trop longue pour être exportée en image", + "exportLabels": { + "untitledConversation": "Conversation sans titre", + "agent": "Agent", + "model": "Modèle", + "status": "Statut", + "started": "Début", + "updated": "Mis à jour", + "tokens": "Statistiques de tokens", + "duration": "Durée", + "inputTokens": "Entrée", + "outputTokens": "Sortie", + "cacheRead": "Cache lu", + "cacheWrite": "Cache écrit", + "user": "Utilisateur", + "assistant": "Assistant", + "system": "Système", + "toolResult": "Résultat", + "toolError": "Erreur" + }, + "moreActions": "Plus d’actions" + }, + "sessionDetails": { + "menuLabel": "Détails de la session", + "noActiveSession": "Aucune session active", + "title": "Détails de la session", + "subtitle": "Métadonnées de la session et utilisation des tokens", + "fieldTitle": "Titre", + "untitled": "Conversation sans titre", + "sessionId": "ID de session", + "externalId": "ID d'extension", + "agent": "Agent", + "model": "Modèle", + "status": "Statut", + "gitBranch": "Branche Git", + "parentId": "Session parente", + "tokensHeading": "Utilisation des tokens", + "totalTokens": "Total", + "inputTokens": "Entrée", + "outputTokens": "Sortie", + "cacheWrite": "Cache écrit", + "cacheRead": "Cache lu", + "contextWindow": "Fenêtre de contexte", + "duration": "Durée", + "loadingStats": "Chargement de l'utilisation des tokens…", + "loadFailed": "Échec du chargement de l'utilisation des tokens", + "noStats": "Aucune utilisation enregistrée", + "timestampsHeading": "Horodatage", + "createdAt": "Créé", + "updatedAt": "Mis à jour", + "none": "—", + "copyField": "Copier {field}", + "copiedField": "{field} copié" + }, + "conversationCard": { + "untitledConversation": "Conversation sans titre", + "newConversation": "Nouvelle conversation", + "rename": "Renommer", + "status": "Statut", + "delete": "Supprimer", + "importLocalSessions": "Importer les sessions locales", + "importing": "Import en cours...", + "renameConversation": "Renommer la conversation", + "deleteConversationTitle": "Supprimer la conversation ?", + "deleteConversationDescription": "Cela supprimera \"{title}\". Cette action est irréversible.", + "cancel": "Annuler", + "save": "Enregistrer", + "pin": "Épingler", + "unpin": "Désépingler", + "markCompleted": "Marquer comme terminé", + "reopen": "Rouvrir", + "expandSubsessions": "Développer les sous-conversations", + "collapseSubsessions": "Réduire les sous-conversations" + }, + "search": { + "dialogTitle": "Rechercher", + "dialogTitleWithFolder": "Rechercher — {name}", + "tabConversations": "Conversations", + "tabFiles": "Fichiers", + "placeholder": "Rechercher des conversations...", + "filePlaceholder": "Rechercher des fichiers ou répertoires...", + "allAgents": "Tout", + "searching": "Recherche...", + "typeToSearch": "Tapez pour rechercher des conversations", + "typeToSearchFiles": "Tapez pour rechercher des fichiers ou répertoires", + "noResults": "Aucun résultat trouvé.", + "untitledConversation": "Conversation sans titre" + }, + "folderTitleBar": { + "showSidebar": "Afficher la barre latérale", + "hideSidebar": "Masquer la barre latérale", + "toggleTerminal": "Basculer le terminal", + "toggleAuxPanel": "Basculer le panneau auxiliaire", + "search": "Rechercher", + "openSettings": "Ouvrir les paramètres", + "backToConversations": "Retour aux conversations", + "withShortcut": "{label} (raccourci : {shortcut})" + }, + "statusBar": { + "connection": { + "connected": "Connecté", + "connecting": "Connexion...", + "prompting": "Réponse...", + "error": "Erreur de connexion", + "disconnected": "Déconnecté", + "tooltip": "{agent} : {status}", + "tooltipError": "{agent} : {error}", + "title": "Connexion de l'agent", + "triggerAria": "Connexion de l'agent : {status}", + "workingDir": "Répertoire de travail", + "sessionId": "ID de session", + "viewerNote": "Rattaché à une session appartenant à un autre client : la reconnexion ne rattache que cette vue.", + "reconnectInterrupts": "La reconnexion redémarre l'agent et interrompt le travail en cours.", + "reconnect": "Reconnecter", + "reconnecting": "Reconnexion...", + "reconnectUnavailable": "Aucune session à laquelle se reconnecter pour l'instant." + }, + "tasks": { + "title": "Tâches" + }, + "alerts": { + "title": "Alertes", + "empty": "Aucune alerte", + "details": "Détails" + }, + "stats": { + "conversations": "{count} discussions", + "openUsage": "Voir les statistiques de sessions et l'usage de tokens" + }, + "tokens": { + "contextWindowUsageAria": "Utilisation de la fenêtre de contexte", + "contextWindow": "Fenêtre de contexte", + "usedMax": "Utilisé / Max", + "tokenUsage": "Utilisation des tokens", + "input": "Entrée", + "output": "Sortie", + "cacheRead": "Lecture cache", + "cacheWrite": "Écriture cache", + "total": "Total des tokens" + } + }, + "auxPanel": { + "tabs": { + "files": "Fichiers", + "changes": "Changements", + "commits": "Validations" + }, + "noFolderTitle": "Aucun dossier ouvert", + "noFolderHint": "Ouvrez un dossier pour voir son contenu ici" + }, + "windowControls": { + "minimizeWindow": "Minimiser la fenêtre", + "minimize": "Minimiser", + "maximizeWindow": "Maximiser la fenêtre", + "maximize": "Maximiser", + "restoreWindow": "Restaurer la fenêtre", + "restore": "Restaurer", + "closeWindow": "Fermer la fenêtre", + "close": "Fermer" + }, + "tabs": { + "closeConversationTab": "Fermer l’onglet de conversation", + "close": "Fermer", + "closeOthers": "Fermer les autres", + "splitRight": "Diviser à droite", + "splitDown": "Diviser en bas", + "splitAndMoveRight": "Diviser et déplacer à droite", + "splitAndMoveDown": "Diviser et déplacer en bas", + "moveToOppositeGroup": "Déplacer vers le groupe opposé", + "moveToGroup": "Déplacer vers le groupe", + "groupLabel": "Groupe {index}", + "changeSplitterOrientation": "Changer l'orientation du séparateur", + "unsplit": "Annuler la division", + "unsplitAll": "Annuler toutes les divisions", + "closeAll": "Tout fermer", + "tileDisplay": "Affichage en mosaïque", + "untileDisplay": "Quitter la mosaïque" + }, + "fileWorkspace": { + "files": "Fichiers", + "closeFileTab": "Fermer l’onglet fichier", + "close": "Fermer", + "closeOthers": "Fermer les autres", + "closeAll": "Tout fermer", + "preview": "Aperçu", + "editSource": "Modifier la source", + "maximize": "Agrandir", + "restore": "Restaurer", + "emptyDirectory": "Dossier vide" + }, + "terminal": { + "rename": "Renommer", + "close": "Fermer", + "closeOthers": "Fermer les autres", + "closeAll": "Tout fermer", + "hideTerminal": "Masquer le terminal ({shortcut})", + "openFolderFirst": "Ouvrez d'abord un dossier" + }, + "workspaceDialog": { + "title": "Ouvrir un dossier", + "manageTitle": "Dossiers liés", + "addTargetsTitle": "Ajouter des dossiers à lier", + "pickRootDescription": "Choisissez le dossier principal de cet espace de travail.", + "linksDescription": "Liez d'autres dossiers en sous-répertoires pour que les agents travaillent sur tous depuis un seul espace de travail.", + "addTargetsDescription": "Sélectionnez un ou plusieurs dossiers. Chacun devient un sous-répertoire de l'espace de travail.", + "useSystemPicker": "Sélecteur système", + "next": "Suivant", + "back": "Retour", + "done": "Terminé", + "change": "Modifier", + "addFolders": "Ajouter des dossiers", + "addSelected": "Ajouter", + "addSelectedCount": "Ajouter {count}", + "createCount": "Lier {count} dossier(s)", + "discardPending": "Abandonner", + "noLinks": "Aucun dossier lié pour l'instant.", + "gitExclude": "Garder les liens hors du statut git", + "rename": "Renommer", + "unlink": "Supprimer le lien", + "repair": "Recréer le lien", + "saveName": "Enregistrer", + "cancelRename": "Annuler", + "removePending": "Retirer", + "willAppearAs": "Apparaît sous le nom {name} dans l'espace de travail", + "renamedForDuplicate": "Renommé — {base} est déjà utilisé par un autre lien", + "renamedForExistingEntry": "Renommé — {base} existe déjà dans ce dossier", + "partiallyCreated": "Seuls {count} dossier(s) ont pu être liés", + "openFailed": "Impossible d'ouvrir le dossier", + "previewFailed": "Impossible de vérifier les dossiers sélectionnés", + "createFailed": "Impossible de lier les dossiers", + "renameFailed": "Impossible de renommer le lien", + "removeFailed": "Impossible de supprimer le lien", + "repairFailed": "Impossible de recréer le lien", + "status": { + "ok": "Lié", + "missing": "Le lien a disparu de ce dossier", + "conflicted": "Une autre entrée utilise désormais ce nom", + "broken": "Le dossier lié n'existe plus" + }, + "nameIssue": { + "empty": "Saisissez un nom", + "illegalChars": "Ne peut pas contenir / \\ : * ? \" < > |", + "tooLong": "Nom trop long", + "reserved": "Ce nom est réservé par Windows", + "duplicate": "Ce nom est déjà utilisé" + }, + "rejection": { + "not_found": "Dossier introuvable", + "not_a_directory": "Ce chemin n'est pas un dossier", + "same_as_root": "C'est le dossier de l'espace de travail lui-même", + "ancestor_of_root": "Ce dossier contient l'espace de travail", + "inside_root": "Déjà dans l'espace de travail", + "already_linked": "Déjà lié", + "name_unavailable": "Plus aucun nom disponible pour ce dossier", + "alreadyLinkedAs": "Déjà lié sous le nom {name}" + } + }, + "folderNameDropdown": { + "fallbackFolderName": "Dossier", + "openFolder": "Ouvrir le dossier", + "cloneRepository": "Cloner le dépôt", + "projectBoot": "Lanceur de projet", + "opened": "Ouvert", + "recentOpen": "Ouvert récemment" + }, + "fileWorkspacePanel": { + "addSelectionToChat": "Ajouter la sélection au chat", + "addToChat": "Ajouter au chat", + "addSelectionToChatDone": "{label} ajouté à la conversation", + "addFileToChat": "Ajouter le fichier au chat", + "toggleWordWrap": "Basculer le retour à la ligne", + "addFileToChatDone": "{label} ajouté à la conversation", + "viewDiff": "Voir le Diff", + "openFile": "Ouvrir le fichier", + "fileCount": "{count, plural, one {# fichier} other {# fichiers}}", + "openFileOrDiff": "Ouvrez un fichier ou un diff depuis le panneau de droite", + "disk": "Disque", + "head": "HEAD", + "unsaved": "Non enregistré", + "workingTree": "Arbre de travail", + "loading": "Chargement...", + "compareWithBranch": "{path} · comparer avec {branch}", + "hunkCount": "{count, plural, one {# bloc} other {# blocs}}", + "prev": "Précédent", + "next": "Suivant", + "jumpToLine": "Aller à la ligne {line}", + "noParsedDiffSections": "Aucune section de diff analysée", + "loadingEditor": "Chargement de l’éditeur...", + "imageZoomIn": "Agrandir", + "imageZoomOut": "Réduire", + "imageZoomReset": "Réinitialiser le zoom", + "htmlPreviewTitle": "Aperçu HTML", + "htmlPreviewTrust": "Activer les scripts", + "htmlPreviewTrustHint": "Exécuter les scripts de ce fichier et autoriser l'accès réseau. À activer uniquement pour les fichiers de confiance.", + "officePreviewTitle": "Aperçu du document Office", + "officeFullRender": "Rendu complet", + "officeFullRenderHint": "Affiche les animations Morph, la 3D et les formules (exécute les scripts de la diapositive)", + "officeNotInstalled": "OfficeCLI n'est pas installé", + "officeNotInstalledHint": "Installe OfficeCLI dans Paramètres → Outils Office pour prévisualiser les fichiers Word, Excel et PowerPoint.", + "officeOpenSettings": "Ouvrir les paramètres", + "officeWatchFailed": "Impossible de démarrer l'aperçu en direct", + "officeWatchRetry": "Réessayer", + "officeServerInstallHint": "OfficeCLI doit être installé sur l'hôte du serveur. Exécutez cette commande là-bas, puis réessayez :", + "officeRemoteDesktopUnsupported": "L'aperçu en direct n'est pas disponible dans une fenêtre de bureau à distance. Ouvrez cet espace de travail dans l'interface web du serveur pour prévisualiser les fichiers Office." + }, + "branchDropdown": { + "toasts": { + "commitCodeCompleted": "Commit de code terminé", + "pushCodeCompleted": "Push de code terminé", + "committedFiles": "{count, plural, one {# fichier commit} other {# fichiers commit}}", + "taskCompleted": "{label} terminé", + "taskFailed": "{label} échoué", + "mergeNoNewCommits": "{branchName} n’a pas de nouveaux commits", + "mergedCommits": "{count, plural, one {# commit fusionné} other {# commits fusionnés}}", + "allFilesUpToDate": "Tous les fichiers sont à jour", + "updatedFiles": "{count, plural, one {# fichier mis à jour} other {# fichiers mis à jour}}", + "openCommitWindowFailed": "Impossible d’ouvrir la fenêtre de commit", + "openPushWindowFailed": "Impossible d’ouvrir la fenêtre de push", + "upstreamSet": "La branche upstream a été définie", + "upstreamSetAndPushed": "Branche upstream définie et {count, plural, one {# commit} other {# commits}} poussé(s)", + "noCommitsToPush": "Aucun commit à pousser", + "pushedCommits": "{count, plural, one {# commit poussé} other {# commits poussés}}", + "switchedToFolder": "Basculé vers {name}", + "switchFailed": "Échec du changement de branche", + "openStashWindowFailed": "Échec de l'ouverture de la fenêtre de remisage" + }, + "tasks": { + "newBranch": "Créer la branche {name}", + "newWorktree": "Créer le worktree {name}", + "checkoutTo": "Basculer vers {branchName}", + "mergeBranch": "Fusionner {branchName}", + "rebaseTo": "Rebase vers {branchName}", + "deleteRemoteBranch": "Supprimer la branche distante {branchName}", + "initGitRepo": "Initialiser le dépôt Git", + "pullCode": "Pull du code", + "fetchInfo": "Récupérer les infos", + "pushCode": "Push du code", + "stashChanges": "Stash des changements", + "stashPop": "Appliquer le stash", + "deleteBranch": "Supprimer la branche {branchName}", + "removeWorktree": "Supprimer le worktree de {branchName}", + "removeWorktreeAndBranch": "Supprimer le worktree et la branche {branchName}", + "updateBranch": "Mettre à jour la branche {branchName}" + }, + "confirm": { + "mergeTitle": "Fusionner la branche", + "rebaseTitle": "Rebase de la branche", + "mergeDescription": "Fusionner {branchName} dans la branche actuelle {currentBranch} ?", + "rebaseDescription": "Rebaser la branche actuelle {currentBranch} sur {branchName} ?", + "deleteRemoteTitle": "Supprimer la branche distante", + "deleteRemoteDescription": "Supprimer la branche distante {branchName} ? Cette action la supprimera du dépôt distant et ne pourra pas être annulée.", + "deleteTitle": "Supprimer la branche", + "deleteDescription": "Supprimer la branche {branchName} ? Cette action est irréversible.", + "forceDeleteTitle": "Forcer la suppression de la branche", + "forceDeleteDescription": "La branche {branchName} n'est pas entièrement fusionnée. Êtes-vous sûr de vouloir la supprimer de force ? Cette action est irréversible.", + "deleteWorktreeTitle": "Supprimer le worktree", + "deleteWorktreeDescription": "Supprimer le répertoire du worktree où {branchName} est extraite ? La branche et ses commits sont conservés.", + "forceDeleteWorktreeTitle": "Forcer la suppression du worktree", + "forceDeleteWorktreeDescription": "Le worktree de {branchName} contient des fichiers non validés ou non suivis. Le supprimer quand même ? Ces modifications seront irrécupérables.", + "deleteWorktreeAndBranchTitle": "Supprimer le worktree et la branche", + "deleteWorktreeAndBranchDescription": "Supprimer le worktree de {branchName}, la branche elle-même et son dossier d'espace de travail ? Ses sessions sont déplacées vers le dossier du dépôt. Cette action est irréversible.", + "forceDeleteWorktreeAndBranchTitle": "Forcer la suppression du worktree et de la branche", + "forceDeleteWorktreeAndBranchDescription": "Le worktree de {branchName} contient des fichiers non validés, ou la branche n'est pas entièrement fusionnée. Tout supprimer quand même ? Cette action est irréversible." + }, + "current": "Actuelle", + "switchToBranch": "Basculer vers cette branche", + "mergeBranchIntoCurrent": "Fusionner {branchName} dans {currentBranch}", + "rebaseCurrentToBranch": "Rebaser {currentBranch} sur {branchName}", + "noBranch": "Aucune branche", + "detachedHead": "HEAD détaché sur {sha}", + "initGitRepo": "Initialiser le dépôt Git", + "pullCode": "Pull du code", + "fetchRemoteBranches": "Récupérer les branches distantes", + "openCommitWindow": "Commit du code...", + "pushCode": "Pousser...", + "pushBranch": "Pousser", + "newBranch": "Nouvelle branche...", + "newWorktree": "Nouveau worktree...", + "stashChanges": "Remiser les changements...", + "stashPop": "Appliquer le stash...", + "manageRemotes": "Gérer les dépôts distants...", + "localBranches": "Branches locales ({count, plural, one {#} other {#}})", + "noLocalBranches": "Aucune branche locale", + "remoteBranches": "Branches distantes ({count, plural, one {#} other {#}})", + "noRemoteBranches": "Aucune branche distante", + "dialogs": { + "newBranchTitle": "Nouvelle branche", + "newBranchDescription": "Créer une nouvelle branche depuis la branche actuelle {branch}", + "branchNamePlaceholder": "Nom de la branche", + "newWorktreeTitle": "Nouveau worktree", + "newWorktreeDescription": "Créer un nouveau worktree depuis la branche actuelle {branch}", + "branchNameLabel": "Nom de la branche", + "worktreePathLabel": "Chemin du worktree", + "worktreePathPlaceholder": "Chemin du worktree", + "manageRemotesTitle": "Gérer les dépôts distants", + "manageRemotesEmpty": "Aucun dépôt distant configuré", + "remoteNamePlaceholder": "Nom du dépôt distant", + "remoteUrlPlaceholder": "URL du dépôt distant", + "addRemote": "Ajouter", + "savingRemotes": "Enregistrement..." + }, + "conflict": { + "title": "Conflits de fusion", + "description": "Les fichiers suivants ont des conflits qui doivent être résolus :", + "abort": "Abandonner la fusion", + "openMergeTool": "Ouvrir l'outil de fusion", + "completeMerge": "Terminer la fusion", + "abortSuccess": "Fusion abandonnée avec succès", + "completeSuccess": "Fusion terminée avec succès" + }, + "stashDialog": { + "title": "Remiser les changements", + "description": "Sauvegarder les changements actuels dans la remise", + "messageLabel": "Message", + "messagePlaceholder": "Message de remise (optionnel)", + "keepIndex": "Conserver l'index (les changements indexés restent indexés)", + "cancel": "Annuler", + "stash": "Remiser", + "success": "Changements remisés", + "error": "Échec de la remise" + }, + "unstashDialog": { + "title": "Appliquer la remise", + "noStashes": "Aucune remise trouvée", + "selectFile": "Sélectionner un fichier pour voir le diff", + "viewDiff": "Voir le diff", + "original": "Original", + "modified": "Modifié", + "apply": "Appliquer", + "drop": "Supprimer", + "applySuccess": "Remise appliquée", + "dropSuccess": "Remise supprimée", + "confirmApply": "Appliquer la remise {ref} au répertoire de travail ?", + "cancel": "Annuler" + }, + "deleteBranch": "Supprimer la branche", + "deleteWorktree": "Supprimer le worktree", + "deleteWorktreeAndBranch": "Supprimer le worktree et la branche", + "searchPlaceholder": "Rechercher des branches et actions", + "searchAriaLabel": "Rechercher des branches et actions", + "branchListLabel": "Branches et actions", + "noMatches": "Aucune correspondance" + }, + "commitDialog": { + "toasts": { + "commitCompleted": "Commit de code terminé", + "pushFailed": "Échec du push", + "committedFiles": "{count, plural, one {# fichier commit} other {# fichiers commit}}", + "addedToVcs": "Ajouté à VCS", + "addToVcsFailed": "Échec de l’ajout à VCS", + "fileDeleted": "Fichier supprimé", + "deleteFailed": "Échec de la suppression", + "fileRolledBack": "Fichier restauré", + "rollbackFailed": "Échec du rollback", + "dirRolledBack": "Répertoire restauré", + "dirDeleted": "Répertoire supprimé" + }, + "confirm": { + "deleteTitle": "Confirmer la suppression", + "deleteDescription": "Supprimer le fichier \"{file}\" ? Cette action est irréversible.", + "rollbackTitle": "Confirmer le rollback", + "rollbackDescription": "Restaurer le fichier \"{file}\" vers HEAD ? Les modifications non enregistrées seront perdues.", + "rollbackDirDescription": "Restaurer le répertoire \"{dir}\" vers HEAD ? Les modifications non enregistrées seront perdues.", + "deleteDirDescription": "Supprimer le répertoire \"{dir}\" ? Cette action est irréversible." + }, + "actions": { + "select": "Sélectionner", + "unselect": "Désélectionner", + "rollback": "Annuler", + "addToVcs": "Ajouter à VCS" + }, + "aria": { + "selectFile": "{action} : {path}", + "unselectAllFiles": "Désélectionner tous les fichiers", + "selectAllFiles": "Sélectionner tous les fichiers", + "unselectTracked": "Désélectionner les changements suivis", + "selectTracked": "Sélectionner les changements suivis", + "unselectUntracked": "Désélectionner les fichiers non suivis", + "selectUntracked": "Sélectionner les fichiers non suivis" + }, + "loading": "Chargement...", + "selectionCount": "{selected} / {total} fichiers", + "emptyFiles": "Aucun fichier modifié", + "trackedChanges": "Changements suivis ({count})", + "untrackedFiles": "Fichiers non suivis ({count})", + "commitMessage": "Message de commit", + "commitMessagePlaceholder": "Saisissez le message de commit...", + "commitButton": "Valider ({count})", + "commitAndPushButton": "Valider et pousser ({count})", + "head": "HEAD", + "workingTree": "Arbre de travail", + "clickFileToDiff": "Cliquez sur un nom de fichier pour voir le diff", + "loadingDiff": "Chargement du diff..." + }, + "pushWindow": { + "title": "Pousser le code", + "noUnpushedCommits": "Aucun commit non poussé", + "noRemoteConfigured": "Aucun dépôt distant Git configuré\nAjoutez-en un dans « Gérer les dépôts distants »", + "newBranchNoPushedCommits": "Nouvelle branche — pousser pour créer la branche de suivi distante", + "unpushed": "Non poussé", + "selectFileToViewDiff": "Sélectionnez un fichier pour voir les différences", + "before": "Avant", + "after": "Après", + "push": "Pousser", + "toasts": { + "pushSuccess": "Push réussi", + "pushFailed": "Échec du push", + "upstreamSet": "La branche distante a été configurée", + "upstreamSetAndPushed": "Branche distante configurée et {count} commits poussés", + "noCommitsToPush": "Aucun commit à pousser", + "pushedCommits": "{count} commits poussés" + } + }, + "gitLogTab": { + "filesTitle": "Fichiers", + "expandAllFiles": "Développer tous les fichiers", + "collapseAllFiles": "Réduire tous les fichiers", + "workspace": "espace de travail", + "retry": "Réessayer", + "noCommitsFound": "Aucun commit trouvé", + "notAGitRepoTitle": "Pas un dépôt Git", + "notAGitRepoHint": "Initialisez Git depuis le menu des branches ci-dessus, ou ouvrez un dépôt existant.", + "hash": "Empreinte", + "copyHash": "Copier le hash", + "copyMessage": "Copier le message", + "showMore": "Afficher plus", + "showLess": "Afficher moins", + "author": "Auteur", + "noFileChangeDetails": "Aucun détail de changement de fichier disponible.", + "loadingFiles": "Chargement des fichiers...", + "branchesTitle": "Branches Git", + "loadingBranches": "Chargement des branches...", + "noContainingBranches": "Aucune branche contenant ce commit.", + "newBranch": "Nouvelle branche...", + "resetToHere": "Réinitialiser ici", + "resetDisabledReasonNotCurrentBranchView": "Disponible uniquement en affichant la branche actuelle", + "copyFullCommitHashAria": "Copier le hash complet du commit {hash}", + "pushStatus": { + "pushed": "Poussé vers le remote", + "notPushed": "Non poussé vers le remote", + "unknown": "Statut de push inconnu (aucun upstream configuré)" + }, + "time": { + "monthsAgo": "{count, plural, one {il y a # mois} other {il y a # mois}}", + "daysAgo": "{count, plural, one {il y a # jour} other {il y a # jours}}", + "hoursAgo": "{count, plural, one {il y a # heure} other {il y a # heures}}", + "minsAgo": "{count, plural, one {il y a # min} other {il y a # mins}}", + "justNow": "à l’instant" + }, + "toasts": { + "createdAndSwitchedNewBranch": "Nouvelle branche créée et activée", + "newBranchFromCommit": "{name} (depuis {shortHash})", + "createBranchFailed": "Échec de la création de la branche", + "openPushWindowFailed": "Échec de l'ouverture de la fenêtre de push", + "resetSuccess": "Réinitialisation réussie", + "resetSuccessDescription": "{branch} a été réinitialisée sur {shortHash} avec {mode}", + "resetFailed": "Échec de la réinitialisation" + }, + "authorFilter": { + "label": "Auteur", + "searchPlaceholder": "Rechercher un auteur", + "noAuthors": "Aucun auteur trouvé", + "you": "vous", + "filterByAuthorAria": "Filtrer les commits par auteur", + "filterByQuery": "Filtrer par « {query} »", + "clearAuthorFilterAria": "Effacer le filtre par auteur", + "recent": "Récents", + "matchingAuthors": "Auteurs correspondants", + "removeFromRecent": "Retirer {name} des récents" + }, + "branchSelector": { + "label": "Branche", + "head": "HEAD", + "headHint": "Suit la branche actuelle", + "headHintWithBranch": "Suit la branche actuelle ({branch})", + "searchBranch": "Rechercher une branche...", + "noBranches": "Aucune branche", + "selectBranchPlaceholder": "Sélectionner une branche...", + "localBranches": "Branches locales", + "current": "Actuelle", + "remoteBranches": "Branches distantes", + "refreshCommitHistory": "Actualiser l’historique des commits", + "clearBranchFilterAria": "Effacer le filtre par branche" + }, + "dialogs": { + "newBranchTitle": "Nouvelle branche", + "newBranchDescription": "Créer une nouvelle branche avec le commit {shortHash} comme dernier commit.", + "branchNamePlaceholder": "Nom de la branche", + "reset": { + "title": "Réinitialiser la branche actuelle jusqu’ici", + "branchLabel": "Branche", + "targetLabel": "Commit cible", + "messageLabel": "Message", + "modeLabel": "Mode de réinitialisation", + "confirmButton": "Réinitialiser", + "modes": { + "soft": { + "label": "--soft", + "description": "Déplace HEAD et le pointeur de la branche actuelle vers le commit cible.\nConserve Index et Working Tree inchangés.\nLes changements des commits retirés restent staged." + }, + "mixed": { + "label": "--mixed (par défaut)", + "description": "Déplace HEAD vers le commit cible.\nRéinitialise Index au commit cible tout en conservant les changements du Working Tree.\nLes changements passent de staged à unstaged." + }, + "hard": { + "label": "--hard", + "description": "Déplace HEAD et réinitialise à la fois Index et Working Tree au commit cible.\nLes changements locaux suivis après le commit cible sont supprimés.\nC’est une opération destructive." + }, + "keep": { + "label": "--keep", + "description": "Déplace HEAD vers le commit cible en conservant les changements locaux quand c’est possible.\nSeuls les changements sans conflit sont conservés.\nEn cas de conflit, la réinitialisation est annulée pour protéger votre travail." + } + } + } + }, + "moreActions": "Autres actions Git" + }, + "gitChangesTab": { + "workspace": "espace de travail", + "noChanges": "Aucun changement local", + "notAGitRepoTitle": "Pas un dépôt Git", + "notAGitRepoHint": "Initialisez Git depuis le menu des branches ci-dessus, ou ouvrez un dépôt existant.", + "trackedChanges": "Changements suivis ({count})", + "untrackedFiles": "Fichiers non suivis ({count})", + "expandTracked": "Développer les changements suivis", + "collapseTracked": "Réduire les changements suivis", + "expandUntracked": "Développer les fichiers non suivis", + "collapseUntracked": "Réduire les fichiers non suivis", + "showRemainingItems": "Afficher {count} éléments de plus", + "actions": { + "commitCode": "Commit du code", + "rollback": "Annuler", + "addToVcs": "Ajouter à VCS", + "delete": "Supprimer", + "moreActions": "Autres actions Git", + "addAllToVcs": "Tout ajouter au VCS", + "rollbackAll": "Tout annuler", + "refresh": "Actualiser" + }, + "toasts": { + "noAddableFilesInDir": "Aucun fichier modifié de ce répertoire ne peut être ajouté à VCS", + "noRollbackFilesInDir": "Aucun fichier modifié de ce répertoire ne peut être rollback", + "addedToVcs": "{name} ajouté à VCS", + "addToVcsFailed": "Échec de l’ajout à VCS", + "openCommitWindowFailed": "Impossible d’ouvrir la fenêtre de commit", + "rolledBack": "{name} restauré", + "rollbackFailed": "Échec du rollback", + "addedFilesToVcs": "{count, plural, one {# fichier} other {# fichiers}} ajouté(s) à VCS", + "rolledBackFiles": "{count, plural, one {# fichier restauré} other {# fichiers restaurés}}", + "deleted": "{name} supprimé", + "deleteFailed": "Échec de la suppression", + "deletedFiles": "{count} fichiers supprimés", + "noDeletableFilesInDir": "Aucun fichier modifié dans ce répertoire ne peut être supprimé", + "commitFailed": "Échec du commit" + }, + "directoryDialog": { + "descriptionAdd": "Sélectionnez les fichiers du répertoire {path} à ajouter à VCS.", + "descriptionRollback": "Sélectionnez les fichiers du répertoire {path} à rollback.", + "descriptionDelete": "Sélectionnez les fichiers du répertoire {path} à supprimer. Cette action est irréversible.", + "descriptionFallback": "Sélectionnez les fichiers pour continuer.", + "selectionCount": "{selected} / {total} fichiers sélectionnés", + "selectAll": "Tout sélectionner", + "unselectAll": "Tout désélectionner", + "loadingCandidates": "Chargement des changements du répertoire...", + "noOperableFiles": "Aucun fichier opérable" + }, + "rollbackConfirm": { + "title": "Confirmer le rollback", + "descriptionWithTarget": "Rollback des changements locaux pour {kind} \"{name}\" ?", + "descriptionFallback": "Rollback des changements locaux ?", + "kindDirectory": "répertoire", + "kindFile": "fichier" + }, + "deleteConfirm": { + "title": "Confirmer la suppression", + "descriptionWithTarget": "Supprimer {kind} \"{name}\" ? Cette action est irréversible.", + "descriptionFallback": "Cette action est irréversible.", + "kindDirectory": "répertoire", + "kindFile": "fichier" + }, + "quickCommit": { + "placeholder": "Message du commit (Entrée pour valider)" + } + }, + "tabContext": { + "loadingConversation": "Chargement...", + "untitledConversation": "Conversation sans titre", + "newConversation": "Nouvelle conversation" + }, + "fileTreeTab": { + "workspace": "Espace de travail", + "retry": "Réessayer", + "git": "Git", + "openInFileManager": "Ouvrir dans le gestionnaire de fichiers", + "openInFinder": "Ouvrir dans Finder", + "openInExplorer": "Ouvrir dans Explorer", + "attachToCurrentSession": "Ajouter à la session", + "compareWithBranch": "Comparer avec la branche...", + "reloadFromDisk": "Recharger depuis le disque", + "new": "Nouveau", + "newFile": "Fichier", + "newDirectory": "Répertoire", + "openIn": "Ouvrir dans", + "openInTerminal": "Ouvrir dans le terminal", + "linkedFolder": "Dossier lié", + "copyPath": "Copier le chemin", + "upload": "Téléverser fichiers/dossier", + "download": "Télécharger le fichier", + "downloadAsZip": "Télécharger en ZIP", + "actions": { + "select": "Sélectionner", + "unselect": "Désélectionner", + "commitCode": "Committer le code", + "rollback": "Annuler", + "addToVcs": "Ajouter au VCS" + }, + "aria": { + "selectPath": "{action} : {path}" + }, + "toasts": { + "openDirectoryFailed": "Échec de l'ouverture du dossier", + "openBuiltinTerminalFailed": "Impossible d'ouvrir le terminal intégré", + "openCommitWindowFailed": "Échec de l'ouverture de la fenêtre de commit", + "noAddableFilesInDir": "Aucun fichier modifié de ce dossier ne peut être ajouté au VCS", + "noRollbackFilesInDir": "Aucun fichier modifié de ce dossier ne peut être annulé", + "addedToVcs": "{name} ajouté au VCS", + "addToVcsFailed": "Échec de l'ajout au VCS", + "loadBranchesFailed": "Échec du chargement des branches", + "renameFailed": "Échec du renommage", + "moveFailed": "Échec du déplacement", + "deleteFailed": "Échec de la suppression", + "rolledBack": "{name} annulé", + "rollbackFailed": "Échec de l'annulation", + "addedFilesToVcs": "{count, plural, one {# fichier ajouté au VCS} other {# fichiers ajoutés au VCS}}", + "rolledBackFiles": "{count, plural, one {# fichier annulé} other {# fichiers annulés}}", + "savedAsCopy": "Enregistré en copie", + "saveCopyFailed": "Échec de l'enregistrement en copie", + "watchStartFailed": "Échec du démarrage de la surveillance de fichiers", + "createFailed": "Échec de la création", + "downloadFailed": "Échec du téléchargement de {name}", + "downloadSaved": "{name} téléchargé", + "pathCopied": "Chemin copié", + "copyPathFailed": "Échec de la copie du chemin" + }, + "createDialog": { + "newFile": "Nouveau fichier", + "newDirectory": "Nouveau répertoire", + "description": "Entrez un nom pour le nouveau {kind}.", + "placeholderFile": "nom-du-fichier.ext", + "placeholderDirectory": "nom-du-dossier" + }, + "renameDialog": { + "renameDirectory": "Renommer le dossier", + "renameFile": "Renommer le fichier", + "description": "Saisissez un nouveau nom (nom uniquement, sans chemin).", + "placeholderDirectory": "nouveau-nom-dossier", + "placeholderFile": "nouveau-nom-fichier.ext" + }, + "uploadDialog": { + "title": "Téléverser vers l'espace de travail", + "description": "Ajustez la destination si besoin, puis ajoutez des fichiers ou dossiers.", + "workspaceRoot": "racine de l'espace de travail", + "targetPathLabel": "Téléverser vers", + "targetPathHint": "Chemin résolu : {path}", + "dropHint": "Déposez des fichiers ou dossiers ici, ou utilisez les boutons ci-dessous", + "dropHintActive": "Relâchez pour ajouter à la file d'attente", + "selectFiles": "Sélectionner des fichiers", + "selectFolder": "Sélectionner un dossier", + "startUpload": "Lancer le téléversement", + "clearQueue": "Effacer terminés", + "removeItem": "Retirer de la file", + "retry": "Réessayer", + "dropZoneAria": "Déposez ici ou activez pour parcourir", + "folderEmpty": "Aucun fichier trouvé dans le dossier déposé", + "summary": "Total : {total} · Réussis : {succeeded} · Échoués : {failed}", + "status": { + "pending": "En attente", + "uploading": "Téléversement", + "success": "Terminé", + "error": "Échec", + "cancelled": "Annulé" + } + }, + "directoryDialog": { + "descriptionAdd": "Sélectionnez des fichiers sous le dossier {path} à ajouter au VCS.", + "descriptionRollback": "Sélectionnez des fichiers sous le dossier {path} à annuler.", + "descriptionFallback": "Sélectionnez des fichiers pour continuer.", + "selectionCount": "{selected} / {total} fichiers sélectionnés", + "selectAll": "Tout sélectionner", + "unselectAll": "Tout désélectionner", + "loadingCandidates": "Chargement des changements du dossier...", + "noOperableFiles": "Aucun fichier exploitable" + }, + "compareDialog": { + "title": "Comparer avec la branche", + "descriptionWithTarget": "Sélectionnez une branche et comparez avec {kind} {path}", + "descriptionFallback": "Sélectionnez une branche à comparer.", + "kindDirectory": "dossier", + "kindFile": "fichier", + "filterPlaceholder": "Filtrer les branches, ex. main / origin/main", + "singleClickHint": "Cliquez sur une branche pour comparer directement", + "loadingBranches": "Chargement des branches...", + "recentBranches": "Branches récentes ({count})", + "noCurrentBranch": "Aucune branche courante", + "localBranches": "Branches locales ({count})", + "remoteBranches": "Branches distantes ({count})", + "noMatchingBranches": "Aucune branche correspondante" + }, + "externalConflictDialog": { + "title": "Modifications externes de fichiers détectées", + "descriptionWithPath": "Le fichier {path} a changé sur le disque et les modifications actuelles ne sont pas enregistrées.", + "descriptionFallback": "Le fichier actuel a changé sur le disque et les modifications actuelles ne sont pas enregistrées.", + "compare": "Comparer", + "savingCopy": "Enregistrement de la copie...", + "saveAsCopy": "Enregistrer en copie", + "reload": "Recharger" + }, + "deleteConfirm": { + "title": "Confirmer la suppression", + "descriptionWithTarget": "Supprimer {kind} \"{name}\" ? Cette action est irréversible.", + "descriptionFallback": "Cette action est irréversible.", + "kindDirectory": "dossier", + "kindFile": "fichier" + }, + "rollbackConfirm": { + "title": "Confirmer l'annulation", + "descriptionWithTarget": "Annuler les modifications locales du fichier \"{name}\" ?", + "descriptionFallback": "Annuler les modifications locales de ce fichier ?" + }, + "terminalTitle": "Console · {name}" + }, + "commandDropdown": { + "loading": "Chargement...", + "addCommand": "Ajouter une commande", + "manageCommands": "Gérer les commandes...", + "runCommandTitle": "Exécuter : {command}", + "stopCommandTitle": "Arrêter : {command}", + "manageDialog": { + "title": "Gérer les commandes", + "empty": "Aucune commande pour le moment", + "noResults": "Aucune commande correspondante", + "searchPlaceholder": "Rechercher des commandes", + "newCommand": "Nouvelle commande", + "nameLabel": "Nom", + "commandLabel": "Commande", + "dragSort": "Glisser pour trier", + "dragSortCommand": "Glisser pour trier {name}", + "orderFailed": "Échec de l'enregistrement de l'ordre des commandes", + "loadFailed": "Échec du chargement des commandes", + "saveFailed": "Échec de l'enregistrement de la commande", + "deleteFailed": "Échec de la suppression de la commande", + "confirmDelete": { + "title": "Supprimer la commande ?", + "message": "Cela supprimera \"{name}\". Cette action est irréversible." + } + } + }, + "workspaceContext": { + "confirmCloseDirtyTab": "Fermer « {title} » sans enregistrer ?", + "confirmCloseOtherDirtyTabs": "Fermer les autres onglets avec des modifications non enregistrées ?", + "confirmCloseAllDirtyTabs": "Fermer tous les onglets avec des modifications non enregistrées ?", + "unableLoadContent": "Impossible de charger le contenu.\n\n{message}", + "previewRequestTimedOut": "La requête de prévisualisation a expiré", + "diffRequestTimedOut": "La requête Diff a expiré", + "branchCompareRequestTimedOut": "La requête de comparaison de branches a expiré", + "commitDiffRequestTimedOut": "La requête de Diff de commit a expiré", + "saveRequestTimedOut": "La requête d’enregistrement a expiré", + "reloadRequestTimedOut": "La requête de rechargement a expiré", + "noChanges": "Aucun changement.", + "noDiffOutput": "Aucune sortie diff.", + "diffTitleWorkspace": "Diff · Espace de travail", + "diffDescriptionWorkingTree": "Arbre de travail (HEAD)", + "diffTitleFile": "Différence · {name}", + "compareTitleFile": "Comparer · {name}", + "compareTitleBranch": "Comparer · {branch}", + "compareDescriptionPath": "{path} · comparer avec {branch}", + "compareDescriptionBranch": "comparer avec {branch}", + "diffTitleCommitFile": "Différence · {name} @ {hash}", + "diffTitleCommit": "Différence · {hash}", + "diffDescriptionCommitPath": "{path} · validation {commit}", + "diffDescriptionCommit": "validation {commit}", + "diffTitleConflictFile": "Conflit · {name}", + "diffDescriptionConflict": "{path} · disque vs non enregistré" + }, + "chat": { + "acpConnections": { + "actions": { + "openAgentsSettings": "Ouvrir les paramètres des agents", + "retry": "Réessayer" + }, + "agentsSetupHint": "Ouvrez Paramètres > Agents pour gérer l'installation.", + "withSetupHint": "{message}\n{hint}", + "blocked": { + "missingConfig": "Impossible de lire la configuration actuelle de l'agent.", + "disabled": "{agent} est désactivé dans les paramètres des agents. Activez-le avant de vous connecter.", + "unavailable": "{agent} n'est pas disponible sur la plateforme actuelle.", + "sdkMissing": "Le SDK de {agent} n'est pas installé", + "adapterMissing": "L'adaptateur ACP de {agent} n'est pas installé" + }, + "backendErrors": { + "initializeTimeout": "Le handshake de connexion de {agent} a expiré (aucune réponse après 60 secondes). Ouvrez Paramètres pour vérifier la configuration de l'agent et du réseau.", + "mcpRejectedByAgent": "{agent} a refusé la session alors que le compagnon MCP de codeg était joint : {message} Si cet agent ne prend pas en charge MCP, désactivez « Prise en charge de MCP » dans les Paramètres puis reconnectez-vous.", + "processExited": "Le processus {agent} s'est arrêté de manière inattendue.", + "spawnFailed": "Impossible de démarrer {agent} : {message}", + "downloadFailed": "Échec du téléchargement de {agent} : {message}", + "sessionLoadResourceNotFound": "Échec du chargement de la session de {agent}. Rechargez pour réessayer ou démarrez une nouvelle conversation.", + "sessionLoadUnavailable": "{agent} n'a pas pu restaurer cette session ; elle a peut-être pris fin ou l'agent s'est arrêté. Rechargez pour réessayer ou démarrez une nouvelle conversation.", + "turnFailedRefusal": "{agent} a refusé de poursuivre ce tour. Cela indique souvent une erreur de backend ou de passerelle. Vérifiez les journaux de l'agent.", + "turnFailedMaxTokens": "{agent} a atteint la limite maximale de jetons pour ce tour.", + "turnFailedMaxTurnRequests": "{agent} a atteint le nombre maximal de requêtes autorisées pour ce tour.", + "turnFailedUnknown": "{agent} a terminé le tour avec une raison d'arrêt inconnue.", + "grokModelSwitchIncompatibleAgent": "{agent} ne peut pas basculer vers ce modèle dans une conversation existante. Démarrez une nouvelle session pour l'utiliser.", + "turnFailedEmpty": "{agent} a terminé le tour sans produire de réponse.", + "turnFailedEmptyProtocol": "{agent} a produit une sortie que codeg n'a pas pu analyser — la version de l'agent ne correspond peut-être pas au protocole.", + "turnFailedEmptyMetadata": "{agent} n'a envoyé que des mises à jour d'état ce tour-ci (plan / mode / utilisation) et aucune réponse.", + "detailsInAlerts": "Ouvrez les alertes de la barre d'état et développez les détails pour voir la sortie de l'agent." + }, + "unableReadAgentConfig": "Impossible de lire la configuration de l'agent : {message}", + "connectFailedTitle": "Échec de la connexion de {agent}", + "toolFallbackTitle": "Outil", + "eventErrorTitle": "Erreur de l'agent", + "notificationTurnComplete": "{agent} a terminé de répondre", + "notificationError": "{agent} erreur : {message}", + "claudeApiRetry": { + "fallbackError": "authentication_failed", + "retryingWithMax": "nouvelle tentative {attempt}/{max}", + "retryingAttempt": "nouvelle tentative {attempt}", + "retrying": "nouvelle tentative", + "nextRetryIn": "prochaine dans {seconds}s", + "line": "{error}{status} · {retry}", + "lineWithDelay": "{error}{status} · {retry}, {delay}", + "httpStatus": " (HTTP {status})" + }, + "configOptionAdjusted": "{agent} a réglé {option} sur {actual} au lieu de {requested}" + }, + "connectionLifecycle": { + "tasks": { + "connectingTitle": "Connexion à {agent}", + "connectingDescription": "Établissement de la connexion", + "loadingSelectorsTitle": "Chargement des sélecteurs de {agent}", + "loadingSelectorsDescription": "Récupération des options de mode et de configuration de session", + "initSessionTitle": "Initialisation de la session {agent}", + "initSessionDescription": "Création de la session et chargement de la configuration" + }, + "errors": { + "connectionFailed": "Échec de la connexion", + "sendPromptFailed": "Échec de l'envoi du message : {error}" + } + }, + "shared": { + "attachedResources": "Ressources jointes", + "toolCallFailed": "Échec de l'appel d'outil" + }, + "messageThread": { + "emptyTitle": "Aucun message pour le moment", + "emptyDescription": "Commencez une conversation pour voir les messages ici" + }, + "chatInput": { + "connecting": "Connexion...", + "agentResponding": "{agent} répond...", + "sendMessage": "Envoyer un message..." + }, + "messageInput": { + "askAnything": "Posez n'importe quelle question...", + "removeAttachmentAria": "Retirer {name}", + "attachFiles": "Joindre des fichiers", + "addActions": "Ajouter", + "quickMessages": "Messages rapides", + "quickMessagesEmpty": "Aucun message rapide pour l'instant", + "quickMessagesLoading": "Chargement...", + "pasteAsPlainText": "Coller en texte brut", + "cut": "Couper", + "copy": "Copier", + "selectAll": "Tout sélectionner", + "pasteUnavailable": "Impossible de lire le presse-papiers. Utilisez Ctrl/⌘V pour coller.", + "clipboardWriteFailed": "Impossible d'écrire dans le presse-papiers. Utilisez le raccourci clavier.", + "quickMessageUntitled": "Sans titre", + "liveFeedback": "Retour en direct", + "liveFeedbackDisabledHint": "Disponible pendant que l'agent travaille", + "dropFilesToAttach": "Déposez des fichiers à joindre", + "loadingSettings": "Chargement des paramètres...", + "loadingMode": "Chargement du mode...", + "modeLabel": "Mode", + "toggleOn": "Activé", + "toggleOff": "Désactivé", + "agentSettings": "Paramètres de l'agent", + "searchModel": "Rechercher des modèles...", + "searchModelAria": "Rechercher des modèles", + "modelListLabel": "Modèles", + "noModels": "Aucun modèle trouvé", + "cancel": "Annuler", + "send": "Envoyer", + "forkAndSend": "Fork & Envoyer", + "queueMessage": "Mettre en file d'attente", + "steerIntoTurn": "Insérer dans le tour en cours", + "steerQueuedInstead": "Mis en file d'attente — il sera envoyé au tour suivant.", + "steerFailed": "Impossible d'insérer dans le tour en cours", + "steerAttachmentsUnsupported": "Texte uniquement — les brouillons avec pièces jointes passent par la file d'attente.", + "slashCommands": "Commandes slash", + "slashSearchPlaceholder": "Rechercher des commandes...", + "slashSearchEmpty": "Aucune commande correspondante", + "experts": "Experts", + "office": "Bureautique", + "research": "Recherche", + "attachLocalUpload": "Téléverser un fichier local", + "attachServerFile": "Sélectionner un fichier serveur", + "attachUploadTooLarge": "{names} dépasse la limite de téléversement de {limit} Mo et a été ignoré.", + "attachUploadFailed": "Échec du téléversement de {names}.", + "attachUploadNotAFile": "{names} n'est pas un fichier régulier (répertoire ou fichier spécial) et a été ignoré.", + "attachUploadQuotaExceeded": "Le serveur n'a plus d'espace pour les téléversements ; {names} n'a pas pu être envoyé.", + "attachUploadInProgress": "Les images sont encore en cours d'envoi — réessayez dans un instant.", + "mentionEmpty": "Aucune correspondance", + "mentionLoading": "Recherche…", + "mentionListLabel": "Mentions", + "mentionMore": "Plus de résultats — continuez à taper pour filtrer", + "mentionCount": "{count, plural, one {# résultat} other {# résultats}}", + "mentionGroupFile": "Fichiers", + "mentionGroupAgent": "Agents", + "mentionGroupSession": "Sessions", + "mentionGroupCommit": "Commits", + "mentionGroupSkill": "Compétences" + }, + "messageQueue": { + "addToQueue": "Mettre en file", + "saveEdit": "Enregistrer", + "cancelEdit": "Annuler la modification", + "editItem": "Modifier", + "deleteItem": "Supprimer" + }, + "welcomeInputPanel": { + "agentsSettingsPath": "Paramètres > Agents", + "autoConnectFallback": "Cliquez pour ouvrir {path} et gérer l'installation.", + "autoConnectAppend": "{message}. Cliquez pour ouvrir {path} et gérer l'installation.", + "enableAgentFirstPlaceholder": "Activez au moins un agent avant de démarrer une session...", + "prepareSessionFailed": "Impossible de préparer la session de chat. Veuillez réessayer.", + "createConversationFailed": "Impossible de créer la conversation. Veuillez réessayer.", + "askAnythingPlaceholder": "Posez n'importe quelle question...", + "agentNotInstalled": "{agent} n'est pas installé · ouvrez les paramètres Agents pour l'installer", + "agentAdapterNotInstalled": "L'adaptateur ACP de {agent} n'est pas installé (distinct de votre propre CLI) · ouvrez les paramètres Agents pour l'installer" + }, + "welcomePanel": { + "greeting": "Que souhaites-tu faire aujourd'hui ?", + "tips": { + "tileTabs": "Faites un clic droit sur un onglet de conversation et choisissez Affichage en mosaïque pour comparer plusieurs sessions côte à côte.", + "pinTab": "Double-cliquez sur un onglet de conversation pour l'épingler : une nouvelle session ne le remplacera plus automatiquement.", + "shortcutsNewSearch": "{newConversation} ouvre une nouvelle conversation, {searchConversations} recherche dans l'historique.", + "slashAtMention": "Saisissez / dans la zone de saisie pour les commandes slash, ou @ pour référencer un fichier du projet.", + "pasteDropFiles": "Collez une capture d'écran ou déposez un fichier directement dans la zone de saisie pour le joindre.", + "queueMessage": "Pendant que l'agent répond, continuez à écrire : votre message suivant est mis en file et envoyé automatiquement à la fin.", + "draftAutoSave": "Les brouillons non envoyés sont sauvegardés automatiquement par conversation et restaurés à votre retour.", + "forkSend": "Le menu déroulant du bouton d'envoi propose Bifurquer et envoyer pour ouvrir une branche dans un nouvel onglet à partir du point actuel.", + "exportConversation": "Faites un clic droit dans la conversation pour l'exporter en Markdown, HTML ou image.", + "chatChannels": "Connectez Telegram / Lark / WeChat dans Paramètres → Canaux de discussion pour continuer depuis votre téléphone.", + "shortcutsAuxPanel": "{toggleAuxPanel} bascule le panneau droit pour voir les fichiers modifiés et les changements Git de cette session.", + "shortcutsTerminalSidebar": "{toggleTerminal} ouvre le terminal intégré, {toggleSidebar} bascule la barre latérale.", + "customShortcuts": "Tous les raccourcis peuvent être réassignés dans Paramètres → Raccourcis.", + "webService": "Activez Paramètres → Service Web pour que votre équipe accède au même codeg depuis un navigateur.", + "fusionMode": "Ouvrez un fichier ou un diff pour l'afficher automatiquement à côté de la conversation.", + "quickMessages": "Ouvrez le bouton + à côté de la saisie et choisissez Messages rapides pour insérer un extrait enregistré (à gérer dans Paramètres → Messages rapides).", + "experts": "Le bouton + propose un menu Compétences expertes — chargez en un clic des rôles comme Débogage ou Planification.", + "taskBoard": "Les tâches à faire exécutent un travail de bout en bout : l'agent travaille dans son propre worktree, vous relisez le diff puis fusionnez.", + "automations": "Les Automatisations exécutent un prompt enregistré selon un planning — une revue nocturne, un rapport récurrent — et chaque exécution peut avoir son propre worktree.", + "tokenUsage": "Cliquez sur le nombre de conversations dans la barre d'état pour ouvrir la Consommation de tokens, détaillée par jour, agent, modèle et dossier.", + "mentionTargets": "@ ne sert pas qu'aux fichiers : mentionnez un autre agent pour lui confier une sous-tâche, ou référencez une session passée, un commit ou une compétence.", + "splitGroups": "Faites un clic droit sur un onglet et choisissez Diviser à droite ou Diviser en bas pour garder deux conversations dans leurs propres volets.", + "worktrees": "Ouvrez le bouton de branche et choisissez Nouveau worktree pour que plusieurs agents travaillent sur le même dépôt sans écraser les fichiers des autres.", + "importSessions": "Vous avez déjà lancé des sessions dans le terminal ? Le menu d'un dossier propose Importer les sessions locales pour récupérer cet historique dans codeg.", + "subSessions": "Quand un agent délègue, la sous-session apparaît imbriquée sous lui dans la barre latérale : dépliez la ligne pour suivre ce que chacune a fait.", + "liveFeedback": "Retour en direct, dans le menu +, glisse une note dans le tour que l'agent exécute déjà, sans l'interrompre.", + "skillPacks": "Paramètres → Packs de compétences regroupe experts du code, recherche scientifique et bureautique ; activez-les agent par agent.", + "modelProviders": "Paramètres → Fournisseurs de Modèles accepte votre propre clé d'API ou endpoint, puis vous choisissez le modèle dans la zone de saisie.", + "workspaceBackground": "Paramètres → Apparence définit une image de fond pour l'espace de travail, l'opacité des panneaux et les polices de l'application." + }, + "quickActions": { + "excel": "Classeur Excel", + "excelDesc": "Tableaux, formules et graphiques", + "word": "Document Word", + "wordDesc": "Rapports, lettres et notes", + "ppt": "Présentation", + "pptDesc": "Diapositives au design professionnel", + "pitchDeck": "Pitch Deck", + "pitchDeckDesc": "Présentation de levée avec indicateurs", + "morph": "Animation Morph", + "morphDesc": "Transitions de diapositive cinématographiques", + "morph3d": "Morph 3D", + "morph3dDesc": "Modèles 3D avec mouvements de caméra", + "academic": "Article académique", + "academicDesc": "Recherche avec citations et structure", + "financial": "Modèle financier", + "financialDesc": "États, DCF et projections", + "dashboard": "Tableau de bord", + "dashboardDesc": "KPI et analyses à partir de vos données", + "prompts": { + "excel": "Crée un classeur Excel avec les exigences suivantes :\n\n[décris ici tes données, tableaux, formules et graphiques]", + "word": "Crée un document Word avec les exigences suivantes :\n\n[décris ici le contenu, la structure et la mise en forme du document]", + "ppt": "Crée une présentation PowerPoint avec les exigences suivantes :\n\n[décris ici tes diapositives, le contenu et le design]", + "pitchDeck": "Crée un pitch deck de levée de fonds avec les exigences suivantes :\n\n[décris ici ton entreprise, le tour de financement et les indicateurs clés]", + "morph": "Crée une présentation avec des animations de transition Morph :\n\n[décris ici le sujet de la présentation et les effets visuels souhaités]", + "morph3d": "Crée une présentation Morph 3D avec des modèles GLB et des mouvements de caméra :\n\n[décris ici ton sujet et le concept visuel en 3D]", + "academic": "Rédige un article académique dans Word avec les exigences suivantes :\n\n[décris ici ton sujet de recherche, la méthodologie et les principaux résultats]", + "financial": "Crée un modèle financier dans Excel avec les exigences suivantes :\n\n[décris ici tes états financiers, projections et analyses]", + "dashboard": "Crée un tableau de bord de données dans Excel avec les exigences suivantes :\n\n[décris ici ta source de données, les KPI et les graphiques]", + "scientific-brainstorming": "Aide-moi à imaginer des pistes de recherche : explore les liens interdisciplinaires, questionne les hypothèses et repère les lacunes prometteuses. Le domaine que j'explore : ", + "hypothesis-generation": "Aide-moi à transformer ces observations en hypothèses testables, avec des prédictions claires, des mécanismes plausibles et des expériences. Mes observations : ", + "experimental-design": "Aide-moi à concevoir une expérience rigoureuse avant de collecter des données : le plan, la randomisation, les contrôles et comment éviter les facteurs de confusion. Ce que je veux étudier : ", + "statistical-power": "Aide-moi à déterminer la taille d'échantillon nécessaire : guide-moi dans une analyse de puissance (taille d'effet, alpha, puissance) pour mon plan. Détails : ", + "statistical-analysis": "Aide-moi à analyser ces données correctement : choisir le bon test, vérifier les hypothèses, rapporter les tailles d'effet et rédiger. Mes données et ma question : ", + "exploratory-data-analysis": "Fais une analyse exploratoire de mon fichier de données : résume sa structure, sa qualité et les motifs notables, puis propose les prochaines étapes. Le fichier est : ", + "scientific-visualization": "Aide-moi à créer une figure de qualité publication : mise en page claire, barres d'erreur honnêtes, palette adaptée au daltonisme et mise en forme de revue. Ce que je veux montrer : ", + "scientific-critical-thinking": "Aide-moi à évaluer de façon critique cette étude ou affirmation : apprécie la qualité des preuves, repère les biais et facteurs de confusion, et pèse les conclusions. La voici : ", + "paper-lookup": "Aide-moi à trouver des articles pertinents et du texte intégral en libre accès dans les bases de données savantes, avec des citations réutilisables. Je cherche : " + }, + "paper-lookup": "Recherche d'articles", + "paper-lookupDesc": "Rechercher dans 10 API savantes (PubMed, arXiv, OpenAlex, Crossref…) articles, citations et texte intégral en libre accès.", + "scientific-critical-thinking": "Pensée critique", + "scientific-critical-thinkingDesc": "Évaluer les affirmations scientifiques et la qualité des preuves : repérer biais et facteurs de confusion, appliquer GRADE.", + "scientific-visualization": "Visualisation scientifique", + "scientific-visualizationDesc": "Figures prêtes à publier : dispositions multipanneaux, annotations de significativité et mise en forme par revue.", + "exploratory-data-analysis": "Analyse exploratoire des données", + "exploratory-data-analysisDesc": "Exploration automatisée de fichiers de données scientifiques (200+ formats) avec métriques de qualité et rapports.", + "statistical-analysis": "Analyse statistique", + "statistical-analysisDesc": "Analyse statistique guidée : choix du test, vérification des hypothèses, tailles d'effet et rapport au format APA.", + "statistical-power": "Puissance statistique", + "statistical-powerDesc": "Analyse de la taille d'échantillon et de la puissance : effectifs nécessaires, effets minimaux détectables, courbes de puissance.", + "experimental-design": "Plan d'expérience", + "experimental-designDesc": "Concevoir des études rigoureuses avant la collecte : randomisation, blocs, contrôles et plans factoriels/DOE.", + "hypothesis-generation": "Génération d'hypothèses", + "hypothesis-generationDesc": "Transformer des observations en hypothèses testables avec prédictions, mécanismes et expériences de test.", + "scientific-brainstorming": "Brainstorming scientifique", + "scientific-brainstormingDesc": "Idéation de recherche ouverte : explorer les liens interdisciplinaires, questionner les hypothèses, repérer les lacunes.", + "tabs": { + "office": "Bureautique", + "coding": "Développement", + "research": "Recherche" + }, + "coding": { + "brainstormingDesc": "Explorer intention et besoins avant de coder", + "debuggingDesc": "Trouver la cause racine avant de corriger", + "writingSkillsDesc": "Créer, modifier et vérifier des skills réutilisables" + }, + "notEnabled": { + "title": "La compétence « {skill} » n’est pas encore activée pour {agent}", + "description": "Activez-la dans les Paramètres pour l’utiliser ici.", + "action": "Activer", + "hint": "Compétence non activée" + }, + "scrollPrev": "Afficher les compétences précédentes", + "scrollNext": "Afficher plus de compétences" + } + }, + "agentSelector": { + "noEnabledAgents": "Aucun agent activé", + "openAgentsSettings": "Ouvrir les paramètres des agents", + "notInstalled": "Non installé", + "moreAgents": "Plus d'agents ({count})" + }, + "subAgentOverlay": { + "title": "Sous-agents", + "collapsedSummary": "Sous-agents {count}", + "collapseAria": "Réduire les sous-agents" + }, + "agentPlanOverlay": { + "title": "Plan de l'agent", + "collapsePlanAria": "Réduire le plan", + "collapsedSummary": "Plan de travail {completed}/{total}", + "status": { + "completed": "Terminé", + "inProgress": "En cours", + "pending": "En attente", + "unknown": "Inconnu" + }, + "priority": { + "high": "Haute", + "medium": "Moyenne", + "low": "Basse", + "unknown": "Inconnue" + } + }, + "permissionDialog": { + "subtitle": "L'agent demande une autorisation pour continuer ce tour.", + "queuedCount": "+{count} en attente", + "kindFallbackTool": "outil", + "command": "Commande", + "cwd": "Répertoire de travail : {cwd}", + "filesSummary": "Fichiers : {count}", + "moreFiles": "+{count} fichiers supplémentaires", + "plan": "Plan de travail", + "allowedActions": "Actions autorisées", + "targetMode": "Mode cible : {mode}", + "optionGrants": "Ce que chaque option accorde", + "changeScopeSession": "Cette session", + "changeScopeProcess": "Cette exécution", + "changeScopeUser": "Enregistré dans les paramètres utilisateur", + "changeScopeProject": "Enregistré dans les paramètres du projet", + "changeScopeProjectLocal": "Enregistré dans les paramètres locaux du projet", + "changeScopePersistent": "Enregistré définitivement" + }, + "questionDialog": { + "title": "L'agent pose une question", + "placeholder": "Tapez votre réponse...", + "send": "Envoyer" + }, + "messageBranch": { + "previousBranchAria": "Branche précédente", + "nextBranchAria": "Branche suivante", + "pageOf": "{current} sur {total}" + }, + "terminal": { + "title": "Console", + "running": "En cours" + }, + "reasoning": { + "thinking": "Réflexion…", + "thoughtForFewSeconds": "Réflexion", + "thoughtForSeconds": "Réflexion" + }, + "linkSafety": { + "errorCannotOpen": "Impossible d'ouvrir le fichier local", + "errorNoWorkspace": "Aucun dossier d'espace de travail n'est actuellement actif.", + "errorFailedOpen": "Échec de l'ouverture du fichier local", + "errorFailedLink": "Échec de l'ouverture du lien", + "errorUnsupportedLinkProtocol": "Ce protocole de lien n’est pas pris en charge." + }, + "fileActions": { + "openInFinder": "Ouvrir dans Finder", + "openInExplorer": "Ouvrir dans Explorer", + "openInFileManager": "Ouvrir dans le gestionnaire de fichiers", + "copyRelativePath": "Copier le chemin relatif", + "copyAbsolutePath": "Copier le chemin absolu", + "pathCopied": "Chemin copié", + "copyPathFailed": "Échec de la copie du chemin", + "openFailed": "Échec de l'ouverture du fichier local" + }, + "messageList": { + "attachedResources": "Ressources jointes", + "loading": "Chargement...", + "loadEarlier": "Charger les messages précédents", + "loadingEarlier": "Chargement des messages précédents…", + "error": "Erreur : {message}", + "errorTitle": "Échec du chargement de la session", + "errorActionReload": "Recharger", + "errorActionNewSession": "Nouvelle conversation", + "emptyConversation": "Aucun message dans cette conversation.", + "systemMessage": "Message système", + "copyMessage": "Copier", + "copied": "Copié", + "downloadImage": "Télécharger l'image", + "downloadFailed": "Échec du téléchargement : {message}", + "imageGeneration": "Génération d'image", + "imageGenerationPending": "Génération de l'image…", + "imageGenerationFailed": "Échec de la génération d'image", + "model": "Modèle", + "tokenStats": "Utilisation des tokens", + "tokenInput": "Entrée", + "tokenOutput": "Sortie", + "tokenCacheRead": "Lecture du cache", + "tokenCacheWrite": "Écriture du cache", + "duration": "Durée", + "completedAt": "Terminé à", + "jumpToPreviousUserMessage": "Aller au message utilisateur", + "showMore": "Afficher plus", + "showLess": "Afficher moins" + }, + "liveTurnStats": { + "thinking": "Réflexion...", + "streaming": "Diffusion", + "elapsedHours": "{value} h", + "elapsedMinutes": "{value} min", + "elapsedSeconds": "{value} s", + "outputSpeedAria": "Vitesse de sortie estimée", + "outputSpeedTooltip": "Vitesse de sortie estimée (texte + raisonnement)" + }, + "jsonTree": { + "viewRaw": "Afficher le JSON brut", + "viewTree": "Afficher l'arborescence", + "fields": "{count, plural, one {# champ} other {# champs}}", + "items": "{count, plural, one {# élément} other {# éléments}}" + }, + "tool": { + "parameters": "Paramètres", + "error": "Erreur", + "result": "Résultat", + "status": { + "approvalRequested": "En attente d'approbation", + "approvalResponded": "Répondu", + "inputAvailable": "En cours", + "inputStreaming": "En attente", + "outputAvailable": "Terminé", + "outputDenied": "Refusé", + "outputError": "Erreur" + } + }, + "toolCallBlock": { + "tool": "Outil", + "error": "Erreur", + "result": "Résultat" + }, + "delegation": { + "subAgentRunning": "Sous-agent en cours…", + "noDetail": "Aucun détail disponible pour le moment.", + "unknownAgent": "Sous-agent", + "openDetail": "Voir la conversation", + "detailTitle": "Conversation du sous-agent", + "detailDescription": "Vue en lecture seule de la conversation du sous-agent délégué.", + "waitForResult": "En attente du résultat de la tâche {task}", + "waitForResultNoTask": "En attente du résultat de la tâche", + "cancelTask": "Annulation de la tâche {task}", + "cancelTaskNoTask": "Annulation de la tâche", + "resultPageOf": "{current} / {total}", + "prevResult": "Résultat précédent", + "nextResult": "Résultat suivant", + "noResultText": "Aucun résultat pour cette vérification.", + "status": { + "starting": "démarrage", + "running": "en cours", + "checked": "vérifié", + "waiting": "en attente d'approbation", + "ok": "terminé", + "err": { + "default": "échec", + "delegation_disabled": "désactivé", + "depth_limit": "limite de profondeur", + "invalid_agent_type": "agent invalide", + "spawn_failed": "échec du démarrage", + "send_failed": "échec de l'envoi", + "timeout": "délai dépassé", + "canceled": "annulé", + "child_refusal": "sous-agent refusé", + "child_max_tokens": "sous-agent : limite de jetons", + "child_max_turn_requests": "sous-agent : limite de requêtes", + "child_empty": "sous-agent sans sortie", + "child_unknown": "sous-agent : erreur", + "unknown": "tâche inconnue" + } + } + }, + "contentParts": { + "showingTailOutput": "Affichage de la fin de la sortie pendant le streaming pour de meilleures performances.", + "result": "Résultat", + "unknown": "inconnu", + "inputTruncated": "L'entrée a été tronquée — le diff peut être incomplet.", + "replaceAll": "TOUT REMPLACER", + "filesCount": "Fichiers : {count}", + "update": "mettre à jour", + "moreFiles": "+{count} fichiers supplémentaires", + "timeoutMs": "Délai d'expiration : {timeout}ms", + "backgroundTrue": "Arrière-plan : true", + "scriptToolCalls": "{count, plural, one {# appel d'outil} other {# appels d'outil}}", + "offset": "Décalage : {offset}", + "limit": "Limite : {limit}", + "pages": "Pages : {pages}", + "mode": "Mode : {mode}", + "cell": "Cellule : {cell}", + "shellSession": "Session {id}", + "pathLabel": "Chemin :", + "globLabel": "Glob :", + "typeLabel": "Type :", + "outputLabel": "Sortie :", + "caseInsensitive": "Insensible à la casse", + "multiline": "Multiligne", + "promptLabel": "Instruction", + "subjectLabel": "Sujet", + "taskLabel": "Tâche", + "nameLabel": "Nom :", + "agentPromptLabel": "Instruction", + "agentModelLabel": "Modèle", + "agentRunning": "En cours...", + "agentLiveTranscript": "Activité en direct", + "agentProgressTools": "{count} appels d'outils", + "agentProgressTurns": "{count} tours", + "agentProgressContext": "contexte {pct}%", + "agentSessionAction": "Voir la session du sous-agent", + "agentSessionTitle": "Session du sous-agent", + "agentSessionLoading": "Chargement de la transcription du sous-agent…", + "agentSessionEmpty": "Le sous-agent n'a encore rien écrit.", + "agentFallbackTitle": "Démarrage du sous-agent…", + "agentCodexLaunchOnly": "Lancé. Codex ne signale plus la progression de ce sous-agent : son résultat arrivera sous forme de message dans cette conversation.", + "agentStatsBash": "Commandes", + "agentStatsRead": "Fichiers lus", + "agentStatsSearch": "Recherches", + "agentStatsEdit": "Modifications", + "agentStatsOther": "Autres", + "goal": { + "title": "Objectif :", + "titleWithStatus": "Objectif {status}", + "objective": "Objectif", + "statusLabel": "Statut", + "tokensUsed": "Tokens utilisés", + "budget": "Budget", + "remaining": "Restant", + "elapsed": "Écoulé", + "tokens": "tokens", + "pause": "Pause", + "clear": "Effacer", + "status": { + "active": "actif", + "paused": "en pause", + "blocked": "bloqué", + "usageLimited": "utilisation limitée", + "budgetLimited": "budget limité", + "complete": "terminé", + "limited": "limite atteinte" + } + }, + "field": { + "file": "Fichier", + "notebook": "Carnet", + "command": "Commande", + "old": "Ancien", + "new": "Nouveau", + "pattern": "Motif", + "path": "Chemin", + "query": "Requête", + "url": "URL :", + "description": "Détails", + "content": "Contenu", + "source": "Origine", + "prompt": "Instruction", + "subject": "Sujet", + "taskId": "ID de tâche", + "status": "Statut", + "skill": "Skill", + "args": "Arguments", + "offset": "Décalage", + "limit": "Limite", + "glob": "Motif glob", + "type": "Type de donnée", + "output": "Sortie", + "replaceAll": "Tout remplacer", + "language": "Langue", + "timeout": "Délai", + "background": "Arrière-plan", + "agentType": "Type d'agent", + "library": "Bibliothèque", + "libraryId": "ID de bibliothèque" + }, + "title": { + "edit": "Modifier", + "command": "Commande", + "script": "Script", + "waitCommand": "Attendre {command}", + "waitCell": "Attendre la session {id}", + "terminateCommand": "Terminer {command}", + "terminateCell": "Terminer la session {id}", + "stdinChars": "Entrée {chars}", + "todoWrite": "TodoWrite (mise à jour des tâches)", + "read": "Lire", + "write": "Écrire", + "notebookEdit": "NotebookEdit (édition du carnet)", + "editFiles": "Modifier ({count} fichiers)", + "editWithTarget": "Modifier {target}", + "readWithTarget": "Lire {target}", + "writeWithTarget": "Écrire {target}", + "notebookEditWithTarget": "NotebookEdit ({target})", + "globWithPattern": "Motif glob {pattern}", + "listFilesWithPath": "Lister les fichiers {path}", + "grepWithPattern": "Motif grep {pattern}", + "taskCreateWithSubject": "Créer une tâche : {subject}", + "taskUpdateWithStatus": "Mettre à jour la tâche #{id} -> {status}", + "taskUpdate": "Mettre à jour la tâche #{id}", + "webFetchWithUrl": "WebFetch ({url})", + "webSearchWithQuery": "Recherche web : {query}", + "todosProgress": "Tâches ({done}/{total})", + "skillWithName": "Skill : {name}", + "genericWithContext": "{tool} ({context})" + }, + "search": { + "noMatches": "Aucune correspondance", + "matchSummary": "{matches, plural, one {# correspondance} other {# correspondances}} dans {files, plural, one {# fichier} other {# fichiers}}", + "fileSummary": "{files, plural, one {# fichier} other {# fichiers}}", + "moreResults": "{count, plural, one {# résultat supplémentaire non affiché} other {# résultats supplémentaires non affichés}}" + }, + "toolGroup": { + "search": "{count, plural, one {A exploré # recherche} other {A exploré # recherches}}", + "command": "{count, plural, one {A exécuté # commande} other {A exécuté # commandes}}", + "read": "{count, plural, one {A lu des fichiers # fois} other {A lu des fichiers # fois}}", + "memory": "{count, plural, one {A rappelé # souvenir} other {A rappelé # souvenirs}}", + "edit": "{count, plural, one {A modifié des fichiers # fois} other {A modifié des fichiers # fois}}", + "fetch": "{count, plural, one {A récupéré # ressource} other {A récupéré # ressources}}", + "think": "{count, plural, one {A réfléchi # fois} other {A réfléchi # fois}}", + "todo": "{count, plural, one {A mis à jour # tâche} other {A mis à jour # tâches}}", + "task": "{count, plural, one {A lancé # tâche} other {A lancé # tâches}}", + "other": "{count, plural, one {A utilisé # outil} other {A utilisé # outils}}", + "errorSuffix": "{count, plural, one {# échec} other {# échecs}}", + "joiner": " · " + }, + "planMode": { + "entered": "Mode planification activé", + "planLabel": "Plan", + "reviewApproved": "Plan approuvé — mise en œuvre", + "reviewKept": "Reste en mode plan", + "reviewPending": "En attente de la décision sur le plan", + "submitted": "Plan soumis", + "switched": "Mode changé" + }, + "backgroundTask": { + "title": "Tâche en arrière-plan", + "titleWithId": "Tâche en arrière-plan · {id}", + "running": "En cours", + "completed": "Terminée", + "failed": "Échouée", + "stopped": "Arrêtée", + "exitCode": "sortie {code}", + "polledTimes": "Interrogée {count} fois", + "runningInBackground": "Arrière-plan", + "launchNote": "En cours d'exécution en arrière-plan · {id}" + }, + "codexScript": { + "outputMissing": "Codex a tronqué la sortie du script et supprimé le séparateur de cette commande ; aucune sortie n'a donc pu lui être attribuée.", + "sharedWith": "Contient aussi la sortie de {commands} — codex en a tronqué les séparateurs.", + "truncated": "tronqué" + } + }, + "messageNav": { + "title": "Navigation des messages", + "collapse": "Réduire la navigation des messages", + "collapsedSummary": "Messages {count}", + "fileCount": "{count, plural, one {# fichier} other {# fichiers}}", + "remove": "Retirer", + "noDiffDataAvailable": "Aucune donnée de diff disponible pour {filePath}" + }, + "replyArtifacts": { + "title": "Fichiers modifiés", + "fileCount": "{count, plural, one {# fichier} other {# fichiers}}", + "newFilesTitle": "Nouveaux fichiers", + "revealInFolder": "Afficher dans le gestionnaire de fichiers", + "openFile": "Ouvrir {filePath}", + "openInEditor": "Ouvrir dans l'éditeur", + "remove": "Retirer", + "noDiffDataAvailable": "Aucune donnée de diff disponible pour {filePath}" + }, + "askQuestion": { + "title": "L'agent attend votre choix", + "subtitle": "Répondez puis envoyez. Vous pouvez ignorer à tout moment.", + "recommended": "Recommandé", + "other": "Autre", + "otherPlaceholder": "Saisissez votre réponse…", + "singleSelect": "Unique", + "multiSelect": "Multiple", + "skip": "Ignorer", + "next": "Suivant", + "submit": "Envoyer", + "submitError": "Échec de l'envoi. Veuillez réessayer." + }, + "planApproval": { + "title": "L'agent a un plan — à vérifier", + "emptyPlan": "L'agent n'a pas rédigé de plan. Approuvez pour commencer ou demandez des modifications.", + "approve": "Approuver et lancer", + "requestChanges": "Demander des modifications", + "abandon": "Abandonner", + "feedbackPlaceholder": "Que faut-il changer ?", + "sendChanges": "Envoyer", + "cancel": "Annuler", + "submitError": "Échec de l'envoi. Veuillez réessayer." + }, + "feedbackCheckResult": { + "count": "{count, plural, =1 {1 retour} other {# retours}}", + "expand": "Afficher tous les retours", + "collapse": "Réduire", + "errorTitle": "Échec de la vérification des retours" + }, + "askQuestionResult": { + "title": "Question", + "answeredLabel": "Question et réponse :", + "awaiting": "En attente de ta réponse…", + "declined": "Tu as ignoré cette question — l’agent a utilisé son propre jugement.", + "noSelection": "Aucune sélection" + }, + "configStale": { + "agentConfigTitle": "Paramètres de l'agent mis à jour", + "modelProviderTitle": "Fournisseur de modèle mis à jour", + "description": "Cette session utilise encore son ancienne configuration. Reconnectez-vous pour l'appliquer (l'historique de conversation est conservé).", + "reconnect": "Reconnecter pour appliquer", + "reconnecting": "Reconnexion…", + "reconnectDisabledDuringTurn": "Disponible une fois le tour en cours terminé", + "dismiss": "Ignorer", + "reconnectFailed": "Échec de la reconnexion de la session", + "applied": "Nouvelle configuration appliquée" + }, + "piProjectTrust": { + "title": "Ce projet fournit des ressources pi", + "description": "pi ne charge pas les fichiers .pi du dépôt. Examinez-les pour décider.", + "descriptionExecutable": "Le dépôt fournit des extensions pi, qui exécutent du code au démarrage. pi ne les charge pas. Examinez-les avant de décider.", + "review": "Examiner…", + "dismiss": "Ignorer", + "dialogTitle": "Faire confiance aux ressources pi de ce projet ?", + "dialogDescription": "pi ne charge les fichiers .pi d'un dépôt que si vous faites confiance au dossier. N'accordez votre confiance que si vous avez confiance dans le contenu de ce dépôt.", + "executionWarning": "Les extensions sont du code. En faisant confiance à ce dossier, vous autorisez le dépôt à les exécuter au démarrage de pi avec vos permissions, avant même l'envoi d'un message.", + "scopeNote": "La décision est enregistrée dans le trust.json de pi pour ce dossier, s'applique à tous les dossiers qu'il contient et sert aussi lorsque vous lancez pi vous-même dans un terminal. Vous pourrez la modifier dans Paramètres → Agents → Pi.", + "trust": "Faire confiance au projet", + "decline": "Ne pas charger", + "disabledDuringTurn": "Disponible une fois le tour en cours terminé", + "trustedToast": "Projet approuvé — reconnexion effectuée pour que pi charge ses ressources", + "declinedToast": "Les ressources du projet restent non chargées", + "saveFailed": "Échec de l'enregistrement de la décision de confiance du projet", + "grantTitle": "Ce projet est déjà approuvé", + "grantDescription": "pi charge les fichiers .pi du dépôt. Examinez ce que cela autorise.", + "grantInheritedDescription": "Un dossier parent est approuvé, donc pi charge les fichiers .pi du dépôt. Examinez ce que cela autorise.", + "grantDialogTitle": "Les ressources pi de ce projet sont approuvées", + "grantDialogDescription": "pi est autorisé à charger les fichiers .pi du dépôt. Les versions précédentes de codeg accordaient cela automatiquement à l'ouverture d'un dossier, la question ne vous a donc peut-être jamais été posée.", + "grantExecutionWarning": "Les extensions sont du code. Le dépôt les exécute au démarrage de pi avec vos permissions, avant même l'envoi d'un message.", + "inheritedFrom": "Approuvé via", + "revoke": "Révoquer la confiance", + "keepTrusted": "Conserver la confiance", + "revokedToast": "Confiance révoquée — reconnexion effectuée pour que pi cesse de charger les ressources du projet", + "trustedNoReconnect": "Projet approuvé — effectif au prochain démarrage de pi", + "revokedNoReconnect": "Confiance révoquée — effectif au prochain démarrage de pi" + }, + "collabAgent": { + "title": "Sous-agent", + "errorTitle": "Échec de la tâche du sous-agent", + "statesLabel": "Sous-agents", + "statusRunning": "En cours", + "statusCompleted": "Terminé", + "statusFailed": "Échec", + "statusPending": "Démarrage", + "statusInterrupted": "Interrompu", + "statusClosed": "Fermé", + "statusNotFound": "Introuvable", + "opSpawn": "Démarrage du sous-agent", + "opWait": "Récupération du résultat du sous-agent", + "opClose": "Fermeture du sous-agent", + "opResume": "Reprise du sous-agent" + }, + "contextCompaction": { + "compacting": "Compactage du contexte…", + "compacted": "Contexte compacté", + "compactedTokens": "Contexte compacté · {before} → {after} tokens", + "failed": "Échec de la compaction du contexte" + }, + "sessionFailure": { + "category": { + "connection": "Problème de connexion", + "access": "Problème d'accès", + "limit": "Limite atteinte", + "request": "Requête rejetée", + "service": "Problème de service", + "unknown": "Problème de session" + }, + "action": { + "retry": "Réessayer", + "login": "Se connecter", + "newSession": "Nouvelle session" + }, + "recovered": "Rétabli", + "retryUnavailable": "Aucun message précédent à renvoyer.", + "toggleDetails": "Afficher/masquer les détails" + }, + "backgroundTasks": { + "running": "{count, plural, one {# tâche en arrière-plan en cours} other {# tâches en arrière-plan en cours}}", + "settling": "Synchronisation des résultats d'arrière-plan…", + "settledFallback": "Tâche en arrière-plan terminée ({status})", + "cardRunning": "En cours d'exécution en arrière-plan", + "cardLaunchedPending": "Tâche lancée en arrière-plan", + "cardCompleted": "Tâche en arrière-plan terminée", + "cardFinishedWithStatus": "Tâche en arrière-plan terminée ({status})", + "cardResultPending": "Résultat pas encore reçu" + }, + "proposedPlan": { + "title": "Plan proposé", + "planning": "Planification…" + } + }, + "diffPreview": { + "mode": { + "added": "Ajouté", + "deleted": "Supprimé", + "renamed": "Renommé", + "modified": "Modifié" + }, + "hunkLabel": "Bloc {index}", + "loadingHunk": "Chargement du hunk...", + "noDiffData": "Aucune donnée diff", + "showRemainingLines": "Afficher {count} lignes de plus" + }, + "conversationContextBar": { + "folderTitle": "Dossier de travail", + "branchTitle": "Branche de travail", + "searchFolder": "Rechercher un dossier...", + "searchBranch": "Rechercher une branche...", + "noFolders": "Aucun dossier", + "noBranches": "Aucune branche", + "noBranch": "(aucune branche)", + "chatModeLabel": "Mode chat", + "commit": "Valider", + "push": "Pousser", + "merge": "Fusionner", + "toasts": { + "folderChanged": "Basculé vers {name}", + "openFolderFailed": "Échec de l'ouverture du dossier", + "switchedToChatMode": "Basculé en mode discussion", + "openStashFailed": "Échec de l'ouverture de la fenêtre de remisage", + "openMergeFailed": "Échec de l'ouverture de la fenêtre de fusion" + } + }, + "cloneDialog": { + "title": "Cloner un dépôt", + "repositoryUrl": "URL du dépôt", + "repositoryUrlPlaceholder": "https://github.com/user/repo.git", + "directory": "Répertoire", + "directoryPlaceholder": "Sélectionnez le répertoire cible...", + "browseDirectory": "Parcourir le répertoire", + "cancel": "Annuler", + "clone": "Cloner", + "clonePath": "Chemin de clonage : {path}" + }, + "toasts": { + "cloneFailed": "Échec du clonage du dépôt" + } + }, + "ProjectBoot": { + "title": "Lanceur de projet", + "tabs": { + "shadcn": "shadcn", + "hyperframes": "HyperFrames" + }, + "hyperframes": { + "title": "Projet vidéo HyperFrames", + "subtitle": "Générez un projet HTML-vers-vidéo. L'agent de l'espace de travail peut ensuite l'écrire et le rendre.", + "resolution": "Résolution", + "skillsTitle": "Skills des agents", + "skillsDesc": "Installe globalement les skills HyperFrames (lien symbolique) pour les agents sélectionnés, afin qu'ils puissent créer et rendre des vidéos.", + "recheck": "Revérifier", + "installedBadge": "Installé", + "skillsInstall": "Installer / mettre à jour les skills", + "skillsInstalling": "Installation des skills…", + "skillsInstalled": "Skills HyperFrames installées", + "skillsInstallFailed": "Impossible d'installer les skills HyperFrames" + }, + "config": { + "base": "Base", + "style": "Style", + "baseColor": "Couleur de base", + "theme": "Thème", + "chartColor": "Couleur du graphique", + "iconLibrary": "Bibliothèque d'icônes", + "font": "Police", + "fontHeading": "Police de titre", + "menuAccent": "Accent du menu", + "menuColor": "Couleur du menu", + "radius": "Rayon", + "template": "Modèle", + "createProject": "Créer un projet", + "sectionStyle": "Style", + "sectionColors": "Couleurs", + "sectionTypography": "Typographie", + "sectionInterface": "Interface" + }, + "preview": { + "loading": "Chargement de l'aperçu..." + }, + "createDialog": { + "title": "Créer un projet", + "projectName": "Nom du projet", + "projectNamePlaceholder": "mon-app", + "frameworkTemplate": "Modèle de framework", + "packageManager": "Gestionnaire de paquets", + "saveDirectory": "Répertoire de sauvegarde", + "saveDirectoryPlaceholder": "Sélectionner un répertoire...", + "browseDirectory": "Parcourir", + "projectPath": "Le projet sera créé dans : {path}", + "advancedOptions": "Options avancées", + "base": "Bibliothèque de base", + "enableRtl": "Activer le support RTL", + "enableRtlDescription": "Activer la prise en charge de la mise en page pour les langues de droite à gauche (ex. arabe, hébreu)", + "pmChecking": "Vérification...", + "pmNotInstalled": "Non installé", + "cancel": "Annuler", + "create": "Créer", + "creating": "Création du projet..." + }, + "toasts": { + "createFailed": "Échec de la création du projet", + "createSuccess": "Projet créé avec succès", + "openWorkspaceFailed": "Projet créé, mais impossible de l'ouvrir dans l'espace de travail" + }, + "errors": { + "directoryExists": "Le répertoire cible existe déjà", + "commandFailed": "La commande de création du projet a échoué." + } + }, + "WebServiceSettings": { + "addressSwitchHint": "Changer ne modifie que l'adresse affichée et ouverte ici ; le service écoute sur toutes les interfaces et reste accessible à chaque adresse.", + "sectionTitle": "Service Web", + "sectionDescription": "Activer pour accéder à Codeg à distance via le navigateur", + "port": "Port", + "status": "Statut", + "autoStart": "Démarrage auto", + "autoStartHint": "Démarrer le service Web au lancement de Codeg", + "running": "En cours", + "stopped": "Arrêté", + "processing": "Traitement...", + "start": "Démarrer", + "stop": "Arrêter", + "startFailed": "Échec du démarrage", + "stopFailed": "Échec de l'arrêt", + "saveConfigFailed": "Échec de l'enregistrement des paramètres du service Web", + "open": "Ouvrir", + "hide": "Masquer", + "show": "Afficher", + "copy": "Copier", + "qrcode": "Code QR", + "qrcodeTitle": "Scanner pour ouvrir", + "qrcodeHint": "Scannez avec votre téléphone pour ouvrir Codeg dans un navigateur", + "addressLabel": "Adresse d'accès", + "tokenLabel": "Token d'accès", + "tokenHint": "Entrez ce token lors du premier accès au client Web", + "tokenPlaceholder": "Laisser vide pour générer automatiquement", + "regenerate": "Régénérer", + "stalePortOccupiedTitle": "Le port {port} est utilisé par un autre processus", + "stalePortUnknownTitle": "L'état du port {port} est indéterminé", + "stalePortHint": "Codeg ne peut pas s'attacher tant que le port n'est pas libéré. Changez de port ci-dessus, ou fermez le processus qui le retient.", + "errors": { + "alreadyRunning": "Le service Web est déjà en cours d'exécution", + "invalidAddress": "Format d'hôte ou de port non valide", + "portInUse": "Le port {port} est déjà utilisé. Fermez le processus qui l'utilise ou choisissez un autre port.", + "permissionDenied": "Permission refusée. Utilisez un port supérieur à 1024 ou exécutez avec des privilèges plus élevés.", + "addressUnavailable": "Cette adresse n'est pas disponible sur cette machine", + "bindFailed": "Échec de la liaison à l'adresse" + } + }, + "DirectoryBrowser": { + "title": "Parcourir le répertoire", + "pathPlaceholder": "Entrez le chemin du répertoire...", + "goHome": "Aller au répertoire personnel", + "navigateUp": "Aller au répertoire parent", + "select": "Sélectionner", + "cancel": "Annuler", + "loading": "Chargement...", + "emptyDirectory": "Ce répertoire est vide", + "errorLoadingDir": "Échec du chargement du répertoire", + "permissionDenied": "Permission refusée" + }, + "ChatChannelSettings": { + "loading": "Chargement...", + "sectionTitle": "Canaux de chat", + "sectionDescription": "Configurez des bots IM pour recevoir des notifications d'événements et interroger l'activité de codage.", + "addChannel": "Ajouter un canal", + "noChannels": "Aucun canal de chat configuré pour le moment.", + "channelName": "Nom", + "channelNamePlaceholder": "Mon bot Telegram", + "channelType": "Type de canal", + "lark": "Lark (Feishu)", + "weixin": "WeChat", + "dailyReport": "Rapport quotidien", + "dailyReportTime": "Heure du rapport", + "nameRequired": "Le nom du canal est requis.", + "tokenRequired": "Le token est requis.", + "chatIdRequired": "Le Chat ID est requis.", + "topicMode": "Mode groupe de sujets", + "topicModeHint": "Route les sujets de forum Telegram comme des sessions Codeg séparées. Le bot doit être dans un supergroupe forum et pouvoir gérer les sujets.", + "loadFailed": "Échec du chargement des canaux.", + "saveFailed": "Échec de l'enregistrement.", + "connectSuccess": "Canal connecté.", + "connectFailed": "Échec de la connexion", + "disconnectSuccess": "Canal déconnecté.", + "disconnectFailed": "Échec de la déconnexion.", + "testSuccess": "Test de connexion réussi.", + "testFailed": "Test de connexion échoué", + "deleteSuccess": "Canal supprimé.", + "deleteFailed": "Échec de la suppression du canal.", + "deleteConfirmTitle": "Supprimer le canal", + "deleteConfirmMessage": "Le canal et ses journaux de messages seront définitivement supprimés. Êtes-vous sûr ?", + "cancel": "Annuler", + "delete": "Supprimer", + "create": "Créer", + "save": "Enregistrer", + "channelListTitle": "Canaux configurés", + "channelListDescription": "Les canaux activés se connectent automatiquement au démarrage du service.", + "editChannel": "Modifier le canal", + "editSuccess": "Canal mis à jour.", + "tokenPlaceholderKeep": "Laisser vide pour conserver l'actuel", + "weixinScanTitle": "Scanner le QR code", + "weixinScanDescription": "Ouvrez WeChat et scannez le QR code pour vous connecter.", + "weixinQrcodeExpired": "QR code expiré.", + "weixinRefreshQrcode": "Actualiser", + "weixinWaitingScan": "En attente du scan...", + "weixinPollError": "Connexion instable, nouvelle tentative...", + "weixinReconnectNotice": "En raison des limitations du protocole iLink, après chaque reconnexion vous devez envoyer un message au bot pour que les déclencheurs d'événements prennent effet.", + "connect": "Connecter", + "disconnect": "Déconnecter", + "test": "Tester la connexion", + "tabs": { + "channels": "Canaux", + "commands": "Commandes", + "events": "Événements", + "other": "Autres" + }, + "commands": { + "title": "Commandes intégrées", + "description": "Commandes bot disponibles dans les canaux de chat. Dans les chats de groupe, @Bot est requis pour traiter les messages.", + "prefixLabel": "Préfixe de commande", + "prefixDescription": "1-3 caractères non alphanumériques pour déclencher les commandes du bot (par défaut /).", + "prefixSaved": "Préfixe de commande enregistré.", + "prefixSaveFailed": "Échec de l'enregistrement du préfixe.", + "prefixInvalid": "Le préfixe doit être de 1-3 caractères non alphanumériques.", + "save": "Enregistrer", + "folderDesc": "Sélectionner le dossier de travail", + "agentDesc": "Sélectionner l'agent IA", + "taskDesc": "Créer une session et exécuter la tâche", + "sessionsDesc": "Lister les sessions actives du dossier", + "resumeDesc": "Conversations récentes / reprendre une session", + "cancelDesc": "Annuler la tâche en cours", + "approveDesc": "Approuver la demande de permission de l'agent", + "denyDesc": "Refuser la demande de permission de l'agent", + "searchDesc": "Rechercher des conversations par mot-clé", + "todayDesc": "Résumé de l'activité du jour", + "statusDesc": "État de connexion du canal", + "helpDesc": "Afficher l'aide" + }, + "events": { + "title": "Notifications d'événements", + "description": "Une fois activés, les événements déclenchés seront envoyés au canal.", + "turnComplete": "Tour terminé", + "turnCompleteDesc": "Lorsqu'un tour d'agent se termine", + "error": "Erreur de l'agent", + "errorDesc": "Lorsqu'un agent rencontre une erreur", + "permissionRequest": "Demande d'autorisation", + "permissionRequestDesc": "Lorsqu'un agent demande une autorisation", + "questionRequest": "Question de l'agent", + "questionRequestDesc": "Quand un agent vous pose une question", + "userPromptSent": "Message de l'utilisateur", + "userPromptSentDesc": "Lorsque vous envoyez un message (le texte du message est inclus dans la notification)", + "saved": "Filtre d'événements mis à jour.", + "saveFailed": "Échec de l'enregistrement du filtre d'événements.", + "loadFailed": "Échec du chargement des paramètres.", + "retry": "Réessayer", + "webhooksTitle": "Webhooks", + "webhooksDescription": "Envoie une charge JSON via POST vers une ou plusieurs URL lorsqu'un événement activé se déclenche. Le filtre d'événements ci-dessus s'applique aussi aux webhooks.", + "webhookUrlPlaceholder": "https://example.com/webhook", + "addWebhook": "Ajouter un webhook", + "removeWebhook": "Supprimer le webhook", + "webhookSave": "Enregistrer", + "webhooksSaved": "Webhooks enregistrés.", + "webhooksSaveFailed": "Échec de l'enregistrement des webhooks.", + "webhookInvalidUrl": "Saisissez des URL http(s) valides.", + "docsTitle": "Format de la requête", + "docsMethod": "Méthode", + "docsContentType": "Content-Type", + "docsNote": "Chaque événement activé est envoyé à toutes les URL. Les webhooks ne sont pas anti-rebond ; le filtre d'événements ci-dessus s'applique toujours.", + "editWebhook": "Modifier le webhook", + "enableWebhook": "Activer le webhook", + "webhookDuplicate": "Cette URL est déjà configurée.", + "cancel": "Annuler", + "webhooksEmpty": "Aucun webhook configuré pour le moment.", + "deleteWebhookTitle": "Supprimer le webhook", + "deleteWebhookMessage": "Supprimer ce webhook ? Les événements ne seront plus envoyés à cette URL.", + "delete": "Supprimer" + }, + "language": { + "title": "Langue des messages", + "description": "Langue utilisée pour les notifications d'événements, les réponses aux commandes et les rapports quotidiens envoyés aux canaux de chat.", + "saved": "Langue des messages enregistrée.", + "saveFailed": "Échec de l'enregistrement de la langue des messages.", + "en": "Anglais", + "zh-cn": "Chinois simplifié", + "zh-tw": "Chinois traditionnel", + "ja": "Japonais", + "ko": "Coréen", + "es": "Espagnol", + "de": "Allemand", + "fr": "Français", + "pt": "Portugais", + "ar": "Arabe" + } + }, + "ModelProviderSettings": { + "sectionTitle": "Fournisseurs de Modèles", + "sectionDescription": "Gérer les identifiants des fournisseurs d'API pour les agents.", + "filterAll": "Tous", + "providerListTitle": "Fournisseurs Configurés", + "addProvider": "Ajouter un Fournisseur", + "editProvider": "Modifier le Fournisseur", + "noProviders": "Aucun fournisseur de modèle configuré.", + "providerName": "Nom", + "providerNamePlaceholder": "Ex. OpenAI, Anthropic", + "apiUrl": "URL de l'API", + "apiUrlPlaceholder": "https://api.openai.com/v1", + "apiKey": "Clé API", + "apiKeyPlaceholder": "sk-...", + "apiKeyKeepCurrent": "Laisser vide pour conserver l'actuelle", + "agentTypes": "Types d'Agent", + "agentTypesRequired": "Au moins un type d'agent est requis.", + "agentType": "Type d'Agent", + "agentTypeRequired": "Le type d'agent est requis.", + "agentTypeImmutableHint": "Le type d'agent ne peut pas être modifié après la création.", + "model": "Modèle", + "modelPlaceholderCodex": "gpt-5.6-sol / gpt-5.5", + "modelPlaceholderGemini": "gemini-3-pro-preview", + "claudeMainModel": "Modèle Principal", + "claudeReasoningModel": "Modèle de Raisonnement (réflexion)", + "claudeHaikuDefaultModel": "Modèle Haiku par Défaut", + "claudeSonnetDefaultModel": "Modèle Sonnet par Défaut", + "claudeOpusDefaultModel": "Modèle Opus par Défaut", + "claudeCustomModelOption": "ID de modèle personnalisé", + "claudeCustomModelOptionName": "Nom du modèle personnalisé", + "claudeCustomModelOptionDescription": "Description du modèle personnalisé", + "claudeCustomModelOptionHint": "Ajoute une entrée personnalisée au sélecteur de modèles de Claude (par exemple un modèle derrière une passerelle/un proxy personnalisé). Le nom et la description sont des informations d'affichage facultatives.", + "nameRequired": "Le nom du fournisseur est requis.", + "apiUrlRequired": "L'URL de l'API est requise.", + "apiKeyRequired": "La clé API est requise.", + "loadFailed": "Échec du chargement des fournisseurs.", + "saveFailed": "Échec de la sauvegarde.", + "createSuccess": "Fournisseur créé.", + "editSuccess": "Fournisseur mis à jour.", + "deleteSuccess": "Fournisseur supprimé.", + "deleteConfirmTitle": "Supprimer le Fournisseur", + "deleteConfirmMessage": "Le fournisseur \"{name}\" sera définitivement supprimé. Êtes-vous sûr ?", + "deleteBlockedByAgent": "{agents} utilise ce fournisseur. Veuillez le dissocier avant de supprimer.", + "cancel": "Annuler", + "delete": "Supprimer", + "create": "Créer", + "save": "Enregistrer", + "affectedRunningSessions": "{count, plural, one {# session active doit se reconnecter pour appliquer la modification} other {# sessions actives doivent se reconnecter pour appliquer la modification}}" + }, + "SkillMatrix": { + "loading": "Chargement…", + "searchPlaceholder": "Rechercher par nom, id ou description", + "empty": "Rien à afficher.", + "emptySearch": "Aucun résultat pour la recherche actuelle.", + "skillColumn": "Compétence", + "selectAll": "Tout sélectionner (visible)", + "selectSkill": "Sélectionner {name}", + "everything": { + "label": "En masse", + "enable": "Tout activer (visible)", + "disable": "Tout désactiver (visible)" + }, + "columnMenu": { + "enableAll": "Activer toutes les compétences", + "disableAll": "Désactiver toutes les compétences" + }, + "rowMenu": { + "label": "Actions groupées pour {name}", + "enableAll": "Activer pour tous les agents", + "disableAll": "Désactiver pour tous les agents" + }, + "bulk": { + "selected": "{count} sélectionné(s)", + "targetAll": "Tous les agents", + "targetSome": "{count} agents", + "enable": "Activer", + "disable": "Désactiver", + "clear": "Effacer" + }, + "confirm": { + "disableTitle": "Désactiver ces liens ?", + "disableBody": "Cela supprimera {count} liens de compétences gérés par codeg. Les compétences occupant un répertoire personnalisé ne sont pas touchées. Vous pouvez les réactiver à tout moment.", + "cancel": "Annuler", + "confirm": "Désactiver" + }, + "toasts": { + "loadFailed": "Échec du chargement des états des compétences", + "applyFailed": "Échec de l'application des modifications", + "enabled": "{count} liens activés", + "disabled": "{count} liens désactivés", + "enabledPartial": "{ok} activés, {failed} échoués", + "disabledPartial": "{ok} désactivés, {failed} échoués" + }, + "detail": { + "enableForAgents": "Activer pour les agents", + "preview": "Aperçu de SKILL.md", + "loadingContent": "Chargement du contenu…" + }, + "copyModeHint": "Copié (non lié) — réactivez après les mises à jour pour obtenir la dernière version" + }, + "ExpertsSettings": { + "title": "Compétences d'experts", + "description": "Activez des workflows de compétences soigneusement sélectionnés et éprouvés pour vos agents de codage IA. Chaque expert est une compétence autonome du projet superpowers — codeg gère la copie centrale et la lie aux agents que vous choisissez.", + "loading": "Chargement des experts…", + "loadingContent": "Chargement du contenu…", + "emptyExperts": "Aucun expert disponible. Vérifiez les journaux de l'application.", + "emptySelection": "Sélectionnez un expert pour voir son contenu et gérer son activation.", + "emptySearch": "Aucun expert ne correspond à la recherche actuelle.", + "searchPlaceholder": "Rechercher des experts par nom, ID ou description", + "enableForAgents": "Activer pour les agents", + "noAgents": "Aucun agent ACP détecté.", + "copyModeWarning": "Copié (non lié). Réactivez après les mises à jour de codeg pour obtenir la dernière version.", + "previewTitle": "Aperçu de SKILL.md", + "categories": { + "discovery": "Découverte et conception", + "planning": "Planification", + "execution": "Exécution", + "quality": "Qualité et tests", + "debugging": "Débogage", + "review": "Révision et intégration", + "meta": "Méta" + }, + "states": { + "not_linked": "Non activé", + "linked_to_codeg": "Activé", + "linked_elsewhere": "Bloqué — un autre lien existe", + "blocked_by_real_directory": "Bloqué — une compétence personnalisée occupe ce nom", + "broken": "Lien cassé" + }, + "badges": { + "userModified": "Modifié par l'utilisateur" + }, + "actions": { + "openCentralDir": "Ouvrir le dossier central", + "refresh": "Actualiser" + }, + "toasts": { + "loadFailed": "Échec du chargement des détails de l'expert", + "enabled": "Expert activé pour cet agent", + "disabled": "Expert désactivé pour cet agent", + "enableFailed": "Échec de l'activation de l'expert", + "disableFailed": "Échec de la désactivation de l'expert", + "openFolderFailed": "Échec de l'ouverture du dossier" + } + }, + "ScienceSettings": { + "title": "Compétences de recherche scientifique", + "description": "Activez des compétences de recherche scientifique sélectionnées pour vos agents de codage IA : génération d'hypothèses, plan d'expérience, statistiques, visualisation, évaluation critique et recherche bibliographique. codeg gère une copie centrale et relie chaque compétence aux agents que vous choisissez.", + "loading": "Chargement des compétences scientifiques…", + "emptySkills": "Aucune compétence scientifique disponible. Consultez les journaux de l'application.", + "searchPlaceholder": "Rechercher des compétences scientifiques par nom, id ou description", + "categories": { + "ideation": "Idéation", + "design": "Plan d'étude", + "analysis": "Analyse", + "visualization": "Visualisation", + "evaluation": "Évaluation", + "literature": "Littérature" + }, + "states": { + "not_linked": "Non activé", + "linked_to_codeg": "Activé", + "linked_elsewhere": "Bloqué — un autre lien existe", + "blocked_by_real_directory": "Bloqué — une compétence personnalisée occupe ce nom", + "broken": "Lien cassé" + }, + "badges": { + "userModified": "Modifié par l'utilisateur", + "needsKey": "Clé API requise", + "needsSetup": "Configuration possible" + }, + "actions": { + "openCentralDir": "Ouvrir le dossier central", + "refresh": "Actualiser" + }, + "toasts": { + "openFolderFailed": "Échec de l'ouverture du dossier" + } + }, + "OfficeToolsSettings": { + "title": "Outils Office", + "description": "Gérez les compétences OfficeCLI pour créer des fichiers Excel, Word et PowerPoint. Installez OfficeCLI, synchronisez les compétences et activez-les par agent.", + "loadingContent": "Chargement du contenu…", + "emptySkills": "Aucune compétence disponible. Installez OfficeCLI et synchronisez les compétences.", + "emptySelection": "Sélectionnez une compétence pour voir son contenu et gérer l'activation.", + "emptySearch": "Aucune compétence correspondante.", + "searchPlaceholder": "Rechercher par nom, ID ou description", + "enableForAgents": "Activer pour les agents", + "noAgents": "Aucun agent ACP détecté.", + "installFirst": "Installez d'abord OfficeCLI pour activer les compétences.", + "syncFirst": "Synchronisez d'abord les compétences pour charger le contenu.", + "noContent": "Aucun contenu disponible.", + "copyModeWarning": "Copié (non lié). Resynchronisez pour obtenir la dernière version.", + "previewTitle": "Aperçu SKILL.md", + "detection": { + "installed": "Installé", + "notInstalled": "Non installé", + "notRunnable": "Installé mais non exécutable", + "installHint": "Installez OfficeCLI pour activer les compétences de génération de documents Office pour vos agents IA.", + "install": "Installer", + "uninstall": "Désinstaller", + "syncSkills": "Synchroniser les compétences" + }, + "categories": { + "general": "Général", + "presentations": "Présentations", + "documents": "Documents", + "spreadsheets": "Tableurs" + }, + "states": { + "not_linked": "Non activé", + "linked_to_codeg": "Activé", + "linked_elsewhere": "Bloqué — un autre lien existe", + "blocked_by_real_directory": "Bloqué — une compétence personnalisée occupe ce nom", + "broken": "Lien cassé" + }, + "badges": { + "notSynced": "Non synchronisé" + }, + "actions": { + "refresh": "Actualiser" + }, + "toasts": { + "loadFailed": "Échec du chargement des détails de la compétence", + "enabled": "Compétence activée pour cet agent", + "disabled": "Compétence désactivée pour cet agent", + "enableFailed": "Échec de l'activation de la compétence", + "disableFailed": "Échec de la désactivation de la compétence", + "installSuccess": "OfficeCLI installé avec succès", + "installFailed": "Échec de l'installation d'OfficeCLI", + "uninstallSuccess": "OfficeCLI désinstallé", + "uninstallFailed": "Échec de la désinstallation d'OfficeCLI", + "syncSuccess": "{synced} compétences synchronisées", + "syncPartial": "{synced} synchronisées, {errors} échouées", + "syncFailed": "Échec de la synchronisation des compétences" + }, + "autoPreviewLabel": "Ouvrir l'aperçu automatiquement", + "autoPreviewHint": "Lorsqu'un agent crée ou modifie un fichier Word, Excel ou PowerPoint, ouvrir automatiquement son aperçu en direct." + }, + "SkillPacksSettings": { + "title": "Packs de compétences", + "description": "Ensembles de compétences sélectionnés que codeg gère de manière centralisée et relie à vos agents IA : experts en programmation, recherche scientifique et outils de documents bureautiques. Activez-les par agent ci-dessous.", + "tabs": { + "experts": "Experts", + "science": "Science", + "office": "Outils bureautiques", + "custom": "Personnalisées" + }, + "actions": { + "openCentralDir": "Ouvrir le dossier central", + "refresh": "Actualiser" + }, + "toasts": { + "openFolderFailed": "Échec de l'ouverture du dossier" + } + }, + "QuickMessagesSettings": { + "title": "Messages rapides", + "description": "Gérez des extraits de messages réutilisables. Glissez pour réorganiser.", + "loading": "Chargement des messages rapides…", + "emptyList": "Aucun message rapide. Cliquez sur « Nouveau » pour en créer un.", + "emptySelection": "Sélectionnez un message rapide à modifier.", + "searchPlaceholder": "Rechercher par titre ou contenu", + "untitled": "Sans titre", + "actions": { + "new": "Nouveau", + "save": "Enregistrer", + "delete": "Supprimer", + "dragSort": "Glisser pour réorganiser", + "dragSortMessage": "Réorganiser le message rapide : {name}" + }, + "fields": { + "title": "Titre", + "titlePlaceholder": "Donnez un titre court à ce message", + "content": "Contenu", + "contentPlaceholder": "Saisissez ici le contenu du message" + }, + "confirmDelete": { + "title": "Supprimer le message rapide ?", + "message": "Cela supprimera définitivement « {name} ». Êtes-vous sûr ?", + "cancel": "Annuler", + "confirm": "Supprimer" + }, + "toasts": { + "loadFailed": "Échec du chargement des messages rapides", + "createFailed": "Échec de la création du message rapide", + "saveFailed": "Échec de l'enregistrement du message rapide", + "deleteFailed": "Échec de la suppression du message rapide", + "saveOrderFailed": "Échec de l'enregistrement de l'ordre", + "created": "Message rapide créé", + "saved": "Message rapide enregistré", + "deleted": "Message rapide supprimé" + } + }, + "Pet": { + "badge": { + "running": "{count} en cours", + "waiting": "{count} en attente d'approbation", + "error": "{count} en erreur" + }, + "panel": { + "title": "Sessions actives", + "empty": "Aucune session active", + "emptyHint": "Les agents en cours et ceux qui vous attendent apparaissent ici.", + "statusRunning": "En cours", + "statusWaiting": "En attente", + "statusError": "Erreur", + "subAgentOf": "Sous-agent de" + }, + "menu": { + "scale": "Échelle", + "openManager": "Gérer les mascottes", + "close": "Fermer" + }, + "loadError": "Échec du chargement de la mascotte", + "missingPetIdParam": "Aucune mascotte sélectionnée", + "summonButton": "Mascotte", + "manager": { + "title": "Mascottes", + "description": "Compagnons flottants de bureau avec des sprites compatibles Codex.", + "addPet": "Ajouter une mascotte", + "importFromCodex": "Importer depuis Codex", + "noPets": "Aucune mascotte. Ajoutez-en ou importez depuis Codex.", + "setActive": "Activer", + "active": "Active", + "edit": "Modifier", + "delete": "Supprimer", + "deleteConfirm": "Supprimer la mascotte « {name} » ? Elle sera retirée du disque.", + "summon": "Invoquer la fenêtre de la mascotte", + "openCodexHelp": "Les mascottes Codex doivent être dans ~/.codex/pets/. Aucune trouvée.", + "specRequirement": "Le sprite doit faire 1536px de large avec une hauteur multiple de 208px (par ex. 1872 ou 2288), en PNG/WebP avec transparence.", + "form": { + "id": "ID mascotte", + "idHelp": "Lettres minuscules, chiffres, '-' et '_'. Max 64 caractères.", + "displayName": "Nom affiché", + "description": "Description (facultative)", + "spritesheet": "Sprite", + "chooseFile": "Choisir un fichier", + "replaceFile": "Remplacer le sprite", + "saveCreate": "Ajouter la mascotte", + "saveUpdate": "Enregistrer", + "cancel": "Annuler" + }, + "errors": { + "missingId": "ID requis", + "missingName": "Nom requis", + "missingSpritesheet": "Sprite requis", + "addFailed": "Ajout impossible", + "updateFailed": "Mise à jour impossible", + "deleteFailed": "Suppression impossible", + "loadFailed": "Chargement impossible", + "setActiveFailed": "Activation impossible", + "summonFailed": "Ouverture de la fenêtre impossible" + } + }, + "import": { + "title": "Importer depuis Codex", + "subtitle": "Mascottes disponibles sous ~/.codex/pets/.", + "selectAll": "Tout sélectionner", + "alreadyImported": "Déjà importée", + "renameOnConflict": "Renommer en -imported en cas de conflit", + "import": "Importer la sélection", + "noneFound": "Aucune mascotte Codex importable.", + "imported": "Import réussi", + "failed": "Import échoué", + "close": "Fermer" + }, + "marketplace": { + "openMarketplace": "Marketplace de mascottes", + "title": "Marketplace de mascottes", + "search": "Rechercher des mascottes", + "kindFilter": { + "all": "Toutes", + "object": "Objet", + "animal": "Animal", + "person": "Personne", + "creature": "Créature" + }, + "sortFilter": { + "latest": "Récents", + "popular": "Populaires", + "views": "Vues" + }, + "refresh": "Actualiser", + "install": "Installer", + "installing": "Installation", + "reinstall": "Réinstaller", + "reinstallConfirm": "Remplacer la mascotte locale « {name} » ? Les données existantes seront écrasées.", + "cancel": "Annuler", + "stats": { + "views": "Vues", + "downloads": "Téléchargements", + "likes": "J’aime" + }, + "actions": { + "idle": "Repos", + "running_right": "Course dr.", + "running_left": "Course g.", + "waving": "Salut", + "jumping": "Saut", + "failed": "Échec", + "waiting": "Attente", + "running": "Course", + "review": "Revue" + }, + "page": "Page {page} sur {total}", + "prev": "Précédent", + "next": "Suivant", + "empty": "Aucune mascotte ne correspond.", + "successInstalled": "« {name} » installée", + "errors": { + "loadFailed": "Impossible de charger le marketplace", + "installFailed": "Échec de l’installation", + "alreadyInstalled": "La mascotte existe déjà localement" + } + } + }, + "RemoteWorkspace": { + "openRemoteWorkspace": "Ouvrir l’espace de travail distant", + "manage": "Gérer l’espace de travail distant", + "manageTitle": "Connexions à l’espace de travail distant", + "empty": "Aucune connexion distante", + "searchPlaceholder": "Rechercher un espace de travail distant", + "orderFailed": "Échec de l’enregistrement de l’ordre des espaces de travail distants", + "dragSort": "Glisser pour trier", + "dragSortConnection": "Glisser pour trier {name}", + "newConnection": "Nouvelle connexion", + "loading": "Chargement", + "loadingConnection": "Chargement de la connexion distante", + "name": "Nom", + "baseUrl": "URL du service", + "token": "Jeton d’accès", + "save": "Enregistrer", + "delete": "Supprimer", + "confirmDelete": { + "title": "Supprimer la connexion distante ?", + "message": "Cela retirera « {name} » de cet appareil. Cette action est irréversible.", + "cancel": "Annuler", + "confirm": "Supprimer" + }, + "saved": "Connexion distante enregistrée.", + "deleted": "Connexion distante supprimée.", + "loadFailed": "Échec du chargement des connexions distantes", + "saveFailed": "Échec de l’enregistrement de la connexion distante", + "deleteFailed": "Échec de la suppression de la connexion distante", + "openFailed": "Échec de l’ouverture de l’espace de travail distant", + "connectionLoadFailed": "Échec du chargement de la connexion distante : {message}", + "connectionExpired": "La connexion distante « {name} » a expiré. Mettez son jeton à jour, puis rechargez cette fenêtre." + }, + "ServerFileBrowser": { + "title": "Sélectionner un fichier serveur", + "pathPlaceholder": "Saisir le chemin du dossier...", + "goHome": "Aller au dossier personnel", + "navigateUp": "Aller au dossier parent", + "select": "Sélectionner", + "cancel": "Annuler", + "loading": "Chargement...", + "emptyDirectory": "Ce dossier est vide", + "errorLoadingDir": "Échec du chargement du dossier", + "selectedCount": "{count} sélectionné(s)" + }, + "BackupSettings": { + "title": "Sauvegarde et restauration", + "description": "Exportez une sauvegarde portable de vos données codeg, ou restaurez à partir d'une sauvegarde.", + "tabs": { + "backup": "Sauvegarde", + "restore": "Restauration" + }, + "export": { + "includeExternal": "Inclure le contenu des conversations", + "includeExternalHint": "Archive aussi les transcriptions des CLI (Claude, Codex, Gemini, …). Augmente la taille.", + "passphrase": "Phrase secrète (facultatif)", + "passphrasePlaceholder": "Laissez vide pour une archive non chiffrée", + "passphraseConfirm": "Confirmer la phrase secrète", + "passphraseMismatch": "Les phrases secrètes ne correspondent pas.", + "noPassphraseWarning": "Cette sauvegarde contiendra des secrets (clés d'API, jetons) en clair. Conservez-la en lieu sûr.", + "passphraseLossWarning": "Chiffrée avec cette phrase secrète. Si vous la perdez, la sauvegarde ne pourra pas être récupérée.", + "button": "Exporter la sauvegarde", + "inProgress": "Création de la sauvegarde…", + "success": "Sauvegarde créée.", + "started": "Téléchargement de la sauvegarde lancé." + }, + "restore": { + "selectFile": "Sélectionner le fichier de sauvegarde", + "passphrasePrompt": "Cette sauvegarde est chiffrée. Saisissez sa phrase secrète.", + "unlock": "Déverrouiller", + "preview": { + "title": "Détails de la sauvegarde", + "encrypted": "Chiffrée", + "compatible": "Compatible", + "incompatible": "Incompatible", + "createdAt": "Créée : {value}", + "appVersion": "Version de l'app : {value}", + "incompatibleHint": "Cette sauvegarde a été créée par une version plus récente de codeg et ne peut pas être restaurée." + }, + "replaceWarning": "La restauration remplace toutes les données codeg actuelles (base de données et téléversements). Vos données actuelles sont d'abord sauvegardées en instantané pour pouvoir être récupérées.", + "keyringNote": "Les jetons GitHub/chat du bureau sont dans le trousseau du système et ne sont pas inclus ; ressaisissez-les après la restauration.", + "button": "Restaurer", + "staging": "Préparation de la restauration…", + "staged": "Restauration préparée. Redémarrage…", + "restarting": "Restauration préparée. Redémarrage du serveur…", + "restartTimeout": "Le serveur n'est pas revenu à temps. Rechargez la page une fois qu'il est actif.", + "externalSideLocation": "Les transcriptions de conversations ont été restaurées dans {path}", + "confirmTitle": "Remplacer toutes les données ?", + "confirmBody": "Cela remplacera votre base de données et vos téléversements codeg actuels par la sauvegarde, puis redémarrera. Vos données actuelles sont d'abord sauvegardées en instantané.", + "cancel": "Annuler", + "confirmAction": "Remplacer et redémarrer", + "external": { + "title": "Contenu des conversations", + "hint": "Cette sauvegarde inclut des transcriptions des CLI. Choisissez où les restaurer.", + "modeSkip": "Ne pas restaurer", + "modeSide": "Restaurer dans un dossier annexe sûr", + "modeOriginal": "Restaurer aux emplacements d'origine des CLI", + "forceOverwrite": "Écraser les fichiers existants", + "forceOverwriteHint": "Remplace les fichiers déjà présents dans les dossiers des CLI.", + "scanning": "Vérification des conflits…", + "noConflicts": "Aucun fichier existant ne sera écrasé.", + "conflictCount": "{count} fichier(s) existant(s) seraient concerné(s).", + "conflictSkipNote": "Les fichiers existants sont conservés (ignorés) sauf si vous activez l'écrasement." + }, + "restartFailed": "Restauration préparée, mais le serveur n'a pas pu redémarrer. Redémarrez-le manuellement pour l'appliquer." + }, + "remoteUnsupported": "La sauvegarde et la restauration agissent sur les données de la machine qui exécute codeg. Vous êtes connecté à un espace de travail distant : gérez ses sauvegardes directement depuis ce serveur." + }, + "backup": { + "restore": { + "error": { + "badPassphrase": "Phrase secrète incorrecte ou sauvegarde corrompue.", + "corrupted": "L'archive de sauvegarde est corrompue.", + "unknownFormat": "Ce fichier n'est pas une sauvegarde codeg reconnue.", + "newerVersion": "Cette sauvegarde a été créée par codeg {backupVersion}, plus récent que cette version ({appVersion}).", + "alreadyPending": "Une restauration est déjà préparée. Redémarrez pour l'appliquer avant d'en préparer une autre." + } + }, + "error": { + "diskSpace": "Espace disque insuffisant pour terminer l'opération.", + "cancelled": "L'opération a été annulée." + } + }, + "WebConnection": { + "disconnectedTitle": "Connexion perdue", + "reconnectingDescription": "Tentative de reconnexion au serveur. Cela se rétablit généralement tout seul en quelques secondes.", + "reconnectNow": "Se reconnecter maintenant", + "sessionExpiredTitle": "Session expirée", + "sessionExpiredDescription": "Votre session n'est plus valide. Veuillez vous reconnecter pour continuer.", + "goToLogin": "Aller à la connexion" + }, + "LiveFeedback": { + "placeholder": "Envoyez une note à {agent} pendant qu'il travaille…", + "agentFallback": "l'agent", + "ariaLabel": "Note de retour en direct", + "dialogTitle": "Retour en direct", + "dialogDescription": "Envoyez une note à l'agent pendant qu'il travaille. Il la lira lors de sa prochaine vérification, sans interrompre l'étape en cours.", + "dialogDescriptionInstant": "Envoyez une note à l'agent pendant qu'il travaille. Elle est insérée immédiatement dans le tour en cours — l'agent la voit aussitôt.", + "channelDowngraded": "L'insertion instantanée n'est pas disponible dans cette session — votre note a été enregistrée et sera récupérée au prochain contrôle de l'agent.", + "send": "Envoyer", + "cancel": "Annuler", + "pending": "en attente", + "delivered": "reçue", + "turnEndedUnread": "L'agent a terminé avant de lire votre retour.", + "sendAsMessage": "Envoyer comme message", + "dismiss": "Ignorer", + "turnEndedResent": "Le tour est terminé : envoyé comme nouveau message.", + "turnEnded": "Le tour est déjà terminé.", + "submitFailed": "Impossible d'envoyer votre note" + }, + "AgentToolsSettings": { + "title": "Outils dans la conversation", + "description": "Outils supplémentaires que codeg fournit à un agent au sein d'une conversation. Ils sont injectés au démarrage de l'agent : une modification s'applique donc aux agents démarrés ensuite.", + "feedbackLabel": "Retour en direct", + "feedbackHint": "Envoyez des notes et corrections à un agent pendant qu'il travaille. Si l'agent prend en charge l'insertion instantanée, votre note est insérée immédiatement dans le tour en cours ; sinon, l'agent reçoit un outil pour consulter vos retours — ces agents ne le consultent généralement que si vous le mentionnez dans votre prompt, par exemple ajoutez « vérifie régulièrement mon feedback en direct » à votre message.", + "questionLabel": "Poser une question à l'utilisateur", + "questionHint": "Permet aux agents de s'interrompre et de vous poser une question à choix multiples affichée au-dessus de la zone de saisie de la conversation. L'agent attend votre réponse (ou que vous ignoriez).", + "sessionInfoLabel": "Obtenir les infos de session", + "sessionInfoHint": "Permet aux agents de consulter une session que vous mentionnez dans votre message (un badge de session) pour lire son titre, son agent, son statut, son espace de travail, sa consommation de jetons et ses messages récents.", + "automationsLabel": "Créer des automatisations", + "automationsHint": "Enregistre la conversation comme une automatisation qui s'exécute selon un planning. Désactivé par défaut : elle démarre ensuite des agents d'elle-même.", + "workTasksLabel": "Créer des tâches à faire", + "workTasksHint": "Ajoute une carte au tableau des tâches depuis la conversation. Désactivé par défaut : écrit l'état de l'application.", + "save": "Enregistrer", + "saving": "Enregistrement…", + "saved": "Paramètres des outils enregistrés", + "saveFailed": "Échec de l'enregistrement des paramètres des outils", + "loadFailed": "Échec du chargement : {detail}" + }, + "NotificationSoundSettings": { + "title": "Sons de notification", + "description": "Joue un son bref lorsqu’un événement d’agent se produit. Ce sont les mêmes événements que ceux envoyés aux canaux de discussion ; ce réglage ne s’applique qu’à cet appareil.", + "enableHint": "Désactivé par défaut. Les sons ne sont joués que dans la fenêtre de l’espace de travail de ce navigateur ou de cette application.", + "volume": "Volume", + "preview": "Écouter", + "previewEvent": "Écouter le son de {event}", + "onlyWhenUnfocused": "Uniquement lorsque la fenêtre n’est pas au premier plan", + "onlyWhenUnfocusedHint": "Reste silencieux tant que Codeg est affiché.", + "eventsTitle": "Événements", + "eventsHint": "Choisissez un son par événement, ou « Silencieux » pour l’ignorer. Si le même événement se répète en quelques secondes, il ne sonne qu’une fois.", + "toneNone": "Silencieux", + "toneChime": "Carillon", + "toneDing": "Clochette", + "toneBlip": "Bip", + "tonePop": "Pop", + "toneAlert": "Alerte", + "toneDescend": "Descendant" + }, + "LogsSettings": { + "loading": "Chargement…", + "sectionTitle": "Journaux d'exécution", + "sectionDescription": "Consultez et configurez les journaux de diagnostic de l'application. Les journaux sont écrits dans des fichiers locaux et conservés en mémoire pour l'affichage en direct.", + "captureTitle": "Niveau de journalisation", + "captureDescription": "Contrôle le niveau de détail capturé. Les niveaux plus élevés (Debug, Trace) enregistrent davantage mais produisent des journaux plus volumineux. « Désactivé » désactive la journalisation.", + "captureLabel": "Niveau de capture", + "levels": { + "off": "Désactivé", + "error": "Erreur", + "warn": "Avertissement", + "info": "Info", + "debug": "Débogage", + "trace": "Trace" + }, + "viewerTitle": "Journaux récents", + "viewerDescription": "Affichage en direct des journaux récents. Filtrez par niveau ou recherchez du texte.", + "searchPlaceholder": "Rechercher un message ou une cible…", + "viewLevels": { + "all": "Tous les niveaux", + "error": "Erreur et plus", + "warn": "Avertissement et plus", + "info": "Info et plus", + "debug": "Débogage et plus", + "trace": "Trace et plus" + }, + "pause": "Pause", + "resume": "Direct", + "refresh": "Actualiser", + "clear": "Effacer", + "openFolder": "Ouvrir le dossier", + "shownCount": "{shown} / {total} affichés", + "empty": "Aucun journal à afficher.", + "levelSaveFailed": "Échec de l'enregistrement du niveau de journalisation", + "openFolderFailed": "Échec de l'ouverture du dossier des journaux", + "downloadFailed": "Échec du téléchargement du fichier journal", + "filesTitle": "Fichiers journaux", + "filesDescription": "Téléchargez les fichiers journaux complets depuis le disque pour l'historique au-delà du tampon en direct.", + "filesEmpty": "Aucun fichier journal pour l'instant.", + "download": "Télécharger", + "downloadTruncated": "Le fichier est volumineux ; les {size} les plus récents ont été téléchargés. Le fichier complet se trouve dans le répertoire des journaux.", + "captureEnvLocked": "Le niveau de journalisation est contrôlé par la variable d'environnement RUST_LOG / CODEG_LOG ; modifiez-la là pour qu'elle prenne effet.", + "targetsTitle": "Remplacements par module", + "targetsDescription": "Définissez un niveau différent pour des modules spécifiques (p. ex. codeg_lib::acp) sans changer le niveau global.", + "targetsAdd": "Ajouter", + "targetsRemove": "Supprimer le remplacement", + "toggleDetails": "Afficher les détails" + }, + "Automations": { + "title": "Automatisations", + "new": "Nouvelle automatisation", + "empty": "Aucune automatisation pour l'instant", + "emptyHint": "Créez-en une pour exécuter une tâche d'agent planifiée ou à la demande.", + "name": "Nom", + "namePlaceholder": "ex. Revue de PR nocturne", + "prompt": "Instruction", + "promptPlaceholder": "Que doit faire l'agent ?", + "agent": "Agent", + "folder": "Dossier de l'espace de travail", + "folderPlaceholder": "Sélectionner un dossier", + "isolation": "Isolation", + "isolationWorktree": "Nouveau worktree par exécution", + "isolationShared": "Exécuter dans le dossier", + "isolationSharedCaveat": "Les exécutions utilisent directement l'arbre de travail de ce dossier et peuvent entrer en conflit avec vos modifications non validées. Activez l'option worktree pour isoler chaque exécution.", + "trigger": "Déclencheur", + "triggerSchedule": "Planifié", + "triggerManual": "Manuel uniquement", + "cron": "Planification (cron)", + "cronPlaceholder": "0 9 * * 1-5", + "timezone": "Fuseau horaire", + "nextRun": "Prochaine exécution", + "branch": "Branche", + "branchOptional": "Branche (facultatif)", + "enabled": "Activé", + "save": "Enregistrer", + "cancel": "Annuler", + "edit": "Modifier", + "delete": "Supprimer", + "runNow": "Exécuter maintenant", + "cancelRun": "Annuler l'exécution", + "runHistory": "Historique d'exécution", + "noRuns": "Aucune exécution pour l'instant", + "allFolders": "Tous les dossiers", + "filterAll": "Tous", + "noMatches": "Aucune automatisation correspondante", + "viewConversation": "Voir la conversation", + "lastRun": "Dernière exécution", + "never": "Jamais", + "running": "En cours", + "deleteTitle": "Supprimer l'automatisation ?", + "deleteDescription": "Cela supprime l'automatisation et sa planification. L'historique est conservé.", + "statusRunning": "En cours", + "statusSucceeded": "Réussie", + "statusFailed": "Échouée", + "statusCancelled": "Annulée", + "statusSkipped": "Ignorée", + "errorName": "Le nom est requis", + "errorPrompt": "L'instruction est requise", + "errorCron": "Les automatisations planifiées nécessitent une expression cron", + "errorFolder": "Sélectionnez un dossier d'espace de travail", + "presetHourly": "Toutes les heures", + "presetDaily": "Tous les jours 9 h", + "presetWeekdays": "En semaine 9 h", + "presetCustom": "Personnalisé", + "probing": "Chargement des options…", + "retry": "Réessayer", + "configNone": "Cet agent n'a aucune option configurable", + "inherit": "Par défaut de l'agent", + "mode": "Mode", + "config": "Configuration", + "branchPlaceholder": "(branche par défaut)", + "selectHint": "Sélectionnez une automatisation pour voir les détails", + "refresh": "Actualiser", + "onboardTitle": "Automatisez les tâches récurrentes de l'agent", + "onboardHint": "Planifiez un agent pour relire le code, mettre à jour les dépendances ou trier les problèmes, de façon périodique ou à la demande.", + "headerSubtitle": "Tâches d'agent planifiées et à la demande", + "startFromTemplate": "Partir d'un modèle", + "blankTitle": "Automatisation vierge", + "blankDesc": "Configurez une tâche d'agent à partir de zéro.", + "backToTemplates": "Modèles", + "sectionSchedule": "Planification et cible", + "sectionTarget": "Cible", + "sectionAction": "Action", + "actionLaunchSession": "Lancer une session", + "actionEnqueueTask": "Mettre une tâche en file", + "actionEnqueueTaskHint": "Chaque déclenchement ajoute une tâche à faire, nommée d'après cette automatisation, aux tâches à faire du dossier ; le moteur de tâches l'exécute selon les réglages du tableau.", + "sectionPrompt": "Instruction", + "nextIn": "Prochaine dans {rel}", + "manual": "Manuel", + "schedEveryMinutes": "Toutes les {n} minutes", + "schedHourly": "Toutes les heures", + "schedDaily": "Tous les jours à {time}", + "schedWeekdays": "En semaine à {time}", + "schedWeekly": "Chaque {day} à {time}", + "schedMonthly": "Le {day} de chaque mois à {time}", + "dow0": "dimanche", + "dow1": "lundi", + "dow2": "mardi", + "dow3": "mercredi", + "dow4": "jeudi", + "dow5": "vendredi", + "dow6": "samedi", + "tplCodeReviewTitle": "Revue de code", + "tplCodeReviewDesc": "Examine les modifications récentes à la recherche de bugs, de régressions et de problèmes de qualité.", + "tplDependencyUpdatesTitle": "Mise à jour des dépendances", + "tplDependencyUpdatesDesc": "Repère les dépendances obsolètes et propose des mises à niveau sûres.", + "tplTestCoverageTitle": "Couverture de tests", + "tplTestCoverageDesc": "Repère les chemins de code non testés et ajoute les tests manquants.", + "tplTodoSweepTitle": "Revue des TODO", + "tplTodoSweepDesc": "Rassemble les commentaires TODO et FIXME et les trie par priorité.", + "tplCiTriageTitle": "Tri CI", + "tplCiTriageDesc": "Enquête sur les vérifications récemment en échec et propose des correctifs.", + "tplReleaseNotesTitle": "Notes de version", + "tplReleaseNotesDesc": "Résume les changements depuis la dernière version dans un journal des modifications.", + "tplSecurityAuditTitle": "Audit de sécurité", + "tplSecurityAuditDesc": "Recherche les vulnérabilités et les schémas à risque, puis signale les constats.", + "enable": "Activer", + "disable": "Désactiver", + "moreActions": "Plus d'actions", + "statusDisabled": "Désactivée", + "cronBuilderTitle": "Générateur de planification", + "cronFreqLabel": "Fréquence", + "cronFreqMinutes": "Toutes les N minutes", + "cronFreqHourly": "Toutes les heures", + "cronFreqDaily": "Quotidien", + "cronFreqWeekdays": "Jours ouvrés", + "cronFreqWeekly": "Hebdomadaire", + "cronFreqMonthly": "Mensuel", + "cronFreqCustom": "Personnalisé", + "cronEveryLabel": "Intervalle (minutes)", + "cronTimeLabel": "Heure", + "cronHourLabel": "Heure", + "cronMinuteLabel": "Minute", + "cronDowLabel": "Jour de la semaine", + "cronDomLabel": "Jour du mois", + "cronApply": "Appliquer", + "cronPreviewLabel": "Aperçu", + "cronOpenBuilder": "Ouvrir le générateur de planification", + "branchDefault": "Branche par défaut", + "branchUseCustom": "Utiliser « {query} »", + "branchLocal": "Locale", + "branchRemote": "Distante", + "branchSearchPlaceholder": "Rechercher des branches…", + "branchNone": "Aucune branche" + }, + "Tasks": { + "title": "Tâches à faire", + "new": "Nouvelle tâche", + "empty": "Aucune tâche pour l’instant", + "emptyHint": "Ajoutez une tâche puis lancez-la : l’agent travaille dans un worktree isolé, vous relisez et fusionnez le résultat.", + "emptyColTodo": "Aucune tâche à faire pour l’instant", + "emptyColInProgress": "Rien en cours", + "emptyColAttention": "Rien à traiter", + "emptyColDone": "Rien de terminé pour l’instant", + "allFolders": "Tous les dossiers", + "showCanceled": "Afficher les annulées", + "showArchived": "Afficher les archivées", + "filter": "Filtrer", + "viewSwitchToBoard": "Passer à la vue tableau", + "viewSwitchToList": "Passer à la vue liste", + "statusFilter": "Statut", + "statusFilterAll": "Tous les statuts", + "listEmpty": "Aucune tâche ne correspond aux filtres actuels", + "listColStatus": "Statut", + "listColTask": "Tâche", + "listColLocation": "Emplacement", + "listColChanges": "Modifications", + "listColUpdated": "Mis à jour", + "colTodo": "À faire", + "colInProgress": "En cours", + "colAttention": "À traiter", + "colDone": "Terminées", + "statusTodo": "À faire", + "statusQueued": "En file", + "statusPreparing": "Préparation", + "statusRunning": "En cours", + "statusAwaitingInput": "En attente de saisie", + "statusReview": "À valider", + "statusMerging": "Fusion en cours", + "statusDone": "Terminée", + "statusFailed": "Échouée", + "statusCanceled": "Annulée", + "statusInterrupted": "Interrompue", + "badgeCleanupFailed": "Nettoyage échoué", + "badgeWorktreeKept": "Worktree conservé", + "badgeWorktreeRemoved": "Worktree supprimé", + "filesChanged": "{count} fichiers", + "actionStart": "Démarrer", + "actionSchedule": "Planifier", + "actionCancel": "Annuler", + "actionRetry": "Réessayer", + "actionRequeue": "Remettre en file", + "actionViewSession": "Voir la conversation", + "actionEdit": "Modifier", + "actionDelete": "Supprimer", + "actionRetryCleanup": "Réessayer le nettoyage", + "actionMerge": "Fusionner", + "actionUnqueueMerge": "Quitter la file de fusion", + "actionEditQueuedMerge": "Modifier la fusion en attente", + "badgeMergeQueued": "En attente de fusion", + "badgeMergeQueuedRank": "En attente de fusion · n° {rank}", + "badgeMergeQueuedHint": "En attente de la fin de la fusion en cours du projet ; celle-ci démarrera toute seule.", + "actionComplete": "Terminer", + "actionAbandon": "Abandonner", + "cancelTitle": "Annuler la tâche ?", + "cancelDescription": "La tâche passe à Annulée. Son worktree est conservé et vous pourrez la remettre en file plus tard.", + "cancelReasonLabel": "Raison (facultatif)", + "cancelReasonPlaceholder": "Ex. : mauvaise approche, je vais réécrire la description", + "cancelKeep": "Finalement non", + "cancelSubmit": "Annuler la tâche", + "restartTitleRetry": "Réessayer la tâche", + "restartTitleRequeue": "Remettre la tâche en file", + "restartDescription": "Vous pouvez ajouter une note (facultatif) : elle arrive dans le prompt de la prochaine exécution.", + "scheduleTitle": "Planifier la tâche", + "scheduleDescription": "La tâche reste dans À faire et démarre d'elle-même à l'heure choisie. La limite de concurrence du dossier s'applique toujours.", + "scheduleDateLabel": "Date", + "schedulePickDate": "Choisir une date", + "scheduleTimeLabel": "Heure", + "schedulePreview": "S'exécute le {time}", + "schedulePastHint": "Cette heure est déjà passée : la tâche démarrera dès l'enregistrement.", + "scheduleInAnHour": "Dans 1 heure", + "scheduleInThreeHours": "Dans 3 heures", + "scheduleTomorrow": "Demain 9:00", + "scheduleClear": "Annuler la planification", + "scheduleBadge": "Démarrage prévu le {time}", + "toastScheduled": "Planifiée pour le {time}", + "toastScheduleCleared": "Planification annulée", + "actionFollowUp": "Poursuivre", + "actionAddNote": "Ajouter une note", + "followUpSubmit": "Envoyer", + "followUpIntentRevise": "Corriger", + "followUpIntentContinue": "Continuer", + "followUpIntentQuestion": "Demander", + "followUpIntentVerify": "Vérifier", + "followUpPlaceholderRevise": "Que doit changer l'agent ? Il poursuit dans la même session.", + "followUpPlaceholderContinue": "Et ensuite ? Le travail déjà fait reste en place.", + "followUpPlaceholderQuestion": "Que voulez-vous savoir ? L'agent répond sans toucher aux fichiers.", + "followUpPlaceholderVerify": "Facultatif : quelque chose à examiner de près ?", + "followUpPlaceholderRetry": "Facultatif : que faire différemment ? Ex. : lancer pnpm install d'abord", + "followUpPlaceholderRequeue": "Facultatif : pourquoi l'avoir annulée, et qu'est-ce qui doit changer ?", + "actionArchive": "Archiver", + "actionUnarchive": "Désarchiver", + "archiveAllDone": "Tout archiver", + "dropToStart": "Relâchez pour lancer", + "errorView": "Voir", + "notifyReview": "Prêt pour révision : {title}", + "notifyFailed": "La tâche a échoué : {title}", + "createFromMessage": "Créer une tâche depuis le message", + "detailTokens": "Total de tokens", + "editorTitleNew": "Nouvelle tâche", + "editorTitleEdit": "Modifier la tâche", + "templates": "Modèles", + "templatesEmpty": "Aucun modèle pour l'instant.", + "templateSaveCurrent": "Enregistrer comme modèle", + "templateDelete": "Supprimer le modèle", + "transcriptTitle": "Conversation de la tâche", + "transcriptDescription": "Vue en direct, en lecture seule, de la session de l'agent de la tâche.", + "phaseWork": "Exécution", + "phaseRetry": "Nouvel essai", + "phaseReturn": "Relance", + "phaseMerge": "Fusion", + "titleLabel": "Titre", + "titlePlaceholder": "Que faut-il faire ?", + "promptLabel": "Description de la tâche", + "promptPlaceholder": "Décrivez la tâche pour l’agent — @ pour référencer des fichiers, / pour les commandes", + "folderPlaceholder": "Choisir un dossier", + "agentInheritedHint": "Hérité des réglages des tâches — modifiez-le pour personnaliser cette tâche", + "agentOverrideReset": "Revenir à l'héritage", + "sectionTarget": "Cible", + "errorTitle": "Le titre est requis", + "errorPrompt": "La description est requise", + "errorFolder": "Choisissez un dossier", + "save": "Enregistrer", + "cancel": "Annuler", + "mergeTitle": "Fusionner la tâche", + "mergeQueuedTitle": "Fusion en attente", + "mergeQueueHint": "Une autre tâche de ce projet est en cours de fusion. Celle-ci rejoint la file et démarrera d'elle-même dès que l'autre sera terminée.", + "mergeQueueUpdateHint": "Cette tâche attend déjà de fusionner. L'envoi la met à jour et conserve sa place dans la file.", + "mergeDescription": "Fusionner {branch} dans {base}. Les changements non commités du worktree sont d’abord commités.", + "mergeMessage": "Message de commit", + "mergeMessagePlaceholder": "ex. feat: add login validation", + "mergeAutoMessage": "Laisser l'agent rédiger le message de commit", + "strategySquash": "Regrouper en un seul commit", + "strategySquashHint": "Toutes les modifications de la tâche arrivent dans la branche principale comme une seule entrée d'historique — un historique plus net.", + "strategyMerge": "Conserver tout l'historique", + "strategyMergeHint": "Chaque commit réalisé pendant la tâche est conservé, plus une entrée de fusion — chaque étape reste traçable.", + "mergeDeleteWorktree": "Supprimer le worktree après la fusion", + "mergeSubmit": "Fusionner", + "mergeSubmitQueue": "Ajouter à la file", + "mergeQueuedToast": "Ajoutée à la file de fusion — elle démarrera dès la fin de la fusion en cours.", + "completeTitle": "Terminer la tâche", + "completeDescription": "Cette tâche n'a modifié aucun fichier : il n'y a rien à fusionner, elle est marquée comme terminée directement.", + "completeDescriptionNoWorktree": "Le worktree de cette tâche a été supprimé : plus rien ne peut être fusionné, elle est marquée comme terminée directement. Une branche de travail contenant encore des commits non fusionnés est conservée.", + "completeDeleteWorktree": "Supprimer le worktree après avoir terminé", + "completeSubmit": "Terminer", + "settingsTitle": "Réglages des tâches", + "settingsDescription": "Valeurs par défaut des tâches de {folder}.", + "settingsScope": "Portée", + "settingsScopeGlobal": "Tous les dossiers (valeurs globales)", + "settingsScopeGlobalHint": "Les dossiers sans réglages propres utilisent ces valeurs globales.", + "settingsSource": "Source de configuration", + "settingsSourceGlobal": "Valeurs globales", + "settingsSourceCustom": "Personnalisée", + "settingsSourceGlobalFollow": "Suit les réglages globaux des tâches — les changements globaux s'appliquent ici automatiquement.", + "settingsSourceCustomHint": "Enregistre des réglages propres à ce dossier, qui ne suit plus les valeurs globales.", + "settingsAgent": "Agent par défaut", + "settingsMaxConcurrent": "Tâches simultanées max.", + "settingsMaxConcurrentHint": "0 = illimité", + "settingsAutoProcess": "Traiter automatiquement", + "settingsAutoProcessHint": "Les tâches à faire démarrent seules, dans la limite de concurrence.", + "settingsMergeStrategy": "Stratégie de fusion par défaut", + "settingsMergeStrategyHint": "Comment les modifications de la tâche sont consignées dans l'historique de la branche lors de la fusion.", + "settingsAutoMerge": "Fusionner automatiquement", + "settingsAutoMergeHint": "Une tâche qui arrive en revue avec des changements à intégrer est fusionnée comme si vous cliquiez sur Fusionner : l'agent rédige le message de commit et le worktree suit le réglage par défaut ci-dessous. Si la pré-vérification échoue ou qu'une fusion a échoué, la tâche vous attend.", + "settingsDeleteWorktree": "Supprimer le worktree après la fusion", + "settingsDeleteWorktreeHint": "Coche l’option par défaut dans la boîte de dialogue de fusion ; elle reste modifiable.", + "settingsWorktreeRoot": "Emplacement du worktree", + "settingsWorktreeRootHint": "Répertoire dans lequel les worktrees des nouvelles tâches sont créés, un par tâche. Laissez vide pour les créer à côté du dossier du projet ; « ~ » désigne votre dossier personnel et un chemin relatif est résolu depuis le dossier du projet.", + "settingsWorktreeRootPlaceholder": "~/codeg-worktrees", + "settingsWorktreeRootBrowse": "Choisir le répertoire des worktrees", + "settingsPreflight": "Commande de pré-vérification", + "settingsPreflightHint": "S'exécute dans le worktree quand une tâche passe en revue.", + "settingsPreflightCustomPlaceholder": "pnpm test", + "settingsInitCommand": "Commande d'initialisation du worktree", + "settingsInitCommandHint": "Exécutée dans un worktree fraîchement créé avant le démarrage de l'agent.", + "settingsInitCommandPlaceholder": "pnpm install", + "settingsTabGeneral": "Général", + "settingsTabMerge": "Fusion", + "settingsTabWorktree": "Worktree", + "settingsTabPrompts": "Instructions", + "settingsPromptsIntro": "Chaque étape envoie déjà son propre prompt intégré : la tâche, les règles du worktree et, pour la fusion, les étapes git exactes. Ce que vous ajoutez ici est apposé à la fin comme instructions supplémentaires : cela affine ces textes intégrés, sans jamais les remplacer.", + "settingsPromptStageAll": "Toutes les phases", + "settingsPromptPlaceholderAll": "ex. Respecte les conventions d’AGENTS.md ; limite le résumé final à deux phrases", + "settingsPromptPlaceholderWork": "ex. Lis d’abord les tests concernés ; fais des commits petits et fréquents", + "settingsPromptPlaceholderRetry": "ex. Vérifie ce qui est déjà commité avant de continuer ; ne refais pas le travail terminé", + "settingsPromptPlaceholderReturn": "Ex. : Traitez chaque point soulevé ; ne refactorisez rien d'autre", + "settingsPromptPlaceholderMerge": "ex. Rédige le message du commit d’intégration en français ; signale les conflits résolus à la main", + "settingsPromptHintAll": "Ajouté à chaque prompt reçu par l'agent, fusion comprise.", + "settingsPromptHintWork": "Ajouté lors de la première exécution d'une tâche.", + "settingsPromptHintRetry": "Ajouté lorsqu'une tâche interrompue ou en échec est reprise.", + "settingsPromptHintReturn": "Ajouté quand vous relancez une tâche en revue (correction, ajout, vérification).", + "settingsPromptHintMerge": "Ajouté lorsque l'agent intègre la tâche dans la branche de base.", + "preflightPassed": "{name} réussie", + "preflightFailed": "{name} échouée", + "preflightRunning": "{name} en cours…", + "detailDescription": "Détail de la tâche", + "detailSummary": "Résultat", + "detailFiles": "Fichiers modifiés", + "detailDiffAll": "Voir tout le diff", + "detailDiffAllTitle": "Diff complet", + "detailNoChanges": "Aucun changement par rapport à la base", + "detailTimeline": "Progression", + "detailTimelineEmpty": "Aucune activité pour l’instant", + "showMore": "Afficher plus", + "showLess": "Afficher moins", + "detailInfo": "Détails", + "detailBranch": "Branche", + "detailMergeCommit": "Commit de fusion", + "detailChanges": "Modifications", + "detailScheduled": "Démarrage prévu", + "detailCreated": "Créée", + "detailStarted": "Démarrée", + "detailFinished": "Terminée", + "diffLoading": "Chargement du diff…", + "deleteConfirmTitle": "Supprimer la tâche ?", + "deleteConfirmBody": "« {title} » sera retirée du tableau. Une exécution active est d’abord annulée.", + "deleteWithWorktree": "Supprimer aussi son worktree", + "eventCreated": "Créée", + "eventStatusChanged": "Changement d’état", + "eventConfigEffective": "Configuration de lancement", + "eventInitCommand": "Commande d'initialisation", + "eventAgentProgress": "Progression de l’agent", + "eventAgentVerdict": "Verdict de l’agent", + "eventMergeAttempt": "Fusion démarrée", + "eventMergeQueued": "Mise en file de fusion", + "eventMergeConflict": "Conflit de fusion", + "eventPreflight": "Pré-vérification", + "eventCleanupFailed": "Échec du nettoyage du worktree", + "eventResumeFallback": "Reprise échouée, nouvelle session utilisée", + "eventUserAction": "Action utilisateur", + "eventDiffStat": "Instantané des changements" + }, + "CustomSkillsSettings": { + "loading": "Chargement des compétences personnalisées…", + "category": "Personnalisées", + "searchPlaceholder": "Rechercher des compétences personnalisées par nom, ID ou description", + "states": { + "not_linked": "Non activée", + "linked_to_codeg": "Activée", + "linked_elsewhere": "Liée ailleurs", + "blocked_by_real_directory": "Bloquée par un dossier réel", + "broken": "Lien rompu" + }, + "actions": { + "new": "Nouvelle", + "import": "Importer", + "importFromAgent": "Importer depuis un agent", + "cancel": "Annuler", + "save": "Enregistrer" + }, + "rowMenu": { + "edit": "Modifier", + "duplicate": "Dupliquer", + "delete": "Supprimer" + }, + "bulk": { + "delete": "Supprimer la sélection" + }, + "editor": { + "createTitle": "Nouvelle compétence personnalisée", + "editTitle": "Modifier la compétence personnalisée", + "description": "Les compétences personnalisées sont stockées dans le magasin partagé (~/.codeg/skills) et peuvent être activées pour n'importe quel agent.", + "idLabel": "ID de la compétence", + "idPlaceholder": "ex. my-workflow", + "contentLabel": "SKILL.md", + "contentPlaceholder": "Rédigez ici le SKILL.md de la compétence…", + "preview": "Aperçu", + "edit": "Modifier", + "emptyBody": "Aucun contenu pour le moment." + }, + "duplicate": { + "title": "Dupliquer la compétence", + "description": "Créer une copie de « {id} » avec un nouvel ID.", + "newIdPlaceholder": "Nouvel ID de compétence", + "confirm": "Dupliquer" + }, + "import": { + "title": "Choisir un dossier de compétence à importer" + }, + "importFromAgent": { + "title": "Importer des compétences depuis un agent", + "description": "Copiez les compétences propres à un agent dans le magasin partagé pour les activer sur n'importe quel agent.", + "agentLabel": "Agent", + "agentPlaceholder": "Sélectionner un agent", + "selectAll": "Tout sélectionner ({count})", + "loading": "Chargement des compétences de l'agent…", + "unsupported": "Cet agent n'expose pas de répertoire de compétences.", + "empty": "Cet agent n'a aucune compétence à importer.", + "alreadyInLibrary": "Dans la bibliothèque", + "confirm": "Importer la sélection ({count})" + }, + "delete": { + "title": "Supprimer les compétences personnalisées ?", + "body": "Cela retire {count} compétence(s) personnalisée(s) du magasin central et les dissocie de tous les agents. Action irréversible.", + "confirm": "Supprimer" + }, + "toasts": { + "loadFailed": "Échec du chargement de la compétence", + "idRequired": "Veuillez saisir un ID de compétence", + "created": "Compétence personnalisée créée", + "updated": "Compétence personnalisée mise à jour", + "saveFailed": "Échec de l'enregistrement de la compétence", + "imported": "Compétence importée", + "importFailed": "Échec de l'importation de la compétence", + "duplicated": "Compétence dupliquée", + "duplicateFailed": "Échec de la duplication de la compétence", + "deleted": "{count} compétence(s) supprimée(s)", + "deletedPartial": "{ok} supprimée(s), {failed} en échec", + "deleteFailed": "Échec de la suppression des compétences", + "importedFromAgent": "{count} compétence(s) importée(s)", + "importedFromAgentPartial": "{ok} importée(s), {failed} en échec", + "importFromAgentAllSkipped": "Rien à importer — {count} déjà dans la bibliothèque", + "importFromAgentFailed": "Échec de l'import depuis l'agent" + } + }, + "CodexModelEditor": { + "customizedNotice": "Vous avez personnalisé la liste des modèles, codeg gère donc désormais toute la table des modèles de codex. Les modèles officiels que codex ajoutera plus tard n'apparaîtront pas automatiquement : cliquez sur le bouton actualiser ci-dessous puis enregistrez à nouveau pour les synchroniser. Effacez vos personnalisations pour laisser codex se mettre à jour automatiquement.", + "officialsTitle": "Modèles officiels", + "officialsHint": "Inclus automatiquement depuis le codex que vous lancez ; supprimez ceux dont vous ne voulez pas.", + "officialsEmpty": "Aucun modèle officiel disponible.", + "refresh": "Actualiser depuis codex", + "readdOfficial": "Rajouter un officiel", + "customsTitle": "Modèles personnalisés", + "customsEmpty": "Aucun modèle personnalisé pour l'instant.", + "addCustom": "Ajouter personnalisé", + "slugPlaceholder": "id du modèle (slug)", + "displayNamePlaceholder": "Nom affiché", + "contextWindow": "Contexte", + "makeDefault": "Définir par défaut", + "defaultHint": "Modèle par défaut", + "remove": "Supprimer", + "advanced": "Avancé", + "baseTemplate": "Modèle de base", + "baseTemplateHint": "Modèle officiel à partir duquel cloner les champs requis (invite système, outils, limites).", + "groupBehavior": "Comportement et capacités", + "fieldReasoningLevel": "Raisonnement par défaut", + "fieldReasoningSummary": "Résumé du raisonnement", + "fieldVerbosity": "Verbosité", + "fieldShellType": "Type de shell", + "fieldApplyPatch": "Outil apply-patch", + "fieldReasoningSummaries": "Résumés de raisonnement", + "fieldSupportVerbosity": "Contrôle de la verbosité", + "fieldParallelToolCalls": "Appels d'outils en parallèle", + "fieldSearchTool": "Outil de recherche web", + "optNone": "Aucun", + "groupInstructions": "Description et prompt système", + "fieldDescription": "Description", + "baseInstructions": "Invite système (base_instructions)" + }, + "DiagnosticsSettings": { + "title": "Diagnostic de l'environnement", + "description": "Vérifie comment cette app résout la CLI de l'agent dans son propre processus, ce qui peut différer de votre terminal.", + "loading": "Diagnostic en cours…", + "error": "Échec du diagnostic", + "rerun": "Relancer", + "copyAll": "Tout copier", + "copied": "Diagnostic copié dans le presse-papiers", + "button": "Diagnostiquer", + "verdict": { + "ok": "L'environnement semble sain. S'il indique toujours non installé, redémarrez complètement l'app pour actualiser le cache du préfixe.", + "node_missing": "Node.js est introuvable dans le PATH de l'app.", + "npm_missing": "npm est introuvable dans le PATH de l'app.", + "not_installed": "Cet agent ne semble pas installé.", + "installed_but_unresolved": "Enregistré comme installé, mais l'app ne trouve pas son exécutable.", + "user_prefix_not_on_path": "Installé dans le préfixe de secours (~/.codeg/npm-global), qui n'est pas dans le PATH de l'app. Redémarrez complètement l'app et réessayez.", + "homebrew_bin_not_on_path": "Installé sous le bin de Homebrew, qui n'est pas dans le PATH de l'app (séparation keg Apple Silicon).", + "terminal_only_path": "La commande se résout dans votre terminal mais pas dans l'app : un écart de PATH GUI. Lancez l'app depuis un terminal ou réinstallez depuis les Paramètres des agents.", + "npm_prefix_timeout": "npm prefix -g était trop lent (plus de 1,5 s), la détection de secours a été ignorée. Redémarrez l'app et réessayez.", + "node_too_old": "Votre Node.js actif est plus ancien que ce que cet agent requiert. Mettez à niveau Node.js.", + "adapter_missing_native_present": "Votre CLI {agent} est bien installée, mais Codeg lance un paquet adaptateur ACP distinct, et celui-ci ne l'est pas encore. Installez-le depuis les paramètres des agents : il ne touche pas à votre CLI et partage la même connexion.", + "adapter_missing": "Codeg lance un paquet adaptateur ACP distinct pour {agent}, et il n'est pas encore installé. Installez-le depuis les paramètres des agents — installer seulement la CLI de l'éditeur ne suffit pas." + } + }, + "TokenUsage": { + "title": "Consommation de tokens", + "rangeLabel": "Période", + "range7d": "7 jours", + "range30d": "30 jours", + "range90d": "90 jours", + "rangeThisMonth": "Ce mois-ci", + "rangeThisYear": "Cette année", + "rangeAll": "Tout", + "rangeCustom": "Personnalisée", + "moreRanges": "Plus", + "customRangePick": "Choisir une période", + "bucketLabel": "Regrouper par", + "bucketDay": "Jour", + "bucketWeek": "Semaine", + "bucketMonth": "Mois", + "bucketUnitDay": "Jour", + "bucketUnitWeek": "Semaine", + "bucketUnitMonth": "Mois", + "folderFilter": "Dossiers", + "allFolders": "Tous les dossiers", + "agentFilter": "Agents", + "allAgents": "Tous les agents", + "modelFilter": "Modèles", + "allModels": "Tous les modèles", + "searchPlaceholder": "Rechercher…", + "noMatches": "Aucun résultat", + "clearFilter": "Effacer la sélection", + "resetFilters": "Réinitialiser les filtres", + "refresh": "Actualiser", + "rebuild": "Tout reconstruire", + "rebuildHint": "Efface les données comptées et relit toutes les transcriptions. Utile si une session a grandi hors de codeg.", + "syncing": "Comptage des sessions…", + "syncProgress": "{done} / {total}", + "syncDone": "{synced} sessions comptées", + "syncFailed": "Certaines sessions n'ont pas pu être lues", + "syncBusy": "Une actualisation est déjà en cours", + "lastSynced": "Mis à jour {time}", + "lastSyncedNever": "Jamais mis à jour", + "tileTotal": "Tokens au total", + "tileSessions": "Sessions", + "tileTurns": "Tours", + "tileActiveDays": "Jours actifs", + "tileGenTime": "Temps de génération", + "vsPrevious": "vs période précédente", + "deltaNew": "nouveau", + "trendTitle": "Consommation dans le temps", + "trendEmpty": "Aucune consommation sur cette période", + "trendTurns": "Tours", + "trendSessions": "Sessions", + "compositionTitle": "À quoi sont partis les tokens", + "compositionHint": "L'entrée est ce que vous avez envoyé, la sortie ce que le modèle a écrit, et les lectures de cache du contexte non refacturé au prix fort.", + "compositionNote": "Renvoyer ces lectures de cache au prix fort aurait coûté {value} de plus.", + "inputTokens": "Entrée", + "outputTokens": "Sortie", + "cacheWrite": "Écriture cache", + "cacheRead": "Lecture cache", + "freshTokens": "Calcul frais", + "cacheHitCaption": "Taux de cache", + "cacheHeroTitleHigh": "L'essentiel du contexte n'a pas été renvoyé", + "cacheHeroTitleLow": "L'essentiel du contexte se calcule encore au prix fort", + "cacheHeroDesc": "Le cache a porté {cached} de contexte ; seuls {fresh} ont été réellement recalculés sur la période.", + "cacheSavedSuffix": "Soit l'équivalent de {saved} de renvois économisés.", + "avgPerSession": "Moy. par session", + "avgTurnsPerSession": "{count} tours par session en moyenne", + "avgPerActiveDay": "Moy. par jour actif", + "peakBucket": "{bucket} le plus chargé", + "peakHour": "Heure de pointe", + "daysValue": "{count} jours", + "idleDays": "Jours sans activité", + "byFolderTitle": "Par dossier", + "byAgentTitle": "Par agent", + "byModelTitle": "Par modèle", + "distributionTitle": "Répartition de l'usage", + "distributionHint": "Sessions et tokens regroupés selon la dimension choisie — cliquez sur une ligne pour filtrer.", + "otherLabel": "Autres", + "unknownModel": "Modèle non renseigné", + "emptyBreakdown": "Rien d'enregistré", + "sessionsCount": "{count} sessions", + "heatmapTitle": "Quand vous codez", + "heatmapHint": "Tokens par jour de la semaine et heure locale.", + "heatmapPeakHint": "Le plus dense autour de {hour}:00.", + "less": "Moins", + "more": "Plus", + "heatmapCell": "{weekday} {hour}:00 — {value} tokens", + "weekMon": "Lun", + "weekTue": "Mar", + "weekWed": "Mer", + "weekThu": "Jeu", + "weekFri": "Ven", + "weekSat": "Sam", + "weekSun": "Dim", + "topSessionsTitle": "Sessions les plus gourmandes", + "untitledSession": "Session sans titre", + "topSessionsEmpty": "Aucune session sur cette période", + "streakLongest": "Plus longue série", + "streakLongestDays": "Plus longue série : {count} jours", + "share": "Partager", + "moreActions": "Autres actions", + "shareDialogTitle": "Partagez votre carte de consommation", + "shareDialogHint": "Un instantané de la période et des filtres affichés.", + "shareSave": "Enregistrer l'image", + "shareCopy": "Copier l'image", + "shareCopied": "Copié dans le presse-papiers", + "shareSaved": "Image enregistrée", + "shareFailed": "Impossible de créer l'image", + "shareRendering": "Génération…", + "cardHeading": "Mon bilan de code assisté par IA", + "cardRangeAll": "Depuis le début", + "cardTotalLabel": "Tokens consommés", + "cardFooter": "Réalisé avec codeg", + "cardTopModels": "Modèles principaux", + "cardTopProjects": "Projets principaux", + "archetypeNightOwl": "Oiseau de nuit", + "archetypeNightOwlDesc": "{percent}% de vos tokens brûlent après la tombée de la nuit.", + "archetypeEarlyBird": "Lève-tôt", + "archetypeEarlyBirdDesc": "{percent}% de vos tokens tombent avant 9 h.", + "archetypeWeekendWarrior": "Guerrier du week-end", + "archetypeWeekendWarriorDesc": "{percent}% de vos tokens arrivent le week-end.", + "archetypeCacheMaster": "Maître du cache", + "archetypeCacheMasterDesc": "{percent}% de votre contexte venait du cache.", + "archetypeMarathoner": "Marathonien", + "archetypeMarathonerDesc": "{days} jours de code sans interruption.", + "archetypePolyglot": "Polyvalent", + "archetypePolyglotDesc": "{count} agents utilisés sérieusement.", + "archetypeLaserFocus": "Focus laser", + "archetypeLaserFocusDesc": "{percent}% de vos tokens sur un seul projet.", + "archetypeDeepDiver": "Plongeur", + "archetypeDeepDiverDesc": "{averageK}K tokens par session en moyenne.", + "archetypeSteady": "Bâtisseur régulier", + "archetypeSteadyDesc": "{days} jours de livraison.", + "emptyTitle": "Rien de compté pour l'instant", + "emptyHint": "Codeg lit les tokens directement dans la transcription de chaque agent. Actualisez pour compter ce qui est déjà sur cette machine.", + "emptyAction": "Compter mes sessions", + "loadFailed": "Impossible de charger la consommation", + "truncatedNotice": "Cette période est très large — les chiffres ne couvrent que sa portion la plus récente." + } +} diff --git a/src/i18n/messages/ja.json b/src/i18n/messages/ja.json index 16016ef45..d11cc6667 100644 --- a/src/i18n/messages/ja.json +++ b/src/i18n/messages/ja.json @@ -1,4958 +1,4958 @@ -{ - "Language": { - "followSystem": "システムに従う", - "english": "英語", - "simplifiedChinese": "简体中文", - "traditionalChinese": "繁體中文", - "japanese": "日本語", - "korean": "韓国語", - "spanish": "スペイン語", - "german": "ドイツ語", - "french": "フランス語", - "portuguese": "ポルトガル語", - "arabic": "アラビア語" - }, - "GitCredentialDialog": { - "title": "認証が必要です", - "description": "リモートサーバーが認証情報を要求しています。ユーザー名とパスワード(またはアクセストークン)を入力してください。", - "username": "ユーザー名", - "usernamePlaceholder": "ユーザー名またはメールアドレス", - "password": "パスワード / トークン", - "passwordPlaceholder": "パスワードまたはアクセストークン", - "passwordHint": "サーバーのユーザー名とパスワードを入力してください。", - "cancel": "キャンセル", - "authenticate": "認証", - "authenticating": "認証中...", - "invalidCredentials": "認証情報が無効です。再試行してください。", - "saveCredentials": "今後の操作のために認証情報を保存する", - "githubTitle": "GitHub 認証", - "githubDescription": "個人アクセストークンを入力して GitHub に接続します。トークン検証後、自動的にアカウントに保存されます。", - "githubToken": "個人アクセストークン", - "githubTokenPlaceholder": "ghp_xxxxxxxxxxxx", - "githubTokenHint": "GitHub → Settings → Developer settings → Personal access tokens でトークンを生成してください。", - "githubAuthenticate": "検証して接続", - "generateToken": "トークンを生成" - }, - "SettingsShell": { - "title": "設定", - "preferences": "環境設定", - "nav": { - "general": "一般", - "appearance": "外観", - "agents": "エージェント", - "mcp": "MCP", - "skills": "Skills", - "shortcuts": "ショートカット", - "version_control": "バージョン管理", - "system": "システム", - "chat_channels": "チャットチャンネル", - "web_service": "Webサービス", - "model_providers": "モデルプロバイダー", - "experts": "エキスパート", - "science": "科学研究", - "office_tools": "Officeツール", - "skill_packs": "スキルパック", - "quick_messages": "クイックメッセージ", - "logs": "実行ログ" - } - }, - "AppearanceSettings": { - "sectionTitle": "テーマ外観", - "sectionDescription": "ライト、ダーク、またはシステム追従を選択できます。設定は自動保存されます。", - "themeMode": "テーマモード", - "placeholder": "テーマモードを選択", - "system": "システムに従う", - "light": "ライト", - "dark": "ダーク", - "currentTheme": "現在の有効テーマ: {theme}", - "resolvedTheme": { - "light": "ライト", - "dark": "ダーク", - "unknown": "--" - }, - "themeColor": { - "sectionTitle": "テーマカラー", - "sectionDescription": "ボタンやアクセント、ハイライトに使用する色を選択します。", - "current": "現在のカラー:{color}", - "options": { - "neutral": "Neutral", - "zinc": "Zinc", - "slate": "Slate", - "stone": "Stone", - "gray": "Gray", - "red": "Red", - "rose": "Rose", - "orange": "Orange", - "green": "Green", - "blue": "Blue", - "yellow": "Yellow", - "violet": "Violet" - } - }, - "customStyle": { - "sectionTitle": "カスタムスタイル", - "sectionDescription": "現在のテーマの配色を微調整したり、独自の CSS を適用したりできます。上書きはベースプリセットの上に重なるため、プリセットを切り替えても保持されます。", - "summarySuspended": "一時停止中", - "summaryDefault": "プリセットのまま", - "summaryTokens": "{count, plural, one {上書き # 件} other {上書き # 件}}", - "summaryCss": "カスタム CSS", - "suspendedByShortcut": "カスタムスタイルは一時停止中です。再開するまで、ここでの設定は反映されません。", - "suspendedBySafeParam": "このウィンドウはセーフ外観モードで開かれているため、カスタムスタイルは適用されません。他のウィンドウには影響しません。", - "resume": "カスタムスタイルを再開", - "enableTheme": "カスタム配色を有効にする", - "editingLight": "ライトモードの値を編集しています。ダークモードに切り替えると個別に設定できます。", - "editingDark": "ダークモードの値を編集しています。ライトモードに切り替えると個別に設定できます。", - "resetToken": "プリセット値に戻す", - "radius": "角丸", - "radiusHint": "sm から 4xl までの角丸スケール全体がこの値から導出されるため、スライダー 1 つでアプリ全体の角丸が変わります。", - "advanced": "詳細(他 {count} 個の変数)", - "enableCss": "カスタム CSS を有効にする", - "cssRisk": "上級者向け機能です。カスタム CSS は組み込みスタイルをすべて上書きするため、画面が使用不能になることがあります。", - "editCss": "CSS を編集…", - "cssPresent": "{size} KB 保存済み", - "cssEmpty": "まだ保存されていません", - "escapeHint": "画面が壊れてしまったら、{shortcut} でカスタムスタイルをすべて停止できます。safeStyle=1 のクエリパラメータ付きでウィンドウを開く方法もあります。", - "copyTheme": "テーマ JSON をコピー", - "importTheme": "テーマをインポート…", - "clearTheme": "上書きをクリア", - "interopHint": "テーマは shadcn の registry:theme 形式です。任意の shadcn テーマをそのまま貼り付けられ、書き出したテーマはどの shadcn プロジェクトでも使えます。", - "importTitle": "テーマをインポート", - "importDescription": "shadcn の registry:theme アイテム、light/dark のみのオブジェクト、またはフラットなトークンマップを貼り付けてください。", - "readClipboard": "クリップボードから読み取る", - "importConfirm": "インポート", - "cancel": "キャンセル", - "apply": "適用", - "toasts": { - "copied": "テーマ JSON をコピーしました", - "copyFailed": "クリップボードにコピーできませんでした", - "clipboardReadFailed": "クリップボードを読み取れませんでした。手動で貼り付けてください", - "importFailed": "この JSON には利用できるテーマ変数がありません", - "imported": "テーマをインポートしました" - }, - "css": { - "dialogTitle": "カスタム CSS", - "dialogDescription": "すべての codeg ウィンドウに適用されます。変更はリアルタイムでプレビューされ、「適用」で保存されます。", - "size": "{used} KB / {max} KB", - "ruleCount": "{count} 個のルール", - "errorTooLarge": "サイズが大きすぎて保存できません。上限以下に減らしてください。", - "errorImportEscaped": "除去後も @import が検出されました(エスケープ記法)。手動で削除してください。", - "warnNoRules": "ルールが 1 つも解析されませんでした。構文を確認してください。", - "noticeImportsRemoved": "@import を {count} 件削除しました。リモートのスタイルシートを取得してしまうためです。", - "noticeRemoteUrl": "リモートの url() が含まれています。適用するとネットワークリクエストが発生します。", - "noticePreviewSuspended": "カスタムスタイルが停止中のため、このプレビューは適用されません。", - "noticeDisabled": "カスタム CSS は無効です。ここでプレビューはできますが、有効にするまで反映されません。", - "hintTokens": "ヒント: 上書きした色は var(--primary) や var(--background) などで参照できます。" - } - }, - "zoomLevel": { - "sectionTitle": "ウィンドウズーム", - "sectionDescription": "インターフェイス全体を拡大・縮小します。すぐに反映され、デバイスごとに保存されます。", - "placeholder": "ズームレベルを選択", - "default": "デフォルト", - "current": "現在のズーム:{zoom}%" - }, - "fonts": { - "sectionTitle": "フォント", - "sectionDescription": "インターフェース、コードエディター、ターミナルのフォントをそれぞれ選択します。内蔵フォントは必要に応じて読み込まれます。「カスタム…」を選ぶと、システムにインストールされた任意のフォントを使用できます。", - "interface": "インターフェース", - "editor": "エディター", - "terminal": "ターミナル", - "groupSans": "サンセリフ", - "groupMono": "等幅", - "custom": "カスタム…", - "customPlaceholder": "フォント名(例:Fira Code)", - "fontSize": "フォントサイズ", - "ligatures": "合字を有効にする", - "ligaturesUnavailable": "このフォントには合字がありません", - "wordWrap": "折り返しを有効にする", - "terminalLigaturesHint": "ターミナルの合字は内蔵のコーディングフォントにのみ適用されます。", - "preview": "プレビュー" - }, - "welcomePanel": { - "sectionTitle": "モード選択エリア", - "sectionDescription": "新しい会話ページで入力欄の上に表示される「コード開発 / 日常業務」のショートカットカードです。", - "showQuickActions": "新しい会話ページに表示する" - }, - "workspaceBackground": { - "sectionTitle": "ワークスペースの背景", - "sectionDescription": "ワークスペース全体の背後に画像を表示します。サイドバーやパネルは半透明のすりガラスになり画像が透けて見えます。マスクで文字の可読性を保ちます。", - "enable": "背景画像を有効にする", - "image": "画像", - "chooseImage": "画像を選択", - "replaceImage": "画像を変更", - "removeImage": "削除", - "fillMode": "表示方法", - "fillModes": { - "cover": "全体を覆う", - "contain": "全体を表示", - "center": "中央", - "tile": "タイル" - }, - "maskOpacity": "マスクの不透明度", - "maskOpacityHint": "値を大きくすると画像がテーマの背景色に近づき、文字のコントラストが上がります。", - "imageBlur": "画像のぼかし", - "panelOpacity": "パネルの不透明度", - "panelOpacityHint": "サイドバー・パネル・タブバーの不透明度です。低いほど画像が透けて見えます。", - "errorTooLarge": "画像が大きすぎます(最大 16 MB)。", - "errorUploadFailed": "背景画像の設定に失敗しました。" - } - }, - "SystemSettings": { - "loading": "読み込み中...", - "sectionTitle": "システム管理", - "sectionDescription": "ネットワークプロキシ、アプリ更新、言語設定を管理します。", - "proxyTitle": "ネットワークプロキシ", - "proxyDescription": "有効にすると、以降のネットワークリクエストはこのプロキシを優先して使用します(ACP チャット、エージェントのインストール、Git リモート操作を含む)。", - "loadFailed": "読み込みに失敗しました: {message}", - "enableProxy": "システムプロキシを有効化", - "proxyAddress": "プロキシアドレス", - "proxyHint": "http(s)/socks5 をサポート。例: {example}。システムプロキシ有効時のみ有効です。", - "save": "保存", - "saving": "保存中...", - "proxyRequired": "プロキシ有効時はプロキシ URL が必要です", - "saveSuccess": "システムプロキシ設定を保存しました", - "saveFailed": "保存に失敗しました: {message}", - "languageTitle": "言語", - "languageDescription": "アプリの言語を設定します。システムに従う場合、未対応言語は英語にフォールバックします。", - "appLanguage": "アプリ言語", - "languageSaveSuccess": "言語設定を保存しました", - "languageSaveFailed": "言語設定の保存に失敗しました: {message}", - "updateTitle": "アプリ更新", - "versionTitle": "ソフトウェアアップデート", - "updateDescription": "設定されたリリースソースで新しいバージョンを確認し、利用可能なら直接インストールします。", - "currentVersion": "現在のバージョン", - "upgradableVersion": "最新バージョン", - "none": "なし", - "lastChecked": "最終確認: {time}", - "updateError": "更新エラー: {message}", - "checking": "確認中...", - "checkUpdate": "更新を確認", - "updating": "インストール中...", - "downloading": "ダウンロード中...", - "upgradeTo": "v{version} にアップグレード", - "viewRelease": "v{version} のリリースを表示", - "foundUpdate": "新しいバージョン v{version} が見つかりました", - "alreadyLatest": "すでに最新バージョンです", - "checkUpdateFailed": "更新確認に失敗しました: {message}", - "installSuccess": "更新をインストールしました。アプリを再起動します。", - "installFailed": "更新に失敗しました: {message}", - "upgradeSuccess": "アップグレードが完了しました。再読み込みしています...", - "restartTimeout": "サーバーが時間内に復帰しませんでした。コンテナまたはサービスのログを確認してください。", - "restartingIn": "{seconds} 秒後に再起動します...", - "waitingForServer": "サーバーの復帰を待っています...", - "restartToUpdate": "再起動して更新", - "newVersionBadge": "新バージョン v{version}", - "updateAvailableTitle": "アップデートがあります", - "releaseNotesTitle": "更新内容", - "remindLater": "後で", - "retry": "再試行", - "stepDownload": "ダウンロード", - "stepInstall": "インストール", - "stepRestart": "再起動", - "updateReadyHint": "アップデートをダウンロードしました。再起動して適用してください。", - "restarting": "再起動しています…", - "dockerUpgradeHint": "いま実行中のコンテナを更新します。コンテナを再作成すると失われます。維持するには、新しいバージョンのイメージを取得またはビルドしてコンテナを再作成してください。", - "upgradeRolledBack": "アップグレードに失敗しました。サーバーは前のバージョンにロールバックしました。", - "serverUnreachable": "アップグレードを開始するためにサーバーに接続できませんでした。サーバーが稼働中であることを確認して再試行してください。", - "rollbackButton": "ロールバック", - "rollingBack": "ロールバック中...", - "rollbackDescription": "前回のアップグレード前にインストールされていたバージョンに戻します。", - "rollbackConfirmTitle": "以前のバージョンにロールバックしますか?", - "rollbackConfirmDescription": "サーバーは前回のアップグレード前のバージョンで再起動します。新しいリリースは引き続き再インストールできます。", - "rollbackConfirm": "ロールバック", - "rollbackCancel": "キャンセル", - "rollbackSuccess": "以前のバージョンにロールバックしました。再読み込みしています...", - "rollbackFailed": "ロールバックに失敗しました。サーバーのログを確認してください。", - "updateErrors": { - "sourceUnavailable": "更新ソースに接続できません。ネットワークまたはプロキシを確認して再試行してください。", - "network": "ネットワーク接続に失敗しました。ネットワークまたはプロキシを確認して再試行してください。", - "downloadFailed": "更新パッケージのダウンロードに失敗しました。しばらくしてから再試行してください。", - "installFailed": "更新のインストールに失敗しました。アプリを閉じて再試行してください。", - "unknown": "更新に失敗しました。しばらくしてから再試行してください。" - } - }, - "VersionControlSettings": { - "loading": "読み込み中...", - "sectionTitle": "バージョン管理", - "sectionDescription": "Git 実行ファイルの設定と GitHub アカウントの管理。", - "gitTitle": "Git 設定", - "gitDescription": "アプリケーションで使用する Git 実行ファイルを設定します。", - "gitDetected": "Git が検出されました", - "gitNotFound": "システムに Git が見つかりません", - "gitVersion": "バージョン", - "gitPath": "パス", - "customGitPath": "カスタム Git パス", - "customGitPathPlaceholder": "/usr/bin/git", - "customGitPathHint": "空欄の場合、自動検出されたパスを使用します。", - "test": "テスト", - "testing": "テスト中...", - "testSuccess": "Git 実行ファイルは有効です。", - "testFailed": "Git テスト失敗:{message}", - "save": "保存", - "saving": "保存中...", - "saveSuccess": "Git 設定を保存しました。", - "saveFailed": "保存に失敗しました:{message}", - "githubTitle": "GitHub アカウント", - "githubDescription": "認証用の GitHub アカウントを管理します。トークンはローカルに保存されます。", - "noAccounts": "GitHub アカウントが設定されていません。", - "addAccount": "アカウントを追加", - "serverUrl": "サーバー URL", - "serverUrlPlaceholder": "https://github.com", - "token": "個人アクセストークン", - "tokenPlaceholder": "ghp_xxxxxxxxxxxx", - "generateToken": "トークンを生成", - "tokenHint": "GitHub → Settings → Developer settings → Personal access tokens でトークンを生成してください。", - "validateAndAdd": "検証して追加", - "validating": "検証中...", - "addSuccess": "アカウント {username} を追加しました。", - "addFailed": "アカウントの追加に失敗しました:{message}", - "testConnection": "テスト", - "connectionSuccess": "接続成功。", - "connectionFailed": "接続失敗:{message}", - "setDefault": "デフォルトに設定", - "defaultLabel": "デフォルト", - "defaultSet": "デフォルトアカウントを更新しました。", - "removeAccount": "削除", - "removeConfirmTitle": "アカウントを削除", - "removeConfirmMessage": "アカウント「{username}」を削除してもよろしいですか?", - "removeConfirm": "削除", - "removeCancel": "キャンセル", - "removeSuccess": "アカウントを削除しました。", - "scopes": "スコープ", - "loadFailed": "設定の読み込みに失敗しました:{message}", - "gitAccount": { - "sectionTitle": "Git サーバーアカウント", - "sectionDescription": "GitHub 以外の Git サーバーの認証情報を管理します(GitLab、Bitbucket、セルフホストなど)。", - "noAccounts": "Git サーバーアカウントが設定されていません。", - "addAccount": "アカウントを追加", - "addTitle": "Git アカウントを追加", - "addDescription": "サーバーアドレス、ユーザー名、パスワードまたはアクセストークンを入力してください。", - "serverUrl": "サーバー URL", - "serverUrlPlaceholder": "https://gitlab.example.com", - "username": "ユーザー名", - "usernamePlaceholder": "ユーザー名またはメールアドレス", - "password": "パスワード / トークン", - "passwordPlaceholder": "パスワードまたはアクセストークン", - "passwordHint": "サーバーのパスワードまたはアクセストークンを入力してください。", - "add": "追加", - "serverRequired": "サーバー URL を入力してください。", - "usernameRequired": "ユーザー名を入力してください。", - "passwordRequired": "パスワードを入力してください。" - } - }, - "ShortcutSettings": { - "sectionTitle": "ショートカット", - "resetDefault": "デフォルトに戻す", - "recordInstruction": "右側のボタンをクリックしてからキーの組み合わせを押してください。Ctrl/Cmd、Alt、Shift が使用できます。Esc で記録をキャンセルします。", - "recording": "ショートカットを入力...", - "toasts": { - "conflict": "ショートカットはすでに「{title}」で使用されています", - "updated": "ショートカットを更新しました", - "invalid": "無効なショートカットです。もう一度お試しください", - "reset": "デフォルトのショートカットを復元しました" - }, - "actions": { - "toggle_search": { - "title": "検索を開く", - "description": "会話検索パネルを表示または非表示にします" - }, - "toggle_sidebar": { - "title": "左サイドバーを切り替え", - "description": "会話一覧サイドバーを表示または非表示にします" - }, - "toggle_terminal": { - "title": "ターミナルを切り替え", - "description": "下部ターミナルパネルを表示または非表示にします" - }, - "new_terminal_tab": { - "title": "新しいターミナル", - "description": "ターミナルにフォーカスがあるとき新しいタブを作成します" - }, - "close_current_terminal_tab": { - "title": "現在のターミナルを閉じる", - "description": "ターミナルにフォーカスがあるとき現在のタブを閉じます" - }, - "toggle_aux_panel": { - "title": "右パネルを切り替え", - "description": "補助情報パネルを表示または非表示にします" - }, - "new_conversation": { - "title": "新しい会話", - "description": "現在のフォルダで新しい会話タブを作成します" - }, - "open_folder": { - "title": "フォルダを開く", - "description": "フォルダ選択を開き、新しいウィンドウで開きます" - }, - "open_settings": { - "title": "設定を開く", - "description": "設定ウィンドウを開きます" - }, - "close_current_tab": { - "title": "現在のタブを閉じる", - "description": "現在の会話またはファイルタブを閉じます" - }, - "close_all_file_tabs": { - "title": "すべてのファイルタブを閉じる", - "description": "ファイルペインがアクティブなときに開いているすべてのファイルタブを閉じます" - }, - "next_tab": { - "title": "次のタブ", - "description": "次の会話またはファイルタブに切り替える" - }, - "prev_tab": { - "title": "前のタブ", - "description": "前の会話またはファイルタブに切り替える" - }, - "send_message": { - "title": "メッセージを送信", - "description": "入力欄のメッセージを送信する" - }, - "newline_in_message": { - "title": "メッセージ内で改行", - "description": "入力欄で改行を挿入する" - }, - "toggle_custom_style": { - "title": "カスタムスタイルの停止/再開", - "description": "緊急脱出用: カスタム配色と CSS をすべてオフにし、再度押すと元に戻します" - } - } - }, - "SkillsSettings": { - "title": "Skills", - "description": "左側でSkillを選択します。右側は既定でMarkdownプレビューです。編集に切り替えると変更して保存できます。", - "loadingAgents": "Skill対応エージェントを読み込み中...", - "emptyNoManageableAgents": "Skillを管理できるエージェントがありません。", - "managedTarget": "管理対象", - "selectAgentPlaceholder": "エージェントを選択", - "searchPlaceholder": "名前 / ID / パスで検索...", - "skillsList": "Skill一覧", - "loadingSkills": "Skillを読み込み中...", - "agentNotSupported": "現在のエージェントはSkill管理に対応していません。", - "emptySkills": "まだSkillがありません。「新規Skill」をクリックして作成してください。", - "newSkillTitle": "新規Skill", - "skillInfo": "Skill情報", - "skillIdPlaceholder": "skill-id(英数字/-/_/.)", - "skillsDirectoryWithPath": "Skillディレクトリ: {path}", - "skillsDirectoryNeedId": "Skillディレクトリ: Skill ID を入力すると完全なパスを生成します", - "markdownContent": "Markdown内容", - "editingStatus": "編集中", - "previewStatus": "プレビュー中", - "contentPlaceholder": "SkillのMarkdown内容を入力...", - "metadataTitle": "Skillメタデータ", - "onlyYamlMetadata": "このSkillにはYAMLメタデータのみが含まれています。", - "emptyContentHint": "まだ内容がありません。「編集」をクリックして開始してください。", - "loadingSkill": "Skillを読み込み中...", - "emptyNoAgents": "利用可能なエージェントがありません。", - "noSelectionHint": "左側から Skill を選択するか、「新規 Skill」をクリックして作成してください。", - "systemBadge": "システム", - "systemHint": "CLI 組み込み Skill・読み取り専用", - "scope": { - "global": "グローバル", - "folder": "フォルダ", - "selectFolderPlaceholder": "フォルダを選択", - "noFolders": "フォルダが見つかりません", - "pickFolderHint": "Skills を表示するフォルダを選択してください。" - }, - "actions": { - "preview": "プレビュー", - "edit": "編集", - "openInWindow": "新しいウィンドウで開く", - "delete": "削除", - "deleting": "削除中...", - "refresh": "更新", - "newSkill": "新規Skill", - "reset": "リセット", - "save": "保存", - "saving": "保存中...", - "cancel": "キャンセル" - }, - "deleteDialog": { - "title": "Skillを削除", - "confirm": "現在のSkillを削除しますか?この操作は元に戻せません。", - "confirmWithNamePrefix": "Skill", - "confirmWithNameSuffix": "を削除しますか?この操作は元に戻せません。" - }, - "toasts": { - "loadFailed": "Skillの読み込みに失敗しました", - "openFolderFailed": "フォルダを開けませんでした", - "noSkillDirectory": "現在のエージェントで利用可能なSkillディレクトリが見つかりません", - "nameRequired": "Skill名は空にできません", - "updated": "Skillを更新しました", - "created": "Skillを作成しました", - "saveFailed": "Skillの保存に失敗しました", - "deleted": "Skillを削除しました", - "deleteFailed": "Skillの削除に失敗しました" - }, - "templates": { - "gemini": "---\nname: example-skill\ndescription: Describe when this skill should be used.\n---\n\n# Skill Name\n\nInstructions for the agent when this skill is active.\n\n## Workflow\n\n1. Add actionable step one.\n2. Add actionable step two.\n", - "openCode": "---\nname: example-skill\ndescription: Describe when this skill should be used.\n---\n\n# Purpose\n\nDescribe what this skill helps with.\n\n# Steps\n\n1. Add actionable step one.\n2. Add actionable step two.\n", - "openClaw": "---\nname: example-skill\ndescription: Describe when this skill should be used.\nuser-invocable: true\ndisable-model-invocation: false\n---\n\n# Purpose\n\nDescribe what this skill helps with.\n\n# Instructions\n\n1. Add actionable instruction one.\n2. Add actionable instruction two.\n", - "default": "---\nname: example-skill\ndescription: Describe when this skill should be used.\n---\n\n# Skill: example-skill\n\n## When to use\n\n- Describe trigger conditions.\n\n## Instructions\n\n1. Add actionable instruction one.\n2. Add actionable instruction two.\n" - } - }, - "McpSettings": { - "loading": "読み込み中...", - "summary": { - "missingCommand": "(コマンド未設定)", - "missingUrl": "(URL未設定)" - }, - "protocol": { - "stdio": "Stdio" - }, - "errors": { - "selectInstallProtocol": "インストールプロトコルを選択してください", - "fieldRequired": "{field} は必須です", - "fieldNeedsBoolean": "{field} は true または false である必要があります", - "fieldNeedsNumber": "{field} は数値である必要があります", - "fieldNeedsInteger": "{field} は整数である必要があります", - "fieldInvalidJson": "{field} のJSONが不正です: {message}", - "fieldOutOfRange": "{field} の値が許可範囲外です", - "jsonEmpty": "{name} は空にできません", - "jsonInvalid": "{name} は有効なJSONではありません: {message}", - "jsonMustBeObject": "{name} はJSONオブジェクトである必要があります", - "specMustBeObject": "MCP 設定は JSON オブジェクトである必要があります。", - "missingType": "MCP 設定に type フィールドがありません。stdio、http(エイリアス:streamable-http、streamableHttp)、sse のいずれかを指定してください。", - "unsupportedType": "サポートされていない MCP タイプ {type}。対応:stdio、http(エイリアス:streamable-http、streamableHttp)、sse。", - "codexEntryUnsupportedType": "Codex MCP エントリ {id} のタイプ {type} はサポートされていません。対応:stdio、http(エイリアス:streamable-http、streamableHttp)、sse。", - "unsupportedTransportType": "サポートされていない transport タイプ {type}。対応:http(エイリアス:streamable-http、streamableHttp)、sse。", - "stdioCommandRequired": "stdio タイプの MCP には空でない command フィールドが必要です。", - "remoteUrlRequired": "リモート MCP には空でない url フィールドが必要です。", - "appsRequired": "対象アプリを少なくとも 1 つ選択してください。" - }, - "jsonNames": { - "localConfig": "MCP設定", - "installConfig": "インストール設定" - }, - "toasts": { - "uninstalled": "MCPをアンインストールしました", - "uninstallFailed": "アンインストールに失敗しました: {message}", - "selectAtLeastOneApp": "対象アプリを少なくとも1つ選択してください", - "saveSuccess": "保存しました", - "saveFailed": "保存に失敗しました: {message}", - "installed": "{name} をインストールしました", - "installFailed": "インストールに失敗しました: {message}", - "serverIdRequired": "Server ID は必須です", - "serverIdExists": "Server ID \"{id}\" は既に存在します。既存の項目を編集するか、別の名前を選択してください。", - "created": "MCP を作成しました" - }, - "installDialog": { - "title": "MCPインストールの確認", - "descriptionWithName": "{name} をローカル設定にインストールします。", - "description": "インストール対象アプリを選択してください。", - "protocol": "プロトコル", - "selectProtocol": "プロトコルを選択", - "parameters": "設定パラメータ", - "booleanPlaceholder": "true/false を選択してください", - "selectOneValue": "値を選択", - "targetApps": "対象アプリ" - }, - "actions": { - "cancel": "キャンセル", - "confirmInstall": "インストールを確定", - "installing": "インストール中", - "uninstall": "アンインストール", - "uninstalling": "アンインストール中", - "viewDetails": "詳細を見る", - "save": "保存", - "saving": "保存中", - "install": "インストール", - "refresh": "更新", - "newMcp": "新規 MCP", - "create": "作成", - "creating": "作成中..." - }, - "tabs": { - "local": "ローカル MCP", - "market": "MCP マーケットプレイス" - }, - "local": { - "filterPlaceholder": "ローカルMCPを絞り込み...", - "loadFailed": "読み込み失敗: {message}", - "empty": "ローカルMCPが見つかりません。", - "description": "ローカルMCP設定は直接編集して保存できます。", - "enabledApps": "有効なアプリ", - "configJson": "MCP設定 (JSON)", - "draftTitle": "新規 MCP", - "draftDescription": "Server ID と設定を入力してローカル MCP サーバーを作成します。", - "serverIdLabel": "Server ID", - "serverIdPlaceholder": "Server ID(例:my-mcp)", - "typeHint": "対応タイプ:stdio、http(エイリアス streamable-http、streamableHttp)、sse。env は stdio 専用です。リモート MCP の認証トークンは headers で渡してください。", - "envOnRemoteWarning": "リモート MCP の設定に env が含まれています。env は stdio のみで使用され、リモート MCP の認証トークンは headers に格納します。env は保存時に無視されます。" - }, - "market": { - "selectMarketplace": "マーケットプレイスを選択", - "searchPlaceholder": "MCPを検索...", - "searchFailed": "検索に失敗しました: {message}", - "loadingList": "MCP一覧を読み込み中...", - "empty": "MCPの検索結果がありません。", - "loadingDetail": "マーケットプレイス詳細を読み込み中...", - "detailLoadFailed": "詳細の読み込みに失敗しました: {message}", - "owner": "オーナー: {owner}", - "namespace": "名前空間: {namespace}", - "defaultInstallProtocol": "デフォルトのインストールプロトコル", - "currentOptionParameterCount": "現在のオプションのパラメータ数: {count}", - "installConfigDescription": "インストール設定 (JSON、インストール前に編集可能。編集内容はプロトコル/パラメータフォームより優先されます)", - "selectLeftToView": "詳細を見るには左側のマーケットプレイスMCPを選択してください。" - }, - "badges": { - "verified": "認証済み", - "remote": "リモート", - "hasHomepage": "ホームページあり", - "uses": "{count} 回使用", - "deployed": "デプロイ済み", - "notDeployed": "未デプロイ" - }, - "selectLeftMcp": "左側でMCPを選択してください。" - }, - "AcpAgentSettings": { - "title": "Agent SDK 管理", - "description": "Agent SDK の接続、有効化状態、環境変数、設定管理、バージョン事前チェック情報を一元管理します。", - "loadingAgents": "エージェント一覧を読み込み中...", - "agentList": "エージェント一覧", - "emptyNoAgent": "利用可能なエージェントがありません。", - "configManagement": "設定管理", - "envVars": "環境変数", - "hostTools": { - "label": "ファイルとコマンドをエージェント自身に処理させる", - "description": "codeg がファイルアクセスとターミナルコマンドを代行しなくなり、エージェントが自身のプロセスで実行します。そうすることで初めて、エージェント自身のサンドボックスと権限ルールが適用されます。他のエージェントへの委任も無効になります(同じ処理が codeg 経由に戻ってしまうため)。codeg 自体はサンドボックスを提供しないため、エージェント側でサンドボックスを設定済みの場合にのみ有効にしてください。" - }, - "nativeJsonConfig": "ネイティブ JSON 設定", - "modelHintDefault": "空欄の場合はシステム既定モデルを使用します。", - "generalConfigDescriptionClaude": "API URL、API Key、Claude モデルをすばやく設定でき、ネイティブ JSON 設定と同期します。", - "generalConfigDescriptionDefault": "重要な設定入力(API URL、API Key、Model)とネイティブ JSON 設定管理をサポートします。", - "multiAgent": { - "title": "マルチエージェント連携", - "description": "アクティブなエージェントがサブタスクを他のエージェントに委任できるようにします。", - "enable": "委任を有効化", - "enableHint": "オフにすると、delegate_to_agent ツールはエージェントの MCP ツール一覧から非表示になります。", - "withheldByHostTools": "{agents} には委任ツールが渡りません。エージェントごとの「ファイルとコマンドをエージェント自身に任せる」スイッチがオンになっています。", - "selfInitiate": "Allow spawn without @", - "selfInitiateHint": "When on, an agent may start a listed sub-agent on its own. An @ mention is still always honored. When off, only an @ mention starts a sub-agent.", - "depthLimit": "最大委任深度", - "depthHint": "許可範囲: {min}–{max}。委任チェーン(ルート → 子 → 孫 …)の再帰深度を制限します。", - "completedCacheLabel": "完了結果のキャッシュ(MB)", - "completedCacheHint": "実行中の委任セッションが保持する、完了したサブエージェント結果のメモリ内キャッシュ。そのセッションの実行中のみ保持され、セッション終了時に自動的に破棄されます。この予算を超えると古い結果から順にメモリから破棄されます(サブエージェント自身のセッションでは引き続き閲覧可能)。0 は無制限(それでもセッション終了時に破棄)。", - "save": "保存", - "saving": "保存中…", - "saved": "委任設定を保存しました", - "saveFailed": "委任設定の保存に失敗しました", - "loadFailed": "委任設定の読み込みに失敗しました: {detail}", - "tabGeneral": "一般", - "tabAgentDefaults": "サブエージェント設定", - "agentDefaultsDescription": "マルチエージェント連携が委任呼び出しのためにサブエージェントを起動するときに適用される上書き設定です。ここに表示されるオプションはライブプローブで取得しており、選択した内容がそのままエージェントに渡されます。", - "probing": "エージェントの利用可能な設定項目を読み込み中…", - "probeFailed": "設定項目の読み込みに失敗しました: {detail}", - "retry": "再試行", - "noConfigAvailable": "このエージェントには設定可能な項目がありません。", - "modeLabel": "モード", - "agentDefaultHint": "エージェント既定: {value}", - "defaultOptionLabel": "既定({value})" - }, - "actions": { - "dragSort": "ドラッグして並べ替え", - "dragSortAgent": "{name} をドラッグして並べ替え", - "refreshCheck": "再チェック", - "refreshCheckAgent": "{name} を再チェック", - "clickEnable": "{name} を有効化", - "clickDisable": "{name} を無効化", - "install": "インストール", - "upgrade": "アップグレード", - "uninstall": "アンインストール", - "uninstalling": "アンインストール中...", - "saveEnvVars": "環境変数を保存", - "saving": "保存中...", - "saveGrokConfig": "Grok 設定を保存", - "saveCodexConfig": "Codex設定を保存", - "saveGeminiConfig": "Gemini設定を保存", - "saveOpenCodeConfig": "OpenCode設定を保存", - "saveOpenClawConfig": "OpenClaw設定を保存", - "saveConfigManagement": "設定管理を保存", - "saveCurrentProvider": "現在のプロバイダーを保存", - "showApiKey": "APIキーを表示", - "hideApiKey": "APIキーを非表示", - "showKey": "キーを表示", - "hideKey": "キーを非表示", - "showToken": "トークンを表示", - "hideToken": "トークンを非表示", - "cancel": "キャンセル", - "delete": "削除", - "deleting": "削除中...", - "confirmDelete": "削除を確認", - "confirmUninstall": "アンインストールを確認", - "saveClineConfig": "Cline設定を保存", - "saveHermesConfig": "Hermes設定を保存", - "saveCodeBuddyConfig": "CodeBuddy 設定を保存", - "saveKimiCodeConfig": "Kimi Code の設定を保存", - "customInstall": "カスタムインストール", - "saveKimiCodeRawConfig": "Save config.toml", - "saveDeepSeekConfig": "DeepSeek 設定を保存", - "diagnose": "診断" - }, - "status": { - "enabled": "有効", - "disabled": "無効", - "unchecked": "未チェック", - "agentEnabledAria": "{name} は有効です", - "agentEnabledSwitch": "{name} 有効化スイッチ" - }, - "preflight": { - "count": "事前チェック項目: {count}", - "notRun": "チェックはまだ実行されていません。" - }, - "grok": { - "configDescription": "ここで Grok を設定します。以下のコントロール(権限モード、推論の強さ、任意のカスタム(独自エンドポイント)モデル、圧縮)は ~/.grok/config.toml にマージされ、他のキーやコメントは保持されます。サインインは XAI_API_KEY または `grok login` を使用します。その他のキーは「詳細」で編集できます。", - "permissionModeLabel": "権限モード", - "permissionDefault": "毎回確認", - "permissionAcceptEdits": "編集を自動承認", - "permissionAuto": "スマート自動承認", - "permissionAlwaysApprove": "常に許可", - "reasoningEffortLabel": "推論レベル", - "effortLow": "低(高速)", - "effortMedium": "中(バランス)", - "effortHigh": "高", - "effortXhigh": "最大", - "optionDefault": "デフォルトを使用", - "authTitle": "認証", - "authMode": "認証方式", - "authModeApiKey": "XAI API キー", - "authModeApiKeyHint": "xAI コンソールの XAI_API_KEY で認証します。非対話・ヘッドレス実行向けで、このエージェントの環境変数に保存されます。", - "authModeCustom": "カスタムエンドポイント", - "authModeCustomHint": "独自のエンドポイント(BYO)を使用します。下でベース URL と API キーを持つカスタムモデルを定義すると、それが Grok の既定モデルになります。", - "subscriptionHint": "`grok login` でサインインします(SuperGrok / X Premium+)。API キーは保存されません。", - "loginHint": "ターミナルで次のコマンドを実行してサインインし、この設定を開き直してください:", - "commandCopied": "コマンドをクリップボードにコピーしました", - "copyCommand": "コマンドをコピー", - "authKeyConfigured": "XAI_API_KEY が設定されています。", - "authKeyMissing": "XAI_API_KEY が未設定です。", - "advancedToggle": "詳細(生の config.toml)", - "configTomlNative": "config.toml(ネイティブ)", - "configTomlHint": "~/.grok/config.toml 全体としてそのまま書き込まれます。無効な TOML は拒否され、タイプミスでファイルが切り詰められることはありません。", - "configTomlPlaceholder": "# 上のコントロール以外のキー。例:\n# [mcp_servers.*]、[cli]、[permission] ルール。", - "customModelTitle": "カスタムモデル(独自エンドポイント)", - "customModelHint": "Grok をカスタムまたは自己ホストのエンドポイントに向けます。codeg はモデルごとの `[model.*]` ブロックを書き込み、既定モデルに設定します。モデル ID を空にすると削除されます。", - "customModelIdLabel": "モデル ID", - "customModelIdPlaceholder": "grok-4.5", - "customModelIdHint": "`[model.*]` ブロックとして登録され、モデル名として API に送信されます。`[models].default` にも設定されます。", - "customBaseUrlLabel": "Base URL", - "customBaseUrlPlaceholder": "https://api.x.ai/v1(既定)", - "customApiBackendLabel": "API バックエンド", - "backendResponses": "Responses", - "backendChatCompletions": "Chat Completions", - "backendMessages": "Messages(Anthropic)", - "customApiKeyLabel": "API キー", - "customApiKeyHint": "`[model.*].api_key` にインラインで保存され、このエンドポイントにのみ適用されます。", - "customContextWindowLabel": "コンテキストウィンドウ(トークン)", - "customContextWindowHint": "任意。自動圧縮のタイミングに使われます。空欄の場合はエンドポイントの既定値を使用します。", - "autoCompactLabel": "自動圧縮のしきい値(%)", - "autoCompactHint": "コンテキスト使用率がこの割合に達したら会話を圧縮します(Grok の既定は 85)。`[session]` に書き込まれます。" - }, - "cursor": { - "configDescription": "ここで Cursor を設定します。まず認証方式を選択し——公式サブスクリプション(ブラウザログイン)またはヘッドレス/サーバー用の Cursor API キー——次にモデルを選び、CLI の権限ルールとサンドボックスを編集します。codeg はこれらを ~/.cursor/cli-config.json に書き込み、cursor-agent CLI と共有します。", - "authTitle": "認証", - "authChecking": "確認中…", - "authNotInstalled": "cursor-agent が未インストールです", - "authLoggedIn": "ログイン済み", - "authNotLoggedIn": "未ログイン", - "loginHint": "ターミナルで次のコマンドを実行して Cursor アカウントにログイン(ブラウザが開きます)し、完了後に更新を押してください:", - "apiKeyLabel": "Cursor API キー", - "apiKeyPlaceholder": "cursor.com/dashboard で取得", - "apiKeyHint": "CURSOR_API_KEY —— Cursor ダッシュボードのアカウントキー。ヘッドレス/サーバー環境でブラウザログインの代わりに使用します。サードパーティや OpenAI のキーではありません。", - "modelTitle": "デフォルトモデル", - "loadModels": "モデル一覧を取得", - "modelsUnavailable": "モデル一覧を取得できません", - "modelHint": "セッション開始時に --model として CLI に渡されます。既定のままなら Cursor が選択します。", - "permissionsTitle": "権限とサンドボックス", - "permissionsDescription": "CLI の権限ルール(cli-config.json)のビジュアルエディタ。許可ルールは確認なしで実行、拒否ルールは常にブロックされます。", - "permissionModeLabel": "権限モード", - "permissionModeDefault": "実行前に確認(デフォルト)", - "permissionModeForce": "Run Everything(--force)", - "permissionModeHint": "Run Everything は --force でセッションを起動します:deny ルール以外のツール呼び出しはすべて確認なしで自動許可されます(組織ポリシーにより allow ルール一致のみに制限される場合があります)。新しいセッションから有効です。", - "optionDefault": "既定(未設定)", - "sandboxLabel": "サンドボックス", - "sandboxEnabled": "有効", - "sandboxDisabled": "無効", - "allowRulesLabel": "許可ルール", - "denyRulesLabel": "拒否ルール", - "addRule": "ルールを追加", - "rulesSyntaxHint": "ルール構文:Shell(コマンド)、Read(パス/グロブ)、Write(パス/グロブ)、WebFetch(ドメイン)、Mcp(サーバー:ツール)——deny ルールが常に優先されます。", - "saveConfig": "設定を保存", - "advancedToggle": "詳細:cli-config.json(生ファイル)", - "advancedHint": "~/.cursor/cli-config.json の全文です。ここでの保存はそのまま書き込み、上の構造化コントロールはマージして書き込みます。", - "saveRawConfig": "ファイルを保存", - "authMode": "認証方式", - "subscriptionHint": "Cursor アカウントでサインインし、Cursor のモデルを使用します。", - "customApiKeyRequired": "Cursor API キーが必要です。", - "authModeApiKey": "Cursor API キー(ヘッドレス/サーバー)", - "authModeApiKeyHint": "Cursor ダッシュボードで発行したアカウント API キーで認証します(ヘッドレス/サーバー環境向け)。これは Cursor アカウントのキーであり、サードパーティ/OpenAI エンドポイントではありません——cursor-agent は Cursor 自身のバックエンドにのみ接続します。codex/OpenAI 互換エンドポイントを使うには、代わりに Codex エージェントを使用してください。", - "modelPickerPlaceholder": "モデルを検索…", - "modelNoMatch": "一致するモデルがありません", - "modelsNeedAuth": "サインインするとモデル一覧を読み込みます。", - "modelDefaultBadge": "既定" - }, - "deepseek": { - "configManagement": "DeepSeek Harness の設定", - "configDescription": "エンドポイントと API キーは deepseek-acp が起動時に読み込む環境変数です。モデルと推論レベルはセッションごとのセレクターなので、入力欄で切り替えます。", - "baseUrlLabel": "API エンドポイント", - "baseUrlHint": "空欄なら公式エンドポイントを使います。保存後に開始したセッションから有効になります。実行中のセッションは再接続してください。", - "baseUrlInvalid": "クエリ文字列を含まない完全な http(s) URL を入力してください(例:https://api.deepseek.com)", - "apiKeyLabel": "API キー", - "apiKeyHint": "DEEPSEEK_API_KEY としてエージェントに渡されます。環境変数は認証情報ファイルより優先されるため、ターミナルでログインする場合は空のままにしてください。" - }, - "codex": { - "configDescription": "API URL、API Key、モデル名、reasoning effort を素早く設定でき、`auth.json` / `config.toml` と同期します。", - "authMode": "認証方式", - "chatgptSubscription": "公式サブスクリプション", - "chatgptSubscriptionHint": "ChatGPT 公式サブスクリプションでログイン、API Key 不要", - "apiKeyHint": "API Key で OpenAI または互換 API サービスに接続", - "selectProvider": "プロバイダーを選択", - "modelName": "モデル名", - "selectReasoningEffort": "Reasoning Effort を選択", - "enableWebsocket": "WebSocket を有効化", - "enableWebsocketAria": "Codex Provider の WebSocket を有効化", - "enableSkills": "Skills を有効化", - "enableSkillsAria": "Codex の Skills を有効化", - "enableFast": "Fast を有効化", - "enableFastAria": "Codex の Fast サービスティアを有効化", - "sandboxGroupTitle": "サンドボックスと承認", - "sandboxGroupHint": "グローバルの ~/.codex/config.toml に書き込むため、codex CLI や IDE のセッションにも反映されます。これはスレッドの既定値で、codex 自身が開始するターン(/goal、/review、/compact)にのみ適用されます。通常のプロンプトは入力欄の承認プリセットを使います。変更はセッションを再起動すると有効になります。", - "sandboxShadowedWarning": "config.toml に default_permissions が設定されているため、codex は権限プロファイル経由で解決し sandbox_mode を完全に無視します。以下の設定を使うには default_permissions を削除してください。", - "sandboxPermissionsTableWarning": "config.toml に [permissions] プロファイルがありますが default_permissions が未設定のため、codex は起動を拒否します。下の生エディタで設定してください。", - "approvalPolicyLabel": "承認ポリシー", - "approvalPolicyUnset": "未設定(codex の既定: 要求時)", - "approvalPolicy_on-request": "要求時 — モデルが確認のタイミングを判断", - "approvalPolicy_untrusted": "未信頼 — 安全と分かっている読み取り専用コマンドのみ自動実行", - "approvalPolicy_never": "確認しない — 承認プロンプトを一切出さない", - "approvalPolicy_granular": "詳細設定 — プロンプト種別ごとに指定", - "approvalPolicyUntrustedAcpWarning": "ACP アダプターの 3 つの承認プリセットに untrusted に相当するものはないため、codeg のセッションは「要求時」にフォールバックします。その場合はモデルが尋ねるタイミングを決め、サンドボックスが既に許可しているコマンドは確認されなくなります。代わりに下のサンドボックスモードで制限してください。", - "granularHint": "オフにすると、その種類の要求は表示されずに自動で拒否されます。", - "granular_sandbox_approval": "シェルコマンドの権限昇格", - "granular_rules": "Execpolicy ルールのプロンプト", - "granular_skill_approval": "スキルスクリプトのプロンプト", - "granular_request_permissions": "request_permissions ツールのプロンプト", - "granular_mcp_elicitations": "MCP elicitation のプロンプト", - "sandboxModeLabel": "サンドボックスモード", - "sandboxModeUnset": "未設定(信頼済みフォルダはワークスペース書き込みにフォールバック)", - "sandboxMode_read-only": "読み取り専用", - "sandboxMode_workspace-write": "ワークスペース書き込み", - "sandboxMode_danger-full-access": "フルアクセス(サンドボックスなし)", - "sandboxModeHint": "Windows では、codex の実験的 Windows サンドボックスが無効な場合、ワークスペース書き込みは読み取り専用に降格されます。", - "sandboxModeSeedsPresetHint": "codeg はこれをセッションの初期承認プリセットにも反映するため、承認ポリシーとは異なり通常のプロンプトにも効きます。入力欄のプリセットが指定されている場合はそちらが優先されます。", - "writableRootsLabel": "追加の書き込み可能フォルダ", - "writableRootsHint": "作業ディレクトリに加えて許可する絶対パスを 1 行に 1 つ。", - "sandboxRootsRelativeError": "絶対パスである必要があります — codex は相対パスを ~/.codex 基準で解決します: {path}", - "networkAccessLabel": "ネットワークアクセスを許可", - "excludeTmpdirLabel": "書き込み可能ルートから TMPDIR を除外", - "excludeSlashTmpLabel": "書き込み可能ルートから /tmp を除外", - "authJsonNative": "auth.json(ネイティブ)", - "configTomlNative": "config.toml(ネイティブ)", - "loginButton": "ChatGPT でログイン", - "loginRequesting": "ログインコードを取得中...", - "loginStep1": "ブラウザで以下の URL を開いてください:", - "loginStep2": "以下のコードを入力してください:", - "loginPolling": "認証を待っています...", - "loginCancel": "キャンセル", - "loginSuccess": "ログイン成功、設定を保存しました!", - "loginFailed": "ログインに失敗しました:{message}", - "loginRetry": "再試行", - "loginCodeCopied": "コードをコピーしました", - "loggedIn": "アカウントにログイン済み", - "loginRelogin": "再ログイン / アカウント切替", - "loginTimeout": "ログインがタイムアウトしました。再試行してください", - "loginSaveFailed": "ログインは成功しましたが、設定の保存に失敗しました" - }, - "gemini": { - "authConfig": "Gemini 認証設定", - "authConfigDescription": "Gemini CLI の認証ドキュメントに準拠し、カスタムエンドポイント、Google ログイン、Gemini API Key、Vertex AI(ADC / サービスアカウント / API Key)をサポートします。", - "authMode": "認証モード", - "selectAuthMode": "認証モードを選択", - "viewAuthDoc": "認証ドキュメントを見る", - "mode": { - "custom": "カスタムエンドポイント", - "loginGoogle": "Google ログイン(OAuth)", - "vertexServiceAccount": "Vertex AI(サービスアカウント)" - }, - "hint": { - "custom": "API URL、API Key、Model を入力してください。GOOGLE_GEMINI_BASE_URL / GEMINI_API_KEY / GEMINI_MODEL に対応します。", - "loginGoogle": "先にターミナルで gemini を実行して Google ログインを完了してください。API key は不要です。", - "geminiApiKey": "Gemini API を使う場合は GEMINI_API_KEY を入力してください。", - "vertexAdc": "gcloud ADC を使用します。GOOGLE_CLOUD_PROJECT と GOOGLE_CLOUD_LOCATION の設定を推奨します。", - "vertexServiceAccount": "サービスアカウント JSON のパスを GOOGLE_APPLICATION_CREDENTIALS に設定してください。", - "vertexApiKey": "Vertex AI API key を使う場合は GOOGLE_API_KEY を入力してください。" - } - }, - "openCode": { - "configManagement": "OpenCode 設定管理", - "configDescription": "OpenCode の `provider` スキーマに準拠し、複数プロバイダー管理とネイティブ JSON ファイルとの双方向同期をサポートします。", - "providerManagement": "プロバイダー管理", - "providerCount": "{count} 個のプロバイダー", - "addProvider": "プロバイダーを追加", - "emptyProvider": "カスタムプロバイダーはまだありません。「カスタムプロバイダーを追加」をクリックして作成してください。", - "providerEnabledState": "{providerId} の有効状態", - "selectProviderNpm": "provider.npm を選択", - "modelManagement": "モデル管理", - "modelCount": "{count} 個のモデル", - "modelDescription": "OpenCode の `provider.models` に準拠。高速管理では現在 `name` / `id` をサポートし、その他の高度な項目は保持され、下部のネイティブ JSON で編集できます。", - "addModel": "モデルを追加", - "emptyModel": "まだモデルがありません。model id を入力して「モデルを追加」をクリックしてください。", - "modelId": "モデル ID", - "modelName": "モデル名", - "deleteModel": "モデル {modelId} を削除", - "nativeJsonConfig": "OpenCode ネイティブ JSON 設定", - "mainModel": "メインモデル", - "smallModel": "スモールモデル", - "noMatchingModels": "一致するモデルがありません", - "connectProvider": "プロバイダーを接続", - "connectedProviders": "接続済みプロバイダー", - "noConnectedProviders": "カタログのプロバイダーはまだ接続されていません。", - "advancedProviderConfig": "カスタムプロバイダー", - "customProviderConfigHint": "自分で定義する OpenAI 互換エンドポイント——opencode.json の provider ブロックで、API キーは auth.json に保存されます。", - "addCustomProvider": "カスタムプロバイダーを追加", - "disconnect": "切断", - "editConfig": "編集", - "customBadge": "カスタム", - "authKindApi": "API キー", - "authKindOauth": "OAuth", - "authKindNone": "認証情報なし", - "connect": { - "title": "プロバイダーを接続", - "description": "models.dev カタログからプロバイダーを選択します。認証情報は OpenCode の auth.json に保存されます。", - "pick": "プロバイダー", - "search": "プロバイダーを検索…", - "loading": "カタログを読み込み中…", - "catalogLabel": "models.dev カタログ", - "modelsAvailable": "{count} 個のモデルが利用可能", - "getKey": "API キーを取得", - "oauthApiKeyNote": "このプロバイダーは opencode auth login によるブラウザサインインにも対応しています。ブラウザサインインは近日対応予定です。今は API キーを貼り付けてください。", - "apiKey": "API キー", - "apiKeyHint": "auth.json に保存され、opencode.json には書き込まれません。", - "baseUrlOptional": "Base URL の上書き(任意)", - "providerId": "プロバイダー ID", - "displayName": "表示名", - "modelsList": "モデル(1 行に 1 つ)", - "modelsHint": "エンドポイントが受け付けるモデル ID。", - "action": "接続", - "editTitle": "プロバイダーを編集", - "editDescription": "このプロバイダーの API キーまたは Base URL を更新します。", - "saveAction": "保存" - }, - "customProvider": { - "title": "カスタムプロバイダーを追加", - "description": "OpenAI 互換エンドポイントを定義します。API キーは auth.json に、provider ブロックは opencode.json に保存されます。", - "action": "プロバイダーを追加", - "idInCatalog": "{providerId} は既知のプロバイダーです。「プロバイダーを接続」から接続してください。" - }, - "refreshCatalog": "カタログを更新", - "reasoningBadge": "推論", - "contextWindow": "コンテキストウィンドウ", - "permissions": { - "title": "権限", - "description": "どの操作をそのまま実行し、確認を求め、あるいはブロックするかを決めます。opencode.json の permission 設定に書き込まれ、下の保存で反映されます。", - "docsLink": "権限のドキュメント", - "unparsableConfig": "下のネイティブ JSON が解析できないため、ビジュアル編集を停止しています。JSON を修正すると再開します。", - "invalidBlock": "permission 設定の形式を認識できません。下のネイティブ JSON で編集するか、「リセット」でやり直してください。", - "orderingUnsafe": "ワイルドカードのルールが個別のツールより後に書かれているため、OpenCode はそれらにも適用します。下の各行は実際に有効な設定ではありません。「順序を修正」は値を変えずに、各スコープの先頭へワイルドカードを戻すだけです。", - "orderingUnsafeManual": "あるルールが後方のより広いパターンに隠されており、OpenCode は決して適用しません。下の各行は実際に有効な設定ではありません。重なり合う 2 つのパターンに唯一の正しい順序はないため、下のネイティブ JSON で広いほうを先に並べ替えてください。", - "fixOrder": "順序を修正", - "agentOverrides": "次のエージェントは権限を個別に上書きしており、最後に適用されるためここの設定より優先されます: {agents}。下のネイティブ JSON で編集するか、自動承認をオンにして削除してください。", - "legacyTools": "トップレベルの旧 tools 設定がツールを拒否しています。OpenCode はこれを権限に統合するため、ここに表示されている設定すべての上に適用されます。下のネイティブ JSON で編集するか、自動承認をオンにして削除してください。", - "autoAcceptTitle": "すべての権限を自動承認", - "autoAcceptHint": "シェルコマンド、ファイル編集、プロジェクト外のパスを含むすべてのツール呼び出しを確認なしで実行します。オンにすると、下のツール別設定は 1 つの全許可ルールに置き換わり、そのままではブロックし続けるエージェントごとの権限の上書きと旧 tools 設定も削除されます。", - "globalLabel": "全体のデフォルト", - "globalHint": "* ルールです。下のツールで上書きされていないものすべてに適用されます。", - "actionUnset": "未設定(OpenCode のデフォルト)", - "actionInherit": "デフォルトに従う({action})", - "actionAllow": "許可", - "actionAsk": "確認する", - "actionDeny": "拒否", - "perToolTitle": "ツール別の権限", - "reset": "リセット", - "ruleCount": "ルール: {count}", - "rulesToggle": "{tool} の詳細ルール", - "rulesHint": "ツールの入力に対して照合し、最後に一致したルールが優先されます。広いパターンを先に書いてください。* は任意の文字列、? はちょうど 1 文字に一致し、先頭の ~ はホームディレクトリに展開されます。", - "noRules": "詳細ルールはまだありません。", - "addRule": "ルールを追加", - "deleteRule": "ルール {pattern} を削除", - "duplicateRule": "そのパターンは既に存在します。", - "blankRule": "ルールにはパターンが必要です。削除するにはゴミ箱アイコンを使ってください。", - "customKeys": "ファイル内のその他の権限キー", - "customKeyHint": "OpenCode の組み込みツールではありません。記述どおり保持されます。", - "keys": { - "bash": "シェルコマンドの実行。解析後のコマンドで照合", - "edit": "ファイルへのすべての変更(edit・write・patch)", - "read": "ファイルの読み取り。パスで照合", - "external_directory": "プロジェクトの作業ディレクトリ外のパスへのアクセス", - "task": "サブエージェントの起動。サブエージェントの種類で照合", - "skill": "スキルの読み込み。スキル名で照合", - "glob": "ファイル検索。グロブパターンで照合", - "grep": "ファイル内容の検索。パターンで照合", - "list": "ディレクトリ内容の一覧表示", - "webfetch": "URL の取得", - "websearch": "ウェブ検索", - "lsp": "LSP クエリの実行", - "todowrite": "TODO リストの書き込み", - "question": "あなたへの質問", - "doom_loop": "同じ入力で同じ呼び出しが 3 回繰り返されたときに作動" - } - } - }, - "openClaw": { - "gatewayConfig": "Gateway 設定", - "gatewayDescription": "OpenClaw Gateway 接続を設定します。ローカルまたはリモートの gateway をサポートします。", - "gatewayUrlHint": "空欄の場合はローカル openclaw 設定の gateway.remote.url を使用します。", - "gatewayTokenPlaceholder": "Gateway 認証トークン", - "gatewayTokenHint": "可能な場合は平文トークンではなく token-file の使用を推奨します。openclaw CLI で設定してください。", - "sessionKeyHint": "任意。gateway の session key を指定します。空欄の場合は分離されたセッションが自動割り当てされます。" - }, - "hermes": { - "configManagement": "Hermes 設定", - "configDescription": "Hermes は認証情報を ~/.hermes/.env に、設定を ~/.hermes/config.yaml に独自に管理します。プロバイダーを選択し、API キーとモデルを設定してください。codeg が両方のファイルを書き込みます。", - "providerLabel": "プロバイダー", - "providerHint": "プロバイダーによって、Hermes が使用する API キー変数と model.provider が決まります。OAuth プロバイダーは下のターミナルセットアップから設定します。", - "groupApiKey": "API キー プロバイダー", - "groupOauth": "OAuth プロバイダー", - "groupAws": "AWS", - "apiKeyHint": "~/.hermes/.env に保存されます。プロセスには注入されません。Hermes が独自の設定から読み取ります。", - "modelName": "モデル", - "oauthHint": "このプロバイダーは OAuth を使用します。下のセットアップを実行し、ターミナルで認証してください。", - "awsHint": "Bedrock は AWS の認証情報(環境変数または共有設定)を使用します。上でモデル ID を設定し、環境で AWS アクセスを構成してください。", - "unsupportedProvider": "このプロバイダーは構造化フィールドでは編集できません。下の config.yaml 直接編集またはターミナルセットアップを使用してください。", - "setupTitle": "自己管理セットアップ", - "setupHint": "Hermes の対話型セットアップにはターミナルが必要です。下から起動するか、コマンドをコピーして自分で実行してください。", - "runSetup": "Hermes セットアップを実行", - "configureModel": "モデルを設定", - "openConfigFolder": "~/.hermes を開く", - "copyCommand": "コマンドをコピー", - "commandCopied": "コマンドをクリップボードにコピーしました", - "advancedTitle": "詳細: config.yaml を編集", - "rawConfigHint": "~/.hermes/config.yaml を直接編集します。ここで保存すると、ファイルがそのまま上書きされます。", - "saveRawConfig": "config.yaml を保存" - }, - "codebuddy": { - "configManagement": "CodeBuddy の設定", - "configDescription": "CodeBuddy は API キーで認証します。中国版では環境を「中国版(internal)」に設定する必要があります。iOA 版は「iOA」を使用し、海外版は未設定のままにします。", - "apiKeyLabel": "API キー", - "apiKeyHint": "このエージェントの CODEBUDDY_API_KEY として保存されます。または、ターミナルで CodeBuddy CLI からサインインすることもできます。", - "apiKeyHintSelfHosted": "このエージェントの CODEBUDDY_API_KEY として保存されます。プライベート展開で発行されたキーを使用してください。", - "environmentLabel": "環境", - "environmentHint": "CODEBUDDY_INTERNET_ENVIRONMENT を設定します。中国本土では「中国版(internal)」を使用する必要があります。海外版は未設定のままにします。", - "envOverseas": "海外版(デフォルト)", - "envChina": "中国版(internal)", - "envIoa": "iOA", - "envSelfHosted": "プライベート展開(セルフホスト)", - "baseUrlLabel": "デプロイ URL", - "baseUrlPlaceholder": "https://codebuddy.your-company.com", - "baseUrlHint": "CODEBUDDY_BASE_URL として保存され、CodeBuddy をプライベートエンドポイントに向けます。セルフホストではネットワーク環境(CODEBUDDY_INTERNET_ENVIRONMENT)は設定しません。", - "baseUrlInvalid": "有効な http(s) URL を入力してください。", - "loginHint": "API キーがない場合は、ターミナルで「codebuddy」を実行して Tencent アカウントでサインインすることもできます。" - }, - "kimiCode": { - "configManagement": "Kimi Code の設定", - "configDescription": "`kimi acp` は保存済みのログイントークンしか受け付けないため、codeg は ~/.kimi-code/config.toml に管理対象プロバイダーを書き込み、ローカルにゲートトークンを配置します。推論は引き続きご自身のキーで実行されます。", - "statusUnconfigured": "未設定", - "statusDirty": "未保存の変更あり", - "summaryLabel": "有効な設定", - "gateReadyApiKey": "API キーを config.toml に書き込み済み", - "gateReadyLogin": "Kimi アカウントでログイン済み", - "revealConfig": "フォルダーで表示", - "envOverrideWarning": "{keys} が設定されており、config.toml より優先されます。ここで保存すると自動的に削除されます。", - "authModeLabel": "認証方式", - "authModeApiKey": "API キー", - "authModeLogin": "Kimi アカウントログイン(サブスクリプション)", - "authModeApiKeyHint": "config.toml に管理対象プロバイダーを書き込み、セッションを開けるようゲートトークンを配置します。", - "loginHint": "ターミナルで `kimi login` を実行し、Kimi サブスクリプションアカウントでログインしてください。codeg は資格情報を保存せず、Kimi 自身のログインを再利用します。ここで保存すると codeg の API キー用ゲートトークンが削除されます。", - "credentialTitle": "資格情報", - "interfaceTypeLabel": "プロバイダー種別", - "interfaceTypeHint": "Kimi が話すプロバイダープロトコル(config.toml の `type`)。Moonshot / platform.kimi.com のキーには「Kimi / Moonshot」を選びます。", - "endpointLabel": "エンドポイント", - "endpointCustom": "カスタム(OpenAI 互換)", - "endpointHint": "国際 = api.moonshot.ai、中国(platform.kimi.com のキー)= api.moonshot.cn。カスタムは任意の OpenAI 互換エンドポイントを指定できます。", - "regionInternational": "国際(api.moonshot.ai)", - "regionChina": "中国(api.moonshot.cn)", - "baseUrlLabel": "Base URL", - "baseUrlHint": "空欄の場合はプロバイダー SDK の既定値を使用します。", - "apiKeyLabel": "API キー", - "apiKeyHint": "~/.kimi-code/config.toml に書き込まれ、推論に使用されます。platform.kimi.com または platform.kimi.ai で取得できます。", - "vertexProjectLabel": "GCP プロジェクト(GOOGLE_CLOUD_PROJECT)", - "vertexLocationLabel": "GCP リージョン(GOOGLE_CLOUD_LOCATION)", - "vertexHint": "Vertex AI は Google のアプリケーションデフォルト認証情報を使用します。`gcloud auth application-default login` を実行してください(API キー不要)。", - "modelTitle": "モデル", - "modelLabel": "モデル", - "modelHint": "config.toml に書き込まれるモデル id。「テストしてモデルを取得」でキーが実際にアクセスできるモデルを確認できます。", - "maxContextLabel": "最大コンテキスト長", - "maxContextHint": "Kimi のスキーマ上必須です。未指定だと Kimi がモデルブロック全体を破棄し、どのプロンプトも応答が返らなくなります。既定値は 262144。", - "fetchModels": "テストしてモデルを取得", - "fetchModelsOk": "キーは有効です — {count} 件のモデルが利用可能", - "fetchModelsEmpty": "キーは有効ですが、モデルが返されませんでした", - "fetchModelsFailed": "テストに失敗しました", - "fetchModelsNeedsKey": "先に API キーとエンドポイントを入力してください", - "modelNotInList": "このモデルはキーがアクセスできる一覧に含まれていません。Kimi は「モデルが見つかりません」で失敗します。", - "reasoningTitle": "推論", - "reasoningEnableLabel": "有効にする", - "reasoningDescription": "モデルが推論機能を宣言している場合にのみ Kimi は入力欄に「Thinking」ピッカーを表示するため、その宣言を codeg がここで書き込みます。新しいセッションから有効になります。", - "effortsLabel": "選択できるレベル", - "effortsHint": "ここで選んだ値が入力欄の「Thinking」ピッカーの項目になります。Kimi はレベルをそのままプロバイダーへ渡すので、モデルが受け付ける値を選んでください。", - "effortsEmptyHint": "レベルを 1 つも選ばない場合、入力欄は Off / On の 2 段トグルに退化します。", - "effortsCustomPlaceholder": "他のレベルを追加", - "effortsAdd": "追加", - "defaultEffortLabel": "既定のレベル", - "defaultEffortAuto": "Kimi に任せる", - "alwaysThinkingLabel": "モデルは常に推論する — ピッカーから Off を削除", - "fixErrorsFirst": "先に赤色の項目を修正してください", - "errorModelRequired": "モデルは必須です", - "errorMaxContextRequired": "最大コンテキスト長は必須です", - "errorMaxContextInvalid": "正の整数を入力してください", - "errorApiKeyRequired": "API キーは必須です", - "errorApiKeyInvalid": "API キーに改行を含めることはできません", - "errorBaseUrlRequired": "Base URL は必須です", - "errorBaseUrlInvalid": "http:// または https:// で始める必要があります", - "errorVertexProjectRequired": "GCP プロジェクトは必須です", - "errorDefaultEffortUnlisted": "上で選択したレベルのいずれかを指定してください", - "advancedTitle": "詳細設定", - "authTypeLabel": "資格情報の書き込み先", - "authTypeApiKey": "インライン api_key", - "authTypeEnv": "プロバイダーの env サブテーブル", - "authTypeHint": "config.toml 内で API キーを書き込む場所。", - "rawEditorLabel": "config.toml を直接編集", - "rawEditorWarning": "ここで保存するとファイル全体がそのまま上書きされ、上の構造化設定が置き換えられます。", - "rawEditorPlaceholder": "[providers.codeg]\ntype = \"kimi\"\nbase_url = \"https://api.moonshot.cn/v1\"\napi_key = \"sk-...\"" - }, - "authModeOfficialSubscription": "公式サブスクリプション", - "authModeCustomEndpoint": "カスタムエンドポイント", - "authModeCustomEndpointHint": "API URL と API Key を手動で設定してカスタムエンドポイントに接続します。", - "authModeModelProvider": "モデルプロバイダー", - "modelProvider": "モデルプロバイダー", - "modelProviderHint": "設定済みモデルプロバイダーの API URL、API Key、モデルを使用します。", - "selectModelProvider": "モデルプロバイダーを選択", - "noModelProviderAvailable": "このエージェントにはモデルプロバイダーが設定されていません。モデルプロバイダー設定で追加してください。", - "claude": { - "authMode": "認証方式", - "officialSubscription": "公式サブスクリプション", - "officialSubscriptionHint": "Anthropic 公式サブスクリプションを使用、API Key 不要。", - "mainModel": "メインモデル", - "reasoningModel": "推論モデル(thinking)", - "haikuDefaultModel": "デフォルト Haiku モデル", - "sonnetDefaultModel": "デフォルト Sonnet モデル", - "opusDefaultModel": "デフォルト Opus モデル", - "customModelOption": "カスタムモデル ID", - "customModelOptionName": "カスタムモデル名", - "customModelOptionDescription": "カスタムモデルの説明", - "customModelOptionHint": "Claude のモデル選択メニューにカスタム項目を1つ追加します(例: カスタムゲートウェイ/プロキシ経由のモデル)。名前と説明は任意の表示用設定です。", - "effortLevel": "推論レベル", - "effortLevelDefault": "デフォルトレベル", - "effortLevel_low": "低", - "effortLevel_medium": "中", - "effortLevel_high": "高", - "effortLevel_xhigh": "超高", - "sendAttributionHeader": "API に帰属/課金識別子を送信", - "sendAttributionHeaderAria": "API に Claude Code の帰属/課金識別子を送信", - "disableNonessentialTraffic": "テレメトリや不要なネットワークリクエストを無効化", - "disableNonessentialTrafficAria": "Claude Code のテレメトリや不要なネットワークリクエストを無効化" - }, - "dialogs": { - "confirmDeleteProvider": "Provider {providerId} を削除しますか?", - "confirmDeleteProviderDescription": "OpenCode config と auth JSON は同時に更新されます。この操作は元に戻せません。", - "confirmUninstall": "{name} をアンインストールしますか?", - "confirmUninstallDescription": "ローカルにインストールされたバージョンを削除します。後で再インストールできます。", - "customInstallTitle": "{name} をカスタムインストール", - "customInstallDescription": "インストールするバージョンを入力します。再インストールされ、現在インストールされているバージョンを置き換えます。", - "customInstallVersionLabel": "バージョン番号", - "customInstallInvalid": "有効なバージョン番号を入力してください(例: 1.2.3)。", - "customInstallSubmit": "インストール" - }, - "errors": { - "windowsFileLocked": "{name} のファイルは実行中のセッションが使用中のため、Windows では置き換えられません。{name} のセッションをすべて終了してから再試行してください。", - "nativeJsonMustBeObject": "ネイティブJSON設定はオブジェクトである必要があります", - "nativeJsonInvalid": "ネイティブJSON設定の形式エラー: {message}", - "openCodeAuthMustBeObject": "OpenCode の auth.json はJSONオブジェクトである必要があります", - "openCodeAuthInvalid": "OpenCode の auth.json 形式エラー: {message}", - "authMustBeObject": "auth.json はJSONオブジェクトである必要があります", - "authInvalid": "auth.json 形式エラー: {message}", - "providerIdPattern": "Provider ID は英字・数字・アンダースコア・ドット・ハイフンのみ使用できます", - "providerExists": "Provider {providerId} はすでに存在します", - "modelIdPattern": "Model ID は英字・数字・アンダースコア・ドット・コロン・ハイフンのみ使用できます", - "modelExists": "Model {modelId} はすでに存在します" - }, - "warnings": { - "nativeJsonRecoveredStructured": "ネイティブJSON設定が不正のため、構造化設定にリセットしました", - "nativeJsonRecoveredOpenCode": "ネイティブJSON設定が不正のため、OpenCode構造化設定にリセットしました", - "openCodeAuthRecovered": "OpenCode の auth.json が不正のため、デフォルト設定にリセットしました", - "authRecoveredStructured": "auth.json が不正のため、構造化設定にリセットしました" - }, - "toasts": { - "agentActionCompleted": "{name} の {action} が完了しました", - "agentActionFailed": "{name} の {action} に失敗しました", - "localVersion": "ローカルバージョン: {version}", - "installCompletedVersionLater": "インストールが完了しました。バージョンは次回チェック時に更新されます", - "uninstallCompleted": "{name} のアンインストールが完了しました", - "uninstallFailed": "{name} のアンインストールに失敗しました", - "localVersionRemoved": "ローカルバージョンを削除しました", - "saveAgentOrderFailed": "Agent の並び順の保存に失敗しました", - "saveAgentSwitchFailed": "Agent の有効スイッチ保存に失敗しました", - "saveEnvFailed": "環境変数の保存に失敗しました", - "grokSaved": "Grok 設定を保存しました", - "saveGrokNativeFailed": "Grok のネイティブ設定の保存に失敗しました", - "saveGrokApiKeyFailed": "設定は保存されましたが、API キーを保存できませんでした", - "cursorSaved": "Cursor の設定を保存しました", - "saveCursorConfigFailed": "Cursor の設定の保存に失敗しました", - "codexSaved": "Codex設定を保存しました", - "saveCodexNativeFailed": "Codexネイティブ設定の保存に失敗しました", - "geminiSaved": "Gemini設定を保存しました", - "saveGeminiFailed": "Gemini設定の保存に失敗しました", - "providerDeleted": "Provider {providerId} を削除しました", - "providerDeleteFailed": "Provider {providerId} の削除に失敗しました", - "providerSaved": "Provider {providerId} を保存しました", - "saveProviderFailed": "Provider {providerId} の保存に失敗しました", - "openCodeConfigSynced": "OpenCode config と auth JSON が同期されました。", - "openCodeSaved": "OpenCode設定を保存しました", - "saveOpenCodeFailed": "OpenCode設定の保存に失敗しました", - "openClawSaved": "OpenClaw設定を保存しました", - "saveOpenClawFailed": "OpenClaw設定の保存に失敗しました", - "configSaved": "設定を保存しました", - "configSavedHint": "既存のセッションは再度開く必要があります", - "saveConfigManagementFailed": "設定管理の保存に失敗しました", - "clineSaved": "Cline設定を保存しました", - "saveClineFailed": "Cline設定の保存に失敗しました", - "hermesSaved": "Hermes設定を保存しました", - "saveHermesFailed": "Hermes設定の保存に失敗しました", - "codeBuddySaved": "CodeBuddy の設定を保存しました", - "saveCodeBuddyFailed": "CodeBuddy の設定の保存に失敗しました", - "kimiCodeSaved": "Kimi Code の設定を保存しました", - "saveKimiCodeFailed": "Kimi Code の設定の保存に失敗しました", - "deepseekSaved": "DeepSeek の設定を保存しました", - "saveDeepSeekFailed": "DeepSeek の設定の保存に失敗しました", - "modelProviderRequired": "保存する前にモデルプロバイダーを選択してください。", - "affectedRunningSessions": "{count} 件の実行中セッションは再接続すると変更が適用されます", - "providerConnected": "{providerId} を接続しました", - "connectFailed": "{providerId} の接続に失敗しました", - "providerDisconnected": "{providerId} を切断しました", - "disconnectFailed": "{providerId} の切断に失敗しました", - "catalogRefreshed": "カタログを更新しました — {count} 個のプロバイダー", - "catalogRefreshFailed": "カタログの更新に失敗しました", - "piSaved": "Pi 設定を保存しました", - "savePiFailed": "Pi 設定の保存に失敗しました", - "piRuntimeSaved": "Pi ランタイムを保存しました", - "savePiRuntimeFailed": "Pi ランタイムの保存に失敗しました", - "piBinaryInstalled": "pi をインストールしました", - "piBinaryInstallFailed": "pi のインストールに失敗しました", - "piBinaryUninstalled": "pi をアンインストールしました", - "piBinaryUninstallFailed": "pi のアンインストールに失敗しました", - "savePiTrustFailed": "ワークスペースの信頼設定の保存に失敗しました" - }, - "version": { - "statusLabel": "バージョン状態", - "notInstalled": "未インストール", - "remoteLocal": "リモート: {remoteVersion} · ローカル: {localVersion}", - "localOnly": "ローカル:{localVersion}", - "localInstalled": "{versionText}。インストール済みです。", - "platformUnsupported": "{versionText}。現在のプラットフォームではこのエージェントをサポートしていません。", - "uvxNotReady": "{versionText}。uv ランタイムが未インストールです。下の uv チェックからインストールするとこのエージェントを使用できます。", - "clickInstall": "{versionText}。右側の「インストール」をクリックしてください。", - "localUnrecognized": "{versionText}。ローカルバージョンは比較できません。上書きインストールのためアップグレードを試してください。", - "upgradeAvailable": "{versionText}。アップグレード可能です。", - "remoteUnavailable": "{versionText}。現在リモートバージョンは取得できません。", - "latest": "{versionText}。すでに最新です。" - }, - "adapter": { - "label": "ACP アダプター", - "badge": "ACP アダプター", - "badgeHint": "このエージェントで Codeg がインストールするのはベンダー CLI ではなく ACP アダプターのパッケージです。両者は独立しており、設定は共有されます。", - "learnMore": "詳細", - "missingWithNative": "お使いの {nativeLabel} を {nativePath} で検出しました。Codeg はエージェントを ACP で駆動しますが、この CLI 自体は ACP に対応していないため、別パッケージのアダプター {adapterPackage}(Agent Client Protocol プロジェクトが保守。当初は Zed チーム)が必要です。独自のランタイムを同梱しており、既存の {nativeCmd} コマンドを変更も置き換えもしません。読み込む設定は同じ {configDir} なので、ログインと設定はそのまま引き継がれます。下のボタンからインストールしてください。", - "missing": "Codeg はエージェントを ACP で駆動しますが、{nativeLabel} 自体は ACP に対応していないため、別パッケージのアダプター {adapterPackage}(Agent Client Protocol プロジェクトが保守。当初は Zed チーム)が必要です。独自のランタイムを同梱しているので {nativeCmd} CLI を先に入れる必要はありません。すでにお持ちの場合も両者は共存し、{configDir} のログインと設定を共有します。下のボタンからインストールしてください。", - "readyWithNative": "アダプター {adapterCmd} はインストール済みです。Codeg が起動するのはこちらで、あなたの {nativeCmd}({nativePath})ではありません。両者は独立したパッケージとして共存し、どちらも {configDir} を読むためログインと設定は共有されます。", - "ready": "アダプター {adapterCmd} はインストール済みで、Codeg が起動するのはこれです。独自のランタイムを同梱しているため {nativeLabel} は不要です。後から入れても両者は共存し、{configDir} を共有します。" - }, - "cline": { - "configDescription": "Cline API プロバイダーと認証情報を設定します。設定は ~/.cline/data/ に保存されます。" - }, - "opencodePlugins": { - "title": "OpenCode プラグイン", - "declared": "宣言済みプラグイン", - "noPlugins": "opencode.json にプラグインが宣言されていません", - "status": { - "installed": "インストール済み", - "missing": "未インストール" - }, - "installAll": "不足プラグインをすべてインストール", - "pinVersions": "@latest バージョンを固定", - "install": "インストール", - "uninstall": "アンインストール", - "refresh": "更新", - "success": "すべてのプラグインが正常にインストールされました", - "failed": "プラグイン操作に失敗しました" - }, - "pi": { - "configManagement": "Pi 設定", - "configDescription": "Pi はモデルプロバイダーの API キーで認証します。キーは ~/.pi/agent/auth.json に、モデル選択は settings.json に書き込まれます。", - "providerLabel": "プロバイダー", - "modelLabel": "モデル", - "thinkingLabel": "思考", - "thinking": { - "off": "オフ", - "low": "低", - "medium": "中", - "high": "高", - "minimal": "最小", - "xhigh": "最高" - }, - "apiKeyLabel": "API キー", - "apiKeyHint": "選択したプロバイダーの ~/.pi/agent/auth.json に保存されます。", - "apiKeySetPlaceholder": "••••••(保存済み・空欄で維持)", - "saveConfig": "Pi 設定を保存", - "providerModelRequired": "プロバイダーとモデルは必須です", - "runtimeTitle": "ランタイム", - "runtimeDescription": "どの pi を実行するか選択します。デフォルト、または自分の pi ビルドを指定します。", - "modeDefault": "デフォルト pi", - "modeDefaultHint": "内蔵の pi-acp アダプターで PATH 上の pi を起動します。 pi のインストール:npm install -g @earendil-works/pi-coding-agent", - "modeCustom": "カスタム pi", - "modeCustomHint": "自分の pi ビルド・インストール・ラッパーを実行します。", - "commandLabel": "pi コマンドまたはパス", - "commandHint": "絶対パス、PATH 上のコマンド名、またはラッパースクリプト(例: monorepo の ./pi-test.sh)。", - "commandNotFound": "コマンドが見つかりません", - "validate": "検証", - "advanced": "詳細設定", - "configDirLabel": "設定ディレクトリ (PI_CODING_AGENT_DIR)", - "sessionDirLabel": "セッションディレクトリ (PI_CODING_AGENT_SESSION_DIR)", - "flagsHint": "pi-acp はカスタム pi フラグ(--approve、-e など)を転送しません。pi をスクリプトでラップしてコマンドに指定してください。", - "customIncomplete": "保存するには pi コマンドを入力してください", - "saveRuntime": "ランタイムを保存", - "providerPlaceholder": "プロバイダーを選択", - "customProvider": "カスタムプロバイダー…", - "providerIdLabel": "プロバイダー ID", - "apiProtocolLabel": "API プロトコル", - "baseUrlLabel": "API エンドポイント(Base URL)", - "customProviderHint": "~/.pi/agent/models.json にエンドポイント向けのプロバイダーを定義します。多くのセルフホスト/プロキシは openai-completions を使用します。", - "baseUrlRequired": "API エンドポイント(Base URL)は必須です", - "binaryTitle": "pi バイナリ (pi-coding-agent)", - "binaryDescription": "pi-acp はこの pi バイナリを実行します。ここでインストールするか、下で独自のビルドを指定できます。", - "binaryInstalled": "インストール済み", - "binaryMissing": "未インストール", - "binaryChecking": "確認中…", - "installBinary": "pi をインストール", - "installing": "インストール中…", - "recheck": "再確認", - "configDirSkillsNote": "カスタム設定ディレクトリを指定すると、設定画面で管理するスキル・エキスパート・オフィスツールはこの pi に適用されません。スキルはそのフォルダー内で直接管理してください。", - "projectTrustTitle": "プロジェクトの信頼", - "projectTrustDescription": "pi にプロジェクトファイルの読み込みを許可したフォルダーです。信頼したフォルダーでは、そのリポジトリの .pi/extensions が pi の起動時にコードを実行します。配下のすべてのフォルダーに適用され、ターミナルで pi を実行するときにも使われます。", - "projectTrustLoading": "読み込み中…", - "projectTrustEmpty": "まだ判断したフォルダーはありません。", - "projectTrustTrusted": "信頼済み", - "projectTrustDenied": "信頼しない", - "projectTrustRevoke": "取り消す", - "reasoningTitle": "推論", - "reasoningEnableLabel": "有効にする", - "reasoningDescription": "モデルが推論能力を宣言している場合にのみ、pi は推論強度を送信します。未宣言のモデルではすべてのレベルが Off に丸められるため、入力欄のセレクターは触れた瞬間に戻ってしまいます。models.json のこのモデルの項目に書き込まれます。", - "levelsLabel": "選択できるレベル", - "levelsHint": "入力欄の推論セレクターの項目になります。エンドポイントが受け付ける値を選んでください。ここにないレベルは pi が拒否します。", - "levelsEmptyError": "レベルを 1 つ以上選んでください。1 つも選ばないと pi は Off に戻ります。", - "wireValuesTitle": "詳細: プロバイダーに送る値", - "wireValuesHint": "空欄ならレベル名をそのまま送信します。エンドポイントが別の表記を求める場合のみ設定してください(Google 系は LOW / HIGH)。", - "defaultLevelUnlisted": "このレベルは上の選択リストにありません。pi が丸めてしまいます。" - }, - "addCustomAgent": "カスタムエージェントを追加", - "addCustomAgentHint": "ACP 対応のエージェントを追加できます。公開 ACP レジストリから選ぶか、レジストリ情報を貼り付けてください。", - "customAgentFromRegistry": "ACP レジストリ", - "customAgentManual": "手動入力", - "customAgentSearchPlaceholder": "エージェントを検索…", - "customAgentLoadingCatalog": "ACP レジストリを読み込み中…", - "customAgentRetry": "再試行", - "customAgentNoResults": "該当するエージェントがありません", - "customAgentAdd": "追加", - "customAgentAlreadyAdded": "追加済み", - "customAgentUnsupportedPlatform": "このプラットフォーム向けのビルドがありません", - "customAgentAdded": "{name} を追加しました", - "customAgentIdLabel": "レジストリ ID", - "customAgentNameLabel": "表示名", - "customAgentVersionLabel": "バージョン", - "customAgentSpecLabel": "配布情報(JSON)", - "customAgentSpecHint": "ACP レジストリの distribution オブジェクトと同じ形式です。npx・uvx・binary の各チャネルに対応し、レジストリ項目全体の貼り付けも可能です。npx/uvx の cmd はパッケージがインストールする実行コマンド名で、省略時はパッケージ名から導出されるため、異なる場合は指定してください。binary はプラットフォームキーごとに指定し(このマシンは {platform})、cmd はアーカイブ内の起動パス、sha256 は任意でダウンロードを検証します。", - "customAgentTemplateLabel": "テンプレート", - "customAgentKindLabel": "起動方法", - "customAgentInvalidJson": "JSON として不正です", - "customAgentNoDistribution": "npx・uvx・binary のいずれの配布も見つかりません", - "customAgentCancel": "キャンセル", - "customAgentSave": "エージェントを追加", - "customAgentSaveChanges": "変更を保存", - "customAgentEdit": "エージェントを編集", - "customAgentEditHint": "名前・アイコン・配布情報・スキル宣言を変更できます。エージェント ID は変更できません。", - "customAgentEditNotFound": "カスタムエージェント {id} が見つかりません", - "customAgentSaved": "{name} を保存しました", - "customAgentVersionProbeLabel": "バージョン確認コマンド(任意)", - "customAgentVersionProbeHint": "ローカルにインストールされたバージョンを表示するコマンドです。空欄の場合はエージェントコマンドに --version を付けて実行します。", - "customAgentRemove": "エージェントを削除", - "customAgentRemoveHint": "エージェント定義を削除します。既存の会話の履歴は残り、エージェントを起動できなくなるだけです。", - "customAgentIconLabel": "アイコン(任意)", - "customAgentIconUpload": "アップロード", - "customAgentIconReplace": "変更", - "customAgentIconClear": "アイコンを削除", - "customAgentIconHint": "エージェントと共に保存されるためオフラインでも表示できます。指定しない場合は色付きの頭文字を使います。", - "customAgentSkillsLabel": "Skills(共有 .agents/skills)", - "customAgentSkillsHint": "このエージェントが共有の .agents/skills ディレクトリ(グローバルおよびプロジェクト)を読み取ることを宣言し、すべてのスキルマトリクスに追加します。共有ディレクトリにリンクしたスキルは、同じディレクトリを読むほかのエージェントからも見えます。", - "customAgentSkillsDirLabel": "専用スキルディレクトリ", - "customAgentSkillsDirHint": "このエージェントがスキルを読み込むディレクトリの絶対パスです。共有ストアと併用も単独利用も可能です。~ はホームディレクトリに展開され、リンクしたスキルはまずここに配置されます。", - "customAgentMcpLabel": "MCP サポート", - "customAgentMcpHint": "セッション開始時に codeg 内蔵の codeg-mcp コンパニオンをこのエージェントへ渡します。委任・リアルタイムフィードバック・タスクツールはこの経路を使います。MCP サーバーを受け付けず接続に失敗するエージェントではオフにしてください。設定は次回の接続から有効になります。", - "customAgentIconNotAnImage": "画像ファイルを選んでください。", - "customAgentIconTooLarge": "アイコンは {limit} KB 未満にしてください。", - "customAgentIconReadFailed": "その画像を読み込めませんでした。", - "customAgentRemoveConfirm": "{name} を削除しますか?既存の会話は残りますが、起動できなくなります。", - "customAgentRemoveWithData": "記録された会話履歴も削除する", - "customAgentRemoved": "{name} を削除しました", - "customAgentBadge": "カスタム", - "customAgentNotLaunchable": "この環境では起動できません: {reason}" - }, - "SettingsPages": { - "agentsLoading": "エージェント設定を読み込み中...", - "skillPacksLoading": "スキルパックを読み込み中…" - }, - "GeneralSettings": { - "loading": "読み込み中...", - "sectionTitle": "一般", - "sectionDescription": "デフォルトターミナル、レンダリング高速化、マルチエージェント委譲などの共通設定をここで一括管理します。", - "terminalTitle": "デフォルトターミナル", - "terminalDescription": "ターミナルバーやファイルツリーから新しいターミナルタブを開くときに使用するシェルを選択します。エージェントが codeg にコマンドライン全体の実行を依頼するときにも使われます。", - "terminalSystemDefault": "システムデフォルト", - "terminalPowerShell7": "PowerShell 7 (pwsh)", - "terminalWindowsPowerShell": "Windows PowerShell", - "terminalCmd": "コマンドプロンプト (cmd)", - "terminalSaveFailed": "ターミナル設定の保存に失敗しました: {message}", - "terminalShellCustom": "カスタムパス", - "terminalShellCustomPath": "Shell パス", - "terminalShellCustomPlaceholder": "/usr/local/bin/fish", - "terminalShellCustomSave": "保存", - "terminalShellCustomHint": "絶対パス、または PATH で解決可能なコマンド名を指定します。", - "terminalShellNotInstalled": "未インストール", - "terminalShellNotFoundWarning": "このパスはホスト上に存在しません。", - "terminalCurrentShell": "現在使用中: {path}", - "renderingDescription": "アプリで黒画面や描画不具合が発生する場合(一部の AMD GPU や Intel 内蔵 GPU で報告あり)、ハードウェアアクセラレーションを無効化してください。Windows デスクトップ版のみ有効です。", - "disableHardwareAcceleration": "ハードウェアアクセラレーションを無効化", - "renderingSaveFailed": "レンダリング設定の保存に失敗しました: {message}", - "restartRequired": "保存しました。再起動後に反映されます。", - "restartNow": "今すぐ再起動", - "restartFailed": "再起動に失敗しました: {message}", - "loadFailed": "読み込みに失敗しました: {message}" - }, - "LoginPage": { - "documentTitle": "ログイン - codeg", - "brand": "Codeg", - "subtitle": "デスクトップアプリに接続するためのアクセストークンを入力してください", - "tokenPlaceholder": "アクセストークン", - "connect": "接続", - "connecting": "接続中...", - "helpText": "トークンはデスクトップアプリの 設定 → Web サービス で取得できます", - "invalidToken": "トークンが無効です。確認して再度お試しください", - "connectionFailed": "接続失敗 (HTTP {status})", - "networkError": "サーバーに接続できません" - }, - "CommitPage": { - "title": "コミット", - "invalidFolderId": "無効なフォルダID", - "loadingRepo": "リポジトリを読み込み中..." - }, - "MergePage": { - "title": "コンフリクトの解決", - "invalidFolderId": "無効なフォルダID", - "loadingRepo": "リポジトリを読み込み中...", - "localVersion": "ローカル(自分側)", - "result": "結果", - "remoteVersion": "リモート(相手側)", - "acceptLocal": "ローカルを採用", - "acceptRemote": "リモートを採用", - "markResolved": "解決済みにする", - "abortMerge": "中止", - "completeMerge": "マージ完了", - "unresolvedConflicts": "ファイルに未解決のコンフリクトマーカーがあります", - "fileResolved": "ファイルが解決されました", - "allResolved": "すべてのコンフリクトが解決されました", - "conflictFiles": "コンフリクトファイル", - "loadingFile": "ファイルを読み込み中...", - "preparingMerge": "マージを準備中...", - "selectFile": "解決するファイルを選択してください", - "noConflicts": "コンフリクトファイルなし", - "skipFile": "スキップ", - "abortSuccess": "操作が中止されました", - "applyAllNonConflicting": "競合しない変更をすべて適用", - "applyLeftNonConflicting": "ローカルを適用", - "applyRightNonConflicting": "リモートを適用" - }, - "ImportSessions": { - "title": "ローカルセッションをインポート", - "scanningTitle": "ローカルエージェントのセッションをスキャン中…", - "scanningHint": "各エージェントのローカルセッションストアを走査しています。履歴が多い場合は時間がかかることがあります。インポート済みのセッションはあわせて更新されます。", - "scanFailed": "スキャンに失敗しました", - "retry": "再試行", - "rescan": "再スキャン", - "empty": "ローカルセッションが見つかりません", - "emptyHint": "このマシンにはエージェントのセッションストアが見つかりませんでした。", - "noMatches": "現在のフィルターに一致するセッションはありません", - "searchPlaceholder": "タイトルまたはパスを検索…", - "allAgents": "すべてのエージェント", - "onlyImportable": "インポート可能のみ", - "selectAll": "すべて選択", - "clearSelection": "クリア", - "expandAll": "すべて展開", - "collapseAll": "すべて折りたたむ", - "summaryCounts": "{total} セッション · インポート可能 {importable} · {folders} フォルダー", - "noFolderSkipped": "プロジェクトフォルダーのない {count} 件をスキップしました", - "folderNew": "新規", - "folderCounts": "インポート可能 {importable}/{total}", - "toggleFolderAria": "{name} のインポート可能なセッションをすべて選択", - "toggleSessionAria": "セッション {title} を選択", - "statusImported": "インポート済み", - "statusDeleted": "削除済み", - "untitled": "無題のセッション", - "messageCount": "{count} 件のメッセージ", - "selectedCount": "{count} 件選択中", - "importSelected": "選択項目をインポート", - "importing": "インポート中…", - "close": "閉じる", - "doneTitle": "インポート完了", - "doneImported": "インポート", - "doneUpdated": "更新済み", - "doneSkipped": "スキップ", - "doneCreatedFolders": "作成フォルダー", - "doneNotFound": "見つからず", - "doneFailed": "失敗", - "continueImport": "続けてインポート", - "toasts": { - "importFailed": "インポートに失敗しました: {message}" - } - }, - "Folder": { - "workspaceStatus": { - "degradedTitle": "リアルタイム更新は利用できません", - "degradedHint": "ウォッチャーの起動に失敗しました(アクセス権限エラーなど)。最新の変更を反映するには手動で更新してください。", - "retry": "再試行", - "retrying": "再試行中..." - }, - "common": { - "all": "すべて", - "cancel": "キャンセル", - "close": "閉じる", - "closeOthers": "他を閉じる", - "closeAll": "すべて閉じる", - "confirm": "確認", - "save": "保存", - "delete": "削除", - "rename": "名前を変更", - "loading": "読み込み中...", - "refresh": "更新", - "refreshing": "更新中...", - "create": "作成", - "createAndSwitch": "作成して切り替え", - "openFile": "ファイルを開く", - "viewDiff": "差分を見る", - "push": "プッシュ..." - }, - "statusLabels": { - "in_progress": "進行中", - "pending_review": "レビュー", - "completed": "完了", - "cancelled": "キャンセル済み" - }, - "sidebar": { - "title": "会話", - "locateActiveConversation": "アクティブな会話を表示", - "expandAllGroups": "すべてのグループを展開", - "collapseAllGroups": "すべてのグループを折りたたむ", - "newConversation": "新しい会話", - "newConversationShort": "新規", - "newChat": "新しい会話", - "search": "検索", - "noConversationsFound": "会話が見つかりません。", - "importLocalSessions": "ローカルセッションをインポート", - "importing": "インポート中...", - "error": "エラー: {message}", - "completeAllSessions": "すべてのセッションを完了", - "completeAllReviewTitle": "すべてのレビューセッションを完了しますか?", - "completeAllReviewDescription": "これにより、レビュー中の {count, plural, one {# 件のセッション} other {# 件のセッション}} が完了としてマークされます。", - "completing": "完了処理中...", - "toasts": { - "importedSessions": "{imported, plural, one {# 件のセッション} other {# 件のセッション}} をインポートし、{skipped} 件をスキップしました", - "importedAndUpdated": "{imported, plural, one {# 件のセッション} other {# 件のセッション}} をインポートし、{updated, plural, one {# 件のタイトル} other {# 件のタイトル}} を更新し、{skipped} 件をスキップしました", - "updatedTitles": "{updated, plural, one {# 件のタイトル} other {# 件のタイトル}} を更新し、{skipped} 件をスキップしました", - "noNewSessionsFound": "新しいセッションは見つかりませんでした({skipped} 件をスキップ)", - "importFailed": "インポートに失敗しました: {message}", - "reviewCompleted": "{count, plural, one {# 件のレビューセッション} other {# 件のレビューセッション}} を完了にしました", - "completeReviewFailed": "レビューセッションの完了処理に失敗しました: {message}", - "folderOpened": "フォルダ {name} を開きました", - "folderRemoved": "フォルダ {name} を削除しました", - "openFolderFailed": "フォルダを開けませんでした", - "removeFolderFailed": "フォルダの削除に失敗しました: {message}", - "reorderFoldersFailed": "フォルダの並べ替えに失敗しました: {message}", - "changeFolderColorFailed": "色の変更に失敗しました: {message}", - "setFolderAliasFailed": "エイリアスの設定に失敗しました: {message}", - "changeFolderDefaultAgentFailed": "デフォルトエージェントの設定に失敗しました: {message}" - }, - "statsLabel": "{folders} フォルダ · {convos} 会話", - "reorderHandle": "ドラッグして並べ替え", - "openFolder": "フォルダを開く", - "searchPlaceholder": "会話を検索...", - "viewOptions": "表示オプション", - "showCompleted": "完了した会話を表示", - "showWorktrees": "ワークツリーフォルダを表示", - "showRecent": "「最近」グループを表示", - "moreOptions": "その他のオプション", - "sortBy": "並び替え", - "sortByCreatedAt": "作成時刻順", - "sortByUpdatedAt": "更新時刻順", - "sectionOrder": "セクションの順序", - "sectionOrderMoveUp": "上へ移動", - "sectionOrderMoveDown": "下へ移動", - "sectionOrderItemLabel": "{name} — {total} 件中 {position} 番目", - "statusRunningBadge": "実行中", - "runningCountBadge": "{count} 件の会話が実行中", - "statusCancelledBadge": "キャンセル済み", - "worktreeRemovedBadge": "元の worktree は削除済み", - "conversationCountUnit": "{count} 件", - "emptyFolderHint": "会話がありません", - "noMatchingConversations": "一致する会話がありません", - "noUnfinishedConversations": "未完了の会話はありません。右上のメニューから「完了した会話を表示」を有効にできます。", - "removeFolderConfirmTitle": "このフォルダをワークスペースから削除しますか?", - "removeFolderConfirmDescription": "\"{name}\" をワークスペースから削除しますか?関連するタブとターミナルが閉じられます。", - "folderHeaderMenu": { - "manageConversations": "会話の管理…", - "manageLinks": "リンク済みフォルダー", - "changeColor": "色を変更", - "useThemeColor": "アプリのテーマを使用", - "setDefaultAgent": "デフォルトエージェントを設定", - "defaultAgentNone": "設定なし(グローバルを使用)", - "agentUnavailableSuffix": "(利用不可)", - "loadingAgents": "エージェントを読み込み中…", - "setAlias": "エイリアスを設定…", - "setAliasTitle": "フォルダーのエイリアスを設定", - "setAliasPlaceholder": "エイリアスを入力(空欄でクリア)", - "setAliasSave": "保存", - "setAliasCancel": "キャンセル", - "removeFromWorkspace": "ワークスペースから削除" - }, - "manageConversations": { - "title": "会話の管理", - "searchPlaceholder": "タイトルで検索…", - "agentFilterAll": "すべてのエージェント", - "statusFilterAll": "すべてのステータス", - "folderFilterAll": "すべてのフォルダ", - "branchFilterAll": "すべてのブランチ", - "branchNone": "ブランチなし", - "branchSearchPlaceholder": "ブランチを検索…", - "noMatchingBranches": "一致するブランチがありません", - "selectAllVisible": "すべて選択", - "deselectAll": "選択を解除", - "selectedCount": "{count} 件選択中", - "matchedCount": "{count} 件該当", - "untitledConversation": "無題の会話", - "setStatus": "ステータスを変更…", - "deleteSelected": "削除", - "noConversations": "このフォルダには会話がありません。", - "noConversationsWorkspace": "ワークスペースに会話がありません。", - "noMatchingConversations": "条件に一致する会話がありません。", - "confirmDeleteTitle": "{count} 件の会話を削除しますか?", - "confirmDeleteDescription": "この操作は元に戻せません。", - "toastDeleted": "{count} 件の会話を削除しました", - "toastStatusUpdated": "{count} 件の会話のステータスを更新しました", - "toastOpFailed": "操作に失敗しました: {message}" - }, - "sectionPinned": "ピン留め", - "sectionFolders": "フォルダ", - "sectionChats": "チャット", - "sectionRecent": "最近", - "noChats": "チャットがありません", - "noRecent": "最近の会話はありません", - "showMoreRecent": "さらに表示({count})", - "noFolders": "開いているフォルダがありません", - "newChatAction": "新しいチャット", - "automations": "オートメーション", - "tasks": "ToDo タスク", - "loadingSubsessions": "サブ会話を読み込み中…" - }, - "conversation": { - "reloadFailed": "会話の再読み込みに失敗しました: {message}", - "reloaded": "会話を再読み込みしました", - "reload": "再読み込み", - "activeConversationIndicator": "アクティブな会話", - "newConversation": "新しい会話", - "closeConversation": "会話を閉じる", - "copyText": "テキストをコピー", - "copyTextSuccess": "コピーしました", - "copyTextFailed": "コピーに失敗しました", - "forkSession": "セッションをフォーク", - "forkSessionSuccess": "セッションのフォークに成功しました", - "forkSessionFailed": "セッションのフォークに失敗しました:{error}", - "exportConversation": "会話をエクスポート", - "exportImage": "画像", - "exportMarkdown": "Markdown", - "exportHtml": "HTML", - "exportSuccess": "会話をエクスポートしました", - "exportFailed": "エクスポートに失敗しました", - "exportImageTooLong": "会話が長すぎるため、画像としてエクスポートできません", - "exportLabels": { - "untitledConversation": "無題の会話", - "agent": "エージェント", - "model": "モデル", - "status": "ステータス", - "started": "開始", - "updated": "更新", - "tokens": "トークン統計", - "duration": "所要時間", - "inputTokens": "入力", - "outputTokens": "出力", - "cacheRead": "キャッシュ読取", - "cacheWrite": "キャッシュ書込", - "user": "ユーザー", - "assistant": "アシスタント", - "system": "システム", - "toolResult": "結果", - "toolError": "エラー" - }, - "moreActions": "その他の操作" - }, - "sessionDetails": { - "menuLabel": "セッション詳細", - "noActiveSession": "アクティブなセッションがありません", - "title": "セッション詳細", - "subtitle": "セッションのメタデータとトークン使用量", - "fieldTitle": "タイトル", - "untitled": "無題の会話", - "sessionId": "セッション ID", - "externalId": "拡張 ID", - "agent": "エージェント", - "model": "モデル", - "status": "ステータス", - "gitBranch": "Git ブランチ", - "parentId": "親セッション", - "tokensHeading": "トークン使用量", - "totalTokens": "合計", - "inputTokens": "入力", - "outputTokens": "出力", - "cacheWrite": "キャッシュ書込", - "cacheRead": "キャッシュ読取", - "contextWindow": "コンテキストウィンドウ", - "duration": "所要時間", - "loadingStats": "トークン使用量を読み込み中…", - "loadFailed": "トークン使用量の読み込みに失敗しました", - "noStats": "使用量の記録なし", - "timestampsHeading": "日時", - "createdAt": "作成日時", - "updatedAt": "更新日時", - "none": "—", - "copyField": "{field}をコピー", - "copiedField": "{field}をコピーしました" - }, - "conversationCard": { - "untitledConversation": "無題の会話", - "newConversation": "新しい会話", - "rename": "名前を変更", - "status": "ステータス", - "delete": "削除", - "importLocalSessions": "ローカルセッションをインポート", - "importing": "インポート中...", - "renameConversation": "会話名を変更", - "deleteConversationTitle": "会話を削除しますか?", - "deleteConversationDescription": "\"{title}\" を削除します。この操作は元に戻せません。", - "cancel": "キャンセル", - "save": "保存", - "pin": "ピン留め", - "unpin": "ピン留めを解除", - "markCompleted": "完了にする", - "reopen": "再開する", - "expandSubsessions": "サブ会話を展開", - "collapseSubsessions": "サブ会話を折りたたむ" - }, - "search": { - "dialogTitle": "検索", - "dialogTitleWithFolder": "検索 — {name}", - "tabConversations": "会話", - "tabFiles": "ファイル", - "placeholder": "会話を検索...", - "filePlaceholder": "ファイルまたはディレクトリを検索...", - "allAgents": "すべて", - "searching": "検索中...", - "typeToSearch": "入力して会話を検索", - "typeToSearchFiles": "入力してファイルまたはディレクトリを検索", - "noResults": "結果が見つかりません。", - "untitledConversation": "無題の会話" - }, - "folderTitleBar": { - "showSidebar": "サイドバーを表示", - "hideSidebar": "サイドバーを非表示", - "toggleTerminal": "ターミナルを切り替え", - "toggleAuxPanel": "補助パネルを切り替え", - "search": "検索", - "openSettings": "設定を開く", - "backToConversations": "会話に戻る", - "withShortcut": "{label}({shortcut})" - }, - "statusBar": { - "connection": { - "connected": "接続済み", - "connecting": "接続中...", - "prompting": "応答中...", - "error": "接続エラー", - "disconnected": "未接続", - "tooltip": "{agent}:{status}", - "tooltipError": "{agent}:{error}", - "title": "エージェント接続", - "triggerAria": "エージェント接続: {status}", - "workingDir": "作業ディレクトリ", - "sessionId": "セッション ID", - "viewerNote": "他のクライアントが所有するセッションに接続しています。再接続してもこのビューが接続し直されるだけです。", - "reconnectInterrupts": "再接続するとエージェントが再起動し、進行中の処理が中断されます。", - "reconnect": "再接続", - "reconnecting": "再接続中...", - "reconnectUnavailable": "再接続できるセッションがまだありません。" - }, - "tasks": { - "title": "タスク" - }, - "alerts": { - "title": "アラート", - "empty": "アラートなし", - "details": "詳細" - }, - "stats": { - "conversations": "{count} 件の会話", - "openUsage": "セッション統計とトークン使用量を表示" - }, - "tokens": { - "contextWindowUsageAria": "コンテキストウィンドウ使用率", - "contextWindow": "コンテキストウィンドウ", - "usedMax": "使用 / 最大", - "tokenUsage": "トークン使用量", - "input": "入力", - "output": "出力", - "cacheRead": "キャッシュ読み取り", - "cacheWrite": "キャッシュ書き込み", - "total": "合計" - } - }, - "auxPanel": { - "tabs": { - "files": "ファイル", - "changes": "変更", - "commits": "コミット" - }, - "noFolderTitle": "開いているフォルダがありません", - "noFolderHint": "フォルダを開くとここに表示されます" - }, - "windowControls": { - "minimizeWindow": "ウィンドウを最小化", - "minimize": "最小化", - "maximizeWindow": "ウィンドウを最大化", - "maximize": "最大化", - "restoreWindow": "ウィンドウを元に戻す", - "restore": "元に戻す", - "closeWindow": "ウィンドウを閉じる", - "close": "閉じる" - }, - "tabs": { - "closeConversationTab": "会話タブを閉じる", - "close": "閉じる", - "closeOthers": "他を閉じる", - "splitRight": "右に分割", - "splitDown": "下に分割", - "splitAndMoveRight": "分割して右へ移動", - "splitAndMoveDown": "分割して下へ移動", - "moveToOppositeGroup": "反対側のグループへ移動", - "moveToGroup": "グループへ移動", - "groupLabel": "グループ {index}", - "changeSplitterOrientation": "分割方向を切り替え", - "unsplit": "分割を解除", - "unsplitAll": "すべての分割を解除", - "closeAll": "すべて閉じる", - "tileDisplay": "タイル表示", - "untileDisplay": "タイル解除" - }, - "fileWorkspace": { - "files": "ファイル", - "closeFileTab": "ファイルタブを閉じる", - "close": "閉じる", - "closeOthers": "他を閉じる", - "closeAll": "すべて閉じる", - "preview": "プレビュー", - "editSource": "ソースを編集", - "maximize": "最大化", - "restore": "元に戻す", - "emptyDirectory": "空のフォルダー" - }, - "terminal": { - "rename": "名前を変更", - "close": "閉じる", - "closeOthers": "他を閉じる", - "closeAll": "すべて閉じる", - "hideTerminal": "ターミナルを隠す ({shortcut})", - "openFolderFirst": "先にフォルダを開いてください" - }, - "workspaceDialog": { - "title": "フォルダーを開く", - "manageTitle": "リンク済みフォルダー", - "addTargetsTitle": "リンクするフォルダーを追加", - "pickRootDescription": "このワークスペースのメインフォルダーを選択します。", - "linksDescription": "他のフォルダーをサブディレクトリとしてリンクすると、エージェントは 1 つのワークスペースから横断的に作業できます。", - "addTargetsDescription": "フォルダーを 1 つ以上選択してください。それぞれがワークスペースのサブディレクトリになります。", - "useSystemPicker": "システムの選択画面", - "next": "次へ", - "back": "戻る", - "done": "完了", - "change": "変更", - "addFolders": "フォルダーを追加", - "addSelected": "追加", - "addSelectedCount": "{count} 件を追加", - "createCount": "{count} 件のフォルダーをリンク", - "discardPending": "破棄", - "noLinks": "リンクされたフォルダーはまだありません。", - "gitExclude": "リンクを git status に出さない", - "rename": "名前を変更", - "unlink": "リンクを解除", - "repair": "リンクを作り直す", - "saveName": "保存", - "cancelRename": "キャンセル", - "removePending": "削除", - "willAppearAs": "ワークスペースでは {name} として表示されます", - "renamedForDuplicate": "改名しました — {base} は別のリンクが使用中です", - "renamedForExistingEntry": "改名しました — このフォルダーには既に {base} があります", - "partiallyCreated": "{count} 件のフォルダーのみリンクできました", - "openFailed": "フォルダーを開けませんでした", - "previewFailed": "選択したフォルダーを確認できませんでした", - "createFailed": "フォルダーをリンクできませんでした", - "renameFailed": "名前を変更できませんでした", - "removeFailed": "リンクを解除できませんでした", - "repairFailed": "リンクを作り直せませんでした", - "status": { - "ok": "リンク済み", - "missing": "リンクがこのフォルダーから消えています", - "conflicted": "この名前は別の項目が使用しています", - "broken": "リンク先のフォルダーが存在しません" - }, - "nameIssue": { - "empty": "名前を入力してください", - "illegalChars": "/ \\ : * ? \" < > | は使用できません", - "tooLong": "名前が長すぎます", - "reserved": "この名前は Windows の予約語です", - "duplicate": "この名前は既に使われています" - }, - "rejection": { - "not_found": "このフォルダーが見つかりません", - "not_a_directory": "このパスはフォルダーではありません", - "same_as_root": "ワークスペースのフォルダー自身です", - "ancestor_of_root": "このフォルダーはワークスペースを含んでいます", - "inside_root": "既にワークスペース内にあります", - "already_linked": "既にリンク済みです", - "name_unavailable": "このフォルダーに使える名前が残っていません", - "alreadyLinkedAs": "{name} として既にリンク済みです" - } - }, - "folderNameDropdown": { - "fallbackFolderName": "フォルダ", - "openFolder": "フォルダを開く", - "cloneRepository": "リポジトリをクローン", - "projectBoot": "プロジェクトブート", - "opened": "開いているフォルダ", - "recentOpen": "最近開いたフォルダ" - }, - "fileWorkspacePanel": { - "addSelectionToChat": "選択範囲をチャットに追加", - "addToChat": "チャットに追加", - "addSelectionToChatDone": "{label} を会話に追加しました", - "addFileToChat": "ファイルをチャットに追加", - "toggleWordWrap": "折り返しの切り替え", - "addFileToChatDone": "{label} を会話に追加しました", - "viewDiff": "差分を見る", - "openFile": "ファイルを開く", - "fileCount": "{count, plural, one {# 個のファイル} other {# 個のファイル}}", - "openFileOrDiff": "右側パネルからファイルまたは差分を開いてください", - "disk": "ディスク", - "head": "HEAD", - "unsaved": "未保存", - "workingTree": "作業ツリー", - "loading": "読み込み中...", - "compareWithBranch": "{path} · {branch} と比較", - "hunkCount": "{count, plural, one {# 個のハンク} other {# 個のハンク}}", - "prev": "前", - "next": "次", - "jumpToLine": "{line} 行へ移動", - "noParsedDiffSections": "解析済みの差分セクションがありません", - "loadingEditor": "エディターを読み込み中...", - "imageZoomIn": "拡大", - "imageZoomOut": "縮小", - "imageZoomReset": "ズームをリセット", - "htmlPreviewTitle": "HTML プレビュー", - "htmlPreviewTrust": "スクリプトを有効化", - "htmlPreviewTrustHint": "このファイルのスクリプトを実行し、ネットワークアクセスを許可します。信頼できるファイルでのみ有効にしてください。", - "officePreviewTitle": "Office ドキュメントのプレビュー", - "officeFullRender": "フル描画", - "officeFullRenderHint": "Morph アニメーション・3D・数式を描画します(スライド自身のスクリプトを実行)", - "officeNotInstalled": "OfficeCLI がインストールされていません", - "officeNotInstalledHint": "設定 → Office ツール から OfficeCLI をインストールすると、Word・Excel・PowerPoint ファイルをプレビューできます。", - "officeOpenSettings": "設定を開く", - "officeWatchFailed": "ライブプレビューを開始できませんでした", - "officeWatchRetry": "再試行", - "officeServerInstallHint": "OfficeCLI はサーバーホストにインストールする必要があります。サーバーで次のコマンドを実行してから再試行してください:", - "officeRemoteDesktopUnsupported": "リモートデスクトップウィンドウではライブプレビューを利用できません。Office ファイルをプレビューするには、サーバーの Web UI でこのワークスペースを開いてください。" - }, - "branchDropdown": { - "toasts": { - "commitCodeCompleted": "コードコミットが完了しました", - "pushCodeCompleted": "コードプッシュが完了しました", - "committedFiles": "{count, plural, one {# 個のファイルをコミット} other {# 個のファイルをコミット}}", - "taskCompleted": "{label} が完了しました", - "taskFailed": "{label} が失敗しました", - "mergeNoNewCommits": "{branchName} に新しいコミットはありません", - "mergedCommits": "{count, plural, one {# 件のコミットをマージ} other {# 件のコミットをマージ}}", - "allFilesUpToDate": "すべてのファイルは最新です", - "updatedFiles": "{count, plural, one {# 個のファイルを更新} other {# 個のファイルを更新}}", - "openCommitWindowFailed": "コミットウィンドウを開けませんでした", - "openPushWindowFailed": "プッシュウィンドウを開けませんでした", - "upstreamSet": "アップストリームブランチを設定しました", - "upstreamSetAndPushed": "アップストリームブランチを設定し、{count, plural, one {# 件のコミット} other {# 件のコミット}}をプッシュしました", - "noCommitsToPush": "プッシュするコミットはありません", - "pushedCommits": "{count, plural, one {# 件のコミットをプッシュ} other {# 件のコミットをプッシュ}}", - "switchedToFolder": "{name} に切り替えました", - "switchFailed": "ブランチの切り替えに失敗しました", - "openStashWindowFailed": "stash ウィンドウを開けませんでした" - }, - "tasks": { - "newBranch": "ブランチ {name} を作成", - "newWorktree": "ワークツリー {name} を作成", - "checkoutTo": "{branchName} にチェックアウト", - "mergeBranch": "{branchName} をマージ", - "rebaseTo": "{branchName} にリベース", - "deleteRemoteBranch": "リモートブランチ {branchName} を削除", - "initGitRepo": "Git リポジトリを初期化", - "pullCode": "コードをプル", - "fetchInfo": "情報をフェッチ", - "pushCode": "コードをプッシュ", - "stashChanges": "変更を stash", - "stashPop": "stash を pop", - "deleteBranch": "ブランチ {branchName} を削除", - "removeWorktree": "{branchName} のワークツリーを削除", - "removeWorktreeAndBranch": "ワークツリーとブランチ {branchName} を削除", - "updateBranch": "ブランチ {branchName} を更新" - }, - "confirm": { - "mergeTitle": "ブランチをマージ", - "rebaseTitle": "ブランチをリベース", - "mergeDescription": "{branchName} を現在のブランチ {currentBranch} にマージしますか?", - "rebaseDescription": "現在のブランチ {currentBranch} を {branchName} にリベースしますか?", - "deleteRemoteTitle": "リモートブランチの削除", - "deleteRemoteDescription": "リモートブランチ {branchName} を削除しますか?この操作はリモートリポジトリからブランチを削除し、元に戻せません。", - "deleteTitle": "ブランチを削除", - "deleteDescription": "ブランチ {branchName} を削除しますか?この操作は元に戻せません。", - "forceDeleteTitle": "ブランチを強制削除", - "forceDeleteDescription": "ブランチ {branchName} はまだ完全にマージされていません。強制削除してもよろしいですか?この操作は元に戻せません。", - "deleteWorktreeTitle": "ワークツリーを削除", - "deleteWorktreeDescription": "{branchName} をチェックアウトしているワークツリーのディレクトリを削除しますか?ブランチとそのコミットは残ります。", - "forceDeleteWorktreeTitle": "ワークツリーを強制削除", - "forceDeleteWorktreeDescription": "{branchName} のワークツリーに未コミットまたは未追跡のファイルがあります。それでも削除しますか?その変更は復元できません。", - "deleteWorktreeAndBranchTitle": "ワークツリーとブランチを削除", - "deleteWorktreeAndBranchDescription": "{branchName} のワークツリー、ブランチ自体、そのワークスペースフォルダーを削除しますか?中のセッションはリポジトリのフォルダーに移動します。この操作は取り消せません。", - "forceDeleteWorktreeAndBranchTitle": "ワークツリーとブランチを強制削除", - "forceDeleteWorktreeAndBranchDescription": "{branchName} のワークツリーに未コミットのファイルがあるか、ブランチが完全にマージされていません。それでも両方を削除しますか?この操作は取り消せません。" - }, - "current": "現在", - "switchToBranch": "このブランチに切り替え", - "mergeBranchIntoCurrent": "{branchName} を {currentBranch} にマージ", - "rebaseCurrentToBranch": "{currentBranch} を {branchName} にリベース", - "noBranch": "ブランチなし", - "detachedHead": "切り離された HEAD({sha})", - "initGitRepo": "Git リポジトリを初期化", - "pullCode": "コードをプル", - "fetchRemoteBranches": "リモートブランチをフェッチ", - "openCommitWindow": "コードをコミット...", - "pushCode": "プッシュ...", - "pushBranch": "プッシュ", - "newBranch": "新規ブランチ...", - "newWorktree": "新規ワークツリー...", - "stashChanges": "スタッシュ...", - "stashPop": "stash を pop...", - "manageRemotes": "リモート管理...", - "localBranches": "ローカルブランチ ({count, plural, one {#} other {#}})", - "noLocalBranches": "ローカルブランチはありません", - "remoteBranches": "リモートブランチ ({count, plural, one {#} other {#}})", - "noRemoteBranches": "リモートブランチはありません", - "dialogs": { - "newBranchTitle": "新規ブランチ", - "newBranchDescription": "現在のブランチ {branch} から新しいブランチを作成", - "branchNamePlaceholder": "ブランチ名", - "newWorktreeTitle": "新規ワークツリー", - "newWorktreeDescription": "現在のブランチ {branch} から新しいワークツリーを作成", - "branchNameLabel": "ブランチ名", - "worktreePathLabel": "ワークツリーのパス", - "worktreePathPlaceholder": "ワークツリーのパス", - "manageRemotesTitle": "リモート管理", - "manageRemotesEmpty": "リモートが設定されていません", - "remoteNamePlaceholder": "リモート名", - "remoteUrlPlaceholder": "リモート URL", - "addRemote": "追加", - "savingRemotes": "保存中..." - }, - "conflict": { - "title": "マージコンフリクト", - "description": "以下のファイルにコンフリクトがあります。解決が必要です:", - "abort": "マージを中止", - "openMergeTool": "マージツールを開く", - "completeMerge": "マージ完了", - "abortSuccess": "マージが中止されました", - "completeSuccess": "マージが完了しました" - }, - "stashDialog": { - "title": "変更をスタッシュ", - "description": "現在の変更をスタッシュに保存", - "messageLabel": "メッセージ", - "messagePlaceholder": "スタッシュメッセージ(任意)", - "keepIndex": "インデックスを保持(ステージ済みの変更はそのまま)", - "cancel": "キャンセル", - "stash": "スタッシュ", - "success": "変更がスタッシュされました", - "error": "スタッシュに失敗しました" - }, - "unstashDialog": { - "title": "スタッシュを適用", - "noStashes": "スタッシュがありません", - "selectFile": "ファイルを選択して差分を表示", - "viewDiff": "差分を表示", - "original": "元", - "modified": "変更後", - "apply": "適用", - "drop": "削除", - "applySuccess": "スタッシュを適用しました", - "dropSuccess": "スタッシュを削除しました", - "confirmApply": "スタッシュ {ref} を作業ディレクトリに適用しますか?", - "cancel": "キャンセル" - }, - "deleteBranch": "ブランチを削除", - "deleteWorktree": "ワークツリーを削除", - "deleteWorktreeAndBranch": "ワークツリーとブランチを削除", - "searchPlaceholder": "ブランチと操作を検索", - "searchAriaLabel": "ブランチと操作を検索", - "branchListLabel": "ブランチと操作", - "noMatches": "一致する項目がありません" - }, - "commitDialog": { - "toasts": { - "commitCompleted": "コードコミットが完了しました", - "pushFailed": "プッシュに失敗しました", - "committedFiles": "{count, plural, one {# 個のファイルをコミット} other {# 個のファイルをコミット}}", - "addedToVcs": "VCS に追加しました", - "addToVcsFailed": "VCS への追加に失敗しました", - "fileDeleted": "ファイルを削除しました", - "deleteFailed": "削除に失敗しました", - "fileRolledBack": "ファイルをロールバックしました", - "rollbackFailed": "ロールバックに失敗しました", - "dirRolledBack": "ディレクトリをロールバックしました", - "dirDeleted": "ディレクトリを削除しました" - }, - "confirm": { - "deleteTitle": "削除の確認", - "deleteDescription": "ファイル \"{file}\" を削除しますか?この操作は元に戻せません。", - "rollbackTitle": "ロールバックの確認", - "rollbackDescription": "ファイル \"{file}\" を HEAD にロールバックしますか?未保存の変更は失われます。", - "rollbackDirDescription": "ディレクトリ「{dir}」をHEADにロールバックしますか?未保存の変更は失われます。", - "deleteDirDescription": "ディレクトリ「{dir}」を削除しますか?この操作は元に戻せません。" - }, - "actions": { - "select": "選択", - "unselect": "選択解除", - "rollback": "ロールバック", - "addToVcs": "VCS に追加" - }, - "aria": { - "selectFile": "{action}: {path}", - "unselectAllFiles": "すべてのファイルの選択を解除", - "selectAllFiles": "すべてのファイルを選択", - "unselectTracked": "追跡中の変更の選択を解除", - "selectTracked": "追跡中の変更を選択", - "unselectUntracked": "未追跡ファイルの選択を解除", - "selectUntracked": "未追跡ファイルを選択" - }, - "loading": "読み込み中...", - "selectionCount": "{selected} / {total} ファイル", - "emptyFiles": "変更されたファイルはありません", - "trackedChanges": "追跡中の変更 ({count})", - "untrackedFiles": "未追跡ファイル ({count})", - "commitMessage": "コミットメッセージ", - "commitMessagePlaceholder": "コミットメッセージを入力...", - "commitButton": "コミット ({count})", - "commitAndPushButton": "コミットしてプッシュ ({count})", - "head": "HEAD", - "workingTree": "作業ツリー", - "clickFileToDiff": "ファイル名をクリックして差分を表示", - "loadingDiff": "差分を読み込み中..." - }, - "pushWindow": { - "title": "コードをプッシュ", - "noUnpushedCommits": "未プッシュのコミットはありません", - "noRemoteConfigured": "Git リモートが設定されていません\n「リモート管理」からリモートを追加してください", - "newBranchNoPushedCommits": "新しいブランチ — プッシュしてリモート追跡ブランチを作成", - "unpushed": "未プッシュ", - "selectFileToViewDiff": "ファイルを選択して差分を表示", - "before": "変更前", - "after": "変更後", - "push": "プッシュ", - "toasts": { - "pushSuccess": "プッシュ成功", - "pushFailed": "プッシュ失敗", - "upstreamSet": "リモート追跡ブランチが設定されました", - "upstreamSetAndPushed": "リモート追跡ブランチを設定し、{count}件のコミットをプッシュしました", - "noCommitsToPush": "プッシュするコミットはありません", - "pushedCommits": "{count}件のコミットをプッシュしました" - } - }, - "gitLogTab": { - "filesTitle": "ファイル", - "expandAllFiles": "すべてのファイルを展開", - "collapseAllFiles": "すべてのファイルを折りたたむ", - "workspace": "ワークスペース", - "retry": "再試行", - "noCommitsFound": "コミットが見つかりません", - "notAGitRepoTitle": "Git リポジトリではありません", - "notAGitRepoHint": "上のブランチメニューから Git を初期化するか、既存のリポジトリを開いてください。", - "hash": "ハッシュ", - "copyHash": "ハッシュをコピー", - "copyMessage": "メッセージをコピー", - "showMore": "もっと見る", - "showLess": "折りたたむ", - "author": "作成者", - "noFileChangeDetails": "ファイル変更の詳細はありません。", - "loadingFiles": "ファイルを読み込み中…", - "branchesTitle": "ブランチ", - "loadingBranches": "ブランチを読み込み中...", - "noContainingBranches": "含まれるブランチが見つかりません。", - "newBranch": "新規ブランチ...", - "resetToHere": "ここにリセット", - "resetDisabledReasonNotCurrentBranchView": "現在のブランチ表示時のみ利用できます", - "copyFullCommitHashAria": "完全なコミットハッシュ {hash} をコピー", - "pushStatus": { - "pushed": "リモートにプッシュ済み", - "notPushed": "リモートに未プッシュ", - "unknown": "プッシュ状態不明(upstream 未設定)" - }, - "time": { - "monthsAgo": "{count, plural, one {# か月前} other {# か月前}}", - "daysAgo": "{count, plural, one {# 日前} other {# 日前}}", - "hoursAgo": "{count, plural, one {# 時間前} other {# 時間前}}", - "minsAgo": "{count, plural, one {# 分前} other {# 分前}}", - "justNow": "たった今" - }, - "toasts": { - "createdAndSwitchedNewBranch": "新しいブランチを作成して切り替えました", - "newBranchFromCommit": "{name}({shortHash} から)", - "createBranchFailed": "ブランチ作成に失敗しました", - "openPushWindowFailed": "プッシュウィンドウを開けませんでした", - "resetSuccess": "リセットが完了しました", - "resetSuccessDescription": "{branch} を {mode} で {shortHash} にリセットしました", - "resetFailed": "リセットに失敗しました" - }, - "authorFilter": { - "label": "作成者", - "searchPlaceholder": "作成者を検索", - "noAuthors": "作成者が見つかりません", - "you": "あなた", - "filterByAuthorAria": "作成者でコミットを絞り込む", - "filterByQuery": "「{query}」で絞り込む", - "clearAuthorFilterAria": "作成者フィルターをクリア", - "recent": "最近", - "matchingAuthors": "一致する作成者", - "removeFromRecent": "{name} を最近から削除" - }, - "branchSelector": { - "label": "ブランチ", - "head": "HEAD", - "headHint": "現在のブランチに追従", - "headHintWithBranch": "現在のブランチに追従({branch})", - "searchBranch": "ブランチを検索...", - "noBranches": "ブランチがありません", - "selectBranchPlaceholder": "ブランチを選択...", - "localBranches": "ローカルブランチ", - "current": "現在", - "remoteBranches": "リモートブランチ", - "refreshCommitHistory": "コミット履歴を更新", - "clearBranchFilterAria": "ブランチフィルターをクリア" - }, - "dialogs": { - "newBranchTitle": "新規ブランチ", - "newBranchDescription": "コミット {shortHash} を最新コミットとして新しいブランチを作成します。", - "branchNamePlaceholder": "ブランチ名", - "reset": { - "title": "現在のブランチをこのコミットへリセット", - "branchLabel": "ブランチ", - "targetLabel": "対象コミット", - "messageLabel": "コミットメッセージ", - "modeLabel": "リセットモード", - "confirmButton": "リセット", - "modes": { - "soft": { - "label": "--soft", - "description": "HEAD と現在のブランチ参照を対象コミットへ移動します。\nIndex と Working Tree は変更しません。\n取り消されたコミットの変更は staged のまま残ります。" - }, - "mixed": { - "label": "--mixed(デフォルト)", - "description": "HEAD を対象コミットへ移動します。\nIndex を対象コミットに戻し、Working Tree の変更は維持します。\n変更は staged から unstaged に戻ります。" - }, - "hard": { - "label": "--hard", - "description": "HEAD を移動し、Index と Working Tree を対象コミットに戻します。\n対象コミット以降の追跡中ローカル変更は破棄されます。\n破壊的な操作です。" - }, - "keep": { - "label": "--keep", - "description": "HEAD を対象コミットへ移動し、可能な限りローカル変更を保持します。\n競合しない変更のみ保持されます。\n競合がある場合は保護のため処理を中止します。" - } - } - } - }, - "moreActions": "その他の Git 操作" - }, - "gitChangesTab": { - "workspace": "ワークスペース", - "noChanges": "ローカルの変更はありません", - "notAGitRepoTitle": "Git リポジトリではありません", - "notAGitRepoHint": "上のブランチメニューから Git を初期化するか、既存のリポジトリを開いてください。", - "trackedChanges": "追跡中の変更 ({count})", - "untrackedFiles": "未追跡ファイル ({count})", - "expandTracked": "追跡中の変更を展開", - "collapseTracked": "追跡中の変更を折りたたむ", - "expandUntracked": "未追跡ファイルを展開", - "collapseUntracked": "未追跡ファイルを折りたたむ", - "showRemainingItems": "残り {count} 件を表示", - "actions": { - "commitCode": "コードをコミット", - "rollback": "ロールバック", - "addToVcs": "VCS に追加", - "delete": "削除", - "moreActions": "その他の Git 操作", - "addAllToVcs": "すべて VCS に追加", - "rollbackAll": "すべてロールバック", - "refresh": "更新" - }, - "toasts": { - "noAddableFilesInDir": "このディレクトリには VCS に追加できる変更ファイルがありません", - "noRollbackFilesInDir": "このディレクトリにはロールバックできる変更ファイルがありません", - "addedToVcs": "{name} を VCS に追加しました", - "addToVcsFailed": "VCS への追加に失敗しました", - "openCommitWindowFailed": "コミットウィンドウを開けませんでした", - "rolledBack": "{name} をロールバックしました", - "rollbackFailed": "ロールバックに失敗しました", - "addedFilesToVcs": "{count, plural, one {# 個のファイルを VCS に追加} other {# 個のファイルを VCS に追加}}", - "rolledBackFiles": "{count, plural, one {# 個のファイルをロールバック} other {# 個のファイルをロールバック}}", - "deleted": "{name} を削除しました", - "deleteFailed": "削除に失敗しました", - "deletedFiles": "{count} 個のファイルを削除しました", - "noDeletableFilesInDir": "このディレクトリには削除可能な変更ファイルがありません", - "commitFailed": "コミットに失敗しました" - }, - "directoryDialog": { - "descriptionAdd": "ディレクトリ {path} 配下で VCS に追加するファイルを選択してください。", - "descriptionRollback": "ディレクトリ {path} 配下でロールバックするファイルを選択してください。", - "descriptionDelete": "ディレクトリ {path} 配下で削除するファイルを選択してください。この操作は元に戻せません。", - "descriptionFallback": "続行するファイルを選択してください。", - "selectionCount": "{selected} / {total} を選択", - "selectAll": "すべて選択", - "unselectAll": "すべて選択解除", - "loadingCandidates": "ディレクトリの変更を読み込み中...", - "noOperableFiles": "操作可能なファイルがありません" - }, - "rollbackConfirm": { - "title": "ロールバックの確認", - "descriptionWithTarget": "{kind} \"{name}\" のローカル変更をロールバックしますか?", - "descriptionFallback": "ローカル変更をロールバックしますか?", - "kindDirectory": "ディレクトリ", - "kindFile": "ファイル" - }, - "deleteConfirm": { - "title": "削除の確認", - "descriptionWithTarget": "{kind}「{name}」を削除しますか?この操作は元に戻せません。", - "descriptionFallback": "この操作は元に戻せません。", - "kindDirectory": "ディレクトリ", - "kindFile": "ファイル" - }, - "quickCommit": { - "placeholder": "コミットメッセージ(Enter でコミット)" - } - }, - "tabContext": { - "loadingConversation": "読み込み中...", - "untitledConversation": "無題の会話", - "newConversation": "新しい会話" - }, - "fileTreeTab": { - "workspace": "ワークスペース", - "retry": "再試行", - "git": "Git", - "openInFileManager": "ファイルマネージャーで開く", - "openInFinder": "Finderで開く", - "openInExplorer": "エクスプローラーで開く", - "attachToCurrentSession": "セッションに追加", - "compareWithBranch": "ブランチと比較...", - "reloadFromDisk": "ディスクから再読み込み", - "new": "新規作成", - "newFile": "ファイル", - "newDirectory": "ディレクトリ", - "openIn": "で開く", - "openInTerminal": "ターミナルで開く", - "linkedFolder": "リンク済みフォルダー", - "copyPath": "パスをコピー", - "upload": "ファイル/フォルダをアップロード", - "download": "ファイルをダウンロード", - "downloadAsZip": "ZIP としてダウンロード", - "actions": { - "select": "選択", - "unselect": "選択解除", - "commitCode": "コードをコミット", - "rollback": "ロールバック", - "addToVcs": "VCSに追加" - }, - "aria": { - "selectPath": "{action}: {path}" - }, - "toasts": { - "openDirectoryFailed": "ディレクトリを開けませんでした", - "openBuiltinTerminalFailed": "内蔵ターミナルを開けませんでした", - "openCommitWindowFailed": "コミットウィンドウを開けませんでした", - "noAddableFilesInDir": "このディレクトリには VCS に追加できる変更ファイルがありません", - "noRollbackFilesInDir": "このディレクトリにはロールバックできる変更ファイルがありません", - "addedToVcs": "{name} を VCS に追加しました", - "addToVcsFailed": "VCS への追加に失敗しました", - "loadBranchesFailed": "ブランチの読み込みに失敗しました", - "renameFailed": "名前の変更に失敗しました", - "moveFailed": "移動に失敗しました", - "deleteFailed": "削除に失敗しました", - "rolledBack": "{name} をロールバックしました", - "rollbackFailed": "ロールバックに失敗しました", - "addedFilesToVcs": "{count, plural, one {# 件のファイルを VCS に追加しました} other {# 件のファイルを VCS に追加しました}}", - "rolledBackFiles": "{count, plural, one {# 件のファイルをロールバックしました} other {# 件のファイルをロールバックしました}}", - "savedAsCopy": "コピーとして保存しました", - "saveCopyFailed": "コピーとして保存できませんでした", - "watchStartFailed": "ファイル監視の開始に失敗しました", - "createFailed": "作成に失敗しました", - "downloadFailed": "{name} のダウンロードに失敗しました", - "downloadSaved": "{name} をダウンロードしました", - "pathCopied": "パスをコピーしました", - "copyPathFailed": "パスのコピーに失敗しました" - }, - "createDialog": { - "newFile": "新規ファイル", - "newDirectory": "新規ディレクトリ", - "description": "新しい{kind}の名前を入力してください。", - "placeholderFile": "file-name.ext", - "placeholderDirectory": "folder-name" - }, - "renameDialog": { - "renameDirectory": "ディレクトリ名を変更", - "renameFile": "ファイル名を変更", - "description": "新しい名前を入力してください(名前のみ、パスは不要)。", - "placeholderDirectory": "新しいフォルダ名", - "placeholderFile": "新しいファイル名.ext" - }, - "uploadDialog": { - "title": "ワークスペースへアップロード", - "description": "必要に応じて上書き先を変更し、ファイルやフォルダを追加してください。", - "workspaceRoot": "ワークスペースのルート", - "targetPathLabel": "アップロード先", - "targetPathHint": "実際の場所:{path}", - "dropHint": "ファイルやフォルダをここにドロップ、または下のボタンから選択", - "dropHintActive": "離してキューに追加", - "selectFiles": "ファイルを選択", - "selectFolder": "フォルダを選択", - "startUpload": "アップロード開始", - "clearQueue": "完了したものをクリア", - "removeItem": "キューから削除", - "retry": "再試行", - "dropZoneAria": "ファイルをここにドロップ、または Enter で参照", - "folderEmpty": "ドロップされたフォルダにファイルが見つかりません", - "summary": "合計:{total} · 成功:{succeeded} · 失敗:{failed}", - "status": { - "pending": "待機中", - "uploading": "アップロード中", - "success": "完了", - "error": "失敗", - "cancelled": "キャンセル済み" - } - }, - "directoryDialog": { - "descriptionAdd": "ディレクトリ {path} 配下で VCS に追加するファイルを選択してください。", - "descriptionRollback": "ディレクトリ {path} 配下でロールバックするファイルを選択してください。", - "descriptionFallback": "続行するファイルを選択してください。", - "selectionCount": "{selected} / {total} ファイルを選択", - "selectAll": "すべて選択", - "unselectAll": "すべて選択解除", - "loadingCandidates": "ディレクトリの変更を読み込み中...", - "noOperableFiles": "操作可能なファイルがありません" - }, - "compareDialog": { - "title": "ブランチと比較", - "descriptionWithTarget": "ブランチを選択し、{kind} {path} と比較します", - "descriptionFallback": "比較するブランチを選択してください。", - "kindDirectory": "ディレクトリ", - "kindFile": "ファイル", - "filterPlaceholder": "ブランチを絞り込み(例: main / origin/main)", - "singleClickHint": "ブランチをクリックすると直接比較します", - "loadingBranches": "ブランチを読み込み中...", - "recentBranches": "最近のブランチ ({count})", - "noCurrentBranch": "現在のブランチがありません", - "localBranches": "ローカルブランチ ({count})", - "remoteBranches": "リモートブランチ ({count})", - "noMatchingBranches": "一致するブランチがありません" - }, - "externalConflictDialog": { - "title": "外部ファイルの変更を検出しました", - "descriptionWithPath": "ファイル {path} がディスク上で変更されました。現在の編集は未保存です。", - "descriptionFallback": "現在のファイルがディスク上で変更されました。現在の編集は未保存です。", - "compare": "比較", - "savingCopy": "コピーを保存中...", - "saveAsCopy": "コピーとして保存", - "reload": "再読み込み" - }, - "deleteConfirm": { - "title": "削除の確認", - "descriptionWithTarget": "{kind} \"{name}\" を削除しますか?この操作は元に戻せません。", - "descriptionFallback": "この操作は元に戻せません。", - "kindDirectory": "ディレクトリ", - "kindFile": "ファイル" - }, - "rollbackConfirm": { - "title": "ロールバックの確認", - "descriptionWithTarget": "ファイル \"{name}\" のローカル変更をロールバックしますか?", - "descriptionFallback": "このファイルのローカル変更をロールバックしますか?" - }, - "terminalTitle": "ターミナル · {name}" - }, - "commandDropdown": { - "loading": "読み込み中...", - "addCommand": "コマンドを追加", - "manageCommands": "コマンドを管理...", - "runCommandTitle": "実行: {command}", - "stopCommandTitle": "停止: {command}", - "manageDialog": { - "title": "コマンド管理", - "empty": "コマンドはまだありません", - "noResults": "一致するコマンドがありません", - "searchPlaceholder": "コマンドを検索", - "newCommand": "新しいコマンド", - "nameLabel": "名前", - "commandLabel": "コマンド", - "dragSort": "ドラッグして並び替え", - "dragSortCommand": "{name} をドラッグして並び替え", - "orderFailed": "コマンドの並び順の保存に失敗しました", - "loadFailed": "コマンドの読み込みに失敗しました", - "saveFailed": "コマンドの保存に失敗しました", - "deleteFailed": "コマンドの削除に失敗しました", - "confirmDelete": { - "title": "コマンドを削除しますか?", - "message": "「{name}」を削除します。この操作は元に戻せません。" - } - } - }, - "workspaceContext": { - "confirmCloseDirtyTab": "保存せずに「{title}」を閉じますか?", - "confirmCloseOtherDirtyTabs": "未保存の変更がある他のタブを閉じますか?", - "confirmCloseAllDirtyTabs": "未保存の変更があるすべてのタブを閉じますか?", - "unableLoadContent": "内容を読み込めません。\n\n{message}", - "previewRequestTimedOut": "プレビュー要求がタイムアウトしました", - "diffRequestTimedOut": "Diff 要求がタイムアウトしました", - "branchCompareRequestTimedOut": "ブランチ比較要求がタイムアウトしました", - "commitDiffRequestTimedOut": "コミット Diff 要求がタイムアウトしました", - "saveRequestTimedOut": "保存要求がタイムアウトしました", - "reloadRequestTimedOut": "再読み込み要求がタイムアウトしました", - "noChanges": "変更はありません。", - "noDiffOutput": "Diff 出力がありません。", - "diffTitleWorkspace": "Diff · ワークスペース", - "diffDescriptionWorkingTree": "作業ツリー (HEAD)", - "diffTitleFile": "差分 · {name}", - "compareTitleFile": "比較 · {name}", - "compareTitleBranch": "比較 · {branch}", - "compareDescriptionPath": "{path} · {branch} と比較", - "compareDescriptionBranch": "{branch} と比較", - "diffTitleCommitFile": "差分 · {name} @ {hash}", - "diffTitleCommit": "差分 · {hash}", - "diffDescriptionCommitPath": "{path} · コミット {commit}", - "diffDescriptionCommit": "コミット {commit}", - "diffTitleConflictFile": "競合 · {name}", - "diffDescriptionConflict": "{path} · ディスク vs 未保存" - }, - "chat": { - "acpConnections": { - "actions": { - "openAgentsSettings": "エージェント設定を開く", - "retry": "再試行" - }, - "agentsSetupHint": "インストール管理は「設定 > エージェント」を開いてください。", - "withSetupHint": "{message}\n{hint}", - "blocked": { - "missingConfig": "現在のエージェント設定を読み取れません。", - "disabled": "{agent} はエージェント設定で無効になっています。接続前に有効化してください。", - "unavailable": "{agent} は現在のプラットフォームでは利用できません。", - "sdkMissing": "{agent} SDK がインストールされていません", - "adapterMissing": "{agent} の ACP アダプターがインストールされていません" - }, - "backendErrors": { - "initializeTimeout": "{agent} の接続ハンドシェイクがタイムアウトしました(60 秒以内に応答なし)。設定を開いてエージェントとネットワーク設定を確認してください。", - "mcpRejectedByAgent": "codeg の MCP コンパニオンを渡した際、{agent} がセッションを拒否しました: {message} このエージェントが MCP に対応していない場合は、設定で「MCP サポート」をオフにして再接続してください。", - "processExited": "{agent} プロセスが予期せず終了しました。", - "spawnFailed": "{agent} の起動に失敗しました: {message}", - "downloadFailed": "{agent} のダウンロードに失敗しました: {message}", - "sessionLoadResourceNotFound": "{agent} セッションの読み込みに失敗しました。再読み込みして再試行するか、新しい会話を開始してください。", - "sessionLoadUnavailable": "{agent} はこのセッションを復元できませんでした。セッションが終了したか、エージェントが停止した可能性があります。再読み込みして再試行するか、新しい会話を開始してください。", - "turnFailedRefusal": "{agent} がこのターンの続行を拒否しました。バックエンドまたはゲートウェイのエラーが原因の可能性があります。エージェントのログを確認してください。", - "turnFailedMaxTokens": "{agent} がこのターンの最大トークン数に達しました。", - "turnFailedMaxTurnRequests": "{agent} がこのターンで許可された最大リクエスト数に達しました。", - "turnFailedUnknown": "{agent} が不明な停止理由でターンを終了しました。", - "grokModelSwitchIncompatibleAgent": "{agent} は既存の会話ではこのモデルに切り替えられません。新しいセッションを開始して使用してください。", - "turnFailedEmpty": "{agent} は応答を生成せずにターンを終了しました。", - "turnFailedEmptyProtocol": "{agent} の出力を codeg が解析できませんでした。エージェントのバージョンがプロトコルと一致していない可能性があります。", - "turnFailedEmptyMetadata": "{agent} はこのターンでステータス更新(計画 / モード / 使用量)のみを送信し、応答はありませんでした。", - "detailsInAlerts": "ステータスバーのアラートを開き、詳細を展開するとエージェントの出力を確認できます。" - }, - "unableReadAgentConfig": "エージェント設定を読み取れません: {message}", - "connectFailedTitle": "{agent} の接続に失敗しました", - "toolFallbackTitle": "ツール", - "eventErrorTitle": "エージェントエラー", - "notificationTurnComplete": "{agent} の応答が完了しました", - "notificationError": "{agent} エラー:{message}", - "claudeApiRetry": { - "fallbackError": "authentication_failed", - "retryingWithMax": "再試行中 {attempt}/{max}", - "retryingAttempt": "再試行中({attempt} 回目)", - "retrying": "再試行中", - "nextRetryIn": "{seconds}秒後に再試行", - "line": "{error}{status} · {retry}", - "lineWithDelay": "{error}{status} · {retry}、{delay}", - "httpStatus": " (HTTP {status})" - }, - "configOptionAdjusted": "{agent} は{option}を {requested} ではなく {actual} にしました" - }, - "connectionLifecycle": { - "tasks": { - "connectingTitle": "{agent} に接続中", - "connectingDescription": "接続を確立しています", - "loadingSelectorsTitle": "{agent} のセレクターを読み込み中", - "loadingSelectorsDescription": "モードとセッション設定オプションを取得しています", - "initSessionTitle": "{agent} セッションを初期化中", - "initSessionDescription": "セッションを作成し設定を読み込んでいます" - }, - "errors": { - "connectionFailed": "接続に失敗しました", - "sendPromptFailed": "メッセージの送信に失敗しました: {error}" - } - }, - "shared": { - "attachedResources": "添付リソース", - "toolCallFailed": "ツール呼び出しに失敗しました" - }, - "messageThread": { - "emptyTitle": "まだメッセージはありません", - "emptyDescription": "会話を開始するとここにメッセージが表示されます" - }, - "chatInput": { - "connecting": "接続中...", - "agentResponding": "{agent} が応答中...", - "sendMessage": "メッセージを送信..." - }, - "messageInput": { - "askAnything": "何でも質問してください...", - "removeAttachmentAria": "{name} を削除", - "attachFiles": "ファイルを添付", - "addActions": "追加", - "quickMessages": "クイックメッセージ", - "quickMessagesEmpty": "クイックメッセージはありません", - "quickMessagesLoading": "読み込み中...", - "pasteAsPlainText": "プレーンテキストとして貼り付け", - "cut": "切り取り", - "copy": "コピー", - "selectAll": "すべて選択", - "pasteUnavailable": "クリップボードを読み取れませんでした。Ctrl/⌘V で貼り付けてください。", - "clipboardWriteFailed": "クリップボードに書き込めませんでした。キーボードショートカットをご利用ください。", - "quickMessageUntitled": "無題", - "liveFeedback": "ライブフィードバック", - "liveFeedbackDisabledHint": "エージェントの作業中に送信できます", - "dropFilesToAttach": "ファイルをドロップして添付", - "loadingSettings": "設定を読み込み中...", - "loadingMode": "モードを読み込み中...", - "modeLabel": "モード", - "toggleOn": "オン", - "toggleOff": "オフ", - "agentSettings": "エージェント設定", - "searchModel": "モデルを検索...", - "searchModelAria": "モデルを検索", - "modelListLabel": "モデル", - "noModels": "モデルが見つかりません", - "cancel": "キャンセル", - "send": "送信", - "forkAndSend": "フォークして送信", - "queueMessage": "キューに追加", - "steerIntoTurn": "現在のターンに挿入", - "steerQueuedInstead": "代わりにキューに追加しました。次のターンで送信されます。", - "steerFailed": "現在のターンに挿入できませんでした", - "steerAttachmentsUnsupported": "テキストのみ対応です。添付ファイル付きの下書きはキューをご利用ください。", - "slashCommands": "スラッシュコマンド", - "slashSearchPlaceholder": "コマンドを検索...", - "slashSearchEmpty": "一致するコマンドがありません", - "experts": "エキスパート", - "office": "日常業務", - "research": "科学研究", - "attachLocalUpload": "ローカルファイルを添付", - "attachServerFile": "サーバーファイルを添付", - "attachUploadTooLarge": "{names} は {limit}MB のアップロード上限を超えたためスキップしました。", - "attachUploadFailed": "{names} のアップロードに失敗しました。", - "attachUploadNotAFile": "{names} は通常ファイルではなく(ディレクトリまたは特殊ファイル)、スキップされました。", - "attachUploadQuotaExceeded": "サーバーのアップロード容量が不足しているため、{names} をアップロードできませんでした。", - "attachUploadInProgress": "画像はまだアップロード中です。しばらくしてからもう一度お試しください。", - "mentionEmpty": "一致する項目がありません", - "mentionLoading": "検索中…", - "mentionListLabel": "メンション", - "mentionMore": "他にも結果があります。入力して絞り込んでください", - "mentionCount": "{count, plural, other {# 件の結果}}", - "mentionGroupFile": "ファイル", - "mentionGroupAgent": "エージェント", - "mentionGroupSession": "セッション", - "mentionGroupCommit": "コミット", - "mentionGroupSkill": "スキル" - }, - "messageQueue": { - "addToQueue": "キューに追加", - "saveEdit": "保存", - "cancelEdit": "編集をキャンセル", - "editItem": "編集", - "deleteItem": "削除" - }, - "welcomeInputPanel": { - "agentsSettingsPath": "設定 > エージェント", - "autoConnectFallback": "{path} を開いてインストールを管理してください。", - "autoConnectAppend": "{message}。{path} を開いてインストールを管理してください。", - "enableAgentFirstPlaceholder": "セッション開始前に少なくとも1つのエージェントを有効化してください...", - "prepareSessionFailed": "チャットセッションを準備できませんでした。もう一度お試しください。", - "createConversationFailed": "会話を作成できませんでした。もう一度お試しください。", - "askAnythingPlaceholder": "何でも質問してください...", - "agentNotInstalled": "{agent} はインストールされていません · クリックして Agents 設定でインストール", - "agentAdapterNotInstalled": "{agent} の ACP アダプターが未インストールです(お使いの CLI とは別物)· クリックして Agents 設定でインストール" - }, - "welcomePanel": { - "greeting": "今日は何をしましょうか?", - "tips": { - "tileTabs": "会話タブを右クリックして「タイル表示」を選ぶと、複数のセッションを並べて比較できます", - "pinTab": "会話タブをダブルクリックすると固定でき、新しい会話に自動で置き換えられなくなります", - "shortcutsNewSearch": "{newConversation} で新規会話、{searchConversations} で履歴を検索できます", - "slashAtMention": "入力欄で / を入力するとスラッシュコマンド、@ を入力するとプロジェクト内のファイルを参照できます", - "pasteDropFiles": "スクリーンショットを貼り付けたり、ファイルを入力欄にドロップするだけで添付できます", - "queueMessage": "エージェントの応答中も入力を続けられ、次のメッセージはキューに入って完了後に自動送信されます", - "draftAutoSave": "未送信の下書きは会話ごとに自動保存され、戻ったときに復元されます", - "forkSend": "送信ボタンのドロップダウンで「分岐して送信」を選ぶと、現在の地点から新しいタブに分岐できます", - "exportConversation": "会話内容を右クリックすると Markdown / HTML / 画像としてエクスポートできます", - "chatChannels": "「設定 → チャットチャネル」で Telegram / Lark / WeChat を連携すれば、スマホから続けて操作できます", - "shortcutsAuxPanel": "{toggleAuxPanel} で右側パネルを開き、このセッションで変更したファイルや Git の差分を確認できます", - "shortcutsTerminalSidebar": "{toggleTerminal} で内蔵ターミナル、{toggleSidebar} でサイドバーを切り替えできます", - "customShortcuts": "すべてのショートカットは「設定 → ショートカット」で自由に変更できます", - "webService": "「設定 → Web サービス」を有効にすると、チームメンバーが同じ codeg にブラウザでアクセスできます", - "fusionMode": "ファイルや差分を開くと、会話の横に自動で表示されます。", - "quickMessages": "入力欄横の + ボタンから「クイックメッセージ」を選ぶと、保存済みのスニペットを一発で挿入できます(「設定 → クイックメッセージ」で管理)", - "experts": "+ ボタンの「エキスパートスキル」メニューから、デバッグや計画などのプリセットロールをワンクリックで読み込めます", - "taskBoard": "ToDo タスクは作業を最後まで実行します。エージェントは専用ワークツリーで作業し、あなたは差分を確認してからマージします。", - "automations": "オートメーションは保存したプロンプトをスケジュール実行します(毎晩のレビューなど)。実行ごとに専用ワークツリーを使うこともできます。", - "tokenUsage": "ステータスバーの会話数をクリックするとトークン使用量が開き、日付・エージェント・モデル・フォルダー別の内訳を確認できます。", - "mentionTargets": "@ で参照できるのはファイルだけではありません。別のエージェントをメンションしてサブタスクを任せたり、過去のセッション・コミット・スキルを参照したりできます。", - "splitGroups": "タブを右クリックして「右に分割」または「下に分割」を選ぶと、2 つの会話をそれぞれのペインで開いたままにできます。", - "worktrees": "ブランチボタンから「新規ワークツリー」を選ぶと、複数のエージェントが同じリポジトリで互いのファイルを上書きせずに並行作業できます。", - "importSessions": "すでにターミナルで実行したセッションは、フォルダーのメニューにある「ローカルセッションをインポート」で codeg に取り込めます。", - "subSessions": "エージェントが委任すると、サブセッションがサイドバーの親セッションの下に入れ子で表示されます。行を展開すれば、それぞれの作業を追えます。", - "liveFeedback": "「+」メニューのライブフィードバックを使えば、エージェントが実行中のターンに、中断させずにメモを差し込めます。", - "skillPacks": "設定 → スキルパックには、コーディング専門家・科学研究・オフィス作業のスキルがまとまっています。エージェントごとに有効化できます。", - "modelProviders": "設定 → モデルプロバイダーでは自分の API キーやエンドポイントを登録でき、モデルは入力欄からそのまま切り替えられます。", - "workspaceBackground": "設定 → 外観では、ワークスペースの背景画像・パネルの不透明度・アプリのフォントを変更できます。" - }, - "quickActions": { - "excel": "Excel ブック", - "excelDesc": "データ表・数式・グラフ", - "word": "Word 文書", - "wordDesc": "報告書・手紙・メモ", - "ppt": "プレゼン資料", - "pptDesc": "プロ仕様のスライド", - "pitchDeck": "ピッチデック", - "pitchDeckDesc": "主要指標付きの資金調達資料", - "morph": "Morph アニメ", - "morphDesc": "映画的なスライド遷移", - "morph3d": "3D Morph", - "morph3dDesc": "3D モデルとカメラワーク", - "academic": "学術論文", - "academicDesc": "引用と構成のある研究論文", - "financial": "財務モデル", - "financialDesc": "財務諸表・DCF・予測", - "dashboard": "データダッシュボード", - "dashboardDesc": "データから KPI と分析を生成", - "prompts": { - "excel": "次の要件で Excel ブックを作成してください:\n\n[データ・表・数式・グラフをここに記述]", - "word": "次の要件で Word 文書を作成してください:\n\n[文書の内容・構成・書式をここに記述]", - "ppt": "次の要件で PowerPoint プレゼンを作成してください:\n\n[スライド・内容・デザインをここに記述]", - "pitchDeck": "次の要件で資金調達のピッチデックを作成してください:\n\n[会社・調達ラウンド・主要指標をここに記述]", - "morph": "Morph トランジションアニメーション付きのプレゼンを作成してください:\n\n[プレゼンのテーマと希望する視覚効果をここに記述]", - "morph3d": "GLB モデルとカメラワーク付きの 3D Morph プレゼンを作成してください:\n\n[テーマと 3D ビジュアルの構想をここに記述]", - "academic": "次の要件で Word の学術論文を執筆してください:\n\n[研究テーマ・手法・主要な発見をここに記述]", - "financial": "次の要件で Excel の財務モデルを作成してください:\n\n[財務諸表・予測・分析をここに記述]", - "dashboard": "次の要件で Excel のデータダッシュボードを作成してください:\n\n[データソース・KPI・グラフをここに記述]", - "scientific-brainstorming": "研究の方向性をブレインストーミングしてください。分野横断のつながりを探り、前提を問い直し、有望な空白を見つけます。検討している領域:", - "hypothesis-generation": "これらの観察を検証可能な仮説に変換してください。明確な予測、妥当なメカニズム、検証実験を示します。私の観察:", - "experimental-design": "データ収集前に厳密な実験を設計してください。デザイン、無作為化、対照、交絡の回避方法を含めます。研究したいこと:", - "statistical-power": "必要なサンプルサイズを求めてください。私のデザインについて検出力分析(効果量・有意水準・検出力)を進めます。詳細:", - "statistical-analysis": "このデータを適切に分析してください。適切な検定の選択、前提の確認、効果量の報告、結果の記述を行います。データと問い:", - "exploratory-data-analysis": "私のデータファイルを探索的に分析してください。構造・品質・注目すべきパターンを要約し、次のステップを提案します。ファイル:", - "scientific-visualization": "出版品質の図を作成してください。明確なレイアウト、誠実なエラーバー、色覚に配慮した配色、ジャーナル書式を用います。示したい内容:", - "scientific-critical-thinking": "この研究や主張を批判的に評価してください。エビデンスの質を評価し、バイアスや交絡を見抜き、結論を吟味します。対象:", - "paper-lookup": "学術データベースから関連論文とオープンアクセス全文を探し、再利用できる引用も示してください。探しているもの:" - }, - "paper-lookup": "論文検索", - "paper-lookupDesc": "10 の学術 API(PubMed、arXiv、OpenAlex、Crossref…)で論文・引用・オープンアクセス全文を検索。", - "scientific-critical-thinking": "批判的思考", - "scientific-critical-thinkingDesc": "科学的主張とエビデンスの質を評価。バイアスや交絡を見抜き、GRADE やバイアスリスク枠組みを適用。", - "scientific-visualization": "科学的可視化", - "scientific-visualizationDesc": "出版品質の図。マルチパネル配置、有意差注釈、ジャーナル固有の書式に対応。", - "exploratory-data-analysis": "探索的データ解析", - "exploratory-data-analysisDesc": "200 以上の形式の科学データファイルを自動探索し、品質指標とレポートを生成。", - "statistical-analysis": "統計解析", - "statistical-analysisDesc": "ガイド付き統計解析。検定の選択、前提確認、効果量、APA 形式の報告に対応。", - "statistical-power": "統計的検出力", - "statistical-powerDesc": "サンプルサイズと検出力の分析。必要な被験者数、最小検出可能効果、検出力曲線を算出。", - "experimental-design": "実験計画", - "experimental-designDesc": "データ収集前に厳密な研究を設計。無作為化・ブロック化・対照・要因/DOE 配置に対応。", - "hypothesis-generation": "仮説生成", - "hypothesis-generationDesc": "観察を検証可能な仮説に変換し、予測・メカニズム・検証実験を提示します。", - "scientific-brainstorming": "科学的ブレインストーミング", - "scientific-brainstormingDesc": "自由な研究アイデア出し。分野横断のつながりを探り、前提を問い直し、研究の空白を見つけます。", - "tabs": { - "office": "日常業務", - "coding": "コード開発", - "research": "科学研究" - }, - "coding": { - "brainstormingDesc": "着手前に意図と要件を整理", - "debuggingDesc": "修正の前に根本原因を特定", - "writingSkillsDesc": "再利用可能なスキルを作成・編集・検証" - }, - "notEnabled": { - "title": "「{skill}」スキルは {agent} でまだ有効になっていません", - "description": "設定で有効にすると、ここで使用できます。", - "action": "有効にする", - "hint": "スキルが無効です" - }, - "scrollPrev": "前のスキルを表示", - "scrollNext": "次のスキルを表示" - } - }, - "agentSelector": { - "noEnabledAgents": "有効なエージェントがありません", - "openAgentsSettings": "エージェント設定を開く", - "notInstalled": "未インストール", - "moreAgents": "他のエージェント({count})" - }, - "subAgentOverlay": { - "title": "サブエージェント", - "collapsedSummary": "サブエージェント {count}", - "collapseAria": "サブエージェントを折りたたむ" - }, - "agentPlanOverlay": { - "title": "エージェントプラン", - "collapsePlanAria": "プランを折りたたむ", - "collapsedSummary": "計画 {completed}/{total}", - "status": { - "completed": "完了", - "inProgress": "進行中", - "pending": "保留", - "unknown": "不明" - }, - "priority": { - "high": "高", - "medium": "中", - "low": "低", - "unknown": "不明" - } - }, - "permissionDialog": { - "subtitle": "エージェントがこのターンを続行するための許可を要求しています。", - "queuedCount": "他 {count} 件待機中", - "kindFallbackTool": "ツール", - "command": "コマンド", - "cwd": "作業ディレクトリ: {cwd}", - "filesSummary": "ファイル: {count}", - "moreFiles": "+{count} 件の追加ファイル", - "plan": "計画", - "allowedActions": "許可されたアクション", - "targetMode": "対象モード: {mode}", - "optionGrants": "各選択肢が許可する内容", - "changeScopeSession": "このセッション", - "changeScopeProcess": "この実行", - "changeScopeUser": "ユーザー設定に保存", - "changeScopeProject": "プロジェクト設定に保存", - "changeScopeProjectLocal": "ローカルプロジェクト設定に保存", - "changeScopePersistent": "永続的に保存" - }, - "questionDialog": { - "title": "エージェントが質問しています", - "placeholder": "回答を入力...", - "send": "送信" - }, - "messageBranch": { - "previousBranchAria": "前のブランチ", - "nextBranchAria": "次のブランチ", - "pageOf": "{current} / {total}" - }, - "terminal": { - "title": "ターミナル", - "running": "実行中" - }, - "reasoning": { - "thinking": "考え中…", - "thoughtForFewSeconds": "考えた", - "thoughtForSeconds": "考えた" - }, - "linkSafety": { - "errorCannotOpen": "ローカルファイルを開けません", - "errorNoWorkspace": "現在アクティブなワークスペースフォルダがありません。", - "errorFailedOpen": "ローカルファイルを開けませんでした", - "errorFailedLink": "リンクを開けませんでした", - "errorUnsupportedLinkProtocol": "このリンクプロトコルはサポートされていません。" - }, - "fileActions": { - "openInFinder": "Finderで開く", - "openInExplorer": "エクスプローラーで開く", - "openInFileManager": "ファイルマネージャーで開く", - "copyRelativePath": "相対パスをコピー", - "copyAbsolutePath": "絶対パスをコピー", - "pathCopied": "パスをコピーしました", - "copyPathFailed": "パスのコピーに失敗しました", - "openFailed": "ローカルファイルを開けませんでした" - }, - "messageList": { - "attachedResources": "添付リソース", - "loading": "読み込み中...", - "loadEarlier": "以前のメッセージを読み込む", - "loadingEarlier": "以前のメッセージを読み込み中…", - "error": "エラー: {message}", - "errorTitle": "セッションの読み込みに失敗しました", - "errorActionReload": "再読み込み", - "errorActionNewSession": "新規会話", - "emptyConversation": "この会話にはメッセージがありません。", - "systemMessage": "システムメッセージ", - "copyMessage": "コピー", - "copied": "コピー済み", - "downloadImage": "画像をダウンロード", - "downloadFailed": "ダウンロードに失敗しました: {message}", - "imageGeneration": "画像生成", - "imageGenerationPending": "画像を生成中…", - "imageGenerationFailed": "画像生成に失敗しました", - "model": "モデル", - "tokenStats": "トークン使用量", - "tokenInput": "入力", - "tokenOutput": "出力", - "tokenCacheRead": "キャッシュ読取", - "tokenCacheWrite": "キャッシュ書込", - "duration": "所要時間", - "completedAt": "完了時刻", - "jumpToPreviousUserMessage": "前のユーザーメッセージへ", - "showMore": "もっと見る", - "showLess": "折りたたむ" - }, - "liveTurnStats": { - "thinking": "考え中...", - "streaming": "ストリーミング中", - "elapsedHours": "{value}時間", - "elapsedMinutes": "{value}分", - "elapsedSeconds": "{value}秒", - "outputSpeedAria": "推定出力速度", - "outputSpeedTooltip": "推定出力速度(テキスト + 思考)" - }, - "jsonTree": { - "viewRaw": "生の JSON を表示", - "viewTree": "ツリー表示", - "fields": "{count} 個のフィールド", - "items": "{count} 件" - }, - "tool": { - "parameters": "パラメーター", - "error": "エラー", - "result": "結果", - "status": { - "approvalRequested": "承認待ち", - "approvalResponded": "応答済み", - "inputAvailable": "実行中", - "inputStreaming": "保留中", - "outputAvailable": "完了", - "outputDenied": "拒否", - "outputError": "エラー" - } - }, - "toolCallBlock": { - "tool": "ツール", - "error": "エラー", - "result": "結果" - }, - "delegation": { - "subAgentRunning": "サブエージェント実行中…", - "noDetail": "No detail available yet.", - "unknownAgent": "サブエージェント", - "openDetail": "会話を表示", - "detailTitle": "サブエージェントの会話", - "detailDescription": "委任されたサブエージェントの会話を読み取り専用で表示します。", - "waitForResult": "タスク {task} の実行結果を待機中", - "waitForResultNoTask": "タスクの実行結果を待機中", - "cancelTask": "タスク {task} をキャンセル中", - "cancelTaskNoTask": "タスクをキャンセル中", - "resultPageOf": "{current} / {total}", - "prevResult": "前の結果", - "nextResult": "次の結果", - "noResultText": "このチェックでは結果がありません", - "status": { - "starting": "起動中", - "running": "実行中", - "checked": "確認済み", - "waiting": "承認待ち", - "ok": "完了", - "err": { - "default": "失敗", - "delegation_disabled": "無効", - "depth_limit": "深さ上限", - "invalid_agent_type": "不正なエージェント", - "spawn_failed": "起動失敗", - "send_failed": "送信失敗", - "timeout": "タイムアウト", - "canceled": "キャンセル済み", - "child_refusal": "サブエージェント拒否", - "child_max_tokens": "サブエージェント: トークン上限", - "child_max_turn_requests": "サブエージェント: 要求上限", - "child_empty": "サブエージェント応答なし", - "child_unknown": "サブエージェント: エラー", - "unknown": "不明なタスク" - } - } - }, - "contentParts": { - "showingTailOutput": "パフォーマンスのため、ストリーミング中は末尾出力を表示しています。", - "result": "結果", - "unknown": "不明", - "inputTruncated": "入力が切り詰められました — diff が不完全な可能性があります。", - "replaceAll": "すべて置換", - "filesCount": "ファイル: {count}", - "update": "更新", - "moreFiles": "+{count} 件の追加ファイル", - "timeoutMs": "タイムアウト: {timeout}ms", - "backgroundTrue": "バックグラウンド: true", - "scriptToolCalls": "{count} 個のツールを呼び出し", - "offset": "オフセット: {offset}", - "limit": "上限: {limit}", - "pages": "ページ: {pages}", - "mode": "モード: {mode}", - "cell": "セル: {cell}", - "shellSession": "セッション {id}", - "pathLabel": "パス:", - "globLabel": "Glob パターン:", - "typeLabel": "タイプ:", - "outputLabel": "出力:", - "caseInsensitive": "大文字小文字を区別しない", - "multiline": "複数行", - "promptLabel": "プロンプト", - "subjectLabel": "件名", - "taskLabel": "タスク", - "nameLabel": "名前:", - "agentPromptLabel": "プロンプト", - "agentModelLabel": "モデル", - "agentRunning": "実行中...", - "agentLiveTranscript": "ライブアクティビティ", - "agentProgressTools": "{count} 件のツール呼び出し", - "agentProgressTurns": "{count} ターン", - "agentProgressContext": "コンテキスト {pct}%", - "agentSessionAction": "サブエージェントのセッションを表示", - "agentSessionTitle": "サブエージェントのセッション", - "agentSessionLoading": "サブエージェントの記録を読み込んでいます…", - "agentSessionEmpty": "サブエージェントはまだ何も書き込んでいません。", - "agentFallbackTitle": "サブエージェント起動中…", - "agentCodexLaunchOnly": "起動しました。Codex はこのサブエージェントの進捗をこれ以上通知しません。結果はこの会話のメッセージとして届きます。", - "agentStatsBash": "コマンド", - "agentStatsRead": "ファイル読取", - "agentStatsSearch": "検索", - "agentStatsEdit": "編集", - "agentStatsOther": "その他", - "goal": { - "title": "目標:", - "titleWithStatus": "目標 {status}", - "objective": "目標", - "statusLabel": "ステータス", - "tokensUsed": "使用 tokens", - "budget": "予算", - "remaining": "残り", - "elapsed": "経過時間", - "tokens": "tokens", - "pause": "一時停止", - "clear": "クリア", - "status": { - "active": "実行中", - "paused": "一時停止", - "blocked": "ブロック中", - "usageLimited": "使用量制限", - "budgetLimited": "予算制限", - "complete": "完了", - "limited": "上限到達" - } - }, - "field": { - "file": "ファイル", - "notebook": "ノートブック", - "command": "コマンド", - "old": "旧", - "new": "新", - "pattern": "パターン", - "path": "パス", - "query": "クエリ", - "url": "URL:", - "description": "説明", - "content": "内容", - "source": "ソース", - "prompt": "プロンプト", - "subject": "件名", - "taskId": "タスク ID", - "status": "状態", - "skill": "Skill", - "args": "引数", - "offset": "オフセット", - "limit": "上限", - "glob": "Glob パターン", - "type": "タイプ", - "output": "出力", - "replaceAll": "すべて置換", - "language": "言語", - "timeout": "タイムアウト", - "background": "バックグラウンド", - "agentType": "エージェント種別", - "library": "ライブラリ", - "libraryId": "ライブラリ ID" - }, - "title": { - "edit": "編集", - "command": "コマンド", - "script": "スクリプト", - "waitCommand": "待機 {command}", - "waitCell": "セッション {id} を待機", - "terminateCommand": "停止 {command}", - "terminateCell": "セッション {id} を停止", - "stdinChars": "入力 {chars}", - "todoWrite": "TodoWrite(タスク更新)", - "read": "読み取り", - "write": "書き込み", - "notebookEdit": "NotebookEdit(ノート編集)", - "editFiles": "編集 ({count} 件のファイル)", - "editWithTarget": "{target} を編集", - "readWithTarget": "{target} を読み取り", - "writeWithTarget": "{target} に書き込み", - "notebookEditWithTarget": "NotebookEdit({target})", - "globWithPattern": "Glob パターン {pattern}", - "listFilesWithPath": "ファイル一覧 {path}", - "grepWithPattern": "Grep パターン {pattern}", - "taskCreateWithSubject": "タスク作成: {subject}", - "taskUpdateWithStatus": "タスク更新 #{id} -> {status}", - "taskUpdate": "タスク更新 #{id}", - "webFetchWithUrl": "WebFetch({url})", - "webSearchWithQuery": "WebSearch({query})", - "todosProgress": "タスク ({done}/{total})", - "skillWithName": "Skill: {name}", - "genericWithContext": "{tool}({context})" - }, - "search": { - "noMatches": "一致する結果なし", - "matchSummary": "{matches} 件の一致 · {files} 件のファイル", - "fileSummary": "{files} 件のファイル", - "moreResults": "他に {count} 件の結果は非表示" - }, - "toolGroup": { - "search": "{count} 件を検索", - "command": "{count} 件のコマンドを実行", - "read": "ファイルを {count} 回読み取り", - "memory": "{count} 件の記憶を呼び出し", - "edit": "ファイルを {count} 回編集", - "fetch": "{count} 件のリソースを取得", - "think": "{count} 回思考", - "todo": "{count} 件の TODO を更新", - "task": "{count} 件のタスクを実行", - "other": "{count} 件のツールを使用", - "errorSuffix": "{count} 件失敗", - "joiner": " · " - }, - "planMode": { - "entered": "計画モードを開始", - "planLabel": "計画", - "reviewApproved": "計画を承認 — 実行します", - "reviewKept": "プランモードを維持", - "reviewPending": "計画の判断待ち", - "submitted": "計画を送信しました", - "switched": "モードを切り替え" - }, - "backgroundTask": { - "title": "バックグラウンドタスク", - "titleWithId": "バックグラウンドタスク · {id}", - "running": "実行中", - "completed": "完了", - "failed": "失敗", - "stopped": "停止しました", - "exitCode": "終了コード {code}", - "polledTimes": "{count} 回ポーリング", - "runningInBackground": "バックグラウンド", - "launchNote": "バックグラウンドで実行中 · {id}" - }, - "codexScript": { - "outputMissing": "codex がスクリプト出力を切り詰めた際にこのコマンドの区切り行が失われたため、出力を割り当てられませんでした。", - "sharedWith": "この範囲には {commands} の出力も含まれます — 区切り行が codex により切り捨てられました。", - "truncated": "切り詰め済み" - } - }, - "messageNav": { - "title": "メッセージナビ", - "collapse": "メッセージナビを閉じる", - "collapsedSummary": "メッセージ {count}", - "fileCount": "{count, plural, one {# 個のファイル} other {# 個のファイル}}", - "remove": "削除", - "noDiffDataAvailable": "{filePath} の差分データがありません" - }, - "replyArtifacts": { - "title": "変更されたファイル", - "fileCount": "{count, plural, one {# 個のファイル} other {# 個のファイル}}", - "newFilesTitle": "新規ファイル", - "revealInFolder": "ファイルマネージャーで表示", - "openFile": "{filePath} を開く", - "openInEditor": "エディタで開く", - "remove": "削除", - "noDiffDataAvailable": "{filePath} の差分データがありません" - }, - "askQuestion": { - "title": "エージェントが選択を求めています", - "subtitle": "回答したら送信してください。いつでもスキップできます", - "recommended": "推奨", - "other": "その他", - "otherPlaceholder": "回答を入力…", - "singleSelect": "単一選択", - "multiSelect": "複数選択", - "skip": "スキップ", - "next": "次へ", - "submit": "送信", - "submitError": "送信できませんでした。もう一度お試しください。" - }, - "planApproval": { - "title": "エージェントが計画を提示しました — 確認してください", - "emptyPlan": "エージェントは計画を作成しませんでした。承認して実装を開始するか、変更を依頼してください。", - "approve": "承認して開始", - "requestChanges": "変更を依頼", - "abandon": "破棄", - "feedbackPlaceholder": "何を変更しますか?", - "sendChanges": "送信", - "cancel": "キャンセル", - "submitError": "送信できませんでした。もう一度お試しください。" - }, - "feedbackCheckResult": { - "count": "フィードバック {count} 件", - "expand": "すべてのフィードバックを表示", - "collapse": "折りたたむ", - "errorTitle": "フィードバックの確認に失敗しました" - }, - "askQuestionResult": { - "title": "質問", - "answeredLabel": "質問と回答:", - "awaiting": "回答をお待ちしています…", - "declined": "この質問をスキップしました — エージェントが独自に判断して進めました。", - "noSelection": "選択なし" - }, - "configStale": { - "agentConfigTitle": "エージェント設定が更新されました", - "modelProviderTitle": "モデルプロバイダーが更新されました", - "description": "このセッションは以前の設定のままです。再接続すると適用されます(会話履歴は保持されます)。", - "reconnect": "再接続して適用", - "reconnecting": "再接続中…", - "reconnectDisabledDuringTurn": "現在のターンが完了すると再接続できます", - "dismiss": "閉じる", - "reconnectFailed": "セッションの再接続に失敗しました", - "applied": "新しい設定を適用しました" - }, - "piProjectTrust": { - "title": "このプロジェクトには pi リソースが含まれています", - "description": "pi はリポジトリ自身の .pi ファイルを読み込んでいません。確認して判断してください。", - "descriptionExecutable": "リポジトリには pi 拡張機能が含まれており、起動時にコードを実行します。pi はまだ読み込んでいません。判断する前に確認してください。", - "review": "確認…", - "dismiss": "閉じる", - "dialogTitle": "このプロジェクトの pi リソースを信頼しますか?", - "dialogDescription": "フォルダーを信頼した場合にのみ、pi はリポジトリ自身の .pi ファイルを読み込みます。このリポジトリの内容を信頼できる場合にのみ許可してください。", - "executionWarning": "拡張機能はコードです。このフォルダーを信頼すると、メッセージを送信する前に、リポジトリの拡張機能が pi の起動時にあなたの権限で実行されます。", - "scopeNote": "この判断は pi の trust.json に保存され、その配下のすべてのフォルダーに適用されます。ターミナルで自分で pi を実行するときにも使われます。後から「設定 → エージェント → Pi」で変更できます。", - "trust": "プロジェクトを信頼", - "decline": "読み込まないままにする", - "disabledDuringTurn": "現在のターンが終了すると利用できます", - "trustedToast": "プロジェクトを信頼しました — pi がリソースを読み込むよう再接続しました", - "declinedToast": "プロジェクトのリソースは読み込まれません", - "saveFailed": "プロジェクトの信頼設定の保存に失敗しました", - "grantTitle": "このプロジェクトは既に信頼されています", - "grantDescription": "pi はこのリポジトリ自身の .pi ファイルを読み込みます。何が許可されるか確認してください。", - "grantInheritedDescription": "親フォルダーが信頼されているため、pi はこのリポジトリ自身の .pi ファイルを読み込みます。何が許可されるか確認してください。", - "grantDialogTitle": "このプロジェクトの pi リソースは信頼されています", - "grantDialogDescription": "pi はこのリポジトリ自身の .pi ファイルの読み込みを許可されています。以前のバージョンの codeg はフォルダーを開いた時点で自動的に許可していたため、確認を求められていない可能性があります。", - "grantExecutionWarning": "拡張機能はコードです。リポジトリの拡張機能は、メッセージを送信する前に pi の起動時にあなたの権限で実行されます。", - "inheritedFrom": "信頼の由来", - "revoke": "信頼を取り消す", - "keepTrusted": "信頼を維持", - "revokedToast": "信頼を取り消しました — 再接続したため pi はプロジェクトのリソースを読み込みません", - "trustedNoReconnect": "プロジェクトを信頼しました — pi の次回起動時に適用されます", - "revokedNoReconnect": "信頼を取り消しました — pi の次回起動時に適用されます" - }, - "collabAgent": { - "title": "サブエージェント", - "errorTitle": "サブエージェントのタスクが失敗しました", - "statesLabel": "サブエージェント", - "statusRunning": "実行中", - "statusCompleted": "完了", - "statusFailed": "失敗", - "statusPending": "起動中", - "statusInterrupted": "中断", - "statusClosed": "終了", - "statusNotFound": "見つかりません", - "opSpawn": "サブエージェントを起動中", - "opWait": "サブエージェントの結果を取得中", - "opClose": "サブエージェントを終了中", - "opResume": "サブエージェントを再開中" - }, - "contextCompaction": { - "compacting": "コンテキストを圧縮しています…", - "compacted": "コンテキストを圧縮しました", - "compactedTokens": "コンテキストを圧縮 · {before} → {after} トークン", - "failed": "コンテキストの圧縮に失敗しました" - }, - "sessionFailure": { - "category": { - "connection": "接続の問題", - "access": "アクセスの問題", - "limit": "上限に到達", - "request": "リクエスト拒否", - "service": "サービスの問題", - "unknown": "セッションの問題" - }, - "action": { - "retry": "再試行", - "login": "サインイン", - "newSession": "新しいセッション" - }, - "recovered": "回復済み", - "retryUnavailable": "再送信できるメッセージがありません。", - "toggleDetails": "詳細の切り替え" - }, - "backgroundTasks": { - "running": "{count} 件のバックグラウンドタスクを実行中", - "settling": "バックグラウンド結果を同期中…", - "settledFallback": "バックグラウンドタスクが終了しました({status})", - "cardRunning": "バックグラウンドで実行中", - "cardLaunchedPending": "バックグラウンドタスクを開始しました", - "cardCompleted": "バックグラウンドタスクが完了しました", - "cardFinishedWithStatus": "バックグラウンドタスクが終了しました({status})", - "cardResultPending": "結果はまだ返っていません" - }, - "proposedPlan": { - "title": "提案された計画", - "planning": "計画中…" - } - }, - "diffPreview": { - "mode": { - "added": "追加", - "deleted": "削除", - "renamed": "名前変更", - "modified": "変更" - }, - "hunkLabel": "ハンク {index}", - "loadingHunk": "Hunk を読み込み中...", - "noDiffData": "Diff データがありません", - "showRemainingLines": "残り {count} 行を表示" - }, - "conversationContextBar": { - "folderTitle": "作業フォルダ", - "branchTitle": "作業ブランチ", - "searchFolder": "Search folder...", - "searchBranch": "Search branch...", - "noFolders": "No folders", - "noBranches": "No branches", - "noBranch": "(no branch)", - "chatModeLabel": "チャットモード", - "commit": "Commit", - "push": "Push", - "merge": "Merge", - "toasts": { - "folderChanged": "Switched to {name}", - "openFolderFailed": "Failed to open folder", - "switchedToChatMode": "チャットモードに切り替えました", - "openStashFailed": "Failed to open stash window", - "openMergeFailed": "Failed to open merge window" - } - }, - "cloneDialog": { - "title": "リポジトリをクローン", - "repositoryUrl": "リポジトリ URL", - "repositoryUrlPlaceholder": "https://github.com/user/repo.git", - "directory": "ディレクトリ", - "directoryPlaceholder": "保存先ディレクトリを選択...", - "browseDirectory": "ディレクトリを参照", - "cancel": "キャンセル", - "clone": "クローン", - "clonePath": "クローンパス: {path}" - }, - "toasts": { - "cloneFailed": "リポジトリのクローンに失敗しました" - } - }, - "ProjectBoot": { - "title": "プロジェクトブート", - "tabs": { - "shadcn": "shadcn", - "hyperframes": "HyperFrames" - }, - "hyperframes": { - "title": "HyperFrames 動画プロジェクト", - "subtitle": "HTML から動画を生成するプロジェクトを作成します。ワークスペースのエージェントがそれを記述・レンダリングできます。", - "resolution": "解像度", - "skillsTitle": "エージェントスキル", - "skillsDesc": "選択したエージェント向けに HyperFrames スキルをグローバル(シンボリックリンク)でインストールし、動画の作成・レンダリングを可能にします。", - "recheck": "再チェック", - "installedBadge": "インストール済み", - "skillsInstall": "スキルをインストール / 更新", - "skillsInstalling": "スキルをインストール中…", - "skillsInstalled": "HyperFrames スキルをインストールしました", - "skillsInstallFailed": "HyperFrames スキルのインストールに失敗しました" - }, - "config": { - "base": "ベース", - "style": "スタイル", - "baseColor": "ベースカラー", - "theme": "テーマ", - "chartColor": "チャートカラー", - "iconLibrary": "アイコンライブラリ", - "font": "フォント", - "fontHeading": "見出しフォント", - "menuAccent": "メニューアクセント", - "menuColor": "メニューカラー", - "radius": "角丸", - "template": "テンプレート", - "createProject": "プロジェクトを作成", - "sectionStyle": "スタイル", - "sectionColors": "カラー", - "sectionTypography": "タイポグラフィ", - "sectionInterface": "インターフェース" - }, - "preview": { - "loading": "プレビューを読み込み中..." - }, - "createDialog": { - "title": "プロジェクトを作成", - "projectName": "プロジェクト名", - "projectNamePlaceholder": "my-app", - "frameworkTemplate": "フレームワークテンプレート", - "packageManager": "パッケージマネージャー", - "saveDirectory": "保存先ディレクトリ", - "saveDirectoryPlaceholder": "ディレクトリを選択...", - "browseDirectory": "参照", - "projectPath": "プロジェクトの作成先:{path}", - "advancedOptions": "詳細オプション", - "base": "基盤ライブラリ", - "enableRtl": "RTL サポートを有効にする", - "enableRtlDescription": "右から左に書く言語(アラビア語、ヘブライ語など)のレイアウトサポートを有効にする", - "pmChecking": "確認中...", - "pmNotInstalled": "未インストール", - "cancel": "キャンセル", - "create": "作成", - "creating": "プロジェクトを作成中..." - }, - "toasts": { - "createFailed": "プロジェクトの作成に失敗しました", - "createSuccess": "プロジェクトが正常に作成されました", - "openWorkspaceFailed": "プロジェクトは作成されましたが、ワークスペースで開けませんでした" - }, - "errors": { - "directoryExists": "対象ディレクトリは既に存在します", - "commandFailed": "プロジェクト作成コマンドが失敗しました。" - } - }, - "WebServiceSettings": { - "addressSwitchHint": "切り替えても、ここに表示され開くアドレスが変わるだけです。サービスはすべてのインターフェースで待ち受けており、どのアドレスからもアクセスできます。", - "sectionTitle": "Webサービス", - "sectionDescription": "有効にするとブラウザからCodegにリモートアクセスできます", - "port": "ポート", - "status": "ステータス", - "autoStart": "自動起動", - "autoStartHint": "Codeg の起動時に Web サービスを開始", - "running": "実行中", - "stopped": "停止中", - "processing": "処理中...", - "start": "開始", - "stop": "停止", - "startFailed": "開始に失敗しました", - "stopFailed": "停止に失敗しました", - "saveConfigFailed": "Webサービス設定の保存に失敗しました", - "open": "開く", - "hide": "非表示", - "show": "表示", - "copy": "コピー", - "qrcode": "QRコード", - "qrcodeTitle": "スキャンして開く", - "qrcodeHint": "スマートフォンでスキャンして、ブラウザで Codeg を開きます", - "addressLabel": "アクセスアドレス", - "tokenLabel": "アクセストークン", - "tokenHint": "Webクライアントの初回アクセス時にこのトークンを入力してください", - "tokenPlaceholder": "空欄の場合は自動生成", - "regenerate": "再生成", - "stalePortOccupiedTitle": "ポート {port} は他のプロセスに使用されています", - "stalePortUnknownTitle": "ポート {port} の状態を確認できません", - "stalePortHint": "ポートが解放されるまで Codeg はバインドできません。上のポートを変更するか、占有しているプロセスを終了してください。", - "errors": { - "alreadyRunning": "Web サービスはすでに起動しています", - "invalidAddress": "ホストまたはポートの形式が無効です", - "portInUse": "ポート {port} はすでに使用中です。そのポートを使用しているプロセスを終了するか、別のポートを指定してください", - "permissionDenied": "権限が不足しています。1024 以上のポートを使用するか、より高い権限で実行してください", - "addressUnavailable": "このアドレスはこの端末では利用できません", - "bindFailed": "アドレスのバインドに失敗しました" - } - }, - "DirectoryBrowser": { - "title": "ディレクトリを参照", - "pathPlaceholder": "ディレクトリパスを入力...", - "goHome": "ホームディレクトリへ", - "navigateUp": "親ディレクトリへ", - "select": "選択", - "cancel": "キャンセル", - "loading": "読み込み中...", - "emptyDirectory": "このディレクトリは空です", - "errorLoadingDir": "ディレクトリの読み込みに失敗しました", - "permissionDenied": "アクセス権がありません" - }, - "ChatChannelSettings": { - "loading": "読み込み中...", - "sectionTitle": "チャットチャンネル", - "sectionDescription": "IM ボットを設定して、イベント通知やコーディング活動の照会を行います。", - "addChannel": "チャンネルを追加", - "noChannels": "チャットチャンネルはまだ設定されていません。", - "channelName": "名前", - "channelNamePlaceholder": "My Telegram Bot", - "channelType": "チャンネルタイプ", - "lark": "Lark(飛書)", - "weixin": "WeChat", - "dailyReport": "デイリーレポート", - "dailyReportTime": "送信時刻", - "nameRequired": "チャンネル名を入力してください。", - "tokenRequired": "トークンを入力してください。", - "chatIdRequired": "Chat ID を入力してください。", - "topicMode": "トピックグループモード", - "topicModeHint": "Telegram forum topics を個別の Codeg セッションとしてルーティングします。Bot は forum supergroup に参加し、topics を管理できる必要があります。", - "loadFailed": "チャンネルの読み込みに失敗しました。", - "saveFailed": "保存に失敗しました。", - "connectSuccess": "チャンネルに接続しました。", - "connectFailed": "接続に失敗しました", - "disconnectSuccess": "チャンネルを切断しました。", - "disconnectFailed": "切断に失敗しました。", - "testSuccess": "接続テストに合格しました。", - "testFailed": "接続テストに失敗しました", - "deleteSuccess": "チャンネルを削除しました。", - "deleteFailed": "チャンネルの削除に失敗しました。", - "deleteConfirmTitle": "チャンネルを削除", - "deleteConfirmMessage": "このチャンネルとメッセージログを完全に削除します。よろしいですか?", - "cancel": "キャンセル", - "delete": "削除", - "create": "作成", - "save": "保存", - "channelListTitle": "設定済みチャンネル", - "channelListDescription": "有効なチャンネルはサービス起動時に自動接続されます。", - "editChannel": "チャンネルを編集", - "editSuccess": "チャンネルを更新しました。", - "tokenPlaceholderKeep": "空欄で現在の値を維持", - "weixinScanTitle": "QRコードをスキャン", - "weixinScanDescription": "WeChatを開いてQRコードをスキャンして接続してください。", - "weixinQrcodeExpired": "QRコードの有効期限が切れました。", - "weixinRefreshQrcode": "更新", - "weixinWaitingScan": "スキャン待ち...", - "weixinPollError": "接続が不安定です。再試行中...", - "weixinReconnectNotice": "iLink プロトコルの制限により、再接続のたびにまずボットにメッセージを送信しないとイベントトリガーが有効になりません。", - "connect": "接続", - "disconnect": "切断", - "test": "接続テスト", - "tabs": { - "channels": "チャンネル", - "commands": "コマンド", - "events": "イベント", - "other": "その他" - }, - "commands": { - "title": "組み込みコマンド", - "description": "チャットチャンネルで使用可能な Bot コマンド。グループチャットではメッセージを処理するために @Bot が必要です。", - "prefixLabel": "コマンドプレフィックス", - "prefixDescription": "Bot コマンドを起動するプレフィックス、1-3 文字の英数字以外の文字(デフォルト /)。", - "prefixSaved": "コマンドプレフィックスを保存しました。", - "prefixSaveFailed": "コマンドプレフィックスの保存に失敗しました。", - "prefixInvalid": "プレフィックスは1-3文字の英数字以外の文字である必要があります。", - "save": "保存", - "folderDesc": "作業フォルダを選択", - "agentDesc": "AIエージェントを選択", - "taskDesc": "セッションを作成してタスクを実行", - "sessionsDesc": "フォルダ内のアクティブなセッション一覧", - "resumeDesc": "最近の会話 / セッションを再開", - "cancelDesc": "現在のタスクをキャンセル", - "approveDesc": "エージェントの権限リクエストを承認", - "denyDesc": "エージェントの権限リクエストを拒否", - "searchDesc": "キーワードで会話を検索", - "todayDesc": "本日のアクティビティ概要", - "statusDesc": "チャンネル接続状態", - "helpDesc": "ヘルプを表示" - }, - "events": { - "title": "イベント通知", - "description": "イベントを有効にすると、トリガーされた際にチャンネルにプッシュされます。", - "turnComplete": "ターン完了", - "turnCompleteDesc": "エージェントのターンが終了した時", - "error": "エージェントエラー", - "errorDesc": "エージェントがエラーに遭遇した時", - "permissionRequest": "権限リクエスト", - "permissionRequestDesc": "エージェントが操作の権限を要求した時", - "questionRequest": "エージェントからの質問", - "questionRequestDesc": "エージェントが質問したとき", - "userPromptSent": "ユーザーメッセージ", - "userPromptSentDesc": "メッセージを送信したとき(通知に本文が含まれます)", - "saved": "イベントフィルターを更新しました。", - "saveFailed": "イベントフィルターの保存に失敗しました。", - "loadFailed": "設定の読み込みに失敗しました。", - "retry": "再試行", - "webhooksTitle": "Webhook", - "webhooksDescription": "有効なイベントの発生時に、1 つ以上の URL へ JSON を POST します。上のイベントフィルターは Webhook にも適用されます。", - "webhookUrlPlaceholder": "https://example.com/webhook", - "addWebhook": "Webhook を追加", - "removeWebhook": "Webhook を削除", - "webhookSave": "保存", - "webhooksSaved": "Webhook を保存しました。", - "webhooksSaveFailed": "Webhook の保存に失敗しました。", - "webhookInvalidUrl": "有効な http(s) URL を入力してください。", - "docsTitle": "リクエスト形式", - "docsMethod": "メソッド", - "docsContentType": "Content-Type", - "docsNote": "有効な各イベントはすべての URL に配信されます。Webhook はデバウンスされず、上のイベントフィルターが適用されます。", - "editWebhook": "Webhook を編集", - "enableWebhook": "Webhook を有効化", - "webhookDuplicate": "この URL は既に設定されています。", - "cancel": "キャンセル", - "webhooksEmpty": "Webhook はまだ設定されていません。", - "deleteWebhookTitle": "Webhook を削除", - "deleteWebhookMessage": "この Webhook を削除しますか?このURLにイベントは配信されなくなります。", - "delete": "削除" - }, - "language": { - "title": "メッセージ言語", - "description": "イベント通知、コマンド応答、日次レポートをチャットチャンネルに送信する際に使用する言語。", - "saved": "メッセージ言語を保存しました。", - "saveFailed": "メッセージ言語の保存に失敗しました。", - "en": "英語", - "zh-cn": "簡体字中国語", - "zh-tw": "繁体字中国語", - "ja": "日本語", - "ko": "韓国語", - "es": "スペイン語", - "de": "ドイツ語", - "fr": "フランス語", - "pt": "ポルトガル語", - "ar": "アラビア語" - } - }, - "ModelProviderSettings": { - "sectionTitle": "モデルプロバイダー", - "sectionDescription": "エージェントのAPIプロバイダー認証情報を管理します。", - "filterAll": "すべて", - "providerListTitle": "設定済みプロバイダー", - "addProvider": "プロバイダーを追加", - "editProvider": "プロバイダーを編集", - "noProviders": "モデルプロバイダーはまだ設定されていません。", - "providerName": "名前", - "providerNamePlaceholder": "例: OpenAI、Anthropic", - "apiUrl": "API URL", - "apiUrlPlaceholder": "https://api.openai.com/v1", - "apiKey": "APIキー", - "apiKeyPlaceholder": "sk-...", - "apiKeyKeepCurrent": "空欄のまま現在の値を維持", - "agentTypes": "エージェントタイプ", - "agentTypesRequired": "少なくとも1つのエージェントタイプを選択してください。", - "agentType": "エージェントタイプ", - "agentTypeRequired": "エージェントタイプを選択してください。", - "agentTypeImmutableHint": "エージェントタイプは作成後に変更できません。", - "model": "モデル", - "modelPlaceholderCodex": "gpt-5.6-sol / gpt-5.5", - "modelPlaceholderGemini": "gemini-3-pro-preview", - "claudeMainModel": "メインモデル", - "claudeReasoningModel": "推論モデル(思考)", - "claudeHaikuDefaultModel": "デフォルトの Haiku モデル", - "claudeSonnetDefaultModel": "デフォルトの Sonnet モデル", - "claudeOpusDefaultModel": "デフォルトの Opus モデル", - "claudeCustomModelOption": "カスタムモデル ID", - "claudeCustomModelOptionName": "カスタムモデル名", - "claudeCustomModelOptionDescription": "カスタムモデルの説明", - "claudeCustomModelOptionHint": "Claude のモデル選択メニューにカスタム項目を1つ追加します(例: カスタムゲートウェイ/プロキシ経由のモデル)。名前と説明は任意の表示用設定です。", - "nameRequired": "プロバイダー名は必須です。", - "apiUrlRequired": "API URLは必須です。", - "apiKeyRequired": "APIキーは必須です。", - "loadFailed": "プロバイダーの読み込みに失敗しました。", - "saveFailed": "変更の保存に失敗しました。", - "createSuccess": "プロバイダーを作成しました。", - "editSuccess": "プロバイダーを更新しました。", - "deleteSuccess": "プロバイダーを削除しました。", - "deleteConfirmTitle": "プロバイダーを削除", - "deleteConfirmMessage": "プロバイダー「{name}」を完全に削除しますか?", - "deleteBlockedByAgent": "{agents} がこのプロバイダーを使用中です。削除する前にリンクを解除してください。", - "cancel": "キャンセル", - "delete": "削除", - "create": "作成", - "save": "保存", - "affectedRunningSessions": "{count} 件の実行中セッションは再接続すると変更が適用されます" - }, - "SkillMatrix": { - "loading": "読み込み中…", - "searchPlaceholder": "名前・ID・説明で検索", - "empty": "表示する項目がありません。", - "emptySearch": "現在の検索に一致する項目がありません。", - "skillColumn": "スキル", - "selectAll": "表示中をすべて選択", - "selectSkill": "{name} を選択", - "everything": { - "label": "一括", - "enable": "すべて有効化(表示中)", - "disable": "すべて無効化(表示中)" - }, - "columnMenu": { - "enableAll": "すべてのスキルを有効化", - "disableAll": "すべてのスキルを無効化" - }, - "rowMenu": { - "label": "{name} の一括操作", - "enableAll": "すべてのエージェントで有効化", - "disableAll": "すべてのエージェントで無効化" - }, - "bulk": { - "selected": "{count} 件選択中", - "targetAll": "すべてのエージェント", - "targetSome": "{count} 個のエージェント", - "enable": "有効化", - "disable": "無効化", - "clear": "クリア" - }, - "confirm": { - "disableTitle": "これらのリンクを無効化しますか?", - "disableBody": "codeg が管理する {count} 件のスキルリンクを削除します。カスタムディレクトリを占有しているスキルはそのまま残ります。いつでも再び有効化できます。", - "cancel": "キャンセル", - "confirm": "無効化" - }, - "toasts": { - "loadFailed": "スキルの状態の読み込みに失敗しました", - "applyFailed": "変更の適用に失敗しました", - "enabled": "{count} 件のリンクを有効化しました", - "disabled": "{count} 件のリンクを無効化しました", - "enabledPartial": "{ok} 件を有効化、{failed} 件が失敗しました", - "disabledPartial": "{ok} 件を無効化、{failed} 件が失敗しました" - }, - "detail": { - "enableForAgents": "エージェントで有効化", - "preview": "SKILL.md プレビュー", - "loadingContent": "コンテンツを読み込み中…" - }, - "copyModeHint": "コピー済み(リンクではありません)— 更新後は最新版を取得するため再度有効化してください" - }, - "ExpertsSettings": { - "title": "エキスパートスキル", - "description": "AI コーディングエージェント向けに、厳選され実戦で検証されたスキルワークフローを有効にします。各エキスパートは superpowers プロジェクトの独立したスキルで、codeg が中央コピーを管理し、選択したエージェントにリンクします。", - "loading": "エキスパートを読み込み中…", - "loadingContent": "コンテンツを読み込み中…", - "emptyExperts": "利用可能なエキスパートがありません。アプリケーションログを確認してください。", - "emptySelection": "エキスパートを選択して内容を表示し、有効化を管理します。", - "emptySearch": "現在の検索に一致するエキスパートはありません。", - "searchPlaceholder": "名前、ID、または説明でエキスパートを検索", - "enableForAgents": "エージェントで有効化", - "noAgents": "ACP エージェントが検出されません。", - "copyModeWarning": "コピー済み(リンクなし)。codeg 更新後に最新版を取得するには再度有効化してください。", - "previewTitle": "SKILL.md プレビュー", - "categories": { - "discovery": "発見と設計", - "planning": "計画", - "execution": "実行", - "quality": "品質とテスト", - "debugging": "デバッグ", - "review": "レビューと統合", - "meta": "メタ" - }, - "states": { - "not_linked": "未有効", - "linked_to_codeg": "有効", - "linked_elsewhere": "ブロック — 別のリンクが存在", - "blocked_by_real_directory": "ブロック — カスタムスキルがこの名前を占有", - "broken": "壊れたリンク" - }, - "badges": { - "userModified": "ユーザーにより変更" - }, - "actions": { - "openCentralDir": "中央フォルダを開く", - "refresh": "更新" - }, - "toasts": { - "loadFailed": "エキスパート詳細の読み込みに失敗しました", - "enabled": "このエージェントでエキスパートを有効化しました", - "disabled": "このエージェントでエキスパートを無効化しました", - "enableFailed": "エキスパートの有効化に失敗しました", - "disableFailed": "エキスパートの無効化に失敗しました", - "openFolderFailed": "フォルダを開けませんでした" - } - }, - "ScienceSettings": { - "title": "科学研究スキル", - "description": "AI コーディングエージェント向けに厳選した科学研究スキル(仮説生成・実験計画・統計・可視化・批判的評価・文献検索)を有効化します。codeg が中央コピーを管理し、選んだエージェントに各スキルをリンクします。", - "loading": "科学研究スキルを読み込み中…", - "emptySkills": "利用可能な科学研究スキルがありません。アプリのログを確認してください。", - "searchPlaceholder": "名前・ID・説明で科学研究スキルを検索", - "categories": { - "ideation": "アイデア出し", - "design": "研究デザイン", - "analysis": "分析", - "visualization": "可視化", - "evaluation": "評価", - "literature": "文献" - }, - "states": { - "not_linked": "未有効", - "linked_to_codeg": "有効", - "linked_elsewhere": "ブロック — 別のリンクが存在", - "blocked_by_real_directory": "ブロック — カスタムスキルがこの名前を占有", - "broken": "壊れたリンク" - }, - "badges": { - "userModified": "ユーザーにより変更", - "needsKey": "APIキーが必要", - "needsSetup": "環境構築が必要な場合あり" - }, - "actions": { - "openCentralDir": "中央フォルダを開く", - "refresh": "更新" - }, - "toasts": { - "openFolderFailed": "フォルダを開けませんでした" - } - }, - "OfficeToolsSettings": { - "title": "Office ツール", - "description": "OfficeCLI スキルを管理し、Excel、Word、PowerPoint ファイルを作成します。OfficeCLI をインストールし、スキルを同期して、エージェントごとに有効化できます。", - "loadingContent": "コンテンツを読み込み中…", - "emptySkills": "スキルがありません。OfficeCLI をインストールしてスキルを同期してください。", - "emptySelection": "スキルを選択して内容を確認し、有効化を管理します。", - "emptySearch": "検索に一致するスキルがありません。", - "searchPlaceholder": "名前、ID、説明でスキルを検索", - "enableForAgents": "エージェントに対して有効化", - "noAgents": "ACP エージェントが検出されませんでした。", - "installFirst": "スキルを有効にするには、まず OfficeCLI をインストールしてください。", - "syncFirst": "コンテンツを読み込むには、まずスキルを同期してください。", - "noContent": "コンテンツがありません。", - "copyModeWarning": "コピー済み(リンクなし)。最新版を取得するには再同期してください。", - "previewTitle": "SKILL.md プレビュー", - "detection": { - "installed": "インストール済み", - "notInstalled": "未インストール", - "notRunnable": "インストール済みですが実行できません", - "installHint": "OfficeCLI をインストールして、AI エージェントにオフィスドキュメント生成スキルを有効にします。", - "install": "インストール", - "uninstall": "アンインストール", - "syncSkills": "スキルを同期" - }, - "categories": { - "general": "一般", - "presentations": "プレゼンテーション", - "documents": "ドキュメント", - "spreadsheets": "スプレッドシート" - }, - "states": { - "not_linked": "無効", - "linked_to_codeg": "有効", - "linked_elsewhere": "ブロック — 他のリンクが存在します", - "blocked_by_real_directory": "ブロック — カスタムスキルがこの名前を使用しています", - "broken": "リンク切れ" - }, - "badges": { - "notSynced": "未同期" - }, - "actions": { - "refresh": "更新" - }, - "toasts": { - "loadFailed": "スキル詳細の読み込みに失敗", - "enabled": "このエージェントでスキルを有効化しました", - "disabled": "このエージェントでスキルを無効化しました", - "enableFailed": "スキルの有効化に失敗", - "disableFailed": "スキルの無効化に失敗", - "installSuccess": "OfficeCLI のインストールに成功", - "installFailed": "OfficeCLI のインストールに失敗", - "uninstallSuccess": "OfficeCLI をアンインストールしました", - "uninstallFailed": "OfficeCLI のアンインストールに失敗", - "syncSuccess": "{synced} 個のスキルを同期しました", - "syncPartial": "{synced} 個同期、{errors} 個失敗", - "syncFailed": "スキルの同期に失敗" - }, - "autoPreviewLabel": "プレビューを自動で開く", - "autoPreviewHint": "エージェントが Word、Excel、PowerPoint ファイルを作成または編集したときに、ライブプレビューを自動で開きます。" - }, - "SkillPacksSettings": { - "title": "スキルパック", - "description": "codeg が一元管理し、各 AI エージェントにリンクする厳選スキルの束です——コーディング専門家、科学研究、オフィス文書ツール。下でエージェントごとに有効化できます。", - "tabs": { - "experts": "エキスパート", - "science": "科学研究", - "office": "Officeツール", - "custom": "カスタム" - }, - "actions": { - "openCentralDir": "中央フォルダを開く", - "refresh": "更新" - }, - "toasts": { - "openFolderFailed": "フォルダを開けませんでした" - } - }, - "QuickMessagesSettings": { - "title": "クイックメッセージ", - "description": "再利用可能なメッセージスニペットを管理します。ドラッグして並べ替えできます。", - "loading": "クイックメッセージを読み込み中…", - "emptyList": "クイックメッセージはまだありません。「新規」をクリックして作成してください。", - "emptySelection": "編集するクイックメッセージを選択してください。", - "searchPlaceholder": "タイトルまたは内容で検索", - "untitled": "無題", - "actions": { - "new": "新規", - "save": "保存", - "delete": "削除", - "dragSort": "ドラッグして並べ替え", - "dragSortMessage": "クイックメッセージを並べ替え: {name}" - }, - "fields": { - "title": "タイトル", - "titlePlaceholder": "このメッセージに短いタイトルを付けてください", - "content": "内容", - "contentPlaceholder": "ここにメッセージ内容を入力してください" - }, - "confirmDelete": { - "title": "クイックメッセージを削除しますか?", - "message": "「{name}」を完全に削除します。よろしいですか?", - "cancel": "キャンセル", - "confirm": "削除" - }, - "toasts": { - "loadFailed": "クイックメッセージの読み込みに失敗しました", - "createFailed": "クイックメッセージの作成に失敗しました", - "saveFailed": "クイックメッセージの保存に失敗しました", - "deleteFailed": "クイックメッセージの削除に失敗しました", - "saveOrderFailed": "順序の保存に失敗しました", - "created": "クイックメッセージを作成しました", - "saved": "クイックメッセージを保存しました", - "deleted": "クイックメッセージを削除しました" - } - }, - "Pet": { - "badge": { - "running": "実行中 {count} 件", - "waiting": "承認待ち {count} 件", - "error": "エラー {count} 件" - }, - "panel": { - "title": "アクティブなセッション", - "empty": "アクティブなセッションはありません", - "emptyHint": "実行中、または対応が必要なセッションがここに表示されます。", - "statusRunning": "実行中", - "statusWaiting": "待機中", - "statusError": "エラー", - "subAgentOf": "サブエージェント" - }, - "menu": { - "scale": "拡大率", - "openManager": "ペット管理", - "close": "閉じる" - }, - "loadError": "ペットの読み込みに失敗", - "missingPetIdParam": "ペットが選択されていません", - "summonButton": "ペット", - "manager": { - "title": "デスクトップペット", - "description": "Codex 互換のスプライトシートで動く、デスクトップ常駐のお供。", - "addPet": "ペットを追加", - "importFromCodex": "Codex から取り込む", - "noPets": "ペットがありません。追加するか、Codex から取り込んでください。", - "setActive": "アクティブにする", - "active": "アクティブ", - "edit": "編集", - "delete": "削除", - "deleteConfirm": "ペット「{name}」を削除しますか?ディスクからも削除されます。", - "summon": "ペットウィンドウを呼び出す", - "openCodexHelp": "Codex ペットは ~/.codex/pets/ 配下に配置する必要があります。見つかりません。", - "specRequirement": "スプライトシートは幅 1536 ピクセル、高さは 208 ピクセルの倍数(例: 1872 または 2288)で、透過 PNG / WebP 形式である必要があります。", - "form": { - "id": "ペット ID", - "idHelp": "英小文字、数字、'-'、'_' のみ。最大 64 文字。", - "displayName": "表示名", - "description": "説明 (任意)", - "spritesheet": "スプライトシート", - "chooseFile": "ファイルを選択", - "replaceFile": "スプライトを差し替え", - "saveCreate": "ペットを追加", - "saveUpdate": "変更を保存", - "cancel": "キャンセル" - }, - "errors": { - "missingId": "ペット ID は必須です", - "missingName": "表示名は必須です", - "missingSpritesheet": "スプライトシートは必須です", - "addFailed": "ペットの追加に失敗しました", - "updateFailed": "ペットの更新に失敗しました", - "deleteFailed": "ペットの削除に失敗しました", - "loadFailed": "ペット一覧の取得に失敗しました", - "setActiveFailed": "アクティブなペットの設定に失敗しました", - "summonFailed": "ペットウィンドウの召喚に失敗しました" - } - }, - "import": { - "title": "Codex から取り込む", - "subtitle": "~/.codex/pets/ 配下に見つかったペット一覧。", - "selectAll": "すべて選択", - "alreadyImported": "取り込み済み", - "renameOnConflict": "ID が重複した場合は -imported を付与", - "import": "選択したものを取り込む", - "noneFound": "取り込み可能な Codex ペットが見つかりません。", - "imported": "取り込みに成功", - "failed": "取り込みに失敗", - "close": "閉じる" - }, - "marketplace": { - "openMarketplace": "ペットマーケット", - "title": "ペットマーケット", - "search": "ペットを検索", - "kindFilter": { - "all": "すべて", - "object": "オブジェクト", - "animal": "動物", - "person": "人物", - "creature": "生き物" - }, - "sortFilter": { - "latest": "新着", - "popular": "人気", - "views": "閲覧数順" - }, - "refresh": "更新", - "install": "インストール", - "installing": "インストール中", - "reinstall": "再インストール", - "reinstallConfirm": "ローカルのペット \"{name}\" を上書きしますか?既存のデータは置き換えられます。", - "cancel": "キャンセル", - "stats": { - "views": "閲覧", - "downloads": "ダウンロード", - "likes": "いいね" - }, - "actions": { - "idle": "待機", - "running_right": "右走り", - "running_left": "左走り", - "waving": "手振り", - "jumping": "ジャンプ", - "failed": "失敗", - "waiting": "待ち", - "running": "実行", - "review": "レビュー" - }, - "page": "{page} / {total} ページ", - "prev": "前へ", - "next": "次へ", - "empty": "条件に一致するペットがありません。", - "successInstalled": "\"{name}\" をインストールしました", - "errors": { - "loadFailed": "マーケットの読み込みに失敗しました", - "installFailed": "インストールに失敗しました", - "alreadyInstalled": "そのペットは既に存在します" - } - } - }, - "RemoteWorkspace": { - "openRemoteWorkspace": "Open remote workspace", - "manage": "Manage remote workspace", - "manageTitle": "Remote Workspace connections", - "empty": "No remote connections", - "searchPlaceholder": "Search remote workspaces", - "orderFailed": "Failed to save remote workspace order", - "dragSort": "Drag to sort", - "dragSortConnection": "Drag to sort {name}", - "newConnection": "New connection", - "loading": "Loading", - "loadingConnection": "Loading remote connection", - "name": "Name", - "baseUrl": "Service URL", - "token": "Access token", - "save": "Save", - "delete": "Delete", - "confirmDelete": { - "title": "Delete remote connection?", - "message": "This will remove \"{name}\" from this device. This action cannot be undone.", - "cancel": "Cancel", - "confirm": "Delete" - }, - "saved": "Remote connection saved.", - "deleted": "Remote connection deleted.", - "loadFailed": "Failed to load remote connections", - "saveFailed": "Failed to save remote connection", - "deleteFailed": "Failed to delete remote connection", - "openFailed": "Failed to open remote workspace", - "connectionLoadFailed": "Failed to load remote connection: {message}", - "connectionExpired": "Remote connection \"{name}\" is expired. Update its token and reload this window." - }, - "ServerFileBrowser": { - "title": "サーバーファイルを選択", - "pathPlaceholder": "ディレクトリパスを入力...", - "goHome": "ホームディレクトリへ", - "navigateUp": "上の階層へ", - "select": "選択", - "cancel": "キャンセル", - "loading": "読み込み中...", - "emptyDirectory": "このディレクトリは空です", - "errorLoadingDir": "ディレクトリの読み込みに失敗しました", - "selectedCount": "{count} 件選択中" - }, - "BackupSettings": { - "title": "バックアップと復元", - "description": "codeg データのポータブルなバックアップを書き出すか、バックアップから復元します。", - "tabs": { - "backup": "バックアップ", - "restore": "復元" - }, - "export": { - "includeExternal": "会話内容を含める", - "includeExternalHint": "各 CLI の会話履歴(Claude、Codex、Gemini など)も保存します。サイズが増えます。", - "passphrase": "パスフレーズ(任意)", - "passphrasePlaceholder": "空欄の場合は暗号化されません", - "passphraseConfirm": "パスフレーズの確認", - "passphraseMismatch": "パスフレーズが一致しません。", - "noPassphraseWarning": "このバックアップには秘密情報(API キー、トークン)が平文で含まれます。安全に保管してください。", - "passphraseLossWarning": "このパスフレーズで暗号化します。紛失するとバックアップは復元できません。", - "button": "バックアップを書き出す", - "inProgress": "バックアップを作成中…", - "success": "バックアップを作成しました。", - "started": "バックアップのダウンロードを開始しました。" - }, - "restore": { - "selectFile": "バックアップファイルを選択", - "passphrasePrompt": "このバックアップは暗号化されています。パスフレーズを入力してください。", - "unlock": "ロック解除", - "preview": { - "title": "バックアップの詳細", - "encrypted": "暗号化済み", - "compatible": "互換あり", - "incompatible": "互換なし", - "createdAt": "作成日時: {value}", - "appVersion": "アプリのバージョン: {value}", - "incompatibleHint": "このバックアップは新しいバージョンの codeg で作成されており、復元できません。" - }, - "replaceWarning": "復元すると現在の codeg データ(データベースとアップロード)がすべて置き換えられます。現在のデータは先にスナップショットされ、復旧できます。", - "keyringNote": "デスクトップの GitHub/チャットのトークンは OS のキーチェーンに保存され、含まれません。復元後に再入力してください。", - "button": "復元", - "staging": "復元を準備中…", - "staged": "復元を準備しました。再起動します…", - "restarting": "復元を準備しました。サーバーを再起動します…", - "restartTimeout": "サーバーが時間内に復帰しませんでした。起動後にページを再読み込みしてください。", - "externalSideLocation": "会話履歴を {path} に復元しました", - "confirmTitle": "すべてのデータを置き換えますか?", - "confirmBody": "現在の codeg データベースとアップロードをバックアップで置き換えてから再起動します。現在のデータは先にスナップショットされます。", - "cancel": "キャンセル", - "confirmAction": "置き換えて再起動", - "external": { - "title": "会話内容", - "hint": "このバックアップには CLI の会話履歴が含まれます。復元先を選択してください。", - "modeSkip": "復元しない", - "modeSide": "安全な別フォルダーに復元", - "modeOriginal": "CLI の元の場所に復元", - "forceOverwrite": "既存のファイルを上書き", - "forceOverwriteHint": "CLI フォルダー内の既存ファイルを置き換えます。", - "scanning": "競合を確認中…", - "noConflicts": "既存のファイルは上書きされません。", - "conflictCount": "既存のファイル {count} 件が影響を受けます。", - "conflictSkipNote": "上書きを有効にしない限り、既存ファイルは保持(スキップ)されます。" - }, - "restartFailed": "復元は準備できましたが、サーバーを再起動できませんでした。手動で再起動して復元を適用してください。" - }, - "remoteUnsupported": "バックアップと復元は codeg を実行しているマシンのデータを対象とします。現在リモートワークスペースに接続中です。そのサーバー上で直接バックアップを管理してください。" - }, - "backup": { - "restore": { - "error": { - "badPassphrase": "パスフレーズが正しくないか、バックアップが破損しています。", - "corrupted": "バックアップアーカイブが破損しています。", - "unknownFormat": "このファイルは認識可能な codeg バックアップではありません。", - "newerVersion": "このバックアップは codeg {backupVersion} で作成されており、現在のバージョン({appVersion})より新しいです。", - "alreadyPending": "適用待ちの復元が既にあります。先に再起動して適用してから、新しい復元を準備してください。" - } - }, - "error": { - "diskSpace": "操作を完了するためのディスク容量が足りません。", - "cancelled": "操作はキャンセルされました。" - } - }, - "WebConnection": { - "disconnectedTitle": "接続が切断されました", - "reconnectingDescription": "サーバーへの再接続を試みています。通常は数秒で自動的に復旧します。", - "reconnectNow": "今すぐ再接続", - "sessionExpiredTitle": "セッションの有効期限が切れました", - "sessionExpiredDescription": "セッションが無効になりました。続行するには再度サインインしてください。", - "goToLogin": "ログインへ移動" - }, - "LiveFeedback": { - "placeholder": "{agent} の作業中にメモを送る…", - "agentFallback": "エージェント", - "ariaLabel": "ライブフィードバックのメモ", - "dialogTitle": "ライブフィードバック", - "dialogDescription": "エージェントの作業中にメモを送ります。現在のステップを中断せず、次の確認時に読み取られます。", - "dialogDescriptionInstant": "作業中のエージェントにメモを送ります。メモは現在のターンに即座に挿入され、エージェントはすぐに確認できます。", - "channelDowngraded": "このセッションでは即時挿入を利用できません。メモは保存され、エージェントが次回チェックする際に読み取られます。", - "send": "送信", - "cancel": "キャンセル", - "pending": "待機中", - "delivered": "受領済み", - "turnEndedUnread": "エージェントはフィードバックを読む前にターンを終了しました。", - "sendAsMessage": "新しいメッセージとして送信", - "dismiss": "閉じる", - "turnEndedResent": "ターンが終了したため、新しいメッセージとして送信しました。", - "turnEnded": "ターンはすでに終了しています。", - "submitFailed": "メモを送信できませんでした" - }, - "AgentToolsSettings": { - "title": "会話内ツール", - "description": "codeg が会話の中でエージェントに追加で渡すツールです。エージェントの起動時に注入されるため、変更は以降に起動したエージェントに適用されます。", - "feedbackLabel": "ライブフィードバック", - "feedbackHint": "作業中のエージェントにメモや修正を送れます。即時ステアリングに対応したエージェントでは、メモは実行中のターンへ即座に挿入されます。それ以外のエージェントはフィードバック確認ツールで読み取りますが、通常はプロンプトで言及した場合にのみ確認します。例:「ライブフィードバックを定期的に確認して」とメッセージに追加してください。", - "questionLabel": "ユーザーに質問", - "questionHint": "エージェントが処理を一時停止し、会話の入力欄の上に表示される選択式の質問をできるようにします。回答(またはスキップ)するまでエージェントは待機します。", - "sessionInfoLabel": "セッション情報の取得", - "sessionInfoHint": "メッセージ内で参照したセッション(セッションバッジ)をエージェントが照会し、タイトル・エージェント・ステータス・ワークスペース・トークン使用量・最近のメッセージを読み取れるようにします。", - "automationsLabel": "自動化を作成", - "automationsHint": "会話をスケジュール実行の自動化として保存します。既定はオフ — 自動化はその後、自分でエージェントを起動します。", - "workTasksLabel": "ToDo タスクを作成", - "workTasksHint": "会話から ToDo ボードにカードを追加します。既定はオフ — アプリの状態を書き換えます。", - "save": "保存", - "saving": "保存中…", - "saved": "ツール設定を保存しました", - "saveFailed": "ツール設定の保存に失敗しました", - "loadFailed": "読み込みに失敗しました: {detail}" - }, - "NotificationSoundSettings": { - "title": "通知音", - "description": "エージェントのイベント発生時に短い通知音を鳴らします。対象はチャットチャンネルに送られるものと同じイベントで、この設定はこの端末にのみ適用されます。", - "enableHint": "既定ではオフです。通知音はこのブラウザまたはアプリのワークスペースウィンドウでのみ再生されます。", - "volume": "音量", - "preview": "試聴", - "previewEvent": "「{event}」の通知音を試聴", - "onlyWhenUnfocused": "ウィンドウが非アクティブなときのみ再生", - "onlyWhenUnfocusedHint": "Codeg を表示している間は鳴らしません。", - "eventsTitle": "イベント", - "eventsHint": "イベントごとに音を選びます。「なし」を選ぶと鳴りません。同じイベントが数秒以内に繰り返された場合は 1 回だけ再生されます。", - "toneNone": "なし", - "toneChime": "チャイム", - "toneDing": "ベル", - "toneBlip": "ブリップ", - "tonePop": "ポップ", - "toneAlert": "アラート", - "toneDescend": "下降音" - }, - "LogsSettings": { - "loading": "読み込み中…", - "sectionTitle": "実行ログ", - "sectionDescription": "アプリケーションの診断ログを表示・設定します。ログはローカルファイルに書き込まれ、ライブ表示のためメモリにも保持されます。", - "captureTitle": "ログレベル", - "captureDescription": "記録する詳細度を制御します。レベルが高い(Debug、Trace)ほど多く記録されますが、ログも大きくなります。「オフ」でログ記録を無効にします。", - "captureLabel": "取得レベル", - "levels": { - "off": "オフ", - "error": "エラー", - "warn": "警告", - "info": "情報", - "debug": "デバッグ", - "trace": "トレース" - }, - "viewerTitle": "最近のログ", - "viewerDescription": "最近のログレコードをライブ表示します。レベルで絞り込みやテキスト検索ができます。", - "searchPlaceholder": "メッセージまたはターゲットを検索…", - "viewLevels": { - "all": "すべてのレベル", - "error": "エラー以上", - "warn": "警告以上", - "info": "情報以上", - "debug": "デバッグ以上", - "trace": "トレース以上" - }, - "pause": "一時停止", - "resume": "ライブ", - "refresh": "更新", - "clear": "クリア", - "openFolder": "フォルダーを開く", - "shownCount": "{shown} / {total} 件表示", - "empty": "表示するログがありません。", - "levelSaveFailed": "ログレベルの保存に失敗しました", - "openFolderFailed": "ログフォルダーを開けませんでした", - "downloadFailed": "ログファイルのダウンロードに失敗しました", - "filesTitle": "ログファイル", - "filesDescription": "ライブバッファを超える履歴のために、ディスクから完全なログファイルをダウンロードします。", - "filesEmpty": "ログファイルはまだありません。", - "download": "ダウンロード", - "downloadTruncated": "ファイルが大きいため、最新の {size} をダウンロードしました。完全なファイルはログディレクトリにあります。", - "captureEnvLocked": "ログレベルは RUST_LOG / CODEG_LOG 環境変数で制御されています。変更はそちらで行ってください。", - "targetsTitle": "モジュール別オーバーライド", - "targetsDescription": "グローバルレベルを変えずに、特定モジュール(例: codeg_lib::acp)のレベルを個別に設定します。", - "targetsAdd": "追加", - "targetsRemove": "オーバーライドを削除", - "toggleDetails": "詳細を切り替え" - }, - "Automations": { - "title": "オートメーション", - "new": "新規オートメーション", - "empty": "オートメーションはまだありません", - "emptyHint": "作成すると、エージェントのタスクをスケジュールまたは手動で実行できます。", - "name": "名前", - "namePlaceholder": "例:夜間の PR レビュー", - "prompt": "プロンプト", - "promptPlaceholder": "エージェントに何をさせますか?", - "agent": "エージェント", - "folder": "ワークスペースフォルダ", - "folderPlaceholder": "フォルダを選択", - "isolation": "分離", - "isolationWorktree": "実行ごとに新しい worktree", - "isolationShared": "フォルダ内で実行", - "isolationSharedCaveat": "実行はこのフォルダーの作業ツリーを直接使用するため、コミットしていない変更と競合する可能性があります。実行ごとに分離するにはワークツリーのオプションを有効にしてください。", - "trigger": "トリガー", - "triggerSchedule": "スケジュール", - "triggerManual": "手動のみ", - "cron": "スケジュール(cron)", - "cronPlaceholder": "0 9 * * 1-5", - "timezone": "タイムゾーン", - "nextRun": "次回実行", - "branch": "ブランチ", - "branchOptional": "ブランチ(任意)", - "enabled": "有効", - "save": "保存", - "cancel": "キャンセル", - "edit": "編集", - "delete": "削除", - "runNow": "今すぐ実行", - "cancelRun": "実行をキャンセル", - "runHistory": "実行履歴", - "noRuns": "実行履歴はまだありません", - "allFolders": "すべてのフォルダ", - "filterAll": "すべて", - "noMatches": "一致する自動化はありません", - "viewConversation": "会話を表示", - "lastRun": "前回の実行", - "never": "なし", - "running": "実行中", - "deleteTitle": "このオートメーションを削除しますか?", - "deleteDescription": "オートメーションとそのスケジュールを削除します。実行履歴は保持されます。", - "statusRunning": "実行中", - "statusSucceeded": "成功", - "statusFailed": "失敗", - "statusCancelled": "キャンセル", - "statusSkipped": "スキップ", - "errorName": "名前は必須です", - "errorPrompt": "プロンプトは必須です", - "errorCron": "スケジュール実行には cron 式が必要です", - "errorFolder": "ワークスペースフォルダを選択してください", - "presetHourly": "毎時", - "presetDaily": "毎日 9 時", - "presetWeekdays": "平日 9 時", - "presetCustom": "カスタム", - "probing": "オプションを読み込み中…", - "retry": "再試行", - "configNone": "このエージェントに設定可能な項目はありません", - "inherit": "エージェント既定", - "mode": "モード", - "config": "設定", - "branchPlaceholder": "(既定のブランチ)", - "selectHint": "詳細を表示する自動化を選択してください", - "refresh": "更新", - "onboardTitle": "定型のエージェント作業を自動化", - "onboardHint": "コードのレビュー、依存関係の更新、課題のトリアージを、定期実行またはオンデマンドでエージェントに実行させます。", - "headerSubtitle": "スケジュール実行とオンデマンドのエージェント作業", - "startFromTemplate": "テンプレートから始める", - "blankTitle": "空の自動化", - "blankDesc": "エージェント作業を一から設定します。", - "backToTemplates": "テンプレート", - "sectionSchedule": "スケジュールと対象", - "sectionTarget": "ターゲット", - "sectionAction": "アクション", - "actionLaunchSession": "セッションを起動", - "actionEnqueueTask": "タスクをキューに追加", - "actionEnqueueTaskHint": "実行のたびに、このオートメーション名を冠した ToDo タスクが対象フォルダの ToDo タスクに追加され、タスクエンジンがボードの設定に従って実行します。", - "sectionPrompt": "プロンプト", - "nextIn": "{rel}後に実行", - "manual": "手動", - "schedEveryMinutes": "{n}分ごと", - "schedHourly": "1時間ごと", - "schedDaily": "毎日 {time}", - "schedWeekdays": "平日 {time}", - "schedWeekly": "毎週{day} {time}", - "schedMonthly": "毎月 {day} 日 {time}", - "dow0": "日曜日", - "dow1": "月曜日", - "dow2": "火曜日", - "dow3": "水曜日", - "dow4": "木曜日", - "dow5": "金曜日", - "dow6": "土曜日", - "tplCodeReviewTitle": "コードレビュー", - "tplCodeReviewDesc": "最近の変更をレビューし、バグ・リグレッション・品質の問題を洗い出します。", - "tplDependencyUpdatesTitle": "依存関係の更新", - "tplDependencyUpdatesDesc": "古くなった依存関係を見つけ、安全なアップグレードを提案します。", - "tplTestCoverageTitle": "テストカバレッジ", - "tplTestCoverageDesc": "テストされていないコードパスを見つけ、不足しているテストを追加します。", - "tplTodoSweepTitle": "TODO 整理", - "tplTodoSweepDesc": "TODO と FIXME のコメントを集め、優先度ごとに整理します。", - "tplCiTriageTitle": "CI トリアージ", - "tplCiTriageDesc": "最近失敗したチェックを調査し、修正を提案します。", - "tplReleaseNotesTitle": "リリースノート", - "tplReleaseNotesDesc": "前回のリリース以降の変更をまとめ、変更履歴を作成します。", - "tplSecurityAuditTitle": "セキュリティ監査", - "tplSecurityAuditDesc": "脆弱性やリスクのあるパターンをスキャンし、結果を報告します。", - "enable": "有効化", - "disable": "無効化", - "moreActions": "その他の操作", - "statusDisabled": "無効", - "cronBuilderTitle": "スケジュールビルダー", - "cronFreqLabel": "頻度", - "cronFreqMinutes": "N 分ごと", - "cronFreqHourly": "毎時", - "cronFreqDaily": "毎日", - "cronFreqWeekdays": "平日", - "cronFreqWeekly": "毎週", - "cronFreqMonthly": "毎月", - "cronFreqCustom": "カスタム", - "cronEveryLabel": "間隔(分)", - "cronTimeLabel": "時刻", - "cronHourLabel": "時", - "cronMinuteLabel": "分", - "cronDowLabel": "曜日", - "cronDomLabel": "日", - "cronApply": "適用", - "cronPreviewLabel": "プレビュー", - "cronOpenBuilder": "スケジュールビルダーを開く", - "branchDefault": "デフォルトブランチ", - "branchUseCustom": "「{query}」を使用", - "branchLocal": "ローカル", - "branchRemote": "リモート", - "branchSearchPlaceholder": "ブランチを検索…", - "branchNone": "ブランチがありません" - }, - "Tasks": { - "title": "ToDo タスク", - "new": "新規タスク", - "empty": "タスクはまだありません", - "emptyHint": "ToDo を追加して実行すると、エージェントが独立した worktree で作業し、結果をレビューしてマージできます。", - "emptyColTodo": "ToDoはまだありません", - "emptyColInProgress": "進行中のタスクはありません", - "emptyColAttention": "対応が必要なタスクはありません", - "emptyColDone": "完了したタスクはまだありません", - "allFolders": "すべてのフォルダ", - "showCanceled": "キャンセル済みを表示", - "showArchived": "アーカイブを表示", - "filter": "フィルター", - "viewSwitchToBoard": "ボード表示に切り替え", - "viewSwitchToList": "リスト表示に切り替え", - "statusFilter": "ステータス", - "statusFilterAll": "すべてのステータス", - "listEmpty": "現在の絞り込み条件に一致するタスクはありません", - "listColStatus": "ステータス", - "listColTask": "タスク", - "listColLocation": "場所", - "listColChanges": "変更", - "listColUpdated": "更新", - "colTodo": "ToDo", - "colInProgress": "進行中", - "colAttention": "要対応", - "colDone": "完了", - "statusTodo": "ToDo", - "statusQueued": "待機中", - "statusPreparing": "準備中", - "statusRunning": "実行中", - "statusAwaitingInput": "入力待ち", - "statusReview": "レビュー待ち", - "statusMerging": "マージ中", - "statusDone": "完了", - "statusFailed": "失敗", - "statusCanceled": "キャンセル済み", - "statusInterrupted": "中断", - "badgeCleanupFailed": "クリーンアップ失敗", - "badgeWorktreeKept": "worktree 保持", - "badgeWorktreeRemoved": "worktree 削除済み", - "filesChanged": "{count} ファイル", - "actionStart": "開始", - "actionSchedule": "予約実行", - "actionCancel": "キャンセル", - "actionRetry": "再試行", - "actionRequeue": "再キュー", - "actionViewSession": "会話を表示", - "actionEdit": "編集", - "actionDelete": "削除", - "actionRetryCleanup": "クリーンアップを再試行", - "actionMerge": "マージ", - "actionUnqueueMerge": "マージ待ちを取り消す", - "actionEditQueuedMerge": "待機中のマージを編集", - "badgeMergeQueued": "マージ待ち", - "badgeMergeQueuedRank": "マージ待ち · {rank} 番目", - "badgeMergeQueuedHint": "このプロジェクトの実行中のマージが終わるのを待っています。順番が来ると自動的に開始します。", - "actionComplete": "完了", - "actionAbandon": "破棄", - "cancelTitle": "タスクをキャンセルしますか?", - "cancelDescription": "タスクは「キャンセル済み」になります。worktree は保持され、あとで再キューできます。", - "cancelReasonLabel": "キャンセルの理由(任意)", - "cancelReasonPlaceholder": "例:方針が違うので説明を書き直す", - "cancelKeep": "やめておく", - "cancelSubmit": "タスクをキャンセル", - "restartTitleRetry": "タスクを再試行", - "restartTitleRequeue": "タスクを再キュー", - "restartDescription": "補足(任意)を書けます。次の実行のプロンプトに含めて agent に渡されます。", - "scheduleTitle": "タスクの実行を予約", - "scheduleDescription": "タスクは ToDo のまま、指定した時刻に自動で開始します。フォルダーの同時実行数の上限は引き続き適用されます。", - "scheduleDateLabel": "日付", - "schedulePickDate": "日付を選択", - "scheduleTimeLabel": "時刻", - "schedulePreview": "{time} に実行", - "schedulePastHint": "指定した時刻は過ぎています。保存するとすぐに開始します。", - "scheduleInAnHour": "1 時間後", - "scheduleInThreeHours": "3 時間後", - "scheduleTomorrow": "明日 9:00", - "scheduleClear": "予約を解除", - "scheduleBadge": "{time} に開始予定", - "toastScheduled": "{time} に予約しました", - "toastScheduleCleared": "予約を解除しました", - "actionFollowUp": "追加指示", - "actionAddNote": "補足を追加", - "followUpSubmit": "送信", - "followUpIntentRevise": "修正を依頼", - "followUpIntentContinue": "作業を続ける", - "followUpIntentQuestion": "質問する", - "followUpIntentVerify": "セルフチェック", - "followUpPlaceholderRevise": "どこを直してほしいですか?同じセッションで続けます。", - "followUpPlaceholderContinue": "次に何をしますか?これまでの作業はそのまま残ります。", - "followUpPlaceholderQuestion": "何を知りたいですか?ファイルには一切手を加えず回答します。", - "followUpPlaceholderVerify": "任意:重点的に確認してほしい点はありますか?", - "followUpPlaceholderRetry": "任意:今回はどう変えますか?例:先に pnpm install を実行", - "followUpPlaceholderRequeue": "任意:なぜ中止したのか、今回は何を変えるかを書いてください。", - "actionArchive": "アーカイブ", - "actionUnarchive": "アーカイブ解除", - "archiveAllDone": "すべてアーカイブ", - "dropToStart": "離すと実行を開始", - "errorView": "表示", - "notifyReview": "レビュー待ち: {title}", - "notifyFailed": "タスクが失敗しました: {title}", - "createFromMessage": "このメッセージからタスクを作成", - "detailTokens": "合計トークン", - "editorTitleNew": "新規タスク", - "editorTitleEdit": "タスクを編集", - "templates": "テンプレート", - "templatesEmpty": "テンプレートはまだありません。", - "templateSaveCurrent": "現在の内容をテンプレートとして保存", - "templateDelete": "テンプレートを削除", - "transcriptTitle": "タスクの会話", - "transcriptDescription": "タスクのエージェントセッションの読み取り専用ライブビュー。", - "phaseWork": "タスク実行", - "phaseRetry": "再実行", - "phaseReturn": "追加指示", - "phaseMerge": "マージ", - "titleLabel": "タイトル", - "titlePlaceholder": "何をしますか?", - "promptLabel": "タスクの説明", - "promptPlaceholder": "エージェントへの指示を記述 — @ でファイル参照、/ でコマンド", - "folderPlaceholder": "フォルダを選択", - "agentInheritedHint": "タスク設定から継承 — 変更するとこのタスク専用になります", - "agentOverrideReset": "継承に戻す", - "sectionTarget": "ターゲット", - "errorTitle": "タイトルを入力してください", - "errorPrompt": "タスクの説明を入力してください", - "errorFolder": "フォルダを選択してください", - "save": "保存", - "cancel": "キャンセル", - "mergeTitle": "タスクをマージ", - "mergeQueuedTitle": "待機中のマージ", - "mergeQueueHint": "このプロジェクトでは別のタスクをマージ中です。このタスクは待機列に入り、前のマージが終わり次第自動的に開始します。", - "mergeQueueUpdateHint": "このタスクはすでにマージ待ちです。送信すると内容だけが更新され、待機列の順番はそのままです。", - "mergeDescription": "{branch} を {base} にマージします。worktree の未コミット変更は先にコミットされます。", - "mergeMessage": "コミットメッセージ", - "mergeMessagePlaceholder": "例: feat: add login validation", - "mergeAutoMessage": "コミットメッセージをエージェントに生成させる", - "strategySquash": "1つのコミットにまとめる", - "strategySquashHint": "タスクのすべての変更が1件の履歴としてメインブランチに取り込まれ、履歴がすっきりします。", - "strategyMerge": "履歴をすべて残す", - "strategyMergeHint": "タスク中の各コミットをそのまま残し、マージの記録を1件追加します。各ステップを追跡できます。", - "mergeDeleteWorktree": "マージ後に worktree を削除", - "mergeSubmit": "マージ", - "mergeSubmitQueue": "マージ待ちに追加", - "mergeQueuedToast": "マージ待ちに追加しました。実行中のマージが終わり次第開始します。", - "completeTitle": "タスクを完了", - "completeDescription": "このタスクはファイルを変更していないため、マージするものはありません。そのまま完了にします。", - "completeDescriptionNoWorktree": "このタスクの worktree は削除されているため、マージできません。そのまま完了にします。未マージのコミットが残る作業ブランチは保持されます。", - "completeDeleteWorktree": "完了後に worktree を削除", - "completeSubmit": "完了", - "settingsTitle": "タスク設定", - "settingsDescription": "{folder} のタスクの既定値。", - "settingsScope": "適用範囲", - "settingsScopeGlobal": "すべてのフォルダ(グローバル既定)", - "settingsScopeGlobalHint": "個別設定のないフォルダはこのグローバル既定を使います。", - "settingsSource": "設定ソース", - "settingsSourceGlobal": "グローバル既定", - "settingsSourceCustom": "個別設定", - "settingsSourceGlobalFollow": "グローバルのタスク設定に従います。グローバル側の変更が自動的に反映されます。", - "settingsSourceCustomHint": "このフォルダ専用の設定を保存し、グローバル既定には従わなくなります。", - "settingsAgent": "既定のエージェント", - "settingsMaxConcurrent": "最大同時実行数", - "settingsMaxConcurrentHint": "0 = 無制限", - "settingsAutoProcess": "自動処理", - "settingsAutoProcessHint": "ToDo タスクを自動的に開始します(同時実行数の上限まで)。", - "settingsMergeStrategy": "既定のマージ戦略", - "settingsMergeStrategyHint": "マージ時にタスクの変更をブランチ履歴へどう記録するか。", - "settingsAutoMerge": "自動マージ", - "settingsAutoMergeHint": "レビュー待ちに達しマージできる変更があるタスクは、「マージ」を押したときと同じように自動で取り込まれます。コミットメッセージはエージェントが生成し、worktree の扱いは下の既定に従います。プリフライトが赤のタスクやマージに失敗したタスクはそのまま残ります。", - "settingsDeleteWorktree": "マージ後に worktree を削除", - "settingsDeleteWorktreeHint": "マージ画面で既定でオンになります。その場で変更もできます。", - "settingsWorktreeRoot": "Worktree の作成先", - "settingsWorktreeRootHint": "新しいタスクの worktree をこのディレクトリ配下にタスクごとに作成します。空欄ならプロジェクトフォルダーと同じ階層に作成されます。「~」はホームディレクトリ、相対パスはプロジェクトフォルダー基準です。", - "settingsWorktreeRootPlaceholder": "~/codeg-worktrees", - "settingsWorktreeRootBrowse": "worktree のディレクトリを選択", - "settingsPreflight": "プリフライトコマンド", - "settingsPreflightHint": "タスクがレビューに達したときワークツリーで実行。", - "settingsPreflightCustomPlaceholder": "pnpm test", - "settingsInitCommand": "Worktree 初期化コマンド", - "settingsInitCommandHint": "worktree の新規作成後、エージェント開始前に実行されます。", - "settingsInitCommandPlaceholder": "pnpm install", - "settingsTabGeneral": "一般", - "settingsTabMerge": "マージ", - "settingsTabWorktree": "Worktree", - "settingsTabPrompts": "プロンプト", - "settingsPromptsIntro": "各ステージには既定のプロンプトが組み込まれています(タスク本体、ワークツリーのルール、マージ時は具体的な git 手順)。ここに書いた内容は補足指示として末尾に追加され、既定の内容を補うだけで置き換えることはありません。", - "settingsPromptStageAll": "全段階", - "settingsPromptPlaceholderAll": "例: AGENTS.md のプロジェクト規約に従う。最後のまとめは 2 文以内で", - "settingsPromptPlaceholderWork": "例: 関連するテストを先に読む。小さな単位でこまめにコミットする", - "settingsPromptPlaceholderRetry": "例: 続ける前に既にコミット済みの内容を確認し、完了済みの作業をやり直さない", - "settingsPromptPlaceholderReturn": "例:指摘された点を一つずつ対応する。無関係なリファクタリングはしない", - "settingsPromptPlaceholderMerge": "例: 取り込みコミットのメッセージは日本語で。手動で解決した衝突は明記する", - "settingsPromptHintAll": "マージ実行を含め、エージェントに渡すすべてのプロンプトに追加されます。", - "settingsPromptHintWork": "タスクを初めて実行するときに追加されます。", - "settingsPromptHintRetry": "中断または失敗したタスクを再開するときに追加されます。", - "settingsPromptHintReturn": "レビュー待ちのタスクに追加指示を出すとき(修正・追加作業・セルフチェック)に付加されます。", - "settingsPromptHintMerge": "エージェントがタスクをベースブランチに取り込むときに追加されます。", - "preflightPassed": "{name} 成功", - "preflightFailed": "{name} 失敗", - "preflightRunning": "{name} 実行中…", - "detailDescription": "タスク詳細", - "detailSummary": "結果", - "detailFiles": "変更ファイル", - "detailDiffAll": "差分をすべて表示", - "detailDiffAllTitle": "全差分", - "detailNoChanges": "ベースからの変更はまだありません", - "detailTimeline": "進行履歴", - "detailTimelineEmpty": "まだアクティビティがありません", - "showMore": "もっと見る", - "showLess": "折りたたむ", - "detailInfo": "詳細", - "detailBranch": "ブランチ", - "detailMergeCommit": "マージコミット", - "detailChanges": "変更", - "detailScheduled": "開始予定", - "detailCreated": "作成日時", - "detailStarted": "開始日時", - "detailFinished": "完了日時", - "diffLoading": "差分を読み込み中…", - "deleteConfirmTitle": "タスクを削除しますか?", - "deleteConfirmBody": "「{title}」をボードから削除します。実行中の場合は先にキャンセルされます。", - "deleteWithWorktree": "worktree も削除する", - "eventCreated": "作成", - "eventStatusChanged": "ステータス変更", - "eventConfigEffective": "起動構成", - "eventInitCommand": "初期化コマンド", - "eventAgentProgress": "エージェントの進捗", - "eventAgentVerdict": "エージェントの判定", - "eventMergeAttempt": "マージ開始", - "eventMergeQueued": "マージ待ちに追加", - "eventMergeConflict": "マージ競合", - "eventPreflight": "プリフライト", - "eventCleanupFailed": "worktree のクリーンアップに失敗", - "eventResumeFallback": "セッション再開に失敗し新規セッションへ", - "eventUserAction": "ユーザー操作", - "eventDiffStat": "変更スナップショット" - }, - "CustomSkillsSettings": { - "loading": "カスタムスキルを読み込み中…", - "category": "カスタム", - "searchPlaceholder": "名前・ID・説明でカスタムスキルを検索", - "states": { - "not_linked": "未有効", - "linked_to_codeg": "有効", - "linked_elsewhere": "別の場所にリンク", - "blocked_by_real_directory": "実在フォルダにより占有", - "broken": "リンク切れ" - }, - "actions": { - "new": "新規", - "import": "インポート", - "importFromAgent": "エージェントから取り込む", - "cancel": "キャンセル", - "save": "保存" - }, - "rowMenu": { - "edit": "編集", - "duplicate": "複製", - "delete": "削除" - }, - "bulk": { - "delete": "選択項目を削除" - }, - "editor": { - "createTitle": "カスタムスキルを新規作成", - "editTitle": "カスタムスキルを編集", - "description": "カスタムスキルは共有ストア(~/.codeg/skills)に保存され、任意のエージェントで有効化できます。", - "idLabel": "スキル ID", - "idPlaceholder": "例: my-workflow", - "contentLabel": "SKILL.md", - "contentPlaceholder": "ここにスキルの SKILL.md を記述…", - "preview": "プレビュー", - "edit": "編集", - "emptyBody": "まだ内容がありません。" - }, - "duplicate": { - "title": "スキルを複製", - "description": "「{id}」を元に、新しい ID でコピーを作成します。", - "newIdPlaceholder": "新しいスキル ID", - "confirm": "複製" - }, - "import": { - "title": "インポートするスキルフォルダを選択" - }, - "importFromAgent": { - "title": "エージェントからスキルを取り込む", - "description": "エージェント独自のスキルを共有ストアにコピーすると、どのエージェントでも有効化できます。", - "agentLabel": "エージェント", - "agentPlaceholder": "エージェントを選択", - "selectAll": "すべて選択({count})", - "loading": "エージェントのスキルを読み込み中…", - "unsupported": "このエージェントはスキルディレクトリを提供していません。", - "empty": "このエージェントに取り込めるスキルはありません。", - "alreadyInLibrary": "ライブラリ済み", - "confirm": "選択を取り込む({count})" - }, - "delete": { - "title": "カスタムスキルを削除しますか?", - "body": "{count} 個のカスタムスキルを中央ストアから削除し、すべてのエージェントからリンクを解除します。この操作は取り消せません。", - "confirm": "削除" - }, - "toasts": { - "loadFailed": "スキルの読み込みに失敗しました", - "idRequired": "スキル ID を入力してください", - "created": "カスタムスキルを作成しました", - "updated": "カスタムスキルを更新しました", - "saveFailed": "スキルの保存に失敗しました", - "imported": "スキルをインポートしました", - "importFailed": "スキルのインポートに失敗しました", - "duplicated": "スキルを複製しました", - "duplicateFailed": "スキルの複製に失敗しました", - "deleted": "{count} 個のスキルを削除しました", - "deletedPartial": "{ok} 個を削除、{failed} 個が失敗", - "deleteFailed": "スキルの削除に失敗しました", - "importedFromAgent": "{count} 件のスキルを取り込みました", - "importedFromAgentPartial": "{ok} 件を取り込み、{failed} 件が失敗しました", - "importFromAgentAllSkipped": "取り込み対象なし — {count} 件はすでにライブラリにあります", - "importFromAgentFailed": "エージェントからの取り込みに失敗しました" - } - }, - "CodexModelEditor": { - "customizedNotice": "モデル一覧をカスタマイズしたため、codeg が codex のモデル表全体を管理します。codex が今後追加する公式モデルは自動では表示されません。下の更新をクリックして保存し直すと同期できます。カスタマイズをすべて削除すると codex の自動更新に戻ります。", - "officialsTitle": "公式モデル", - "officialsHint": "起動する codex の公式モデルを自動的に含めます。不要なものは削除できます。", - "officialsEmpty": "利用可能な公式モデルがありません。", - "refresh": "codex から更新", - "readdOfficial": "公式を再追加", - "customsTitle": "カスタムモデル", - "customsEmpty": "カスタムモデルはまだありません。", - "addCustom": "カスタム追加", - "slugPlaceholder": "モデル ID(slug)", - "displayNamePlaceholder": "表示名", - "contextWindow": "コンテキスト", - "makeDefault": "デフォルトに設定", - "defaultHint": "デフォルトモデル", - "remove": "削除", - "advanced": "詳細", - "baseTemplate": "ベーステンプレート", - "baseTemplateHint": "必須フィールド(システムプロンプト、ツール、制限)を複製する公式モデル。", - "groupBehavior": "動作と機能", - "fieldReasoningLevel": "既定の推論レベル", - "fieldReasoningSummary": "推論サマリー", - "fieldVerbosity": "詳細度", - "fieldShellType": "シェルタイプ", - "fieldApplyPatch": "パッチ適用ツール", - "fieldReasoningSummaries": "推論サマリー対応", - "fieldSupportVerbosity": "詳細度の制御", - "fieldParallelToolCalls": "並列ツール呼び出し", - "fieldSearchTool": "Web 検索ツール", - "optNone": "なし", - "groupInstructions": "説明とシステムプロンプト", - "fieldDescription": "説明", - "baseInstructions": "システムプロンプト(base_instructions)" - }, - "DiagnosticsSettings": { - "title": "環境診断", - "description": "このアプリが自身のプロセス内でエージェントの CLI をどう解決するかを確認します(ターミナルとは異なる場合があります)。", - "loading": "診断を実行中…", - "error": "診断に失敗しました", - "rerun": "再実行", - "copyAll": "すべてコピー", - "copied": "診断情報をクリップボードにコピーしました", - "button": "診断", - "verdict": { - "ok": "環境は正常です。それでも未インストールと表示される場合は、アプリを完全に再起動してプレフィックスキャッシュを更新してください。", - "node_missing": "アプリの PATH に Node.js が見つかりませんでした。", - "npm_missing": "アプリの PATH に npm が見つかりませんでした。", - "not_installed": "このエージェントはインストールされていないようです。", - "installed_but_unresolved": "インストール済みと記録されていますが、アプリが実行ファイルを見つけられません。", - "user_prefix_not_on_path": "フォールバックのプレフィックス(~/.codeg/npm-global)にインストールされていますが、アプリの PATH に含まれていません。アプリを完全に再起動して再試行してください。", - "homebrew_bin_not_on_path": "Homebrew の bin にインストールされていますが、アプリの PATH に含まれていません(Apple Silicon の keg 分割)。", - "terminal_only_path": "このコマンドはターミナルでは解決されますが、アプリでは解決されません。GUI の PATH のずれです。ターミナルからアプリを起動するか、エージェント設定から再インストールしてください。", - "npm_prefix_timeout": "npm prefix -g が遅すぎました(1.5 秒超)。フォールバック検出をスキップしました。アプリを再起動して再試行してください。", - "node_too_old": "使用中の Node.js がこのエージェントの要件より古いです。Node.js をアップグレードしてください。", - "adapter_missing_native_present": "お使いの {agent} CLI は確かにインストールされていますが、Codeg が起動するのは別の ACP アダプターパッケージで、そちらが未インストールです。エージェント設定からインストールしてください。既存の CLI には触れず、ログインも共有されます。", - "adapter_missing": "Codeg は {agent} 用に別個の ACP アダプターパッケージを起動しますが、まだインストールされていません。エージェント設定からインストールしてください。ベンダー CLI を入れるだけでは足りません。" - } - }, - "TokenUsage": { - "title": "トークン使用量", - "rangeLabel": "期間", - "range7d": "7日間", - "range30d": "30日間", - "range90d": "90日間", - "rangeThisMonth": "今月", - "rangeThisYear": "今年", - "rangeAll": "全期間", - "rangeCustom": "カスタム", - "moreRanges": "その他", - "customRangePick": "期間を選択", - "bucketLabel": "集計単位", - "bucketDay": "日", - "bucketWeek": "週", - "bucketMonth": "月", - "bucketUnitDay": "日", - "bucketUnitWeek": "週", - "bucketUnitMonth": "月", - "folderFilter": "フォルダ", - "allFolders": "すべてのフォルダ", - "agentFilter": "エージェント", - "allAgents": "すべてのエージェント", - "modelFilter": "モデル", - "allModels": "すべてのモデル", - "searchPlaceholder": "検索…", - "noMatches": "該当なし", - "clearFilter": "選択をクリア", - "resetFilters": "フィルタをリセット", - "refresh": "更新", - "rebuild": "すべて再構築", - "rebuildHint": "集計済みデータを破棄し、すべてのセッション記録を読み直します。codeg 以外の CLI で追記された場合に使います。", - "syncing": "セッションを集計中…", - "syncProgress": "{done} / {total}", - "syncDone": "{synced} 件のセッションを集計しました", - "syncFailed": "一部のセッションを読み取れませんでした", - "syncBusy": "すでに更新が実行中です", - "lastSynced": "{time} に更新", - "lastSyncedNever": "未集計", - "tileTotal": "合計トークン", - "tileSessions": "セッション数", - "tileTurns": "ターン数", - "tileActiveDays": "稼働日数", - "tileGenTime": "生成時間", - "vsPrevious": "前期間との比較", - "deltaNew": "新規", - "trendTitle": "使用量の推移", - "trendEmpty": "この期間の使用量はありません", - "trendTurns": "ターン", - "trendSessions": "セッション", - "compositionTitle": "トークンの内訳", - "compositionHint": "入力は送った内容、出力はモデルが書いた内容、キャッシュ読み取りは再送せずに済んだコンテキストです。", - "compositionNote": "これらのキャッシュ命中を定価で再送すると、あと {value} かかっていました。", - "inputTokens": "入力", - "outputTokens": "出力", - "cacheWrite": "キャッシュ書き込み", - "cacheRead": "キャッシュ読み取り", - "freshTokens": "新規計算トークン", - "cacheHitCaption": "キャッシュ命中", - "cacheHeroTitleHigh": "コンテキストの大半は再送不要でした", - "cacheHeroTitleLow": "コンテキストの大半はまだ全額計算です", - "cacheHeroDesc": "{cached} のコンテキストはキャッシュが担い、この期間に実際に新規計算されたのは {fresh} だけです。", - "cacheSavedSuffix": "再送を {saved} 相当分節約できました。", - "avgPerSession": "セッション平均", - "avgTurnsPerSession": "1 セッションあたり平均 {count} ターン", - "avgPerActiveDay": "稼働日平均", - "peakBucket": "最も多い{bucket}", - "peakHour": "ピーク時間帯", - "daysValue": "{count} 日", - "idleDays": "空き日数", - "byFolderTitle": "フォルダー別", - "byAgentTitle": "エージェント別", - "byModelTitle": "モデル別", - "distributionTitle": "使用量の分布", - "distributionHint": "選択した軸でセッションとトークンを集計。行をクリックすると絞り込めます。", - "otherLabel": "その他", - "unknownModel": "モデル未記録", - "emptyBreakdown": "記録がありません", - "sessionsCount": "{count} セッション", - "heatmapTitle": "作業リズム", - "heatmapHint": "ローカル時間の曜日・時刻ごとのトークン量。", - "heatmapPeakHint": "最も集中しているのは {hour}:00 前後です。", - "less": "少", - "more": "多", - "heatmapCell": "{weekday} {hour}:00 — {value} トークン", - "weekMon": "月", - "weekTue": "火", - "weekWed": "水", - "weekThu": "木", - "weekFri": "金", - "weekSat": "土", - "weekSun": "日", - "topSessionsTitle": "消費の多いセッション", - "untitledSession": "名称未設定のセッション", - "topSessionsEmpty": "この期間にセッションはありません", - "streakLongest": "最長の連続日数", - "streakLongestDays": "最長連続 {count} 日", - "share": "共有", - "moreActions": "その他の操作", - "shareDialogTitle": "使用量カードを共有", - "shareDialogHint": "いま選んでいる期間とフィルタのスナップショットです。", - "shareSave": "画像を保存", - "shareCopy": "画像をコピー", - "shareCopied": "クリップボードにコピーしました", - "shareSaved": "画像を保存しました", - "shareFailed": "画像を生成できませんでした", - "shareRendering": "生成中…", - "cardHeading": "私の AI コーディング記録", - "cardRangeAll": "全期間", - "cardTotalLabel": "使用トークン", - "cardFooter": "codeg で作成", - "cardTopModels": "よく使うモデル", - "cardTopProjects": "主なプロジェクト", - "archetypeNightOwl": "夜型コーダー", - "archetypeNightOwlDesc": "トークンの {percent}% は日没後に使われています。", - "archetypeEarlyBird": "早起きタイプ", - "archetypeEarlyBirdDesc": "トークンの {percent}% は朝 9 時前に使われています。", - "archetypeWeekendWarrior": "週末戦士", - "archetypeWeekendWarriorDesc": "トークンの {percent}% は週末に使われています。", - "archetypeCacheMaster": "キャッシュの達人", - "archetypeCacheMasterDesc": "コンテキストの {percent}% がキャッシュ由来です。", - "archetypeMarathoner": "マラソンランナー", - "archetypeMarathonerDesc": "{days} 日連続で開発を続けました。", - "archetypePolyglot": "マルチプレイヤー", - "archetypePolyglotDesc": "{count} 個のエージェントを本格的に併用しています。", - "archetypeLaserFocus": "一点集中", - "archetypeLaserFocusDesc": "トークンの {percent}% を一つのプロジェクトに投じています。", - "archetypeDeepDiver": "深掘り型", - "archetypeDeepDiverDesc": "1 セッションあたり平均 {averageK}K トークン。", - "archetypeSteady": "安定型ビルダー", - "archetypeSteadyDesc": "のべ {days} 日開発しました。", - "emptyTitle": "集計データがまだありません", - "emptyHint": "codeg は各エージェント自身のセッション記録から直接トークン数を読み取ります。更新すると、このマシンにある記録を集計します。", - "emptyAction": "セッションを集計", - "loadFailed": "使用量を読み込めませんでした", - "truncatedNotice": "期間が非常に長いため、表示中の数値は直近の一部のみを対象としています。" - } -} +{ + "Language": { + "followSystem": "システムに従う", + "english": "英語", + "simplifiedChinese": "简体中文", + "traditionalChinese": "繁體中文", + "japanese": "日本語", + "korean": "韓国語", + "spanish": "スペイン語", + "german": "ドイツ語", + "french": "フランス語", + "portuguese": "ポルトガル語", + "arabic": "アラビア語" + }, + "GitCredentialDialog": { + "title": "認証が必要です", + "description": "リモートサーバーが認証情報を要求しています。ユーザー名とパスワード(またはアクセストークン)を入力してください。", + "username": "ユーザー名", + "usernamePlaceholder": "ユーザー名またはメールアドレス", + "password": "パスワード / トークン", + "passwordPlaceholder": "パスワードまたはアクセストークン", + "passwordHint": "サーバーのユーザー名とパスワードを入力してください。", + "cancel": "キャンセル", + "authenticate": "認証", + "authenticating": "認証中...", + "invalidCredentials": "認証情報が無効です。再試行してください。", + "saveCredentials": "今後の操作のために認証情報を保存する", + "githubTitle": "GitHub 認証", + "githubDescription": "個人アクセストークンを入力して GitHub に接続します。トークン検証後、自動的にアカウントに保存されます。", + "githubToken": "個人アクセストークン", + "githubTokenPlaceholder": "ghp_xxxxxxxxxxxx", + "githubTokenHint": "GitHub → Settings → Developer settings → Personal access tokens でトークンを生成してください。", + "githubAuthenticate": "検証して接続", + "generateToken": "トークンを生成" + }, + "SettingsShell": { + "title": "設定", + "preferences": "環境設定", + "nav": { + "general": "一般", + "appearance": "外観", + "agents": "エージェント", + "mcp": "MCP", + "skills": "Skills", + "shortcuts": "ショートカット", + "version_control": "バージョン管理", + "system": "システム", + "chat_channels": "チャットチャンネル", + "web_service": "Webサービス", + "model_providers": "モデルプロバイダー", + "experts": "エキスパート", + "science": "科学研究", + "office_tools": "Officeツール", + "skill_packs": "スキルパック", + "quick_messages": "クイックメッセージ", + "logs": "実行ログ" + } + }, + "AppearanceSettings": { + "sectionTitle": "テーマ外観", + "sectionDescription": "ライト、ダーク、またはシステム追従を選択できます。設定は自動保存されます。", + "themeMode": "テーマモード", + "placeholder": "テーマモードを選択", + "system": "システムに従う", + "light": "ライト", + "dark": "ダーク", + "currentTheme": "現在の有効テーマ: {theme}", + "resolvedTheme": { + "light": "ライト", + "dark": "ダーク", + "unknown": "--" + }, + "themeColor": { + "sectionTitle": "テーマカラー", + "sectionDescription": "ボタンやアクセント、ハイライトに使用する色を選択します。", + "current": "現在のカラー:{color}", + "options": { + "neutral": "Neutral", + "zinc": "Zinc", + "slate": "Slate", + "stone": "Stone", + "gray": "Gray", + "red": "Red", + "rose": "Rose", + "orange": "Orange", + "green": "Green", + "blue": "Blue", + "yellow": "Yellow", + "violet": "Violet" + } + }, + "customStyle": { + "sectionTitle": "カスタムスタイル", + "sectionDescription": "現在のテーマの配色を微調整したり、独自の CSS を適用したりできます。上書きはベースプリセットの上に重なるため、プリセットを切り替えても保持されます。", + "summarySuspended": "一時停止中", + "summaryDefault": "プリセットのまま", + "summaryTokens": "{count, plural, one {上書き # 件} other {上書き # 件}}", + "summaryCss": "カスタム CSS", + "suspendedByShortcut": "カスタムスタイルは一時停止中です。再開するまで、ここでの設定は反映されません。", + "suspendedBySafeParam": "このウィンドウはセーフ外観モードで開かれているため、カスタムスタイルは適用されません。他のウィンドウには影響しません。", + "resume": "カスタムスタイルを再開", + "enableTheme": "カスタム配色を有効にする", + "editingLight": "ライトモードの値を編集しています。ダークモードに切り替えると個別に設定できます。", + "editingDark": "ダークモードの値を編集しています。ライトモードに切り替えると個別に設定できます。", + "resetToken": "プリセット値に戻す", + "radius": "角丸", + "radiusHint": "sm から 4xl までの角丸スケール全体がこの値から導出されるため、スライダー 1 つでアプリ全体の角丸が変わります。", + "advanced": "詳細(他 {count} 個の変数)", + "enableCss": "カスタム CSS を有効にする", + "cssRisk": "上級者向け機能です。カスタム CSS は組み込みスタイルをすべて上書きするため、画面が使用不能になることがあります。", + "editCss": "CSS を編集…", + "cssPresent": "{size} KB 保存済み", + "cssEmpty": "まだ保存されていません", + "escapeHint": "画面が壊れてしまったら、{shortcut} でカスタムスタイルをすべて停止できます。safeStyle=1 のクエリパラメータ付きでウィンドウを開く方法もあります。", + "copyTheme": "テーマ JSON をコピー", + "importTheme": "テーマをインポート…", + "clearTheme": "上書きをクリア", + "interopHint": "テーマは shadcn の registry:theme 形式です。任意の shadcn テーマをそのまま貼り付けられ、書き出したテーマはどの shadcn プロジェクトでも使えます。", + "importTitle": "テーマをインポート", + "importDescription": "shadcn の registry:theme アイテム、light/dark のみのオブジェクト、またはフラットなトークンマップを貼り付けてください。", + "readClipboard": "クリップボードから読み取る", + "importConfirm": "インポート", + "cancel": "キャンセル", + "apply": "適用", + "toasts": { + "copied": "テーマ JSON をコピーしました", + "copyFailed": "クリップボードにコピーできませんでした", + "clipboardReadFailed": "クリップボードを読み取れませんでした。手動で貼り付けてください", + "importFailed": "この JSON には利用できるテーマ変数がありません", + "imported": "テーマをインポートしました" + }, + "css": { + "dialogTitle": "カスタム CSS", + "dialogDescription": "すべての codeg ウィンドウに適用されます。変更はリアルタイムでプレビューされ、「適用」で保存されます。", + "size": "{used} KB / {max} KB", + "ruleCount": "{count} 個のルール", + "errorTooLarge": "サイズが大きすぎて保存できません。上限以下に減らしてください。", + "errorImportEscaped": "除去後も @import が検出されました(エスケープ記法)。手動で削除してください。", + "warnNoRules": "ルールが 1 つも解析されませんでした。構文を確認してください。", + "noticeImportsRemoved": "@import を {count} 件削除しました。リモートのスタイルシートを取得してしまうためです。", + "noticeRemoteUrl": "リモートの url() が含まれています。適用するとネットワークリクエストが発生します。", + "noticePreviewSuspended": "カスタムスタイルが停止中のため、このプレビューは適用されません。", + "noticeDisabled": "カスタム CSS は無効です。ここでプレビューはできますが、有効にするまで反映されません。", + "hintTokens": "ヒント: 上書きした色は var(--primary) や var(--background) などで参照できます。" + } + }, + "zoomLevel": { + "sectionTitle": "ウィンドウズーム", + "sectionDescription": "インターフェイス全体を拡大・縮小します。すぐに反映され、デバイスごとに保存されます。", + "placeholder": "ズームレベルを選択", + "default": "デフォルト", + "current": "現在のズーム:{zoom}%" + }, + "fonts": { + "sectionTitle": "フォント", + "sectionDescription": "インターフェース、コードエディター、ターミナルのフォントをそれぞれ選択します。内蔵フォントは必要に応じて読み込まれます。「カスタム…」を選ぶと、システムにインストールされた任意のフォントを使用できます。", + "interface": "インターフェース", + "editor": "エディター", + "terminal": "ターミナル", + "groupSans": "サンセリフ", + "groupMono": "等幅", + "custom": "カスタム…", + "customPlaceholder": "フォント名(例:Fira Code)", + "fontSize": "フォントサイズ", + "ligatures": "合字を有効にする", + "ligaturesUnavailable": "このフォントには合字がありません", + "wordWrap": "折り返しを有効にする", + "terminalLigaturesHint": "ターミナルの合字は内蔵のコーディングフォントにのみ適用されます。", + "preview": "プレビュー" + }, + "welcomePanel": { + "sectionTitle": "モード選択エリア", + "sectionDescription": "新しい会話ページで入力欄の上に表示される「コード開発 / 日常業務」のショートカットカードです。", + "showQuickActions": "新しい会話ページに表示する" + }, + "workspaceBackground": { + "sectionTitle": "ワークスペースの背景", + "sectionDescription": "ワークスペース全体の背後に画像を表示します。サイドバーやパネルは半透明のすりガラスになり画像が透けて見えます。マスクで文字の可読性を保ちます。", + "enable": "背景画像を有効にする", + "image": "画像", + "chooseImage": "画像を選択", + "replaceImage": "画像を変更", + "removeImage": "削除", + "fillMode": "表示方法", + "fillModes": { + "cover": "全体を覆う", + "contain": "全体を表示", + "center": "中央", + "tile": "タイル" + }, + "maskOpacity": "マスクの不透明度", + "maskOpacityHint": "値を大きくすると画像がテーマの背景色に近づき、文字のコントラストが上がります。", + "imageBlur": "画像のぼかし", + "panelOpacity": "パネルの不透明度", + "panelOpacityHint": "サイドバー・パネル・タブバーの不透明度です。低いほど画像が透けて見えます。", + "errorTooLarge": "画像が大きすぎます(最大 16 MB)。", + "errorUploadFailed": "背景画像の設定に失敗しました。" + } + }, + "SystemSettings": { + "loading": "読み込み中...", + "sectionTitle": "システム管理", + "sectionDescription": "ネットワークプロキシ、アプリ更新、言語設定を管理します。", + "proxyTitle": "ネットワークプロキシ", + "proxyDescription": "有効にすると、以降のネットワークリクエストはこのプロキシを優先して使用します(ACP チャット、エージェントのインストール、Git リモート操作を含む)。", + "loadFailed": "読み込みに失敗しました: {message}", + "enableProxy": "システムプロキシを有効化", + "proxyAddress": "プロキシアドレス", + "proxyHint": "http(s)/socks5 をサポート。例: {example}。システムプロキシ有効時のみ有効です。", + "save": "保存", + "saving": "保存中...", + "proxyRequired": "プロキシ有効時はプロキシ URL が必要です", + "saveSuccess": "システムプロキシ設定を保存しました", + "saveFailed": "保存に失敗しました: {message}", + "languageTitle": "言語", + "languageDescription": "アプリの言語を設定します。システムに従う場合、未対応言語は英語にフォールバックします。", + "appLanguage": "アプリ言語", + "languageSaveSuccess": "言語設定を保存しました", + "languageSaveFailed": "言語設定の保存に失敗しました: {message}", + "updateTitle": "アプリ更新", + "versionTitle": "ソフトウェアアップデート", + "updateDescription": "設定されたリリースソースで新しいバージョンを確認し、利用可能なら直接インストールします。", + "currentVersion": "現在のバージョン", + "upgradableVersion": "最新バージョン", + "none": "なし", + "lastChecked": "最終確認: {time}", + "updateError": "更新エラー: {message}", + "checking": "確認中...", + "checkUpdate": "更新を確認", + "updating": "インストール中...", + "downloading": "ダウンロード中...", + "upgradeTo": "v{version} にアップグレード", + "viewRelease": "v{version} のリリースを表示", + "foundUpdate": "新しいバージョン v{version} が見つかりました", + "alreadyLatest": "すでに最新バージョンです", + "checkUpdateFailed": "更新確認に失敗しました: {message}", + "installSuccess": "更新をインストールしました。アプリを再起動します。", + "installFailed": "更新に失敗しました: {message}", + "upgradeSuccess": "アップグレードが完了しました。再読み込みしています...", + "restartTimeout": "サーバーが時間内に復帰しませんでした。コンテナまたはサービスのログを確認してください。", + "restartingIn": "{seconds} 秒後に再起動します...", + "waitingForServer": "サーバーの復帰を待っています...", + "restartToUpdate": "再起動して更新", + "newVersionBadge": "新バージョン v{version}", + "updateAvailableTitle": "アップデートがあります", + "releaseNotesTitle": "更新内容", + "remindLater": "後で", + "retry": "再試行", + "stepDownload": "ダウンロード", + "stepInstall": "インストール", + "stepRestart": "再起動", + "updateReadyHint": "アップデートをダウンロードしました。再起動して適用してください。", + "restarting": "再起動しています…", + "dockerUpgradeHint": "いま実行中のコンテナを更新します。コンテナを再作成すると失われます。維持するには、新しいバージョンのイメージを取得またはビルドしてコンテナを再作成してください。", + "upgradeRolledBack": "アップグレードに失敗しました。サーバーは前のバージョンにロールバックしました。", + "serverUnreachable": "アップグレードを開始するためにサーバーに接続できませんでした。サーバーが稼働中であることを確認して再試行してください。", + "rollbackButton": "ロールバック", + "rollingBack": "ロールバック中...", + "rollbackDescription": "前回のアップグレード前にインストールされていたバージョンに戻します。", + "rollbackConfirmTitle": "以前のバージョンにロールバックしますか?", + "rollbackConfirmDescription": "サーバーは前回のアップグレード前のバージョンで再起動します。新しいリリースは引き続き再インストールできます。", + "rollbackConfirm": "ロールバック", + "rollbackCancel": "キャンセル", + "rollbackSuccess": "以前のバージョンにロールバックしました。再読み込みしています...", + "rollbackFailed": "ロールバックに失敗しました。サーバーのログを確認してください。", + "updateErrors": { + "sourceUnavailable": "更新ソースに接続できません。ネットワークまたはプロキシを確認して再試行してください。", + "network": "ネットワーク接続に失敗しました。ネットワークまたはプロキシを確認して再試行してください。", + "downloadFailed": "更新パッケージのダウンロードに失敗しました。しばらくしてから再試行してください。", + "installFailed": "更新のインストールに失敗しました。アプリを閉じて再試行してください。", + "unknown": "更新に失敗しました。しばらくしてから再試行してください。" + } + }, + "VersionControlSettings": { + "loading": "読み込み中...", + "sectionTitle": "バージョン管理", + "sectionDescription": "Git 実行ファイルの設定と GitHub アカウントの管理。", + "gitTitle": "Git 設定", + "gitDescription": "アプリケーションで使用する Git 実行ファイルを設定します。", + "gitDetected": "Git が検出されました", + "gitNotFound": "システムに Git が見つかりません", + "gitVersion": "バージョン", + "gitPath": "パス", + "customGitPath": "カスタム Git パス", + "customGitPathPlaceholder": "/usr/bin/git", + "customGitPathHint": "空欄の場合、自動検出されたパスを使用します。", + "test": "テスト", + "testing": "テスト中...", + "testSuccess": "Git 実行ファイルは有効です。", + "testFailed": "Git テスト失敗:{message}", + "save": "保存", + "saving": "保存中...", + "saveSuccess": "Git 設定を保存しました。", + "saveFailed": "保存に失敗しました:{message}", + "githubTitle": "GitHub アカウント", + "githubDescription": "認証用の GitHub アカウントを管理します。トークンはローカルに保存されます。", + "noAccounts": "GitHub アカウントが設定されていません。", + "addAccount": "アカウントを追加", + "serverUrl": "サーバー URL", + "serverUrlPlaceholder": "https://github.com", + "token": "個人アクセストークン", + "tokenPlaceholder": "ghp_xxxxxxxxxxxx", + "generateToken": "トークンを生成", + "tokenHint": "GitHub → Settings → Developer settings → Personal access tokens でトークンを生成してください。", + "validateAndAdd": "検証して追加", + "validating": "検証中...", + "addSuccess": "アカウント {username} を追加しました。", + "addFailed": "アカウントの追加に失敗しました:{message}", + "testConnection": "テスト", + "connectionSuccess": "接続成功。", + "connectionFailed": "接続失敗:{message}", + "setDefault": "デフォルトに設定", + "defaultLabel": "デフォルト", + "defaultSet": "デフォルトアカウントを更新しました。", + "removeAccount": "削除", + "removeConfirmTitle": "アカウントを削除", + "removeConfirmMessage": "アカウント「{username}」を削除してもよろしいですか?", + "removeConfirm": "削除", + "removeCancel": "キャンセル", + "removeSuccess": "アカウントを削除しました。", + "scopes": "スコープ", + "loadFailed": "設定の読み込みに失敗しました:{message}", + "gitAccount": { + "sectionTitle": "Git サーバーアカウント", + "sectionDescription": "GitHub 以外の Git サーバーの認証情報を管理します(GitLab、Bitbucket、セルフホストなど)。", + "noAccounts": "Git サーバーアカウントが設定されていません。", + "addAccount": "アカウントを追加", + "addTitle": "Git アカウントを追加", + "addDescription": "サーバーアドレス、ユーザー名、パスワードまたはアクセストークンを入力してください。", + "serverUrl": "サーバー URL", + "serverUrlPlaceholder": "https://gitlab.example.com", + "username": "ユーザー名", + "usernamePlaceholder": "ユーザー名またはメールアドレス", + "password": "パスワード / トークン", + "passwordPlaceholder": "パスワードまたはアクセストークン", + "passwordHint": "サーバーのパスワードまたはアクセストークンを入力してください。", + "add": "追加", + "serverRequired": "サーバー URL を入力してください。", + "usernameRequired": "ユーザー名を入力してください。", + "passwordRequired": "パスワードを入力してください。" + } + }, + "ShortcutSettings": { + "sectionTitle": "ショートカット", + "resetDefault": "デフォルトに戻す", + "recordInstruction": "右側のボタンをクリックしてからキーの組み合わせを押してください。Ctrl/Cmd、Alt、Shift が使用できます。Esc で記録をキャンセルします。", + "recording": "ショートカットを入力...", + "toasts": { + "conflict": "ショートカットはすでに「{title}」で使用されています", + "updated": "ショートカットを更新しました", + "invalid": "無効なショートカットです。もう一度お試しください", + "reset": "デフォルトのショートカットを復元しました" + }, + "actions": { + "toggle_search": { + "title": "検索を開く", + "description": "会話検索パネルを表示または非表示にします" + }, + "toggle_sidebar": { + "title": "左サイドバーを切り替え", + "description": "会話一覧サイドバーを表示または非表示にします" + }, + "toggle_terminal": { + "title": "ターミナルを切り替え", + "description": "下部ターミナルパネルを表示または非表示にします" + }, + "new_terminal_tab": { + "title": "新しいターミナル", + "description": "ターミナルにフォーカスがあるとき新しいタブを作成します" + }, + "close_current_terminal_tab": { + "title": "現在のターミナルを閉じる", + "description": "ターミナルにフォーカスがあるとき現在のタブを閉じます" + }, + "toggle_aux_panel": { + "title": "右パネルを切り替え", + "description": "補助情報パネルを表示または非表示にします" + }, + "new_conversation": { + "title": "新しい会話", + "description": "現在のフォルダで新しい会話タブを作成します" + }, + "open_folder": { + "title": "フォルダを開く", + "description": "フォルダ選択を開き、新しいウィンドウで開きます" + }, + "open_settings": { + "title": "設定を開く", + "description": "設定ウィンドウを開きます" + }, + "close_current_tab": { + "title": "現在のタブを閉じる", + "description": "現在の会話またはファイルタブを閉じます" + }, + "close_all_file_tabs": { + "title": "すべてのファイルタブを閉じる", + "description": "ファイルペインがアクティブなときに開いているすべてのファイルタブを閉じます" + }, + "next_tab": { + "title": "次のタブ", + "description": "次の会話またはファイルタブに切り替える" + }, + "prev_tab": { + "title": "前のタブ", + "description": "前の会話またはファイルタブに切り替える" + }, + "send_message": { + "title": "メッセージを送信", + "description": "入力欄のメッセージを送信する" + }, + "newline_in_message": { + "title": "メッセージ内で改行", + "description": "入力欄で改行を挿入する" + }, + "toggle_custom_style": { + "title": "カスタムスタイルの停止/再開", + "description": "緊急脱出用: カスタム配色と CSS をすべてオフにし、再度押すと元に戻します" + } + } + }, + "SkillsSettings": { + "title": "Skills", + "description": "左側でSkillを選択します。右側は既定でMarkdownプレビューです。編集に切り替えると変更して保存できます。", + "loadingAgents": "Skill対応エージェントを読み込み中...", + "emptyNoManageableAgents": "Skillを管理できるエージェントがありません。", + "managedTarget": "管理対象", + "selectAgentPlaceholder": "エージェントを選択", + "searchPlaceholder": "名前 / ID / パスで検索...", + "skillsList": "Skill一覧", + "loadingSkills": "Skillを読み込み中...", + "agentNotSupported": "現在のエージェントはSkill管理に対応していません。", + "emptySkills": "まだSkillがありません。「新規Skill」をクリックして作成してください。", + "newSkillTitle": "新規Skill", + "skillInfo": "Skill情報", + "skillIdPlaceholder": "skill-id(英数字/-/_/.)", + "skillsDirectoryWithPath": "Skillディレクトリ: {path}", + "skillsDirectoryNeedId": "Skillディレクトリ: Skill ID を入力すると完全なパスを生成します", + "markdownContent": "Markdown内容", + "editingStatus": "編集中", + "previewStatus": "プレビュー中", + "contentPlaceholder": "SkillのMarkdown内容を入力...", + "metadataTitle": "Skillメタデータ", + "onlyYamlMetadata": "このSkillにはYAMLメタデータのみが含まれています。", + "emptyContentHint": "まだ内容がありません。「編集」をクリックして開始してください。", + "loadingSkill": "Skillを読み込み中...", + "emptyNoAgents": "利用可能なエージェントがありません。", + "noSelectionHint": "左側から Skill を選択するか、「新規 Skill」をクリックして作成してください。", + "systemBadge": "システム", + "systemHint": "CLI 組み込み Skill・読み取り専用", + "scope": { + "global": "グローバル", + "folder": "フォルダ", + "selectFolderPlaceholder": "フォルダを選択", + "noFolders": "フォルダが見つかりません", + "pickFolderHint": "Skills を表示するフォルダを選択してください。" + }, + "actions": { + "preview": "プレビュー", + "edit": "編集", + "openInWindow": "新しいウィンドウで開く", + "delete": "削除", + "deleting": "削除中...", + "refresh": "更新", + "newSkill": "新規Skill", + "reset": "リセット", + "save": "保存", + "saving": "保存中...", + "cancel": "キャンセル" + }, + "deleteDialog": { + "title": "Skillを削除", + "confirm": "現在のSkillを削除しますか?この操作は元に戻せません。", + "confirmWithNamePrefix": "Skill", + "confirmWithNameSuffix": "を削除しますか?この操作は元に戻せません。" + }, + "toasts": { + "loadFailed": "Skillの読み込みに失敗しました", + "openFolderFailed": "フォルダを開けませんでした", + "noSkillDirectory": "現在のエージェントで利用可能なSkillディレクトリが見つかりません", + "nameRequired": "Skill名は空にできません", + "updated": "Skillを更新しました", + "created": "Skillを作成しました", + "saveFailed": "Skillの保存に失敗しました", + "deleted": "Skillを削除しました", + "deleteFailed": "Skillの削除に失敗しました" + }, + "templates": { + "gemini": "---\nname: example-skill\ndescription: Describe when this skill should be used.\n---\n\n# Skill Name\n\nInstructions for the agent when this skill is active.\n\n## Workflow\n\n1. Add actionable step one.\n2. Add actionable step two.\n", + "openCode": "---\nname: example-skill\ndescription: Describe when this skill should be used.\n---\n\n# Purpose\n\nDescribe what this skill helps with.\n\n# Steps\n\n1. Add actionable step one.\n2. Add actionable step two.\n", + "openClaw": "---\nname: example-skill\ndescription: Describe when this skill should be used.\nuser-invocable: true\ndisable-model-invocation: false\n---\n\n# Purpose\n\nDescribe what this skill helps with.\n\n# Instructions\n\n1. Add actionable instruction one.\n2. Add actionable instruction two.\n", + "default": "---\nname: example-skill\ndescription: Describe when this skill should be used.\n---\n\n# Skill: example-skill\n\n## When to use\n\n- Describe trigger conditions.\n\n## Instructions\n\n1. Add actionable instruction one.\n2. Add actionable instruction two.\n" + } + }, + "McpSettings": { + "loading": "読み込み中...", + "summary": { + "missingCommand": "(コマンド未設定)", + "missingUrl": "(URL未設定)" + }, + "protocol": { + "stdio": "Stdio" + }, + "errors": { + "selectInstallProtocol": "インストールプロトコルを選択してください", + "fieldRequired": "{field} は必須です", + "fieldNeedsBoolean": "{field} は true または false である必要があります", + "fieldNeedsNumber": "{field} は数値である必要があります", + "fieldNeedsInteger": "{field} は整数である必要があります", + "fieldInvalidJson": "{field} のJSONが不正です: {message}", + "fieldOutOfRange": "{field} の値が許可範囲外です", + "jsonEmpty": "{name} は空にできません", + "jsonInvalid": "{name} は有効なJSONではありません: {message}", + "jsonMustBeObject": "{name} はJSONオブジェクトである必要があります", + "specMustBeObject": "MCP 設定は JSON オブジェクトである必要があります。", + "missingType": "MCP 設定に type フィールドがありません。stdio、http(エイリアス:streamable-http、streamableHttp)、sse のいずれかを指定してください。", + "unsupportedType": "サポートされていない MCP タイプ {type}。対応:stdio、http(エイリアス:streamable-http、streamableHttp)、sse。", + "codexEntryUnsupportedType": "Codex MCP エントリ {id} のタイプ {type} はサポートされていません。対応:stdio、http(エイリアス:streamable-http、streamableHttp)、sse。", + "unsupportedTransportType": "サポートされていない transport タイプ {type}。対応:http(エイリアス:streamable-http、streamableHttp)、sse。", + "stdioCommandRequired": "stdio タイプの MCP には空でない command フィールドが必要です。", + "remoteUrlRequired": "リモート MCP には空でない url フィールドが必要です。", + "appsRequired": "対象アプリを少なくとも 1 つ選択してください。" + }, + "jsonNames": { + "localConfig": "MCP設定", + "installConfig": "インストール設定" + }, + "toasts": { + "uninstalled": "MCPをアンインストールしました", + "uninstallFailed": "アンインストールに失敗しました: {message}", + "selectAtLeastOneApp": "対象アプリを少なくとも1つ選択してください", + "saveSuccess": "保存しました", + "saveFailed": "保存に失敗しました: {message}", + "installed": "{name} をインストールしました", + "installFailed": "インストールに失敗しました: {message}", + "serverIdRequired": "Server ID は必須です", + "serverIdExists": "Server ID \"{id}\" は既に存在します。既存の項目を編集するか、別の名前を選択してください。", + "created": "MCP を作成しました" + }, + "installDialog": { + "title": "MCPインストールの確認", + "descriptionWithName": "{name} をローカル設定にインストールします。", + "description": "インストール対象アプリを選択してください。", + "protocol": "プロトコル", + "selectProtocol": "プロトコルを選択", + "parameters": "設定パラメータ", + "booleanPlaceholder": "true/false を選択してください", + "selectOneValue": "値を選択", + "targetApps": "対象アプリ" + }, + "actions": { + "cancel": "キャンセル", + "confirmInstall": "インストールを確定", + "installing": "インストール中", + "uninstall": "アンインストール", + "uninstalling": "アンインストール中", + "viewDetails": "詳細を見る", + "save": "保存", + "saving": "保存中", + "install": "インストール", + "refresh": "更新", + "newMcp": "新規 MCP", + "create": "作成", + "creating": "作成中..." + }, + "tabs": { + "local": "ローカル MCP", + "market": "MCP マーケットプレイス" + }, + "local": { + "filterPlaceholder": "ローカルMCPを絞り込み...", + "loadFailed": "読み込み失敗: {message}", + "empty": "ローカルMCPが見つかりません。", + "description": "ローカルMCP設定は直接編集して保存できます。", + "enabledApps": "有効なアプリ", + "configJson": "MCP設定 (JSON)", + "draftTitle": "新規 MCP", + "draftDescription": "Server ID と設定を入力してローカル MCP サーバーを作成します。", + "serverIdLabel": "Server ID", + "serverIdPlaceholder": "Server ID(例:my-mcp)", + "typeHint": "対応タイプ:stdio、http(エイリアス streamable-http、streamableHttp)、sse。env は stdio 専用です。リモート MCP の認証トークンは headers で渡してください。", + "envOnRemoteWarning": "リモート MCP の設定に env が含まれています。env は stdio のみで使用され、リモート MCP の認証トークンは headers に格納します。env は保存時に無視されます。" + }, + "market": { + "selectMarketplace": "マーケットプレイスを選択", + "searchPlaceholder": "MCPを検索...", + "searchFailed": "検索に失敗しました: {message}", + "loadingList": "MCP一覧を読み込み中...", + "empty": "MCPの検索結果がありません。", + "loadingDetail": "マーケットプレイス詳細を読み込み中...", + "detailLoadFailed": "詳細の読み込みに失敗しました: {message}", + "owner": "オーナー: {owner}", + "namespace": "名前空間: {namespace}", + "defaultInstallProtocol": "デフォルトのインストールプロトコル", + "currentOptionParameterCount": "現在のオプションのパラメータ数: {count}", + "installConfigDescription": "インストール設定 (JSON、インストール前に編集可能。編集内容はプロトコル/パラメータフォームより優先されます)", + "selectLeftToView": "詳細を見るには左側のマーケットプレイスMCPを選択してください。" + }, + "badges": { + "verified": "認証済み", + "remote": "リモート", + "hasHomepage": "ホームページあり", + "uses": "{count} 回使用", + "deployed": "デプロイ済み", + "notDeployed": "未デプロイ" + }, + "selectLeftMcp": "左側でMCPを選択してください。" + }, + "AcpAgentSettings": { + "title": "Agent SDK 管理", + "description": "Agent SDK の接続、有効化状態、環境変数、設定管理、バージョン事前チェック情報を一元管理します。", + "loadingAgents": "エージェント一覧を読み込み中...", + "agentList": "エージェント一覧", + "emptyNoAgent": "利用可能なエージェントがありません。", + "configManagement": "設定管理", + "envVars": "環境変数", + "hostTools": { + "label": "ファイルとコマンドをエージェント自身に処理させる", + "description": "codeg がファイルアクセスとターミナルコマンドを代行しなくなり、エージェントが自身のプロセスで実行します。そうすることで初めて、エージェント自身のサンドボックスと権限ルールが適用されます。他のエージェントへの委任も無効になります(同じ処理が codeg 経由に戻ってしまうため)。codeg 自体はサンドボックスを提供しないため、エージェント側でサンドボックスを設定済みの場合にのみ有効にしてください。" + }, + "nativeJsonConfig": "ネイティブ JSON 設定", + "modelHintDefault": "空欄の場合はシステム既定モデルを使用します。", + "generalConfigDescriptionClaude": "API URL、API Key、Claude モデルをすばやく設定でき、ネイティブ JSON 設定と同期します。", + "generalConfigDescriptionDefault": "重要な設定入力(API URL、API Key、Model)とネイティブ JSON 設定管理をサポートします。", + "multiAgent": { + "title": "マルチエージェント連携", + "description": "アクティブなエージェントがサブタスクを他のエージェントに委任できるようにします。", + "enable": "委任を有効化", + "enableHint": "オフにすると、delegate_to_agent ツールはエージェントの MCP ツール一覧から非表示になります。", + "withheldByHostTools": "{agents} には委任ツールが渡りません。エージェントごとの「ファイルとコマンドをエージェント自身に任せる」スイッチがオンになっています。", + "selfInitiate": "Allow spawn without @", + "selfInitiateHint": "When on, an agent may start a listed sub-agent on its own. An @ mention is still always honored. When off, only an @ mention starts a sub-agent.", + "depthLimit": "最大委任深度", + "depthHint": "許可範囲: {min}–{max}。委任チェーン(ルート → 子 → 孫 …)の再帰深度を制限します。", + "completedCacheLabel": "完了結果のキャッシュ(MB)", + "completedCacheHint": "実行中の委任セッションが保持する、完了したサブエージェント結果のメモリ内キャッシュ。そのセッションの実行中のみ保持され、セッション終了時に自動的に破棄されます。この予算を超えると古い結果から順にメモリから破棄されます(サブエージェント自身のセッションでは引き続き閲覧可能)。0 は無制限(それでもセッション終了時に破棄)。", + "save": "保存", + "saving": "保存中…", + "saved": "委任設定を保存しました", + "saveFailed": "委任設定の保存に失敗しました", + "loadFailed": "委任設定の読み込みに失敗しました: {detail}", + "tabGeneral": "一般", + "tabAgentDefaults": "サブエージェント設定", + "agentDefaultsDescription": "マルチエージェント連携が委任呼び出しのためにサブエージェントを起動するときに適用される上書き設定です。ここに表示されるオプションはライブプローブで取得しており、選択した内容がそのままエージェントに渡されます。", + "probing": "エージェントの利用可能な設定項目を読み込み中…", + "probeFailed": "設定項目の読み込みに失敗しました: {detail}", + "retry": "再試行", + "noConfigAvailable": "このエージェントには設定可能な項目がありません。", + "modeLabel": "モード", + "agentDefaultHint": "エージェント既定: {value}", + "defaultOptionLabel": "既定({value})" + }, + "actions": { + "dragSort": "ドラッグして並べ替え", + "dragSortAgent": "{name} をドラッグして並べ替え", + "refreshCheck": "再チェック", + "refreshCheckAgent": "{name} を再チェック", + "clickEnable": "{name} を有効化", + "clickDisable": "{name} を無効化", + "install": "インストール", + "upgrade": "アップグレード", + "uninstall": "アンインストール", + "uninstalling": "アンインストール中...", + "saveEnvVars": "環境変数を保存", + "saving": "保存中...", + "saveGrokConfig": "Grok 設定を保存", + "saveCodexConfig": "Codex設定を保存", + "saveGeminiConfig": "Gemini設定を保存", + "saveOpenCodeConfig": "OpenCode設定を保存", + "saveOpenClawConfig": "OpenClaw設定を保存", + "saveConfigManagement": "設定管理を保存", + "saveCurrentProvider": "現在のプロバイダーを保存", + "showApiKey": "APIキーを表示", + "hideApiKey": "APIキーを非表示", + "showKey": "キーを表示", + "hideKey": "キーを非表示", + "showToken": "トークンを表示", + "hideToken": "トークンを非表示", + "cancel": "キャンセル", + "delete": "削除", + "deleting": "削除中...", + "confirmDelete": "削除を確認", + "confirmUninstall": "アンインストールを確認", + "saveClineConfig": "Cline設定を保存", + "saveHermesConfig": "Hermes設定を保存", + "saveCodeBuddyConfig": "CodeBuddy 設定を保存", + "saveKimiCodeConfig": "Kimi Code の設定を保存", + "customInstall": "カスタムインストール", + "saveKimiCodeRawConfig": "Save config.toml", + "saveDeepSeekConfig": "DeepSeek 設定を保存", + "diagnose": "診断" + }, + "status": { + "enabled": "有効", + "disabled": "無効", + "unchecked": "未チェック", + "agentEnabledAria": "{name} は有効です", + "agentEnabledSwitch": "{name} 有効化スイッチ" + }, + "preflight": { + "count": "事前チェック項目: {count}", + "notRun": "チェックはまだ実行されていません。" + }, + "grok": { + "configDescription": "ここで Grok を設定します。以下のコントロール(権限モード、推論の強さ、任意のカスタム(独自エンドポイント)モデル、圧縮)は ~/.grok/config.toml にマージされ、他のキーやコメントは保持されます。サインインは XAI_API_KEY または `grok login` を使用します。その他のキーは「詳細」で編集できます。", + "permissionModeLabel": "権限モード", + "permissionDefault": "毎回確認", + "permissionAcceptEdits": "編集を自動承認", + "permissionAuto": "スマート自動承認", + "permissionAlwaysApprove": "常に許可", + "reasoningEffortLabel": "推論レベル", + "effortLow": "低(高速)", + "effortMedium": "中(バランス)", + "effortHigh": "高", + "effortXhigh": "最大", + "optionDefault": "デフォルトを使用", + "authTitle": "認証", + "authMode": "認証方式", + "authModeApiKey": "XAI API キー", + "authModeApiKeyHint": "xAI コンソールの XAI_API_KEY で認証します。非対話・ヘッドレス実行向けで、このエージェントの環境変数に保存されます。", + "authModeCustom": "カスタムエンドポイント", + "authModeCustomHint": "独自のエンドポイント(BYO)を使用します。下でベース URL と API キーを持つカスタムモデルを定義すると、それが Grok の既定モデルになります。", + "subscriptionHint": "`grok login` でサインインします(SuperGrok / X Premium+)。API キーは保存されません。", + "loginHint": "ターミナルで次のコマンドを実行してサインインし、この設定を開き直してください:", + "commandCopied": "コマンドをクリップボードにコピーしました", + "copyCommand": "コマンドをコピー", + "authKeyConfigured": "XAI_API_KEY が設定されています。", + "authKeyMissing": "XAI_API_KEY が未設定です。", + "advancedToggle": "詳細(生の config.toml)", + "configTomlNative": "config.toml(ネイティブ)", + "configTomlHint": "~/.grok/config.toml 全体としてそのまま書き込まれます。無効な TOML は拒否され、タイプミスでファイルが切り詰められることはありません。", + "configTomlPlaceholder": "# 上のコントロール以外のキー。例:\n# [mcp_servers.*]、[cli]、[permission] ルール。", + "customModelTitle": "カスタムモデル(独自エンドポイント)", + "customModelHint": "Grok をカスタムまたは自己ホストのエンドポイントに向けます。codeg はモデルごとの `[model.*]` ブロックを書き込み、既定モデルに設定します。モデル ID を空にすると削除されます。", + "customModelIdLabel": "モデル ID", + "customModelIdPlaceholder": "grok-4.5", + "customModelIdHint": "`[model.*]` ブロックとして登録され、モデル名として API に送信されます。`[models].default` にも設定されます。", + "customBaseUrlLabel": "Base URL", + "customBaseUrlPlaceholder": "https://api.x.ai/v1(既定)", + "customApiBackendLabel": "API バックエンド", + "backendResponses": "Responses", + "backendChatCompletions": "Chat Completions", + "backendMessages": "Messages(Anthropic)", + "customApiKeyLabel": "API キー", + "customApiKeyHint": "`[model.*].api_key` にインラインで保存され、このエンドポイントにのみ適用されます。", + "customContextWindowLabel": "コンテキストウィンドウ(トークン)", + "customContextWindowHint": "任意。自動圧縮のタイミングに使われます。空欄の場合はエンドポイントの既定値を使用します。", + "autoCompactLabel": "自動圧縮のしきい値(%)", + "autoCompactHint": "コンテキスト使用率がこの割合に達したら会話を圧縮します(Grok の既定は 85)。`[session]` に書き込まれます。" + }, + "cursor": { + "configDescription": "ここで Cursor を設定します。まず認証方式を選択し——公式サブスクリプション(ブラウザログイン)またはヘッドレス/サーバー用の Cursor API キー——次にモデルを選び、CLI の権限ルールとサンドボックスを編集します。codeg はこれらを ~/.cursor/cli-config.json に書き込み、cursor-agent CLI と共有します。", + "authTitle": "認証", + "authChecking": "確認中…", + "authNotInstalled": "cursor-agent が未インストールです", + "authLoggedIn": "ログイン済み", + "authNotLoggedIn": "未ログイン", + "loginHint": "ターミナルで次のコマンドを実行して Cursor アカウントにログイン(ブラウザが開きます)し、完了後に更新を押してください:", + "apiKeyLabel": "Cursor API キー", + "apiKeyPlaceholder": "cursor.com/dashboard で取得", + "apiKeyHint": "CURSOR_API_KEY —— Cursor ダッシュボードのアカウントキー。ヘッドレス/サーバー環境でブラウザログインの代わりに使用します。サードパーティや OpenAI のキーではありません。", + "modelTitle": "デフォルトモデル", + "loadModels": "モデル一覧を取得", + "modelsUnavailable": "モデル一覧を取得できません", + "modelHint": "セッション開始時に --model として CLI に渡されます。既定のままなら Cursor が選択します。", + "permissionsTitle": "権限とサンドボックス", + "permissionsDescription": "CLI の権限ルール(cli-config.json)のビジュアルエディタ。許可ルールは確認なしで実行、拒否ルールは常にブロックされます。", + "permissionModeLabel": "権限モード", + "permissionModeDefault": "実行前に確認(デフォルト)", + "permissionModeForce": "Run Everything(--force)", + "permissionModeHint": "Run Everything は --force でセッションを起動します:deny ルール以外のツール呼び出しはすべて確認なしで自動許可されます(組織ポリシーにより allow ルール一致のみに制限される場合があります)。新しいセッションから有効です。", + "optionDefault": "既定(未設定)", + "sandboxLabel": "サンドボックス", + "sandboxEnabled": "有効", + "sandboxDisabled": "無効", + "allowRulesLabel": "許可ルール", + "denyRulesLabel": "拒否ルール", + "addRule": "ルールを追加", + "rulesSyntaxHint": "ルール構文:Shell(コマンド)、Read(パス/グロブ)、Write(パス/グロブ)、WebFetch(ドメイン)、Mcp(サーバー:ツール)——deny ルールが常に優先されます。", + "saveConfig": "設定を保存", + "advancedToggle": "詳細:cli-config.json(生ファイル)", + "advancedHint": "~/.cursor/cli-config.json の全文です。ここでの保存はそのまま書き込み、上の構造化コントロールはマージして書き込みます。", + "saveRawConfig": "ファイルを保存", + "authMode": "認証方式", + "subscriptionHint": "Cursor アカウントでサインインし、Cursor のモデルを使用します。", + "customApiKeyRequired": "Cursor API キーが必要です。", + "authModeApiKey": "Cursor API キー(ヘッドレス/サーバー)", + "authModeApiKeyHint": "Cursor ダッシュボードで発行したアカウント API キーで認証します(ヘッドレス/サーバー環境向け)。これは Cursor アカウントのキーであり、サードパーティ/OpenAI エンドポイントではありません——cursor-agent は Cursor 自身のバックエンドにのみ接続します。codex/OpenAI 互換エンドポイントを使うには、代わりに Codex エージェントを使用してください。", + "modelPickerPlaceholder": "モデルを検索…", + "modelNoMatch": "一致するモデルがありません", + "modelsNeedAuth": "サインインするとモデル一覧を読み込みます。", + "modelDefaultBadge": "既定" + }, + "deepseek": { + "configManagement": "DeepSeek Harness の設定", + "configDescription": "エンドポイントと API キーは deepseek-acp が起動時に読み込む環境変数です。モデルと推論レベルはセッションごとのセレクターなので、入力欄で切り替えます。", + "baseUrlLabel": "API エンドポイント", + "baseUrlHint": "空欄なら公式エンドポイントを使います。保存後に開始したセッションから有効になります。実行中のセッションは再接続してください。", + "baseUrlInvalid": "クエリ文字列を含まない完全な http(s) URL を入力してください(例:https://api.deepseek.com)", + "apiKeyLabel": "API キー", + "apiKeyHint": "DEEPSEEK_API_KEY としてエージェントに渡されます。環境変数は認証情報ファイルより優先されるため、ターミナルでログインする場合は空のままにしてください。" + }, + "codex": { + "configDescription": "API URL、API Key、モデル名、reasoning effort を素早く設定でき、`auth.json` / `config.toml` と同期します。", + "authMode": "認証方式", + "chatgptSubscription": "公式サブスクリプション", + "chatgptSubscriptionHint": "ChatGPT 公式サブスクリプションでログイン、API Key 不要", + "apiKeyHint": "API Key で OpenAI または互換 API サービスに接続", + "selectProvider": "プロバイダーを選択", + "modelName": "モデル名", + "selectReasoningEffort": "Reasoning Effort を選択", + "enableWebsocket": "WebSocket を有効化", + "enableWebsocketAria": "Codex Provider の WebSocket を有効化", + "enableSkills": "Skills を有効化", + "enableSkillsAria": "Codex の Skills を有効化", + "enableFast": "Fast を有効化", + "enableFastAria": "Codex の Fast サービスティアを有効化", + "sandboxGroupTitle": "サンドボックスと承認", + "sandboxGroupHint": "グローバルの ~/.codex/config.toml に書き込むため、codex CLI や IDE のセッションにも反映されます。これはスレッドの既定値で、codex 自身が開始するターン(/goal、/review、/compact)にのみ適用されます。通常のプロンプトは入力欄の承認プリセットを使います。変更はセッションを再起動すると有効になります。", + "sandboxShadowedWarning": "config.toml に default_permissions が設定されているため、codex は権限プロファイル経由で解決し sandbox_mode を完全に無視します。以下の設定を使うには default_permissions を削除してください。", + "sandboxPermissionsTableWarning": "config.toml に [permissions] プロファイルがありますが default_permissions が未設定のため、codex は起動を拒否します。下の生エディタで設定してください。", + "approvalPolicyLabel": "承認ポリシー", + "approvalPolicyUnset": "未設定(codex の既定: 要求時)", + "approvalPolicy_on-request": "要求時 — モデルが確認のタイミングを判断", + "approvalPolicy_untrusted": "未信頼 — 安全と分かっている読み取り専用コマンドのみ自動実行", + "approvalPolicy_never": "確認しない — 承認プロンプトを一切出さない", + "approvalPolicy_granular": "詳細設定 — プロンプト種別ごとに指定", + "approvalPolicyUntrustedAcpWarning": "ACP アダプターの 3 つの承認プリセットに untrusted に相当するものはないため、codeg のセッションは「要求時」にフォールバックします。その場合はモデルが尋ねるタイミングを決め、サンドボックスが既に許可しているコマンドは確認されなくなります。代わりに下のサンドボックスモードで制限してください。", + "granularHint": "オフにすると、その種類の要求は表示されずに自動で拒否されます。", + "granular_sandbox_approval": "シェルコマンドの権限昇格", + "granular_rules": "Execpolicy ルールのプロンプト", + "granular_skill_approval": "スキルスクリプトのプロンプト", + "granular_request_permissions": "request_permissions ツールのプロンプト", + "granular_mcp_elicitations": "MCP elicitation のプロンプト", + "sandboxModeLabel": "サンドボックスモード", + "sandboxModeUnset": "未設定(信頼済みフォルダはワークスペース書き込みにフォールバック)", + "sandboxMode_read-only": "読み取り専用", + "sandboxMode_workspace-write": "ワークスペース書き込み", + "sandboxMode_danger-full-access": "フルアクセス(サンドボックスなし)", + "sandboxModeHint": "Windows では、codex の実験的 Windows サンドボックスが無効な場合、ワークスペース書き込みは読み取り専用に降格されます。", + "sandboxModeSeedsPresetHint": "codeg はこれをセッションの初期承認プリセットにも反映するため、承認ポリシーとは異なり通常のプロンプトにも効きます。入力欄のプリセットが指定されている場合はそちらが優先されます。", + "writableRootsLabel": "追加の書き込み可能フォルダ", + "writableRootsHint": "作業ディレクトリに加えて許可する絶対パスを 1 行に 1 つ。", + "sandboxRootsRelativeError": "絶対パスである必要があります — codex は相対パスを ~/.codex 基準で解決します: {path}", + "networkAccessLabel": "ネットワークアクセスを許可", + "excludeTmpdirLabel": "書き込み可能ルートから TMPDIR を除外", + "excludeSlashTmpLabel": "書き込み可能ルートから /tmp を除外", + "authJsonNative": "auth.json(ネイティブ)", + "configTomlNative": "config.toml(ネイティブ)", + "loginButton": "ChatGPT でログイン", + "loginRequesting": "ログインコードを取得中...", + "loginStep1": "ブラウザで以下の URL を開いてください:", + "loginStep2": "以下のコードを入力してください:", + "loginPolling": "認証を待っています...", + "loginCancel": "キャンセル", + "loginSuccess": "ログイン成功、設定を保存しました!", + "loginFailed": "ログインに失敗しました:{message}", + "loginRetry": "再試行", + "loginCodeCopied": "コードをコピーしました", + "loggedIn": "アカウントにログイン済み", + "loginRelogin": "再ログイン / アカウント切替", + "loginTimeout": "ログインがタイムアウトしました。再試行してください", + "loginSaveFailed": "ログインは成功しましたが、設定の保存に失敗しました" + }, + "gemini": { + "authConfig": "Gemini 認証設定", + "authConfigDescription": "Gemini CLI の認証ドキュメントに準拠し、カスタムエンドポイント、Google ログイン、Gemini API Key、Vertex AI(ADC / サービスアカウント / API Key)をサポートします。", + "authMode": "認証モード", + "selectAuthMode": "認証モードを選択", + "viewAuthDoc": "認証ドキュメントを見る", + "mode": { + "custom": "カスタムエンドポイント", + "loginGoogle": "Google ログイン(OAuth)", + "vertexServiceAccount": "Vertex AI(サービスアカウント)" + }, + "hint": { + "custom": "API URL、API Key、Model を入力してください。GOOGLE_GEMINI_BASE_URL / GEMINI_API_KEY / GEMINI_MODEL に対応します。", + "loginGoogle": "先にターミナルで gemini を実行して Google ログインを完了してください。API key は不要です。", + "geminiApiKey": "Gemini API を使う場合は GEMINI_API_KEY を入力してください。", + "vertexAdc": "gcloud ADC を使用します。GOOGLE_CLOUD_PROJECT と GOOGLE_CLOUD_LOCATION の設定を推奨します。", + "vertexServiceAccount": "サービスアカウント JSON のパスを GOOGLE_APPLICATION_CREDENTIALS に設定してください。", + "vertexApiKey": "Vertex AI API key を使う場合は GOOGLE_API_KEY を入力してください。" + } + }, + "openCode": { + "configManagement": "OpenCode 設定管理", + "configDescription": "OpenCode の `provider` スキーマに準拠し、複数プロバイダー管理とネイティブ JSON ファイルとの双方向同期をサポートします。", + "providerManagement": "プロバイダー管理", + "providerCount": "{count} 個のプロバイダー", + "addProvider": "プロバイダーを追加", + "emptyProvider": "カスタムプロバイダーはまだありません。「カスタムプロバイダーを追加」をクリックして作成してください。", + "providerEnabledState": "{providerId} の有効状態", + "selectProviderNpm": "provider.npm を選択", + "modelManagement": "モデル管理", + "modelCount": "{count} 個のモデル", + "modelDescription": "OpenCode の `provider.models` に準拠。高速管理では現在 `name` / `id` をサポートし、その他の高度な項目は保持され、下部のネイティブ JSON で編集できます。", + "addModel": "モデルを追加", + "emptyModel": "まだモデルがありません。model id を入力して「モデルを追加」をクリックしてください。", + "modelId": "モデル ID", + "modelName": "モデル名", + "deleteModel": "モデル {modelId} を削除", + "nativeJsonConfig": "OpenCode ネイティブ JSON 設定", + "mainModel": "メインモデル", + "smallModel": "スモールモデル", + "noMatchingModels": "一致するモデルがありません", + "connectProvider": "プロバイダーを接続", + "connectedProviders": "接続済みプロバイダー", + "noConnectedProviders": "カタログのプロバイダーはまだ接続されていません。", + "advancedProviderConfig": "カスタムプロバイダー", + "customProviderConfigHint": "自分で定義する OpenAI 互換エンドポイント——opencode.json の provider ブロックで、API キーは auth.json に保存されます。", + "addCustomProvider": "カスタムプロバイダーを追加", + "disconnect": "切断", + "editConfig": "編集", + "customBadge": "カスタム", + "authKindApi": "API キー", + "authKindOauth": "OAuth", + "authKindNone": "認証情報なし", + "connect": { + "title": "プロバイダーを接続", + "description": "models.dev カタログからプロバイダーを選択します。認証情報は OpenCode の auth.json に保存されます。", + "pick": "プロバイダー", + "search": "プロバイダーを検索…", + "loading": "カタログを読み込み中…", + "catalogLabel": "models.dev カタログ", + "modelsAvailable": "{count} 個のモデルが利用可能", + "getKey": "API キーを取得", + "oauthApiKeyNote": "このプロバイダーは opencode auth login によるブラウザサインインにも対応しています。ブラウザサインインは近日対応予定です。今は API キーを貼り付けてください。", + "apiKey": "API キー", + "apiKeyHint": "auth.json に保存され、opencode.json には書き込まれません。", + "baseUrlOptional": "Base URL の上書き(任意)", + "providerId": "プロバイダー ID", + "displayName": "表示名", + "modelsList": "モデル(1 行に 1 つ)", + "modelsHint": "エンドポイントが受け付けるモデル ID。", + "action": "接続", + "editTitle": "プロバイダーを編集", + "editDescription": "このプロバイダーの API キーまたは Base URL を更新します。", + "saveAction": "保存" + }, + "customProvider": { + "title": "カスタムプロバイダーを追加", + "description": "OpenAI 互換エンドポイントを定義します。API キーは auth.json に、provider ブロックは opencode.json に保存されます。", + "action": "プロバイダーを追加", + "idInCatalog": "{providerId} は既知のプロバイダーです。「プロバイダーを接続」から接続してください。" + }, + "refreshCatalog": "カタログを更新", + "reasoningBadge": "推論", + "contextWindow": "コンテキストウィンドウ", + "permissions": { + "title": "権限", + "description": "どの操作をそのまま実行し、確認を求め、あるいはブロックするかを決めます。opencode.json の permission 設定に書き込まれ、下の保存で反映されます。", + "docsLink": "権限のドキュメント", + "unparsableConfig": "下のネイティブ JSON が解析できないため、ビジュアル編集を停止しています。JSON を修正すると再開します。", + "invalidBlock": "permission 設定の形式を認識できません。下のネイティブ JSON で編集するか、「リセット」でやり直してください。", + "orderingUnsafe": "ワイルドカードのルールが個別のツールより後に書かれているため、OpenCode はそれらにも適用します。下の各行は実際に有効な設定ではありません。「順序を修正」は値を変えずに、各スコープの先頭へワイルドカードを戻すだけです。", + "orderingUnsafeManual": "あるルールが後方のより広いパターンに隠されており、OpenCode は決して適用しません。下の各行は実際に有効な設定ではありません。重なり合う 2 つのパターンに唯一の正しい順序はないため、下のネイティブ JSON で広いほうを先に並べ替えてください。", + "fixOrder": "順序を修正", + "agentOverrides": "次のエージェントは権限を個別に上書きしており、最後に適用されるためここの設定より優先されます: {agents}。下のネイティブ JSON で編集するか、自動承認をオンにして削除してください。", + "legacyTools": "トップレベルの旧 tools 設定がツールを拒否しています。OpenCode はこれを権限に統合するため、ここに表示されている設定すべての上に適用されます。下のネイティブ JSON で編集するか、自動承認をオンにして削除してください。", + "autoAcceptTitle": "すべての権限を自動承認", + "autoAcceptHint": "シェルコマンド、ファイル編集、プロジェクト外のパスを含むすべてのツール呼び出しを確認なしで実行します。オンにすると、下のツール別設定は 1 つの全許可ルールに置き換わり、そのままではブロックし続けるエージェントごとの権限の上書きと旧 tools 設定も削除されます。", + "globalLabel": "全体のデフォルト", + "globalHint": "* ルールです。下のツールで上書きされていないものすべてに適用されます。", + "actionUnset": "未設定(OpenCode のデフォルト)", + "actionInherit": "デフォルトに従う({action})", + "actionAllow": "許可", + "actionAsk": "確認する", + "actionDeny": "拒否", + "perToolTitle": "ツール別の権限", + "reset": "リセット", + "ruleCount": "ルール: {count}", + "rulesToggle": "{tool} の詳細ルール", + "rulesHint": "ツールの入力に対して照合し、最後に一致したルールが優先されます。広いパターンを先に書いてください。* は任意の文字列、? はちょうど 1 文字に一致し、先頭の ~ はホームディレクトリに展開されます。", + "noRules": "詳細ルールはまだありません。", + "addRule": "ルールを追加", + "deleteRule": "ルール {pattern} を削除", + "duplicateRule": "そのパターンは既に存在します。", + "blankRule": "ルールにはパターンが必要です。削除するにはゴミ箱アイコンを使ってください。", + "customKeys": "ファイル内のその他の権限キー", + "customKeyHint": "OpenCode の組み込みツールではありません。記述どおり保持されます。", + "keys": { + "bash": "シェルコマンドの実行。解析後のコマンドで照合", + "edit": "ファイルへのすべての変更(edit・write・patch)", + "read": "ファイルの読み取り。パスで照合", + "external_directory": "プロジェクトの作業ディレクトリ外のパスへのアクセス", + "task": "サブエージェントの起動。サブエージェントの種類で照合", + "skill": "スキルの読み込み。スキル名で照合", + "glob": "ファイル検索。グロブパターンで照合", + "grep": "ファイル内容の検索。パターンで照合", + "list": "ディレクトリ内容の一覧表示", + "webfetch": "URL の取得", + "websearch": "ウェブ検索", + "lsp": "LSP クエリの実行", + "todowrite": "TODO リストの書き込み", + "question": "あなたへの質問", + "doom_loop": "同じ入力で同じ呼び出しが 3 回繰り返されたときに作動" + } + } + }, + "openClaw": { + "gatewayConfig": "Gateway 設定", + "gatewayDescription": "OpenClaw Gateway 接続を設定します。ローカルまたはリモートの gateway をサポートします。", + "gatewayUrlHint": "空欄の場合はローカル openclaw 設定の gateway.remote.url を使用します。", + "gatewayTokenPlaceholder": "Gateway 認証トークン", + "gatewayTokenHint": "可能な場合は平文トークンではなく token-file の使用を推奨します。openclaw CLI で設定してください。", + "sessionKeyHint": "任意。gateway の session key を指定します。空欄の場合は分離されたセッションが自動割り当てされます。" + }, + "hermes": { + "configManagement": "Hermes 設定", + "configDescription": "Hermes は認証情報を ~/.hermes/.env に、設定を ~/.hermes/config.yaml に独自に管理します。プロバイダーを選択し、API キーとモデルを設定してください。codeg が両方のファイルを書き込みます。", + "providerLabel": "プロバイダー", + "providerHint": "プロバイダーによって、Hermes が使用する API キー変数と model.provider が決まります。OAuth プロバイダーは下のターミナルセットアップから設定します。", + "groupApiKey": "API キー プロバイダー", + "groupOauth": "OAuth プロバイダー", + "groupAws": "AWS", + "apiKeyHint": "~/.hermes/.env に保存されます。プロセスには注入されません。Hermes が独自の設定から読み取ります。", + "modelName": "モデル", + "oauthHint": "このプロバイダーは OAuth を使用します。下のセットアップを実行し、ターミナルで認証してください。", + "awsHint": "Bedrock は AWS の認証情報(環境変数または共有設定)を使用します。上でモデル ID を設定し、環境で AWS アクセスを構成してください。", + "unsupportedProvider": "このプロバイダーは構造化フィールドでは編集できません。下の config.yaml 直接編集またはターミナルセットアップを使用してください。", + "setupTitle": "自己管理セットアップ", + "setupHint": "Hermes の対話型セットアップにはターミナルが必要です。下から起動するか、コマンドをコピーして自分で実行してください。", + "runSetup": "Hermes セットアップを実行", + "configureModel": "モデルを設定", + "openConfigFolder": "~/.hermes を開く", + "copyCommand": "コマンドをコピー", + "commandCopied": "コマンドをクリップボードにコピーしました", + "advancedTitle": "詳細: config.yaml を編集", + "rawConfigHint": "~/.hermes/config.yaml を直接編集します。ここで保存すると、ファイルがそのまま上書きされます。", + "saveRawConfig": "config.yaml を保存" + }, + "codebuddy": { + "configManagement": "CodeBuddy の設定", + "configDescription": "CodeBuddy は API キーで認証します。中国版では環境を「中国版(internal)」に設定する必要があります。iOA 版は「iOA」を使用し、海外版は未設定のままにします。", + "apiKeyLabel": "API キー", + "apiKeyHint": "このエージェントの CODEBUDDY_API_KEY として保存されます。または、ターミナルで CodeBuddy CLI からサインインすることもできます。", + "apiKeyHintSelfHosted": "このエージェントの CODEBUDDY_API_KEY として保存されます。プライベート展開で発行されたキーを使用してください。", + "environmentLabel": "環境", + "environmentHint": "CODEBUDDY_INTERNET_ENVIRONMENT を設定します。中国本土では「中国版(internal)」を使用する必要があります。海外版は未設定のままにします。", + "envOverseas": "海外版(デフォルト)", + "envChina": "中国版(internal)", + "envIoa": "iOA", + "envSelfHosted": "プライベート展開(セルフホスト)", + "baseUrlLabel": "デプロイ URL", + "baseUrlPlaceholder": "https://codebuddy.your-company.com", + "baseUrlHint": "CODEBUDDY_BASE_URL として保存され、CodeBuddy をプライベートエンドポイントに向けます。セルフホストではネットワーク環境(CODEBUDDY_INTERNET_ENVIRONMENT)は設定しません。", + "baseUrlInvalid": "有効な http(s) URL を入力してください。", + "loginHint": "API キーがない場合は、ターミナルで「codebuddy」を実行して Tencent アカウントでサインインすることもできます。" + }, + "kimiCode": { + "configManagement": "Kimi Code の設定", + "configDescription": "`kimi acp` は保存済みのログイントークンしか受け付けないため、codeg は ~/.kimi-code/config.toml に管理対象プロバイダーを書き込み、ローカルにゲートトークンを配置します。推論は引き続きご自身のキーで実行されます。", + "statusUnconfigured": "未設定", + "statusDirty": "未保存の変更あり", + "summaryLabel": "有効な設定", + "gateReadyApiKey": "API キーを config.toml に書き込み済み", + "gateReadyLogin": "Kimi アカウントでログイン済み", + "revealConfig": "フォルダーで表示", + "envOverrideWarning": "{keys} が設定されており、config.toml より優先されます。ここで保存すると自動的に削除されます。", + "authModeLabel": "認証方式", + "authModeApiKey": "API キー", + "authModeLogin": "Kimi アカウントログイン(サブスクリプション)", + "authModeApiKeyHint": "config.toml に管理対象プロバイダーを書き込み、セッションを開けるようゲートトークンを配置します。", + "loginHint": "ターミナルで `kimi login` を実行し、Kimi サブスクリプションアカウントでログインしてください。codeg は資格情報を保存せず、Kimi 自身のログインを再利用します。ここで保存すると codeg の API キー用ゲートトークンが削除されます。", + "credentialTitle": "資格情報", + "interfaceTypeLabel": "プロバイダー種別", + "interfaceTypeHint": "Kimi が話すプロバイダープロトコル(config.toml の `type`)。Moonshot / platform.kimi.com のキーには「Kimi / Moonshot」を選びます。", + "endpointLabel": "エンドポイント", + "endpointCustom": "カスタム(OpenAI 互換)", + "endpointHint": "国際 = api.moonshot.ai、中国(platform.kimi.com のキー)= api.moonshot.cn。カスタムは任意の OpenAI 互換エンドポイントを指定できます。", + "regionInternational": "国際(api.moonshot.ai)", + "regionChina": "中国(api.moonshot.cn)", + "baseUrlLabel": "Base URL", + "baseUrlHint": "空欄の場合はプロバイダー SDK の既定値を使用します。", + "apiKeyLabel": "API キー", + "apiKeyHint": "~/.kimi-code/config.toml に書き込まれ、推論に使用されます。platform.kimi.com または platform.kimi.ai で取得できます。", + "vertexProjectLabel": "GCP プロジェクト(GOOGLE_CLOUD_PROJECT)", + "vertexLocationLabel": "GCP リージョン(GOOGLE_CLOUD_LOCATION)", + "vertexHint": "Vertex AI は Google のアプリケーションデフォルト認証情報を使用します。`gcloud auth application-default login` を実行してください(API キー不要)。", + "modelTitle": "モデル", + "modelLabel": "モデル", + "modelHint": "config.toml に書き込まれるモデル id。「テストしてモデルを取得」でキーが実際にアクセスできるモデルを確認できます。", + "maxContextLabel": "最大コンテキスト長", + "maxContextHint": "Kimi のスキーマ上必須です。未指定だと Kimi がモデルブロック全体を破棄し、どのプロンプトも応答が返らなくなります。既定値は 262144。", + "fetchModels": "テストしてモデルを取得", + "fetchModelsOk": "キーは有効です — {count} 件のモデルが利用可能", + "fetchModelsEmpty": "キーは有効ですが、モデルが返されませんでした", + "fetchModelsFailed": "テストに失敗しました", + "fetchModelsNeedsKey": "先に API キーとエンドポイントを入力してください", + "modelNotInList": "このモデルはキーがアクセスできる一覧に含まれていません。Kimi は「モデルが見つかりません」で失敗します。", + "reasoningTitle": "推論", + "reasoningEnableLabel": "有効にする", + "reasoningDescription": "モデルが推論機能を宣言している場合にのみ Kimi は入力欄に「Thinking」ピッカーを表示するため、その宣言を codeg がここで書き込みます。新しいセッションから有効になります。", + "effortsLabel": "選択できるレベル", + "effortsHint": "ここで選んだ値が入力欄の「Thinking」ピッカーの項目になります。Kimi はレベルをそのままプロバイダーへ渡すので、モデルが受け付ける値を選んでください。", + "effortsEmptyHint": "レベルを 1 つも選ばない場合、入力欄は Off / On の 2 段トグルに退化します。", + "effortsCustomPlaceholder": "他のレベルを追加", + "effortsAdd": "追加", + "defaultEffortLabel": "既定のレベル", + "defaultEffortAuto": "Kimi に任せる", + "alwaysThinkingLabel": "モデルは常に推論する — ピッカーから Off を削除", + "fixErrorsFirst": "先に赤色の項目を修正してください", + "errorModelRequired": "モデルは必須です", + "errorMaxContextRequired": "最大コンテキスト長は必須です", + "errorMaxContextInvalid": "正の整数を入力してください", + "errorApiKeyRequired": "API キーは必須です", + "errorApiKeyInvalid": "API キーに改行を含めることはできません", + "errorBaseUrlRequired": "Base URL は必須です", + "errorBaseUrlInvalid": "http:// または https:// で始める必要があります", + "errorVertexProjectRequired": "GCP プロジェクトは必須です", + "errorDefaultEffortUnlisted": "上で選択したレベルのいずれかを指定してください", + "advancedTitle": "詳細設定", + "authTypeLabel": "資格情報の書き込み先", + "authTypeApiKey": "インライン api_key", + "authTypeEnv": "プロバイダーの env サブテーブル", + "authTypeHint": "config.toml 内で API キーを書き込む場所。", + "rawEditorLabel": "config.toml を直接編集", + "rawEditorWarning": "ここで保存するとファイル全体がそのまま上書きされ、上の構造化設定が置き換えられます。", + "rawEditorPlaceholder": "[providers.codeg]\ntype = \"kimi\"\nbase_url = \"https://api.moonshot.cn/v1\"\napi_key = \"sk-...\"" + }, + "authModeOfficialSubscription": "公式サブスクリプション", + "authModeCustomEndpoint": "カスタムエンドポイント", + "authModeCustomEndpointHint": "API URL と API Key を手動で設定してカスタムエンドポイントに接続します。", + "authModeModelProvider": "モデルプロバイダー", + "modelProvider": "モデルプロバイダー", + "modelProviderHint": "設定済みモデルプロバイダーの API URL、API Key、モデルを使用します。", + "selectModelProvider": "モデルプロバイダーを選択", + "noModelProviderAvailable": "このエージェントにはモデルプロバイダーが設定されていません。モデルプロバイダー設定で追加してください。", + "claude": { + "authMode": "認証方式", + "officialSubscription": "公式サブスクリプション", + "officialSubscriptionHint": "Anthropic 公式サブスクリプションを使用、API Key 不要。", + "mainModel": "メインモデル", + "reasoningModel": "推論モデル(thinking)", + "haikuDefaultModel": "デフォルト Haiku モデル", + "sonnetDefaultModel": "デフォルト Sonnet モデル", + "opusDefaultModel": "デフォルト Opus モデル", + "customModelOption": "カスタムモデル ID", + "customModelOptionName": "カスタムモデル名", + "customModelOptionDescription": "カスタムモデルの説明", + "customModelOptionHint": "Claude のモデル選択メニューにカスタム項目を1つ追加します(例: カスタムゲートウェイ/プロキシ経由のモデル)。名前と説明は任意の表示用設定です。", + "effortLevel": "推論レベル", + "effortLevelDefault": "デフォルトレベル", + "effortLevel_low": "低", + "effortLevel_medium": "中", + "effortLevel_high": "高", + "effortLevel_xhigh": "超高", + "sendAttributionHeader": "API に帰属/課金識別子を送信", + "sendAttributionHeaderAria": "API に Claude Code の帰属/課金識別子を送信", + "disableNonessentialTraffic": "テレメトリや不要なネットワークリクエストを無効化", + "disableNonessentialTrafficAria": "Claude Code のテレメトリや不要なネットワークリクエストを無効化" + }, + "dialogs": { + "confirmDeleteProvider": "Provider {providerId} を削除しますか?", + "confirmDeleteProviderDescription": "OpenCode config と auth JSON は同時に更新されます。この操作は元に戻せません。", + "confirmUninstall": "{name} をアンインストールしますか?", + "confirmUninstallDescription": "ローカルにインストールされたバージョンを削除します。後で再インストールできます。", + "customInstallTitle": "{name} をカスタムインストール", + "customInstallDescription": "インストールするバージョンを入力します。再インストールされ、現在インストールされているバージョンを置き換えます。", + "customInstallVersionLabel": "バージョン番号", + "customInstallInvalid": "有効なバージョン番号を入力してください(例: 1.2.3)。", + "customInstallSubmit": "インストール" + }, + "errors": { + "windowsFileLocked": "{name} のファイルは実行中のセッションが使用中のため、Windows では置き換えられません。{name} のセッションをすべて終了してから再試行してください。", + "nativeJsonMustBeObject": "ネイティブJSON設定はオブジェクトである必要があります", + "nativeJsonInvalid": "ネイティブJSON設定の形式エラー: {message}", + "openCodeAuthMustBeObject": "OpenCode の auth.json はJSONオブジェクトである必要があります", + "openCodeAuthInvalid": "OpenCode の auth.json 形式エラー: {message}", + "authMustBeObject": "auth.json はJSONオブジェクトである必要があります", + "authInvalid": "auth.json 形式エラー: {message}", + "providerIdPattern": "Provider ID は英字・数字・アンダースコア・ドット・ハイフンのみ使用できます", + "providerExists": "Provider {providerId} はすでに存在します", + "modelIdPattern": "Model ID は英字・数字・アンダースコア・ドット・コロン・ハイフンのみ使用できます", + "modelExists": "Model {modelId} はすでに存在します" + }, + "warnings": { + "nativeJsonRecoveredStructured": "ネイティブJSON設定が不正のため、構造化設定にリセットしました", + "nativeJsonRecoveredOpenCode": "ネイティブJSON設定が不正のため、OpenCode構造化設定にリセットしました", + "openCodeAuthRecovered": "OpenCode の auth.json が不正のため、デフォルト設定にリセットしました", + "authRecoveredStructured": "auth.json が不正のため、構造化設定にリセットしました" + }, + "toasts": { + "agentActionCompleted": "{name} の {action} が完了しました", + "agentActionFailed": "{name} の {action} に失敗しました", + "localVersion": "ローカルバージョン: {version}", + "installCompletedVersionLater": "インストールが完了しました。バージョンは次回チェック時に更新されます", + "uninstallCompleted": "{name} のアンインストールが完了しました", + "uninstallFailed": "{name} のアンインストールに失敗しました", + "localVersionRemoved": "ローカルバージョンを削除しました", + "saveAgentOrderFailed": "Agent の並び順の保存に失敗しました", + "saveAgentSwitchFailed": "Agent の有効スイッチ保存に失敗しました", + "saveEnvFailed": "環境変数の保存に失敗しました", + "grokSaved": "Grok 設定を保存しました", + "saveGrokNativeFailed": "Grok のネイティブ設定の保存に失敗しました", + "saveGrokApiKeyFailed": "設定は保存されましたが、API キーを保存できませんでした", + "cursorSaved": "Cursor の設定を保存しました", + "saveCursorConfigFailed": "Cursor の設定の保存に失敗しました", + "codexSaved": "Codex設定を保存しました", + "saveCodexNativeFailed": "Codexネイティブ設定の保存に失敗しました", + "geminiSaved": "Gemini設定を保存しました", + "saveGeminiFailed": "Gemini設定の保存に失敗しました", + "providerDeleted": "Provider {providerId} を削除しました", + "providerDeleteFailed": "Provider {providerId} の削除に失敗しました", + "providerSaved": "Provider {providerId} を保存しました", + "saveProviderFailed": "Provider {providerId} の保存に失敗しました", + "openCodeConfigSynced": "OpenCode config と auth JSON が同期されました。", + "openCodeSaved": "OpenCode設定を保存しました", + "saveOpenCodeFailed": "OpenCode設定の保存に失敗しました", + "openClawSaved": "OpenClaw設定を保存しました", + "saveOpenClawFailed": "OpenClaw設定の保存に失敗しました", + "configSaved": "設定を保存しました", + "configSavedHint": "既存のセッションは再度開く必要があります", + "saveConfigManagementFailed": "設定管理の保存に失敗しました", + "clineSaved": "Cline設定を保存しました", + "saveClineFailed": "Cline設定の保存に失敗しました", + "hermesSaved": "Hermes設定を保存しました", + "saveHermesFailed": "Hermes設定の保存に失敗しました", + "codeBuddySaved": "CodeBuddy の設定を保存しました", + "saveCodeBuddyFailed": "CodeBuddy の設定の保存に失敗しました", + "kimiCodeSaved": "Kimi Code の設定を保存しました", + "saveKimiCodeFailed": "Kimi Code の設定の保存に失敗しました", + "deepseekSaved": "DeepSeek の設定を保存しました", + "saveDeepSeekFailed": "DeepSeek の設定の保存に失敗しました", + "modelProviderRequired": "保存する前にモデルプロバイダーを選択してください。", + "affectedRunningSessions": "{count} 件の実行中セッションは再接続すると変更が適用されます", + "providerConnected": "{providerId} を接続しました", + "connectFailed": "{providerId} の接続に失敗しました", + "providerDisconnected": "{providerId} を切断しました", + "disconnectFailed": "{providerId} の切断に失敗しました", + "catalogRefreshed": "カタログを更新しました — {count} 個のプロバイダー", + "catalogRefreshFailed": "カタログの更新に失敗しました", + "piSaved": "Pi 設定を保存しました", + "savePiFailed": "Pi 設定の保存に失敗しました", + "piRuntimeSaved": "Pi ランタイムを保存しました", + "savePiRuntimeFailed": "Pi ランタイムの保存に失敗しました", + "piBinaryInstalled": "pi をインストールしました", + "piBinaryInstallFailed": "pi のインストールに失敗しました", + "piBinaryUninstalled": "pi をアンインストールしました", + "piBinaryUninstallFailed": "pi のアンインストールに失敗しました", + "savePiTrustFailed": "ワークスペースの信頼設定の保存に失敗しました" + }, + "version": { + "statusLabel": "バージョン状態", + "notInstalled": "未インストール", + "remoteLocal": "リモート: {remoteVersion} · ローカル: {localVersion}", + "localOnly": "ローカル:{localVersion}", + "localInstalled": "{versionText}。インストール済みです。", + "platformUnsupported": "{versionText}。現在のプラットフォームではこのエージェントをサポートしていません。", + "uvxNotReady": "{versionText}。uv ランタイムが未インストールです。下の uv チェックからインストールするとこのエージェントを使用できます。", + "clickInstall": "{versionText}。右側の「インストール」をクリックしてください。", + "localUnrecognized": "{versionText}。ローカルバージョンは比較できません。上書きインストールのためアップグレードを試してください。", + "upgradeAvailable": "{versionText}。アップグレード可能です。", + "remoteUnavailable": "{versionText}。現在リモートバージョンは取得できません。", + "latest": "{versionText}。すでに最新です。" + }, + "adapter": { + "label": "ACP アダプター", + "badge": "ACP アダプター", + "badgeHint": "このエージェントで Codeg がインストールするのはベンダー CLI ではなく ACP アダプターのパッケージです。両者は独立しており、設定は共有されます。", + "learnMore": "詳細", + "missingWithNative": "お使いの {nativeLabel} を {nativePath} で検出しました。Codeg はエージェントを ACP で駆動しますが、この CLI 自体は ACP に対応していないため、別パッケージのアダプター {adapterPackage}(Agent Client Protocol プロジェクトが保守。当初は Zed チーム)が必要です。独自のランタイムを同梱しており、既存の {nativeCmd} コマンドを変更も置き換えもしません。読み込む設定は同じ {configDir} なので、ログインと設定はそのまま引き継がれます。下のボタンからインストールしてください。", + "missing": "Codeg はエージェントを ACP で駆動しますが、{nativeLabel} 自体は ACP に対応していないため、別パッケージのアダプター {adapterPackage}(Agent Client Protocol プロジェクトが保守。当初は Zed チーム)が必要です。独自のランタイムを同梱しているので {nativeCmd} CLI を先に入れる必要はありません。すでにお持ちの場合も両者は共存し、{configDir} のログインと設定を共有します。下のボタンからインストールしてください。", + "readyWithNative": "アダプター {adapterCmd} はインストール済みです。Codeg が起動するのはこちらで、あなたの {nativeCmd}({nativePath})ではありません。両者は独立したパッケージとして共存し、どちらも {configDir} を読むためログインと設定は共有されます。", + "ready": "アダプター {adapterCmd} はインストール済みで、Codeg が起動するのはこれです。独自のランタイムを同梱しているため {nativeLabel} は不要です。後から入れても両者は共存し、{configDir} を共有します。" + }, + "cline": { + "configDescription": "Cline API プロバイダーと認証情報を設定します。設定は ~/.cline/data/ に保存されます。" + }, + "opencodePlugins": { + "title": "OpenCode プラグイン", + "declared": "宣言済みプラグイン", + "noPlugins": "opencode.json にプラグインが宣言されていません", + "status": { + "installed": "インストール済み", + "missing": "未インストール" + }, + "installAll": "不足プラグインをすべてインストール", + "pinVersions": "@latest バージョンを固定", + "install": "インストール", + "uninstall": "アンインストール", + "refresh": "更新", + "success": "すべてのプラグインが正常にインストールされました", + "failed": "プラグイン操作に失敗しました" + }, + "pi": { + "configManagement": "Pi 設定", + "configDescription": "Pi はモデルプロバイダーの API キーで認証します。キーは ~/.pi/agent/auth.json に、モデル選択は settings.json に書き込まれます。", + "providerLabel": "プロバイダー", + "modelLabel": "モデル", + "thinkingLabel": "思考", + "thinking": { + "off": "オフ", + "low": "低", + "medium": "中", + "high": "高", + "minimal": "最小", + "xhigh": "最高" + }, + "apiKeyLabel": "API キー", + "apiKeyHint": "選択したプロバイダーの ~/.pi/agent/auth.json に保存されます。", + "apiKeySetPlaceholder": "••••••(保存済み・空欄で維持)", + "saveConfig": "Pi 設定を保存", + "providerModelRequired": "プロバイダーとモデルは必須です", + "runtimeTitle": "ランタイム", + "runtimeDescription": "どの pi を実行するか選択します。デフォルト、または自分の pi ビルドを指定します。", + "modeDefault": "デフォルト pi", + "modeDefaultHint": "内蔵の pi-acp アダプターで PATH 上の pi を起動します。 pi のインストール:npm install -g @earendil-works/pi-coding-agent", + "modeCustom": "カスタム pi", + "modeCustomHint": "自分の pi ビルド・インストール・ラッパーを実行します。", + "commandLabel": "pi コマンドまたはパス", + "commandHint": "絶対パス、PATH 上のコマンド名、またはラッパースクリプト(例: monorepo の ./pi-test.sh)。", + "commandNotFound": "コマンドが見つかりません", + "validate": "検証", + "advanced": "詳細設定", + "configDirLabel": "設定ディレクトリ (PI_CODING_AGENT_DIR)", + "sessionDirLabel": "セッションディレクトリ (PI_CODING_AGENT_SESSION_DIR)", + "flagsHint": "pi-acp はカスタム pi フラグ(--approve、-e など)を転送しません。pi をスクリプトでラップしてコマンドに指定してください。", + "customIncomplete": "保存するには pi コマンドを入力してください", + "saveRuntime": "ランタイムを保存", + "providerPlaceholder": "プロバイダーを選択", + "customProvider": "カスタムプロバイダー…", + "providerIdLabel": "プロバイダー ID", + "apiProtocolLabel": "API プロトコル", + "baseUrlLabel": "API エンドポイント(Base URL)", + "customProviderHint": "~/.pi/agent/models.json にエンドポイント向けのプロバイダーを定義します。多くのセルフホスト/プロキシは openai-completions を使用します。", + "baseUrlRequired": "API エンドポイント(Base URL)は必須です", + "binaryTitle": "pi バイナリ (pi-coding-agent)", + "binaryDescription": "pi-acp はこの pi バイナリを実行します。ここでインストールするか、下で独自のビルドを指定できます。", + "binaryInstalled": "インストール済み", + "binaryMissing": "未インストール", + "binaryChecking": "確認中…", + "installBinary": "pi をインストール", + "installing": "インストール中…", + "recheck": "再確認", + "configDirSkillsNote": "カスタム設定ディレクトリを指定すると、設定画面で管理するスキル・エキスパート・オフィスツールはこの pi に適用されません。スキルはそのフォルダー内で直接管理してください。", + "projectTrustTitle": "プロジェクトの信頼", + "projectTrustDescription": "pi にプロジェクトファイルの読み込みを許可したフォルダーです。信頼したフォルダーでは、そのリポジトリの .pi/extensions が pi の起動時にコードを実行します。配下のすべてのフォルダーに適用され、ターミナルで pi を実行するときにも使われます。", + "projectTrustLoading": "読み込み中…", + "projectTrustEmpty": "まだ判断したフォルダーはありません。", + "projectTrustTrusted": "信頼済み", + "projectTrustDenied": "信頼しない", + "projectTrustRevoke": "取り消す", + "reasoningTitle": "推論", + "reasoningEnableLabel": "有効にする", + "reasoningDescription": "モデルが推論能力を宣言している場合にのみ、pi は推論強度を送信します。未宣言のモデルではすべてのレベルが Off に丸められるため、入力欄のセレクターは触れた瞬間に戻ってしまいます。models.json のこのモデルの項目に書き込まれます。", + "levelsLabel": "選択できるレベル", + "levelsHint": "入力欄の推論セレクターの項目になります。エンドポイントが受け付ける値を選んでください。ここにないレベルは pi が拒否します。", + "levelsEmptyError": "レベルを 1 つ以上選んでください。1 つも選ばないと pi は Off に戻ります。", + "wireValuesTitle": "詳細: プロバイダーに送る値", + "wireValuesHint": "空欄ならレベル名をそのまま送信します。エンドポイントが別の表記を求める場合のみ設定してください(Google 系は LOW / HIGH)。", + "defaultLevelUnlisted": "このレベルは上の選択リストにありません。pi が丸めてしまいます。" + }, + "addCustomAgent": "カスタムエージェントを追加", + "addCustomAgentHint": "ACP 対応のエージェントを追加できます。公開 ACP レジストリから選ぶか、レジストリ情報を貼り付けてください。", + "customAgentFromRegistry": "ACP レジストリ", + "customAgentManual": "手動入力", + "customAgentSearchPlaceholder": "エージェントを検索…", + "customAgentLoadingCatalog": "ACP レジストリを読み込み中…", + "customAgentRetry": "再試行", + "customAgentNoResults": "該当するエージェントがありません", + "customAgentAdd": "追加", + "customAgentAlreadyAdded": "追加済み", + "customAgentUnsupportedPlatform": "このプラットフォーム向けのビルドがありません", + "customAgentAdded": "{name} を追加しました", + "customAgentIdLabel": "レジストリ ID", + "customAgentNameLabel": "表示名", + "customAgentVersionLabel": "バージョン", + "customAgentSpecLabel": "配布情報(JSON)", + "customAgentSpecHint": "ACP レジストリの distribution オブジェクトと同じ形式です。npx・uvx・binary の各チャネルに対応し、レジストリ項目全体の貼り付けも可能です。npx/uvx の cmd はパッケージがインストールする実行コマンド名で、省略時はパッケージ名から導出されるため、異なる場合は指定してください。binary はプラットフォームキーごとに指定し(このマシンは {platform})、cmd はアーカイブ内の起動パス、sha256 は任意でダウンロードを検証します。", + "customAgentTemplateLabel": "テンプレート", + "customAgentKindLabel": "起動方法", + "customAgentInvalidJson": "JSON として不正です", + "customAgentNoDistribution": "npx・uvx・binary のいずれの配布も見つかりません", + "customAgentCancel": "キャンセル", + "customAgentSave": "エージェントを追加", + "customAgentSaveChanges": "変更を保存", + "customAgentEdit": "エージェントを編集", + "customAgentEditHint": "名前・アイコン・配布情報・スキル宣言を変更できます。エージェント ID は変更できません。", + "customAgentEditNotFound": "カスタムエージェント {id} が見つかりません", + "customAgentSaved": "{name} を保存しました", + "customAgentVersionProbeLabel": "バージョン確認コマンド(任意)", + "customAgentVersionProbeHint": "ローカルにインストールされたバージョンを表示するコマンドです。空欄の場合はエージェントコマンドに --version を付けて実行します。", + "customAgentRemove": "エージェントを削除", + "customAgentRemoveHint": "エージェント定義を削除します。既存の会話の履歴は残り、エージェントを起動できなくなるだけです。", + "customAgentIconLabel": "アイコン(任意)", + "customAgentIconUpload": "アップロード", + "customAgentIconReplace": "変更", + "customAgentIconClear": "アイコンを削除", + "customAgentIconHint": "エージェントと共に保存されるためオフラインでも表示できます。指定しない場合は色付きの頭文字を使います。", + "customAgentSkillsLabel": "Skills(共有 .agents/skills)", + "customAgentSkillsHint": "このエージェントが共有の .agents/skills ディレクトリ(グローバルおよびプロジェクト)を読み取ることを宣言し、すべてのスキルマトリクスに追加します。共有ディレクトリにリンクしたスキルは、同じディレクトリを読むほかのエージェントからも見えます。", + "customAgentSkillsDirLabel": "専用スキルディレクトリ", + "customAgentSkillsDirHint": "このエージェントがスキルを読み込むディレクトリの絶対パスです。共有ストアと併用も単独利用も可能です。~ はホームディレクトリに展開され、リンクしたスキルはまずここに配置されます。", + "customAgentMcpLabel": "MCP サポート", + "customAgentMcpHint": "セッション開始時に codeg 内蔵の codeg-mcp コンパニオンをこのエージェントへ渡します。委任・リアルタイムフィードバック・タスクツールはこの経路を使います。MCP サーバーを受け付けず接続に失敗するエージェントではオフにしてください。設定は次回の接続から有効になります。", + "customAgentIconNotAnImage": "画像ファイルを選んでください。", + "customAgentIconTooLarge": "アイコンは {limit} KB 未満にしてください。", + "customAgentIconReadFailed": "その画像を読み込めませんでした。", + "customAgentRemoveConfirm": "{name} を削除しますか?既存の会話は残りますが、起動できなくなります。", + "customAgentRemoveWithData": "記録された会話履歴も削除する", + "customAgentRemoved": "{name} を削除しました", + "customAgentBadge": "カスタム", + "customAgentNotLaunchable": "この環境では起動できません: {reason}" + }, + "SettingsPages": { + "agentsLoading": "エージェント設定を読み込み中...", + "skillPacksLoading": "スキルパックを読み込み中…" + }, + "GeneralSettings": { + "loading": "読み込み中...", + "sectionTitle": "一般", + "sectionDescription": "デフォルトターミナル、レンダリング高速化、マルチエージェント委譲などの共通設定をここで一括管理します。", + "terminalTitle": "デフォルトターミナル", + "terminalDescription": "ターミナルバーやファイルツリーから新しいターミナルタブを開くときに使用するシェルを選択します。エージェントが codeg にコマンドライン全体の実行を依頼するときにも使われます。", + "terminalSystemDefault": "システムデフォルト", + "terminalPowerShell7": "PowerShell 7 (pwsh)", + "terminalWindowsPowerShell": "Windows PowerShell", + "terminalCmd": "コマンドプロンプト (cmd)", + "terminalSaveFailed": "ターミナル設定の保存に失敗しました: {message}", + "terminalShellCustom": "カスタムパス", + "terminalShellCustomPath": "Shell パス", + "terminalShellCustomPlaceholder": "/usr/local/bin/fish", + "terminalShellCustomSave": "保存", + "terminalShellCustomHint": "絶対パス、または PATH で解決可能なコマンド名を指定します。", + "terminalShellNotInstalled": "未インストール", + "terminalShellNotFoundWarning": "このパスはホスト上に存在しません。", + "terminalCurrentShell": "現在使用中: {path}", + "renderingDescription": "アプリで黒画面や描画不具合が発生する場合(一部の AMD GPU や Intel 内蔵 GPU で報告あり)、ハードウェアアクセラレーションを無効化してください。Windows デスクトップ版のみ有効です。", + "disableHardwareAcceleration": "ハードウェアアクセラレーションを無効化", + "renderingSaveFailed": "レンダリング設定の保存に失敗しました: {message}", + "restartRequired": "保存しました。再起動後に反映されます。", + "restartNow": "今すぐ再起動", + "restartFailed": "再起動に失敗しました: {message}", + "loadFailed": "読み込みに失敗しました: {message}" + }, + "LoginPage": { + "documentTitle": "ログイン - codeg", + "brand": "Codeg", + "subtitle": "デスクトップアプリに接続するためのアクセストークンを入力してください", + "tokenPlaceholder": "アクセストークン", + "connect": "接続", + "connecting": "接続中...", + "helpText": "トークンはデスクトップアプリの 設定 → Web サービス で取得できます", + "invalidToken": "トークンが無効です。確認して再度お試しください", + "connectionFailed": "接続失敗 (HTTP {status})", + "networkError": "サーバーに接続できません" + }, + "CommitPage": { + "title": "コミット", + "invalidFolderId": "無効なフォルダID", + "loadingRepo": "リポジトリを読み込み中..." + }, + "MergePage": { + "title": "コンフリクトの解決", + "invalidFolderId": "無効なフォルダID", + "loadingRepo": "リポジトリを読み込み中...", + "localVersion": "ローカル(自分側)", + "result": "結果", + "remoteVersion": "リモート(相手側)", + "acceptLocal": "ローカルを採用", + "acceptRemote": "リモートを採用", + "markResolved": "解決済みにする", + "abortMerge": "中止", + "completeMerge": "マージ完了", + "unresolvedConflicts": "ファイルに未解決のコンフリクトマーカーがあります", + "fileResolved": "ファイルが解決されました", + "allResolved": "すべてのコンフリクトが解決されました", + "conflictFiles": "コンフリクトファイル", + "loadingFile": "ファイルを読み込み中...", + "preparingMerge": "マージを準備中...", + "selectFile": "解決するファイルを選択してください", + "noConflicts": "コンフリクトファイルなし", + "skipFile": "スキップ", + "abortSuccess": "操作が中止されました", + "applyAllNonConflicting": "競合しない変更をすべて適用", + "applyLeftNonConflicting": "ローカルを適用", + "applyRightNonConflicting": "リモートを適用" + }, + "ImportSessions": { + "title": "ローカルセッションをインポート", + "scanningTitle": "ローカルエージェントのセッションをスキャン中…", + "scanningHint": "各エージェントのローカルセッションストアを走査しています。履歴が多い場合は時間がかかることがあります。インポート済みのセッションはあわせて更新されます。", + "scanFailed": "スキャンに失敗しました", + "retry": "再試行", + "rescan": "再スキャン", + "empty": "ローカルセッションが見つかりません", + "emptyHint": "このマシンにはエージェントのセッションストアが見つかりませんでした。", + "noMatches": "現在のフィルターに一致するセッションはありません", + "searchPlaceholder": "タイトルまたはパスを検索…", + "allAgents": "すべてのエージェント", + "onlyImportable": "インポート可能のみ", + "selectAll": "すべて選択", + "clearSelection": "クリア", + "expandAll": "すべて展開", + "collapseAll": "すべて折りたたむ", + "summaryCounts": "{total} セッション · インポート可能 {importable} · {folders} フォルダー", + "noFolderSkipped": "プロジェクトフォルダーのない {count} 件をスキップしました", + "folderNew": "新規", + "folderCounts": "インポート可能 {importable}/{total}", + "toggleFolderAria": "{name} のインポート可能なセッションをすべて選択", + "toggleSessionAria": "セッション {title} を選択", + "statusImported": "インポート済み", + "statusDeleted": "削除済み", + "untitled": "無題のセッション", + "messageCount": "{count} 件のメッセージ", + "selectedCount": "{count} 件選択中", + "importSelected": "選択項目をインポート", + "importing": "インポート中…", + "close": "閉じる", + "doneTitle": "インポート完了", + "doneImported": "インポート", + "doneUpdated": "更新済み", + "doneSkipped": "スキップ", + "doneCreatedFolders": "作成フォルダー", + "doneNotFound": "見つからず", + "doneFailed": "失敗", + "continueImport": "続けてインポート", + "toasts": { + "importFailed": "インポートに失敗しました: {message}" + } + }, + "Folder": { + "workspaceStatus": { + "degradedTitle": "リアルタイム更新は利用できません", + "degradedHint": "ウォッチャーの起動に失敗しました(アクセス権限エラーなど)。最新の変更を反映するには手動で更新してください。", + "retry": "再試行", + "retrying": "再試行中..." + }, + "common": { + "all": "すべて", + "cancel": "キャンセル", + "close": "閉じる", + "closeOthers": "他を閉じる", + "closeAll": "すべて閉じる", + "confirm": "確認", + "save": "保存", + "delete": "削除", + "rename": "名前を変更", + "loading": "読み込み中...", + "refresh": "更新", + "refreshing": "更新中...", + "create": "作成", + "createAndSwitch": "作成して切り替え", + "openFile": "ファイルを開く", + "viewDiff": "差分を見る", + "push": "プッシュ..." + }, + "statusLabels": { + "in_progress": "進行中", + "pending_review": "レビュー", + "completed": "完了", + "cancelled": "キャンセル済み" + }, + "sidebar": { + "title": "会話", + "locateActiveConversation": "アクティブな会話を表示", + "expandAllGroups": "すべてのグループを展開", + "collapseAllGroups": "すべてのグループを折りたたむ", + "newConversation": "新しい会話", + "newConversationShort": "新規", + "newChat": "新しい会話", + "search": "検索", + "noConversationsFound": "会話が見つかりません。", + "importLocalSessions": "ローカルセッションをインポート", + "importing": "インポート中...", + "error": "エラー: {message}", + "completeAllSessions": "すべてのセッションを完了", + "completeAllReviewTitle": "すべてのレビューセッションを完了しますか?", + "completeAllReviewDescription": "これにより、レビュー中の {count, plural, one {# 件のセッション} other {# 件のセッション}} が完了としてマークされます。", + "completing": "完了処理中...", + "toasts": { + "importedSessions": "{imported, plural, one {# 件のセッション} other {# 件のセッション}} をインポートし、{skipped} 件をスキップしました", + "importedAndUpdated": "{imported, plural, one {# 件のセッション} other {# 件のセッション}} をインポートし、{updated, plural, one {# 件のタイトル} other {# 件のタイトル}} を更新し、{skipped} 件をスキップしました", + "updatedTitles": "{updated, plural, one {# 件のタイトル} other {# 件のタイトル}} を更新し、{skipped} 件をスキップしました", + "noNewSessionsFound": "新しいセッションは見つかりませんでした({skipped} 件をスキップ)", + "importFailed": "インポートに失敗しました: {message}", + "reviewCompleted": "{count, plural, one {# 件のレビューセッション} other {# 件のレビューセッション}} を完了にしました", + "completeReviewFailed": "レビューセッションの完了処理に失敗しました: {message}", + "folderOpened": "フォルダ {name} を開きました", + "folderRemoved": "フォルダ {name} を削除しました", + "openFolderFailed": "フォルダを開けませんでした", + "removeFolderFailed": "フォルダの削除に失敗しました: {message}", + "reorderFoldersFailed": "フォルダの並べ替えに失敗しました: {message}", + "changeFolderColorFailed": "色の変更に失敗しました: {message}", + "setFolderAliasFailed": "エイリアスの設定に失敗しました: {message}", + "changeFolderDefaultAgentFailed": "デフォルトエージェントの設定に失敗しました: {message}" + }, + "statsLabel": "{folders} フォルダ · {convos} 会話", + "reorderHandle": "ドラッグして並べ替え", + "openFolder": "フォルダを開く", + "searchPlaceholder": "会話を検索...", + "viewOptions": "表示オプション", + "showCompleted": "完了した会話を表示", + "showWorktrees": "ワークツリーフォルダを表示", + "showRecent": "「最近」グループを表示", + "moreOptions": "その他のオプション", + "sortBy": "並び替え", + "sortByCreatedAt": "作成時刻順", + "sortByUpdatedAt": "更新時刻順", + "sectionOrder": "セクションの順序", + "sectionOrderMoveUp": "上へ移動", + "sectionOrderMoveDown": "下へ移動", + "sectionOrderItemLabel": "{name} — {total} 件中 {position} 番目", + "statusRunningBadge": "実行中", + "runningCountBadge": "{count} 件の会話が実行中", + "statusCancelledBadge": "キャンセル済み", + "worktreeRemovedBadge": "元の worktree は削除済み", + "conversationCountUnit": "{count} 件", + "emptyFolderHint": "会話がありません", + "noMatchingConversations": "一致する会話がありません", + "noUnfinishedConversations": "未完了の会話はありません。右上のメニューから「完了した会話を表示」を有効にできます。", + "removeFolderConfirmTitle": "このフォルダをワークスペースから削除しますか?", + "removeFolderConfirmDescription": "\"{name}\" をワークスペースから削除しますか?関連するタブとターミナルが閉じられます。", + "folderHeaderMenu": { + "manageConversations": "会話の管理…", + "manageLinks": "リンク済みフォルダー", + "changeColor": "色を変更", + "useThemeColor": "アプリのテーマを使用", + "setDefaultAgent": "デフォルトエージェントを設定", + "defaultAgentNone": "設定なし(グローバルを使用)", + "agentUnavailableSuffix": "(利用不可)", + "loadingAgents": "エージェントを読み込み中…", + "setAlias": "エイリアスを設定…", + "setAliasTitle": "フォルダーのエイリアスを設定", + "setAliasPlaceholder": "エイリアスを入力(空欄でクリア)", + "setAliasSave": "保存", + "setAliasCancel": "キャンセル", + "removeFromWorkspace": "ワークスペースから削除" + }, + "manageConversations": { + "title": "会話の管理", + "searchPlaceholder": "タイトルで検索…", + "agentFilterAll": "すべてのエージェント", + "statusFilterAll": "すべてのステータス", + "folderFilterAll": "すべてのフォルダ", + "branchFilterAll": "すべてのブランチ", + "branchNone": "ブランチなし", + "branchSearchPlaceholder": "ブランチを検索…", + "noMatchingBranches": "一致するブランチがありません", + "selectAllVisible": "すべて選択", + "deselectAll": "選択を解除", + "selectedCount": "{count} 件選択中", + "matchedCount": "{count} 件該当", + "untitledConversation": "無題の会話", + "setStatus": "ステータスを変更…", + "deleteSelected": "削除", + "noConversations": "このフォルダには会話がありません。", + "noConversationsWorkspace": "ワークスペースに会話がありません。", + "noMatchingConversations": "条件に一致する会話がありません。", + "confirmDeleteTitle": "{count} 件の会話を削除しますか?", + "confirmDeleteDescription": "この操作は元に戻せません。", + "toastDeleted": "{count} 件の会話を削除しました", + "toastStatusUpdated": "{count} 件の会話のステータスを更新しました", + "toastOpFailed": "操作に失敗しました: {message}" + }, + "sectionPinned": "ピン留め", + "sectionFolders": "フォルダ", + "sectionChats": "チャット", + "sectionRecent": "最近", + "noChats": "チャットがありません", + "noRecent": "最近の会話はありません", + "showMoreRecent": "さらに表示({count})", + "noFolders": "開いているフォルダがありません", + "newChatAction": "新しいチャット", + "automations": "オートメーション", + "tasks": "ToDo タスク", + "loadingSubsessions": "サブ会話を読み込み中…" + }, + "conversation": { + "reloadFailed": "会話の再読み込みに失敗しました: {message}", + "reloaded": "会話を再読み込みしました", + "reload": "再読み込み", + "activeConversationIndicator": "アクティブな会話", + "newConversation": "新しい会話", + "closeConversation": "会話を閉じる", + "copyText": "テキストをコピー", + "copyTextSuccess": "コピーしました", + "copyTextFailed": "コピーに失敗しました", + "forkSession": "セッションをフォーク", + "forkSessionSuccess": "セッションのフォークに成功しました", + "forkSessionFailed": "セッションのフォークに失敗しました:{error}", + "exportConversation": "会話をエクスポート", + "exportImage": "画像", + "exportMarkdown": "Markdown", + "exportHtml": "HTML", + "exportSuccess": "会話をエクスポートしました", + "exportFailed": "エクスポートに失敗しました", + "exportImageTooLong": "会話が長すぎるため、画像としてエクスポートできません", + "exportLabels": { + "untitledConversation": "無題の会話", + "agent": "エージェント", + "model": "モデル", + "status": "ステータス", + "started": "開始", + "updated": "更新", + "tokens": "トークン統計", + "duration": "所要時間", + "inputTokens": "入力", + "outputTokens": "出力", + "cacheRead": "キャッシュ読取", + "cacheWrite": "キャッシュ書込", + "user": "ユーザー", + "assistant": "アシスタント", + "system": "システム", + "toolResult": "結果", + "toolError": "エラー" + }, + "moreActions": "その他の操作" + }, + "sessionDetails": { + "menuLabel": "セッション詳細", + "noActiveSession": "アクティブなセッションがありません", + "title": "セッション詳細", + "subtitle": "セッションのメタデータとトークン使用量", + "fieldTitle": "タイトル", + "untitled": "無題の会話", + "sessionId": "セッション ID", + "externalId": "拡張 ID", + "agent": "エージェント", + "model": "モデル", + "status": "ステータス", + "gitBranch": "Git ブランチ", + "parentId": "親セッション", + "tokensHeading": "トークン使用量", + "totalTokens": "合計", + "inputTokens": "入力", + "outputTokens": "出力", + "cacheWrite": "キャッシュ書込", + "cacheRead": "キャッシュ読取", + "contextWindow": "コンテキストウィンドウ", + "duration": "所要時間", + "loadingStats": "トークン使用量を読み込み中…", + "loadFailed": "トークン使用量の読み込みに失敗しました", + "noStats": "使用量の記録なし", + "timestampsHeading": "日時", + "createdAt": "作成日時", + "updatedAt": "更新日時", + "none": "—", + "copyField": "{field}をコピー", + "copiedField": "{field}をコピーしました" + }, + "conversationCard": { + "untitledConversation": "無題の会話", + "newConversation": "新しい会話", + "rename": "名前を変更", + "status": "ステータス", + "delete": "削除", + "importLocalSessions": "ローカルセッションをインポート", + "importing": "インポート中...", + "renameConversation": "会話名を変更", + "deleteConversationTitle": "会話を削除しますか?", + "deleteConversationDescription": "\"{title}\" を削除します。この操作は元に戻せません。", + "cancel": "キャンセル", + "save": "保存", + "pin": "ピン留め", + "unpin": "ピン留めを解除", + "markCompleted": "完了にする", + "reopen": "再開する", + "expandSubsessions": "サブ会話を展開", + "collapseSubsessions": "サブ会話を折りたたむ" + }, + "search": { + "dialogTitle": "検索", + "dialogTitleWithFolder": "検索 — {name}", + "tabConversations": "会話", + "tabFiles": "ファイル", + "placeholder": "会話を検索...", + "filePlaceholder": "ファイルまたはディレクトリを検索...", + "allAgents": "すべて", + "searching": "検索中...", + "typeToSearch": "入力して会話を検索", + "typeToSearchFiles": "入力してファイルまたはディレクトリを検索", + "noResults": "結果が見つかりません。", + "untitledConversation": "無題の会話" + }, + "folderTitleBar": { + "showSidebar": "サイドバーを表示", + "hideSidebar": "サイドバーを非表示", + "toggleTerminal": "ターミナルを切り替え", + "toggleAuxPanel": "補助パネルを切り替え", + "search": "検索", + "openSettings": "設定を開く", + "backToConversations": "会話に戻る", + "withShortcut": "{label}({shortcut})" + }, + "statusBar": { + "connection": { + "connected": "接続済み", + "connecting": "接続中...", + "prompting": "応答中...", + "error": "接続エラー", + "disconnected": "未接続", + "tooltip": "{agent}:{status}", + "tooltipError": "{agent}:{error}", + "title": "エージェント接続", + "triggerAria": "エージェント接続: {status}", + "workingDir": "作業ディレクトリ", + "sessionId": "セッション ID", + "viewerNote": "他のクライアントが所有するセッションに接続しています。再接続してもこのビューが接続し直されるだけです。", + "reconnectInterrupts": "再接続するとエージェントが再起動し、進行中の処理が中断されます。", + "reconnect": "再接続", + "reconnecting": "再接続中...", + "reconnectUnavailable": "再接続できるセッションがまだありません。" + }, + "tasks": { + "title": "タスク" + }, + "alerts": { + "title": "アラート", + "empty": "アラートなし", + "details": "詳細" + }, + "stats": { + "conversations": "{count} 件の会話", + "openUsage": "セッション統計とトークン使用量を表示" + }, + "tokens": { + "contextWindowUsageAria": "コンテキストウィンドウ使用率", + "contextWindow": "コンテキストウィンドウ", + "usedMax": "使用 / 最大", + "tokenUsage": "トークン使用量", + "input": "入力", + "output": "出力", + "cacheRead": "キャッシュ読み取り", + "cacheWrite": "キャッシュ書き込み", + "total": "合計" + } + }, + "auxPanel": { + "tabs": { + "files": "ファイル", + "changes": "変更", + "commits": "コミット" + }, + "noFolderTitle": "開いているフォルダがありません", + "noFolderHint": "フォルダを開くとここに表示されます" + }, + "windowControls": { + "minimizeWindow": "ウィンドウを最小化", + "minimize": "最小化", + "maximizeWindow": "ウィンドウを最大化", + "maximize": "最大化", + "restoreWindow": "ウィンドウを元に戻す", + "restore": "元に戻す", + "closeWindow": "ウィンドウを閉じる", + "close": "閉じる" + }, + "tabs": { + "closeConversationTab": "会話タブを閉じる", + "close": "閉じる", + "closeOthers": "他を閉じる", + "splitRight": "右に分割", + "splitDown": "下に分割", + "splitAndMoveRight": "分割して右へ移動", + "splitAndMoveDown": "分割して下へ移動", + "moveToOppositeGroup": "反対側のグループへ移動", + "moveToGroup": "グループへ移動", + "groupLabel": "グループ {index}", + "changeSplitterOrientation": "分割方向を切り替え", + "unsplit": "分割を解除", + "unsplitAll": "すべての分割を解除", + "closeAll": "すべて閉じる", + "tileDisplay": "タイル表示", + "untileDisplay": "タイル解除" + }, + "fileWorkspace": { + "files": "ファイル", + "closeFileTab": "ファイルタブを閉じる", + "close": "閉じる", + "closeOthers": "他を閉じる", + "closeAll": "すべて閉じる", + "preview": "プレビュー", + "editSource": "ソースを編集", + "maximize": "最大化", + "restore": "元に戻す", + "emptyDirectory": "空のフォルダー" + }, + "terminal": { + "rename": "名前を変更", + "close": "閉じる", + "closeOthers": "他を閉じる", + "closeAll": "すべて閉じる", + "hideTerminal": "ターミナルを隠す ({shortcut})", + "openFolderFirst": "先にフォルダを開いてください" + }, + "workspaceDialog": { + "title": "フォルダーを開く", + "manageTitle": "リンク済みフォルダー", + "addTargetsTitle": "リンクするフォルダーを追加", + "pickRootDescription": "このワークスペースのメインフォルダーを選択します。", + "linksDescription": "他のフォルダーをサブディレクトリとしてリンクすると、エージェントは 1 つのワークスペースから横断的に作業できます。", + "addTargetsDescription": "フォルダーを 1 つ以上選択してください。それぞれがワークスペースのサブディレクトリになります。", + "useSystemPicker": "システムの選択画面", + "next": "次へ", + "back": "戻る", + "done": "完了", + "change": "変更", + "addFolders": "フォルダーを追加", + "addSelected": "追加", + "addSelectedCount": "{count} 件を追加", + "createCount": "{count} 件のフォルダーをリンク", + "discardPending": "破棄", + "noLinks": "リンクされたフォルダーはまだありません。", + "gitExclude": "リンクを git status に出さない", + "rename": "名前を変更", + "unlink": "リンクを解除", + "repair": "リンクを作り直す", + "saveName": "保存", + "cancelRename": "キャンセル", + "removePending": "削除", + "willAppearAs": "ワークスペースでは {name} として表示されます", + "renamedForDuplicate": "改名しました — {base} は別のリンクが使用中です", + "renamedForExistingEntry": "改名しました — このフォルダーには既に {base} があります", + "partiallyCreated": "{count} 件のフォルダーのみリンクできました", + "openFailed": "フォルダーを開けませんでした", + "previewFailed": "選択したフォルダーを確認できませんでした", + "createFailed": "フォルダーをリンクできませんでした", + "renameFailed": "名前を変更できませんでした", + "removeFailed": "リンクを解除できませんでした", + "repairFailed": "リンクを作り直せませんでした", + "status": { + "ok": "リンク済み", + "missing": "リンクがこのフォルダーから消えています", + "conflicted": "この名前は別の項目が使用しています", + "broken": "リンク先のフォルダーが存在しません" + }, + "nameIssue": { + "empty": "名前を入力してください", + "illegalChars": "/ \\ : * ? \" < > | は使用できません", + "tooLong": "名前が長すぎます", + "reserved": "この名前は Windows の予約語です", + "duplicate": "この名前は既に使われています" + }, + "rejection": { + "not_found": "このフォルダーが見つかりません", + "not_a_directory": "このパスはフォルダーではありません", + "same_as_root": "ワークスペースのフォルダー自身です", + "ancestor_of_root": "このフォルダーはワークスペースを含んでいます", + "inside_root": "既にワークスペース内にあります", + "already_linked": "既にリンク済みです", + "name_unavailable": "このフォルダーに使える名前が残っていません", + "alreadyLinkedAs": "{name} として既にリンク済みです" + } + }, + "folderNameDropdown": { + "fallbackFolderName": "フォルダ", + "openFolder": "フォルダを開く", + "cloneRepository": "リポジトリをクローン", + "projectBoot": "プロジェクトブート", + "opened": "開いているフォルダ", + "recentOpen": "最近開いたフォルダ" + }, + "fileWorkspacePanel": { + "addSelectionToChat": "選択範囲をチャットに追加", + "addToChat": "チャットに追加", + "addSelectionToChatDone": "{label} を会話に追加しました", + "addFileToChat": "ファイルをチャットに追加", + "toggleWordWrap": "折り返しの切り替え", + "addFileToChatDone": "{label} を会話に追加しました", + "viewDiff": "差分を見る", + "openFile": "ファイルを開く", + "fileCount": "{count, plural, one {# 個のファイル} other {# 個のファイル}}", + "openFileOrDiff": "右側パネルからファイルまたは差分を開いてください", + "disk": "ディスク", + "head": "HEAD", + "unsaved": "未保存", + "workingTree": "作業ツリー", + "loading": "読み込み中...", + "compareWithBranch": "{path} · {branch} と比較", + "hunkCount": "{count, plural, one {# 個のハンク} other {# 個のハンク}}", + "prev": "前", + "next": "次", + "jumpToLine": "{line} 行へ移動", + "noParsedDiffSections": "解析済みの差分セクションがありません", + "loadingEditor": "エディターを読み込み中...", + "imageZoomIn": "拡大", + "imageZoomOut": "縮小", + "imageZoomReset": "ズームをリセット", + "htmlPreviewTitle": "HTML プレビュー", + "htmlPreviewTrust": "スクリプトを有効化", + "htmlPreviewTrustHint": "このファイルのスクリプトを実行し、ネットワークアクセスを許可します。信頼できるファイルでのみ有効にしてください。", + "officePreviewTitle": "Office ドキュメントのプレビュー", + "officeFullRender": "フル描画", + "officeFullRenderHint": "Morph アニメーション・3D・数式を描画します(スライド自身のスクリプトを実行)", + "officeNotInstalled": "OfficeCLI がインストールされていません", + "officeNotInstalledHint": "設定 → Office ツール から OfficeCLI をインストールすると、Word・Excel・PowerPoint ファイルをプレビューできます。", + "officeOpenSettings": "設定を開く", + "officeWatchFailed": "ライブプレビューを開始できませんでした", + "officeWatchRetry": "再試行", + "officeServerInstallHint": "OfficeCLI はサーバーホストにインストールする必要があります。サーバーで次のコマンドを実行してから再試行してください:", + "officeRemoteDesktopUnsupported": "リモートデスクトップウィンドウではライブプレビューを利用できません。Office ファイルをプレビューするには、サーバーの Web UI でこのワークスペースを開いてください。" + }, + "branchDropdown": { + "toasts": { + "commitCodeCompleted": "コードコミットが完了しました", + "pushCodeCompleted": "コードプッシュが完了しました", + "committedFiles": "{count, plural, one {# 個のファイルをコミット} other {# 個のファイルをコミット}}", + "taskCompleted": "{label} が完了しました", + "taskFailed": "{label} が失敗しました", + "mergeNoNewCommits": "{branchName} に新しいコミットはありません", + "mergedCommits": "{count, plural, one {# 件のコミットをマージ} other {# 件のコミットをマージ}}", + "allFilesUpToDate": "すべてのファイルは最新です", + "updatedFiles": "{count, plural, one {# 個のファイルを更新} other {# 個のファイルを更新}}", + "openCommitWindowFailed": "コミットウィンドウを開けませんでした", + "openPushWindowFailed": "プッシュウィンドウを開けませんでした", + "upstreamSet": "アップストリームブランチを設定しました", + "upstreamSetAndPushed": "アップストリームブランチを設定し、{count, plural, one {# 件のコミット} other {# 件のコミット}}をプッシュしました", + "noCommitsToPush": "プッシュするコミットはありません", + "pushedCommits": "{count, plural, one {# 件のコミットをプッシュ} other {# 件のコミットをプッシュ}}", + "switchedToFolder": "{name} に切り替えました", + "switchFailed": "ブランチの切り替えに失敗しました", + "openStashWindowFailed": "stash ウィンドウを開けませんでした" + }, + "tasks": { + "newBranch": "ブランチ {name} を作成", + "newWorktree": "ワークツリー {name} を作成", + "checkoutTo": "{branchName} にチェックアウト", + "mergeBranch": "{branchName} をマージ", + "rebaseTo": "{branchName} にリベース", + "deleteRemoteBranch": "リモートブランチ {branchName} を削除", + "initGitRepo": "Git リポジトリを初期化", + "pullCode": "コードをプル", + "fetchInfo": "情報をフェッチ", + "pushCode": "コードをプッシュ", + "stashChanges": "変更を stash", + "stashPop": "stash を pop", + "deleteBranch": "ブランチ {branchName} を削除", + "removeWorktree": "{branchName} のワークツリーを削除", + "removeWorktreeAndBranch": "ワークツリーとブランチ {branchName} を削除", + "updateBranch": "ブランチ {branchName} を更新" + }, + "confirm": { + "mergeTitle": "ブランチをマージ", + "rebaseTitle": "ブランチをリベース", + "mergeDescription": "{branchName} を現在のブランチ {currentBranch} にマージしますか?", + "rebaseDescription": "現在のブランチ {currentBranch} を {branchName} にリベースしますか?", + "deleteRemoteTitle": "リモートブランチの削除", + "deleteRemoteDescription": "リモートブランチ {branchName} を削除しますか?この操作はリモートリポジトリからブランチを削除し、元に戻せません。", + "deleteTitle": "ブランチを削除", + "deleteDescription": "ブランチ {branchName} を削除しますか?この操作は元に戻せません。", + "forceDeleteTitle": "ブランチを強制削除", + "forceDeleteDescription": "ブランチ {branchName} はまだ完全にマージされていません。強制削除してもよろしいですか?この操作は元に戻せません。", + "deleteWorktreeTitle": "ワークツリーを削除", + "deleteWorktreeDescription": "{branchName} をチェックアウトしているワークツリーのディレクトリを削除しますか?ブランチとそのコミットは残ります。", + "forceDeleteWorktreeTitle": "ワークツリーを強制削除", + "forceDeleteWorktreeDescription": "{branchName} のワークツリーに未コミットまたは未追跡のファイルがあります。それでも削除しますか?その変更は復元できません。", + "deleteWorktreeAndBranchTitle": "ワークツリーとブランチを削除", + "deleteWorktreeAndBranchDescription": "{branchName} のワークツリー、ブランチ自体、そのワークスペースフォルダーを削除しますか?中のセッションはリポジトリのフォルダーに移動します。この操作は取り消せません。", + "forceDeleteWorktreeAndBranchTitle": "ワークツリーとブランチを強制削除", + "forceDeleteWorktreeAndBranchDescription": "{branchName} のワークツリーに未コミットのファイルがあるか、ブランチが完全にマージされていません。それでも両方を削除しますか?この操作は取り消せません。" + }, + "current": "現在", + "switchToBranch": "このブランチに切り替え", + "mergeBranchIntoCurrent": "{branchName} を {currentBranch} にマージ", + "rebaseCurrentToBranch": "{currentBranch} を {branchName} にリベース", + "noBranch": "ブランチなし", + "detachedHead": "切り離された HEAD({sha})", + "initGitRepo": "Git リポジトリを初期化", + "pullCode": "コードをプル", + "fetchRemoteBranches": "リモートブランチをフェッチ", + "openCommitWindow": "コードをコミット...", + "pushCode": "プッシュ...", + "pushBranch": "プッシュ", + "newBranch": "新規ブランチ...", + "newWorktree": "新規ワークツリー...", + "stashChanges": "スタッシュ...", + "stashPop": "stash を pop...", + "manageRemotes": "リモート管理...", + "localBranches": "ローカルブランチ ({count, plural, one {#} other {#}})", + "noLocalBranches": "ローカルブランチはありません", + "remoteBranches": "リモートブランチ ({count, plural, one {#} other {#}})", + "noRemoteBranches": "リモートブランチはありません", + "dialogs": { + "newBranchTitle": "新規ブランチ", + "newBranchDescription": "現在のブランチ {branch} から新しいブランチを作成", + "branchNamePlaceholder": "ブランチ名", + "newWorktreeTitle": "新規ワークツリー", + "newWorktreeDescription": "現在のブランチ {branch} から新しいワークツリーを作成", + "branchNameLabel": "ブランチ名", + "worktreePathLabel": "ワークツリーのパス", + "worktreePathPlaceholder": "ワークツリーのパス", + "manageRemotesTitle": "リモート管理", + "manageRemotesEmpty": "リモートが設定されていません", + "remoteNamePlaceholder": "リモート名", + "remoteUrlPlaceholder": "リモート URL", + "addRemote": "追加", + "savingRemotes": "保存中..." + }, + "conflict": { + "title": "マージコンフリクト", + "description": "以下のファイルにコンフリクトがあります。解決が必要です:", + "abort": "マージを中止", + "openMergeTool": "マージツールを開く", + "completeMerge": "マージ完了", + "abortSuccess": "マージが中止されました", + "completeSuccess": "マージが完了しました" + }, + "stashDialog": { + "title": "変更をスタッシュ", + "description": "現在の変更をスタッシュに保存", + "messageLabel": "メッセージ", + "messagePlaceholder": "スタッシュメッセージ(任意)", + "keepIndex": "インデックスを保持(ステージ済みの変更はそのまま)", + "cancel": "キャンセル", + "stash": "スタッシュ", + "success": "変更がスタッシュされました", + "error": "スタッシュに失敗しました" + }, + "unstashDialog": { + "title": "スタッシュを適用", + "noStashes": "スタッシュがありません", + "selectFile": "ファイルを選択して差分を表示", + "viewDiff": "差分を表示", + "original": "元", + "modified": "変更後", + "apply": "適用", + "drop": "削除", + "applySuccess": "スタッシュを適用しました", + "dropSuccess": "スタッシュを削除しました", + "confirmApply": "スタッシュ {ref} を作業ディレクトリに適用しますか?", + "cancel": "キャンセル" + }, + "deleteBranch": "ブランチを削除", + "deleteWorktree": "ワークツリーを削除", + "deleteWorktreeAndBranch": "ワークツリーとブランチを削除", + "searchPlaceholder": "ブランチと操作を検索", + "searchAriaLabel": "ブランチと操作を検索", + "branchListLabel": "ブランチと操作", + "noMatches": "一致する項目がありません" + }, + "commitDialog": { + "toasts": { + "commitCompleted": "コードコミットが完了しました", + "pushFailed": "プッシュに失敗しました", + "committedFiles": "{count, plural, one {# 個のファイルをコミット} other {# 個のファイルをコミット}}", + "addedToVcs": "VCS に追加しました", + "addToVcsFailed": "VCS への追加に失敗しました", + "fileDeleted": "ファイルを削除しました", + "deleteFailed": "削除に失敗しました", + "fileRolledBack": "ファイルをロールバックしました", + "rollbackFailed": "ロールバックに失敗しました", + "dirRolledBack": "ディレクトリをロールバックしました", + "dirDeleted": "ディレクトリを削除しました" + }, + "confirm": { + "deleteTitle": "削除の確認", + "deleteDescription": "ファイル \"{file}\" を削除しますか?この操作は元に戻せません。", + "rollbackTitle": "ロールバックの確認", + "rollbackDescription": "ファイル \"{file}\" を HEAD にロールバックしますか?未保存の変更は失われます。", + "rollbackDirDescription": "ディレクトリ「{dir}」をHEADにロールバックしますか?未保存の変更は失われます。", + "deleteDirDescription": "ディレクトリ「{dir}」を削除しますか?この操作は元に戻せません。" + }, + "actions": { + "select": "選択", + "unselect": "選択解除", + "rollback": "ロールバック", + "addToVcs": "VCS に追加" + }, + "aria": { + "selectFile": "{action}: {path}", + "unselectAllFiles": "すべてのファイルの選択を解除", + "selectAllFiles": "すべてのファイルを選択", + "unselectTracked": "追跡中の変更の選択を解除", + "selectTracked": "追跡中の変更を選択", + "unselectUntracked": "未追跡ファイルの選択を解除", + "selectUntracked": "未追跡ファイルを選択" + }, + "loading": "読み込み中...", + "selectionCount": "{selected} / {total} ファイル", + "emptyFiles": "変更されたファイルはありません", + "trackedChanges": "追跡中の変更 ({count})", + "untrackedFiles": "未追跡ファイル ({count})", + "commitMessage": "コミットメッセージ", + "commitMessagePlaceholder": "コミットメッセージを入力...", + "commitButton": "コミット ({count})", + "commitAndPushButton": "コミットしてプッシュ ({count})", + "head": "HEAD", + "workingTree": "作業ツリー", + "clickFileToDiff": "ファイル名をクリックして差分を表示", + "loadingDiff": "差分を読み込み中..." + }, + "pushWindow": { + "title": "コードをプッシュ", + "noUnpushedCommits": "未プッシュのコミットはありません", + "noRemoteConfigured": "Git リモートが設定されていません\n「リモート管理」からリモートを追加してください", + "newBranchNoPushedCommits": "新しいブランチ — プッシュしてリモート追跡ブランチを作成", + "unpushed": "未プッシュ", + "selectFileToViewDiff": "ファイルを選択して差分を表示", + "before": "変更前", + "after": "変更後", + "push": "プッシュ", + "toasts": { + "pushSuccess": "プッシュ成功", + "pushFailed": "プッシュ失敗", + "upstreamSet": "リモート追跡ブランチが設定されました", + "upstreamSetAndPushed": "リモート追跡ブランチを設定し、{count}件のコミットをプッシュしました", + "noCommitsToPush": "プッシュするコミットはありません", + "pushedCommits": "{count}件のコミットをプッシュしました" + } + }, + "gitLogTab": { + "filesTitle": "ファイル", + "expandAllFiles": "すべてのファイルを展開", + "collapseAllFiles": "すべてのファイルを折りたたむ", + "workspace": "ワークスペース", + "retry": "再試行", + "noCommitsFound": "コミットが見つかりません", + "notAGitRepoTitle": "Git リポジトリではありません", + "notAGitRepoHint": "上のブランチメニューから Git を初期化するか、既存のリポジトリを開いてください。", + "hash": "ハッシュ", + "copyHash": "ハッシュをコピー", + "copyMessage": "メッセージをコピー", + "showMore": "もっと見る", + "showLess": "折りたたむ", + "author": "作成者", + "noFileChangeDetails": "ファイル変更の詳細はありません。", + "loadingFiles": "ファイルを読み込み中…", + "branchesTitle": "ブランチ", + "loadingBranches": "ブランチを読み込み中...", + "noContainingBranches": "含まれるブランチが見つかりません。", + "newBranch": "新規ブランチ...", + "resetToHere": "ここにリセット", + "resetDisabledReasonNotCurrentBranchView": "現在のブランチ表示時のみ利用できます", + "copyFullCommitHashAria": "完全なコミットハッシュ {hash} をコピー", + "pushStatus": { + "pushed": "リモートにプッシュ済み", + "notPushed": "リモートに未プッシュ", + "unknown": "プッシュ状態不明(upstream 未設定)" + }, + "time": { + "monthsAgo": "{count, plural, one {# か月前} other {# か月前}}", + "daysAgo": "{count, plural, one {# 日前} other {# 日前}}", + "hoursAgo": "{count, plural, one {# 時間前} other {# 時間前}}", + "minsAgo": "{count, plural, one {# 分前} other {# 分前}}", + "justNow": "たった今" + }, + "toasts": { + "createdAndSwitchedNewBranch": "新しいブランチを作成して切り替えました", + "newBranchFromCommit": "{name}({shortHash} から)", + "createBranchFailed": "ブランチ作成に失敗しました", + "openPushWindowFailed": "プッシュウィンドウを開けませんでした", + "resetSuccess": "リセットが完了しました", + "resetSuccessDescription": "{branch} を {mode} で {shortHash} にリセットしました", + "resetFailed": "リセットに失敗しました" + }, + "authorFilter": { + "label": "作成者", + "searchPlaceholder": "作成者を検索", + "noAuthors": "作成者が見つかりません", + "you": "あなた", + "filterByAuthorAria": "作成者でコミットを絞り込む", + "filterByQuery": "「{query}」で絞り込む", + "clearAuthorFilterAria": "作成者フィルターをクリア", + "recent": "最近", + "matchingAuthors": "一致する作成者", + "removeFromRecent": "{name} を最近から削除" + }, + "branchSelector": { + "label": "ブランチ", + "head": "HEAD", + "headHint": "現在のブランチに追従", + "headHintWithBranch": "現在のブランチに追従({branch})", + "searchBranch": "ブランチを検索...", + "noBranches": "ブランチがありません", + "selectBranchPlaceholder": "ブランチを選択...", + "localBranches": "ローカルブランチ", + "current": "現在", + "remoteBranches": "リモートブランチ", + "refreshCommitHistory": "コミット履歴を更新", + "clearBranchFilterAria": "ブランチフィルターをクリア" + }, + "dialogs": { + "newBranchTitle": "新規ブランチ", + "newBranchDescription": "コミット {shortHash} を最新コミットとして新しいブランチを作成します。", + "branchNamePlaceholder": "ブランチ名", + "reset": { + "title": "現在のブランチをこのコミットへリセット", + "branchLabel": "ブランチ", + "targetLabel": "対象コミット", + "messageLabel": "コミットメッセージ", + "modeLabel": "リセットモード", + "confirmButton": "リセット", + "modes": { + "soft": { + "label": "--soft", + "description": "HEAD と現在のブランチ参照を対象コミットへ移動します。\nIndex と Working Tree は変更しません。\n取り消されたコミットの変更は staged のまま残ります。" + }, + "mixed": { + "label": "--mixed(デフォルト)", + "description": "HEAD を対象コミットへ移動します。\nIndex を対象コミットに戻し、Working Tree の変更は維持します。\n変更は staged から unstaged に戻ります。" + }, + "hard": { + "label": "--hard", + "description": "HEAD を移動し、Index と Working Tree を対象コミットに戻します。\n対象コミット以降の追跡中ローカル変更は破棄されます。\n破壊的な操作です。" + }, + "keep": { + "label": "--keep", + "description": "HEAD を対象コミットへ移動し、可能な限りローカル変更を保持します。\n競合しない変更のみ保持されます。\n競合がある場合は保護のため処理を中止します。" + } + } + } + }, + "moreActions": "その他の Git 操作" + }, + "gitChangesTab": { + "workspace": "ワークスペース", + "noChanges": "ローカルの変更はありません", + "notAGitRepoTitle": "Git リポジトリではありません", + "notAGitRepoHint": "上のブランチメニューから Git を初期化するか、既存のリポジトリを開いてください。", + "trackedChanges": "追跡中の変更 ({count})", + "untrackedFiles": "未追跡ファイル ({count})", + "expandTracked": "追跡中の変更を展開", + "collapseTracked": "追跡中の変更を折りたたむ", + "expandUntracked": "未追跡ファイルを展開", + "collapseUntracked": "未追跡ファイルを折りたたむ", + "showRemainingItems": "残り {count} 件を表示", + "actions": { + "commitCode": "コードをコミット", + "rollback": "ロールバック", + "addToVcs": "VCS に追加", + "delete": "削除", + "moreActions": "その他の Git 操作", + "addAllToVcs": "すべて VCS に追加", + "rollbackAll": "すべてロールバック", + "refresh": "更新" + }, + "toasts": { + "noAddableFilesInDir": "このディレクトリには VCS に追加できる変更ファイルがありません", + "noRollbackFilesInDir": "このディレクトリにはロールバックできる変更ファイルがありません", + "addedToVcs": "{name} を VCS に追加しました", + "addToVcsFailed": "VCS への追加に失敗しました", + "openCommitWindowFailed": "コミットウィンドウを開けませんでした", + "rolledBack": "{name} をロールバックしました", + "rollbackFailed": "ロールバックに失敗しました", + "addedFilesToVcs": "{count, plural, one {# 個のファイルを VCS に追加} other {# 個のファイルを VCS に追加}}", + "rolledBackFiles": "{count, plural, one {# 個のファイルをロールバック} other {# 個のファイルをロールバック}}", + "deleted": "{name} を削除しました", + "deleteFailed": "削除に失敗しました", + "deletedFiles": "{count} 個のファイルを削除しました", + "noDeletableFilesInDir": "このディレクトリには削除可能な変更ファイルがありません", + "commitFailed": "コミットに失敗しました" + }, + "directoryDialog": { + "descriptionAdd": "ディレクトリ {path} 配下で VCS に追加するファイルを選択してください。", + "descriptionRollback": "ディレクトリ {path} 配下でロールバックするファイルを選択してください。", + "descriptionDelete": "ディレクトリ {path} 配下で削除するファイルを選択してください。この操作は元に戻せません。", + "descriptionFallback": "続行するファイルを選択してください。", + "selectionCount": "{selected} / {total} を選択", + "selectAll": "すべて選択", + "unselectAll": "すべて選択解除", + "loadingCandidates": "ディレクトリの変更を読み込み中...", + "noOperableFiles": "操作可能なファイルがありません" + }, + "rollbackConfirm": { + "title": "ロールバックの確認", + "descriptionWithTarget": "{kind} \"{name}\" のローカル変更をロールバックしますか?", + "descriptionFallback": "ローカル変更をロールバックしますか?", + "kindDirectory": "ディレクトリ", + "kindFile": "ファイル" + }, + "deleteConfirm": { + "title": "削除の確認", + "descriptionWithTarget": "{kind}「{name}」を削除しますか?この操作は元に戻せません。", + "descriptionFallback": "この操作は元に戻せません。", + "kindDirectory": "ディレクトリ", + "kindFile": "ファイル" + }, + "quickCommit": { + "placeholder": "コミットメッセージ(Enter でコミット)" + } + }, + "tabContext": { + "loadingConversation": "読み込み中...", + "untitledConversation": "無題の会話", + "newConversation": "新しい会話" + }, + "fileTreeTab": { + "workspace": "ワークスペース", + "retry": "再試行", + "git": "Git", + "openInFileManager": "ファイルマネージャーで開く", + "openInFinder": "Finderで開く", + "openInExplorer": "エクスプローラーで開く", + "attachToCurrentSession": "セッションに追加", + "compareWithBranch": "ブランチと比較...", + "reloadFromDisk": "ディスクから再読み込み", + "new": "新規作成", + "newFile": "ファイル", + "newDirectory": "ディレクトリ", + "openIn": "で開く", + "openInTerminal": "ターミナルで開く", + "linkedFolder": "リンク済みフォルダー", + "copyPath": "パスをコピー", + "upload": "ファイル/フォルダをアップロード", + "download": "ファイルをダウンロード", + "downloadAsZip": "ZIP としてダウンロード", + "actions": { + "select": "選択", + "unselect": "選択解除", + "commitCode": "コードをコミット", + "rollback": "ロールバック", + "addToVcs": "VCSに追加" + }, + "aria": { + "selectPath": "{action}: {path}" + }, + "toasts": { + "openDirectoryFailed": "ディレクトリを開けませんでした", + "openBuiltinTerminalFailed": "内蔵ターミナルを開けませんでした", + "openCommitWindowFailed": "コミットウィンドウを開けませんでした", + "noAddableFilesInDir": "このディレクトリには VCS に追加できる変更ファイルがありません", + "noRollbackFilesInDir": "このディレクトリにはロールバックできる変更ファイルがありません", + "addedToVcs": "{name} を VCS に追加しました", + "addToVcsFailed": "VCS への追加に失敗しました", + "loadBranchesFailed": "ブランチの読み込みに失敗しました", + "renameFailed": "名前の変更に失敗しました", + "moveFailed": "移動に失敗しました", + "deleteFailed": "削除に失敗しました", + "rolledBack": "{name} をロールバックしました", + "rollbackFailed": "ロールバックに失敗しました", + "addedFilesToVcs": "{count, plural, one {# 件のファイルを VCS に追加しました} other {# 件のファイルを VCS に追加しました}}", + "rolledBackFiles": "{count, plural, one {# 件のファイルをロールバックしました} other {# 件のファイルをロールバックしました}}", + "savedAsCopy": "コピーとして保存しました", + "saveCopyFailed": "コピーとして保存できませんでした", + "watchStartFailed": "ファイル監視の開始に失敗しました", + "createFailed": "作成に失敗しました", + "downloadFailed": "{name} のダウンロードに失敗しました", + "downloadSaved": "{name} をダウンロードしました", + "pathCopied": "パスをコピーしました", + "copyPathFailed": "パスのコピーに失敗しました" + }, + "createDialog": { + "newFile": "新規ファイル", + "newDirectory": "新規ディレクトリ", + "description": "新しい{kind}の名前を入力してください。", + "placeholderFile": "file-name.ext", + "placeholderDirectory": "folder-name" + }, + "renameDialog": { + "renameDirectory": "ディレクトリ名を変更", + "renameFile": "ファイル名を変更", + "description": "新しい名前を入力してください(名前のみ、パスは不要)。", + "placeholderDirectory": "新しいフォルダ名", + "placeholderFile": "新しいファイル名.ext" + }, + "uploadDialog": { + "title": "ワークスペースへアップロード", + "description": "必要に応じて上書き先を変更し、ファイルやフォルダを追加してください。", + "workspaceRoot": "ワークスペースのルート", + "targetPathLabel": "アップロード先", + "targetPathHint": "実際の場所:{path}", + "dropHint": "ファイルやフォルダをここにドロップ、または下のボタンから選択", + "dropHintActive": "離してキューに追加", + "selectFiles": "ファイルを選択", + "selectFolder": "フォルダを選択", + "startUpload": "アップロード開始", + "clearQueue": "完了したものをクリア", + "removeItem": "キューから削除", + "retry": "再試行", + "dropZoneAria": "ファイルをここにドロップ、または Enter で参照", + "folderEmpty": "ドロップされたフォルダにファイルが見つかりません", + "summary": "合計:{total} · 成功:{succeeded} · 失敗:{failed}", + "status": { + "pending": "待機中", + "uploading": "アップロード中", + "success": "完了", + "error": "失敗", + "cancelled": "キャンセル済み" + } + }, + "directoryDialog": { + "descriptionAdd": "ディレクトリ {path} 配下で VCS に追加するファイルを選択してください。", + "descriptionRollback": "ディレクトリ {path} 配下でロールバックするファイルを選択してください。", + "descriptionFallback": "続行するファイルを選択してください。", + "selectionCount": "{selected} / {total} ファイルを選択", + "selectAll": "すべて選択", + "unselectAll": "すべて選択解除", + "loadingCandidates": "ディレクトリの変更を読み込み中...", + "noOperableFiles": "操作可能なファイルがありません" + }, + "compareDialog": { + "title": "ブランチと比較", + "descriptionWithTarget": "ブランチを選択し、{kind} {path} と比較します", + "descriptionFallback": "比較するブランチを選択してください。", + "kindDirectory": "ディレクトリ", + "kindFile": "ファイル", + "filterPlaceholder": "ブランチを絞り込み(例: main / origin/main)", + "singleClickHint": "ブランチをクリックすると直接比較します", + "loadingBranches": "ブランチを読み込み中...", + "recentBranches": "最近のブランチ ({count})", + "noCurrentBranch": "現在のブランチがありません", + "localBranches": "ローカルブランチ ({count})", + "remoteBranches": "リモートブランチ ({count})", + "noMatchingBranches": "一致するブランチがありません" + }, + "externalConflictDialog": { + "title": "外部ファイルの変更を検出しました", + "descriptionWithPath": "ファイル {path} がディスク上で変更されました。現在の編集は未保存です。", + "descriptionFallback": "現在のファイルがディスク上で変更されました。現在の編集は未保存です。", + "compare": "比較", + "savingCopy": "コピーを保存中...", + "saveAsCopy": "コピーとして保存", + "reload": "再読み込み" + }, + "deleteConfirm": { + "title": "削除の確認", + "descriptionWithTarget": "{kind} \"{name}\" を削除しますか?この操作は元に戻せません。", + "descriptionFallback": "この操作は元に戻せません。", + "kindDirectory": "ディレクトリ", + "kindFile": "ファイル" + }, + "rollbackConfirm": { + "title": "ロールバックの確認", + "descriptionWithTarget": "ファイル \"{name}\" のローカル変更をロールバックしますか?", + "descriptionFallback": "このファイルのローカル変更をロールバックしますか?" + }, + "terminalTitle": "ターミナル · {name}" + }, + "commandDropdown": { + "loading": "読み込み中...", + "addCommand": "コマンドを追加", + "manageCommands": "コマンドを管理...", + "runCommandTitle": "実行: {command}", + "stopCommandTitle": "停止: {command}", + "manageDialog": { + "title": "コマンド管理", + "empty": "コマンドはまだありません", + "noResults": "一致するコマンドがありません", + "searchPlaceholder": "コマンドを検索", + "newCommand": "新しいコマンド", + "nameLabel": "名前", + "commandLabel": "コマンド", + "dragSort": "ドラッグして並び替え", + "dragSortCommand": "{name} をドラッグして並び替え", + "orderFailed": "コマンドの並び順の保存に失敗しました", + "loadFailed": "コマンドの読み込みに失敗しました", + "saveFailed": "コマンドの保存に失敗しました", + "deleteFailed": "コマンドの削除に失敗しました", + "confirmDelete": { + "title": "コマンドを削除しますか?", + "message": "「{name}」を削除します。この操作は元に戻せません。" + } + } + }, + "workspaceContext": { + "confirmCloseDirtyTab": "保存せずに「{title}」を閉じますか?", + "confirmCloseOtherDirtyTabs": "未保存の変更がある他のタブを閉じますか?", + "confirmCloseAllDirtyTabs": "未保存の変更があるすべてのタブを閉じますか?", + "unableLoadContent": "内容を読み込めません。\n\n{message}", + "previewRequestTimedOut": "プレビュー要求がタイムアウトしました", + "diffRequestTimedOut": "Diff 要求がタイムアウトしました", + "branchCompareRequestTimedOut": "ブランチ比較要求がタイムアウトしました", + "commitDiffRequestTimedOut": "コミット Diff 要求がタイムアウトしました", + "saveRequestTimedOut": "保存要求がタイムアウトしました", + "reloadRequestTimedOut": "再読み込み要求がタイムアウトしました", + "noChanges": "変更はありません。", + "noDiffOutput": "Diff 出力がありません。", + "diffTitleWorkspace": "Diff · ワークスペース", + "diffDescriptionWorkingTree": "作業ツリー (HEAD)", + "diffTitleFile": "差分 · {name}", + "compareTitleFile": "比較 · {name}", + "compareTitleBranch": "比較 · {branch}", + "compareDescriptionPath": "{path} · {branch} と比較", + "compareDescriptionBranch": "{branch} と比較", + "diffTitleCommitFile": "差分 · {name} @ {hash}", + "diffTitleCommit": "差分 · {hash}", + "diffDescriptionCommitPath": "{path} · コミット {commit}", + "diffDescriptionCommit": "コミット {commit}", + "diffTitleConflictFile": "競合 · {name}", + "diffDescriptionConflict": "{path} · ディスク vs 未保存" + }, + "chat": { + "acpConnections": { + "actions": { + "openAgentsSettings": "エージェント設定を開く", + "retry": "再試行" + }, + "agentsSetupHint": "インストール管理は「設定 > エージェント」を開いてください。", + "withSetupHint": "{message}\n{hint}", + "blocked": { + "missingConfig": "現在のエージェント設定を読み取れません。", + "disabled": "{agent} はエージェント設定で無効になっています。接続前に有効化してください。", + "unavailable": "{agent} は現在のプラットフォームでは利用できません。", + "sdkMissing": "{agent} SDK がインストールされていません", + "adapterMissing": "{agent} の ACP アダプターがインストールされていません" + }, + "backendErrors": { + "initializeTimeout": "{agent} の接続ハンドシェイクがタイムアウトしました(60 秒以内に応答なし)。設定を開いてエージェントとネットワーク設定を確認してください。", + "mcpRejectedByAgent": "codeg の MCP コンパニオンを渡した際、{agent} がセッションを拒否しました: {message} このエージェントが MCP に対応していない場合は、設定で「MCP サポート」をオフにして再接続してください。", + "processExited": "{agent} プロセスが予期せず終了しました。", + "spawnFailed": "{agent} の起動に失敗しました: {message}", + "downloadFailed": "{agent} のダウンロードに失敗しました: {message}", + "sessionLoadResourceNotFound": "{agent} セッションの読み込みに失敗しました。再読み込みして再試行するか、新しい会話を開始してください。", + "sessionLoadUnavailable": "{agent} はこのセッションを復元できませんでした。セッションが終了したか、エージェントが停止した可能性があります。再読み込みして再試行するか、新しい会話を開始してください。", + "turnFailedRefusal": "{agent} がこのターンの続行を拒否しました。バックエンドまたはゲートウェイのエラーが原因の可能性があります。エージェントのログを確認してください。", + "turnFailedMaxTokens": "{agent} がこのターンの最大トークン数に達しました。", + "turnFailedMaxTurnRequests": "{agent} がこのターンで許可された最大リクエスト数に達しました。", + "turnFailedUnknown": "{agent} が不明な停止理由でターンを終了しました。", + "grokModelSwitchIncompatibleAgent": "{agent} は既存の会話ではこのモデルに切り替えられません。新しいセッションを開始して使用してください。", + "turnFailedEmpty": "{agent} は応答を生成せずにターンを終了しました。", + "turnFailedEmptyProtocol": "{agent} の出力を codeg が解析できませんでした。エージェントのバージョンがプロトコルと一致していない可能性があります。", + "turnFailedEmptyMetadata": "{agent} はこのターンでステータス更新(計画 / モード / 使用量)のみを送信し、応答はありませんでした。", + "detailsInAlerts": "ステータスバーのアラートを開き、詳細を展開するとエージェントの出力を確認できます。" + }, + "unableReadAgentConfig": "エージェント設定を読み取れません: {message}", + "connectFailedTitle": "{agent} の接続に失敗しました", + "toolFallbackTitle": "ツール", + "eventErrorTitle": "エージェントエラー", + "notificationTurnComplete": "{agent} の応答が完了しました", + "notificationError": "{agent} エラー:{message}", + "claudeApiRetry": { + "fallbackError": "authentication_failed", + "retryingWithMax": "再試行中 {attempt}/{max}", + "retryingAttempt": "再試行中({attempt} 回目)", + "retrying": "再試行中", + "nextRetryIn": "{seconds}秒後に再試行", + "line": "{error}{status} · {retry}", + "lineWithDelay": "{error}{status} · {retry}、{delay}", + "httpStatus": " (HTTP {status})" + }, + "configOptionAdjusted": "{agent} は{option}を {requested} ではなく {actual} にしました" + }, + "connectionLifecycle": { + "tasks": { + "connectingTitle": "{agent} に接続中", + "connectingDescription": "接続を確立しています", + "loadingSelectorsTitle": "{agent} のセレクターを読み込み中", + "loadingSelectorsDescription": "モードとセッション設定オプションを取得しています", + "initSessionTitle": "{agent} セッションを初期化中", + "initSessionDescription": "セッションを作成し設定を読み込んでいます" + }, + "errors": { + "connectionFailed": "接続に失敗しました", + "sendPromptFailed": "メッセージの送信に失敗しました: {error}" + } + }, + "shared": { + "attachedResources": "添付リソース", + "toolCallFailed": "ツール呼び出しに失敗しました" + }, + "messageThread": { + "emptyTitle": "まだメッセージはありません", + "emptyDescription": "会話を開始するとここにメッセージが表示されます" + }, + "chatInput": { + "connecting": "接続中...", + "agentResponding": "{agent} が応答中...", + "sendMessage": "メッセージを送信..." + }, + "messageInput": { + "askAnything": "何でも質問してください...", + "removeAttachmentAria": "{name} を削除", + "attachFiles": "ファイルを添付", + "addActions": "追加", + "quickMessages": "クイックメッセージ", + "quickMessagesEmpty": "クイックメッセージはありません", + "quickMessagesLoading": "読み込み中...", + "pasteAsPlainText": "プレーンテキストとして貼り付け", + "cut": "切り取り", + "copy": "コピー", + "selectAll": "すべて選択", + "pasteUnavailable": "クリップボードを読み取れませんでした。Ctrl/⌘V で貼り付けてください。", + "clipboardWriteFailed": "クリップボードに書き込めませんでした。キーボードショートカットをご利用ください。", + "quickMessageUntitled": "無題", + "liveFeedback": "ライブフィードバック", + "liveFeedbackDisabledHint": "エージェントの作業中に送信できます", + "dropFilesToAttach": "ファイルをドロップして添付", + "loadingSettings": "設定を読み込み中...", + "loadingMode": "モードを読み込み中...", + "modeLabel": "モード", + "toggleOn": "オン", + "toggleOff": "オフ", + "agentSettings": "エージェント設定", + "searchModel": "モデルを検索...", + "searchModelAria": "モデルを検索", + "modelListLabel": "モデル", + "noModels": "モデルが見つかりません", + "cancel": "キャンセル", + "send": "送信", + "forkAndSend": "フォークして送信", + "queueMessage": "キューに追加", + "steerIntoTurn": "現在のターンに挿入", + "steerQueuedInstead": "代わりにキューに追加しました。次のターンで送信されます。", + "steerFailed": "現在のターンに挿入できませんでした", + "steerAttachmentsUnsupported": "テキストのみ対応です。添付ファイル付きの下書きはキューをご利用ください。", + "slashCommands": "スラッシュコマンド", + "slashSearchPlaceholder": "コマンドを検索...", + "slashSearchEmpty": "一致するコマンドがありません", + "experts": "エキスパート", + "office": "日常業務", + "research": "科学研究", + "attachLocalUpload": "ローカルファイルを添付", + "attachServerFile": "サーバーファイルを添付", + "attachUploadTooLarge": "{names} は {limit}MB のアップロード上限を超えたためスキップしました。", + "attachUploadFailed": "{names} のアップロードに失敗しました。", + "attachUploadNotAFile": "{names} は通常ファイルではなく(ディレクトリまたは特殊ファイル)、スキップされました。", + "attachUploadQuotaExceeded": "サーバーのアップロード容量が不足しているため、{names} をアップロードできませんでした。", + "attachUploadInProgress": "画像はまだアップロード中です。しばらくしてからもう一度お試しください。", + "mentionEmpty": "一致する項目がありません", + "mentionLoading": "検索中…", + "mentionListLabel": "メンション", + "mentionMore": "他にも結果があります。入力して絞り込んでください", + "mentionCount": "{count, plural, other {# 件の結果}}", + "mentionGroupFile": "ファイル", + "mentionGroupAgent": "エージェント", + "mentionGroupSession": "セッション", + "mentionGroupCommit": "コミット", + "mentionGroupSkill": "スキル" + }, + "messageQueue": { + "addToQueue": "キューに追加", + "saveEdit": "保存", + "cancelEdit": "編集をキャンセル", + "editItem": "編集", + "deleteItem": "削除" + }, + "welcomeInputPanel": { + "agentsSettingsPath": "設定 > エージェント", + "autoConnectFallback": "{path} を開いてインストールを管理してください。", + "autoConnectAppend": "{message}。{path} を開いてインストールを管理してください。", + "enableAgentFirstPlaceholder": "セッション開始前に少なくとも1つのエージェントを有効化してください...", + "prepareSessionFailed": "チャットセッションを準備できませんでした。もう一度お試しください。", + "createConversationFailed": "会話を作成できませんでした。もう一度お試しください。", + "askAnythingPlaceholder": "何でも質問してください...", + "agentNotInstalled": "{agent} はインストールされていません · クリックして Agents 設定でインストール", + "agentAdapterNotInstalled": "{agent} の ACP アダプターが未インストールです(お使いの CLI とは別物)· クリックして Agents 設定でインストール" + }, + "welcomePanel": { + "greeting": "今日は何をしましょうか?", + "tips": { + "tileTabs": "会話タブを右クリックして「タイル表示」を選ぶと、複数のセッションを並べて比較できます", + "pinTab": "会話タブをダブルクリックすると固定でき、新しい会話に自動で置き換えられなくなります", + "shortcutsNewSearch": "{newConversation} で新規会話、{searchConversations} で履歴を検索できます", + "slashAtMention": "入力欄で / を入力するとスラッシュコマンド、@ を入力するとプロジェクト内のファイルを参照できます", + "pasteDropFiles": "スクリーンショットを貼り付けたり、ファイルを入力欄にドロップするだけで添付できます", + "queueMessage": "エージェントの応答中も入力を続けられ、次のメッセージはキューに入って完了後に自動送信されます", + "draftAutoSave": "未送信の下書きは会話ごとに自動保存され、戻ったときに復元されます", + "forkSend": "送信ボタンのドロップダウンで「分岐して送信」を選ぶと、現在の地点から新しいタブに分岐できます", + "exportConversation": "会話内容を右クリックすると Markdown / HTML / 画像としてエクスポートできます", + "chatChannels": "「設定 → チャットチャネル」で Telegram / Lark / WeChat を連携すれば、スマホから続けて操作できます", + "shortcutsAuxPanel": "{toggleAuxPanel} で右側パネルを開き、このセッションで変更したファイルや Git の差分を確認できます", + "shortcutsTerminalSidebar": "{toggleTerminal} で内蔵ターミナル、{toggleSidebar} でサイドバーを切り替えできます", + "customShortcuts": "すべてのショートカットは「設定 → ショートカット」で自由に変更できます", + "webService": "「設定 → Web サービス」を有効にすると、チームメンバーが同じ codeg にブラウザでアクセスできます", + "fusionMode": "ファイルや差分を開くと、会話の横に自動で表示されます。", + "quickMessages": "入力欄横の + ボタンから「クイックメッセージ」を選ぶと、保存済みのスニペットを一発で挿入できます(「設定 → クイックメッセージ」で管理)", + "experts": "+ ボタンの「エキスパートスキル」メニューから、デバッグや計画などのプリセットロールをワンクリックで読み込めます", + "taskBoard": "ToDo タスクは作業を最後まで実行します。エージェントは専用ワークツリーで作業し、あなたは差分を確認してからマージします。", + "automations": "オートメーションは保存したプロンプトをスケジュール実行します(毎晩のレビューなど)。実行ごとに専用ワークツリーを使うこともできます。", + "tokenUsage": "ステータスバーの会話数をクリックするとトークン使用量が開き、日付・エージェント・モデル・フォルダー別の内訳を確認できます。", + "mentionTargets": "@ で参照できるのはファイルだけではありません。別のエージェントをメンションしてサブタスクを任せたり、過去のセッション・コミット・スキルを参照したりできます。", + "splitGroups": "タブを右クリックして「右に分割」または「下に分割」を選ぶと、2 つの会話をそれぞれのペインで開いたままにできます。", + "worktrees": "ブランチボタンから「新規ワークツリー」を選ぶと、複数のエージェントが同じリポジトリで互いのファイルを上書きせずに並行作業できます。", + "importSessions": "すでにターミナルで実行したセッションは、フォルダーのメニューにある「ローカルセッションをインポート」で codeg に取り込めます。", + "subSessions": "エージェントが委任すると、サブセッションがサイドバーの親セッションの下に入れ子で表示されます。行を展開すれば、それぞれの作業を追えます。", + "liveFeedback": "「+」メニューのライブフィードバックを使えば、エージェントが実行中のターンに、中断させずにメモを差し込めます。", + "skillPacks": "設定 → スキルパックには、コーディング専門家・科学研究・オフィス作業のスキルがまとまっています。エージェントごとに有効化できます。", + "modelProviders": "設定 → モデルプロバイダーでは自分の API キーやエンドポイントを登録でき、モデルは入力欄からそのまま切り替えられます。", + "workspaceBackground": "設定 → 外観では、ワークスペースの背景画像・パネルの不透明度・アプリのフォントを変更できます。" + }, + "quickActions": { + "excel": "Excel ブック", + "excelDesc": "データ表・数式・グラフ", + "word": "Word 文書", + "wordDesc": "報告書・手紙・メモ", + "ppt": "プレゼン資料", + "pptDesc": "プロ仕様のスライド", + "pitchDeck": "ピッチデック", + "pitchDeckDesc": "主要指標付きの資金調達資料", + "morph": "Morph アニメ", + "morphDesc": "映画的なスライド遷移", + "morph3d": "3D Morph", + "morph3dDesc": "3D モデルとカメラワーク", + "academic": "学術論文", + "academicDesc": "引用と構成のある研究論文", + "financial": "財務モデル", + "financialDesc": "財務諸表・DCF・予測", + "dashboard": "データダッシュボード", + "dashboardDesc": "データから KPI と分析を生成", + "prompts": { + "excel": "次の要件で Excel ブックを作成してください:\n\n[データ・表・数式・グラフをここに記述]", + "word": "次の要件で Word 文書を作成してください:\n\n[文書の内容・構成・書式をここに記述]", + "ppt": "次の要件で PowerPoint プレゼンを作成してください:\n\n[スライド・内容・デザインをここに記述]", + "pitchDeck": "次の要件で資金調達のピッチデックを作成してください:\n\n[会社・調達ラウンド・主要指標をここに記述]", + "morph": "Morph トランジションアニメーション付きのプレゼンを作成してください:\n\n[プレゼンのテーマと希望する視覚効果をここに記述]", + "morph3d": "GLB モデルとカメラワーク付きの 3D Morph プレゼンを作成してください:\n\n[テーマと 3D ビジュアルの構想をここに記述]", + "academic": "次の要件で Word の学術論文を執筆してください:\n\n[研究テーマ・手法・主要な発見をここに記述]", + "financial": "次の要件で Excel の財務モデルを作成してください:\n\n[財務諸表・予測・分析をここに記述]", + "dashboard": "次の要件で Excel のデータダッシュボードを作成してください:\n\n[データソース・KPI・グラフをここに記述]", + "scientific-brainstorming": "研究の方向性をブレインストーミングしてください。分野横断のつながりを探り、前提を問い直し、有望な空白を見つけます。検討している領域:", + "hypothesis-generation": "これらの観察を検証可能な仮説に変換してください。明確な予測、妥当なメカニズム、検証実験を示します。私の観察:", + "experimental-design": "データ収集前に厳密な実験を設計してください。デザイン、無作為化、対照、交絡の回避方法を含めます。研究したいこと:", + "statistical-power": "必要なサンプルサイズを求めてください。私のデザインについて検出力分析(効果量・有意水準・検出力)を進めます。詳細:", + "statistical-analysis": "このデータを適切に分析してください。適切な検定の選択、前提の確認、効果量の報告、結果の記述を行います。データと問い:", + "exploratory-data-analysis": "私のデータファイルを探索的に分析してください。構造・品質・注目すべきパターンを要約し、次のステップを提案します。ファイル:", + "scientific-visualization": "出版品質の図を作成してください。明確なレイアウト、誠実なエラーバー、色覚に配慮した配色、ジャーナル書式を用います。示したい内容:", + "scientific-critical-thinking": "この研究や主張を批判的に評価してください。エビデンスの質を評価し、バイアスや交絡を見抜き、結論を吟味します。対象:", + "paper-lookup": "学術データベースから関連論文とオープンアクセス全文を探し、再利用できる引用も示してください。探しているもの:" + }, + "paper-lookup": "論文検索", + "paper-lookupDesc": "10 の学術 API(PubMed、arXiv、OpenAlex、Crossref…)で論文・引用・オープンアクセス全文を検索。", + "scientific-critical-thinking": "批判的思考", + "scientific-critical-thinkingDesc": "科学的主張とエビデンスの質を評価。バイアスや交絡を見抜き、GRADE やバイアスリスク枠組みを適用。", + "scientific-visualization": "科学的可視化", + "scientific-visualizationDesc": "出版品質の図。マルチパネル配置、有意差注釈、ジャーナル固有の書式に対応。", + "exploratory-data-analysis": "探索的データ解析", + "exploratory-data-analysisDesc": "200 以上の形式の科学データファイルを自動探索し、品質指標とレポートを生成。", + "statistical-analysis": "統計解析", + "statistical-analysisDesc": "ガイド付き統計解析。検定の選択、前提確認、効果量、APA 形式の報告に対応。", + "statistical-power": "統計的検出力", + "statistical-powerDesc": "サンプルサイズと検出力の分析。必要な被験者数、最小検出可能効果、検出力曲線を算出。", + "experimental-design": "実験計画", + "experimental-designDesc": "データ収集前に厳密な研究を設計。無作為化・ブロック化・対照・要因/DOE 配置に対応。", + "hypothesis-generation": "仮説生成", + "hypothesis-generationDesc": "観察を検証可能な仮説に変換し、予測・メカニズム・検証実験を提示します。", + "scientific-brainstorming": "科学的ブレインストーミング", + "scientific-brainstormingDesc": "自由な研究アイデア出し。分野横断のつながりを探り、前提を問い直し、研究の空白を見つけます。", + "tabs": { + "office": "日常業務", + "coding": "コード開発", + "research": "科学研究" + }, + "coding": { + "brainstormingDesc": "着手前に意図と要件を整理", + "debuggingDesc": "修正の前に根本原因を特定", + "writingSkillsDesc": "再利用可能なスキルを作成・編集・検証" + }, + "notEnabled": { + "title": "「{skill}」スキルは {agent} でまだ有効になっていません", + "description": "設定で有効にすると、ここで使用できます。", + "action": "有効にする", + "hint": "スキルが無効です" + }, + "scrollPrev": "前のスキルを表示", + "scrollNext": "次のスキルを表示" + } + }, + "agentSelector": { + "noEnabledAgents": "有効なエージェントがありません", + "openAgentsSettings": "エージェント設定を開く", + "notInstalled": "未インストール", + "moreAgents": "他のエージェント({count})" + }, + "subAgentOverlay": { + "title": "サブエージェント", + "collapsedSummary": "サブエージェント {count}", + "collapseAria": "サブエージェントを折りたたむ" + }, + "agentPlanOverlay": { + "title": "エージェントプラン", + "collapsePlanAria": "プランを折りたたむ", + "collapsedSummary": "計画 {completed}/{total}", + "status": { + "completed": "完了", + "inProgress": "進行中", + "pending": "保留", + "unknown": "不明" + }, + "priority": { + "high": "高", + "medium": "中", + "low": "低", + "unknown": "不明" + } + }, + "permissionDialog": { + "subtitle": "エージェントがこのターンを続行するための許可を要求しています。", + "queuedCount": "他 {count} 件待機中", + "kindFallbackTool": "ツール", + "command": "コマンド", + "cwd": "作業ディレクトリ: {cwd}", + "filesSummary": "ファイル: {count}", + "moreFiles": "+{count} 件の追加ファイル", + "plan": "計画", + "allowedActions": "許可されたアクション", + "targetMode": "対象モード: {mode}", + "optionGrants": "各選択肢が許可する内容", + "changeScopeSession": "このセッション", + "changeScopeProcess": "この実行", + "changeScopeUser": "ユーザー設定に保存", + "changeScopeProject": "プロジェクト設定に保存", + "changeScopeProjectLocal": "ローカルプロジェクト設定に保存", + "changeScopePersistent": "永続的に保存" + }, + "questionDialog": { + "title": "エージェントが質問しています", + "placeholder": "回答を入力...", + "send": "送信" + }, + "messageBranch": { + "previousBranchAria": "前のブランチ", + "nextBranchAria": "次のブランチ", + "pageOf": "{current} / {total}" + }, + "terminal": { + "title": "ターミナル", + "running": "実行中" + }, + "reasoning": { + "thinking": "考え中…", + "thoughtForFewSeconds": "考えた", + "thoughtForSeconds": "考えた" + }, + "linkSafety": { + "errorCannotOpen": "ローカルファイルを開けません", + "errorNoWorkspace": "現在アクティブなワークスペースフォルダがありません。", + "errorFailedOpen": "ローカルファイルを開けませんでした", + "errorFailedLink": "リンクを開けませんでした", + "errorUnsupportedLinkProtocol": "このリンクプロトコルはサポートされていません。" + }, + "fileActions": { + "openInFinder": "Finderで開く", + "openInExplorer": "エクスプローラーで開く", + "openInFileManager": "ファイルマネージャーで開く", + "copyRelativePath": "相対パスをコピー", + "copyAbsolutePath": "絶対パスをコピー", + "pathCopied": "パスをコピーしました", + "copyPathFailed": "パスのコピーに失敗しました", + "openFailed": "ローカルファイルを開けませんでした" + }, + "messageList": { + "attachedResources": "添付リソース", + "loading": "読み込み中...", + "loadEarlier": "以前のメッセージを読み込む", + "loadingEarlier": "以前のメッセージを読み込み中…", + "error": "エラー: {message}", + "errorTitle": "セッションの読み込みに失敗しました", + "errorActionReload": "再読み込み", + "errorActionNewSession": "新規会話", + "emptyConversation": "この会話にはメッセージがありません。", + "systemMessage": "システムメッセージ", + "copyMessage": "コピー", + "copied": "コピー済み", + "downloadImage": "画像をダウンロード", + "downloadFailed": "ダウンロードに失敗しました: {message}", + "imageGeneration": "画像生成", + "imageGenerationPending": "画像を生成中…", + "imageGenerationFailed": "画像生成に失敗しました", + "model": "モデル", + "tokenStats": "トークン使用量", + "tokenInput": "入力", + "tokenOutput": "出力", + "tokenCacheRead": "キャッシュ読取", + "tokenCacheWrite": "キャッシュ書込", + "duration": "所要時間", + "completedAt": "完了時刻", + "jumpToPreviousUserMessage": "前のユーザーメッセージへ", + "showMore": "もっと見る", + "showLess": "折りたたむ" + }, + "liveTurnStats": { + "thinking": "考え中...", + "streaming": "ストリーミング中", + "elapsedHours": "{value}時間", + "elapsedMinutes": "{value}分", + "elapsedSeconds": "{value}秒", + "outputSpeedAria": "推定出力速度", + "outputSpeedTooltip": "推定出力速度(テキスト + 思考)" + }, + "jsonTree": { + "viewRaw": "生の JSON を表示", + "viewTree": "ツリー表示", + "fields": "{count} 個のフィールド", + "items": "{count} 件" + }, + "tool": { + "parameters": "パラメーター", + "error": "エラー", + "result": "結果", + "status": { + "approvalRequested": "承認待ち", + "approvalResponded": "応答済み", + "inputAvailable": "実行中", + "inputStreaming": "保留中", + "outputAvailable": "完了", + "outputDenied": "拒否", + "outputError": "エラー" + } + }, + "toolCallBlock": { + "tool": "ツール", + "error": "エラー", + "result": "結果" + }, + "delegation": { + "subAgentRunning": "サブエージェント実行中…", + "noDetail": "No detail available yet.", + "unknownAgent": "サブエージェント", + "openDetail": "会話を表示", + "detailTitle": "サブエージェントの会話", + "detailDescription": "委任されたサブエージェントの会話を読み取り専用で表示します。", + "waitForResult": "タスク {task} の実行結果を待機中", + "waitForResultNoTask": "タスクの実行結果を待機中", + "cancelTask": "タスク {task} をキャンセル中", + "cancelTaskNoTask": "タスクをキャンセル中", + "resultPageOf": "{current} / {total}", + "prevResult": "前の結果", + "nextResult": "次の結果", + "noResultText": "このチェックでは結果がありません", + "status": { + "starting": "起動中", + "running": "実行中", + "checked": "確認済み", + "waiting": "承認待ち", + "ok": "完了", + "err": { + "default": "失敗", + "delegation_disabled": "無効", + "depth_limit": "深さ上限", + "invalid_agent_type": "不正なエージェント", + "spawn_failed": "起動失敗", + "send_failed": "送信失敗", + "timeout": "タイムアウト", + "canceled": "キャンセル済み", + "child_refusal": "サブエージェント拒否", + "child_max_tokens": "サブエージェント: トークン上限", + "child_max_turn_requests": "サブエージェント: 要求上限", + "child_empty": "サブエージェント応答なし", + "child_unknown": "サブエージェント: エラー", + "unknown": "不明なタスク" + } + } + }, + "contentParts": { + "showingTailOutput": "パフォーマンスのため、ストリーミング中は末尾出力を表示しています。", + "result": "結果", + "unknown": "不明", + "inputTruncated": "入力が切り詰められました — diff が不完全な可能性があります。", + "replaceAll": "すべて置換", + "filesCount": "ファイル: {count}", + "update": "更新", + "moreFiles": "+{count} 件の追加ファイル", + "timeoutMs": "タイムアウト: {timeout}ms", + "backgroundTrue": "バックグラウンド: true", + "scriptToolCalls": "{count} 個のツールを呼び出し", + "offset": "オフセット: {offset}", + "limit": "上限: {limit}", + "pages": "ページ: {pages}", + "mode": "モード: {mode}", + "cell": "セル: {cell}", + "shellSession": "セッション {id}", + "pathLabel": "パス:", + "globLabel": "Glob パターン:", + "typeLabel": "タイプ:", + "outputLabel": "出力:", + "caseInsensitive": "大文字小文字を区別しない", + "multiline": "複数行", + "promptLabel": "プロンプト", + "subjectLabel": "件名", + "taskLabel": "タスク", + "nameLabel": "名前:", + "agentPromptLabel": "プロンプト", + "agentModelLabel": "モデル", + "agentRunning": "実行中...", + "agentLiveTranscript": "ライブアクティビティ", + "agentProgressTools": "{count} 件のツール呼び出し", + "agentProgressTurns": "{count} ターン", + "agentProgressContext": "コンテキスト {pct}%", + "agentSessionAction": "サブエージェントのセッションを表示", + "agentSessionTitle": "サブエージェントのセッション", + "agentSessionLoading": "サブエージェントの記録を読み込んでいます…", + "agentSessionEmpty": "サブエージェントはまだ何も書き込んでいません。", + "agentFallbackTitle": "サブエージェント起動中…", + "agentCodexLaunchOnly": "起動しました。Codex はこのサブエージェントの進捗をこれ以上通知しません。結果はこの会話のメッセージとして届きます。", + "agentStatsBash": "コマンド", + "agentStatsRead": "ファイル読取", + "agentStatsSearch": "検索", + "agentStatsEdit": "編集", + "agentStatsOther": "その他", + "goal": { + "title": "目標:", + "titleWithStatus": "目標 {status}", + "objective": "目標", + "statusLabel": "ステータス", + "tokensUsed": "使用 tokens", + "budget": "予算", + "remaining": "残り", + "elapsed": "経過時間", + "tokens": "tokens", + "pause": "一時停止", + "clear": "クリア", + "status": { + "active": "実行中", + "paused": "一時停止", + "blocked": "ブロック中", + "usageLimited": "使用量制限", + "budgetLimited": "予算制限", + "complete": "完了", + "limited": "上限到達" + } + }, + "field": { + "file": "ファイル", + "notebook": "ノートブック", + "command": "コマンド", + "old": "旧", + "new": "新", + "pattern": "パターン", + "path": "パス", + "query": "クエリ", + "url": "URL:", + "description": "説明", + "content": "内容", + "source": "ソース", + "prompt": "プロンプト", + "subject": "件名", + "taskId": "タスク ID", + "status": "状態", + "skill": "Skill", + "args": "引数", + "offset": "オフセット", + "limit": "上限", + "glob": "Glob パターン", + "type": "タイプ", + "output": "出力", + "replaceAll": "すべて置換", + "language": "言語", + "timeout": "タイムアウト", + "background": "バックグラウンド", + "agentType": "エージェント種別", + "library": "ライブラリ", + "libraryId": "ライブラリ ID" + }, + "title": { + "edit": "編集", + "command": "コマンド", + "script": "スクリプト", + "waitCommand": "待機 {command}", + "waitCell": "セッション {id} を待機", + "terminateCommand": "停止 {command}", + "terminateCell": "セッション {id} を停止", + "stdinChars": "入力 {chars}", + "todoWrite": "TodoWrite(タスク更新)", + "read": "読み取り", + "write": "書き込み", + "notebookEdit": "NotebookEdit(ノート編集)", + "editFiles": "編集 ({count} 件のファイル)", + "editWithTarget": "{target} を編集", + "readWithTarget": "{target} を読み取り", + "writeWithTarget": "{target} に書き込み", + "notebookEditWithTarget": "NotebookEdit({target})", + "globWithPattern": "Glob パターン {pattern}", + "listFilesWithPath": "ファイル一覧 {path}", + "grepWithPattern": "Grep パターン {pattern}", + "taskCreateWithSubject": "タスク作成: {subject}", + "taskUpdateWithStatus": "タスク更新 #{id} -> {status}", + "taskUpdate": "タスク更新 #{id}", + "webFetchWithUrl": "WebFetch({url})", + "webSearchWithQuery": "WebSearch({query})", + "todosProgress": "タスク ({done}/{total})", + "skillWithName": "Skill: {name}", + "genericWithContext": "{tool}({context})" + }, + "search": { + "noMatches": "一致する結果なし", + "matchSummary": "{matches} 件の一致 · {files} 件のファイル", + "fileSummary": "{files} 件のファイル", + "moreResults": "他に {count} 件の結果は非表示" + }, + "toolGroup": { + "search": "{count} 件を検索", + "command": "{count} 件のコマンドを実行", + "read": "ファイルを {count} 回読み取り", + "memory": "{count} 件の記憶を呼び出し", + "edit": "ファイルを {count} 回編集", + "fetch": "{count} 件のリソースを取得", + "think": "{count} 回思考", + "todo": "{count} 件の TODO を更新", + "task": "{count} 件のタスクを実行", + "other": "{count} 件のツールを使用", + "errorSuffix": "{count} 件失敗", + "joiner": " · " + }, + "planMode": { + "entered": "計画モードを開始", + "planLabel": "計画", + "reviewApproved": "計画を承認 — 実行します", + "reviewKept": "プランモードを維持", + "reviewPending": "計画の判断待ち", + "submitted": "計画を送信しました", + "switched": "モードを切り替え" + }, + "backgroundTask": { + "title": "バックグラウンドタスク", + "titleWithId": "バックグラウンドタスク · {id}", + "running": "実行中", + "completed": "完了", + "failed": "失敗", + "stopped": "停止しました", + "exitCode": "終了コード {code}", + "polledTimes": "{count} 回ポーリング", + "runningInBackground": "バックグラウンド", + "launchNote": "バックグラウンドで実行中 · {id}" + }, + "codexScript": { + "outputMissing": "codex がスクリプト出力を切り詰めた際にこのコマンドの区切り行が失われたため、出力を割り当てられませんでした。", + "sharedWith": "この範囲には {commands} の出力も含まれます — 区切り行が codex により切り捨てられました。", + "truncated": "切り詰め済み" + } + }, + "messageNav": { + "title": "メッセージナビ", + "collapse": "メッセージナビを閉じる", + "collapsedSummary": "メッセージ {count}", + "fileCount": "{count, plural, one {# 個のファイル} other {# 個のファイル}}", + "remove": "削除", + "noDiffDataAvailable": "{filePath} の差分データがありません" + }, + "replyArtifacts": { + "title": "変更されたファイル", + "fileCount": "{count, plural, one {# 個のファイル} other {# 個のファイル}}", + "newFilesTitle": "新規ファイル", + "revealInFolder": "ファイルマネージャーで表示", + "openFile": "{filePath} を開く", + "openInEditor": "エディタで開く", + "remove": "削除", + "noDiffDataAvailable": "{filePath} の差分データがありません" + }, + "askQuestion": { + "title": "エージェントが選択を求めています", + "subtitle": "回答したら送信してください。いつでもスキップできます", + "recommended": "推奨", + "other": "その他", + "otherPlaceholder": "回答を入力…", + "singleSelect": "単一選択", + "multiSelect": "複数選択", + "skip": "スキップ", + "next": "次へ", + "submit": "送信", + "submitError": "送信できませんでした。もう一度お試しください。" + }, + "planApproval": { + "title": "エージェントが計画を提示しました — 確認してください", + "emptyPlan": "エージェントは計画を作成しませんでした。承認して実装を開始するか、変更を依頼してください。", + "approve": "承認して開始", + "requestChanges": "変更を依頼", + "abandon": "破棄", + "feedbackPlaceholder": "何を変更しますか?", + "sendChanges": "送信", + "cancel": "キャンセル", + "submitError": "送信できませんでした。もう一度お試しください。" + }, + "feedbackCheckResult": { + "count": "フィードバック {count} 件", + "expand": "すべてのフィードバックを表示", + "collapse": "折りたたむ", + "errorTitle": "フィードバックの確認に失敗しました" + }, + "askQuestionResult": { + "title": "質問", + "answeredLabel": "質問と回答:", + "awaiting": "回答をお待ちしています…", + "declined": "この質問をスキップしました — エージェントが独自に判断して進めました。", + "noSelection": "選択なし" + }, + "configStale": { + "agentConfigTitle": "エージェント設定が更新されました", + "modelProviderTitle": "モデルプロバイダーが更新されました", + "description": "このセッションは以前の設定のままです。再接続すると適用されます(会話履歴は保持されます)。", + "reconnect": "再接続して適用", + "reconnecting": "再接続中…", + "reconnectDisabledDuringTurn": "現在のターンが完了すると再接続できます", + "dismiss": "閉じる", + "reconnectFailed": "セッションの再接続に失敗しました", + "applied": "新しい設定を適用しました" + }, + "piProjectTrust": { + "title": "このプロジェクトには pi リソースが含まれています", + "description": "pi はリポジトリ自身の .pi ファイルを読み込んでいません。確認して判断してください。", + "descriptionExecutable": "リポジトリには pi 拡張機能が含まれており、起動時にコードを実行します。pi はまだ読み込んでいません。判断する前に確認してください。", + "review": "確認…", + "dismiss": "閉じる", + "dialogTitle": "このプロジェクトの pi リソースを信頼しますか?", + "dialogDescription": "フォルダーを信頼した場合にのみ、pi はリポジトリ自身の .pi ファイルを読み込みます。このリポジトリの内容を信頼できる場合にのみ許可してください。", + "executionWarning": "拡張機能はコードです。このフォルダーを信頼すると、メッセージを送信する前に、リポジトリの拡張機能が pi の起動時にあなたの権限で実行されます。", + "scopeNote": "この判断は pi の trust.json に保存され、その配下のすべてのフォルダーに適用されます。ターミナルで自分で pi を実行するときにも使われます。後から「設定 → エージェント → Pi」で変更できます。", + "trust": "プロジェクトを信頼", + "decline": "読み込まないままにする", + "disabledDuringTurn": "現在のターンが終了すると利用できます", + "trustedToast": "プロジェクトを信頼しました — pi がリソースを読み込むよう再接続しました", + "declinedToast": "プロジェクトのリソースは読み込まれません", + "saveFailed": "プロジェクトの信頼設定の保存に失敗しました", + "grantTitle": "このプロジェクトは既に信頼されています", + "grantDescription": "pi はこのリポジトリ自身の .pi ファイルを読み込みます。何が許可されるか確認してください。", + "grantInheritedDescription": "親フォルダーが信頼されているため、pi はこのリポジトリ自身の .pi ファイルを読み込みます。何が許可されるか確認してください。", + "grantDialogTitle": "このプロジェクトの pi リソースは信頼されています", + "grantDialogDescription": "pi はこのリポジトリ自身の .pi ファイルの読み込みを許可されています。以前のバージョンの codeg はフォルダーを開いた時点で自動的に許可していたため、確認を求められていない可能性があります。", + "grantExecutionWarning": "拡張機能はコードです。リポジトリの拡張機能は、メッセージを送信する前に pi の起動時にあなたの権限で実行されます。", + "inheritedFrom": "信頼の由来", + "revoke": "信頼を取り消す", + "keepTrusted": "信頼を維持", + "revokedToast": "信頼を取り消しました — 再接続したため pi はプロジェクトのリソースを読み込みません", + "trustedNoReconnect": "プロジェクトを信頼しました — pi の次回起動時に適用されます", + "revokedNoReconnect": "信頼を取り消しました — pi の次回起動時に適用されます" + }, + "collabAgent": { + "title": "サブエージェント", + "errorTitle": "サブエージェントのタスクが失敗しました", + "statesLabel": "サブエージェント", + "statusRunning": "実行中", + "statusCompleted": "完了", + "statusFailed": "失敗", + "statusPending": "起動中", + "statusInterrupted": "中断", + "statusClosed": "終了", + "statusNotFound": "見つかりません", + "opSpawn": "サブエージェントを起動中", + "opWait": "サブエージェントの結果を取得中", + "opClose": "サブエージェントを終了中", + "opResume": "サブエージェントを再開中" + }, + "contextCompaction": { + "compacting": "コンテキストを圧縮しています…", + "compacted": "コンテキストを圧縮しました", + "compactedTokens": "コンテキストを圧縮 · {before} → {after} トークン", + "failed": "コンテキストの圧縮に失敗しました" + }, + "sessionFailure": { + "category": { + "connection": "接続の問題", + "access": "アクセスの問題", + "limit": "上限に到達", + "request": "リクエスト拒否", + "service": "サービスの問題", + "unknown": "セッションの問題" + }, + "action": { + "retry": "再試行", + "login": "サインイン", + "newSession": "新しいセッション" + }, + "recovered": "回復済み", + "retryUnavailable": "再送信できるメッセージがありません。", + "toggleDetails": "詳細の切り替え" + }, + "backgroundTasks": { + "running": "{count} 件のバックグラウンドタスクを実行中", + "settling": "バックグラウンド結果を同期中…", + "settledFallback": "バックグラウンドタスクが終了しました({status})", + "cardRunning": "バックグラウンドで実行中", + "cardLaunchedPending": "バックグラウンドタスクを開始しました", + "cardCompleted": "バックグラウンドタスクが完了しました", + "cardFinishedWithStatus": "バックグラウンドタスクが終了しました({status})", + "cardResultPending": "結果はまだ返っていません" + }, + "proposedPlan": { + "title": "提案された計画", + "planning": "計画中…" + } + }, + "diffPreview": { + "mode": { + "added": "追加", + "deleted": "削除", + "renamed": "名前変更", + "modified": "変更" + }, + "hunkLabel": "ハンク {index}", + "loadingHunk": "Hunk を読み込み中...", + "noDiffData": "Diff データがありません", + "showRemainingLines": "残り {count} 行を表示" + }, + "conversationContextBar": { + "folderTitle": "作業フォルダ", + "branchTitle": "作業ブランチ", + "searchFolder": "Search folder...", + "searchBranch": "Search branch...", + "noFolders": "No folders", + "noBranches": "No branches", + "noBranch": "(no branch)", + "chatModeLabel": "チャットモード", + "commit": "Commit", + "push": "Push", + "merge": "Merge", + "toasts": { + "folderChanged": "Switched to {name}", + "openFolderFailed": "Failed to open folder", + "switchedToChatMode": "チャットモードに切り替えました", + "openStashFailed": "Failed to open stash window", + "openMergeFailed": "Failed to open merge window" + } + }, + "cloneDialog": { + "title": "リポジトリをクローン", + "repositoryUrl": "リポジトリ URL", + "repositoryUrlPlaceholder": "https://github.com/user/repo.git", + "directory": "ディレクトリ", + "directoryPlaceholder": "保存先ディレクトリを選択...", + "browseDirectory": "ディレクトリを参照", + "cancel": "キャンセル", + "clone": "クローン", + "clonePath": "クローンパス: {path}" + }, + "toasts": { + "cloneFailed": "リポジトリのクローンに失敗しました" + } + }, + "ProjectBoot": { + "title": "プロジェクトブート", + "tabs": { + "shadcn": "shadcn", + "hyperframes": "HyperFrames" + }, + "hyperframes": { + "title": "HyperFrames 動画プロジェクト", + "subtitle": "HTML から動画を生成するプロジェクトを作成します。ワークスペースのエージェントがそれを記述・レンダリングできます。", + "resolution": "解像度", + "skillsTitle": "エージェントスキル", + "skillsDesc": "選択したエージェント向けに HyperFrames スキルをグローバル(シンボリックリンク)でインストールし、動画の作成・レンダリングを可能にします。", + "recheck": "再チェック", + "installedBadge": "インストール済み", + "skillsInstall": "スキルをインストール / 更新", + "skillsInstalling": "スキルをインストール中…", + "skillsInstalled": "HyperFrames スキルをインストールしました", + "skillsInstallFailed": "HyperFrames スキルのインストールに失敗しました" + }, + "config": { + "base": "ベース", + "style": "スタイル", + "baseColor": "ベースカラー", + "theme": "テーマ", + "chartColor": "チャートカラー", + "iconLibrary": "アイコンライブラリ", + "font": "フォント", + "fontHeading": "見出しフォント", + "menuAccent": "メニューアクセント", + "menuColor": "メニューカラー", + "radius": "角丸", + "template": "テンプレート", + "createProject": "プロジェクトを作成", + "sectionStyle": "スタイル", + "sectionColors": "カラー", + "sectionTypography": "タイポグラフィ", + "sectionInterface": "インターフェース" + }, + "preview": { + "loading": "プレビューを読み込み中..." + }, + "createDialog": { + "title": "プロジェクトを作成", + "projectName": "プロジェクト名", + "projectNamePlaceholder": "my-app", + "frameworkTemplate": "フレームワークテンプレート", + "packageManager": "パッケージマネージャー", + "saveDirectory": "保存先ディレクトリ", + "saveDirectoryPlaceholder": "ディレクトリを選択...", + "browseDirectory": "参照", + "projectPath": "プロジェクトの作成先:{path}", + "advancedOptions": "詳細オプション", + "base": "基盤ライブラリ", + "enableRtl": "RTL サポートを有効にする", + "enableRtlDescription": "右から左に書く言語(アラビア語、ヘブライ語など)のレイアウトサポートを有効にする", + "pmChecking": "確認中...", + "pmNotInstalled": "未インストール", + "cancel": "キャンセル", + "create": "作成", + "creating": "プロジェクトを作成中..." + }, + "toasts": { + "createFailed": "プロジェクトの作成に失敗しました", + "createSuccess": "プロジェクトが正常に作成されました", + "openWorkspaceFailed": "プロジェクトは作成されましたが、ワークスペースで開けませんでした" + }, + "errors": { + "directoryExists": "対象ディレクトリは既に存在します", + "commandFailed": "プロジェクト作成コマンドが失敗しました。" + } + }, + "WebServiceSettings": { + "addressSwitchHint": "切り替えても、ここに表示され開くアドレスが変わるだけです。サービスはすべてのインターフェースで待ち受けており、どのアドレスからもアクセスできます。", + "sectionTitle": "Webサービス", + "sectionDescription": "有効にするとブラウザからCodegにリモートアクセスできます", + "port": "ポート", + "status": "ステータス", + "autoStart": "自動起動", + "autoStartHint": "Codeg の起動時に Web サービスを開始", + "running": "実行中", + "stopped": "停止中", + "processing": "処理中...", + "start": "開始", + "stop": "停止", + "startFailed": "開始に失敗しました", + "stopFailed": "停止に失敗しました", + "saveConfigFailed": "Webサービス設定の保存に失敗しました", + "open": "開く", + "hide": "非表示", + "show": "表示", + "copy": "コピー", + "qrcode": "QRコード", + "qrcodeTitle": "スキャンして開く", + "qrcodeHint": "スマートフォンでスキャンして、ブラウザで Codeg を開きます", + "addressLabel": "アクセスアドレス", + "tokenLabel": "アクセストークン", + "tokenHint": "Webクライアントの初回アクセス時にこのトークンを入力してください", + "tokenPlaceholder": "空欄の場合は自動生成", + "regenerate": "再生成", + "stalePortOccupiedTitle": "ポート {port} は他のプロセスに使用されています", + "stalePortUnknownTitle": "ポート {port} の状態を確認できません", + "stalePortHint": "ポートが解放されるまで Codeg はバインドできません。上のポートを変更するか、占有しているプロセスを終了してください。", + "errors": { + "alreadyRunning": "Web サービスはすでに起動しています", + "invalidAddress": "ホストまたはポートの形式が無効です", + "portInUse": "ポート {port} はすでに使用中です。そのポートを使用しているプロセスを終了するか、別のポートを指定してください", + "permissionDenied": "権限が不足しています。1024 以上のポートを使用するか、より高い権限で実行してください", + "addressUnavailable": "このアドレスはこの端末では利用できません", + "bindFailed": "アドレスのバインドに失敗しました" + } + }, + "DirectoryBrowser": { + "title": "ディレクトリを参照", + "pathPlaceholder": "ディレクトリパスを入力...", + "goHome": "ホームディレクトリへ", + "navigateUp": "親ディレクトリへ", + "select": "選択", + "cancel": "キャンセル", + "loading": "読み込み中...", + "emptyDirectory": "このディレクトリは空です", + "errorLoadingDir": "ディレクトリの読み込みに失敗しました", + "permissionDenied": "アクセス権がありません" + }, + "ChatChannelSettings": { + "loading": "読み込み中...", + "sectionTitle": "チャットチャンネル", + "sectionDescription": "IM ボットを設定して、イベント通知やコーディング活動の照会を行います。", + "addChannel": "チャンネルを追加", + "noChannels": "チャットチャンネルはまだ設定されていません。", + "channelName": "名前", + "channelNamePlaceholder": "My Telegram Bot", + "channelType": "チャンネルタイプ", + "lark": "Lark(飛書)", + "weixin": "WeChat", + "dailyReport": "デイリーレポート", + "dailyReportTime": "送信時刻", + "nameRequired": "チャンネル名を入力してください。", + "tokenRequired": "トークンを入力してください。", + "chatIdRequired": "Chat ID を入力してください。", + "topicMode": "トピックグループモード", + "topicModeHint": "Telegram forum topics を個別の Codeg セッションとしてルーティングします。Bot は forum supergroup に参加し、topics を管理できる必要があります。", + "loadFailed": "チャンネルの読み込みに失敗しました。", + "saveFailed": "保存に失敗しました。", + "connectSuccess": "チャンネルに接続しました。", + "connectFailed": "接続に失敗しました", + "disconnectSuccess": "チャンネルを切断しました。", + "disconnectFailed": "切断に失敗しました。", + "testSuccess": "接続テストに合格しました。", + "testFailed": "接続テストに失敗しました", + "deleteSuccess": "チャンネルを削除しました。", + "deleteFailed": "チャンネルの削除に失敗しました。", + "deleteConfirmTitle": "チャンネルを削除", + "deleteConfirmMessage": "このチャンネルとメッセージログを完全に削除します。よろしいですか?", + "cancel": "キャンセル", + "delete": "削除", + "create": "作成", + "save": "保存", + "channelListTitle": "設定済みチャンネル", + "channelListDescription": "有効なチャンネルはサービス起動時に自動接続されます。", + "editChannel": "チャンネルを編集", + "editSuccess": "チャンネルを更新しました。", + "tokenPlaceholderKeep": "空欄で現在の値を維持", + "weixinScanTitle": "QRコードをスキャン", + "weixinScanDescription": "WeChatを開いてQRコードをスキャンして接続してください。", + "weixinQrcodeExpired": "QRコードの有効期限が切れました。", + "weixinRefreshQrcode": "更新", + "weixinWaitingScan": "スキャン待ち...", + "weixinPollError": "接続が不安定です。再試行中...", + "weixinReconnectNotice": "iLink プロトコルの制限により、再接続のたびにまずボットにメッセージを送信しないとイベントトリガーが有効になりません。", + "connect": "接続", + "disconnect": "切断", + "test": "接続テスト", + "tabs": { + "channels": "チャンネル", + "commands": "コマンド", + "events": "イベント", + "other": "その他" + }, + "commands": { + "title": "組み込みコマンド", + "description": "チャットチャンネルで使用可能な Bot コマンド。グループチャットではメッセージを処理するために @Bot が必要です。", + "prefixLabel": "コマンドプレフィックス", + "prefixDescription": "Bot コマンドを起動するプレフィックス、1-3 文字の英数字以外の文字(デフォルト /)。", + "prefixSaved": "コマンドプレフィックスを保存しました。", + "prefixSaveFailed": "コマンドプレフィックスの保存に失敗しました。", + "prefixInvalid": "プレフィックスは1-3文字の英数字以外の文字である必要があります。", + "save": "保存", + "folderDesc": "作業フォルダを選択", + "agentDesc": "AIエージェントを選択", + "taskDesc": "セッションを作成してタスクを実行", + "sessionsDesc": "フォルダ内のアクティブなセッション一覧", + "resumeDesc": "最近の会話 / セッションを再開", + "cancelDesc": "現在のタスクをキャンセル", + "approveDesc": "エージェントの権限リクエストを承認", + "denyDesc": "エージェントの権限リクエストを拒否", + "searchDesc": "キーワードで会話を検索", + "todayDesc": "本日のアクティビティ概要", + "statusDesc": "チャンネル接続状態", + "helpDesc": "ヘルプを表示" + }, + "events": { + "title": "イベント通知", + "description": "イベントを有効にすると、トリガーされた際にチャンネルにプッシュされます。", + "turnComplete": "ターン完了", + "turnCompleteDesc": "エージェントのターンが終了した時", + "error": "エージェントエラー", + "errorDesc": "エージェントがエラーに遭遇した時", + "permissionRequest": "権限リクエスト", + "permissionRequestDesc": "エージェントが操作の権限を要求した時", + "questionRequest": "エージェントからの質問", + "questionRequestDesc": "エージェントが質問したとき", + "userPromptSent": "ユーザーメッセージ", + "userPromptSentDesc": "メッセージを送信したとき(通知に本文が含まれます)", + "saved": "イベントフィルターを更新しました。", + "saveFailed": "イベントフィルターの保存に失敗しました。", + "loadFailed": "設定の読み込みに失敗しました。", + "retry": "再試行", + "webhooksTitle": "Webhook", + "webhooksDescription": "有効なイベントの発生時に、1 つ以上の URL へ JSON を POST します。上のイベントフィルターは Webhook にも適用されます。", + "webhookUrlPlaceholder": "https://example.com/webhook", + "addWebhook": "Webhook を追加", + "removeWebhook": "Webhook を削除", + "webhookSave": "保存", + "webhooksSaved": "Webhook を保存しました。", + "webhooksSaveFailed": "Webhook の保存に失敗しました。", + "webhookInvalidUrl": "有効な http(s) URL を入力してください。", + "docsTitle": "リクエスト形式", + "docsMethod": "メソッド", + "docsContentType": "Content-Type", + "docsNote": "有効な各イベントはすべての URL に配信されます。Webhook はデバウンスされず、上のイベントフィルターが適用されます。", + "editWebhook": "Webhook を編集", + "enableWebhook": "Webhook を有効化", + "webhookDuplicate": "この URL は既に設定されています。", + "cancel": "キャンセル", + "webhooksEmpty": "Webhook はまだ設定されていません。", + "deleteWebhookTitle": "Webhook を削除", + "deleteWebhookMessage": "この Webhook を削除しますか?このURLにイベントは配信されなくなります。", + "delete": "削除" + }, + "language": { + "title": "メッセージ言語", + "description": "イベント通知、コマンド応答、日次レポートをチャットチャンネルに送信する際に使用する言語。", + "saved": "メッセージ言語を保存しました。", + "saveFailed": "メッセージ言語の保存に失敗しました。", + "en": "英語", + "zh-cn": "簡体字中国語", + "zh-tw": "繁体字中国語", + "ja": "日本語", + "ko": "韓国語", + "es": "スペイン語", + "de": "ドイツ語", + "fr": "フランス語", + "pt": "ポルトガル語", + "ar": "アラビア語" + } + }, + "ModelProviderSettings": { + "sectionTitle": "モデルプロバイダー", + "sectionDescription": "エージェントのAPIプロバイダー認証情報を管理します。", + "filterAll": "すべて", + "providerListTitle": "設定済みプロバイダー", + "addProvider": "プロバイダーを追加", + "editProvider": "プロバイダーを編集", + "noProviders": "モデルプロバイダーはまだ設定されていません。", + "providerName": "名前", + "providerNamePlaceholder": "例: OpenAI、Anthropic", + "apiUrl": "API URL", + "apiUrlPlaceholder": "https://api.openai.com/v1", + "apiKey": "APIキー", + "apiKeyPlaceholder": "sk-...", + "apiKeyKeepCurrent": "空欄のまま現在の値を維持", + "agentTypes": "エージェントタイプ", + "agentTypesRequired": "少なくとも1つのエージェントタイプを選択してください。", + "agentType": "エージェントタイプ", + "agentTypeRequired": "エージェントタイプを選択してください。", + "agentTypeImmutableHint": "エージェントタイプは作成後に変更できません。", + "model": "モデル", + "modelPlaceholderCodex": "gpt-5.6-sol / gpt-5.5", + "modelPlaceholderGemini": "gemini-3-pro-preview", + "claudeMainModel": "メインモデル", + "claudeReasoningModel": "推論モデル(思考)", + "claudeHaikuDefaultModel": "デフォルトの Haiku モデル", + "claudeSonnetDefaultModel": "デフォルトの Sonnet モデル", + "claudeOpusDefaultModel": "デフォルトの Opus モデル", + "claudeCustomModelOption": "カスタムモデル ID", + "claudeCustomModelOptionName": "カスタムモデル名", + "claudeCustomModelOptionDescription": "カスタムモデルの説明", + "claudeCustomModelOptionHint": "Claude のモデル選択メニューにカスタム項目を1つ追加します(例: カスタムゲートウェイ/プロキシ経由のモデル)。名前と説明は任意の表示用設定です。", + "nameRequired": "プロバイダー名は必須です。", + "apiUrlRequired": "API URLは必須です。", + "apiKeyRequired": "APIキーは必須です。", + "loadFailed": "プロバイダーの読み込みに失敗しました。", + "saveFailed": "変更の保存に失敗しました。", + "createSuccess": "プロバイダーを作成しました。", + "editSuccess": "プロバイダーを更新しました。", + "deleteSuccess": "プロバイダーを削除しました。", + "deleteConfirmTitle": "プロバイダーを削除", + "deleteConfirmMessage": "プロバイダー「{name}」を完全に削除しますか?", + "deleteBlockedByAgent": "{agents} がこのプロバイダーを使用中です。削除する前にリンクを解除してください。", + "cancel": "キャンセル", + "delete": "削除", + "create": "作成", + "save": "保存", + "affectedRunningSessions": "{count} 件の実行中セッションは再接続すると変更が適用されます" + }, + "SkillMatrix": { + "loading": "読み込み中…", + "searchPlaceholder": "名前・ID・説明で検索", + "empty": "表示する項目がありません。", + "emptySearch": "現在の検索に一致する項目がありません。", + "skillColumn": "スキル", + "selectAll": "表示中をすべて選択", + "selectSkill": "{name} を選択", + "everything": { + "label": "一括", + "enable": "すべて有効化(表示中)", + "disable": "すべて無効化(表示中)" + }, + "columnMenu": { + "enableAll": "すべてのスキルを有効化", + "disableAll": "すべてのスキルを無効化" + }, + "rowMenu": { + "label": "{name} の一括操作", + "enableAll": "すべてのエージェントで有効化", + "disableAll": "すべてのエージェントで無効化" + }, + "bulk": { + "selected": "{count} 件選択中", + "targetAll": "すべてのエージェント", + "targetSome": "{count} 個のエージェント", + "enable": "有効化", + "disable": "無効化", + "clear": "クリア" + }, + "confirm": { + "disableTitle": "これらのリンクを無効化しますか?", + "disableBody": "codeg が管理する {count} 件のスキルリンクを削除します。カスタムディレクトリを占有しているスキルはそのまま残ります。いつでも再び有効化できます。", + "cancel": "キャンセル", + "confirm": "無効化" + }, + "toasts": { + "loadFailed": "スキルの状態の読み込みに失敗しました", + "applyFailed": "変更の適用に失敗しました", + "enabled": "{count} 件のリンクを有効化しました", + "disabled": "{count} 件のリンクを無効化しました", + "enabledPartial": "{ok} 件を有効化、{failed} 件が失敗しました", + "disabledPartial": "{ok} 件を無効化、{failed} 件が失敗しました" + }, + "detail": { + "enableForAgents": "エージェントで有効化", + "preview": "SKILL.md プレビュー", + "loadingContent": "コンテンツを読み込み中…" + }, + "copyModeHint": "コピー済み(リンクではありません)— 更新後は最新版を取得するため再度有効化してください" + }, + "ExpertsSettings": { + "title": "エキスパートスキル", + "description": "AI コーディングエージェント向けに、厳選され実戦で検証されたスキルワークフローを有効にします。各エキスパートは superpowers プロジェクトの独立したスキルで、codeg が中央コピーを管理し、選択したエージェントにリンクします。", + "loading": "エキスパートを読み込み中…", + "loadingContent": "コンテンツを読み込み中…", + "emptyExperts": "利用可能なエキスパートがありません。アプリケーションログを確認してください。", + "emptySelection": "エキスパートを選択して内容を表示し、有効化を管理します。", + "emptySearch": "現在の検索に一致するエキスパートはありません。", + "searchPlaceholder": "名前、ID、または説明でエキスパートを検索", + "enableForAgents": "エージェントで有効化", + "noAgents": "ACP エージェントが検出されません。", + "copyModeWarning": "コピー済み(リンクなし)。codeg 更新後に最新版を取得するには再度有効化してください。", + "previewTitle": "SKILL.md プレビュー", + "categories": { + "discovery": "発見と設計", + "planning": "計画", + "execution": "実行", + "quality": "品質とテスト", + "debugging": "デバッグ", + "review": "レビューと統合", + "meta": "メタ" + }, + "states": { + "not_linked": "未有効", + "linked_to_codeg": "有効", + "linked_elsewhere": "ブロック — 別のリンクが存在", + "blocked_by_real_directory": "ブロック — カスタムスキルがこの名前を占有", + "broken": "壊れたリンク" + }, + "badges": { + "userModified": "ユーザーにより変更" + }, + "actions": { + "openCentralDir": "中央フォルダを開く", + "refresh": "更新" + }, + "toasts": { + "loadFailed": "エキスパート詳細の読み込みに失敗しました", + "enabled": "このエージェントでエキスパートを有効化しました", + "disabled": "このエージェントでエキスパートを無効化しました", + "enableFailed": "エキスパートの有効化に失敗しました", + "disableFailed": "エキスパートの無効化に失敗しました", + "openFolderFailed": "フォルダを開けませんでした" + } + }, + "ScienceSettings": { + "title": "科学研究スキル", + "description": "AI コーディングエージェント向けに厳選した科学研究スキル(仮説生成・実験計画・統計・可視化・批判的評価・文献検索)を有効化します。codeg が中央コピーを管理し、選んだエージェントに各スキルをリンクします。", + "loading": "科学研究スキルを読み込み中…", + "emptySkills": "利用可能な科学研究スキルがありません。アプリのログを確認してください。", + "searchPlaceholder": "名前・ID・説明で科学研究スキルを検索", + "categories": { + "ideation": "アイデア出し", + "design": "研究デザイン", + "analysis": "分析", + "visualization": "可視化", + "evaluation": "評価", + "literature": "文献" + }, + "states": { + "not_linked": "未有効", + "linked_to_codeg": "有効", + "linked_elsewhere": "ブロック — 別のリンクが存在", + "blocked_by_real_directory": "ブロック — カスタムスキルがこの名前を占有", + "broken": "壊れたリンク" + }, + "badges": { + "userModified": "ユーザーにより変更", + "needsKey": "APIキーが必要", + "needsSetup": "環境構築が必要な場合あり" + }, + "actions": { + "openCentralDir": "中央フォルダを開く", + "refresh": "更新" + }, + "toasts": { + "openFolderFailed": "フォルダを開けませんでした" + } + }, + "OfficeToolsSettings": { + "title": "Office ツール", + "description": "OfficeCLI スキルを管理し、Excel、Word、PowerPoint ファイルを作成します。OfficeCLI をインストールし、スキルを同期して、エージェントごとに有効化できます。", + "loadingContent": "コンテンツを読み込み中…", + "emptySkills": "スキルがありません。OfficeCLI をインストールしてスキルを同期してください。", + "emptySelection": "スキルを選択して内容を確認し、有効化を管理します。", + "emptySearch": "検索に一致するスキルがありません。", + "searchPlaceholder": "名前、ID、説明でスキルを検索", + "enableForAgents": "エージェントに対して有効化", + "noAgents": "ACP エージェントが検出されませんでした。", + "installFirst": "スキルを有効にするには、まず OfficeCLI をインストールしてください。", + "syncFirst": "コンテンツを読み込むには、まずスキルを同期してください。", + "noContent": "コンテンツがありません。", + "copyModeWarning": "コピー済み(リンクなし)。最新版を取得するには再同期してください。", + "previewTitle": "SKILL.md プレビュー", + "detection": { + "installed": "インストール済み", + "notInstalled": "未インストール", + "notRunnable": "インストール済みですが実行できません", + "installHint": "OfficeCLI をインストールして、AI エージェントにオフィスドキュメント生成スキルを有効にします。", + "install": "インストール", + "uninstall": "アンインストール", + "syncSkills": "スキルを同期" + }, + "categories": { + "general": "一般", + "presentations": "プレゼンテーション", + "documents": "ドキュメント", + "spreadsheets": "スプレッドシート" + }, + "states": { + "not_linked": "無効", + "linked_to_codeg": "有効", + "linked_elsewhere": "ブロック — 他のリンクが存在します", + "blocked_by_real_directory": "ブロック — カスタムスキルがこの名前を使用しています", + "broken": "リンク切れ" + }, + "badges": { + "notSynced": "未同期" + }, + "actions": { + "refresh": "更新" + }, + "toasts": { + "loadFailed": "スキル詳細の読み込みに失敗", + "enabled": "このエージェントでスキルを有効化しました", + "disabled": "このエージェントでスキルを無効化しました", + "enableFailed": "スキルの有効化に失敗", + "disableFailed": "スキルの無効化に失敗", + "installSuccess": "OfficeCLI のインストールに成功", + "installFailed": "OfficeCLI のインストールに失敗", + "uninstallSuccess": "OfficeCLI をアンインストールしました", + "uninstallFailed": "OfficeCLI のアンインストールに失敗", + "syncSuccess": "{synced} 個のスキルを同期しました", + "syncPartial": "{synced} 個同期、{errors} 個失敗", + "syncFailed": "スキルの同期に失敗" + }, + "autoPreviewLabel": "プレビューを自動で開く", + "autoPreviewHint": "エージェントが Word、Excel、PowerPoint ファイルを作成または編集したときに、ライブプレビューを自動で開きます。" + }, + "SkillPacksSettings": { + "title": "スキルパック", + "description": "codeg が一元管理し、各 AI エージェントにリンクする厳選スキルの束です——コーディング専門家、科学研究、オフィス文書ツール。下でエージェントごとに有効化できます。", + "tabs": { + "experts": "エキスパート", + "science": "科学研究", + "office": "Officeツール", + "custom": "カスタム" + }, + "actions": { + "openCentralDir": "中央フォルダを開く", + "refresh": "更新" + }, + "toasts": { + "openFolderFailed": "フォルダを開けませんでした" + } + }, + "QuickMessagesSettings": { + "title": "クイックメッセージ", + "description": "再利用可能なメッセージスニペットを管理します。ドラッグして並べ替えできます。", + "loading": "クイックメッセージを読み込み中…", + "emptyList": "クイックメッセージはまだありません。「新規」をクリックして作成してください。", + "emptySelection": "編集するクイックメッセージを選択してください。", + "searchPlaceholder": "タイトルまたは内容で検索", + "untitled": "無題", + "actions": { + "new": "新規", + "save": "保存", + "delete": "削除", + "dragSort": "ドラッグして並べ替え", + "dragSortMessage": "クイックメッセージを並べ替え: {name}" + }, + "fields": { + "title": "タイトル", + "titlePlaceholder": "このメッセージに短いタイトルを付けてください", + "content": "内容", + "contentPlaceholder": "ここにメッセージ内容を入力してください" + }, + "confirmDelete": { + "title": "クイックメッセージを削除しますか?", + "message": "「{name}」を完全に削除します。よろしいですか?", + "cancel": "キャンセル", + "confirm": "削除" + }, + "toasts": { + "loadFailed": "クイックメッセージの読み込みに失敗しました", + "createFailed": "クイックメッセージの作成に失敗しました", + "saveFailed": "クイックメッセージの保存に失敗しました", + "deleteFailed": "クイックメッセージの削除に失敗しました", + "saveOrderFailed": "順序の保存に失敗しました", + "created": "クイックメッセージを作成しました", + "saved": "クイックメッセージを保存しました", + "deleted": "クイックメッセージを削除しました" + } + }, + "Pet": { + "badge": { + "running": "実行中 {count} 件", + "waiting": "承認待ち {count} 件", + "error": "エラー {count} 件" + }, + "panel": { + "title": "アクティブなセッション", + "empty": "アクティブなセッションはありません", + "emptyHint": "実行中、または対応が必要なセッションがここに表示されます。", + "statusRunning": "実行中", + "statusWaiting": "待機中", + "statusError": "エラー", + "subAgentOf": "サブエージェント" + }, + "menu": { + "scale": "拡大率", + "openManager": "ペット管理", + "close": "閉じる" + }, + "loadError": "ペットの読み込みに失敗", + "missingPetIdParam": "ペットが選択されていません", + "summonButton": "ペット", + "manager": { + "title": "デスクトップペット", + "description": "Codex 互換のスプライトシートで動く、デスクトップ常駐のお供。", + "addPet": "ペットを追加", + "importFromCodex": "Codex から取り込む", + "noPets": "ペットがありません。追加するか、Codex から取り込んでください。", + "setActive": "アクティブにする", + "active": "アクティブ", + "edit": "編集", + "delete": "削除", + "deleteConfirm": "ペット「{name}」を削除しますか?ディスクからも削除されます。", + "summon": "ペットウィンドウを呼び出す", + "openCodexHelp": "Codex ペットは ~/.codex/pets/ 配下に配置する必要があります。見つかりません。", + "specRequirement": "スプライトシートは幅 1536 ピクセル、高さは 208 ピクセルの倍数(例: 1872 または 2288)で、透過 PNG / WebP 形式である必要があります。", + "form": { + "id": "ペット ID", + "idHelp": "英小文字、数字、'-'、'_' のみ。最大 64 文字。", + "displayName": "表示名", + "description": "説明 (任意)", + "spritesheet": "スプライトシート", + "chooseFile": "ファイルを選択", + "replaceFile": "スプライトを差し替え", + "saveCreate": "ペットを追加", + "saveUpdate": "変更を保存", + "cancel": "キャンセル" + }, + "errors": { + "missingId": "ペット ID は必須です", + "missingName": "表示名は必須です", + "missingSpritesheet": "スプライトシートは必須です", + "addFailed": "ペットの追加に失敗しました", + "updateFailed": "ペットの更新に失敗しました", + "deleteFailed": "ペットの削除に失敗しました", + "loadFailed": "ペット一覧の取得に失敗しました", + "setActiveFailed": "アクティブなペットの設定に失敗しました", + "summonFailed": "ペットウィンドウの召喚に失敗しました" + } + }, + "import": { + "title": "Codex から取り込む", + "subtitle": "~/.codex/pets/ 配下に見つかったペット一覧。", + "selectAll": "すべて選択", + "alreadyImported": "取り込み済み", + "renameOnConflict": "ID が重複した場合は -imported を付与", + "import": "選択したものを取り込む", + "noneFound": "取り込み可能な Codex ペットが見つかりません。", + "imported": "取り込みに成功", + "failed": "取り込みに失敗", + "close": "閉じる" + }, + "marketplace": { + "openMarketplace": "ペットマーケット", + "title": "ペットマーケット", + "search": "ペットを検索", + "kindFilter": { + "all": "すべて", + "object": "オブジェクト", + "animal": "動物", + "person": "人物", + "creature": "生き物" + }, + "sortFilter": { + "latest": "新着", + "popular": "人気", + "views": "閲覧数順" + }, + "refresh": "更新", + "install": "インストール", + "installing": "インストール中", + "reinstall": "再インストール", + "reinstallConfirm": "ローカルのペット \"{name}\" を上書きしますか?既存のデータは置き換えられます。", + "cancel": "キャンセル", + "stats": { + "views": "閲覧", + "downloads": "ダウンロード", + "likes": "いいね" + }, + "actions": { + "idle": "待機", + "running_right": "右走り", + "running_left": "左走り", + "waving": "手振り", + "jumping": "ジャンプ", + "failed": "失敗", + "waiting": "待ち", + "running": "実行", + "review": "レビュー" + }, + "page": "{page} / {total} ページ", + "prev": "前へ", + "next": "次へ", + "empty": "条件に一致するペットがありません。", + "successInstalled": "\"{name}\" をインストールしました", + "errors": { + "loadFailed": "マーケットの読み込みに失敗しました", + "installFailed": "インストールに失敗しました", + "alreadyInstalled": "そのペットは既に存在します" + } + } + }, + "RemoteWorkspace": { + "openRemoteWorkspace": "Open remote workspace", + "manage": "Manage remote workspace", + "manageTitle": "Remote Workspace connections", + "empty": "No remote connections", + "searchPlaceholder": "Search remote workspaces", + "orderFailed": "Failed to save remote workspace order", + "dragSort": "Drag to sort", + "dragSortConnection": "Drag to sort {name}", + "newConnection": "New connection", + "loading": "Loading", + "loadingConnection": "Loading remote connection", + "name": "Name", + "baseUrl": "Service URL", + "token": "Access token", + "save": "Save", + "delete": "Delete", + "confirmDelete": { + "title": "Delete remote connection?", + "message": "This will remove \"{name}\" from this device. This action cannot be undone.", + "cancel": "Cancel", + "confirm": "Delete" + }, + "saved": "Remote connection saved.", + "deleted": "Remote connection deleted.", + "loadFailed": "Failed to load remote connections", + "saveFailed": "Failed to save remote connection", + "deleteFailed": "Failed to delete remote connection", + "openFailed": "Failed to open remote workspace", + "connectionLoadFailed": "Failed to load remote connection: {message}", + "connectionExpired": "Remote connection \"{name}\" is expired. Update its token and reload this window." + }, + "ServerFileBrowser": { + "title": "サーバーファイルを選択", + "pathPlaceholder": "ディレクトリパスを入力...", + "goHome": "ホームディレクトリへ", + "navigateUp": "上の階層へ", + "select": "選択", + "cancel": "キャンセル", + "loading": "読み込み中...", + "emptyDirectory": "このディレクトリは空です", + "errorLoadingDir": "ディレクトリの読み込みに失敗しました", + "selectedCount": "{count} 件選択中" + }, + "BackupSettings": { + "title": "バックアップと復元", + "description": "codeg データのポータブルなバックアップを書き出すか、バックアップから復元します。", + "tabs": { + "backup": "バックアップ", + "restore": "復元" + }, + "export": { + "includeExternal": "会話内容を含める", + "includeExternalHint": "各 CLI の会話履歴(Claude、Codex、Gemini など)も保存します。サイズが増えます。", + "passphrase": "パスフレーズ(任意)", + "passphrasePlaceholder": "空欄の場合は暗号化されません", + "passphraseConfirm": "パスフレーズの確認", + "passphraseMismatch": "パスフレーズが一致しません。", + "noPassphraseWarning": "このバックアップには秘密情報(API キー、トークン)が平文で含まれます。安全に保管してください。", + "passphraseLossWarning": "このパスフレーズで暗号化します。紛失するとバックアップは復元できません。", + "button": "バックアップを書き出す", + "inProgress": "バックアップを作成中…", + "success": "バックアップを作成しました。", + "started": "バックアップのダウンロードを開始しました。" + }, + "restore": { + "selectFile": "バックアップファイルを選択", + "passphrasePrompt": "このバックアップは暗号化されています。パスフレーズを入力してください。", + "unlock": "ロック解除", + "preview": { + "title": "バックアップの詳細", + "encrypted": "暗号化済み", + "compatible": "互換あり", + "incompatible": "互換なし", + "createdAt": "作成日時: {value}", + "appVersion": "アプリのバージョン: {value}", + "incompatibleHint": "このバックアップは新しいバージョンの codeg で作成されており、復元できません。" + }, + "replaceWarning": "復元すると現在の codeg データ(データベースとアップロード)がすべて置き換えられます。現在のデータは先にスナップショットされ、復旧できます。", + "keyringNote": "デスクトップの GitHub/チャットのトークンは OS のキーチェーンに保存され、含まれません。復元後に再入力してください。", + "button": "復元", + "staging": "復元を準備中…", + "staged": "復元を準備しました。再起動します…", + "restarting": "復元を準備しました。サーバーを再起動します…", + "restartTimeout": "サーバーが時間内に復帰しませんでした。起動後にページを再読み込みしてください。", + "externalSideLocation": "会話履歴を {path} に復元しました", + "confirmTitle": "すべてのデータを置き換えますか?", + "confirmBody": "現在の codeg データベースとアップロードをバックアップで置き換えてから再起動します。現在のデータは先にスナップショットされます。", + "cancel": "キャンセル", + "confirmAction": "置き換えて再起動", + "external": { + "title": "会話内容", + "hint": "このバックアップには CLI の会話履歴が含まれます。復元先を選択してください。", + "modeSkip": "復元しない", + "modeSide": "安全な別フォルダーに復元", + "modeOriginal": "CLI の元の場所に復元", + "forceOverwrite": "既存のファイルを上書き", + "forceOverwriteHint": "CLI フォルダー内の既存ファイルを置き換えます。", + "scanning": "競合を確認中…", + "noConflicts": "既存のファイルは上書きされません。", + "conflictCount": "既存のファイル {count} 件が影響を受けます。", + "conflictSkipNote": "上書きを有効にしない限り、既存ファイルは保持(スキップ)されます。" + }, + "restartFailed": "復元は準備できましたが、サーバーを再起動できませんでした。手動で再起動して復元を適用してください。" + }, + "remoteUnsupported": "バックアップと復元は codeg を実行しているマシンのデータを対象とします。現在リモートワークスペースに接続中です。そのサーバー上で直接バックアップを管理してください。" + }, + "backup": { + "restore": { + "error": { + "badPassphrase": "パスフレーズが正しくないか、バックアップが破損しています。", + "corrupted": "バックアップアーカイブが破損しています。", + "unknownFormat": "このファイルは認識可能な codeg バックアップではありません。", + "newerVersion": "このバックアップは codeg {backupVersion} で作成されており、現在のバージョン({appVersion})より新しいです。", + "alreadyPending": "適用待ちの復元が既にあります。先に再起動して適用してから、新しい復元を準備してください。" + } + }, + "error": { + "diskSpace": "操作を完了するためのディスク容量が足りません。", + "cancelled": "操作はキャンセルされました。" + } + }, + "WebConnection": { + "disconnectedTitle": "接続が切断されました", + "reconnectingDescription": "サーバーへの再接続を試みています。通常は数秒で自動的に復旧します。", + "reconnectNow": "今すぐ再接続", + "sessionExpiredTitle": "セッションの有効期限が切れました", + "sessionExpiredDescription": "セッションが無効になりました。続行するには再度サインインしてください。", + "goToLogin": "ログインへ移動" + }, + "LiveFeedback": { + "placeholder": "{agent} の作業中にメモを送る…", + "agentFallback": "エージェント", + "ariaLabel": "ライブフィードバックのメモ", + "dialogTitle": "ライブフィードバック", + "dialogDescription": "エージェントの作業中にメモを送ります。現在のステップを中断せず、次の確認時に読み取られます。", + "dialogDescriptionInstant": "作業中のエージェントにメモを送ります。メモは現在のターンに即座に挿入され、エージェントはすぐに確認できます。", + "channelDowngraded": "このセッションでは即時挿入を利用できません。メモは保存され、エージェントが次回チェックする際に読み取られます。", + "send": "送信", + "cancel": "キャンセル", + "pending": "待機中", + "delivered": "受領済み", + "turnEndedUnread": "エージェントはフィードバックを読む前にターンを終了しました。", + "sendAsMessage": "新しいメッセージとして送信", + "dismiss": "閉じる", + "turnEndedResent": "ターンが終了したため、新しいメッセージとして送信しました。", + "turnEnded": "ターンはすでに終了しています。", + "submitFailed": "メモを送信できませんでした" + }, + "AgentToolsSettings": { + "title": "会話内ツール", + "description": "codeg が会話の中でエージェントに追加で渡すツールです。エージェントの起動時に注入されるため、変更は以降に起動したエージェントに適用されます。", + "feedbackLabel": "ライブフィードバック", + "feedbackHint": "作業中のエージェントにメモや修正を送れます。即時ステアリングに対応したエージェントでは、メモは実行中のターンへ即座に挿入されます。それ以外のエージェントはフィードバック確認ツールで読み取りますが、通常はプロンプトで言及した場合にのみ確認します。例:「ライブフィードバックを定期的に確認して」とメッセージに追加してください。", + "questionLabel": "ユーザーに質問", + "questionHint": "エージェントが処理を一時停止し、会話の入力欄の上に表示される選択式の質問をできるようにします。回答(またはスキップ)するまでエージェントは待機します。", + "sessionInfoLabel": "セッション情報の取得", + "sessionInfoHint": "メッセージ内で参照したセッション(セッションバッジ)をエージェントが照会し、タイトル・エージェント・ステータス・ワークスペース・トークン使用量・最近のメッセージを読み取れるようにします。", + "automationsLabel": "自動化を作成", + "automationsHint": "会話をスケジュール実行の自動化として保存します。既定はオフ — 自動化はその後、自分でエージェントを起動します。", + "workTasksLabel": "ToDo タスクを作成", + "workTasksHint": "会話から ToDo ボードにカードを追加します。既定はオフ — アプリの状態を書き換えます。", + "save": "保存", + "saving": "保存中…", + "saved": "ツール設定を保存しました", + "saveFailed": "ツール設定の保存に失敗しました", + "loadFailed": "読み込みに失敗しました: {detail}" + }, + "NotificationSoundSettings": { + "title": "通知音", + "description": "エージェントのイベント発生時に短い通知音を鳴らします。対象はチャットチャンネルに送られるものと同じイベントで、この設定はこの端末にのみ適用されます。", + "enableHint": "既定ではオフです。通知音はこのブラウザまたはアプリのワークスペースウィンドウでのみ再生されます。", + "volume": "音量", + "preview": "試聴", + "previewEvent": "「{event}」の通知音を試聴", + "onlyWhenUnfocused": "ウィンドウが非アクティブなときのみ再生", + "onlyWhenUnfocusedHint": "Codeg を表示している間は鳴らしません。", + "eventsTitle": "イベント", + "eventsHint": "イベントごとに音を選びます。「なし」を選ぶと鳴りません。同じイベントが数秒以内に繰り返された場合は 1 回だけ再生されます。", + "toneNone": "なし", + "toneChime": "チャイム", + "toneDing": "ベル", + "toneBlip": "ブリップ", + "tonePop": "ポップ", + "toneAlert": "アラート", + "toneDescend": "下降音" + }, + "LogsSettings": { + "loading": "読み込み中…", + "sectionTitle": "実行ログ", + "sectionDescription": "アプリケーションの診断ログを表示・設定します。ログはローカルファイルに書き込まれ、ライブ表示のためメモリにも保持されます。", + "captureTitle": "ログレベル", + "captureDescription": "記録する詳細度を制御します。レベルが高い(Debug、Trace)ほど多く記録されますが、ログも大きくなります。「オフ」でログ記録を無効にします。", + "captureLabel": "取得レベル", + "levels": { + "off": "オフ", + "error": "エラー", + "warn": "警告", + "info": "情報", + "debug": "デバッグ", + "trace": "トレース" + }, + "viewerTitle": "最近のログ", + "viewerDescription": "最近のログレコードをライブ表示します。レベルで絞り込みやテキスト検索ができます。", + "searchPlaceholder": "メッセージまたはターゲットを検索…", + "viewLevels": { + "all": "すべてのレベル", + "error": "エラー以上", + "warn": "警告以上", + "info": "情報以上", + "debug": "デバッグ以上", + "trace": "トレース以上" + }, + "pause": "一時停止", + "resume": "ライブ", + "refresh": "更新", + "clear": "クリア", + "openFolder": "フォルダーを開く", + "shownCount": "{shown} / {total} 件表示", + "empty": "表示するログがありません。", + "levelSaveFailed": "ログレベルの保存に失敗しました", + "openFolderFailed": "ログフォルダーを開けませんでした", + "downloadFailed": "ログファイルのダウンロードに失敗しました", + "filesTitle": "ログファイル", + "filesDescription": "ライブバッファを超える履歴のために、ディスクから完全なログファイルをダウンロードします。", + "filesEmpty": "ログファイルはまだありません。", + "download": "ダウンロード", + "downloadTruncated": "ファイルが大きいため、最新の {size} をダウンロードしました。完全なファイルはログディレクトリにあります。", + "captureEnvLocked": "ログレベルは RUST_LOG / CODEG_LOG 環境変数で制御されています。変更はそちらで行ってください。", + "targetsTitle": "モジュール別オーバーライド", + "targetsDescription": "グローバルレベルを変えずに、特定モジュール(例: codeg_lib::acp)のレベルを個別に設定します。", + "targetsAdd": "追加", + "targetsRemove": "オーバーライドを削除", + "toggleDetails": "詳細を切り替え" + }, + "Automations": { + "title": "オートメーション", + "new": "新規オートメーション", + "empty": "オートメーションはまだありません", + "emptyHint": "作成すると、エージェントのタスクをスケジュールまたは手動で実行できます。", + "name": "名前", + "namePlaceholder": "例:夜間の PR レビュー", + "prompt": "プロンプト", + "promptPlaceholder": "エージェントに何をさせますか?", + "agent": "エージェント", + "folder": "ワークスペースフォルダ", + "folderPlaceholder": "フォルダを選択", + "isolation": "分離", + "isolationWorktree": "実行ごとに新しい worktree", + "isolationShared": "フォルダ内で実行", + "isolationSharedCaveat": "実行はこのフォルダーの作業ツリーを直接使用するため、コミットしていない変更と競合する可能性があります。実行ごとに分離するにはワークツリーのオプションを有効にしてください。", + "trigger": "トリガー", + "triggerSchedule": "スケジュール", + "triggerManual": "手動のみ", + "cron": "スケジュール(cron)", + "cronPlaceholder": "0 9 * * 1-5", + "timezone": "タイムゾーン", + "nextRun": "次回実行", + "branch": "ブランチ", + "branchOptional": "ブランチ(任意)", + "enabled": "有効", + "save": "保存", + "cancel": "キャンセル", + "edit": "編集", + "delete": "削除", + "runNow": "今すぐ実行", + "cancelRun": "実行をキャンセル", + "runHistory": "実行履歴", + "noRuns": "実行履歴はまだありません", + "allFolders": "すべてのフォルダ", + "filterAll": "すべて", + "noMatches": "一致する自動化はありません", + "viewConversation": "会話を表示", + "lastRun": "前回の実行", + "never": "なし", + "running": "実行中", + "deleteTitle": "このオートメーションを削除しますか?", + "deleteDescription": "オートメーションとそのスケジュールを削除します。実行履歴は保持されます。", + "statusRunning": "実行中", + "statusSucceeded": "成功", + "statusFailed": "失敗", + "statusCancelled": "キャンセル", + "statusSkipped": "スキップ", + "errorName": "名前は必須です", + "errorPrompt": "プロンプトは必須です", + "errorCron": "スケジュール実行には cron 式が必要です", + "errorFolder": "ワークスペースフォルダを選択してください", + "presetHourly": "毎時", + "presetDaily": "毎日 9 時", + "presetWeekdays": "平日 9 時", + "presetCustom": "カスタム", + "probing": "オプションを読み込み中…", + "retry": "再試行", + "configNone": "このエージェントに設定可能な項目はありません", + "inherit": "エージェント既定", + "mode": "モード", + "config": "設定", + "branchPlaceholder": "(既定のブランチ)", + "selectHint": "詳細を表示する自動化を選択してください", + "refresh": "更新", + "onboardTitle": "定型のエージェント作業を自動化", + "onboardHint": "コードのレビュー、依存関係の更新、課題のトリアージを、定期実行またはオンデマンドでエージェントに実行させます。", + "headerSubtitle": "スケジュール実行とオンデマンドのエージェント作業", + "startFromTemplate": "テンプレートから始める", + "blankTitle": "空の自動化", + "blankDesc": "エージェント作業を一から設定します。", + "backToTemplates": "テンプレート", + "sectionSchedule": "スケジュールと対象", + "sectionTarget": "ターゲット", + "sectionAction": "アクション", + "actionLaunchSession": "セッションを起動", + "actionEnqueueTask": "タスクをキューに追加", + "actionEnqueueTaskHint": "実行のたびに、このオートメーション名を冠した ToDo タスクが対象フォルダの ToDo タスクに追加され、タスクエンジンがボードの設定に従って実行します。", + "sectionPrompt": "プロンプト", + "nextIn": "{rel}後に実行", + "manual": "手動", + "schedEveryMinutes": "{n}分ごと", + "schedHourly": "1時間ごと", + "schedDaily": "毎日 {time}", + "schedWeekdays": "平日 {time}", + "schedWeekly": "毎週{day} {time}", + "schedMonthly": "毎月 {day} 日 {time}", + "dow0": "日曜日", + "dow1": "月曜日", + "dow2": "火曜日", + "dow3": "水曜日", + "dow4": "木曜日", + "dow5": "金曜日", + "dow6": "土曜日", + "tplCodeReviewTitle": "コードレビュー", + "tplCodeReviewDesc": "最近の変更をレビューし、バグ・リグレッション・品質の問題を洗い出します。", + "tplDependencyUpdatesTitle": "依存関係の更新", + "tplDependencyUpdatesDesc": "古くなった依存関係を見つけ、安全なアップグレードを提案します。", + "tplTestCoverageTitle": "テストカバレッジ", + "tplTestCoverageDesc": "テストされていないコードパスを見つけ、不足しているテストを追加します。", + "tplTodoSweepTitle": "TODO 整理", + "tplTodoSweepDesc": "TODO と FIXME のコメントを集め、優先度ごとに整理します。", + "tplCiTriageTitle": "CI トリアージ", + "tplCiTriageDesc": "最近失敗したチェックを調査し、修正を提案します。", + "tplReleaseNotesTitle": "リリースノート", + "tplReleaseNotesDesc": "前回のリリース以降の変更をまとめ、変更履歴を作成します。", + "tplSecurityAuditTitle": "セキュリティ監査", + "tplSecurityAuditDesc": "脆弱性やリスクのあるパターンをスキャンし、結果を報告します。", + "enable": "有効化", + "disable": "無効化", + "moreActions": "その他の操作", + "statusDisabled": "無効", + "cronBuilderTitle": "スケジュールビルダー", + "cronFreqLabel": "頻度", + "cronFreqMinutes": "N 分ごと", + "cronFreqHourly": "毎時", + "cronFreqDaily": "毎日", + "cronFreqWeekdays": "平日", + "cronFreqWeekly": "毎週", + "cronFreqMonthly": "毎月", + "cronFreqCustom": "カスタム", + "cronEveryLabel": "間隔(分)", + "cronTimeLabel": "時刻", + "cronHourLabel": "時", + "cronMinuteLabel": "分", + "cronDowLabel": "曜日", + "cronDomLabel": "日", + "cronApply": "適用", + "cronPreviewLabel": "プレビュー", + "cronOpenBuilder": "スケジュールビルダーを開く", + "branchDefault": "デフォルトブランチ", + "branchUseCustom": "「{query}」を使用", + "branchLocal": "ローカル", + "branchRemote": "リモート", + "branchSearchPlaceholder": "ブランチを検索…", + "branchNone": "ブランチがありません" + }, + "Tasks": { + "title": "ToDo タスク", + "new": "新規タスク", + "empty": "タスクはまだありません", + "emptyHint": "ToDo を追加して実行すると、エージェントが独立した worktree で作業し、結果をレビューしてマージできます。", + "emptyColTodo": "ToDoはまだありません", + "emptyColInProgress": "進行中のタスクはありません", + "emptyColAttention": "対応が必要なタスクはありません", + "emptyColDone": "完了したタスクはまだありません", + "allFolders": "すべてのフォルダ", + "showCanceled": "キャンセル済みを表示", + "showArchived": "アーカイブを表示", + "filter": "フィルター", + "viewSwitchToBoard": "ボード表示に切り替え", + "viewSwitchToList": "リスト表示に切り替え", + "statusFilter": "ステータス", + "statusFilterAll": "すべてのステータス", + "listEmpty": "現在の絞り込み条件に一致するタスクはありません", + "listColStatus": "ステータス", + "listColTask": "タスク", + "listColLocation": "場所", + "listColChanges": "変更", + "listColUpdated": "更新", + "colTodo": "ToDo", + "colInProgress": "進行中", + "colAttention": "要対応", + "colDone": "完了", + "statusTodo": "ToDo", + "statusQueued": "待機中", + "statusPreparing": "準備中", + "statusRunning": "実行中", + "statusAwaitingInput": "入力待ち", + "statusReview": "レビュー待ち", + "statusMerging": "マージ中", + "statusDone": "完了", + "statusFailed": "失敗", + "statusCanceled": "キャンセル済み", + "statusInterrupted": "中断", + "badgeCleanupFailed": "クリーンアップ失敗", + "badgeWorktreeKept": "worktree 保持", + "badgeWorktreeRemoved": "worktree 削除済み", + "filesChanged": "{count} ファイル", + "actionStart": "開始", + "actionSchedule": "予約実行", + "actionCancel": "キャンセル", + "actionRetry": "再試行", + "actionRequeue": "再キュー", + "actionViewSession": "会話を表示", + "actionEdit": "編集", + "actionDelete": "削除", + "actionRetryCleanup": "クリーンアップを再試行", + "actionMerge": "マージ", + "actionUnqueueMerge": "マージ待ちを取り消す", + "actionEditQueuedMerge": "待機中のマージを編集", + "badgeMergeQueued": "マージ待ち", + "badgeMergeQueuedRank": "マージ待ち · {rank} 番目", + "badgeMergeQueuedHint": "このプロジェクトの実行中のマージが終わるのを待っています。順番が来ると自動的に開始します。", + "actionComplete": "完了", + "actionAbandon": "破棄", + "cancelTitle": "タスクをキャンセルしますか?", + "cancelDescription": "タスクは「キャンセル済み」になります。worktree は保持され、あとで再キューできます。", + "cancelReasonLabel": "キャンセルの理由(任意)", + "cancelReasonPlaceholder": "例:方針が違うので説明を書き直す", + "cancelKeep": "やめておく", + "cancelSubmit": "タスクをキャンセル", + "restartTitleRetry": "タスクを再試行", + "restartTitleRequeue": "タスクを再キュー", + "restartDescription": "補足(任意)を書けます。次の実行のプロンプトに含めて agent に渡されます。", + "scheduleTitle": "タスクの実行を予約", + "scheduleDescription": "タスクは ToDo のまま、指定した時刻に自動で開始します。フォルダーの同時実行数の上限は引き続き適用されます。", + "scheduleDateLabel": "日付", + "schedulePickDate": "日付を選択", + "scheduleTimeLabel": "時刻", + "schedulePreview": "{time} に実行", + "schedulePastHint": "指定した時刻は過ぎています。保存するとすぐに開始します。", + "scheduleInAnHour": "1 時間後", + "scheduleInThreeHours": "3 時間後", + "scheduleTomorrow": "明日 9:00", + "scheduleClear": "予約を解除", + "scheduleBadge": "{time} に開始予定", + "toastScheduled": "{time} に予約しました", + "toastScheduleCleared": "予約を解除しました", + "actionFollowUp": "追加指示", + "actionAddNote": "補足を追加", + "followUpSubmit": "送信", + "followUpIntentRevise": "修正を依頼", + "followUpIntentContinue": "作業を続ける", + "followUpIntentQuestion": "質問する", + "followUpIntentVerify": "セルフチェック", + "followUpPlaceholderRevise": "どこを直してほしいですか?同じセッションで続けます。", + "followUpPlaceholderContinue": "次に何をしますか?これまでの作業はそのまま残ります。", + "followUpPlaceholderQuestion": "何を知りたいですか?ファイルには一切手を加えず回答します。", + "followUpPlaceholderVerify": "任意:重点的に確認してほしい点はありますか?", + "followUpPlaceholderRetry": "任意:今回はどう変えますか?例:先に pnpm install を実行", + "followUpPlaceholderRequeue": "任意:なぜ中止したのか、今回は何を変えるかを書いてください。", + "actionArchive": "アーカイブ", + "actionUnarchive": "アーカイブ解除", + "archiveAllDone": "すべてアーカイブ", + "dropToStart": "離すと実行を開始", + "errorView": "表示", + "notifyReview": "レビュー待ち: {title}", + "notifyFailed": "タスクが失敗しました: {title}", + "createFromMessage": "このメッセージからタスクを作成", + "detailTokens": "合計トークン", + "editorTitleNew": "新規タスク", + "editorTitleEdit": "タスクを編集", + "templates": "テンプレート", + "templatesEmpty": "テンプレートはまだありません。", + "templateSaveCurrent": "現在の内容をテンプレートとして保存", + "templateDelete": "テンプレートを削除", + "transcriptTitle": "タスクの会話", + "transcriptDescription": "タスクのエージェントセッションの読み取り専用ライブビュー。", + "phaseWork": "タスク実行", + "phaseRetry": "再実行", + "phaseReturn": "追加指示", + "phaseMerge": "マージ", + "titleLabel": "タイトル", + "titlePlaceholder": "何をしますか?", + "promptLabel": "タスクの説明", + "promptPlaceholder": "エージェントへの指示を記述 — @ でファイル参照、/ でコマンド", + "folderPlaceholder": "フォルダを選択", + "agentInheritedHint": "タスク設定から継承 — 変更するとこのタスク専用になります", + "agentOverrideReset": "継承に戻す", + "sectionTarget": "ターゲット", + "errorTitle": "タイトルを入力してください", + "errorPrompt": "タスクの説明を入力してください", + "errorFolder": "フォルダを選択してください", + "save": "保存", + "cancel": "キャンセル", + "mergeTitle": "タスクをマージ", + "mergeQueuedTitle": "待機中のマージ", + "mergeQueueHint": "このプロジェクトでは別のタスクをマージ中です。このタスクは待機列に入り、前のマージが終わり次第自動的に開始します。", + "mergeQueueUpdateHint": "このタスクはすでにマージ待ちです。送信すると内容だけが更新され、待機列の順番はそのままです。", + "mergeDescription": "{branch} を {base} にマージします。worktree の未コミット変更は先にコミットされます。", + "mergeMessage": "コミットメッセージ", + "mergeMessagePlaceholder": "例: feat: add login validation", + "mergeAutoMessage": "コミットメッセージをエージェントに生成させる", + "strategySquash": "1つのコミットにまとめる", + "strategySquashHint": "タスクのすべての変更が1件の履歴としてメインブランチに取り込まれ、履歴がすっきりします。", + "strategyMerge": "履歴をすべて残す", + "strategyMergeHint": "タスク中の各コミットをそのまま残し、マージの記録を1件追加します。各ステップを追跡できます。", + "mergeDeleteWorktree": "マージ後に worktree を削除", + "mergeSubmit": "マージ", + "mergeSubmitQueue": "マージ待ちに追加", + "mergeQueuedToast": "マージ待ちに追加しました。実行中のマージが終わり次第開始します。", + "completeTitle": "タスクを完了", + "completeDescription": "このタスクはファイルを変更していないため、マージするものはありません。そのまま完了にします。", + "completeDescriptionNoWorktree": "このタスクの worktree は削除されているため、マージできません。そのまま完了にします。未マージのコミットが残る作業ブランチは保持されます。", + "completeDeleteWorktree": "完了後に worktree を削除", + "completeSubmit": "完了", + "settingsTitle": "タスク設定", + "settingsDescription": "{folder} のタスクの既定値。", + "settingsScope": "適用範囲", + "settingsScopeGlobal": "すべてのフォルダ(グローバル既定)", + "settingsScopeGlobalHint": "個別設定のないフォルダはこのグローバル既定を使います。", + "settingsSource": "設定ソース", + "settingsSourceGlobal": "グローバル既定", + "settingsSourceCustom": "個別設定", + "settingsSourceGlobalFollow": "グローバルのタスク設定に従います。グローバル側の変更が自動的に反映されます。", + "settingsSourceCustomHint": "このフォルダ専用の設定を保存し、グローバル既定には従わなくなります。", + "settingsAgent": "既定のエージェント", + "settingsMaxConcurrent": "最大同時実行数", + "settingsMaxConcurrentHint": "0 = 無制限", + "settingsAutoProcess": "自動処理", + "settingsAutoProcessHint": "ToDo タスクを自動的に開始します(同時実行数の上限まで)。", + "settingsMergeStrategy": "既定のマージ戦略", + "settingsMergeStrategyHint": "マージ時にタスクの変更をブランチ履歴へどう記録するか。", + "settingsAutoMerge": "自動マージ", + "settingsAutoMergeHint": "レビュー待ちに達しマージできる変更があるタスクは、「マージ」を押したときと同じように自動で取り込まれます。コミットメッセージはエージェントが生成し、worktree の扱いは下の既定に従います。プリフライトが赤のタスクやマージに失敗したタスクはそのまま残ります。", + "settingsDeleteWorktree": "マージ後に worktree を削除", + "settingsDeleteWorktreeHint": "マージ画面で既定でオンになります。その場で変更もできます。", + "settingsWorktreeRoot": "Worktree の作成先", + "settingsWorktreeRootHint": "新しいタスクの worktree をこのディレクトリ配下にタスクごとに作成します。空欄ならプロジェクトフォルダーと同じ階層に作成されます。「~」はホームディレクトリ、相対パスはプロジェクトフォルダー基準です。", + "settingsWorktreeRootPlaceholder": "~/codeg-worktrees", + "settingsWorktreeRootBrowse": "worktree のディレクトリを選択", + "settingsPreflight": "プリフライトコマンド", + "settingsPreflightHint": "タスクがレビューに達したときワークツリーで実行。", + "settingsPreflightCustomPlaceholder": "pnpm test", + "settingsInitCommand": "Worktree 初期化コマンド", + "settingsInitCommandHint": "worktree の新規作成後、エージェント開始前に実行されます。", + "settingsInitCommandPlaceholder": "pnpm install", + "settingsTabGeneral": "一般", + "settingsTabMerge": "マージ", + "settingsTabWorktree": "Worktree", + "settingsTabPrompts": "プロンプト", + "settingsPromptsIntro": "各ステージには既定のプロンプトが組み込まれています(タスク本体、ワークツリーのルール、マージ時は具体的な git 手順)。ここに書いた内容は補足指示として末尾に追加され、既定の内容を補うだけで置き換えることはありません。", + "settingsPromptStageAll": "全段階", + "settingsPromptPlaceholderAll": "例: AGENTS.md のプロジェクト規約に従う。最後のまとめは 2 文以内で", + "settingsPromptPlaceholderWork": "例: 関連するテストを先に読む。小さな単位でこまめにコミットする", + "settingsPromptPlaceholderRetry": "例: 続ける前に既にコミット済みの内容を確認し、完了済みの作業をやり直さない", + "settingsPromptPlaceholderReturn": "例:指摘された点を一つずつ対応する。無関係なリファクタリングはしない", + "settingsPromptPlaceholderMerge": "例: 取り込みコミットのメッセージは日本語で。手動で解決した衝突は明記する", + "settingsPromptHintAll": "マージ実行を含め、エージェントに渡すすべてのプロンプトに追加されます。", + "settingsPromptHintWork": "タスクを初めて実行するときに追加されます。", + "settingsPromptHintRetry": "中断または失敗したタスクを再開するときに追加されます。", + "settingsPromptHintReturn": "レビュー待ちのタスクに追加指示を出すとき(修正・追加作業・セルフチェック)に付加されます。", + "settingsPromptHintMerge": "エージェントがタスクをベースブランチに取り込むときに追加されます。", + "preflightPassed": "{name} 成功", + "preflightFailed": "{name} 失敗", + "preflightRunning": "{name} 実行中…", + "detailDescription": "タスク詳細", + "detailSummary": "結果", + "detailFiles": "変更ファイル", + "detailDiffAll": "差分をすべて表示", + "detailDiffAllTitle": "全差分", + "detailNoChanges": "ベースからの変更はまだありません", + "detailTimeline": "進行履歴", + "detailTimelineEmpty": "まだアクティビティがありません", + "showMore": "もっと見る", + "showLess": "折りたたむ", + "detailInfo": "詳細", + "detailBranch": "ブランチ", + "detailMergeCommit": "マージコミット", + "detailChanges": "変更", + "detailScheduled": "開始予定", + "detailCreated": "作成日時", + "detailStarted": "開始日時", + "detailFinished": "完了日時", + "diffLoading": "差分を読み込み中…", + "deleteConfirmTitle": "タスクを削除しますか?", + "deleteConfirmBody": "「{title}」をボードから削除します。実行中の場合は先にキャンセルされます。", + "deleteWithWorktree": "worktree も削除する", + "eventCreated": "作成", + "eventStatusChanged": "ステータス変更", + "eventConfigEffective": "起動構成", + "eventInitCommand": "初期化コマンド", + "eventAgentProgress": "エージェントの進捗", + "eventAgentVerdict": "エージェントの判定", + "eventMergeAttempt": "マージ開始", + "eventMergeQueued": "マージ待ちに追加", + "eventMergeConflict": "マージ競合", + "eventPreflight": "プリフライト", + "eventCleanupFailed": "worktree のクリーンアップに失敗", + "eventResumeFallback": "セッション再開に失敗し新規セッションへ", + "eventUserAction": "ユーザー操作", + "eventDiffStat": "変更スナップショット" + }, + "CustomSkillsSettings": { + "loading": "カスタムスキルを読み込み中…", + "category": "カスタム", + "searchPlaceholder": "名前・ID・説明でカスタムスキルを検索", + "states": { + "not_linked": "未有効", + "linked_to_codeg": "有効", + "linked_elsewhere": "別の場所にリンク", + "blocked_by_real_directory": "実在フォルダにより占有", + "broken": "リンク切れ" + }, + "actions": { + "new": "新規", + "import": "インポート", + "importFromAgent": "エージェントから取り込む", + "cancel": "キャンセル", + "save": "保存" + }, + "rowMenu": { + "edit": "編集", + "duplicate": "複製", + "delete": "削除" + }, + "bulk": { + "delete": "選択項目を削除" + }, + "editor": { + "createTitle": "カスタムスキルを新規作成", + "editTitle": "カスタムスキルを編集", + "description": "カスタムスキルは共有ストア(~/.codeg/skills)に保存され、任意のエージェントで有効化できます。", + "idLabel": "スキル ID", + "idPlaceholder": "例: my-workflow", + "contentLabel": "SKILL.md", + "contentPlaceholder": "ここにスキルの SKILL.md を記述…", + "preview": "プレビュー", + "edit": "編集", + "emptyBody": "まだ内容がありません。" + }, + "duplicate": { + "title": "スキルを複製", + "description": "「{id}」を元に、新しい ID でコピーを作成します。", + "newIdPlaceholder": "新しいスキル ID", + "confirm": "複製" + }, + "import": { + "title": "インポートするスキルフォルダを選択" + }, + "importFromAgent": { + "title": "エージェントからスキルを取り込む", + "description": "エージェント独自のスキルを共有ストアにコピーすると、どのエージェントでも有効化できます。", + "agentLabel": "エージェント", + "agentPlaceholder": "エージェントを選択", + "selectAll": "すべて選択({count})", + "loading": "エージェントのスキルを読み込み中…", + "unsupported": "このエージェントはスキルディレクトリを提供していません。", + "empty": "このエージェントに取り込めるスキルはありません。", + "alreadyInLibrary": "ライブラリ済み", + "confirm": "選択を取り込む({count})" + }, + "delete": { + "title": "カスタムスキルを削除しますか?", + "body": "{count} 個のカスタムスキルを中央ストアから削除し、すべてのエージェントからリンクを解除します。この操作は取り消せません。", + "confirm": "削除" + }, + "toasts": { + "loadFailed": "スキルの読み込みに失敗しました", + "idRequired": "スキル ID を入力してください", + "created": "カスタムスキルを作成しました", + "updated": "カスタムスキルを更新しました", + "saveFailed": "スキルの保存に失敗しました", + "imported": "スキルをインポートしました", + "importFailed": "スキルのインポートに失敗しました", + "duplicated": "スキルを複製しました", + "duplicateFailed": "スキルの複製に失敗しました", + "deleted": "{count} 個のスキルを削除しました", + "deletedPartial": "{ok} 個を削除、{failed} 個が失敗", + "deleteFailed": "スキルの削除に失敗しました", + "importedFromAgent": "{count} 件のスキルを取り込みました", + "importedFromAgentPartial": "{ok} 件を取り込み、{failed} 件が失敗しました", + "importFromAgentAllSkipped": "取り込み対象なし — {count} 件はすでにライブラリにあります", + "importFromAgentFailed": "エージェントからの取り込みに失敗しました" + } + }, + "CodexModelEditor": { + "customizedNotice": "モデル一覧をカスタマイズしたため、codeg が codex のモデル表全体を管理します。codex が今後追加する公式モデルは自動では表示されません。下の更新をクリックして保存し直すと同期できます。カスタマイズをすべて削除すると codex の自動更新に戻ります。", + "officialsTitle": "公式モデル", + "officialsHint": "起動する codex の公式モデルを自動的に含めます。不要なものは削除できます。", + "officialsEmpty": "利用可能な公式モデルがありません。", + "refresh": "codex から更新", + "readdOfficial": "公式を再追加", + "customsTitle": "カスタムモデル", + "customsEmpty": "カスタムモデルはまだありません。", + "addCustom": "カスタム追加", + "slugPlaceholder": "モデル ID(slug)", + "displayNamePlaceholder": "表示名", + "contextWindow": "コンテキスト", + "makeDefault": "デフォルトに設定", + "defaultHint": "デフォルトモデル", + "remove": "削除", + "advanced": "詳細", + "baseTemplate": "ベーステンプレート", + "baseTemplateHint": "必須フィールド(システムプロンプト、ツール、制限)を複製する公式モデル。", + "groupBehavior": "動作と機能", + "fieldReasoningLevel": "既定の推論レベル", + "fieldReasoningSummary": "推論サマリー", + "fieldVerbosity": "詳細度", + "fieldShellType": "シェルタイプ", + "fieldApplyPatch": "パッチ適用ツール", + "fieldReasoningSummaries": "推論サマリー対応", + "fieldSupportVerbosity": "詳細度の制御", + "fieldParallelToolCalls": "並列ツール呼び出し", + "fieldSearchTool": "Web 検索ツール", + "optNone": "なし", + "groupInstructions": "説明とシステムプロンプト", + "fieldDescription": "説明", + "baseInstructions": "システムプロンプト(base_instructions)" + }, + "DiagnosticsSettings": { + "title": "環境診断", + "description": "このアプリが自身のプロセス内でエージェントの CLI をどう解決するかを確認します(ターミナルとは異なる場合があります)。", + "loading": "診断を実行中…", + "error": "診断に失敗しました", + "rerun": "再実行", + "copyAll": "すべてコピー", + "copied": "診断情報をクリップボードにコピーしました", + "button": "診断", + "verdict": { + "ok": "環境は正常です。それでも未インストールと表示される場合は、アプリを完全に再起動してプレフィックスキャッシュを更新してください。", + "node_missing": "アプリの PATH に Node.js が見つかりませんでした。", + "npm_missing": "アプリの PATH に npm が見つかりませんでした。", + "not_installed": "このエージェントはインストールされていないようです。", + "installed_but_unresolved": "インストール済みと記録されていますが、アプリが実行ファイルを見つけられません。", + "user_prefix_not_on_path": "フォールバックのプレフィックス(~/.codeg/npm-global)にインストールされていますが、アプリの PATH に含まれていません。アプリを完全に再起動して再試行してください。", + "homebrew_bin_not_on_path": "Homebrew の bin にインストールされていますが、アプリの PATH に含まれていません(Apple Silicon の keg 分割)。", + "terminal_only_path": "このコマンドはターミナルでは解決されますが、アプリでは解決されません。GUI の PATH のずれです。ターミナルからアプリを起動するか、エージェント設定から再インストールしてください。", + "npm_prefix_timeout": "npm prefix -g が遅すぎました(1.5 秒超)。フォールバック検出をスキップしました。アプリを再起動して再試行してください。", + "node_too_old": "使用中の Node.js がこのエージェントの要件より古いです。Node.js をアップグレードしてください。", + "adapter_missing_native_present": "お使いの {agent} CLI は確かにインストールされていますが、Codeg が起動するのは別の ACP アダプターパッケージで、そちらが未インストールです。エージェント設定からインストールしてください。既存の CLI には触れず、ログインも共有されます。", + "adapter_missing": "Codeg は {agent} 用に別個の ACP アダプターパッケージを起動しますが、まだインストールされていません。エージェント設定からインストールしてください。ベンダー CLI を入れるだけでは足りません。" + } + }, + "TokenUsage": { + "title": "トークン使用量", + "rangeLabel": "期間", + "range7d": "7日間", + "range30d": "30日間", + "range90d": "90日間", + "rangeThisMonth": "今月", + "rangeThisYear": "今年", + "rangeAll": "全期間", + "rangeCustom": "カスタム", + "moreRanges": "その他", + "customRangePick": "期間を選択", + "bucketLabel": "集計単位", + "bucketDay": "日", + "bucketWeek": "週", + "bucketMonth": "月", + "bucketUnitDay": "日", + "bucketUnitWeek": "週", + "bucketUnitMonth": "月", + "folderFilter": "フォルダ", + "allFolders": "すべてのフォルダ", + "agentFilter": "エージェント", + "allAgents": "すべてのエージェント", + "modelFilter": "モデル", + "allModels": "すべてのモデル", + "searchPlaceholder": "検索…", + "noMatches": "該当なし", + "clearFilter": "選択をクリア", + "resetFilters": "フィルタをリセット", + "refresh": "更新", + "rebuild": "すべて再構築", + "rebuildHint": "集計済みデータを破棄し、すべてのセッション記録を読み直します。codeg 以外の CLI で追記された場合に使います。", + "syncing": "セッションを集計中…", + "syncProgress": "{done} / {total}", + "syncDone": "{synced} 件のセッションを集計しました", + "syncFailed": "一部のセッションを読み取れませんでした", + "syncBusy": "すでに更新が実行中です", + "lastSynced": "{time} に更新", + "lastSyncedNever": "未集計", + "tileTotal": "合計トークン", + "tileSessions": "セッション数", + "tileTurns": "ターン数", + "tileActiveDays": "稼働日数", + "tileGenTime": "生成時間", + "vsPrevious": "前期間との比較", + "deltaNew": "新規", + "trendTitle": "使用量の推移", + "trendEmpty": "この期間の使用量はありません", + "trendTurns": "ターン", + "trendSessions": "セッション", + "compositionTitle": "トークンの内訳", + "compositionHint": "入力は送った内容、出力はモデルが書いた内容、キャッシュ読み取りは再送せずに済んだコンテキストです。", + "compositionNote": "これらのキャッシュ命中を定価で再送すると、あと {value} かかっていました。", + "inputTokens": "入力", + "outputTokens": "出力", + "cacheWrite": "キャッシュ書き込み", + "cacheRead": "キャッシュ読み取り", + "freshTokens": "新規計算トークン", + "cacheHitCaption": "キャッシュ命中", + "cacheHeroTitleHigh": "コンテキストの大半は再送不要でした", + "cacheHeroTitleLow": "コンテキストの大半はまだ全額計算です", + "cacheHeroDesc": "{cached} のコンテキストはキャッシュが担い、この期間に実際に新規計算されたのは {fresh} だけです。", + "cacheSavedSuffix": "再送を {saved} 相当分節約できました。", + "avgPerSession": "セッション平均", + "avgTurnsPerSession": "1 セッションあたり平均 {count} ターン", + "avgPerActiveDay": "稼働日平均", + "peakBucket": "最も多い{bucket}", + "peakHour": "ピーク時間帯", + "daysValue": "{count} 日", + "idleDays": "空き日数", + "byFolderTitle": "フォルダー別", + "byAgentTitle": "エージェント別", + "byModelTitle": "モデル別", + "distributionTitle": "使用量の分布", + "distributionHint": "選択した軸でセッションとトークンを集計。行をクリックすると絞り込めます。", + "otherLabel": "その他", + "unknownModel": "モデル未記録", + "emptyBreakdown": "記録がありません", + "sessionsCount": "{count} セッション", + "heatmapTitle": "作業リズム", + "heatmapHint": "ローカル時間の曜日・時刻ごとのトークン量。", + "heatmapPeakHint": "最も集中しているのは {hour}:00 前後です。", + "less": "少", + "more": "多", + "heatmapCell": "{weekday} {hour}:00 — {value} トークン", + "weekMon": "月", + "weekTue": "火", + "weekWed": "水", + "weekThu": "木", + "weekFri": "金", + "weekSat": "土", + "weekSun": "日", + "topSessionsTitle": "消費の多いセッション", + "untitledSession": "名称未設定のセッション", + "topSessionsEmpty": "この期間にセッションはありません", + "streakLongest": "最長の連続日数", + "streakLongestDays": "最長連続 {count} 日", + "share": "共有", + "moreActions": "その他の操作", + "shareDialogTitle": "使用量カードを共有", + "shareDialogHint": "いま選んでいる期間とフィルタのスナップショットです。", + "shareSave": "画像を保存", + "shareCopy": "画像をコピー", + "shareCopied": "クリップボードにコピーしました", + "shareSaved": "画像を保存しました", + "shareFailed": "画像を生成できませんでした", + "shareRendering": "生成中…", + "cardHeading": "私の AI コーディング記録", + "cardRangeAll": "全期間", + "cardTotalLabel": "使用トークン", + "cardFooter": "codeg で作成", + "cardTopModels": "よく使うモデル", + "cardTopProjects": "主なプロジェクト", + "archetypeNightOwl": "夜型コーダー", + "archetypeNightOwlDesc": "トークンの {percent}% は日没後に使われています。", + "archetypeEarlyBird": "早起きタイプ", + "archetypeEarlyBirdDesc": "トークンの {percent}% は朝 9 時前に使われています。", + "archetypeWeekendWarrior": "週末戦士", + "archetypeWeekendWarriorDesc": "トークンの {percent}% は週末に使われています。", + "archetypeCacheMaster": "キャッシュの達人", + "archetypeCacheMasterDesc": "コンテキストの {percent}% がキャッシュ由来です。", + "archetypeMarathoner": "マラソンランナー", + "archetypeMarathonerDesc": "{days} 日連続で開発を続けました。", + "archetypePolyglot": "マルチプレイヤー", + "archetypePolyglotDesc": "{count} 個のエージェントを本格的に併用しています。", + "archetypeLaserFocus": "一点集中", + "archetypeLaserFocusDesc": "トークンの {percent}% を一つのプロジェクトに投じています。", + "archetypeDeepDiver": "深掘り型", + "archetypeDeepDiverDesc": "1 セッションあたり平均 {averageK}K トークン。", + "archetypeSteady": "安定型ビルダー", + "archetypeSteadyDesc": "のべ {days} 日開発しました。", + "emptyTitle": "集計データがまだありません", + "emptyHint": "codeg は各エージェント自身のセッション記録から直接トークン数を読み取ります。更新すると、このマシンにある記録を集計します。", + "emptyAction": "セッションを集計", + "loadFailed": "使用量を読み込めませんでした", + "truncatedNotice": "期間が非常に長いため、表示中の数値は直近の一部のみを対象としています。" + } +} diff --git a/src/i18n/messages/ko.json b/src/i18n/messages/ko.json index f8929f829..8aefc947b 100644 --- a/src/i18n/messages/ko.json +++ b/src/i18n/messages/ko.json @@ -1,4958 +1,4958 @@ -{ - "Language": { - "followSystem": "시스템 설정 따름", - "english": "영어", - "simplifiedChinese": "简体中文", - "traditionalChinese": "繁體中文", - "japanese": "일본어", - "korean": "한국어", - "spanish": "스페인어", - "german": "독일어", - "french": "프랑스어", - "portuguese": "포르투갈어", - "arabic": "아랍어" - }, - "GitCredentialDialog": { - "title": "인증 필요", - "description": "원격 서버에서 자격 증명을 요구합니다. 사용자 이름과 비밀번호(또는 개인 액세스 토큰)를 입력하세요.", - "username": "사용자 이름", - "usernamePlaceholder": "사용자 이름 또는 이메일", - "password": "비밀번호 / 토큰", - "passwordPlaceholder": "비밀번호 또는 개인 액세스 토큰", - "passwordHint": "서버의 사용자 이름과 비밀번호를 입력하세요.", - "cancel": "취소", - "authenticate": "인증", - "authenticating": "인증 중...", - "invalidCredentials": "자격 증명이 유효하지 않습니다. 다시 시도하세요.", - "saveCredentials": "향후 작업을 위해 자격 증명 저장", - "githubTitle": "GitHub 인증", - "githubDescription": "개인 액세스 토큰을 입력하여 GitHub에 연결합니다. 토큰 확인 후 계정에 자동으로 저장됩니다.", - "githubToken": "개인 액세스 토큰", - "githubTokenPlaceholder": "ghp_xxxxxxxxxxxx", - "githubTokenHint": "GitHub → Settings → Developer settings → Personal access tokens에서 토큰을 생성하세요.", - "githubAuthenticate": "확인 및 연결", - "generateToken": "토큰 생성" - }, - "SettingsShell": { - "title": "설정", - "preferences": "환경설정", - "nav": { - "general": "일반", - "appearance": "외관", - "agents": "에이전트", - "mcp": "MCP", - "skills": "Skills", - "shortcuts": "단축키", - "version_control": "버전 관리", - "system": "시스템", - "chat_channels": "채팅 채널", - "web_service": "웹 서비스", - "model_providers": "모델 제공업체", - "experts": "전문가", - "science": "과학 연구", - "office_tools": "오피스 도구", - "skill_packs": "스킬 팩", - "quick_messages": "빠른 메시지", - "logs": "실행 로그" - } - }, - "AppearanceSettings": { - "sectionTitle": "테마 모양", - "sectionDescription": "라이트, 다크 또는 시스템 설정을 선택할 수 있습니다. 설정은 자동으로 저장됩니다.", - "themeMode": "테마 모드", - "placeholder": "테마 모드 선택", - "system": "시스템 설정 따름", - "light": "라이트", - "dark": "다크", - "currentTheme": "현재 적용된 테마: {theme}", - "resolvedTheme": { - "light": "라이트", - "dark": "다크", - "unknown": "--" - }, - "themeColor": { - "sectionTitle": "테마 색상", - "sectionDescription": "버튼, 강조 색상, 하이라이트에 사용할 색상 팔레트를 선택하세요.", - "current": "현재 색상: {color}", - "options": { - "neutral": "Neutral", - "zinc": "Zinc", - "slate": "Slate", - "stone": "Stone", - "gray": "Gray", - "red": "Red", - "rose": "Rose", - "orange": "Orange", - "green": "Green", - "blue": "Blue", - "yellow": "Yellow", - "violet": "Violet" - } - }, - "customStyle": { - "sectionTitle": "사용자 지정 스타일", - "sectionDescription": "현재 테마의 색상을 미세 조정하거나 직접 작성한 CSS를 적용합니다. 재정의는 기본 프리셋 위에 얹히므로 프리셋을 바꿔도 유지됩니다.", - "summarySuspended": "일시 중지됨", - "summaryDefault": "프리셋 기본값", - "summaryTokens": "{count, plural, one {재정의 #개} other {재정의 #개}}", - "summaryCss": "사용자 지정 CSS", - "suspendedByShortcut": "사용자 지정 스타일이 일시 중지되었습니다. 다시 켜기 전까지 여기서 설정한 내용은 적용되지 않습니다.", - "suspendedBySafeParam": "이 창은 안전 외관 모드로 열려 사용자 지정 스타일이 적용되지 않습니다. 다른 창에는 영향이 없습니다.", - "resume": "사용자 지정 스타일 재개", - "enableTheme": "사용자 지정 색상 사용", - "editingLight": "라이트 모드 값을 편집하고 있습니다. 다크 모드로 전환하면 따로 설정할 수 있습니다.", - "editingDark": "다크 모드 값을 편집하고 있습니다. 라이트 모드로 전환하면 따로 설정할 수 있습니다.", - "resetToken": "프리셋 값으로 되돌리기", - "radius": "모서리 둥글기", - "radiusHint": "sm부터 4xl까지의 둥글기 척도 전체가 이 값에서 파생되므로 슬라이더 하나로 앱 전체가 바뀝니다.", - "advanced": "고급 (변수 {count}개 더)", - "enableCss": "사용자 지정 CSS 사용", - "cssRisk": "고급 기능입니다. 사용자 지정 CSS는 모든 기본 스타일을 덮어쓰므로 화면을 사용할 수 없게 만들 수 있습니다.", - "editCss": "CSS 편집…", - "cssPresent": "{size} KB 저장됨", - "cssEmpty": "아직 저장된 내용이 없습니다", - "escapeHint": "화면이 망가졌나요? {shortcut} 키로 모든 사용자 지정 스타일을 중지할 수 있고, safeStyle=1 쿼리 파라미터로 창을 열 수도 있습니다.", - "copyTheme": "테마 JSON 복사", - "importTheme": "테마 가져오기…", - "clearTheme": "재정의 지우기", - "interopHint": "테마는 shadcn의 registry:theme 형식을 사용합니다. 어떤 shadcn 테마든 붙여넣을 수 있고, 내보낸 테마는 모든 shadcn 프로젝트에서 쓸 수 있습니다.", - "importTitle": "테마 가져오기", - "importDescription": "shadcn의 registry:theme 항목, light/dark 객체, 또는 단층 토큰 맵을 붙여넣으세요.", - "readClipboard": "클립보드 읽기", - "importConfirm": "가져오기", - "cancel": "취소", - "apply": "적용", - "toasts": { - "copied": "테마 JSON을 복사했습니다", - "copyFailed": "클립보드에 복사하지 못했습니다", - "clipboardReadFailed": "클립보드를 읽지 못했습니다. 직접 붙여넣어 주세요", - "importFailed": "이 JSON에는 사용할 수 있는 테마 변수가 없습니다", - "imported": "테마를 가져왔습니다" - }, - "css": { - "dialogTitle": "사용자 지정 CSS", - "dialogDescription": "모든 codeg 창에 적용됩니다. 변경 사항은 실시간으로 미리 보이며 적용을 눌러야 저장됩니다.", - "size": "{used} KB / {max} KB", - "ruleCount": "규칙 {count}개", - "errorTooLarge": "너무 커서 저장할 수 없습니다. 상한 아래로 줄여 주세요.", - "errorImportEscaped": "제거 후에도 @import가 감지되었습니다(이스케이프 표기). 직접 삭제해 주세요.", - "warnNoRules": "해석된 규칙이 없습니다. 문법을 확인하세요.", - "noticeImportsRemoved": "@import 규칙 {count}개를 제거했습니다. 원격 스타일시트를 가져오기 때문입니다.", - "noticeRemoteUrl": "원격 url()이 포함되어 있어 적용 시 네트워크 요청이 발생합니다.", - "noticePreviewSuspended": "사용자 지정 스타일이 중지되어 이 미리보기는 적용되지 않습니다.", - "noticeDisabled": "사용자 지정 CSS가 꺼져 있습니다. 여기서 미리 볼 수는 있지만 켜야 실제로 적용됩니다.", - "hintTokens": "팁: 재정의한 색상은 var(--primary), var(--background) 등으로 참조할 수 있습니다." - } - }, - "zoomLevel": { - "sectionTitle": "창 확대/축소", - "sectionDescription": "전체 인터페이스를 확대하거나 축소합니다. 즉시 적용되며 장치별로 저장됩니다.", - "placeholder": "확대/축소 단계 선택", - "default": "기본값", - "current": "현재 확대/축소: {zoom}%" - }, - "fonts": { - "sectionTitle": "글꼴", - "sectionDescription": "인터페이스, 코드 편집기, 터미널의 글꼴을 각각 선택합니다. 내장 글꼴은 필요할 때 불러옵니다. “사용자 지정…”을 선택하면 시스템에 설치된 모든 글꼴을 사용할 수 있습니다.", - "interface": "인터페이스", - "editor": "편집기", - "terminal": "터미널", - "groupSans": "산세리프", - "groupMono": "고정폭", - "custom": "사용자 지정…", - "customPlaceholder": "글꼴 이름 (예: Fira Code)", - "fontSize": "글꼴 크기", - "ligatures": "합자 사용", - "ligaturesUnavailable": "이 글꼴에는 합자가 없습니다", - "wordWrap": "자동 줄 바꿈 사용", - "terminalLigaturesHint": "터미널 합자는 내장 코딩 글꼴에만 적용됩니다.", - "preview": "미리 보기" - }, - "welcomePanel": { - "sectionTitle": "모드 선택 영역", - "sectionDescription": "새 대화 페이지에서 입력창 위에 표시되는 '코드 개발 / 일상 업무' 바로가기 카드입니다.", - "showQuickActions": "새 대화 페이지에 표시" - }, - "workspaceBackground": { - "sectionTitle": "작업 공간 배경", - "sectionDescription": "작업 공간 전체 뒤에 이미지를 표시합니다. 사이드바와 패널이 반투명 유리 효과로 바뀌어 이미지가 비쳐 보이며, 마스크가 텍스트 가독성을 유지합니다.", - "enable": "배경 이미지 사용", - "image": "이미지", - "chooseImage": "이미지 선택", - "replaceImage": "이미지 변경", - "removeImage": "제거", - "fillMode": "채우기 방식", - "fillModes": { - "cover": "채우기", - "contain": "맞춤", - "center": "가운데", - "tile": "바둑판식" - }, - "maskOpacity": "마스크 불투명도", - "maskOpacityHint": "값이 높을수록 이미지가 테마 배경색으로 흐려져 텍스트 대비가 좋아집니다.", - "imageBlur": "이미지 흐림", - "panelOpacity": "패널 불투명도", - "panelOpacityHint": "사이드바, 패널, 탭 바의 불투명도입니다. 낮을수록 이미지가 더 많이 비쳐 보입니다.", - "errorTooLarge": "이미지가 너무 큽니다(최대 16 MB).", - "errorUploadFailed": "배경 이미지 설정에 실패했습니다." - } - }, - "SystemSettings": { - "loading": "로딩 중...", - "sectionTitle": "시스템 관리", - "sectionDescription": "네트워크 프록시, 앱 업데이트, 언어 설정을 관리합니다.", - "proxyTitle": "네트워크 프록시", - "proxyDescription": "활성화하면 이후 네트워크 요청에서 이 프록시를 우선 사용합니다(ACP 채팅, 에이전트 설치, Git 원격 작업 포함).", - "loadFailed": "불러오기 실패: {message}", - "enableProxy": "시스템 프록시 활성화", - "proxyAddress": "프록시 주소", - "proxyHint": "http(s)/socks5 지원, 예: {example}. 시스템 프록시를 활성화한 경우에만 적용됩니다.", - "save": "저장", - "saving": "저장 중...", - "proxyRequired": "프록시를 활성화하면 프록시 URL이 필요합니다", - "saveSuccess": "시스템 프록시 설정이 저장되었습니다", - "saveFailed": "저장 실패: {message}", - "languageTitle": "언어", - "languageDescription": "앱 언어를 설정합니다. 시스템 언어를 따를 때 지원되지 않는 언어는 영어로 대체됩니다.", - "appLanguage": "앱 언어", - "languageSaveSuccess": "언어 설정이 저장되었습니다", - "languageSaveFailed": "언어 설정 저장 실패: {message}", - "updateTitle": "앱 업데이트", - "versionTitle": "소프트웨어 업데이트", - "updateDescription": "설정된 릴리스 소스에서 새 버전을 확인하고 가능하면 바로 설치합니다.", - "currentVersion": "현재 버전", - "upgradableVersion": "최신 버전", - "none": "없음", - "lastChecked": "마지막 확인: {time}", - "updateError": "업데이트 오류: {message}", - "checking": "확인 중...", - "checkUpdate": "업데이트 확인", - "updating": "설치 중...", - "downloading": "다운로드 중...", - "upgradeTo": "v{version}로 업그레이드", - "viewRelease": "v{version} 릴리스 보기", - "foundUpdate": "새 버전 v{version}을 찾았습니다", - "alreadyLatest": "이미 최신 버전입니다", - "checkUpdateFailed": "업데이트 확인 실패: {message}", - "installSuccess": "업데이트가 설치되었습니다. 앱을 다시 시작합니다.", - "installFailed": "업데이트 실패: {message}", - "upgradeSuccess": "업그레이드가 완료되었습니다. 다시 불러오는 중...", - "restartTimeout": "서버가 제때 복구되지 않았습니다. 컨테이너 또는 서비스 로그를 확인하세요.", - "restartingIn": "{seconds}초 후에 다시 시작합니다...", - "waitingForServer": "서버가 복구되기를 기다리는 중...", - "restartToUpdate": "다시 시작하여 업데이트", - "newVersionBadge": "새 버전 v{version}", - "updateAvailableTitle": "업데이트 있음", - "releaseNotesTitle": "새로운 기능", - "remindLater": "나중에", - "retry": "다시 시도", - "stepDownload": "다운로드", - "stepInstall": "설치", - "stepRestart": "다시 시작", - "updateReadyHint": "업데이트를 다운로드했습니다. 다시 시작하여 적용하세요.", - "restarting": "다시 시작하는 중…", - "dockerUpgradeHint": "지금 실행 중인 컨테이너를 업그레이드합니다. 컨테이너를 다시 만들면 사라집니다. 유지하려면 새 버전 이미지를 가져오거나 빌드한 뒤 컨테이너를 다시 만드세요.", - "upgradeRolledBack": "업그레이드에 실패하여 서버가 이전 버전으로 롤백되었습니다.", - "serverUnreachable": "업그레이드를 시작하기 위해 서버에 연결할 수 없습니다. 서버가 실행 중인지 확인한 후 다시 시도하세요.", - "rollbackButton": "롤백", - "rollingBack": "롤백 중...", - "rollbackDescription": "마지막 업그레이드 이전에 설치된 버전으로 복원합니다.", - "rollbackConfirmTitle": "이전 버전으로 롤백하시겠습니까?", - "rollbackConfirmDescription": "서버가 마지막 업그레이드 이전에 설치된 버전으로 다시 시작됩니다. 최신 릴리스는 다시 설치할 수 있습니다.", - "rollbackConfirm": "롤백", - "rollbackCancel": "취소", - "rollbackSuccess": "이전 버전으로 롤백했습니다. 다시 불러오는 중...", - "rollbackFailed": "롤백에 실패했습니다. 서버 로그를 확인하세요.", - "updateErrors": { - "sourceUnavailable": "업데이트 소스에 연결할 수 없습니다. 네트워크 또는 프록시를 확인한 뒤 다시 시도하세요.", - "network": "네트워크 연결에 실패했습니다. 네트워크 또는 프록시를 확인한 뒤 다시 시도하세요.", - "downloadFailed": "업데이트 패키지 다운로드에 실패했습니다. 잠시 후 다시 시도하세요.", - "installFailed": "업데이트 설치에 실패했습니다. 앱을 종료한 뒤 다시 시도하세요.", - "unknown": "업데이트에 실패했습니다. 잠시 후 다시 시도하세요." - } - }, - "VersionControlSettings": { - "loading": "로딩 중...", - "sectionTitle": "버전 관리", - "sectionDescription": "Git 실행 파일을 설정하고 GitHub 계정을 관리합니다.", - "gitTitle": "Git 설정", - "gitDescription": "애플리케이션에서 사용할 Git 실행 파일을 설정합니다.", - "gitDetected": "Git이 감지되었습니다", - "gitNotFound": "시스템에서 Git을 찾을 수 없습니다", - "gitVersion": "버전", - "gitPath": "경로", - "customGitPath": "사용자 지정 Git 경로", - "customGitPathPlaceholder": "/usr/bin/git", - "customGitPathHint": "비워두면 자동 감지된 경로를 사용합니다.", - "test": "테스트", - "testing": "테스트 중...", - "testSuccess": "Git 실행 파일이 유효합니다.", - "testFailed": "Git 테스트 실패: {message}", - "save": "저장", - "saving": "저장 중...", - "saveSuccess": "Git 설정이 저장되었습니다.", - "saveFailed": "저장 실패: {message}", - "githubTitle": "GitHub 계정", - "githubDescription": "인증용 GitHub 계정을 관리합니다. 토큰은 로컬에 저장됩니다.", - "noAccounts": "설정된 GitHub 계정이 없습니다.", - "addAccount": "계정 추가", - "serverUrl": "서버 URL", - "serverUrlPlaceholder": "https://github.com", - "token": "개인 액세스 토큰", - "tokenPlaceholder": "ghp_xxxxxxxxxxxx", - "generateToken": "토큰 생성", - "tokenHint": "GitHub → Settings → Developer settings → Personal access tokens에서 토큰을 생성하세요.", - "validateAndAdd": "검증 및 추가", - "validating": "검증 중...", - "addSuccess": "계정 {username}이(가) 추가되었습니다.", - "addFailed": "계정 추가 실패: {message}", - "testConnection": "테스트", - "connectionSuccess": "연결 성공.", - "connectionFailed": "연결 실패: {message}", - "setDefault": "기본값으로 설정", - "defaultLabel": "기본", - "defaultSet": "기본 계정이 업데이트되었습니다.", - "removeAccount": "삭제", - "removeConfirmTitle": "계정 삭제", - "removeConfirmMessage": "계정 \"{username}\"을(를) 삭제하시겠습니까?", - "removeConfirm": "삭제", - "removeCancel": "취소", - "removeSuccess": "계정이 삭제되었습니다.", - "scopes": "범위", - "loadFailed": "설정 로드 실패: {message}", - "gitAccount": { - "sectionTitle": "Git 서버 계정", - "sectionDescription": "GitHub 이외의 Git 서버 자격 증명을 관리합니다 (GitLab, Bitbucket, 자체 호스팅 등).", - "noAccounts": "설정된 Git 서버 계정이 없습니다.", - "addAccount": "계정 추가", - "addTitle": "Git 계정 추가", - "addDescription": "서버 주소, 사용자 이름, 비밀번호 또는 액세스 토큰을 입력하세요.", - "serverUrl": "서버 URL", - "serverUrlPlaceholder": "https://gitlab.example.com", - "username": "사용자 이름", - "usernamePlaceholder": "사용자 이름 또는 이메일", - "password": "비밀번호 / 토큰", - "passwordPlaceholder": "비밀번호 또는 액세스 토큰", - "passwordHint": "서버의 비밀번호 또는 액세스 토큰을 입력하세요.", - "add": "추가", - "serverRequired": "서버 URL을 입력하세요.", - "usernameRequired": "사용자 이름을 입력하세요.", - "passwordRequired": "비밀번호를 입력하세요." - } - }, - "ShortcutSettings": { - "sectionTitle": "단축키", - "resetDefault": "기본값으로 재설정", - "recordInstruction": "오른쪽 버튼을 클릭한 다음 키 조합을 누르세요. Ctrl/Cmd, Alt, Shift를 사용할 수 있습니다. Esc를 누르면 기록을 취소합니다.", - "recording": "단축키 입력...", - "toasts": { - "conflict": "단축키가 이미 \"{title}\"에서 사용 중입니다", - "updated": "단축키가 업데이트되었습니다", - "invalid": "유효하지 않은 단축키입니다. 다시 시도하세요", - "reset": "기본 단축키를 복원했습니다" - }, - "actions": { - "toggle_search": { - "title": "검색 열기", - "description": "대화 검색 패널을 표시하거나 숨깁니다" - }, - "toggle_sidebar": { - "title": "왼쪽 사이드바 전환", - "description": "대화 목록 사이드바를 표시하거나 숨깁니다" - }, - "toggle_terminal": { - "title": "터미널 전환", - "description": "하단 터미널 패널을 표시하거나 숨깁니다" - }, - "new_terminal_tab": { - "title": "새 터미널", - "description": "터미널에 포커스가 있을 때 새 터미널 탭을 만듭니다" - }, - "close_current_terminal_tab": { - "title": "현재 터미널 닫기", - "description": "터미널에 포커스가 있을 때 현재 터미널 탭을 닫습니다" - }, - "toggle_aux_panel": { - "title": "오른쪽 패널 전환", - "description": "보조 정보 패널을 표시하거나 숨깁니다" - }, - "new_conversation": { - "title": "새 대화", - "description": "현재 폴더에 새 대화 탭을 만듭니다" - }, - "open_folder": { - "title": "폴더 열기", - "description": "폴더 선택기를 열고 새 창에서 엽니다" - }, - "open_settings": { - "title": "설정 열기", - "description": "설정 창을 엽니다" - }, - "close_current_tab": { - "title": "현재 탭 닫기", - "description": "현재 대화 또는 파일 탭을 닫습니다" - }, - "close_all_file_tabs": { - "title": "모든 파일 탭 닫기", - "description": "파일 패널이 활성 상태일 때 열린 모든 파일 탭을 닫습니다" - }, - "next_tab": { - "title": "다음 탭", - "description": "다음 대화 또는 파일 탭으로 전환" - }, - "prev_tab": { - "title": "이전 탭", - "description": "이전 대화 또는 파일 탭으로 전환" - }, - "send_message": { - "title": "메시지 보내기", - "description": "입력창에서 현재 메시지를 전송" - }, - "newline_in_message": { - "title": "메시지 줄바꿈", - "description": "입력창에 줄바꿈을 삽입" - }, - "toggle_custom_style": { - "title": "사용자 지정 스타일 중지/재개", - "description": "비상 탈출구: 모든 사용자 지정 색상과 CSS를 끄고, 다시 누르면 되돌립니다" - } - } - }, - "SkillsSettings": { - "title": "Skills", - "description": "왼쪽에서 Skill을 선택하세요. 오른쪽은 기본적으로 Markdown 미리보기이며, 편집으로 전환해 수정 후 저장할 수 있습니다.", - "loadingAgents": "Skill을 지원하는 에이전트를 불러오는 중...", - "emptyNoManageableAgents": "Skill을 관리할 수 있는 에이전트가 없습니다.", - "managedTarget": "관리 대상", - "selectAgentPlaceholder": "에이전트 선택", - "searchPlaceholder": "이름 / ID / 경로로 검색...", - "skillsList": "Skill 목록", - "loadingSkills": "Skill 불러오는 중...", - "agentNotSupported": "현재 에이전트는 Skill 관리를 지원하지 않습니다.", - "emptySkills": "아직 Skill이 없습니다. \"새 Skill\"을 클릭해 생성하세요.", - "newSkillTitle": "새 Skill", - "skillInfo": "Skill 정보", - "skillIdPlaceholder": "skill-id(영문/숫자/-/_/.)", - "skillsDirectoryWithPath": "Skill 디렉터리: {path}", - "skillsDirectoryNeedId": "Skill 디렉터리: Skill ID를 입력하면 전체 경로를 생성합니다", - "markdownContent": "Markdown 내용", - "editingStatus": "편집 중", - "previewStatus": "미리보기 중", - "contentPlaceholder": "Skill Markdown 내용을 입력하세요...", - "metadataTitle": "Skill 메타데이터", - "onlyYamlMetadata": "이 Skill에는 YAML 메타데이터만 포함되어 있습니다.", - "emptyContentHint": "아직 내용이 없습니다. \"편집\"을 눌러 시작하세요.", - "loadingSkill": "Skill 불러오는 중...", - "emptyNoAgents": "사용 가능한 에이전트가 없습니다.", - "noSelectionHint": "왼쪽에서 Skill을 선택하거나 \"새 Skill\"을 클릭하여 만드세요.", - "systemBadge": "시스템", - "systemHint": "CLI 내장 Skill · 읽기 전용", - "scope": { - "global": "전역", - "folder": "폴더", - "selectFolderPlaceholder": "폴더 선택", - "noFolders": "폴더를 찾을 수 없습니다", - "pickFolderHint": "Skills을 보려면 폴더를 선택하세요." - }, - "actions": { - "preview": "미리보기", - "edit": "편집", - "openInWindow": "새 창에서 열기", - "delete": "삭제", - "deleting": "삭제 중...", - "refresh": "새로고침", - "newSkill": "새 Skill", - "reset": "초기화", - "save": "저장", - "saving": "저장 중...", - "cancel": "취소" - }, - "deleteDialog": { - "title": "Skill 삭제", - "confirm": "현재 Skill을 삭제하시겠습니까? 이 작업은 되돌릴 수 없습니다.", - "confirmWithNamePrefix": "Skill", - "confirmWithNameSuffix": "을(를) 삭제하시겠습니까? 이 작업은 되돌릴 수 없습니다." - }, - "toasts": { - "loadFailed": "Skill을 불러오지 못했습니다", - "openFolderFailed": "폴더를 열지 못했습니다", - "noSkillDirectory": "현재 에이전트에서 사용할 수 있는 Skill 디렉터리를 찾지 못했습니다", - "nameRequired": "Skill 이름은 비워둘 수 없습니다", - "updated": "Skill이 업데이트되었습니다", - "created": "Skill이 생성되었습니다", - "saveFailed": "Skill 저장에 실패했습니다", - "deleted": "Skill이 삭제되었습니다", - "deleteFailed": "Skill 삭제에 실패했습니다" - }, - "templates": { - "gemini": "---\nname: example-skill\ndescription: Describe when this skill should be used.\n---\n\n# Skill Name\n\nInstructions for the agent when this skill is active.\n\n## Workflow\n\n1. Add actionable step one.\n2. Add actionable step two.\n", - "openCode": "---\nname: example-skill\ndescription: Describe when this skill should be used.\n---\n\n# Purpose\n\nDescribe what this skill helps with.\n\n# Steps\n\n1. Add actionable step one.\n2. Add actionable step two.\n", - "openClaw": "---\nname: example-skill\ndescription: Describe when this skill should be used.\nuser-invocable: true\ndisable-model-invocation: false\n---\n\n# Purpose\n\nDescribe what this skill helps with.\n\n# Instructions\n\n1. Add actionable instruction one.\n2. Add actionable instruction two.\n", - "default": "---\nname: example-skill\ndescription: Describe when this skill should be used.\n---\n\n# Skill: example-skill\n\n## When to use\n\n- Describe trigger conditions.\n\n## Instructions\n\n1. Add actionable instruction one.\n2. Add actionable instruction two.\n" - } - }, - "McpSettings": { - "loading": "로딩 중...", - "summary": { - "missingCommand": "(명령 없음)", - "missingUrl": "(URL 없음)" - }, - "protocol": { - "stdio": "Stdio" - }, - "errors": { - "selectInstallProtocol": "설치 프로토콜을 선택하세요", - "fieldRequired": "{field}은(는) 필수입니다", - "fieldNeedsBoolean": "{field}은(는) true 또는 false여야 합니다", - "fieldNeedsNumber": "{field}은(는) 숫자여야 합니다", - "fieldNeedsInteger": "{field}은(는) 정수여야 합니다", - "fieldInvalidJson": "{field}의 JSON이 잘못되었습니다: {message}", - "fieldOutOfRange": "{field} 값이 허용 범위를 벗어났습니다", - "jsonEmpty": "{name}은(는) 비워둘 수 없습니다", - "jsonInvalid": "{name}은(는) 유효한 JSON이 아닙니다: {message}", - "jsonMustBeObject": "{name}은(는) JSON 객체여야 합니다", - "specMustBeObject": "MCP 구성은 JSON 객체여야 합니다.", - "missingType": "MCP 구성에 type 필드가 없습니다. stdio, http (별칭: streamable-http, streamableHttp), sse 중 하나를 지정하세요.", - "unsupportedType": "지원하지 않는 MCP type {type}. 지원: stdio, http (별칭: streamable-http, streamableHttp), sse.", - "codexEntryUnsupportedType": "Codex MCP 항목 {id}의 type {type}은(는) 지원되지 않습니다. 지원: stdio, http (별칭: streamable-http, streamableHttp), sse.", - "unsupportedTransportType": "지원하지 않는 transport type {type}. 지원: http (별칭: streamable-http, streamableHttp), sse.", - "stdioCommandRequired": "stdio 타입의 MCP에는 비어 있지 않은 command 필드가 필요합니다.", - "remoteUrlRequired": "원격 MCP에는 비어 있지 않은 url 필드가 필요합니다.", - "appsRequired": "대상 앱을 하나 이상 선택하세요." - }, - "jsonNames": { - "localConfig": "MCP 구성", - "installConfig": "설치 구성" - }, - "toasts": { - "uninstalled": "MCP가 제거되었습니다", - "uninstallFailed": "제거 실패: {message}", - "selectAtLeastOneApp": "대상 앱을 최소 하나 선택하세요", - "saveSuccess": "저장됨", - "saveFailed": "저장 실패: {message}", - "installed": "{name} 설치됨", - "installFailed": "설치 실패: {message}", - "serverIdRequired": "Server ID는 필수입니다", - "serverIdExists": "Server ID \"{id}\"이(가) 이미 존재합니다. 기존 항목을 편집하거나 다른 이름을 사용하세요.", - "created": "MCP가 생성되었습니다" - }, - "installDialog": { - "title": "MCP 설치 확인", - "descriptionWithName": "{name}을(를) 로컬 구성에 설치합니다.", - "description": "설치할 대상 앱을 선택하세요.", - "protocol": "프로토콜", - "selectProtocol": "프로토콜 선택", - "parameters": "구성 매개변수", - "booleanPlaceholder": "true/false를 선택하세요", - "selectOneValue": "값 선택", - "targetApps": "대상 앱" - }, - "actions": { - "cancel": "취소", - "confirmInstall": "설치 확인", - "installing": "설치 중", - "uninstall": "제거", - "uninstalling": "제거 중", - "viewDetails": "상세 보기", - "save": "저장", - "saving": "저장 중", - "install": "설치", - "refresh": "새로고침", - "newMcp": "새 MCP", - "create": "생성", - "creating": "생성 중..." - }, - "tabs": { - "local": "로컬 MCP", - "market": "MCP 마켓플레이스" - }, - "local": { - "filterPlaceholder": "로컬 MCP 필터...", - "loadFailed": "로드 실패: {message}", - "empty": "감지된 로컬 MCP가 없습니다.", - "description": "로컬 MCP 구성은 직접 수정하고 저장할 수 있습니다.", - "enabledApps": "활성화된 앱", - "configJson": "MCP 구성 (JSON)", - "draftTitle": "새 MCP", - "draftDescription": "Server ID와 설정을 입력하여 로컬 MCP 서버를 생성합니다.", - "serverIdLabel": "Server ID", - "serverIdPlaceholder": "Server ID (예: my-mcp)", - "typeHint": "지원 타입: stdio, http (별칭: streamable-http, streamableHttp), sse. env는 stdio 전용이며, 원격 MCP는 인증 토큰을 headers로 전달해야 합니다.", - "envOnRemoteWarning": "원격 MCP 설정에 env가 포함되어 있습니다. env는 stdio에서만 사용되며 원격 MCP는 headers로 인증 토큰을 전달합니다. 저장 시 env는 무시됩니다." - }, - "market": { - "selectMarketplace": "마켓플레이스 선택", - "searchPlaceholder": "MCP 검색...", - "searchFailed": "검색 실패: {message}", - "loadingList": "MCP 목록을 불러오는 중...", - "empty": "MCP 검색 결과가 없습니다.", - "loadingDetail": "마켓플레이스 상세 정보를 불러오는 중...", - "detailLoadFailed": "상세 정보를 불러오지 못했습니다: {message}", - "owner": "소유자: {owner}", - "namespace": "네임스페이스: {namespace}", - "defaultInstallProtocol": "기본 설치 프로토콜", - "currentOptionParameterCount": "현재 옵션의 매개변수 수: {count}", - "installConfigDescription": "설치 구성 (JSON, 설치 전에 편집 가능; 편집 내용은 프로토콜/매개변수 폼을 덮어씁니다)", - "selectLeftToView": "상세 정보를 보려면 왼쪽에서 마켓플레이스 MCP를 선택하세요." - }, - "badges": { - "verified": "검증됨", - "remote": "원격", - "hasHomepage": "홈페이지 있음", - "uses": "{count}회 사용", - "deployed": "배포됨", - "notDeployed": "미배포" - }, - "selectLeftMcp": "왼쪽에서 MCP를 선택하세요." - }, - "AcpAgentSettings": { - "title": "Agent SDK 관리", - "description": "Agent SDK 연결, 활성화 상태, 환경 변수, 구성 관리, 버전 사전 점검 정보를 한곳에서 관리합니다.", - "loadingAgents": "에이전트 목록 불러오는 중...", - "agentList": "에이전트 목록", - "emptyNoAgent": "사용 가능한 에이전트가 없습니다.", - "configManagement": "구성 관리", - "envVars": "환경 변수", - "hostTools": { - "label": "파일과 명령을 에이전트가 직접 처리", - "description": "codeg가 파일 접근과 터미널 명령을 대신 처리하지 않고 에이전트가 자체 프로세스에서 실행합니다. 그래야 에이전트 자체의 샌드박스와 권한 규칙이 적용됩니다. 다른 에이전트에 위임하는 기능도 함께 꺼집니다. 같은 작업이 다시 codeg를 거치게 되기 때문입니다. codeg는 자체 샌드박스를 제공하지 않으므로 에이전트에 샌드박스를 구성한 경우에만 켜세요." - }, - "nativeJsonConfig": "네이티브 JSON 구성", - "modelHintDefault": "비워두면 시스템 기본 모델을 사용합니다.", - "generalConfigDescriptionClaude": "API URL, API Key, Claude 모델을 빠르게 설정하고 네이티브 JSON 구성과 동기화합니다.", - "generalConfigDescriptionDefault": "주요 구성 입력(API URL, API Key, Model)과 네이티브 JSON 구성 관리를 지원합니다.", - "multiAgent": { - "title": "다중 에이전트 협업", - "description": "활성 에이전트가 하위 작업을 다른 에이전트에게 위임할 수 있도록 합니다.", - "enable": "위임 사용", - "enableHint": "끄면 delegate_to_agent 도구가 에이전트의 MCP 도구 목록에서 숨겨집니다.", - "withheldByHostTools": "{agents}에는 위임 도구가 제공되지 않습니다. 해당 에이전트의 “파일과 명령을 에이전트가 직접 처리” 스위치가 켜져 있습니다.", - "selfInitiate": "Allow spawn without @", - "selfInitiateHint": "When on, an agent may start a listed sub-agent on its own. An @ mention is still always honored. When off, only an @ mention starts a sub-agent.", - "depthLimit": "최대 위임 깊이", - "depthHint": "허용 범위: {min}–{max}. 위임 체인(루트 → 하위 → 손자 …)의 재귀 깊이를 제한합니다.", - "completedCacheLabel": "완료 결과 캐시(MB)", - "completedCacheHint": "실행 중인 위임 세션이 보관하는 완료된 하위 에이전트 결과의 메모리 내 캐시입니다. 해당 세션이 실행되는 동안에만 유지되며 세션이 종료되면 자동으로 삭제됩니다. 이 예산을 초과하면 오래된 결과부터 메모리에서 삭제됩니다(하위 에이전트 자체 세션에서는 계속 확인 가능). 0은 무제한(세션 종료 시에는 그래도 삭제됨).", - "save": "저장", - "saving": "저장 중…", - "saved": "위임 설정이 저장되었습니다", - "saveFailed": "위임 설정 저장 실패", - "loadFailed": "위임 설정 로드 실패: {detail}", - "tabGeneral": "일반", - "tabAgentDefaults": "하위 에이전트 설정", - "agentDefaultsDescription": "다중 에이전트 협업이 위임 호출을 위해 하위 에이전트를 시작할 때 적용되는 재정의 항목입니다. 아래 옵션은 실시간 프로브로 가져오므로 선택한 항목이 그대로 에이전트에 전달됩니다.", - "probing": "에이전트에서 사용 가능한 옵션을 로드 중…", - "probeFailed": "옵션 로드 실패: {detail}", - "retry": "다시 시도", - "noConfigAvailable": "이 에이전트에는 구성 가능한 옵션이 없습니다.", - "modeLabel": "모드", - "agentDefaultHint": "에이전트 기본값: {value}", - "defaultOptionLabel": "기본값 ({value})" - }, - "actions": { - "dragSort": "드래그하여 순서 변경", - "dragSortAgent": "{name} 순서 변경", - "refreshCheck": "다시 확인", - "refreshCheckAgent": "{name} 다시 확인", - "clickEnable": "{name} 활성화", - "clickDisable": "{name} 비활성화", - "install": "설치", - "upgrade": "업그레이드", - "uninstall": "제거", - "uninstalling": "제거 중...", - "saveEnvVars": "환경 변수 저장", - "saving": "저장 중...", - "saveGrokConfig": "Grok 설정 저장", - "saveCodexConfig": "Codex 설정 저장", - "saveGeminiConfig": "Gemini 설정 저장", - "saveOpenCodeConfig": "OpenCode 설정 저장", - "saveOpenClawConfig": "OpenClaw 설정 저장", - "saveConfigManagement": "구성 관리 저장", - "saveCurrentProvider": "현재 Provider 저장", - "showApiKey": "API 키 보기", - "hideApiKey": "API 키 숨기기", - "showKey": "키 보기", - "hideKey": "키 숨기기", - "showToken": "토큰 보기", - "hideToken": "토큰 숨기기", - "cancel": "취소", - "delete": "삭제", - "deleting": "삭제 중...", - "confirmDelete": "삭제 확인", - "confirmUninstall": "제거 확인", - "saveClineConfig": "Cline 설정 저장", - "saveHermesConfig": "Hermes 설정 저장", - "saveCodeBuddyConfig": "CodeBuddy 구성 저장", - "saveKimiCodeConfig": "Kimi Code 구성 저장", - "customInstall": "사용자 지정 설치", - "saveKimiCodeRawConfig": "Save config.toml", - "saveDeepSeekConfig": "DeepSeek 구성 저장", - "diagnose": "진단" - }, - "status": { - "enabled": "활성화됨", - "disabled": "비활성화됨", - "unchecked": "확인 안 됨", - "agentEnabledAria": "{name} 활성화됨", - "agentEnabledSwitch": "{name} 활성화 스위치" - }, - "preflight": { - "count": "사전 점검 항목: {count}", - "notRun": "점검이 아직 실행되지 않았습니다." - }, - "grok": { - "configDescription": "여기에서 Grok을 설정합니다. 아래 컨트롤(권한 모드, 추론 강도, 선택적 사용자 지정(자체 엔드포인트) 모델, 압축)은 ~/.grok/config.toml에 병합되며 다른 키와 주석은 유지됩니다. 로그인은 XAI_API_KEY 또는 `grok login`을 사용합니다. 기타 키는 '고급'에서 편집할 수 있습니다.", - "permissionModeLabel": "권한 모드", - "permissionDefault": "매번 확인", - "permissionAcceptEdits": "편집 자동 승인", - "permissionAuto": "스마트 자동 승인", - "permissionAlwaysApprove": "항상 허용", - "reasoningEffortLabel": "추론 강도", - "effortLow": "낮음(빠름)", - "effortMedium": "중간(균형)", - "effortHigh": "높음", - "effortXhigh": "최대", - "optionDefault": "기본값 사용", - "authTitle": "인증", - "authMode": "인증 방식", - "authModeApiKey": "XAI API 키", - "authModeApiKeyHint": "xAI 콘솔의 XAI_API_KEY로 인증합니다. 비대화형·헤드리스 실행에 적합하며 이 에이전트의 환경 변수에 저장됩니다.", - "authModeCustom": "사용자 지정 엔드포인트", - "authModeCustomHint": "자체 엔드포인트(BYO)를 사용합니다. 아래에서 자체 base URL과 API 키를 가진 사용자 지정 모델을 정의하면 Grok의 기본 모델이 됩니다.", - "subscriptionHint": "`grok login`으로 로그인합니다(SuperGrok / X Premium+). API 키는 저장되지 않습니다.", - "loginHint": "터미널에서 다음 명령을 실행해 로그인한 뒤 이 설정을 다시 여세요:", - "commandCopied": "명령을 클립보드에 복사했습니다", - "copyCommand": "명령 복사", - "authKeyConfigured": "XAI_API_KEY가 구성되어 있습니다.", - "authKeyMissing": "XAI_API_KEY가 설정되지 않았습니다.", - "advancedToggle": "고급(원본 config.toml)", - "configTomlNative": "config.toml(네이티브)", - "configTomlHint": "~/.grok/config.toml 전체로 그대로 저장됩니다. 잘못된 TOML은 거부되어 오타로 파일이 잘리지 않습니다.", - "configTomlPlaceholder": "# 위 컨트롤 이외의 키, 예:\n# [mcp_servers.*], [cli], [permission] 규칙.", - "customModelTitle": "사용자 지정 모델(자체 엔드포인트)", - "customModelHint": "Grok을 사용자 지정 또는 자체 호스팅 엔드포인트로 연결합니다. codeg는 모델별 `[model.*]` 블록을 작성하고 기본 모델로 설정합니다. 모델 ID를 비우면 제거됩니다.", - "customModelIdLabel": "모델 ID", - "customModelIdPlaceholder": "grok-4.5", - "customModelIdHint": "`[model.*]` 블록으로 등록되어 모델 이름으로 API에 전송되며 `[models].default`로도 설정됩니다.", - "customBaseUrlLabel": "Base URL", - "customBaseUrlPlaceholder": "https://api.x.ai/v1(기본값)", - "customApiBackendLabel": "API 백엔드", - "backendResponses": "Responses", - "backendChatCompletions": "Chat Completions", - "backendMessages": "Messages(Anthropic)", - "customApiKeyLabel": "API 키", - "customApiKeyHint": "`[model.*].api_key`에 인라인으로 저장되며 이 엔드포인트에만 적용됩니다.", - "customContextWindowLabel": "컨텍스트 윈도우(토큰)", - "customContextWindowHint": "선택 사항. 자동 압축 타이밍에 사용됩니다. 비워 두면 엔드포인트 기본값을 사용합니다.", - "autoCompactLabel": "자동 압축 임계값(%)", - "autoCompactHint": "컨텍스트 사용량이 이 비율에 도달하면 대화를 압축합니다(Grok 기본값 85). `[session]`에 기록됩니다." - }, - "cursor": { - "configDescription": "여기에서 Cursor를 설정합니다. 먼저 인증 방식을 선택하세요——공식 구독(브라우저 로그인) 또는 헤드리스/서버용 Cursor API 키——그런 다음 모델을 선택하고 CLI의 권한 규칙과 샌드박스를 편집합니다. codeg는 이를 ~/.cursor/cli-config.json에 기록하며 cursor-agent CLI와 공유합니다.", - "authTitle": "인증", - "authChecking": "확인 중…", - "authNotInstalled": "cursor-agent가 설치되지 않았습니다", - "authLoggedIn": "로그인됨", - "authNotLoggedIn": "로그인되지 않음", - "loginHint": "터미널에서 아래 명령을 실행해 Cursor 계정으로 로그인(브라우저가 열립니다)한 뒤 새로고침을 누르세요:", - "apiKeyLabel": "Cursor API 키", - "apiKeyPlaceholder": "cursor.com/dashboard에서 발급", - "apiKeyHint": "CURSOR_API_KEY —— Cursor 대시보드의 계정 키로, 헤드리스/서버 환경에서 브라우저 로그인 대신 사용합니다. 서드파티나 OpenAI 키가 아닙니다.", - "modelTitle": "기본 모델", - "loadModels": "모델 목록 가져오기", - "modelsUnavailable": "모델 목록을 가져올 수 없음", - "modelHint": "세션 시작 시 --model로 CLI에 전달됩니다. 기본값이면 Cursor가 선택합니다.", - "permissionsTitle": "권한 및 샌드박스", - "permissionsDescription": "CLI 권한 규칙(cli-config.json)의 시각 편집기입니다. 허용 규칙은 확인 없이 실행되고 거부 규칙은 항상 차단됩니다.", - "permissionModeLabel": "권한 모드", - "permissionModeDefault": "실행 전 확인(기본)", - "permissionModeForce": "Run Everything(--force)", - "permissionModeHint": "Run Everything은 --force로 세션을 시작합니다. deny 규칙을 제외한 모든 도구 호출이 확인 없이 자동 허용됩니다(조직 정책에 따라 allow 규칙 일치로 제한될 수 있음). 새 세션부터 적용됩니다.", - "optionDefault": "기본(미설정)", - "sandboxLabel": "샌드박스", - "sandboxEnabled": "사용", - "sandboxDisabled": "사용 안 함", - "allowRulesLabel": "허용 규칙", - "denyRulesLabel": "거부 규칙", - "addRule": "규칙 추가", - "rulesSyntaxHint": "규칙 구문: Shell(명령), Read(경로/글롭), Write(경로/글롭), WebFetch(도메인), Mcp(서버:도구) — deny 규칙이 항상 우선합니다.", - "saveConfig": "설정 저장", - "advancedToggle": "고급: 원본 cli-config.json", - "advancedHint": "~/.cursor/cli-config.json 전체입니다. 여기서 저장하면 그대로 기록되며, 위 구조화 컨트롤은 병합 방식으로 기록됩니다.", - "saveRawConfig": "파일 저장", - "authMode": "인증 방식", - "subscriptionHint": "Cursor 계정으로 로그인하고 Cursor의 모델을 사용합니다.", - "customApiKeyRequired": "Cursor API 키가 필요합니다.", - "authModeApiKey": "Cursor API 키 (헤드리스/서버)", - "authModeApiKeyHint": "Cursor 대시보드에서 발급한 계정 API 키로 인증합니다(헤드리스/서버 환경용). 이는 Cursor 계정 키이며 서드파티/OpenAI 엔드포인트가 아닙니다——cursor-agent는 Cursor 자체 백엔드에만 연결됩니다. codex/OpenAI 호환 엔드포인트를 사용하려면 Codex 에이전트를 대신 사용하세요.", - "modelPickerPlaceholder": "모델 검색…", - "modelNoMatch": "일치하는 모델 없음", - "modelsNeedAuth": "로그인하면 모델 목록을 불러옵니다.", - "modelDefaultBadge": "기본값" - }, - "deepseek": { - "configManagement": "DeepSeek Harness 구성", - "configDescription": "엔드포인트와 API 키는 deepseek-acp가 시작할 때 읽는 환경 변수입니다. 모델과 추론 강도는 세션별 선택기이므로 입력창에서 바꿉니다.", - "baseUrlLabel": "API 엔드포인트", - "baseUrlHint": "비워 두면 공식 엔드포인트를 사용합니다. 저장 후 시작하는 세션부터 적용되며, 실행 중인 세션은 다시 연결해야 반영됩니다.", - "baseUrlInvalid": "쿼리 문자열이 없는 완전한 http(s) URL을 입력하세요. 예: https://api.deepseek.com", - "apiKeyLabel": "API 키", - "apiKeyHint": "DEEPSEEK_API_KEY로 에이전트에 전달됩니다. 환경 변수가 자격 증명 파일보다 우선하므로 터미널로 로그인한다면 비워 두세요." - }, - "codex": { - "configDescription": "API URL, API Key, 모델 이름, reasoning effort를 빠르게 설정하고 `auth.json` / `config.toml`과 동기화합니다.", - "authMode": "인증 방식", - "chatgptSubscription": "공식 구독", - "chatgptSubscriptionHint": "ChatGPT 공식 구독으로 로그인, API Key 불필요", - "apiKeyHint": "API Key로 OpenAI 또는 호환 API 서비스에 연결", - "selectProvider": "Provider 선택", - "modelName": "모델 이름", - "selectReasoningEffort": "Reasoning Effort 선택", - "enableWebsocket": "WebSocket 활성화", - "enableWebsocketAria": "Codex Provider용 WebSocket 활성화", - "enableSkills": "Skills 활성화", - "enableSkillsAria": "Codex용 Skills 활성화", - "enableFast": "Fast 활성화", - "enableFastAria": "Codex용 Fast 서비스 계층 활성화", - "sandboxGroupTitle": "샌드박스 및 승인", - "sandboxGroupHint": "전역 ~/.codex/config.toml에 기록되므로 codex CLI와 IDE 세션에도 적용됩니다. 스레드 기본값이며 codex가 스스로 시작하는 턴(/goal, /review, /compact)에만 적용됩니다. 일반 프롬프트는 입력창의 승인 프리셋을 사용합니다. 변경 사항은 세션을 다시 시작해야 반영됩니다.", - "sandboxShadowedWarning": "config.toml에 default_permissions가 설정되어 있어 codex가 권한 프로필로 해석하고 sandbox_mode를 완전히 무시합니다. 아래 설정을 사용하려면 default_permissions를 제거하세요.", - "sandboxPermissionsTableWarning": "config.toml에 [permissions] 프로필이 있지만 default_permissions가 없어 codex가 시작을 거부합니다. 아래 원본 편집기에서 설정하세요.", - "approvalPolicyLabel": "승인 정책", - "approvalPolicyUnset": "설정 안 함(codex 기본값: 요청 시)", - "approvalPolicy_on-request": "요청 시 — 모델이 확인 시점을 결정", - "approvalPolicy_untrusted": "신뢰 안 함 — 안전이 확인된 읽기 전용 명령만 자동 실행", - "approvalPolicy_never": "묻지 않음 — 승인 창을 전혀 띄우지 않음", - "approvalPolicy_granular": "세부 설정 — 프롬프트 종류별로 지정", - "approvalPolicyUntrustedAcpWarning": "ACP 어댑터의 세 가지 승인 프리셋에는 untrusted에 해당하는 항목이 없으므로 codeg 세션은 \"요청 시\"로 대체됩니다. 이 경우 모델이 물어볼 시점을 스스로 정하며, 샌드박스가 이미 허용한 명령은 더 이상 확인하지 않습니다. 대신 아래 샌드박스 모드로 제한하세요.", - "granularHint": "끄면 해당 종류의 요청은 표시되지 않고 자동으로 거부됩니다.", - "granular_sandbox_approval": "셸 명령 권한 상승", - "granular_rules": "Execpolicy 규칙 프롬프트", - "granular_skill_approval": "스킬 스크립트 프롬프트", - "granular_request_permissions": "request_permissions 도구 프롬프트", - "granular_mcp_elicitations": "MCP elicitation 프롬프트", - "sandboxModeLabel": "샌드박스 모드", - "sandboxModeUnset": "설정 안 함(신뢰된 폴더는 워크스페이스 쓰기로 대체)", - "sandboxMode_read-only": "읽기 전용", - "sandboxMode_workspace-write": "워크스페이스 쓰기", - "sandboxMode_danger-full-access": "전체 접근(샌드박스 없음)", - "sandboxModeHint": "Windows에서는 codex의 실험적 Windows 샌드박스를 켜지 않으면 워크스페이스 쓰기가 읽기 전용으로 낮아집니다.", - "sandboxModeSeedsPresetHint": "codeg는 이 값으로 세션의 초기 승인 프리셋도 정하므로, 승인 정책과 달리 일반 프롬프트에도 적용됩니다. 입력창에서 선택한 프리셋이 이를 덮어씁니다.", - "writableRootsLabel": "추가 쓰기 가능 폴더", - "writableRootsHint": "작업 디렉터리 외에 허용할 절대 경로를 한 줄에 하나씩.", - "sandboxRootsRelativeError": "절대 경로여야 합니다 — codex는 상대 경로를 ~/.codex 기준으로 해석합니다: {path}", - "networkAccessLabel": "네트워크 접근 허용", - "excludeTmpdirLabel": "쓰기 가능 루트에서 TMPDIR 제외", - "excludeSlashTmpLabel": "쓰기 가능 루트에서 /tmp 제외", - "authJsonNative": "auth.json (네이티브)", - "configTomlNative": "config.toml (네이티브)", - "loginButton": "ChatGPT로 로그인", - "loginRequesting": "로그인 코드 요청 중...", - "loginStep1": "브라우저에서 다음 URL을 열어주세요:", - "loginStep2": "아래 코드를 입력하세요:", - "loginPolling": "인증 대기 중...", - "loginCancel": "취소", - "loginSuccess": "로그인 성공, 설정이 저장되었습니다!", - "loginFailed": "로그인 실패: {message}", - "loginRetry": "재시도", - "loginCodeCopied": "코드가 복사되었습니다", - "loggedIn": "계정 로그인됨", - "loginRelogin": "재로그인 / 계정 전환", - "loginTimeout": "로그인 시간 초과, 다시 시도해 주세요", - "loginSaveFailed": "로그인 성공했지만 설정 저장 실패" - }, - "gemini": { - "authConfig": "Gemini 인증 설정", - "authConfigDescription": "Gemini CLI 인증 문서와 정렬되며, 커스텀 엔드포인트, Google 로그인, Gemini API Key, Vertex AI(ADC / 서비스 계정 / API Key)를 지원합니다.", - "authMode": "인증 모드", - "selectAuthMode": "인증 모드 선택", - "viewAuthDoc": "인증 문서 보기", - "mode": { - "custom": "커스텀 엔드포인트", - "loginGoogle": "Google 로그인 (OAuth)", - "vertexServiceAccount": "Vertex AI (서비스 계정)" - }, - "hint": { - "custom": "API URL, API Key, Model을 입력하세요. GOOGLE_GEMINI_BASE_URL / GEMINI_API_KEY / GEMINI_MODEL에 매핑됩니다.", - "loginGoogle": "먼저 터미널에서 gemini를 실행해 Google 로그인을 완료하세요. API key는 필요하지 않습니다.", - "geminiApiKey": "Gemini API 사용 시 GEMINI_API_KEY를 입력하세요.", - "vertexAdc": "gcloud ADC를 사용합니다. GOOGLE_CLOUD_PROJECT와 GOOGLE_CLOUD_LOCATION 설정을 권장합니다.", - "vertexServiceAccount": "서비스 계정 JSON 경로를 GOOGLE_APPLICATION_CREDENTIALS에 설정하세요.", - "vertexApiKey": "Vertex AI API key 사용 시 GOOGLE_API_KEY를 입력하세요." - } - }, - "openCode": { - "configManagement": "OpenCode 구성 관리", - "configDescription": "OpenCode `provider` 스키마에 맞추어 다중 Provider 관리와 네이티브 JSON 파일 양방향 동기화를 지원합니다.", - "providerManagement": "Provider 관리", - "providerCount": "Provider {count}개", - "addProvider": "Provider 추가", - "emptyProvider": "아직 사용자 지정 공급자가 없습니다. '사용자 지정 공급자 추가'를 클릭해 만드세요.", - "providerEnabledState": "{providerId} 활성 상태", - "selectProviderNpm": "provider.npm 선택", - "modelManagement": "모델 관리", - "modelCount": "모델 {count}개", - "modelDescription": "OpenCode `provider.models`와 정렬됩니다. 빠른 관리는 현재 `name` / `id`를 지원하며, 기타 고급 필드는 유지되고 아래 네이티브 JSON에서 편집할 수 있습니다.", - "addModel": "모델 추가", - "emptyModel": "아직 모델이 없습니다. model id를 입력한 뒤 \"모델 추가\"를 클릭하세요.", - "modelId": "모델 ID", - "modelName": "모델 이름", - "deleteModel": "모델 {modelId} 삭제", - "nativeJsonConfig": "OpenCode 네이티브 JSON 구성", - "mainModel": "메인 모델", - "smallModel": "스몰 모델", - "noMatchingModels": "일치하는 모델 없음", - "connectProvider": "공급자 연결", - "connectedProviders": "연결된 공급자", - "noConnectedProviders": "아직 카탈로그 공급자를 연결하지 않았습니다.", - "advancedProviderConfig": "사용자 지정 공급자", - "customProviderConfigHint": "직접 정의하는 OpenAI 호환 엔드포인트입니다 — opencode.json의 provider 블록이며 API 키는 auth.json에 저장됩니다.", - "addCustomProvider": "사용자 지정 공급자 추가", - "disconnect": "연결 해제", - "editConfig": "편집", - "customBadge": "사용자 지정", - "authKindApi": "API 키", - "authKindOauth": "OAuth", - "authKindNone": "자격 증명 없음", - "connect": { - "title": "공급자 연결", - "description": "models.dev 카탈로그에서 공급자를 선택하세요. 자격 증명은 OpenCode의 auth.json 파일에 저장됩니다.", - "pick": "공급자", - "search": "공급자 검색…", - "loading": "카탈로그 불러오는 중…", - "catalogLabel": "models.dev 카탈로그", - "modelsAvailable": "{count}개 모델 사용 가능", - "getKey": "API 키 받기", - "oauthApiKeyNote": "이 공급자는 opencode auth login을 통한 브라우저 로그인도 지원합니다. 브라우저 로그인은 곧 제공됩니다. 지금은 API 키를 붙여넣으세요.", - "apiKey": "API 키", - "apiKeyHint": "auth.json에 저장되며 opencode.json에는 저장되지 않습니다.", - "baseUrlOptional": "Base URL 재정의 (선택)", - "providerId": "공급자 ID", - "displayName": "표시 이름", - "modelsList": "모델 (한 줄에 하나)", - "modelsHint": "엔드포인트가 허용하는 모델 ID.", - "action": "연결", - "editTitle": "공급자 편집", - "editDescription": "이 공급자의 API 키 또는 Base URL을 업데이트합니다.", - "saveAction": "저장" - }, - "customProvider": { - "title": "사용자 지정 공급자 추가", - "description": "OpenAI 호환 엔드포인트를 정의합니다. API 키는 auth.json에, provider 블록은 opencode.json에 저장됩니다.", - "action": "공급자 추가", - "idInCatalog": "{providerId}은(는) 알려진 공급자입니다. 대신 '공급자 연결'로 연결하세요." - }, - "refreshCatalog": "카탈로그 새로고침", - "reasoningBadge": "추론", - "contextWindow": "컨텍스트 윈도우", - "permissions": { - "title": "권한", - "description": "어떤 작업을 바로 실행할지, 먼저 확인할지, 차단할지 정합니다. opencode.json 의 permission 설정에 기록되며 아래에서 저장하면 적용됩니다.", - "docsLink": "권한 문서", - "unparsableConfig": "아래 네이티브 JSON 을 해석할 수 없어 시각적 편집을 멈췄습니다. JSON 을 고치면 다시 사용할 수 있습니다.", - "invalidBlock": "permission 설정의 형태를 인식할 수 없습니다. 아래 네이티브 JSON 에서 수정하거나 [초기화] 로 다시 시작하세요.", - "orderingUnsafe": "와일드카드 규칙이 개별 도구보다 뒤에 적혀 있어 OpenCode 가 그 도구들에도 적용합니다. 아래 행은 실제로 적용되는 값이 아닙니다. [순서 수정] 은 값을 바꾸지 않고 와일드카드를 각 범위 맨 앞으로 되돌립니다.", - "orderingUnsafeManual": "어떤 규칙이 뒤의 더 넓은 패턴에 가려져 OpenCode 가 절대 적용하지 않습니다. 아래 행은 실제로 적용되는 값이 아닙니다. 겹치는 두 패턴에는 정답인 순서가 없으므로, 아래 네이티브 JSON 에서 더 넓은 쪽을 앞으로 옮기세요.", - "fixOrder": "순서 수정", - "agentOverrides": "다음 에이전트가 권한을 재정의하며 마지막에 적용되므로 여기 설정보다 우선합니다: {agents}. 아래 네이티브 JSON 에서 수정하거나 자동 수락을 켜서 지우세요.", - "legacyTools": "최상위 레거시 tools 설정이 어떤 도구를 거부하고 있습니다. OpenCode 가 이를 권한에 합치므로 여기 표시된 모든 설정 위에 적용됩니다. 아래 네이티브 JSON 에서 수정하거나 자동 수락을 켜서 지우세요.", - "autoAcceptTitle": "모든 권한 자동 수락", - "autoAcceptHint": "셸 명령, 파일 수정, 프로젝트 밖 경로를 포함한 모든 도구 호출을 묻지 않고 실행합니다. 켜면 아래 도구별 설정이 전체 허용 규칙 하나로 대체되고, 그대로 두면 계속 막을 에이전트별 권한 재정의와 레거시 tools 설정도 지워집니다.", - "globalLabel": "전역 기본값", - "globalHint": "* 규칙입니다. 아래 도구에서 따로 지정하지 않은 모든 경우에 적용됩니다.", - "actionUnset": "설정 안 함 (OpenCode 기본값)", - "actionInherit": "기본값 따름 ({action})", - "actionAllow": "허용", - "actionAsk": "확인", - "actionDeny": "거부", - "perToolTitle": "도구별 권한", - "reset": "초기화", - "ruleCount": "규칙: {count}", - "rulesToggle": "{tool} 의 세부 규칙", - "rulesHint": "도구 입력과 대조하며 마지막으로 일치한 규칙이 우선하므로 넓은 패턴을 먼저 적으세요. * 는 임의의 문자열, ? 는 정확히 한 글자와 일치하고 맨 앞의 ~ 는 홈 디렉터리로 확장됩니다.", - "noRules": "아직 세부 규칙이 없습니다.", - "addRule": "규칙 추가", - "deleteRule": "규칙 {pattern} 삭제", - "duplicateRule": "이미 있는 패턴입니다.", - "blankRule": "규칙에는 패턴이 필요합니다. 삭제하려면 휴지통 아이콘을 사용하세요.", - "customKeys": "파일에 있는 다른 권한 키", - "customKeyHint": "OpenCode 기본 도구가 아니며 작성된 그대로 유지됩니다.", - "keys": { - "bash": "셸 명령 실행, 파싱된 명령으로 대조", - "edit": "모든 파일 수정: edit, write, patch", - "read": "파일 읽기, 경로로 대조", - "external_directory": "프로젝트 작업 디렉터리 밖 경로 접근", - "task": "서브에이전트 실행, 서브에이전트 유형으로 대조", - "skill": "스킬 로드, 스킬 이름으로 대조", - "glob": "파일 찾기, 글로브 패턴으로 대조", - "grep": "파일 내용 검색, 패턴으로 대조", - "list": "디렉터리 내용 나열", - "webfetch": "URL 가져오기", - "websearch": "웹 검색", - "lsp": "LSP 질의 실행", - "todowrite": "할 일 목록 작성", - "question": "사용자에게 질문", - "doom_loop": "같은 호출이 같은 입력으로 3 번 반복되면 작동" - } - } - }, - "openClaw": { - "gatewayConfig": "Gateway 구성", - "gatewayDescription": "OpenClaw Gateway 연결을 구성합니다. 로컬 또는 원격 gateway를 지원합니다.", - "gatewayUrlHint": "비워두면 로컬 openclaw 설정의 gateway.remote.url을 사용합니다.", - "gatewayTokenPlaceholder": "Gateway 인증 토큰", - "gatewayTokenHint": "가능하면 평문 토큰 대신 token-file을 사용하세요. openclaw CLI로 설정하세요.", - "sessionKeyHint": "선택 사항입니다. gateway 세션 키를 지정합니다. 비워두면 격리된 세션이 자동 할당됩니다." - }, - "hermes": { - "configManagement": "Hermes 구성", - "configDescription": "Hermes는 자격 증명을 ~/.hermes/.env에, 설정을 ~/.hermes/config.yaml에 직접 관리합니다. 공급자를 선택한 다음 API 키와 모델을 설정하세요. codeg가 두 파일을 모두 작성해 줍니다.", - "providerLabel": "공급자", - "providerHint": "공급자에 따라 Hermes가 사용하는 API 키 변수와 model.provider가 결정됩니다. OAuth 공급자는 아래 터미널 설정을 통해 구성합니다.", - "groupApiKey": "API 키 제공자", - "groupOauth": "OAuth 제공자", - "groupAws": "AWS", - "apiKeyHint": "~/.hermes/.env에 저장됩니다. 프로세스에 절대 주입되지 않으며, Hermes가 자체 구성에서 읽어옵니다.", - "modelName": "모델", - "oauthHint": "이 공급자는 OAuth를 사용합니다. 아래 설정을 실행하여 터미널에서 인증하세요.", - "awsHint": "Bedrock은 AWS 자격 증명(환경 변수 또는 공유 구성)을 사용합니다. 위에서 모델 ID를 설정하고 환경에서 AWS 액세스를 구성하세요.", - "unsupportedProvider": "이 제공자는 구조화된 필드로 편집할 수 없습니다. 아래의 config.yaml 원본 편집기나 터미널 설정을 사용하세요.", - "setupTitle": "자체 관리 설정", - "setupHint": "Hermes의 대화형 설정에는 터미널이 필요합니다. 아래에서 실행하거나 명령을 복사하여 직접 실행하세요.", - "runSetup": "Hermes 설정 실행", - "configureModel": "모델 구성", - "openConfigFolder": "~/.hermes 열기", - "copyCommand": "명령 복사", - "commandCopied": "명령을 클립보드에 복사했습니다", - "advancedTitle": "고급: config.yaml 편집", - "rawConfigHint": "~/.hermes/config.yaml을 직접 편집합니다. 여기서 저장하면 파일이 그대로 덮어쓰여집니다.", - "saveRawConfig": "config.yaml 저장" - }, - "codebuddy": { - "configManagement": "CodeBuddy 구성", - "configDescription": "CodeBuddy는 API 키로 인증합니다. 중국 버전은 환경을 ‘중국(internal)’으로 설정해야 하며, iOA 버전은 ‘iOA’를 사용하고, 해외 버전은 설정하지 않습니다.", - "apiKeyLabel": "API 키", - "apiKeyHint": "이 에이전트의 CODEBUDDY_API_KEY로 저장됩니다. 또는 터미널에서 CodeBuddy CLI로 로그인할 수도 있습니다.", - "apiKeyHintSelfHosted": "이 에이전트의 CODEBUDDY_API_KEY로 저장됩니다. 비공개 배포에서 발급한 키를 사용하세요.", - "environmentLabel": "환경", - "environmentHint": "CODEBUDDY_INTERNET_ENVIRONMENT를 설정합니다. 중국 본토는 ‘중국(internal)’을 사용해야 하며, 해외 버전은 설정하지 않습니다.", - "envOverseas": "해외(기본값)", - "envChina": "중국(internal)", - "envIoa": "iOA", - "envSelfHosted": "프라이빗 배포(자체 호스팅)", - "baseUrlLabel": "배포 URL", - "baseUrlPlaceholder": "https://codebuddy.your-company.com", - "baseUrlHint": "CODEBUDDY_BASE_URL로 저장되어 CodeBuddy를 비공개 엔드포인트로 연결합니다. 자체 호스팅에서는 네트워크 환경(CODEBUDDY_INTERNET_ENVIRONMENT)을 설정하지 않습니다.", - "baseUrlInvalid": "유효한 http(s) URL을 입력하세요.", - "loginHint": "API 키가 없나요? 터미널에서 ‘codebuddy’를 실행하여 Tencent 계정으로 로그인할 수도 있습니다." - }, - "kimiCode": { - "configManagement": "Kimi Code 설정", - "configDescription": "`kimi acp`는 저장된 로그인 토큰만 인정하므로, codeg가 ~/.kimi-code/config.toml에 관리형 공급자를 기록하고 로컬에 게이트 토큰을 심습니다. 추론은 여전히 사용자의 키로 실행됩니다.", - "statusUnconfigured": "아직 설정되지 않음", - "statusDirty": "저장되지 않은 변경 사항", - "summaryLabel": "적용된 설정", - "gateReadyApiKey": "API 키가 config.toml에 기록됨", - "gateReadyLogin": "Kimi 계정으로 로그인됨", - "revealConfig": "폴더에서 보기", - "envOverrideWarning": "{keys}이(가) 설정되어 있으며 config.toml보다 우선합니다. 여기서 저장하면 자동으로 삭제됩니다.", - "authModeLabel": "인증 방식", - "authModeApiKey": "API 키", - "authModeLogin": "Kimi 계정 로그인(구독)", - "authModeApiKeyHint": "config.toml에 관리형 공급자를 기록하고, 세션이 열리도록 게이트 토큰을 심습니다.", - "loginHint": "터미널에서 `kimi login`을 실행해 Kimi 구독 계정으로 로그인하세요. codeg는 자격 증명을 저장하지 않고 Kimi 자체 로그인을 재사용합니다. 여기서 저장하면 codeg의 API 키 게이트 토큰이 제거됩니다.", - "credentialTitle": "자격 증명", - "interfaceTypeLabel": "공급자 유형", - "interfaceTypeHint": "Kimi가 사용하는 공급자 프로토콜(config.toml의 `type`). Moonshot / platform.kimi.com 키라면 「Kimi / Moonshot」을 선택하세요.", - "endpointLabel": "엔드포인트", - "endpointCustom": "사용자 지정(OpenAI 호환)", - "endpointHint": "국제 = api.moonshot.ai, 중국(platform.kimi.com 키) = api.moonshot.cn. 사용자 지정은 모든 OpenAI 호환 엔드포인트를 가리킬 수 있습니다.", - "regionInternational": "국제(api.moonshot.ai)", - "regionChina": "중국(api.moonshot.cn)", - "baseUrlLabel": "Base URL", - "baseUrlHint": "비워 두면 공급자 SDK 기본값을 사용합니다.", - "apiKeyLabel": "API 키", - "apiKeyHint": "~/.kimi-code/config.toml에 기록되어 추론에 사용됩니다. platform.kimi.com 또는 platform.kimi.ai에서 발급받습니다.", - "vertexProjectLabel": "GCP 프로젝트(GOOGLE_CLOUD_PROJECT)", - "vertexLocationLabel": "GCP 리전(GOOGLE_CLOUD_LOCATION)", - "vertexHint": "Vertex AI는 Google 애플리케이션 기본 자격 증명을 사용합니다. `gcloud auth application-default login`을 실행하세요(API 키 불필요).", - "modelTitle": "모델", - "modelLabel": "모델", - "modelHint": "config.toml에 기록되는 모델 id입니다. 「테스트 후 모델 가져오기」로 키가 실제로 접근 가능한 모델을 확인하세요.", - "maxContextLabel": "최대 컨텍스트 길이", - "maxContextHint": "Kimi 스키마에서 필수입니다. 값이 없으면 Kimi가 모델 블록 전체를 버려 모든 프롬프트가 응답 없이 끝납니다. 기본값은 262144입니다.", - "fetchModels": "테스트 후 모델 가져오기", - "fetchModelsOk": "키 정상 — 모델 {count}개 사용 가능", - "fetchModelsEmpty": "키는 정상이지만 반환된 모델이 없습니다", - "fetchModelsFailed": "테스트 실패", - "fetchModelsNeedsKey": "먼저 API 키와 엔드포인트를 입력하세요", - "modelNotInList": "이 모델은 키가 접근할 수 있는 목록에 없습니다. Kimi가 「모델을 찾을 수 없음」으로 실패합니다.", - "reasoningTitle": "추론", - "reasoningEnableLabel": "사용", - "reasoningDescription": "모델이 추론 기능을 선언한 경우에만 Kimi가 입력창에 「Thinking」선택기를 표시하므로, codeg가 여기서 그 선언을 기록합니다. 새 세션부터 적용됩니다.", - "effortsLabel": "제공할 단계", - "effortsHint": "여기서 고른 값이 입력창 「Thinking」선택기의 항목이 됩니다. Kimi는 단계를 공급자에게 그대로 전달하므로 모델이 받아들이는 값을 고르세요.", - "effortsEmptyHint": "단계를 하나도 고르지 않으면 입력창은 Off / On 2단 토글로 축소됩니다.", - "effortsCustomPlaceholder": "다른 단계 추가", - "effortsAdd": "추가", - "defaultEffortLabel": "기본 단계", - "defaultEffortAuto": "Kimi에 맡기기", - "alwaysThinkingLabel": "모델이 항상 추론함 — 선택기에서 Off 항목 제거", - "fixErrorsFirst": "먼저 표시된 항목을 수정하세요", - "errorModelRequired": "모델은 필수 항목입니다", - "errorMaxContextRequired": "최대 컨텍스트 길이는 필수 항목입니다", - "errorMaxContextInvalid": "양의 정수여야 합니다", - "errorApiKeyRequired": "API 키는 필수 항목입니다", - "errorApiKeyInvalid": "API 키에는 줄바꿈을 포함할 수 없습니다", - "errorBaseUrlRequired": "Base URL은 필수 항목입니다", - "errorBaseUrlInvalid": "http:// 또는 https://로 시작해야 합니다", - "errorVertexProjectRequired": "GCP 프로젝트는 필수 항목입니다", - "errorDefaultEffortUnlisted": "위에서 선택한 단계 중 하나여야 합니다", - "advancedTitle": "고급", - "authTypeLabel": "자격 증명 기록 위치", - "authTypeApiKey": "인라인 api_key", - "authTypeEnv": "공급자 env 하위 테이블", - "authTypeHint": "config.toml 안에서 API 키를 기록할 위치입니다.", - "rawEditorLabel": "config.toml 직접 편집", - "rawEditorWarning": "여기서 저장하면 파일 전체가 그대로 덮어써져 위의 구조화된 설정이 대체됩니다.", - "rawEditorPlaceholder": "[providers.codeg]\ntype = \"kimi\"\nbase_url = \"https://api.moonshot.cn/v1\"\napi_key = \"sk-...\"" - }, - "authModeOfficialSubscription": "공식 구독", - "authModeCustomEndpoint": "사용자 정의 엔드포인트", - "authModeCustomEndpointHint": "API URL과 API Key를 수동으로 구성하여 사용자 정의 엔드포인트에 연결합니다.", - "authModeModelProvider": "모델 공급자", - "modelProvider": "모델 공급자", - "modelProviderHint": "구성된 모델 공급자의 API URL, API Key 및 모델을 사용합니다.", - "selectModelProvider": "모델 공급자 선택", - "noModelProviderAvailable": "이 에이전트에 구성된 모델 공급자가 없습니다. 모델 공급자 설정에서 추가하세요.", - "claude": { - "authMode": "인증 방식", - "officialSubscription": "공식 구독", - "officialSubscriptionHint": "Anthropic 공식 구독 사용, API Key 불필요.", - "mainModel": "메인 모델", - "reasoningModel": "추론 모델 (thinking)", - "haikuDefaultModel": "기본 Haiku 모델", - "sonnetDefaultModel": "기본 Sonnet 모델", - "opusDefaultModel": "기본 Opus 모델", - "customModelOption": "사용자 지정 모델 ID", - "customModelOptionName": "사용자 지정 모델 이름", - "customModelOptionDescription": "사용자 지정 모델 설명", - "customModelOptionHint": "Claude 모델 선택기에 사용자 지정 항목 하나를 추가합니다(예: 사용자 지정 게이트웨이/프록시를 통해 제공되는 모델). 이름과 설명은 선택적 표시 설정입니다.", - "effortLevel": "추론 수준", - "effortLevelDefault": "기본 수준", - "effortLevel_low": "낮음", - "effortLevel_medium": "중간", - "effortLevel_high": "높음", - "effortLevel_xhigh": "매우 높음", - "sendAttributionHeader": "API에 속성/청구 식별자 전송", - "sendAttributionHeaderAria": "API에 Claude Code 속성/청구 식별자 전송", - "disableNonessentialTraffic": "텔레메트리 또는 불필요한 네트워크 요청 비활성화", - "disableNonessentialTrafficAria": "Claude Code 텔레메트리 또는 불필요한 네트워크 요청 비활성화" - }, - "dialogs": { - "confirmDeleteProvider": "Provider {providerId}를 삭제하시겠습니까?", - "confirmDeleteProviderDescription": "OpenCode config와 auth JSON이 함께 업데이트됩니다. 이 작업은 되돌릴 수 없습니다.", - "confirmUninstall": "{name}을(를) 제거하시겠습니까?", - "confirmUninstallDescription": "로컬 설치 버전을 제거합니다. 나중에 다시 설치할 수 있습니다.", - "customInstallTitle": "{name} 사용자 지정 설치", - "customInstallDescription": "설치할 버전을 입력하세요. 다시 설치되며 현재 설치된 버전을 대체합니다.", - "customInstallVersionLabel": "버전 번호", - "customInstallInvalid": "유효한 버전 번호를 입력하세요. 예: 1.2.3", - "customInstallSubmit": "설치" - }, - "errors": { - "windowsFileLocked": "{name}의 파일이 실행 중인 세션에서 사용 중이어서 Windows에서 교체할 수 없습니다. 모든 {name} 세션을 닫은 후 다시 시도하세요.", - "nativeJsonMustBeObject": "네이티브 JSON 구성은 객체여야 합니다", - "nativeJsonInvalid": "네이티브 JSON 구성 형식 오류: {message}", - "openCodeAuthMustBeObject": "OpenCode auth.json은 JSON 객체여야 합니다", - "openCodeAuthInvalid": "OpenCode auth.json 형식 오류: {message}", - "authMustBeObject": "auth.json은 JSON 객체여야 합니다", - "authInvalid": "auth.json 형식 오류: {message}", - "providerIdPattern": "Provider ID는 문자, 숫자, 밑줄, 점, 하이픈만 지원합니다", - "providerExists": "Provider {providerId}가 이미 존재합니다", - "modelIdPattern": "Model ID는 문자, 숫자, 밑줄, 점, 콜론, 하이픈만 지원합니다", - "modelExists": "Model {modelId}가 이미 존재합니다" - }, - "warnings": { - "nativeJsonRecoveredStructured": "네이티브 JSON 구성이 잘못되어 구조화 구성으로 재설정했습니다", - "nativeJsonRecoveredOpenCode": "네이티브 JSON 구성이 잘못되어 OpenCode 구조화 구성으로 재설정했습니다", - "openCodeAuthRecovered": "OpenCode auth.json이 잘못되어 기본 구성으로 재설정했습니다", - "authRecoveredStructured": "auth.json이 잘못되어 구조화 구성으로 재설정했습니다" - }, - "toasts": { - "agentActionCompleted": "{name} {action} 완료", - "agentActionFailed": "{name} {action} 실패", - "localVersion": "로컬 버전: {version}", - "installCompletedVersionLater": "설치가 완료되었습니다. 버전은 다음 확인 시 업데이트됩니다", - "uninstallCompleted": "{name} 제거 완료", - "uninstallFailed": "{name} 제거 실패", - "localVersionRemoved": "로컬 버전이 제거되었습니다", - "saveAgentOrderFailed": "Agent 순서 저장 실패", - "saveAgentSwitchFailed": "Agent 스위치 저장 실패", - "saveEnvFailed": "환경 변수 저장 실패", - "grokSaved": "Grok 설정이 저장됨", - "saveGrokNativeFailed": "Grok 네이티브 설정 저장 실패", - "saveGrokApiKeyFailed": "설정은 저장되었지만 API 키를 저장하지 못했습니다", - "cursorSaved": "Cursor 설정이 저장되었습니다", - "saveCursorConfigFailed": "Cursor 설정 저장 실패", - "codexSaved": "Codex 설정 저장됨", - "saveCodexNativeFailed": "Codex 네이티브 구성 저장 실패", - "geminiSaved": "Gemini 설정 저장됨", - "saveGeminiFailed": "Gemini 설정 저장 실패", - "providerDeleted": "Provider {providerId} 삭제됨", - "providerDeleteFailed": "Provider {providerId} 삭제 실패", - "providerSaved": "Provider {providerId} 저장됨", - "saveProviderFailed": "Provider {providerId} 저장 실패", - "openCodeConfigSynced": "OpenCode config와 auth JSON이 동기화되었습니다.", - "openCodeSaved": "OpenCode 설정 저장됨", - "saveOpenCodeFailed": "OpenCode 설정 저장 실패", - "openClawSaved": "OpenClaw 설정 저장됨", - "saveOpenClawFailed": "OpenClaw 설정 저장 실패", - "configSaved": "구성이 저장되었습니다", - "configSavedHint": "기존 세션은 다시 열어야 적용됩니다", - "saveConfigManagementFailed": "구성 관리 저장 실패", - "clineSaved": "Cline 설정 저장됨", - "saveClineFailed": "Cline 설정 저장 실패", - "hermesSaved": "Hermes 설정 저장됨", - "saveHermesFailed": "Hermes 설정 저장 실패", - "codeBuddySaved": "CodeBuddy 구성이 저장되었습니다", - "saveCodeBuddyFailed": "CodeBuddy 구성 저장에 실패했습니다", - "kimiCodeSaved": "Kimi Code 구성이 저장되었습니다", - "saveKimiCodeFailed": "Kimi Code 구성 저장 실패", - "deepseekSaved": "DeepSeek 구성을 저장했습니다", - "saveDeepSeekFailed": "DeepSeek 구성 저장 실패", - "modelProviderRequired": "저장하기 전에 모델 공급자를 선택하세요.", - "affectedRunningSessions": "{count}개의 실행 중인 세션은 다시 연결하면 변경 사항이 적용됩니다", - "providerConnected": "{providerId} 연결됨", - "connectFailed": "{providerId} 연결 실패", - "providerDisconnected": "{providerId} 연결 해제됨", - "disconnectFailed": "{providerId} 연결 해제 실패", - "catalogRefreshed": "카탈로그를 새로고침했습니다 — 공급자 {count}개", - "catalogRefreshFailed": "카탈로그 새로고침 실패", - "piSaved": "Pi 설정이 저장됨", - "savePiFailed": "Pi 설정 저장 실패", - "piRuntimeSaved": "Pi 런타임이 저장됨", - "savePiRuntimeFailed": "Pi 런타임 저장 실패", - "piBinaryInstalled": "pi 설치됨", - "piBinaryInstallFailed": "pi 설치 실패", - "piBinaryUninstalled": "pi 제거됨", - "piBinaryUninstallFailed": "pi 제거 실패", - "savePiTrustFailed": "작업 공간 신뢰 저장 실패" - }, - "version": { - "statusLabel": "버전 상태", - "notInstalled": "설치되지 않음", - "remoteLocal": "원격: {remoteVersion} · 로컬: {localVersion}", - "localOnly": "로컬: {localVersion}", - "localInstalled": "{versionText}. 설치되어 있습니다.", - "platformUnsupported": "{versionText}. 현재 플랫폼에서는 이 에이전트를 지원하지 않습니다.", - "uvxNotReady": "{versionText}. uv 런타임이 설치되지 않았습니다. 아래 uv 검사에서 설치하면 이 에이전트를 사용할 수 있습니다.", - "clickInstall": "{versionText}. 오른쪽의 설치를 클릭하세요.", - "localUnrecognized": "{versionText}. 로컬 버전을 비교할 수 없습니다. 덮어쓰기 설치를 위해 업그레이드를 시도하세요.", - "upgradeAvailable": "{versionText}. 업그레이드가 가능합니다.", - "remoteUnavailable": "{versionText}. 현재 원격 버전을 사용할 수 없습니다.", - "latest": "{versionText}. 이미 최신입니다." - }, - "adapter": { - "label": "ACP 어댑터", - "badge": "ACP 어댑터", - "badgeHint": "이 에이전트에 대해 Codeg가 설치하는 것은 벤더 CLI가 아니라 ACP 어댑터 패키지입니다. 둘은 서로 독립적이며 설정을 공유합니다.", - "learnMore": "자세히 보기", - "missingWithNative": "사용 중인 {nativeLabel}을(를) {nativePath}에서 찾았습니다. Codeg는 에이전트를 ACP로 구동하는데 이 CLI 자체는 ACP를 지원하지 않으므로, 별도의 어댑터 패키지 {adapterPackage}(Agent Client Protocol 프로젝트가 관리, 처음에는 Zed 팀)가 필요합니다. 자체 런타임을 포함하고 있어 기존 {nativeCmd} 명령을 수정하거나 대체하지 않으며, 같은 {configDir}를 읽으므로 기존 로그인과 설정이 그대로 적용됩니다. 아래에서 설치하세요.", - "missing": "Codeg는 에이전트를 ACP로 구동하는데 {nativeLabel} 자체는 ACP를 지원하지 않으므로, 별도의 어댑터 패키지 {adapterPackage}(Agent Client Protocol 프로젝트가 관리, 처음에는 Zed 팀)가 필요합니다. 자체 런타임을 포함하므로 {nativeCmd} CLI를 먼저 설치할 필요는 없습니다. 이미 설치했다면 둘은 공존하며 {configDir}의 로그인과 설정을 공유합니다. 아래에서 설치하세요.", - "readyWithNative": "어댑터 {adapterCmd}가 설치되어 있습니다. Codeg가 실행하는 것은 이 어댑터이며, {nativePath}에 있는 사용자의 {nativeCmd}가 아닙니다. 둘은 독립된 패키지로 공존하고 모두 {configDir}를 읽으므로 로그인과 설정을 공유합니다.", - "ready": "어댑터 {adapterCmd}가 설치되어 있으며 Codeg가 실행하는 것이 바로 이것입니다. 자체 런타임을 포함하므로 {nativeLabel}은 필요하지 않습니다. 나중에 설치해도 둘은 공존하며 {configDir}를 공유합니다." - }, - "cline": { - "configDescription": "Cline API 제공자와 자격 증명을 구성합니다. 설정은 ~/.cline/data/에 저장됩니다." - }, - "opencodePlugins": { - "title": "OpenCode 플러그인", - "declared": "선언된 플러그인", - "noPlugins": "opencode.json에 선언된 플러그인이 없습니다", - "status": { - "installed": "설치됨", - "missing": "미설치" - }, - "installAll": "누락된 플러그인 모두 설치", - "pinVersions": "@latest 버전 고정", - "install": "설치", - "uninstall": "제거", - "refresh": "새로고침", - "success": "모든 플러그인이 성공적으로 설치되었습니다", - "failed": "플러그인 작업 실패" - }, - "pi": { - "configManagement": "Pi 설정", - "configDescription": "Pi는 모델 제공자의 API 키로 인증합니다. 키는 ~/.pi/agent/auth.json에, 모델 선택은 settings.json에 저장됩니다.", - "providerLabel": "제공자", - "modelLabel": "모델", - "thinkingLabel": "사고", - "thinking": { - "off": "끔", - "low": "낮음", - "medium": "중간", - "high": "높음", - "minimal": "최소", - "xhigh": "매우 높음" - }, - "apiKeyLabel": "API 키", - "apiKeyHint": "선택한 제공자의 ~/.pi/agent/auth.json에 저장됩니다.", - "apiKeySetPlaceholder": "••••••(저장됨 · 비워두면 유지)", - "saveConfig": "Pi 설정 저장", - "providerModelRequired": "제공자와 모델은 필수입니다", - "runtimeTitle": "런타임", - "runtimeDescription": "어떤 pi를 실행할지 선택합니다. 기본값을 사용하거나 자신의 pi 빌드를 지정하세요.", - "modeDefault": "기본 pi", - "modeDefaultHint": "내장 pi-acp 어댑터로 PATH의 pi를 실행합니다. pi 설치: npm install -g @earendil-works/pi-coding-agent", - "modeCustom": "사용자 지정 pi", - "modeCustomHint": "자신의 pi 빌드, 설치 또는 래퍼를 실행합니다.", - "commandLabel": "pi 명령 또는 경로", - "commandHint": "절대 경로, PATH의 명령 이름 또는 래퍼 스크립트(예: 모노레포의 ./pi-test.sh).", - "commandNotFound": "명령을 찾을 수 없음", - "validate": "검증", - "advanced": "고급", - "configDirLabel": "설정 디렉터리 (PI_CODING_AGENT_DIR)", - "sessionDirLabel": "세션 디렉터리 (PI_CODING_AGENT_SESSION_DIR)", - "flagsHint": "pi-acp는 사용자 지정 pi 플래그(--approve, -e 등)를 전달하지 않습니다. pi를 스크립트로 감싸고 명령이 이를 가리키도록 하세요.", - "customIncomplete": "저장하려면 pi 명령을 입력하세요", - "saveRuntime": "런타임 저장", - "providerPlaceholder": "제공자 선택", - "customProvider": "사용자 지정 제공자…", - "providerIdLabel": "제공자 ID", - "apiProtocolLabel": "API 프로토콜", - "baseUrlLabel": "API 엔드포인트(Base URL)", - "customProviderHint": "~/.pi/agent/models.json에 엔드포인트용 제공자를 정의합니다. 대부분의 자체 호스팅 또는 프록시 서버는 openai-completions를 사용합니다.", - "baseUrlRequired": "API 엔드포인트(Base URL)는 필수입니다", - "binaryTitle": "pi 바이너리 (pi-coding-agent)", - "binaryDescription": "pi-acp가 이 pi 바이너리를 실행합니다. 여기서 설치하거나 아래에서 직접 빌드한 pi를 지정하세요.", - "binaryInstalled": "설치됨", - "binaryMissing": "설치되지 않음", - "binaryChecking": "확인 중…", - "installBinary": "pi 설치", - "installing": "설치 중…", - "recheck": "다시 확인", - "configDirSkillsNote": "사용자 지정 구성 디렉터리를 설정하면 설정에서 관리하는 스킬, 전문가, 오피스 도구가 이 pi에 적용되지 않습니다. 해당 폴더에서 스킬을 직접 관리하세요.", - "projectTrustTitle": "프로젝트 신뢰", - "projectTrustDescription": "pi가 프로젝트 파일을 불러오도록 허용한 폴더입니다. 신뢰한 폴더에서는 해당 저장소의 .pi/extensions가 pi 시작 시 코드를 실행하며, 그 아래 모든 폴더에 적용되고 터미널에서 pi를 실행할 때에도 사용됩니다.", - "projectTrustLoading": "불러오는 중…", - "projectTrustEmpty": "아직 결정한 폴더가 없습니다.", - "projectTrustTrusted": "신뢰함", - "projectTrustDenied": "신뢰 안 함", - "projectTrustRevoke": "취소", - "reasoningTitle": "추론", - "reasoningEnableLabel": "사용", - "reasoningDescription": "모델이 추론 기능을 선언한 경우에만 pi가 추론 강도를 보냅니다. 선언하지 않은 모델은 모든 단계가 Off로 고정되어, 입력창의 선택기가 건드리는 즉시 되돌아갑니다. models.json의 해당 모델 항목에 기록됩니다.", - "levelsLabel": "선택 가능한 단계", - "levelsHint": "입력창 추론 선택기의 항목이 됩니다. 엔드포인트가 받아들이는 값을 고르세요. 여기 없는 단계는 pi가 거부합니다.", - "levelsEmptyError": "단계를 하나 이상 선택하세요. 하나도 없으면 pi는 Off로 되돌아갑니다.", - "wireValuesTitle": "고급: 공급자에게 보내는 값", - "wireValuesHint": "비워 두면 단계 이름을 그대로 보냅니다. 엔드포인트가 다른 표기를 요구할 때만 설정하세요 — Google 계열은 LOW / HIGH가 필요합니다.", - "defaultLevelUnlisted": "이 단계는 위 선택 목록에 없습니다 — pi가 낮춰 버립니다." - }, - "addCustomAgent": "사용자 지정 에이전트 추가", - "addCustomAgentHint": "ACP를 지원하는 모든 에이전트를 등록할 수 있습니다. 공개 ACP 레지스트리에서 선택하거나 레지스트리 정보를 붙여넣으세요.", - "customAgentFromRegistry": "ACP 레지스트리", - "customAgentManual": "직접 입력", - "customAgentSearchPlaceholder": "에이전트 검색…", - "customAgentLoadingCatalog": "ACP 레지스트리를 불러오는 중…", - "customAgentRetry": "다시 시도", - "customAgentNoResults": "일치하는 에이전트가 없습니다", - "customAgentAdd": "추가", - "customAgentAlreadyAdded": "추가됨", - "customAgentUnsupportedPlatform": "이 플랫폼용 빌드가 없습니다", - "customAgentAdded": "{name} 추가됨", - "customAgentIdLabel": "레지스트리 ID", - "customAgentNameLabel": "표시 이름", - "customAgentVersionLabel": "버전", - "customAgentSpecLabel": "배포 정보(JSON)", - "customAgentSpecHint": "ACP 레지스트리의 distribution 객체와 동일한 형식입니다. npx·uvx·binary 채널을 지원하며 레지스트리 항목 전체를 붙여넣어도 됩니다. npx/uvx의 cmd는 패키지가 설치하는 실행 명령 이름으로, 생략하면 패키지 이름에서 유도되므로 서로 다를 때는 지정하세요. binary는 플랫폼 키로 구분하며(이 컴퓨터: {platform}) cmd는 아카이브 내 실행 경로, sha256은 선택 사항으로 다운로드를 검증합니다.", - "customAgentTemplateLabel": "템플릿", - "customAgentKindLabel": "실행 방식", - "customAgentInvalidJson": "올바른 JSON이 아닙니다", - "customAgentNoDistribution": "npx, uvx, binary 배포를 찾을 수 없습니다", - "customAgentCancel": "취소", - "customAgentSave": "에이전트 추가", - "customAgentSaveChanges": "변경 사항 저장", - "customAgentEdit": "에이전트 편집", - "customAgentEditHint": "이름, 아이콘, 배포 정보, 스킬 선언을 수정할 수 있습니다. 에이전트 ID는 변경할 수 없습니다.", - "customAgentEditNotFound": "커스텀 에이전트 {id}을(를) 찾을 수 없습니다", - "customAgentSaved": "{name} 저장됨", - "customAgentVersionProbeLabel": "버전 조회 명령(선택)", - "customAgentVersionProbeHint": "로컬에 설치된 버전을 출력하는 명령입니다. 비워 두면 에이전트 명령에 --version을 붙여 실행합니다.", - "customAgentRemove": "에이전트 제거", - "customAgentRemoveHint": "에이전트 정의를 삭제합니다. 기존 대화 기록은 유지되며 에이전트를 더 이상 실행할 수 없게 될 뿐입니다.", - "customAgentIconLabel": "아이콘(선택)", - "customAgentIconUpload": "업로드", - "customAgentIconReplace": "변경", - "customAgentIconClear": "아이콘 제거", - "customAgentIconHint": "에이전트와 함께 저장되어 오프라인에서도 표시됩니다. 지정하지 않으면 색상 이니셜을 사용합니다.", - "customAgentSkillsLabel": "Skills(공유 .agents/skills)", - "customAgentSkillsHint": "이 에이전트가 공유 .agents/skills 디렉터리(전역 및 프로젝트)를 읽는다고 선언하고 모든 스킬 매트릭스에 추가합니다. 공유 디렉터리에 연결된 스킬은 해당 디렉터리를 읽는 다른 에이전트에게도 보입니다.", - "customAgentSkillsDirLabel": "전용 스킬 디렉터리", - "customAgentSkillsDirHint": "이 에이전트가 스킬을 불러오는 디렉터리의 절대 경로입니다. 공유 저장소와 함께 또는 단독으로 사용할 수 있습니다. ~ 는 홈 디렉터리로 확장되며, 연결된 스킬은 이 디렉터리에 우선 배치됩니다.", - "customAgentMcpLabel": "MCP 지원", - "customAgentMcpHint": "세션을 시작할 때 codeg 내장 codeg-mcp 동반 프로세스를 이 에이전트에 전달합니다. 위임, 실시간 피드백, 작업 도구가 이 채널을 사용합니다. MCP 서버를 거부해 연결에 실패하는 에이전트라면 꺼 두세요. 변경은 다음 연결부터 적용됩니다.", - "customAgentIconNotAnImage": "이미지 파일을 선택하세요.", - "customAgentIconTooLarge": "아이콘은 {limit} KB 미만이어야 합니다.", - "customAgentIconReadFailed": "해당 이미지를 읽을 수 없습니다.", - "customAgentRemoveConfirm": "{name}을(를) 제거할까요? 기존 대화는 유지되지만 더 이상 실행할 수 없습니다.", - "customAgentRemoveWithData": "기록된 대화 기록도 삭제", - "customAgentRemoved": "{name} 제거됨", - "customAgentBadge": "사용자 지정", - "customAgentNotLaunchable": "이 환경에서는 실행할 수 없습니다: {reason}" - }, - "SettingsPages": { - "agentsLoading": "에이전트 설정을 불러오는 중...", - "skillPacksLoading": "스킬 팩 로딩 중…" - }, - "GeneralSettings": { - "loading": "로딩 중...", - "sectionTitle": "일반", - "sectionDescription": "기본 터미널, 렌더링 가속, 다중 에이전트 위임 등 공용 환경설정을 한곳에서 관리합니다.", - "terminalTitle": "기본 터미널", - "terminalDescription": "터미널 바나 파일 트리에서 새 터미널 탭을 열 때 사용할 셸을 선택합니다. 에이전트가 codeg에 전체 명령줄 실행을 요청할 때도 사용됩니다.", - "terminalSystemDefault": "시스템 기본값", - "terminalPowerShell7": "PowerShell 7 (pwsh)", - "terminalWindowsPowerShell": "Windows PowerShell", - "terminalCmd": "명령 프롬프트 (cmd)", - "terminalSaveFailed": "터미널 설정 저장 실패: {message}", - "terminalShellCustom": "사용자 지정 경로", - "terminalShellCustomPath": "Shell 경로", - "terminalShellCustomPlaceholder": "/usr/local/bin/fish", - "terminalShellCustomSave": "저장", - "terminalShellCustomHint": "절대 경로 또는 PATH에서 찾을 수 있는 명령 이름을 입력하세요.", - "terminalShellNotInstalled": "설치되지 않음", - "terminalShellNotFoundWarning": "이 경로는 현재 호스트에 존재하지 않습니다.", - "terminalCurrentShell": "현재 사용 중: {path}", - "renderingDescription": "앱이 검은 화면이 되거나 렌더링 문제가 발생하면(일부 AMD GPU 또는 Intel 내장 GPU에서 보고됨) 하드웨어 가속을 끄세요. Windows 데스크톱에서만 적용됩니다.", - "disableHardwareAcceleration": "하드웨어 가속 비활성화", - "renderingSaveFailed": "렌더링 설정 저장 실패: {message}", - "restartRequired": "저장되었습니다. 변경 사항을 적용하려면 앱을 다시 시작하세요.", - "restartNow": "지금 다시 시작", - "restartFailed": "다시 시작 실패: {message}", - "loadFailed": "불러오기 실패: {message}" - }, - "LoginPage": { - "documentTitle": "로그인 - codeg", - "brand": "Codeg", - "subtitle": "데스크톱 앱에 연결하려면 액세스 토큰을 입력하세요", - "tokenPlaceholder": "액세스 토큰", - "connect": "연결", - "connecting": "연결 중...", - "helpText": "토큰은 데스크톱 앱의 설정 → 웹 서비스에서 확인할 수 있습니다", - "invalidToken": "유효하지 않은 토큰입니다. 확인 후 다시 시도하세요", - "connectionFailed": "연결 실패 (HTTP {status})", - "networkError": "서버에 연결할 수 없습니다" - }, - "CommitPage": { - "title": "커밋", - "invalidFolderId": "유효하지 않은 폴더 ID", - "loadingRepo": "저장소를 불러오는 중..." - }, - "MergePage": { - "title": "충돌 해결", - "invalidFolderId": "잘못된 폴더 ID", - "loadingRepo": "저장소 로딩 중...", - "localVersion": "로컬 (우리 쪽)", - "result": "결과", - "remoteVersion": "원격 (상대 쪽)", - "acceptLocal": "로컬 적용", - "acceptRemote": "원격 적용", - "markResolved": "해결됨으로 표시", - "abortMerge": "중단", - "completeMerge": "병합 완료", - "unresolvedConflicts": "파일에 아직 해결되지 않은 충돌 마커가 있습니다", - "fileResolved": "파일이 해결되었습니다", - "allResolved": "모든 충돌이 해결되었습니다", - "conflictFiles": "충돌 파일", - "loadingFile": "파일 로딩 중...", - "preparingMerge": "병합 준비 중...", - "selectFile": "해결할 파일을 선택하세요", - "noConflicts": "충돌 파일 없음", - "skipFile": "건너뛰기", - "abortSuccess": "작업이 중단되었습니다", - "applyAllNonConflicting": "충돌하지 않는 모든 변경 적용", - "applyLeftNonConflicting": "로컬 적용", - "applyRightNonConflicting": "원격 적용" - }, - "ImportSessions": { - "title": "로컬 세션 가져오기", - "scanningTitle": "로컬 에이전트 세션 검색 중…", - "scanningHint": "각 에이전트의 로컬 세션 저장소를 탐색하고 있습니다. 기록이 많으면 시간이 걸릴 수 있습니다. 이미 가져온 세션은 이 과정에서 함께 갱신됩니다.", - "scanFailed": "검색 실패", - "retry": "다시 시도", - "rescan": "다시 검색", - "empty": "로컬 세션을 찾을 수 없습니다", - "emptyHint": "이 컴퓨터에서 에이전트 세션 저장소를 찾지 못했습니다.", - "noMatches": "현재 필터와 일치하는 세션이 없습니다", - "searchPlaceholder": "제목 또는 경로 검색…", - "allAgents": "모든 에이전트", - "onlyImportable": "가져오기 가능만", - "selectAll": "모두 선택", - "clearSelection": "지우기", - "expandAll": "모두 펼치기", - "collapseAll": "모두 접기", - "summaryCounts": "세션 {total}개 · 가져오기 가능 {importable}개 · 폴더 {folders}개", - "noFolderSkipped": "프로젝트 폴더가 없는 {count}개 건너뜀", - "folderNew": "신규", - "folderCounts": "가져오기 가능 {importable}/{total}", - "toggleFolderAria": "{name}의 가져오기 가능한 세션 모두 선택", - "toggleSessionAria": "세션 {title} 선택", - "statusImported": "가져옴", - "statusDeleted": "삭제됨", - "untitled": "제목 없는 세션", - "messageCount": "메시지 {count}개", - "selectedCount": "{count}개 선택됨", - "importSelected": "선택 항목 가져오기", - "importing": "가져오는 중…", - "close": "닫기", - "doneTitle": "가져오기 완료", - "doneImported": "가져옴", - "doneUpdated": "갱신됨", - "doneSkipped": "건너뜀", - "doneCreatedFolders": "생성된 폴더", - "doneNotFound": "찾을 수 없음", - "doneFailed": "실패", - "continueImport": "계속 가져오기", - "toasts": { - "importFailed": "가져오기 실패: {message}" - } - }, - "Folder": { - "workspaceStatus": { - "degradedTitle": "실시간 업데이트를 사용할 수 없음", - "degradedHint": "감시자 시작 실패(권한 거부 등). 최신 변경 사항을 보려면 수동으로 새로 고치세요.", - "retry": "다시 시도", - "retrying": "다시 시도 중..." - }, - "common": { - "all": "전체", - "cancel": "취소", - "close": "닫기", - "closeOthers": "다른 항목 닫기", - "closeAll": "모두 닫기", - "confirm": "확인", - "save": "저장", - "delete": "삭제", - "rename": "이름 변경", - "loading": "로딩 중...", - "refresh": "새로고침", - "refreshing": "새로고침 중...", - "create": "생성", - "createAndSwitch": "생성 후 전환", - "openFile": "파일 열기", - "viewDiff": "Diff 보기", - "push": "푸시..." - }, - "statusLabels": { - "in_progress": "진행 중", - "pending_review": "검토", - "completed": "완료", - "cancelled": "취소됨" - }, - "sidebar": { - "title": "대화", - "locateActiveConversation": "활성 대화 찾기", - "expandAllGroups": "모든 그룹 펼치기", - "collapseAllGroups": "모든 그룹 접기", - "newConversation": "새 대화", - "newConversationShort": "새로 만들기", - "newChat": "새 대화", - "search": "검색", - "noConversationsFound": "대화를 찾을 수 없습니다.", - "importLocalSessions": "로컬 세션 가져오기", - "importing": "가져오는 중...", - "error": "오류: {message}", - "completeAllSessions": "모든 세션 완료 처리", - "completeAllReviewTitle": "모든 검토 세션을 완료 처리할까요?", - "completeAllReviewDescription": "검토 상태의 {count, plural, one {#개 세션} other {#개 세션}}을 모두 완료로 표시합니다.", - "completing": "완료 처리 중...", - "toasts": { - "importedSessions": "{imported, plural, one {#개 세션} other {#개 세션}}을 가져오고 {skipped}개를 건너뛰었습니다", - "importedAndUpdated": "{imported, plural, one {#개 세션} other {#개 세션}}을 가져오고 {updated, plural, one {#개 제목} other {#개 제목}}을 업데이트하고 {skipped}개를 건너뛰었습니다", - "updatedTitles": "{updated, plural, one {#개 제목} other {#개 제목}}을 업데이트하고 {skipped}개를 건너뛰었습니다", - "noNewSessionsFound": "새 세션이 없습니다 ({skipped}개 건너뜀)", - "importFailed": "가져오기 실패: {message}", - "reviewCompleted": "{count, plural, one {#개 검토 세션} other {#개 검토 세션}}을 완료로 표시했습니다", - "completeReviewFailed": "검토 세션 완료 처리 실패: {message}", - "folderOpened": "폴더 {name}을(를) 열었습니다", - "folderRemoved": "폴더 {name}을(를) 제거했습니다", - "openFolderFailed": "폴더를 열 수 없습니다", - "removeFolderFailed": "폴더 제거 실패: {message}", - "reorderFoldersFailed": "폴더 순서 변경 실패: {message}", - "changeFolderColorFailed": "색상 변경 실패: {message}", - "setFolderAliasFailed": "별칭 설정 실패: {message}", - "changeFolderDefaultAgentFailed": "기본 에이전트 설정 실패: {message}" - }, - "statsLabel": "{folders}개 폴더 · {convos}개 대화", - "reorderHandle": "드래그하여 순서 변경", - "openFolder": "폴더 열기", - "searchPlaceholder": "대화 검색...", - "viewOptions": "보기 옵션", - "showCompleted": "완료된 대화 표시", - "showWorktrees": "워크트리 폴더 표시", - "showRecent": "'최근' 그룹 표시", - "moreOptions": "더 많은 옵션", - "sortBy": "정렬 기준", - "sortByCreatedAt": "생성 시간순", - "sortByUpdatedAt": "업데이트 시간순", - "sectionOrder": "섹션 순서", - "sectionOrderMoveUp": "위로 이동", - "sectionOrderMoveDown": "아래로 이동", - "sectionOrderItemLabel": "{name} — {total}개 중 {position}번째", - "statusRunningBadge": "실행 중", - "runningCountBadge": "{count}개 세션 실행 중", - "statusCancelledBadge": "취소됨", - "worktreeRemovedBadge": "원본 worktree가 삭제됨", - "conversationCountUnit": "{count}개", - "emptyFolderHint": "대화 없음", - "noMatchingConversations": "일치하는 대화가 없습니다", - "noUnfinishedConversations": "미완료 대화가 없습니다. 오른쪽 상단 메뉴에서 \"완료된 대화 표시\"를 활성화할 수 있습니다.", - "removeFolderConfirmTitle": "이 폴더를 워크스페이스에서 제거하시겠습니까?", - "removeFolderConfirmDescription": "워크스페이스에서 \"{name}\"을(를) 제거하시겠습니까? 관련 탭과 터미널이 닫힙니다.", - "folderHeaderMenu": { - "manageConversations": "대화 관리…", - "manageLinks": "연결된 폴더", - "changeColor": "색상 변경", - "useThemeColor": "앱 테마 사용", - "setDefaultAgent": "기본 에이전트 설정", - "defaultAgentNone": "설정 없음(전역 사용)", - "agentUnavailableSuffix": "(사용 불가)", - "loadingAgents": "에이전트 로드 중…", - "setAlias": "별칭 설정…", - "setAliasTitle": "폴더 별칭 설정", - "setAliasPlaceholder": "별칭 입력 (비우면 지움)", - "setAliasSave": "저장", - "setAliasCancel": "취소", - "removeFromWorkspace": "워크스페이스에서 제거" - }, - "manageConversations": { - "title": "대화 관리", - "searchPlaceholder": "제목으로 검색…", - "agentFilterAll": "모든 에이전트", - "statusFilterAll": "모든 상태", - "folderFilterAll": "모든 폴더", - "branchFilterAll": "모든 브랜치", - "branchNone": "브랜치 없음", - "branchSearchPlaceholder": "브랜치 검색…", - "noMatchingBranches": "일치하는 브랜치가 없습니다", - "selectAllVisible": "전체 선택", - "deselectAll": "선택 해제", - "selectedCount": "{count}개 선택됨", - "matchedCount": "{count}개 일치", - "untitledConversation": "제목 없는 대화", - "setStatus": "상태 변경…", - "deleteSelected": "삭제", - "noConversations": "이 폴더에 대화가 없습니다.", - "noConversationsWorkspace": "작업 공간에 대화가 없습니다.", - "noMatchingConversations": "필터에 일치하는 대화가 없습니다.", - "confirmDeleteTitle": "{count}개 대화를 삭제하시겠습니까?", - "confirmDeleteDescription": "이 작업은 되돌릴 수 없습니다.", - "toastDeleted": "{count}개 대화를 삭제했습니다", - "toastStatusUpdated": "{count}개 대화의 상태를 업데이트했습니다", - "toastOpFailed": "작업 실패: {message}" - }, - "sectionPinned": "고정됨", - "sectionFolders": "폴더", - "sectionChats": "채팅", - "sectionRecent": "최근", - "noChats": "채팅 없음", - "noRecent": "최근 대화 없음", - "showMoreRecent": "더 보기 ({count})", - "noFolders": "열린 폴더 없음", - "newChatAction": "새 채팅", - "automations": "자동화", - "tasks": "할 일", - "loadingSubsessions": "하위 대화 로드 중…" - }, - "conversation": { - "reloadFailed": "대화 다시 불러오기 실패: {message}", - "reloaded": "대화를 다시 불러왔습니다", - "reload": "다시 불러오기", - "activeConversationIndicator": "활성 대화", - "newConversation": "새 대화", - "closeConversation": "대화 닫기", - "copyText": "텍스트 복사", - "copyTextSuccess": "복사됨", - "copyTextFailed": "복사 실패", - "forkSession": "세션 포크", - "forkSessionSuccess": "세션 포크 성공", - "forkSessionFailed": "세션 포크 실패: {error}", - "exportConversation": "대화 내보내기", - "exportImage": "이미지", - "exportMarkdown": "Markdown", - "exportHtml": "HTML", - "exportSuccess": "대화를 내보냈습니다", - "exportFailed": "내보내기 실패", - "exportImageTooLong": "대화가 너무 길어 이미지로 내보낼 수 없습니다", - "exportLabels": { - "untitledConversation": "제목 없는 대화", - "agent": "에이전트", - "model": "모델", - "status": "상태", - "started": "시작", - "updated": "업데이트", - "tokens": "토큰 통계", - "duration": "소요 시간", - "inputTokens": "입력", - "outputTokens": "출력", - "cacheRead": "캐시 읽기", - "cacheWrite": "캐시 쓰기", - "user": "사용자", - "assistant": "어시스턴트", - "system": "시스템", - "toolResult": "결과", - "toolError": "오류" - }, - "moreActions": "추가 작업" - }, - "sessionDetails": { - "menuLabel": "세션 세부 정보", - "noActiveSession": "활성 세션이 없습니다", - "title": "세션 세부 정보", - "subtitle": "세션 메타데이터 및 토큰 사용량", - "fieldTitle": "제목", - "untitled": "제목 없는 대화", - "sessionId": "세션 ID", - "externalId": "확장 ID", - "agent": "에이전트", - "model": "모델", - "status": "상태", - "gitBranch": "Git 브랜치", - "parentId": "상위 세션", - "tokensHeading": "토큰 사용량", - "totalTokens": "합계", - "inputTokens": "입력", - "outputTokens": "출력", - "cacheWrite": "캐시 쓰기", - "cacheRead": "캐시 읽기", - "contextWindow": "컨텍스트 창", - "duration": "소요 시간", - "loadingStats": "토큰 사용량 불러오는 중…", - "loadFailed": "토큰 사용량을 불러오지 못했습니다", - "noStats": "사용량 기록 없음", - "timestampsHeading": "타임스탬프", - "createdAt": "생성됨", - "updatedAt": "업데이트됨", - "none": "—", - "copyField": "{field} 복사", - "copiedField": "{field} 복사됨" - }, - "conversationCard": { - "untitledConversation": "제목 없는 대화", - "newConversation": "새 대화", - "rename": "이름 변경", - "status": "상태", - "delete": "삭제", - "importLocalSessions": "로컬 세션 가져오기", - "importing": "가져오는 중...", - "renameConversation": "대화 이름 변경", - "deleteConversationTitle": "대화를 삭제할까요?", - "deleteConversationDescription": "\"{title}\"을(를) 삭제합니다. 이 작업은 되돌릴 수 없습니다.", - "cancel": "취소", - "save": "저장", - "pin": "고정", - "unpin": "고정 해제", - "markCompleted": "완료로 표시", - "reopen": "다시 열기", - "expandSubsessions": "하위 대화 펼치기", - "collapseSubsessions": "하위 대화 접기" - }, - "search": { - "dialogTitle": "검색", - "dialogTitleWithFolder": "검색 — {name}", - "tabConversations": "대화", - "tabFiles": "파일", - "placeholder": "대화 검색...", - "filePlaceholder": "파일 또는 디렉토리 검색...", - "allAgents": "전체", - "searching": "검색 중...", - "typeToSearch": "입력하여 대화를 검색하세요", - "typeToSearchFiles": "입력하여 파일 또는 디렉토리를 검색하세요", - "noResults": "검색 결과가 없습니다.", - "untitledConversation": "제목 없는 대화" - }, - "folderTitleBar": { - "showSidebar": "사이드바 표시", - "hideSidebar": "사이드바 숨기기", - "toggleTerminal": "터미널 전환", - "toggleAuxPanel": "보조 패널 전환", - "search": "검색", - "openSettings": "설정 열기", - "backToConversations": "대화로 돌아가기", - "withShortcut": "{label} ({shortcut} 단축키)" - }, - "statusBar": { - "connection": { - "connected": "연결됨", - "connecting": "연결 중...", - "prompting": "응답 중...", - "error": "연결 오류", - "disconnected": "연결 끊김", - "tooltip": "{agent}: {status}", - "tooltipError": "{agent}: {error}", - "title": "에이전트 연결", - "triggerAria": "에이전트 연결: {status}", - "workingDir": "작업 디렉터리", - "sessionId": "세션 ID", - "viewerNote": "다른 클라이언트가 소유한 세션에 연결되어 있습니다. 다시 연결해도 이 보기만 다시 연결됩니다.", - "reconnectInterrupts": "다시 연결하면 에이전트가 재시작되어 진행 중인 작업이 중단됩니다.", - "reconnect": "다시 연결", - "reconnecting": "다시 연결하는 중...", - "reconnectUnavailable": "아직 다시 연결할 세션이 없습니다." - }, - "tasks": { - "title": "작업" - }, - "alerts": { - "title": "알림", - "empty": "알림 없음", - "details": "세부 정보" - }, - "stats": { - "conversations": "{count}개 대화", - "openUsage": "세션 통계 및 토큰 사용량 보기" - }, - "tokens": { - "contextWindowUsageAria": "컨텍스트 윈도우 사용량", - "contextWindow": "컨텍스트 윈도우", - "usedMax": "사용 / 최대", - "tokenUsage": "토큰 사용량", - "input": "입력", - "output": "출력", - "cacheRead": "캐시 읽기", - "cacheWrite": "캐시 쓰기", - "total": "합계" - } - }, - "auxPanel": { - "tabs": { - "files": "파일", - "changes": "변경사항", - "commits": "커밋" - }, - "noFolderTitle": "열린 폴더 없음", - "noFolderHint": "폴더를 열면 여기에 표시됩니다" - }, - "windowControls": { - "minimizeWindow": "창 최소화", - "minimize": "최소화", - "maximizeWindow": "창 최대화", - "maximize": "최대화", - "restoreWindow": "창 복원", - "restore": "복원", - "closeWindow": "창 닫기", - "close": "닫기" - }, - "tabs": { - "closeConversationTab": "대화 탭 닫기", - "close": "닫기", - "closeOthers": "다른 항목 닫기", - "splitRight": "오른쪽으로 분할", - "splitDown": "아래로 분할", - "splitAndMoveRight": "분할하고 오른쪽으로 이동", - "splitAndMoveDown": "분할하고 아래로 이동", - "moveToOppositeGroup": "반대쪽 그룹으로 이동", - "moveToGroup": "그룹으로 이동", - "groupLabel": "그룹 {index}", - "changeSplitterOrientation": "분할 방향 전환", - "unsplit": "분할 해제", - "unsplitAll": "모든 분할 해제", - "closeAll": "모두 닫기", - "tileDisplay": "타일 표시", - "untileDisplay": "타일 해제" - }, - "fileWorkspace": { - "files": "파일", - "closeFileTab": "파일 탭 닫기", - "close": "닫기", - "closeOthers": "다른 항목 닫기", - "closeAll": "모두 닫기", - "preview": "미리보기", - "editSource": "소스 편집", - "maximize": "최대화", - "restore": "복원", - "emptyDirectory": "빈 폴더" - }, - "terminal": { - "rename": "이름 변경", - "close": "닫기", - "closeOthers": "다른 항목 닫기", - "closeAll": "모두 닫기", - "hideTerminal": "터미널 숨기기 ({shortcut})", - "openFolderFirst": "먼저 폴더를 여세요" - }, - "workspaceDialog": { - "title": "폴더 열기", - "manageTitle": "연결된 폴더", - "addTargetsTitle": "연결할 폴더 추가", - "pickRootDescription": "이 작업 공간의 기본 폴더를 선택하세요.", - "linksDescription": "다른 폴더를 하위 디렉터리로 연결하면 에이전트가 하나의 작업 공간에서 여러 프로젝트를 함께 다룰 수 있습니다.", - "addTargetsDescription": "폴더를 하나 이상 선택하세요. 각각 작업 공간의 하위 디렉터리가 됩니다.", - "useSystemPicker": "시스템 선택기", - "next": "다음", - "back": "뒤로", - "done": "완료", - "change": "변경", - "addFolders": "폴더 추가", - "addSelected": "추가", - "addSelectedCount": "{count}개 추가", - "createCount": "폴더 {count}개 연결", - "discardPending": "취소", - "noLinks": "아직 연결된 폴더가 없습니다.", - "gitExclude": "연결을 git 상태에 노출하지 않기", - "rename": "이름 변경", - "unlink": "연결 해제", - "repair": "연결 다시 만들기", - "saveName": "저장", - "cancelRename": "취소", - "removePending": "제거", - "willAppearAs": "작업 공간에서 {name}(으)로 표시됩니다", - "renamedForDuplicate": "이름이 변경됨 — {base}은(는) 다른 연결이 사용 중입니다", - "renamedForExistingEntry": "이름이 변경됨 — 이 폴더에 이미 {base}이(가) 있습니다", - "partiallyCreated": "폴더 {count}개만 연결되었습니다", - "openFailed": "폴더를 열지 못했습니다", - "previewFailed": "선택한 폴더를 확인하지 못했습니다", - "createFailed": "폴더를 연결하지 못했습니다", - "renameFailed": "이름을 변경하지 못했습니다", - "removeFailed": "연결을 해제하지 못했습니다", - "repairFailed": "연결을 다시 만들지 못했습니다", - "status": { - "ok": "연결됨", - "missing": "이 폴더에서 링크가 사라졌습니다", - "conflicted": "다른 항목이 이 이름을 사용 중입니다", - "broken": "연결된 폴더가 더 이상 존재하지 않습니다" - }, - "nameIssue": { - "empty": "이름을 입력하세요", - "illegalChars": "/ \\ : * ? \" < > | 는 사용할 수 없습니다", - "tooLong": "이름이 너무 깁니다", - "reserved": "Windows 예약어입니다", - "duplicate": "이미 사용 중인 이름입니다" - }, - "rejection": { - "not_found": "폴더를 찾을 수 없습니다", - "not_a_directory": "이 경로는 폴더가 아닙니다", - "same_as_root": "작업 공간 폴더 자신입니다", - "ancestor_of_root": "이 폴더가 작업 공간을 포함합니다", - "inside_root": "이미 작업 공간 안에 있습니다", - "already_linked": "이미 연결되어 있습니다", - "name_unavailable": "이 폴더에 사용할 수 있는 이름이 없습니다", - "alreadyLinkedAs": "{name}(으)로 이미 연결되어 있습니다" - } - }, - "folderNameDropdown": { - "fallbackFolderName": "폴더", - "openFolder": "폴더 열기", - "cloneRepository": "리포지토리 클론", - "projectBoot": "프로젝트 부트", - "opened": "열린 항목", - "recentOpen": "최근 연 항목" - }, - "fileWorkspacePanel": { - "addSelectionToChat": "선택 영역을 대화에 추가", - "addToChat": "대화에 추가", - "addSelectionToChatDone": "{label}을(를) 대화에 추가했습니다", - "addFileToChat": "파일을 대화에 추가", - "toggleWordWrap": "자동 줄 바꿈 전환", - "addFileToChatDone": "{label}을(를) 대화에 추가했습니다", - "viewDiff": "Diff 보기", - "openFile": "파일 열기", - "fileCount": "{count, plural, one {#개 파일} other {#개 파일}}", - "openFileOrDiff": "오른쪽 패널에서 파일 또는 diff를 여세요", - "disk": "디스크", - "head": "HEAD", - "unsaved": "저장되지 않음", - "workingTree": "작업 트리", - "loading": "로딩 중...", - "compareWithBranch": "{path} · {branch}와 비교", - "hunkCount": "{count, plural, one {#개 hunk} other {#개 hunks}}", - "prev": "이전", - "next": "다음", - "jumpToLine": "{line}행으로 이동", - "noParsedDiffSections": "파싱된 diff 섹션이 없습니다", - "loadingEditor": "에디터 로딩 중...", - "imageZoomIn": "확대", - "imageZoomOut": "축소", - "imageZoomReset": "확대/축소 초기화", - "htmlPreviewTitle": "HTML 미리보기", - "htmlPreviewTrust": "스크립트 사용", - "htmlPreviewTrustHint": "이 파일의 스크립트를 실행하고 네트워크 접근을 허용합니다. 신뢰할 수 있는 파일에서만 사용하세요.", - "officePreviewTitle": "Office 문서 미리보기", - "officeFullRender": "전체 렌더링", - "officeFullRenderHint": "Morph 애니메이션, 3D, 수식을 렌더링합니다(슬라이드 자체 스크립트 실행).", - "officeNotInstalled": "OfficeCLI가 설치되지 않았습니다", - "officeNotInstalledHint": "설정 → Office 도구에서 OfficeCLI를 설치하면 Word, Excel, PowerPoint 파일을 미리볼 수 있습니다.", - "officeOpenSettings": "설정 열기", - "officeWatchFailed": "실시간 미리보기를 시작할 수 없습니다", - "officeWatchRetry": "다시 시도", - "officeServerInstallHint": "OfficeCLI는 서버 호스트에 설치해야 합니다. 서버에서 다음 명령을 실행한 후 다시 시도하세요:", - "officeRemoteDesktopUnsupported": "원격 데스크톱 창에서는 실시간 미리보기를 사용할 수 없습니다. Office 파일을 미리 보려면 서버의 웹 UI에서 이 작업 공간을 여세요." - }, - "branchDropdown": { - "toasts": { - "commitCodeCompleted": "코드 커밋이 완료되었습니다", - "pushCodeCompleted": "코드 푸시가 완료되었습니다", - "committedFiles": "{count, plural, one {#개 파일 커밋됨} other {#개 파일 커밋됨}}", - "taskCompleted": "{label} 완료", - "taskFailed": "{label} 실패", - "mergeNoNewCommits": "{branchName}에는 새 커밋이 없습니다", - "mergedCommits": "{count, plural, one {#개 커밋 병합됨} other {#개 커밋 병합됨}}", - "allFilesUpToDate": "모든 파일이 최신 상태입니다", - "updatedFiles": "{count, plural, one {#개 파일 업데이트됨} other {#개 파일 업데이트됨}}", - "openCommitWindowFailed": "커밋 창을 열지 못했습니다", - "openPushWindowFailed": "푸시 창 열기 실패", - "upstreamSet": "업스트림 브랜치가 설정되었습니다", - "upstreamSetAndPushed": "업스트림 브랜치를 설정하고 {count, plural, one {#개 커밋} other {#개 커밋}}을 푸시했습니다", - "noCommitsToPush": "푸시할 커밋이 없습니다", - "pushedCommits": "{count, plural, one {#개 커밋 푸시됨} other {#개 커밋 푸시됨}}", - "switchedToFolder": "{name}(으)로 전환했습니다", - "switchFailed": "브랜치 전환에 실패했습니다", - "openStashWindowFailed": "스태시 창을 열지 못했습니다" - }, - "tasks": { - "newBranch": "브랜치 {name} 생성", - "newWorktree": "워크트리 {name} 생성", - "checkoutTo": "{branchName}(으)로 체크아웃", - "mergeBranch": "{branchName} 병합", - "rebaseTo": "{branchName}로 리베이스", - "deleteRemoteBranch": "원격 브랜치 {branchName} 삭제", - "initGitRepo": "Git 저장소 초기화", - "pullCode": "코드 pull", - "fetchInfo": "정보 fetch", - "pushCode": "코드 push", - "stashChanges": "변경 사항 stash", - "stashPop": "stash pop", - "deleteBranch": "브랜치 {branchName} 삭제", - "removeWorktree": "{branchName}의 워크트리 삭제", - "removeWorktreeAndBranch": "워크트리 및 브랜치 {branchName} 삭제", - "updateBranch": "브랜치 {branchName} 업데이트" - }, - "confirm": { - "mergeTitle": "브랜치 병합", - "rebaseTitle": "브랜치 리베이스", - "mergeDescription": "{branchName}을(를) 현재 브랜치 {currentBranch}에 병합할까요?", - "rebaseDescription": "현재 브랜치 {currentBranch}를 {branchName} 위로 리베이스할까요?", - "deleteRemoteTitle": "원격 브랜치 삭제", - "deleteRemoteDescription": "원격 브랜치 {branchName}을(를) 삭제하시겠습니까? 이 작업은 원격 저장소에서 브랜치를 제거하며 되돌릴 수 없습니다.", - "deleteTitle": "브랜치 삭제", - "deleteDescription": "브랜치 {branchName}을(를) 삭제할까요? 이 작업은 되돌릴 수 없습니다.", - "forceDeleteTitle": "브랜치 강제 삭제", - "forceDeleteDescription": "브랜치 {branchName}가 완전히 병합되지 않았습니다. 강제 삭제하시겠습니까? 이 작업은 되돌릴 수 없습니다.", - "deleteWorktreeTitle": "워크트리 삭제", - "deleteWorktreeDescription": "{branchName}이(가) 체크아웃된 워크트리 디렉터리를 삭제할까요? 브랜치와 커밋은 유지됩니다.", - "forceDeleteWorktreeTitle": "워크트리 강제 삭제", - "forceDeleteWorktreeDescription": "{branchName}의 워크트리에 커밋되지 않았거나 추적되지 않는 파일이 있습니다. 그래도 삭제할까요? 해당 변경 사항은 복구할 수 없습니다.", - "deleteWorktreeAndBranchTitle": "워크트리 및 브랜치 삭제", - "deleteWorktreeAndBranchDescription": "{branchName}의 워크트리와 브랜치, 그리고 워크스페이스 폴더를 삭제할까요? 그 안의 세션은 저장소 폴더로 이동합니다. 이 작업은 되돌릴 수 없습니다.", - "forceDeleteWorktreeAndBranchTitle": "워크트리 및 브랜치 강제 삭제", - "forceDeleteWorktreeAndBranchDescription": "{branchName}의 워크트리에 커밋되지 않은 파일이 있거나 브랜치가 완전히 병합되지 않았습니다. 그래도 둘 다 삭제할까요? 이 작업은 되돌릴 수 없습니다." - }, - "current": "현재", - "switchToBranch": "이 브랜치로 전환", - "mergeBranchIntoCurrent": "{branchName}을(를) {currentBranch}에 병합", - "rebaseCurrentToBranch": "{currentBranch}를 {branchName}로 리베이스", - "noBranch": "브랜치 없음", - "detachedHead": "분리된 HEAD ({sha})", - "initGitRepo": "Git 저장소 초기화", - "pullCode": "코드 pull", - "fetchRemoteBranches": "원격 브랜치 가져오기", - "openCommitWindow": "코드 커밋...", - "pushCode": "푸시...", - "pushBranch": "푸시", - "newBranch": "새 브랜치...", - "newWorktree": "새 워크트리...", - "stashChanges": "스태시...", - "stashPop": "stash pop...", - "manageRemotes": "원격 관리...", - "localBranches": "로컬 브랜치 ({count, plural, one {#} other {#}})", - "noLocalBranches": "로컬 브랜치가 없습니다", - "remoteBranches": "원격 브랜치 ({count, plural, one {#} other {#}})", - "noRemoteBranches": "원격 브랜치가 없습니다", - "dialogs": { - "newBranchTitle": "새 브랜치", - "newBranchDescription": "현재 브랜치 {branch}에서 새 브랜치를 만듭니다", - "branchNamePlaceholder": "브랜치 이름", - "newWorktreeTitle": "새 워크트리", - "newWorktreeDescription": "현재 브랜치 {branch}에서 새 워크트리를 만듭니다", - "branchNameLabel": "브랜치 이름", - "worktreePathLabel": "워크트리 경로", - "worktreePathPlaceholder": "워크트리 경로", - "manageRemotesTitle": "원격 관리", - "manageRemotesEmpty": "구성된 원격이 없습니다", - "remoteNamePlaceholder": "원격 이름", - "remoteUrlPlaceholder": "원격 URL", - "addRemote": "추가", - "savingRemotes": "저장 중..." - }, - "conflict": { - "title": "병합 충돌", - "description": "다음 파일에 충돌이 있어 해결이 필요합니다:", - "abort": "병합 중단", - "openMergeTool": "병합 도구 열기", - "completeMerge": "병합 완료", - "abortSuccess": "병합이 중단되었습니다", - "completeSuccess": "병합이 완료되었습니다" - }, - "stashDialog": { - "title": "변경 사항 스태시", - "description": "현재 변경 사항을 스태시에 저장", - "messageLabel": "메시지", - "messagePlaceholder": "스태시 메시지 (선택사항)", - "keepIndex": "인덱스 유지 (스테이지된 변경 사항 유지)", - "cancel": "취소", - "stash": "스태시", - "success": "변경 사항이 스태시되었습니다", - "error": "스태시 실패" - }, - "unstashDialog": { - "title": "스태시 적용", - "noStashes": "스태시가 없습니다", - "selectFile": "파일을 선택하여 차이 보기", - "viewDiff": "차이 보기", - "original": "원본", - "modified": "수정됨", - "apply": "적용", - "drop": "삭제", - "applySuccess": "스태시가 적용되었습니다", - "dropSuccess": "스태시가 삭제되었습니다", - "confirmApply": "스태시 {ref}을(를) 작업 디렉토리에 적용하시겠습니까?", - "cancel": "취소" - }, - "deleteBranch": "브랜치 삭제", - "deleteWorktree": "워크트리 삭제", - "deleteWorktreeAndBranch": "워크트리 및 브랜치 삭제", - "searchPlaceholder": "브랜치 및 작업 검색", - "searchAriaLabel": "브랜치 및 작업 검색", - "branchListLabel": "브랜치 및 작업", - "noMatches": "일치하는 항목 없음" - }, - "commitDialog": { - "toasts": { - "commitCompleted": "코드 커밋이 완료되었습니다", - "pushFailed": "푸시 실패", - "committedFiles": "{count, plural, one {#개 파일 커밋됨} other {#개 파일 커밋됨}}", - "addedToVcs": "VCS에 추가되었습니다", - "addToVcsFailed": "VCS에 추가하지 못했습니다", - "fileDeleted": "파일이 삭제되었습니다", - "deleteFailed": "삭제에 실패했습니다", - "fileRolledBack": "파일이 롤백되었습니다", - "rollbackFailed": "롤백에 실패했습니다", - "dirRolledBack": "디렉토리가 롤백되었습니다", - "dirDeleted": "디렉토리가 삭제되었습니다" - }, - "confirm": { - "deleteTitle": "삭제 확인", - "deleteDescription": "파일 \"{file}\"을(를) 삭제할까요? 이 작업은 되돌릴 수 없습니다.", - "rollbackTitle": "롤백 확인", - "rollbackDescription": "파일 \"{file}\"을(를) HEAD로 롤백할까요? 저장되지 않은 변경 사항은 사라집니다.", - "rollbackDirDescription": "디렉토리 \"{dir}\"를 HEAD로 롤백하시겠습니까? 저장되지 않은 변경 사항이 손실됩니다.", - "deleteDirDescription": "디렉토리 \"{dir}\"를 삭제하시겠습니까? 이 작업은 되돌릴 수 없습니다." - }, - "actions": { - "select": "선택", - "unselect": "선택 해제", - "rollback": "롤백", - "addToVcs": "VCS에 추가" - }, - "aria": { - "selectFile": "{action}: {path}", - "unselectAllFiles": "모든 파일 선택 해제", - "selectAllFiles": "모든 파일 선택", - "unselectTracked": "추적된 변경 선택 해제", - "selectTracked": "추적된 변경 선택", - "unselectUntracked": "추적되지 않은 파일 선택 해제", - "selectUntracked": "추적되지 않은 파일 선택" - }, - "loading": "로딩 중...", - "selectionCount": "{selected} / {total}개 파일", - "emptyFiles": "변경된 파일이 없습니다", - "trackedChanges": "추적된 변경 ({count})", - "untrackedFiles": "추적되지 않은 파일 ({count})", - "commitMessage": "커밋 메시지", - "commitMessagePlaceholder": "커밋 메시지 입력...", - "commitButton": "커밋 ({count})", - "commitAndPushButton": "커밋 후 푸시 ({count})", - "head": "HEAD", - "workingTree": "작업 트리", - "clickFileToDiff": "파일 이름을 클릭해 diff를 확인하세요", - "loadingDiff": "diff 로딩 중..." - }, - "pushWindow": { - "title": "코드 푸시", - "noUnpushedCommits": "푸시되지 않은 커밋이 없습니다", - "noRemoteConfigured": "Git 원격이 구성되지 않았습니다\n「원격 관리」에서 원격을 추가하세요", - "newBranchNoPushedCommits": "새 브랜치 — 푸시하여 원격 추적 브랜치 생성", - "unpushed": "미푸시", - "selectFileToViewDiff": "파일을 선택하여 차이 보기", - "before": "변경 전", - "after": "변경 후", - "push": "푸시", - "toasts": { - "pushSuccess": "푸시 성공", - "pushFailed": "푸시 실패", - "upstreamSet": "원격 추적 브랜치가 설정되었습니다", - "upstreamSetAndPushed": "원격 추적 브랜치 설정 및 {count}개 커밋 푸시 완료", - "noCommitsToPush": "푸시할 커밋이 없습니다", - "pushedCommits": "{count}개 커밋 푸시 완료" - } - }, - "gitLogTab": { - "filesTitle": "파일", - "expandAllFiles": "모든 파일 펼치기", - "collapseAllFiles": "모든 파일 접기", - "workspace": "작업 공간", - "retry": "다시 시도", - "noCommitsFound": "커밋을 찾을 수 없습니다", - "notAGitRepoTitle": "Git 저장소가 아닙니다", - "notAGitRepoHint": "위의 브랜치 메뉴에서 Git을 초기화하거나 기존 저장소를 여세요.", - "hash": "해시", - "copyHash": "해시 복사", - "copyMessage": "메시지 복사", - "showMore": "더보기", - "showLess": "접기", - "author": "작성자", - "noFileChangeDetails": "파일 변경 상세 정보가 없습니다.", - "loadingFiles": "파일 로딩 중…", - "branchesTitle": "브랜치", - "loadingBranches": "브랜치 로딩 중...", - "noContainingBranches": "포함하는 브랜치를 찾을 수 없습니다.", - "newBranch": "새 브랜치...", - "resetToHere": "여기로 리셋", - "resetDisabledReasonNotCurrentBranchView": "현재 브랜치 보기에서만 사용할 수 있습니다", - "copyFullCommitHashAria": "전체 커밋 해시 {hash} 복사", - "pushStatus": { - "pushed": "원격에 푸시됨", - "notPushed": "원격에 푸시되지 않음", - "unknown": "푸시 상태 알 수 없음 (upstream 미설정)" - }, - "time": { - "monthsAgo": "{count, plural, one {#개월 전} other {#개월 전}}", - "daysAgo": "{count, plural, one {#일 전} other {#일 전}}", - "hoursAgo": "{count, plural, one {#시간 전} other {#시간 전}}", - "minsAgo": "{count, plural, one {#분 전} other {#분 전}}", - "justNow": "방금 전" - }, - "toasts": { - "createdAndSwitchedNewBranch": "새 브랜치를 생성하고 전환했습니다", - "newBranchFromCommit": "{name} ({shortHash}에서 생성)", - "createBranchFailed": "브랜치 생성에 실패했습니다", - "openPushWindowFailed": "푸시 창을 열지 못했습니다", - "resetSuccess": "리셋 완료", - "resetSuccessDescription": "{branch}을(를) {mode}로 {shortHash}에 리셋했습니다", - "resetFailed": "리셋 실패" - }, - "authorFilter": { - "label": "작성자", - "searchPlaceholder": "작성자 검색", - "noAuthors": "작성자를 찾을 수 없습니다", - "you": "나", - "filterByAuthorAria": "작성자별로 커밋 필터링", - "filterByQuery": "\"{query}\"(으)로 필터링", - "clearAuthorFilterAria": "작성자 필터 지우기", - "recent": "최근", - "matchingAuthors": "일치하는 작성자", - "removeFromRecent": "최근에서 {name} 제거" - }, - "branchSelector": { - "label": "브랜치", - "head": "HEAD", - "headHint": "현재 브랜치를 따라감", - "headHintWithBranch": "현재 브랜치를 따라감 ({branch})", - "searchBranch": "브랜치 검색...", - "noBranches": "브랜치 없음", - "selectBranchPlaceholder": "브랜치 선택...", - "localBranches": "로컬 브랜치", - "current": "현재", - "remoteBranches": "원격 브랜치", - "refreshCommitHistory": "커밋 히스토리 새로고침", - "clearBranchFilterAria": "브랜치 필터 지우기" - }, - "dialogs": { - "newBranchTitle": "새 브랜치", - "newBranchDescription": "커밋 {shortHash}를 최신 커밋으로 하여 새 브랜치를 생성합니다.", - "branchNamePlaceholder": "브랜치 이름", - "reset": { - "title": "현재 브랜치를 이 커밋으로 리셋", - "branchLabel": "브랜치", - "targetLabel": "대상 커밋", - "messageLabel": "커밋 메시지", - "modeLabel": "리셋 모드", - "confirmButton": "리셋", - "modes": { - "soft": { - "label": "--soft", - "description": "HEAD와 현재 브랜치 포인터를 대상 커밋으로 이동합니다.\nIndex와 Working Tree는 변경하지 않습니다.\n되돌려진 커밋의 변경 사항은 staged 상태로 유지됩니다." - }, - "mixed": { - "label": "--mixed (기본값)", - "description": "HEAD를 대상 커밋으로 이동합니다.\nIndex를 대상 커밋으로 되돌리고 Working Tree 변경은 유지합니다.\n변경 사항은 staged에서 unstaged로 바뀝니다." - }, - "hard": { - "label": "--hard", - "description": "HEAD를 이동하고 Index와 Working Tree를 모두 대상 커밋으로 되돌립니다.\n대상 커밋 이후의 추적된 로컬 변경은 삭제됩니다.\n파괴적인 작업입니다." - }, - "keep": { - "label": "--keep", - "description": "HEAD를 대상 커밋으로 이동하면서 가능한 한 로컬 변경을 유지합니다.\n충돌하지 않는 변경만 보존됩니다.\n충돌이 감지되면 작업 보호를 위해 리셋이 중단됩니다." - } - } - } - }, - "moreActions": "추가 Git 작업" - }, - "gitChangesTab": { - "workspace": "작업 공간", - "noChanges": "로컬 변경 사항이 없습니다", - "notAGitRepoTitle": "Git 저장소가 아닙니다", - "notAGitRepoHint": "위의 브랜치 메뉴에서 Git을 초기화하거나 기존 저장소를 여세요.", - "trackedChanges": "추적된 변경 ({count})", - "untrackedFiles": "추적되지 않은 파일 ({count})", - "expandTracked": "추적된 변경 펼치기", - "collapseTracked": "추적된 변경 접기", - "expandUntracked": "추적되지 않은 파일 펼치기", - "collapseUntracked": "추적되지 않은 파일 접기", - "showRemainingItems": "나머지 {count}개 표시", - "actions": { - "commitCode": "코드 커밋", - "rollback": "롤백", - "addToVcs": "VCS에 추가", - "delete": "삭제", - "moreActions": "추가 Git 작업", - "addAllToVcs": "모두 VCS에 추가", - "rollbackAll": "모두 롤백", - "refresh": "새로 고침" - }, - "toasts": { - "noAddableFilesInDir": "이 디렉터리에는 VCS에 추가할 수 있는 변경 파일이 없습니다", - "noRollbackFilesInDir": "이 디렉터리에는 롤백할 수 있는 변경 파일이 없습니다", - "addedToVcs": "{name}을(를) VCS에 추가했습니다", - "addToVcsFailed": "VCS에 추가하지 못했습니다", - "openCommitWindowFailed": "커밋 창을 열지 못했습니다", - "rolledBack": "{name}을(를) 롤백했습니다", - "rollbackFailed": "롤백에 실패했습니다", - "addedFilesToVcs": "{count, plural, one {#개 파일을 VCS에 추가} other {#개 파일을 VCS에 추가}}", - "rolledBackFiles": "{count, plural, one {#개 파일 롤백} other {#개 파일 롤백}}", - "deleted": "{name}이(가) 삭제되었습니다", - "deleteFailed": "삭제에 실패했습니다", - "deletedFiles": "{count}개 파일을 삭제했습니다", - "noDeletableFilesInDir": "이 디렉터리에서 삭제할 수 있는 변경된 파일이 없습니다", - "commitFailed": "커밋 실패" - }, - "directoryDialog": { - "descriptionAdd": "디렉터리 {path} 아래에서 VCS에 추가할 파일을 선택하세요.", - "descriptionRollback": "디렉터리 {path} 아래에서 롤백할 파일을 선택하세요.", - "descriptionDelete": "디렉터리 {path} 아래에서 삭제할 파일을 선택하세요. 이 작업은 되돌릴 수 없습니다.", - "descriptionFallback": "계속 진행할 파일을 선택하세요.", - "selectionCount": "{selected} / {total} 선택됨", - "selectAll": "모두 선택", - "unselectAll": "모두 선택 해제", - "loadingCandidates": "디렉터리 변경 사항 로딩 중...", - "noOperableFiles": "작업 가능한 파일이 없습니다" - }, - "rollbackConfirm": { - "title": "롤백 확인", - "descriptionWithTarget": "{kind} \"{name}\"의 로컬 변경 사항을 롤백할까요?", - "descriptionFallback": "로컬 변경 사항을 롤백할까요?", - "kindDirectory": "디렉터리", - "kindFile": "파일" - }, - "deleteConfirm": { - "title": "삭제 확인", - "descriptionWithTarget": "{kind} \"{name}\"을(를) 삭제할까요? 이 작업은 되돌릴 수 없습니다.", - "descriptionFallback": "이 작업은 되돌릴 수 없습니다.", - "kindDirectory": "디렉터리", - "kindFile": "파일" - }, - "quickCommit": { - "placeholder": "커밋 메시지 (Enter로 커밋)" - } - }, - "tabContext": { - "loadingConversation": "로딩 중...", - "untitledConversation": "제목 없는 대화", - "newConversation": "새 대화" - }, - "fileTreeTab": { - "workspace": "작업 공간", - "retry": "다시 시도", - "git": "Git", - "openInFileManager": "파일 관리자에서 열기", - "openInFinder": "Finder에서 열기", - "openInExplorer": "Explorer에서 열기", - "attachToCurrentSession": "세션에 추가", - "compareWithBranch": "브랜치와 비교...", - "reloadFromDisk": "디스크에서 다시 불러오기", - "new": "새로 만들기", - "newFile": "파일", - "newDirectory": "디렉터리", - "openIn": "열기", - "openInTerminal": "터미널에서 열기", - "linkedFolder": "연결된 폴더", - "copyPath": "경로 복사", - "upload": "파일/폴더 업로드", - "download": "파일 다운로드", - "downloadAsZip": "ZIP으로 다운로드", - "actions": { - "select": "선택", - "unselect": "선택 해제", - "commitCode": "코드 커밋", - "rollback": "롤백", - "addToVcs": "VCS에 추가" - }, - "aria": { - "selectPath": "{action}: {path}" - }, - "toasts": { - "openDirectoryFailed": "디렉터리를 열지 못했습니다", - "openBuiltinTerminalFailed": "내장 터미널을 열 수 없습니다", - "openCommitWindowFailed": "커밋 창을 열지 못했습니다", - "noAddableFilesInDir": "이 디렉터리에는 VCS에 추가할 수 있는 변경 파일이 없습니다", - "noRollbackFilesInDir": "이 디렉터리에는 롤백할 수 있는 변경 파일이 없습니다", - "addedToVcs": "{name}을(를) VCS에 추가했습니다", - "addToVcsFailed": "VCS에 추가하지 못했습니다", - "loadBranchesFailed": "브랜치를 불러오지 못했습니다", - "renameFailed": "이름 변경에 실패했습니다", - "moveFailed": "이동에 실패했습니다", - "deleteFailed": "삭제에 실패했습니다", - "rolledBack": "{name}을(를) 롤백했습니다", - "rollbackFailed": "롤백에 실패했습니다", - "addedFilesToVcs": "{count, plural, one {#개 파일을 VCS에 추가했습니다} other {#개 파일을 VCS에 추가했습니다}}", - "rolledBackFiles": "{count, plural, one {#개 파일을 롤백했습니다} other {#개 파일을 롤백했습니다}}", - "savedAsCopy": "사본으로 저장했습니다", - "saveCopyFailed": "사본으로 저장하지 못했습니다", - "watchStartFailed": "파일 감시 시작에 실패했습니다", - "createFailed": "생성 실패", - "downloadFailed": "{name} 다운로드 실패", - "downloadSaved": "{name} 다운로드 완료", - "pathCopied": "경로가 복사되었습니다", - "copyPathFailed": "경로 복사에 실패했습니다" - }, - "createDialog": { - "newFile": "새 파일", - "newDirectory": "새 디렉터리", - "description": "새 {kind}의 이름을 입력하세요.", - "placeholderFile": "file-name.ext", - "placeholderDirectory": "folder-name" - }, - "renameDialog": { - "renameDirectory": "디렉터리 이름 변경", - "renameFile": "파일 이름 변경", - "description": "새 이름을 입력하세요(이름만, 경로 제외).", - "placeholderDirectory": "새-폴더-이름", - "placeholderFile": "새-파일-이름.ext" - }, - "uploadDialog": { - "title": "작업 공간에 업로드", - "description": "필요하면 업로드 위치를 변경한 다음 파일이나 폴더를 추가하세요.", - "workspaceRoot": "작업 공간 루트", - "targetPathLabel": "업로드 위치", - "targetPathHint": "실제 경로: {path}", - "dropHint": "파일 또는 폴더를 여기에 끌어오거나 아래 버튼을 사용하세요", - "dropHintActive": "놓으면 대기열에 추가됩니다", - "selectFiles": "파일 선택", - "selectFolder": "폴더 선택", - "startUpload": "업로드 시작", - "clearQueue": "완료된 항목 지우기", - "removeItem": "대기열에서 제거", - "retry": "다시 시도", - "dropZoneAria": "파일을 여기에 드롭하거나 Enter 키로 찾아보기", - "folderEmpty": "드롭한 폴더에서 파일을 찾을 수 없습니다", - "summary": "합계: {total} · 성공: {succeeded} · 실패: {failed}", - "status": { - "pending": "대기 중", - "uploading": "업로드 중", - "success": "완료", - "error": "실패", - "cancelled": "취소됨" - } - }, - "directoryDialog": { - "descriptionAdd": "디렉터리 {path} 아래에서 VCS에 추가할 파일을 선택하세요.", - "descriptionRollback": "디렉터리 {path} 아래에서 롤백할 파일을 선택하세요.", - "descriptionFallback": "계속할 파일을 선택하세요.", - "selectionCount": "{selected} / {total}개 파일 선택됨", - "selectAll": "모두 선택", - "unselectAll": "모두 선택 해제", - "loadingCandidates": "디렉터리 변경 사항을 불러오는 중...", - "noOperableFiles": "작업 가능한 파일이 없습니다" - }, - "compareDialog": { - "title": "브랜치와 비교", - "descriptionWithTarget": "브랜치를 선택하고 {kind} {path}와(과) 비교하세요", - "descriptionFallback": "비교할 브랜치를 선택하세요.", - "kindDirectory": "디렉터리", - "kindFile": "파일", - "filterPlaceholder": "브랜치 필터링 (예: main / origin/main)", - "singleClickHint": "브랜치를 클릭하면 바로 비교합니다", - "loadingBranches": "브랜치를 불러오는 중...", - "recentBranches": "최근 브랜치 ({count})", - "noCurrentBranch": "현재 브랜치 없음", - "localBranches": "로컬 브랜치 ({count})", - "remoteBranches": "원격 브랜치 ({count})", - "noMatchingBranches": "일치하는 브랜치가 없습니다" - }, - "externalConflictDialog": { - "title": "외부 파일 변경 감지됨", - "descriptionWithPath": "파일 {path} 이(가) 디스크에서 변경되었고 현재 편집 내용은 저장되지 않았습니다.", - "descriptionFallback": "현재 파일이 디스크에서 변경되었고 현재 편집 내용은 저장되지 않았습니다.", - "compare": "비교", - "savingCopy": "사본 저장 중...", - "saveAsCopy": "사본으로 저장", - "reload": "다시 불러오기" - }, - "deleteConfirm": { - "title": "삭제 확인", - "descriptionWithTarget": "{kind} \"{name}\"을(를) 삭제할까요? 이 작업은 되돌릴 수 없습니다.", - "descriptionFallback": "이 작업은 되돌릴 수 없습니다.", - "kindDirectory": "디렉터리", - "kindFile": "파일" - }, - "rollbackConfirm": { - "title": "롤백 확인", - "descriptionWithTarget": "파일 \"{name}\"의 로컬 변경 사항을 롤백할까요?", - "descriptionFallback": "이 파일의 로컬 변경 사항을 롤백할까요?" - }, - "terminalTitle": "터미널 · {name}" - }, - "commandDropdown": { - "loading": "로딩 중...", - "addCommand": "명령 추가", - "manageCommands": "명령 관리...", - "runCommandTitle": "실행: {command}", - "stopCommandTitle": "중지: {command}", - "manageDialog": { - "title": "명령 관리", - "empty": "아직 명령이 없습니다", - "noResults": "일치하는 명령이 없습니다", - "searchPlaceholder": "명령 검색", - "newCommand": "새 명령", - "nameLabel": "이름", - "commandLabel": "명령", - "dragSort": "드래그하여 정렬", - "dragSortCommand": "{name} 드래그하여 정렬", - "orderFailed": "명령 순서 저장에 실패했습니다", - "loadFailed": "명령을 불러오지 못했습니다", - "saveFailed": "명령을 저장하지 못했습니다", - "deleteFailed": "명령을 삭제하지 못했습니다", - "confirmDelete": { - "title": "명령을 삭제하시겠습니까?", - "message": "\"{name}\"을(를) 제거합니다. 이 작업은 되돌릴 수 없습니다." - } - } - }, - "workspaceContext": { - "confirmCloseDirtyTab": "저장하지 않고 \"{title}\" 탭을 닫을까요?", - "confirmCloseOtherDirtyTabs": "저장되지 않은 변경 사항이 있는 다른 탭을 닫을까요?", - "confirmCloseAllDirtyTabs": "저장되지 않은 변경 사항이 있는 모든 탭을 닫을까요?", - "unableLoadContent": "콘텐츠를 불러올 수 없습니다.\n\n{message}", - "previewRequestTimedOut": "미리보기 요청 시간이 초과되었습니다", - "diffRequestTimedOut": "Diff 요청 시간이 초과되었습니다", - "branchCompareRequestTimedOut": "브랜치 비교 요청 시간이 초과되었습니다", - "commitDiffRequestTimedOut": "커밋 Diff 요청 시간이 초과되었습니다", - "saveRequestTimedOut": "저장 요청 시간이 초과되었습니다", - "reloadRequestTimedOut": "다시 불러오기 요청 시간이 초과되었습니다", - "noChanges": "변경 사항이 없습니다.", - "noDiffOutput": "Diff 출력이 없습니다.", - "diffTitleWorkspace": "Diff · 워크스페이스", - "diffDescriptionWorkingTree": "작업 트리 (HEAD)", - "diffTitleFile": "차이 · {name}", - "compareTitleFile": "비교 · {name}", - "compareTitleBranch": "비교 · {branch}", - "compareDescriptionPath": "{path} · {branch}와 비교", - "compareDescriptionBranch": "{branch}와 비교", - "diffTitleCommitFile": "차이 · {name} @ {hash}", - "diffTitleCommit": "차이 · {hash}", - "diffDescriptionCommitPath": "{path} · 커밋 {commit}", - "diffDescriptionCommit": "커밋 {commit}", - "diffTitleConflictFile": "충돌 · {name}", - "diffDescriptionConflict": "{path} · 디스크 vs 저장되지 않음" - }, - "chat": { - "acpConnections": { - "actions": { - "openAgentsSettings": "에이전트 설정 열기", - "retry": "다시 시도" - }, - "agentsSetupHint": "설정 > 에이전트를 열어 설치를 관리하세요.", - "withSetupHint": "{message}\n{hint}", - "blocked": { - "missingConfig": "현재 에이전트 구성을 읽을 수 없습니다.", - "disabled": "{agent}은(는) 에이전트 설정에서 비활성화되어 있습니다. 연결 전에 활성화하세요.", - "unavailable": "{agent}은(는) 현재 플랫폼에서 사용할 수 없습니다.", - "sdkMissing": "{agent} SDK가 설치되어 있지 않습니다", - "adapterMissing": "{agent}의 ACP 어댑터가 설치되어 있지 않습니다" - }, - "backendErrors": { - "initializeTimeout": "{agent} 연결 핸드셰이크가 시간 초과되었습니다(60초 동안 응답 없음). 설정을 열어 에이전트 및 네트워크 구성을 확인하세요.", - "mcpRejectedByAgent": "codeg의 MCP 동반 프로세스를 전달하는 동안 {agent}이(가) 세션을 거부했습니다: {message} 이 에이전트가 MCP를 지원하지 않는다면 설정에서 ‘MCP 지원’을 끄고 다시 연결하세요.", - "processExited": "{agent} 프로세스가 예기치 않게 종료되었습니다.", - "spawnFailed": "{agent} 시작 실패: {message}", - "downloadFailed": "{agent} 다운로드 실패: {message}", - "sessionLoadResourceNotFound": "{agent} 세션 불러오기에 실패했습니다. 다시 불러와 재시도하거나 새 대화를 시작하세요.", - "sessionLoadUnavailable": "{agent}에서 이 세션을 복원할 수 없습니다. 세션이 종료되었거나 에이전트가 중지되었을 수 있습니다. 다시 불러와 재시도하거나 새 대화를 시작하세요.", - "turnFailedRefusal": "{agent}이(가) 이번 턴을 계속하지 않았습니다. 백엔드나 게이트웨이 오류일 수 있습니다. 에이전트 로그를 확인하세요.", - "turnFailedMaxTokens": "{agent}이(가) 이번 턴의 최대 토큰 한도에 도달했습니다.", - "turnFailedMaxTurnRequests": "{agent}이(가) 이번 턴에서 허용된 최대 요청 수에 도달했습니다.", - "turnFailedUnknown": "{agent}이(가) 알 수 없는 중지 사유로 턴을 종료했습니다.", - "grokModelSwitchIncompatibleAgent": "{agent}은(는) 기존 대화에서는 해당 모델로 전환할 수 없습니다. 새 세션을 시작하여 사용하세요.", - "turnFailedEmpty": "{agent}이(가) 어떤 응답도 생성하지 않고 턴을 종료했습니다.", - "turnFailedEmptyProtocol": "{agent}의 출력을 codeg가 구문 분석할 수 없습니다. 에이전트 버전이 프로토콜과 맞지 않을 수 있습니다.", - "turnFailedEmptyMetadata": "{agent}이(가) 이번 턴에 상태 업데이트(계획 / 모드 / 사용량)만 보내고 응답은 없었습니다.", - "detailsInAlerts": "상태 표시줄의 알림을 열고 세부 정보를 펼치면 에이전트 출력을 확인할 수 있습니다." - }, - "unableReadAgentConfig": "에이전트 구성을 읽을 수 없습니다: {message}", - "connectFailedTitle": "{agent} 연결 실패", - "toolFallbackTitle": "도구", - "eventErrorTitle": "에이전트 오류", - "notificationTurnComplete": "{agent} 응답이 완료되었습니다", - "notificationError": "{agent} 오류: {message}", - "claudeApiRetry": { - "fallbackError": "authentication_failed", - "retryingWithMax": "재시도 중 {attempt}/{max}", - "retryingAttempt": "{attempt}번째 재시도 중", - "retrying": "재시도 중", - "nextRetryIn": "{seconds}초 후 재시도", - "line": "{error}{status} · {retry}", - "lineWithDelay": "{error}{status} · {retry}, {delay}", - "httpStatus": " (HTTP {status})" - }, - "configOptionAdjusted": "{agent}이(가) {option}을(를) {requested} 대신 {actual}(으)로 설정했습니다" - }, - "connectionLifecycle": { - "tasks": { - "connectingTitle": "{agent}에 연결 중", - "connectingDescription": "연결을 설정하는 중", - "loadingSelectorsTitle": "{agent} 선택자 불러오는 중", - "loadingSelectorsDescription": "모드 및 세션 구성 옵션을 가져오는 중", - "initSessionTitle": "{agent} 세션 초기화 중", - "initSessionDescription": "세션 생성 및 설정 불러오는 중" - }, - "errors": { - "connectionFailed": "연결 실패", - "sendPromptFailed": "메시지 전송에 실패했습니다: {error}" - } - }, - "shared": { - "attachedResources": "첨부된 리소스", - "toolCallFailed": "도구 호출 실패" - }, - "messageThread": { - "emptyTitle": "아직 메시지가 없습니다", - "emptyDescription": "대화를 시작하면 여기에서 메시지를 볼 수 있습니다" - }, - "chatInput": { - "connecting": "연결 중...", - "agentResponding": "{agent} 응답 중...", - "sendMessage": "메시지 보내기..." - }, - "messageInput": { - "askAnything": "무엇이든 물어보세요...", - "removeAttachmentAria": "{name} 제거", - "attachFiles": "파일 첨부", - "addActions": "추가", - "quickMessages": "빠른 메시지", - "quickMessagesEmpty": "빠른 메시지가 없습니다", - "quickMessagesLoading": "불러오는 중...", - "pasteAsPlainText": "일반 텍스트로 붙여넣기", - "cut": "잘라내기", - "copy": "복사", - "selectAll": "모두 선택", - "pasteUnavailable": "클립보드를 읽을 수 없습니다. Ctrl/⌘V로 붙여넣으세요.", - "clipboardWriteFailed": "클립보드에 쓸 수 없습니다. 키보드 단축키를 사용하세요.", - "quickMessageUntitled": "제목 없음", - "liveFeedback": "라이브 피드백", - "liveFeedbackDisabledHint": "에이전트가 작업 중일 때 보낼 수 있습니다", - "dropFilesToAttach": "파일을 놓아 첨부", - "loadingSettings": "설정 불러오는 중...", - "loadingMode": "모드 불러오는 중...", - "modeLabel": "모드", - "toggleOn": "켬", - "toggleOff": "끔", - "agentSettings": "에이전트 설정", - "searchModel": "모델 검색...", - "searchModelAria": "모델 검색", - "modelListLabel": "모델", - "noModels": "모델을 찾을 수 없습니다", - "cancel": "취소", - "send": "보내기", - "forkAndSend": "포크 & 전송", - "queueMessage": "대기열에 추가", - "steerIntoTurn": "현재 턴에 삽입", - "steerQueuedInstead": "대신 대기열에 추가되었습니다. 다음 턴에 전송됩니다.", - "steerFailed": "현재 턴에 삽입하지 못했습니다", - "steerAttachmentsUnsupported": "텍스트만 지원됩니다. 첨부 파일이 있는 초안은 대기열을 이용하세요.", - "slashCommands": "슬래시 명령", - "slashSearchPlaceholder": "명령 검색...", - "slashSearchEmpty": "일치하는 명령이 없습니다", - "experts": "전문가", - "office": "일상 업무", - "research": "과학 연구", - "attachLocalUpload": "로컬 파일 첨부", - "attachServerFile": "서버 파일 첨부", - "attachUploadTooLarge": "{names}이(가) {limit}MB 업로드 한도를 초과하여 건너뛰었습니다.", - "attachUploadFailed": "{names} 업로드 실패.", - "attachUploadNotAFile": "{names} 은(는) 일반 파일이 아니므로(디렉터리 또는 특수 파일) 건너뛰었습니다.", - "attachUploadQuotaExceeded": "서버 업로드 저장 공간이 부족하여 {names} 을(를) 업로드하지 못했습니다.", - "attachUploadInProgress": "이미지가 아직 업로드 중입니다. 잠시 후 다시 시도하세요.", - "mentionEmpty": "일치하는 항목 없음", - "mentionLoading": "검색 중…", - "mentionListLabel": "멘션", - "mentionMore": "결과가 더 있습니다. 계속 입력하여 필터링하세요", - "mentionCount": "{count, plural, other {결과 #개}}", - "mentionGroupFile": "파일", - "mentionGroupAgent": "에이전트", - "mentionGroupSession": "세션", - "mentionGroupCommit": "커밋", - "mentionGroupSkill": "스킬" - }, - "messageQueue": { - "addToQueue": "대기열에 추가", - "saveEdit": "저장", - "cancelEdit": "편집 취소", - "editItem": "편집", - "deleteItem": "삭제" - }, - "welcomeInputPanel": { - "agentsSettingsPath": "설정 > 에이전트", - "autoConnectFallback": "{path}을(를) 열어 설치를 관리하세요.", - "autoConnectAppend": "{message}. {path}을(를) 열어 설치를 관리하세요.", - "enableAgentFirstPlaceholder": "세션을 시작하기 전에 최소 한 개의 에이전트를 활성화하세요...", - "prepareSessionFailed": "채팅 세션을 준비하지 못했습니다. 다시 시도해 주세요.", - "createConversationFailed": "대화를 만들지 못했습니다. 다시 시도해 주세요.", - "askAnythingPlaceholder": "무엇이든 물어보세요...", - "agentNotInstalled": "{agent}이(가) 설치되지 않았습니다 · 클릭하여 Agents 설정에서 설치하세요", - "agentAdapterNotInstalled": "{agent}의 ACP 어댑터가 설치되지 않았습니다(사용 중인 CLI와는 별개) · 클릭하여 Agents 설정에서 설치하세요" - }, - "welcomePanel": { - "greeting": "오늘은 무엇을 해볼까요?", - "tips": { - "tileTabs": "대화 탭을 우클릭하고 '바둑판 표시'를 선택하면 여러 세션을 나란히 비교할 수 있습니다", - "pinTab": "대화 탭을 더블클릭하면 고정되어 새로 열린 세션이 자동으로 대체하지 않습니다", - "shortcutsNewSearch": "{newConversation}로 새 대화를 열고, {searchConversations}로 기록을 검색할 수 있습니다", - "slashAtMention": "입력창에서 /를 입력하면 슬래시 명령, @를 입력하면 프로젝트 내 파일을 참조할 수 있습니다", - "pasteDropFiles": "스크린샷을 붙여넣거나 파일을 입력창에 드롭하면 바로 첨부됩니다", - "queueMessage": "에이전트가 응답 중일 때도 계속 입력하면 다음 메시지가 대기열에 들어가 응답 후 자동 전송됩니다", - "draftAutoSave": "보내지 않은 초안은 대화별로 자동 저장되어 돌아왔을 때 복원됩니다", - "forkSend": "전송 버튼의 드롭다운에서 '분기 후 전송'을 선택하면 현재 지점에서 새 탭으로 분기할 수 있습니다", - "exportConversation": "대화 내용을 우클릭하면 Markdown / HTML / 이미지로 내보낼 수 있습니다", - "chatChannels": "'설정 → 채팅 채널'에서 Telegram / Lark / WeChat을 연결하면 휴대폰에서 이어서 사용할 수 있습니다", - "shortcutsAuxPanel": "{toggleAuxPanel}로 오른쪽 패널을 열어 이번 세션에서 변경된 파일과 Git 변경 사항을 확인할 수 있습니다", - "shortcutsTerminalSidebar": "{toggleTerminal}로 내장 터미널, {toggleSidebar}로 사이드바를 토글할 수 있습니다", - "customShortcuts": "모든 단축키는 '설정 → 단축키'에서 자유롭게 변경할 수 있습니다", - "webService": "'설정 → 웹 서비스'를 켜면 팀원이 브라우저로 같은 codeg에 접속할 수 있습니다", - "fusionMode": "파일이나 diff를 열면 대화 옆에 자동으로 표시됩니다.", - "quickMessages": "입력창 옆 + 버튼에서 '빠른 메시지'를 선택하면 저장된 스니펫을 한 번에 삽입할 수 있습니다('설정 → 빠른 메시지'에서 관리)", - "experts": "+ 버튼의 '전문가 스킬' 메뉴에서 디버그 / 기획 등 사전 정의된 역할을 한 번에 불러올 수 있습니다", - "taskBoard": "할 일은 작업을 끝까지 처리합니다. 에이전트가 전용 워크트리에서 작업하고, 여러분은 diff를 검토한 뒤 병합합니다.", - "automations": "자동화는 저장한 프롬프트를 일정에 따라 실행합니다(매일 밤 리뷰 등). 실행마다 전용 워크트리를 쓸 수도 있습니다.", - "tokenUsage": "상태 표시줄의 대화 수를 클릭하면 토큰 사용량이 열립니다. 날짜·에이전트·모델·폴더별 사용량을 확인할 수 있습니다.", - "mentionTargets": "@는 파일만 참조하는 것이 아닙니다. 다른 에이전트를 멘션해 하위 작업을 맡기거나, 지난 세션·커밋·스킬을 참조할 수 있습니다.", - "splitGroups": "탭을 우클릭해 「오른쪽으로 분할」 또는 「아래로 분할」을 고르면 두 대화를 각각의 창에 열어 둘 수 있습니다.", - "worktrees": "브랜치 버튼에서 「새 워크트리」를 고르면 여러 에이전트가 같은 저장소에서 서로의 파일을 덮어쓰지 않고 동시에 작업할 수 있습니다.", - "importSessions": "터미널에서 이미 실행한 세션이 있다면 폴더 메뉴의 「로컬 세션 가져오기」로 그 기록을 codeg에 가져올 수 있습니다.", - "subSessions": "에이전트가 위임하면 하위 세션이 사이드바에서 상위 세션 아래에 중첩되어 표시됩니다. 행을 펼치면 각각이 무엇을 했는지 확인할 수 있습니다.", - "liveFeedback": "「+」 메뉴의 라이브 피드백은 에이전트가 진행 중인 턴에 메모를 끼워 넣습니다. 작업을 끊지 않아도 됩니다.", - "skillPacks": "설정 → 스킬 팩에는 코딩 전문가, 과학 연구, 오피스 스킬이 묶여 있습니다. 에이전트별로 켜고 끌 수 있습니다.", - "modelProviders": "설정 → 모델 제공업체에서 직접 API 키나 엔드포인트를 등록하면, 입력창에서 바로 모델을 고를 수 있습니다.", - "workspaceBackground": "설정 → 외관에서 작업 공간 배경 이미지, 패널 불투명도, 앱 글꼴을 바꿀 수 있습니다." - }, - "quickActions": { - "excel": "Excel 통합 문서", - "excelDesc": "데이터 표, 수식, 차트", - "word": "Word 문서", - "wordDesc": "보고서, 편지, 메모", - "ppt": "프레젠테이션", - "pptDesc": "전문 디자인 슬라이드", - "pitchDeck": "피치덱", - "pitchDeckDesc": "핵심 지표가 담긴 투자 자료", - "morph": "Morph 애니메이션", - "morphDesc": "영화 같은 슬라이드 전환", - "morph3d": "3D Morph", - "morph3dDesc": "3D 모델과 카메라 무빙", - "academic": "학술 논문", - "academicDesc": "인용과 구조를 갖춘 연구 논문", - "financial": "재무 모델", - "financialDesc": "재무제표, DCF, 예측", - "dashboard": "데이터 대시보드", - "dashboardDesc": "데이터로 KPI와 분석 생성", - "prompts": { - "excel": "다음 요구 사항으로 Excel 통합 문서를 만들어 주세요:\n\n[데이터, 표, 수식, 차트를 여기에 설명]", - "word": "다음 요구 사항으로 Word 문서를 만들어 주세요:\n\n[문서 내용, 구조, 서식을 여기에 설명]", - "ppt": "다음 요구 사항으로 PowerPoint 프레젠테이션을 만들어 주세요:\n\n[슬라이드, 내용, 디자인을 여기에 설명]", - "pitchDeck": "다음 요구 사항으로 투자 피치덱을 만들어 주세요:\n\n[회사, 투자 라운드, 핵심 지표를 여기에 설명]", - "morph": "Morph 전환 애니메이션이 있는 프레젠테이션을 만들어 주세요:\n\n[발표 주제와 원하는 시각 효과를 여기에 설명]", - "morph3d": "GLB 모델과 카메라 무빙이 있는 3D Morph 프레젠테이션을 만들어 주세요:\n\n[주제와 3D 비주얼 콘셉트를 여기에 설명]", - "academic": "다음 요구 사항으로 Word 학술 논문을 작성해 주세요:\n\n[연구 주제, 방법론, 주요 결과를 여기에 설명]", - "financial": "다음 요구 사항으로 Excel 재무 모델을 만들어 주세요:\n\n[재무제표, 예측, 분석을 여기에 설명]", - "dashboard": "다음 요구 사항으로 Excel 데이터 대시보드를 만들어 주세요:\n\n[데이터 소스, KPI, 차트를 여기에 설명]", - "scientific-brainstorming": "연구 방향을 브레인스토밍해 주세요. 학제 간 연결을 탐색하고 가정을 검토하며 유망한 공백을 찾습니다. 탐색 중인 분야: ", - "hypothesis-generation": "이 관찰을 검증 가능한 가설로 바꿔 주세요. 명확한 예측, 그럴듯한 메커니즘, 검증 실험을 제시합니다. 내 관찰: ", - "experimental-design": "데이터 수집 전에 엄밀한 실험을 설계해 주세요. 설계, 무작위화, 대조, 교란 회피 방법을 포함합니다. 연구하려는 것: ", - "statistical-power": "필요한 표본 크기를 정해 주세요. 내 설계에 대해 검정력 분석(효과크기, 유의수준, 검정력)을 진행합니다. 세부 정보: ", - "statistical-analysis": "이 데이터를 제대로 분석해 주세요. 올바른 검정 선택, 가정 점검, 효과크기 보고, 결과 서술을 합니다. 내 데이터와 질문: ", - "exploratory-data-analysis": "내 데이터 파일을 탐색적으로 분석해 주세요. 구조, 품질, 주목할 패턴을 요약하고 다음 단계를 제안합니다. 파일: ", - "scientific-visualization": "출판 수준의 그림을 만들어 주세요. 명확한 배치, 정직한 오차 막대, 색각 이상을 고려한 팔레트, 저널 서식을 사용합니다. 보여주려는 것: ", - "scientific-critical-thinking": "이 연구나 주장을 비판적으로 평가해 주세요. 근거의 질을 평가하고 편향과 교란을 찾아 결론을 따져봅니다. 대상: ", - "paper-lookup": "학술 데이터베이스에서 관련 논문과 오픈액세스 전문을 찾고 재사용할 수 있는 인용도 제시해 주세요. 찾는 것: " - }, - "paper-lookup": "논문 검색", - "paper-lookupDesc": "10개 학술 API(PubMed, arXiv, OpenAlex, Crossref…)에서 논문·인용·오픈액세스 전문을 검색합니다.", - "scientific-critical-thinking": "비판적 사고", - "scientific-critical-thinkingDesc": "과학적 주장과 근거의 질을 평가 — 편향·교란을 찾고 GRADE 및 비뚤림 위험 프레임워크를 적용.", - "scientific-visualization": "과학적 시각화", - "scientific-visualizationDesc": "출판 수준 그림 — 다중 패널 배치, 유의성 주석, 저널별 서식.", - "exploratory-data-analysis": "탐색적 데이터 분석", - "exploratory-data-analysisDesc": "200종 이상 형식의 과학 데이터 파일을 자동 탐색하고 품질 지표와 보고서를 생성합니다.", - "statistical-analysis": "통계 분석", - "statistical-analysisDesc": "안내형 통계 분석 — 검정 선택, 가정 점검, 효과크기, APA 형식 보고.", - "statistical-power": "통계적 검정력", - "statistical-powerDesc": "표본 크기와 검정력 분석 — 필요한 대상 수, 최소 검출 가능 효과, 검정력 곡선.", - "experimental-design": "실험 설계", - "experimental-designDesc": "데이터 수집 전에 엄밀한 연구를 설계 — 무작위화, 블록화, 대조, 요인/DOE 배치.", - "hypothesis-generation": "가설 생성", - "hypothesis-generationDesc": "관찰을 검증 가능한 가설로 전환하고 예측·메커니즘·검증 실험을 제시합니다.", - "scientific-brainstorming": "과학적 브레인스토밍", - "scientific-brainstormingDesc": "열린 연구 아이디어 발상 — 학제 간 연결을 탐색하고 가정을 검토하며 연구 공백을 찾습니다.", - "tabs": { - "office": "일상 업무", - "coding": "코드 개발", - "research": "과학 연구" - }, - "coding": { - "brainstormingDesc": "구현 전 의도와 요구사항 탐색", - "debuggingDesc": "수정 제안 전에 근본 원인 파악", - "writingSkillsDesc": "재사용 가능한 스킬 생성·편집·검증" - }, - "notEnabled": { - "title": "‘{skill}’ 스킬이 아직 {agent}에서 활성화되지 않았습니다", - "description": "설정에서 활성화하면 여기서 사용할 수 있습니다.", - "action": "활성화하기", - "hint": "스킬이 비활성화됨" - }, - "scrollPrev": "이전 스킬 표시", - "scrollNext": "다음 스킬 표시" - } - }, - "agentSelector": { - "noEnabledAgents": "활성화된 에이전트가 없습니다", - "openAgentsSettings": "에이전트 설정 열기", - "notInstalled": "설치되지 않음", - "moreAgents": "에이전트 더 보기 ({count})" - }, - "subAgentOverlay": { - "title": "서브 에이전트", - "collapsedSummary": "서브 에이전트 {count}", - "collapseAria": "서브 에이전트 접기" - }, - "agentPlanOverlay": { - "title": "에이전트 계획", - "collapsePlanAria": "계획 접기", - "collapsedSummary": "계획 {completed}/{total}", - "status": { - "completed": "완료", - "inProgress": "진행 중", - "pending": "대기", - "unknown": "알 수 없음" - }, - "priority": { - "high": "높음", - "medium": "중간", - "low": "낮음", - "unknown": "알 수 없음" - } - }, - "permissionDialog": { - "subtitle": "에이전트가 이 턴을 계속하기 위한 권한을 요청합니다.", - "queuedCount": "{count}건 대기 중", - "kindFallbackTool": "도구", - "command": "명령", - "cwd": "작업 디렉터리: {cwd}", - "filesSummary": "파일: {count}", - "moreFiles": "+{count}개 파일 더", - "plan": "계획", - "allowedActions": "허용된 작업", - "targetMode": "대상 모드: {mode}", - "optionGrants": "각 옵션이 부여하는 권한", - "changeScopeSession": "이 세션", - "changeScopeProcess": "이 실행", - "changeScopeUser": "사용자 설정에 저장", - "changeScopeProject": "프로젝트 설정에 저장", - "changeScopeProjectLocal": "로컬 프로젝트 설정에 저장", - "changeScopePersistent": "영구 저장" - }, - "questionDialog": { - "title": "에이전트가 질문하고 있습니다", - "placeholder": "답변을 입력하세요...", - "send": "전송" - }, - "messageBranch": { - "previousBranchAria": "이전 브랜치", - "nextBranchAria": "다음 브랜치", - "pageOf": "{current} / {total}" - }, - "terminal": { - "title": "터미널", - "running": "실행 중" - }, - "reasoning": { - "thinking": "생각 중…", - "thoughtForFewSeconds": "생각함", - "thoughtForSeconds": "생각함" - }, - "linkSafety": { - "errorCannotOpen": "로컬 파일을 열 수 없습니다", - "errorNoWorkspace": "현재 활성화된 워크스페이스 폴더가 없습니다.", - "errorFailedOpen": "로컬 파일 열기 실패", - "errorFailedLink": "링크 열기 실패", - "errorUnsupportedLinkProtocol": "이 링크 프로토콜은 지원되지 않습니다." - }, - "fileActions": { - "openInFinder": "Finder에서 열기", - "openInExplorer": "Explorer에서 열기", - "openInFileManager": "파일 관리자에서 열기", - "copyRelativePath": "상대 경로 복사", - "copyAbsolutePath": "절대 경로 복사", - "pathCopied": "경로가 복사되었습니다", - "copyPathFailed": "경로 복사에 실패했습니다", - "openFailed": "로컬 파일 열기 실패" - }, - "messageList": { - "attachedResources": "첨부된 리소스", - "loading": "불러오는 중...", - "loadEarlier": "이전 메시지 불러오기", - "loadingEarlier": "이전 메시지를 불러오는 중…", - "error": "오류: {message}", - "errorTitle": "세션 불러오기 실패", - "errorActionReload": "다시 불러오기", - "errorActionNewSession": "새 대화", - "emptyConversation": "이 대화에는 메시지가 없습니다.", - "systemMessage": "시스템 메시지", - "copyMessage": "복사", - "copied": "복사됨", - "downloadImage": "이미지 다운로드", - "downloadFailed": "다운로드 실패: {message}", - "imageGeneration": "이미지 생성", - "imageGenerationPending": "이미지 생성 중…", - "imageGenerationFailed": "이미지 생성 실패", - "model": "모델", - "tokenStats": "토큰 사용량", - "tokenInput": "입력", - "tokenOutput": "출력", - "tokenCacheRead": "캐시 읽기", - "tokenCacheWrite": "캐시 쓰기", - "duration": "소요 시간", - "completedAt": "완료 시각", - "jumpToPreviousUserMessage": "이전 사용자 메시지로 이동", - "showMore": "더보기", - "showLess": "접기" - }, - "liveTurnStats": { - "thinking": "생각 중...", - "streaming": "스트리밍 중", - "elapsedHours": "{value}시간", - "elapsedMinutes": "{value}분", - "elapsedSeconds": "{value}초", - "outputSpeedAria": "예상 출력 속도", - "outputSpeedTooltip": "예상 출력 속도(텍스트 + 추론)" - }, - "jsonTree": { - "viewRaw": "원본 JSON 보기", - "viewTree": "트리 보기", - "fields": "필드 {count}개", - "items": "항목 {count}개" - }, - "tool": { - "parameters": "매개변수", - "error": "오류", - "result": "결과", - "status": { - "approvalRequested": "승인 대기 중", - "approvalResponded": "응답됨", - "inputAvailable": "실행 중", - "inputStreaming": "대기 중", - "outputAvailable": "완료", - "outputDenied": "거부됨", - "outputError": "오류" - } - }, - "toolCallBlock": { - "tool": "도구", - "error": "오류", - "result": "결과" - }, - "delegation": { - "subAgentRunning": "서브에이전트 실행 중…", - "noDetail": "No detail available yet.", - "unknownAgent": "하위 에이전트", - "openDetail": "대화 보기", - "detailTitle": "서브에이전트 대화", - "detailDescription": "위임된 서브에이전트 대화를 읽기 전용으로 봅니다.", - "waitForResult": "작업 {task} 실행 결과 대기 중", - "waitForResultNoTask": "작업 실행 결과 대기 중", - "cancelTask": "작업 {task} 취소 중", - "cancelTaskNoTask": "작업 취소 중", - "resultPageOf": "{current} / {total}", - "prevResult": "이전 결과", - "nextResult": "다음 결과", - "noResultText": "이 확인에서는 결과가 없습니다", - "status": { - "starting": "시작 중", - "running": "실행 중", - "checked": "확인됨", - "waiting": "승인 대기 중", - "ok": "완료", - "err": { - "default": "실패", - "delegation_disabled": "비활성화됨", - "depth_limit": "깊이 제한", - "invalid_agent_type": "잘못된 에이전트", - "spawn_failed": "시작 실패", - "send_failed": "전송 실패", - "timeout": "시간 초과", - "canceled": "취소됨", - "child_refusal": "서브에이전트 거부", - "child_max_tokens": "서브에이전트: 토큰 한도", - "child_max_turn_requests": "서브에이전트: 요청 한도", - "child_empty": "서브에이전트 응답 없음", - "child_unknown": "서브에이전트: 오류", - "unknown": "알 수 없는 작업" - } - } - }, - "contentParts": { - "showingTailOutput": "성능을 위해 스트리밍 중에는 출력의 끝부분만 표시합니다.", - "result": "결과", - "unknown": "알 수 없음", - "inputTruncated": "입력이 잘렸습니다 — diff가 불완전할 수 있습니다.", - "replaceAll": "모두 바꾸기", - "filesCount": "파일: {count}", - "update": "업데이트", - "moreFiles": "+{count}개 파일 더", - "timeoutMs": "시간 초과: {timeout}ms", - "backgroundTrue": "백그라운드: true", - "scriptToolCalls": "도구 {count}개 호출", - "offset": "오프셋: {offset}", - "limit": "제한: {limit}", - "pages": "페이지: {pages}", - "mode": "모드: {mode}", - "cell": "셀: {cell}", - "shellSession": "세션 {id}", - "pathLabel": "경로:", - "globLabel": "Glob 패턴:", - "typeLabel": "유형:", - "outputLabel": "출력:", - "caseInsensitive": "대소문자 구분 안 함", - "multiline": "여러 줄", - "promptLabel": "프롬프트", - "subjectLabel": "제목", - "taskLabel": "작업", - "nameLabel": "이름:", - "agentPromptLabel": "프롬프트", - "agentModelLabel": "모델", - "agentRunning": "실행 중...", - "agentLiveTranscript": "실시간 활동", - "agentProgressTools": "도구 호출 {count}회", - "agentProgressTurns": "{count} 턴", - "agentProgressContext": "컨텍스트 {pct}%", - "agentSessionAction": "하위 에이전트 세션 보기", - "agentSessionTitle": "하위 에이전트 세션", - "agentSessionLoading": "하위 에이전트의 기록을 불러오는 중…", - "agentSessionEmpty": "하위 에이전트가 아직 아무것도 기록하지 않았습니다.", - "agentFallbackTitle": "서브 에이전트 시작 중…", - "agentCodexLaunchOnly": "시작되었습니다. Codex는 이 하위 에이전트의 진행 상황을 더 이상 알리지 않으며, 결과는 이 대화의 메시지로 도착합니다.", - "agentStatsBash": "명령", - "agentStatsRead": "파일 읽기", - "agentStatsSearch": "검색", - "agentStatsEdit": "편집", - "agentStatsOther": "기타", - "goal": { - "title": "목표:", - "titleWithStatus": "목표 {status}", - "objective": "목표", - "statusLabel": "상태", - "tokensUsed": "사용 tokens", - "budget": "예산", - "remaining": "남음", - "elapsed": "경과", - "tokens": "tokens", - "pause": "일시정지", - "clear": "지우기", - "status": { - "active": "진행 중", - "paused": "일시 중지", - "blocked": "차단됨", - "usageLimited": "사용량 제한", - "budgetLimited": "예산 제한", - "complete": "완료", - "limited": "한도 도달" - } - }, - "field": { - "file": "파일", - "notebook": "노트북", - "command": "명령", - "old": "이전", - "new": "새", - "pattern": "패턴", - "path": "경로", - "query": "쿼리", - "url": "URL:", - "description": "설명", - "content": "내용", - "source": "소스", - "prompt": "프롬프트", - "subject": "제목", - "taskId": "작업 ID", - "status": "상태", - "skill": "Skill", - "args": "인자", - "offset": "오프셋", - "limit": "제한", - "glob": "Glob 패턴", - "type": "유형", - "output": "출력", - "replaceAll": "모두 바꾸기", - "language": "언어", - "timeout": "시간 초과", - "background": "백그라운드", - "agentType": "에이전트 유형", - "library": "라이브러리", - "libraryId": "라이브러리 ID" - }, - "title": { - "edit": "편집", - "command": "명령", - "script": "스크립트", - "waitCommand": "대기 {command}", - "waitCell": "세션 {id} 대기", - "terminateCommand": "종료 {command}", - "terminateCell": "세션 {id} 종료", - "stdinChars": "입력 {chars}", - "todoWrite": "TodoWrite(할 일 업데이트)", - "read": "읽기", - "write": "쓰기", - "notebookEdit": "NotebookEdit(노트북 편집)", - "editFiles": "편집 ({count}개 파일)", - "editWithTarget": "{target} 편집", - "readWithTarget": "{target} 읽기", - "writeWithTarget": "{target} 쓰기", - "notebookEditWithTarget": "NotebookEdit({target})", - "globWithPattern": "Glob 패턴 {pattern}", - "listFilesWithPath": "파일 목록 {path}", - "grepWithPattern": "Grep 패턴 {pattern}", - "taskCreateWithSubject": "작업 생성: {subject}", - "taskUpdateWithStatus": "작업 업데이트 #{id} -> {status}", - "taskUpdate": "작업 업데이트 #{id}", - "webFetchWithUrl": "WebFetch ({url})", - "webSearchWithQuery": "WebSearch ({query})", - "todosProgress": "할 일 ({done}/{total})", - "skillWithName": "Skill: {name}", - "genericWithContext": "{tool} ({context})" - }, - "search": { - "noMatches": "일치하는 결과 없음", - "matchSummary": "{matches}개 일치 · {files}개 파일", - "fileSummary": "{files}개 파일", - "moreResults": "{count}개 결과가 더 있음(표시되지 않음)" - }, - "toolGroup": { - "search": "{count}회 검색", - "command": "명령 {count}개 실행", - "read": "파일 {count}회 읽기", - "memory": "기억 {count}개 회상", - "edit": "파일 {count}회 편집", - "fetch": "리소스 {count}개 가져오기", - "think": "{count}회 사고", - "todo": "할 일 {count}개 업데이트", - "task": "작업 {count}개 실행", - "other": "도구 {count}개 사용", - "errorSuffix": "{count}건 실패", - "joiner": " · " - }, - "planMode": { - "entered": "계획 모드 시작", - "planLabel": "계획", - "reviewApproved": "계획 승인됨 — 실행 중", - "reviewKept": "계획 모드 유지", - "reviewPending": "계획 결정 대기 중", - "submitted": "계획 제출됨", - "switched": "모드 전환됨" - }, - "backgroundTask": { - "title": "백그라운드 작업", - "titleWithId": "백그라운드 작업 · {id}", - "running": "실행 중", - "completed": "완료됨", - "failed": "실패", - "stopped": "중지됨", - "exitCode": "종료 코드 {code}", - "polledTimes": "{count}회 폴링", - "runningInBackground": "백그라운드", - "launchNote": "백그라운드에서 실행 중 · {id}" - }, - "codexScript": { - "outputMissing": "codex가 스크립트 출력을 잘라내면서 이 명령의 구분선이 사라져 출력을 귀속시킬 수 없습니다.", - "sharedWith": "이 구간에는 {commands}의 출력도 포함됩니다 — 구분선이 codex에 의해 잘렸습니다.", - "truncated": "잘림" - } - }, - "messageNav": { - "title": "메시지 탐색", - "collapse": "메시지 탐색 접기", - "collapsedSummary": "메시지 {count}", - "fileCount": "{count, plural, one {#개 파일} other {#개 파일}}", - "remove": "제거", - "noDiffDataAvailable": "{filePath}에 대한 diff 데이터가 없습니다" - }, - "replyArtifacts": { - "title": "변경된 파일", - "fileCount": "{count, plural, one {#개 파일} other {#개 파일}}", - "newFilesTitle": "새 파일", - "revealInFolder": "파일 관리자에서 표시", - "openFile": "{filePath} 열기", - "openInEditor": "편집기에서 열기", - "remove": "제거", - "noDiffDataAvailable": "{filePath}에 대한 diff 데이터가 없습니다" - }, - "askQuestion": { - "title": "에이전트가 선택을 요청합니다", - "subtitle": "답변 후 제출하세요. 언제든 건너뛸 수 있습니다", - "recommended": "추천", - "other": "기타", - "otherPlaceholder": "답변을 입력하세요…", - "singleSelect": "단일 선택", - "multiSelect": "다중 선택", - "skip": "건너뛰기", - "next": "다음", - "submit": "제출", - "submitError": "제출하지 못했습니다. 다시 시도해 주세요." - }, - "planApproval": { - "title": "에이전트가 계획을 제시했습니다 — 검토하세요", - "emptyPlan": "에이전트가 계획을 작성하지 않았습니다. 승인하여 구현을 시작하거나 변경을 요청하세요.", - "approve": "승인하고 시작", - "requestChanges": "변경 요청", - "abandon": "포기", - "feedbackPlaceholder": "무엇을 변경할까요?", - "sendChanges": "보내기", - "cancel": "취소", - "submitError": "제출하지 못했습니다. 다시 시도하세요." - }, - "feedbackCheckResult": { - "count": "피드백 {count}개", - "expand": "모든 피드백 표시", - "collapse": "접기", - "errorTitle": "피드백 확인 실패" - }, - "askQuestionResult": { - "title": "질문", - "answeredLabel": "질문과 답변:", - "awaiting": "답변을 기다리는 중…", - "declined": "이 질문을 건너뛰었습니다 — 에이전트가 자체 판단으로 진행했습니다.", - "noSelection": "선택 없음" - }, - "configStale": { - "agentConfigTitle": "에이전트 설정이 업데이트되었습니다", - "modelProviderTitle": "모델 공급자가 업데이트되었습니다", - "description": "이 세션은 아직 이전 설정을 사용 중입니다. 다시 연결하면 적용됩니다(대화 기록은 유지됩니다).", - "reconnect": "다시 연결하여 적용", - "reconnecting": "다시 연결하는 중…", - "reconnectDisabledDuringTurn": "현재 턴이 끝나면 다시 연결할 수 있습니다", - "dismiss": "닫기", - "reconnectFailed": "세션 다시 연결 실패", - "applied": "새 설정이 적용되었습니다" - }, - "piProjectTrust": { - "title": "이 프로젝트에 pi 리소스가 포함되어 있습니다", - "description": "pi가 저장소 자체의 .pi 파일을 불러오지 않고 있습니다. 확인 후 결정하세요.", - "descriptionExecutable": "저장소에 pi 확장이 포함되어 있으며, 확장은 시작 시 코드를 실행합니다. pi는 아직 불러오지 않았습니다. 결정하기 전에 확인하세요.", - "review": "검토…", - "dismiss": "닫기", - "dialogTitle": "이 프로젝트의 pi 리소스를 신뢰하시겠습니까?", - "dialogDescription": "폴더를 신뢰해야만 pi가 저장소 자체의 .pi 파일을 불러옵니다. 이 저장소의 내용을 신뢰하는 경우에만 허용하세요.", - "executionWarning": "확장은 코드입니다. 이 폴더를 신뢰하면 메시지를 보내기 전에 저장소의 확장이 pi 시작 시 사용자 권한으로 실행됩니다.", - "scopeNote": "이 결정은 pi의 trust.json에 저장되며 해당 폴더 아래의 모든 폴더에 적용되고, 터미널에서 직접 pi를 실행할 때에도 사용됩니다. 나중에 설정 → 에이전트 → Pi에서 변경할 수 있습니다.", - "trust": "프로젝트 신뢰", - "decline": "불러오지 않음", - "disabledDuringTurn": "현재 턴이 끝나면 사용할 수 있습니다", - "trustedToast": "프로젝트를 신뢰했습니다 — pi가 리소스를 불러오도록 다시 연결했습니다", - "declinedToast": "프로젝트 리소스를 불러오지 않습니다", - "saveFailed": "프로젝트 신뢰 설정을 저장하지 못했습니다", - "grantTitle": "이 프로젝트는 이미 신뢰됨", - "grantDescription": "pi가 이 저장소 자체의 .pi 파일을 불러옵니다. 무엇이 허용되는지 확인하세요.", - "grantInheritedDescription": "상위 폴더가 신뢰되어 pi가 이 저장소 자체의 .pi 파일을 불러옵니다. 무엇이 허용되는지 확인하세요.", - "grantDialogTitle": "이 프로젝트의 pi 리소스가 신뢰됨", - "grantDialogDescription": "pi가 이 저장소 자체의 .pi 파일을 불러오도록 허용되어 있습니다. 이전 codeg 버전은 폴더를 열 때 자동으로 이를 허용했으므로 확인을 요청받지 않았을 수 있습니다.", - "grantExecutionWarning": "확장은 코드입니다. 저장소의 확장은 메시지를 보내기 전에 pi 시작 시 사용자 권한으로 실행됩니다.", - "inheritedFrom": "신뢰 출처", - "revoke": "신뢰 취소", - "keepTrusted": "신뢰 유지", - "revokedToast": "신뢰를 취소했습니다 — 다시 연결하여 pi가 프로젝트 리소스를 불러오지 않습니다", - "trustedNoReconnect": "프로젝트를 신뢰했습니다 — pi가 다음에 시작할 때 적용됩니다", - "revokedNoReconnect": "신뢰를 취소했습니다 — pi가 다음에 시작할 때 적용됩니다" - }, - "collabAgent": { - "title": "서브 에이전트", - "errorTitle": "서브 에이전트 작업이 실패했습니다", - "statesLabel": "서브 에이전트", - "statusRunning": "실행 중", - "statusCompleted": "완료됨", - "statusFailed": "실패", - "statusPending": "시작 중", - "statusInterrupted": "중단됨", - "statusClosed": "종료됨", - "statusNotFound": "찾을 수 없음", - "opSpawn": "서브 에이전트 시작 중", - "opWait": "서브 에이전트 결과 가져오는 중", - "opClose": "서브 에이전트 종료 중", - "opResume": "서브 에이전트 재개 중" - }, - "contextCompaction": { - "compacting": "컨텍스트 압축 중…", - "compacted": "컨텍스트 압축 완료", - "compactedTokens": "컨텍스트 압축 완료 · {before} → {after} 토큰", - "failed": "컨텍스트 압축 실패" - }, - "sessionFailure": { - "category": { - "connection": "연결 문제", - "access": "액세스 문제", - "limit": "한도 도달", - "request": "요청 거부됨", - "service": "서비스 문제", - "unknown": "세션 문제" - }, - "action": { - "retry": "다시 시도", - "login": "로그인", - "newSession": "새 세션" - }, - "recovered": "복구됨", - "retryUnavailable": "다시 보낼 메시지가 없습니다.", - "toggleDetails": "세부 정보 전환" - }, - "backgroundTasks": { - "running": "백그라운드 작업 {count}개 실행 중", - "settling": "백그라운드 결과 동기화 중…", - "settledFallback": "백그라운드 작업이 종료되었습니다 ({status})", - "cardRunning": "백그라운드에서 실행 중", - "cardLaunchedPending": "백그라운드 작업 시작됨", - "cardCompleted": "백그라운드 작업 완료", - "cardFinishedWithStatus": "백그라운드 작업 종료 ({status})", - "cardResultPending": "결과가 아직 반환되지 않았습니다" - }, - "proposedPlan": { - "title": "제안된 계획", - "planning": "계획 중…" - } - }, - "diffPreview": { - "mode": { - "added": "추가됨", - "deleted": "삭제됨", - "renamed": "이름 변경됨", - "modified": "수정됨" - }, - "hunkLabel": "청크 {index}", - "loadingHunk": "Hunk 로딩 중...", - "noDiffData": "Diff 데이터 없음", - "showRemainingLines": "나머지 {count}줄 표시" - }, - "conversationContextBar": { - "folderTitle": "작업 폴더", - "branchTitle": "작업 브랜치", - "searchFolder": "Search folder...", - "searchBranch": "Search branch...", - "noFolders": "No folders", - "noBranches": "No branches", - "noBranch": "(no branch)", - "chatModeLabel": "채팅 모드", - "commit": "Commit", - "push": "Push", - "merge": "Merge", - "toasts": { - "folderChanged": "Switched to {name}", - "openFolderFailed": "Failed to open folder", - "switchedToChatMode": "채팅 모드로 전환했습니다", - "openStashFailed": "Failed to open stash window", - "openMergeFailed": "Failed to open merge window" - } - }, - "cloneDialog": { - "title": "저장소 클론", - "repositoryUrl": "저장소 URL", - "repositoryUrlPlaceholder": "https://github.com/user/repo.git", - "directory": "디렉터리", - "directoryPlaceholder": "대상 디렉터리 선택...", - "browseDirectory": "디렉터리 찾아보기", - "cancel": "취소", - "clone": "클론", - "clonePath": "클론 경로: {path}" - }, - "toasts": { - "cloneFailed": "저장소 클론에 실패했습니다" - } - }, - "ProjectBoot": { - "title": "프로젝트 부트", - "tabs": { - "shadcn": "shadcn", - "hyperframes": "HyperFrames" - }, - "hyperframes": { - "title": "HyperFrames 비디오 프로젝트", - "subtitle": "HTML을 비디오로 만드는 프로젝트를 생성합니다. 이후 워크스페이스 에이전트가 작성하고 렌더링할 수 있습니다.", - "resolution": "해상도", - "skillsTitle": "에이전트 스킬", - "skillsDesc": "선택한 에이전트에 HyperFrames 스킬을 전역(심볼릭 링크)으로 설치하여 영상 작성·렌더링을 지원합니다.", - "recheck": "다시 확인", - "installedBadge": "설치됨", - "skillsInstall": "스킬 설치 / 업데이트", - "skillsInstalling": "스킬 설치 중…", - "skillsInstalled": "HyperFrames 스킬 설치 완료", - "skillsInstallFailed": "HyperFrames 스킬 설치 실패" - }, - "config": { - "base": "베이스", - "style": "스타일", - "baseColor": "베이스 색상", - "theme": "테마", - "chartColor": "차트 색상", - "iconLibrary": "아이콘 라이브러리", - "font": "글꼴", - "fontHeading": "제목 글꼴", - "menuAccent": "메뉴 강조", - "menuColor": "메뉴 색상", - "radius": "둥글기", - "template": "템플릿", - "createProject": "프로젝트 만들기", - "sectionStyle": "스타일", - "sectionColors": "색상", - "sectionTypography": "타이포그래피", - "sectionInterface": "인터페이스" - }, - "preview": { - "loading": "미리보기 로딩 중..." - }, - "createDialog": { - "title": "프로젝트 만들기", - "projectName": "프로젝트 이름", - "projectNamePlaceholder": "my-app", - "frameworkTemplate": "프레임워크 템플릿", - "packageManager": "패키지 매니저", - "saveDirectory": "저장 디렉토리", - "saveDirectoryPlaceholder": "디렉토리 선택...", - "browseDirectory": "찾아보기", - "projectPath": "프로젝트 생성 위치: {path}", - "advancedOptions": "고급 옵션", - "base": "기본 라이브러리", - "enableRtl": "RTL 지원 활성화", - "enableRtlDescription": "오른쪽에서 왼쪽으로 쓰는 언어(예: 아랍어, 히브리어)의 레이아웃 지원 활성화", - "pmChecking": "확인 중...", - "pmNotInstalled": "설치되지 않음", - "cancel": "취소", - "create": "만들기", - "creating": "프로젝트 생성 중..." - }, - "toasts": { - "createFailed": "프로젝트 생성에 실패했습니다", - "createSuccess": "프로젝트가 성공적으로 생성되었습니다", - "openWorkspaceFailed": "프로젝트가 생성되었지만 작업 공간에서 열지 못했습니다" - }, - "errors": { - "directoryExists": "대상 디렉터리가 이미 존재합니다", - "commandFailed": "프로젝트 생성 명령이 실패했습니다." - } - }, - "WebServiceSettings": { - "addressSwitchHint": "전환해도 여기에 표시되고 열리는 주소만 바뀝니다. 서비스는 모든 인터페이스에서 수신하며 어떤 주소로도 접속할 수 있습니다.", - "sectionTitle": "웹 서비스", - "sectionDescription": "활성화하면 브라우저를 통해 Codeg에 원격으로 접속할 수 있습니다", - "port": "포트", - "status": "상태", - "autoStart": "자동 시작", - "autoStartHint": "Codeg가 시작될 때 웹 서비스를 시작합니다", - "running": "실행 중", - "stopped": "중지됨", - "processing": "처리 중...", - "start": "시작", - "stop": "중지", - "startFailed": "시작 실패", - "stopFailed": "중지 실패", - "saveConfigFailed": "웹 서비스 설정 저장 실패", - "open": "열기", - "hide": "숨기기", - "show": "표시", - "copy": "복사", - "qrcode": "QR 코드", - "qrcodeTitle": "스캔하여 열기", - "qrcodeHint": "휴대폰으로 스캔하여 브라우저에서 Codeg를 엽니다", - "addressLabel": "접속 주소", - "tokenLabel": "접속 토큰", - "tokenHint": "웹 클라이언트 첫 접속 시 이 토큰을 입력하세요", - "tokenPlaceholder": "비워두면 자동 생성", - "regenerate": "재생성", - "stalePortOccupiedTitle": "포트 {port}이(가) 다른 프로세스에 의해 사용 중입니다", - "stalePortUnknownTitle": "포트 {port}의 상태를 확인할 수 없습니다", - "stalePortHint": "포트가 해제될 때까지 Codeg은 바인딩할 수 없습니다. 위의 포트를 변경하거나 사용 중인 프로세스를 종료하세요.", - "errors": { - "alreadyRunning": "웹 서비스가 이미 실행 중입니다", - "invalidAddress": "호스트 또는 포트 형식이 올바르지 않습니다", - "portInUse": "포트 {port}가 이미 사용 중입니다. 해당 포트를 사용 중인 프로세스를 종료하거나 다른 포트를 선택하세요", - "permissionDenied": "권한이 부족합니다. 1024 이상의 포트를 사용하거나 더 높은 권한으로 실행하세요", - "addressUnavailable": "이 주소는 현재 시스템에서 사용할 수 없습니다", - "bindFailed": "주소 바인딩에 실패했습니다" - } - }, - "DirectoryBrowser": { - "title": "디렉토리 찾아보기", - "pathPlaceholder": "디렉토리 경로 입력...", - "goHome": "홈 디렉토리로 이동", - "navigateUp": "상위 디렉토리로 이동", - "select": "선택", - "cancel": "취소", - "loading": "로딩 중...", - "emptyDirectory": "이 디렉토리는 비어 있습니다", - "errorLoadingDir": "디렉토리 로딩 실패", - "permissionDenied": "권한이 없습니다" - }, - "ChatChannelSettings": { - "loading": "로딩 중...", - "sectionTitle": "채팅 채널", - "sectionDescription": "IM 봇을 설정하여 이벤트 알림을 수신하고 코딩 활동을 조회합니다.", - "addChannel": "채널 추가", - "noChannels": "설정된 채팅 채널이 없습니다.", - "channelName": "이름", - "channelNamePlaceholder": "내 Telegram 봇", - "channelType": "채널 유형", - "lark": "Lark (飛書)", - "weixin": "WeChat", - "dailyReport": "일일 리포트", - "dailyReportTime": "발송 시간", - "nameRequired": "채널 이름을 입력하세요.", - "tokenRequired": "토큰을 입력하세요.", - "chatIdRequired": "Chat ID를 입력하세요.", - "topicMode": "토픽 그룹 모드", - "topicModeHint": "Telegram forum topics를 별도 Codeg 세션으로 라우팅합니다. Bot은 forum supergroup에 있어야 하며 topics 관리 권한이 필요합니다.", - "loadFailed": "채널 로딩에 실패했습니다.", - "saveFailed": "저장에 실패했습니다.", - "connectSuccess": "채널이 연결되었습니다.", - "connectFailed": "연결에 실패했습니다", - "disconnectSuccess": "채널이 연결 해제되었습니다.", - "disconnectFailed": "연결 해제에 실패했습니다.", - "testSuccess": "연결 테스트를 통과했습니다.", - "testFailed": "연결 테스트에 실패했습니다", - "deleteSuccess": "채널이 삭제되었습니다.", - "deleteFailed": "채널 삭제에 실패했습니다.", - "deleteConfirmTitle": "채널 삭제", - "deleteConfirmMessage": "이 채널과 메시지 기록이 영구 삭제됩니다. 계속하시겠습니까?", - "cancel": "취소", - "delete": "삭제", - "create": "생성", - "save": "저장", - "channelListTitle": "설정된 채널", - "channelListDescription": "활성화된 채널은 서비스 시작 시 자동으로 연결됩니다.", - "editChannel": "채널 편집", - "editSuccess": "채널이 업데이트되었습니다.", - "tokenPlaceholderKeep": "비워두면 현재 값 유지", - "weixinScanTitle": "QR 코드 스캔", - "weixinScanDescription": "WeChat을 열고 QR 코드를 스캔하여 연결하세요.", - "weixinQrcodeExpired": "QR 코드가 만료되었습니다.", - "weixinRefreshQrcode": "새로고침", - "weixinWaitingScan": "스캔 대기 중...", - "weixinPollError": "연결이 불안정합니다. 재시도 중...", - "weixinReconnectNotice": "iLink 프로토콜 제한으로 인해, 재연결할 때마다 먼저 봇에게 메시지를 보내야 이벤트 트리거가 활성화됩니다.", - "connect": "연결", - "disconnect": "연결 해제", - "test": "연결 테스트", - "tabs": { - "channels": "채널", - "commands": "명령어", - "events": "이벤트", - "other": "기타" - }, - "commands": { - "title": "내장 명령어", - "description": "채팅 채널에서 사용 가능한 Bot 명령어입니다. 그룹 채팅에서는 메시지를 처리하려면 @Bot이 필요합니다.", - "prefixLabel": "명령어 접두사", - "prefixDescription": "Bot 명령어를 실행하는 접두사, 1-3개의 영숫자가 아닌 문자 (기본값 /).", - "prefixSaved": "명령어 접두사가 저장되었습니다.", - "prefixSaveFailed": "명령어 접두사 저장에 실패했습니다.", - "prefixInvalid": "접두사는 1-3개의 영숫자가 아닌 문자여야 합니다.", - "save": "저장", - "folderDesc": "작업 폴더 선택", - "agentDesc": "AI 에이전트 선택", - "taskDesc": "세션 생성 및 작업 실행", - "sessionsDesc": "폴더 내 활성 세션 목록", - "resumeDesc": "최근 대화 / 세션 재개", - "cancelDesc": "현재 작업 취소", - "approveDesc": "에이전트 권한 요청 승인", - "denyDesc": "에이전트 권한 요청 거부", - "searchDesc": "키워드로 대화 검색", - "todayDesc": "오늘의 활동 요약", - "statusDesc": "채널 연결 상태", - "helpDesc": "도움말 표시" - }, - "events": { - "title": "이벤트 알림", - "description": "이벤트를 활성화하면, 트리거 시 채널로 푸시됩니다.", - "turnComplete": "턴 완료", - "turnCompleteDesc": "에이전트 턴이 종료될 때", - "error": "에이전트 오류", - "errorDesc": "에이전트에 오류가 발생했을 때", - "permissionRequest": "권한 요청", - "permissionRequestDesc": "에이전트가 작업 권한을 요청할 때", - "questionRequest": "에이전트 질문", - "questionRequestDesc": "에이전트가 질문할 때", - "userPromptSent": "사용자 메시지", - "userPromptSentDesc": "메시지를 보낼 때 — 알림에 메시지 내용이 포함됩니다", - "saved": "이벤트 필터가 업데이트되었습니다.", - "saveFailed": "이벤트 필터 저장에 실패했습니다.", - "loadFailed": "설정을 불러오지 못했습니다.", - "retry": "다시 시도", - "webhooksTitle": "Webhook", - "webhooksDescription": "활성화된 이벤트가 발생하면 하나 이상의 URL로 JSON을 POST합니다. 위의 이벤트 필터는 Webhook에도 적용됩니다.", - "webhookUrlPlaceholder": "https://example.com/webhook", - "addWebhook": "Webhook 추가", - "removeWebhook": "Webhook 삭제", - "webhookSave": "저장", - "webhooksSaved": "Webhook을 저장했습니다.", - "webhooksSaveFailed": "Webhook 저장에 실패했습니다.", - "webhookInvalidUrl": "유효한 http(s) URL을 입력하세요.", - "docsTitle": "요청 형식", - "docsMethod": "메서드", - "docsContentType": "Content-Type", - "docsNote": "활성화된 각 이벤트는 모든 URL로 전달됩니다. Webhook은 디바운스되지 않으며 위의 이벤트 필터가 계속 적용됩니다.", - "editWebhook": "Webhook 편집", - "enableWebhook": "Webhook 활성화", - "webhookDuplicate": "이미 설정된 URL입니다.", - "cancel": "취소", - "webhooksEmpty": "아직 구성된 Webhook이 없습니다.", - "deleteWebhookTitle": "Webhook 삭제", - "deleteWebhookMessage": "이 Webhook을 삭제하시겠습니까? 이 URL로 더 이상 이벤트가 전달되지 않습니다.", - "delete": "삭제" - }, - "language": { - "title": "메시지 언어", - "description": "이벤트 알림, 명령 응답, 일일 보고서를 채팅 채널로 전송할 때 사용하는 언어입니다.", - "saved": "메시지 언어가 저장되었습니다.", - "saveFailed": "메시지 언어 저장에 실패했습니다.", - "en": "영어", - "zh-cn": "중국어 간체", - "zh-tw": "중국어 번체", - "ja": "일본어", - "ko": "한국어", - "es": "스페인어", - "de": "독일어", - "fr": "프랑스어", - "pt": "포르투갈어", - "ar": "아랍어" - } - }, - "ModelProviderSettings": { - "sectionTitle": "모델 제공업체", - "sectionDescription": "에이전트의 API 제공업체 자격 증명을 관리합니다.", - "filterAll": "전체", - "providerListTitle": "구성된 제공업체", - "addProvider": "제공업체 추가", - "editProvider": "제공업체 편집", - "noProviders": "아직 구성된 모델 제공업체가 없습니다.", - "providerName": "이름", - "providerNamePlaceholder": "예: OpenAI, Anthropic", - "apiUrl": "API URL", - "apiUrlPlaceholder": "https://api.openai.com/v1", - "apiKey": "API 키", - "apiKeyPlaceholder": "sk-...", - "apiKeyKeepCurrent": "현재 값을 유지하려면 비워두세요", - "agentTypes": "에이전트 유형", - "agentTypesRequired": "최소 하나의 에이전트 유형을 선택하세요.", - "agentType": "에이전트 유형", - "agentTypeRequired": "에이전트 유형을 선택하세요.", - "agentTypeImmutableHint": "에이전트 유형은 생성 후 변경할 수 없습니다.", - "model": "모델", - "modelPlaceholderCodex": "gpt-5.6-sol / gpt-5.5", - "modelPlaceholderGemini": "gemini-3-pro-preview", - "claudeMainModel": "메인 모델", - "claudeReasoningModel": "추론 모델 (사고)", - "claudeHaikuDefaultModel": "기본 Haiku 모델", - "claudeSonnetDefaultModel": "기본 Sonnet 모델", - "claudeOpusDefaultModel": "기본 Opus 모델", - "claudeCustomModelOption": "사용자 지정 모델 ID", - "claudeCustomModelOptionName": "사용자 지정 모델 이름", - "claudeCustomModelOptionDescription": "사용자 지정 모델 설명", - "claudeCustomModelOptionHint": "Claude 모델 선택기에 사용자 지정 항목 하나를 추가합니다(예: 사용자 지정 게이트웨이/프록시를 통해 제공되는 모델). 이름과 설명은 선택적 표시 설정입니다.", - "nameRequired": "제공업체 이름은 필수입니다.", - "apiUrlRequired": "API URL은 필수입니다.", - "apiKeyRequired": "API 키는 필수입니다.", - "loadFailed": "제공업체를 불러오지 못했습니다.", - "saveFailed": "변경 사항을 저장하지 못했습니다.", - "createSuccess": "제공업체가 생성되었습니다.", - "editSuccess": "제공업체가 업데이트되었습니다.", - "deleteSuccess": "제공업체가 삭제되었습니다.", - "deleteConfirmTitle": "제공업체 삭제", - "deleteConfirmMessage": "제공업체 \"{name}\"을(를) 영구적으로 삭제하시겠습니까?", - "deleteBlockedByAgent": "{agents}이(가) 이 공급자를 사용 중입니다. 삭제하기 전에 연결을 해제해 주세요.", - "cancel": "취소", - "delete": "삭제", - "create": "생성", - "save": "저장", - "affectedRunningSessions": "{count}개의 실행 중인 세션은 다시 연결하면 변경 사항이 적용됩니다" - }, - "SkillMatrix": { - "loading": "불러오는 중…", - "searchPlaceholder": "이름, ID 또는 설명으로 검색", - "empty": "표시할 항목이 없습니다.", - "emptySearch": "현재 검색과 일치하는 항목이 없습니다.", - "skillColumn": "스킬", - "selectAll": "표시된 항목 모두 선택", - "selectSkill": "{name} 선택", - "everything": { - "label": "일괄", - "enable": "모두 활성화(표시된 항목)", - "disable": "모두 비활성화(표시된 항목)" - }, - "columnMenu": { - "enableAll": "모든 스킬 활성화", - "disableAll": "모든 스킬 비활성화" - }, - "rowMenu": { - "label": "{name} 일괄 작업", - "enableAll": "모든 에이전트에 활성화", - "disableAll": "모든 에이전트에서 비활성화" - }, - "bulk": { - "selected": "{count}개 선택됨", - "targetAll": "모든 에이전트", - "targetSome": "에이전트 {count}개", - "enable": "활성화", - "disable": "비활성화", - "clear": "지우기" - }, - "confirm": { - "disableTitle": "이 링크를 비활성화할까요?", - "disableBody": "codeg가 관리하는 스킬 링크 {count}개를 제거합니다. 사용자 지정 디렉터리를 차지한 스킬은 그대로 유지됩니다. 언제든지 다시 활성화할 수 있습니다.", - "cancel": "취소", - "confirm": "비활성화" - }, - "toasts": { - "loadFailed": "스킬 상태를 불러오지 못했습니다", - "applyFailed": "변경 사항을 적용하지 못했습니다", - "enabled": "링크 {count}개를 활성화했습니다", - "disabled": "링크 {count}개를 비활성화했습니다", - "enabledPartial": "{ok}개 활성화, {failed}개 실패", - "disabledPartial": "{ok}개 비활성화, {failed}개 실패" - }, - "detail": { - "enableForAgents": "에이전트에 활성화", - "preview": "SKILL.md 미리보기", - "loadingContent": "콘텐츠 불러오는 중…" - }, - "copyModeHint": "복사됨(링크 아님) — 업데이트 후 최신 버전을 받으려면 다시 활성화하세요" - }, - "ExpertsSettings": { - "title": "전문가 스킬", - "description": "AI 코딩 에이전트를 위해 엄선되고 실전 검증된 스킬 워크플로를 활성화하세요. 각 전문가는 superpowers 프로젝트의 독립 실행형 스킬이며 — codeg가 중앙 복사본을 관리하고 선택한 에이전트에 연결합니다.", - "loading": "전문가 로딩 중…", - "loadingContent": "콘텐츠 로딩 중…", - "emptyExperts": "사용 가능한 전문가가 없습니다. 애플리케이션 로그를 확인하세요.", - "emptySelection": "전문가를 선택하여 내용을 보고 활성화를 관리하세요.", - "emptySearch": "현재 검색과 일치하는 전문가가 없습니다.", - "searchPlaceholder": "이름, ID 또는 설명으로 전문가 검색", - "enableForAgents": "에이전트에 활성화", - "noAgents": "ACP 에이전트가 감지되지 않았습니다.", - "copyModeWarning": "복사됨(연결되지 않음). 최신 버전을 받으려면 codeg 업데이트 후 재활성화하세요.", - "previewTitle": "SKILL.md 미리보기", - "categories": { - "discovery": "발견 및 설계", - "planning": "계획", - "execution": "실행", - "quality": "품질 및 테스트", - "debugging": "디버깅", - "review": "검토 및 통합", - "meta": "메타" - }, - "states": { - "not_linked": "활성화되지 않음", - "linked_to_codeg": "활성화됨", - "linked_elsewhere": "차단됨 — 다른 링크가 존재함", - "blocked_by_real_directory": "차단됨 — 사용자 정의 스킬이 이 이름을 점유 중", - "broken": "손상된 링크" - }, - "badges": { - "userModified": "사용자가 수정함" - }, - "actions": { - "openCentralDir": "중앙 폴더 열기", - "refresh": "새로고침" - }, - "toasts": { - "loadFailed": "전문가 세부 정보를 로드하지 못했습니다", - "enabled": "이 에이전트에 전문가가 활성화되었습니다", - "disabled": "이 에이전트에서 전문가가 비활성화되었습니다", - "enableFailed": "전문가 활성화에 실패했습니다", - "disableFailed": "전문가 비활성화에 실패했습니다", - "openFolderFailed": "폴더를 열지 못했습니다" - } - }, - "ScienceSettings": { - "title": "과학 연구 스킬", - "description": "AI 코딩 에이전트를 위한 엄선된 과학 연구 스킬(가설 생성, 실험 설계, 통계, 시각화, 비판적 평가, 문헌 검색)을 활성화합니다. codeg가 중앙 복사본을 관리하고 선택한 에이전트에 각 스킬을 연결합니다.", - "loading": "과학 연구 스킬 불러오는 중…", - "emptySkills": "사용 가능한 과학 연구 스킬이 없습니다. 애플리케이션 로그를 확인하세요.", - "searchPlaceholder": "이름, ID 또는 설명으로 과학 연구 스킬 검색", - "categories": { - "ideation": "아이디어", - "design": "연구 설계", - "analysis": "분석", - "visualization": "시각화", - "evaluation": "평가", - "literature": "문헌" - }, - "states": { - "not_linked": "활성화되지 않음", - "linked_to_codeg": "활성화됨", - "linked_elsewhere": "차단됨 — 다른 링크가 존재함", - "blocked_by_real_directory": "차단됨 — 사용자 정의 스킬이 이 이름을 점유 중", - "broken": "손상된 링크" - }, - "badges": { - "userModified": "사용자가 수정함", - "needsKey": "API 키 필요", - "needsSetup": "설정 필요할 수 있음" - }, - "actions": { - "openCentralDir": "중앙 폴더 열기", - "refresh": "새로고침" - }, - "toasts": { - "openFolderFailed": "폴더를 열지 못했습니다" - } - }, - "OfficeToolsSettings": { - "title": "Office 도구", - "description": "OfficeCLI 스킬을 관리하여 Excel, Word, PowerPoint 파일을 생성합니다. OfficeCLI를 설치하고 스킬을 동기화한 후 에이전트별로 활성화할 수 있습니다.", - "loadingContent": "콘텐츠 로드 중…", - "emptySkills": "스킬이 없습니다. OfficeCLI를 설치하고 스킬을 동기화하세요.", - "emptySelection": "스킬을 선택하여 내용을 확인하고 활성화를 관리합니다.", - "emptySearch": "검색과 일치하는 스킬이 없습니다.", - "searchPlaceholder": "이름, ID 또는 설명으로 스킬 검색", - "enableForAgents": "에이전트에 활성화", - "noAgents": "ACP 에이전트가 감지되지 않았습니다.", - "installFirst": "스킬을 활성화하려면 먼저 OfficeCLI를 설치하세요.", - "syncFirst": "콘텐츠를 로드하려면 먼저 스킬을 동기화하세요.", - "noContent": "콘텐츠가 없습니다.", - "copyModeWarning": "복사됨(링크 아님). 최신 버전을 가져오려면 다시 동기화하세요.", - "previewTitle": "SKILL.md 미리보기", - "detection": { - "installed": "설치됨", - "notInstalled": "미설치", - "notRunnable": "설치됨, 실행 불가", - "installHint": "OfficeCLI를 설치하여 AI 에이전트에 오피스 문서 생성 스킬을 활성화합니다.", - "install": "설치", - "uninstall": "제거", - "syncSkills": "스킬 동기화" - }, - "categories": { - "general": "일반", - "presentations": "프레젠테이션", - "documents": "문서", - "spreadsheets": "스프레드시트" - }, - "states": { - "not_linked": "비활성", - "linked_to_codeg": "활성", - "linked_elsewhere": "차단됨 — 다른 링크가 존재합니다", - "blocked_by_real_directory": "차단됨 — 사용자 정의 스킬이 이 이름을 사용 중", - "broken": "링크 끊김" - }, - "badges": { - "notSynced": "미동기화" - }, - "actions": { - "refresh": "새로고침" - }, - "toasts": { - "loadFailed": "스킬 상세 로드 실패", - "enabled": "이 에이전트에 스킬 활성화됨", - "disabled": "이 에이전트에서 스킬 비활성화됨", - "enableFailed": "스킬 활성화 실패", - "disableFailed": "스킬 비활성화 실패", - "installSuccess": "OfficeCLI 설치 성공", - "installFailed": "OfficeCLI 설치 실패", - "uninstallSuccess": "OfficeCLI 제거됨", - "uninstallFailed": "OfficeCLI 제거 실패", - "syncSuccess": "{synced}개 스킬 동기화 완료", - "syncPartial": "{synced}개 동기화, {errors}개 실패", - "syncFailed": "스킬 동기화 실패" - }, - "autoPreviewLabel": "미리보기 자동 열기", - "autoPreviewHint": "에이전트가 Word, Excel, PowerPoint 파일을 만들거나 편집하면 실시간 미리보기를 자동으로 엽니다." - }, - "SkillPacksSettings": { - "title": "스킬 팩", - "description": "codeg가 중앙에서 관리하고 각 AI 에이전트에 연결하는 엄선된 스킬 모음입니다 — 코딩 전문가, 과학 연구, 오피스 문서 도구. 아래에서 에이전트별로 활성화하세요.", - "tabs": { - "experts": "전문가", - "science": "과학 연구", - "office": "오피스 도구", - "custom": "사용자 지정" - }, - "actions": { - "openCentralDir": "중앙 폴더 열기", - "refresh": "새로고침" - }, - "toasts": { - "openFolderFailed": "폴더를 열지 못했습니다" - } - }, - "QuickMessagesSettings": { - "title": "빠른 메시지", - "description": "재사용 가능한 메시지 스니펫을 관리합니다. 드래그하여 순서를 변경하세요.", - "loading": "빠른 메시지 불러오는 중…", - "emptyList": "빠른 메시지가 없습니다. \"새로 만들기\"를 클릭하여 추가하세요.", - "emptySelection": "편집할 빠른 메시지를 선택하세요.", - "searchPlaceholder": "제목 또는 내용으로 검색", - "untitled": "제목 없음", - "actions": { - "new": "새로 만들기", - "save": "저장", - "delete": "삭제", - "dragSort": "드래그하여 순서 변경", - "dragSortMessage": "빠른 메시지 순서 변경: {name}" - }, - "fields": { - "title": "제목", - "titlePlaceholder": "이 메시지에 짧은 제목을 지정하세요", - "content": "내용", - "contentPlaceholder": "여기에 메시지 내용을 입력하세요" - }, - "confirmDelete": { - "title": "빠른 메시지를 삭제하시겠습니까?", - "message": "\"{name}\" 이(가) 영구적으로 삭제됩니다. 계속하시겠습니까?", - "cancel": "취소", - "confirm": "삭제" - }, - "toasts": { - "loadFailed": "빠른 메시지를 불러오지 못했습니다", - "createFailed": "빠른 메시지를 만들지 못했습니다", - "saveFailed": "빠른 메시지를 저장하지 못했습니다", - "deleteFailed": "빠른 메시지를 삭제하지 못했습니다", - "saveOrderFailed": "순서를 저장하지 못했습니다", - "created": "빠른 메시지가 생성되었습니다", - "saved": "빠른 메시지가 저장되었습니다", - "deleted": "빠른 메시지가 삭제되었습니다" - } - }, - "Pet": { - "badge": { - "running": "실행 중 {count}개", - "waiting": "승인 대기 {count}개", - "error": "오류 {count}개" - }, - "panel": { - "title": "활성 세션", - "empty": "활성 세션 없음", - "emptyHint": "실행 중이거나 사용자의 조치가 필요한 세션이 여기에 표시됩니다.", - "statusRunning": "실행 중", - "statusWaiting": "대기 중", - "statusError": "오류", - "subAgentOf": "하위 에이전트" - }, - "menu": { - "scale": "크기", - "openManager": "펫 관리", - "close": "닫기" - }, - "loadError": "펫을 불러오지 못했습니다", - "missingPetIdParam": "선택된 펫이 없습니다", - "summonButton": "펫", - "manager": { - "title": "데스크톱 펫", - "description": "Codex 호환 스프라이트 시트로 동작하는 데스크톱 동반자.", - "addPet": "펫 추가", - "importFromCodex": "Codex 에서 가져오기", - "noPets": "펫이 아직 없습니다. 새로 추가하거나 Codex 에서 가져오세요.", - "setActive": "활성화", - "active": "활성", - "edit": "편집", - "delete": "삭제", - "deleteConfirm": "펫 \"{name}\"을(를) 삭제할까요? 디스크에서도 함께 제거됩니다.", - "summon": "펫 창 호출", - "openCodexHelp": "Codex 펫은 ~/.codex/pets/ 아래에 설치되어야 합니다. 찾을 수 없습니다.", - "specRequirement": "스프라이트 시트는 너비 1536px, 높이는 208px의 배수(예: 1872 또는 2288)인 투명 PNG 또는 WebP여야 합니다.", - "form": { - "id": "펫 ID", - "idHelp": "소문자/숫자/'-'/'_' 만 가능. 최대 64자.", - "displayName": "표시 이름", - "description": "설명 (선택)", - "spritesheet": "스프라이트 시트", - "chooseFile": "파일 선택", - "replaceFile": "스프라이트 교체", - "saveCreate": "펫 추가", - "saveUpdate": "변경 저장", - "cancel": "취소" - }, - "errors": { - "missingId": "펫 ID 는 필수입니다", - "missingName": "표시 이름은 필수입니다", - "missingSpritesheet": "스프라이트 시트는 필수입니다", - "addFailed": "펫 추가에 실패했습니다", - "updateFailed": "펫 갱신에 실패했습니다", - "deleteFailed": "펫 삭제에 실패했습니다", - "loadFailed": "펫 목록 로드에 실패했습니다", - "setActiveFailed": "활성 펫 설정에 실패했습니다", - "summonFailed": "펫 창 호출에 실패했습니다" - } - }, - "import": { - "title": "Codex 에서 가져오기", - "subtitle": "~/.codex/pets/ 에서 발견된 펫 목록입니다.", - "selectAll": "전체 선택", - "alreadyImported": "이미 가져옴", - "renameOnConflict": "충돌 시 -imported 접미어로 이름 변경", - "import": "선택 항목 가져오기", - "noneFound": "가져올 수 있는 Codex 펫이 없습니다.", - "imported": "가져오기 완료", - "failed": "가져오기 실패", - "close": "닫기" - }, - "marketplace": { - "openMarketplace": "펫 마켓", - "title": "펫 마켓", - "search": "펫 검색", - "kindFilter": { - "all": "전체", - "object": "오브젝트", - "animal": "동물", - "person": "인물", - "creature": "생물" - }, - "sortFilter": { - "latest": "최신", - "popular": "인기", - "views": "조회수순" - }, - "refresh": "새로고침", - "install": "설치", - "installing": "설치 중", - "reinstall": "다시 설치", - "reinstallConfirm": "로컬 펫 \"{name}\" 을(를) 덮어쓰시겠습니까? 기존 데이터가 교체됩니다.", - "cancel": "취소", - "stats": { - "views": "조회수", - "downloads": "다운로드", - "likes": "좋아요" - }, - "actions": { - "idle": "대기", - "running_right": "오른쪽 달리기", - "running_left": "왼쪽 달리기", - "waving": "손 흔들기", - "jumping": "점프", - "failed": "실패", - "waiting": "기다림", - "running": "실행", - "review": "리뷰" - }, - "page": "{page} / {total} 페이지", - "prev": "이전", - "next": "다음", - "empty": "조건에 맞는 펫이 없습니다.", - "successInstalled": "\"{name}\" 을(를) 설치했습니다", - "errors": { - "loadFailed": "마켓을 불러오지 못했습니다", - "installFailed": "설치에 실패했습니다", - "alreadyInstalled": "해당 펫이 이미 존재합니다" - } - } - }, - "RemoteWorkspace": { - "openRemoteWorkspace": "Open remote workspace", - "manage": "Manage remote workspace", - "manageTitle": "Remote Workspace connections", - "empty": "No remote connections", - "searchPlaceholder": "Search remote workspaces", - "orderFailed": "Failed to save remote workspace order", - "dragSort": "Drag to sort", - "dragSortConnection": "Drag to sort {name}", - "newConnection": "New connection", - "loading": "Loading", - "loadingConnection": "Loading remote connection", - "name": "Name", - "baseUrl": "Service URL", - "token": "Access token", - "save": "Save", - "delete": "Delete", - "confirmDelete": { - "title": "Delete remote connection?", - "message": "This will remove \"{name}\" from this device. This action cannot be undone.", - "cancel": "Cancel", - "confirm": "Delete" - }, - "saved": "Remote connection saved.", - "deleted": "Remote connection deleted.", - "loadFailed": "Failed to load remote connections", - "saveFailed": "Failed to save remote connection", - "deleteFailed": "Failed to delete remote connection", - "openFailed": "Failed to open remote workspace", - "connectionLoadFailed": "Failed to load remote connection: {message}", - "connectionExpired": "Remote connection \"{name}\" is expired. Update its token and reload this window." - }, - "ServerFileBrowser": { - "title": "서버 파일 선택", - "pathPlaceholder": "디렉토리 경로 입력...", - "goHome": "홈 디렉토리로", - "navigateUp": "상위 디렉토리로", - "select": "선택", - "cancel": "취소", - "loading": "로드 중...", - "emptyDirectory": "이 디렉토리는 비어 있습니다", - "errorLoadingDir": "디렉토리 로드 실패", - "selectedCount": "{count}개 선택됨" - }, - "BackupSettings": { - "title": "백업 및 복원", - "description": "codeg 데이터의 이동 가능한 백업을 내보내거나 백업에서 복원합니다.", - "tabs": { - "backup": "백업", - "restore": "복원" - }, - "export": { - "includeExternal": "대화 내용 포함", - "includeExternalHint": "각 CLI의 대화 기록(Claude, Codex, Gemini 등)도 함께 보관합니다. 용량이 커집니다.", - "passphrase": "암호문 (선택)", - "passphrasePlaceholder": "비워 두면 암호화하지 않습니다", - "passphraseConfirm": "암호문 확인", - "passphraseMismatch": "암호문이 일치하지 않습니다.", - "noPassphraseWarning": "이 백업에는 비밀 정보(API 키, 토큰)가 평문으로 포함됩니다. 안전한 곳에 보관하세요.", - "passphraseLossWarning": "이 암호문으로 암호화됩니다. 분실하면 백업을 복구할 수 없습니다.", - "button": "백업 내보내기", - "inProgress": "백업 만드는 중…", - "success": "백업을 만들었습니다.", - "started": "백업 다운로드를 시작했습니다." - }, - "restore": { - "selectFile": "백업 파일 선택", - "passphrasePrompt": "이 백업은 암호화되어 있습니다. 암호문을 입력하세요.", - "unlock": "잠금 해제", - "preview": { - "title": "백업 정보", - "encrypted": "암호화됨", - "compatible": "호환됨", - "incompatible": "호환되지 않음", - "createdAt": "생성: {value}", - "appVersion": "앱 버전: {value}", - "incompatibleHint": "이 백업은 더 새로운 버전의 codeg에서 만들어져 복원할 수 없습니다." - }, - "replaceWarning": "복원하면 현재의 모든 codeg 데이터(데이터베이스 및 업로드)가 교체됩니다. 현재 데이터는 먼저 스냅샷되어 복구할 수 있습니다.", - "keyringNote": "데스크톱의 GitHub/채팅 토큰은 OS 키체인에 저장되어 포함되지 않습니다. 복원 후 다시 입력하세요.", - "button": "복원", - "staging": "복원 준비 중…", - "staged": "복원이 준비되었습니다. 다시 시작합니다…", - "restarting": "복원이 준비되었습니다. 서버를 다시 시작합니다…", - "restartTimeout": "서버가 제때 돌아오지 않았습니다. 서버가 켜지면 페이지를 새로 고치세요.", - "externalSideLocation": "대화 기록을 {path}에 복원했습니다", - "confirmTitle": "모든 데이터를 교체할까요?", - "confirmBody": "현재 codeg 데이터베이스와 업로드를 백업으로 교체한 후 다시 시작합니다. 현재 데이터는 먼저 스냅샷됩니다.", - "cancel": "취소", - "confirmAction": "교체 후 다시 시작", - "external": { - "title": "대화 내용", - "hint": "이 백업에는 CLI 대화 기록이 포함됩니다. 복원 위치를 선택하세요.", - "modeSkip": "복원 안 함", - "modeSide": "안전한 별도 폴더에 복원", - "modeOriginal": "CLI 원래 위치에 복원", - "forceOverwrite": "기존 파일 덮어쓰기", - "forceOverwriteHint": "CLI 폴더에 이미 있는 파일을 교체합니다.", - "scanning": "충돌 확인 중…", - "noConflicts": "덮어쓸 기존 파일이 없습니다.", - "conflictCount": "기존 파일 {count}개가 영향을 받습니다.", - "conflictSkipNote": "덮어쓰기를 켜지 않으면 기존 파일은 유지(건너뜀)됩니다." - }, - "restartFailed": "복원이 준비되었지만 서버를 다시 시작하지 못했습니다. 수동으로 다시 시작해 복원을 적용하세요." - }, - "remoteUnsupported": "백업 및 복원은 codeg를 실행 중인 컴퓨터의 데이터를 대상으로 합니다. 현재 원격 작업 공간에 연결되어 있습니다. 해당 서버에서 직접 백업을 관리하세요." - }, - "backup": { - "restore": { - "error": { - "badPassphrase": "암호문이 올바르지 않거나 백업이 손상되었습니다.", - "corrupted": "백업 아카이브가 손상되었습니다.", - "unknownFormat": "이 파일은 인식할 수 있는 codeg 백업이 아닙니다.", - "newerVersion": "이 백업은 codeg {backupVersion}에서 만들어졌으며 현재 버전({appVersion})보다 최신입니다.", - "alreadyPending": "적용 대기 중인 복원이 이미 있습니다. 먼저 다시 시작해 적용한 뒤 새 복원을 준비하세요." - } - }, - "error": { - "diskSpace": "작업을 완료할 디스크 공간이 부족합니다.", - "cancelled": "작업이 취소되었습니다." - } - }, - "WebConnection": { - "disconnectedTitle": "연결이 끊어졌습니다", - "reconnectingDescription": "서버에 다시 연결하는 중입니다. 보통 몇 초 내에 자동으로 복구됩니다.", - "reconnectNow": "지금 다시 연결", - "sessionExpiredTitle": "세션이 만료되었습니다", - "sessionExpiredDescription": "세션이 더 이상 유효하지 않습니다. 계속하려면 다시 로그인하세요.", - "goToLogin": "로그인으로 이동" - }, - "LiveFeedback": { - "placeholder": "{agent}이(가) 작업하는 동안 메모 보내기…", - "agentFallback": "에이전트", - "ariaLabel": "라이브 피드백 메모", - "dialogTitle": "라이브 피드백", - "dialogDescription": "에이전트가 작업하는 동안 메모를 보냅니다. 현재 단계를 중단하지 않고 다음 확인 시 읽습니다.", - "dialogDescriptionInstant": "에이전트가 작업하는 동안 메모를 보냅니다. 메모는 현재 턴에 즉시 삽입되어 에이전트가 바로 확인합니다.", - "channelDowngraded": "이 세션에서는 즉시 삽입을 사용할 수 없습니다. 메모는 저장되어 에이전트가 다음에 확인할 때 전달됩니다.", - "send": "보내기", - "cancel": "취소", - "pending": "대기 중", - "delivered": "수신됨", - "turnEndedUnread": "에이전트가 피드백을 읽기 전에 턴을 마쳤습니다.", - "sendAsMessage": "새 메시지로 보내기", - "dismiss": "닫기", - "turnEndedResent": "턴이 종료되어 새 메시지로 보냈습니다.", - "turnEnded": "턴이 이미 종료되었습니다.", - "submitFailed": "메모를 보내지 못했습니다" - }, - "AgentToolsSettings": { - "title": "대화 내 도구", - "description": "codeg가 대화 안에서 에이전트에게 추가로 제공하는 도구입니다. 에이전트가 시작할 때 주입되므로 변경 사항은 이후에 시작한 에이전트부터 적용됩니다.", - "feedbackLabel": "라이브 피드백", - "feedbackHint": "에이전트가 작업하는 동안 메모와 수정 사항을 보낼 수 있습니다. 즉시 삽입을 지원하는 에이전트는 실행 중인 턴에 메모가 바로 삽입됩니다. 그 외 에이전트는 피드백 확인 도구로 읽는데, 보통 프롬프트에서 언급할 때만 확인합니다. 예: 메시지에 \"실시간 피드백을 정기적으로 확인해\"를 추가하세요.", - "questionLabel": "사용자에게 질문", - "questionHint": "에이전트가 작업을 멈추고 대화 입력창 위에 표시되는 객관식 질문을 할 수 있습니다. 답변(또는 건너뛰기)할 때까지 에이전트는 대기합니다.", - "sessionInfoLabel": "세션 정보 가져오기", - "sessionInfoHint": "메시지에서 참조한 세션(세션 배지)을 에이전트가 조회하여 제목, 에이전트, 상태, 작업 공간, 토큰 사용량, 최근 메시지를 읽을 수 있도록 합니다.", - "automationsLabel": "자동화 만들기", - "automationsHint": "대화를 일정에 따라 실행되는 자동화로 저장합니다. 기본값은 꺼짐 — 자동화는 이후 스스로 에이전트를 시작합니다.", - "workTasksLabel": "할 일 작업 만들기", - "workTasksHint": "대화에서 할 일 보드에 카드를 추가합니다. 기본값은 꺼짐 — 앱 상태를 기록합니다.", - "save": "저장", - "saving": "저장 중…", - "saved": "도구 설정을 저장했습니다", - "saveFailed": "도구 설정 저장에 실패했습니다", - "loadFailed": "불러오기 실패: {detail}" - }, - "NotificationSoundSettings": { - "title": "알림음", - "description": "에이전트 이벤트가 발생하면 짧은 알림음을 재생합니다. 채팅 채널로 전송되는 것과 같은 이벤트이며, 이 설정은 이 기기에만 적용됩니다.", - "enableHint": "기본값은 꺼짐입니다. 알림음은 이 브라우저 또는 앱의 작업 공간 창에서만 재생됩니다.", - "volume": "음량", - "preview": "미리 듣기", - "previewEvent": "{event} 알림음 미리 듣기", - "onlyWhenUnfocused": "창이 활성화되지 않았을 때만 재생", - "onlyWhenUnfocusedHint": "Codeg을 보고 있는 동안에는 소리를 내지 않습니다.", - "eventsTitle": "이벤트", - "eventsHint": "이벤트마다 소리를 선택하세요. “무음”을 선택하면 재생하지 않습니다. 같은 이벤트가 몇 초 안에 반복되면 한 번만 재생됩니다.", - "toneNone": "무음", - "toneChime": "차임", - "toneDing": "딩", - "toneBlip": "블립", - "tonePop": "팝", - "toneAlert": "알림", - "toneDescend": "하강음" - }, - "LogsSettings": { - "loading": "불러오는 중…", - "sectionTitle": "실행 로그", - "sectionDescription": "애플리케이션 진단 로그를 보고 구성합니다. 로그는 로컬 파일에 기록되며 실시간 보기를 위해 메모리에도 보관됩니다.", - "captureTitle": "로그 수준", - "captureDescription": "기록되는 상세 수준을 제어합니다. 수준이 높을수록(Debug, Trace) 더 많이 기록되지만 로그도 커집니다. '끔'은 로깅을 비활성화합니다.", - "captureLabel": "수집 수준", - "levels": { - "off": "끔", - "error": "오류", - "warn": "경고", - "info": "정보", - "debug": "디버그", - "trace": "추적" - }, - "viewerTitle": "최근 로그", - "viewerDescription": "최근 로그 레코드를 실시간으로 봅니다. 수준으로 필터링하거나 텍스트를 검색하세요.", - "searchPlaceholder": "메시지 또는 대상 검색…", - "viewLevels": { - "all": "모든 수준", - "error": "오류 이상", - "warn": "경고 이상", - "info": "정보 이상", - "debug": "디버그 이상", - "trace": "추적 이상" - }, - "pause": "일시정지", - "resume": "실시간", - "refresh": "새로고침", - "clear": "지우기", - "openFolder": "폴더 열기", - "shownCount": "{shown} / {total} 표시됨", - "empty": "표시할 로그가 없습니다.", - "levelSaveFailed": "로그 수준 저장 실패", - "openFolderFailed": "로그 폴더 열기 실패", - "downloadFailed": "로그 파일 다운로드 실패", - "filesTitle": "로그 파일", - "filesDescription": "실시간 버퍼를 넘어선 기록을 위해 디스크에서 전체 로그 파일을 다운로드합니다.", - "filesEmpty": "아직 로그 파일이 없습니다.", - "download": "다운로드", - "downloadTruncated": "파일이 커서 최신 {size}만 다운로드했습니다. 전체 파일은 로그 디렉터리에 있습니다.", - "captureEnvLocked": "로그 수준은 RUST_LOG / CODEG_LOG 환경 변수로 제어됩니다. 변경하려면 해당 변수를 수정하세요.", - "targetsTitle": "모듈별 재정의", - "targetsDescription": "전역 레벨을 바꾸지 않고 특정 모듈(예: codeg_lib::acp)의 레벨을 따로 설정합니다.", - "targetsAdd": "추가", - "targetsRemove": "재정의 제거", - "toggleDetails": "세부 정보 전환" - }, - "Automations": { - "title": "자동화", - "new": "새 자동화", - "empty": "아직 자동화가 없습니다", - "emptyHint": "하나를 만들어 에이전트 작업을 예약하거나 수동으로 실행하세요.", - "name": "이름", - "namePlaceholder": "예: 야간 PR 검토", - "prompt": "프롬프트", - "promptPlaceholder": "에이전트가 무엇을 하길 원하나요?", - "agent": "에이전트", - "folder": "워크스페이스 폴더", - "folderPlaceholder": "폴더 선택", - "isolation": "격리", - "isolationWorktree": "실행마다 새 worktree", - "isolationShared": "폴더에서 실행", - "isolationSharedCaveat": "실행이 이 폴더의 작업 트리를 직접 사용하므로 커밋하지 않은 변경 사항과 충돌할 수 있습니다. 각 실행을 격리하려면 워크트리 옵션을 활성화하세요.", - "trigger": "트리거", - "triggerSchedule": "예약 실행", - "triggerManual": "수동만", - "cron": "예약(cron)", - "cronPlaceholder": "0 9 * * 1-5", - "timezone": "시간대", - "nextRun": "다음 실행", - "branch": "브랜치", - "branchOptional": "브랜치(선택)", - "enabled": "사용", - "save": "저장", - "cancel": "취소", - "edit": "편집", - "delete": "삭제", - "runNow": "지금 실행", - "cancelRun": "실행 취소", - "runHistory": "실행 기록", - "noRuns": "아직 실행 기록이 없습니다", - "allFolders": "모든 폴더", - "filterAll": "전체", - "noMatches": "일치하는 자동화가 없습니다", - "viewConversation": "대화 보기", - "lastRun": "마지막 실행", - "never": "없음", - "running": "실행 중", - "deleteTitle": "이 자동화를 삭제할까요?", - "deleteDescription": "자동화와 예약이 삭제됩니다. 실행 기록은 유지됩니다.", - "statusRunning": "실행 중", - "statusSucceeded": "성공", - "statusFailed": "실패", - "statusCancelled": "취소됨", - "statusSkipped": "건너뜀", - "errorName": "이름은 필수입니다", - "errorPrompt": "프롬프트는 필수입니다", - "errorCron": "예약 자동화에는 cron 식이 필요합니다", - "errorFolder": "워크스페이스 폴더를 선택하세요", - "presetHourly": "매시간", - "presetDaily": "매일 오전 9시", - "presetWeekdays": "평일 오전 9시", - "presetCustom": "사용자 지정", - "probing": "옵션 불러오는 중…", - "retry": "다시 시도", - "configNone": "이 에이전트에는 구성 가능한 옵션이 없습니다", - "inherit": "에이전트 기본값", - "mode": "모드", - "config": "구성", - "branchPlaceholder": "(기본 브랜치)", - "selectHint": "세부 정보를 보려면 자동화를 선택하세요", - "refresh": "새로고침", - "onboardTitle": "반복적인 에이전트 작업 자동화", - "onboardHint": "코드 리뷰, 의존성 업데이트, 이슈 분류를 일정에 따라 또는 필요할 때 에이전트가 수행하도록 예약하세요.", - "headerSubtitle": "예약 및 온디맨드 에이전트 작업", - "startFromTemplate": "템플릿으로 시작", - "blankTitle": "빈 자동화", - "blankDesc": "에이전트 작업을 처음부터 구성합니다.", - "backToTemplates": "템플릿", - "sectionSchedule": "일정 및 대상", - "sectionTarget": "대상", - "sectionAction": "동작", - "actionLaunchSession": "세션 시작", - "actionEnqueueTask": "작업 대기열에 추가", - "actionEnqueueTaskHint": "실행될 때마다 이 자동화 이름을 제목으로 하는 할 일 작업이 대상 폴더의 할 일 목록에 추가되며, 작업 엔진이 보드 설정에 따라 실행합니다.", - "sectionPrompt": "프롬프트", - "nextIn": "{rel} 후 실행", - "manual": "수동", - "schedEveryMinutes": "{n}분마다", - "schedHourly": "1시간마다", - "schedDaily": "매일 {time}", - "schedWeekdays": "평일 {time}", - "schedWeekly": "매주 {day} {time}", - "schedMonthly": "매월 {day}일 {time}", - "dow0": "일요일", - "dow1": "월요일", - "dow2": "화요일", - "dow3": "수요일", - "dow4": "목요일", - "dow5": "금요일", - "dow6": "토요일", - "tplCodeReviewTitle": "코드 리뷰", - "tplCodeReviewDesc": "최근 변경 사항에서 버그, 회귀, 품질 문제를 검토합니다.", - "tplDependencyUpdatesTitle": "의존성 업데이트", - "tplDependencyUpdatesDesc": "오래된 의존성을 찾아 안전한 업그레이드를 제안합니다.", - "tplTestCoverageTitle": "테스트 커버리지", - "tplTestCoverageDesc": "테스트되지 않은 코드 경로를 찾아 누락된 테스트를 추가합니다.", - "tplTodoSweepTitle": "TODO 정리", - "tplTodoSweepDesc": "TODO와 FIXME 주석을 모아 우선순위에 따라 분류합니다.", - "tplCiTriageTitle": "CI 분류", - "tplCiTriageDesc": "최근 실패한 검사를 조사하고 수정을 제안합니다.", - "tplReleaseNotesTitle": "릴리스 노트", - "tplReleaseNotesDesc": "지난 릴리스 이후의 변경 사항을 요약해 변경 로그를 만듭니다.", - "tplSecurityAuditTitle": "보안 감사", - "tplSecurityAuditDesc": "취약점과 위험한 패턴을 스캔하고 결과를 보고합니다.", - "enable": "활성화", - "disable": "비활성화", - "moreActions": "추가 작업", - "statusDisabled": "비활성화됨", - "cronBuilderTitle": "일정 빌더", - "cronFreqLabel": "빈도", - "cronFreqMinutes": "N분마다", - "cronFreqHourly": "매시간", - "cronFreqDaily": "매일", - "cronFreqWeekdays": "평일", - "cronFreqWeekly": "매주", - "cronFreqMonthly": "매월", - "cronFreqCustom": "사용자 지정", - "cronEveryLabel": "간격(분)", - "cronTimeLabel": "시간", - "cronHourLabel": "시", - "cronMinuteLabel": "분", - "cronDowLabel": "요일", - "cronDomLabel": "일", - "cronApply": "적용", - "cronPreviewLabel": "미리 보기", - "cronOpenBuilder": "일정 빌더 열기", - "branchDefault": "기본 브랜치", - "branchUseCustom": "\"{query}\" 사용", - "branchLocal": "로컬", - "branchRemote": "원격", - "branchSearchPlaceholder": "브랜치 검색…", - "branchNone": "브랜치 없음" - }, - "Tasks": { - "title": "할 일", - "new": "새 작업", - "empty": "아직 작업이 없습니다", - "emptyHint": "할 일을 추가하고 실행하세요. 에이전트가 독립된 worktree에서 작업하고, 결과를 검토한 뒤 병합합니다.", - "emptyColTodo": "아직 할 일이 없습니다", - "emptyColInProgress": "진행 중인 작업이 없습니다", - "emptyColAttention": "처리할 작업이 없습니다", - "emptyColDone": "완료된 작업이 아직 없습니다", - "allFolders": "모든 폴더", - "showCanceled": "취소됨 표시", - "showArchived": "보관된 항목 표시", - "filter": "필터", - "viewSwitchToBoard": "보드 보기로 전환", - "viewSwitchToList": "목록 보기로 전환", - "statusFilter": "상태", - "statusFilterAll": "모든 상태", - "listEmpty": "현재 필터와 일치하는 작업이 없습니다", - "listColStatus": "상태", - "listColTask": "작업", - "listColLocation": "위치", - "listColChanges": "변경", - "listColUpdated": "업데이트", - "colTodo": "할 일", - "colInProgress": "진행 중", - "colAttention": "처리 필요", - "colDone": "완료", - "statusTodo": "할 일", - "statusQueued": "대기 중", - "statusPreparing": "준비 중", - "statusRunning": "실행 중", - "statusAwaitingInput": "입력 대기", - "statusReview": "검토 대기", - "statusMerging": "병합 중", - "statusDone": "완료", - "statusFailed": "실패", - "statusCanceled": "취소됨", - "statusInterrupted": "중단됨", - "badgeCleanupFailed": "정리 실패", - "badgeWorktreeKept": "worktree 유지", - "badgeWorktreeRemoved": "worktree 삭제됨", - "filesChanged": "{count}개 파일", - "actionStart": "시작", - "actionSchedule": "예약 실행", - "actionCancel": "취소", - "actionRetry": "다시 시도", - "actionRequeue": "다시 대기열에", - "actionViewSession": "대화 보기", - "actionEdit": "편집", - "actionDelete": "삭제", - "actionRetryCleanup": "정리 다시 시도", - "actionMerge": "병합", - "actionUnqueueMerge": "병합 대기 취소", - "actionEditQueuedMerge": "대기 중인 병합 수정", - "badgeMergeQueued": "병합 대기 중", - "badgeMergeQueuedRank": "병합 대기 · {rank}번째", - "badgeMergeQueuedHint": "이 프로젝트에서 진행 중인 병합이 끝나기를 기다리는 중이며, 차례가 되면 자동으로 시작합니다.", - "actionComplete": "완료", - "actionAbandon": "포기", - "cancelTitle": "작업을 취소할까요?", - "cancelDescription": "작업이 취소됨으로 바뀝니다. worktree는 그대로 두며 나중에 다시 대기열에 넣을 수 있습니다.", - "cancelReasonLabel": "취소 사유 (선택)", - "cancelReasonPlaceholder": "예: 방향이 잘못돼서 설명을 다시 쓸게요", - "cancelKeep": "그대로 두기", - "cancelSubmit": "작업 취소", - "restartTitleRetry": "작업 다시 시도", - "restartTitleRequeue": "작업 다시 대기열에", - "restartDescription": "메모(선택)를 남기면 다음 실행 프롬프트에 담겨 에이전트에게 전달됩니다.", - "scheduleTitle": "작업 실행 예약", - "scheduleDescription": "작업은 '할 일'에 남아 있다가 지정한 시각에 자동으로 시작됩니다. 폴더의 동시 실행 한도는 그대로 적용됩니다.", - "scheduleDateLabel": "날짜", - "schedulePickDate": "날짜 선택", - "scheduleTimeLabel": "시간", - "schedulePreview": "{time}에 실행", - "schedulePastHint": "이미 지난 시각입니다. 저장하면 바로 시작합니다.", - "scheduleInAnHour": "1시간 후", - "scheduleInThreeHours": "3시간 후", - "scheduleTomorrow": "내일 9:00", - "scheduleClear": "예약 해제", - "scheduleBadge": "{time}에 시작 예정", - "toastScheduled": "{time}에 실행하도록 예약했습니다", - "toastScheduleCleared": "예약을 해제했습니다", - "actionFollowUp": "이어서 요청", - "actionAddNote": "메모 추가", - "followUpSubmit": "보내기", - "followUpIntentRevise": "수정 요청", - "followUpIntentContinue": "계속 진행", - "followUpIntentQuestion": "질문하기", - "followUpIntentVerify": "자체 점검", - "followUpPlaceholderRevise": "무엇을 고쳐야 하나요? 같은 세션에서 이어집니다.", - "followUpPlaceholderContinue": "다음은 무엇인가요? 지금까지의 작업은 그대로 둡니다.", - "followUpPlaceholderQuestion": "무엇이 궁금한가요? 파일은 건드리지 않고 답변만 합니다.", - "followUpPlaceholderVerify": "선택: 특별히 확인했으면 하는 부분이 있나요?", - "followUpPlaceholderRetry": "선택: 이번엔 무엇을 다르게 할까요? 예: pnpm install 먼저 실행", - "followUpPlaceholderRequeue": "선택: 왜 취소했고, 이번엔 무엇이 달라져야 하나요?", - "actionArchive": "보관", - "actionUnarchive": "보관 해제", - "archiveAllDone": "모두 보관", - "dropToStart": "놓으면 실행 시작", - "errorView": "보기", - "notifyReview": "검수 대기: {title}", - "notifyFailed": "작업 실패: {title}", - "createFromMessage": "이 메시지로 작업 만들기", - "detailTokens": "총 토큰", - "editorTitleNew": "새 작업", - "editorTitleEdit": "작업 편집", - "templates": "템플릿", - "templatesEmpty": "아직 템플릿이 없습니다.", - "templateSaveCurrent": "현재 내용을 템플릿으로 저장", - "templateDelete": "템플릿 삭제", - "transcriptTitle": "작업 대화", - "transcriptDescription": "작업 에이전트 세션의 읽기 전용 실시간 보기입니다.", - "phaseWork": "작업 실행", - "phaseRetry": "다시 실행", - "phaseReturn": "이어서 요청", - "phaseMerge": "병합", - "titleLabel": "제목", - "titlePlaceholder": "무엇을 해야 하나요?", - "promptLabel": "작업 설명", - "promptPlaceholder": "에이전트에게 작업을 설명하세요 — @로 파일 참조, /로 명령", - "folderPlaceholder": "폴더 선택", - "agentInheritedHint": "작업 설정에서 상속됨 — 변경하면 이 작업에만 적용됩니다", - "agentOverrideReset": "상속으로 되돌리기", - "sectionTarget": "대상", - "errorTitle": "제목을 입력하세요", - "errorPrompt": "작업 설명을 입력하세요", - "errorFolder": "폴더를 선택하세요", - "save": "저장", - "cancel": "취소", - "mergeTitle": "작업 병합", - "mergeQueuedTitle": "대기 중인 병합", - "mergeQueueHint": "이 프로젝트의 다른 작업이 병합 중입니다. 이 작업은 대기열에 들어가며 앞의 병합이 끝나는 대로 자동으로 시작합니다.", - "mergeQueueUpdateHint": "이 작업은 이미 병합을 기다리고 있습니다. 제출하면 내용만 업데이트되고 대기 순서는 그대로 유지됩니다.", - "mergeDescription": "{branch}을(를) {base}에 병합합니다. worktree의 커밋되지 않은 변경은 먼저 커밋됩니다.", - "mergeMessage": "커밋 메시지", - "mergeMessagePlaceholder": "예: feat: add login validation", - "mergeAutoMessage": "커밋 메시지를 에이전트가 작성하도록 하기", - "strategySquash": "하나의 커밋으로 합치기", - "strategySquashHint": "작업의 모든 변경 사항이 하나의 기록으로 메인 브랜치에 반영되어 히스토리가 깔끔해집니다.", - "strategyMerge": "전체 히스토리 유지", - "strategyMergeHint": "작업 중의 모든 커밋을 그대로 유지하고 병합 기록을 하나 추가합니다. 각 단계를 추적할 수 있습니다.", - "mergeDeleteWorktree": "병합 후 worktree 삭제", - "mergeSubmit": "병합", - "mergeSubmitQueue": "병합 대기열에 추가", - "mergeQueuedToast": "병합 대기열에 추가했습니다. 현재 병합이 끝나는 대로 시작합니다.", - "completeTitle": "작업 완료", - "completeDescription": "이 작업은 파일을 변경하지 않아 병합할 것이 없습니다. 그대로 완료로 표시합니다.", - "completeDescriptionNoWorktree": "이 작업의 worktree가 삭제되어 더 이상 병합할 수 없습니다. 그대로 완료로 표시합니다. 병합되지 않은 커밋이 남아 있는 작업 브랜치는 유지됩니다.", - "completeDeleteWorktree": "완료 후 worktree 삭제", - "completeSubmit": "완료", - "settingsTitle": "작업 설정", - "settingsDescription": "{folder}의 작업 기본값입니다.", - "settingsScope": "적용 범위", - "settingsScopeGlobal": "모든 폴더(전역 기본값)", - "settingsScopeGlobalHint": "별도 설정이 없는 폴더는 이 전역 기본값을 사용합니다.", - "settingsSource": "설정 출처", - "settingsSourceGlobal": "전역 기본값 사용", - "settingsSourceCustom": "개별 설정", - "settingsSourceGlobalFollow": "전역 작업 설정을 따릅니다. 전역 변경 사항이 자동으로 적용됩니다.", - "settingsSourceCustomHint": "이 폴더만의 설정을 저장하며 더 이상 전역 기본값을 따르지 않습니다.", - "settingsAgent": "기본 에이전트", - "settingsMaxConcurrent": "최대 동시 작업 수", - "settingsMaxConcurrentHint": "0 = 무제한", - "settingsAutoProcess": "자동 처리", - "settingsAutoProcessHint": "할 일 작업이 동시 실행 한도 내에서 자동으로 시작됩니다.", - "settingsMergeStrategy": "기본 병합 전략", - "settingsMergeStrategyHint": "병합할 때 작업의 변경 사항을 브랜치 히스토리에 어떻게 기록할지 정합니다.", - "settingsAutoMerge": "자동 병합", - "settingsAutoMergeHint": "검토 대기에 도달하고 병합할 변경이 있는 작업은 병합 버튼을 누른 것과 똑같이 자동으로 병합됩니다. 커밋 메시지는 에이전트가 작성하고 worktree 처리는 아래 기본값을 따릅니다. 사전 점검이 실패했거나 병합에 실패한 작업은 남아서 기다립니다.", - "settingsDeleteWorktree": "머지 후 worktree 삭제", - "settingsDeleteWorktreeHint": "머지 대화상자에서 기본으로 선택됩니다. 거기서 바꿀 수도 있습니다.", - "settingsWorktreeRoot": "워크트리 위치", - "settingsWorktreeRootHint": "새 작업의 worktree를 이 디렉터리 아래에 작업마다 하나씩 만듭니다. 비워 두면 프로젝트 폴더와 같은 위치에 만듭니다. \"~\"는 홈 디렉터리이고 상대 경로는 프로젝트 폴더 기준입니다.", - "settingsWorktreeRootPlaceholder": "~/codeg-worktrees", - "settingsWorktreeRootBrowse": "워크트리 디렉터리 선택", - "settingsPreflight": "사전 점검 명령", - "settingsPreflightHint": "작업이 검토 단계에 도달하면 워크트리에서 실행.", - "settingsPreflightCustomPlaceholder": "pnpm test", - "settingsInitCommand": "워크트리 초기화 명령", - "settingsInitCommandHint": "워크트리를 새로 만든 뒤 에이전트 시작 전에 실행됩니다.", - "settingsInitCommandPlaceholder": "pnpm install", - "settingsTabGeneral": "일반", - "settingsTabMerge": "병합", - "settingsTabWorktree": "워크트리", - "settingsTabPrompts": "프롬프트", - "settingsPromptsIntro": "각 단계에는 이미 기본 프롬프트가 들어 있습니다 — 작업 내용, 워크트리 규칙, 머지 단계의 구체적인 git 절차. 여기에 적은 내용은 추가 지시로 맨 뒤에 덧붙으며, 기본 프롬프트를 보완할 뿐 대체하지 않습니다.", - "settingsPromptStageAll": "전체 단계", - "settingsPromptPlaceholderAll": "예: AGENTS.md의 프로젝트 규칙을 따르고, 마지막 요약은 두 문장 이내로", - "settingsPromptPlaceholderWork": "예: 관련 테스트를 먼저 읽고, 작은 단위로 자주 커밋", - "settingsPromptPlaceholderRetry": "예: 이어서 하기 전에 이미 커밋된 내용을 확인하고, 끝난 작업은 다시 하지 말 것", - "settingsPromptPlaceholderReturn": "예: 언급된 항목을 하나씩 처리하고, 관련 없는 리팩터링은 하지 마세요", - "settingsPromptPlaceholderMerge": "예: 최종 반영 커밋 메시지는 한국어로, 수동으로 해결한 충돌은 따로 밝힐 것", - "settingsPromptHintAll": "머지 실행을 포함해 에이전트가 받는 모든 프롬프트에 추가됩니다.", - "settingsPromptHintWork": "작업을 처음 실행할 때 추가됩니다.", - "settingsPromptHintRetry": "중단되거나 실패한 작업을 다시 이어갈 때 추가됩니다.", - "settingsPromptHintReturn": "검토 대기 작업에 이어서 요청할 때(수정·추가 작업·자체 점검) 덧붙습니다.", - "settingsPromptHintMerge": "에이전트가 작업을 기준 브랜치에 병합할 때 추가됩니다.", - "preflightPassed": "{name} 통과", - "preflightFailed": "{name} 실패", - "preflightRunning": "{name} 실행 중…", - "detailDescription": "작업 상세", - "detailSummary": "결과", - "detailFiles": "변경된 파일", - "detailDiffAll": "전체 차이 보기", - "detailDiffAllTitle": "전체 차이", - "detailNoChanges": "기준 대비 변경 사항이 아직 없습니다", - "detailTimeline": "진행 기록", - "detailTimelineEmpty": "아직 활동이 없습니다", - "showMore": "더 보기", - "showLess": "접기", - "detailInfo": "상세 정보", - "detailBranch": "브랜치", - "detailMergeCommit": "병합 커밋", - "detailChanges": "변경 사항", - "detailScheduled": "시작 예정", - "detailCreated": "생성 시간", - "detailStarted": "시작 시간", - "detailFinished": "완료 시간", - "diffLoading": "차이를 불러오는 중…", - "deleteConfirmTitle": "작업을 삭제할까요?", - "deleteConfirmBody": "“{title}”이(가) 보드에서 제거됩니다. 실행 중이면 먼저 취소됩니다.", - "deleteWithWorktree": "worktree도 함께 삭제", - "eventCreated": "생성됨", - "eventStatusChanged": "상태 변경", - "eventConfigEffective": "실행 구성", - "eventInitCommand": "초기화 명령", - "eventAgentProgress": "에이전트 진행", - "eventAgentVerdict": "에이전트 판정", - "eventMergeAttempt": "병합 시작", - "eventMergeQueued": "병합 대기열에 추가", - "eventMergeConflict": "병합 충돌", - "eventPreflight": "사전 점검", - "eventCleanupFailed": "worktree 정리 실패", - "eventResumeFallback": "세션 재개 실패, 새 세션으로 전환", - "eventUserAction": "사용자 작업", - "eventDiffStat": "변경 스냅샷" - }, - "CustomSkillsSettings": { - "loading": "사용자 지정 스킬 불러오는 중…", - "category": "사용자 지정", - "searchPlaceholder": "이름, ID 또는 설명으로 사용자 지정 스킬 검색", - "states": { - "not_linked": "사용 안 함", - "linked_to_codeg": "사용 중", - "linked_elsewhere": "다른 위치에 연결됨", - "blocked_by_real_directory": "실제 폴더가 차지함", - "broken": "손상된 링크" - }, - "actions": { - "new": "새로 만들기", - "import": "가져오기", - "importFromAgent": "에이전트에서 가져오기", - "cancel": "취소", - "save": "저장" - }, - "rowMenu": { - "edit": "편집", - "duplicate": "복제", - "delete": "삭제" - }, - "bulk": { - "delete": "선택 항목 삭제" - }, - "editor": { - "createTitle": "새 사용자 지정 스킬", - "editTitle": "사용자 지정 스킬 편집", - "description": "사용자 지정 스킬은 공유 저장소(~/.codeg/skills)에 있으며 모든 에이전트에서 사용할 수 있습니다.", - "idLabel": "스킬 ID", - "idPlaceholder": "예: my-workflow", - "contentLabel": "SKILL.md", - "contentPlaceholder": "여기에 스킬의 SKILL.md를 작성하세요…", - "preview": "미리보기", - "edit": "편집", - "emptyBody": "아직 내용이 없습니다." - }, - "duplicate": { - "title": "스킬 복제", - "description": "\"{id}\"을(를) 기반으로 새 ID로 복사본을 만듭니다.", - "newIdPlaceholder": "새 스킬 ID", - "confirm": "복제" - }, - "import": { - "title": "가져올 스킬 폴더 선택" - }, - "importFromAgent": { - "title": "에이전트에서 스킬 가져오기", - "description": "에이전트의 자체 스킬을 공유 저장소로 복사하면 어떤 에이전트에서도 사용할 수 있습니다.", - "agentLabel": "에이전트", - "agentPlaceholder": "에이전트 선택", - "selectAll": "모두 선택 ({count})", - "loading": "에이전트의 스킬을 불러오는 중…", - "unsupported": "이 에이전트는 스킬 디렉터리를 제공하지 않습니다.", - "empty": "이 에이전트에는 가져올 스킬이 없습니다.", - "alreadyInLibrary": "라이브러리에 있음", - "confirm": "선택 항목 가져오기 ({count})" - }, - "delete": { - "title": "사용자 지정 스킬을 삭제할까요?", - "body": "{count}개의 사용자 지정 스킬을 중앙 저장소에서 제거하고 모든 에이전트에서 링크를 해제합니다. 이 작업은 취소할 수 없습니다.", - "confirm": "삭제" - }, - "toasts": { - "loadFailed": "스킬 불러오기 실패", - "idRequired": "스킬 ID를 입력하세요", - "created": "사용자 지정 스킬 생성됨", - "updated": "사용자 지정 스킬 업데이트됨", - "saveFailed": "스킬 저장 실패", - "imported": "스킬 가져옴", - "importFailed": "스킬 가져오기 실패", - "duplicated": "스킬 복제됨", - "duplicateFailed": "스킬 복제 실패", - "deleted": "{count}개 스킬 삭제됨", - "deletedPartial": "{ok}개 삭제, {failed}개 실패", - "deleteFailed": "스킬 삭제 실패", - "importedFromAgent": "{count}개의 스킬을 가져왔습니다", - "importedFromAgentPartial": "{ok}개 가져옴, {failed}개 실패", - "importFromAgentAllSkipped": "가져올 항목 없음 — {count}개가 이미 라이브러리에 있습니다", - "importFromAgentFailed": "에이전트에서 가져오기 실패" - } - }, - "CodexModelEditor": { - "customizedNotice": "모델 목록을 사용자 지정했으므로 이제 codeg가 codex의 전체 모델 표를 관리합니다. codex가 이후 추가하는 공식 모델은 자동으로 나타나지 않습니다. 아래의 새로 고침을 클릭한 뒤 다시 저장하면 동기화됩니다. 사용자 지정을 모두 지우면 codex 자동 업데이트로 되돌아갑니다.", - "officialsTitle": "공식 모델", - "officialsHint": "실행하는 codex의 공식 모델을 자동 포함합니다. 필요 없는 항목은 삭제하세요.", - "officialsEmpty": "사용 가능한 공식 모델이 없습니다.", - "refresh": "codex에서 새로고침", - "readdOfficial": "공식 다시 추가", - "customsTitle": "사용자 지정 모델", - "customsEmpty": "사용자 지정 모델이 없습니다.", - "addCustom": "사용자 지정 추가", - "slugPlaceholder": "모델 ID(slug)", - "displayNamePlaceholder": "표시 이름", - "contextWindow": "컨텍스트", - "makeDefault": "기본값으로 설정", - "defaultHint": "기본 모델", - "remove": "제거", - "advanced": "고급", - "baseTemplate": "기본 템플릿", - "baseTemplateHint": "필수 필드(시스템 프롬프트, 도구, 제한)를 복제할 공식 모델.", - "groupBehavior": "동작 및 기능", - "fieldReasoningLevel": "기본 추론 강도", - "fieldReasoningSummary": "추론 요약", - "fieldVerbosity": "상세도", - "fieldShellType": "셸 유형", - "fieldApplyPatch": "패치 적용 도구", - "fieldReasoningSummaries": "추론 요약 지원", - "fieldSupportVerbosity": "상세도 제어", - "fieldParallelToolCalls": "병렬 도구 호출", - "fieldSearchTool": "웹 검색 도구", - "optNone": "없음", - "groupInstructions": "설명 및 시스템 프롬프트", - "fieldDescription": "설명", - "baseInstructions": "시스템 프롬프트(base_instructions)" - }, - "DiagnosticsSettings": { - "title": "환경 진단", - "description": "이 앱이 자체 프로세스에서 에이전트 CLI를 어떻게 확인하는지 점검합니다(터미널과 다를 수 있음).", - "loading": "진단 실행 중…", - "error": "진단 실패", - "rerun": "다시 실행", - "copyAll": "전체 복사", - "copied": "진단 정보를 클립보드에 복사했습니다", - "button": "진단", - "verdict": { - "ok": "환경이 정상입니다. 그래도 설치되지 않았다고 표시되면 앱을 완전히 재시작하여 프리픽스 캐시를 새로 고치세요.", - "node_missing": "앱 PATH에서 Node.js를 찾을 수 없습니다.", - "npm_missing": "앱 PATH에서 npm을 찾을 수 없습니다.", - "not_installed": "이 에이전트가 설치되지 않은 것 같습니다.", - "installed_but_unresolved": "설치된 것으로 기록되어 있지만 앱이 실행 파일을 찾지 못합니다.", - "user_prefix_not_on_path": "폴백 프리픽스(~/.codeg/npm-global)에 설치되었지만 앱 PATH에 없습니다. 앱을 완전히 재시작한 후 다시 시도하세요.", - "homebrew_bin_not_on_path": "Homebrew bin에 설치되었지만 앱 PATH에 없습니다(Apple Silicon keg 분리).", - "terminal_only_path": "이 명령은 터미널에서는 확인되지만 앱에서는 확인되지 않습니다. GUI PATH 불일치입니다. 터미널에서 앱을 실행하거나 에이전트 설정에서 다시 설치하세요.", - "npm_prefix_timeout": "npm prefix -g가 너무 느립니다(1.5초 초과). 폴백 감지를 건너뛰었습니다. 앱을 재시작한 후 다시 시도하세요.", - "node_too_old": "현재 Node.js가 이 에이전트의 요구 버전보다 낮습니다. Node.js를 업그레이드하세요.", - "adapter_missing_native_present": "사용 중인 {agent} CLI는 설치되어 있지만, Codeg가 실행하는 것은 별도의 ACP 어댑터 패키지이며 그것이 아직 설치되지 않았습니다. 에이전트 설정에서 설치하세요. 기존 CLI는 건드리지 않으며 로그인도 공유됩니다.", - "adapter_missing": "Codeg는 {agent}에 대해 별도의 ACP 어댑터 패키지를 실행하는데, 아직 설치되지 않았습니다. 에이전트 설정에서 설치하세요 — 벤더 CLI만 설치하는 것으로는 충분하지 않습니다." - } - }, - "TokenUsage": { - "title": "토큰 사용량", - "rangeLabel": "기간", - "range7d": "7일", - "range30d": "30일", - "range90d": "90일", - "rangeThisMonth": "이번 달", - "rangeThisYear": "올해", - "rangeAll": "전체", - "rangeCustom": "사용자 지정", - "moreRanges": "더보기", - "customRangePick": "기간 선택", - "bucketLabel": "집계 단위", - "bucketDay": "일", - "bucketWeek": "주", - "bucketMonth": "월", - "bucketUnitDay": "날", - "bucketUnitWeek": "주", - "bucketUnitMonth": "월", - "folderFilter": "폴더", - "allFolders": "모든 폴더", - "agentFilter": "에이전트", - "allAgents": "모든 에이전트", - "modelFilter": "모델", - "allModels": "모든 모델", - "searchPlaceholder": "검색…", - "noMatches": "일치하는 항목 없음", - "clearFilter": "선택 해제", - "resetFilters": "필터 초기화", - "refresh": "새로 고침", - "rebuild": "전체 재구성", - "rebuildHint": "집계된 데이터를 버리고 모든 세션 기록을 다시 읽습니다. codeg 밖의 CLI가 기록을 이어썼을 때 사용하세요.", - "syncing": "세션 집계 중…", - "syncProgress": "{done} / {total}", - "syncDone": "{synced}개 세션을 집계했습니다", - "syncFailed": "일부 세션을 읽지 못했습니다", - "syncBusy": "이미 새로 고침이 진행 중입니다", - "lastSynced": "{time}에 업데이트", - "lastSyncedNever": "집계된 적 없음", - "tileTotal": "총 토큰", - "tileSessions": "세션 수", - "tileTurns": "대화 턴", - "tileActiveDays": "활동 일수", - "tileGenTime": "생성 시간", - "vsPrevious": "이전 기간 대비", - "deltaNew": "신규", - "trendTitle": "사용량 추이", - "trendEmpty": "이 기간에는 사용량이 없습니다", - "trendTurns": "턴", - "trendSessions": "세션", - "compositionTitle": "토큰 구성", - "compositionHint": "입력은 보낸 내용, 출력은 모델이 쓴 내용, 캐시 읽기는 다시 보내지 않아도 된 컨텍스트입니다.", - "compositionNote": "이 캐시 적중을 정가로 다시 보냈다면 {value}가 더 들었을 것입니다.", - "inputTokens": "입력", - "outputTokens": "출력", - "cacheWrite": "캐시 쓰기", - "cacheRead": "캐시 읽기", - "freshTokens": "신규 연산 토큰", - "cacheHitCaption": "캐시 적중", - "cacheHeroTitleHigh": "컨텍스트 대부분은 다시 보낼 필요가 없었습니다", - "cacheHeroTitleLow": "컨텍스트 대부분이 아직 정가로 계산됩니다", - "cacheHeroDesc": "{cached}의 컨텍스트를 캐시가 감당했고, 이 기간에 실제로 새로 연산된 것은 {fresh}뿐입니다.", - "cacheSavedSuffix": "재전송을 {saved}만큼 아꼈습니다.", - "avgPerSession": "세션당 평균", - "avgTurnsPerSession": "세션당 평균 {count}턴", - "avgPerActiveDay": "활동일당 평균", - "peakBucket": "가장 많은 {bucket}", - "peakHour": "피크 시간대", - "daysValue": "{count}일", - "idleDays": "쉬어간 날", - "byFolderTitle": "폴더별", - "byAgentTitle": "에이전트별", - "byModelTitle": "모델별", - "distributionTitle": "사용량 분포", - "distributionHint": "선택한 기준으로 세션과 토큰을 집계합니다. 행을 클릭하면 해당 항목으로 필터링됩니다.", - "otherLabel": "기타", - "unknownModel": "모델 미기록", - "emptyBreakdown": "기록이 없습니다", - "sessionsCount": "{count}개 세션", - "heatmapTitle": "작업 리듬", - "heatmapHint": "로컬 요일·시간대별 토큰 분포입니다.", - "heatmapPeakHint": "{hour}:00 전후가 가장 밀집되어 있습니다.", - "less": "적음", - "more": "많음", - "heatmapCell": "{weekday} {hour}:00 — {value} 토큰", - "weekMon": "월", - "weekTue": "화", - "weekWed": "수", - "weekThu": "목", - "weekFri": "금", - "weekSat": "토", - "weekSun": "일", - "topSessionsTitle": "소비가 큰 세션", - "untitledSession": "제목 없는 세션", - "topSessionsEmpty": "이 기간에는 세션이 없습니다", - "streakLongest": "최장 연속", - "streakLongestDays": "최장 연속 {count}일", - "share": "공유", - "moreActions": "기타 작업", - "shareDialogTitle": "사용량 카드 공유", - "shareDialogHint": "지금 보고 있는 기간과 필터의 스냅샷입니다.", - "shareSave": "이미지 저장", - "shareCopy": "이미지 복사", - "shareCopied": "클립보드에 복사했습니다", - "shareSaved": "이미지를 저장했습니다", - "shareFailed": "이미지를 만들지 못했습니다", - "shareRendering": "생성 중…", - "cardHeading": "나의 AI 코딩 기록", - "cardRangeAll": "전체 기간", - "cardTotalLabel": "사용 토큰", - "cardFooter": "codeg로 제작", - "cardTopModels": "주요 모델", - "cardTopProjects": "주요 프로젝트", - "archetypeNightOwl": "야행성 개발자", - "archetypeNightOwlDesc": "토큰의 {percent}%를 해가 진 뒤에 씁니다.", - "archetypeEarlyBird": "아침형 개발자", - "archetypeEarlyBirdDesc": "토큰의 {percent}%를 오전 9시 전에 씁니다.", - "archetypeWeekendWarrior": "주말 전사", - "archetypeWeekendWarriorDesc": "토큰의 {percent}%가 주말에 발생합니다.", - "archetypeCacheMaster": "캐시 마스터", - "archetypeCacheMasterDesc": "컨텍스트의 {percent}%가 캐시에서 왔습니다.", - "archetypeMarathoner": "마라토너", - "archetypeMarathonerDesc": "{days}일 연속으로 개발했습니다.", - "archetypePolyglot": "멀티 플레이어", - "archetypePolyglotDesc": "{count}개 에이전트를 본격적으로 함께 씁니다.", - "archetypeLaserFocus": "한 우물", - "archetypeLaserFocusDesc": "토큰의 {percent}%를 한 프로젝트에 썼습니다.", - "archetypeDeepDiver": "딥 다이버", - "archetypeDeepDiverDesc": "세션당 평균 {averageK}K 토큰.", - "archetypeSteady": "꾸준한 빌더", - "archetypeSteadyDesc": "총 {days}일 동안 개발했습니다.", - "emptyTitle": "아직 집계된 데이터가 없습니다", - "emptyHint": "codeg는 각 에이전트의 세션 기록에서 토큰 수를 직접 읽습니다. 새로 고침하면 이 컴퓨터에 있는 기록을 집계합니다.", - "emptyAction": "내 세션 집계", - "loadFailed": "사용량을 불러오지 못했습니다", - "truncatedNotice": "기간이 매우 길어 표시된 수치는 가장 최근 구간만 반영합니다." - } -} +{ + "Language": { + "followSystem": "시스템 설정 따름", + "english": "영어", + "simplifiedChinese": "简体中文", + "traditionalChinese": "繁體中文", + "japanese": "일본어", + "korean": "한국어", + "spanish": "스페인어", + "german": "독일어", + "french": "프랑스어", + "portuguese": "포르투갈어", + "arabic": "아랍어" + }, + "GitCredentialDialog": { + "title": "인증 필요", + "description": "원격 서버에서 자격 증명을 요구합니다. 사용자 이름과 비밀번호(또는 개인 액세스 토큰)를 입력하세요.", + "username": "사용자 이름", + "usernamePlaceholder": "사용자 이름 또는 이메일", + "password": "비밀번호 / 토큰", + "passwordPlaceholder": "비밀번호 또는 개인 액세스 토큰", + "passwordHint": "서버의 사용자 이름과 비밀번호를 입력하세요.", + "cancel": "취소", + "authenticate": "인증", + "authenticating": "인증 중...", + "invalidCredentials": "자격 증명이 유효하지 않습니다. 다시 시도하세요.", + "saveCredentials": "향후 작업을 위해 자격 증명 저장", + "githubTitle": "GitHub 인증", + "githubDescription": "개인 액세스 토큰을 입력하여 GitHub에 연결합니다. 토큰 확인 후 계정에 자동으로 저장됩니다.", + "githubToken": "개인 액세스 토큰", + "githubTokenPlaceholder": "ghp_xxxxxxxxxxxx", + "githubTokenHint": "GitHub → Settings → Developer settings → Personal access tokens에서 토큰을 생성하세요.", + "githubAuthenticate": "확인 및 연결", + "generateToken": "토큰 생성" + }, + "SettingsShell": { + "title": "설정", + "preferences": "환경설정", + "nav": { + "general": "일반", + "appearance": "외관", + "agents": "에이전트", + "mcp": "MCP", + "skills": "Skills", + "shortcuts": "단축키", + "version_control": "버전 관리", + "system": "시스템", + "chat_channels": "채팅 채널", + "web_service": "웹 서비스", + "model_providers": "모델 제공업체", + "experts": "전문가", + "science": "과학 연구", + "office_tools": "오피스 도구", + "skill_packs": "스킬 팩", + "quick_messages": "빠른 메시지", + "logs": "실행 로그" + } + }, + "AppearanceSettings": { + "sectionTitle": "테마 모양", + "sectionDescription": "라이트, 다크 또는 시스템 설정을 선택할 수 있습니다. 설정은 자동으로 저장됩니다.", + "themeMode": "테마 모드", + "placeholder": "테마 모드 선택", + "system": "시스템 설정 따름", + "light": "라이트", + "dark": "다크", + "currentTheme": "현재 적용된 테마: {theme}", + "resolvedTheme": { + "light": "라이트", + "dark": "다크", + "unknown": "--" + }, + "themeColor": { + "sectionTitle": "테마 색상", + "sectionDescription": "버튼, 강조 색상, 하이라이트에 사용할 색상 팔레트를 선택하세요.", + "current": "현재 색상: {color}", + "options": { + "neutral": "Neutral", + "zinc": "Zinc", + "slate": "Slate", + "stone": "Stone", + "gray": "Gray", + "red": "Red", + "rose": "Rose", + "orange": "Orange", + "green": "Green", + "blue": "Blue", + "yellow": "Yellow", + "violet": "Violet" + } + }, + "customStyle": { + "sectionTitle": "사용자 지정 스타일", + "sectionDescription": "현재 테마의 색상을 미세 조정하거나 직접 작성한 CSS를 적용합니다. 재정의는 기본 프리셋 위에 얹히므로 프리셋을 바꿔도 유지됩니다.", + "summarySuspended": "일시 중지됨", + "summaryDefault": "프리셋 기본값", + "summaryTokens": "{count, plural, one {재정의 #개} other {재정의 #개}}", + "summaryCss": "사용자 지정 CSS", + "suspendedByShortcut": "사용자 지정 스타일이 일시 중지되었습니다. 다시 켜기 전까지 여기서 설정한 내용은 적용되지 않습니다.", + "suspendedBySafeParam": "이 창은 안전 외관 모드로 열려 사용자 지정 스타일이 적용되지 않습니다. 다른 창에는 영향이 없습니다.", + "resume": "사용자 지정 스타일 재개", + "enableTheme": "사용자 지정 색상 사용", + "editingLight": "라이트 모드 값을 편집하고 있습니다. 다크 모드로 전환하면 따로 설정할 수 있습니다.", + "editingDark": "다크 모드 값을 편집하고 있습니다. 라이트 모드로 전환하면 따로 설정할 수 있습니다.", + "resetToken": "프리셋 값으로 되돌리기", + "radius": "모서리 둥글기", + "radiusHint": "sm부터 4xl까지의 둥글기 척도 전체가 이 값에서 파생되므로 슬라이더 하나로 앱 전체가 바뀝니다.", + "advanced": "고급 (변수 {count}개 더)", + "enableCss": "사용자 지정 CSS 사용", + "cssRisk": "고급 기능입니다. 사용자 지정 CSS는 모든 기본 스타일을 덮어쓰므로 화면을 사용할 수 없게 만들 수 있습니다.", + "editCss": "CSS 편집…", + "cssPresent": "{size} KB 저장됨", + "cssEmpty": "아직 저장된 내용이 없습니다", + "escapeHint": "화면이 망가졌나요? {shortcut} 키로 모든 사용자 지정 스타일을 중지할 수 있고, safeStyle=1 쿼리 파라미터로 창을 열 수도 있습니다.", + "copyTheme": "테마 JSON 복사", + "importTheme": "테마 가져오기…", + "clearTheme": "재정의 지우기", + "interopHint": "테마는 shadcn의 registry:theme 형식을 사용합니다. 어떤 shadcn 테마든 붙여넣을 수 있고, 내보낸 테마는 모든 shadcn 프로젝트에서 쓸 수 있습니다.", + "importTitle": "테마 가져오기", + "importDescription": "shadcn의 registry:theme 항목, light/dark 객체, 또는 단층 토큰 맵을 붙여넣으세요.", + "readClipboard": "클립보드 읽기", + "importConfirm": "가져오기", + "cancel": "취소", + "apply": "적용", + "toasts": { + "copied": "테마 JSON을 복사했습니다", + "copyFailed": "클립보드에 복사하지 못했습니다", + "clipboardReadFailed": "클립보드를 읽지 못했습니다. 직접 붙여넣어 주세요", + "importFailed": "이 JSON에는 사용할 수 있는 테마 변수가 없습니다", + "imported": "테마를 가져왔습니다" + }, + "css": { + "dialogTitle": "사용자 지정 CSS", + "dialogDescription": "모든 codeg 창에 적용됩니다. 변경 사항은 실시간으로 미리 보이며 적용을 눌러야 저장됩니다.", + "size": "{used} KB / {max} KB", + "ruleCount": "규칙 {count}개", + "errorTooLarge": "너무 커서 저장할 수 없습니다. 상한 아래로 줄여 주세요.", + "errorImportEscaped": "제거 후에도 @import가 감지되었습니다(이스케이프 표기). 직접 삭제해 주세요.", + "warnNoRules": "해석된 규칙이 없습니다. 문법을 확인하세요.", + "noticeImportsRemoved": "@import 규칙 {count}개를 제거했습니다. 원격 스타일시트를 가져오기 때문입니다.", + "noticeRemoteUrl": "원격 url()이 포함되어 있어 적용 시 네트워크 요청이 발생합니다.", + "noticePreviewSuspended": "사용자 지정 스타일이 중지되어 이 미리보기는 적용되지 않습니다.", + "noticeDisabled": "사용자 지정 CSS가 꺼져 있습니다. 여기서 미리 볼 수는 있지만 켜야 실제로 적용됩니다.", + "hintTokens": "팁: 재정의한 색상은 var(--primary), var(--background) 등으로 참조할 수 있습니다." + } + }, + "zoomLevel": { + "sectionTitle": "창 확대/축소", + "sectionDescription": "전체 인터페이스를 확대하거나 축소합니다. 즉시 적용되며 장치별로 저장됩니다.", + "placeholder": "확대/축소 단계 선택", + "default": "기본값", + "current": "현재 확대/축소: {zoom}%" + }, + "fonts": { + "sectionTitle": "글꼴", + "sectionDescription": "인터페이스, 코드 편집기, 터미널의 글꼴을 각각 선택합니다. 내장 글꼴은 필요할 때 불러옵니다. “사용자 지정…”을 선택하면 시스템에 설치된 모든 글꼴을 사용할 수 있습니다.", + "interface": "인터페이스", + "editor": "편집기", + "terminal": "터미널", + "groupSans": "산세리프", + "groupMono": "고정폭", + "custom": "사용자 지정…", + "customPlaceholder": "글꼴 이름 (예: Fira Code)", + "fontSize": "글꼴 크기", + "ligatures": "합자 사용", + "ligaturesUnavailable": "이 글꼴에는 합자가 없습니다", + "wordWrap": "자동 줄 바꿈 사용", + "terminalLigaturesHint": "터미널 합자는 내장 코딩 글꼴에만 적용됩니다.", + "preview": "미리 보기" + }, + "welcomePanel": { + "sectionTitle": "모드 선택 영역", + "sectionDescription": "새 대화 페이지에서 입력창 위에 표시되는 '코드 개발 / 일상 업무' 바로가기 카드입니다.", + "showQuickActions": "새 대화 페이지에 표시" + }, + "workspaceBackground": { + "sectionTitle": "작업 공간 배경", + "sectionDescription": "작업 공간 전체 뒤에 이미지를 표시합니다. 사이드바와 패널이 반투명 유리 효과로 바뀌어 이미지가 비쳐 보이며, 마스크가 텍스트 가독성을 유지합니다.", + "enable": "배경 이미지 사용", + "image": "이미지", + "chooseImage": "이미지 선택", + "replaceImage": "이미지 변경", + "removeImage": "제거", + "fillMode": "채우기 방식", + "fillModes": { + "cover": "채우기", + "contain": "맞춤", + "center": "가운데", + "tile": "바둑판식" + }, + "maskOpacity": "마스크 불투명도", + "maskOpacityHint": "값이 높을수록 이미지가 테마 배경색으로 흐려져 텍스트 대비가 좋아집니다.", + "imageBlur": "이미지 흐림", + "panelOpacity": "패널 불투명도", + "panelOpacityHint": "사이드바, 패널, 탭 바의 불투명도입니다. 낮을수록 이미지가 더 많이 비쳐 보입니다.", + "errorTooLarge": "이미지가 너무 큽니다(최대 16 MB).", + "errorUploadFailed": "배경 이미지 설정에 실패했습니다." + } + }, + "SystemSettings": { + "loading": "로딩 중...", + "sectionTitle": "시스템 관리", + "sectionDescription": "네트워크 프록시, 앱 업데이트, 언어 설정을 관리합니다.", + "proxyTitle": "네트워크 프록시", + "proxyDescription": "활성화하면 이후 네트워크 요청에서 이 프록시를 우선 사용합니다(ACP 채팅, 에이전트 설치, Git 원격 작업 포함).", + "loadFailed": "불러오기 실패: {message}", + "enableProxy": "시스템 프록시 활성화", + "proxyAddress": "프록시 주소", + "proxyHint": "http(s)/socks5 지원, 예: {example}. 시스템 프록시를 활성화한 경우에만 적용됩니다.", + "save": "저장", + "saving": "저장 중...", + "proxyRequired": "프록시를 활성화하면 프록시 URL이 필요합니다", + "saveSuccess": "시스템 프록시 설정이 저장되었습니다", + "saveFailed": "저장 실패: {message}", + "languageTitle": "언어", + "languageDescription": "앱 언어를 설정합니다. 시스템 언어를 따를 때 지원되지 않는 언어는 영어로 대체됩니다.", + "appLanguage": "앱 언어", + "languageSaveSuccess": "언어 설정이 저장되었습니다", + "languageSaveFailed": "언어 설정 저장 실패: {message}", + "updateTitle": "앱 업데이트", + "versionTitle": "소프트웨어 업데이트", + "updateDescription": "설정된 릴리스 소스에서 새 버전을 확인하고 가능하면 바로 설치합니다.", + "currentVersion": "현재 버전", + "upgradableVersion": "최신 버전", + "none": "없음", + "lastChecked": "마지막 확인: {time}", + "updateError": "업데이트 오류: {message}", + "checking": "확인 중...", + "checkUpdate": "업데이트 확인", + "updating": "설치 중...", + "downloading": "다운로드 중...", + "upgradeTo": "v{version}로 업그레이드", + "viewRelease": "v{version} 릴리스 보기", + "foundUpdate": "새 버전 v{version}을 찾았습니다", + "alreadyLatest": "이미 최신 버전입니다", + "checkUpdateFailed": "업데이트 확인 실패: {message}", + "installSuccess": "업데이트가 설치되었습니다. 앱을 다시 시작합니다.", + "installFailed": "업데이트 실패: {message}", + "upgradeSuccess": "업그레이드가 완료되었습니다. 다시 불러오는 중...", + "restartTimeout": "서버가 제때 복구되지 않았습니다. 컨테이너 또는 서비스 로그를 확인하세요.", + "restartingIn": "{seconds}초 후에 다시 시작합니다...", + "waitingForServer": "서버가 복구되기를 기다리는 중...", + "restartToUpdate": "다시 시작하여 업데이트", + "newVersionBadge": "새 버전 v{version}", + "updateAvailableTitle": "업데이트 있음", + "releaseNotesTitle": "새로운 기능", + "remindLater": "나중에", + "retry": "다시 시도", + "stepDownload": "다운로드", + "stepInstall": "설치", + "stepRestart": "다시 시작", + "updateReadyHint": "업데이트를 다운로드했습니다. 다시 시작하여 적용하세요.", + "restarting": "다시 시작하는 중…", + "dockerUpgradeHint": "지금 실행 중인 컨테이너를 업그레이드합니다. 컨테이너를 다시 만들면 사라집니다. 유지하려면 새 버전 이미지를 가져오거나 빌드한 뒤 컨테이너를 다시 만드세요.", + "upgradeRolledBack": "업그레이드에 실패하여 서버가 이전 버전으로 롤백되었습니다.", + "serverUnreachable": "업그레이드를 시작하기 위해 서버에 연결할 수 없습니다. 서버가 실행 중인지 확인한 후 다시 시도하세요.", + "rollbackButton": "롤백", + "rollingBack": "롤백 중...", + "rollbackDescription": "마지막 업그레이드 이전에 설치된 버전으로 복원합니다.", + "rollbackConfirmTitle": "이전 버전으로 롤백하시겠습니까?", + "rollbackConfirmDescription": "서버가 마지막 업그레이드 이전에 설치된 버전으로 다시 시작됩니다. 최신 릴리스는 다시 설치할 수 있습니다.", + "rollbackConfirm": "롤백", + "rollbackCancel": "취소", + "rollbackSuccess": "이전 버전으로 롤백했습니다. 다시 불러오는 중...", + "rollbackFailed": "롤백에 실패했습니다. 서버 로그를 확인하세요.", + "updateErrors": { + "sourceUnavailable": "업데이트 소스에 연결할 수 없습니다. 네트워크 또는 프록시를 확인한 뒤 다시 시도하세요.", + "network": "네트워크 연결에 실패했습니다. 네트워크 또는 프록시를 확인한 뒤 다시 시도하세요.", + "downloadFailed": "업데이트 패키지 다운로드에 실패했습니다. 잠시 후 다시 시도하세요.", + "installFailed": "업데이트 설치에 실패했습니다. 앱을 종료한 뒤 다시 시도하세요.", + "unknown": "업데이트에 실패했습니다. 잠시 후 다시 시도하세요." + } + }, + "VersionControlSettings": { + "loading": "로딩 중...", + "sectionTitle": "버전 관리", + "sectionDescription": "Git 실행 파일을 설정하고 GitHub 계정을 관리합니다.", + "gitTitle": "Git 설정", + "gitDescription": "애플리케이션에서 사용할 Git 실행 파일을 설정합니다.", + "gitDetected": "Git이 감지되었습니다", + "gitNotFound": "시스템에서 Git을 찾을 수 없습니다", + "gitVersion": "버전", + "gitPath": "경로", + "customGitPath": "사용자 지정 Git 경로", + "customGitPathPlaceholder": "/usr/bin/git", + "customGitPathHint": "비워두면 자동 감지된 경로를 사용합니다.", + "test": "테스트", + "testing": "테스트 중...", + "testSuccess": "Git 실행 파일이 유효합니다.", + "testFailed": "Git 테스트 실패: {message}", + "save": "저장", + "saving": "저장 중...", + "saveSuccess": "Git 설정이 저장되었습니다.", + "saveFailed": "저장 실패: {message}", + "githubTitle": "GitHub 계정", + "githubDescription": "인증용 GitHub 계정을 관리합니다. 토큰은 로컬에 저장됩니다.", + "noAccounts": "설정된 GitHub 계정이 없습니다.", + "addAccount": "계정 추가", + "serverUrl": "서버 URL", + "serverUrlPlaceholder": "https://github.com", + "token": "개인 액세스 토큰", + "tokenPlaceholder": "ghp_xxxxxxxxxxxx", + "generateToken": "토큰 생성", + "tokenHint": "GitHub → Settings → Developer settings → Personal access tokens에서 토큰을 생성하세요.", + "validateAndAdd": "검증 및 추가", + "validating": "검증 중...", + "addSuccess": "계정 {username}이(가) 추가되었습니다.", + "addFailed": "계정 추가 실패: {message}", + "testConnection": "테스트", + "connectionSuccess": "연결 성공.", + "connectionFailed": "연결 실패: {message}", + "setDefault": "기본값으로 설정", + "defaultLabel": "기본", + "defaultSet": "기본 계정이 업데이트되었습니다.", + "removeAccount": "삭제", + "removeConfirmTitle": "계정 삭제", + "removeConfirmMessage": "계정 \"{username}\"을(를) 삭제하시겠습니까?", + "removeConfirm": "삭제", + "removeCancel": "취소", + "removeSuccess": "계정이 삭제되었습니다.", + "scopes": "범위", + "loadFailed": "설정 로드 실패: {message}", + "gitAccount": { + "sectionTitle": "Git 서버 계정", + "sectionDescription": "GitHub 이외의 Git 서버 자격 증명을 관리합니다 (GitLab, Bitbucket, 자체 호스팅 등).", + "noAccounts": "설정된 Git 서버 계정이 없습니다.", + "addAccount": "계정 추가", + "addTitle": "Git 계정 추가", + "addDescription": "서버 주소, 사용자 이름, 비밀번호 또는 액세스 토큰을 입력하세요.", + "serverUrl": "서버 URL", + "serverUrlPlaceholder": "https://gitlab.example.com", + "username": "사용자 이름", + "usernamePlaceholder": "사용자 이름 또는 이메일", + "password": "비밀번호 / 토큰", + "passwordPlaceholder": "비밀번호 또는 액세스 토큰", + "passwordHint": "서버의 비밀번호 또는 액세스 토큰을 입력하세요.", + "add": "추가", + "serverRequired": "서버 URL을 입력하세요.", + "usernameRequired": "사용자 이름을 입력하세요.", + "passwordRequired": "비밀번호를 입력하세요." + } + }, + "ShortcutSettings": { + "sectionTitle": "단축키", + "resetDefault": "기본값으로 재설정", + "recordInstruction": "오른쪽 버튼을 클릭한 다음 키 조합을 누르세요. Ctrl/Cmd, Alt, Shift를 사용할 수 있습니다. Esc를 누르면 기록을 취소합니다.", + "recording": "단축키 입력...", + "toasts": { + "conflict": "단축키가 이미 \"{title}\"에서 사용 중입니다", + "updated": "단축키가 업데이트되었습니다", + "invalid": "유효하지 않은 단축키입니다. 다시 시도하세요", + "reset": "기본 단축키를 복원했습니다" + }, + "actions": { + "toggle_search": { + "title": "검색 열기", + "description": "대화 검색 패널을 표시하거나 숨깁니다" + }, + "toggle_sidebar": { + "title": "왼쪽 사이드바 전환", + "description": "대화 목록 사이드바를 표시하거나 숨깁니다" + }, + "toggle_terminal": { + "title": "터미널 전환", + "description": "하단 터미널 패널을 표시하거나 숨깁니다" + }, + "new_terminal_tab": { + "title": "새 터미널", + "description": "터미널에 포커스가 있을 때 새 터미널 탭을 만듭니다" + }, + "close_current_terminal_tab": { + "title": "현재 터미널 닫기", + "description": "터미널에 포커스가 있을 때 현재 터미널 탭을 닫습니다" + }, + "toggle_aux_panel": { + "title": "오른쪽 패널 전환", + "description": "보조 정보 패널을 표시하거나 숨깁니다" + }, + "new_conversation": { + "title": "새 대화", + "description": "현재 폴더에 새 대화 탭을 만듭니다" + }, + "open_folder": { + "title": "폴더 열기", + "description": "폴더 선택기를 열고 새 창에서 엽니다" + }, + "open_settings": { + "title": "설정 열기", + "description": "설정 창을 엽니다" + }, + "close_current_tab": { + "title": "현재 탭 닫기", + "description": "현재 대화 또는 파일 탭을 닫습니다" + }, + "close_all_file_tabs": { + "title": "모든 파일 탭 닫기", + "description": "파일 패널이 활성 상태일 때 열린 모든 파일 탭을 닫습니다" + }, + "next_tab": { + "title": "다음 탭", + "description": "다음 대화 또는 파일 탭으로 전환" + }, + "prev_tab": { + "title": "이전 탭", + "description": "이전 대화 또는 파일 탭으로 전환" + }, + "send_message": { + "title": "메시지 보내기", + "description": "입력창에서 현재 메시지를 전송" + }, + "newline_in_message": { + "title": "메시지 줄바꿈", + "description": "입력창에 줄바꿈을 삽입" + }, + "toggle_custom_style": { + "title": "사용자 지정 스타일 중지/재개", + "description": "비상 탈출구: 모든 사용자 지정 색상과 CSS를 끄고, 다시 누르면 되돌립니다" + } + } + }, + "SkillsSettings": { + "title": "Skills", + "description": "왼쪽에서 Skill을 선택하세요. 오른쪽은 기본적으로 Markdown 미리보기이며, 편집으로 전환해 수정 후 저장할 수 있습니다.", + "loadingAgents": "Skill을 지원하는 에이전트를 불러오는 중...", + "emptyNoManageableAgents": "Skill을 관리할 수 있는 에이전트가 없습니다.", + "managedTarget": "관리 대상", + "selectAgentPlaceholder": "에이전트 선택", + "searchPlaceholder": "이름 / ID / 경로로 검색...", + "skillsList": "Skill 목록", + "loadingSkills": "Skill 불러오는 중...", + "agentNotSupported": "현재 에이전트는 Skill 관리를 지원하지 않습니다.", + "emptySkills": "아직 Skill이 없습니다. \"새 Skill\"을 클릭해 생성하세요.", + "newSkillTitle": "새 Skill", + "skillInfo": "Skill 정보", + "skillIdPlaceholder": "skill-id(영문/숫자/-/_/.)", + "skillsDirectoryWithPath": "Skill 디렉터리: {path}", + "skillsDirectoryNeedId": "Skill 디렉터리: Skill ID를 입력하면 전체 경로를 생성합니다", + "markdownContent": "Markdown 내용", + "editingStatus": "편집 중", + "previewStatus": "미리보기 중", + "contentPlaceholder": "Skill Markdown 내용을 입력하세요...", + "metadataTitle": "Skill 메타데이터", + "onlyYamlMetadata": "이 Skill에는 YAML 메타데이터만 포함되어 있습니다.", + "emptyContentHint": "아직 내용이 없습니다. \"편집\"을 눌러 시작하세요.", + "loadingSkill": "Skill 불러오는 중...", + "emptyNoAgents": "사용 가능한 에이전트가 없습니다.", + "noSelectionHint": "왼쪽에서 Skill을 선택하거나 \"새 Skill\"을 클릭하여 만드세요.", + "systemBadge": "시스템", + "systemHint": "CLI 내장 Skill · 읽기 전용", + "scope": { + "global": "전역", + "folder": "폴더", + "selectFolderPlaceholder": "폴더 선택", + "noFolders": "폴더를 찾을 수 없습니다", + "pickFolderHint": "Skills을 보려면 폴더를 선택하세요." + }, + "actions": { + "preview": "미리보기", + "edit": "편집", + "openInWindow": "새 창에서 열기", + "delete": "삭제", + "deleting": "삭제 중...", + "refresh": "새로고침", + "newSkill": "새 Skill", + "reset": "초기화", + "save": "저장", + "saving": "저장 중...", + "cancel": "취소" + }, + "deleteDialog": { + "title": "Skill 삭제", + "confirm": "현재 Skill을 삭제하시겠습니까? 이 작업은 되돌릴 수 없습니다.", + "confirmWithNamePrefix": "Skill", + "confirmWithNameSuffix": "을(를) 삭제하시겠습니까? 이 작업은 되돌릴 수 없습니다." + }, + "toasts": { + "loadFailed": "Skill을 불러오지 못했습니다", + "openFolderFailed": "폴더를 열지 못했습니다", + "noSkillDirectory": "현재 에이전트에서 사용할 수 있는 Skill 디렉터리를 찾지 못했습니다", + "nameRequired": "Skill 이름은 비워둘 수 없습니다", + "updated": "Skill이 업데이트되었습니다", + "created": "Skill이 생성되었습니다", + "saveFailed": "Skill 저장에 실패했습니다", + "deleted": "Skill이 삭제되었습니다", + "deleteFailed": "Skill 삭제에 실패했습니다" + }, + "templates": { + "gemini": "---\nname: example-skill\ndescription: Describe when this skill should be used.\n---\n\n# Skill Name\n\nInstructions for the agent when this skill is active.\n\n## Workflow\n\n1. Add actionable step one.\n2. Add actionable step two.\n", + "openCode": "---\nname: example-skill\ndescription: Describe when this skill should be used.\n---\n\n# Purpose\n\nDescribe what this skill helps with.\n\n# Steps\n\n1. Add actionable step one.\n2. Add actionable step two.\n", + "openClaw": "---\nname: example-skill\ndescription: Describe when this skill should be used.\nuser-invocable: true\ndisable-model-invocation: false\n---\n\n# Purpose\n\nDescribe what this skill helps with.\n\n# Instructions\n\n1. Add actionable instruction one.\n2. Add actionable instruction two.\n", + "default": "---\nname: example-skill\ndescription: Describe when this skill should be used.\n---\n\n# Skill: example-skill\n\n## When to use\n\n- Describe trigger conditions.\n\n## Instructions\n\n1. Add actionable instruction one.\n2. Add actionable instruction two.\n" + } + }, + "McpSettings": { + "loading": "로딩 중...", + "summary": { + "missingCommand": "(명령 없음)", + "missingUrl": "(URL 없음)" + }, + "protocol": { + "stdio": "Stdio" + }, + "errors": { + "selectInstallProtocol": "설치 프로토콜을 선택하세요", + "fieldRequired": "{field}은(는) 필수입니다", + "fieldNeedsBoolean": "{field}은(는) true 또는 false여야 합니다", + "fieldNeedsNumber": "{field}은(는) 숫자여야 합니다", + "fieldNeedsInteger": "{field}은(는) 정수여야 합니다", + "fieldInvalidJson": "{field}의 JSON이 잘못되었습니다: {message}", + "fieldOutOfRange": "{field} 값이 허용 범위를 벗어났습니다", + "jsonEmpty": "{name}은(는) 비워둘 수 없습니다", + "jsonInvalid": "{name}은(는) 유효한 JSON이 아닙니다: {message}", + "jsonMustBeObject": "{name}은(는) JSON 객체여야 합니다", + "specMustBeObject": "MCP 구성은 JSON 객체여야 합니다.", + "missingType": "MCP 구성에 type 필드가 없습니다. stdio, http (별칭: streamable-http, streamableHttp), sse 중 하나를 지정하세요.", + "unsupportedType": "지원하지 않는 MCP type {type}. 지원: stdio, http (별칭: streamable-http, streamableHttp), sse.", + "codexEntryUnsupportedType": "Codex MCP 항목 {id}의 type {type}은(는) 지원되지 않습니다. 지원: stdio, http (별칭: streamable-http, streamableHttp), sse.", + "unsupportedTransportType": "지원하지 않는 transport type {type}. 지원: http (별칭: streamable-http, streamableHttp), sse.", + "stdioCommandRequired": "stdio 타입의 MCP에는 비어 있지 않은 command 필드가 필요합니다.", + "remoteUrlRequired": "원격 MCP에는 비어 있지 않은 url 필드가 필요합니다.", + "appsRequired": "대상 앱을 하나 이상 선택하세요." + }, + "jsonNames": { + "localConfig": "MCP 구성", + "installConfig": "설치 구성" + }, + "toasts": { + "uninstalled": "MCP가 제거되었습니다", + "uninstallFailed": "제거 실패: {message}", + "selectAtLeastOneApp": "대상 앱을 최소 하나 선택하세요", + "saveSuccess": "저장됨", + "saveFailed": "저장 실패: {message}", + "installed": "{name} 설치됨", + "installFailed": "설치 실패: {message}", + "serverIdRequired": "Server ID는 필수입니다", + "serverIdExists": "Server ID \"{id}\"이(가) 이미 존재합니다. 기존 항목을 편집하거나 다른 이름을 사용하세요.", + "created": "MCP가 생성되었습니다" + }, + "installDialog": { + "title": "MCP 설치 확인", + "descriptionWithName": "{name}을(를) 로컬 구성에 설치합니다.", + "description": "설치할 대상 앱을 선택하세요.", + "protocol": "프로토콜", + "selectProtocol": "프로토콜 선택", + "parameters": "구성 매개변수", + "booleanPlaceholder": "true/false를 선택하세요", + "selectOneValue": "값 선택", + "targetApps": "대상 앱" + }, + "actions": { + "cancel": "취소", + "confirmInstall": "설치 확인", + "installing": "설치 중", + "uninstall": "제거", + "uninstalling": "제거 중", + "viewDetails": "상세 보기", + "save": "저장", + "saving": "저장 중", + "install": "설치", + "refresh": "새로고침", + "newMcp": "새 MCP", + "create": "생성", + "creating": "생성 중..." + }, + "tabs": { + "local": "로컬 MCP", + "market": "MCP 마켓플레이스" + }, + "local": { + "filterPlaceholder": "로컬 MCP 필터...", + "loadFailed": "로드 실패: {message}", + "empty": "감지된 로컬 MCP가 없습니다.", + "description": "로컬 MCP 구성은 직접 수정하고 저장할 수 있습니다.", + "enabledApps": "활성화된 앱", + "configJson": "MCP 구성 (JSON)", + "draftTitle": "새 MCP", + "draftDescription": "Server ID와 설정을 입력하여 로컬 MCP 서버를 생성합니다.", + "serverIdLabel": "Server ID", + "serverIdPlaceholder": "Server ID (예: my-mcp)", + "typeHint": "지원 타입: stdio, http (별칭: streamable-http, streamableHttp), sse. env는 stdio 전용이며, 원격 MCP는 인증 토큰을 headers로 전달해야 합니다.", + "envOnRemoteWarning": "원격 MCP 설정에 env가 포함되어 있습니다. env는 stdio에서만 사용되며 원격 MCP는 headers로 인증 토큰을 전달합니다. 저장 시 env는 무시됩니다." + }, + "market": { + "selectMarketplace": "마켓플레이스 선택", + "searchPlaceholder": "MCP 검색...", + "searchFailed": "검색 실패: {message}", + "loadingList": "MCP 목록을 불러오는 중...", + "empty": "MCP 검색 결과가 없습니다.", + "loadingDetail": "마켓플레이스 상세 정보를 불러오는 중...", + "detailLoadFailed": "상세 정보를 불러오지 못했습니다: {message}", + "owner": "소유자: {owner}", + "namespace": "네임스페이스: {namespace}", + "defaultInstallProtocol": "기본 설치 프로토콜", + "currentOptionParameterCount": "현재 옵션의 매개변수 수: {count}", + "installConfigDescription": "설치 구성 (JSON, 설치 전에 편집 가능; 편집 내용은 프로토콜/매개변수 폼을 덮어씁니다)", + "selectLeftToView": "상세 정보를 보려면 왼쪽에서 마켓플레이스 MCP를 선택하세요." + }, + "badges": { + "verified": "검증됨", + "remote": "원격", + "hasHomepage": "홈페이지 있음", + "uses": "{count}회 사용", + "deployed": "배포됨", + "notDeployed": "미배포" + }, + "selectLeftMcp": "왼쪽에서 MCP를 선택하세요." + }, + "AcpAgentSettings": { + "title": "Agent SDK 관리", + "description": "Agent SDK 연결, 활성화 상태, 환경 변수, 구성 관리, 버전 사전 점검 정보를 한곳에서 관리합니다.", + "loadingAgents": "에이전트 목록 불러오는 중...", + "agentList": "에이전트 목록", + "emptyNoAgent": "사용 가능한 에이전트가 없습니다.", + "configManagement": "구성 관리", + "envVars": "환경 변수", + "hostTools": { + "label": "파일과 명령을 에이전트가 직접 처리", + "description": "codeg가 파일 접근과 터미널 명령을 대신 처리하지 않고 에이전트가 자체 프로세스에서 실행합니다. 그래야 에이전트 자체의 샌드박스와 권한 규칙이 적용됩니다. 다른 에이전트에 위임하는 기능도 함께 꺼집니다. 같은 작업이 다시 codeg를 거치게 되기 때문입니다. codeg는 자체 샌드박스를 제공하지 않으므로 에이전트에 샌드박스를 구성한 경우에만 켜세요." + }, + "nativeJsonConfig": "네이티브 JSON 구성", + "modelHintDefault": "비워두면 시스템 기본 모델을 사용합니다.", + "generalConfigDescriptionClaude": "API URL, API Key, Claude 모델을 빠르게 설정하고 네이티브 JSON 구성과 동기화합니다.", + "generalConfigDescriptionDefault": "주요 구성 입력(API URL, API Key, Model)과 네이티브 JSON 구성 관리를 지원합니다.", + "multiAgent": { + "title": "다중 에이전트 협업", + "description": "활성 에이전트가 하위 작업을 다른 에이전트에게 위임할 수 있도록 합니다.", + "enable": "위임 사용", + "enableHint": "끄면 delegate_to_agent 도구가 에이전트의 MCP 도구 목록에서 숨겨집니다.", + "withheldByHostTools": "{agents}에는 위임 도구가 제공되지 않습니다. 해당 에이전트의 “파일과 명령을 에이전트가 직접 처리” 스위치가 켜져 있습니다.", + "selfInitiate": "Allow spawn without @", + "selfInitiateHint": "When on, an agent may start a listed sub-agent on its own. An @ mention is still always honored. When off, only an @ mention starts a sub-agent.", + "depthLimit": "최대 위임 깊이", + "depthHint": "허용 범위: {min}–{max}. 위임 체인(루트 → 하위 → 손자 …)의 재귀 깊이를 제한합니다.", + "completedCacheLabel": "완료 결과 캐시(MB)", + "completedCacheHint": "실행 중인 위임 세션이 보관하는 완료된 하위 에이전트 결과의 메모리 내 캐시입니다. 해당 세션이 실행되는 동안에만 유지되며 세션이 종료되면 자동으로 삭제됩니다. 이 예산을 초과하면 오래된 결과부터 메모리에서 삭제됩니다(하위 에이전트 자체 세션에서는 계속 확인 가능). 0은 무제한(세션 종료 시에는 그래도 삭제됨).", + "save": "저장", + "saving": "저장 중…", + "saved": "위임 설정이 저장되었습니다", + "saveFailed": "위임 설정 저장 실패", + "loadFailed": "위임 설정 로드 실패: {detail}", + "tabGeneral": "일반", + "tabAgentDefaults": "하위 에이전트 설정", + "agentDefaultsDescription": "다중 에이전트 협업이 위임 호출을 위해 하위 에이전트를 시작할 때 적용되는 재정의 항목입니다. 아래 옵션은 실시간 프로브로 가져오므로 선택한 항목이 그대로 에이전트에 전달됩니다.", + "probing": "에이전트에서 사용 가능한 옵션을 로드 중…", + "probeFailed": "옵션 로드 실패: {detail}", + "retry": "다시 시도", + "noConfigAvailable": "이 에이전트에는 구성 가능한 옵션이 없습니다.", + "modeLabel": "모드", + "agentDefaultHint": "에이전트 기본값: {value}", + "defaultOptionLabel": "기본값 ({value})" + }, + "actions": { + "dragSort": "드래그하여 순서 변경", + "dragSortAgent": "{name} 순서 변경", + "refreshCheck": "다시 확인", + "refreshCheckAgent": "{name} 다시 확인", + "clickEnable": "{name} 활성화", + "clickDisable": "{name} 비활성화", + "install": "설치", + "upgrade": "업그레이드", + "uninstall": "제거", + "uninstalling": "제거 중...", + "saveEnvVars": "환경 변수 저장", + "saving": "저장 중...", + "saveGrokConfig": "Grok 설정 저장", + "saveCodexConfig": "Codex 설정 저장", + "saveGeminiConfig": "Gemini 설정 저장", + "saveOpenCodeConfig": "OpenCode 설정 저장", + "saveOpenClawConfig": "OpenClaw 설정 저장", + "saveConfigManagement": "구성 관리 저장", + "saveCurrentProvider": "현재 Provider 저장", + "showApiKey": "API 키 보기", + "hideApiKey": "API 키 숨기기", + "showKey": "키 보기", + "hideKey": "키 숨기기", + "showToken": "토큰 보기", + "hideToken": "토큰 숨기기", + "cancel": "취소", + "delete": "삭제", + "deleting": "삭제 중...", + "confirmDelete": "삭제 확인", + "confirmUninstall": "제거 확인", + "saveClineConfig": "Cline 설정 저장", + "saveHermesConfig": "Hermes 설정 저장", + "saveCodeBuddyConfig": "CodeBuddy 구성 저장", + "saveKimiCodeConfig": "Kimi Code 구성 저장", + "customInstall": "사용자 지정 설치", + "saveKimiCodeRawConfig": "Save config.toml", + "saveDeepSeekConfig": "DeepSeek 구성 저장", + "diagnose": "진단" + }, + "status": { + "enabled": "활성화됨", + "disabled": "비활성화됨", + "unchecked": "확인 안 됨", + "agentEnabledAria": "{name} 활성화됨", + "agentEnabledSwitch": "{name} 활성화 스위치" + }, + "preflight": { + "count": "사전 점검 항목: {count}", + "notRun": "점검이 아직 실행되지 않았습니다." + }, + "grok": { + "configDescription": "여기에서 Grok을 설정합니다. 아래 컨트롤(권한 모드, 추론 강도, 선택적 사용자 지정(자체 엔드포인트) 모델, 압축)은 ~/.grok/config.toml에 병합되며 다른 키와 주석은 유지됩니다. 로그인은 XAI_API_KEY 또는 `grok login`을 사용합니다. 기타 키는 '고급'에서 편집할 수 있습니다.", + "permissionModeLabel": "권한 모드", + "permissionDefault": "매번 확인", + "permissionAcceptEdits": "편집 자동 승인", + "permissionAuto": "스마트 자동 승인", + "permissionAlwaysApprove": "항상 허용", + "reasoningEffortLabel": "추론 강도", + "effortLow": "낮음(빠름)", + "effortMedium": "중간(균형)", + "effortHigh": "높음", + "effortXhigh": "최대", + "optionDefault": "기본값 사용", + "authTitle": "인증", + "authMode": "인증 방식", + "authModeApiKey": "XAI API 키", + "authModeApiKeyHint": "xAI 콘솔의 XAI_API_KEY로 인증합니다. 비대화형·헤드리스 실행에 적합하며 이 에이전트의 환경 변수에 저장됩니다.", + "authModeCustom": "사용자 지정 엔드포인트", + "authModeCustomHint": "자체 엔드포인트(BYO)를 사용합니다. 아래에서 자체 base URL과 API 키를 가진 사용자 지정 모델을 정의하면 Grok의 기본 모델이 됩니다.", + "subscriptionHint": "`grok login`으로 로그인합니다(SuperGrok / X Premium+). API 키는 저장되지 않습니다.", + "loginHint": "터미널에서 다음 명령을 실행해 로그인한 뒤 이 설정을 다시 여세요:", + "commandCopied": "명령을 클립보드에 복사했습니다", + "copyCommand": "명령 복사", + "authKeyConfigured": "XAI_API_KEY가 구성되어 있습니다.", + "authKeyMissing": "XAI_API_KEY가 설정되지 않았습니다.", + "advancedToggle": "고급(원본 config.toml)", + "configTomlNative": "config.toml(네이티브)", + "configTomlHint": "~/.grok/config.toml 전체로 그대로 저장됩니다. 잘못된 TOML은 거부되어 오타로 파일이 잘리지 않습니다.", + "configTomlPlaceholder": "# 위 컨트롤 이외의 키, 예:\n# [mcp_servers.*], [cli], [permission] 규칙.", + "customModelTitle": "사용자 지정 모델(자체 엔드포인트)", + "customModelHint": "Grok을 사용자 지정 또는 자체 호스팅 엔드포인트로 연결합니다. codeg는 모델별 `[model.*]` 블록을 작성하고 기본 모델로 설정합니다. 모델 ID를 비우면 제거됩니다.", + "customModelIdLabel": "모델 ID", + "customModelIdPlaceholder": "grok-4.5", + "customModelIdHint": "`[model.*]` 블록으로 등록되어 모델 이름으로 API에 전송되며 `[models].default`로도 설정됩니다.", + "customBaseUrlLabel": "Base URL", + "customBaseUrlPlaceholder": "https://api.x.ai/v1(기본값)", + "customApiBackendLabel": "API 백엔드", + "backendResponses": "Responses", + "backendChatCompletions": "Chat Completions", + "backendMessages": "Messages(Anthropic)", + "customApiKeyLabel": "API 키", + "customApiKeyHint": "`[model.*].api_key`에 인라인으로 저장되며 이 엔드포인트에만 적용됩니다.", + "customContextWindowLabel": "컨텍스트 윈도우(토큰)", + "customContextWindowHint": "선택 사항. 자동 압축 타이밍에 사용됩니다. 비워 두면 엔드포인트 기본값을 사용합니다.", + "autoCompactLabel": "자동 압축 임계값(%)", + "autoCompactHint": "컨텍스트 사용량이 이 비율에 도달하면 대화를 압축합니다(Grok 기본값 85). `[session]`에 기록됩니다." + }, + "cursor": { + "configDescription": "여기에서 Cursor를 설정합니다. 먼저 인증 방식을 선택하세요——공식 구독(브라우저 로그인) 또는 헤드리스/서버용 Cursor API 키——그런 다음 모델을 선택하고 CLI의 권한 규칙과 샌드박스를 편집합니다. codeg는 이를 ~/.cursor/cli-config.json에 기록하며 cursor-agent CLI와 공유합니다.", + "authTitle": "인증", + "authChecking": "확인 중…", + "authNotInstalled": "cursor-agent가 설치되지 않았습니다", + "authLoggedIn": "로그인됨", + "authNotLoggedIn": "로그인되지 않음", + "loginHint": "터미널에서 아래 명령을 실행해 Cursor 계정으로 로그인(브라우저가 열립니다)한 뒤 새로고침을 누르세요:", + "apiKeyLabel": "Cursor API 키", + "apiKeyPlaceholder": "cursor.com/dashboard에서 발급", + "apiKeyHint": "CURSOR_API_KEY —— Cursor 대시보드의 계정 키로, 헤드리스/서버 환경에서 브라우저 로그인 대신 사용합니다. 서드파티나 OpenAI 키가 아닙니다.", + "modelTitle": "기본 모델", + "loadModels": "모델 목록 가져오기", + "modelsUnavailable": "모델 목록을 가져올 수 없음", + "modelHint": "세션 시작 시 --model로 CLI에 전달됩니다. 기본값이면 Cursor가 선택합니다.", + "permissionsTitle": "권한 및 샌드박스", + "permissionsDescription": "CLI 권한 규칙(cli-config.json)의 시각 편집기입니다. 허용 규칙은 확인 없이 실행되고 거부 규칙은 항상 차단됩니다.", + "permissionModeLabel": "권한 모드", + "permissionModeDefault": "실행 전 확인(기본)", + "permissionModeForce": "Run Everything(--force)", + "permissionModeHint": "Run Everything은 --force로 세션을 시작합니다. deny 규칙을 제외한 모든 도구 호출이 확인 없이 자동 허용됩니다(조직 정책에 따라 allow 규칙 일치로 제한될 수 있음). 새 세션부터 적용됩니다.", + "optionDefault": "기본(미설정)", + "sandboxLabel": "샌드박스", + "sandboxEnabled": "사용", + "sandboxDisabled": "사용 안 함", + "allowRulesLabel": "허용 규칙", + "denyRulesLabel": "거부 규칙", + "addRule": "규칙 추가", + "rulesSyntaxHint": "규칙 구문: Shell(명령), Read(경로/글롭), Write(경로/글롭), WebFetch(도메인), Mcp(서버:도구) — deny 규칙이 항상 우선합니다.", + "saveConfig": "설정 저장", + "advancedToggle": "고급: 원본 cli-config.json", + "advancedHint": "~/.cursor/cli-config.json 전체입니다. 여기서 저장하면 그대로 기록되며, 위 구조화 컨트롤은 병합 방식으로 기록됩니다.", + "saveRawConfig": "파일 저장", + "authMode": "인증 방식", + "subscriptionHint": "Cursor 계정으로 로그인하고 Cursor의 모델을 사용합니다.", + "customApiKeyRequired": "Cursor API 키가 필요합니다.", + "authModeApiKey": "Cursor API 키 (헤드리스/서버)", + "authModeApiKeyHint": "Cursor 대시보드에서 발급한 계정 API 키로 인증합니다(헤드리스/서버 환경용). 이는 Cursor 계정 키이며 서드파티/OpenAI 엔드포인트가 아닙니다——cursor-agent는 Cursor 자체 백엔드에만 연결됩니다. codex/OpenAI 호환 엔드포인트를 사용하려면 Codex 에이전트를 대신 사용하세요.", + "modelPickerPlaceholder": "모델 검색…", + "modelNoMatch": "일치하는 모델 없음", + "modelsNeedAuth": "로그인하면 모델 목록을 불러옵니다.", + "modelDefaultBadge": "기본값" + }, + "deepseek": { + "configManagement": "DeepSeek Harness 구성", + "configDescription": "엔드포인트와 API 키는 deepseek-acp가 시작할 때 읽는 환경 변수입니다. 모델과 추론 강도는 세션별 선택기이므로 입력창에서 바꿉니다.", + "baseUrlLabel": "API 엔드포인트", + "baseUrlHint": "비워 두면 공식 엔드포인트를 사용합니다. 저장 후 시작하는 세션부터 적용되며, 실행 중인 세션은 다시 연결해야 반영됩니다.", + "baseUrlInvalid": "쿼리 문자열이 없는 완전한 http(s) URL을 입력하세요. 예: https://api.deepseek.com", + "apiKeyLabel": "API 키", + "apiKeyHint": "DEEPSEEK_API_KEY로 에이전트에 전달됩니다. 환경 변수가 자격 증명 파일보다 우선하므로 터미널로 로그인한다면 비워 두세요." + }, + "codex": { + "configDescription": "API URL, API Key, 모델 이름, reasoning effort를 빠르게 설정하고 `auth.json` / `config.toml`과 동기화합니다.", + "authMode": "인증 방식", + "chatgptSubscription": "공식 구독", + "chatgptSubscriptionHint": "ChatGPT 공식 구독으로 로그인, API Key 불필요", + "apiKeyHint": "API Key로 OpenAI 또는 호환 API 서비스에 연결", + "selectProvider": "Provider 선택", + "modelName": "모델 이름", + "selectReasoningEffort": "Reasoning Effort 선택", + "enableWebsocket": "WebSocket 활성화", + "enableWebsocketAria": "Codex Provider용 WebSocket 활성화", + "enableSkills": "Skills 활성화", + "enableSkillsAria": "Codex용 Skills 활성화", + "enableFast": "Fast 활성화", + "enableFastAria": "Codex용 Fast 서비스 계층 활성화", + "sandboxGroupTitle": "샌드박스 및 승인", + "sandboxGroupHint": "전역 ~/.codex/config.toml에 기록되므로 codex CLI와 IDE 세션에도 적용됩니다. 스레드 기본값이며 codex가 스스로 시작하는 턴(/goal, /review, /compact)에만 적용됩니다. 일반 프롬프트는 입력창의 승인 프리셋을 사용합니다. 변경 사항은 세션을 다시 시작해야 반영됩니다.", + "sandboxShadowedWarning": "config.toml에 default_permissions가 설정되어 있어 codex가 권한 프로필로 해석하고 sandbox_mode를 완전히 무시합니다. 아래 설정을 사용하려면 default_permissions를 제거하세요.", + "sandboxPermissionsTableWarning": "config.toml에 [permissions] 프로필이 있지만 default_permissions가 없어 codex가 시작을 거부합니다. 아래 원본 편집기에서 설정하세요.", + "approvalPolicyLabel": "승인 정책", + "approvalPolicyUnset": "설정 안 함(codex 기본값: 요청 시)", + "approvalPolicy_on-request": "요청 시 — 모델이 확인 시점을 결정", + "approvalPolicy_untrusted": "신뢰 안 함 — 안전이 확인된 읽기 전용 명령만 자동 실행", + "approvalPolicy_never": "묻지 않음 — 승인 창을 전혀 띄우지 않음", + "approvalPolicy_granular": "세부 설정 — 프롬프트 종류별로 지정", + "approvalPolicyUntrustedAcpWarning": "ACP 어댑터의 세 가지 승인 프리셋에는 untrusted에 해당하는 항목이 없으므로 codeg 세션은 \"요청 시\"로 대체됩니다. 이 경우 모델이 물어볼 시점을 스스로 정하며, 샌드박스가 이미 허용한 명령은 더 이상 확인하지 않습니다. 대신 아래 샌드박스 모드로 제한하세요.", + "granularHint": "끄면 해당 종류의 요청은 표시되지 않고 자동으로 거부됩니다.", + "granular_sandbox_approval": "셸 명령 권한 상승", + "granular_rules": "Execpolicy 규칙 프롬프트", + "granular_skill_approval": "스킬 스크립트 프롬프트", + "granular_request_permissions": "request_permissions 도구 프롬프트", + "granular_mcp_elicitations": "MCP elicitation 프롬프트", + "sandboxModeLabel": "샌드박스 모드", + "sandboxModeUnset": "설정 안 함(신뢰된 폴더는 워크스페이스 쓰기로 대체)", + "sandboxMode_read-only": "읽기 전용", + "sandboxMode_workspace-write": "워크스페이스 쓰기", + "sandboxMode_danger-full-access": "전체 접근(샌드박스 없음)", + "sandboxModeHint": "Windows에서는 codex의 실험적 Windows 샌드박스를 켜지 않으면 워크스페이스 쓰기가 읽기 전용으로 낮아집니다.", + "sandboxModeSeedsPresetHint": "codeg는 이 값으로 세션의 초기 승인 프리셋도 정하므로, 승인 정책과 달리 일반 프롬프트에도 적용됩니다. 입력창에서 선택한 프리셋이 이를 덮어씁니다.", + "writableRootsLabel": "추가 쓰기 가능 폴더", + "writableRootsHint": "작업 디렉터리 외에 허용할 절대 경로를 한 줄에 하나씩.", + "sandboxRootsRelativeError": "절대 경로여야 합니다 — codex는 상대 경로를 ~/.codex 기준으로 해석합니다: {path}", + "networkAccessLabel": "네트워크 접근 허용", + "excludeTmpdirLabel": "쓰기 가능 루트에서 TMPDIR 제외", + "excludeSlashTmpLabel": "쓰기 가능 루트에서 /tmp 제외", + "authJsonNative": "auth.json (네이티브)", + "configTomlNative": "config.toml (네이티브)", + "loginButton": "ChatGPT로 로그인", + "loginRequesting": "로그인 코드 요청 중...", + "loginStep1": "브라우저에서 다음 URL을 열어주세요:", + "loginStep2": "아래 코드를 입력하세요:", + "loginPolling": "인증 대기 중...", + "loginCancel": "취소", + "loginSuccess": "로그인 성공, 설정이 저장되었습니다!", + "loginFailed": "로그인 실패: {message}", + "loginRetry": "재시도", + "loginCodeCopied": "코드가 복사되었습니다", + "loggedIn": "계정 로그인됨", + "loginRelogin": "재로그인 / 계정 전환", + "loginTimeout": "로그인 시간 초과, 다시 시도해 주세요", + "loginSaveFailed": "로그인 성공했지만 설정 저장 실패" + }, + "gemini": { + "authConfig": "Gemini 인증 설정", + "authConfigDescription": "Gemini CLI 인증 문서와 정렬되며, 커스텀 엔드포인트, Google 로그인, Gemini API Key, Vertex AI(ADC / 서비스 계정 / API Key)를 지원합니다.", + "authMode": "인증 모드", + "selectAuthMode": "인증 모드 선택", + "viewAuthDoc": "인증 문서 보기", + "mode": { + "custom": "커스텀 엔드포인트", + "loginGoogle": "Google 로그인 (OAuth)", + "vertexServiceAccount": "Vertex AI (서비스 계정)" + }, + "hint": { + "custom": "API URL, API Key, Model을 입력하세요. GOOGLE_GEMINI_BASE_URL / GEMINI_API_KEY / GEMINI_MODEL에 매핑됩니다.", + "loginGoogle": "먼저 터미널에서 gemini를 실행해 Google 로그인을 완료하세요. API key는 필요하지 않습니다.", + "geminiApiKey": "Gemini API 사용 시 GEMINI_API_KEY를 입력하세요.", + "vertexAdc": "gcloud ADC를 사용합니다. GOOGLE_CLOUD_PROJECT와 GOOGLE_CLOUD_LOCATION 설정을 권장합니다.", + "vertexServiceAccount": "서비스 계정 JSON 경로를 GOOGLE_APPLICATION_CREDENTIALS에 설정하세요.", + "vertexApiKey": "Vertex AI API key 사용 시 GOOGLE_API_KEY를 입력하세요." + } + }, + "openCode": { + "configManagement": "OpenCode 구성 관리", + "configDescription": "OpenCode `provider` 스키마에 맞추어 다중 Provider 관리와 네이티브 JSON 파일 양방향 동기화를 지원합니다.", + "providerManagement": "Provider 관리", + "providerCount": "Provider {count}개", + "addProvider": "Provider 추가", + "emptyProvider": "아직 사용자 지정 공급자가 없습니다. '사용자 지정 공급자 추가'를 클릭해 만드세요.", + "providerEnabledState": "{providerId} 활성 상태", + "selectProviderNpm": "provider.npm 선택", + "modelManagement": "모델 관리", + "modelCount": "모델 {count}개", + "modelDescription": "OpenCode `provider.models`와 정렬됩니다. 빠른 관리는 현재 `name` / `id`를 지원하며, 기타 고급 필드는 유지되고 아래 네이티브 JSON에서 편집할 수 있습니다.", + "addModel": "모델 추가", + "emptyModel": "아직 모델이 없습니다. model id를 입력한 뒤 \"모델 추가\"를 클릭하세요.", + "modelId": "모델 ID", + "modelName": "모델 이름", + "deleteModel": "모델 {modelId} 삭제", + "nativeJsonConfig": "OpenCode 네이티브 JSON 구성", + "mainModel": "메인 모델", + "smallModel": "스몰 모델", + "noMatchingModels": "일치하는 모델 없음", + "connectProvider": "공급자 연결", + "connectedProviders": "연결된 공급자", + "noConnectedProviders": "아직 카탈로그 공급자를 연결하지 않았습니다.", + "advancedProviderConfig": "사용자 지정 공급자", + "customProviderConfigHint": "직접 정의하는 OpenAI 호환 엔드포인트입니다 — opencode.json의 provider 블록이며 API 키는 auth.json에 저장됩니다.", + "addCustomProvider": "사용자 지정 공급자 추가", + "disconnect": "연결 해제", + "editConfig": "편집", + "customBadge": "사용자 지정", + "authKindApi": "API 키", + "authKindOauth": "OAuth", + "authKindNone": "자격 증명 없음", + "connect": { + "title": "공급자 연결", + "description": "models.dev 카탈로그에서 공급자를 선택하세요. 자격 증명은 OpenCode의 auth.json 파일에 저장됩니다.", + "pick": "공급자", + "search": "공급자 검색…", + "loading": "카탈로그 불러오는 중…", + "catalogLabel": "models.dev 카탈로그", + "modelsAvailable": "{count}개 모델 사용 가능", + "getKey": "API 키 받기", + "oauthApiKeyNote": "이 공급자는 opencode auth login을 통한 브라우저 로그인도 지원합니다. 브라우저 로그인은 곧 제공됩니다. 지금은 API 키를 붙여넣으세요.", + "apiKey": "API 키", + "apiKeyHint": "auth.json에 저장되며 opencode.json에는 저장되지 않습니다.", + "baseUrlOptional": "Base URL 재정의 (선택)", + "providerId": "공급자 ID", + "displayName": "표시 이름", + "modelsList": "모델 (한 줄에 하나)", + "modelsHint": "엔드포인트가 허용하는 모델 ID.", + "action": "연결", + "editTitle": "공급자 편집", + "editDescription": "이 공급자의 API 키 또는 Base URL을 업데이트합니다.", + "saveAction": "저장" + }, + "customProvider": { + "title": "사용자 지정 공급자 추가", + "description": "OpenAI 호환 엔드포인트를 정의합니다. API 키는 auth.json에, provider 블록은 opencode.json에 저장됩니다.", + "action": "공급자 추가", + "idInCatalog": "{providerId}은(는) 알려진 공급자입니다. 대신 '공급자 연결'로 연결하세요." + }, + "refreshCatalog": "카탈로그 새로고침", + "reasoningBadge": "추론", + "contextWindow": "컨텍스트 윈도우", + "permissions": { + "title": "권한", + "description": "어떤 작업을 바로 실행할지, 먼저 확인할지, 차단할지 정합니다. opencode.json 의 permission 설정에 기록되며 아래에서 저장하면 적용됩니다.", + "docsLink": "권한 문서", + "unparsableConfig": "아래 네이티브 JSON 을 해석할 수 없어 시각적 편집을 멈췄습니다. JSON 을 고치면 다시 사용할 수 있습니다.", + "invalidBlock": "permission 설정의 형태를 인식할 수 없습니다. 아래 네이티브 JSON 에서 수정하거나 [초기화] 로 다시 시작하세요.", + "orderingUnsafe": "와일드카드 규칙이 개별 도구보다 뒤에 적혀 있어 OpenCode 가 그 도구들에도 적용합니다. 아래 행은 실제로 적용되는 값이 아닙니다. [순서 수정] 은 값을 바꾸지 않고 와일드카드를 각 범위 맨 앞으로 되돌립니다.", + "orderingUnsafeManual": "어떤 규칙이 뒤의 더 넓은 패턴에 가려져 OpenCode 가 절대 적용하지 않습니다. 아래 행은 실제로 적용되는 값이 아닙니다. 겹치는 두 패턴에는 정답인 순서가 없으므로, 아래 네이티브 JSON 에서 더 넓은 쪽을 앞으로 옮기세요.", + "fixOrder": "순서 수정", + "agentOverrides": "다음 에이전트가 권한을 재정의하며 마지막에 적용되므로 여기 설정보다 우선합니다: {agents}. 아래 네이티브 JSON 에서 수정하거나 자동 수락을 켜서 지우세요.", + "legacyTools": "최상위 레거시 tools 설정이 어떤 도구를 거부하고 있습니다. OpenCode 가 이를 권한에 합치므로 여기 표시된 모든 설정 위에 적용됩니다. 아래 네이티브 JSON 에서 수정하거나 자동 수락을 켜서 지우세요.", + "autoAcceptTitle": "모든 권한 자동 수락", + "autoAcceptHint": "셸 명령, 파일 수정, 프로젝트 밖 경로를 포함한 모든 도구 호출을 묻지 않고 실행합니다. 켜면 아래 도구별 설정이 전체 허용 규칙 하나로 대체되고, 그대로 두면 계속 막을 에이전트별 권한 재정의와 레거시 tools 설정도 지워집니다.", + "globalLabel": "전역 기본값", + "globalHint": "* 규칙입니다. 아래 도구에서 따로 지정하지 않은 모든 경우에 적용됩니다.", + "actionUnset": "설정 안 함 (OpenCode 기본값)", + "actionInherit": "기본값 따름 ({action})", + "actionAllow": "허용", + "actionAsk": "확인", + "actionDeny": "거부", + "perToolTitle": "도구별 권한", + "reset": "초기화", + "ruleCount": "규칙: {count}", + "rulesToggle": "{tool} 의 세부 규칙", + "rulesHint": "도구 입력과 대조하며 마지막으로 일치한 규칙이 우선하므로 넓은 패턴을 먼저 적으세요. * 는 임의의 문자열, ? 는 정확히 한 글자와 일치하고 맨 앞의 ~ 는 홈 디렉터리로 확장됩니다.", + "noRules": "아직 세부 규칙이 없습니다.", + "addRule": "규칙 추가", + "deleteRule": "규칙 {pattern} 삭제", + "duplicateRule": "이미 있는 패턴입니다.", + "blankRule": "규칙에는 패턴이 필요합니다. 삭제하려면 휴지통 아이콘을 사용하세요.", + "customKeys": "파일에 있는 다른 권한 키", + "customKeyHint": "OpenCode 기본 도구가 아니며 작성된 그대로 유지됩니다.", + "keys": { + "bash": "셸 명령 실행, 파싱된 명령으로 대조", + "edit": "모든 파일 수정: edit, write, patch", + "read": "파일 읽기, 경로로 대조", + "external_directory": "프로젝트 작업 디렉터리 밖 경로 접근", + "task": "서브에이전트 실행, 서브에이전트 유형으로 대조", + "skill": "스킬 로드, 스킬 이름으로 대조", + "glob": "파일 찾기, 글로브 패턴으로 대조", + "grep": "파일 내용 검색, 패턴으로 대조", + "list": "디렉터리 내용 나열", + "webfetch": "URL 가져오기", + "websearch": "웹 검색", + "lsp": "LSP 질의 실행", + "todowrite": "할 일 목록 작성", + "question": "사용자에게 질문", + "doom_loop": "같은 호출이 같은 입력으로 3 번 반복되면 작동" + } + } + }, + "openClaw": { + "gatewayConfig": "Gateway 구성", + "gatewayDescription": "OpenClaw Gateway 연결을 구성합니다. 로컬 또는 원격 gateway를 지원합니다.", + "gatewayUrlHint": "비워두면 로컬 openclaw 설정의 gateway.remote.url을 사용합니다.", + "gatewayTokenPlaceholder": "Gateway 인증 토큰", + "gatewayTokenHint": "가능하면 평문 토큰 대신 token-file을 사용하세요. openclaw CLI로 설정하세요.", + "sessionKeyHint": "선택 사항입니다. gateway 세션 키를 지정합니다. 비워두면 격리된 세션이 자동 할당됩니다." + }, + "hermes": { + "configManagement": "Hermes 구성", + "configDescription": "Hermes는 자격 증명을 ~/.hermes/.env에, 설정을 ~/.hermes/config.yaml에 직접 관리합니다. 공급자를 선택한 다음 API 키와 모델을 설정하세요. codeg가 두 파일을 모두 작성해 줍니다.", + "providerLabel": "공급자", + "providerHint": "공급자에 따라 Hermes가 사용하는 API 키 변수와 model.provider가 결정됩니다. OAuth 공급자는 아래 터미널 설정을 통해 구성합니다.", + "groupApiKey": "API 키 제공자", + "groupOauth": "OAuth 제공자", + "groupAws": "AWS", + "apiKeyHint": "~/.hermes/.env에 저장됩니다. 프로세스에 절대 주입되지 않으며, Hermes가 자체 구성에서 읽어옵니다.", + "modelName": "모델", + "oauthHint": "이 공급자는 OAuth를 사용합니다. 아래 설정을 실행하여 터미널에서 인증하세요.", + "awsHint": "Bedrock은 AWS 자격 증명(환경 변수 또는 공유 구성)을 사용합니다. 위에서 모델 ID를 설정하고 환경에서 AWS 액세스를 구성하세요.", + "unsupportedProvider": "이 제공자는 구조화된 필드로 편집할 수 없습니다. 아래의 config.yaml 원본 편집기나 터미널 설정을 사용하세요.", + "setupTitle": "자체 관리 설정", + "setupHint": "Hermes의 대화형 설정에는 터미널이 필요합니다. 아래에서 실행하거나 명령을 복사하여 직접 실행하세요.", + "runSetup": "Hermes 설정 실행", + "configureModel": "모델 구성", + "openConfigFolder": "~/.hermes 열기", + "copyCommand": "명령 복사", + "commandCopied": "명령을 클립보드에 복사했습니다", + "advancedTitle": "고급: config.yaml 편집", + "rawConfigHint": "~/.hermes/config.yaml을 직접 편집합니다. 여기서 저장하면 파일이 그대로 덮어쓰여집니다.", + "saveRawConfig": "config.yaml 저장" + }, + "codebuddy": { + "configManagement": "CodeBuddy 구성", + "configDescription": "CodeBuddy는 API 키로 인증합니다. 중국 버전은 환경을 ‘중국(internal)’으로 설정해야 하며, iOA 버전은 ‘iOA’를 사용하고, 해외 버전은 설정하지 않습니다.", + "apiKeyLabel": "API 키", + "apiKeyHint": "이 에이전트의 CODEBUDDY_API_KEY로 저장됩니다. 또는 터미널에서 CodeBuddy CLI로 로그인할 수도 있습니다.", + "apiKeyHintSelfHosted": "이 에이전트의 CODEBUDDY_API_KEY로 저장됩니다. 비공개 배포에서 발급한 키를 사용하세요.", + "environmentLabel": "환경", + "environmentHint": "CODEBUDDY_INTERNET_ENVIRONMENT를 설정합니다. 중국 본토는 ‘중국(internal)’을 사용해야 하며, 해외 버전은 설정하지 않습니다.", + "envOverseas": "해외(기본값)", + "envChina": "중국(internal)", + "envIoa": "iOA", + "envSelfHosted": "프라이빗 배포(자체 호스팅)", + "baseUrlLabel": "배포 URL", + "baseUrlPlaceholder": "https://codebuddy.your-company.com", + "baseUrlHint": "CODEBUDDY_BASE_URL로 저장되어 CodeBuddy를 비공개 엔드포인트로 연결합니다. 자체 호스팅에서는 네트워크 환경(CODEBUDDY_INTERNET_ENVIRONMENT)을 설정하지 않습니다.", + "baseUrlInvalid": "유효한 http(s) URL을 입력하세요.", + "loginHint": "API 키가 없나요? 터미널에서 ‘codebuddy’를 실행하여 Tencent 계정으로 로그인할 수도 있습니다." + }, + "kimiCode": { + "configManagement": "Kimi Code 설정", + "configDescription": "`kimi acp`는 저장된 로그인 토큰만 인정하므로, codeg가 ~/.kimi-code/config.toml에 관리형 공급자를 기록하고 로컬에 게이트 토큰을 심습니다. 추론은 여전히 사용자의 키로 실행됩니다.", + "statusUnconfigured": "아직 설정되지 않음", + "statusDirty": "저장되지 않은 변경 사항", + "summaryLabel": "적용된 설정", + "gateReadyApiKey": "API 키가 config.toml에 기록됨", + "gateReadyLogin": "Kimi 계정으로 로그인됨", + "revealConfig": "폴더에서 보기", + "envOverrideWarning": "{keys}이(가) 설정되어 있으며 config.toml보다 우선합니다. 여기서 저장하면 자동으로 삭제됩니다.", + "authModeLabel": "인증 방식", + "authModeApiKey": "API 키", + "authModeLogin": "Kimi 계정 로그인(구독)", + "authModeApiKeyHint": "config.toml에 관리형 공급자를 기록하고, 세션이 열리도록 게이트 토큰을 심습니다.", + "loginHint": "터미널에서 `kimi login`을 실행해 Kimi 구독 계정으로 로그인하세요. codeg는 자격 증명을 저장하지 않고 Kimi 자체 로그인을 재사용합니다. 여기서 저장하면 codeg의 API 키 게이트 토큰이 제거됩니다.", + "credentialTitle": "자격 증명", + "interfaceTypeLabel": "공급자 유형", + "interfaceTypeHint": "Kimi가 사용하는 공급자 프로토콜(config.toml의 `type`). Moonshot / platform.kimi.com 키라면 「Kimi / Moonshot」을 선택하세요.", + "endpointLabel": "엔드포인트", + "endpointCustom": "사용자 지정(OpenAI 호환)", + "endpointHint": "국제 = api.moonshot.ai, 중국(platform.kimi.com 키) = api.moonshot.cn. 사용자 지정은 모든 OpenAI 호환 엔드포인트를 가리킬 수 있습니다.", + "regionInternational": "국제(api.moonshot.ai)", + "regionChina": "중국(api.moonshot.cn)", + "baseUrlLabel": "Base URL", + "baseUrlHint": "비워 두면 공급자 SDK 기본값을 사용합니다.", + "apiKeyLabel": "API 키", + "apiKeyHint": "~/.kimi-code/config.toml에 기록되어 추론에 사용됩니다. platform.kimi.com 또는 platform.kimi.ai에서 발급받습니다.", + "vertexProjectLabel": "GCP 프로젝트(GOOGLE_CLOUD_PROJECT)", + "vertexLocationLabel": "GCP 리전(GOOGLE_CLOUD_LOCATION)", + "vertexHint": "Vertex AI는 Google 애플리케이션 기본 자격 증명을 사용합니다. `gcloud auth application-default login`을 실행하세요(API 키 불필요).", + "modelTitle": "모델", + "modelLabel": "모델", + "modelHint": "config.toml에 기록되는 모델 id입니다. 「테스트 후 모델 가져오기」로 키가 실제로 접근 가능한 모델을 확인하세요.", + "maxContextLabel": "최대 컨텍스트 길이", + "maxContextHint": "Kimi 스키마에서 필수입니다. 값이 없으면 Kimi가 모델 블록 전체를 버려 모든 프롬프트가 응답 없이 끝납니다. 기본값은 262144입니다.", + "fetchModels": "테스트 후 모델 가져오기", + "fetchModelsOk": "키 정상 — 모델 {count}개 사용 가능", + "fetchModelsEmpty": "키는 정상이지만 반환된 모델이 없습니다", + "fetchModelsFailed": "테스트 실패", + "fetchModelsNeedsKey": "먼저 API 키와 엔드포인트를 입력하세요", + "modelNotInList": "이 모델은 키가 접근할 수 있는 목록에 없습니다. Kimi가 「모델을 찾을 수 없음」으로 실패합니다.", + "reasoningTitle": "추론", + "reasoningEnableLabel": "사용", + "reasoningDescription": "모델이 추론 기능을 선언한 경우에만 Kimi가 입력창에 「Thinking」선택기를 표시하므로, codeg가 여기서 그 선언을 기록합니다. 새 세션부터 적용됩니다.", + "effortsLabel": "제공할 단계", + "effortsHint": "여기서 고른 값이 입력창 「Thinking」선택기의 항목이 됩니다. Kimi는 단계를 공급자에게 그대로 전달하므로 모델이 받아들이는 값을 고르세요.", + "effortsEmptyHint": "단계를 하나도 고르지 않으면 입력창은 Off / On 2단 토글로 축소됩니다.", + "effortsCustomPlaceholder": "다른 단계 추가", + "effortsAdd": "추가", + "defaultEffortLabel": "기본 단계", + "defaultEffortAuto": "Kimi에 맡기기", + "alwaysThinkingLabel": "모델이 항상 추론함 — 선택기에서 Off 항목 제거", + "fixErrorsFirst": "먼저 표시된 항목을 수정하세요", + "errorModelRequired": "모델은 필수 항목입니다", + "errorMaxContextRequired": "최대 컨텍스트 길이는 필수 항목입니다", + "errorMaxContextInvalid": "양의 정수여야 합니다", + "errorApiKeyRequired": "API 키는 필수 항목입니다", + "errorApiKeyInvalid": "API 키에는 줄바꿈을 포함할 수 없습니다", + "errorBaseUrlRequired": "Base URL은 필수 항목입니다", + "errorBaseUrlInvalid": "http:// 또는 https://로 시작해야 합니다", + "errorVertexProjectRequired": "GCP 프로젝트는 필수 항목입니다", + "errorDefaultEffortUnlisted": "위에서 선택한 단계 중 하나여야 합니다", + "advancedTitle": "고급", + "authTypeLabel": "자격 증명 기록 위치", + "authTypeApiKey": "인라인 api_key", + "authTypeEnv": "공급자 env 하위 테이블", + "authTypeHint": "config.toml 안에서 API 키를 기록할 위치입니다.", + "rawEditorLabel": "config.toml 직접 편집", + "rawEditorWarning": "여기서 저장하면 파일 전체가 그대로 덮어써져 위의 구조화된 설정이 대체됩니다.", + "rawEditorPlaceholder": "[providers.codeg]\ntype = \"kimi\"\nbase_url = \"https://api.moonshot.cn/v1\"\napi_key = \"sk-...\"" + }, + "authModeOfficialSubscription": "공식 구독", + "authModeCustomEndpoint": "사용자 정의 엔드포인트", + "authModeCustomEndpointHint": "API URL과 API Key를 수동으로 구성하여 사용자 정의 엔드포인트에 연결합니다.", + "authModeModelProvider": "모델 공급자", + "modelProvider": "모델 공급자", + "modelProviderHint": "구성된 모델 공급자의 API URL, API Key 및 모델을 사용합니다.", + "selectModelProvider": "모델 공급자 선택", + "noModelProviderAvailable": "이 에이전트에 구성된 모델 공급자가 없습니다. 모델 공급자 설정에서 추가하세요.", + "claude": { + "authMode": "인증 방식", + "officialSubscription": "공식 구독", + "officialSubscriptionHint": "Anthropic 공식 구독 사용, API Key 불필요.", + "mainModel": "메인 모델", + "reasoningModel": "추론 모델 (thinking)", + "haikuDefaultModel": "기본 Haiku 모델", + "sonnetDefaultModel": "기본 Sonnet 모델", + "opusDefaultModel": "기본 Opus 모델", + "customModelOption": "사용자 지정 모델 ID", + "customModelOptionName": "사용자 지정 모델 이름", + "customModelOptionDescription": "사용자 지정 모델 설명", + "customModelOptionHint": "Claude 모델 선택기에 사용자 지정 항목 하나를 추가합니다(예: 사용자 지정 게이트웨이/프록시를 통해 제공되는 모델). 이름과 설명은 선택적 표시 설정입니다.", + "effortLevel": "추론 수준", + "effortLevelDefault": "기본 수준", + "effortLevel_low": "낮음", + "effortLevel_medium": "중간", + "effortLevel_high": "높음", + "effortLevel_xhigh": "매우 높음", + "sendAttributionHeader": "API에 속성/청구 식별자 전송", + "sendAttributionHeaderAria": "API에 Claude Code 속성/청구 식별자 전송", + "disableNonessentialTraffic": "텔레메트리 또는 불필요한 네트워크 요청 비활성화", + "disableNonessentialTrafficAria": "Claude Code 텔레메트리 또는 불필요한 네트워크 요청 비활성화" + }, + "dialogs": { + "confirmDeleteProvider": "Provider {providerId}를 삭제하시겠습니까?", + "confirmDeleteProviderDescription": "OpenCode config와 auth JSON이 함께 업데이트됩니다. 이 작업은 되돌릴 수 없습니다.", + "confirmUninstall": "{name}을(를) 제거하시겠습니까?", + "confirmUninstallDescription": "로컬 설치 버전을 제거합니다. 나중에 다시 설치할 수 있습니다.", + "customInstallTitle": "{name} 사용자 지정 설치", + "customInstallDescription": "설치할 버전을 입력하세요. 다시 설치되며 현재 설치된 버전을 대체합니다.", + "customInstallVersionLabel": "버전 번호", + "customInstallInvalid": "유효한 버전 번호를 입력하세요. 예: 1.2.3", + "customInstallSubmit": "설치" + }, + "errors": { + "windowsFileLocked": "{name}의 파일이 실행 중인 세션에서 사용 중이어서 Windows에서 교체할 수 없습니다. 모든 {name} 세션을 닫은 후 다시 시도하세요.", + "nativeJsonMustBeObject": "네이티브 JSON 구성은 객체여야 합니다", + "nativeJsonInvalid": "네이티브 JSON 구성 형식 오류: {message}", + "openCodeAuthMustBeObject": "OpenCode auth.json은 JSON 객체여야 합니다", + "openCodeAuthInvalid": "OpenCode auth.json 형식 오류: {message}", + "authMustBeObject": "auth.json은 JSON 객체여야 합니다", + "authInvalid": "auth.json 형식 오류: {message}", + "providerIdPattern": "Provider ID는 문자, 숫자, 밑줄, 점, 하이픈만 지원합니다", + "providerExists": "Provider {providerId}가 이미 존재합니다", + "modelIdPattern": "Model ID는 문자, 숫자, 밑줄, 점, 콜론, 하이픈만 지원합니다", + "modelExists": "Model {modelId}가 이미 존재합니다" + }, + "warnings": { + "nativeJsonRecoveredStructured": "네이티브 JSON 구성이 잘못되어 구조화 구성으로 재설정했습니다", + "nativeJsonRecoveredOpenCode": "네이티브 JSON 구성이 잘못되어 OpenCode 구조화 구성으로 재설정했습니다", + "openCodeAuthRecovered": "OpenCode auth.json이 잘못되어 기본 구성으로 재설정했습니다", + "authRecoveredStructured": "auth.json이 잘못되어 구조화 구성으로 재설정했습니다" + }, + "toasts": { + "agentActionCompleted": "{name} {action} 완료", + "agentActionFailed": "{name} {action} 실패", + "localVersion": "로컬 버전: {version}", + "installCompletedVersionLater": "설치가 완료되었습니다. 버전은 다음 확인 시 업데이트됩니다", + "uninstallCompleted": "{name} 제거 완료", + "uninstallFailed": "{name} 제거 실패", + "localVersionRemoved": "로컬 버전이 제거되었습니다", + "saveAgentOrderFailed": "Agent 순서 저장 실패", + "saveAgentSwitchFailed": "Agent 스위치 저장 실패", + "saveEnvFailed": "환경 변수 저장 실패", + "grokSaved": "Grok 설정이 저장됨", + "saveGrokNativeFailed": "Grok 네이티브 설정 저장 실패", + "saveGrokApiKeyFailed": "설정은 저장되었지만 API 키를 저장하지 못했습니다", + "cursorSaved": "Cursor 설정이 저장되었습니다", + "saveCursorConfigFailed": "Cursor 설정 저장 실패", + "codexSaved": "Codex 설정 저장됨", + "saveCodexNativeFailed": "Codex 네이티브 구성 저장 실패", + "geminiSaved": "Gemini 설정 저장됨", + "saveGeminiFailed": "Gemini 설정 저장 실패", + "providerDeleted": "Provider {providerId} 삭제됨", + "providerDeleteFailed": "Provider {providerId} 삭제 실패", + "providerSaved": "Provider {providerId} 저장됨", + "saveProviderFailed": "Provider {providerId} 저장 실패", + "openCodeConfigSynced": "OpenCode config와 auth JSON이 동기화되었습니다.", + "openCodeSaved": "OpenCode 설정 저장됨", + "saveOpenCodeFailed": "OpenCode 설정 저장 실패", + "openClawSaved": "OpenClaw 설정 저장됨", + "saveOpenClawFailed": "OpenClaw 설정 저장 실패", + "configSaved": "구성이 저장되었습니다", + "configSavedHint": "기존 세션은 다시 열어야 적용됩니다", + "saveConfigManagementFailed": "구성 관리 저장 실패", + "clineSaved": "Cline 설정 저장됨", + "saveClineFailed": "Cline 설정 저장 실패", + "hermesSaved": "Hermes 설정 저장됨", + "saveHermesFailed": "Hermes 설정 저장 실패", + "codeBuddySaved": "CodeBuddy 구성이 저장되었습니다", + "saveCodeBuddyFailed": "CodeBuddy 구성 저장에 실패했습니다", + "kimiCodeSaved": "Kimi Code 구성이 저장되었습니다", + "saveKimiCodeFailed": "Kimi Code 구성 저장 실패", + "deepseekSaved": "DeepSeek 구성을 저장했습니다", + "saveDeepSeekFailed": "DeepSeek 구성 저장 실패", + "modelProviderRequired": "저장하기 전에 모델 공급자를 선택하세요.", + "affectedRunningSessions": "{count}개의 실행 중인 세션은 다시 연결하면 변경 사항이 적용됩니다", + "providerConnected": "{providerId} 연결됨", + "connectFailed": "{providerId} 연결 실패", + "providerDisconnected": "{providerId} 연결 해제됨", + "disconnectFailed": "{providerId} 연결 해제 실패", + "catalogRefreshed": "카탈로그를 새로고침했습니다 — 공급자 {count}개", + "catalogRefreshFailed": "카탈로그 새로고침 실패", + "piSaved": "Pi 설정이 저장됨", + "savePiFailed": "Pi 설정 저장 실패", + "piRuntimeSaved": "Pi 런타임이 저장됨", + "savePiRuntimeFailed": "Pi 런타임 저장 실패", + "piBinaryInstalled": "pi 설치됨", + "piBinaryInstallFailed": "pi 설치 실패", + "piBinaryUninstalled": "pi 제거됨", + "piBinaryUninstallFailed": "pi 제거 실패", + "savePiTrustFailed": "작업 공간 신뢰 저장 실패" + }, + "version": { + "statusLabel": "버전 상태", + "notInstalled": "설치되지 않음", + "remoteLocal": "원격: {remoteVersion} · 로컬: {localVersion}", + "localOnly": "로컬: {localVersion}", + "localInstalled": "{versionText}. 설치되어 있습니다.", + "platformUnsupported": "{versionText}. 현재 플랫폼에서는 이 에이전트를 지원하지 않습니다.", + "uvxNotReady": "{versionText}. uv 런타임이 설치되지 않았습니다. 아래 uv 검사에서 설치하면 이 에이전트를 사용할 수 있습니다.", + "clickInstall": "{versionText}. 오른쪽의 설치를 클릭하세요.", + "localUnrecognized": "{versionText}. 로컬 버전을 비교할 수 없습니다. 덮어쓰기 설치를 위해 업그레이드를 시도하세요.", + "upgradeAvailable": "{versionText}. 업그레이드가 가능합니다.", + "remoteUnavailable": "{versionText}. 현재 원격 버전을 사용할 수 없습니다.", + "latest": "{versionText}. 이미 최신입니다." + }, + "adapter": { + "label": "ACP 어댑터", + "badge": "ACP 어댑터", + "badgeHint": "이 에이전트에 대해 Codeg가 설치하는 것은 벤더 CLI가 아니라 ACP 어댑터 패키지입니다. 둘은 서로 독립적이며 설정을 공유합니다.", + "learnMore": "자세히 보기", + "missingWithNative": "사용 중인 {nativeLabel}을(를) {nativePath}에서 찾았습니다. Codeg는 에이전트를 ACP로 구동하는데 이 CLI 자체는 ACP를 지원하지 않으므로, 별도의 어댑터 패키지 {adapterPackage}(Agent Client Protocol 프로젝트가 관리, 처음에는 Zed 팀)가 필요합니다. 자체 런타임을 포함하고 있어 기존 {nativeCmd} 명령을 수정하거나 대체하지 않으며, 같은 {configDir}를 읽으므로 기존 로그인과 설정이 그대로 적용됩니다. 아래에서 설치하세요.", + "missing": "Codeg는 에이전트를 ACP로 구동하는데 {nativeLabel} 자체는 ACP를 지원하지 않으므로, 별도의 어댑터 패키지 {adapterPackage}(Agent Client Protocol 프로젝트가 관리, 처음에는 Zed 팀)가 필요합니다. 자체 런타임을 포함하므로 {nativeCmd} CLI를 먼저 설치할 필요는 없습니다. 이미 설치했다면 둘은 공존하며 {configDir}의 로그인과 설정을 공유합니다. 아래에서 설치하세요.", + "readyWithNative": "어댑터 {adapterCmd}가 설치되어 있습니다. Codeg가 실행하는 것은 이 어댑터이며, {nativePath}에 있는 사용자의 {nativeCmd}가 아닙니다. 둘은 독립된 패키지로 공존하고 모두 {configDir}를 읽으므로 로그인과 설정을 공유합니다.", + "ready": "어댑터 {adapterCmd}가 설치되어 있으며 Codeg가 실행하는 것이 바로 이것입니다. 자체 런타임을 포함하므로 {nativeLabel}은 필요하지 않습니다. 나중에 설치해도 둘은 공존하며 {configDir}를 공유합니다." + }, + "cline": { + "configDescription": "Cline API 제공자와 자격 증명을 구성합니다. 설정은 ~/.cline/data/에 저장됩니다." + }, + "opencodePlugins": { + "title": "OpenCode 플러그인", + "declared": "선언된 플러그인", + "noPlugins": "opencode.json에 선언된 플러그인이 없습니다", + "status": { + "installed": "설치됨", + "missing": "미설치" + }, + "installAll": "누락된 플러그인 모두 설치", + "pinVersions": "@latest 버전 고정", + "install": "설치", + "uninstall": "제거", + "refresh": "새로고침", + "success": "모든 플러그인이 성공적으로 설치되었습니다", + "failed": "플러그인 작업 실패" + }, + "pi": { + "configManagement": "Pi 설정", + "configDescription": "Pi는 모델 제공자의 API 키로 인증합니다. 키는 ~/.pi/agent/auth.json에, 모델 선택은 settings.json에 저장됩니다.", + "providerLabel": "제공자", + "modelLabel": "모델", + "thinkingLabel": "사고", + "thinking": { + "off": "끔", + "low": "낮음", + "medium": "중간", + "high": "높음", + "minimal": "최소", + "xhigh": "매우 높음" + }, + "apiKeyLabel": "API 키", + "apiKeyHint": "선택한 제공자의 ~/.pi/agent/auth.json에 저장됩니다.", + "apiKeySetPlaceholder": "••••••(저장됨 · 비워두면 유지)", + "saveConfig": "Pi 설정 저장", + "providerModelRequired": "제공자와 모델은 필수입니다", + "runtimeTitle": "런타임", + "runtimeDescription": "어떤 pi를 실행할지 선택합니다. 기본값을 사용하거나 자신의 pi 빌드를 지정하세요.", + "modeDefault": "기본 pi", + "modeDefaultHint": "내장 pi-acp 어댑터로 PATH의 pi를 실행합니다. pi 설치: npm install -g @earendil-works/pi-coding-agent", + "modeCustom": "사용자 지정 pi", + "modeCustomHint": "자신의 pi 빌드, 설치 또는 래퍼를 실행합니다.", + "commandLabel": "pi 명령 또는 경로", + "commandHint": "절대 경로, PATH의 명령 이름 또는 래퍼 스크립트(예: 모노레포의 ./pi-test.sh).", + "commandNotFound": "명령을 찾을 수 없음", + "validate": "검증", + "advanced": "고급", + "configDirLabel": "설정 디렉터리 (PI_CODING_AGENT_DIR)", + "sessionDirLabel": "세션 디렉터리 (PI_CODING_AGENT_SESSION_DIR)", + "flagsHint": "pi-acp는 사용자 지정 pi 플래그(--approve, -e 등)를 전달하지 않습니다. pi를 스크립트로 감싸고 명령이 이를 가리키도록 하세요.", + "customIncomplete": "저장하려면 pi 명령을 입력하세요", + "saveRuntime": "런타임 저장", + "providerPlaceholder": "제공자 선택", + "customProvider": "사용자 지정 제공자…", + "providerIdLabel": "제공자 ID", + "apiProtocolLabel": "API 프로토콜", + "baseUrlLabel": "API 엔드포인트(Base URL)", + "customProviderHint": "~/.pi/agent/models.json에 엔드포인트용 제공자를 정의합니다. 대부분의 자체 호스팅 또는 프록시 서버는 openai-completions를 사용합니다.", + "baseUrlRequired": "API 엔드포인트(Base URL)는 필수입니다", + "binaryTitle": "pi 바이너리 (pi-coding-agent)", + "binaryDescription": "pi-acp가 이 pi 바이너리를 실행합니다. 여기서 설치하거나 아래에서 직접 빌드한 pi를 지정하세요.", + "binaryInstalled": "설치됨", + "binaryMissing": "설치되지 않음", + "binaryChecking": "확인 중…", + "installBinary": "pi 설치", + "installing": "설치 중…", + "recheck": "다시 확인", + "configDirSkillsNote": "사용자 지정 구성 디렉터리를 설정하면 설정에서 관리하는 스킬, 전문가, 오피스 도구가 이 pi에 적용되지 않습니다. 해당 폴더에서 스킬을 직접 관리하세요.", + "projectTrustTitle": "프로젝트 신뢰", + "projectTrustDescription": "pi가 프로젝트 파일을 불러오도록 허용한 폴더입니다. 신뢰한 폴더에서는 해당 저장소의 .pi/extensions가 pi 시작 시 코드를 실행하며, 그 아래 모든 폴더에 적용되고 터미널에서 pi를 실행할 때에도 사용됩니다.", + "projectTrustLoading": "불러오는 중…", + "projectTrustEmpty": "아직 결정한 폴더가 없습니다.", + "projectTrustTrusted": "신뢰함", + "projectTrustDenied": "신뢰 안 함", + "projectTrustRevoke": "취소", + "reasoningTitle": "추론", + "reasoningEnableLabel": "사용", + "reasoningDescription": "모델이 추론 기능을 선언한 경우에만 pi가 추론 강도를 보냅니다. 선언하지 않은 모델은 모든 단계가 Off로 고정되어, 입력창의 선택기가 건드리는 즉시 되돌아갑니다. models.json의 해당 모델 항목에 기록됩니다.", + "levelsLabel": "선택 가능한 단계", + "levelsHint": "입력창 추론 선택기의 항목이 됩니다. 엔드포인트가 받아들이는 값을 고르세요. 여기 없는 단계는 pi가 거부합니다.", + "levelsEmptyError": "단계를 하나 이상 선택하세요. 하나도 없으면 pi는 Off로 되돌아갑니다.", + "wireValuesTitle": "고급: 공급자에게 보내는 값", + "wireValuesHint": "비워 두면 단계 이름을 그대로 보냅니다. 엔드포인트가 다른 표기를 요구할 때만 설정하세요 — Google 계열은 LOW / HIGH가 필요합니다.", + "defaultLevelUnlisted": "이 단계는 위 선택 목록에 없습니다 — pi가 낮춰 버립니다." + }, + "addCustomAgent": "사용자 지정 에이전트 추가", + "addCustomAgentHint": "ACP를 지원하는 모든 에이전트를 등록할 수 있습니다. 공개 ACP 레지스트리에서 선택하거나 레지스트리 정보를 붙여넣으세요.", + "customAgentFromRegistry": "ACP 레지스트리", + "customAgentManual": "직접 입력", + "customAgentSearchPlaceholder": "에이전트 검색…", + "customAgentLoadingCatalog": "ACP 레지스트리를 불러오는 중…", + "customAgentRetry": "다시 시도", + "customAgentNoResults": "일치하는 에이전트가 없습니다", + "customAgentAdd": "추가", + "customAgentAlreadyAdded": "추가됨", + "customAgentUnsupportedPlatform": "이 플랫폼용 빌드가 없습니다", + "customAgentAdded": "{name} 추가됨", + "customAgentIdLabel": "레지스트리 ID", + "customAgentNameLabel": "표시 이름", + "customAgentVersionLabel": "버전", + "customAgentSpecLabel": "배포 정보(JSON)", + "customAgentSpecHint": "ACP 레지스트리의 distribution 객체와 동일한 형식입니다. npx·uvx·binary 채널을 지원하며 레지스트리 항목 전체를 붙여넣어도 됩니다. npx/uvx의 cmd는 패키지가 설치하는 실행 명령 이름으로, 생략하면 패키지 이름에서 유도되므로 서로 다를 때는 지정하세요. binary는 플랫폼 키로 구분하며(이 컴퓨터: {platform}) cmd는 아카이브 내 실행 경로, sha256은 선택 사항으로 다운로드를 검증합니다.", + "customAgentTemplateLabel": "템플릿", + "customAgentKindLabel": "실행 방식", + "customAgentInvalidJson": "올바른 JSON이 아닙니다", + "customAgentNoDistribution": "npx, uvx, binary 배포를 찾을 수 없습니다", + "customAgentCancel": "취소", + "customAgentSave": "에이전트 추가", + "customAgentSaveChanges": "변경 사항 저장", + "customAgentEdit": "에이전트 편집", + "customAgentEditHint": "이름, 아이콘, 배포 정보, 스킬 선언을 수정할 수 있습니다. 에이전트 ID는 변경할 수 없습니다.", + "customAgentEditNotFound": "커스텀 에이전트 {id}을(를) 찾을 수 없습니다", + "customAgentSaved": "{name} 저장됨", + "customAgentVersionProbeLabel": "버전 조회 명령(선택)", + "customAgentVersionProbeHint": "로컬에 설치된 버전을 출력하는 명령입니다. 비워 두면 에이전트 명령에 --version을 붙여 실행합니다.", + "customAgentRemove": "에이전트 제거", + "customAgentRemoveHint": "에이전트 정의를 삭제합니다. 기존 대화 기록은 유지되며 에이전트를 더 이상 실행할 수 없게 될 뿐입니다.", + "customAgentIconLabel": "아이콘(선택)", + "customAgentIconUpload": "업로드", + "customAgentIconReplace": "변경", + "customAgentIconClear": "아이콘 제거", + "customAgentIconHint": "에이전트와 함께 저장되어 오프라인에서도 표시됩니다. 지정하지 않으면 색상 이니셜을 사용합니다.", + "customAgentSkillsLabel": "Skills(공유 .agents/skills)", + "customAgentSkillsHint": "이 에이전트가 공유 .agents/skills 디렉터리(전역 및 프로젝트)를 읽는다고 선언하고 모든 스킬 매트릭스에 추가합니다. 공유 디렉터리에 연결된 스킬은 해당 디렉터리를 읽는 다른 에이전트에게도 보입니다.", + "customAgentSkillsDirLabel": "전용 스킬 디렉터리", + "customAgentSkillsDirHint": "이 에이전트가 스킬을 불러오는 디렉터리의 절대 경로입니다. 공유 저장소와 함께 또는 단독으로 사용할 수 있습니다. ~ 는 홈 디렉터리로 확장되며, 연결된 스킬은 이 디렉터리에 우선 배치됩니다.", + "customAgentMcpLabel": "MCP 지원", + "customAgentMcpHint": "세션을 시작할 때 codeg 내장 codeg-mcp 동반 프로세스를 이 에이전트에 전달합니다. 위임, 실시간 피드백, 작업 도구가 이 채널을 사용합니다. MCP 서버를 거부해 연결에 실패하는 에이전트라면 꺼 두세요. 변경은 다음 연결부터 적용됩니다.", + "customAgentIconNotAnImage": "이미지 파일을 선택하세요.", + "customAgentIconTooLarge": "아이콘은 {limit} KB 미만이어야 합니다.", + "customAgentIconReadFailed": "해당 이미지를 읽을 수 없습니다.", + "customAgentRemoveConfirm": "{name}을(를) 제거할까요? 기존 대화는 유지되지만 더 이상 실행할 수 없습니다.", + "customAgentRemoveWithData": "기록된 대화 기록도 삭제", + "customAgentRemoved": "{name} 제거됨", + "customAgentBadge": "사용자 지정", + "customAgentNotLaunchable": "이 환경에서는 실행할 수 없습니다: {reason}" + }, + "SettingsPages": { + "agentsLoading": "에이전트 설정을 불러오는 중...", + "skillPacksLoading": "스킬 팩 로딩 중…" + }, + "GeneralSettings": { + "loading": "로딩 중...", + "sectionTitle": "일반", + "sectionDescription": "기본 터미널, 렌더링 가속, 다중 에이전트 위임 등 공용 환경설정을 한곳에서 관리합니다.", + "terminalTitle": "기본 터미널", + "terminalDescription": "터미널 바나 파일 트리에서 새 터미널 탭을 열 때 사용할 셸을 선택합니다. 에이전트가 codeg에 전체 명령줄 실행을 요청할 때도 사용됩니다.", + "terminalSystemDefault": "시스템 기본값", + "terminalPowerShell7": "PowerShell 7 (pwsh)", + "terminalWindowsPowerShell": "Windows PowerShell", + "terminalCmd": "명령 프롬프트 (cmd)", + "terminalSaveFailed": "터미널 설정 저장 실패: {message}", + "terminalShellCustom": "사용자 지정 경로", + "terminalShellCustomPath": "Shell 경로", + "terminalShellCustomPlaceholder": "/usr/local/bin/fish", + "terminalShellCustomSave": "저장", + "terminalShellCustomHint": "절대 경로 또는 PATH에서 찾을 수 있는 명령 이름을 입력하세요.", + "terminalShellNotInstalled": "설치되지 않음", + "terminalShellNotFoundWarning": "이 경로는 현재 호스트에 존재하지 않습니다.", + "terminalCurrentShell": "현재 사용 중: {path}", + "renderingDescription": "앱이 검은 화면이 되거나 렌더링 문제가 발생하면(일부 AMD GPU 또는 Intel 내장 GPU에서 보고됨) 하드웨어 가속을 끄세요. Windows 데스크톱에서만 적용됩니다.", + "disableHardwareAcceleration": "하드웨어 가속 비활성화", + "renderingSaveFailed": "렌더링 설정 저장 실패: {message}", + "restartRequired": "저장되었습니다. 변경 사항을 적용하려면 앱을 다시 시작하세요.", + "restartNow": "지금 다시 시작", + "restartFailed": "다시 시작 실패: {message}", + "loadFailed": "불러오기 실패: {message}" + }, + "LoginPage": { + "documentTitle": "로그인 - codeg", + "brand": "Codeg", + "subtitle": "데스크톱 앱에 연결하려면 액세스 토큰을 입력하세요", + "tokenPlaceholder": "액세스 토큰", + "connect": "연결", + "connecting": "연결 중...", + "helpText": "토큰은 데스크톱 앱의 설정 → 웹 서비스에서 확인할 수 있습니다", + "invalidToken": "유효하지 않은 토큰입니다. 확인 후 다시 시도하세요", + "connectionFailed": "연결 실패 (HTTP {status})", + "networkError": "서버에 연결할 수 없습니다" + }, + "CommitPage": { + "title": "커밋", + "invalidFolderId": "유효하지 않은 폴더 ID", + "loadingRepo": "저장소를 불러오는 중..." + }, + "MergePage": { + "title": "충돌 해결", + "invalidFolderId": "잘못된 폴더 ID", + "loadingRepo": "저장소 로딩 중...", + "localVersion": "로컬 (우리 쪽)", + "result": "결과", + "remoteVersion": "원격 (상대 쪽)", + "acceptLocal": "로컬 적용", + "acceptRemote": "원격 적용", + "markResolved": "해결됨으로 표시", + "abortMerge": "중단", + "completeMerge": "병합 완료", + "unresolvedConflicts": "파일에 아직 해결되지 않은 충돌 마커가 있습니다", + "fileResolved": "파일이 해결되었습니다", + "allResolved": "모든 충돌이 해결되었습니다", + "conflictFiles": "충돌 파일", + "loadingFile": "파일 로딩 중...", + "preparingMerge": "병합 준비 중...", + "selectFile": "해결할 파일을 선택하세요", + "noConflicts": "충돌 파일 없음", + "skipFile": "건너뛰기", + "abortSuccess": "작업이 중단되었습니다", + "applyAllNonConflicting": "충돌하지 않는 모든 변경 적용", + "applyLeftNonConflicting": "로컬 적용", + "applyRightNonConflicting": "원격 적용" + }, + "ImportSessions": { + "title": "로컬 세션 가져오기", + "scanningTitle": "로컬 에이전트 세션 검색 중…", + "scanningHint": "각 에이전트의 로컬 세션 저장소를 탐색하고 있습니다. 기록이 많으면 시간이 걸릴 수 있습니다. 이미 가져온 세션은 이 과정에서 함께 갱신됩니다.", + "scanFailed": "검색 실패", + "retry": "다시 시도", + "rescan": "다시 검색", + "empty": "로컬 세션을 찾을 수 없습니다", + "emptyHint": "이 컴퓨터에서 에이전트 세션 저장소를 찾지 못했습니다.", + "noMatches": "현재 필터와 일치하는 세션이 없습니다", + "searchPlaceholder": "제목 또는 경로 검색…", + "allAgents": "모든 에이전트", + "onlyImportable": "가져오기 가능만", + "selectAll": "모두 선택", + "clearSelection": "지우기", + "expandAll": "모두 펼치기", + "collapseAll": "모두 접기", + "summaryCounts": "세션 {total}개 · 가져오기 가능 {importable}개 · 폴더 {folders}개", + "noFolderSkipped": "프로젝트 폴더가 없는 {count}개 건너뜀", + "folderNew": "신규", + "folderCounts": "가져오기 가능 {importable}/{total}", + "toggleFolderAria": "{name}의 가져오기 가능한 세션 모두 선택", + "toggleSessionAria": "세션 {title} 선택", + "statusImported": "가져옴", + "statusDeleted": "삭제됨", + "untitled": "제목 없는 세션", + "messageCount": "메시지 {count}개", + "selectedCount": "{count}개 선택됨", + "importSelected": "선택 항목 가져오기", + "importing": "가져오는 중…", + "close": "닫기", + "doneTitle": "가져오기 완료", + "doneImported": "가져옴", + "doneUpdated": "갱신됨", + "doneSkipped": "건너뜀", + "doneCreatedFolders": "생성된 폴더", + "doneNotFound": "찾을 수 없음", + "doneFailed": "실패", + "continueImport": "계속 가져오기", + "toasts": { + "importFailed": "가져오기 실패: {message}" + } + }, + "Folder": { + "workspaceStatus": { + "degradedTitle": "실시간 업데이트를 사용할 수 없음", + "degradedHint": "감시자 시작 실패(권한 거부 등). 최신 변경 사항을 보려면 수동으로 새로 고치세요.", + "retry": "다시 시도", + "retrying": "다시 시도 중..." + }, + "common": { + "all": "전체", + "cancel": "취소", + "close": "닫기", + "closeOthers": "다른 항목 닫기", + "closeAll": "모두 닫기", + "confirm": "확인", + "save": "저장", + "delete": "삭제", + "rename": "이름 변경", + "loading": "로딩 중...", + "refresh": "새로고침", + "refreshing": "새로고침 중...", + "create": "생성", + "createAndSwitch": "생성 후 전환", + "openFile": "파일 열기", + "viewDiff": "Diff 보기", + "push": "푸시..." + }, + "statusLabels": { + "in_progress": "진행 중", + "pending_review": "검토", + "completed": "완료", + "cancelled": "취소됨" + }, + "sidebar": { + "title": "대화", + "locateActiveConversation": "활성 대화 찾기", + "expandAllGroups": "모든 그룹 펼치기", + "collapseAllGroups": "모든 그룹 접기", + "newConversation": "새 대화", + "newConversationShort": "새로 만들기", + "newChat": "새 대화", + "search": "검색", + "noConversationsFound": "대화를 찾을 수 없습니다.", + "importLocalSessions": "로컬 세션 가져오기", + "importing": "가져오는 중...", + "error": "오류: {message}", + "completeAllSessions": "모든 세션 완료 처리", + "completeAllReviewTitle": "모든 검토 세션을 완료 처리할까요?", + "completeAllReviewDescription": "검토 상태의 {count, plural, one {#개 세션} other {#개 세션}}을 모두 완료로 표시합니다.", + "completing": "완료 처리 중...", + "toasts": { + "importedSessions": "{imported, plural, one {#개 세션} other {#개 세션}}을 가져오고 {skipped}개를 건너뛰었습니다", + "importedAndUpdated": "{imported, plural, one {#개 세션} other {#개 세션}}을 가져오고 {updated, plural, one {#개 제목} other {#개 제목}}을 업데이트하고 {skipped}개를 건너뛰었습니다", + "updatedTitles": "{updated, plural, one {#개 제목} other {#개 제목}}을 업데이트하고 {skipped}개를 건너뛰었습니다", + "noNewSessionsFound": "새 세션이 없습니다 ({skipped}개 건너뜀)", + "importFailed": "가져오기 실패: {message}", + "reviewCompleted": "{count, plural, one {#개 검토 세션} other {#개 검토 세션}}을 완료로 표시했습니다", + "completeReviewFailed": "검토 세션 완료 처리 실패: {message}", + "folderOpened": "폴더 {name}을(를) 열었습니다", + "folderRemoved": "폴더 {name}을(를) 제거했습니다", + "openFolderFailed": "폴더를 열 수 없습니다", + "removeFolderFailed": "폴더 제거 실패: {message}", + "reorderFoldersFailed": "폴더 순서 변경 실패: {message}", + "changeFolderColorFailed": "색상 변경 실패: {message}", + "setFolderAliasFailed": "별칭 설정 실패: {message}", + "changeFolderDefaultAgentFailed": "기본 에이전트 설정 실패: {message}" + }, + "statsLabel": "{folders}개 폴더 · {convos}개 대화", + "reorderHandle": "드래그하여 순서 변경", + "openFolder": "폴더 열기", + "searchPlaceholder": "대화 검색...", + "viewOptions": "보기 옵션", + "showCompleted": "완료된 대화 표시", + "showWorktrees": "워크트리 폴더 표시", + "showRecent": "'최근' 그룹 표시", + "moreOptions": "더 많은 옵션", + "sortBy": "정렬 기준", + "sortByCreatedAt": "생성 시간순", + "sortByUpdatedAt": "업데이트 시간순", + "sectionOrder": "섹션 순서", + "sectionOrderMoveUp": "위로 이동", + "sectionOrderMoveDown": "아래로 이동", + "sectionOrderItemLabel": "{name} — {total}개 중 {position}번째", + "statusRunningBadge": "실행 중", + "runningCountBadge": "{count}개 세션 실행 중", + "statusCancelledBadge": "취소됨", + "worktreeRemovedBadge": "원본 worktree가 삭제됨", + "conversationCountUnit": "{count}개", + "emptyFolderHint": "대화 없음", + "noMatchingConversations": "일치하는 대화가 없습니다", + "noUnfinishedConversations": "미완료 대화가 없습니다. 오른쪽 상단 메뉴에서 \"완료된 대화 표시\"를 활성화할 수 있습니다.", + "removeFolderConfirmTitle": "이 폴더를 워크스페이스에서 제거하시겠습니까?", + "removeFolderConfirmDescription": "워크스페이스에서 \"{name}\"을(를) 제거하시겠습니까? 관련 탭과 터미널이 닫힙니다.", + "folderHeaderMenu": { + "manageConversations": "대화 관리…", + "manageLinks": "연결된 폴더", + "changeColor": "색상 변경", + "useThemeColor": "앱 테마 사용", + "setDefaultAgent": "기본 에이전트 설정", + "defaultAgentNone": "설정 없음(전역 사용)", + "agentUnavailableSuffix": "(사용 불가)", + "loadingAgents": "에이전트 로드 중…", + "setAlias": "별칭 설정…", + "setAliasTitle": "폴더 별칭 설정", + "setAliasPlaceholder": "별칭 입력 (비우면 지움)", + "setAliasSave": "저장", + "setAliasCancel": "취소", + "removeFromWorkspace": "워크스페이스에서 제거" + }, + "manageConversations": { + "title": "대화 관리", + "searchPlaceholder": "제목으로 검색…", + "agentFilterAll": "모든 에이전트", + "statusFilterAll": "모든 상태", + "folderFilterAll": "모든 폴더", + "branchFilterAll": "모든 브랜치", + "branchNone": "브랜치 없음", + "branchSearchPlaceholder": "브랜치 검색…", + "noMatchingBranches": "일치하는 브랜치가 없습니다", + "selectAllVisible": "전체 선택", + "deselectAll": "선택 해제", + "selectedCount": "{count}개 선택됨", + "matchedCount": "{count}개 일치", + "untitledConversation": "제목 없는 대화", + "setStatus": "상태 변경…", + "deleteSelected": "삭제", + "noConversations": "이 폴더에 대화가 없습니다.", + "noConversationsWorkspace": "작업 공간에 대화가 없습니다.", + "noMatchingConversations": "필터에 일치하는 대화가 없습니다.", + "confirmDeleteTitle": "{count}개 대화를 삭제하시겠습니까?", + "confirmDeleteDescription": "이 작업은 되돌릴 수 없습니다.", + "toastDeleted": "{count}개 대화를 삭제했습니다", + "toastStatusUpdated": "{count}개 대화의 상태를 업데이트했습니다", + "toastOpFailed": "작업 실패: {message}" + }, + "sectionPinned": "고정됨", + "sectionFolders": "폴더", + "sectionChats": "채팅", + "sectionRecent": "최근", + "noChats": "채팅 없음", + "noRecent": "최근 대화 없음", + "showMoreRecent": "더 보기 ({count})", + "noFolders": "열린 폴더 없음", + "newChatAction": "새 채팅", + "automations": "자동화", + "tasks": "할 일", + "loadingSubsessions": "하위 대화 로드 중…" + }, + "conversation": { + "reloadFailed": "대화 다시 불러오기 실패: {message}", + "reloaded": "대화를 다시 불러왔습니다", + "reload": "다시 불러오기", + "activeConversationIndicator": "활성 대화", + "newConversation": "새 대화", + "closeConversation": "대화 닫기", + "copyText": "텍스트 복사", + "copyTextSuccess": "복사됨", + "copyTextFailed": "복사 실패", + "forkSession": "세션 포크", + "forkSessionSuccess": "세션 포크 성공", + "forkSessionFailed": "세션 포크 실패: {error}", + "exportConversation": "대화 내보내기", + "exportImage": "이미지", + "exportMarkdown": "Markdown", + "exportHtml": "HTML", + "exportSuccess": "대화를 내보냈습니다", + "exportFailed": "내보내기 실패", + "exportImageTooLong": "대화가 너무 길어 이미지로 내보낼 수 없습니다", + "exportLabels": { + "untitledConversation": "제목 없는 대화", + "agent": "에이전트", + "model": "모델", + "status": "상태", + "started": "시작", + "updated": "업데이트", + "tokens": "토큰 통계", + "duration": "소요 시간", + "inputTokens": "입력", + "outputTokens": "출력", + "cacheRead": "캐시 읽기", + "cacheWrite": "캐시 쓰기", + "user": "사용자", + "assistant": "어시스턴트", + "system": "시스템", + "toolResult": "결과", + "toolError": "오류" + }, + "moreActions": "추가 작업" + }, + "sessionDetails": { + "menuLabel": "세션 세부 정보", + "noActiveSession": "활성 세션이 없습니다", + "title": "세션 세부 정보", + "subtitle": "세션 메타데이터 및 토큰 사용량", + "fieldTitle": "제목", + "untitled": "제목 없는 대화", + "sessionId": "세션 ID", + "externalId": "확장 ID", + "agent": "에이전트", + "model": "모델", + "status": "상태", + "gitBranch": "Git 브랜치", + "parentId": "상위 세션", + "tokensHeading": "토큰 사용량", + "totalTokens": "합계", + "inputTokens": "입력", + "outputTokens": "출력", + "cacheWrite": "캐시 쓰기", + "cacheRead": "캐시 읽기", + "contextWindow": "컨텍스트 창", + "duration": "소요 시간", + "loadingStats": "토큰 사용량 불러오는 중…", + "loadFailed": "토큰 사용량을 불러오지 못했습니다", + "noStats": "사용량 기록 없음", + "timestampsHeading": "타임스탬프", + "createdAt": "생성됨", + "updatedAt": "업데이트됨", + "none": "—", + "copyField": "{field} 복사", + "copiedField": "{field} 복사됨" + }, + "conversationCard": { + "untitledConversation": "제목 없는 대화", + "newConversation": "새 대화", + "rename": "이름 변경", + "status": "상태", + "delete": "삭제", + "importLocalSessions": "로컬 세션 가져오기", + "importing": "가져오는 중...", + "renameConversation": "대화 이름 변경", + "deleteConversationTitle": "대화를 삭제할까요?", + "deleteConversationDescription": "\"{title}\"을(를) 삭제합니다. 이 작업은 되돌릴 수 없습니다.", + "cancel": "취소", + "save": "저장", + "pin": "고정", + "unpin": "고정 해제", + "markCompleted": "완료로 표시", + "reopen": "다시 열기", + "expandSubsessions": "하위 대화 펼치기", + "collapseSubsessions": "하위 대화 접기" + }, + "search": { + "dialogTitle": "검색", + "dialogTitleWithFolder": "검색 — {name}", + "tabConversations": "대화", + "tabFiles": "파일", + "placeholder": "대화 검색...", + "filePlaceholder": "파일 또는 디렉토리 검색...", + "allAgents": "전체", + "searching": "검색 중...", + "typeToSearch": "입력하여 대화를 검색하세요", + "typeToSearchFiles": "입력하여 파일 또는 디렉토리를 검색하세요", + "noResults": "검색 결과가 없습니다.", + "untitledConversation": "제목 없는 대화" + }, + "folderTitleBar": { + "showSidebar": "사이드바 표시", + "hideSidebar": "사이드바 숨기기", + "toggleTerminal": "터미널 전환", + "toggleAuxPanel": "보조 패널 전환", + "search": "검색", + "openSettings": "설정 열기", + "backToConversations": "대화로 돌아가기", + "withShortcut": "{label} ({shortcut} 단축키)" + }, + "statusBar": { + "connection": { + "connected": "연결됨", + "connecting": "연결 중...", + "prompting": "응답 중...", + "error": "연결 오류", + "disconnected": "연결 끊김", + "tooltip": "{agent}: {status}", + "tooltipError": "{agent}: {error}", + "title": "에이전트 연결", + "triggerAria": "에이전트 연결: {status}", + "workingDir": "작업 디렉터리", + "sessionId": "세션 ID", + "viewerNote": "다른 클라이언트가 소유한 세션에 연결되어 있습니다. 다시 연결해도 이 보기만 다시 연결됩니다.", + "reconnectInterrupts": "다시 연결하면 에이전트가 재시작되어 진행 중인 작업이 중단됩니다.", + "reconnect": "다시 연결", + "reconnecting": "다시 연결하는 중...", + "reconnectUnavailable": "아직 다시 연결할 세션이 없습니다." + }, + "tasks": { + "title": "작업" + }, + "alerts": { + "title": "알림", + "empty": "알림 없음", + "details": "세부 정보" + }, + "stats": { + "conversations": "{count}개 대화", + "openUsage": "세션 통계 및 토큰 사용량 보기" + }, + "tokens": { + "contextWindowUsageAria": "컨텍스트 윈도우 사용량", + "contextWindow": "컨텍스트 윈도우", + "usedMax": "사용 / 최대", + "tokenUsage": "토큰 사용량", + "input": "입력", + "output": "출력", + "cacheRead": "캐시 읽기", + "cacheWrite": "캐시 쓰기", + "total": "합계" + } + }, + "auxPanel": { + "tabs": { + "files": "파일", + "changes": "변경사항", + "commits": "커밋" + }, + "noFolderTitle": "열린 폴더 없음", + "noFolderHint": "폴더를 열면 여기에 표시됩니다" + }, + "windowControls": { + "minimizeWindow": "창 최소화", + "minimize": "최소화", + "maximizeWindow": "창 최대화", + "maximize": "최대화", + "restoreWindow": "창 복원", + "restore": "복원", + "closeWindow": "창 닫기", + "close": "닫기" + }, + "tabs": { + "closeConversationTab": "대화 탭 닫기", + "close": "닫기", + "closeOthers": "다른 항목 닫기", + "splitRight": "오른쪽으로 분할", + "splitDown": "아래로 분할", + "splitAndMoveRight": "분할하고 오른쪽으로 이동", + "splitAndMoveDown": "분할하고 아래로 이동", + "moveToOppositeGroup": "반대쪽 그룹으로 이동", + "moveToGroup": "그룹으로 이동", + "groupLabel": "그룹 {index}", + "changeSplitterOrientation": "분할 방향 전환", + "unsplit": "분할 해제", + "unsplitAll": "모든 분할 해제", + "closeAll": "모두 닫기", + "tileDisplay": "타일 표시", + "untileDisplay": "타일 해제" + }, + "fileWorkspace": { + "files": "파일", + "closeFileTab": "파일 탭 닫기", + "close": "닫기", + "closeOthers": "다른 항목 닫기", + "closeAll": "모두 닫기", + "preview": "미리보기", + "editSource": "소스 편집", + "maximize": "최대화", + "restore": "복원", + "emptyDirectory": "빈 폴더" + }, + "terminal": { + "rename": "이름 변경", + "close": "닫기", + "closeOthers": "다른 항목 닫기", + "closeAll": "모두 닫기", + "hideTerminal": "터미널 숨기기 ({shortcut})", + "openFolderFirst": "먼저 폴더를 여세요" + }, + "workspaceDialog": { + "title": "폴더 열기", + "manageTitle": "연결된 폴더", + "addTargetsTitle": "연결할 폴더 추가", + "pickRootDescription": "이 작업 공간의 기본 폴더를 선택하세요.", + "linksDescription": "다른 폴더를 하위 디렉터리로 연결하면 에이전트가 하나의 작업 공간에서 여러 프로젝트를 함께 다룰 수 있습니다.", + "addTargetsDescription": "폴더를 하나 이상 선택하세요. 각각 작업 공간의 하위 디렉터리가 됩니다.", + "useSystemPicker": "시스템 선택기", + "next": "다음", + "back": "뒤로", + "done": "완료", + "change": "변경", + "addFolders": "폴더 추가", + "addSelected": "추가", + "addSelectedCount": "{count}개 추가", + "createCount": "폴더 {count}개 연결", + "discardPending": "취소", + "noLinks": "아직 연결된 폴더가 없습니다.", + "gitExclude": "연결을 git 상태에 노출하지 않기", + "rename": "이름 변경", + "unlink": "연결 해제", + "repair": "연결 다시 만들기", + "saveName": "저장", + "cancelRename": "취소", + "removePending": "제거", + "willAppearAs": "작업 공간에서 {name}(으)로 표시됩니다", + "renamedForDuplicate": "이름이 변경됨 — {base}은(는) 다른 연결이 사용 중입니다", + "renamedForExistingEntry": "이름이 변경됨 — 이 폴더에 이미 {base}이(가) 있습니다", + "partiallyCreated": "폴더 {count}개만 연결되었습니다", + "openFailed": "폴더를 열지 못했습니다", + "previewFailed": "선택한 폴더를 확인하지 못했습니다", + "createFailed": "폴더를 연결하지 못했습니다", + "renameFailed": "이름을 변경하지 못했습니다", + "removeFailed": "연결을 해제하지 못했습니다", + "repairFailed": "연결을 다시 만들지 못했습니다", + "status": { + "ok": "연결됨", + "missing": "이 폴더에서 링크가 사라졌습니다", + "conflicted": "다른 항목이 이 이름을 사용 중입니다", + "broken": "연결된 폴더가 더 이상 존재하지 않습니다" + }, + "nameIssue": { + "empty": "이름을 입력하세요", + "illegalChars": "/ \\ : * ? \" < > | 는 사용할 수 없습니다", + "tooLong": "이름이 너무 깁니다", + "reserved": "Windows 예약어입니다", + "duplicate": "이미 사용 중인 이름입니다" + }, + "rejection": { + "not_found": "폴더를 찾을 수 없습니다", + "not_a_directory": "이 경로는 폴더가 아닙니다", + "same_as_root": "작업 공간 폴더 자신입니다", + "ancestor_of_root": "이 폴더가 작업 공간을 포함합니다", + "inside_root": "이미 작업 공간 안에 있습니다", + "already_linked": "이미 연결되어 있습니다", + "name_unavailable": "이 폴더에 사용할 수 있는 이름이 없습니다", + "alreadyLinkedAs": "{name}(으)로 이미 연결되어 있습니다" + } + }, + "folderNameDropdown": { + "fallbackFolderName": "폴더", + "openFolder": "폴더 열기", + "cloneRepository": "리포지토리 클론", + "projectBoot": "프로젝트 부트", + "opened": "열린 항목", + "recentOpen": "최근 연 항목" + }, + "fileWorkspacePanel": { + "addSelectionToChat": "선택 영역을 대화에 추가", + "addToChat": "대화에 추가", + "addSelectionToChatDone": "{label}을(를) 대화에 추가했습니다", + "addFileToChat": "파일을 대화에 추가", + "toggleWordWrap": "자동 줄 바꿈 전환", + "addFileToChatDone": "{label}을(를) 대화에 추가했습니다", + "viewDiff": "Diff 보기", + "openFile": "파일 열기", + "fileCount": "{count, plural, one {#개 파일} other {#개 파일}}", + "openFileOrDiff": "오른쪽 패널에서 파일 또는 diff를 여세요", + "disk": "디스크", + "head": "HEAD", + "unsaved": "저장되지 않음", + "workingTree": "작업 트리", + "loading": "로딩 중...", + "compareWithBranch": "{path} · {branch}와 비교", + "hunkCount": "{count, plural, one {#개 hunk} other {#개 hunks}}", + "prev": "이전", + "next": "다음", + "jumpToLine": "{line}행으로 이동", + "noParsedDiffSections": "파싱된 diff 섹션이 없습니다", + "loadingEditor": "에디터 로딩 중...", + "imageZoomIn": "확대", + "imageZoomOut": "축소", + "imageZoomReset": "확대/축소 초기화", + "htmlPreviewTitle": "HTML 미리보기", + "htmlPreviewTrust": "스크립트 사용", + "htmlPreviewTrustHint": "이 파일의 스크립트를 실행하고 네트워크 접근을 허용합니다. 신뢰할 수 있는 파일에서만 사용하세요.", + "officePreviewTitle": "Office 문서 미리보기", + "officeFullRender": "전체 렌더링", + "officeFullRenderHint": "Morph 애니메이션, 3D, 수식을 렌더링합니다(슬라이드 자체 스크립트 실행).", + "officeNotInstalled": "OfficeCLI가 설치되지 않았습니다", + "officeNotInstalledHint": "설정 → Office 도구에서 OfficeCLI를 설치하면 Word, Excel, PowerPoint 파일을 미리볼 수 있습니다.", + "officeOpenSettings": "설정 열기", + "officeWatchFailed": "실시간 미리보기를 시작할 수 없습니다", + "officeWatchRetry": "다시 시도", + "officeServerInstallHint": "OfficeCLI는 서버 호스트에 설치해야 합니다. 서버에서 다음 명령을 실행한 후 다시 시도하세요:", + "officeRemoteDesktopUnsupported": "원격 데스크톱 창에서는 실시간 미리보기를 사용할 수 없습니다. Office 파일을 미리 보려면 서버의 웹 UI에서 이 작업 공간을 여세요." + }, + "branchDropdown": { + "toasts": { + "commitCodeCompleted": "코드 커밋이 완료되었습니다", + "pushCodeCompleted": "코드 푸시가 완료되었습니다", + "committedFiles": "{count, plural, one {#개 파일 커밋됨} other {#개 파일 커밋됨}}", + "taskCompleted": "{label} 완료", + "taskFailed": "{label} 실패", + "mergeNoNewCommits": "{branchName}에는 새 커밋이 없습니다", + "mergedCommits": "{count, plural, one {#개 커밋 병합됨} other {#개 커밋 병합됨}}", + "allFilesUpToDate": "모든 파일이 최신 상태입니다", + "updatedFiles": "{count, plural, one {#개 파일 업데이트됨} other {#개 파일 업데이트됨}}", + "openCommitWindowFailed": "커밋 창을 열지 못했습니다", + "openPushWindowFailed": "푸시 창 열기 실패", + "upstreamSet": "업스트림 브랜치가 설정되었습니다", + "upstreamSetAndPushed": "업스트림 브랜치를 설정하고 {count, plural, one {#개 커밋} other {#개 커밋}}을 푸시했습니다", + "noCommitsToPush": "푸시할 커밋이 없습니다", + "pushedCommits": "{count, plural, one {#개 커밋 푸시됨} other {#개 커밋 푸시됨}}", + "switchedToFolder": "{name}(으)로 전환했습니다", + "switchFailed": "브랜치 전환에 실패했습니다", + "openStashWindowFailed": "스태시 창을 열지 못했습니다" + }, + "tasks": { + "newBranch": "브랜치 {name} 생성", + "newWorktree": "워크트리 {name} 생성", + "checkoutTo": "{branchName}(으)로 체크아웃", + "mergeBranch": "{branchName} 병합", + "rebaseTo": "{branchName}로 리베이스", + "deleteRemoteBranch": "원격 브랜치 {branchName} 삭제", + "initGitRepo": "Git 저장소 초기화", + "pullCode": "코드 pull", + "fetchInfo": "정보 fetch", + "pushCode": "코드 push", + "stashChanges": "변경 사항 stash", + "stashPop": "stash pop", + "deleteBranch": "브랜치 {branchName} 삭제", + "removeWorktree": "{branchName}의 워크트리 삭제", + "removeWorktreeAndBranch": "워크트리 및 브랜치 {branchName} 삭제", + "updateBranch": "브랜치 {branchName} 업데이트" + }, + "confirm": { + "mergeTitle": "브랜치 병합", + "rebaseTitle": "브랜치 리베이스", + "mergeDescription": "{branchName}을(를) 현재 브랜치 {currentBranch}에 병합할까요?", + "rebaseDescription": "현재 브랜치 {currentBranch}를 {branchName} 위로 리베이스할까요?", + "deleteRemoteTitle": "원격 브랜치 삭제", + "deleteRemoteDescription": "원격 브랜치 {branchName}을(를) 삭제하시겠습니까? 이 작업은 원격 저장소에서 브랜치를 제거하며 되돌릴 수 없습니다.", + "deleteTitle": "브랜치 삭제", + "deleteDescription": "브랜치 {branchName}을(를) 삭제할까요? 이 작업은 되돌릴 수 없습니다.", + "forceDeleteTitle": "브랜치 강제 삭제", + "forceDeleteDescription": "브랜치 {branchName}가 완전히 병합되지 않았습니다. 강제 삭제하시겠습니까? 이 작업은 되돌릴 수 없습니다.", + "deleteWorktreeTitle": "워크트리 삭제", + "deleteWorktreeDescription": "{branchName}이(가) 체크아웃된 워크트리 디렉터리를 삭제할까요? 브랜치와 커밋은 유지됩니다.", + "forceDeleteWorktreeTitle": "워크트리 강제 삭제", + "forceDeleteWorktreeDescription": "{branchName}의 워크트리에 커밋되지 않았거나 추적되지 않는 파일이 있습니다. 그래도 삭제할까요? 해당 변경 사항은 복구할 수 없습니다.", + "deleteWorktreeAndBranchTitle": "워크트리 및 브랜치 삭제", + "deleteWorktreeAndBranchDescription": "{branchName}의 워크트리와 브랜치, 그리고 워크스페이스 폴더를 삭제할까요? 그 안의 세션은 저장소 폴더로 이동합니다. 이 작업은 되돌릴 수 없습니다.", + "forceDeleteWorktreeAndBranchTitle": "워크트리 및 브랜치 강제 삭제", + "forceDeleteWorktreeAndBranchDescription": "{branchName}의 워크트리에 커밋되지 않은 파일이 있거나 브랜치가 완전히 병합되지 않았습니다. 그래도 둘 다 삭제할까요? 이 작업은 되돌릴 수 없습니다." + }, + "current": "현재", + "switchToBranch": "이 브랜치로 전환", + "mergeBranchIntoCurrent": "{branchName}을(를) {currentBranch}에 병합", + "rebaseCurrentToBranch": "{currentBranch}를 {branchName}로 리베이스", + "noBranch": "브랜치 없음", + "detachedHead": "분리된 HEAD ({sha})", + "initGitRepo": "Git 저장소 초기화", + "pullCode": "코드 pull", + "fetchRemoteBranches": "원격 브랜치 가져오기", + "openCommitWindow": "코드 커밋...", + "pushCode": "푸시...", + "pushBranch": "푸시", + "newBranch": "새 브랜치...", + "newWorktree": "새 워크트리...", + "stashChanges": "스태시...", + "stashPop": "stash pop...", + "manageRemotes": "원격 관리...", + "localBranches": "로컬 브랜치 ({count, plural, one {#} other {#}})", + "noLocalBranches": "로컬 브랜치가 없습니다", + "remoteBranches": "원격 브랜치 ({count, plural, one {#} other {#}})", + "noRemoteBranches": "원격 브랜치가 없습니다", + "dialogs": { + "newBranchTitle": "새 브랜치", + "newBranchDescription": "현재 브랜치 {branch}에서 새 브랜치를 만듭니다", + "branchNamePlaceholder": "브랜치 이름", + "newWorktreeTitle": "새 워크트리", + "newWorktreeDescription": "현재 브랜치 {branch}에서 새 워크트리를 만듭니다", + "branchNameLabel": "브랜치 이름", + "worktreePathLabel": "워크트리 경로", + "worktreePathPlaceholder": "워크트리 경로", + "manageRemotesTitle": "원격 관리", + "manageRemotesEmpty": "구성된 원격이 없습니다", + "remoteNamePlaceholder": "원격 이름", + "remoteUrlPlaceholder": "원격 URL", + "addRemote": "추가", + "savingRemotes": "저장 중..." + }, + "conflict": { + "title": "병합 충돌", + "description": "다음 파일에 충돌이 있어 해결이 필요합니다:", + "abort": "병합 중단", + "openMergeTool": "병합 도구 열기", + "completeMerge": "병합 완료", + "abortSuccess": "병합이 중단되었습니다", + "completeSuccess": "병합이 완료되었습니다" + }, + "stashDialog": { + "title": "변경 사항 스태시", + "description": "현재 변경 사항을 스태시에 저장", + "messageLabel": "메시지", + "messagePlaceholder": "스태시 메시지 (선택사항)", + "keepIndex": "인덱스 유지 (스테이지된 변경 사항 유지)", + "cancel": "취소", + "stash": "스태시", + "success": "변경 사항이 스태시되었습니다", + "error": "스태시 실패" + }, + "unstashDialog": { + "title": "스태시 적용", + "noStashes": "스태시가 없습니다", + "selectFile": "파일을 선택하여 차이 보기", + "viewDiff": "차이 보기", + "original": "원본", + "modified": "수정됨", + "apply": "적용", + "drop": "삭제", + "applySuccess": "스태시가 적용되었습니다", + "dropSuccess": "스태시가 삭제되었습니다", + "confirmApply": "스태시 {ref}을(를) 작업 디렉토리에 적용하시겠습니까?", + "cancel": "취소" + }, + "deleteBranch": "브랜치 삭제", + "deleteWorktree": "워크트리 삭제", + "deleteWorktreeAndBranch": "워크트리 및 브랜치 삭제", + "searchPlaceholder": "브랜치 및 작업 검색", + "searchAriaLabel": "브랜치 및 작업 검색", + "branchListLabel": "브랜치 및 작업", + "noMatches": "일치하는 항목 없음" + }, + "commitDialog": { + "toasts": { + "commitCompleted": "코드 커밋이 완료되었습니다", + "pushFailed": "푸시 실패", + "committedFiles": "{count, plural, one {#개 파일 커밋됨} other {#개 파일 커밋됨}}", + "addedToVcs": "VCS에 추가되었습니다", + "addToVcsFailed": "VCS에 추가하지 못했습니다", + "fileDeleted": "파일이 삭제되었습니다", + "deleteFailed": "삭제에 실패했습니다", + "fileRolledBack": "파일이 롤백되었습니다", + "rollbackFailed": "롤백에 실패했습니다", + "dirRolledBack": "디렉토리가 롤백되었습니다", + "dirDeleted": "디렉토리가 삭제되었습니다" + }, + "confirm": { + "deleteTitle": "삭제 확인", + "deleteDescription": "파일 \"{file}\"을(를) 삭제할까요? 이 작업은 되돌릴 수 없습니다.", + "rollbackTitle": "롤백 확인", + "rollbackDescription": "파일 \"{file}\"을(를) HEAD로 롤백할까요? 저장되지 않은 변경 사항은 사라집니다.", + "rollbackDirDescription": "디렉토리 \"{dir}\"를 HEAD로 롤백하시겠습니까? 저장되지 않은 변경 사항이 손실됩니다.", + "deleteDirDescription": "디렉토리 \"{dir}\"를 삭제하시겠습니까? 이 작업은 되돌릴 수 없습니다." + }, + "actions": { + "select": "선택", + "unselect": "선택 해제", + "rollback": "롤백", + "addToVcs": "VCS에 추가" + }, + "aria": { + "selectFile": "{action}: {path}", + "unselectAllFiles": "모든 파일 선택 해제", + "selectAllFiles": "모든 파일 선택", + "unselectTracked": "추적된 변경 선택 해제", + "selectTracked": "추적된 변경 선택", + "unselectUntracked": "추적되지 않은 파일 선택 해제", + "selectUntracked": "추적되지 않은 파일 선택" + }, + "loading": "로딩 중...", + "selectionCount": "{selected} / {total}개 파일", + "emptyFiles": "변경된 파일이 없습니다", + "trackedChanges": "추적된 변경 ({count})", + "untrackedFiles": "추적되지 않은 파일 ({count})", + "commitMessage": "커밋 메시지", + "commitMessagePlaceholder": "커밋 메시지 입력...", + "commitButton": "커밋 ({count})", + "commitAndPushButton": "커밋 후 푸시 ({count})", + "head": "HEAD", + "workingTree": "작업 트리", + "clickFileToDiff": "파일 이름을 클릭해 diff를 확인하세요", + "loadingDiff": "diff 로딩 중..." + }, + "pushWindow": { + "title": "코드 푸시", + "noUnpushedCommits": "푸시되지 않은 커밋이 없습니다", + "noRemoteConfigured": "Git 원격이 구성되지 않았습니다\n「원격 관리」에서 원격을 추가하세요", + "newBranchNoPushedCommits": "새 브랜치 — 푸시하여 원격 추적 브랜치 생성", + "unpushed": "미푸시", + "selectFileToViewDiff": "파일을 선택하여 차이 보기", + "before": "변경 전", + "after": "변경 후", + "push": "푸시", + "toasts": { + "pushSuccess": "푸시 성공", + "pushFailed": "푸시 실패", + "upstreamSet": "원격 추적 브랜치가 설정되었습니다", + "upstreamSetAndPushed": "원격 추적 브랜치 설정 및 {count}개 커밋 푸시 완료", + "noCommitsToPush": "푸시할 커밋이 없습니다", + "pushedCommits": "{count}개 커밋 푸시 완료" + } + }, + "gitLogTab": { + "filesTitle": "파일", + "expandAllFiles": "모든 파일 펼치기", + "collapseAllFiles": "모든 파일 접기", + "workspace": "작업 공간", + "retry": "다시 시도", + "noCommitsFound": "커밋을 찾을 수 없습니다", + "notAGitRepoTitle": "Git 저장소가 아닙니다", + "notAGitRepoHint": "위의 브랜치 메뉴에서 Git을 초기화하거나 기존 저장소를 여세요.", + "hash": "해시", + "copyHash": "해시 복사", + "copyMessage": "메시지 복사", + "showMore": "더보기", + "showLess": "접기", + "author": "작성자", + "noFileChangeDetails": "파일 변경 상세 정보가 없습니다.", + "loadingFiles": "파일 로딩 중…", + "branchesTitle": "브랜치", + "loadingBranches": "브랜치 로딩 중...", + "noContainingBranches": "포함하는 브랜치를 찾을 수 없습니다.", + "newBranch": "새 브랜치...", + "resetToHere": "여기로 리셋", + "resetDisabledReasonNotCurrentBranchView": "현재 브랜치 보기에서만 사용할 수 있습니다", + "copyFullCommitHashAria": "전체 커밋 해시 {hash} 복사", + "pushStatus": { + "pushed": "원격에 푸시됨", + "notPushed": "원격에 푸시되지 않음", + "unknown": "푸시 상태 알 수 없음 (upstream 미설정)" + }, + "time": { + "monthsAgo": "{count, plural, one {#개월 전} other {#개월 전}}", + "daysAgo": "{count, plural, one {#일 전} other {#일 전}}", + "hoursAgo": "{count, plural, one {#시간 전} other {#시간 전}}", + "minsAgo": "{count, plural, one {#분 전} other {#분 전}}", + "justNow": "방금 전" + }, + "toasts": { + "createdAndSwitchedNewBranch": "새 브랜치를 생성하고 전환했습니다", + "newBranchFromCommit": "{name} ({shortHash}에서 생성)", + "createBranchFailed": "브랜치 생성에 실패했습니다", + "openPushWindowFailed": "푸시 창을 열지 못했습니다", + "resetSuccess": "리셋 완료", + "resetSuccessDescription": "{branch}을(를) {mode}로 {shortHash}에 리셋했습니다", + "resetFailed": "리셋 실패" + }, + "authorFilter": { + "label": "작성자", + "searchPlaceholder": "작성자 검색", + "noAuthors": "작성자를 찾을 수 없습니다", + "you": "나", + "filterByAuthorAria": "작성자별로 커밋 필터링", + "filterByQuery": "\"{query}\"(으)로 필터링", + "clearAuthorFilterAria": "작성자 필터 지우기", + "recent": "최근", + "matchingAuthors": "일치하는 작성자", + "removeFromRecent": "최근에서 {name} 제거" + }, + "branchSelector": { + "label": "브랜치", + "head": "HEAD", + "headHint": "현재 브랜치를 따라감", + "headHintWithBranch": "현재 브랜치를 따라감 ({branch})", + "searchBranch": "브랜치 검색...", + "noBranches": "브랜치 없음", + "selectBranchPlaceholder": "브랜치 선택...", + "localBranches": "로컬 브랜치", + "current": "현재", + "remoteBranches": "원격 브랜치", + "refreshCommitHistory": "커밋 히스토리 새로고침", + "clearBranchFilterAria": "브랜치 필터 지우기" + }, + "dialogs": { + "newBranchTitle": "새 브랜치", + "newBranchDescription": "커밋 {shortHash}를 최신 커밋으로 하여 새 브랜치를 생성합니다.", + "branchNamePlaceholder": "브랜치 이름", + "reset": { + "title": "현재 브랜치를 이 커밋으로 리셋", + "branchLabel": "브랜치", + "targetLabel": "대상 커밋", + "messageLabel": "커밋 메시지", + "modeLabel": "리셋 모드", + "confirmButton": "리셋", + "modes": { + "soft": { + "label": "--soft", + "description": "HEAD와 현재 브랜치 포인터를 대상 커밋으로 이동합니다.\nIndex와 Working Tree는 변경하지 않습니다.\n되돌려진 커밋의 변경 사항은 staged 상태로 유지됩니다." + }, + "mixed": { + "label": "--mixed (기본값)", + "description": "HEAD를 대상 커밋으로 이동합니다.\nIndex를 대상 커밋으로 되돌리고 Working Tree 변경은 유지합니다.\n변경 사항은 staged에서 unstaged로 바뀝니다." + }, + "hard": { + "label": "--hard", + "description": "HEAD를 이동하고 Index와 Working Tree를 모두 대상 커밋으로 되돌립니다.\n대상 커밋 이후의 추적된 로컬 변경은 삭제됩니다.\n파괴적인 작업입니다." + }, + "keep": { + "label": "--keep", + "description": "HEAD를 대상 커밋으로 이동하면서 가능한 한 로컬 변경을 유지합니다.\n충돌하지 않는 변경만 보존됩니다.\n충돌이 감지되면 작업 보호를 위해 리셋이 중단됩니다." + } + } + } + }, + "moreActions": "추가 Git 작업" + }, + "gitChangesTab": { + "workspace": "작업 공간", + "noChanges": "로컬 변경 사항이 없습니다", + "notAGitRepoTitle": "Git 저장소가 아닙니다", + "notAGitRepoHint": "위의 브랜치 메뉴에서 Git을 초기화하거나 기존 저장소를 여세요.", + "trackedChanges": "추적된 변경 ({count})", + "untrackedFiles": "추적되지 않은 파일 ({count})", + "expandTracked": "추적된 변경 펼치기", + "collapseTracked": "추적된 변경 접기", + "expandUntracked": "추적되지 않은 파일 펼치기", + "collapseUntracked": "추적되지 않은 파일 접기", + "showRemainingItems": "나머지 {count}개 표시", + "actions": { + "commitCode": "코드 커밋", + "rollback": "롤백", + "addToVcs": "VCS에 추가", + "delete": "삭제", + "moreActions": "추가 Git 작업", + "addAllToVcs": "모두 VCS에 추가", + "rollbackAll": "모두 롤백", + "refresh": "새로 고침" + }, + "toasts": { + "noAddableFilesInDir": "이 디렉터리에는 VCS에 추가할 수 있는 변경 파일이 없습니다", + "noRollbackFilesInDir": "이 디렉터리에는 롤백할 수 있는 변경 파일이 없습니다", + "addedToVcs": "{name}을(를) VCS에 추가했습니다", + "addToVcsFailed": "VCS에 추가하지 못했습니다", + "openCommitWindowFailed": "커밋 창을 열지 못했습니다", + "rolledBack": "{name}을(를) 롤백했습니다", + "rollbackFailed": "롤백에 실패했습니다", + "addedFilesToVcs": "{count, plural, one {#개 파일을 VCS에 추가} other {#개 파일을 VCS에 추가}}", + "rolledBackFiles": "{count, plural, one {#개 파일 롤백} other {#개 파일 롤백}}", + "deleted": "{name}이(가) 삭제되었습니다", + "deleteFailed": "삭제에 실패했습니다", + "deletedFiles": "{count}개 파일을 삭제했습니다", + "noDeletableFilesInDir": "이 디렉터리에서 삭제할 수 있는 변경된 파일이 없습니다", + "commitFailed": "커밋 실패" + }, + "directoryDialog": { + "descriptionAdd": "디렉터리 {path} 아래에서 VCS에 추가할 파일을 선택하세요.", + "descriptionRollback": "디렉터리 {path} 아래에서 롤백할 파일을 선택하세요.", + "descriptionDelete": "디렉터리 {path} 아래에서 삭제할 파일을 선택하세요. 이 작업은 되돌릴 수 없습니다.", + "descriptionFallback": "계속 진행할 파일을 선택하세요.", + "selectionCount": "{selected} / {total} 선택됨", + "selectAll": "모두 선택", + "unselectAll": "모두 선택 해제", + "loadingCandidates": "디렉터리 변경 사항 로딩 중...", + "noOperableFiles": "작업 가능한 파일이 없습니다" + }, + "rollbackConfirm": { + "title": "롤백 확인", + "descriptionWithTarget": "{kind} \"{name}\"의 로컬 변경 사항을 롤백할까요?", + "descriptionFallback": "로컬 변경 사항을 롤백할까요?", + "kindDirectory": "디렉터리", + "kindFile": "파일" + }, + "deleteConfirm": { + "title": "삭제 확인", + "descriptionWithTarget": "{kind} \"{name}\"을(를) 삭제할까요? 이 작업은 되돌릴 수 없습니다.", + "descriptionFallback": "이 작업은 되돌릴 수 없습니다.", + "kindDirectory": "디렉터리", + "kindFile": "파일" + }, + "quickCommit": { + "placeholder": "커밋 메시지 (Enter로 커밋)" + } + }, + "tabContext": { + "loadingConversation": "로딩 중...", + "untitledConversation": "제목 없는 대화", + "newConversation": "새 대화" + }, + "fileTreeTab": { + "workspace": "작업 공간", + "retry": "다시 시도", + "git": "Git", + "openInFileManager": "파일 관리자에서 열기", + "openInFinder": "Finder에서 열기", + "openInExplorer": "Explorer에서 열기", + "attachToCurrentSession": "세션에 추가", + "compareWithBranch": "브랜치와 비교...", + "reloadFromDisk": "디스크에서 다시 불러오기", + "new": "새로 만들기", + "newFile": "파일", + "newDirectory": "디렉터리", + "openIn": "열기", + "openInTerminal": "터미널에서 열기", + "linkedFolder": "연결된 폴더", + "copyPath": "경로 복사", + "upload": "파일/폴더 업로드", + "download": "파일 다운로드", + "downloadAsZip": "ZIP으로 다운로드", + "actions": { + "select": "선택", + "unselect": "선택 해제", + "commitCode": "코드 커밋", + "rollback": "롤백", + "addToVcs": "VCS에 추가" + }, + "aria": { + "selectPath": "{action}: {path}" + }, + "toasts": { + "openDirectoryFailed": "디렉터리를 열지 못했습니다", + "openBuiltinTerminalFailed": "내장 터미널을 열 수 없습니다", + "openCommitWindowFailed": "커밋 창을 열지 못했습니다", + "noAddableFilesInDir": "이 디렉터리에는 VCS에 추가할 수 있는 변경 파일이 없습니다", + "noRollbackFilesInDir": "이 디렉터리에는 롤백할 수 있는 변경 파일이 없습니다", + "addedToVcs": "{name}을(를) VCS에 추가했습니다", + "addToVcsFailed": "VCS에 추가하지 못했습니다", + "loadBranchesFailed": "브랜치를 불러오지 못했습니다", + "renameFailed": "이름 변경에 실패했습니다", + "moveFailed": "이동에 실패했습니다", + "deleteFailed": "삭제에 실패했습니다", + "rolledBack": "{name}을(를) 롤백했습니다", + "rollbackFailed": "롤백에 실패했습니다", + "addedFilesToVcs": "{count, plural, one {#개 파일을 VCS에 추가했습니다} other {#개 파일을 VCS에 추가했습니다}}", + "rolledBackFiles": "{count, plural, one {#개 파일을 롤백했습니다} other {#개 파일을 롤백했습니다}}", + "savedAsCopy": "사본으로 저장했습니다", + "saveCopyFailed": "사본으로 저장하지 못했습니다", + "watchStartFailed": "파일 감시 시작에 실패했습니다", + "createFailed": "생성 실패", + "downloadFailed": "{name} 다운로드 실패", + "downloadSaved": "{name} 다운로드 완료", + "pathCopied": "경로가 복사되었습니다", + "copyPathFailed": "경로 복사에 실패했습니다" + }, + "createDialog": { + "newFile": "새 파일", + "newDirectory": "새 디렉터리", + "description": "새 {kind}의 이름을 입력하세요.", + "placeholderFile": "file-name.ext", + "placeholderDirectory": "folder-name" + }, + "renameDialog": { + "renameDirectory": "디렉터리 이름 변경", + "renameFile": "파일 이름 변경", + "description": "새 이름을 입력하세요(이름만, 경로 제외).", + "placeholderDirectory": "새-폴더-이름", + "placeholderFile": "새-파일-이름.ext" + }, + "uploadDialog": { + "title": "작업 공간에 업로드", + "description": "필요하면 업로드 위치를 변경한 다음 파일이나 폴더를 추가하세요.", + "workspaceRoot": "작업 공간 루트", + "targetPathLabel": "업로드 위치", + "targetPathHint": "실제 경로: {path}", + "dropHint": "파일 또는 폴더를 여기에 끌어오거나 아래 버튼을 사용하세요", + "dropHintActive": "놓으면 대기열에 추가됩니다", + "selectFiles": "파일 선택", + "selectFolder": "폴더 선택", + "startUpload": "업로드 시작", + "clearQueue": "완료된 항목 지우기", + "removeItem": "대기열에서 제거", + "retry": "다시 시도", + "dropZoneAria": "파일을 여기에 드롭하거나 Enter 키로 찾아보기", + "folderEmpty": "드롭한 폴더에서 파일을 찾을 수 없습니다", + "summary": "합계: {total} · 성공: {succeeded} · 실패: {failed}", + "status": { + "pending": "대기 중", + "uploading": "업로드 중", + "success": "완료", + "error": "실패", + "cancelled": "취소됨" + } + }, + "directoryDialog": { + "descriptionAdd": "디렉터리 {path} 아래에서 VCS에 추가할 파일을 선택하세요.", + "descriptionRollback": "디렉터리 {path} 아래에서 롤백할 파일을 선택하세요.", + "descriptionFallback": "계속할 파일을 선택하세요.", + "selectionCount": "{selected} / {total}개 파일 선택됨", + "selectAll": "모두 선택", + "unselectAll": "모두 선택 해제", + "loadingCandidates": "디렉터리 변경 사항을 불러오는 중...", + "noOperableFiles": "작업 가능한 파일이 없습니다" + }, + "compareDialog": { + "title": "브랜치와 비교", + "descriptionWithTarget": "브랜치를 선택하고 {kind} {path}와(과) 비교하세요", + "descriptionFallback": "비교할 브랜치를 선택하세요.", + "kindDirectory": "디렉터리", + "kindFile": "파일", + "filterPlaceholder": "브랜치 필터링 (예: main / origin/main)", + "singleClickHint": "브랜치를 클릭하면 바로 비교합니다", + "loadingBranches": "브랜치를 불러오는 중...", + "recentBranches": "최근 브랜치 ({count})", + "noCurrentBranch": "현재 브랜치 없음", + "localBranches": "로컬 브랜치 ({count})", + "remoteBranches": "원격 브랜치 ({count})", + "noMatchingBranches": "일치하는 브랜치가 없습니다" + }, + "externalConflictDialog": { + "title": "외부 파일 변경 감지됨", + "descriptionWithPath": "파일 {path} 이(가) 디스크에서 변경되었고 현재 편집 내용은 저장되지 않았습니다.", + "descriptionFallback": "현재 파일이 디스크에서 변경되었고 현재 편집 내용은 저장되지 않았습니다.", + "compare": "비교", + "savingCopy": "사본 저장 중...", + "saveAsCopy": "사본으로 저장", + "reload": "다시 불러오기" + }, + "deleteConfirm": { + "title": "삭제 확인", + "descriptionWithTarget": "{kind} \"{name}\"을(를) 삭제할까요? 이 작업은 되돌릴 수 없습니다.", + "descriptionFallback": "이 작업은 되돌릴 수 없습니다.", + "kindDirectory": "디렉터리", + "kindFile": "파일" + }, + "rollbackConfirm": { + "title": "롤백 확인", + "descriptionWithTarget": "파일 \"{name}\"의 로컬 변경 사항을 롤백할까요?", + "descriptionFallback": "이 파일의 로컬 변경 사항을 롤백할까요?" + }, + "terminalTitle": "터미널 · {name}" + }, + "commandDropdown": { + "loading": "로딩 중...", + "addCommand": "명령 추가", + "manageCommands": "명령 관리...", + "runCommandTitle": "실행: {command}", + "stopCommandTitle": "중지: {command}", + "manageDialog": { + "title": "명령 관리", + "empty": "아직 명령이 없습니다", + "noResults": "일치하는 명령이 없습니다", + "searchPlaceholder": "명령 검색", + "newCommand": "새 명령", + "nameLabel": "이름", + "commandLabel": "명령", + "dragSort": "드래그하여 정렬", + "dragSortCommand": "{name} 드래그하여 정렬", + "orderFailed": "명령 순서 저장에 실패했습니다", + "loadFailed": "명령을 불러오지 못했습니다", + "saveFailed": "명령을 저장하지 못했습니다", + "deleteFailed": "명령을 삭제하지 못했습니다", + "confirmDelete": { + "title": "명령을 삭제하시겠습니까?", + "message": "\"{name}\"을(를) 제거합니다. 이 작업은 되돌릴 수 없습니다." + } + } + }, + "workspaceContext": { + "confirmCloseDirtyTab": "저장하지 않고 \"{title}\" 탭을 닫을까요?", + "confirmCloseOtherDirtyTabs": "저장되지 않은 변경 사항이 있는 다른 탭을 닫을까요?", + "confirmCloseAllDirtyTabs": "저장되지 않은 변경 사항이 있는 모든 탭을 닫을까요?", + "unableLoadContent": "콘텐츠를 불러올 수 없습니다.\n\n{message}", + "previewRequestTimedOut": "미리보기 요청 시간이 초과되었습니다", + "diffRequestTimedOut": "Diff 요청 시간이 초과되었습니다", + "branchCompareRequestTimedOut": "브랜치 비교 요청 시간이 초과되었습니다", + "commitDiffRequestTimedOut": "커밋 Diff 요청 시간이 초과되었습니다", + "saveRequestTimedOut": "저장 요청 시간이 초과되었습니다", + "reloadRequestTimedOut": "다시 불러오기 요청 시간이 초과되었습니다", + "noChanges": "변경 사항이 없습니다.", + "noDiffOutput": "Diff 출력이 없습니다.", + "diffTitleWorkspace": "Diff · 워크스페이스", + "diffDescriptionWorkingTree": "작업 트리 (HEAD)", + "diffTitleFile": "차이 · {name}", + "compareTitleFile": "비교 · {name}", + "compareTitleBranch": "비교 · {branch}", + "compareDescriptionPath": "{path} · {branch}와 비교", + "compareDescriptionBranch": "{branch}와 비교", + "diffTitleCommitFile": "차이 · {name} @ {hash}", + "diffTitleCommit": "차이 · {hash}", + "diffDescriptionCommitPath": "{path} · 커밋 {commit}", + "diffDescriptionCommit": "커밋 {commit}", + "diffTitleConflictFile": "충돌 · {name}", + "diffDescriptionConflict": "{path} · 디스크 vs 저장되지 않음" + }, + "chat": { + "acpConnections": { + "actions": { + "openAgentsSettings": "에이전트 설정 열기", + "retry": "다시 시도" + }, + "agentsSetupHint": "설정 > 에이전트를 열어 설치를 관리하세요.", + "withSetupHint": "{message}\n{hint}", + "blocked": { + "missingConfig": "현재 에이전트 구성을 읽을 수 없습니다.", + "disabled": "{agent}은(는) 에이전트 설정에서 비활성화되어 있습니다. 연결 전에 활성화하세요.", + "unavailable": "{agent}은(는) 현재 플랫폼에서 사용할 수 없습니다.", + "sdkMissing": "{agent} SDK가 설치되어 있지 않습니다", + "adapterMissing": "{agent}의 ACP 어댑터가 설치되어 있지 않습니다" + }, + "backendErrors": { + "initializeTimeout": "{agent} 연결 핸드셰이크가 시간 초과되었습니다(60초 동안 응답 없음). 설정을 열어 에이전트 및 네트워크 구성을 확인하세요.", + "mcpRejectedByAgent": "codeg의 MCP 동반 프로세스를 전달하는 동안 {agent}이(가) 세션을 거부했습니다: {message} 이 에이전트가 MCP를 지원하지 않는다면 설정에서 ‘MCP 지원’을 끄고 다시 연결하세요.", + "processExited": "{agent} 프로세스가 예기치 않게 종료되었습니다.", + "spawnFailed": "{agent} 시작 실패: {message}", + "downloadFailed": "{agent} 다운로드 실패: {message}", + "sessionLoadResourceNotFound": "{agent} 세션 불러오기에 실패했습니다. 다시 불러와 재시도하거나 새 대화를 시작하세요.", + "sessionLoadUnavailable": "{agent}에서 이 세션을 복원할 수 없습니다. 세션이 종료되었거나 에이전트가 중지되었을 수 있습니다. 다시 불러와 재시도하거나 새 대화를 시작하세요.", + "turnFailedRefusal": "{agent}이(가) 이번 턴을 계속하지 않았습니다. 백엔드나 게이트웨이 오류일 수 있습니다. 에이전트 로그를 확인하세요.", + "turnFailedMaxTokens": "{agent}이(가) 이번 턴의 최대 토큰 한도에 도달했습니다.", + "turnFailedMaxTurnRequests": "{agent}이(가) 이번 턴에서 허용된 최대 요청 수에 도달했습니다.", + "turnFailedUnknown": "{agent}이(가) 알 수 없는 중지 사유로 턴을 종료했습니다.", + "grokModelSwitchIncompatibleAgent": "{agent}은(는) 기존 대화에서는 해당 모델로 전환할 수 없습니다. 새 세션을 시작하여 사용하세요.", + "turnFailedEmpty": "{agent}이(가) 어떤 응답도 생성하지 않고 턴을 종료했습니다.", + "turnFailedEmptyProtocol": "{agent}의 출력을 codeg가 구문 분석할 수 없습니다. 에이전트 버전이 프로토콜과 맞지 않을 수 있습니다.", + "turnFailedEmptyMetadata": "{agent}이(가) 이번 턴에 상태 업데이트(계획 / 모드 / 사용량)만 보내고 응답은 없었습니다.", + "detailsInAlerts": "상태 표시줄의 알림을 열고 세부 정보를 펼치면 에이전트 출력을 확인할 수 있습니다." + }, + "unableReadAgentConfig": "에이전트 구성을 읽을 수 없습니다: {message}", + "connectFailedTitle": "{agent} 연결 실패", + "toolFallbackTitle": "도구", + "eventErrorTitle": "에이전트 오류", + "notificationTurnComplete": "{agent} 응답이 완료되었습니다", + "notificationError": "{agent} 오류: {message}", + "claudeApiRetry": { + "fallbackError": "authentication_failed", + "retryingWithMax": "재시도 중 {attempt}/{max}", + "retryingAttempt": "{attempt}번째 재시도 중", + "retrying": "재시도 중", + "nextRetryIn": "{seconds}초 후 재시도", + "line": "{error}{status} · {retry}", + "lineWithDelay": "{error}{status} · {retry}, {delay}", + "httpStatus": " (HTTP {status})" + }, + "configOptionAdjusted": "{agent}이(가) {option}을(를) {requested} 대신 {actual}(으)로 설정했습니다" + }, + "connectionLifecycle": { + "tasks": { + "connectingTitle": "{agent}에 연결 중", + "connectingDescription": "연결을 설정하는 중", + "loadingSelectorsTitle": "{agent} 선택자 불러오는 중", + "loadingSelectorsDescription": "모드 및 세션 구성 옵션을 가져오는 중", + "initSessionTitle": "{agent} 세션 초기화 중", + "initSessionDescription": "세션 생성 및 설정 불러오는 중" + }, + "errors": { + "connectionFailed": "연결 실패", + "sendPromptFailed": "메시지 전송에 실패했습니다: {error}" + } + }, + "shared": { + "attachedResources": "첨부된 리소스", + "toolCallFailed": "도구 호출 실패" + }, + "messageThread": { + "emptyTitle": "아직 메시지가 없습니다", + "emptyDescription": "대화를 시작하면 여기에서 메시지를 볼 수 있습니다" + }, + "chatInput": { + "connecting": "연결 중...", + "agentResponding": "{agent} 응답 중...", + "sendMessage": "메시지 보내기..." + }, + "messageInput": { + "askAnything": "무엇이든 물어보세요...", + "removeAttachmentAria": "{name} 제거", + "attachFiles": "파일 첨부", + "addActions": "추가", + "quickMessages": "빠른 메시지", + "quickMessagesEmpty": "빠른 메시지가 없습니다", + "quickMessagesLoading": "불러오는 중...", + "pasteAsPlainText": "일반 텍스트로 붙여넣기", + "cut": "잘라내기", + "copy": "복사", + "selectAll": "모두 선택", + "pasteUnavailable": "클립보드를 읽을 수 없습니다. Ctrl/⌘V로 붙여넣으세요.", + "clipboardWriteFailed": "클립보드에 쓸 수 없습니다. 키보드 단축키를 사용하세요.", + "quickMessageUntitled": "제목 없음", + "liveFeedback": "라이브 피드백", + "liveFeedbackDisabledHint": "에이전트가 작업 중일 때 보낼 수 있습니다", + "dropFilesToAttach": "파일을 놓아 첨부", + "loadingSettings": "설정 불러오는 중...", + "loadingMode": "모드 불러오는 중...", + "modeLabel": "모드", + "toggleOn": "켬", + "toggleOff": "끔", + "agentSettings": "에이전트 설정", + "searchModel": "모델 검색...", + "searchModelAria": "모델 검색", + "modelListLabel": "모델", + "noModels": "모델을 찾을 수 없습니다", + "cancel": "취소", + "send": "보내기", + "forkAndSend": "포크 & 전송", + "queueMessage": "대기열에 추가", + "steerIntoTurn": "현재 턴에 삽입", + "steerQueuedInstead": "대신 대기열에 추가되었습니다. 다음 턴에 전송됩니다.", + "steerFailed": "현재 턴에 삽입하지 못했습니다", + "steerAttachmentsUnsupported": "텍스트만 지원됩니다. 첨부 파일이 있는 초안은 대기열을 이용하세요.", + "slashCommands": "슬래시 명령", + "slashSearchPlaceholder": "명령 검색...", + "slashSearchEmpty": "일치하는 명령이 없습니다", + "experts": "전문가", + "office": "일상 업무", + "research": "과학 연구", + "attachLocalUpload": "로컬 파일 첨부", + "attachServerFile": "서버 파일 첨부", + "attachUploadTooLarge": "{names}이(가) {limit}MB 업로드 한도를 초과하여 건너뛰었습니다.", + "attachUploadFailed": "{names} 업로드 실패.", + "attachUploadNotAFile": "{names} 은(는) 일반 파일이 아니므로(디렉터리 또는 특수 파일) 건너뛰었습니다.", + "attachUploadQuotaExceeded": "서버 업로드 저장 공간이 부족하여 {names} 을(를) 업로드하지 못했습니다.", + "attachUploadInProgress": "이미지가 아직 업로드 중입니다. 잠시 후 다시 시도하세요.", + "mentionEmpty": "일치하는 항목 없음", + "mentionLoading": "검색 중…", + "mentionListLabel": "멘션", + "mentionMore": "결과가 더 있습니다. 계속 입력하여 필터링하세요", + "mentionCount": "{count, plural, other {결과 #개}}", + "mentionGroupFile": "파일", + "mentionGroupAgent": "에이전트", + "mentionGroupSession": "세션", + "mentionGroupCommit": "커밋", + "mentionGroupSkill": "스킬" + }, + "messageQueue": { + "addToQueue": "대기열에 추가", + "saveEdit": "저장", + "cancelEdit": "편집 취소", + "editItem": "편집", + "deleteItem": "삭제" + }, + "welcomeInputPanel": { + "agentsSettingsPath": "설정 > 에이전트", + "autoConnectFallback": "{path}을(를) 열어 설치를 관리하세요.", + "autoConnectAppend": "{message}. {path}을(를) 열어 설치를 관리하세요.", + "enableAgentFirstPlaceholder": "세션을 시작하기 전에 최소 한 개의 에이전트를 활성화하세요...", + "prepareSessionFailed": "채팅 세션을 준비하지 못했습니다. 다시 시도해 주세요.", + "createConversationFailed": "대화를 만들지 못했습니다. 다시 시도해 주세요.", + "askAnythingPlaceholder": "무엇이든 물어보세요...", + "agentNotInstalled": "{agent}이(가) 설치되지 않았습니다 · 클릭하여 Agents 설정에서 설치하세요", + "agentAdapterNotInstalled": "{agent}의 ACP 어댑터가 설치되지 않았습니다(사용 중인 CLI와는 별개) · 클릭하여 Agents 설정에서 설치하세요" + }, + "welcomePanel": { + "greeting": "오늘은 무엇을 해볼까요?", + "tips": { + "tileTabs": "대화 탭을 우클릭하고 '바둑판 표시'를 선택하면 여러 세션을 나란히 비교할 수 있습니다", + "pinTab": "대화 탭을 더블클릭하면 고정되어 새로 열린 세션이 자동으로 대체하지 않습니다", + "shortcutsNewSearch": "{newConversation}로 새 대화를 열고, {searchConversations}로 기록을 검색할 수 있습니다", + "slashAtMention": "입력창에서 /를 입력하면 슬래시 명령, @를 입력하면 프로젝트 내 파일을 참조할 수 있습니다", + "pasteDropFiles": "스크린샷을 붙여넣거나 파일을 입력창에 드롭하면 바로 첨부됩니다", + "queueMessage": "에이전트가 응답 중일 때도 계속 입력하면 다음 메시지가 대기열에 들어가 응답 후 자동 전송됩니다", + "draftAutoSave": "보내지 않은 초안은 대화별로 자동 저장되어 돌아왔을 때 복원됩니다", + "forkSend": "전송 버튼의 드롭다운에서 '분기 후 전송'을 선택하면 현재 지점에서 새 탭으로 분기할 수 있습니다", + "exportConversation": "대화 내용을 우클릭하면 Markdown / HTML / 이미지로 내보낼 수 있습니다", + "chatChannels": "'설정 → 채팅 채널'에서 Telegram / Lark / WeChat을 연결하면 휴대폰에서 이어서 사용할 수 있습니다", + "shortcutsAuxPanel": "{toggleAuxPanel}로 오른쪽 패널을 열어 이번 세션에서 변경된 파일과 Git 변경 사항을 확인할 수 있습니다", + "shortcutsTerminalSidebar": "{toggleTerminal}로 내장 터미널, {toggleSidebar}로 사이드바를 토글할 수 있습니다", + "customShortcuts": "모든 단축키는 '설정 → 단축키'에서 자유롭게 변경할 수 있습니다", + "webService": "'설정 → 웹 서비스'를 켜면 팀원이 브라우저로 같은 codeg에 접속할 수 있습니다", + "fusionMode": "파일이나 diff를 열면 대화 옆에 자동으로 표시됩니다.", + "quickMessages": "입력창 옆 + 버튼에서 '빠른 메시지'를 선택하면 저장된 스니펫을 한 번에 삽입할 수 있습니다('설정 → 빠른 메시지'에서 관리)", + "experts": "+ 버튼의 '전문가 스킬' 메뉴에서 디버그 / 기획 등 사전 정의된 역할을 한 번에 불러올 수 있습니다", + "taskBoard": "할 일은 작업을 끝까지 처리합니다. 에이전트가 전용 워크트리에서 작업하고, 여러분은 diff를 검토한 뒤 병합합니다.", + "automations": "자동화는 저장한 프롬프트를 일정에 따라 실행합니다(매일 밤 리뷰 등). 실행마다 전용 워크트리를 쓸 수도 있습니다.", + "tokenUsage": "상태 표시줄의 대화 수를 클릭하면 토큰 사용량이 열립니다. 날짜·에이전트·모델·폴더별 사용량을 확인할 수 있습니다.", + "mentionTargets": "@는 파일만 참조하는 것이 아닙니다. 다른 에이전트를 멘션해 하위 작업을 맡기거나, 지난 세션·커밋·스킬을 참조할 수 있습니다.", + "splitGroups": "탭을 우클릭해 「오른쪽으로 분할」 또는 「아래로 분할」을 고르면 두 대화를 각각의 창에 열어 둘 수 있습니다.", + "worktrees": "브랜치 버튼에서 「새 워크트리」를 고르면 여러 에이전트가 같은 저장소에서 서로의 파일을 덮어쓰지 않고 동시에 작업할 수 있습니다.", + "importSessions": "터미널에서 이미 실행한 세션이 있다면 폴더 메뉴의 「로컬 세션 가져오기」로 그 기록을 codeg에 가져올 수 있습니다.", + "subSessions": "에이전트가 위임하면 하위 세션이 사이드바에서 상위 세션 아래에 중첩되어 표시됩니다. 행을 펼치면 각각이 무엇을 했는지 확인할 수 있습니다.", + "liveFeedback": "「+」 메뉴의 라이브 피드백은 에이전트가 진행 중인 턴에 메모를 끼워 넣습니다. 작업을 끊지 않아도 됩니다.", + "skillPacks": "설정 → 스킬 팩에는 코딩 전문가, 과학 연구, 오피스 스킬이 묶여 있습니다. 에이전트별로 켜고 끌 수 있습니다.", + "modelProviders": "설정 → 모델 제공업체에서 직접 API 키나 엔드포인트를 등록하면, 입력창에서 바로 모델을 고를 수 있습니다.", + "workspaceBackground": "설정 → 외관에서 작업 공간 배경 이미지, 패널 불투명도, 앱 글꼴을 바꿀 수 있습니다." + }, + "quickActions": { + "excel": "Excel 통합 문서", + "excelDesc": "데이터 표, 수식, 차트", + "word": "Word 문서", + "wordDesc": "보고서, 편지, 메모", + "ppt": "프레젠테이션", + "pptDesc": "전문 디자인 슬라이드", + "pitchDeck": "피치덱", + "pitchDeckDesc": "핵심 지표가 담긴 투자 자료", + "morph": "Morph 애니메이션", + "morphDesc": "영화 같은 슬라이드 전환", + "morph3d": "3D Morph", + "morph3dDesc": "3D 모델과 카메라 무빙", + "academic": "학술 논문", + "academicDesc": "인용과 구조를 갖춘 연구 논문", + "financial": "재무 모델", + "financialDesc": "재무제표, DCF, 예측", + "dashboard": "데이터 대시보드", + "dashboardDesc": "데이터로 KPI와 분석 생성", + "prompts": { + "excel": "다음 요구 사항으로 Excel 통합 문서를 만들어 주세요:\n\n[데이터, 표, 수식, 차트를 여기에 설명]", + "word": "다음 요구 사항으로 Word 문서를 만들어 주세요:\n\n[문서 내용, 구조, 서식을 여기에 설명]", + "ppt": "다음 요구 사항으로 PowerPoint 프레젠테이션을 만들어 주세요:\n\n[슬라이드, 내용, 디자인을 여기에 설명]", + "pitchDeck": "다음 요구 사항으로 투자 피치덱을 만들어 주세요:\n\n[회사, 투자 라운드, 핵심 지표를 여기에 설명]", + "morph": "Morph 전환 애니메이션이 있는 프레젠테이션을 만들어 주세요:\n\n[발표 주제와 원하는 시각 효과를 여기에 설명]", + "morph3d": "GLB 모델과 카메라 무빙이 있는 3D Morph 프레젠테이션을 만들어 주세요:\n\n[주제와 3D 비주얼 콘셉트를 여기에 설명]", + "academic": "다음 요구 사항으로 Word 학술 논문을 작성해 주세요:\n\n[연구 주제, 방법론, 주요 결과를 여기에 설명]", + "financial": "다음 요구 사항으로 Excel 재무 모델을 만들어 주세요:\n\n[재무제표, 예측, 분석을 여기에 설명]", + "dashboard": "다음 요구 사항으로 Excel 데이터 대시보드를 만들어 주세요:\n\n[데이터 소스, KPI, 차트를 여기에 설명]", + "scientific-brainstorming": "연구 방향을 브레인스토밍해 주세요. 학제 간 연결을 탐색하고 가정을 검토하며 유망한 공백을 찾습니다. 탐색 중인 분야: ", + "hypothesis-generation": "이 관찰을 검증 가능한 가설로 바꿔 주세요. 명확한 예측, 그럴듯한 메커니즘, 검증 실험을 제시합니다. 내 관찰: ", + "experimental-design": "데이터 수집 전에 엄밀한 실험을 설계해 주세요. 설계, 무작위화, 대조, 교란 회피 방법을 포함합니다. 연구하려는 것: ", + "statistical-power": "필요한 표본 크기를 정해 주세요. 내 설계에 대해 검정력 분석(효과크기, 유의수준, 검정력)을 진행합니다. 세부 정보: ", + "statistical-analysis": "이 데이터를 제대로 분석해 주세요. 올바른 검정 선택, 가정 점검, 효과크기 보고, 결과 서술을 합니다. 내 데이터와 질문: ", + "exploratory-data-analysis": "내 데이터 파일을 탐색적으로 분석해 주세요. 구조, 품질, 주목할 패턴을 요약하고 다음 단계를 제안합니다. 파일: ", + "scientific-visualization": "출판 수준의 그림을 만들어 주세요. 명확한 배치, 정직한 오차 막대, 색각 이상을 고려한 팔레트, 저널 서식을 사용합니다. 보여주려는 것: ", + "scientific-critical-thinking": "이 연구나 주장을 비판적으로 평가해 주세요. 근거의 질을 평가하고 편향과 교란을 찾아 결론을 따져봅니다. 대상: ", + "paper-lookup": "학술 데이터베이스에서 관련 논문과 오픈액세스 전문을 찾고 재사용할 수 있는 인용도 제시해 주세요. 찾는 것: " + }, + "paper-lookup": "논문 검색", + "paper-lookupDesc": "10개 학술 API(PubMed, arXiv, OpenAlex, Crossref…)에서 논문·인용·오픈액세스 전문을 검색합니다.", + "scientific-critical-thinking": "비판적 사고", + "scientific-critical-thinkingDesc": "과학적 주장과 근거의 질을 평가 — 편향·교란을 찾고 GRADE 및 비뚤림 위험 프레임워크를 적용.", + "scientific-visualization": "과학적 시각화", + "scientific-visualizationDesc": "출판 수준 그림 — 다중 패널 배치, 유의성 주석, 저널별 서식.", + "exploratory-data-analysis": "탐색적 데이터 분석", + "exploratory-data-analysisDesc": "200종 이상 형식의 과학 데이터 파일을 자동 탐색하고 품질 지표와 보고서를 생성합니다.", + "statistical-analysis": "통계 분석", + "statistical-analysisDesc": "안내형 통계 분석 — 검정 선택, 가정 점검, 효과크기, APA 형식 보고.", + "statistical-power": "통계적 검정력", + "statistical-powerDesc": "표본 크기와 검정력 분석 — 필요한 대상 수, 최소 검출 가능 효과, 검정력 곡선.", + "experimental-design": "실험 설계", + "experimental-designDesc": "데이터 수집 전에 엄밀한 연구를 설계 — 무작위화, 블록화, 대조, 요인/DOE 배치.", + "hypothesis-generation": "가설 생성", + "hypothesis-generationDesc": "관찰을 검증 가능한 가설로 전환하고 예측·메커니즘·검증 실험을 제시합니다.", + "scientific-brainstorming": "과학적 브레인스토밍", + "scientific-brainstormingDesc": "열린 연구 아이디어 발상 — 학제 간 연결을 탐색하고 가정을 검토하며 연구 공백을 찾습니다.", + "tabs": { + "office": "일상 업무", + "coding": "코드 개발", + "research": "과학 연구" + }, + "coding": { + "brainstormingDesc": "구현 전 의도와 요구사항 탐색", + "debuggingDesc": "수정 제안 전에 근본 원인 파악", + "writingSkillsDesc": "재사용 가능한 스킬 생성·편집·검증" + }, + "notEnabled": { + "title": "‘{skill}’ 스킬이 아직 {agent}에서 활성화되지 않았습니다", + "description": "설정에서 활성화하면 여기서 사용할 수 있습니다.", + "action": "활성화하기", + "hint": "스킬이 비활성화됨" + }, + "scrollPrev": "이전 스킬 표시", + "scrollNext": "다음 스킬 표시" + } + }, + "agentSelector": { + "noEnabledAgents": "활성화된 에이전트가 없습니다", + "openAgentsSettings": "에이전트 설정 열기", + "notInstalled": "설치되지 않음", + "moreAgents": "에이전트 더 보기 ({count})" + }, + "subAgentOverlay": { + "title": "서브 에이전트", + "collapsedSummary": "서브 에이전트 {count}", + "collapseAria": "서브 에이전트 접기" + }, + "agentPlanOverlay": { + "title": "에이전트 계획", + "collapsePlanAria": "계획 접기", + "collapsedSummary": "계획 {completed}/{total}", + "status": { + "completed": "완료", + "inProgress": "진행 중", + "pending": "대기", + "unknown": "알 수 없음" + }, + "priority": { + "high": "높음", + "medium": "중간", + "low": "낮음", + "unknown": "알 수 없음" + } + }, + "permissionDialog": { + "subtitle": "에이전트가 이 턴을 계속하기 위한 권한을 요청합니다.", + "queuedCount": "{count}건 대기 중", + "kindFallbackTool": "도구", + "command": "명령", + "cwd": "작업 디렉터리: {cwd}", + "filesSummary": "파일: {count}", + "moreFiles": "+{count}개 파일 더", + "plan": "계획", + "allowedActions": "허용된 작업", + "targetMode": "대상 모드: {mode}", + "optionGrants": "각 옵션이 부여하는 권한", + "changeScopeSession": "이 세션", + "changeScopeProcess": "이 실행", + "changeScopeUser": "사용자 설정에 저장", + "changeScopeProject": "프로젝트 설정에 저장", + "changeScopeProjectLocal": "로컬 프로젝트 설정에 저장", + "changeScopePersistent": "영구 저장" + }, + "questionDialog": { + "title": "에이전트가 질문하고 있습니다", + "placeholder": "답변을 입력하세요...", + "send": "전송" + }, + "messageBranch": { + "previousBranchAria": "이전 브랜치", + "nextBranchAria": "다음 브랜치", + "pageOf": "{current} / {total}" + }, + "terminal": { + "title": "터미널", + "running": "실행 중" + }, + "reasoning": { + "thinking": "생각 중…", + "thoughtForFewSeconds": "생각함", + "thoughtForSeconds": "생각함" + }, + "linkSafety": { + "errorCannotOpen": "로컬 파일을 열 수 없습니다", + "errorNoWorkspace": "현재 활성화된 워크스페이스 폴더가 없습니다.", + "errorFailedOpen": "로컬 파일 열기 실패", + "errorFailedLink": "링크 열기 실패", + "errorUnsupportedLinkProtocol": "이 링크 프로토콜은 지원되지 않습니다." + }, + "fileActions": { + "openInFinder": "Finder에서 열기", + "openInExplorer": "Explorer에서 열기", + "openInFileManager": "파일 관리자에서 열기", + "copyRelativePath": "상대 경로 복사", + "copyAbsolutePath": "절대 경로 복사", + "pathCopied": "경로가 복사되었습니다", + "copyPathFailed": "경로 복사에 실패했습니다", + "openFailed": "로컬 파일 열기 실패" + }, + "messageList": { + "attachedResources": "첨부된 리소스", + "loading": "불러오는 중...", + "loadEarlier": "이전 메시지 불러오기", + "loadingEarlier": "이전 메시지를 불러오는 중…", + "error": "오류: {message}", + "errorTitle": "세션 불러오기 실패", + "errorActionReload": "다시 불러오기", + "errorActionNewSession": "새 대화", + "emptyConversation": "이 대화에는 메시지가 없습니다.", + "systemMessage": "시스템 메시지", + "copyMessage": "복사", + "copied": "복사됨", + "downloadImage": "이미지 다운로드", + "downloadFailed": "다운로드 실패: {message}", + "imageGeneration": "이미지 생성", + "imageGenerationPending": "이미지 생성 중…", + "imageGenerationFailed": "이미지 생성 실패", + "model": "모델", + "tokenStats": "토큰 사용량", + "tokenInput": "입력", + "tokenOutput": "출력", + "tokenCacheRead": "캐시 읽기", + "tokenCacheWrite": "캐시 쓰기", + "duration": "소요 시간", + "completedAt": "완료 시각", + "jumpToPreviousUserMessage": "이전 사용자 메시지로 이동", + "showMore": "더보기", + "showLess": "접기" + }, + "liveTurnStats": { + "thinking": "생각 중...", + "streaming": "스트리밍 중", + "elapsedHours": "{value}시간", + "elapsedMinutes": "{value}분", + "elapsedSeconds": "{value}초", + "outputSpeedAria": "예상 출력 속도", + "outputSpeedTooltip": "예상 출력 속도(텍스트 + 추론)" + }, + "jsonTree": { + "viewRaw": "원본 JSON 보기", + "viewTree": "트리 보기", + "fields": "필드 {count}개", + "items": "항목 {count}개" + }, + "tool": { + "parameters": "매개변수", + "error": "오류", + "result": "결과", + "status": { + "approvalRequested": "승인 대기 중", + "approvalResponded": "응답됨", + "inputAvailable": "실행 중", + "inputStreaming": "대기 중", + "outputAvailable": "완료", + "outputDenied": "거부됨", + "outputError": "오류" + } + }, + "toolCallBlock": { + "tool": "도구", + "error": "오류", + "result": "결과" + }, + "delegation": { + "subAgentRunning": "서브에이전트 실행 중…", + "noDetail": "No detail available yet.", + "unknownAgent": "하위 에이전트", + "openDetail": "대화 보기", + "detailTitle": "서브에이전트 대화", + "detailDescription": "위임된 서브에이전트 대화를 읽기 전용으로 봅니다.", + "waitForResult": "작업 {task} 실행 결과 대기 중", + "waitForResultNoTask": "작업 실행 결과 대기 중", + "cancelTask": "작업 {task} 취소 중", + "cancelTaskNoTask": "작업 취소 중", + "resultPageOf": "{current} / {total}", + "prevResult": "이전 결과", + "nextResult": "다음 결과", + "noResultText": "이 확인에서는 결과가 없습니다", + "status": { + "starting": "시작 중", + "running": "실행 중", + "checked": "확인됨", + "waiting": "승인 대기 중", + "ok": "완료", + "err": { + "default": "실패", + "delegation_disabled": "비활성화됨", + "depth_limit": "깊이 제한", + "invalid_agent_type": "잘못된 에이전트", + "spawn_failed": "시작 실패", + "send_failed": "전송 실패", + "timeout": "시간 초과", + "canceled": "취소됨", + "child_refusal": "서브에이전트 거부", + "child_max_tokens": "서브에이전트: 토큰 한도", + "child_max_turn_requests": "서브에이전트: 요청 한도", + "child_empty": "서브에이전트 응답 없음", + "child_unknown": "서브에이전트: 오류", + "unknown": "알 수 없는 작업" + } + } + }, + "contentParts": { + "showingTailOutput": "성능을 위해 스트리밍 중에는 출력의 끝부분만 표시합니다.", + "result": "결과", + "unknown": "알 수 없음", + "inputTruncated": "입력이 잘렸습니다 — diff가 불완전할 수 있습니다.", + "replaceAll": "모두 바꾸기", + "filesCount": "파일: {count}", + "update": "업데이트", + "moreFiles": "+{count}개 파일 더", + "timeoutMs": "시간 초과: {timeout}ms", + "backgroundTrue": "백그라운드: true", + "scriptToolCalls": "도구 {count}개 호출", + "offset": "오프셋: {offset}", + "limit": "제한: {limit}", + "pages": "페이지: {pages}", + "mode": "모드: {mode}", + "cell": "셀: {cell}", + "shellSession": "세션 {id}", + "pathLabel": "경로:", + "globLabel": "Glob 패턴:", + "typeLabel": "유형:", + "outputLabel": "출력:", + "caseInsensitive": "대소문자 구분 안 함", + "multiline": "여러 줄", + "promptLabel": "프롬프트", + "subjectLabel": "제목", + "taskLabel": "작업", + "nameLabel": "이름:", + "agentPromptLabel": "프롬프트", + "agentModelLabel": "모델", + "agentRunning": "실행 중...", + "agentLiveTranscript": "실시간 활동", + "agentProgressTools": "도구 호출 {count}회", + "agentProgressTurns": "{count} 턴", + "agentProgressContext": "컨텍스트 {pct}%", + "agentSessionAction": "하위 에이전트 세션 보기", + "agentSessionTitle": "하위 에이전트 세션", + "agentSessionLoading": "하위 에이전트의 기록을 불러오는 중…", + "agentSessionEmpty": "하위 에이전트가 아직 아무것도 기록하지 않았습니다.", + "agentFallbackTitle": "서브 에이전트 시작 중…", + "agentCodexLaunchOnly": "시작되었습니다. Codex는 이 하위 에이전트의 진행 상황을 더 이상 알리지 않으며, 결과는 이 대화의 메시지로 도착합니다.", + "agentStatsBash": "명령", + "agentStatsRead": "파일 읽기", + "agentStatsSearch": "검색", + "agentStatsEdit": "편집", + "agentStatsOther": "기타", + "goal": { + "title": "목표:", + "titleWithStatus": "목표 {status}", + "objective": "목표", + "statusLabel": "상태", + "tokensUsed": "사용 tokens", + "budget": "예산", + "remaining": "남음", + "elapsed": "경과", + "tokens": "tokens", + "pause": "일시정지", + "clear": "지우기", + "status": { + "active": "진행 중", + "paused": "일시 중지", + "blocked": "차단됨", + "usageLimited": "사용량 제한", + "budgetLimited": "예산 제한", + "complete": "완료", + "limited": "한도 도달" + } + }, + "field": { + "file": "파일", + "notebook": "노트북", + "command": "명령", + "old": "이전", + "new": "새", + "pattern": "패턴", + "path": "경로", + "query": "쿼리", + "url": "URL:", + "description": "설명", + "content": "내용", + "source": "소스", + "prompt": "프롬프트", + "subject": "제목", + "taskId": "작업 ID", + "status": "상태", + "skill": "Skill", + "args": "인자", + "offset": "오프셋", + "limit": "제한", + "glob": "Glob 패턴", + "type": "유형", + "output": "출력", + "replaceAll": "모두 바꾸기", + "language": "언어", + "timeout": "시간 초과", + "background": "백그라운드", + "agentType": "에이전트 유형", + "library": "라이브러리", + "libraryId": "라이브러리 ID" + }, + "title": { + "edit": "편집", + "command": "명령", + "script": "스크립트", + "waitCommand": "대기 {command}", + "waitCell": "세션 {id} 대기", + "terminateCommand": "종료 {command}", + "terminateCell": "세션 {id} 종료", + "stdinChars": "입력 {chars}", + "todoWrite": "TodoWrite(할 일 업데이트)", + "read": "읽기", + "write": "쓰기", + "notebookEdit": "NotebookEdit(노트북 편집)", + "editFiles": "편집 ({count}개 파일)", + "editWithTarget": "{target} 편집", + "readWithTarget": "{target} 읽기", + "writeWithTarget": "{target} 쓰기", + "notebookEditWithTarget": "NotebookEdit({target})", + "globWithPattern": "Glob 패턴 {pattern}", + "listFilesWithPath": "파일 목록 {path}", + "grepWithPattern": "Grep 패턴 {pattern}", + "taskCreateWithSubject": "작업 생성: {subject}", + "taskUpdateWithStatus": "작업 업데이트 #{id} -> {status}", + "taskUpdate": "작업 업데이트 #{id}", + "webFetchWithUrl": "WebFetch ({url})", + "webSearchWithQuery": "WebSearch ({query})", + "todosProgress": "할 일 ({done}/{total})", + "skillWithName": "Skill: {name}", + "genericWithContext": "{tool} ({context})" + }, + "search": { + "noMatches": "일치하는 결과 없음", + "matchSummary": "{matches}개 일치 · {files}개 파일", + "fileSummary": "{files}개 파일", + "moreResults": "{count}개 결과가 더 있음(표시되지 않음)" + }, + "toolGroup": { + "search": "{count}회 검색", + "command": "명령 {count}개 실행", + "read": "파일 {count}회 읽기", + "memory": "기억 {count}개 회상", + "edit": "파일 {count}회 편집", + "fetch": "리소스 {count}개 가져오기", + "think": "{count}회 사고", + "todo": "할 일 {count}개 업데이트", + "task": "작업 {count}개 실행", + "other": "도구 {count}개 사용", + "errorSuffix": "{count}건 실패", + "joiner": " · " + }, + "planMode": { + "entered": "계획 모드 시작", + "planLabel": "계획", + "reviewApproved": "계획 승인됨 — 실행 중", + "reviewKept": "계획 모드 유지", + "reviewPending": "계획 결정 대기 중", + "submitted": "계획 제출됨", + "switched": "모드 전환됨" + }, + "backgroundTask": { + "title": "백그라운드 작업", + "titleWithId": "백그라운드 작업 · {id}", + "running": "실행 중", + "completed": "완료됨", + "failed": "실패", + "stopped": "중지됨", + "exitCode": "종료 코드 {code}", + "polledTimes": "{count}회 폴링", + "runningInBackground": "백그라운드", + "launchNote": "백그라운드에서 실행 중 · {id}" + }, + "codexScript": { + "outputMissing": "codex가 스크립트 출력을 잘라내면서 이 명령의 구분선이 사라져 출력을 귀속시킬 수 없습니다.", + "sharedWith": "이 구간에는 {commands}의 출력도 포함됩니다 — 구분선이 codex에 의해 잘렸습니다.", + "truncated": "잘림" + } + }, + "messageNav": { + "title": "메시지 탐색", + "collapse": "메시지 탐색 접기", + "collapsedSummary": "메시지 {count}", + "fileCount": "{count, plural, one {#개 파일} other {#개 파일}}", + "remove": "제거", + "noDiffDataAvailable": "{filePath}에 대한 diff 데이터가 없습니다" + }, + "replyArtifacts": { + "title": "변경된 파일", + "fileCount": "{count, plural, one {#개 파일} other {#개 파일}}", + "newFilesTitle": "새 파일", + "revealInFolder": "파일 관리자에서 표시", + "openFile": "{filePath} 열기", + "openInEditor": "편집기에서 열기", + "remove": "제거", + "noDiffDataAvailable": "{filePath}에 대한 diff 데이터가 없습니다" + }, + "askQuestion": { + "title": "에이전트가 선택을 요청합니다", + "subtitle": "답변 후 제출하세요. 언제든 건너뛸 수 있습니다", + "recommended": "추천", + "other": "기타", + "otherPlaceholder": "답변을 입력하세요…", + "singleSelect": "단일 선택", + "multiSelect": "다중 선택", + "skip": "건너뛰기", + "next": "다음", + "submit": "제출", + "submitError": "제출하지 못했습니다. 다시 시도해 주세요." + }, + "planApproval": { + "title": "에이전트가 계획을 제시했습니다 — 검토하세요", + "emptyPlan": "에이전트가 계획을 작성하지 않았습니다. 승인하여 구현을 시작하거나 변경을 요청하세요.", + "approve": "승인하고 시작", + "requestChanges": "변경 요청", + "abandon": "포기", + "feedbackPlaceholder": "무엇을 변경할까요?", + "sendChanges": "보내기", + "cancel": "취소", + "submitError": "제출하지 못했습니다. 다시 시도하세요." + }, + "feedbackCheckResult": { + "count": "피드백 {count}개", + "expand": "모든 피드백 표시", + "collapse": "접기", + "errorTitle": "피드백 확인 실패" + }, + "askQuestionResult": { + "title": "질문", + "answeredLabel": "질문과 답변:", + "awaiting": "답변을 기다리는 중…", + "declined": "이 질문을 건너뛰었습니다 — 에이전트가 자체 판단으로 진행했습니다.", + "noSelection": "선택 없음" + }, + "configStale": { + "agentConfigTitle": "에이전트 설정이 업데이트되었습니다", + "modelProviderTitle": "모델 공급자가 업데이트되었습니다", + "description": "이 세션은 아직 이전 설정을 사용 중입니다. 다시 연결하면 적용됩니다(대화 기록은 유지됩니다).", + "reconnect": "다시 연결하여 적용", + "reconnecting": "다시 연결하는 중…", + "reconnectDisabledDuringTurn": "현재 턴이 끝나면 다시 연결할 수 있습니다", + "dismiss": "닫기", + "reconnectFailed": "세션 다시 연결 실패", + "applied": "새 설정이 적용되었습니다" + }, + "piProjectTrust": { + "title": "이 프로젝트에 pi 리소스가 포함되어 있습니다", + "description": "pi가 저장소 자체의 .pi 파일을 불러오지 않고 있습니다. 확인 후 결정하세요.", + "descriptionExecutable": "저장소에 pi 확장이 포함되어 있으며, 확장은 시작 시 코드를 실행합니다. pi는 아직 불러오지 않았습니다. 결정하기 전에 확인하세요.", + "review": "검토…", + "dismiss": "닫기", + "dialogTitle": "이 프로젝트의 pi 리소스를 신뢰하시겠습니까?", + "dialogDescription": "폴더를 신뢰해야만 pi가 저장소 자체의 .pi 파일을 불러옵니다. 이 저장소의 내용을 신뢰하는 경우에만 허용하세요.", + "executionWarning": "확장은 코드입니다. 이 폴더를 신뢰하면 메시지를 보내기 전에 저장소의 확장이 pi 시작 시 사용자 권한으로 실행됩니다.", + "scopeNote": "이 결정은 pi의 trust.json에 저장되며 해당 폴더 아래의 모든 폴더에 적용되고, 터미널에서 직접 pi를 실행할 때에도 사용됩니다. 나중에 설정 → 에이전트 → Pi에서 변경할 수 있습니다.", + "trust": "프로젝트 신뢰", + "decline": "불러오지 않음", + "disabledDuringTurn": "현재 턴이 끝나면 사용할 수 있습니다", + "trustedToast": "프로젝트를 신뢰했습니다 — pi가 리소스를 불러오도록 다시 연결했습니다", + "declinedToast": "프로젝트 리소스를 불러오지 않습니다", + "saveFailed": "프로젝트 신뢰 설정을 저장하지 못했습니다", + "grantTitle": "이 프로젝트는 이미 신뢰됨", + "grantDescription": "pi가 이 저장소 자체의 .pi 파일을 불러옵니다. 무엇이 허용되는지 확인하세요.", + "grantInheritedDescription": "상위 폴더가 신뢰되어 pi가 이 저장소 자체의 .pi 파일을 불러옵니다. 무엇이 허용되는지 확인하세요.", + "grantDialogTitle": "이 프로젝트의 pi 리소스가 신뢰됨", + "grantDialogDescription": "pi가 이 저장소 자체의 .pi 파일을 불러오도록 허용되어 있습니다. 이전 codeg 버전은 폴더를 열 때 자동으로 이를 허용했으므로 확인을 요청받지 않았을 수 있습니다.", + "grantExecutionWarning": "확장은 코드입니다. 저장소의 확장은 메시지를 보내기 전에 pi 시작 시 사용자 권한으로 실행됩니다.", + "inheritedFrom": "신뢰 출처", + "revoke": "신뢰 취소", + "keepTrusted": "신뢰 유지", + "revokedToast": "신뢰를 취소했습니다 — 다시 연결하여 pi가 프로젝트 리소스를 불러오지 않습니다", + "trustedNoReconnect": "프로젝트를 신뢰했습니다 — pi가 다음에 시작할 때 적용됩니다", + "revokedNoReconnect": "신뢰를 취소했습니다 — pi가 다음에 시작할 때 적용됩니다" + }, + "collabAgent": { + "title": "서브 에이전트", + "errorTitle": "서브 에이전트 작업이 실패했습니다", + "statesLabel": "서브 에이전트", + "statusRunning": "실행 중", + "statusCompleted": "완료됨", + "statusFailed": "실패", + "statusPending": "시작 중", + "statusInterrupted": "중단됨", + "statusClosed": "종료됨", + "statusNotFound": "찾을 수 없음", + "opSpawn": "서브 에이전트 시작 중", + "opWait": "서브 에이전트 결과 가져오는 중", + "opClose": "서브 에이전트 종료 중", + "opResume": "서브 에이전트 재개 중" + }, + "contextCompaction": { + "compacting": "컨텍스트 압축 중…", + "compacted": "컨텍스트 압축 완료", + "compactedTokens": "컨텍스트 압축 완료 · {before} → {after} 토큰", + "failed": "컨텍스트 압축 실패" + }, + "sessionFailure": { + "category": { + "connection": "연결 문제", + "access": "액세스 문제", + "limit": "한도 도달", + "request": "요청 거부됨", + "service": "서비스 문제", + "unknown": "세션 문제" + }, + "action": { + "retry": "다시 시도", + "login": "로그인", + "newSession": "새 세션" + }, + "recovered": "복구됨", + "retryUnavailable": "다시 보낼 메시지가 없습니다.", + "toggleDetails": "세부 정보 전환" + }, + "backgroundTasks": { + "running": "백그라운드 작업 {count}개 실행 중", + "settling": "백그라운드 결과 동기화 중…", + "settledFallback": "백그라운드 작업이 종료되었습니다 ({status})", + "cardRunning": "백그라운드에서 실행 중", + "cardLaunchedPending": "백그라운드 작업 시작됨", + "cardCompleted": "백그라운드 작업 완료", + "cardFinishedWithStatus": "백그라운드 작업 종료 ({status})", + "cardResultPending": "결과가 아직 반환되지 않았습니다" + }, + "proposedPlan": { + "title": "제안된 계획", + "planning": "계획 중…" + } + }, + "diffPreview": { + "mode": { + "added": "추가됨", + "deleted": "삭제됨", + "renamed": "이름 변경됨", + "modified": "수정됨" + }, + "hunkLabel": "청크 {index}", + "loadingHunk": "Hunk 로딩 중...", + "noDiffData": "Diff 데이터 없음", + "showRemainingLines": "나머지 {count}줄 표시" + }, + "conversationContextBar": { + "folderTitle": "작업 폴더", + "branchTitle": "작업 브랜치", + "searchFolder": "Search folder...", + "searchBranch": "Search branch...", + "noFolders": "No folders", + "noBranches": "No branches", + "noBranch": "(no branch)", + "chatModeLabel": "채팅 모드", + "commit": "Commit", + "push": "Push", + "merge": "Merge", + "toasts": { + "folderChanged": "Switched to {name}", + "openFolderFailed": "Failed to open folder", + "switchedToChatMode": "채팅 모드로 전환했습니다", + "openStashFailed": "Failed to open stash window", + "openMergeFailed": "Failed to open merge window" + } + }, + "cloneDialog": { + "title": "저장소 클론", + "repositoryUrl": "저장소 URL", + "repositoryUrlPlaceholder": "https://github.com/user/repo.git", + "directory": "디렉터리", + "directoryPlaceholder": "대상 디렉터리 선택...", + "browseDirectory": "디렉터리 찾아보기", + "cancel": "취소", + "clone": "클론", + "clonePath": "클론 경로: {path}" + }, + "toasts": { + "cloneFailed": "저장소 클론에 실패했습니다" + } + }, + "ProjectBoot": { + "title": "프로젝트 부트", + "tabs": { + "shadcn": "shadcn", + "hyperframes": "HyperFrames" + }, + "hyperframes": { + "title": "HyperFrames 비디오 프로젝트", + "subtitle": "HTML을 비디오로 만드는 프로젝트를 생성합니다. 이후 워크스페이스 에이전트가 작성하고 렌더링할 수 있습니다.", + "resolution": "해상도", + "skillsTitle": "에이전트 스킬", + "skillsDesc": "선택한 에이전트에 HyperFrames 스킬을 전역(심볼릭 링크)으로 설치하여 영상 작성·렌더링을 지원합니다.", + "recheck": "다시 확인", + "installedBadge": "설치됨", + "skillsInstall": "스킬 설치 / 업데이트", + "skillsInstalling": "스킬 설치 중…", + "skillsInstalled": "HyperFrames 스킬 설치 완료", + "skillsInstallFailed": "HyperFrames 스킬 설치 실패" + }, + "config": { + "base": "베이스", + "style": "스타일", + "baseColor": "베이스 색상", + "theme": "테마", + "chartColor": "차트 색상", + "iconLibrary": "아이콘 라이브러리", + "font": "글꼴", + "fontHeading": "제목 글꼴", + "menuAccent": "메뉴 강조", + "menuColor": "메뉴 색상", + "radius": "둥글기", + "template": "템플릿", + "createProject": "프로젝트 만들기", + "sectionStyle": "스타일", + "sectionColors": "색상", + "sectionTypography": "타이포그래피", + "sectionInterface": "인터페이스" + }, + "preview": { + "loading": "미리보기 로딩 중..." + }, + "createDialog": { + "title": "프로젝트 만들기", + "projectName": "프로젝트 이름", + "projectNamePlaceholder": "my-app", + "frameworkTemplate": "프레임워크 템플릿", + "packageManager": "패키지 매니저", + "saveDirectory": "저장 디렉토리", + "saveDirectoryPlaceholder": "디렉토리 선택...", + "browseDirectory": "찾아보기", + "projectPath": "프로젝트 생성 위치: {path}", + "advancedOptions": "고급 옵션", + "base": "기본 라이브러리", + "enableRtl": "RTL 지원 활성화", + "enableRtlDescription": "오른쪽에서 왼쪽으로 쓰는 언어(예: 아랍어, 히브리어)의 레이아웃 지원 활성화", + "pmChecking": "확인 중...", + "pmNotInstalled": "설치되지 않음", + "cancel": "취소", + "create": "만들기", + "creating": "프로젝트 생성 중..." + }, + "toasts": { + "createFailed": "프로젝트 생성에 실패했습니다", + "createSuccess": "프로젝트가 성공적으로 생성되었습니다", + "openWorkspaceFailed": "프로젝트가 생성되었지만 작업 공간에서 열지 못했습니다" + }, + "errors": { + "directoryExists": "대상 디렉터리가 이미 존재합니다", + "commandFailed": "프로젝트 생성 명령이 실패했습니다." + } + }, + "WebServiceSettings": { + "addressSwitchHint": "전환해도 여기에 표시되고 열리는 주소만 바뀝니다. 서비스는 모든 인터페이스에서 수신하며 어떤 주소로도 접속할 수 있습니다.", + "sectionTitle": "웹 서비스", + "sectionDescription": "활성화하면 브라우저를 통해 Codeg에 원격으로 접속할 수 있습니다", + "port": "포트", + "status": "상태", + "autoStart": "자동 시작", + "autoStartHint": "Codeg가 시작될 때 웹 서비스를 시작합니다", + "running": "실행 중", + "stopped": "중지됨", + "processing": "처리 중...", + "start": "시작", + "stop": "중지", + "startFailed": "시작 실패", + "stopFailed": "중지 실패", + "saveConfigFailed": "웹 서비스 설정 저장 실패", + "open": "열기", + "hide": "숨기기", + "show": "표시", + "copy": "복사", + "qrcode": "QR 코드", + "qrcodeTitle": "스캔하여 열기", + "qrcodeHint": "휴대폰으로 스캔하여 브라우저에서 Codeg를 엽니다", + "addressLabel": "접속 주소", + "tokenLabel": "접속 토큰", + "tokenHint": "웹 클라이언트 첫 접속 시 이 토큰을 입력하세요", + "tokenPlaceholder": "비워두면 자동 생성", + "regenerate": "재생성", + "stalePortOccupiedTitle": "포트 {port}이(가) 다른 프로세스에 의해 사용 중입니다", + "stalePortUnknownTitle": "포트 {port}의 상태를 확인할 수 없습니다", + "stalePortHint": "포트가 해제될 때까지 Codeg은 바인딩할 수 없습니다. 위의 포트를 변경하거나 사용 중인 프로세스를 종료하세요.", + "errors": { + "alreadyRunning": "웹 서비스가 이미 실행 중입니다", + "invalidAddress": "호스트 또는 포트 형식이 올바르지 않습니다", + "portInUse": "포트 {port}가 이미 사용 중입니다. 해당 포트를 사용 중인 프로세스를 종료하거나 다른 포트를 선택하세요", + "permissionDenied": "권한이 부족합니다. 1024 이상의 포트를 사용하거나 더 높은 권한으로 실행하세요", + "addressUnavailable": "이 주소는 현재 시스템에서 사용할 수 없습니다", + "bindFailed": "주소 바인딩에 실패했습니다" + } + }, + "DirectoryBrowser": { + "title": "디렉토리 찾아보기", + "pathPlaceholder": "디렉토리 경로 입력...", + "goHome": "홈 디렉토리로 이동", + "navigateUp": "상위 디렉토리로 이동", + "select": "선택", + "cancel": "취소", + "loading": "로딩 중...", + "emptyDirectory": "이 디렉토리는 비어 있습니다", + "errorLoadingDir": "디렉토리 로딩 실패", + "permissionDenied": "권한이 없습니다" + }, + "ChatChannelSettings": { + "loading": "로딩 중...", + "sectionTitle": "채팅 채널", + "sectionDescription": "IM 봇을 설정하여 이벤트 알림을 수신하고 코딩 활동을 조회합니다.", + "addChannel": "채널 추가", + "noChannels": "설정된 채팅 채널이 없습니다.", + "channelName": "이름", + "channelNamePlaceholder": "내 Telegram 봇", + "channelType": "채널 유형", + "lark": "Lark (飛書)", + "weixin": "WeChat", + "dailyReport": "일일 리포트", + "dailyReportTime": "발송 시간", + "nameRequired": "채널 이름을 입력하세요.", + "tokenRequired": "토큰을 입력하세요.", + "chatIdRequired": "Chat ID를 입력하세요.", + "topicMode": "토픽 그룹 모드", + "topicModeHint": "Telegram forum topics를 별도 Codeg 세션으로 라우팅합니다. Bot은 forum supergroup에 있어야 하며 topics 관리 권한이 필요합니다.", + "loadFailed": "채널 로딩에 실패했습니다.", + "saveFailed": "저장에 실패했습니다.", + "connectSuccess": "채널이 연결되었습니다.", + "connectFailed": "연결에 실패했습니다", + "disconnectSuccess": "채널이 연결 해제되었습니다.", + "disconnectFailed": "연결 해제에 실패했습니다.", + "testSuccess": "연결 테스트를 통과했습니다.", + "testFailed": "연결 테스트에 실패했습니다", + "deleteSuccess": "채널이 삭제되었습니다.", + "deleteFailed": "채널 삭제에 실패했습니다.", + "deleteConfirmTitle": "채널 삭제", + "deleteConfirmMessage": "이 채널과 메시지 기록이 영구 삭제됩니다. 계속하시겠습니까?", + "cancel": "취소", + "delete": "삭제", + "create": "생성", + "save": "저장", + "channelListTitle": "설정된 채널", + "channelListDescription": "활성화된 채널은 서비스 시작 시 자동으로 연결됩니다.", + "editChannel": "채널 편집", + "editSuccess": "채널이 업데이트되었습니다.", + "tokenPlaceholderKeep": "비워두면 현재 값 유지", + "weixinScanTitle": "QR 코드 스캔", + "weixinScanDescription": "WeChat을 열고 QR 코드를 스캔하여 연결하세요.", + "weixinQrcodeExpired": "QR 코드가 만료되었습니다.", + "weixinRefreshQrcode": "새로고침", + "weixinWaitingScan": "스캔 대기 중...", + "weixinPollError": "연결이 불안정합니다. 재시도 중...", + "weixinReconnectNotice": "iLink 프로토콜 제한으로 인해, 재연결할 때마다 먼저 봇에게 메시지를 보내야 이벤트 트리거가 활성화됩니다.", + "connect": "연결", + "disconnect": "연결 해제", + "test": "연결 테스트", + "tabs": { + "channels": "채널", + "commands": "명령어", + "events": "이벤트", + "other": "기타" + }, + "commands": { + "title": "내장 명령어", + "description": "채팅 채널에서 사용 가능한 Bot 명령어입니다. 그룹 채팅에서는 메시지를 처리하려면 @Bot이 필요합니다.", + "prefixLabel": "명령어 접두사", + "prefixDescription": "Bot 명령어를 실행하는 접두사, 1-3개의 영숫자가 아닌 문자 (기본값 /).", + "prefixSaved": "명령어 접두사가 저장되었습니다.", + "prefixSaveFailed": "명령어 접두사 저장에 실패했습니다.", + "prefixInvalid": "접두사는 1-3개의 영숫자가 아닌 문자여야 합니다.", + "save": "저장", + "folderDesc": "작업 폴더 선택", + "agentDesc": "AI 에이전트 선택", + "taskDesc": "세션 생성 및 작업 실행", + "sessionsDesc": "폴더 내 활성 세션 목록", + "resumeDesc": "최근 대화 / 세션 재개", + "cancelDesc": "현재 작업 취소", + "approveDesc": "에이전트 권한 요청 승인", + "denyDesc": "에이전트 권한 요청 거부", + "searchDesc": "키워드로 대화 검색", + "todayDesc": "오늘의 활동 요약", + "statusDesc": "채널 연결 상태", + "helpDesc": "도움말 표시" + }, + "events": { + "title": "이벤트 알림", + "description": "이벤트를 활성화하면, 트리거 시 채널로 푸시됩니다.", + "turnComplete": "턴 완료", + "turnCompleteDesc": "에이전트 턴이 종료될 때", + "error": "에이전트 오류", + "errorDesc": "에이전트에 오류가 발생했을 때", + "permissionRequest": "권한 요청", + "permissionRequestDesc": "에이전트가 작업 권한을 요청할 때", + "questionRequest": "에이전트 질문", + "questionRequestDesc": "에이전트가 질문할 때", + "userPromptSent": "사용자 메시지", + "userPromptSentDesc": "메시지를 보낼 때 — 알림에 메시지 내용이 포함됩니다", + "saved": "이벤트 필터가 업데이트되었습니다.", + "saveFailed": "이벤트 필터 저장에 실패했습니다.", + "loadFailed": "설정을 불러오지 못했습니다.", + "retry": "다시 시도", + "webhooksTitle": "Webhook", + "webhooksDescription": "활성화된 이벤트가 발생하면 하나 이상의 URL로 JSON을 POST합니다. 위의 이벤트 필터는 Webhook에도 적용됩니다.", + "webhookUrlPlaceholder": "https://example.com/webhook", + "addWebhook": "Webhook 추가", + "removeWebhook": "Webhook 삭제", + "webhookSave": "저장", + "webhooksSaved": "Webhook을 저장했습니다.", + "webhooksSaveFailed": "Webhook 저장에 실패했습니다.", + "webhookInvalidUrl": "유효한 http(s) URL을 입력하세요.", + "docsTitle": "요청 형식", + "docsMethod": "메서드", + "docsContentType": "Content-Type", + "docsNote": "활성화된 각 이벤트는 모든 URL로 전달됩니다. Webhook은 디바운스되지 않으며 위의 이벤트 필터가 계속 적용됩니다.", + "editWebhook": "Webhook 편집", + "enableWebhook": "Webhook 활성화", + "webhookDuplicate": "이미 설정된 URL입니다.", + "cancel": "취소", + "webhooksEmpty": "아직 구성된 Webhook이 없습니다.", + "deleteWebhookTitle": "Webhook 삭제", + "deleteWebhookMessage": "이 Webhook을 삭제하시겠습니까? 이 URL로 더 이상 이벤트가 전달되지 않습니다.", + "delete": "삭제" + }, + "language": { + "title": "메시지 언어", + "description": "이벤트 알림, 명령 응답, 일일 보고서를 채팅 채널로 전송할 때 사용하는 언어입니다.", + "saved": "메시지 언어가 저장되었습니다.", + "saveFailed": "메시지 언어 저장에 실패했습니다.", + "en": "영어", + "zh-cn": "중국어 간체", + "zh-tw": "중국어 번체", + "ja": "일본어", + "ko": "한국어", + "es": "스페인어", + "de": "독일어", + "fr": "프랑스어", + "pt": "포르투갈어", + "ar": "아랍어" + } + }, + "ModelProviderSettings": { + "sectionTitle": "모델 제공업체", + "sectionDescription": "에이전트의 API 제공업체 자격 증명을 관리합니다.", + "filterAll": "전체", + "providerListTitle": "구성된 제공업체", + "addProvider": "제공업체 추가", + "editProvider": "제공업체 편집", + "noProviders": "아직 구성된 모델 제공업체가 없습니다.", + "providerName": "이름", + "providerNamePlaceholder": "예: OpenAI, Anthropic", + "apiUrl": "API URL", + "apiUrlPlaceholder": "https://api.openai.com/v1", + "apiKey": "API 키", + "apiKeyPlaceholder": "sk-...", + "apiKeyKeepCurrent": "현재 값을 유지하려면 비워두세요", + "agentTypes": "에이전트 유형", + "agentTypesRequired": "최소 하나의 에이전트 유형을 선택하세요.", + "agentType": "에이전트 유형", + "agentTypeRequired": "에이전트 유형을 선택하세요.", + "agentTypeImmutableHint": "에이전트 유형은 생성 후 변경할 수 없습니다.", + "model": "모델", + "modelPlaceholderCodex": "gpt-5.6-sol / gpt-5.5", + "modelPlaceholderGemini": "gemini-3-pro-preview", + "claudeMainModel": "메인 모델", + "claudeReasoningModel": "추론 모델 (사고)", + "claudeHaikuDefaultModel": "기본 Haiku 모델", + "claudeSonnetDefaultModel": "기본 Sonnet 모델", + "claudeOpusDefaultModel": "기본 Opus 모델", + "claudeCustomModelOption": "사용자 지정 모델 ID", + "claudeCustomModelOptionName": "사용자 지정 모델 이름", + "claudeCustomModelOptionDescription": "사용자 지정 모델 설명", + "claudeCustomModelOptionHint": "Claude 모델 선택기에 사용자 지정 항목 하나를 추가합니다(예: 사용자 지정 게이트웨이/프록시를 통해 제공되는 모델). 이름과 설명은 선택적 표시 설정입니다.", + "nameRequired": "제공업체 이름은 필수입니다.", + "apiUrlRequired": "API URL은 필수입니다.", + "apiKeyRequired": "API 키는 필수입니다.", + "loadFailed": "제공업체를 불러오지 못했습니다.", + "saveFailed": "변경 사항을 저장하지 못했습니다.", + "createSuccess": "제공업체가 생성되었습니다.", + "editSuccess": "제공업체가 업데이트되었습니다.", + "deleteSuccess": "제공업체가 삭제되었습니다.", + "deleteConfirmTitle": "제공업체 삭제", + "deleteConfirmMessage": "제공업체 \"{name}\"을(를) 영구적으로 삭제하시겠습니까?", + "deleteBlockedByAgent": "{agents}이(가) 이 공급자를 사용 중입니다. 삭제하기 전에 연결을 해제해 주세요.", + "cancel": "취소", + "delete": "삭제", + "create": "생성", + "save": "저장", + "affectedRunningSessions": "{count}개의 실행 중인 세션은 다시 연결하면 변경 사항이 적용됩니다" + }, + "SkillMatrix": { + "loading": "불러오는 중…", + "searchPlaceholder": "이름, ID 또는 설명으로 검색", + "empty": "표시할 항목이 없습니다.", + "emptySearch": "현재 검색과 일치하는 항목이 없습니다.", + "skillColumn": "스킬", + "selectAll": "표시된 항목 모두 선택", + "selectSkill": "{name} 선택", + "everything": { + "label": "일괄", + "enable": "모두 활성화(표시된 항목)", + "disable": "모두 비활성화(표시된 항목)" + }, + "columnMenu": { + "enableAll": "모든 스킬 활성화", + "disableAll": "모든 스킬 비활성화" + }, + "rowMenu": { + "label": "{name} 일괄 작업", + "enableAll": "모든 에이전트에 활성화", + "disableAll": "모든 에이전트에서 비활성화" + }, + "bulk": { + "selected": "{count}개 선택됨", + "targetAll": "모든 에이전트", + "targetSome": "에이전트 {count}개", + "enable": "활성화", + "disable": "비활성화", + "clear": "지우기" + }, + "confirm": { + "disableTitle": "이 링크를 비활성화할까요?", + "disableBody": "codeg가 관리하는 스킬 링크 {count}개를 제거합니다. 사용자 지정 디렉터리를 차지한 스킬은 그대로 유지됩니다. 언제든지 다시 활성화할 수 있습니다.", + "cancel": "취소", + "confirm": "비활성화" + }, + "toasts": { + "loadFailed": "스킬 상태를 불러오지 못했습니다", + "applyFailed": "변경 사항을 적용하지 못했습니다", + "enabled": "링크 {count}개를 활성화했습니다", + "disabled": "링크 {count}개를 비활성화했습니다", + "enabledPartial": "{ok}개 활성화, {failed}개 실패", + "disabledPartial": "{ok}개 비활성화, {failed}개 실패" + }, + "detail": { + "enableForAgents": "에이전트에 활성화", + "preview": "SKILL.md 미리보기", + "loadingContent": "콘텐츠 불러오는 중…" + }, + "copyModeHint": "복사됨(링크 아님) — 업데이트 후 최신 버전을 받으려면 다시 활성화하세요" + }, + "ExpertsSettings": { + "title": "전문가 스킬", + "description": "AI 코딩 에이전트를 위해 엄선되고 실전 검증된 스킬 워크플로를 활성화하세요. 각 전문가는 superpowers 프로젝트의 독립 실행형 스킬이며 — codeg가 중앙 복사본을 관리하고 선택한 에이전트에 연결합니다.", + "loading": "전문가 로딩 중…", + "loadingContent": "콘텐츠 로딩 중…", + "emptyExperts": "사용 가능한 전문가가 없습니다. 애플리케이션 로그를 확인하세요.", + "emptySelection": "전문가를 선택하여 내용을 보고 활성화를 관리하세요.", + "emptySearch": "현재 검색과 일치하는 전문가가 없습니다.", + "searchPlaceholder": "이름, ID 또는 설명으로 전문가 검색", + "enableForAgents": "에이전트에 활성화", + "noAgents": "ACP 에이전트가 감지되지 않았습니다.", + "copyModeWarning": "복사됨(연결되지 않음). 최신 버전을 받으려면 codeg 업데이트 후 재활성화하세요.", + "previewTitle": "SKILL.md 미리보기", + "categories": { + "discovery": "발견 및 설계", + "planning": "계획", + "execution": "실행", + "quality": "품질 및 테스트", + "debugging": "디버깅", + "review": "검토 및 통합", + "meta": "메타" + }, + "states": { + "not_linked": "활성화되지 않음", + "linked_to_codeg": "활성화됨", + "linked_elsewhere": "차단됨 — 다른 링크가 존재함", + "blocked_by_real_directory": "차단됨 — 사용자 정의 스킬이 이 이름을 점유 중", + "broken": "손상된 링크" + }, + "badges": { + "userModified": "사용자가 수정함" + }, + "actions": { + "openCentralDir": "중앙 폴더 열기", + "refresh": "새로고침" + }, + "toasts": { + "loadFailed": "전문가 세부 정보를 로드하지 못했습니다", + "enabled": "이 에이전트에 전문가가 활성화되었습니다", + "disabled": "이 에이전트에서 전문가가 비활성화되었습니다", + "enableFailed": "전문가 활성화에 실패했습니다", + "disableFailed": "전문가 비활성화에 실패했습니다", + "openFolderFailed": "폴더를 열지 못했습니다" + } + }, + "ScienceSettings": { + "title": "과학 연구 스킬", + "description": "AI 코딩 에이전트를 위한 엄선된 과학 연구 스킬(가설 생성, 실험 설계, 통계, 시각화, 비판적 평가, 문헌 검색)을 활성화합니다. codeg가 중앙 복사본을 관리하고 선택한 에이전트에 각 스킬을 연결합니다.", + "loading": "과학 연구 스킬 불러오는 중…", + "emptySkills": "사용 가능한 과학 연구 스킬이 없습니다. 애플리케이션 로그를 확인하세요.", + "searchPlaceholder": "이름, ID 또는 설명으로 과학 연구 스킬 검색", + "categories": { + "ideation": "아이디어", + "design": "연구 설계", + "analysis": "분석", + "visualization": "시각화", + "evaluation": "평가", + "literature": "문헌" + }, + "states": { + "not_linked": "활성화되지 않음", + "linked_to_codeg": "활성화됨", + "linked_elsewhere": "차단됨 — 다른 링크가 존재함", + "blocked_by_real_directory": "차단됨 — 사용자 정의 스킬이 이 이름을 점유 중", + "broken": "손상된 링크" + }, + "badges": { + "userModified": "사용자가 수정함", + "needsKey": "API 키 필요", + "needsSetup": "설정 필요할 수 있음" + }, + "actions": { + "openCentralDir": "중앙 폴더 열기", + "refresh": "새로고침" + }, + "toasts": { + "openFolderFailed": "폴더를 열지 못했습니다" + } + }, + "OfficeToolsSettings": { + "title": "Office 도구", + "description": "OfficeCLI 스킬을 관리하여 Excel, Word, PowerPoint 파일을 생성합니다. OfficeCLI를 설치하고 스킬을 동기화한 후 에이전트별로 활성화할 수 있습니다.", + "loadingContent": "콘텐츠 로드 중…", + "emptySkills": "스킬이 없습니다. OfficeCLI를 설치하고 스킬을 동기화하세요.", + "emptySelection": "스킬을 선택하여 내용을 확인하고 활성화를 관리합니다.", + "emptySearch": "검색과 일치하는 스킬이 없습니다.", + "searchPlaceholder": "이름, ID 또는 설명으로 스킬 검색", + "enableForAgents": "에이전트에 활성화", + "noAgents": "ACP 에이전트가 감지되지 않았습니다.", + "installFirst": "스킬을 활성화하려면 먼저 OfficeCLI를 설치하세요.", + "syncFirst": "콘텐츠를 로드하려면 먼저 스킬을 동기화하세요.", + "noContent": "콘텐츠가 없습니다.", + "copyModeWarning": "복사됨(링크 아님). 최신 버전을 가져오려면 다시 동기화하세요.", + "previewTitle": "SKILL.md 미리보기", + "detection": { + "installed": "설치됨", + "notInstalled": "미설치", + "notRunnable": "설치됨, 실행 불가", + "installHint": "OfficeCLI를 설치하여 AI 에이전트에 오피스 문서 생성 스킬을 활성화합니다.", + "install": "설치", + "uninstall": "제거", + "syncSkills": "스킬 동기화" + }, + "categories": { + "general": "일반", + "presentations": "프레젠테이션", + "documents": "문서", + "spreadsheets": "스프레드시트" + }, + "states": { + "not_linked": "비활성", + "linked_to_codeg": "활성", + "linked_elsewhere": "차단됨 — 다른 링크가 존재합니다", + "blocked_by_real_directory": "차단됨 — 사용자 정의 스킬이 이 이름을 사용 중", + "broken": "링크 끊김" + }, + "badges": { + "notSynced": "미동기화" + }, + "actions": { + "refresh": "새로고침" + }, + "toasts": { + "loadFailed": "스킬 상세 로드 실패", + "enabled": "이 에이전트에 스킬 활성화됨", + "disabled": "이 에이전트에서 스킬 비활성화됨", + "enableFailed": "스킬 활성화 실패", + "disableFailed": "스킬 비활성화 실패", + "installSuccess": "OfficeCLI 설치 성공", + "installFailed": "OfficeCLI 설치 실패", + "uninstallSuccess": "OfficeCLI 제거됨", + "uninstallFailed": "OfficeCLI 제거 실패", + "syncSuccess": "{synced}개 스킬 동기화 완료", + "syncPartial": "{synced}개 동기화, {errors}개 실패", + "syncFailed": "스킬 동기화 실패" + }, + "autoPreviewLabel": "미리보기 자동 열기", + "autoPreviewHint": "에이전트가 Word, Excel, PowerPoint 파일을 만들거나 편집하면 실시간 미리보기를 자동으로 엽니다." + }, + "SkillPacksSettings": { + "title": "스킬 팩", + "description": "codeg가 중앙에서 관리하고 각 AI 에이전트에 연결하는 엄선된 스킬 모음입니다 — 코딩 전문가, 과학 연구, 오피스 문서 도구. 아래에서 에이전트별로 활성화하세요.", + "tabs": { + "experts": "전문가", + "science": "과학 연구", + "office": "오피스 도구", + "custom": "사용자 지정" + }, + "actions": { + "openCentralDir": "중앙 폴더 열기", + "refresh": "새로고침" + }, + "toasts": { + "openFolderFailed": "폴더를 열지 못했습니다" + } + }, + "QuickMessagesSettings": { + "title": "빠른 메시지", + "description": "재사용 가능한 메시지 스니펫을 관리합니다. 드래그하여 순서를 변경하세요.", + "loading": "빠른 메시지 불러오는 중…", + "emptyList": "빠른 메시지가 없습니다. \"새로 만들기\"를 클릭하여 추가하세요.", + "emptySelection": "편집할 빠른 메시지를 선택하세요.", + "searchPlaceholder": "제목 또는 내용으로 검색", + "untitled": "제목 없음", + "actions": { + "new": "새로 만들기", + "save": "저장", + "delete": "삭제", + "dragSort": "드래그하여 순서 변경", + "dragSortMessage": "빠른 메시지 순서 변경: {name}" + }, + "fields": { + "title": "제목", + "titlePlaceholder": "이 메시지에 짧은 제목을 지정하세요", + "content": "내용", + "contentPlaceholder": "여기에 메시지 내용을 입력하세요" + }, + "confirmDelete": { + "title": "빠른 메시지를 삭제하시겠습니까?", + "message": "\"{name}\" 이(가) 영구적으로 삭제됩니다. 계속하시겠습니까?", + "cancel": "취소", + "confirm": "삭제" + }, + "toasts": { + "loadFailed": "빠른 메시지를 불러오지 못했습니다", + "createFailed": "빠른 메시지를 만들지 못했습니다", + "saveFailed": "빠른 메시지를 저장하지 못했습니다", + "deleteFailed": "빠른 메시지를 삭제하지 못했습니다", + "saveOrderFailed": "순서를 저장하지 못했습니다", + "created": "빠른 메시지가 생성되었습니다", + "saved": "빠른 메시지가 저장되었습니다", + "deleted": "빠른 메시지가 삭제되었습니다" + } + }, + "Pet": { + "badge": { + "running": "실행 중 {count}개", + "waiting": "승인 대기 {count}개", + "error": "오류 {count}개" + }, + "panel": { + "title": "활성 세션", + "empty": "활성 세션 없음", + "emptyHint": "실행 중이거나 사용자의 조치가 필요한 세션이 여기에 표시됩니다.", + "statusRunning": "실행 중", + "statusWaiting": "대기 중", + "statusError": "오류", + "subAgentOf": "하위 에이전트" + }, + "menu": { + "scale": "크기", + "openManager": "펫 관리", + "close": "닫기" + }, + "loadError": "펫을 불러오지 못했습니다", + "missingPetIdParam": "선택된 펫이 없습니다", + "summonButton": "펫", + "manager": { + "title": "데스크톱 펫", + "description": "Codex 호환 스프라이트 시트로 동작하는 데스크톱 동반자.", + "addPet": "펫 추가", + "importFromCodex": "Codex 에서 가져오기", + "noPets": "펫이 아직 없습니다. 새로 추가하거나 Codex 에서 가져오세요.", + "setActive": "활성화", + "active": "활성", + "edit": "편집", + "delete": "삭제", + "deleteConfirm": "펫 \"{name}\"을(를) 삭제할까요? 디스크에서도 함께 제거됩니다.", + "summon": "펫 창 호출", + "openCodexHelp": "Codex 펫은 ~/.codex/pets/ 아래에 설치되어야 합니다. 찾을 수 없습니다.", + "specRequirement": "스프라이트 시트는 너비 1536px, 높이는 208px의 배수(예: 1872 또는 2288)인 투명 PNG 또는 WebP여야 합니다.", + "form": { + "id": "펫 ID", + "idHelp": "소문자/숫자/'-'/'_' 만 가능. 최대 64자.", + "displayName": "표시 이름", + "description": "설명 (선택)", + "spritesheet": "스프라이트 시트", + "chooseFile": "파일 선택", + "replaceFile": "스프라이트 교체", + "saveCreate": "펫 추가", + "saveUpdate": "변경 저장", + "cancel": "취소" + }, + "errors": { + "missingId": "펫 ID 는 필수입니다", + "missingName": "표시 이름은 필수입니다", + "missingSpritesheet": "스프라이트 시트는 필수입니다", + "addFailed": "펫 추가에 실패했습니다", + "updateFailed": "펫 갱신에 실패했습니다", + "deleteFailed": "펫 삭제에 실패했습니다", + "loadFailed": "펫 목록 로드에 실패했습니다", + "setActiveFailed": "활성 펫 설정에 실패했습니다", + "summonFailed": "펫 창 호출에 실패했습니다" + } + }, + "import": { + "title": "Codex 에서 가져오기", + "subtitle": "~/.codex/pets/ 에서 발견된 펫 목록입니다.", + "selectAll": "전체 선택", + "alreadyImported": "이미 가져옴", + "renameOnConflict": "충돌 시 -imported 접미어로 이름 변경", + "import": "선택 항목 가져오기", + "noneFound": "가져올 수 있는 Codex 펫이 없습니다.", + "imported": "가져오기 완료", + "failed": "가져오기 실패", + "close": "닫기" + }, + "marketplace": { + "openMarketplace": "펫 마켓", + "title": "펫 마켓", + "search": "펫 검색", + "kindFilter": { + "all": "전체", + "object": "오브젝트", + "animal": "동물", + "person": "인물", + "creature": "생물" + }, + "sortFilter": { + "latest": "최신", + "popular": "인기", + "views": "조회수순" + }, + "refresh": "새로고침", + "install": "설치", + "installing": "설치 중", + "reinstall": "다시 설치", + "reinstallConfirm": "로컬 펫 \"{name}\" 을(를) 덮어쓰시겠습니까? 기존 데이터가 교체됩니다.", + "cancel": "취소", + "stats": { + "views": "조회수", + "downloads": "다운로드", + "likes": "좋아요" + }, + "actions": { + "idle": "대기", + "running_right": "오른쪽 달리기", + "running_left": "왼쪽 달리기", + "waving": "손 흔들기", + "jumping": "점프", + "failed": "실패", + "waiting": "기다림", + "running": "실행", + "review": "리뷰" + }, + "page": "{page} / {total} 페이지", + "prev": "이전", + "next": "다음", + "empty": "조건에 맞는 펫이 없습니다.", + "successInstalled": "\"{name}\" 을(를) 설치했습니다", + "errors": { + "loadFailed": "마켓을 불러오지 못했습니다", + "installFailed": "설치에 실패했습니다", + "alreadyInstalled": "해당 펫이 이미 존재합니다" + } + } + }, + "RemoteWorkspace": { + "openRemoteWorkspace": "Open remote workspace", + "manage": "Manage remote workspace", + "manageTitle": "Remote Workspace connections", + "empty": "No remote connections", + "searchPlaceholder": "Search remote workspaces", + "orderFailed": "Failed to save remote workspace order", + "dragSort": "Drag to sort", + "dragSortConnection": "Drag to sort {name}", + "newConnection": "New connection", + "loading": "Loading", + "loadingConnection": "Loading remote connection", + "name": "Name", + "baseUrl": "Service URL", + "token": "Access token", + "save": "Save", + "delete": "Delete", + "confirmDelete": { + "title": "Delete remote connection?", + "message": "This will remove \"{name}\" from this device. This action cannot be undone.", + "cancel": "Cancel", + "confirm": "Delete" + }, + "saved": "Remote connection saved.", + "deleted": "Remote connection deleted.", + "loadFailed": "Failed to load remote connections", + "saveFailed": "Failed to save remote connection", + "deleteFailed": "Failed to delete remote connection", + "openFailed": "Failed to open remote workspace", + "connectionLoadFailed": "Failed to load remote connection: {message}", + "connectionExpired": "Remote connection \"{name}\" is expired. Update its token and reload this window." + }, + "ServerFileBrowser": { + "title": "서버 파일 선택", + "pathPlaceholder": "디렉토리 경로 입력...", + "goHome": "홈 디렉토리로", + "navigateUp": "상위 디렉토리로", + "select": "선택", + "cancel": "취소", + "loading": "로드 중...", + "emptyDirectory": "이 디렉토리는 비어 있습니다", + "errorLoadingDir": "디렉토리 로드 실패", + "selectedCount": "{count}개 선택됨" + }, + "BackupSettings": { + "title": "백업 및 복원", + "description": "codeg 데이터의 이동 가능한 백업을 내보내거나 백업에서 복원합니다.", + "tabs": { + "backup": "백업", + "restore": "복원" + }, + "export": { + "includeExternal": "대화 내용 포함", + "includeExternalHint": "각 CLI의 대화 기록(Claude, Codex, Gemini 등)도 함께 보관합니다. 용량이 커집니다.", + "passphrase": "암호문 (선택)", + "passphrasePlaceholder": "비워 두면 암호화하지 않습니다", + "passphraseConfirm": "암호문 확인", + "passphraseMismatch": "암호문이 일치하지 않습니다.", + "noPassphraseWarning": "이 백업에는 비밀 정보(API 키, 토큰)가 평문으로 포함됩니다. 안전한 곳에 보관하세요.", + "passphraseLossWarning": "이 암호문으로 암호화됩니다. 분실하면 백업을 복구할 수 없습니다.", + "button": "백업 내보내기", + "inProgress": "백업 만드는 중…", + "success": "백업을 만들었습니다.", + "started": "백업 다운로드를 시작했습니다." + }, + "restore": { + "selectFile": "백업 파일 선택", + "passphrasePrompt": "이 백업은 암호화되어 있습니다. 암호문을 입력하세요.", + "unlock": "잠금 해제", + "preview": { + "title": "백업 정보", + "encrypted": "암호화됨", + "compatible": "호환됨", + "incompatible": "호환되지 않음", + "createdAt": "생성: {value}", + "appVersion": "앱 버전: {value}", + "incompatibleHint": "이 백업은 더 새로운 버전의 codeg에서 만들어져 복원할 수 없습니다." + }, + "replaceWarning": "복원하면 현재의 모든 codeg 데이터(데이터베이스 및 업로드)가 교체됩니다. 현재 데이터는 먼저 스냅샷되어 복구할 수 있습니다.", + "keyringNote": "데스크톱의 GitHub/채팅 토큰은 OS 키체인에 저장되어 포함되지 않습니다. 복원 후 다시 입력하세요.", + "button": "복원", + "staging": "복원 준비 중…", + "staged": "복원이 준비되었습니다. 다시 시작합니다…", + "restarting": "복원이 준비되었습니다. 서버를 다시 시작합니다…", + "restartTimeout": "서버가 제때 돌아오지 않았습니다. 서버가 켜지면 페이지를 새로 고치세요.", + "externalSideLocation": "대화 기록을 {path}에 복원했습니다", + "confirmTitle": "모든 데이터를 교체할까요?", + "confirmBody": "현재 codeg 데이터베이스와 업로드를 백업으로 교체한 후 다시 시작합니다. 현재 데이터는 먼저 스냅샷됩니다.", + "cancel": "취소", + "confirmAction": "교체 후 다시 시작", + "external": { + "title": "대화 내용", + "hint": "이 백업에는 CLI 대화 기록이 포함됩니다. 복원 위치를 선택하세요.", + "modeSkip": "복원 안 함", + "modeSide": "안전한 별도 폴더에 복원", + "modeOriginal": "CLI 원래 위치에 복원", + "forceOverwrite": "기존 파일 덮어쓰기", + "forceOverwriteHint": "CLI 폴더에 이미 있는 파일을 교체합니다.", + "scanning": "충돌 확인 중…", + "noConflicts": "덮어쓸 기존 파일이 없습니다.", + "conflictCount": "기존 파일 {count}개가 영향을 받습니다.", + "conflictSkipNote": "덮어쓰기를 켜지 않으면 기존 파일은 유지(건너뜀)됩니다." + }, + "restartFailed": "복원이 준비되었지만 서버를 다시 시작하지 못했습니다. 수동으로 다시 시작해 복원을 적용하세요." + }, + "remoteUnsupported": "백업 및 복원은 codeg를 실행 중인 컴퓨터의 데이터를 대상으로 합니다. 현재 원격 작업 공간에 연결되어 있습니다. 해당 서버에서 직접 백업을 관리하세요." + }, + "backup": { + "restore": { + "error": { + "badPassphrase": "암호문이 올바르지 않거나 백업이 손상되었습니다.", + "corrupted": "백업 아카이브가 손상되었습니다.", + "unknownFormat": "이 파일은 인식할 수 있는 codeg 백업이 아닙니다.", + "newerVersion": "이 백업은 codeg {backupVersion}에서 만들어졌으며 현재 버전({appVersion})보다 최신입니다.", + "alreadyPending": "적용 대기 중인 복원이 이미 있습니다. 먼저 다시 시작해 적용한 뒤 새 복원을 준비하세요." + } + }, + "error": { + "diskSpace": "작업을 완료할 디스크 공간이 부족합니다.", + "cancelled": "작업이 취소되었습니다." + } + }, + "WebConnection": { + "disconnectedTitle": "연결이 끊어졌습니다", + "reconnectingDescription": "서버에 다시 연결하는 중입니다. 보통 몇 초 내에 자동으로 복구됩니다.", + "reconnectNow": "지금 다시 연결", + "sessionExpiredTitle": "세션이 만료되었습니다", + "sessionExpiredDescription": "세션이 더 이상 유효하지 않습니다. 계속하려면 다시 로그인하세요.", + "goToLogin": "로그인으로 이동" + }, + "LiveFeedback": { + "placeholder": "{agent}이(가) 작업하는 동안 메모 보내기…", + "agentFallback": "에이전트", + "ariaLabel": "라이브 피드백 메모", + "dialogTitle": "라이브 피드백", + "dialogDescription": "에이전트가 작업하는 동안 메모를 보냅니다. 현재 단계를 중단하지 않고 다음 확인 시 읽습니다.", + "dialogDescriptionInstant": "에이전트가 작업하는 동안 메모를 보냅니다. 메모는 현재 턴에 즉시 삽입되어 에이전트가 바로 확인합니다.", + "channelDowngraded": "이 세션에서는 즉시 삽입을 사용할 수 없습니다. 메모는 저장되어 에이전트가 다음에 확인할 때 전달됩니다.", + "send": "보내기", + "cancel": "취소", + "pending": "대기 중", + "delivered": "수신됨", + "turnEndedUnread": "에이전트가 피드백을 읽기 전에 턴을 마쳤습니다.", + "sendAsMessage": "새 메시지로 보내기", + "dismiss": "닫기", + "turnEndedResent": "턴이 종료되어 새 메시지로 보냈습니다.", + "turnEnded": "턴이 이미 종료되었습니다.", + "submitFailed": "메모를 보내지 못했습니다" + }, + "AgentToolsSettings": { + "title": "대화 내 도구", + "description": "codeg가 대화 안에서 에이전트에게 추가로 제공하는 도구입니다. 에이전트가 시작할 때 주입되므로 변경 사항은 이후에 시작한 에이전트부터 적용됩니다.", + "feedbackLabel": "라이브 피드백", + "feedbackHint": "에이전트가 작업하는 동안 메모와 수정 사항을 보낼 수 있습니다. 즉시 삽입을 지원하는 에이전트는 실행 중인 턴에 메모가 바로 삽입됩니다. 그 외 에이전트는 피드백 확인 도구로 읽는데, 보통 프롬프트에서 언급할 때만 확인합니다. 예: 메시지에 \"실시간 피드백을 정기적으로 확인해\"를 추가하세요.", + "questionLabel": "사용자에게 질문", + "questionHint": "에이전트가 작업을 멈추고 대화 입력창 위에 표시되는 객관식 질문을 할 수 있습니다. 답변(또는 건너뛰기)할 때까지 에이전트는 대기합니다.", + "sessionInfoLabel": "세션 정보 가져오기", + "sessionInfoHint": "메시지에서 참조한 세션(세션 배지)을 에이전트가 조회하여 제목, 에이전트, 상태, 작업 공간, 토큰 사용량, 최근 메시지를 읽을 수 있도록 합니다.", + "automationsLabel": "자동화 만들기", + "automationsHint": "대화를 일정에 따라 실행되는 자동화로 저장합니다. 기본값은 꺼짐 — 자동화는 이후 스스로 에이전트를 시작합니다.", + "workTasksLabel": "할 일 작업 만들기", + "workTasksHint": "대화에서 할 일 보드에 카드를 추가합니다. 기본값은 꺼짐 — 앱 상태를 기록합니다.", + "save": "저장", + "saving": "저장 중…", + "saved": "도구 설정을 저장했습니다", + "saveFailed": "도구 설정 저장에 실패했습니다", + "loadFailed": "불러오기 실패: {detail}" + }, + "NotificationSoundSettings": { + "title": "알림음", + "description": "에이전트 이벤트가 발생하면 짧은 알림음을 재생합니다. 채팅 채널로 전송되는 것과 같은 이벤트이며, 이 설정은 이 기기에만 적용됩니다.", + "enableHint": "기본값은 꺼짐입니다. 알림음은 이 브라우저 또는 앱의 작업 공간 창에서만 재생됩니다.", + "volume": "음량", + "preview": "미리 듣기", + "previewEvent": "{event} 알림음 미리 듣기", + "onlyWhenUnfocused": "창이 활성화되지 않았을 때만 재생", + "onlyWhenUnfocusedHint": "Codeg을 보고 있는 동안에는 소리를 내지 않습니다.", + "eventsTitle": "이벤트", + "eventsHint": "이벤트마다 소리를 선택하세요. “무음”을 선택하면 재생하지 않습니다. 같은 이벤트가 몇 초 안에 반복되면 한 번만 재생됩니다.", + "toneNone": "무음", + "toneChime": "차임", + "toneDing": "딩", + "toneBlip": "블립", + "tonePop": "팝", + "toneAlert": "알림", + "toneDescend": "하강음" + }, + "LogsSettings": { + "loading": "불러오는 중…", + "sectionTitle": "실행 로그", + "sectionDescription": "애플리케이션 진단 로그를 보고 구성합니다. 로그는 로컬 파일에 기록되며 실시간 보기를 위해 메모리에도 보관됩니다.", + "captureTitle": "로그 수준", + "captureDescription": "기록되는 상세 수준을 제어합니다. 수준이 높을수록(Debug, Trace) 더 많이 기록되지만 로그도 커집니다. '끔'은 로깅을 비활성화합니다.", + "captureLabel": "수집 수준", + "levels": { + "off": "끔", + "error": "오류", + "warn": "경고", + "info": "정보", + "debug": "디버그", + "trace": "추적" + }, + "viewerTitle": "최근 로그", + "viewerDescription": "최근 로그 레코드를 실시간으로 봅니다. 수준으로 필터링하거나 텍스트를 검색하세요.", + "searchPlaceholder": "메시지 또는 대상 검색…", + "viewLevels": { + "all": "모든 수준", + "error": "오류 이상", + "warn": "경고 이상", + "info": "정보 이상", + "debug": "디버그 이상", + "trace": "추적 이상" + }, + "pause": "일시정지", + "resume": "실시간", + "refresh": "새로고침", + "clear": "지우기", + "openFolder": "폴더 열기", + "shownCount": "{shown} / {total} 표시됨", + "empty": "표시할 로그가 없습니다.", + "levelSaveFailed": "로그 수준 저장 실패", + "openFolderFailed": "로그 폴더 열기 실패", + "downloadFailed": "로그 파일 다운로드 실패", + "filesTitle": "로그 파일", + "filesDescription": "실시간 버퍼를 넘어선 기록을 위해 디스크에서 전체 로그 파일을 다운로드합니다.", + "filesEmpty": "아직 로그 파일이 없습니다.", + "download": "다운로드", + "downloadTruncated": "파일이 커서 최신 {size}만 다운로드했습니다. 전체 파일은 로그 디렉터리에 있습니다.", + "captureEnvLocked": "로그 수준은 RUST_LOG / CODEG_LOG 환경 변수로 제어됩니다. 변경하려면 해당 변수를 수정하세요.", + "targetsTitle": "모듈별 재정의", + "targetsDescription": "전역 레벨을 바꾸지 않고 특정 모듈(예: codeg_lib::acp)의 레벨을 따로 설정합니다.", + "targetsAdd": "추가", + "targetsRemove": "재정의 제거", + "toggleDetails": "세부 정보 전환" + }, + "Automations": { + "title": "자동화", + "new": "새 자동화", + "empty": "아직 자동화가 없습니다", + "emptyHint": "하나를 만들어 에이전트 작업을 예약하거나 수동으로 실행하세요.", + "name": "이름", + "namePlaceholder": "예: 야간 PR 검토", + "prompt": "프롬프트", + "promptPlaceholder": "에이전트가 무엇을 하길 원하나요?", + "agent": "에이전트", + "folder": "워크스페이스 폴더", + "folderPlaceholder": "폴더 선택", + "isolation": "격리", + "isolationWorktree": "실행마다 새 worktree", + "isolationShared": "폴더에서 실행", + "isolationSharedCaveat": "실행이 이 폴더의 작업 트리를 직접 사용하므로 커밋하지 않은 변경 사항과 충돌할 수 있습니다. 각 실행을 격리하려면 워크트리 옵션을 활성화하세요.", + "trigger": "트리거", + "triggerSchedule": "예약 실행", + "triggerManual": "수동만", + "cron": "예약(cron)", + "cronPlaceholder": "0 9 * * 1-5", + "timezone": "시간대", + "nextRun": "다음 실행", + "branch": "브랜치", + "branchOptional": "브랜치(선택)", + "enabled": "사용", + "save": "저장", + "cancel": "취소", + "edit": "편집", + "delete": "삭제", + "runNow": "지금 실행", + "cancelRun": "실행 취소", + "runHistory": "실행 기록", + "noRuns": "아직 실행 기록이 없습니다", + "allFolders": "모든 폴더", + "filterAll": "전체", + "noMatches": "일치하는 자동화가 없습니다", + "viewConversation": "대화 보기", + "lastRun": "마지막 실행", + "never": "없음", + "running": "실행 중", + "deleteTitle": "이 자동화를 삭제할까요?", + "deleteDescription": "자동화와 예약이 삭제됩니다. 실행 기록은 유지됩니다.", + "statusRunning": "실행 중", + "statusSucceeded": "성공", + "statusFailed": "실패", + "statusCancelled": "취소됨", + "statusSkipped": "건너뜀", + "errorName": "이름은 필수입니다", + "errorPrompt": "프롬프트는 필수입니다", + "errorCron": "예약 자동화에는 cron 식이 필요합니다", + "errorFolder": "워크스페이스 폴더를 선택하세요", + "presetHourly": "매시간", + "presetDaily": "매일 오전 9시", + "presetWeekdays": "평일 오전 9시", + "presetCustom": "사용자 지정", + "probing": "옵션 불러오는 중…", + "retry": "다시 시도", + "configNone": "이 에이전트에는 구성 가능한 옵션이 없습니다", + "inherit": "에이전트 기본값", + "mode": "모드", + "config": "구성", + "branchPlaceholder": "(기본 브랜치)", + "selectHint": "세부 정보를 보려면 자동화를 선택하세요", + "refresh": "새로고침", + "onboardTitle": "반복적인 에이전트 작업 자동화", + "onboardHint": "코드 리뷰, 의존성 업데이트, 이슈 분류를 일정에 따라 또는 필요할 때 에이전트가 수행하도록 예약하세요.", + "headerSubtitle": "예약 및 온디맨드 에이전트 작업", + "startFromTemplate": "템플릿으로 시작", + "blankTitle": "빈 자동화", + "blankDesc": "에이전트 작업을 처음부터 구성합니다.", + "backToTemplates": "템플릿", + "sectionSchedule": "일정 및 대상", + "sectionTarget": "대상", + "sectionAction": "동작", + "actionLaunchSession": "세션 시작", + "actionEnqueueTask": "작업 대기열에 추가", + "actionEnqueueTaskHint": "실행될 때마다 이 자동화 이름을 제목으로 하는 할 일 작업이 대상 폴더의 할 일 목록에 추가되며, 작업 엔진이 보드 설정에 따라 실행합니다.", + "sectionPrompt": "프롬프트", + "nextIn": "{rel} 후 실행", + "manual": "수동", + "schedEveryMinutes": "{n}분마다", + "schedHourly": "1시간마다", + "schedDaily": "매일 {time}", + "schedWeekdays": "평일 {time}", + "schedWeekly": "매주 {day} {time}", + "schedMonthly": "매월 {day}일 {time}", + "dow0": "일요일", + "dow1": "월요일", + "dow2": "화요일", + "dow3": "수요일", + "dow4": "목요일", + "dow5": "금요일", + "dow6": "토요일", + "tplCodeReviewTitle": "코드 리뷰", + "tplCodeReviewDesc": "최근 변경 사항에서 버그, 회귀, 품질 문제를 검토합니다.", + "tplDependencyUpdatesTitle": "의존성 업데이트", + "tplDependencyUpdatesDesc": "오래된 의존성을 찾아 안전한 업그레이드를 제안합니다.", + "tplTestCoverageTitle": "테스트 커버리지", + "tplTestCoverageDesc": "테스트되지 않은 코드 경로를 찾아 누락된 테스트를 추가합니다.", + "tplTodoSweepTitle": "TODO 정리", + "tplTodoSweepDesc": "TODO와 FIXME 주석을 모아 우선순위에 따라 분류합니다.", + "tplCiTriageTitle": "CI 분류", + "tplCiTriageDesc": "최근 실패한 검사를 조사하고 수정을 제안합니다.", + "tplReleaseNotesTitle": "릴리스 노트", + "tplReleaseNotesDesc": "지난 릴리스 이후의 변경 사항을 요약해 변경 로그를 만듭니다.", + "tplSecurityAuditTitle": "보안 감사", + "tplSecurityAuditDesc": "취약점과 위험한 패턴을 스캔하고 결과를 보고합니다.", + "enable": "활성화", + "disable": "비활성화", + "moreActions": "추가 작업", + "statusDisabled": "비활성화됨", + "cronBuilderTitle": "일정 빌더", + "cronFreqLabel": "빈도", + "cronFreqMinutes": "N분마다", + "cronFreqHourly": "매시간", + "cronFreqDaily": "매일", + "cronFreqWeekdays": "평일", + "cronFreqWeekly": "매주", + "cronFreqMonthly": "매월", + "cronFreqCustom": "사용자 지정", + "cronEveryLabel": "간격(분)", + "cronTimeLabel": "시간", + "cronHourLabel": "시", + "cronMinuteLabel": "분", + "cronDowLabel": "요일", + "cronDomLabel": "일", + "cronApply": "적용", + "cronPreviewLabel": "미리 보기", + "cronOpenBuilder": "일정 빌더 열기", + "branchDefault": "기본 브랜치", + "branchUseCustom": "\"{query}\" 사용", + "branchLocal": "로컬", + "branchRemote": "원격", + "branchSearchPlaceholder": "브랜치 검색…", + "branchNone": "브랜치 없음" + }, + "Tasks": { + "title": "할 일", + "new": "새 작업", + "empty": "아직 작업이 없습니다", + "emptyHint": "할 일을 추가하고 실행하세요. 에이전트가 독립된 worktree에서 작업하고, 결과를 검토한 뒤 병합합니다.", + "emptyColTodo": "아직 할 일이 없습니다", + "emptyColInProgress": "진행 중인 작업이 없습니다", + "emptyColAttention": "처리할 작업이 없습니다", + "emptyColDone": "완료된 작업이 아직 없습니다", + "allFolders": "모든 폴더", + "showCanceled": "취소됨 표시", + "showArchived": "보관된 항목 표시", + "filter": "필터", + "viewSwitchToBoard": "보드 보기로 전환", + "viewSwitchToList": "목록 보기로 전환", + "statusFilter": "상태", + "statusFilterAll": "모든 상태", + "listEmpty": "현재 필터와 일치하는 작업이 없습니다", + "listColStatus": "상태", + "listColTask": "작업", + "listColLocation": "위치", + "listColChanges": "변경", + "listColUpdated": "업데이트", + "colTodo": "할 일", + "colInProgress": "진행 중", + "colAttention": "처리 필요", + "colDone": "완료", + "statusTodo": "할 일", + "statusQueued": "대기 중", + "statusPreparing": "준비 중", + "statusRunning": "실행 중", + "statusAwaitingInput": "입력 대기", + "statusReview": "검토 대기", + "statusMerging": "병합 중", + "statusDone": "완료", + "statusFailed": "실패", + "statusCanceled": "취소됨", + "statusInterrupted": "중단됨", + "badgeCleanupFailed": "정리 실패", + "badgeWorktreeKept": "worktree 유지", + "badgeWorktreeRemoved": "worktree 삭제됨", + "filesChanged": "{count}개 파일", + "actionStart": "시작", + "actionSchedule": "예약 실행", + "actionCancel": "취소", + "actionRetry": "다시 시도", + "actionRequeue": "다시 대기열에", + "actionViewSession": "대화 보기", + "actionEdit": "편집", + "actionDelete": "삭제", + "actionRetryCleanup": "정리 다시 시도", + "actionMerge": "병합", + "actionUnqueueMerge": "병합 대기 취소", + "actionEditQueuedMerge": "대기 중인 병합 수정", + "badgeMergeQueued": "병합 대기 중", + "badgeMergeQueuedRank": "병합 대기 · {rank}번째", + "badgeMergeQueuedHint": "이 프로젝트에서 진행 중인 병합이 끝나기를 기다리는 중이며, 차례가 되면 자동으로 시작합니다.", + "actionComplete": "완료", + "actionAbandon": "포기", + "cancelTitle": "작업을 취소할까요?", + "cancelDescription": "작업이 취소됨으로 바뀝니다. worktree는 그대로 두며 나중에 다시 대기열에 넣을 수 있습니다.", + "cancelReasonLabel": "취소 사유 (선택)", + "cancelReasonPlaceholder": "예: 방향이 잘못돼서 설명을 다시 쓸게요", + "cancelKeep": "그대로 두기", + "cancelSubmit": "작업 취소", + "restartTitleRetry": "작업 다시 시도", + "restartTitleRequeue": "작업 다시 대기열에", + "restartDescription": "메모(선택)를 남기면 다음 실행 프롬프트에 담겨 에이전트에게 전달됩니다.", + "scheduleTitle": "작업 실행 예약", + "scheduleDescription": "작업은 '할 일'에 남아 있다가 지정한 시각에 자동으로 시작됩니다. 폴더의 동시 실행 한도는 그대로 적용됩니다.", + "scheduleDateLabel": "날짜", + "schedulePickDate": "날짜 선택", + "scheduleTimeLabel": "시간", + "schedulePreview": "{time}에 실행", + "schedulePastHint": "이미 지난 시각입니다. 저장하면 바로 시작합니다.", + "scheduleInAnHour": "1시간 후", + "scheduleInThreeHours": "3시간 후", + "scheduleTomorrow": "내일 9:00", + "scheduleClear": "예약 해제", + "scheduleBadge": "{time}에 시작 예정", + "toastScheduled": "{time}에 실행하도록 예약했습니다", + "toastScheduleCleared": "예약을 해제했습니다", + "actionFollowUp": "이어서 요청", + "actionAddNote": "메모 추가", + "followUpSubmit": "보내기", + "followUpIntentRevise": "수정 요청", + "followUpIntentContinue": "계속 진행", + "followUpIntentQuestion": "질문하기", + "followUpIntentVerify": "자체 점검", + "followUpPlaceholderRevise": "무엇을 고쳐야 하나요? 같은 세션에서 이어집니다.", + "followUpPlaceholderContinue": "다음은 무엇인가요? 지금까지의 작업은 그대로 둡니다.", + "followUpPlaceholderQuestion": "무엇이 궁금한가요? 파일은 건드리지 않고 답변만 합니다.", + "followUpPlaceholderVerify": "선택: 특별히 확인했으면 하는 부분이 있나요?", + "followUpPlaceholderRetry": "선택: 이번엔 무엇을 다르게 할까요? 예: pnpm install 먼저 실행", + "followUpPlaceholderRequeue": "선택: 왜 취소했고, 이번엔 무엇이 달라져야 하나요?", + "actionArchive": "보관", + "actionUnarchive": "보관 해제", + "archiveAllDone": "모두 보관", + "dropToStart": "놓으면 실행 시작", + "errorView": "보기", + "notifyReview": "검수 대기: {title}", + "notifyFailed": "작업 실패: {title}", + "createFromMessage": "이 메시지로 작업 만들기", + "detailTokens": "총 토큰", + "editorTitleNew": "새 작업", + "editorTitleEdit": "작업 편집", + "templates": "템플릿", + "templatesEmpty": "아직 템플릿이 없습니다.", + "templateSaveCurrent": "현재 내용을 템플릿으로 저장", + "templateDelete": "템플릿 삭제", + "transcriptTitle": "작업 대화", + "transcriptDescription": "작업 에이전트 세션의 읽기 전용 실시간 보기입니다.", + "phaseWork": "작업 실행", + "phaseRetry": "다시 실행", + "phaseReturn": "이어서 요청", + "phaseMerge": "병합", + "titleLabel": "제목", + "titlePlaceholder": "무엇을 해야 하나요?", + "promptLabel": "작업 설명", + "promptPlaceholder": "에이전트에게 작업을 설명하세요 — @로 파일 참조, /로 명령", + "folderPlaceholder": "폴더 선택", + "agentInheritedHint": "작업 설정에서 상속됨 — 변경하면 이 작업에만 적용됩니다", + "agentOverrideReset": "상속으로 되돌리기", + "sectionTarget": "대상", + "errorTitle": "제목을 입력하세요", + "errorPrompt": "작업 설명을 입력하세요", + "errorFolder": "폴더를 선택하세요", + "save": "저장", + "cancel": "취소", + "mergeTitle": "작업 병합", + "mergeQueuedTitle": "대기 중인 병합", + "mergeQueueHint": "이 프로젝트의 다른 작업이 병합 중입니다. 이 작업은 대기열에 들어가며 앞의 병합이 끝나는 대로 자동으로 시작합니다.", + "mergeQueueUpdateHint": "이 작업은 이미 병합을 기다리고 있습니다. 제출하면 내용만 업데이트되고 대기 순서는 그대로 유지됩니다.", + "mergeDescription": "{branch}을(를) {base}에 병합합니다. worktree의 커밋되지 않은 변경은 먼저 커밋됩니다.", + "mergeMessage": "커밋 메시지", + "mergeMessagePlaceholder": "예: feat: add login validation", + "mergeAutoMessage": "커밋 메시지를 에이전트가 작성하도록 하기", + "strategySquash": "하나의 커밋으로 합치기", + "strategySquashHint": "작업의 모든 변경 사항이 하나의 기록으로 메인 브랜치에 반영되어 히스토리가 깔끔해집니다.", + "strategyMerge": "전체 히스토리 유지", + "strategyMergeHint": "작업 중의 모든 커밋을 그대로 유지하고 병합 기록을 하나 추가합니다. 각 단계를 추적할 수 있습니다.", + "mergeDeleteWorktree": "병합 후 worktree 삭제", + "mergeSubmit": "병합", + "mergeSubmitQueue": "병합 대기열에 추가", + "mergeQueuedToast": "병합 대기열에 추가했습니다. 현재 병합이 끝나는 대로 시작합니다.", + "completeTitle": "작업 완료", + "completeDescription": "이 작업은 파일을 변경하지 않아 병합할 것이 없습니다. 그대로 완료로 표시합니다.", + "completeDescriptionNoWorktree": "이 작업의 worktree가 삭제되어 더 이상 병합할 수 없습니다. 그대로 완료로 표시합니다. 병합되지 않은 커밋이 남아 있는 작업 브랜치는 유지됩니다.", + "completeDeleteWorktree": "완료 후 worktree 삭제", + "completeSubmit": "완료", + "settingsTitle": "작업 설정", + "settingsDescription": "{folder}의 작업 기본값입니다.", + "settingsScope": "적용 범위", + "settingsScopeGlobal": "모든 폴더(전역 기본값)", + "settingsScopeGlobalHint": "별도 설정이 없는 폴더는 이 전역 기본값을 사용합니다.", + "settingsSource": "설정 출처", + "settingsSourceGlobal": "전역 기본값 사용", + "settingsSourceCustom": "개별 설정", + "settingsSourceGlobalFollow": "전역 작업 설정을 따릅니다. 전역 변경 사항이 자동으로 적용됩니다.", + "settingsSourceCustomHint": "이 폴더만의 설정을 저장하며 더 이상 전역 기본값을 따르지 않습니다.", + "settingsAgent": "기본 에이전트", + "settingsMaxConcurrent": "최대 동시 작업 수", + "settingsMaxConcurrentHint": "0 = 무제한", + "settingsAutoProcess": "자동 처리", + "settingsAutoProcessHint": "할 일 작업이 동시 실행 한도 내에서 자동으로 시작됩니다.", + "settingsMergeStrategy": "기본 병합 전략", + "settingsMergeStrategyHint": "병합할 때 작업의 변경 사항을 브랜치 히스토리에 어떻게 기록할지 정합니다.", + "settingsAutoMerge": "자동 병합", + "settingsAutoMergeHint": "검토 대기에 도달하고 병합할 변경이 있는 작업은 병합 버튼을 누른 것과 똑같이 자동으로 병합됩니다. 커밋 메시지는 에이전트가 작성하고 worktree 처리는 아래 기본값을 따릅니다. 사전 점검이 실패했거나 병합에 실패한 작업은 남아서 기다립니다.", + "settingsDeleteWorktree": "머지 후 worktree 삭제", + "settingsDeleteWorktreeHint": "머지 대화상자에서 기본으로 선택됩니다. 거기서 바꿀 수도 있습니다.", + "settingsWorktreeRoot": "워크트리 위치", + "settingsWorktreeRootHint": "새 작업의 worktree를 이 디렉터리 아래에 작업마다 하나씩 만듭니다. 비워 두면 프로젝트 폴더와 같은 위치에 만듭니다. \"~\"는 홈 디렉터리이고 상대 경로는 프로젝트 폴더 기준입니다.", + "settingsWorktreeRootPlaceholder": "~/codeg-worktrees", + "settingsWorktreeRootBrowse": "워크트리 디렉터리 선택", + "settingsPreflight": "사전 점검 명령", + "settingsPreflightHint": "작업이 검토 단계에 도달하면 워크트리에서 실행.", + "settingsPreflightCustomPlaceholder": "pnpm test", + "settingsInitCommand": "워크트리 초기화 명령", + "settingsInitCommandHint": "워크트리를 새로 만든 뒤 에이전트 시작 전에 실행됩니다.", + "settingsInitCommandPlaceholder": "pnpm install", + "settingsTabGeneral": "일반", + "settingsTabMerge": "병합", + "settingsTabWorktree": "워크트리", + "settingsTabPrompts": "프롬프트", + "settingsPromptsIntro": "각 단계에는 이미 기본 프롬프트가 들어 있습니다 — 작업 내용, 워크트리 규칙, 머지 단계의 구체적인 git 절차. 여기에 적은 내용은 추가 지시로 맨 뒤에 덧붙으며, 기본 프롬프트를 보완할 뿐 대체하지 않습니다.", + "settingsPromptStageAll": "전체 단계", + "settingsPromptPlaceholderAll": "예: AGENTS.md의 프로젝트 규칙을 따르고, 마지막 요약은 두 문장 이내로", + "settingsPromptPlaceholderWork": "예: 관련 테스트를 먼저 읽고, 작은 단위로 자주 커밋", + "settingsPromptPlaceholderRetry": "예: 이어서 하기 전에 이미 커밋된 내용을 확인하고, 끝난 작업은 다시 하지 말 것", + "settingsPromptPlaceholderReturn": "예: 언급된 항목을 하나씩 처리하고, 관련 없는 리팩터링은 하지 마세요", + "settingsPromptPlaceholderMerge": "예: 최종 반영 커밋 메시지는 한국어로, 수동으로 해결한 충돌은 따로 밝힐 것", + "settingsPromptHintAll": "머지 실행을 포함해 에이전트가 받는 모든 프롬프트에 추가됩니다.", + "settingsPromptHintWork": "작업을 처음 실행할 때 추가됩니다.", + "settingsPromptHintRetry": "중단되거나 실패한 작업을 다시 이어갈 때 추가됩니다.", + "settingsPromptHintReturn": "검토 대기 작업에 이어서 요청할 때(수정·추가 작업·자체 점검) 덧붙습니다.", + "settingsPromptHintMerge": "에이전트가 작업을 기준 브랜치에 병합할 때 추가됩니다.", + "preflightPassed": "{name} 통과", + "preflightFailed": "{name} 실패", + "preflightRunning": "{name} 실행 중…", + "detailDescription": "작업 상세", + "detailSummary": "결과", + "detailFiles": "변경된 파일", + "detailDiffAll": "전체 차이 보기", + "detailDiffAllTitle": "전체 차이", + "detailNoChanges": "기준 대비 변경 사항이 아직 없습니다", + "detailTimeline": "진행 기록", + "detailTimelineEmpty": "아직 활동이 없습니다", + "showMore": "더 보기", + "showLess": "접기", + "detailInfo": "상세 정보", + "detailBranch": "브랜치", + "detailMergeCommit": "병합 커밋", + "detailChanges": "변경 사항", + "detailScheduled": "시작 예정", + "detailCreated": "생성 시간", + "detailStarted": "시작 시간", + "detailFinished": "완료 시간", + "diffLoading": "차이를 불러오는 중…", + "deleteConfirmTitle": "작업을 삭제할까요?", + "deleteConfirmBody": "“{title}”이(가) 보드에서 제거됩니다. 실행 중이면 먼저 취소됩니다.", + "deleteWithWorktree": "worktree도 함께 삭제", + "eventCreated": "생성됨", + "eventStatusChanged": "상태 변경", + "eventConfigEffective": "실행 구성", + "eventInitCommand": "초기화 명령", + "eventAgentProgress": "에이전트 진행", + "eventAgentVerdict": "에이전트 판정", + "eventMergeAttempt": "병합 시작", + "eventMergeQueued": "병합 대기열에 추가", + "eventMergeConflict": "병합 충돌", + "eventPreflight": "사전 점검", + "eventCleanupFailed": "worktree 정리 실패", + "eventResumeFallback": "세션 재개 실패, 새 세션으로 전환", + "eventUserAction": "사용자 작업", + "eventDiffStat": "변경 스냅샷" + }, + "CustomSkillsSettings": { + "loading": "사용자 지정 스킬 불러오는 중…", + "category": "사용자 지정", + "searchPlaceholder": "이름, ID 또는 설명으로 사용자 지정 스킬 검색", + "states": { + "not_linked": "사용 안 함", + "linked_to_codeg": "사용 중", + "linked_elsewhere": "다른 위치에 연결됨", + "blocked_by_real_directory": "실제 폴더가 차지함", + "broken": "손상된 링크" + }, + "actions": { + "new": "새로 만들기", + "import": "가져오기", + "importFromAgent": "에이전트에서 가져오기", + "cancel": "취소", + "save": "저장" + }, + "rowMenu": { + "edit": "편집", + "duplicate": "복제", + "delete": "삭제" + }, + "bulk": { + "delete": "선택 항목 삭제" + }, + "editor": { + "createTitle": "새 사용자 지정 스킬", + "editTitle": "사용자 지정 스킬 편집", + "description": "사용자 지정 스킬은 공유 저장소(~/.codeg/skills)에 있으며 모든 에이전트에서 사용할 수 있습니다.", + "idLabel": "스킬 ID", + "idPlaceholder": "예: my-workflow", + "contentLabel": "SKILL.md", + "contentPlaceholder": "여기에 스킬의 SKILL.md를 작성하세요…", + "preview": "미리보기", + "edit": "편집", + "emptyBody": "아직 내용이 없습니다." + }, + "duplicate": { + "title": "스킬 복제", + "description": "\"{id}\"을(를) 기반으로 새 ID로 복사본을 만듭니다.", + "newIdPlaceholder": "새 스킬 ID", + "confirm": "복제" + }, + "import": { + "title": "가져올 스킬 폴더 선택" + }, + "importFromAgent": { + "title": "에이전트에서 스킬 가져오기", + "description": "에이전트의 자체 스킬을 공유 저장소로 복사하면 어떤 에이전트에서도 사용할 수 있습니다.", + "agentLabel": "에이전트", + "agentPlaceholder": "에이전트 선택", + "selectAll": "모두 선택 ({count})", + "loading": "에이전트의 스킬을 불러오는 중…", + "unsupported": "이 에이전트는 스킬 디렉터리를 제공하지 않습니다.", + "empty": "이 에이전트에는 가져올 스킬이 없습니다.", + "alreadyInLibrary": "라이브러리에 있음", + "confirm": "선택 항목 가져오기 ({count})" + }, + "delete": { + "title": "사용자 지정 스킬을 삭제할까요?", + "body": "{count}개의 사용자 지정 스킬을 중앙 저장소에서 제거하고 모든 에이전트에서 링크를 해제합니다. 이 작업은 취소할 수 없습니다.", + "confirm": "삭제" + }, + "toasts": { + "loadFailed": "스킬 불러오기 실패", + "idRequired": "스킬 ID를 입력하세요", + "created": "사용자 지정 스킬 생성됨", + "updated": "사용자 지정 스킬 업데이트됨", + "saveFailed": "스킬 저장 실패", + "imported": "스킬 가져옴", + "importFailed": "스킬 가져오기 실패", + "duplicated": "스킬 복제됨", + "duplicateFailed": "스킬 복제 실패", + "deleted": "{count}개 스킬 삭제됨", + "deletedPartial": "{ok}개 삭제, {failed}개 실패", + "deleteFailed": "스킬 삭제 실패", + "importedFromAgent": "{count}개의 스킬을 가져왔습니다", + "importedFromAgentPartial": "{ok}개 가져옴, {failed}개 실패", + "importFromAgentAllSkipped": "가져올 항목 없음 — {count}개가 이미 라이브러리에 있습니다", + "importFromAgentFailed": "에이전트에서 가져오기 실패" + } + }, + "CodexModelEditor": { + "customizedNotice": "모델 목록을 사용자 지정했으므로 이제 codeg가 codex의 전체 모델 표를 관리합니다. codex가 이후 추가하는 공식 모델은 자동으로 나타나지 않습니다. 아래의 새로 고침을 클릭한 뒤 다시 저장하면 동기화됩니다. 사용자 지정을 모두 지우면 codex 자동 업데이트로 되돌아갑니다.", + "officialsTitle": "공식 모델", + "officialsHint": "실행하는 codex의 공식 모델을 자동 포함합니다. 필요 없는 항목은 삭제하세요.", + "officialsEmpty": "사용 가능한 공식 모델이 없습니다.", + "refresh": "codex에서 새로고침", + "readdOfficial": "공식 다시 추가", + "customsTitle": "사용자 지정 모델", + "customsEmpty": "사용자 지정 모델이 없습니다.", + "addCustom": "사용자 지정 추가", + "slugPlaceholder": "모델 ID(slug)", + "displayNamePlaceholder": "표시 이름", + "contextWindow": "컨텍스트", + "makeDefault": "기본값으로 설정", + "defaultHint": "기본 모델", + "remove": "제거", + "advanced": "고급", + "baseTemplate": "기본 템플릿", + "baseTemplateHint": "필수 필드(시스템 프롬프트, 도구, 제한)를 복제할 공식 모델.", + "groupBehavior": "동작 및 기능", + "fieldReasoningLevel": "기본 추론 강도", + "fieldReasoningSummary": "추론 요약", + "fieldVerbosity": "상세도", + "fieldShellType": "셸 유형", + "fieldApplyPatch": "패치 적용 도구", + "fieldReasoningSummaries": "추론 요약 지원", + "fieldSupportVerbosity": "상세도 제어", + "fieldParallelToolCalls": "병렬 도구 호출", + "fieldSearchTool": "웹 검색 도구", + "optNone": "없음", + "groupInstructions": "설명 및 시스템 프롬프트", + "fieldDescription": "설명", + "baseInstructions": "시스템 프롬프트(base_instructions)" + }, + "DiagnosticsSettings": { + "title": "환경 진단", + "description": "이 앱이 자체 프로세스에서 에이전트 CLI를 어떻게 확인하는지 점검합니다(터미널과 다를 수 있음).", + "loading": "진단 실행 중…", + "error": "진단 실패", + "rerun": "다시 실행", + "copyAll": "전체 복사", + "copied": "진단 정보를 클립보드에 복사했습니다", + "button": "진단", + "verdict": { + "ok": "환경이 정상입니다. 그래도 설치되지 않았다고 표시되면 앱을 완전히 재시작하여 프리픽스 캐시를 새로 고치세요.", + "node_missing": "앱 PATH에서 Node.js를 찾을 수 없습니다.", + "npm_missing": "앱 PATH에서 npm을 찾을 수 없습니다.", + "not_installed": "이 에이전트가 설치되지 않은 것 같습니다.", + "installed_but_unresolved": "설치된 것으로 기록되어 있지만 앱이 실행 파일을 찾지 못합니다.", + "user_prefix_not_on_path": "폴백 프리픽스(~/.codeg/npm-global)에 설치되었지만 앱 PATH에 없습니다. 앱을 완전히 재시작한 후 다시 시도하세요.", + "homebrew_bin_not_on_path": "Homebrew bin에 설치되었지만 앱 PATH에 없습니다(Apple Silicon keg 분리).", + "terminal_only_path": "이 명령은 터미널에서는 확인되지만 앱에서는 확인되지 않습니다. GUI PATH 불일치입니다. 터미널에서 앱을 실행하거나 에이전트 설정에서 다시 설치하세요.", + "npm_prefix_timeout": "npm prefix -g가 너무 느립니다(1.5초 초과). 폴백 감지를 건너뛰었습니다. 앱을 재시작한 후 다시 시도하세요.", + "node_too_old": "현재 Node.js가 이 에이전트의 요구 버전보다 낮습니다. Node.js를 업그레이드하세요.", + "adapter_missing_native_present": "사용 중인 {agent} CLI는 설치되어 있지만, Codeg가 실행하는 것은 별도의 ACP 어댑터 패키지이며 그것이 아직 설치되지 않았습니다. 에이전트 설정에서 설치하세요. 기존 CLI는 건드리지 않으며 로그인도 공유됩니다.", + "adapter_missing": "Codeg는 {agent}에 대해 별도의 ACP 어댑터 패키지를 실행하는데, 아직 설치되지 않았습니다. 에이전트 설정에서 설치하세요 — 벤더 CLI만 설치하는 것으로는 충분하지 않습니다." + } + }, + "TokenUsage": { + "title": "토큰 사용량", + "rangeLabel": "기간", + "range7d": "7일", + "range30d": "30일", + "range90d": "90일", + "rangeThisMonth": "이번 달", + "rangeThisYear": "올해", + "rangeAll": "전체", + "rangeCustom": "사용자 지정", + "moreRanges": "더보기", + "customRangePick": "기간 선택", + "bucketLabel": "집계 단위", + "bucketDay": "일", + "bucketWeek": "주", + "bucketMonth": "월", + "bucketUnitDay": "날", + "bucketUnitWeek": "주", + "bucketUnitMonth": "월", + "folderFilter": "폴더", + "allFolders": "모든 폴더", + "agentFilter": "에이전트", + "allAgents": "모든 에이전트", + "modelFilter": "모델", + "allModels": "모든 모델", + "searchPlaceholder": "검색…", + "noMatches": "일치하는 항목 없음", + "clearFilter": "선택 해제", + "resetFilters": "필터 초기화", + "refresh": "새로 고침", + "rebuild": "전체 재구성", + "rebuildHint": "집계된 데이터를 버리고 모든 세션 기록을 다시 읽습니다. codeg 밖의 CLI가 기록을 이어썼을 때 사용하세요.", + "syncing": "세션 집계 중…", + "syncProgress": "{done} / {total}", + "syncDone": "{synced}개 세션을 집계했습니다", + "syncFailed": "일부 세션을 읽지 못했습니다", + "syncBusy": "이미 새로 고침이 진행 중입니다", + "lastSynced": "{time}에 업데이트", + "lastSyncedNever": "집계된 적 없음", + "tileTotal": "총 토큰", + "tileSessions": "세션 수", + "tileTurns": "대화 턴", + "tileActiveDays": "활동 일수", + "tileGenTime": "생성 시간", + "vsPrevious": "이전 기간 대비", + "deltaNew": "신규", + "trendTitle": "사용량 추이", + "trendEmpty": "이 기간에는 사용량이 없습니다", + "trendTurns": "턴", + "trendSessions": "세션", + "compositionTitle": "토큰 구성", + "compositionHint": "입력은 보낸 내용, 출력은 모델이 쓴 내용, 캐시 읽기는 다시 보내지 않아도 된 컨텍스트입니다.", + "compositionNote": "이 캐시 적중을 정가로 다시 보냈다면 {value}가 더 들었을 것입니다.", + "inputTokens": "입력", + "outputTokens": "출력", + "cacheWrite": "캐시 쓰기", + "cacheRead": "캐시 읽기", + "freshTokens": "신규 연산 토큰", + "cacheHitCaption": "캐시 적중", + "cacheHeroTitleHigh": "컨텍스트 대부분은 다시 보낼 필요가 없었습니다", + "cacheHeroTitleLow": "컨텍스트 대부분이 아직 정가로 계산됩니다", + "cacheHeroDesc": "{cached}의 컨텍스트를 캐시가 감당했고, 이 기간에 실제로 새로 연산된 것은 {fresh}뿐입니다.", + "cacheSavedSuffix": "재전송을 {saved}만큼 아꼈습니다.", + "avgPerSession": "세션당 평균", + "avgTurnsPerSession": "세션당 평균 {count}턴", + "avgPerActiveDay": "활동일당 평균", + "peakBucket": "가장 많은 {bucket}", + "peakHour": "피크 시간대", + "daysValue": "{count}일", + "idleDays": "쉬어간 날", + "byFolderTitle": "폴더별", + "byAgentTitle": "에이전트별", + "byModelTitle": "모델별", + "distributionTitle": "사용량 분포", + "distributionHint": "선택한 기준으로 세션과 토큰을 집계합니다. 행을 클릭하면 해당 항목으로 필터링됩니다.", + "otherLabel": "기타", + "unknownModel": "모델 미기록", + "emptyBreakdown": "기록이 없습니다", + "sessionsCount": "{count}개 세션", + "heatmapTitle": "작업 리듬", + "heatmapHint": "로컬 요일·시간대별 토큰 분포입니다.", + "heatmapPeakHint": "{hour}:00 전후가 가장 밀집되어 있습니다.", + "less": "적음", + "more": "많음", + "heatmapCell": "{weekday} {hour}:00 — {value} 토큰", + "weekMon": "월", + "weekTue": "화", + "weekWed": "수", + "weekThu": "목", + "weekFri": "금", + "weekSat": "토", + "weekSun": "일", + "topSessionsTitle": "소비가 큰 세션", + "untitledSession": "제목 없는 세션", + "topSessionsEmpty": "이 기간에는 세션이 없습니다", + "streakLongest": "최장 연속", + "streakLongestDays": "최장 연속 {count}일", + "share": "공유", + "moreActions": "기타 작업", + "shareDialogTitle": "사용량 카드 공유", + "shareDialogHint": "지금 보고 있는 기간과 필터의 스냅샷입니다.", + "shareSave": "이미지 저장", + "shareCopy": "이미지 복사", + "shareCopied": "클립보드에 복사했습니다", + "shareSaved": "이미지를 저장했습니다", + "shareFailed": "이미지를 만들지 못했습니다", + "shareRendering": "생성 중…", + "cardHeading": "나의 AI 코딩 기록", + "cardRangeAll": "전체 기간", + "cardTotalLabel": "사용 토큰", + "cardFooter": "codeg로 제작", + "cardTopModels": "주요 모델", + "cardTopProjects": "주요 프로젝트", + "archetypeNightOwl": "야행성 개발자", + "archetypeNightOwlDesc": "토큰의 {percent}%를 해가 진 뒤에 씁니다.", + "archetypeEarlyBird": "아침형 개발자", + "archetypeEarlyBirdDesc": "토큰의 {percent}%를 오전 9시 전에 씁니다.", + "archetypeWeekendWarrior": "주말 전사", + "archetypeWeekendWarriorDesc": "토큰의 {percent}%가 주말에 발생합니다.", + "archetypeCacheMaster": "캐시 마스터", + "archetypeCacheMasterDesc": "컨텍스트의 {percent}%가 캐시에서 왔습니다.", + "archetypeMarathoner": "마라토너", + "archetypeMarathonerDesc": "{days}일 연속으로 개발했습니다.", + "archetypePolyglot": "멀티 플레이어", + "archetypePolyglotDesc": "{count}개 에이전트를 본격적으로 함께 씁니다.", + "archetypeLaserFocus": "한 우물", + "archetypeLaserFocusDesc": "토큰의 {percent}%를 한 프로젝트에 썼습니다.", + "archetypeDeepDiver": "딥 다이버", + "archetypeDeepDiverDesc": "세션당 평균 {averageK}K 토큰.", + "archetypeSteady": "꾸준한 빌더", + "archetypeSteadyDesc": "총 {days}일 동안 개발했습니다.", + "emptyTitle": "아직 집계된 데이터가 없습니다", + "emptyHint": "codeg는 각 에이전트의 세션 기록에서 토큰 수를 직접 읽습니다. 새로 고침하면 이 컴퓨터에 있는 기록을 집계합니다.", + "emptyAction": "내 세션 집계", + "loadFailed": "사용량을 불러오지 못했습니다", + "truncatedNotice": "기간이 매우 길어 표시된 수치는 가장 최근 구간만 반영합니다." + } +} diff --git a/src/i18n/messages/pt.json b/src/i18n/messages/pt.json index bce0354d9..9a43f592f 100644 --- a/src/i18n/messages/pt.json +++ b/src/i18n/messages/pt.json @@ -1,4958 +1,4958 @@ -{ - "Language": { - "followSystem": "Seguir o sistema", - "english": "Inglês", - "simplifiedChinese": "Chinês simplificado", - "traditionalChinese": "Chinês tradicional", - "japanese": "Japonês", - "korean": "Coreano", - "spanish": "Espanhol", - "german": "Alemão", - "french": "Francês", - "portuguese": "Português", - "arabic": "Árabe" - }, - "GitCredentialDialog": { - "title": "Autenticação necessária", - "description": "O servidor remoto requer credenciais. Insira seu nome de usuário e senha (ou token de acesso pessoal).", - "username": "Nome de usuário", - "usernamePlaceholder": "Nome de usuário ou e-mail", - "password": "Senha / Token", - "passwordPlaceholder": "Senha ou token de acesso pessoal", - "passwordHint": "Insira o nome de usuário e a senha do servidor.", - "cancel": "Cancelar", - "authenticate": "Autenticar", - "authenticating": "Autenticando...", - "invalidCredentials": "Credenciais inválidas. Tente novamente.", - "saveCredentials": "Salvar credenciais para operações futuras", - "githubTitle": "Autenticação do GitHub", - "githubDescription": "Insira um token de acesso pessoal para se conectar ao GitHub. O token será validado e salvo automaticamente.", - "githubToken": "Token de acesso pessoal", - "githubTokenPlaceholder": "ghp_xxxxxxxxxxxx", - "githubTokenHint": "Gere um token em GitHub → Settings → Developer settings → Personal access tokens.", - "githubAuthenticate": "Validar e conectar", - "generateToken": "Gerar token" - }, - "SettingsShell": { - "title": "Configurações", - "preferences": "Preferências", - "nav": { - "general": "Geral", - "appearance": "Aparência", - "agents": "Agentes", - "mcp": "MCP", - "skills": "Skills", - "shortcuts": "Atalhos", - "version_control": "Controle de versão", - "system": "Sistema", - "chat_channels": "Canais de chat", - "web_service": "Serviço Web", - "model_providers": "Provedores de Modelos", - "experts": "Especialistas", - "science": "Ciência", - "office_tools": "Ferramentas de escritório", - "skill_packs": "Pacotes de habilidades", - "quick_messages": "Mensagens rápidas", - "logs": "Registros de execução" - } - }, - "AppearanceSettings": { - "sectionTitle": "Aparência do tema", - "sectionDescription": "Escolha claro, escuro ou seguir o sistema. As configurações são salvas automaticamente.", - "themeMode": "Modo de tema", - "placeholder": "Selecionar modo de tema", - "system": "Seguir o sistema", - "light": "Claro", - "dark": "Escuro", - "currentTheme": "Tema efetivo atual: {theme}", - "resolvedTheme": { - "light": "Claro", - "dark": "Escuro", - "unknown": "--" - }, - "themeColor": { - "sectionTitle": "Cor do tema", - "sectionDescription": "Escolha uma paleta de cores para acentos, botões e destaques.", - "current": "Cor atual: {color}", - "options": { - "neutral": "Neutral", - "zinc": "Zinc", - "slate": "Slate", - "stone": "Stone", - "gray": "Gray", - "red": "Red", - "rose": "Rose", - "orange": "Orange", - "green": "Green", - "blue": "Blue", - "yellow": "Yellow", - "violet": "Violet" - } - }, - "customStyle": { - "sectionTitle": "Estilo personalizado", - "sectionDescription": "Ajuste as cores do tema atual ou injete o seu próprio CSS. As substituições ficam sobre a predefinição base, por isso permanecem ao trocar de predefinição.", - "summarySuspended": "Suspenso", - "summaryDefault": "Predefinição inalterada", - "summaryTokens": "{count, plural, one {# substituição} other {# substituições}}", - "summaryCss": "CSS personalizado", - "suspendedByShortcut": "O estilo personalizado está suspenso. Nada do que definir aqui terá efeito até retomá-lo.", - "suspendedBySafeParam": "Esta janela foi aberta no modo de aparência segura, por isso o estilo personalizado é ignorado aqui. As outras janelas não são afetadas.", - "resume": "Retomar estilo personalizado", - "enableTheme": "Ativar cores personalizadas", - "editingLight": "A editar os valores do modo claro. Mude a aplicação para o modo escuro para o definir em separado.", - "editingDark": "A editar os valores do modo escuro. Mude a aplicação para o modo claro para o definir em separado.", - "resetToken": "Repor o valor da predefinição", - "radius": "Raio dos cantos", - "radiusHint": "Toda a escala de raios, de sm a 4xl, deriva dele: um único cursor arredonda a aplicação inteira.", - "advanced": "Avançado (mais {count} variáveis)", - "enableCss": "Ativar CSS personalizado", - "cssRisk": "Funcionalidade avançada. O CSS personalizado substitui todos os estilos integrados e pode tornar a interface inutilizável.", - "editCss": "Editar CSS…", - "cssPresent": "{size} KB guardados", - "cssEmpty": "Ainda não há nada guardado", - "escapeHint": "Interface estragada? Prima {shortcut} para suspender todo o estilo personalizado, ou abra uma janela com o parâmetro safeStyle=1.", - "copyTheme": "Copiar JSON do tema", - "importTheme": "Importar tema…", - "clearTheme": "Limpar substituições", - "interopHint": "Os temas usam o formato registry:theme do shadcn, por isso pode colar aqui qualquer tema shadcn e usar os exportados em qualquer projeto shadcn.", - "importTitle": "Importar tema", - "importDescription": "Cole um item registry:theme do shadcn, um objeto light/dark simples ou um mapa plano de tokens.", - "readClipboard": "Ler área de transferência", - "importConfirm": "Importar", - "cancel": "Cancelar", - "apply": "Aplicar", - "toasts": { - "copied": "JSON do tema copiado", - "copyFailed": "Não foi possível copiar para a área de transferência", - "clipboardReadFailed": "Não foi possível ler a área de transferência, cole manualmente", - "importFailed": "Esse JSON não contém variáveis de tema utilizáveis", - "imported": "Tema importado" - }, - "css": { - "dialogTitle": "CSS personalizado", - "dialogDescription": "Aplica-se a todas as janelas do codeg. As alterações são pré-visualizadas ao vivo; carregue em Aplicar para guardar.", - "size": "{used} KB / {max} KB", - "ruleCount": "{count} regras", - "errorTooLarge": "Demasiado grande para guardar. Reduza abaixo do limite.", - "errorImportEscaped": "Uma regra @import sobreviveu à remoção (sintaxe com escapes). Remova-a para guardar.", - "warnNoRules": "Nenhuma regra foi analisada; verifique a sintaxe.", - "noticeImportsRemoved": "Regras @import removidas: {count}. Iriam obter folhas de estilo remotas.", - "noticeRemoteUrl": "Contém um url() remoto, que fará um pedido de rede ao ser aplicado.", - "noticePreviewSuspended": "O estilo personalizado está suspenso, por isso esta pré-visualização não é aplicada.", - "noticeDisabled": "O CSS personalizado está desativado. Pode pré-visualizar aqui, mas nada se aplica até o ativar.", - "hintTokens": "Dica: as cores que substituiu ficam disponíveis como var(--primary), var(--background), etc." - } - }, - "zoomLevel": { - "sectionTitle": "Zoom da janela", - "sectionDescription": "Dimensiona toda a interface. Aplica imediatamente e é salvo por dispositivo.", - "placeholder": "Selecione o nível de zoom", - "default": "Padrão", - "current": "Zoom atual: {zoom}%" - }, - "fonts": { - "sectionTitle": "Fontes", - "sectionDescription": "Escolha as fontes para a interface, o editor de código e o terminal. As fontes incluídas são carregadas sob demanda; selecione “Personalizada…” para usar qualquer fonte instalada no seu sistema.", - "interface": "Interface", - "editor": "Editor", - "terminal": "Terminal", - "groupSans": "Sem serifa", - "groupMono": "Monoespaçada", - "custom": "Personalizada…", - "customPlaceholder": "Nome da fonte, ex.: Fira Code", - "fontSize": "Tamanho da fonte", - "ligatures": "Ativar ligaduras", - "ligaturesUnavailable": "Esta fonte não tem ligaduras", - "wordWrap": "Ativar quebra de linha", - "terminalLigaturesHint": "As ligaduras do terminal aplicam-se apenas às fontes de programação incluídas.", - "preview": "Pré-visualização" - }, - "welcomePanel": { - "sectionTitle": "Área de seleção de modo", - "sectionDescription": "Os cartões de atalho «Desenvolvimento / Escritório» exibidos acima do campo de entrada na página de nova conversa.", - "showQuickActions": "Mostrar na página de nova conversa" - }, - "workspaceBackground": { - "sectionTitle": "Plano de fundo da área de trabalho", - "sectionDescription": "Mostra uma imagem atrás de toda a área de trabalho. A barra lateral e os painéis ficam translúcidos e foscos para deixar a imagem transparecer, e uma máscara mantém o texto legível.", - "enable": "Ativar imagem de fundo", - "image": "Imagem", - "chooseImage": "Escolher imagem", - "replaceImage": "Substituir imagem", - "removeImage": "Remover", - "fillMode": "Modo de preenchimento", - "fillModes": { - "cover": "Preencher", - "contain": "Ajustar", - "center": "Centralizar", - "tile": "Lado a lado" - }, - "maskOpacity": "Opacidade da máscara", - "maskOpacityHint": "Valores mais altos esmaecem a imagem em direção à cor de fundo do tema, melhorando o contraste do texto.", - "imageBlur": "Desfoque da imagem", - "panelOpacity": "Opacidade dos painéis", - "panelOpacityHint": "O quão opacos são a barra lateral, os painéis e as barras de abas. Mais baixo deixa a imagem transparecer mais.", - "errorTooLarge": "A imagem é muito grande (máx. 16 MB).", - "errorUploadFailed": "Falha ao definir a imagem de fundo." - } - }, - "SystemSettings": { - "loading": "Carregando...", - "sectionTitle": "Gerenciamento do sistema", - "sectionDescription": "Gerencie proxy de rede, atualizações do app e preferências de idioma.", - "proxyTitle": "Proxy de rede", - "proxyDescription": "Quando ativado, as solicitações de rede seguintes priorizam este proxy (incluindo chat ACP, instalação de agentes e operações remotas do Git).", - "loadFailed": "Falha ao carregar: {message}", - "enableProxy": "Ativar proxy do sistema", - "proxyAddress": "Endereço do proxy", - "proxyHint": "Suporta http(s)/socks5, exemplo: {example}. Só funciona quando o proxy do sistema está ativado.", - "save": "Salvar", - "saving": "Salvando...", - "proxyRequired": "A URL do proxy é obrigatória quando o proxy está ativado", - "saveSuccess": "As configurações de proxy do sistema foram salvas", - "saveFailed": "Falha ao salvar: {message}", - "languageTitle": "Idioma", - "languageDescription": "Defina o idioma do app. Ao seguir o idioma do sistema, idiomas não suportados voltam para inglês.", - "appLanguage": "Idioma do app", - "languageSaveSuccess": "As configurações de idioma foram salvas", - "languageSaveFailed": "Falha ao salvar as configurações de idioma: {message}", - "updateTitle": "Atualização do app", - "versionTitle": "Atualização de software", - "updateDescription": "Verifique versões mais novas na fonte de releases configurada e instale diretamente quando disponíveis.", - "currentVersion": "Versão atual", - "upgradableVersion": "Versão mais recente", - "none": "Nenhuma", - "lastChecked": "Última verificação: {time}", - "updateError": "Erro de atualização: {message}", - "checking": "Verificando...", - "checkUpdate": "Verificar atualizações", - "updating": "Instalando...", - "downloading": "Baixando...", - "upgradeTo": "Atualizar para v{version}", - "viewRelease": "Ver lançamento v{version}", - "foundUpdate": "Nova versão v{version} encontrada", - "alreadyLatest": "Você já está na versão mais recente", - "checkUpdateFailed": "Falha ao verificar atualizações: {message}", - "installSuccess": "Atualização instalada. Reiniciando o app.", - "installFailed": "Falha na atualização: {message}", - "upgradeSuccess": "Atualização concluída. Recarregando...", - "restartTimeout": "O servidor não voltou a tempo. Verifique os logs do contêiner ou do serviço.", - "restartingIn": "Reiniciando em {seconds} s...", - "waitingForServer": "Aguardando o servidor voltar...", - "restartToUpdate": "Reiniciar para atualizar", - "newVersionBadge": "Nova v{version}", - "updateAvailableTitle": "Atualização disponível", - "releaseNotesTitle": "Novidades", - "remindLater": "Mais tarde", - "retry": "Tentar novamente", - "stepDownload": "Download", - "stepInstall": "Instalação", - "stepRestart": "Reinício", - "updateReadyHint": "Atualização baixada — reinicie para aplicar.", - "restarting": "Reiniciando...", - "dockerUpgradeHint": "Isto atualiza o contêiner em execução agora. Perde-se se o contêiner for recriado — para mantê-lo, baixe ou crie uma imagem na nova versão e recrie o contêiner.", - "upgradeRolledBack": "Falha na atualização; o servidor reverteu para a versão anterior.", - "serverUnreachable": "Não foi possível acessar o servidor para iniciar a atualização. Verifique se ele está em execução e tente novamente.", - "rollbackButton": "Reverter", - "rollingBack": "Revertendo...", - "rollbackDescription": "Restaura a versão instalada antes da última atualização.", - "rollbackConfirmTitle": "Reverter para a versão anterior?", - "rollbackConfirmDescription": "O servidor será reiniciado na versão instalada antes da última atualização. Uma versão mais recente continua disponível para instalar novamente.", - "rollbackConfirm": "Reverter", - "rollbackCancel": "Cancelar", - "rollbackSuccess": "Revertido para a versão anterior. Recarregando...", - "rollbackFailed": "Falha ao reverter. Verifique os registros do servidor.", - "updateErrors": { - "sourceUnavailable": "Não foi possível acessar a fonte de atualização. Verifique sua rede ou proxy e tente novamente.", - "network": "Falha na conexão de rede. Verifique sua rede ou proxy e tente novamente.", - "downloadFailed": "Falha ao baixar o pacote de atualização. Tente novamente mais tarde.", - "installFailed": "Falha ao instalar a atualização. Feche o app e tente novamente.", - "unknown": "Falha na atualização. Tente novamente mais tarde." - } - }, - "VersionControlSettings": { - "loading": "Carregando...", - "sectionTitle": "Controle de versão", - "sectionDescription": "Configure o executável Git e gerencie contas do GitHub.", - "gitTitle": "Configuração do Git", - "gitDescription": "Configure o executável Git usado pelo aplicativo.", - "gitDetected": "Git detectado", - "gitNotFound": "Git não encontrado no sistema", - "gitVersion": "Versão", - "gitPath": "Caminho", - "customGitPath": "Caminho personalizado do Git", - "customGitPathPlaceholder": "/usr/bin/git", - "customGitPathHint": "Deixe vazio para usar o caminho detectado automaticamente.", - "test": "Testar", - "testing": "Testando...", - "testSuccess": "Executável Git é válido.", - "testFailed": "Teste do Git falhou: {message}", - "save": "Salvar", - "saving": "Salvando...", - "saveSuccess": "Configurações do Git salvas.", - "saveFailed": "Falha ao salvar: {message}", - "githubTitle": "Contas do GitHub", - "githubDescription": "Gerencie contas do GitHub para autenticação. Os tokens são armazenados localmente.", - "noAccounts": "Nenhuma conta do GitHub configurada.", - "addAccount": "Adicionar conta", - "serverUrl": "URL do servidor", - "serverUrlPlaceholder": "https://github.com", - "token": "Token de acesso pessoal", - "tokenPlaceholder": "ghp_xxxxxxxxxxxx", - "generateToken": "Gerar token", - "tokenHint": "Gere um token em GitHub → Settings → Developer settings → Personal access tokens.", - "validateAndAdd": "Validar e adicionar", - "validating": "Validando...", - "addSuccess": "Conta {username} adicionada com sucesso.", - "addFailed": "Falha ao adicionar conta: {message}", - "testConnection": "Testar", - "connectionSuccess": "Conexão bem-sucedida.", - "connectionFailed": "Falha na conexão: {message}", - "setDefault": "Definir como padrão", - "defaultLabel": "Padrão", - "defaultSet": "Conta padrão atualizada.", - "removeAccount": "Remover", - "removeConfirmTitle": "Remover conta", - "removeConfirmMessage": "Tem certeza de que deseja remover a conta \"{username}\"?", - "removeConfirm": "Remover", - "removeCancel": "Cancelar", - "removeSuccess": "Conta removida.", - "scopes": "Escopos", - "loadFailed": "Falha ao carregar configurações: {message}", - "gitAccount": { - "sectionTitle": "Contas de servidor Git", - "sectionDescription": "Gerencie credenciais para servidores Git que não são GitHub (GitLab, Bitbucket, auto-hospedados, etc.).", - "noAccounts": "Nenhuma conta de servidor Git configurada.", - "addAccount": "Adicionar conta", - "addTitle": "Adicionar conta Git", - "addDescription": "Insira o endereço do servidor, nome de usuário e senha ou token de acesso.", - "serverUrl": "URL do servidor", - "serverUrlPlaceholder": "https://gitlab.example.com", - "username": "Nome de usuário", - "usernamePlaceholder": "Nome de usuário ou e-mail", - "password": "Senha / Token", - "passwordPlaceholder": "Senha ou token de acesso", - "passwordHint": "Insira a senha ou o token de acesso do servidor.", - "add": "Adicionar", - "serverRequired": "A URL do servidor é obrigatória.", - "usernameRequired": "O nome de usuário é obrigatório.", - "passwordRequired": "A senha é obrigatória." - } - }, - "ShortcutSettings": { - "sectionTitle": "Atalhos", - "resetDefault": "Restaurar padrões", - "recordInstruction": "Clique no botão à direita e pressione uma combinação de teclas. Use Ctrl/Cmd, Alt e Shift. Pressione Esc para cancelar a gravação.", - "recording": "Pressione um atalho...", - "toasts": { - "conflict": "O atalho já está em uso por \"{title}\"", - "updated": "Atalho atualizado", - "invalid": "Atalho inválido, tente novamente", - "reset": "Atalhos padrão restaurados" - }, - "actions": { - "toggle_search": { - "title": "Abrir busca", - "description": "Mostra ou oculta o painel de busca de conversas" - }, - "toggle_sidebar": { - "title": "Alternar barra lateral esquerda", - "description": "Mostra ou oculta a barra lateral da lista de conversas" - }, - "toggle_terminal": { - "title": "Alternar terminal", - "description": "Mostra ou oculta o painel de terminal inferior" - }, - "new_terminal_tab": { - "title": "Novo terminal", - "description": "Cria uma nova aba de terminal quando o foco está no terminal" - }, - "close_current_terminal_tab": { - "title": "Fechar terminal atual", - "description": "Fecha a aba de terminal atual quando o foco está no terminal" - }, - "toggle_aux_panel": { - "title": "Alternar painel direito", - "description": "Mostra ou oculta o painel de informações auxiliares" - }, - "new_conversation": { - "title": "Nova conversa", - "description": "Cria uma nova aba de conversa na pasta atual" - }, - "open_folder": { - "title": "Abrir pasta", - "description": "Abre o seletor de pastas e abre em uma nova janela" - }, - "open_settings": { - "title": "Abrir configurações", - "description": "Abre a janela de configurações" - }, - "close_current_tab": { - "title": "Fechar aba atual", - "description": "Fecha a conversa atual ou aba de arquivo" - }, - "close_all_file_tabs": { - "title": "Fechar todas as abas de arquivo", - "description": "Fecha todas as abas de arquivo abertas quando o painel de arquivos está ativo" - }, - "next_tab": { - "title": "Próxima aba", - "description": "Mudar para a próxima aba de conversa ou arquivo" - }, - "prev_tab": { - "title": "Aba anterior", - "description": "Mudar para a aba anterior de conversa ou arquivo" - }, - "send_message": { - "title": "Enviar mensagem", - "description": "Enviar a mensagem atual na caixa de entrada" - }, - "newline_in_message": { - "title": "Nova linha na mensagem", - "description": "Inserir uma nova linha na caixa de entrada" - }, - "toggle_custom_style": { - "title": "Suspender/retomar estilo personalizado", - "description": "Saída de emergência: desliga todas as cores e o CSS personalizados e volta a ligá-los" - } - } - }, - "SkillsSettings": { - "title": "Skills", - "description": "Selecione uma Skill à esquerda. À direita, a prévia em Markdown é mostrada por padrão; mude para edição para modificar e salvar.", - "loadingAgents": "Carregando agentes que suportam Skills...", - "emptyNoManageableAgents": "Não há agentes disponíveis para gerenciamento de Skills.", - "managedTarget": "Alvo gerenciado", - "selectAgentPlaceholder": "Selecione um agente", - "searchPlaceholder": "Pesquisar por nome / ID / caminho...", - "skillsList": "Lista de Skills", - "loadingSkills": "Carregando Skills...", - "agentNotSupported": "O agente atual não suporta gerenciamento de Skills.", - "emptySkills": "Ainda não há Skills. Clique em \"Nova Skill\" para criar uma.", - "newSkillTitle": "Nova Skill", - "skillInfo": "Informações da Skill", - "skillIdPlaceholder": "skill-id (letras/números/-/_/.)", - "skillsDirectoryWithPath": "Diretório de Skills: {path}", - "skillsDirectoryNeedId": "Diretório de Skills: digite o ID da Skill para gerar o caminho completo", - "markdownContent": "Conteúdo Markdown", - "editingStatus": "Editando", - "previewStatus": "Visualizando", - "contentPlaceholder": "Digite o conteúdo Markdown da Skill...", - "metadataTitle": "Metadados de Skills", - "onlyYamlMetadata": "Esta Skill contém apenas metadados YAML.", - "emptyContentHint": "Ainda não há conteúdo. Clique em \"Editar\" para começar.", - "loadingSkill": "Carregando Skill...", - "emptyNoAgents": "Nenhum agente disponível.", - "noSelectionHint": "Selecione um Skill à esquerda ou clique em \"Novo Skill\" para criar um.", - "systemBadge": "Sistema", - "systemHint": "Skill integrado do CLI · somente leitura", - "scope": { - "global": "Global", - "folder": "Pasta", - "selectFolderPlaceholder": "Selecionar uma pasta", - "noFolders": "Nenhuma pasta encontrada", - "pickFolderHint": "Selecione uma pasta para ver suas Skills." - }, - "actions": { - "preview": "Prévia", - "edit": "Editar", - "openInWindow": "Abrir em nova janela", - "delete": "Excluir", - "deleting": "Excluindo...", - "refresh": "Atualizar", - "newSkill": "Nova Skill", - "reset": "Redefinir", - "save": "Salvar", - "saving": "Salvando...", - "cancel": "Cancelar" - }, - "deleteDialog": { - "title": "Excluir Skill", - "confirm": "Excluir a Skill atual? Esta ação não pode ser desfeita.", - "confirmWithNamePrefix": "Excluir Skill", - "confirmWithNameSuffix": "? Esta ação não pode ser desfeita." - }, - "toasts": { - "loadFailed": "Falha ao carregar Skill", - "openFolderFailed": "Falha ao abrir pasta", - "noSkillDirectory": "Nenhum diretório de Skills disponível para o agente atual", - "nameRequired": "O nome da Skill não pode estar vazio", - "updated": "Skill atualizada", - "created": "Skill criada", - "saveFailed": "Falha ao salvar Skill", - "deleted": "Skill excluída", - "deleteFailed": "Falha ao excluir Skill" - }, - "templates": { - "gemini": "---\nname: example-skill\ndescription: Describe when this skill should be used.\n---\n\n# Skill Name\n\nInstructions for the agent when this skill is active.\n\n## Workflow\n\n1. Add actionable step one.\n2. Add actionable step two.\n", - "openCode": "---\nname: example-skill\ndescription: Describe when this skill should be used.\n---\n\n# Purpose\n\nDescribe what this skill helps with.\n\n# Steps\n\n1. Add actionable step one.\n2. Add actionable step two.\n", - "openClaw": "---\nname: example-skill\ndescription: Describe when this skill should be used.\nuser-invocable: true\ndisable-model-invocation: false\n---\n\n# Purpose\n\nDescribe what this skill helps with.\n\n# Instructions\n\n1. Add actionable instruction one.\n2. Add actionable instruction two.\n", - "default": "---\nname: example-skill\ndescription: Describe when this skill should be used.\n---\n\n# Skill: example-skill\n\n## When to use\n\n- Describe trigger conditions.\n\n## Instructions\n\n1. Add actionable instruction one.\n2. Add actionable instruction two.\n" - } - }, - "McpSettings": { - "loading": "Carregando...", - "summary": { - "missingCommand": "(comando ausente)", - "missingUrl": "(URL ausente)" - }, - "protocol": { - "stdio": "Stdio" - }, - "errors": { - "selectInstallProtocol": "Selecione um protocolo de instalação", - "fieldRequired": "{field} é obrigatório", - "fieldNeedsBoolean": "{field} deve ser true ou false", - "fieldNeedsNumber": "{field} deve ser um número", - "fieldNeedsInteger": "{field} deve ser um inteiro", - "fieldInvalidJson": "{field} tem JSON inválido: {message}", - "fieldOutOfRange": "O valor de {field} está fora do intervalo permitido", - "jsonEmpty": "{name} não pode estar vazio", - "jsonInvalid": "{name} não é um JSON válido: {message}", - "jsonMustBeObject": "{name} deve ser um objeto JSON", - "specMustBeObject": "A configuração do MCP deve ser um objeto JSON.", - "missingType": "Falta o campo type na configuração do MCP. Use stdio, http (aliases: streamable-http, streamableHttp) ou sse.", - "unsupportedType": "Tipo de MCP não suportado {type}. Suportados: stdio, http (aliases: streamable-http, streamableHttp), sse.", - "codexEntryUnsupportedType": "A entrada Codex MCP {id} tem tipo não suportado {type}. Suportados: stdio, http (aliases: streamable-http, streamableHttp), sse.", - "unsupportedTransportType": "Tipo de transport não suportado {type}. Suportados: http (aliases: streamable-http, streamableHttp), sse.", - "stdioCommandRequired": "Um MCP stdio exige um campo command não vazio.", - "remoteUrlRequired": "Um MCP remoto exige um campo url não vazio.", - "appsRequired": "Selecione ao menos um aplicativo alvo." - }, - "jsonNames": { - "localConfig": "Configuração MCP", - "installConfig": "Configuração de instalação" - }, - "toasts": { - "uninstalled": "MCP desinstalado", - "uninstallFailed": "Falha ao desinstalar: {message}", - "selectAtLeastOneApp": "Selecione pelo menos um app de destino", - "saveSuccess": "Salvo", - "saveFailed": "Falha ao salvar: {message}", - "installed": "{name} instalado", - "installFailed": "Falha na instalação: {message}", - "serverIdRequired": "O Server ID é obrigatório", - "serverIdExists": "O Server ID \"{id}\" já existe. Edite a entrada existente ou escolha outro nome.", - "created": "MCP criado" - }, - "installDialog": { - "title": "Confirmar instalação do MCP", - "descriptionWithName": "Instalar {name} na configuração local.", - "description": "Selecione os apps de destino para instalação.", - "protocol": "Protocolo", - "selectProtocol": "Selecionar protocolo", - "parameters": "Parâmetros de configuração", - "booleanPlaceholder": "Selecione true/false", - "selectOneValue": "Selecione um valor", - "targetApps": "Apps de destino" - }, - "actions": { - "cancel": "Cancelar", - "confirmInstall": "Confirmar instalação", - "installing": "Instalando", - "uninstall": "Desinstalar", - "uninstalling": "Desinstalando", - "viewDetails": "Ver detalhes", - "save": "Salvar", - "saving": "Salvando", - "install": "Instalar", - "refresh": "Atualizar", - "newMcp": "Novo MCP", - "create": "Criar", - "creating": "Criando..." - }, - "tabs": { - "local": "MCP local", - "market": "Marketplace MCP" - }, - "local": { - "filterPlaceholder": "Filtrar MCP local...", - "loadFailed": "Falha ao carregar: {message}", - "empty": "Nenhum MCP local detectado.", - "description": "A configuração local de MCP pode ser editada e salva diretamente.", - "enabledApps": "Apps habilitados", - "configJson": "Configuração MCP (JSON)", - "draftTitle": "Novo MCP", - "draftDescription": "Informe um Server ID e a configuração para criar um servidor MCP local.", - "serverIdLabel": "Server ID", - "serverIdPlaceholder": "Server ID (ex.: my-mcp)", - "typeHint": "Tipos suportados: stdio, http (aliases: streamable-http, streamableHttp), sse. env só é usado por stdio; para MCPs remotos use headers para transportar tokens de autenticação.", - "envOnRemoteWarning": "env detectado em um MCP remoto. Apenas stdio usa env; MCPs remotos transportam tokens de autenticação via headers, portanto env será ignorado ao salvar." - }, - "market": { - "selectMarketplace": "Selecionar marketplace", - "searchPlaceholder": "Pesquisar MCP...", - "searchFailed": "Falha na busca: {message}", - "loadingList": "Carregando lista de MCP...", - "empty": "Nenhum resultado de MCP.", - "loadingDetail": "Carregando detalhes do marketplace...", - "detailLoadFailed": "Falha ao carregar detalhes: {message}", - "owner": "Proprietário: {owner}", - "namespace": "Namespace: {namespace}", - "defaultInstallProtocol": "Protocolo de instalação padrão", - "currentOptionParameterCount": "Quantidade de parâmetros da opção atual: {count}", - "installConfigDescription": "Configuração de instalação (JSON, editável antes de instalar; edições substituirão o formulário de protocolo/parâmetros)", - "selectLeftToView": "Selecione um MCP do marketplace à esquerda para ver detalhes." - }, - "badges": { - "verified": "Verificado", - "remote": "Remoto", - "hasHomepage": "Tem homepage", - "uses": "{count} usos", - "deployed": "Implantado", - "notDeployed": "Não implantado" - }, - "selectLeftMcp": "Selecione um MCP à esquerda." - }, - "AcpAgentSettings": { - "title": "Gerenciamento do SDK de agentes", - "description": "Gerencie em um só lugar a conexão do SDK de agentes, estado habilitado, variáveis de ambiente, gerenciamento de configuração e informações de preflight de versão.", - "loadingAgents": "Carregando lista de agentes...", - "agentList": "Lista de agentes", - "emptyNoAgent": "Nenhum agente disponível.", - "configManagement": "Gerenciamento de configuração", - "envVars": "Variáveis de ambiente", - "hostTools": { - "label": "Deixar o agente cuidar de arquivos e comandos", - "description": "O codeg deixa de atender o acesso a arquivos e os comandos de terminal, de modo que o agente os executa no próprio processo — onde o sandbox e as regras de permissão dele realmente se aplicam. A delegação a outros agentes também é desativada, pois levaria o mesmo trabalho de volta ao codeg. O codeg não adiciona sandbox algum, então ative isto apenas se o agente tiver um configurado." - }, - "nativeJsonConfig": "Configuração JSON nativa", - "modelHintDefault": "Deixe em branco para usar o modelo padrão do sistema.", - "generalConfigDescriptionClaude": "Suporta configuração rápida de API URL, API Key e modelos Claude, e sincroniza com a configuração JSON nativa.", - "generalConfigDescriptionDefault": "Suporta entrada de configuração importante (API URL, API Key, Model) e gerenciamento de configuração JSON nativa.", - "multiAgent": { - "title": "Colaboração multiagente", - "description": "Permite que agentes ativos deleguem subtarefas a outros agentes.", - "enable": "Ativar delegação", - "enableHint": "Quando desativado, a ferramenta delegate_to_agent fica oculta no catálogo de ferramentas MCP do agente.", - "withheldByHostTools": "{agents} não receberão as ferramentas de delegação: o interruptor por agente “Deixar o agente lidar com arquivos e comandos” está ligado.", - "selfInitiate": "Allow spawn without @", - "selfInitiateHint": "When on, an agent may start a listed sub-agent on its own. An @ mention is still always honored. When off, only an @ mention starts a sub-agent.", - "depthLimit": "Profundidade máxima de delegação", - "depthHint": "Intervalo permitido: {min}–{max}. Limita a profundidade de recursão de uma cadeia de delegação (raiz → filho → neto …).", - "completedCacheLabel": "Cache de resultados concluídos (MB)", - "completedCacheHint": "Cache em memória dos resultados concluídos de subagentes, mantido apenas enquanto a sessão de delegação está em execução e liberado automaticamente quando essa sessão termina. Acima deste limite, os resultados mais antigos são descartados da memória primeiro (ainda visíveis na sessão do próprio subagente); 0 = ilimitado (ainda assim liberado ao terminar a sessão).", - "save": "Salvar", - "saving": "Salvando…", - "saved": "Configurações de delegação salvas", - "saveFailed": "Falha ao salvar configurações de delegação", - "loadFailed": "Falha ao carregar configurações de delegação: {detail}", - "tabGeneral": "Geral", - "tabAgentDefaults": "Padrões do subagente", - "agentDefaultsDescription": "Substituições por agente aplicadas quando a Colaboração multiagente inicia um subagente para uma chamada de delegação. As opções mostradas vêm de uma sondagem ao vivo: o que você escolhe é exatamente o que o agente aceitará.", - "probing": "Carregando opções disponíveis do agente…", - "probeFailed": "Falha ao carregar opções: {detail}", - "retry": "Tentar novamente", - "noConfigAvailable": "Este agente não possui opções configuráveis.", - "modeLabel": "Modo", - "agentDefaultHint": "Padrão do agente: {value}", - "defaultOptionLabel": "Padrão ({value})" - }, - "actions": { - "dragSort": "Arraste para reordenar", - "dragSortAgent": "Arraste para reordenar {name}", - "refreshCheck": "Atualizar verificação", - "refreshCheckAgent": "Atualizar verificação de {name}", - "clickEnable": "Clique para habilitar {name}", - "clickDisable": "Clique para desabilitar {name}", - "install": "Instalar", - "upgrade": "Atualizar", - "uninstall": "Desinstalar", - "uninstalling": "Desinstalando...", - "saveEnvVars": "Salvar variáveis de ambiente", - "saving": "Salvando...", - "saveGrokConfig": "Salvar configuração do Grok", - "saveCodexConfig": "Salvar configuração do Codex", - "saveGeminiConfig": "Salvar configuração do Gemini", - "saveOpenCodeConfig": "Salvar configuração do OpenCode", - "saveOpenClawConfig": "Salvar configuração do OpenClaw", - "saveConfigManagement": "Salvar gerenciamento de configuração", - "saveCurrentProvider": "Salvar provedor atual", - "showApiKey": "Mostrar API Key", - "hideApiKey": "Ocultar API Key", - "showKey": "Mostrar chave", - "hideKey": "Ocultar chave", - "showToken": "Mostrar token", - "hideToken": "Ocultar token", - "cancel": "Cancelar", - "delete": "Excluir", - "deleting": "Excluindo...", - "confirmDelete": "Confirmar exclusão", - "confirmUninstall": "Confirmar desinstalação", - "saveClineConfig": "Salvar configuração do Cline", - "saveHermesConfig": "Salvar configuração do Hermes", - "saveCodeBuddyConfig": "Salvar configuração do CodeBuddy", - "saveKimiCodeConfig": "Salvar configuração do Kimi Code", - "customInstall": "Instalação personalizada", - "saveKimiCodeRawConfig": "Save config.toml", - "saveDeepSeekConfig": "Salvar configuração do DeepSeek", - "diagnose": "Diagnosticar" - }, - "status": { - "enabled": "Habilitado", - "disabled": "Desabilitado", - "unchecked": "Não verificado", - "agentEnabledAria": "{name} habilitado", - "agentEnabledSwitch": "Chave de habilitação de {name}" - }, - "preflight": { - "count": "Itens de preflight: {count}", - "notRun": "As verificações ainda não foram executadas." - }, - "grok": { - "configDescription": "Configure o Grok aqui. Os controles abaixo — modo de permissão, esforço de raciocínio, um modelo personalizado opcional (endpoint próprio) e a compactação — são mesclados em ~/.grok/config.toml, preservando suas outras chaves e comentários. O login usa seu XAI_API_KEY ou `grok login`. As demais chaves continuam editáveis em Avançado.", - "permissionModeLabel": "Modo de permissão", - "permissionDefault": "Perguntar sempre", - "permissionAcceptEdits": "Aprovar edições automaticamente", - "permissionAuto": "Aprovação automática inteligente", - "permissionAlwaysApprove": "Sempre aprovar", - "reasoningEffortLabel": "Esforço de raciocínio", - "effortLow": "Baixo (mais rápido)", - "effortMedium": "Médio (equilibrado)", - "effortHigh": "Alto", - "effortXhigh": "Máximo", - "optionDefault": "Usar padrão", - "authTitle": "Autenticação", - "authMode": "Método de autenticação", - "authModeApiKey": "Chave de API da XAI", - "authModeApiKeyHint": "Autentique-se com uma XAI_API_KEY do console da xAI, para execuções não interativas ou headless. Armazenada no ambiente deste agente.", - "authModeCustom": "Endpoint personalizado", - "authModeCustomHint": "Use um endpoint próprio (BYO): defina abaixo um modelo personalizado com a sua própria base URL e chave de API. Ele se torna o modelo padrão do Grok.", - "subscriptionHint": "Entre com `grok login` (SuperGrok / X Premium+). Nenhuma chave de API é armazenada.", - "loginHint": "Execute isto num terminal para entrar e depois reabra estas configurações:", - "commandCopied": "Comando copiado para a área de transferência", - "copyCommand": "Copiar comando", - "authKeyConfigured": "XAI_API_KEY está configurada.", - "authKeyMissing": "Nenhuma XAI_API_KEY definida.", - "advancedToggle": "Avançado (config.toml bruto)", - "configTomlNative": "config.toml (nativo)", - "configTomlHint": "Salvo literalmente como todo o ~/.grok/config.toml. TOML inválido é rejeitado para que um erro de digitação nunca trunque seu arquivo.", - "configTomlPlaceholder": "# Chaves além dos controles acima, por ex.\n# [mcp_servers.*], [cli], regras [permission].", - "customModelTitle": "Modelo personalizado (endpoint próprio)", - "customModelHint": "Aponte o Grok para um endpoint personalizado ou auto-hospedado. O codeg grava um bloco `[model.*]` por modelo e o define como padrão. Deixe o ID do modelo vazio para removê-lo.", - "customModelIdLabel": "ID do modelo", - "customModelIdPlaceholder": "grok-4.5", - "customModelIdHint": "Registrado como um bloco `[model.*]` e enviado à API como nome do modelo; também definido como `[models].default`.", - "customBaseUrlLabel": "URL base", - "customBaseUrlPlaceholder": "https://api.x.ai/v1 (padrão)", - "customApiBackendLabel": "Backend da API", - "backendResponses": "Responses", - "backendChatCompletions": "Chat Completions", - "backendMessages": "Messages (Anthropic)", - "customApiKeyLabel": "Chave de API", - "customApiKeyHint": "Armazenada em linha em `[model.*].api_key`, restrita a este endpoint.", - "customContextWindowLabel": "Janela de contexto (tokens)", - "customContextWindowHint": "Opcional. Define o momento da autocompactação; deixe vazio para o padrão do endpoint.", - "autoCompactLabel": "Limite de autocompactação (%)", - "autoCompactHint": "Compacta a conversa quando o uso do contexto atinge esta porcentagem (padrão do Grok: 85). Gravado em `[session]`." - }, - "cursor": { - "configDescription": "Configure o Cursor aqui. Escolha um método de autenticação — assinatura oficial (login pelo navegador) ou uma chave de API do Cursor para máquinas headless ou servidores — depois escolha um modelo e edite as regras de permissão e o sandbox do CLI. O codeg as grava em ~/.cursor/cli-config.json, compartilhado com o CLI cursor-agent.", - "authTitle": "Autenticação", - "authChecking": "Verificando…", - "authNotInstalled": "cursor-agent não está instalado", - "authLoggedIn": "Conectado", - "authNotLoggedIn": "Não conectado", - "loginHint": "Execute isto em um terminal para entrar na sua conta Cursor (uma janela do navegador abre) e depois clique em atualizar:", - "apiKeyLabel": "Chave de API do Cursor", - "apiKeyPlaceholder": "chave de cursor.com/dashboard", - "apiKeyHint": "CURSOR_API_KEY — uma chave de conta do painel do Cursor, alternativa ao login pelo navegador para máquinas headless ou servidores. Não é uma chave de terceiros nem da OpenAI.", - "modelTitle": "Modelo padrão", - "loadModels": "Carregar modelos", - "modelsUnavailable": "Lista de modelos indisponível", - "modelHint": "Passado à CLI como --model ao iniciar a sessão. Deixe no padrão para o Cursor escolher.", - "permissionsTitle": "Permissões e sandbox", - "permissionsDescription": "Editor visual das regras de permissão da CLI (cli-config.json). Regras permitidas executam sem confirmação; regras negadas são sempre bloqueadas.", - "permissionModeLabel": "Modo de permissões", - "permissionModeDefault": "Perguntar antes de executar (padrão)", - "permissionModeForce": "Run Everything (--force)", - "permissionModeHint": "Run Everything inicia as sessões com --force: todas as chamadas de ferramentas são permitidas automaticamente, exceto as regras de negação, sem confirmações (uma política da organização pode limitá-lo às regras de permissão). Vale para novas sessões.", - "optionDefault": "Padrão (não definido)", - "sandboxLabel": "Sandbox", - "sandboxEnabled": "Ativado", - "sandboxDisabled": "Desativado", - "allowRulesLabel": "Regras permitidas", - "denyRulesLabel": "Regras negadas", - "addRule": "Adicionar regra", - "rulesSyntaxHint": "Sintaxe das regras: Shell(cmd), Read(caminho/glob), Write(caminho/glob), WebFetch(domínio), Mcp(servidor:ferramenta) — as regras de negação sempre prevalecem.", - "saveConfig": "Salvar configuração", - "advancedToggle": "Avançado: cli-config.json bruto", - "advancedHint": "O ~/.cursor/cli-config.json completo. Salvar grava o arquivo como está; os controles estruturados acima são mesclados nele.", - "saveRawConfig": "Salvar arquivo", - "authMode": "Método de autenticação", - "subscriptionHint": "Faça login com sua conta Cursor e use os modelos do Cursor.", - "customApiKeyRequired": "É necessária uma chave de API do Cursor.", - "authModeApiKey": "Chave de API do Cursor (headless/servidor)", - "authModeApiKeyHint": "Autentique-se com uma chave de API de conta do Cursor gerada no painel do Cursor (para máquinas headless ou servidores). É uma chave de conta do Cursor, não um endpoint de terceiros/OpenAI: o cursor-agent só se comunica com o backend do próprio Cursor. Para usar um endpoint compatível com codex/OpenAI, use o agente Codex.", - "modelPickerPlaceholder": "Pesquisar modelos…", - "modelNoMatch": "Nenhum modelo correspondente", - "modelsNeedAuth": "Faça login para carregar a lista de modelos.", - "modelDefaultBadge": "padrão" - }, - "deepseek": { - "configManagement": "Configuração do DeepSeek Harness", - "configDescription": "O endpoint e a chave são variáveis de ambiente que o deepseek-acp lê ao iniciar. O modelo e o nível de raciocínio são seletores por sessão — escolha-os no campo de mensagem.", - "baseUrlLabel": "Endpoint da API", - "baseUrlHint": "Deixe vazio para o endpoint oficial. Vale para as sessões iniciadas depois de salvar; reconecte uma sessão em andamento para que ela use o novo valor.", - "baseUrlInvalid": "Informe uma URL http(s) completa e sem query string, por exemplo https://api.deepseek.com", - "apiKeyLabel": "Chave de API", - "apiKeyHint": "Enviada ao agente como DEEPSEEK_API_KEY. Uma variável de ambiente tem precedência sobre o arquivo de credenciais, então deixe em branco se você entrar pelo terminal." - }, - "codex": { - "configDescription": "Suporta configuração rápida de URL da API, API Key, nome do modelo e reasoning effort, com sincronização para `auth.json` / `config.toml`.", - "authMode": "Modo de Autenticação", - "chatgptSubscription": "Assinatura oficial", - "chatgptSubscriptionHint": "Faça login com assinatura oficial do ChatGPT, sem necessidade de API Key", - "apiKeyHint": "Conecte-se usando API Key ao OpenAI ou serviços de API compatíveis", - "selectProvider": "Selecionar provedor", - "modelName": "Nome do modelo", - "selectReasoningEffort": "Selecionar Reasoning Effort", - "enableWebsocket": "Habilitar WebSocket", - "enableWebsocketAria": "Habilitar WebSocket para Codex Provider", - "enableSkills": "Habilitar Skills", - "enableSkillsAria": "Habilitar Skills para Codex", - "enableFast": "Habilitar Fast", - "enableFastAria": "Habilitar nível de serviço Fast para Codex", - "sandboxGroupTitle": "Sandbox e aprovações", - "sandboxGroupHint": "Gravado no ~/.codex/config.toml global, portanto as sessões do codex CLI e do IDE também usam. São padrões do thread: valem para os turnos que o codex inicia sozinho (/goal, /review, /compact). Mensagens comuns usam a predefinição de aprovação do compositor. Reinicie a sessão para aplicar as alterações.", - "sandboxShadowedWarning": "O config.toml define default_permissions, então o codex resolve as permissões por esse perfil e ignora sandbox_mode por completo. Remova default_permissions para usar os controles abaixo.", - "sandboxPermissionsTableWarning": "O config.toml define perfis [permissions] sem default_permissions, o que faz o codex recusar a iniciar. Defina um no editor bruto abaixo.", - "approvalPolicyLabel": "Política de aprovação", - "approvalPolicyUnset": "Não definida (padrão do codex: sob demanda)", - "approvalPolicy_on-request": "Sob demanda — o modelo decide quando perguntar", - "approvalPolicy_untrusted": "Não confiável — só comandos de leitura reconhecidos como seguros rodam sem confirmação", - "approvalPolicy_never": "Nunca — nenhum pedido de aprovação", - "approvalPolicy_granular": "Granular — escolha por tipo de solicitação", - "approvalPolicyUntrustedAcpWarning": "Untrusted não tem equivalente entre os três presets de aprovação do adaptador ACP, então as sessões do codeg voltam para \"quando solicitado\": o modelo passa a decidir quando perguntar, e comandos que o sandbox já permite deixam de pedir confirmação. Restrinja o modo de sandbox abaixo em vez disso.", - "granularHint": "Desligado significa que esse tipo de solicitação é recusado automaticamente em vez de exibido a você.", - "granular_sandbox_approval": "Escalonamentos de comandos de shell", - "granular_rules": "Avisos de regras do execpolicy", - "granular_skill_approval": "Avisos de scripts de habilidades", - "granular_request_permissions": "Avisos da ferramenta request_permissions", - "granular_mcp_elicitations": "Avisos de elicitação MCP", - "sandboxModeLabel": "Modo de sandbox", - "sandboxModeUnset": "Não definido (pastas confiáveis caem para escrita no espaço de trabalho)", - "sandboxMode_read-only": "Somente leitura", - "sandboxMode_workspace-write": "Escrita no espaço de trabalho", - "sandboxMode_danger-full-access": "Acesso total (sem sandbox)", - "sandboxModeHint": "No Windows, a escrita no espaço de trabalho é rebaixada para somente leitura, a menos que o sandbox experimental do Windows do codex esteja ativado.", - "sandboxModeSeedsPresetHint": "O codeg também usa isto para o preset de aprovação inicial da sessão, portanto — ao contrário da política de aprovação — ele afeta os prompts comuns. O preset escolhido no editor continua tendo prioridade.", - "writableRootsLabel": "Pastas graváveis extras", - "writableRootsHint": "Um caminho absoluto por linha, além do diretório de trabalho.", - "sandboxRootsRelativeError": "Precisa ser um caminho absoluto — o codex resolve caminhos relativos dentro de ~/.codex: {path}", - "networkAccessLabel": "Permitir acesso à rede", - "excludeTmpdirLabel": "Excluir TMPDIR das raízes graváveis", - "excludeSlashTmpLabel": "Excluir /tmp das raízes graváveis", - "authJsonNative": "auth.json (nativo)", - "configTomlNative": "config.toml (nativo)", - "loginButton": "Entrar com ChatGPT", - "loginRequesting": "Solicitando código de login...", - "loginStep1": "Abra a seguinte URL no seu navegador:", - "loginStep2": "Digite o código abaixo:", - "loginPolling": "Aguardando autorização...", - "loginCancel": "Cancelar", - "loginSuccess": "Login realizado com sucesso, configuração salva!", - "loginFailed": "Falha no login: {message}", - "loginRetry": "Tentar novamente", - "loginCodeCopied": "Código copiado", - "loggedIn": "Conta conectada", - "loginRelogin": "Reconectar / Trocar conta", - "loginTimeout": "Login expirou, tente novamente", - "loginSaveFailed": "Login realizado com sucesso, mas falha ao salvar configuração" - }, - "gemini": { - "authConfig": "Configuração de autenticação do Gemini", - "authConfigDescription": "Alinhada à documentação de autenticação do Gemini CLI, com suporte a endpoint personalizado, login Google, Gemini API Key e Vertex AI (ADC / conta de serviço / API Key).", - "authMode": "Modo de autenticação", - "selectAuthMode": "Selecionar modo de autenticação", - "viewAuthDoc": "Ver documentação de autenticação", - "mode": { - "custom": "Endpoint personalizado", - "loginGoogle": "Login Google (OAuth)", - "vertexServiceAccount": "Vertex AI (Conta de serviço)" - }, - "hint": { - "custom": "Preencha API URL, API Key e Modelo; mapeados para GOOGLE_GEMINI_BASE_URL / GEMINI_API_KEY / GEMINI_MODEL.", - "loginGoogle": "Execute gemini no terminal e conclua o login Google primeiro; API key não é necessária.", - "geminiApiKey": "Preencha GEMINI_API_KEY ao usar a API Gemini.", - "vertexAdc": "Use gcloud ADC; GOOGLE_CLOUD_PROJECT e GOOGLE_CLOUD_LOCATION são recomendados.", - "vertexServiceAccount": "Defina o caminho do JSON da conta de serviço em GOOGLE_APPLICATION_CREDENTIALS.", - "vertexApiKey": "Preencha GOOGLE_API_KEY ao usar API key do Vertex AI." - } - }, - "openCode": { - "configManagement": "Gerenciamento de configuração do OpenCode", - "configDescription": "Alinhado ao esquema `provider` do OpenCode, com suporte a gerenciamento multi-provedor e sincronização bidirecional com arquivos JSON nativos.", - "providerManagement": "Gerenciamento de provedores", - "providerCount": "{count} provedores", - "addProvider": "Adicionar provedor", - "emptyProvider": "Ainda não há provedores personalizados. Clique em Adicionar provedor personalizado para criar um.", - "providerEnabledState": "Estado habilitado de {providerId}", - "selectProviderNpm": "Selecionar provider.npm", - "modelManagement": "Gerenciamento de modelos", - "modelCount": "{count} modelos", - "modelDescription": "Alinhado ao `provider.models` do OpenCode. O gerenciamento rápido atualmente suporta `name` / `id`; outros campos avançados são preservados e podem ser editados no JSON nativo abaixo.", - "addModel": "Adicionar modelo", - "emptyModel": "Ainda não há modelo. Informe model id e clique em \"Adicionar modelo\".", - "modelId": "ID do modelo", - "modelName": "Nome do modelo", - "deleteModel": "Excluir modelo {modelId}", - "nativeJsonConfig": "Configuração JSON nativa do OpenCode", - "mainModel": "Modelo principal", - "smallModel": "Modelo pequeno", - "noMatchingModels": "Nenhum modelo correspondente", - "connectProvider": "Conectar provedor", - "connectedProviders": "Provedores conectados", - "noConnectedProviders": "Ainda não há provedores do catálogo conectados.", - "advancedProviderConfig": "Provedores personalizados", - "customProviderConfigHint": "Endpoints compatíveis com OpenAI que você mesmo define — um bloco de provider em opencode.json, com a API key em auth.json.", - "addCustomProvider": "Adicionar provedor personalizado", - "disconnect": "Desconectar", - "editConfig": "Editar", - "customBadge": "Personalizado", - "authKindApi": "Chave de API", - "authKindOauth": "OAuth", - "authKindNone": "Sem credencial", - "connect": { - "title": "Conectar um provedor", - "description": "Escolha um provedor no catálogo do models.dev. As credenciais são salvas no arquivo auth.json do OpenCode.", - "pick": "Provedor", - "search": "Pesquisar provedores…", - "loading": "Carregando catálogo…", - "catalogLabel": "Catálogo do models.dev", - "modelsAvailable": "{count} modelos disponíveis", - "getKey": "Obter chave de API", - "oauthApiKeyNote": "Este provedor também oferece login pelo navegador via opencode auth login. O login pelo navegador chegará em breve — por enquanto, cole uma chave de API.", - "apiKey": "Chave de API", - "apiKeyHint": "Salva em auth.json, nunca em opencode.json.", - "baseUrlOptional": "Substituir Base URL (opcional)", - "providerId": "ID do provedor", - "displayName": "Nome de exibição", - "modelsList": "Modelos (um por linha)", - "modelsHint": "IDs de modelo que o endpoint aceita.", - "action": "Conectar", - "editTitle": "Editar provedor", - "editDescription": "Atualize a chave de API ou a Base URL deste provedor.", - "saveAction": "Salvar" - }, - "customProvider": { - "title": "Adicionar um provedor personalizado", - "description": "Defina um endpoint compatível com OpenAI. A API key é salva em auth.json; o bloco de provider vai para opencode.json.", - "action": "Adicionar provedor", - "idInCatalog": "{providerId} é um provedor conhecido — conecte-o via Conectar provedor." - }, - "refreshCatalog": "Atualizar catálogo", - "reasoningBadge": "raciocínio", - "contextWindow": "Janela de contexto", - "permissions": { - "title": "Permissões", - "description": "Decida quais ações rodam sozinhas, quais pedem sua confirmação e quais são bloqueadas. Gravado no bloco permission do opencode.json e aplicado ao salvar abaixo.", - "docsLink": "Documentação de permissões", - "unparsableConfig": "O JSON nativo abaixo não é válido, então o editor visual está pausado. Corrija o JSON para continuar.", - "invalidBlock": "O bloco permission tem um formato que o codeg não reconhece. Edite-o no JSON nativo abaixo ou use Redefinir para começar de novo.", - "orderingUnsafe": "Há uma regra curinga escrita depois de ferramentas específicas, então o OpenCode a aplica a elas também — as linhas abaixo não são o que está em vigor. Corrigir ordem apenas devolve cada curinga ao início do seu escopo, sem mudar nenhum valor.", - "orderingUnsafeManual": "Uma regra fica encoberta por um padrão mais geral escrito depois dela, então o OpenCode nunca a aplica — as linhas abaixo não são o que está em vigor. Dois padrões que se sobrepõem não têm uma única ordem certa; reordene-os no JSON nativo para que o mais geral venha primeiro.", - "fixOrder": "Corrigir ordem", - "agentOverrides": "Estes agentes sobrepõem as permissões e são aplicados por último, então vencem tudo daqui: {agents}. Edite-os no JSON nativo abaixo ou ative o aceite automático para apagá-los.", - "legacyTools": "O mapa tools legado de nível superior nega uma ferramenta. O OpenCode o funde com as permissões, então ele se aplica acima de tudo o que aparece aqui. Edite-o no JSON nativo abaixo ou ative o aceite automático para apagá-lo.", - "autoAcceptTitle": "Aceitar todas as permissões automaticamente", - "autoAcceptHint": "Toda chamada de ferramenta — comandos de shell, edições de arquivos, caminhos fora do projeto — roda sem perguntar. Ao ativar, as configurações por ferramenta abaixo são substituídas por uma única regra que permite tudo, e as sobreposições por agente e os interruptores tools legados que ainda bloqueariam são apagados.", - "globalLabel": "Padrão global", - "globalHint": "A regra *: vale para tudo que as ferramentas abaixo não sobrescreverem.", - "actionUnset": "Não definido (padrões do OpenCode)", - "actionInherit": "Herdar ({action})", - "actionAllow": "Permitir", - "actionAsk": "Perguntar", - "actionDeny": "Negar", - "perToolTitle": "Permissões por ferramenta", - "reset": "Redefinir", - "ruleCount": "regras: {count}", - "rulesToggle": "Regras detalhadas de {tool}", - "rulesHint": "São comparadas com a entrada da ferramenta e a última correspondência vence, então coloque os padrões amplos primeiro. * corresponde a quaisquer caracteres, ? a exatamente um, e um ~ inicial vira sua pasta pessoal.", - "noRules": "Ainda não há regras detalhadas.", - "addRule": "Adicionar regra", - "deleteRule": "Excluir a regra {pattern}", - "duplicateRule": "Esse padrão já existe.", - "blankRule": "Uma regra precisa de um padrão — use o ícone de lixeira para removê-la.", - "customKeys": "Outras chaves de permissão no arquivo", - "customKeyHint": "Não é uma ferramenta integrada do OpenCode — mantida como está.", - "keys": { - "bash": "Executar comandos de shell, pelo comando analisado", - "edit": "Todas as modificações de arquivos: edit, write e patch", - "read": "Ler arquivos, pelo caminho", - "external_directory": "Acessar caminhos fora do diretório de trabalho do projeto", - "task": "Iniciar subagentes, pelo tipo de subagente", - "skill": "Carregar skills, pelo nome", - "glob": "Encontrar arquivos, pelo padrão glob", - "grep": "Pesquisar o conteúdo dos arquivos, pelo padrão", - "list": "Listar o conteúdo de um diretório", - "webfetch": "Buscar uma URL", - "websearch": "Pesquisar na web", - "lsp": "Executar consultas LSP", - "todowrite": "Escrever a lista de tarefas", - "question": "Fazer uma pergunta a você", - "doom_loop": "Dispara quando a mesma chamada se repete três vezes com a mesma entrada" - } - } - }, - "openClaw": { - "gatewayConfig": "Configuração de Gateway", - "gatewayDescription": "Configure a conexão do OpenClaw Gateway. Suporta gateway local ou remoto.", - "gatewayUrlHint": "Deixe vazio para usar gateway.remote.url da configuração local do openclaw.", - "gatewayTokenPlaceholder": "Token de autenticação do Gateway", - "gatewayTokenHint": "Use token-file em vez de token em texto puro quando possível; configure via CLI do openclaw.", - "sessionKeyHint": "Opcional. Especifique a session key do gateway; deixe vazio para atribuição automática de sessão isolada." - }, - "hermes": { - "configManagement": "Configuração do Hermes", - "configDescription": "O Hermes gerencia suas próprias credenciais em ~/.hermes/.env e as configurações em ~/.hermes/config.yaml. Escolha um provedor e, em seguida, defina a chave de API e o modelo — o codeg grava os dois arquivos para você.", - "providerLabel": "Provedor", - "providerHint": "O provedor determina qual variável de chave de API e qual model.provider o Hermes usa. Provedores OAuth são configurados pela configuração de terminal abaixo.", - "groupApiKey": "Provedores com chave de API", - "groupOauth": "Provedores OAuth", - "groupAws": "AWS", - "apiKeyHint": "Salva em ~/.hermes/.env. Ela nunca é injetada no processo — o Hermes a lê da sua própria configuração.", - "modelName": "Modelo", - "oauthHint": "Este provedor usa OAuth. Execute a configuração abaixo para autenticar no seu terminal.", - "awsHint": "O Bedrock usa suas credenciais da AWS (ambiente ou configuração compartilhada). Defina o ID do modelo acima e configure o acesso à AWS no seu ambiente.", - "unsupportedProvider": "Este provedor não pode ser editado com campos estruturados. Use o editor de config.yaml abaixo ou a configuração pelo terminal.", - "setupTitle": "Configuração autogerenciada", - "setupHint": "A configuração interativa do Hermes precisa de um terminal. Inicie-a abaixo ou copie o comando para executá-lo você mesmo.", - "runSetup": "Executar configuração do Hermes", - "configureModel": "Configurar modelo", - "openConfigFolder": "Abrir ~/.hermes", - "copyCommand": "Copiar comando", - "commandCopied": "Comando copiado para a área de transferência", - "advancedTitle": "Avançado: editar config.yaml", - "rawConfigHint": "Edite ~/.hermes/config.yaml diretamente. Salvar aqui sobrescreve o arquivo exatamente como está.", - "saveRawConfig": "Salvar config.yaml" - }, - "codebuddy": { - "configManagement": "Configuração do CodeBuddy", - "configDescription": "O CodeBuddy autentica com uma chave de API. As versões da China continental também exigem o ambiente definido como “China (internal)”; as versões iOA usam “iOA”. A versão internacional deixa sem definir.", - "apiKeyLabel": "Chave de API", - "apiKeyHint": "Salvo como CODEBUDDY_API_KEY para este agente. Como alternativa, faça login com a CLI do CodeBuddy em um terminal.", - "apiKeyHintSelfHosted": "Salvo como CODEBUDDY_API_KEY para este agente. Use a chave emitida pela sua implantação privada.", - "environmentLabel": "Ambiente", - "environmentHint": "Define CODEBUDDY_INTERNET_ENVIRONMENT. A China continental deve usar “China (internal)”; a versão internacional deixa sem definir.", - "envOverseas": "Internacional (padrão)", - "envChina": "China (internal)", - "envIoa": "iOA", - "envSelfHosted": "Auto-hospedado (implantação privada)", - "baseUrlLabel": "URL de implantação", - "baseUrlPlaceholder": "https://codebuddy.your-company.com", - "baseUrlHint": "Salvo como CODEBUDDY_BASE_URL e aponta o CodeBuddy para seu endpoint privado. No auto-hospedado, o ambiente de rede (CODEBUDDY_INTERNET_ENVIRONMENT) fica sem definição.", - "baseUrlInvalid": "Insira uma URL http(s) válida.", - "loginHint": "Sem chave de API? Execute “codebuddy” em um terminal para fazer login com sua conta Tencent." - }, - "kimiCode": { - "configManagement": "Configuração do Kimi Code", - "configDescription": "O `kimi acp` só aceita um token de login armazenado, por isso o codeg grava um provedor gerenciado em ~/.kimi-code/config.toml e cria um token de acesso local — a inferência continua usando a sua própria chave.", - "statusUnconfigured": "Ainda não configurado", - "statusDirty": "Alterações não salvas", - "summaryLabel": "Em vigor", - "gateReadyApiKey": "Chave de API gravada em config.toml", - "gateReadyLogin": "Conectado com uma conta Kimi", - "revealConfig": "Mostrar na pasta", - "envOverrideWarning": "{keys} está definido e tem prioridade sobre o config.toml. Salvar aqui remove essa variável.", - "authModeLabel": "Método de autenticação", - "authModeApiKey": "Chave de API", - "authModeLogin": "Login da conta Kimi (assinatura)", - "authModeApiKeyHint": "Grava um provedor gerenciado no config.toml e cria o token de acesso para que as sessões possam abrir.", - "loginHint": "Execute `kimi login` em um terminal para entrar com uma conta Kimi por assinatura. O codeg não armazena nada e reutiliza o login do próprio Kimi. Salvar aqui remove o token de acesso por chave de API do codeg.", - "credentialTitle": "Credencial", - "interfaceTypeLabel": "Tipo de provedor", - "interfaceTypeHint": "O protocolo de provedor que o Kimi fala (o `type` do config.toml). Use Kimi / Moonshot para uma chave da Moonshot / platform.kimi.com.", - "endpointLabel": "Endpoint", - "endpointCustom": "Personalizado (compatível com OpenAI)", - "endpointHint": "Internacional = api.moonshot.ai; China (chaves de platform.kimi.com) = api.moonshot.cn. Personalizado aponta para qualquer endpoint compatível com OpenAI.", - "regionInternational": "Internacional (api.moonshot.ai)", - "regionChina": "China (api.moonshot.cn)", - "baseUrlLabel": "URL base", - "baseUrlHint": "Deixe em branco para usar o padrão do SDK do provedor.", - "apiKeyLabel": "Chave de API", - "apiKeyHint": "Gravada em ~/.kimi-code/config.toml e usada para inferência. De platform.kimi.com ou platform.kimi.ai.", - "vertexProjectLabel": "Projeto do GCP (GOOGLE_CLOUD_PROJECT)", - "vertexLocationLabel": "Região do GCP (GOOGLE_CLOUD_LOCATION)", - "vertexHint": "O Vertex AI usa as credenciais padrão do aplicativo Google — execute `gcloud auth application-default login` (sem chave de API).", - "modelTitle": "Modelo", - "modelLabel": "Modelo", - "modelHint": "O id do modelo gravado no config.toml. Use «Testar e listar modelos» para ver o que a sua chave realmente acessa.", - "maxContextLabel": "Tamanho máximo de contexto", - "maxContextHint": "Obrigatório pelo esquema do Kimi: sem ele o Kimi descarta todo o bloco do modelo e nenhuma solicitação retorna resposta. Padrão 262144.", - "fetchModels": "Testar e listar modelos", - "fetchModelsOk": "A chave funciona — {count} modelos disponíveis", - "fetchModelsEmpty": "A chave funciona, mas nenhum modelo foi retornado", - "fetchModelsFailed": "Falha no teste", - "fetchModelsNeedsKey": "Informe primeiro uma chave de API e um endpoint", - "modelNotInList": "Este modelo não está na lista acessível pela sua chave — o Kimi falhará com «modelo não encontrado».", - "reasoningTitle": "Raciocínio", - "reasoningEnableLabel": "Ativar", - "reasoningDescription": "O Kimi só mostra o seletor «Thinking» na caixa de mensagem quando o modelo declara uma capacidade de raciocínio, por isso o codeg a grava aqui. Vale para sessões novas.", - "effortsLabel": "Níveis oferecidos", - "effortsHint": "Estes níveis viram as opções do seletor «Thinking». O Kimi repassa o nível ao provedor tal como está, então escolha os que o seu modelo aceita.", - "effortsEmptyHint": "Sem nenhum nível escolhido, a caixa de mensagem fica apenas com um interruptor Off / On.", - "effortsCustomPlaceholder": "Adicionar outro nível", - "effortsAdd": "Adicionar", - "defaultEffortLabel": "Nível padrão", - "defaultEffortAuto": "Deixar o Kimi escolher", - "alwaysThinkingLabel": "O modelo sempre raciocina — remover a opção Off do seletor", - "fixErrorsFirst": "Corrija primeiro os campos destacados", - "errorModelRequired": "O modelo é obrigatório", - "errorMaxContextRequired": "O tamanho máximo de contexto é obrigatório", - "errorMaxContextInvalid": "Deve ser um número inteiro positivo", - "errorApiKeyRequired": "A chave de API é obrigatória", - "errorApiKeyInvalid": "A chave de API não pode conter quebras de linha", - "errorBaseUrlRequired": "A URL base é obrigatória", - "errorBaseUrlInvalid": "Deve começar com http:// ou https://", - "errorVertexProjectRequired": "O projeto do GCP é obrigatório", - "errorDefaultEffortUnlisted": "Escolha um dos níveis selecionados acima", - "advancedTitle": "Avançado", - "authTypeLabel": "Local da credencial", - "authTypeApiKey": "api_key em linha", - "authTypeEnv": "Subtabela env do provedor", - "authTypeHint": "Onde a chave de API é gravada dentro do config.toml.", - "rawEditorLabel": "Editar config.toml diretamente", - "rawEditorWarning": "Salvar aqui sobrescreve o arquivo inteiro literalmente, substituindo as configurações estruturadas acima.", - "rawEditorPlaceholder": "[providers.codeg]\ntype = \"kimi\"\nbase_url = \"https://api.moonshot.cn/v1\"\napi_key = \"sk-...\"" - }, - "authModeOfficialSubscription": "Assinatura oficial", - "authModeCustomEndpoint": "Endpoint personalizado", - "authModeCustomEndpointHint": "Configurar manualmente a URL da API e a chave API para um endpoint personalizado.", - "authModeModelProvider": "Provedor de modelo", - "modelProvider": "Provedor de modelo", - "modelProviderHint": "Usar URL da API, chave API e modelo de um provedor de modelo configurado.", - "selectModelProvider": "Selecionar provedor de modelo", - "noModelProviderAvailable": "Nenhum provedor de modelo configurado para este agente. Vá para as configurações de provedores de modelo para adicionar um.", - "claude": { - "authMode": "Modo de autenticação", - "officialSubscription": "Assinatura oficial", - "officialSubscriptionHint": "Usar assinatura oficial da Anthropic, sem necessidade de API Key.", - "mainModel": "Modelo principal", - "reasoningModel": "Modelo de raciocínio (thinking)", - "haikuDefaultModel": "Modelo Haiku padrão", - "sonnetDefaultModel": "Modelo Sonnet padrão", - "opusDefaultModel": "Modelo Opus padrão", - "customModelOption": "ID do modelo personalizado", - "customModelOptionName": "Nome do modelo personalizado", - "customModelOptionDescription": "Descrição do modelo personalizado", - "customModelOptionHint": "Adiciona uma única entrada personalizada ao seletor de modelos do Claude (por exemplo, um modelo atrás de um gateway/proxy personalizado). Nome e descrição são informações de exibição opcionais.", - "effortLevel": "Nível de raciocínio", - "effortLevelDefault": "Nível padrão", - "effortLevel_low": "Baixo", - "effortLevel_medium": "Médio", - "effortLevel_high": "Alto", - "effortLevel_xhigh": "Extra Alto", - "sendAttributionHeader": "Enviar identificador de atribuição/cobrança para a API", - "sendAttributionHeaderAria": "Enviar o identificador de atribuição/cobrança do Claude Code para a API", - "disableNonessentialTraffic": "Desativar a telemetria ou solicitações de rede desnecessárias", - "disableNonessentialTrafficAria": "Desativar a telemetria ou solicitações de rede desnecessárias do Claude Code" - }, - "dialogs": { - "confirmDeleteProvider": "Excluir o provedor {providerId}?", - "confirmDeleteProviderDescription": "A configuração do OpenCode e o auth JSON serão atualizados juntos. Esta ação não pode ser desfeita.", - "confirmUninstall": "Desinstalar {name}?", - "confirmUninstallDescription": "Isso remove a versão instalada localmente. Você pode reinstalar depois.", - "customInstallTitle": "Instalação personalizada de {name}", - "customInstallDescription": "Digite a versão a instalar. Isso reinstala e substitui a versão instalada atualmente.", - "customInstallVersionLabel": "Número da versão", - "customInstallInvalid": "Digite um número de versão válido, ex.: 1.2.3.", - "customInstallSubmit": "Instalar" - }, - "errors": { - "windowsFileLocked": "Os arquivos de {name} estão em uso por uma sessão ativa, então o Windows não consegue substituí-los. Feche todas as sessões de {name} e tente novamente.", - "nativeJsonMustBeObject": "A configuração JSON nativa deve ser um objeto", - "nativeJsonInvalid": "Erro de formato na configuração JSON nativa: {message}", - "openCodeAuthMustBeObject": "OpenCode auth.json deve ser um objeto JSON", - "openCodeAuthInvalid": "Erro de formato no OpenCode auth.json: {message}", - "authMustBeObject": "auth.json deve ser um objeto JSON", - "authInvalid": "Erro de formato no auth.json: {message}", - "providerIdPattern": "O ID do provedor só aceita letras, números, sublinhado, ponto e hífen", - "providerExists": "O provedor {providerId} já existe", - "modelIdPattern": "O ID do modelo só aceita letras, números, sublinhado, ponto, dois-pontos e hífen", - "modelExists": "O modelo {modelId} já existe" - }, - "warnings": { - "nativeJsonRecoveredStructured": "A configuração JSON nativa é inválida; redefinida para configuração estruturada", - "nativeJsonRecoveredOpenCode": "A configuração JSON nativa é inválida; redefinida para configuração estruturada do OpenCode", - "openCodeAuthRecovered": "OpenCode auth.json é inválido; redefinido para configuração padrão", - "authRecoveredStructured": "auth.json é inválido; redefinido para configuração estruturada" - }, - "toasts": { - "agentActionCompleted": "{name} {action} concluído", - "agentActionFailed": "{name} {action} falhou", - "localVersion": "Versão local: {version}", - "installCompletedVersionLater": "Instalação concluída, a versão será atualizada na próxima verificação", - "uninstallCompleted": "Desinstalação de {name} concluída", - "uninstallFailed": "Desinstalação de {name} falhou", - "localVersionRemoved": "Versão local removida", - "saveAgentOrderFailed": "Falha ao salvar a ordem dos Agents", - "saveAgentSwitchFailed": "Falha ao salvar o switch dos Agents", - "saveEnvFailed": "Falha ao salvar variáveis de ambiente", - "grokSaved": "Configuração do Grok salva", - "saveGrokNativeFailed": "Falha ao salvar a configuração nativa do Grok", - "saveGrokApiKeyFailed": "Configurações salvas, mas não foi possível salvar a chave de API", - "cursorSaved": "Configuração do Cursor salva", - "saveCursorConfigFailed": "Falha ao salvar a configuração do Cursor", - "codexSaved": "Configuração do Codex salva", - "saveCodexNativeFailed": "Falha ao salvar configuração nativa do Codex", - "geminiSaved": "Configuração do Gemini salva", - "saveGeminiFailed": "Falha ao salvar configuração do Gemini", - "providerDeleted": "Provedor {providerId} excluído", - "providerDeleteFailed": "Falha ao excluir o provedor {providerId}", - "providerSaved": "Provedor {providerId} salvo", - "saveProviderFailed": "Falha ao salvar o provedor {providerId}", - "openCodeConfigSynced": "A configuração do OpenCode e o auth JSON foram sincronizados.", - "openCodeSaved": "Configuração do OpenCode salva", - "saveOpenCodeFailed": "Falha ao salvar configuração do OpenCode", - "openClawSaved": "Configuração do OpenClaw salva", - "saveOpenClawFailed": "Falha ao salvar configuração do OpenClaw", - "configSaved": "Configuração salva", - "configSavedHint": "Sessões existentes precisam ser reabertas para que as alterações tenham efeito", - "saveConfigManagementFailed": "Falha ao salvar o gerenciamento de configuração", - "clineSaved": "Configuração do Cline salva", - "saveClineFailed": "Falha ao salvar a configuração do Cline", - "hermesSaved": "Configuração do Hermes salva", - "saveHermesFailed": "Falha ao salvar a configuração do Hermes", - "codeBuddySaved": "Configuração do CodeBuddy salva", - "saveCodeBuddyFailed": "Falha ao salvar a configuração do CodeBuddy", - "kimiCodeSaved": "Configuração do Kimi Code salva", - "saveKimiCodeFailed": "Falha ao salvar a configuração do Kimi Code", - "deepseekSaved": "Configuração do DeepSeek salva", - "saveDeepSeekFailed": "Falha ao salvar a configuração do DeepSeek", - "modelProviderRequired": "Selecione um provedor de modelo antes de salvar.", - "affectedRunningSessions": "{count, plural, one {# sessão ativa precisa reconectar para aplicar a alteração} other {# sessões ativas precisam reconectar para aplicar a alteração}}", - "providerConnected": "{providerId} conectado", - "connectFailed": "Falha ao conectar {providerId}", - "providerDisconnected": "{providerId} desconectado", - "disconnectFailed": "Falha ao desconectar {providerId}", - "catalogRefreshed": "Catálogo atualizado — {count} provedores", - "catalogRefreshFailed": "Falha ao atualizar o catálogo", - "piSaved": "Configuração do Pi salva", - "savePiFailed": "Falha ao salvar a configuração do Pi", - "piRuntimeSaved": "Tempo de execução do Pi salvo", - "savePiRuntimeFailed": "Falha ao salvar o tempo de execução do Pi", - "piBinaryInstalled": "pi instalado", - "piBinaryInstallFailed": "Falha ao instalar o pi", - "piBinaryUninstalled": "pi desinstalado", - "piBinaryUninstallFailed": "Falha ao desinstalar o pi", - "savePiTrustFailed": "Falha ao salvar a confiança do espaço de trabalho" - }, - "version": { - "statusLabel": "Status da versão", - "notInstalled": "Não instalado", - "remoteLocal": "Remoto: {remoteVersion} · Local: {localVersion}", - "localOnly": "Local: {localVersion}", - "localInstalled": "{versionText}. Instalado.", - "platformUnsupported": "{versionText}. A plataforma atual não suporta este agente.", - "uvxNotReady": "{versionText}. O runtime do uv não está instalado — instale-o na verificação do uv abaixo para usar este agente.", - "clickInstall": "{versionText}. Clique em Instalar à direita.", - "localUnrecognized": "{versionText}. A versão local não é comparável; tente atualizar para sobrescrever a instalação.", - "upgradeAvailable": "{versionText}. Atualização disponível.", - "remoteUnavailable": "{versionText}. A versão remota está indisponível no momento.", - "latest": "{versionText}. Já está na versão mais recente." - }, - "adapter": { - "label": "Adaptador ACP", - "badge": "Adaptador ACP", - "badgeHint": "Para este agente o Codeg instala um pacote adaptador ACP, não a CLI do fornecedor. Os dois são independentes e compartilham a mesma configuração.", - "learnMore": "Saiba mais", - "missingWithNative": "Encontramos a sua {nativeLabel} em {nativePath}. O Codeg conversa com os agentes por ACP e essa CLI não fala ACP, então o Codeg precisa de um pacote adaptador separado, {adapterPackage}, mantido pelo projeto Agent Client Protocol (originalmente Zed). Ele traz o próprio runtime, nunca modifica nem substitui o seu comando {nativeCmd} e lê o mesmo {configDir} — seu login e suas configurações continuam valendo. Instale abaixo.", - "missing": "O Codeg conversa com os agentes por ACP e a {nativeLabel} não fala ACP, então o Codeg precisa de um pacote adaptador separado, {adapterPackage}, mantido pelo projeto Agent Client Protocol (originalmente Zed). Ele traz o próprio runtime, então a CLI {nativeCmd} não é pré-requisito; se você já a tem, as duas coexistem e compartilham o login e as configurações de {configDir}. Instale abaixo.", - "readyWithNative": "O adaptador {adapterCmd} está instalado — é ele que o Codeg inicia, não a sua {nativeCmd} em {nativePath}. São pacotes distintos que coexistem e ambos leem {configDir}, então login e configurações são compartilhados.", - "ready": "O adaptador {adapterCmd} está instalado — é ele que o Codeg inicia. Ele traz o próprio runtime, então a {nativeLabel} não é necessária; se instalá-la depois, as duas coexistem e compartilham {configDir}." - }, - "cline": { - "configDescription": "Configure o provedor de API e as credenciais do Cline. As configurações são salvas em ~/.cline/data/." - }, - "opencodePlugins": { - "title": "Plugins do OpenCode", - "declared": "Plugins declarados", - "noPlugins": "Nenhum plugin declarado em opencode.json", - "status": { - "installed": "Instalado", - "missing": "Não instalado" - }, - "installAll": "Instalar todos os ausentes", - "pinVersions": "Fixar versões @latest", - "install": "Instalar", - "uninstall": "Desinstalar", - "refresh": "Atualizar", - "success": "Todos os plugins foram instalados com sucesso", - "failed": "Operação do plugin falhou" - }, - "pi": { - "configManagement": "Configuração do Pi", - "configDescription": "O Pi autentica via a chave de API do seu provedor de modelos. A chave é gravada em ~/.pi/agent/auth.json e a seleção de modelo em settings.json.", - "providerLabel": "Provedor", - "modelLabel": "Modelo", - "thinkingLabel": "Raciocínio", - "thinking": { - "off": "Desligado", - "low": "Baixo", - "medium": "Médio", - "high": "Alto", - "minimal": "Mínimo", - "xhigh": "Muito alto" - }, - "apiKeyLabel": "Chave de API", - "apiKeyHint": "Gravada em ~/.pi/agent/auth.json para o provedor selecionado.", - "apiKeySetPlaceholder": "•••••• (salva — deixe em branco para manter)", - "saveConfig": "Salvar configuração do Pi", - "providerModelRequired": "Provedor e modelo são obrigatórios", - "runtimeTitle": "Tempo de execução", - "runtimeDescription": "Escolha qual binário do pi é executado. Use o padrão ou aponte para sua própria build do pi.", - "modeDefault": "pi padrão", - "modeDefaultHint": "Usa o adaptador pi-acp integrado com o pi no seu PATH. Instale o pi com: npm install -g @earendil-works/pi-coding-agent", - "modeCustom": "pi personalizado", - "modeCustomHint": "Execute sua própria build, instalação ou wrapper do pi.", - "commandLabel": "Comando ou caminho do pi", - "commandHint": "Um caminho absoluto, um nome de comando no PATH ou um script wrapper (ex.: ./pi-test.sh de um monorepo).", - "commandNotFound": "Comando não encontrado", - "validate": "Validar", - "advanced": "Avançado", - "configDirLabel": "Diretório de configuração (PI_CODING_AGENT_DIR)", - "sessionDirLabel": "Diretório de sessões (PI_CODING_AGENT_SESSION_DIR)", - "flagsHint": "O pi-acp não encaminha flags personalizados do pi (--approve, -e, …) — envolva o pi num script e aponte o comando para ele.", - "customIncomplete": "Digite um comando do pi para salvar", - "saveRuntime": "Salvar tempo de execução", - "providerPlaceholder": "Selecionar um provedor", - "customProvider": "Provedor personalizado…", - "providerIdLabel": "ID do provedor", - "apiProtocolLabel": "Protocolo da API", - "baseUrlLabel": "Endpoint da API (Base URL)", - "customProviderHint": "Define um provedor em ~/.pi/agent/models.json para o seu endpoint. A maioria dos servidores auto-hospedados ou proxy usa openai-completions.", - "baseUrlRequired": "O endpoint da API (Base URL) é obrigatório", - "binaryTitle": "binário pi (pi-coding-agent)", - "binaryDescription": "O pi-acp executa este binário pi. Instale-o aqui ou aponte o pi-acp para sua própria build abaixo.", - "binaryInstalled": "Instalado", - "binaryMissing": "Não instalado", - "binaryChecking": "Verificando…", - "installBinary": "Instalar pi", - "installing": "Instalando…", - "recheck": "Verificar novamente", - "configDirSkillsNote": "Com um diretório de configuração personalizado, as habilidades, os especialistas e as ferramentas de escritório gerenciados nas Configurações não se aplicam a este pi — gerencie as habilidades dele diretamente nessa pasta.", - "projectTrustTitle": "Confiança do projeto", - "projectTrustDescription": "Pastas das quais você permitiu que o pi carregue arquivos do projeto. Uma pasta confiável permite que as .pi/extensions daquele repositório executem código ao iniciar o pi, vale para todas as pastas dentro dela e também é usada quando você executa o pi no terminal.", - "projectTrustLoading": "Carregando…", - "projectTrustEmpty": "Nenhuma pasta decidida ainda.", - "projectTrustTrusted": "Confiável", - "projectTrustDenied": "Não confiável", - "projectTrustRevoke": "Revogar", - "reasoningTitle": "Raciocínio", - "reasoningEnableLabel": "Ativar", - "reasoningDescription": "O pi só envia um esforço de raciocínio para um modelo que o declara — num modelo sem declaração, todos os níveis são reduzidos para Off, por isso o seletor do compositor volta atrás assim que se mexe nele. Escrito na entrada deste modelo em models.json.", - "levelsLabel": "Níveis disponíveis", - "levelsHint": "Passam a ser as linhas do seletor de raciocínio do compositor. Escolha os que o seu endpoint aceita; o pi recusa qualquer nível que não esteja aqui.", - "levelsEmptyError": "Escolha pelo menos um nível — sem nenhum, o pi volta para Off.", - "wireValuesTitle": "Avançado: valores enviados ao fornecedor", - "wireValuesHint": "Deixe em branco para enviar o nome do nível tal como está. Defina quando o seu endpoint esperar outra coisa — backends ao estilo Google querem LOW / HIGH.", - "defaultLevelUnlisted": "Este nível não está na lista acima — o pi iria reduzi-lo." - }, - "addCustomAgent": "Adicionar agente personalizado", - "addCustomAgentHint": "Registre qualquer agente compatível com ACP. Escolha um no registro público do ACP ou cole as informações de registro dele.", - "customAgentFromRegistry": "Registro ACP", - "customAgentManual": "Manual", - "customAgentSearchPlaceholder": "Buscar agentes…", - "customAgentLoadingCatalog": "Carregando o registro ACP…", - "customAgentRetry": "Tentar novamente", - "customAgentNoResults": "Nenhum agente correspondente", - "customAgentAdd": "Adicionar", - "customAgentAlreadyAdded": "Adicionado", - "customAgentUnsupportedPlatform": "Nenhuma compilação disponível para esta plataforma", - "customAgentAdded": "{name} adicionado", - "customAgentIdLabel": "ID do registro", - "customAgentNameLabel": "Nome exibido", - "customAgentVersionLabel": "Versão", - "customAgentSpecLabel": "Distribuição (JSON)", - "customAgentSpecHint": "Mesma forma do objeto distribution do registro ACP: canais npx, uvx e binary, ou cole uma entrada completa do registro. Em npx/uvx, cmd é o executável que o pacote instala — derivado do nome do pacote quando omitido, então defina-o quando forem diferentes. binary é organizado por chave de plataforma (esta máquina: {platform}); cmd é o caminho de execução dentro do arquivo e sha256 verifica opcionalmente o download.", - "customAgentTemplateLabel": "Modelos", - "customAgentKindLabel": "Iniciar via", - "customAgentInvalidJson": "JSON inválido", - "customAgentNoDistribution": "Nenhuma distribuição npx, uvx ou binary encontrada", - "customAgentCancel": "Cancelar", - "customAgentSave": "Adicionar agente", - "customAgentSaveChanges": "Salvar alterações", - "customAgentEdit": "Editar agente", - "customAgentEditHint": "Atualize o nome, o ícone, a distribuição e as declarações de skills. O ID do agente não pode ser alterado.", - "customAgentEditNotFound": "Agente personalizado {id} não encontrado", - "customAgentSaved": "{name} salvo", - "customAgentVersionProbeLabel": "Comando de consulta de versão (opcional)", - "customAgentVersionProbeHint": "Comando que imprime a versão instalada localmente. Se ficar vazio, o codeg executa o comando do agente com --version.", - "customAgentRemove": "Remover agente", - "customAgentRemoveHint": "Exclui a definição do agente. As conversas existentes mantêm o histórico; o agente apenas não pode mais ser iniciado.", - "customAgentIconLabel": "Ícone (opcional)", - "customAgentIconUpload": "Enviar", - "customAgentIconReplace": "Substituir", - "customAgentIconClear": "Remover ícone", - "customAgentIconHint": "Salvo junto com o agente, portanto funciona offline. Sem um ícone, usa-se uma inicial colorida.", - "customAgentSkillsLabel": "Skills (.agents/skills compartilhado)", - "customAgentSkillsHint": "Declara que este agente lê o repositório compartilhado .agents/skills (diretórios global e de projeto) e o adiciona a todas as matrizes de habilidades. Habilidades vinculadas lá ficam visíveis para todos os agentes que leem esse repositório compartilhado.", - "customAgentSkillsDirLabel": "Diretório de skills dedicado", - "customAgentSkillsDirHint": "Caminho absoluto do diretório de onde este agente carrega skills — o seu próprio repositório, além do compartilhado ou no lugar dele. ~ expande para o diretório pessoal; skills vinculadas são colocadas aqui primeiro.", - "customAgentMcpLabel": "Suporte a MCP", - "customAgentMcpHint": "Envia o companheiro MCP integrado do codeg para este agente ao iniciar a sessão — o canal por trás da delegação, do feedback ao vivo e das ferramentas de tarefas. Desative para um agente que rejeita servidores MCP e não consegue conectar; a mudança vale a partir da próxima conexão.", - "customAgentIconNotAnImage": "Selecione um arquivo de imagem.", - "customAgentIconTooLarge": "O ícone deve ter menos de {limit} KB.", - "customAgentIconReadFailed": "Não foi possível ler essa imagem.", - "customAgentRemoveConfirm": "Remover {name}? As conversas existentes permanecem, mas o agente não poderá mais ser iniciado.", - "customAgentRemoveWithData": "Excluir também o histórico de conversas registrado", - "customAgentRemoved": "{name} removido", - "customAgentBadge": "Personalizado", - "customAgentNotLaunchable": "Este agente não pode ser iniciado aqui: {reason}" - }, - "SettingsPages": { - "agentsLoading": "Carregando configurações de agentes...", - "skillPacksLoading": "Carregando pacotes de habilidades…" - }, - "GeneralSettings": { - "loading": "Carregando...", - "sectionTitle": "Geral", - "sectionDescription": "Preferências centralizadas para o terminal padrão, aceleração de renderização e delegação multi-agente.", - "terminalTitle": "Terminal padrão", - "terminalDescription": "Escolha o shell usado ao abrir novas abas de terminal pela barra de terminal ou pela árvore de arquivos. Os agentes também o usam quando pedem ao codeg para executar uma linha de comando inteira.", - "terminalSystemDefault": "Padrão do sistema", - "terminalPowerShell7": "PowerShell 7 (pwsh)", - "terminalWindowsPowerShell": "Windows PowerShell", - "terminalCmd": "Prompt de Comando (cmd)", - "terminalSaveFailed": "Falha ao salvar as configurações do terminal: {message}", - "terminalShellCustom": "Caminho personalizado", - "terminalShellCustomPath": "Caminho do shell", - "terminalShellCustomPlaceholder": "/usr/local/bin/fish", - "terminalShellCustomSave": "Salvar", - "terminalShellCustomHint": "Informe um caminho absoluto ou um nome resolvível pelo PATH.", - "terminalShellNotInstalled": "não instalado", - "terminalShellNotFoundWarning": "Este caminho não existe neste host.", - "terminalCurrentShell": "Em uso: {path}", - "renderingDescription": "Desative a aceleração de hardware se o aplicativo apresentar tela preta ou falhas de renderização (comum em certas GPUs AMD ou GPUs Intel integradas). Aplica-se apenas à versão desktop do Windows.", - "disableHardwareAcceleration": "Desativar aceleração de hardware", - "renderingSaveFailed": "Falha ao salvar as configurações de renderização: {message}", - "restartRequired": "Salvo. Reinicie o aplicativo para aplicar a alteração.", - "restartNow": "Reiniciar agora", - "restartFailed": "Falha ao reiniciar: {message}", - "loadFailed": "Falha ao carregar: {message}" - }, - "LoginPage": { - "documentTitle": "Entrar - codeg", - "brand": "Codeg", - "subtitle": "Digite seu token de acesso para conectar ao aplicativo de desktop", - "tokenPlaceholder": "Token de acesso", - "connect": "Conectar", - "connecting": "Conectando...", - "helpText": "Encontre seu token no app de desktop em Configurações → Serviço Web", - "invalidToken": "Token inválido. Verifique e tente novamente.", - "connectionFailed": "Falha na conexão (HTTP {status})", - "networkError": "Não foi possível conectar ao servidor" - }, - "CommitPage": { - "title": "Confirmar", - "invalidFolderId": "ID de pasta inválido", - "loadingRepo": "Carregando repositório..." - }, - "MergePage": { - "title": "Resolver conflitos", - "invalidFolderId": "ID de pasta inválido", - "loadingRepo": "Carregando repositório...", - "localVersion": "Local (Nosso)", - "result": "Resultado", - "remoteVersion": "Remoto (Deles)", - "acceptLocal": "Aceitar local", - "acceptRemote": "Aceitar remoto", - "markResolved": "Marcar como resolvido", - "abortMerge": "Abortar", - "completeMerge": "Concluir merge", - "unresolvedConflicts": "Ainda há marcadores de conflito não resolvidos neste arquivo", - "fileResolved": "Arquivo resolvido com sucesso", - "allResolved": "Todos os conflitos resolvidos", - "conflictFiles": "Arquivos em conflito", - "loadingFile": "Carregando arquivo...", - "preparingMerge": "Preparando mesclagem...", - "selectFile": "Selecione um arquivo para resolver", - "noConflicts": "Nenhum arquivo em conflito", - "skipFile": "Pular", - "abortSuccess": "Operação abortada", - "applyAllNonConflicting": "Aplicar todas as alterações sem conflito", - "applyLeftNonConflicting": "Aplicar local", - "applyRightNonConflicting": "Aplicar remoto" - }, - "ImportSessions": { - "title": "Importar sessões locais", - "scanningTitle": "Verificando sessões locais dos agentes…", - "scanningHint": "Percorrendo o armazenamento local de sessões de cada agente. Históricos grandes podem levar um momento. As sessões já importadas são atualizadas no processo.", - "scanFailed": "Falha na verificação", - "retry": "Tentar novamente", - "rescan": "Verificar novamente", - "empty": "Nenhuma sessão local encontrada", - "emptyHint": "Nenhum armazenamento de sessões de agentes foi encontrado nesta máquina.", - "noMatches": "Nenhuma sessão corresponde aos filtros atuais", - "searchPlaceholder": "Pesquisar título ou caminho…", - "allAgents": "Todos os agentes", - "onlyImportable": "Somente importáveis", - "selectAll": "Selecionar tudo", - "clearSelection": "Limpar", - "expandAll": "Expandir tudo", - "collapseAll": "Recolher tudo", - "summaryCounts": "{total} sessões · {importable} importáveis · {folders} pastas", - "noFolderSkipped": "{count} sem pasta de projeto ignoradas", - "folderNew": "Nova", - "folderCounts": "{importable}/{total} importáveis", - "toggleFolderAria": "Selecionar todas as sessões importáveis de {name}", - "toggleSessionAria": "Selecionar a sessão {title}", - "statusImported": "Importada", - "statusDeleted": "Excluída", - "untitled": "Sessão sem título", - "messageCount": "{count} mensagens", - "selectedCount": "{count} selecionadas", - "importSelected": "Importar seleção", - "importing": "Importando…", - "close": "Fechar", - "doneTitle": "Importação concluída", - "doneImported": "Importadas", - "doneUpdated": "Atualizadas", - "doneSkipped": "Ignoradas", - "doneCreatedFolders": "Pastas criadas", - "doneNotFound": "Não encontradas", - "doneFailed": "Falharam", - "continueImport": "Continuar importando", - "toasts": { - "importFailed": "Falha ao importar: {message}" - } - }, - "Folder": { - "workspaceStatus": { - "degradedTitle": "Atualizações em tempo real indisponíveis", - "degradedHint": "O observador falhou ao iniciar (por exemplo, permissão negada). Atualize manualmente para ver as mudanças.", - "retry": "Tentar novamente", - "retrying": "Tentando novamente..." - }, - "common": { - "all": "Todos", - "cancel": "Cancelar", - "close": "Fechar", - "closeOthers": "Fechar outros", - "closeAll": "Fechar tudo", - "confirm": "Confirmar", - "save": "Salvar", - "delete": "Excluir", - "rename": "Renomear", - "loading": "Carregando...", - "refresh": "Atualizar", - "refreshing": "Atualizando...", - "create": "Criar", - "createAndSwitch": "Criar e alternar", - "openFile": "Abrir arquivo", - "viewDiff": "Ver Diff", - "push": "Enviar..." - }, - "statusLabels": { - "in_progress": "Em andamento", - "pending_review": "Revisão", - "completed": "Concluído", - "cancelled": "Cancelado" - }, - "sidebar": { - "title": "Conversas", - "locateActiveConversation": "Localizar conversa ativa", - "expandAllGroups": "Expandir todos os grupos", - "collapseAllGroups": "Recolher todos os grupos", - "newConversation": "Nova conversa", - "newConversationShort": "Nova", - "newChat": "Nova conversa", - "search": "Buscar", - "noConversationsFound": "Nenhuma conversa encontrada.", - "importLocalSessions": "Importar sessões locais", - "importing": "Importando...", - "error": "Erro: {message}", - "completeAllSessions": "Concluir todas as sessões", - "completeAllReviewTitle": "Concluir todas as sessões em revisão?", - "completeAllReviewDescription": "Isso marcará como concluídas todas as {count, plural, one {# sessão} other {# sessões}} em Revisão.", - "completing": "Concluindo...", - "toasts": { - "importedSessions": "Importadas {imported, plural, one {# sessão} other {# sessões}}, ignoradas {skipped}", - "importedAndUpdated": "Importadas {imported, plural, one {# sessão} other {# sessões}}, atualizados {updated, plural, one {# título} other {# títulos}}, ignoradas {skipped}", - "updatedTitles": "Atualizados {updated, plural, one {# título} other {# títulos}}, ignoradas {skipped}", - "noNewSessionsFound": "Nenhuma nova sessão encontrada (ignoradas {skipped})", - "importFailed": "Falha na importação: {message}", - "reviewCompleted": "Marcadas {count, plural, one {# sessão em revisão} other {# sessões em revisão}} como concluídas", - "completeReviewFailed": "Falha ao concluir sessões em revisão: {message}", - "folderOpened": "Pasta {name} aberta", - "folderRemoved": "Pasta {name} removida", - "openFolderFailed": "Falha ao abrir pasta", - "removeFolderFailed": "Falha ao remover pasta: {message}", - "reorderFoldersFailed": "Falha ao reordenar pastas: {message}", - "changeFolderColorFailed": "Falha ao alterar a cor: {message}", - "setFolderAliasFailed": "Falha ao definir o alias: {message}", - "changeFolderDefaultAgentFailed": "Falha ao definir agente padrão: {message}" - }, - "statsLabel": "{folders} pastas · {convos} conversas", - "reorderHandle": "Arraste para reordenar", - "openFolder": "Abrir pasta", - "searchPlaceholder": "Buscar conversas...", - "viewOptions": "Opções de exibição", - "showCompleted": "Mostrar conversas concluídas", - "showWorktrees": "Mostrar pastas de worktree", - "showRecent": "Mostrar grupo Recentes", - "moreOptions": "Mais opções", - "sortBy": "Ordenar por", - "sortByCreatedAt": "Data de criação", - "sortByUpdatedAt": "Data de atualização", - "sectionOrder": "Ordem das seções", - "sectionOrderMoveUp": "Mover para cima", - "sectionOrderMoveDown": "Mover para baixo", - "sectionOrderItemLabel": "{name} — posição {position} de {total}", - "statusRunningBadge": "Executando", - "runningCountBadge": "{count, plural, one {# sessão em execução} other {# sessões em execução}}", - "statusCancelledBadge": "Cancelado", - "worktreeRemovedBadge": "Worktree de origem removida", - "conversationCountUnit": "{count, plural, one {# conversa} other {# conversas}}", - "emptyFolderHint": "Sem conversas", - "noMatchingConversations": "Nenhuma conversa correspondente", - "noUnfinishedConversations": "Nenhuma conversa pendente. Ative \"Mostrar concluídas\" no menu superior direito.", - "removeFolderConfirmTitle": "Remover pasta do espaço de trabalho?", - "removeFolderConfirmDescription": "Remover \"{name}\" do espaço de trabalho? As abas e terminais relacionados serão fechados.", - "folderHeaderMenu": { - "manageConversations": "Gerenciar conversas…", - "manageLinks": "Pastas vinculadas", - "changeColor": "Alterar cor", - "useThemeColor": "Usar tema do app", - "setDefaultAgent": "Definir agente padrão", - "defaultAgentNone": "Sem padrão (usar global)", - "agentUnavailableSuffix": "(indisponível)", - "loadingAgents": "Carregando agentes…", - "setAlias": "Definir alias…", - "setAliasTitle": "Definir alias da pasta", - "setAliasPlaceholder": "Insira um alias (deixe vazio para limpar)", - "setAliasSave": "Salvar", - "setAliasCancel": "Cancelar", - "removeFromWorkspace": "Remover do espaço de trabalho" - }, - "manageConversations": { - "title": "Gerenciar conversas", - "searchPlaceholder": "Pesquisar por título…", - "agentFilterAll": "Todos os agentes", - "statusFilterAll": "Todos os status", - "folderFilterAll": "Todas as pastas", - "branchFilterAll": "Todas as branches", - "branchNone": "Sem branch", - "branchSearchPlaceholder": "Pesquisar branches…", - "noMatchingBranches": "Nenhuma branch correspondente", - "selectAllVisible": "Selecionar tudo", - "deselectAll": "Desmarcar tudo", - "selectedCount": "{count} selecionada(s)", - "matchedCount": "{count} correspondência(s)", - "untitledConversation": "Conversa sem título", - "setStatus": "Definir status…", - "deleteSelected": "Excluir", - "noConversations": "Sem conversas nesta pasta.", - "noConversationsWorkspace": "Sem conversas na área de trabalho.", - "noMatchingConversations": "Nenhuma conversa corresponde aos filtros.", - "confirmDeleteTitle": "Excluir {count} conversa(s)?", - "confirmDeleteDescription": "Esta ação não pode ser desfeita.", - "toastDeleted": "{count} conversa(s) excluída(s)", - "toastStatusUpdated": "Status atualizado para {count} conversa(s)", - "toastOpFailed": "Falha na operação: {message}" - }, - "sectionPinned": "Fixadas", - "sectionFolders": "Pastas", - "sectionChats": "Chat", - "sectionRecent": "Recentes", - "noChats": "Sem chats", - "noRecent": "Sem conversas recentes", - "showMoreRecent": "Mostrar mais ({count})", - "noFolders": "Nenhuma pasta aberta", - "newChatAction": "Novo chat", - "automations": "Automações", - "tasks": "Tarefas a fazer", - "loadingSubsessions": "Carregando subconversas…" - }, - "conversation": { - "reloadFailed": "Falha ao recarregar conversa: {message}", - "reloaded": "Conversa recarregada", - "reload": "Recarregar", - "activeConversationIndicator": "Conversa ativa", - "newConversation": "Nova conversa", - "closeConversation": "Fechar conversa", - "copyText": "Copiar texto", - "copyTextSuccess": "Copiado", - "copyTextFailed": "Falha ao copiar", - "forkSession": "Bifurcar sessão", - "forkSessionSuccess": "Sessão bifurcada com sucesso", - "forkSessionFailed": "Falha ao bifurcar a sessão: {error}", - "exportConversation": "Exportar conversa", - "exportImage": "Imagem", - "exportMarkdown": "Markdown", - "exportHtml": "HTML", - "exportSuccess": "Conversa exportada", - "exportFailed": "Falha ao exportar", - "exportImageTooLong": "A conversa é muito longa para exportar como imagem", - "exportLabels": { - "untitledConversation": "Conversa sem título", - "agent": "Agente", - "model": "Modelo", - "status": "Estado", - "started": "Início", - "updated": "Atualizado", - "tokens": "Estatísticas de tokens", - "duration": "Duração", - "inputTokens": "Entrada", - "outputTokens": "Saída", - "cacheRead": "Cache lido", - "cacheWrite": "Cache escrito", - "user": "Utilizador", - "assistant": "Assistente", - "system": "Sistema", - "toolResult": "Resultado", - "toolError": "Erro" - }, - "moreActions": "Mais ações" - }, - "sessionDetails": { - "menuLabel": "Detalhes da sessão", - "noActiveSession": "Nenhuma sessão ativa", - "title": "Detalhes da sessão", - "subtitle": "Metadados da sessão e uso de tokens", - "fieldTitle": "Título", - "untitled": "Conversa sem título", - "sessionId": "ID da sessão", - "externalId": "ID da extensão", - "agent": "Agente", - "model": "Modelo", - "status": "Estado", - "gitBranch": "Branch do Git", - "parentId": "Sessão principal", - "tokensHeading": "Uso de tokens", - "totalTokens": "Total", - "inputTokens": "Entrada", - "outputTokens": "Saída", - "cacheWrite": "Cache escrito", - "cacheRead": "Cache lido", - "contextWindow": "Janela de contexto", - "duration": "Duração", - "loadingStats": "Carregando uso de tokens…", - "loadFailed": "Falha ao carregar o uso de tokens", - "noStats": "Nenhum uso registrado", - "timestampsHeading": "Carimbos de data/hora", - "createdAt": "Criado", - "updatedAt": "Atualizado", - "none": "—", - "copyField": "Copiar {field}", - "copiedField": "{field} copiado" - }, - "conversationCard": { - "untitledConversation": "Conversa sem título", - "newConversation": "Nova conversa", - "rename": "Renomear", - "status": "Status", - "delete": "Excluir", - "importLocalSessions": "Importar sessões locais", - "importing": "Importando...", - "renameConversation": "Renomear conversa", - "deleteConversationTitle": "Excluir conversa?", - "deleteConversationDescription": "Isso excluirá \"{title}\". Esta ação não pode ser desfeita.", - "cancel": "Cancelar", - "save": "Salvar", - "pin": "Fixar", - "unpin": "Desafixar", - "markCompleted": "Marcar como concluída", - "reopen": "Reabrir", - "expandSubsessions": "Expandir subconversas", - "collapseSubsessions": "Recolher subconversas" - }, - "search": { - "dialogTitle": "Buscar", - "dialogTitleWithFolder": "Buscar — {name}", - "tabConversations": "Conversas", - "tabFiles": "Arquivos", - "placeholder": "Buscar conversas...", - "filePlaceholder": "Buscar arquivos ou diretórios...", - "allAgents": "Todos", - "searching": "Buscando...", - "typeToSearch": "Digite para buscar conversas", - "typeToSearchFiles": "Digite para buscar arquivos ou diretórios", - "noResults": "Nenhum resultado encontrado.", - "untitledConversation": "Conversa sem título" - }, - "folderTitleBar": { - "showSidebar": "Mostrar barra lateral", - "hideSidebar": "Ocultar barra lateral", - "toggleTerminal": "Alternar terminal", - "toggleAuxPanel": "Alternar painel auxiliar", - "search": "Buscar", - "openSettings": "Abrir configurações", - "backToConversations": "Voltar às conversas", - "withShortcut": "{label} (atalho: {shortcut})" - }, - "statusBar": { - "connection": { - "connected": "Conectado", - "connecting": "Conectando...", - "prompting": "Respondendo...", - "error": "Erro de conexão", - "disconnected": "Desconectado", - "tooltip": "{agent}: {status}", - "tooltipError": "{agent}: {error}", - "title": "Conexão do agente", - "triggerAria": "Conexão do agente: {status}", - "workingDir": "Diretório de trabalho", - "sessionId": "ID da sessão", - "viewerNote": "Anexado a uma sessão de outro cliente — reconectar apenas reanexa esta visualização.", - "reconnectInterrupts": "Reconectar reinicia o agente e interrompe o trabalho em andamento.", - "reconnect": "Reconectar", - "reconnecting": "Reconectando...", - "reconnectUnavailable": "Ainda não há sessão para reconectar." - }, - "tasks": { - "title": "Tarefas" - }, - "alerts": { - "title": "Alertas", - "empty": "Sem alertas", - "details": "Detalhes" - }, - "stats": { - "conversations": "{count} conversas", - "openUsage": "Ver estatísticas de sessões e uso de tokens" - }, - "tokens": { - "contextWindowUsageAria": "Uso da janela de contexto", - "contextWindow": "Janela de contexto", - "usedMax": "Usado / Máx", - "tokenUsage": "Uso de tokens", - "input": "Entrada", - "output": "Saída", - "cacheRead": "Leitura de cache", - "cacheWrite": "Gravação de cache", - "total": "Total de tokens" - } - }, - "auxPanel": { - "tabs": { - "files": "Arquivos", - "changes": "Alterações", - "commits": "Confirmações" - }, - "noFolderTitle": "Nenhuma pasta aberta", - "noFolderHint": "Abra uma pasta para ver seu conteúdo aqui" - }, - "windowControls": { - "minimizeWindow": "Minimizar janela", - "minimize": "Minimizar", - "maximizeWindow": "Maximizar janela", - "maximize": "Maximizar", - "restoreWindow": "Restaurar janela", - "restore": "Restaurar", - "closeWindow": "Fechar janela", - "close": "Fechar" - }, - "tabs": { - "closeConversationTab": "Fechar aba de conversa", - "close": "Fechar", - "closeOthers": "Fechar outros", - "splitRight": "Dividir à direita", - "splitDown": "Dividir abaixo", - "splitAndMoveRight": "Dividir e mover para a direita", - "splitAndMoveDown": "Dividir e mover para baixo", - "moveToOppositeGroup": "Mover para o grupo oposto", - "moveToGroup": "Mover para o grupo", - "groupLabel": "Grupo {index}", - "changeSplitterOrientation": "Alternar orientação do divisor", - "unsplit": "Desfazer divisão", - "unsplitAll": "Desfazer todas as divisões", - "closeAll": "Fechar tudo", - "tileDisplay": "Exibição em mosaico", - "untileDisplay": "Sair do mosaico" - }, - "fileWorkspace": { - "files": "Arquivos", - "closeFileTab": "Fechar aba de arquivo", - "close": "Fechar", - "closeOthers": "Fechar outros", - "closeAll": "Fechar tudo", - "preview": "Visualizar", - "editSource": "Editar fonte", - "maximize": "Maximizar", - "restore": "Restaurar", - "emptyDirectory": "Pasta vazia" - }, - "terminal": { - "rename": "Renomear", - "close": "Fechar", - "closeOthers": "Fechar outros", - "closeAll": "Fechar tudo", - "hideTerminal": "Ocultar terminal ({shortcut})", - "openFolderFirst": "Abra primeiro uma pasta" - }, - "workspaceDialog": { - "title": "Abrir pasta", - "manageTitle": "Pastas vinculadas", - "addTargetsTitle": "Adicionar pastas para vincular", - "pickRootDescription": "Escolha a pasta principal deste espaço de trabalho.", - "linksDescription": "Vincule outras pastas como subdiretórios para que os agentes trabalhem em todas elas a partir de um único espaço de trabalho.", - "addTargetsDescription": "Selecione uma ou mais pastas. Cada uma vira um subdiretório do espaço de trabalho.", - "useSystemPicker": "Seletor do sistema", - "next": "Avançar", - "back": "Voltar", - "done": "Concluir", - "change": "Alterar", - "addFolders": "Adicionar pastas", - "addSelected": "Adicionar", - "addSelectedCount": "Adicionar {count}", - "createCount": "Vincular {count} pasta(s)", - "discardPending": "Descartar", - "noLinks": "Ainda não há pastas vinculadas.", - "gitExclude": "Manter os vínculos fora do status do git", - "rename": "Renomear", - "unlink": "Remover vínculo", - "repair": "Recriar vínculo", - "saveName": "Salvar", - "cancelRename": "Cancelar", - "removePending": "Remover", - "willAppearAs": "Aparece como {name} no espaço de trabalho", - "renamedForDuplicate": "Renomeada — {base} já é usada por outro vínculo", - "renamedForExistingEntry": "Renomeada — {base} já existe nesta pasta", - "partiallyCreated": "Apenas {count} pasta(s) puderam ser vinculadas", - "openFailed": "Falha ao abrir a pasta", - "previewFailed": "Falha ao verificar as pastas selecionadas", - "createFailed": "Falha ao vincular as pastas", - "renameFailed": "Falha ao renomear o vínculo", - "removeFailed": "Falha ao remover o vínculo", - "repairFailed": "Falha ao recriar o vínculo", - "status": { - "ok": "Vinculada", - "missing": "O vínculo sumiu desta pasta", - "conflicted": "Outra entrada usa esse nome agora", - "broken": "A pasta vinculada não existe mais" - }, - "nameIssue": { - "empty": "Digite um nome", - "illegalChars": "Não pode conter / \\ : * ? \" < > |", - "tooLong": "Nome muito longo", - "reserved": "Este nome é reservado pelo Windows", - "duplicate": "Este nome já está em uso" - }, - "rejection": { - "not_found": "Pasta não encontrada", - "not_a_directory": "Este caminho não é uma pasta", - "same_as_root": "É a própria pasta do espaço de trabalho", - "ancestor_of_root": "Esta pasta contém o espaço de trabalho", - "inside_root": "Já está dentro do espaço de trabalho", - "already_linked": "Já vinculada", - "name_unavailable": "Não há mais nomes livres para esta pasta", - "alreadyLinkedAs": "Já vinculada como {name}" - } - }, - "folderNameDropdown": { - "fallbackFolderName": "Pasta", - "openFolder": "Abrir pasta", - "cloneRepository": "Clonar repositório", - "projectBoot": "Inicializador de projeto", - "opened": "Aberto", - "recentOpen": "Abertos recentemente" - }, - "fileWorkspacePanel": { - "addSelectionToChat": "Adicionar seleção ao chat", - "addToChat": "Adicionar ao chat", - "addSelectionToChatDone": "{label} adicionado à conversa", - "addFileToChat": "Adicionar arquivo ao chat", - "toggleWordWrap": "Alternar quebra de linha", - "addFileToChatDone": "{label} adicionado à conversa", - "viewDiff": "Ver Diff", - "openFile": "Abrir arquivo", - "fileCount": "{count, plural, one {# arquivo} other {# arquivos}}", - "openFileOrDiff": "Abra um arquivo ou diff pelo painel direito", - "disk": "Disco", - "head": "HEAD", - "unsaved": "Não salvo", - "workingTree": "Árvore de trabalho", - "loading": "Carregando...", - "compareWithBranch": "{path} · comparar com {branch}", - "hunkCount": "{count, plural, one {# bloco} other {# blocos}}", - "prev": "Anterior", - "next": "Próximo", - "jumpToLine": "Ir para a linha {line}", - "noParsedDiffSections": "Sem seções de diff analisadas", - "loadingEditor": "Carregando editor...", - "imageZoomIn": "Ampliar", - "imageZoomOut": "Reduzir", - "imageZoomReset": "Redefinir zoom", - "htmlPreviewTitle": "Visualização HTML", - "htmlPreviewTrust": "Ativar scripts", - "htmlPreviewTrustHint": "Executa os scripts deste arquivo e permite acesso à rede. Ative apenas para arquivos confiáveis.", - "officePreviewTitle": "Pré-visualização de documento do Office", - "officeFullRender": "Renderização completa", - "officeFullRenderHint": "Renderiza animações Morph, 3D e fórmulas (executa os scripts do próprio slide)", - "officeNotInstalled": "OfficeCLI não está instalado", - "officeNotInstalledHint": "Instale o OfficeCLI em Configurações → Ferramentas do Office para pré-visualizar arquivos do Word, Excel e PowerPoint.", - "officeOpenSettings": "Abrir configurações", - "officeWatchFailed": "Não foi possível iniciar a visualização ao vivo", - "officeWatchRetry": "Tentar novamente", - "officeServerInstallHint": "O OfficeCLI precisa estar instalado no host do servidor. Execute este comando lá e tente novamente:", - "officeRemoteDesktopUnsupported": "A pré-visualização ao vivo não está disponível em uma janela de área de trabalho remota. Abra este espaço de trabalho na interface web do servidor para visualizar arquivos do Office." - }, - "branchDropdown": { - "toasts": { - "commitCodeCompleted": "Commit de código concluído", - "pushCodeCompleted": "Push de código concluído", - "committedFiles": "{count, plural, one {# arquivo commitado} other {# arquivos commitados}}", - "taskCompleted": "{label} concluído", - "taskFailed": "{label} falhou", - "mergeNoNewCommits": "{branchName} não tem novos commits", - "mergedCommits": "{count, plural, one {# commit mesclado} other {# commits mesclados}}", - "allFilesUpToDate": "Todos os arquivos estão atualizados", - "updatedFiles": "{count, plural, one {# arquivo atualizado} other {# arquivos atualizados}}", - "openCommitWindowFailed": "Falha ao abrir a janela de commit", - "openPushWindowFailed": "Falha ao abrir janela de envio", - "upstreamSet": "A branch upstream foi definida", - "upstreamSetAndPushed": "Branch upstream definida e {count, plural, one {# commit} other {# commits}} enviado(s)", - "noCommitsToPush": "Não há commits para enviar", - "pushedCommits": "{count, plural, one {# commit enviado} other {# commits enviados}}", - "switchedToFolder": "Alternado para {name}", - "switchFailed": "Falha ao trocar de branch", - "openStashWindowFailed": "Falha ao abrir a janela de stash" - }, - "tasks": { - "newBranch": "Criar branch {name}", - "newWorktree": "Criar worktree {name}", - "checkoutTo": "Fazer checkout para {branchName}", - "mergeBranch": "Mesclar {branchName}", - "rebaseTo": "Rebase para {branchName}", - "deleteRemoteBranch": "Excluir branch remoto {branchName}", - "initGitRepo": "Inicializar repositório Git", - "pullCode": "Fazer pull do código", - "fetchInfo": "Buscar informações", - "pushCode": "Enviar código", - "stashChanges": "Fazer stash das alterações", - "stashPop": "Aplicar stash", - "deleteBranch": "Excluir branch {branchName}", - "removeWorktree": "Excluir o worktree de {branchName}", - "removeWorktreeAndBranch": "Excluir o worktree e o branch {branchName}", - "updateBranch": "Atualizar o branch {branchName}" - }, - "confirm": { - "mergeTitle": "Mesclar branch", - "rebaseTitle": "Rebase da branch", - "mergeDescription": "Mesclar {branchName} na branch atual {currentBranch}?", - "rebaseDescription": "Fazer rebase da branch atual {currentBranch} sobre {branchName}?", - "deleteRemoteTitle": "Excluir branch remoto", - "deleteRemoteDescription": "Excluir o branch remoto {branchName}? Isso o removerá do repositório remoto e não poderá ser desfeito.", - "deleteTitle": "Excluir branch", - "deleteDescription": "Excluir a branch {branchName}? Esta ação não pode ser desfeita.", - "forceDeleteTitle": "Forçar exclusão do branch", - "forceDeleteDescription": "O branch {branchName} não está totalmente mesclado. Tem certeza de que deseja forçar a exclusão? Esta ação não pode ser desfeita.", - "deleteWorktreeTitle": "Excluir worktree", - "deleteWorktreeDescription": "Excluir o diretório do worktree onde {branchName} está em uso? O branch e seus commits são mantidos.", - "forceDeleteWorktreeTitle": "Forçar a exclusão do worktree", - "forceDeleteWorktreeDescription": "O worktree de {branchName} tem arquivos não commitados ou não rastreados. Excluir mesmo assim? Essas alterações não poderão ser recuperadas.", - "deleteWorktreeAndBranchTitle": "Excluir worktree e branch", - "deleteWorktreeAndBranchDescription": "Excluir o worktree de {branchName}, o próprio branch e a pasta dele no espaço de trabalho? As sessões passam para a pasta do repositório. Esta ação não pode ser desfeita.", - "forceDeleteWorktreeAndBranchTitle": "Forçar a exclusão do worktree e do branch", - "forceDeleteWorktreeAndBranchDescription": "O worktree de {branchName} tem arquivos não commitados, ou o branch não está totalmente mesclado. Excluir os dois mesmo assim? Esta ação não pode ser desfeita." - }, - "current": "Atual", - "switchToBranch": "Mudar para esta branch", - "mergeBranchIntoCurrent": "Mesclar {branchName} em {currentBranch}", - "rebaseCurrentToBranch": "Rebase de {currentBranch} sobre {branchName}", - "noBranch": "Sem ramo", - "detachedHead": "HEAD desanexado em {sha}", - "initGitRepo": "Inicializar repositório Git", - "pullCode": "Fazer pull do código", - "fetchRemoteBranches": "Buscar branches remotas", - "openCommitWindow": "Commit de código...", - "pushCode": "Enviar...", - "pushBranch": "Enviar", - "newBranch": "Nova branch...", - "newWorktree": "Novo worktree...", - "stashChanges": "Guardar alterações...", - "stashPop": "Aplicar stash...", - "manageRemotes": "Gerenciar remotos...", - "localBranches": "Branches locais ({count, plural, one {#} other {#}})", - "noLocalBranches": "Sem branches locais", - "remoteBranches": "Branches remotas ({count, plural, one {#} other {#}})", - "noRemoteBranches": "Sem branches remotas", - "dialogs": { - "newBranchTitle": "Nova branch", - "newBranchDescription": "Criar uma nova branch a partir da branch atual {branch}", - "branchNamePlaceholder": "Nome da branch", - "newWorktreeTitle": "Novo worktree", - "newWorktreeDescription": "Criar um novo worktree a partir da branch atual {branch}", - "branchNameLabel": "Nome da branch", - "worktreePathLabel": "Caminho do worktree", - "worktreePathPlaceholder": "Caminho do worktree", - "manageRemotesTitle": "Gerenciar remotos", - "manageRemotesEmpty": "Nenhum remoto configurado", - "remoteNamePlaceholder": "Nome do remoto", - "remoteUrlPlaceholder": "URL do remoto", - "addRemote": "Adicionar", - "savingRemotes": "Salvando..." - }, - "conflict": { - "title": "Conflitos de merge", - "description": "Os seguintes arquivos têm conflitos que precisam ser resolvidos:", - "abort": "Abortar merge", - "openMergeTool": "Abrir ferramenta de merge", - "completeMerge": "Concluir merge", - "abortSuccess": "Merge abortado com sucesso", - "completeSuccess": "Merge concluído com sucesso" - }, - "stashDialog": { - "title": "Guardar alterações no stash", - "description": "Guardar as alterações atuais no stash", - "messageLabel": "Mensagem", - "messagePlaceholder": "Mensagem do stash (opcional)", - "keepIndex": "Manter índice (alterações preparadas permanecem preparadas)", - "cancel": "Cancelar", - "stash": "Guardar", - "success": "Alterações guardadas no stash", - "error": "Erro ao guardar no stash" - }, - "unstashDialog": { - "title": "Aplicar stash", - "noStashes": "Nenhum stash encontrado", - "selectFile": "Selecione um ficheiro para ver diferenças", - "viewDiff": "Ver diferenças", - "original": "Original", - "modified": "Modificado", - "apply": "Aplicar", - "drop": "Eliminar", - "applySuccess": "Stash aplicado", - "dropSuccess": "Stash eliminado", - "confirmApply": "Aplicar stash {ref} ao diretório de trabalho?", - "cancel": "Cancelar" - }, - "deleteBranch": "Excluir branch", - "deleteWorktree": "Excluir worktree", - "deleteWorktreeAndBranch": "Excluir worktree e branch", - "searchPlaceholder": "Pesquisar ramos e ações", - "searchAriaLabel": "Pesquisar ramos e ações", - "branchListLabel": "Ramos e ações", - "noMatches": "Nenhuma correspondência" - }, - "commitDialog": { - "toasts": { - "commitCompleted": "Commit de código concluído", - "pushFailed": "Falha no envio", - "committedFiles": "{count, plural, one {# arquivo commitado} other {# arquivos commitados}}", - "addedToVcs": "Adicionado ao VCS", - "addToVcsFailed": "Falha ao adicionar ao VCS", - "fileDeleted": "Arquivo excluído", - "deleteFailed": "Falha ao excluir", - "fileRolledBack": "Arquivo revertido", - "rollbackFailed": "Falha no rollback", - "dirRolledBack": "Diretório revertido", - "dirDeleted": "Diretório excluído" - }, - "confirm": { - "deleteTitle": "Confirmar exclusão", - "deleteDescription": "Excluir o arquivo \"{file}\"? Esta ação não pode ser desfeita.", - "rollbackTitle": "Confirmar rollback", - "rollbackDescription": "Reverter o arquivo \"{file}\" para o HEAD? Alterações não salvas serão perdidas.", - "rollbackDirDescription": "Reverter o diretório \"{dir}\" para HEAD? Alterações não salvas serão perdidas.", - "deleteDirDescription": "Excluir o diretório \"{dir}\"? Esta ação não pode ser desfeita." - }, - "actions": { - "select": "Selecionar", - "unselect": "Desmarcar", - "rollback": "Reverter", - "addToVcs": "Adicionar ao VCS" - }, - "aria": { - "selectFile": "{action}: {path}", - "unselectAllFiles": "Desmarcar todos os arquivos", - "selectAllFiles": "Selecionar todos os arquivos", - "unselectTracked": "Desmarcar alterações rastreadas", - "selectTracked": "Selecionar alterações rastreadas", - "unselectUntracked": "Desmarcar arquivos não rastreados", - "selectUntracked": "Selecionar arquivos não rastreados" - }, - "loading": "Carregando...", - "selectionCount": "{selected} / {total} arquivos", - "emptyFiles": "Sem arquivos alterados", - "trackedChanges": "Alterações rastreadas ({count})", - "untrackedFiles": "Arquivos não rastreados ({count})", - "commitMessage": "Mensagem de commit", - "commitMessagePlaceholder": "Digite a mensagem de commit...", - "commitButton": "Confirmar ({count})", - "commitAndPushButton": "Confirmar e enviar ({count})", - "head": "HEAD", - "workingTree": "Árvore de trabalho", - "clickFileToDiff": "Clique no nome do arquivo para ver o diff", - "loadingDiff": "Carregando diff..." - }, - "pushWindow": { - "title": "Enviar código", - "noUnpushedCommits": "Nenhum commit não enviado", - "noRemoteConfigured": "Nenhum remoto Git configurado\nAdicione um em «Gerenciar remotos»", - "newBranchNoPushedCommits": "Nova branch — enviar para criar branch de rastreamento remota", - "unpushed": "Não enviado", - "selectFileToViewDiff": "Selecione um arquivo para ver as diferenças", - "before": "Antes", - "after": "Depois", - "push": "Enviar", - "toasts": { - "pushSuccess": "Envio bem-sucedido", - "pushFailed": "Falha no envio", - "upstreamSet": "Branch remoto foi configurado", - "upstreamSetAndPushed": "Branch remoto configurado e {count} commits enviados", - "noCommitsToPush": "Nenhum commit para enviar", - "pushedCommits": "{count} commits enviados" - } - }, - "gitLogTab": { - "filesTitle": "Arquivos", - "expandAllFiles": "Expandir todos os arquivos", - "collapseAllFiles": "Recolher todos os arquivos", - "workspace": "espaço de trabalho", - "retry": "Tentar novamente", - "noCommitsFound": "Nenhum commit encontrado", - "notAGitRepoTitle": "Não é um repositório Git", - "notAGitRepoHint": "Inicialize o Git pelo menu de ramificações acima, ou abra um repositório existente.", - "hash": "Hash do commit", - "copyHash": "Copiar hash", - "copyMessage": "Copiar mensagem", - "showMore": "Mostrar mais", - "showLess": "Mostrar menos", - "author": "Autor", - "noFileChangeDetails": "Sem detalhes de alteração de arquivos disponíveis.", - "loadingFiles": "Carregando arquivos...", - "branchesTitle": "Branches Git", - "loadingBranches": "Carregando branches...", - "noContainingBranches": "Nenhuma branch contendo este commit foi encontrada.", - "newBranch": "Nova branch...", - "resetToHere": "Resetar para aqui", - "resetDisabledReasonNotCurrentBranchView": "Disponível somente ao visualizar a branch atual", - "copyFullCommitHashAria": "Copiar hash completo do commit {hash}", - "pushStatus": { - "pushed": "Enviado para o remoto", - "notPushed": "Não enviado para o remoto", - "unknown": "Status de push desconhecido (upstream não configurado)" - }, - "time": { - "monthsAgo": "{count, plural, one {há # mês} other {há # meses}}", - "daysAgo": "{count, plural, one {há # dia} other {há # dias}}", - "hoursAgo": "{count, plural, one {há # hora} other {há # horas}}", - "minsAgo": "{count, plural, one {há # min} other {há # mins}}", - "justNow": "agora mesmo" - }, - "toasts": { - "createdAndSwitchedNewBranch": "Nova branch criada e selecionada", - "newBranchFromCommit": "{name} (de {shortHash})", - "createBranchFailed": "Falha ao criar branch", - "openPushWindowFailed": "Falha ao abrir a janela de push", - "resetSuccess": "Reset concluído", - "resetSuccessDescription": "{branch} foi resetada para {shortHash} com {mode}", - "resetFailed": "Falha no reset" - }, - "authorFilter": { - "label": "Autor", - "searchPlaceholder": "Pesquisar autor", - "noAuthors": "Nenhum autor encontrado", - "you": "você", - "filterByAuthorAria": "Filtrar commits por autor", - "filterByQuery": "Filtrar por \"{query}\"", - "clearAuthorFilterAria": "Limpar filtro de autor", - "recent": "Recentes", - "matchingAuthors": "Autores correspondentes", - "removeFromRecent": "Remover {name} dos recentes" - }, - "branchSelector": { - "label": "Branch", - "head": "HEAD", - "headHint": "Acompanha a branch atual", - "headHintWithBranch": "Acompanha a branch atual ({branch})", - "searchBranch": "Pesquisar branch...", - "noBranches": "Nenhum branch", - "selectBranchPlaceholder": "Selecionar branch...", - "localBranches": "Branches locais", - "current": "Atual", - "remoteBranches": "Branches remotas", - "refreshCommitHistory": "Atualizar histórico de commits", - "clearBranchFilterAria": "Limpar filtro de branch" - }, - "dialogs": { - "newBranchTitle": "Nova branch", - "newBranchDescription": "Criar uma nova branch com o commit {shortHash} como commit mais recente.", - "branchNamePlaceholder": "Nome da branch", - "reset": { - "title": "Resetar a branch atual para este commit", - "branchLabel": "Branch", - "targetLabel": "Commit alvo", - "messageLabel": "Mensagem", - "modeLabel": "Modo de reset", - "confirmButton": "Resetar", - "modes": { - "soft": { - "label": "--soft", - "description": "Move o HEAD e o ponteiro da branch atual para o commit alvo.\nMantém Index e Working Tree sem alterações.\nAs mudanças dos commits removidos permanecem staged." - }, - "mixed": { - "label": "--mixed (padrão)", - "description": "Move o HEAD para o commit alvo.\nReseta o Index para o commit alvo e mantém as mudanças no Working Tree.\nAs mudanças passam de staged para unstaged." - }, - "hard": { - "label": "--hard", - "description": "Move o HEAD e reseta tanto Index quanto Working Tree para o commit alvo.\nAs mudanças locais rastreadas após o commit alvo são descartadas.\nEsta é uma operação destrutiva." - }, - "keep": { - "label": "--keep", - "description": "Move o HEAD para o commit alvo e tenta preservar alterações locais.\nSomente alterações sem conflito são mantidas.\nSe houver conflito, o reset é abortado para proteger seu trabalho." - } - } - } - }, - "moreActions": "Mais ações do Git" - }, - "gitChangesTab": { - "workspace": "espaço de trabalho", - "noChanges": "Sem alterações locais", - "notAGitRepoTitle": "Não é um repositório Git", - "notAGitRepoHint": "Inicialize o Git pelo menu de ramificações acima, ou abra um repositório existente.", - "trackedChanges": "Alterações rastreadas ({count})", - "untrackedFiles": "Arquivos não rastreados ({count})", - "expandTracked": "Expandir alterações rastreadas", - "collapseTracked": "Recolher alterações rastreadas", - "expandUntracked": "Expandir arquivos não rastreados", - "collapseUntracked": "Recolher arquivos não rastreados", - "showRemainingItems": "Mostrar mais {count} itens", - "actions": { - "commitCode": "Commit do código", - "rollback": "Reverter", - "addToVcs": "Adicionar ao VCS", - "delete": "Excluir", - "moreActions": "Mais ações do Git", - "addAllToVcs": "Adicionar tudo ao VCS", - "rollbackAll": "Reverter tudo", - "refresh": "Atualizar" - }, - "toasts": { - "noAddableFilesInDir": "Nenhum arquivo alterado neste diretório pode ser adicionado ao VCS", - "noRollbackFilesInDir": "Nenhum arquivo alterado neste diretório pode ser revertido", - "addedToVcs": "{name} adicionado ao VCS", - "addToVcsFailed": "Falha ao adicionar ao VCS", - "openCommitWindowFailed": "Falha ao abrir a janela de commit", - "rolledBack": "{name} revertido", - "rollbackFailed": "Falha no rollback", - "addedFilesToVcs": "{count, plural, one {# arquivo} other {# arquivos}} adicionados ao VCS", - "rolledBackFiles": "{count, plural, one {# arquivo revertido} other {# arquivos revertidos}}", - "deleted": "{name} excluído", - "deleteFailed": "Falha ao excluir", - "deletedFiles": "{count} arquivos excluídos", - "noDeletableFilesInDir": "Nenhum arquivo alterado neste diretório pode ser excluído", - "commitFailed": "Falha ao confirmar" - }, - "directoryDialog": { - "descriptionAdd": "Selecione arquivos sob o diretório {path} para adicionar ao VCS.", - "descriptionRollback": "Selecione arquivos sob o diretório {path} para reverter.", - "descriptionDelete": "Selecione arquivos no diretório {path} para excluir. Esta ação não pode ser desfeita.", - "descriptionFallback": "Selecione arquivos para prosseguir.", - "selectionCount": "Selecionados {selected} / {total} arquivos", - "selectAll": "Selecionar todos", - "unselectAll": "Desmarcar todos", - "loadingCandidates": "Carregando alterações do diretório...", - "noOperableFiles": "Nenhum arquivo operável" - }, - "rollbackConfirm": { - "title": "Confirmar rollback", - "descriptionWithTarget": "Reverter alterações locais de {kind} \"{name}\"?", - "descriptionFallback": "Reverter alterações locais?", - "kindDirectory": "diretório", - "kindFile": "arquivo" - }, - "deleteConfirm": { - "title": "Confirmar exclusão", - "descriptionWithTarget": "Excluir {kind} \"{name}\"? Esta ação não pode ser desfeita.", - "descriptionFallback": "Esta ação não pode ser desfeita.", - "kindDirectory": "diretório", - "kindFile": "arquivo" - }, - "quickCommit": { - "placeholder": "Mensagem do commit (Enter para confirmar)" - } - }, - "tabContext": { - "loadingConversation": "Carregando...", - "untitledConversation": "Conversa sem título", - "newConversation": "Nova conversa" - }, - "fileTreeTab": { - "workspace": "Espaço de trabalho", - "retry": "Tentar novamente", - "git": "Git", - "openInFileManager": "Abrir no gerenciador de arquivos", - "openInFinder": "Abrir no Finder", - "openInExplorer": "Abrir no Explorer", - "attachToCurrentSession": "Adicionar à sessão", - "compareWithBranch": "Comparar com branch...", - "reloadFromDisk": "Recarregar do disco", - "new": "Novo", - "newFile": "Arquivo", - "newDirectory": "Diretório", - "openIn": "Abrir em", - "openInTerminal": "Abrir no terminal", - "linkedFolder": "Pasta vinculada", - "copyPath": "Copiar caminho", - "upload": "Enviar arquivos/pasta", - "download": "Baixar arquivo", - "downloadAsZip": "Baixar como ZIP", - "actions": { - "select": "Selecionar", - "unselect": "Desmarcar", - "commitCode": "Fazer commit do código", - "rollback": "Reverter", - "addToVcs": "Adicionar ao VCS" - }, - "aria": { - "selectPath": "{action}: {path}" - }, - "toasts": { - "openDirectoryFailed": "Falha ao abrir diretório", - "openBuiltinTerminalFailed": "Não foi possível abrir o terminal embutido", - "openCommitWindowFailed": "Falha ao abrir janela de commit", - "noAddableFilesInDir": "Nenhum arquivo alterado neste diretório pode ser adicionado ao VCS", - "noRollbackFilesInDir": "Nenhum arquivo alterado neste diretório pode ser revertido", - "addedToVcs": "{name} adicionado ao VCS", - "addToVcsFailed": "Falha ao adicionar ao VCS", - "loadBranchesFailed": "Falha ao carregar branches", - "renameFailed": "Falha ao renomear", - "moveFailed": "Falha ao mover", - "deleteFailed": "Falha ao excluir", - "rolledBack": "{name} revertido", - "rollbackFailed": "Falha ao reverter", - "addedFilesToVcs": "{count, plural, one {# arquivo adicionado ao VCS} other {# arquivos adicionados ao VCS}}", - "rolledBackFiles": "{count, plural, one {# arquivo revertido} other {# arquivos revertidos}}", - "savedAsCopy": "Salvo como cópia", - "saveCopyFailed": "Falha ao salvar como cópia", - "watchStartFailed": "Falha ao iniciar monitoramento de arquivos", - "createFailed": "Falha ao criar", - "downloadFailed": "Falha ao baixar {name}", - "downloadSaved": "{name} baixado", - "pathCopied": "Caminho copiado", - "copyPathFailed": "Falha ao copiar o caminho" - }, - "createDialog": { - "newFile": "Novo arquivo", - "newDirectory": "Novo diretório", - "description": "Digite um nome para o novo {kind}.", - "placeholderFile": "file-name.ext", - "placeholderDirectory": "folder-name" - }, - "renameDialog": { - "renameDirectory": "Renomear diretório", - "renameFile": "Renomear arquivo", - "description": "Digite um novo nome (apenas nome, sem caminho).", - "placeholderDirectory": "novo-nome-da-pasta", - "placeholderFile": "novo-nome-do-arquivo.ext" - }, - "uploadDialog": { - "title": "Enviar para o workspace", - "description": "Ajuste o destino se necessário e adicione arquivos ou pastas.", - "workspaceRoot": "raiz do workspace", - "targetPathLabel": "Enviar para", - "targetPathHint": "Caminho resolvido: {path}", - "dropHint": "Arraste arquivos ou pastas aqui, ou use os botões abaixo", - "dropHintActive": "Solte para adicionar à fila", - "selectFiles": "Selecionar arquivos", - "selectFolder": "Selecionar pasta", - "startUpload": "Iniciar upload", - "clearQueue": "Limpar finalizados", - "removeItem": "Remover da fila", - "retry": "Tentar novamente", - "dropZoneAria": "Solte arquivos aqui ou ative para procurar", - "folderEmpty": "Nenhum arquivo encontrado na pasta solta", - "summary": "Total: {total} · Sucesso: {succeeded} · Falhas: {failed}", - "status": { - "pending": "Aguardando", - "uploading": "Enviando", - "success": "Concluído", - "error": "Falhou", - "cancelled": "Cancelado" - } - }, - "directoryDialog": { - "descriptionAdd": "Selecione arquivos no diretório {path} para adicionar ao VCS.", - "descriptionRollback": "Selecione arquivos no diretório {path} para reverter.", - "descriptionFallback": "Selecione arquivos para continuar.", - "selectionCount": "{selected} / {total} arquivos selecionados", - "selectAll": "Selecionar tudo", - "unselectAll": "Desmarcar tudo", - "loadingCandidates": "Carregando alterações do diretório...", - "noOperableFiles": "Nenhum arquivo operável" - }, - "compareDialog": { - "title": "Comparar com branch", - "descriptionWithTarget": "Selecione uma branch e compare com {kind} {path}", - "descriptionFallback": "Selecione uma branch para comparar.", - "kindDirectory": "diretório", - "kindFile": "arquivo", - "filterPlaceholder": "Filtre branches, ex.: main / origin/main", - "singleClickHint": "Clique em uma branch para comparar diretamente", - "loadingBranches": "Carregando branches...", - "recentBranches": "Branches recentes ({count})", - "noCurrentBranch": "Sem branch atual", - "localBranches": "Branches locais ({count})", - "remoteBranches": "Branches remotas ({count})", - "noMatchingBranches": "Nenhuma branch correspondente" - }, - "externalConflictDialog": { - "title": "Alterações externas de arquivo detectadas", - "descriptionWithPath": "O arquivo {path} foi alterado no disco e as edições atuais não foram salvas.", - "descriptionFallback": "O arquivo atual foi alterado no disco e as edições atuais não foram salvas.", - "compare": "Comparar", - "savingCopy": "Salvando cópia...", - "saveAsCopy": "Salvar como cópia", - "reload": "Recarregar" - }, - "deleteConfirm": { - "title": "Confirmar exclusão", - "descriptionWithTarget": "Excluir {kind} \"{name}\"? Esta ação não pode ser desfeita.", - "descriptionFallback": "Esta ação não pode ser desfeita.", - "kindDirectory": "diretório", - "kindFile": "arquivo" - }, - "rollbackConfirm": { - "title": "Confirmar reversão", - "descriptionWithTarget": "Reverter alterações locais do arquivo \"{name}\"?", - "descriptionFallback": "Reverter alterações locais deste arquivo?" - }, - "terminalTitle": "Console · {name}" - }, - "commandDropdown": { - "loading": "Carregando...", - "addCommand": "Adicionar comando", - "manageCommands": "Gerenciar comandos...", - "runCommandTitle": "Executar: {command}", - "stopCommandTitle": "Parar: {command}", - "manageDialog": { - "title": "Gerenciar comandos", - "empty": "Ainda não há comandos", - "noResults": "Nenhum comando correspondente", - "searchPlaceholder": "Pesquisar comandos", - "newCommand": "Novo comando", - "nameLabel": "Nome", - "commandLabel": "Comando", - "dragSort": "Arraste para ordenar", - "dragSortCommand": "Arraste para ordenar {name}", - "orderFailed": "Falha ao salvar a ordem dos comandos", - "loadFailed": "Falha ao carregar os comandos", - "saveFailed": "Falha ao salvar o comando", - "deleteFailed": "Falha ao excluir o comando", - "confirmDelete": { - "title": "Excluir comando?", - "message": "Isso removerá \"{name}\". Esta ação não pode ser desfeita." - } - } - }, - "workspaceContext": { - "confirmCloseDirtyTab": "Fechar \"{title}\" sem salvar?", - "confirmCloseOtherDirtyTabs": "Fechar outras abas com alterações não salvas?", - "confirmCloseAllDirtyTabs": "Fechar todas as abas com alterações não salvas?", - "unableLoadContent": "Não foi possível carregar o conteúdo.\n\n{message}", - "previewRequestTimedOut": "A solicitação de preview expirou", - "diffRequestTimedOut": "A solicitação de Diff expirou", - "branchCompareRequestTimedOut": "A solicitação de comparação de branch expirou", - "commitDiffRequestTimedOut": "A solicitação de Diff de commit expirou", - "saveRequestTimedOut": "A solicitação de salvamento expirou", - "reloadRequestTimedOut": "A solicitação de recarga expirou", - "noChanges": "Sem alterações.", - "noDiffOutput": "Sem saída de diff.", - "diffTitleWorkspace": "Diff · Espaço de trabalho", - "diffDescriptionWorkingTree": "Árvore de trabalho (HEAD)", - "diffTitleFile": "Diferença · {name}", - "compareTitleFile": "Comparar · {name}", - "compareTitleBranch": "Comparar · {branch}", - "compareDescriptionPath": "{path} · comparar com {branch}", - "compareDescriptionBranch": "comparar com {branch}", - "diffTitleCommitFile": "Diferença · {name} @ {hash}", - "diffTitleCommit": "Diferença · {hash}", - "diffDescriptionCommitPath": "{path} · confirmação {commit}", - "diffDescriptionCommit": "confirmação {commit}", - "diffTitleConflictFile": "Conflito · {name}", - "diffDescriptionConflict": "{path} · disco vs não salvo" - }, - "chat": { - "acpConnections": { - "actions": { - "openAgentsSettings": "Abrir configurações de agentes", - "retry": "Tentar novamente" - }, - "agentsSetupHint": "Abra Configurações > Agentes para gerenciar a instalação.", - "withSetupHint": "{message}\n{hint}", - "blocked": { - "missingConfig": "Não foi possível ler a configuração atual do agente.", - "disabled": "{agent} está desativado nas configurações de agentes. Ative-o antes de conectar.", - "unavailable": "{agent} está indisponível na plataforma atual.", - "sdkMissing": "O SDK de {agent} não está instalado", - "adapterMissing": "O adaptador ACP de {agent} não está instalado" - }, - "backendErrors": { - "initializeTimeout": "O handshake de conexão de {agent} expirou (sem resposta após 60 segundos). Abra Configurações para verificar a configuração do agente e da rede.", - "mcpRejectedByAgent": "{agent} recusou a sessão com o companheiro MCP do codeg anexado: {message} Se este agente não suporta MCP, desative “Suporte a MCP” nas Configurações e conecte novamente.", - "processExited": "O processo de {agent} encerrou inesperadamente.", - "spawnFailed": "Falha ao iniciar {agent}: {message}", - "downloadFailed": "Falha no download de {agent}: {message}", - "sessionLoadResourceNotFound": "Falha ao carregar a sessão de {agent}. Recarregue para tentar novamente ou inicie uma nova conversa.", - "sessionLoadUnavailable": "{agent} não conseguiu restaurar esta sessão; ela pode ter terminado ou o agente parou. Recarregue para tentar novamente ou inicie uma nova conversa.", - "turnFailedRefusal": "{agent} recusou continuar este turno. Costuma indicar um erro de backend ou gateway. Confira os logs do agente.", - "turnFailedMaxTokens": "{agent} atingiu o limite máximo de tokens para este turno.", - "turnFailedMaxTurnRequests": "{agent} atingiu o número máximo de solicitações permitidas para este turno.", - "turnFailedUnknown": "{agent} encerrou o turno com um motivo de parada desconhecido.", - "grokModelSwitchIncompatibleAgent": "{agent} não pode mudar para esse modelo em uma conversa existente. Inicie uma nova sessão para usá-lo.", - "turnFailedEmpty": "{agent} encerrou o turno sem produzir nenhuma resposta.", - "turnFailedEmptyProtocol": "{agent} produziu uma saída que o codeg não conseguiu analisar — a versão do agente pode não corresponder ao protocolo.", - "turnFailedEmptyMetadata": "{agent} enviou apenas atualizações de status neste turno (plano / modo / uso) e nenhuma resposta.", - "detailsInAlerts": "Abra os alertas na barra de status e expanda os detalhes para ver a saída do agente." - }, - "unableReadAgentConfig": "Não foi possível ler a configuração do agente: {message}", - "connectFailedTitle": "Falha na conexão de {agent}", - "toolFallbackTitle": "Ferramenta", - "eventErrorTitle": "Erro do agente", - "notificationTurnComplete": "{agent} terminou de responder", - "notificationError": "{agent} erro: {message}", - "claudeApiRetry": { - "fallbackError": "authentication_failed", - "retryingWithMax": "tentando novamente {attempt}/{max}", - "retryingAttempt": "tentando novamente tentativa {attempt}", - "retrying": "tentando novamente", - "nextRetryIn": "próxima em {seconds}s", - "line": "{error}{status} · {retry}", - "lineWithDelay": "{error}{status} · {retry}, {delay}", - "httpStatus": " (HTTP {status})" - }, - "configOptionAdjusted": "O {agent} definiu {option} como {actual} em vez de {requested}" - }, - "connectionLifecycle": { - "tasks": { - "connectingTitle": "Conectando a {agent}", - "connectingDescription": "Estabelecendo conexão", - "loadingSelectorsTitle": "Carregando seletores de {agent}", - "loadingSelectorsDescription": "Buscando opções de modo e configuração de sessão", - "initSessionTitle": "Initializing {agent} session", - "initSessionDescription": "Creating session and loading configuration" - }, - "errors": { - "connectionFailed": "Falha na conexão", - "sendPromptFailed": "Falha ao enviar a mensagem: {error}" - } - }, - "shared": { - "attachedResources": "Recursos anexados", - "toolCallFailed": "Falha na chamada da ferramenta" - }, - "messageThread": { - "emptyTitle": "Ainda não há mensagens", - "emptyDescription": "Inicie uma conversa para ver mensagens aqui" - }, - "chatInput": { - "connecting": "Conectando...", - "agentResponding": "{agent} está respondendo...", - "sendMessage": "Envie uma mensagem..." - }, - "messageInput": { - "askAnything": "Pergunte qualquer coisa...", - "removeAttachmentAria": "Remover {name}", - "attachFiles": "Anexar arquivos", - "addActions": "Adicionar", - "quickMessages": "Mensagens rápidas", - "quickMessagesEmpty": "Ainda não há mensagens rápidas", - "quickMessagesLoading": "Carregando...", - "pasteAsPlainText": "Colar como texto simples", - "cut": "Cortar", - "copy": "Copiar", - "selectAll": "Selecionar tudo", - "pasteUnavailable": "Não foi possível ler a área de transferência. Use Ctrl/⌘V para colar.", - "clipboardWriteFailed": "Não foi possível escrever na área de transferência. Use o atalho de teclado.", - "quickMessageUntitled": "Sem título", - "liveFeedback": "Feedback ao vivo", - "liveFeedbackDisabledHint": "Disponível enquanto o agente trabalha", - "dropFilesToAttach": "Solte arquivos para anexar", - "loadingSettings": "Carregando configurações...", - "loadingMode": "Carregando modo...", - "modeLabel": "Modo", - "toggleOn": "Ligado", - "toggleOff": "Desligado", - "agentSettings": "Configurações do agente", - "searchModel": "Buscar modelos...", - "searchModelAria": "Buscar modelos", - "modelListLabel": "Modelos", - "noModels": "Nenhum modelo encontrado", - "cancel": "Cancelar", - "send": "Enviar", - "forkAndSend": "Fork & Enviar", - "queueMessage": "Adicionar à fila", - "steerIntoTurn": "Inserir no turno atual", - "steerQueuedInstead": "Adicionado à fila — será enviado no próximo turno.", - "steerFailed": "Não foi possível inserir no turno atual", - "steerAttachmentsUnsupported": "Somente texto — rascunhos com anexos vão pela fila.", - "slashCommands": "Comandos de barra", - "slashSearchPlaceholder": "Buscar comandos...", - "slashSearchEmpty": "Nenhum comando correspondente", - "experts": "Especialistas", - "office": "Escritório", - "research": "Pesquisa", - "attachLocalUpload": "Carregar arquivo local", - "attachServerFile": "Selecionar arquivo do servidor", - "attachUploadTooLarge": "{names} excede o limite de upload de {limit}MB e foi ignorado.", - "attachUploadFailed": "Falha ao enviar {names}.", - "attachUploadNotAFile": "{names} não é um arquivo regular (diretório ou arquivo especial) e foi ignorado.", - "attachUploadQuotaExceeded": "O servidor ficou sem espaço para uploads; {names} não pôde ser enviado.", - "attachUploadInProgress": "As imagens ainda estão sendo enviadas — tente novamente em instantes.", - "mentionEmpty": "Nenhuma correspondência", - "mentionLoading": "Pesquisando…", - "mentionListLabel": "Menções", - "mentionMore": "Mais resultados — continue digitando para filtrar", - "mentionCount": "{count, plural, one {# resultado} other {# resultados}}", - "mentionGroupFile": "Arquivos", - "mentionGroupAgent": "Agentes", - "mentionGroupSession": "Sessões", - "mentionGroupCommit": "Commits", - "mentionGroupSkill": "Habilidades" - }, - "messageQueue": { - "addToQueue": "Adicionar à fila", - "saveEdit": "Salvar", - "cancelEdit": "Cancelar edição", - "editItem": "Editar", - "deleteItem": "Remover" - }, - "welcomeInputPanel": { - "agentsSettingsPath": "Configurações > Agentes", - "autoConnectFallback": "Clique para abrir {path} e gerenciar a instalação.", - "autoConnectAppend": "{message}. Clique para abrir {path} e gerenciar a instalação.", - "enableAgentFirstPlaceholder": "Ative pelo menos um agente antes de iniciar uma sessão...", - "prepareSessionFailed": "Não foi possível preparar a sessão de chat. Tente novamente.", - "createConversationFailed": "Não foi possível criar a conversa. Tente novamente.", - "askAnythingPlaceholder": "Pergunte qualquer coisa...", - "agentNotInstalled": "{agent} não está instalado · abra as configurações de Agents para instalá-lo", - "agentAdapterNotInstalled": "O adaptador ACP de {agent} não está instalado (separado da sua própria CLI) · abra as configurações de Agents para instalá-lo" - }, - "welcomePanel": { - "greeting": "O que você gostaria de fazer hoje?", - "tips": { - "tileTabs": "Clique com o botão direito em uma aba de conversa e escolha Exibir em mosaico para ver várias sessões lado a lado.", - "pinTab": "Clique duas vezes em uma aba de conversa para fixá-la, evitando que uma nova sessão a substitua automaticamente.", - "shortcutsNewSearch": "{newConversation} abre uma nova conversa, {searchConversations} pesquisa no histórico.", - "slashAtMention": "Digite / na entrada para acionar comandos slash, ou @ para referenciar um arquivo do projeto.", - "pasteDropFiles": "Cole uma captura de tela ou arraste um arquivo direto para a entrada para anexá-lo.", - "queueMessage": "Enquanto o agente responde, continue digitando — sua próxima mensagem entra na fila e é enviada automaticamente ao terminar.", - "draftAutoSave": "Rascunhos não enviados são salvos automaticamente por conversa e restaurados quando você volta.", - "forkSend": "O menu suspenso do botão de enviar tem Bifurcar e enviar — ramifique do ponto atual para uma nova aba.", - "exportConversation": "Clique com o botão direito dentro da conversa para exportá-la como Markdown, HTML ou imagem.", - "chatChannels": "Conecte Telegram / Lark / WeChat em Configurações → Canais de chat para continuar pelo celular.", - "shortcutsAuxPanel": "{toggleAuxPanel} alterna o painel direito para ver os arquivos tocados e as mudanças do Git desta sessão.", - "shortcutsTerminalSidebar": "{toggleTerminal} abre o terminal integrado, {toggleSidebar} alterna a barra lateral.", - "customShortcuts": "Todos os atalhos podem ser reatribuídos em Configurações → Atalhos.", - "webService": "Ative Configurações → Serviço web para que sua equipe acesse o mesmo codeg pelo navegador.", - "fusionMode": "Abra um arquivo ou diff para exibi-lo automaticamente ao lado da conversa.", - "quickMessages": "Abra o botão + ao lado da entrada e escolha Mensagens rápidas para inserir um trecho salvo (gerencie-os em Configurações → Mensagens rápidas).", - "experts": "O botão + tem um menu Habilidades de especialista — carregue papéis como Depuração ou Planejamento com um clique.", - "taskBoard": "As tarefas a fazer executam um trabalho do início ao fim: o agente trabalha no próprio worktree e você revisa o diff antes de mesclar.", - "automations": "As Automações executam um prompt salvo em uma agenda — uma revisão noturna, um relatório recorrente — e cada execução pode ter seu próprio worktree.", - "tokenUsage": "Clique no número de conversas na barra de status para abrir o Uso de tokens, detalhado por dia, agente, modelo e pasta.", - "mentionTargets": "@ não traz só arquivos: mencione outro agente para delegar uma subtarefa, ou referencie uma sessão anterior, um commit ou uma habilidade.", - "splitGroups": "Clique com o botão direito em uma aba e escolha Dividir à direita ou Dividir abaixo para manter duas conversas em painéis próprios.", - "worktrees": "Abra o botão de branch e escolha Novo worktree para vários agentes trabalharem no mesmo repositório sem sobrescrever os arquivos uns dos outros.", - "importSessions": "Já rodou sessões no terminal? O menu de uma pasta tem Importar sessões locais para trazer esse histórico para o codeg.", - "subSessions": "Quando um agente delega, a subsessão aparece aninhada abaixo dele na barra lateral — expanda a linha para acompanhar o que cada uma fez.", - "liveFeedback": "Feedback ao vivo, no menu +, insere uma nota no turno que o agente já está executando, sem interrompê-lo.", - "skillPacks": "Configurações → Pacotes de habilidades reúne especialistas de código, pesquisa científica e escritório; ative por agente.", - "modelProviders": "Configurações → Provedores de Modelos aceita sua própria chave de API ou endpoint, e o modelo você escolhe no campo de entrada.", - "workspaceBackground": "Configurações → Aparência define uma imagem de fundo do espaço de trabalho, a opacidade dos painéis e as fontes do app." - }, - "quickActions": { - "excel": "Pasta do Excel", - "excelDesc": "Tabelas, fórmulas e gráficos", - "word": "Documento do Word", - "wordDesc": "Relatórios, cartas e memorandos", - "ppt": "Apresentação", - "pptDesc": "Slides com design profissional", - "pitchDeck": "Pitch Deck", - "pitchDeckDesc": "Apresentação de captação com métricas", - "morph": "Animação Morph", - "morphDesc": "Transições de slide cinematográficas", - "morph3d": "Morph 3D", - "morph3dDesc": "Modelos 3D com movimentos de câmera", - "academic": "Artigo acadêmico", - "academicDesc": "Pesquisa com citações e estrutura", - "financial": "Modelo financeiro", - "financialDesc": "Demonstrações, DCF e projeções", - "dashboard": "Painel de dados", - "dashboardDesc": "KPIs e análises a partir dos seus dados", - "prompts": { - "excel": "Crie uma pasta do Excel com os seguintes requisitos:\n\n[descreva aqui seus dados, tabelas, fórmulas e gráficos]", - "word": "Crie um documento do Word com os seguintes requisitos:\n\n[descreva aqui o conteúdo, a estrutura e a formatação do documento]", - "ppt": "Crie uma apresentação do PowerPoint com os seguintes requisitos:\n\n[descreva aqui seus slides, conteúdo e design]", - "pitchDeck": "Crie um pitch deck de captação com os seguintes requisitos:\n\n[descreva aqui sua empresa, rodada de investimento e métricas-chave]", - "morph": "Crie uma apresentação com animações de transição Morph:\n\n[descreva aqui o tema da apresentação e os efeitos visuais desejados]", - "morph3d": "Crie uma apresentação Morph 3D com modelos GLB e movimentos de câmera:\n\n[descreva aqui seu tema e conceito visual em 3D]", - "academic": "Escreva um artigo acadêmico no Word com os seguintes requisitos:\n\n[descreva aqui seu tema de pesquisa, metodologia e principais resultados]", - "financial": "Crie um modelo financeiro no Excel com os seguintes requisitos:\n\n[descreva aqui suas demonstrações financeiras, projeções e análises]", - "dashboard": "Crie um painel de dados no Excel com os seguintes requisitos:\n\n[descreva aqui sua fonte de dados, KPIs e gráficos]", - "scientific-brainstorming": "Ajude-me a fazer um brainstorming de direções de pesquisa: explore conexões interdisciplinares, questione premissas e revele lacunas promissoras. A área que estou explorando: ", - "hypothesis-generation": "Ajude-me a transformar estas observações em hipóteses testáveis, com previsões claras, mecanismos plausíveis e experimentos. Minhas observações: ", - "experimental-design": "Ajude-me a planejar um experimento rigoroso antes de coletar dados: o delineamento, a aleatorização, os controles e como evitar confundimento. O que quero estudar: ", - "statistical-power": "Ajude-me a determinar o tamanho amostral necessário: conduza uma análise de poder (tamanho de efeito, alfa, poder) para o meu delineamento. Detalhes: ", - "statistical-analysis": "Ajude-me a analisar estes dados corretamente: escolha o teste certo, verifique os pressupostos, relate os tamanhos de efeito e redija. Meus dados e pergunta: ", - "exploratory-data-analysis": "Faça uma análise exploratória do meu arquivo de dados: resuma sua estrutura, qualidade e padrões notáveis e sugira os próximos passos. O arquivo é: ", - "scientific-visualization": "Ajude-me a criar uma figura com qualidade de publicação: layout claro, barras de erro honestas, uma paleta segura para daltônicos e formatação de periódico. O que quero mostrar: ", - "scientific-critical-thinking": "Ajude-me a avaliar criticamente este estudo ou alegação: avalie a qualidade da evidência, identifique vieses e confundidores e pondere as conclusões. Aqui está: ", - "paper-lookup": "Ajude-me a encontrar artigos relevantes e texto completo de acesso aberto em bases de dados acadêmicas, com citações reutilizáveis. Estou procurando: " - }, - "paper-lookup": "Busca de artigos", - "paper-lookupDesc": "Pesquise em 10 APIs acadêmicas (PubMed, arXiv, OpenAlex, Crossref…) artigos, citações e texto completo de acesso aberto.", - "scientific-critical-thinking": "Pensamento crítico", - "scientific-critical-thinkingDesc": "Avalie alegações científicas e a qualidade da evidência: identifique vieses e confundidores e aplique GRADE.", - "scientific-visualization": "Visualização científica", - "scientific-visualizationDesc": "Figuras prontas para publicação: layouts multipainel, anotações de significância e formatação específica de periódico.", - "exploratory-data-analysis": "Análise exploratória de dados", - "exploratory-data-analysisDesc": "Exploração automatizada de arquivos de dados científicos em mais de 200 formatos com métricas de qualidade e relatórios.", - "statistical-analysis": "Análise estatística", - "statistical-analysisDesc": "Análise estatística guiada: seleção de testes, verificação de pressupostos, tamanhos de efeito e relato no estilo APA.", - "statistical-power": "Poder estatístico", - "statistical-powerDesc": "Análise de tamanho amostral e poder: quantos sujeitos são necessários, efeitos mínimos detectáveis e curvas de poder.", - "experimental-design": "Delineamento experimental", - "experimental-designDesc": "Planeje estudos rigorosos antes de coletar dados: aleatorização, blocagem, controles e delineamentos fatoriais/DOE.", - "hypothesis-generation": "Geração de hipóteses", - "hypothesis-generationDesc": "Transforme observações em hipóteses testáveis com previsões, mecanismos e experimentos para testá-las.", - "scientific-brainstorming": "Brainstorming científico", - "scientific-brainstormingDesc": "Ideação aberta de pesquisa: explore conexões interdisciplinares, questione premissas e revele lacunas.", - "tabs": { - "office": "Escritório", - "coding": "Desenvolvimento", - "research": "Pesquisa" - }, - "coding": { - "brainstormingDesc": "Explore intenção e requisitos antes de construir", - "debuggingDesc": "Encontre a causa raiz antes de propor correções", - "writingSkillsDesc": "Crie, edite e verifique skills reutilizáveis" - }, - "notEnabled": { - "title": "A habilidade “{skill}” ainda não está ativada para {agent}", - "description": "Ative-a nas Configurações para usá-la aqui.", - "action": "Ativar", - "hint": "Habilidade não ativada" - }, - "scrollPrev": "Mostrar habilidades anteriores", - "scrollNext": "Mostrar mais habilidades" - } - }, - "agentSelector": { - "noEnabledAgents": "Nenhum agente habilitado", - "openAgentsSettings": "Abrir configurações de agentes", - "notInstalled": "Não instalado", - "moreAgents": "Mais agentes ({count})" - }, - "subAgentOverlay": { - "title": "Subagentes", - "collapsedSummary": "Subagentes {count}", - "collapseAria": "Recolher subagentes" - }, - "agentPlanOverlay": { - "title": "Plano do agente", - "collapsePlanAria": "Recolher plano", - "collapsedSummary": "Plano {completed}/{total}", - "status": { - "completed": "Concluído", - "inProgress": "Em andamento", - "pending": "Pendente", - "unknown": "Desconhecido" - }, - "priority": { - "high": "Alta", - "medium": "Média", - "low": "Baixa", - "unknown": "Desconhecida" - } - }, - "permissionDialog": { - "subtitle": "O agente solicita permissão para continuar este turno.", - "queuedCount": "+{count} aguardando", - "kindFallbackTool": "ferramenta", - "command": "Comando", - "cwd": "Diretório de trabalho: {cwd}", - "filesSummary": "Arquivos: {count}", - "moreFiles": "+{count} arquivos a mais", - "plan": "Plano", - "allowedActions": "Ações permitidas", - "targetMode": "Modo de destino: {mode}", - "optionGrants": "O que cada opção concede", - "changeScopeSession": "Esta sessão", - "changeScopeProcess": "Esta execução", - "changeScopeUser": "Salvo nas configurações do usuário", - "changeScopeProject": "Salvo nas configurações do projeto", - "changeScopeProjectLocal": "Salvo nas configurações locais do projeto", - "changeScopePersistent": "Salvo permanentemente" - }, - "questionDialog": { - "title": "O agente está fazendo uma pergunta", - "placeholder": "Digite sua resposta...", - "send": "Enviar" - }, - "messageBranch": { - "previousBranchAria": "Branch anterior", - "nextBranchAria": "Próxima branch", - "pageOf": "{current} de {total}" - }, - "terminal": { - "title": "Console", - "running": "Em execução" - }, - "reasoning": { - "thinking": "Pensando…", - "thoughtForFewSeconds": "Pensamento", - "thoughtForSeconds": "Pensamento" - }, - "linkSafety": { - "errorCannotOpen": "Não é possível abrir o arquivo local", - "errorNoWorkspace": "Nenhuma pasta de espaço de trabalho está ativa no momento.", - "errorFailedOpen": "Falha ao abrir o arquivo local", - "errorFailedLink": "Falha ao abrir o link", - "errorUnsupportedLinkProtocol": "Este protocolo de link não é compatível." - }, - "fileActions": { - "openInFinder": "Abrir no Finder", - "openInExplorer": "Abrir no Explorer", - "openInFileManager": "Abrir no gerenciador de arquivos", - "copyRelativePath": "Copiar caminho relativo", - "copyAbsolutePath": "Copiar caminho absoluto", - "pathCopied": "Caminho copiado", - "copyPathFailed": "Falha ao copiar o caminho", - "openFailed": "Falha ao abrir o arquivo local" - }, - "messageList": { - "attachedResources": "Recursos anexados", - "loading": "Carregando...", - "loadEarlier": "Carregar mensagens anteriores", - "loadingEarlier": "Carregando mensagens anteriores…", - "error": "Erro: {message}", - "errorTitle": "Falha ao carregar a sessão", - "errorActionReload": "Recarregar", - "errorActionNewSession": "Nova conversa", - "emptyConversation": "Nenhuma mensagem nesta conversa.", - "systemMessage": "Mensagem do sistema", - "copyMessage": "Copiar", - "copied": "Copiado", - "downloadImage": "Baixar imagem", - "downloadFailed": "Falha no download: {message}", - "imageGeneration": "Geração de imagem", - "imageGenerationPending": "Gerando imagem…", - "imageGenerationFailed": "Falha na geração da imagem", - "model": "Modelo", - "tokenStats": "Uso de tokens", - "tokenInput": "Entrada", - "tokenOutput": "Saída", - "tokenCacheRead": "Leitura de cache", - "tokenCacheWrite": "Escrita de cache", - "duration": "Duração", - "completedAt": "Concluído às", - "jumpToPreviousUserMessage": "Ir para a mensagem do usuário", - "showMore": "Mostrar mais", - "showLess": "Mostrar menos" - }, - "liveTurnStats": { - "thinking": "Pensando...", - "streaming": "Transmitindo", - "elapsedHours": "{value} h", - "elapsedMinutes": "{value} min", - "elapsedSeconds": "{value} s", - "outputSpeedAria": "Velocidade de saída estimada", - "outputSpeedTooltip": "Velocidade de saída estimada (texto + raciocínio)" - }, - "jsonTree": { - "viewRaw": "Ver JSON bruto", - "viewTree": "Ver árvore", - "fields": "{count, plural, one {# campo} other {# campos}}", - "items": "{count, plural, one {# item} other {# itens}}" - }, - "tool": { - "parameters": "Parâmetros", - "error": "Erro", - "result": "Resultado", - "status": { - "approvalRequested": "Aguardando aprovação", - "approvalResponded": "Respondido", - "inputAvailable": "Em execução", - "inputStreaming": "Pendente", - "outputAvailable": "Concluído", - "outputDenied": "Negado", - "outputError": "Erro" - } - }, - "toolCallBlock": { - "tool": "Ferramenta", - "error": "Erro", - "result": "Resultado" - }, - "delegation": { - "subAgentRunning": "Subagente em execução…", - "noDetail": "No detail available yet.", - "unknownAgent": "Subagente", - "openDetail": "Ver conversa", - "detailTitle": "Conversa do subagente", - "detailDescription": "Visualização somente leitura da conversa do subagente delegado.", - "waitForResult": "Aguardando o resultado da tarefa {task}", - "waitForResultNoTask": "Aguardando o resultado da tarefa", - "cancelTask": "Cancelando a tarefa {task}", - "cancelTaskNoTask": "Cancelando a tarefa", - "resultPageOf": "{current} / {total}", - "prevResult": "Resultado anterior", - "nextResult": "Próximo resultado", - "noResultText": "Sem resultado nesta verificação.", - "status": { - "starting": "iniciando", - "running": "em execução", - "checked": "verificado", - "waiting": "aguardando aprovação", - "ok": "concluído", - "err": { - "default": "falhou", - "delegation_disabled": "desativado", - "depth_limit": "limite de profundidade", - "invalid_agent_type": "agente inválido", - "spawn_failed": "falha ao iniciar", - "send_failed": "falha ao enviar", - "timeout": "tempo esgotado", - "canceled": "cancelado", - "child_refusal": "subagente recusou", - "child_max_tokens": "subagente: limite de tokens", - "child_max_turn_requests": "subagente: limite de solicitações", - "child_empty": "subagente sem saída", - "child_unknown": "subagente: erro", - "unknown": "tarefa desconhecida" - } - } - }, - "contentParts": { - "showingTailOutput": "Mostrando a saída final durante o streaming para melhor desempenho.", - "result": "Resultado", - "unknown": "desconhecido", - "inputTruncated": "A entrada foi truncada — o diff pode estar incompleto.", - "replaceAll": "SUBSTITUIR TUDO", - "filesCount": "Arquivos: {count}", - "update": "atualizar", - "moreFiles": "+{count} arquivos a mais", - "timeoutMs": "Tempo limite: {timeout}ms", - "backgroundTrue": "Segundo plano: true", - "scriptToolCalls": "{count, plural, one {# chamada de ferramenta} other {# chamadas de ferramenta}}", - "offset": "Deslocamento: {offset}", - "limit": "Limite: {limit}", - "pages": "Páginas: {pages}", - "mode": "Modo: {mode}", - "cell": "Célula: {cell}", - "shellSession": "Sessão {id}", - "pathLabel": "Caminho:", - "globLabel": "Padrão glob:", - "typeLabel": "Tipo:", - "outputLabel": "Saída:", - "caseInsensitive": "Sem diferenciar maiúsculas/minúsculas", - "multiline": "Multilinha", - "promptLabel": "Instrução", - "subjectLabel": "Assunto", - "taskLabel": "Tarefa", - "nameLabel": "Nome:", - "agentPromptLabel": "Instrução", - "agentModelLabel": "Modelo", - "agentRunning": "Em execução...", - "agentLiveTranscript": "Atividade ao vivo", - "agentProgressTools": "{count} chamadas de ferramentas", - "agentProgressTurns": "{count} turnos", - "agentProgressContext": "contexto {pct}%", - "agentSessionAction": "Ver a sessão do subagente", - "agentSessionTitle": "Sessão do subagente", - "agentSessionLoading": "Carregando a transcrição do subagente…", - "agentSessionEmpty": "O subagente ainda não escreveu nada.", - "agentFallbackTitle": "Iniciando subagente…", - "agentCodexLaunchOnly": "Iniciado. O Codex não informa mais o progresso deste subagente — o resultado chega como uma mensagem nesta conversa.", - "agentStatsBash": "Comandos", - "agentStatsRead": "Arquivos lidos", - "agentStatsSearch": "Pesquisas", - "agentStatsEdit": "Edições", - "agentStatsOther": "Outros", - "goal": { - "title": "Objetivo:", - "titleWithStatus": "Objetivo {status}", - "objective": "Objetivo", - "statusLabel": "Status", - "tokensUsed": "Tokens usados", - "budget": "Orçamento", - "remaining": "Restante", - "elapsed": "Decorrido", - "tokens": "tokens", - "pause": "Pausar", - "clear": "Limpar", - "status": { - "active": "ativo", - "paused": "pausado", - "blocked": "bloqueado", - "usageLimited": "uso limitado", - "budgetLimited": "orçamento limitado", - "complete": "concluído", - "limited": "limite atingido" - } - }, - "field": { - "file": "Arquivo", - "notebook": "Caderno", - "command": "Comando", - "old": "Antigo", - "new": "Novo", - "pattern": "Padrão", - "path": "Caminho", - "query": "Consulta", - "url": "URL:", - "description": "Descrição", - "content": "Conteúdo", - "source": "Fonte", - "prompt": "Instrução", - "subject": "Assunto", - "taskId": "ID da tarefa", - "status": "Situação", - "skill": "Skill", - "args": "Argumentos", - "offset": "Deslocamento", - "limit": "Limite", - "glob": "Padrão glob", - "type": "Tipo", - "output": "Saída", - "replaceAll": "Substituir tudo", - "language": "Idioma", - "timeout": "Tempo limite", - "background": "Segundo plano", - "agentType": "Tipo de agente", - "library": "Biblioteca", - "libraryId": "ID da biblioteca" - }, - "title": { - "edit": "Editar", - "command": "Comando", - "script": "Script", - "waitCommand": "Aguardar {command}", - "waitCell": "Aguardar sessão {id}", - "terminateCommand": "Encerrar {command}", - "terminateCell": "Encerrar sessão {id}", - "stdinChars": "Entrada {chars}", - "todoWrite": "TodoWrite (atualização de tarefas)", - "read": "Ler", - "write": "Escrever", - "notebookEdit": "NotebookEdit (edição de caderno)", - "editFiles": "Editar ({count} arquivos)", - "editWithTarget": "Editar {target}", - "readWithTarget": "Ler {target}", - "writeWithTarget": "Escrever {target}", - "notebookEditWithTarget": "NotebookEdit ({target})", - "globWithPattern": "Padrão glob {pattern}", - "listFilesWithPath": "Listar arquivos {path}", - "grepWithPattern": "Padrão grep {pattern}", - "taskCreateWithSubject": "Criar tarefa: {subject}", - "taskUpdateWithStatus": "Atualizar tarefa #{id} -> {status}", - "taskUpdate": "Atualizar tarefa #{id}", - "webFetchWithUrl": "WebFetch ({url})", - "webSearchWithQuery": "Pesquisa web: {query}", - "todosProgress": "Tarefas ({done}/{total})", - "skillWithName": "Skill: {name}", - "genericWithContext": "{tool} ({context})" - }, - "search": { - "noMatches": "Nenhuma correspondência", - "matchSummary": "{matches, plural, one {# correspondência} other {# correspondências}} em {files, plural, one {# arquivo} other {# arquivos}}", - "fileSummary": "{files, plural, one {# arquivo} other {# arquivos}}", - "moreResults": "{count, plural, one {# resultado adicional não exibido} other {# resultados adicionais não exibidos}}" - }, - "toolGroup": { - "search": "{count, plural, one {Explorou # busca} other {Explorou # buscas}}", - "command": "{count, plural, one {Executou # comando} other {Executou # comandos}}", - "read": "{count, plural, one {Leu arquivos # vez} other {Leu arquivos # vezes}}", - "memory": "{count, plural, one {Recordou # memória} other {Recordou # memórias}}", - "edit": "{count, plural, one {Editou arquivos # vez} other {Editou arquivos # vezes}}", - "fetch": "{count, plural, one {Buscou # recurso} other {Buscou # recursos}}", - "think": "{count, plural, one {Pensou # vez} other {Pensou # vezes}}", - "todo": "{count, plural, one {Atualizou # tarefa} other {Atualizou # tarefas}}", - "task": "{count, plural, one {Executou # tarefa} other {Executou # tarefas}}", - "other": "{count, plural, one {Usou # ferramenta} other {Usou # ferramentas}}", - "errorSuffix": "{count, plural, one {# falhou} other {# falharam}}", - "joiner": " · " - }, - "planMode": { - "entered": "Modo de planejamento iniciado", - "planLabel": "Plano", - "reviewApproved": "Plano aprovado — implementando", - "reviewKept": "Mantido no modo de plano", - "reviewPending": "Aguardando decisão sobre o plano", - "submitted": "Plano enviado", - "switched": "Modo alterado" - }, - "backgroundTask": { - "title": "Tarefa em segundo plano", - "titleWithId": "Tarefa em segundo plano · {id}", - "running": "Em execução", - "completed": "Concluída", - "failed": "Falhou", - "stopped": "Interrompida", - "exitCode": "saída {code}", - "polledTimes": "Consultada {count} vezes", - "runningInBackground": "Segundo plano", - "launchNote": "Em execução em segundo plano · {id}" - }, - "codexScript": { - "outputMissing": "O codex truncou a saída do script e removeu o separador deste comando, então nenhuma saída pôde ser atribuída a ele.", - "sharedWith": "Também contém a saída de {commands} — o codex truncou os separadores delas.", - "truncated": "truncado" - } - }, - "messageNav": { - "title": "Navegação de mensagens", - "collapse": "Recolher navegação de mensagens", - "collapsedSummary": "Mensagens {count}", - "fileCount": "{count, plural, one {# arquivo} other {# arquivos}}", - "remove": "Remover", - "noDiffDataAvailable": "Nenhum dado de diff disponível para {filePath}" - }, - "replyArtifacts": { - "title": "Arquivos alterados", - "fileCount": "{count, plural, one {# arquivo} other {# arquivos}}", - "newFilesTitle": "Novos arquivos", - "revealInFolder": "Mostrar no gerenciador de arquivos", - "openFile": "Abrir {filePath}", - "openInEditor": "Abrir no editor", - "remove": "Remover", - "noDiffDataAvailable": "Nenhum dado de diff disponível para {filePath}" - }, - "askQuestion": { - "title": "O agente precisa da sua escolha", - "subtitle": "Responda e envie. Você pode pular a qualquer momento.", - "recommended": "Recomendado", - "other": "Outro", - "otherPlaceholder": "Digite sua resposta…", - "singleSelect": "Única", - "multiSelect": "Múltipla", - "skip": "Pular", - "next": "Próxima", - "submit": "Enviar", - "submitError": "Falha ao enviar. Tente novamente." - }, - "planApproval": { - "title": "O agente tem um plano — revise", - "emptyPlan": "O agente não escreveu um plano. Aprove para começar ou solicite alterações.", - "approve": "Aprovar e construir", - "requestChanges": "Solicitar alterações", - "abandon": "Descartar", - "feedbackPlaceholder": "O que deve mudar?", - "sendChanges": "Enviar", - "cancel": "Cancelar", - "submitError": "Não foi possível enviar. Tente novamente." - }, - "feedbackCheckResult": { - "count": "{count, plural, =1 {1 comentário} other {# comentários}}", - "expand": "Mostrar todos os comentários", - "collapse": "Recolher", - "errorTitle": "Falha ao verificar comentários" - }, - "askQuestionResult": { - "title": "Pergunta", - "answeredLabel": "Pergunta e resposta:", - "awaiting": "Aguardando sua resposta…", - "declined": "Você ignorou isto — o agente usou o próprio julgamento.", - "noSelection": "Sem seleção" - }, - "configStale": { - "agentConfigTitle": "Configurações do agente atualizadas", - "modelProviderTitle": "Provedor de modelo atualizado", - "description": "Esta sessão ainda está usando a configuração anterior. Reconecte para aplicar (o histórico da conversa é mantido).", - "reconnect": "Reconectar para aplicar", - "reconnecting": "Reconectando…", - "reconnectDisabledDuringTurn": "Disponível quando o turno atual terminar", - "dismiss": "Dispensar", - "reconnectFailed": "Falha ao reconectar a sessão", - "applied": "Nova configuração aplicada" - }, - "piProjectTrust": { - "title": "Este projeto inclui recursos do pi", - "description": "O pi não está carregando os arquivos .pi do próprio repositório. Revise-os para decidir.", - "descriptionExecutable": "O repositório inclui extensões do pi, que executam código na inicialização. O pi não as está carregando. Revise antes de decidir.", - "review": "Revisar…", - "dismiss": "Dispensar", - "dialogTitle": "Confiar nos recursos do pi deste projeto?", - "dialogDescription": "O pi só carrega os arquivos .pi do próprio repositório se você confiar na pasta. Confie apenas se confiar no conteúdo deste repositório.", - "executionWarning": "Extensões são código. Ao confiar nesta pasta, o repositório poderá executá-las na inicialização do pi com suas permissões, antes de você enviar qualquer mensagem.", - "scopeNote": "A decisão é salva no trust.json do pi para esta pasta, vale para todas as pastas dentro dela e também é usada quando você executa o pi no terminal. Você pode alterá-la em Configurações → Agentes → Pi.", - "trust": "Confiar no projeto", - "decline": "Manter sem carregar", - "disabledDuringTurn": "Disponível quando o turno atual terminar", - "trustedToast": "Projeto confiável — reconectado para que o pi carregue seus recursos", - "declinedToast": "Os recursos do projeto continuam sem ser carregados", - "saveFailed": "Falha ao salvar a decisão de confiança do projeto", - "grantTitle": "Este projeto já é confiável", - "grantDescription": "O pi carrega os arquivos .pi do próprio repositório. Revise o que isso permite.", - "grantInheritedDescription": "Uma pasta superior é confiável, então o pi carrega os arquivos .pi do próprio repositório. Revise o que isso permite.", - "grantDialogTitle": "Os recursos do pi deste projeto são confiáveis", - "grantDialogDescription": "O pi tem permissão para carregar os arquivos .pi do próprio repositório. Versões anteriores do codeg concediam isso automaticamente ao abrir uma pasta, então talvez você nunca tenha sido perguntado.", - "grantExecutionWarning": "Extensões são código. O repositório as executa na inicialização do pi com suas permissões, antes de você enviar qualquer mensagem.", - "inheritedFrom": "Confiança herdada de", - "revoke": "Revogar confiança", - "keepTrusted": "Manter confiável", - "revokedToast": "Confiança revogada — reconectado para que o pi pare de carregar os recursos do projeto", - "trustedNoReconnect": "Projeto confiável — será aplicado na próxima inicialização do pi", - "revokedNoReconnect": "Confiança revogada — será aplicada na próxima inicialização do pi" - }, - "collabAgent": { - "title": "Subagente", - "errorTitle": "Falha na tarefa do subagente", - "statesLabel": "Subagentes", - "statusRunning": "Em execução", - "statusCompleted": "Concluído", - "statusFailed": "Falhou", - "statusPending": "Iniciando", - "statusInterrupted": "Interrompido", - "statusClosed": "Encerrado", - "statusNotFound": "Não encontrado", - "opSpawn": "Iniciando subagente", - "opWait": "Obtendo resultado do subagente", - "opClose": "Encerrando subagente", - "opResume": "Retomando subagente" - }, - "contextCompaction": { - "compacting": "Compactando o contexto…", - "compacted": "Contexto compactado", - "compactedTokens": "Contexto compactado · {before} → {after} tokens", - "failed": "Falha ao compactar o contexto" - }, - "sessionFailure": { - "category": { - "connection": "Problema de conexão", - "access": "Problema de acesso", - "limit": "Limite atingido", - "request": "Solicitação rejeitada", - "service": "Problema do serviço", - "unknown": "Problema de sessão" - }, - "action": { - "retry": "Tentar novamente", - "login": "Entrar", - "newSession": "Nova sessão" - }, - "recovered": "Recuperado", - "retryUnavailable": "Nenhuma mensagem anterior para reenviar.", - "toggleDetails": "Alternar detalhes" - }, - "backgroundTasks": { - "running": "{count, plural, one {# tarefa em segundo plano em execução} other {# tarefas em segundo plano em execução}}", - "settling": "Sincronizando resultados em segundo plano…", - "settledFallback": "Tarefa em segundo plano concluída ({status})", - "cardRunning": "Executando em segundo plano", - "cardLaunchedPending": "Tarefa iniciada em segundo plano", - "cardCompleted": "Tarefa em segundo plano concluída", - "cardFinishedWithStatus": "Tarefa em segundo plano encerrada ({status})", - "cardResultPending": "Resultado ainda não retornou" - }, - "proposedPlan": { - "title": "Plano proposto", - "planning": "A planear…" - } - }, - "diffPreview": { - "mode": { - "added": "Adicionado", - "deleted": "Excluído", - "renamed": "Renomeado", - "modified": "Modificado" - }, - "hunkLabel": "Bloco {index}", - "loadingHunk": "Carregando hunk...", - "noDiffData": "Sem dados de diff", - "showRemainingLines": "Mostrar mais {count} linhas" - }, - "conversationContextBar": { - "folderTitle": "Pasta de trabalho", - "branchTitle": "Branch de trabalho", - "searchFolder": "Search folder...", - "searchBranch": "Search branch...", - "noFolders": "No folders", - "noBranches": "No branches", - "noBranch": "(no branch)", - "chatModeLabel": "Modo de chat", - "commit": "Commit", - "push": "Push", - "merge": "Merge", - "toasts": { - "folderChanged": "Switched to {name}", - "openFolderFailed": "Failed to open folder", - "switchedToChatMode": "Alternado para o modo de chat", - "openStashFailed": "Failed to open stash window", - "openMergeFailed": "Failed to open merge window" - } - }, - "cloneDialog": { - "title": "Clonar repositório", - "repositoryUrl": "URL do repositório", - "repositoryUrlPlaceholder": "https://github.com/user/repo.git", - "directory": "Diretório", - "directoryPlaceholder": "Selecione o diretório de destino...", - "browseDirectory": "Procurar diretório", - "cancel": "Cancelar", - "clone": "Clonar", - "clonePath": "Caminho de clonagem: {path}" - }, - "toasts": { - "cloneFailed": "Falha ao clonar o repositório" - } - }, - "ProjectBoot": { - "title": "Inicializador de Projeto", - "tabs": { - "shadcn": "shadcn", - "hyperframes": "HyperFrames" - }, - "hyperframes": { - "title": "Projeto de vídeo HyperFrames", - "subtitle": "Crie um projeto de HTML para vídeo. O agente do espaço de trabalho pode então escrevê-lo e renderizá-lo.", - "resolution": "Resolução", - "skillsTitle": "Skills dos agentes", - "skillsDesc": "Instala globalmente as skills do HyperFrames (link simbólico) para os agentes selecionados, para que possam criar e renderizar vídeo.", - "recheck": "Verificar novamente", - "installedBadge": "Instalado", - "skillsInstall": "Instalar / atualizar skills", - "skillsInstalling": "Instalando skills…", - "skillsInstalled": "Skills do HyperFrames instaladas", - "skillsInstallFailed": "Não foi possível instalar as skills do HyperFrames" - }, - "config": { - "base": "Base", - "style": "Estilo", - "baseColor": "Cor base", - "theme": "Tema", - "chartColor": "Cor do gráfico", - "iconLibrary": "Biblioteca de ícones", - "font": "Fonte", - "fontHeading": "Fonte do título", - "menuAccent": "Destaque do menu", - "menuColor": "Cor do menu", - "radius": "Raio", - "template": "Modelo", - "createProject": "Criar projeto", - "sectionStyle": "Estilo", - "sectionColors": "Cores", - "sectionTypography": "Tipografia", - "sectionInterface": "Interface" - }, - "preview": { - "loading": "Carregando visualização..." - }, - "createDialog": { - "title": "Criar projeto", - "projectName": "Nome do projeto", - "projectNamePlaceholder": "my-app", - "frameworkTemplate": "Modelo de framework", - "packageManager": "Gerenciador de pacotes", - "saveDirectory": "Diretório de salvamento", - "saveDirectoryPlaceholder": "Selecionar diretório...", - "browseDirectory": "Procurar", - "projectPath": "O projeto será criado em: {path}", - "advancedOptions": "Opções Avançadas", - "base": "Biblioteca Base", - "enableRtl": "Ativar Suporte RTL", - "enableRtlDescription": "Ativar suporte de layout para idiomas da direita para a esquerda (ex.: árabe, hebraico)", - "pmChecking": "Verificando...", - "pmNotInstalled": "Não instalado", - "cancel": "Cancelar", - "create": "Criar", - "creating": "Criando projeto..." - }, - "toasts": { - "createFailed": "Falha ao criar o projeto", - "createSuccess": "Projeto criado com sucesso", - "openWorkspaceFailed": "Projeto criado, mas não foi possível abri-lo no espaço de trabalho" - }, - "errors": { - "directoryExists": "O diretório de destino já existe", - "commandFailed": "O comando de criação do projeto falhou." - } - }, - "WebServiceSettings": { - "addressSwitchHint": "Alternar muda apenas o endereço mostrado e aberto aqui; o serviço escuta em todas as interfaces e continua acessível em cada endereço.", - "sectionTitle": "Serviço Web", - "sectionDescription": "Ativar para acessar o Codeg remotamente pelo navegador", - "port": "Porta", - "status": "Status", - "autoStart": "Início automático", - "autoStartHint": "Iniciar o serviço Web ao abrir o Codeg", - "running": "Em execução", - "stopped": "Parado", - "processing": "Processando...", - "start": "Iniciar", - "stop": "Parar", - "startFailed": "Falha ao iniciar", - "stopFailed": "Falha ao parar", - "saveConfigFailed": "Falha ao salvar as configurações do serviço Web", - "open": "Abrir", - "hide": "Ocultar", - "show": "Mostrar", - "copy": "Copiar", - "qrcode": "Código QR", - "qrcodeTitle": "Escanear para abrir", - "qrcodeHint": "Escaneie com seu telefone para abrir o Codeg no navegador", - "addressLabel": "Endereço de acesso", - "tokenLabel": "Token de acesso", - "tokenHint": "Insira este token ao acessar o cliente Web pela primeira vez", - "tokenPlaceholder": "Deixe em branco para gerar automaticamente", - "regenerate": "Regenerar", - "stalePortOccupiedTitle": "A porta {port} está em uso por outro processo", - "stalePortUnknownTitle": "Estado da porta {port} é incerto", - "stalePortHint": "O Codeg não consegue vincular até a porta ser liberada. Altere a porta acima ou feche o processo que a retém.", - "errors": { - "alreadyRunning": "O serviço Web já está em execução", - "invalidAddress": "Formato de host ou porta inválido", - "portInUse": "A porta {port} já está em uso. Feche o processo que a utiliza ou escolha outra porta.", - "permissionDenied": "Permissão negada. Use uma porta acima de 1024 ou execute com privilégios mais altos.", - "addressUnavailable": "O endereço não está disponível nesta máquina", - "bindFailed": "Falha ao vincular o endereço" - } - }, - "DirectoryBrowser": { - "title": "Explorar diretório", - "pathPlaceholder": "Digite o caminho do diretório...", - "goHome": "Ir para o diretório inicial", - "navigateUp": "Ir para o diretório superior", - "select": "Selecionar", - "cancel": "Cancelar", - "loading": "Carregando...", - "emptyDirectory": "Este diretório está vazio", - "errorLoadingDir": "Falha ao carregar o diretório", - "permissionDenied": "Permissão negada" - }, - "ChatChannelSettings": { - "loading": "Carregando...", - "sectionTitle": "Canais de chat", - "sectionDescription": "Configure bots de IM para receber notificações de eventos e consultar atividade de codificação.", - "addChannel": "Adicionar canal", - "noChannels": "Nenhum canal de chat configurado ainda.", - "channelName": "Nome", - "channelNamePlaceholder": "Meu bot do Telegram", - "channelType": "Tipo de canal", - "lark": "Lark (Feishu)", - "weixin": "WeChat", - "dailyReport": "Relatório diário", - "dailyReportTime": "Horário do relatório", - "nameRequired": "O nome do canal é obrigatório.", - "tokenRequired": "O token é obrigatório.", - "chatIdRequired": "O Chat ID é obrigatório.", - "topicMode": "Modo de grupo por tópicos", - "topicModeHint": "Roteia tópicos de fórum do Telegram como sessões Codeg separadas. O bot deve estar em um supergrupo de fórum e poder gerenciar tópicos.", - "loadFailed": "Falha ao carregar os canais.", - "saveFailed": "Falha ao salvar as alterações.", - "connectSuccess": "Canal conectado.", - "connectFailed": "Falha na conexão", - "disconnectSuccess": "Canal desconectado.", - "disconnectFailed": "Falha ao desconectar.", - "testSuccess": "Teste de conexão aprovado.", - "testFailed": "Teste de conexão falhou", - "deleteSuccess": "Canal excluído.", - "deleteFailed": "Falha ao excluir o canal.", - "deleteConfirmTitle": "Excluir canal", - "deleteConfirmMessage": "O canal e seus registros de mensagens serão excluídos permanentemente. Tem certeza?", - "cancel": "Cancelar", - "delete": "Excluir", - "create": "Criar", - "save": "Salvar", - "channelListTitle": "Canais configurados", - "channelListDescription": "Os canais habilitados serão conectados automaticamente ao iniciar o serviço.", - "editChannel": "Editar canal", - "editSuccess": "Canal atualizado.", - "tokenPlaceholderKeep": "Deixar em branco para manter atual", - "weixinScanTitle": "Escanear código QR", - "weixinScanDescription": "Abra o WeChat e escaneie o código QR para conectar.", - "weixinQrcodeExpired": "Código QR expirado.", - "weixinRefreshQrcode": "Atualizar", - "weixinWaitingScan": "Aguardando escaneamento...", - "weixinPollError": "Conexão instável, tentando novamente...", - "weixinReconnectNotice": "Devido a limitações do protocolo iLink, após cada reconexão você precisa enviar uma mensagem ao bot para que os disparadores de eventos tenham efeito.", - "connect": "Conectar", - "disconnect": "Desconectar", - "test": "Testar conexão", - "tabs": { - "channels": "Canais", - "commands": "Comandos", - "events": "Eventos", - "other": "Outros" - }, - "commands": { - "title": "Comandos integrados", - "description": "Comandos de bot disponíveis nos canais de chat. Em chats em grupo, @Bot é necessário para processar mensagens.", - "prefixLabel": "Prefixo de comando", - "prefixDescription": "1-3 caracteres não alfanuméricos para acionar comandos do bot (padrão /).", - "prefixSaved": "Prefixo de comando salvo.", - "prefixSaveFailed": "Falha ao salvar o prefixo.", - "prefixInvalid": "O prefixo deve ser de 1-3 caracteres não alfanuméricos.", - "save": "Salvar", - "folderDesc": "Selecionar pasta de trabalho", - "agentDesc": "Selecionar agente de IA", - "taskDesc": "Criar sessão e executar tarefa", - "sessionsDesc": "Listar sessões ativas na pasta", - "resumeDesc": "Conversas recentes / retomar uma sessão", - "cancelDesc": "Cancelar tarefa atual", - "approveDesc": "Aprovar solicitação de permissão do agente", - "denyDesc": "Negar solicitação de permissão do agente", - "searchDesc": "Pesquisar conversas por palavra-chave", - "todayDesc": "Resumo da atividade de hoje", - "statusDesc": "Status da conexão do canal", - "helpDesc": "Mostrar ajuda" - }, - "events": { - "title": "Notificações de eventos", - "description": "Ao habilitar eventos, eles serão enviados ao canal quando acionados.", - "turnComplete": "Turno concluído", - "turnCompleteDesc": "Quando um turno do agente termina", - "error": "Erro do agente", - "errorDesc": "Quando um agente encontra um erro", - "permissionRequest": "Solicitação de permissão", - "permissionRequestDesc": "Quando um agente solicita permissão para agir", - "questionRequest": "Pergunta do agente", - "questionRequestDesc": "Quando um agente faz uma pergunta", - "userPromptSent": "Mensagem do usuário", - "userPromptSentDesc": "Quando você envia uma mensagem (o texto da mensagem é incluído na notificação)", - "saved": "Filtro de eventos atualizado.", - "saveFailed": "Falha ao salvar o filtro de eventos.", - "loadFailed": "Falha ao carregar as configurações.", - "retry": "Tentar novamente", - "webhooksTitle": "Webhooks", - "webhooksDescription": "Envia uma carga JSON via POST para uma ou mais URLs quando um evento ativado ocorre. O filtro de eventos acima também se aplica aos webhooks.", - "webhookUrlPlaceholder": "https://example.com/webhook", - "addWebhook": "Adicionar webhook", - "removeWebhook": "Remover webhook", - "webhookSave": "Salvar", - "webhooksSaved": "Webhooks salvos.", - "webhooksSaveFailed": "Falha ao salvar os webhooks.", - "webhookInvalidUrl": "Insira URLs http(s) válidas.", - "docsTitle": "Formato da requisição", - "docsMethod": "Método", - "docsContentType": "Content-Type", - "docsNote": "Cada evento ativado é entregue a todas as URLs. Os webhooks não têm debounce; o filtro de eventos acima continua valendo.", - "editWebhook": "Editar webhook", - "enableWebhook": "Ativar webhook", - "webhookDuplicate": "Esta URL já está configurada.", - "cancel": "Cancelar", - "webhooksEmpty": "Nenhum webhook configurado ainda.", - "deleteWebhookTitle": "Excluir webhook", - "deleteWebhookMessage": "Remover este webhook? Os eventos não serão mais entregues a esta URL.", - "delete": "Excluir" - }, - "language": { - "title": "Idioma das mensagens", - "description": "Idioma utilizado para notificações de eventos, respostas de comandos e relatórios diários enviados aos canais de chat.", - "saved": "Idioma das mensagens salvo.", - "saveFailed": "Falha ao salvar o idioma das mensagens.", - "en": "Inglês", - "zh-cn": "Chinês simplificado", - "zh-tw": "Chinês tradicional", - "ja": "Japonês", - "ko": "Coreano", - "es": "Espanhol", - "de": "Alemão", - "fr": "Francês", - "pt": "Português", - "ar": "Árabe" - } - }, - "ModelProviderSettings": { - "sectionTitle": "Provedores de Modelos", - "sectionDescription": "Gerenciar credenciais de provedores de API para agentes.", - "filterAll": "Todos", - "providerListTitle": "Provedores Configurados", - "addProvider": "Adicionar Provedor", - "editProvider": "Editar Provedor", - "noProviders": "Nenhum provedor de modelo configurado.", - "providerName": "Nome", - "providerNamePlaceholder": "Ex. OpenAI, Anthropic", - "apiUrl": "URL da API", - "apiUrlPlaceholder": "https://api.openai.com/v1", - "apiKey": "Chave da API", - "apiKeyPlaceholder": "sk-...", - "apiKeyKeepCurrent": "Deixe em branco para manter atual", - "agentTypes": "Tipos de Agente", - "agentTypesRequired": "Pelo menos um tipo de agente é necessário.", - "agentType": "Tipo de Agente", - "agentTypeRequired": "O tipo de agente é obrigatório.", - "agentTypeImmutableHint": "O tipo de agente não pode ser alterado após a criação.", - "model": "Modelo", - "modelPlaceholderCodex": "gpt-5.6-sol / gpt-5.5", - "modelPlaceholderGemini": "gemini-3-pro-preview", - "claudeMainModel": "Modelo Principal", - "claudeReasoningModel": "Modelo de Raciocínio (pensamento)", - "claudeHaikuDefaultModel": "Modelo Haiku Padrão", - "claudeSonnetDefaultModel": "Modelo Sonnet Padrão", - "claudeOpusDefaultModel": "Modelo Opus Padrão", - "claudeCustomModelOption": "ID do modelo personalizado", - "claudeCustomModelOptionName": "Nome do modelo personalizado", - "claudeCustomModelOptionDescription": "Descrição do modelo personalizado", - "claudeCustomModelOptionHint": "Adiciona uma única entrada personalizada ao seletor de modelos do Claude (por exemplo, um modelo atrás de um gateway/proxy personalizado). Nome e descrição são informações de exibição opcionais.", - "nameRequired": "O nome do provedor é obrigatório.", - "apiUrlRequired": "A URL da API é obrigatória.", - "apiKeyRequired": "A chave da API é obrigatória.", - "loadFailed": "Falha ao carregar provedores.", - "saveFailed": "Falha ao salvar alterações.", - "createSuccess": "Provedor criado.", - "editSuccess": "Provedor atualizado.", - "deleteSuccess": "Provedor excluído.", - "deleteConfirmTitle": "Excluir Provedor", - "deleteConfirmMessage": "O provedor \"{name}\" será excluído permanentemente. Tem certeza?", - "deleteBlockedByAgent": "{agents} está usando este provedor. Desvincule-o antes de excluir.", - "cancel": "Cancelar", - "delete": "Excluir", - "create": "Criar", - "save": "Salvar", - "affectedRunningSessions": "{count, plural, one {# sessão ativa precisa reconectar para aplicar a alteração} other {# sessões ativas precisam reconectar para aplicar a alteração}}" - }, - "SkillMatrix": { - "loading": "Carregando…", - "searchPlaceholder": "Pesquisar por nome, id ou descrição", - "empty": "Nada para mostrar.", - "emptySearch": "Nenhuma correspondência para a pesquisa atual.", - "skillColumn": "Habilidade", - "selectAll": "Selecionar tudo visível", - "selectSkill": "Selecionar {name}", - "everything": { - "label": "Em massa", - "enable": "Ativar tudo (visível)", - "disable": "Desativar tudo (visível)" - }, - "columnMenu": { - "enableAll": "Ativar todas as habilidades", - "disableAll": "Desativar todas as habilidades" - }, - "rowMenu": { - "label": "Ações em massa para {name}", - "enableAll": "Ativar para todos os agentes", - "disableAll": "Desativar para todos os agentes" - }, - "bulk": { - "selected": "{count} selecionados", - "targetAll": "Todos os agentes", - "targetSome": "{count} agentes", - "enable": "Ativar", - "disable": "Desativar", - "clear": "Limpar" - }, - "confirm": { - "disableTitle": "Desativar estes links?", - "disableBody": "Isto remove {count} links de habilidades gerenciados pelo codeg. Habilidades que ocupam um diretório personalizado não são afetadas. Você pode reativá-las a qualquer momento.", - "cancel": "Cancelar", - "confirm": "Desativar" - }, - "toasts": { - "loadFailed": "Falha ao carregar os status das habilidades", - "applyFailed": "Falha ao aplicar as alterações", - "enabled": "{count} links ativados", - "disabled": "{count} links desativados", - "enabledPartial": "{ok} ativados, {failed} falharam", - "disabledPartial": "{ok} desativados, {failed} falharam" - }, - "detail": { - "enableForAgents": "Ativar para agentes", - "preview": "Visualização do SKILL.md", - "loadingContent": "Carregando conteúdo…" - }, - "copyModeHint": "Copiado (não vinculado) — reative após atualizações para obter a versão mais recente" - }, - "ExpertsSettings": { - "title": "Habilidades de Especialista", - "description": "Ative fluxos de trabalho de habilidades selecionados e comprovados em campo para seus agentes de codificação de IA. Cada especialista é uma habilidade independente do projeto superpowers — o codeg gerencia a cópia central e a vincula aos agentes escolhidos.", - "loading": "Carregando especialistas…", - "loadingContent": "Carregando conteúdo…", - "emptyExperts": "Nenhum especialista disponível. Verifique os logs da aplicação.", - "emptySelection": "Selecione um especialista para ver seu conteúdo e gerenciar a ativação.", - "emptySearch": "Nenhum especialista corresponde à pesquisa atual.", - "searchPlaceholder": "Pesquisar especialistas por nome, ID ou descrição", - "enableForAgents": "Ativar para agentes", - "noAgents": "Nenhum agente ACP detectado.", - "copyModeWarning": "Copiado (não vinculado). Reative após as atualizações do codeg para obter a versão mais recente.", - "previewTitle": "Prévia do SKILL.md", - "categories": { - "discovery": "Descoberta e Design", - "planning": "Planejamento", - "execution": "Execução", - "quality": "Qualidade e Testes", - "debugging": "Depuração", - "review": "Revisão e Integração", - "meta": "Meta" - }, - "states": { - "not_linked": "Não ativado", - "linked_to_codeg": "Ativado", - "linked_elsewhere": "Bloqueado — outro vínculo existe", - "blocked_by_real_directory": "Bloqueado — uma habilidade personalizada ocupa este nome", - "broken": "Vínculo quebrado" - }, - "badges": { - "userModified": "Modificado pelo usuário" - }, - "actions": { - "openCentralDir": "Abrir pasta central", - "refresh": "Atualizar" - }, - "toasts": { - "loadFailed": "Falha ao carregar detalhes do especialista", - "enabled": "Especialista ativado para este agente", - "disabled": "Especialista desativado para este agente", - "enableFailed": "Falha ao ativar o especialista", - "disableFailed": "Falha ao desativar o especialista", - "openFolderFailed": "Falha ao abrir a pasta" - } - }, - "ScienceSettings": { - "title": "Habilidades de pesquisa científica", - "description": "Ative habilidades de pesquisa científica selecionadas para seus agentes de código com IA: geração de hipóteses, delineamento experimental, estatística, visualização, avaliação crítica e busca de literatura. O codeg gerencia uma cópia central e vincula cada habilidade aos agentes que você escolher.", - "loading": "Carregando habilidades científicas…", - "emptySkills": "Nenhuma habilidade científica disponível. Verifique os registros do aplicativo.", - "searchPlaceholder": "Pesquisar habilidades científicas por nome, id ou descrição", - "categories": { - "ideation": "Ideação", - "design": "Delineamento", - "analysis": "Análise", - "visualization": "Visualização", - "evaluation": "Avaliação", - "literature": "Literatura" - }, - "states": { - "not_linked": "Não ativado", - "linked_to_codeg": "Ativado", - "linked_elsewhere": "Bloqueado — outro vínculo existe", - "blocked_by_real_directory": "Bloqueado — uma habilidade personalizada ocupa este nome", - "broken": "Vínculo quebrado" - }, - "badges": { - "userModified": "Modificado pelo usuário", - "needsKey": "Requer chave", - "needsSetup": "Pode exigir configuração" - }, - "actions": { - "openCentralDir": "Abrir pasta central", - "refresh": "Atualizar" - }, - "toasts": { - "openFolderFailed": "Falha ao abrir a pasta" - } - }, - "OfficeToolsSettings": { - "title": "Ferramentas Office", - "description": "Gerencie as habilidades do OfficeCLI para criar arquivos Excel, Word e PowerPoint. Instale o OfficeCLI, sincronize as habilidades e ative-as por agente.", - "loadingContent": "Carregando conteúdo…", - "emptySkills": "Nenhuma habilidade disponível. Instale o OfficeCLI e sincronize as habilidades.", - "emptySelection": "Selecione uma habilidade para ver seu conteúdo e gerenciar a ativação.", - "emptySearch": "Nenhuma habilidade encontrada.", - "searchPlaceholder": "Pesquisar habilidades por nome, ID ou descrição", - "enableForAgents": "Ativar para agentes", - "noAgents": "Nenhum agente ACP detectado.", - "installFirst": "Instale o OfficeCLI primeiro para ativar as habilidades.", - "syncFirst": "Sincronize as habilidades primeiro para carregar o conteúdo.", - "noContent": "Nenhum conteúdo disponível.", - "copyModeWarning": "Copiado (não vinculado). Sincronize novamente para obter a versão mais recente.", - "previewTitle": "Pré-visualização SKILL.md", - "detection": { - "installed": "Instalado", - "notInstalled": "Não instalado", - "notRunnable": "Instalado, mas não executável", - "installHint": "Instale o OfficeCLI para habilitar as habilidades de geração de documentos Office para seus agentes de IA.", - "install": "Instalar", - "uninstall": "Desinstalar", - "syncSkills": "Sincronizar habilidades" - }, - "categories": { - "general": "Geral", - "presentations": "Apresentações", - "documents": "Documentos", - "spreadsheets": "Planilhas" - }, - "states": { - "not_linked": "Não ativado", - "linked_to_codeg": "Ativado", - "linked_elsewhere": "Bloqueado — existe outro link", - "blocked_by_real_directory": "Bloqueado — uma habilidade personalizada ocupa este nome", - "broken": "Link quebrado" - }, - "badges": { - "notSynced": "Não sincronizado" - }, - "actions": { - "refresh": "Atualizar" - }, - "toasts": { - "loadFailed": "Falha ao carregar detalhes da habilidade", - "enabled": "Habilidade ativada para este agente", - "disabled": "Habilidade desativada para este agente", - "enableFailed": "Falha ao ativar habilidade", - "disableFailed": "Falha ao desativar habilidade", - "installSuccess": "OfficeCLI instalado com sucesso", - "installFailed": "Falha ao instalar o OfficeCLI", - "uninstallSuccess": "OfficeCLI desinstalado", - "uninstallFailed": "Falha ao desinstalar o OfficeCLI", - "syncSuccess": "{synced} habilidades sincronizadas", - "syncPartial": "{synced} sincronizadas, {errors} falharam", - "syncFailed": "Falha ao sincronizar habilidades" - }, - "autoPreviewLabel": "Abrir visualização automaticamente", - "autoPreviewHint": "Quando um agente cria ou edita um arquivo do Word, Excel ou PowerPoint, abre sua visualização ao vivo automaticamente." - }, - "SkillPacksSettings": { - "title": "Pacotes de habilidades", - "description": "Pacotes de habilidades selecionados que o codeg gerencia de forma centralizada e vincula aos seus agentes de IA — especialistas em programação, pesquisa científica e ferramentas de documentos de escritório. Ative-os por agente abaixo.", - "tabs": { - "experts": "Especialistas", - "science": "Ciência", - "office": "Ferramentas de escritório", - "custom": "Personalizadas" - }, - "actions": { - "openCentralDir": "Abrir pasta central", - "refresh": "Atualizar" - }, - "toasts": { - "openFolderFailed": "Falha ao abrir a pasta" - } - }, - "QuickMessagesSettings": { - "title": "Mensagens rápidas", - "description": "Gerencie trechos de mensagens reutilizáveis. Arraste para reordenar.", - "loading": "Carregando mensagens rápidas…", - "emptyList": "Ainda não há mensagens rápidas. Clique em \"Nova\" para criar uma.", - "emptySelection": "Selecione uma mensagem rápida para editar.", - "searchPlaceholder": "Pesquisar por título ou conteúdo", - "untitled": "Sem título", - "actions": { - "new": "Nova", - "save": "Salvar", - "delete": "Excluir", - "dragSort": "Arraste para reordenar", - "dragSortMessage": "Arrastar para reordenar mensagem rápida: {name}" - }, - "fields": { - "title": "Título", - "titlePlaceholder": "Dê um título curto a esta mensagem", - "content": "Conteúdo", - "contentPlaceholder": "Digite aqui o conteúdo da mensagem" - }, - "confirmDelete": { - "title": "Excluir mensagem rápida?", - "message": "Isso excluirá permanentemente \"{name}\". Tem certeza?", - "cancel": "Cancelar", - "confirm": "Excluir" - }, - "toasts": { - "loadFailed": "Falha ao carregar mensagens rápidas", - "createFailed": "Falha ao criar mensagem rápida", - "saveFailed": "Falha ao salvar mensagem rápida", - "deleteFailed": "Falha ao excluir mensagem rápida", - "saveOrderFailed": "Falha ao salvar a ordem", - "created": "Mensagem rápida criada", - "saved": "Mensagem rápida salva", - "deleted": "Mensagem rápida excluída" - } - }, - "Pet": { - "badge": { - "running": "{count} em execução", - "waiting": "{count} aguardando aprovação", - "error": "{count} com erro" - }, - "panel": { - "title": "Sessões ativas", - "empty": "Nenhuma sessão ativa", - "emptyHint": "Agentes em execução e os que precisam de você aparecem aqui.", - "statusRunning": "Em execução", - "statusWaiting": "Aguardando", - "statusError": "Erro", - "subAgentOf": "Subagente de" - }, - "menu": { - "scale": "Escala", - "openManager": "Gerenciar pets", - "close": "Fechar" - }, - "loadError": "Falha ao carregar pet", - "missingPetIdParam": "Nenhum pet selecionado", - "summonButton": "Pet", - "manager": { - "title": "Pets", - "description": "Companheiros flutuantes de desktop com sprites compatíveis com o Codex.", - "addPet": "Adicionar pet", - "importFromCodex": "Importar do Codex", - "noPets": "Sem pets. Adicione um ou importe do Codex.", - "setActive": "Ativar", - "active": "Ativo", - "edit": "Editar", - "delete": "Excluir", - "deleteConfirm": "Excluir o pet \"{name}\"? Será removido do disco.", - "summon": "Invocar janela do pet", - "openCodexHelp": "Pets do Codex precisam estar em ~/.codex/pets/. Nenhum encontrado.", - "specRequirement": "O sprite precisa ter 1536px de largura e altura múltipla de 208px (ex.: 1872 ou 2288), em PNG ou WebP com transparência.", - "form": { - "id": "ID do pet", - "idHelp": "Minúsculas, dígitos, '-' e '_'. Máx 64 caracteres.", - "displayName": "Nome", - "description": "Descrição (opcional)", - "spritesheet": "Sprite", - "chooseFile": "Escolher arquivo", - "replaceFile": "Substituir sprite", - "saveCreate": "Adicionar pet", - "saveUpdate": "Salvar alterações", - "cancel": "Cancelar" - }, - "errors": { - "missingId": "ID obrigatório", - "missingName": "Nome obrigatório", - "missingSpritesheet": "Sprite obrigatório", - "addFailed": "Falha ao adicionar", - "updateFailed": "Falha ao atualizar", - "deleteFailed": "Falha ao excluir", - "loadFailed": "Falha ao carregar pets", - "setActiveFailed": "Falha ao ativar pet", - "summonFailed": "Falha ao abrir a janela do pet" - } - }, - "import": { - "title": "Importar do Codex", - "subtitle": "Pets disponíveis em ~/.codex/pets/.", - "selectAll": "Selecionar todos", - "alreadyImported": "Já importado", - "renameOnConflict": "Renomear conflitos com sufixo -imported", - "import": "Importar selecionados", - "noneFound": "Nenhum pet do Codex disponível.", - "imported": "Importação concluída", - "failed": "Falha no import", - "close": "Fechar" - }, - "marketplace": { - "openMarketplace": "Mercado de pets", - "title": "Mercado de pets", - "search": "Buscar pets", - "kindFilter": { - "all": "Todos", - "object": "Objeto", - "animal": "Animal", - "person": "Pessoa", - "creature": "Criatura" - }, - "sortFilter": { - "latest": "Recentes", - "popular": "Populares", - "views": "Mais vistos" - }, - "refresh": "Atualizar", - "install": "Instalar", - "installing": "Instalando", - "reinstall": "Reinstalar", - "reinstallConfirm": "Sobrescrever o pet local \"{name}\"? Os dados existentes serão substituídos.", - "cancel": "Cancelar", - "stats": { - "views": "Visualizações", - "downloads": "Downloads", - "likes": "Curtidas" - }, - "actions": { - "idle": "Parado", - "running_right": "Corre dir.", - "running_left": "Corre esq.", - "waving": "Acena", - "jumping": "Pula", - "failed": "Falha", - "waiting": "Espera", - "running": "Corre", - "review": "Revisão" - }, - "page": "Página {page} de {total}", - "prev": "Anterior", - "next": "Próxima", - "empty": "Nenhum pet corresponde.", - "successInstalled": "\"{name}\" instalado", - "errors": { - "loadFailed": "Falha ao carregar o mercado", - "installFailed": "Falha ao instalar o pet", - "alreadyInstalled": "O pet já existe localmente" - } - } - }, - "RemoteWorkspace": { - "openRemoteWorkspace": "Open remote workspace", - "manage": "Manage remote workspace", - "manageTitle": "Remote Workspace connections", - "empty": "No remote connections", - "searchPlaceholder": "Search remote workspaces", - "orderFailed": "Failed to save remote workspace order", - "dragSort": "Drag to sort", - "dragSortConnection": "Drag to sort {name}", - "newConnection": "New connection", - "loading": "Loading", - "loadingConnection": "Loading remote connection", - "name": "Name", - "baseUrl": "Service URL", - "token": "Access token", - "save": "Save", - "delete": "Delete", - "confirmDelete": { - "title": "Delete remote connection?", - "message": "This will remove \"{name}\" from this device. This action cannot be undone.", - "cancel": "Cancel", - "confirm": "Delete" - }, - "saved": "Remote connection saved.", - "deleted": "Remote connection deleted.", - "loadFailed": "Failed to load remote connections", - "saveFailed": "Failed to save remote connection", - "deleteFailed": "Failed to delete remote connection", - "openFailed": "Failed to open remote workspace", - "connectionLoadFailed": "Failed to load remote connection: {message}", - "connectionExpired": "Remote connection \"{name}\" is expired. Update its token and reload this window." - }, - "ServerFileBrowser": { - "title": "Selecionar arquivo do servidor", - "pathPlaceholder": "Inserir caminho do diretório...", - "goHome": "Ir para o diretório inicial", - "navigateUp": "Ir para o diretório acima", - "select": "Selecionar", - "cancel": "Cancelar", - "loading": "Carregando...", - "emptyDirectory": "Este diretório está vazio", - "errorLoadingDir": "Falha ao carregar o diretório", - "selectedCount": "{count} selecionado(s)" - }, - "BackupSettings": { - "title": "Backup e restauração", - "description": "Exporte um backup portátil dos seus dados do codeg ou restaure a partir de um.", - "tabs": { - "backup": "Backup", - "restore": "Restauração" - }, - "export": { - "includeExternal": "Incluir o conteúdo das conversas", - "includeExternalHint": "Também arquiva as transcrições das CLIs (Claude, Codex, Gemini, …). Aumenta o tamanho.", - "passphrase": "Senha (opcional)", - "passphrasePlaceholder": "Deixe em branco para um arquivo sem criptografia", - "passphraseConfirm": "Confirmar a senha", - "passphraseMismatch": "As senhas não coincidem.", - "noPassphraseWarning": "Este backup conterá segredos (chaves de API, tokens) em texto puro. Guarde-o em local seguro.", - "passphraseLossWarning": "Criptografado com esta senha. Se você perdê-la, o backup não poderá ser recuperado.", - "button": "Exportar backup", - "inProgress": "Criando backup…", - "success": "Backup criado.", - "started": "Download do backup iniciado." - }, - "restore": { - "selectFile": "Selecionar arquivo de backup", - "passphrasePrompt": "Este backup está criptografado. Digite a senha dele.", - "unlock": "Desbloquear", - "preview": { - "title": "Detalhes do backup", - "encrypted": "Criptografado", - "compatible": "Compatível", - "incompatible": "Incompatível", - "createdAt": "Criado: {value}", - "appVersion": "Versão do app: {value}", - "incompatibleHint": "Este backup foi criado por uma versão mais recente do codeg e não pode ser restaurado." - }, - "replaceWarning": "Restaurar substitui todos os dados atuais do codeg (banco de dados e uploads). Seus dados atuais são salvos em um snapshot primeiro, para que possam ser recuperados.", - "keyringNote": "Os tokens de GitHub/chat do desktop ficam no chaveiro do sistema e não são incluídos; insira-os novamente após restaurar.", - "button": "Restaurar", - "staging": "Preparando a restauração…", - "staged": "Restauração preparada. Reiniciando…", - "restarting": "Restauração preparada. Reiniciando o servidor…", - "restartTimeout": "O servidor não voltou a tempo. Recarregue a página quando ele estiver ativo.", - "externalSideLocation": "As transcrições de conversas foram restauradas em {path}", - "confirmTitle": "Substituir todos os dados?", - "confirmBody": "Isto substituirá seu banco de dados e uploads atuais do codeg pelo backup e, em seguida, reiniciará. Seus dados atuais são salvos em um snapshot primeiro.", - "cancel": "Cancelar", - "confirmAction": "Substituir e reiniciar", - "external": { - "title": "Conteúdo das conversas", - "hint": "Este backup inclui transcrições das CLIs. Escolha para onde restaurá-las.", - "modeSkip": "Não restaurar", - "modeSide": "Restaurar em uma pasta separada segura", - "modeOriginal": "Restaurar nos locais originais das CLIs", - "forceOverwrite": "Sobrescrever arquivos existentes", - "forceOverwriteHint": "Substitui os arquivos que já existem nas pastas das CLIs.", - "scanning": "Verificando conflitos…", - "noConflicts": "Nenhum arquivo existente será sobrescrito.", - "conflictCount": "{count} arquivo(s) existente(s) seriam afetados.", - "conflictSkipNote": "Os arquivos existentes são mantidos (ignorados) a menos que você ative a sobrescrita." - }, - "restartFailed": "Restauração preparada, mas o servidor não conseguiu reiniciar. Reinicie-o manualmente para aplicá-la." - }, - "remoteUnsupported": "O backup e a restauração atuam sobre os dados da máquina que executa o codeg. Você está conectado a um espaço de trabalho remoto — gerencie os backups dele diretamente nesse servidor." - }, - "backup": { - "restore": { - "error": { - "badPassphrase": "Senha incorreta ou backup corrompido.", - "corrupted": "O arquivo de backup está corrompido.", - "unknownFormat": "Este arquivo não é um backup do codeg reconhecido.", - "newerVersion": "Este backup foi criado pelo codeg {backupVersion}, mais recente que esta versão ({appVersion}).", - "alreadyPending": "Já existe uma restauração preparada. Reinicie para aplicá-la antes de preparar outra." - } - }, - "error": { - "diskSpace": "Espaço em disco insuficiente para concluir a operação.", - "cancelled": "A operação foi cancelada." - } - }, - "WebConnection": { - "disconnectedTitle": "Conexão perdida", - "reconnectingDescription": "Tentando reconectar ao servidor. Normalmente isso se resolve sozinho em alguns segundos.", - "reconnectNow": "Reconectar agora", - "sessionExpiredTitle": "Sessão expirada", - "sessionExpiredDescription": "Sua sessão não é mais válida. Faça login novamente para continuar.", - "goToLogin": "Ir para o login" - }, - "LiveFeedback": { - "placeholder": "Envie uma nota para {agent} enquanto ele trabalha…", - "agentFallback": "o agente", - "ariaLabel": "Nota de feedback ao vivo", - "dialogTitle": "Feedback ao vivo", - "dialogDescription": "Envie uma nota ao agente enquanto ele trabalha. Ele a lerá na próxima verificação, sem interromper a etapa atual.", - "dialogDescriptionInstant": "Envie uma nota ao agente enquanto ele trabalha. Ela é inserida imediatamente no turno atual — o agente a vê na hora.", - "channelDowngraded": "A inserção instantânea não está disponível nesta sessão — sua nota foi salva para o agente ler na próxima verificação.", - "send": "Enviar", - "cancel": "Cancelar", - "pending": "aguardando", - "delivered": "recebida", - "turnEndedUnread": "O agente terminou antes de ler o seu feedback.", - "sendAsMessage": "Enviar como mensagem", - "dismiss": "Dispensar", - "turnEndedResent": "O turno terminou — enviado como nova mensagem.", - "turnEnded": "O turno já terminou.", - "submitFailed": "Não foi possível enviar a sua nota" - }, - "AgentToolsSettings": { - "title": "Ferramentas na conversa", - "description": "Ferramentas extras que o codeg dá a um agente dentro de uma conversa. Elas são injetadas quando o agente inicia, então a mudança vale para os agentes iniciados depois.", - "feedbackLabel": "Feedback ao vivo", - "feedbackHint": "Envie notas e correções a um agente enquanto ele trabalha. Se o agente oferecer inserção instantânea, sua nota entra imediatamente no turno em andamento; caso contrário, o agente recebe uma ferramenta para verificar seu feedback — esses agentes normalmente só verificam quando você menciona isso no prompt, por exemplo, adicione \"verifique meu feedback ao vivo regularmente\" à sua mensagem.", - "questionLabel": "Perguntar ao usuário", - "questionHint": "Permite que os agentes pausem e façam uma pergunta de múltipla escolha que aparece acima da caixa de entrada da conversa. O agente aguarda até você responder (ou pular).", - "sessionInfoLabel": "Obter informações da sessão", - "sessionInfoHint": "Permite que os agentes consultem uma sessão mencionada na sua mensagem (um selo de sessão) para ler o título, agente, status, espaço de trabalho, uso de tokens e mensagens recentes.", - "automationsLabel": "Criar automações", - "automationsHint": "Salva a conversa como uma automação que roda em um agendamento. Desativado por padrão — depois ela inicia agentes por conta própria.", - "workTasksLabel": "Criar tarefas a fazer", - "workTasksHint": "Coloca um cartão no quadro de tarefas a partir da conversa. Desativado por padrão — grava o estado do app.", - "save": "Salvar", - "saving": "Salvando…", - "saved": "Configurações de ferramentas salvas", - "saveFailed": "Falha ao salvar as configurações de ferramentas", - "loadFailed": "Falha ao carregar: {detail}" - }, - "NotificationSoundSettings": { - "title": "Sons de notificação", - "description": "Reproduz um som curto quando ocorre um evento do agente. São os mesmos eventos enviados aos canais de chat; esta configuração vale apenas para este dispositivo.", - "enableHint": "Desativado por padrão. Os sons tocam apenas na janela do espaço de trabalho deste navegador ou aplicativo.", - "volume": "Volume", - "preview": "Ouvir", - "previewEvent": "Ouvir o som de {event}", - "onlyWhenUnfocused": "Somente quando a janela não estiver em foco", - "onlyWhenUnfocusedHint": "Fica em silêncio enquanto você está olhando para o Codeg.", - "eventsTitle": "Eventos", - "eventsHint": "Escolha um som para cada evento ou «Silencioso» para ignorá-lo. Se o mesmo evento se repetir em poucos segundos, ele toca apenas uma vez.", - "toneNone": "Silencioso", - "toneChime": "Carrilhão", - "toneDing": "Sino", - "toneBlip": "Bipe", - "tonePop": "Pop", - "toneAlert": "Alerta", - "toneDescend": "Descendente" - }, - "LogsSettings": { - "loading": "Carregando…", - "sectionTitle": "Registros de execução", - "sectionDescription": "Visualize e configure os registros de diagnóstico do aplicativo. Os registros são gravados em arquivos locais e mantidos na memória para visualização ao vivo.", - "captureTitle": "Nível de registro", - "captureDescription": "Controla quanto detalhe é capturado. Níveis mais altos (Debug, Trace) registram mais, mas geram registros maiores. «Desligado» desativa o registro.", - "captureLabel": "Nível de captura", - "levels": { - "off": "Desligado", - "error": "Erro", - "warn": "Aviso", - "info": "Informação", - "debug": "Depuração", - "trace": "Rastreamento" - }, - "viewerTitle": "Registros recentes", - "viewerDescription": "Visualização ao vivo dos registros recentes. Filtre por nível ou pesquise texto.", - "searchPlaceholder": "Pesquisar mensagem ou origem…", - "viewLevels": { - "all": "Todos os níveis", - "error": "Erro e acima", - "warn": "Aviso e acima", - "info": "Informação e acima", - "debug": "Depuração e acima", - "trace": "Rastreamento e acima" - }, - "pause": "Pausar", - "resume": "Ao vivo", - "refresh": "Atualizar", - "clear": "Limpar", - "openFolder": "Abrir pasta", - "shownCount": "{shown} / {total} exibidos", - "empty": "Nenhum registro para exibir.", - "levelSaveFailed": "Falha ao salvar o nível de registro", - "openFolderFailed": "Falha ao abrir a pasta de registros", - "downloadFailed": "Falha ao baixar o arquivo de registro", - "filesTitle": "Arquivos de registro", - "filesDescription": "Baixe arquivos de registro completos do disco para o histórico além do buffer ao vivo.", - "filesEmpty": "Ainda não há arquivos de registro.", - "download": "Baixar", - "downloadTruncated": "O arquivo é grande; foram baixados os {size} mais recentes. O arquivo completo está no diretório de logs.", - "captureEnvLocked": "O nível de registro é controlado pela variável de ambiente RUST_LOG / CODEG_LOG; altere-a lá para ter efeito.", - "targetsTitle": "Substituições por módulo", - "targetsDescription": "Defina um nível diferente para módulos específicos (ex.: codeg_lib::acp) sem alterar o nível global.", - "targetsAdd": "Adicionar", - "targetsRemove": "Remover substituição", - "toggleDetails": "Alternar detalhes" - }, - "Automations": { - "title": "Automações", - "new": "Nova automação", - "empty": "Ainda não há automações", - "emptyHint": "Crie uma para executar uma tarefa do agente de forma agendada ou manual.", - "name": "Nome", - "namePlaceholder": "ex.: Revisão de PR noturna", - "prompt": "Instrução", - "promptPlaceholder": "O que o agente deve fazer?", - "agent": "Agente", - "folder": "Pasta do espaço de trabalho", - "folderPlaceholder": "Selecione uma pasta", - "isolation": "Isolamento", - "isolationWorktree": "Novo worktree por execução", - "isolationShared": "Executar na pasta", - "isolationSharedCaveat": "As execuções usam diretamente a árvore de trabalho desta pasta e podem entrar em conflito com suas alterações não confirmadas. Ative a opção de worktree para isolar cada execução.", - "trigger": "Gatilho", - "triggerSchedule": "Agendado", - "triggerManual": "Somente manual", - "cron": "Agendamento (cron)", - "cronPlaceholder": "0 9 * * 1-5", - "timezone": "Fuso horário", - "nextRun": "Próxima execução", - "branch": "Branch", - "branchOptional": "Branch (opcional)", - "enabled": "Ativado", - "save": "Salvar", - "cancel": "Cancelar", - "edit": "Editar", - "delete": "Excluir", - "runNow": "Executar agora", - "cancelRun": "Cancelar execução", - "runHistory": "Histórico de execuções", - "noRuns": "Ainda não há execuções", - "allFolders": "Todas as pastas", - "filterAll": "Todos", - "noMatches": "Nenhuma automação correspondente", - "viewConversation": "Ver conversa", - "lastRun": "Última execução", - "never": "Nunca", - "running": "Em execução", - "deleteTitle": "Excluir automação?", - "deleteDescription": "Isso remove a automação e seu agendamento. O histórico é mantido.", - "statusRunning": "Em execução", - "statusSucceeded": "Concluída", - "statusFailed": "Falhou", - "statusCancelled": "Cancelada", - "statusSkipped": "Ignorada", - "errorName": "O nome é obrigatório", - "errorPrompt": "A instrução é obrigatória", - "errorCron": "Automações agendadas exigem uma expressão cron", - "errorFolder": "Selecione uma pasta do espaço de trabalho", - "presetHourly": "A cada hora", - "presetDaily": "Diariamente 9h", - "presetWeekdays": "Dias úteis 9h", - "presetCustom": "Personalizado", - "probing": "Carregando opções…", - "retry": "Tentar novamente", - "configNone": "Este agente não tem opções configuráveis", - "inherit": "Padrão do agente", - "mode": "Modo", - "config": "Configuração", - "branchPlaceholder": "(branch padrão)", - "selectHint": "Selecione uma automação para ver os detalhes", - "refresh": "Atualizar", - "onboardTitle": "Automatize tarefas rotineiras do agente", - "onboardHint": "Agende um agente para revisar código, atualizar dependências ou triar problemas, periodicamente ou sob demanda.", - "headerSubtitle": "Tarefas do agente agendadas e sob demanda", - "startFromTemplate": "Começar com um modelo", - "blankTitle": "Automação em branco", - "blankDesc": "Configure uma tarefa do agente do zero.", - "backToTemplates": "Modelos", - "sectionSchedule": "Agendamento e destino", - "sectionTarget": "Destino", - "sectionAction": "Ação", - "actionLaunchSession": "Executar sessão", - "actionEnqueueTask": "Enfileirar tarefa", - "actionEnqueueTaskHint": "Cada disparo adiciona uma tarefa pendente, com o nome desta automação, às tarefas a fazer da pasta; o motor de tarefas a executa conforme as configurações do quadro.", - "sectionPrompt": "Prompt", - "nextIn": "Próxima em {rel}", - "manual": "Manual", - "schedEveryMinutes": "A cada {n} minutos", - "schedHourly": "De hora em hora", - "schedDaily": "Todos os dias às {time}", - "schedWeekdays": "Dias úteis às {time}", - "schedWeekly": "Toda {day} às {time}", - "schedMonthly": "Mensalmente no dia {day} às {time}", - "dow0": "domingo", - "dow1": "segunda-feira", - "dow2": "terça-feira", - "dow3": "quarta-feira", - "dow4": "quinta-feira", - "dow5": "sexta-feira", - "dow6": "sábado", - "tplCodeReviewTitle": "Revisão de código", - "tplCodeReviewDesc": "Revisa as alterações recentes em busca de bugs, regressões e problemas de qualidade.", - "tplDependencyUpdatesTitle": "Atualização de dependências", - "tplDependencyUpdatesDesc": "Encontra dependências desatualizadas e propõe atualizações seguras.", - "tplTestCoverageTitle": "Cobertura de testes", - "tplTestCoverageDesc": "Encontra caminhos de código sem testes e adiciona os testes que faltam.", - "tplTodoSweepTitle": "Varredura de TODO", - "tplTodoSweepDesc": "Reúne comentários TODO e FIXME e os tria por prioridade.", - "tplCiTriageTitle": "Triagem de CI", - "tplCiTriageDesc": "Investiga verificações que falharam recentemente e propõe correções.", - "tplReleaseNotesTitle": "Notas de versão", - "tplReleaseNotesDesc": "Resume as alterações desde a última versão em um changelog.", - "tplSecurityAuditTitle": "Auditoria de segurança", - "tplSecurityAuditDesc": "Verifica vulnerabilidades e padrões de risco e relata as constatações.", - "enable": "Ativar", - "disable": "Desativar", - "moreActions": "Mais ações", - "statusDisabled": "Desativada", - "cronBuilderTitle": "Gerador de agendamento", - "cronFreqLabel": "Frequência", - "cronFreqMinutes": "A cada N minutos", - "cronFreqHourly": "De hora em hora", - "cronFreqDaily": "Diário", - "cronFreqWeekdays": "Dias úteis", - "cronFreqWeekly": "Semanal", - "cronFreqMonthly": "Mensal", - "cronFreqCustom": "Personalizado", - "cronEveryLabel": "Intervalo (minutos)", - "cronTimeLabel": "Hora", - "cronHourLabel": "Hora", - "cronMinuteLabel": "Minuto", - "cronDowLabel": "Dia da semana", - "cronDomLabel": "Dia do mês", - "cronApply": "Aplicar", - "cronPreviewLabel": "Pré-visualização", - "cronOpenBuilder": "Abrir o gerador de agendamento", - "branchDefault": "Branch padrão", - "branchUseCustom": "Usar \"{query}\"", - "branchLocal": "Local", - "branchRemote": "Remoto", - "branchSearchPlaceholder": "Pesquisar branches…", - "branchNone": "Sem branches" - }, - "Tasks": { - "title": "Tarefas a fazer", - "new": "Nova tarefa", - "empty": "Ainda não há tarefas", - "emptyHint": "Adicione uma pendência e execute — o agente trabalha num worktree isolado e você revisa e faz merge do resultado.", - "emptyColTodo": "Ainda não há tarefas a fazer", - "emptyColInProgress": "Nada em andamento", - "emptyColAttention": "Nada aguardando você", - "emptyColDone": "Ainda não há concluídas", - "allFolders": "Todas as pastas", - "showCanceled": "Mostrar canceladas", - "showArchived": "Mostrar arquivadas", - "filter": "Filtrar", - "viewSwitchToBoard": "Mudar para a visualização de quadro", - "viewSwitchToList": "Mudar para a visualização de lista", - "statusFilter": "Estado", - "statusFilterAll": "Todos os estados", - "listEmpty": "Nenhuma tarefa corresponde aos filtros atuais", - "listColStatus": "Estado", - "listColTask": "Tarefa", - "listColLocation": "Localização", - "listColChanges": "Alterações", - "listColUpdated": "Atualizado", - "colTodo": "A fazer", - "colInProgress": "Em andamento", - "colAttention": "Aguardando você", - "colDone": "Concluídas", - "statusTodo": "A fazer", - "statusQueued": "Na fila", - "statusPreparing": "Preparando", - "statusRunning": "Em execução", - "statusAwaitingInput": "Aguardando entrada", - "statusReview": "Para revisar", - "statusMerging": "Fazendo merge", - "statusDone": "Concluída", - "statusFailed": "Falhou", - "statusCanceled": "Cancelada", - "statusInterrupted": "Interrompida", - "badgeCleanupFailed": "Limpeza falhou", - "badgeWorktreeKept": "Worktree mantido", - "badgeWorktreeRemoved": "Worktree removido", - "filesChanged": "{count} arquivos", - "actionStart": "Iniciar", - "actionSchedule": "Agendar", - "actionCancel": "Cancelar", - "actionRetry": "Tentar novamente", - "actionRequeue": "Reenfileirar", - "actionViewSession": "Ver conversa", - "actionEdit": "Editar", - "actionDelete": "Excluir", - "actionRetryCleanup": "Repetir limpeza", - "actionMerge": "Merge", - "actionUnqueueMerge": "Sair da fila de merge", - "actionEditQueuedMerge": "Editar merge na fila", - "badgeMergeQueued": "Na fila para merge", - "badgeMergeQueuedRank": "Na fila para merge · n.º {rank}", - "badgeMergeQueuedHint": "Aguardando o merge em andamento do projeto terminar; este começa sozinho.", - "actionComplete": "Concluir", - "actionAbandon": "Abandonar", - "cancelTitle": "Cancelar tarefa?", - "cancelDescription": "A tarefa passa para Cancelada. O worktree é mantido e você pode reenfileirá-la depois.", - "cancelReasonLabel": "Motivo (opcional)", - "cancelReasonPlaceholder": "Ex.: abordagem errada — vou reescrever a descrição", - "cancelKeep": "Deixa pra lá", - "cancelSubmit": "Cancelar tarefa", - "restartTitleRetry": "Tentar a tarefa novamente", - "restartTitleRequeue": "Reenfileirar a tarefa", - "restartDescription": "Você pode adicionar uma nota (opcional): ela chega ao prompt da próxima execução.", - "scheduleTitle": "Agendar tarefa", - "scheduleDescription": "A tarefa continua em A fazer e inicia sozinha no horário escolhido. O limite de concorrência da pasta continua valendo.", - "scheduleDateLabel": "Data", - "schedulePickDate": "Escolher data", - "scheduleTimeLabel": "Hora", - "schedulePreview": "Executa em {time}", - "schedulePastHint": "Esse horário já passou: a tarefa começa assim que você salvar.", - "scheduleInAnHour": "Em 1 hora", - "scheduleInThreeHours": "Em 3 horas", - "scheduleTomorrow": "Amanhã 9:00", - "scheduleClear": "Remover agendamento", - "scheduleBadge": "Início agendado para {time}", - "toastScheduled": "Agendada para {time}", - "toastScheduleCleared": "Agendamento removido", - "actionFollowUp": "Continuar", - "actionAddNote": "Adicionar observação", - "followUpSubmit": "Enviar", - "followUpIntentRevise": "Corrigir", - "followUpIntentContinue": "Prosseguir", - "followUpIntentQuestion": "Perguntar", - "followUpIntentVerify": "Revisar", - "followUpPlaceholderRevise": "O que o agente deve mudar? Ele continua na mesma sessão.", - "followUpPlaceholderContinue": "E agora? O que já foi feito permanece.", - "followUpPlaceholderQuestion": "O que você quer saber? O agente responde sem mexer em nenhum arquivo.", - "followUpPlaceholderVerify": "Opcional: algo que deva revisar com atenção?", - "followUpPlaceholderRetry": "Opcional: o que deve ser feito diferente? Ex.: rodar pnpm install antes", - "followUpPlaceholderRequeue": "Opcional: por que você cancelou e o que deve mudar desta vez?", - "actionArchive": "Arquivar", - "actionUnarchive": "Desarquivar", - "archiveAllDone": "Arquivar tudo", - "dropToStart": "Solte para iniciar", - "errorView": "Ver", - "notifyReview": "Pronto para revisão: {title}", - "notifyFailed": "A tarefa falhou: {title}", - "createFromMessage": "Criar tarefa a partir da mensagem", - "detailTokens": "Total de tokens", - "editorTitleNew": "Nova tarefa", - "editorTitleEdit": "Editar tarefa", - "templates": "Modelos", - "templatesEmpty": "Ainda não há modelos.", - "templateSaveCurrent": "Salvar como modelo", - "templateDelete": "Excluir modelo", - "transcriptTitle": "Conversa da tarefa", - "transcriptDescription": "Visão ao vivo somente leitura da sessão do agente da tarefa.", - "phaseWork": "Execução", - "phaseRetry": "Nova tentativa", - "phaseReturn": "Continuação", - "phaseMerge": "Merge", - "titleLabel": "Título", - "titlePlaceholder": "O que precisa ser feito?", - "promptLabel": "Descrição da tarefa", - "promptPlaceholder": "Descreva a tarefa para o agente — @ para referenciar arquivos, / para comandos", - "folderPlaceholder": "Selecione uma pasta", - "agentInheritedHint": "Herdado das configurações de tarefas; altere para personalizar esta tarefa", - "agentOverrideReset": "Voltar a herdar", - "sectionTarget": "Destino", - "errorTitle": "O título é obrigatório", - "errorPrompt": "A descrição é obrigatória", - "errorFolder": "Selecione uma pasta", - "save": "Salvar", - "cancel": "Cancelar", - "mergeTitle": "Merge da tarefa", - "mergeQueuedTitle": "Merge na fila", - "mergeQueueHint": "Outra tarefa deste projeto está sendo mesclada agora. Esta entra na fila e começa sozinha assim que a outra terminar.", - "mergeQueueUpdateHint": "Esta tarefa já está esperando para mesclar. Enviar atualiza o merge e mantém o lugar na fila.", - "mergeDescription": "Fazer merge de {branch} em {base}. Alterações não commitadas no worktree são commitadas antes.", - "mergeMessage": "Mensagem do commit", - "mergeMessagePlaceholder": "ex.: feat: add login validation", - "mergeAutoMessage": "Deixar o agente escrever a mensagem de commit", - "strategySquash": "Combinar em um único commit", - "strategySquashHint": "Todas as mudanças da tarefa entram na branch principal como um único registro — histórico mais limpo.", - "strategyMerge": "Manter o histórico completo", - "strategyMergeHint": "Cada commit feito durante a tarefa é mantido, mais um registro de merge — cada etapa fica rastreável.", - "mergeDeleteWorktree": "Excluir o worktree após o merge", - "mergeSubmit": "Merge", - "mergeSubmitQueue": "Adicionar à fila", - "mergeQueuedToast": "Adicionada à fila de merge — começa assim que o merge atual terminar.", - "completeTitle": "Concluir tarefa", - "completeDescription": "Esta tarefa não alterou nenhum arquivo, então não há nada para fazer merge: ela é marcada como concluída.", - "completeDescriptionNoWorktree": "O worktree desta tarefa foi removido, então não é mais possível fazer merge: ela é marcada como concluída. Um branch de trabalho que ainda tenha commits não mesclados é mantido.", - "completeDeleteWorktree": "Excluir o worktree ao concluir", - "completeSubmit": "Concluir", - "settingsTitle": "Configurações de tarefas", - "settingsDescription": "Padrões para tarefas em {folder}.", - "settingsScope": "Escopo", - "settingsScopeGlobal": "Todas as pastas (padrões globais)", - "settingsScopeGlobalHint": "Pastas sem configurações próprias usam estes padrões globais.", - "settingsSource": "Origem da configuração", - "settingsSourceGlobal": "Padrões globais", - "settingsSourceCustom": "Personalizada", - "settingsSourceGlobalFollow": "Segue as configurações globais de tarefas — mudanças lá se aplicam aqui automaticamente.", - "settingsSourceCustomHint": "Salva configurações próprias desta pasta, que deixa de seguir os padrões globais.", - "settingsAgent": "Agente padrão", - "settingsMaxConcurrent": "Máx. de tarefas simultâneas", - "settingsMaxConcurrentHint": "0 = ilimitado", - "settingsAutoProcess": "Processar automaticamente", - "settingsAutoProcessHint": "As tarefas pendentes iniciam sozinhas, até o limite de concorrência.", - "settingsMergeStrategy": "Estratégia de merge padrão", - "settingsMergeStrategyHint": "Como as mudanças da tarefa são registradas no histórico da branch ao mesclar.", - "settingsAutoMerge": "Merge automático", - "settingsAutoMergeHint": "Uma tarefa que chega à revisão com mudanças a integrar recebe merge como se você clicasse em Merge: o agente escreve a mensagem de commit e o worktree segue o padrão abaixo. Se a pré-verificação falhar ou um merge tiver falhado, a tarefa fica esperando por você.", - "settingsDeleteWorktree": "Excluir o worktree após o merge", - "settingsDeleteWorktreeHint": "Marca a opção por padrão no diálogo de merge; ainda dá para alterar lá.", - "settingsWorktreeRoot": "Local do worktree", - "settingsWorktreeRootHint": "Diretório onde os worktrees das novas tarefas são criados, um por tarefa. Deixe vazio para criá-los ao lado da pasta do projeto; \"~\" é a sua pasta pessoal e um caminho relativo é resolvido a partir da pasta do projeto.", - "settingsWorktreeRootPlaceholder": "~/codeg-worktrees", - "settingsWorktreeRootBrowse": "Escolher o diretório dos worktrees", - "settingsPreflight": "Comando de pré-verificação", - "settingsPreflightHint": "Executa no worktree quando uma tarefa chega à revisão.", - "settingsPreflightCustomPlaceholder": "pnpm test", - "settingsInitCommand": "Comando de inicialização do worktree", - "settingsInitCommandHint": "Executado em um worktree recém-criado antes de o agente iniciar.", - "settingsInitCommandPlaceholder": "pnpm install", - "settingsTabGeneral": "Geral", - "settingsTabMerge": "Merge", - "settingsTabWorktree": "Worktree", - "settingsTabPrompts": "Prompts", - "settingsPromptsIntro": "Cada etapa já envia seu próprio prompt embutido: a tarefa, as regras do worktree e, no merge, os passos exatos do git. O que você escrever aqui é anexado ao final como instruções extras: refina esses textos embutidos, mas nunca os substitui.", - "settingsPromptStageAll": "Todas as fases", - "settingsPromptPlaceholderAll": "ex.: Siga as convenções do AGENTS.md; mantenha o resumo final em duas frases", - "settingsPromptPlaceholderWork": "ex.: Leia primeiro os testes relacionados; faça commits pequenos ao longo do trabalho", - "settingsPromptPlaceholderRetry": "ex.: Verifique o que já está commitado antes de continuar; não refaça o que está pronto", - "settingsPromptPlaceholderReturn": "Ex.: Trate cada ponto levantado; não refatore nada não relacionado", - "settingsPromptPlaceholderMerge": "ex.: Escreva a mensagem do commit de integração em português; aponte os conflitos resolvidos à mão", - "settingsPromptHintAll": "Acrescentado a todos os prompts que o agente recebe, inclusive no merge.", - "settingsPromptHintWork": "Acrescentado quando uma tarefa é executada pela primeira vez.", - "settingsPromptHintRetry": "Acrescentado ao retomar uma tarefa interrompida ou com falha.", - "settingsPromptHintReturn": "Anexado quando você continua uma tarefa em revisão (corrigir, ampliar, revisar).", - "settingsPromptHintMerge": "Acrescentado quando o agente integra a tarefa no branch base.", - "preflightPassed": "{name} aprovado", - "preflightFailed": "{name} falhou", - "preflightRunning": "{name} em execução…", - "detailDescription": "Detalhes da tarefa", - "detailSummary": "Resultado", - "detailFiles": "Arquivos alterados", - "detailDiffAll": "Ver diff completo", - "detailDiffAllTitle": "Diff completo", - "detailNoChanges": "Ainda não há mudanças em relação à base", - "detailTimeline": "Progresso", - "detailTimelineEmpty": "Nenhuma atividade ainda", - "showMore": "Ver mais", - "showLess": "Ver menos", - "detailInfo": "Detalhes", - "detailBranch": "Branch", - "detailMergeCommit": "Commit de merge", - "detailChanges": "Alterações", - "detailScheduled": "Início agendado", - "detailCreated": "Criada", - "detailStarted": "Iniciada", - "detailFinished": "Concluída", - "diffLoading": "Carregando diff…", - "deleteConfirmTitle": "Excluir tarefa?", - "deleteConfirmBody": "“{title}” será removida do quadro. Uma execução ativa é cancelada antes.", - "deleteWithWorktree": "Excluir também o worktree", - "eventCreated": "Criada", - "eventStatusChanged": "Mudança de status", - "eventConfigEffective": "Configuração de execução", - "eventInitCommand": "Comando de inicialização", - "eventAgentProgress": "Progresso do agente", - "eventAgentVerdict": "Veredito do agente", - "eventMergeAttempt": "Merge iniciado", - "eventMergeQueued": "Na fila para merge", - "eventMergeConflict": "Conflito de merge", - "eventPreflight": "Pré-verificação", - "eventCleanupFailed": "Falha na limpeza do worktree", - "eventResumeFallback": "Retomada falhou; nova sessão usada", - "eventUserAction": "Ação do usuário", - "eventDiffStat": "Resumo das mudanças" - }, - "CustomSkillsSettings": { - "loading": "Carregando habilidades personalizadas…", - "category": "Personalizadas", - "searchPlaceholder": "Pesquisar habilidades personalizadas por nome, ID ou descrição", - "states": { - "not_linked": "Não ativada", - "linked_to_codeg": "Ativada", - "linked_elsewhere": "Vinculada em outro lugar", - "blocked_by_real_directory": "Bloqueada por uma pasta real", - "broken": "Link quebrado" - }, - "actions": { - "new": "Nova", - "import": "Importar", - "importFromAgent": "Importar de um agente", - "cancel": "Cancelar", - "save": "Salvar" - }, - "rowMenu": { - "edit": "Editar", - "duplicate": "Duplicar", - "delete": "Excluir" - }, - "bulk": { - "delete": "Excluir selecionadas" - }, - "editor": { - "createTitle": "Nova habilidade personalizada", - "editTitle": "Editar habilidade personalizada", - "description": "As habilidades personalizadas ficam no armazenamento compartilhado (~/.codeg/skills) e podem ser ativadas para qualquer agente.", - "idLabel": "ID da habilidade", - "idPlaceholder": "ex.: my-workflow", - "contentLabel": "SKILL.md", - "contentPlaceholder": "Escreva aqui o SKILL.md da habilidade…", - "preview": "Pré-visualização", - "edit": "Editar", - "emptyBody": "Ainda sem conteúdo." - }, - "duplicate": { - "title": "Duplicar habilidade", - "description": "Criar uma cópia de \"{id}\" com um novo ID.", - "newIdPlaceholder": "Novo ID da habilidade", - "confirm": "Duplicar" - }, - "import": { - "title": "Escolha uma pasta de habilidade para importar" - }, - "importFromAgent": { - "title": "Importar habilidades de um agente", - "description": "Copie as habilidades próprias de um agente para o repositório compartilhado e ative-as em qualquer agente.", - "agentLabel": "Agente", - "agentPlaceholder": "Selecione um agente", - "selectAll": "Selecionar tudo ({count})", - "loading": "Carregando as habilidades do agente…", - "unsupported": "Este agente não expõe um diretório de habilidades.", - "empty": "Este agente não tem habilidades para importar.", - "alreadyInLibrary": "Na biblioteca", - "confirm": "Importar selecionadas ({count})" - }, - "delete": { - "title": "Excluir habilidades personalizadas?", - "body": "Isto remove {count} habilidade(s) personalizada(s) do armazenamento central e as desvincula de todos os agentes. Não pode ser desfeito.", - "confirm": "Excluir" - }, - "toasts": { - "loadFailed": "Falha ao carregar a habilidade", - "idRequired": "Informe um ID de habilidade", - "created": "Habilidade personalizada criada", - "updated": "Habilidade personalizada atualizada", - "saveFailed": "Falha ao salvar a habilidade", - "imported": "Habilidade importada", - "importFailed": "Falha ao importar a habilidade", - "duplicated": "Habilidade duplicada", - "duplicateFailed": "Falha ao duplicar a habilidade", - "deleted": "{count} habilidade(s) excluída(s)", - "deletedPartial": "{ok} excluída(s), {failed} com falha", - "deleteFailed": "Falha ao excluir as habilidades", - "importedFromAgent": "{count} habilidade(s) importada(s)", - "importedFromAgentPartial": "{ok} importada(s), {failed} com falha", - "importFromAgentAllSkipped": "Nada a importar — {count} já na biblioteca", - "importFromAgentFailed": "Falha ao importar do agente" - } - }, - "CodexModelEditor": { - "customizedNotice": "Você personalizou a lista de modelos, então agora o codeg gerencia toda a tabela de modelos do codex. Os modelos oficiais que o codex adicionar depois não aparecerão automaticamente — clique no botão atualizar abaixo e salve novamente para sincronizá-los. Limpe suas personalizações para que o codex volte a atualizar automaticamente.", - "officialsTitle": "Modelos oficiais", - "officialsHint": "Incluídos automaticamente do codex que você inicia; remova os que não quiser.", - "officialsEmpty": "Nenhum modelo oficial disponível.", - "refresh": "Atualizar do codex", - "readdOfficial": "Readicionar oficial", - "customsTitle": "Modelos personalizados", - "customsEmpty": "Ainda não há modelos personalizados.", - "addCustom": "Adicionar personalizado", - "slugPlaceholder": "id do modelo (slug)", - "displayNamePlaceholder": "Nome de exibição", - "contextWindow": "Contexto", - "makeDefault": "Definir como padrão", - "defaultHint": "Modelo padrão", - "remove": "Remover", - "advanced": "Avançado", - "baseTemplate": "Modelo base", - "baseTemplateHint": "Modelo oficial do qual clonar os campos obrigatórios (prompt do sistema, ferramentas, limites).", - "groupBehavior": "Comportamento e recursos", - "fieldReasoningLevel": "Raciocínio padrão", - "fieldReasoningSummary": "Resumo do raciocínio", - "fieldVerbosity": "Verbosidade", - "fieldShellType": "Tipo de shell", - "fieldApplyPatch": "Ferramenta apply-patch", - "fieldReasoningSummaries": "Resumos de raciocínio", - "fieldSupportVerbosity": "Controle de verbosidade", - "fieldParallelToolCalls": "Chamadas de ferramentas em paralelo", - "fieldSearchTool": "Ferramenta de busca na web", - "optNone": "Nenhum", - "groupInstructions": "Descrição e prompt do sistema", - "fieldDescription": "Descrição", - "baseInstructions": "Prompt do sistema (base_instructions)" - }, - "DiagnosticsSettings": { - "title": "Diagnóstico do ambiente", - "description": "Verifica como este app resolve a CLI do agente no próprio processo, que pode diferir do seu terminal.", - "loading": "Executando diagnóstico…", - "error": "Falha no diagnóstico", - "rerun": "Executar novamente", - "copyAll": "Copiar tudo", - "copied": "Diagnóstico copiado para a área de transferência", - "button": "Diagnosticar", - "verdict": { - "ok": "O ambiente parece saudável. Se ainda aparecer como não instalado, reinicie o app completamente para atualizar o cache do prefixo.", - "node_missing": "Node.js não foi encontrado no PATH do app.", - "npm_missing": "npm não foi encontrado no PATH do app.", - "not_installed": "Este agente não parece estar instalado.", - "installed_but_unresolved": "Consta como instalado, mas o app não consegue localizar o executável.", - "user_prefix_not_on_path": "Instalado no prefixo de fallback (~/.codeg/npm-global), que não está no PATH do app. Reinicie o app completamente e tente novamente.", - "homebrew_bin_not_on_path": "Instalado no bin do Homebrew, que não está no PATH do app (divisão de keg no Apple Silicon).", - "terminal_only_path": "O comando é resolvido no seu terminal, mas não no app: uma diferença de PATH da GUI. Inicie o app por um terminal ou reinstale nas Configurações de agentes.", - "npm_prefix_timeout": "npm prefix -g foi muito lento (mais de 1,5 s), então a detecção de fallback foi ignorada. Reinicie o app e tente novamente.", - "node_too_old": "Seu Node.js ativo é mais antigo do que este agente requer. Atualize o Node.js.", - "adapter_missing_native_present": "A sua CLI do {agent} está instalada, mas o Codeg inicia um pacote adaptador ACP separado — e esse ainda não está. Instale-o nas configurações de agentes: ele não mexe na sua CLI e compartilha o mesmo login.", - "adapter_missing": "O Codeg inicia um pacote adaptador ACP separado para o {agent}, e ele ainda não está instalado. Instale-o nas configurações de agentes — instalar só a CLI do fornecedor não basta." - } - }, - "TokenUsage": { - "title": "Uso de tokens", - "rangeLabel": "Período", - "range7d": "7 dias", - "range30d": "30 dias", - "range90d": "90 dias", - "rangeThisMonth": "Este mês", - "rangeThisYear": "Este ano", - "rangeAll": "Tudo", - "rangeCustom": "Personalizado", - "moreRanges": "Mais", - "customRangePick": "Escolher um período", - "bucketLabel": "Agrupar por", - "bucketDay": "Dia", - "bucketWeek": "Semana", - "bucketMonth": "Mês", - "bucketUnitDay": "Dia", - "bucketUnitWeek": "Semana", - "bucketUnitMonth": "Mês", - "folderFilter": "Pastas", - "allFolders": "Todas as pastas", - "agentFilter": "Agentes", - "allAgents": "Todos os agentes", - "modelFilter": "Modelos", - "allModels": "Todos os modelos", - "searchPlaceholder": "Pesquisar…", - "noMatches": "Nenhum resultado", - "clearFilter": "Limpar seleção", - "resetFilters": "Limpar filtros", - "refresh": "Atualizar", - "rebuild": "Reconstruir tudo", - "rebuildHint": "Descarta o que já foi contabilizado e relê todas as transcrições. Útil se uma sessão cresceu fora do codeg.", - "syncing": "Contando sessões…", - "syncProgress": "{done} / {total}", - "syncDone": "{synced} sessões contabilizadas", - "syncFailed": "Não foi possível ler algumas sessões", - "syncBusy": "Já existe uma atualização em andamento", - "lastSynced": "Atualizado {time}", - "lastSyncedNever": "Nunca atualizado", - "tileTotal": "Tokens totais", - "tileSessions": "Sessões", - "tileTurns": "Turnos", - "tileActiveDays": "Dias ativos", - "tileGenTime": "Tempo de geração", - "vsPrevious": "vs. período anterior", - "deltaNew": "novo", - "trendTitle": "Uso ao longo do tempo", - "trendEmpty": "Sem uso neste período", - "trendTurns": "Turnos", - "trendSessions": "Sessões", - "compositionTitle": "Para onde foram os tokens", - "compositionHint": "Entrada é o que você enviou, saída é o que o modelo escreveu e leituras de cache são contexto que não custou preço cheio.", - "compositionNote": "Reenviar esses acertos de cache a preço cheio custaria mais {value}.", - "inputTokens": "Entrada", - "outputTokens": "Saída", - "cacheWrite": "Escrita de cache", - "cacheRead": "Leitura de cache", - "freshTokens": "Cômputo novo", - "cacheHitCaption": "Acerto de cache", - "cacheHeroTitleHigh": "A maior parte do contexto não precisou ser reenviada", - "cacheHeroTitleLow": "A maior parte do contexto ainda é calculada a preço cheio", - "cacheHeroDesc": "O cache carregou {cached} de contexto; só {fresh} foi de fato calculado de novo no período.", - "cacheSavedSuffix": "Isso poupou reenviar o equivalente a {saved}.", - "avgPerSession": "Média por sessão", - "avgTurnsPerSession": "{count} turnos por sessão em média", - "avgPerActiveDay": "Média por dia ativo", - "peakBucket": "{bucket} de pico", - "peakHour": "Hora de pico", - "daysValue": "{count} dias", - "idleDays": "Dias parados", - "byFolderTitle": "Por pasta", - "byAgentTitle": "Por agente", - "byModelTitle": "Por modelo", - "distributionTitle": "Distribuição de uso", - "distributionHint": "Sessões e tokens agrupados pela dimensão escolhida — clique numa linha para filtrar.", - "otherLabel": "Outros", - "unknownModel": "Modelo não registrado", - "emptyBreakdown": "Nada registrado ainda", - "sessionsCount": "{count} sessões", - "heatmapTitle": "Quando você programa", - "heatmapHint": "Tokens por dia da semana e hora local.", - "heatmapPeakHint": "Mais denso por volta das {hour}:00.", - "less": "Menos", - "more": "Mais", - "heatmapCell": "{weekday} {hour}:00 — {value} tokens", - "weekMon": "Seg", - "weekTue": "Ter", - "weekWed": "Qua", - "weekThu": "Qui", - "weekFri": "Sex", - "weekSat": "Sáb", - "weekSun": "Dom", - "topSessionsTitle": "Sessões mais pesadas", - "untitledSession": "Sessão sem título", - "topSessionsEmpty": "Sem sessões neste período", - "streakLongest": "Maior sequência", - "streakLongestDays": "Maior sequência: {count} dias", - "share": "Compartilhar", - "moreActions": "Mais ações", - "shareDialogTitle": "Compartilhe seu cartão de uso", - "shareDialogHint": "Um retrato do período e dos filtros que você está vendo.", - "shareSave": "Salvar imagem", - "shareCopy": "Copiar imagem", - "shareCopied": "Copiado para a área de transferência", - "shareSaved": "Imagem salva", - "shareFailed": "Não foi possível criar a imagem", - "shareRendering": "Gerando…", - "cardHeading": "Minhas estatísticas de código com IA", - "cardRangeAll": "Todo o período", - "cardTotalLabel": "Tokens usados", - "cardFooter": "Feito com codeg", - "cardTopModels": "Principais modelos", - "cardTopProjects": "Principais projetos", - "archetypeNightOwl": "Coruja noturna", - "archetypeNightOwlDesc": "{percent}% dos seus tokens queimam depois do anoitecer.", - "archetypeEarlyBird": "Madrugador", - "archetypeEarlyBirdDesc": "{percent}% dos seus tokens acontecem antes das 9h.", - "archetypeWeekendWarrior": "Guerreiro de fim de semana", - "archetypeWeekendWarriorDesc": "{percent}% dos seus tokens acontecem no fim de semana.", - "archetypeCacheMaster": "Mestre do cache", - "archetypeCacheMasterDesc": "{percent}% do seu contexto veio do cache.", - "archetypeMarathoner": "Maratonista", - "archetypeMarathonerDesc": "{days} dias programando sem parar.", - "archetypePolyglot": "Polivalente", - "archetypePolyglotDesc": "{count} agentes em uso pesado.", - "archetypeLaserFocus": "Foco total", - "archetypeLaserFocusDesc": "{percent}% dos seus tokens foram para um único projeto.", - "archetypeDeepDiver": "Mergulhador", - "archetypeDeepDiverDesc": "{averageK}K tokens numa sessão média.", - "archetypeSteady": "Construtor constante", - "archetypeSteadyDesc": "{days} dias entregando.", - "emptyTitle": "Nada contabilizado ainda", - "emptyHint": "O codeg lê os tokens direto da transcrição de cada agente. Atualize para contabilizar o que já existe nesta máquina.", - "emptyAction": "Contabilizar minhas sessões", - "loadFailed": "Não foi possível carregar o uso", - "truncatedNotice": "Este período é muito amplo — os números cobrem apenas o trecho mais recente." - } -} +{ + "Language": { + "followSystem": "Seguir o sistema", + "english": "Inglês", + "simplifiedChinese": "Chinês simplificado", + "traditionalChinese": "Chinês tradicional", + "japanese": "Japonês", + "korean": "Coreano", + "spanish": "Espanhol", + "german": "Alemão", + "french": "Francês", + "portuguese": "Português", + "arabic": "Árabe" + }, + "GitCredentialDialog": { + "title": "Autenticação necessária", + "description": "O servidor remoto requer credenciais. Insira seu nome de usuário e senha (ou token de acesso pessoal).", + "username": "Nome de usuário", + "usernamePlaceholder": "Nome de usuário ou e-mail", + "password": "Senha / Token", + "passwordPlaceholder": "Senha ou token de acesso pessoal", + "passwordHint": "Insira o nome de usuário e a senha do servidor.", + "cancel": "Cancelar", + "authenticate": "Autenticar", + "authenticating": "Autenticando...", + "invalidCredentials": "Credenciais inválidas. Tente novamente.", + "saveCredentials": "Salvar credenciais para operações futuras", + "githubTitle": "Autenticação do GitHub", + "githubDescription": "Insira um token de acesso pessoal para se conectar ao GitHub. O token será validado e salvo automaticamente.", + "githubToken": "Token de acesso pessoal", + "githubTokenPlaceholder": "ghp_xxxxxxxxxxxx", + "githubTokenHint": "Gere um token em GitHub → Settings → Developer settings → Personal access tokens.", + "githubAuthenticate": "Validar e conectar", + "generateToken": "Gerar token" + }, + "SettingsShell": { + "title": "Configurações", + "preferences": "Preferências", + "nav": { + "general": "Geral", + "appearance": "Aparência", + "agents": "Agentes", + "mcp": "MCP", + "skills": "Skills", + "shortcuts": "Atalhos", + "version_control": "Controle de versão", + "system": "Sistema", + "chat_channels": "Canais de chat", + "web_service": "Serviço Web", + "model_providers": "Provedores de Modelos", + "experts": "Especialistas", + "science": "Ciência", + "office_tools": "Ferramentas de escritório", + "skill_packs": "Pacotes de habilidades", + "quick_messages": "Mensagens rápidas", + "logs": "Registros de execução" + } + }, + "AppearanceSettings": { + "sectionTitle": "Aparência do tema", + "sectionDescription": "Escolha claro, escuro ou seguir o sistema. As configurações são salvas automaticamente.", + "themeMode": "Modo de tema", + "placeholder": "Selecionar modo de tema", + "system": "Seguir o sistema", + "light": "Claro", + "dark": "Escuro", + "currentTheme": "Tema efetivo atual: {theme}", + "resolvedTheme": { + "light": "Claro", + "dark": "Escuro", + "unknown": "--" + }, + "themeColor": { + "sectionTitle": "Cor do tema", + "sectionDescription": "Escolha uma paleta de cores para acentos, botões e destaques.", + "current": "Cor atual: {color}", + "options": { + "neutral": "Neutral", + "zinc": "Zinc", + "slate": "Slate", + "stone": "Stone", + "gray": "Gray", + "red": "Red", + "rose": "Rose", + "orange": "Orange", + "green": "Green", + "blue": "Blue", + "yellow": "Yellow", + "violet": "Violet" + } + }, + "customStyle": { + "sectionTitle": "Estilo personalizado", + "sectionDescription": "Ajuste as cores do tema atual ou injete o seu próprio CSS. As substituições ficam sobre a predefinição base, por isso permanecem ao trocar de predefinição.", + "summarySuspended": "Suspenso", + "summaryDefault": "Predefinição inalterada", + "summaryTokens": "{count, plural, one {# substituição} other {# substituições}}", + "summaryCss": "CSS personalizado", + "suspendedByShortcut": "O estilo personalizado está suspenso. Nada do que definir aqui terá efeito até retomá-lo.", + "suspendedBySafeParam": "Esta janela foi aberta no modo de aparência segura, por isso o estilo personalizado é ignorado aqui. As outras janelas não são afetadas.", + "resume": "Retomar estilo personalizado", + "enableTheme": "Ativar cores personalizadas", + "editingLight": "A editar os valores do modo claro. Mude a aplicação para o modo escuro para o definir em separado.", + "editingDark": "A editar os valores do modo escuro. Mude a aplicação para o modo claro para o definir em separado.", + "resetToken": "Repor o valor da predefinição", + "radius": "Raio dos cantos", + "radiusHint": "Toda a escala de raios, de sm a 4xl, deriva dele: um único cursor arredonda a aplicação inteira.", + "advanced": "Avançado (mais {count} variáveis)", + "enableCss": "Ativar CSS personalizado", + "cssRisk": "Funcionalidade avançada. O CSS personalizado substitui todos os estilos integrados e pode tornar a interface inutilizável.", + "editCss": "Editar CSS…", + "cssPresent": "{size} KB guardados", + "cssEmpty": "Ainda não há nada guardado", + "escapeHint": "Interface estragada? Prima {shortcut} para suspender todo o estilo personalizado, ou abra uma janela com o parâmetro safeStyle=1.", + "copyTheme": "Copiar JSON do tema", + "importTheme": "Importar tema…", + "clearTheme": "Limpar substituições", + "interopHint": "Os temas usam o formato registry:theme do shadcn, por isso pode colar aqui qualquer tema shadcn e usar os exportados em qualquer projeto shadcn.", + "importTitle": "Importar tema", + "importDescription": "Cole um item registry:theme do shadcn, um objeto light/dark simples ou um mapa plano de tokens.", + "readClipboard": "Ler área de transferência", + "importConfirm": "Importar", + "cancel": "Cancelar", + "apply": "Aplicar", + "toasts": { + "copied": "JSON do tema copiado", + "copyFailed": "Não foi possível copiar para a área de transferência", + "clipboardReadFailed": "Não foi possível ler a área de transferência, cole manualmente", + "importFailed": "Esse JSON não contém variáveis de tema utilizáveis", + "imported": "Tema importado" + }, + "css": { + "dialogTitle": "CSS personalizado", + "dialogDescription": "Aplica-se a todas as janelas do codeg. As alterações são pré-visualizadas ao vivo; carregue em Aplicar para guardar.", + "size": "{used} KB / {max} KB", + "ruleCount": "{count} regras", + "errorTooLarge": "Demasiado grande para guardar. Reduza abaixo do limite.", + "errorImportEscaped": "Uma regra @import sobreviveu à remoção (sintaxe com escapes). Remova-a para guardar.", + "warnNoRules": "Nenhuma regra foi analisada; verifique a sintaxe.", + "noticeImportsRemoved": "Regras @import removidas: {count}. Iriam obter folhas de estilo remotas.", + "noticeRemoteUrl": "Contém um url() remoto, que fará um pedido de rede ao ser aplicado.", + "noticePreviewSuspended": "O estilo personalizado está suspenso, por isso esta pré-visualização não é aplicada.", + "noticeDisabled": "O CSS personalizado está desativado. Pode pré-visualizar aqui, mas nada se aplica até o ativar.", + "hintTokens": "Dica: as cores que substituiu ficam disponíveis como var(--primary), var(--background), etc." + } + }, + "zoomLevel": { + "sectionTitle": "Zoom da janela", + "sectionDescription": "Dimensiona toda a interface. Aplica imediatamente e é salvo por dispositivo.", + "placeholder": "Selecione o nível de zoom", + "default": "Padrão", + "current": "Zoom atual: {zoom}%" + }, + "fonts": { + "sectionTitle": "Fontes", + "sectionDescription": "Escolha as fontes para a interface, o editor de código e o terminal. As fontes incluídas são carregadas sob demanda; selecione “Personalizada…” para usar qualquer fonte instalada no seu sistema.", + "interface": "Interface", + "editor": "Editor", + "terminal": "Terminal", + "groupSans": "Sem serifa", + "groupMono": "Monoespaçada", + "custom": "Personalizada…", + "customPlaceholder": "Nome da fonte, ex.: Fira Code", + "fontSize": "Tamanho da fonte", + "ligatures": "Ativar ligaduras", + "ligaturesUnavailable": "Esta fonte não tem ligaduras", + "wordWrap": "Ativar quebra de linha", + "terminalLigaturesHint": "As ligaduras do terminal aplicam-se apenas às fontes de programação incluídas.", + "preview": "Pré-visualização" + }, + "welcomePanel": { + "sectionTitle": "Área de seleção de modo", + "sectionDescription": "Os cartões de atalho «Desenvolvimento / Escritório» exibidos acima do campo de entrada na página de nova conversa.", + "showQuickActions": "Mostrar na página de nova conversa" + }, + "workspaceBackground": { + "sectionTitle": "Plano de fundo da área de trabalho", + "sectionDescription": "Mostra uma imagem atrás de toda a área de trabalho. A barra lateral e os painéis ficam translúcidos e foscos para deixar a imagem transparecer, e uma máscara mantém o texto legível.", + "enable": "Ativar imagem de fundo", + "image": "Imagem", + "chooseImage": "Escolher imagem", + "replaceImage": "Substituir imagem", + "removeImage": "Remover", + "fillMode": "Modo de preenchimento", + "fillModes": { + "cover": "Preencher", + "contain": "Ajustar", + "center": "Centralizar", + "tile": "Lado a lado" + }, + "maskOpacity": "Opacidade da máscara", + "maskOpacityHint": "Valores mais altos esmaecem a imagem em direção à cor de fundo do tema, melhorando o contraste do texto.", + "imageBlur": "Desfoque da imagem", + "panelOpacity": "Opacidade dos painéis", + "panelOpacityHint": "O quão opacos são a barra lateral, os painéis e as barras de abas. Mais baixo deixa a imagem transparecer mais.", + "errorTooLarge": "A imagem é muito grande (máx. 16 MB).", + "errorUploadFailed": "Falha ao definir a imagem de fundo." + } + }, + "SystemSettings": { + "loading": "Carregando...", + "sectionTitle": "Gerenciamento do sistema", + "sectionDescription": "Gerencie proxy de rede, atualizações do app e preferências de idioma.", + "proxyTitle": "Proxy de rede", + "proxyDescription": "Quando ativado, as solicitações de rede seguintes priorizam este proxy (incluindo chat ACP, instalação de agentes e operações remotas do Git).", + "loadFailed": "Falha ao carregar: {message}", + "enableProxy": "Ativar proxy do sistema", + "proxyAddress": "Endereço do proxy", + "proxyHint": "Suporta http(s)/socks5, exemplo: {example}. Só funciona quando o proxy do sistema está ativado.", + "save": "Salvar", + "saving": "Salvando...", + "proxyRequired": "A URL do proxy é obrigatória quando o proxy está ativado", + "saveSuccess": "As configurações de proxy do sistema foram salvas", + "saveFailed": "Falha ao salvar: {message}", + "languageTitle": "Idioma", + "languageDescription": "Defina o idioma do app. Ao seguir o idioma do sistema, idiomas não suportados voltam para inglês.", + "appLanguage": "Idioma do app", + "languageSaveSuccess": "As configurações de idioma foram salvas", + "languageSaveFailed": "Falha ao salvar as configurações de idioma: {message}", + "updateTitle": "Atualização do app", + "versionTitle": "Atualização de software", + "updateDescription": "Verifique versões mais novas na fonte de releases configurada e instale diretamente quando disponíveis.", + "currentVersion": "Versão atual", + "upgradableVersion": "Versão mais recente", + "none": "Nenhuma", + "lastChecked": "Última verificação: {time}", + "updateError": "Erro de atualização: {message}", + "checking": "Verificando...", + "checkUpdate": "Verificar atualizações", + "updating": "Instalando...", + "downloading": "Baixando...", + "upgradeTo": "Atualizar para v{version}", + "viewRelease": "Ver lançamento v{version}", + "foundUpdate": "Nova versão v{version} encontrada", + "alreadyLatest": "Você já está na versão mais recente", + "checkUpdateFailed": "Falha ao verificar atualizações: {message}", + "installSuccess": "Atualização instalada. Reiniciando o app.", + "installFailed": "Falha na atualização: {message}", + "upgradeSuccess": "Atualização concluída. Recarregando...", + "restartTimeout": "O servidor não voltou a tempo. Verifique os logs do contêiner ou do serviço.", + "restartingIn": "Reiniciando em {seconds} s...", + "waitingForServer": "Aguardando o servidor voltar...", + "restartToUpdate": "Reiniciar para atualizar", + "newVersionBadge": "Nova v{version}", + "updateAvailableTitle": "Atualização disponível", + "releaseNotesTitle": "Novidades", + "remindLater": "Mais tarde", + "retry": "Tentar novamente", + "stepDownload": "Download", + "stepInstall": "Instalação", + "stepRestart": "Reinício", + "updateReadyHint": "Atualização baixada — reinicie para aplicar.", + "restarting": "Reiniciando...", + "dockerUpgradeHint": "Isto atualiza o contêiner em execução agora. Perde-se se o contêiner for recriado — para mantê-lo, baixe ou crie uma imagem na nova versão e recrie o contêiner.", + "upgradeRolledBack": "Falha na atualização; o servidor reverteu para a versão anterior.", + "serverUnreachable": "Não foi possível acessar o servidor para iniciar a atualização. Verifique se ele está em execução e tente novamente.", + "rollbackButton": "Reverter", + "rollingBack": "Revertendo...", + "rollbackDescription": "Restaura a versão instalada antes da última atualização.", + "rollbackConfirmTitle": "Reverter para a versão anterior?", + "rollbackConfirmDescription": "O servidor será reiniciado na versão instalada antes da última atualização. Uma versão mais recente continua disponível para instalar novamente.", + "rollbackConfirm": "Reverter", + "rollbackCancel": "Cancelar", + "rollbackSuccess": "Revertido para a versão anterior. Recarregando...", + "rollbackFailed": "Falha ao reverter. Verifique os registros do servidor.", + "updateErrors": { + "sourceUnavailable": "Não foi possível acessar a fonte de atualização. Verifique sua rede ou proxy e tente novamente.", + "network": "Falha na conexão de rede. Verifique sua rede ou proxy e tente novamente.", + "downloadFailed": "Falha ao baixar o pacote de atualização. Tente novamente mais tarde.", + "installFailed": "Falha ao instalar a atualização. Feche o app e tente novamente.", + "unknown": "Falha na atualização. Tente novamente mais tarde." + } + }, + "VersionControlSettings": { + "loading": "Carregando...", + "sectionTitle": "Controle de versão", + "sectionDescription": "Configure o executável Git e gerencie contas do GitHub.", + "gitTitle": "Configuração do Git", + "gitDescription": "Configure o executável Git usado pelo aplicativo.", + "gitDetected": "Git detectado", + "gitNotFound": "Git não encontrado no sistema", + "gitVersion": "Versão", + "gitPath": "Caminho", + "customGitPath": "Caminho personalizado do Git", + "customGitPathPlaceholder": "/usr/bin/git", + "customGitPathHint": "Deixe vazio para usar o caminho detectado automaticamente.", + "test": "Testar", + "testing": "Testando...", + "testSuccess": "Executável Git é válido.", + "testFailed": "Teste do Git falhou: {message}", + "save": "Salvar", + "saving": "Salvando...", + "saveSuccess": "Configurações do Git salvas.", + "saveFailed": "Falha ao salvar: {message}", + "githubTitle": "Contas do GitHub", + "githubDescription": "Gerencie contas do GitHub para autenticação. Os tokens são armazenados localmente.", + "noAccounts": "Nenhuma conta do GitHub configurada.", + "addAccount": "Adicionar conta", + "serverUrl": "URL do servidor", + "serverUrlPlaceholder": "https://github.com", + "token": "Token de acesso pessoal", + "tokenPlaceholder": "ghp_xxxxxxxxxxxx", + "generateToken": "Gerar token", + "tokenHint": "Gere um token em GitHub → Settings → Developer settings → Personal access tokens.", + "validateAndAdd": "Validar e adicionar", + "validating": "Validando...", + "addSuccess": "Conta {username} adicionada com sucesso.", + "addFailed": "Falha ao adicionar conta: {message}", + "testConnection": "Testar", + "connectionSuccess": "Conexão bem-sucedida.", + "connectionFailed": "Falha na conexão: {message}", + "setDefault": "Definir como padrão", + "defaultLabel": "Padrão", + "defaultSet": "Conta padrão atualizada.", + "removeAccount": "Remover", + "removeConfirmTitle": "Remover conta", + "removeConfirmMessage": "Tem certeza de que deseja remover a conta \"{username}\"?", + "removeConfirm": "Remover", + "removeCancel": "Cancelar", + "removeSuccess": "Conta removida.", + "scopes": "Escopos", + "loadFailed": "Falha ao carregar configurações: {message}", + "gitAccount": { + "sectionTitle": "Contas de servidor Git", + "sectionDescription": "Gerencie credenciais para servidores Git que não são GitHub (GitLab, Bitbucket, auto-hospedados, etc.).", + "noAccounts": "Nenhuma conta de servidor Git configurada.", + "addAccount": "Adicionar conta", + "addTitle": "Adicionar conta Git", + "addDescription": "Insira o endereço do servidor, nome de usuário e senha ou token de acesso.", + "serverUrl": "URL do servidor", + "serverUrlPlaceholder": "https://gitlab.example.com", + "username": "Nome de usuário", + "usernamePlaceholder": "Nome de usuário ou e-mail", + "password": "Senha / Token", + "passwordPlaceholder": "Senha ou token de acesso", + "passwordHint": "Insira a senha ou o token de acesso do servidor.", + "add": "Adicionar", + "serverRequired": "A URL do servidor é obrigatória.", + "usernameRequired": "O nome de usuário é obrigatório.", + "passwordRequired": "A senha é obrigatória." + } + }, + "ShortcutSettings": { + "sectionTitle": "Atalhos", + "resetDefault": "Restaurar padrões", + "recordInstruction": "Clique no botão à direita e pressione uma combinação de teclas. Use Ctrl/Cmd, Alt e Shift. Pressione Esc para cancelar a gravação.", + "recording": "Pressione um atalho...", + "toasts": { + "conflict": "O atalho já está em uso por \"{title}\"", + "updated": "Atalho atualizado", + "invalid": "Atalho inválido, tente novamente", + "reset": "Atalhos padrão restaurados" + }, + "actions": { + "toggle_search": { + "title": "Abrir busca", + "description": "Mostra ou oculta o painel de busca de conversas" + }, + "toggle_sidebar": { + "title": "Alternar barra lateral esquerda", + "description": "Mostra ou oculta a barra lateral da lista de conversas" + }, + "toggle_terminal": { + "title": "Alternar terminal", + "description": "Mostra ou oculta o painel de terminal inferior" + }, + "new_terminal_tab": { + "title": "Novo terminal", + "description": "Cria uma nova aba de terminal quando o foco está no terminal" + }, + "close_current_terminal_tab": { + "title": "Fechar terminal atual", + "description": "Fecha a aba de terminal atual quando o foco está no terminal" + }, + "toggle_aux_panel": { + "title": "Alternar painel direito", + "description": "Mostra ou oculta o painel de informações auxiliares" + }, + "new_conversation": { + "title": "Nova conversa", + "description": "Cria uma nova aba de conversa na pasta atual" + }, + "open_folder": { + "title": "Abrir pasta", + "description": "Abre o seletor de pastas e abre em uma nova janela" + }, + "open_settings": { + "title": "Abrir configurações", + "description": "Abre a janela de configurações" + }, + "close_current_tab": { + "title": "Fechar aba atual", + "description": "Fecha a conversa atual ou aba de arquivo" + }, + "close_all_file_tabs": { + "title": "Fechar todas as abas de arquivo", + "description": "Fecha todas as abas de arquivo abertas quando o painel de arquivos está ativo" + }, + "next_tab": { + "title": "Próxima aba", + "description": "Mudar para a próxima aba de conversa ou arquivo" + }, + "prev_tab": { + "title": "Aba anterior", + "description": "Mudar para a aba anterior de conversa ou arquivo" + }, + "send_message": { + "title": "Enviar mensagem", + "description": "Enviar a mensagem atual na caixa de entrada" + }, + "newline_in_message": { + "title": "Nova linha na mensagem", + "description": "Inserir uma nova linha na caixa de entrada" + }, + "toggle_custom_style": { + "title": "Suspender/retomar estilo personalizado", + "description": "Saída de emergência: desliga todas as cores e o CSS personalizados e volta a ligá-los" + } + } + }, + "SkillsSettings": { + "title": "Skills", + "description": "Selecione uma Skill à esquerda. À direita, a prévia em Markdown é mostrada por padrão; mude para edição para modificar e salvar.", + "loadingAgents": "Carregando agentes que suportam Skills...", + "emptyNoManageableAgents": "Não há agentes disponíveis para gerenciamento de Skills.", + "managedTarget": "Alvo gerenciado", + "selectAgentPlaceholder": "Selecione um agente", + "searchPlaceholder": "Pesquisar por nome / ID / caminho...", + "skillsList": "Lista de Skills", + "loadingSkills": "Carregando Skills...", + "agentNotSupported": "O agente atual não suporta gerenciamento de Skills.", + "emptySkills": "Ainda não há Skills. Clique em \"Nova Skill\" para criar uma.", + "newSkillTitle": "Nova Skill", + "skillInfo": "Informações da Skill", + "skillIdPlaceholder": "skill-id (letras/números/-/_/.)", + "skillsDirectoryWithPath": "Diretório de Skills: {path}", + "skillsDirectoryNeedId": "Diretório de Skills: digite o ID da Skill para gerar o caminho completo", + "markdownContent": "Conteúdo Markdown", + "editingStatus": "Editando", + "previewStatus": "Visualizando", + "contentPlaceholder": "Digite o conteúdo Markdown da Skill...", + "metadataTitle": "Metadados de Skills", + "onlyYamlMetadata": "Esta Skill contém apenas metadados YAML.", + "emptyContentHint": "Ainda não há conteúdo. Clique em \"Editar\" para começar.", + "loadingSkill": "Carregando Skill...", + "emptyNoAgents": "Nenhum agente disponível.", + "noSelectionHint": "Selecione um Skill à esquerda ou clique em \"Novo Skill\" para criar um.", + "systemBadge": "Sistema", + "systemHint": "Skill integrado do CLI · somente leitura", + "scope": { + "global": "Global", + "folder": "Pasta", + "selectFolderPlaceholder": "Selecionar uma pasta", + "noFolders": "Nenhuma pasta encontrada", + "pickFolderHint": "Selecione uma pasta para ver suas Skills." + }, + "actions": { + "preview": "Prévia", + "edit": "Editar", + "openInWindow": "Abrir em nova janela", + "delete": "Excluir", + "deleting": "Excluindo...", + "refresh": "Atualizar", + "newSkill": "Nova Skill", + "reset": "Redefinir", + "save": "Salvar", + "saving": "Salvando...", + "cancel": "Cancelar" + }, + "deleteDialog": { + "title": "Excluir Skill", + "confirm": "Excluir a Skill atual? Esta ação não pode ser desfeita.", + "confirmWithNamePrefix": "Excluir Skill", + "confirmWithNameSuffix": "? Esta ação não pode ser desfeita." + }, + "toasts": { + "loadFailed": "Falha ao carregar Skill", + "openFolderFailed": "Falha ao abrir pasta", + "noSkillDirectory": "Nenhum diretório de Skills disponível para o agente atual", + "nameRequired": "O nome da Skill não pode estar vazio", + "updated": "Skill atualizada", + "created": "Skill criada", + "saveFailed": "Falha ao salvar Skill", + "deleted": "Skill excluída", + "deleteFailed": "Falha ao excluir Skill" + }, + "templates": { + "gemini": "---\nname: example-skill\ndescription: Describe when this skill should be used.\n---\n\n# Skill Name\n\nInstructions for the agent when this skill is active.\n\n## Workflow\n\n1. Add actionable step one.\n2. Add actionable step two.\n", + "openCode": "---\nname: example-skill\ndescription: Describe when this skill should be used.\n---\n\n# Purpose\n\nDescribe what this skill helps with.\n\n# Steps\n\n1. Add actionable step one.\n2. Add actionable step two.\n", + "openClaw": "---\nname: example-skill\ndescription: Describe when this skill should be used.\nuser-invocable: true\ndisable-model-invocation: false\n---\n\n# Purpose\n\nDescribe what this skill helps with.\n\n# Instructions\n\n1. Add actionable instruction one.\n2. Add actionable instruction two.\n", + "default": "---\nname: example-skill\ndescription: Describe when this skill should be used.\n---\n\n# Skill: example-skill\n\n## When to use\n\n- Describe trigger conditions.\n\n## Instructions\n\n1. Add actionable instruction one.\n2. Add actionable instruction two.\n" + } + }, + "McpSettings": { + "loading": "Carregando...", + "summary": { + "missingCommand": "(comando ausente)", + "missingUrl": "(URL ausente)" + }, + "protocol": { + "stdio": "Stdio" + }, + "errors": { + "selectInstallProtocol": "Selecione um protocolo de instalação", + "fieldRequired": "{field} é obrigatório", + "fieldNeedsBoolean": "{field} deve ser true ou false", + "fieldNeedsNumber": "{field} deve ser um número", + "fieldNeedsInteger": "{field} deve ser um inteiro", + "fieldInvalidJson": "{field} tem JSON inválido: {message}", + "fieldOutOfRange": "O valor de {field} está fora do intervalo permitido", + "jsonEmpty": "{name} não pode estar vazio", + "jsonInvalid": "{name} não é um JSON válido: {message}", + "jsonMustBeObject": "{name} deve ser um objeto JSON", + "specMustBeObject": "A configuração do MCP deve ser um objeto JSON.", + "missingType": "Falta o campo type na configuração do MCP. Use stdio, http (aliases: streamable-http, streamableHttp) ou sse.", + "unsupportedType": "Tipo de MCP não suportado {type}. Suportados: stdio, http (aliases: streamable-http, streamableHttp), sse.", + "codexEntryUnsupportedType": "A entrada Codex MCP {id} tem tipo não suportado {type}. Suportados: stdio, http (aliases: streamable-http, streamableHttp), sse.", + "unsupportedTransportType": "Tipo de transport não suportado {type}. Suportados: http (aliases: streamable-http, streamableHttp), sse.", + "stdioCommandRequired": "Um MCP stdio exige um campo command não vazio.", + "remoteUrlRequired": "Um MCP remoto exige um campo url não vazio.", + "appsRequired": "Selecione ao menos um aplicativo alvo." + }, + "jsonNames": { + "localConfig": "Configuração MCP", + "installConfig": "Configuração de instalação" + }, + "toasts": { + "uninstalled": "MCP desinstalado", + "uninstallFailed": "Falha ao desinstalar: {message}", + "selectAtLeastOneApp": "Selecione pelo menos um app de destino", + "saveSuccess": "Salvo", + "saveFailed": "Falha ao salvar: {message}", + "installed": "{name} instalado", + "installFailed": "Falha na instalação: {message}", + "serverIdRequired": "O Server ID é obrigatório", + "serverIdExists": "O Server ID \"{id}\" já existe. Edite a entrada existente ou escolha outro nome.", + "created": "MCP criado" + }, + "installDialog": { + "title": "Confirmar instalação do MCP", + "descriptionWithName": "Instalar {name} na configuração local.", + "description": "Selecione os apps de destino para instalação.", + "protocol": "Protocolo", + "selectProtocol": "Selecionar protocolo", + "parameters": "Parâmetros de configuração", + "booleanPlaceholder": "Selecione true/false", + "selectOneValue": "Selecione um valor", + "targetApps": "Apps de destino" + }, + "actions": { + "cancel": "Cancelar", + "confirmInstall": "Confirmar instalação", + "installing": "Instalando", + "uninstall": "Desinstalar", + "uninstalling": "Desinstalando", + "viewDetails": "Ver detalhes", + "save": "Salvar", + "saving": "Salvando", + "install": "Instalar", + "refresh": "Atualizar", + "newMcp": "Novo MCP", + "create": "Criar", + "creating": "Criando..." + }, + "tabs": { + "local": "MCP local", + "market": "Marketplace MCP" + }, + "local": { + "filterPlaceholder": "Filtrar MCP local...", + "loadFailed": "Falha ao carregar: {message}", + "empty": "Nenhum MCP local detectado.", + "description": "A configuração local de MCP pode ser editada e salva diretamente.", + "enabledApps": "Apps habilitados", + "configJson": "Configuração MCP (JSON)", + "draftTitle": "Novo MCP", + "draftDescription": "Informe um Server ID e a configuração para criar um servidor MCP local.", + "serverIdLabel": "Server ID", + "serverIdPlaceholder": "Server ID (ex.: my-mcp)", + "typeHint": "Tipos suportados: stdio, http (aliases: streamable-http, streamableHttp), sse. env só é usado por stdio; para MCPs remotos use headers para transportar tokens de autenticação.", + "envOnRemoteWarning": "env detectado em um MCP remoto. Apenas stdio usa env; MCPs remotos transportam tokens de autenticação via headers, portanto env será ignorado ao salvar." + }, + "market": { + "selectMarketplace": "Selecionar marketplace", + "searchPlaceholder": "Pesquisar MCP...", + "searchFailed": "Falha na busca: {message}", + "loadingList": "Carregando lista de MCP...", + "empty": "Nenhum resultado de MCP.", + "loadingDetail": "Carregando detalhes do marketplace...", + "detailLoadFailed": "Falha ao carregar detalhes: {message}", + "owner": "Proprietário: {owner}", + "namespace": "Namespace: {namespace}", + "defaultInstallProtocol": "Protocolo de instalação padrão", + "currentOptionParameterCount": "Quantidade de parâmetros da opção atual: {count}", + "installConfigDescription": "Configuração de instalação (JSON, editável antes de instalar; edições substituirão o formulário de protocolo/parâmetros)", + "selectLeftToView": "Selecione um MCP do marketplace à esquerda para ver detalhes." + }, + "badges": { + "verified": "Verificado", + "remote": "Remoto", + "hasHomepage": "Tem homepage", + "uses": "{count} usos", + "deployed": "Implantado", + "notDeployed": "Não implantado" + }, + "selectLeftMcp": "Selecione um MCP à esquerda." + }, + "AcpAgentSettings": { + "title": "Gerenciamento do SDK de agentes", + "description": "Gerencie em um só lugar a conexão do SDK de agentes, estado habilitado, variáveis de ambiente, gerenciamento de configuração e informações de preflight de versão.", + "loadingAgents": "Carregando lista de agentes...", + "agentList": "Lista de agentes", + "emptyNoAgent": "Nenhum agente disponível.", + "configManagement": "Gerenciamento de configuração", + "envVars": "Variáveis de ambiente", + "hostTools": { + "label": "Deixar o agente cuidar de arquivos e comandos", + "description": "O codeg deixa de atender o acesso a arquivos e os comandos de terminal, de modo que o agente os executa no próprio processo — onde o sandbox e as regras de permissão dele realmente se aplicam. A delegação a outros agentes também é desativada, pois levaria o mesmo trabalho de volta ao codeg. O codeg não adiciona sandbox algum, então ative isto apenas se o agente tiver um configurado." + }, + "nativeJsonConfig": "Configuração JSON nativa", + "modelHintDefault": "Deixe em branco para usar o modelo padrão do sistema.", + "generalConfigDescriptionClaude": "Suporta configuração rápida de API URL, API Key e modelos Claude, e sincroniza com a configuração JSON nativa.", + "generalConfigDescriptionDefault": "Suporta entrada de configuração importante (API URL, API Key, Model) e gerenciamento de configuração JSON nativa.", + "multiAgent": { + "title": "Colaboração multiagente", + "description": "Permite que agentes ativos deleguem subtarefas a outros agentes.", + "enable": "Ativar delegação", + "enableHint": "Quando desativado, a ferramenta delegate_to_agent fica oculta no catálogo de ferramentas MCP do agente.", + "withheldByHostTools": "{agents} não receberão as ferramentas de delegação: o interruptor por agente “Deixar o agente lidar com arquivos e comandos” está ligado.", + "selfInitiate": "Allow spawn without @", + "selfInitiateHint": "When on, an agent may start a listed sub-agent on its own. An @ mention is still always honored. When off, only an @ mention starts a sub-agent.", + "depthLimit": "Profundidade máxima de delegação", + "depthHint": "Intervalo permitido: {min}–{max}. Limita a profundidade de recursão de uma cadeia de delegação (raiz → filho → neto …).", + "completedCacheLabel": "Cache de resultados concluídos (MB)", + "completedCacheHint": "Cache em memória dos resultados concluídos de subagentes, mantido apenas enquanto a sessão de delegação está em execução e liberado automaticamente quando essa sessão termina. Acima deste limite, os resultados mais antigos são descartados da memória primeiro (ainda visíveis na sessão do próprio subagente); 0 = ilimitado (ainda assim liberado ao terminar a sessão).", + "save": "Salvar", + "saving": "Salvando…", + "saved": "Configurações de delegação salvas", + "saveFailed": "Falha ao salvar configurações de delegação", + "loadFailed": "Falha ao carregar configurações de delegação: {detail}", + "tabGeneral": "Geral", + "tabAgentDefaults": "Padrões do subagente", + "agentDefaultsDescription": "Substituições por agente aplicadas quando a Colaboração multiagente inicia um subagente para uma chamada de delegação. As opções mostradas vêm de uma sondagem ao vivo: o que você escolhe é exatamente o que o agente aceitará.", + "probing": "Carregando opções disponíveis do agente…", + "probeFailed": "Falha ao carregar opções: {detail}", + "retry": "Tentar novamente", + "noConfigAvailable": "Este agente não possui opções configuráveis.", + "modeLabel": "Modo", + "agentDefaultHint": "Padrão do agente: {value}", + "defaultOptionLabel": "Padrão ({value})" + }, + "actions": { + "dragSort": "Arraste para reordenar", + "dragSortAgent": "Arraste para reordenar {name}", + "refreshCheck": "Atualizar verificação", + "refreshCheckAgent": "Atualizar verificação de {name}", + "clickEnable": "Clique para habilitar {name}", + "clickDisable": "Clique para desabilitar {name}", + "install": "Instalar", + "upgrade": "Atualizar", + "uninstall": "Desinstalar", + "uninstalling": "Desinstalando...", + "saveEnvVars": "Salvar variáveis de ambiente", + "saving": "Salvando...", + "saveGrokConfig": "Salvar configuração do Grok", + "saveCodexConfig": "Salvar configuração do Codex", + "saveGeminiConfig": "Salvar configuração do Gemini", + "saveOpenCodeConfig": "Salvar configuração do OpenCode", + "saveOpenClawConfig": "Salvar configuração do OpenClaw", + "saveConfigManagement": "Salvar gerenciamento de configuração", + "saveCurrentProvider": "Salvar provedor atual", + "showApiKey": "Mostrar API Key", + "hideApiKey": "Ocultar API Key", + "showKey": "Mostrar chave", + "hideKey": "Ocultar chave", + "showToken": "Mostrar token", + "hideToken": "Ocultar token", + "cancel": "Cancelar", + "delete": "Excluir", + "deleting": "Excluindo...", + "confirmDelete": "Confirmar exclusão", + "confirmUninstall": "Confirmar desinstalação", + "saveClineConfig": "Salvar configuração do Cline", + "saveHermesConfig": "Salvar configuração do Hermes", + "saveCodeBuddyConfig": "Salvar configuração do CodeBuddy", + "saveKimiCodeConfig": "Salvar configuração do Kimi Code", + "customInstall": "Instalação personalizada", + "saveKimiCodeRawConfig": "Save config.toml", + "saveDeepSeekConfig": "Salvar configuração do DeepSeek", + "diagnose": "Diagnosticar" + }, + "status": { + "enabled": "Habilitado", + "disabled": "Desabilitado", + "unchecked": "Não verificado", + "agentEnabledAria": "{name} habilitado", + "agentEnabledSwitch": "Chave de habilitação de {name}" + }, + "preflight": { + "count": "Itens de preflight: {count}", + "notRun": "As verificações ainda não foram executadas." + }, + "grok": { + "configDescription": "Configure o Grok aqui. Os controles abaixo — modo de permissão, esforço de raciocínio, um modelo personalizado opcional (endpoint próprio) e a compactação — são mesclados em ~/.grok/config.toml, preservando suas outras chaves e comentários. O login usa seu XAI_API_KEY ou `grok login`. As demais chaves continuam editáveis em Avançado.", + "permissionModeLabel": "Modo de permissão", + "permissionDefault": "Perguntar sempre", + "permissionAcceptEdits": "Aprovar edições automaticamente", + "permissionAuto": "Aprovação automática inteligente", + "permissionAlwaysApprove": "Sempre aprovar", + "reasoningEffortLabel": "Esforço de raciocínio", + "effortLow": "Baixo (mais rápido)", + "effortMedium": "Médio (equilibrado)", + "effortHigh": "Alto", + "effortXhigh": "Máximo", + "optionDefault": "Usar padrão", + "authTitle": "Autenticação", + "authMode": "Método de autenticação", + "authModeApiKey": "Chave de API da XAI", + "authModeApiKeyHint": "Autentique-se com uma XAI_API_KEY do console da xAI, para execuções não interativas ou headless. Armazenada no ambiente deste agente.", + "authModeCustom": "Endpoint personalizado", + "authModeCustomHint": "Use um endpoint próprio (BYO): defina abaixo um modelo personalizado com a sua própria base URL e chave de API. Ele se torna o modelo padrão do Grok.", + "subscriptionHint": "Entre com `grok login` (SuperGrok / X Premium+). Nenhuma chave de API é armazenada.", + "loginHint": "Execute isto num terminal para entrar e depois reabra estas configurações:", + "commandCopied": "Comando copiado para a área de transferência", + "copyCommand": "Copiar comando", + "authKeyConfigured": "XAI_API_KEY está configurada.", + "authKeyMissing": "Nenhuma XAI_API_KEY definida.", + "advancedToggle": "Avançado (config.toml bruto)", + "configTomlNative": "config.toml (nativo)", + "configTomlHint": "Salvo literalmente como todo o ~/.grok/config.toml. TOML inválido é rejeitado para que um erro de digitação nunca trunque seu arquivo.", + "configTomlPlaceholder": "# Chaves além dos controles acima, por ex.\n# [mcp_servers.*], [cli], regras [permission].", + "customModelTitle": "Modelo personalizado (endpoint próprio)", + "customModelHint": "Aponte o Grok para um endpoint personalizado ou auto-hospedado. O codeg grava um bloco `[model.*]` por modelo e o define como padrão. Deixe o ID do modelo vazio para removê-lo.", + "customModelIdLabel": "ID do modelo", + "customModelIdPlaceholder": "grok-4.5", + "customModelIdHint": "Registrado como um bloco `[model.*]` e enviado à API como nome do modelo; também definido como `[models].default`.", + "customBaseUrlLabel": "URL base", + "customBaseUrlPlaceholder": "https://api.x.ai/v1 (padrão)", + "customApiBackendLabel": "Backend da API", + "backendResponses": "Responses", + "backendChatCompletions": "Chat Completions", + "backendMessages": "Messages (Anthropic)", + "customApiKeyLabel": "Chave de API", + "customApiKeyHint": "Armazenada em linha em `[model.*].api_key`, restrita a este endpoint.", + "customContextWindowLabel": "Janela de contexto (tokens)", + "customContextWindowHint": "Opcional. Define o momento da autocompactação; deixe vazio para o padrão do endpoint.", + "autoCompactLabel": "Limite de autocompactação (%)", + "autoCompactHint": "Compacta a conversa quando o uso do contexto atinge esta porcentagem (padrão do Grok: 85). Gravado em `[session]`." + }, + "cursor": { + "configDescription": "Configure o Cursor aqui. Escolha um método de autenticação — assinatura oficial (login pelo navegador) ou uma chave de API do Cursor para máquinas headless ou servidores — depois escolha um modelo e edite as regras de permissão e o sandbox do CLI. O codeg as grava em ~/.cursor/cli-config.json, compartilhado com o CLI cursor-agent.", + "authTitle": "Autenticação", + "authChecking": "Verificando…", + "authNotInstalled": "cursor-agent não está instalado", + "authLoggedIn": "Conectado", + "authNotLoggedIn": "Não conectado", + "loginHint": "Execute isto em um terminal para entrar na sua conta Cursor (uma janela do navegador abre) e depois clique em atualizar:", + "apiKeyLabel": "Chave de API do Cursor", + "apiKeyPlaceholder": "chave de cursor.com/dashboard", + "apiKeyHint": "CURSOR_API_KEY — uma chave de conta do painel do Cursor, alternativa ao login pelo navegador para máquinas headless ou servidores. Não é uma chave de terceiros nem da OpenAI.", + "modelTitle": "Modelo padrão", + "loadModels": "Carregar modelos", + "modelsUnavailable": "Lista de modelos indisponível", + "modelHint": "Passado à CLI como --model ao iniciar a sessão. Deixe no padrão para o Cursor escolher.", + "permissionsTitle": "Permissões e sandbox", + "permissionsDescription": "Editor visual das regras de permissão da CLI (cli-config.json). Regras permitidas executam sem confirmação; regras negadas são sempre bloqueadas.", + "permissionModeLabel": "Modo de permissões", + "permissionModeDefault": "Perguntar antes de executar (padrão)", + "permissionModeForce": "Run Everything (--force)", + "permissionModeHint": "Run Everything inicia as sessões com --force: todas as chamadas de ferramentas são permitidas automaticamente, exceto as regras de negação, sem confirmações (uma política da organização pode limitá-lo às regras de permissão). Vale para novas sessões.", + "optionDefault": "Padrão (não definido)", + "sandboxLabel": "Sandbox", + "sandboxEnabled": "Ativado", + "sandboxDisabled": "Desativado", + "allowRulesLabel": "Regras permitidas", + "denyRulesLabel": "Regras negadas", + "addRule": "Adicionar regra", + "rulesSyntaxHint": "Sintaxe das regras: Shell(cmd), Read(caminho/glob), Write(caminho/glob), WebFetch(domínio), Mcp(servidor:ferramenta) — as regras de negação sempre prevalecem.", + "saveConfig": "Salvar configuração", + "advancedToggle": "Avançado: cli-config.json bruto", + "advancedHint": "O ~/.cursor/cli-config.json completo. Salvar grava o arquivo como está; os controles estruturados acima são mesclados nele.", + "saveRawConfig": "Salvar arquivo", + "authMode": "Método de autenticação", + "subscriptionHint": "Faça login com sua conta Cursor e use os modelos do Cursor.", + "customApiKeyRequired": "É necessária uma chave de API do Cursor.", + "authModeApiKey": "Chave de API do Cursor (headless/servidor)", + "authModeApiKeyHint": "Autentique-se com uma chave de API de conta do Cursor gerada no painel do Cursor (para máquinas headless ou servidores). É uma chave de conta do Cursor, não um endpoint de terceiros/OpenAI: o cursor-agent só se comunica com o backend do próprio Cursor. Para usar um endpoint compatível com codex/OpenAI, use o agente Codex.", + "modelPickerPlaceholder": "Pesquisar modelos…", + "modelNoMatch": "Nenhum modelo correspondente", + "modelsNeedAuth": "Faça login para carregar a lista de modelos.", + "modelDefaultBadge": "padrão" + }, + "deepseek": { + "configManagement": "Configuração do DeepSeek Harness", + "configDescription": "O endpoint e a chave são variáveis de ambiente que o deepseek-acp lê ao iniciar. O modelo e o nível de raciocínio são seletores por sessão — escolha-os no campo de mensagem.", + "baseUrlLabel": "Endpoint da API", + "baseUrlHint": "Deixe vazio para o endpoint oficial. Vale para as sessões iniciadas depois de salvar; reconecte uma sessão em andamento para que ela use o novo valor.", + "baseUrlInvalid": "Informe uma URL http(s) completa e sem query string, por exemplo https://api.deepseek.com", + "apiKeyLabel": "Chave de API", + "apiKeyHint": "Enviada ao agente como DEEPSEEK_API_KEY. Uma variável de ambiente tem precedência sobre o arquivo de credenciais, então deixe em branco se você entrar pelo terminal." + }, + "codex": { + "configDescription": "Suporta configuração rápida de URL da API, API Key, nome do modelo e reasoning effort, com sincronização para `auth.json` / `config.toml`.", + "authMode": "Modo de Autenticação", + "chatgptSubscription": "Assinatura oficial", + "chatgptSubscriptionHint": "Faça login com assinatura oficial do ChatGPT, sem necessidade de API Key", + "apiKeyHint": "Conecte-se usando API Key ao OpenAI ou serviços de API compatíveis", + "selectProvider": "Selecionar provedor", + "modelName": "Nome do modelo", + "selectReasoningEffort": "Selecionar Reasoning Effort", + "enableWebsocket": "Habilitar WebSocket", + "enableWebsocketAria": "Habilitar WebSocket para Codex Provider", + "enableSkills": "Habilitar Skills", + "enableSkillsAria": "Habilitar Skills para Codex", + "enableFast": "Habilitar Fast", + "enableFastAria": "Habilitar nível de serviço Fast para Codex", + "sandboxGroupTitle": "Sandbox e aprovações", + "sandboxGroupHint": "Gravado no ~/.codex/config.toml global, portanto as sessões do codex CLI e do IDE também usam. São padrões do thread: valem para os turnos que o codex inicia sozinho (/goal, /review, /compact). Mensagens comuns usam a predefinição de aprovação do compositor. Reinicie a sessão para aplicar as alterações.", + "sandboxShadowedWarning": "O config.toml define default_permissions, então o codex resolve as permissões por esse perfil e ignora sandbox_mode por completo. Remova default_permissions para usar os controles abaixo.", + "sandboxPermissionsTableWarning": "O config.toml define perfis [permissions] sem default_permissions, o que faz o codex recusar a iniciar. Defina um no editor bruto abaixo.", + "approvalPolicyLabel": "Política de aprovação", + "approvalPolicyUnset": "Não definida (padrão do codex: sob demanda)", + "approvalPolicy_on-request": "Sob demanda — o modelo decide quando perguntar", + "approvalPolicy_untrusted": "Não confiável — só comandos de leitura reconhecidos como seguros rodam sem confirmação", + "approvalPolicy_never": "Nunca — nenhum pedido de aprovação", + "approvalPolicy_granular": "Granular — escolha por tipo de solicitação", + "approvalPolicyUntrustedAcpWarning": "Untrusted não tem equivalente entre os três presets de aprovação do adaptador ACP, então as sessões do codeg voltam para \"quando solicitado\": o modelo passa a decidir quando perguntar, e comandos que o sandbox já permite deixam de pedir confirmação. Restrinja o modo de sandbox abaixo em vez disso.", + "granularHint": "Desligado significa que esse tipo de solicitação é recusado automaticamente em vez de exibido a você.", + "granular_sandbox_approval": "Escalonamentos de comandos de shell", + "granular_rules": "Avisos de regras do execpolicy", + "granular_skill_approval": "Avisos de scripts de habilidades", + "granular_request_permissions": "Avisos da ferramenta request_permissions", + "granular_mcp_elicitations": "Avisos de elicitação MCP", + "sandboxModeLabel": "Modo de sandbox", + "sandboxModeUnset": "Não definido (pastas confiáveis caem para escrita no espaço de trabalho)", + "sandboxMode_read-only": "Somente leitura", + "sandboxMode_workspace-write": "Escrita no espaço de trabalho", + "sandboxMode_danger-full-access": "Acesso total (sem sandbox)", + "sandboxModeHint": "No Windows, a escrita no espaço de trabalho é rebaixada para somente leitura, a menos que o sandbox experimental do Windows do codex esteja ativado.", + "sandboxModeSeedsPresetHint": "O codeg também usa isto para o preset de aprovação inicial da sessão, portanto — ao contrário da política de aprovação — ele afeta os prompts comuns. O preset escolhido no editor continua tendo prioridade.", + "writableRootsLabel": "Pastas graváveis extras", + "writableRootsHint": "Um caminho absoluto por linha, além do diretório de trabalho.", + "sandboxRootsRelativeError": "Precisa ser um caminho absoluto — o codex resolve caminhos relativos dentro de ~/.codex: {path}", + "networkAccessLabel": "Permitir acesso à rede", + "excludeTmpdirLabel": "Excluir TMPDIR das raízes graváveis", + "excludeSlashTmpLabel": "Excluir /tmp das raízes graváveis", + "authJsonNative": "auth.json (nativo)", + "configTomlNative": "config.toml (nativo)", + "loginButton": "Entrar com ChatGPT", + "loginRequesting": "Solicitando código de login...", + "loginStep1": "Abra a seguinte URL no seu navegador:", + "loginStep2": "Digite o código abaixo:", + "loginPolling": "Aguardando autorização...", + "loginCancel": "Cancelar", + "loginSuccess": "Login realizado com sucesso, configuração salva!", + "loginFailed": "Falha no login: {message}", + "loginRetry": "Tentar novamente", + "loginCodeCopied": "Código copiado", + "loggedIn": "Conta conectada", + "loginRelogin": "Reconectar / Trocar conta", + "loginTimeout": "Login expirou, tente novamente", + "loginSaveFailed": "Login realizado com sucesso, mas falha ao salvar configuração" + }, + "gemini": { + "authConfig": "Configuração de autenticação do Gemini", + "authConfigDescription": "Alinhada à documentação de autenticação do Gemini CLI, com suporte a endpoint personalizado, login Google, Gemini API Key e Vertex AI (ADC / conta de serviço / API Key).", + "authMode": "Modo de autenticação", + "selectAuthMode": "Selecionar modo de autenticação", + "viewAuthDoc": "Ver documentação de autenticação", + "mode": { + "custom": "Endpoint personalizado", + "loginGoogle": "Login Google (OAuth)", + "vertexServiceAccount": "Vertex AI (Conta de serviço)" + }, + "hint": { + "custom": "Preencha API URL, API Key e Modelo; mapeados para GOOGLE_GEMINI_BASE_URL / GEMINI_API_KEY / GEMINI_MODEL.", + "loginGoogle": "Execute gemini no terminal e conclua o login Google primeiro; API key não é necessária.", + "geminiApiKey": "Preencha GEMINI_API_KEY ao usar a API Gemini.", + "vertexAdc": "Use gcloud ADC; GOOGLE_CLOUD_PROJECT e GOOGLE_CLOUD_LOCATION são recomendados.", + "vertexServiceAccount": "Defina o caminho do JSON da conta de serviço em GOOGLE_APPLICATION_CREDENTIALS.", + "vertexApiKey": "Preencha GOOGLE_API_KEY ao usar API key do Vertex AI." + } + }, + "openCode": { + "configManagement": "Gerenciamento de configuração do OpenCode", + "configDescription": "Alinhado ao esquema `provider` do OpenCode, com suporte a gerenciamento multi-provedor e sincronização bidirecional com arquivos JSON nativos.", + "providerManagement": "Gerenciamento de provedores", + "providerCount": "{count} provedores", + "addProvider": "Adicionar provedor", + "emptyProvider": "Ainda não há provedores personalizados. Clique em Adicionar provedor personalizado para criar um.", + "providerEnabledState": "Estado habilitado de {providerId}", + "selectProviderNpm": "Selecionar provider.npm", + "modelManagement": "Gerenciamento de modelos", + "modelCount": "{count} modelos", + "modelDescription": "Alinhado ao `provider.models` do OpenCode. O gerenciamento rápido atualmente suporta `name` / `id`; outros campos avançados são preservados e podem ser editados no JSON nativo abaixo.", + "addModel": "Adicionar modelo", + "emptyModel": "Ainda não há modelo. Informe model id e clique em \"Adicionar modelo\".", + "modelId": "ID do modelo", + "modelName": "Nome do modelo", + "deleteModel": "Excluir modelo {modelId}", + "nativeJsonConfig": "Configuração JSON nativa do OpenCode", + "mainModel": "Modelo principal", + "smallModel": "Modelo pequeno", + "noMatchingModels": "Nenhum modelo correspondente", + "connectProvider": "Conectar provedor", + "connectedProviders": "Provedores conectados", + "noConnectedProviders": "Ainda não há provedores do catálogo conectados.", + "advancedProviderConfig": "Provedores personalizados", + "customProviderConfigHint": "Endpoints compatíveis com OpenAI que você mesmo define — um bloco de provider em opencode.json, com a API key em auth.json.", + "addCustomProvider": "Adicionar provedor personalizado", + "disconnect": "Desconectar", + "editConfig": "Editar", + "customBadge": "Personalizado", + "authKindApi": "Chave de API", + "authKindOauth": "OAuth", + "authKindNone": "Sem credencial", + "connect": { + "title": "Conectar um provedor", + "description": "Escolha um provedor no catálogo do models.dev. As credenciais são salvas no arquivo auth.json do OpenCode.", + "pick": "Provedor", + "search": "Pesquisar provedores…", + "loading": "Carregando catálogo…", + "catalogLabel": "Catálogo do models.dev", + "modelsAvailable": "{count} modelos disponíveis", + "getKey": "Obter chave de API", + "oauthApiKeyNote": "Este provedor também oferece login pelo navegador via opencode auth login. O login pelo navegador chegará em breve — por enquanto, cole uma chave de API.", + "apiKey": "Chave de API", + "apiKeyHint": "Salva em auth.json, nunca em opencode.json.", + "baseUrlOptional": "Substituir Base URL (opcional)", + "providerId": "ID do provedor", + "displayName": "Nome de exibição", + "modelsList": "Modelos (um por linha)", + "modelsHint": "IDs de modelo que o endpoint aceita.", + "action": "Conectar", + "editTitle": "Editar provedor", + "editDescription": "Atualize a chave de API ou a Base URL deste provedor.", + "saveAction": "Salvar" + }, + "customProvider": { + "title": "Adicionar um provedor personalizado", + "description": "Defina um endpoint compatível com OpenAI. A API key é salva em auth.json; o bloco de provider vai para opencode.json.", + "action": "Adicionar provedor", + "idInCatalog": "{providerId} é um provedor conhecido — conecte-o via Conectar provedor." + }, + "refreshCatalog": "Atualizar catálogo", + "reasoningBadge": "raciocínio", + "contextWindow": "Janela de contexto", + "permissions": { + "title": "Permissões", + "description": "Decida quais ações rodam sozinhas, quais pedem sua confirmação e quais são bloqueadas. Gravado no bloco permission do opencode.json e aplicado ao salvar abaixo.", + "docsLink": "Documentação de permissões", + "unparsableConfig": "O JSON nativo abaixo não é válido, então o editor visual está pausado. Corrija o JSON para continuar.", + "invalidBlock": "O bloco permission tem um formato que o codeg não reconhece. Edite-o no JSON nativo abaixo ou use Redefinir para começar de novo.", + "orderingUnsafe": "Há uma regra curinga escrita depois de ferramentas específicas, então o OpenCode a aplica a elas também — as linhas abaixo não são o que está em vigor. Corrigir ordem apenas devolve cada curinga ao início do seu escopo, sem mudar nenhum valor.", + "orderingUnsafeManual": "Uma regra fica encoberta por um padrão mais geral escrito depois dela, então o OpenCode nunca a aplica — as linhas abaixo não são o que está em vigor. Dois padrões que se sobrepõem não têm uma única ordem certa; reordene-os no JSON nativo para que o mais geral venha primeiro.", + "fixOrder": "Corrigir ordem", + "agentOverrides": "Estes agentes sobrepõem as permissões e são aplicados por último, então vencem tudo daqui: {agents}. Edite-os no JSON nativo abaixo ou ative o aceite automático para apagá-los.", + "legacyTools": "O mapa tools legado de nível superior nega uma ferramenta. O OpenCode o funde com as permissões, então ele se aplica acima de tudo o que aparece aqui. Edite-o no JSON nativo abaixo ou ative o aceite automático para apagá-lo.", + "autoAcceptTitle": "Aceitar todas as permissões automaticamente", + "autoAcceptHint": "Toda chamada de ferramenta — comandos de shell, edições de arquivos, caminhos fora do projeto — roda sem perguntar. Ao ativar, as configurações por ferramenta abaixo são substituídas por uma única regra que permite tudo, e as sobreposições por agente e os interruptores tools legados que ainda bloqueariam são apagados.", + "globalLabel": "Padrão global", + "globalHint": "A regra *: vale para tudo que as ferramentas abaixo não sobrescreverem.", + "actionUnset": "Não definido (padrões do OpenCode)", + "actionInherit": "Herdar ({action})", + "actionAllow": "Permitir", + "actionAsk": "Perguntar", + "actionDeny": "Negar", + "perToolTitle": "Permissões por ferramenta", + "reset": "Redefinir", + "ruleCount": "regras: {count}", + "rulesToggle": "Regras detalhadas de {tool}", + "rulesHint": "São comparadas com a entrada da ferramenta e a última correspondência vence, então coloque os padrões amplos primeiro. * corresponde a quaisquer caracteres, ? a exatamente um, e um ~ inicial vira sua pasta pessoal.", + "noRules": "Ainda não há regras detalhadas.", + "addRule": "Adicionar regra", + "deleteRule": "Excluir a regra {pattern}", + "duplicateRule": "Esse padrão já existe.", + "blankRule": "Uma regra precisa de um padrão — use o ícone de lixeira para removê-la.", + "customKeys": "Outras chaves de permissão no arquivo", + "customKeyHint": "Não é uma ferramenta integrada do OpenCode — mantida como está.", + "keys": { + "bash": "Executar comandos de shell, pelo comando analisado", + "edit": "Todas as modificações de arquivos: edit, write e patch", + "read": "Ler arquivos, pelo caminho", + "external_directory": "Acessar caminhos fora do diretório de trabalho do projeto", + "task": "Iniciar subagentes, pelo tipo de subagente", + "skill": "Carregar skills, pelo nome", + "glob": "Encontrar arquivos, pelo padrão glob", + "grep": "Pesquisar o conteúdo dos arquivos, pelo padrão", + "list": "Listar o conteúdo de um diretório", + "webfetch": "Buscar uma URL", + "websearch": "Pesquisar na web", + "lsp": "Executar consultas LSP", + "todowrite": "Escrever a lista de tarefas", + "question": "Fazer uma pergunta a você", + "doom_loop": "Dispara quando a mesma chamada se repete três vezes com a mesma entrada" + } + } + }, + "openClaw": { + "gatewayConfig": "Configuração de Gateway", + "gatewayDescription": "Configure a conexão do OpenClaw Gateway. Suporta gateway local ou remoto.", + "gatewayUrlHint": "Deixe vazio para usar gateway.remote.url da configuração local do openclaw.", + "gatewayTokenPlaceholder": "Token de autenticação do Gateway", + "gatewayTokenHint": "Use token-file em vez de token em texto puro quando possível; configure via CLI do openclaw.", + "sessionKeyHint": "Opcional. Especifique a session key do gateway; deixe vazio para atribuição automática de sessão isolada." + }, + "hermes": { + "configManagement": "Configuração do Hermes", + "configDescription": "O Hermes gerencia suas próprias credenciais em ~/.hermes/.env e as configurações em ~/.hermes/config.yaml. Escolha um provedor e, em seguida, defina a chave de API e o modelo — o codeg grava os dois arquivos para você.", + "providerLabel": "Provedor", + "providerHint": "O provedor determina qual variável de chave de API e qual model.provider o Hermes usa. Provedores OAuth são configurados pela configuração de terminal abaixo.", + "groupApiKey": "Provedores com chave de API", + "groupOauth": "Provedores OAuth", + "groupAws": "AWS", + "apiKeyHint": "Salva em ~/.hermes/.env. Ela nunca é injetada no processo — o Hermes a lê da sua própria configuração.", + "modelName": "Modelo", + "oauthHint": "Este provedor usa OAuth. Execute a configuração abaixo para autenticar no seu terminal.", + "awsHint": "O Bedrock usa suas credenciais da AWS (ambiente ou configuração compartilhada). Defina o ID do modelo acima e configure o acesso à AWS no seu ambiente.", + "unsupportedProvider": "Este provedor não pode ser editado com campos estruturados. Use o editor de config.yaml abaixo ou a configuração pelo terminal.", + "setupTitle": "Configuração autogerenciada", + "setupHint": "A configuração interativa do Hermes precisa de um terminal. Inicie-a abaixo ou copie o comando para executá-lo você mesmo.", + "runSetup": "Executar configuração do Hermes", + "configureModel": "Configurar modelo", + "openConfigFolder": "Abrir ~/.hermes", + "copyCommand": "Copiar comando", + "commandCopied": "Comando copiado para a área de transferência", + "advancedTitle": "Avançado: editar config.yaml", + "rawConfigHint": "Edite ~/.hermes/config.yaml diretamente. Salvar aqui sobrescreve o arquivo exatamente como está.", + "saveRawConfig": "Salvar config.yaml" + }, + "codebuddy": { + "configManagement": "Configuração do CodeBuddy", + "configDescription": "O CodeBuddy autentica com uma chave de API. As versões da China continental também exigem o ambiente definido como “China (internal)”; as versões iOA usam “iOA”. A versão internacional deixa sem definir.", + "apiKeyLabel": "Chave de API", + "apiKeyHint": "Salvo como CODEBUDDY_API_KEY para este agente. Como alternativa, faça login com a CLI do CodeBuddy em um terminal.", + "apiKeyHintSelfHosted": "Salvo como CODEBUDDY_API_KEY para este agente. Use a chave emitida pela sua implantação privada.", + "environmentLabel": "Ambiente", + "environmentHint": "Define CODEBUDDY_INTERNET_ENVIRONMENT. A China continental deve usar “China (internal)”; a versão internacional deixa sem definir.", + "envOverseas": "Internacional (padrão)", + "envChina": "China (internal)", + "envIoa": "iOA", + "envSelfHosted": "Auto-hospedado (implantação privada)", + "baseUrlLabel": "URL de implantação", + "baseUrlPlaceholder": "https://codebuddy.your-company.com", + "baseUrlHint": "Salvo como CODEBUDDY_BASE_URL e aponta o CodeBuddy para seu endpoint privado. No auto-hospedado, o ambiente de rede (CODEBUDDY_INTERNET_ENVIRONMENT) fica sem definição.", + "baseUrlInvalid": "Insira uma URL http(s) válida.", + "loginHint": "Sem chave de API? Execute “codebuddy” em um terminal para fazer login com sua conta Tencent." + }, + "kimiCode": { + "configManagement": "Configuração do Kimi Code", + "configDescription": "O `kimi acp` só aceita um token de login armazenado, por isso o codeg grava um provedor gerenciado em ~/.kimi-code/config.toml e cria um token de acesso local — a inferência continua usando a sua própria chave.", + "statusUnconfigured": "Ainda não configurado", + "statusDirty": "Alterações não salvas", + "summaryLabel": "Em vigor", + "gateReadyApiKey": "Chave de API gravada em config.toml", + "gateReadyLogin": "Conectado com uma conta Kimi", + "revealConfig": "Mostrar na pasta", + "envOverrideWarning": "{keys} está definido e tem prioridade sobre o config.toml. Salvar aqui remove essa variável.", + "authModeLabel": "Método de autenticação", + "authModeApiKey": "Chave de API", + "authModeLogin": "Login da conta Kimi (assinatura)", + "authModeApiKeyHint": "Grava um provedor gerenciado no config.toml e cria o token de acesso para que as sessões possam abrir.", + "loginHint": "Execute `kimi login` em um terminal para entrar com uma conta Kimi por assinatura. O codeg não armazena nada e reutiliza o login do próprio Kimi. Salvar aqui remove o token de acesso por chave de API do codeg.", + "credentialTitle": "Credencial", + "interfaceTypeLabel": "Tipo de provedor", + "interfaceTypeHint": "O protocolo de provedor que o Kimi fala (o `type` do config.toml). Use Kimi / Moonshot para uma chave da Moonshot / platform.kimi.com.", + "endpointLabel": "Endpoint", + "endpointCustom": "Personalizado (compatível com OpenAI)", + "endpointHint": "Internacional = api.moonshot.ai; China (chaves de platform.kimi.com) = api.moonshot.cn. Personalizado aponta para qualquer endpoint compatível com OpenAI.", + "regionInternational": "Internacional (api.moonshot.ai)", + "regionChina": "China (api.moonshot.cn)", + "baseUrlLabel": "URL base", + "baseUrlHint": "Deixe em branco para usar o padrão do SDK do provedor.", + "apiKeyLabel": "Chave de API", + "apiKeyHint": "Gravada em ~/.kimi-code/config.toml e usada para inferência. De platform.kimi.com ou platform.kimi.ai.", + "vertexProjectLabel": "Projeto do GCP (GOOGLE_CLOUD_PROJECT)", + "vertexLocationLabel": "Região do GCP (GOOGLE_CLOUD_LOCATION)", + "vertexHint": "O Vertex AI usa as credenciais padrão do aplicativo Google — execute `gcloud auth application-default login` (sem chave de API).", + "modelTitle": "Modelo", + "modelLabel": "Modelo", + "modelHint": "O id do modelo gravado no config.toml. Use «Testar e listar modelos» para ver o que a sua chave realmente acessa.", + "maxContextLabel": "Tamanho máximo de contexto", + "maxContextHint": "Obrigatório pelo esquema do Kimi: sem ele o Kimi descarta todo o bloco do modelo e nenhuma solicitação retorna resposta. Padrão 262144.", + "fetchModels": "Testar e listar modelos", + "fetchModelsOk": "A chave funciona — {count} modelos disponíveis", + "fetchModelsEmpty": "A chave funciona, mas nenhum modelo foi retornado", + "fetchModelsFailed": "Falha no teste", + "fetchModelsNeedsKey": "Informe primeiro uma chave de API e um endpoint", + "modelNotInList": "Este modelo não está na lista acessível pela sua chave — o Kimi falhará com «modelo não encontrado».", + "reasoningTitle": "Raciocínio", + "reasoningEnableLabel": "Ativar", + "reasoningDescription": "O Kimi só mostra o seletor «Thinking» na caixa de mensagem quando o modelo declara uma capacidade de raciocínio, por isso o codeg a grava aqui. Vale para sessões novas.", + "effortsLabel": "Níveis oferecidos", + "effortsHint": "Estes níveis viram as opções do seletor «Thinking». O Kimi repassa o nível ao provedor tal como está, então escolha os que o seu modelo aceita.", + "effortsEmptyHint": "Sem nenhum nível escolhido, a caixa de mensagem fica apenas com um interruptor Off / On.", + "effortsCustomPlaceholder": "Adicionar outro nível", + "effortsAdd": "Adicionar", + "defaultEffortLabel": "Nível padrão", + "defaultEffortAuto": "Deixar o Kimi escolher", + "alwaysThinkingLabel": "O modelo sempre raciocina — remover a opção Off do seletor", + "fixErrorsFirst": "Corrija primeiro os campos destacados", + "errorModelRequired": "O modelo é obrigatório", + "errorMaxContextRequired": "O tamanho máximo de contexto é obrigatório", + "errorMaxContextInvalid": "Deve ser um número inteiro positivo", + "errorApiKeyRequired": "A chave de API é obrigatória", + "errorApiKeyInvalid": "A chave de API não pode conter quebras de linha", + "errorBaseUrlRequired": "A URL base é obrigatória", + "errorBaseUrlInvalid": "Deve começar com http:// ou https://", + "errorVertexProjectRequired": "O projeto do GCP é obrigatório", + "errorDefaultEffortUnlisted": "Escolha um dos níveis selecionados acima", + "advancedTitle": "Avançado", + "authTypeLabel": "Local da credencial", + "authTypeApiKey": "api_key em linha", + "authTypeEnv": "Subtabela env do provedor", + "authTypeHint": "Onde a chave de API é gravada dentro do config.toml.", + "rawEditorLabel": "Editar config.toml diretamente", + "rawEditorWarning": "Salvar aqui sobrescreve o arquivo inteiro literalmente, substituindo as configurações estruturadas acima.", + "rawEditorPlaceholder": "[providers.codeg]\ntype = \"kimi\"\nbase_url = \"https://api.moonshot.cn/v1\"\napi_key = \"sk-...\"" + }, + "authModeOfficialSubscription": "Assinatura oficial", + "authModeCustomEndpoint": "Endpoint personalizado", + "authModeCustomEndpointHint": "Configurar manualmente a URL da API e a chave API para um endpoint personalizado.", + "authModeModelProvider": "Provedor de modelo", + "modelProvider": "Provedor de modelo", + "modelProviderHint": "Usar URL da API, chave API e modelo de um provedor de modelo configurado.", + "selectModelProvider": "Selecionar provedor de modelo", + "noModelProviderAvailable": "Nenhum provedor de modelo configurado para este agente. Vá para as configurações de provedores de modelo para adicionar um.", + "claude": { + "authMode": "Modo de autenticação", + "officialSubscription": "Assinatura oficial", + "officialSubscriptionHint": "Usar assinatura oficial da Anthropic, sem necessidade de API Key.", + "mainModel": "Modelo principal", + "reasoningModel": "Modelo de raciocínio (thinking)", + "haikuDefaultModel": "Modelo Haiku padrão", + "sonnetDefaultModel": "Modelo Sonnet padrão", + "opusDefaultModel": "Modelo Opus padrão", + "customModelOption": "ID do modelo personalizado", + "customModelOptionName": "Nome do modelo personalizado", + "customModelOptionDescription": "Descrição do modelo personalizado", + "customModelOptionHint": "Adiciona uma única entrada personalizada ao seletor de modelos do Claude (por exemplo, um modelo atrás de um gateway/proxy personalizado). Nome e descrição são informações de exibição opcionais.", + "effortLevel": "Nível de raciocínio", + "effortLevelDefault": "Nível padrão", + "effortLevel_low": "Baixo", + "effortLevel_medium": "Médio", + "effortLevel_high": "Alto", + "effortLevel_xhigh": "Extra Alto", + "sendAttributionHeader": "Enviar identificador de atribuição/cobrança para a API", + "sendAttributionHeaderAria": "Enviar o identificador de atribuição/cobrança do Claude Code para a API", + "disableNonessentialTraffic": "Desativar a telemetria ou solicitações de rede desnecessárias", + "disableNonessentialTrafficAria": "Desativar a telemetria ou solicitações de rede desnecessárias do Claude Code" + }, + "dialogs": { + "confirmDeleteProvider": "Excluir o provedor {providerId}?", + "confirmDeleteProviderDescription": "A configuração do OpenCode e o auth JSON serão atualizados juntos. Esta ação não pode ser desfeita.", + "confirmUninstall": "Desinstalar {name}?", + "confirmUninstallDescription": "Isso remove a versão instalada localmente. Você pode reinstalar depois.", + "customInstallTitle": "Instalação personalizada de {name}", + "customInstallDescription": "Digite a versão a instalar. Isso reinstala e substitui a versão instalada atualmente.", + "customInstallVersionLabel": "Número da versão", + "customInstallInvalid": "Digite um número de versão válido, ex.: 1.2.3.", + "customInstallSubmit": "Instalar" + }, + "errors": { + "windowsFileLocked": "Os arquivos de {name} estão em uso por uma sessão ativa, então o Windows não consegue substituí-los. Feche todas as sessões de {name} e tente novamente.", + "nativeJsonMustBeObject": "A configuração JSON nativa deve ser um objeto", + "nativeJsonInvalid": "Erro de formato na configuração JSON nativa: {message}", + "openCodeAuthMustBeObject": "OpenCode auth.json deve ser um objeto JSON", + "openCodeAuthInvalid": "Erro de formato no OpenCode auth.json: {message}", + "authMustBeObject": "auth.json deve ser um objeto JSON", + "authInvalid": "Erro de formato no auth.json: {message}", + "providerIdPattern": "O ID do provedor só aceita letras, números, sublinhado, ponto e hífen", + "providerExists": "O provedor {providerId} já existe", + "modelIdPattern": "O ID do modelo só aceita letras, números, sublinhado, ponto, dois-pontos e hífen", + "modelExists": "O modelo {modelId} já existe" + }, + "warnings": { + "nativeJsonRecoveredStructured": "A configuração JSON nativa é inválida; redefinida para configuração estruturada", + "nativeJsonRecoveredOpenCode": "A configuração JSON nativa é inválida; redefinida para configuração estruturada do OpenCode", + "openCodeAuthRecovered": "OpenCode auth.json é inválido; redefinido para configuração padrão", + "authRecoveredStructured": "auth.json é inválido; redefinido para configuração estruturada" + }, + "toasts": { + "agentActionCompleted": "{name} {action} concluído", + "agentActionFailed": "{name} {action} falhou", + "localVersion": "Versão local: {version}", + "installCompletedVersionLater": "Instalação concluída, a versão será atualizada na próxima verificação", + "uninstallCompleted": "Desinstalação de {name} concluída", + "uninstallFailed": "Desinstalação de {name} falhou", + "localVersionRemoved": "Versão local removida", + "saveAgentOrderFailed": "Falha ao salvar a ordem dos Agents", + "saveAgentSwitchFailed": "Falha ao salvar o switch dos Agents", + "saveEnvFailed": "Falha ao salvar variáveis de ambiente", + "grokSaved": "Configuração do Grok salva", + "saveGrokNativeFailed": "Falha ao salvar a configuração nativa do Grok", + "saveGrokApiKeyFailed": "Configurações salvas, mas não foi possível salvar a chave de API", + "cursorSaved": "Configuração do Cursor salva", + "saveCursorConfigFailed": "Falha ao salvar a configuração do Cursor", + "codexSaved": "Configuração do Codex salva", + "saveCodexNativeFailed": "Falha ao salvar configuração nativa do Codex", + "geminiSaved": "Configuração do Gemini salva", + "saveGeminiFailed": "Falha ao salvar configuração do Gemini", + "providerDeleted": "Provedor {providerId} excluído", + "providerDeleteFailed": "Falha ao excluir o provedor {providerId}", + "providerSaved": "Provedor {providerId} salvo", + "saveProviderFailed": "Falha ao salvar o provedor {providerId}", + "openCodeConfigSynced": "A configuração do OpenCode e o auth JSON foram sincronizados.", + "openCodeSaved": "Configuração do OpenCode salva", + "saveOpenCodeFailed": "Falha ao salvar configuração do OpenCode", + "openClawSaved": "Configuração do OpenClaw salva", + "saveOpenClawFailed": "Falha ao salvar configuração do OpenClaw", + "configSaved": "Configuração salva", + "configSavedHint": "Sessões existentes precisam ser reabertas para que as alterações tenham efeito", + "saveConfigManagementFailed": "Falha ao salvar o gerenciamento de configuração", + "clineSaved": "Configuração do Cline salva", + "saveClineFailed": "Falha ao salvar a configuração do Cline", + "hermesSaved": "Configuração do Hermes salva", + "saveHermesFailed": "Falha ao salvar a configuração do Hermes", + "codeBuddySaved": "Configuração do CodeBuddy salva", + "saveCodeBuddyFailed": "Falha ao salvar a configuração do CodeBuddy", + "kimiCodeSaved": "Configuração do Kimi Code salva", + "saveKimiCodeFailed": "Falha ao salvar a configuração do Kimi Code", + "deepseekSaved": "Configuração do DeepSeek salva", + "saveDeepSeekFailed": "Falha ao salvar a configuração do DeepSeek", + "modelProviderRequired": "Selecione um provedor de modelo antes de salvar.", + "affectedRunningSessions": "{count, plural, one {# sessão ativa precisa reconectar para aplicar a alteração} other {# sessões ativas precisam reconectar para aplicar a alteração}}", + "providerConnected": "{providerId} conectado", + "connectFailed": "Falha ao conectar {providerId}", + "providerDisconnected": "{providerId} desconectado", + "disconnectFailed": "Falha ao desconectar {providerId}", + "catalogRefreshed": "Catálogo atualizado — {count} provedores", + "catalogRefreshFailed": "Falha ao atualizar o catálogo", + "piSaved": "Configuração do Pi salva", + "savePiFailed": "Falha ao salvar a configuração do Pi", + "piRuntimeSaved": "Tempo de execução do Pi salvo", + "savePiRuntimeFailed": "Falha ao salvar o tempo de execução do Pi", + "piBinaryInstalled": "pi instalado", + "piBinaryInstallFailed": "Falha ao instalar o pi", + "piBinaryUninstalled": "pi desinstalado", + "piBinaryUninstallFailed": "Falha ao desinstalar o pi", + "savePiTrustFailed": "Falha ao salvar a confiança do espaço de trabalho" + }, + "version": { + "statusLabel": "Status da versão", + "notInstalled": "Não instalado", + "remoteLocal": "Remoto: {remoteVersion} · Local: {localVersion}", + "localOnly": "Local: {localVersion}", + "localInstalled": "{versionText}. Instalado.", + "platformUnsupported": "{versionText}. A plataforma atual não suporta este agente.", + "uvxNotReady": "{versionText}. O runtime do uv não está instalado — instale-o na verificação do uv abaixo para usar este agente.", + "clickInstall": "{versionText}. Clique em Instalar à direita.", + "localUnrecognized": "{versionText}. A versão local não é comparável; tente atualizar para sobrescrever a instalação.", + "upgradeAvailable": "{versionText}. Atualização disponível.", + "remoteUnavailable": "{versionText}. A versão remota está indisponível no momento.", + "latest": "{versionText}. Já está na versão mais recente." + }, + "adapter": { + "label": "Adaptador ACP", + "badge": "Adaptador ACP", + "badgeHint": "Para este agente o Codeg instala um pacote adaptador ACP, não a CLI do fornecedor. Os dois são independentes e compartilham a mesma configuração.", + "learnMore": "Saiba mais", + "missingWithNative": "Encontramos a sua {nativeLabel} em {nativePath}. O Codeg conversa com os agentes por ACP e essa CLI não fala ACP, então o Codeg precisa de um pacote adaptador separado, {adapterPackage}, mantido pelo projeto Agent Client Protocol (originalmente Zed). Ele traz o próprio runtime, nunca modifica nem substitui o seu comando {nativeCmd} e lê o mesmo {configDir} — seu login e suas configurações continuam valendo. Instale abaixo.", + "missing": "O Codeg conversa com os agentes por ACP e a {nativeLabel} não fala ACP, então o Codeg precisa de um pacote adaptador separado, {adapterPackage}, mantido pelo projeto Agent Client Protocol (originalmente Zed). Ele traz o próprio runtime, então a CLI {nativeCmd} não é pré-requisito; se você já a tem, as duas coexistem e compartilham o login e as configurações de {configDir}. Instale abaixo.", + "readyWithNative": "O adaptador {adapterCmd} está instalado — é ele que o Codeg inicia, não a sua {nativeCmd} em {nativePath}. São pacotes distintos que coexistem e ambos leem {configDir}, então login e configurações são compartilhados.", + "ready": "O adaptador {adapterCmd} está instalado — é ele que o Codeg inicia. Ele traz o próprio runtime, então a {nativeLabel} não é necessária; se instalá-la depois, as duas coexistem e compartilham {configDir}." + }, + "cline": { + "configDescription": "Configure o provedor de API e as credenciais do Cline. As configurações são salvas em ~/.cline/data/." + }, + "opencodePlugins": { + "title": "Plugins do OpenCode", + "declared": "Plugins declarados", + "noPlugins": "Nenhum plugin declarado em opencode.json", + "status": { + "installed": "Instalado", + "missing": "Não instalado" + }, + "installAll": "Instalar todos os ausentes", + "pinVersions": "Fixar versões @latest", + "install": "Instalar", + "uninstall": "Desinstalar", + "refresh": "Atualizar", + "success": "Todos os plugins foram instalados com sucesso", + "failed": "Operação do plugin falhou" + }, + "pi": { + "configManagement": "Configuração do Pi", + "configDescription": "O Pi autentica via a chave de API do seu provedor de modelos. A chave é gravada em ~/.pi/agent/auth.json e a seleção de modelo em settings.json.", + "providerLabel": "Provedor", + "modelLabel": "Modelo", + "thinkingLabel": "Raciocínio", + "thinking": { + "off": "Desligado", + "low": "Baixo", + "medium": "Médio", + "high": "Alto", + "minimal": "Mínimo", + "xhigh": "Muito alto" + }, + "apiKeyLabel": "Chave de API", + "apiKeyHint": "Gravada em ~/.pi/agent/auth.json para o provedor selecionado.", + "apiKeySetPlaceholder": "•••••• (salva — deixe em branco para manter)", + "saveConfig": "Salvar configuração do Pi", + "providerModelRequired": "Provedor e modelo são obrigatórios", + "runtimeTitle": "Tempo de execução", + "runtimeDescription": "Escolha qual binário do pi é executado. Use o padrão ou aponte para sua própria build do pi.", + "modeDefault": "pi padrão", + "modeDefaultHint": "Usa o adaptador pi-acp integrado com o pi no seu PATH. Instale o pi com: npm install -g @earendil-works/pi-coding-agent", + "modeCustom": "pi personalizado", + "modeCustomHint": "Execute sua própria build, instalação ou wrapper do pi.", + "commandLabel": "Comando ou caminho do pi", + "commandHint": "Um caminho absoluto, um nome de comando no PATH ou um script wrapper (ex.: ./pi-test.sh de um monorepo).", + "commandNotFound": "Comando não encontrado", + "validate": "Validar", + "advanced": "Avançado", + "configDirLabel": "Diretório de configuração (PI_CODING_AGENT_DIR)", + "sessionDirLabel": "Diretório de sessões (PI_CODING_AGENT_SESSION_DIR)", + "flagsHint": "O pi-acp não encaminha flags personalizados do pi (--approve, -e, …) — envolva o pi num script e aponte o comando para ele.", + "customIncomplete": "Digite um comando do pi para salvar", + "saveRuntime": "Salvar tempo de execução", + "providerPlaceholder": "Selecionar um provedor", + "customProvider": "Provedor personalizado…", + "providerIdLabel": "ID do provedor", + "apiProtocolLabel": "Protocolo da API", + "baseUrlLabel": "Endpoint da API (Base URL)", + "customProviderHint": "Define um provedor em ~/.pi/agent/models.json para o seu endpoint. A maioria dos servidores auto-hospedados ou proxy usa openai-completions.", + "baseUrlRequired": "O endpoint da API (Base URL) é obrigatório", + "binaryTitle": "binário pi (pi-coding-agent)", + "binaryDescription": "O pi-acp executa este binário pi. Instale-o aqui ou aponte o pi-acp para sua própria build abaixo.", + "binaryInstalled": "Instalado", + "binaryMissing": "Não instalado", + "binaryChecking": "Verificando…", + "installBinary": "Instalar pi", + "installing": "Instalando…", + "recheck": "Verificar novamente", + "configDirSkillsNote": "Com um diretório de configuração personalizado, as habilidades, os especialistas e as ferramentas de escritório gerenciados nas Configurações não se aplicam a este pi — gerencie as habilidades dele diretamente nessa pasta.", + "projectTrustTitle": "Confiança do projeto", + "projectTrustDescription": "Pastas das quais você permitiu que o pi carregue arquivos do projeto. Uma pasta confiável permite que as .pi/extensions daquele repositório executem código ao iniciar o pi, vale para todas as pastas dentro dela e também é usada quando você executa o pi no terminal.", + "projectTrustLoading": "Carregando…", + "projectTrustEmpty": "Nenhuma pasta decidida ainda.", + "projectTrustTrusted": "Confiável", + "projectTrustDenied": "Não confiável", + "projectTrustRevoke": "Revogar", + "reasoningTitle": "Raciocínio", + "reasoningEnableLabel": "Ativar", + "reasoningDescription": "O pi só envia um esforço de raciocínio para um modelo que o declara — num modelo sem declaração, todos os níveis são reduzidos para Off, por isso o seletor do compositor volta atrás assim que se mexe nele. Escrito na entrada deste modelo em models.json.", + "levelsLabel": "Níveis disponíveis", + "levelsHint": "Passam a ser as linhas do seletor de raciocínio do compositor. Escolha os que o seu endpoint aceita; o pi recusa qualquer nível que não esteja aqui.", + "levelsEmptyError": "Escolha pelo menos um nível — sem nenhum, o pi volta para Off.", + "wireValuesTitle": "Avançado: valores enviados ao fornecedor", + "wireValuesHint": "Deixe em branco para enviar o nome do nível tal como está. Defina quando o seu endpoint esperar outra coisa — backends ao estilo Google querem LOW / HIGH.", + "defaultLevelUnlisted": "Este nível não está na lista acima — o pi iria reduzi-lo." + }, + "addCustomAgent": "Adicionar agente personalizado", + "addCustomAgentHint": "Registre qualquer agente compatível com ACP. Escolha um no registro público do ACP ou cole as informações de registro dele.", + "customAgentFromRegistry": "Registro ACP", + "customAgentManual": "Manual", + "customAgentSearchPlaceholder": "Buscar agentes…", + "customAgentLoadingCatalog": "Carregando o registro ACP…", + "customAgentRetry": "Tentar novamente", + "customAgentNoResults": "Nenhum agente correspondente", + "customAgentAdd": "Adicionar", + "customAgentAlreadyAdded": "Adicionado", + "customAgentUnsupportedPlatform": "Nenhuma compilação disponível para esta plataforma", + "customAgentAdded": "{name} adicionado", + "customAgentIdLabel": "ID do registro", + "customAgentNameLabel": "Nome exibido", + "customAgentVersionLabel": "Versão", + "customAgentSpecLabel": "Distribuição (JSON)", + "customAgentSpecHint": "Mesma forma do objeto distribution do registro ACP: canais npx, uvx e binary, ou cole uma entrada completa do registro. Em npx/uvx, cmd é o executável que o pacote instala — derivado do nome do pacote quando omitido, então defina-o quando forem diferentes. binary é organizado por chave de plataforma (esta máquina: {platform}); cmd é o caminho de execução dentro do arquivo e sha256 verifica opcionalmente o download.", + "customAgentTemplateLabel": "Modelos", + "customAgentKindLabel": "Iniciar via", + "customAgentInvalidJson": "JSON inválido", + "customAgentNoDistribution": "Nenhuma distribuição npx, uvx ou binary encontrada", + "customAgentCancel": "Cancelar", + "customAgentSave": "Adicionar agente", + "customAgentSaveChanges": "Salvar alterações", + "customAgentEdit": "Editar agente", + "customAgentEditHint": "Atualize o nome, o ícone, a distribuição e as declarações de skills. O ID do agente não pode ser alterado.", + "customAgentEditNotFound": "Agente personalizado {id} não encontrado", + "customAgentSaved": "{name} salvo", + "customAgentVersionProbeLabel": "Comando de consulta de versão (opcional)", + "customAgentVersionProbeHint": "Comando que imprime a versão instalada localmente. Se ficar vazio, o codeg executa o comando do agente com --version.", + "customAgentRemove": "Remover agente", + "customAgentRemoveHint": "Exclui a definição do agente. As conversas existentes mantêm o histórico; o agente apenas não pode mais ser iniciado.", + "customAgentIconLabel": "Ícone (opcional)", + "customAgentIconUpload": "Enviar", + "customAgentIconReplace": "Substituir", + "customAgentIconClear": "Remover ícone", + "customAgentIconHint": "Salvo junto com o agente, portanto funciona offline. Sem um ícone, usa-se uma inicial colorida.", + "customAgentSkillsLabel": "Skills (.agents/skills compartilhado)", + "customAgentSkillsHint": "Declara que este agente lê o repositório compartilhado .agents/skills (diretórios global e de projeto) e o adiciona a todas as matrizes de habilidades. Habilidades vinculadas lá ficam visíveis para todos os agentes que leem esse repositório compartilhado.", + "customAgentSkillsDirLabel": "Diretório de skills dedicado", + "customAgentSkillsDirHint": "Caminho absoluto do diretório de onde este agente carrega skills — o seu próprio repositório, além do compartilhado ou no lugar dele. ~ expande para o diretório pessoal; skills vinculadas são colocadas aqui primeiro.", + "customAgentMcpLabel": "Suporte a MCP", + "customAgentMcpHint": "Envia o companheiro MCP integrado do codeg para este agente ao iniciar a sessão — o canal por trás da delegação, do feedback ao vivo e das ferramentas de tarefas. Desative para um agente que rejeita servidores MCP e não consegue conectar; a mudança vale a partir da próxima conexão.", + "customAgentIconNotAnImage": "Selecione um arquivo de imagem.", + "customAgentIconTooLarge": "O ícone deve ter menos de {limit} KB.", + "customAgentIconReadFailed": "Não foi possível ler essa imagem.", + "customAgentRemoveConfirm": "Remover {name}? As conversas existentes permanecem, mas o agente não poderá mais ser iniciado.", + "customAgentRemoveWithData": "Excluir também o histórico de conversas registrado", + "customAgentRemoved": "{name} removido", + "customAgentBadge": "Personalizado", + "customAgentNotLaunchable": "Este agente não pode ser iniciado aqui: {reason}" + }, + "SettingsPages": { + "agentsLoading": "Carregando configurações de agentes...", + "skillPacksLoading": "Carregando pacotes de habilidades…" + }, + "GeneralSettings": { + "loading": "Carregando...", + "sectionTitle": "Geral", + "sectionDescription": "Preferências centralizadas para o terminal padrão, aceleração de renderização e delegação multi-agente.", + "terminalTitle": "Terminal padrão", + "terminalDescription": "Escolha o shell usado ao abrir novas abas de terminal pela barra de terminal ou pela árvore de arquivos. Os agentes também o usam quando pedem ao codeg para executar uma linha de comando inteira.", + "terminalSystemDefault": "Padrão do sistema", + "terminalPowerShell7": "PowerShell 7 (pwsh)", + "terminalWindowsPowerShell": "Windows PowerShell", + "terminalCmd": "Prompt de Comando (cmd)", + "terminalSaveFailed": "Falha ao salvar as configurações do terminal: {message}", + "terminalShellCustom": "Caminho personalizado", + "terminalShellCustomPath": "Caminho do shell", + "terminalShellCustomPlaceholder": "/usr/local/bin/fish", + "terminalShellCustomSave": "Salvar", + "terminalShellCustomHint": "Informe um caminho absoluto ou um nome resolvível pelo PATH.", + "terminalShellNotInstalled": "não instalado", + "terminalShellNotFoundWarning": "Este caminho não existe neste host.", + "terminalCurrentShell": "Em uso: {path}", + "renderingDescription": "Desative a aceleração de hardware se o aplicativo apresentar tela preta ou falhas de renderização (comum em certas GPUs AMD ou GPUs Intel integradas). Aplica-se apenas à versão desktop do Windows.", + "disableHardwareAcceleration": "Desativar aceleração de hardware", + "renderingSaveFailed": "Falha ao salvar as configurações de renderização: {message}", + "restartRequired": "Salvo. Reinicie o aplicativo para aplicar a alteração.", + "restartNow": "Reiniciar agora", + "restartFailed": "Falha ao reiniciar: {message}", + "loadFailed": "Falha ao carregar: {message}" + }, + "LoginPage": { + "documentTitle": "Entrar - codeg", + "brand": "Codeg", + "subtitle": "Digite seu token de acesso para conectar ao aplicativo de desktop", + "tokenPlaceholder": "Token de acesso", + "connect": "Conectar", + "connecting": "Conectando...", + "helpText": "Encontre seu token no app de desktop em Configurações → Serviço Web", + "invalidToken": "Token inválido. Verifique e tente novamente.", + "connectionFailed": "Falha na conexão (HTTP {status})", + "networkError": "Não foi possível conectar ao servidor" + }, + "CommitPage": { + "title": "Confirmar", + "invalidFolderId": "ID de pasta inválido", + "loadingRepo": "Carregando repositório..." + }, + "MergePage": { + "title": "Resolver conflitos", + "invalidFolderId": "ID de pasta inválido", + "loadingRepo": "Carregando repositório...", + "localVersion": "Local (Nosso)", + "result": "Resultado", + "remoteVersion": "Remoto (Deles)", + "acceptLocal": "Aceitar local", + "acceptRemote": "Aceitar remoto", + "markResolved": "Marcar como resolvido", + "abortMerge": "Abortar", + "completeMerge": "Concluir merge", + "unresolvedConflicts": "Ainda há marcadores de conflito não resolvidos neste arquivo", + "fileResolved": "Arquivo resolvido com sucesso", + "allResolved": "Todos os conflitos resolvidos", + "conflictFiles": "Arquivos em conflito", + "loadingFile": "Carregando arquivo...", + "preparingMerge": "Preparando mesclagem...", + "selectFile": "Selecione um arquivo para resolver", + "noConflicts": "Nenhum arquivo em conflito", + "skipFile": "Pular", + "abortSuccess": "Operação abortada", + "applyAllNonConflicting": "Aplicar todas as alterações sem conflito", + "applyLeftNonConflicting": "Aplicar local", + "applyRightNonConflicting": "Aplicar remoto" + }, + "ImportSessions": { + "title": "Importar sessões locais", + "scanningTitle": "Verificando sessões locais dos agentes…", + "scanningHint": "Percorrendo o armazenamento local de sessões de cada agente. Históricos grandes podem levar um momento. As sessões já importadas são atualizadas no processo.", + "scanFailed": "Falha na verificação", + "retry": "Tentar novamente", + "rescan": "Verificar novamente", + "empty": "Nenhuma sessão local encontrada", + "emptyHint": "Nenhum armazenamento de sessões de agentes foi encontrado nesta máquina.", + "noMatches": "Nenhuma sessão corresponde aos filtros atuais", + "searchPlaceholder": "Pesquisar título ou caminho…", + "allAgents": "Todos os agentes", + "onlyImportable": "Somente importáveis", + "selectAll": "Selecionar tudo", + "clearSelection": "Limpar", + "expandAll": "Expandir tudo", + "collapseAll": "Recolher tudo", + "summaryCounts": "{total} sessões · {importable} importáveis · {folders} pastas", + "noFolderSkipped": "{count} sem pasta de projeto ignoradas", + "folderNew": "Nova", + "folderCounts": "{importable}/{total} importáveis", + "toggleFolderAria": "Selecionar todas as sessões importáveis de {name}", + "toggleSessionAria": "Selecionar a sessão {title}", + "statusImported": "Importada", + "statusDeleted": "Excluída", + "untitled": "Sessão sem título", + "messageCount": "{count} mensagens", + "selectedCount": "{count} selecionadas", + "importSelected": "Importar seleção", + "importing": "Importando…", + "close": "Fechar", + "doneTitle": "Importação concluída", + "doneImported": "Importadas", + "doneUpdated": "Atualizadas", + "doneSkipped": "Ignoradas", + "doneCreatedFolders": "Pastas criadas", + "doneNotFound": "Não encontradas", + "doneFailed": "Falharam", + "continueImport": "Continuar importando", + "toasts": { + "importFailed": "Falha ao importar: {message}" + } + }, + "Folder": { + "workspaceStatus": { + "degradedTitle": "Atualizações em tempo real indisponíveis", + "degradedHint": "O observador falhou ao iniciar (por exemplo, permissão negada). Atualize manualmente para ver as mudanças.", + "retry": "Tentar novamente", + "retrying": "Tentando novamente..." + }, + "common": { + "all": "Todos", + "cancel": "Cancelar", + "close": "Fechar", + "closeOthers": "Fechar outros", + "closeAll": "Fechar tudo", + "confirm": "Confirmar", + "save": "Salvar", + "delete": "Excluir", + "rename": "Renomear", + "loading": "Carregando...", + "refresh": "Atualizar", + "refreshing": "Atualizando...", + "create": "Criar", + "createAndSwitch": "Criar e alternar", + "openFile": "Abrir arquivo", + "viewDiff": "Ver Diff", + "push": "Enviar..." + }, + "statusLabels": { + "in_progress": "Em andamento", + "pending_review": "Revisão", + "completed": "Concluído", + "cancelled": "Cancelado" + }, + "sidebar": { + "title": "Conversas", + "locateActiveConversation": "Localizar conversa ativa", + "expandAllGroups": "Expandir todos os grupos", + "collapseAllGroups": "Recolher todos os grupos", + "newConversation": "Nova conversa", + "newConversationShort": "Nova", + "newChat": "Nova conversa", + "search": "Buscar", + "noConversationsFound": "Nenhuma conversa encontrada.", + "importLocalSessions": "Importar sessões locais", + "importing": "Importando...", + "error": "Erro: {message}", + "completeAllSessions": "Concluir todas as sessões", + "completeAllReviewTitle": "Concluir todas as sessões em revisão?", + "completeAllReviewDescription": "Isso marcará como concluídas todas as {count, plural, one {# sessão} other {# sessões}} em Revisão.", + "completing": "Concluindo...", + "toasts": { + "importedSessions": "Importadas {imported, plural, one {# sessão} other {# sessões}}, ignoradas {skipped}", + "importedAndUpdated": "Importadas {imported, plural, one {# sessão} other {# sessões}}, atualizados {updated, plural, one {# título} other {# títulos}}, ignoradas {skipped}", + "updatedTitles": "Atualizados {updated, plural, one {# título} other {# títulos}}, ignoradas {skipped}", + "noNewSessionsFound": "Nenhuma nova sessão encontrada (ignoradas {skipped})", + "importFailed": "Falha na importação: {message}", + "reviewCompleted": "Marcadas {count, plural, one {# sessão em revisão} other {# sessões em revisão}} como concluídas", + "completeReviewFailed": "Falha ao concluir sessões em revisão: {message}", + "folderOpened": "Pasta {name} aberta", + "folderRemoved": "Pasta {name} removida", + "openFolderFailed": "Falha ao abrir pasta", + "removeFolderFailed": "Falha ao remover pasta: {message}", + "reorderFoldersFailed": "Falha ao reordenar pastas: {message}", + "changeFolderColorFailed": "Falha ao alterar a cor: {message}", + "setFolderAliasFailed": "Falha ao definir o alias: {message}", + "changeFolderDefaultAgentFailed": "Falha ao definir agente padrão: {message}" + }, + "statsLabel": "{folders} pastas · {convos} conversas", + "reorderHandle": "Arraste para reordenar", + "openFolder": "Abrir pasta", + "searchPlaceholder": "Buscar conversas...", + "viewOptions": "Opções de exibição", + "showCompleted": "Mostrar conversas concluídas", + "showWorktrees": "Mostrar pastas de worktree", + "showRecent": "Mostrar grupo Recentes", + "moreOptions": "Mais opções", + "sortBy": "Ordenar por", + "sortByCreatedAt": "Data de criação", + "sortByUpdatedAt": "Data de atualização", + "sectionOrder": "Ordem das seções", + "sectionOrderMoveUp": "Mover para cima", + "sectionOrderMoveDown": "Mover para baixo", + "sectionOrderItemLabel": "{name} — posição {position} de {total}", + "statusRunningBadge": "Executando", + "runningCountBadge": "{count, plural, one {# sessão em execução} other {# sessões em execução}}", + "statusCancelledBadge": "Cancelado", + "worktreeRemovedBadge": "Worktree de origem removida", + "conversationCountUnit": "{count, plural, one {# conversa} other {# conversas}}", + "emptyFolderHint": "Sem conversas", + "noMatchingConversations": "Nenhuma conversa correspondente", + "noUnfinishedConversations": "Nenhuma conversa pendente. Ative \"Mostrar concluídas\" no menu superior direito.", + "removeFolderConfirmTitle": "Remover pasta do espaço de trabalho?", + "removeFolderConfirmDescription": "Remover \"{name}\" do espaço de trabalho? As abas e terminais relacionados serão fechados.", + "folderHeaderMenu": { + "manageConversations": "Gerenciar conversas…", + "manageLinks": "Pastas vinculadas", + "changeColor": "Alterar cor", + "useThemeColor": "Usar tema do app", + "setDefaultAgent": "Definir agente padrão", + "defaultAgentNone": "Sem padrão (usar global)", + "agentUnavailableSuffix": "(indisponível)", + "loadingAgents": "Carregando agentes…", + "setAlias": "Definir alias…", + "setAliasTitle": "Definir alias da pasta", + "setAliasPlaceholder": "Insira um alias (deixe vazio para limpar)", + "setAliasSave": "Salvar", + "setAliasCancel": "Cancelar", + "removeFromWorkspace": "Remover do espaço de trabalho" + }, + "manageConversations": { + "title": "Gerenciar conversas", + "searchPlaceholder": "Pesquisar por título…", + "agentFilterAll": "Todos os agentes", + "statusFilterAll": "Todos os status", + "folderFilterAll": "Todas as pastas", + "branchFilterAll": "Todas as branches", + "branchNone": "Sem branch", + "branchSearchPlaceholder": "Pesquisar branches…", + "noMatchingBranches": "Nenhuma branch correspondente", + "selectAllVisible": "Selecionar tudo", + "deselectAll": "Desmarcar tudo", + "selectedCount": "{count} selecionada(s)", + "matchedCount": "{count} correspondência(s)", + "untitledConversation": "Conversa sem título", + "setStatus": "Definir status…", + "deleteSelected": "Excluir", + "noConversations": "Sem conversas nesta pasta.", + "noConversationsWorkspace": "Sem conversas na área de trabalho.", + "noMatchingConversations": "Nenhuma conversa corresponde aos filtros.", + "confirmDeleteTitle": "Excluir {count} conversa(s)?", + "confirmDeleteDescription": "Esta ação não pode ser desfeita.", + "toastDeleted": "{count} conversa(s) excluída(s)", + "toastStatusUpdated": "Status atualizado para {count} conversa(s)", + "toastOpFailed": "Falha na operação: {message}" + }, + "sectionPinned": "Fixadas", + "sectionFolders": "Pastas", + "sectionChats": "Chat", + "sectionRecent": "Recentes", + "noChats": "Sem chats", + "noRecent": "Sem conversas recentes", + "showMoreRecent": "Mostrar mais ({count})", + "noFolders": "Nenhuma pasta aberta", + "newChatAction": "Novo chat", + "automations": "Automações", + "tasks": "Tarefas a fazer", + "loadingSubsessions": "Carregando subconversas…" + }, + "conversation": { + "reloadFailed": "Falha ao recarregar conversa: {message}", + "reloaded": "Conversa recarregada", + "reload": "Recarregar", + "activeConversationIndicator": "Conversa ativa", + "newConversation": "Nova conversa", + "closeConversation": "Fechar conversa", + "copyText": "Copiar texto", + "copyTextSuccess": "Copiado", + "copyTextFailed": "Falha ao copiar", + "forkSession": "Bifurcar sessão", + "forkSessionSuccess": "Sessão bifurcada com sucesso", + "forkSessionFailed": "Falha ao bifurcar a sessão: {error}", + "exportConversation": "Exportar conversa", + "exportImage": "Imagem", + "exportMarkdown": "Markdown", + "exportHtml": "HTML", + "exportSuccess": "Conversa exportada", + "exportFailed": "Falha ao exportar", + "exportImageTooLong": "A conversa é muito longa para exportar como imagem", + "exportLabels": { + "untitledConversation": "Conversa sem título", + "agent": "Agente", + "model": "Modelo", + "status": "Estado", + "started": "Início", + "updated": "Atualizado", + "tokens": "Estatísticas de tokens", + "duration": "Duração", + "inputTokens": "Entrada", + "outputTokens": "Saída", + "cacheRead": "Cache lido", + "cacheWrite": "Cache escrito", + "user": "Utilizador", + "assistant": "Assistente", + "system": "Sistema", + "toolResult": "Resultado", + "toolError": "Erro" + }, + "moreActions": "Mais ações" + }, + "sessionDetails": { + "menuLabel": "Detalhes da sessão", + "noActiveSession": "Nenhuma sessão ativa", + "title": "Detalhes da sessão", + "subtitle": "Metadados da sessão e uso de tokens", + "fieldTitle": "Título", + "untitled": "Conversa sem título", + "sessionId": "ID da sessão", + "externalId": "ID da extensão", + "agent": "Agente", + "model": "Modelo", + "status": "Estado", + "gitBranch": "Branch do Git", + "parentId": "Sessão principal", + "tokensHeading": "Uso de tokens", + "totalTokens": "Total", + "inputTokens": "Entrada", + "outputTokens": "Saída", + "cacheWrite": "Cache escrito", + "cacheRead": "Cache lido", + "contextWindow": "Janela de contexto", + "duration": "Duração", + "loadingStats": "Carregando uso de tokens…", + "loadFailed": "Falha ao carregar o uso de tokens", + "noStats": "Nenhum uso registrado", + "timestampsHeading": "Carimbos de data/hora", + "createdAt": "Criado", + "updatedAt": "Atualizado", + "none": "—", + "copyField": "Copiar {field}", + "copiedField": "{field} copiado" + }, + "conversationCard": { + "untitledConversation": "Conversa sem título", + "newConversation": "Nova conversa", + "rename": "Renomear", + "status": "Status", + "delete": "Excluir", + "importLocalSessions": "Importar sessões locais", + "importing": "Importando...", + "renameConversation": "Renomear conversa", + "deleteConversationTitle": "Excluir conversa?", + "deleteConversationDescription": "Isso excluirá \"{title}\". Esta ação não pode ser desfeita.", + "cancel": "Cancelar", + "save": "Salvar", + "pin": "Fixar", + "unpin": "Desafixar", + "markCompleted": "Marcar como concluída", + "reopen": "Reabrir", + "expandSubsessions": "Expandir subconversas", + "collapseSubsessions": "Recolher subconversas" + }, + "search": { + "dialogTitle": "Buscar", + "dialogTitleWithFolder": "Buscar — {name}", + "tabConversations": "Conversas", + "tabFiles": "Arquivos", + "placeholder": "Buscar conversas...", + "filePlaceholder": "Buscar arquivos ou diretórios...", + "allAgents": "Todos", + "searching": "Buscando...", + "typeToSearch": "Digite para buscar conversas", + "typeToSearchFiles": "Digite para buscar arquivos ou diretórios", + "noResults": "Nenhum resultado encontrado.", + "untitledConversation": "Conversa sem título" + }, + "folderTitleBar": { + "showSidebar": "Mostrar barra lateral", + "hideSidebar": "Ocultar barra lateral", + "toggleTerminal": "Alternar terminal", + "toggleAuxPanel": "Alternar painel auxiliar", + "search": "Buscar", + "openSettings": "Abrir configurações", + "backToConversations": "Voltar às conversas", + "withShortcut": "{label} (atalho: {shortcut})" + }, + "statusBar": { + "connection": { + "connected": "Conectado", + "connecting": "Conectando...", + "prompting": "Respondendo...", + "error": "Erro de conexão", + "disconnected": "Desconectado", + "tooltip": "{agent}: {status}", + "tooltipError": "{agent}: {error}", + "title": "Conexão do agente", + "triggerAria": "Conexão do agente: {status}", + "workingDir": "Diretório de trabalho", + "sessionId": "ID da sessão", + "viewerNote": "Anexado a uma sessão de outro cliente — reconectar apenas reanexa esta visualização.", + "reconnectInterrupts": "Reconectar reinicia o agente e interrompe o trabalho em andamento.", + "reconnect": "Reconectar", + "reconnecting": "Reconectando...", + "reconnectUnavailable": "Ainda não há sessão para reconectar." + }, + "tasks": { + "title": "Tarefas" + }, + "alerts": { + "title": "Alertas", + "empty": "Sem alertas", + "details": "Detalhes" + }, + "stats": { + "conversations": "{count} conversas", + "openUsage": "Ver estatísticas de sessões e uso de tokens" + }, + "tokens": { + "contextWindowUsageAria": "Uso da janela de contexto", + "contextWindow": "Janela de contexto", + "usedMax": "Usado / Máx", + "tokenUsage": "Uso de tokens", + "input": "Entrada", + "output": "Saída", + "cacheRead": "Leitura de cache", + "cacheWrite": "Gravação de cache", + "total": "Total de tokens" + } + }, + "auxPanel": { + "tabs": { + "files": "Arquivos", + "changes": "Alterações", + "commits": "Confirmações" + }, + "noFolderTitle": "Nenhuma pasta aberta", + "noFolderHint": "Abra uma pasta para ver seu conteúdo aqui" + }, + "windowControls": { + "minimizeWindow": "Minimizar janela", + "minimize": "Minimizar", + "maximizeWindow": "Maximizar janela", + "maximize": "Maximizar", + "restoreWindow": "Restaurar janela", + "restore": "Restaurar", + "closeWindow": "Fechar janela", + "close": "Fechar" + }, + "tabs": { + "closeConversationTab": "Fechar aba de conversa", + "close": "Fechar", + "closeOthers": "Fechar outros", + "splitRight": "Dividir à direita", + "splitDown": "Dividir abaixo", + "splitAndMoveRight": "Dividir e mover para a direita", + "splitAndMoveDown": "Dividir e mover para baixo", + "moveToOppositeGroup": "Mover para o grupo oposto", + "moveToGroup": "Mover para o grupo", + "groupLabel": "Grupo {index}", + "changeSplitterOrientation": "Alternar orientação do divisor", + "unsplit": "Desfazer divisão", + "unsplitAll": "Desfazer todas as divisões", + "closeAll": "Fechar tudo", + "tileDisplay": "Exibição em mosaico", + "untileDisplay": "Sair do mosaico" + }, + "fileWorkspace": { + "files": "Arquivos", + "closeFileTab": "Fechar aba de arquivo", + "close": "Fechar", + "closeOthers": "Fechar outros", + "closeAll": "Fechar tudo", + "preview": "Visualizar", + "editSource": "Editar fonte", + "maximize": "Maximizar", + "restore": "Restaurar", + "emptyDirectory": "Pasta vazia" + }, + "terminal": { + "rename": "Renomear", + "close": "Fechar", + "closeOthers": "Fechar outros", + "closeAll": "Fechar tudo", + "hideTerminal": "Ocultar terminal ({shortcut})", + "openFolderFirst": "Abra primeiro uma pasta" + }, + "workspaceDialog": { + "title": "Abrir pasta", + "manageTitle": "Pastas vinculadas", + "addTargetsTitle": "Adicionar pastas para vincular", + "pickRootDescription": "Escolha a pasta principal deste espaço de trabalho.", + "linksDescription": "Vincule outras pastas como subdiretórios para que os agentes trabalhem em todas elas a partir de um único espaço de trabalho.", + "addTargetsDescription": "Selecione uma ou mais pastas. Cada uma vira um subdiretório do espaço de trabalho.", + "useSystemPicker": "Seletor do sistema", + "next": "Avançar", + "back": "Voltar", + "done": "Concluir", + "change": "Alterar", + "addFolders": "Adicionar pastas", + "addSelected": "Adicionar", + "addSelectedCount": "Adicionar {count}", + "createCount": "Vincular {count} pasta(s)", + "discardPending": "Descartar", + "noLinks": "Ainda não há pastas vinculadas.", + "gitExclude": "Manter os vínculos fora do status do git", + "rename": "Renomear", + "unlink": "Remover vínculo", + "repair": "Recriar vínculo", + "saveName": "Salvar", + "cancelRename": "Cancelar", + "removePending": "Remover", + "willAppearAs": "Aparece como {name} no espaço de trabalho", + "renamedForDuplicate": "Renomeada — {base} já é usada por outro vínculo", + "renamedForExistingEntry": "Renomeada — {base} já existe nesta pasta", + "partiallyCreated": "Apenas {count} pasta(s) puderam ser vinculadas", + "openFailed": "Falha ao abrir a pasta", + "previewFailed": "Falha ao verificar as pastas selecionadas", + "createFailed": "Falha ao vincular as pastas", + "renameFailed": "Falha ao renomear o vínculo", + "removeFailed": "Falha ao remover o vínculo", + "repairFailed": "Falha ao recriar o vínculo", + "status": { + "ok": "Vinculada", + "missing": "O vínculo sumiu desta pasta", + "conflicted": "Outra entrada usa esse nome agora", + "broken": "A pasta vinculada não existe mais" + }, + "nameIssue": { + "empty": "Digite um nome", + "illegalChars": "Não pode conter / \\ : * ? \" < > |", + "tooLong": "Nome muito longo", + "reserved": "Este nome é reservado pelo Windows", + "duplicate": "Este nome já está em uso" + }, + "rejection": { + "not_found": "Pasta não encontrada", + "not_a_directory": "Este caminho não é uma pasta", + "same_as_root": "É a própria pasta do espaço de trabalho", + "ancestor_of_root": "Esta pasta contém o espaço de trabalho", + "inside_root": "Já está dentro do espaço de trabalho", + "already_linked": "Já vinculada", + "name_unavailable": "Não há mais nomes livres para esta pasta", + "alreadyLinkedAs": "Já vinculada como {name}" + } + }, + "folderNameDropdown": { + "fallbackFolderName": "Pasta", + "openFolder": "Abrir pasta", + "cloneRepository": "Clonar repositório", + "projectBoot": "Inicializador de projeto", + "opened": "Aberto", + "recentOpen": "Abertos recentemente" + }, + "fileWorkspacePanel": { + "addSelectionToChat": "Adicionar seleção ao chat", + "addToChat": "Adicionar ao chat", + "addSelectionToChatDone": "{label} adicionado à conversa", + "addFileToChat": "Adicionar arquivo ao chat", + "toggleWordWrap": "Alternar quebra de linha", + "addFileToChatDone": "{label} adicionado à conversa", + "viewDiff": "Ver Diff", + "openFile": "Abrir arquivo", + "fileCount": "{count, plural, one {# arquivo} other {# arquivos}}", + "openFileOrDiff": "Abra um arquivo ou diff pelo painel direito", + "disk": "Disco", + "head": "HEAD", + "unsaved": "Não salvo", + "workingTree": "Árvore de trabalho", + "loading": "Carregando...", + "compareWithBranch": "{path} · comparar com {branch}", + "hunkCount": "{count, plural, one {# bloco} other {# blocos}}", + "prev": "Anterior", + "next": "Próximo", + "jumpToLine": "Ir para a linha {line}", + "noParsedDiffSections": "Sem seções de diff analisadas", + "loadingEditor": "Carregando editor...", + "imageZoomIn": "Ampliar", + "imageZoomOut": "Reduzir", + "imageZoomReset": "Redefinir zoom", + "htmlPreviewTitle": "Visualização HTML", + "htmlPreviewTrust": "Ativar scripts", + "htmlPreviewTrustHint": "Executa os scripts deste arquivo e permite acesso à rede. Ative apenas para arquivos confiáveis.", + "officePreviewTitle": "Pré-visualização de documento do Office", + "officeFullRender": "Renderização completa", + "officeFullRenderHint": "Renderiza animações Morph, 3D e fórmulas (executa os scripts do próprio slide)", + "officeNotInstalled": "OfficeCLI não está instalado", + "officeNotInstalledHint": "Instale o OfficeCLI em Configurações → Ferramentas do Office para pré-visualizar arquivos do Word, Excel e PowerPoint.", + "officeOpenSettings": "Abrir configurações", + "officeWatchFailed": "Não foi possível iniciar a visualização ao vivo", + "officeWatchRetry": "Tentar novamente", + "officeServerInstallHint": "O OfficeCLI precisa estar instalado no host do servidor. Execute este comando lá e tente novamente:", + "officeRemoteDesktopUnsupported": "A pré-visualização ao vivo não está disponível em uma janela de área de trabalho remota. Abra este espaço de trabalho na interface web do servidor para visualizar arquivos do Office." + }, + "branchDropdown": { + "toasts": { + "commitCodeCompleted": "Commit de código concluído", + "pushCodeCompleted": "Push de código concluído", + "committedFiles": "{count, plural, one {# arquivo commitado} other {# arquivos commitados}}", + "taskCompleted": "{label} concluído", + "taskFailed": "{label} falhou", + "mergeNoNewCommits": "{branchName} não tem novos commits", + "mergedCommits": "{count, plural, one {# commit mesclado} other {# commits mesclados}}", + "allFilesUpToDate": "Todos os arquivos estão atualizados", + "updatedFiles": "{count, plural, one {# arquivo atualizado} other {# arquivos atualizados}}", + "openCommitWindowFailed": "Falha ao abrir a janela de commit", + "openPushWindowFailed": "Falha ao abrir janela de envio", + "upstreamSet": "A branch upstream foi definida", + "upstreamSetAndPushed": "Branch upstream definida e {count, plural, one {# commit} other {# commits}} enviado(s)", + "noCommitsToPush": "Não há commits para enviar", + "pushedCommits": "{count, plural, one {# commit enviado} other {# commits enviados}}", + "switchedToFolder": "Alternado para {name}", + "switchFailed": "Falha ao trocar de branch", + "openStashWindowFailed": "Falha ao abrir a janela de stash" + }, + "tasks": { + "newBranch": "Criar branch {name}", + "newWorktree": "Criar worktree {name}", + "checkoutTo": "Fazer checkout para {branchName}", + "mergeBranch": "Mesclar {branchName}", + "rebaseTo": "Rebase para {branchName}", + "deleteRemoteBranch": "Excluir branch remoto {branchName}", + "initGitRepo": "Inicializar repositório Git", + "pullCode": "Fazer pull do código", + "fetchInfo": "Buscar informações", + "pushCode": "Enviar código", + "stashChanges": "Fazer stash das alterações", + "stashPop": "Aplicar stash", + "deleteBranch": "Excluir branch {branchName}", + "removeWorktree": "Excluir o worktree de {branchName}", + "removeWorktreeAndBranch": "Excluir o worktree e o branch {branchName}", + "updateBranch": "Atualizar o branch {branchName}" + }, + "confirm": { + "mergeTitle": "Mesclar branch", + "rebaseTitle": "Rebase da branch", + "mergeDescription": "Mesclar {branchName} na branch atual {currentBranch}?", + "rebaseDescription": "Fazer rebase da branch atual {currentBranch} sobre {branchName}?", + "deleteRemoteTitle": "Excluir branch remoto", + "deleteRemoteDescription": "Excluir o branch remoto {branchName}? Isso o removerá do repositório remoto e não poderá ser desfeito.", + "deleteTitle": "Excluir branch", + "deleteDescription": "Excluir a branch {branchName}? Esta ação não pode ser desfeita.", + "forceDeleteTitle": "Forçar exclusão do branch", + "forceDeleteDescription": "O branch {branchName} não está totalmente mesclado. Tem certeza de que deseja forçar a exclusão? Esta ação não pode ser desfeita.", + "deleteWorktreeTitle": "Excluir worktree", + "deleteWorktreeDescription": "Excluir o diretório do worktree onde {branchName} está em uso? O branch e seus commits são mantidos.", + "forceDeleteWorktreeTitle": "Forçar a exclusão do worktree", + "forceDeleteWorktreeDescription": "O worktree de {branchName} tem arquivos não commitados ou não rastreados. Excluir mesmo assim? Essas alterações não poderão ser recuperadas.", + "deleteWorktreeAndBranchTitle": "Excluir worktree e branch", + "deleteWorktreeAndBranchDescription": "Excluir o worktree de {branchName}, o próprio branch e a pasta dele no espaço de trabalho? As sessões passam para a pasta do repositório. Esta ação não pode ser desfeita.", + "forceDeleteWorktreeAndBranchTitle": "Forçar a exclusão do worktree e do branch", + "forceDeleteWorktreeAndBranchDescription": "O worktree de {branchName} tem arquivos não commitados, ou o branch não está totalmente mesclado. Excluir os dois mesmo assim? Esta ação não pode ser desfeita." + }, + "current": "Atual", + "switchToBranch": "Mudar para esta branch", + "mergeBranchIntoCurrent": "Mesclar {branchName} em {currentBranch}", + "rebaseCurrentToBranch": "Rebase de {currentBranch} sobre {branchName}", + "noBranch": "Sem ramo", + "detachedHead": "HEAD desanexado em {sha}", + "initGitRepo": "Inicializar repositório Git", + "pullCode": "Fazer pull do código", + "fetchRemoteBranches": "Buscar branches remotas", + "openCommitWindow": "Commit de código...", + "pushCode": "Enviar...", + "pushBranch": "Enviar", + "newBranch": "Nova branch...", + "newWorktree": "Novo worktree...", + "stashChanges": "Guardar alterações...", + "stashPop": "Aplicar stash...", + "manageRemotes": "Gerenciar remotos...", + "localBranches": "Branches locais ({count, plural, one {#} other {#}})", + "noLocalBranches": "Sem branches locais", + "remoteBranches": "Branches remotas ({count, plural, one {#} other {#}})", + "noRemoteBranches": "Sem branches remotas", + "dialogs": { + "newBranchTitle": "Nova branch", + "newBranchDescription": "Criar uma nova branch a partir da branch atual {branch}", + "branchNamePlaceholder": "Nome da branch", + "newWorktreeTitle": "Novo worktree", + "newWorktreeDescription": "Criar um novo worktree a partir da branch atual {branch}", + "branchNameLabel": "Nome da branch", + "worktreePathLabel": "Caminho do worktree", + "worktreePathPlaceholder": "Caminho do worktree", + "manageRemotesTitle": "Gerenciar remotos", + "manageRemotesEmpty": "Nenhum remoto configurado", + "remoteNamePlaceholder": "Nome do remoto", + "remoteUrlPlaceholder": "URL do remoto", + "addRemote": "Adicionar", + "savingRemotes": "Salvando..." + }, + "conflict": { + "title": "Conflitos de merge", + "description": "Os seguintes arquivos têm conflitos que precisam ser resolvidos:", + "abort": "Abortar merge", + "openMergeTool": "Abrir ferramenta de merge", + "completeMerge": "Concluir merge", + "abortSuccess": "Merge abortado com sucesso", + "completeSuccess": "Merge concluído com sucesso" + }, + "stashDialog": { + "title": "Guardar alterações no stash", + "description": "Guardar as alterações atuais no stash", + "messageLabel": "Mensagem", + "messagePlaceholder": "Mensagem do stash (opcional)", + "keepIndex": "Manter índice (alterações preparadas permanecem preparadas)", + "cancel": "Cancelar", + "stash": "Guardar", + "success": "Alterações guardadas no stash", + "error": "Erro ao guardar no stash" + }, + "unstashDialog": { + "title": "Aplicar stash", + "noStashes": "Nenhum stash encontrado", + "selectFile": "Selecione um ficheiro para ver diferenças", + "viewDiff": "Ver diferenças", + "original": "Original", + "modified": "Modificado", + "apply": "Aplicar", + "drop": "Eliminar", + "applySuccess": "Stash aplicado", + "dropSuccess": "Stash eliminado", + "confirmApply": "Aplicar stash {ref} ao diretório de trabalho?", + "cancel": "Cancelar" + }, + "deleteBranch": "Excluir branch", + "deleteWorktree": "Excluir worktree", + "deleteWorktreeAndBranch": "Excluir worktree e branch", + "searchPlaceholder": "Pesquisar ramos e ações", + "searchAriaLabel": "Pesquisar ramos e ações", + "branchListLabel": "Ramos e ações", + "noMatches": "Nenhuma correspondência" + }, + "commitDialog": { + "toasts": { + "commitCompleted": "Commit de código concluído", + "pushFailed": "Falha no envio", + "committedFiles": "{count, plural, one {# arquivo commitado} other {# arquivos commitados}}", + "addedToVcs": "Adicionado ao VCS", + "addToVcsFailed": "Falha ao adicionar ao VCS", + "fileDeleted": "Arquivo excluído", + "deleteFailed": "Falha ao excluir", + "fileRolledBack": "Arquivo revertido", + "rollbackFailed": "Falha no rollback", + "dirRolledBack": "Diretório revertido", + "dirDeleted": "Diretório excluído" + }, + "confirm": { + "deleteTitle": "Confirmar exclusão", + "deleteDescription": "Excluir o arquivo \"{file}\"? Esta ação não pode ser desfeita.", + "rollbackTitle": "Confirmar rollback", + "rollbackDescription": "Reverter o arquivo \"{file}\" para o HEAD? Alterações não salvas serão perdidas.", + "rollbackDirDescription": "Reverter o diretório \"{dir}\" para HEAD? Alterações não salvas serão perdidas.", + "deleteDirDescription": "Excluir o diretório \"{dir}\"? Esta ação não pode ser desfeita." + }, + "actions": { + "select": "Selecionar", + "unselect": "Desmarcar", + "rollback": "Reverter", + "addToVcs": "Adicionar ao VCS" + }, + "aria": { + "selectFile": "{action}: {path}", + "unselectAllFiles": "Desmarcar todos os arquivos", + "selectAllFiles": "Selecionar todos os arquivos", + "unselectTracked": "Desmarcar alterações rastreadas", + "selectTracked": "Selecionar alterações rastreadas", + "unselectUntracked": "Desmarcar arquivos não rastreados", + "selectUntracked": "Selecionar arquivos não rastreados" + }, + "loading": "Carregando...", + "selectionCount": "{selected} / {total} arquivos", + "emptyFiles": "Sem arquivos alterados", + "trackedChanges": "Alterações rastreadas ({count})", + "untrackedFiles": "Arquivos não rastreados ({count})", + "commitMessage": "Mensagem de commit", + "commitMessagePlaceholder": "Digite a mensagem de commit...", + "commitButton": "Confirmar ({count})", + "commitAndPushButton": "Confirmar e enviar ({count})", + "head": "HEAD", + "workingTree": "Árvore de trabalho", + "clickFileToDiff": "Clique no nome do arquivo para ver o diff", + "loadingDiff": "Carregando diff..." + }, + "pushWindow": { + "title": "Enviar código", + "noUnpushedCommits": "Nenhum commit não enviado", + "noRemoteConfigured": "Nenhum remoto Git configurado\nAdicione um em «Gerenciar remotos»", + "newBranchNoPushedCommits": "Nova branch — enviar para criar branch de rastreamento remota", + "unpushed": "Não enviado", + "selectFileToViewDiff": "Selecione um arquivo para ver as diferenças", + "before": "Antes", + "after": "Depois", + "push": "Enviar", + "toasts": { + "pushSuccess": "Envio bem-sucedido", + "pushFailed": "Falha no envio", + "upstreamSet": "Branch remoto foi configurado", + "upstreamSetAndPushed": "Branch remoto configurado e {count} commits enviados", + "noCommitsToPush": "Nenhum commit para enviar", + "pushedCommits": "{count} commits enviados" + } + }, + "gitLogTab": { + "filesTitle": "Arquivos", + "expandAllFiles": "Expandir todos os arquivos", + "collapseAllFiles": "Recolher todos os arquivos", + "workspace": "espaço de trabalho", + "retry": "Tentar novamente", + "noCommitsFound": "Nenhum commit encontrado", + "notAGitRepoTitle": "Não é um repositório Git", + "notAGitRepoHint": "Inicialize o Git pelo menu de ramificações acima, ou abra um repositório existente.", + "hash": "Hash do commit", + "copyHash": "Copiar hash", + "copyMessage": "Copiar mensagem", + "showMore": "Mostrar mais", + "showLess": "Mostrar menos", + "author": "Autor", + "noFileChangeDetails": "Sem detalhes de alteração de arquivos disponíveis.", + "loadingFiles": "Carregando arquivos...", + "branchesTitle": "Branches Git", + "loadingBranches": "Carregando branches...", + "noContainingBranches": "Nenhuma branch contendo este commit foi encontrada.", + "newBranch": "Nova branch...", + "resetToHere": "Resetar para aqui", + "resetDisabledReasonNotCurrentBranchView": "Disponível somente ao visualizar a branch atual", + "copyFullCommitHashAria": "Copiar hash completo do commit {hash}", + "pushStatus": { + "pushed": "Enviado para o remoto", + "notPushed": "Não enviado para o remoto", + "unknown": "Status de push desconhecido (upstream não configurado)" + }, + "time": { + "monthsAgo": "{count, plural, one {há # mês} other {há # meses}}", + "daysAgo": "{count, plural, one {há # dia} other {há # dias}}", + "hoursAgo": "{count, plural, one {há # hora} other {há # horas}}", + "minsAgo": "{count, plural, one {há # min} other {há # mins}}", + "justNow": "agora mesmo" + }, + "toasts": { + "createdAndSwitchedNewBranch": "Nova branch criada e selecionada", + "newBranchFromCommit": "{name} (de {shortHash})", + "createBranchFailed": "Falha ao criar branch", + "openPushWindowFailed": "Falha ao abrir a janela de push", + "resetSuccess": "Reset concluído", + "resetSuccessDescription": "{branch} foi resetada para {shortHash} com {mode}", + "resetFailed": "Falha no reset" + }, + "authorFilter": { + "label": "Autor", + "searchPlaceholder": "Pesquisar autor", + "noAuthors": "Nenhum autor encontrado", + "you": "você", + "filterByAuthorAria": "Filtrar commits por autor", + "filterByQuery": "Filtrar por \"{query}\"", + "clearAuthorFilterAria": "Limpar filtro de autor", + "recent": "Recentes", + "matchingAuthors": "Autores correspondentes", + "removeFromRecent": "Remover {name} dos recentes" + }, + "branchSelector": { + "label": "Branch", + "head": "HEAD", + "headHint": "Acompanha a branch atual", + "headHintWithBranch": "Acompanha a branch atual ({branch})", + "searchBranch": "Pesquisar branch...", + "noBranches": "Nenhum branch", + "selectBranchPlaceholder": "Selecionar branch...", + "localBranches": "Branches locais", + "current": "Atual", + "remoteBranches": "Branches remotas", + "refreshCommitHistory": "Atualizar histórico de commits", + "clearBranchFilterAria": "Limpar filtro de branch" + }, + "dialogs": { + "newBranchTitle": "Nova branch", + "newBranchDescription": "Criar uma nova branch com o commit {shortHash} como commit mais recente.", + "branchNamePlaceholder": "Nome da branch", + "reset": { + "title": "Resetar a branch atual para este commit", + "branchLabel": "Branch", + "targetLabel": "Commit alvo", + "messageLabel": "Mensagem", + "modeLabel": "Modo de reset", + "confirmButton": "Resetar", + "modes": { + "soft": { + "label": "--soft", + "description": "Move o HEAD e o ponteiro da branch atual para o commit alvo.\nMantém Index e Working Tree sem alterações.\nAs mudanças dos commits removidos permanecem staged." + }, + "mixed": { + "label": "--mixed (padrão)", + "description": "Move o HEAD para o commit alvo.\nReseta o Index para o commit alvo e mantém as mudanças no Working Tree.\nAs mudanças passam de staged para unstaged." + }, + "hard": { + "label": "--hard", + "description": "Move o HEAD e reseta tanto Index quanto Working Tree para o commit alvo.\nAs mudanças locais rastreadas após o commit alvo são descartadas.\nEsta é uma operação destrutiva." + }, + "keep": { + "label": "--keep", + "description": "Move o HEAD para o commit alvo e tenta preservar alterações locais.\nSomente alterações sem conflito são mantidas.\nSe houver conflito, o reset é abortado para proteger seu trabalho." + } + } + } + }, + "moreActions": "Mais ações do Git" + }, + "gitChangesTab": { + "workspace": "espaço de trabalho", + "noChanges": "Sem alterações locais", + "notAGitRepoTitle": "Não é um repositório Git", + "notAGitRepoHint": "Inicialize o Git pelo menu de ramificações acima, ou abra um repositório existente.", + "trackedChanges": "Alterações rastreadas ({count})", + "untrackedFiles": "Arquivos não rastreados ({count})", + "expandTracked": "Expandir alterações rastreadas", + "collapseTracked": "Recolher alterações rastreadas", + "expandUntracked": "Expandir arquivos não rastreados", + "collapseUntracked": "Recolher arquivos não rastreados", + "showRemainingItems": "Mostrar mais {count} itens", + "actions": { + "commitCode": "Commit do código", + "rollback": "Reverter", + "addToVcs": "Adicionar ao VCS", + "delete": "Excluir", + "moreActions": "Mais ações do Git", + "addAllToVcs": "Adicionar tudo ao VCS", + "rollbackAll": "Reverter tudo", + "refresh": "Atualizar" + }, + "toasts": { + "noAddableFilesInDir": "Nenhum arquivo alterado neste diretório pode ser adicionado ao VCS", + "noRollbackFilesInDir": "Nenhum arquivo alterado neste diretório pode ser revertido", + "addedToVcs": "{name} adicionado ao VCS", + "addToVcsFailed": "Falha ao adicionar ao VCS", + "openCommitWindowFailed": "Falha ao abrir a janela de commit", + "rolledBack": "{name} revertido", + "rollbackFailed": "Falha no rollback", + "addedFilesToVcs": "{count, plural, one {# arquivo} other {# arquivos}} adicionados ao VCS", + "rolledBackFiles": "{count, plural, one {# arquivo revertido} other {# arquivos revertidos}}", + "deleted": "{name} excluído", + "deleteFailed": "Falha ao excluir", + "deletedFiles": "{count} arquivos excluídos", + "noDeletableFilesInDir": "Nenhum arquivo alterado neste diretório pode ser excluído", + "commitFailed": "Falha ao confirmar" + }, + "directoryDialog": { + "descriptionAdd": "Selecione arquivos sob o diretório {path} para adicionar ao VCS.", + "descriptionRollback": "Selecione arquivos sob o diretório {path} para reverter.", + "descriptionDelete": "Selecione arquivos no diretório {path} para excluir. Esta ação não pode ser desfeita.", + "descriptionFallback": "Selecione arquivos para prosseguir.", + "selectionCount": "Selecionados {selected} / {total} arquivos", + "selectAll": "Selecionar todos", + "unselectAll": "Desmarcar todos", + "loadingCandidates": "Carregando alterações do diretório...", + "noOperableFiles": "Nenhum arquivo operável" + }, + "rollbackConfirm": { + "title": "Confirmar rollback", + "descriptionWithTarget": "Reverter alterações locais de {kind} \"{name}\"?", + "descriptionFallback": "Reverter alterações locais?", + "kindDirectory": "diretório", + "kindFile": "arquivo" + }, + "deleteConfirm": { + "title": "Confirmar exclusão", + "descriptionWithTarget": "Excluir {kind} \"{name}\"? Esta ação não pode ser desfeita.", + "descriptionFallback": "Esta ação não pode ser desfeita.", + "kindDirectory": "diretório", + "kindFile": "arquivo" + }, + "quickCommit": { + "placeholder": "Mensagem do commit (Enter para confirmar)" + } + }, + "tabContext": { + "loadingConversation": "Carregando...", + "untitledConversation": "Conversa sem título", + "newConversation": "Nova conversa" + }, + "fileTreeTab": { + "workspace": "Espaço de trabalho", + "retry": "Tentar novamente", + "git": "Git", + "openInFileManager": "Abrir no gerenciador de arquivos", + "openInFinder": "Abrir no Finder", + "openInExplorer": "Abrir no Explorer", + "attachToCurrentSession": "Adicionar à sessão", + "compareWithBranch": "Comparar com branch...", + "reloadFromDisk": "Recarregar do disco", + "new": "Novo", + "newFile": "Arquivo", + "newDirectory": "Diretório", + "openIn": "Abrir em", + "openInTerminal": "Abrir no terminal", + "linkedFolder": "Pasta vinculada", + "copyPath": "Copiar caminho", + "upload": "Enviar arquivos/pasta", + "download": "Baixar arquivo", + "downloadAsZip": "Baixar como ZIP", + "actions": { + "select": "Selecionar", + "unselect": "Desmarcar", + "commitCode": "Fazer commit do código", + "rollback": "Reverter", + "addToVcs": "Adicionar ao VCS" + }, + "aria": { + "selectPath": "{action}: {path}" + }, + "toasts": { + "openDirectoryFailed": "Falha ao abrir diretório", + "openBuiltinTerminalFailed": "Não foi possível abrir o terminal embutido", + "openCommitWindowFailed": "Falha ao abrir janela de commit", + "noAddableFilesInDir": "Nenhum arquivo alterado neste diretório pode ser adicionado ao VCS", + "noRollbackFilesInDir": "Nenhum arquivo alterado neste diretório pode ser revertido", + "addedToVcs": "{name} adicionado ao VCS", + "addToVcsFailed": "Falha ao adicionar ao VCS", + "loadBranchesFailed": "Falha ao carregar branches", + "renameFailed": "Falha ao renomear", + "moveFailed": "Falha ao mover", + "deleteFailed": "Falha ao excluir", + "rolledBack": "{name} revertido", + "rollbackFailed": "Falha ao reverter", + "addedFilesToVcs": "{count, plural, one {# arquivo adicionado ao VCS} other {# arquivos adicionados ao VCS}}", + "rolledBackFiles": "{count, plural, one {# arquivo revertido} other {# arquivos revertidos}}", + "savedAsCopy": "Salvo como cópia", + "saveCopyFailed": "Falha ao salvar como cópia", + "watchStartFailed": "Falha ao iniciar monitoramento de arquivos", + "createFailed": "Falha ao criar", + "downloadFailed": "Falha ao baixar {name}", + "downloadSaved": "{name} baixado", + "pathCopied": "Caminho copiado", + "copyPathFailed": "Falha ao copiar o caminho" + }, + "createDialog": { + "newFile": "Novo arquivo", + "newDirectory": "Novo diretório", + "description": "Digite um nome para o novo {kind}.", + "placeholderFile": "file-name.ext", + "placeholderDirectory": "folder-name" + }, + "renameDialog": { + "renameDirectory": "Renomear diretório", + "renameFile": "Renomear arquivo", + "description": "Digite um novo nome (apenas nome, sem caminho).", + "placeholderDirectory": "novo-nome-da-pasta", + "placeholderFile": "novo-nome-do-arquivo.ext" + }, + "uploadDialog": { + "title": "Enviar para o workspace", + "description": "Ajuste o destino se necessário e adicione arquivos ou pastas.", + "workspaceRoot": "raiz do workspace", + "targetPathLabel": "Enviar para", + "targetPathHint": "Caminho resolvido: {path}", + "dropHint": "Arraste arquivos ou pastas aqui, ou use os botões abaixo", + "dropHintActive": "Solte para adicionar à fila", + "selectFiles": "Selecionar arquivos", + "selectFolder": "Selecionar pasta", + "startUpload": "Iniciar upload", + "clearQueue": "Limpar finalizados", + "removeItem": "Remover da fila", + "retry": "Tentar novamente", + "dropZoneAria": "Solte arquivos aqui ou ative para procurar", + "folderEmpty": "Nenhum arquivo encontrado na pasta solta", + "summary": "Total: {total} · Sucesso: {succeeded} · Falhas: {failed}", + "status": { + "pending": "Aguardando", + "uploading": "Enviando", + "success": "Concluído", + "error": "Falhou", + "cancelled": "Cancelado" + } + }, + "directoryDialog": { + "descriptionAdd": "Selecione arquivos no diretório {path} para adicionar ao VCS.", + "descriptionRollback": "Selecione arquivos no diretório {path} para reverter.", + "descriptionFallback": "Selecione arquivos para continuar.", + "selectionCount": "{selected} / {total} arquivos selecionados", + "selectAll": "Selecionar tudo", + "unselectAll": "Desmarcar tudo", + "loadingCandidates": "Carregando alterações do diretório...", + "noOperableFiles": "Nenhum arquivo operável" + }, + "compareDialog": { + "title": "Comparar com branch", + "descriptionWithTarget": "Selecione uma branch e compare com {kind} {path}", + "descriptionFallback": "Selecione uma branch para comparar.", + "kindDirectory": "diretório", + "kindFile": "arquivo", + "filterPlaceholder": "Filtre branches, ex.: main / origin/main", + "singleClickHint": "Clique em uma branch para comparar diretamente", + "loadingBranches": "Carregando branches...", + "recentBranches": "Branches recentes ({count})", + "noCurrentBranch": "Sem branch atual", + "localBranches": "Branches locais ({count})", + "remoteBranches": "Branches remotas ({count})", + "noMatchingBranches": "Nenhuma branch correspondente" + }, + "externalConflictDialog": { + "title": "Alterações externas de arquivo detectadas", + "descriptionWithPath": "O arquivo {path} foi alterado no disco e as edições atuais não foram salvas.", + "descriptionFallback": "O arquivo atual foi alterado no disco e as edições atuais não foram salvas.", + "compare": "Comparar", + "savingCopy": "Salvando cópia...", + "saveAsCopy": "Salvar como cópia", + "reload": "Recarregar" + }, + "deleteConfirm": { + "title": "Confirmar exclusão", + "descriptionWithTarget": "Excluir {kind} \"{name}\"? Esta ação não pode ser desfeita.", + "descriptionFallback": "Esta ação não pode ser desfeita.", + "kindDirectory": "diretório", + "kindFile": "arquivo" + }, + "rollbackConfirm": { + "title": "Confirmar reversão", + "descriptionWithTarget": "Reverter alterações locais do arquivo \"{name}\"?", + "descriptionFallback": "Reverter alterações locais deste arquivo?" + }, + "terminalTitle": "Console · {name}" + }, + "commandDropdown": { + "loading": "Carregando...", + "addCommand": "Adicionar comando", + "manageCommands": "Gerenciar comandos...", + "runCommandTitle": "Executar: {command}", + "stopCommandTitle": "Parar: {command}", + "manageDialog": { + "title": "Gerenciar comandos", + "empty": "Ainda não há comandos", + "noResults": "Nenhum comando correspondente", + "searchPlaceholder": "Pesquisar comandos", + "newCommand": "Novo comando", + "nameLabel": "Nome", + "commandLabel": "Comando", + "dragSort": "Arraste para ordenar", + "dragSortCommand": "Arraste para ordenar {name}", + "orderFailed": "Falha ao salvar a ordem dos comandos", + "loadFailed": "Falha ao carregar os comandos", + "saveFailed": "Falha ao salvar o comando", + "deleteFailed": "Falha ao excluir o comando", + "confirmDelete": { + "title": "Excluir comando?", + "message": "Isso removerá \"{name}\". Esta ação não pode ser desfeita." + } + } + }, + "workspaceContext": { + "confirmCloseDirtyTab": "Fechar \"{title}\" sem salvar?", + "confirmCloseOtherDirtyTabs": "Fechar outras abas com alterações não salvas?", + "confirmCloseAllDirtyTabs": "Fechar todas as abas com alterações não salvas?", + "unableLoadContent": "Não foi possível carregar o conteúdo.\n\n{message}", + "previewRequestTimedOut": "A solicitação de preview expirou", + "diffRequestTimedOut": "A solicitação de Diff expirou", + "branchCompareRequestTimedOut": "A solicitação de comparação de branch expirou", + "commitDiffRequestTimedOut": "A solicitação de Diff de commit expirou", + "saveRequestTimedOut": "A solicitação de salvamento expirou", + "reloadRequestTimedOut": "A solicitação de recarga expirou", + "noChanges": "Sem alterações.", + "noDiffOutput": "Sem saída de diff.", + "diffTitleWorkspace": "Diff · Espaço de trabalho", + "diffDescriptionWorkingTree": "Árvore de trabalho (HEAD)", + "diffTitleFile": "Diferença · {name}", + "compareTitleFile": "Comparar · {name}", + "compareTitleBranch": "Comparar · {branch}", + "compareDescriptionPath": "{path} · comparar com {branch}", + "compareDescriptionBranch": "comparar com {branch}", + "diffTitleCommitFile": "Diferença · {name} @ {hash}", + "diffTitleCommit": "Diferença · {hash}", + "diffDescriptionCommitPath": "{path} · confirmação {commit}", + "diffDescriptionCommit": "confirmação {commit}", + "diffTitleConflictFile": "Conflito · {name}", + "diffDescriptionConflict": "{path} · disco vs não salvo" + }, + "chat": { + "acpConnections": { + "actions": { + "openAgentsSettings": "Abrir configurações de agentes", + "retry": "Tentar novamente" + }, + "agentsSetupHint": "Abra Configurações > Agentes para gerenciar a instalação.", + "withSetupHint": "{message}\n{hint}", + "blocked": { + "missingConfig": "Não foi possível ler a configuração atual do agente.", + "disabled": "{agent} está desativado nas configurações de agentes. Ative-o antes de conectar.", + "unavailable": "{agent} está indisponível na plataforma atual.", + "sdkMissing": "O SDK de {agent} não está instalado", + "adapterMissing": "O adaptador ACP de {agent} não está instalado" + }, + "backendErrors": { + "initializeTimeout": "O handshake de conexão de {agent} expirou (sem resposta após 60 segundos). Abra Configurações para verificar a configuração do agente e da rede.", + "mcpRejectedByAgent": "{agent} recusou a sessão com o companheiro MCP do codeg anexado: {message} Se este agente não suporta MCP, desative “Suporte a MCP” nas Configurações e conecte novamente.", + "processExited": "O processo de {agent} encerrou inesperadamente.", + "spawnFailed": "Falha ao iniciar {agent}: {message}", + "downloadFailed": "Falha no download de {agent}: {message}", + "sessionLoadResourceNotFound": "Falha ao carregar a sessão de {agent}. Recarregue para tentar novamente ou inicie uma nova conversa.", + "sessionLoadUnavailable": "{agent} não conseguiu restaurar esta sessão; ela pode ter terminado ou o agente parou. Recarregue para tentar novamente ou inicie uma nova conversa.", + "turnFailedRefusal": "{agent} recusou continuar este turno. Costuma indicar um erro de backend ou gateway. Confira os logs do agente.", + "turnFailedMaxTokens": "{agent} atingiu o limite máximo de tokens para este turno.", + "turnFailedMaxTurnRequests": "{agent} atingiu o número máximo de solicitações permitidas para este turno.", + "turnFailedUnknown": "{agent} encerrou o turno com um motivo de parada desconhecido.", + "grokModelSwitchIncompatibleAgent": "{agent} não pode mudar para esse modelo em uma conversa existente. Inicie uma nova sessão para usá-lo.", + "turnFailedEmpty": "{agent} encerrou o turno sem produzir nenhuma resposta.", + "turnFailedEmptyProtocol": "{agent} produziu uma saída que o codeg não conseguiu analisar — a versão do agente pode não corresponder ao protocolo.", + "turnFailedEmptyMetadata": "{agent} enviou apenas atualizações de status neste turno (plano / modo / uso) e nenhuma resposta.", + "detailsInAlerts": "Abra os alertas na barra de status e expanda os detalhes para ver a saída do agente." + }, + "unableReadAgentConfig": "Não foi possível ler a configuração do agente: {message}", + "connectFailedTitle": "Falha na conexão de {agent}", + "toolFallbackTitle": "Ferramenta", + "eventErrorTitle": "Erro do agente", + "notificationTurnComplete": "{agent} terminou de responder", + "notificationError": "{agent} erro: {message}", + "claudeApiRetry": { + "fallbackError": "authentication_failed", + "retryingWithMax": "tentando novamente {attempt}/{max}", + "retryingAttempt": "tentando novamente tentativa {attempt}", + "retrying": "tentando novamente", + "nextRetryIn": "próxima em {seconds}s", + "line": "{error}{status} · {retry}", + "lineWithDelay": "{error}{status} · {retry}, {delay}", + "httpStatus": " (HTTP {status})" + }, + "configOptionAdjusted": "O {agent} definiu {option} como {actual} em vez de {requested}" + }, + "connectionLifecycle": { + "tasks": { + "connectingTitle": "Conectando a {agent}", + "connectingDescription": "Estabelecendo conexão", + "loadingSelectorsTitle": "Carregando seletores de {agent}", + "loadingSelectorsDescription": "Buscando opções de modo e configuração de sessão", + "initSessionTitle": "Initializing {agent} session", + "initSessionDescription": "Creating session and loading configuration" + }, + "errors": { + "connectionFailed": "Falha na conexão", + "sendPromptFailed": "Falha ao enviar a mensagem: {error}" + } + }, + "shared": { + "attachedResources": "Recursos anexados", + "toolCallFailed": "Falha na chamada da ferramenta" + }, + "messageThread": { + "emptyTitle": "Ainda não há mensagens", + "emptyDescription": "Inicie uma conversa para ver mensagens aqui" + }, + "chatInput": { + "connecting": "Conectando...", + "agentResponding": "{agent} está respondendo...", + "sendMessage": "Envie uma mensagem..." + }, + "messageInput": { + "askAnything": "Pergunte qualquer coisa...", + "removeAttachmentAria": "Remover {name}", + "attachFiles": "Anexar arquivos", + "addActions": "Adicionar", + "quickMessages": "Mensagens rápidas", + "quickMessagesEmpty": "Ainda não há mensagens rápidas", + "quickMessagesLoading": "Carregando...", + "pasteAsPlainText": "Colar como texto simples", + "cut": "Cortar", + "copy": "Copiar", + "selectAll": "Selecionar tudo", + "pasteUnavailable": "Não foi possível ler a área de transferência. Use Ctrl/⌘V para colar.", + "clipboardWriteFailed": "Não foi possível escrever na área de transferência. Use o atalho de teclado.", + "quickMessageUntitled": "Sem título", + "liveFeedback": "Feedback ao vivo", + "liveFeedbackDisabledHint": "Disponível enquanto o agente trabalha", + "dropFilesToAttach": "Solte arquivos para anexar", + "loadingSettings": "Carregando configurações...", + "loadingMode": "Carregando modo...", + "modeLabel": "Modo", + "toggleOn": "Ligado", + "toggleOff": "Desligado", + "agentSettings": "Configurações do agente", + "searchModel": "Buscar modelos...", + "searchModelAria": "Buscar modelos", + "modelListLabel": "Modelos", + "noModels": "Nenhum modelo encontrado", + "cancel": "Cancelar", + "send": "Enviar", + "forkAndSend": "Fork & Enviar", + "queueMessage": "Adicionar à fila", + "steerIntoTurn": "Inserir no turno atual", + "steerQueuedInstead": "Adicionado à fila — será enviado no próximo turno.", + "steerFailed": "Não foi possível inserir no turno atual", + "steerAttachmentsUnsupported": "Somente texto — rascunhos com anexos vão pela fila.", + "slashCommands": "Comandos de barra", + "slashSearchPlaceholder": "Buscar comandos...", + "slashSearchEmpty": "Nenhum comando correspondente", + "experts": "Especialistas", + "office": "Escritório", + "research": "Pesquisa", + "attachLocalUpload": "Carregar arquivo local", + "attachServerFile": "Selecionar arquivo do servidor", + "attachUploadTooLarge": "{names} excede o limite de upload de {limit}MB e foi ignorado.", + "attachUploadFailed": "Falha ao enviar {names}.", + "attachUploadNotAFile": "{names} não é um arquivo regular (diretório ou arquivo especial) e foi ignorado.", + "attachUploadQuotaExceeded": "O servidor ficou sem espaço para uploads; {names} não pôde ser enviado.", + "attachUploadInProgress": "As imagens ainda estão sendo enviadas — tente novamente em instantes.", + "mentionEmpty": "Nenhuma correspondência", + "mentionLoading": "Pesquisando…", + "mentionListLabel": "Menções", + "mentionMore": "Mais resultados — continue digitando para filtrar", + "mentionCount": "{count, plural, one {# resultado} other {# resultados}}", + "mentionGroupFile": "Arquivos", + "mentionGroupAgent": "Agentes", + "mentionGroupSession": "Sessões", + "mentionGroupCommit": "Commits", + "mentionGroupSkill": "Habilidades" + }, + "messageQueue": { + "addToQueue": "Adicionar à fila", + "saveEdit": "Salvar", + "cancelEdit": "Cancelar edição", + "editItem": "Editar", + "deleteItem": "Remover" + }, + "welcomeInputPanel": { + "agentsSettingsPath": "Configurações > Agentes", + "autoConnectFallback": "Clique para abrir {path} e gerenciar a instalação.", + "autoConnectAppend": "{message}. Clique para abrir {path} e gerenciar a instalação.", + "enableAgentFirstPlaceholder": "Ative pelo menos um agente antes de iniciar uma sessão...", + "prepareSessionFailed": "Não foi possível preparar a sessão de chat. Tente novamente.", + "createConversationFailed": "Não foi possível criar a conversa. Tente novamente.", + "askAnythingPlaceholder": "Pergunte qualquer coisa...", + "agentNotInstalled": "{agent} não está instalado · abra as configurações de Agents para instalá-lo", + "agentAdapterNotInstalled": "O adaptador ACP de {agent} não está instalado (separado da sua própria CLI) · abra as configurações de Agents para instalá-lo" + }, + "welcomePanel": { + "greeting": "O que você gostaria de fazer hoje?", + "tips": { + "tileTabs": "Clique com o botão direito em uma aba de conversa e escolha Exibir em mosaico para ver várias sessões lado a lado.", + "pinTab": "Clique duas vezes em uma aba de conversa para fixá-la, evitando que uma nova sessão a substitua automaticamente.", + "shortcutsNewSearch": "{newConversation} abre uma nova conversa, {searchConversations} pesquisa no histórico.", + "slashAtMention": "Digite / na entrada para acionar comandos slash, ou @ para referenciar um arquivo do projeto.", + "pasteDropFiles": "Cole uma captura de tela ou arraste um arquivo direto para a entrada para anexá-lo.", + "queueMessage": "Enquanto o agente responde, continue digitando — sua próxima mensagem entra na fila e é enviada automaticamente ao terminar.", + "draftAutoSave": "Rascunhos não enviados são salvos automaticamente por conversa e restaurados quando você volta.", + "forkSend": "O menu suspenso do botão de enviar tem Bifurcar e enviar — ramifique do ponto atual para uma nova aba.", + "exportConversation": "Clique com o botão direito dentro da conversa para exportá-la como Markdown, HTML ou imagem.", + "chatChannels": "Conecte Telegram / Lark / WeChat em Configurações → Canais de chat para continuar pelo celular.", + "shortcutsAuxPanel": "{toggleAuxPanel} alterna o painel direito para ver os arquivos tocados e as mudanças do Git desta sessão.", + "shortcutsTerminalSidebar": "{toggleTerminal} abre o terminal integrado, {toggleSidebar} alterna a barra lateral.", + "customShortcuts": "Todos os atalhos podem ser reatribuídos em Configurações → Atalhos.", + "webService": "Ative Configurações → Serviço web para que sua equipe acesse o mesmo codeg pelo navegador.", + "fusionMode": "Abra um arquivo ou diff para exibi-lo automaticamente ao lado da conversa.", + "quickMessages": "Abra o botão + ao lado da entrada e escolha Mensagens rápidas para inserir um trecho salvo (gerencie-os em Configurações → Mensagens rápidas).", + "experts": "O botão + tem um menu Habilidades de especialista — carregue papéis como Depuração ou Planejamento com um clique.", + "taskBoard": "As tarefas a fazer executam um trabalho do início ao fim: o agente trabalha no próprio worktree e você revisa o diff antes de mesclar.", + "automations": "As Automações executam um prompt salvo em uma agenda — uma revisão noturna, um relatório recorrente — e cada execução pode ter seu próprio worktree.", + "tokenUsage": "Clique no número de conversas na barra de status para abrir o Uso de tokens, detalhado por dia, agente, modelo e pasta.", + "mentionTargets": "@ não traz só arquivos: mencione outro agente para delegar uma subtarefa, ou referencie uma sessão anterior, um commit ou uma habilidade.", + "splitGroups": "Clique com o botão direito em uma aba e escolha Dividir à direita ou Dividir abaixo para manter duas conversas em painéis próprios.", + "worktrees": "Abra o botão de branch e escolha Novo worktree para vários agentes trabalharem no mesmo repositório sem sobrescrever os arquivos uns dos outros.", + "importSessions": "Já rodou sessões no terminal? O menu de uma pasta tem Importar sessões locais para trazer esse histórico para o codeg.", + "subSessions": "Quando um agente delega, a subsessão aparece aninhada abaixo dele na barra lateral — expanda a linha para acompanhar o que cada uma fez.", + "liveFeedback": "Feedback ao vivo, no menu +, insere uma nota no turno que o agente já está executando, sem interrompê-lo.", + "skillPacks": "Configurações → Pacotes de habilidades reúne especialistas de código, pesquisa científica e escritório; ative por agente.", + "modelProviders": "Configurações → Provedores de Modelos aceita sua própria chave de API ou endpoint, e o modelo você escolhe no campo de entrada.", + "workspaceBackground": "Configurações → Aparência define uma imagem de fundo do espaço de trabalho, a opacidade dos painéis e as fontes do app." + }, + "quickActions": { + "excel": "Pasta do Excel", + "excelDesc": "Tabelas, fórmulas e gráficos", + "word": "Documento do Word", + "wordDesc": "Relatórios, cartas e memorandos", + "ppt": "Apresentação", + "pptDesc": "Slides com design profissional", + "pitchDeck": "Pitch Deck", + "pitchDeckDesc": "Apresentação de captação com métricas", + "morph": "Animação Morph", + "morphDesc": "Transições de slide cinematográficas", + "morph3d": "Morph 3D", + "morph3dDesc": "Modelos 3D com movimentos de câmera", + "academic": "Artigo acadêmico", + "academicDesc": "Pesquisa com citações e estrutura", + "financial": "Modelo financeiro", + "financialDesc": "Demonstrações, DCF e projeções", + "dashboard": "Painel de dados", + "dashboardDesc": "KPIs e análises a partir dos seus dados", + "prompts": { + "excel": "Crie uma pasta do Excel com os seguintes requisitos:\n\n[descreva aqui seus dados, tabelas, fórmulas e gráficos]", + "word": "Crie um documento do Word com os seguintes requisitos:\n\n[descreva aqui o conteúdo, a estrutura e a formatação do documento]", + "ppt": "Crie uma apresentação do PowerPoint com os seguintes requisitos:\n\n[descreva aqui seus slides, conteúdo e design]", + "pitchDeck": "Crie um pitch deck de captação com os seguintes requisitos:\n\n[descreva aqui sua empresa, rodada de investimento e métricas-chave]", + "morph": "Crie uma apresentação com animações de transição Morph:\n\n[descreva aqui o tema da apresentação e os efeitos visuais desejados]", + "morph3d": "Crie uma apresentação Morph 3D com modelos GLB e movimentos de câmera:\n\n[descreva aqui seu tema e conceito visual em 3D]", + "academic": "Escreva um artigo acadêmico no Word com os seguintes requisitos:\n\n[descreva aqui seu tema de pesquisa, metodologia e principais resultados]", + "financial": "Crie um modelo financeiro no Excel com os seguintes requisitos:\n\n[descreva aqui suas demonstrações financeiras, projeções e análises]", + "dashboard": "Crie um painel de dados no Excel com os seguintes requisitos:\n\n[descreva aqui sua fonte de dados, KPIs e gráficos]", + "scientific-brainstorming": "Ajude-me a fazer um brainstorming de direções de pesquisa: explore conexões interdisciplinares, questione premissas e revele lacunas promissoras. A área que estou explorando: ", + "hypothesis-generation": "Ajude-me a transformar estas observações em hipóteses testáveis, com previsões claras, mecanismos plausíveis e experimentos. Minhas observações: ", + "experimental-design": "Ajude-me a planejar um experimento rigoroso antes de coletar dados: o delineamento, a aleatorização, os controles e como evitar confundimento. O que quero estudar: ", + "statistical-power": "Ajude-me a determinar o tamanho amostral necessário: conduza uma análise de poder (tamanho de efeito, alfa, poder) para o meu delineamento. Detalhes: ", + "statistical-analysis": "Ajude-me a analisar estes dados corretamente: escolha o teste certo, verifique os pressupostos, relate os tamanhos de efeito e redija. Meus dados e pergunta: ", + "exploratory-data-analysis": "Faça uma análise exploratória do meu arquivo de dados: resuma sua estrutura, qualidade e padrões notáveis e sugira os próximos passos. O arquivo é: ", + "scientific-visualization": "Ajude-me a criar uma figura com qualidade de publicação: layout claro, barras de erro honestas, uma paleta segura para daltônicos e formatação de periódico. O que quero mostrar: ", + "scientific-critical-thinking": "Ajude-me a avaliar criticamente este estudo ou alegação: avalie a qualidade da evidência, identifique vieses e confundidores e pondere as conclusões. Aqui está: ", + "paper-lookup": "Ajude-me a encontrar artigos relevantes e texto completo de acesso aberto em bases de dados acadêmicas, com citações reutilizáveis. Estou procurando: " + }, + "paper-lookup": "Busca de artigos", + "paper-lookupDesc": "Pesquise em 10 APIs acadêmicas (PubMed, arXiv, OpenAlex, Crossref…) artigos, citações e texto completo de acesso aberto.", + "scientific-critical-thinking": "Pensamento crítico", + "scientific-critical-thinkingDesc": "Avalie alegações científicas e a qualidade da evidência: identifique vieses e confundidores e aplique GRADE.", + "scientific-visualization": "Visualização científica", + "scientific-visualizationDesc": "Figuras prontas para publicação: layouts multipainel, anotações de significância e formatação específica de periódico.", + "exploratory-data-analysis": "Análise exploratória de dados", + "exploratory-data-analysisDesc": "Exploração automatizada de arquivos de dados científicos em mais de 200 formatos com métricas de qualidade e relatórios.", + "statistical-analysis": "Análise estatística", + "statistical-analysisDesc": "Análise estatística guiada: seleção de testes, verificação de pressupostos, tamanhos de efeito e relato no estilo APA.", + "statistical-power": "Poder estatístico", + "statistical-powerDesc": "Análise de tamanho amostral e poder: quantos sujeitos são necessários, efeitos mínimos detectáveis e curvas de poder.", + "experimental-design": "Delineamento experimental", + "experimental-designDesc": "Planeje estudos rigorosos antes de coletar dados: aleatorização, blocagem, controles e delineamentos fatoriais/DOE.", + "hypothesis-generation": "Geração de hipóteses", + "hypothesis-generationDesc": "Transforme observações em hipóteses testáveis com previsões, mecanismos e experimentos para testá-las.", + "scientific-brainstorming": "Brainstorming científico", + "scientific-brainstormingDesc": "Ideação aberta de pesquisa: explore conexões interdisciplinares, questione premissas e revele lacunas.", + "tabs": { + "office": "Escritório", + "coding": "Desenvolvimento", + "research": "Pesquisa" + }, + "coding": { + "brainstormingDesc": "Explore intenção e requisitos antes de construir", + "debuggingDesc": "Encontre a causa raiz antes de propor correções", + "writingSkillsDesc": "Crie, edite e verifique skills reutilizáveis" + }, + "notEnabled": { + "title": "A habilidade “{skill}” ainda não está ativada para {agent}", + "description": "Ative-a nas Configurações para usá-la aqui.", + "action": "Ativar", + "hint": "Habilidade não ativada" + }, + "scrollPrev": "Mostrar habilidades anteriores", + "scrollNext": "Mostrar mais habilidades" + } + }, + "agentSelector": { + "noEnabledAgents": "Nenhum agente habilitado", + "openAgentsSettings": "Abrir configurações de agentes", + "notInstalled": "Não instalado", + "moreAgents": "Mais agentes ({count})" + }, + "subAgentOverlay": { + "title": "Subagentes", + "collapsedSummary": "Subagentes {count}", + "collapseAria": "Recolher subagentes" + }, + "agentPlanOverlay": { + "title": "Plano do agente", + "collapsePlanAria": "Recolher plano", + "collapsedSummary": "Plano {completed}/{total}", + "status": { + "completed": "Concluído", + "inProgress": "Em andamento", + "pending": "Pendente", + "unknown": "Desconhecido" + }, + "priority": { + "high": "Alta", + "medium": "Média", + "low": "Baixa", + "unknown": "Desconhecida" + } + }, + "permissionDialog": { + "subtitle": "O agente solicita permissão para continuar este turno.", + "queuedCount": "+{count} aguardando", + "kindFallbackTool": "ferramenta", + "command": "Comando", + "cwd": "Diretório de trabalho: {cwd}", + "filesSummary": "Arquivos: {count}", + "moreFiles": "+{count} arquivos a mais", + "plan": "Plano", + "allowedActions": "Ações permitidas", + "targetMode": "Modo de destino: {mode}", + "optionGrants": "O que cada opção concede", + "changeScopeSession": "Esta sessão", + "changeScopeProcess": "Esta execução", + "changeScopeUser": "Salvo nas configurações do usuário", + "changeScopeProject": "Salvo nas configurações do projeto", + "changeScopeProjectLocal": "Salvo nas configurações locais do projeto", + "changeScopePersistent": "Salvo permanentemente" + }, + "questionDialog": { + "title": "O agente está fazendo uma pergunta", + "placeholder": "Digite sua resposta...", + "send": "Enviar" + }, + "messageBranch": { + "previousBranchAria": "Branch anterior", + "nextBranchAria": "Próxima branch", + "pageOf": "{current} de {total}" + }, + "terminal": { + "title": "Console", + "running": "Em execução" + }, + "reasoning": { + "thinking": "Pensando…", + "thoughtForFewSeconds": "Pensamento", + "thoughtForSeconds": "Pensamento" + }, + "linkSafety": { + "errorCannotOpen": "Não é possível abrir o arquivo local", + "errorNoWorkspace": "Nenhuma pasta de espaço de trabalho está ativa no momento.", + "errorFailedOpen": "Falha ao abrir o arquivo local", + "errorFailedLink": "Falha ao abrir o link", + "errorUnsupportedLinkProtocol": "Este protocolo de link não é compatível." + }, + "fileActions": { + "openInFinder": "Abrir no Finder", + "openInExplorer": "Abrir no Explorer", + "openInFileManager": "Abrir no gerenciador de arquivos", + "copyRelativePath": "Copiar caminho relativo", + "copyAbsolutePath": "Copiar caminho absoluto", + "pathCopied": "Caminho copiado", + "copyPathFailed": "Falha ao copiar o caminho", + "openFailed": "Falha ao abrir o arquivo local" + }, + "messageList": { + "attachedResources": "Recursos anexados", + "loading": "Carregando...", + "loadEarlier": "Carregar mensagens anteriores", + "loadingEarlier": "Carregando mensagens anteriores…", + "error": "Erro: {message}", + "errorTitle": "Falha ao carregar a sessão", + "errorActionReload": "Recarregar", + "errorActionNewSession": "Nova conversa", + "emptyConversation": "Nenhuma mensagem nesta conversa.", + "systemMessage": "Mensagem do sistema", + "copyMessage": "Copiar", + "copied": "Copiado", + "downloadImage": "Baixar imagem", + "downloadFailed": "Falha no download: {message}", + "imageGeneration": "Geração de imagem", + "imageGenerationPending": "Gerando imagem…", + "imageGenerationFailed": "Falha na geração da imagem", + "model": "Modelo", + "tokenStats": "Uso de tokens", + "tokenInput": "Entrada", + "tokenOutput": "Saída", + "tokenCacheRead": "Leitura de cache", + "tokenCacheWrite": "Escrita de cache", + "duration": "Duração", + "completedAt": "Concluído às", + "jumpToPreviousUserMessage": "Ir para a mensagem do usuário", + "showMore": "Mostrar mais", + "showLess": "Mostrar menos" + }, + "liveTurnStats": { + "thinking": "Pensando...", + "streaming": "Transmitindo", + "elapsedHours": "{value} h", + "elapsedMinutes": "{value} min", + "elapsedSeconds": "{value} s", + "outputSpeedAria": "Velocidade de saída estimada", + "outputSpeedTooltip": "Velocidade de saída estimada (texto + raciocínio)" + }, + "jsonTree": { + "viewRaw": "Ver JSON bruto", + "viewTree": "Ver árvore", + "fields": "{count, plural, one {# campo} other {# campos}}", + "items": "{count, plural, one {# item} other {# itens}}" + }, + "tool": { + "parameters": "Parâmetros", + "error": "Erro", + "result": "Resultado", + "status": { + "approvalRequested": "Aguardando aprovação", + "approvalResponded": "Respondido", + "inputAvailable": "Em execução", + "inputStreaming": "Pendente", + "outputAvailable": "Concluído", + "outputDenied": "Negado", + "outputError": "Erro" + } + }, + "toolCallBlock": { + "tool": "Ferramenta", + "error": "Erro", + "result": "Resultado" + }, + "delegation": { + "subAgentRunning": "Subagente em execução…", + "noDetail": "No detail available yet.", + "unknownAgent": "Subagente", + "openDetail": "Ver conversa", + "detailTitle": "Conversa do subagente", + "detailDescription": "Visualização somente leitura da conversa do subagente delegado.", + "waitForResult": "Aguardando o resultado da tarefa {task}", + "waitForResultNoTask": "Aguardando o resultado da tarefa", + "cancelTask": "Cancelando a tarefa {task}", + "cancelTaskNoTask": "Cancelando a tarefa", + "resultPageOf": "{current} / {total}", + "prevResult": "Resultado anterior", + "nextResult": "Próximo resultado", + "noResultText": "Sem resultado nesta verificação.", + "status": { + "starting": "iniciando", + "running": "em execução", + "checked": "verificado", + "waiting": "aguardando aprovação", + "ok": "concluído", + "err": { + "default": "falhou", + "delegation_disabled": "desativado", + "depth_limit": "limite de profundidade", + "invalid_agent_type": "agente inválido", + "spawn_failed": "falha ao iniciar", + "send_failed": "falha ao enviar", + "timeout": "tempo esgotado", + "canceled": "cancelado", + "child_refusal": "subagente recusou", + "child_max_tokens": "subagente: limite de tokens", + "child_max_turn_requests": "subagente: limite de solicitações", + "child_empty": "subagente sem saída", + "child_unknown": "subagente: erro", + "unknown": "tarefa desconhecida" + } + } + }, + "contentParts": { + "showingTailOutput": "Mostrando a saída final durante o streaming para melhor desempenho.", + "result": "Resultado", + "unknown": "desconhecido", + "inputTruncated": "A entrada foi truncada — o diff pode estar incompleto.", + "replaceAll": "SUBSTITUIR TUDO", + "filesCount": "Arquivos: {count}", + "update": "atualizar", + "moreFiles": "+{count} arquivos a mais", + "timeoutMs": "Tempo limite: {timeout}ms", + "backgroundTrue": "Segundo plano: true", + "scriptToolCalls": "{count, plural, one {# chamada de ferramenta} other {# chamadas de ferramenta}}", + "offset": "Deslocamento: {offset}", + "limit": "Limite: {limit}", + "pages": "Páginas: {pages}", + "mode": "Modo: {mode}", + "cell": "Célula: {cell}", + "shellSession": "Sessão {id}", + "pathLabel": "Caminho:", + "globLabel": "Padrão glob:", + "typeLabel": "Tipo:", + "outputLabel": "Saída:", + "caseInsensitive": "Sem diferenciar maiúsculas/minúsculas", + "multiline": "Multilinha", + "promptLabel": "Instrução", + "subjectLabel": "Assunto", + "taskLabel": "Tarefa", + "nameLabel": "Nome:", + "agentPromptLabel": "Instrução", + "agentModelLabel": "Modelo", + "agentRunning": "Em execução...", + "agentLiveTranscript": "Atividade ao vivo", + "agentProgressTools": "{count} chamadas de ferramentas", + "agentProgressTurns": "{count} turnos", + "agentProgressContext": "contexto {pct}%", + "agentSessionAction": "Ver a sessão do subagente", + "agentSessionTitle": "Sessão do subagente", + "agentSessionLoading": "Carregando a transcrição do subagente…", + "agentSessionEmpty": "O subagente ainda não escreveu nada.", + "agentFallbackTitle": "Iniciando subagente…", + "agentCodexLaunchOnly": "Iniciado. O Codex não informa mais o progresso deste subagente — o resultado chega como uma mensagem nesta conversa.", + "agentStatsBash": "Comandos", + "agentStatsRead": "Arquivos lidos", + "agentStatsSearch": "Pesquisas", + "agentStatsEdit": "Edições", + "agentStatsOther": "Outros", + "goal": { + "title": "Objetivo:", + "titleWithStatus": "Objetivo {status}", + "objective": "Objetivo", + "statusLabel": "Status", + "tokensUsed": "Tokens usados", + "budget": "Orçamento", + "remaining": "Restante", + "elapsed": "Decorrido", + "tokens": "tokens", + "pause": "Pausar", + "clear": "Limpar", + "status": { + "active": "ativo", + "paused": "pausado", + "blocked": "bloqueado", + "usageLimited": "uso limitado", + "budgetLimited": "orçamento limitado", + "complete": "concluído", + "limited": "limite atingido" + } + }, + "field": { + "file": "Arquivo", + "notebook": "Caderno", + "command": "Comando", + "old": "Antigo", + "new": "Novo", + "pattern": "Padrão", + "path": "Caminho", + "query": "Consulta", + "url": "URL:", + "description": "Descrição", + "content": "Conteúdo", + "source": "Fonte", + "prompt": "Instrução", + "subject": "Assunto", + "taskId": "ID da tarefa", + "status": "Situação", + "skill": "Skill", + "args": "Argumentos", + "offset": "Deslocamento", + "limit": "Limite", + "glob": "Padrão glob", + "type": "Tipo", + "output": "Saída", + "replaceAll": "Substituir tudo", + "language": "Idioma", + "timeout": "Tempo limite", + "background": "Segundo plano", + "agentType": "Tipo de agente", + "library": "Biblioteca", + "libraryId": "ID da biblioteca" + }, + "title": { + "edit": "Editar", + "command": "Comando", + "script": "Script", + "waitCommand": "Aguardar {command}", + "waitCell": "Aguardar sessão {id}", + "terminateCommand": "Encerrar {command}", + "terminateCell": "Encerrar sessão {id}", + "stdinChars": "Entrada {chars}", + "todoWrite": "TodoWrite (atualização de tarefas)", + "read": "Ler", + "write": "Escrever", + "notebookEdit": "NotebookEdit (edição de caderno)", + "editFiles": "Editar ({count} arquivos)", + "editWithTarget": "Editar {target}", + "readWithTarget": "Ler {target}", + "writeWithTarget": "Escrever {target}", + "notebookEditWithTarget": "NotebookEdit ({target})", + "globWithPattern": "Padrão glob {pattern}", + "listFilesWithPath": "Listar arquivos {path}", + "grepWithPattern": "Padrão grep {pattern}", + "taskCreateWithSubject": "Criar tarefa: {subject}", + "taskUpdateWithStatus": "Atualizar tarefa #{id} -> {status}", + "taskUpdate": "Atualizar tarefa #{id}", + "webFetchWithUrl": "WebFetch ({url})", + "webSearchWithQuery": "Pesquisa web: {query}", + "todosProgress": "Tarefas ({done}/{total})", + "skillWithName": "Skill: {name}", + "genericWithContext": "{tool} ({context})" + }, + "search": { + "noMatches": "Nenhuma correspondência", + "matchSummary": "{matches, plural, one {# correspondência} other {# correspondências}} em {files, plural, one {# arquivo} other {# arquivos}}", + "fileSummary": "{files, plural, one {# arquivo} other {# arquivos}}", + "moreResults": "{count, plural, one {# resultado adicional não exibido} other {# resultados adicionais não exibidos}}" + }, + "toolGroup": { + "search": "{count, plural, one {Explorou # busca} other {Explorou # buscas}}", + "command": "{count, plural, one {Executou # comando} other {Executou # comandos}}", + "read": "{count, plural, one {Leu arquivos # vez} other {Leu arquivos # vezes}}", + "memory": "{count, plural, one {Recordou # memória} other {Recordou # memórias}}", + "edit": "{count, plural, one {Editou arquivos # vez} other {Editou arquivos # vezes}}", + "fetch": "{count, plural, one {Buscou # recurso} other {Buscou # recursos}}", + "think": "{count, plural, one {Pensou # vez} other {Pensou # vezes}}", + "todo": "{count, plural, one {Atualizou # tarefa} other {Atualizou # tarefas}}", + "task": "{count, plural, one {Executou # tarefa} other {Executou # tarefas}}", + "other": "{count, plural, one {Usou # ferramenta} other {Usou # ferramentas}}", + "errorSuffix": "{count, plural, one {# falhou} other {# falharam}}", + "joiner": " · " + }, + "planMode": { + "entered": "Modo de planejamento iniciado", + "planLabel": "Plano", + "reviewApproved": "Plano aprovado — implementando", + "reviewKept": "Mantido no modo de plano", + "reviewPending": "Aguardando decisão sobre o plano", + "submitted": "Plano enviado", + "switched": "Modo alterado" + }, + "backgroundTask": { + "title": "Tarefa em segundo plano", + "titleWithId": "Tarefa em segundo plano · {id}", + "running": "Em execução", + "completed": "Concluída", + "failed": "Falhou", + "stopped": "Interrompida", + "exitCode": "saída {code}", + "polledTimes": "Consultada {count} vezes", + "runningInBackground": "Segundo plano", + "launchNote": "Em execução em segundo plano · {id}" + }, + "codexScript": { + "outputMissing": "O codex truncou a saída do script e removeu o separador deste comando, então nenhuma saída pôde ser atribuída a ele.", + "sharedWith": "Também contém a saída de {commands} — o codex truncou os separadores delas.", + "truncated": "truncado" + } + }, + "messageNav": { + "title": "Navegação de mensagens", + "collapse": "Recolher navegação de mensagens", + "collapsedSummary": "Mensagens {count}", + "fileCount": "{count, plural, one {# arquivo} other {# arquivos}}", + "remove": "Remover", + "noDiffDataAvailable": "Nenhum dado de diff disponível para {filePath}" + }, + "replyArtifacts": { + "title": "Arquivos alterados", + "fileCount": "{count, plural, one {# arquivo} other {# arquivos}}", + "newFilesTitle": "Novos arquivos", + "revealInFolder": "Mostrar no gerenciador de arquivos", + "openFile": "Abrir {filePath}", + "openInEditor": "Abrir no editor", + "remove": "Remover", + "noDiffDataAvailable": "Nenhum dado de diff disponível para {filePath}" + }, + "askQuestion": { + "title": "O agente precisa da sua escolha", + "subtitle": "Responda e envie. Você pode pular a qualquer momento.", + "recommended": "Recomendado", + "other": "Outro", + "otherPlaceholder": "Digite sua resposta…", + "singleSelect": "Única", + "multiSelect": "Múltipla", + "skip": "Pular", + "next": "Próxima", + "submit": "Enviar", + "submitError": "Falha ao enviar. Tente novamente." + }, + "planApproval": { + "title": "O agente tem um plano — revise", + "emptyPlan": "O agente não escreveu um plano. Aprove para começar ou solicite alterações.", + "approve": "Aprovar e construir", + "requestChanges": "Solicitar alterações", + "abandon": "Descartar", + "feedbackPlaceholder": "O que deve mudar?", + "sendChanges": "Enviar", + "cancel": "Cancelar", + "submitError": "Não foi possível enviar. Tente novamente." + }, + "feedbackCheckResult": { + "count": "{count, plural, =1 {1 comentário} other {# comentários}}", + "expand": "Mostrar todos os comentários", + "collapse": "Recolher", + "errorTitle": "Falha ao verificar comentários" + }, + "askQuestionResult": { + "title": "Pergunta", + "answeredLabel": "Pergunta e resposta:", + "awaiting": "Aguardando sua resposta…", + "declined": "Você ignorou isto — o agente usou o próprio julgamento.", + "noSelection": "Sem seleção" + }, + "configStale": { + "agentConfigTitle": "Configurações do agente atualizadas", + "modelProviderTitle": "Provedor de modelo atualizado", + "description": "Esta sessão ainda está usando a configuração anterior. Reconecte para aplicar (o histórico da conversa é mantido).", + "reconnect": "Reconectar para aplicar", + "reconnecting": "Reconectando…", + "reconnectDisabledDuringTurn": "Disponível quando o turno atual terminar", + "dismiss": "Dispensar", + "reconnectFailed": "Falha ao reconectar a sessão", + "applied": "Nova configuração aplicada" + }, + "piProjectTrust": { + "title": "Este projeto inclui recursos do pi", + "description": "O pi não está carregando os arquivos .pi do próprio repositório. Revise-os para decidir.", + "descriptionExecutable": "O repositório inclui extensões do pi, que executam código na inicialização. O pi não as está carregando. Revise antes de decidir.", + "review": "Revisar…", + "dismiss": "Dispensar", + "dialogTitle": "Confiar nos recursos do pi deste projeto?", + "dialogDescription": "O pi só carrega os arquivos .pi do próprio repositório se você confiar na pasta. Confie apenas se confiar no conteúdo deste repositório.", + "executionWarning": "Extensões são código. Ao confiar nesta pasta, o repositório poderá executá-las na inicialização do pi com suas permissões, antes de você enviar qualquer mensagem.", + "scopeNote": "A decisão é salva no trust.json do pi para esta pasta, vale para todas as pastas dentro dela e também é usada quando você executa o pi no terminal. Você pode alterá-la em Configurações → Agentes → Pi.", + "trust": "Confiar no projeto", + "decline": "Manter sem carregar", + "disabledDuringTurn": "Disponível quando o turno atual terminar", + "trustedToast": "Projeto confiável — reconectado para que o pi carregue seus recursos", + "declinedToast": "Os recursos do projeto continuam sem ser carregados", + "saveFailed": "Falha ao salvar a decisão de confiança do projeto", + "grantTitle": "Este projeto já é confiável", + "grantDescription": "O pi carrega os arquivos .pi do próprio repositório. Revise o que isso permite.", + "grantInheritedDescription": "Uma pasta superior é confiável, então o pi carrega os arquivos .pi do próprio repositório. Revise o que isso permite.", + "grantDialogTitle": "Os recursos do pi deste projeto são confiáveis", + "grantDialogDescription": "O pi tem permissão para carregar os arquivos .pi do próprio repositório. Versões anteriores do codeg concediam isso automaticamente ao abrir uma pasta, então talvez você nunca tenha sido perguntado.", + "grantExecutionWarning": "Extensões são código. O repositório as executa na inicialização do pi com suas permissões, antes de você enviar qualquer mensagem.", + "inheritedFrom": "Confiança herdada de", + "revoke": "Revogar confiança", + "keepTrusted": "Manter confiável", + "revokedToast": "Confiança revogada — reconectado para que o pi pare de carregar os recursos do projeto", + "trustedNoReconnect": "Projeto confiável — será aplicado na próxima inicialização do pi", + "revokedNoReconnect": "Confiança revogada — será aplicada na próxima inicialização do pi" + }, + "collabAgent": { + "title": "Subagente", + "errorTitle": "Falha na tarefa do subagente", + "statesLabel": "Subagentes", + "statusRunning": "Em execução", + "statusCompleted": "Concluído", + "statusFailed": "Falhou", + "statusPending": "Iniciando", + "statusInterrupted": "Interrompido", + "statusClosed": "Encerrado", + "statusNotFound": "Não encontrado", + "opSpawn": "Iniciando subagente", + "opWait": "Obtendo resultado do subagente", + "opClose": "Encerrando subagente", + "opResume": "Retomando subagente" + }, + "contextCompaction": { + "compacting": "Compactando o contexto…", + "compacted": "Contexto compactado", + "compactedTokens": "Contexto compactado · {before} → {after} tokens", + "failed": "Falha ao compactar o contexto" + }, + "sessionFailure": { + "category": { + "connection": "Problema de conexão", + "access": "Problema de acesso", + "limit": "Limite atingido", + "request": "Solicitação rejeitada", + "service": "Problema do serviço", + "unknown": "Problema de sessão" + }, + "action": { + "retry": "Tentar novamente", + "login": "Entrar", + "newSession": "Nova sessão" + }, + "recovered": "Recuperado", + "retryUnavailable": "Nenhuma mensagem anterior para reenviar.", + "toggleDetails": "Alternar detalhes" + }, + "backgroundTasks": { + "running": "{count, plural, one {# tarefa em segundo plano em execução} other {# tarefas em segundo plano em execução}}", + "settling": "Sincronizando resultados em segundo plano…", + "settledFallback": "Tarefa em segundo plano concluída ({status})", + "cardRunning": "Executando em segundo plano", + "cardLaunchedPending": "Tarefa iniciada em segundo plano", + "cardCompleted": "Tarefa em segundo plano concluída", + "cardFinishedWithStatus": "Tarefa em segundo plano encerrada ({status})", + "cardResultPending": "Resultado ainda não retornou" + }, + "proposedPlan": { + "title": "Plano proposto", + "planning": "A planear…" + } + }, + "diffPreview": { + "mode": { + "added": "Adicionado", + "deleted": "Excluído", + "renamed": "Renomeado", + "modified": "Modificado" + }, + "hunkLabel": "Bloco {index}", + "loadingHunk": "Carregando hunk...", + "noDiffData": "Sem dados de diff", + "showRemainingLines": "Mostrar mais {count} linhas" + }, + "conversationContextBar": { + "folderTitle": "Pasta de trabalho", + "branchTitle": "Branch de trabalho", + "searchFolder": "Search folder...", + "searchBranch": "Search branch...", + "noFolders": "No folders", + "noBranches": "No branches", + "noBranch": "(no branch)", + "chatModeLabel": "Modo de chat", + "commit": "Commit", + "push": "Push", + "merge": "Merge", + "toasts": { + "folderChanged": "Switched to {name}", + "openFolderFailed": "Failed to open folder", + "switchedToChatMode": "Alternado para o modo de chat", + "openStashFailed": "Failed to open stash window", + "openMergeFailed": "Failed to open merge window" + } + }, + "cloneDialog": { + "title": "Clonar repositório", + "repositoryUrl": "URL do repositório", + "repositoryUrlPlaceholder": "https://github.com/user/repo.git", + "directory": "Diretório", + "directoryPlaceholder": "Selecione o diretório de destino...", + "browseDirectory": "Procurar diretório", + "cancel": "Cancelar", + "clone": "Clonar", + "clonePath": "Caminho de clonagem: {path}" + }, + "toasts": { + "cloneFailed": "Falha ao clonar o repositório" + } + }, + "ProjectBoot": { + "title": "Inicializador de Projeto", + "tabs": { + "shadcn": "shadcn", + "hyperframes": "HyperFrames" + }, + "hyperframes": { + "title": "Projeto de vídeo HyperFrames", + "subtitle": "Crie um projeto de HTML para vídeo. O agente do espaço de trabalho pode então escrevê-lo e renderizá-lo.", + "resolution": "Resolução", + "skillsTitle": "Skills dos agentes", + "skillsDesc": "Instala globalmente as skills do HyperFrames (link simbólico) para os agentes selecionados, para que possam criar e renderizar vídeo.", + "recheck": "Verificar novamente", + "installedBadge": "Instalado", + "skillsInstall": "Instalar / atualizar skills", + "skillsInstalling": "Instalando skills…", + "skillsInstalled": "Skills do HyperFrames instaladas", + "skillsInstallFailed": "Não foi possível instalar as skills do HyperFrames" + }, + "config": { + "base": "Base", + "style": "Estilo", + "baseColor": "Cor base", + "theme": "Tema", + "chartColor": "Cor do gráfico", + "iconLibrary": "Biblioteca de ícones", + "font": "Fonte", + "fontHeading": "Fonte do título", + "menuAccent": "Destaque do menu", + "menuColor": "Cor do menu", + "radius": "Raio", + "template": "Modelo", + "createProject": "Criar projeto", + "sectionStyle": "Estilo", + "sectionColors": "Cores", + "sectionTypography": "Tipografia", + "sectionInterface": "Interface" + }, + "preview": { + "loading": "Carregando visualização..." + }, + "createDialog": { + "title": "Criar projeto", + "projectName": "Nome do projeto", + "projectNamePlaceholder": "my-app", + "frameworkTemplate": "Modelo de framework", + "packageManager": "Gerenciador de pacotes", + "saveDirectory": "Diretório de salvamento", + "saveDirectoryPlaceholder": "Selecionar diretório...", + "browseDirectory": "Procurar", + "projectPath": "O projeto será criado em: {path}", + "advancedOptions": "Opções Avançadas", + "base": "Biblioteca Base", + "enableRtl": "Ativar Suporte RTL", + "enableRtlDescription": "Ativar suporte de layout para idiomas da direita para a esquerda (ex.: árabe, hebraico)", + "pmChecking": "Verificando...", + "pmNotInstalled": "Não instalado", + "cancel": "Cancelar", + "create": "Criar", + "creating": "Criando projeto..." + }, + "toasts": { + "createFailed": "Falha ao criar o projeto", + "createSuccess": "Projeto criado com sucesso", + "openWorkspaceFailed": "Projeto criado, mas não foi possível abri-lo no espaço de trabalho" + }, + "errors": { + "directoryExists": "O diretório de destino já existe", + "commandFailed": "O comando de criação do projeto falhou." + } + }, + "WebServiceSettings": { + "addressSwitchHint": "Alternar muda apenas o endereço mostrado e aberto aqui; o serviço escuta em todas as interfaces e continua acessível em cada endereço.", + "sectionTitle": "Serviço Web", + "sectionDescription": "Ativar para acessar o Codeg remotamente pelo navegador", + "port": "Porta", + "status": "Status", + "autoStart": "Início automático", + "autoStartHint": "Iniciar o serviço Web ao abrir o Codeg", + "running": "Em execução", + "stopped": "Parado", + "processing": "Processando...", + "start": "Iniciar", + "stop": "Parar", + "startFailed": "Falha ao iniciar", + "stopFailed": "Falha ao parar", + "saveConfigFailed": "Falha ao salvar as configurações do serviço Web", + "open": "Abrir", + "hide": "Ocultar", + "show": "Mostrar", + "copy": "Copiar", + "qrcode": "Código QR", + "qrcodeTitle": "Escanear para abrir", + "qrcodeHint": "Escaneie com seu telefone para abrir o Codeg no navegador", + "addressLabel": "Endereço de acesso", + "tokenLabel": "Token de acesso", + "tokenHint": "Insira este token ao acessar o cliente Web pela primeira vez", + "tokenPlaceholder": "Deixe em branco para gerar automaticamente", + "regenerate": "Regenerar", + "stalePortOccupiedTitle": "A porta {port} está em uso por outro processo", + "stalePortUnknownTitle": "Estado da porta {port} é incerto", + "stalePortHint": "O Codeg não consegue vincular até a porta ser liberada. Altere a porta acima ou feche o processo que a retém.", + "errors": { + "alreadyRunning": "O serviço Web já está em execução", + "invalidAddress": "Formato de host ou porta inválido", + "portInUse": "A porta {port} já está em uso. Feche o processo que a utiliza ou escolha outra porta.", + "permissionDenied": "Permissão negada. Use uma porta acima de 1024 ou execute com privilégios mais altos.", + "addressUnavailable": "O endereço não está disponível nesta máquina", + "bindFailed": "Falha ao vincular o endereço" + } + }, + "DirectoryBrowser": { + "title": "Explorar diretório", + "pathPlaceholder": "Digite o caminho do diretório...", + "goHome": "Ir para o diretório inicial", + "navigateUp": "Ir para o diretório superior", + "select": "Selecionar", + "cancel": "Cancelar", + "loading": "Carregando...", + "emptyDirectory": "Este diretório está vazio", + "errorLoadingDir": "Falha ao carregar o diretório", + "permissionDenied": "Permissão negada" + }, + "ChatChannelSettings": { + "loading": "Carregando...", + "sectionTitle": "Canais de chat", + "sectionDescription": "Configure bots de IM para receber notificações de eventos e consultar atividade de codificação.", + "addChannel": "Adicionar canal", + "noChannels": "Nenhum canal de chat configurado ainda.", + "channelName": "Nome", + "channelNamePlaceholder": "Meu bot do Telegram", + "channelType": "Tipo de canal", + "lark": "Lark (Feishu)", + "weixin": "WeChat", + "dailyReport": "Relatório diário", + "dailyReportTime": "Horário do relatório", + "nameRequired": "O nome do canal é obrigatório.", + "tokenRequired": "O token é obrigatório.", + "chatIdRequired": "O Chat ID é obrigatório.", + "topicMode": "Modo de grupo por tópicos", + "topicModeHint": "Roteia tópicos de fórum do Telegram como sessões Codeg separadas. O bot deve estar em um supergrupo de fórum e poder gerenciar tópicos.", + "loadFailed": "Falha ao carregar os canais.", + "saveFailed": "Falha ao salvar as alterações.", + "connectSuccess": "Canal conectado.", + "connectFailed": "Falha na conexão", + "disconnectSuccess": "Canal desconectado.", + "disconnectFailed": "Falha ao desconectar.", + "testSuccess": "Teste de conexão aprovado.", + "testFailed": "Teste de conexão falhou", + "deleteSuccess": "Canal excluído.", + "deleteFailed": "Falha ao excluir o canal.", + "deleteConfirmTitle": "Excluir canal", + "deleteConfirmMessage": "O canal e seus registros de mensagens serão excluídos permanentemente. Tem certeza?", + "cancel": "Cancelar", + "delete": "Excluir", + "create": "Criar", + "save": "Salvar", + "channelListTitle": "Canais configurados", + "channelListDescription": "Os canais habilitados serão conectados automaticamente ao iniciar o serviço.", + "editChannel": "Editar canal", + "editSuccess": "Canal atualizado.", + "tokenPlaceholderKeep": "Deixar em branco para manter atual", + "weixinScanTitle": "Escanear código QR", + "weixinScanDescription": "Abra o WeChat e escaneie o código QR para conectar.", + "weixinQrcodeExpired": "Código QR expirado.", + "weixinRefreshQrcode": "Atualizar", + "weixinWaitingScan": "Aguardando escaneamento...", + "weixinPollError": "Conexão instável, tentando novamente...", + "weixinReconnectNotice": "Devido a limitações do protocolo iLink, após cada reconexão você precisa enviar uma mensagem ao bot para que os disparadores de eventos tenham efeito.", + "connect": "Conectar", + "disconnect": "Desconectar", + "test": "Testar conexão", + "tabs": { + "channels": "Canais", + "commands": "Comandos", + "events": "Eventos", + "other": "Outros" + }, + "commands": { + "title": "Comandos integrados", + "description": "Comandos de bot disponíveis nos canais de chat. Em chats em grupo, @Bot é necessário para processar mensagens.", + "prefixLabel": "Prefixo de comando", + "prefixDescription": "1-3 caracteres não alfanuméricos para acionar comandos do bot (padrão /).", + "prefixSaved": "Prefixo de comando salvo.", + "prefixSaveFailed": "Falha ao salvar o prefixo.", + "prefixInvalid": "O prefixo deve ser de 1-3 caracteres não alfanuméricos.", + "save": "Salvar", + "folderDesc": "Selecionar pasta de trabalho", + "agentDesc": "Selecionar agente de IA", + "taskDesc": "Criar sessão e executar tarefa", + "sessionsDesc": "Listar sessões ativas na pasta", + "resumeDesc": "Conversas recentes / retomar uma sessão", + "cancelDesc": "Cancelar tarefa atual", + "approveDesc": "Aprovar solicitação de permissão do agente", + "denyDesc": "Negar solicitação de permissão do agente", + "searchDesc": "Pesquisar conversas por palavra-chave", + "todayDesc": "Resumo da atividade de hoje", + "statusDesc": "Status da conexão do canal", + "helpDesc": "Mostrar ajuda" + }, + "events": { + "title": "Notificações de eventos", + "description": "Ao habilitar eventos, eles serão enviados ao canal quando acionados.", + "turnComplete": "Turno concluído", + "turnCompleteDesc": "Quando um turno do agente termina", + "error": "Erro do agente", + "errorDesc": "Quando um agente encontra um erro", + "permissionRequest": "Solicitação de permissão", + "permissionRequestDesc": "Quando um agente solicita permissão para agir", + "questionRequest": "Pergunta do agente", + "questionRequestDesc": "Quando um agente faz uma pergunta", + "userPromptSent": "Mensagem do usuário", + "userPromptSentDesc": "Quando você envia uma mensagem (o texto da mensagem é incluído na notificação)", + "saved": "Filtro de eventos atualizado.", + "saveFailed": "Falha ao salvar o filtro de eventos.", + "loadFailed": "Falha ao carregar as configurações.", + "retry": "Tentar novamente", + "webhooksTitle": "Webhooks", + "webhooksDescription": "Envia uma carga JSON via POST para uma ou mais URLs quando um evento ativado ocorre. O filtro de eventos acima também se aplica aos webhooks.", + "webhookUrlPlaceholder": "https://example.com/webhook", + "addWebhook": "Adicionar webhook", + "removeWebhook": "Remover webhook", + "webhookSave": "Salvar", + "webhooksSaved": "Webhooks salvos.", + "webhooksSaveFailed": "Falha ao salvar os webhooks.", + "webhookInvalidUrl": "Insira URLs http(s) válidas.", + "docsTitle": "Formato da requisição", + "docsMethod": "Método", + "docsContentType": "Content-Type", + "docsNote": "Cada evento ativado é entregue a todas as URLs. Os webhooks não têm debounce; o filtro de eventos acima continua valendo.", + "editWebhook": "Editar webhook", + "enableWebhook": "Ativar webhook", + "webhookDuplicate": "Esta URL já está configurada.", + "cancel": "Cancelar", + "webhooksEmpty": "Nenhum webhook configurado ainda.", + "deleteWebhookTitle": "Excluir webhook", + "deleteWebhookMessage": "Remover este webhook? Os eventos não serão mais entregues a esta URL.", + "delete": "Excluir" + }, + "language": { + "title": "Idioma das mensagens", + "description": "Idioma utilizado para notificações de eventos, respostas de comandos e relatórios diários enviados aos canais de chat.", + "saved": "Idioma das mensagens salvo.", + "saveFailed": "Falha ao salvar o idioma das mensagens.", + "en": "Inglês", + "zh-cn": "Chinês simplificado", + "zh-tw": "Chinês tradicional", + "ja": "Japonês", + "ko": "Coreano", + "es": "Espanhol", + "de": "Alemão", + "fr": "Francês", + "pt": "Português", + "ar": "Árabe" + } + }, + "ModelProviderSettings": { + "sectionTitle": "Provedores de Modelos", + "sectionDescription": "Gerenciar credenciais de provedores de API para agentes.", + "filterAll": "Todos", + "providerListTitle": "Provedores Configurados", + "addProvider": "Adicionar Provedor", + "editProvider": "Editar Provedor", + "noProviders": "Nenhum provedor de modelo configurado.", + "providerName": "Nome", + "providerNamePlaceholder": "Ex. OpenAI, Anthropic", + "apiUrl": "URL da API", + "apiUrlPlaceholder": "https://api.openai.com/v1", + "apiKey": "Chave da API", + "apiKeyPlaceholder": "sk-...", + "apiKeyKeepCurrent": "Deixe em branco para manter atual", + "agentTypes": "Tipos de Agente", + "agentTypesRequired": "Pelo menos um tipo de agente é necessário.", + "agentType": "Tipo de Agente", + "agentTypeRequired": "O tipo de agente é obrigatório.", + "agentTypeImmutableHint": "O tipo de agente não pode ser alterado após a criação.", + "model": "Modelo", + "modelPlaceholderCodex": "gpt-5.6-sol / gpt-5.5", + "modelPlaceholderGemini": "gemini-3-pro-preview", + "claudeMainModel": "Modelo Principal", + "claudeReasoningModel": "Modelo de Raciocínio (pensamento)", + "claudeHaikuDefaultModel": "Modelo Haiku Padrão", + "claudeSonnetDefaultModel": "Modelo Sonnet Padrão", + "claudeOpusDefaultModel": "Modelo Opus Padrão", + "claudeCustomModelOption": "ID do modelo personalizado", + "claudeCustomModelOptionName": "Nome do modelo personalizado", + "claudeCustomModelOptionDescription": "Descrição do modelo personalizado", + "claudeCustomModelOptionHint": "Adiciona uma única entrada personalizada ao seletor de modelos do Claude (por exemplo, um modelo atrás de um gateway/proxy personalizado). Nome e descrição são informações de exibição opcionais.", + "nameRequired": "O nome do provedor é obrigatório.", + "apiUrlRequired": "A URL da API é obrigatória.", + "apiKeyRequired": "A chave da API é obrigatória.", + "loadFailed": "Falha ao carregar provedores.", + "saveFailed": "Falha ao salvar alterações.", + "createSuccess": "Provedor criado.", + "editSuccess": "Provedor atualizado.", + "deleteSuccess": "Provedor excluído.", + "deleteConfirmTitle": "Excluir Provedor", + "deleteConfirmMessage": "O provedor \"{name}\" será excluído permanentemente. Tem certeza?", + "deleteBlockedByAgent": "{agents} está usando este provedor. Desvincule-o antes de excluir.", + "cancel": "Cancelar", + "delete": "Excluir", + "create": "Criar", + "save": "Salvar", + "affectedRunningSessions": "{count, plural, one {# sessão ativa precisa reconectar para aplicar a alteração} other {# sessões ativas precisam reconectar para aplicar a alteração}}" + }, + "SkillMatrix": { + "loading": "Carregando…", + "searchPlaceholder": "Pesquisar por nome, id ou descrição", + "empty": "Nada para mostrar.", + "emptySearch": "Nenhuma correspondência para a pesquisa atual.", + "skillColumn": "Habilidade", + "selectAll": "Selecionar tudo visível", + "selectSkill": "Selecionar {name}", + "everything": { + "label": "Em massa", + "enable": "Ativar tudo (visível)", + "disable": "Desativar tudo (visível)" + }, + "columnMenu": { + "enableAll": "Ativar todas as habilidades", + "disableAll": "Desativar todas as habilidades" + }, + "rowMenu": { + "label": "Ações em massa para {name}", + "enableAll": "Ativar para todos os agentes", + "disableAll": "Desativar para todos os agentes" + }, + "bulk": { + "selected": "{count} selecionados", + "targetAll": "Todos os agentes", + "targetSome": "{count} agentes", + "enable": "Ativar", + "disable": "Desativar", + "clear": "Limpar" + }, + "confirm": { + "disableTitle": "Desativar estes links?", + "disableBody": "Isto remove {count} links de habilidades gerenciados pelo codeg. Habilidades que ocupam um diretório personalizado não são afetadas. Você pode reativá-las a qualquer momento.", + "cancel": "Cancelar", + "confirm": "Desativar" + }, + "toasts": { + "loadFailed": "Falha ao carregar os status das habilidades", + "applyFailed": "Falha ao aplicar as alterações", + "enabled": "{count} links ativados", + "disabled": "{count} links desativados", + "enabledPartial": "{ok} ativados, {failed} falharam", + "disabledPartial": "{ok} desativados, {failed} falharam" + }, + "detail": { + "enableForAgents": "Ativar para agentes", + "preview": "Visualização do SKILL.md", + "loadingContent": "Carregando conteúdo…" + }, + "copyModeHint": "Copiado (não vinculado) — reative após atualizações para obter a versão mais recente" + }, + "ExpertsSettings": { + "title": "Habilidades de Especialista", + "description": "Ative fluxos de trabalho de habilidades selecionados e comprovados em campo para seus agentes de codificação de IA. Cada especialista é uma habilidade independente do projeto superpowers — o codeg gerencia a cópia central e a vincula aos agentes escolhidos.", + "loading": "Carregando especialistas…", + "loadingContent": "Carregando conteúdo…", + "emptyExperts": "Nenhum especialista disponível. Verifique os logs da aplicação.", + "emptySelection": "Selecione um especialista para ver seu conteúdo e gerenciar a ativação.", + "emptySearch": "Nenhum especialista corresponde à pesquisa atual.", + "searchPlaceholder": "Pesquisar especialistas por nome, ID ou descrição", + "enableForAgents": "Ativar para agentes", + "noAgents": "Nenhum agente ACP detectado.", + "copyModeWarning": "Copiado (não vinculado). Reative após as atualizações do codeg para obter a versão mais recente.", + "previewTitle": "Prévia do SKILL.md", + "categories": { + "discovery": "Descoberta e Design", + "planning": "Planejamento", + "execution": "Execução", + "quality": "Qualidade e Testes", + "debugging": "Depuração", + "review": "Revisão e Integração", + "meta": "Meta" + }, + "states": { + "not_linked": "Não ativado", + "linked_to_codeg": "Ativado", + "linked_elsewhere": "Bloqueado — outro vínculo existe", + "blocked_by_real_directory": "Bloqueado — uma habilidade personalizada ocupa este nome", + "broken": "Vínculo quebrado" + }, + "badges": { + "userModified": "Modificado pelo usuário" + }, + "actions": { + "openCentralDir": "Abrir pasta central", + "refresh": "Atualizar" + }, + "toasts": { + "loadFailed": "Falha ao carregar detalhes do especialista", + "enabled": "Especialista ativado para este agente", + "disabled": "Especialista desativado para este agente", + "enableFailed": "Falha ao ativar o especialista", + "disableFailed": "Falha ao desativar o especialista", + "openFolderFailed": "Falha ao abrir a pasta" + } + }, + "ScienceSettings": { + "title": "Habilidades de pesquisa científica", + "description": "Ative habilidades de pesquisa científica selecionadas para seus agentes de código com IA: geração de hipóteses, delineamento experimental, estatística, visualização, avaliação crítica e busca de literatura. O codeg gerencia uma cópia central e vincula cada habilidade aos agentes que você escolher.", + "loading": "Carregando habilidades científicas…", + "emptySkills": "Nenhuma habilidade científica disponível. Verifique os registros do aplicativo.", + "searchPlaceholder": "Pesquisar habilidades científicas por nome, id ou descrição", + "categories": { + "ideation": "Ideação", + "design": "Delineamento", + "analysis": "Análise", + "visualization": "Visualização", + "evaluation": "Avaliação", + "literature": "Literatura" + }, + "states": { + "not_linked": "Não ativado", + "linked_to_codeg": "Ativado", + "linked_elsewhere": "Bloqueado — outro vínculo existe", + "blocked_by_real_directory": "Bloqueado — uma habilidade personalizada ocupa este nome", + "broken": "Vínculo quebrado" + }, + "badges": { + "userModified": "Modificado pelo usuário", + "needsKey": "Requer chave", + "needsSetup": "Pode exigir configuração" + }, + "actions": { + "openCentralDir": "Abrir pasta central", + "refresh": "Atualizar" + }, + "toasts": { + "openFolderFailed": "Falha ao abrir a pasta" + } + }, + "OfficeToolsSettings": { + "title": "Ferramentas Office", + "description": "Gerencie as habilidades do OfficeCLI para criar arquivos Excel, Word e PowerPoint. Instale o OfficeCLI, sincronize as habilidades e ative-as por agente.", + "loadingContent": "Carregando conteúdo…", + "emptySkills": "Nenhuma habilidade disponível. Instale o OfficeCLI e sincronize as habilidades.", + "emptySelection": "Selecione uma habilidade para ver seu conteúdo e gerenciar a ativação.", + "emptySearch": "Nenhuma habilidade encontrada.", + "searchPlaceholder": "Pesquisar habilidades por nome, ID ou descrição", + "enableForAgents": "Ativar para agentes", + "noAgents": "Nenhum agente ACP detectado.", + "installFirst": "Instale o OfficeCLI primeiro para ativar as habilidades.", + "syncFirst": "Sincronize as habilidades primeiro para carregar o conteúdo.", + "noContent": "Nenhum conteúdo disponível.", + "copyModeWarning": "Copiado (não vinculado). Sincronize novamente para obter a versão mais recente.", + "previewTitle": "Pré-visualização SKILL.md", + "detection": { + "installed": "Instalado", + "notInstalled": "Não instalado", + "notRunnable": "Instalado, mas não executável", + "installHint": "Instale o OfficeCLI para habilitar as habilidades de geração de documentos Office para seus agentes de IA.", + "install": "Instalar", + "uninstall": "Desinstalar", + "syncSkills": "Sincronizar habilidades" + }, + "categories": { + "general": "Geral", + "presentations": "Apresentações", + "documents": "Documentos", + "spreadsheets": "Planilhas" + }, + "states": { + "not_linked": "Não ativado", + "linked_to_codeg": "Ativado", + "linked_elsewhere": "Bloqueado — existe outro link", + "blocked_by_real_directory": "Bloqueado — uma habilidade personalizada ocupa este nome", + "broken": "Link quebrado" + }, + "badges": { + "notSynced": "Não sincronizado" + }, + "actions": { + "refresh": "Atualizar" + }, + "toasts": { + "loadFailed": "Falha ao carregar detalhes da habilidade", + "enabled": "Habilidade ativada para este agente", + "disabled": "Habilidade desativada para este agente", + "enableFailed": "Falha ao ativar habilidade", + "disableFailed": "Falha ao desativar habilidade", + "installSuccess": "OfficeCLI instalado com sucesso", + "installFailed": "Falha ao instalar o OfficeCLI", + "uninstallSuccess": "OfficeCLI desinstalado", + "uninstallFailed": "Falha ao desinstalar o OfficeCLI", + "syncSuccess": "{synced} habilidades sincronizadas", + "syncPartial": "{synced} sincronizadas, {errors} falharam", + "syncFailed": "Falha ao sincronizar habilidades" + }, + "autoPreviewLabel": "Abrir visualização automaticamente", + "autoPreviewHint": "Quando um agente cria ou edita um arquivo do Word, Excel ou PowerPoint, abre sua visualização ao vivo automaticamente." + }, + "SkillPacksSettings": { + "title": "Pacotes de habilidades", + "description": "Pacotes de habilidades selecionados que o codeg gerencia de forma centralizada e vincula aos seus agentes de IA — especialistas em programação, pesquisa científica e ferramentas de documentos de escritório. Ative-os por agente abaixo.", + "tabs": { + "experts": "Especialistas", + "science": "Ciência", + "office": "Ferramentas de escritório", + "custom": "Personalizadas" + }, + "actions": { + "openCentralDir": "Abrir pasta central", + "refresh": "Atualizar" + }, + "toasts": { + "openFolderFailed": "Falha ao abrir a pasta" + } + }, + "QuickMessagesSettings": { + "title": "Mensagens rápidas", + "description": "Gerencie trechos de mensagens reutilizáveis. Arraste para reordenar.", + "loading": "Carregando mensagens rápidas…", + "emptyList": "Ainda não há mensagens rápidas. Clique em \"Nova\" para criar uma.", + "emptySelection": "Selecione uma mensagem rápida para editar.", + "searchPlaceholder": "Pesquisar por título ou conteúdo", + "untitled": "Sem título", + "actions": { + "new": "Nova", + "save": "Salvar", + "delete": "Excluir", + "dragSort": "Arraste para reordenar", + "dragSortMessage": "Arrastar para reordenar mensagem rápida: {name}" + }, + "fields": { + "title": "Título", + "titlePlaceholder": "Dê um título curto a esta mensagem", + "content": "Conteúdo", + "contentPlaceholder": "Digite aqui o conteúdo da mensagem" + }, + "confirmDelete": { + "title": "Excluir mensagem rápida?", + "message": "Isso excluirá permanentemente \"{name}\". Tem certeza?", + "cancel": "Cancelar", + "confirm": "Excluir" + }, + "toasts": { + "loadFailed": "Falha ao carregar mensagens rápidas", + "createFailed": "Falha ao criar mensagem rápida", + "saveFailed": "Falha ao salvar mensagem rápida", + "deleteFailed": "Falha ao excluir mensagem rápida", + "saveOrderFailed": "Falha ao salvar a ordem", + "created": "Mensagem rápida criada", + "saved": "Mensagem rápida salva", + "deleted": "Mensagem rápida excluída" + } + }, + "Pet": { + "badge": { + "running": "{count} em execução", + "waiting": "{count} aguardando aprovação", + "error": "{count} com erro" + }, + "panel": { + "title": "Sessões ativas", + "empty": "Nenhuma sessão ativa", + "emptyHint": "Agentes em execução e os que precisam de você aparecem aqui.", + "statusRunning": "Em execução", + "statusWaiting": "Aguardando", + "statusError": "Erro", + "subAgentOf": "Subagente de" + }, + "menu": { + "scale": "Escala", + "openManager": "Gerenciar pets", + "close": "Fechar" + }, + "loadError": "Falha ao carregar pet", + "missingPetIdParam": "Nenhum pet selecionado", + "summonButton": "Pet", + "manager": { + "title": "Pets", + "description": "Companheiros flutuantes de desktop com sprites compatíveis com o Codex.", + "addPet": "Adicionar pet", + "importFromCodex": "Importar do Codex", + "noPets": "Sem pets. Adicione um ou importe do Codex.", + "setActive": "Ativar", + "active": "Ativo", + "edit": "Editar", + "delete": "Excluir", + "deleteConfirm": "Excluir o pet \"{name}\"? Será removido do disco.", + "summon": "Invocar janela do pet", + "openCodexHelp": "Pets do Codex precisam estar em ~/.codex/pets/. Nenhum encontrado.", + "specRequirement": "O sprite precisa ter 1536px de largura e altura múltipla de 208px (ex.: 1872 ou 2288), em PNG ou WebP com transparência.", + "form": { + "id": "ID do pet", + "idHelp": "Minúsculas, dígitos, '-' e '_'. Máx 64 caracteres.", + "displayName": "Nome", + "description": "Descrição (opcional)", + "spritesheet": "Sprite", + "chooseFile": "Escolher arquivo", + "replaceFile": "Substituir sprite", + "saveCreate": "Adicionar pet", + "saveUpdate": "Salvar alterações", + "cancel": "Cancelar" + }, + "errors": { + "missingId": "ID obrigatório", + "missingName": "Nome obrigatório", + "missingSpritesheet": "Sprite obrigatório", + "addFailed": "Falha ao adicionar", + "updateFailed": "Falha ao atualizar", + "deleteFailed": "Falha ao excluir", + "loadFailed": "Falha ao carregar pets", + "setActiveFailed": "Falha ao ativar pet", + "summonFailed": "Falha ao abrir a janela do pet" + } + }, + "import": { + "title": "Importar do Codex", + "subtitle": "Pets disponíveis em ~/.codex/pets/.", + "selectAll": "Selecionar todos", + "alreadyImported": "Já importado", + "renameOnConflict": "Renomear conflitos com sufixo -imported", + "import": "Importar selecionados", + "noneFound": "Nenhum pet do Codex disponível.", + "imported": "Importação concluída", + "failed": "Falha no import", + "close": "Fechar" + }, + "marketplace": { + "openMarketplace": "Mercado de pets", + "title": "Mercado de pets", + "search": "Buscar pets", + "kindFilter": { + "all": "Todos", + "object": "Objeto", + "animal": "Animal", + "person": "Pessoa", + "creature": "Criatura" + }, + "sortFilter": { + "latest": "Recentes", + "popular": "Populares", + "views": "Mais vistos" + }, + "refresh": "Atualizar", + "install": "Instalar", + "installing": "Instalando", + "reinstall": "Reinstalar", + "reinstallConfirm": "Sobrescrever o pet local \"{name}\"? Os dados existentes serão substituídos.", + "cancel": "Cancelar", + "stats": { + "views": "Visualizações", + "downloads": "Downloads", + "likes": "Curtidas" + }, + "actions": { + "idle": "Parado", + "running_right": "Corre dir.", + "running_left": "Corre esq.", + "waving": "Acena", + "jumping": "Pula", + "failed": "Falha", + "waiting": "Espera", + "running": "Corre", + "review": "Revisão" + }, + "page": "Página {page} de {total}", + "prev": "Anterior", + "next": "Próxima", + "empty": "Nenhum pet corresponde.", + "successInstalled": "\"{name}\" instalado", + "errors": { + "loadFailed": "Falha ao carregar o mercado", + "installFailed": "Falha ao instalar o pet", + "alreadyInstalled": "O pet já existe localmente" + } + } + }, + "RemoteWorkspace": { + "openRemoteWorkspace": "Open remote workspace", + "manage": "Manage remote workspace", + "manageTitle": "Remote Workspace connections", + "empty": "No remote connections", + "searchPlaceholder": "Search remote workspaces", + "orderFailed": "Failed to save remote workspace order", + "dragSort": "Drag to sort", + "dragSortConnection": "Drag to sort {name}", + "newConnection": "New connection", + "loading": "Loading", + "loadingConnection": "Loading remote connection", + "name": "Name", + "baseUrl": "Service URL", + "token": "Access token", + "save": "Save", + "delete": "Delete", + "confirmDelete": { + "title": "Delete remote connection?", + "message": "This will remove \"{name}\" from this device. This action cannot be undone.", + "cancel": "Cancel", + "confirm": "Delete" + }, + "saved": "Remote connection saved.", + "deleted": "Remote connection deleted.", + "loadFailed": "Failed to load remote connections", + "saveFailed": "Failed to save remote connection", + "deleteFailed": "Failed to delete remote connection", + "openFailed": "Failed to open remote workspace", + "connectionLoadFailed": "Failed to load remote connection: {message}", + "connectionExpired": "Remote connection \"{name}\" is expired. Update its token and reload this window." + }, + "ServerFileBrowser": { + "title": "Selecionar arquivo do servidor", + "pathPlaceholder": "Inserir caminho do diretório...", + "goHome": "Ir para o diretório inicial", + "navigateUp": "Ir para o diretório acima", + "select": "Selecionar", + "cancel": "Cancelar", + "loading": "Carregando...", + "emptyDirectory": "Este diretório está vazio", + "errorLoadingDir": "Falha ao carregar o diretório", + "selectedCount": "{count} selecionado(s)" + }, + "BackupSettings": { + "title": "Backup e restauração", + "description": "Exporte um backup portátil dos seus dados do codeg ou restaure a partir de um.", + "tabs": { + "backup": "Backup", + "restore": "Restauração" + }, + "export": { + "includeExternal": "Incluir o conteúdo das conversas", + "includeExternalHint": "Também arquiva as transcrições das CLIs (Claude, Codex, Gemini, …). Aumenta o tamanho.", + "passphrase": "Senha (opcional)", + "passphrasePlaceholder": "Deixe em branco para um arquivo sem criptografia", + "passphraseConfirm": "Confirmar a senha", + "passphraseMismatch": "As senhas não coincidem.", + "noPassphraseWarning": "Este backup conterá segredos (chaves de API, tokens) em texto puro. Guarde-o em local seguro.", + "passphraseLossWarning": "Criptografado com esta senha. Se você perdê-la, o backup não poderá ser recuperado.", + "button": "Exportar backup", + "inProgress": "Criando backup…", + "success": "Backup criado.", + "started": "Download do backup iniciado." + }, + "restore": { + "selectFile": "Selecionar arquivo de backup", + "passphrasePrompt": "Este backup está criptografado. Digite a senha dele.", + "unlock": "Desbloquear", + "preview": { + "title": "Detalhes do backup", + "encrypted": "Criptografado", + "compatible": "Compatível", + "incompatible": "Incompatível", + "createdAt": "Criado: {value}", + "appVersion": "Versão do app: {value}", + "incompatibleHint": "Este backup foi criado por uma versão mais recente do codeg e não pode ser restaurado." + }, + "replaceWarning": "Restaurar substitui todos os dados atuais do codeg (banco de dados e uploads). Seus dados atuais são salvos em um snapshot primeiro, para que possam ser recuperados.", + "keyringNote": "Os tokens de GitHub/chat do desktop ficam no chaveiro do sistema e não são incluídos; insira-os novamente após restaurar.", + "button": "Restaurar", + "staging": "Preparando a restauração…", + "staged": "Restauração preparada. Reiniciando…", + "restarting": "Restauração preparada. Reiniciando o servidor…", + "restartTimeout": "O servidor não voltou a tempo. Recarregue a página quando ele estiver ativo.", + "externalSideLocation": "As transcrições de conversas foram restauradas em {path}", + "confirmTitle": "Substituir todos os dados?", + "confirmBody": "Isto substituirá seu banco de dados e uploads atuais do codeg pelo backup e, em seguida, reiniciará. Seus dados atuais são salvos em um snapshot primeiro.", + "cancel": "Cancelar", + "confirmAction": "Substituir e reiniciar", + "external": { + "title": "Conteúdo das conversas", + "hint": "Este backup inclui transcrições das CLIs. Escolha para onde restaurá-las.", + "modeSkip": "Não restaurar", + "modeSide": "Restaurar em uma pasta separada segura", + "modeOriginal": "Restaurar nos locais originais das CLIs", + "forceOverwrite": "Sobrescrever arquivos existentes", + "forceOverwriteHint": "Substitui os arquivos que já existem nas pastas das CLIs.", + "scanning": "Verificando conflitos…", + "noConflicts": "Nenhum arquivo existente será sobrescrito.", + "conflictCount": "{count} arquivo(s) existente(s) seriam afetados.", + "conflictSkipNote": "Os arquivos existentes são mantidos (ignorados) a menos que você ative a sobrescrita." + }, + "restartFailed": "Restauração preparada, mas o servidor não conseguiu reiniciar. Reinicie-o manualmente para aplicá-la." + }, + "remoteUnsupported": "O backup e a restauração atuam sobre os dados da máquina que executa o codeg. Você está conectado a um espaço de trabalho remoto — gerencie os backups dele diretamente nesse servidor." + }, + "backup": { + "restore": { + "error": { + "badPassphrase": "Senha incorreta ou backup corrompido.", + "corrupted": "O arquivo de backup está corrompido.", + "unknownFormat": "Este arquivo não é um backup do codeg reconhecido.", + "newerVersion": "Este backup foi criado pelo codeg {backupVersion}, mais recente que esta versão ({appVersion}).", + "alreadyPending": "Já existe uma restauração preparada. Reinicie para aplicá-la antes de preparar outra." + } + }, + "error": { + "diskSpace": "Espaço em disco insuficiente para concluir a operação.", + "cancelled": "A operação foi cancelada." + } + }, + "WebConnection": { + "disconnectedTitle": "Conexão perdida", + "reconnectingDescription": "Tentando reconectar ao servidor. Normalmente isso se resolve sozinho em alguns segundos.", + "reconnectNow": "Reconectar agora", + "sessionExpiredTitle": "Sessão expirada", + "sessionExpiredDescription": "Sua sessão não é mais válida. Faça login novamente para continuar.", + "goToLogin": "Ir para o login" + }, + "LiveFeedback": { + "placeholder": "Envie uma nota para {agent} enquanto ele trabalha…", + "agentFallback": "o agente", + "ariaLabel": "Nota de feedback ao vivo", + "dialogTitle": "Feedback ao vivo", + "dialogDescription": "Envie uma nota ao agente enquanto ele trabalha. Ele a lerá na próxima verificação, sem interromper a etapa atual.", + "dialogDescriptionInstant": "Envie uma nota ao agente enquanto ele trabalha. Ela é inserida imediatamente no turno atual — o agente a vê na hora.", + "channelDowngraded": "A inserção instantânea não está disponível nesta sessão — sua nota foi salva para o agente ler na próxima verificação.", + "send": "Enviar", + "cancel": "Cancelar", + "pending": "aguardando", + "delivered": "recebida", + "turnEndedUnread": "O agente terminou antes de ler o seu feedback.", + "sendAsMessage": "Enviar como mensagem", + "dismiss": "Dispensar", + "turnEndedResent": "O turno terminou — enviado como nova mensagem.", + "turnEnded": "O turno já terminou.", + "submitFailed": "Não foi possível enviar a sua nota" + }, + "AgentToolsSettings": { + "title": "Ferramentas na conversa", + "description": "Ferramentas extras que o codeg dá a um agente dentro de uma conversa. Elas são injetadas quando o agente inicia, então a mudança vale para os agentes iniciados depois.", + "feedbackLabel": "Feedback ao vivo", + "feedbackHint": "Envie notas e correções a um agente enquanto ele trabalha. Se o agente oferecer inserção instantânea, sua nota entra imediatamente no turno em andamento; caso contrário, o agente recebe uma ferramenta para verificar seu feedback — esses agentes normalmente só verificam quando você menciona isso no prompt, por exemplo, adicione \"verifique meu feedback ao vivo regularmente\" à sua mensagem.", + "questionLabel": "Perguntar ao usuário", + "questionHint": "Permite que os agentes pausem e façam uma pergunta de múltipla escolha que aparece acima da caixa de entrada da conversa. O agente aguarda até você responder (ou pular).", + "sessionInfoLabel": "Obter informações da sessão", + "sessionInfoHint": "Permite que os agentes consultem uma sessão mencionada na sua mensagem (um selo de sessão) para ler o título, agente, status, espaço de trabalho, uso de tokens e mensagens recentes.", + "automationsLabel": "Criar automações", + "automationsHint": "Salva a conversa como uma automação que roda em um agendamento. Desativado por padrão — depois ela inicia agentes por conta própria.", + "workTasksLabel": "Criar tarefas a fazer", + "workTasksHint": "Coloca um cartão no quadro de tarefas a partir da conversa. Desativado por padrão — grava o estado do app.", + "save": "Salvar", + "saving": "Salvando…", + "saved": "Configurações de ferramentas salvas", + "saveFailed": "Falha ao salvar as configurações de ferramentas", + "loadFailed": "Falha ao carregar: {detail}" + }, + "NotificationSoundSettings": { + "title": "Sons de notificação", + "description": "Reproduz um som curto quando ocorre um evento do agente. São os mesmos eventos enviados aos canais de chat; esta configuração vale apenas para este dispositivo.", + "enableHint": "Desativado por padrão. Os sons tocam apenas na janela do espaço de trabalho deste navegador ou aplicativo.", + "volume": "Volume", + "preview": "Ouvir", + "previewEvent": "Ouvir o som de {event}", + "onlyWhenUnfocused": "Somente quando a janela não estiver em foco", + "onlyWhenUnfocusedHint": "Fica em silêncio enquanto você está olhando para o Codeg.", + "eventsTitle": "Eventos", + "eventsHint": "Escolha um som para cada evento ou «Silencioso» para ignorá-lo. Se o mesmo evento se repetir em poucos segundos, ele toca apenas uma vez.", + "toneNone": "Silencioso", + "toneChime": "Carrilhão", + "toneDing": "Sino", + "toneBlip": "Bipe", + "tonePop": "Pop", + "toneAlert": "Alerta", + "toneDescend": "Descendente" + }, + "LogsSettings": { + "loading": "Carregando…", + "sectionTitle": "Registros de execução", + "sectionDescription": "Visualize e configure os registros de diagnóstico do aplicativo. Os registros são gravados em arquivos locais e mantidos na memória para visualização ao vivo.", + "captureTitle": "Nível de registro", + "captureDescription": "Controla quanto detalhe é capturado. Níveis mais altos (Debug, Trace) registram mais, mas geram registros maiores. «Desligado» desativa o registro.", + "captureLabel": "Nível de captura", + "levels": { + "off": "Desligado", + "error": "Erro", + "warn": "Aviso", + "info": "Informação", + "debug": "Depuração", + "trace": "Rastreamento" + }, + "viewerTitle": "Registros recentes", + "viewerDescription": "Visualização ao vivo dos registros recentes. Filtre por nível ou pesquise texto.", + "searchPlaceholder": "Pesquisar mensagem ou origem…", + "viewLevels": { + "all": "Todos os níveis", + "error": "Erro e acima", + "warn": "Aviso e acima", + "info": "Informação e acima", + "debug": "Depuração e acima", + "trace": "Rastreamento e acima" + }, + "pause": "Pausar", + "resume": "Ao vivo", + "refresh": "Atualizar", + "clear": "Limpar", + "openFolder": "Abrir pasta", + "shownCount": "{shown} / {total} exibidos", + "empty": "Nenhum registro para exibir.", + "levelSaveFailed": "Falha ao salvar o nível de registro", + "openFolderFailed": "Falha ao abrir a pasta de registros", + "downloadFailed": "Falha ao baixar o arquivo de registro", + "filesTitle": "Arquivos de registro", + "filesDescription": "Baixe arquivos de registro completos do disco para o histórico além do buffer ao vivo.", + "filesEmpty": "Ainda não há arquivos de registro.", + "download": "Baixar", + "downloadTruncated": "O arquivo é grande; foram baixados os {size} mais recentes. O arquivo completo está no diretório de logs.", + "captureEnvLocked": "O nível de registro é controlado pela variável de ambiente RUST_LOG / CODEG_LOG; altere-a lá para ter efeito.", + "targetsTitle": "Substituições por módulo", + "targetsDescription": "Defina um nível diferente para módulos específicos (ex.: codeg_lib::acp) sem alterar o nível global.", + "targetsAdd": "Adicionar", + "targetsRemove": "Remover substituição", + "toggleDetails": "Alternar detalhes" + }, + "Automations": { + "title": "Automações", + "new": "Nova automação", + "empty": "Ainda não há automações", + "emptyHint": "Crie uma para executar uma tarefa do agente de forma agendada ou manual.", + "name": "Nome", + "namePlaceholder": "ex.: Revisão de PR noturna", + "prompt": "Instrução", + "promptPlaceholder": "O que o agente deve fazer?", + "agent": "Agente", + "folder": "Pasta do espaço de trabalho", + "folderPlaceholder": "Selecione uma pasta", + "isolation": "Isolamento", + "isolationWorktree": "Novo worktree por execução", + "isolationShared": "Executar na pasta", + "isolationSharedCaveat": "As execuções usam diretamente a árvore de trabalho desta pasta e podem entrar em conflito com suas alterações não confirmadas. Ative a opção de worktree para isolar cada execução.", + "trigger": "Gatilho", + "triggerSchedule": "Agendado", + "triggerManual": "Somente manual", + "cron": "Agendamento (cron)", + "cronPlaceholder": "0 9 * * 1-5", + "timezone": "Fuso horário", + "nextRun": "Próxima execução", + "branch": "Branch", + "branchOptional": "Branch (opcional)", + "enabled": "Ativado", + "save": "Salvar", + "cancel": "Cancelar", + "edit": "Editar", + "delete": "Excluir", + "runNow": "Executar agora", + "cancelRun": "Cancelar execução", + "runHistory": "Histórico de execuções", + "noRuns": "Ainda não há execuções", + "allFolders": "Todas as pastas", + "filterAll": "Todos", + "noMatches": "Nenhuma automação correspondente", + "viewConversation": "Ver conversa", + "lastRun": "Última execução", + "never": "Nunca", + "running": "Em execução", + "deleteTitle": "Excluir automação?", + "deleteDescription": "Isso remove a automação e seu agendamento. O histórico é mantido.", + "statusRunning": "Em execução", + "statusSucceeded": "Concluída", + "statusFailed": "Falhou", + "statusCancelled": "Cancelada", + "statusSkipped": "Ignorada", + "errorName": "O nome é obrigatório", + "errorPrompt": "A instrução é obrigatória", + "errorCron": "Automações agendadas exigem uma expressão cron", + "errorFolder": "Selecione uma pasta do espaço de trabalho", + "presetHourly": "A cada hora", + "presetDaily": "Diariamente 9h", + "presetWeekdays": "Dias úteis 9h", + "presetCustom": "Personalizado", + "probing": "Carregando opções…", + "retry": "Tentar novamente", + "configNone": "Este agente não tem opções configuráveis", + "inherit": "Padrão do agente", + "mode": "Modo", + "config": "Configuração", + "branchPlaceholder": "(branch padrão)", + "selectHint": "Selecione uma automação para ver os detalhes", + "refresh": "Atualizar", + "onboardTitle": "Automatize tarefas rotineiras do agente", + "onboardHint": "Agende um agente para revisar código, atualizar dependências ou triar problemas, periodicamente ou sob demanda.", + "headerSubtitle": "Tarefas do agente agendadas e sob demanda", + "startFromTemplate": "Começar com um modelo", + "blankTitle": "Automação em branco", + "blankDesc": "Configure uma tarefa do agente do zero.", + "backToTemplates": "Modelos", + "sectionSchedule": "Agendamento e destino", + "sectionTarget": "Destino", + "sectionAction": "Ação", + "actionLaunchSession": "Executar sessão", + "actionEnqueueTask": "Enfileirar tarefa", + "actionEnqueueTaskHint": "Cada disparo adiciona uma tarefa pendente, com o nome desta automação, às tarefas a fazer da pasta; o motor de tarefas a executa conforme as configurações do quadro.", + "sectionPrompt": "Prompt", + "nextIn": "Próxima em {rel}", + "manual": "Manual", + "schedEveryMinutes": "A cada {n} minutos", + "schedHourly": "De hora em hora", + "schedDaily": "Todos os dias às {time}", + "schedWeekdays": "Dias úteis às {time}", + "schedWeekly": "Toda {day} às {time}", + "schedMonthly": "Mensalmente no dia {day} às {time}", + "dow0": "domingo", + "dow1": "segunda-feira", + "dow2": "terça-feira", + "dow3": "quarta-feira", + "dow4": "quinta-feira", + "dow5": "sexta-feira", + "dow6": "sábado", + "tplCodeReviewTitle": "Revisão de código", + "tplCodeReviewDesc": "Revisa as alterações recentes em busca de bugs, regressões e problemas de qualidade.", + "tplDependencyUpdatesTitle": "Atualização de dependências", + "tplDependencyUpdatesDesc": "Encontra dependências desatualizadas e propõe atualizações seguras.", + "tplTestCoverageTitle": "Cobertura de testes", + "tplTestCoverageDesc": "Encontra caminhos de código sem testes e adiciona os testes que faltam.", + "tplTodoSweepTitle": "Varredura de TODO", + "tplTodoSweepDesc": "Reúne comentários TODO e FIXME e os tria por prioridade.", + "tplCiTriageTitle": "Triagem de CI", + "tplCiTriageDesc": "Investiga verificações que falharam recentemente e propõe correções.", + "tplReleaseNotesTitle": "Notas de versão", + "tplReleaseNotesDesc": "Resume as alterações desde a última versão em um changelog.", + "tplSecurityAuditTitle": "Auditoria de segurança", + "tplSecurityAuditDesc": "Verifica vulnerabilidades e padrões de risco e relata as constatações.", + "enable": "Ativar", + "disable": "Desativar", + "moreActions": "Mais ações", + "statusDisabled": "Desativada", + "cronBuilderTitle": "Gerador de agendamento", + "cronFreqLabel": "Frequência", + "cronFreqMinutes": "A cada N minutos", + "cronFreqHourly": "De hora em hora", + "cronFreqDaily": "Diário", + "cronFreqWeekdays": "Dias úteis", + "cronFreqWeekly": "Semanal", + "cronFreqMonthly": "Mensal", + "cronFreqCustom": "Personalizado", + "cronEveryLabel": "Intervalo (minutos)", + "cronTimeLabel": "Hora", + "cronHourLabel": "Hora", + "cronMinuteLabel": "Minuto", + "cronDowLabel": "Dia da semana", + "cronDomLabel": "Dia do mês", + "cronApply": "Aplicar", + "cronPreviewLabel": "Pré-visualização", + "cronOpenBuilder": "Abrir o gerador de agendamento", + "branchDefault": "Branch padrão", + "branchUseCustom": "Usar \"{query}\"", + "branchLocal": "Local", + "branchRemote": "Remoto", + "branchSearchPlaceholder": "Pesquisar branches…", + "branchNone": "Sem branches" + }, + "Tasks": { + "title": "Tarefas a fazer", + "new": "Nova tarefa", + "empty": "Ainda não há tarefas", + "emptyHint": "Adicione uma pendência e execute — o agente trabalha num worktree isolado e você revisa e faz merge do resultado.", + "emptyColTodo": "Ainda não há tarefas a fazer", + "emptyColInProgress": "Nada em andamento", + "emptyColAttention": "Nada aguardando você", + "emptyColDone": "Ainda não há concluídas", + "allFolders": "Todas as pastas", + "showCanceled": "Mostrar canceladas", + "showArchived": "Mostrar arquivadas", + "filter": "Filtrar", + "viewSwitchToBoard": "Mudar para a visualização de quadro", + "viewSwitchToList": "Mudar para a visualização de lista", + "statusFilter": "Estado", + "statusFilterAll": "Todos os estados", + "listEmpty": "Nenhuma tarefa corresponde aos filtros atuais", + "listColStatus": "Estado", + "listColTask": "Tarefa", + "listColLocation": "Localização", + "listColChanges": "Alterações", + "listColUpdated": "Atualizado", + "colTodo": "A fazer", + "colInProgress": "Em andamento", + "colAttention": "Aguardando você", + "colDone": "Concluídas", + "statusTodo": "A fazer", + "statusQueued": "Na fila", + "statusPreparing": "Preparando", + "statusRunning": "Em execução", + "statusAwaitingInput": "Aguardando entrada", + "statusReview": "Para revisar", + "statusMerging": "Fazendo merge", + "statusDone": "Concluída", + "statusFailed": "Falhou", + "statusCanceled": "Cancelada", + "statusInterrupted": "Interrompida", + "badgeCleanupFailed": "Limpeza falhou", + "badgeWorktreeKept": "Worktree mantido", + "badgeWorktreeRemoved": "Worktree removido", + "filesChanged": "{count} arquivos", + "actionStart": "Iniciar", + "actionSchedule": "Agendar", + "actionCancel": "Cancelar", + "actionRetry": "Tentar novamente", + "actionRequeue": "Reenfileirar", + "actionViewSession": "Ver conversa", + "actionEdit": "Editar", + "actionDelete": "Excluir", + "actionRetryCleanup": "Repetir limpeza", + "actionMerge": "Merge", + "actionUnqueueMerge": "Sair da fila de merge", + "actionEditQueuedMerge": "Editar merge na fila", + "badgeMergeQueued": "Na fila para merge", + "badgeMergeQueuedRank": "Na fila para merge · n.º {rank}", + "badgeMergeQueuedHint": "Aguardando o merge em andamento do projeto terminar; este começa sozinho.", + "actionComplete": "Concluir", + "actionAbandon": "Abandonar", + "cancelTitle": "Cancelar tarefa?", + "cancelDescription": "A tarefa passa para Cancelada. O worktree é mantido e você pode reenfileirá-la depois.", + "cancelReasonLabel": "Motivo (opcional)", + "cancelReasonPlaceholder": "Ex.: abordagem errada — vou reescrever a descrição", + "cancelKeep": "Deixa pra lá", + "cancelSubmit": "Cancelar tarefa", + "restartTitleRetry": "Tentar a tarefa novamente", + "restartTitleRequeue": "Reenfileirar a tarefa", + "restartDescription": "Você pode adicionar uma nota (opcional): ela chega ao prompt da próxima execução.", + "scheduleTitle": "Agendar tarefa", + "scheduleDescription": "A tarefa continua em A fazer e inicia sozinha no horário escolhido. O limite de concorrência da pasta continua valendo.", + "scheduleDateLabel": "Data", + "schedulePickDate": "Escolher data", + "scheduleTimeLabel": "Hora", + "schedulePreview": "Executa em {time}", + "schedulePastHint": "Esse horário já passou: a tarefa começa assim que você salvar.", + "scheduleInAnHour": "Em 1 hora", + "scheduleInThreeHours": "Em 3 horas", + "scheduleTomorrow": "Amanhã 9:00", + "scheduleClear": "Remover agendamento", + "scheduleBadge": "Início agendado para {time}", + "toastScheduled": "Agendada para {time}", + "toastScheduleCleared": "Agendamento removido", + "actionFollowUp": "Continuar", + "actionAddNote": "Adicionar observação", + "followUpSubmit": "Enviar", + "followUpIntentRevise": "Corrigir", + "followUpIntentContinue": "Prosseguir", + "followUpIntentQuestion": "Perguntar", + "followUpIntentVerify": "Revisar", + "followUpPlaceholderRevise": "O que o agente deve mudar? Ele continua na mesma sessão.", + "followUpPlaceholderContinue": "E agora? O que já foi feito permanece.", + "followUpPlaceholderQuestion": "O que você quer saber? O agente responde sem mexer em nenhum arquivo.", + "followUpPlaceholderVerify": "Opcional: algo que deva revisar com atenção?", + "followUpPlaceholderRetry": "Opcional: o que deve ser feito diferente? Ex.: rodar pnpm install antes", + "followUpPlaceholderRequeue": "Opcional: por que você cancelou e o que deve mudar desta vez?", + "actionArchive": "Arquivar", + "actionUnarchive": "Desarquivar", + "archiveAllDone": "Arquivar tudo", + "dropToStart": "Solte para iniciar", + "errorView": "Ver", + "notifyReview": "Pronto para revisão: {title}", + "notifyFailed": "A tarefa falhou: {title}", + "createFromMessage": "Criar tarefa a partir da mensagem", + "detailTokens": "Total de tokens", + "editorTitleNew": "Nova tarefa", + "editorTitleEdit": "Editar tarefa", + "templates": "Modelos", + "templatesEmpty": "Ainda não há modelos.", + "templateSaveCurrent": "Salvar como modelo", + "templateDelete": "Excluir modelo", + "transcriptTitle": "Conversa da tarefa", + "transcriptDescription": "Visão ao vivo somente leitura da sessão do agente da tarefa.", + "phaseWork": "Execução", + "phaseRetry": "Nova tentativa", + "phaseReturn": "Continuação", + "phaseMerge": "Merge", + "titleLabel": "Título", + "titlePlaceholder": "O que precisa ser feito?", + "promptLabel": "Descrição da tarefa", + "promptPlaceholder": "Descreva a tarefa para o agente — @ para referenciar arquivos, / para comandos", + "folderPlaceholder": "Selecione uma pasta", + "agentInheritedHint": "Herdado das configurações de tarefas; altere para personalizar esta tarefa", + "agentOverrideReset": "Voltar a herdar", + "sectionTarget": "Destino", + "errorTitle": "O título é obrigatório", + "errorPrompt": "A descrição é obrigatória", + "errorFolder": "Selecione uma pasta", + "save": "Salvar", + "cancel": "Cancelar", + "mergeTitle": "Merge da tarefa", + "mergeQueuedTitle": "Merge na fila", + "mergeQueueHint": "Outra tarefa deste projeto está sendo mesclada agora. Esta entra na fila e começa sozinha assim que a outra terminar.", + "mergeQueueUpdateHint": "Esta tarefa já está esperando para mesclar. Enviar atualiza o merge e mantém o lugar na fila.", + "mergeDescription": "Fazer merge de {branch} em {base}. Alterações não commitadas no worktree são commitadas antes.", + "mergeMessage": "Mensagem do commit", + "mergeMessagePlaceholder": "ex.: feat: add login validation", + "mergeAutoMessage": "Deixar o agente escrever a mensagem de commit", + "strategySquash": "Combinar em um único commit", + "strategySquashHint": "Todas as mudanças da tarefa entram na branch principal como um único registro — histórico mais limpo.", + "strategyMerge": "Manter o histórico completo", + "strategyMergeHint": "Cada commit feito durante a tarefa é mantido, mais um registro de merge — cada etapa fica rastreável.", + "mergeDeleteWorktree": "Excluir o worktree após o merge", + "mergeSubmit": "Merge", + "mergeSubmitQueue": "Adicionar à fila", + "mergeQueuedToast": "Adicionada à fila de merge — começa assim que o merge atual terminar.", + "completeTitle": "Concluir tarefa", + "completeDescription": "Esta tarefa não alterou nenhum arquivo, então não há nada para fazer merge: ela é marcada como concluída.", + "completeDescriptionNoWorktree": "O worktree desta tarefa foi removido, então não é mais possível fazer merge: ela é marcada como concluída. Um branch de trabalho que ainda tenha commits não mesclados é mantido.", + "completeDeleteWorktree": "Excluir o worktree ao concluir", + "completeSubmit": "Concluir", + "settingsTitle": "Configurações de tarefas", + "settingsDescription": "Padrões para tarefas em {folder}.", + "settingsScope": "Escopo", + "settingsScopeGlobal": "Todas as pastas (padrões globais)", + "settingsScopeGlobalHint": "Pastas sem configurações próprias usam estes padrões globais.", + "settingsSource": "Origem da configuração", + "settingsSourceGlobal": "Padrões globais", + "settingsSourceCustom": "Personalizada", + "settingsSourceGlobalFollow": "Segue as configurações globais de tarefas — mudanças lá se aplicam aqui automaticamente.", + "settingsSourceCustomHint": "Salva configurações próprias desta pasta, que deixa de seguir os padrões globais.", + "settingsAgent": "Agente padrão", + "settingsMaxConcurrent": "Máx. de tarefas simultâneas", + "settingsMaxConcurrentHint": "0 = ilimitado", + "settingsAutoProcess": "Processar automaticamente", + "settingsAutoProcessHint": "As tarefas pendentes iniciam sozinhas, até o limite de concorrência.", + "settingsMergeStrategy": "Estratégia de merge padrão", + "settingsMergeStrategyHint": "Como as mudanças da tarefa são registradas no histórico da branch ao mesclar.", + "settingsAutoMerge": "Merge automático", + "settingsAutoMergeHint": "Uma tarefa que chega à revisão com mudanças a integrar recebe merge como se você clicasse em Merge: o agente escreve a mensagem de commit e o worktree segue o padrão abaixo. Se a pré-verificação falhar ou um merge tiver falhado, a tarefa fica esperando por você.", + "settingsDeleteWorktree": "Excluir o worktree após o merge", + "settingsDeleteWorktreeHint": "Marca a opção por padrão no diálogo de merge; ainda dá para alterar lá.", + "settingsWorktreeRoot": "Local do worktree", + "settingsWorktreeRootHint": "Diretório onde os worktrees das novas tarefas são criados, um por tarefa. Deixe vazio para criá-los ao lado da pasta do projeto; \"~\" é a sua pasta pessoal e um caminho relativo é resolvido a partir da pasta do projeto.", + "settingsWorktreeRootPlaceholder": "~/codeg-worktrees", + "settingsWorktreeRootBrowse": "Escolher o diretório dos worktrees", + "settingsPreflight": "Comando de pré-verificação", + "settingsPreflightHint": "Executa no worktree quando uma tarefa chega à revisão.", + "settingsPreflightCustomPlaceholder": "pnpm test", + "settingsInitCommand": "Comando de inicialização do worktree", + "settingsInitCommandHint": "Executado em um worktree recém-criado antes de o agente iniciar.", + "settingsInitCommandPlaceholder": "pnpm install", + "settingsTabGeneral": "Geral", + "settingsTabMerge": "Merge", + "settingsTabWorktree": "Worktree", + "settingsTabPrompts": "Prompts", + "settingsPromptsIntro": "Cada etapa já envia seu próprio prompt embutido: a tarefa, as regras do worktree e, no merge, os passos exatos do git. O que você escrever aqui é anexado ao final como instruções extras: refina esses textos embutidos, mas nunca os substitui.", + "settingsPromptStageAll": "Todas as fases", + "settingsPromptPlaceholderAll": "ex.: Siga as convenções do AGENTS.md; mantenha o resumo final em duas frases", + "settingsPromptPlaceholderWork": "ex.: Leia primeiro os testes relacionados; faça commits pequenos ao longo do trabalho", + "settingsPromptPlaceholderRetry": "ex.: Verifique o que já está commitado antes de continuar; não refaça o que está pronto", + "settingsPromptPlaceholderReturn": "Ex.: Trate cada ponto levantado; não refatore nada não relacionado", + "settingsPromptPlaceholderMerge": "ex.: Escreva a mensagem do commit de integração em português; aponte os conflitos resolvidos à mão", + "settingsPromptHintAll": "Acrescentado a todos os prompts que o agente recebe, inclusive no merge.", + "settingsPromptHintWork": "Acrescentado quando uma tarefa é executada pela primeira vez.", + "settingsPromptHintRetry": "Acrescentado ao retomar uma tarefa interrompida ou com falha.", + "settingsPromptHintReturn": "Anexado quando você continua uma tarefa em revisão (corrigir, ampliar, revisar).", + "settingsPromptHintMerge": "Acrescentado quando o agente integra a tarefa no branch base.", + "preflightPassed": "{name} aprovado", + "preflightFailed": "{name} falhou", + "preflightRunning": "{name} em execução…", + "detailDescription": "Detalhes da tarefa", + "detailSummary": "Resultado", + "detailFiles": "Arquivos alterados", + "detailDiffAll": "Ver diff completo", + "detailDiffAllTitle": "Diff completo", + "detailNoChanges": "Ainda não há mudanças em relação à base", + "detailTimeline": "Progresso", + "detailTimelineEmpty": "Nenhuma atividade ainda", + "showMore": "Ver mais", + "showLess": "Ver menos", + "detailInfo": "Detalhes", + "detailBranch": "Branch", + "detailMergeCommit": "Commit de merge", + "detailChanges": "Alterações", + "detailScheduled": "Início agendado", + "detailCreated": "Criada", + "detailStarted": "Iniciada", + "detailFinished": "Concluída", + "diffLoading": "Carregando diff…", + "deleteConfirmTitle": "Excluir tarefa?", + "deleteConfirmBody": "“{title}” será removida do quadro. Uma execução ativa é cancelada antes.", + "deleteWithWorktree": "Excluir também o worktree", + "eventCreated": "Criada", + "eventStatusChanged": "Mudança de status", + "eventConfigEffective": "Configuração de execução", + "eventInitCommand": "Comando de inicialização", + "eventAgentProgress": "Progresso do agente", + "eventAgentVerdict": "Veredito do agente", + "eventMergeAttempt": "Merge iniciado", + "eventMergeQueued": "Na fila para merge", + "eventMergeConflict": "Conflito de merge", + "eventPreflight": "Pré-verificação", + "eventCleanupFailed": "Falha na limpeza do worktree", + "eventResumeFallback": "Retomada falhou; nova sessão usada", + "eventUserAction": "Ação do usuário", + "eventDiffStat": "Resumo das mudanças" + }, + "CustomSkillsSettings": { + "loading": "Carregando habilidades personalizadas…", + "category": "Personalizadas", + "searchPlaceholder": "Pesquisar habilidades personalizadas por nome, ID ou descrição", + "states": { + "not_linked": "Não ativada", + "linked_to_codeg": "Ativada", + "linked_elsewhere": "Vinculada em outro lugar", + "blocked_by_real_directory": "Bloqueada por uma pasta real", + "broken": "Link quebrado" + }, + "actions": { + "new": "Nova", + "import": "Importar", + "importFromAgent": "Importar de um agente", + "cancel": "Cancelar", + "save": "Salvar" + }, + "rowMenu": { + "edit": "Editar", + "duplicate": "Duplicar", + "delete": "Excluir" + }, + "bulk": { + "delete": "Excluir selecionadas" + }, + "editor": { + "createTitle": "Nova habilidade personalizada", + "editTitle": "Editar habilidade personalizada", + "description": "As habilidades personalizadas ficam no armazenamento compartilhado (~/.codeg/skills) e podem ser ativadas para qualquer agente.", + "idLabel": "ID da habilidade", + "idPlaceholder": "ex.: my-workflow", + "contentLabel": "SKILL.md", + "contentPlaceholder": "Escreva aqui o SKILL.md da habilidade…", + "preview": "Pré-visualização", + "edit": "Editar", + "emptyBody": "Ainda sem conteúdo." + }, + "duplicate": { + "title": "Duplicar habilidade", + "description": "Criar uma cópia de \"{id}\" com um novo ID.", + "newIdPlaceholder": "Novo ID da habilidade", + "confirm": "Duplicar" + }, + "import": { + "title": "Escolha uma pasta de habilidade para importar" + }, + "importFromAgent": { + "title": "Importar habilidades de um agente", + "description": "Copie as habilidades próprias de um agente para o repositório compartilhado e ative-as em qualquer agente.", + "agentLabel": "Agente", + "agentPlaceholder": "Selecione um agente", + "selectAll": "Selecionar tudo ({count})", + "loading": "Carregando as habilidades do agente…", + "unsupported": "Este agente não expõe um diretório de habilidades.", + "empty": "Este agente não tem habilidades para importar.", + "alreadyInLibrary": "Na biblioteca", + "confirm": "Importar selecionadas ({count})" + }, + "delete": { + "title": "Excluir habilidades personalizadas?", + "body": "Isto remove {count} habilidade(s) personalizada(s) do armazenamento central e as desvincula de todos os agentes. Não pode ser desfeito.", + "confirm": "Excluir" + }, + "toasts": { + "loadFailed": "Falha ao carregar a habilidade", + "idRequired": "Informe um ID de habilidade", + "created": "Habilidade personalizada criada", + "updated": "Habilidade personalizada atualizada", + "saveFailed": "Falha ao salvar a habilidade", + "imported": "Habilidade importada", + "importFailed": "Falha ao importar a habilidade", + "duplicated": "Habilidade duplicada", + "duplicateFailed": "Falha ao duplicar a habilidade", + "deleted": "{count} habilidade(s) excluída(s)", + "deletedPartial": "{ok} excluída(s), {failed} com falha", + "deleteFailed": "Falha ao excluir as habilidades", + "importedFromAgent": "{count} habilidade(s) importada(s)", + "importedFromAgentPartial": "{ok} importada(s), {failed} com falha", + "importFromAgentAllSkipped": "Nada a importar — {count} já na biblioteca", + "importFromAgentFailed": "Falha ao importar do agente" + } + }, + "CodexModelEditor": { + "customizedNotice": "Você personalizou a lista de modelos, então agora o codeg gerencia toda a tabela de modelos do codex. Os modelos oficiais que o codex adicionar depois não aparecerão automaticamente — clique no botão atualizar abaixo e salve novamente para sincronizá-los. Limpe suas personalizações para que o codex volte a atualizar automaticamente.", + "officialsTitle": "Modelos oficiais", + "officialsHint": "Incluídos automaticamente do codex que você inicia; remova os que não quiser.", + "officialsEmpty": "Nenhum modelo oficial disponível.", + "refresh": "Atualizar do codex", + "readdOfficial": "Readicionar oficial", + "customsTitle": "Modelos personalizados", + "customsEmpty": "Ainda não há modelos personalizados.", + "addCustom": "Adicionar personalizado", + "slugPlaceholder": "id do modelo (slug)", + "displayNamePlaceholder": "Nome de exibição", + "contextWindow": "Contexto", + "makeDefault": "Definir como padrão", + "defaultHint": "Modelo padrão", + "remove": "Remover", + "advanced": "Avançado", + "baseTemplate": "Modelo base", + "baseTemplateHint": "Modelo oficial do qual clonar os campos obrigatórios (prompt do sistema, ferramentas, limites).", + "groupBehavior": "Comportamento e recursos", + "fieldReasoningLevel": "Raciocínio padrão", + "fieldReasoningSummary": "Resumo do raciocínio", + "fieldVerbosity": "Verbosidade", + "fieldShellType": "Tipo de shell", + "fieldApplyPatch": "Ferramenta apply-patch", + "fieldReasoningSummaries": "Resumos de raciocínio", + "fieldSupportVerbosity": "Controle de verbosidade", + "fieldParallelToolCalls": "Chamadas de ferramentas em paralelo", + "fieldSearchTool": "Ferramenta de busca na web", + "optNone": "Nenhum", + "groupInstructions": "Descrição e prompt do sistema", + "fieldDescription": "Descrição", + "baseInstructions": "Prompt do sistema (base_instructions)" + }, + "DiagnosticsSettings": { + "title": "Diagnóstico do ambiente", + "description": "Verifica como este app resolve a CLI do agente no próprio processo, que pode diferir do seu terminal.", + "loading": "Executando diagnóstico…", + "error": "Falha no diagnóstico", + "rerun": "Executar novamente", + "copyAll": "Copiar tudo", + "copied": "Diagnóstico copiado para a área de transferência", + "button": "Diagnosticar", + "verdict": { + "ok": "O ambiente parece saudável. Se ainda aparecer como não instalado, reinicie o app completamente para atualizar o cache do prefixo.", + "node_missing": "Node.js não foi encontrado no PATH do app.", + "npm_missing": "npm não foi encontrado no PATH do app.", + "not_installed": "Este agente não parece estar instalado.", + "installed_but_unresolved": "Consta como instalado, mas o app não consegue localizar o executável.", + "user_prefix_not_on_path": "Instalado no prefixo de fallback (~/.codeg/npm-global), que não está no PATH do app. Reinicie o app completamente e tente novamente.", + "homebrew_bin_not_on_path": "Instalado no bin do Homebrew, que não está no PATH do app (divisão de keg no Apple Silicon).", + "terminal_only_path": "O comando é resolvido no seu terminal, mas não no app: uma diferença de PATH da GUI. Inicie o app por um terminal ou reinstale nas Configurações de agentes.", + "npm_prefix_timeout": "npm prefix -g foi muito lento (mais de 1,5 s), então a detecção de fallback foi ignorada. Reinicie o app e tente novamente.", + "node_too_old": "Seu Node.js ativo é mais antigo do que este agente requer. Atualize o Node.js.", + "adapter_missing_native_present": "A sua CLI do {agent} está instalada, mas o Codeg inicia um pacote adaptador ACP separado — e esse ainda não está. Instale-o nas configurações de agentes: ele não mexe na sua CLI e compartilha o mesmo login.", + "adapter_missing": "O Codeg inicia um pacote adaptador ACP separado para o {agent}, e ele ainda não está instalado. Instale-o nas configurações de agentes — instalar só a CLI do fornecedor não basta." + } + }, + "TokenUsage": { + "title": "Uso de tokens", + "rangeLabel": "Período", + "range7d": "7 dias", + "range30d": "30 dias", + "range90d": "90 dias", + "rangeThisMonth": "Este mês", + "rangeThisYear": "Este ano", + "rangeAll": "Tudo", + "rangeCustom": "Personalizado", + "moreRanges": "Mais", + "customRangePick": "Escolher um período", + "bucketLabel": "Agrupar por", + "bucketDay": "Dia", + "bucketWeek": "Semana", + "bucketMonth": "Mês", + "bucketUnitDay": "Dia", + "bucketUnitWeek": "Semana", + "bucketUnitMonth": "Mês", + "folderFilter": "Pastas", + "allFolders": "Todas as pastas", + "agentFilter": "Agentes", + "allAgents": "Todos os agentes", + "modelFilter": "Modelos", + "allModels": "Todos os modelos", + "searchPlaceholder": "Pesquisar…", + "noMatches": "Nenhum resultado", + "clearFilter": "Limpar seleção", + "resetFilters": "Limpar filtros", + "refresh": "Atualizar", + "rebuild": "Reconstruir tudo", + "rebuildHint": "Descarta o que já foi contabilizado e relê todas as transcrições. Útil se uma sessão cresceu fora do codeg.", + "syncing": "Contando sessões…", + "syncProgress": "{done} / {total}", + "syncDone": "{synced} sessões contabilizadas", + "syncFailed": "Não foi possível ler algumas sessões", + "syncBusy": "Já existe uma atualização em andamento", + "lastSynced": "Atualizado {time}", + "lastSyncedNever": "Nunca atualizado", + "tileTotal": "Tokens totais", + "tileSessions": "Sessões", + "tileTurns": "Turnos", + "tileActiveDays": "Dias ativos", + "tileGenTime": "Tempo de geração", + "vsPrevious": "vs. período anterior", + "deltaNew": "novo", + "trendTitle": "Uso ao longo do tempo", + "trendEmpty": "Sem uso neste período", + "trendTurns": "Turnos", + "trendSessions": "Sessões", + "compositionTitle": "Para onde foram os tokens", + "compositionHint": "Entrada é o que você enviou, saída é o que o modelo escreveu e leituras de cache são contexto que não custou preço cheio.", + "compositionNote": "Reenviar esses acertos de cache a preço cheio custaria mais {value}.", + "inputTokens": "Entrada", + "outputTokens": "Saída", + "cacheWrite": "Escrita de cache", + "cacheRead": "Leitura de cache", + "freshTokens": "Cômputo novo", + "cacheHitCaption": "Acerto de cache", + "cacheHeroTitleHigh": "A maior parte do contexto não precisou ser reenviada", + "cacheHeroTitleLow": "A maior parte do contexto ainda é calculada a preço cheio", + "cacheHeroDesc": "O cache carregou {cached} de contexto; só {fresh} foi de fato calculado de novo no período.", + "cacheSavedSuffix": "Isso poupou reenviar o equivalente a {saved}.", + "avgPerSession": "Média por sessão", + "avgTurnsPerSession": "{count} turnos por sessão em média", + "avgPerActiveDay": "Média por dia ativo", + "peakBucket": "{bucket} de pico", + "peakHour": "Hora de pico", + "daysValue": "{count} dias", + "idleDays": "Dias parados", + "byFolderTitle": "Por pasta", + "byAgentTitle": "Por agente", + "byModelTitle": "Por modelo", + "distributionTitle": "Distribuição de uso", + "distributionHint": "Sessões e tokens agrupados pela dimensão escolhida — clique numa linha para filtrar.", + "otherLabel": "Outros", + "unknownModel": "Modelo não registrado", + "emptyBreakdown": "Nada registrado ainda", + "sessionsCount": "{count} sessões", + "heatmapTitle": "Quando você programa", + "heatmapHint": "Tokens por dia da semana e hora local.", + "heatmapPeakHint": "Mais denso por volta das {hour}:00.", + "less": "Menos", + "more": "Mais", + "heatmapCell": "{weekday} {hour}:00 — {value} tokens", + "weekMon": "Seg", + "weekTue": "Ter", + "weekWed": "Qua", + "weekThu": "Qui", + "weekFri": "Sex", + "weekSat": "Sáb", + "weekSun": "Dom", + "topSessionsTitle": "Sessões mais pesadas", + "untitledSession": "Sessão sem título", + "topSessionsEmpty": "Sem sessões neste período", + "streakLongest": "Maior sequência", + "streakLongestDays": "Maior sequência: {count} dias", + "share": "Compartilhar", + "moreActions": "Mais ações", + "shareDialogTitle": "Compartilhe seu cartão de uso", + "shareDialogHint": "Um retrato do período e dos filtros que você está vendo.", + "shareSave": "Salvar imagem", + "shareCopy": "Copiar imagem", + "shareCopied": "Copiado para a área de transferência", + "shareSaved": "Imagem salva", + "shareFailed": "Não foi possível criar a imagem", + "shareRendering": "Gerando…", + "cardHeading": "Minhas estatísticas de código com IA", + "cardRangeAll": "Todo o período", + "cardTotalLabel": "Tokens usados", + "cardFooter": "Feito com codeg", + "cardTopModels": "Principais modelos", + "cardTopProjects": "Principais projetos", + "archetypeNightOwl": "Coruja noturna", + "archetypeNightOwlDesc": "{percent}% dos seus tokens queimam depois do anoitecer.", + "archetypeEarlyBird": "Madrugador", + "archetypeEarlyBirdDesc": "{percent}% dos seus tokens acontecem antes das 9h.", + "archetypeWeekendWarrior": "Guerreiro de fim de semana", + "archetypeWeekendWarriorDesc": "{percent}% dos seus tokens acontecem no fim de semana.", + "archetypeCacheMaster": "Mestre do cache", + "archetypeCacheMasterDesc": "{percent}% do seu contexto veio do cache.", + "archetypeMarathoner": "Maratonista", + "archetypeMarathonerDesc": "{days} dias programando sem parar.", + "archetypePolyglot": "Polivalente", + "archetypePolyglotDesc": "{count} agentes em uso pesado.", + "archetypeLaserFocus": "Foco total", + "archetypeLaserFocusDesc": "{percent}% dos seus tokens foram para um único projeto.", + "archetypeDeepDiver": "Mergulhador", + "archetypeDeepDiverDesc": "{averageK}K tokens numa sessão média.", + "archetypeSteady": "Construtor constante", + "archetypeSteadyDesc": "{days} dias entregando.", + "emptyTitle": "Nada contabilizado ainda", + "emptyHint": "O codeg lê os tokens direto da transcrição de cada agente. Atualize para contabilizar o que já existe nesta máquina.", + "emptyAction": "Contabilizar minhas sessões", + "loadFailed": "Não foi possível carregar o uso", + "truncatedNotice": "Este período é muito amplo — os números cobrem apenas o trecho mais recente." + } +} diff --git a/src/i18n/messages/zh-CN.json b/src/i18n/messages/zh-CN.json index 6c9651365..0db368b76 100644 --- a/src/i18n/messages/zh-CN.json +++ b/src/i18n/messages/zh-CN.json @@ -1,4958 +1,4958 @@ -{ - "Language": { - "followSystem": "跟随系统", - "english": "英语", - "simplifiedChinese": "简体中文", - "traditionalChinese": "繁體中文", - "japanese": "日语", - "korean": "韩语", - "spanish": "西班牙语", - "german": "德语", - "french": "法语", - "portuguese": "葡萄牙语", - "arabic": "阿拉伯语" - }, - "GitCredentialDialog": { - "title": "需要身份验证", - "description": "远程服务器要求输入凭据。请输入用户名和密码(或个人访问令牌)。", - "username": "用户名", - "usernamePlaceholder": "用户名或邮箱", - "password": "密码 / 令牌", - "passwordPlaceholder": "密码或个人访问令牌", - "passwordHint": "请输入服务器的用户名和密码。", - "cancel": "取消", - "authenticate": "认证", - "authenticating": "认证中...", - "invalidCredentials": "凭据无效,请重试。", - "saveCredentials": "保存凭据以供后续操作使用", - "githubTitle": "GitHub 身份验证", - "githubDescription": "输入个人访问令牌以连接 GitHub。令牌验证成功后将自动保存到账号列表。", - "githubToken": "个人访问令牌", - "githubTokenPlaceholder": "ghp_xxxxxxxxxxxx", - "githubTokenHint": "在 GitHub → Settings → Developer settings → Personal access tokens 中生成令牌。", - "githubAuthenticate": "验证并连接", - "generateToken": "生成令牌" - }, - "SettingsShell": { - "title": "设置", - "preferences": "偏好设置", - "nav": { - "general": "常规", - "appearance": "外观", - "agents": "智能体", - "mcp": "MCP", - "skills": "Skills", - "shortcuts": "快捷键", - "version_control": "版本控制", - "system": "系统", - "chat_channels": "消息渠道", - "web_service": "Web 服务", - "model_providers": "模型供应商", - "experts": "专家", - "science": "科学研究", - "office_tools": "办公工具", - "skill_packs": "技能包", - "quick_messages": "快捷消息", - "logs": "运行日志" - } - }, - "AppearanceSettings": { - "sectionTitle": "主题外观", - "sectionDescription": "选择浅色、深色或跟随系统主题,设置会自动保存。", - "themeMode": "主题模式", - "placeholder": "请选择主题模式", - "system": "跟随系统", - "light": "浅色", - "dark": "深色", - "currentTheme": "当前生效主题:{theme}", - "resolvedTheme": { - "light": "浅色", - "dark": "深色", - "unknown": "未知" - }, - "themeColor": { - "sectionTitle": "主题颜色", - "sectionDescription": "选择按钮、强调色和高亮使用的色调。", - "current": "当前颜色:{color}", - "options": { - "neutral": "Neutral", - "zinc": "Zinc", - "slate": "Slate", - "stone": "Stone", - "gray": "Gray", - "red": "Red", - "rose": "Rose", - "orange": "Orange", - "green": "Green", - "blue": "Blue", - "yellow": "Yellow", - "violet": "Violet" - } - }, - "customStyle": { - "sectionTitle": "自定义样式", - "sectionDescription": "在当前主题的基础上微调配色,或写入自己的 CSS。覆盖叠加在基底预设之上,切换预设后依然保留。", - "summarySuspended": "已停用", - "summaryDefault": "跟随预设", - "summaryTokens": "{count, plural, other {# 项覆盖}}", - "summaryCss": "自定义 CSS", - "suspendedByShortcut": "自定义样式已停用。在恢复之前,这里的设置都不会生效。", - "suspendedBySafeParam": "本窗口以安全外观模式打开,自定义样式在此不生效,其它窗口不受影响。", - "resume": "恢复自定义样式", - "enableTheme": "启用自定义配色", - "editingLight": "正在编辑浅色模式的取值。切换到深色模式可单独设置深色。", - "editingDark": "正在编辑深色模式的取值。切换到浅色模式可单独设置浅色。", - "resetToken": "恢复为预设取值", - "radius": "圆角", - "radiusHint": "从 sm 到 4xl 的整套圆角尺寸都由它派生,一个滑块即可改变全局圆角。", - "advanced": "高级(另有 {count} 个变量)", - "enableCss": "启用自定义 CSS", - "cssRisk": "高级功能。自定义 CSS 会压过所有内置样式,写坏可能导致界面不可用。", - "editCss": "编辑 CSS…", - "cssPresent": "已保存 {size} KB", - "cssEmpty": "尚未保存内容", - "escapeHint": "界面被改坏了?按 {shortcut} 可停用全部自定义样式,也可以用 safeStyle=1 查询参数打开窗口。", - "copyTheme": "复制主题 JSON", - "importTheme": "导入主题…", - "clearTheme": "清除覆盖", - "interopHint": "主题采用 shadcn 的 registry:theme 格式,可以直接粘贴任意 shadcn 主题,导出的主题也能用在任何 shadcn 项目里。", - "importTitle": "导入主题", - "importDescription": "粘贴 shadcn 的 registry:theme 条目、裸的 light/dark 对象,或者单层的 token 映射。", - "readClipboard": "读取剪贴板", - "importConfirm": "导入", - "cancel": "取消", - "apply": "应用", - "toasts": { - "copied": "主题 JSON 已复制", - "copyFailed": "无法写入剪贴板", - "clipboardReadFailed": "无法读取剪贴板,请手动粘贴", - "importFailed": "这段 JSON 里没有可用的主题变量", - "imported": "主题已导入" - }, - "css": { - "dialogTitle": "自定义 CSS", - "dialogDescription": "对所有 codeg 窗口生效。修改会实时预览,点击「应用」才会保存。", - "size": "{used} KB / {max} KB", - "ruleCount": "{count} 条规则", - "errorTooLarge": "内容过大,无法保存,请精简到上限以内。", - "errorImportEscaped": "剥离后仍检测到 @import(转义写法),请手动移除后再保存。", - "warnNoRules": "没有解析出任何规则,请检查语法。", - "noticeImportsRemoved": "已移除 {count} 条 @import:它们会拉取远程样式表。", - "noticeRemoteUrl": "含远程 url(),应用后会发起网络请求。", - "noticePreviewSuspended": "自定义样式已停用,此处预览不会生效。", - "noticeDisabled": "自定义 CSS 未启用。这里可以预览,但启用后才会真正生效。", - "hintTokens": "提示:你覆盖的颜色可以直接用 var(--primary)、var(--background) 等引用。" - } - }, - "zoomLevel": { - "sectionTitle": "窗口缩放", - "sectionDescription": "整体放大或缩小界面,立即生效,按设备分别保存。", - "placeholder": "请选择缩放档位", - "default": "默认", - "current": "当前缩放:{zoom}%" - }, - "fonts": { - "sectionTitle": "字体", - "sectionDescription": "为界面、代码编辑器和终端分别选择字体。内置字体按需加载;选择“自定义…”可使用系统已安装的任意字体。", - "interface": "界面", - "editor": "编辑器", - "terminal": "终端", - "groupSans": "无衬线", - "groupMono": "等宽", - "custom": "自定义…", - "customPlaceholder": "字体名称,如 Fira Code", - "fontSize": "字号", - "ligatures": "启用连字", - "ligaturesUnavailable": "该字体不含连字", - "wordWrap": "启用自动换行", - "terminalLigaturesHint": "终端连字仅对内置编程字体生效。", - "preview": "预览" - }, - "welcomePanel": { - "sectionTitle": "模式选择区域", - "sectionDescription": "新会话页面输入框上方显示的「代码开发 / 日常办公」快捷卡片区域。", - "showQuickActions": "在新会话页面显示" - }, - "workspaceBackground": { - "sectionTitle": "工作区背景", - "sectionDescription": "在整个工作区背后显示一张图片。侧栏与面板会变半透明并磨砂让图片透出,遮罩保证文字可读。", - "enable": "启用背景图片", - "image": "图片", - "chooseImage": "选择图片", - "replaceImage": "更换图片", - "removeImage": "移除", - "fillMode": "填充方式", - "fillModes": { - "cover": "覆盖", - "contain": "适应", - "center": "居中", - "tile": "平铺" - }, - "maskOpacity": "遮罩不透明度", - "maskOpacityHint": "数值越高,图片越向主题背景色淡化,文字对比越清晰。", - "imageBlur": "图片模糊", - "panelOpacity": "面板不透明度", - "panelOpacityHint": "侧栏、面板与标签栏的不透明程度。越低,透出的图片越多。", - "errorTooLarge": "图片太大(最大 16 MB)。", - "errorUploadFailed": "设置背景图片失败。" - } - }, - "SystemSettings": { - "loading": "加载中...", - "sectionTitle": "系统管理", - "sectionDescription": "管理网络代理、应用升级与语言偏好。", - "proxyTitle": "网络代理", - "proxyDescription": "开启后,后续网络请求将优先走该代理(包括 ACP 对话、Agent 安装、Git 远程操作等)。", - "loadFailed": "加载失败:{message}", - "enableProxy": "启用系统代理", - "proxyAddress": "代理地址", - "proxyHint": "支持 http(s)/socks5,示例:{example}。仅在启用系统代理时生效。", - "save": "保存", - "saving": "保存中...", - "proxyRequired": "启用代理时必须填写代理地址", - "saveSuccess": "系统代理设置已保存", - "saveFailed": "保存失败:{message}", - "languageTitle": "语言", - "languageDescription": "设置应用语言。跟随系统时,若系统语言不受支持将回退为英文。", - "appLanguage": "应用语言", - "languageSaveSuccess": "语言设置已保存", - "languageSaveFailed": "语言设置保存失败:{message}", - "updateTitle": "应用升级", - "versionTitle": "软件更新", - "updateDescription": "点击检查后会从配置的发布源拉取最新版本信息,有新版本时可直接下载并安装。", - "currentVersion": "当前版本", - "upgradableVersion": "最新版本", - "none": "暂无", - "lastChecked": "上次检查:{time}", - "updateError": "更新异常:{message}", - "checking": "检查中...", - "checkUpdate": "检查更新", - "updating": "升级中...", - "downloading": "下载中...", - "upgradeTo": "升级到 v{version}", - "viewRelease": "查看 v{version} 发布", - "foundUpdate": "发现新版本 v{version}", - "alreadyLatest": "当前已经是最新版本", - "checkUpdateFailed": "检查更新失败:{message}", - "installSuccess": "升级包已安装,正在重启应用", - "installFailed": "升级失败:{message}", - "upgradeSuccess": "升级完成,正在重新加载...", - "restartTimeout": "服务未能按时恢复,请检查容器或服务日志。", - "restartingIn": "将在 {seconds} 秒后重启...", - "waitingForServer": "正在等待服务恢复...", - "restartToUpdate": "重启以更新", - "newVersionBadge": "新版本 v{version}", - "updateAvailableTitle": "发现新版本", - "releaseNotesTitle": "更新内容", - "remindLater": "稍后", - "retry": "重试", - "stepDownload": "下载", - "stepInstall": "安装", - "stepRestart": "重启", - "updateReadyHint": "新版本已下载,重启以完成更新。", - "restarting": "正在重启…", - "dockerUpgradeHint": "现在升级的是正在运行的容器。容器一旦被重建即丢失——如需保留,请拉取或构建新版本镜像后重建容器。", - "upgradeRolledBack": "升级失败,服务器已自动回滚到上一版本。", - "serverUnreachable": "无法连接到服务器以开始升级。请确认服务器正在运行后重试。", - "rollbackButton": "回滚", - "rollingBack": "回滚中...", - "rollbackDescription": "恢复到上次升级前安装的版本。", - "rollbackConfirmTitle": "回滚到上一个版本?", - "rollbackConfirmDescription": "服务器将重启并运行上次升级前安装的版本。更新的版本仍可再次安装。", - "rollbackConfirm": "回滚", - "rollbackCancel": "取消", - "rollbackSuccess": "已回滚到上一个版本,正在重新加载……", - "rollbackFailed": "回滚失败,请检查服务器日志。", - "updateErrors": { - "sourceUnavailable": "无法连接更新源,请检查网络或代理设置后重试。", - "network": "网络连接异常,请检查网络或代理设置后重试。", - "downloadFailed": "下载更新包失败,请稍后重试。", - "installFailed": "安装更新失败,请关闭应用后重试。", - "unknown": "更新失败,请稍后重试。" - } - }, - "VersionControlSettings": { - "loading": "加载中...", - "sectionTitle": "版本控制", - "sectionDescription": "配置 Git 可执行文件并管理 GitHub 账号。", - "gitTitle": "Git 配置", - "gitDescription": "配置应用使用的 Git 可执行文件。", - "gitDetected": "已检测到 Git", - "gitNotFound": "未在系统中找到 Git", - "gitVersion": "版本", - "gitPath": "路径", - "customGitPath": "自定义 Git 路径", - "customGitPathPlaceholder": "/usr/bin/git", - "customGitPathHint": "留空则使用自动检测的路径。", - "test": "测试", - "testing": "测试中...", - "testSuccess": "Git 可执行文件有效。", - "testFailed": "Git 测试失败:{message}", - "save": "保存", - "saving": "保存中...", - "saveSuccess": "Git 设置已保存。", - "saveFailed": "保存失败:{message}", - "githubTitle": "GitHub 账号", - "githubDescription": "管理用于身份验证的 GitHub 账号。令牌存储在本地。", - "noAccounts": "暂无 GitHub 账号。", - "addAccount": "添加账号", - "serverUrl": "服务器地址", - "serverUrlPlaceholder": "https://github.com", - "token": "个人访问令牌", - "tokenPlaceholder": "ghp_xxxxxxxxxxxx", - "generateToken": "生成令牌", - "tokenHint": "在 GitHub → Settings → Developer settings → Personal access tokens 中生成令牌。", - "validateAndAdd": "验证并添加", - "validating": "验证中...", - "addSuccess": "账号 {username} 添加成功。", - "addFailed": "添加账号失败:{message}", - "testConnection": "测试", - "connectionSuccess": "连接成功。", - "connectionFailed": "连接失败:{message}", - "setDefault": "设为默认", - "defaultLabel": "默认", - "defaultSet": "默认账号已更新。", - "removeAccount": "删除", - "removeConfirmTitle": "删除账号", - "removeConfirmMessage": "确定要删除账号「{username}」吗?", - "removeConfirm": "删除", - "removeCancel": "取消", - "removeSuccess": "账号已删除。", - "scopes": "权限范围", - "loadFailed": "加载设置失败:{message}", - "gitAccount": { - "sectionTitle": "Git 服务器账号", - "sectionDescription": "管理非 GitHub 的 Git 服务器凭据(GitLab、Bitbucket、自建服务等)。", - "noAccounts": "暂无 Git 服务器账号。", - "addAccount": "添加账号", - "addTitle": "添加 Git 账号", - "addDescription": "输入服务器地址、用户名和密码或访问令牌。", - "serverUrl": "服务器地址", - "serverUrlPlaceholder": "https://gitlab.example.com", - "username": "用户名", - "usernamePlaceholder": "用户名或邮箱", - "password": "密码 / 令牌", - "passwordPlaceholder": "密码或访问令牌", - "passwordHint": "输入服务器的密码或个人访问令牌。", - "add": "添加", - "serverRequired": "请输入服务器地址。", - "usernameRequired": "请输入用户名。", - "passwordRequired": "请输入密码。" - } - }, - "ShortcutSettings": { - "sectionTitle": "快捷键", - "resetDefault": "恢复默认", - "recordInstruction": "点击右侧按钮后按下组合键即可修改。建议使用 Ctrl/Cmd、Alt、Shift 的组合。按 Esc 可取消录制。", - "recording": "按下快捷键...", - "toasts": { - "conflict": "快捷键已被「{title}」占用", - "updated": "快捷键已更新", - "invalid": "快捷键无效,请重试", - "reset": "已恢复默认快捷键" - }, - "actions": { - "toggle_search": { - "title": "打开搜索", - "description": "打开或关闭会话搜索面板" - }, - "toggle_sidebar": { - "title": "切换左侧边栏", - "description": "显示或隐藏会话列表侧边栏" - }, - "toggle_terminal": { - "title": "切换终端", - "description": "显示或隐藏底部终端面板" - }, - "new_terminal_tab": { - "title": "新建终端", - "description": "当最近鼠标活动在终端时新建终端标签" - }, - "close_current_terminal_tab": { - "title": "关闭当前终端", - "description": "当最近鼠标活动在终端时关闭当前终端标签" - }, - "toggle_aux_panel": { - "title": "切换右侧面板", - "description": "显示或隐藏辅助信息面板" - }, - "new_conversation": { - "title": "新建会话", - "description": "在当前文件夹中创建新的对话标签" - }, - "open_folder": { - "title": "打开文件夹", - "description": "打开文件夹选择器并在新窗口中打开" - }, - "open_settings": { - "title": "打开设置", - "description": "打开设置窗口" - }, - "close_current_tab": { - "title": "关闭当前标签", - "description": "关闭当前会话或文件标签" - }, - "close_all_file_tabs": { - "title": "关闭全部文件标签", - "description": "当文件面板处于活动状态时关闭所有打开的文件标签" - }, - "next_tab": { - "title": "下一个标签页", - "description": "切换到下一个会话或文件标签页" - }, - "prev_tab": { - "title": "上一个标签页", - "description": "切换到上一个会话或文件标签页" - }, - "send_message": { - "title": "发送消息", - "description": "在输入框中发送当前消息" - }, - "newline_in_message": { - "title": "消息换行", - "description": "在输入框中插入换行符" - }, - "toggle_custom_style": { - "title": "停用/恢复自定义样式", - "description": "逃生舱:一键关闭全部自定义配色与 CSS,再按一次恢复" - } - } - }, - "SkillsSettings": { - "title": "Skills", - "description": "左侧选择 Skill,右侧默认预览 Markdown,点击编辑后可修改并保存。", - "loadingAgents": "正在加载支持 Skills 的 Agent...", - "emptyNoManageableAgents": "当前没有可管理 Skills 的 Agent。", - "managedTarget": "管理对象", - "selectAgentPlaceholder": "请选择 Agent", - "searchPlaceholder": "搜索名称 / ID / 路径...", - "skillsList": "Skills 列表", - "loadingSkills": "加载 Skills 中...", - "agentNotSupported": "当前 Agent 暂不支持 Skills 管理。", - "emptySkills": "暂无 Skill,可点击“新建 Skill”。", - "newSkillTitle": "新建 Skill", - "skillInfo": "Skill 信息", - "skillIdPlaceholder": "Skill ID(例如:my-skill)", - "skillsDirectoryWithPath": "Skills目录:{path}", - "skillsDirectoryNeedId": "Skills目录:请输入 Skill ID 以生成完整路径", - "markdownContent": "Markdown 内容", - "editingStatus": "编辑中", - "previewStatus": "预览中", - "contentPlaceholder": "输入 Skill 文本内容...", - "metadataTitle": "Skills 元信息", - "onlyYamlMetadata": "该 Skill 仅包含 YAML 元信息。", - "emptyContentHint": "暂无内容。点击“编辑”开始输入。", - "loadingSkill": "正在加载 Skill...", - "emptyNoAgents": "暂无可用 Agent。", - "noSelectionHint": "从左侧选择一个 Skill,或点击“新建 Skill”创建。", - "systemBadge": "系统", - "systemHint": "CLI 内置 Skill · 只读", - "scope": { - "global": "全局", - "folder": "文件夹", - "selectFolderPlaceholder": "选择文件夹", - "noFolders": "未找到任何文件夹", - "pickFolderHint": "选择一个文件夹以查看其 Skills。" - }, - "actions": { - "preview": "预览", - "edit": "编辑", - "openInWindow": "在新窗口打开", - "delete": "删除", - "deleting": "删除中...", - "refresh": "刷新", - "newSkill": "新建 Skill", - "reset": "重置", - "save": "保存", - "saving": "保存中...", - "cancel": "取消" - }, - "deleteDialog": { - "title": "删除 Skill", - "confirm": "确认删除当前 Skill 吗?该操作无法撤销。", - "confirmWithNamePrefix": "确认删除 Skill", - "confirmWithNameSuffix": "吗?该操作无法撤销。" - }, - "toasts": { - "loadFailed": "加载 Skill 失败", - "openFolderFailed": "打开目录失败", - "noSkillDirectory": "当前 Agent 未找到可用的 Skills 目录", - "nameRequired": "Skill 名称不能为空", - "updated": "Skill 已更新", - "created": "Skill 已创建", - "saveFailed": "保存 Skill 失败", - "deleted": "Skill 已删除", - "deleteFailed": "删除 Skill 失败" - }, - "templates": { - "gemini": "---\nname: example-skill\ndescription: Describe when this skill should be used.\n---\n\n# Skill Name\n\nInstructions for the agent when this skill is active.\n\n## Workflow\n\n1. Add actionable step one.\n2. Add actionable step two.\n", - "openCode": "---\nname: example-skill\ndescription: Describe when this skill should be used.\n---\n\n# Purpose\n\nDescribe what this skill helps with.\n\n# Steps\n\n1. Add actionable step one.\n2. Add actionable step two.\n", - "openClaw": "---\nname: example-skill\ndescription: Describe when this skill should be used.\nuser-invocable: true\ndisable-model-invocation: false\n---\n\n# Purpose\n\nDescribe what this skill helps with.\n\n# Instructions\n\n1. Add actionable instruction one.\n2. Add actionable instruction two.\n", - "default": "---\nname: example-skill\ndescription: Describe when this skill should be used.\n---\n\n# Skill: example-skill\n\n## When to use\n\n- Describe trigger conditions.\n\n## Instructions\n\n1. Add actionable instruction one.\n2. Add actionable instruction two.\n" - } - }, - "McpSettings": { - "loading": "加载中...", - "summary": { - "missingCommand": "(缺少 command)", - "missingUrl": "(缺少 url)" - }, - "protocol": { - "stdio": "Stdio" - }, - "errors": { - "selectInstallProtocol": "请选择安装协议", - "fieldRequired": "{field} 为必填项", - "fieldNeedsBoolean": "{field} 需要 true 或 false", - "fieldNeedsNumber": "{field} 需要数字", - "fieldNeedsInteger": "{field} 需要整数", - "fieldInvalidJson": "{field} JSON 无效:{message}", - "fieldOutOfRange": "{field} 的值不在可选范围内", - "jsonEmpty": "{name} 不能为空", - "jsonInvalid": "{name} 不是合法 JSON:{message}", - "jsonMustBeObject": "{name} 必须是 JSON 对象", - "specMustBeObject": "MCP 配置必须是 JSON 对象。", - "missingType": "MCP 配置缺少 type 字段。请填写 stdio、http(别名 streamable-http、streamableHttp)、sse 之一。", - "unsupportedType": "不支持的 MCP type:{type}。支持的类型:stdio、http(别名 streamable-http、streamableHttp)、sse。", - "codexEntryUnsupportedType": "Codex MCP 条目 {id} 的 type 不受支持:{type}。支持的类型:stdio、http(别名 streamable-http、streamableHttp)、sse。", - "unsupportedTransportType": "不支持的 transport 类型:{type}。支持的类型:http(别名 streamable-http、streamableHttp)、sse。", - "stdioCommandRequired": "stdio 类型的 MCP 必须填写非空的 command 字段。", - "remoteUrlRequired": "远端 MCP 必须填写非空的 url 字段。", - "appsRequired": "请至少选择一个目标 App。" - }, - "jsonNames": { - "localConfig": "MCP 配置", - "installConfig": "安装配置" - }, - "toasts": { - "uninstalled": "已卸载 MCP", - "uninstallFailed": "卸载失败:{message}", - "selectAtLeastOneApp": "请至少选择一个目标应用", - "saveSuccess": "保存成功", - "saveFailed": "保存失败:{message}", - "installed": "已安装 {name}", - "installFailed": "安装失败:{message}", - "serverIdRequired": "Server ID 不能为空", - "serverIdExists": "Server ID \"{id}\" 已存在,请编辑现有项或更换名称", - "created": "MCP 已创建" - }, - "installDialog": { - "title": "确认安装 MCP", - "descriptionWithName": "将 {name} 安装到本地配置。", - "description": "选择安装目标应用。", - "protocol": "协议", - "selectProtocol": "选择协议", - "parameters": "配置参数", - "booleanPlaceholder": "请选择 true/false", - "selectOneValue": "选择一个值", - "targetApps": "目标应用" - }, - "actions": { - "cancel": "取消", - "confirmInstall": "确认安装", - "installing": "安装中", - "uninstall": "卸载", - "uninstalling": "卸载中", - "viewDetails": "查看详情", - "save": "保存", - "saving": "保存中", - "install": "安装", - "refresh": "刷新", - "newMcp": "新建 MCP", - "create": "创建", - "creating": "创建中..." - }, - "tabs": { - "local": "本地 MCP", - "market": "MCP 市场" - }, - "local": { - "filterPlaceholder": "筛选本地 MCP...", - "loadFailed": "加载失败:{message}", - "empty": "当前未检测到本地 MCP。", - "description": "本地 MCP 配置可直接编辑并保存。", - "enabledApps": "启用应用", - "configJson": "MCP 配置(JSON)", - "draftTitle": "新建 MCP", - "draftDescription": "填写 Server ID 与配置以创建本地 MCP 服务器。", - "serverIdLabel": "Server ID", - "serverIdPlaceholder": "Server ID(例如:my-mcp)", - "typeHint": "支持类型:stdio、http(别名 streamable-http、streamableHttp)、sse。env 仅适用于 stdio;远端 MCP 请通过 headers 字段传递鉴权 token。", - "envOnRemoteWarning": "检测到远端 MCP 配置中包含 env 字段。env 仅 stdio 类型使用,远端 MCP 应通过 headers 携带鉴权信息,env 字段保存时会被忽略。" - }, - "market": { - "selectMarketplace": "选择市场", - "searchPlaceholder": "搜索 MCP...", - "searchFailed": "搜索失败:{message}", - "loadingList": "加载 MCP 列表...", - "empty": "暂无 MCP 结果。", - "loadingDetail": "加载市场详情...", - "detailLoadFailed": "加载详情失败:{message}", - "owner": "所有者:{owner}", - "namespace": "命名空间:{namespace}", - "defaultInstallProtocol": "默认安装协议", - "currentOptionParameterCount": "当前选项参数数:{count}", - "installConfigDescription": "安装配置(JSON,可修改后安装;修改后将覆盖协议/参数表单)", - "selectLeftToView": "请选择左侧市场 MCP 查看详情。" - }, - "badges": { - "verified": "已验证", - "remote": "远程", - "hasHomepage": "有主页", - "uses": "{count} 次使用", - "deployed": "已部署", - "notDeployed": "未部署" - }, - "selectLeftMcp": "请选择左侧 MCP。" - }, - "AcpAgentSettings": { - "title": "Agent SDK管理", - "description": "统一管理 Agent 的连接SDK、启用状态、环境变量、配置管理与版本预检信息。", - "loadingAgents": "加载 Agent 列表中...", - "agentList": "Agent 列表", - "emptyNoAgent": "暂无可用 Agent。", - "configManagement": "配置管理", - "envVars": "环境变量", - "hostTools": { - "label": "由 Agent 自行处理文件与命令", - "description": "codeg 不再代为提供文件访问和终端命令,改由 Agent 在自己的进程中执行——只有这样它自带的沙箱与权限规则才会生效。同时会关闭向其他 Agent 委托,否则同样的操作又会绕回 codeg 执行。codeg 本身不提供沙箱,因此请仅在 Agent 已配置沙箱时开启。" - }, - "nativeJsonConfig": "原生 JSON 配置", - "modelHintDefault": "留空则使用系统默认模型。", - "generalConfigDescriptionClaude": "支持 API URL、API Key 与 Claude 模型快捷配置,并与原生 JSON 配置联动。", - "generalConfigDescriptionDefault": "支持重要配置输入(API URL、API Key、Model)和原生 JSON 配置管理。", - "multiAgent": { - "title": "多智能体协同", - "description": "允许活跃的智能体把子任务委托给其他智能体。", - "enable": "启用委托", - "enableHint": "关闭后,delegate_to_agent 工具会从智能体的 MCP 工具清单中隐藏。", - "withheldByHostTools": "{agents} 不会拿到委派工具:它们单独开启了「由 Agent 自行处理文件与命令」。", - "selfInitiate": "Allow spawn without @", - "selfInitiateHint": "When on, an agent may start a listed sub-agent on its own. An @ mention is still always honored. When off, only an @ mention starts a sub-agent.", - "depthLimit": "最大委托深度", - "depthHint": "允许范围:{min}–{max}。限制委托链(根 → 子 → 孙 …)的最大递归深度。", - "completedCacheLabel": "已完成结果缓存(MB)", - "completedCacheHint": "运行中委托会话已完成子智能体结果的内存缓存,仅在该会话运行期间保留,会话结束后自动清除。超出此预算时优先从内存中丢弃最旧的结果(仍可在子智能体自己的会话中查看);0 表示不限(会话结束后仍会清除)。", - "save": "保存", - "saving": "保存中…", - "saved": "委托设置已保存", - "saveFailed": "委托设置保存失败", - "loadFailed": "加载委托设置失败:{detail}", - "tabGeneral": "通用", - "tabAgentDefaults": "子智能体配置", - "agentDefaultsDescription": "多智能体协同在为委托调用启动子智能体时使用这些覆盖项。下方选项通过实时探测获取,所选即所用。", - "probing": "正在加载该智能体的可用配置项…", - "probeFailed": "加载配置项失败:{detail}", - "retry": "重试", - "noConfigAvailable": "该智能体没有可配置项。", - "modeLabel": "模式", - "agentDefaultHint": "智能体默认:{value}", - "defaultOptionLabel": "默认({value})" - }, - "actions": { - "dragSort": "拖拽排序", - "dragSortAgent": "拖拽排序 {name}", - "refreshCheck": "刷新检测", - "refreshCheckAgent": "刷新检测 {name}", - "clickEnable": "点击启用 {name}", - "clickDisable": "点击禁用 {name}", - "install": "安装", - "upgrade": "升级", - "uninstall": "卸载", - "uninstalling": "卸载中...", - "saveEnvVars": "保存环境变量", - "saving": "保存中...", - "saveGrokConfig": "保存 Grok 配置", - "saveCodexConfig": "保存 Codex 配置", - "saveGeminiConfig": "保存 Gemini 配置", - "saveOpenCodeConfig": "保存 OpenCode 配置", - "saveOpenClawConfig": "保存 OpenClaw 配置", - "saveConfigManagement": "保存配置管理", - "saveCurrentProvider": "保存当前 Provider", - "showApiKey": "显示 API Key", - "hideApiKey": "隐藏 API Key", - "showKey": "显示 Key", - "hideKey": "隐藏 Key", - "showToken": "显示 Token", - "hideToken": "隐藏 Token", - "cancel": "取消", - "delete": "删除", - "deleting": "删除中...", - "confirmDelete": "确认删除", - "confirmUninstall": "确认卸载", - "saveClineConfig": "保存 Cline 配置", - "saveHermesConfig": "保存 Hermes 配置", - "saveCodeBuddyConfig": "保存 CodeBuddy 配置", - "saveKimiCodeConfig": "保存 Kimi Code 配置", - "customInstall": "自定义安装", - "saveKimiCodeRawConfig": "保存 config.toml", - "saveDeepSeekConfig": "保存 DeepSeek 配置", - "diagnose": "诊断" - }, - "status": { - "enabled": "启用", - "disabled": "禁用", - "unchecked": "未检测", - "agentEnabledAria": "{name} 已启用", - "agentEnabledSwitch": "{name} 启用" - }, - "preflight": { - "count": "预检项:{count}", - "notRun": "尚未执行检测。" - }, - "grok": { - "configDescription": "在此配置 Grok。下方控件——权限模式、推理强度、可选的自定义(自带端点)模型和压缩——会合并写入 ~/.grok/config.toml,并保留你的其他键与注释。登录使用你的 XAI_API_KEY 或 `grok login`。其他键可在“高级”中编辑。", - "permissionModeLabel": "权限模式", - "permissionDefault": "每次询问", - "permissionAcceptEdits": "自动批准编辑", - "permissionAuto": "智能自动批准", - "permissionAlwaysApprove": "始终允许", - "reasoningEffortLabel": "推理级别", - "effortLow": "低(更快)", - "effortMedium": "中(均衡)", - "effortHigh": "高", - "effortXhigh": "最高", - "optionDefault": "使用默认", - "authTitle": "认证", - "authMode": "认证方式", - "authModeApiKey": "XAI API 密钥", - "authModeApiKeyHint": "使用 xAI 控制台的 XAI_API_KEY 认证——适用于非交互/无头运行。保存在该智能体的环境变量中。", - "authModeCustom": "自定义接口", - "authModeCustomHint": "使用自定义接口(BYO 端点):在下方定义一个带有独立 base URL 和 API 密钥的自定义模型,它将成为 Grok 的默认模型。", - "subscriptionHint": "使用 `grok login` 登录(SuperGrok / X Premium+)。不保存 API 密钥。", - "loginHint": "在终端运行以下命令登录,然后重新打开此设置:", - "commandCopied": "命令已复制到剪贴板", - "copyCommand": "复制命令", - "authKeyConfigured": "已配置 XAI_API_KEY。", - "authKeyMissing": "未设置 XAI_API_KEY。", - "advancedToggle": "高级(原始 config.toml)", - "configTomlNative": "config.toml(原生)", - "configTomlHint": "按原样整体写入 ~/.grok/config.toml。非法 TOML 会被拒绝,绝不因笔误截断文件。", - "configTomlPlaceholder": "# 上面控件之外的键,例如\n# [mcp_servers.*]、[cli]、[permission] 规则。", - "customModelTitle": "自定义模型(自带端点)", - "customModelHint": "让 Grok 指向自定义或自托管端点。codeg 会写入按模型的 `[model.*]` 块并将其设为默认模型。清空模型 ID 即可移除。", - "customModelIdLabel": "模型 ID", - "customModelIdPlaceholder": "grok-4.5", - "customModelIdHint": "注册为 `[model.*]` 块,并作为模型名发送给 API;同时设为 `[models].default`。", - "customBaseUrlLabel": "Base URL", - "customBaseUrlPlaceholder": "https://api.x.ai/v1(默认)", - "customApiBackendLabel": "API 后端", - "backendResponses": "Responses", - "backendChatCompletions": "Chat Completions", - "backendMessages": "Messages(Anthropic)", - "customApiKeyLabel": "API Key", - "customApiKeyHint": "内联存储于 `[model.*].api_key`,仅作用于该端点。", - "customContextWindowLabel": "上下文窗口(tokens)", - "customContextWindowHint": "可选。用于自动压缩计时;留空则使用端点默认值。", - "autoCompactLabel": "自动压缩阈值(%)", - "autoCompactHint": "当上下文使用率达到该百分比时压缩对话(Grok 默认 85)。写入 `[session]`。" - }, - "cursor": { - "configDescription": "在此配置 Cursor。先选择认证方式——官网订阅(浏览器登录)或用于无头/服务器的 Cursor API 密钥——然后选择模型并编辑 CLI 的权限规则与沙箱。codeg 会写入 ~/.cursor/cli-config.json,与 cursor-agent CLI 共享。", - "authTitle": "鉴权", - "authChecking": "检测中…", - "authNotInstalled": "cursor-agent 未安装", - "authLoggedIn": "已登录", - "authNotLoggedIn": "未登录", - "loginHint": "在终端运行以下命令登录 Cursor 账号(会打开浏览器),完成后点刷新:", - "apiKeyLabel": "Cursor API 密钥", - "apiKeyPlaceholder": "在 cursor.com/dashboard 获取", - "apiKeyHint": "CURSOR_API_KEY —— Cursor Dashboard 的账号密钥,在无头/服务器环境下替代浏览器登录。不是第三方或 OpenAI 密钥。", - "modelTitle": "默认模型", - "loadModels": "获取模型列表", - "modelsUnavailable": "模型列表不可用", - "modelHint": "会话启动时通过 --model 传给 CLI;保持默认则由 Cursor 自行选择。", - "permissionsTitle": "权限与沙箱", - "permissionsDescription": "可视化编辑 CLI 权限规则(cli-config.json)。允许规则免确认执行;拒绝规则始终拦截。", - "permissionModeLabel": "权限模式", - "permissionModeDefault": "执行前询问(默认)", - "permissionModeForce": "全部放行 Run Everything(--force)", - "permissionModeHint": "Run Everything 以 --force 启动会话:除 deny 规则外的所有工具调用自动放行、不再弹确认(组织策略可能将其降级为仅按 allow 规则放行)。对新会话生效。", - "optionDefault": "默认(未设置)", - "sandboxLabel": "沙箱", - "sandboxEnabled": "启用", - "sandboxDisabled": "禁用", - "allowRulesLabel": "允许规则", - "denyRulesLabel": "拒绝规则", - "addRule": "添加规则", - "rulesSyntaxHint": "规则语法:Shell(命令)、Read(路径/通配)、Write(路径/通配)、WebFetch(域名)、Mcp(服务器:工具)——deny 规则始终优先。", - "saveConfig": "保存配置", - "advancedToggle": "高级:原始 cli-config.json", - "advancedHint": "完整的 ~/.cursor/cli-config.json。此处保存按原文写入;上方结构化控件则以合并方式写入。", - "saveRawConfig": "保存文件", - "authMode": "认证方式", - "subscriptionHint": "使用 Cursor 账号登录,使用 Cursor 的模型。", - "customApiKeyRequired": "需要填写 Cursor API 密钥。", - "authModeApiKey": "Cursor API 密钥(无头/服务器)", - "authModeApiKeyHint": "用 Cursor 官网 Dashboard 生成的账号 API 密钥认证(适用于无头/服务器环境)。这是 Cursor 账号密钥,不是第三方/OpenAI 端点——cursor-agent 只连 Cursor 自己的后端。要使用 codex/OpenAI 兼容端点,请改用 Codex 智能体。", - "modelPickerPlaceholder": "搜索模型…", - "modelNoMatch": "没有匹配的模型", - "modelsNeedAuth": "登录后加载模型列表。", - "modelDefaultBadge": "默认" - }, - "deepseek": { - "configManagement": "DeepSeek Harness 配置", - "configDescription": "端点与密钥是 deepseek-acp 启动时读取的环境变量。模型和推理档位是会话级选择器,在输入框里切换。", - "baseUrlLabel": "API 端点", - "baseUrlHint": "留空则使用官方端点。保存后对新建的会话生效——正在进行的会话需要重新连接才会切换。", - "baseUrlInvalid": "请填写完整的 http(s) 地址且不带查询参数,例如 https://api.deepseek.com", - "apiKeyLabel": "API 密钥", - "apiKeyHint": "以 DEEPSEEK_API_KEY 传给智能体。环境变量的优先级高于凭据文件,因此若用终端登录,这里留空即可。" - }, - "codex": { - "configDescription": "支持 API URL、API Key、模型名称、Reasoning Effort 快捷配置,并与 `auth.json` / `config.toml` 双向联动。", - "authMode": "认证方式", - "chatgptSubscription": "官网订阅", - "chatgptSubscriptionHint": "使用 ChatGPT 官网订阅登录,无需配置 API Key", - "apiKeyHint": "使用 API Key 连接 OpenAI 或兼容的 API 服务", - "selectProvider": "选择 Provider", - "modelName": "模型名称", - "selectReasoningEffort": "选择 Reasoning Effort", - "enableWebsocket": "启用 WebSocket", - "enableWebsocketAria": "Codex Provider 启用 WebSocket", - "enableSkills": "启用 Skills", - "enableSkillsAria": "Codex 启用 Skills", - "enableFast": "启用 Fast", - "enableFastAria": "Codex 启用 Fast 服务等级", - "sandboxGroupTitle": "沙箱与审批", - "sandboxGroupHint": "写入全局 ~/.codex/config.toml,codex CLI 与 IDE 的会话同样生效。这是线程默认值,只作用于 codex 自行发起的回合(/goal、/review、/compact);普通对话使用输入框里的审批预设。改动需重开会话才生效。", - "sandboxShadowedWarning": "config.toml 里设置了 default_permissions,codex 会改走权限配置档并完全忽略 sandbox_mode。删掉 default_permissions 后下面的选项才会生效。", - "sandboxPermissionsTableWarning": "config.toml 定义了 [permissions] 配置档却没有 default_permissions,codex 会拒绝启动。请在下方原始编辑器里补上。", - "approvalPolicyLabel": "审批策略", - "approvalPolicyUnset": "未设置(codex 默认:按需询问)", - "approvalPolicy_on-request": "按需询问 — 由模型决定何时请求批准", - "approvalPolicy_untrusted": "仅信任只读 — 只有已知安全的只读命令免批准", - "approvalPolicy_never": "从不询问 — 完全不弹审批", - "approvalPolicy_granular": "精细控制 — 按提示类型分别设置", - "approvalPolicyUntrustedAcpWarning": "ACP 适配器只有三种审批预设,untrusted 无对应项,codeg 会话会退回「按需询问」——此时由模型自行决定何时询问,沙箱本就允许的命令不再询问。请改用下方的沙箱模式收紧。", - "granularHint": "关闭表示该类请求被自动拒绝,而不是弹给你确认。", - "granular_sandbox_approval": "Shell 命令越权申请", - "granular_rules": "Execpolicy 规则提示", - "granular_skill_approval": "技能脚本执行提示", - "granular_request_permissions": "request_permissions 工具提示", - "granular_mcp_elicitations": "MCP elicitation 提示", - "sandboxModeLabel": "沙箱模式", - "sandboxModeUnset": "未设置(受信任的文件夹回落为可写工作区)", - "sandboxMode_read-only": "只读", - "sandboxMode_workspace-write": "可写工作区", - "sandboxMode_danger-full-access": "完全放开(无沙箱)", - "sandboxModeHint": "在 Windows 上,未开启 codex 的实验性 Windows 沙箱时,可写工作区会被降级为只读。", - "sandboxModeSeedsPresetHint": "codeg 还会用它推导会话的初始审批预设,因此与审批策略不同,它对普通提问同样生效。输入框中选择的预设仍会覆盖它。", - "writableRootsLabel": "额外可写目录", - "writableRootsHint": "每行一个绝对路径,作为工作目录之外的额外可写位置。", - "sandboxRootsRelativeError": "必须是绝对路径 — codex 会把相对路径解析到 ~/.codex 下:{path}", - "networkAccessLabel": "允许网络访问", - "excludeTmpdirLabel": "从可写目录中排除 TMPDIR", - "excludeSlashTmpLabel": "从可写目录中排除 /tmp", - "authJsonNative": "auth.json(原生)", - "configTomlNative": "config.toml(原生)", - "loginButton": "使用 ChatGPT 登录", - "loginRequesting": "正在请求登录码...", - "loginStep1": "在浏览器中打开以下链接:", - "loginStep2": "输入以下代码:", - "loginPolling": "等待授权中...", - "loginCancel": "取消", - "loginSuccess": "登录成功,配置已保存!", - "loginFailed": "登录失败:{message}", - "loginRetry": "重试", - "loginCodeCopied": "已复制代码", - "loggedIn": "账号已登录", - "loginRelogin": "重新登录 / 切换账号", - "loginTimeout": "登录超时,请重试", - "loginSaveFailed": "登录成功但配置保存失败" - }, - "gemini": { - "authConfig": "Gemini 认证配置", - "authConfigDescription": "对齐 Gemini CLI 认证文档,支持自定义、Google 登录、Gemini API Key、Vertex AI(ADC / 服务账号 / API Key)。", - "authMode": "认证方式", - "selectAuthMode": "选择认证方式", - "viewAuthDoc": "查看认证文档", - "mode": { - "custom": "自定义接口", - "loginGoogle": "Google 登录(OAuth)", - "vertexServiceAccount": "Vertex AI(服务账号)" - }, - "hint": { - "custom": "填写 API URL、API Key 和 Model,分别映射到 GOOGLE_GEMINI_BASE_URL / GEMINI_API_KEY / GEMINI_MODEL。", - "loginGoogle": "首次在终端运行 gemini 并完成 Google 登录;无需填写 API Key。", - "geminiApiKey": "使用 Gemini API 时填写 GEMINI_API_KEY。", - "vertexAdc": "使用 gcloud ADC,建议填写 GOOGLE_CLOUD_PROJECT 与 GOOGLE_CLOUD_LOCATION。", - "vertexServiceAccount": "服务账号 JSON 路径写入 GOOGLE_APPLICATION_CREDENTIALS。", - "vertexApiKey": "使用 Vertex AI API key 时填写 GOOGLE_API_KEY。" - } - }, - "openCode": { - "configManagement": "OpenCode 配置管理", - "configDescription": "对齐 OpenCode `provider` 配置结构,支持多供应商管理,并与原生 JSON 文件双向联动。", - "providerManagement": "Provider 管理", - "providerCount": "共 {count} 个", - "addProvider": "新增 Provider", - "emptyProvider": "还没有自定义 Provider。点击「添加自定义 Provider」创建。", - "providerEnabledState": "{providerId} 启用状态", - "selectProviderNpm": "选择 provider.npm", - "modelManagement": "模型管理", - "modelCount": "共 {count} 个", - "modelDescription": "对齐 OpenCode `provider.models` 结构。当前支持 `name` / `id` 快速管理;其它高级字段会保留,可在下方原生 JSON 中继续编辑。", - "addModel": "添加模型", - "emptyModel": "暂无模型,输入 model id 后点击“添加模型”创建。", - "modelId": "模型 ID", - "modelName": "模型名称", - "deleteModel": "删除模型 {modelId}", - "nativeJsonConfig": "OpenCode 原生 JSON 配置", - "mainModel": "主模型", - "smallModel": "小模型", - "noMatchingModels": "没有匹配的模型", - "connectProvider": "连接 Provider", - "connectedProviders": "已连接的 Provider", - "noConnectedProviders": "还没有从目录连接 Provider。", - "advancedProviderConfig": "自定义 Provider", - "customProviderConfigHint": "你自己定义的 OpenAI 兼容端点——opencode.json 里的一个 provider 配置块,API key 存在 auth.json。", - "addCustomProvider": "添加自定义 Provider", - "disconnect": "断开", - "editConfig": "编辑", - "customBadge": "自定义", - "authKindApi": "API Key", - "authKindOauth": "OAuth", - "authKindNone": "无凭证", - "connect": { - "title": "连接 Provider", - "description": "从 models.dev 目录选择一个 Provider。凭证保存到 OpenCode 的 auth.json 文件。", - "pick": "Provider", - "search": "搜索 Provider…", - "loading": "正在加载目录…", - "catalogLabel": "models.dev 目录", - "modelsAvailable": "{count} 个可用模型", - "getKey": "获取 API Key", - "oauthApiKeyNote": "该 Provider 也支持通过 opencode auth login 浏览器登录。浏览器登录即将推出——目前请粘贴 API Key。", - "apiKey": "API Key", - "apiKeyHint": "保存在 auth.json,绝不写入 opencode.json。", - "baseUrlOptional": "Base URL 覆盖(可选)", - "providerId": "Provider ID", - "displayName": "显示名称", - "modelsList": "模型(每行一个)", - "modelsHint": "端点接受的模型 ID。", - "action": "连接", - "editTitle": "编辑 Provider", - "editDescription": "更新该 Provider 的 API Key 或 Base URL。", - "saveAction": "保存" - }, - "customProvider": { - "title": "添加自定义 Provider", - "description": "定义一个 OpenAI 兼容端点。API key 保存到 auth.json;provider 配置块写入 opencode.json。", - "action": "添加 Provider", - "idInCatalog": "{providerId} 是已知 Provider,请改用「连接 Provider」连接。" - }, - "refreshCatalog": "刷新目录", - "reasoningBadge": "推理", - "contextWindow": "上下文窗口", - "permissions": { - "title": "权限", - "description": "决定哪些操作直接运行、先征求你的同意,还是被阻止。写入 opencode.json 的 permission 配置,点击下方保存后生效。", - "docsLink": "权限文档", - "unparsableConfig": "下方的原生 JSON 当前无法解析,可视化编辑已暂停。修复 JSON 后即可继续。", - "invalidBlock": "permission 配置的结构无法识别。请在下方原生 JSON 中修改,或点击「恢复默认」重来。", - "orderingUnsafe": "通配规则写在了具体工具之后,OpenCode 会把它一并应用到这些工具上——下方各行显示的并非实际生效的规则。「修正顺序」只把通配规则移回各自作用域的最前面,不改动任何取值。", - "orderingUnsafeManual": "有规则被后面更宽泛的模式遮蔽,OpenCode 永远不会应用它——下方各行显示的并非实际生效的规则。两个互相重叠的模式没有唯一正确的顺序,请在下方原生 JSON 中调整,把更宽泛的写在前面。", - "fixOrder": "修正顺序", - "agentOverrides": "以下智能体单独覆盖了权限,且在最后应用,因此会盖过此处的全部设置:{agents}。请在下方原生 JSON 中修改,或开启「自动接受所有权限」将其清除。", - "legacyTools": "顶层的旧版 tools 配置禁用了某个工具。OpenCode 会把它并入权限,因此它会叠加在此处显示的全部设置之上。请在下方原生 JSON 中修改,或开启「自动接受所有权限」将其清除。", - "autoAcceptTitle": "自动接受所有权限", - "autoAcceptHint": "所有工具调用(shell 命令、文件修改、访问项目外路径)都不再询问,直接执行。开启后会用一条全局允许规则替换下方的逐工具设置,并清除各智能体单独的权限覆盖与旧版 tools 开关——否则它们仍会拦截。", - "globalLabel": "全局默认", - "globalHint": "即 * 规则:下方工具未单独覆盖时采用的动作。", - "actionUnset": "未设置(OpenCode 默认)", - "actionInherit": "跟随默认({action})", - "actionAllow": "允许", - "actionAsk": "询问", - "actionDeny": "拒绝", - "perToolTitle": "逐工具权限", - "reset": "恢复默认", - "ruleCount": "细则 {count} 条", - "rulesToggle": "{tool} 的细粒度规则", - "rulesHint": "按工具输入匹配,最后匹配的规则优先,因此请把宽泛的模式写在前面。* 匹配任意多个字符,? 精确匹配一个字符,开头的 ~ 展开为主目录。", - "noRules": "暂无细粒度规则。", - "addRule": "添加规则", - "deleteRule": "删除规则 {pattern}", - "duplicateRule": "该模式已存在。", - "blankRule": "规则必须有模式;如需删除请点击垃圾桶图标。", - "customKeys": "文件中的其他权限键", - "customKeyHint": "并非 OpenCode 内置工具,将按原样保留。", - "keys": { - "bash": "运行 shell 命令,按解析后的命令匹配", - "edit": "所有文件修改:edit、write 与 patch", - "read": "读取文件,按文件路径匹配", - "external_directory": "访问项目工作目录之外的路径", - "task": "启动子代理,按子代理类型匹配", - "skill": "加载技能,按技能名称匹配", - "glob": "查找文件,按通配模式匹配", - "grep": "搜索文件内容,按模式匹配", - "list": "列出目录内容", - "webfetch": "获取 URL", - "websearch": "网页搜索", - "lsp": "运行 LSP 查询", - "todowrite": "写入待办列表", - "question": "向你提问", - "doom_loop": "同一调用以相同输入重复 3 次时触发" - } - } - }, - "openClaw": { - "gatewayConfig": "Gateway 配置", - "gatewayDescription": "配置 OpenClaw Gateway 连接信息。支持本地或远程 Gateway。", - "gatewayUrlHint": "留空则使用 openclaw 本地配置的 gateway.remote.url。", - "gatewayTokenPlaceholder": "Gateway 认证 Token", - "gatewayTokenHint": "建议使用 token-file 替代明文 Token,可通过 openclaw 命令行配置。", - "sessionKeyHint": "可选。指定 Gateway Session Key,留空则自动分配隔离会话。" - }, - "hermes": { - "configManagement": "Hermes 配置", - "configDescription": "Hermes 在 ~/.hermes/.env 中管理自己的凭据,在 ~/.hermes/config.yaml 中管理设置。选择一个供应商,然后设置 API 密钥和模型——codeg 会替你写入这两个文件。", - "providerLabel": "供应商", - "providerHint": "供应商决定 Hermes 使用哪个 API 密钥变量和 model.provider。OAuth 供应商通过下方的终端设置进行配置。", - "groupApiKey": "API 密钥提供商", - "groupOauth": "OAuth 提供商", - "groupAws": "AWS", - "apiKeyHint": "保存到 ~/.hermes/.env。它绝不会被注入进程——Hermes 会从自己的配置中读取它。", - "modelName": "模型", - "oauthHint": "此供应商使用 OAuth。请运行下方的设置流程,在终端中完成认证。", - "awsHint": "Bedrock 使用你的 AWS 凭据(环境变量或共享配置)。请在上方填写模型 ID,并在系统环境中配置 AWS 访问权限。", - "unsupportedProvider": "该提供商无法通过结构化字段编辑。请使用下方的 config.yaml 原始编辑器或终端引导设置。", - "setupTitle": "自管理设置", - "setupHint": "Hermes 的交互式设置需要终端。可在下方启动,或复制命令自行运行。", - "runSetup": "运行 Hermes 设置", - "configureModel": "配置模型", - "openConfigFolder": "打开 ~/.hermes", - "copyCommand": "复制命令", - "commandCopied": "命令已复制到剪贴板", - "advancedTitle": "高级:编辑 config.yaml", - "rawConfigHint": "直接编辑 ~/.hermes/config.yaml。在此保存将原样覆盖该文件。", - "saveRawConfig": "保存 config.yaml" - }, - "codebuddy": { - "configManagement": "CodeBuddy 配置", - "configDescription": "CodeBuddy 使用 API Key 进行认证。中国版还必须将环境设为“中国版(internal)”;iOA 版使用“iOA”;海外版则不设置。", - "apiKeyLabel": "API Key", - "apiKeyHint": "将作为该智能体的 CODEBUDDY_API_KEY 保存。也可以在终端用 CodeBuddy CLI 登录。", - "apiKeyHintSelfHosted": "将作为该智能体的 CODEBUDDY_API_KEY 保存。请使用你的私有化部署签发的密钥。", - "environmentLabel": "环境", - "environmentHint": "设置 CODEBUDDY_INTERNET_ENVIRONMENT。中国大陆必须使用“中国版(internal)”;海外版则不设置。", - "envOverseas": "海外版(默认)", - "envChina": "中国版(internal)", - "envIoa": "iOA", - "envSelfHosted": "私有化部署", - "baseUrlLabel": "私有化部署地址", - "baseUrlPlaceholder": "https://codebuddy.your-company.com", - "baseUrlHint": "保存为 CODEBUDDY_BASE_URL,将 CodeBuddy 指向你的私有端点。私有化部署不设置网络环境(CODEBUDDY_INTERNET_ENVIRONMENT)。", - "baseUrlInvalid": "请输入合法的 http(s) 地址。", - "loginHint": "没有 API Key?也可以在终端运行 “codebuddy” 用腾讯云账号登录。" - }, - "kimiCode": { - "configManagement": "Kimi Code 配置", - "configDescription": "`kimi acp` 只认已存储的登录令牌,所以 codeg 会在 ~/.kimi-code/config.toml 写入受管供应商,并在本地播种一个门控令牌——推理仍然走你自己的 Key。", - "statusUnconfigured": "尚未配置", - "statusDirty": "有未保存的修改", - "summaryLabel": "生效配置", - "gateReadyApiKey": "API Key 已写入 config.toml", - "gateReadyLogin": "已通过 Kimi 账号登录", - "revealConfig": "在文件夹中显示", - "envOverrideWarning": "检测到 {keys},其优先级高于 config.toml。在此保存会自动清除它。", - "authModeLabel": "鉴权方式", - "authModeApiKey": "API Key", - "authModeLogin": "Kimi 账号登录(订阅)", - "authModeApiKeyHint": "在 config.toml 写入受管供应商,并播种门控令牌以便会话能够打开。", - "loginHint": "在终端运行 `kimi login`,用 Kimi 订阅账号登录。codeg 不存储任何凭据,复用 Kimi 自己的登录。在此保存会移除 codeg 的 API Key 门控令牌。", - "credentialTitle": "凭据", - "interfaceTypeLabel": "供应商类型", - "interfaceTypeHint": "Kimi 使用的供应商协议(config.toml 的 `type`)。Moonshot / platform.kimi.com 的 Key 请选「Kimi / Moonshot」。", - "endpointLabel": "接入点", - "endpointCustom": "自定义(OpenAI 兼容)", - "endpointHint": "国际 = api.moonshot.ai;中国(platform.kimi.com 的 Key)= api.moonshot.cn。自定义可指向任意 OpenAI 兼容端点。", - "regionInternational": "国际(api.moonshot.ai)", - "regionChina": "中国(api.moonshot.cn)", - "baseUrlLabel": "Base URL", - "baseUrlHint": "留空则使用供应商 SDK 默认值。", - "apiKeyLabel": "API Key", - "apiKeyHint": "写入 ~/.kimi-code/config.toml 并用于推理。来自 platform.kimi.com 或 platform.kimi.ai。", - "vertexProjectLabel": "GCP 项目(GOOGLE_CLOUD_PROJECT)", - "vertexLocationLabel": "GCP 区域(GOOGLE_CLOUD_LOCATION)", - "vertexHint": "Vertex AI 使用 Google 应用默认凭据——运行 `gcloud auth application-default login`(无需 API Key)。", - "modelTitle": "模型", - "modelLabel": "模型", - "modelHint": "写入 config.toml 的模型 id。点「测试并获取模型」可查看你的 Key 实际能访问哪些模型。", - "maxContextLabel": "最大上下文长度", - "maxContextHint": "Kimi 的配置 schema 要求必填:缺失会让 Kimi 丢弃整个模型块,导致每次对话都没有回复。默认 262144。", - "fetchModels": "测试并获取模型", - "fetchModelsOk": "Key 可用——共 {count} 个模型", - "fetchModelsEmpty": "Key 可用,但未返回任何模型", - "fetchModelsFailed": "测试失败", - "fetchModelsNeedsKey": "请先填写 API Key 和接入点", - "modelNotInList": "该模型不在你的 Key 可访问列表中,Kimi 会报「模型不存在」。", - "reasoningTitle": "推理", - "reasoningEnableLabel": "启用", - "reasoningDescription": "只有当模型声明了推理能力,Kimi 才会在输入框显示「Thinking」选择器,所以这里由 codeg 写入该声明。对新建会话生效。", - "effortsLabel": "可选档位", - "effortsHint": "这些会成为输入框「Thinking」选择器里的档位。Kimi 会把档位原样透传给供应商,请选你的模型能接受的值。", - "effortsEmptyHint": "一个档位都不选时,输入框只会退化成 Off / On 两档开关。", - "effortsCustomPlaceholder": "添加其它档位", - "effortsAdd": "添加", - "defaultEffortLabel": "默认档位", - "defaultEffortAuto": "由 Kimi 决定", - "alwaysThinkingLabel": "模型始终推理——从选择器中去掉 Off 档", - "fixErrorsFirst": "请先修正标红的字段", - "errorModelRequired": "模型为必填项", - "errorMaxContextRequired": "最大上下文长度为必填项", - "errorMaxContextInvalid": "必须是正整数", - "errorApiKeyRequired": "API Key 为必填项", - "errorApiKeyInvalid": "API Key 不能包含换行", - "errorBaseUrlRequired": "Base URL 为必填项", - "errorBaseUrlInvalid": "必须以 http:// 或 https:// 开头", - "errorVertexProjectRequired": "GCP 项目为必填项", - "errorDefaultEffortUnlisted": "必须是上面已选中的档位之一", - "advancedTitle": "高级", - "authTypeLabel": "凭据写入位置", - "authTypeApiKey": "内联 api_key", - "authTypeEnv": "供应商 env 子表", - "authTypeHint": "API Key 在 config.toml 中的写入位置。", - "rawEditorLabel": "直接编辑 config.toml", - "rawEditorWarning": "在此保存会按原文覆盖整个文件,替换掉上方的结构化配置。", - "rawEditorPlaceholder": "[providers.codeg]\ntype = \"kimi\"\nbase_url = \"https://api.moonshot.cn/v1\"\napi_key = \"sk-...\"" - }, - "authModeOfficialSubscription": "官网订阅", - "authModeCustomEndpoint": "自定义接口", - "authModeCustomEndpointHint": "手动配置 API URL 和 API Key 连接自定义接口。", - "authModeModelProvider": "模型供应商", - "modelProvider": "模型供应商", - "modelProviderHint": "使用已配置的模型供应商的 API URL、API Key 和模型。", - "selectModelProvider": "选择模型供应商", - "noModelProviderAvailable": "该代理未配置模型供应商。请前往模型供应商设置添加。", - "claude": { - "authMode": "认证方式", - "officialSubscription": "官方订阅", - "officialSubscriptionHint": "使用 Anthropic 官方订阅,无需 API Key。", - "mainModel": "主模型", - "reasoningModel": "推理模型(thinking)", - "haikuDefaultModel": "Haiku 默认模型", - "sonnetDefaultModel": "Sonnet 默认模型", - "opusDefaultModel": "Opus 默认模型", - "customModelOption": "自定义模型 ID", - "customModelOptionName": "自定义模型名称", - "customModelOptionDescription": "自定义模型描述", - "customModelOptionHint": "在 Claude 模型选择器中追加一个自定义条目(例如经自定义网关/代理提供的模型)。名称与描述为可选的显示信息。", - "effortLevel": "推理级别", - "effortLevelDefault": "默认级别", - "effortLevel_low": "低", - "effortLevel_medium": "中", - "effortLevel_high": "高", - "effortLevel_xhigh": "超高", - "sendAttributionHeader": "向接口发送归属/计费标识", - "sendAttributionHeaderAria": "向接口发送 Claude Code 归属/计费标识", - "disableNonessentialTraffic": "禁用遥测或多余的网络请求", - "disableNonessentialTrafficAria": "禁用 Claude Code 遥测或多余的网络请求" - }, - "dialogs": { - "confirmDeleteProvider": "确认删除 Provider {providerId}?", - "confirmDeleteProviderDescription": "将同步更新 OpenCode 配置与认证 JSON 文件,删除后不可恢复。", - "confirmUninstall": "确认卸载 {name}?", - "confirmUninstallDescription": "这会移除本地安装版本,之后可随时重新安装。", - "customInstallTitle": "自定义安装 {name}", - "customInstallDescription": "输入要安装的版本号。将重新安装并替换当前已安装的版本。", - "customInstallVersionLabel": "版本号", - "customInstallInvalid": "请输入有效的版本号,例如 1.2.3。", - "customInstallSubmit": "安装" - }, - "errors": { - "windowsFileLocked": "{name} 的程序文件正被运行中的会话占用,Windows 下无法替换。请先关闭所有 {name} 会话后重试。", - "nativeJsonMustBeObject": "原生 JSON 配置必须是对象", - "nativeJsonInvalid": "原生 JSON 配置格式错误:{message}", - "openCodeAuthMustBeObject": "OpenCode auth.json 必须是 JSON 对象", - "openCodeAuthInvalid": "OpenCode auth.json 格式错误:{message}", - "authMustBeObject": "auth.json 必须是 JSON 对象", - "authInvalid": "auth.json 格式错误:{message}", - "providerIdPattern": "Provider ID 仅支持字母、数字、下划线、点与中划线", - "providerExists": "Provider {providerId} 已存在", - "modelIdPattern": "模型 ID 仅支持字母、数字、下划线、点、冒号与中划线", - "modelExists": "Model {modelId} 已存在" - }, - "warnings": { - "nativeJsonRecoveredStructured": "原生 JSON 配置格式无效,已重置为结构化配置", - "nativeJsonRecoveredOpenCode": "原生 JSON 配置格式无效,已重置为 OpenCode 结构化配置", - "openCodeAuthRecovered": "OpenCode auth.json 格式无效,已重置为默认配置", - "authRecoveredStructured": "auth.json 格式无效,已重置为结构化配置" - }, - "toasts": { - "agentActionCompleted": "{name}{action}完成", - "agentActionFailed": "{name}{action}失败", - "localVersion": "本地版本:{version}", - "installCompletedVersionLater": "安装完成,版本将在下一次检测时更新", - "uninstallCompleted": "{name}卸载完成", - "uninstallFailed": "{name}卸载失败", - "localVersionRemoved": "本地版本已移除", - "saveAgentOrderFailed": "保存 Agent 排序失败", - "saveAgentSwitchFailed": "保存 Agent 开关失败", - "saveEnvFailed": "保存环境变量失败", - "grokSaved": "Grok 配置已保存", - "saveGrokNativeFailed": "保存 Grok 原生配置失败", - "saveGrokApiKeyFailed": "设置已保存,但 API Key 未能保存", - "cursorSaved": "Cursor 配置已保存", - "saveCursorConfigFailed": "保存 Cursor 配置失败", - "codexSaved": "Codex 配置已保存", - "saveCodexNativeFailed": "保存 Codex 原生配置失败", - "geminiSaved": "Gemini 配置已保存", - "saveGeminiFailed": "保存 Gemini 配置失败", - "providerDeleted": "Provider {providerId} 已删除", - "providerDeleteFailed": "删除 Provider {providerId} 失败", - "providerSaved": "Provider {providerId} 保存成功", - "saveProviderFailed": "保存 Provider {providerId} 失败", - "openCodeConfigSynced": "OpenCode 配置与认证 JSON 已同步保存。", - "openCodeSaved": "OpenCode 配置已保存", - "saveOpenCodeFailed": "保存 OpenCode 配置失败", - "openClawSaved": "OpenClaw 配置已保存", - "saveOpenClawFailed": "保存 OpenClaw 配置失败", - "configSaved": "配置已保存", - "configSavedHint": "已有会话需要重新打开才能生效", - "saveConfigManagementFailed": "保存配置管理失败", - "clineSaved": "Cline 配置已保存", - "saveClineFailed": "保存 Cline 配置失败", - "hermesSaved": "Hermes 配置已保存", - "saveHermesFailed": "保存 Hermes 配置失败", - "codeBuddySaved": "CodeBuddy 配置已保存", - "saveCodeBuddyFailed": "保存 CodeBuddy 配置失败", - "kimiCodeSaved": "Kimi Code 配置已保存", - "saveKimiCodeFailed": "保存 Kimi Code 配置失败", - "deepseekSaved": "DeepSeek 配置已保存", - "saveDeepSeekFailed": "保存 DeepSeek 配置失败", - "modelProviderRequired": "请先选择一个模型供应商再保存。", - "affectedRunningSessions": "{count} 个进行中的会话需重连以应用更改", - "providerConnected": "已连接 {providerId}", - "connectFailed": "连接 {providerId} 失败", - "providerDisconnected": "已断开 {providerId}", - "disconnectFailed": "断开 {providerId} 失败", - "catalogRefreshed": "目录已刷新——{count} 个 provider", - "catalogRefreshFailed": "刷新目录失败", - "piSaved": "Pi 配置已保存", - "savePiFailed": "保存 Pi 配置失败", - "piRuntimeSaved": "Pi 运行时已保存", - "savePiRuntimeFailed": "保存 Pi 运行时失败", - "piBinaryInstalled": "pi 已安装", - "piBinaryInstallFailed": "pi 安装失败", - "piBinaryUninstalled": "pi 已卸载", - "piBinaryUninstallFailed": "pi 卸载失败", - "savePiTrustFailed": "保存工作区信任失败" - }, - "version": { - "statusLabel": "版本状态", - "notInstalled": "未安装", - "remoteLocal": "远程:{remoteVersion} · 本地:{localVersion}", - "localOnly": "本地:{localVersion}", - "localInstalled": "{versionText}。已安装。", - "platformUnsupported": "{versionText}。当前平台不支持该 Agent。", - "uvxNotReady": "{versionText}。uv 运行时未安装——请在下方 uv 预检项中安装后再使用该 Agent。", - "clickInstall": "{versionText}。请点击右侧安装。", - "localUnrecognized": "{versionText}。本地版本无法识别,可尝试升级覆盖安装。", - "upgradeAvailable": "{versionText}。发现可升级版本。", - "remoteUnavailable": "{versionText}。远程版本暂不可用。", - "latest": "{versionText}。已是最新版本。" - }, - "adapter": { - "label": "ACP 适配器", - "badge": "ACP 适配器", - "badgeHint": "Codeg 为该智能体安装的是 ACP 适配器包,而不是厂商 CLI —— 两者互相独立,配置共享。", - "learnMore": "了解详情", - "missingWithNative": "已检测到你本地的 {nativeLabel}:{nativePath}。Codeg 通过 ACP 协议驱动智能体,而该 CLI 本身不支持 ACP,所以 Codeg 需要单独的适配器包 {adapterPackage}(由 Agent Client Protocol 项目维护,最初由 Zed 团队发起)。它自带运行时,不会修改或替换你的 {nativeCmd} 命令,读取的也是同一个 {configDir} —— 已有的登录和配置直接沿用。点击下方安装即可。", - "missing": "Codeg 通过 ACP 协议驱动智能体,而 {nativeLabel} 本身不支持 ACP,所以 Codeg 需要单独的适配器包 {adapterPackage}(由 Agent Client Protocol 项目维护,最初由 Zed 团队发起)。它自带运行时,因此不必先装 {nativeCmd} CLI;如果你已经装了,两者可以共存,并共用 {configDir} 里的登录和配置。点击下方安装即可。", - "readyWithNative": "适配器 {adapterCmd} 已安装 —— Codeg 启动的是它,而不是你本地的 {nativeCmd}({nativePath})。两者是各自独立的包,可以共存,且都读取 {configDir},登录和配置共享。", - "ready": "适配器 {adapterCmd} 已安装 —— Codeg 启动的就是它。它自带运行时,所以不需要另外安装 {nativeLabel};即便以后你装了,两者也能共存并共用 {configDir}。" - }, - "cline": { - "configDescription": "配置 Cline API 提供商和凭证。设置将保存到 ~/.cline/data/。" - }, - "opencodePlugins": { - "title": "OpenCode 插件", - "declared": "已声明的插件", - "noPlugins": "opencode.json 中未声明任何插件", - "status": { - "installed": "已安装", - "missing": "未安装" - }, - "installAll": "安装全部缺失插件", - "pinVersions": "固定 @latest 版本", - "install": "安装", - "uninstall": "卸载", - "refresh": "刷新", - "success": "所有插件安装成功", - "failed": "插件操作失败" - }, - "pi": { - "configManagement": "Pi 配置", - "configDescription": "Pi 通过模型提供方的 API Key 鉴权。Key 写入 ~/.pi/agent/auth.json,模型选择写入 settings.json。", - "providerLabel": "提供方", - "modelLabel": "模型", - "thinkingLabel": "思考", - "thinking": { - "off": "关闭", - "low": "低", - "medium": "中", - "high": "高", - "minimal": "极低", - "xhigh": "极高" - }, - "apiKeyLabel": "API Key", - "apiKeyHint": "为所选提供方写入 ~/.pi/agent/auth.json。", - "apiKeySetPlaceholder": "•••••• (已保存,留空则保持不变)", - "saveConfig": "保存 Pi 配置", - "providerModelRequired": "提供方和模型为必填", - "runtimeTitle": "运行时", - "runtimeDescription": "选择运行哪个 pi。使用默认,或指向你自己的 pi 构建。", - "modeDefault": "默认 pi", - "modeDefaultHint": "使用内置 pi-acp 适配器拉起 PATH 上的 pi。 安装 pi:npm install -g @earendil-works/pi-coding-agent", - "modeCustom": "自定义 pi", - "modeCustomHint": "运行你自己的 pi 构建、安装或包装脚本。", - "commandLabel": "pi 命令或路径", - "commandHint": "绝对路径、PATH 上的命令名,或包装脚本(如 monorepo 的 ./pi-test.sh)。", - "commandNotFound": "未找到命令", - "validate": "验证", - "advanced": "高级", - "configDirLabel": "配置目录 (PI_CODING_AGENT_DIR)", - "sessionDirLabel": "会话目录 (PI_CODING_AGENT_SESSION_DIR)", - "flagsHint": "pi-acp 不转发自定义 pi 参数(--approve、-e 等)——用脚本包装 pi 并将命令指向它。", - "customIncomplete": "请输入 pi 命令以保存", - "saveRuntime": "保存运行时", - "providerPlaceholder": "选择提供方", - "customProvider": "自定义提供方…", - "providerIdLabel": "提供方 ID", - "apiProtocolLabel": "API 协议", - "baseUrlLabel": "接口地址(Base URL)", - "customProviderHint": "在 ~/.pi/agent/models.json 中按你的接口地址定义一个提供方。多数自托管或代理服务使用 openai-completions。", - "baseUrlRequired": "接口地址(Base URL)为必填项", - "binaryTitle": "pi 二进制 (pi-coding-agent)", - "binaryDescription": "pi-acp 运行此 pi 二进制。可在此安装,或在下方指向你自己的构建。", - "binaryInstalled": "已安装", - "binaryMissing": "未安装", - "binaryChecking": "检测中…", - "installBinary": "安装 pi", - "installing": "安装中…", - "recheck": "重新检测", - "configDirSkillsNote": "设置了自定义配置目录后,设置页中管理的技能、专家与办公工具将不会作用于该 pi;请直接在该目录中管理其技能。", - "projectTrustTitle": "项目信任", - "projectTrustDescription": "你允许 pi 从中加载项目文件的目录。被信任的目录会让该仓库的 .pi/extensions 在 pi 启动时执行代码,且对其下所有子目录同样生效,你在终端里运行 pi 时也会沿用。", - "projectTrustLoading": "加载中…", - "projectTrustEmpty": "尚未对任何目录做出决定。", - "projectTrustTrusted": "已信任", - "projectTrustDenied": "不信任", - "projectTrustRevoke": "撤销", - "reasoningTitle": "推理", - "reasoningEnableLabel": "启用", - "reasoningDescription": "只有模型声明了推理能力,pi 才会发送推理强度——未声明的模型所有档位都会被压回 Off,所以输入框里的选择器一改就弹回。这里写入 models.json 中该模型的条目。", - "levelsLabel": "可选档位", - "levelsHint": "这些会成为输入框推理选择器里的档位。请选你的接入点能接受的值;不在这里的档位 pi 一律拒绝。", - "levelsEmptyError": "至少选一个档位——一个都不选时 pi 只会退回 Off。", - "wireValuesTitle": "高级:发给供应商的值", - "wireValuesHint": "留空表示原样发送档位名。接入点需要别的写法时才填——Google 系需要 LOW / HIGH。", - "defaultLevelUnlisted": "该档位不在上面的可选列表里——pi 会把它压下来。" - }, - "addCustomAgent": "添加自定义智能体", - "addCustomAgentHint": "接入任意兼容 ACP 的智能体。可从公开 ACP 注册表中选择,或直接粘贴其注册表信息。", - "customAgentFromRegistry": "ACP 注册表", - "customAgentManual": "手动填写", - "customAgentSearchPlaceholder": "搜索智能体…", - "customAgentLoadingCatalog": "正在加载 ACP 注册表…", - "customAgentRetry": "重试", - "customAgentNoResults": "没有匹配的智能体", - "customAgentAdd": "添加", - "customAgentAlreadyAdded": "已添加", - "customAgentUnsupportedPlatform": "当前平台没有可用的构建", - "customAgentAdded": "已添加 {name}", - "customAgentIdLabel": "注册表 ID", - "customAgentNameLabel": "显示名称", - "customAgentVersionLabel": "版本", - "customAgentSpecLabel": "分发信息(JSON)", - "customAgentSpecHint": "与 ACP 注册表 distribution 对象同构:支持 npx、uvx、binary 三种通道,也可整条粘贴注册表条目。npx/uvx 的 cmd 为包安装的可执行命令名,缺省按包名推导,与包名不同时需填写。binary 按平台键区分(本机为 {platform}),cmd 为压缩包内启动路径,sha256 可选用于校验下载。", - "customAgentTemplateLabel": "模板", - "customAgentKindLabel": "启动方式", - "customAgentInvalidJson": "不是合法的 JSON", - "customAgentNoDistribution": "未找到 npx、uvx 或 binary 分发方式", - "customAgentCancel": "取消", - "customAgentSave": "添加智能体", - "customAgentSaveChanges": "保存修改", - "customAgentEdit": "编辑智能体", - "customAgentEditHint": "修改名称、图标、分发信息与技能声明;智能体 ID 不可修改。", - "customAgentEditNotFound": "未找到自定义智能体 {id}", - "customAgentSaved": "已保存 {name}", - "customAgentVersionProbeLabel": "版本查询命令(可选)", - "customAgentVersionProbeHint": "查询本地安装版本的命令;留空时默认执行智能体命令加 --version。", - "customAgentRemove": "移除智能体", - "customAgentRemoveHint": "删除该智能体定义。已有会话的历史会保留,只是该智能体无法再启动。", - "customAgentIconLabel": "图标(可选)", - "customAgentIconUpload": "上传", - "customAgentIconReplace": "更换", - "customAgentIconClear": "移除图标", - "customAgentIconHint": "随智能体一起保存,离线也能显示。不上传则使用彩色首字母。", - "customAgentSkillsLabel": "Skills(共享 .agents/skills)", - "customAgentSkillsHint": "声明该智能体会读取共享的 .agents/skills 目录(全局与项目级),并将其加入所有技能矩阵。链接到共享目录的技能对读取该目录的其他智能体同样可见。", - "customAgentSkillsDirLabel": "专属技能目录", - "customAgentSkillsDirHint": "该智能体自身加载技能的目录绝对路径 —— 可与共享目录并存,也可单独使用。~ 会展开为主目录;链接技能时优先放入此目录。", - "customAgentMcpLabel": "MCP 支持", - "customAgentMcpHint": "会话建立时向该智能体注入 codeg 内置的 codeg-mcp 伴生进程 —— 委托、实时反馈与任务工具都依赖它。若该智能体不支持 MCP、连接时报错,请关闭此项;设置在下次连接时生效。", - "customAgentIconNotAnImage": "请选择图片文件。", - "customAgentIconTooLarge": "图标需小于 {limit} KB。", - "customAgentIconReadFailed": "无法读取该图片。", - "customAgentRemoveConfirm": "确定移除 {name}?已有会话会保留,但该智能体将无法再启动。", - "customAgentRemoveWithData": "同时删除已记录的会话历史", - "customAgentRemoved": "已移除 {name}", - "customAgentBadge": "自定义", - "customAgentNotLaunchable": "该智能体在此环境无法启动:{reason}" - }, - "SettingsPages": { - "agentsLoading": "加载 Agent 设置中...", - "skillPacksLoading": "正在加载技能包…" - }, - "GeneralSettings": { - "loading": "加载中...", - "sectionTitle": "常规", - "sectionDescription": "集中管理默认终端、渲染加速以及多智能体协同等通用偏好。", - "terminalTitle": "默认终端", - "terminalDescription": "选择从终端栏或文件树打开新终端标签页时使用的 Shell。智能体请求 codeg 代为执行整条命令行时也会使用它。", - "terminalSystemDefault": "系统默认", - "terminalPowerShell7": "PowerShell 7 (pwsh)", - "terminalWindowsPowerShell": "Windows PowerShell", - "terminalCmd": "命令提示符 (cmd)", - "terminalSaveFailed": "保存终端设置失败:{message}", - "terminalShellCustom": "自定义路径", - "terminalShellCustomPath": "Shell 路径", - "terminalShellCustomPlaceholder": "/usr/local/bin/fish", - "terminalShellCustomSave": "保存", - "terminalShellCustomHint": "支持绝对路径,或 PATH 中可解析的命令名。", - "terminalShellNotInstalled": "未安装", - "terminalShellNotFoundWarning": "当前主机上不存在此路径。", - "terminalCurrentShell": "当前使用:{path}", - "renderingDescription": "如果应用出现黑屏或渲染异常(常见于 AMD 显卡或部分 Intel 集成显卡),可关闭硬件加速。仅 Windows 桌面端生效。", - "disableHardwareAcceleration": "禁用硬件加速", - "renderingSaveFailed": "渲染设置保存失败:{message}", - "restartRequired": "已保存,重启应用后生效。", - "restartNow": "立即重启", - "restartFailed": "重启失败:{message}", - "loadFailed": "加载失败:{message}" - }, - "LoginPage": { - "documentTitle": "登录 - codeg", - "brand": "Codeg", - "subtitle": "输入访问 Token 以连接到桌面端", - "tokenPlaceholder": "Access Token", - "connect": "连接", - "connecting": "连接中...", - "helpText": "Token 可在桌面端 设置 → Web 服务 中获取", - "invalidToken": "Token 无效,请检查后重试", - "connectionFailed": "连接失败 (HTTP {status})", - "networkError": "无法连接到服务器" - }, - "CommitPage": { - "title": "提交代码", - "invalidFolderId": "无效的 folderId", - "loadingRepo": "正在加载仓库..." - }, - "MergePage": { - "title": "解决冲突", - "invalidFolderId": "无效的 folderId", - "loadingRepo": "正在加载仓库...", - "localVersion": "本地(我们的)", - "result": "结果", - "remoteVersion": "远程(他们的)", - "acceptLocal": "采用本地", - "acceptRemote": "采用远程", - "markResolved": "标记已解决", - "abortMerge": "中止", - "completeMerge": "完成合并", - "unresolvedConflicts": "文件中仍有未解决的冲突标记", - "fileResolved": "文件已解决", - "allResolved": "所有冲突已解决", - "conflictFiles": "冲突文件", - "loadingFile": "正在加载文件...", - "preparingMerge": "正在准备合并...", - "selectFile": "选择一个文件进行解决", - "noConflicts": "无冲突文件", - "skipFile": "跳过", - "abortSuccess": "操作已中止", - "applyAllNonConflicting": "应用所有非冲突变更", - "applyLeftNonConflicting": "应用本地", - "applyRightNonConflicting": "应用远程" - }, - "ImportSessions": { - "title": "导入本地会话", - "scanningTitle": "正在扫描本地智能体会话…", - "scanningHint": "正在遍历各智能体的本地会话存储,历史较多时可能需要一些时间。已导入的会话会顺带刷新。", - "scanFailed": "扫描失败", - "retry": "重试", - "rescan": "重新扫描", - "empty": "未发现本地会话", - "emptyHint": "本机未找到任何智能体的会话存储。", - "noMatches": "没有匹配当前筛选的会话", - "searchPlaceholder": "搜索标题或路径…", - "allAgents": "全部智能体", - "onlyImportable": "仅显示可导入", - "selectAll": "全选", - "clearSelection": "清空", - "expandAll": "全部展开", - "collapseAll": "全部折叠", - "summaryCounts": "共 {total} 个会话 · {importable} 个可导入 · {folders} 个文件夹", - "noFolderSkipped": "已跳过 {count} 个无项目目录的会话", - "folderNew": "新建", - "folderCounts": "可导入 {importable}/{total}", - "toggleFolderAria": "选择 {name} 中的全部可导入会话", - "toggleSessionAria": "选择会话 {title}", - "statusImported": "已导入", - "statusDeleted": "已删除", - "untitled": "未命名会话", - "messageCount": "{count} 条消息", - "selectedCount": "已选 {count} 个", - "importSelected": "导入所选", - "importing": "导入中…", - "close": "关闭", - "doneTitle": "导入完成", - "doneImported": "新导入", - "doneUpdated": "已刷新", - "doneSkipped": "已跳过", - "doneCreatedFolders": "新建文件夹", - "doneNotFound": "未找到", - "doneFailed": "失败", - "continueImport": "继续导入", - "toasts": { - "importFailed": "导入失败:{message}" - } - }, - "Folder": { - "workspaceStatus": { - "degradedTitle": "实时更新不可用", - "degradedHint": "监听器启动失败(如目录无读取权限)。请手动刷新以获取最新变更。", - "retry": "重试", - "retrying": "重试中..." - }, - "common": { - "all": "全部", - "cancel": "取消", - "close": "关闭", - "closeOthers": "关闭其它", - "closeAll": "关闭所有", - "confirm": "确认", - "save": "保存", - "delete": "删除", - "rename": "重命名", - "loading": "加载中...", - "refresh": "刷新", - "refreshing": "刷新中...", - "create": "创建", - "createAndSwitch": "创建并切换", - "openFile": "打开文件", - "viewDiff": "查看差异", - "push": "推送..." - }, - "statusLabels": { - "in_progress": "进行中", - "pending_review": "待复查", - "completed": "已完成", - "cancelled": "已取消" - }, - "sidebar": { - "title": "会话", - "locateActiveConversation": "定位当前会话", - "expandAllGroups": "展开全部分组", - "collapseAllGroups": "折叠全部分组", - "newConversation": "新建会话", - "newConversationShort": "新建", - "newChat": "新建会话", - "search": "搜索", - "noConversationsFound": "未找到会话。", - "importLocalSessions": "导入本地会话", - "importing": "导入中...", - "error": "错误:{message}", - "completeAllSessions": "完成全部会话", - "completeAllReviewTitle": "完成全部复查会话?", - "completeAllReviewDescription": "这会将复查中的 {count} 个会话全部标记为已完成。", - "completing": "处理中...", - "toasts": { - "importedSessions": "已导入 {imported} 个会话,跳过 {skipped} 个", - "importedAndUpdated": "已导入 {imported} 个会话,更新 {updated} 个标题,跳过 {skipped} 个", - "updatedTitles": "已更新 {updated} 个标题,跳过 {skipped} 个", - "noNewSessionsFound": "没有新会话(已跳过 {skipped} 个)", - "importFailed": "导入失败:{message}", - "reviewCompleted": "已将 {count} 个复查会话标记为已完成", - "completeReviewFailed": "批量完成复查会话失败:{message}", - "folderOpened": "已打开文件夹 {name}", - "folderRemoved": "已移除文件夹 {name}", - "openFolderFailed": "打开文件夹失败", - "removeFolderFailed": "移除文件夹失败:{message}", - "reorderFoldersFailed": "重新排序文件夹失败:{message}", - "changeFolderColorFailed": "修改颜色失败:{message}", - "setFolderAliasFailed": "设置别名失败:{message}", - "changeFolderDefaultAgentFailed": "设置默认智能体失败:{message}" - }, - "statsLabel": "{folders} 个文件夹 · {convos} 个会话", - "reorderHandle": "拖拽排序", - "openFolder": "打开文件夹", - "searchPlaceholder": "搜索会话...", - "viewOptions": "显示选项", - "showCompleted": "显示已完成会话", - "showWorktrees": "显示工作树文件夹", - "showRecent": "显示「最近」分组", - "moreOptions": "更多选项", - "sortBy": "排序方式", - "sortByCreatedAt": "按创建时间排序", - "sortByUpdatedAt": "按更新时间排序", - "sectionOrder": "区域顺序", - "sectionOrderMoveUp": "上移", - "sectionOrderMoveDown": "下移", - "sectionOrderItemLabel": "{name} — 第 {position} 位,共 {total} 位", - "statusRunningBadge": "运行中", - "runningCountBadge": "{count} 个会话进行中", - "statusCancelledBadge": "已取消", - "worktreeRemovedBadge": "源 worktree 已删除", - "conversationCountUnit": "{count} 条", - "emptyFolderHint": "暂无会话", - "noMatchingConversations": "未找到匹配的会话", - "noUnfinishedConversations": "当前暂无未完成会话,右上角可启用显示已完成会话", - "removeFolderConfirmTitle": "从工作区移除该文件夹?", - "removeFolderConfirmDescription": "从工作区移除 \"{name}\"?其相关 Tab 与终端将会关闭。", - "folderHeaderMenu": { - "manageConversations": "会话管理…", - "manageLinks": "关联的文件夹", - "changeColor": "修改颜色", - "useThemeColor": "使用设置主题", - "setDefaultAgent": "设置默认智能体", - "defaultAgentNone": "不设置(使用全局默认)", - "agentUnavailableSuffix": "(不可用)", - "loadingAgents": "正在加载代理…", - "setAlias": "设置别名…", - "setAliasTitle": "设置文件夹别名", - "setAliasPlaceholder": "输入别名(留空清除)", - "setAliasSave": "保存", - "setAliasCancel": "取消", - "removeFromWorkspace": "从工作区移除" - }, - "manageConversations": { - "title": "会话管理", - "searchPlaceholder": "按标题搜索…", - "agentFilterAll": "全部智能体", - "statusFilterAll": "全部状态", - "folderFilterAll": "全部文件夹", - "branchFilterAll": "全部分支", - "branchNone": "无分支", - "branchSearchPlaceholder": "搜索分支…", - "noMatchingBranches": "无匹配分支", - "selectAllVisible": "全选", - "deselectAll": "取消全选", - "selectedCount": "已选 {count} 条", - "matchedCount": "匹配 {count} 条", - "untitledConversation": "未命名会话", - "setStatus": "设为状态…", - "deleteSelected": "删除", - "noConversations": "此文件夹暂无会话。", - "noConversationsWorkspace": "工作区暂无会话。", - "noMatchingConversations": "没有匹配过滤条件的会话。", - "confirmDeleteTitle": "删除 {count} 个会话?", - "confirmDeleteDescription": "此操作不可撤销。", - "toastDeleted": "已删除 {count} 个会话", - "toastStatusUpdated": "已更新 {count} 个会话的状态", - "toastOpFailed": "操作失败:{message}" - }, - "sectionPinned": "已置顶", - "sectionFolders": "文件夹", - "sectionChats": "聊天", - "sectionRecent": "最近", - "noChats": "没有聊天", - "noRecent": "暂无最近会话", - "showMoreRecent": "显示更多({count})", - "noFolders": "没有打开的文件夹", - "newChatAction": "新建聊天", - "automations": "自动化", - "tasks": "待办任务", - "loadingSubsessions": "正在加载子会话…" - }, - "conversation": { - "reloadFailed": "会话重新加载失败:{message}", - "reloaded": "当前会话已重新加载", - "reload": "重新加载", - "activeConversationIndicator": "当前激活会话", - "newConversation": "新建会话", - "closeConversation": "关闭会话", - "copyText": "复制文本", - "copyTextSuccess": "已复制", - "copyTextFailed": "复制失败", - "forkSession": "分叉会话", - "forkSessionSuccess": "会话分叉成功", - "forkSessionFailed": "会话分叉失败:{error}", - "exportConversation": "导出会话", - "exportImage": "图片", - "exportMarkdown": "Markdown", - "exportHtml": "HTML", - "exportSuccess": "会话已导出", - "exportFailed": "导出失败", - "exportImageTooLong": "会话内容过长,不支持导出为图片", - "exportLabels": { - "untitledConversation": "未命名会话", - "agent": "代理", - "model": "模型", - "status": "状态", - "started": "开始时间", - "updated": "更新时间", - "tokens": "令牌统计", - "duration": "时长", - "inputTokens": "输入", - "outputTokens": "输出", - "cacheRead": "缓存读取", - "cacheWrite": "缓存写入", - "user": "用户", - "assistant": "助手", - "system": "系统", - "toolResult": "结果", - "toolError": "错误" - }, - "moreActions": "更多操作" - }, - "sessionDetails": { - "menuLabel": "会话详情", - "noActiveSession": "暂无活动会话", - "title": "会话详情", - "subtitle": "会话元信息与 Token 用量", - "fieldTitle": "标题", - "untitled": "未命名会话", - "sessionId": "会话 ID", - "externalId": "扩展 ID", - "agent": "智能体", - "model": "模型", - "status": "状态", - "gitBranch": "Git 分支", - "parentId": "父会话", - "tokensHeading": "Token 用量", - "totalTokens": "总计", - "inputTokens": "输入", - "outputTokens": "输出", - "cacheWrite": "缓存写入", - "cacheRead": "缓存读取", - "contextWindow": "上下文窗口", - "duration": "时长", - "loadingStats": "正在加载 Token 用量…", - "loadFailed": "加载 Token 用量失败", - "noStats": "暂无用量记录", - "timestampsHeading": "时间", - "createdAt": "创建时间", - "updatedAt": "更新时间", - "none": "—", - "copyField": "复制{field}", - "copiedField": "已复制{field}" - }, - "conversationCard": { - "untitledConversation": "未命名会话", - "newConversation": "新建会话", - "rename": "重命名", - "status": "状态", - "delete": "删除", - "importLocalSessions": "导入本地会话", - "importing": "导入中...", - "renameConversation": "重命名会话", - "deleteConversationTitle": "删除会话?", - "deleteConversationDescription": "会删除“{title}”,此操作不可撤销。", - "cancel": "取消", - "save": "保存", - "pin": "置顶", - "unpin": "取消置顶", - "markCompleted": "标记为已完成", - "reopen": "重新打开", - "expandSubsessions": "展开子会话", - "collapseSubsessions": "折叠子会话" - }, - "search": { - "dialogTitle": "搜索", - "dialogTitleWithFolder": "搜索 — {name}", - "tabConversations": "会话", - "tabFiles": "文件", - "placeholder": "搜索会话...", - "filePlaceholder": "搜索文件或目录...", - "allAgents": "全部", - "searching": "搜索中...", - "typeToSearch": "输入关键词搜索会话", - "typeToSearchFiles": "输入关键词搜索文件或目录", - "noResults": "未找到结果。", - "untitledConversation": "未命名会话" - }, - "folderTitleBar": { - "showSidebar": "显示侧边栏", - "hideSidebar": "隐藏侧边栏", - "toggleTerminal": "切换终端", - "toggleAuxPanel": "切换辅助面板", - "search": "搜索", - "openSettings": "打开设置", - "backToConversations": "返回会话", - "withShortcut": "{label}({shortcut})" - }, - "statusBar": { - "connection": { - "connected": "已连接", - "connecting": "连接中...", - "prompting": "响应中...", - "error": "连接异常", - "disconnected": "未连接", - "tooltip": "{agent}:{status}", - "tooltipError": "{agent}:{error}", - "title": "智能体连接", - "triggerAria": "智能体连接:{status}", - "workingDir": "工作目录", - "sessionId": "会话 ID", - "viewerNote": "已接入其他客户端拥有的会话——重连只会重新接入当前视图。", - "reconnectInterrupts": "重连会重启智能体,并中断正在进行的工作。", - "reconnect": "重新连接", - "reconnecting": "正在重新连接...", - "reconnectUnavailable": "暂无可重连的会话。" - }, - "tasks": { - "title": "任务" - }, - "alerts": { - "title": "告警", - "empty": "暂无告警信息", - "details": "详情" - }, - "stats": { - "conversations": "{count} 个会话", - "openUsage": "查看会话统计与 Token 用量" - }, - "tokens": { - "contextWindowUsageAria": "上下文窗口使用率", - "contextWindow": "上下文窗口", - "usedMax": "已用 / 上限", - "tokenUsage": "Token 用量", - "input": "输入", - "output": "输出", - "cacheRead": "缓存读取", - "cacheWrite": "缓存写入", - "total": "总计" - } - }, - "auxPanel": { - "tabs": { - "files": "文件", - "changes": "变更", - "commits": "提交" - }, - "noFolderTitle": "暂无打开的文件夹", - "noFolderHint": "打开一个文件夹后在这里查看" - }, - "windowControls": { - "minimizeWindow": "最小化窗口", - "minimize": "最小化", - "maximizeWindow": "最大化窗口", - "maximize": "最大化", - "restoreWindow": "还原窗口", - "restore": "还原", - "closeWindow": "关闭窗口", - "close": "关闭" - }, - "tabs": { - "closeConversationTab": "关闭会话标签", - "close": "关闭", - "closeOthers": "关闭其它", - "splitRight": "向右拆分", - "splitDown": "向下拆分", - "splitAndMoveRight": "拆分并右移", - "splitAndMoveDown": "拆分并下移", - "moveToOppositeGroup": "移动到对侧分组", - "moveToGroup": "移动到分组", - "groupLabel": "分组 {index}", - "changeSplitterOrientation": "切换分隔方向", - "unsplit": "取消拆分", - "unsplitAll": "全部取消拆分", - "closeAll": "关闭所有", - "tileDisplay": "平铺显示", - "untileDisplay": "取消平铺" - }, - "fileWorkspace": { - "files": "文件", - "closeFileTab": "关闭文件标签", - "close": "关闭", - "closeOthers": "关闭其它", - "closeAll": "关闭所有", - "preview": "预览", - "editSource": "编辑源码", - "maximize": "最大化", - "restore": "还原", - "emptyDirectory": "空目录" - }, - "terminal": { - "rename": "重命名", - "close": "关闭", - "closeOthers": "关闭其它", - "closeAll": "关闭所有", - "hideTerminal": "隐藏终端({shortcut})", - "openFolderFirst": "请先打开一个文件夹" - }, - "workspaceDialog": { - "title": "打开文件夹", - "manageTitle": "关联的文件夹", - "addTargetsTitle": "添加要关联的文件夹", - "pickRootDescription": "选择该工作空间的主文件夹。", - "linksDescription": "把其它文件夹以子目录的形式关联进来,智能体就能在同一个工作空间里跨项目工作。", - "addTargetsDescription": "选择一个或多个文件夹,每个都会成为工作空间的一个子目录。", - "useSystemPicker": "系统选择器", - "next": "下一步", - "back": "返回", - "done": "完成", - "change": "更改", - "addFolders": "添加文件夹", - "addSelected": "添加", - "addSelectedCount": "添加 {count} 个", - "createCount": "关联 {count} 个文件夹", - "discardPending": "放弃", - "noLinks": "还没有关联任何文件夹。", - "gitExclude": "不让关联目录污染 git 状态", - "rename": "重命名", - "unlink": "解除关联", - "repair": "重建链接", - "saveName": "保存", - "cancelRename": "取消", - "removePending": "移除", - "willAppearAs": "在工作空间中显示为 {name}", - "renamedForDuplicate": "已改名 —— {base} 已被另一个关联占用", - "renamedForExistingEntry": "已改名 —— 该文件夹中已存在 {base}", - "partiallyCreated": "只成功关联了 {count} 个文件夹", - "openFailed": "打开文件夹失败", - "previewFailed": "检查所选文件夹失败", - "createFailed": "关联文件夹失败", - "renameFailed": "重命名失败", - "removeFailed": "解除关联失败", - "repairFailed": "重建链接失败", - "status": { - "ok": "已关联", - "missing": "链接已从该文件夹中消失", - "conflicted": "该名称已被其它条目占用", - "broken": "被关联的文件夹已不存在" - }, - "nameIssue": { - "empty": "请输入名称", - "illegalChars": "不能包含 / \\ : * ? \" < > |", - "tooLong": "名称过长", - "reserved": "该名称是 Windows 保留名", - "duplicate": "该名称已被使用" - }, - "rejection": { - "not_found": "找不到该文件夹", - "not_a_directory": "该路径不是文件夹", - "same_as_root": "这就是工作空间文件夹本身", - "ancestor_of_root": "该文件夹包含了当前工作空间", - "inside_root": "已在工作空间内部", - "already_linked": "已经关联过", - "name_unavailable": "该文件夹已无可用的名称", - "alreadyLinkedAs": "已作为 {name} 关联" - } - }, - "folderNameDropdown": { - "fallbackFolderName": "文件夹", - "openFolder": "打开文件夹", - "cloneRepository": "克隆仓库", - "projectBoot": "项目启动器", - "opened": "已打开", - "recentOpen": "最近打开" - }, - "fileWorkspacePanel": { - "addSelectionToChat": "添加选区到会话", - "addToChat": "加入会话", - "addSelectionToChatDone": "已将 {label} 加入会话", - "addFileToChat": "添加文件到会话", - "toggleWordWrap": "切换自动换行", - "addFileToChatDone": "已将 {label} 加入会话", - "viewDiff": "查看差异", - "openFile": "打开文件", - "fileCount": "{count} 个文件", - "openFileOrDiff": "从右侧面板打开文件或差异", - "disk": "磁盘", - "head": "HEAD(当前提交)", - "unsaved": "未保存", - "workingTree": "工作区", - "loading": "加载中...", - "compareWithBranch": "{path} · 与 {branch} 比较", - "hunkCount": "{count} 个区块", - "prev": "上一个", - "next": "下一个", - "jumpToLine": "跳转到第 {line} 行", - "noParsedDiffSections": "未解析到差异区块", - "loadingEditor": "编辑器加载中...", - "imageZoomIn": "放大", - "imageZoomOut": "缩小", - "imageZoomReset": "重置缩放", - "htmlPreviewTitle": "HTML 预览", - "htmlPreviewTrust": "运行脚本", - "htmlPreviewTrustHint": "运行此文件的脚本并允许网络访问。仅对可信任的文件启用。", - "officePreviewTitle": "办公文档预览", - "officeFullRender": "完整渲染", - "officeFullRenderHint": "渲染 Morph 动画、3D 和公式(会运行幻灯片自带的脚本)", - "officeNotInstalled": "未安装 OfficeCLI", - "officeNotInstalledHint": "在 设置 → 办公工具 中安装 OfficeCLI,即可预览 Word、Excel 和 PowerPoint 文件。", - "officeOpenSettings": "打开设置", - "officeWatchFailed": "无法启动实时预览", - "officeWatchRetry": "重试", - "officeServerInstallHint": "OfficeCLI 需安装在服务器主机上。请在服务器上运行以下命令后重试:", - "officeRemoteDesktopUnsupported": "远程桌面窗口暂不支持实时预览。请在服务器的 Web 界面中打开此工作区来预览 Office 文件。" - }, - "branchDropdown": { - "toasts": { - "commitCodeCompleted": "提交代码完成", - "pushCodeCompleted": "推送代码完成", - "committedFiles": "已提交 {count} 个文件", - "taskCompleted": "{label} 完成", - "taskFailed": "{label} 失败", - "mergeNoNewCommits": "{branchName} 没有新的提交", - "mergedCommits": "已合并 {count} 个提交", - "allFilesUpToDate": "所有文件均为最新版本", - "updatedFiles": "已更新 {count} 个文件", - "openCommitWindowFailed": "打开提交窗口失败", - "openPushWindowFailed": "打开推送窗口失败", - "upstreamSet": "已设置远程跟踪分支", - "upstreamSetAndPushed": "已设置远程跟踪分支并推送 {count} 个提交", - "noCommitsToPush": "没有可推送的提交", - "pushedCommits": "已推送 {count} 个提交", - "switchedToFolder": "已切换到 {name}", - "switchFailed": "切换分支失败", - "openStashWindowFailed": "打开贮藏窗口失败" - }, - "tasks": { - "newBranch": "新建分支 {name}", - "newWorktree": "新建工作树 {name}", - "checkoutTo": "切换到 {branchName}", - "mergeBranch": "合并 {branchName}", - "rebaseTo": "变基到 {branchName}", - "deleteRemoteBranch": "删除远程分支 {branchName}", - "initGitRepo": "初始化 Git 仓库", - "pullCode": "更新代码", - "fetchInfo": "获取信息", - "pushCode": "推送代码", - "stashChanges": "贮藏更改", - "stashPop": "取消贮藏", - "deleteBranch": "删除分支 {branchName}", - "removeWorktree": "删除 {branchName} 的工作树", - "removeWorktreeAndBranch": "删除工作树及分支 {branchName}", - "updateBranch": "更新分支 {branchName}" - }, - "confirm": { - "mergeTitle": "合并分支", - "rebaseTitle": "变基分支", - "mergeDescription": "确定将 {branchName} 合并到当前分支 {currentBranch} 吗?", - "rebaseDescription": "确定将当前分支 {currentBranch} 变基到 {branchName} 吗?", - "deleteRemoteTitle": "删除远程分支", - "deleteRemoteDescription": "确定删除远程分支 {branchName} 吗?此操作将从远程仓库中移除该分支,且不可恢复。", - "deleteTitle": "删除分支", - "deleteDescription": "确定删除分支 {branchName} 吗?此操作不可恢复。", - "forceDeleteTitle": "强制删除分支", - "forceDeleteDescription": "分支 {branchName} 尚未完全合并,确定要强制删除吗?此操作不可恢复。", - "deleteWorktreeTitle": "删除工作树", - "deleteWorktreeDescription": "删除检出了 {branchName} 的工作树目录?分支及其提交会保留。", - "forceDeleteWorktreeTitle": "强制删除工作树", - "forceDeleteWorktreeDescription": "{branchName} 的工作树中有未提交或未跟踪的文件。仍要删除吗?这些改动将无法恢复。", - "deleteWorktreeAndBranchTitle": "删除工作树及分支", - "deleteWorktreeAndBranchDescription": "删除 {branchName} 的工作树、该分支本身及其工作区文件夹?其中的会话会移动到仓库文件夹下。此操作无法撤销。", - "forceDeleteWorktreeAndBranchTitle": "强制删除工作树及分支", - "forceDeleteWorktreeAndBranchDescription": "{branchName} 的工作树中有未提交的文件,或该分支尚未完全合并。仍要一并删除吗?此操作无法撤销。" - }, - "current": "当前", - "switchToBranch": "切换到此分支", - "mergeBranchIntoCurrent": "将 {branchName} 合并到 {currentBranch}", - "rebaseCurrentToBranch": "将 {currentBranch} 变基到 {branchName}", - "noBranch": "无分支", - "detachedHead": "游离 HEAD({sha})", - "initGitRepo": "初始化 Git 仓库", - "pullCode": "更新代码", - "fetchRemoteBranches": "提取远程分支", - "openCommitWindow": "提交代码...", - "pushCode": "推送...", - "pushBranch": "推送", - "newBranch": "新建分支...", - "newWorktree": "新建工作树...", - "stashChanges": "贮藏更改...", - "stashPop": "取消贮藏...", - "manageRemotes": "管理远程...", - "localBranches": "本地分支 ({count})", - "noLocalBranches": "无本地分支", - "remoteBranches": "远程分支 ({count})", - "noRemoteBranches": "无远程分支", - "dialogs": { - "newBranchTitle": "新建分支", - "newBranchDescription": "从当前分支 {branch} 创建新分支", - "branchNamePlaceholder": "分支名称", - "newWorktreeTitle": "新建工作树", - "newWorktreeDescription": "从当前分支 {branch} 创建新的工作树", - "branchNameLabel": "分支名称", - "worktreePathLabel": "工作树路径", - "worktreePathPlaceholder": "工作树路径", - "manageRemotesTitle": "管理远程", - "manageRemotesEmpty": "未配置远程仓库", - "remoteNamePlaceholder": "远程名称", - "remoteUrlPlaceholder": "远程 URL", - "addRemote": "添加", - "savingRemotes": "保存中..." - }, - "conflict": { - "title": "合并冲突", - "description": "以下文件存在冲突,需要手动解决:", - "abort": "中止合并", - "openMergeTool": "打开合并工具", - "completeMerge": "完成合并", - "abortSuccess": "合并已中止", - "completeSuccess": "合并完成" - }, - "stashDialog": { - "title": "贮藏更改", - "description": "将当前更改保存到贮藏区", - "messageLabel": "消息", - "messagePlaceholder": "贮藏消息(可选)", - "keepIndex": "保留暂存区(已暂存的更改保持不变)", - "cancel": "取消", - "stash": "贮藏", - "success": "更改已贮藏", - "error": "贮藏更改失败" - }, - "unstashDialog": { - "title": "取消贮藏", - "noStashes": "没有贮藏记录", - "selectFile": "选择文件查看差异", - "viewDiff": "查看差异", - "original": "原始", - "modified": "修改后", - "apply": "应用", - "drop": "删除", - "applySuccess": "贮藏已应用", - "dropSuccess": "贮藏已删除", - "confirmApply": "将贮藏 {ref} 应用到工作目录?", - "cancel": "取消" - }, - "deleteBranch": "删除分支", - "deleteWorktree": "删除工作树", - "deleteWorktreeAndBranch": "删除工作树及分支", - "searchPlaceholder": "搜索分支和操作", - "searchAriaLabel": "搜索分支和操作", - "branchListLabel": "分支和操作", - "noMatches": "无匹配项" - }, - "commitDialog": { - "toasts": { - "commitCompleted": "提交代码完成", - "pushFailed": "推送失败", - "committedFiles": "已提交 {count} 个文件", - "addedToVcs": "已添加到 VCS", - "addToVcsFailed": "添加到 VCS 失败", - "fileDeleted": "文件已删除", - "deleteFailed": "删除失败", - "fileRolledBack": "文件已回滚", - "rollbackFailed": "回滚失败", - "dirRolledBack": "目录已回滚", - "dirDeleted": "目录已删除" - }, - "confirm": { - "deleteTitle": "确认删除", - "deleteDescription": "确定要删除文件「{file}」吗?此操作不可恢复。", - "rollbackTitle": "确认回滚", - "rollbackDescription": "确定要回滚文件「{file}」到 HEAD 版本吗?未保存的修改将丢失。", - "rollbackDirDescription": "确定要回滚目录「{dir}」到 HEAD 版本吗?未保存的修改将丢失。", - "deleteDirDescription": "确定要删除目录「{dir}」吗?此操作不可恢复。" - }, - "actions": { - "select": "选择", - "unselect": "取消选择", - "rollback": "回滚", - "addToVcs": "添加到 VCS" - }, - "aria": { - "selectFile": "{action}:{path}", - "unselectAllFiles": "取消选择全部文件", - "selectAllFiles": "选择全部文件", - "unselectTracked": "取消选择已跟踪改动", - "selectTracked": "选择已跟踪改动", - "unselectUntracked": "取消选择未跟踪文件", - "selectUntracked": "选择未跟踪文件" - }, - "loading": "加载中...", - "selectionCount": "{selected} / {total} 个文件", - "emptyFiles": "没有改动的文件", - "trackedChanges": "已跟踪改动 ({count})", - "untrackedFiles": "未跟踪文件 ({count})", - "commitMessage": "提交消息", - "commitMessagePlaceholder": "输入提交信息...", - "commitButton": "提交 ({count})", - "commitAndPushButton": "提交并推送 ({count})", - "head": "HEAD(当前提交)", - "workingTree": "工作区", - "clickFileToDiff": "点击文件名查看差异", - "loadingDiff": "加载差异..." - }, - "pushWindow": { - "title": "推送代码", - "noUnpushedCommits": "没有未推送的提交", - "noRemoteConfigured": "未配置 Git 远程仓库\n请在「管理远程」中添加远程地址", - "newBranchNoPushedCommits": "新分支 — 推送以创建远程跟踪分支", - "unpushed": "未推送", - "selectFileToViewDiff": "选择文件查看差异", - "before": "修改前", - "after": "修改后", - "push": "推送", - "toasts": { - "pushSuccess": "推送成功", - "pushFailed": "推送失败", - "upstreamSet": "已设置远程跟踪分支", - "upstreamSetAndPushed": "已设置远程跟踪分支并推送 {count} 个提交", - "noCommitsToPush": "没有可推送的提交", - "pushedCommits": "已推送 {count} 个提交" - } - }, - "gitLogTab": { - "filesTitle": "文件", - "expandAllFiles": "展开全部文件", - "collapseAllFiles": "折叠全部文件", - "workspace": "工作区", - "retry": "重试", - "noCommitsFound": "未找到提交记录", - "notAGitRepoTitle": "不是 Git 仓库", - "notAGitRepoHint": "可从上方分支菜单初始化 Git,或打开已有的 Git 仓库。", - "hash": "Hash", - "copyHash": "复制哈希", - "copyMessage": "复制提交消息", - "showMore": "展开", - "showLess": "收起", - "author": "作者", - "noFileChangeDetails": "暂无文件变更详情。", - "loadingFiles": "正在加载文件…", - "branchesTitle": "分支", - "loadingBranches": "正在加载分支...", - "noContainingBranches": "未找到包含此提交的分支。", - "newBranch": "新建分支...", - "resetToHere": "重置到此处", - "resetDisabledReasonNotCurrentBranchView": "仅在查看当前分支时可用", - "copyFullCommitHashAria": "复制完整提交哈希 {hash}", - "pushStatus": { - "pushed": "已推送到远程", - "notPushed": "未推送到远程", - "unknown": "推送状态未知(未配置上游分支)" - }, - "time": { - "monthsAgo": "{count} 个月前", - "daysAgo": "{count} 天前", - "hoursAgo": "{count} 小时前", - "minsAgo": "{count} 分钟前", - "justNow": "刚刚" - }, - "toasts": { - "createdAndSwitchedNewBranch": "已创建并切换到新分支", - "newBranchFromCommit": "{name}(来自 {shortHash})", - "createBranchFailed": "新建分支失败", - "openPushWindowFailed": "打开推送窗口失败", - "resetSuccess": "重置成功", - "resetSuccessDescription": "已将 {branch} 以 {mode} 重置到 {shortHash}", - "resetFailed": "重置失败" - }, - "authorFilter": { - "label": "作者", - "searchPlaceholder": "搜索作者", - "noAuthors": "未找到作者", - "you": "你", - "filterByAuthorAria": "按作者筛选提交", - "filterByQuery": "按“{query}”过滤", - "clearAuthorFilterAria": "清除作者过滤", - "recent": "最近", - "matchingAuthors": "匹配的作者", - "removeFromRecent": "从最近列表移除 {name}" - }, - "branchSelector": { - "label": "分支", - "head": "HEAD", - "headHint": "跟随当前分支", - "headHintWithBranch": "跟随当前分支({branch})", - "searchBranch": "搜索分支...", - "noBranches": "无分支", - "selectBranchPlaceholder": "选择分支...", - "localBranches": "本地分支", - "current": "当前", - "remoteBranches": "远程分支", - "refreshCommitHistory": "刷新提交记录", - "clearBranchFilterAria": "清除分支过滤" - }, - "dialogs": { - "newBranchTitle": "新建分支", - "newBranchDescription": "以提交 {shortHash} 作为最后提交创建新分支。", - "branchNamePlaceholder": "分支名称", - "reset": { - "title": "将当前分支重置到此提交", - "branchLabel": "分支", - "targetLabel": "目标提交", - "messageLabel": "提交信息", - "modeLabel": "重置模式", - "confirmButton": "重置", - "modes": { - "soft": { - "label": "--soft", - "description": "将 HEAD 和当前分支指针移动到目标提交。\n暂存区(Index)和工作区(Working Tree)保持不变。\n被回退提交对应的改动会保留为“已暂存”状态。" - }, - "mixed": { - "label": "--mixed(默认)", - "description": "将 HEAD 移动到目标提交。\n把暂存区重置为目标提交状态,但保留工作区改动。\n这些改动会从“已暂存”变为“未暂存”。" - }, - "hard": { - "label": "--hard", - "description": "将 HEAD、暂存区和工作区全部重置到目标提交。\n目标提交之后的本地已跟踪改动会被直接丢弃。\n这是破坏性操作。" - }, - "keep": { - "label": "--keep", - "description": "将 HEAD 移动到目标提交,并尽量保留本地改动。\n仅当本地改动与目标提交不冲突时才会保留。\n若存在冲突,操作会中止以避免覆盖你的修改。" - } - } - } - }, - "moreActions": "更多 Git 操作" - }, - "gitChangesTab": { - "workspace": "工作区", - "noChanges": "暂无本地改动", - "notAGitRepoTitle": "不是 Git 仓库", - "notAGitRepoHint": "可从上方分支菜单初始化 Git,或打开已有的 Git 仓库。", - "trackedChanges": "本地已跟踪改动 ({count})", - "untrackedFiles": "本地未跟踪文件 ({count})", - "expandTracked": "展开已跟踪改动", - "collapseTracked": "折叠已跟踪改动", - "expandUntracked": "展开未跟踪文件", - "collapseUntracked": "折叠未跟踪文件", - "showRemainingItems": "显示其余 {count} 项", - "actions": { - "commitCode": "提交代码", - "rollback": "回滚", - "addToVcs": "添加到 VCS", - "delete": "删除", - "moreActions": "更多 Git 操作", - "addAllToVcs": "全部添加到 VCS", - "rollbackAll": "全部回滚", - "refresh": "刷新" - }, - "toasts": { - "noAddableFilesInDir": "该目录下没有可添加到 VCS 的变更文件", - "noRollbackFilesInDir": "该目录下没有可回滚的变更文件", - "addedToVcs": "已添加 {name} 到 VCS", - "addToVcsFailed": "添加到 VCS 失败", - "openCommitWindowFailed": "打开提交窗口失败", - "rolledBack": "已回滚 {name}", - "rollbackFailed": "回滚失败", - "addedFilesToVcs": "已添加 {count} 个文件到 VCS", - "rolledBackFiles": "已回滚 {count} 个文件", - "deleted": "已删除 {name}", - "deleteFailed": "删除失败", - "deletedFiles": "已删除 {count} 个文件", - "noDeletableFilesInDir": "该目录下没有可删除的变更文件", - "commitFailed": "提交失败" - }, - "directoryDialog": { - "descriptionAdd": "选择目录 {path} 下要添加到 VCS 的文件。", - "descriptionRollback": "选择目录 {path} 下要回滚的文件。", - "descriptionDelete": "选择目录 {path} 下要删除的文件。此操作不可撤销。", - "descriptionFallback": "选择要操作的文件。", - "selectionCount": "已选择 {selected} / {total} 个文件", - "selectAll": "全选", - "unselectAll": "取消全选", - "loadingCandidates": "正在加载目录变更...", - "noOperableFiles": "没有可操作的文件" - }, - "rollbackConfirm": { - "title": "确认回滚", - "descriptionWithTarget": "确定回滚{kind}「{name}」的本地修改吗?", - "descriptionFallback": "确定回滚本地修改吗?", - "kindDirectory": "目录", - "kindFile": "文件" - }, - "deleteConfirm": { - "title": "确认删除", - "descriptionWithTarget": "确定删除{kind}「{name}」吗?此操作不可撤销。", - "descriptionFallback": "确定删除吗?此操作不可撤销。", - "kindDirectory": "目录", - "kindFile": "文件" - }, - "quickCommit": { - "placeholder": "提交信息(回车提交)" - } - }, - "tabContext": { - "loadingConversation": "加载中...", - "untitledConversation": "未命名会话", - "newConversation": "新建会话" - }, - "fileTreeTab": { - "workspace": "工作区", - "retry": "重试", - "git": "Git", - "openInFileManager": "在文件管理器打开", - "openInFinder": "在访达打开", - "openInExplorer": "在资源管理器打开", - "attachToCurrentSession": "添加到会话", - "compareWithBranch": "与分支比较...", - "reloadFromDisk": "从磁盘重新加载", - "new": "新建", - "newFile": "文件", - "newDirectory": "目录", - "openIn": "打开于", - "openInTerminal": "在终端打开", - "linkedFolder": "关联的文件夹", - "copyPath": "复制路径", - "upload": "上传文件/目录", - "download": "下载文件", - "downloadAsZip": "下载为 ZIP", - "actions": { - "select": "选择", - "unselect": "取消选择", - "commitCode": "提交代码", - "rollback": "回滚", - "addToVcs": "添加到 VCS" - }, - "aria": { - "selectPath": "{action}:{path}" - }, - "toasts": { - "openDirectoryFailed": "打开目录失败", - "openBuiltinTerminalFailed": "无法打开内置终端", - "openCommitWindowFailed": "打开提交窗口失败", - "noAddableFilesInDir": "该目录下没有可添加到 VCS 的变更文件", - "noRollbackFilesInDir": "该目录下没有可回滚的变更文件", - "addedToVcs": "已添加 {name} 到 VCS", - "addToVcsFailed": "添加到 VCS 失败", - "loadBranchesFailed": "加载分支失败", - "renameFailed": "重命名失败", - "moveFailed": "移动失败", - "deleteFailed": "删除失败", - "rolledBack": "已回滚 {name}", - "rollbackFailed": "回滚失败", - "addedFilesToVcs": "已添加 {count} 个文件到 VCS", - "rolledBackFiles": "已回滚 {count} 个文件", - "savedAsCopy": "已另存为副本", - "saveCopyFailed": "另存为副本失败", - "watchStartFailed": "文件监听启动失败", - "createFailed": "创建失败", - "downloadFailed": "下载 {name} 失败", - "downloadSaved": "已下载 {name}", - "pathCopied": "已复制路径", - "copyPathFailed": "复制路径失败" - }, - "createDialog": { - "newFile": "新建文件", - "newDirectory": "新建目录", - "description": "输入新{kind}的名称。", - "placeholderFile": "文件名.ext", - "placeholderDirectory": "文件夹名" - }, - "renameDialog": { - "renameDirectory": "重命名目录", - "renameFile": "重命名文件", - "description": "输入新的名称(仅名称,不含路径)。", - "placeholderDirectory": "新建文件夹名称", - "placeholderFile": "新建文件名称.ext" - }, - "uploadDialog": { - "title": "上传到工作区", - "description": "可以在下方修改上传目录,然后添加文件或文件夹。", - "workspaceRoot": "工作区根目录", - "targetPathLabel": "上传到", - "targetPathHint": "实际目录:{path}", - "dropHint": "拖拽文件或文件夹到此处,或使用下方按钮", - "dropHintActive": "释放鼠标以加入上传队列", - "selectFiles": "选择文件", - "selectFolder": "选择文件夹", - "startUpload": "开始上传", - "clearQueue": "清除已完成", - "removeItem": "从队列移除", - "retry": "重试", - "dropZoneAria": "拖放文件到此处,或按回车键浏览", - "folderEmpty": "拖入的文件夹中没有可上传的文件", - "summary": "总数:{total} · 成功:{succeeded} · 失败:{failed}", - "status": { - "pending": "等待中", - "uploading": "上传中", - "success": "完成", - "error": "失败", - "cancelled": "已取消" - } - }, - "directoryDialog": { - "descriptionAdd": "选择目录 {path} 下要添加到 VCS 的文件。", - "descriptionRollback": "选择目录 {path} 下要回滚的文件。", - "descriptionFallback": "选择要操作的文件。", - "selectionCount": "已选择 {selected} / {total} 个文件", - "selectAll": "全选", - "unselectAll": "取消全选", - "loadingCandidates": "正在加载目录变更...", - "noOperableFiles": "没有可操作的文件" - }, - "compareDialog": { - "title": "与分支比较", - "descriptionWithTarget": "选择分支并与{kind} {path} 对比", - "descriptionFallback": "选择要比较的分支。", - "kindDirectory": "目录", - "kindFile": "文件", - "filterPlaceholder": "过滤分支,例如 main / origin/main", - "singleClickHint": "单击分支即可直接比较", - "loadingBranches": "正在加载分支...", - "recentBranches": "最近分支 ({count})", - "noCurrentBranch": "无当前分支", - "localBranches": "本地分支 ({count})", - "remoteBranches": "远程分支 ({count})", - "noMatchingBranches": "无匹配分支" - }, - "externalConflictDialog": { - "title": "检测到外部文件变更", - "descriptionWithPath": "文件 {path} 在磁盘已发生变化,当前编辑内容尚未保存。", - "descriptionFallback": "当前文件在磁盘已发生变化,当前编辑内容尚未保存。", - "compare": "对比", - "savingCopy": "另存中...", - "saveAsCopy": "另存为副本", - "reload": "重载" - }, - "deleteConfirm": { - "title": "确认删除", - "descriptionWithTarget": "确定删除{kind} \"{name}\" 吗?此操作不可撤销。", - "descriptionFallback": "此操作不可撤销。", - "kindDirectory": "目录", - "kindFile": "文件" - }, - "rollbackConfirm": { - "title": "确认回滚", - "descriptionWithTarget": "确定回滚文件 \"{name}\" 的本地修改吗?", - "descriptionFallback": "确定回滚该文件的本地修改吗?" - }, - "terminalTitle": "终端 · {name}" - }, - "commandDropdown": { - "loading": "加载中...", - "addCommand": "添加命令", - "manageCommands": "管理命令...", - "runCommandTitle": "运行:{command}", - "stopCommandTitle": "停止:{command}", - "manageDialog": { - "title": "管理命令", - "empty": "暂无命令", - "noResults": "没有匹配的命令", - "searchPlaceholder": "搜索命令", - "newCommand": "新建命令", - "nameLabel": "名称", - "commandLabel": "命令", - "dragSort": "拖拽排序", - "dragSortCommand": "拖拽排序 {name}", - "orderFailed": "保存命令排序失败", - "loadFailed": "加载命令失败", - "saveFailed": "保存命令失败", - "deleteFailed": "删除命令失败", - "confirmDelete": { - "title": "删除命令?", - "message": "这会移除“{name}”,此操作不可撤销。" - } - } - }, - "workspaceContext": { - "confirmCloseDirtyTab": "文件“{title}”有未保存更改,确定关闭吗?", - "confirmCloseOtherDirtyTabs": "其它标签页有未保存更改,确定关闭吗?", - "confirmCloseAllDirtyTabs": "存在未保存更改,确定关闭全部标签页吗?", - "unableLoadContent": "无法加载内容。\n\n{message}", - "previewRequestTimedOut": "预览请求超时", - "diffRequestTimedOut": "Diff 请求超时", - "branchCompareRequestTimedOut": "分支比较请求超时", - "commitDiffRequestTimedOut": "提交差异请求超时", - "saveRequestTimedOut": "保存请求超时", - "reloadRequestTimedOut": "重载请求超时", - "noChanges": "暂无变更。", - "noDiffOutput": "无差异输出。", - "diffTitleWorkspace": "Diff · 工作区", - "diffDescriptionWorkingTree": "工作区变更(HEAD)", - "diffTitleFile": "差异 · {name}", - "compareTitleFile": "比较 · {name}", - "compareTitleBranch": "比较 · {branch}", - "compareDescriptionPath": "{path} · 与 {branch} 比较", - "compareDescriptionBranch": "与 {branch} 比较", - "diffTitleCommitFile": "差异 · {name} @ {hash}", - "diffTitleCommit": "差异 · {hash}", - "diffDescriptionCommitPath": "{path} · 提交 {commit}", - "diffDescriptionCommit": "提交 {commit}", - "diffTitleConflictFile": "冲突 · {name}", - "diffDescriptionConflict": "{path} · 磁盘与未保存内容" - }, - "chat": { - "acpConnections": { - "actions": { - "openAgentsSettings": "打开 Agents 管理", - "retry": "重试" - }, - "agentsSetupHint": "点击前往设置 > Agents 管理安装。", - "withSetupHint": "{message}\n提示:{hint}", - "blocked": { - "missingConfig": "无法读取当前 Agent 配置。", - "disabled": "{agent} 已在 Agents 管理中禁用,请先启用后再连接。", - "unavailable": "{agent} 当前平台不可用。", - "sdkMissing": "{agent} SDK 尚未安装", - "adapterMissing": "{agent} 的 ACP 适配器尚未安装" - }, - "backendErrors": { - "initializeTimeout": "{agent} 连接握手超时(60 秒未响应),请前往设置页面检查智能体和网络配置。", - "mcpRejectedByAgent": "附带 codeg 的 MCP 伴生进程时,{agent} 拒绝了本次会话:{message} 如果该智能体不支持 MCP,请在设置中关闭它的“MCP 支持”后重新连接。", - "processExited": "{agent} 进程意外退出。", - "spawnFailed": "启动 {agent} 失败:{message}", - "downloadFailed": "{agent} 下载失败:{message}", - "sessionLoadResourceNotFound": "{agent} 会话加载失败,可重新加载重试,或开始新会话。", - "sessionLoadUnavailable": "{agent} 无法恢复此会话,它可能已结束或 agent 已停止。可重新加载重试,或开始新会话。", - "turnFailedRefusal": "{agent} 拒绝继续本轮回复,通常意味着后端或网关出错,请检查代理日志。", - "turnFailedMaxTokens": "{agent} 已达到本轮回复的最大 Token 限制。", - "turnFailedMaxTurnRequests": "{agent} 已达到本轮回复允许的最大请求次数。", - "turnFailedUnknown": "{agent} 以未知的停止原因结束了本轮回复。", - "grokModelSwitchIncompatibleAgent": "{agent} 无法在已有对话中切换到该模型,请新建会话以使用它。", - "turnFailedEmpty": "{agent} 本轮没有产生任何回复就结束了。", - "turnFailedEmptyProtocol": "{agent} 本轮的输出 codeg 无法解析,可能是代理版本与协议不匹配。", - "turnFailedEmptyMetadata": "{agent} 本轮只收到状态更新(计划 / 模式 / 用量),没有收到任何回复。", - "detailsInAlerts": "在状态栏的「告警」中展开详情,可查看代理输出。" - }, - "unableReadAgentConfig": "无法读取 Agent 配置:{message}", - "connectFailedTitle": "{agent} 连接失败", - "toolFallbackTitle": "工具", - "eventErrorTitle": "Agent 错误", - "notificationTurnComplete": "{agent} 已完成响应", - "notificationError": "{agent} 错误:{message}", - "claudeApiRetry": { - "fallbackError": "authentication_failed", - "retryingWithMax": "正在重试 {attempt}/{max}", - "retryingAttempt": "正在重试(第 {attempt} 次)", - "retrying": "正在重试", - "nextRetryIn": "{seconds} 秒后重试", - "line": "{error}{status} · {retry}", - "lineWithDelay": "{error}{status} · {retry},{delay}", - "httpStatus": "(HTTP {status})" - }, - "configOptionAdjusted": "{agent} 把{option}设成了 {actual},而不是 {requested}" - }, - "connectionLifecycle": { - "tasks": { - "connectingTitle": "正在连接 {agent}", - "connectingDescription": "正在建立连接", - "loadingSelectorsTitle": "正在加载 {agent} 选择项", - "loadingSelectorsDescription": "正在获取模式和会话配置选项", - "initSessionTitle": "正在初始化 {agent} 会话", - "initSessionDescription": "正在创建会话并加载配置" - }, - "errors": { - "connectionFailed": "连接失败", - "sendPromptFailed": "消息发送失败:{error}" - } - }, - "shared": { - "attachedResources": "附加资源", - "toolCallFailed": "工具调用失败" - }, - "messageThread": { - "emptyTitle": "暂无消息", - "emptyDescription": "开始一个会话后,消息会显示在这里" - }, - "chatInput": { - "connecting": "连接中...", - "agentResponding": "{agent} 正在响应...", - "sendMessage": "发送消息..." - }, - "messageInput": { - "askAnything": "请开始输入...", - "removeAttachmentAria": "移除 {name}", - "attachFiles": "附加文件", - "attachLocalUpload": "附加本地文件", - "attachServerFile": "附加服务端文件", - "addActions": "添加", - "quickMessages": "快捷消息", - "quickMessagesEmpty": "暂无快捷消息", - "quickMessagesLoading": "加载中...", - "pasteAsPlainText": "粘贴为纯文本", - "cut": "剪切", - "copy": "复制", - "selectAll": "全选", - "pasteUnavailable": "无法读取剪贴板,请改用 Ctrl/⌘V 粘贴。", - "clipboardWriteFailed": "无法写入剪贴板,请改用键盘快捷键。", - "quickMessageUntitled": "未命名", - "liveFeedback": "实时反馈", - "liveFeedbackDisabledHint": "智能体工作时可发送", - "dropFilesToAttach": "拖拽文件到此处附加", - "loadingSettings": "正在加载设置...", - "loadingMode": "正在加载模式...", - "modeLabel": "模式", - "toggleOn": "开", - "toggleOff": "关", - "agentSettings": "智能体设置", - "searchModel": "搜索模型...", - "searchModelAria": "搜索模型", - "modelListLabel": "模型", - "noModels": "未找到模型", - "cancel": "取消", - "send": "发送", - "forkAndSend": "分叉发送", - "queueMessage": "加入队列", - "steerIntoTurn": "插入当前回合", - "steerQueuedInstead": "已转入队列——将随下一回合发送。", - "steerFailed": "无法插入当前回合", - "steerAttachmentsUnsupported": "仅支持纯文本——带附件的草稿请走队列。", - "slashCommands": "斜杠命令", - "slashSearchPlaceholder": "搜索命令...", - "slashSearchEmpty": "没有匹配的命令", - "experts": "专家", - "office": "日常办公", - "research": "科学研究", - "attachUploadTooLarge": "{names} 超过 {limit}MB 上传上限,已跳过。", - "attachUploadFailed": "上传失败:{names}。", - "attachUploadNotAFile": "{names} 不是常规文件(目录或特殊文件),已跳过。", - "attachUploadQuotaExceeded": "服务器上传空间已用尽,{names} 未能上传。", - "attachUploadInProgress": "图片仍在上传中,请稍候再发送。", - "mentionEmpty": "无匹配项", - "mentionLoading": "搜索中…", - "mentionListLabel": "提及", - "mentionMore": "还有更多结果,继续输入以筛选", - "mentionCount": "{count, plural, other {# 项结果}}", - "mentionGroupFile": "文件", - "mentionGroupAgent": "智能体", - "mentionGroupSession": "会话", - "mentionGroupCommit": "提交", - "mentionGroupSkill": "技能" - }, - "messageQueue": { - "addToQueue": "加入队列", - "saveEdit": "保存", - "cancelEdit": "取消编辑", - "editItem": "编辑", - "deleteItem": "删除" - }, - "welcomeInputPanel": { - "agentsSettingsPath": "设置 > Agents", - "autoConnectFallback": "点击前往 {path} 管理安装。", - "autoConnectAppend": "{message},点击前往 {path} 管理安装。", - "enableAgentFirstPlaceholder": "请先启用至少一个 Agent 后开始会话...", - "prepareSessionFailed": "无法准备聊天会话,请重试。", - "createConversationFailed": "无法创建会话,请重试。", - "askAnythingPlaceholder": "请开始输入...", - "agentNotInstalled": "{agent} 尚未安装 · 点击前往 Agents 设置安装", - "agentAdapterNotInstalled": "{agent} 的 ACP 适配器尚未安装(与你本地的 CLI 无关)· 点击前往 Agents 设置安装" - }, - "welcomePanel": { - "greeting": "今天准备做些什么呢?", - "tips": { - "tileTabs": "右键点击会话标签选择「平铺显示」,可同屏对比多个会话", - "pinTab": "双击会话标签可将其固定,避免被新打开的会话自动替换", - "shortcutsNewSearch": "{newConversation} 快速新建会话,{searchConversations} 搜索历史会话", - "slashAtMention": "在输入框输入 / 触发斜杠命令,输入 @ 引用项目内文件", - "pasteDropFiles": "直接粘贴截图或把文件拖到输入框,即可作为附件", - "queueMessage": "智能体回复中也能继续输入并排队,回答完毕会自动续发", - "draftAutoSave": "未发送的草稿会自动保存,重新打开会话仍在", - "forkSend": "发送按钮旁的下拉选择「分叉发送」,从当前位置开一条新分支", - "exportConversation": "右键会话内容区可导出为 Markdown / HTML / 图片", - "chatChannels": "在「设置 → 聊天频道」接入 Telegram / 飞书 / 微信,从手机继续操作", - "shortcutsAuxPanel": "{toggleAuxPanel} 切换右侧面板,查看本次会话改动的文件与 Git 变更", - "shortcutsTerminalSidebar": "{toggleTerminal} 打开内置终端,{toggleSidebar} 切换侧边栏", - "customShortcuts": "所有快捷键都可在「设置 → 快捷键」中自定义", - "webService": "开启「设置 → Web 服务」后,团队成员可从浏览器接入同一台 codeg", - "fusionMode": "打开文件或差异后,会自动与会话并排显示", - "quickMessages": "点输入框旁的 + 按钮选择「快捷消息」,可一键插入预存片段(在「设置 → 快捷消息」中管理)", - "experts": "通过 + 按钮里的「专家技能」可一键加载预设角色(调试 / 规划等)", - "taskBoard": "「待办任务」能把一条待办从头跑到尾:智能体在独立工作树里干活,你 review 完差异再合并。", - "automations": "「自动化」按计划定时跑保存好的提示词(比如每晚一次代码评审),还能让每次运行都开一个独立工作树。", - "tokenUsage": "点击状态栏左下角的会话数即可打开「Token 用量」,按天、智能体、模型和文件夹拆分统计。", - "mentionTargets": "@ 不只能引用文件:还能 @ 另一个智能体把子任务交给它,或引用历史会话、某次提交、某个技能。", - "splitGroups": "右键点击标签选择「向右拆分」或「向下拆分」,两个会话各占一个分栏同时开着。", - "worktrees": "点开分支按钮选「新建工作树」,多个智能体就能在同一个仓库并行干活,互不覆盖彼此的文件。", - "importSessions": "之前在终端里跑过的会话,用文件夹右键菜单的「导入本地会话」就能把那段历史接进 codeg。", - "subSessions": "智能体委派出去的子会话会嵌套显示在侧边栏的父会话下面,展开就能跟踪每一个子会话做了什么。", - "liveFeedback": "「+」菜单里的「实时反馈」能把一条便条塞进智能体正在跑的这一轮,不用打断它。", - "skillPacks": "设置 → 技能包 里打包了编程专家、科研和办公三类技能,可以按智能体分别开关。", - "modelProviders": "设置 → 模型供应商 支持填自己的 API key 或接口地址,之后直接在输入框里切换模型。", - "workspaceBackground": "设置 → 外观 里可以换工作区背景图、调面板不透明度,还能换应用字体。" - }, - "quickActions": { - "excel": "Excel 工作簿", - "excelDesc": "数据表、公式和图表", - "word": "Word 文档", - "wordDesc": "报告、信函和备忘录", - "ppt": "演示文稿", - "pptDesc": "专业设计的幻灯片", - "pitchDeck": "融资路演", - "pitchDeckDesc": "含关键指标的路演 PPT", - "morph": "Morph 动画", - "morphDesc": "电影级幻灯片转场", - "morph3d": "3D Morph", - "morph3dDesc": "3D 模型与镜头运动", - "academic": "学术论文", - "academicDesc": "含引用与结构的研究论文", - "financial": "财务模型", - "financialDesc": "报表、DCF 与预测", - "dashboard": "数据仪表盘", - "dashboardDesc": "从数据生成 KPI 与分析", - "prompts": { - "excel": "创建一个 Excel 工作簿,要求如下:\n\n[在此描述你的数据、表格、公式和图表]", - "word": "创建一个 Word 文档,要求如下:\n\n[在此描述文档内容、结构和排版]", - "ppt": "创建一个 PowerPoint 演示文稿,要求如下:\n\n[在此描述幻灯片、内容和设计]", - "pitchDeck": "创建一个融资路演 PPT,要求如下:\n\n[在此描述公司、融资轮次和关键指标]", - "morph": "创建一个带 Morph 转场动画的演示文稿:\n\n[在此描述演示主题和期望的视觉效果]", - "morph3d": "创建一个带 GLB 模型和镜头运动的 3D Morph 演示文稿:\n\n[在此描述主题和 3D 视觉构想]", - "academic": "用 Word 写一篇学术论文,要求如下:\n\n[在此描述研究主题、方法和主要发现]", - "financial": "用 Excel 创建一个财务模型,要求如下:\n\n[在此描述财务报表、预测和分析]", - "dashboard": "用 Excel 创建一个数据仪表盘,要求如下:\n\n[在此描述数据来源、KPI 和图表]", - "scientific-brainstorming": "帮我进行科研头脑风暴:探索跨学科联系、挑战假设、发现有潜力的研究空白。我正在探索的方向:", - "hypothesis-generation": "帮我把这些观察转化为可检验的假设:给出明确预测、合理机制,并设计验证实验。我的观察:", - "experimental-design": "在采集数据前帮我设计严谨的实验:设计方案、随机化、对照,以及如何避免混杂。我想研究的问题:", - "statistical-power": "帮我确定所需样本量:为我的设计做功效分析(效应量、显著性水平、功效)。具体信息:", - "statistical-analysis": "帮我正确分析这份数据:选择合适的检验、检查假设、报告效应量并撰写结论。我的数据与问题:", - "exploratory-data-analysis": "对我的数据文件做探索性分析:概述其结构、质量与值得注意的模式,并建议后续步骤。文件是:", - "scientific-visualization": "帮我制作出版级图表:清晰布局、真实误差棒、色盲友好配色,以及期刊格式。我想展示的内容:", - "scientific-critical-thinking": "帮我批判性评估这项研究或主张:评估证据质量、识别偏倚与混杂,并权衡结论。内容如下:", - "paper-lookup": "帮我在学术数据库中查找相关论文与开放获取全文,并提供可复用的引用。我要找的是:" - }, - "paper-lookup": "论文检索", - "paper-lookupDesc": "检索 10 个学术 API(PubMed、arXiv、OpenAlex、Crossref…)查找论文、引用与开放获取全文。", - "scientific-critical-thinking": "批判性思维", - "scientific-critical-thinkingDesc": "评估科学主张与证据质量:识别偏倚与混杂,运用 GRADE 与偏倚风险框架。", - "scientific-visualization": "科学可视化", - "scientific-visualizationDesc": "出版级图表:多面板布局、显著性标注与期刊专属格式。", - "exploratory-data-analysis": "探索性数据分析", - "exploratory-data-analysisDesc": "对 200+ 种格式的科学数据文件做自动化探索,输出质量指标与报告。", - "statistical-analysis": "统计分析", - "statistical-analysisDesc": "引导式统计分析:检验选择、假设检查、效应量与 APA 格式报告。", - "statistical-power": "统计功效", - "statistical-powerDesc": "样本量与统计功效分析:所需样本数、最小可检测效应与功效曲线。", - "experimental-design": "实验设计", - "experimental-designDesc": "在采集数据前设计严谨研究:随机化、区组、对照与析因/DOE 布局。", - "hypothesis-generation": "假设生成", - "hypothesis-generationDesc": "将观察转化为可检验的假设,给出预测、机制并设计验证实验。", - "scientific-brainstorming": "科学头脑风暴", - "scientific-brainstormingDesc": "开放式科研构思:探索跨学科联系、挑战假设、发现研究空白。", - "tabs": { - "office": "日常办公", - "coding": "代码开发", - "research": "科学研究" - }, - "coding": { - "brainstormingDesc": "动手前先梳理意图与需求", - "debuggingDesc": "先定位根因再提出修复", - "writingSkillsDesc": "创建、编辑并验证可复用技能" - }, - "notEnabled": { - "title": "「{skill}」技能尚未对 {agent} 启用", - "description": "前往设置启用后即可在此使用。", - "action": "去启用", - "hint": "技能未启用" - }, - "scrollPrev": "显示上一组技能", - "scrollNext": "显示下一组技能" - } - }, - "agentSelector": { - "noEnabledAgents": "暂无已启用的 Agent", - "openAgentsSettings": "打开 Agents 设置", - "notInstalled": "未安装", - "moreAgents": "更多 Agent({count})" - }, - "subAgentOverlay": { - "title": "子智能体", - "collapsedSummary": "子智能体 {count}", - "collapseAria": "折叠子智能体" - }, - "agentPlanOverlay": { - "title": "计划任务", - "collapsePlanAria": "折叠计划", - "collapsedSummary": "计划 {completed}/{total}", - "status": { - "completed": "已完成", - "inProgress": "进行中", - "pending": "待处理", - "unknown": "未知" - }, - "priority": { - "high": "高", - "medium": "中", - "low": "低", - "unknown": "未知" - } - }, - "permissionDialog": { - "subtitle": "Agent 请求继续当前轮次的权限。", - "queuedCount": "还有 {count} 项待审批", - "kindFallbackTool": "工具", - "command": "命令", - "cwd": "工作目录:{cwd}", - "filesSummary": "文件:{count}", - "moreFiles": "+{count} 个更多文件", - "plan": "计划", - "allowedActions": "允许的操作", - "targetMode": "目标模式:{mode}", - "optionGrants": "各选项将授予的权限", - "changeScopeSession": "本次会话", - "changeScopeProcess": "本次运行", - "changeScopeUser": "保存到用户设置", - "changeScopeProject": "保存到项目设置", - "changeScopeProjectLocal": "保存到本地项目设置", - "changeScopePersistent": "永久保存" - }, - "questionDialog": { - "title": "代理正在提问", - "placeholder": "输入你的回答...", - "send": "发送" - }, - "messageBranch": { - "previousBranchAria": "上一分支", - "nextBranchAria": "下一分支", - "pageOf": "{current} / {total}" - }, - "terminal": { - "title": "终端", - "running": "运行中" - }, - "reasoning": { - "thinking": "思考中…", - "thoughtForFewSeconds": "思考", - "thoughtForSeconds": "思考" - }, - "linkSafety": { - "errorCannotOpen": "无法打开本地文件", - "errorNoWorkspace": "当前没有活跃的工作区文件夹。", - "errorFailedOpen": "打开本地文件失败", - "errorFailedLink": "打开链接失败", - "errorUnsupportedLinkProtocol": "不支持该链接协议。" - }, - "fileActions": { - "openInFinder": "在访达打开", - "openInExplorer": "在资源管理器打开", - "openInFileManager": "在文件管理器打开", - "copyRelativePath": "复制相对路径", - "copyAbsolutePath": "复制绝对路径", - "pathCopied": "已复制路径", - "copyPathFailed": "复制路径失败", - "openFailed": "打开本地文件失败" - }, - "messageList": { - "attachedResources": "附加资源", - "loading": "加载中...", - "loadEarlier": "加载更早的消息", - "loadingEarlier": "正在加载更早的消息…", - "error": "错误:{message}", - "errorTitle": "会话加载失败", - "errorActionReload": "重新加载", - "errorActionNewSession": "新建会话", - "emptyConversation": "当前会话暂无消息。", - "systemMessage": "系统消息", - "copyMessage": "复制", - "copied": "已复制", - "downloadImage": "下载图片", - "downloadFailed": "下载失败:{message}", - "imageGeneration": "图片生成", - "imageGenerationPending": "正在生成图片…", - "imageGenerationFailed": "图片生成失败", - "model": "模型", - "tokenStats": "Token 使用情况", - "tokenInput": "输入", - "tokenOutput": "输出", - "tokenCacheRead": "缓存读取", - "tokenCacheWrite": "缓存写入", - "duration": "耗时", - "completedAt": "完成时间", - "jumpToPreviousUserMessage": "跳转到上一条用户消息", - "showMore": "展开", - "showLess": "收起" - }, - "liveTurnStats": { - "thinking": "思考中...", - "streaming": "生成中", - "elapsedHours": "{value} 小时", - "elapsedMinutes": "{value} 分钟", - "elapsedSeconds": "{value} 秒", - "outputSpeedAria": "估算输出速度", - "outputSpeedTooltip": "估算输出速度(正文 + 思考)" - }, - "jsonTree": { - "viewRaw": "查看原始 JSON", - "viewTree": "查看树状视图", - "fields": "{count} 个字段", - "items": "{count} 项" - }, - "tool": { - "parameters": "参数", - "error": "错误", - "result": "结果", - "status": { - "approvalRequested": "等待授权", - "approvalResponded": "已响应", - "inputAvailable": "运行中", - "inputStreaming": "等待中", - "outputAvailable": "已完成", - "outputDenied": "已拒绝", - "outputError": "错误" - } - }, - "toolCallBlock": { - "tool": "工具", - "error": "错误", - "result": "结果" - }, - "delegation": { - "subAgentRunning": "子智能体运行中…", - "noDetail": "暂无详情。", - "unknownAgent": "子智能体", - "openDetail": "查看会话", - "detailTitle": "子智能体会话", - "detailDescription": "只读查看委托给子智能体的会话内容。", - "waitForResult": "等待 {task} 任务执行结果", - "waitForResultNoTask": "等待任务执行结果", - "cancelTask": "取消 {task} 任务", - "cancelTaskNoTask": "取消任务", - "resultPageOf": "{current} / {total}", - "prevResult": "上一个结果", - "nextResult": "下一个结果", - "noResultText": "本次检查暂无结果", - "status": { - "starting": "启动中", - "running": "运行中", - "checked": "已查询", - "waiting": "待批准", - "ok": "完成", - "err": { - "default": "失败", - "delegation_disabled": "已禁用", - "depth_limit": "深度超限", - "invalid_agent_type": "代理类型无效", - "spawn_failed": "启动失败", - "send_failed": "发送失败", - "timeout": "超时", - "canceled": "已取消", - "child_refusal": "子代理拒绝", - "child_max_tokens": "子代理超出 token 上限", - "child_max_turn_requests": "子代理超出请求上限", - "child_empty": "子代理无响应", - "child_unknown": "子代理未知错误", - "unknown": "未知任务" - } - } - }, - "contentParts": { - "showingTailOutput": "为保证性能,流式输出时仅显示尾部内容。", - "result": "结果", - "unknown": "未知", - "inputTruncated": "输入已截断,diff 可能不完整。", - "replaceAll": "全部替换", - "filesCount": "文件:{count}", - "update": "更新", - "moreFiles": "+{count} 个更多文件", - "timeoutMs": "超时:{timeout}ms", - "backgroundTrue": "后台:true", - "scriptToolCalls": "调用 {count} 个工具", - "offset": "偏移:{offset}", - "limit": "限制:{limit}", - "pages": "页码:{pages}", - "mode": "模式:{mode}", - "cell": "单元:{cell}", - "shellSession": "会话 {id}", - "pathLabel": "路径:", - "globLabel": "Glob:", - "typeLabel": "类型:", - "outputLabel": "输出:", - "caseInsensitive": "忽略大小写", - "multiline": "多行", - "promptLabel": "提示词", - "subjectLabel": "主题", - "taskLabel": "任务", - "nameLabel": "名称:", - "agentPromptLabel": "提示词", - "agentModelLabel": "模型", - "agentRunning": "运行中...", - "agentLiveTranscript": "实时活动", - "agentProgressTools": "{count} 次工具调用", - "agentProgressTurns": "{count} 轮", - "agentProgressContext": "上下文 {pct}%", - "agentSessionAction": "查看子智能体会话", - "agentSessionTitle": "子智能体会话", - "agentSessionLoading": "正在加载子智能体的会话记录…", - "agentSessionEmpty": "子智能体还没有写入任何内容。", - "agentFallbackTitle": "子智能体启动中…", - "agentCodexLaunchOnly": "已启动。Codex 不会再报告这个子智能体的进展——它的结果会作为一条消息出现在本会话中。", - "agentStatsBash": "命令", - "agentStatsRead": "读取文件", - "agentStatsSearch": "搜索", - "agentStatsEdit": "编辑", - "agentStatsOther": "其他", - "goal": { - "title": "目标:", - "titleWithStatus": "目标{status}", - "objective": "目标", - "statusLabel": "状态", - "tokensUsed": "已用 tokens", - "budget": "预算", - "remaining": "剩余", - "elapsed": "耗时", - "tokens": "tokens", - "pause": "暂停", - "clear": "清除", - "status": { - "active": "进行中", - "paused": "已暂停", - "blocked": "受阻", - "usageLimited": "用量受限", - "budgetLimited": "预算受限", - "complete": "已完成", - "limited": "已达上限" - } - }, - "field": { - "file": "文件", - "notebook": "笔记本", - "command": "命令", - "old": "旧内容", - "new": "新内容", - "pattern": "模式", - "path": "路径", - "query": "查询", - "url": "URL地址", - "description": "描述", - "content": "内容", - "source": "源内容", - "prompt": "提示词", - "subject": "主题", - "taskId": "任务 ID", - "status": "状态", - "skill": "Skill", - "args": "参数", - "offset": "偏移", - "limit": "限制", - "glob": "Glob", - "type": "类型", - "output": "输出", - "replaceAll": "全部替换", - "language": "语言", - "timeout": "超时", - "background": "后台", - "agentType": "Agent 类型", - "library": "库", - "libraryId": "库 ID" - }, - "title": { - "edit": "编辑", - "command": "命令", - "script": "脚本", - "waitCommand": "等待 {command}", - "waitCell": "等待会话 {id}", - "terminateCommand": "终止 {command}", - "terminateCell": "终止会话 {id}", - "stdinChars": "输入 {chars}", - "todoWrite": "待办", - "read": "读取", - "write": "写入", - "notebookEdit": "Notebook 编辑", - "editFiles": "编辑({count} 个文件)", - "editWithTarget": "编辑 {target}", - "readWithTarget": "读取 {target}", - "writeWithTarget": "写入 {target}", - "notebookEditWithTarget": "Notebook 编辑 {target}", - "globWithPattern": "Glob {pattern}", - "listFilesWithPath": "列出文件 {path}", - "grepWithPattern": "Grep {pattern}", - "taskCreateWithSubject": "创建任务:{subject}", - "taskUpdateWithStatus": "更新任务 #{id} -> {status}", - "taskUpdate": "更新任务 #{id}", - "webFetchWithUrl": "抓取网页 {url}", - "webSearchWithQuery": "网页搜索:{query}", - "todosProgress": "待办({done}/{total})", - "skillWithName": "Skill:{name}", - "genericWithContext": "{tool}:{context}" - }, - "search": { - "noMatches": "无匹配结果", - "matchSummary": "{matches} 处匹配 · {files} 个文件", - "fileSummary": "{files} 个文件", - "moreResults": "另有 {count} 条结果未显示" - }, - "toolGroup": { - "search": "搜索 {count} 次", - "command": "运行 {count} 个命令", - "read": "读取 {count} 次文件", - "memory": "回忆 {count} 项记忆", - "edit": "编辑 {count} 次文件", - "fetch": "抓取 {count} 个资源", - "think": "思考 {count} 次", - "todo": "更新 {count} 项待办", - "task": "执行 {count} 个任务", - "other": "调用 {count} 个工具", - "errorSuffix": "{count} 个失败", - "joiner": " · " - }, - "planMode": { - "entered": "进入计划模式", - "planLabel": "计划", - "reviewApproved": "已批准执行计划", - "reviewKept": "保持在计划模式", - "reviewPending": "等待计划决定", - "submitted": "计划已提交", - "switched": "切换模式" - }, - "backgroundTask": { - "title": "后台任务", - "titleWithId": "后台任务 · {id}", - "running": "运行中", - "completed": "已完成", - "failed": "失败", - "stopped": "已停止", - "exitCode": "退出码 {code}", - "polledTimes": "轮询 {count} 次", - "runningInBackground": "后台运行", - "launchNote": "已在后台运行 · {id}" - }, - "codexScript": { - "outputMissing": "codex 截断脚本输出时丢掉了这条命令的分隔行,因此没有输出可以归属给它。", - "sharedWith": "本段还包含 {commands} 的输出——它们的分隔行被 codex 截断丢弃了。", - "truncated": "已截断" - } - }, - "messageNav": { - "title": "消息导航", - "collapse": "收起消息导航", - "collapsedSummary": "消息 {count}", - "fileCount": "{count} 个文件", - "remove": "移除", - "noDiffDataAvailable": "未找到 {filePath} 的差异数据" - }, - "replyArtifacts": { - "title": "改动文件", - "fileCount": "{count} 个文件", - "newFilesTitle": "新增文件", - "revealInFolder": "在访达/资源管理器中显示", - "openFile": "打开 {filePath}", - "openInEditor": "在编辑器中打开", - "remove": "移除", - "noDiffDataAvailable": "未找到 {filePath} 的差异数据" - }, - "askQuestion": { - "title": "智能体需要你的选择", - "subtitle": "回答后点击提交,可随时跳过", - "recommended": "推荐", - "other": "其他", - "otherPlaceholder": "输入你的回答…", - "singleSelect": "单选", - "multiSelect": "多选", - "skip": "跳过", - "next": "下一题", - "submit": "提交", - "submitError": "提交失败,请重试。" - }, - "planApproval": { - "title": "智能体已给出计划——请审阅", - "emptyPlan": "智能体未写入计划。可批准开始实施,或要求修改。", - "approve": "批准并开始", - "requestChanges": "要求修改", - "abandon": "放弃", - "feedbackPlaceholder": "需要修改什么?", - "sendChanges": "发送", - "cancel": "取消", - "submitError": "提交失败,请重试。" - }, - "feedbackCheckResult": { - "count": "{count} 条反馈", - "expand": "展开全部反馈", - "collapse": "收起", - "errorTitle": "反馈检查失败" - }, - "askQuestionResult": { - "title": "提问", - "answeredLabel": "提问回答:", - "awaiting": "等待你的回答…", - "declined": "你已忽略此问题 — 代理已自行判断。", - "noSelection": "未选择" - }, - "configStale": { - "agentConfigTitle": "智能体配置已更新", - "modelProviderTitle": "模型供应商已更新", - "description": "当前会话仍在使用旧配置,重连后生效(对话历史不会丢失)。", - "reconnect": "重连以应用", - "reconnecting": "正在重连…", - "reconnectDisabledDuringTurn": "当前回合结束后可重连", - "dismiss": "忽略", - "reconnectFailed": "重连会话失败", - "applied": "新配置已应用" - }, - "piProjectTrust": { - "title": "该项目自带 pi 资源", - "description": "pi 未加载仓库自带的 .pi 文件。请查看后决定。", - "descriptionExecutable": "仓库自带 pi 扩展,扩展会在启动时执行代码。pi 尚未加载它们,请先查看再决定。", - "review": "查看…", - "dismiss": "忽略", - "dialogTitle": "信任该项目的 pi 资源?", - "dialogDescription": "只有在你信任该目录后,pi 才会加载仓库自带的 .pi 文件。请仅在你信任该仓库内容时才信任。", - "executionWarning": "扩展就是代码。信任该目录后,仓库中的扩展会在 pi 启动时以你的权限执行——早于你发送任何消息。", - "scopeNote": "该决定保存在 pi 的 trust.json 中,对该目录下的所有子目录同样生效,你在终端里自己运行 pi 时也会沿用。之后可在「设置 → 智能体 → Pi」中修改。", - "trust": "信任项目", - "decline": "保持不加载", - "disabledDuringTurn": "当前回合结束后可用", - "trustedToast": "已信任项目——已重连以便 pi 加载其资源", - "declinedToast": "项目资源保持不加载", - "saveFailed": "保存项目信任决定失败", - "grantTitle": "该项目已被信任", - "grantDescription": "pi 会加载该仓库自带的 .pi 文件。请查看这意味着什么。", - "grantInheritedDescription": "某个上级目录已被信任,因此 pi 会加载该仓库自带的 .pi 文件。请查看这意味着什么。", - "grantDialogTitle": "该项目的 pi 资源已被信任", - "grantDialogDescription": "pi 被允许加载该仓库自带的 .pi 文件。旧版本 codeg 会在你打开目录时自动授予该权限,因此你可能从未被询问过。", - "grantExecutionWarning": "扩展就是代码。仓库中的扩展会在 pi 启动时以你的权限执行——早于你发送任何消息。", - "inheritedFrom": "信任来自", - "revoke": "撤销信任", - "keepTrusted": "保持信任", - "revokedToast": "已撤销信任——已重连,pi 不再加载该项目的资源", - "trustedNoReconnect": "已信任项目——将在 pi 下次启动时生效", - "revokedNoReconnect": "已撤销信任——将在 pi 下次启动时生效" - }, - "collabAgent": { - "title": "子智能体", - "errorTitle": "子智能体任务失败", - "statesLabel": "子智能体", - "statusRunning": "运行中", - "statusCompleted": "已完成", - "statusFailed": "失败", - "statusPending": "初始化中", - "statusInterrupted": "已中断", - "statusClosed": "已关闭", - "statusNotFound": "未找到", - "opSpawn": "启动子智能体", - "opWait": "获取子智能体结果", - "opClose": "结束子智能体", - "opResume": "恢复子智能体" - }, - "contextCompaction": { - "compacting": "正在压缩上下文…", - "compacted": "上下文已压缩", - "compactedTokens": "上下文已压缩 · {before} → {after} tokens", - "failed": "上下文压缩失败" - }, - "sessionFailure": { - "category": { - "connection": "连接异常", - "access": "访问受限", - "limit": "已达限制", - "request": "请求被拒绝", - "service": "服务异常", - "unknown": "会话异常" - }, - "action": { - "retry": "重试", - "login": "去登录", - "newSession": "新建会话" - }, - "recovered": "已恢复", - "retryUnavailable": "没有可重发的消息。", - "toggleDetails": "展开/收起详情" - }, - "backgroundTasks": { - "running": "{count} 个后台任务运行中", - "settling": "正在同步后台结果…", - "settledFallback": "后台任务已结束({status})", - "cardRunning": "后台运行中", - "cardLaunchedPending": "已启动后台任务", - "cardCompleted": "后台任务已完成", - "cardFinishedWithStatus": "后台任务已结束({status})", - "cardResultPending": "结果尚未返回" - }, - "proposedPlan": { - "title": "计划提案", - "planning": "规划中…" - } - }, - "diffPreview": { - "mode": { - "added": "新增", - "deleted": "删除", - "renamed": "重命名", - "modified": "修改" - }, - "hunkLabel": "代码块 {index}", - "loadingHunk": "正在加载代码块...", - "noDiffData": "无差异数据", - "showRemainingLines": "显示剩余 {count} 行" - }, - "conversationContextBar": { - "folderTitle": "工作文件夹", - "branchTitle": "工作分支", - "searchFolder": "搜索文件夹...", - "searchBranch": "搜索分支...", - "noFolders": "暂无文件夹", - "noBranches": "暂无分支", - "noBranch": "(无分支)", - "chatModeLabel": "聊天模式", - "commit": "提交", - "push": "推送", - "merge": "合并", - "toasts": { - "folderChanged": "已切换到 {name}", - "openFolderFailed": "打开文件夹失败", - "switchedToChatMode": "已切换到聊天模式", - "openStashFailed": "打开贮藏窗口失败", - "openMergeFailed": "打开合并窗口失败" - } - }, - "cloneDialog": { - "title": "克隆仓库", - "repositoryUrl": "仓库地址", - "repositoryUrlPlaceholder": "https://github.com/user/repo.git", - "directory": "目录", - "directoryPlaceholder": "选择目标目录...", - "browseDirectory": "浏览目录", - "cancel": "取消", - "clone": "克隆", - "clonePath": "克隆路径: {path}" - }, - "toasts": { - "cloneFailed": "克隆仓库失败" - } - }, - "ProjectBoot": { - "title": "项目启动器", - "tabs": { - "shadcn": "shadcn", - "hyperframes": "HyperFrames" - }, - "hyperframes": { - "title": "HyperFrames 视频项目", - "subtitle": "脚手架一个 HTML 转视频项目,随后工作区的智能体即可编写并渲染它。", - "resolution": "分辨率", - "skillsTitle": "智能体技能", - "skillsDesc": "为所选智能体全局安装 HyperFrames 技能(软链接),让它们会编写并渲染视频。", - "recheck": "重新检查", - "installedBadge": "已安装", - "skillsInstall": "安装 / 更新技能", - "skillsInstalling": "正在安装技能…", - "skillsInstalled": "HyperFrames 技能安装成功", - "skillsInstallFailed": "HyperFrames 技能安装失败" - }, - "config": { - "base": "基础库", - "style": "风格", - "baseColor": "基础颜色", - "theme": "主题", - "chartColor": "图表颜色", - "iconLibrary": "图标库", - "font": "字体", - "fontHeading": "标题字体", - "menuAccent": "菜单强调", - "menuColor": "菜单颜色", - "radius": "圆角", - "template": "模板", - "createProject": "创建项目", - "sectionStyle": "风格", - "sectionColors": "配色", - "sectionTypography": "排版", - "sectionInterface": "界面" - }, - "preview": { - "loading": "加载预览..." - }, - "createDialog": { - "title": "创建项目", - "projectName": "项目名称", - "projectNamePlaceholder": "my-app", - "frameworkTemplate": "框架模板", - "packageManager": "包管理器", - "saveDirectory": "保存目录", - "saveDirectoryPlaceholder": "选择目录...", - "browseDirectory": "浏览", - "projectPath": "项目将创建在:{path}", - "advancedOptions": "高级选项", - "base": "基础库", - "enableRtl": "启用 RTL 支持", - "enableRtlDescription": "为从右到左书写的语言(如阿拉伯语、希伯来语)启用布局支持", - "pmChecking": "正在检测...", - "pmNotInstalled": "未安装", - "cancel": "取消", - "create": "创建", - "creating": "正在创建项目..." - }, - "toasts": { - "createFailed": "创建项目失败", - "createSuccess": "项目创建成功", - "openWorkspaceFailed": "项目已创建,但无法在工作区中打开" - }, - "errors": { - "directoryExists": "目标目录已存在", - "commandFailed": "项目创建命令执行失败。" - } - }, - "WebServiceSettings": { - "addressSwitchHint": "切换只改变这里显示和打开的地址;服务监听所有网卡,每个地址都可访问。", - "sectionTitle": "Web 服务", - "sectionDescription": "启用后可通过浏览器远程访问 Codeg", - "port": "端口", - "status": "状态", - "autoStart": "自动启动", - "autoStartHint": "Codeg 启动时自动开启 Web 服务", - "running": "运行中", - "stopped": "已停止", - "processing": "处理中...", - "start": "启动", - "stop": "停止", - "startFailed": "启动失败", - "stopFailed": "停止失败", - "saveConfigFailed": "保存 Web 服务设置失败", - "open": "打开", - "hide": "隐藏", - "show": "显示", - "copy": "复制", - "qrcode": "二维码", - "qrcodeTitle": "扫码打开", - "qrcodeHint": "用手机扫描,在浏览器中打开 Codeg", - "addressLabel": "访问地址", - "tokenLabel": "访问 Token", - "tokenHint": "Web 客户端首次访问时需输入此 Token", - "tokenPlaceholder": "留空则自动生成", - "regenerate": "重新生成", - "stalePortOccupiedTitle": "端口 {port} 已被其他进程占用", - "stalePortUnknownTitle": "端口 {port} 状态未知", - "stalePortHint": "在端口释放前 Codeg 无法绑定。可以更换上方的端口,或结束占用该端口的进程。", - "errors": { - "alreadyRunning": "Web 服务已在运行", - "invalidAddress": "主机或端口格式无效", - "portInUse": "端口 {port} 已被占用,请关闭占用该端口的程序或更换其他端口", - "permissionDenied": "权限不足,请使用 1024 以上的端口,或以更高权限运行", - "addressUnavailable": "该地址在本机不可用", - "bindFailed": "绑定地址失败" - } - }, - "DirectoryBrowser": { - "title": "浏览目录", - "pathPlaceholder": "输入目录路径...", - "goHome": "回到主目录", - "navigateUp": "返回上级目录", - "select": "选择", - "cancel": "取消", - "loading": "加载中...", - "emptyDirectory": "此目录为空", - "errorLoadingDir": "加载目录失败", - "permissionDenied": "权限不足" - }, - "ServerFileBrowser": { - "title": "选择服务端文件", - "pathPlaceholder": "输入目录路径...", - "goHome": "回到主目录", - "navigateUp": "返回上级目录", - "select": "选择", - "cancel": "取消", - "loading": "加载中...", - "emptyDirectory": "此目录为空", - "errorLoadingDir": "加载目录失败", - "selectedCount": "已选 {count} 项" - }, - "ChatChannelSettings": { - "loading": "加载中...", - "sectionTitle": "消息渠道", - "sectionDescription": "配置 IM 机器人,接收事件通知和查询编码活动。", - "addChannel": "添加渠道", - "noChannels": "尚未配置任何消息渠道。", - "channelName": "名称", - "channelNamePlaceholder": "我的 Telegram 机器人", - "channelType": "渠道类型", - "lark": "飞书", - "weixin": "微信", - "dailyReport": "每日报告", - "dailyReportTime": "推送时间", - "nameRequired": "请输入渠道名称。", - "tokenRequired": "请输入 Token。", - "chatIdRequired": "请输入 Chat ID。", - "topicMode": "话题群模式", - "topicModeHint": "将 Telegram forum topics 路由为独立 Codeg 会话。Bot 必须加入 forum supergroup,并拥有管理 topics 权限。", - "loadFailed": "加载渠道失败。", - "saveFailed": "保存失败。", - "connectSuccess": "渠道已连接。", - "connectFailed": "连接失败", - "disconnectSuccess": "渠道已断开。", - "disconnectFailed": "断开连接失败。", - "testSuccess": "连接测试通过。", - "testFailed": "连接测试失败", - "deleteSuccess": "渠道已删除。", - "deleteFailed": "删除渠道失败。", - "deleteConfirmTitle": "删除渠道", - "deleteConfirmMessage": "将永久删除该渠道及其消息日志,确定吗?", - "cancel": "取消", - "delete": "删除", - "create": "创建", - "save": "保存", - "channelListTitle": "已配置渠道", - "channelListDescription": "已启用的渠道在服务启动时会自动连接。", - "editChannel": "编辑渠道", - "editSuccess": "渠道已更新。", - "tokenPlaceholderKeep": "留空保持不变", - "weixinScanTitle": "扫码登录", - "weixinScanDescription": "打开微信扫描二维码以连接。", - "weixinQrcodeExpired": "二维码已过期。", - "weixinRefreshQrcode": "刷新二维码", - "weixinWaitingScan": "等待扫码...", - "weixinPollError": "连接不稳定,正在重试...", - "weixinReconnectNotice": "因 iLink 协议限制,每次重新连接后需先主动向机器人发送一条消息,事件触发才会生效。", - "connect": "连接", - "disconnect": "断开", - "test": "测试连接", - "tabs": { - "channels": "渠道", - "commands": "指令", - "events": "事件", - "other": "其他" - }, - "commands": { - "title": "内置指令", - "description": "消息渠道中可用的 Bot 指令。群聊中需 @Bot 才会处理消息。", - "prefixLabel": "指令前缀", - "prefixDescription": "触发 Bot 指令的前缀,1-3 个非字母数字字符(默认 /)。", - "prefixSaved": "指令前缀已保存。", - "prefixSaveFailed": "保存指令前缀失败。", - "prefixInvalid": "前缀必须是 1-3 个非字母数字字符。", - "save": "保存", - "folderDesc": "选择工作目录", - "agentDesc": "选择 AI Agent", - "taskDesc": "创建会话并执行任务", - "sessionsDesc": "列出当前目录的活跃会话", - "resumeDesc": "最近会话 / 恢复指定会话", - "cancelDesc": "取消当前任务", - "approveDesc": "批准 Agent 权限请求", - "denyDesc": "拒绝 Agent 权限请求", - "searchDesc": "按关键词搜索会话", - "todayDesc": "今日活动汇总", - "statusDesc": "渠道连接状态", - "helpDesc": "显示帮助" - }, - "events": { - "title": "事件通知", - "description": "启用事件后,事件被触发时将推送到渠道。", - "turnComplete": "对话完成", - "turnCompleteDesc": "代理回合结束时", - "error": "代理错误", - "errorDesc": "代理遇到错误时", - "permissionRequest": "权限请求", - "permissionRequestDesc": "智能体请求操作权限时", - "questionRequest": "智能体提问", - "questionRequestDesc": "当智能体向你提问时", - "userPromptSent": "用户消息", - "userPromptSentDesc": "当你发送消息时——通知中会包含消息内容", - "saved": "事件过滤已更新。", - "saveFailed": "保存事件过滤失败。", - "loadFailed": "加载设置失败。", - "retry": "重试", - "webhooksTitle": "Webhook", - "webhooksDescription": "事件触发时,向一个或多个地址 POST 一份 JSON。上方的事件过滤同样作用于 Webhook。", - "webhookUrlPlaceholder": "https://example.com/webhook", - "addWebhook": "添加 Webhook", - "removeWebhook": "删除 Webhook", - "webhookSave": "保存", - "webhooksSaved": "Webhook 已保存。", - "webhooksSaveFailed": "保存 Webhook 失败。", - "webhookInvalidUrl": "请输入有效的 http(s) 地址。", - "docsTitle": "请求格式", - "docsMethod": "请求方式", - "docsContentType": "内容类型", - "docsNote": "每个启用的事件都会投递到所有地址。Webhook 不做去抖;上方的事件过滤仍然生效。", - "editWebhook": "编辑 Webhook", - "enableWebhook": "启用 Webhook", - "webhookDuplicate": "该地址已配置。", - "cancel": "取消", - "webhooksEmpty": "尚未配置 Webhook。", - "deleteWebhookTitle": "删除 Webhook", - "deleteWebhookMessage": "删除此 Webhook?事件将不再投递到该地址。", - "delete": "删除" - }, - "language": { - "title": "消息语言", - "description": "事件通知、指令响应和每日报告推送到消息渠道时使用的语言。", - "saved": "消息语言已保存。", - "saveFailed": "保存消息语言失败。", - "en": "英语", - "zh-cn": "简体中文", - "zh-tw": "繁体中文", - "ja": "日语", - "ko": "韩语", - "es": "西班牙语", - "de": "德语", - "fr": "法语", - "pt": "葡萄牙语", - "ar": "阿拉伯语" - } - }, - "ModelProviderSettings": { - "sectionTitle": "模型供应商", - "sectionDescription": "管理 Agent 的 API 供应商凭据。", - "filterAll": "全部", - "providerListTitle": "已配置的供应商", - "addProvider": "添加供应商", - "editProvider": "编辑供应商", - "noProviders": "尚未配置模型供应商。", - "providerName": "名称", - "providerNamePlaceholder": "例如 OpenAI、Anthropic", - "apiUrl": "API 地址", - "apiUrlPlaceholder": "https://api.openai.com/v1", - "apiKey": "API 密钥", - "apiKeyPlaceholder": "sk-...", - "apiKeyKeepCurrent": "留空则保持不变", - "agentTypes": "代理类型", - "agentTypesRequired": "至少选择一个代理类型。", - "agentType": "智能体类型", - "agentTypeRequired": "请选择智能体类型。", - "agentTypeImmutableHint": "智能体类型创建后不可修改。", - "model": "模型", - "modelPlaceholderCodex": "gpt-5.6-sol / gpt-5.5", - "modelPlaceholderGemini": "gemini-3-pro-preview", - "claudeMainModel": "主模型", - "claudeReasoningModel": "推理模型(思考)", - "claudeHaikuDefaultModel": "默认 Haiku 模型", - "claudeSonnetDefaultModel": "默认 Sonnet 模型", - "claudeOpusDefaultModel": "默认 Opus 模型", - "claudeCustomModelOption": "自定义模型 ID", - "claudeCustomModelOptionName": "自定义模型名称", - "claudeCustomModelOptionDescription": "自定义模型描述", - "claudeCustomModelOptionHint": "在 Claude 模型选择器中追加一个自定义条目(例如经自定义网关/代理提供的模型)。名称与描述为可选的显示信息。", - "nameRequired": "供应商名称不能为空。", - "apiUrlRequired": "API 地址不能为空。", - "apiKeyRequired": "API 密钥不能为空。", - "loadFailed": "加载供应商失败。", - "saveFailed": "保存更改失败。", - "createSuccess": "供应商已创建。", - "editSuccess": "供应商已更新。", - "deleteSuccess": "供应商已删除。", - "deleteConfirmTitle": "删除供应商", - "deleteConfirmMessage": "确定要永久删除供应商「{name}」吗?", - "deleteBlockedByAgent": "{agents} 正在使用该配置,请先解除关联后再删除。", - "cancel": "取消", - "delete": "删除", - "create": "创建", - "save": "保存", - "affectedRunningSessions": "{count} 个进行中的会话需重连以应用更改" - }, - "SkillMatrix": { - "loading": "加载中…", - "searchPlaceholder": "按名称、ID 或描述搜索", - "empty": "暂无内容。", - "emptySearch": "没有匹配当前搜索的结果。", - "skillColumn": "技能", - "selectAll": "全选可见项", - "selectSkill": "选择 {name}", - "everything": { - "label": "批量", - "enable": "全部启用(可见)", - "disable": "全部禁用(可见)" - }, - "columnMenu": { - "enableAll": "启用全部技能", - "disableAll": "禁用全部技能" - }, - "rowMenu": { - "label": "对 {name} 批量操作", - "enableAll": "对所有 agent 启用", - "disableAll": "对所有 agent 禁用" - }, - "bulk": { - "selected": "已选择 {count} 项", - "targetAll": "全部 agent", - "targetSome": "{count} 个 agent", - "enable": "启用", - "disable": "禁用", - "clear": "清除" - }, - "confirm": { - "disableTitle": "禁用这些链接?", - "disableBody": "这将移除 {count} 个由 codeg 管理的技能链接。占用自定义目录的技能不受影响。你可以随时重新启用。", - "cancel": "取消", - "confirm": "禁用" - }, - "toasts": { - "loadFailed": "加载技能状态失败", - "applyFailed": "应用更改失败", - "enabled": "已启用 {count} 个链接", - "disabled": "已禁用 {count} 个链接", - "enabledPartial": "已启用 {ok} 个,{failed} 个失败", - "disabledPartial": "已禁用 {ok} 个,{failed} 个失败" - }, - "detail": { - "enableForAgents": "为 agent 启用", - "preview": "SKILL.md 预览", - "loadingContent": "加载内容中…" - }, - "copyModeHint": "已复制(非链接)——更新后请重新启用以获取最新版本" - }, - "ExpertsSettings": { - "title": "专家技能", - "description": "为 AI 编码代理启用精心挑选、经过实战验证的技能工作流。每个专家都是 superpowers 项目中的独立技能 —— codeg 维护中央副本,并将其软链接到你选择的代理目录。", - "loading": "正在加载专家列表…", - "loadingContent": "正在加载内容…", - "emptyExperts": "当前没有可用的专家,请查看应用日志。", - "emptySelection": "从左侧选择一个专家以查看内容并管理启用状态。", - "emptySearch": "没有匹配当前搜索条件的专家。", - "searchPlaceholder": "按名称、ID 或描述搜索专家", - "enableForAgents": "为代理启用", - "noAgents": "未检测到 ACP 代理。", - "copyModeWarning": "已复制(非软链接)。codeg 更新后需要重新启用以获取最新版本。", - "previewTitle": "SKILL.md 预览", - "categories": { - "discovery": "发现与设计", - "planning": "规划", - "execution": "执行", - "quality": "质量与测试", - "debugging": "调试", - "review": "评审与集成", - "meta": "元技能" - }, - "states": { - "not_linked": "未启用", - "linked_to_codeg": "已启用", - "linked_elsewhere": "冲突 — 已有其他链接", - "blocked_by_real_directory": "冲突 — 已有同名的自定义 skill 占用", - "broken": "链接损坏" - }, - "badges": { - "userModified": "用户修改过" - }, - "actions": { - "openCentralDir": "打开中央目录", - "refresh": "刷新" - }, - "toasts": { - "loadFailed": "加载专家详情失败", - "enabled": "已为该代理启用专家", - "disabled": "已为该代理禁用专家", - "enableFailed": "启用专家失败", - "disableFailed": "禁用专家失败", - "openFolderFailed": "打开目录失败" - } - }, - "ScienceSettings": { - "title": "科学研究技能", - "description": "为你的 AI 编码智能体启用精选的科学研究技能:假设生成、实验设计、统计、可视化、批判性评估与文献检索。codeg 管理中央副本,并将每个技能链接到你选择的智能体。", - "loading": "正在加载科学研究技能…", - "emptySkills": "没有可用的科学研究技能。请检查应用日志。", - "searchPlaceholder": "按名称、ID 或描述搜索科学研究技能", - "categories": { - "ideation": "构思", - "design": "研究设计", - "analysis": "分析", - "visualization": "可视化", - "evaluation": "评估", - "literature": "文献" - }, - "states": { - "not_linked": "未启用", - "linked_to_codeg": "已启用", - "linked_elsewhere": "冲突 — 已有其他链接", - "blocked_by_real_directory": "冲突 — 已有同名的自定义 skill 占用", - "broken": "链接损坏" - }, - "badges": { - "userModified": "用户修改过", - "needsKey": "需要密钥", - "needsSetup": "可能需环境" - }, - "actions": { - "openCentralDir": "打开中央目录", - "refresh": "刷新" - }, - "toasts": { - "openFolderFailed": "打开目录失败" - } - }, - "OfficeToolsSettings": { - "title": "Office 工具", - "description": "管理 OfficeCLI 技能,用于创建 Excel、Word 和 PowerPoint 文件。安装 OfficeCLI,同步技能,并为每个智能体启用。", - "loadingContent": "加载内容中…", - "emptySkills": "暂无技能。请先安装 OfficeCLI 并同步技能。", - "emptySelection": "选择一个技能查看内容和管理激活状态。", - "emptySearch": "没有匹配的技能。", - "searchPlaceholder": "按名称、ID 或描述搜索技能", - "enableForAgents": "为智能体启用", - "noAgents": "未检测到 ACP 智能体。", - "installFirst": "请先安装 OfficeCLI 以启用技能。", - "syncFirst": "请先同步技能以加载内容。", - "noContent": "暂无内容。", - "copyModeWarning": "已复制(非链接)。重新同步以获取最新版本。", - "previewTitle": "SKILL.md 预览", - "detection": { - "installed": "已安装", - "notInstalled": "未安装", - "notRunnable": "已安装但无法运行", - "installHint": "安装 OfficeCLI 以为 AI 智能体启用办公文档生成技能。", - "install": "安装", - "uninstall": "卸载", - "syncSkills": "同步技能" - }, - "categories": { - "general": "通用", - "presentations": "演示文稿", - "documents": "文档", - "spreadsheets": "电子表格" - }, - "states": { - "not_linked": "未启用", - "linked_to_codeg": "已启用", - "linked_elsewhere": "已阻止——存在其他链接", - "blocked_by_real_directory": "已阻止——自定义技能占用此名称", - "broken": "链接已损坏" - }, - "badges": { - "notSynced": "未同步" - }, - "actions": { - "refresh": "刷新" - }, - "toasts": { - "loadFailed": "加载技能详情失败", - "enabled": "已为此智能体启用技能", - "disabled": "已为此智能体禁用技能", - "enableFailed": "启用技能失败", - "disableFailed": "禁用技能失败", - "installSuccess": "OfficeCLI 安装成功", - "installFailed": "安装 OfficeCLI 失败", - "uninstallSuccess": "OfficeCLI 已卸载", - "uninstallFailed": "卸载 OfficeCLI 失败", - "syncSuccess": "已成功同步 {synced} 个技能", - "syncPartial": "已同步 {synced} 个技能,{errors} 个失败", - "syncFailed": "同步技能失败" - }, - "autoPreviewLabel": "自动打开预览", - "autoPreviewHint": "当智能体创建或编辑 Word、Excel、PowerPoint 文件时,自动打开其实时预览。" - }, - "SkillPacksSettings": { - "title": "技能包", - "description": "由 codeg 集中管理、并链接到各 AI 智能体的成套技能——编码专家、科学研究与办公文档工具。可在下方按智能体分别启用。", - "tabs": { - "experts": "专家", - "science": "科学研究", - "office": "办公工具", - "custom": "自定义" - }, - "actions": { - "openCentralDir": "打开中央目录", - "refresh": "刷新" - }, - "toasts": { - "openFolderFailed": "打开目录失败" - } - }, - "QuickMessagesSettings": { - "title": "快捷消息", - "description": "管理可复用的消息片段。拖拽以调整顺序。", - "loading": "加载快捷消息…", - "emptyList": "暂无快捷消息。点击“新建”创建一条。", - "emptySelection": "选择一条快捷消息进行编辑。", - "searchPlaceholder": "按标题或内容搜索", - "untitled": "未命名", - "actions": { - "new": "新建", - "save": "保存", - "delete": "删除", - "dragSort": "拖拽排序", - "dragSortMessage": "拖拽排序快捷消息:{name}" - }, - "fields": { - "title": "标题", - "titlePlaceholder": "为此消息取一个简短的标题", - "content": "内容", - "contentPlaceholder": "在此输入消息内容" - }, - "confirmDelete": { - "title": "删除快捷消息?", - "message": "将永久删除“{name}”。确定吗?", - "cancel": "取消", - "confirm": "删除" - }, - "toasts": { - "loadFailed": "加载快捷消息失败", - "createFailed": "创建快捷消息失败", - "saveFailed": "保存快捷消息失败", - "deleteFailed": "删除快捷消息失败", - "saveOrderFailed": "保存顺序失败", - "created": "已创建快捷消息", - "saved": "已保存快捷消息", - "deleted": "已删除快捷消息" - } - }, - "Pet": { - "badge": { - "running": "{count} 个运行中", - "waiting": "{count} 个待批准", - "error": "{count} 个出错" - }, - "panel": { - "title": "活动会话", - "empty": "没有活动会话", - "emptyHint": "正在运行或需要你处理的会话会显示在这里。", - "statusRunning": "运行中", - "statusWaiting": "等待中", - "statusError": "出错", - "subAgentOf": "子智能体" - }, - "menu": { - "scale": "缩放", - "openManager": "管理宠物", - "close": "关闭" - }, - "loadError": "加载宠物失败", - "missingPetIdParam": "未选中任何宠物", - "summonButton": "宠物", - "manager": { - "title": "桌面宠物", - "description": "悬浮在桌面上的伴侣,使用与 Codex 兼容的精灵图。", - "addPet": "添加宠物", - "importFromCodex": "从 Codex 导入", - "noPets": "暂无宠物。可以添加一只,或从 Codex 导入。", - "setActive": "设为活跃", - "active": "当前活跃", - "edit": "编辑", - "delete": "删除", - "deleteConfirm": "确认删除宠物 \"{name}\" 吗?会从磁盘上一并移除。", - "summon": "召唤宠物窗口", - "openCodexHelp": "Codex 宠物需位于 ~/.codex/pets/ 目录下,但未找到。", - "specRequirement": "精灵图宽度必须为 1536 像素,高度需为 208 像素的整数倍(如 1872 或 2288),并为带透明通道的 PNG 或 WebP。", - "form": { - "id": "宠物 ID", - "idHelp": "仅允许小写字母、数字、'-' 和 '_',最多 64 字符。", - "displayName": "显示名称", - "description": "描述 (可选)", - "spritesheet": "精灵图", - "chooseFile": "选择文件", - "replaceFile": "替换精灵图", - "saveCreate": "添加宠物", - "saveUpdate": "保存修改", - "cancel": "取消" - }, - "errors": { - "missingId": "宠物 ID 不能为空", - "missingName": "显示名称不能为空", - "missingSpritesheet": "必须选择一个精灵图", - "addFailed": "添加宠物失败", - "updateFailed": "更新宠物失败", - "deleteFailed": "删除宠物失败", - "loadFailed": "加载宠物列表失败", - "setActiveFailed": "设置活跃宠物失败", - "summonFailed": "召唤宠物窗口失败" - } - }, - "import": { - "title": "从 Codex 导入", - "subtitle": "在 ~/.codex/pets/ 下找到以下可导入的宠物。", - "selectAll": "全选", - "alreadyImported": "已导入", - "renameOnConflict": "冲突时自动添加 -imported 后缀", - "import": "导入所选", - "noneFound": "未找到可导入的 Codex 宠物。", - "imported": "导入完成", - "failed": "导入失败", - "close": "关闭" - }, - "marketplace": { - "openMarketplace": "宠物市场", - "title": "宠物市场", - "search": "搜索宠物", - "kindFilter": { - "all": "全部", - "object": "物品", - "animal": "动物", - "person": "人物", - "creature": "生物" - }, - "sortFilter": { - "latest": "最新", - "popular": "热门", - "views": "最多浏览" - }, - "refresh": "刷新", - "install": "安装", - "installing": "安装中", - "reinstall": "替换重装", - "reinstallConfirm": "确认覆盖本地宠物 \"{name}\" 吗?现有数据将被替换。", - "cancel": "取消", - "stats": { - "views": "浏览", - "downloads": "下载", - "likes": "点赞" - }, - "actions": { - "idle": "待机", - "running_right": "右跑", - "running_left": "左跑", - "waving": "挥手", - "jumping": "跳跃", - "failed": "失败", - "waiting": "等待", - "running": "运行", - "review": "评审" - }, - "page": "第 {page} / {total} 页", - "prev": "上一页", - "next": "下一页", - "empty": "没有匹配的宠物。", - "successInstalled": "已安装 \"{name}\"", - "errors": { - "loadFailed": "加载市场失败", - "installFailed": "安装失败", - "alreadyInstalled": "该宠物已存在" - } - } - }, - "RemoteWorkspace": { - "openRemoteWorkspace": "打开远端工作区", - "manage": "管理远端工作区", - "manageTitle": "远端工作区连接", - "empty": "暂无远端连接", - "searchPlaceholder": "搜索远端工作区", - "orderFailed": "保存远端工作区排序失败", - "dragSort": "拖拽排序", - "dragSortConnection": "拖拽排序 {name}", - "newConnection": "新建连接", - "loading": "加载中", - "loadingConnection": "正在加载远端连接", - "name": "名称", - "baseUrl": "服务地址", - "token": "访问 Token", - "save": "保存", - "delete": "删除", - "confirmDelete": { - "title": "删除远端连接?", - "message": "这会从当前设备移除“{name}”,此操作不可撤销。", - "cancel": "取消", - "confirm": "删除" - }, - "saved": "远端连接已保存。", - "deleted": "远端连接已删除。", - "loadFailed": "加载远端连接失败", - "saveFailed": "保存远端连接失败", - "deleteFailed": "删除远端连接失败", - "openFailed": "打开远端工作区失败", - "connectionLoadFailed": "加载远端连接失败:{message}", - "connectionExpired": "远端连接“{name}”已失效。请更新 Token 后重新加载此窗口。" - }, - "BackupSettings": { - "title": "备份与恢复", - "description": "导出一份可移植的 codeg 数据备份,或从备份中恢复。", - "tabs": { - "backup": "备份", - "restore": "恢复" - }, - "export": { - "includeExternal": "包含会话内容", - "includeExternalHint": "同时打包各 CLI 的会话记录(Claude、Codex、Gemini 等),体积更大。", - "passphrase": "口令(可选)", - "passphrasePlaceholder": "留空则生成未加密的归档", - "passphraseConfirm": "确认口令", - "passphraseMismatch": "两次输入的口令不一致。", - "noPassphraseWarning": "该备份将以明文包含密钥(API key、token)。请妥善保管。", - "passphraseLossWarning": "将使用此口令加密。口令一旦丢失,备份将无法恢复。", - "button": "导出备份", - "inProgress": "正在创建备份…", - "success": "备份已创建。", - "started": "已开始下载备份。" - }, - "restore": { - "selectFile": "选择备份文件", - "passphrasePrompt": "该备份已加密,请输入其口令。", - "unlock": "解锁", - "preview": { - "title": "备份详情", - "encrypted": "已加密", - "compatible": "兼容", - "incompatible": "不兼容", - "createdAt": "创建时间:{value}", - "appVersion": "应用版本:{value}", - "incompatibleHint": "该备份由更新版本的 codeg 创建,无法恢复。" - }, - "replaceWarning": "恢复将替换当前全部 codeg 数据(数据库与上传文件)。当前数据会先做快照以便回退。", - "keyringNote": "桌面端的 GitHub/聊天 token 存于系统钥匙串,不包含在备份中;恢复后需重新填写。", - "button": "恢复", - "staging": "正在准备恢复…", - "staged": "恢复已就绪,正在重启…", - "restarting": "恢复已就绪,正在重启服务…", - "restartTimeout": "服务未能及时恢复。待其启动后请刷新页面。", - "externalSideLocation": "会话记录已恢复到 {path}", - "confirmTitle": "替换全部数据?", - "confirmBody": "这将用备份替换当前的 codeg 数据库与上传文件,然后重启。当前数据会先做快照。", - "cancel": "取消", - "confirmAction": "替换并重启", - "external": { - "title": "会话内容", - "hint": "该备份包含各 CLI 的会话记录。请选择恢复到何处。", - "modeSkip": "不恢复", - "modeSide": "恢复到安全的旁路目录", - "modeOriginal": "恢复到 CLI 的原始位置", - "forceOverwrite": "覆盖已存在的文件", - "forceOverwriteHint": "替换 CLI 目录中已存在的文件。", - "scanning": "正在检查冲突…", - "noConflicts": "不会覆盖任何已存在的文件。", - "conflictCount": "将影响 {count} 个已存在的文件。", - "conflictSkipNote": "未启用覆盖时,已存在的文件将被保留(跳过)。" - }, - "restartFailed": "恢复已就绪,但服务未能重启。请手动重启以应用此次恢复。" - }, - "remoteUnsupported": "备份与恢复作用于运行 codeg 的那台机器上的数据。你当前连接的是远程工作区——请直接在该服务器上管理其备份。" - }, - "backup": { - "restore": { - "error": { - "badPassphrase": "口令错误或备份已损坏。", - "corrupted": "备份归档已损坏。", - "unknownFormat": "该文件不是可识别的 codeg 备份。", - "newerVersion": "该备份由 codeg {backupVersion} 创建,比当前版本({appVersion})更新。", - "alreadyPending": "已有一个恢复在等待生效。请先重启应用它,再暂存新的恢复。" - } - }, - "error": { - "diskSpace": "磁盘空间不足,无法完成操作。", - "cancelled": "操作已取消。" - } - }, - "WebConnection": { - "disconnectedTitle": "连接已断开", - "reconnectingDescription": "正在尝试重新连接服务器,通常会在几秒内自动恢复。", - "reconnectNow": "立即重连", - "sessionExpiredTitle": "会话已过期", - "sessionExpiredDescription": "登录状态已失效,请重新登录以继续。", - "goToLogin": "前往登录" - }, - "LiveFeedback": { - "placeholder": "在 {agent} 工作时给它留言…", - "agentFallback": "智能体", - "ariaLabel": "实时反馈留言", - "dialogTitle": "实时反馈", - "dialogDescription": "在智能体工作时给它留言。它会在下次检查时读取,不会打断当前步骤。", - "dialogDescriptionInstant": "在智能体工作时给它发一条备注。备注会立即插入当前回合——智能体马上就能看到。", - "channelDowngraded": "本会话无法即时插入——备注已保存,等智能体下次检查时读取。", - "send": "发送", - "cancel": "取消", - "pending": "等待中", - "delivered": "已收到", - "turnEndedUnread": "智能体在读取你的反馈前已结束本轮。", - "sendAsMessage": "作为新消息发送", - "dismiss": "忽略", - "turnEndedResent": "本轮已结束——已改为作为新消息发送。", - "turnEnded": "本轮已结束。", - "submitFailed": "留言发送失败" - }, - "AgentToolsSettings": { - "title": "会话内工具", - "description": "codeg 在会话中额外提供给智能体的工具。工具在智能体启动时注入,改动只对之后启动的智能体生效。", - "feedbackLabel": "实时反馈", - "feedbackHint": "在智能体工作时向它发送备注与纠偏。支持即时插入的智能体会立刻在当前回合中看到你的备注;其他智能体则通过检查反馈的工具读取——这类智能体通常只有在提示词里提到时才会检查,例如在消息中加上“定期检查我的实时反馈”。", - "questionLabel": "向用户提问", - "questionHint": "允许智能体暂停并向你提出多选问题,问题会显示在会话输入框上方。智能体会一直等待,直到你作答(或跳过)。", - "sessionInfoLabel": "获取会话信息", - "sessionInfoHint": "允许智能体查询你在消息中提及的会话(会话徽章),读取其标题、智能体、状态、工作区、Token 用量和最近消息。", - "automationsLabel": "创建自动化", - "automationsHint": "把对话保存为按计划运行的自动化。默认关闭——它之后会自行启动智能体。", - "workTasksLabel": "创建待办任务", - "workTasksHint": "从对话中往待办看板排一张任务卡。默认关闭——它会写入应用状态。", - "save": "保存", - "saving": "保存中…", - "saved": "工具设置已保存", - "saveFailed": "保存工具设置失败", - "loadFailed": "加载失败:{detail}" - }, - "NotificationSoundSettings": { - "title": "提示音", - "description": "智能体事件触发时播放一段简短的提示音。这里的事件与消息渠道推送的完全一致,但设置只对本设备生效。", - "enableHint": "默认关闭。提示音只在当前浏览器或应用的工作区窗口中播放。", - "volume": "音量", - "preview": "试听", - "previewEvent": "试听「{event}」提示音", - "onlyWhenUnfocused": "仅在窗口未聚焦时播放", - "onlyWhenUnfocusedHint": "正在查看 Codeg 时保持静音。", - "eventsTitle": "事件", - "eventsHint": "为每个事件选择一种音效,选择「静音」则不播放。同一事件在数秒内重复触发时只播放一次。", - "toneNone": "静音", - "toneChime": "叮咚", - "toneDing": "清铃", - "toneBlip": "短音", - "tonePop": "轻点", - "toneAlert": "警示", - "toneDescend": "下行音" - }, - "LogsSettings": { - "loading": "加载中…", - "sectionTitle": "运行日志", - "sectionDescription": "查看和配置应用诊断日志。日志会写入本地文件,并保留在内存中以便实时查看。", - "captureTitle": "日志级别", - "captureDescription": "控制记录的详细程度。级别越高(Debug、Trace)记录越多,但日志也越大。“关闭”将停止记录日志。", - "captureLabel": "采集级别", - "levels": { - "off": "关闭", - "error": "错误", - "warn": "警告", - "info": "信息", - "debug": "调试", - "trace": "跟踪" - }, - "viewerTitle": "最近日志", - "viewerDescription": "实时查看最近的日志记录。可按级别筛选或搜索文本。", - "searchPlaceholder": "搜索消息或来源…", - "viewLevels": { - "all": "全部级别", - "error": "错误及以上", - "warn": "警告及以上", - "info": "信息及以上", - "debug": "调试及以上", - "trace": "跟踪及以上" - }, - "pause": "暂停", - "resume": "实时", - "refresh": "刷新", - "clear": "清空", - "openFolder": "打开文件夹", - "shownCount": "已显示 {shown} / {total}", - "empty": "暂无日志。", - "levelSaveFailed": "保存日志级别失败", - "openFolderFailed": "打开日志文件夹失败", - "downloadFailed": "下载日志文件失败", - "filesTitle": "日志文件", - "filesDescription": "从磁盘下载完整日志文件,查看实时缓冲区之外的历史记录。", - "filesEmpty": "暂无日志文件。", - "download": "下载", - "downloadTruncated": "文件较大,已下载最新的 {size}。完整文件请在日志目录中查看。", - "captureEnvLocked": "日志级别由 RUST_LOG / CODEG_LOG 环境变量控制;请在该处修改以生效。", - "targetsTitle": "按模块覆盖", - "targetsDescription": "为特定模块(如 codeg_lib::acp)单独设置级别,不影响全局级别。", - "targetsAdd": "添加", - "targetsRemove": "移除覆盖", - "toggleDetails": "切换详情" - }, - "Automations": { - "title": "自动化", - "new": "新建自动化", - "empty": "暂无自动化", - "emptyHint": "创建一个,让智能体按计划或手动执行任务。", - "name": "名称", - "namePlaceholder": "例如:每晚 PR 审查", - "prompt": "提示词", - "promptPlaceholder": "让智能体做什么?", - "agent": "智能体", - "folder": "工作区文件夹", - "folderPlaceholder": "选择文件夹", - "isolation": "隔离方式", - "isolationWorktree": "每次运行新建 worktree", - "isolationShared": "在文件夹内运行", - "isolationSharedCaveat": "运行会直接使用该文件夹的工作树,可能与你未提交的改动冲突。勾选每次运行新建工作树以隔离每次运行。", - "trigger": "触发方式", - "triggerSchedule": "按计划", - "triggerManual": "仅手动", - "cron": "计划(cron)", - "cronPlaceholder": "0 9 * * 1-5", - "timezone": "时区", - "nextRun": "下次运行", - "branch": "分支", - "branchOptional": "分支(可选)", - "enabled": "已启用", - "save": "保存", - "cancel": "取消", - "edit": "编辑", - "delete": "删除", - "runNow": "立即运行", - "cancelRun": "取消运行", - "runHistory": "运行历史", - "noRuns": "暂无运行记录", - "allFolders": "所有文件夹", - "filterAll": "全部", - "noMatches": "没有匹配的自动化", - "viewConversation": "查看会话", - "lastRun": "上次运行", - "never": "从未", - "running": "运行中", - "deleteTitle": "删除此自动化?", - "deleteDescription": "这将删除该自动化及其计划。运行历史会保留。", - "statusRunning": "运行中", - "statusSucceeded": "成功", - "statusFailed": "失败", - "statusCancelled": "已取消", - "statusSkipped": "已跳过", - "errorName": "名称必填", - "errorPrompt": "提示词必填", - "errorCron": "按计划的自动化需要 cron 表达式", - "errorFolder": "请选择工作区文件夹", - "presetHourly": "每小时", - "presetDaily": "每天 9 点", - "presetWeekdays": "工作日 9 点", - "presetCustom": "自定义", - "probing": "正在加载选项…", - "retry": "重试", - "configNone": "该智能体没有可配置项", - "inherit": "智能体默认", - "mode": "模式", - "config": "配置", - "branchPlaceholder": "(默认分支)", - "selectHint": "选择一个自动化以查看详情", - "refresh": "刷新", - "onboardTitle": "自动化日常智能体任务", - "onboardHint": "安排智能体定时或按需审查代码、更新依赖或处理问题。", - "headerSubtitle": "定时与按需的智能体任务", - "startFromTemplate": "从模板开始", - "blankTitle": "空白自动化", - "blankDesc": "从零配置一个智能体任务。", - "backToTemplates": "模板", - "sectionSchedule": "计划与目标", - "sectionTarget": "运行目标", - "sectionAction": "动作", - "actionLaunchSession": "启动会话", - "actionEnqueueTask": "任务入队", - "actionEnqueueTaskHint": "每次触发都会在目标文件夹的待办任务里加入一个待办任务(标题为本自动化名称),由任务引擎按看板设置执行。", - "sectionPrompt": "提示词", - "nextIn": "{rel}后运行", - "manual": "手动", - "schedEveryMinutes": "每 {n} 分钟", - "schedHourly": "每小时", - "schedDaily": "每天 {time}", - "schedWeekdays": "工作日 {time}", - "schedWeekly": "每{day} {time}", - "schedMonthly": "每月 {day} 日 {time}", - "dow0": "周日", - "dow1": "周一", - "dow2": "周二", - "dow3": "周三", - "dow4": "周四", - "dow5": "周五", - "dow6": "周六", - "tplCodeReviewTitle": "代码审查", - "tplCodeReviewDesc": "审查最近的改动,查找缺陷、回归和质量问题。", - "tplDependencyUpdatesTitle": "依赖更新", - "tplDependencyUpdatesDesc": "查找过时的依赖并提出安全的升级方案。", - "tplTestCoverageTitle": "测试覆盖", - "tplTestCoverageDesc": "找出未覆盖的代码路径并补充缺失的测试。", - "tplTodoSweepTitle": "TODO 清理", - "tplTodoSweepDesc": "收集 TODO 和 FIXME 注释并按优先级整理。", - "tplCiTriageTitle": "CI 排查", - "tplCiTriageDesc": "排查最近失败的检查并提出修复方案。", - "tplReleaseNotesTitle": "发布说明", - "tplReleaseNotesDesc": "汇总自上次发布以来的改动,生成更新日志。", - "tplSecurityAuditTitle": "安全审计", - "tplSecurityAuditDesc": "扫描漏洞和风险模式,并报告发现的问题。", - "enable": "启用", - "disable": "停用", - "moreActions": "更多操作", - "statusDisabled": "已停用", - "cronBuilderTitle": "计划生成器", - "cronFreqLabel": "频率", - "cronFreqMinutes": "每 N 分钟", - "cronFreqHourly": "每小时", - "cronFreqDaily": "每天", - "cronFreqWeekdays": "工作日", - "cronFreqWeekly": "每周", - "cronFreqMonthly": "每月", - "cronFreqCustom": "自定义", - "cronEveryLabel": "间隔(分钟)", - "cronTimeLabel": "时间", - "cronHourLabel": "小时", - "cronMinuteLabel": "分钟", - "cronDowLabel": "星期", - "cronDomLabel": "日期", - "cronApply": "应用", - "cronPreviewLabel": "预览", - "cronOpenBuilder": "打开计划生成器", - "branchDefault": "默认分支", - "branchUseCustom": "使用 “{query}”", - "branchLocal": "本地", - "branchRemote": "远程", - "branchSearchPlaceholder": "搜索分支…", - "branchNone": "无分支" - }, - "Tasks": { - "title": "待办任务", - "new": "新建任务", - "empty": "还没有任务", - "emptyHint": "添加待办后即可处理——agent 在独立 worktree 中工作,你验收并合并结果。", - "emptyColTodo": "还没有待办任务", - "emptyColInProgress": "暂无进行中的任务", - "emptyColAttention": "暂无等你处理的任务", - "emptyColDone": "还没有已完成的任务", - "allFolders": "全部文件夹", - "showCanceled": "显示已取消", - "showArchived": "显示已归档", - "filter": "筛选", - "viewSwitchToBoard": "切换到看板视图", - "viewSwitchToList": "切换到列表视图", - "statusFilter": "状态", - "statusFilterAll": "全部状态", - "listEmpty": "没有符合当前筛选条件的任务", - "listColStatus": "状态", - "listColTask": "任务", - "listColLocation": "位置", - "listColChanges": "变更", - "listColUpdated": "更新", - "colTodo": "待办", - "colInProgress": "进行中", - "colAttention": "等你处理", - "colDone": "已完成", - "statusTodo": "待办", - "statusQueued": "排队中", - "statusPreparing": "初始化中", - "statusRunning": "进行中", - "statusAwaitingInput": "等待输入", - "statusReview": "待验收", - "statusMerging": "合并中", - "statusDone": "已完成", - "statusFailed": "失败", - "statusCanceled": "已取消", - "statusInterrupted": "已中断", - "badgeCleanupFailed": "清理失败", - "badgeWorktreeKept": "保留 worktree", - "badgeWorktreeRemoved": "Worktree 已删除", - "filesChanged": "{count} 个文件", - "actionStart": "开始", - "actionSchedule": "定时运行", - "actionCancel": "取消", - "actionRetry": "重试", - "actionRequeue": "重新排队", - "actionViewSession": "查看会话", - "actionEdit": "编辑", - "actionDelete": "删除", - "actionRetryCleanup": "重试清理", - "actionMerge": "合并", - "actionUnqueueMerge": "取消排队", - "actionEditQueuedMerge": "修改排队的合并", - "badgeMergeQueued": "排队合并中", - "badgeMergeQueuedRank": "排队合并 · 第 {rank} 位", - "badgeMergeQueuedHint": "正在等待该项目当前的合并完成,轮到时会自动开始。", - "actionComplete": "完成", - "actionAbandon": "放弃", - "cancelTitle": "取消任务?", - "cancelDescription": "任务将变为已取消。worktree 会保留,之后可以重新排队。", - "cancelReasonLabel": "取消原因(可选)", - "cancelReasonPlaceholder": "例如:方向不对,我重写一下任务描述", - "cancelKeep": "先不取消", - "cancelSubmit": "取消任务", - "restartTitleRetry": "重试任务", - "restartTitleRequeue": "重新排队", - "restartDescription": "可以补充一段说明(可选),它会随下一轮的提示词一起发给 agent。", - "scheduleTitle": "定时运行任务", - "scheduleDescription": "任务留在「待办」,到点自动开始。文件夹的并发上限依然生效。", - "scheduleDateLabel": "日期", - "schedulePickDate": "选择日期", - "scheduleTimeLabel": "时间", - "schedulePreview": "{time} 运行", - "schedulePastHint": "该时间已过——保存后会立即开始。", - "scheduleInAnHour": "1 小时后", - "scheduleInThreeHours": "3 小时后", - "scheduleTomorrow": "明天 9:00", - "scheduleClear": "清除定时", - "scheduleBadge": "计划于 {time} 开始", - "toastScheduled": "已定时:{time}", - "toastScheduleCleared": "已清除定时", - "actionFollowUp": "继续处理", - "actionAddNote": "补充说明", - "followUpSubmit": "发送", - "followUpIntentRevise": "修改返工", - "followUpIntentContinue": "继续推进", - "followUpIntentQuestion": "提问答疑", - "followUpIntentVerify": "自查验证", - "followUpPlaceholderRevise": "希望 agent 改哪里?会在同一会话里继续。", - "followUpPlaceholderContinue": "接下来还要做什么?已有的工作会保留。", - "followUpPlaceholderQuestion": "想了解什么?agent 只回答,不会改动任何文件。", - "followUpPlaceholderVerify": "可选:有什么想让它重点检查的?", - "followUpPlaceholderRetry": "可选:这次要怎么做才不一样?例如:先跑 pnpm install", - "followUpPlaceholderRequeue": "可选:当时为什么取消?这次要注意什么?", - "actionArchive": "归档", - "actionUnarchive": "取消归档", - "archiveAllDone": "全部归档", - "dropToStart": "松开即开始执行", - "errorView": "查看", - "notifyReview": "待验收:{title}", - "notifyFailed": "任务失败:{title}", - "createFromMessage": "由此消息创建任务", - "detailTokens": "总 token 用量", - "editorTitleNew": "新建任务", - "editorTitleEdit": "编辑任务", - "templates": "模板", - "templatesEmpty": "还没有模板。", - "templateSaveCurrent": "把当前内容存为模板", - "templateDelete": "删除模板", - "transcriptTitle": "任务会话", - "transcriptDescription": "任务智能体会话的只读实时视图。", - "phaseWork": "任务执行", - "phaseRetry": "重试执行", - "phaseReturn": "继续处理", - "phaseMerge": "合并变更", - "titleLabel": "标题", - "titlePlaceholder": "要做什么?", - "promptLabel": "任务描述", - "promptPlaceholder": "向 agent 描述任务——输入 @ 可引用文件,/ 可唤起命令", - "folderPlaceholder": "选择文件夹", - "agentInheritedHint": "继承自任务设置,修改后仅对本任务生效", - "agentOverrideReset": "恢复继承", - "sectionTarget": "目标", - "errorTitle": "请输入标题", - "errorPrompt": "请输入任务描述", - "errorFolder": "请选择文件夹", - "save": "保存", - "cancel": "取消", - "mergeTitle": "合并任务", - "mergeQueuedTitle": "排队中的合并", - "mergeQueueHint": "该项目正在合并另一个任务。此任务会加入队列,等前一个完成后自动开始。", - "mergeQueueUpdateHint": "该任务已在合并队列中。提交将更新它的合并选项,并保留原有的排队位置。", - "mergeDescription": "将 {branch} 合并到 {base}。worktree 中未提交的变更会先自动提交。", - "mergeMessage": "提交信息", - "mergeMessagePlaceholder": "例如 feat: add login validation", - "mergeAutoMessage": "让 agent 自动生成提交信息", - "strategySquash": "合并为一条提交", - "strategySquashHint": "任务的所有修改压缩成一条提交记录并入主分支,历史更简洁。", - "strategyMerge": "保留完整提交历史", - "strategyMergeHint": "保留任务过程中的每一条提交,另加一条合并记录,每一步都可追溯。", - "mergeDeleteWorktree": "合并后删除 worktree", - "mergeSubmit": "合并", - "mergeSubmitQueue": "加入合并队列", - "mergeQueuedToast": "已加入合并队列,等当前合并完成后自动开始。", - "completeTitle": "完成任务", - "completeDescription": "该任务没有改动任何文件,无需合并,将直接标记为已完成。", - "completeDescriptionNoWorktree": "该任务的 worktree 已被删除,无法再合并,将直接标记为已完成。若工作分支上仍有未合并的提交,分支会被保留。", - "completeDeleteWorktree": "完成后删除 worktree", - "completeSubmit": "完成", - "settingsTitle": "任务设置", - "settingsDescription": "{folder} 中任务的默认配置。", - "settingsScope": "作用域", - "settingsScopeGlobal": "全部文件夹(全局默认)", - "settingsScopeGlobalHint": "未单独设置的文件夹将使用这份全局默认配置。", - "settingsSource": "配置来源", - "settingsSourceGlobal": "使用全局默认", - "settingsSourceCustom": "单独配置", - "settingsSourceGlobalFollow": "跟随全局任务设置,全局改动会自动生效。", - "settingsSourceCustomHint": "为此文件夹保存独立设置,不再跟随全局默认。", - "settingsAgent": "默认 agent", - "settingsMaxConcurrent": "最大并发任务数", - "settingsMaxConcurrentHint": "0 表示不限制", - "settingsAutoProcess": "自动处理", - "settingsAutoProcessHint": "待办任务自动开始处理,受并发上限约束。", - "settingsMergeStrategy": "默认合并策略", - "settingsMergeStrategyHint": "合并任务时,这些修改在分支历史里如何记录。", - "settingsAutoMerge": "自动合并", - "settingsAutoMergeHint": "任务进入待验收且有可合并改动时自动落地,与点击「合并」相同:提交信息由 agent 自动生成,是否删除 worktree 沿用下方默认。预检未通过或合并失败的任务会留下等你处理。", - "settingsDeleteWorktree": "合并后删除 worktree", - "settingsDeleteWorktreeHint": "合并对话框里默认勾选,仍可临时改。", - "settingsWorktreeRoot": "Worktree 位置", - "settingsWorktreeRootHint": "新任务的 worktree 创建在该目录下,每个任务一个。留空则创建在项目文件夹的同级目录;「~」表示主目录,相对路径相对于项目文件夹。", - "settingsWorktreeRootPlaceholder": "~/codeg-worktrees", - "settingsWorktreeRootBrowse": "选择 worktree 目录", - "settingsPreflight": "预检命令", - "settingsPreflightHint": "任务进入待验收时在 worktree 中运行。", - "settingsPreflightCustomPlaceholder": "pnpm test", - "settingsInitCommand": "Worktree 初始化命令", - "settingsInitCommandHint": "新建 worktree 后、会话开始前执行。", - "settingsInitCommandPlaceholder": "pnpm install", - "settingsTabGeneral": "常规", - "settingsTabMerge": "合并", - "settingsTabWorktree": "Worktree", - "settingsTabPrompts": "提示词", - "settingsPromptsIntro": "每个阶段都已内置固定的提示词——任务本身、worktree 规则,合并阶段还包含具体的 git 步骤。这里填的内容会作为补充说明追加到末尾:只是对内置提示词的细化,不会替换它们。", - "settingsPromptStageAll": "全部阶段", - "settingsPromptPlaceholderAll": "例如:遵循 AGENTS.md 里的项目约定;始终用中文回复", - "settingsPromptPlaceholderWork": "例如:先读相关测试;小步提交,边做边交", - "settingsPromptPlaceholderRetry": "例如:先看清楚已经提交了哪些改动再继续,别重做已完成的部分", - "settingsPromptPlaceholderReturn": "例如:逐条处理提到的每一点;不要顺手重构无关代码", - "settingsPromptPlaceholderMerge": "例如:最终合并的提交信息用中文;手动解决过的冲突要单独说明", - "settingsPromptHintAll": "追加到每一次发给 agent 的提示词,包括合并那一轮。", - "settingsPromptHintWork": "任务首次执行时追加。", - "settingsPromptHintRetry": "重试被中断或失败的任务时追加。", - "settingsPromptHintReturn": "对待验收的任务继续处理时追加(返工、追加工作、自查)。", - "settingsPromptHintMerge": "agent 把任务合并到基线分支时追加。", - "preflightPassed": "{name} 通过", - "preflightFailed": "{name} 未通过", - "preflightRunning": "{name} 运行中…", - "detailDescription": "任务详情", - "detailSummary": "结果", - "detailFiles": "变更文件", - "detailDiffAll": "查看全部差异", - "detailDiffAllTitle": "全部差异", - "detailNoChanges": "相对基准还没有变更", - "detailTimeline": "推进记录", - "detailTimelineEmpty": "暂无活动", - "showMore": "展开", - "showLess": "收起", - "detailInfo": "详情", - "detailBranch": "分支", - "detailMergeCommit": "合并提交", - "detailChanges": "变更", - "detailScheduled": "计划开始", - "detailCreated": "创建时间", - "detailStarted": "开始时间", - "detailFinished": "完成时间", - "diffLoading": "正在加载差异…", - "deleteConfirmTitle": "删除任务?", - "deleteConfirmBody": "「{title}」将从看板移除。进行中的运行会先被取消。", - "deleteWithWorktree": "同时删除其 worktree", - "eventCreated": "已创建", - "eventStatusChanged": "状态变更", - "eventConfigEffective": "启动配置", - "eventInitCommand": "初始化命令", - "eventAgentProgress": "Agent 进展", - "eventAgentVerdict": "Agent 结论", - "eventMergeAttempt": "开始合并", - "eventMergeQueued": "加入合并队列", - "eventMergeConflict": "合并冲突", - "eventPreflight": "预检", - "eventCleanupFailed": "worktree 清理失败", - "eventResumeFallback": "会话恢复失败,已改用新会话", - "eventUserAction": "用户操作", - "eventDiffStat": "变更快照" - }, - "CustomSkillsSettings": { - "loading": "正在加载自定义技能…", - "category": "自定义", - "searchPlaceholder": "按名称、ID 或描述搜索自定义技能", - "states": { - "not_linked": "未启用", - "linked_to_codeg": "已启用", - "linked_elsewhere": "链接到其他位置", - "blocked_by_real_directory": "被同名真实目录占用", - "broken": "链接已失效" - }, - "actions": { - "new": "新建", - "import": "导入", - "importFromAgent": "从 Agent 导入", - "cancel": "取消", - "save": "保存" - }, - "rowMenu": { - "edit": "编辑", - "duplicate": "复制为新技能", - "delete": "删除" - }, - "bulk": { - "delete": "删除所选" - }, - "editor": { - "createTitle": "新建自定义技能", - "editTitle": "编辑自定义技能", - "description": "自定义技能存放在共享库(~/.codeg/skills),可为任意智能体启用。", - "idLabel": "技能 ID", - "idPlaceholder": "例如 my-workflow", - "contentLabel": "SKILL.md", - "contentPlaceholder": "在此编写技能的 SKILL.md…", - "preview": "预览", - "edit": "编辑", - "emptyBody": "暂无内容。" - }, - "duplicate": { - "title": "复制技能", - "description": "以「{id}」为模板,用新 ID 创建一份副本。", - "newIdPlaceholder": "新技能 ID", - "confirm": "复制" - }, - "import": { - "title": "选择要导入的技能文件夹" - }, - "importFromAgent": { - "title": "从 Agent 导入技能", - "description": "把某个 Agent 自己的技能复制到共享库,即可为任意 Agent 启用。", - "agentLabel": "Agent", - "agentPlaceholder": "选择一个 Agent", - "selectAll": "全选({count})", - "loading": "正在加载该 Agent 的技能…", - "unsupported": "该 Agent 未提供技能目录。", - "empty": "该 Agent 没有可导入的技能。", - "alreadyInLibrary": "已在库中", - "confirm": "导入所选({count})" - }, - "delete": { - "title": "删除自定义技能?", - "body": "将从中央库移除 {count} 个自定义技能,并解除它们在所有智能体中的链接。此操作不可撤销。", - "confirm": "删除" - }, - "toasts": { - "loadFailed": "加载技能失败", - "idRequired": "请输入技能 ID", - "created": "已创建自定义技能", - "updated": "已更新自定义技能", - "saveFailed": "保存技能失败", - "imported": "已导入技能", - "importFailed": "导入技能失败", - "duplicated": "已复制技能", - "duplicateFailed": "复制技能失败", - "deleted": "已删除 {count} 个技能", - "deletedPartial": "已删除 {ok} 个,{failed} 个失败", - "deleteFailed": "删除技能失败", - "importedFromAgent": "已导入 {count} 个技能", - "importedFromAgentPartial": "已导入 {ok} 个,{failed} 个失败", - "importFromAgentAllSkipped": "无需导入——{count} 个已在库中", - "importFromAgentFailed": "从 Agent 导入失败" - } - }, - "CodexModelEditor": { - "customizedNotice": "你已自定义模型列表,codeg 将接管 codex 的完整模型表。codex 日后新增的官方模型不会自动出现——点击下方刷新并重新保存即可同步。清空全部自定义即可交回 codex 自动更新。", - "officialsTitle": "官方模型", - "officialsHint": "自动纳入你启动的 codex 的官方模型;可删除不需要的。", - "officialsEmpty": "暂无官方模型。", - "refresh": "从 codex 刷新", - "readdOfficial": "重新加入官方", - "customsTitle": "自定义模型", - "customsEmpty": "暂无自定义模型。", - "addCustom": "添加自定义", - "slugPlaceholder": "模型 id(slug)", - "displayNamePlaceholder": "显示名", - "contextWindow": "上下文", - "makeDefault": "设为默认", - "defaultHint": "默认模型", - "remove": "删除", - "advanced": "高级", - "baseTemplate": "基础模板", - "baseTemplateHint": "从哪个官方模型克隆必填字段(系统提示词、工具、限制)。", - "groupBehavior": "行为与能力", - "fieldReasoningLevel": "默认推理强度", - "fieldReasoningSummary": "推理摘要", - "fieldVerbosity": "详细程度", - "fieldShellType": "Shell 类型", - "fieldApplyPatch": "应用补丁工具", - "fieldReasoningSummaries": "推理摘要支持", - "fieldSupportVerbosity": "详细程度控制", - "fieldParallelToolCalls": "并行工具调用", - "fieldSearchTool": "联网搜索工具", - "optNone": "无", - "groupInstructions": "描述与系统提示词", - "fieldDescription": "描述", - "baseInstructions": "系统提示词(base_instructions)" - }, - "DiagnosticsSettings": { - "title": "环境诊断", - "description": "检查本应用在自身进程中如何解析该智能体的 CLI——这可能与你的终端不同。", - "loading": "正在运行诊断…", - "error": "诊断失败", - "rerun": "重新运行", - "copyAll": "复制全部", - "copied": "诊断信息已复制到剪贴板", - "button": "诊断", - "verdict": { - "ok": "环境正常。若仍提示未安装,请彻底重启应用以刷新前缀缓存。", - "node_missing": "在应用的 PATH 上未找到 Node.js。", - "npm_missing": "在应用的 PATH 上未找到 npm。", - "not_installed": "该智能体似乎尚未安装。", - "installed_but_unresolved": "记录显示已安装,但应用无法定位其可执行文件。", - "user_prefix_not_on_path": "安装到了回退前缀(~/.codeg/npm-global),但它不在应用的 PATH 上。请彻底重启应用后重试。", - "homebrew_bin_not_on_path": "安装在 Homebrew 的 bin 目录下,但它不在应用的 PATH 上(Apple Silicon keg 拆分)。", - "terminal_only_path": "该命令在你的终端能解析,但在应用中不能——这是 GUI PATH 差异。请从终端启动应用,或在智能体设置中重新安装。", - "npm_prefix_timeout": "npm prefix -g 太慢(超过 1.5 秒),已跳过回退检测。请重启应用后重试。", - "node_too_old": "当前 Node.js 版本低于该智能体的要求。请升级 Node.js。", - "adapter_missing_native_present": "你本地的 {agent} CLI 确实装了,但 Codeg 启动的是另一个 ACP 适配器包,而它还没装。到「智能体设置」里安装即可 —— 它不会动你的 CLI,登录状态也是共享的。", - "adapter_missing": "Codeg 为 {agent} 启动的是单独的 ACP 适配器包,目前尚未安装。请到「智能体设置」里安装 —— 只装厂商 CLI 是不够的。" - } - }, - "TokenUsage": { - "title": "Token 用量", - "rangeLabel": "时间范围", - "range7d": "近 7 天", - "range30d": "近 30 天", - "range90d": "近 90 天", - "rangeThisMonth": "本月", - "rangeThisYear": "今年", - "rangeAll": "全部", - "rangeCustom": "自定义", - "moreRanges": "更多", - "customRangePick": "选择日期范围", - "bucketLabel": "统计粒度", - "bucketDay": "按天", - "bucketWeek": "按周", - "bucketMonth": "按月", - "bucketUnitDay": "天", - "bucketUnitWeek": "周", - "bucketUnitMonth": "月", - "folderFilter": "文件夹", - "allFolders": "全部文件夹", - "agentFilter": "智能体", - "allAgents": "全部智能体", - "modelFilter": "模型", - "allModels": "全部模型", - "searchPlaceholder": "搜索…", - "noMatches": "没有匹配项", - "clearFilter": "清除选择", - "resetFilters": "重置筛选", - "refresh": "刷新数据", - "rebuild": "全量重建", - "rebuildHint": "丢弃已统计的数据并重新解析全部会话记录。会话被 codeg 之外的 CLI 追加过时用它。", - "syncing": "正在统计会话…", - "syncProgress": "{done} / {total}", - "syncDone": "已统计 {synced} 个会话", - "syncFailed": "部分会话读取失败", - "syncBusy": "已有一次刷新在进行中", - "lastSynced": "更新于 {time}", - "lastSyncedNever": "尚未统计", - "tileTotal": "总 Token", - "tileSessions": "会话数", - "tileTurns": "对话轮次", - "tileActiveDays": "活跃天数", - "tileGenTime": "生成时长", - "vsPrevious": "对比上一周期", - "deltaNew": "新增", - "trendTitle": "用量趋势", - "trendEmpty": "该范围内没有用量", - "trendTurns": "轮次", - "trendSessions": "会话", - "compositionTitle": "Token 都花在哪", - "compositionHint": "输入是你发出去的内容,输出是模型写回来的,缓存读取则是不必再按原价重发的上下文。", - "compositionNote": "这些缓存命中若按原价重发,要多花 {value}。", - "inputTokens": "输入", - "outputTokens": "输出", - "cacheWrite": "缓存写入", - "cacheRead": "缓存读取", - "freshTokens": "新算 Token", - "cacheHitCaption": "缓存命中", - "cacheHeroTitleHigh": "上下文大多不必重发", - "cacheHeroTitleLow": "多数上下文仍按原价计算", - "cacheHeroDesc": "{cached} 的上下文由缓存承担,这段时间真正新算的只有 {fresh}。", - "cacheSavedSuffix": "省下的重发量相当于 {saved}。", - "avgPerSession": "平均每会话", - "avgTurnsPerSession": "平均每会话 {count} 轮", - "avgPerActiveDay": "平均每活跃日", - "peakBucket": "最高的一{bucket}", - "peakHour": "高峰时段", - "daysValue": "{count} 天", - "idleDays": "空转天数", - "byFolderTitle": "按文件夹", - "byAgentTitle": "按智能体", - "byModelTitle": "按模型", - "distributionTitle": "用量分布", - "distributionHint": "会话与 Token 按所选维度归集,点任意一行可按它筛选。", - "otherLabel": "其他", - "unknownModel": "未标注模型", - "emptyBreakdown": "还没有记录", - "sessionsCount": "{count} 个会话", - "heatmapTitle": "你的编码作息", - "heatmapHint": "按本地星期与小时统计的 Token 分布。", - "heatmapPeakHint": "最密集的时段在 {hour}:00 前后。", - "less": "少", - "more": "多", - "heatmapCell": "{weekday} {hour}:00 — {value} tokens", - "weekMon": "一", - "weekTue": "二", - "weekWed": "三", - "weekThu": "四", - "weekFri": "五", - "weekSat": "六", - "weekSun": "日", - "topSessionsTitle": "消耗最高的会话", - "untitledSession": "未命名会话", - "topSessionsEmpty": "该范围内没有会话", - "streakLongest": "最长连续", - "streakLongestDays": "最长连续 {count} 天", - "share": "分享", - "moreActions": "更多操作", - "shareDialogTitle": "分享你的用量卡片", - "shareDialogHint": "卡片内容就是你当前所选的时间范围与筛选条件。", - "shareSave": "保存图片", - "shareCopy": "复制图片", - "shareCopied": "已复制到剪贴板", - "shareSaved": "图片已保存", - "shareFailed": "图片生成失败", - "shareRendering": "生成中…", - "cardHeading": "我的 AI 编码战绩", - "cardRangeAll": "全部时间", - "cardTotalLabel": "累计 Token", - "cardFooter": "由 codeg 生成", - "cardTopModels": "常用模型", - "cardTopProjects": "主力项目", - "archetypeNightOwl": "深夜码农", - "archetypeNightOwlDesc": "{percent}% 的 Token 烧在天黑之后。", - "archetypeEarlyBird": "清晨型选手", - "archetypeEarlyBirdDesc": "{percent}% 的 Token 在早上 9 点前就用掉了。", - "archetypeWeekendWarrior": "周末战士", - "archetypeWeekendWarriorDesc": "{percent}% 的 Token 发生在周末。", - "archetypeCacheMaster": "缓存大师", - "archetypeCacheMasterDesc": "{percent}% 的上下文来自缓存。", - "archetypeMarathoner": "长跑选手", - "archetypeMarathonerDesc": "连续 {days} 天没有断更。", - "archetypePolyglot": "多面手", - "archetypePolyglotDesc": "{count} 个智能体都在主力使用。", - "archetypeLaserFocus": "专注一役", - "archetypeLaserFocusDesc": "{percent}% 的 Token 投在同一个项目上。", - "archetypeDeepDiver": "深潜者", - "archetypeDeepDiverDesc": "平均每个会话 {averageK}K tokens。", - "archetypeSteady": "稳定输出", - "archetypeSteadyDesc": "累计 {days} 天在写代码。", - "emptyTitle": "还没有可统计的数据", - "emptyHint": "codeg 直接从各智能体自己的会话记录里读取 Token 数。点一下刷新,把本机已有的会话统计进来。", - "emptyAction": "统计我的会话", - "loadFailed": "用量加载失败", - "truncatedNotice": "该范围过大 —— 下面的数字只覆盖了其中最近的一段。" - } -} +{ + "Language": { + "followSystem": "跟随系统", + "english": "英语", + "simplifiedChinese": "简体中文", + "traditionalChinese": "繁體中文", + "japanese": "日语", + "korean": "韩语", + "spanish": "西班牙语", + "german": "德语", + "french": "法语", + "portuguese": "葡萄牙语", + "arabic": "阿拉伯语" + }, + "GitCredentialDialog": { + "title": "需要身份验证", + "description": "远程服务器要求输入凭据。请输入用户名和密码(或个人访问令牌)。", + "username": "用户名", + "usernamePlaceholder": "用户名或邮箱", + "password": "密码 / 令牌", + "passwordPlaceholder": "密码或个人访问令牌", + "passwordHint": "请输入服务器的用户名和密码。", + "cancel": "取消", + "authenticate": "认证", + "authenticating": "认证中...", + "invalidCredentials": "凭据无效,请重试。", + "saveCredentials": "保存凭据以供后续操作使用", + "githubTitle": "GitHub 身份验证", + "githubDescription": "输入个人访问令牌以连接 GitHub。令牌验证成功后将自动保存到账号列表。", + "githubToken": "个人访问令牌", + "githubTokenPlaceholder": "ghp_xxxxxxxxxxxx", + "githubTokenHint": "在 GitHub → Settings → Developer settings → Personal access tokens 中生成令牌。", + "githubAuthenticate": "验证并连接", + "generateToken": "生成令牌" + }, + "SettingsShell": { + "title": "设置", + "preferences": "偏好设置", + "nav": { + "general": "常规", + "appearance": "外观", + "agents": "智能体", + "mcp": "MCP", + "skills": "Skills", + "shortcuts": "快捷键", + "version_control": "版本控制", + "system": "系统", + "chat_channels": "消息渠道", + "web_service": "Web 服务", + "model_providers": "模型供应商", + "experts": "专家", + "science": "科学研究", + "office_tools": "办公工具", + "skill_packs": "技能包", + "quick_messages": "快捷消息", + "logs": "运行日志" + } + }, + "AppearanceSettings": { + "sectionTitle": "主题外观", + "sectionDescription": "选择浅色、深色或跟随系统主题,设置会自动保存。", + "themeMode": "主题模式", + "placeholder": "请选择主题模式", + "system": "跟随系统", + "light": "浅色", + "dark": "深色", + "currentTheme": "当前生效主题:{theme}", + "resolvedTheme": { + "light": "浅色", + "dark": "深色", + "unknown": "未知" + }, + "themeColor": { + "sectionTitle": "主题颜色", + "sectionDescription": "选择按钮、强调色和高亮使用的色调。", + "current": "当前颜色:{color}", + "options": { + "neutral": "Neutral", + "zinc": "Zinc", + "slate": "Slate", + "stone": "Stone", + "gray": "Gray", + "red": "Red", + "rose": "Rose", + "orange": "Orange", + "green": "Green", + "blue": "Blue", + "yellow": "Yellow", + "violet": "Violet" + } + }, + "customStyle": { + "sectionTitle": "自定义样式", + "sectionDescription": "在当前主题的基础上微调配色,或写入自己的 CSS。覆盖叠加在基底预设之上,切换预设后依然保留。", + "summarySuspended": "已停用", + "summaryDefault": "跟随预设", + "summaryTokens": "{count, plural, other {# 项覆盖}}", + "summaryCss": "自定义 CSS", + "suspendedByShortcut": "自定义样式已停用。在恢复之前,这里的设置都不会生效。", + "suspendedBySafeParam": "本窗口以安全外观模式打开,自定义样式在此不生效,其它窗口不受影响。", + "resume": "恢复自定义样式", + "enableTheme": "启用自定义配色", + "editingLight": "正在编辑浅色模式的取值。切换到深色模式可单独设置深色。", + "editingDark": "正在编辑深色模式的取值。切换到浅色模式可单独设置浅色。", + "resetToken": "恢复为预设取值", + "radius": "圆角", + "radiusHint": "从 sm 到 4xl 的整套圆角尺寸都由它派生,一个滑块即可改变全局圆角。", + "advanced": "高级(另有 {count} 个变量)", + "enableCss": "启用自定义 CSS", + "cssRisk": "高级功能。自定义 CSS 会压过所有内置样式,写坏可能导致界面不可用。", + "editCss": "编辑 CSS…", + "cssPresent": "已保存 {size} KB", + "cssEmpty": "尚未保存内容", + "escapeHint": "界面被改坏了?按 {shortcut} 可停用全部自定义样式,也可以用 safeStyle=1 查询参数打开窗口。", + "copyTheme": "复制主题 JSON", + "importTheme": "导入主题…", + "clearTheme": "清除覆盖", + "interopHint": "主题采用 shadcn 的 registry:theme 格式,可以直接粘贴任意 shadcn 主题,导出的主题也能用在任何 shadcn 项目里。", + "importTitle": "导入主题", + "importDescription": "粘贴 shadcn 的 registry:theme 条目、裸的 light/dark 对象,或者单层的 token 映射。", + "readClipboard": "读取剪贴板", + "importConfirm": "导入", + "cancel": "取消", + "apply": "应用", + "toasts": { + "copied": "主题 JSON 已复制", + "copyFailed": "无法写入剪贴板", + "clipboardReadFailed": "无法读取剪贴板,请手动粘贴", + "importFailed": "这段 JSON 里没有可用的主题变量", + "imported": "主题已导入" + }, + "css": { + "dialogTitle": "自定义 CSS", + "dialogDescription": "对所有 codeg 窗口生效。修改会实时预览,点击「应用」才会保存。", + "size": "{used} KB / {max} KB", + "ruleCount": "{count} 条规则", + "errorTooLarge": "内容过大,无法保存,请精简到上限以内。", + "errorImportEscaped": "剥离后仍检测到 @import(转义写法),请手动移除后再保存。", + "warnNoRules": "没有解析出任何规则,请检查语法。", + "noticeImportsRemoved": "已移除 {count} 条 @import:它们会拉取远程样式表。", + "noticeRemoteUrl": "含远程 url(),应用后会发起网络请求。", + "noticePreviewSuspended": "自定义样式已停用,此处预览不会生效。", + "noticeDisabled": "自定义 CSS 未启用。这里可以预览,但启用后才会真正生效。", + "hintTokens": "提示:你覆盖的颜色可以直接用 var(--primary)、var(--background) 等引用。" + } + }, + "zoomLevel": { + "sectionTitle": "窗口缩放", + "sectionDescription": "整体放大或缩小界面,立即生效,按设备分别保存。", + "placeholder": "请选择缩放档位", + "default": "默认", + "current": "当前缩放:{zoom}%" + }, + "fonts": { + "sectionTitle": "字体", + "sectionDescription": "为界面、代码编辑器和终端分别选择字体。内置字体按需加载;选择“自定义…”可使用系统已安装的任意字体。", + "interface": "界面", + "editor": "编辑器", + "terminal": "终端", + "groupSans": "无衬线", + "groupMono": "等宽", + "custom": "自定义…", + "customPlaceholder": "字体名称,如 Fira Code", + "fontSize": "字号", + "ligatures": "启用连字", + "ligaturesUnavailable": "该字体不含连字", + "wordWrap": "启用自动换行", + "terminalLigaturesHint": "终端连字仅对内置编程字体生效。", + "preview": "预览" + }, + "welcomePanel": { + "sectionTitle": "模式选择区域", + "sectionDescription": "新会话页面输入框上方显示的「代码开发 / 日常办公」快捷卡片区域。", + "showQuickActions": "在新会话页面显示" + }, + "workspaceBackground": { + "sectionTitle": "工作区背景", + "sectionDescription": "在整个工作区背后显示一张图片。侧栏与面板会变半透明并磨砂让图片透出,遮罩保证文字可读。", + "enable": "启用背景图片", + "image": "图片", + "chooseImage": "选择图片", + "replaceImage": "更换图片", + "removeImage": "移除", + "fillMode": "填充方式", + "fillModes": { + "cover": "覆盖", + "contain": "适应", + "center": "居中", + "tile": "平铺" + }, + "maskOpacity": "遮罩不透明度", + "maskOpacityHint": "数值越高,图片越向主题背景色淡化,文字对比越清晰。", + "imageBlur": "图片模糊", + "panelOpacity": "面板不透明度", + "panelOpacityHint": "侧栏、面板与标签栏的不透明程度。越低,透出的图片越多。", + "errorTooLarge": "图片太大(最大 16 MB)。", + "errorUploadFailed": "设置背景图片失败。" + } + }, + "SystemSettings": { + "loading": "加载中...", + "sectionTitle": "系统管理", + "sectionDescription": "管理网络代理、应用升级与语言偏好。", + "proxyTitle": "网络代理", + "proxyDescription": "开启后,后续网络请求将优先走该代理(包括 ACP 对话、Agent 安装、Git 远程操作等)。", + "loadFailed": "加载失败:{message}", + "enableProxy": "启用系统代理", + "proxyAddress": "代理地址", + "proxyHint": "支持 http(s)/socks5,示例:{example}。仅在启用系统代理时生效。", + "save": "保存", + "saving": "保存中...", + "proxyRequired": "启用代理时必须填写代理地址", + "saveSuccess": "系统代理设置已保存", + "saveFailed": "保存失败:{message}", + "languageTitle": "语言", + "languageDescription": "设置应用语言。跟随系统时,若系统语言不受支持将回退为英文。", + "appLanguage": "应用语言", + "languageSaveSuccess": "语言设置已保存", + "languageSaveFailed": "语言设置保存失败:{message}", + "updateTitle": "应用升级", + "versionTitle": "软件更新", + "updateDescription": "点击检查后会从配置的发布源拉取最新版本信息,有新版本时可直接下载并安装。", + "currentVersion": "当前版本", + "upgradableVersion": "最新版本", + "none": "暂无", + "lastChecked": "上次检查:{time}", + "updateError": "更新异常:{message}", + "checking": "检查中...", + "checkUpdate": "检查更新", + "updating": "升级中...", + "downloading": "下载中...", + "upgradeTo": "升级到 v{version}", + "viewRelease": "查看 v{version} 发布", + "foundUpdate": "发现新版本 v{version}", + "alreadyLatest": "当前已经是最新版本", + "checkUpdateFailed": "检查更新失败:{message}", + "installSuccess": "升级包已安装,正在重启应用", + "installFailed": "升级失败:{message}", + "upgradeSuccess": "升级完成,正在重新加载...", + "restartTimeout": "服务未能按时恢复,请检查容器或服务日志。", + "restartingIn": "将在 {seconds} 秒后重启...", + "waitingForServer": "正在等待服务恢复...", + "restartToUpdate": "重启以更新", + "newVersionBadge": "新版本 v{version}", + "updateAvailableTitle": "发现新版本", + "releaseNotesTitle": "更新内容", + "remindLater": "稍后", + "retry": "重试", + "stepDownload": "下载", + "stepInstall": "安装", + "stepRestart": "重启", + "updateReadyHint": "新版本已下载,重启以完成更新。", + "restarting": "正在重启…", + "dockerUpgradeHint": "现在升级的是正在运行的容器。容器一旦被重建即丢失——如需保留,请拉取或构建新版本镜像后重建容器。", + "upgradeRolledBack": "升级失败,服务器已自动回滚到上一版本。", + "serverUnreachable": "无法连接到服务器以开始升级。请确认服务器正在运行后重试。", + "rollbackButton": "回滚", + "rollingBack": "回滚中...", + "rollbackDescription": "恢复到上次升级前安装的版本。", + "rollbackConfirmTitle": "回滚到上一个版本?", + "rollbackConfirmDescription": "服务器将重启并运行上次升级前安装的版本。更新的版本仍可再次安装。", + "rollbackConfirm": "回滚", + "rollbackCancel": "取消", + "rollbackSuccess": "已回滚到上一个版本,正在重新加载……", + "rollbackFailed": "回滚失败,请检查服务器日志。", + "updateErrors": { + "sourceUnavailable": "无法连接更新源,请检查网络或代理设置后重试。", + "network": "网络连接异常,请检查网络或代理设置后重试。", + "downloadFailed": "下载更新包失败,请稍后重试。", + "installFailed": "安装更新失败,请关闭应用后重试。", + "unknown": "更新失败,请稍后重试。" + } + }, + "VersionControlSettings": { + "loading": "加载中...", + "sectionTitle": "版本控制", + "sectionDescription": "配置 Git 可执行文件并管理 GitHub 账号。", + "gitTitle": "Git 配置", + "gitDescription": "配置应用使用的 Git 可执行文件。", + "gitDetected": "已检测到 Git", + "gitNotFound": "未在系统中找到 Git", + "gitVersion": "版本", + "gitPath": "路径", + "customGitPath": "自定义 Git 路径", + "customGitPathPlaceholder": "/usr/bin/git", + "customGitPathHint": "留空则使用自动检测的路径。", + "test": "测试", + "testing": "测试中...", + "testSuccess": "Git 可执行文件有效。", + "testFailed": "Git 测试失败:{message}", + "save": "保存", + "saving": "保存中...", + "saveSuccess": "Git 设置已保存。", + "saveFailed": "保存失败:{message}", + "githubTitle": "GitHub 账号", + "githubDescription": "管理用于身份验证的 GitHub 账号。令牌存储在本地。", + "noAccounts": "暂无 GitHub 账号。", + "addAccount": "添加账号", + "serverUrl": "服务器地址", + "serverUrlPlaceholder": "https://github.com", + "token": "个人访问令牌", + "tokenPlaceholder": "ghp_xxxxxxxxxxxx", + "generateToken": "生成令牌", + "tokenHint": "在 GitHub → Settings → Developer settings → Personal access tokens 中生成令牌。", + "validateAndAdd": "验证并添加", + "validating": "验证中...", + "addSuccess": "账号 {username} 添加成功。", + "addFailed": "添加账号失败:{message}", + "testConnection": "测试", + "connectionSuccess": "连接成功。", + "connectionFailed": "连接失败:{message}", + "setDefault": "设为默认", + "defaultLabel": "默认", + "defaultSet": "默认账号已更新。", + "removeAccount": "删除", + "removeConfirmTitle": "删除账号", + "removeConfirmMessage": "确定要删除账号「{username}」吗?", + "removeConfirm": "删除", + "removeCancel": "取消", + "removeSuccess": "账号已删除。", + "scopes": "权限范围", + "loadFailed": "加载设置失败:{message}", + "gitAccount": { + "sectionTitle": "Git 服务器账号", + "sectionDescription": "管理非 GitHub 的 Git 服务器凭据(GitLab、Bitbucket、自建服务等)。", + "noAccounts": "暂无 Git 服务器账号。", + "addAccount": "添加账号", + "addTitle": "添加 Git 账号", + "addDescription": "输入服务器地址、用户名和密码或访问令牌。", + "serverUrl": "服务器地址", + "serverUrlPlaceholder": "https://gitlab.example.com", + "username": "用户名", + "usernamePlaceholder": "用户名或邮箱", + "password": "密码 / 令牌", + "passwordPlaceholder": "密码或访问令牌", + "passwordHint": "输入服务器的密码或个人访问令牌。", + "add": "添加", + "serverRequired": "请输入服务器地址。", + "usernameRequired": "请输入用户名。", + "passwordRequired": "请输入密码。" + } + }, + "ShortcutSettings": { + "sectionTitle": "快捷键", + "resetDefault": "恢复默认", + "recordInstruction": "点击右侧按钮后按下组合键即可修改。建议使用 Ctrl/Cmd、Alt、Shift 的组合。按 Esc 可取消录制。", + "recording": "按下快捷键...", + "toasts": { + "conflict": "快捷键已被「{title}」占用", + "updated": "快捷键已更新", + "invalid": "快捷键无效,请重试", + "reset": "已恢复默认快捷键" + }, + "actions": { + "toggle_search": { + "title": "打开搜索", + "description": "打开或关闭会话搜索面板" + }, + "toggle_sidebar": { + "title": "切换左侧边栏", + "description": "显示或隐藏会话列表侧边栏" + }, + "toggle_terminal": { + "title": "切换终端", + "description": "显示或隐藏底部终端面板" + }, + "new_terminal_tab": { + "title": "新建终端", + "description": "当最近鼠标活动在终端时新建终端标签" + }, + "close_current_terminal_tab": { + "title": "关闭当前终端", + "description": "当最近鼠标活动在终端时关闭当前终端标签" + }, + "toggle_aux_panel": { + "title": "切换右侧面板", + "description": "显示或隐藏辅助信息面板" + }, + "new_conversation": { + "title": "新建会话", + "description": "在当前文件夹中创建新的对话标签" + }, + "open_folder": { + "title": "打开文件夹", + "description": "打开文件夹选择器并在新窗口中打开" + }, + "open_settings": { + "title": "打开设置", + "description": "打开设置窗口" + }, + "close_current_tab": { + "title": "关闭当前标签", + "description": "关闭当前会话或文件标签" + }, + "close_all_file_tabs": { + "title": "关闭全部文件标签", + "description": "当文件面板处于活动状态时关闭所有打开的文件标签" + }, + "next_tab": { + "title": "下一个标签页", + "description": "切换到下一个会话或文件标签页" + }, + "prev_tab": { + "title": "上一个标签页", + "description": "切换到上一个会话或文件标签页" + }, + "send_message": { + "title": "发送消息", + "description": "在输入框中发送当前消息" + }, + "newline_in_message": { + "title": "消息换行", + "description": "在输入框中插入换行符" + }, + "toggle_custom_style": { + "title": "停用/恢复自定义样式", + "description": "逃生舱:一键关闭全部自定义配色与 CSS,再按一次恢复" + } + } + }, + "SkillsSettings": { + "title": "Skills", + "description": "左侧选择 Skill,右侧默认预览 Markdown,点击编辑后可修改并保存。", + "loadingAgents": "正在加载支持 Skills 的 Agent...", + "emptyNoManageableAgents": "当前没有可管理 Skills 的 Agent。", + "managedTarget": "管理对象", + "selectAgentPlaceholder": "请选择 Agent", + "searchPlaceholder": "搜索名称 / ID / 路径...", + "skillsList": "Skills 列表", + "loadingSkills": "加载 Skills 中...", + "agentNotSupported": "当前 Agent 暂不支持 Skills 管理。", + "emptySkills": "暂无 Skill,可点击“新建 Skill”。", + "newSkillTitle": "新建 Skill", + "skillInfo": "Skill 信息", + "skillIdPlaceholder": "Skill ID(例如:my-skill)", + "skillsDirectoryWithPath": "Skills目录:{path}", + "skillsDirectoryNeedId": "Skills目录:请输入 Skill ID 以生成完整路径", + "markdownContent": "Markdown 内容", + "editingStatus": "编辑中", + "previewStatus": "预览中", + "contentPlaceholder": "输入 Skill 文本内容...", + "metadataTitle": "Skills 元信息", + "onlyYamlMetadata": "该 Skill 仅包含 YAML 元信息。", + "emptyContentHint": "暂无内容。点击“编辑”开始输入。", + "loadingSkill": "正在加载 Skill...", + "emptyNoAgents": "暂无可用 Agent。", + "noSelectionHint": "从左侧选择一个 Skill,或点击“新建 Skill”创建。", + "systemBadge": "系统", + "systemHint": "CLI 内置 Skill · 只读", + "scope": { + "global": "全局", + "folder": "文件夹", + "selectFolderPlaceholder": "选择文件夹", + "noFolders": "未找到任何文件夹", + "pickFolderHint": "选择一个文件夹以查看其 Skills。" + }, + "actions": { + "preview": "预览", + "edit": "编辑", + "openInWindow": "在新窗口打开", + "delete": "删除", + "deleting": "删除中...", + "refresh": "刷新", + "newSkill": "新建 Skill", + "reset": "重置", + "save": "保存", + "saving": "保存中...", + "cancel": "取消" + }, + "deleteDialog": { + "title": "删除 Skill", + "confirm": "确认删除当前 Skill 吗?该操作无法撤销。", + "confirmWithNamePrefix": "确认删除 Skill", + "confirmWithNameSuffix": "吗?该操作无法撤销。" + }, + "toasts": { + "loadFailed": "加载 Skill 失败", + "openFolderFailed": "打开目录失败", + "noSkillDirectory": "当前 Agent 未找到可用的 Skills 目录", + "nameRequired": "Skill 名称不能为空", + "updated": "Skill 已更新", + "created": "Skill 已创建", + "saveFailed": "保存 Skill 失败", + "deleted": "Skill 已删除", + "deleteFailed": "删除 Skill 失败" + }, + "templates": { + "gemini": "---\nname: example-skill\ndescription: Describe when this skill should be used.\n---\n\n# Skill Name\n\nInstructions for the agent when this skill is active.\n\n## Workflow\n\n1. Add actionable step one.\n2. Add actionable step two.\n", + "openCode": "---\nname: example-skill\ndescription: Describe when this skill should be used.\n---\n\n# Purpose\n\nDescribe what this skill helps with.\n\n# Steps\n\n1. Add actionable step one.\n2. Add actionable step two.\n", + "openClaw": "---\nname: example-skill\ndescription: Describe when this skill should be used.\nuser-invocable: true\ndisable-model-invocation: false\n---\n\n# Purpose\n\nDescribe what this skill helps with.\n\n# Instructions\n\n1. Add actionable instruction one.\n2. Add actionable instruction two.\n", + "default": "---\nname: example-skill\ndescription: Describe when this skill should be used.\n---\n\n# Skill: example-skill\n\n## When to use\n\n- Describe trigger conditions.\n\n## Instructions\n\n1. Add actionable instruction one.\n2. Add actionable instruction two.\n" + } + }, + "McpSettings": { + "loading": "加载中...", + "summary": { + "missingCommand": "(缺少 command)", + "missingUrl": "(缺少 url)" + }, + "protocol": { + "stdio": "Stdio" + }, + "errors": { + "selectInstallProtocol": "请选择安装协议", + "fieldRequired": "{field} 为必填项", + "fieldNeedsBoolean": "{field} 需要 true 或 false", + "fieldNeedsNumber": "{field} 需要数字", + "fieldNeedsInteger": "{field} 需要整数", + "fieldInvalidJson": "{field} JSON 无效:{message}", + "fieldOutOfRange": "{field} 的值不在可选范围内", + "jsonEmpty": "{name} 不能为空", + "jsonInvalid": "{name} 不是合法 JSON:{message}", + "jsonMustBeObject": "{name} 必须是 JSON 对象", + "specMustBeObject": "MCP 配置必须是 JSON 对象。", + "missingType": "MCP 配置缺少 type 字段。请填写 stdio、http(别名 streamable-http、streamableHttp)、sse 之一。", + "unsupportedType": "不支持的 MCP type:{type}。支持的类型:stdio、http(别名 streamable-http、streamableHttp)、sse。", + "codexEntryUnsupportedType": "Codex MCP 条目 {id} 的 type 不受支持:{type}。支持的类型:stdio、http(别名 streamable-http、streamableHttp)、sse。", + "unsupportedTransportType": "不支持的 transport 类型:{type}。支持的类型:http(别名 streamable-http、streamableHttp)、sse。", + "stdioCommandRequired": "stdio 类型的 MCP 必须填写非空的 command 字段。", + "remoteUrlRequired": "远端 MCP 必须填写非空的 url 字段。", + "appsRequired": "请至少选择一个目标 App。" + }, + "jsonNames": { + "localConfig": "MCP 配置", + "installConfig": "安装配置" + }, + "toasts": { + "uninstalled": "已卸载 MCP", + "uninstallFailed": "卸载失败:{message}", + "selectAtLeastOneApp": "请至少选择一个目标应用", + "saveSuccess": "保存成功", + "saveFailed": "保存失败:{message}", + "installed": "已安装 {name}", + "installFailed": "安装失败:{message}", + "serverIdRequired": "Server ID 不能为空", + "serverIdExists": "Server ID \"{id}\" 已存在,请编辑现有项或更换名称", + "created": "MCP 已创建" + }, + "installDialog": { + "title": "确认安装 MCP", + "descriptionWithName": "将 {name} 安装到本地配置。", + "description": "选择安装目标应用。", + "protocol": "协议", + "selectProtocol": "选择协议", + "parameters": "配置参数", + "booleanPlaceholder": "请选择 true/false", + "selectOneValue": "选择一个值", + "targetApps": "目标应用" + }, + "actions": { + "cancel": "取消", + "confirmInstall": "确认安装", + "installing": "安装中", + "uninstall": "卸载", + "uninstalling": "卸载中", + "viewDetails": "查看详情", + "save": "保存", + "saving": "保存中", + "install": "安装", + "refresh": "刷新", + "newMcp": "新建 MCP", + "create": "创建", + "creating": "创建中..." + }, + "tabs": { + "local": "本地 MCP", + "market": "MCP 市场" + }, + "local": { + "filterPlaceholder": "筛选本地 MCP...", + "loadFailed": "加载失败:{message}", + "empty": "当前未检测到本地 MCP。", + "description": "本地 MCP 配置可直接编辑并保存。", + "enabledApps": "启用应用", + "configJson": "MCP 配置(JSON)", + "draftTitle": "新建 MCP", + "draftDescription": "填写 Server ID 与配置以创建本地 MCP 服务器。", + "serverIdLabel": "Server ID", + "serverIdPlaceholder": "Server ID(例如:my-mcp)", + "typeHint": "支持类型:stdio、http(别名 streamable-http、streamableHttp)、sse。env 仅适用于 stdio;远端 MCP 请通过 headers 字段传递鉴权 token。", + "envOnRemoteWarning": "检测到远端 MCP 配置中包含 env 字段。env 仅 stdio 类型使用,远端 MCP 应通过 headers 携带鉴权信息,env 字段保存时会被忽略。" + }, + "market": { + "selectMarketplace": "选择市场", + "searchPlaceholder": "搜索 MCP...", + "searchFailed": "搜索失败:{message}", + "loadingList": "加载 MCP 列表...", + "empty": "暂无 MCP 结果。", + "loadingDetail": "加载市场详情...", + "detailLoadFailed": "加载详情失败:{message}", + "owner": "所有者:{owner}", + "namespace": "命名空间:{namespace}", + "defaultInstallProtocol": "默认安装协议", + "currentOptionParameterCount": "当前选项参数数:{count}", + "installConfigDescription": "安装配置(JSON,可修改后安装;修改后将覆盖协议/参数表单)", + "selectLeftToView": "请选择左侧市场 MCP 查看详情。" + }, + "badges": { + "verified": "已验证", + "remote": "远程", + "hasHomepage": "有主页", + "uses": "{count} 次使用", + "deployed": "已部署", + "notDeployed": "未部署" + }, + "selectLeftMcp": "请选择左侧 MCP。" + }, + "AcpAgentSettings": { + "title": "Agent SDK管理", + "description": "统一管理 Agent 的连接SDK、启用状态、环境变量、配置管理与版本预检信息。", + "loadingAgents": "加载 Agent 列表中...", + "agentList": "Agent 列表", + "emptyNoAgent": "暂无可用 Agent。", + "configManagement": "配置管理", + "envVars": "环境变量", + "hostTools": { + "label": "由 Agent 自行处理文件与命令", + "description": "codeg 不再代为提供文件访问和终端命令,改由 Agent 在自己的进程中执行——只有这样它自带的沙箱与权限规则才会生效。同时会关闭向其他 Agent 委托,否则同样的操作又会绕回 codeg 执行。codeg 本身不提供沙箱,因此请仅在 Agent 已配置沙箱时开启。" + }, + "nativeJsonConfig": "原生 JSON 配置", + "modelHintDefault": "留空则使用系统默认模型。", + "generalConfigDescriptionClaude": "支持 API URL、API Key 与 Claude 模型快捷配置,并与原生 JSON 配置联动。", + "generalConfigDescriptionDefault": "支持重要配置输入(API URL、API Key、Model)和原生 JSON 配置管理。", + "multiAgent": { + "title": "多智能体协同", + "description": "允许活跃的智能体把子任务委托给其他智能体。", + "enable": "启用委托", + "enableHint": "关闭后,delegate_to_agent 工具会从智能体的 MCP 工具清单中隐藏。", + "withheldByHostTools": "{agents} 不会拿到委派工具:它们单独开启了「由 Agent 自行处理文件与命令」。", + "selfInitiate": "Allow spawn without @", + "selfInitiateHint": "When on, an agent may start a listed sub-agent on its own. An @ mention is still always honored. When off, only an @ mention starts a sub-agent.", + "depthLimit": "最大委托深度", + "depthHint": "允许范围:{min}–{max}。限制委托链(根 → 子 → 孙 …)的最大递归深度。", + "completedCacheLabel": "已完成结果缓存(MB)", + "completedCacheHint": "运行中委托会话已完成子智能体结果的内存缓存,仅在该会话运行期间保留,会话结束后自动清除。超出此预算时优先从内存中丢弃最旧的结果(仍可在子智能体自己的会话中查看);0 表示不限(会话结束后仍会清除)。", + "save": "保存", + "saving": "保存中…", + "saved": "委托设置已保存", + "saveFailed": "委托设置保存失败", + "loadFailed": "加载委托设置失败:{detail}", + "tabGeneral": "通用", + "tabAgentDefaults": "子智能体配置", + "agentDefaultsDescription": "多智能体协同在为委托调用启动子智能体时使用这些覆盖项。下方选项通过实时探测获取,所选即所用。", + "probing": "正在加载该智能体的可用配置项…", + "probeFailed": "加载配置项失败:{detail}", + "retry": "重试", + "noConfigAvailable": "该智能体没有可配置项。", + "modeLabel": "模式", + "agentDefaultHint": "智能体默认:{value}", + "defaultOptionLabel": "默认({value})" + }, + "actions": { + "dragSort": "拖拽排序", + "dragSortAgent": "拖拽排序 {name}", + "refreshCheck": "刷新检测", + "refreshCheckAgent": "刷新检测 {name}", + "clickEnable": "点击启用 {name}", + "clickDisable": "点击禁用 {name}", + "install": "安装", + "upgrade": "升级", + "uninstall": "卸载", + "uninstalling": "卸载中...", + "saveEnvVars": "保存环境变量", + "saving": "保存中...", + "saveGrokConfig": "保存 Grok 配置", + "saveCodexConfig": "保存 Codex 配置", + "saveGeminiConfig": "保存 Gemini 配置", + "saveOpenCodeConfig": "保存 OpenCode 配置", + "saveOpenClawConfig": "保存 OpenClaw 配置", + "saveConfigManagement": "保存配置管理", + "saveCurrentProvider": "保存当前 Provider", + "showApiKey": "显示 API Key", + "hideApiKey": "隐藏 API Key", + "showKey": "显示 Key", + "hideKey": "隐藏 Key", + "showToken": "显示 Token", + "hideToken": "隐藏 Token", + "cancel": "取消", + "delete": "删除", + "deleting": "删除中...", + "confirmDelete": "确认删除", + "confirmUninstall": "确认卸载", + "saveClineConfig": "保存 Cline 配置", + "saveHermesConfig": "保存 Hermes 配置", + "saveCodeBuddyConfig": "保存 CodeBuddy 配置", + "saveKimiCodeConfig": "保存 Kimi Code 配置", + "customInstall": "自定义安装", + "saveKimiCodeRawConfig": "保存 config.toml", + "saveDeepSeekConfig": "保存 DeepSeek 配置", + "diagnose": "诊断" + }, + "status": { + "enabled": "启用", + "disabled": "禁用", + "unchecked": "未检测", + "agentEnabledAria": "{name} 已启用", + "agentEnabledSwitch": "{name} 启用" + }, + "preflight": { + "count": "预检项:{count}", + "notRun": "尚未执行检测。" + }, + "grok": { + "configDescription": "在此配置 Grok。下方控件——权限模式、推理强度、可选的自定义(自带端点)模型和压缩——会合并写入 ~/.grok/config.toml,并保留你的其他键与注释。登录使用你的 XAI_API_KEY 或 `grok login`。其他键可在“高级”中编辑。", + "permissionModeLabel": "权限模式", + "permissionDefault": "每次询问", + "permissionAcceptEdits": "自动批准编辑", + "permissionAuto": "智能自动批准", + "permissionAlwaysApprove": "始终允许", + "reasoningEffortLabel": "推理级别", + "effortLow": "低(更快)", + "effortMedium": "中(均衡)", + "effortHigh": "高", + "effortXhigh": "最高", + "optionDefault": "使用默认", + "authTitle": "认证", + "authMode": "认证方式", + "authModeApiKey": "XAI API 密钥", + "authModeApiKeyHint": "使用 xAI 控制台的 XAI_API_KEY 认证——适用于非交互/无头运行。保存在该智能体的环境变量中。", + "authModeCustom": "自定义接口", + "authModeCustomHint": "使用自定义接口(BYO 端点):在下方定义一个带有独立 base URL 和 API 密钥的自定义模型,它将成为 Grok 的默认模型。", + "subscriptionHint": "使用 `grok login` 登录(SuperGrok / X Premium+)。不保存 API 密钥。", + "loginHint": "在终端运行以下命令登录,然后重新打开此设置:", + "commandCopied": "命令已复制到剪贴板", + "copyCommand": "复制命令", + "authKeyConfigured": "已配置 XAI_API_KEY。", + "authKeyMissing": "未设置 XAI_API_KEY。", + "advancedToggle": "高级(原始 config.toml)", + "configTomlNative": "config.toml(原生)", + "configTomlHint": "按原样整体写入 ~/.grok/config.toml。非法 TOML 会被拒绝,绝不因笔误截断文件。", + "configTomlPlaceholder": "# 上面控件之外的键,例如\n# [mcp_servers.*]、[cli]、[permission] 规则。", + "customModelTitle": "自定义模型(自带端点)", + "customModelHint": "让 Grok 指向自定义或自托管端点。codeg 会写入按模型的 `[model.*]` 块并将其设为默认模型。清空模型 ID 即可移除。", + "customModelIdLabel": "模型 ID", + "customModelIdPlaceholder": "grok-4.5", + "customModelIdHint": "注册为 `[model.*]` 块,并作为模型名发送给 API;同时设为 `[models].default`。", + "customBaseUrlLabel": "Base URL", + "customBaseUrlPlaceholder": "https://api.x.ai/v1(默认)", + "customApiBackendLabel": "API 后端", + "backendResponses": "Responses", + "backendChatCompletions": "Chat Completions", + "backendMessages": "Messages(Anthropic)", + "customApiKeyLabel": "API Key", + "customApiKeyHint": "内联存储于 `[model.*].api_key`,仅作用于该端点。", + "customContextWindowLabel": "上下文窗口(tokens)", + "customContextWindowHint": "可选。用于自动压缩计时;留空则使用端点默认值。", + "autoCompactLabel": "自动压缩阈值(%)", + "autoCompactHint": "当上下文使用率达到该百分比时压缩对话(Grok 默认 85)。写入 `[session]`。" + }, + "cursor": { + "configDescription": "在此配置 Cursor。先选择认证方式——官网订阅(浏览器登录)或用于无头/服务器的 Cursor API 密钥——然后选择模型并编辑 CLI 的权限规则与沙箱。codeg 会写入 ~/.cursor/cli-config.json,与 cursor-agent CLI 共享。", + "authTitle": "鉴权", + "authChecking": "检测中…", + "authNotInstalled": "cursor-agent 未安装", + "authLoggedIn": "已登录", + "authNotLoggedIn": "未登录", + "loginHint": "在终端运行以下命令登录 Cursor 账号(会打开浏览器),完成后点刷新:", + "apiKeyLabel": "Cursor API 密钥", + "apiKeyPlaceholder": "在 cursor.com/dashboard 获取", + "apiKeyHint": "CURSOR_API_KEY —— Cursor Dashboard 的账号密钥,在无头/服务器环境下替代浏览器登录。不是第三方或 OpenAI 密钥。", + "modelTitle": "默认模型", + "loadModels": "获取模型列表", + "modelsUnavailable": "模型列表不可用", + "modelHint": "会话启动时通过 --model 传给 CLI;保持默认则由 Cursor 自行选择。", + "permissionsTitle": "权限与沙箱", + "permissionsDescription": "可视化编辑 CLI 权限规则(cli-config.json)。允许规则免确认执行;拒绝规则始终拦截。", + "permissionModeLabel": "权限模式", + "permissionModeDefault": "执行前询问(默认)", + "permissionModeForce": "全部放行 Run Everything(--force)", + "permissionModeHint": "Run Everything 以 --force 启动会话:除 deny 规则外的所有工具调用自动放行、不再弹确认(组织策略可能将其降级为仅按 allow 规则放行)。对新会话生效。", + "optionDefault": "默认(未设置)", + "sandboxLabel": "沙箱", + "sandboxEnabled": "启用", + "sandboxDisabled": "禁用", + "allowRulesLabel": "允许规则", + "denyRulesLabel": "拒绝规则", + "addRule": "添加规则", + "rulesSyntaxHint": "规则语法:Shell(命令)、Read(路径/通配)、Write(路径/通配)、WebFetch(域名)、Mcp(服务器:工具)——deny 规则始终优先。", + "saveConfig": "保存配置", + "advancedToggle": "高级:原始 cli-config.json", + "advancedHint": "完整的 ~/.cursor/cli-config.json。此处保存按原文写入;上方结构化控件则以合并方式写入。", + "saveRawConfig": "保存文件", + "authMode": "认证方式", + "subscriptionHint": "使用 Cursor 账号登录,使用 Cursor 的模型。", + "customApiKeyRequired": "需要填写 Cursor API 密钥。", + "authModeApiKey": "Cursor API 密钥(无头/服务器)", + "authModeApiKeyHint": "用 Cursor 官网 Dashboard 生成的账号 API 密钥认证(适用于无头/服务器环境)。这是 Cursor 账号密钥,不是第三方/OpenAI 端点——cursor-agent 只连 Cursor 自己的后端。要使用 codex/OpenAI 兼容端点,请改用 Codex 智能体。", + "modelPickerPlaceholder": "搜索模型…", + "modelNoMatch": "没有匹配的模型", + "modelsNeedAuth": "登录后加载模型列表。", + "modelDefaultBadge": "默认" + }, + "deepseek": { + "configManagement": "DeepSeek Harness 配置", + "configDescription": "端点与密钥是 deepseek-acp 启动时读取的环境变量。模型和推理档位是会话级选择器,在输入框里切换。", + "baseUrlLabel": "API 端点", + "baseUrlHint": "留空则使用官方端点。保存后对新建的会话生效——正在进行的会话需要重新连接才会切换。", + "baseUrlInvalid": "请填写完整的 http(s) 地址且不带查询参数,例如 https://api.deepseek.com", + "apiKeyLabel": "API 密钥", + "apiKeyHint": "以 DEEPSEEK_API_KEY 传给智能体。环境变量的优先级高于凭据文件,因此若用终端登录,这里留空即可。" + }, + "codex": { + "configDescription": "支持 API URL、API Key、模型名称、Reasoning Effort 快捷配置,并与 `auth.json` / `config.toml` 双向联动。", + "authMode": "认证方式", + "chatgptSubscription": "官网订阅", + "chatgptSubscriptionHint": "使用 ChatGPT 官网订阅登录,无需配置 API Key", + "apiKeyHint": "使用 API Key 连接 OpenAI 或兼容的 API 服务", + "selectProvider": "选择 Provider", + "modelName": "模型名称", + "selectReasoningEffort": "选择 Reasoning Effort", + "enableWebsocket": "启用 WebSocket", + "enableWebsocketAria": "Codex Provider 启用 WebSocket", + "enableSkills": "启用 Skills", + "enableSkillsAria": "Codex 启用 Skills", + "enableFast": "启用 Fast", + "enableFastAria": "Codex 启用 Fast 服务等级", + "sandboxGroupTitle": "沙箱与审批", + "sandboxGroupHint": "写入全局 ~/.codex/config.toml,codex CLI 与 IDE 的会话同样生效。这是线程默认值,只作用于 codex 自行发起的回合(/goal、/review、/compact);普通对话使用输入框里的审批预设。改动需重开会话才生效。", + "sandboxShadowedWarning": "config.toml 里设置了 default_permissions,codex 会改走权限配置档并完全忽略 sandbox_mode。删掉 default_permissions 后下面的选项才会生效。", + "sandboxPermissionsTableWarning": "config.toml 定义了 [permissions] 配置档却没有 default_permissions,codex 会拒绝启动。请在下方原始编辑器里补上。", + "approvalPolicyLabel": "审批策略", + "approvalPolicyUnset": "未设置(codex 默认:按需询问)", + "approvalPolicy_on-request": "按需询问 — 由模型决定何时请求批准", + "approvalPolicy_untrusted": "仅信任只读 — 只有已知安全的只读命令免批准", + "approvalPolicy_never": "从不询问 — 完全不弹审批", + "approvalPolicy_granular": "精细控制 — 按提示类型分别设置", + "approvalPolicyUntrustedAcpWarning": "ACP 适配器只有三种审批预设,untrusted 无对应项,codeg 会话会退回「按需询问」——此时由模型自行决定何时询问,沙箱本就允许的命令不再询问。请改用下方的沙箱模式收紧。", + "granularHint": "关闭表示该类请求被自动拒绝,而不是弹给你确认。", + "granular_sandbox_approval": "Shell 命令越权申请", + "granular_rules": "Execpolicy 规则提示", + "granular_skill_approval": "技能脚本执行提示", + "granular_request_permissions": "request_permissions 工具提示", + "granular_mcp_elicitations": "MCP elicitation 提示", + "sandboxModeLabel": "沙箱模式", + "sandboxModeUnset": "未设置(受信任的文件夹回落为可写工作区)", + "sandboxMode_read-only": "只读", + "sandboxMode_workspace-write": "可写工作区", + "sandboxMode_danger-full-access": "完全放开(无沙箱)", + "sandboxModeHint": "在 Windows 上,未开启 codex 的实验性 Windows 沙箱时,可写工作区会被降级为只读。", + "sandboxModeSeedsPresetHint": "codeg 还会用它推导会话的初始审批预设,因此与审批策略不同,它对普通提问同样生效。输入框中选择的预设仍会覆盖它。", + "writableRootsLabel": "额外可写目录", + "writableRootsHint": "每行一个绝对路径,作为工作目录之外的额外可写位置。", + "sandboxRootsRelativeError": "必须是绝对路径 — codex 会把相对路径解析到 ~/.codex 下:{path}", + "networkAccessLabel": "允许网络访问", + "excludeTmpdirLabel": "从可写目录中排除 TMPDIR", + "excludeSlashTmpLabel": "从可写目录中排除 /tmp", + "authJsonNative": "auth.json(原生)", + "configTomlNative": "config.toml(原生)", + "loginButton": "使用 ChatGPT 登录", + "loginRequesting": "正在请求登录码...", + "loginStep1": "在浏览器中打开以下链接:", + "loginStep2": "输入以下代码:", + "loginPolling": "等待授权中...", + "loginCancel": "取消", + "loginSuccess": "登录成功,配置已保存!", + "loginFailed": "登录失败:{message}", + "loginRetry": "重试", + "loginCodeCopied": "已复制代码", + "loggedIn": "账号已登录", + "loginRelogin": "重新登录 / 切换账号", + "loginTimeout": "登录超时,请重试", + "loginSaveFailed": "登录成功但配置保存失败" + }, + "gemini": { + "authConfig": "Gemini 认证配置", + "authConfigDescription": "对齐 Gemini CLI 认证文档,支持自定义、Google 登录、Gemini API Key、Vertex AI(ADC / 服务账号 / API Key)。", + "authMode": "认证方式", + "selectAuthMode": "选择认证方式", + "viewAuthDoc": "查看认证文档", + "mode": { + "custom": "自定义接口", + "loginGoogle": "Google 登录(OAuth)", + "vertexServiceAccount": "Vertex AI(服务账号)" + }, + "hint": { + "custom": "填写 API URL、API Key 和 Model,分别映射到 GOOGLE_GEMINI_BASE_URL / GEMINI_API_KEY / GEMINI_MODEL。", + "loginGoogle": "首次在终端运行 gemini 并完成 Google 登录;无需填写 API Key。", + "geminiApiKey": "使用 Gemini API 时填写 GEMINI_API_KEY。", + "vertexAdc": "使用 gcloud ADC,建议填写 GOOGLE_CLOUD_PROJECT 与 GOOGLE_CLOUD_LOCATION。", + "vertexServiceAccount": "服务账号 JSON 路径写入 GOOGLE_APPLICATION_CREDENTIALS。", + "vertexApiKey": "使用 Vertex AI API key 时填写 GOOGLE_API_KEY。" + } + }, + "openCode": { + "configManagement": "OpenCode 配置管理", + "configDescription": "对齐 OpenCode `provider` 配置结构,支持多供应商管理,并与原生 JSON 文件双向联动。", + "providerManagement": "Provider 管理", + "providerCount": "共 {count} 个", + "addProvider": "新增 Provider", + "emptyProvider": "还没有自定义 Provider。点击「添加自定义 Provider」创建。", + "providerEnabledState": "{providerId} 启用状态", + "selectProviderNpm": "选择 provider.npm", + "modelManagement": "模型管理", + "modelCount": "共 {count} 个", + "modelDescription": "对齐 OpenCode `provider.models` 结构。当前支持 `name` / `id` 快速管理;其它高级字段会保留,可在下方原生 JSON 中继续编辑。", + "addModel": "添加模型", + "emptyModel": "暂无模型,输入 model id 后点击“添加模型”创建。", + "modelId": "模型 ID", + "modelName": "模型名称", + "deleteModel": "删除模型 {modelId}", + "nativeJsonConfig": "OpenCode 原生 JSON 配置", + "mainModel": "主模型", + "smallModel": "小模型", + "noMatchingModels": "没有匹配的模型", + "connectProvider": "连接 Provider", + "connectedProviders": "已连接的 Provider", + "noConnectedProviders": "还没有从目录连接 Provider。", + "advancedProviderConfig": "自定义 Provider", + "customProviderConfigHint": "你自己定义的 OpenAI 兼容端点——opencode.json 里的一个 provider 配置块,API key 存在 auth.json。", + "addCustomProvider": "添加自定义 Provider", + "disconnect": "断开", + "editConfig": "编辑", + "customBadge": "自定义", + "authKindApi": "API Key", + "authKindOauth": "OAuth", + "authKindNone": "无凭证", + "connect": { + "title": "连接 Provider", + "description": "从 models.dev 目录选择一个 Provider。凭证保存到 OpenCode 的 auth.json 文件。", + "pick": "Provider", + "search": "搜索 Provider…", + "loading": "正在加载目录…", + "catalogLabel": "models.dev 目录", + "modelsAvailable": "{count} 个可用模型", + "getKey": "获取 API Key", + "oauthApiKeyNote": "该 Provider 也支持通过 opencode auth login 浏览器登录。浏览器登录即将推出——目前请粘贴 API Key。", + "apiKey": "API Key", + "apiKeyHint": "保存在 auth.json,绝不写入 opencode.json。", + "baseUrlOptional": "Base URL 覆盖(可选)", + "providerId": "Provider ID", + "displayName": "显示名称", + "modelsList": "模型(每行一个)", + "modelsHint": "端点接受的模型 ID。", + "action": "连接", + "editTitle": "编辑 Provider", + "editDescription": "更新该 Provider 的 API Key 或 Base URL。", + "saveAction": "保存" + }, + "customProvider": { + "title": "添加自定义 Provider", + "description": "定义一个 OpenAI 兼容端点。API key 保存到 auth.json;provider 配置块写入 opencode.json。", + "action": "添加 Provider", + "idInCatalog": "{providerId} 是已知 Provider,请改用「连接 Provider」连接。" + }, + "refreshCatalog": "刷新目录", + "reasoningBadge": "推理", + "contextWindow": "上下文窗口", + "permissions": { + "title": "权限", + "description": "决定哪些操作直接运行、先征求你的同意,还是被阻止。写入 opencode.json 的 permission 配置,点击下方保存后生效。", + "docsLink": "权限文档", + "unparsableConfig": "下方的原生 JSON 当前无法解析,可视化编辑已暂停。修复 JSON 后即可继续。", + "invalidBlock": "permission 配置的结构无法识别。请在下方原生 JSON 中修改,或点击「恢复默认」重来。", + "orderingUnsafe": "通配规则写在了具体工具之后,OpenCode 会把它一并应用到这些工具上——下方各行显示的并非实际生效的规则。「修正顺序」只把通配规则移回各自作用域的最前面,不改动任何取值。", + "orderingUnsafeManual": "有规则被后面更宽泛的模式遮蔽,OpenCode 永远不会应用它——下方各行显示的并非实际生效的规则。两个互相重叠的模式没有唯一正确的顺序,请在下方原生 JSON 中调整,把更宽泛的写在前面。", + "fixOrder": "修正顺序", + "agentOverrides": "以下智能体单独覆盖了权限,且在最后应用,因此会盖过此处的全部设置:{agents}。请在下方原生 JSON 中修改,或开启「自动接受所有权限」将其清除。", + "legacyTools": "顶层的旧版 tools 配置禁用了某个工具。OpenCode 会把它并入权限,因此它会叠加在此处显示的全部设置之上。请在下方原生 JSON 中修改,或开启「自动接受所有权限」将其清除。", + "autoAcceptTitle": "自动接受所有权限", + "autoAcceptHint": "所有工具调用(shell 命令、文件修改、访问项目外路径)都不再询问,直接执行。开启后会用一条全局允许规则替换下方的逐工具设置,并清除各智能体单独的权限覆盖与旧版 tools 开关——否则它们仍会拦截。", + "globalLabel": "全局默认", + "globalHint": "即 * 规则:下方工具未单独覆盖时采用的动作。", + "actionUnset": "未设置(OpenCode 默认)", + "actionInherit": "跟随默认({action})", + "actionAllow": "允许", + "actionAsk": "询问", + "actionDeny": "拒绝", + "perToolTitle": "逐工具权限", + "reset": "恢复默认", + "ruleCount": "细则 {count} 条", + "rulesToggle": "{tool} 的细粒度规则", + "rulesHint": "按工具输入匹配,最后匹配的规则优先,因此请把宽泛的模式写在前面。* 匹配任意多个字符,? 精确匹配一个字符,开头的 ~ 展开为主目录。", + "noRules": "暂无细粒度规则。", + "addRule": "添加规则", + "deleteRule": "删除规则 {pattern}", + "duplicateRule": "该模式已存在。", + "blankRule": "规则必须有模式;如需删除请点击垃圾桶图标。", + "customKeys": "文件中的其他权限键", + "customKeyHint": "并非 OpenCode 内置工具,将按原样保留。", + "keys": { + "bash": "运行 shell 命令,按解析后的命令匹配", + "edit": "所有文件修改:edit、write 与 patch", + "read": "读取文件,按文件路径匹配", + "external_directory": "访问项目工作目录之外的路径", + "task": "启动子代理,按子代理类型匹配", + "skill": "加载技能,按技能名称匹配", + "glob": "查找文件,按通配模式匹配", + "grep": "搜索文件内容,按模式匹配", + "list": "列出目录内容", + "webfetch": "获取 URL", + "websearch": "网页搜索", + "lsp": "运行 LSP 查询", + "todowrite": "写入待办列表", + "question": "向你提问", + "doom_loop": "同一调用以相同输入重复 3 次时触发" + } + } + }, + "openClaw": { + "gatewayConfig": "Gateway 配置", + "gatewayDescription": "配置 OpenClaw Gateway 连接信息。支持本地或远程 Gateway。", + "gatewayUrlHint": "留空则使用 openclaw 本地配置的 gateway.remote.url。", + "gatewayTokenPlaceholder": "Gateway 认证 Token", + "gatewayTokenHint": "建议使用 token-file 替代明文 Token,可通过 openclaw 命令行配置。", + "sessionKeyHint": "可选。指定 Gateway Session Key,留空则自动分配隔离会话。" + }, + "hermes": { + "configManagement": "Hermes 配置", + "configDescription": "Hermes 在 ~/.hermes/.env 中管理自己的凭据,在 ~/.hermes/config.yaml 中管理设置。选择一个供应商,然后设置 API 密钥和模型——codeg 会替你写入这两个文件。", + "providerLabel": "供应商", + "providerHint": "供应商决定 Hermes 使用哪个 API 密钥变量和 model.provider。OAuth 供应商通过下方的终端设置进行配置。", + "groupApiKey": "API 密钥提供商", + "groupOauth": "OAuth 提供商", + "groupAws": "AWS", + "apiKeyHint": "保存到 ~/.hermes/.env。它绝不会被注入进程——Hermes 会从自己的配置中读取它。", + "modelName": "模型", + "oauthHint": "此供应商使用 OAuth。请运行下方的设置流程,在终端中完成认证。", + "awsHint": "Bedrock 使用你的 AWS 凭据(环境变量或共享配置)。请在上方填写模型 ID,并在系统环境中配置 AWS 访问权限。", + "unsupportedProvider": "该提供商无法通过结构化字段编辑。请使用下方的 config.yaml 原始编辑器或终端引导设置。", + "setupTitle": "自管理设置", + "setupHint": "Hermes 的交互式设置需要终端。可在下方启动,或复制命令自行运行。", + "runSetup": "运行 Hermes 设置", + "configureModel": "配置模型", + "openConfigFolder": "打开 ~/.hermes", + "copyCommand": "复制命令", + "commandCopied": "命令已复制到剪贴板", + "advancedTitle": "高级:编辑 config.yaml", + "rawConfigHint": "直接编辑 ~/.hermes/config.yaml。在此保存将原样覆盖该文件。", + "saveRawConfig": "保存 config.yaml" + }, + "codebuddy": { + "configManagement": "CodeBuddy 配置", + "configDescription": "CodeBuddy 使用 API Key 进行认证。中国版还必须将环境设为“中国版(internal)”;iOA 版使用“iOA”;海外版则不设置。", + "apiKeyLabel": "API Key", + "apiKeyHint": "将作为该智能体的 CODEBUDDY_API_KEY 保存。也可以在终端用 CodeBuddy CLI 登录。", + "apiKeyHintSelfHosted": "将作为该智能体的 CODEBUDDY_API_KEY 保存。请使用你的私有化部署签发的密钥。", + "environmentLabel": "环境", + "environmentHint": "设置 CODEBUDDY_INTERNET_ENVIRONMENT。中国大陆必须使用“中国版(internal)”;海外版则不设置。", + "envOverseas": "海外版(默认)", + "envChina": "中国版(internal)", + "envIoa": "iOA", + "envSelfHosted": "私有化部署", + "baseUrlLabel": "私有化部署地址", + "baseUrlPlaceholder": "https://codebuddy.your-company.com", + "baseUrlHint": "保存为 CODEBUDDY_BASE_URL,将 CodeBuddy 指向你的私有端点。私有化部署不设置网络环境(CODEBUDDY_INTERNET_ENVIRONMENT)。", + "baseUrlInvalid": "请输入合法的 http(s) 地址。", + "loginHint": "没有 API Key?也可以在终端运行 “codebuddy” 用腾讯云账号登录。" + }, + "kimiCode": { + "configManagement": "Kimi Code 配置", + "configDescription": "`kimi acp` 只认已存储的登录令牌,所以 codeg 会在 ~/.kimi-code/config.toml 写入受管供应商,并在本地播种一个门控令牌——推理仍然走你自己的 Key。", + "statusUnconfigured": "尚未配置", + "statusDirty": "有未保存的修改", + "summaryLabel": "生效配置", + "gateReadyApiKey": "API Key 已写入 config.toml", + "gateReadyLogin": "已通过 Kimi 账号登录", + "revealConfig": "在文件夹中显示", + "envOverrideWarning": "检测到 {keys},其优先级高于 config.toml。在此保存会自动清除它。", + "authModeLabel": "鉴权方式", + "authModeApiKey": "API Key", + "authModeLogin": "Kimi 账号登录(订阅)", + "authModeApiKeyHint": "在 config.toml 写入受管供应商,并播种门控令牌以便会话能够打开。", + "loginHint": "在终端运行 `kimi login`,用 Kimi 订阅账号登录。codeg 不存储任何凭据,复用 Kimi 自己的登录。在此保存会移除 codeg 的 API Key 门控令牌。", + "credentialTitle": "凭据", + "interfaceTypeLabel": "供应商类型", + "interfaceTypeHint": "Kimi 使用的供应商协议(config.toml 的 `type`)。Moonshot / platform.kimi.com 的 Key 请选「Kimi / Moonshot」。", + "endpointLabel": "接入点", + "endpointCustom": "自定义(OpenAI 兼容)", + "endpointHint": "国际 = api.moonshot.ai;中国(platform.kimi.com 的 Key)= api.moonshot.cn。自定义可指向任意 OpenAI 兼容端点。", + "regionInternational": "国际(api.moonshot.ai)", + "regionChina": "中国(api.moonshot.cn)", + "baseUrlLabel": "Base URL", + "baseUrlHint": "留空则使用供应商 SDK 默认值。", + "apiKeyLabel": "API Key", + "apiKeyHint": "写入 ~/.kimi-code/config.toml 并用于推理。来自 platform.kimi.com 或 platform.kimi.ai。", + "vertexProjectLabel": "GCP 项目(GOOGLE_CLOUD_PROJECT)", + "vertexLocationLabel": "GCP 区域(GOOGLE_CLOUD_LOCATION)", + "vertexHint": "Vertex AI 使用 Google 应用默认凭据——运行 `gcloud auth application-default login`(无需 API Key)。", + "modelTitle": "模型", + "modelLabel": "模型", + "modelHint": "写入 config.toml 的模型 id。点「测试并获取模型」可查看你的 Key 实际能访问哪些模型。", + "maxContextLabel": "最大上下文长度", + "maxContextHint": "Kimi 的配置 schema 要求必填:缺失会让 Kimi 丢弃整个模型块,导致每次对话都没有回复。默认 262144。", + "fetchModels": "测试并获取模型", + "fetchModelsOk": "Key 可用——共 {count} 个模型", + "fetchModelsEmpty": "Key 可用,但未返回任何模型", + "fetchModelsFailed": "测试失败", + "fetchModelsNeedsKey": "请先填写 API Key 和接入点", + "modelNotInList": "该模型不在你的 Key 可访问列表中,Kimi 会报「模型不存在」。", + "reasoningTitle": "推理", + "reasoningEnableLabel": "启用", + "reasoningDescription": "只有当模型声明了推理能力,Kimi 才会在输入框显示「Thinking」选择器,所以这里由 codeg 写入该声明。对新建会话生效。", + "effortsLabel": "可选档位", + "effortsHint": "这些会成为输入框「Thinking」选择器里的档位。Kimi 会把档位原样透传给供应商,请选你的模型能接受的值。", + "effortsEmptyHint": "一个档位都不选时,输入框只会退化成 Off / On 两档开关。", + "effortsCustomPlaceholder": "添加其它档位", + "effortsAdd": "添加", + "defaultEffortLabel": "默认档位", + "defaultEffortAuto": "由 Kimi 决定", + "alwaysThinkingLabel": "模型始终推理——从选择器中去掉 Off 档", + "fixErrorsFirst": "请先修正标红的字段", + "errorModelRequired": "模型为必填项", + "errorMaxContextRequired": "最大上下文长度为必填项", + "errorMaxContextInvalid": "必须是正整数", + "errorApiKeyRequired": "API Key 为必填项", + "errorApiKeyInvalid": "API Key 不能包含换行", + "errorBaseUrlRequired": "Base URL 为必填项", + "errorBaseUrlInvalid": "必须以 http:// 或 https:// 开头", + "errorVertexProjectRequired": "GCP 项目为必填项", + "errorDefaultEffortUnlisted": "必须是上面已选中的档位之一", + "advancedTitle": "高级", + "authTypeLabel": "凭据写入位置", + "authTypeApiKey": "内联 api_key", + "authTypeEnv": "供应商 env 子表", + "authTypeHint": "API Key 在 config.toml 中的写入位置。", + "rawEditorLabel": "直接编辑 config.toml", + "rawEditorWarning": "在此保存会按原文覆盖整个文件,替换掉上方的结构化配置。", + "rawEditorPlaceholder": "[providers.codeg]\ntype = \"kimi\"\nbase_url = \"https://api.moonshot.cn/v1\"\napi_key = \"sk-...\"" + }, + "authModeOfficialSubscription": "官网订阅", + "authModeCustomEndpoint": "自定义接口", + "authModeCustomEndpointHint": "手动配置 API URL 和 API Key 连接自定义接口。", + "authModeModelProvider": "模型供应商", + "modelProvider": "模型供应商", + "modelProviderHint": "使用已配置的模型供应商的 API URL、API Key 和模型。", + "selectModelProvider": "选择模型供应商", + "noModelProviderAvailable": "该代理未配置模型供应商。请前往模型供应商设置添加。", + "claude": { + "authMode": "认证方式", + "officialSubscription": "官方订阅", + "officialSubscriptionHint": "使用 Anthropic 官方订阅,无需 API Key。", + "mainModel": "主模型", + "reasoningModel": "推理模型(thinking)", + "haikuDefaultModel": "Haiku 默认模型", + "sonnetDefaultModel": "Sonnet 默认模型", + "opusDefaultModel": "Opus 默认模型", + "customModelOption": "自定义模型 ID", + "customModelOptionName": "自定义模型名称", + "customModelOptionDescription": "自定义模型描述", + "customModelOptionHint": "在 Claude 模型选择器中追加一个自定义条目(例如经自定义网关/代理提供的模型)。名称与描述为可选的显示信息。", + "effortLevel": "推理级别", + "effortLevelDefault": "默认级别", + "effortLevel_low": "低", + "effortLevel_medium": "中", + "effortLevel_high": "高", + "effortLevel_xhigh": "超高", + "sendAttributionHeader": "向接口发送归属/计费标识", + "sendAttributionHeaderAria": "向接口发送 Claude Code 归属/计费标识", + "disableNonessentialTraffic": "禁用遥测或多余的网络请求", + "disableNonessentialTrafficAria": "禁用 Claude Code 遥测或多余的网络请求" + }, + "dialogs": { + "confirmDeleteProvider": "确认删除 Provider {providerId}?", + "confirmDeleteProviderDescription": "将同步更新 OpenCode 配置与认证 JSON 文件,删除后不可恢复。", + "confirmUninstall": "确认卸载 {name}?", + "confirmUninstallDescription": "这会移除本地安装版本,之后可随时重新安装。", + "customInstallTitle": "自定义安装 {name}", + "customInstallDescription": "输入要安装的版本号。将重新安装并替换当前已安装的版本。", + "customInstallVersionLabel": "版本号", + "customInstallInvalid": "请输入有效的版本号,例如 1.2.3。", + "customInstallSubmit": "安装" + }, + "errors": { + "windowsFileLocked": "{name} 的程序文件正被运行中的会话占用,Windows 下无法替换。请先关闭所有 {name} 会话后重试。", + "nativeJsonMustBeObject": "原生 JSON 配置必须是对象", + "nativeJsonInvalid": "原生 JSON 配置格式错误:{message}", + "openCodeAuthMustBeObject": "OpenCode auth.json 必须是 JSON 对象", + "openCodeAuthInvalid": "OpenCode auth.json 格式错误:{message}", + "authMustBeObject": "auth.json 必须是 JSON 对象", + "authInvalid": "auth.json 格式错误:{message}", + "providerIdPattern": "Provider ID 仅支持字母、数字、下划线、点与中划线", + "providerExists": "Provider {providerId} 已存在", + "modelIdPattern": "模型 ID 仅支持字母、数字、下划线、点、冒号与中划线", + "modelExists": "Model {modelId} 已存在" + }, + "warnings": { + "nativeJsonRecoveredStructured": "原生 JSON 配置格式无效,已重置为结构化配置", + "nativeJsonRecoveredOpenCode": "原生 JSON 配置格式无效,已重置为 OpenCode 结构化配置", + "openCodeAuthRecovered": "OpenCode auth.json 格式无效,已重置为默认配置", + "authRecoveredStructured": "auth.json 格式无效,已重置为结构化配置" + }, + "toasts": { + "agentActionCompleted": "{name}{action}完成", + "agentActionFailed": "{name}{action}失败", + "localVersion": "本地版本:{version}", + "installCompletedVersionLater": "安装完成,版本将在下一次检测时更新", + "uninstallCompleted": "{name}卸载完成", + "uninstallFailed": "{name}卸载失败", + "localVersionRemoved": "本地版本已移除", + "saveAgentOrderFailed": "保存 Agent 排序失败", + "saveAgentSwitchFailed": "保存 Agent 开关失败", + "saveEnvFailed": "保存环境变量失败", + "grokSaved": "Grok 配置已保存", + "saveGrokNativeFailed": "保存 Grok 原生配置失败", + "saveGrokApiKeyFailed": "设置已保存,但 API Key 未能保存", + "cursorSaved": "Cursor 配置已保存", + "saveCursorConfigFailed": "保存 Cursor 配置失败", + "codexSaved": "Codex 配置已保存", + "saveCodexNativeFailed": "保存 Codex 原生配置失败", + "geminiSaved": "Gemini 配置已保存", + "saveGeminiFailed": "保存 Gemini 配置失败", + "providerDeleted": "Provider {providerId} 已删除", + "providerDeleteFailed": "删除 Provider {providerId} 失败", + "providerSaved": "Provider {providerId} 保存成功", + "saveProviderFailed": "保存 Provider {providerId} 失败", + "openCodeConfigSynced": "OpenCode 配置与认证 JSON 已同步保存。", + "openCodeSaved": "OpenCode 配置已保存", + "saveOpenCodeFailed": "保存 OpenCode 配置失败", + "openClawSaved": "OpenClaw 配置已保存", + "saveOpenClawFailed": "保存 OpenClaw 配置失败", + "configSaved": "配置已保存", + "configSavedHint": "已有会话需要重新打开才能生效", + "saveConfigManagementFailed": "保存配置管理失败", + "clineSaved": "Cline 配置已保存", + "saveClineFailed": "保存 Cline 配置失败", + "hermesSaved": "Hermes 配置已保存", + "saveHermesFailed": "保存 Hermes 配置失败", + "codeBuddySaved": "CodeBuddy 配置已保存", + "saveCodeBuddyFailed": "保存 CodeBuddy 配置失败", + "kimiCodeSaved": "Kimi Code 配置已保存", + "saveKimiCodeFailed": "保存 Kimi Code 配置失败", + "deepseekSaved": "DeepSeek 配置已保存", + "saveDeepSeekFailed": "保存 DeepSeek 配置失败", + "modelProviderRequired": "请先选择一个模型供应商再保存。", + "affectedRunningSessions": "{count} 个进行中的会话需重连以应用更改", + "providerConnected": "已连接 {providerId}", + "connectFailed": "连接 {providerId} 失败", + "providerDisconnected": "已断开 {providerId}", + "disconnectFailed": "断开 {providerId} 失败", + "catalogRefreshed": "目录已刷新——{count} 个 provider", + "catalogRefreshFailed": "刷新目录失败", + "piSaved": "Pi 配置已保存", + "savePiFailed": "保存 Pi 配置失败", + "piRuntimeSaved": "Pi 运行时已保存", + "savePiRuntimeFailed": "保存 Pi 运行时失败", + "piBinaryInstalled": "pi 已安装", + "piBinaryInstallFailed": "pi 安装失败", + "piBinaryUninstalled": "pi 已卸载", + "piBinaryUninstallFailed": "pi 卸载失败", + "savePiTrustFailed": "保存工作区信任失败" + }, + "version": { + "statusLabel": "版本状态", + "notInstalled": "未安装", + "remoteLocal": "远程:{remoteVersion} · 本地:{localVersion}", + "localOnly": "本地:{localVersion}", + "localInstalled": "{versionText}。已安装。", + "platformUnsupported": "{versionText}。当前平台不支持该 Agent。", + "uvxNotReady": "{versionText}。uv 运行时未安装——请在下方 uv 预检项中安装后再使用该 Agent。", + "clickInstall": "{versionText}。请点击右侧安装。", + "localUnrecognized": "{versionText}。本地版本无法识别,可尝试升级覆盖安装。", + "upgradeAvailable": "{versionText}。发现可升级版本。", + "remoteUnavailable": "{versionText}。远程版本暂不可用。", + "latest": "{versionText}。已是最新版本。" + }, + "adapter": { + "label": "ACP 适配器", + "badge": "ACP 适配器", + "badgeHint": "Codeg 为该智能体安装的是 ACP 适配器包,而不是厂商 CLI —— 两者互相独立,配置共享。", + "learnMore": "了解详情", + "missingWithNative": "已检测到你本地的 {nativeLabel}:{nativePath}。Codeg 通过 ACP 协议驱动智能体,而该 CLI 本身不支持 ACP,所以 Codeg 需要单独的适配器包 {adapterPackage}(由 Agent Client Protocol 项目维护,最初由 Zed 团队发起)。它自带运行时,不会修改或替换你的 {nativeCmd} 命令,读取的也是同一个 {configDir} —— 已有的登录和配置直接沿用。点击下方安装即可。", + "missing": "Codeg 通过 ACP 协议驱动智能体,而 {nativeLabel} 本身不支持 ACP,所以 Codeg 需要单独的适配器包 {adapterPackage}(由 Agent Client Protocol 项目维护,最初由 Zed 团队发起)。它自带运行时,因此不必先装 {nativeCmd} CLI;如果你已经装了,两者可以共存,并共用 {configDir} 里的登录和配置。点击下方安装即可。", + "readyWithNative": "适配器 {adapterCmd} 已安装 —— Codeg 启动的是它,而不是你本地的 {nativeCmd}({nativePath})。两者是各自独立的包,可以共存,且都读取 {configDir},登录和配置共享。", + "ready": "适配器 {adapterCmd} 已安装 —— Codeg 启动的就是它。它自带运行时,所以不需要另外安装 {nativeLabel};即便以后你装了,两者也能共存并共用 {configDir}。" + }, + "cline": { + "configDescription": "配置 Cline API 提供商和凭证。设置将保存到 ~/.cline/data/。" + }, + "opencodePlugins": { + "title": "OpenCode 插件", + "declared": "已声明的插件", + "noPlugins": "opencode.json 中未声明任何插件", + "status": { + "installed": "已安装", + "missing": "未安装" + }, + "installAll": "安装全部缺失插件", + "pinVersions": "固定 @latest 版本", + "install": "安装", + "uninstall": "卸载", + "refresh": "刷新", + "success": "所有插件安装成功", + "failed": "插件操作失败" + }, + "pi": { + "configManagement": "Pi 配置", + "configDescription": "Pi 通过模型提供方的 API Key 鉴权。Key 写入 ~/.pi/agent/auth.json,模型选择写入 settings.json。", + "providerLabel": "提供方", + "modelLabel": "模型", + "thinkingLabel": "思考", + "thinking": { + "off": "关闭", + "low": "低", + "medium": "中", + "high": "高", + "minimal": "极低", + "xhigh": "极高" + }, + "apiKeyLabel": "API Key", + "apiKeyHint": "为所选提供方写入 ~/.pi/agent/auth.json。", + "apiKeySetPlaceholder": "•••••• (已保存,留空则保持不变)", + "saveConfig": "保存 Pi 配置", + "providerModelRequired": "提供方和模型为必填", + "runtimeTitle": "运行时", + "runtimeDescription": "选择运行哪个 pi。使用默认,或指向你自己的 pi 构建。", + "modeDefault": "默认 pi", + "modeDefaultHint": "使用内置 pi-acp 适配器拉起 PATH 上的 pi。 安装 pi:npm install -g @earendil-works/pi-coding-agent", + "modeCustom": "自定义 pi", + "modeCustomHint": "运行你自己的 pi 构建、安装或包装脚本。", + "commandLabel": "pi 命令或路径", + "commandHint": "绝对路径、PATH 上的命令名,或包装脚本(如 monorepo 的 ./pi-test.sh)。", + "commandNotFound": "未找到命令", + "validate": "验证", + "advanced": "高级", + "configDirLabel": "配置目录 (PI_CODING_AGENT_DIR)", + "sessionDirLabel": "会话目录 (PI_CODING_AGENT_SESSION_DIR)", + "flagsHint": "pi-acp 不转发自定义 pi 参数(--approve、-e 等)——用脚本包装 pi 并将命令指向它。", + "customIncomplete": "请输入 pi 命令以保存", + "saveRuntime": "保存运行时", + "providerPlaceholder": "选择提供方", + "customProvider": "自定义提供方…", + "providerIdLabel": "提供方 ID", + "apiProtocolLabel": "API 协议", + "baseUrlLabel": "接口地址(Base URL)", + "customProviderHint": "在 ~/.pi/agent/models.json 中按你的接口地址定义一个提供方。多数自托管或代理服务使用 openai-completions。", + "baseUrlRequired": "接口地址(Base URL)为必填项", + "binaryTitle": "pi 二进制 (pi-coding-agent)", + "binaryDescription": "pi-acp 运行此 pi 二进制。可在此安装,或在下方指向你自己的构建。", + "binaryInstalled": "已安装", + "binaryMissing": "未安装", + "binaryChecking": "检测中…", + "installBinary": "安装 pi", + "installing": "安装中…", + "recheck": "重新检测", + "configDirSkillsNote": "设置了自定义配置目录后,设置页中管理的技能、专家与办公工具将不会作用于该 pi;请直接在该目录中管理其技能。", + "projectTrustTitle": "项目信任", + "projectTrustDescription": "你允许 pi 从中加载项目文件的目录。被信任的目录会让该仓库的 .pi/extensions 在 pi 启动时执行代码,且对其下所有子目录同样生效,你在终端里运行 pi 时也会沿用。", + "projectTrustLoading": "加载中…", + "projectTrustEmpty": "尚未对任何目录做出决定。", + "projectTrustTrusted": "已信任", + "projectTrustDenied": "不信任", + "projectTrustRevoke": "撤销", + "reasoningTitle": "推理", + "reasoningEnableLabel": "启用", + "reasoningDescription": "只有模型声明了推理能力,pi 才会发送推理强度——未声明的模型所有档位都会被压回 Off,所以输入框里的选择器一改就弹回。这里写入 models.json 中该模型的条目。", + "levelsLabel": "可选档位", + "levelsHint": "这些会成为输入框推理选择器里的档位。请选你的接入点能接受的值;不在这里的档位 pi 一律拒绝。", + "levelsEmptyError": "至少选一个档位——一个都不选时 pi 只会退回 Off。", + "wireValuesTitle": "高级:发给供应商的值", + "wireValuesHint": "留空表示原样发送档位名。接入点需要别的写法时才填——Google 系需要 LOW / HIGH。", + "defaultLevelUnlisted": "该档位不在上面的可选列表里——pi 会把它压下来。" + }, + "addCustomAgent": "添加自定义智能体", + "addCustomAgentHint": "接入任意兼容 ACP 的智能体。可从公开 ACP 注册表中选择,或直接粘贴其注册表信息。", + "customAgentFromRegistry": "ACP 注册表", + "customAgentManual": "手动填写", + "customAgentSearchPlaceholder": "搜索智能体…", + "customAgentLoadingCatalog": "正在加载 ACP 注册表…", + "customAgentRetry": "重试", + "customAgentNoResults": "没有匹配的智能体", + "customAgentAdd": "添加", + "customAgentAlreadyAdded": "已添加", + "customAgentUnsupportedPlatform": "当前平台没有可用的构建", + "customAgentAdded": "已添加 {name}", + "customAgentIdLabel": "注册表 ID", + "customAgentNameLabel": "显示名称", + "customAgentVersionLabel": "版本", + "customAgentSpecLabel": "分发信息(JSON)", + "customAgentSpecHint": "与 ACP 注册表 distribution 对象同构:支持 npx、uvx、binary 三种通道,也可整条粘贴注册表条目。npx/uvx 的 cmd 为包安装的可执行命令名,缺省按包名推导,与包名不同时需填写。binary 按平台键区分(本机为 {platform}),cmd 为压缩包内启动路径,sha256 可选用于校验下载。", + "customAgentTemplateLabel": "模板", + "customAgentKindLabel": "启动方式", + "customAgentInvalidJson": "不是合法的 JSON", + "customAgentNoDistribution": "未找到 npx、uvx 或 binary 分发方式", + "customAgentCancel": "取消", + "customAgentSave": "添加智能体", + "customAgentSaveChanges": "保存修改", + "customAgentEdit": "编辑智能体", + "customAgentEditHint": "修改名称、图标、分发信息与技能声明;智能体 ID 不可修改。", + "customAgentEditNotFound": "未找到自定义智能体 {id}", + "customAgentSaved": "已保存 {name}", + "customAgentVersionProbeLabel": "版本查询命令(可选)", + "customAgentVersionProbeHint": "查询本地安装版本的命令;留空时默认执行智能体命令加 --version。", + "customAgentRemove": "移除智能体", + "customAgentRemoveHint": "删除该智能体定义。已有会话的历史会保留,只是该智能体无法再启动。", + "customAgentIconLabel": "图标(可选)", + "customAgentIconUpload": "上传", + "customAgentIconReplace": "更换", + "customAgentIconClear": "移除图标", + "customAgentIconHint": "随智能体一起保存,离线也能显示。不上传则使用彩色首字母。", + "customAgentSkillsLabel": "Skills(共享 .agents/skills)", + "customAgentSkillsHint": "声明该智能体会读取共享的 .agents/skills 目录(全局与项目级),并将其加入所有技能矩阵。链接到共享目录的技能对读取该目录的其他智能体同样可见。", + "customAgentSkillsDirLabel": "专属技能目录", + "customAgentSkillsDirHint": "该智能体自身加载技能的目录绝对路径 —— 可与共享目录并存,也可单独使用。~ 会展开为主目录;链接技能时优先放入此目录。", + "customAgentMcpLabel": "MCP 支持", + "customAgentMcpHint": "会话建立时向该智能体注入 codeg 内置的 codeg-mcp 伴生进程 —— 委托、实时反馈与任务工具都依赖它。若该智能体不支持 MCP、连接时报错,请关闭此项;设置在下次连接时生效。", + "customAgentIconNotAnImage": "请选择图片文件。", + "customAgentIconTooLarge": "图标需小于 {limit} KB。", + "customAgentIconReadFailed": "无法读取该图片。", + "customAgentRemoveConfirm": "确定移除 {name}?已有会话会保留,但该智能体将无法再启动。", + "customAgentRemoveWithData": "同时删除已记录的会话历史", + "customAgentRemoved": "已移除 {name}", + "customAgentBadge": "自定义", + "customAgentNotLaunchable": "该智能体在此环境无法启动:{reason}" + }, + "SettingsPages": { + "agentsLoading": "加载 Agent 设置中...", + "skillPacksLoading": "正在加载技能包…" + }, + "GeneralSettings": { + "loading": "加载中...", + "sectionTitle": "常规", + "sectionDescription": "集中管理默认终端、渲染加速以及多智能体协同等通用偏好。", + "terminalTitle": "默认终端", + "terminalDescription": "选择从终端栏或文件树打开新终端标签页时使用的 Shell。智能体请求 codeg 代为执行整条命令行时也会使用它。", + "terminalSystemDefault": "系统默认", + "terminalPowerShell7": "PowerShell 7 (pwsh)", + "terminalWindowsPowerShell": "Windows PowerShell", + "terminalCmd": "命令提示符 (cmd)", + "terminalSaveFailed": "保存终端设置失败:{message}", + "terminalShellCustom": "自定义路径", + "terminalShellCustomPath": "Shell 路径", + "terminalShellCustomPlaceholder": "/usr/local/bin/fish", + "terminalShellCustomSave": "保存", + "terminalShellCustomHint": "支持绝对路径,或 PATH 中可解析的命令名。", + "terminalShellNotInstalled": "未安装", + "terminalShellNotFoundWarning": "当前主机上不存在此路径。", + "terminalCurrentShell": "当前使用:{path}", + "renderingDescription": "如果应用出现黑屏或渲染异常(常见于 AMD 显卡或部分 Intel 集成显卡),可关闭硬件加速。仅 Windows 桌面端生效。", + "disableHardwareAcceleration": "禁用硬件加速", + "renderingSaveFailed": "渲染设置保存失败:{message}", + "restartRequired": "已保存,重启应用后生效。", + "restartNow": "立即重启", + "restartFailed": "重启失败:{message}", + "loadFailed": "加载失败:{message}" + }, + "LoginPage": { + "documentTitle": "登录 - codeg", + "brand": "Codeg", + "subtitle": "输入访问 Token 以连接到桌面端", + "tokenPlaceholder": "Access Token", + "connect": "连接", + "connecting": "连接中...", + "helpText": "Token 可在桌面端 设置 → Web 服务 中获取", + "invalidToken": "Token 无效,请检查后重试", + "connectionFailed": "连接失败 (HTTP {status})", + "networkError": "无法连接到服务器" + }, + "CommitPage": { + "title": "提交代码", + "invalidFolderId": "无效的 folderId", + "loadingRepo": "正在加载仓库..." + }, + "MergePage": { + "title": "解决冲突", + "invalidFolderId": "无效的 folderId", + "loadingRepo": "正在加载仓库...", + "localVersion": "本地(我们的)", + "result": "结果", + "remoteVersion": "远程(他们的)", + "acceptLocal": "采用本地", + "acceptRemote": "采用远程", + "markResolved": "标记已解决", + "abortMerge": "中止", + "completeMerge": "完成合并", + "unresolvedConflicts": "文件中仍有未解决的冲突标记", + "fileResolved": "文件已解决", + "allResolved": "所有冲突已解决", + "conflictFiles": "冲突文件", + "loadingFile": "正在加载文件...", + "preparingMerge": "正在准备合并...", + "selectFile": "选择一个文件进行解决", + "noConflicts": "无冲突文件", + "skipFile": "跳过", + "abortSuccess": "操作已中止", + "applyAllNonConflicting": "应用所有非冲突变更", + "applyLeftNonConflicting": "应用本地", + "applyRightNonConflicting": "应用远程" + }, + "ImportSessions": { + "title": "导入本地会话", + "scanningTitle": "正在扫描本地智能体会话…", + "scanningHint": "正在遍历各智能体的本地会话存储,历史较多时可能需要一些时间。已导入的会话会顺带刷新。", + "scanFailed": "扫描失败", + "retry": "重试", + "rescan": "重新扫描", + "empty": "未发现本地会话", + "emptyHint": "本机未找到任何智能体的会话存储。", + "noMatches": "没有匹配当前筛选的会话", + "searchPlaceholder": "搜索标题或路径…", + "allAgents": "全部智能体", + "onlyImportable": "仅显示可导入", + "selectAll": "全选", + "clearSelection": "清空", + "expandAll": "全部展开", + "collapseAll": "全部折叠", + "summaryCounts": "共 {total} 个会话 · {importable} 个可导入 · {folders} 个文件夹", + "noFolderSkipped": "已跳过 {count} 个无项目目录的会话", + "folderNew": "新建", + "folderCounts": "可导入 {importable}/{total}", + "toggleFolderAria": "选择 {name} 中的全部可导入会话", + "toggleSessionAria": "选择会话 {title}", + "statusImported": "已导入", + "statusDeleted": "已删除", + "untitled": "未命名会话", + "messageCount": "{count} 条消息", + "selectedCount": "已选 {count} 个", + "importSelected": "导入所选", + "importing": "导入中…", + "close": "关闭", + "doneTitle": "导入完成", + "doneImported": "新导入", + "doneUpdated": "已刷新", + "doneSkipped": "已跳过", + "doneCreatedFolders": "新建文件夹", + "doneNotFound": "未找到", + "doneFailed": "失败", + "continueImport": "继续导入", + "toasts": { + "importFailed": "导入失败:{message}" + } + }, + "Folder": { + "workspaceStatus": { + "degradedTitle": "实时更新不可用", + "degradedHint": "监听器启动失败(如目录无读取权限)。请手动刷新以获取最新变更。", + "retry": "重试", + "retrying": "重试中..." + }, + "common": { + "all": "全部", + "cancel": "取消", + "close": "关闭", + "closeOthers": "关闭其它", + "closeAll": "关闭所有", + "confirm": "确认", + "save": "保存", + "delete": "删除", + "rename": "重命名", + "loading": "加载中...", + "refresh": "刷新", + "refreshing": "刷新中...", + "create": "创建", + "createAndSwitch": "创建并切换", + "openFile": "打开文件", + "viewDiff": "查看差异", + "push": "推送..." + }, + "statusLabels": { + "in_progress": "进行中", + "pending_review": "待复查", + "completed": "已完成", + "cancelled": "已取消" + }, + "sidebar": { + "title": "会话", + "locateActiveConversation": "定位当前会话", + "expandAllGroups": "展开全部分组", + "collapseAllGroups": "折叠全部分组", + "newConversation": "新建会话", + "newConversationShort": "新建", + "newChat": "新建会话", + "search": "搜索", + "noConversationsFound": "未找到会话。", + "importLocalSessions": "导入本地会话", + "importing": "导入中...", + "error": "错误:{message}", + "completeAllSessions": "完成全部会话", + "completeAllReviewTitle": "完成全部复查会话?", + "completeAllReviewDescription": "这会将复查中的 {count} 个会话全部标记为已完成。", + "completing": "处理中...", + "toasts": { + "importedSessions": "已导入 {imported} 个会话,跳过 {skipped} 个", + "importedAndUpdated": "已导入 {imported} 个会话,更新 {updated} 个标题,跳过 {skipped} 个", + "updatedTitles": "已更新 {updated} 个标题,跳过 {skipped} 个", + "noNewSessionsFound": "没有新会话(已跳过 {skipped} 个)", + "importFailed": "导入失败:{message}", + "reviewCompleted": "已将 {count} 个复查会话标记为已完成", + "completeReviewFailed": "批量完成复查会话失败:{message}", + "folderOpened": "已打开文件夹 {name}", + "folderRemoved": "已移除文件夹 {name}", + "openFolderFailed": "打开文件夹失败", + "removeFolderFailed": "移除文件夹失败:{message}", + "reorderFoldersFailed": "重新排序文件夹失败:{message}", + "changeFolderColorFailed": "修改颜色失败:{message}", + "setFolderAliasFailed": "设置别名失败:{message}", + "changeFolderDefaultAgentFailed": "设置默认智能体失败:{message}" + }, + "statsLabel": "{folders} 个文件夹 · {convos} 个会话", + "reorderHandle": "拖拽排序", + "openFolder": "打开文件夹", + "searchPlaceholder": "搜索会话...", + "viewOptions": "显示选项", + "showCompleted": "显示已完成会话", + "showWorktrees": "显示工作树文件夹", + "showRecent": "显示「最近」分组", + "moreOptions": "更多选项", + "sortBy": "排序方式", + "sortByCreatedAt": "按创建时间排序", + "sortByUpdatedAt": "按更新时间排序", + "sectionOrder": "区域顺序", + "sectionOrderMoveUp": "上移", + "sectionOrderMoveDown": "下移", + "sectionOrderItemLabel": "{name} — 第 {position} 位,共 {total} 位", + "statusRunningBadge": "运行中", + "runningCountBadge": "{count} 个会话进行中", + "statusCancelledBadge": "已取消", + "worktreeRemovedBadge": "源 worktree 已删除", + "conversationCountUnit": "{count} 条", + "emptyFolderHint": "暂无会话", + "noMatchingConversations": "未找到匹配的会话", + "noUnfinishedConversations": "当前暂无未完成会话,右上角可启用显示已完成会话", + "removeFolderConfirmTitle": "从工作区移除该文件夹?", + "removeFolderConfirmDescription": "从工作区移除 \"{name}\"?其相关 Tab 与终端将会关闭。", + "folderHeaderMenu": { + "manageConversations": "会话管理…", + "manageLinks": "关联的文件夹", + "changeColor": "修改颜色", + "useThemeColor": "使用设置主题", + "setDefaultAgent": "设置默认智能体", + "defaultAgentNone": "不设置(使用全局默认)", + "agentUnavailableSuffix": "(不可用)", + "loadingAgents": "正在加载代理…", + "setAlias": "设置别名…", + "setAliasTitle": "设置文件夹别名", + "setAliasPlaceholder": "输入别名(留空清除)", + "setAliasSave": "保存", + "setAliasCancel": "取消", + "removeFromWorkspace": "从工作区移除" + }, + "manageConversations": { + "title": "会话管理", + "searchPlaceholder": "按标题搜索…", + "agentFilterAll": "全部智能体", + "statusFilterAll": "全部状态", + "folderFilterAll": "全部文件夹", + "branchFilterAll": "全部分支", + "branchNone": "无分支", + "branchSearchPlaceholder": "搜索分支…", + "noMatchingBranches": "无匹配分支", + "selectAllVisible": "全选", + "deselectAll": "取消全选", + "selectedCount": "已选 {count} 条", + "matchedCount": "匹配 {count} 条", + "untitledConversation": "未命名会话", + "setStatus": "设为状态…", + "deleteSelected": "删除", + "noConversations": "此文件夹暂无会话。", + "noConversationsWorkspace": "工作区暂无会话。", + "noMatchingConversations": "没有匹配过滤条件的会话。", + "confirmDeleteTitle": "删除 {count} 个会话?", + "confirmDeleteDescription": "此操作不可撤销。", + "toastDeleted": "已删除 {count} 个会话", + "toastStatusUpdated": "已更新 {count} 个会话的状态", + "toastOpFailed": "操作失败:{message}" + }, + "sectionPinned": "已置顶", + "sectionFolders": "文件夹", + "sectionChats": "聊天", + "sectionRecent": "最近", + "noChats": "没有聊天", + "noRecent": "暂无最近会话", + "showMoreRecent": "显示更多({count})", + "noFolders": "没有打开的文件夹", + "newChatAction": "新建聊天", + "automations": "自动化", + "tasks": "待办任务", + "loadingSubsessions": "正在加载子会话…" + }, + "conversation": { + "reloadFailed": "会话重新加载失败:{message}", + "reloaded": "当前会话已重新加载", + "reload": "重新加载", + "activeConversationIndicator": "当前激活会话", + "newConversation": "新建会话", + "closeConversation": "关闭会话", + "copyText": "复制文本", + "copyTextSuccess": "已复制", + "copyTextFailed": "复制失败", + "forkSession": "分叉会话", + "forkSessionSuccess": "会话分叉成功", + "forkSessionFailed": "会话分叉失败:{error}", + "exportConversation": "导出会话", + "exportImage": "图片", + "exportMarkdown": "Markdown", + "exportHtml": "HTML", + "exportSuccess": "会话已导出", + "exportFailed": "导出失败", + "exportImageTooLong": "会话内容过长,不支持导出为图片", + "exportLabels": { + "untitledConversation": "未命名会话", + "agent": "代理", + "model": "模型", + "status": "状态", + "started": "开始时间", + "updated": "更新时间", + "tokens": "令牌统计", + "duration": "时长", + "inputTokens": "输入", + "outputTokens": "输出", + "cacheRead": "缓存读取", + "cacheWrite": "缓存写入", + "user": "用户", + "assistant": "助手", + "system": "系统", + "toolResult": "结果", + "toolError": "错误" + }, + "moreActions": "更多操作" + }, + "sessionDetails": { + "menuLabel": "会话详情", + "noActiveSession": "暂无活动会话", + "title": "会话详情", + "subtitle": "会话元信息与 Token 用量", + "fieldTitle": "标题", + "untitled": "未命名会话", + "sessionId": "会话 ID", + "externalId": "扩展 ID", + "agent": "智能体", + "model": "模型", + "status": "状态", + "gitBranch": "Git 分支", + "parentId": "父会话", + "tokensHeading": "Token 用量", + "totalTokens": "总计", + "inputTokens": "输入", + "outputTokens": "输出", + "cacheWrite": "缓存写入", + "cacheRead": "缓存读取", + "contextWindow": "上下文窗口", + "duration": "时长", + "loadingStats": "正在加载 Token 用量…", + "loadFailed": "加载 Token 用量失败", + "noStats": "暂无用量记录", + "timestampsHeading": "时间", + "createdAt": "创建时间", + "updatedAt": "更新时间", + "none": "—", + "copyField": "复制{field}", + "copiedField": "已复制{field}" + }, + "conversationCard": { + "untitledConversation": "未命名会话", + "newConversation": "新建会话", + "rename": "重命名", + "status": "状态", + "delete": "删除", + "importLocalSessions": "导入本地会话", + "importing": "导入中...", + "renameConversation": "重命名会话", + "deleteConversationTitle": "删除会话?", + "deleteConversationDescription": "会删除“{title}”,此操作不可撤销。", + "cancel": "取消", + "save": "保存", + "pin": "置顶", + "unpin": "取消置顶", + "markCompleted": "标记为已完成", + "reopen": "重新打开", + "expandSubsessions": "展开子会话", + "collapseSubsessions": "折叠子会话" + }, + "search": { + "dialogTitle": "搜索", + "dialogTitleWithFolder": "搜索 — {name}", + "tabConversations": "会话", + "tabFiles": "文件", + "placeholder": "搜索会话...", + "filePlaceholder": "搜索文件或目录...", + "allAgents": "全部", + "searching": "搜索中...", + "typeToSearch": "输入关键词搜索会话", + "typeToSearchFiles": "输入关键词搜索文件或目录", + "noResults": "未找到结果。", + "untitledConversation": "未命名会话" + }, + "folderTitleBar": { + "showSidebar": "显示侧边栏", + "hideSidebar": "隐藏侧边栏", + "toggleTerminal": "切换终端", + "toggleAuxPanel": "切换辅助面板", + "search": "搜索", + "openSettings": "打开设置", + "backToConversations": "返回会话", + "withShortcut": "{label}({shortcut})" + }, + "statusBar": { + "connection": { + "connected": "已连接", + "connecting": "连接中...", + "prompting": "响应中...", + "error": "连接异常", + "disconnected": "未连接", + "tooltip": "{agent}:{status}", + "tooltipError": "{agent}:{error}", + "title": "智能体连接", + "triggerAria": "智能体连接:{status}", + "workingDir": "工作目录", + "sessionId": "会话 ID", + "viewerNote": "已接入其他客户端拥有的会话——重连只会重新接入当前视图。", + "reconnectInterrupts": "重连会重启智能体,并中断正在进行的工作。", + "reconnect": "重新连接", + "reconnecting": "正在重新连接...", + "reconnectUnavailable": "暂无可重连的会话。" + }, + "tasks": { + "title": "任务" + }, + "alerts": { + "title": "告警", + "empty": "暂无告警信息", + "details": "详情" + }, + "stats": { + "conversations": "{count} 个会话", + "openUsage": "查看会话统计与 Token 用量" + }, + "tokens": { + "contextWindowUsageAria": "上下文窗口使用率", + "contextWindow": "上下文窗口", + "usedMax": "已用 / 上限", + "tokenUsage": "Token 用量", + "input": "输入", + "output": "输出", + "cacheRead": "缓存读取", + "cacheWrite": "缓存写入", + "total": "总计" + } + }, + "auxPanel": { + "tabs": { + "files": "文件", + "changes": "变更", + "commits": "提交" + }, + "noFolderTitle": "暂无打开的文件夹", + "noFolderHint": "打开一个文件夹后在这里查看" + }, + "windowControls": { + "minimizeWindow": "最小化窗口", + "minimize": "最小化", + "maximizeWindow": "最大化窗口", + "maximize": "最大化", + "restoreWindow": "还原窗口", + "restore": "还原", + "closeWindow": "关闭窗口", + "close": "关闭" + }, + "tabs": { + "closeConversationTab": "关闭会话标签", + "close": "关闭", + "closeOthers": "关闭其它", + "splitRight": "向右拆分", + "splitDown": "向下拆分", + "splitAndMoveRight": "拆分并右移", + "splitAndMoveDown": "拆分并下移", + "moveToOppositeGroup": "移动到对侧分组", + "moveToGroup": "移动到分组", + "groupLabel": "分组 {index}", + "changeSplitterOrientation": "切换分隔方向", + "unsplit": "取消拆分", + "unsplitAll": "全部取消拆分", + "closeAll": "关闭所有", + "tileDisplay": "平铺显示", + "untileDisplay": "取消平铺" + }, + "fileWorkspace": { + "files": "文件", + "closeFileTab": "关闭文件标签", + "close": "关闭", + "closeOthers": "关闭其它", + "closeAll": "关闭所有", + "preview": "预览", + "editSource": "编辑源码", + "maximize": "最大化", + "restore": "还原", + "emptyDirectory": "空目录" + }, + "terminal": { + "rename": "重命名", + "close": "关闭", + "closeOthers": "关闭其它", + "closeAll": "关闭所有", + "hideTerminal": "隐藏终端({shortcut})", + "openFolderFirst": "请先打开一个文件夹" + }, + "workspaceDialog": { + "title": "打开文件夹", + "manageTitle": "关联的文件夹", + "addTargetsTitle": "添加要关联的文件夹", + "pickRootDescription": "选择该工作空间的主文件夹。", + "linksDescription": "把其它文件夹以子目录的形式关联进来,智能体就能在同一个工作空间里跨项目工作。", + "addTargetsDescription": "选择一个或多个文件夹,每个都会成为工作空间的一个子目录。", + "useSystemPicker": "系统选择器", + "next": "下一步", + "back": "返回", + "done": "完成", + "change": "更改", + "addFolders": "添加文件夹", + "addSelected": "添加", + "addSelectedCount": "添加 {count} 个", + "createCount": "关联 {count} 个文件夹", + "discardPending": "放弃", + "noLinks": "还没有关联任何文件夹。", + "gitExclude": "不让关联目录污染 git 状态", + "rename": "重命名", + "unlink": "解除关联", + "repair": "重建链接", + "saveName": "保存", + "cancelRename": "取消", + "removePending": "移除", + "willAppearAs": "在工作空间中显示为 {name}", + "renamedForDuplicate": "已改名 —— {base} 已被另一个关联占用", + "renamedForExistingEntry": "已改名 —— 该文件夹中已存在 {base}", + "partiallyCreated": "只成功关联了 {count} 个文件夹", + "openFailed": "打开文件夹失败", + "previewFailed": "检查所选文件夹失败", + "createFailed": "关联文件夹失败", + "renameFailed": "重命名失败", + "removeFailed": "解除关联失败", + "repairFailed": "重建链接失败", + "status": { + "ok": "已关联", + "missing": "链接已从该文件夹中消失", + "conflicted": "该名称已被其它条目占用", + "broken": "被关联的文件夹已不存在" + }, + "nameIssue": { + "empty": "请输入名称", + "illegalChars": "不能包含 / \\ : * ? \" < > |", + "tooLong": "名称过长", + "reserved": "该名称是 Windows 保留名", + "duplicate": "该名称已被使用" + }, + "rejection": { + "not_found": "找不到该文件夹", + "not_a_directory": "该路径不是文件夹", + "same_as_root": "这就是工作空间文件夹本身", + "ancestor_of_root": "该文件夹包含了当前工作空间", + "inside_root": "已在工作空间内部", + "already_linked": "已经关联过", + "name_unavailable": "该文件夹已无可用的名称", + "alreadyLinkedAs": "已作为 {name} 关联" + } + }, + "folderNameDropdown": { + "fallbackFolderName": "文件夹", + "openFolder": "打开文件夹", + "cloneRepository": "克隆仓库", + "projectBoot": "项目启动器", + "opened": "已打开", + "recentOpen": "最近打开" + }, + "fileWorkspacePanel": { + "addSelectionToChat": "添加选区到会话", + "addToChat": "加入会话", + "addSelectionToChatDone": "已将 {label} 加入会话", + "addFileToChat": "添加文件到会话", + "toggleWordWrap": "切换自动换行", + "addFileToChatDone": "已将 {label} 加入会话", + "viewDiff": "查看差异", + "openFile": "打开文件", + "fileCount": "{count} 个文件", + "openFileOrDiff": "从右侧面板打开文件或差异", + "disk": "磁盘", + "head": "HEAD(当前提交)", + "unsaved": "未保存", + "workingTree": "工作区", + "loading": "加载中...", + "compareWithBranch": "{path} · 与 {branch} 比较", + "hunkCount": "{count} 个区块", + "prev": "上一个", + "next": "下一个", + "jumpToLine": "跳转到第 {line} 行", + "noParsedDiffSections": "未解析到差异区块", + "loadingEditor": "编辑器加载中...", + "imageZoomIn": "放大", + "imageZoomOut": "缩小", + "imageZoomReset": "重置缩放", + "htmlPreviewTitle": "HTML 预览", + "htmlPreviewTrust": "运行脚本", + "htmlPreviewTrustHint": "运行此文件的脚本并允许网络访问。仅对可信任的文件启用。", + "officePreviewTitle": "办公文档预览", + "officeFullRender": "完整渲染", + "officeFullRenderHint": "渲染 Morph 动画、3D 和公式(会运行幻灯片自带的脚本)", + "officeNotInstalled": "未安装 OfficeCLI", + "officeNotInstalledHint": "在 设置 → 办公工具 中安装 OfficeCLI,即可预览 Word、Excel 和 PowerPoint 文件。", + "officeOpenSettings": "打开设置", + "officeWatchFailed": "无法启动实时预览", + "officeWatchRetry": "重试", + "officeServerInstallHint": "OfficeCLI 需安装在服务器主机上。请在服务器上运行以下命令后重试:", + "officeRemoteDesktopUnsupported": "远程桌面窗口暂不支持实时预览。请在服务器的 Web 界面中打开此工作区来预览 Office 文件。" + }, + "branchDropdown": { + "toasts": { + "commitCodeCompleted": "提交代码完成", + "pushCodeCompleted": "推送代码完成", + "committedFiles": "已提交 {count} 个文件", + "taskCompleted": "{label} 完成", + "taskFailed": "{label} 失败", + "mergeNoNewCommits": "{branchName} 没有新的提交", + "mergedCommits": "已合并 {count} 个提交", + "allFilesUpToDate": "所有文件均为最新版本", + "updatedFiles": "已更新 {count} 个文件", + "openCommitWindowFailed": "打开提交窗口失败", + "openPushWindowFailed": "打开推送窗口失败", + "upstreamSet": "已设置远程跟踪分支", + "upstreamSetAndPushed": "已设置远程跟踪分支并推送 {count} 个提交", + "noCommitsToPush": "没有可推送的提交", + "pushedCommits": "已推送 {count} 个提交", + "switchedToFolder": "已切换到 {name}", + "switchFailed": "切换分支失败", + "openStashWindowFailed": "打开贮藏窗口失败" + }, + "tasks": { + "newBranch": "新建分支 {name}", + "newWorktree": "新建工作树 {name}", + "checkoutTo": "切换到 {branchName}", + "mergeBranch": "合并 {branchName}", + "rebaseTo": "变基到 {branchName}", + "deleteRemoteBranch": "删除远程分支 {branchName}", + "initGitRepo": "初始化 Git 仓库", + "pullCode": "更新代码", + "fetchInfo": "获取信息", + "pushCode": "推送代码", + "stashChanges": "贮藏更改", + "stashPop": "取消贮藏", + "deleteBranch": "删除分支 {branchName}", + "removeWorktree": "删除 {branchName} 的工作树", + "removeWorktreeAndBranch": "删除工作树及分支 {branchName}", + "updateBranch": "更新分支 {branchName}" + }, + "confirm": { + "mergeTitle": "合并分支", + "rebaseTitle": "变基分支", + "mergeDescription": "确定将 {branchName} 合并到当前分支 {currentBranch} 吗?", + "rebaseDescription": "确定将当前分支 {currentBranch} 变基到 {branchName} 吗?", + "deleteRemoteTitle": "删除远程分支", + "deleteRemoteDescription": "确定删除远程分支 {branchName} 吗?此操作将从远程仓库中移除该分支,且不可恢复。", + "deleteTitle": "删除分支", + "deleteDescription": "确定删除分支 {branchName} 吗?此操作不可恢复。", + "forceDeleteTitle": "强制删除分支", + "forceDeleteDescription": "分支 {branchName} 尚未完全合并,确定要强制删除吗?此操作不可恢复。", + "deleteWorktreeTitle": "删除工作树", + "deleteWorktreeDescription": "删除检出了 {branchName} 的工作树目录?分支及其提交会保留。", + "forceDeleteWorktreeTitle": "强制删除工作树", + "forceDeleteWorktreeDescription": "{branchName} 的工作树中有未提交或未跟踪的文件。仍要删除吗?这些改动将无法恢复。", + "deleteWorktreeAndBranchTitle": "删除工作树及分支", + "deleteWorktreeAndBranchDescription": "删除 {branchName} 的工作树、该分支本身及其工作区文件夹?其中的会话会移动到仓库文件夹下。此操作无法撤销。", + "forceDeleteWorktreeAndBranchTitle": "强制删除工作树及分支", + "forceDeleteWorktreeAndBranchDescription": "{branchName} 的工作树中有未提交的文件,或该分支尚未完全合并。仍要一并删除吗?此操作无法撤销。" + }, + "current": "当前", + "switchToBranch": "切换到此分支", + "mergeBranchIntoCurrent": "将 {branchName} 合并到 {currentBranch}", + "rebaseCurrentToBranch": "将 {currentBranch} 变基到 {branchName}", + "noBranch": "无分支", + "detachedHead": "游离 HEAD({sha})", + "initGitRepo": "初始化 Git 仓库", + "pullCode": "更新代码", + "fetchRemoteBranches": "提取远程分支", + "openCommitWindow": "提交代码...", + "pushCode": "推送...", + "pushBranch": "推送", + "newBranch": "新建分支...", + "newWorktree": "新建工作树...", + "stashChanges": "贮藏更改...", + "stashPop": "取消贮藏...", + "manageRemotes": "管理远程...", + "localBranches": "本地分支 ({count})", + "noLocalBranches": "无本地分支", + "remoteBranches": "远程分支 ({count})", + "noRemoteBranches": "无远程分支", + "dialogs": { + "newBranchTitle": "新建分支", + "newBranchDescription": "从当前分支 {branch} 创建新分支", + "branchNamePlaceholder": "分支名称", + "newWorktreeTitle": "新建工作树", + "newWorktreeDescription": "从当前分支 {branch} 创建新的工作树", + "branchNameLabel": "分支名称", + "worktreePathLabel": "工作树路径", + "worktreePathPlaceholder": "工作树路径", + "manageRemotesTitle": "管理远程", + "manageRemotesEmpty": "未配置远程仓库", + "remoteNamePlaceholder": "远程名称", + "remoteUrlPlaceholder": "远程 URL", + "addRemote": "添加", + "savingRemotes": "保存中..." + }, + "conflict": { + "title": "合并冲突", + "description": "以下文件存在冲突,需要手动解决:", + "abort": "中止合并", + "openMergeTool": "打开合并工具", + "completeMerge": "完成合并", + "abortSuccess": "合并已中止", + "completeSuccess": "合并完成" + }, + "stashDialog": { + "title": "贮藏更改", + "description": "将当前更改保存到贮藏区", + "messageLabel": "消息", + "messagePlaceholder": "贮藏消息(可选)", + "keepIndex": "保留暂存区(已暂存的更改保持不变)", + "cancel": "取消", + "stash": "贮藏", + "success": "更改已贮藏", + "error": "贮藏更改失败" + }, + "unstashDialog": { + "title": "取消贮藏", + "noStashes": "没有贮藏记录", + "selectFile": "选择文件查看差异", + "viewDiff": "查看差异", + "original": "原始", + "modified": "修改后", + "apply": "应用", + "drop": "删除", + "applySuccess": "贮藏已应用", + "dropSuccess": "贮藏已删除", + "confirmApply": "将贮藏 {ref} 应用到工作目录?", + "cancel": "取消" + }, + "deleteBranch": "删除分支", + "deleteWorktree": "删除工作树", + "deleteWorktreeAndBranch": "删除工作树及分支", + "searchPlaceholder": "搜索分支和操作", + "searchAriaLabel": "搜索分支和操作", + "branchListLabel": "分支和操作", + "noMatches": "无匹配项" + }, + "commitDialog": { + "toasts": { + "commitCompleted": "提交代码完成", + "pushFailed": "推送失败", + "committedFiles": "已提交 {count} 个文件", + "addedToVcs": "已添加到 VCS", + "addToVcsFailed": "添加到 VCS 失败", + "fileDeleted": "文件已删除", + "deleteFailed": "删除失败", + "fileRolledBack": "文件已回滚", + "rollbackFailed": "回滚失败", + "dirRolledBack": "目录已回滚", + "dirDeleted": "目录已删除" + }, + "confirm": { + "deleteTitle": "确认删除", + "deleteDescription": "确定要删除文件「{file}」吗?此操作不可恢复。", + "rollbackTitle": "确认回滚", + "rollbackDescription": "确定要回滚文件「{file}」到 HEAD 版本吗?未保存的修改将丢失。", + "rollbackDirDescription": "确定要回滚目录「{dir}」到 HEAD 版本吗?未保存的修改将丢失。", + "deleteDirDescription": "确定要删除目录「{dir}」吗?此操作不可恢复。" + }, + "actions": { + "select": "选择", + "unselect": "取消选择", + "rollback": "回滚", + "addToVcs": "添加到 VCS" + }, + "aria": { + "selectFile": "{action}:{path}", + "unselectAllFiles": "取消选择全部文件", + "selectAllFiles": "选择全部文件", + "unselectTracked": "取消选择已跟踪改动", + "selectTracked": "选择已跟踪改动", + "unselectUntracked": "取消选择未跟踪文件", + "selectUntracked": "选择未跟踪文件" + }, + "loading": "加载中...", + "selectionCount": "{selected} / {total} 个文件", + "emptyFiles": "没有改动的文件", + "trackedChanges": "已跟踪改动 ({count})", + "untrackedFiles": "未跟踪文件 ({count})", + "commitMessage": "提交消息", + "commitMessagePlaceholder": "输入提交信息...", + "commitButton": "提交 ({count})", + "commitAndPushButton": "提交并推送 ({count})", + "head": "HEAD(当前提交)", + "workingTree": "工作区", + "clickFileToDiff": "点击文件名查看差异", + "loadingDiff": "加载差异..." + }, + "pushWindow": { + "title": "推送代码", + "noUnpushedCommits": "没有未推送的提交", + "noRemoteConfigured": "未配置 Git 远程仓库\n请在「管理远程」中添加远程地址", + "newBranchNoPushedCommits": "新分支 — 推送以创建远程跟踪分支", + "unpushed": "未推送", + "selectFileToViewDiff": "选择文件查看差异", + "before": "修改前", + "after": "修改后", + "push": "推送", + "toasts": { + "pushSuccess": "推送成功", + "pushFailed": "推送失败", + "upstreamSet": "已设置远程跟踪分支", + "upstreamSetAndPushed": "已设置远程跟踪分支并推送 {count} 个提交", + "noCommitsToPush": "没有可推送的提交", + "pushedCommits": "已推送 {count} 个提交" + } + }, + "gitLogTab": { + "filesTitle": "文件", + "expandAllFiles": "展开全部文件", + "collapseAllFiles": "折叠全部文件", + "workspace": "工作区", + "retry": "重试", + "noCommitsFound": "未找到提交记录", + "notAGitRepoTitle": "不是 Git 仓库", + "notAGitRepoHint": "可从上方分支菜单初始化 Git,或打开已有的 Git 仓库。", + "hash": "Hash", + "copyHash": "复制哈希", + "copyMessage": "复制提交消息", + "showMore": "展开", + "showLess": "收起", + "author": "作者", + "noFileChangeDetails": "暂无文件变更详情。", + "loadingFiles": "正在加载文件…", + "branchesTitle": "分支", + "loadingBranches": "正在加载分支...", + "noContainingBranches": "未找到包含此提交的分支。", + "newBranch": "新建分支...", + "resetToHere": "重置到此处", + "resetDisabledReasonNotCurrentBranchView": "仅在查看当前分支时可用", + "copyFullCommitHashAria": "复制完整提交哈希 {hash}", + "pushStatus": { + "pushed": "已推送到远程", + "notPushed": "未推送到远程", + "unknown": "推送状态未知(未配置上游分支)" + }, + "time": { + "monthsAgo": "{count} 个月前", + "daysAgo": "{count} 天前", + "hoursAgo": "{count} 小时前", + "minsAgo": "{count} 分钟前", + "justNow": "刚刚" + }, + "toasts": { + "createdAndSwitchedNewBranch": "已创建并切换到新分支", + "newBranchFromCommit": "{name}(来自 {shortHash})", + "createBranchFailed": "新建分支失败", + "openPushWindowFailed": "打开推送窗口失败", + "resetSuccess": "重置成功", + "resetSuccessDescription": "已将 {branch} 以 {mode} 重置到 {shortHash}", + "resetFailed": "重置失败" + }, + "authorFilter": { + "label": "作者", + "searchPlaceholder": "搜索作者", + "noAuthors": "未找到作者", + "you": "你", + "filterByAuthorAria": "按作者筛选提交", + "filterByQuery": "按“{query}”过滤", + "clearAuthorFilterAria": "清除作者过滤", + "recent": "最近", + "matchingAuthors": "匹配的作者", + "removeFromRecent": "从最近列表移除 {name}" + }, + "branchSelector": { + "label": "分支", + "head": "HEAD", + "headHint": "跟随当前分支", + "headHintWithBranch": "跟随当前分支({branch})", + "searchBranch": "搜索分支...", + "noBranches": "无分支", + "selectBranchPlaceholder": "选择分支...", + "localBranches": "本地分支", + "current": "当前", + "remoteBranches": "远程分支", + "refreshCommitHistory": "刷新提交记录", + "clearBranchFilterAria": "清除分支过滤" + }, + "dialogs": { + "newBranchTitle": "新建分支", + "newBranchDescription": "以提交 {shortHash} 作为最后提交创建新分支。", + "branchNamePlaceholder": "分支名称", + "reset": { + "title": "将当前分支重置到此提交", + "branchLabel": "分支", + "targetLabel": "目标提交", + "messageLabel": "提交信息", + "modeLabel": "重置模式", + "confirmButton": "重置", + "modes": { + "soft": { + "label": "--soft", + "description": "将 HEAD 和当前分支指针移动到目标提交。\n暂存区(Index)和工作区(Working Tree)保持不变。\n被回退提交对应的改动会保留为“已暂存”状态。" + }, + "mixed": { + "label": "--mixed(默认)", + "description": "将 HEAD 移动到目标提交。\n把暂存区重置为目标提交状态,但保留工作区改动。\n这些改动会从“已暂存”变为“未暂存”。" + }, + "hard": { + "label": "--hard", + "description": "将 HEAD、暂存区和工作区全部重置到目标提交。\n目标提交之后的本地已跟踪改动会被直接丢弃。\n这是破坏性操作。" + }, + "keep": { + "label": "--keep", + "description": "将 HEAD 移动到目标提交,并尽量保留本地改动。\n仅当本地改动与目标提交不冲突时才会保留。\n若存在冲突,操作会中止以避免覆盖你的修改。" + } + } + } + }, + "moreActions": "更多 Git 操作" + }, + "gitChangesTab": { + "workspace": "工作区", + "noChanges": "暂无本地改动", + "notAGitRepoTitle": "不是 Git 仓库", + "notAGitRepoHint": "可从上方分支菜单初始化 Git,或打开已有的 Git 仓库。", + "trackedChanges": "本地已跟踪改动 ({count})", + "untrackedFiles": "本地未跟踪文件 ({count})", + "expandTracked": "展开已跟踪改动", + "collapseTracked": "折叠已跟踪改动", + "expandUntracked": "展开未跟踪文件", + "collapseUntracked": "折叠未跟踪文件", + "showRemainingItems": "显示其余 {count} 项", + "actions": { + "commitCode": "提交代码", + "rollback": "回滚", + "addToVcs": "添加到 VCS", + "delete": "删除", + "moreActions": "更多 Git 操作", + "addAllToVcs": "全部添加到 VCS", + "rollbackAll": "全部回滚", + "refresh": "刷新" + }, + "toasts": { + "noAddableFilesInDir": "该目录下没有可添加到 VCS 的变更文件", + "noRollbackFilesInDir": "该目录下没有可回滚的变更文件", + "addedToVcs": "已添加 {name} 到 VCS", + "addToVcsFailed": "添加到 VCS 失败", + "openCommitWindowFailed": "打开提交窗口失败", + "rolledBack": "已回滚 {name}", + "rollbackFailed": "回滚失败", + "addedFilesToVcs": "已添加 {count} 个文件到 VCS", + "rolledBackFiles": "已回滚 {count} 个文件", + "deleted": "已删除 {name}", + "deleteFailed": "删除失败", + "deletedFiles": "已删除 {count} 个文件", + "noDeletableFilesInDir": "该目录下没有可删除的变更文件", + "commitFailed": "提交失败" + }, + "directoryDialog": { + "descriptionAdd": "选择目录 {path} 下要添加到 VCS 的文件。", + "descriptionRollback": "选择目录 {path} 下要回滚的文件。", + "descriptionDelete": "选择目录 {path} 下要删除的文件。此操作不可撤销。", + "descriptionFallback": "选择要操作的文件。", + "selectionCount": "已选择 {selected} / {total} 个文件", + "selectAll": "全选", + "unselectAll": "取消全选", + "loadingCandidates": "正在加载目录变更...", + "noOperableFiles": "没有可操作的文件" + }, + "rollbackConfirm": { + "title": "确认回滚", + "descriptionWithTarget": "确定回滚{kind}「{name}」的本地修改吗?", + "descriptionFallback": "确定回滚本地修改吗?", + "kindDirectory": "目录", + "kindFile": "文件" + }, + "deleteConfirm": { + "title": "确认删除", + "descriptionWithTarget": "确定删除{kind}「{name}」吗?此操作不可撤销。", + "descriptionFallback": "确定删除吗?此操作不可撤销。", + "kindDirectory": "目录", + "kindFile": "文件" + }, + "quickCommit": { + "placeholder": "提交信息(回车提交)" + } + }, + "tabContext": { + "loadingConversation": "加载中...", + "untitledConversation": "未命名会话", + "newConversation": "新建会话" + }, + "fileTreeTab": { + "workspace": "工作区", + "retry": "重试", + "git": "Git", + "openInFileManager": "在文件管理器打开", + "openInFinder": "在访达打开", + "openInExplorer": "在资源管理器打开", + "attachToCurrentSession": "添加到会话", + "compareWithBranch": "与分支比较...", + "reloadFromDisk": "从磁盘重新加载", + "new": "新建", + "newFile": "文件", + "newDirectory": "目录", + "openIn": "打开于", + "openInTerminal": "在终端打开", + "linkedFolder": "关联的文件夹", + "copyPath": "复制路径", + "upload": "上传文件/目录", + "download": "下载文件", + "downloadAsZip": "下载为 ZIP", + "actions": { + "select": "选择", + "unselect": "取消选择", + "commitCode": "提交代码", + "rollback": "回滚", + "addToVcs": "添加到 VCS" + }, + "aria": { + "selectPath": "{action}:{path}" + }, + "toasts": { + "openDirectoryFailed": "打开目录失败", + "openBuiltinTerminalFailed": "无法打开内置终端", + "openCommitWindowFailed": "打开提交窗口失败", + "noAddableFilesInDir": "该目录下没有可添加到 VCS 的变更文件", + "noRollbackFilesInDir": "该目录下没有可回滚的变更文件", + "addedToVcs": "已添加 {name} 到 VCS", + "addToVcsFailed": "添加到 VCS 失败", + "loadBranchesFailed": "加载分支失败", + "renameFailed": "重命名失败", + "moveFailed": "移动失败", + "deleteFailed": "删除失败", + "rolledBack": "已回滚 {name}", + "rollbackFailed": "回滚失败", + "addedFilesToVcs": "已添加 {count} 个文件到 VCS", + "rolledBackFiles": "已回滚 {count} 个文件", + "savedAsCopy": "已另存为副本", + "saveCopyFailed": "另存为副本失败", + "watchStartFailed": "文件监听启动失败", + "createFailed": "创建失败", + "downloadFailed": "下载 {name} 失败", + "downloadSaved": "已下载 {name}", + "pathCopied": "已复制路径", + "copyPathFailed": "复制路径失败" + }, + "createDialog": { + "newFile": "新建文件", + "newDirectory": "新建目录", + "description": "输入新{kind}的名称。", + "placeholderFile": "文件名.ext", + "placeholderDirectory": "文件夹名" + }, + "renameDialog": { + "renameDirectory": "重命名目录", + "renameFile": "重命名文件", + "description": "输入新的名称(仅名称,不含路径)。", + "placeholderDirectory": "新建文件夹名称", + "placeholderFile": "新建文件名称.ext" + }, + "uploadDialog": { + "title": "上传到工作区", + "description": "可以在下方修改上传目录,然后添加文件或文件夹。", + "workspaceRoot": "工作区根目录", + "targetPathLabel": "上传到", + "targetPathHint": "实际目录:{path}", + "dropHint": "拖拽文件或文件夹到此处,或使用下方按钮", + "dropHintActive": "释放鼠标以加入上传队列", + "selectFiles": "选择文件", + "selectFolder": "选择文件夹", + "startUpload": "开始上传", + "clearQueue": "清除已完成", + "removeItem": "从队列移除", + "retry": "重试", + "dropZoneAria": "拖放文件到此处,或按回车键浏览", + "folderEmpty": "拖入的文件夹中没有可上传的文件", + "summary": "总数:{total} · 成功:{succeeded} · 失败:{failed}", + "status": { + "pending": "等待中", + "uploading": "上传中", + "success": "完成", + "error": "失败", + "cancelled": "已取消" + } + }, + "directoryDialog": { + "descriptionAdd": "选择目录 {path} 下要添加到 VCS 的文件。", + "descriptionRollback": "选择目录 {path} 下要回滚的文件。", + "descriptionFallback": "选择要操作的文件。", + "selectionCount": "已选择 {selected} / {total} 个文件", + "selectAll": "全选", + "unselectAll": "取消全选", + "loadingCandidates": "正在加载目录变更...", + "noOperableFiles": "没有可操作的文件" + }, + "compareDialog": { + "title": "与分支比较", + "descriptionWithTarget": "选择分支并与{kind} {path} 对比", + "descriptionFallback": "选择要比较的分支。", + "kindDirectory": "目录", + "kindFile": "文件", + "filterPlaceholder": "过滤分支,例如 main / origin/main", + "singleClickHint": "单击分支即可直接比较", + "loadingBranches": "正在加载分支...", + "recentBranches": "最近分支 ({count})", + "noCurrentBranch": "无当前分支", + "localBranches": "本地分支 ({count})", + "remoteBranches": "远程分支 ({count})", + "noMatchingBranches": "无匹配分支" + }, + "externalConflictDialog": { + "title": "检测到外部文件变更", + "descriptionWithPath": "文件 {path} 在磁盘已发生变化,当前编辑内容尚未保存。", + "descriptionFallback": "当前文件在磁盘已发生变化,当前编辑内容尚未保存。", + "compare": "对比", + "savingCopy": "另存中...", + "saveAsCopy": "另存为副本", + "reload": "重载" + }, + "deleteConfirm": { + "title": "确认删除", + "descriptionWithTarget": "确定删除{kind} \"{name}\" 吗?此操作不可撤销。", + "descriptionFallback": "此操作不可撤销。", + "kindDirectory": "目录", + "kindFile": "文件" + }, + "rollbackConfirm": { + "title": "确认回滚", + "descriptionWithTarget": "确定回滚文件 \"{name}\" 的本地修改吗?", + "descriptionFallback": "确定回滚该文件的本地修改吗?" + }, + "terminalTitle": "终端 · {name}" + }, + "commandDropdown": { + "loading": "加载中...", + "addCommand": "添加命令", + "manageCommands": "管理命令...", + "runCommandTitle": "运行:{command}", + "stopCommandTitle": "停止:{command}", + "manageDialog": { + "title": "管理命令", + "empty": "暂无命令", + "noResults": "没有匹配的命令", + "searchPlaceholder": "搜索命令", + "newCommand": "新建命令", + "nameLabel": "名称", + "commandLabel": "命令", + "dragSort": "拖拽排序", + "dragSortCommand": "拖拽排序 {name}", + "orderFailed": "保存命令排序失败", + "loadFailed": "加载命令失败", + "saveFailed": "保存命令失败", + "deleteFailed": "删除命令失败", + "confirmDelete": { + "title": "删除命令?", + "message": "这会移除“{name}”,此操作不可撤销。" + } + } + }, + "workspaceContext": { + "confirmCloseDirtyTab": "文件“{title}”有未保存更改,确定关闭吗?", + "confirmCloseOtherDirtyTabs": "其它标签页有未保存更改,确定关闭吗?", + "confirmCloseAllDirtyTabs": "存在未保存更改,确定关闭全部标签页吗?", + "unableLoadContent": "无法加载内容。\n\n{message}", + "previewRequestTimedOut": "预览请求超时", + "diffRequestTimedOut": "Diff 请求超时", + "branchCompareRequestTimedOut": "分支比较请求超时", + "commitDiffRequestTimedOut": "提交差异请求超时", + "saveRequestTimedOut": "保存请求超时", + "reloadRequestTimedOut": "重载请求超时", + "noChanges": "暂无变更。", + "noDiffOutput": "无差异输出。", + "diffTitleWorkspace": "Diff · 工作区", + "diffDescriptionWorkingTree": "工作区变更(HEAD)", + "diffTitleFile": "差异 · {name}", + "compareTitleFile": "比较 · {name}", + "compareTitleBranch": "比较 · {branch}", + "compareDescriptionPath": "{path} · 与 {branch} 比较", + "compareDescriptionBranch": "与 {branch} 比较", + "diffTitleCommitFile": "差异 · {name} @ {hash}", + "diffTitleCommit": "差异 · {hash}", + "diffDescriptionCommitPath": "{path} · 提交 {commit}", + "diffDescriptionCommit": "提交 {commit}", + "diffTitleConflictFile": "冲突 · {name}", + "diffDescriptionConflict": "{path} · 磁盘与未保存内容" + }, + "chat": { + "acpConnections": { + "actions": { + "openAgentsSettings": "打开 Agents 管理", + "retry": "重试" + }, + "agentsSetupHint": "点击前往设置 > Agents 管理安装。", + "withSetupHint": "{message}\n提示:{hint}", + "blocked": { + "missingConfig": "无法读取当前 Agent 配置。", + "disabled": "{agent} 已在 Agents 管理中禁用,请先启用后再连接。", + "unavailable": "{agent} 当前平台不可用。", + "sdkMissing": "{agent} SDK 尚未安装", + "adapterMissing": "{agent} 的 ACP 适配器尚未安装" + }, + "backendErrors": { + "initializeTimeout": "{agent} 连接握手超时(60 秒未响应),请前往设置页面检查智能体和网络配置。", + "mcpRejectedByAgent": "附带 codeg 的 MCP 伴生进程时,{agent} 拒绝了本次会话:{message} 如果该智能体不支持 MCP,请在设置中关闭它的“MCP 支持”后重新连接。", + "processExited": "{agent} 进程意外退出。", + "spawnFailed": "启动 {agent} 失败:{message}", + "downloadFailed": "{agent} 下载失败:{message}", + "sessionLoadResourceNotFound": "{agent} 会话加载失败,可重新加载重试,或开始新会话。", + "sessionLoadUnavailable": "{agent} 无法恢复此会话,它可能已结束或 agent 已停止。可重新加载重试,或开始新会话。", + "turnFailedRefusal": "{agent} 拒绝继续本轮回复,通常意味着后端或网关出错,请检查代理日志。", + "turnFailedMaxTokens": "{agent} 已达到本轮回复的最大 Token 限制。", + "turnFailedMaxTurnRequests": "{agent} 已达到本轮回复允许的最大请求次数。", + "turnFailedUnknown": "{agent} 以未知的停止原因结束了本轮回复。", + "grokModelSwitchIncompatibleAgent": "{agent} 无法在已有对话中切换到该模型,请新建会话以使用它。", + "turnFailedEmpty": "{agent} 本轮没有产生任何回复就结束了。", + "turnFailedEmptyProtocol": "{agent} 本轮的输出 codeg 无法解析,可能是代理版本与协议不匹配。", + "turnFailedEmptyMetadata": "{agent} 本轮只收到状态更新(计划 / 模式 / 用量),没有收到任何回复。", + "detailsInAlerts": "在状态栏的「告警」中展开详情,可查看代理输出。" + }, + "unableReadAgentConfig": "无法读取 Agent 配置:{message}", + "connectFailedTitle": "{agent} 连接失败", + "toolFallbackTitle": "工具", + "eventErrorTitle": "Agent 错误", + "notificationTurnComplete": "{agent} 已完成响应", + "notificationError": "{agent} 错误:{message}", + "claudeApiRetry": { + "fallbackError": "authentication_failed", + "retryingWithMax": "正在重试 {attempt}/{max}", + "retryingAttempt": "正在重试(第 {attempt} 次)", + "retrying": "正在重试", + "nextRetryIn": "{seconds} 秒后重试", + "line": "{error}{status} · {retry}", + "lineWithDelay": "{error}{status} · {retry},{delay}", + "httpStatus": "(HTTP {status})" + }, + "configOptionAdjusted": "{agent} 把{option}设成了 {actual},而不是 {requested}" + }, + "connectionLifecycle": { + "tasks": { + "connectingTitle": "正在连接 {agent}", + "connectingDescription": "正在建立连接", + "loadingSelectorsTitle": "正在加载 {agent} 选择项", + "loadingSelectorsDescription": "正在获取模式和会话配置选项", + "initSessionTitle": "正在初始化 {agent} 会话", + "initSessionDescription": "正在创建会话并加载配置" + }, + "errors": { + "connectionFailed": "连接失败", + "sendPromptFailed": "消息发送失败:{error}" + } + }, + "shared": { + "attachedResources": "附加资源", + "toolCallFailed": "工具调用失败" + }, + "messageThread": { + "emptyTitle": "暂无消息", + "emptyDescription": "开始一个会话后,消息会显示在这里" + }, + "chatInput": { + "connecting": "连接中...", + "agentResponding": "{agent} 正在响应...", + "sendMessage": "发送消息..." + }, + "messageInput": { + "askAnything": "请开始输入...", + "removeAttachmentAria": "移除 {name}", + "attachFiles": "附加文件", + "attachLocalUpload": "附加本地文件", + "attachServerFile": "附加服务端文件", + "addActions": "添加", + "quickMessages": "快捷消息", + "quickMessagesEmpty": "暂无快捷消息", + "quickMessagesLoading": "加载中...", + "pasteAsPlainText": "粘贴为纯文本", + "cut": "剪切", + "copy": "复制", + "selectAll": "全选", + "pasteUnavailable": "无法读取剪贴板,请改用 Ctrl/⌘V 粘贴。", + "clipboardWriteFailed": "无法写入剪贴板,请改用键盘快捷键。", + "quickMessageUntitled": "未命名", + "liveFeedback": "实时反馈", + "liveFeedbackDisabledHint": "智能体工作时可发送", + "dropFilesToAttach": "拖拽文件到此处附加", + "loadingSettings": "正在加载设置...", + "loadingMode": "正在加载模式...", + "modeLabel": "模式", + "toggleOn": "开", + "toggleOff": "关", + "agentSettings": "智能体设置", + "searchModel": "搜索模型...", + "searchModelAria": "搜索模型", + "modelListLabel": "模型", + "noModels": "未找到模型", + "cancel": "取消", + "send": "发送", + "forkAndSend": "分叉发送", + "queueMessage": "加入队列", + "steerIntoTurn": "插入当前回合", + "steerQueuedInstead": "已转入队列——将随下一回合发送。", + "steerFailed": "无法插入当前回合", + "steerAttachmentsUnsupported": "仅支持纯文本——带附件的草稿请走队列。", + "slashCommands": "斜杠命令", + "slashSearchPlaceholder": "搜索命令...", + "slashSearchEmpty": "没有匹配的命令", + "experts": "专家", + "office": "日常办公", + "research": "科学研究", + "attachUploadTooLarge": "{names} 超过 {limit}MB 上传上限,已跳过。", + "attachUploadFailed": "上传失败:{names}。", + "attachUploadNotAFile": "{names} 不是常规文件(目录或特殊文件),已跳过。", + "attachUploadQuotaExceeded": "服务器上传空间已用尽,{names} 未能上传。", + "attachUploadInProgress": "图片仍在上传中,请稍候再发送。", + "mentionEmpty": "无匹配项", + "mentionLoading": "搜索中…", + "mentionListLabel": "提及", + "mentionMore": "还有更多结果,继续输入以筛选", + "mentionCount": "{count, plural, other {# 项结果}}", + "mentionGroupFile": "文件", + "mentionGroupAgent": "智能体", + "mentionGroupSession": "会话", + "mentionGroupCommit": "提交", + "mentionGroupSkill": "技能" + }, + "messageQueue": { + "addToQueue": "加入队列", + "saveEdit": "保存", + "cancelEdit": "取消编辑", + "editItem": "编辑", + "deleteItem": "删除" + }, + "welcomeInputPanel": { + "agentsSettingsPath": "设置 > Agents", + "autoConnectFallback": "点击前往 {path} 管理安装。", + "autoConnectAppend": "{message},点击前往 {path} 管理安装。", + "enableAgentFirstPlaceholder": "请先启用至少一个 Agent 后开始会话...", + "prepareSessionFailed": "无法准备聊天会话,请重试。", + "createConversationFailed": "无法创建会话,请重试。", + "askAnythingPlaceholder": "请开始输入...", + "agentNotInstalled": "{agent} 尚未安装 · 点击前往 Agents 设置安装", + "agentAdapterNotInstalled": "{agent} 的 ACP 适配器尚未安装(与你本地的 CLI 无关)· 点击前往 Agents 设置安装" + }, + "welcomePanel": { + "greeting": "今天准备做些什么呢?", + "tips": { + "tileTabs": "右键点击会话标签选择「平铺显示」,可同屏对比多个会话", + "pinTab": "双击会话标签可将其固定,避免被新打开的会话自动替换", + "shortcutsNewSearch": "{newConversation} 快速新建会话,{searchConversations} 搜索历史会话", + "slashAtMention": "在输入框输入 / 触发斜杠命令,输入 @ 引用项目内文件", + "pasteDropFiles": "直接粘贴截图或把文件拖到输入框,即可作为附件", + "queueMessage": "智能体回复中也能继续输入并排队,回答完毕会自动续发", + "draftAutoSave": "未发送的草稿会自动保存,重新打开会话仍在", + "forkSend": "发送按钮旁的下拉选择「分叉发送」,从当前位置开一条新分支", + "exportConversation": "右键会话内容区可导出为 Markdown / HTML / 图片", + "chatChannels": "在「设置 → 聊天频道」接入 Telegram / 飞书 / 微信,从手机继续操作", + "shortcutsAuxPanel": "{toggleAuxPanel} 切换右侧面板,查看本次会话改动的文件与 Git 变更", + "shortcutsTerminalSidebar": "{toggleTerminal} 打开内置终端,{toggleSidebar} 切换侧边栏", + "customShortcuts": "所有快捷键都可在「设置 → 快捷键」中自定义", + "webService": "开启「设置 → Web 服务」后,团队成员可从浏览器接入同一台 codeg", + "fusionMode": "打开文件或差异后,会自动与会话并排显示", + "quickMessages": "点输入框旁的 + 按钮选择「快捷消息」,可一键插入预存片段(在「设置 → 快捷消息」中管理)", + "experts": "通过 + 按钮里的「专家技能」可一键加载预设角色(调试 / 规划等)", + "taskBoard": "「待办任务」能把一条待办从头跑到尾:智能体在独立工作树里干活,你 review 完差异再合并。", + "automations": "「自动化」按计划定时跑保存好的提示词(比如每晚一次代码评审),还能让每次运行都开一个独立工作树。", + "tokenUsage": "点击状态栏左下角的会话数即可打开「Token 用量」,按天、智能体、模型和文件夹拆分统计。", + "mentionTargets": "@ 不只能引用文件:还能 @ 另一个智能体把子任务交给它,或引用历史会话、某次提交、某个技能。", + "splitGroups": "右键点击标签选择「向右拆分」或「向下拆分」,两个会话各占一个分栏同时开着。", + "worktrees": "点开分支按钮选「新建工作树」,多个智能体就能在同一个仓库并行干活,互不覆盖彼此的文件。", + "importSessions": "之前在终端里跑过的会话,用文件夹右键菜单的「导入本地会话」就能把那段历史接进 codeg。", + "subSessions": "智能体委派出去的子会话会嵌套显示在侧边栏的父会话下面,展开就能跟踪每一个子会话做了什么。", + "liveFeedback": "「+」菜单里的「实时反馈」能把一条便条塞进智能体正在跑的这一轮,不用打断它。", + "skillPacks": "设置 → 技能包 里打包了编程专家、科研和办公三类技能,可以按智能体分别开关。", + "modelProviders": "设置 → 模型供应商 支持填自己的 API key 或接口地址,之后直接在输入框里切换模型。", + "workspaceBackground": "设置 → 外观 里可以换工作区背景图、调面板不透明度,还能换应用字体。" + }, + "quickActions": { + "excel": "Excel 工作簿", + "excelDesc": "数据表、公式和图表", + "word": "Word 文档", + "wordDesc": "报告、信函和备忘录", + "ppt": "演示文稿", + "pptDesc": "专业设计的幻灯片", + "pitchDeck": "融资路演", + "pitchDeckDesc": "含关键指标的路演 PPT", + "morph": "Morph 动画", + "morphDesc": "电影级幻灯片转场", + "morph3d": "3D Morph", + "morph3dDesc": "3D 模型与镜头运动", + "academic": "学术论文", + "academicDesc": "含引用与结构的研究论文", + "financial": "财务模型", + "financialDesc": "报表、DCF 与预测", + "dashboard": "数据仪表盘", + "dashboardDesc": "从数据生成 KPI 与分析", + "prompts": { + "excel": "创建一个 Excel 工作簿,要求如下:\n\n[在此描述你的数据、表格、公式和图表]", + "word": "创建一个 Word 文档,要求如下:\n\n[在此描述文档内容、结构和排版]", + "ppt": "创建一个 PowerPoint 演示文稿,要求如下:\n\n[在此描述幻灯片、内容和设计]", + "pitchDeck": "创建一个融资路演 PPT,要求如下:\n\n[在此描述公司、融资轮次和关键指标]", + "morph": "创建一个带 Morph 转场动画的演示文稿:\n\n[在此描述演示主题和期望的视觉效果]", + "morph3d": "创建一个带 GLB 模型和镜头运动的 3D Morph 演示文稿:\n\n[在此描述主题和 3D 视觉构想]", + "academic": "用 Word 写一篇学术论文,要求如下:\n\n[在此描述研究主题、方法和主要发现]", + "financial": "用 Excel 创建一个财务模型,要求如下:\n\n[在此描述财务报表、预测和分析]", + "dashboard": "用 Excel 创建一个数据仪表盘,要求如下:\n\n[在此描述数据来源、KPI 和图表]", + "scientific-brainstorming": "帮我进行科研头脑风暴:探索跨学科联系、挑战假设、发现有潜力的研究空白。我正在探索的方向:", + "hypothesis-generation": "帮我把这些观察转化为可检验的假设:给出明确预测、合理机制,并设计验证实验。我的观察:", + "experimental-design": "在采集数据前帮我设计严谨的实验:设计方案、随机化、对照,以及如何避免混杂。我想研究的问题:", + "statistical-power": "帮我确定所需样本量:为我的设计做功效分析(效应量、显著性水平、功效)。具体信息:", + "statistical-analysis": "帮我正确分析这份数据:选择合适的检验、检查假设、报告效应量并撰写结论。我的数据与问题:", + "exploratory-data-analysis": "对我的数据文件做探索性分析:概述其结构、质量与值得注意的模式,并建议后续步骤。文件是:", + "scientific-visualization": "帮我制作出版级图表:清晰布局、真实误差棒、色盲友好配色,以及期刊格式。我想展示的内容:", + "scientific-critical-thinking": "帮我批判性评估这项研究或主张:评估证据质量、识别偏倚与混杂,并权衡结论。内容如下:", + "paper-lookup": "帮我在学术数据库中查找相关论文与开放获取全文,并提供可复用的引用。我要找的是:" + }, + "paper-lookup": "论文检索", + "paper-lookupDesc": "检索 10 个学术 API(PubMed、arXiv、OpenAlex、Crossref…)查找论文、引用与开放获取全文。", + "scientific-critical-thinking": "批判性思维", + "scientific-critical-thinkingDesc": "评估科学主张与证据质量:识别偏倚与混杂,运用 GRADE 与偏倚风险框架。", + "scientific-visualization": "科学可视化", + "scientific-visualizationDesc": "出版级图表:多面板布局、显著性标注与期刊专属格式。", + "exploratory-data-analysis": "探索性数据分析", + "exploratory-data-analysisDesc": "对 200+ 种格式的科学数据文件做自动化探索,输出质量指标与报告。", + "statistical-analysis": "统计分析", + "statistical-analysisDesc": "引导式统计分析:检验选择、假设检查、效应量与 APA 格式报告。", + "statistical-power": "统计功效", + "statistical-powerDesc": "样本量与统计功效分析:所需样本数、最小可检测效应与功效曲线。", + "experimental-design": "实验设计", + "experimental-designDesc": "在采集数据前设计严谨研究:随机化、区组、对照与析因/DOE 布局。", + "hypothesis-generation": "假设生成", + "hypothesis-generationDesc": "将观察转化为可检验的假设,给出预测、机制并设计验证实验。", + "scientific-brainstorming": "科学头脑风暴", + "scientific-brainstormingDesc": "开放式科研构思:探索跨学科联系、挑战假设、发现研究空白。", + "tabs": { + "office": "日常办公", + "coding": "代码开发", + "research": "科学研究" + }, + "coding": { + "brainstormingDesc": "动手前先梳理意图与需求", + "debuggingDesc": "先定位根因再提出修复", + "writingSkillsDesc": "创建、编辑并验证可复用技能" + }, + "notEnabled": { + "title": "「{skill}」技能尚未对 {agent} 启用", + "description": "前往设置启用后即可在此使用。", + "action": "去启用", + "hint": "技能未启用" + }, + "scrollPrev": "显示上一组技能", + "scrollNext": "显示下一组技能" + } + }, + "agentSelector": { + "noEnabledAgents": "暂无已启用的 Agent", + "openAgentsSettings": "打开 Agents 设置", + "notInstalled": "未安装", + "moreAgents": "更多 Agent({count})" + }, + "subAgentOverlay": { + "title": "子智能体", + "collapsedSummary": "子智能体 {count}", + "collapseAria": "折叠子智能体" + }, + "agentPlanOverlay": { + "title": "计划任务", + "collapsePlanAria": "折叠计划", + "collapsedSummary": "计划 {completed}/{total}", + "status": { + "completed": "已完成", + "inProgress": "进行中", + "pending": "待处理", + "unknown": "未知" + }, + "priority": { + "high": "高", + "medium": "中", + "low": "低", + "unknown": "未知" + } + }, + "permissionDialog": { + "subtitle": "Agent 请求继续当前轮次的权限。", + "queuedCount": "还有 {count} 项待审批", + "kindFallbackTool": "工具", + "command": "命令", + "cwd": "工作目录:{cwd}", + "filesSummary": "文件:{count}", + "moreFiles": "+{count} 个更多文件", + "plan": "计划", + "allowedActions": "允许的操作", + "targetMode": "目标模式:{mode}", + "optionGrants": "各选项将授予的权限", + "changeScopeSession": "本次会话", + "changeScopeProcess": "本次运行", + "changeScopeUser": "保存到用户设置", + "changeScopeProject": "保存到项目设置", + "changeScopeProjectLocal": "保存到本地项目设置", + "changeScopePersistent": "永久保存" + }, + "questionDialog": { + "title": "代理正在提问", + "placeholder": "输入你的回答...", + "send": "发送" + }, + "messageBranch": { + "previousBranchAria": "上一分支", + "nextBranchAria": "下一分支", + "pageOf": "{current} / {total}" + }, + "terminal": { + "title": "终端", + "running": "运行中" + }, + "reasoning": { + "thinking": "思考中…", + "thoughtForFewSeconds": "思考", + "thoughtForSeconds": "思考" + }, + "linkSafety": { + "errorCannotOpen": "无法打开本地文件", + "errorNoWorkspace": "当前没有活跃的工作区文件夹。", + "errorFailedOpen": "打开本地文件失败", + "errorFailedLink": "打开链接失败", + "errorUnsupportedLinkProtocol": "不支持该链接协议。" + }, + "fileActions": { + "openInFinder": "在访达打开", + "openInExplorer": "在资源管理器打开", + "openInFileManager": "在文件管理器打开", + "copyRelativePath": "复制相对路径", + "copyAbsolutePath": "复制绝对路径", + "pathCopied": "已复制路径", + "copyPathFailed": "复制路径失败", + "openFailed": "打开本地文件失败" + }, + "messageList": { + "attachedResources": "附加资源", + "loading": "加载中...", + "loadEarlier": "加载更早的消息", + "loadingEarlier": "正在加载更早的消息…", + "error": "错误:{message}", + "errorTitle": "会话加载失败", + "errorActionReload": "重新加载", + "errorActionNewSession": "新建会话", + "emptyConversation": "当前会话暂无消息。", + "systemMessage": "系统消息", + "copyMessage": "复制", + "copied": "已复制", + "downloadImage": "下载图片", + "downloadFailed": "下载失败:{message}", + "imageGeneration": "图片生成", + "imageGenerationPending": "正在生成图片…", + "imageGenerationFailed": "图片生成失败", + "model": "模型", + "tokenStats": "Token 使用情况", + "tokenInput": "输入", + "tokenOutput": "输出", + "tokenCacheRead": "缓存读取", + "tokenCacheWrite": "缓存写入", + "duration": "耗时", + "completedAt": "完成时间", + "jumpToPreviousUserMessage": "跳转到上一条用户消息", + "showMore": "展开", + "showLess": "收起" + }, + "liveTurnStats": { + "thinking": "思考中...", + "streaming": "生成中", + "elapsedHours": "{value} 小时", + "elapsedMinutes": "{value} 分钟", + "elapsedSeconds": "{value} 秒", + "outputSpeedAria": "估算输出速度", + "outputSpeedTooltip": "估算输出速度(正文 + 思考)" + }, + "jsonTree": { + "viewRaw": "查看原始 JSON", + "viewTree": "查看树状视图", + "fields": "{count} 个字段", + "items": "{count} 项" + }, + "tool": { + "parameters": "参数", + "error": "错误", + "result": "结果", + "status": { + "approvalRequested": "等待授权", + "approvalResponded": "已响应", + "inputAvailable": "运行中", + "inputStreaming": "等待中", + "outputAvailable": "已完成", + "outputDenied": "已拒绝", + "outputError": "错误" + } + }, + "toolCallBlock": { + "tool": "工具", + "error": "错误", + "result": "结果" + }, + "delegation": { + "subAgentRunning": "子智能体运行中…", + "noDetail": "暂无详情。", + "unknownAgent": "子智能体", + "openDetail": "查看会话", + "detailTitle": "子智能体会话", + "detailDescription": "只读查看委托给子智能体的会话内容。", + "waitForResult": "等待 {task} 任务执行结果", + "waitForResultNoTask": "等待任务执行结果", + "cancelTask": "取消 {task} 任务", + "cancelTaskNoTask": "取消任务", + "resultPageOf": "{current} / {total}", + "prevResult": "上一个结果", + "nextResult": "下一个结果", + "noResultText": "本次检查暂无结果", + "status": { + "starting": "启动中", + "running": "运行中", + "checked": "已查询", + "waiting": "待批准", + "ok": "完成", + "err": { + "default": "失败", + "delegation_disabled": "已禁用", + "depth_limit": "深度超限", + "invalid_agent_type": "代理类型无效", + "spawn_failed": "启动失败", + "send_failed": "发送失败", + "timeout": "超时", + "canceled": "已取消", + "child_refusal": "子代理拒绝", + "child_max_tokens": "子代理超出 token 上限", + "child_max_turn_requests": "子代理超出请求上限", + "child_empty": "子代理无响应", + "child_unknown": "子代理未知错误", + "unknown": "未知任务" + } + } + }, + "contentParts": { + "showingTailOutput": "为保证性能,流式输出时仅显示尾部内容。", + "result": "结果", + "unknown": "未知", + "inputTruncated": "输入已截断,diff 可能不完整。", + "replaceAll": "全部替换", + "filesCount": "文件:{count}", + "update": "更新", + "moreFiles": "+{count} 个更多文件", + "timeoutMs": "超时:{timeout}ms", + "backgroundTrue": "后台:true", + "scriptToolCalls": "调用 {count} 个工具", + "offset": "偏移:{offset}", + "limit": "限制:{limit}", + "pages": "页码:{pages}", + "mode": "模式:{mode}", + "cell": "单元:{cell}", + "shellSession": "会话 {id}", + "pathLabel": "路径:", + "globLabel": "Glob:", + "typeLabel": "类型:", + "outputLabel": "输出:", + "caseInsensitive": "忽略大小写", + "multiline": "多行", + "promptLabel": "提示词", + "subjectLabel": "主题", + "taskLabel": "任务", + "nameLabel": "名称:", + "agentPromptLabel": "提示词", + "agentModelLabel": "模型", + "agentRunning": "运行中...", + "agentLiveTranscript": "实时活动", + "agentProgressTools": "{count} 次工具调用", + "agentProgressTurns": "{count} 轮", + "agentProgressContext": "上下文 {pct}%", + "agentSessionAction": "查看子智能体会话", + "agentSessionTitle": "子智能体会话", + "agentSessionLoading": "正在加载子智能体的会话记录…", + "agentSessionEmpty": "子智能体还没有写入任何内容。", + "agentFallbackTitle": "子智能体启动中…", + "agentCodexLaunchOnly": "已启动。Codex 不会再报告这个子智能体的进展——它的结果会作为一条消息出现在本会话中。", + "agentStatsBash": "命令", + "agentStatsRead": "读取文件", + "agentStatsSearch": "搜索", + "agentStatsEdit": "编辑", + "agentStatsOther": "其他", + "goal": { + "title": "目标:", + "titleWithStatus": "目标{status}", + "objective": "目标", + "statusLabel": "状态", + "tokensUsed": "已用 tokens", + "budget": "预算", + "remaining": "剩余", + "elapsed": "耗时", + "tokens": "tokens", + "pause": "暂停", + "clear": "清除", + "status": { + "active": "进行中", + "paused": "已暂停", + "blocked": "受阻", + "usageLimited": "用量受限", + "budgetLimited": "预算受限", + "complete": "已完成", + "limited": "已达上限" + } + }, + "field": { + "file": "文件", + "notebook": "笔记本", + "command": "命令", + "old": "旧内容", + "new": "新内容", + "pattern": "模式", + "path": "路径", + "query": "查询", + "url": "URL地址", + "description": "描述", + "content": "内容", + "source": "源内容", + "prompt": "提示词", + "subject": "主题", + "taskId": "任务 ID", + "status": "状态", + "skill": "Skill", + "args": "参数", + "offset": "偏移", + "limit": "限制", + "glob": "Glob", + "type": "类型", + "output": "输出", + "replaceAll": "全部替换", + "language": "语言", + "timeout": "超时", + "background": "后台", + "agentType": "Agent 类型", + "library": "库", + "libraryId": "库 ID" + }, + "title": { + "edit": "编辑", + "command": "命令", + "script": "脚本", + "waitCommand": "等待 {command}", + "waitCell": "等待会话 {id}", + "terminateCommand": "终止 {command}", + "terminateCell": "终止会话 {id}", + "stdinChars": "输入 {chars}", + "todoWrite": "待办", + "read": "读取", + "write": "写入", + "notebookEdit": "Notebook 编辑", + "editFiles": "编辑({count} 个文件)", + "editWithTarget": "编辑 {target}", + "readWithTarget": "读取 {target}", + "writeWithTarget": "写入 {target}", + "notebookEditWithTarget": "Notebook 编辑 {target}", + "globWithPattern": "Glob {pattern}", + "listFilesWithPath": "列出文件 {path}", + "grepWithPattern": "Grep {pattern}", + "taskCreateWithSubject": "创建任务:{subject}", + "taskUpdateWithStatus": "更新任务 #{id} -> {status}", + "taskUpdate": "更新任务 #{id}", + "webFetchWithUrl": "抓取网页 {url}", + "webSearchWithQuery": "网页搜索:{query}", + "todosProgress": "待办({done}/{total})", + "skillWithName": "Skill:{name}", + "genericWithContext": "{tool}:{context}" + }, + "search": { + "noMatches": "无匹配结果", + "matchSummary": "{matches} 处匹配 · {files} 个文件", + "fileSummary": "{files} 个文件", + "moreResults": "另有 {count} 条结果未显示" + }, + "toolGroup": { + "search": "搜索 {count} 次", + "command": "运行 {count} 个命令", + "read": "读取 {count} 次文件", + "memory": "回忆 {count} 项记忆", + "edit": "编辑 {count} 次文件", + "fetch": "抓取 {count} 个资源", + "think": "思考 {count} 次", + "todo": "更新 {count} 项待办", + "task": "执行 {count} 个任务", + "other": "调用 {count} 个工具", + "errorSuffix": "{count} 个失败", + "joiner": " · " + }, + "planMode": { + "entered": "进入计划模式", + "planLabel": "计划", + "reviewApproved": "已批准执行计划", + "reviewKept": "保持在计划模式", + "reviewPending": "等待计划决定", + "submitted": "计划已提交", + "switched": "切换模式" + }, + "backgroundTask": { + "title": "后台任务", + "titleWithId": "后台任务 · {id}", + "running": "运行中", + "completed": "已完成", + "failed": "失败", + "stopped": "已停止", + "exitCode": "退出码 {code}", + "polledTimes": "轮询 {count} 次", + "runningInBackground": "后台运行", + "launchNote": "已在后台运行 · {id}" + }, + "codexScript": { + "outputMissing": "codex 截断脚本输出时丢掉了这条命令的分隔行,因此没有输出可以归属给它。", + "sharedWith": "本段还包含 {commands} 的输出——它们的分隔行被 codex 截断丢弃了。", + "truncated": "已截断" + } + }, + "messageNav": { + "title": "消息导航", + "collapse": "收起消息导航", + "collapsedSummary": "消息 {count}", + "fileCount": "{count} 个文件", + "remove": "移除", + "noDiffDataAvailable": "未找到 {filePath} 的差异数据" + }, + "replyArtifacts": { + "title": "改动文件", + "fileCount": "{count} 个文件", + "newFilesTitle": "新增文件", + "revealInFolder": "在访达/资源管理器中显示", + "openFile": "打开 {filePath}", + "openInEditor": "在编辑器中打开", + "remove": "移除", + "noDiffDataAvailable": "未找到 {filePath} 的差异数据" + }, + "askQuestion": { + "title": "智能体需要你的选择", + "subtitle": "回答后点击提交,可随时跳过", + "recommended": "推荐", + "other": "其他", + "otherPlaceholder": "输入你的回答…", + "singleSelect": "单选", + "multiSelect": "多选", + "skip": "跳过", + "next": "下一题", + "submit": "提交", + "submitError": "提交失败,请重试。" + }, + "planApproval": { + "title": "智能体已给出计划——请审阅", + "emptyPlan": "智能体未写入计划。可批准开始实施,或要求修改。", + "approve": "批准并开始", + "requestChanges": "要求修改", + "abandon": "放弃", + "feedbackPlaceholder": "需要修改什么?", + "sendChanges": "发送", + "cancel": "取消", + "submitError": "提交失败,请重试。" + }, + "feedbackCheckResult": { + "count": "{count} 条反馈", + "expand": "展开全部反馈", + "collapse": "收起", + "errorTitle": "反馈检查失败" + }, + "askQuestionResult": { + "title": "提问", + "answeredLabel": "提问回答:", + "awaiting": "等待你的回答…", + "declined": "你已忽略此问题 — 代理已自行判断。", + "noSelection": "未选择" + }, + "configStale": { + "agentConfigTitle": "智能体配置已更新", + "modelProviderTitle": "模型供应商已更新", + "description": "当前会话仍在使用旧配置,重连后生效(对话历史不会丢失)。", + "reconnect": "重连以应用", + "reconnecting": "正在重连…", + "reconnectDisabledDuringTurn": "当前回合结束后可重连", + "dismiss": "忽略", + "reconnectFailed": "重连会话失败", + "applied": "新配置已应用" + }, + "piProjectTrust": { + "title": "该项目自带 pi 资源", + "description": "pi 未加载仓库自带的 .pi 文件。请查看后决定。", + "descriptionExecutable": "仓库自带 pi 扩展,扩展会在启动时执行代码。pi 尚未加载它们,请先查看再决定。", + "review": "查看…", + "dismiss": "忽略", + "dialogTitle": "信任该项目的 pi 资源?", + "dialogDescription": "只有在你信任该目录后,pi 才会加载仓库自带的 .pi 文件。请仅在你信任该仓库内容时才信任。", + "executionWarning": "扩展就是代码。信任该目录后,仓库中的扩展会在 pi 启动时以你的权限执行——早于你发送任何消息。", + "scopeNote": "该决定保存在 pi 的 trust.json 中,对该目录下的所有子目录同样生效,你在终端里自己运行 pi 时也会沿用。之后可在「设置 → 智能体 → Pi」中修改。", + "trust": "信任项目", + "decline": "保持不加载", + "disabledDuringTurn": "当前回合结束后可用", + "trustedToast": "已信任项目——已重连以便 pi 加载其资源", + "declinedToast": "项目资源保持不加载", + "saveFailed": "保存项目信任决定失败", + "grantTitle": "该项目已被信任", + "grantDescription": "pi 会加载该仓库自带的 .pi 文件。请查看这意味着什么。", + "grantInheritedDescription": "某个上级目录已被信任,因此 pi 会加载该仓库自带的 .pi 文件。请查看这意味着什么。", + "grantDialogTitle": "该项目的 pi 资源已被信任", + "grantDialogDescription": "pi 被允许加载该仓库自带的 .pi 文件。旧版本 codeg 会在你打开目录时自动授予该权限,因此你可能从未被询问过。", + "grantExecutionWarning": "扩展就是代码。仓库中的扩展会在 pi 启动时以你的权限执行——早于你发送任何消息。", + "inheritedFrom": "信任来自", + "revoke": "撤销信任", + "keepTrusted": "保持信任", + "revokedToast": "已撤销信任——已重连,pi 不再加载该项目的资源", + "trustedNoReconnect": "已信任项目——将在 pi 下次启动时生效", + "revokedNoReconnect": "已撤销信任——将在 pi 下次启动时生效" + }, + "collabAgent": { + "title": "子智能体", + "errorTitle": "子智能体任务失败", + "statesLabel": "子智能体", + "statusRunning": "运行中", + "statusCompleted": "已完成", + "statusFailed": "失败", + "statusPending": "初始化中", + "statusInterrupted": "已中断", + "statusClosed": "已关闭", + "statusNotFound": "未找到", + "opSpawn": "启动子智能体", + "opWait": "获取子智能体结果", + "opClose": "结束子智能体", + "opResume": "恢复子智能体" + }, + "contextCompaction": { + "compacting": "正在压缩上下文…", + "compacted": "上下文已压缩", + "compactedTokens": "上下文已压缩 · {before} → {after} tokens", + "failed": "上下文压缩失败" + }, + "sessionFailure": { + "category": { + "connection": "连接异常", + "access": "访问受限", + "limit": "已达限制", + "request": "请求被拒绝", + "service": "服务异常", + "unknown": "会话异常" + }, + "action": { + "retry": "重试", + "login": "去登录", + "newSession": "新建会话" + }, + "recovered": "已恢复", + "retryUnavailable": "没有可重发的消息。", + "toggleDetails": "展开/收起详情" + }, + "backgroundTasks": { + "running": "{count} 个后台任务运行中", + "settling": "正在同步后台结果…", + "settledFallback": "后台任务已结束({status})", + "cardRunning": "后台运行中", + "cardLaunchedPending": "已启动后台任务", + "cardCompleted": "后台任务已完成", + "cardFinishedWithStatus": "后台任务已结束({status})", + "cardResultPending": "结果尚未返回" + }, + "proposedPlan": { + "title": "计划提案", + "planning": "规划中…" + } + }, + "diffPreview": { + "mode": { + "added": "新增", + "deleted": "删除", + "renamed": "重命名", + "modified": "修改" + }, + "hunkLabel": "代码块 {index}", + "loadingHunk": "正在加载代码块...", + "noDiffData": "无差异数据", + "showRemainingLines": "显示剩余 {count} 行" + }, + "conversationContextBar": { + "folderTitle": "工作文件夹", + "branchTitle": "工作分支", + "searchFolder": "搜索文件夹...", + "searchBranch": "搜索分支...", + "noFolders": "暂无文件夹", + "noBranches": "暂无分支", + "noBranch": "(无分支)", + "chatModeLabel": "聊天模式", + "commit": "提交", + "push": "推送", + "merge": "合并", + "toasts": { + "folderChanged": "已切换到 {name}", + "openFolderFailed": "打开文件夹失败", + "switchedToChatMode": "已切换到聊天模式", + "openStashFailed": "打开贮藏窗口失败", + "openMergeFailed": "打开合并窗口失败" + } + }, + "cloneDialog": { + "title": "克隆仓库", + "repositoryUrl": "仓库地址", + "repositoryUrlPlaceholder": "https://github.com/user/repo.git", + "directory": "目录", + "directoryPlaceholder": "选择目标目录...", + "browseDirectory": "浏览目录", + "cancel": "取消", + "clone": "克隆", + "clonePath": "克隆路径: {path}" + }, + "toasts": { + "cloneFailed": "克隆仓库失败" + } + }, + "ProjectBoot": { + "title": "项目启动器", + "tabs": { + "shadcn": "shadcn", + "hyperframes": "HyperFrames" + }, + "hyperframes": { + "title": "HyperFrames 视频项目", + "subtitle": "脚手架一个 HTML 转视频项目,随后工作区的智能体即可编写并渲染它。", + "resolution": "分辨率", + "skillsTitle": "智能体技能", + "skillsDesc": "为所选智能体全局安装 HyperFrames 技能(软链接),让它们会编写并渲染视频。", + "recheck": "重新检查", + "installedBadge": "已安装", + "skillsInstall": "安装 / 更新技能", + "skillsInstalling": "正在安装技能…", + "skillsInstalled": "HyperFrames 技能安装成功", + "skillsInstallFailed": "HyperFrames 技能安装失败" + }, + "config": { + "base": "基础库", + "style": "风格", + "baseColor": "基础颜色", + "theme": "主题", + "chartColor": "图表颜色", + "iconLibrary": "图标库", + "font": "字体", + "fontHeading": "标题字体", + "menuAccent": "菜单强调", + "menuColor": "菜单颜色", + "radius": "圆角", + "template": "模板", + "createProject": "创建项目", + "sectionStyle": "风格", + "sectionColors": "配色", + "sectionTypography": "排版", + "sectionInterface": "界面" + }, + "preview": { + "loading": "加载预览..." + }, + "createDialog": { + "title": "创建项目", + "projectName": "项目名称", + "projectNamePlaceholder": "my-app", + "frameworkTemplate": "框架模板", + "packageManager": "包管理器", + "saveDirectory": "保存目录", + "saveDirectoryPlaceholder": "选择目录...", + "browseDirectory": "浏览", + "projectPath": "项目将创建在:{path}", + "advancedOptions": "高级选项", + "base": "基础库", + "enableRtl": "启用 RTL 支持", + "enableRtlDescription": "为从右到左书写的语言(如阿拉伯语、希伯来语)启用布局支持", + "pmChecking": "正在检测...", + "pmNotInstalled": "未安装", + "cancel": "取消", + "create": "创建", + "creating": "正在创建项目..." + }, + "toasts": { + "createFailed": "创建项目失败", + "createSuccess": "项目创建成功", + "openWorkspaceFailed": "项目已创建,但无法在工作区中打开" + }, + "errors": { + "directoryExists": "目标目录已存在", + "commandFailed": "项目创建命令执行失败。" + } + }, + "WebServiceSettings": { + "addressSwitchHint": "切换只改变这里显示和打开的地址;服务监听所有网卡,每个地址都可访问。", + "sectionTitle": "Web 服务", + "sectionDescription": "启用后可通过浏览器远程访问 Codeg", + "port": "端口", + "status": "状态", + "autoStart": "自动启动", + "autoStartHint": "Codeg 启动时自动开启 Web 服务", + "running": "运行中", + "stopped": "已停止", + "processing": "处理中...", + "start": "启动", + "stop": "停止", + "startFailed": "启动失败", + "stopFailed": "停止失败", + "saveConfigFailed": "保存 Web 服务设置失败", + "open": "打开", + "hide": "隐藏", + "show": "显示", + "copy": "复制", + "qrcode": "二维码", + "qrcodeTitle": "扫码打开", + "qrcodeHint": "用手机扫描,在浏览器中打开 Codeg", + "addressLabel": "访问地址", + "tokenLabel": "访问 Token", + "tokenHint": "Web 客户端首次访问时需输入此 Token", + "tokenPlaceholder": "留空则自动生成", + "regenerate": "重新生成", + "stalePortOccupiedTitle": "端口 {port} 已被其他进程占用", + "stalePortUnknownTitle": "端口 {port} 状态未知", + "stalePortHint": "在端口释放前 Codeg 无法绑定。可以更换上方的端口,或结束占用该端口的进程。", + "errors": { + "alreadyRunning": "Web 服务已在运行", + "invalidAddress": "主机或端口格式无效", + "portInUse": "端口 {port} 已被占用,请关闭占用该端口的程序或更换其他端口", + "permissionDenied": "权限不足,请使用 1024 以上的端口,或以更高权限运行", + "addressUnavailable": "该地址在本机不可用", + "bindFailed": "绑定地址失败" + } + }, + "DirectoryBrowser": { + "title": "浏览目录", + "pathPlaceholder": "输入目录路径...", + "goHome": "回到主目录", + "navigateUp": "返回上级目录", + "select": "选择", + "cancel": "取消", + "loading": "加载中...", + "emptyDirectory": "此目录为空", + "errorLoadingDir": "加载目录失败", + "permissionDenied": "权限不足" + }, + "ServerFileBrowser": { + "title": "选择服务端文件", + "pathPlaceholder": "输入目录路径...", + "goHome": "回到主目录", + "navigateUp": "返回上级目录", + "select": "选择", + "cancel": "取消", + "loading": "加载中...", + "emptyDirectory": "此目录为空", + "errorLoadingDir": "加载目录失败", + "selectedCount": "已选 {count} 项" + }, + "ChatChannelSettings": { + "loading": "加载中...", + "sectionTitle": "消息渠道", + "sectionDescription": "配置 IM 机器人,接收事件通知和查询编码活动。", + "addChannel": "添加渠道", + "noChannels": "尚未配置任何消息渠道。", + "channelName": "名称", + "channelNamePlaceholder": "我的 Telegram 机器人", + "channelType": "渠道类型", + "lark": "飞书", + "weixin": "微信", + "dailyReport": "每日报告", + "dailyReportTime": "推送时间", + "nameRequired": "请输入渠道名称。", + "tokenRequired": "请输入 Token。", + "chatIdRequired": "请输入 Chat ID。", + "topicMode": "话题群模式", + "topicModeHint": "将 Telegram forum topics 路由为独立 Codeg 会话。Bot 必须加入 forum supergroup,并拥有管理 topics 权限。", + "loadFailed": "加载渠道失败。", + "saveFailed": "保存失败。", + "connectSuccess": "渠道已连接。", + "connectFailed": "连接失败", + "disconnectSuccess": "渠道已断开。", + "disconnectFailed": "断开连接失败。", + "testSuccess": "连接测试通过。", + "testFailed": "连接测试失败", + "deleteSuccess": "渠道已删除。", + "deleteFailed": "删除渠道失败。", + "deleteConfirmTitle": "删除渠道", + "deleteConfirmMessage": "将永久删除该渠道及其消息日志,确定吗?", + "cancel": "取消", + "delete": "删除", + "create": "创建", + "save": "保存", + "channelListTitle": "已配置渠道", + "channelListDescription": "已启用的渠道在服务启动时会自动连接。", + "editChannel": "编辑渠道", + "editSuccess": "渠道已更新。", + "tokenPlaceholderKeep": "留空保持不变", + "weixinScanTitle": "扫码登录", + "weixinScanDescription": "打开微信扫描二维码以连接。", + "weixinQrcodeExpired": "二维码已过期。", + "weixinRefreshQrcode": "刷新二维码", + "weixinWaitingScan": "等待扫码...", + "weixinPollError": "连接不稳定,正在重试...", + "weixinReconnectNotice": "因 iLink 协议限制,每次重新连接后需先主动向机器人发送一条消息,事件触发才会生效。", + "connect": "连接", + "disconnect": "断开", + "test": "测试连接", + "tabs": { + "channels": "渠道", + "commands": "指令", + "events": "事件", + "other": "其他" + }, + "commands": { + "title": "内置指令", + "description": "消息渠道中可用的 Bot 指令。群聊中需 @Bot 才会处理消息。", + "prefixLabel": "指令前缀", + "prefixDescription": "触发 Bot 指令的前缀,1-3 个非字母数字字符(默认 /)。", + "prefixSaved": "指令前缀已保存。", + "prefixSaveFailed": "保存指令前缀失败。", + "prefixInvalid": "前缀必须是 1-3 个非字母数字字符。", + "save": "保存", + "folderDesc": "选择工作目录", + "agentDesc": "选择 AI Agent", + "taskDesc": "创建会话并执行任务", + "sessionsDesc": "列出当前目录的活跃会话", + "resumeDesc": "最近会话 / 恢复指定会话", + "cancelDesc": "取消当前任务", + "approveDesc": "批准 Agent 权限请求", + "denyDesc": "拒绝 Agent 权限请求", + "searchDesc": "按关键词搜索会话", + "todayDesc": "今日活动汇总", + "statusDesc": "渠道连接状态", + "helpDesc": "显示帮助" + }, + "events": { + "title": "事件通知", + "description": "启用事件后,事件被触发时将推送到渠道。", + "turnComplete": "对话完成", + "turnCompleteDesc": "代理回合结束时", + "error": "代理错误", + "errorDesc": "代理遇到错误时", + "permissionRequest": "权限请求", + "permissionRequestDesc": "智能体请求操作权限时", + "questionRequest": "智能体提问", + "questionRequestDesc": "当智能体向你提问时", + "userPromptSent": "用户消息", + "userPromptSentDesc": "当你发送消息时——通知中会包含消息内容", + "saved": "事件过滤已更新。", + "saveFailed": "保存事件过滤失败。", + "loadFailed": "加载设置失败。", + "retry": "重试", + "webhooksTitle": "Webhook", + "webhooksDescription": "事件触发时,向一个或多个地址 POST 一份 JSON。上方的事件过滤同样作用于 Webhook。", + "webhookUrlPlaceholder": "https://example.com/webhook", + "addWebhook": "添加 Webhook", + "removeWebhook": "删除 Webhook", + "webhookSave": "保存", + "webhooksSaved": "Webhook 已保存。", + "webhooksSaveFailed": "保存 Webhook 失败。", + "webhookInvalidUrl": "请输入有效的 http(s) 地址。", + "docsTitle": "请求格式", + "docsMethod": "请求方式", + "docsContentType": "内容类型", + "docsNote": "每个启用的事件都会投递到所有地址。Webhook 不做去抖;上方的事件过滤仍然生效。", + "editWebhook": "编辑 Webhook", + "enableWebhook": "启用 Webhook", + "webhookDuplicate": "该地址已配置。", + "cancel": "取消", + "webhooksEmpty": "尚未配置 Webhook。", + "deleteWebhookTitle": "删除 Webhook", + "deleteWebhookMessage": "删除此 Webhook?事件将不再投递到该地址。", + "delete": "删除" + }, + "language": { + "title": "消息语言", + "description": "事件通知、指令响应和每日报告推送到消息渠道时使用的语言。", + "saved": "消息语言已保存。", + "saveFailed": "保存消息语言失败。", + "en": "英语", + "zh-cn": "简体中文", + "zh-tw": "繁体中文", + "ja": "日语", + "ko": "韩语", + "es": "西班牙语", + "de": "德语", + "fr": "法语", + "pt": "葡萄牙语", + "ar": "阿拉伯语" + } + }, + "ModelProviderSettings": { + "sectionTitle": "模型供应商", + "sectionDescription": "管理 Agent 的 API 供应商凭据。", + "filterAll": "全部", + "providerListTitle": "已配置的供应商", + "addProvider": "添加供应商", + "editProvider": "编辑供应商", + "noProviders": "尚未配置模型供应商。", + "providerName": "名称", + "providerNamePlaceholder": "例如 OpenAI、Anthropic", + "apiUrl": "API 地址", + "apiUrlPlaceholder": "https://api.openai.com/v1", + "apiKey": "API 密钥", + "apiKeyPlaceholder": "sk-...", + "apiKeyKeepCurrent": "留空则保持不变", + "agentTypes": "代理类型", + "agentTypesRequired": "至少选择一个代理类型。", + "agentType": "智能体类型", + "agentTypeRequired": "请选择智能体类型。", + "agentTypeImmutableHint": "智能体类型创建后不可修改。", + "model": "模型", + "modelPlaceholderCodex": "gpt-5.6-sol / gpt-5.5", + "modelPlaceholderGemini": "gemini-3-pro-preview", + "claudeMainModel": "主模型", + "claudeReasoningModel": "推理模型(思考)", + "claudeHaikuDefaultModel": "默认 Haiku 模型", + "claudeSonnetDefaultModel": "默认 Sonnet 模型", + "claudeOpusDefaultModel": "默认 Opus 模型", + "claudeCustomModelOption": "自定义模型 ID", + "claudeCustomModelOptionName": "自定义模型名称", + "claudeCustomModelOptionDescription": "自定义模型描述", + "claudeCustomModelOptionHint": "在 Claude 模型选择器中追加一个自定义条目(例如经自定义网关/代理提供的模型)。名称与描述为可选的显示信息。", + "nameRequired": "供应商名称不能为空。", + "apiUrlRequired": "API 地址不能为空。", + "apiKeyRequired": "API 密钥不能为空。", + "loadFailed": "加载供应商失败。", + "saveFailed": "保存更改失败。", + "createSuccess": "供应商已创建。", + "editSuccess": "供应商已更新。", + "deleteSuccess": "供应商已删除。", + "deleteConfirmTitle": "删除供应商", + "deleteConfirmMessage": "确定要永久删除供应商「{name}」吗?", + "deleteBlockedByAgent": "{agents} 正在使用该配置,请先解除关联后再删除。", + "cancel": "取消", + "delete": "删除", + "create": "创建", + "save": "保存", + "affectedRunningSessions": "{count} 个进行中的会话需重连以应用更改" + }, + "SkillMatrix": { + "loading": "加载中…", + "searchPlaceholder": "按名称、ID 或描述搜索", + "empty": "暂无内容。", + "emptySearch": "没有匹配当前搜索的结果。", + "skillColumn": "技能", + "selectAll": "全选可见项", + "selectSkill": "选择 {name}", + "everything": { + "label": "批量", + "enable": "全部启用(可见)", + "disable": "全部禁用(可见)" + }, + "columnMenu": { + "enableAll": "启用全部技能", + "disableAll": "禁用全部技能" + }, + "rowMenu": { + "label": "对 {name} 批量操作", + "enableAll": "对所有 agent 启用", + "disableAll": "对所有 agent 禁用" + }, + "bulk": { + "selected": "已选择 {count} 项", + "targetAll": "全部 agent", + "targetSome": "{count} 个 agent", + "enable": "启用", + "disable": "禁用", + "clear": "清除" + }, + "confirm": { + "disableTitle": "禁用这些链接?", + "disableBody": "这将移除 {count} 个由 codeg 管理的技能链接。占用自定义目录的技能不受影响。你可以随时重新启用。", + "cancel": "取消", + "confirm": "禁用" + }, + "toasts": { + "loadFailed": "加载技能状态失败", + "applyFailed": "应用更改失败", + "enabled": "已启用 {count} 个链接", + "disabled": "已禁用 {count} 个链接", + "enabledPartial": "已启用 {ok} 个,{failed} 个失败", + "disabledPartial": "已禁用 {ok} 个,{failed} 个失败" + }, + "detail": { + "enableForAgents": "为 agent 启用", + "preview": "SKILL.md 预览", + "loadingContent": "加载内容中…" + }, + "copyModeHint": "已复制(非链接)——更新后请重新启用以获取最新版本" + }, + "ExpertsSettings": { + "title": "专家技能", + "description": "为 AI 编码代理启用精心挑选、经过实战验证的技能工作流。每个专家都是 superpowers 项目中的独立技能 —— codeg 维护中央副本,并将其软链接到你选择的代理目录。", + "loading": "正在加载专家列表…", + "loadingContent": "正在加载内容…", + "emptyExperts": "当前没有可用的专家,请查看应用日志。", + "emptySelection": "从左侧选择一个专家以查看内容并管理启用状态。", + "emptySearch": "没有匹配当前搜索条件的专家。", + "searchPlaceholder": "按名称、ID 或描述搜索专家", + "enableForAgents": "为代理启用", + "noAgents": "未检测到 ACP 代理。", + "copyModeWarning": "已复制(非软链接)。codeg 更新后需要重新启用以获取最新版本。", + "previewTitle": "SKILL.md 预览", + "categories": { + "discovery": "发现与设计", + "planning": "规划", + "execution": "执行", + "quality": "质量与测试", + "debugging": "调试", + "review": "评审与集成", + "meta": "元技能" + }, + "states": { + "not_linked": "未启用", + "linked_to_codeg": "已启用", + "linked_elsewhere": "冲突 — 已有其他链接", + "blocked_by_real_directory": "冲突 — 已有同名的自定义 skill 占用", + "broken": "链接损坏" + }, + "badges": { + "userModified": "用户修改过" + }, + "actions": { + "openCentralDir": "打开中央目录", + "refresh": "刷新" + }, + "toasts": { + "loadFailed": "加载专家详情失败", + "enabled": "已为该代理启用专家", + "disabled": "已为该代理禁用专家", + "enableFailed": "启用专家失败", + "disableFailed": "禁用专家失败", + "openFolderFailed": "打开目录失败" + } + }, + "ScienceSettings": { + "title": "科学研究技能", + "description": "为你的 AI 编码智能体启用精选的科学研究技能:假设生成、实验设计、统计、可视化、批判性评估与文献检索。codeg 管理中央副本,并将每个技能链接到你选择的智能体。", + "loading": "正在加载科学研究技能…", + "emptySkills": "没有可用的科学研究技能。请检查应用日志。", + "searchPlaceholder": "按名称、ID 或描述搜索科学研究技能", + "categories": { + "ideation": "构思", + "design": "研究设计", + "analysis": "分析", + "visualization": "可视化", + "evaluation": "评估", + "literature": "文献" + }, + "states": { + "not_linked": "未启用", + "linked_to_codeg": "已启用", + "linked_elsewhere": "冲突 — 已有其他链接", + "blocked_by_real_directory": "冲突 — 已有同名的自定义 skill 占用", + "broken": "链接损坏" + }, + "badges": { + "userModified": "用户修改过", + "needsKey": "需要密钥", + "needsSetup": "可能需环境" + }, + "actions": { + "openCentralDir": "打开中央目录", + "refresh": "刷新" + }, + "toasts": { + "openFolderFailed": "打开目录失败" + } + }, + "OfficeToolsSettings": { + "title": "Office 工具", + "description": "管理 OfficeCLI 技能,用于创建 Excel、Word 和 PowerPoint 文件。安装 OfficeCLI,同步技能,并为每个智能体启用。", + "loadingContent": "加载内容中…", + "emptySkills": "暂无技能。请先安装 OfficeCLI 并同步技能。", + "emptySelection": "选择一个技能查看内容和管理激活状态。", + "emptySearch": "没有匹配的技能。", + "searchPlaceholder": "按名称、ID 或描述搜索技能", + "enableForAgents": "为智能体启用", + "noAgents": "未检测到 ACP 智能体。", + "installFirst": "请先安装 OfficeCLI 以启用技能。", + "syncFirst": "请先同步技能以加载内容。", + "noContent": "暂无内容。", + "copyModeWarning": "已复制(非链接)。重新同步以获取最新版本。", + "previewTitle": "SKILL.md 预览", + "detection": { + "installed": "已安装", + "notInstalled": "未安装", + "notRunnable": "已安装但无法运行", + "installHint": "安装 OfficeCLI 以为 AI 智能体启用办公文档生成技能。", + "install": "安装", + "uninstall": "卸载", + "syncSkills": "同步技能" + }, + "categories": { + "general": "通用", + "presentations": "演示文稿", + "documents": "文档", + "spreadsheets": "电子表格" + }, + "states": { + "not_linked": "未启用", + "linked_to_codeg": "已启用", + "linked_elsewhere": "已阻止——存在其他链接", + "blocked_by_real_directory": "已阻止——自定义技能占用此名称", + "broken": "链接已损坏" + }, + "badges": { + "notSynced": "未同步" + }, + "actions": { + "refresh": "刷新" + }, + "toasts": { + "loadFailed": "加载技能详情失败", + "enabled": "已为此智能体启用技能", + "disabled": "已为此智能体禁用技能", + "enableFailed": "启用技能失败", + "disableFailed": "禁用技能失败", + "installSuccess": "OfficeCLI 安装成功", + "installFailed": "安装 OfficeCLI 失败", + "uninstallSuccess": "OfficeCLI 已卸载", + "uninstallFailed": "卸载 OfficeCLI 失败", + "syncSuccess": "已成功同步 {synced} 个技能", + "syncPartial": "已同步 {synced} 个技能,{errors} 个失败", + "syncFailed": "同步技能失败" + }, + "autoPreviewLabel": "自动打开预览", + "autoPreviewHint": "当智能体创建或编辑 Word、Excel、PowerPoint 文件时,自动打开其实时预览。" + }, + "SkillPacksSettings": { + "title": "技能包", + "description": "由 codeg 集中管理、并链接到各 AI 智能体的成套技能——编码专家、科学研究与办公文档工具。可在下方按智能体分别启用。", + "tabs": { + "experts": "专家", + "science": "科学研究", + "office": "办公工具", + "custom": "自定义" + }, + "actions": { + "openCentralDir": "打开中央目录", + "refresh": "刷新" + }, + "toasts": { + "openFolderFailed": "打开目录失败" + } + }, + "QuickMessagesSettings": { + "title": "快捷消息", + "description": "管理可复用的消息片段。拖拽以调整顺序。", + "loading": "加载快捷消息…", + "emptyList": "暂无快捷消息。点击“新建”创建一条。", + "emptySelection": "选择一条快捷消息进行编辑。", + "searchPlaceholder": "按标题或内容搜索", + "untitled": "未命名", + "actions": { + "new": "新建", + "save": "保存", + "delete": "删除", + "dragSort": "拖拽排序", + "dragSortMessage": "拖拽排序快捷消息:{name}" + }, + "fields": { + "title": "标题", + "titlePlaceholder": "为此消息取一个简短的标题", + "content": "内容", + "contentPlaceholder": "在此输入消息内容" + }, + "confirmDelete": { + "title": "删除快捷消息?", + "message": "将永久删除“{name}”。确定吗?", + "cancel": "取消", + "confirm": "删除" + }, + "toasts": { + "loadFailed": "加载快捷消息失败", + "createFailed": "创建快捷消息失败", + "saveFailed": "保存快捷消息失败", + "deleteFailed": "删除快捷消息失败", + "saveOrderFailed": "保存顺序失败", + "created": "已创建快捷消息", + "saved": "已保存快捷消息", + "deleted": "已删除快捷消息" + } + }, + "Pet": { + "badge": { + "running": "{count} 个运行中", + "waiting": "{count} 个待批准", + "error": "{count} 个出错" + }, + "panel": { + "title": "活动会话", + "empty": "没有活动会话", + "emptyHint": "正在运行或需要你处理的会话会显示在这里。", + "statusRunning": "运行中", + "statusWaiting": "等待中", + "statusError": "出错", + "subAgentOf": "子智能体" + }, + "menu": { + "scale": "缩放", + "openManager": "管理宠物", + "close": "关闭" + }, + "loadError": "加载宠物失败", + "missingPetIdParam": "未选中任何宠物", + "summonButton": "宠物", + "manager": { + "title": "桌面宠物", + "description": "悬浮在桌面上的伴侣,使用与 Codex 兼容的精灵图。", + "addPet": "添加宠物", + "importFromCodex": "从 Codex 导入", + "noPets": "暂无宠物。可以添加一只,或从 Codex 导入。", + "setActive": "设为活跃", + "active": "当前活跃", + "edit": "编辑", + "delete": "删除", + "deleteConfirm": "确认删除宠物 \"{name}\" 吗?会从磁盘上一并移除。", + "summon": "召唤宠物窗口", + "openCodexHelp": "Codex 宠物需位于 ~/.codex/pets/ 目录下,但未找到。", + "specRequirement": "精灵图宽度必须为 1536 像素,高度需为 208 像素的整数倍(如 1872 或 2288),并为带透明通道的 PNG 或 WebP。", + "form": { + "id": "宠物 ID", + "idHelp": "仅允许小写字母、数字、'-' 和 '_',最多 64 字符。", + "displayName": "显示名称", + "description": "描述 (可选)", + "spritesheet": "精灵图", + "chooseFile": "选择文件", + "replaceFile": "替换精灵图", + "saveCreate": "添加宠物", + "saveUpdate": "保存修改", + "cancel": "取消" + }, + "errors": { + "missingId": "宠物 ID 不能为空", + "missingName": "显示名称不能为空", + "missingSpritesheet": "必须选择一个精灵图", + "addFailed": "添加宠物失败", + "updateFailed": "更新宠物失败", + "deleteFailed": "删除宠物失败", + "loadFailed": "加载宠物列表失败", + "setActiveFailed": "设置活跃宠物失败", + "summonFailed": "召唤宠物窗口失败" + } + }, + "import": { + "title": "从 Codex 导入", + "subtitle": "在 ~/.codex/pets/ 下找到以下可导入的宠物。", + "selectAll": "全选", + "alreadyImported": "已导入", + "renameOnConflict": "冲突时自动添加 -imported 后缀", + "import": "导入所选", + "noneFound": "未找到可导入的 Codex 宠物。", + "imported": "导入完成", + "failed": "导入失败", + "close": "关闭" + }, + "marketplace": { + "openMarketplace": "宠物市场", + "title": "宠物市场", + "search": "搜索宠物", + "kindFilter": { + "all": "全部", + "object": "物品", + "animal": "动物", + "person": "人物", + "creature": "生物" + }, + "sortFilter": { + "latest": "最新", + "popular": "热门", + "views": "最多浏览" + }, + "refresh": "刷新", + "install": "安装", + "installing": "安装中", + "reinstall": "替换重装", + "reinstallConfirm": "确认覆盖本地宠物 \"{name}\" 吗?现有数据将被替换。", + "cancel": "取消", + "stats": { + "views": "浏览", + "downloads": "下载", + "likes": "点赞" + }, + "actions": { + "idle": "待机", + "running_right": "右跑", + "running_left": "左跑", + "waving": "挥手", + "jumping": "跳跃", + "failed": "失败", + "waiting": "等待", + "running": "运行", + "review": "评审" + }, + "page": "第 {page} / {total} 页", + "prev": "上一页", + "next": "下一页", + "empty": "没有匹配的宠物。", + "successInstalled": "已安装 \"{name}\"", + "errors": { + "loadFailed": "加载市场失败", + "installFailed": "安装失败", + "alreadyInstalled": "该宠物已存在" + } + } + }, + "RemoteWorkspace": { + "openRemoteWorkspace": "打开远端工作区", + "manage": "管理远端工作区", + "manageTitle": "远端工作区连接", + "empty": "暂无远端连接", + "searchPlaceholder": "搜索远端工作区", + "orderFailed": "保存远端工作区排序失败", + "dragSort": "拖拽排序", + "dragSortConnection": "拖拽排序 {name}", + "newConnection": "新建连接", + "loading": "加载中", + "loadingConnection": "正在加载远端连接", + "name": "名称", + "baseUrl": "服务地址", + "token": "访问 Token", + "save": "保存", + "delete": "删除", + "confirmDelete": { + "title": "删除远端连接?", + "message": "这会从当前设备移除“{name}”,此操作不可撤销。", + "cancel": "取消", + "confirm": "删除" + }, + "saved": "远端连接已保存。", + "deleted": "远端连接已删除。", + "loadFailed": "加载远端连接失败", + "saveFailed": "保存远端连接失败", + "deleteFailed": "删除远端连接失败", + "openFailed": "打开远端工作区失败", + "connectionLoadFailed": "加载远端连接失败:{message}", + "connectionExpired": "远端连接“{name}”已失效。请更新 Token 后重新加载此窗口。" + }, + "BackupSettings": { + "title": "备份与恢复", + "description": "导出一份可移植的 codeg 数据备份,或从备份中恢复。", + "tabs": { + "backup": "备份", + "restore": "恢复" + }, + "export": { + "includeExternal": "包含会话内容", + "includeExternalHint": "同时打包各 CLI 的会话记录(Claude、Codex、Gemini 等),体积更大。", + "passphrase": "口令(可选)", + "passphrasePlaceholder": "留空则生成未加密的归档", + "passphraseConfirm": "确认口令", + "passphraseMismatch": "两次输入的口令不一致。", + "noPassphraseWarning": "该备份将以明文包含密钥(API key、token)。请妥善保管。", + "passphraseLossWarning": "将使用此口令加密。口令一旦丢失,备份将无法恢复。", + "button": "导出备份", + "inProgress": "正在创建备份…", + "success": "备份已创建。", + "started": "已开始下载备份。" + }, + "restore": { + "selectFile": "选择备份文件", + "passphrasePrompt": "该备份已加密,请输入其口令。", + "unlock": "解锁", + "preview": { + "title": "备份详情", + "encrypted": "已加密", + "compatible": "兼容", + "incompatible": "不兼容", + "createdAt": "创建时间:{value}", + "appVersion": "应用版本:{value}", + "incompatibleHint": "该备份由更新版本的 codeg 创建,无法恢复。" + }, + "replaceWarning": "恢复将替换当前全部 codeg 数据(数据库与上传文件)。当前数据会先做快照以便回退。", + "keyringNote": "桌面端的 GitHub/聊天 token 存于系统钥匙串,不包含在备份中;恢复后需重新填写。", + "button": "恢复", + "staging": "正在准备恢复…", + "staged": "恢复已就绪,正在重启…", + "restarting": "恢复已就绪,正在重启服务…", + "restartTimeout": "服务未能及时恢复。待其启动后请刷新页面。", + "externalSideLocation": "会话记录已恢复到 {path}", + "confirmTitle": "替换全部数据?", + "confirmBody": "这将用备份替换当前的 codeg 数据库与上传文件,然后重启。当前数据会先做快照。", + "cancel": "取消", + "confirmAction": "替换并重启", + "external": { + "title": "会话内容", + "hint": "该备份包含各 CLI 的会话记录。请选择恢复到何处。", + "modeSkip": "不恢复", + "modeSide": "恢复到安全的旁路目录", + "modeOriginal": "恢复到 CLI 的原始位置", + "forceOverwrite": "覆盖已存在的文件", + "forceOverwriteHint": "替换 CLI 目录中已存在的文件。", + "scanning": "正在检查冲突…", + "noConflicts": "不会覆盖任何已存在的文件。", + "conflictCount": "将影响 {count} 个已存在的文件。", + "conflictSkipNote": "未启用覆盖时,已存在的文件将被保留(跳过)。" + }, + "restartFailed": "恢复已就绪,但服务未能重启。请手动重启以应用此次恢复。" + }, + "remoteUnsupported": "备份与恢复作用于运行 codeg 的那台机器上的数据。你当前连接的是远程工作区——请直接在该服务器上管理其备份。" + }, + "backup": { + "restore": { + "error": { + "badPassphrase": "口令错误或备份已损坏。", + "corrupted": "备份归档已损坏。", + "unknownFormat": "该文件不是可识别的 codeg 备份。", + "newerVersion": "该备份由 codeg {backupVersion} 创建,比当前版本({appVersion})更新。", + "alreadyPending": "已有一个恢复在等待生效。请先重启应用它,再暂存新的恢复。" + } + }, + "error": { + "diskSpace": "磁盘空间不足,无法完成操作。", + "cancelled": "操作已取消。" + } + }, + "WebConnection": { + "disconnectedTitle": "连接已断开", + "reconnectingDescription": "正在尝试重新连接服务器,通常会在几秒内自动恢复。", + "reconnectNow": "立即重连", + "sessionExpiredTitle": "会话已过期", + "sessionExpiredDescription": "登录状态已失效,请重新登录以继续。", + "goToLogin": "前往登录" + }, + "LiveFeedback": { + "placeholder": "在 {agent} 工作时给它留言…", + "agentFallback": "智能体", + "ariaLabel": "实时反馈留言", + "dialogTitle": "实时反馈", + "dialogDescription": "在智能体工作时给它留言。它会在下次检查时读取,不会打断当前步骤。", + "dialogDescriptionInstant": "在智能体工作时给它发一条备注。备注会立即插入当前回合——智能体马上就能看到。", + "channelDowngraded": "本会话无法即时插入——备注已保存,等智能体下次检查时读取。", + "send": "发送", + "cancel": "取消", + "pending": "等待中", + "delivered": "已收到", + "turnEndedUnread": "智能体在读取你的反馈前已结束本轮。", + "sendAsMessage": "作为新消息发送", + "dismiss": "忽略", + "turnEndedResent": "本轮已结束——已改为作为新消息发送。", + "turnEnded": "本轮已结束。", + "submitFailed": "留言发送失败" + }, + "AgentToolsSettings": { + "title": "会话内工具", + "description": "codeg 在会话中额外提供给智能体的工具。工具在智能体启动时注入,改动只对之后启动的智能体生效。", + "feedbackLabel": "实时反馈", + "feedbackHint": "在智能体工作时向它发送备注与纠偏。支持即时插入的智能体会立刻在当前回合中看到你的备注;其他智能体则通过检查反馈的工具读取——这类智能体通常只有在提示词里提到时才会检查,例如在消息中加上“定期检查我的实时反馈”。", + "questionLabel": "向用户提问", + "questionHint": "允许智能体暂停并向你提出多选问题,问题会显示在会话输入框上方。智能体会一直等待,直到你作答(或跳过)。", + "sessionInfoLabel": "获取会话信息", + "sessionInfoHint": "允许智能体查询你在消息中提及的会话(会话徽章),读取其标题、智能体、状态、工作区、Token 用量和最近消息。", + "automationsLabel": "创建自动化", + "automationsHint": "把对话保存为按计划运行的自动化。默认关闭——它之后会自行启动智能体。", + "workTasksLabel": "创建待办任务", + "workTasksHint": "从对话中往待办看板排一张任务卡。默认关闭——它会写入应用状态。", + "save": "保存", + "saving": "保存中…", + "saved": "工具设置已保存", + "saveFailed": "保存工具设置失败", + "loadFailed": "加载失败:{detail}" + }, + "NotificationSoundSettings": { + "title": "提示音", + "description": "智能体事件触发时播放一段简短的提示音。这里的事件与消息渠道推送的完全一致,但设置只对本设备生效。", + "enableHint": "默认关闭。提示音只在当前浏览器或应用的工作区窗口中播放。", + "volume": "音量", + "preview": "试听", + "previewEvent": "试听「{event}」提示音", + "onlyWhenUnfocused": "仅在窗口未聚焦时播放", + "onlyWhenUnfocusedHint": "正在查看 Codeg 时保持静音。", + "eventsTitle": "事件", + "eventsHint": "为每个事件选择一种音效,选择「静音」则不播放。同一事件在数秒内重复触发时只播放一次。", + "toneNone": "静音", + "toneChime": "叮咚", + "toneDing": "清铃", + "toneBlip": "短音", + "tonePop": "轻点", + "toneAlert": "警示", + "toneDescend": "下行音" + }, + "LogsSettings": { + "loading": "加载中…", + "sectionTitle": "运行日志", + "sectionDescription": "查看和配置应用诊断日志。日志会写入本地文件,并保留在内存中以便实时查看。", + "captureTitle": "日志级别", + "captureDescription": "控制记录的详细程度。级别越高(Debug、Trace)记录越多,但日志也越大。“关闭”将停止记录日志。", + "captureLabel": "采集级别", + "levels": { + "off": "关闭", + "error": "错误", + "warn": "警告", + "info": "信息", + "debug": "调试", + "trace": "跟踪" + }, + "viewerTitle": "最近日志", + "viewerDescription": "实时查看最近的日志记录。可按级别筛选或搜索文本。", + "searchPlaceholder": "搜索消息或来源…", + "viewLevels": { + "all": "全部级别", + "error": "错误及以上", + "warn": "警告及以上", + "info": "信息及以上", + "debug": "调试及以上", + "trace": "跟踪及以上" + }, + "pause": "暂停", + "resume": "实时", + "refresh": "刷新", + "clear": "清空", + "openFolder": "打开文件夹", + "shownCount": "已显示 {shown} / {total}", + "empty": "暂无日志。", + "levelSaveFailed": "保存日志级别失败", + "openFolderFailed": "打开日志文件夹失败", + "downloadFailed": "下载日志文件失败", + "filesTitle": "日志文件", + "filesDescription": "从磁盘下载完整日志文件,查看实时缓冲区之外的历史记录。", + "filesEmpty": "暂无日志文件。", + "download": "下载", + "downloadTruncated": "文件较大,已下载最新的 {size}。完整文件请在日志目录中查看。", + "captureEnvLocked": "日志级别由 RUST_LOG / CODEG_LOG 环境变量控制;请在该处修改以生效。", + "targetsTitle": "按模块覆盖", + "targetsDescription": "为特定模块(如 codeg_lib::acp)单独设置级别,不影响全局级别。", + "targetsAdd": "添加", + "targetsRemove": "移除覆盖", + "toggleDetails": "切换详情" + }, + "Automations": { + "title": "自动化", + "new": "新建自动化", + "empty": "暂无自动化", + "emptyHint": "创建一个,让智能体按计划或手动执行任务。", + "name": "名称", + "namePlaceholder": "例如:每晚 PR 审查", + "prompt": "提示词", + "promptPlaceholder": "让智能体做什么?", + "agent": "智能体", + "folder": "工作区文件夹", + "folderPlaceholder": "选择文件夹", + "isolation": "隔离方式", + "isolationWorktree": "每次运行新建 worktree", + "isolationShared": "在文件夹内运行", + "isolationSharedCaveat": "运行会直接使用该文件夹的工作树,可能与你未提交的改动冲突。勾选每次运行新建工作树以隔离每次运行。", + "trigger": "触发方式", + "triggerSchedule": "按计划", + "triggerManual": "仅手动", + "cron": "计划(cron)", + "cronPlaceholder": "0 9 * * 1-5", + "timezone": "时区", + "nextRun": "下次运行", + "branch": "分支", + "branchOptional": "分支(可选)", + "enabled": "已启用", + "save": "保存", + "cancel": "取消", + "edit": "编辑", + "delete": "删除", + "runNow": "立即运行", + "cancelRun": "取消运行", + "runHistory": "运行历史", + "noRuns": "暂无运行记录", + "allFolders": "所有文件夹", + "filterAll": "全部", + "noMatches": "没有匹配的自动化", + "viewConversation": "查看会话", + "lastRun": "上次运行", + "never": "从未", + "running": "运行中", + "deleteTitle": "删除此自动化?", + "deleteDescription": "这将删除该自动化及其计划。运行历史会保留。", + "statusRunning": "运行中", + "statusSucceeded": "成功", + "statusFailed": "失败", + "statusCancelled": "已取消", + "statusSkipped": "已跳过", + "errorName": "名称必填", + "errorPrompt": "提示词必填", + "errorCron": "按计划的自动化需要 cron 表达式", + "errorFolder": "请选择工作区文件夹", + "presetHourly": "每小时", + "presetDaily": "每天 9 点", + "presetWeekdays": "工作日 9 点", + "presetCustom": "自定义", + "probing": "正在加载选项…", + "retry": "重试", + "configNone": "该智能体没有可配置项", + "inherit": "智能体默认", + "mode": "模式", + "config": "配置", + "branchPlaceholder": "(默认分支)", + "selectHint": "选择一个自动化以查看详情", + "refresh": "刷新", + "onboardTitle": "自动化日常智能体任务", + "onboardHint": "安排智能体定时或按需审查代码、更新依赖或处理问题。", + "headerSubtitle": "定时与按需的智能体任务", + "startFromTemplate": "从模板开始", + "blankTitle": "空白自动化", + "blankDesc": "从零配置一个智能体任务。", + "backToTemplates": "模板", + "sectionSchedule": "计划与目标", + "sectionTarget": "运行目标", + "sectionAction": "动作", + "actionLaunchSession": "启动会话", + "actionEnqueueTask": "任务入队", + "actionEnqueueTaskHint": "每次触发都会在目标文件夹的待办任务里加入一个待办任务(标题为本自动化名称),由任务引擎按看板设置执行。", + "sectionPrompt": "提示词", + "nextIn": "{rel}后运行", + "manual": "手动", + "schedEveryMinutes": "每 {n} 分钟", + "schedHourly": "每小时", + "schedDaily": "每天 {time}", + "schedWeekdays": "工作日 {time}", + "schedWeekly": "每{day} {time}", + "schedMonthly": "每月 {day} 日 {time}", + "dow0": "周日", + "dow1": "周一", + "dow2": "周二", + "dow3": "周三", + "dow4": "周四", + "dow5": "周五", + "dow6": "周六", + "tplCodeReviewTitle": "代码审查", + "tplCodeReviewDesc": "审查最近的改动,查找缺陷、回归和质量问题。", + "tplDependencyUpdatesTitle": "依赖更新", + "tplDependencyUpdatesDesc": "查找过时的依赖并提出安全的升级方案。", + "tplTestCoverageTitle": "测试覆盖", + "tplTestCoverageDesc": "找出未覆盖的代码路径并补充缺失的测试。", + "tplTodoSweepTitle": "TODO 清理", + "tplTodoSweepDesc": "收集 TODO 和 FIXME 注释并按优先级整理。", + "tplCiTriageTitle": "CI 排查", + "tplCiTriageDesc": "排查最近失败的检查并提出修复方案。", + "tplReleaseNotesTitle": "发布说明", + "tplReleaseNotesDesc": "汇总自上次发布以来的改动,生成更新日志。", + "tplSecurityAuditTitle": "安全审计", + "tplSecurityAuditDesc": "扫描漏洞和风险模式,并报告发现的问题。", + "enable": "启用", + "disable": "停用", + "moreActions": "更多操作", + "statusDisabled": "已停用", + "cronBuilderTitle": "计划生成器", + "cronFreqLabel": "频率", + "cronFreqMinutes": "每 N 分钟", + "cronFreqHourly": "每小时", + "cronFreqDaily": "每天", + "cronFreqWeekdays": "工作日", + "cronFreqWeekly": "每周", + "cronFreqMonthly": "每月", + "cronFreqCustom": "自定义", + "cronEveryLabel": "间隔(分钟)", + "cronTimeLabel": "时间", + "cronHourLabel": "小时", + "cronMinuteLabel": "分钟", + "cronDowLabel": "星期", + "cronDomLabel": "日期", + "cronApply": "应用", + "cronPreviewLabel": "预览", + "cronOpenBuilder": "打开计划生成器", + "branchDefault": "默认分支", + "branchUseCustom": "使用 “{query}”", + "branchLocal": "本地", + "branchRemote": "远程", + "branchSearchPlaceholder": "搜索分支…", + "branchNone": "无分支" + }, + "Tasks": { + "title": "待办任务", + "new": "新建任务", + "empty": "还没有任务", + "emptyHint": "添加待办后即可处理——agent 在独立 worktree 中工作,你验收并合并结果。", + "emptyColTodo": "还没有待办任务", + "emptyColInProgress": "暂无进行中的任务", + "emptyColAttention": "暂无等你处理的任务", + "emptyColDone": "还没有已完成的任务", + "allFolders": "全部文件夹", + "showCanceled": "显示已取消", + "showArchived": "显示已归档", + "filter": "筛选", + "viewSwitchToBoard": "切换到看板视图", + "viewSwitchToList": "切换到列表视图", + "statusFilter": "状态", + "statusFilterAll": "全部状态", + "listEmpty": "没有符合当前筛选条件的任务", + "listColStatus": "状态", + "listColTask": "任务", + "listColLocation": "位置", + "listColChanges": "变更", + "listColUpdated": "更新", + "colTodo": "待办", + "colInProgress": "进行中", + "colAttention": "等你处理", + "colDone": "已完成", + "statusTodo": "待办", + "statusQueued": "排队中", + "statusPreparing": "初始化中", + "statusRunning": "进行中", + "statusAwaitingInput": "等待输入", + "statusReview": "待验收", + "statusMerging": "合并中", + "statusDone": "已完成", + "statusFailed": "失败", + "statusCanceled": "已取消", + "statusInterrupted": "已中断", + "badgeCleanupFailed": "清理失败", + "badgeWorktreeKept": "保留 worktree", + "badgeWorktreeRemoved": "Worktree 已删除", + "filesChanged": "{count} 个文件", + "actionStart": "开始", + "actionSchedule": "定时运行", + "actionCancel": "取消", + "actionRetry": "重试", + "actionRequeue": "重新排队", + "actionViewSession": "查看会话", + "actionEdit": "编辑", + "actionDelete": "删除", + "actionRetryCleanup": "重试清理", + "actionMerge": "合并", + "actionUnqueueMerge": "取消排队", + "actionEditQueuedMerge": "修改排队的合并", + "badgeMergeQueued": "排队合并中", + "badgeMergeQueuedRank": "排队合并 · 第 {rank} 位", + "badgeMergeQueuedHint": "正在等待该项目当前的合并完成,轮到时会自动开始。", + "actionComplete": "完成", + "actionAbandon": "放弃", + "cancelTitle": "取消任务?", + "cancelDescription": "任务将变为已取消。worktree 会保留,之后可以重新排队。", + "cancelReasonLabel": "取消原因(可选)", + "cancelReasonPlaceholder": "例如:方向不对,我重写一下任务描述", + "cancelKeep": "先不取消", + "cancelSubmit": "取消任务", + "restartTitleRetry": "重试任务", + "restartTitleRequeue": "重新排队", + "restartDescription": "可以补充一段说明(可选),它会随下一轮的提示词一起发给 agent。", + "scheduleTitle": "定时运行任务", + "scheduleDescription": "任务留在「待办」,到点自动开始。文件夹的并发上限依然生效。", + "scheduleDateLabel": "日期", + "schedulePickDate": "选择日期", + "scheduleTimeLabel": "时间", + "schedulePreview": "{time} 运行", + "schedulePastHint": "该时间已过——保存后会立即开始。", + "scheduleInAnHour": "1 小时后", + "scheduleInThreeHours": "3 小时后", + "scheduleTomorrow": "明天 9:00", + "scheduleClear": "清除定时", + "scheduleBadge": "计划于 {time} 开始", + "toastScheduled": "已定时:{time}", + "toastScheduleCleared": "已清除定时", + "actionFollowUp": "继续处理", + "actionAddNote": "补充说明", + "followUpSubmit": "发送", + "followUpIntentRevise": "修改返工", + "followUpIntentContinue": "继续推进", + "followUpIntentQuestion": "提问答疑", + "followUpIntentVerify": "自查验证", + "followUpPlaceholderRevise": "希望 agent 改哪里?会在同一会话里继续。", + "followUpPlaceholderContinue": "接下来还要做什么?已有的工作会保留。", + "followUpPlaceholderQuestion": "想了解什么?agent 只回答,不会改动任何文件。", + "followUpPlaceholderVerify": "可选:有什么想让它重点检查的?", + "followUpPlaceholderRetry": "可选:这次要怎么做才不一样?例如:先跑 pnpm install", + "followUpPlaceholderRequeue": "可选:当时为什么取消?这次要注意什么?", + "actionArchive": "归档", + "actionUnarchive": "取消归档", + "archiveAllDone": "全部归档", + "dropToStart": "松开即开始执行", + "errorView": "查看", + "notifyReview": "待验收:{title}", + "notifyFailed": "任务失败:{title}", + "createFromMessage": "由此消息创建任务", + "detailTokens": "总 token 用量", + "editorTitleNew": "新建任务", + "editorTitleEdit": "编辑任务", + "templates": "模板", + "templatesEmpty": "还没有模板。", + "templateSaveCurrent": "把当前内容存为模板", + "templateDelete": "删除模板", + "transcriptTitle": "任务会话", + "transcriptDescription": "任务智能体会话的只读实时视图。", + "phaseWork": "任务执行", + "phaseRetry": "重试执行", + "phaseReturn": "继续处理", + "phaseMerge": "合并变更", + "titleLabel": "标题", + "titlePlaceholder": "要做什么?", + "promptLabel": "任务描述", + "promptPlaceholder": "向 agent 描述任务——输入 @ 可引用文件,/ 可唤起命令", + "folderPlaceholder": "选择文件夹", + "agentInheritedHint": "继承自任务设置,修改后仅对本任务生效", + "agentOverrideReset": "恢复继承", + "sectionTarget": "目标", + "errorTitle": "请输入标题", + "errorPrompt": "请输入任务描述", + "errorFolder": "请选择文件夹", + "save": "保存", + "cancel": "取消", + "mergeTitle": "合并任务", + "mergeQueuedTitle": "排队中的合并", + "mergeQueueHint": "该项目正在合并另一个任务。此任务会加入队列,等前一个完成后自动开始。", + "mergeQueueUpdateHint": "该任务已在合并队列中。提交将更新它的合并选项,并保留原有的排队位置。", + "mergeDescription": "将 {branch} 合并到 {base}。worktree 中未提交的变更会先自动提交。", + "mergeMessage": "提交信息", + "mergeMessagePlaceholder": "例如 feat: add login validation", + "mergeAutoMessage": "让 agent 自动生成提交信息", + "strategySquash": "合并为一条提交", + "strategySquashHint": "任务的所有修改压缩成一条提交记录并入主分支,历史更简洁。", + "strategyMerge": "保留完整提交历史", + "strategyMergeHint": "保留任务过程中的每一条提交,另加一条合并记录,每一步都可追溯。", + "mergeDeleteWorktree": "合并后删除 worktree", + "mergeSubmit": "合并", + "mergeSubmitQueue": "加入合并队列", + "mergeQueuedToast": "已加入合并队列,等当前合并完成后自动开始。", + "completeTitle": "完成任务", + "completeDescription": "该任务没有改动任何文件,无需合并,将直接标记为已完成。", + "completeDescriptionNoWorktree": "该任务的 worktree 已被删除,无法再合并,将直接标记为已完成。若工作分支上仍有未合并的提交,分支会被保留。", + "completeDeleteWorktree": "完成后删除 worktree", + "completeSubmit": "完成", + "settingsTitle": "任务设置", + "settingsDescription": "{folder} 中任务的默认配置。", + "settingsScope": "作用域", + "settingsScopeGlobal": "全部文件夹(全局默认)", + "settingsScopeGlobalHint": "未单独设置的文件夹将使用这份全局默认配置。", + "settingsSource": "配置来源", + "settingsSourceGlobal": "使用全局默认", + "settingsSourceCustom": "单独配置", + "settingsSourceGlobalFollow": "跟随全局任务设置,全局改动会自动生效。", + "settingsSourceCustomHint": "为此文件夹保存独立设置,不再跟随全局默认。", + "settingsAgent": "默认 agent", + "settingsMaxConcurrent": "最大并发任务数", + "settingsMaxConcurrentHint": "0 表示不限制", + "settingsAutoProcess": "自动处理", + "settingsAutoProcessHint": "待办任务自动开始处理,受并发上限约束。", + "settingsMergeStrategy": "默认合并策略", + "settingsMergeStrategyHint": "合并任务时,这些修改在分支历史里如何记录。", + "settingsAutoMerge": "自动合并", + "settingsAutoMergeHint": "任务进入待验收且有可合并改动时自动落地,与点击「合并」相同:提交信息由 agent 自动生成,是否删除 worktree 沿用下方默认。预检未通过或合并失败的任务会留下等你处理。", + "settingsDeleteWorktree": "合并后删除 worktree", + "settingsDeleteWorktreeHint": "合并对话框里默认勾选,仍可临时改。", + "settingsWorktreeRoot": "Worktree 位置", + "settingsWorktreeRootHint": "新任务的 worktree 创建在该目录下,每个任务一个。留空则创建在项目文件夹的同级目录;「~」表示主目录,相对路径相对于项目文件夹。", + "settingsWorktreeRootPlaceholder": "~/codeg-worktrees", + "settingsWorktreeRootBrowse": "选择 worktree 目录", + "settingsPreflight": "预检命令", + "settingsPreflightHint": "任务进入待验收时在 worktree 中运行。", + "settingsPreflightCustomPlaceholder": "pnpm test", + "settingsInitCommand": "Worktree 初始化命令", + "settingsInitCommandHint": "新建 worktree 后、会话开始前执行。", + "settingsInitCommandPlaceholder": "pnpm install", + "settingsTabGeneral": "常规", + "settingsTabMerge": "合并", + "settingsTabWorktree": "Worktree", + "settingsTabPrompts": "提示词", + "settingsPromptsIntro": "每个阶段都已内置固定的提示词——任务本身、worktree 规则,合并阶段还包含具体的 git 步骤。这里填的内容会作为补充说明追加到末尾:只是对内置提示词的细化,不会替换它们。", + "settingsPromptStageAll": "全部阶段", + "settingsPromptPlaceholderAll": "例如:遵循 AGENTS.md 里的项目约定;始终用中文回复", + "settingsPromptPlaceholderWork": "例如:先读相关测试;小步提交,边做边交", + "settingsPromptPlaceholderRetry": "例如:先看清楚已经提交了哪些改动再继续,别重做已完成的部分", + "settingsPromptPlaceholderReturn": "例如:逐条处理提到的每一点;不要顺手重构无关代码", + "settingsPromptPlaceholderMerge": "例如:最终合并的提交信息用中文;手动解决过的冲突要单独说明", + "settingsPromptHintAll": "追加到每一次发给 agent 的提示词,包括合并那一轮。", + "settingsPromptHintWork": "任务首次执行时追加。", + "settingsPromptHintRetry": "重试被中断或失败的任务时追加。", + "settingsPromptHintReturn": "对待验收的任务继续处理时追加(返工、追加工作、自查)。", + "settingsPromptHintMerge": "agent 把任务合并到基线分支时追加。", + "preflightPassed": "{name} 通过", + "preflightFailed": "{name} 未通过", + "preflightRunning": "{name} 运行中…", + "detailDescription": "任务详情", + "detailSummary": "结果", + "detailFiles": "变更文件", + "detailDiffAll": "查看全部差异", + "detailDiffAllTitle": "全部差异", + "detailNoChanges": "相对基准还没有变更", + "detailTimeline": "推进记录", + "detailTimelineEmpty": "暂无活动", + "showMore": "展开", + "showLess": "收起", + "detailInfo": "详情", + "detailBranch": "分支", + "detailMergeCommit": "合并提交", + "detailChanges": "变更", + "detailScheduled": "计划开始", + "detailCreated": "创建时间", + "detailStarted": "开始时间", + "detailFinished": "完成时间", + "diffLoading": "正在加载差异…", + "deleteConfirmTitle": "删除任务?", + "deleteConfirmBody": "「{title}」将从看板移除。进行中的运行会先被取消。", + "deleteWithWorktree": "同时删除其 worktree", + "eventCreated": "已创建", + "eventStatusChanged": "状态变更", + "eventConfigEffective": "启动配置", + "eventInitCommand": "初始化命令", + "eventAgentProgress": "Agent 进展", + "eventAgentVerdict": "Agent 结论", + "eventMergeAttempt": "开始合并", + "eventMergeQueued": "加入合并队列", + "eventMergeConflict": "合并冲突", + "eventPreflight": "预检", + "eventCleanupFailed": "worktree 清理失败", + "eventResumeFallback": "会话恢复失败,已改用新会话", + "eventUserAction": "用户操作", + "eventDiffStat": "变更快照" + }, + "CustomSkillsSettings": { + "loading": "正在加载自定义技能…", + "category": "自定义", + "searchPlaceholder": "按名称、ID 或描述搜索自定义技能", + "states": { + "not_linked": "未启用", + "linked_to_codeg": "已启用", + "linked_elsewhere": "链接到其他位置", + "blocked_by_real_directory": "被同名真实目录占用", + "broken": "链接已失效" + }, + "actions": { + "new": "新建", + "import": "导入", + "importFromAgent": "从 Agent 导入", + "cancel": "取消", + "save": "保存" + }, + "rowMenu": { + "edit": "编辑", + "duplicate": "复制为新技能", + "delete": "删除" + }, + "bulk": { + "delete": "删除所选" + }, + "editor": { + "createTitle": "新建自定义技能", + "editTitle": "编辑自定义技能", + "description": "自定义技能存放在共享库(~/.codeg/skills),可为任意智能体启用。", + "idLabel": "技能 ID", + "idPlaceholder": "例如 my-workflow", + "contentLabel": "SKILL.md", + "contentPlaceholder": "在此编写技能的 SKILL.md…", + "preview": "预览", + "edit": "编辑", + "emptyBody": "暂无内容。" + }, + "duplicate": { + "title": "复制技能", + "description": "以「{id}」为模板,用新 ID 创建一份副本。", + "newIdPlaceholder": "新技能 ID", + "confirm": "复制" + }, + "import": { + "title": "选择要导入的技能文件夹" + }, + "importFromAgent": { + "title": "从 Agent 导入技能", + "description": "把某个 Agent 自己的技能复制到共享库,即可为任意 Agent 启用。", + "agentLabel": "Agent", + "agentPlaceholder": "选择一个 Agent", + "selectAll": "全选({count})", + "loading": "正在加载该 Agent 的技能…", + "unsupported": "该 Agent 未提供技能目录。", + "empty": "该 Agent 没有可导入的技能。", + "alreadyInLibrary": "已在库中", + "confirm": "导入所选({count})" + }, + "delete": { + "title": "删除自定义技能?", + "body": "将从中央库移除 {count} 个自定义技能,并解除它们在所有智能体中的链接。此操作不可撤销。", + "confirm": "删除" + }, + "toasts": { + "loadFailed": "加载技能失败", + "idRequired": "请输入技能 ID", + "created": "已创建自定义技能", + "updated": "已更新自定义技能", + "saveFailed": "保存技能失败", + "imported": "已导入技能", + "importFailed": "导入技能失败", + "duplicated": "已复制技能", + "duplicateFailed": "复制技能失败", + "deleted": "已删除 {count} 个技能", + "deletedPartial": "已删除 {ok} 个,{failed} 个失败", + "deleteFailed": "删除技能失败", + "importedFromAgent": "已导入 {count} 个技能", + "importedFromAgentPartial": "已导入 {ok} 个,{failed} 个失败", + "importFromAgentAllSkipped": "无需导入——{count} 个已在库中", + "importFromAgentFailed": "从 Agent 导入失败" + } + }, + "CodexModelEditor": { + "customizedNotice": "你已自定义模型列表,codeg 将接管 codex 的完整模型表。codex 日后新增的官方模型不会自动出现——点击下方刷新并重新保存即可同步。清空全部自定义即可交回 codex 自动更新。", + "officialsTitle": "官方模型", + "officialsHint": "自动纳入你启动的 codex 的官方模型;可删除不需要的。", + "officialsEmpty": "暂无官方模型。", + "refresh": "从 codex 刷新", + "readdOfficial": "重新加入官方", + "customsTitle": "自定义模型", + "customsEmpty": "暂无自定义模型。", + "addCustom": "添加自定义", + "slugPlaceholder": "模型 id(slug)", + "displayNamePlaceholder": "显示名", + "contextWindow": "上下文", + "makeDefault": "设为默认", + "defaultHint": "默认模型", + "remove": "删除", + "advanced": "高级", + "baseTemplate": "基础模板", + "baseTemplateHint": "从哪个官方模型克隆必填字段(系统提示词、工具、限制)。", + "groupBehavior": "行为与能力", + "fieldReasoningLevel": "默认推理强度", + "fieldReasoningSummary": "推理摘要", + "fieldVerbosity": "详细程度", + "fieldShellType": "Shell 类型", + "fieldApplyPatch": "应用补丁工具", + "fieldReasoningSummaries": "推理摘要支持", + "fieldSupportVerbosity": "详细程度控制", + "fieldParallelToolCalls": "并行工具调用", + "fieldSearchTool": "联网搜索工具", + "optNone": "无", + "groupInstructions": "描述与系统提示词", + "fieldDescription": "描述", + "baseInstructions": "系统提示词(base_instructions)" + }, + "DiagnosticsSettings": { + "title": "环境诊断", + "description": "检查本应用在自身进程中如何解析该智能体的 CLI——这可能与你的终端不同。", + "loading": "正在运行诊断…", + "error": "诊断失败", + "rerun": "重新运行", + "copyAll": "复制全部", + "copied": "诊断信息已复制到剪贴板", + "button": "诊断", + "verdict": { + "ok": "环境正常。若仍提示未安装,请彻底重启应用以刷新前缀缓存。", + "node_missing": "在应用的 PATH 上未找到 Node.js。", + "npm_missing": "在应用的 PATH 上未找到 npm。", + "not_installed": "该智能体似乎尚未安装。", + "installed_but_unresolved": "记录显示已安装,但应用无法定位其可执行文件。", + "user_prefix_not_on_path": "安装到了回退前缀(~/.codeg/npm-global),但它不在应用的 PATH 上。请彻底重启应用后重试。", + "homebrew_bin_not_on_path": "安装在 Homebrew 的 bin 目录下,但它不在应用的 PATH 上(Apple Silicon keg 拆分)。", + "terminal_only_path": "该命令在你的终端能解析,但在应用中不能——这是 GUI PATH 差异。请从终端启动应用,或在智能体设置中重新安装。", + "npm_prefix_timeout": "npm prefix -g 太慢(超过 1.5 秒),已跳过回退检测。请重启应用后重试。", + "node_too_old": "当前 Node.js 版本低于该智能体的要求。请升级 Node.js。", + "adapter_missing_native_present": "你本地的 {agent} CLI 确实装了,但 Codeg 启动的是另一个 ACP 适配器包,而它还没装。到「智能体设置」里安装即可 —— 它不会动你的 CLI,登录状态也是共享的。", + "adapter_missing": "Codeg 为 {agent} 启动的是单独的 ACP 适配器包,目前尚未安装。请到「智能体设置」里安装 —— 只装厂商 CLI 是不够的。" + } + }, + "TokenUsage": { + "title": "Token 用量", + "rangeLabel": "时间范围", + "range7d": "近 7 天", + "range30d": "近 30 天", + "range90d": "近 90 天", + "rangeThisMonth": "本月", + "rangeThisYear": "今年", + "rangeAll": "全部", + "rangeCustom": "自定义", + "moreRanges": "更多", + "customRangePick": "选择日期范围", + "bucketLabel": "统计粒度", + "bucketDay": "按天", + "bucketWeek": "按周", + "bucketMonth": "按月", + "bucketUnitDay": "天", + "bucketUnitWeek": "周", + "bucketUnitMonth": "月", + "folderFilter": "文件夹", + "allFolders": "全部文件夹", + "agentFilter": "智能体", + "allAgents": "全部智能体", + "modelFilter": "模型", + "allModels": "全部模型", + "searchPlaceholder": "搜索…", + "noMatches": "没有匹配项", + "clearFilter": "清除选择", + "resetFilters": "重置筛选", + "refresh": "刷新数据", + "rebuild": "全量重建", + "rebuildHint": "丢弃已统计的数据并重新解析全部会话记录。会话被 codeg 之外的 CLI 追加过时用它。", + "syncing": "正在统计会话…", + "syncProgress": "{done} / {total}", + "syncDone": "已统计 {synced} 个会话", + "syncFailed": "部分会话读取失败", + "syncBusy": "已有一次刷新在进行中", + "lastSynced": "更新于 {time}", + "lastSyncedNever": "尚未统计", + "tileTotal": "总 Token", + "tileSessions": "会话数", + "tileTurns": "对话轮次", + "tileActiveDays": "活跃天数", + "tileGenTime": "生成时长", + "vsPrevious": "对比上一周期", + "deltaNew": "新增", + "trendTitle": "用量趋势", + "trendEmpty": "该范围内没有用量", + "trendTurns": "轮次", + "trendSessions": "会话", + "compositionTitle": "Token 都花在哪", + "compositionHint": "输入是你发出去的内容,输出是模型写回来的,缓存读取则是不必再按原价重发的上下文。", + "compositionNote": "这些缓存命中若按原价重发,要多花 {value}。", + "inputTokens": "输入", + "outputTokens": "输出", + "cacheWrite": "缓存写入", + "cacheRead": "缓存读取", + "freshTokens": "新算 Token", + "cacheHitCaption": "缓存命中", + "cacheHeroTitleHigh": "上下文大多不必重发", + "cacheHeroTitleLow": "多数上下文仍按原价计算", + "cacheHeroDesc": "{cached} 的上下文由缓存承担,这段时间真正新算的只有 {fresh}。", + "cacheSavedSuffix": "省下的重发量相当于 {saved}。", + "avgPerSession": "平均每会话", + "avgTurnsPerSession": "平均每会话 {count} 轮", + "avgPerActiveDay": "平均每活跃日", + "peakBucket": "最高的一{bucket}", + "peakHour": "高峰时段", + "daysValue": "{count} 天", + "idleDays": "空转天数", + "byFolderTitle": "按文件夹", + "byAgentTitle": "按智能体", + "byModelTitle": "按模型", + "distributionTitle": "用量分布", + "distributionHint": "会话与 Token 按所选维度归集,点任意一行可按它筛选。", + "otherLabel": "其他", + "unknownModel": "未标注模型", + "emptyBreakdown": "还没有记录", + "sessionsCount": "{count} 个会话", + "heatmapTitle": "你的编码作息", + "heatmapHint": "按本地星期与小时统计的 Token 分布。", + "heatmapPeakHint": "最密集的时段在 {hour}:00 前后。", + "less": "少", + "more": "多", + "heatmapCell": "{weekday} {hour}:00 — {value} tokens", + "weekMon": "一", + "weekTue": "二", + "weekWed": "三", + "weekThu": "四", + "weekFri": "五", + "weekSat": "六", + "weekSun": "日", + "topSessionsTitle": "消耗最高的会话", + "untitledSession": "未命名会话", + "topSessionsEmpty": "该范围内没有会话", + "streakLongest": "最长连续", + "streakLongestDays": "最长连续 {count} 天", + "share": "分享", + "moreActions": "更多操作", + "shareDialogTitle": "分享你的用量卡片", + "shareDialogHint": "卡片内容就是你当前所选的时间范围与筛选条件。", + "shareSave": "保存图片", + "shareCopy": "复制图片", + "shareCopied": "已复制到剪贴板", + "shareSaved": "图片已保存", + "shareFailed": "图片生成失败", + "shareRendering": "生成中…", + "cardHeading": "我的 AI 编码战绩", + "cardRangeAll": "全部时间", + "cardTotalLabel": "累计 Token", + "cardFooter": "由 codeg 生成", + "cardTopModels": "常用模型", + "cardTopProjects": "主力项目", + "archetypeNightOwl": "深夜码农", + "archetypeNightOwlDesc": "{percent}% 的 Token 烧在天黑之后。", + "archetypeEarlyBird": "清晨型选手", + "archetypeEarlyBirdDesc": "{percent}% 的 Token 在早上 9 点前就用掉了。", + "archetypeWeekendWarrior": "周末战士", + "archetypeWeekendWarriorDesc": "{percent}% 的 Token 发生在周末。", + "archetypeCacheMaster": "缓存大师", + "archetypeCacheMasterDesc": "{percent}% 的上下文来自缓存。", + "archetypeMarathoner": "长跑选手", + "archetypeMarathonerDesc": "连续 {days} 天没有断更。", + "archetypePolyglot": "多面手", + "archetypePolyglotDesc": "{count} 个智能体都在主力使用。", + "archetypeLaserFocus": "专注一役", + "archetypeLaserFocusDesc": "{percent}% 的 Token 投在同一个项目上。", + "archetypeDeepDiver": "深潜者", + "archetypeDeepDiverDesc": "平均每个会话 {averageK}K tokens。", + "archetypeSteady": "稳定输出", + "archetypeSteadyDesc": "累计 {days} 天在写代码。", + "emptyTitle": "还没有可统计的数据", + "emptyHint": "codeg 直接从各智能体自己的会话记录里读取 Token 数。点一下刷新,把本机已有的会话统计进来。", + "emptyAction": "统计我的会话", + "loadFailed": "用量加载失败", + "truncatedNotice": "该范围过大 —— 下面的数字只覆盖了其中最近的一段。" + } +} diff --git a/src/i18n/messages/zh-TW.json b/src/i18n/messages/zh-TW.json index 9d2737f10..0af81bafa 100644 --- a/src/i18n/messages/zh-TW.json +++ b/src/i18n/messages/zh-TW.json @@ -1,4958 +1,4958 @@ -{ - "Language": { - "followSystem": "跟隨系統", - "english": "英文", - "simplifiedChinese": "簡體中文", - "traditionalChinese": "繁體中文", - "japanese": "日語", - "korean": "韓語", - "spanish": "西班牙語", - "german": "德語", - "french": "法語", - "portuguese": "葡萄牙語", - "arabic": "阿拉伯語" - }, - "GitCredentialDialog": { - "title": "需要身份驗證", - "description": "遠端伺服器要求輸入憑據。請輸入使用者名稱和密碼(或個人存取權杖)。", - "username": "使用者名稱", - "usernamePlaceholder": "使用者名稱或電子郵件", - "password": "密碼 / 權杖", - "passwordPlaceholder": "密碼或個人存取權杖", - "passwordHint": "請輸入伺服器的使用者名稱和密碼。", - "cancel": "取消", - "authenticate": "驗證", - "authenticating": "驗證中...", - "invalidCredentials": "憑據無效,請重試。", - "saveCredentials": "儲存憑據以供後續操作使用", - "githubTitle": "GitHub 身份驗證", - "githubDescription": "輸入個人存取權杖以連線 GitHub。權杖驗證成功後將自動儲存至帳號列表。", - "githubToken": "個人存取權杖", - "githubTokenPlaceholder": "ghp_xxxxxxxxxxxx", - "githubTokenHint": "在 GitHub → Settings → Developer settings → Personal access tokens 中產生權杖。", - "githubAuthenticate": "驗證並連線", - "generateToken": "產生權杖" - }, - "SettingsShell": { - "title": "設定", - "preferences": "偏好設定", - "nav": { - "general": "一般", - "appearance": "外觀", - "agents": "智能體", - "mcp": "MCP", - "skills": "Skills", - "shortcuts": "快捷鍵", - "version_control": "版本控制", - "system": "系統", - "chat_channels": "訊息頻道", - "web_service": "Web 服務", - "model_providers": "模型供應商", - "experts": "專家", - "science": "科學研究", - "office_tools": "辦公工具", - "skill_packs": "技能包", - "quick_messages": "快捷訊息", - "logs": "執行日誌" - } - }, - "AppearanceSettings": { - "sectionTitle": "主題外觀", - "sectionDescription": "選擇淺色、深色或跟隨系統主題,設定會自動儲存。", - "themeMode": "主題模式", - "placeholder": "請選擇主題模式", - "system": "跟隨系統", - "light": "淺色", - "dark": "深色", - "currentTheme": "目前生效主題:{theme}", - "resolvedTheme": { - "light": "淺色", - "dark": "深色", - "unknown": "未知" - }, - "themeColor": { - "sectionTitle": "主題顏色", - "sectionDescription": "選擇按鈕、強調色和高亮使用的色調。", - "current": "目前顏色:{color}", - "options": { - "neutral": "Neutral", - "zinc": "Zinc", - "slate": "Slate", - "stone": "Stone", - "gray": "Gray", - "red": "Red", - "rose": "Rose", - "orange": "Orange", - "green": "Green", - "blue": "Blue", - "yellow": "Yellow", - "violet": "Violet" - } - }, - "customStyle": { - "sectionTitle": "自訂樣式", - "sectionDescription": "在目前主題的基礎上微調配色,或寫入自己的 CSS。覆寫疊加在基底預設之上,切換預設後依然保留。", - "summarySuspended": "已停用", - "summaryDefault": "跟隨預設", - "summaryTokens": "{count, plural, other {# 項覆寫}}", - "summaryCss": "自訂 CSS", - "suspendedByShortcut": "自訂樣式已停用。在恢復之前,這裡的設定都不會生效。", - "suspendedBySafeParam": "本視窗以安全外觀模式開啟,自訂樣式在此不生效,其它視窗不受影響。", - "resume": "恢復自訂樣式", - "enableTheme": "啟用自訂配色", - "editingLight": "正在編輯淺色模式的取值。切換到深色模式可單獨設定深色。", - "editingDark": "正在編輯深色模式的取值。切換到淺色模式可單獨設定淺色。", - "resetToken": "還原為預設取值", - "radius": "圓角", - "radiusHint": "從 sm 到 4xl 的整套圓角尺寸都由它衍生,一個滑桿即可改變全域圓角。", - "advanced": "進階(另有 {count} 個變數)", - "enableCss": "啟用自訂 CSS", - "cssRisk": "進階功能。自訂 CSS 會壓過所有內建樣式,寫壞可能導致介面無法使用。", - "editCss": "編輯 CSS…", - "cssPresent": "已儲存 {size} KB", - "cssEmpty": "尚未儲存內容", - "escapeHint": "介面被改壞了?按 {shortcut} 可停用全部自訂樣式,也可以用 safeStyle=1 查詢參數開啟視窗。", - "copyTheme": "複製主題 JSON", - "importTheme": "匯入主題…", - "clearTheme": "清除覆寫", - "interopHint": "主題採用 shadcn 的 registry:theme 格式,可以直接貼上任意 shadcn 主題,匯出的主題也能用在任何 shadcn 專案裡。", - "importTitle": "匯入主題", - "importDescription": "貼上 shadcn 的 registry:theme 項目、裸的 light/dark 物件,或者單層的 token 對應表。", - "readClipboard": "讀取剪貼簿", - "importConfirm": "匯入", - "cancel": "取消", - "apply": "套用", - "toasts": { - "copied": "主題 JSON 已複製", - "copyFailed": "無法寫入剪貼簿", - "clipboardReadFailed": "無法讀取剪貼簿,請手動貼上", - "importFailed": "這段 JSON 裡沒有可用的主題變數", - "imported": "主題已匯入" - }, - "css": { - "dialogTitle": "自訂 CSS", - "dialogDescription": "對所有 codeg 視窗生效。修改會即時預覽,點擊「套用」才會儲存。", - "size": "{used} KB / {max} KB", - "ruleCount": "{count} 條規則", - "errorTooLarge": "內容過大,無法儲存,請精簡到上限以內。", - "errorImportEscaped": "剝離後仍偵測到 @import(跳脫寫法),請手動移除後再儲存。", - "warnNoRules": "沒有解析出任何規則,請檢查語法。", - "noticeImportsRemoved": "已移除 {count} 條 @import:它們會拉取遠端樣式表。", - "noticeRemoteUrl": "含遠端 url(),套用後會發起網路請求。", - "noticePreviewSuspended": "自訂樣式已停用,此處預覽不會生效。", - "noticeDisabled": "自訂 CSS 未啟用。這裡可以預覽,但啟用後才會真正生效。", - "hintTokens": "提示:你覆寫的顏色可以直接用 var(--primary)、var(--background) 等引用。" - } - }, - "zoomLevel": { - "sectionTitle": "視窗縮放", - "sectionDescription": "整體放大或縮小介面,立即生效,依裝置分別儲存。", - "placeholder": "請選擇縮放檔位", - "default": "預設", - "current": "目前縮放:{zoom}%" - }, - "fonts": { - "sectionTitle": "字型", - "sectionDescription": "為介面、程式碼編輯器與終端機分別選擇字型。內建字型會按需載入;選擇「自訂…」可使用系統已安裝的任意字型。", - "interface": "介面", - "editor": "編輯器", - "terminal": "終端機", - "groupSans": "無襯線", - "groupMono": "等寬", - "custom": "自訂…", - "customPlaceholder": "字型名稱,如 Fira Code", - "fontSize": "字級", - "ligatures": "啟用連字", - "ligaturesUnavailable": "此字型不含連字", - "wordWrap": "啟用自動換行", - "terminalLigaturesHint": "終端機連字僅對內建程式字型生效。", - "preview": "預覽" - }, - "welcomePanel": { - "sectionTitle": "模式選擇區域", - "sectionDescription": "新會話頁面輸入框上方顯示的「程式開發 / 日常辦公」快捷卡片區域。", - "showQuickActions": "在新會話頁面顯示" - }, - "workspaceBackground": { - "sectionTitle": "工作區背景", - "sectionDescription": "在整個工作區背後顯示一張圖片。側邊欄與面板會變半透明並磨砂讓圖片透出,遮罩確保文字可讀。", - "enable": "啟用背景圖片", - "image": "圖片", - "chooseImage": "選擇圖片", - "replaceImage": "更換圖片", - "removeImage": "移除", - "fillMode": "填滿方式", - "fillModes": { - "cover": "覆蓋", - "contain": "適應", - "center": "置中", - "tile": "平鋪" - }, - "maskOpacity": "遮罩不透明度", - "maskOpacityHint": "數值越高,圖片越向主題背景色淡化,文字對比越清晰。", - "imageBlur": "圖片模糊", - "panelOpacity": "面板不透明度", - "panelOpacityHint": "側邊欄、面板與標籤列的不透明程度。越低,透出的圖片越多。", - "errorTooLarge": "圖片太大(最大 16 MB)。", - "errorUploadFailed": "設定背景圖片失敗。" - } - }, - "SystemSettings": { - "loading": "載入中...", - "sectionTitle": "系統管理", - "sectionDescription": "管理網路代理、應用升級與語言偏好。", - "proxyTitle": "網路代理", - "proxyDescription": "啟用後,後續網路請求將優先走該代理(包含 ACP 對話、Agent 安裝、Git 遠端操作等)。", - "loadFailed": "載入失敗:{message}", - "enableProxy": "啟用系統代理", - "proxyAddress": "代理位址", - "proxyHint": "支援 http(s)/socks5,範例:{example}。僅在啟用系統代理時生效。", - "save": "儲存", - "saving": "儲存中...", - "proxyRequired": "啟用代理時必須填寫代理位址", - "saveSuccess": "系統代理設定已儲存", - "saveFailed": "儲存失敗:{message}", - "languageTitle": "語言", - "languageDescription": "設定應用語言。跟隨系統時,若系統語言不受支援將回退為英文。", - "appLanguage": "應用語言", - "languageSaveSuccess": "語言設定已儲存", - "languageSaveFailed": "語言設定儲存失敗:{message}", - "updateTitle": "應用升級", - "versionTitle": "軟體更新", - "updateDescription": "點擊檢查後會從設定的發佈來源拉取最新版本資訊,有新版本時可直接下載並安裝。", - "currentVersion": "目前版本", - "upgradableVersion": "最新版本", - "none": "暫無", - "lastChecked": "上次檢查:{time}", - "updateError": "更新異常:{message}", - "checking": "檢查中...", - "checkUpdate": "檢查更新", - "updating": "升級中...", - "downloading": "下載中...", - "upgradeTo": "升級到 v{version}", - "viewRelease": "查看 v{version} 發布", - "foundUpdate": "發現新版本 v{version}", - "alreadyLatest": "目前已是最新版本", - "checkUpdateFailed": "檢查更新失敗:{message}", - "installSuccess": "升級包已安裝,正在重新啟動應用", - "installFailed": "升級失敗:{message}", - "upgradeSuccess": "升級完成,正在重新載入...", - "restartTimeout": "服務未能即時恢復,請檢查容器或服務記錄。", - "restartingIn": "將在 {seconds} 秒後重新啟動...", - "waitingForServer": "正在等待服務恢復...", - "restartToUpdate": "重新啟動以更新", - "newVersionBadge": "新版本 v{version}", - "updateAvailableTitle": "發現新版本", - "releaseNotesTitle": "更新內容", - "remindLater": "稍後", - "retry": "重試", - "stepDownload": "下載", - "stepInstall": "安裝", - "stepRestart": "重新啟動", - "updateReadyHint": "新版本已下載,重新啟動以完成更新。", - "restarting": "正在重新啟動…", - "dockerUpgradeHint": "現在升級的是正在執行的容器。容器一旦被重新建立即遺失——如需保留,請拉取或建置新版本映像後重新建立容器。", - "upgradeRolledBack": "升級失敗,伺服器已自動回復到上一版本。", - "serverUnreachable": "無法連線到伺服器以開始升級。請確認伺服器正在執行後重試。", - "rollbackButton": "復原", - "rollingBack": "復原中...", - "rollbackDescription": "還原至上次升級前安裝的版本。", - "rollbackConfirmTitle": "復原到上一個版本?", - "rollbackConfirmDescription": "伺服器將重新啟動並執行上次升級前安裝的版本。較新的版本仍可再次安裝。", - "rollbackConfirm": "復原", - "rollbackCancel": "取消", - "rollbackSuccess": "已復原到上一個版本,正在重新載入……", - "rollbackFailed": "復原失敗,請檢查伺服器日誌。", - "updateErrors": { - "sourceUnavailable": "無法連線更新來源,請檢查網路或代理設定後重試。", - "network": "網路連線異常,請檢查網路或代理設定後重試。", - "downloadFailed": "下載更新包失敗,請稍後再試。", - "installFailed": "安裝更新失敗,請關閉應用後重試。", - "unknown": "更新失敗,請稍後再試。" - } - }, - "VersionControlSettings": { - "loading": "載入中...", - "sectionTitle": "版本控制", - "sectionDescription": "設定 Git 執行檔並管理 GitHub 帳號。", - "gitTitle": "Git 設定", - "gitDescription": "設定應用程式使用的 Git 執行檔。", - "gitDetected": "已偵測到 Git", - "gitNotFound": "未在系統中找到 Git", - "gitVersion": "版本", - "gitPath": "路徑", - "customGitPath": "自訂 Git 路徑", - "customGitPathPlaceholder": "/usr/bin/git", - "customGitPathHint": "留空則使用自動偵測的路徑。", - "test": "測試", - "testing": "測試中...", - "testSuccess": "Git 執行檔有效。", - "testFailed": "Git 測試失敗:{message}", - "save": "儲存", - "saving": "儲存中...", - "saveSuccess": "Git 設定已儲存。", - "saveFailed": "儲存失敗:{message}", - "githubTitle": "GitHub 帳號", - "githubDescription": "管理用於身份驗證的 GitHub 帳號。權杖儲存在本機。", - "noAccounts": "尚未設定 GitHub 帳號。", - "addAccount": "新增帳號", - "serverUrl": "伺服器網址", - "serverUrlPlaceholder": "https://github.com", - "token": "個人存取權杖", - "tokenPlaceholder": "ghp_xxxxxxxxxxxx", - "generateToken": "產生權杖", - "tokenHint": "在 GitHub → Settings → Developer settings → Personal access tokens 中產生權杖。", - "validateAndAdd": "驗證並新增", - "validating": "驗證中...", - "addSuccess": "帳號 {username} 新增成功。", - "addFailed": "新增帳號失敗:{message}", - "testConnection": "測試", - "connectionSuccess": "連線成功。", - "connectionFailed": "連線失敗:{message}", - "setDefault": "設為預設", - "defaultLabel": "預設", - "defaultSet": "預設帳號已更新。", - "removeAccount": "刪除", - "removeConfirmTitle": "刪除帳號", - "removeConfirmMessage": "確定要刪除帳號「{username}」嗎?", - "removeConfirm": "刪除", - "removeCancel": "取消", - "removeSuccess": "帳號已刪除。", - "scopes": "權限範圍", - "loadFailed": "載入設定失敗:{message}", - "gitAccount": { - "sectionTitle": "Git 伺服器帳號", - "sectionDescription": "管理非 GitHub 的 Git 伺服器憑據(GitLab、Bitbucket、自建服務等)。", - "noAccounts": "尚未設定 Git 伺服器帳號。", - "addAccount": "新增帳號", - "addTitle": "新增 Git 帳號", - "addDescription": "輸入伺服器網址、使用者名稱和密碼或存取權杖。", - "serverUrl": "伺服器網址", - "serverUrlPlaceholder": "https://gitlab.example.com", - "username": "使用者名稱", - "usernamePlaceholder": "使用者名稱或電子郵件", - "password": "密碼 / 權杖", - "passwordPlaceholder": "密碼或存取權杖", - "passwordHint": "輸入伺服器的密碼或個人存取權杖。", - "add": "新增", - "serverRequired": "請輸入伺服器網址。", - "usernameRequired": "請輸入使用者名稱。", - "passwordRequired": "請輸入密碼。" - } - }, - "ShortcutSettings": { - "sectionTitle": "快捷鍵", - "resetDefault": "恢復預設", - "recordInstruction": "點擊右側按鈕後按下組合鍵即可修改。建議使用 Ctrl/Cmd、Alt、Shift 的組合。按 Esc 可取消錄製。", - "recording": "按下快捷鍵...", - "toasts": { - "conflict": "快捷鍵已被「{title}」占用", - "updated": "快捷鍵已更新", - "invalid": "快捷鍵無效,請重試", - "reset": "已恢復預設快捷鍵" - }, - "actions": { - "toggle_search": { - "title": "打開搜尋", - "description": "打開或關閉會話搜尋面板" - }, - "toggle_sidebar": { - "title": "切換左側邊欄", - "description": "顯示或隱藏會話列表側邊欄" - }, - "toggle_terminal": { - "title": "切換終端", - "description": "顯示或隱藏底部終端面板" - }, - "new_terminal_tab": { - "title": "新增終端", - "description": "當最近滑鼠活動在終端時新增終端分頁" - }, - "close_current_terminal_tab": { - "title": "關閉目前終端", - "description": "當最近滑鼠活動在終端時關閉目前終端分頁" - }, - "toggle_aux_panel": { - "title": "切換右側面板", - "description": "顯示或隱藏輔助資訊面板" - }, - "new_conversation": { - "title": "新增會話", - "description": "在目前資料夾中建立新的對話分頁" - }, - "open_folder": { - "title": "打開資料夾", - "description": "打開資料夾選擇器並在新視窗中開啟" - }, - "open_settings": { - "title": "打開設定", - "description": "打開設定視窗" - }, - "close_current_tab": { - "title": "關閉目前分頁", - "description": "關閉目前會話或檔案分頁" - }, - "close_all_file_tabs": { - "title": "關閉全部檔案分頁", - "description": "當檔案面板處於作用中狀態時關閉所有開啟的檔案分頁" - }, - "next_tab": { - "title": "下一個標籤頁", - "description": "切換到下一個會話或檔案標籤頁" - }, - "prev_tab": { - "title": "上一個標籤頁", - "description": "切換到上一個會話或檔案標籤頁" - }, - "send_message": { - "title": "傳送訊息", - "description": "在輸入框中傳送目前的訊息" - }, - "newline_in_message": { - "title": "訊息換行", - "description": "在輸入框中插入換行符" - }, - "toggle_custom_style": { - "title": "停用/恢復自訂樣式", - "description": "逃生艙:一鍵關閉全部自訂配色與 CSS,再按一次恢復" - } - } - }, - "SkillsSettings": { - "title": "Skills", - "description": "左側選擇 Skill,右側預設預覽 Markdown,點擊編輯後可修改並儲存。", - "loadingAgents": "正在載入支援 Skills 的 Agent...", - "emptyNoManageableAgents": "目前沒有可管理 Skills 的 Agent。", - "managedTarget": "管理對象", - "selectAgentPlaceholder": "請選擇 Agent", - "searchPlaceholder": "搜尋名稱 / ID / 路徑...", - "skillsList": "Skills 列表", - "loadingSkills": "載入 Skills 中...", - "agentNotSupported": "目前 Agent 暫不支援 Skills 管理。", - "emptySkills": "暫無 Skill,可點擊「新增 Skill」。", - "newSkillTitle": "新增 Skill", - "skillInfo": "Skill 資訊", - "skillIdPlaceholder": "Skill ID(例如:my-skill)", - "skillsDirectoryWithPath": "Skills目錄:{path}", - "skillsDirectoryNeedId": "Skills目錄:請輸入 Skill ID 以產生完整路徑", - "markdownContent": "Markdown 內容", - "editingStatus": "編輯中", - "previewStatus": "預覽中", - "contentPlaceholder": "輸入 Skill 文字內容...", - "metadataTitle": "Skills 中繼資訊", - "onlyYamlMetadata": "該 Skill 僅包含 YAML 中繼資訊。", - "emptyContentHint": "暫無內容。點擊「編輯」開始輸入。", - "loadingSkill": "正在載入 Skill...", - "emptyNoAgents": "暫無可用 Agent。", - "noSelectionHint": "從左側選擇一個 Skill,或點擊「新建 Skill」建立。", - "systemBadge": "系統", - "systemHint": "CLI 內建 Skill · 唯讀", - "scope": { - "global": "全域", - "folder": "資料夾", - "selectFolderPlaceholder": "選擇資料夾", - "noFolders": "找不到任何資料夾", - "pickFolderHint": "選擇一個資料夾以檢視其 Skills。" - }, - "actions": { - "preview": "預覽", - "edit": "編輯", - "openInWindow": "在新視窗打開", - "delete": "刪除", - "deleting": "刪除中...", - "refresh": "刷新", - "newSkill": "新增 Skill", - "reset": "重置", - "save": "儲存", - "saving": "儲存中...", - "cancel": "取消" - }, - "deleteDialog": { - "title": "刪除 Skill", - "confirm": "確認刪除目前 Skill 嗎?此操作無法復原。", - "confirmWithNamePrefix": "確認刪除 Skill", - "confirmWithNameSuffix": "嗎?此操作無法復原。" - }, - "toasts": { - "loadFailed": "載入 Skill 失敗", - "openFolderFailed": "打開目錄失敗", - "noSkillDirectory": "目前 Agent 未找到可用的 Skills 目錄", - "nameRequired": "Skill 名稱不能為空", - "updated": "Skill 已更新", - "created": "Skill 已建立", - "saveFailed": "儲存 Skill 失敗", - "deleted": "Skill 已刪除", - "deleteFailed": "刪除 Skill 失敗" - }, - "templates": { - "gemini": "---\nname: example-skill\ndescription: Describe when this skill should be used.\n---\n\n# Skill Name\n\nInstructions for the agent when this skill is active.\n\n## Workflow\n\n1. Add actionable step one.\n2. Add actionable step two.\n", - "openCode": "---\nname: example-skill\ndescription: Describe when this skill should be used.\n---\n\n# Purpose\n\nDescribe what this skill helps with.\n\n# Steps\n\n1. Add actionable step one.\n2. Add actionable step two.\n", - "openClaw": "---\nname: example-skill\ndescription: Describe when this skill should be used.\nuser-invocable: true\ndisable-model-invocation: false\n---\n\n# Purpose\n\nDescribe what this skill helps with.\n\n# Instructions\n\n1. Add actionable instruction one.\n2. Add actionable instruction two.\n", - "default": "---\nname: example-skill\ndescription: Describe when this skill should be used.\n---\n\n# Skill: example-skill\n\n## When to use\n\n- Describe trigger conditions.\n\n## Instructions\n\n1. Add actionable instruction one.\n2. Add actionable instruction two.\n" - } - }, - "McpSettings": { - "loading": "載入中...", - "summary": { - "missingCommand": "(缺少 command)", - "missingUrl": "(缺少 url)" - }, - "protocol": { - "stdio": "Stdio" - }, - "errors": { - "selectInstallProtocol": "請選擇安裝協議", - "fieldRequired": "{field} 為必填項", - "fieldNeedsBoolean": "{field} 需要 true 或 false", - "fieldNeedsNumber": "{field} 需要數字", - "fieldNeedsInteger": "{field} 需要整數", - "fieldInvalidJson": "{field} JSON 無效:{message}", - "fieldOutOfRange": "{field} 的值不在可選範圍內", - "jsonEmpty": "{name} 不能為空", - "jsonInvalid": "{name} 不是合法 JSON:{message}", - "jsonMustBeObject": "{name} 必須是 JSON 物件", - "specMustBeObject": "MCP 設定必須是 JSON 物件。", - "missingType": "MCP 設定缺少 type 欄位。請填寫 stdio、http(別名 streamable-http、streamableHttp)、sse 其中之一。", - "unsupportedType": "不支援的 MCP type:{type}。支援的類型:stdio、http(別名 streamable-http、streamableHttp)、sse。", - "codexEntryUnsupportedType": "Codex MCP 項目 {id} 的 type 不受支援:{type}。支援的類型:stdio、http(別名 streamable-http、streamableHttp)、sse。", - "unsupportedTransportType": "不支援的 transport 類型:{type}。支援的類型:http(別名 streamable-http、streamableHttp)、sse。", - "stdioCommandRequired": "stdio 類型的 MCP 必須填寫非空的 command 欄位。", - "remoteUrlRequired": "遠端 MCP 必須填寫非空的 url 欄位。", - "appsRequired": "請至少選擇一個目標 App。" - }, - "jsonNames": { - "localConfig": "MCP 配置", - "installConfig": "安裝配置" - }, - "toasts": { - "uninstalled": "已卸載 MCP", - "uninstallFailed": "卸載失敗:{message}", - "selectAtLeastOneApp": "請至少選擇一個目標應用", - "saveSuccess": "儲存成功", - "saveFailed": "儲存失敗:{message}", - "installed": "已安裝 {name}", - "installFailed": "安裝失敗:{message}", - "serverIdRequired": "Server ID 不能為空", - "serverIdExists": "Server ID \"{id}\" 已存在,請編輯現有項或更換名稱", - "created": "MCP 已建立" - }, - "installDialog": { - "title": "確認安裝 MCP", - "descriptionWithName": "將 {name} 安裝到本地配置。", - "description": "選擇安裝目標應用。", - "protocol": "協議", - "selectProtocol": "選擇協議", - "parameters": "配置參數", - "booleanPlaceholder": "請選擇 true/false", - "selectOneValue": "選擇一個值", - "targetApps": "目標應用" - }, - "actions": { - "cancel": "取消", - "confirmInstall": "確認安裝", - "installing": "安裝中", - "uninstall": "卸載", - "uninstalling": "卸載中", - "viewDetails": "查看詳情", - "save": "儲存", - "saving": "儲存中", - "install": "安裝", - "refresh": "重新整理", - "newMcp": "新建 MCP", - "create": "建立", - "creating": "建立中..." - }, - "tabs": { - "local": "本地 MCP", - "market": "MCP 市場" - }, - "local": { - "filterPlaceholder": "篩選本地 MCP...", - "loadFailed": "載入失敗:{message}", - "empty": "目前未檢測到本地 MCP。", - "description": "本地 MCP 配置可直接編輯並儲存。", - "enabledApps": "啟用應用", - "configJson": "MCP 配置(JSON)", - "draftTitle": "新建 MCP", - "draftDescription": "填寫 Server ID 與設定以建立本地 MCP 伺服器。", - "serverIdLabel": "Server ID", - "serverIdPlaceholder": "Server ID(例如:my-mcp)", - "typeHint": "支援類型:stdio、http(別名 streamable-http、streamableHttp)、sse。env 僅適用於 stdio;遠端 MCP 請透過 headers 欄位傳遞認證 token。", - "envOnRemoteWarning": "偵測到遠端 MCP 設定中包含 env 欄位。env 僅 stdio 類型使用,遠端 MCP 應透過 headers 攜帶認證資訊,env 欄位儲存時會被忽略。" - }, - "market": { - "selectMarketplace": "選擇市場", - "searchPlaceholder": "搜尋 MCP...", - "searchFailed": "搜尋失敗:{message}", - "loadingList": "載入 MCP 列表...", - "empty": "暫無 MCP 結果。", - "loadingDetail": "載入市場詳情...", - "detailLoadFailed": "載入詳情失敗:{message}", - "owner": "擁有者:{owner}", - "namespace": "命名空間:{namespace}", - "defaultInstallProtocol": "預設安裝協議", - "currentOptionParameterCount": "目前選項參數數:{count}", - "installConfigDescription": "安裝配置(JSON,可修改後安裝;修改後將覆蓋協議/參數表單)", - "selectLeftToView": "請選擇左側市場 MCP 查看詳情。" - }, - "badges": { - "verified": "已驗證", - "remote": "遠端", - "hasHomepage": "有首頁", - "uses": "{count} 次使用", - "deployed": "已部署", - "notDeployed": "未部署" - }, - "selectLeftMcp": "請選擇左側 MCP。" - }, - "AcpAgentSettings": { - "title": "Agent SDK管理", - "description": "統一管理 Agent 的連接SDK、啟用狀態、環境變數、配置管理與版本預檢資訊。", - "loadingAgents": "載入 Agent 列表中...", - "agentList": "Agent 列表", - "emptyNoAgent": "暫無可用 Agent。", - "configManagement": "配置管理", - "envVars": "環境變數", - "hostTools": { - "label": "由 Agent 自行處理檔案與指令", - "description": "codeg 不再代為提供檔案存取與終端指令,改由 Agent 在自己的行程中執行——只有這樣它自帶的沙箱與權限規則才會生效。同時會關閉向其他 Agent 委派,否則同樣的操作又會繞回 codeg 執行。codeg 本身不提供沙箱,因此請僅在 Agent 已設定沙箱時開啟。" - }, - "nativeJsonConfig": "原生 JSON 配置", - "modelHintDefault": "留空則使用系統預設模型。", - "generalConfigDescriptionClaude": "支援 API URL、API Key 與 Claude 模型快捷配置,並與原生 JSON 配置聯動。", - "generalConfigDescriptionDefault": "支援重要配置輸入(API URL、API Key、Model)和原生 JSON 配置管理。", - "multiAgent": { - "title": "多智慧體協同", - "description": "允許活躍的智慧體將子任務委派給其他智慧體。", - "enable": "啟用委派", - "enableHint": "關閉後,delegate_to_agent 工具會從智慧體的 MCP 工具清單中隱藏。", - "withheldByHostTools": "{agents} 不會拿到委派工具:它們單獨開啟了「由 Agent 自行處理檔案與命令」。", - "selfInitiate": "Allow spawn without @", - "selfInitiateHint": "When on, an agent may start a listed sub-agent on its own. An @ mention is still always honored. When off, only an @ mention starts a sub-agent.", - "depthLimit": "最大委派深度", - "depthHint": "允許範圍:{min}–{max}。限制委派鏈(根 → 子 → 孫 …)的最大遞迴深度。", - "completedCacheLabel": "已完成結果快取(MB)", - "completedCacheHint": "執行中委派工作階段已完成子代理結果的記憶體快取,僅在該工作階段執行期間保留,工作階段結束後自動清除。超出此預算時優先從記憶體中捨棄最舊的結果(仍可在子代理自己的工作階段中檢視);0 表示不限(工作階段結束後仍會清除)。", - "save": "儲存", - "saving": "儲存中…", - "saved": "委派設定已儲存", - "saveFailed": "委派設定儲存失敗", - "loadFailed": "載入委派設定失敗:{detail}", - "tabGeneral": "一般", - "tabAgentDefaults": "子智慧體設定", - "agentDefaultsDescription": "多智慧體協同在為委派呼叫啟動子智慧體時使用這些覆寫項。下方選項透過即時探測取得,所選即所用。", - "probing": "正在載入該智慧體的可用設定項…", - "probeFailed": "載入設定項失敗:{detail}", - "retry": "重試", - "noConfigAvailable": "該智慧體沒有可設定項。", - "modeLabel": "模式", - "agentDefaultHint": "智慧體預設:{value}", - "defaultOptionLabel": "預設({value})" - }, - "actions": { - "dragSort": "拖拽排序", - "dragSortAgent": "拖拽排序 {name}", - "refreshCheck": "刷新檢測", - "refreshCheckAgent": "刷新檢測 {name}", - "clickEnable": "點擊啟用 {name}", - "clickDisable": "點擊停用 {name}", - "install": "安裝", - "upgrade": "升級", - "uninstall": "卸載", - "uninstalling": "卸載中...", - "saveEnvVars": "儲存環境變數", - "saving": "儲存中...", - "saveGrokConfig": "儲存 Grok 設定", - "saveCodexConfig": "儲存 Codex 配置", - "saveGeminiConfig": "儲存 Gemini 配置", - "saveOpenCodeConfig": "儲存 OpenCode 配置", - "saveOpenClawConfig": "儲存 OpenClaw 配置", - "saveConfigManagement": "儲存配置管理", - "saveCurrentProvider": "儲存目前 Provider", - "showApiKey": "顯示 API Key", - "hideApiKey": "隱藏 API Key", - "showKey": "顯示 Key", - "hideKey": "隱藏 Key", - "showToken": "顯示 Token", - "hideToken": "隱藏 Token", - "cancel": "取消", - "delete": "刪除", - "deleting": "刪除中...", - "confirmDelete": "確認刪除", - "confirmUninstall": "確認卸載", - "saveClineConfig": "儲存 Cline 配置", - "saveHermesConfig": "儲存 Hermes 配置", - "saveCodeBuddyConfig": "儲存 CodeBuddy 設定", - "saveKimiCodeConfig": "儲存 Kimi Code 設定", - "customInstall": "自訂安裝", - "saveKimiCodeRawConfig": "儲存 config.toml", - "saveDeepSeekConfig": "儲存 DeepSeek 設定", - "diagnose": "診斷" - }, - "status": { - "enabled": "啟用", - "disabled": "停用", - "unchecked": "未檢測", - "agentEnabledAria": "{name} 已啟用", - "agentEnabledSwitch": "{name} 啟用" - }, - "preflight": { - "count": "預檢項:{count}", - "notRun": "尚未執行檢測。" - }, - "grok": { - "configDescription": "在此設定 Grok。下方控制項——權限模式、推理強度、選用的自訂(自帶端點)模型與壓縮——會合併寫入 ~/.grok/config.toml,並保留你的其他鍵與註解。登入使用你的 XAI_API_KEY 或 `grok login`。其他鍵可在「進階」中編輯。", - "permissionModeLabel": "權限模式", - "permissionDefault": "每次詢問", - "permissionAcceptEdits": "自動批准編輯", - "permissionAuto": "智慧自動批准", - "permissionAlwaysApprove": "永遠允許", - "reasoningEffortLabel": "推理級別", - "effortLow": "低(較快)", - "effortMedium": "中(均衡)", - "effortHigh": "高", - "effortXhigh": "最高", - "optionDefault": "使用預設", - "authTitle": "驗證", - "authMode": "認證方式", - "authModeApiKey": "XAI API 金鑰", - "authModeApiKeyHint": "使用 xAI 主控台的 XAI_API_KEY 認證——適用於非互動/無頭執行。儲存在該智慧體的環境變數中。", - "authModeCustom": "自訂接口", - "authModeCustomHint": "使用自訂接口(BYO 端點):在下方定義一個帶有獨立 base URL 和 API 金鑰的自訂模型,它將成為 Grok 的預設模型。", - "subscriptionHint": "使用 `grok login` 登入(SuperGrok / X Premium+)。不會儲存 API 金鑰。", - "loginHint": "在終端機執行以下指令登入,然後重新開啟此設定:", - "commandCopied": "指令已複製到剪貼簿", - "copyCommand": "複製指令", - "authKeyConfigured": "已設定 XAI_API_KEY。", - "authKeyMissing": "未設定 XAI_API_KEY。", - "advancedToggle": "進階(原始 config.toml)", - "configTomlNative": "config.toml(原生)", - "configTomlHint": "按原樣整體寫入 ~/.grok/config.toml。非法 TOML 會被拒絕,絕不因筆誤截斷檔案。", - "configTomlPlaceholder": "# 上面控制項之外的鍵,例如\n# [mcp_servers.*]、[cli]、[permission] 規則。", - "customModelTitle": "自訂模型(自帶端點)", - "customModelHint": "讓 Grok 指向自訂或自架端點。codeg 會寫入按模型的 `[model.*]` 區塊並設為預設模型。清空模型 ID 即可移除。", - "customModelIdLabel": "模型 ID", - "customModelIdPlaceholder": "grok-4.5", - "customModelIdHint": "註冊為 `[model.*]` 區塊,並作為模型名稱傳送給 API;同時設為 `[models].default`。", - "customBaseUrlLabel": "Base URL", - "customBaseUrlPlaceholder": "https://api.x.ai/v1(預設)", - "customApiBackendLabel": "API 後端", - "backendResponses": "Responses", - "backendChatCompletions": "Chat Completions", - "backendMessages": "Messages(Anthropic)", - "customApiKeyLabel": "API Key", - "customApiKeyHint": "內聯儲存於 `[model.*].api_key`,僅作用於此端點。", - "customContextWindowLabel": "上下文視窗(tokens)", - "customContextWindowHint": "選填。用於自動壓縮計時;留空則使用端點預設值。", - "autoCompactLabel": "自動壓縮閾值(%)", - "autoCompactHint": "當上下文使用率達到此百分比時壓縮對話(Grok 預設 85)。寫入 `[session]`。" - }, - "cursor": { - "configDescription": "在此設定 Cursor。先選擇驗證方式——官網訂閱(瀏覽器登入)或用於無頭/伺服器的 Cursor API 金鑰——然後選擇模型並編輯 CLI 的權限規則與沙箱。codeg 會寫入 ~/.cursor/cli-config.json,與 cursor-agent CLI 共用。", - "authTitle": "驗證", - "authChecking": "檢測中…", - "authNotInstalled": "cursor-agent 未安裝", - "authLoggedIn": "已登入", - "authNotLoggedIn": "未登入", - "loginHint": "在終端機執行以下指令登入 Cursor 帳號(會開啟瀏覽器),完成後點重新整理:", - "apiKeyLabel": "Cursor API 金鑰", - "apiKeyPlaceholder": "在 cursor.com/dashboard 取得", - "apiKeyHint": "CURSOR_API_KEY —— Cursor Dashboard 的帳號金鑰,在無頭/伺服器環境下取代瀏覽器登入。不是第三方或 OpenAI 金鑰。", - "modelTitle": "預設模型", - "loadModels": "取得模型清單", - "modelsUnavailable": "模型清單不可用", - "modelHint": "會話啟動時透過 --model 傳給 CLI;保持預設則由 Cursor 自行選擇。", - "permissionsTitle": "權限與沙箱", - "permissionsDescription": "可視化編輯 CLI 權限規則(cli-config.json)。允許規則免確認執行;拒絕規則一律攔截。", - "permissionModeLabel": "權限模式", - "permissionModeDefault": "執行前詢問(預設)", - "permissionModeForce": "全部放行 Run Everything(--force)", - "permissionModeHint": "Run Everything 以 --force 啟動工作階段:除 deny 規則外的所有工具呼叫自動放行、不再跳出確認(組織政策可能將其降級為僅按 allow 規則放行)。對新工作階段生效。", - "optionDefault": "預設(未設定)", - "sandboxLabel": "沙箱", - "sandboxEnabled": "啟用", - "sandboxDisabled": "停用", - "allowRulesLabel": "允許規則", - "denyRulesLabel": "拒絕規則", - "addRule": "新增規則", - "rulesSyntaxHint": "規則語法:Shell(命令)、Read(路徑/萬用字元)、Write(路徑/萬用字元)、WebFetch(網域)、Mcp(伺服器:工具)——deny 規則始終優先。", - "saveConfig": "儲存設定", - "advancedToggle": "進階:原始 cli-config.json", - "advancedHint": "完整的 ~/.cursor/cli-config.json。此處儲存按原文寫入;上方結構化控制項則以合併方式寫入。", - "saveRawConfig": "儲存檔案", - "authMode": "認證方式", - "subscriptionHint": "使用 Cursor 帳號登入,使用 Cursor 的模型。", - "customApiKeyRequired": "需要填寫 Cursor API 金鑰。", - "authModeApiKey": "Cursor API 金鑰(無頭/伺服器)", - "authModeApiKeyHint": "使用 Cursor 官網 Dashboard 產生的帳號 API 金鑰進行驗證(適用於無頭/伺服器環境)。這是 Cursor 帳號金鑰,不是第三方/OpenAI 端點——cursor-agent 只會連線到 Cursor 自己的後端。若要使用 codex/OpenAI 相容端點,請改用 Codex 智慧體。", - "modelPickerPlaceholder": "搜尋模型…", - "modelNoMatch": "沒有相符的模型", - "modelsNeedAuth": "登入後載入模型清單。", - "modelDefaultBadge": "預設" - }, - "deepseek": { - "configManagement": "DeepSeek Harness 設定", - "configDescription": "端點與金鑰是 deepseek-acp 啟動時讀取的環境變數。模型與推理等級是工作階段層級的選擇器,在輸入框裡切換。", - "baseUrlLabel": "API 端點", - "baseUrlHint": "留空則使用官方端點。儲存後對新建的工作階段生效——正在進行的工作階段需要重新連線才會切換。", - "baseUrlInvalid": "請填寫完整的 http(s) 網址且不帶查詢參數,例如 https://api.deepseek.com", - "apiKeyLabel": "API 金鑰", - "apiKeyHint": "以 DEEPSEEK_API_KEY 傳給智慧體。環境變數的優先權高於憑證檔,因此若用終端機登入,這裡留空即可。" - }, - "codex": { - "configDescription": "支援 API URL、API Key、模型名稱、Reasoning Effort 快捷配置,並與 `auth.json` / `config.toml` 雙向聯動。", - "authMode": "認證方式", - "chatgptSubscription": "官網訂閱", - "chatgptSubscriptionHint": "使用 ChatGPT 官網訂閱登入,無需配置 API Key", - "apiKeyHint": "使用 API Key 連接 OpenAI 或相容的 API 服務", - "selectProvider": "選擇 Provider", - "modelName": "模型名稱", - "selectReasoningEffort": "選擇 Reasoning Effort", - "enableWebsocket": "啟用 WebSocket", - "enableWebsocketAria": "Codex Provider 啟用 WebSocket", - "enableSkills": "啟用 Skills", - "enableSkillsAria": "Codex 啟用 Skills", - "enableFast": "啟用 Fast", - "enableFastAria": "Codex 啟用 Fast 服務等級", - "sandboxGroupTitle": "沙箱與審批", - "sandboxGroupHint": "寫入全域 ~/.codex/config.toml,codex CLI 與 IDE 的工作階段同樣生效。這是執行緒預設值,只作用於 codex 自行發起的回合(/goal、/review、/compact);一般對話使用輸入框裡的審批預設。變更需重開工作階段才生效。", - "sandboxShadowedWarning": "config.toml 裡設定了 default_permissions,codex 會改走權限設定檔並完全忽略 sandbox_mode。刪除 default_permissions 後下面的選項才會生效。", - "sandboxPermissionsTableWarning": "config.toml 定義了 [permissions] 設定檔卻沒有 default_permissions,codex 會拒絕啟動。請在下方原始編輯器裡補上。", - "approvalPolicyLabel": "審批策略", - "approvalPolicyUnset": "未設定(codex 預設:依需求詢問)", - "approvalPolicy_on-request": "依需求詢問 — 由模型決定何時請求批准", - "approvalPolicy_untrusted": "僅信任唯讀 — 只有已知安全的唯讀指令免批准", - "approvalPolicy_never": "從不詢問 — 完全不彈審批", - "approvalPolicy_granular": "精細控制 — 依提示類型分別設定", - "approvalPolicyUntrustedAcpWarning": "ACP 轉接器只有三種審批預設,untrusted 無對應項,codeg 工作階段會退回「按需詢問」——此時由模型自行決定何時詢問,沙箱本就允許的命令不再詢問。請改用下方的沙箱模式收緊。", - "granularHint": "關閉表示該類請求會被自動拒絕,而不是彈給你確認。", - "granular_sandbox_approval": "Shell 指令越權申請", - "granular_rules": "Execpolicy 規則提示", - "granular_skill_approval": "技能指令碼執行提示", - "granular_request_permissions": "request_permissions 工具提示", - "granular_mcp_elicitations": "MCP elicitation 提示", - "sandboxModeLabel": "沙箱模式", - "sandboxModeUnset": "未設定(受信任的資料夾回落為可寫工作區)", - "sandboxMode_read-only": "唯讀", - "sandboxMode_workspace-write": "可寫工作區", - "sandboxMode_danger-full-access": "完全開放(無沙箱)", - "sandboxModeHint": "在 Windows 上,未開啟 codex 的實驗性 Windows 沙箱時,可寫工作區會被降級為唯讀。", - "sandboxModeSeedsPresetHint": "codeg 還會用它推導工作階段的初始審批預設,因此與審批策略不同,它對一般提問同樣生效。輸入框中選擇的預設仍會覆蓋它。", - "writableRootsLabel": "額外可寫目錄", - "writableRootsHint": "每行一個絕對路徑,作為工作目錄之外的額外可寫位置。", - "sandboxRootsRelativeError": "必須是絕對路徑 — codex 會把相對路徑解析到 ~/.codex 底下:{path}", - "networkAccessLabel": "允許網路存取", - "excludeTmpdirLabel": "從可寫目錄中排除 TMPDIR", - "excludeSlashTmpLabel": "從可寫目錄中排除 /tmp", - "authJsonNative": "auth.json(原生)", - "configTomlNative": "config.toml(原生)", - "loginButton": "使用 ChatGPT 登入", - "loginRequesting": "正在請求登入碼...", - "loginStep1": "在瀏覽器中打開以下連結:", - "loginStep2": "輸入以下代碼:", - "loginPolling": "等待授權中...", - "loginCancel": "取消", - "loginSuccess": "登入成功,配置已儲存!", - "loginFailed": "登入失敗:{message}", - "loginRetry": "重試", - "loginCodeCopied": "已複製代碼", - "loggedIn": "帳號已登入", - "loginRelogin": "重新登入 / 切換帳號", - "loginTimeout": "登入逾時,請重試", - "loginSaveFailed": "登入成功但配置儲存失敗" - }, - "gemini": { - "authConfig": "Gemini 認證配置", - "authConfigDescription": "對齊 Gemini CLI 認證文件,支援自訂、Google 登入、Gemini API Key、Vertex AI(ADC / 服務帳號 / API Key)。", - "authMode": "認證方式", - "selectAuthMode": "選擇認證方式", - "viewAuthDoc": "查看認證文件", - "mode": { - "custom": "自訂介面", - "loginGoogle": "Google 登入(OAuth)", - "vertexServiceAccount": "Vertex AI(服務帳號)" - }, - "hint": { - "custom": "填寫 API URL、API Key 和 Model,分別映射到 GOOGLE_GEMINI_BASE_URL / GEMINI_API_KEY / GEMINI_MODEL。", - "loginGoogle": "首次在終端執行 gemini 並完成 Google 登入;無需填寫 API Key。", - "geminiApiKey": "使用 Gemini API 時填寫 GEMINI_API_KEY。", - "vertexAdc": "使用 gcloud ADC,建議填寫 GOOGLE_CLOUD_PROJECT 與 GOOGLE_CLOUD_LOCATION。", - "vertexServiceAccount": "服務帳號 JSON 路徑寫入 GOOGLE_APPLICATION_CREDENTIALS。", - "vertexApiKey": "使用 Vertex AI API key 時填寫 GOOGLE_API_KEY。" - } - }, - "openCode": { - "configManagement": "OpenCode 配置管理", - "configDescription": "對齊 OpenCode `provider` 配置結構,支援多供應商管理,並與原生 JSON 檔案雙向聯動。", - "providerManagement": "Provider 管理", - "providerCount": "共 {count} 個", - "addProvider": "新增 Provider", - "emptyProvider": "還沒有自訂 Provider。點擊「新增自訂 Provider」建立。", - "providerEnabledState": "{providerId} 啟用狀態", - "selectProviderNpm": "選擇 provider.npm", - "modelManagement": "模型管理", - "modelCount": "共 {count} 個", - "modelDescription": "對齊 OpenCode `provider.models` 結構。目前支援 `name` / `id` 快速管理;其它進階欄位會保留,可在下方原生 JSON 中繼續編輯。", - "addModel": "新增模型", - "emptyModel": "暫無模型,輸入 model id 後點擊「新增模型」建立。", - "modelId": "模型 ID", - "modelName": "模型名稱", - "deleteModel": "刪除模型 {modelId}", - "nativeJsonConfig": "OpenCode 原生 JSON 配置", - "mainModel": "主模型", - "smallModel": "小模型", - "noMatchingModels": "沒有匹配的模型", - "connectProvider": "連接 Provider", - "connectedProviders": "已連接的 Provider", - "noConnectedProviders": "還沒有從目錄連接 Provider。", - "advancedProviderConfig": "自訂 Provider", - "customProviderConfigHint": "你自己定義的 OpenAI 相容端點——opencode.json 裡的一個 provider 設定區塊,API key 存在 auth.json。", - "addCustomProvider": "新增自訂 Provider", - "disconnect": "中斷連接", - "editConfig": "編輯", - "customBadge": "自訂", - "authKindApi": "API Key", - "authKindOauth": "OAuth", - "authKindNone": "無憑證", - "connect": { - "title": "連接 Provider", - "description": "從 models.dev 目錄選擇一個 Provider。憑證儲存到 OpenCode 的 auth.json 檔案。", - "pick": "Provider", - "search": "搜尋 Provider…", - "loading": "正在載入目錄…", - "catalogLabel": "models.dev 目錄", - "modelsAvailable": "{count} 個可用模型", - "getKey": "取得 API Key", - "oauthApiKeyNote": "此 Provider 也支援透過 opencode auth login 瀏覽器登入。瀏覽器登入即將推出——目前請貼上 API Key。", - "apiKey": "API Key", - "apiKeyHint": "儲存在 auth.json,絕不寫入 opencode.json。", - "baseUrlOptional": "Base URL 覆寫(選填)", - "providerId": "Provider ID", - "displayName": "顯示名稱", - "modelsList": "模型(每行一個)", - "modelsHint": "端點接受的模型 ID。", - "action": "連接", - "editTitle": "編輯 Provider", - "editDescription": "更新該 Provider 的 API Key 或 Base URL。", - "saveAction": "儲存" - }, - "customProvider": { - "title": "新增自訂 Provider", - "description": "定義一個 OpenAI 相容端點。API key 儲存到 auth.json;provider 設定區塊寫入 opencode.json。", - "action": "新增 Provider", - "idInCatalog": "{providerId} 是已知 Provider,請改用「連接 Provider」連接。" - }, - "refreshCatalog": "重新整理目錄", - "reasoningBadge": "推理", - "contextWindow": "上下文視窗", - "permissions": { - "title": "權限", - "description": "決定哪些操作直接執行、先徵求你的同意,還是被阻擋。寫入 opencode.json 的 permission 設定,點擊下方儲存後生效。", - "docsLink": "權限文件", - "unparsableConfig": "下方的原生 JSON 目前無法解析,視覺化編輯已暫停。修正 JSON 後即可繼續。", - "invalidBlock": "permission 設定的結構無法辨識。請在下方原生 JSON 中修改,或點擊「恢復預設」重來。", - "orderingUnsafe": "萬用規則寫在了具體工具之後,OpenCode 會把它一併套用到這些工具上——下方各列顯示的並非實際生效的規則。「修正順序」只把萬用規則移回各自範圍的最前面,不更動任何值。", - "orderingUnsafeManual": "有規則被後面更寬鬆的模式遮蔽,OpenCode 永遠不會套用它——下方各列顯示的並非實際生效的規則。兩個互相重疊的模式沒有唯一正確的順序,請在下方原生 JSON 中調整,把較寬鬆的寫在前面。", - "fixOrder": "修正順序", - "agentOverrides": "下列智慧代理個別覆寫了權限,且在最後套用,因此會蓋過此處的所有設定:{agents}。請在下方原生 JSON 中修改,或開啟「自動接受所有權限」將其清除。", - "legacyTools": "頂層的舊版 tools 設定停用了某個工具。OpenCode 會把它併入權限,因此會疊加在此處顯示的所有設定之上。請在下方原生 JSON 中修改,或開啟「自動接受所有權限」將其清除。", - "autoAcceptTitle": "自動接受所有權限", - "autoAcceptHint": "所有工具呼叫(shell 指令、檔案修改、存取專案外路徑)都不再詢問,直接執行。開啟後會以一條全域允許規則取代下方的逐工具設定,並清除各智慧代理個別的權限覆寫與舊版 tools 開關——否則它們仍會攔截。", - "globalLabel": "全域預設", - "globalHint": "即 * 規則:下方工具未個別覆寫時採用的動作。", - "actionUnset": "未設定(OpenCode 預設)", - "actionInherit": "沿用預設({action})", - "actionAllow": "允許", - "actionAsk": "詢問", - "actionDeny": "拒絕", - "perToolTitle": "逐工具權限", - "reset": "恢復預設", - "ruleCount": "細則 {count} 條", - "rulesToggle": "{tool} 的細緻規則", - "rulesHint": "依工具輸入比對,最後符合的規則優先,因此請把寬鬆的模式寫在前面。* 比對任意多個字元,? 精確比對一個字元,開頭的 ~ 會展開為主目錄。", - "noRules": "尚無細緻規則。", - "addRule": "新增規則", - "deleteRule": "刪除規則 {pattern}", - "duplicateRule": "此模式已存在。", - "blankRule": "規則必須有模式;如需刪除請點擊垃圾桶圖示。", - "customKeys": "檔案中的其他權限鍵", - "customKeyHint": "並非 OpenCode 內建工具,將原樣保留。", - "keys": { - "bash": "執行 shell 指令,依解析後的指令比對", - "edit": "所有檔案修改:edit、write 與 patch", - "read": "讀取檔案,依檔案路徑比對", - "external_directory": "存取專案工作目錄之外的路徑", - "task": "啟動子代理,依子代理類型比對", - "skill": "載入技能,依技能名稱比對", - "glob": "尋找檔案,依萬用字元模式比對", - "grep": "搜尋檔案內容,依模式比對", - "list": "列出目錄內容", - "webfetch": "擷取 URL", - "websearch": "網頁搜尋", - "lsp": "執行 LSP 查詢", - "todowrite": "寫入待辦清單", - "question": "向你提問", - "doom_loop": "同一呼叫以相同輸入重複 3 次時觸發" - } - } - }, - "openClaw": { - "gatewayConfig": "Gateway 配置", - "gatewayDescription": "配置 OpenClaw Gateway 連線資訊。支援本地或遠端 Gateway。", - "gatewayUrlHint": "留空則使用 openclaw 本地配置的 gateway.remote.url。", - "gatewayTokenPlaceholder": "Gateway 認證 Token", - "gatewayTokenHint": "建議使用 token-file 取代明文 Token,可透過 openclaw 命令列配置。", - "sessionKeyHint": "可選。指定 Gateway Session Key,留空則自動分配隔離會話。" - }, - "hermes": { - "configManagement": "Hermes 配置", - "configDescription": "Hermes 在 ~/.hermes/.env 中管理自己的憑證,在 ~/.hermes/config.yaml 中管理設定。選擇一個供應商,然後設定 API 金鑰與模型——codeg 會替你寫入這兩個檔案。", - "providerLabel": "供應商", - "providerHint": "供應商決定 Hermes 使用哪個 API 金鑰變數與 model.provider。OAuth 供應商透過下方的終端機設定進行設定。", - "groupApiKey": "API 金鑰供應商", - "groupOauth": "OAuth 供應商", - "groupAws": "AWS", - "apiKeyHint": "儲存到 ~/.hermes/.env。它絕不會被注入行程——Hermes 會從自己的設定中讀取它。", - "modelName": "模型", - "oauthHint": "此供應商使用 OAuth。請執行下方的設定流程,在終端機中完成驗證。", - "awsHint": "Bedrock 使用你的 AWS 憑證(環境變數或共用設定)。請在上方填寫模型 ID,並在系統環境中設定 AWS 存取權限。", - "unsupportedProvider": "此供應商無法透過結構化欄位編輯。請使用下方的 config.yaml 原始編輯器或終端機引導設定。", - "setupTitle": "自管理設定", - "setupHint": "Hermes 的互動式設定需要終端機。可在下方啟動,或複製指令自行執行。", - "runSetup": "執行 Hermes 設定", - "configureModel": "設定模型", - "openConfigFolder": "開啟 ~/.hermes", - "copyCommand": "複製指令", - "commandCopied": "指令已複製到剪貼簿", - "advancedTitle": "進階:編輯 config.yaml", - "rawConfigHint": "直接編輯 ~/.hermes/config.yaml。在此儲存將原樣覆寫該檔案。", - "saveRawConfig": "儲存 config.yaml" - }, - "codebuddy": { - "configManagement": "CodeBuddy 設定", - "configDescription": "CodeBuddy 使用 API Key 進行驗證。中國版還必須將環境設為「中國版(internal)」;iOA 版使用「iOA」;海外版則不設定。", - "apiKeyLabel": "API Key", - "apiKeyHint": "將作為此智能體的 CODEBUDDY_API_KEY 儲存。也可以在終端機用 CodeBuddy CLI 登入。", - "apiKeyHintSelfHosted": "將作為此智能體的 CODEBUDDY_API_KEY 儲存。請使用你的私有化部署簽發的金鑰。", - "environmentLabel": "環境", - "environmentHint": "設定 CODEBUDDY_INTERNET_ENVIRONMENT。中國大陸必須使用「中國版(internal)」;海外版則不設定。", - "envOverseas": "海外版(預設)", - "envChina": "中國版(internal)", - "envIoa": "iOA", - "envSelfHosted": "私有化部署", - "baseUrlLabel": "私有化部署位址", - "baseUrlPlaceholder": "https://codebuddy.your-company.com", - "baseUrlHint": "儲存為 CODEBUDDY_BASE_URL,將 CodeBuddy 指向你的私有端點。私有化部署不設定網路環境(CODEBUDDY_INTERNET_ENVIRONMENT)。", - "baseUrlInvalid": "請輸入合法的 http(s) 位址。", - "loginHint": "沒有 API Key?也可以在終端機執行「codebuddy」用騰訊雲帳號登入。" - }, - "kimiCode": { - "configManagement": "Kimi Code 設定", - "configDescription": "`kimi acp` 只認已儲存的登入權杖,所以 codeg 會在 ~/.kimi-code/config.toml 寫入受管供應商,並在本機植入一個門控權杖——推論仍然走你自己的 Key。", - "statusUnconfigured": "尚未設定", - "statusDirty": "有未儲存的變更", - "summaryLabel": "生效設定", - "gateReadyApiKey": "API Key 已寫入 config.toml", - "gateReadyLogin": "已透過 Kimi 帳號登入", - "revealConfig": "在資料夾中顯示", - "envOverrideWarning": "偵測到 {keys},其優先權高於 config.toml。在此儲存會自動清除它。", - "authModeLabel": "驗證方式", - "authModeApiKey": "API Key", - "authModeLogin": "Kimi 帳號登入(訂閱)", - "authModeApiKeyHint": "在 config.toml 寫入受管供應商,並植入門控權杖以便工作階段能夠開啟。", - "loginHint": "在終端機執行 `kimi login`,用 Kimi 訂閱帳號登入。codeg 不儲存任何憑證,沿用 Kimi 自己的登入。在此儲存會移除 codeg 的 API Key 門控權杖。", - "credentialTitle": "憑證", - "interfaceTypeLabel": "供應商類型", - "interfaceTypeHint": "Kimi 使用的供應商協定(config.toml 的 `type`)。Moonshot / platform.kimi.com 的 Key 請選「Kimi / Moonshot」。", - "endpointLabel": "接入點", - "endpointCustom": "自訂(OpenAI 相容)", - "endpointHint": "國際 = api.moonshot.ai;中國(platform.kimi.com 的 Key)= api.moonshot.cn。自訂可指向任意 OpenAI 相容端點。", - "regionInternational": "國際(api.moonshot.ai)", - "regionChina": "中國(api.moonshot.cn)", - "baseUrlLabel": "Base URL", - "baseUrlHint": "留空則使用供應商 SDK 預設值。", - "apiKeyLabel": "API Key", - "apiKeyHint": "寫入 ~/.kimi-code/config.toml 並用於推論。來自 platform.kimi.com 或 platform.kimi.ai。", - "vertexProjectLabel": "GCP 專案(GOOGLE_CLOUD_PROJECT)", - "vertexLocationLabel": "GCP 區域(GOOGLE_CLOUD_LOCATION)", - "vertexHint": "Vertex AI 使用 Google 應用程式預設憑證——執行 `gcloud auth application-default login`(不需 API Key)。", - "modelTitle": "模型", - "modelLabel": "模型", - "modelHint": "寫入 config.toml 的模型 id。點「測試並取得模型」可查看你的 Key 實際能存取哪些模型。", - "maxContextLabel": "最大上下文長度", - "maxContextHint": "Kimi 的設定 schema 要求必填:缺少會讓 Kimi 丟棄整個模型區塊,導致每次對話都沒有回覆。預設 262144。", - "fetchModels": "測試並取得模型", - "fetchModelsOk": "Key 可用——共 {count} 個模型", - "fetchModelsEmpty": "Key 可用,但未回傳任何模型", - "fetchModelsFailed": "測試失敗", - "fetchModelsNeedsKey": "請先填寫 API Key 和接入點", - "modelNotInList": "該模型不在你的 Key 可存取清單中,Kimi 會回報「模型不存在」。", - "reasoningTitle": "推理", - "reasoningEnableLabel": "啟用", - "reasoningDescription": "只有當模型宣告了推理能力,Kimi 才會在輸入框顯示「Thinking」選擇器,所以這裡由 codeg 寫入該宣告。對新建工作階段生效。", - "effortsLabel": "可選檔位", - "effortsHint": "這些會成為輸入框「Thinking」選擇器裡的檔位。Kimi 會把檔位原樣轉傳給供應商,請選你的模型能接受的值。", - "effortsEmptyHint": "一個檔位都不選時,輸入框只會退化成 Off / On 兩檔開關。", - "effortsCustomPlaceholder": "新增其他檔位", - "effortsAdd": "新增", - "defaultEffortLabel": "預設檔位", - "defaultEffortAuto": "由 Kimi 決定", - "alwaysThinkingLabel": "模型始終推理——從選擇器中移除 Off 檔", - "fixErrorsFirst": "請先修正標紅的欄位", - "errorModelRequired": "模型為必填欄位", - "errorMaxContextRequired": "最大上下文長度為必填欄位", - "errorMaxContextInvalid": "必須是正整數", - "errorApiKeyRequired": "API Key 為必填欄位", - "errorApiKeyInvalid": "API Key 不能包含換行", - "errorBaseUrlRequired": "Base URL 為必填欄位", - "errorBaseUrlInvalid": "必須以 http:// 或 https:// 開頭", - "errorVertexProjectRequired": "GCP 專案為必填欄位", - "errorDefaultEffortUnlisted": "必須是上面已選取的檔位之一", - "advancedTitle": "進階", - "authTypeLabel": "憑證寫入位置", - "authTypeApiKey": "內聯 api_key", - "authTypeEnv": "供應商 env 子表", - "authTypeHint": "API Key 在 config.toml 中的寫入位置。", - "rawEditorLabel": "直接編輯 config.toml", - "rawEditorWarning": "在此儲存會按原文覆寫整個檔案,取代掉上方的結構化設定。", - "rawEditorPlaceholder": "[providers.codeg]\ntype = \"kimi\"\nbase_url = \"https://api.moonshot.cn/v1\"\napi_key = \"sk-...\"" - }, - "authModeOfficialSubscription": "官網訂閱", - "authModeCustomEndpoint": "自定義介面", - "authModeCustomEndpointHint": "手動配置 API URL 和 API Key 連接自定義介面。", - "authModeModelProvider": "模型供應商", - "modelProvider": "模型供應商", - "modelProviderHint": "使用已配置的模型供應商的 API URL、API Key 和模型。", - "selectModelProvider": "選擇模型供應商", - "noModelProviderAvailable": "該代理未配置模型供應商。請前往模型供應商設定添加。", - "claude": { - "authMode": "認證方式", - "officialSubscription": "官方訂閱", - "officialSubscriptionHint": "使用 Anthropic 官方訂閱,無需 API Key。", - "mainModel": "主模型", - "reasoningModel": "推理模型(thinking)", - "haikuDefaultModel": "Haiku 預設模型", - "sonnetDefaultModel": "Sonnet 預設模型", - "opusDefaultModel": "Opus 預設模型", - "customModelOption": "自訂模型 ID", - "customModelOptionName": "自訂模型名稱", - "customModelOptionDescription": "自訂模型描述", - "customModelOptionHint": "在 Claude 模型選擇器中新增一個自訂項目(例如透過自訂閘道/代理提供的模型)。名稱與描述為選填的顯示資訊。", - "effortLevel": "推理等級", - "effortLevelDefault": "預設等級", - "effortLevel_low": "低", - "effortLevel_medium": "中", - "effortLevel_high": "高", - "effortLevel_xhigh": "超高", - "sendAttributionHeader": "向介面傳送歸屬/計費識別碼", - "sendAttributionHeaderAria": "向介面傳送 Claude Code 歸屬/計費識別碼", - "disableNonessentialTraffic": "停用遙測或多餘的網路請求", - "disableNonessentialTrafficAria": "停用 Claude Code 遙測或多餘的網路請求" - }, - "dialogs": { - "confirmDeleteProvider": "確認刪除 Provider {providerId}?", - "confirmDeleteProviderDescription": "將同步更新 OpenCode 配置與認證 JSON 檔案,刪除後不可恢復。", - "confirmUninstall": "確認卸載 {name}?", - "confirmUninstallDescription": "這會移除本地安裝版本,之後可隨時重新安裝。", - "customInstallTitle": "自訂安裝 {name}", - "customInstallDescription": "輸入要安裝的版本號。將重新安裝並替換目前已安裝的版本。", - "customInstallVersionLabel": "版本號", - "customInstallInvalid": "請輸入有效的版本號,例如 1.2.3。", - "customInstallSubmit": "安裝" - }, - "errors": { - "windowsFileLocked": "{name} 的程式檔案正被執行中的工作階段佔用,Windows 下無法替換。請先關閉所有 {name} 工作階段後重試。", - "nativeJsonMustBeObject": "原生 JSON 配置必須是物件", - "nativeJsonInvalid": "原生 JSON 配置格式錯誤:{message}", - "openCodeAuthMustBeObject": "OpenCode auth.json 必須是 JSON 物件", - "openCodeAuthInvalid": "OpenCode auth.json 格式錯誤:{message}", - "authMustBeObject": "auth.json 必須是 JSON 物件", - "authInvalid": "auth.json 格式錯誤:{message}", - "providerIdPattern": "Provider ID 僅支援字母、數字、底線、點與中劃線", - "providerExists": "Provider {providerId} 已存在", - "modelIdPattern": "模型 ID 僅支援字母、數字、底線、點、冒號與中劃線", - "modelExists": "Model {modelId} 已存在" - }, - "warnings": { - "nativeJsonRecoveredStructured": "原生 JSON 配置格式無效,已重置為結構化配置", - "nativeJsonRecoveredOpenCode": "原生 JSON 配置格式無效,已重置為 OpenCode 結構化配置", - "openCodeAuthRecovered": "OpenCode auth.json 格式無效,已重置為預設配置", - "authRecoveredStructured": "auth.json 格式無效,已重置為結構化配置" - }, - "toasts": { - "agentActionCompleted": "{name}{action}完成", - "agentActionFailed": "{name}{action}失敗", - "localVersion": "本地版本:{version}", - "installCompletedVersionLater": "安裝完成,版本將在下一次檢測時更新", - "uninstallCompleted": "{name}卸載完成", - "uninstallFailed": "{name}卸載失敗", - "localVersionRemoved": "本地版本已移除", - "saveAgentOrderFailed": "儲存 Agent 排序失敗", - "saveAgentSwitchFailed": "儲存 Agent 開關失敗", - "saveEnvFailed": "儲存環境變數失敗", - "grokSaved": "Grok 設定已儲存", - "saveGrokNativeFailed": "儲存 Grok 原生設定失敗", - "saveGrokApiKeyFailed": "設定已儲存,但 API Key 未能儲存", - "cursorSaved": "Cursor 設定已儲存", - "saveCursorConfigFailed": "儲存 Cursor 設定失敗", - "codexSaved": "Codex 配置已儲存", - "saveCodexNativeFailed": "儲存 Codex 原生配置失敗", - "geminiSaved": "Gemini 配置已儲存", - "saveGeminiFailed": "儲存 Gemini 配置失敗", - "providerDeleted": "Provider {providerId} 已刪除", - "providerDeleteFailed": "刪除 Provider {providerId} 失敗", - "providerSaved": "Provider {providerId} 儲存成功", - "saveProviderFailed": "儲存 Provider {providerId} 失敗", - "openCodeConfigSynced": "OpenCode 配置與認證 JSON 已同步儲存。", - "openCodeSaved": "OpenCode 配置已儲存", - "saveOpenCodeFailed": "儲存 OpenCode 配置失敗", - "openClawSaved": "OpenClaw 配置已儲存", - "saveOpenClawFailed": "儲存 OpenClaw 配置失敗", - "configSaved": "配置已儲存", - "configSavedHint": "已有會話需要重新打開才能生效", - "saveConfigManagementFailed": "儲存配置管理失敗", - "clineSaved": "Cline 配置已儲存", - "saveClineFailed": "儲存 Cline 配置失敗", - "hermesSaved": "Hermes 配置已儲存", - "saveHermesFailed": "儲存 Hermes 配置失敗", - "codeBuddySaved": "CodeBuddy 設定已儲存", - "saveCodeBuddyFailed": "儲存 CodeBuddy 設定失敗", - "kimiCodeSaved": "Kimi Code 設定已儲存", - "saveKimiCodeFailed": "儲存 Kimi Code 設定失敗", - "deepseekSaved": "DeepSeek 設定已儲存", - "saveDeepSeekFailed": "儲存 DeepSeek 設定失敗", - "modelProviderRequired": "請先選擇一個模型供應商再儲存。", - "affectedRunningSessions": "{count} 個進行中的工作階段需重新連線以套用變更", - "providerConnected": "已連接 {providerId}", - "connectFailed": "連接 {providerId} 失敗", - "providerDisconnected": "已中斷 {providerId}", - "disconnectFailed": "中斷 {providerId} 失敗", - "catalogRefreshed": "目錄已重新整理——{count} 個 provider", - "catalogRefreshFailed": "重新整理目錄失敗", - "piSaved": "Pi 設定已儲存", - "savePiFailed": "儲存 Pi 設定失敗", - "piRuntimeSaved": "Pi 執行環境已儲存", - "savePiRuntimeFailed": "儲存 Pi 執行環境失敗", - "piBinaryInstalled": "pi 已安裝", - "piBinaryInstallFailed": "pi 安裝失敗", - "piBinaryUninstalled": "pi 已解除安裝", - "piBinaryUninstallFailed": "pi 解除安裝失敗", - "savePiTrustFailed": "儲存工作區信任失敗" - }, - "version": { - "statusLabel": "版本狀態", - "notInstalled": "未安裝", - "remoteLocal": "遠端:{remoteVersion} · 本地:{localVersion}", - "localOnly": "本機:{localVersion}", - "localInstalled": "{versionText}。已安裝。", - "platformUnsupported": "{versionText}。目前平台不支援該 Agent。", - "uvxNotReady": "{versionText}。uv 執行階段未安裝——請在下方 uv 預檢項中安裝後再使用該 Agent。", - "clickInstall": "{versionText}。請點擊右側安裝。", - "localUnrecognized": "{versionText}。本地版本無法識別,可嘗試升級覆蓋安裝。", - "upgradeAvailable": "{versionText}。發現可升級版本。", - "remoteUnavailable": "{versionText}。遠端版本暫不可用。", - "latest": "{versionText}。已是最新版本。" - }, - "adapter": { - "label": "ACP 轉接器", - "badge": "ACP 轉接器", - "badgeHint": "Codeg 為此智能體安裝的是 ACP 轉接器套件,而不是廠商 CLI —— 兩者各自獨立,設定共用。", - "learnMore": "了解詳情", - "missingWithNative": "已偵測到你本機的 {nativeLabel}:{nativePath}。Codeg 透過 ACP 協定驅動智能體,而該 CLI 本身不支援 ACP,所以 Codeg 需要獨立的轉接器套件 {adapterPackage}(由 Agent Client Protocol 專案維護,最初由 Zed 團隊發起)。它自帶執行環境,不會修改或取代你的 {nativeCmd} 指令,讀取的也是同一個 {configDir} —— 既有的登入與設定可直接沿用。點擊下方安裝即可。", - "missing": "Codeg 透過 ACP 協定驅動智能體,而 {nativeLabel} 本身不支援 ACP,所以 Codeg 需要獨立的轉接器套件 {adapterPackage}(由 Agent Client Protocol 專案維護,最初由 Zed 團隊發起)。它自帶執行環境,因此不必先安裝 {nativeCmd} CLI;若你已經安裝,兩者可以並存,並共用 {configDir} 中的登入與設定。點擊下方安裝即可。", - "readyWithNative": "轉接器 {adapterCmd} 已安裝 —— Codeg 啟動的是它,而不是你本機的 {nativeCmd}({nativePath})。兩者是各自獨立的套件,可以並存,且都讀取 {configDir},登入與設定共用。", - "ready": "轉接器 {adapterCmd} 已安裝 —— Codeg 啟動的就是它。它自帶執行環境,所以不需要另外安裝 {nativeLabel};即使日後你安裝了,兩者也能並存並共用 {configDir}。" - }, - "cline": { - "configDescription": "配置 Cline API 提供商和憑證。設定將儲存到 ~/.cline/data/。" - }, - "opencodePlugins": { - "title": "OpenCode 外掛", - "declared": "已宣告的外掛", - "noPlugins": "opencode.json 中未宣告任何外掛", - "status": { - "installed": "已安裝", - "missing": "未安裝" - }, - "installAll": "安裝全部缺失外掛", - "pinVersions": "固定 @latest 版本", - "install": "安裝", - "uninstall": "解除安裝", - "refresh": "重新整理", - "success": "所有外掛安裝成功", - "failed": "外掛操作失敗" - }, - "pi": { - "configManagement": "Pi 設定", - "configDescription": "Pi 透過模型提供方的 API Key 驗證。Key 寫入 ~/.pi/agent/auth.json,模型選擇寫入 settings.json。", - "providerLabel": "提供方", - "modelLabel": "模型", - "thinkingLabel": "思考", - "thinking": { - "off": "關閉", - "low": "低", - "medium": "中", - "high": "高", - "minimal": "極低", - "xhigh": "極高" - }, - "apiKeyLabel": "API Key", - "apiKeyHint": "為所選提供方寫入 ~/.pi/agent/auth.json。", - "apiKeySetPlaceholder": "•••••• (已儲存,留空則保持不變)", - "saveConfig": "儲存 Pi 設定", - "providerModelRequired": "提供方與模型為必填", - "runtimeTitle": "執行環境", - "runtimeDescription": "選擇執行哪個 pi。使用預設,或指向你自己的 pi 建置。", - "modeDefault": "預設 pi", - "modeDefaultHint": "使用內建 pi-acp 轉接器拉起 PATH 上的 pi。 安裝 pi:npm install -g @earendil-works/pi-coding-agent", - "modeCustom": "自訂 pi", - "modeCustomHint": "執行你自己的 pi 建置、安裝或包裝腳本。", - "commandLabel": "pi 命令或路徑", - "commandHint": "絕對路徑、PATH 上的命令名,或包裝腳本(如 monorepo 的 ./pi-test.sh)。", - "commandNotFound": "找不到命令", - "validate": "驗證", - "advanced": "進階", - "configDirLabel": "設定目錄 (PI_CODING_AGENT_DIR)", - "sessionDirLabel": "工作階段目錄 (PI_CODING_AGENT_SESSION_DIR)", - "flagsHint": "pi-acp 不會轉發自訂 pi 參數(--approve、-e 等)——用腳本包裝 pi 並將命令指向它。", - "customIncomplete": "請輸入 pi 命令以儲存", - "saveRuntime": "儲存執行環境", - "providerPlaceholder": "選擇供應方", - "customProvider": "自訂供應方…", - "providerIdLabel": "供應方 ID", - "apiProtocolLabel": "API 協定", - "baseUrlLabel": "介接位址(Base URL)", - "customProviderHint": "在 ~/.pi/agent/models.json 中依你的介接位址定義一個供應方。多數自架或代理服務使用 openai-completions。", - "baseUrlRequired": "介接位址(Base URL)為必填", - "binaryTitle": "pi 二進位 (pi-coding-agent)", - "binaryDescription": "pi-acp 會執行此 pi 二進位。可在此安裝,或在下方指向你自己的組建。", - "binaryInstalled": "已安裝", - "binaryMissing": "未安裝", - "binaryChecking": "偵測中…", - "installBinary": "安裝 pi", - "installing": "安裝中…", - "recheck": "重新偵測", - "configDirSkillsNote": "設定自訂組態目錄後,設定頁中管理的技能、專家與辦公工具將不會套用至該 pi;請直接在該目錄中管理其技能。", - "projectTrustTitle": "專案信任", - "projectTrustDescription": "你允許 pi 從中載入專案檔案的目錄。被信任的目錄會讓該儲存庫的 .pi/extensions 在 pi 啟動時執行程式碼,且對其下所有子目錄同樣生效,你在終端機執行 pi 時也會沿用。", - "projectTrustLoading": "載入中…", - "projectTrustEmpty": "尚未對任何目錄做出決定。", - "projectTrustTrusted": "已信任", - "projectTrustDenied": "不信任", - "projectTrustRevoke": "撤銷", - "reasoningTitle": "推理", - "reasoningEnableLabel": "啟用", - "reasoningDescription": "只有模型宣告了推理能力,pi 才會傳送推理強度——未宣告的模型所有等級都會被壓回 Off,所以輸入框裡的選擇器一改就彈回。這裡寫入 models.json 中該模型的項目。", - "levelsLabel": "可選等級", - "levelsHint": "這些會成為輸入框推理選擇器裡的等級。請選你的端點能接受的值;不在這裡的等級 pi 一律拒絕。", - "levelsEmptyError": "至少選一個等級——一個都不選時 pi 只會退回 Off。", - "wireValuesTitle": "進階:送給供應商的值", - "wireValuesHint": "留空表示原樣送出等級名稱。端點需要別的寫法時才填——Google 系需要 LOW / HIGH。", - "defaultLevelUnlisted": "該等級不在上面的可選清單裡——pi 會把它壓下來。" - }, - "addCustomAgent": "新增自訂智慧體", - "addCustomAgentHint": "接入任何相容 ACP 的智慧體。可從公開 ACP 註冊表中選擇,或直接貼上其註冊表資訊。", - "customAgentFromRegistry": "ACP 註冊表", - "customAgentManual": "手動填寫", - "customAgentSearchPlaceholder": "搜尋智慧體…", - "customAgentLoadingCatalog": "正在載入 ACP 註冊表…", - "customAgentRetry": "重試", - "customAgentNoResults": "沒有符合的智慧體", - "customAgentAdd": "新增", - "customAgentAlreadyAdded": "已新增", - "customAgentUnsupportedPlatform": "目前平台沒有可用的建置", - "customAgentAdded": "已新增 {name}", - "customAgentIdLabel": "註冊表 ID", - "customAgentNameLabel": "顯示名稱", - "customAgentVersionLabel": "版本", - "customAgentSpecLabel": "散發資訊(JSON)", - "customAgentSpecHint": "與 ACP 註冊表 distribution 物件同構:支援 npx、uvx、binary 三種通道,也可整筆貼上註冊表條目。npx/uvx 的 cmd 為套件安裝的可執行命令名稱,預設按套件名稱推導,與套件名稱不同時需填寫。binary 按平台鍵區分(本機為 {platform}),cmd 為壓縮檔內啟動路徑,sha256 可選用於驗證下載。", - "customAgentTemplateLabel": "範本", - "customAgentKindLabel": "啟動方式", - "customAgentInvalidJson": "不是合法的 JSON", - "customAgentNoDistribution": "找不到 npx、uvx 或 binary 散發方式", - "customAgentCancel": "取消", - "customAgentSave": "新增智慧體", - "customAgentSaveChanges": "儲存變更", - "customAgentEdit": "編輯智慧體", - "customAgentEditHint": "修改名稱、圖示、分發資訊與技能宣告;智慧體 ID 不可修改。", - "customAgentEditNotFound": "找不到自訂智慧體 {id}", - "customAgentSaved": "已儲存 {name}", - "customAgentVersionProbeLabel": "版本查詢命令(可選)", - "customAgentVersionProbeHint": "查詢本機安裝版本的命令;留空時預設執行智慧體命令加 --version。", - "customAgentRemove": "移除智慧體", - "customAgentRemoveHint": "刪除該智慧體定義。既有工作階段的歷史會保留,只是該智慧體無法再啟動。", - "customAgentIconLabel": "圖示(選填)", - "customAgentIconUpload": "上傳", - "customAgentIconReplace": "更換", - "customAgentIconClear": "移除圖示", - "customAgentIconHint": "隨智慧體一併儲存,離線也能顯示。未上傳則使用彩色首字母。", - "customAgentSkillsLabel": "Skills(共享 .agents/skills)", - "customAgentSkillsHint": "聲明該智能體會讀取共享的 .agents/skills 目錄(全域與專案級),並將其加入所有技能矩陣。連結到共享目錄的技能對讀取該目錄的其他智能體同樣可見。", - "customAgentSkillsDirLabel": "專屬技能目錄", - "customAgentSkillsDirHint": "該智慧體自身載入技能的目錄絕對路徑 —— 可與共享目錄並存,也可單獨使用。~ 會展開為主目錄;連結技能時優先放入此目錄。", - "customAgentMcpLabel": "MCP 支援", - "customAgentMcpHint": "工作階段建立時向該智慧體注入 codeg 內建的 codeg-mcp 伴生行程 —— 委派、即時回饋與任務工具都依賴它。若該智慧體不支援 MCP、連線時報錯,請關閉此項;設定會在下次連線時生效。", - "customAgentIconNotAnImage": "請選擇圖片檔案。", - "customAgentIconTooLarge": "圖示需小於 {limit} KB。", - "customAgentIconReadFailed": "無法讀取該圖片。", - "customAgentRemoveConfirm": "確定移除 {name}?既有會話會保留,但該智慧體將無法再啟動。", - "customAgentRemoveWithData": "同時刪除已記錄的會話歷史", - "customAgentRemoved": "已移除 {name}", - "customAgentBadge": "自訂", - "customAgentNotLaunchable": "該智慧體在此環境無法啟動:{reason}" - }, - "SettingsPages": { - "agentsLoading": "載入 Agent 設定中...", - "skillPacksLoading": "正在載入技能包…" - }, - "GeneralSettings": { - "loading": "載入中...", - "sectionTitle": "一般", - "sectionDescription": "集中管理預設終端機、渲染加速以及多智能體協同等通用偏好。", - "terminalTitle": "預設終端", - "terminalDescription": "選擇從終端列或檔案樹開啟新終端分頁時使用的 Shell。智慧代理請求 codeg 代為執行整條命令列時也會使用它。", - "terminalSystemDefault": "系統預設", - "terminalPowerShell7": "PowerShell 7 (pwsh)", - "terminalWindowsPowerShell": "Windows PowerShell", - "terminalCmd": "命令提示字元 (cmd)", - "terminalSaveFailed": "儲存終端設定失敗:{message}", - "terminalShellCustom": "自訂路徑", - "terminalShellCustomPath": "Shell 路徑", - "terminalShellCustomPlaceholder": "/usr/local/bin/fish", - "terminalShellCustomSave": "儲存", - "terminalShellCustomHint": "支援絕對路徑,或 PATH 中可解析的命令名。", - "terminalShellNotInstalled": "未安裝", - "terminalShellNotFoundWarning": "目前主機上不存在此路徑。", - "terminalCurrentShell": "目前使用:{path}", - "renderingDescription": "若應用出現黑屏或渲染異常(常見於 AMD 顯示卡或部分 Intel 內顯),可關閉硬體加速。僅 Windows 桌面端生效。", - "disableHardwareAcceleration": "停用硬體加速", - "renderingSaveFailed": "渲染設定儲存失敗:{message}", - "restartRequired": "已儲存,需重新啟動應用程式才會生效。", - "restartNow": "立即重新啟動", - "restartFailed": "重新啟動失敗:{message}", - "loadFailed": "載入失敗:{message}" - }, - "LoginPage": { - "documentTitle": "登入 - codeg", - "brand": "Codeg", - "subtitle": "輸入存取 Token 以連接到桌面端", - "tokenPlaceholder": "Access Token", - "connect": "連接", - "connecting": "連接中...", - "helpText": "Token 可在桌面端 設定 → Web 服務 中取得", - "invalidToken": "Token 無效,請檢查後重試", - "connectionFailed": "連接失敗 (HTTP {status})", - "networkError": "無法連接到伺服器" - }, - "CommitPage": { - "title": "提交程式碼", - "invalidFolderId": "無效的 folderId", - "loadingRepo": "正在載入倉庫..." - }, - "MergePage": { - "title": "解決衝突", - "invalidFolderId": "無效的 folderId", - "loadingRepo": "正在載入倉庫...", - "localVersion": "本地(我們的)", - "result": "結果", - "remoteVersion": "遠端(他們的)", - "acceptLocal": "採用本地", - "acceptRemote": "採用遠端", - "markResolved": "標記已解決", - "abortMerge": "中止", - "completeMerge": "完成合併", - "unresolvedConflicts": "檔案中仍有未解決的衝突標記", - "fileResolved": "檔案已解決", - "allResolved": "所有衝突已解決", - "conflictFiles": "衝突檔案", - "loadingFile": "正在載入檔案...", - "preparingMerge": "正在準備合併...", - "selectFile": "選擇一個檔案進行解決", - "noConflicts": "無衝突檔案", - "skipFile": "跳過", - "abortSuccess": "操作已中止", - "applyAllNonConflicting": "套用所有非衝突變更", - "applyLeftNonConflicting": "套用本地", - "applyRightNonConflicting": "套用遠端" - }, - "ImportSessions": { - "title": "匯入本機工作階段", - "scanningTitle": "正在掃描本機智慧代理工作階段…", - "scanningHint": "正在遍歷各智慧代理的本機工作階段儲存,歷史較多時可能需要一些時間。已匯入的工作階段會順帶重新整理。", - "scanFailed": "掃描失敗", - "retry": "重試", - "rescan": "重新掃描", - "empty": "未發現本機工作階段", - "emptyHint": "本機未找到任何智慧代理的工作階段儲存。", - "noMatches": "沒有符合目前篩選的工作階段", - "searchPlaceholder": "搜尋標題或路徑…", - "allAgents": "全部智慧代理", - "onlyImportable": "僅顯示可匯入", - "selectAll": "全選", - "clearSelection": "清空", - "expandAll": "全部展開", - "collapseAll": "全部摺疊", - "summaryCounts": "共 {total} 個工作階段 · {importable} 個可匯入 · {folders} 個資料夾", - "noFolderSkipped": "已略過 {count} 個無專案目錄的工作階段", - "folderNew": "新建", - "folderCounts": "可匯入 {importable}/{total}", - "toggleFolderAria": "選擇 {name} 中的全部可匯入工作階段", - "toggleSessionAria": "選擇工作階段 {title}", - "statusImported": "已匯入", - "statusDeleted": "已刪除", - "untitled": "未命名工作階段", - "messageCount": "{count} 則訊息", - "selectedCount": "已選 {count} 個", - "importSelected": "匯入所選", - "importing": "匯入中…", - "close": "關閉", - "doneTitle": "匯入完成", - "doneImported": "新匯入", - "doneUpdated": "已重新整理", - "doneSkipped": "已略過", - "doneCreatedFolders": "新建資料夾", - "doneNotFound": "未找到", - "doneFailed": "失敗", - "continueImport": "繼續匯入", - "toasts": { - "importFailed": "匯入失敗:{message}" - } - }, - "Folder": { - "workspaceStatus": { - "degradedTitle": "即時更新不可用", - "degradedHint": "監聽器啟動失敗(如目錄無讀取權限)。請手動重新整理以取得最新變更。", - "retry": "重試", - "retrying": "重試中..." - }, - "common": { - "all": "全部", - "cancel": "取消", - "close": "關閉", - "closeOthers": "關閉其它", - "closeAll": "關閉所有", - "confirm": "確認", - "save": "儲存", - "delete": "刪除", - "rename": "重新命名", - "loading": "載入中...", - "refresh": "刷新", - "refreshing": "刷新中...", - "create": "建立", - "createAndSwitch": "建立並切換", - "openFile": "打開檔案", - "viewDiff": "查看差異", - "push": "推送..." - }, - "statusLabels": { - "in_progress": "進行中", - "pending_review": "待複查", - "completed": "已完成", - "cancelled": "已取消" - }, - "sidebar": { - "title": "會話", - "locateActiveConversation": "定位目前會話", - "expandAllGroups": "展開全部分組", - "collapseAllGroups": "折疊全部分組", - "newConversation": "新增會話", - "newConversationShort": "新增", - "newChat": "新增會話", - "search": "搜尋", - "noConversationsFound": "找不到會話。", - "importLocalSessions": "匯入本地會話", - "importing": "匯入中...", - "error": "錯誤:{message}", - "completeAllSessions": "完成全部會話", - "completeAllReviewTitle": "完成全部複查會話?", - "completeAllReviewDescription": "這會將複查中的 {count} 個會話全部標記為已完成。", - "completing": "處理中...", - "toasts": { - "importedSessions": "已匯入 {imported} 個會話,跳過 {skipped} 個", - "importedAndUpdated": "已匯入 {imported} 個會話,更新 {updated} 個標題,跳過 {skipped} 個", - "updatedTitles": "已更新 {updated} 個標題,跳過 {skipped} 個", - "noNewSessionsFound": "沒有新會話(已跳過 {skipped} 個)", - "importFailed": "匯入失敗:{message}", - "reviewCompleted": "已將 {count} 個複查會話標記為已完成", - "completeReviewFailed": "批次完成複查會話失敗:{message}", - "folderOpened": "已開啟資料夾 {name}", - "folderRemoved": "已移除資料夾 {name}", - "openFolderFailed": "開啟資料夾失敗", - "removeFolderFailed": "移除資料夾失敗:{message}", - "reorderFoldersFailed": "重新排序資料夾失敗:{message}", - "changeFolderColorFailed": "修改顏色失敗:{message}", - "setFolderAliasFailed": "設定別名失敗:{message}", - "changeFolderDefaultAgentFailed": "設定預設智能體失敗:{message}" - }, - "statsLabel": "{folders} 個資料夾 · {convos} 個對話", - "reorderHandle": "拖拽排序", - "openFolder": "開啟資料夾", - "searchPlaceholder": "搜尋對話...", - "viewOptions": "顯示選項", - "showCompleted": "顯示已完成對話", - "showWorktrees": "顯示工作樹資料夾", - "showRecent": "顯示「最近」分組", - "moreOptions": "更多選項", - "sortBy": "排序方式", - "sortByCreatedAt": "按建立時間排序", - "sortByUpdatedAt": "按更新時間排序", - "sectionOrder": "區域順序", - "sectionOrderMoveUp": "上移", - "sectionOrderMoveDown": "下移", - "sectionOrderItemLabel": "{name} — 第 {position} 位,共 {total} 位", - "statusRunningBadge": "運行中", - "runningCountBadge": "{count} 個會話進行中", - "statusCancelledBadge": "已取消", - "worktreeRemovedBadge": "來源 worktree 已刪除", - "conversationCountUnit": "{count} 條", - "emptyFolderHint": "暫無對話", - "noMatchingConversations": "找不到符合的對話", - "noUnfinishedConversations": "目前沒有未完成的會話,右上角可啟用顯示已完成會話", - "removeFolderConfirmTitle": "從工作區移除此資料夾?", - "removeFolderConfirmDescription": "從工作區移除 \"{name}\"?相關分頁與終端機將會關閉。", - "folderHeaderMenu": { - "manageConversations": "會話管理…", - "manageLinks": "已連結的資料夾", - "changeColor": "修改顏色", - "useThemeColor": "使用設定主題", - "setDefaultAgent": "設定預設智能體", - "defaultAgentNone": "不設定(使用全域預設)", - "agentUnavailableSuffix": "(不可用)", - "loadingAgents": "正在載入代理…", - "setAlias": "設定別名…", - "setAliasTitle": "設定資料夾別名", - "setAliasPlaceholder": "輸入別名(留空清除)", - "setAliasSave": "儲存", - "setAliasCancel": "取消", - "removeFromWorkspace": "從工作區移除" - }, - "manageConversations": { - "title": "會話管理", - "searchPlaceholder": "依標題搜尋…", - "agentFilterAll": "全部智能體", - "statusFilterAll": "全部狀態", - "folderFilterAll": "全部資料夾", - "branchFilterAll": "全部分支", - "branchNone": "無分支", - "branchSearchPlaceholder": "搜尋分支…", - "noMatchingBranches": "無匹配分支", - "selectAllVisible": "全選", - "deselectAll": "取消全選", - "selectedCount": "已選 {count} 筆", - "matchedCount": "符合 {count} 筆", - "untitledConversation": "未命名會話", - "setStatus": "設為狀態…", - "deleteSelected": "刪除", - "noConversations": "此資料夾暫無會話。", - "noConversationsWorkspace": "工作區暫無會話。", - "noMatchingConversations": "沒有符合過濾條件的會話。", - "confirmDeleteTitle": "刪除 {count} 個會話?", - "confirmDeleteDescription": "此操作無法復原。", - "toastDeleted": "已刪除 {count} 個會話", - "toastStatusUpdated": "已更新 {count} 個會話的狀態", - "toastOpFailed": "操作失敗:{message}" - }, - "sectionPinned": "已置頂", - "sectionFolders": "資料夾", - "sectionChats": "聊天", - "sectionRecent": "最近", - "noChats": "沒有聊天", - "noRecent": "暫無最近對話", - "showMoreRecent": "顯示更多({count})", - "noFolders": "沒有開啟的資料夾", - "newChatAction": "新增聊天", - "automations": "自動化", - "tasks": "待辦任務", - "loadingSubsessions": "正在載入子會話…" - }, - "conversation": { - "reloadFailed": "會話重新載入失敗:{message}", - "reloaded": "目前會話已重新載入", - "reload": "重新載入", - "activeConversationIndicator": "目前啟用的會話", - "newConversation": "新增會話", - "closeConversation": "關閉會話", - "copyText": "複製文字", - "copyTextSuccess": "已複製", - "copyTextFailed": "複製失敗", - "forkSession": "分叉會話", - "forkSessionSuccess": "會話分叉成功", - "forkSessionFailed": "會話分叉失敗:{error}", - "exportConversation": "匯出對話", - "exportImage": "圖片", - "exportMarkdown": "Markdown", - "exportHtml": "HTML", - "exportSuccess": "對話已匯出", - "exportFailed": "匯出失敗", - "exportImageTooLong": "對話內容過長,不支援匯出為圖片", - "exportLabels": { - "untitledConversation": "未命名對話", - "agent": "代理", - "model": "模型", - "status": "狀態", - "started": "開始時間", - "updated": "更新時間", - "tokens": "令牌統計", - "duration": "時長", - "inputTokens": "輸入", - "outputTokens": "輸出", - "cacheRead": "快取讀取", - "cacheWrite": "快取寫入", - "user": "使用者", - "assistant": "助手", - "system": "系統", - "toolResult": "結果", - "toolError": "錯誤" - }, - "moreActions": "更多操作" - }, - "sessionDetails": { - "menuLabel": "對話詳情", - "noActiveSession": "暫無使用中的對話", - "title": "對話詳情", - "subtitle": "對話中繼資料與 Token 用量", - "fieldTitle": "標題", - "untitled": "未命名對話", - "sessionId": "對話 ID", - "externalId": "擴充 ID", - "agent": "智能體", - "model": "模型", - "status": "狀態", - "gitBranch": "Git 分支", - "parentId": "父對話", - "tokensHeading": "Token 用量", - "totalTokens": "總計", - "inputTokens": "輸入", - "outputTokens": "輸出", - "cacheWrite": "快取寫入", - "cacheRead": "快取讀取", - "contextWindow": "上下文視窗", - "duration": "時長", - "loadingStats": "正在載入 Token 用量…", - "loadFailed": "載入 Token 用量失敗", - "noStats": "尚無用量記錄", - "timestampsHeading": "時間", - "createdAt": "建立時間", - "updatedAt": "更新時間", - "none": "—", - "copyField": "複製{field}", - "copiedField": "已複製{field}" - }, - "conversationCard": { - "untitledConversation": "未命名會話", - "newConversation": "新增會話", - "rename": "重新命名", - "status": "狀態", - "delete": "刪除", - "importLocalSessions": "匯入本地會話", - "importing": "匯入中...", - "renameConversation": "重新命名會話", - "deleteConversationTitle": "刪除會話?", - "deleteConversationDescription": "會刪除「{title}」,此操作無法復原。", - "cancel": "取消", - "save": "儲存", - "pin": "置頂", - "unpin": "取消置頂", - "markCompleted": "標記為已完成", - "reopen": "重新開啟", - "expandSubsessions": "展開子會話", - "collapseSubsessions": "摺疊子會話" - }, - "search": { - "dialogTitle": "搜尋", - "dialogTitleWithFolder": "搜尋 — {name}", - "tabConversations": "會話", - "tabFiles": "檔案", - "placeholder": "搜尋會話...", - "filePlaceholder": "搜尋檔案或目錄...", - "allAgents": "全部", - "searching": "搜尋中...", - "typeToSearch": "輸入關鍵字搜尋會話", - "typeToSearchFiles": "輸入關鍵字搜尋檔案或目錄", - "noResults": "找不到結果。", - "untitledConversation": "未命名會話" - }, - "folderTitleBar": { - "showSidebar": "顯示側邊欄", - "hideSidebar": "隱藏側邊欄", - "toggleTerminal": "切換終端", - "toggleAuxPanel": "切換輔助面板", - "search": "搜尋", - "openSettings": "打開設定", - "backToConversations": "返回會話", - "withShortcut": "{label}({shortcut})" - }, - "statusBar": { - "connection": { - "connected": "已連線", - "connecting": "連線中...", - "prompting": "回應中...", - "error": "連線異常", - "disconnected": "未連線", - "tooltip": "{agent}:{status}", - "tooltipError": "{agent}:{error}", - "title": "智慧體連線", - "triggerAria": "智慧體連線:{status}", - "workingDir": "工作目錄", - "sessionId": "工作階段 ID", - "viewerNote": "已接入其他用戶端擁有的工作階段——重新連線只會重新接入目前檢視。", - "reconnectInterrupts": "重新連線會重啟智慧體,並中斷進行中的工作。", - "reconnect": "重新連線", - "reconnecting": "正在重新連線...", - "reconnectUnavailable": "目前沒有可重新連線的工作階段。" - }, - "tasks": { - "title": "任務" - }, - "alerts": { - "title": "警示", - "empty": "暫無警示資訊", - "details": "詳情" - }, - "stats": { - "conversations": "{count} 個會話", - "openUsage": "檢視會話統計與 Token 用量" - }, - "tokens": { - "contextWindowUsageAria": "上下文視窗使用率", - "contextWindow": "上下文視窗", - "usedMax": "已用 / 上限", - "tokenUsage": "Token 用量", - "input": "輸入", - "output": "輸出", - "cacheRead": "快取讀取", - "cacheWrite": "快取寫入", - "total": "總計" - } - }, - "auxPanel": { - "tabs": { - "files": "檔案", - "changes": "變更", - "commits": "提交" - }, - "noFolderTitle": "尚無開啟的資料夾", - "noFolderHint": "開啟一個資料夾後可在此查看" - }, - "windowControls": { - "minimizeWindow": "最小化視窗", - "minimize": "最小化", - "maximizeWindow": "最大化視窗", - "maximize": "最大化", - "restoreWindow": "還原視窗", - "restore": "還原", - "closeWindow": "關閉視窗", - "close": "關閉" - }, - "tabs": { - "closeConversationTab": "關閉會話分頁", - "close": "關閉", - "closeOthers": "關閉其它", - "splitRight": "向右拆分", - "splitDown": "向下拆分", - "splitAndMoveRight": "拆分並右移", - "splitAndMoveDown": "拆分並下移", - "moveToOppositeGroup": "移動到對側分組", - "moveToGroup": "移動到分組", - "groupLabel": "分組 {index}", - "changeSplitterOrientation": "切換分隔方向", - "unsplit": "取消拆分", - "unsplitAll": "全部取消拆分", - "closeAll": "關閉所有", - "tileDisplay": "平鋪顯示", - "untileDisplay": "取消平鋪" - }, - "fileWorkspace": { - "files": "檔案", - "closeFileTab": "關閉檔案分頁", - "close": "關閉", - "closeOthers": "關閉其它", - "closeAll": "關閉所有", - "preview": "預覽", - "editSource": "編輯原始碼", - "maximize": "最大化", - "restore": "還原", - "emptyDirectory": "空目錄" - }, - "terminal": { - "rename": "重新命名", - "close": "關閉", - "closeOthers": "關閉其它", - "closeAll": "關閉所有", - "hideTerminal": "隱藏終端({shortcut})", - "openFolderFirst": "請先開啟一個資料夾" - }, - "workspaceDialog": { - "title": "開啟資料夾", - "manageTitle": "已連結的資料夾", - "addTargetsTitle": "新增要連結的資料夾", - "pickRootDescription": "選擇這個工作區的主資料夾。", - "linksDescription": "把其他資料夾以子目錄的形式連結進來,代理就能在同一個工作區跨專案工作。", - "addTargetsDescription": "選擇一個或多個資料夾,每個都會成為工作區的一個子目錄。", - "useSystemPicker": "系統選擇器", - "next": "下一步", - "back": "返回", - "done": "完成", - "change": "變更", - "addFolders": "新增資料夾", - "addSelected": "新增", - "addSelectedCount": "新增 {count} 個", - "createCount": "連結 {count} 個資料夾", - "discardPending": "捨棄", - "noLinks": "尚未連結任何資料夾。", - "gitExclude": "不讓連結目錄污染 git 狀態", - "rename": "重新命名", - "unlink": "解除連結", - "repair": "重建連結", - "saveName": "儲存", - "cancelRename": "取消", - "removePending": "移除", - "willAppearAs": "在工作區中顯示為 {name}", - "renamedForDuplicate": "已改名 —— {base} 已被另一個連結佔用", - "renamedForExistingEntry": "已改名 —— 該資料夾中已存在 {base}", - "partiallyCreated": "只成功連結了 {count} 個資料夾", - "openFailed": "開啟資料夾失敗", - "previewFailed": "檢查所選資料夾失敗", - "createFailed": "連結資料夾失敗", - "renameFailed": "重新命名失敗", - "removeFailed": "解除連結失敗", - "repairFailed": "重建連結失敗", - "status": { - "ok": "已連結", - "missing": "連結已從該資料夾中消失", - "conflicted": "該名稱已被其他項目佔用", - "broken": "被連結的資料夾已不存在" - }, - "nameIssue": { - "empty": "請輸入名稱", - "illegalChars": "不能包含 / \\ : * ? \" < > |", - "tooLong": "名稱過長", - "reserved": "該名稱是 Windows 保留名", - "duplicate": "該名稱已被使用" - }, - "rejection": { - "not_found": "找不到該資料夾", - "not_a_directory": "該路徑不是資料夾", - "same_as_root": "這就是工作區資料夾本身", - "ancestor_of_root": "該資料夾包含了目前工作區", - "inside_root": "已在工作區內部", - "already_linked": "已經連結過", - "name_unavailable": "該資料夾已無可用的名稱", - "alreadyLinkedAs": "已作為 {name} 連結" - } - }, - "folderNameDropdown": { - "fallbackFolderName": "資料夾", - "openFolder": "打開資料夾", - "cloneRepository": "複製倉庫", - "projectBoot": "專案啟動器", - "opened": "已打開", - "recentOpen": "最近打開" - }, - "fileWorkspacePanel": { - "addSelectionToChat": "新增選取範圍到對話", - "addToChat": "加入對話", - "addSelectionToChatDone": "已將 {label} 加入對話", - "addFileToChat": "新增檔案到對話", - "toggleWordWrap": "切換自動換行", - "addFileToChatDone": "已將 {label} 加入對話", - "viewDiff": "查看差異", - "openFile": "打開檔案", - "fileCount": "{count} 個檔案", - "openFileOrDiff": "從右側面板打開檔案或差異", - "disk": "磁碟", - "head": "HEAD(目前提交)", - "unsaved": "未儲存", - "workingTree": "工作區", - "loading": "載入中...", - "compareWithBranch": "{path} · 與 {branch} 比較", - "hunkCount": "{count} 個區塊", - "prev": "上一個", - "next": "下一個", - "jumpToLine": "跳到第 {line} 行", - "noParsedDiffSections": "未解析到差異區塊", - "loadingEditor": "編輯器載入中...", - "imageZoomIn": "放大", - "imageZoomOut": "縮小", - "imageZoomReset": "重設縮放", - "htmlPreviewTitle": "HTML 預覽", - "htmlPreviewTrust": "執行指令碼", - "htmlPreviewTrustHint": "執行此檔案的指令碼並允許網路存取。僅對信任的檔案啟用。", - "officePreviewTitle": "辦公文件預覽", - "officeFullRender": "完整渲染", - "officeFullRenderHint": "渲染 Morph 動畫、3D 與公式(會執行投影片自帶的指令碼)", - "officeNotInstalled": "未安裝 OfficeCLI", - "officeNotInstalledHint": "在 設定 → 辦公工具 中安裝 OfficeCLI,即可預覽 Word、Excel 與 PowerPoint 檔案。", - "officeOpenSettings": "開啟設定", - "officeWatchFailed": "無法啟動即時預覽", - "officeWatchRetry": "重試", - "officeServerInstallHint": "OfficeCLI 需安裝在伺服器主機上。請在伺服器上執行以下指令後重試:", - "officeRemoteDesktopUnsupported": "遠端桌面視窗暫不支援即時預覽。請在伺服器的 Web 介面中開啟此工作區以預覽 Office 檔案。" - }, - "branchDropdown": { - "toasts": { - "commitCodeCompleted": "提交程式碼完成", - "pushCodeCompleted": "推送程式碼完成", - "committedFiles": "已提交 {count} 個檔案", - "taskCompleted": "{label} 完成", - "taskFailed": "{label} 失敗", - "mergeNoNewCommits": "{branchName} 沒有新的提交", - "mergedCommits": "已合併 {count} 個提交", - "allFilesUpToDate": "所有檔案均為最新版本", - "updatedFiles": "已更新 {count} 個檔案", - "openCommitWindowFailed": "打開提交視窗失敗", - "openPushWindowFailed": "開啟推送視窗失敗", - "upstreamSet": "已設定遠端追蹤分支", - "upstreamSetAndPushed": "已設定遠端追蹤分支並推送 {count} 個提交", - "noCommitsToPush": "沒有可推送的提交", - "pushedCommits": "已推送 {count} 個提交", - "switchedToFolder": "已切換到 {name}", - "switchFailed": "切換分支失敗", - "openStashWindowFailed": "開啟收藏視窗失敗" - }, - "tasks": { - "newBranch": "新增分支 {name}", - "newWorktree": "新增工作樹 {name}", - "checkoutTo": "切換到 {branchName}", - "mergeBranch": "合併 {branchName}", - "rebaseTo": "變基到 {branchName}", - "deleteRemoteBranch": "刪除遠端分支 {branchName}", - "initGitRepo": "初始化 Git 倉庫", - "pullCode": "更新程式碼", - "fetchInfo": "獲取資訊", - "pushCode": "推送程式碼", - "stashChanges": "暫存變更", - "stashPop": "取消暫存", - "deleteBranch": "刪除分支 {branchName}", - "removeWorktree": "刪除 {branchName} 的工作樹", - "removeWorktreeAndBranch": "刪除工作樹及分支 {branchName}", - "updateBranch": "更新分支 {branchName}" - }, - "confirm": { - "mergeTitle": "合併分支", - "rebaseTitle": "變基分支", - "mergeDescription": "確定將 {branchName} 合併到目前分支 {currentBranch} 嗎?", - "rebaseDescription": "確定將目前分支 {currentBranch} 變基到 {branchName} 嗎?", - "deleteRemoteTitle": "刪除遠端分支", - "deleteRemoteDescription": "確定刪除遠端分支 {branchName} 嗎?此操作將從遠端倉庫中移除該分支,且不可恢復。", - "deleteTitle": "刪除分支", - "deleteDescription": "確定刪除分支 {branchName} 嗎?此操作無法復原。", - "forceDeleteTitle": "強制刪除分支", - "forceDeleteDescription": "分支 {branchName} 尚未完全合併,確定要強制刪除嗎?此操作不可恢復。", - "deleteWorktreeTitle": "刪除工作樹", - "deleteWorktreeDescription": "刪除簽出了 {branchName} 的工作樹目錄?分支及其提交會保留。", - "forceDeleteWorktreeTitle": "強制刪除工作樹", - "forceDeleteWorktreeDescription": "{branchName} 的工作樹中有未提交或未追蹤的檔案。仍要刪除嗎?這些變更將無法復原。", - "deleteWorktreeAndBranchTitle": "刪除工作樹及分支", - "deleteWorktreeAndBranchDescription": "刪除 {branchName} 的工作樹、該分支本身及其工作區資料夾?其中的工作階段會移動到儲存庫資料夾下。此操作無法復原。", - "forceDeleteWorktreeAndBranchTitle": "強制刪除工作樹及分支", - "forceDeleteWorktreeAndBranchDescription": "{branchName} 的工作樹中有未提交的檔案,或該分支尚未完全合併。仍要一併刪除嗎?此操作無法復原。" - }, - "current": "目前", - "switchToBranch": "切換到此分支", - "mergeBranchIntoCurrent": "將 {branchName} 合併到 {currentBranch}", - "rebaseCurrentToBranch": "將 {currentBranch} 變基到 {branchName}", - "noBranch": "無分支", - "detachedHead": "分離 HEAD({sha})", - "initGitRepo": "初始化 Git 倉庫", - "pullCode": "更新程式碼", - "fetchRemoteBranches": "提取遠端分支", - "openCommitWindow": "提交程式碼...", - "pushCode": "推送...", - "pushBranch": "推送", - "newBranch": "新增分支...", - "newWorktree": "新增工作樹...", - "stashChanges": "貯藏更改...", - "stashPop": "取消暫存...", - "manageRemotes": "管理遠端...", - "localBranches": "本地分支 ({count})", - "noLocalBranches": "無本地分支", - "remoteBranches": "遠端分支 ({count})", - "noRemoteBranches": "無遠端分支", - "dialogs": { - "newBranchTitle": "新增分支", - "newBranchDescription": "從目前分支 {branch} 建立新分支", - "branchNamePlaceholder": "分支名稱", - "newWorktreeTitle": "新增工作樹", - "newWorktreeDescription": "從目前分支 {branch} 建立新的工作樹", - "branchNameLabel": "分支名稱", - "worktreePathLabel": "工作樹路徑", - "worktreePathPlaceholder": "工作樹路徑", - "manageRemotesTitle": "管理遠端", - "manageRemotesEmpty": "未設定遠端儲存庫", - "remoteNamePlaceholder": "遠端名稱", - "remoteUrlPlaceholder": "遠端 URL", - "addRemote": "新增", - "savingRemotes": "儲存中..." - }, - "conflict": { - "title": "合併衝突", - "description": "以下檔案存在衝突,需要手動解決:", - "abort": "中止合併", - "openMergeTool": "開啟合併工具", - "completeMerge": "完成合併", - "abortSuccess": "合併已中止", - "completeSuccess": "合併完成" - }, - "stashDialog": { - "title": "貯藏更改", - "description": "將當前更改保存到貯藏區", - "messageLabel": "訊息", - "messagePlaceholder": "貯藏訊息(可選)", - "keepIndex": "保留暫存區(已暫存的更改保持不變)", - "cancel": "取消", - "stash": "貯藏", - "success": "更改已貯藏", - "error": "貯藏更改失敗" - }, - "unstashDialog": { - "title": "取消貯藏", - "noStashes": "沒有貯藏記錄", - "selectFile": "選擇檔案查看差異", - "viewDiff": "查看差異", - "original": "原始", - "modified": "修改後", - "apply": "套用", - "drop": "刪除", - "applySuccess": "貯藏已套用", - "dropSuccess": "貯藏已刪除", - "confirmApply": "將貯藏 {ref} 套用到工作目錄?", - "cancel": "取消" - }, - "deleteBranch": "刪除分支", - "deleteWorktree": "刪除工作樹", - "deleteWorktreeAndBranch": "刪除工作樹及分支", - "searchPlaceholder": "搜尋分支與操作", - "searchAriaLabel": "搜尋分支與操作", - "branchListLabel": "分支與操作", - "noMatches": "無相符項目" - }, - "commitDialog": { - "toasts": { - "commitCompleted": "提交程式碼完成", - "pushFailed": "推送失敗", - "committedFiles": "已提交 {count} 個檔案", - "addedToVcs": "已加入到 VCS", - "addToVcsFailed": "加入到 VCS 失敗", - "fileDeleted": "檔案已刪除", - "deleteFailed": "刪除失敗", - "fileRolledBack": "檔案已回滾", - "rollbackFailed": "回滾失敗", - "dirRolledBack": "目錄已回滾", - "dirDeleted": "目錄已刪除" - }, - "confirm": { - "deleteTitle": "確認刪除", - "deleteDescription": "確定要刪除檔案「{file}」嗎?此操作無法復原。", - "rollbackTitle": "確認回滾", - "rollbackDescription": "確定要回滾檔案「{file}」到 HEAD 版本嗎?未儲存修改將遺失。", - "rollbackDirDescription": "確定要回滾目錄「{dir}」到 HEAD 版本嗎?未儲存的修改將遺失。", - "deleteDirDescription": "確定要刪除目錄「{dir}」嗎?此操作不可恢復。" - }, - "actions": { - "select": "選擇", - "unselect": "取消選擇", - "rollback": "回滾", - "addToVcs": "加入到 VCS" - }, - "aria": { - "selectFile": "{action}:{path}", - "unselectAllFiles": "取消選擇全部檔案", - "selectAllFiles": "選擇全部檔案", - "unselectTracked": "取消選擇已追蹤變更", - "selectTracked": "選擇已追蹤變更", - "unselectUntracked": "取消選擇未追蹤檔案", - "selectUntracked": "選擇未追蹤檔案" - }, - "loading": "載入中...", - "selectionCount": "{selected} / {total} 個檔案", - "emptyFiles": "沒有變更的檔案", - "trackedChanges": "已追蹤變更 ({count})", - "untrackedFiles": "未追蹤檔案 ({count})", - "commitMessage": "提交訊息", - "commitMessagePlaceholder": "輸入提交訊息...", - "commitButton": "提交 ({count})", - "commitAndPushButton": "提交並推送 ({count})", - "head": "HEAD(目前提交)", - "workingTree": "工作目錄", - "clickFileToDiff": "點擊檔案名稱查看差異", - "loadingDiff": "載入差異中..." - }, - "pushWindow": { - "title": "推送程式碼", - "noUnpushedCommits": "沒有未推送的提交", - "noRemoteConfigured": "未設定 Git 遠端儲存庫\n請在「管理遠端」中新增遠端地址", - "newBranchNoPushedCommits": "新分支 — 推送以建立遠端追蹤分支", - "unpushed": "未推送", - "selectFileToViewDiff": "選擇檔案查看差異", - "before": "修改前", - "after": "修改後", - "push": "推送", - "toasts": { - "pushSuccess": "推送成功", - "pushFailed": "推送失敗", - "upstreamSet": "已設定遠端追蹤分支", - "upstreamSetAndPushed": "已設定遠端追蹤分支並推送 {count} 個提交", - "noCommitsToPush": "沒有可推送的提交", - "pushedCommits": "已推送 {count} 個提交" - } - }, - "gitLogTab": { - "filesTitle": "檔案", - "expandAllFiles": "展開全部檔案", - "collapseAllFiles": "折疊全部檔案", - "workspace": "工作區", - "retry": "重試", - "noCommitsFound": "未找到提交記錄", - "notAGitRepoTitle": "不是 Git 儲存庫", - "notAGitRepoHint": "可從上方分支選單初始化 Git,或開啟已有的 Git 儲存庫。", - "hash": "Hash", - "copyHash": "複製雜湊", - "copyMessage": "複製提交訊息", - "showMore": "展開", - "showLess": "收合", - "author": "作者", - "noFileChangeDetails": "暫無檔案變更詳情。", - "loadingFiles": "正在載入檔案…", - "branchesTitle": "分支", - "loadingBranches": "正在載入分支...", - "noContainingBranches": "未找到包含此提交的分支。", - "newBranch": "新增分支...", - "resetToHere": "重設到此處", - "resetDisabledReasonNotCurrentBranchView": "僅在檢視目前分支時可用", - "copyFullCommitHashAria": "複製完整提交雜湊 {hash}", - "pushStatus": { - "pushed": "已推送到遠端", - "notPushed": "未推送到遠端", - "unknown": "推送狀態未知(未配置上游分支)" - }, - "time": { - "monthsAgo": "{count} 個月前", - "daysAgo": "{count} 天前", - "hoursAgo": "{count} 小時前", - "minsAgo": "{count} 分鐘前", - "justNow": "剛剛" - }, - "toasts": { - "createdAndSwitchedNewBranch": "已建立並切換到新分支", - "newBranchFromCommit": "{name}(來自 {shortHash})", - "createBranchFailed": "新增分支失敗", - "openPushWindowFailed": "開啟推送視窗失敗", - "resetSuccess": "重設成功", - "resetSuccessDescription": "已將 {branch} 以 {mode} 重設到 {shortHash}", - "resetFailed": "重設失敗" - }, - "authorFilter": { - "label": "作者", - "searchPlaceholder": "搜尋作者", - "noAuthors": "找不到作者", - "you": "你", - "filterByAuthorAria": "依作者篩選提交", - "filterByQuery": "依「{query}」篩選", - "clearAuthorFilterAria": "清除作者篩選", - "recent": "最近", - "matchingAuthors": "符合的作者", - "removeFromRecent": "從最近列表移除 {name}" - }, - "branchSelector": { - "label": "分支", - "head": "HEAD", - "headHint": "跟隨目前分支", - "headHintWithBranch": "跟隨目前分支({branch})", - "searchBranch": "搜尋分支...", - "noBranches": "無分支", - "selectBranchPlaceholder": "選擇分支...", - "localBranches": "本地分支", - "current": "目前", - "remoteBranches": "遠端分支", - "refreshCommitHistory": "刷新提交記錄", - "clearBranchFilterAria": "清除分支篩選" - }, - "dialogs": { - "newBranchTitle": "新增分支", - "newBranchDescription": "以提交 {shortHash} 作為最後提交建立新分支。", - "branchNamePlaceholder": "分支名稱", - "reset": { - "title": "將目前分支重設到此提交", - "branchLabel": "分支", - "targetLabel": "目標提交", - "messageLabel": "提交訊息", - "modeLabel": "重設模式", - "confirmButton": "重設", - "modes": { - "soft": { - "label": "--soft", - "description": "將 HEAD 與目前分支指標移動到目標提交。\n暫存區(Index)與工作區(Working Tree)保持不變。\n被回退提交的變更會保留為「已暫存」。" - }, - "mixed": { - "label": "--mixed(預設)", - "description": "將 HEAD 移動到目標提交。\n把暫存區重設為目標提交狀態,但保留工作區變更。\n這些變更會由「已暫存」變成「未暫存」。" - }, - "hard": { - "label": "--hard", - "description": "將 HEAD、暫存區與工作區全部重設到目標提交。\n目標提交之後的本地已追蹤變更會被直接捨棄。\n這是破壞性操作。" - }, - "keep": { - "label": "--keep", - "description": "將 HEAD 移動到目標提交,並盡可能保留本地變更。\n僅保留與目標提交不衝突的本地變更。\n若檢測到衝突,操作會中止以保護你的修改。" - } - } - } - }, - "moreActions": "更多 Git 操作" - }, - "gitChangesTab": { - "workspace": "工作區", - "noChanges": "暫無本地變更", - "notAGitRepoTitle": "不是 Git 儲存庫", - "notAGitRepoHint": "可從上方分支選單初始化 Git,或開啟已有的 Git 儲存庫。", - "trackedChanges": "本地已追蹤變更 ({count})", - "untrackedFiles": "本地未追蹤檔案 ({count})", - "expandTracked": "展開已追蹤變更", - "collapseTracked": "折疊已追蹤變更", - "expandUntracked": "展開未追蹤檔案", - "collapseUntracked": "折疊未追蹤檔案", - "showRemainingItems": "顯示其餘 {count} 項", - "actions": { - "commitCode": "提交程式碼", - "rollback": "回滾", - "addToVcs": "加入到 VCS", - "delete": "刪除", - "moreActions": "更多 Git 操作", - "addAllToVcs": "全部加入 VCS", - "rollbackAll": "全部還原", - "refresh": "重新整理" - }, - "toasts": { - "noAddableFilesInDir": "該目錄下沒有可加入到 VCS 的變更檔案", - "noRollbackFilesInDir": "該目錄下沒有可回滾的變更檔案", - "addedToVcs": "已加入 {name} 到 VCS", - "addToVcsFailed": "加入到 VCS 失敗", - "openCommitWindowFailed": "打開提交視窗失敗", - "rolledBack": "已回滾 {name}", - "rollbackFailed": "回滾失敗", - "addedFilesToVcs": "已加入 {count} 個檔案到 VCS", - "rolledBackFiles": "已回滾 {count} 個檔案", - "deleted": "已刪除 {name}", - "deleteFailed": "刪除失敗", - "deletedFiles": "已刪除 {count} 個檔案", - "noDeletableFilesInDir": "此目錄下沒有可刪除的變更檔案", - "commitFailed": "提交失敗" - }, - "directoryDialog": { - "descriptionAdd": "選擇目錄 {path} 下要加入到 VCS 的檔案。", - "descriptionRollback": "選擇目錄 {path} 下要回滾的檔案。", - "descriptionDelete": "選擇目錄 {path} 下要刪除的檔案。此操作不可撤銷。", - "descriptionFallback": "選擇要操作的檔案。", - "selectionCount": "已選擇 {selected} / {total} 個檔案", - "selectAll": "全選", - "unselectAll": "取消全選", - "loadingCandidates": "正在載入目錄變更...", - "noOperableFiles": "沒有可操作的檔案" - }, - "rollbackConfirm": { - "title": "確認回滾", - "descriptionWithTarget": "確定回滾{kind}「{name}」的本地修改嗎?", - "descriptionFallback": "確定回滾本地修改嗎?", - "kindDirectory": "目錄", - "kindFile": "檔案" - }, - "deleteConfirm": { - "title": "確認刪除", - "descriptionWithTarget": "確定刪除{kind}「{name}」嗎?此操作無法撤銷。", - "descriptionFallback": "此操作無法撤銷。", - "kindDirectory": "目錄", - "kindFile": "檔案" - }, - "quickCommit": { - "placeholder": "提交訊息(Enter 提交)" - } - }, - "tabContext": { - "loadingConversation": "載入中...", - "untitledConversation": "未命名會話", - "newConversation": "新增會話" - }, - "fileTreeTab": { - "workspace": "工作區", - "retry": "重試", - "git": "Git", - "openInFileManager": "在檔案管理器開啟", - "openInFinder": "在 Finder 開啟", - "openInExplorer": "在檔案總管開啟", - "attachToCurrentSession": "添加到會話", - "compareWithBranch": "與分支比較...", - "reloadFromDisk": "從磁碟重新載入", - "new": "新建", - "newFile": "檔案", - "newDirectory": "目錄", - "openIn": "開啟於", - "openInTerminal": "在終端開啟", - "linkedFolder": "已連結的資料夾", - "copyPath": "複製路徑", - "upload": "上傳檔案/目錄", - "download": "下載檔案", - "downloadAsZip": "下載為 ZIP", - "actions": { - "select": "選擇", - "unselect": "取消選擇", - "commitCode": "提交程式碼", - "rollback": "回滾", - "addToVcs": "加入到 VCS" - }, - "aria": { - "selectPath": "{action}:{path}" - }, - "toasts": { - "openDirectoryFailed": "開啟目錄失敗", - "openBuiltinTerminalFailed": "無法開啟內建終端", - "openCommitWindowFailed": "打開提交視窗失敗", - "noAddableFilesInDir": "該目錄下沒有可加入到 VCS 的變更檔案", - "noRollbackFilesInDir": "該目錄下沒有可回滾的變更檔案", - "addedToVcs": "已加入 {name} 到 VCS", - "addToVcsFailed": "加入到 VCS 失敗", - "loadBranchesFailed": "載入分支失敗", - "renameFailed": "重新命名失敗", - "moveFailed": "移動失敗", - "deleteFailed": "刪除失敗", - "rolledBack": "已回滾 {name}", - "rollbackFailed": "回滾失敗", - "addedFilesToVcs": "已加入 {count} 個檔案到 VCS", - "rolledBackFiles": "已回滾 {count} 個檔案", - "savedAsCopy": "已另存為副本", - "saveCopyFailed": "另存為副本失敗", - "watchStartFailed": "檔案監聽啟動失敗", - "createFailed": "建立失敗", - "downloadFailed": "下載 {name} 失敗", - "downloadSaved": "已下載 {name}", - "pathCopied": "已複製路徑", - "copyPathFailed": "複製路徑失敗" - }, - "createDialog": { - "newFile": "新建檔案", - "newDirectory": "新建目錄", - "description": "輸入新{kind}的名稱。", - "placeholderFile": "file-name.ext", - "placeholderDirectory": "folder-name" - }, - "renameDialog": { - "renameDirectory": "重新命名目錄", - "renameFile": "重新命名檔案", - "description": "輸入新的名稱(僅名稱,不含路徑)。", - "placeholderDirectory": "新資料夾名稱", - "placeholderFile": "新檔案名稱.ext" - }, - "uploadDialog": { - "title": "上傳到工作區", - "description": "可在下方修改上傳目錄,然後加入檔案或資料夾。", - "workspaceRoot": "工作區根目錄", - "targetPathLabel": "上傳到", - "targetPathHint": "實際目錄:{path}", - "dropHint": "拖曳檔案或資料夾到此處,或使用下方按鈕", - "dropHintActive": "放開以加入上傳佇列", - "selectFiles": "選擇檔案", - "selectFolder": "選擇資料夾", - "startUpload": "開始上傳", - "clearQueue": "清除已完成", - "removeItem": "從佇列移除", - "retry": "重試", - "dropZoneAria": "拖放檔案到此處,或按 Enter 鍵瀏覽", - "folderEmpty": "拖入的資料夾中沒有可上傳的檔案", - "summary": "總數:{total} · 成功:{succeeded} · 失敗:{failed}", - "status": { - "pending": "等待中", - "uploading": "上傳中", - "success": "完成", - "error": "失敗", - "cancelled": "已取消" - } - }, - "directoryDialog": { - "descriptionAdd": "選擇目錄 {path} 下要加入到 VCS 的檔案。", - "descriptionRollback": "選擇目錄 {path} 下要回滾的檔案。", - "descriptionFallback": "選擇要操作的檔案。", - "selectionCount": "已選擇 {selected} / {total} 個檔案", - "selectAll": "全選", - "unselectAll": "取消全選", - "loadingCandidates": "正在載入目錄變更...", - "noOperableFiles": "沒有可操作的檔案" - }, - "compareDialog": { - "title": "與分支比較", - "descriptionWithTarget": "選擇分支並與{kind} {path} 比對", - "descriptionFallback": "選擇要比較的分支。", - "kindDirectory": "目錄", - "kindFile": "檔案", - "filterPlaceholder": "過濾分支,例如 main / origin/main", - "singleClickHint": "單擊分支即可直接比較", - "loadingBranches": "正在載入分支...", - "recentBranches": "最近分支 ({count})", - "noCurrentBranch": "無目前分支", - "localBranches": "本地分支 ({count})", - "remoteBranches": "遠端分支 ({count})", - "noMatchingBranches": "無匹配分支" - }, - "externalConflictDialog": { - "title": "偵測到外部檔案變更", - "descriptionWithPath": "檔案 {path} 在磁碟已發生變化,目前編輯內容尚未儲存。", - "descriptionFallback": "目前檔案在磁碟已發生變化,目前編輯內容尚未儲存。", - "compare": "比較", - "savingCopy": "另存中...", - "saveAsCopy": "另存為副本", - "reload": "重載" - }, - "deleteConfirm": { - "title": "確認刪除", - "descriptionWithTarget": "確定刪除{kind} \"{name}\" 嗎?此操作不可撤銷。", - "descriptionFallback": "此操作不可撤銷。", - "kindDirectory": "目錄", - "kindFile": "檔案" - }, - "rollbackConfirm": { - "title": "確認回滾", - "descriptionWithTarget": "確定回滾檔案 \"{name}\" 的本地修改嗎?", - "descriptionFallback": "確定回滾該檔案的本地修改嗎?" - }, - "terminalTitle": "終端 · {name}" - }, - "commandDropdown": { - "loading": "載入中...", - "addCommand": "新增命令", - "manageCommands": "管理命令...", - "runCommandTitle": "執行:{command}", - "stopCommandTitle": "停止:{command}", - "manageDialog": { - "title": "管理命令", - "empty": "暫無命令", - "noResults": "沒有符合的命令", - "searchPlaceholder": "搜尋命令", - "newCommand": "新增命令", - "nameLabel": "名稱", - "commandLabel": "命令", - "dragSort": "拖曳排序", - "dragSortCommand": "拖曳排序 {name}", - "orderFailed": "儲存命令排序失敗", - "loadFailed": "載入命令失敗", - "saveFailed": "儲存命令失敗", - "deleteFailed": "刪除命令失敗", - "confirmDelete": { - "title": "刪除命令?", - "message": "這會移除「{name}」,此操作無法復原。" - } - } - }, - "workspaceContext": { - "confirmCloseDirtyTab": "檔案「{title}」有未儲存變更,確定關閉嗎?", - "confirmCloseOtherDirtyTabs": "其他分頁有未儲存變更,確定關閉嗎?", - "confirmCloseAllDirtyTabs": "存在未儲存變更,確定關閉全部分頁嗎?", - "unableLoadContent": "無法載入內容。\n\n{message}", - "previewRequestTimedOut": "預覽請求逾時", - "diffRequestTimedOut": "Diff 請求逾時", - "branchCompareRequestTimedOut": "分支比較請求逾時", - "commitDiffRequestTimedOut": "提交差異請求逾時", - "saveRequestTimedOut": "儲存請求逾時", - "reloadRequestTimedOut": "重載請求逾時", - "noChanges": "暫無變更。", - "noDiffOutput": "無差異輸出。", - "diffTitleWorkspace": "Diff · 工作區", - "diffDescriptionWorkingTree": "工作區變更(HEAD)", - "diffTitleFile": "差異 · {name}", - "compareTitleFile": "比較 · {name}", - "compareTitleBranch": "比較 · {branch}", - "compareDescriptionPath": "{path} · 與 {branch} 比較", - "compareDescriptionBranch": "與 {branch} 比較", - "diffTitleCommitFile": "差異 · {name} @ {hash}", - "diffTitleCommit": "差異 · {hash}", - "diffDescriptionCommitPath": "{path} · 提交 {commit}", - "diffDescriptionCommit": "提交 {commit}", - "diffTitleConflictFile": "衝突 · {name}", - "diffDescriptionConflict": "{path} · 磁碟與未儲存內容" - }, - "chat": { - "acpConnections": { - "actions": { - "openAgentsSettings": "打開 Agents 管理", - "retry": "重試" - }, - "agentsSetupHint": "點擊前往設定 > Agents 管理安裝。", - "withSetupHint": "{message}\n提示:{hint}", - "blocked": { - "missingConfig": "無法讀取目前 Agent 設定。", - "disabled": "{agent} 已在 Agents 管理中停用,請先啟用後再連線。", - "unavailable": "{agent} 目前平台不可用。", - "sdkMissing": "{agent} SDK 尚未安裝", - "adapterMissing": "{agent} 的 ACP 轉接器尚未安裝" - }, - "backendErrors": { - "initializeTimeout": "{agent} 連線交握逾時(60 秒未回應),請前往設定頁面檢查智能體與網路設定。", - "mcpRejectedByAgent": "附帶 codeg 的 MCP 伴生程序時,{agent} 拒絕了本次會話:{message} 如果該智能體不支援 MCP,請在設定中關閉它的「MCP 支援」後重新連線。", - "processExited": "{agent} 處理程序意外結束。", - "spawnFailed": "啟動 {agent} 失敗:{message}", - "downloadFailed": "{agent} 下載失敗:{message}", - "sessionLoadResourceNotFound": "{agent} 會話載入失敗,可重新載入重試,或開始新會話。", - "sessionLoadUnavailable": "{agent} 無法還原此會話,它可能已結束或 agent 已停止。可重新載入重試,或開始新會話。", - "turnFailedRefusal": "{agent} 拒絕繼續此輪回覆,通常代表後端或網關出錯,請檢查代理日誌。", - "turnFailedMaxTokens": "{agent} 已達到此輪回覆的最大 Token 限制。", - "turnFailedMaxTurnRequests": "{agent} 已達到此輪回覆允許的最大請求次數。", - "turnFailedUnknown": "{agent} 以未知的停止原因結束了此輪回覆。", - "grokModelSwitchIncompatibleAgent": "{agent} 無法在既有對話中切換到該模型,請新建工作階段以使用它。", - "turnFailedEmpty": "{agent} 此輪沒有產生任何回覆就結束了。", - "turnFailedEmptyProtocol": "{agent} 此輪的輸出 codeg 無法解析,可能是代理版本與協定不相符。", - "turnFailedEmptyMetadata": "{agent} 此輪只收到狀態更新(計畫 / 模式 / 用量),沒有收到任何回覆。", - "detailsInAlerts": "在狀態列的「警示」中展開詳情,即可查看代理輸出。" - }, - "unableReadAgentConfig": "無法讀取 Agent 設定:{message}", - "connectFailedTitle": "{agent} 連線失敗", - "toolFallbackTitle": "工具", - "eventErrorTitle": "Agent 錯誤", - "notificationTurnComplete": "{agent} 已完成回應", - "notificationError": "{agent} 錯誤:{message}", - "claudeApiRetry": { - "fallbackError": "authentication_failed", - "retryingWithMax": "正在重試 {attempt}/{max}", - "retryingAttempt": "正在重試(第 {attempt} 次)", - "retrying": "正在重試", - "nextRetryIn": "{seconds} 秒後重試", - "line": "{error}{status} · {retry}", - "lineWithDelay": "{error}{status} · {retry},{delay}", - "httpStatus": "(HTTP {status})" - }, - "configOptionAdjusted": "{agent} 把{option}設成了 {actual},而不是 {requested}" - }, - "connectionLifecycle": { - "tasks": { - "connectingTitle": "正在連線 {agent}", - "connectingDescription": "正在建立連線", - "loadingSelectorsTitle": "正在載入 {agent} 選擇項", - "loadingSelectorsDescription": "正在取得模式與會話設定選項", - "initSessionTitle": "正在初始化 {agent} 會話", - "initSessionDescription": "正在建立會話並載入設定" - }, - "errors": { - "connectionFailed": "連線失敗", - "sendPromptFailed": "訊息傳送失敗:{error}" - } - }, - "shared": { - "attachedResources": "附加資源", - "toolCallFailed": "工具呼叫失敗" - }, - "messageThread": { - "emptyTitle": "暫無訊息", - "emptyDescription": "開始一個會話後,訊息會顯示在這裡" - }, - "chatInput": { - "connecting": "連線中...", - "agentResponding": "{agent} 正在回應...", - "sendMessage": "傳送訊息..." - }, - "messageInput": { - "askAnything": "請開始輸入...", - "removeAttachmentAria": "移除 {name}", - "attachFiles": "附加檔案", - "addActions": "新增", - "quickMessages": "快捷訊息", - "quickMessagesEmpty": "尚無快捷訊息", - "quickMessagesLoading": "載入中...", - "pasteAsPlainText": "貼上純文字", - "cut": "剪下", - "copy": "複製", - "selectAll": "全選", - "pasteUnavailable": "無法讀取剪貼簿,請改用 Ctrl/⌘V 貼上。", - "clipboardWriteFailed": "無法寫入剪貼簿,請改用鍵盤快速鍵。", - "quickMessageUntitled": "未命名", - "liveFeedback": "即時回饋", - "liveFeedbackDisabledHint": "智能體工作時可傳送", - "dropFilesToAttach": "拖曳檔案到此處附加", - "loadingSettings": "正在載入設定...", - "loadingMode": "正在載入模式...", - "modeLabel": "模式", - "toggleOn": "開", - "toggleOff": "關", - "agentSettings": "智能體設定", - "searchModel": "搜尋模型...", - "searchModelAria": "搜尋模型", - "modelListLabel": "模型", - "noModels": "找不到模型", - "cancel": "取消", - "send": "傳送", - "forkAndSend": "分叉發送", - "queueMessage": "加入佇列", - "steerIntoTurn": "插入目前回合", - "steerQueuedInstead": "已轉入佇列——將隨下一回合傳送。", - "steerFailed": "無法插入目前回合", - "steerAttachmentsUnsupported": "僅支援純文字——帶附件的草稿請走佇列。", - "slashCommands": "斜線命令", - "slashSearchPlaceholder": "搜尋命令...", - "slashSearchEmpty": "沒有符合的指令", - "experts": "專家", - "office": "日常辦公", - "research": "科學研究", - "attachLocalUpload": "附加本機檔案", - "attachServerFile": "附加伺服器檔案", - "attachUploadTooLarge": "{names} 超過 {limit}MB 上傳上限,已略過。", - "attachUploadFailed": "上傳失敗:{names}。", - "attachUploadNotAFile": "{names} 不是常規檔案(目錄或特殊檔案),已略過。", - "attachUploadQuotaExceeded": "伺服器上傳空間已用盡,{names} 未能上傳。", - "attachUploadInProgress": "圖片仍在上傳中,請稍候再傳送。", - "mentionEmpty": "無相符項目", - "mentionLoading": "搜尋中…", - "mentionListLabel": "提及", - "mentionMore": "還有更多結果,繼續輸入以篩選", - "mentionCount": "{count, plural, other {# 項結果}}", - "mentionGroupFile": "檔案", - "mentionGroupAgent": "智能體", - "mentionGroupSession": "工作階段", - "mentionGroupCommit": "提交", - "mentionGroupSkill": "技能" - }, - "messageQueue": { - "addToQueue": "加入佇列", - "saveEdit": "儲存", - "cancelEdit": "取消編輯", - "editItem": "編輯", - "deleteItem": "刪除" - }, - "welcomeInputPanel": { - "agentsSettingsPath": "設定 > Agents", - "autoConnectFallback": "點擊前往 {path} 管理安裝。", - "autoConnectAppend": "{message},點擊前往 {path} 管理安裝。", - "enableAgentFirstPlaceholder": "請先啟用至少一個 Agent 後開始會話...", - "prepareSessionFailed": "無法準備聊天工作階段,請重試。", - "createConversationFailed": "無法建立會話,請重試。", - "askAnythingPlaceholder": "請開始輸入...", - "agentNotInstalled": "{agent} 尚未安裝 · 點擊前往 Agents 設定安裝", - "agentAdapterNotInstalled": "{agent} 的 ACP 轉接器尚未安裝(與你本機的 CLI 無關)· 點擊前往 Agents 設定安裝" - }, - "welcomePanel": { - "greeting": "今天打算做些什麼呢?", - "tips": { - "tileTabs": "右鍵點擊會話標籤選擇「平鋪顯示」,可同螢幕對比多個會話", - "pinTab": "雙擊會話標籤可將其固定,避免被新開啟的會話自動取代", - "shortcutsNewSearch": "{newConversation} 快速新建會話,{searchConversations} 搜尋歷史會話", - "slashAtMention": "在輸入框輸入 / 觸發斜線命令,輸入 @ 引用專案內檔案", - "pasteDropFiles": "直接貼上截圖或把檔案拖到輸入框,即可作為附件", - "queueMessage": "智能體回覆中也能繼續輸入並排隊,回答完畢會自動續發", - "draftAutoSave": "未發送的草稿會自動儲存,重新開啟會話仍在", - "forkSend": "傳送按鈕旁的下拉選擇「分叉傳送」,從目前位置開一條新分支", - "exportConversation": "右鍵會話內容區可匯出為 Markdown / HTML / 圖片", - "chatChannels": "在「設定 → 聊天頻道」接入 Telegram / 飛書 / 微信,從手機繼續操作", - "shortcutsAuxPanel": "{toggleAuxPanel} 切換右側面板,檢視本次會話改動的檔案與 Git 變更", - "shortcutsTerminalSidebar": "{toggleTerminal} 開啟內建終端機,{toggleSidebar} 切換側邊欄", - "customShortcuts": "所有快捷鍵都可在「設定 → 快捷鍵」中自訂", - "webService": "開啟「設定 → Web 服務」後,團隊成員可從瀏覽器接入同一臺 codeg", - "fusionMode": "開啟檔案或差異後,會自動與會話並排顯示", - "quickMessages": "點輸入框旁的 + 按鈕選擇「快捷訊息」,可一鍵插入預存片段(在「設定 → 快捷訊息」中管理)", - "experts": "透過 + 按鈕裡的「專家技能」可一鍵載入預設角色(除錯 / 規劃等)", - "taskBoard": "「待辦任務」能把一條待辦從頭跑到尾:智能體在獨立工作樹裡執行,你檢視完差異再合併。", - "automations": "「自動化」按排程定時執行儲存好的提示詞(例如每晚一次程式碼審查),還能讓每次執行都開一個獨立工作樹。", - "tokenUsage": "點擊狀態列左下角的會話數即可開啟「Token 用量」,按日期、智能體、模型與資料夾拆分統計。", - "mentionTargets": "@ 不只能引用檔案:還能 @ 另一個智能體把子任務交給它,或引用歷史會話、某次提交、某個技能。", - "splitGroups": "右鍵點擊標籤選擇「向右拆分」或「向下拆分」,兩個會話各佔一個分割區同時開著。", - "worktrees": "點開分支按鈕選「新增工作樹」,多個智能體就能在同一個儲存庫並行工作,互不覆蓋彼此的檔案。", - "importSessions": "之前在終端機裡跑過的會話,用資料夾右鍵選單的「匯入本地會話」就能把那段歷史接進 codeg。", - "subSessions": "智能體委派出去的子會話會巢狀顯示在側邊欄的父會話底下,展開就能追蹤每一個子會話做了什麼。", - "liveFeedback": "「+」選單裡的「即時回饋」能把一則便條塞進智能體正在跑的這一輪,不用打斷它。", - "skillPacks": "設定 → 技能包 裡打包了程式專家、科研與辦公三類技能,可以按智能體分別開關。", - "modelProviders": "設定 → 模型供應商 支援填自己的 API key 或端點位址,之後直接在輸入框裡切換模型。", - "workspaceBackground": "設定 → 外觀 裡可以換工作區背景圖、調面板不透明度,還能換應用程式字型。" - }, - "quickActions": { - "excel": "Excel 活頁簿", - "excelDesc": "資料表、公式與圖表", - "word": "Word 文件", - "wordDesc": "報告、信函與備忘錄", - "ppt": "簡報", - "pptDesc": "專業設計的投影片", - "pitchDeck": "募資簡報", - "pitchDeckDesc": "含關鍵指標的募資簡報", - "morph": "Morph 動畫", - "morphDesc": "電影級投影片轉場", - "morph3d": "3D Morph", - "morph3dDesc": "3D 模型與鏡頭運動", - "academic": "學術論文", - "academicDesc": "含引用與結構的研究論文", - "financial": "財務模型", - "financialDesc": "報表、DCF 與預測", - "dashboard": "資料儀表板", - "dashboardDesc": "從資料產生 KPI 與分析", - "prompts": { - "excel": "建立一個 Excel 活頁簿,需求如下:\n\n[在此描述你的資料、表格、公式與圖表]", - "word": "建立一個 Word 文件,需求如下:\n\n[在此描述文件內容、結構與排版]", - "ppt": "建立一個 PowerPoint 簡報,需求如下:\n\n[在此描述投影片、內容與設計]", - "pitchDeck": "建立一個募資簡報,需求如下:\n\n[在此描述公司、募資輪次與關鍵指標]", - "morph": "建立一個帶 Morph 轉場動畫的簡報:\n\n[在此描述簡報主題與期望的視覺效果]", - "morph3d": "建立一個帶 GLB 模型與鏡頭運動的 3D Morph 簡報:\n\n[在此描述主題與 3D 視覺構想]", - "academic": "用 Word 撰寫一篇學術論文,需求如下:\n\n[在此描述研究主題、方法與主要發現]", - "financial": "用 Excel 建立一個財務模型,需求如下:\n\n[在此描述財務報表、預測與分析]", - "dashboard": "用 Excel 建立一個資料儀表板,需求如下:\n\n[在此描述資料來源、KPI 與圖表]", - "scientific-brainstorming": "幫我進行科研腦力激盪:探索跨學科連結、挑戰假設、發掘有潛力的研究缺口。我正在探索的方向:", - "hypothesis-generation": "幫我把這些觀察轉化為可檢驗的假設:提出明確預測、合理機制,並設計驗證實驗。我的觀察:", - "experimental-design": "在蒐集資料前幫我設計嚴謹的實驗:設計方案、隨機化、對照,以及如何避免干擾。我想研究的問題:", - "statistical-power": "幫我確定所需樣本數:為我的設計做檢定力分析(效應量、顯著水準、檢定力)。具體資訊:", - "statistical-analysis": "幫我正確分析這份資料:選擇合適的檢定、檢查假設、報告效應量並撰寫結論。我的資料與問題:", - "exploratory-data-analysis": "對我的資料檔案做探索性分析:概述其結構、品質與值得注意的模式,並建議後續步驟。檔案是:", - "scientific-visualization": "幫我製作出版級圖表:清晰佈局、真實誤差棒、色盲友善配色,以及期刊格式。我想展示的內容:", - "scientific-critical-thinking": "幫我批判性評估這項研究或主張:評估證據品質、辨識偏誤與干擾,並權衡結論。內容如下:", - "paper-lookup": "幫我在學術資料庫中查找相關論文與開放取用全文,並提供可重用的引用。我要找的是:" - }, - "paper-lookup": "論文檢索", - "paper-lookupDesc": "檢索 10 個學術 API(PubMed、arXiv、OpenAlex、Crossref…)查找論文、引用與開放取用全文。", - "scientific-critical-thinking": "批判性思維", - "scientific-critical-thinkingDesc": "評估科學主張與證據品質:辨識偏誤與干擾,運用 GRADE 與偏誤風險框架。", - "scientific-visualization": "科學視覺化", - "scientific-visualizationDesc": "出版級圖表:多面板佈局、顯著性標註與期刊專屬格式。", - "exploratory-data-analysis": "探索性資料分析", - "exploratory-data-analysisDesc": "對 200+ 種格式的科學資料檔案做自動化探索,輸出品質指標與報告。", - "statistical-analysis": "統計分析", - "statistical-analysisDesc": "引導式統計分析:檢定選擇、假設檢查、效應量與 APA 格式報告。", - "statistical-power": "統計檢定力", - "statistical-powerDesc": "樣本數與統計檢定力分析:所需樣本數、最小可檢測效應與檢定力曲線。", - "experimental-design": "實驗設計", - "experimental-designDesc": "在蒐集資料前設計嚴謹研究:隨機化、區集、對照與析因/DOE 佈局。", - "hypothesis-generation": "假設生成", - "hypothesis-generationDesc": "將觀察轉化為可檢驗的假設,提出預測、機制並設計驗證實驗。", - "scientific-brainstorming": "科學腦力激盪", - "scientific-brainstormingDesc": "開放式科研構思:探索跨學科連結、挑戰假設、發掘研究缺口。", - "tabs": { - "office": "日常辦公", - "coding": "程式開發", - "research": "科學研究" - }, - "coding": { - "brainstormingDesc": "動手前先梳理意圖與需求", - "debuggingDesc": "先定位根因再提出修復", - "writingSkillsDesc": "建立、編輯並驗證可重用技能" - }, - "notEnabled": { - "title": "「{skill}」技能尚未對 {agent} 啟用", - "description": "前往設定啟用後即可在此使用。", - "action": "前往啟用", - "hint": "技能未啟用" - }, - "scrollPrev": "顯示上一組技能", - "scrollNext": "顯示下一組技能" - } - }, - "agentSelector": { - "noEnabledAgents": "暫無已啟用的 Agent", - "openAgentsSettings": "開啟 Agents 設定", - "notInstalled": "未安裝", - "moreAgents": "更多 Agent({count})" - }, - "subAgentOverlay": { - "title": "子智能體", - "collapsedSummary": "子智能體 {count}", - "collapseAria": "摺疊子智能體" - }, - "agentPlanOverlay": { - "title": "計畫任務", - "collapsePlanAria": "摺疊計畫", - "collapsedSummary": "計畫 {completed}/{total}", - "status": { - "completed": "已完成", - "inProgress": "進行中", - "pending": "待處理", - "unknown": "未知" - }, - "priority": { - "high": "高", - "medium": "中", - "low": "低", - "unknown": "未知" - } - }, - "permissionDialog": { - "subtitle": "Agent 請求繼續目前輪次的權限。", - "queuedCount": "還有 {count} 項待審批", - "kindFallbackTool": "工具", - "command": "命令", - "cwd": "工作目錄:{cwd}", - "filesSummary": "檔案:{count}", - "moreFiles": "+{count} 個更多檔案", - "plan": "計畫", - "allowedActions": "允許的操作", - "targetMode": "目標模式:{mode}", - "optionGrants": "各選項將授予的權限", - "changeScopeSession": "本次工作階段", - "changeScopeProcess": "本次執行", - "changeScopeUser": "儲存至使用者設定", - "changeScopeProject": "儲存至專案設定", - "changeScopeProjectLocal": "儲存至本機專案設定", - "changeScopePersistent": "永久儲存" - }, - "questionDialog": { - "title": "代理正在提問", - "placeholder": "輸入你的回答...", - "send": "傳送" - }, - "messageBranch": { - "previousBranchAria": "上一個分支", - "nextBranchAria": "下一個分支", - "pageOf": "{current} / {total}" - }, - "terminal": { - "title": "終端", - "running": "執行中" - }, - "reasoning": { - "thinking": "思考中…", - "thoughtForFewSeconds": "思考", - "thoughtForSeconds": "思考" - }, - "linkSafety": { - "errorCannotOpen": "無法開啟本地檔案", - "errorNoWorkspace": "目前沒有活躍的工作區資料夾。", - "errorFailedOpen": "開啟本地檔案失敗", - "errorFailedLink": "開啟連結失敗", - "errorUnsupportedLinkProtocol": "不支援此連結協議。" - }, - "fileActions": { - "openInFinder": "在 Finder 開啟", - "openInExplorer": "在檔案總管開啟", - "openInFileManager": "在檔案管理器開啟", - "copyRelativePath": "複製相對路徑", - "copyAbsolutePath": "複製絕對路徑", - "pathCopied": "已複製路徑", - "copyPathFailed": "複製路徑失敗", - "openFailed": "開啟本地檔案失敗" - }, - "messageList": { - "attachedResources": "附加資源", - "loading": "載入中...", - "loadEarlier": "載入更早的訊息", - "loadingEarlier": "正在載入更早的訊息…", - "error": "錯誤:{message}", - "errorTitle": "會話載入失敗", - "errorActionReload": "重新載入", - "errorActionNewSession": "新建會話", - "emptyConversation": "目前會話暫無訊息。", - "systemMessage": "系統訊息", - "copyMessage": "複製", - "copied": "已複製", - "downloadImage": "下載圖片", - "downloadFailed": "下載失敗:{message}", - "imageGeneration": "圖片生成", - "imageGenerationPending": "正在生成圖片…", - "imageGenerationFailed": "圖片生成失敗", - "model": "模型", - "tokenStats": "Token 使用情況", - "tokenInput": "輸入", - "tokenOutput": "輸出", - "tokenCacheRead": "快取讀取", - "tokenCacheWrite": "快取寫入", - "duration": "耗時", - "completedAt": "完成時間", - "jumpToPreviousUserMessage": "跳轉到上一條使用者訊息", - "showMore": "展開", - "showLess": "收合" - }, - "liveTurnStats": { - "thinking": "思考中...", - "streaming": "生成中", - "elapsedHours": "{value} 小時", - "elapsedMinutes": "{value} 分鐘", - "elapsedSeconds": "{value} 秒", - "outputSpeedAria": "估算輸出速度", - "outputSpeedTooltip": "估算輸出速度(正文 + 思考)" - }, - "jsonTree": { - "viewRaw": "檢視原始 JSON", - "viewTree": "檢視樹狀檢視", - "fields": "{count} 個欄位", - "items": "{count} 項" - }, - "tool": { - "parameters": "參數", - "error": "錯誤", - "result": "結果", - "status": { - "approvalRequested": "等待授權", - "approvalResponded": "已回應", - "inputAvailable": "執行中", - "inputStreaming": "等待中", - "outputAvailable": "已完成", - "outputDenied": "已拒絕", - "outputError": "錯誤" - } - }, - "toolCallBlock": { - "tool": "工具", - "error": "錯誤", - "result": "結果" - }, - "delegation": { - "subAgentRunning": "子代理執行中…", - "noDetail": "暫無詳情。", - "unknownAgent": "子智慧體", - "openDetail": "檢視會話", - "detailTitle": "子智慧體會話", - "detailDescription": "唯讀檢視委派給子智慧體的會話內容。", - "waitForResult": "等待 {task} 任務執行結果", - "waitForResultNoTask": "等待任務執行結果", - "cancelTask": "取消 {task} 任務", - "cancelTaskNoTask": "取消任務", - "resultPageOf": "{current} / {total}", - "prevResult": "上一個結果", - "nextResult": "下一個結果", - "noResultText": "本次檢查暫無結果", - "status": { - "starting": "啟動中", - "running": "執行中", - "checked": "已查詢", - "waiting": "待批准", - "ok": "完成", - "err": { - "default": "失敗", - "delegation_disabled": "已停用", - "depth_limit": "深度超限", - "invalid_agent_type": "代理類型無效", - "spawn_failed": "啟動失敗", - "send_failed": "傳送失敗", - "timeout": "逾時", - "canceled": "已取消", - "child_refusal": "子代理拒絕", - "child_max_tokens": "子代理超出 token 上限", - "child_max_turn_requests": "子代理超出請求上限", - "child_empty": "子代理無回應", - "child_unknown": "子代理未知錯誤", - "unknown": "未知任務" - } - } - }, - "contentParts": { - "showingTailOutput": "為確保效能,串流輸出時僅顯示尾端內容。", - "result": "結果", - "unknown": "未知", - "inputTruncated": "輸入已截斷,diff 可能不完整。", - "replaceAll": "全部替換", - "filesCount": "檔案:{count}", - "update": "更新", - "moreFiles": "+{count} 個更多檔案", - "timeoutMs": "逾時:{timeout}ms", - "backgroundTrue": "背景:true", - "scriptToolCalls": "呼叫 {count} 個工具", - "offset": "位移:{offset}", - "limit": "限制:{limit}", - "pages": "頁碼:{pages}", - "mode": "模式:{mode}", - "cell": "儲存格:{cell}", - "shellSession": "工作階段 {id}", - "pathLabel": "路徑:", - "globLabel": "Glob:", - "typeLabel": "類型:", - "outputLabel": "輸出:", - "caseInsensitive": "不區分大小寫", - "multiline": "多行", - "promptLabel": "提示詞", - "subjectLabel": "主題", - "taskLabel": "任務", - "nameLabel": "名稱:", - "agentPromptLabel": "提示詞", - "agentModelLabel": "模型", - "agentRunning": "執行中...", - "agentLiveTranscript": "即時活動", - "agentProgressTools": "{count} 次工具調用", - "agentProgressTurns": "{count} 輪", - "agentProgressContext": "上下文 {pct}%", - "agentSessionAction": "檢視子智慧體工作階段", - "agentSessionTitle": "子智慧體工作階段", - "agentSessionLoading": "正在載入子智慧體的對話記錄…", - "agentSessionEmpty": "子智慧體尚未寫入任何內容。", - "agentFallbackTitle": "子智能體啟動中…", - "agentCodexLaunchOnly": "已啟動。Codex 不會再回報這個子智能體的進度——它的結果會以一則訊息出現在本工作階段中。", - "agentStatsBash": "命令", - "agentStatsRead": "讀取檔案", - "agentStatsSearch": "搜尋", - "agentStatsEdit": "編輯", - "agentStatsOther": "其他", - "goal": { - "title": "目標:", - "titleWithStatus": "目標{status}", - "objective": "目標", - "statusLabel": "狀態", - "tokensUsed": "已用 tokens", - "budget": "預算", - "remaining": "剩餘", - "elapsed": "耗時", - "tokens": "tokens", - "pause": "暫停", - "clear": "清除", - "status": { - "active": "進行中", - "paused": "已暫停", - "blocked": "受阻", - "usageLimited": "用量受限", - "budgetLimited": "預算受限", - "complete": "已完成", - "limited": "已達上限" - } - }, - "field": { - "file": "檔案", - "notebook": "筆記本", - "command": "命令", - "old": "舊內容", - "new": "新內容", - "pattern": "模式", - "path": "路徑", - "query": "查詢", - "url": "URL 位址", - "description": "描述", - "content": "內容", - "source": "來源內容", - "prompt": "提示詞", - "subject": "主題", - "taskId": "任務 ID", - "status": "狀態", - "skill": "Skill", - "args": "參數", - "offset": "位移", - "limit": "限制", - "glob": "Glob", - "type": "類型", - "output": "輸出", - "replaceAll": "全部替換", - "language": "語言", - "timeout": "逾時", - "background": "背景", - "agentType": "Agent 類型", - "library": "函式庫", - "libraryId": "函式庫 ID" - }, - "title": { - "edit": "編輯", - "command": "命令", - "script": "腳本", - "waitCommand": "等待 {command}", - "waitCell": "等待工作階段 {id}", - "terminateCommand": "終止 {command}", - "terminateCell": "終止工作階段 {id}", - "stdinChars": "輸入 {chars}", - "todoWrite": "待辦", - "read": "讀取", - "write": "寫入", - "notebookEdit": "Notebook 編輯", - "editFiles": "編輯({count} 個檔案)", - "editWithTarget": "編輯 {target}", - "readWithTarget": "讀取 {target}", - "writeWithTarget": "寫入 {target}", - "notebookEditWithTarget": "Notebook 編輯 {target}", - "globWithPattern": "Glob {pattern}", - "listFilesWithPath": "列出檔案 {path}", - "grepWithPattern": "Grep {pattern}", - "taskCreateWithSubject": "建立任務:{subject}", - "taskUpdateWithStatus": "更新任務 #{id} -> {status}", - "taskUpdate": "更新任務 #{id}", - "webFetchWithUrl": "擷取網頁 {url}", - "webSearchWithQuery": "網頁搜尋:{query}", - "todosProgress": "待辦({done}/{total})", - "skillWithName": "Skill:{name}", - "genericWithContext": "{tool}:{context}" - }, - "search": { - "noMatches": "無相符結果", - "matchSummary": "{matches} 處相符 · {files} 個檔案", - "fileSummary": "{files} 個檔案", - "moreResults": "另有 {count} 筆結果未顯示" - }, - "toolGroup": { - "search": "搜尋 {count} 次", - "command": "執行 {count} 個指令", - "read": "讀取 {count} 次檔案", - "memory": "回憶 {count} 項記憶", - "edit": "編輯 {count} 次檔案", - "fetch": "抓取 {count} 個資源", - "think": "思考 {count} 次", - "todo": "更新 {count} 項待辦", - "task": "執行 {count} 個任務", - "other": "呼叫 {count} 個工具", - "errorSuffix": "{count} 個失敗", - "joiner": " · " - }, - "planMode": { - "entered": "進入計畫模式", - "planLabel": "計畫", - "reviewApproved": "已核准執行計畫", - "reviewKept": "維持在計畫模式", - "reviewPending": "等待計畫決定", - "submitted": "計畫已提交", - "switched": "切換模式" - }, - "backgroundTask": { - "title": "背景任務", - "titleWithId": "背景任務 · {id}", - "running": "執行中", - "completed": "已完成", - "failed": "失敗", - "stopped": "已停止", - "exitCode": "退出碼 {code}", - "polledTimes": "輪詢 {count} 次", - "runningInBackground": "背景執行", - "launchNote": "已在背景執行 · {id}" - }, - "codexScript": { - "outputMissing": "codex 截斷指令碼輸出時捨棄了這個命令的分隔行,因此沒有輸出可歸屬給它。", - "sharedWith": "本段還包含 {commands} 的輸出——它們的分隔行已被 codex 截斷捨棄。", - "truncated": "已截斷" - } - }, - "messageNav": { - "title": "訊息導覽", - "collapse": "收合訊息導覽", - "collapsedSummary": "訊息 {count}", - "fileCount": "{count} 個檔案", - "remove": "移除", - "noDiffDataAvailable": "找不到 {filePath} 的差異資料" - }, - "replyArtifacts": { - "title": "變更檔案", - "fileCount": "{count} 個檔案", - "newFilesTitle": "新增檔案", - "revealInFolder": "在 Finder/檔案總管中顯示", - "openFile": "開啟 {filePath}", - "openInEditor": "在編輯器中開啟", - "remove": "移除", - "noDiffDataAvailable": "找不到 {filePath} 的差異資料" - }, - "askQuestion": { - "title": "智能體需要你的選擇", - "subtitle": "回答後點擊提交,可隨時跳過", - "recommended": "推薦", - "other": "其他", - "otherPlaceholder": "輸入你的回答…", - "singleSelect": "單選", - "multiSelect": "多選", - "skip": "略過", - "next": "下一題", - "submit": "提交", - "submitError": "提交失敗,請重試。" - }, - "planApproval": { - "title": "智慧代理已提出計畫——請審閱", - "emptyPlan": "智慧代理未寫入計畫。可核准開始實作,或要求修改。", - "approve": "核准並開始", - "requestChanges": "要求修改", - "abandon": "放棄", - "feedbackPlaceholder": "需要修改什麼?", - "sendChanges": "傳送", - "cancel": "取消", - "submitError": "提交失敗,請重試。" - }, - "feedbackCheckResult": { - "count": "{count} 則回饋", - "expand": "展開全部回饋", - "collapse": "收合", - "errorTitle": "回饋檢查失敗" - }, - "askQuestionResult": { - "title": "提問", - "answeredLabel": "提問回答:", - "awaiting": "等待你的回答…", - "declined": "你已略過此問題 — 代理已自行判斷。", - "noSelection": "未選擇" - }, - "configStale": { - "agentConfigTitle": "智能體設定已更新", - "modelProviderTitle": "模型供應商已更新", - "description": "目前的工作階段仍在使用舊設定,重新連線後生效(對話紀錄不會遺失)。", - "reconnect": "重新連線以套用", - "reconnecting": "正在重新連線…", - "reconnectDisabledDuringTurn": "目前回合結束後可重新連線", - "dismiss": "忽略", - "reconnectFailed": "重新連線工作階段失敗", - "applied": "已套用新設定" - }, - "piProjectTrust": { - "title": "此專案自帶 pi 資源", - "description": "pi 未載入儲存庫自帶的 .pi 檔案。請檢視後決定。", - "descriptionExecutable": "儲存庫自帶 pi 擴充功能,擴充功能會在啟動時執行程式碼。pi 尚未載入它們,請先檢視再決定。", - "review": "檢視…", - "dismiss": "忽略", - "dialogTitle": "信任此專案的 pi 資源?", - "dialogDescription": "只有在你信任該目錄後,pi 才會載入儲存庫自帶的 .pi 檔案。請僅在你信任此儲存庫內容時才信任。", - "executionWarning": "擴充功能就是程式碼。信任該目錄後,儲存庫中的擴充功能會在 pi 啟動時以你的權限執行——早於你送出任何訊息。", - "scopeNote": "此決定儲存在 pi 的 trust.json 中,對該目錄下的所有子目錄同樣生效,你在終端機自行執行 pi 時也會沿用。之後可在「設定 → 智慧代理 → Pi」中修改。", - "trust": "信任專案", - "decline": "保持不載入", - "disabledDuringTurn": "目前回合結束後可用", - "trustedToast": "已信任專案——已重新連線以便 pi 載入其資源", - "declinedToast": "專案資源保持不載入", - "saveFailed": "儲存專案信任決定失敗", - "grantTitle": "此專案已被信任", - "grantDescription": "pi 會載入此儲存庫自帶的 .pi 檔案。請檢視這代表什麼。", - "grantInheritedDescription": "某個上層目錄已被信任,因此 pi 會載入此儲存庫自帶的 .pi 檔案。請檢視這代表什麼。", - "grantDialogTitle": "此專案的 pi 資源已被信任", - "grantDialogDescription": "pi 被允許載入此儲存庫自帶的 .pi 檔案。舊版 codeg 會在你開啟目錄時自動授予此權限,因此你可能從未被詢問過。", - "grantExecutionWarning": "擴充功能就是程式碼。儲存庫中的擴充功能會在 pi 啟動時以你的權限執行——早於你送出任何訊息。", - "inheritedFrom": "信任來自", - "revoke": "撤銷信任", - "keepTrusted": "保持信任", - "revokedToast": "已撤銷信任——已重新連線,pi 不再載入此專案的資源", - "trustedNoReconnect": "已信任專案——將在 pi 下次啟動時生效", - "revokedNoReconnect": "已撤銷信任——將在 pi 下次啟動時生效" - }, - "collabAgent": { - "title": "子智能體", - "errorTitle": "子智能體任務失敗", - "statesLabel": "子智能體", - "statusRunning": "執行中", - "statusCompleted": "已完成", - "statusFailed": "失敗", - "statusPending": "初始化中", - "statusInterrupted": "已中斷", - "statusClosed": "已關閉", - "statusNotFound": "未找到", - "opSpawn": "啟動子智能體", - "opWait": "取得子智能體結果", - "opClose": "結束子智能體", - "opResume": "恢復子智能體" - }, - "contextCompaction": { - "compacting": "正在壓縮上下文…", - "compacted": "上下文已壓縮", - "compactedTokens": "上下文已壓縮 · {before} → {after} tokens", - "failed": "上下文壓縮失敗" - }, - "sessionFailure": { - "category": { - "connection": "連線異常", - "access": "存取受限", - "limit": "已達限制", - "request": "請求被拒絕", - "service": "服務異常", - "unknown": "會話異常" - }, - "action": { - "retry": "重試", - "login": "去登入", - "newSession": "新增會話" - }, - "recovered": "已恢復", - "retryUnavailable": "沒有可重發的訊息。", - "toggleDetails": "展開/收合詳情" - }, - "backgroundTasks": { - "running": "{count} 個背景任務執行中", - "settling": "正在同步背景結果…", - "settledFallback": "背景任務已結束({status})", - "cardRunning": "背景執行中", - "cardLaunchedPending": "已啟動背景任務", - "cardCompleted": "背景任務已完成", - "cardFinishedWithStatus": "背景任務已結束({status})", - "cardResultPending": "結果尚未返回" - }, - "proposedPlan": { - "title": "計劃提案", - "planning": "規劃中…" - } - }, - "diffPreview": { - "mode": { - "added": "新增", - "deleted": "刪除", - "renamed": "重新命名", - "modified": "修改" - }, - "hunkLabel": "區塊 {index}", - "loadingHunk": "正在載入區塊...", - "noDiffData": "無差異資料", - "showRemainingLines": "顯示剩餘 {count} 行" - }, - "conversationContextBar": { - "folderTitle": "工作資料夾", - "branchTitle": "工作分支", - "searchFolder": "Search folder...", - "searchBranch": "Search branch...", - "noFolders": "No folders", - "noBranches": "No branches", - "noBranch": "(no branch)", - "chatModeLabel": "聊天模式", - "commit": "Commit", - "push": "Push", - "merge": "Merge", - "toasts": { - "folderChanged": "Switched to {name}", - "openFolderFailed": "Failed to open folder", - "switchedToChatMode": "已切換到聊天模式", - "openStashFailed": "Failed to open stash window", - "openMergeFailed": "Failed to open merge window" - } - }, - "cloneDialog": { - "title": "複製倉庫", - "repositoryUrl": "倉庫地址", - "repositoryUrlPlaceholder": "https://github.com/user/repo.git", - "directory": "目錄", - "directoryPlaceholder": "選擇目標目錄...", - "browseDirectory": "瀏覽目錄", - "cancel": "取消", - "clone": "複製", - "clonePath": "克隆路徑: {path}" - }, - "toasts": { - "cloneFailed": "複製倉庫失敗" - } - }, - "ProjectBoot": { - "title": "專案啟動器", - "tabs": { - "shadcn": "shadcn", - "hyperframes": "HyperFrames" - }, - "hyperframes": { - "title": "HyperFrames 影片專案", - "subtitle": "建立一個 HTML 轉影片專案,接著工作區的智慧代理即可撰寫並算繪它。", - "resolution": "解析度", - "skillsTitle": "智慧代理技能", - "skillsDesc": "為所選代理全域安裝 HyperFrames 技能(符號連結),讓它們會編寫並算繪影片。", - "recheck": "重新檢查", - "installedBadge": "已安裝", - "skillsInstall": "安裝 / 更新技能", - "skillsInstalling": "正在安裝技能…", - "skillsInstalled": "HyperFrames 技能安裝成功", - "skillsInstallFailed": "HyperFrames 技能安裝失敗" - }, - "config": { - "base": "基礎庫", - "style": "風格", - "baseColor": "基礎顏色", - "theme": "主題", - "chartColor": "圖表顏色", - "iconLibrary": "圖示庫", - "font": "字體", - "fontHeading": "標題字體", - "menuAccent": "選單強調", - "menuColor": "選單顏色", - "radius": "圓角", - "template": "模板", - "createProject": "建立專案", - "sectionStyle": "風格", - "sectionColors": "配色", - "sectionTypography": "排版", - "sectionInterface": "介面" - }, - "preview": { - "loading": "載入預覽..." - }, - "createDialog": { - "title": "建立專案", - "projectName": "專案名稱", - "projectNamePlaceholder": "my-app", - "frameworkTemplate": "框架模板", - "packageManager": "套件管理器", - "saveDirectory": "儲存目錄", - "saveDirectoryPlaceholder": "選擇目錄...", - "browseDirectory": "瀏覽", - "projectPath": "專案將建立在:{path}", - "advancedOptions": "進階選項", - "base": "基礎庫", - "enableRtl": "啟用 RTL 支援", - "enableRtlDescription": "為從右到左書寫的語言(如阿拉伯語、希伯來語)啟用佈局支援", - "pmChecking": "正在檢測...", - "pmNotInstalled": "未安裝", - "cancel": "取消", - "create": "建立", - "creating": "正在建立專案..." - }, - "toasts": { - "createFailed": "建立專案失敗", - "createSuccess": "專案建立成功", - "openWorkspaceFailed": "專案已建立,但無法在工作區中開啟" - }, - "errors": { - "directoryExists": "目標目錄已存在", - "commandFailed": "專案建立命令執行失敗。" - } - }, - "WebServiceSettings": { - "addressSwitchHint": "切換只會改變這裡顯示與開啟的位址;服務會監聽所有網路介面,每個位址都可存取。", - "sectionTitle": "Web 服務", - "sectionDescription": "啟用後可透過瀏覽器遠端存取 Codeg", - "port": "連接埠", - "status": "狀態", - "autoStart": "自動啟動", - "autoStartHint": "Codeg 啟動時自動開啟 Web 服務", - "running": "執行中", - "stopped": "已停止", - "processing": "處理中...", - "start": "啟動", - "stop": "停止", - "startFailed": "啟動失敗", - "stopFailed": "停止失敗", - "saveConfigFailed": "儲存 Web 服務設定失敗", - "open": "開啟", - "hide": "隱藏", - "show": "顯示", - "copy": "複製", - "qrcode": "QR 碼", - "qrcodeTitle": "掃碼開啟", - "qrcodeHint": "用手機掃描,在瀏覽器中開啟 Codeg", - "addressLabel": "存取位址", - "tokenLabel": "存取 Token", - "tokenHint": "Web 用戶端首次存取時需輸入此 Token", - "tokenPlaceholder": "留空則自動產生", - "regenerate": "重新產生", - "stalePortOccupiedTitle": "連接埠 {port} 已被其他行程佔用", - "stalePortUnknownTitle": "連接埠 {port} 狀態不明", - "stalePortHint": "在連接埠釋放前 Codeg 無法繫結。可以更換上方的連接埠,或結束佔用該連接埠的行程。", - "errors": { - "alreadyRunning": "Web 服務已在執行", - "invalidAddress": "主機或連接埠格式無效", - "portInUse": "連接埠 {port} 已被佔用,請關閉佔用的程式或改用其他連接埠", - "permissionDenied": "權限不足,請使用 1024 以上的連接埠,或以更高權限執行", - "addressUnavailable": "該位址在本機不可用", - "bindFailed": "綁定位址失敗" - } - }, - "DirectoryBrowser": { - "title": "瀏覽目錄", - "pathPlaceholder": "輸入目錄路徑...", - "goHome": "回到主目錄", - "navigateUp": "返回上層目錄", - "select": "選擇", - "cancel": "取消", - "loading": "載入中...", - "emptyDirectory": "此目錄為空", - "errorLoadingDir": "載入目錄失敗", - "permissionDenied": "權限不足" - }, - "ChatChannelSettings": { - "loading": "載入中...", - "sectionTitle": "訊息頻道", - "sectionDescription": "設定 IM 機器人,接收事件通知和查詢編碼活動。", - "addChannel": "新增頻道", - "noChannels": "尚未設定任何訊息頻道。", - "channelName": "名稱", - "channelNamePlaceholder": "我的 Telegram 機器人", - "channelType": "頻道類型", - "lark": "飛書", - "weixin": "微信", - "dailyReport": "每日報告", - "dailyReportTime": "推送時間", - "nameRequired": "請輸入頻道名稱。", - "tokenRequired": "請輸入 Token。", - "chatIdRequired": "請輸入 Chat ID。", - "topicMode": "話題群模式", - "topicModeHint": "將 Telegram forum topics 路由為獨立 Codeg 對話。Bot 必須加入 forum supergroup,並擁有管理 topics 權限。", - "loadFailed": "載入頻道失敗。", - "saveFailed": "儲存失敗。", - "connectSuccess": "頻道已連線。", - "connectFailed": "連線失敗", - "disconnectSuccess": "頻道已斷線。", - "disconnectFailed": "斷線失敗。", - "testSuccess": "連線測試通過。", - "testFailed": "連線測試失敗", - "deleteSuccess": "頻道已刪除。", - "deleteFailed": "刪除頻道失敗。", - "deleteConfirmTitle": "刪除頻道", - "deleteConfirmMessage": "將永久刪除該頻道及其訊息紀錄,確定嗎?", - "cancel": "取消", - "delete": "刪除", - "create": "建立", - "save": "儲存", - "channelListTitle": "已設定頻道", - "channelListDescription": "已啟用的頻道在服務啟動時會自動連線。", - "editChannel": "編輯頻道", - "editSuccess": "頻道已更新。", - "tokenPlaceholderKeep": "留空保持不變", - "weixinScanTitle": "掃碼登入", - "weixinScanDescription": "打開微信掃描二維碼以連接。", - "weixinQrcodeExpired": "二維碼已過期。", - "weixinRefreshQrcode": "重新整理", - "weixinWaitingScan": "等待掃碼...", - "weixinPollError": "連接不穩定,正在重試...", - "weixinReconnectNotice": "因 iLink 協議限制,每次重新連接後需先主動向機器人發送一條訊息,事件觸發才會生效。", - "connect": "連線", - "disconnect": "斷開", - "test": "測試連線", - "tabs": { - "channels": "頻道", - "commands": "指令", - "events": "事件", - "other": "其他" - }, - "commands": { - "title": "內建指令", - "description": "訊息頻道中可用的 Bot 指令。群組聊天中需 @Bot 才會處理訊息。", - "prefixLabel": "指令前綴", - "prefixDescription": "觸發 Bot 指令的前綴,1-3 個非字母數字字元(預設 /)。", - "prefixSaved": "指令前綴已儲存。", - "prefixSaveFailed": "儲存指令前綴失敗。", - "prefixInvalid": "前綴必須是 1-3 個非字母數字字元。", - "save": "儲存", - "folderDesc": "選擇工作目錄", - "agentDesc": "選擇 AI Agent", - "taskDesc": "建立會話並執行任務", - "sessionsDesc": "列出當前目錄的活躍會話", - "resumeDesc": "最近對話 / 恢復指定對話", - "cancelDesc": "取消當前任務", - "approveDesc": "批准 Agent 權限請求", - "denyDesc": "拒絕 Agent 權限請求", - "searchDesc": "依關鍵字搜尋對話", - "todayDesc": "今日活動摘要", - "statusDesc": "頻道連線狀態", - "helpDesc": "顯示說明" - }, - "events": { - "title": "事件通知", - "description": "啟用事件後,事件被觸發時將推送到頻道。", - "turnComplete": "對話完成", - "turnCompleteDesc": "代理回合結束時", - "error": "代理錯誤", - "errorDesc": "代理遇到錯誤時", - "permissionRequest": "權限請求", - "permissionRequestDesc": "智慧代理請求操作權限時", - "questionRequest": "智慧代理提問", - "questionRequestDesc": "當智慧代理向你提問時", - "userPromptSent": "使用者訊息", - "userPromptSentDesc": "當你傳送訊息時——通知中會包含訊息內容", - "saved": "事件篩選已更新。", - "saveFailed": "儲存事件篩選失敗。", - "loadFailed": "載入設定失敗。", - "retry": "重試", - "webhooksTitle": "Webhook", - "webhooksDescription": "事件觸發時,向一個或多個位址 POST 一份 JSON。上方的事件篩選同樣作用於 Webhook。", - "webhookUrlPlaceholder": "https://example.com/webhook", - "addWebhook": "新增 Webhook", - "removeWebhook": "刪除 Webhook", - "webhookSave": "儲存", - "webhooksSaved": "Webhook 已儲存。", - "webhooksSaveFailed": "儲存 Webhook 失敗。", - "webhookInvalidUrl": "請輸入有效的 http(s) 位址。", - "docsTitle": "請求格式", - "docsMethod": "請求方式", - "docsContentType": "內容類型", - "docsNote": "每個啟用的事件都會投遞到所有位址。Webhook 不做去抖;上方的事件篩選仍然生效。", - "editWebhook": "編輯 Webhook", - "enableWebhook": "啟用 Webhook", - "webhookDuplicate": "該位址已設定。", - "cancel": "取消", - "webhooksEmpty": "尚未設定 Webhook。", - "deleteWebhookTitle": "刪除 Webhook", - "deleteWebhookMessage": "刪除此 Webhook?事件將不再傳送到該網址。", - "delete": "刪除" - }, - "language": { - "title": "訊息語言", - "description": "事件通知、指令回應和每日報告推送到訊息頻道時使用的語言。", - "saved": "訊息語言已儲存。", - "saveFailed": "儲存訊息語言失敗。", - "en": "英語", - "zh-cn": "簡體中文", - "zh-tw": "繁體中文", - "ja": "日語", - "ko": "韓語", - "es": "西班牙語", - "de": "德語", - "fr": "法語", - "pt": "葡萄牙語", - "ar": "阿拉伯語" - } - }, - "ModelProviderSettings": { - "sectionTitle": "模型供應商", - "sectionDescription": "管理 Agent 的 API 供應商憑據。", - "filterAll": "全部", - "providerListTitle": "已配置的供應商", - "addProvider": "新增供應商", - "editProvider": "編輯供應商", - "noProviders": "尚未配置模型供應商。", - "providerName": "名稱", - "providerNamePlaceholder": "例如 OpenAI、Anthropic", - "apiUrl": "API 位址", - "apiUrlPlaceholder": "https://api.openai.com/v1", - "apiKey": "API 金鑰", - "apiKeyPlaceholder": "sk-...", - "apiKeyKeepCurrent": "留空則保持不變", - "agentTypes": "代理類型", - "agentTypesRequired": "至少選擇一個代理類型。", - "agentType": "智能體類型", - "agentTypeRequired": "請選擇智能體類型。", - "agentTypeImmutableHint": "智能體類型建立後不可修改。", - "model": "模型", - "modelPlaceholderCodex": "gpt-5.6-sol / gpt-5.5", - "modelPlaceholderGemini": "gemini-3-pro-preview", - "claudeMainModel": "主要模型", - "claudeReasoningModel": "推理模型(思考)", - "claudeHaikuDefaultModel": "預設 Haiku 模型", - "claudeSonnetDefaultModel": "預設 Sonnet 模型", - "claudeOpusDefaultModel": "預設 Opus 模型", - "claudeCustomModelOption": "自訂模型 ID", - "claudeCustomModelOptionName": "自訂模型名稱", - "claudeCustomModelOptionDescription": "自訂模型描述", - "claudeCustomModelOptionHint": "在 Claude 模型選擇器中新增一個自訂項目(例如透過自訂閘道/代理提供的模型)。名稱與描述為選填的顯示資訊。", - "nameRequired": "供應商名稱不能為空。", - "apiUrlRequired": "API 位址不能為空。", - "apiKeyRequired": "API 金鑰不能為空。", - "loadFailed": "載入供應商失敗。", - "saveFailed": "儲存變更失敗。", - "createSuccess": "供應商已建立。", - "editSuccess": "供應商已更新。", - "deleteSuccess": "供應商已刪除。", - "deleteConfirmTitle": "刪除供應商", - "deleteConfirmMessage": "確定要永久刪除供應商「{name}」嗎?", - "deleteBlockedByAgent": "{agents} 正在使用此設定,請先解除關聯後再刪除。", - "cancel": "取消", - "delete": "刪除", - "create": "建立", - "save": "儲存", - "affectedRunningSessions": "{count} 個進行中的工作階段需重新連線以套用變更" - }, - "SkillMatrix": { - "loading": "載入中…", - "searchPlaceholder": "依名稱、ID 或描述搜尋", - "empty": "暫無內容。", - "emptySearch": "沒有符合目前搜尋的結果。", - "skillColumn": "技能", - "selectAll": "全選可見項目", - "selectSkill": "選擇 {name}", - "everything": { - "label": "批次", - "enable": "全部啟用(可見)", - "disable": "全部停用(可見)" - }, - "columnMenu": { - "enableAll": "啟用全部技能", - "disableAll": "停用全部技能" - }, - "rowMenu": { - "label": "對 {name} 批次操作", - "enableAll": "對所有 agent 啟用", - "disableAll": "對所有 agent 停用" - }, - "bulk": { - "selected": "已選擇 {count} 項", - "targetAll": "全部 agent", - "targetSome": "{count} 個 agent", - "enable": "啟用", - "disable": "停用", - "clear": "清除" - }, - "confirm": { - "disableTitle": "停用這些連結?", - "disableBody": "這將移除 {count} 個由 codeg 管理的技能連結。佔用自訂目錄的技能不受影響。你可以隨時重新啟用。", - "cancel": "取消", - "confirm": "停用" - }, - "toasts": { - "loadFailed": "載入技能狀態失敗", - "applyFailed": "套用變更失敗", - "enabled": "已啟用 {count} 個連結", - "disabled": "已停用 {count} 個連結", - "enabledPartial": "已啟用 {ok} 個,{failed} 個失敗", - "disabledPartial": "已停用 {ok} 個,{failed} 個失敗" - }, - "detail": { - "enableForAgents": "為 agent 啟用", - "preview": "SKILL.md 預覽", - "loadingContent": "載入內容中…" - }, - "copyModeHint": "已複製(非連結)——更新後請重新啟用以取得最新版本" - }, - "ExpertsSettings": { - "title": "專家技能", - "description": "為 AI 編碼代理啟用精心挑選、經過實戰驗證的技能工作流程。每個專家都是 superpowers 專案中的獨立技能 —— codeg 維護中央副本,並將其軟連結到你選擇的代理目錄。", - "loading": "正在載入專家清單…", - "loadingContent": "正在載入內容…", - "emptyExperts": "目前沒有可用的專家,請查看應用程式日誌。", - "emptySelection": "從左側選擇一個專家以檢視內容並管理啟用狀態。", - "emptySearch": "沒有符合目前搜尋條件的專家。", - "searchPlaceholder": "依名稱、ID 或描述搜尋專家", - "enableForAgents": "為代理啟用", - "noAgents": "未偵測到 ACP 代理。", - "copyModeWarning": "已複製(非軟連結)。codeg 更新後需要重新啟用以取得最新版本。", - "previewTitle": "SKILL.md 預覽", - "categories": { - "discovery": "探索與設計", - "planning": "規劃", - "execution": "執行", - "quality": "品質與測試", - "debugging": "除錯", - "review": "審查與整合", - "meta": "後設技能" - }, - "states": { - "not_linked": "未啟用", - "linked_to_codeg": "已啟用", - "linked_elsewhere": "衝突 — 已有其他連結", - "blocked_by_real_directory": "衝突 — 已有同名的自訂 skill 佔用", - "broken": "連結損壞" - }, - "badges": { - "userModified": "使用者修改過" - }, - "actions": { - "openCentralDir": "開啟中央目錄", - "refresh": "重新整理" - }, - "toasts": { - "loadFailed": "載入專家詳情失敗", - "enabled": "已為該代理啟用專家", - "disabled": "已為該代理停用專家", - "enableFailed": "啟用專家失敗", - "disableFailed": "停用專家失敗", - "openFolderFailed": "開啟目錄失敗" - } - }, - "ScienceSettings": { - "title": "科學研究技能", - "description": "為你的 AI 編碼智能體啟用精選的科學研究技能:假設生成、實驗設計、統計、視覺化、批判性評估與文獻檢索。codeg 管理中央副本,並將每個技能連結到你選擇的智能體。", - "loading": "正在載入科學研究技能…", - "emptySkills": "沒有可用的科學研究技能。請檢查應用程式日誌。", - "searchPlaceholder": "依名稱、ID 或描述搜尋科學研究技能", - "categories": { - "ideation": "構思", - "design": "研究設計", - "analysis": "分析", - "visualization": "視覺化", - "evaluation": "評估", - "literature": "文獻" - }, - "states": { - "not_linked": "未啟用", - "linked_to_codeg": "已啟用", - "linked_elsewhere": "衝突 — 已有其他連結", - "blocked_by_real_directory": "衝突 — 已有同名的自訂 skill 佔用", - "broken": "連結損壞" - }, - "badges": { - "userModified": "使用者修改過", - "needsKey": "需要金鑰", - "needsSetup": "可能需環境" - }, - "actions": { - "openCentralDir": "開啟中央目錄", - "refresh": "重新整理" - }, - "toasts": { - "openFolderFailed": "開啟目錄失敗" - } - }, - "OfficeToolsSettings": { - "title": "Office 工具", - "description": "管理 OfficeCLI 技能,用於建立 Excel、Word 和 PowerPoint 檔案。安裝 OfficeCLI,同步技能,並為每個智慧體啟用。", - "loadingContent": "載入內容中…", - "emptySkills": "暫無技能。請先安裝 OfficeCLI 並同步技能。", - "emptySelection": "選擇一個技能查看內容和管理啟用狀態。", - "emptySearch": "沒有匹配的技能。", - "searchPlaceholder": "按名稱、ID 或描述搜尋技能", - "enableForAgents": "為智慧體啟用", - "noAgents": "未偵測到 ACP 智慧體。", - "installFirst": "請先安裝 OfficeCLI 以啟用技能。", - "syncFirst": "請先同步技能以載入內容。", - "noContent": "暫無內容。", - "copyModeWarning": "已複製(非連結)。重新同步以取得最新版本。", - "previewTitle": "SKILL.md 預覽", - "detection": { - "installed": "已安裝", - "notInstalled": "未安裝", - "notRunnable": "已安裝但無法執行", - "installHint": "安裝 OfficeCLI 以為 AI 智慧體啟用辦公文件生成技能。", - "install": "安裝", - "uninstall": "解除安裝", - "syncSkills": "同步技能" - }, - "categories": { - "general": "通用", - "presentations": "簡報", - "documents": "文件", - "spreadsheets": "試算表" - }, - "states": { - "not_linked": "未啟用", - "linked_to_codeg": "已啟用", - "linked_elsewhere": "已阻止——存在其他連結", - "blocked_by_real_directory": "已阻止——自訂技能佔用此名稱", - "broken": "連結已損壞" - }, - "badges": { - "notSynced": "未同步" - }, - "actions": { - "refresh": "重新整理" - }, - "toasts": { - "loadFailed": "載入技能詳情失敗", - "enabled": "已為此智慧體啟用技能", - "disabled": "已為此智慧體停用技能", - "enableFailed": "啟用技能失敗", - "disableFailed": "停用技能失敗", - "installSuccess": "OfficeCLI 安裝成功", - "installFailed": "安裝 OfficeCLI 失敗", - "uninstallSuccess": "OfficeCLI 已解除安裝", - "uninstallFailed": "解除安裝 OfficeCLI 失敗", - "syncSuccess": "已成功同步 {synced} 個技能", - "syncPartial": "已同步 {synced} 個技能,{errors} 個失敗", - "syncFailed": "同步技能失敗" - }, - "autoPreviewLabel": "自動開啟預覽", - "autoPreviewHint": "當智慧代理建立或編輯 Word、Excel、PowerPoint 檔案時,自動開啟其即時預覽。" - }, - "SkillPacksSettings": { - "title": "技能包", - "description": "由 codeg 集中管理、並連結到各 AI 智慧代理的成套技能——程式設計專家、科學研究與辦公文件工具。可在下方依代理分別啟用。", - "tabs": { - "experts": "專家", - "science": "科學研究", - "office": "辦公工具", - "custom": "自訂" - }, - "actions": { - "openCentralDir": "開啟中央目錄", - "refresh": "重新整理" - }, - "toasts": { - "openFolderFailed": "開啟目錄失敗" - } - }, - "QuickMessagesSettings": { - "title": "快捷訊息", - "description": "管理可重用的訊息片段。拖曳以調整順序。", - "loading": "載入快捷訊息…", - "emptyList": "尚無快捷訊息。點擊「新增」建立一條。", - "emptySelection": "選擇一條快捷訊息進行編輯。", - "searchPlaceholder": "依標題或內容搜尋", - "untitled": "未命名", - "actions": { - "new": "新增", - "save": "儲存", - "delete": "刪除", - "dragSort": "拖曳排序", - "dragSortMessage": "拖曳排序快捷訊息:{name}" - }, - "fields": { - "title": "標題", - "titlePlaceholder": "為此訊息取一個簡短的標題", - "content": "內容", - "contentPlaceholder": "在此輸入訊息內容" - }, - "confirmDelete": { - "title": "刪除快捷訊息?", - "message": "將永久刪除「{name}」。確定嗎?", - "cancel": "取消", - "confirm": "刪除" - }, - "toasts": { - "loadFailed": "載入快捷訊息失敗", - "createFailed": "建立快捷訊息失敗", - "saveFailed": "儲存快捷訊息失敗", - "deleteFailed": "刪除快捷訊息失敗", - "saveOrderFailed": "儲存順序失敗", - "created": "已建立快捷訊息", - "saved": "已儲存快捷訊息", - "deleted": "已刪除快捷訊息" - } - }, - "Pet": { - "badge": { - "running": "{count} 個執行中", - "waiting": "{count} 個待核准", - "error": "{count} 個發生錯誤" - }, - "panel": { - "title": "活動工作階段", - "empty": "沒有活動工作階段", - "emptyHint": "正在執行或需要你處理的工作階段會顯示在這裡。", - "statusRunning": "執行中", - "statusWaiting": "等待中", - "statusError": "發生錯誤", - "subAgentOf": "子智慧代理" - }, - "menu": { - "scale": "縮放", - "openManager": "管理寵物", - "close": "關閉" - }, - "loadError": "載入寵物失敗", - "missingPetIdParam": "未選中任何寵物", - "summonButton": "寵物", - "manager": { - "title": "桌面寵物", - "description": "懸浮在桌面上的夥伴,使用與 Codex 相容的精靈圖。", - "addPet": "新增寵物", - "importFromCodex": "從 Codex 匯入", - "noPets": "暫無寵物。可以新增一隻,或從 Codex 匯入。", - "setActive": "設為使用中", - "active": "使用中", - "edit": "編輯", - "delete": "刪除", - "deleteConfirm": "確認刪除寵物「{name}」嗎?會從磁碟上一併移除。", - "summon": "召喚寵物視窗", - "openCodexHelp": "Codex 寵物需位於 ~/.codex/pets/ 目錄下,但未找到。", - "specRequirement": "精靈圖寬度必須為 1536 像素,高度需為 208 像素的整數倍(如 1872 或 2288),並為帶透明通道的 PNG 或 WebP。", - "form": { - "id": "寵物 ID", - "idHelp": "僅允許小寫字母、數字、'-' 和 '_',最多 64 字元。", - "displayName": "顯示名稱", - "description": "描述 (選填)", - "spritesheet": "精靈圖", - "chooseFile": "選擇檔案", - "replaceFile": "替換精靈圖", - "saveCreate": "新增寵物", - "saveUpdate": "儲存變更", - "cancel": "取消" - }, - "errors": { - "missingId": "寵物 ID 不能為空", - "missingName": "顯示名稱不能為空", - "missingSpritesheet": "必須選擇一個精靈圖", - "addFailed": "新增寵物失敗", - "updateFailed": "更新寵物失敗", - "deleteFailed": "刪除寵物失敗", - "loadFailed": "載入寵物列表失敗", - "setActiveFailed": "設定活躍寵物失敗", - "summonFailed": "召喚寵物視窗失敗" - } - }, - "import": { - "title": "從 Codex 匯入", - "subtitle": "在 ~/.codex/pets/ 下找到以下可匯入的寵物。", - "selectAll": "全選", - "alreadyImported": "已匯入", - "renameOnConflict": "衝突時自動加上 -imported 後綴", - "import": "匯入所選", - "noneFound": "未找到可匯入的 Codex 寵物。", - "imported": "匯入完成", - "failed": "匯入失敗", - "close": "關閉" - }, - "marketplace": { - "openMarketplace": "寵物市集", - "title": "寵物市集", - "search": "搜尋寵物", - "kindFilter": { - "all": "全部", - "object": "物品", - "animal": "動物", - "person": "人物", - "creature": "生物" - }, - "sortFilter": { - "latest": "最新", - "popular": "熱門", - "views": "最多瀏覽" - }, - "refresh": "重新整理", - "install": "安裝", - "installing": "安裝中", - "reinstall": "重新安裝", - "reinstallConfirm": "確認覆蓋本機寵物 \"{name}\" 嗎?現有資料將被取代。", - "cancel": "取消", - "stats": { - "views": "瀏覽", - "downloads": "下載", - "likes": "讚" - }, - "actions": { - "idle": "待機", - "running_right": "右跑", - "running_left": "左跑", - "waving": "揮手", - "jumping": "跳躍", - "failed": "失敗", - "waiting": "等待", - "running": "執行", - "review": "審閱" - }, - "page": "第 {page} / {total} 頁", - "prev": "上一頁", - "next": "下一頁", - "empty": "沒有符合的寵物。", - "successInstalled": "已安裝 \"{name}\"", - "errors": { - "loadFailed": "載入市集失敗", - "installFailed": "安裝失敗", - "alreadyInstalled": "該寵物已存在" - } - } - }, - "RemoteWorkspace": { - "openRemoteWorkspace": "Open remote workspace", - "manage": "Manage remote workspace", - "manageTitle": "Remote Workspace connections", - "empty": "No remote connections", - "searchPlaceholder": "Search remote workspaces", - "orderFailed": "Failed to save remote workspace order", - "dragSort": "Drag to sort", - "dragSortConnection": "Drag to sort {name}", - "newConnection": "New connection", - "loading": "Loading", - "loadingConnection": "Loading remote connection", - "name": "Name", - "baseUrl": "Service URL", - "token": "Access token", - "save": "Save", - "delete": "Delete", - "confirmDelete": { - "title": "Delete remote connection?", - "message": "This will remove \"{name}\" from this device. This action cannot be undone.", - "cancel": "Cancel", - "confirm": "Delete" - }, - "saved": "Remote connection saved.", - "deleted": "Remote connection deleted.", - "loadFailed": "Failed to load remote connections", - "saveFailed": "Failed to save remote connection", - "deleteFailed": "Failed to delete remote connection", - "openFailed": "Failed to open remote workspace", - "connectionLoadFailed": "Failed to load remote connection: {message}", - "connectionExpired": "Remote connection \"{name}\" is expired. Update its token and reload this window." - }, - "ServerFileBrowser": { - "title": "選擇伺服器檔案", - "pathPlaceholder": "輸入目錄路徑...", - "goHome": "回到主目錄", - "navigateUp": "返回上層目錄", - "select": "選擇", - "cancel": "取消", - "loading": "載入中...", - "emptyDirectory": "此目錄為空", - "errorLoadingDir": "載入目錄失敗", - "selectedCount": "已選 {count} 項" - }, - "BackupSettings": { - "title": "備份與還原", - "description": "匯出一份可攜的 codeg 資料備份,或從備份還原。", - "tabs": { - "backup": "備份", - "restore": "還原" - }, - "export": { - "includeExternal": "包含對話內容", - "includeExternalHint": "一併打包各 CLI 的對話記錄(Claude、Codex、Gemini 等),體積更大。", - "passphrase": "通行碼(選填)", - "passphrasePlaceholder": "留空則產生未加密的封存檔", - "passphraseConfirm": "確認通行碼", - "passphraseMismatch": "兩次輸入的通行碼不一致。", - "noPassphraseWarning": "此備份將以明文包含密鑰(API key、token)。請妥善保管。", - "passphraseLossWarning": "將以此通行碼加密。通行碼一旦遺失,備份將無法還原。", - "button": "匯出備份", - "inProgress": "正在建立備份…", - "success": "備份已建立。", - "started": "已開始下載備份。" - }, - "restore": { - "selectFile": "選擇備份檔案", - "passphrasePrompt": "此備份已加密,請輸入其通行碼。", - "unlock": "解鎖", - "preview": { - "title": "備份詳情", - "encrypted": "已加密", - "compatible": "相容", - "incompatible": "不相容", - "createdAt": "建立時間:{value}", - "appVersion": "應用程式版本:{value}", - "incompatibleHint": "此備份由較新版本的 codeg 建立,無法還原。" - }, - "replaceWarning": "還原將取代目前全部 codeg 資料(資料庫與上傳檔案)。目前資料會先做快照以便復原。", - "keyringNote": "桌面端的 GitHub/聊天 token 存於系統鑰匙圈,不包含在備份中;還原後需重新填寫。", - "button": "還原", - "staging": "正在準備還原…", - "staged": "還原已就緒,正在重新啟動…", - "restarting": "還原已就緒,正在重新啟動服務…", - "restartTimeout": "服務未能及時恢復。待其啟動後請重新整理頁面。", - "externalSideLocation": "對話記錄已還原至 {path}", - "confirmTitle": "取代全部資料?", - "confirmBody": "這將以備份取代目前的 codeg 資料庫與上傳檔案,然後重新啟動。目前資料會先做快照。", - "cancel": "取消", - "confirmAction": "取代並重新啟動", - "external": { - "title": "對話內容", - "hint": "此備份包含各 CLI 的對話記錄。請選擇還原到何處。", - "modeSkip": "不還原", - "modeSide": "還原到安全的旁路資料夾", - "modeOriginal": "還原到 CLI 的原始位置", - "forceOverwrite": "覆寫已存在的檔案", - "forceOverwriteHint": "取代 CLI 資料夾中已存在的檔案。", - "scanning": "正在檢查衝突…", - "noConflicts": "不會覆寫任何已存在的檔案。", - "conflictCount": "將影響 {count} 個已存在的檔案。", - "conflictSkipNote": "未啟用覆寫時,已存在的檔案將被保留(略過)。" - }, - "restartFailed": "還原已就緒,但伺服器未能重新啟動。請手動重新啟動以套用此次還原。" - }, - "remoteUnsupported": "備份與還原作用於執行 codeg 的那台機器上的資料。你目前連線的是遠端工作區——請直接在該伺服器上管理其備份。" - }, - "backup": { - "restore": { - "error": { - "badPassphrase": "通行碼錯誤或備份已損毀。", - "corrupted": "備份封存檔已損毀。", - "unknownFormat": "此檔案不是可識別的 codeg 備份。", - "newerVersion": "此備份由 codeg {backupVersion} 建立,比目前版本({appVersion})更新。", - "alreadyPending": "已有一個還原在等待生效。請先重新啟動套用它,再暫存新的還原。" - } - }, - "error": { - "diskSpace": "磁碟空間不足,無法完成操作。", - "cancelled": "操作已取消。" - } - }, - "WebConnection": { - "disconnectedTitle": "連線已中斷", - "reconnectingDescription": "正在嘗試重新連線伺服器,通常會在幾秒內自動恢復。", - "reconnectNow": "立即重新連線", - "sessionExpiredTitle": "工作階段已過期", - "sessionExpiredDescription": "登入狀態已失效,請重新登入以繼續。", - "goToLogin": "前往登入" - }, - "LiveFeedback": { - "placeholder": "在 {agent} 工作時給它留言…", - "agentFallback": "智能體", - "ariaLabel": "即時回饋留言", - "dialogTitle": "即時回饋", - "dialogDescription": "在智能體工作時給它留言。它會在下次檢查時讀取,不會打斷當前步驟。", - "dialogDescriptionInstant": "在智慧代理工作時傳送備註。備註會立即插入目前回合——代理馬上就能看到。", - "channelDowngraded": "本工作階段無法即時插入——備註已儲存,待代理下次檢查時讀取。", - "send": "送出", - "cancel": "取消", - "pending": "等待中", - "delivered": "已收到", - "turnEndedUnread": "智能體在讀取你的回饋前已結束本輪。", - "sendAsMessage": "作為新訊息送出", - "dismiss": "忽略", - "turnEndedResent": "本輪已結束——已改為作為新訊息送出。", - "turnEnded": "本輪已結束。", - "submitFailed": "留言送出失敗" - }, - "AgentToolsSettings": { - "title": "對話內工具", - "description": "codeg 在對話中額外提供給智慧代理的工具。工具會在代理啟動時注入,變更只對之後啟動的代理生效。", - "feedbackLabel": "即時回饋", - "feedbackHint": "在智慧代理工作時向它傳送備註與修正。支援即時插入的代理會立刻在目前回合中看到你的備註;其他代理則透過檢查回饋的工具讀取——這類代理通常只有在提示中提到時才會檢查,例如在訊息中加上「定期檢查我的即時回饋」。", - "questionLabel": "向使用者提問", - "questionHint": "允許智能體暫停並向你提出多選問題,問題會顯示在對話輸入框上方。智能體會一直等待,直到你作答(或略過)。", - "sessionInfoLabel": "取得工作階段資訊", - "sessionInfoHint": "允許智慧代理查詢你在訊息中提及的工作階段(工作階段徽章),讀取其標題、代理、狀態、工作區、Token 用量與最近訊息。", - "automationsLabel": "建立自動化", - "automationsHint": "把對話儲存為按排程執行的自動化。預設關閉——它之後會自行啟動代理。", - "workTasksLabel": "建立待辦任務", - "workTasksHint": "從對話中往待辦看板排一張任務卡。預設關閉——它會寫入應用程式狀態。", - "save": "儲存", - "saving": "儲存中…", - "saved": "工具設定已儲存", - "saveFailed": "儲存工具設定失敗", - "loadFailed": "載入失敗:{detail}" - }, - "NotificationSoundSettings": { - "title": "提示音", - "description": "智慧體事件觸發時播放一段簡短的提示音。這裡的事件與訊息通道推送的完全一致,但設定只對本裝置生效。", - "enableHint": "預設關閉。提示音只在目前瀏覽器或應用程式的工作區視窗中播放。", - "volume": "音量", - "preview": "試聽", - "previewEvent": "試聽「{event}」提示音", - "onlyWhenUnfocused": "僅在視窗未聚焦時播放", - "onlyWhenUnfocusedHint": "正在檢視 Codeg 時保持靜音。", - "eventsTitle": "事件", - "eventsHint": "為每個事件選擇一種音效,選擇「靜音」則不播放。同一事件在數秒內重複觸發時只播放一次。", - "toneNone": "靜音", - "toneChime": "叮咚", - "toneDing": "清鈴", - "toneBlip": "短音", - "tonePop": "輕點", - "toneAlert": "警示", - "toneDescend": "下行音" - }, - "LogsSettings": { - "loading": "載入中…", - "sectionTitle": "執行日誌", - "sectionDescription": "檢視與設定應用程式診斷日誌。日誌會寫入本機檔案,並保留在記憶體中以便即時檢視。", - "captureTitle": "日誌等級", - "captureDescription": "控制記錄的詳細程度。等級越高(Debug、Trace)記錄越多,但日誌也越大。「關閉」會停止記錄日誌。", - "captureLabel": "擷取等級", - "levels": { - "off": "關閉", - "error": "錯誤", - "warn": "警告", - "info": "資訊", - "debug": "除錯", - "trace": "追蹤" - }, - "viewerTitle": "最近日誌", - "viewerDescription": "即時檢視最近的日誌記錄。可依等級篩選或搜尋文字。", - "searchPlaceholder": "搜尋訊息或來源…", - "viewLevels": { - "all": "所有等級", - "error": "錯誤以上", - "warn": "警告以上", - "info": "資訊以上", - "debug": "除錯以上", - "trace": "追蹤以上" - }, - "pause": "暫停", - "resume": "即時", - "refresh": "重新整理", - "clear": "清除", - "openFolder": "開啟資料夾", - "shownCount": "已顯示 {shown} / {total}", - "empty": "尚無日誌。", - "levelSaveFailed": "儲存日誌等級失敗", - "openFolderFailed": "開啟日誌資料夾失敗", - "downloadFailed": "下載日誌檔案失敗", - "filesTitle": "日誌檔案", - "filesDescription": "從磁碟下載完整日誌檔案,檢視即時緩衝區以外的歷史記錄。", - "filesEmpty": "尚無日誌檔案。", - "download": "下載", - "downloadTruncated": "檔案較大,已下載最新的 {size}。完整檔案請在日誌目錄中查看。", - "captureEnvLocked": "日誌等級由 RUST_LOG / CODEG_LOG 環境變數控制;請在該處修改以生效。", - "targetsTitle": "依模組覆寫", - "targetsDescription": "為特定模組(如 codeg_lib::acp)單獨設定級別,不影響全域級別。", - "targetsAdd": "新增", - "targetsRemove": "移除覆寫", - "toggleDetails": "切換詳情" - }, - "Automations": { - "title": "自動化", - "new": "新增自動化", - "empty": "尚無自動化", - "emptyHint": "建立一個,讓代理程式按排程或手動執行任務。", - "name": "名稱", - "namePlaceholder": "例如:每晚 PR 審查", - "prompt": "提示詞", - "promptPlaceholder": "讓代理程式做什麼?", - "agent": "代理程式", - "folder": "工作區資料夾", - "folderPlaceholder": "選擇資料夾", - "isolation": "隔離方式", - "isolationWorktree": "每次執行新增 worktree", - "isolationShared": "在資料夾內執行", - "isolationSharedCaveat": "執行會直接使用該資料夾的工作樹,可能與你未提交的變更衝突。勾選每次執行新建工作樹以隔離每次執行。", - "trigger": "觸發方式", - "triggerSchedule": "按排程", - "triggerManual": "僅手動", - "cron": "排程(cron)", - "cronPlaceholder": "0 9 * * 1-5", - "timezone": "時區", - "nextRun": "下次執行", - "branch": "分支", - "branchOptional": "分支(選填)", - "enabled": "已啟用", - "save": "儲存", - "cancel": "取消", - "edit": "編輯", - "delete": "刪除", - "runNow": "立即執行", - "cancelRun": "取消執行", - "runHistory": "執行紀錄", - "noRuns": "尚無執行紀錄", - "allFolders": "所有資料夾", - "filterAll": "全部", - "noMatches": "沒有符合的自動化", - "viewConversation": "檢視對話", - "lastRun": "上次執行", - "never": "從未", - "running": "執行中", - "deleteTitle": "刪除此自動化?", - "deleteDescription": "這會刪除該自動化及其排程。執行紀錄會保留。", - "statusRunning": "執行中", - "statusSucceeded": "成功", - "statusFailed": "失敗", - "statusCancelled": "已取消", - "statusSkipped": "已略過", - "errorName": "名稱必填", - "errorPrompt": "提示詞必填", - "errorCron": "按排程的自動化需要 cron 運算式", - "errorFolder": "請選擇工作區資料夾", - "presetHourly": "每小時", - "presetDaily": "每天 9 點", - "presetWeekdays": "工作日 9 點", - "presetCustom": "自訂", - "probing": "正在載入選項…", - "retry": "重試", - "configNone": "此代理程式沒有可設定的選項", - "inherit": "代理程式預設", - "mode": "模式", - "config": "設定", - "branchPlaceholder": "(預設分支)", - "selectHint": "選擇一個自動化以查看詳情", - "refresh": "重新整理", - "onboardTitle": "自動化日常代理任務", - "onboardHint": "安排代理定時或隨需審查程式碼、更新相依套件或處理問題。", - "headerSubtitle": "定時與隨需的代理任務", - "startFromTemplate": "從範本開始", - "blankTitle": "空白自動化", - "blankDesc": "從零設定一個代理任務。", - "backToTemplates": "範本", - "sectionSchedule": "排程與目標", - "sectionTarget": "執行目標", - "sectionAction": "動作", - "actionLaunchSession": "啟動會話", - "actionEnqueueTask": "任務入列", - "actionEnqueueTaskHint": "每次觸發都會在目標資料夾的待辦任務裡加入一個待辦任務(標題為本自動化名稱),由任務引擎依看板設定執行。", - "sectionPrompt": "提示詞", - "nextIn": "{rel}後執行", - "manual": "手動", - "schedEveryMinutes": "每 {n} 分鐘", - "schedHourly": "每小時", - "schedDaily": "每天 {time}", - "schedWeekdays": "工作日 {time}", - "schedWeekly": "每{day} {time}", - "schedMonthly": "每月 {day} 日 {time}", - "dow0": "週日", - "dow1": "週一", - "dow2": "週二", - "dow3": "週三", - "dow4": "週四", - "dow5": "週五", - "dow6": "週六", - "tplCodeReviewTitle": "程式碼審查", - "tplCodeReviewDesc": "審查最近的變更,找出缺陷、回歸與品質問題。", - "tplDependencyUpdatesTitle": "相依套件更新", - "tplDependencyUpdatesDesc": "找出過時的相依套件並提出安全的升級方案。", - "tplTestCoverageTitle": "測試涵蓋率", - "tplTestCoverageDesc": "找出未涵蓋的程式碼路徑並補上缺少的測試。", - "tplTodoSweepTitle": "TODO 清理", - "tplTodoSweepDesc": "收集 TODO 與 FIXME 註解並依優先順序整理。", - "tplCiTriageTitle": "CI 排查", - "tplCiTriageDesc": "調查最近失敗的檢查並提出修復方案。", - "tplReleaseNotesTitle": "發行說明", - "tplReleaseNotesDesc": "彙整自上次發行以來的變更,產生更新日誌。", - "tplSecurityAuditTitle": "安全稽核", - "tplSecurityAuditDesc": "掃描漏洞與風險模式,並回報發現的問題。", - "enable": "啟用", - "disable": "停用", - "moreActions": "更多操作", - "statusDisabled": "已停用", - "cronBuilderTitle": "排程產生器", - "cronFreqLabel": "頻率", - "cronFreqMinutes": "每 N 分鐘", - "cronFreqHourly": "每小時", - "cronFreqDaily": "每天", - "cronFreqWeekdays": "工作日", - "cronFreqWeekly": "每週", - "cronFreqMonthly": "每月", - "cronFreqCustom": "自訂", - "cronEveryLabel": "間隔(分鐘)", - "cronTimeLabel": "時間", - "cronHourLabel": "小時", - "cronMinuteLabel": "分鐘", - "cronDowLabel": "星期", - "cronDomLabel": "日期", - "cronApply": "套用", - "cronPreviewLabel": "預覽", - "cronOpenBuilder": "開啟排程產生器", - "branchDefault": "預設分支", - "branchUseCustom": "使用「{query}」", - "branchLocal": "本機", - "branchRemote": "遠端", - "branchSearchPlaceholder": "搜尋分支…", - "branchNone": "無分支" - }, - "Tasks": { - "title": "待辦任務", - "new": "新增任務", - "empty": "還沒有任務", - "emptyHint": "新增待辦後即可處理——agent 在獨立 worktree 中工作,你驗收並合併結果。", - "emptyColTodo": "還沒有待辦任務", - "emptyColInProgress": "暫無進行中的任務", - "emptyColAttention": "暫無等你處理的任務", - "emptyColDone": "還沒有已完成的任務", - "allFolders": "全部資料夾", - "showCanceled": "顯示已取消", - "showArchived": "顯示已封存", - "filter": "篩選", - "viewSwitchToBoard": "切換到看板檢視", - "viewSwitchToList": "切換到清單檢視", - "statusFilter": "狀態", - "statusFilterAll": "全部狀態", - "listEmpty": "沒有符合目前篩選條件的任務", - "listColStatus": "狀態", - "listColTask": "任務", - "listColLocation": "位置", - "listColChanges": "變更", - "listColUpdated": "更新", - "colTodo": "待辦", - "colInProgress": "進行中", - "colAttention": "等你處理", - "colDone": "已完成", - "statusTodo": "待辦", - "statusQueued": "排隊中", - "statusPreparing": "初始化中", - "statusRunning": "進行中", - "statusAwaitingInput": "等待輸入", - "statusReview": "待驗收", - "statusMerging": "合併中", - "statusDone": "已完成", - "statusFailed": "失敗", - "statusCanceled": "已取消", - "statusInterrupted": "已中斷", - "badgeCleanupFailed": "清理失敗", - "badgeWorktreeKept": "保留 worktree", - "badgeWorktreeRemoved": "Worktree 已刪除", - "filesChanged": "{count} 個檔案", - "actionStart": "開始", - "actionSchedule": "定時執行", - "actionCancel": "取消", - "actionRetry": "重試", - "actionRequeue": "重新排隊", - "actionViewSession": "檢視會話", - "actionEdit": "編輯", - "actionDelete": "刪除", - "actionRetryCleanup": "重試清理", - "actionMerge": "合併", - "actionUnqueueMerge": "取消排隊", - "actionEditQueuedMerge": "修改排隊的合併", - "badgeMergeQueued": "排隊合併中", - "badgeMergeQueuedRank": "排隊合併 · 第 {rank} 位", - "badgeMergeQueuedHint": "正在等待該專案目前的合併完成,輪到時會自動開始。", - "actionComplete": "完成", - "actionAbandon": "放棄", - "cancelTitle": "取消任務?", - "cancelDescription": "任務將變為已取消。worktree 會保留,之後可以重新排隊。", - "cancelReasonLabel": "取消原因(選填)", - "cancelReasonPlaceholder": "例如:方向不對,我重寫一下任務描述", - "cancelKeep": "先不取消", - "cancelSubmit": "取消任務", - "restartTitleRetry": "重試任務", - "restartTitleRequeue": "重新排隊", - "restartDescription": "可以補充一段說明(選填),它會隨下一輪的提示詞一起傳給 agent。", - "scheduleTitle": "定時執行任務", - "scheduleDescription": "任務留在「待辦」,到時間自動開始。資料夾的並行上限仍然有效。", - "scheduleDateLabel": "日期", - "schedulePickDate": "選擇日期", - "scheduleTimeLabel": "時間", - "schedulePreview": "{time} 執行", - "schedulePastHint": "該時間已過——儲存後會立即開始。", - "scheduleInAnHour": "1 小時後", - "scheduleInThreeHours": "3 小時後", - "scheduleTomorrow": "明天 9:00", - "scheduleClear": "清除定時", - "scheduleBadge": "預計於 {time} 開始", - "toastScheduled": "已定時:{time}", - "toastScheduleCleared": "已清除定時", - "actionFollowUp": "繼續處理", - "actionAddNote": "補充說明", - "followUpSubmit": "傳送", - "followUpIntentRevise": "修改返工", - "followUpIntentContinue": "繼續推進", - "followUpIntentQuestion": "提問答疑", - "followUpIntentVerify": "自查驗證", - "followUpPlaceholderRevise": "希望 agent 改哪裡?會在同一個工作階段繼續。", - "followUpPlaceholderContinue": "接下來還要做什麼?已有的工作會保留。", - "followUpPlaceholderQuestion": "想了解什麼?agent 只回答,不會改動任何檔案。", - "followUpPlaceholderVerify": "選填:有什麼想讓它重點檢查的?", - "followUpPlaceholderRetry": "選填:這次要怎麼做才不一樣?例如:先跑 pnpm install", - "followUpPlaceholderRequeue": "選填:當時為什麼取消?這次要注意什麼?", - "actionArchive": "封存", - "actionUnarchive": "取消封存", - "archiveAllDone": "全部封存", - "dropToStart": "放開即開始執行", - "errorView": "檢視", - "notifyReview": "待驗收:{title}", - "notifyFailed": "任務失敗:{title}", - "createFromMessage": "由此訊息建立任務", - "detailTokens": "總 token 用量", - "editorTitleNew": "新增任務", - "editorTitleEdit": "編輯任務", - "templates": "範本", - "templatesEmpty": "還沒有範本。", - "templateSaveCurrent": "將目前內容存為範本", - "templateDelete": "刪除範本", - "transcriptTitle": "任務會話", - "transcriptDescription": "任務智慧代理會話的唯讀即時檢視。", - "phaseWork": "任務執行", - "phaseRetry": "重試執行", - "phaseReturn": "繼續處理", - "phaseMerge": "合併變更", - "titleLabel": "標題", - "titlePlaceholder": "要做什麼?", - "promptLabel": "任務描述", - "promptPlaceholder": "向 agent 描述任務——輸入 @ 可引用檔案,/ 可喚起指令", - "folderPlaceholder": "選擇資料夾", - "agentInheritedHint": "繼承自任務設定,修改後僅對本任務生效", - "agentOverrideReset": "恢復繼承", - "sectionTarget": "目標", - "errorTitle": "請輸入標題", - "errorPrompt": "請輸入任務描述", - "errorFolder": "請選擇資料夾", - "save": "儲存", - "cancel": "取消", - "mergeTitle": "合併任務", - "mergeQueuedTitle": "排隊中的合併", - "mergeQueueHint": "該專案正在合併另一個任務。此任務會加入佇列,等前一個完成後自動開始。", - "mergeQueueUpdateHint": "此任務已在合併佇列中。送出將更新它的合併選項,並保留原本的排隊位置。", - "mergeDescription": "將 {branch} 合併到 {base}。worktree 中未提交的變更會先自動提交。", - "mergeMessage": "提交訊息", - "mergeMessagePlaceholder": "例如 feat: add login validation", - "mergeAutoMessage": "讓 agent 自動產生提交訊息", - "strategySquash": "合併為一筆提交", - "strategySquashHint": "任務的所有修改壓縮成一筆提交記錄併入主分支,歷史更簡潔。", - "strategyMerge": "保留完整提交歷史", - "strategyMergeHint": "保留任務過程中的每一筆提交,另加一筆合併記錄,每一步都可追溯。", - "mergeDeleteWorktree": "合併後刪除 worktree", - "mergeSubmit": "合併", - "mergeSubmitQueue": "加入合併佇列", - "mergeQueuedToast": "已加入合併佇列,等目前的合併完成後自動開始。", - "completeTitle": "完成任務", - "completeDescription": "此任務沒有變更任何檔案,無須合併,將直接標記為已完成。", - "completeDescriptionNoWorktree": "此任務的 worktree 已被刪除,無法再合併,將直接標記為已完成。若工作分支上仍有未合併的提交,分支會被保留。", - "completeDeleteWorktree": "完成後刪除 worktree", - "completeSubmit": "完成", - "settingsTitle": "任務設定", - "settingsDescription": "{folder} 中任務的預設配置。", - "settingsScope": "套用範圍", - "settingsScopeGlobal": "全部資料夾(全域預設)", - "settingsScopeGlobalHint": "未單獨設定的資料夾將使用這份全域預設。", - "settingsSource": "設定來源", - "settingsSourceGlobal": "使用全域預設", - "settingsSourceCustom": "單獨設定", - "settingsSourceGlobalFollow": "跟隨全域任務設定,全域變更會自動生效。", - "settingsSourceCustomHint": "為此資料夾儲存獨立設定,不再跟隨全域預設。", - "settingsAgent": "預設 agent", - "settingsMaxConcurrent": "最大並行任務數", - "settingsMaxConcurrentHint": "0 表示不限制", - "settingsAutoProcess": "自動處理", - "settingsAutoProcessHint": "待辦任務自動開始處理,受並行上限約束。", - "settingsMergeStrategy": "預設合併策略", - "settingsMergeStrategyHint": "合併任務時,這些修改在分支歷史裡如何記錄。", - "settingsAutoMerge": "自動合併", - "settingsAutoMergeHint": "任務進入待驗收且有可合併改動時自動落地,與點擊「合併」相同:提交訊息由 agent 自動產生,是否刪除 worktree 沿用下方預設。預檢未通過或合併失敗的任務會留下等你處理。", - "settingsDeleteWorktree": "合併後刪除 worktree", - "settingsDeleteWorktreeHint": "合併對話框裡預設勾選,仍可臨時更改。", - "settingsWorktreeRoot": "Worktree 位置", - "settingsWorktreeRootHint": "新任務的 worktree 會建立在該目錄下,每個任務一個。留空則建立在專案資料夾的同層目錄;「~」表示家目錄,相對路徑相對於專案資料夾。", - "settingsWorktreeRootPlaceholder": "~/codeg-worktrees", - "settingsWorktreeRootBrowse": "選擇 worktree 目錄", - "settingsPreflight": "預檢命令", - "settingsPreflightHint": "任務進入待驗收時在 worktree 中執行。", - "settingsPreflightCustomPlaceholder": "pnpm test", - "settingsInitCommand": "Worktree 初始化命令", - "settingsInitCommandHint": "建立 worktree 後、工作階段開始前執行。", - "settingsInitCommandPlaceholder": "pnpm install", - "settingsTabGeneral": "一般", - "settingsTabMerge": "合併", - "settingsTabWorktree": "Worktree", - "settingsTabPrompts": "提示詞", - "settingsPromptsIntro": "每個階段都已內建固定的提示詞——任務本身、worktree 規則,合併階段還包含具體的 git 步驟。這裡填的內容會作為補充說明追加到最後:只是對內建提示詞的細化,不會取代它們。", - "settingsPromptStageAll": "全部階段", - "settingsPromptPlaceholderAll": "例如:遵循 AGENTS.md 裡的專案慣例;一律用繁體中文回覆", - "settingsPromptPlaceholderWork": "例如:先讀相關測試;小步提交,邊做邊交", - "settingsPromptPlaceholderRetry": "例如:先看清楚已經提交了哪些改動再繼續,別重做已完成的部分", - "settingsPromptPlaceholderReturn": "例如:逐條處理提到的每一點;不要順手重構無關程式碼", - "settingsPromptPlaceholderMerge": "例如:最終合併的提交訊息用繁體中文;手動解決過的衝突要另外說明", - "settingsPromptHintAll": "追加到每一次發給 agent 的提示詞,包括合併那一輪。", - "settingsPromptHintWork": "任務首次執行時追加。", - "settingsPromptHintRetry": "重試被中斷或失敗的任務時追加。", - "settingsPromptHintReturn": "對待驗收的任務繼續處理時追加(返工、追加工作、自查)。", - "settingsPromptHintMerge": "agent 把任務合併到基線分支時追加。", - "preflightPassed": "{name} 通過", - "preflightFailed": "{name} 未通過", - "preflightRunning": "{name} 執行中…", - "detailDescription": "任務詳情", - "detailSummary": "結果", - "detailFiles": "變更檔案", - "detailDiffAll": "檢視全部差異", - "detailDiffAllTitle": "全部差異", - "detailNoChanges": "相對基準還沒有變更", - "detailTimeline": "推進記錄", - "detailTimelineEmpty": "暫無活動", - "showMore": "展開", - "showLess": "收起", - "detailInfo": "詳情", - "detailBranch": "分支", - "detailMergeCommit": "合併提交", - "detailChanges": "變更", - "detailScheduled": "預計開始", - "detailCreated": "建立時間", - "detailStarted": "開始時間", - "detailFinished": "完成時間", - "diffLoading": "正在載入差異…", - "deleteConfirmTitle": "刪除任務?", - "deleteConfirmBody": "「{title}」將從看板移除。進行中的執行會先被取消。", - "deleteWithWorktree": "同時刪除其 worktree", - "eventCreated": "已建立", - "eventStatusChanged": "狀態變更", - "eventConfigEffective": "啟動配置", - "eventInitCommand": "初始化命令", - "eventAgentProgress": "Agent 進展", - "eventAgentVerdict": "Agent 結論", - "eventMergeAttempt": "開始合併", - "eventMergeQueued": "加入合併佇列", - "eventMergeConflict": "合併衝突", - "eventPreflight": "預檢", - "eventCleanupFailed": "worktree 清理失敗", - "eventResumeFallback": "會話恢復失敗,已改用新會話", - "eventUserAction": "使用者操作", - "eventDiffStat": "變更快照" - }, - "CustomSkillsSettings": { - "loading": "正在載入自訂技能…", - "category": "自訂", - "searchPlaceholder": "依名稱、ID 或描述搜尋自訂技能", - "states": { - "not_linked": "未啟用", - "linked_to_codeg": "已啟用", - "linked_elsewhere": "連結到其他位置", - "blocked_by_real_directory": "被同名實體目錄佔用", - "broken": "連結已失效" - }, - "actions": { - "new": "新增", - "import": "匯入", - "importFromAgent": "從 Agent 匯入", - "cancel": "取消", - "save": "儲存" - }, - "rowMenu": { - "edit": "編輯", - "duplicate": "複製為新技能", - "delete": "刪除" - }, - "bulk": { - "delete": "刪除所選" - }, - "editor": { - "createTitle": "新增自訂技能", - "editTitle": "編輯自訂技能", - "description": "自訂技能存放於共用庫(~/.codeg/skills),可為任意智能體啟用。", - "idLabel": "技能 ID", - "idPlaceholder": "例如 my-workflow", - "contentLabel": "SKILL.md", - "contentPlaceholder": "在此撰寫技能的 SKILL.md…", - "preview": "預覽", - "edit": "編輯", - "emptyBody": "尚無內容。" - }, - "duplicate": { - "title": "複製技能", - "description": "以「{id}」為範本,以新 ID 建立一份副本。", - "newIdPlaceholder": "新技能 ID", - "confirm": "複製" - }, - "import": { - "title": "選擇要匯入的技能資料夾" - }, - "importFromAgent": { - "title": "從 Agent 匯入技能", - "description": "將某個 Agent 自己的技能複製到共享庫,即可為任意 Agent 啟用。", - "agentLabel": "Agent", - "agentPlaceholder": "選擇一個 Agent", - "selectAll": "全選({count})", - "loading": "正在載入該 Agent 的技能…", - "unsupported": "此 Agent 未提供技能目錄。", - "empty": "此 Agent 沒有可匯入的技能。", - "alreadyInLibrary": "已在庫中", - "confirm": "匯入所選({count})" - }, - "delete": { - "title": "刪除自訂技能?", - "body": "將從中央庫移除 {count} 個自訂技能,並解除它們在所有智能體中的連結。此操作無法復原。", - "confirm": "刪除" - }, - "toasts": { - "loadFailed": "載入技能失敗", - "idRequired": "請輸入技能 ID", - "created": "已建立自訂技能", - "updated": "已更新自訂技能", - "saveFailed": "儲存技能失敗", - "imported": "已匯入技能", - "importFailed": "匯入技能失敗", - "duplicated": "已複製技能", - "duplicateFailed": "複製技能失敗", - "deleted": "已刪除 {count} 個技能", - "deletedPartial": "已刪除 {ok} 個,{failed} 個失敗", - "deleteFailed": "刪除技能失敗", - "importedFromAgent": "已匯入 {count} 個技能", - "importedFromAgentPartial": "已匯入 {ok} 個,{failed} 個失敗", - "importFromAgentAllSkipped": "無需匯入——{count} 個已在庫中", - "importFromAgentFailed": "從 Agent 匯入失敗" - } - }, - "CodexModelEditor": { - "customizedNotice": "你已自訂模型清單,codeg 將接管 codex 的完整模型表。codex 日後新增的官方模型不會自動出現——點擊下方重新整理並再次儲存即可同步。清空所有自訂即可交回 codex 自動更新。", - "officialsTitle": "官方模型", - "officialsHint": "自動納入你啟動的 codex 的官方模型;可刪除不需要的。", - "officialsEmpty": "暫無官方模型。", - "refresh": "從 codex 重新整理", - "readdOfficial": "重新加入官方", - "customsTitle": "自訂模型", - "customsEmpty": "暫無自訂模型。", - "addCustom": "新增自訂", - "slugPlaceholder": "模型 id(slug)", - "displayNamePlaceholder": "顯示名稱", - "contextWindow": "上下文", - "makeDefault": "設為預設", - "defaultHint": "預設模型", - "remove": "移除", - "advanced": "進階", - "baseTemplate": "基礎範本", - "baseTemplateHint": "從哪個官方模型複製必填欄位(系統提示詞、工具、限制)。", - "groupBehavior": "行為與能力", - "fieldReasoningLevel": "預設推理強度", - "fieldReasoningSummary": "推理摘要", - "fieldVerbosity": "詳細程度", - "fieldShellType": "Shell 類型", - "fieldApplyPatch": "套用修補工具", - "fieldReasoningSummaries": "推理摘要支援", - "fieldSupportVerbosity": "詳細程度控制", - "fieldParallelToolCalls": "並行工具呼叫", - "fieldSearchTool": "網路搜尋工具", - "optNone": "無", - "groupInstructions": "描述與系統提示詞", - "fieldDescription": "描述", - "baseInstructions": "系統提示詞(base_instructions)" - }, - "DiagnosticsSettings": { - "title": "環境診斷", - "description": "檢查本應用在自身行程中如何解析該智能體的 CLI——這可能與你的終端機不同。", - "loading": "正在執行診斷…", - "error": "診斷失敗", - "rerun": "重新執行", - "copyAll": "複製全部", - "copied": "診斷資訊已複製到剪貼簿", - "button": "診斷", - "verdict": { - "ok": "環境正常。若仍提示未安裝,請徹底重新啟動應用以重新整理前綴快取。", - "node_missing": "在應用的 PATH 上找不到 Node.js。", - "npm_missing": "在應用的 PATH 上找不到 npm。", - "not_installed": "此智能體似乎尚未安裝。", - "installed_but_unresolved": "紀錄顯示已安裝,但應用無法定位其執行檔。", - "user_prefix_not_on_path": "安裝到了回退前綴(~/.codeg/npm-global),但它不在應用的 PATH 上。請徹底重新啟動應用後再試。", - "homebrew_bin_not_on_path": "安裝在 Homebrew 的 bin 目錄下,但它不在應用的 PATH 上(Apple Silicon keg 拆分)。", - "terminal_only_path": "此命令在你的終端機能解析,但在應用中不能——這是 GUI PATH 差異。請從終端機啟動應用,或在智能體設定中重新安裝。", - "npm_prefix_timeout": "npm prefix -g 太慢(超過 1.5 秒),已略過回退偵測。請重新啟動應用後再試。", - "node_too_old": "目前 Node.js 版本低於此智能體的要求。請升級 Node.js。", - "adapter_missing_native_present": "你本機的 {agent} CLI 確實安裝了,但 Codeg 啟動的是另一個 ACP 轉接器套件,而它還沒安裝。到「智能體設定」中安裝即可 —— 它不會動到你的 CLI,登入狀態也是共用的。", - "adapter_missing": "Codeg 為 {agent} 啟動的是獨立的 ACP 轉接器套件,目前尚未安裝。請到「智能體設定」中安裝 —— 只安裝廠商 CLI 是不夠的。" - } - }, - "TokenUsage": { - "title": "Token 用量", - "rangeLabel": "時間範圍", - "range7d": "近 7 天", - "range30d": "近 30 天", - "range90d": "近 90 天", - "rangeThisMonth": "本月", - "rangeThisYear": "今年", - "rangeAll": "全部", - "rangeCustom": "自訂", - "moreRanges": "更多", - "customRangePick": "選擇日期範圍", - "bucketLabel": "統計粒度", - "bucketDay": "依天", - "bucketWeek": "依週", - "bucketMonth": "依月", - "bucketUnitDay": "天", - "bucketUnitWeek": "週", - "bucketUnitMonth": "月", - "folderFilter": "資料夾", - "allFolders": "全部資料夾", - "agentFilter": "智慧代理", - "allAgents": "全部智慧代理", - "modelFilter": "模型", - "allModels": "全部模型", - "searchPlaceholder": "搜尋…", - "noMatches": "沒有符合項目", - "clearFilter": "清除選擇", - "resetFilters": "重設篩選", - "refresh": "重新整理", - "rebuild": "全量重建", - "rebuildHint": "捨棄已統計的資料並重新解析全部工作階段紀錄。當紀錄被 codeg 以外的 CLI 追加過時使用。", - "syncing": "正在統計工作階段…", - "syncProgress": "{done} / {total}", - "syncDone": "已統計 {synced} 個工作階段", - "syncFailed": "部分工作階段讀取失敗", - "syncBusy": "已有一次重新整理進行中", - "lastSynced": "更新於 {time}", - "lastSyncedNever": "尚未統計", - "tileTotal": "總 Token", - "tileSessions": "工作階段數", - "tileTurns": "對話輪次", - "tileActiveDays": "活躍天數", - "tileGenTime": "生成時長", - "vsPrevious": "對比上一週期", - "deltaNew": "新增", - "trendTitle": "用量趨勢", - "trendEmpty": "此範圍內沒有用量", - "trendTurns": "輪次", - "trendSessions": "工作階段", - "compositionTitle": "Token 花在哪裡", - "compositionHint": "輸入是你送出的內容,輸出是模型寫回來的,快取讀取則是不必再按原價重送的上下文。", - "compositionNote": "這些快取命中若按原價重送,要多花 {value}。", - "inputTokens": "輸入", - "outputTokens": "輸出", - "cacheWrite": "快取寫入", - "cacheRead": "快取讀取", - "freshTokens": "新算 Token", - "cacheHitCaption": "快取命中", - "cacheHeroTitleHigh": "上下文大多不必重送", - "cacheHeroTitleLow": "多數上下文仍按原價計算", - "cacheHeroDesc": "{cached} 的上下文由快取承擔,這段時間真正新算的只有 {fresh}。", - "cacheSavedSuffix": "省下的重送量相當於 {saved}。", - "avgPerSession": "平均每工作階段", - "avgTurnsPerSession": "平均每個工作階段 {count} 輪", - "avgPerActiveDay": "平均每活躍日", - "peakBucket": "最高的一{bucket}", - "peakHour": "尖峰時段", - "daysValue": "{count} 天", - "idleDays": "空轉天數", - "byFolderTitle": "依資料夾", - "byAgentTitle": "依智慧代理", - "byModelTitle": "依模型", - "distributionTitle": "用量分布", - "distributionHint": "工作階段與 Token 依所選維度歸集,點任一列可依它篩選。", - "otherLabel": "其他", - "unknownModel": "未標註模型", - "emptyBreakdown": "尚無紀錄", - "sessionsCount": "{count} 個工作階段", - "heatmapTitle": "你的編碼作息", - "heatmapHint": "依本地星期與小時統計的 Token 分佈。", - "heatmapPeakHint": "最密集的時段在 {hour}:00 前後。", - "less": "少", - "more": "多", - "heatmapCell": "{weekday} {hour}:00 — {value} tokens", - "weekMon": "一", - "weekTue": "二", - "weekWed": "三", - "weekThu": "四", - "weekFri": "五", - "weekSat": "六", - "weekSun": "日", - "topSessionsTitle": "消耗最高的工作階段", - "untitledSession": "未命名工作階段", - "topSessionsEmpty": "此範圍內沒有工作階段", - "streakLongest": "最長連續", - "streakLongestDays": "最長連續 {count} 天", - "share": "分享", - "moreActions": "更多操作", - "shareDialogTitle": "分享你的用量卡片", - "shareDialogHint": "卡片內容就是你目前所選的時間範圍與篩選條件。", - "shareSave": "儲存圖片", - "shareCopy": "複製圖片", - "shareCopied": "已複製到剪貼簿", - "shareSaved": "圖片已儲存", - "shareFailed": "圖片產生失敗", - "shareRendering": "產生中…", - "cardHeading": "我的 AI 編碼戰績", - "cardRangeAll": "全部時間", - "cardTotalLabel": "累計 Token", - "cardFooter": "由 codeg 產生", - "cardTopModels": "常用模型", - "cardTopProjects": "主力專案", - "archetypeNightOwl": "深夜工程師", - "archetypeNightOwlDesc": "{percent}% 的 Token 燒在天黑之後。", - "archetypeEarlyBird": "清晨型選手", - "archetypeEarlyBirdDesc": "{percent}% 的 Token 在早上 9 點前就用掉了。", - "archetypeWeekendWarrior": "週末戰士", - "archetypeWeekendWarriorDesc": "{percent}% 的 Token 發生在週末。", - "archetypeCacheMaster": "快取大師", - "archetypeCacheMasterDesc": "{percent}% 的上下文來自快取。", - "archetypeMarathoner": "長跑選手", - "archetypeMarathonerDesc": "連續 {days} 天沒有中斷。", - "archetypePolyglot": "多面手", - "archetypePolyglotDesc": "{count} 個智慧代理都在主力使用。", - "archetypeLaserFocus": "專注一役", - "archetypeLaserFocusDesc": "{percent}% 的 Token 投在同一個專案上。", - "archetypeDeepDiver": "深潛者", - "archetypeDeepDiverDesc": "平均每個工作階段 {averageK}K tokens。", - "archetypeSteady": "穩定輸出", - "archetypeSteadyDesc": "累計 {days} 天在寫程式。", - "emptyTitle": "還沒有可統計的資料", - "emptyHint": "codeg 直接從各智慧代理自己的工作階段紀錄讀取 Token 數。點一下重新整理,把本機已有的紀錄統計進來。", - "emptyAction": "統計我的工作階段", - "loadFailed": "用量載入失敗", - "truncatedNotice": "此範圍過大 —— 下面的數字只涵蓋其中最近的一段。" - } -} +{ + "Language": { + "followSystem": "跟隨系統", + "english": "英文", + "simplifiedChinese": "簡體中文", + "traditionalChinese": "繁體中文", + "japanese": "日語", + "korean": "韓語", + "spanish": "西班牙語", + "german": "德語", + "french": "法語", + "portuguese": "葡萄牙語", + "arabic": "阿拉伯語" + }, + "GitCredentialDialog": { + "title": "需要身份驗證", + "description": "遠端伺服器要求輸入憑據。請輸入使用者名稱和密碼(或個人存取權杖)。", + "username": "使用者名稱", + "usernamePlaceholder": "使用者名稱或電子郵件", + "password": "密碼 / 權杖", + "passwordPlaceholder": "密碼或個人存取權杖", + "passwordHint": "請輸入伺服器的使用者名稱和密碼。", + "cancel": "取消", + "authenticate": "驗證", + "authenticating": "驗證中...", + "invalidCredentials": "憑據無效,請重試。", + "saveCredentials": "儲存憑據以供後續操作使用", + "githubTitle": "GitHub 身份驗證", + "githubDescription": "輸入個人存取權杖以連線 GitHub。權杖驗證成功後將自動儲存至帳號列表。", + "githubToken": "個人存取權杖", + "githubTokenPlaceholder": "ghp_xxxxxxxxxxxx", + "githubTokenHint": "在 GitHub → Settings → Developer settings → Personal access tokens 中產生權杖。", + "githubAuthenticate": "驗證並連線", + "generateToken": "產生權杖" + }, + "SettingsShell": { + "title": "設定", + "preferences": "偏好設定", + "nav": { + "general": "一般", + "appearance": "外觀", + "agents": "智能體", + "mcp": "MCP", + "skills": "Skills", + "shortcuts": "快捷鍵", + "version_control": "版本控制", + "system": "系統", + "chat_channels": "訊息頻道", + "web_service": "Web 服務", + "model_providers": "模型供應商", + "experts": "專家", + "science": "科學研究", + "office_tools": "辦公工具", + "skill_packs": "技能包", + "quick_messages": "快捷訊息", + "logs": "執行日誌" + } + }, + "AppearanceSettings": { + "sectionTitle": "主題外觀", + "sectionDescription": "選擇淺色、深色或跟隨系統主題,設定會自動儲存。", + "themeMode": "主題模式", + "placeholder": "請選擇主題模式", + "system": "跟隨系統", + "light": "淺色", + "dark": "深色", + "currentTheme": "目前生效主題:{theme}", + "resolvedTheme": { + "light": "淺色", + "dark": "深色", + "unknown": "未知" + }, + "themeColor": { + "sectionTitle": "主題顏色", + "sectionDescription": "選擇按鈕、強調色和高亮使用的色調。", + "current": "目前顏色:{color}", + "options": { + "neutral": "Neutral", + "zinc": "Zinc", + "slate": "Slate", + "stone": "Stone", + "gray": "Gray", + "red": "Red", + "rose": "Rose", + "orange": "Orange", + "green": "Green", + "blue": "Blue", + "yellow": "Yellow", + "violet": "Violet" + } + }, + "customStyle": { + "sectionTitle": "自訂樣式", + "sectionDescription": "在目前主題的基礎上微調配色,或寫入自己的 CSS。覆寫疊加在基底預設之上,切換預設後依然保留。", + "summarySuspended": "已停用", + "summaryDefault": "跟隨預設", + "summaryTokens": "{count, plural, other {# 項覆寫}}", + "summaryCss": "自訂 CSS", + "suspendedByShortcut": "自訂樣式已停用。在恢復之前,這裡的設定都不會生效。", + "suspendedBySafeParam": "本視窗以安全外觀模式開啟,自訂樣式在此不生效,其它視窗不受影響。", + "resume": "恢復自訂樣式", + "enableTheme": "啟用自訂配色", + "editingLight": "正在編輯淺色模式的取值。切換到深色模式可單獨設定深色。", + "editingDark": "正在編輯深色模式的取值。切換到淺色模式可單獨設定淺色。", + "resetToken": "還原為預設取值", + "radius": "圓角", + "radiusHint": "從 sm 到 4xl 的整套圓角尺寸都由它衍生,一個滑桿即可改變全域圓角。", + "advanced": "進階(另有 {count} 個變數)", + "enableCss": "啟用自訂 CSS", + "cssRisk": "進階功能。自訂 CSS 會壓過所有內建樣式,寫壞可能導致介面無法使用。", + "editCss": "編輯 CSS…", + "cssPresent": "已儲存 {size} KB", + "cssEmpty": "尚未儲存內容", + "escapeHint": "介面被改壞了?按 {shortcut} 可停用全部自訂樣式,也可以用 safeStyle=1 查詢參數開啟視窗。", + "copyTheme": "複製主題 JSON", + "importTheme": "匯入主題…", + "clearTheme": "清除覆寫", + "interopHint": "主題採用 shadcn 的 registry:theme 格式,可以直接貼上任意 shadcn 主題,匯出的主題也能用在任何 shadcn 專案裡。", + "importTitle": "匯入主題", + "importDescription": "貼上 shadcn 的 registry:theme 項目、裸的 light/dark 物件,或者單層的 token 對應表。", + "readClipboard": "讀取剪貼簿", + "importConfirm": "匯入", + "cancel": "取消", + "apply": "套用", + "toasts": { + "copied": "主題 JSON 已複製", + "copyFailed": "無法寫入剪貼簿", + "clipboardReadFailed": "無法讀取剪貼簿,請手動貼上", + "importFailed": "這段 JSON 裡沒有可用的主題變數", + "imported": "主題已匯入" + }, + "css": { + "dialogTitle": "自訂 CSS", + "dialogDescription": "對所有 codeg 視窗生效。修改會即時預覽,點擊「套用」才會儲存。", + "size": "{used} KB / {max} KB", + "ruleCount": "{count} 條規則", + "errorTooLarge": "內容過大,無法儲存,請精簡到上限以內。", + "errorImportEscaped": "剝離後仍偵測到 @import(跳脫寫法),請手動移除後再儲存。", + "warnNoRules": "沒有解析出任何規則,請檢查語法。", + "noticeImportsRemoved": "已移除 {count} 條 @import:它們會拉取遠端樣式表。", + "noticeRemoteUrl": "含遠端 url(),套用後會發起網路請求。", + "noticePreviewSuspended": "自訂樣式已停用,此處預覽不會生效。", + "noticeDisabled": "自訂 CSS 未啟用。這裡可以預覽,但啟用後才會真正生效。", + "hintTokens": "提示:你覆寫的顏色可以直接用 var(--primary)、var(--background) 等引用。" + } + }, + "zoomLevel": { + "sectionTitle": "視窗縮放", + "sectionDescription": "整體放大或縮小介面,立即生效,依裝置分別儲存。", + "placeholder": "請選擇縮放檔位", + "default": "預設", + "current": "目前縮放:{zoom}%" + }, + "fonts": { + "sectionTitle": "字型", + "sectionDescription": "為介面、程式碼編輯器與終端機分別選擇字型。內建字型會按需載入;選擇「自訂…」可使用系統已安裝的任意字型。", + "interface": "介面", + "editor": "編輯器", + "terminal": "終端機", + "groupSans": "無襯線", + "groupMono": "等寬", + "custom": "自訂…", + "customPlaceholder": "字型名稱,如 Fira Code", + "fontSize": "字級", + "ligatures": "啟用連字", + "ligaturesUnavailable": "此字型不含連字", + "wordWrap": "啟用自動換行", + "terminalLigaturesHint": "終端機連字僅對內建程式字型生效。", + "preview": "預覽" + }, + "welcomePanel": { + "sectionTitle": "模式選擇區域", + "sectionDescription": "新會話頁面輸入框上方顯示的「程式開發 / 日常辦公」快捷卡片區域。", + "showQuickActions": "在新會話頁面顯示" + }, + "workspaceBackground": { + "sectionTitle": "工作區背景", + "sectionDescription": "在整個工作區背後顯示一張圖片。側邊欄與面板會變半透明並磨砂讓圖片透出,遮罩確保文字可讀。", + "enable": "啟用背景圖片", + "image": "圖片", + "chooseImage": "選擇圖片", + "replaceImage": "更換圖片", + "removeImage": "移除", + "fillMode": "填滿方式", + "fillModes": { + "cover": "覆蓋", + "contain": "適應", + "center": "置中", + "tile": "平鋪" + }, + "maskOpacity": "遮罩不透明度", + "maskOpacityHint": "數值越高,圖片越向主題背景色淡化,文字對比越清晰。", + "imageBlur": "圖片模糊", + "panelOpacity": "面板不透明度", + "panelOpacityHint": "側邊欄、面板與標籤列的不透明程度。越低,透出的圖片越多。", + "errorTooLarge": "圖片太大(最大 16 MB)。", + "errorUploadFailed": "設定背景圖片失敗。" + } + }, + "SystemSettings": { + "loading": "載入中...", + "sectionTitle": "系統管理", + "sectionDescription": "管理網路代理、應用升級與語言偏好。", + "proxyTitle": "網路代理", + "proxyDescription": "啟用後,後續網路請求將優先走該代理(包含 ACP 對話、Agent 安裝、Git 遠端操作等)。", + "loadFailed": "載入失敗:{message}", + "enableProxy": "啟用系統代理", + "proxyAddress": "代理位址", + "proxyHint": "支援 http(s)/socks5,範例:{example}。僅在啟用系統代理時生效。", + "save": "儲存", + "saving": "儲存中...", + "proxyRequired": "啟用代理時必須填寫代理位址", + "saveSuccess": "系統代理設定已儲存", + "saveFailed": "儲存失敗:{message}", + "languageTitle": "語言", + "languageDescription": "設定應用語言。跟隨系統時,若系統語言不受支援將回退為英文。", + "appLanguage": "應用語言", + "languageSaveSuccess": "語言設定已儲存", + "languageSaveFailed": "語言設定儲存失敗:{message}", + "updateTitle": "應用升級", + "versionTitle": "軟體更新", + "updateDescription": "點擊檢查後會從設定的發佈來源拉取最新版本資訊,有新版本時可直接下載並安裝。", + "currentVersion": "目前版本", + "upgradableVersion": "最新版本", + "none": "暫無", + "lastChecked": "上次檢查:{time}", + "updateError": "更新異常:{message}", + "checking": "檢查中...", + "checkUpdate": "檢查更新", + "updating": "升級中...", + "downloading": "下載中...", + "upgradeTo": "升級到 v{version}", + "viewRelease": "查看 v{version} 發布", + "foundUpdate": "發現新版本 v{version}", + "alreadyLatest": "目前已是最新版本", + "checkUpdateFailed": "檢查更新失敗:{message}", + "installSuccess": "升級包已安裝,正在重新啟動應用", + "installFailed": "升級失敗:{message}", + "upgradeSuccess": "升級完成,正在重新載入...", + "restartTimeout": "服務未能即時恢復,請檢查容器或服務記錄。", + "restartingIn": "將在 {seconds} 秒後重新啟動...", + "waitingForServer": "正在等待服務恢復...", + "restartToUpdate": "重新啟動以更新", + "newVersionBadge": "新版本 v{version}", + "updateAvailableTitle": "發現新版本", + "releaseNotesTitle": "更新內容", + "remindLater": "稍後", + "retry": "重試", + "stepDownload": "下載", + "stepInstall": "安裝", + "stepRestart": "重新啟動", + "updateReadyHint": "新版本已下載,重新啟動以完成更新。", + "restarting": "正在重新啟動…", + "dockerUpgradeHint": "現在升級的是正在執行的容器。容器一旦被重新建立即遺失——如需保留,請拉取或建置新版本映像後重新建立容器。", + "upgradeRolledBack": "升級失敗,伺服器已自動回復到上一版本。", + "serverUnreachable": "無法連線到伺服器以開始升級。請確認伺服器正在執行後重試。", + "rollbackButton": "復原", + "rollingBack": "復原中...", + "rollbackDescription": "還原至上次升級前安裝的版本。", + "rollbackConfirmTitle": "復原到上一個版本?", + "rollbackConfirmDescription": "伺服器將重新啟動並執行上次升級前安裝的版本。較新的版本仍可再次安裝。", + "rollbackConfirm": "復原", + "rollbackCancel": "取消", + "rollbackSuccess": "已復原到上一個版本,正在重新載入……", + "rollbackFailed": "復原失敗,請檢查伺服器日誌。", + "updateErrors": { + "sourceUnavailable": "無法連線更新來源,請檢查網路或代理設定後重試。", + "network": "網路連線異常,請檢查網路或代理設定後重試。", + "downloadFailed": "下載更新包失敗,請稍後再試。", + "installFailed": "安裝更新失敗,請關閉應用後重試。", + "unknown": "更新失敗,請稍後再試。" + } + }, + "VersionControlSettings": { + "loading": "載入中...", + "sectionTitle": "版本控制", + "sectionDescription": "設定 Git 執行檔並管理 GitHub 帳號。", + "gitTitle": "Git 設定", + "gitDescription": "設定應用程式使用的 Git 執行檔。", + "gitDetected": "已偵測到 Git", + "gitNotFound": "未在系統中找到 Git", + "gitVersion": "版本", + "gitPath": "路徑", + "customGitPath": "自訂 Git 路徑", + "customGitPathPlaceholder": "/usr/bin/git", + "customGitPathHint": "留空則使用自動偵測的路徑。", + "test": "測試", + "testing": "測試中...", + "testSuccess": "Git 執行檔有效。", + "testFailed": "Git 測試失敗:{message}", + "save": "儲存", + "saving": "儲存中...", + "saveSuccess": "Git 設定已儲存。", + "saveFailed": "儲存失敗:{message}", + "githubTitle": "GitHub 帳號", + "githubDescription": "管理用於身份驗證的 GitHub 帳號。權杖儲存在本機。", + "noAccounts": "尚未設定 GitHub 帳號。", + "addAccount": "新增帳號", + "serverUrl": "伺服器網址", + "serverUrlPlaceholder": "https://github.com", + "token": "個人存取權杖", + "tokenPlaceholder": "ghp_xxxxxxxxxxxx", + "generateToken": "產生權杖", + "tokenHint": "在 GitHub → Settings → Developer settings → Personal access tokens 中產生權杖。", + "validateAndAdd": "驗證並新增", + "validating": "驗證中...", + "addSuccess": "帳號 {username} 新增成功。", + "addFailed": "新增帳號失敗:{message}", + "testConnection": "測試", + "connectionSuccess": "連線成功。", + "connectionFailed": "連線失敗:{message}", + "setDefault": "設為預設", + "defaultLabel": "預設", + "defaultSet": "預設帳號已更新。", + "removeAccount": "刪除", + "removeConfirmTitle": "刪除帳號", + "removeConfirmMessage": "確定要刪除帳號「{username}」嗎?", + "removeConfirm": "刪除", + "removeCancel": "取消", + "removeSuccess": "帳號已刪除。", + "scopes": "權限範圍", + "loadFailed": "載入設定失敗:{message}", + "gitAccount": { + "sectionTitle": "Git 伺服器帳號", + "sectionDescription": "管理非 GitHub 的 Git 伺服器憑據(GitLab、Bitbucket、自建服務等)。", + "noAccounts": "尚未設定 Git 伺服器帳號。", + "addAccount": "新增帳號", + "addTitle": "新增 Git 帳號", + "addDescription": "輸入伺服器網址、使用者名稱和密碼或存取權杖。", + "serverUrl": "伺服器網址", + "serverUrlPlaceholder": "https://gitlab.example.com", + "username": "使用者名稱", + "usernamePlaceholder": "使用者名稱或電子郵件", + "password": "密碼 / 權杖", + "passwordPlaceholder": "密碼或存取權杖", + "passwordHint": "輸入伺服器的密碼或個人存取權杖。", + "add": "新增", + "serverRequired": "請輸入伺服器網址。", + "usernameRequired": "請輸入使用者名稱。", + "passwordRequired": "請輸入密碼。" + } + }, + "ShortcutSettings": { + "sectionTitle": "快捷鍵", + "resetDefault": "恢復預設", + "recordInstruction": "點擊右側按鈕後按下組合鍵即可修改。建議使用 Ctrl/Cmd、Alt、Shift 的組合。按 Esc 可取消錄製。", + "recording": "按下快捷鍵...", + "toasts": { + "conflict": "快捷鍵已被「{title}」占用", + "updated": "快捷鍵已更新", + "invalid": "快捷鍵無效,請重試", + "reset": "已恢復預設快捷鍵" + }, + "actions": { + "toggle_search": { + "title": "打開搜尋", + "description": "打開或關閉會話搜尋面板" + }, + "toggle_sidebar": { + "title": "切換左側邊欄", + "description": "顯示或隱藏會話列表側邊欄" + }, + "toggle_terminal": { + "title": "切換終端", + "description": "顯示或隱藏底部終端面板" + }, + "new_terminal_tab": { + "title": "新增終端", + "description": "當最近滑鼠活動在終端時新增終端分頁" + }, + "close_current_terminal_tab": { + "title": "關閉目前終端", + "description": "當最近滑鼠活動在終端時關閉目前終端分頁" + }, + "toggle_aux_panel": { + "title": "切換右側面板", + "description": "顯示或隱藏輔助資訊面板" + }, + "new_conversation": { + "title": "新增會話", + "description": "在目前資料夾中建立新的對話分頁" + }, + "open_folder": { + "title": "打開資料夾", + "description": "打開資料夾選擇器並在新視窗中開啟" + }, + "open_settings": { + "title": "打開設定", + "description": "打開設定視窗" + }, + "close_current_tab": { + "title": "關閉目前分頁", + "description": "關閉目前會話或檔案分頁" + }, + "close_all_file_tabs": { + "title": "關閉全部檔案分頁", + "description": "當檔案面板處於作用中狀態時關閉所有開啟的檔案分頁" + }, + "next_tab": { + "title": "下一個標籤頁", + "description": "切換到下一個會話或檔案標籤頁" + }, + "prev_tab": { + "title": "上一個標籤頁", + "description": "切換到上一個會話或檔案標籤頁" + }, + "send_message": { + "title": "傳送訊息", + "description": "在輸入框中傳送目前的訊息" + }, + "newline_in_message": { + "title": "訊息換行", + "description": "在輸入框中插入換行符" + }, + "toggle_custom_style": { + "title": "停用/恢復自訂樣式", + "description": "逃生艙:一鍵關閉全部自訂配色與 CSS,再按一次恢復" + } + } + }, + "SkillsSettings": { + "title": "Skills", + "description": "左側選擇 Skill,右側預設預覽 Markdown,點擊編輯後可修改並儲存。", + "loadingAgents": "正在載入支援 Skills 的 Agent...", + "emptyNoManageableAgents": "目前沒有可管理 Skills 的 Agent。", + "managedTarget": "管理對象", + "selectAgentPlaceholder": "請選擇 Agent", + "searchPlaceholder": "搜尋名稱 / ID / 路徑...", + "skillsList": "Skills 列表", + "loadingSkills": "載入 Skills 中...", + "agentNotSupported": "目前 Agent 暫不支援 Skills 管理。", + "emptySkills": "暫無 Skill,可點擊「新增 Skill」。", + "newSkillTitle": "新增 Skill", + "skillInfo": "Skill 資訊", + "skillIdPlaceholder": "Skill ID(例如:my-skill)", + "skillsDirectoryWithPath": "Skills目錄:{path}", + "skillsDirectoryNeedId": "Skills目錄:請輸入 Skill ID 以產生完整路徑", + "markdownContent": "Markdown 內容", + "editingStatus": "編輯中", + "previewStatus": "預覽中", + "contentPlaceholder": "輸入 Skill 文字內容...", + "metadataTitle": "Skills 中繼資訊", + "onlyYamlMetadata": "該 Skill 僅包含 YAML 中繼資訊。", + "emptyContentHint": "暫無內容。點擊「編輯」開始輸入。", + "loadingSkill": "正在載入 Skill...", + "emptyNoAgents": "暫無可用 Agent。", + "noSelectionHint": "從左側選擇一個 Skill,或點擊「新建 Skill」建立。", + "systemBadge": "系統", + "systemHint": "CLI 內建 Skill · 唯讀", + "scope": { + "global": "全域", + "folder": "資料夾", + "selectFolderPlaceholder": "選擇資料夾", + "noFolders": "找不到任何資料夾", + "pickFolderHint": "選擇一個資料夾以檢視其 Skills。" + }, + "actions": { + "preview": "預覽", + "edit": "編輯", + "openInWindow": "在新視窗打開", + "delete": "刪除", + "deleting": "刪除中...", + "refresh": "刷新", + "newSkill": "新增 Skill", + "reset": "重置", + "save": "儲存", + "saving": "儲存中...", + "cancel": "取消" + }, + "deleteDialog": { + "title": "刪除 Skill", + "confirm": "確認刪除目前 Skill 嗎?此操作無法復原。", + "confirmWithNamePrefix": "確認刪除 Skill", + "confirmWithNameSuffix": "嗎?此操作無法復原。" + }, + "toasts": { + "loadFailed": "載入 Skill 失敗", + "openFolderFailed": "打開目錄失敗", + "noSkillDirectory": "目前 Agent 未找到可用的 Skills 目錄", + "nameRequired": "Skill 名稱不能為空", + "updated": "Skill 已更新", + "created": "Skill 已建立", + "saveFailed": "儲存 Skill 失敗", + "deleted": "Skill 已刪除", + "deleteFailed": "刪除 Skill 失敗" + }, + "templates": { + "gemini": "---\nname: example-skill\ndescription: Describe when this skill should be used.\n---\n\n# Skill Name\n\nInstructions for the agent when this skill is active.\n\n## Workflow\n\n1. Add actionable step one.\n2. Add actionable step two.\n", + "openCode": "---\nname: example-skill\ndescription: Describe when this skill should be used.\n---\n\n# Purpose\n\nDescribe what this skill helps with.\n\n# Steps\n\n1. Add actionable step one.\n2. Add actionable step two.\n", + "openClaw": "---\nname: example-skill\ndescription: Describe when this skill should be used.\nuser-invocable: true\ndisable-model-invocation: false\n---\n\n# Purpose\n\nDescribe what this skill helps with.\n\n# Instructions\n\n1. Add actionable instruction one.\n2. Add actionable instruction two.\n", + "default": "---\nname: example-skill\ndescription: Describe when this skill should be used.\n---\n\n# Skill: example-skill\n\n## When to use\n\n- Describe trigger conditions.\n\n## Instructions\n\n1. Add actionable instruction one.\n2. Add actionable instruction two.\n" + } + }, + "McpSettings": { + "loading": "載入中...", + "summary": { + "missingCommand": "(缺少 command)", + "missingUrl": "(缺少 url)" + }, + "protocol": { + "stdio": "Stdio" + }, + "errors": { + "selectInstallProtocol": "請選擇安裝協議", + "fieldRequired": "{field} 為必填項", + "fieldNeedsBoolean": "{field} 需要 true 或 false", + "fieldNeedsNumber": "{field} 需要數字", + "fieldNeedsInteger": "{field} 需要整數", + "fieldInvalidJson": "{field} JSON 無效:{message}", + "fieldOutOfRange": "{field} 的值不在可選範圍內", + "jsonEmpty": "{name} 不能為空", + "jsonInvalid": "{name} 不是合法 JSON:{message}", + "jsonMustBeObject": "{name} 必須是 JSON 物件", + "specMustBeObject": "MCP 設定必須是 JSON 物件。", + "missingType": "MCP 設定缺少 type 欄位。請填寫 stdio、http(別名 streamable-http、streamableHttp)、sse 其中之一。", + "unsupportedType": "不支援的 MCP type:{type}。支援的類型:stdio、http(別名 streamable-http、streamableHttp)、sse。", + "codexEntryUnsupportedType": "Codex MCP 項目 {id} 的 type 不受支援:{type}。支援的類型:stdio、http(別名 streamable-http、streamableHttp)、sse。", + "unsupportedTransportType": "不支援的 transport 類型:{type}。支援的類型:http(別名 streamable-http、streamableHttp)、sse。", + "stdioCommandRequired": "stdio 類型的 MCP 必須填寫非空的 command 欄位。", + "remoteUrlRequired": "遠端 MCP 必須填寫非空的 url 欄位。", + "appsRequired": "請至少選擇一個目標 App。" + }, + "jsonNames": { + "localConfig": "MCP 配置", + "installConfig": "安裝配置" + }, + "toasts": { + "uninstalled": "已卸載 MCP", + "uninstallFailed": "卸載失敗:{message}", + "selectAtLeastOneApp": "請至少選擇一個目標應用", + "saveSuccess": "儲存成功", + "saveFailed": "儲存失敗:{message}", + "installed": "已安裝 {name}", + "installFailed": "安裝失敗:{message}", + "serverIdRequired": "Server ID 不能為空", + "serverIdExists": "Server ID \"{id}\" 已存在,請編輯現有項或更換名稱", + "created": "MCP 已建立" + }, + "installDialog": { + "title": "確認安裝 MCP", + "descriptionWithName": "將 {name} 安裝到本地配置。", + "description": "選擇安裝目標應用。", + "protocol": "協議", + "selectProtocol": "選擇協議", + "parameters": "配置參數", + "booleanPlaceholder": "請選擇 true/false", + "selectOneValue": "選擇一個值", + "targetApps": "目標應用" + }, + "actions": { + "cancel": "取消", + "confirmInstall": "確認安裝", + "installing": "安裝中", + "uninstall": "卸載", + "uninstalling": "卸載中", + "viewDetails": "查看詳情", + "save": "儲存", + "saving": "儲存中", + "install": "安裝", + "refresh": "重新整理", + "newMcp": "新建 MCP", + "create": "建立", + "creating": "建立中..." + }, + "tabs": { + "local": "本地 MCP", + "market": "MCP 市場" + }, + "local": { + "filterPlaceholder": "篩選本地 MCP...", + "loadFailed": "載入失敗:{message}", + "empty": "目前未檢測到本地 MCP。", + "description": "本地 MCP 配置可直接編輯並儲存。", + "enabledApps": "啟用應用", + "configJson": "MCP 配置(JSON)", + "draftTitle": "新建 MCP", + "draftDescription": "填寫 Server ID 與設定以建立本地 MCP 伺服器。", + "serverIdLabel": "Server ID", + "serverIdPlaceholder": "Server ID(例如:my-mcp)", + "typeHint": "支援類型:stdio、http(別名 streamable-http、streamableHttp)、sse。env 僅適用於 stdio;遠端 MCP 請透過 headers 欄位傳遞認證 token。", + "envOnRemoteWarning": "偵測到遠端 MCP 設定中包含 env 欄位。env 僅 stdio 類型使用,遠端 MCP 應透過 headers 攜帶認證資訊,env 欄位儲存時會被忽略。" + }, + "market": { + "selectMarketplace": "選擇市場", + "searchPlaceholder": "搜尋 MCP...", + "searchFailed": "搜尋失敗:{message}", + "loadingList": "載入 MCP 列表...", + "empty": "暫無 MCP 結果。", + "loadingDetail": "載入市場詳情...", + "detailLoadFailed": "載入詳情失敗:{message}", + "owner": "擁有者:{owner}", + "namespace": "命名空間:{namespace}", + "defaultInstallProtocol": "預設安裝協議", + "currentOptionParameterCount": "目前選項參數數:{count}", + "installConfigDescription": "安裝配置(JSON,可修改後安裝;修改後將覆蓋協議/參數表單)", + "selectLeftToView": "請選擇左側市場 MCP 查看詳情。" + }, + "badges": { + "verified": "已驗證", + "remote": "遠端", + "hasHomepage": "有首頁", + "uses": "{count} 次使用", + "deployed": "已部署", + "notDeployed": "未部署" + }, + "selectLeftMcp": "請選擇左側 MCP。" + }, + "AcpAgentSettings": { + "title": "Agent SDK管理", + "description": "統一管理 Agent 的連接SDK、啟用狀態、環境變數、配置管理與版本預檢資訊。", + "loadingAgents": "載入 Agent 列表中...", + "agentList": "Agent 列表", + "emptyNoAgent": "暫無可用 Agent。", + "configManagement": "配置管理", + "envVars": "環境變數", + "hostTools": { + "label": "由 Agent 自行處理檔案與指令", + "description": "codeg 不再代為提供檔案存取與終端指令,改由 Agent 在自己的行程中執行——只有這樣它自帶的沙箱與權限規則才會生效。同時會關閉向其他 Agent 委派,否則同樣的操作又會繞回 codeg 執行。codeg 本身不提供沙箱,因此請僅在 Agent 已設定沙箱時開啟。" + }, + "nativeJsonConfig": "原生 JSON 配置", + "modelHintDefault": "留空則使用系統預設模型。", + "generalConfigDescriptionClaude": "支援 API URL、API Key 與 Claude 模型快捷配置,並與原生 JSON 配置聯動。", + "generalConfigDescriptionDefault": "支援重要配置輸入(API URL、API Key、Model)和原生 JSON 配置管理。", + "multiAgent": { + "title": "多智慧體協同", + "description": "允許活躍的智慧體將子任務委派給其他智慧體。", + "enable": "啟用委派", + "enableHint": "關閉後,delegate_to_agent 工具會從智慧體的 MCP 工具清單中隱藏。", + "withheldByHostTools": "{agents} 不會拿到委派工具:它們單獨開啟了「由 Agent 自行處理檔案與命令」。", + "selfInitiate": "Allow spawn without @", + "selfInitiateHint": "When on, an agent may start a listed sub-agent on its own. An @ mention is still always honored. When off, only an @ mention starts a sub-agent.", + "depthLimit": "最大委派深度", + "depthHint": "允許範圍:{min}–{max}。限制委派鏈(根 → 子 → 孫 …)的最大遞迴深度。", + "completedCacheLabel": "已完成結果快取(MB)", + "completedCacheHint": "執行中委派工作階段已完成子代理結果的記憶體快取,僅在該工作階段執行期間保留,工作階段結束後自動清除。超出此預算時優先從記憶體中捨棄最舊的結果(仍可在子代理自己的工作階段中檢視);0 表示不限(工作階段結束後仍會清除)。", + "save": "儲存", + "saving": "儲存中…", + "saved": "委派設定已儲存", + "saveFailed": "委派設定儲存失敗", + "loadFailed": "載入委派設定失敗:{detail}", + "tabGeneral": "一般", + "tabAgentDefaults": "子智慧體設定", + "agentDefaultsDescription": "多智慧體協同在為委派呼叫啟動子智慧體時使用這些覆寫項。下方選項透過即時探測取得,所選即所用。", + "probing": "正在載入該智慧體的可用設定項…", + "probeFailed": "載入設定項失敗:{detail}", + "retry": "重試", + "noConfigAvailable": "該智慧體沒有可設定項。", + "modeLabel": "模式", + "agentDefaultHint": "智慧體預設:{value}", + "defaultOptionLabel": "預設({value})" + }, + "actions": { + "dragSort": "拖拽排序", + "dragSortAgent": "拖拽排序 {name}", + "refreshCheck": "刷新檢測", + "refreshCheckAgent": "刷新檢測 {name}", + "clickEnable": "點擊啟用 {name}", + "clickDisable": "點擊停用 {name}", + "install": "安裝", + "upgrade": "升級", + "uninstall": "卸載", + "uninstalling": "卸載中...", + "saveEnvVars": "儲存環境變數", + "saving": "儲存中...", + "saveGrokConfig": "儲存 Grok 設定", + "saveCodexConfig": "儲存 Codex 配置", + "saveGeminiConfig": "儲存 Gemini 配置", + "saveOpenCodeConfig": "儲存 OpenCode 配置", + "saveOpenClawConfig": "儲存 OpenClaw 配置", + "saveConfigManagement": "儲存配置管理", + "saveCurrentProvider": "儲存目前 Provider", + "showApiKey": "顯示 API Key", + "hideApiKey": "隱藏 API Key", + "showKey": "顯示 Key", + "hideKey": "隱藏 Key", + "showToken": "顯示 Token", + "hideToken": "隱藏 Token", + "cancel": "取消", + "delete": "刪除", + "deleting": "刪除中...", + "confirmDelete": "確認刪除", + "confirmUninstall": "確認卸載", + "saveClineConfig": "儲存 Cline 配置", + "saveHermesConfig": "儲存 Hermes 配置", + "saveCodeBuddyConfig": "儲存 CodeBuddy 設定", + "saveKimiCodeConfig": "儲存 Kimi Code 設定", + "customInstall": "自訂安裝", + "saveKimiCodeRawConfig": "儲存 config.toml", + "saveDeepSeekConfig": "儲存 DeepSeek 設定", + "diagnose": "診斷" + }, + "status": { + "enabled": "啟用", + "disabled": "停用", + "unchecked": "未檢測", + "agentEnabledAria": "{name} 已啟用", + "agentEnabledSwitch": "{name} 啟用" + }, + "preflight": { + "count": "預檢項:{count}", + "notRun": "尚未執行檢測。" + }, + "grok": { + "configDescription": "在此設定 Grok。下方控制項——權限模式、推理強度、選用的自訂(自帶端點)模型與壓縮——會合併寫入 ~/.grok/config.toml,並保留你的其他鍵與註解。登入使用你的 XAI_API_KEY 或 `grok login`。其他鍵可在「進階」中編輯。", + "permissionModeLabel": "權限模式", + "permissionDefault": "每次詢問", + "permissionAcceptEdits": "自動批准編輯", + "permissionAuto": "智慧自動批准", + "permissionAlwaysApprove": "永遠允許", + "reasoningEffortLabel": "推理級別", + "effortLow": "低(較快)", + "effortMedium": "中(均衡)", + "effortHigh": "高", + "effortXhigh": "最高", + "optionDefault": "使用預設", + "authTitle": "驗證", + "authMode": "認證方式", + "authModeApiKey": "XAI API 金鑰", + "authModeApiKeyHint": "使用 xAI 主控台的 XAI_API_KEY 認證——適用於非互動/無頭執行。儲存在該智慧體的環境變數中。", + "authModeCustom": "自訂接口", + "authModeCustomHint": "使用自訂接口(BYO 端點):在下方定義一個帶有獨立 base URL 和 API 金鑰的自訂模型,它將成為 Grok 的預設模型。", + "subscriptionHint": "使用 `grok login` 登入(SuperGrok / X Premium+)。不會儲存 API 金鑰。", + "loginHint": "在終端機執行以下指令登入,然後重新開啟此設定:", + "commandCopied": "指令已複製到剪貼簿", + "copyCommand": "複製指令", + "authKeyConfigured": "已設定 XAI_API_KEY。", + "authKeyMissing": "未設定 XAI_API_KEY。", + "advancedToggle": "進階(原始 config.toml)", + "configTomlNative": "config.toml(原生)", + "configTomlHint": "按原樣整體寫入 ~/.grok/config.toml。非法 TOML 會被拒絕,絕不因筆誤截斷檔案。", + "configTomlPlaceholder": "# 上面控制項之外的鍵,例如\n# [mcp_servers.*]、[cli]、[permission] 規則。", + "customModelTitle": "自訂模型(自帶端點)", + "customModelHint": "讓 Grok 指向自訂或自架端點。codeg 會寫入按模型的 `[model.*]` 區塊並設為預設模型。清空模型 ID 即可移除。", + "customModelIdLabel": "模型 ID", + "customModelIdPlaceholder": "grok-4.5", + "customModelIdHint": "註冊為 `[model.*]` 區塊,並作為模型名稱傳送給 API;同時設為 `[models].default`。", + "customBaseUrlLabel": "Base URL", + "customBaseUrlPlaceholder": "https://api.x.ai/v1(預設)", + "customApiBackendLabel": "API 後端", + "backendResponses": "Responses", + "backendChatCompletions": "Chat Completions", + "backendMessages": "Messages(Anthropic)", + "customApiKeyLabel": "API Key", + "customApiKeyHint": "內聯儲存於 `[model.*].api_key`,僅作用於此端點。", + "customContextWindowLabel": "上下文視窗(tokens)", + "customContextWindowHint": "選填。用於自動壓縮計時;留空則使用端點預設值。", + "autoCompactLabel": "自動壓縮閾值(%)", + "autoCompactHint": "當上下文使用率達到此百分比時壓縮對話(Grok 預設 85)。寫入 `[session]`。" + }, + "cursor": { + "configDescription": "在此設定 Cursor。先選擇驗證方式——官網訂閱(瀏覽器登入)或用於無頭/伺服器的 Cursor API 金鑰——然後選擇模型並編輯 CLI 的權限規則與沙箱。codeg 會寫入 ~/.cursor/cli-config.json,與 cursor-agent CLI 共用。", + "authTitle": "驗證", + "authChecking": "檢測中…", + "authNotInstalled": "cursor-agent 未安裝", + "authLoggedIn": "已登入", + "authNotLoggedIn": "未登入", + "loginHint": "在終端機執行以下指令登入 Cursor 帳號(會開啟瀏覽器),完成後點重新整理:", + "apiKeyLabel": "Cursor API 金鑰", + "apiKeyPlaceholder": "在 cursor.com/dashboard 取得", + "apiKeyHint": "CURSOR_API_KEY —— Cursor Dashboard 的帳號金鑰,在無頭/伺服器環境下取代瀏覽器登入。不是第三方或 OpenAI 金鑰。", + "modelTitle": "預設模型", + "loadModels": "取得模型清單", + "modelsUnavailable": "模型清單不可用", + "modelHint": "會話啟動時透過 --model 傳給 CLI;保持預設則由 Cursor 自行選擇。", + "permissionsTitle": "權限與沙箱", + "permissionsDescription": "可視化編輯 CLI 權限規則(cli-config.json)。允許規則免確認執行;拒絕規則一律攔截。", + "permissionModeLabel": "權限模式", + "permissionModeDefault": "執行前詢問(預設)", + "permissionModeForce": "全部放行 Run Everything(--force)", + "permissionModeHint": "Run Everything 以 --force 啟動工作階段:除 deny 規則外的所有工具呼叫自動放行、不再跳出確認(組織政策可能將其降級為僅按 allow 規則放行)。對新工作階段生效。", + "optionDefault": "預設(未設定)", + "sandboxLabel": "沙箱", + "sandboxEnabled": "啟用", + "sandboxDisabled": "停用", + "allowRulesLabel": "允許規則", + "denyRulesLabel": "拒絕規則", + "addRule": "新增規則", + "rulesSyntaxHint": "規則語法:Shell(命令)、Read(路徑/萬用字元)、Write(路徑/萬用字元)、WebFetch(網域)、Mcp(伺服器:工具)——deny 規則始終優先。", + "saveConfig": "儲存設定", + "advancedToggle": "進階:原始 cli-config.json", + "advancedHint": "完整的 ~/.cursor/cli-config.json。此處儲存按原文寫入;上方結構化控制項則以合併方式寫入。", + "saveRawConfig": "儲存檔案", + "authMode": "認證方式", + "subscriptionHint": "使用 Cursor 帳號登入,使用 Cursor 的模型。", + "customApiKeyRequired": "需要填寫 Cursor API 金鑰。", + "authModeApiKey": "Cursor API 金鑰(無頭/伺服器)", + "authModeApiKeyHint": "使用 Cursor 官網 Dashboard 產生的帳號 API 金鑰進行驗證(適用於無頭/伺服器環境)。這是 Cursor 帳號金鑰,不是第三方/OpenAI 端點——cursor-agent 只會連線到 Cursor 自己的後端。若要使用 codex/OpenAI 相容端點,請改用 Codex 智慧體。", + "modelPickerPlaceholder": "搜尋模型…", + "modelNoMatch": "沒有相符的模型", + "modelsNeedAuth": "登入後載入模型清單。", + "modelDefaultBadge": "預設" + }, + "deepseek": { + "configManagement": "DeepSeek Harness 設定", + "configDescription": "端點與金鑰是 deepseek-acp 啟動時讀取的環境變數。模型與推理等級是工作階段層級的選擇器,在輸入框裡切換。", + "baseUrlLabel": "API 端點", + "baseUrlHint": "留空則使用官方端點。儲存後對新建的工作階段生效——正在進行的工作階段需要重新連線才會切換。", + "baseUrlInvalid": "請填寫完整的 http(s) 網址且不帶查詢參數,例如 https://api.deepseek.com", + "apiKeyLabel": "API 金鑰", + "apiKeyHint": "以 DEEPSEEK_API_KEY 傳給智慧體。環境變數的優先權高於憑證檔,因此若用終端機登入,這裡留空即可。" + }, + "codex": { + "configDescription": "支援 API URL、API Key、模型名稱、Reasoning Effort 快捷配置,並與 `auth.json` / `config.toml` 雙向聯動。", + "authMode": "認證方式", + "chatgptSubscription": "官網訂閱", + "chatgptSubscriptionHint": "使用 ChatGPT 官網訂閱登入,無需配置 API Key", + "apiKeyHint": "使用 API Key 連接 OpenAI 或相容的 API 服務", + "selectProvider": "選擇 Provider", + "modelName": "模型名稱", + "selectReasoningEffort": "選擇 Reasoning Effort", + "enableWebsocket": "啟用 WebSocket", + "enableWebsocketAria": "Codex Provider 啟用 WebSocket", + "enableSkills": "啟用 Skills", + "enableSkillsAria": "Codex 啟用 Skills", + "enableFast": "啟用 Fast", + "enableFastAria": "Codex 啟用 Fast 服務等級", + "sandboxGroupTitle": "沙箱與審批", + "sandboxGroupHint": "寫入全域 ~/.codex/config.toml,codex CLI 與 IDE 的工作階段同樣生效。這是執行緒預設值,只作用於 codex 自行發起的回合(/goal、/review、/compact);一般對話使用輸入框裡的審批預設。變更需重開工作階段才生效。", + "sandboxShadowedWarning": "config.toml 裡設定了 default_permissions,codex 會改走權限設定檔並完全忽略 sandbox_mode。刪除 default_permissions 後下面的選項才會生效。", + "sandboxPermissionsTableWarning": "config.toml 定義了 [permissions] 設定檔卻沒有 default_permissions,codex 會拒絕啟動。請在下方原始編輯器裡補上。", + "approvalPolicyLabel": "審批策略", + "approvalPolicyUnset": "未設定(codex 預設:依需求詢問)", + "approvalPolicy_on-request": "依需求詢問 — 由模型決定何時請求批准", + "approvalPolicy_untrusted": "僅信任唯讀 — 只有已知安全的唯讀指令免批准", + "approvalPolicy_never": "從不詢問 — 完全不彈審批", + "approvalPolicy_granular": "精細控制 — 依提示類型分別設定", + "approvalPolicyUntrustedAcpWarning": "ACP 轉接器只有三種審批預設,untrusted 無對應項,codeg 工作階段會退回「按需詢問」——此時由模型自行決定何時詢問,沙箱本就允許的命令不再詢問。請改用下方的沙箱模式收緊。", + "granularHint": "關閉表示該類請求會被自動拒絕,而不是彈給你確認。", + "granular_sandbox_approval": "Shell 指令越權申請", + "granular_rules": "Execpolicy 規則提示", + "granular_skill_approval": "技能指令碼執行提示", + "granular_request_permissions": "request_permissions 工具提示", + "granular_mcp_elicitations": "MCP elicitation 提示", + "sandboxModeLabel": "沙箱模式", + "sandboxModeUnset": "未設定(受信任的資料夾回落為可寫工作區)", + "sandboxMode_read-only": "唯讀", + "sandboxMode_workspace-write": "可寫工作區", + "sandboxMode_danger-full-access": "完全開放(無沙箱)", + "sandboxModeHint": "在 Windows 上,未開啟 codex 的實驗性 Windows 沙箱時,可寫工作區會被降級為唯讀。", + "sandboxModeSeedsPresetHint": "codeg 還會用它推導工作階段的初始審批預設,因此與審批策略不同,它對一般提問同樣生效。輸入框中選擇的預設仍會覆蓋它。", + "writableRootsLabel": "額外可寫目錄", + "writableRootsHint": "每行一個絕對路徑,作為工作目錄之外的額外可寫位置。", + "sandboxRootsRelativeError": "必須是絕對路徑 — codex 會把相對路徑解析到 ~/.codex 底下:{path}", + "networkAccessLabel": "允許網路存取", + "excludeTmpdirLabel": "從可寫目錄中排除 TMPDIR", + "excludeSlashTmpLabel": "從可寫目錄中排除 /tmp", + "authJsonNative": "auth.json(原生)", + "configTomlNative": "config.toml(原生)", + "loginButton": "使用 ChatGPT 登入", + "loginRequesting": "正在請求登入碼...", + "loginStep1": "在瀏覽器中打開以下連結:", + "loginStep2": "輸入以下代碼:", + "loginPolling": "等待授權中...", + "loginCancel": "取消", + "loginSuccess": "登入成功,配置已儲存!", + "loginFailed": "登入失敗:{message}", + "loginRetry": "重試", + "loginCodeCopied": "已複製代碼", + "loggedIn": "帳號已登入", + "loginRelogin": "重新登入 / 切換帳號", + "loginTimeout": "登入逾時,請重試", + "loginSaveFailed": "登入成功但配置儲存失敗" + }, + "gemini": { + "authConfig": "Gemini 認證配置", + "authConfigDescription": "對齊 Gemini CLI 認證文件,支援自訂、Google 登入、Gemini API Key、Vertex AI(ADC / 服務帳號 / API Key)。", + "authMode": "認證方式", + "selectAuthMode": "選擇認證方式", + "viewAuthDoc": "查看認證文件", + "mode": { + "custom": "自訂介面", + "loginGoogle": "Google 登入(OAuth)", + "vertexServiceAccount": "Vertex AI(服務帳號)" + }, + "hint": { + "custom": "填寫 API URL、API Key 和 Model,分別映射到 GOOGLE_GEMINI_BASE_URL / GEMINI_API_KEY / GEMINI_MODEL。", + "loginGoogle": "首次在終端執行 gemini 並完成 Google 登入;無需填寫 API Key。", + "geminiApiKey": "使用 Gemini API 時填寫 GEMINI_API_KEY。", + "vertexAdc": "使用 gcloud ADC,建議填寫 GOOGLE_CLOUD_PROJECT 與 GOOGLE_CLOUD_LOCATION。", + "vertexServiceAccount": "服務帳號 JSON 路徑寫入 GOOGLE_APPLICATION_CREDENTIALS。", + "vertexApiKey": "使用 Vertex AI API key 時填寫 GOOGLE_API_KEY。" + } + }, + "openCode": { + "configManagement": "OpenCode 配置管理", + "configDescription": "對齊 OpenCode `provider` 配置結構,支援多供應商管理,並與原生 JSON 檔案雙向聯動。", + "providerManagement": "Provider 管理", + "providerCount": "共 {count} 個", + "addProvider": "新增 Provider", + "emptyProvider": "還沒有自訂 Provider。點擊「新增自訂 Provider」建立。", + "providerEnabledState": "{providerId} 啟用狀態", + "selectProviderNpm": "選擇 provider.npm", + "modelManagement": "模型管理", + "modelCount": "共 {count} 個", + "modelDescription": "對齊 OpenCode `provider.models` 結構。目前支援 `name` / `id` 快速管理;其它進階欄位會保留,可在下方原生 JSON 中繼續編輯。", + "addModel": "新增模型", + "emptyModel": "暫無模型,輸入 model id 後點擊「新增模型」建立。", + "modelId": "模型 ID", + "modelName": "模型名稱", + "deleteModel": "刪除模型 {modelId}", + "nativeJsonConfig": "OpenCode 原生 JSON 配置", + "mainModel": "主模型", + "smallModel": "小模型", + "noMatchingModels": "沒有匹配的模型", + "connectProvider": "連接 Provider", + "connectedProviders": "已連接的 Provider", + "noConnectedProviders": "還沒有從目錄連接 Provider。", + "advancedProviderConfig": "自訂 Provider", + "customProviderConfigHint": "你自己定義的 OpenAI 相容端點——opencode.json 裡的一個 provider 設定區塊,API key 存在 auth.json。", + "addCustomProvider": "新增自訂 Provider", + "disconnect": "中斷連接", + "editConfig": "編輯", + "customBadge": "自訂", + "authKindApi": "API Key", + "authKindOauth": "OAuth", + "authKindNone": "無憑證", + "connect": { + "title": "連接 Provider", + "description": "從 models.dev 目錄選擇一個 Provider。憑證儲存到 OpenCode 的 auth.json 檔案。", + "pick": "Provider", + "search": "搜尋 Provider…", + "loading": "正在載入目錄…", + "catalogLabel": "models.dev 目錄", + "modelsAvailable": "{count} 個可用模型", + "getKey": "取得 API Key", + "oauthApiKeyNote": "此 Provider 也支援透過 opencode auth login 瀏覽器登入。瀏覽器登入即將推出——目前請貼上 API Key。", + "apiKey": "API Key", + "apiKeyHint": "儲存在 auth.json,絕不寫入 opencode.json。", + "baseUrlOptional": "Base URL 覆寫(選填)", + "providerId": "Provider ID", + "displayName": "顯示名稱", + "modelsList": "模型(每行一個)", + "modelsHint": "端點接受的模型 ID。", + "action": "連接", + "editTitle": "編輯 Provider", + "editDescription": "更新該 Provider 的 API Key 或 Base URL。", + "saveAction": "儲存" + }, + "customProvider": { + "title": "新增自訂 Provider", + "description": "定義一個 OpenAI 相容端點。API key 儲存到 auth.json;provider 設定區塊寫入 opencode.json。", + "action": "新增 Provider", + "idInCatalog": "{providerId} 是已知 Provider,請改用「連接 Provider」連接。" + }, + "refreshCatalog": "重新整理目錄", + "reasoningBadge": "推理", + "contextWindow": "上下文視窗", + "permissions": { + "title": "權限", + "description": "決定哪些操作直接執行、先徵求你的同意,還是被阻擋。寫入 opencode.json 的 permission 設定,點擊下方儲存後生效。", + "docsLink": "權限文件", + "unparsableConfig": "下方的原生 JSON 目前無法解析,視覺化編輯已暫停。修正 JSON 後即可繼續。", + "invalidBlock": "permission 設定的結構無法辨識。請在下方原生 JSON 中修改,或點擊「恢復預設」重來。", + "orderingUnsafe": "萬用規則寫在了具體工具之後,OpenCode 會把它一併套用到這些工具上——下方各列顯示的並非實際生效的規則。「修正順序」只把萬用規則移回各自範圍的最前面,不更動任何值。", + "orderingUnsafeManual": "有規則被後面更寬鬆的模式遮蔽,OpenCode 永遠不會套用它——下方各列顯示的並非實際生效的規則。兩個互相重疊的模式沒有唯一正確的順序,請在下方原生 JSON 中調整,把較寬鬆的寫在前面。", + "fixOrder": "修正順序", + "agentOverrides": "下列智慧代理個別覆寫了權限,且在最後套用,因此會蓋過此處的所有設定:{agents}。請在下方原生 JSON 中修改,或開啟「自動接受所有權限」將其清除。", + "legacyTools": "頂層的舊版 tools 設定停用了某個工具。OpenCode 會把它併入權限,因此會疊加在此處顯示的所有設定之上。請在下方原生 JSON 中修改,或開啟「自動接受所有權限」將其清除。", + "autoAcceptTitle": "自動接受所有權限", + "autoAcceptHint": "所有工具呼叫(shell 指令、檔案修改、存取專案外路徑)都不再詢問,直接執行。開啟後會以一條全域允許規則取代下方的逐工具設定,並清除各智慧代理個別的權限覆寫與舊版 tools 開關——否則它們仍會攔截。", + "globalLabel": "全域預設", + "globalHint": "即 * 規則:下方工具未個別覆寫時採用的動作。", + "actionUnset": "未設定(OpenCode 預設)", + "actionInherit": "沿用預設({action})", + "actionAllow": "允許", + "actionAsk": "詢問", + "actionDeny": "拒絕", + "perToolTitle": "逐工具權限", + "reset": "恢復預設", + "ruleCount": "細則 {count} 條", + "rulesToggle": "{tool} 的細緻規則", + "rulesHint": "依工具輸入比對,最後符合的規則優先,因此請把寬鬆的模式寫在前面。* 比對任意多個字元,? 精確比對一個字元,開頭的 ~ 會展開為主目錄。", + "noRules": "尚無細緻規則。", + "addRule": "新增規則", + "deleteRule": "刪除規則 {pattern}", + "duplicateRule": "此模式已存在。", + "blankRule": "規則必須有模式;如需刪除請點擊垃圾桶圖示。", + "customKeys": "檔案中的其他權限鍵", + "customKeyHint": "並非 OpenCode 內建工具,將原樣保留。", + "keys": { + "bash": "執行 shell 指令,依解析後的指令比對", + "edit": "所有檔案修改:edit、write 與 patch", + "read": "讀取檔案,依檔案路徑比對", + "external_directory": "存取專案工作目錄之外的路徑", + "task": "啟動子代理,依子代理類型比對", + "skill": "載入技能,依技能名稱比對", + "glob": "尋找檔案,依萬用字元模式比對", + "grep": "搜尋檔案內容,依模式比對", + "list": "列出目錄內容", + "webfetch": "擷取 URL", + "websearch": "網頁搜尋", + "lsp": "執行 LSP 查詢", + "todowrite": "寫入待辦清單", + "question": "向你提問", + "doom_loop": "同一呼叫以相同輸入重複 3 次時觸發" + } + } + }, + "openClaw": { + "gatewayConfig": "Gateway 配置", + "gatewayDescription": "配置 OpenClaw Gateway 連線資訊。支援本地或遠端 Gateway。", + "gatewayUrlHint": "留空則使用 openclaw 本地配置的 gateway.remote.url。", + "gatewayTokenPlaceholder": "Gateway 認證 Token", + "gatewayTokenHint": "建議使用 token-file 取代明文 Token,可透過 openclaw 命令列配置。", + "sessionKeyHint": "可選。指定 Gateway Session Key,留空則自動分配隔離會話。" + }, + "hermes": { + "configManagement": "Hermes 配置", + "configDescription": "Hermes 在 ~/.hermes/.env 中管理自己的憑證,在 ~/.hermes/config.yaml 中管理設定。選擇一個供應商,然後設定 API 金鑰與模型——codeg 會替你寫入這兩個檔案。", + "providerLabel": "供應商", + "providerHint": "供應商決定 Hermes 使用哪個 API 金鑰變數與 model.provider。OAuth 供應商透過下方的終端機設定進行設定。", + "groupApiKey": "API 金鑰供應商", + "groupOauth": "OAuth 供應商", + "groupAws": "AWS", + "apiKeyHint": "儲存到 ~/.hermes/.env。它絕不會被注入行程——Hermes 會從自己的設定中讀取它。", + "modelName": "模型", + "oauthHint": "此供應商使用 OAuth。請執行下方的設定流程,在終端機中完成驗證。", + "awsHint": "Bedrock 使用你的 AWS 憑證(環境變數或共用設定)。請在上方填寫模型 ID,並在系統環境中設定 AWS 存取權限。", + "unsupportedProvider": "此供應商無法透過結構化欄位編輯。請使用下方的 config.yaml 原始編輯器或終端機引導設定。", + "setupTitle": "自管理設定", + "setupHint": "Hermes 的互動式設定需要終端機。可在下方啟動,或複製指令自行執行。", + "runSetup": "執行 Hermes 設定", + "configureModel": "設定模型", + "openConfigFolder": "開啟 ~/.hermes", + "copyCommand": "複製指令", + "commandCopied": "指令已複製到剪貼簿", + "advancedTitle": "進階:編輯 config.yaml", + "rawConfigHint": "直接編輯 ~/.hermes/config.yaml。在此儲存將原樣覆寫該檔案。", + "saveRawConfig": "儲存 config.yaml" + }, + "codebuddy": { + "configManagement": "CodeBuddy 設定", + "configDescription": "CodeBuddy 使用 API Key 進行驗證。中國版還必須將環境設為「中國版(internal)」;iOA 版使用「iOA」;海外版則不設定。", + "apiKeyLabel": "API Key", + "apiKeyHint": "將作為此智能體的 CODEBUDDY_API_KEY 儲存。也可以在終端機用 CodeBuddy CLI 登入。", + "apiKeyHintSelfHosted": "將作為此智能體的 CODEBUDDY_API_KEY 儲存。請使用你的私有化部署簽發的金鑰。", + "environmentLabel": "環境", + "environmentHint": "設定 CODEBUDDY_INTERNET_ENVIRONMENT。中國大陸必須使用「中國版(internal)」;海外版則不設定。", + "envOverseas": "海外版(預設)", + "envChina": "中國版(internal)", + "envIoa": "iOA", + "envSelfHosted": "私有化部署", + "baseUrlLabel": "私有化部署位址", + "baseUrlPlaceholder": "https://codebuddy.your-company.com", + "baseUrlHint": "儲存為 CODEBUDDY_BASE_URL,將 CodeBuddy 指向你的私有端點。私有化部署不設定網路環境(CODEBUDDY_INTERNET_ENVIRONMENT)。", + "baseUrlInvalid": "請輸入合法的 http(s) 位址。", + "loginHint": "沒有 API Key?也可以在終端機執行「codebuddy」用騰訊雲帳號登入。" + }, + "kimiCode": { + "configManagement": "Kimi Code 設定", + "configDescription": "`kimi acp` 只認已儲存的登入權杖,所以 codeg 會在 ~/.kimi-code/config.toml 寫入受管供應商,並在本機植入一個門控權杖——推論仍然走你自己的 Key。", + "statusUnconfigured": "尚未設定", + "statusDirty": "有未儲存的變更", + "summaryLabel": "生效設定", + "gateReadyApiKey": "API Key 已寫入 config.toml", + "gateReadyLogin": "已透過 Kimi 帳號登入", + "revealConfig": "在資料夾中顯示", + "envOverrideWarning": "偵測到 {keys},其優先權高於 config.toml。在此儲存會自動清除它。", + "authModeLabel": "驗證方式", + "authModeApiKey": "API Key", + "authModeLogin": "Kimi 帳號登入(訂閱)", + "authModeApiKeyHint": "在 config.toml 寫入受管供應商,並植入門控權杖以便工作階段能夠開啟。", + "loginHint": "在終端機執行 `kimi login`,用 Kimi 訂閱帳號登入。codeg 不儲存任何憑證,沿用 Kimi 自己的登入。在此儲存會移除 codeg 的 API Key 門控權杖。", + "credentialTitle": "憑證", + "interfaceTypeLabel": "供應商類型", + "interfaceTypeHint": "Kimi 使用的供應商協定(config.toml 的 `type`)。Moonshot / platform.kimi.com 的 Key 請選「Kimi / Moonshot」。", + "endpointLabel": "接入點", + "endpointCustom": "自訂(OpenAI 相容)", + "endpointHint": "國際 = api.moonshot.ai;中國(platform.kimi.com 的 Key)= api.moonshot.cn。自訂可指向任意 OpenAI 相容端點。", + "regionInternational": "國際(api.moonshot.ai)", + "regionChina": "中國(api.moonshot.cn)", + "baseUrlLabel": "Base URL", + "baseUrlHint": "留空則使用供應商 SDK 預設值。", + "apiKeyLabel": "API Key", + "apiKeyHint": "寫入 ~/.kimi-code/config.toml 並用於推論。來自 platform.kimi.com 或 platform.kimi.ai。", + "vertexProjectLabel": "GCP 專案(GOOGLE_CLOUD_PROJECT)", + "vertexLocationLabel": "GCP 區域(GOOGLE_CLOUD_LOCATION)", + "vertexHint": "Vertex AI 使用 Google 應用程式預設憑證——執行 `gcloud auth application-default login`(不需 API Key)。", + "modelTitle": "模型", + "modelLabel": "模型", + "modelHint": "寫入 config.toml 的模型 id。點「測試並取得模型」可查看你的 Key 實際能存取哪些模型。", + "maxContextLabel": "最大上下文長度", + "maxContextHint": "Kimi 的設定 schema 要求必填:缺少會讓 Kimi 丟棄整個模型區塊,導致每次對話都沒有回覆。預設 262144。", + "fetchModels": "測試並取得模型", + "fetchModelsOk": "Key 可用——共 {count} 個模型", + "fetchModelsEmpty": "Key 可用,但未回傳任何模型", + "fetchModelsFailed": "測試失敗", + "fetchModelsNeedsKey": "請先填寫 API Key 和接入點", + "modelNotInList": "該模型不在你的 Key 可存取清單中,Kimi 會回報「模型不存在」。", + "reasoningTitle": "推理", + "reasoningEnableLabel": "啟用", + "reasoningDescription": "只有當模型宣告了推理能力,Kimi 才會在輸入框顯示「Thinking」選擇器,所以這裡由 codeg 寫入該宣告。對新建工作階段生效。", + "effortsLabel": "可選檔位", + "effortsHint": "這些會成為輸入框「Thinking」選擇器裡的檔位。Kimi 會把檔位原樣轉傳給供應商,請選你的模型能接受的值。", + "effortsEmptyHint": "一個檔位都不選時,輸入框只會退化成 Off / On 兩檔開關。", + "effortsCustomPlaceholder": "新增其他檔位", + "effortsAdd": "新增", + "defaultEffortLabel": "預設檔位", + "defaultEffortAuto": "由 Kimi 決定", + "alwaysThinkingLabel": "模型始終推理——從選擇器中移除 Off 檔", + "fixErrorsFirst": "請先修正標紅的欄位", + "errorModelRequired": "模型為必填欄位", + "errorMaxContextRequired": "最大上下文長度為必填欄位", + "errorMaxContextInvalid": "必須是正整數", + "errorApiKeyRequired": "API Key 為必填欄位", + "errorApiKeyInvalid": "API Key 不能包含換行", + "errorBaseUrlRequired": "Base URL 為必填欄位", + "errorBaseUrlInvalid": "必須以 http:// 或 https:// 開頭", + "errorVertexProjectRequired": "GCP 專案為必填欄位", + "errorDefaultEffortUnlisted": "必須是上面已選取的檔位之一", + "advancedTitle": "進階", + "authTypeLabel": "憑證寫入位置", + "authTypeApiKey": "內聯 api_key", + "authTypeEnv": "供應商 env 子表", + "authTypeHint": "API Key 在 config.toml 中的寫入位置。", + "rawEditorLabel": "直接編輯 config.toml", + "rawEditorWarning": "在此儲存會按原文覆寫整個檔案,取代掉上方的結構化設定。", + "rawEditorPlaceholder": "[providers.codeg]\ntype = \"kimi\"\nbase_url = \"https://api.moonshot.cn/v1\"\napi_key = \"sk-...\"" + }, + "authModeOfficialSubscription": "官網訂閱", + "authModeCustomEndpoint": "自定義介面", + "authModeCustomEndpointHint": "手動配置 API URL 和 API Key 連接自定義介面。", + "authModeModelProvider": "模型供應商", + "modelProvider": "模型供應商", + "modelProviderHint": "使用已配置的模型供應商的 API URL、API Key 和模型。", + "selectModelProvider": "選擇模型供應商", + "noModelProviderAvailable": "該代理未配置模型供應商。請前往模型供應商設定添加。", + "claude": { + "authMode": "認證方式", + "officialSubscription": "官方訂閱", + "officialSubscriptionHint": "使用 Anthropic 官方訂閱,無需 API Key。", + "mainModel": "主模型", + "reasoningModel": "推理模型(thinking)", + "haikuDefaultModel": "Haiku 預設模型", + "sonnetDefaultModel": "Sonnet 預設模型", + "opusDefaultModel": "Opus 預設模型", + "customModelOption": "自訂模型 ID", + "customModelOptionName": "自訂模型名稱", + "customModelOptionDescription": "自訂模型描述", + "customModelOptionHint": "在 Claude 模型選擇器中新增一個自訂項目(例如透過自訂閘道/代理提供的模型)。名稱與描述為選填的顯示資訊。", + "effortLevel": "推理等級", + "effortLevelDefault": "預設等級", + "effortLevel_low": "低", + "effortLevel_medium": "中", + "effortLevel_high": "高", + "effortLevel_xhigh": "超高", + "sendAttributionHeader": "向介面傳送歸屬/計費識別碼", + "sendAttributionHeaderAria": "向介面傳送 Claude Code 歸屬/計費識別碼", + "disableNonessentialTraffic": "停用遙測或多餘的網路請求", + "disableNonessentialTrafficAria": "停用 Claude Code 遙測或多餘的網路請求" + }, + "dialogs": { + "confirmDeleteProvider": "確認刪除 Provider {providerId}?", + "confirmDeleteProviderDescription": "將同步更新 OpenCode 配置與認證 JSON 檔案,刪除後不可恢復。", + "confirmUninstall": "確認卸載 {name}?", + "confirmUninstallDescription": "這會移除本地安裝版本,之後可隨時重新安裝。", + "customInstallTitle": "自訂安裝 {name}", + "customInstallDescription": "輸入要安裝的版本號。將重新安裝並替換目前已安裝的版本。", + "customInstallVersionLabel": "版本號", + "customInstallInvalid": "請輸入有效的版本號,例如 1.2.3。", + "customInstallSubmit": "安裝" + }, + "errors": { + "windowsFileLocked": "{name} 的程式檔案正被執行中的工作階段佔用,Windows 下無法替換。請先關閉所有 {name} 工作階段後重試。", + "nativeJsonMustBeObject": "原生 JSON 配置必須是物件", + "nativeJsonInvalid": "原生 JSON 配置格式錯誤:{message}", + "openCodeAuthMustBeObject": "OpenCode auth.json 必須是 JSON 物件", + "openCodeAuthInvalid": "OpenCode auth.json 格式錯誤:{message}", + "authMustBeObject": "auth.json 必須是 JSON 物件", + "authInvalid": "auth.json 格式錯誤:{message}", + "providerIdPattern": "Provider ID 僅支援字母、數字、底線、點與中劃線", + "providerExists": "Provider {providerId} 已存在", + "modelIdPattern": "模型 ID 僅支援字母、數字、底線、點、冒號與中劃線", + "modelExists": "Model {modelId} 已存在" + }, + "warnings": { + "nativeJsonRecoveredStructured": "原生 JSON 配置格式無效,已重置為結構化配置", + "nativeJsonRecoveredOpenCode": "原生 JSON 配置格式無效,已重置為 OpenCode 結構化配置", + "openCodeAuthRecovered": "OpenCode auth.json 格式無效,已重置為預設配置", + "authRecoveredStructured": "auth.json 格式無效,已重置為結構化配置" + }, + "toasts": { + "agentActionCompleted": "{name}{action}完成", + "agentActionFailed": "{name}{action}失敗", + "localVersion": "本地版本:{version}", + "installCompletedVersionLater": "安裝完成,版本將在下一次檢測時更新", + "uninstallCompleted": "{name}卸載完成", + "uninstallFailed": "{name}卸載失敗", + "localVersionRemoved": "本地版本已移除", + "saveAgentOrderFailed": "儲存 Agent 排序失敗", + "saveAgentSwitchFailed": "儲存 Agent 開關失敗", + "saveEnvFailed": "儲存環境變數失敗", + "grokSaved": "Grok 設定已儲存", + "saveGrokNativeFailed": "儲存 Grok 原生設定失敗", + "saveGrokApiKeyFailed": "設定已儲存,但 API Key 未能儲存", + "cursorSaved": "Cursor 設定已儲存", + "saveCursorConfigFailed": "儲存 Cursor 設定失敗", + "codexSaved": "Codex 配置已儲存", + "saveCodexNativeFailed": "儲存 Codex 原生配置失敗", + "geminiSaved": "Gemini 配置已儲存", + "saveGeminiFailed": "儲存 Gemini 配置失敗", + "providerDeleted": "Provider {providerId} 已刪除", + "providerDeleteFailed": "刪除 Provider {providerId} 失敗", + "providerSaved": "Provider {providerId} 儲存成功", + "saveProviderFailed": "儲存 Provider {providerId} 失敗", + "openCodeConfigSynced": "OpenCode 配置與認證 JSON 已同步儲存。", + "openCodeSaved": "OpenCode 配置已儲存", + "saveOpenCodeFailed": "儲存 OpenCode 配置失敗", + "openClawSaved": "OpenClaw 配置已儲存", + "saveOpenClawFailed": "儲存 OpenClaw 配置失敗", + "configSaved": "配置已儲存", + "configSavedHint": "已有會話需要重新打開才能生效", + "saveConfigManagementFailed": "儲存配置管理失敗", + "clineSaved": "Cline 配置已儲存", + "saveClineFailed": "儲存 Cline 配置失敗", + "hermesSaved": "Hermes 配置已儲存", + "saveHermesFailed": "儲存 Hermes 配置失敗", + "codeBuddySaved": "CodeBuddy 設定已儲存", + "saveCodeBuddyFailed": "儲存 CodeBuddy 設定失敗", + "kimiCodeSaved": "Kimi Code 設定已儲存", + "saveKimiCodeFailed": "儲存 Kimi Code 設定失敗", + "deepseekSaved": "DeepSeek 設定已儲存", + "saveDeepSeekFailed": "儲存 DeepSeek 設定失敗", + "modelProviderRequired": "請先選擇一個模型供應商再儲存。", + "affectedRunningSessions": "{count} 個進行中的工作階段需重新連線以套用變更", + "providerConnected": "已連接 {providerId}", + "connectFailed": "連接 {providerId} 失敗", + "providerDisconnected": "已中斷 {providerId}", + "disconnectFailed": "中斷 {providerId} 失敗", + "catalogRefreshed": "目錄已重新整理——{count} 個 provider", + "catalogRefreshFailed": "重新整理目錄失敗", + "piSaved": "Pi 設定已儲存", + "savePiFailed": "儲存 Pi 設定失敗", + "piRuntimeSaved": "Pi 執行環境已儲存", + "savePiRuntimeFailed": "儲存 Pi 執行環境失敗", + "piBinaryInstalled": "pi 已安裝", + "piBinaryInstallFailed": "pi 安裝失敗", + "piBinaryUninstalled": "pi 已解除安裝", + "piBinaryUninstallFailed": "pi 解除安裝失敗", + "savePiTrustFailed": "儲存工作區信任失敗" + }, + "version": { + "statusLabel": "版本狀態", + "notInstalled": "未安裝", + "remoteLocal": "遠端:{remoteVersion} · 本地:{localVersion}", + "localOnly": "本機:{localVersion}", + "localInstalled": "{versionText}。已安裝。", + "platformUnsupported": "{versionText}。目前平台不支援該 Agent。", + "uvxNotReady": "{versionText}。uv 執行階段未安裝——請在下方 uv 預檢項中安裝後再使用該 Agent。", + "clickInstall": "{versionText}。請點擊右側安裝。", + "localUnrecognized": "{versionText}。本地版本無法識別,可嘗試升級覆蓋安裝。", + "upgradeAvailable": "{versionText}。發現可升級版本。", + "remoteUnavailable": "{versionText}。遠端版本暫不可用。", + "latest": "{versionText}。已是最新版本。" + }, + "adapter": { + "label": "ACP 轉接器", + "badge": "ACP 轉接器", + "badgeHint": "Codeg 為此智能體安裝的是 ACP 轉接器套件,而不是廠商 CLI —— 兩者各自獨立,設定共用。", + "learnMore": "了解詳情", + "missingWithNative": "已偵測到你本機的 {nativeLabel}:{nativePath}。Codeg 透過 ACP 協定驅動智能體,而該 CLI 本身不支援 ACP,所以 Codeg 需要獨立的轉接器套件 {adapterPackage}(由 Agent Client Protocol 專案維護,最初由 Zed 團隊發起)。它自帶執行環境,不會修改或取代你的 {nativeCmd} 指令,讀取的也是同一個 {configDir} —— 既有的登入與設定可直接沿用。點擊下方安裝即可。", + "missing": "Codeg 透過 ACP 協定驅動智能體,而 {nativeLabel} 本身不支援 ACP,所以 Codeg 需要獨立的轉接器套件 {adapterPackage}(由 Agent Client Protocol 專案維護,最初由 Zed 團隊發起)。它自帶執行環境,因此不必先安裝 {nativeCmd} CLI;若你已經安裝,兩者可以並存,並共用 {configDir} 中的登入與設定。點擊下方安裝即可。", + "readyWithNative": "轉接器 {adapterCmd} 已安裝 —— Codeg 啟動的是它,而不是你本機的 {nativeCmd}({nativePath})。兩者是各自獨立的套件,可以並存,且都讀取 {configDir},登入與設定共用。", + "ready": "轉接器 {adapterCmd} 已安裝 —— Codeg 啟動的就是它。它自帶執行環境,所以不需要另外安裝 {nativeLabel};即使日後你安裝了,兩者也能並存並共用 {configDir}。" + }, + "cline": { + "configDescription": "配置 Cline API 提供商和憑證。設定將儲存到 ~/.cline/data/。" + }, + "opencodePlugins": { + "title": "OpenCode 外掛", + "declared": "已宣告的外掛", + "noPlugins": "opencode.json 中未宣告任何外掛", + "status": { + "installed": "已安裝", + "missing": "未安裝" + }, + "installAll": "安裝全部缺失外掛", + "pinVersions": "固定 @latest 版本", + "install": "安裝", + "uninstall": "解除安裝", + "refresh": "重新整理", + "success": "所有外掛安裝成功", + "failed": "外掛操作失敗" + }, + "pi": { + "configManagement": "Pi 設定", + "configDescription": "Pi 透過模型提供方的 API Key 驗證。Key 寫入 ~/.pi/agent/auth.json,模型選擇寫入 settings.json。", + "providerLabel": "提供方", + "modelLabel": "模型", + "thinkingLabel": "思考", + "thinking": { + "off": "關閉", + "low": "低", + "medium": "中", + "high": "高", + "minimal": "極低", + "xhigh": "極高" + }, + "apiKeyLabel": "API Key", + "apiKeyHint": "為所選提供方寫入 ~/.pi/agent/auth.json。", + "apiKeySetPlaceholder": "•••••• (已儲存,留空則保持不變)", + "saveConfig": "儲存 Pi 設定", + "providerModelRequired": "提供方與模型為必填", + "runtimeTitle": "執行環境", + "runtimeDescription": "選擇執行哪個 pi。使用預設,或指向你自己的 pi 建置。", + "modeDefault": "預設 pi", + "modeDefaultHint": "使用內建 pi-acp 轉接器拉起 PATH 上的 pi。 安裝 pi:npm install -g @earendil-works/pi-coding-agent", + "modeCustom": "自訂 pi", + "modeCustomHint": "執行你自己的 pi 建置、安裝或包裝腳本。", + "commandLabel": "pi 命令或路徑", + "commandHint": "絕對路徑、PATH 上的命令名,或包裝腳本(如 monorepo 的 ./pi-test.sh)。", + "commandNotFound": "找不到命令", + "validate": "驗證", + "advanced": "進階", + "configDirLabel": "設定目錄 (PI_CODING_AGENT_DIR)", + "sessionDirLabel": "工作階段目錄 (PI_CODING_AGENT_SESSION_DIR)", + "flagsHint": "pi-acp 不會轉發自訂 pi 參數(--approve、-e 等)——用腳本包裝 pi 並將命令指向它。", + "customIncomplete": "請輸入 pi 命令以儲存", + "saveRuntime": "儲存執行環境", + "providerPlaceholder": "選擇供應方", + "customProvider": "自訂供應方…", + "providerIdLabel": "供應方 ID", + "apiProtocolLabel": "API 協定", + "baseUrlLabel": "介接位址(Base URL)", + "customProviderHint": "在 ~/.pi/agent/models.json 中依你的介接位址定義一個供應方。多數自架或代理服務使用 openai-completions。", + "baseUrlRequired": "介接位址(Base URL)為必填", + "binaryTitle": "pi 二進位 (pi-coding-agent)", + "binaryDescription": "pi-acp 會執行此 pi 二進位。可在此安裝,或在下方指向你自己的組建。", + "binaryInstalled": "已安裝", + "binaryMissing": "未安裝", + "binaryChecking": "偵測中…", + "installBinary": "安裝 pi", + "installing": "安裝中…", + "recheck": "重新偵測", + "configDirSkillsNote": "設定自訂組態目錄後,設定頁中管理的技能、專家與辦公工具將不會套用至該 pi;請直接在該目錄中管理其技能。", + "projectTrustTitle": "專案信任", + "projectTrustDescription": "你允許 pi 從中載入專案檔案的目錄。被信任的目錄會讓該儲存庫的 .pi/extensions 在 pi 啟動時執行程式碼,且對其下所有子目錄同樣生效,你在終端機執行 pi 時也會沿用。", + "projectTrustLoading": "載入中…", + "projectTrustEmpty": "尚未對任何目錄做出決定。", + "projectTrustTrusted": "已信任", + "projectTrustDenied": "不信任", + "projectTrustRevoke": "撤銷", + "reasoningTitle": "推理", + "reasoningEnableLabel": "啟用", + "reasoningDescription": "只有模型宣告了推理能力,pi 才會傳送推理強度——未宣告的模型所有等級都會被壓回 Off,所以輸入框裡的選擇器一改就彈回。這裡寫入 models.json 中該模型的項目。", + "levelsLabel": "可選等級", + "levelsHint": "這些會成為輸入框推理選擇器裡的等級。請選你的端點能接受的值;不在這裡的等級 pi 一律拒絕。", + "levelsEmptyError": "至少選一個等級——一個都不選時 pi 只會退回 Off。", + "wireValuesTitle": "進階:送給供應商的值", + "wireValuesHint": "留空表示原樣送出等級名稱。端點需要別的寫法時才填——Google 系需要 LOW / HIGH。", + "defaultLevelUnlisted": "該等級不在上面的可選清單裡——pi 會把它壓下來。" + }, + "addCustomAgent": "新增自訂智慧體", + "addCustomAgentHint": "接入任何相容 ACP 的智慧體。可從公開 ACP 註冊表中選擇,或直接貼上其註冊表資訊。", + "customAgentFromRegistry": "ACP 註冊表", + "customAgentManual": "手動填寫", + "customAgentSearchPlaceholder": "搜尋智慧體…", + "customAgentLoadingCatalog": "正在載入 ACP 註冊表…", + "customAgentRetry": "重試", + "customAgentNoResults": "沒有符合的智慧體", + "customAgentAdd": "新增", + "customAgentAlreadyAdded": "已新增", + "customAgentUnsupportedPlatform": "目前平台沒有可用的建置", + "customAgentAdded": "已新增 {name}", + "customAgentIdLabel": "註冊表 ID", + "customAgentNameLabel": "顯示名稱", + "customAgentVersionLabel": "版本", + "customAgentSpecLabel": "散發資訊(JSON)", + "customAgentSpecHint": "與 ACP 註冊表 distribution 物件同構:支援 npx、uvx、binary 三種通道,也可整筆貼上註冊表條目。npx/uvx 的 cmd 為套件安裝的可執行命令名稱,預設按套件名稱推導,與套件名稱不同時需填寫。binary 按平台鍵區分(本機為 {platform}),cmd 為壓縮檔內啟動路徑,sha256 可選用於驗證下載。", + "customAgentTemplateLabel": "範本", + "customAgentKindLabel": "啟動方式", + "customAgentInvalidJson": "不是合法的 JSON", + "customAgentNoDistribution": "找不到 npx、uvx 或 binary 散發方式", + "customAgentCancel": "取消", + "customAgentSave": "新增智慧體", + "customAgentSaveChanges": "儲存變更", + "customAgentEdit": "編輯智慧體", + "customAgentEditHint": "修改名稱、圖示、分發資訊與技能宣告;智慧體 ID 不可修改。", + "customAgentEditNotFound": "找不到自訂智慧體 {id}", + "customAgentSaved": "已儲存 {name}", + "customAgentVersionProbeLabel": "版本查詢命令(可選)", + "customAgentVersionProbeHint": "查詢本機安裝版本的命令;留空時預設執行智慧體命令加 --version。", + "customAgentRemove": "移除智慧體", + "customAgentRemoveHint": "刪除該智慧體定義。既有工作階段的歷史會保留,只是該智慧體無法再啟動。", + "customAgentIconLabel": "圖示(選填)", + "customAgentIconUpload": "上傳", + "customAgentIconReplace": "更換", + "customAgentIconClear": "移除圖示", + "customAgentIconHint": "隨智慧體一併儲存,離線也能顯示。未上傳則使用彩色首字母。", + "customAgentSkillsLabel": "Skills(共享 .agents/skills)", + "customAgentSkillsHint": "聲明該智能體會讀取共享的 .agents/skills 目錄(全域與專案級),並將其加入所有技能矩陣。連結到共享目錄的技能對讀取該目錄的其他智能體同樣可見。", + "customAgentSkillsDirLabel": "專屬技能目錄", + "customAgentSkillsDirHint": "該智慧體自身載入技能的目錄絕對路徑 —— 可與共享目錄並存,也可單獨使用。~ 會展開為主目錄;連結技能時優先放入此目錄。", + "customAgentMcpLabel": "MCP 支援", + "customAgentMcpHint": "工作階段建立時向該智慧體注入 codeg 內建的 codeg-mcp 伴生行程 —— 委派、即時回饋與任務工具都依賴它。若該智慧體不支援 MCP、連線時報錯,請關閉此項;設定會在下次連線時生效。", + "customAgentIconNotAnImage": "請選擇圖片檔案。", + "customAgentIconTooLarge": "圖示需小於 {limit} KB。", + "customAgentIconReadFailed": "無法讀取該圖片。", + "customAgentRemoveConfirm": "確定移除 {name}?既有會話會保留,但該智慧體將無法再啟動。", + "customAgentRemoveWithData": "同時刪除已記錄的會話歷史", + "customAgentRemoved": "已移除 {name}", + "customAgentBadge": "自訂", + "customAgentNotLaunchable": "該智慧體在此環境無法啟動:{reason}" + }, + "SettingsPages": { + "agentsLoading": "載入 Agent 設定中...", + "skillPacksLoading": "正在載入技能包…" + }, + "GeneralSettings": { + "loading": "載入中...", + "sectionTitle": "一般", + "sectionDescription": "集中管理預設終端機、渲染加速以及多智能體協同等通用偏好。", + "terminalTitle": "預設終端", + "terminalDescription": "選擇從終端列或檔案樹開啟新終端分頁時使用的 Shell。智慧代理請求 codeg 代為執行整條命令列時也會使用它。", + "terminalSystemDefault": "系統預設", + "terminalPowerShell7": "PowerShell 7 (pwsh)", + "terminalWindowsPowerShell": "Windows PowerShell", + "terminalCmd": "命令提示字元 (cmd)", + "terminalSaveFailed": "儲存終端設定失敗:{message}", + "terminalShellCustom": "自訂路徑", + "terminalShellCustomPath": "Shell 路徑", + "terminalShellCustomPlaceholder": "/usr/local/bin/fish", + "terminalShellCustomSave": "儲存", + "terminalShellCustomHint": "支援絕對路徑,或 PATH 中可解析的命令名。", + "terminalShellNotInstalled": "未安裝", + "terminalShellNotFoundWarning": "目前主機上不存在此路徑。", + "terminalCurrentShell": "目前使用:{path}", + "renderingDescription": "若應用出現黑屏或渲染異常(常見於 AMD 顯示卡或部分 Intel 內顯),可關閉硬體加速。僅 Windows 桌面端生效。", + "disableHardwareAcceleration": "停用硬體加速", + "renderingSaveFailed": "渲染設定儲存失敗:{message}", + "restartRequired": "已儲存,需重新啟動應用程式才會生效。", + "restartNow": "立即重新啟動", + "restartFailed": "重新啟動失敗:{message}", + "loadFailed": "載入失敗:{message}" + }, + "LoginPage": { + "documentTitle": "登入 - codeg", + "brand": "Codeg", + "subtitle": "輸入存取 Token 以連接到桌面端", + "tokenPlaceholder": "Access Token", + "connect": "連接", + "connecting": "連接中...", + "helpText": "Token 可在桌面端 設定 → Web 服務 中取得", + "invalidToken": "Token 無效,請檢查後重試", + "connectionFailed": "連接失敗 (HTTP {status})", + "networkError": "無法連接到伺服器" + }, + "CommitPage": { + "title": "提交程式碼", + "invalidFolderId": "無效的 folderId", + "loadingRepo": "正在載入倉庫..." + }, + "MergePage": { + "title": "解決衝突", + "invalidFolderId": "無效的 folderId", + "loadingRepo": "正在載入倉庫...", + "localVersion": "本地(我們的)", + "result": "結果", + "remoteVersion": "遠端(他們的)", + "acceptLocal": "採用本地", + "acceptRemote": "採用遠端", + "markResolved": "標記已解決", + "abortMerge": "中止", + "completeMerge": "完成合併", + "unresolvedConflicts": "檔案中仍有未解決的衝突標記", + "fileResolved": "檔案已解決", + "allResolved": "所有衝突已解決", + "conflictFiles": "衝突檔案", + "loadingFile": "正在載入檔案...", + "preparingMerge": "正在準備合併...", + "selectFile": "選擇一個檔案進行解決", + "noConflicts": "無衝突檔案", + "skipFile": "跳過", + "abortSuccess": "操作已中止", + "applyAllNonConflicting": "套用所有非衝突變更", + "applyLeftNonConflicting": "套用本地", + "applyRightNonConflicting": "套用遠端" + }, + "ImportSessions": { + "title": "匯入本機工作階段", + "scanningTitle": "正在掃描本機智慧代理工作階段…", + "scanningHint": "正在遍歷各智慧代理的本機工作階段儲存,歷史較多時可能需要一些時間。已匯入的工作階段會順帶重新整理。", + "scanFailed": "掃描失敗", + "retry": "重試", + "rescan": "重新掃描", + "empty": "未發現本機工作階段", + "emptyHint": "本機未找到任何智慧代理的工作階段儲存。", + "noMatches": "沒有符合目前篩選的工作階段", + "searchPlaceholder": "搜尋標題或路徑…", + "allAgents": "全部智慧代理", + "onlyImportable": "僅顯示可匯入", + "selectAll": "全選", + "clearSelection": "清空", + "expandAll": "全部展開", + "collapseAll": "全部摺疊", + "summaryCounts": "共 {total} 個工作階段 · {importable} 個可匯入 · {folders} 個資料夾", + "noFolderSkipped": "已略過 {count} 個無專案目錄的工作階段", + "folderNew": "新建", + "folderCounts": "可匯入 {importable}/{total}", + "toggleFolderAria": "選擇 {name} 中的全部可匯入工作階段", + "toggleSessionAria": "選擇工作階段 {title}", + "statusImported": "已匯入", + "statusDeleted": "已刪除", + "untitled": "未命名工作階段", + "messageCount": "{count} 則訊息", + "selectedCount": "已選 {count} 個", + "importSelected": "匯入所選", + "importing": "匯入中…", + "close": "關閉", + "doneTitle": "匯入完成", + "doneImported": "新匯入", + "doneUpdated": "已重新整理", + "doneSkipped": "已略過", + "doneCreatedFolders": "新建資料夾", + "doneNotFound": "未找到", + "doneFailed": "失敗", + "continueImport": "繼續匯入", + "toasts": { + "importFailed": "匯入失敗:{message}" + } + }, + "Folder": { + "workspaceStatus": { + "degradedTitle": "即時更新不可用", + "degradedHint": "監聽器啟動失敗(如目錄無讀取權限)。請手動重新整理以取得最新變更。", + "retry": "重試", + "retrying": "重試中..." + }, + "common": { + "all": "全部", + "cancel": "取消", + "close": "關閉", + "closeOthers": "關閉其它", + "closeAll": "關閉所有", + "confirm": "確認", + "save": "儲存", + "delete": "刪除", + "rename": "重新命名", + "loading": "載入中...", + "refresh": "刷新", + "refreshing": "刷新中...", + "create": "建立", + "createAndSwitch": "建立並切換", + "openFile": "打開檔案", + "viewDiff": "查看差異", + "push": "推送..." + }, + "statusLabels": { + "in_progress": "進行中", + "pending_review": "待複查", + "completed": "已完成", + "cancelled": "已取消" + }, + "sidebar": { + "title": "會話", + "locateActiveConversation": "定位目前會話", + "expandAllGroups": "展開全部分組", + "collapseAllGroups": "折疊全部分組", + "newConversation": "新增會話", + "newConversationShort": "新增", + "newChat": "新增會話", + "search": "搜尋", + "noConversationsFound": "找不到會話。", + "importLocalSessions": "匯入本地會話", + "importing": "匯入中...", + "error": "錯誤:{message}", + "completeAllSessions": "完成全部會話", + "completeAllReviewTitle": "完成全部複查會話?", + "completeAllReviewDescription": "這會將複查中的 {count} 個會話全部標記為已完成。", + "completing": "處理中...", + "toasts": { + "importedSessions": "已匯入 {imported} 個會話,跳過 {skipped} 個", + "importedAndUpdated": "已匯入 {imported} 個會話,更新 {updated} 個標題,跳過 {skipped} 個", + "updatedTitles": "已更新 {updated} 個標題,跳過 {skipped} 個", + "noNewSessionsFound": "沒有新會話(已跳過 {skipped} 個)", + "importFailed": "匯入失敗:{message}", + "reviewCompleted": "已將 {count} 個複查會話標記為已完成", + "completeReviewFailed": "批次完成複查會話失敗:{message}", + "folderOpened": "已開啟資料夾 {name}", + "folderRemoved": "已移除資料夾 {name}", + "openFolderFailed": "開啟資料夾失敗", + "removeFolderFailed": "移除資料夾失敗:{message}", + "reorderFoldersFailed": "重新排序資料夾失敗:{message}", + "changeFolderColorFailed": "修改顏色失敗:{message}", + "setFolderAliasFailed": "設定別名失敗:{message}", + "changeFolderDefaultAgentFailed": "設定預設智能體失敗:{message}" + }, + "statsLabel": "{folders} 個資料夾 · {convos} 個對話", + "reorderHandle": "拖拽排序", + "openFolder": "開啟資料夾", + "searchPlaceholder": "搜尋對話...", + "viewOptions": "顯示選項", + "showCompleted": "顯示已完成對話", + "showWorktrees": "顯示工作樹資料夾", + "showRecent": "顯示「最近」分組", + "moreOptions": "更多選項", + "sortBy": "排序方式", + "sortByCreatedAt": "按建立時間排序", + "sortByUpdatedAt": "按更新時間排序", + "sectionOrder": "區域順序", + "sectionOrderMoveUp": "上移", + "sectionOrderMoveDown": "下移", + "sectionOrderItemLabel": "{name} — 第 {position} 位,共 {total} 位", + "statusRunningBadge": "運行中", + "runningCountBadge": "{count} 個會話進行中", + "statusCancelledBadge": "已取消", + "worktreeRemovedBadge": "來源 worktree 已刪除", + "conversationCountUnit": "{count} 條", + "emptyFolderHint": "暫無對話", + "noMatchingConversations": "找不到符合的對話", + "noUnfinishedConversations": "目前沒有未完成的會話,右上角可啟用顯示已完成會話", + "removeFolderConfirmTitle": "從工作區移除此資料夾?", + "removeFolderConfirmDescription": "從工作區移除 \"{name}\"?相關分頁與終端機將會關閉。", + "folderHeaderMenu": { + "manageConversations": "會話管理…", + "manageLinks": "已連結的資料夾", + "changeColor": "修改顏色", + "useThemeColor": "使用設定主題", + "setDefaultAgent": "設定預設智能體", + "defaultAgentNone": "不設定(使用全域預設)", + "agentUnavailableSuffix": "(不可用)", + "loadingAgents": "正在載入代理…", + "setAlias": "設定別名…", + "setAliasTitle": "設定資料夾別名", + "setAliasPlaceholder": "輸入別名(留空清除)", + "setAliasSave": "儲存", + "setAliasCancel": "取消", + "removeFromWorkspace": "從工作區移除" + }, + "manageConversations": { + "title": "會話管理", + "searchPlaceholder": "依標題搜尋…", + "agentFilterAll": "全部智能體", + "statusFilterAll": "全部狀態", + "folderFilterAll": "全部資料夾", + "branchFilterAll": "全部分支", + "branchNone": "無分支", + "branchSearchPlaceholder": "搜尋分支…", + "noMatchingBranches": "無匹配分支", + "selectAllVisible": "全選", + "deselectAll": "取消全選", + "selectedCount": "已選 {count} 筆", + "matchedCount": "符合 {count} 筆", + "untitledConversation": "未命名會話", + "setStatus": "設為狀態…", + "deleteSelected": "刪除", + "noConversations": "此資料夾暫無會話。", + "noConversationsWorkspace": "工作區暫無會話。", + "noMatchingConversations": "沒有符合過濾條件的會話。", + "confirmDeleteTitle": "刪除 {count} 個會話?", + "confirmDeleteDescription": "此操作無法復原。", + "toastDeleted": "已刪除 {count} 個會話", + "toastStatusUpdated": "已更新 {count} 個會話的狀態", + "toastOpFailed": "操作失敗:{message}" + }, + "sectionPinned": "已置頂", + "sectionFolders": "資料夾", + "sectionChats": "聊天", + "sectionRecent": "最近", + "noChats": "沒有聊天", + "noRecent": "暫無最近對話", + "showMoreRecent": "顯示更多({count})", + "noFolders": "沒有開啟的資料夾", + "newChatAction": "新增聊天", + "automations": "自動化", + "tasks": "待辦任務", + "loadingSubsessions": "正在載入子會話…" + }, + "conversation": { + "reloadFailed": "會話重新載入失敗:{message}", + "reloaded": "目前會話已重新載入", + "reload": "重新載入", + "activeConversationIndicator": "目前啟用的會話", + "newConversation": "新增會話", + "closeConversation": "關閉會話", + "copyText": "複製文字", + "copyTextSuccess": "已複製", + "copyTextFailed": "複製失敗", + "forkSession": "分叉會話", + "forkSessionSuccess": "會話分叉成功", + "forkSessionFailed": "會話分叉失敗:{error}", + "exportConversation": "匯出對話", + "exportImage": "圖片", + "exportMarkdown": "Markdown", + "exportHtml": "HTML", + "exportSuccess": "對話已匯出", + "exportFailed": "匯出失敗", + "exportImageTooLong": "對話內容過長,不支援匯出為圖片", + "exportLabels": { + "untitledConversation": "未命名對話", + "agent": "代理", + "model": "模型", + "status": "狀態", + "started": "開始時間", + "updated": "更新時間", + "tokens": "令牌統計", + "duration": "時長", + "inputTokens": "輸入", + "outputTokens": "輸出", + "cacheRead": "快取讀取", + "cacheWrite": "快取寫入", + "user": "使用者", + "assistant": "助手", + "system": "系統", + "toolResult": "結果", + "toolError": "錯誤" + }, + "moreActions": "更多操作" + }, + "sessionDetails": { + "menuLabel": "對話詳情", + "noActiveSession": "暫無使用中的對話", + "title": "對話詳情", + "subtitle": "對話中繼資料與 Token 用量", + "fieldTitle": "標題", + "untitled": "未命名對話", + "sessionId": "對話 ID", + "externalId": "擴充 ID", + "agent": "智能體", + "model": "模型", + "status": "狀態", + "gitBranch": "Git 分支", + "parentId": "父對話", + "tokensHeading": "Token 用量", + "totalTokens": "總計", + "inputTokens": "輸入", + "outputTokens": "輸出", + "cacheWrite": "快取寫入", + "cacheRead": "快取讀取", + "contextWindow": "上下文視窗", + "duration": "時長", + "loadingStats": "正在載入 Token 用量…", + "loadFailed": "載入 Token 用量失敗", + "noStats": "尚無用量記錄", + "timestampsHeading": "時間", + "createdAt": "建立時間", + "updatedAt": "更新時間", + "none": "—", + "copyField": "複製{field}", + "copiedField": "已複製{field}" + }, + "conversationCard": { + "untitledConversation": "未命名會話", + "newConversation": "新增會話", + "rename": "重新命名", + "status": "狀態", + "delete": "刪除", + "importLocalSessions": "匯入本地會話", + "importing": "匯入中...", + "renameConversation": "重新命名會話", + "deleteConversationTitle": "刪除會話?", + "deleteConversationDescription": "會刪除「{title}」,此操作無法復原。", + "cancel": "取消", + "save": "儲存", + "pin": "置頂", + "unpin": "取消置頂", + "markCompleted": "標記為已完成", + "reopen": "重新開啟", + "expandSubsessions": "展開子會話", + "collapseSubsessions": "摺疊子會話" + }, + "search": { + "dialogTitle": "搜尋", + "dialogTitleWithFolder": "搜尋 — {name}", + "tabConversations": "會話", + "tabFiles": "檔案", + "placeholder": "搜尋會話...", + "filePlaceholder": "搜尋檔案或目錄...", + "allAgents": "全部", + "searching": "搜尋中...", + "typeToSearch": "輸入關鍵字搜尋會話", + "typeToSearchFiles": "輸入關鍵字搜尋檔案或目錄", + "noResults": "找不到結果。", + "untitledConversation": "未命名會話" + }, + "folderTitleBar": { + "showSidebar": "顯示側邊欄", + "hideSidebar": "隱藏側邊欄", + "toggleTerminal": "切換終端", + "toggleAuxPanel": "切換輔助面板", + "search": "搜尋", + "openSettings": "打開設定", + "backToConversations": "返回會話", + "withShortcut": "{label}({shortcut})" + }, + "statusBar": { + "connection": { + "connected": "已連線", + "connecting": "連線中...", + "prompting": "回應中...", + "error": "連線異常", + "disconnected": "未連線", + "tooltip": "{agent}:{status}", + "tooltipError": "{agent}:{error}", + "title": "智慧體連線", + "triggerAria": "智慧體連線:{status}", + "workingDir": "工作目錄", + "sessionId": "工作階段 ID", + "viewerNote": "已接入其他用戶端擁有的工作階段——重新連線只會重新接入目前檢視。", + "reconnectInterrupts": "重新連線會重啟智慧體,並中斷進行中的工作。", + "reconnect": "重新連線", + "reconnecting": "正在重新連線...", + "reconnectUnavailable": "目前沒有可重新連線的工作階段。" + }, + "tasks": { + "title": "任務" + }, + "alerts": { + "title": "警示", + "empty": "暫無警示資訊", + "details": "詳情" + }, + "stats": { + "conversations": "{count} 個會話", + "openUsage": "檢視會話統計與 Token 用量" + }, + "tokens": { + "contextWindowUsageAria": "上下文視窗使用率", + "contextWindow": "上下文視窗", + "usedMax": "已用 / 上限", + "tokenUsage": "Token 用量", + "input": "輸入", + "output": "輸出", + "cacheRead": "快取讀取", + "cacheWrite": "快取寫入", + "total": "總計" + } + }, + "auxPanel": { + "tabs": { + "files": "檔案", + "changes": "變更", + "commits": "提交" + }, + "noFolderTitle": "尚無開啟的資料夾", + "noFolderHint": "開啟一個資料夾後可在此查看" + }, + "windowControls": { + "minimizeWindow": "最小化視窗", + "minimize": "最小化", + "maximizeWindow": "最大化視窗", + "maximize": "最大化", + "restoreWindow": "還原視窗", + "restore": "還原", + "closeWindow": "關閉視窗", + "close": "關閉" + }, + "tabs": { + "closeConversationTab": "關閉會話分頁", + "close": "關閉", + "closeOthers": "關閉其它", + "splitRight": "向右拆分", + "splitDown": "向下拆分", + "splitAndMoveRight": "拆分並右移", + "splitAndMoveDown": "拆分並下移", + "moveToOppositeGroup": "移動到對側分組", + "moveToGroup": "移動到分組", + "groupLabel": "分組 {index}", + "changeSplitterOrientation": "切換分隔方向", + "unsplit": "取消拆分", + "unsplitAll": "全部取消拆分", + "closeAll": "關閉所有", + "tileDisplay": "平鋪顯示", + "untileDisplay": "取消平鋪" + }, + "fileWorkspace": { + "files": "檔案", + "closeFileTab": "關閉檔案分頁", + "close": "關閉", + "closeOthers": "關閉其它", + "closeAll": "關閉所有", + "preview": "預覽", + "editSource": "編輯原始碼", + "maximize": "最大化", + "restore": "還原", + "emptyDirectory": "空目錄" + }, + "terminal": { + "rename": "重新命名", + "close": "關閉", + "closeOthers": "關閉其它", + "closeAll": "關閉所有", + "hideTerminal": "隱藏終端({shortcut})", + "openFolderFirst": "請先開啟一個資料夾" + }, + "workspaceDialog": { + "title": "開啟資料夾", + "manageTitle": "已連結的資料夾", + "addTargetsTitle": "新增要連結的資料夾", + "pickRootDescription": "選擇這個工作區的主資料夾。", + "linksDescription": "把其他資料夾以子目錄的形式連結進來,代理就能在同一個工作區跨專案工作。", + "addTargetsDescription": "選擇一個或多個資料夾,每個都會成為工作區的一個子目錄。", + "useSystemPicker": "系統選擇器", + "next": "下一步", + "back": "返回", + "done": "完成", + "change": "變更", + "addFolders": "新增資料夾", + "addSelected": "新增", + "addSelectedCount": "新增 {count} 個", + "createCount": "連結 {count} 個資料夾", + "discardPending": "捨棄", + "noLinks": "尚未連結任何資料夾。", + "gitExclude": "不讓連結目錄污染 git 狀態", + "rename": "重新命名", + "unlink": "解除連結", + "repair": "重建連結", + "saveName": "儲存", + "cancelRename": "取消", + "removePending": "移除", + "willAppearAs": "在工作區中顯示為 {name}", + "renamedForDuplicate": "已改名 —— {base} 已被另一個連結佔用", + "renamedForExistingEntry": "已改名 —— 該資料夾中已存在 {base}", + "partiallyCreated": "只成功連結了 {count} 個資料夾", + "openFailed": "開啟資料夾失敗", + "previewFailed": "檢查所選資料夾失敗", + "createFailed": "連結資料夾失敗", + "renameFailed": "重新命名失敗", + "removeFailed": "解除連結失敗", + "repairFailed": "重建連結失敗", + "status": { + "ok": "已連結", + "missing": "連結已從該資料夾中消失", + "conflicted": "該名稱已被其他項目佔用", + "broken": "被連結的資料夾已不存在" + }, + "nameIssue": { + "empty": "請輸入名稱", + "illegalChars": "不能包含 / \\ : * ? \" < > |", + "tooLong": "名稱過長", + "reserved": "該名稱是 Windows 保留名", + "duplicate": "該名稱已被使用" + }, + "rejection": { + "not_found": "找不到該資料夾", + "not_a_directory": "該路徑不是資料夾", + "same_as_root": "這就是工作區資料夾本身", + "ancestor_of_root": "該資料夾包含了目前工作區", + "inside_root": "已在工作區內部", + "already_linked": "已經連結過", + "name_unavailable": "該資料夾已無可用的名稱", + "alreadyLinkedAs": "已作為 {name} 連結" + } + }, + "folderNameDropdown": { + "fallbackFolderName": "資料夾", + "openFolder": "打開資料夾", + "cloneRepository": "複製倉庫", + "projectBoot": "專案啟動器", + "opened": "已打開", + "recentOpen": "最近打開" + }, + "fileWorkspacePanel": { + "addSelectionToChat": "新增選取範圍到對話", + "addToChat": "加入對話", + "addSelectionToChatDone": "已將 {label} 加入對話", + "addFileToChat": "新增檔案到對話", + "toggleWordWrap": "切換自動換行", + "addFileToChatDone": "已將 {label} 加入對話", + "viewDiff": "查看差異", + "openFile": "打開檔案", + "fileCount": "{count} 個檔案", + "openFileOrDiff": "從右側面板打開檔案或差異", + "disk": "磁碟", + "head": "HEAD(目前提交)", + "unsaved": "未儲存", + "workingTree": "工作區", + "loading": "載入中...", + "compareWithBranch": "{path} · 與 {branch} 比較", + "hunkCount": "{count} 個區塊", + "prev": "上一個", + "next": "下一個", + "jumpToLine": "跳到第 {line} 行", + "noParsedDiffSections": "未解析到差異區塊", + "loadingEditor": "編輯器載入中...", + "imageZoomIn": "放大", + "imageZoomOut": "縮小", + "imageZoomReset": "重設縮放", + "htmlPreviewTitle": "HTML 預覽", + "htmlPreviewTrust": "執行指令碼", + "htmlPreviewTrustHint": "執行此檔案的指令碼並允許網路存取。僅對信任的檔案啟用。", + "officePreviewTitle": "辦公文件預覽", + "officeFullRender": "完整渲染", + "officeFullRenderHint": "渲染 Morph 動畫、3D 與公式(會執行投影片自帶的指令碼)", + "officeNotInstalled": "未安裝 OfficeCLI", + "officeNotInstalledHint": "在 設定 → 辦公工具 中安裝 OfficeCLI,即可預覽 Word、Excel 與 PowerPoint 檔案。", + "officeOpenSettings": "開啟設定", + "officeWatchFailed": "無法啟動即時預覽", + "officeWatchRetry": "重試", + "officeServerInstallHint": "OfficeCLI 需安裝在伺服器主機上。請在伺服器上執行以下指令後重試:", + "officeRemoteDesktopUnsupported": "遠端桌面視窗暫不支援即時預覽。請在伺服器的 Web 介面中開啟此工作區以預覽 Office 檔案。" + }, + "branchDropdown": { + "toasts": { + "commitCodeCompleted": "提交程式碼完成", + "pushCodeCompleted": "推送程式碼完成", + "committedFiles": "已提交 {count} 個檔案", + "taskCompleted": "{label} 完成", + "taskFailed": "{label} 失敗", + "mergeNoNewCommits": "{branchName} 沒有新的提交", + "mergedCommits": "已合併 {count} 個提交", + "allFilesUpToDate": "所有檔案均為最新版本", + "updatedFiles": "已更新 {count} 個檔案", + "openCommitWindowFailed": "打開提交視窗失敗", + "openPushWindowFailed": "開啟推送視窗失敗", + "upstreamSet": "已設定遠端追蹤分支", + "upstreamSetAndPushed": "已設定遠端追蹤分支並推送 {count} 個提交", + "noCommitsToPush": "沒有可推送的提交", + "pushedCommits": "已推送 {count} 個提交", + "switchedToFolder": "已切換到 {name}", + "switchFailed": "切換分支失敗", + "openStashWindowFailed": "開啟收藏視窗失敗" + }, + "tasks": { + "newBranch": "新增分支 {name}", + "newWorktree": "新增工作樹 {name}", + "checkoutTo": "切換到 {branchName}", + "mergeBranch": "合併 {branchName}", + "rebaseTo": "變基到 {branchName}", + "deleteRemoteBranch": "刪除遠端分支 {branchName}", + "initGitRepo": "初始化 Git 倉庫", + "pullCode": "更新程式碼", + "fetchInfo": "獲取資訊", + "pushCode": "推送程式碼", + "stashChanges": "暫存變更", + "stashPop": "取消暫存", + "deleteBranch": "刪除分支 {branchName}", + "removeWorktree": "刪除 {branchName} 的工作樹", + "removeWorktreeAndBranch": "刪除工作樹及分支 {branchName}", + "updateBranch": "更新分支 {branchName}" + }, + "confirm": { + "mergeTitle": "合併分支", + "rebaseTitle": "變基分支", + "mergeDescription": "確定將 {branchName} 合併到目前分支 {currentBranch} 嗎?", + "rebaseDescription": "確定將目前分支 {currentBranch} 變基到 {branchName} 嗎?", + "deleteRemoteTitle": "刪除遠端分支", + "deleteRemoteDescription": "確定刪除遠端分支 {branchName} 嗎?此操作將從遠端倉庫中移除該分支,且不可恢復。", + "deleteTitle": "刪除分支", + "deleteDescription": "確定刪除分支 {branchName} 嗎?此操作無法復原。", + "forceDeleteTitle": "強制刪除分支", + "forceDeleteDescription": "分支 {branchName} 尚未完全合併,確定要強制刪除嗎?此操作不可恢復。", + "deleteWorktreeTitle": "刪除工作樹", + "deleteWorktreeDescription": "刪除簽出了 {branchName} 的工作樹目錄?分支及其提交會保留。", + "forceDeleteWorktreeTitle": "強制刪除工作樹", + "forceDeleteWorktreeDescription": "{branchName} 的工作樹中有未提交或未追蹤的檔案。仍要刪除嗎?這些變更將無法復原。", + "deleteWorktreeAndBranchTitle": "刪除工作樹及分支", + "deleteWorktreeAndBranchDescription": "刪除 {branchName} 的工作樹、該分支本身及其工作區資料夾?其中的工作階段會移動到儲存庫資料夾下。此操作無法復原。", + "forceDeleteWorktreeAndBranchTitle": "強制刪除工作樹及分支", + "forceDeleteWorktreeAndBranchDescription": "{branchName} 的工作樹中有未提交的檔案,或該分支尚未完全合併。仍要一併刪除嗎?此操作無法復原。" + }, + "current": "目前", + "switchToBranch": "切換到此分支", + "mergeBranchIntoCurrent": "將 {branchName} 合併到 {currentBranch}", + "rebaseCurrentToBranch": "將 {currentBranch} 變基到 {branchName}", + "noBranch": "無分支", + "detachedHead": "分離 HEAD({sha})", + "initGitRepo": "初始化 Git 倉庫", + "pullCode": "更新程式碼", + "fetchRemoteBranches": "提取遠端分支", + "openCommitWindow": "提交程式碼...", + "pushCode": "推送...", + "pushBranch": "推送", + "newBranch": "新增分支...", + "newWorktree": "新增工作樹...", + "stashChanges": "貯藏更改...", + "stashPop": "取消暫存...", + "manageRemotes": "管理遠端...", + "localBranches": "本地分支 ({count})", + "noLocalBranches": "無本地分支", + "remoteBranches": "遠端分支 ({count})", + "noRemoteBranches": "無遠端分支", + "dialogs": { + "newBranchTitle": "新增分支", + "newBranchDescription": "從目前分支 {branch} 建立新分支", + "branchNamePlaceholder": "分支名稱", + "newWorktreeTitle": "新增工作樹", + "newWorktreeDescription": "從目前分支 {branch} 建立新的工作樹", + "branchNameLabel": "分支名稱", + "worktreePathLabel": "工作樹路徑", + "worktreePathPlaceholder": "工作樹路徑", + "manageRemotesTitle": "管理遠端", + "manageRemotesEmpty": "未設定遠端儲存庫", + "remoteNamePlaceholder": "遠端名稱", + "remoteUrlPlaceholder": "遠端 URL", + "addRemote": "新增", + "savingRemotes": "儲存中..." + }, + "conflict": { + "title": "合併衝突", + "description": "以下檔案存在衝突,需要手動解決:", + "abort": "中止合併", + "openMergeTool": "開啟合併工具", + "completeMerge": "完成合併", + "abortSuccess": "合併已中止", + "completeSuccess": "合併完成" + }, + "stashDialog": { + "title": "貯藏更改", + "description": "將當前更改保存到貯藏區", + "messageLabel": "訊息", + "messagePlaceholder": "貯藏訊息(可選)", + "keepIndex": "保留暫存區(已暫存的更改保持不變)", + "cancel": "取消", + "stash": "貯藏", + "success": "更改已貯藏", + "error": "貯藏更改失敗" + }, + "unstashDialog": { + "title": "取消貯藏", + "noStashes": "沒有貯藏記錄", + "selectFile": "選擇檔案查看差異", + "viewDiff": "查看差異", + "original": "原始", + "modified": "修改後", + "apply": "套用", + "drop": "刪除", + "applySuccess": "貯藏已套用", + "dropSuccess": "貯藏已刪除", + "confirmApply": "將貯藏 {ref} 套用到工作目錄?", + "cancel": "取消" + }, + "deleteBranch": "刪除分支", + "deleteWorktree": "刪除工作樹", + "deleteWorktreeAndBranch": "刪除工作樹及分支", + "searchPlaceholder": "搜尋分支與操作", + "searchAriaLabel": "搜尋分支與操作", + "branchListLabel": "分支與操作", + "noMatches": "無相符項目" + }, + "commitDialog": { + "toasts": { + "commitCompleted": "提交程式碼完成", + "pushFailed": "推送失敗", + "committedFiles": "已提交 {count} 個檔案", + "addedToVcs": "已加入到 VCS", + "addToVcsFailed": "加入到 VCS 失敗", + "fileDeleted": "檔案已刪除", + "deleteFailed": "刪除失敗", + "fileRolledBack": "檔案已回滾", + "rollbackFailed": "回滾失敗", + "dirRolledBack": "目錄已回滾", + "dirDeleted": "目錄已刪除" + }, + "confirm": { + "deleteTitle": "確認刪除", + "deleteDescription": "確定要刪除檔案「{file}」嗎?此操作無法復原。", + "rollbackTitle": "確認回滾", + "rollbackDescription": "確定要回滾檔案「{file}」到 HEAD 版本嗎?未儲存修改將遺失。", + "rollbackDirDescription": "確定要回滾目錄「{dir}」到 HEAD 版本嗎?未儲存的修改將遺失。", + "deleteDirDescription": "確定要刪除目錄「{dir}」嗎?此操作不可恢復。" + }, + "actions": { + "select": "選擇", + "unselect": "取消選擇", + "rollback": "回滾", + "addToVcs": "加入到 VCS" + }, + "aria": { + "selectFile": "{action}:{path}", + "unselectAllFiles": "取消選擇全部檔案", + "selectAllFiles": "選擇全部檔案", + "unselectTracked": "取消選擇已追蹤變更", + "selectTracked": "選擇已追蹤變更", + "unselectUntracked": "取消選擇未追蹤檔案", + "selectUntracked": "選擇未追蹤檔案" + }, + "loading": "載入中...", + "selectionCount": "{selected} / {total} 個檔案", + "emptyFiles": "沒有變更的檔案", + "trackedChanges": "已追蹤變更 ({count})", + "untrackedFiles": "未追蹤檔案 ({count})", + "commitMessage": "提交訊息", + "commitMessagePlaceholder": "輸入提交訊息...", + "commitButton": "提交 ({count})", + "commitAndPushButton": "提交並推送 ({count})", + "head": "HEAD(目前提交)", + "workingTree": "工作目錄", + "clickFileToDiff": "點擊檔案名稱查看差異", + "loadingDiff": "載入差異中..." + }, + "pushWindow": { + "title": "推送程式碼", + "noUnpushedCommits": "沒有未推送的提交", + "noRemoteConfigured": "未設定 Git 遠端儲存庫\n請在「管理遠端」中新增遠端地址", + "newBranchNoPushedCommits": "新分支 — 推送以建立遠端追蹤分支", + "unpushed": "未推送", + "selectFileToViewDiff": "選擇檔案查看差異", + "before": "修改前", + "after": "修改後", + "push": "推送", + "toasts": { + "pushSuccess": "推送成功", + "pushFailed": "推送失敗", + "upstreamSet": "已設定遠端追蹤分支", + "upstreamSetAndPushed": "已設定遠端追蹤分支並推送 {count} 個提交", + "noCommitsToPush": "沒有可推送的提交", + "pushedCommits": "已推送 {count} 個提交" + } + }, + "gitLogTab": { + "filesTitle": "檔案", + "expandAllFiles": "展開全部檔案", + "collapseAllFiles": "折疊全部檔案", + "workspace": "工作區", + "retry": "重試", + "noCommitsFound": "未找到提交記錄", + "notAGitRepoTitle": "不是 Git 儲存庫", + "notAGitRepoHint": "可從上方分支選單初始化 Git,或開啟已有的 Git 儲存庫。", + "hash": "Hash", + "copyHash": "複製雜湊", + "copyMessage": "複製提交訊息", + "showMore": "展開", + "showLess": "收合", + "author": "作者", + "noFileChangeDetails": "暫無檔案變更詳情。", + "loadingFiles": "正在載入檔案…", + "branchesTitle": "分支", + "loadingBranches": "正在載入分支...", + "noContainingBranches": "未找到包含此提交的分支。", + "newBranch": "新增分支...", + "resetToHere": "重設到此處", + "resetDisabledReasonNotCurrentBranchView": "僅在檢視目前分支時可用", + "copyFullCommitHashAria": "複製完整提交雜湊 {hash}", + "pushStatus": { + "pushed": "已推送到遠端", + "notPushed": "未推送到遠端", + "unknown": "推送狀態未知(未配置上游分支)" + }, + "time": { + "monthsAgo": "{count} 個月前", + "daysAgo": "{count} 天前", + "hoursAgo": "{count} 小時前", + "minsAgo": "{count} 分鐘前", + "justNow": "剛剛" + }, + "toasts": { + "createdAndSwitchedNewBranch": "已建立並切換到新分支", + "newBranchFromCommit": "{name}(來自 {shortHash})", + "createBranchFailed": "新增分支失敗", + "openPushWindowFailed": "開啟推送視窗失敗", + "resetSuccess": "重設成功", + "resetSuccessDescription": "已將 {branch} 以 {mode} 重設到 {shortHash}", + "resetFailed": "重設失敗" + }, + "authorFilter": { + "label": "作者", + "searchPlaceholder": "搜尋作者", + "noAuthors": "找不到作者", + "you": "你", + "filterByAuthorAria": "依作者篩選提交", + "filterByQuery": "依「{query}」篩選", + "clearAuthorFilterAria": "清除作者篩選", + "recent": "最近", + "matchingAuthors": "符合的作者", + "removeFromRecent": "從最近列表移除 {name}" + }, + "branchSelector": { + "label": "分支", + "head": "HEAD", + "headHint": "跟隨目前分支", + "headHintWithBranch": "跟隨目前分支({branch})", + "searchBranch": "搜尋分支...", + "noBranches": "無分支", + "selectBranchPlaceholder": "選擇分支...", + "localBranches": "本地分支", + "current": "目前", + "remoteBranches": "遠端分支", + "refreshCommitHistory": "刷新提交記錄", + "clearBranchFilterAria": "清除分支篩選" + }, + "dialogs": { + "newBranchTitle": "新增分支", + "newBranchDescription": "以提交 {shortHash} 作為最後提交建立新分支。", + "branchNamePlaceholder": "分支名稱", + "reset": { + "title": "將目前分支重設到此提交", + "branchLabel": "分支", + "targetLabel": "目標提交", + "messageLabel": "提交訊息", + "modeLabel": "重設模式", + "confirmButton": "重設", + "modes": { + "soft": { + "label": "--soft", + "description": "將 HEAD 與目前分支指標移動到目標提交。\n暫存區(Index)與工作區(Working Tree)保持不變。\n被回退提交的變更會保留為「已暫存」。" + }, + "mixed": { + "label": "--mixed(預設)", + "description": "將 HEAD 移動到目標提交。\n把暫存區重設為目標提交狀態,但保留工作區變更。\n這些變更會由「已暫存」變成「未暫存」。" + }, + "hard": { + "label": "--hard", + "description": "將 HEAD、暫存區與工作區全部重設到目標提交。\n目標提交之後的本地已追蹤變更會被直接捨棄。\n這是破壞性操作。" + }, + "keep": { + "label": "--keep", + "description": "將 HEAD 移動到目標提交,並盡可能保留本地變更。\n僅保留與目標提交不衝突的本地變更。\n若檢測到衝突,操作會中止以保護你的修改。" + } + } + } + }, + "moreActions": "更多 Git 操作" + }, + "gitChangesTab": { + "workspace": "工作區", + "noChanges": "暫無本地變更", + "notAGitRepoTitle": "不是 Git 儲存庫", + "notAGitRepoHint": "可從上方分支選單初始化 Git,或開啟已有的 Git 儲存庫。", + "trackedChanges": "本地已追蹤變更 ({count})", + "untrackedFiles": "本地未追蹤檔案 ({count})", + "expandTracked": "展開已追蹤變更", + "collapseTracked": "折疊已追蹤變更", + "expandUntracked": "展開未追蹤檔案", + "collapseUntracked": "折疊未追蹤檔案", + "showRemainingItems": "顯示其餘 {count} 項", + "actions": { + "commitCode": "提交程式碼", + "rollback": "回滾", + "addToVcs": "加入到 VCS", + "delete": "刪除", + "moreActions": "更多 Git 操作", + "addAllToVcs": "全部加入 VCS", + "rollbackAll": "全部還原", + "refresh": "重新整理" + }, + "toasts": { + "noAddableFilesInDir": "該目錄下沒有可加入到 VCS 的變更檔案", + "noRollbackFilesInDir": "該目錄下沒有可回滾的變更檔案", + "addedToVcs": "已加入 {name} 到 VCS", + "addToVcsFailed": "加入到 VCS 失敗", + "openCommitWindowFailed": "打開提交視窗失敗", + "rolledBack": "已回滾 {name}", + "rollbackFailed": "回滾失敗", + "addedFilesToVcs": "已加入 {count} 個檔案到 VCS", + "rolledBackFiles": "已回滾 {count} 個檔案", + "deleted": "已刪除 {name}", + "deleteFailed": "刪除失敗", + "deletedFiles": "已刪除 {count} 個檔案", + "noDeletableFilesInDir": "此目錄下沒有可刪除的變更檔案", + "commitFailed": "提交失敗" + }, + "directoryDialog": { + "descriptionAdd": "選擇目錄 {path} 下要加入到 VCS 的檔案。", + "descriptionRollback": "選擇目錄 {path} 下要回滾的檔案。", + "descriptionDelete": "選擇目錄 {path} 下要刪除的檔案。此操作不可撤銷。", + "descriptionFallback": "選擇要操作的檔案。", + "selectionCount": "已選擇 {selected} / {total} 個檔案", + "selectAll": "全選", + "unselectAll": "取消全選", + "loadingCandidates": "正在載入目錄變更...", + "noOperableFiles": "沒有可操作的檔案" + }, + "rollbackConfirm": { + "title": "確認回滾", + "descriptionWithTarget": "確定回滾{kind}「{name}」的本地修改嗎?", + "descriptionFallback": "確定回滾本地修改嗎?", + "kindDirectory": "目錄", + "kindFile": "檔案" + }, + "deleteConfirm": { + "title": "確認刪除", + "descriptionWithTarget": "確定刪除{kind}「{name}」嗎?此操作無法撤銷。", + "descriptionFallback": "此操作無法撤銷。", + "kindDirectory": "目錄", + "kindFile": "檔案" + }, + "quickCommit": { + "placeholder": "提交訊息(Enter 提交)" + } + }, + "tabContext": { + "loadingConversation": "載入中...", + "untitledConversation": "未命名會話", + "newConversation": "新增會話" + }, + "fileTreeTab": { + "workspace": "工作區", + "retry": "重試", + "git": "Git", + "openInFileManager": "在檔案管理器開啟", + "openInFinder": "在 Finder 開啟", + "openInExplorer": "在檔案總管開啟", + "attachToCurrentSession": "添加到會話", + "compareWithBranch": "與分支比較...", + "reloadFromDisk": "從磁碟重新載入", + "new": "新建", + "newFile": "檔案", + "newDirectory": "目錄", + "openIn": "開啟於", + "openInTerminal": "在終端開啟", + "linkedFolder": "已連結的資料夾", + "copyPath": "複製路徑", + "upload": "上傳檔案/目錄", + "download": "下載檔案", + "downloadAsZip": "下載為 ZIP", + "actions": { + "select": "選擇", + "unselect": "取消選擇", + "commitCode": "提交程式碼", + "rollback": "回滾", + "addToVcs": "加入到 VCS" + }, + "aria": { + "selectPath": "{action}:{path}" + }, + "toasts": { + "openDirectoryFailed": "開啟目錄失敗", + "openBuiltinTerminalFailed": "無法開啟內建終端", + "openCommitWindowFailed": "打開提交視窗失敗", + "noAddableFilesInDir": "該目錄下沒有可加入到 VCS 的變更檔案", + "noRollbackFilesInDir": "該目錄下沒有可回滾的變更檔案", + "addedToVcs": "已加入 {name} 到 VCS", + "addToVcsFailed": "加入到 VCS 失敗", + "loadBranchesFailed": "載入分支失敗", + "renameFailed": "重新命名失敗", + "moveFailed": "移動失敗", + "deleteFailed": "刪除失敗", + "rolledBack": "已回滾 {name}", + "rollbackFailed": "回滾失敗", + "addedFilesToVcs": "已加入 {count} 個檔案到 VCS", + "rolledBackFiles": "已回滾 {count} 個檔案", + "savedAsCopy": "已另存為副本", + "saveCopyFailed": "另存為副本失敗", + "watchStartFailed": "檔案監聽啟動失敗", + "createFailed": "建立失敗", + "downloadFailed": "下載 {name} 失敗", + "downloadSaved": "已下載 {name}", + "pathCopied": "已複製路徑", + "copyPathFailed": "複製路徑失敗" + }, + "createDialog": { + "newFile": "新建檔案", + "newDirectory": "新建目錄", + "description": "輸入新{kind}的名稱。", + "placeholderFile": "file-name.ext", + "placeholderDirectory": "folder-name" + }, + "renameDialog": { + "renameDirectory": "重新命名目錄", + "renameFile": "重新命名檔案", + "description": "輸入新的名稱(僅名稱,不含路徑)。", + "placeholderDirectory": "新資料夾名稱", + "placeholderFile": "新檔案名稱.ext" + }, + "uploadDialog": { + "title": "上傳到工作區", + "description": "可在下方修改上傳目錄,然後加入檔案或資料夾。", + "workspaceRoot": "工作區根目錄", + "targetPathLabel": "上傳到", + "targetPathHint": "實際目錄:{path}", + "dropHint": "拖曳檔案或資料夾到此處,或使用下方按鈕", + "dropHintActive": "放開以加入上傳佇列", + "selectFiles": "選擇檔案", + "selectFolder": "選擇資料夾", + "startUpload": "開始上傳", + "clearQueue": "清除已完成", + "removeItem": "從佇列移除", + "retry": "重試", + "dropZoneAria": "拖放檔案到此處,或按 Enter 鍵瀏覽", + "folderEmpty": "拖入的資料夾中沒有可上傳的檔案", + "summary": "總數:{total} · 成功:{succeeded} · 失敗:{failed}", + "status": { + "pending": "等待中", + "uploading": "上傳中", + "success": "完成", + "error": "失敗", + "cancelled": "已取消" + } + }, + "directoryDialog": { + "descriptionAdd": "選擇目錄 {path} 下要加入到 VCS 的檔案。", + "descriptionRollback": "選擇目錄 {path} 下要回滾的檔案。", + "descriptionFallback": "選擇要操作的檔案。", + "selectionCount": "已選擇 {selected} / {total} 個檔案", + "selectAll": "全選", + "unselectAll": "取消全選", + "loadingCandidates": "正在載入目錄變更...", + "noOperableFiles": "沒有可操作的檔案" + }, + "compareDialog": { + "title": "與分支比較", + "descriptionWithTarget": "選擇分支並與{kind} {path} 比對", + "descriptionFallback": "選擇要比較的分支。", + "kindDirectory": "目錄", + "kindFile": "檔案", + "filterPlaceholder": "過濾分支,例如 main / origin/main", + "singleClickHint": "單擊分支即可直接比較", + "loadingBranches": "正在載入分支...", + "recentBranches": "最近分支 ({count})", + "noCurrentBranch": "無目前分支", + "localBranches": "本地分支 ({count})", + "remoteBranches": "遠端分支 ({count})", + "noMatchingBranches": "無匹配分支" + }, + "externalConflictDialog": { + "title": "偵測到外部檔案變更", + "descriptionWithPath": "檔案 {path} 在磁碟已發生變化,目前編輯內容尚未儲存。", + "descriptionFallback": "目前檔案在磁碟已發生變化,目前編輯內容尚未儲存。", + "compare": "比較", + "savingCopy": "另存中...", + "saveAsCopy": "另存為副本", + "reload": "重載" + }, + "deleteConfirm": { + "title": "確認刪除", + "descriptionWithTarget": "確定刪除{kind} \"{name}\" 嗎?此操作不可撤銷。", + "descriptionFallback": "此操作不可撤銷。", + "kindDirectory": "目錄", + "kindFile": "檔案" + }, + "rollbackConfirm": { + "title": "確認回滾", + "descriptionWithTarget": "確定回滾檔案 \"{name}\" 的本地修改嗎?", + "descriptionFallback": "確定回滾該檔案的本地修改嗎?" + }, + "terminalTitle": "終端 · {name}" + }, + "commandDropdown": { + "loading": "載入中...", + "addCommand": "新增命令", + "manageCommands": "管理命令...", + "runCommandTitle": "執行:{command}", + "stopCommandTitle": "停止:{command}", + "manageDialog": { + "title": "管理命令", + "empty": "暫無命令", + "noResults": "沒有符合的命令", + "searchPlaceholder": "搜尋命令", + "newCommand": "新增命令", + "nameLabel": "名稱", + "commandLabel": "命令", + "dragSort": "拖曳排序", + "dragSortCommand": "拖曳排序 {name}", + "orderFailed": "儲存命令排序失敗", + "loadFailed": "載入命令失敗", + "saveFailed": "儲存命令失敗", + "deleteFailed": "刪除命令失敗", + "confirmDelete": { + "title": "刪除命令?", + "message": "這會移除「{name}」,此操作無法復原。" + } + } + }, + "workspaceContext": { + "confirmCloseDirtyTab": "檔案「{title}」有未儲存變更,確定關閉嗎?", + "confirmCloseOtherDirtyTabs": "其他分頁有未儲存變更,確定關閉嗎?", + "confirmCloseAllDirtyTabs": "存在未儲存變更,確定關閉全部分頁嗎?", + "unableLoadContent": "無法載入內容。\n\n{message}", + "previewRequestTimedOut": "預覽請求逾時", + "diffRequestTimedOut": "Diff 請求逾時", + "branchCompareRequestTimedOut": "分支比較請求逾時", + "commitDiffRequestTimedOut": "提交差異請求逾時", + "saveRequestTimedOut": "儲存請求逾時", + "reloadRequestTimedOut": "重載請求逾時", + "noChanges": "暫無變更。", + "noDiffOutput": "無差異輸出。", + "diffTitleWorkspace": "Diff · 工作區", + "diffDescriptionWorkingTree": "工作區變更(HEAD)", + "diffTitleFile": "差異 · {name}", + "compareTitleFile": "比較 · {name}", + "compareTitleBranch": "比較 · {branch}", + "compareDescriptionPath": "{path} · 與 {branch} 比較", + "compareDescriptionBranch": "與 {branch} 比較", + "diffTitleCommitFile": "差異 · {name} @ {hash}", + "diffTitleCommit": "差異 · {hash}", + "diffDescriptionCommitPath": "{path} · 提交 {commit}", + "diffDescriptionCommit": "提交 {commit}", + "diffTitleConflictFile": "衝突 · {name}", + "diffDescriptionConflict": "{path} · 磁碟與未儲存內容" + }, + "chat": { + "acpConnections": { + "actions": { + "openAgentsSettings": "打開 Agents 管理", + "retry": "重試" + }, + "agentsSetupHint": "點擊前往設定 > Agents 管理安裝。", + "withSetupHint": "{message}\n提示:{hint}", + "blocked": { + "missingConfig": "無法讀取目前 Agent 設定。", + "disabled": "{agent} 已在 Agents 管理中停用,請先啟用後再連線。", + "unavailable": "{agent} 目前平台不可用。", + "sdkMissing": "{agent} SDK 尚未安裝", + "adapterMissing": "{agent} 的 ACP 轉接器尚未安裝" + }, + "backendErrors": { + "initializeTimeout": "{agent} 連線交握逾時(60 秒未回應),請前往設定頁面檢查智能體與網路設定。", + "mcpRejectedByAgent": "附帶 codeg 的 MCP 伴生程序時,{agent} 拒絕了本次會話:{message} 如果該智能體不支援 MCP,請在設定中關閉它的「MCP 支援」後重新連線。", + "processExited": "{agent} 處理程序意外結束。", + "spawnFailed": "啟動 {agent} 失敗:{message}", + "downloadFailed": "{agent} 下載失敗:{message}", + "sessionLoadResourceNotFound": "{agent} 會話載入失敗,可重新載入重試,或開始新會話。", + "sessionLoadUnavailable": "{agent} 無法還原此會話,它可能已結束或 agent 已停止。可重新載入重試,或開始新會話。", + "turnFailedRefusal": "{agent} 拒絕繼續此輪回覆,通常代表後端或網關出錯,請檢查代理日誌。", + "turnFailedMaxTokens": "{agent} 已達到此輪回覆的最大 Token 限制。", + "turnFailedMaxTurnRequests": "{agent} 已達到此輪回覆允許的最大請求次數。", + "turnFailedUnknown": "{agent} 以未知的停止原因結束了此輪回覆。", + "grokModelSwitchIncompatibleAgent": "{agent} 無法在既有對話中切換到該模型,請新建工作階段以使用它。", + "turnFailedEmpty": "{agent} 此輪沒有產生任何回覆就結束了。", + "turnFailedEmptyProtocol": "{agent} 此輪的輸出 codeg 無法解析,可能是代理版本與協定不相符。", + "turnFailedEmptyMetadata": "{agent} 此輪只收到狀態更新(計畫 / 模式 / 用量),沒有收到任何回覆。", + "detailsInAlerts": "在狀態列的「警示」中展開詳情,即可查看代理輸出。" + }, + "unableReadAgentConfig": "無法讀取 Agent 設定:{message}", + "connectFailedTitle": "{agent} 連線失敗", + "toolFallbackTitle": "工具", + "eventErrorTitle": "Agent 錯誤", + "notificationTurnComplete": "{agent} 已完成回應", + "notificationError": "{agent} 錯誤:{message}", + "claudeApiRetry": { + "fallbackError": "authentication_failed", + "retryingWithMax": "正在重試 {attempt}/{max}", + "retryingAttempt": "正在重試(第 {attempt} 次)", + "retrying": "正在重試", + "nextRetryIn": "{seconds} 秒後重試", + "line": "{error}{status} · {retry}", + "lineWithDelay": "{error}{status} · {retry},{delay}", + "httpStatus": "(HTTP {status})" + }, + "configOptionAdjusted": "{agent} 把{option}設成了 {actual},而不是 {requested}" + }, + "connectionLifecycle": { + "tasks": { + "connectingTitle": "正在連線 {agent}", + "connectingDescription": "正在建立連線", + "loadingSelectorsTitle": "正在載入 {agent} 選擇項", + "loadingSelectorsDescription": "正在取得模式與會話設定選項", + "initSessionTitle": "正在初始化 {agent} 會話", + "initSessionDescription": "正在建立會話並載入設定" + }, + "errors": { + "connectionFailed": "連線失敗", + "sendPromptFailed": "訊息傳送失敗:{error}" + } + }, + "shared": { + "attachedResources": "附加資源", + "toolCallFailed": "工具呼叫失敗" + }, + "messageThread": { + "emptyTitle": "暫無訊息", + "emptyDescription": "開始一個會話後,訊息會顯示在這裡" + }, + "chatInput": { + "connecting": "連線中...", + "agentResponding": "{agent} 正在回應...", + "sendMessage": "傳送訊息..." + }, + "messageInput": { + "askAnything": "請開始輸入...", + "removeAttachmentAria": "移除 {name}", + "attachFiles": "附加檔案", + "addActions": "新增", + "quickMessages": "快捷訊息", + "quickMessagesEmpty": "尚無快捷訊息", + "quickMessagesLoading": "載入中...", + "pasteAsPlainText": "貼上純文字", + "cut": "剪下", + "copy": "複製", + "selectAll": "全選", + "pasteUnavailable": "無法讀取剪貼簿,請改用 Ctrl/⌘V 貼上。", + "clipboardWriteFailed": "無法寫入剪貼簿,請改用鍵盤快速鍵。", + "quickMessageUntitled": "未命名", + "liveFeedback": "即時回饋", + "liveFeedbackDisabledHint": "智能體工作時可傳送", + "dropFilesToAttach": "拖曳檔案到此處附加", + "loadingSettings": "正在載入設定...", + "loadingMode": "正在載入模式...", + "modeLabel": "模式", + "toggleOn": "開", + "toggleOff": "關", + "agentSettings": "智能體設定", + "searchModel": "搜尋模型...", + "searchModelAria": "搜尋模型", + "modelListLabel": "模型", + "noModels": "找不到模型", + "cancel": "取消", + "send": "傳送", + "forkAndSend": "分叉發送", + "queueMessage": "加入佇列", + "steerIntoTurn": "插入目前回合", + "steerQueuedInstead": "已轉入佇列——將隨下一回合傳送。", + "steerFailed": "無法插入目前回合", + "steerAttachmentsUnsupported": "僅支援純文字——帶附件的草稿請走佇列。", + "slashCommands": "斜線命令", + "slashSearchPlaceholder": "搜尋命令...", + "slashSearchEmpty": "沒有符合的指令", + "experts": "專家", + "office": "日常辦公", + "research": "科學研究", + "attachLocalUpload": "附加本機檔案", + "attachServerFile": "附加伺服器檔案", + "attachUploadTooLarge": "{names} 超過 {limit}MB 上傳上限,已略過。", + "attachUploadFailed": "上傳失敗:{names}。", + "attachUploadNotAFile": "{names} 不是常規檔案(目錄或特殊檔案),已略過。", + "attachUploadQuotaExceeded": "伺服器上傳空間已用盡,{names} 未能上傳。", + "attachUploadInProgress": "圖片仍在上傳中,請稍候再傳送。", + "mentionEmpty": "無相符項目", + "mentionLoading": "搜尋中…", + "mentionListLabel": "提及", + "mentionMore": "還有更多結果,繼續輸入以篩選", + "mentionCount": "{count, plural, other {# 項結果}}", + "mentionGroupFile": "檔案", + "mentionGroupAgent": "智能體", + "mentionGroupSession": "工作階段", + "mentionGroupCommit": "提交", + "mentionGroupSkill": "技能" + }, + "messageQueue": { + "addToQueue": "加入佇列", + "saveEdit": "儲存", + "cancelEdit": "取消編輯", + "editItem": "編輯", + "deleteItem": "刪除" + }, + "welcomeInputPanel": { + "agentsSettingsPath": "設定 > Agents", + "autoConnectFallback": "點擊前往 {path} 管理安裝。", + "autoConnectAppend": "{message},點擊前往 {path} 管理安裝。", + "enableAgentFirstPlaceholder": "請先啟用至少一個 Agent 後開始會話...", + "prepareSessionFailed": "無法準備聊天工作階段,請重試。", + "createConversationFailed": "無法建立會話,請重試。", + "askAnythingPlaceholder": "請開始輸入...", + "agentNotInstalled": "{agent} 尚未安裝 · 點擊前往 Agents 設定安裝", + "agentAdapterNotInstalled": "{agent} 的 ACP 轉接器尚未安裝(與你本機的 CLI 無關)· 點擊前往 Agents 設定安裝" + }, + "welcomePanel": { + "greeting": "今天打算做些什麼呢?", + "tips": { + "tileTabs": "右鍵點擊會話標籤選擇「平鋪顯示」,可同螢幕對比多個會話", + "pinTab": "雙擊會話標籤可將其固定,避免被新開啟的會話自動取代", + "shortcutsNewSearch": "{newConversation} 快速新建會話,{searchConversations} 搜尋歷史會話", + "slashAtMention": "在輸入框輸入 / 觸發斜線命令,輸入 @ 引用專案內檔案", + "pasteDropFiles": "直接貼上截圖或把檔案拖到輸入框,即可作為附件", + "queueMessage": "智能體回覆中也能繼續輸入並排隊,回答完畢會自動續發", + "draftAutoSave": "未發送的草稿會自動儲存,重新開啟會話仍在", + "forkSend": "傳送按鈕旁的下拉選擇「分叉傳送」,從目前位置開一條新分支", + "exportConversation": "右鍵會話內容區可匯出為 Markdown / HTML / 圖片", + "chatChannels": "在「設定 → 聊天頻道」接入 Telegram / 飛書 / 微信,從手機繼續操作", + "shortcutsAuxPanel": "{toggleAuxPanel} 切換右側面板,檢視本次會話改動的檔案與 Git 變更", + "shortcutsTerminalSidebar": "{toggleTerminal} 開啟內建終端機,{toggleSidebar} 切換側邊欄", + "customShortcuts": "所有快捷鍵都可在「設定 → 快捷鍵」中自訂", + "webService": "開啟「設定 → Web 服務」後,團隊成員可從瀏覽器接入同一臺 codeg", + "fusionMode": "開啟檔案或差異後,會自動與會話並排顯示", + "quickMessages": "點輸入框旁的 + 按鈕選擇「快捷訊息」,可一鍵插入預存片段(在「設定 → 快捷訊息」中管理)", + "experts": "透過 + 按鈕裡的「專家技能」可一鍵載入預設角色(除錯 / 規劃等)", + "taskBoard": "「待辦任務」能把一條待辦從頭跑到尾:智能體在獨立工作樹裡執行,你檢視完差異再合併。", + "automations": "「自動化」按排程定時執行儲存好的提示詞(例如每晚一次程式碼審查),還能讓每次執行都開一個獨立工作樹。", + "tokenUsage": "點擊狀態列左下角的會話數即可開啟「Token 用量」,按日期、智能體、模型與資料夾拆分統計。", + "mentionTargets": "@ 不只能引用檔案:還能 @ 另一個智能體把子任務交給它,或引用歷史會話、某次提交、某個技能。", + "splitGroups": "右鍵點擊標籤選擇「向右拆分」或「向下拆分」,兩個會話各佔一個分割區同時開著。", + "worktrees": "點開分支按鈕選「新增工作樹」,多個智能體就能在同一個儲存庫並行工作,互不覆蓋彼此的檔案。", + "importSessions": "之前在終端機裡跑過的會話,用資料夾右鍵選單的「匯入本地會話」就能把那段歷史接進 codeg。", + "subSessions": "智能體委派出去的子會話會巢狀顯示在側邊欄的父會話底下,展開就能追蹤每一個子會話做了什麼。", + "liveFeedback": "「+」選單裡的「即時回饋」能把一則便條塞進智能體正在跑的這一輪,不用打斷它。", + "skillPacks": "設定 → 技能包 裡打包了程式專家、科研與辦公三類技能,可以按智能體分別開關。", + "modelProviders": "設定 → 模型供應商 支援填自己的 API key 或端點位址,之後直接在輸入框裡切換模型。", + "workspaceBackground": "設定 → 外觀 裡可以換工作區背景圖、調面板不透明度,還能換應用程式字型。" + }, + "quickActions": { + "excel": "Excel 活頁簿", + "excelDesc": "資料表、公式與圖表", + "word": "Word 文件", + "wordDesc": "報告、信函與備忘錄", + "ppt": "簡報", + "pptDesc": "專業設計的投影片", + "pitchDeck": "募資簡報", + "pitchDeckDesc": "含關鍵指標的募資簡報", + "morph": "Morph 動畫", + "morphDesc": "電影級投影片轉場", + "morph3d": "3D Morph", + "morph3dDesc": "3D 模型與鏡頭運動", + "academic": "學術論文", + "academicDesc": "含引用與結構的研究論文", + "financial": "財務模型", + "financialDesc": "報表、DCF 與預測", + "dashboard": "資料儀表板", + "dashboardDesc": "從資料產生 KPI 與分析", + "prompts": { + "excel": "建立一個 Excel 活頁簿,需求如下:\n\n[在此描述你的資料、表格、公式與圖表]", + "word": "建立一個 Word 文件,需求如下:\n\n[在此描述文件內容、結構與排版]", + "ppt": "建立一個 PowerPoint 簡報,需求如下:\n\n[在此描述投影片、內容與設計]", + "pitchDeck": "建立一個募資簡報,需求如下:\n\n[在此描述公司、募資輪次與關鍵指標]", + "morph": "建立一個帶 Morph 轉場動畫的簡報:\n\n[在此描述簡報主題與期望的視覺效果]", + "morph3d": "建立一個帶 GLB 模型與鏡頭運動的 3D Morph 簡報:\n\n[在此描述主題與 3D 視覺構想]", + "academic": "用 Word 撰寫一篇學術論文,需求如下:\n\n[在此描述研究主題、方法與主要發現]", + "financial": "用 Excel 建立一個財務模型,需求如下:\n\n[在此描述財務報表、預測與分析]", + "dashboard": "用 Excel 建立一個資料儀表板,需求如下:\n\n[在此描述資料來源、KPI 與圖表]", + "scientific-brainstorming": "幫我進行科研腦力激盪:探索跨學科連結、挑戰假設、發掘有潛力的研究缺口。我正在探索的方向:", + "hypothesis-generation": "幫我把這些觀察轉化為可檢驗的假設:提出明確預測、合理機制,並設計驗證實驗。我的觀察:", + "experimental-design": "在蒐集資料前幫我設計嚴謹的實驗:設計方案、隨機化、對照,以及如何避免干擾。我想研究的問題:", + "statistical-power": "幫我確定所需樣本數:為我的設計做檢定力分析(效應量、顯著水準、檢定力)。具體資訊:", + "statistical-analysis": "幫我正確分析這份資料:選擇合適的檢定、檢查假設、報告效應量並撰寫結論。我的資料與問題:", + "exploratory-data-analysis": "對我的資料檔案做探索性分析:概述其結構、品質與值得注意的模式,並建議後續步驟。檔案是:", + "scientific-visualization": "幫我製作出版級圖表:清晰佈局、真實誤差棒、色盲友善配色,以及期刊格式。我想展示的內容:", + "scientific-critical-thinking": "幫我批判性評估這項研究或主張:評估證據品質、辨識偏誤與干擾,並權衡結論。內容如下:", + "paper-lookup": "幫我在學術資料庫中查找相關論文與開放取用全文,並提供可重用的引用。我要找的是:" + }, + "paper-lookup": "論文檢索", + "paper-lookupDesc": "檢索 10 個學術 API(PubMed、arXiv、OpenAlex、Crossref…)查找論文、引用與開放取用全文。", + "scientific-critical-thinking": "批判性思維", + "scientific-critical-thinkingDesc": "評估科學主張與證據品質:辨識偏誤與干擾,運用 GRADE 與偏誤風險框架。", + "scientific-visualization": "科學視覺化", + "scientific-visualizationDesc": "出版級圖表:多面板佈局、顯著性標註與期刊專屬格式。", + "exploratory-data-analysis": "探索性資料分析", + "exploratory-data-analysisDesc": "對 200+ 種格式的科學資料檔案做自動化探索,輸出品質指標與報告。", + "statistical-analysis": "統計分析", + "statistical-analysisDesc": "引導式統計分析:檢定選擇、假設檢查、效應量與 APA 格式報告。", + "statistical-power": "統計檢定力", + "statistical-powerDesc": "樣本數與統計檢定力分析:所需樣本數、最小可檢測效應與檢定力曲線。", + "experimental-design": "實驗設計", + "experimental-designDesc": "在蒐集資料前設計嚴謹研究:隨機化、區集、對照與析因/DOE 佈局。", + "hypothesis-generation": "假設生成", + "hypothesis-generationDesc": "將觀察轉化為可檢驗的假設,提出預測、機制並設計驗證實驗。", + "scientific-brainstorming": "科學腦力激盪", + "scientific-brainstormingDesc": "開放式科研構思:探索跨學科連結、挑戰假設、發掘研究缺口。", + "tabs": { + "office": "日常辦公", + "coding": "程式開發", + "research": "科學研究" + }, + "coding": { + "brainstormingDesc": "動手前先梳理意圖與需求", + "debuggingDesc": "先定位根因再提出修復", + "writingSkillsDesc": "建立、編輯並驗證可重用技能" + }, + "notEnabled": { + "title": "「{skill}」技能尚未對 {agent} 啟用", + "description": "前往設定啟用後即可在此使用。", + "action": "前往啟用", + "hint": "技能未啟用" + }, + "scrollPrev": "顯示上一組技能", + "scrollNext": "顯示下一組技能" + } + }, + "agentSelector": { + "noEnabledAgents": "暫無已啟用的 Agent", + "openAgentsSettings": "開啟 Agents 設定", + "notInstalled": "未安裝", + "moreAgents": "更多 Agent({count})" + }, + "subAgentOverlay": { + "title": "子智能體", + "collapsedSummary": "子智能體 {count}", + "collapseAria": "摺疊子智能體" + }, + "agentPlanOverlay": { + "title": "計畫任務", + "collapsePlanAria": "摺疊計畫", + "collapsedSummary": "計畫 {completed}/{total}", + "status": { + "completed": "已完成", + "inProgress": "進行中", + "pending": "待處理", + "unknown": "未知" + }, + "priority": { + "high": "高", + "medium": "中", + "low": "低", + "unknown": "未知" + } + }, + "permissionDialog": { + "subtitle": "Agent 請求繼續目前輪次的權限。", + "queuedCount": "還有 {count} 項待審批", + "kindFallbackTool": "工具", + "command": "命令", + "cwd": "工作目錄:{cwd}", + "filesSummary": "檔案:{count}", + "moreFiles": "+{count} 個更多檔案", + "plan": "計畫", + "allowedActions": "允許的操作", + "targetMode": "目標模式:{mode}", + "optionGrants": "各選項將授予的權限", + "changeScopeSession": "本次工作階段", + "changeScopeProcess": "本次執行", + "changeScopeUser": "儲存至使用者設定", + "changeScopeProject": "儲存至專案設定", + "changeScopeProjectLocal": "儲存至本機專案設定", + "changeScopePersistent": "永久儲存" + }, + "questionDialog": { + "title": "代理正在提問", + "placeholder": "輸入你的回答...", + "send": "傳送" + }, + "messageBranch": { + "previousBranchAria": "上一個分支", + "nextBranchAria": "下一個分支", + "pageOf": "{current} / {total}" + }, + "terminal": { + "title": "終端", + "running": "執行中" + }, + "reasoning": { + "thinking": "思考中…", + "thoughtForFewSeconds": "思考", + "thoughtForSeconds": "思考" + }, + "linkSafety": { + "errorCannotOpen": "無法開啟本地檔案", + "errorNoWorkspace": "目前沒有活躍的工作區資料夾。", + "errorFailedOpen": "開啟本地檔案失敗", + "errorFailedLink": "開啟連結失敗", + "errorUnsupportedLinkProtocol": "不支援此連結協議。" + }, + "fileActions": { + "openInFinder": "在 Finder 開啟", + "openInExplorer": "在檔案總管開啟", + "openInFileManager": "在檔案管理器開啟", + "copyRelativePath": "複製相對路徑", + "copyAbsolutePath": "複製絕對路徑", + "pathCopied": "已複製路徑", + "copyPathFailed": "複製路徑失敗", + "openFailed": "開啟本地檔案失敗" + }, + "messageList": { + "attachedResources": "附加資源", + "loading": "載入中...", + "loadEarlier": "載入更早的訊息", + "loadingEarlier": "正在載入更早的訊息…", + "error": "錯誤:{message}", + "errorTitle": "會話載入失敗", + "errorActionReload": "重新載入", + "errorActionNewSession": "新建會話", + "emptyConversation": "目前會話暫無訊息。", + "systemMessage": "系統訊息", + "copyMessage": "複製", + "copied": "已複製", + "downloadImage": "下載圖片", + "downloadFailed": "下載失敗:{message}", + "imageGeneration": "圖片生成", + "imageGenerationPending": "正在生成圖片…", + "imageGenerationFailed": "圖片生成失敗", + "model": "模型", + "tokenStats": "Token 使用情況", + "tokenInput": "輸入", + "tokenOutput": "輸出", + "tokenCacheRead": "快取讀取", + "tokenCacheWrite": "快取寫入", + "duration": "耗時", + "completedAt": "完成時間", + "jumpToPreviousUserMessage": "跳轉到上一條使用者訊息", + "showMore": "展開", + "showLess": "收合" + }, + "liveTurnStats": { + "thinking": "思考中...", + "streaming": "生成中", + "elapsedHours": "{value} 小時", + "elapsedMinutes": "{value} 分鐘", + "elapsedSeconds": "{value} 秒", + "outputSpeedAria": "估算輸出速度", + "outputSpeedTooltip": "估算輸出速度(正文 + 思考)" + }, + "jsonTree": { + "viewRaw": "檢視原始 JSON", + "viewTree": "檢視樹狀檢視", + "fields": "{count} 個欄位", + "items": "{count} 項" + }, + "tool": { + "parameters": "參數", + "error": "錯誤", + "result": "結果", + "status": { + "approvalRequested": "等待授權", + "approvalResponded": "已回應", + "inputAvailable": "執行中", + "inputStreaming": "等待中", + "outputAvailable": "已完成", + "outputDenied": "已拒絕", + "outputError": "錯誤" + } + }, + "toolCallBlock": { + "tool": "工具", + "error": "錯誤", + "result": "結果" + }, + "delegation": { + "subAgentRunning": "子代理執行中…", + "noDetail": "暫無詳情。", + "unknownAgent": "子智慧體", + "openDetail": "檢視會話", + "detailTitle": "子智慧體會話", + "detailDescription": "唯讀檢視委派給子智慧體的會話內容。", + "waitForResult": "等待 {task} 任務執行結果", + "waitForResultNoTask": "等待任務執行結果", + "cancelTask": "取消 {task} 任務", + "cancelTaskNoTask": "取消任務", + "resultPageOf": "{current} / {total}", + "prevResult": "上一個結果", + "nextResult": "下一個結果", + "noResultText": "本次檢查暫無結果", + "status": { + "starting": "啟動中", + "running": "執行中", + "checked": "已查詢", + "waiting": "待批准", + "ok": "完成", + "err": { + "default": "失敗", + "delegation_disabled": "已停用", + "depth_limit": "深度超限", + "invalid_agent_type": "代理類型無效", + "spawn_failed": "啟動失敗", + "send_failed": "傳送失敗", + "timeout": "逾時", + "canceled": "已取消", + "child_refusal": "子代理拒絕", + "child_max_tokens": "子代理超出 token 上限", + "child_max_turn_requests": "子代理超出請求上限", + "child_empty": "子代理無回應", + "child_unknown": "子代理未知錯誤", + "unknown": "未知任務" + } + } + }, + "contentParts": { + "showingTailOutput": "為確保效能,串流輸出時僅顯示尾端內容。", + "result": "結果", + "unknown": "未知", + "inputTruncated": "輸入已截斷,diff 可能不完整。", + "replaceAll": "全部替換", + "filesCount": "檔案:{count}", + "update": "更新", + "moreFiles": "+{count} 個更多檔案", + "timeoutMs": "逾時:{timeout}ms", + "backgroundTrue": "背景:true", + "scriptToolCalls": "呼叫 {count} 個工具", + "offset": "位移:{offset}", + "limit": "限制:{limit}", + "pages": "頁碼:{pages}", + "mode": "模式:{mode}", + "cell": "儲存格:{cell}", + "shellSession": "工作階段 {id}", + "pathLabel": "路徑:", + "globLabel": "Glob:", + "typeLabel": "類型:", + "outputLabel": "輸出:", + "caseInsensitive": "不區分大小寫", + "multiline": "多行", + "promptLabel": "提示詞", + "subjectLabel": "主題", + "taskLabel": "任務", + "nameLabel": "名稱:", + "agentPromptLabel": "提示詞", + "agentModelLabel": "模型", + "agentRunning": "執行中...", + "agentLiveTranscript": "即時活動", + "agentProgressTools": "{count} 次工具調用", + "agentProgressTurns": "{count} 輪", + "agentProgressContext": "上下文 {pct}%", + "agentSessionAction": "檢視子智慧體工作階段", + "agentSessionTitle": "子智慧體工作階段", + "agentSessionLoading": "正在載入子智慧體的對話記錄…", + "agentSessionEmpty": "子智慧體尚未寫入任何內容。", + "agentFallbackTitle": "子智能體啟動中…", + "agentCodexLaunchOnly": "已啟動。Codex 不會再回報這個子智能體的進度——它的結果會以一則訊息出現在本工作階段中。", + "agentStatsBash": "命令", + "agentStatsRead": "讀取檔案", + "agentStatsSearch": "搜尋", + "agentStatsEdit": "編輯", + "agentStatsOther": "其他", + "goal": { + "title": "目標:", + "titleWithStatus": "目標{status}", + "objective": "目標", + "statusLabel": "狀態", + "tokensUsed": "已用 tokens", + "budget": "預算", + "remaining": "剩餘", + "elapsed": "耗時", + "tokens": "tokens", + "pause": "暫停", + "clear": "清除", + "status": { + "active": "進行中", + "paused": "已暫停", + "blocked": "受阻", + "usageLimited": "用量受限", + "budgetLimited": "預算受限", + "complete": "已完成", + "limited": "已達上限" + } + }, + "field": { + "file": "檔案", + "notebook": "筆記本", + "command": "命令", + "old": "舊內容", + "new": "新內容", + "pattern": "模式", + "path": "路徑", + "query": "查詢", + "url": "URL 位址", + "description": "描述", + "content": "內容", + "source": "來源內容", + "prompt": "提示詞", + "subject": "主題", + "taskId": "任務 ID", + "status": "狀態", + "skill": "Skill", + "args": "參數", + "offset": "位移", + "limit": "限制", + "glob": "Glob", + "type": "類型", + "output": "輸出", + "replaceAll": "全部替換", + "language": "語言", + "timeout": "逾時", + "background": "背景", + "agentType": "Agent 類型", + "library": "函式庫", + "libraryId": "函式庫 ID" + }, + "title": { + "edit": "編輯", + "command": "命令", + "script": "腳本", + "waitCommand": "等待 {command}", + "waitCell": "等待工作階段 {id}", + "terminateCommand": "終止 {command}", + "terminateCell": "終止工作階段 {id}", + "stdinChars": "輸入 {chars}", + "todoWrite": "待辦", + "read": "讀取", + "write": "寫入", + "notebookEdit": "Notebook 編輯", + "editFiles": "編輯({count} 個檔案)", + "editWithTarget": "編輯 {target}", + "readWithTarget": "讀取 {target}", + "writeWithTarget": "寫入 {target}", + "notebookEditWithTarget": "Notebook 編輯 {target}", + "globWithPattern": "Glob {pattern}", + "listFilesWithPath": "列出檔案 {path}", + "grepWithPattern": "Grep {pattern}", + "taskCreateWithSubject": "建立任務:{subject}", + "taskUpdateWithStatus": "更新任務 #{id} -> {status}", + "taskUpdate": "更新任務 #{id}", + "webFetchWithUrl": "擷取網頁 {url}", + "webSearchWithQuery": "網頁搜尋:{query}", + "todosProgress": "待辦({done}/{total})", + "skillWithName": "Skill:{name}", + "genericWithContext": "{tool}:{context}" + }, + "search": { + "noMatches": "無相符結果", + "matchSummary": "{matches} 處相符 · {files} 個檔案", + "fileSummary": "{files} 個檔案", + "moreResults": "另有 {count} 筆結果未顯示" + }, + "toolGroup": { + "search": "搜尋 {count} 次", + "command": "執行 {count} 個指令", + "read": "讀取 {count} 次檔案", + "memory": "回憶 {count} 項記憶", + "edit": "編輯 {count} 次檔案", + "fetch": "抓取 {count} 個資源", + "think": "思考 {count} 次", + "todo": "更新 {count} 項待辦", + "task": "執行 {count} 個任務", + "other": "呼叫 {count} 個工具", + "errorSuffix": "{count} 個失敗", + "joiner": " · " + }, + "planMode": { + "entered": "進入計畫模式", + "planLabel": "計畫", + "reviewApproved": "已核准執行計畫", + "reviewKept": "維持在計畫模式", + "reviewPending": "等待計畫決定", + "submitted": "計畫已提交", + "switched": "切換模式" + }, + "backgroundTask": { + "title": "背景任務", + "titleWithId": "背景任務 · {id}", + "running": "執行中", + "completed": "已完成", + "failed": "失敗", + "stopped": "已停止", + "exitCode": "退出碼 {code}", + "polledTimes": "輪詢 {count} 次", + "runningInBackground": "背景執行", + "launchNote": "已在背景執行 · {id}" + }, + "codexScript": { + "outputMissing": "codex 截斷指令碼輸出時捨棄了這個命令的分隔行,因此沒有輸出可歸屬給它。", + "sharedWith": "本段還包含 {commands} 的輸出——它們的分隔行已被 codex 截斷捨棄。", + "truncated": "已截斷" + } + }, + "messageNav": { + "title": "訊息導覽", + "collapse": "收合訊息導覽", + "collapsedSummary": "訊息 {count}", + "fileCount": "{count} 個檔案", + "remove": "移除", + "noDiffDataAvailable": "找不到 {filePath} 的差異資料" + }, + "replyArtifacts": { + "title": "變更檔案", + "fileCount": "{count} 個檔案", + "newFilesTitle": "新增檔案", + "revealInFolder": "在 Finder/檔案總管中顯示", + "openFile": "開啟 {filePath}", + "openInEditor": "在編輯器中開啟", + "remove": "移除", + "noDiffDataAvailable": "找不到 {filePath} 的差異資料" + }, + "askQuestion": { + "title": "智能體需要你的選擇", + "subtitle": "回答後點擊提交,可隨時跳過", + "recommended": "推薦", + "other": "其他", + "otherPlaceholder": "輸入你的回答…", + "singleSelect": "單選", + "multiSelect": "多選", + "skip": "略過", + "next": "下一題", + "submit": "提交", + "submitError": "提交失敗,請重試。" + }, + "planApproval": { + "title": "智慧代理已提出計畫——請審閱", + "emptyPlan": "智慧代理未寫入計畫。可核准開始實作,或要求修改。", + "approve": "核准並開始", + "requestChanges": "要求修改", + "abandon": "放棄", + "feedbackPlaceholder": "需要修改什麼?", + "sendChanges": "傳送", + "cancel": "取消", + "submitError": "提交失敗,請重試。" + }, + "feedbackCheckResult": { + "count": "{count} 則回饋", + "expand": "展開全部回饋", + "collapse": "收合", + "errorTitle": "回饋檢查失敗" + }, + "askQuestionResult": { + "title": "提問", + "answeredLabel": "提問回答:", + "awaiting": "等待你的回答…", + "declined": "你已略過此問題 — 代理已自行判斷。", + "noSelection": "未選擇" + }, + "configStale": { + "agentConfigTitle": "智能體設定已更新", + "modelProviderTitle": "模型供應商已更新", + "description": "目前的工作階段仍在使用舊設定,重新連線後生效(對話紀錄不會遺失)。", + "reconnect": "重新連線以套用", + "reconnecting": "正在重新連線…", + "reconnectDisabledDuringTurn": "目前回合結束後可重新連線", + "dismiss": "忽略", + "reconnectFailed": "重新連線工作階段失敗", + "applied": "已套用新設定" + }, + "piProjectTrust": { + "title": "此專案自帶 pi 資源", + "description": "pi 未載入儲存庫自帶的 .pi 檔案。請檢視後決定。", + "descriptionExecutable": "儲存庫自帶 pi 擴充功能,擴充功能會在啟動時執行程式碼。pi 尚未載入它們,請先檢視再決定。", + "review": "檢視…", + "dismiss": "忽略", + "dialogTitle": "信任此專案的 pi 資源?", + "dialogDescription": "只有在你信任該目錄後,pi 才會載入儲存庫自帶的 .pi 檔案。請僅在你信任此儲存庫內容時才信任。", + "executionWarning": "擴充功能就是程式碼。信任該目錄後,儲存庫中的擴充功能會在 pi 啟動時以你的權限執行——早於你送出任何訊息。", + "scopeNote": "此決定儲存在 pi 的 trust.json 中,對該目錄下的所有子目錄同樣生效,你在終端機自行執行 pi 時也會沿用。之後可在「設定 → 智慧代理 → Pi」中修改。", + "trust": "信任專案", + "decline": "保持不載入", + "disabledDuringTurn": "目前回合結束後可用", + "trustedToast": "已信任專案——已重新連線以便 pi 載入其資源", + "declinedToast": "專案資源保持不載入", + "saveFailed": "儲存專案信任決定失敗", + "grantTitle": "此專案已被信任", + "grantDescription": "pi 會載入此儲存庫自帶的 .pi 檔案。請檢視這代表什麼。", + "grantInheritedDescription": "某個上層目錄已被信任,因此 pi 會載入此儲存庫自帶的 .pi 檔案。請檢視這代表什麼。", + "grantDialogTitle": "此專案的 pi 資源已被信任", + "grantDialogDescription": "pi 被允許載入此儲存庫自帶的 .pi 檔案。舊版 codeg 會在你開啟目錄時自動授予此權限,因此你可能從未被詢問過。", + "grantExecutionWarning": "擴充功能就是程式碼。儲存庫中的擴充功能會在 pi 啟動時以你的權限執行——早於你送出任何訊息。", + "inheritedFrom": "信任來自", + "revoke": "撤銷信任", + "keepTrusted": "保持信任", + "revokedToast": "已撤銷信任——已重新連線,pi 不再載入此專案的資源", + "trustedNoReconnect": "已信任專案——將在 pi 下次啟動時生效", + "revokedNoReconnect": "已撤銷信任——將在 pi 下次啟動時生效" + }, + "collabAgent": { + "title": "子智能體", + "errorTitle": "子智能體任務失敗", + "statesLabel": "子智能體", + "statusRunning": "執行中", + "statusCompleted": "已完成", + "statusFailed": "失敗", + "statusPending": "初始化中", + "statusInterrupted": "已中斷", + "statusClosed": "已關閉", + "statusNotFound": "未找到", + "opSpawn": "啟動子智能體", + "opWait": "取得子智能體結果", + "opClose": "結束子智能體", + "opResume": "恢復子智能體" + }, + "contextCompaction": { + "compacting": "正在壓縮上下文…", + "compacted": "上下文已壓縮", + "compactedTokens": "上下文已壓縮 · {before} → {after} tokens", + "failed": "上下文壓縮失敗" + }, + "sessionFailure": { + "category": { + "connection": "連線異常", + "access": "存取受限", + "limit": "已達限制", + "request": "請求被拒絕", + "service": "服務異常", + "unknown": "會話異常" + }, + "action": { + "retry": "重試", + "login": "去登入", + "newSession": "新增會話" + }, + "recovered": "已恢復", + "retryUnavailable": "沒有可重發的訊息。", + "toggleDetails": "展開/收合詳情" + }, + "backgroundTasks": { + "running": "{count} 個背景任務執行中", + "settling": "正在同步背景結果…", + "settledFallback": "背景任務已結束({status})", + "cardRunning": "背景執行中", + "cardLaunchedPending": "已啟動背景任務", + "cardCompleted": "背景任務已完成", + "cardFinishedWithStatus": "背景任務已結束({status})", + "cardResultPending": "結果尚未返回" + }, + "proposedPlan": { + "title": "計劃提案", + "planning": "規劃中…" + } + }, + "diffPreview": { + "mode": { + "added": "新增", + "deleted": "刪除", + "renamed": "重新命名", + "modified": "修改" + }, + "hunkLabel": "區塊 {index}", + "loadingHunk": "正在載入區塊...", + "noDiffData": "無差異資料", + "showRemainingLines": "顯示剩餘 {count} 行" + }, + "conversationContextBar": { + "folderTitle": "工作資料夾", + "branchTitle": "工作分支", + "searchFolder": "Search folder...", + "searchBranch": "Search branch...", + "noFolders": "No folders", + "noBranches": "No branches", + "noBranch": "(no branch)", + "chatModeLabel": "聊天模式", + "commit": "Commit", + "push": "Push", + "merge": "Merge", + "toasts": { + "folderChanged": "Switched to {name}", + "openFolderFailed": "Failed to open folder", + "switchedToChatMode": "已切換到聊天模式", + "openStashFailed": "Failed to open stash window", + "openMergeFailed": "Failed to open merge window" + } + }, + "cloneDialog": { + "title": "複製倉庫", + "repositoryUrl": "倉庫地址", + "repositoryUrlPlaceholder": "https://github.com/user/repo.git", + "directory": "目錄", + "directoryPlaceholder": "選擇目標目錄...", + "browseDirectory": "瀏覽目錄", + "cancel": "取消", + "clone": "複製", + "clonePath": "克隆路徑: {path}" + }, + "toasts": { + "cloneFailed": "複製倉庫失敗" + } + }, + "ProjectBoot": { + "title": "專案啟動器", + "tabs": { + "shadcn": "shadcn", + "hyperframes": "HyperFrames" + }, + "hyperframes": { + "title": "HyperFrames 影片專案", + "subtitle": "建立一個 HTML 轉影片專案,接著工作區的智慧代理即可撰寫並算繪它。", + "resolution": "解析度", + "skillsTitle": "智慧代理技能", + "skillsDesc": "為所選代理全域安裝 HyperFrames 技能(符號連結),讓它們會編寫並算繪影片。", + "recheck": "重新檢查", + "installedBadge": "已安裝", + "skillsInstall": "安裝 / 更新技能", + "skillsInstalling": "正在安裝技能…", + "skillsInstalled": "HyperFrames 技能安裝成功", + "skillsInstallFailed": "HyperFrames 技能安裝失敗" + }, + "config": { + "base": "基礎庫", + "style": "風格", + "baseColor": "基礎顏色", + "theme": "主題", + "chartColor": "圖表顏色", + "iconLibrary": "圖示庫", + "font": "字體", + "fontHeading": "標題字體", + "menuAccent": "選單強調", + "menuColor": "選單顏色", + "radius": "圓角", + "template": "模板", + "createProject": "建立專案", + "sectionStyle": "風格", + "sectionColors": "配色", + "sectionTypography": "排版", + "sectionInterface": "介面" + }, + "preview": { + "loading": "載入預覽..." + }, + "createDialog": { + "title": "建立專案", + "projectName": "專案名稱", + "projectNamePlaceholder": "my-app", + "frameworkTemplate": "框架模板", + "packageManager": "套件管理器", + "saveDirectory": "儲存目錄", + "saveDirectoryPlaceholder": "選擇目錄...", + "browseDirectory": "瀏覽", + "projectPath": "專案將建立在:{path}", + "advancedOptions": "進階選項", + "base": "基礎庫", + "enableRtl": "啟用 RTL 支援", + "enableRtlDescription": "為從右到左書寫的語言(如阿拉伯語、希伯來語)啟用佈局支援", + "pmChecking": "正在檢測...", + "pmNotInstalled": "未安裝", + "cancel": "取消", + "create": "建立", + "creating": "正在建立專案..." + }, + "toasts": { + "createFailed": "建立專案失敗", + "createSuccess": "專案建立成功", + "openWorkspaceFailed": "專案已建立,但無法在工作區中開啟" + }, + "errors": { + "directoryExists": "目標目錄已存在", + "commandFailed": "專案建立命令執行失敗。" + } + }, + "WebServiceSettings": { + "addressSwitchHint": "切換只會改變這裡顯示與開啟的位址;服務會監聽所有網路介面,每個位址都可存取。", + "sectionTitle": "Web 服務", + "sectionDescription": "啟用後可透過瀏覽器遠端存取 Codeg", + "port": "連接埠", + "status": "狀態", + "autoStart": "自動啟動", + "autoStartHint": "Codeg 啟動時自動開啟 Web 服務", + "running": "執行中", + "stopped": "已停止", + "processing": "處理中...", + "start": "啟動", + "stop": "停止", + "startFailed": "啟動失敗", + "stopFailed": "停止失敗", + "saveConfigFailed": "儲存 Web 服務設定失敗", + "open": "開啟", + "hide": "隱藏", + "show": "顯示", + "copy": "複製", + "qrcode": "QR 碼", + "qrcodeTitle": "掃碼開啟", + "qrcodeHint": "用手機掃描,在瀏覽器中開啟 Codeg", + "addressLabel": "存取位址", + "tokenLabel": "存取 Token", + "tokenHint": "Web 用戶端首次存取時需輸入此 Token", + "tokenPlaceholder": "留空則自動產生", + "regenerate": "重新產生", + "stalePortOccupiedTitle": "連接埠 {port} 已被其他行程佔用", + "stalePortUnknownTitle": "連接埠 {port} 狀態不明", + "stalePortHint": "在連接埠釋放前 Codeg 無法繫結。可以更換上方的連接埠,或結束佔用該連接埠的行程。", + "errors": { + "alreadyRunning": "Web 服務已在執行", + "invalidAddress": "主機或連接埠格式無效", + "portInUse": "連接埠 {port} 已被佔用,請關閉佔用的程式或改用其他連接埠", + "permissionDenied": "權限不足,請使用 1024 以上的連接埠,或以更高權限執行", + "addressUnavailable": "該位址在本機不可用", + "bindFailed": "綁定位址失敗" + } + }, + "DirectoryBrowser": { + "title": "瀏覽目錄", + "pathPlaceholder": "輸入目錄路徑...", + "goHome": "回到主目錄", + "navigateUp": "返回上層目錄", + "select": "選擇", + "cancel": "取消", + "loading": "載入中...", + "emptyDirectory": "此目錄為空", + "errorLoadingDir": "載入目錄失敗", + "permissionDenied": "權限不足" + }, + "ChatChannelSettings": { + "loading": "載入中...", + "sectionTitle": "訊息頻道", + "sectionDescription": "設定 IM 機器人,接收事件通知和查詢編碼活動。", + "addChannel": "新增頻道", + "noChannels": "尚未設定任何訊息頻道。", + "channelName": "名稱", + "channelNamePlaceholder": "我的 Telegram 機器人", + "channelType": "頻道類型", + "lark": "飛書", + "weixin": "微信", + "dailyReport": "每日報告", + "dailyReportTime": "推送時間", + "nameRequired": "請輸入頻道名稱。", + "tokenRequired": "請輸入 Token。", + "chatIdRequired": "請輸入 Chat ID。", + "topicMode": "話題群模式", + "topicModeHint": "將 Telegram forum topics 路由為獨立 Codeg 對話。Bot 必須加入 forum supergroup,並擁有管理 topics 權限。", + "loadFailed": "載入頻道失敗。", + "saveFailed": "儲存失敗。", + "connectSuccess": "頻道已連線。", + "connectFailed": "連線失敗", + "disconnectSuccess": "頻道已斷線。", + "disconnectFailed": "斷線失敗。", + "testSuccess": "連線測試通過。", + "testFailed": "連線測試失敗", + "deleteSuccess": "頻道已刪除。", + "deleteFailed": "刪除頻道失敗。", + "deleteConfirmTitle": "刪除頻道", + "deleteConfirmMessage": "將永久刪除該頻道及其訊息紀錄,確定嗎?", + "cancel": "取消", + "delete": "刪除", + "create": "建立", + "save": "儲存", + "channelListTitle": "已設定頻道", + "channelListDescription": "已啟用的頻道在服務啟動時會自動連線。", + "editChannel": "編輯頻道", + "editSuccess": "頻道已更新。", + "tokenPlaceholderKeep": "留空保持不變", + "weixinScanTitle": "掃碼登入", + "weixinScanDescription": "打開微信掃描二維碼以連接。", + "weixinQrcodeExpired": "二維碼已過期。", + "weixinRefreshQrcode": "重新整理", + "weixinWaitingScan": "等待掃碼...", + "weixinPollError": "連接不穩定,正在重試...", + "weixinReconnectNotice": "因 iLink 協議限制,每次重新連接後需先主動向機器人發送一條訊息,事件觸發才會生效。", + "connect": "連線", + "disconnect": "斷開", + "test": "測試連線", + "tabs": { + "channels": "頻道", + "commands": "指令", + "events": "事件", + "other": "其他" + }, + "commands": { + "title": "內建指令", + "description": "訊息頻道中可用的 Bot 指令。群組聊天中需 @Bot 才會處理訊息。", + "prefixLabel": "指令前綴", + "prefixDescription": "觸發 Bot 指令的前綴,1-3 個非字母數字字元(預設 /)。", + "prefixSaved": "指令前綴已儲存。", + "prefixSaveFailed": "儲存指令前綴失敗。", + "prefixInvalid": "前綴必須是 1-3 個非字母數字字元。", + "save": "儲存", + "folderDesc": "選擇工作目錄", + "agentDesc": "選擇 AI Agent", + "taskDesc": "建立會話並執行任務", + "sessionsDesc": "列出當前目錄的活躍會話", + "resumeDesc": "最近對話 / 恢復指定對話", + "cancelDesc": "取消當前任務", + "approveDesc": "批准 Agent 權限請求", + "denyDesc": "拒絕 Agent 權限請求", + "searchDesc": "依關鍵字搜尋對話", + "todayDesc": "今日活動摘要", + "statusDesc": "頻道連線狀態", + "helpDesc": "顯示說明" + }, + "events": { + "title": "事件通知", + "description": "啟用事件後,事件被觸發時將推送到頻道。", + "turnComplete": "對話完成", + "turnCompleteDesc": "代理回合結束時", + "error": "代理錯誤", + "errorDesc": "代理遇到錯誤時", + "permissionRequest": "權限請求", + "permissionRequestDesc": "智慧代理請求操作權限時", + "questionRequest": "智慧代理提問", + "questionRequestDesc": "當智慧代理向你提問時", + "userPromptSent": "使用者訊息", + "userPromptSentDesc": "當你傳送訊息時——通知中會包含訊息內容", + "saved": "事件篩選已更新。", + "saveFailed": "儲存事件篩選失敗。", + "loadFailed": "載入設定失敗。", + "retry": "重試", + "webhooksTitle": "Webhook", + "webhooksDescription": "事件觸發時,向一個或多個位址 POST 一份 JSON。上方的事件篩選同樣作用於 Webhook。", + "webhookUrlPlaceholder": "https://example.com/webhook", + "addWebhook": "新增 Webhook", + "removeWebhook": "刪除 Webhook", + "webhookSave": "儲存", + "webhooksSaved": "Webhook 已儲存。", + "webhooksSaveFailed": "儲存 Webhook 失敗。", + "webhookInvalidUrl": "請輸入有效的 http(s) 位址。", + "docsTitle": "請求格式", + "docsMethod": "請求方式", + "docsContentType": "內容類型", + "docsNote": "每個啟用的事件都會投遞到所有位址。Webhook 不做去抖;上方的事件篩選仍然生效。", + "editWebhook": "編輯 Webhook", + "enableWebhook": "啟用 Webhook", + "webhookDuplicate": "該位址已設定。", + "cancel": "取消", + "webhooksEmpty": "尚未設定 Webhook。", + "deleteWebhookTitle": "刪除 Webhook", + "deleteWebhookMessage": "刪除此 Webhook?事件將不再傳送到該網址。", + "delete": "刪除" + }, + "language": { + "title": "訊息語言", + "description": "事件通知、指令回應和每日報告推送到訊息頻道時使用的語言。", + "saved": "訊息語言已儲存。", + "saveFailed": "儲存訊息語言失敗。", + "en": "英語", + "zh-cn": "簡體中文", + "zh-tw": "繁體中文", + "ja": "日語", + "ko": "韓語", + "es": "西班牙語", + "de": "德語", + "fr": "法語", + "pt": "葡萄牙語", + "ar": "阿拉伯語" + } + }, + "ModelProviderSettings": { + "sectionTitle": "模型供應商", + "sectionDescription": "管理 Agent 的 API 供應商憑據。", + "filterAll": "全部", + "providerListTitle": "已配置的供應商", + "addProvider": "新增供應商", + "editProvider": "編輯供應商", + "noProviders": "尚未配置模型供應商。", + "providerName": "名稱", + "providerNamePlaceholder": "例如 OpenAI、Anthropic", + "apiUrl": "API 位址", + "apiUrlPlaceholder": "https://api.openai.com/v1", + "apiKey": "API 金鑰", + "apiKeyPlaceholder": "sk-...", + "apiKeyKeepCurrent": "留空則保持不變", + "agentTypes": "代理類型", + "agentTypesRequired": "至少選擇一個代理類型。", + "agentType": "智能體類型", + "agentTypeRequired": "請選擇智能體類型。", + "agentTypeImmutableHint": "智能體類型建立後不可修改。", + "model": "模型", + "modelPlaceholderCodex": "gpt-5.6-sol / gpt-5.5", + "modelPlaceholderGemini": "gemini-3-pro-preview", + "claudeMainModel": "主要模型", + "claudeReasoningModel": "推理模型(思考)", + "claudeHaikuDefaultModel": "預設 Haiku 模型", + "claudeSonnetDefaultModel": "預設 Sonnet 模型", + "claudeOpusDefaultModel": "預設 Opus 模型", + "claudeCustomModelOption": "自訂模型 ID", + "claudeCustomModelOptionName": "自訂模型名稱", + "claudeCustomModelOptionDescription": "自訂模型描述", + "claudeCustomModelOptionHint": "在 Claude 模型選擇器中新增一個自訂項目(例如透過自訂閘道/代理提供的模型)。名稱與描述為選填的顯示資訊。", + "nameRequired": "供應商名稱不能為空。", + "apiUrlRequired": "API 位址不能為空。", + "apiKeyRequired": "API 金鑰不能為空。", + "loadFailed": "載入供應商失敗。", + "saveFailed": "儲存變更失敗。", + "createSuccess": "供應商已建立。", + "editSuccess": "供應商已更新。", + "deleteSuccess": "供應商已刪除。", + "deleteConfirmTitle": "刪除供應商", + "deleteConfirmMessage": "確定要永久刪除供應商「{name}」嗎?", + "deleteBlockedByAgent": "{agents} 正在使用此設定,請先解除關聯後再刪除。", + "cancel": "取消", + "delete": "刪除", + "create": "建立", + "save": "儲存", + "affectedRunningSessions": "{count} 個進行中的工作階段需重新連線以套用變更" + }, + "SkillMatrix": { + "loading": "載入中…", + "searchPlaceholder": "依名稱、ID 或描述搜尋", + "empty": "暫無內容。", + "emptySearch": "沒有符合目前搜尋的結果。", + "skillColumn": "技能", + "selectAll": "全選可見項目", + "selectSkill": "選擇 {name}", + "everything": { + "label": "批次", + "enable": "全部啟用(可見)", + "disable": "全部停用(可見)" + }, + "columnMenu": { + "enableAll": "啟用全部技能", + "disableAll": "停用全部技能" + }, + "rowMenu": { + "label": "對 {name} 批次操作", + "enableAll": "對所有 agent 啟用", + "disableAll": "對所有 agent 停用" + }, + "bulk": { + "selected": "已選擇 {count} 項", + "targetAll": "全部 agent", + "targetSome": "{count} 個 agent", + "enable": "啟用", + "disable": "停用", + "clear": "清除" + }, + "confirm": { + "disableTitle": "停用這些連結?", + "disableBody": "這將移除 {count} 個由 codeg 管理的技能連結。佔用自訂目錄的技能不受影響。你可以隨時重新啟用。", + "cancel": "取消", + "confirm": "停用" + }, + "toasts": { + "loadFailed": "載入技能狀態失敗", + "applyFailed": "套用變更失敗", + "enabled": "已啟用 {count} 個連結", + "disabled": "已停用 {count} 個連結", + "enabledPartial": "已啟用 {ok} 個,{failed} 個失敗", + "disabledPartial": "已停用 {ok} 個,{failed} 個失敗" + }, + "detail": { + "enableForAgents": "為 agent 啟用", + "preview": "SKILL.md 預覽", + "loadingContent": "載入內容中…" + }, + "copyModeHint": "已複製(非連結)——更新後請重新啟用以取得最新版本" + }, + "ExpertsSettings": { + "title": "專家技能", + "description": "為 AI 編碼代理啟用精心挑選、經過實戰驗證的技能工作流程。每個專家都是 superpowers 專案中的獨立技能 —— codeg 維護中央副本,並將其軟連結到你選擇的代理目錄。", + "loading": "正在載入專家清單…", + "loadingContent": "正在載入內容…", + "emptyExperts": "目前沒有可用的專家,請查看應用程式日誌。", + "emptySelection": "從左側選擇一個專家以檢視內容並管理啟用狀態。", + "emptySearch": "沒有符合目前搜尋條件的專家。", + "searchPlaceholder": "依名稱、ID 或描述搜尋專家", + "enableForAgents": "為代理啟用", + "noAgents": "未偵測到 ACP 代理。", + "copyModeWarning": "已複製(非軟連結)。codeg 更新後需要重新啟用以取得最新版本。", + "previewTitle": "SKILL.md 預覽", + "categories": { + "discovery": "探索與設計", + "planning": "規劃", + "execution": "執行", + "quality": "品質與測試", + "debugging": "除錯", + "review": "審查與整合", + "meta": "後設技能" + }, + "states": { + "not_linked": "未啟用", + "linked_to_codeg": "已啟用", + "linked_elsewhere": "衝突 — 已有其他連結", + "blocked_by_real_directory": "衝突 — 已有同名的自訂 skill 佔用", + "broken": "連結損壞" + }, + "badges": { + "userModified": "使用者修改過" + }, + "actions": { + "openCentralDir": "開啟中央目錄", + "refresh": "重新整理" + }, + "toasts": { + "loadFailed": "載入專家詳情失敗", + "enabled": "已為該代理啟用專家", + "disabled": "已為該代理停用專家", + "enableFailed": "啟用專家失敗", + "disableFailed": "停用專家失敗", + "openFolderFailed": "開啟目錄失敗" + } + }, + "ScienceSettings": { + "title": "科學研究技能", + "description": "為你的 AI 編碼智能體啟用精選的科學研究技能:假設生成、實驗設計、統計、視覺化、批判性評估與文獻檢索。codeg 管理中央副本,並將每個技能連結到你選擇的智能體。", + "loading": "正在載入科學研究技能…", + "emptySkills": "沒有可用的科學研究技能。請檢查應用程式日誌。", + "searchPlaceholder": "依名稱、ID 或描述搜尋科學研究技能", + "categories": { + "ideation": "構思", + "design": "研究設計", + "analysis": "分析", + "visualization": "視覺化", + "evaluation": "評估", + "literature": "文獻" + }, + "states": { + "not_linked": "未啟用", + "linked_to_codeg": "已啟用", + "linked_elsewhere": "衝突 — 已有其他連結", + "blocked_by_real_directory": "衝突 — 已有同名的自訂 skill 佔用", + "broken": "連結損壞" + }, + "badges": { + "userModified": "使用者修改過", + "needsKey": "需要金鑰", + "needsSetup": "可能需環境" + }, + "actions": { + "openCentralDir": "開啟中央目錄", + "refresh": "重新整理" + }, + "toasts": { + "openFolderFailed": "開啟目錄失敗" + } + }, + "OfficeToolsSettings": { + "title": "Office 工具", + "description": "管理 OfficeCLI 技能,用於建立 Excel、Word 和 PowerPoint 檔案。安裝 OfficeCLI,同步技能,並為每個智慧體啟用。", + "loadingContent": "載入內容中…", + "emptySkills": "暫無技能。請先安裝 OfficeCLI 並同步技能。", + "emptySelection": "選擇一個技能查看內容和管理啟用狀態。", + "emptySearch": "沒有匹配的技能。", + "searchPlaceholder": "按名稱、ID 或描述搜尋技能", + "enableForAgents": "為智慧體啟用", + "noAgents": "未偵測到 ACP 智慧體。", + "installFirst": "請先安裝 OfficeCLI 以啟用技能。", + "syncFirst": "請先同步技能以載入內容。", + "noContent": "暫無內容。", + "copyModeWarning": "已複製(非連結)。重新同步以取得最新版本。", + "previewTitle": "SKILL.md 預覽", + "detection": { + "installed": "已安裝", + "notInstalled": "未安裝", + "notRunnable": "已安裝但無法執行", + "installHint": "安裝 OfficeCLI 以為 AI 智慧體啟用辦公文件生成技能。", + "install": "安裝", + "uninstall": "解除安裝", + "syncSkills": "同步技能" + }, + "categories": { + "general": "通用", + "presentations": "簡報", + "documents": "文件", + "spreadsheets": "試算表" + }, + "states": { + "not_linked": "未啟用", + "linked_to_codeg": "已啟用", + "linked_elsewhere": "已阻止——存在其他連結", + "blocked_by_real_directory": "已阻止——自訂技能佔用此名稱", + "broken": "連結已損壞" + }, + "badges": { + "notSynced": "未同步" + }, + "actions": { + "refresh": "重新整理" + }, + "toasts": { + "loadFailed": "載入技能詳情失敗", + "enabled": "已為此智慧體啟用技能", + "disabled": "已為此智慧體停用技能", + "enableFailed": "啟用技能失敗", + "disableFailed": "停用技能失敗", + "installSuccess": "OfficeCLI 安裝成功", + "installFailed": "安裝 OfficeCLI 失敗", + "uninstallSuccess": "OfficeCLI 已解除安裝", + "uninstallFailed": "解除安裝 OfficeCLI 失敗", + "syncSuccess": "已成功同步 {synced} 個技能", + "syncPartial": "已同步 {synced} 個技能,{errors} 個失敗", + "syncFailed": "同步技能失敗" + }, + "autoPreviewLabel": "自動開啟預覽", + "autoPreviewHint": "當智慧代理建立或編輯 Word、Excel、PowerPoint 檔案時,自動開啟其即時預覽。" + }, + "SkillPacksSettings": { + "title": "技能包", + "description": "由 codeg 集中管理、並連結到各 AI 智慧代理的成套技能——程式設計專家、科學研究與辦公文件工具。可在下方依代理分別啟用。", + "tabs": { + "experts": "專家", + "science": "科學研究", + "office": "辦公工具", + "custom": "自訂" + }, + "actions": { + "openCentralDir": "開啟中央目錄", + "refresh": "重新整理" + }, + "toasts": { + "openFolderFailed": "開啟目錄失敗" + } + }, + "QuickMessagesSettings": { + "title": "快捷訊息", + "description": "管理可重用的訊息片段。拖曳以調整順序。", + "loading": "載入快捷訊息…", + "emptyList": "尚無快捷訊息。點擊「新增」建立一條。", + "emptySelection": "選擇一條快捷訊息進行編輯。", + "searchPlaceholder": "依標題或內容搜尋", + "untitled": "未命名", + "actions": { + "new": "新增", + "save": "儲存", + "delete": "刪除", + "dragSort": "拖曳排序", + "dragSortMessage": "拖曳排序快捷訊息:{name}" + }, + "fields": { + "title": "標題", + "titlePlaceholder": "為此訊息取一個簡短的標題", + "content": "內容", + "contentPlaceholder": "在此輸入訊息內容" + }, + "confirmDelete": { + "title": "刪除快捷訊息?", + "message": "將永久刪除「{name}」。確定嗎?", + "cancel": "取消", + "confirm": "刪除" + }, + "toasts": { + "loadFailed": "載入快捷訊息失敗", + "createFailed": "建立快捷訊息失敗", + "saveFailed": "儲存快捷訊息失敗", + "deleteFailed": "刪除快捷訊息失敗", + "saveOrderFailed": "儲存順序失敗", + "created": "已建立快捷訊息", + "saved": "已儲存快捷訊息", + "deleted": "已刪除快捷訊息" + } + }, + "Pet": { + "badge": { + "running": "{count} 個執行中", + "waiting": "{count} 個待核准", + "error": "{count} 個發生錯誤" + }, + "panel": { + "title": "活動工作階段", + "empty": "沒有活動工作階段", + "emptyHint": "正在執行或需要你處理的工作階段會顯示在這裡。", + "statusRunning": "執行中", + "statusWaiting": "等待中", + "statusError": "發生錯誤", + "subAgentOf": "子智慧代理" + }, + "menu": { + "scale": "縮放", + "openManager": "管理寵物", + "close": "關閉" + }, + "loadError": "載入寵物失敗", + "missingPetIdParam": "未選中任何寵物", + "summonButton": "寵物", + "manager": { + "title": "桌面寵物", + "description": "懸浮在桌面上的夥伴,使用與 Codex 相容的精靈圖。", + "addPet": "新增寵物", + "importFromCodex": "從 Codex 匯入", + "noPets": "暫無寵物。可以新增一隻,或從 Codex 匯入。", + "setActive": "設為使用中", + "active": "使用中", + "edit": "編輯", + "delete": "刪除", + "deleteConfirm": "確認刪除寵物「{name}」嗎?會從磁碟上一併移除。", + "summon": "召喚寵物視窗", + "openCodexHelp": "Codex 寵物需位於 ~/.codex/pets/ 目錄下,但未找到。", + "specRequirement": "精靈圖寬度必須為 1536 像素,高度需為 208 像素的整數倍(如 1872 或 2288),並為帶透明通道的 PNG 或 WebP。", + "form": { + "id": "寵物 ID", + "idHelp": "僅允許小寫字母、數字、'-' 和 '_',最多 64 字元。", + "displayName": "顯示名稱", + "description": "描述 (選填)", + "spritesheet": "精靈圖", + "chooseFile": "選擇檔案", + "replaceFile": "替換精靈圖", + "saveCreate": "新增寵物", + "saveUpdate": "儲存變更", + "cancel": "取消" + }, + "errors": { + "missingId": "寵物 ID 不能為空", + "missingName": "顯示名稱不能為空", + "missingSpritesheet": "必須選擇一個精靈圖", + "addFailed": "新增寵物失敗", + "updateFailed": "更新寵物失敗", + "deleteFailed": "刪除寵物失敗", + "loadFailed": "載入寵物列表失敗", + "setActiveFailed": "設定活躍寵物失敗", + "summonFailed": "召喚寵物視窗失敗" + } + }, + "import": { + "title": "從 Codex 匯入", + "subtitle": "在 ~/.codex/pets/ 下找到以下可匯入的寵物。", + "selectAll": "全選", + "alreadyImported": "已匯入", + "renameOnConflict": "衝突時自動加上 -imported 後綴", + "import": "匯入所選", + "noneFound": "未找到可匯入的 Codex 寵物。", + "imported": "匯入完成", + "failed": "匯入失敗", + "close": "關閉" + }, + "marketplace": { + "openMarketplace": "寵物市集", + "title": "寵物市集", + "search": "搜尋寵物", + "kindFilter": { + "all": "全部", + "object": "物品", + "animal": "動物", + "person": "人物", + "creature": "生物" + }, + "sortFilter": { + "latest": "最新", + "popular": "熱門", + "views": "最多瀏覽" + }, + "refresh": "重新整理", + "install": "安裝", + "installing": "安裝中", + "reinstall": "重新安裝", + "reinstallConfirm": "確認覆蓋本機寵物 \"{name}\" 嗎?現有資料將被取代。", + "cancel": "取消", + "stats": { + "views": "瀏覽", + "downloads": "下載", + "likes": "讚" + }, + "actions": { + "idle": "待機", + "running_right": "右跑", + "running_left": "左跑", + "waving": "揮手", + "jumping": "跳躍", + "failed": "失敗", + "waiting": "等待", + "running": "執行", + "review": "審閱" + }, + "page": "第 {page} / {total} 頁", + "prev": "上一頁", + "next": "下一頁", + "empty": "沒有符合的寵物。", + "successInstalled": "已安裝 \"{name}\"", + "errors": { + "loadFailed": "載入市集失敗", + "installFailed": "安裝失敗", + "alreadyInstalled": "該寵物已存在" + } + } + }, + "RemoteWorkspace": { + "openRemoteWorkspace": "Open remote workspace", + "manage": "Manage remote workspace", + "manageTitle": "Remote Workspace connections", + "empty": "No remote connections", + "searchPlaceholder": "Search remote workspaces", + "orderFailed": "Failed to save remote workspace order", + "dragSort": "Drag to sort", + "dragSortConnection": "Drag to sort {name}", + "newConnection": "New connection", + "loading": "Loading", + "loadingConnection": "Loading remote connection", + "name": "Name", + "baseUrl": "Service URL", + "token": "Access token", + "save": "Save", + "delete": "Delete", + "confirmDelete": { + "title": "Delete remote connection?", + "message": "This will remove \"{name}\" from this device. This action cannot be undone.", + "cancel": "Cancel", + "confirm": "Delete" + }, + "saved": "Remote connection saved.", + "deleted": "Remote connection deleted.", + "loadFailed": "Failed to load remote connections", + "saveFailed": "Failed to save remote connection", + "deleteFailed": "Failed to delete remote connection", + "openFailed": "Failed to open remote workspace", + "connectionLoadFailed": "Failed to load remote connection: {message}", + "connectionExpired": "Remote connection \"{name}\" is expired. Update its token and reload this window." + }, + "ServerFileBrowser": { + "title": "選擇伺服器檔案", + "pathPlaceholder": "輸入目錄路徑...", + "goHome": "回到主目錄", + "navigateUp": "返回上層目錄", + "select": "選擇", + "cancel": "取消", + "loading": "載入中...", + "emptyDirectory": "此目錄為空", + "errorLoadingDir": "載入目錄失敗", + "selectedCount": "已選 {count} 項" + }, + "BackupSettings": { + "title": "備份與還原", + "description": "匯出一份可攜的 codeg 資料備份,或從備份還原。", + "tabs": { + "backup": "備份", + "restore": "還原" + }, + "export": { + "includeExternal": "包含對話內容", + "includeExternalHint": "一併打包各 CLI 的對話記錄(Claude、Codex、Gemini 等),體積更大。", + "passphrase": "通行碼(選填)", + "passphrasePlaceholder": "留空則產生未加密的封存檔", + "passphraseConfirm": "確認通行碼", + "passphraseMismatch": "兩次輸入的通行碼不一致。", + "noPassphraseWarning": "此備份將以明文包含密鑰(API key、token)。請妥善保管。", + "passphraseLossWarning": "將以此通行碼加密。通行碼一旦遺失,備份將無法還原。", + "button": "匯出備份", + "inProgress": "正在建立備份…", + "success": "備份已建立。", + "started": "已開始下載備份。" + }, + "restore": { + "selectFile": "選擇備份檔案", + "passphrasePrompt": "此備份已加密,請輸入其通行碼。", + "unlock": "解鎖", + "preview": { + "title": "備份詳情", + "encrypted": "已加密", + "compatible": "相容", + "incompatible": "不相容", + "createdAt": "建立時間:{value}", + "appVersion": "應用程式版本:{value}", + "incompatibleHint": "此備份由較新版本的 codeg 建立,無法還原。" + }, + "replaceWarning": "還原將取代目前全部 codeg 資料(資料庫與上傳檔案)。目前資料會先做快照以便復原。", + "keyringNote": "桌面端的 GitHub/聊天 token 存於系統鑰匙圈,不包含在備份中;還原後需重新填寫。", + "button": "還原", + "staging": "正在準備還原…", + "staged": "還原已就緒,正在重新啟動…", + "restarting": "還原已就緒,正在重新啟動服務…", + "restartTimeout": "服務未能及時恢復。待其啟動後請重新整理頁面。", + "externalSideLocation": "對話記錄已還原至 {path}", + "confirmTitle": "取代全部資料?", + "confirmBody": "這將以備份取代目前的 codeg 資料庫與上傳檔案,然後重新啟動。目前資料會先做快照。", + "cancel": "取消", + "confirmAction": "取代並重新啟動", + "external": { + "title": "對話內容", + "hint": "此備份包含各 CLI 的對話記錄。請選擇還原到何處。", + "modeSkip": "不還原", + "modeSide": "還原到安全的旁路資料夾", + "modeOriginal": "還原到 CLI 的原始位置", + "forceOverwrite": "覆寫已存在的檔案", + "forceOverwriteHint": "取代 CLI 資料夾中已存在的檔案。", + "scanning": "正在檢查衝突…", + "noConflicts": "不會覆寫任何已存在的檔案。", + "conflictCount": "將影響 {count} 個已存在的檔案。", + "conflictSkipNote": "未啟用覆寫時,已存在的檔案將被保留(略過)。" + }, + "restartFailed": "還原已就緒,但伺服器未能重新啟動。請手動重新啟動以套用此次還原。" + }, + "remoteUnsupported": "備份與還原作用於執行 codeg 的那台機器上的資料。你目前連線的是遠端工作區——請直接在該伺服器上管理其備份。" + }, + "backup": { + "restore": { + "error": { + "badPassphrase": "通行碼錯誤或備份已損毀。", + "corrupted": "備份封存檔已損毀。", + "unknownFormat": "此檔案不是可識別的 codeg 備份。", + "newerVersion": "此備份由 codeg {backupVersion} 建立,比目前版本({appVersion})更新。", + "alreadyPending": "已有一個還原在等待生效。請先重新啟動套用它,再暫存新的還原。" + } + }, + "error": { + "diskSpace": "磁碟空間不足,無法完成操作。", + "cancelled": "操作已取消。" + } + }, + "WebConnection": { + "disconnectedTitle": "連線已中斷", + "reconnectingDescription": "正在嘗試重新連線伺服器,通常會在幾秒內自動恢復。", + "reconnectNow": "立即重新連線", + "sessionExpiredTitle": "工作階段已過期", + "sessionExpiredDescription": "登入狀態已失效,請重新登入以繼續。", + "goToLogin": "前往登入" + }, + "LiveFeedback": { + "placeholder": "在 {agent} 工作時給它留言…", + "agentFallback": "智能體", + "ariaLabel": "即時回饋留言", + "dialogTitle": "即時回饋", + "dialogDescription": "在智能體工作時給它留言。它會在下次檢查時讀取,不會打斷當前步驟。", + "dialogDescriptionInstant": "在智慧代理工作時傳送備註。備註會立即插入目前回合——代理馬上就能看到。", + "channelDowngraded": "本工作階段無法即時插入——備註已儲存,待代理下次檢查時讀取。", + "send": "送出", + "cancel": "取消", + "pending": "等待中", + "delivered": "已收到", + "turnEndedUnread": "智能體在讀取你的回饋前已結束本輪。", + "sendAsMessage": "作為新訊息送出", + "dismiss": "忽略", + "turnEndedResent": "本輪已結束——已改為作為新訊息送出。", + "turnEnded": "本輪已結束。", + "submitFailed": "留言送出失敗" + }, + "AgentToolsSettings": { + "title": "對話內工具", + "description": "codeg 在對話中額外提供給智慧代理的工具。工具會在代理啟動時注入,變更只對之後啟動的代理生效。", + "feedbackLabel": "即時回饋", + "feedbackHint": "在智慧代理工作時向它傳送備註與修正。支援即時插入的代理會立刻在目前回合中看到你的備註;其他代理則透過檢查回饋的工具讀取——這類代理通常只有在提示中提到時才會檢查,例如在訊息中加上「定期檢查我的即時回饋」。", + "questionLabel": "向使用者提問", + "questionHint": "允許智能體暫停並向你提出多選問題,問題會顯示在對話輸入框上方。智能體會一直等待,直到你作答(或略過)。", + "sessionInfoLabel": "取得工作階段資訊", + "sessionInfoHint": "允許智慧代理查詢你在訊息中提及的工作階段(工作階段徽章),讀取其標題、代理、狀態、工作區、Token 用量與最近訊息。", + "automationsLabel": "建立自動化", + "automationsHint": "把對話儲存為按排程執行的自動化。預設關閉——它之後會自行啟動代理。", + "workTasksLabel": "建立待辦任務", + "workTasksHint": "從對話中往待辦看板排一張任務卡。預設關閉——它會寫入應用程式狀態。", + "save": "儲存", + "saving": "儲存中…", + "saved": "工具設定已儲存", + "saveFailed": "儲存工具設定失敗", + "loadFailed": "載入失敗:{detail}" + }, + "NotificationSoundSettings": { + "title": "提示音", + "description": "智慧體事件觸發時播放一段簡短的提示音。這裡的事件與訊息通道推送的完全一致,但設定只對本裝置生效。", + "enableHint": "預設關閉。提示音只在目前瀏覽器或應用程式的工作區視窗中播放。", + "volume": "音量", + "preview": "試聽", + "previewEvent": "試聽「{event}」提示音", + "onlyWhenUnfocused": "僅在視窗未聚焦時播放", + "onlyWhenUnfocusedHint": "正在檢視 Codeg 時保持靜音。", + "eventsTitle": "事件", + "eventsHint": "為每個事件選擇一種音效,選擇「靜音」則不播放。同一事件在數秒內重複觸發時只播放一次。", + "toneNone": "靜音", + "toneChime": "叮咚", + "toneDing": "清鈴", + "toneBlip": "短音", + "tonePop": "輕點", + "toneAlert": "警示", + "toneDescend": "下行音" + }, + "LogsSettings": { + "loading": "載入中…", + "sectionTitle": "執行日誌", + "sectionDescription": "檢視與設定應用程式診斷日誌。日誌會寫入本機檔案,並保留在記憶體中以便即時檢視。", + "captureTitle": "日誌等級", + "captureDescription": "控制記錄的詳細程度。等級越高(Debug、Trace)記錄越多,但日誌也越大。「關閉」會停止記錄日誌。", + "captureLabel": "擷取等級", + "levels": { + "off": "關閉", + "error": "錯誤", + "warn": "警告", + "info": "資訊", + "debug": "除錯", + "trace": "追蹤" + }, + "viewerTitle": "最近日誌", + "viewerDescription": "即時檢視最近的日誌記錄。可依等級篩選或搜尋文字。", + "searchPlaceholder": "搜尋訊息或來源…", + "viewLevels": { + "all": "所有等級", + "error": "錯誤以上", + "warn": "警告以上", + "info": "資訊以上", + "debug": "除錯以上", + "trace": "追蹤以上" + }, + "pause": "暫停", + "resume": "即時", + "refresh": "重新整理", + "clear": "清除", + "openFolder": "開啟資料夾", + "shownCount": "已顯示 {shown} / {total}", + "empty": "尚無日誌。", + "levelSaveFailed": "儲存日誌等級失敗", + "openFolderFailed": "開啟日誌資料夾失敗", + "downloadFailed": "下載日誌檔案失敗", + "filesTitle": "日誌檔案", + "filesDescription": "從磁碟下載完整日誌檔案,檢視即時緩衝區以外的歷史記錄。", + "filesEmpty": "尚無日誌檔案。", + "download": "下載", + "downloadTruncated": "檔案較大,已下載最新的 {size}。完整檔案請在日誌目錄中查看。", + "captureEnvLocked": "日誌等級由 RUST_LOG / CODEG_LOG 環境變數控制;請在該處修改以生效。", + "targetsTitle": "依模組覆寫", + "targetsDescription": "為特定模組(如 codeg_lib::acp)單獨設定級別,不影響全域級別。", + "targetsAdd": "新增", + "targetsRemove": "移除覆寫", + "toggleDetails": "切換詳情" + }, + "Automations": { + "title": "自動化", + "new": "新增自動化", + "empty": "尚無自動化", + "emptyHint": "建立一個,讓代理程式按排程或手動執行任務。", + "name": "名稱", + "namePlaceholder": "例如:每晚 PR 審查", + "prompt": "提示詞", + "promptPlaceholder": "讓代理程式做什麼?", + "agent": "代理程式", + "folder": "工作區資料夾", + "folderPlaceholder": "選擇資料夾", + "isolation": "隔離方式", + "isolationWorktree": "每次執行新增 worktree", + "isolationShared": "在資料夾內執行", + "isolationSharedCaveat": "執行會直接使用該資料夾的工作樹,可能與你未提交的變更衝突。勾選每次執行新建工作樹以隔離每次執行。", + "trigger": "觸發方式", + "triggerSchedule": "按排程", + "triggerManual": "僅手動", + "cron": "排程(cron)", + "cronPlaceholder": "0 9 * * 1-5", + "timezone": "時區", + "nextRun": "下次執行", + "branch": "分支", + "branchOptional": "分支(選填)", + "enabled": "已啟用", + "save": "儲存", + "cancel": "取消", + "edit": "編輯", + "delete": "刪除", + "runNow": "立即執行", + "cancelRun": "取消執行", + "runHistory": "執行紀錄", + "noRuns": "尚無執行紀錄", + "allFolders": "所有資料夾", + "filterAll": "全部", + "noMatches": "沒有符合的自動化", + "viewConversation": "檢視對話", + "lastRun": "上次執行", + "never": "從未", + "running": "執行中", + "deleteTitle": "刪除此自動化?", + "deleteDescription": "這會刪除該自動化及其排程。執行紀錄會保留。", + "statusRunning": "執行中", + "statusSucceeded": "成功", + "statusFailed": "失敗", + "statusCancelled": "已取消", + "statusSkipped": "已略過", + "errorName": "名稱必填", + "errorPrompt": "提示詞必填", + "errorCron": "按排程的自動化需要 cron 運算式", + "errorFolder": "請選擇工作區資料夾", + "presetHourly": "每小時", + "presetDaily": "每天 9 點", + "presetWeekdays": "工作日 9 點", + "presetCustom": "自訂", + "probing": "正在載入選項…", + "retry": "重試", + "configNone": "此代理程式沒有可設定的選項", + "inherit": "代理程式預設", + "mode": "模式", + "config": "設定", + "branchPlaceholder": "(預設分支)", + "selectHint": "選擇一個自動化以查看詳情", + "refresh": "重新整理", + "onboardTitle": "自動化日常代理任務", + "onboardHint": "安排代理定時或隨需審查程式碼、更新相依套件或處理問題。", + "headerSubtitle": "定時與隨需的代理任務", + "startFromTemplate": "從範本開始", + "blankTitle": "空白自動化", + "blankDesc": "從零設定一個代理任務。", + "backToTemplates": "範本", + "sectionSchedule": "排程與目標", + "sectionTarget": "執行目標", + "sectionAction": "動作", + "actionLaunchSession": "啟動會話", + "actionEnqueueTask": "任務入列", + "actionEnqueueTaskHint": "每次觸發都會在目標資料夾的待辦任務裡加入一個待辦任務(標題為本自動化名稱),由任務引擎依看板設定執行。", + "sectionPrompt": "提示詞", + "nextIn": "{rel}後執行", + "manual": "手動", + "schedEveryMinutes": "每 {n} 分鐘", + "schedHourly": "每小時", + "schedDaily": "每天 {time}", + "schedWeekdays": "工作日 {time}", + "schedWeekly": "每{day} {time}", + "schedMonthly": "每月 {day} 日 {time}", + "dow0": "週日", + "dow1": "週一", + "dow2": "週二", + "dow3": "週三", + "dow4": "週四", + "dow5": "週五", + "dow6": "週六", + "tplCodeReviewTitle": "程式碼審查", + "tplCodeReviewDesc": "審查最近的變更,找出缺陷、回歸與品質問題。", + "tplDependencyUpdatesTitle": "相依套件更新", + "tplDependencyUpdatesDesc": "找出過時的相依套件並提出安全的升級方案。", + "tplTestCoverageTitle": "測試涵蓋率", + "tplTestCoverageDesc": "找出未涵蓋的程式碼路徑並補上缺少的測試。", + "tplTodoSweepTitle": "TODO 清理", + "tplTodoSweepDesc": "收集 TODO 與 FIXME 註解並依優先順序整理。", + "tplCiTriageTitle": "CI 排查", + "tplCiTriageDesc": "調查最近失敗的檢查並提出修復方案。", + "tplReleaseNotesTitle": "發行說明", + "tplReleaseNotesDesc": "彙整自上次發行以來的變更,產生更新日誌。", + "tplSecurityAuditTitle": "安全稽核", + "tplSecurityAuditDesc": "掃描漏洞與風險模式,並回報發現的問題。", + "enable": "啟用", + "disable": "停用", + "moreActions": "更多操作", + "statusDisabled": "已停用", + "cronBuilderTitle": "排程產生器", + "cronFreqLabel": "頻率", + "cronFreqMinutes": "每 N 分鐘", + "cronFreqHourly": "每小時", + "cronFreqDaily": "每天", + "cronFreqWeekdays": "工作日", + "cronFreqWeekly": "每週", + "cronFreqMonthly": "每月", + "cronFreqCustom": "自訂", + "cronEveryLabel": "間隔(分鐘)", + "cronTimeLabel": "時間", + "cronHourLabel": "小時", + "cronMinuteLabel": "分鐘", + "cronDowLabel": "星期", + "cronDomLabel": "日期", + "cronApply": "套用", + "cronPreviewLabel": "預覽", + "cronOpenBuilder": "開啟排程產生器", + "branchDefault": "預設分支", + "branchUseCustom": "使用「{query}」", + "branchLocal": "本機", + "branchRemote": "遠端", + "branchSearchPlaceholder": "搜尋分支…", + "branchNone": "無分支" + }, + "Tasks": { + "title": "待辦任務", + "new": "新增任務", + "empty": "還沒有任務", + "emptyHint": "新增待辦後即可處理——agent 在獨立 worktree 中工作,你驗收並合併結果。", + "emptyColTodo": "還沒有待辦任務", + "emptyColInProgress": "暫無進行中的任務", + "emptyColAttention": "暫無等你處理的任務", + "emptyColDone": "還沒有已完成的任務", + "allFolders": "全部資料夾", + "showCanceled": "顯示已取消", + "showArchived": "顯示已封存", + "filter": "篩選", + "viewSwitchToBoard": "切換到看板檢視", + "viewSwitchToList": "切換到清單檢視", + "statusFilter": "狀態", + "statusFilterAll": "全部狀態", + "listEmpty": "沒有符合目前篩選條件的任務", + "listColStatus": "狀態", + "listColTask": "任務", + "listColLocation": "位置", + "listColChanges": "變更", + "listColUpdated": "更新", + "colTodo": "待辦", + "colInProgress": "進行中", + "colAttention": "等你處理", + "colDone": "已完成", + "statusTodo": "待辦", + "statusQueued": "排隊中", + "statusPreparing": "初始化中", + "statusRunning": "進行中", + "statusAwaitingInput": "等待輸入", + "statusReview": "待驗收", + "statusMerging": "合併中", + "statusDone": "已完成", + "statusFailed": "失敗", + "statusCanceled": "已取消", + "statusInterrupted": "已中斷", + "badgeCleanupFailed": "清理失敗", + "badgeWorktreeKept": "保留 worktree", + "badgeWorktreeRemoved": "Worktree 已刪除", + "filesChanged": "{count} 個檔案", + "actionStart": "開始", + "actionSchedule": "定時執行", + "actionCancel": "取消", + "actionRetry": "重試", + "actionRequeue": "重新排隊", + "actionViewSession": "檢視會話", + "actionEdit": "編輯", + "actionDelete": "刪除", + "actionRetryCleanup": "重試清理", + "actionMerge": "合併", + "actionUnqueueMerge": "取消排隊", + "actionEditQueuedMerge": "修改排隊的合併", + "badgeMergeQueued": "排隊合併中", + "badgeMergeQueuedRank": "排隊合併 · 第 {rank} 位", + "badgeMergeQueuedHint": "正在等待該專案目前的合併完成,輪到時會自動開始。", + "actionComplete": "完成", + "actionAbandon": "放棄", + "cancelTitle": "取消任務?", + "cancelDescription": "任務將變為已取消。worktree 會保留,之後可以重新排隊。", + "cancelReasonLabel": "取消原因(選填)", + "cancelReasonPlaceholder": "例如:方向不對,我重寫一下任務描述", + "cancelKeep": "先不取消", + "cancelSubmit": "取消任務", + "restartTitleRetry": "重試任務", + "restartTitleRequeue": "重新排隊", + "restartDescription": "可以補充一段說明(選填),它會隨下一輪的提示詞一起傳給 agent。", + "scheduleTitle": "定時執行任務", + "scheduleDescription": "任務留在「待辦」,到時間自動開始。資料夾的並行上限仍然有效。", + "scheduleDateLabel": "日期", + "schedulePickDate": "選擇日期", + "scheduleTimeLabel": "時間", + "schedulePreview": "{time} 執行", + "schedulePastHint": "該時間已過——儲存後會立即開始。", + "scheduleInAnHour": "1 小時後", + "scheduleInThreeHours": "3 小時後", + "scheduleTomorrow": "明天 9:00", + "scheduleClear": "清除定時", + "scheduleBadge": "預計於 {time} 開始", + "toastScheduled": "已定時:{time}", + "toastScheduleCleared": "已清除定時", + "actionFollowUp": "繼續處理", + "actionAddNote": "補充說明", + "followUpSubmit": "傳送", + "followUpIntentRevise": "修改返工", + "followUpIntentContinue": "繼續推進", + "followUpIntentQuestion": "提問答疑", + "followUpIntentVerify": "自查驗證", + "followUpPlaceholderRevise": "希望 agent 改哪裡?會在同一個工作階段繼續。", + "followUpPlaceholderContinue": "接下來還要做什麼?已有的工作會保留。", + "followUpPlaceholderQuestion": "想了解什麼?agent 只回答,不會改動任何檔案。", + "followUpPlaceholderVerify": "選填:有什麼想讓它重點檢查的?", + "followUpPlaceholderRetry": "選填:這次要怎麼做才不一樣?例如:先跑 pnpm install", + "followUpPlaceholderRequeue": "選填:當時為什麼取消?這次要注意什麼?", + "actionArchive": "封存", + "actionUnarchive": "取消封存", + "archiveAllDone": "全部封存", + "dropToStart": "放開即開始執行", + "errorView": "檢視", + "notifyReview": "待驗收:{title}", + "notifyFailed": "任務失敗:{title}", + "createFromMessage": "由此訊息建立任務", + "detailTokens": "總 token 用量", + "editorTitleNew": "新增任務", + "editorTitleEdit": "編輯任務", + "templates": "範本", + "templatesEmpty": "還沒有範本。", + "templateSaveCurrent": "將目前內容存為範本", + "templateDelete": "刪除範本", + "transcriptTitle": "任務會話", + "transcriptDescription": "任務智慧代理會話的唯讀即時檢視。", + "phaseWork": "任務執行", + "phaseRetry": "重試執行", + "phaseReturn": "繼續處理", + "phaseMerge": "合併變更", + "titleLabel": "標題", + "titlePlaceholder": "要做什麼?", + "promptLabel": "任務描述", + "promptPlaceholder": "向 agent 描述任務——輸入 @ 可引用檔案,/ 可喚起指令", + "folderPlaceholder": "選擇資料夾", + "agentInheritedHint": "繼承自任務設定,修改後僅對本任務生效", + "agentOverrideReset": "恢復繼承", + "sectionTarget": "目標", + "errorTitle": "請輸入標題", + "errorPrompt": "請輸入任務描述", + "errorFolder": "請選擇資料夾", + "save": "儲存", + "cancel": "取消", + "mergeTitle": "合併任務", + "mergeQueuedTitle": "排隊中的合併", + "mergeQueueHint": "該專案正在合併另一個任務。此任務會加入佇列,等前一個完成後自動開始。", + "mergeQueueUpdateHint": "此任務已在合併佇列中。送出將更新它的合併選項,並保留原本的排隊位置。", + "mergeDescription": "將 {branch} 合併到 {base}。worktree 中未提交的變更會先自動提交。", + "mergeMessage": "提交訊息", + "mergeMessagePlaceholder": "例如 feat: add login validation", + "mergeAutoMessage": "讓 agent 自動產生提交訊息", + "strategySquash": "合併為一筆提交", + "strategySquashHint": "任務的所有修改壓縮成一筆提交記錄併入主分支,歷史更簡潔。", + "strategyMerge": "保留完整提交歷史", + "strategyMergeHint": "保留任務過程中的每一筆提交,另加一筆合併記錄,每一步都可追溯。", + "mergeDeleteWorktree": "合併後刪除 worktree", + "mergeSubmit": "合併", + "mergeSubmitQueue": "加入合併佇列", + "mergeQueuedToast": "已加入合併佇列,等目前的合併完成後自動開始。", + "completeTitle": "完成任務", + "completeDescription": "此任務沒有變更任何檔案,無須合併,將直接標記為已完成。", + "completeDescriptionNoWorktree": "此任務的 worktree 已被刪除,無法再合併,將直接標記為已完成。若工作分支上仍有未合併的提交,分支會被保留。", + "completeDeleteWorktree": "完成後刪除 worktree", + "completeSubmit": "完成", + "settingsTitle": "任務設定", + "settingsDescription": "{folder} 中任務的預設配置。", + "settingsScope": "套用範圍", + "settingsScopeGlobal": "全部資料夾(全域預設)", + "settingsScopeGlobalHint": "未單獨設定的資料夾將使用這份全域預設。", + "settingsSource": "設定來源", + "settingsSourceGlobal": "使用全域預設", + "settingsSourceCustom": "單獨設定", + "settingsSourceGlobalFollow": "跟隨全域任務設定,全域變更會自動生效。", + "settingsSourceCustomHint": "為此資料夾儲存獨立設定,不再跟隨全域預設。", + "settingsAgent": "預設 agent", + "settingsMaxConcurrent": "最大並行任務數", + "settingsMaxConcurrentHint": "0 表示不限制", + "settingsAutoProcess": "自動處理", + "settingsAutoProcessHint": "待辦任務自動開始處理,受並行上限約束。", + "settingsMergeStrategy": "預設合併策略", + "settingsMergeStrategyHint": "合併任務時,這些修改在分支歷史裡如何記錄。", + "settingsAutoMerge": "自動合併", + "settingsAutoMergeHint": "任務進入待驗收且有可合併改動時自動落地,與點擊「合併」相同:提交訊息由 agent 自動產生,是否刪除 worktree 沿用下方預設。預檢未通過或合併失敗的任務會留下等你處理。", + "settingsDeleteWorktree": "合併後刪除 worktree", + "settingsDeleteWorktreeHint": "合併對話框裡預設勾選,仍可臨時更改。", + "settingsWorktreeRoot": "Worktree 位置", + "settingsWorktreeRootHint": "新任務的 worktree 會建立在該目錄下,每個任務一個。留空則建立在專案資料夾的同層目錄;「~」表示家目錄,相對路徑相對於專案資料夾。", + "settingsWorktreeRootPlaceholder": "~/codeg-worktrees", + "settingsWorktreeRootBrowse": "選擇 worktree 目錄", + "settingsPreflight": "預檢命令", + "settingsPreflightHint": "任務進入待驗收時在 worktree 中執行。", + "settingsPreflightCustomPlaceholder": "pnpm test", + "settingsInitCommand": "Worktree 初始化命令", + "settingsInitCommandHint": "建立 worktree 後、工作階段開始前執行。", + "settingsInitCommandPlaceholder": "pnpm install", + "settingsTabGeneral": "一般", + "settingsTabMerge": "合併", + "settingsTabWorktree": "Worktree", + "settingsTabPrompts": "提示詞", + "settingsPromptsIntro": "每個階段都已內建固定的提示詞——任務本身、worktree 規則,合併階段還包含具體的 git 步驟。這裡填的內容會作為補充說明追加到最後:只是對內建提示詞的細化,不會取代它們。", + "settingsPromptStageAll": "全部階段", + "settingsPromptPlaceholderAll": "例如:遵循 AGENTS.md 裡的專案慣例;一律用繁體中文回覆", + "settingsPromptPlaceholderWork": "例如:先讀相關測試;小步提交,邊做邊交", + "settingsPromptPlaceholderRetry": "例如:先看清楚已經提交了哪些改動再繼續,別重做已完成的部分", + "settingsPromptPlaceholderReturn": "例如:逐條處理提到的每一點;不要順手重構無關程式碼", + "settingsPromptPlaceholderMerge": "例如:最終合併的提交訊息用繁體中文;手動解決過的衝突要另外說明", + "settingsPromptHintAll": "追加到每一次發給 agent 的提示詞,包括合併那一輪。", + "settingsPromptHintWork": "任務首次執行時追加。", + "settingsPromptHintRetry": "重試被中斷或失敗的任務時追加。", + "settingsPromptHintReturn": "對待驗收的任務繼續處理時追加(返工、追加工作、自查)。", + "settingsPromptHintMerge": "agent 把任務合併到基線分支時追加。", + "preflightPassed": "{name} 通過", + "preflightFailed": "{name} 未通過", + "preflightRunning": "{name} 執行中…", + "detailDescription": "任務詳情", + "detailSummary": "結果", + "detailFiles": "變更檔案", + "detailDiffAll": "檢視全部差異", + "detailDiffAllTitle": "全部差異", + "detailNoChanges": "相對基準還沒有變更", + "detailTimeline": "推進記錄", + "detailTimelineEmpty": "暫無活動", + "showMore": "展開", + "showLess": "收起", + "detailInfo": "詳情", + "detailBranch": "分支", + "detailMergeCommit": "合併提交", + "detailChanges": "變更", + "detailScheduled": "預計開始", + "detailCreated": "建立時間", + "detailStarted": "開始時間", + "detailFinished": "完成時間", + "diffLoading": "正在載入差異…", + "deleteConfirmTitle": "刪除任務?", + "deleteConfirmBody": "「{title}」將從看板移除。進行中的執行會先被取消。", + "deleteWithWorktree": "同時刪除其 worktree", + "eventCreated": "已建立", + "eventStatusChanged": "狀態變更", + "eventConfigEffective": "啟動配置", + "eventInitCommand": "初始化命令", + "eventAgentProgress": "Agent 進展", + "eventAgentVerdict": "Agent 結論", + "eventMergeAttempt": "開始合併", + "eventMergeQueued": "加入合併佇列", + "eventMergeConflict": "合併衝突", + "eventPreflight": "預檢", + "eventCleanupFailed": "worktree 清理失敗", + "eventResumeFallback": "會話恢復失敗,已改用新會話", + "eventUserAction": "使用者操作", + "eventDiffStat": "變更快照" + }, + "CustomSkillsSettings": { + "loading": "正在載入自訂技能…", + "category": "自訂", + "searchPlaceholder": "依名稱、ID 或描述搜尋自訂技能", + "states": { + "not_linked": "未啟用", + "linked_to_codeg": "已啟用", + "linked_elsewhere": "連結到其他位置", + "blocked_by_real_directory": "被同名實體目錄佔用", + "broken": "連結已失效" + }, + "actions": { + "new": "新增", + "import": "匯入", + "importFromAgent": "從 Agent 匯入", + "cancel": "取消", + "save": "儲存" + }, + "rowMenu": { + "edit": "編輯", + "duplicate": "複製為新技能", + "delete": "刪除" + }, + "bulk": { + "delete": "刪除所選" + }, + "editor": { + "createTitle": "新增自訂技能", + "editTitle": "編輯自訂技能", + "description": "自訂技能存放於共用庫(~/.codeg/skills),可為任意智能體啟用。", + "idLabel": "技能 ID", + "idPlaceholder": "例如 my-workflow", + "contentLabel": "SKILL.md", + "contentPlaceholder": "在此撰寫技能的 SKILL.md…", + "preview": "預覽", + "edit": "編輯", + "emptyBody": "尚無內容。" + }, + "duplicate": { + "title": "複製技能", + "description": "以「{id}」為範本,以新 ID 建立一份副本。", + "newIdPlaceholder": "新技能 ID", + "confirm": "複製" + }, + "import": { + "title": "選擇要匯入的技能資料夾" + }, + "importFromAgent": { + "title": "從 Agent 匯入技能", + "description": "將某個 Agent 自己的技能複製到共享庫,即可為任意 Agent 啟用。", + "agentLabel": "Agent", + "agentPlaceholder": "選擇一個 Agent", + "selectAll": "全選({count})", + "loading": "正在載入該 Agent 的技能…", + "unsupported": "此 Agent 未提供技能目錄。", + "empty": "此 Agent 沒有可匯入的技能。", + "alreadyInLibrary": "已在庫中", + "confirm": "匯入所選({count})" + }, + "delete": { + "title": "刪除自訂技能?", + "body": "將從中央庫移除 {count} 個自訂技能,並解除它們在所有智能體中的連結。此操作無法復原。", + "confirm": "刪除" + }, + "toasts": { + "loadFailed": "載入技能失敗", + "idRequired": "請輸入技能 ID", + "created": "已建立自訂技能", + "updated": "已更新自訂技能", + "saveFailed": "儲存技能失敗", + "imported": "已匯入技能", + "importFailed": "匯入技能失敗", + "duplicated": "已複製技能", + "duplicateFailed": "複製技能失敗", + "deleted": "已刪除 {count} 個技能", + "deletedPartial": "已刪除 {ok} 個,{failed} 個失敗", + "deleteFailed": "刪除技能失敗", + "importedFromAgent": "已匯入 {count} 個技能", + "importedFromAgentPartial": "已匯入 {ok} 個,{failed} 個失敗", + "importFromAgentAllSkipped": "無需匯入——{count} 個已在庫中", + "importFromAgentFailed": "從 Agent 匯入失敗" + } + }, + "CodexModelEditor": { + "customizedNotice": "你已自訂模型清單,codeg 將接管 codex 的完整模型表。codex 日後新增的官方模型不會自動出現——點擊下方重新整理並再次儲存即可同步。清空所有自訂即可交回 codex 自動更新。", + "officialsTitle": "官方模型", + "officialsHint": "自動納入你啟動的 codex 的官方模型;可刪除不需要的。", + "officialsEmpty": "暫無官方模型。", + "refresh": "從 codex 重新整理", + "readdOfficial": "重新加入官方", + "customsTitle": "自訂模型", + "customsEmpty": "暫無自訂模型。", + "addCustom": "新增自訂", + "slugPlaceholder": "模型 id(slug)", + "displayNamePlaceholder": "顯示名稱", + "contextWindow": "上下文", + "makeDefault": "設為預設", + "defaultHint": "預設模型", + "remove": "移除", + "advanced": "進階", + "baseTemplate": "基礎範本", + "baseTemplateHint": "從哪個官方模型複製必填欄位(系統提示詞、工具、限制)。", + "groupBehavior": "行為與能力", + "fieldReasoningLevel": "預設推理強度", + "fieldReasoningSummary": "推理摘要", + "fieldVerbosity": "詳細程度", + "fieldShellType": "Shell 類型", + "fieldApplyPatch": "套用修補工具", + "fieldReasoningSummaries": "推理摘要支援", + "fieldSupportVerbosity": "詳細程度控制", + "fieldParallelToolCalls": "並行工具呼叫", + "fieldSearchTool": "網路搜尋工具", + "optNone": "無", + "groupInstructions": "描述與系統提示詞", + "fieldDescription": "描述", + "baseInstructions": "系統提示詞(base_instructions)" + }, + "DiagnosticsSettings": { + "title": "環境診斷", + "description": "檢查本應用在自身行程中如何解析該智能體的 CLI——這可能與你的終端機不同。", + "loading": "正在執行診斷…", + "error": "診斷失敗", + "rerun": "重新執行", + "copyAll": "複製全部", + "copied": "診斷資訊已複製到剪貼簿", + "button": "診斷", + "verdict": { + "ok": "環境正常。若仍提示未安裝,請徹底重新啟動應用以重新整理前綴快取。", + "node_missing": "在應用的 PATH 上找不到 Node.js。", + "npm_missing": "在應用的 PATH 上找不到 npm。", + "not_installed": "此智能體似乎尚未安裝。", + "installed_but_unresolved": "紀錄顯示已安裝,但應用無法定位其執行檔。", + "user_prefix_not_on_path": "安裝到了回退前綴(~/.codeg/npm-global),但它不在應用的 PATH 上。請徹底重新啟動應用後再試。", + "homebrew_bin_not_on_path": "安裝在 Homebrew 的 bin 目錄下,但它不在應用的 PATH 上(Apple Silicon keg 拆分)。", + "terminal_only_path": "此命令在你的終端機能解析,但在應用中不能——這是 GUI PATH 差異。請從終端機啟動應用,或在智能體設定中重新安裝。", + "npm_prefix_timeout": "npm prefix -g 太慢(超過 1.5 秒),已略過回退偵測。請重新啟動應用後再試。", + "node_too_old": "目前 Node.js 版本低於此智能體的要求。請升級 Node.js。", + "adapter_missing_native_present": "你本機的 {agent} CLI 確實安裝了,但 Codeg 啟動的是另一個 ACP 轉接器套件,而它還沒安裝。到「智能體設定」中安裝即可 —— 它不會動到你的 CLI,登入狀態也是共用的。", + "adapter_missing": "Codeg 為 {agent} 啟動的是獨立的 ACP 轉接器套件,目前尚未安裝。請到「智能體設定」中安裝 —— 只安裝廠商 CLI 是不夠的。" + } + }, + "TokenUsage": { + "title": "Token 用量", + "rangeLabel": "時間範圍", + "range7d": "近 7 天", + "range30d": "近 30 天", + "range90d": "近 90 天", + "rangeThisMonth": "本月", + "rangeThisYear": "今年", + "rangeAll": "全部", + "rangeCustom": "自訂", + "moreRanges": "更多", + "customRangePick": "選擇日期範圍", + "bucketLabel": "統計粒度", + "bucketDay": "依天", + "bucketWeek": "依週", + "bucketMonth": "依月", + "bucketUnitDay": "天", + "bucketUnitWeek": "週", + "bucketUnitMonth": "月", + "folderFilter": "資料夾", + "allFolders": "全部資料夾", + "agentFilter": "智慧代理", + "allAgents": "全部智慧代理", + "modelFilter": "模型", + "allModels": "全部模型", + "searchPlaceholder": "搜尋…", + "noMatches": "沒有符合項目", + "clearFilter": "清除選擇", + "resetFilters": "重設篩選", + "refresh": "重新整理", + "rebuild": "全量重建", + "rebuildHint": "捨棄已統計的資料並重新解析全部工作階段紀錄。當紀錄被 codeg 以外的 CLI 追加過時使用。", + "syncing": "正在統計工作階段…", + "syncProgress": "{done} / {total}", + "syncDone": "已統計 {synced} 個工作階段", + "syncFailed": "部分工作階段讀取失敗", + "syncBusy": "已有一次重新整理進行中", + "lastSynced": "更新於 {time}", + "lastSyncedNever": "尚未統計", + "tileTotal": "總 Token", + "tileSessions": "工作階段數", + "tileTurns": "對話輪次", + "tileActiveDays": "活躍天數", + "tileGenTime": "生成時長", + "vsPrevious": "對比上一週期", + "deltaNew": "新增", + "trendTitle": "用量趨勢", + "trendEmpty": "此範圍內沒有用量", + "trendTurns": "輪次", + "trendSessions": "工作階段", + "compositionTitle": "Token 花在哪裡", + "compositionHint": "輸入是你送出的內容,輸出是模型寫回來的,快取讀取則是不必再按原價重送的上下文。", + "compositionNote": "這些快取命中若按原價重送,要多花 {value}。", + "inputTokens": "輸入", + "outputTokens": "輸出", + "cacheWrite": "快取寫入", + "cacheRead": "快取讀取", + "freshTokens": "新算 Token", + "cacheHitCaption": "快取命中", + "cacheHeroTitleHigh": "上下文大多不必重送", + "cacheHeroTitleLow": "多數上下文仍按原價計算", + "cacheHeroDesc": "{cached} 的上下文由快取承擔,這段時間真正新算的只有 {fresh}。", + "cacheSavedSuffix": "省下的重送量相當於 {saved}。", + "avgPerSession": "平均每工作階段", + "avgTurnsPerSession": "平均每個工作階段 {count} 輪", + "avgPerActiveDay": "平均每活躍日", + "peakBucket": "最高的一{bucket}", + "peakHour": "尖峰時段", + "daysValue": "{count} 天", + "idleDays": "空轉天數", + "byFolderTitle": "依資料夾", + "byAgentTitle": "依智慧代理", + "byModelTitle": "依模型", + "distributionTitle": "用量分布", + "distributionHint": "工作階段與 Token 依所選維度歸集,點任一列可依它篩選。", + "otherLabel": "其他", + "unknownModel": "未標註模型", + "emptyBreakdown": "尚無紀錄", + "sessionsCount": "{count} 個工作階段", + "heatmapTitle": "你的編碼作息", + "heatmapHint": "依本地星期與小時統計的 Token 分佈。", + "heatmapPeakHint": "最密集的時段在 {hour}:00 前後。", + "less": "少", + "more": "多", + "heatmapCell": "{weekday} {hour}:00 — {value} tokens", + "weekMon": "一", + "weekTue": "二", + "weekWed": "三", + "weekThu": "四", + "weekFri": "五", + "weekSat": "六", + "weekSun": "日", + "topSessionsTitle": "消耗最高的工作階段", + "untitledSession": "未命名工作階段", + "topSessionsEmpty": "此範圍內沒有工作階段", + "streakLongest": "最長連續", + "streakLongestDays": "最長連續 {count} 天", + "share": "分享", + "moreActions": "更多操作", + "shareDialogTitle": "分享你的用量卡片", + "shareDialogHint": "卡片內容就是你目前所選的時間範圍與篩選條件。", + "shareSave": "儲存圖片", + "shareCopy": "複製圖片", + "shareCopied": "已複製到剪貼簿", + "shareSaved": "圖片已儲存", + "shareFailed": "圖片產生失敗", + "shareRendering": "產生中…", + "cardHeading": "我的 AI 編碼戰績", + "cardRangeAll": "全部時間", + "cardTotalLabel": "累計 Token", + "cardFooter": "由 codeg 產生", + "cardTopModels": "常用模型", + "cardTopProjects": "主力專案", + "archetypeNightOwl": "深夜工程師", + "archetypeNightOwlDesc": "{percent}% 的 Token 燒在天黑之後。", + "archetypeEarlyBird": "清晨型選手", + "archetypeEarlyBirdDesc": "{percent}% 的 Token 在早上 9 點前就用掉了。", + "archetypeWeekendWarrior": "週末戰士", + "archetypeWeekendWarriorDesc": "{percent}% 的 Token 發生在週末。", + "archetypeCacheMaster": "快取大師", + "archetypeCacheMasterDesc": "{percent}% 的上下文來自快取。", + "archetypeMarathoner": "長跑選手", + "archetypeMarathonerDesc": "連續 {days} 天沒有中斷。", + "archetypePolyglot": "多面手", + "archetypePolyglotDesc": "{count} 個智慧代理都在主力使用。", + "archetypeLaserFocus": "專注一役", + "archetypeLaserFocusDesc": "{percent}% 的 Token 投在同一個專案上。", + "archetypeDeepDiver": "深潛者", + "archetypeDeepDiverDesc": "平均每個工作階段 {averageK}K tokens。", + "archetypeSteady": "穩定輸出", + "archetypeSteadyDesc": "累計 {days} 天在寫程式。", + "emptyTitle": "還沒有可統計的資料", + "emptyHint": "codeg 直接從各智慧代理自己的工作階段紀錄讀取 Token 數。點一下重新整理,把本機已有的紀錄統計進來。", + "emptyAction": "統計我的工作階段", + "loadFailed": "用量載入失敗", + "truncatedNotice": "此範圍過大 —— 下面的數字只涵蓋其中最近的一段。" + } +}